Merge "Perf: Fix PID for tracepoints"
diff --git a/Documentation/arm/msm/msm_sharedmem.txt b/Documentation/arm/msm/msm_sharedmem.txt
new file mode 100644
index 0000000..d9c939e
--- /dev/null
+++ b/Documentation/arm/msm/msm_sharedmem.txt
@@ -0,0 +1,115 @@
+Introduction
+============
+
+This is a new platform driver for newly introduced UIO devices
+to facilitate clients in Userspace.
+
+Hardware description
+====================
+This driver does not implement any specific hardware driver.
+
+Software description
+====================
+
+Design
+======
+
+The goal of this driver is to ensure there is no security lapse in the
+Userspace clients' functionality. This new driver uses the existing
+UIO framework to facilitate the clients to be able to memory map their
+respective allotted shared memory address in the client's address space.
+
+ |
+ Userspace | Kernel space
+ +--------------+ +---------------+ +---------------+
+ | Client | | Shared | | shrdmem_uio |
+ | <-------> Memory <-------> driver |
+ +--------------+ +---------------+ +---------------+
+ |
+ |
+
+The shared memory (a transport buffer) address is unique for each
+individual client and is made available to the driver via device tree.
+
+For a given client the probe would be called once in the shrdmem_uio driver.
+This driver would parse the device tree and register a new UIO device with kernel
+available under /dev/uioX (where X would start from zero, being serially
+incremented for the next UIO device probed)
+
+The client in Userspace would be able to access the respective UIO device
+under the sysfs entry(/sys/class/uio/uioX) upon verifying the name and version
+of the device under this sysfs node. Once verified it could access the physical
+address under /sys/class/uio/uioX/maps/map0/addr
+
+The client would request for memory mapping which would be taken care of in the
+kernel space by the UIO framework. No explicit mmap() implementation required by
+the shrdmem_uio driver.
+
+Power Management
+================
+Does not implement any power management.
+
+SMP/multi-core
+==============
+
+The platform driver would be loaded/probed once per client.
+DTS files will be looked up for shared memory addresses and sizes for all the clients.
+The UIO char device will be created under /dev/uioX.
+
+This being one time activity for a given client it does not require SMP/multi-core safety.
+
+Security
+========
+
+The devices (/dev/uioX) would have permission checks for restricted access
+
+Performance
+===========
+
+None.
+
+Interface
+=========
+
+This driver does not export any APIs for kernel.
+Android user space can access the shared memory by mmaping it.
+
+Driver parameters
+=================
+
+None.
+
+Config options
+==============
+
+None.
+
+Dependencies
+============
+
+The only dependency is the kernel device tree files for the
+Userspace client details.
+
+User space utilities
+====================
+This driver communicates with the following user space clients/utilities:
+
+Remote File System:
+ - Based on Qualcomm Messaging Interface (QMI)
+ - This service enables the modules on the MSM modem processor to
+ read data from and write data to the embedded multimedia card (eMMC),
+ which is solely controlled by the applications processor.
+
+Remote File System Access (QMI_RFSA):
+ - Based on Qualcomm Messaging Interface (QMI)
+ - This service provides access from the Hexagon processor to a High-Level
+ Operating Sytem (HLOS) file system
+Other
+=====
+
+None.
+
+Known issues
+============
+
+None.
diff --git a/Documentation/cpu-freq/governors.txt b/Documentation/cpu-freq/governors.txt
index b4ae5e6..92bbd16 100644
--- a/Documentation/cpu-freq/governors.txt
+++ b/Documentation/cpu-freq/governors.txt
@@ -234,7 +234,17 @@
above_hispeed_delay: When speed is at or above hispeed_freq, wait for
this long before raising speed in response to continued high load.
-Default is 20000 uS.
+The format is a single delay value, optionally followed by pairs of
+CPU speeds and the delay to use at or above those speeds. Colons can
+be used between the speeds and associated delays for readability. For
+example:
+
+ 80000 1300000:200000 1500000:40000
+
+uses delay 80000 uS until CPU speed 1.3 GHz, at which speed delay
+200000 uS is used until speed 1.5 GHz, at which speed (and above)
+delay 40000 uS is used. If speeds are specified these must appear in
+ascending order. Default is 20000 uS.
timer_rate: Sample rate for reevaluating CPU load when the CPU is not
idle. A deferrable timer is used, such that the CPU will not be woken
diff --git a/Documentation/cpuidle/driver.txt b/Documentation/cpuidle/driver.txt
index 7a9e09e..1b0d81d 100644
--- a/Documentation/cpuidle/driver.txt
+++ b/Documentation/cpuidle/driver.txt
@@ -15,11 +15,17 @@
cpuidle driver initializes the cpuidle_device structure for each CPU device
and registers with cpuidle using cpuidle_register_device.
+If all the idle states are the same, the wrapper function cpuidle_register
+could be used instead.
+
It can also support the dynamic changes (like battery <-> AC), by using
cpuidle_pause_and_lock, cpuidle_disable_device and cpuidle_enable_device,
cpuidle_resume_and_unlock.
Interfaces:
+extern int cpuidle_register(struct cpuidle_driver *drv,
+ const struct cpumask *const coupled_cpus);
+extern int cpuidle_unregister(struct cpuidle_driver *drv);
extern int cpuidle_register_driver(struct cpuidle_driver *drv);
extern void cpuidle_unregister_driver(struct cpuidle_driver *drv);
extern int cpuidle_register_device(struct cpuidle_device *dev);
diff --git a/Documentation/csdio.txt b/Documentation/csdio.txt
deleted file mode 100644
index 22d5e35..0000000
--- a/Documentation/csdio.txt
+++ /dev/null
@@ -1,189 +0,0 @@
-Introduction
-============
-The Char SDIO Device Driver is an interface which exposes an SDIO
-card/function from kernel space as a char device in user space.
-
-The driver doesn't interact with any HW directly. It relies on SDIO
-card/function interface provided as a part of Linux kernel.
-
-Hardware description
-====================
-Each SDIO device/card contains an SDIO client HW block.
-The host interacts with the device by sending byte sequences called
-command (CMD). Some commands can be followed by data blocks. The
-device sends back a byte sequence called response (R) and a data
-block if required. CMD3, CMD5 and CMD7 are used to initialize the
-device. CMD52 and CMD53 are used to access the device. Command
-format and properties are defined by SDIO Specification document
-published by SD Association:
- http://www.sdcard.org/developers/tech/sdio/.
-
-CMD52 and CMD53 can access up to 8 address spaces called Functions.
-Function 0 contains system information predefined by SD/SDIO
-standard and Functions 1-7 are defined by the SDIO device
-manufacturer.
-
-An SDIO device/card can send an interrupt to SDIO host. This
-interrupt is intercepted and handled by SDIO host.
-
-Software description
-====================
-Linux provides a framework for handling SDIO devices. It implements
-kind of plug-and-play model in which the Linux SDIO Host Driver is
-responsible for initializing an SDIO device upon insertion. It also
-reads device/card identification information and enumerates functions
-provided by the device and then looks up in the list of
-preregistered user SDIO drivers for a suitable one.
-
-During its lifecycle the user SDIO driver interacts with the Linux
-SDIO Host Driver in order to send/receive information to/from SDIO
-device/card. The user SDIO driver doesn't work with CMD52/CMD53
-directly. Instead it uses an abstraction provided by the Linux SDIO
-Host Driver.
-
-The Linux SDIO Host Driver is also in charge of handling SDIO
-interrupts. User SDIO driver can register its own callback in SDIO
-Host Driver and get a notification about interrupt event.
-
-The Char SDIO Device Driver follows the design guidelines mentioned
-above. It provides the following functionality:
-
- - Register itself in the user SDIO drivers list;
- - Handle Probe event upon insertion of supported card/device;
- - Creates and maintains a char device driver for each SDIO Function
- found in the card/device;
- - Translates read/write/ioctl calls to appropriate SDIO call
- sequences;
-
-In order to handle general SDIO configuration functionality and
-Function 0 the Char SDIO Device Driver provides additional
-simplified char device driver.
-
-The Manufacturer and Device IDs of handled SDIO device should be
-provided as parameters for kernel module or as configuration
-parameters in case of statically linked driver.
-
-Design
-======
-The main goal of the Char SDIO Device Driver is to expose an SDIO
-card/device from kernel space to user space as a char device driver.
-The driver should be generic and simple as far as possible.
-
-The biggest design tradeoff is maintaining a balance between the
-system call overhead required to initiate an SDIO transaction from
-user space and overall SDIO communication performance. But luckily,
-because of nature of SDIO protocol, this overhead is negligible
-comparing to time required to execute SDIO transaction itself. So,
-each CMD52 (read or write) consists from single ioctl system call.
-And each CMD53 invokes single ioctl system call followed by read or
-write system call.
-
-The Char SDIO Device Driver registers its own class of the devices
-called 'csdio'. This class will serve as a common roof for all SDIO
-devices served by different instances of the Char SDIO Device Driver.
-Additional benefit from maintaining its own class is the driver
-ability to overwrite default permissions of the dev nodes created by
-the driver.
-
-Power Management
-================
-None
-
-SMP/multi-core
-==============
-The driver does not anticipate any issues related to multi-core
-since it is expected to run on one core only.
-
-Security
-========
-None
-
-Performance
-===========
-None
-
-Interface
-=========
-The Char SDIO Device Driver has two char device interfaces:
- - Control Interface;
- - Function Interface.
-
-Char SDIO Device Driver Control Interface consists of:
- - open() - device node is /dev/csdio0;
- - close()
- - ioctl() - the following options are available:
- - CSDIO_IOC_ENABLE_HIGHSPEED_MODE;
- - CSDIO_IOC_SET_DATA_TRANSFER_CLOCKS;
- - CSDIO_IOC_ENABLE_ISR;
- - CSDIO_IOC_DISABLE_ISR.
-
-Char SDIO Device Driver Function Interface consists of:
- - open() - device node is /dev/csdiofX, where X is Function Id;
- - close()
- - read() - send CMD53 read;
- - write() - send CMD53 write;
- - ioctl() - the following options are available:
- - CSDIO_IOC_SET_OP_CODE - 0 fixed adrress, 1 autoincrement.
- - CSDIO_IOC_FUNCTION_SET_BLOCK_SIZE;
- - CSDIO_IOC_SET_BLOCK_MODE - 0 byte mode, 1 block mode;
- - CSDIO_IOC_CMD52 - execute CMD52, receives the
- following structure as a parameter:
- struct csdio_cmd52_ctrl_t {
- uint32_t m_write; // 0 - read, 1 -write
- uint32_t m_address;
- uint32_t m_data; // data to write or read data
- uint32_t m_ret; // command execution status
- }__attribute__ ((packed));
- - CSDIO_IOC_CMD53 - setup CMD53 data transfer, receives the
- following structure as a parameter:
- struct csdio_cmd53_ctrl_t {
- uint32_t m_block_mode;
- uint32_t m_op_code;
- uint32_t m_address;
- }__attribute__ ((packed));
- - CSDIO_IOC_CONNECT_ISR;
- - CSDIO_IOC_DISCONNECT_ISR;
- - CSDIO_IOC_GET_VDD;
- - CSDIO_IOC_SET_VDD.
-
-Additionally, user space application can use fcntl system call with
-parameters F_SETOWN and F_SETFL in order to set an asynchronous
-callback for SDIO interrupt.
-
-Driver parameters
-=================
-If the driver is compiled as a kernel module, the following
-parameters can be used in order to provide Manufacturer and Device IDs
-upon module download:
- - csdio_vendor_id;
- - csdio_device_id.
-If the driver is intended to work with specific SDIO host the
-host_name parameter should be added followed by the name of the MMC
-host platform device.
-
-Config options
-==============
-These are the kernel configuration options:
- - CONFIG_CSDIO_VENDOR_ID;
- - CONFIG_CSDIO_DEVICE_ID.
-
-Dependencies
-============
-The Char SDIO Device Driver depends on Linux SDIO Host Driver.
-
-User space utilities
-====================
-None
-
-Other
-=====
-None
-
-Known issues
-============
-None
-
-To do
-=====
-Provide mechanism to support a number of SDIO devices simultaneously
-connected to different SDIO hosts.
diff --git a/Documentation/devicetree/bindings/arm/msm/acpuclock/clock-a7.txt b/Documentation/devicetree/bindings/arm/msm/acpuclock/clock-a7.txt
new file mode 100644
index 0000000..10eb0fe
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/acpuclock/clock-a7.txt
@@ -0,0 +1,37 @@
+* Qualcomm Application CPU clock driver
+
+clock-a7 is the driver for the Root Clock Generator (rcg) hw which controls
+the cpu rate. RCGs support selecting one of several clock inputs, as well as
+a configurable divider. This hw is different than normal rcgs in that it may
+optionally have a register which encodes the maximum rate supported by hw.
+
+Required properties:
+- compatible: "qcom,clock-a7-8226"
+- reg: pairs of physical address and region size
+- reg-names: "rcg-base" is expected
+- clock-names: list of names of clock inputs
+- qcom,speedX-bin-vZ:
+ A table of CPU frequency (Hz) to regulator voltage (uV) mapping.
+ Format: <freq uV>
+ This represents the max frequency possible for each possible
+ power configuration for a CPU that's binned as speed bin X,
+ speed bin revision Z. Speed bin values can be between [0-7]
+ and the version can be between [0-3].
+
+- cpu-vdd-supply: regulator phandle for cpu power domain.
+
+Optional properties:
+- reg-names: "efuse"
+
+Example:
+ qcom,acpuclk@f9011050 {
+ compatible = "qcom,clock-a7-8226";
+ reg = <0xf9011050 0x8>;
+ reg-names = "rcg_base";
+ cpu-vdd-supply = <&apc_vreg_corner>;
+
+ clock-names = "clk-4", "clk-5";
+ qcom,speed0-bin-v0 =
+ <384000000 1150000>,
+ <600000000 1200000>;
+ };
diff --git a/Documentation/devicetree/bindings/arm/msm/clock-krait-8974.txt b/Documentation/devicetree/bindings/arm/msm/clock-krait-8974.txt
new file mode 100644
index 0000000..d9ccb09
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/clock-krait-8974.txt
@@ -0,0 +1,100 @@
+Qualcomm MSM8974 Krait clock tree
+
+clock-krait-8974 is a device that represents the MSM8974 Krait subsystem
+clock tree. It lists the various power supplies that need to be scaled when
+the clocks are scaled and also other HW specific parameters like fmax tables,
+avs settings table, etc.
+
+Required properties:
+- compatible: Must be "qcom,clock-krait-8974"
+- reg: Pairs of physical base addresses and region sizes of
+ memory mapped registers.
+- reg-names: Names of the bases for the above registers. Expected
+ bases are:
+ "hfpll_l2_clk", "hfpll0_clk", ... "hfpllN_clk", "efuse"
+- cpuX-supply: The regulator powering the CPUX.
+- l2-dig-supply: The regulator powering the L2 digital logic.
+- hfpll-dig-supply: The regulator powering the HFPLL digital domains.
+- hfpll-analog-supply: The regulator powering the HFPLL analog domains.
+- qcom,l2-fmax: A table of L2 frequency to voltage mappings that
+ represents the max frequency (Hz) possible for each
+ supported voltage level (uV).
+- qcom,speedX-pvsY-bin-vZ:
+ A table of CPU frequency (Hz) to voltage (uV) and
+ current (uA) mapping that represents the max
+ frequency possible for each supported voltage level
+ for a CPU that's binned as speed bin X, PVS bin Y
+ based on characterization version Z. Speed and PVS
+ bin values can be between [0-7] and the version can
+ be between [0-3]
+
+Optional properties:
+- qcom,avs-tbl: A table of frequencies (Hz) and their corresponding
+ AVS DSCR register settings (32 bit value) to program
+ into the AVS HW. Frequencies with no AVS support do
+ not need to be listed in the table. If there is no
+ AVS support at all, then the whole property can be
+ omitted.
+- qcom,hfpll-config-val:
+ A 32 bit value to be programmed into the HFPLL
+ configuration control register.
+- qcom,hfpll-user-vco-mask:
+ The mask to be used when programming the VCO selection
+ bits in the user control register.
+- qcom,pvs-config-ver:
+ The version of the data in qcom,speedX-pvsY-bin-vZ.
+
+Example:
+ qcom,clock-krait@f9016000 {
+ compatible = "qcom,clock-krait-8974";
+ reg = <0xf9016000 0x20>,
+ <0xf908a000 0x20>,
+ <0xf909a000 0x20>,
+ <0xf90aa000 0x20>,
+ <0xf90ba000 0x20>,
+ <0xfc4b80b0 0x08>;
+ reg-names = "hfpll_l2_clk", "hfpll0_clk",
+ "hfpll1_clk", "hfpll2_clk",
+ "hfpll3_clk", "efuse";
+ cpu0-supply = <&krait0_vreg>;
+ cpu1-supply = <&krait1_vreg>;
+ cpu2-supply = <&krait2_vreg>;
+ cpu3-supply = <&krait3_vreg>;
+ l2-dig-supply = <&pm8841_s2_corner_ao>;
+ hfpll-dig-supply = <&pm8841_s2_corner_ao>;
+ hfpll-analog-supply = <&pm8941_l12_ao>;
+
+ qcom,l2-fmax =
+ < 576000000 4 /* svs_soc */ >,
+ < 1036800000 5 /* normal */ >,
+ < 1728000000 7 /* super_turbo */>;
+
+ qcom,avs-tbl =
+ < 300000000 0xfa70054 >,
+ < 1574400000 0xfa70100 >;
+
+ qcom,speed0-pvs0-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 815000 73 >,
+ .....
+ .....
+ < 1958400000 1100000 598 >;
+
+ qcom,speed0-pvs1-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 800000 73 >,
+ .....
+ .....
+ < 1958400000 1075000 598 >;
+
+ .....
+ .....
+
+ qcom,speed2-pvs6-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 750000 72 >,
+ .....
+ .....
+ < 2265600000 950000 691 >;
+
+ };
diff --git a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
index a0b2f6d..9af81da 100644
--- a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
+++ b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
@@ -56,38 +56,50 @@
- qcom,cpr-gcnt-time: The time for gate count in microseconds.
- qcom,cpr-apc-volt-step: The voltage in microvolt per CPR step, such as 5000uV.
-- qcom,pvs-fuse-redun-sel: Array of 4 elements to indicate where to read the bits and what value to
+- qcom,pvs-fuse-redun-sel: Array of 5 elements to indicate where to read the bits, what value to
compare with in order to decide if the redundant PVS fuse bits would be
- used instead of the original bits. The 4 elements with index [0..3] are:
+ used instead of the original bits and method to read fuse row, reading
+ register through SCM or directly. The 5 elements with index [0..4] are:
[0] => the fuse row number of the selector
[1] => LSB bit position of the bits
[2] => number of bits
[3] => the value to indicate redundant selection
+ [4] => fuse reading method, 0 for direct reading or 1 for SCM reading
When the value of the fuse bits specified by first 3 elements equals to
the value in 4th element, redundant PVS fuse bits should be selected.
- Otherwise, the original PVS bits should be selected.
-- qcom,pvs-fuse: Array of three elements to indicate the bits for PVS fuse. The array
- should have index and value like this:
+ Otherwise, the original PVS bits should be selected. If the 5th
+ element is 0, read the fuse row from register directly. Otherwise,
+ read it through SCM.
+- qcom,pvs-fuse: Array of 4 elements to indicate the bits for PVS fuse and read method.
+ The array should have index and value like this:
[0] => the PVS fuse row number
[1] => LSB bit position of the bits
[2] => number of bits
-- qcom,pvs-fuse-redun: Array of three elements to indicate the bits for redundant PVS fuse.
+ [3] => fuse reading method, 0 for direct reading or 1 for SCM reading
+- qcom,pvs-fuse-redun: Array of 4 elements to indicate the bits for redundant PVS fuse.
The array should have index and value like this:
[0] => the redundant PVS fuse row number
[1] => LSB bit position of the bits
[2] => number of bits
-
-- qcom,cpr-fuse-redun-sel: Array of 4 elements to indicate where to read the bits and what value to
+ [3] => fuse reading method, 0 for direct reading or 1 for SCM reading
+- qcom,cpr-fuse-redun-sel: Array of 5 elements to indicate where to read the bits, what value to
compare with in order to decide if the redundant CPR fuse bits would be
- used instead of the original bits. The 4 elements with index [0..3] are:
+ used instead of the original bits and method to read fuse row, using SCM
+ to read or read register directly. The 5 elements with index [0..4] are:
[0] => the fuse row number of the selector
[1] => LSB bit position of the bits
[2] => number of bits
[3] => the value to indicate redundant selection
+ [4] => fuse reading method, 0 for direct reading or 1 for SCM reading
When the value of the fuse bits specified by first 3 elements equals to
the value in 4th element, redundant CPR fuse bits should be selected.
- Otherwise, the original CPR bits should be selected.
-- qcom,cpr-fuse-row: Row number of CPR fuse
+ Otherwise, the original CPR bits should be selected. If the 5th element
+ is 0, read the fuse row from register directly. Otherwise, read it through
+ SCM.
+- qcom,cpr-fuse-row: Array of row number of CPR fuse and method to read that row. It should have
+ index and value like this:
+ [0] => the fuse row number
+ [1] => fuse reading method, 0 for direct reading or 1 for SCM reading
- qcom,cpr-fuse-bp-cpr-disable: Bit position of the bit to indicate if CPR should be disable
- qcom,cpr-fuse-bp-scheme: Bit position of the bit to indicate if it's a global/local scheme
- qcom,cpr-fuse-target-quot: Array of bit positions in fuse for Target Quotient of all corners.
@@ -100,7 +112,10 @@
[0] => bit position of the LSB bit for SVS RO select bits
[1] => bit position of the LSB bit for NOMINAL RO select bits
[2] => bit position of the LSB bit for TURBO RO select bits
-- qcom,cpr-fuse-redun-row: Row number of the redundant CPR fuse
+- qcom,cpr-fuse-redun-row: Array of row number of redundant CPR fuse and method to read that
+ row. It should have index and value like this:
+ [0] => the redundant fuse row number
+ [1] => the value to indicate reading the fuse row directly or using SCM
- qcom,cpr-fuse-redun-target-quot: Array of bit positions in fuse for redundant Target Quotient of all corners.
It should have index and value like this:
[0] => bit position of the LSB bit for redundant SVS target quotient
@@ -132,9 +147,76 @@
is present, and vise versa.
- qcom,cpr-enable: Present: CPR enabled by default.
Not Present: CPR disable by default.
-- qcom,use-tz-api: Present: CPR reads efuse parameters through trustzone API.
- Not Present: CPR reads efuse parameters directly.
-
+- qcom,cpr-fuse-cond-min-volt-sel: Array of 5 elements to indicate where to read the bits, what value to
+ compare with in order to decide if the conditional minimum apc voltage needs
+ to be applied and the fuse reading method.
+ The 5 elements with index[0..4] are:
+ [0] => the fuse row number;
+ [1] => LSB bit position of the bits;
+ [2] => number of the bits;
+ [3] => the expected data to read;
+ [4] => fuse reading method, 0 for direct reading or 1 for SCM reading;
+ When the value of the fuse bits specified by first 3 elements is not equal to
+ the value in 4th element, then set the apc voltage for all parts running
+ at each voltage corner to be not lower than the voltage defined
+ using "qcom,cpr-cond-min-voltage".
+- qcom,cpr-cond-min-voltage: Minimum voltage in microvolts for SVS, NOM and TURBO mode if the fuse bits
+ defined in qcom,cpr-fuse-cond-min-volt-sel have not been programmed with the
+ expected data. This is required if cpr-fuse-cond-min-volt-sel is present.
+- qcom,cpr-fuse-uplift-sel: Array of 5 elements to indicate where to read the bits, what value to
+ compare with in order to enable or disable the pvs voltage uplift workaround,
+ and the fuse reading method.
+ The 5 elements with index[0..4] are:
+ [0]: => the fuse row number of the selector;
+ [1]: => LSB bit position of the bits;
+ [2]: => number of the bits;
+ [3]: => the value to indicate if the apc pvs voltage uplift workaround will
+ be enabled;
+ [4]: => fuse reading method, 0 for direct reading or 1 for SCM reading.
+ When the value of the fuse bits specified by first 3 elements equals to the
+ value in 4th element, the pvs voltage uplift workaround will be enabled.
+- qcom,speed-bin-fuse-sel: Array of 4 elements to indicate where to read the speed bin of the processor,
+ and the fuse reading method.
+ The 4 elements with index[0..3] are:
+ [0]: => the fuse row number of the selector;
+ [1]: => LSB bit position of the bits;
+ [2]: => number of the bits;
+ [3]: => fuse reading method, 0 for direct reading or 1 for SCM reading.
+ This is required if cpr-fuse-uplift-disable-sel is present.
+- qcom,cpr-uplift-voltage: Uplift in microvolts used for increasing pvs init voltage. If this property is present,
+ This is required if cpr-fuse-uplift-disable-sel is present.
+- qcom,cpr-uplift-max-volt: Maximum voltage in microvolts used for pvs voltage uplift workaround to limit
+ the maximum pvs voltage.
+ This is required if cpr-fuse-uplift-disable-sel is present.
+- qcom,cpr-uplift-quotient: Three numbers used for pvs voltage uplift workaround to be added to the target
+ quotient for each corner.
+ The 3 quotient increment with index[0..2] are:
+ [0]: => for SVS corner target quotient;
+ [1]: => for NORM corner target quotient;
+ [2]: => for TURBO corner target quotient;
+ This is required if cpr-fuse-uplift-disable-sel is present.
+- qcom,cpr-uplift-speed-bin: The speed bin value corresponding to one type of processor which needs to apply the
+ pvs voltage uplift workaround.
+ This is required if cpr-fuse-uplift-disable-sel is present.
+- qcom,cpr-quot-adjust-table: Array of triples in which each triple indicates the speed bin of the CPU, the virtual
+ corner to use and the quotient adjustment.
+ The 3 elements in one triple are:
+ [0]: => the speed bin of the CPU.
+ [1]: => the virtual voltage corner to use.
+ [2]: => the quotient adjustment for the corresponding virtual corner.
+ If the speed bin in a triple is equal to the speed bin of the CPU, the adjustment would
+ be subtracted from the quotient value of the voltage corner when the CPU is running at
+ that virtual corner. Each virtual corner value must be in the range 1 to the number of
+ elements in qcom,cpr-corner-map.
+- qcom,cpr-corner-map: Array of elements of fuse corner value for each virtual corner.
+ The location or 1-based index of an element in the list corresponds to
+ the virtual corner value. For example, the first element in the list is the fuse corner
+ value that virtual corner 1 maps to.
+ This is required if qcom,cpr-quot-adjust-table is present.
+- qcom,cpr-quotient-adjustment: Present: CPR adjusts quotient value. The
+ adjustment equals to the quotient adjustment
+ in millivolts multiply the KV value.
+ Not Present: CPR will not adjust quotient value.
Example:
apc_vreg_corner: regulator@f9018000 {
@@ -147,9 +229,9 @@
regulator-min-microvolt = <1>;
regulator-max-microvolt = <3>;
- qcom,pvs-fuse = <22 6 5>;
- qcom,pvs-fuse-redun-sel = <22 24 3 2>;
- qcom,pvs-fuse-redun = <22 27 5>;
+ qcom,pvs-fuse = <22 6 5 1>;
+ qcom,pvs-fuse-redun-sel = <22 24 3 2 1>;
+ qcom,pvs-fuse-redun = <22 27 5 1>;
qcom,pvs-init-voltage = <1330000 1330000 1330000 1320000
1310000 1300000 1290000 1280000
@@ -180,14 +262,27 @@
qcom,cpr-gcnt-time = <1>;
qcom,cpr-apc-volt-step = <5000>;
- qcom,cpr-fuse-row = <138>;
+ qcom,cpr-fuse-row = <138 1>;
qcom,cpr-fuse-bp-cpr-disable = <36>;
qcom,cpr-fuse-bp-scheme = <37>;
qcom,cpr-fuse-target-quot = <24 12 0>;
qcom,cpr-fuse-ro-sel = <54 38 41>;
- qcom,cpr-fuse-redun-sel = <138 57 1 1>;
- qcom,cpr-fuse-redun-row = <139>;
+ qcom,cpr-fuse-redun-sel = <138 57 1 1 1>;
+ qcom,cpr-fuse-redun-row = <139 1>;
qcom,cpr-fuse-redun-target-quot = <24 12 0>;
qcom,cpr-fuse-redun-ro-sel = <46 36 39>;
+ qcom,cpr-fuse-cond-min-volt-sel = <54 42 6 7 1>;
+ qcom,cpr-cond-min-voltage = <1140000>;
+ qcom,cpr-fuse-uplift-sel = <22 53 1 0 0>;
+ qcom,cpr-uplift-voltage = <50000>;
+ qcom,cpr-uplift-quotient = <0 0 120>;
+ qcom,cpr-uplift-max-volt = <1350000>;
+ qcom,cpr-uplift-speed-bin = <1>;
+ qcom,speed-bin-fuse-sel = <22 0 3 0>;
+ qcom,cpr-corner-map = <1 1 2 2 3 3 3 3 3 3 3 3>;
+ qcom,cpr-quot-adjust-table = <1 1 0>, <1 2 0>, <1 3 0>,
+ <1 4 0>, <1 5 450>, <1 6 375>,
+ <1 7 300>, <1 8 225>, <1 9 187>,
+ <1 10 150>, <1 11 75>, <1 12 0>;
};
diff --git a/Documentation/devicetree/bindings/arm/msm/cpubw.txt b/Documentation/devicetree/bindings/arm/msm/cpubw.txt
new file mode 100644
index 0000000..1dc3835
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/cpubw.txt
@@ -0,0 +1,30 @@
+MSM CPU bandwidth device
+
+cpubw is a device that represents the CPU subsystem master ports in a MSM SoC
+and the related info that is needed to make CPU to DDR bandwidth votes.
+
+Required properties:
+- compatible: Must be "qcom,cpubw"
+- qcom,cpu-mem-ports: A list of tuples where each tuple consists of a bus
+ master (CPU subsystem) port number and a bus slave
+ (memory) port number.
+- qcom,bw-tbl: A list of meaningful instantaneous bandwidth values
+ (in MB/s) that can be requested from the CPU
+ subsystem to DDR. The list of values depend on the
+ supported DDR frequencies and the bus widths.
+
+Example:
+
+ qcom,cpubw {
+ compatible = "qcom,cpubw";
+ qcom,cpu-mem-ports = <1 512>, <2 512>;
+ qcom,bw-tbl =
+ < 572 /* 75 MHz */ >,
+ < 1144 /* 150 MHz */ >,
+ < 1525 /* 200 MHz */ >,
+ < 2342 /* 307 MHz */ >,
+ < 3509 /* 460 MHz */ >,
+ < 4684 /* 614 MHz */ >,
+ < 6103 /* 800 MHz */ >,
+ < 7102 /* 931 MHz */ >;
+ };
diff --git a/Documentation/devicetree/bindings/arm/msm/kraitbw-l2pm.txt b/Documentation/devicetree/bindings/arm/msm/kraitbw-l2pm.txt
new file mode 100644
index 0000000..17d55d4
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/kraitbw-l2pm.txt
@@ -0,0 +1,18 @@
+MSM Krait L2 performance monitor counters for bandwidth measurement device
+
+krait-l2pm is a device that represents the Krait L2 PM counters that can be
+used to measure the bandwidth of read/write traffic from the Krait CPU
+subsystem.
+
+Required properties:
+- compatible: Must be "qcom,kraitbw_l2pm"
+- interrupts: Lists the L2 PM counter overflow IRQ.
+- qcom,bytes-per-beat: The number of bytes transferred in one data beat from
+ the Krait CPU subsystem.
+
+Example:
+ qcom,kraitbw-l2pm {
+ compatible = "qcom,kraitbw-l2pm";
+ interrupts = <0 1 1>;
+ qcom,bytes-per-beat = <8>;
+ };
diff --git a/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
index 917ea75..0696730 100644
--- a/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
+++ b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
@@ -1,52 +1,106 @@
* Low Power Management Levels
The application processor in MSM can do a variety of C-States for low power
-management. These C-States are invoked by the CPUIdle framework when the core
-becomes idle. But based on the time available until the next scheduled wakeup,
-the system can do several low power modes. The combination is captured in the
-device tree as lpm-level.
+management. The LPM module performs the CPU and System low power modes based
+on it latency and residency information of the individual CPU/System low power
+levels.
-The required nodes for lpm-levels are:
+The first level node represents the properties of the system and includes
+second level node to represent the low power modes of cpu and system.
+
+[First Level Nodes]
+Required properties:
- compatible: "qcom,lpm-levels"
-- reg: The numeric level id
+
+The optional nodes for the First level nodes are:
+- qcom,no-l2-saw: Indicates if this target has an L2 SAW (SPM and AVS wrapper).
+- qcom,default-l2-state: Indicates what the default low power state of the L2
+ SAW should be. This property should be mentioned when there is
+ a L2 saw.
+- qcom,allow-synced-levels: Indicates if certain low power modes should be
+ synchronized across all cores so as to configure a system
+ low power mode.
+
+[Second Level Nodes]
+Required properties to define CPU low power modes :
+- compatible = "qcom,cpu-modes";
- qcom,mode: The sleep mode of the processor, values for the property are:
"wfi" - Wait for Interrupt
- "ramp_down_and_wfi" - Ramp down and wait for interrupt
+ "retention" - Retention
"standalone_pc" - Standalone power collapse
"pc" - Power Collapse
- "retention" - Retention
- "pc_suspend" - Suspended Power Collapse
- "pc_no_xo_shutdown" - Power Collapse with no XO shutdown
+- qcom,latency-us: The latency in handling the interrupt if this level was
+ chosen, in uSec
+- qcom,ss-power: The steady state power expelled when the processor is in this
+ level in mWatts
+- qcom,energy-overhead: The energy used up in entering and exiting this level
+ in mWatts.uSec
+- qcom,time-overhead: The time spent in entering and exiting this level in uS
+
+Required propertieis to define System low power mode :
+- compatible: "qcom,system-modes"
- qcom,l2: The state of L2 cache. Values are:
"l2_cache_pc" - L2 cache in power collapse
- "l2_cache_pc_no_rpm" - L2 cache in power collapse. This mode wouldn't inform the RPM
+ "l2_cache_pc_no_rpm" - L2 cache in power collapse. This mode
+ wouldn't inform the RPM
"l2_cache_retenetion" - L2 cache in retention
"l2_cache_gdhs" - L2 cache in GDHS
"l2_cache_active" - L2 cache in active mode
-- qcom,latency-us: The latency in handling the interrupt if this level was
- chosen, in uSec
-- qcom,ss-power: The steady state power expelled when the processor is in this
- level in mWatts
-- qcom,energy-overhead: The energy used up in entering and exiting this level
- in mWatts.uSec
-- qcom,time-overhead: The time spent in entering and exiting this level in uS
-The optional nodes for lpm-levels are :
-- qcom,no-l2-saw: Indicates if this target has an L2 SAW (SPM and AVS wrapper).
-- qcom,default-l2-state: Indicates what the default low power state of the L2 SAW should be. This property is used only when there is an L2 SAW.
+- qcom,latency-us: The latency in handling the interrupt if this level was
+ chosen, in uSec
+- qcom,ss-power: The steady state power expelled when the processor is in this
+ level in mWatts
+- qcom,energy-overhead: The energy used up in entering and exiting this level
+ in mWatts.uSec
+- qcom,time-overhead: The time spent in entering and exiting this level in uS
+- qcom,min-cpu-mode: The min cpu sleep mode at which the given system level is
+ valid. All cpus should have entered this low power mode before
+ this system level can be chosen.
Example:
-
qcom,lpm-levels {
- qcom,no-l2-saw;
- qcom,lpm-level@0 {
- reg = <0>;
- qcom,mode = "wfi";
- qcom,l2 = "l2_cache_active";
- qcom,latency-us = <100>;
- qcom,ss-power = <650>;
- qcom,energy-overhead = <801>;
- qcom,time-overhead = <200>;
- };
+ compatible = "qcom,lpm-levels";
+ qcom,default-l2-state = "l2_cache_retention";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ qcom,cpu-modes {
+ compatible = "qcom,cpu-modes";
+ qcom,cpu-mode@0 {
+ qcom,mode = "wfi";
+ qcom,latency-us = <1>;
+ qcom,ss-power = <715>;
+ qcom,energy-overhead = <17700>;
+ qcom,time-overhead = <2>;
+ };
+
+ qcom,cpu-mode@1 {
+ qcom,mode = "retention";
+ qcom,latency-us = <35>;
+ qcom,ss-power = <542>;
+ qcom,energy-overhead = <34920>;
+ qcom,time-overhead = <40>;
+ };
+ };
+ qcom,system-modes {
+ compatible = "qcom,system-modes";
+
+ qcom,system-mode@0 {
+ qcom,l2 = "l2_cache_gdhs";
+ qcom,latency-us = <20000>;
+ qcom,ss-power = <163>;
+ qcom,energy-overhead = <1577736>;
+ qcom,time-overhead = <5067>;
+ };
+
+ qcom,system-mode@1 {
+ qcom,l2 = "l2_cache_pc";
+ qcom,latency-us = <30000>;
+ qcom,ss-power = <83>;
+ qcom,energy-overhead = <2274420>;
+ qcom,time-overhead = <6605>;
+ };
+ };
};
diff --git a/Documentation/devicetree/bindings/arm/msm/msm-cpufreq.txt b/Documentation/devicetree/bindings/arm/msm/msm-cpufreq.txt
new file mode 100644
index 0000000..fed49c9
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/msm-cpufreq.txt
@@ -0,0 +1,36 @@
+Qualcomm MSM CPUfreq device
+
+msm-cpufreq is a device that represents the list of useable CPU frequencies
+and the cache frequency and/or memory bandwidth required for each of them. It
+also captures the bus master/slave ports towards which the bus bandwidth
+requests need to be made to ensure the required memory bandwidth.
+
+Required properties:
+- compatible: Must be "qcom,msm-cpufreq"
+- qcom,cpufreq-table: A list of tuples where each tuple consists of a
+ usable CPU frequency (KHz), an optional cache
+ frequency (KHz) and a mandatory memory bandwidth
+ value (MBPS) listed in that order. The cache
+ frequencies shall not be listed if the device cannot
+ run the cache asynchronous to one or more CPUs.
+
+Example:
+ qcom,msm-cpufreq@0 {
+ regs = <0 4>
+ compatible = "qcom,msm-cpufreq";
+ qcom,cpufreq-table =
+ < 300000 300000 600 >,
+ < 422400 422400 1200 >,
+ < 652800 499200 1600 >,
+ < 729600 576000 2456 >,
+ < 883200 576000 2456 >,
+ < 960000 960000 3680 >,
+ < 1036800 1036800 3680 >,
+ < 1190400 1036800 3680 >,
+ < 1267200 1267200 6400 >,
+ < 1497600 1497600 6400 >,
+ < 1574400 1574400 6400 >,
+ < 1728000 1651200 6400 >,
+ < 1958400 1728000 7448 >,
+ < 2265600 1728000 7448 >;
+ };
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_bus.txt b/Documentation/devicetree/bindings/arm/msm/msm_bus.txt
index fbf1a1f..6283a82 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm_bus.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm_bus.txt
@@ -101,7 +101,7 @@
other parameters used in Limiter and Regular mode
for static BKE configuration. It is defined in KBps.
qcom,bimc,gp: Grant Period for configuring a master in limiter
- mode. This is an integer value in micro-seconds.
+ mode. This is an integer value in nano-seconds.
qcom,bimc,thmp: Medium threshold percentage for BIMC masters.
This percentage is used to calculate medium threshold
value for BIMC Masters in Limiter mode for static
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_ion.txt b/Documentation/devicetree/bindings/arm/msm/msm_ion.txt
index 2d83614..d2e0916 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm_ion.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm_ion.txt
@@ -17,6 +17,16 @@
Required properties for Ion heaps
- reg: The ID of the ION heap.
+- qcom,ion-heap-type: The heap type to use for this heap. Should be one of
+ the following:
+ - "SYSTEM"
+ - "SYSTEM_CONTIG"
+ - "CARVEOUT"
+ - "CHUNK"
+ - "CP"
+ - "DMA"
+ - "SECURE_DMA"
+ - "REMOVED"
Optional properties for Ion heaps
@@ -27,6 +37,8 @@
- qcom,memory-reservation-size: size of reserved memory for the ION heap.
- qcom,memory-reservation-type: type of memory to be reserved
(see memory-reserve.txt for information about memory reservations)
+- qcom,default-prefetch-size: Based value to be used for prefetching
+ optimizations. Ignored if the heap does not support prefetching.
Example:
qcom,ion {
@@ -34,16 +46,17 @@
#address-cells = <1>;
#size-cells = <0>;
- qcom,ion-heap@30 { /* SYSTEM HEAP */
- reg = <30>;
+ qcom,ion-heap@25 {
+ reg = <25>;
+ qcom,ion-heap-type = "SYSTEM";
};
qcom,ion-heap@8 { /* CP_MM HEAP */
compatible = "qcom,msm-ion-reserve";
reg = <8>;
qcom,heap-align = <0x1000>;
- qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
- qcom,memory-reservation-size = <0x7800000>;
+ linux,contiguous-region = <&secure_mem>;
+ qcom,ion-heap-type = "SECURE_DMA";
};
qcom,ion-heap@29 { /* FIRMWARE HEAP */
@@ -53,5 +66,6 @@
qcom,heap-adjacent = <8>;
qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
qcom,memory-reservation-size = <0xA00000>;
-
+ qcom,ion-heap-type = "CARVEOUT";
+ };
};
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
index 3947f75..15b94ca 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
@@ -43,6 +43,29 @@
- qcpm,cpu-sensors: List of type names in thermal zone device struct which maps
to cpu0, cpu1, cpu2, cpu3 in sequence depending on how many
cpus there are.
+- qcom,freq-mitigation-temp: Threshold temperature to mitigate
+ the CPU max frequency in degC. This will be
+ used when polling based frequency control is disabled.
+ The difference between freq-mitigation-temp
+ and limit-temp is that limit-temp is used during
+ early boot prior to thermal_sys being available for registering
+ temperature thresholds. Also, this emergency frequency
+ mitigation is a single step frequency mitigation to a predefined value
+ as opposed to the step by step frequency mitigation during boot-up.
+- qcom,freq-mitigation-temp-hysteresis: Degrees C below which thermal will not mitigate the
+ cpu max frequency.
+- qcom,freq-mitigation-value: The frequency value (in kHz) to which the thermal
+ should mitigate the CPU, when the freq-mitigation-temp
+ threshold is reached.
+- qcom,freq-mitigation-control-mask: The frequency mitigation bitmask that will be
+ used to determine if KTM should do emergency frequency
+ mitigation for a core or not. A mask of 0x00 indicates the
+ mitigation is disabled for all the cores and a mask of 0x05
+ indicates this mitigation is enabled for cpu-0 and cpu-2.
+ Note: For KTM's frequency mitigation to work, the data for all the
+ above four properties (qcom,freq-mitigation-temp; qcom,
+ freq-mitigation-temp-hysteresis; qcom,freq-mitigation-value and
+ qcom,freq-mitigation-control-mask) should be populated.
- qcom,vdd-restriction-temp: When temperature is below this threshold, will
enable vdd restriction which will set higher voltage on
key voltage rails, in degC.
@@ -67,6 +90,20 @@
phandle_of_regulator is defined by reuglator device tree.
Optional child nodes
+- qti,pmic-opt-curr-temp: Threshold temperature for requesting optimum current (request
+ dual phase) for rails with PMIC, in degC. If this property exists,
+ then the properties, qti,pmic-opt-curr-temp-hysteresis and
+ qti,pmic-opt-curr-regs should also be defined to enable this
+ feature.
+- qti,pmic-opt-curr-temp-hysteresis: Degree below the threshold to disable the optimum
+ current request for a rail, in degC. If this property exists,
+ then the properties, qti,pmic-opt-curr-temp and
+ qti,pmic-opt-curr-regs should also be defined to enable
+ this feature.
+- qti,pmic-opt-curr-regs: Name of the rails for which the optimum current should be
+ requested. If this property exists, then the properties,
+ qti,pmic-opt-curr-temp and qti,pmic-opt-curr-temp-hysteresis
+ should also be defined to enable this feature.
- qcom,<vdd restriction child node name>: Define the name of the child node.
If this property exisits, qcom,vdd-rstr-reg, qcom,levels
need to exist. qcom,min-level is optional if qcom,freq-req
@@ -97,11 +134,18 @@
qcom,hotplug-temp-hysteresis = <20>;
qcom,cpu-sensors = "tsens_tz_sensor5", "tsens_tz_sensor6",
"tsens_tz_sensor7", "tsens_tz_sensor8";
+ qcom,freq-mitigation-temp = <110>;
+ qcom,freq-mitigation-temp-hysteresis = <20>;
+ qcom,freq-mitigation-value = <960000>;
+ qcom,freq-mitigation-control-mask = <0x01>;
qcom,pmic-sw-mode-temp = <90>;
qcom,pmic-sw-mode-temp-hysteresis = <80>;
qcom,pmic-sw-mode-regs = "vdd-dig";
qcom,vdd-restriction-temp = <5>;
qcom,vdd-restriction-temp-hysteresis = <10>;
+ qti,pmic-opt-curr-temp = <85>;
+ qti,pmic-opt-curr-temp-hysteresis = <10>;
+ qti,pmic-opt-curr-regs = "vdd-dig";
vdd-dig-supply=<&pm8841_s2_floor_corner>
qcom,vdd-dig-rstr{
diff --git a/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt b/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
index 82e7e2a..795af3b 100644
--- a/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
+++ b/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
@@ -25,6 +25,11 @@
- qcom,saw-turns-off-pll: Version of SAW2.1 or can turn off the HFPLL, when
doing power collapse and so the core need to switch to Global PLL before
PC.
+- qcom,synced-clocks: Indicates that all cpus running off a single clock source and to
+ instantiate the necessary clock source.
+- qcom,cpus-as-clocks: Indicates that the CPU clocks are implemented using clock APIs and should
+ switch to using generic clock APIs to enable/disable power collapse.
+ If set, the pm driver would ignore clock API errors and continue to call acpuclock API directly.
- qcom,pc-resets-timer: Indicates that the timer gets reset during power collapse.
Example:
diff --git a/Documentation/devicetree/bindings/arm/msm/spm-v2.txt b/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
index d9a0d59..f969e2f 100644
--- a/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
+++ b/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
@@ -40,6 +40,8 @@
- qcom,saw2-spm-cmd-wfi: The WFI command sequence
- qcom,saw2-spm-cmd-ret: The Retention command sequence
- qcom,saw2-spm-cmd-spc: The Standalone PC command sequence
+- qcom,saw2-spm-cmd-pc-no-rpm: The Power Collapse command sequence where APPS
+ proc won't inform the RPM.
- qcom,saw2-spm-cmd-pc: The Power Collapse command sequence
- qcom,saw2-spm-cmd-gdhs: L2 GDHS command sequence
- qcom,L2-spm-is-apcs-master: Boolean indicates if the target uses L2 SAW to
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index 1a44f5a..113ded8 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -142,6 +142,8 @@
0 = default value.
- qcom,mdss-dsi-bl-max-level: Specifies the max backlight level supported by the panel.
255 = default value.
+- qcom,mdss-brightness-max-level: Specifies the max brightness level supported.
+ 255 = default value.
- qcom,mdss-dsi-interleave-mode: Specifies interleave mode.
0 = default value.
- qcom,mdss-dsi-panel-type: Specifies the panel operating mode.
@@ -178,34 +180,33 @@
- qcom,mdss-dsi-bllp-power-mode: Boolean to determine DSI lane state during
blanking low power period (BLLP) mode.
- qcom,mdss-dsi-traffic-mode: Specifies the panel traffic mode.
- 0 = non burst with sync pulses (default mode).
- 1 = non burst with sync start event.
- 2 = burst mode.
+ "non_burst_sync_pulse" = non burst with sync pulses (default).
+ "non_burst_sync_event" = non burst with sync start event.
+ "burst_mode" = burst mode.
- qcom,mdss-dsi-pixel-packing: Specifies if pixel packing is used (in case of RGB666).
- 0 = Tight packing (default value).
- 1 = Loose packing.
+ "tight" = Tight packing (default value).
+ "loose" = Loose packing.
- qcom,mdss-dsi-virtual-channel-id: Specifies the virtual channel identefier.
0 = default value.
- qcom,mdss-dsi-color-order: Specifies the R, G and B channel ordering.
- 0 = DSI_RGB_SWAP_RGB (default value)
- 1 = DSI_RGB_SWAP_RBG
- 2 = DSI_RGB_SWAP_BGR
- 3 = DSI_RGB_SWAP_BRG
- 4 = DSI_RGB_SWAP_GRB
- 5 = DSI_RGB_SWAP_GBR
+ "rgb_swap_rgb" = DSI_RGB_SWAP_RGB (default value)
+ "rgb_swap_rbg" = DSI_RGB_SWAP_RBG
+ "rgb_swap_brg" = DSI_RGB_SWAP_BRG
+ "rgb_swap_grb" = DSI_RGB_SWAP_GRB
+ "rgb_swap_gbr" = DSI_RGB_SWAP_GBR
- qcom,mdss-dsi-lane-0-state: Boolean that specifies whether data lane 0 is enabled.
- qcom,mdss-dsi-lane-1-state: Boolean that specifies whether data lane 1 is enabled.
- qcom,mdss-dsi-lane-2-state: Boolean that specifies whether data lane 2 is enabled.
- qcom,mdss-dsi-lane-3-state: Boolean that specifies whether data lane 3 is enabled.
- qcom,mdss-dsi-lane-map: Specifies the data lane swap configuration.
- 0 = <0 1 2 3> (default value)
- 1 = <3 0 1 2>
- 2 = <2 3 0 1>
- 3 = <1 2 3 0>
- 4 = <0 3 2 1>
- 5 = <1 0 3 2>
- 6 = <2 1 0 3>
- 7 = <3 2 1 0>
+ "lane_map_0123" = <0 1 2 3> (default value)
+ "lane_map_3012" = <3 0 1 2>
+ "lane_map_2301" = <2 3 0 1>
+ "lane_map_1230" = <1 2 3 0>
+ "lane_map_0321" = <0 3 2 1>
+ "lane_map_1032" = <1 0 3 2>
+ "lane_map_2103" = <2 1 0 3>
+ "lane_map_3210" = <3 2 1 0>
- qcom,mdss-dsi-t-clk-post: Specifies the byte clock cycles after mode switch.
0x03 = default value.
- qcom,mdss-dsi-t-clk-pre: Specifies the byte clock cycles before mode switch.
@@ -214,16 +215,16 @@
0 = stream 0 (default)
1 = stream 1
- qcom,mdss-dsi-mdp-trigger: Specifies the trigger mechanism to be used for MDP path.
- 0 = no trigger
- 2 = Tear check signal line used for trigger
- 4 = Triggered by software (default)
- 6 = Software trigger and TE
+ "none" = no trigger
+ "trigger_te" = Tear check signal line used for trigger
+ "trigger_sw" = Triggered by software (default)
+ "trigger_sw_te" = Software trigger and TE
- qcom,mdss-dsi-dma-trigger: Specifies the trigger mechanism to be used for DMA path.
- 0 = no trigger
- 2 = Tear check signal line used for trigger
- 4 = Triggered by software (default)
- 5 = Software trigger and start/end of frame trigger.
- 6 = Software trigger and TE
+ "none" = no trigger
+ "trigger_te" = Tear check signal line used for trigger
+ "trigger_sw" = Triggered by software (default)
+ "trigger_sw_seof" = Software trigger and start/end of frame trigger.
+ "trigger_sw_te" = Software trigger and TE
- qcom,mdss-dsi-panel-framerate: Specifies the frame rate for the panel.
60 = 60 frames per second (default)
- qcom,mdss-dsi-panel-clockrate: Specifies the panel clock speed in Hz.
@@ -250,7 +251,12 @@
as below:
--> Reset GPIO value
--> Sleep value (in ms)
-
+- qcom,mdss-dsi-lp11-init: Boolean used to enable the DSI clocks and data lanes (low power 11)
+ before issuing hardware reset line.
+- qcom,mdss-dsi-init-delay-us: Delay in microseconds(us) before performing any DSI activity in lp11
+ mode. This master delay (t_init_delay as per DSI spec) should be sum
+ of DSI internal delay to reach fuctional after power up and minimum
+ delay required by panel to reach functional.
Note, if a given optional qcom,* binding is not present, then the driver will configure
the default values specified.
@@ -343,5 +349,7 @@
qcom,mdss-dsi-panel-mode-gpio-state = "low";
qcom,partial-update-enabled;
qcom,mdss-dsi-reset-sequence = <1 2>, <0 10>, <1 10>;
+ qcom,mdss-dsi-lp11-init;
+ qcom,mdss-dsi-init-delay-us = <100>;
};
};
diff --git a/Documentation/devicetree/bindings/fb/mdss-edp.txt b/Documentation/devicetree/bindings/fb/mdss-edp.txt
index e564cd5..fd8d14f 100644
--- a/Documentation/devicetree/bindings/fb/mdss-edp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-edp.txt
@@ -23,6 +23,12 @@
interface is mapped.
- gpio-panel-hpd : gpio pin use for edp hpd
+
+Optional properties:
+- qcom,cont-splash-enabled: Boolean used to enable continuous splash mode.
+- qcom,mdss-brightness-max-level: Specifies the max brightness level supported.
+ 255 = default value.
+
Example:
mdss_edp: qcom,mdss_edp@fd923400 {
compatible = "qcom,mdss-edp";
diff --git a/Documentation/devicetree/bindings/fb/mdss-mdp.txt b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
index a4e61e8..9530c62 100644
--- a/Documentation/devicetree/bindings/fb/mdss-mdp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
@@ -146,7 +146,18 @@
total numbers of MMBs per pipe while values, if
any, following first one denotes indexes of MMBs
to that RGB pipe.
-
+- qcom,max-bandwidth-low-kbps: This value indicates the max bandwidth in KB
+ that can be supported without underflow.
+ This is a low bandwidth threshold which should
+ be applied in most scenarios to be safe from
+ underflows when unable to satisfy bandwith
+ requirements.
+- qcom,max-bandwidth-high-kbps: This value indicates the max bandwidth in KB
+ that can be supported without underflow.
+ This is a high bandwidth threshold which can be
+ applied in scenarios where panel interface can
+ be more tolerant to memory latency such as
+ command mode panels.
Optional subnodes:
Child nodes representing the frame buffer virtual devices.
@@ -186,6 +197,10 @@
vdd-supply = <&gdsc_mdss>;
vdd-cx-supply = <&pm8841_s2_corner>;
batfet-supply = <&pm8941_chg_batif>;
+
+ qcom,max-bandwidth-low-kbps = <2300000>;
+ qcom,max-bandwidth-high-kbps = <3000000>;
+
qcom,max-clk-rate = <320000000>;
qcom,vbif-settings = <0x0004 0x00000001>,
<0x00D8 0x00000707>;
diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
index aa0aa8c..656f3a4 100644
--- a/Documentation/devicetree/bindings/gpu/adreno.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno.txt
@@ -64,7 +64,7 @@
Optional Properties:
- qcom,initial-powerlevel: This value indicates which qcom,gpu-pwrlevel should be used at start time
and when coming back out of resume
-- qcom,step-pwrlevel: How many qcom,gpu-pwrlevel should be decremented at once
+- qcom,bus-control: Boolean. Enables an independent bus vote from the gpu frequency
- qcom,idle-timeout: This property represents the time in microseconds for idle timeout.
- qcom,chipid: If it exists this property is used to replace
the chip identification read from the GPU hardware.
diff --git a/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
index ae7d039..1be5504 100644
--- a/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
+++ b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
@@ -65,6 +65,8 @@
3 : Returns current across 0.1 ohm resistor.
4 : Returns XO thermistor voltage in degree's Centigrade.
5 : Returns result in degC for 150k pull-up.
+ 9 : Conversion to temperature based on -15~55 allowable
+ battery charging tempeature setting for btm parameters.
- qcom,hw-settle-time : Settling period for the channel before ADC read.
Select from the following unsigned int.
0 : 0us
diff --git a/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt b/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt
index fdba7c2..f2ca95b 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt
@@ -30,6 +30,7 @@
min y, max x and max y values.
- goodix,i2c-pull-up : To specify pull up is required.
- goodix,no-force-update : To specify force update is allowed.
+ - goodix,enable-power-off : Power off touchscreen during suspend.
- goodix,button-map : Button map of key codes. The number of key codes
depend on panel.
- goodix,cfg-data0 : Touch screen controller config data group 0. Ask vendor
@@ -50,6 +51,7 @@
to provide that.
- goodix,cfg-data5 : Touch screen controller config data group 5. Ask vendor
to provide that.
+ - goodix,fw-name : Touch screen controller firmware file name.
Example:
i2c@f9927000 {
goodix@5d {
@@ -84,5 +86,6 @@
20 21 22 24 26 28 29 2A FF FF
FF FF FF FF FF FF FF 22 22 22
22 22 22 FF 07 01];
+ goodix,fw_name = "gtp_fw.bin";
};
};
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp.txt b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
index af6a0b5..749c594 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
@@ -10,13 +10,13 @@
node will further contain the type of LED supported and its
properties. At least one child node is required for each LED
module. Each must have the required properties below, in addition
-to the properties for the LED type, WLED, Flash or RGB.
+to the properties for the LED type, WLED, Flash, RGB and MPP.
Required properties for each child node, WLED, Flash and RGB:
- compatible : should be "qcom,leds-qpnp"
- qcom,id : must be one of values supported in enum qpnp_led
- label : type of led that will be used, ie "wled"
-- qcom,max-current : maximum current that the LED can sustain
+- qcom,max-current : maximum current that the LED can sustain in mA
- linux,name : name of the led that is used in led framework
WLED is primarily used as display backlight. Display subsystem uses
@@ -85,6 +85,7 @@
- qcom,vin-ctrl: select input source, supported values are 0 to 3
- qcom,use-blink: Use blink sysfs entry for switching into lpg mode. For optimal use, set default mode to pwm. All required lpg parameters must be supplied.
- qcom,min-brightness - Lowest possible brightness supported on this LED other than 0.
+- qcom,current-setting: default current value for wled used as button backlight in mA
Required properties for PWM mode only:
- qcom,pwm-channel: pwm channel the led will operate on
@@ -131,6 +132,22 @@
Example:
+ qcom,leds@a100 {
+ status = "okay";
+ qcom,led_mpp_2 {
+ label = "mpp";
+ linux,name = "button-backlight";
+ linux,default-trigger = "hr-trigger";
+ qcom,default-state = "off";
+ qcom,current-setting = <20>;
+ qcom,max-current = <40>;
+ qcom,id = <6>;
+ qcom,source-sel = <1>;
+ qcom,mode-ctrl = <0x61>;
+ qcom,mode = "manual";
+ };
+ };
+
qcom,leds@a200 {
status = "okay";
qcom,led_mpp_3 {
diff --git a/Documentation/devicetree/bindings/nfc/nfc-nci.txt b/Documentation/devicetree/bindings/nfc/nfc-nci.txt
index 5c53470..dca7d5c 100644
--- a/Documentation/devicetree/bindings/nfc/nfc-nci.txt
+++ b/Documentation/devicetree/bindings/nfc/nfc-nci.txt
@@ -8,7 +8,7 @@
- reg: NCI i2c slave address.
- qcom,dis-gpio: specific gpio for hardware reset.
- qcom,irq-gpio: specific gpio for read interrupt.
-- qcom,clk-src: nfc clock source ("BBCLK2", "RFCLK3", "GPCLK", ...)
+- qcom,clk-src: nfc clock source ("BBCLK2", "RFCLK3", "GPCLK","GPCLK2" ...)
- qcom,clk-en-gpio: msm gpio clock,used ony if clock source is msm gpio
- vlogic-supply: LDO for power supply
- interrupt-parent: Should be phandle for the interrupt controller
diff --git a/Documentation/devicetree/bindings/power/qpnp-charger.txt b/Documentation/devicetree/bindings/power/qpnp-charger.txt
index 5425c92..7d8fe0a 100644
--- a/Documentation/devicetree/bindings/power/qpnp-charger.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-charger.txt
@@ -93,6 +93,16 @@
set, the charger ovp status is monitored in software.
- qcom,ext-ovp-present Indicates if an external OVP exists which reduces the
overall input resistance of the charge path.
+- qcom,ibat-calibration-enabled Indicates if ibat calibration is enabled. This is
+ required for devices which have a ibat trim error
+ causing ibatmax to go out of spec.
+- qcom,power-stage-reduced Indicates if power stage workaround is enabled. This work
+ around reduces the power stage segments while charging
+ under high load during low battery voltages. It's for
+ improving IADC accuracy while board has a bad layout.
+- qcom,use-external-rsense A boolean that controls whether BMS will use
+ an external sensor resistor instead of the default
+ RDS of the batfet.
Sub node required structure:
- A qcom,chg node must be a child of an SPMI node that has specified
diff --git a/Documentation/devicetree/bindings/regulator/krait-regulator.txt b/Documentation/devicetree/bindings/regulator/krait-regulator.txt
index a8195df..7c661fe 100644
--- a/Documentation/devicetree/bindings/regulator/krait-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/krait-regulator.txt
@@ -55,6 +55,9 @@
to LDO mode. Acceptable values are from 1000uV to 100000uV
- qcom,cpu-num: Indicates what cpu this regulator controls
+Optional properties:
+- qcom,ldo-disable: Indicates whether to disable using LDO mode
+
Any property defined as part of the core regulator
binding, defined in regulator.txt, can also be used.
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 5e686a4f..6277054 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -4,23 +4,29 @@
Required properties:
- - compatible : "qcom,msm-pcm-dsp"
+ - compatible : "qti,msm-pcm-dsp"
- - qcom,msm-pcm-dsp-id : device node id
+ - qti,msm-pcm-dsp-id : device node id
* msm-pcm-low-latency
Required properties:
- - compatible : "qcom,msm-pcm-dsp"
+ - compatible : "qti,msm-pcm-dsp"
- - qcom,msm-pcm-dsp-id : device node id
+ - qti,msm-pcm-dsp-id : device node id
Optional properties
- - qcom,msm-pcm-low-latency : Flag indicating whether
+ - qti,msm-pcm-low-latency : Flag indicating whether
the device node is of type low latency.
+ - qti,latency-level : Flag indicating whether the device node
+ is of type regular low latency or ultra
+ low latency.
+ regular : regular low latency stream
+ ultra : ultra low latency stream
+
* msm-pcm-routing
Required properties:
@@ -102,6 +108,12 @@
- compatible : "qcom,msm-lsm-client"
+* msm-pcm-loopback
+
+Required properties:
+
+ - compatible : "qti,msm-pcm-loopback"
+
* msm-dai-q6
[First Level Nodes]
@@ -220,16 +232,16 @@
Example:
- qcom,msm-pcm {
- compatible = "qcom,msm-pcm-dsp";
- qcom,msm-pcm-dsp-id = <0>;
+ qti,msm-pcm {
+ compatible = "qti,msm-pcm-dsp";
+ qti,msm-pcm-dsp-id = <0>;
};
- qcom,msm-pcm-low-latency {
- compatible = "qcom,msm-pcm-dsp";
- qcom,msm-pcm-dsp-id = <1>;
- qcom,msm-pcm-low-latency;
- };
+ qti,msm-pcm-low-latency {
+ compatible = "qti,msm-pcm-dsp";
+ qti,msm-pcm-dsp-id = <1>;
+ qti,msm-pcm-low-latency;
+ };
qcom,msm-pcm-routing {
compatible = "qcom,msm-pcm-routing";
@@ -407,6 +419,17 @@
Required properties:
- compatible : "qcom,msm8974-audio-taiko"
- qcom,model : The user-visible name of this sound card.
+- reg : Offset and length of the register region(s) for MI2S/PCM MUX
+- reg-names : Register region name(s) referenced in reg above
+ Required register resource entries are:
+ "lpaif_pri_mode_muxsel": Physical address of MUX to select between
+ Primary PCM and Primary MI2S
+ "lpaif_sec_mode_muxsel": Physical address of MUX to select between
+ Secondary PCM and Secondary MI2S
+ "lpaif_tert_mode_muxsel": Physical address of MUX to select between
+ Primary PCM and Tertiary MI2S
+ "lpaif_quat_mode_muxsel": Physical address of MUX to select between
+ Secondary PCM and Quarternary MI2S
- qcom,audio-routing : A list of the connections between audio components.
Each entry is a pair of strings, the first being the connection's sink,
the second being the connection's source.
diff --git a/Documentation/devicetree/bindings/uio/msm_sharedmem.txt b/Documentation/devicetree/bindings/uio/msm_sharedmem.txt
new file mode 100644
index 0000000..5af50da
--- /dev/null
+++ b/Documentation/devicetree/bindings/uio/msm_sharedmem.txt
@@ -0,0 +1,13 @@
+msm_sharedmem provides the shared memory addresses for various clients in user-space
+
+Required properties:
+- compatible: Must be "qcom,sharedmem-uio"
+- reg : The address and size of the shared memory. The address/sizes may vary.
+- reg-names : indicates various client-names.
+
+Example:
+ msm_sharedmem {
+ compatible = "qcom,sharedmem-uio";
+ reg = <0x0dc80000 0x00180000>,
+ reg-names = "rmtfs";
+ };
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index e7eae76..623a23c 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -86,6 +86,13 @@
for detection of dp line transition during VDD minimization.
- qcom,hsusb-otg-dmsehv-int: If present, indicates mpm interrupt to be configured
for detection of dm line transition during VDD minimization.
+- qcom,ahb-async-bridge-bypass: If present, indicates that enable AHB2AHB By Pass
+ mode with device controller for better throughput. With this mode, USB Core
+ runs using PNOC clock and synchronous to it. Hence it is must to have proper
+ "qcom,msm_bus,vectors" to have high bus frequency. User shouldn't try to
+ enable this feature without proper bus voting.
+-qcom,disable-retention-with-vdd-min: If present dont allow phy retention but allow
+ vdd min.
Example HSUSB OTG controller device node :
usb@f9690000 {
@@ -110,6 +117,7 @@
HSUSB_3p3-supply = <&pm8226_l20>;
qcom,vdd-voltage-level = <1 5 7>;
qcom,dp-manual-pullup;
+ qcom,disable-retention-with-vdd-min;
qcom,hsusb-otg-dpsehv-int = <49>;
qcom,hsusb-otg-dmsehv-int = <58>;
qcom,msm_bus,name = "usb2";
@@ -176,12 +184,19 @@
- qcom,android-usb-cdrom : if this property is present then device creates
a new LUN as CD-ROM
- qcom,android-usb-internal-ums : if this property is present then device
- creates a new LUN as internal usb mass storage
+ creates a new LUN as internal usb mass storage.
+- qcom,streaming-func : add list of usb function name. If mention usb function
+ is being enable as part of USB composition, streaming mode is enable with
+ usb device controller to get better throughput. NOTE: Inverted CRC and
+ turnaround timeout is observed on enabling streaming. Hence it is required
+ to see these errors and number of erros on enabling this at USB level to make
+ final decision to enable this feature or not.
Example Android USB device node :
android_usb@fc42b0c8 {
compatible = "qcom,android-usb";
reg = <0xfc42b0c8 0xc8>;
qcom,android-usb-swfi-latency = <1>;
+ qcom,streaming-func = "rndis","mtp";
};
diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt
index 96f0ee8..9c11d97 100644
--- a/Documentation/sysctl/vm.txt
+++ b/Documentation/sysctl/vm.txt
@@ -28,6 +28,7 @@
- dirty_writeback_centisecs
- drop_caches
- extfrag_threshold
+- extra_free_kbytes
- hugepages_treat_as_movable
- hugetlb_shm_group
- laptop_mode
@@ -168,6 +169,21 @@
==============================================================
+extra_free_kbytes
+
+This parameter tells the VM to keep extra free memory between the threshold
+where background reclaim (kswapd) kicks in, and the threshold where direct
+reclaim (by allocating processes) kicks in.
+
+This is useful for workloads that require low latency memory allocations
+and have a bounded burstiness in memory allocations, for example a
+realtime application that receives and transmits network traffic
+(causing in-kernel memory allocations) with a maximum total message burst
+size of 200MB may need 200MB of extra free memory to avoid direct reclaim
+related latencies.
+
+==============================================================
+
hugepages_treat_as_movable
This parameter is only useful when kernelcore= is specified at boot time to
diff --git a/Documentation/usb/uicc.txt b/Documentation/usb/uicc.txt
new file mode 100644
index 0000000..7bf4d86
--- /dev/null
+++ b/Documentation/usb/uicc.txt
@@ -0,0 +1,161 @@
+Introduction
+============
+
+This feature requires supporting Mass Storage and Integrated Circuit Card
+interfaces exposed by the UICC (Universal Integrated Circuit Card) device.
+The MSM acts as a USB host and UICC acts as a peripheral. The UICC device
+that is used here is also referred to as Mega-SIM. This feature will be
+supported on MSM8x26.
+
+Hardware description
+====================
+
+The USB3503 HSIC (High Speed Inter Chip) hub's down stream port is modified
+to support Inter-Chip USB for connecting the UICC device. The USB3503 is
+connected to MSM via HSIC interface. The UICC device operates in Full Speed
+mode.
+
+The UICC device will support CCID (Integrated Circuit Card interface Device)
+specification. This interface supports 1 Bulk In, 1 Bulk Out and 1 Interrupt
+endpoint. The Interrupt endpoint is used by the device to send asynchronous
+notifications like card insertion/removal and hardware error events.
+The Bulk endpoints are used for the data communication.
+
+The UICC device will support the Mass Storage Bulk Only 1.0 specification.
+It supports SCSI Transparent subclass '06', corresponding to support of the
+SCSI Primary Command set. It implements SCSI Peripheral Device Type '00'
+(TYPE_DISK) corresponding to a direct access SCSI block device.
+
+Software description
+====================
+
+The MSM HSIC controller driver(drivers/usb/host/ehci-msm-hsic.c) takes care
+of HSIC PHY and link management. The USB3503 HSIC hub is managed by the SMSC
+hub driver(drivers/misc/smsc_hubc.c). Both these drivers are well tested on
+APQ8074 dragon board and are re-used to support this feature.
+
+The mass storage interface is managed by the standard Linux USB storage driver.
+This driver interfaces with SCSI and block layers to export the disk to
+user space.
+
+A new USB driver is implemented to manage the CCID interface. This driver is
+referred to as USB CCID driver in this document. This driver is implemented
+as a pass-through module and provides the character device interface to
+user space. The CCID specification is implemented in the user space.
+
+The CCID command and responses are exchanged over the Bulk endpoints. The
+user space application uses write() and read() calls to send commands and
+receive responses.
+
+The CCID class specific requests are sent over the control endpoint. As
+control requests have a specific format, ioctls are implemented.
+
+The UICC device sends asynchronous notifications over the interrupt endpoint.
+The card insertion/removal and hardware error events are sent to user space
+via an ioctl().
+
+Design Goals:
+============
+
+1. Re-use the existing services available in user space. This is achieved
+by implementing the kernel USB CCID driver as a pass-through module.
+
+2. Support runtime card insertion/removal.
+
+3. Support runtime power management.
+
+4. Support Multiple card configuration. More than 1 IC can be connected to
+the USB UICC device.
+
+Power Management
+================
+
+The USB core uses the runtime PM framework to auto suspend the USB devices that
+are not in use. The Auto-suspend is forbidden for all devices except hub class
+devices. The USB CCID driver enables auto-suspend for the UICC device.
+
+An USB device can be suspended only when all of its interfaces are suspended.
+The USB storage interface device acts as a parent device to the underlying
+SCSI host, target and block devices. Runtime PM must be enabled for the
+SCSI device to allow USB storage interface suspend. The SCSI device runtime
+suspend and auto-suspend timeout will be configured from user space via sysfs
+files.
+
+The HSIC platform device and USB3503 HUB device will be runtime suspended
+only after the USB UICC device is suspended.
+
+SMP/multi-core
+==============
+
+The USB CCID driver does not allow multiple clients to open the device file
+concurrently. -EBUSY will be returned if open() is attempted when the
+file is already opened.
+
+The write() and read() methods are implemented synchronously. If another
+write() is called when a previous write() is in progress, -EBUSY is
+returned. The same is applicable to read().
+
+Mutexes will be used to prevent concurrent open(), read() and write() access.
+
+Interface
+=========
+
+A character device file (/dev/ccid_bridge) will be exposed by the USB CCID
+driver. open(), read(), write(), ioctl() and close() methods are implemented.
+This device node is accessible only to the root by default. User space init
+or udev scripts should change the permissions of this device file if it needs
+to be accessed by non-root applications.
+
+open(): The open() is blocked until the UICC device is detected and the CCID
+interface probe is completed. Returns the appropriate error code in case of
+failure.
+
+read(): An URB is submitted on the Bulk In endpoint. The read() is blocked
+until the URB is completed and the data is copied to the user space buffer
+upon success. An appropriate error code is returned in case of failure.
+-ENODEV must be treated as a serious error and no further I/O will be
+attempted.
+
+write(): An URB is submitted on the Bulk Out endpoint. The write() is blocked
+until the URB is completed. An appropriate error code is returned in case of
+failure. -ENODEV must be treated as a serious error and no further I/O will be
+attempted.
+
+ioctl(): The ioctl() method is required for facilitating Control transfers and
+Interrupt transfers.
+
+USB_CCID_GET_CLASS_DESC: This read-only ioctl returns the smart card class
+descriptor as described in the 5.1 section of USB smart card class spec.
+
+USB_CCID_ABORT: This write-only ioctl sends A ABORT class specific request on
+control endpoint. The class request details are mentioned in section 5.3.1.
+
+USB_CCID_GET_CLOCK_FREQUENCIES: This read and write ioctl returns the clock
+frequencies supported by the CCID device. A GET_CLOCK_FREQUENCIES class request
+is sent on the control endpoint. The class request details are mentioned in
+section 5.3.2.
+
+USB_CCID_GET_DATA_RATES: This read and write ioctl returns the data rates
+supported by the CCID device. A GET_DATA_RATES class request is sent on the
+control endpoint. The class request details are mentioned in section 5.3.3.
+
+USB_CCID_GET_EVENT: This read-only ioctl returns the asynchronous event sent
+by the UICC device. The ioctl() is blocked until such event is received from
+the UICC device. This ioctl() returns -ENOENT error code when the device
+does not have an interrupt endpoint and does not support remote wakeup
+capability.
+
+close(): Cancels any ongoing I/O before it returns.
+
+Config options
+==============
+
+Turn on USB_EHCI_MSM_HSIC, USB_HSIC_SMSC_HUB and USB_CCID_BRIDGE configs to
+enable this feature.
+
+References
+==========
+
+Specification for Integrated Circuit(s) Cards Interface Devices
+
+Smart Cards; UICC-Terminal interface; Physical and logical characteristics
diff --git a/Makefile b/Makefile
index be32c2f..0c11d69 100644
--- a/Makefile
+++ b/Makefile
@@ -864,6 +864,7 @@
# Generate .S file with all kernel symbols
quiet_cmd_kallsyms = KSYM $@
cmd_kallsyms = $(NM) -n $< | $(KALLSYMS) \
+ --page-offset=$(CONFIG_PAGE_OFFSET) \
$(if $(CONFIG_KALLSYMS_ALL),--all-symbols) > $@
.tmp_kallsyms1.o .tmp_kallsyms2.o .tmp_kallsyms3.o: %.o: %.S scripts FORCE
diff --git a/arch/arm/boot/dts/apq8026-v1-cdp.dts b/arch/arm/boot/dts/apq8026-v1-cdp.dts
index d7e283b..b9ec6f9 100644
--- a/arch/arm/boot/dts/apq8026-v1-cdp.dts
+++ b/arch/arm/boot/dts/apq8026-v1-cdp.dts
@@ -13,7 +13,7 @@
/dts-v1/;
/include/ "apq8026-v1.dtsi"
-/include/ "msm8226-cdp.dtsi"
+/include/ "msm8226-720p-cdp.dtsi"
/ {
model = "Qualcomm APQ 8026 CDP";
diff --git a/arch/arm/boot/dts/apq8026-v1-mtp.dts b/arch/arm/boot/dts/apq8026-v1-mtp.dts
index d24875c..c2fc72c 100644
--- a/arch/arm/boot/dts/apq8026-v1-mtp.dts
+++ b/arch/arm/boot/dts/apq8026-v1-mtp.dts
@@ -13,7 +13,7 @@
/dts-v1/;
/include/ "apq8026-v1.dtsi"
-/include/ "msm8226-mtp.dtsi"
+/include/ "msm8226-720p-mtp.dtsi"
/ {
model = "Qualcomm APQ 8026 MTP";
diff --git a/arch/arm/boot/dts/apq8026-v1-xpm.dts b/arch/arm/boot/dts/apq8026-v1-xpm.dts
index f69511b..b435018 100644
--- a/arch/arm/boot/dts/apq8026-v1-xpm.dts
+++ b/arch/arm/boot/dts/apq8026-v1-xpm.dts
@@ -13,7 +13,7 @@
/dts-v1/;
/include/ "apq8026-v1.dtsi"
-/include/ "msm8226-cdp.dtsi"
+/include/ "msm8226-720p-cdp.dtsi"
/ {
model = "Qualcomm APQ 8026 XPM";
diff --git a/arch/arm/boot/dts/apq8026-v2-cdp.dts b/arch/arm/boot/dts/apq8026-v2-1080p-cdp.dts
similarity index 91%
copy from arch/arm/boot/dts/apq8026-v2-cdp.dts
copy to arch/arm/boot/dts/apq8026-v2-1080p-cdp.dts
index cb68779..5294628 100644
--- a/arch/arm/boot/dts/apq8026-v2-cdp.dts
+++ b/arch/arm/boot/dts/apq8026-v2-1080p-cdp.dts
@@ -13,10 +13,10 @@
/dts-v1/;
/include/ "apq8026-v2.dtsi"
-/include/ "msm8226-cdp.dtsi"
+/include/ "msm8226-1080p-cdp.dtsi"
/ {
model = "Qualcomm APQ 8026v2 CDP";
compatible = "qcom,apq8026-cdp", "qcom,apq8026", "qcom,cdp";
- qcom,board-id = <1 0>;
+ qcom,board-id = <1 2>;
};
diff --git a/arch/arm/boot/dts/apq8026-v2-mtp.dts b/arch/arm/boot/dts/apq8026-v2-1080p-mtp.dts
similarity index 91%
copy from arch/arm/boot/dts/apq8026-v2-mtp.dts
copy to arch/arm/boot/dts/apq8026-v2-1080p-mtp.dts
index 40856c8..0ea98f5 100644
--- a/arch/arm/boot/dts/apq8026-v2-mtp.dts
+++ b/arch/arm/boot/dts/apq8026-v2-1080p-mtp.dts
@@ -13,10 +13,10 @@
/dts-v1/;
/include/ "apq8026-v2.dtsi"
-/include/ "msm8226-mtp.dtsi"
+/include/ "msm8226-1080p-mtp.dtsi"
/ {
model = "Qualcomm APQ 8026v2 MTP";
compatible = "qcom,apq8026-mtp", "qcom,apq8026", "qcom,mtp";
- qcom,board-id = <8 0>;
+ qcom,board-id = <8 2>;
};
diff --git a/arch/arm/boot/dts/apq8026-v2-cdp.dts b/arch/arm/boot/dts/apq8026-v2-720p-cdp.dts
similarity index 95%
rename from arch/arm/boot/dts/apq8026-v2-cdp.dts
rename to arch/arm/boot/dts/apq8026-v2-720p-cdp.dts
index cb68779..cb2226a 100644
--- a/arch/arm/boot/dts/apq8026-v2-cdp.dts
+++ b/arch/arm/boot/dts/apq8026-v2-720p-cdp.dts
@@ -13,7 +13,7 @@
/dts-v1/;
/include/ "apq8026-v2.dtsi"
-/include/ "msm8226-cdp.dtsi"
+/include/ "msm8226-720p-cdp.dtsi"
/ {
model = "Qualcomm APQ 8026v2 CDP";
diff --git a/arch/arm/boot/dts/apq8026-v2-mtp.dts b/arch/arm/boot/dts/apq8026-v2-720p-mtp.dts
similarity index 95%
rename from arch/arm/boot/dts/apq8026-v2-mtp.dts
rename to arch/arm/boot/dts/apq8026-v2-720p-mtp.dts
index 40856c8..439b3d7 100644
--- a/arch/arm/boot/dts/apq8026-v2-mtp.dts
+++ b/arch/arm/boot/dts/apq8026-v2-720p-mtp.dts
@@ -13,7 +13,7 @@
/dts-v1/;
/include/ "apq8026-v2.dtsi"
-/include/ "msm8226-mtp.dtsi"
+/include/ "msm8226-720p-mtp.dtsi"
/ {
model = "Qualcomm APQ 8026v2 MTP";
diff --git a/arch/arm/boot/dts/apq8026-v2-xpm.dts b/arch/arm/boot/dts/apq8026-v2-xpm.dts
index 324516d..3133424 100644
--- a/arch/arm/boot/dts/apq8026-v2-xpm.dts
+++ b/arch/arm/boot/dts/apq8026-v2-xpm.dts
@@ -13,7 +13,7 @@
/dts-v1/;
/include/ "apq8026-v2.dtsi"
-/include/ "msm8226-cdp.dtsi"
+/include/ "msm8226-720p-cdp.dtsi"
/ {
model = "Qualcomm APQ 8026v2 XPM";
diff --git a/arch/arm/boot/dts/apq8074-dragonboard.dtsi b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
index 824b0ab..c7e24d9 100644
--- a/arch/arm/boot/dts/apq8074-dragonboard.dtsi
+++ b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
@@ -13,6 +13,7 @@
/include/ "dsi-panel-sharp-qhd-video.dtsi"
/include/ "msm8974-camera-sensor-dragonboard.dtsi"
/include/ "msm8974-leds.dtsi"
+/include/ "msm-rdbg.dtsi"
&vph_pwr_vreg {
status = "ok";
diff --git a/arch/arm/boot/dts/apq8074-v1-ion.dtsi b/arch/arm/boot/dts/apq8074-v1-ion.dtsi
index 49d7ee1..3611132 100644
--- a/arch/arm/boot/dts/apq8074-v1-ion.dtsi
+++ b/arch/arm/boot/dts/apq8074-v1-ion.dtsi
@@ -17,6 +17,7 @@
reg = <23>;
qcom,heap-align = <0x1000>;
qcom,memory-fixed = <0x0dc00000 0x1e00000>;
+ qcom,ion-heap-type = "CARVEOUT";
};
};
};
diff --git a/arch/arm/boot/dts/apq8074-v2.0-1-ion.dtsi b/arch/arm/boot/dts/apq8074-v2.0-1-ion.dtsi
index 49d7ee1..3611132 100644
--- a/arch/arm/boot/dts/apq8074-v2.0-1-ion.dtsi
+++ b/arch/arm/boot/dts/apq8074-v2.0-1-ion.dtsi
@@ -17,6 +17,7 @@
reg = <23>;
qcom,heap-align = <0x1000>;
qcom,memory-fixed = <0x0dc00000 0x1e00000>;
+ qcom,ion-heap-type = "CARVEOUT";
};
};
};
diff --git a/arch/arm/boot/dts/apq8074-v2.2-ion.dtsi b/arch/arm/boot/dts/apq8074-v2.2-ion.dtsi
index 49d7ee1..3611132 100644
--- a/arch/arm/boot/dts/apq8074-v2.2-ion.dtsi
+++ b/arch/arm/boot/dts/apq8074-v2.2-ion.dtsi
@@ -17,6 +17,7 @@
reg = <23>;
qcom,heap-align = <0x1000>;
qcom,memory-fixed = <0x0dc00000 0x1e00000>;
+ qcom,ion-heap-type = "CARVEOUT";
};
};
};
diff --git a/arch/arm/boot/dts/apq8084-ion.dtsi b/arch/arm/boot/dts/apq8084-ion.dtsi
index ea954b8..167b8b7 100644
--- a/arch/arm/boot/dts/apq8084-ion.dtsi
+++ b/arch/arm/boot/dts/apq8084-ion.dtsi
@@ -16,16 +16,14 @@
#address-cells = <1>;
#size-cells = <0>;
- qcom,ion-heap@30 { /* SYSTEM HEAP */
- reg = <30>;
- };
-
- qcom,ion-heap@21 { /* SYSTEM CONTIG HEAP */
- reg = <21>;
- };
-
- qcom,ion-heap@25 { /* IOMMU HEAP */
+ qcom,ion-heap@25 {
reg = <25>;
+ qcom,ion-heap-type = "SYSTEM";
+ };
+
+ qcom,ion-heap@21 {
+ reg = <21>;
+ qcom,ion-heap-type = "SYSTEM_CONTIG";
};
};
};
diff --git a/arch/arm/boot/dts/apq8084-mdss.dtsi b/arch/arm/boot/dts/apq8084-mdss.dtsi
index 5c5cd1b..15d5018 100644
--- a/arch/arm/boot/dts/apq8084-mdss.dtsi
+++ b/arch/arm/boot/dts/apq8084-mdss.dtsi
@@ -21,6 +21,9 @@
status = "disabled";
+ qcom,max-bandwidth-low-kbps = <6000000>;
+ qcom,max-bandwidth-high-kbps = <6000000>;
+
qcom,max-clk-rate = <320000000>;
qcom,mdss-pipe-vig-off = <0x00001200 0x00001600
diff --git a/arch/arm/boot/dts/batterydata-qrd-4v2-2200mah.dtsi b/arch/arm/boot/dts/batterydata-qrd-4v2-2200mah.dtsi
new file mode 100644
index 0000000..53aa781
--- /dev/null
+++ b/arch/arm/boot/dts/batterydata-qrd-4v2-2200mah.dtsi
@@ -0,0 +1,105 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+qcom,qrd-4v2-2200mah-data {
+ qcom,default-rbatt-mohm = <163>;
+ qcom,max-voltage-uv = <4200>;
+ qcom,fcc-mah = <2200>;
+ qcom,rbatt-capacitive-mohm = <0>;
+ qcom,v-cutoff-uv = <3400000>;
+ qcom,chg-term-ua = <100000>;
+ qcom,batt-id-kohm = <10>;
+ qcom,flat-ocv-threshold-uv = <3800000>;
+
+ qcom,fcc-temp-lut {
+ qcom,lut-col-legend = <(-20) 0 25 40 60>;
+ qcom,lut-data = <2167 2179 2234 2178 2164>;
+ };
+
+ qcom,pc-temp-ocv-lut {
+ qcom,lut-col-legend = <(-20) 0 25 40 60>;
+ qcom,lut-row-legend = <100 95 90 85 80>,
+ <75 70 65 60 55>,
+ <50 45 40 35 30>,
+ <25 20 15 10 9>,
+ <8 7 6 5 4>,
+ <3 2 1 0>;
+ qcom,lut-data = <4188 4184 4199 4176 4170>,
+ <4109 4124 4145 4124 4118>,
+ <4051 4082 4097 4077 4072>,
+ <3963 4024 4055 4034 4029>,
+ <3920 3971 4002 3993 3989>,
+ <3880 3932 3963 3957 3952>,
+ <3846 3892 3920 3913 3910>,
+ <3822 3859 3881 3873 3871>,
+ <3805 3834 3851 3845 3844>,
+ <3790 3813 3828 3823 3822>,
+ <3777 3796 3808 3805 3803>,
+ <3764 3784 3792 3790 3788>,
+ <3750 3775 3778 3777 3774>,
+ <3736 3766 3766 3761 3751>,
+ <3721 3752 3755 3745 3732>,
+ <3704 3733 3737 3729 3716>,
+ <3684 3707 3713 3707 3694>,
+ <3655 3686 3688 3682 3672>,
+ <3598 3661 3677 3671 3659>,
+ <3585 3655 3673 3669 3656>,
+ <3571 3644 3664 3663 3650>,
+ <3551 3626 3643 3648 3631>,
+ <3523 3598 3609 3618 3600>,
+ <3489 3561 3565 3578 3561>,
+ <3445 3514 3510 3529 3512>,
+ <3389 3453 3440 3468 3450>,
+ <3313 3372 3345 3386 3366>,
+ <3207 3252 3209 3262 3239>,
+ <3000 3000 3000 3000 3000>;
+ };
+
+ qcom,rbatt-sf-lut {
+ qcom,lut-col-legend = <(-20) 0 25 40 60>;
+ qcom,lut-row-legend = <100 95 90 85 80>,
+ <75 70 65 60 55>,
+ <50 45 40 35 30>,
+ <25 20 15 10 9>,
+ <8 7 6 5 4>,
+ <3 2 1 0>;
+ qcom,lut-data = <1371 224 100 79 74>,
+ <1358 242 100 80 74>,
+ <1358 242 103 80 74>,
+ <1195 257 107 82 75>,
+ <1171 256 112 84 77>,
+ <1149 250 119 89 79>,
+ <1144 232 114 90 79>,
+ <1150 225 101 83 76>,
+ <1175 227 98 81 76>,
+ <1210 232 98 82 76>,
+ <1260 236 98 82 77>,
+ <1329 242 100 84 77>,
+ <1421 251 100 86 79>,
+ <1536 263 101 81 76>,
+ <1671 280 100 80 74>,
+ <1830 304 100 81 75>,
+ <2036 338 101 82 76>,
+ <2326 443 103 82 76>,
+ <2788 708 112 88 79>,
+ <2890 747 115 90 80>,
+ <2755 676 117 89 79>,
+ <2750 716 118 87 78>,
+ <2916 765 119 87 79>,
+ <3336 833 123 89 80>,
+ <4214 920 133 92 81>,
+ <5615 1031 151 96 83>,
+ <7923 1188 192 104 89>,
+ <13252 1886 585 137 122>,
+ <43764 20050 47711 3680 16847>;
+ };
+};
diff --git a/arch/arm/boot/dts/dsi-panel-generic-720p-cmd.dtsi b/arch/arm/boot/dts/dsi-panel-generic-720p-cmd.dtsi
index 2963d15..17e6e94 100644
--- a/arch/arm/boot/dts/dsi-panel-generic-720p-cmd.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-generic-720p-cmd.dtsi
@@ -37,7 +37,6 @@
qcom,mdss-dsi-v-top-border = <0>;
qcom,mdss-dsi-v-bottom-border = <0>;
qcom,mdss-dsi-bpp = <24>;
- qcom,mdss-dsi-color-order = <0>;
qcom,mdss-dsi-underflow-color = <0xff>;
qcom,mdss-dsi-border-color = <0>;
qcom,mdss-dsi-on-command = [05 01 00 00 78 00 01 11
@@ -52,8 +51,7 @@
qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
qcom,mdss-dsi-h-sync-pulse = <0>;
- qcom,mdss-dsi-traffic-mode = <1>;
- qcom,mdss-dsi-lane-map = <0>;
+ qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
qcom,mdss-dsi-bllp-eof-power-mode;
qcom,mdss-dsi-bllp-power-mode;
qcom,mdss-dsi-lane-0-state;
@@ -73,8 +71,8 @@
qcom,mdss-dsi-bl-max-level = <255>;
qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>;
qcom,mdss-dsi-bl-pmic-bank-select = <7>;
- qcom,mdss-dsi-dma-trigger = <4>;
- qcom,mdss-dsi-mdp-trigger = <0>;
+ qcom,mdss-dsi-dma-trigger = "trigger_sw";
+ qcom,mdss-dsi-mdp-trigger = "none";
qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm";
qcom,mdss-dsi-reset-sequence = <1 20>, <0 200>, <1 20>;
};
diff --git a/arch/arm/boot/dts/dsi-panel-hx8379a-wvga-video.dtsi b/arch/arm/boot/dts/dsi-panel-hx8379a-wvga-video.dtsi
index 23b65f3..88ccd08 100644
--- a/arch/arm/boot/dts/dsi-panel-hx8379a-wvga-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-hx8379a-wvga-video.dtsi
@@ -38,7 +38,6 @@
qcom,mdss-dsi-v-top-border = <0>;
qcom,mdss-dsi-v-bottom-border = <0>;
qcom,mdss-dsi-bpp = <24>;
- qcom,mdss-dsi-color-order = <0>;
qcom,mdss-dsi-underflow-color = <0xff>;
qcom,mdss-dsi-border-color = <0>;
qcom,mdss-dsi-on-command = [
@@ -81,14 +80,47 @@
00 00 00 00
39 01 00 00 00 00 24
E0 79 05 0F
- 14 26 20 3F
- 2A 43 04 0C
- 11 15 17 15
- 15 10 13 05
- 0F 14 26 20
- 3F 2A 43 04
- 0C 11 15 17
- 15 15 10 13
+ 14 23 24 3F
+ 30 46 06 10
+ 13 16 17 16
+ 16 13 18 05
+ 0F 14 23 24
+ 3F 30 46 06
+ 10 13 16 17
+ 16 16 13 18
+ 39 01 00 00 00 00 80
+ C1 01 00 07
+ 10 17 1D 2A
+ 33 3A 43 4A
+ 52 5B 64 6D
+ 78 7F 88 90
+ 98 A0 A9 B2
+ B9 C1 C9 D1
+ D7 DF E6 ED
+ F4 FA FD 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 08 10 18
+ 20 28 30 38
+ 40 47 4F 58
+ 60 68 70 78
+ 80 88 90 98
+ A0 A9 B1 B9
+ C1 C9 D1 D8
+ E0 E8 F0 F9
+ FE 00 00 00
+ 00 00 00 00
+ 00 00 00 08
+ 10 18 1E 26
+ 2E 34 3A 41
+ 49 4F 58 5E
+ 67 6F 77 80
+ 88 8F 97 9F
+ A7 AF B8 BF
+ C7 D1 D8 E3
+ EA F6 FF 00
+ 00 00 00 00
+ 00 00 00 00
23 01 00 00 00 00 02
cc 02
39 01 00 00 00 00 05
@@ -104,8 +136,8 @@
qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
qcom,mdss-dsi-off-command-state = "dsi_lp_mode";
qcom,mdss-dsi-h-sync-pulse = <1>;
- qcom,mdss-dsi-traffic-mode = <2>;
- qcom,mdss-dsi-lane-map = <1>;
+ qcom,mdss-dsi-traffic-mode = "burst_mode";
+ qcom,mdss-dsi-lane-map = "lane_map_3012";
qcom,mdss-dsi-bllp-eof-power-mode;
qcom,mdss-dsi-bllp-power-mode;
qcom,mdss-dsi-lane-0-state;
@@ -115,8 +147,8 @@
qcom,mdss-dsi-t-clk-pre = <0x1b>;
qcom,mdss-dsi-bl-min-level = <1>;
qcom,mdss-dsi-bl-max-level = <255>;
- qcom,mdss-dsi-dma-trigger = <4>;
- qcom,mdss-dsi-mdp-trigger = <0>;
+ qcom,mdss-dsi-dma-trigger = "trigger_sw";
+ qcom,mdss-dsi-mdp-trigger = "none";
qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
qcom,mdss-dsi-reset-sequence = <1 20>, <0 2>, <1 20>;
diff --git a/arch/arm/boot/dts/dsi-panel-hx8389b-qhd-video.dtsi b/arch/arm/boot/dts/dsi-panel-hx8389b-qhd-video.dtsi
index 7e63014..25e5072 100755
--- a/arch/arm/boot/dts/dsi-panel-hx8389b-qhd-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-hx8389b-qhd-video.dtsi
@@ -17,7 +17,7 @@
*---------------------------------------------------------------------------*/
&mdss_mdp {
dsi_hx8389b_qhd_vid: qcom,mdss_dsi_hx8389b_qhd_video {
- qcom,mdss-dsi-panel-name = "HX8389b qhd video mode dsi panel";
+ qcom,mdss-dsi-panel-name = "hx8389b qhd video mode dsi panel";
qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
qcom,mdss-dsi-panel-type = "dsi_video_mode";
qcom,mdss-dsi-panel-destination = "display_1";
@@ -26,13 +26,13 @@
qcom,mdss-dsi-stream = <0>;
qcom,mdss-dsi-panel-width = <540>;
qcom,mdss-dsi-panel-height = <960>;
- qcom,mdss-dsi-h-front-porch = <48>;
- qcom,mdss-dsi-h-back-porch = <96>;
- qcom,mdss-dsi-h-pulse-width = <96>;
+ qcom,mdss-dsi-h-front-porch = <60>;
+ qcom,mdss-dsi-h-back-porch = <39>;
+ qcom,mdss-dsi-h-pulse-width = <39>;
qcom,mdss-dsi-h-sync-skew = <0>;
+ qcom,mdss-dsi-v-back-porch = <13>;
qcom,mdss-dsi-v-front-porch = <9>;
qcom,mdss-dsi-v-pulse-width = <3>;
- qcom,mdss-dsi-v-back-porch = <13>;
qcom,mdss-dsi-h-left-border = <0>;
qcom,mdss-dsi-h-right-border = <0>;
qcom,mdss-dsi-v-top-border = <0>;
@@ -41,95 +41,39 @@
qcom,mdss-dsi-color-order = <0>;
qcom,mdss-dsi-underflow-color = <0xff>;
qcom,mdss-dsi-border-color = <0>;
- qcom,mdss-dsi-on-command = [
- 39 01 00 00 00 00 04
- B9 FF 83 89
- 39 01 00 00 00 00 08
- BA 41 93 00
- 16 A4 10 18
- 23 01 00 00 00 00 02
- C6 08
- 39 01 00 00 00 00 03
- BC 02 00
- 23 01 00 00 00 00 02
- CC 02
- 39 01 00 00 00 00 14
- B1 00 00 07
- E8 50 10 11
- 98 f8 21 29
- 27 27 43 01
- 58 F0 00 E6
- 39 01 00 00 00 00 08
- B2 00 00 78
- 0C 07 3F 80
- 39 01 00 00 00 00 18
- b4 82 08 00
- 32 10 04 32
- 10 00 32 10
- 00 37 0a 40
- 08 37 0a 40
- 14 46 50 0a
- 39 01 00 00 00 00 39
- d5 00 00 00
- 00 01 00 00
- 00 60 00 99
- 88 AA BB 88
- 23 88 01 88
- 67 88 45 01
- 23 88 88 88
- 88 88 88 99
- BB AA 88 54
- 88 76 88 10
- 88 32 32 10
- 88 88 88 88
- 88 00 04 00
- 00 00 00 00
- 00
- 39 01 00 00 00 00 03
- CB 07 07
- 39 01 00 00 00 00 05
- BB 00 00 FF
- 80
- 39 01 00 00 00 00 04
- DE 05 58 10
- 39 01 00 00 00 00 05
- B6 00 8A 00
- 8A
- 39 01 00 00 00 00 23
- E0 01 08 0C
- 1F 25 36 12
- 35 05 09 0D
- 10 11 0F 0F
- 1C 1D 01 08
- 0C 1F 25 36
- 12 35 05 09
- 0D 10 11 0F
- 0F 1C 1D
- 05 01 00 00 96 00 02
- 11 00
- 05 01 00 00 96 00 02
- 29 00
- ];
+ qcom,mdss-dsi-on-command = [39 01 00 00 0A 00 04 B9 FF 83 89
+ 15 01 00 00 01 00 02 CC 02
+ 39 01 00 00 01 00 03 C0 43 17
+ 39 01 00 00 01 00 08 BA 41 93 00 16 A4 10 18
+ 39 01 00 00 01 00 14 B1 00 00 06 EB 59 10 11 EE EE 3A 42 3F 3F 43 01 5A F6 00 E6
+ 39 01 00 00 01 00 08 B2 00 00 78 0C 07 3F 80
+ 39 01 00 00 01 00 04 b7 00 00 50
+ 39 01 00 00 01 00 18 B4 80 08 00 32 10 04 32 10 00 32 10 00 37 0a 40 08 37 00 46 02 58 58 02
+ 39 01 00 00 01 00 39 D5 00 00 00 00 01 00 00 00 60 00 99 88 AA BB 88 23 88 01 88 67 88 45 01 23 88 88 88 88 88 88 99 BB AA 88 54 88 76 88 10 88 32 32 10 88 88 88 88 88 3C 04 00 00 00 00 00 00
+ 39 01 00 00 01 00 23 E0 05 11 16 35 3F 3F 21 43 07 0C 0F 11 12 10 10 1D 18 05 11 16 35 3F 3F 21 43 07 0C 0F 11 12 10 10 1D 18
+ 39 01 00 00 05 00 80 C1 01 00 07 13 21 29 2F 34 3B 42 48 50 58 61 69 71 79 81 88 90 98 A0 A9 B1 B9 C1 C8 CE D6 DF E6 EF F7 FF 0E 5A 73 69 36 8E 69 5F C0 00 07 13 21 29 2F 34 3B 42 48 50 58 61 69 71 79 81 88 90 98 A0 A9 B1 B9 C1 C8 CE D6 DF E6 EF F7 FF 0E 5A 73 69 36 8E 69 5F C0 00 07 13 21 29 2F 34 3B 42 48 50 58 61 69 71 79 81 88 90 98 A0 A9 B1 B9 C1 C8 CE D6 DF E6 EF F7 FF 0E 5A 73 69 36 8E 69 5F C0
+ 39 01 00 00 01 00 05 B6 00 88 00 88
+ 05 01 00 00 78 00 02 11 00
+ 05 01 00 00 32 00 02 29 00];
qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00
05 01 00 00 78 00 02 10 00];
qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
qcom,mdss-dsi-off-command-state = "dsi_lp_mode";
qcom,mdss-dsi-h-sync-pulse = <1>;
- qcom,mdss-dsi-traffic-mode = <2>;
- qcom,mdss-dsi-lane-map = <1>;
+ qcom,mdss-dsi-traffic-mode = "burst_mode";
+ qcom,mdss-dsi-lane-map = "lane_map_3012";
qcom,mdss-dsi-bllp-eof-power-mode;
qcom,mdss-dsi-bllp-power-mode;
qcom,mdss-dsi-lane-0-state;
qcom,mdss-dsi-lane-1-state;
- qcom,mdss-dsi-panel-timings = [97 23 17 00 4B 53 1C 27 27 03 04 00];
+ qcom,mdss-dsi-panel-timings = [87 1E 14 00 44 4B 19 21 22 03 04 00];
qcom,mdss-dsi-t-clk-post = <0x04>;
qcom,mdss-dsi-t-clk-pre = <0x1b>;
- qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-min-level = <26>;
qcom,mdss-dsi-bl-max-level = <255>;
- qcom,mdss-dsi-dma-trigger = <4>;
- qcom,mdss-dsi-mdp-trigger = <0>;
+ qcom,mdss-dsi-dma-trigger = "trigger_sw";
+ qcom,mdss-dsi-mdp-trigger = "none";
qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
qcom,mdss-dsi-reset-sequence = <1 20>, <0 2>, <1 20>;
-
};
};
diff --git a/arch/arm/boot/dts/dsi-panel-hx8394a-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-hx8394a-720p-video.dtsi
index 83351ca..5302d8ae 100644
--- a/arch/arm/boot/dts/dsi-panel-hx8394a-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-hx8394a-720p-video.dtsi
@@ -38,7 +38,6 @@
qcom,mdss-dsi-v-top-border = <0>;
qcom,mdss-dsi-v-bottom-border = <0>;
qcom,mdss-dsi-bpp = <24>;
- qcom,mdss-dsi-color-order = <0>;
qcom,mdss-dsi-underflow-color = <0xff>;
qcom,mdss-dsi-border-color = <0>;
qcom,mdss-dsi-on-command = [39 01 00 00 00 00 04 b9 ff 83 94
@@ -62,8 +61,7 @@
qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
qcom,mdss-dsi-h-sync-pulse = <1>;
- qcom,mdss-dsi-traffic-mode = <2>;
- qcom,mdss-dsi-lane-map = <0>;
+ qcom,mdss-dsi-traffic-mode = "burst_mode";
qcom,mdss-dsi-bllp-eof-power-mode;
qcom,mdss-dsi-bllp-power-mode;
qcom,mdss-dsi-lane-0-state;
@@ -75,8 +73,8 @@
qcom,mdss-dsi-t-clk-pre = <0x2d>;
qcom,mdss-dsi-bl-min-level = <1>;
qcom,mdss-dsi-bl-max-level = <4095>;
- qcom,mdss-dsi-dma-trigger = <4>;
- qcom,mdss-dsi-mdp-trigger = <0>;
+ qcom,mdss-dsi-dma-trigger = "trigger_sw";
+ qcom,mdss-dsi-mdp-trigger = "none";
qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
qcom,mdss-dsi-reset-sequence = <1 20>, <0 1>, <1 20>;
diff --git a/arch/arm/boot/dts/dsi-panel-jdi-1080p-video.dtsi b/arch/arm/boot/dts/dsi-panel-jdi-1080p-video.dtsi
index 1b64cf7..be42509 100644
--- a/arch/arm/boot/dts/dsi-panel-jdi-1080p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-jdi-1080p-video.dtsi
@@ -38,7 +38,6 @@
qcom,mdss-dsi-v-top-border = <0>;
qcom,mdss-dsi-v-bottom-border = <0>;
qcom,mdss-dsi-bpp = <24>;
- qcom,mdss-dsi-color-order = <0>;
qcom,mdss-dsi-underflow-color = <0xff>;
qcom,mdss-dsi-border-color = <0>;
qcom,mdss-dsi-on-command = [15 01 00 00 00 00 02 55 00
@@ -51,8 +50,7 @@
qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
qcom,mdss-dsi-h-sync-pulse = <0>;
- qcom,mdss-dsi-traffic-mode = <2>;
- qcom,mdss-dsi-lane-map = <0>;
+ qcom,mdss-dsi-traffic-mode = "burst_mode";
qcom,mdss-dsi-bllp-eof-power-mode;
qcom,mdss-dsi-bllp-power-mode;
qcom,mdss-dsi-lane-0-state;
@@ -64,8 +62,8 @@
qcom,mdss-dsi-t-clk-pre = <0x1b>;
qcom,mdss-dsi-bl-min-level = <1>;
qcom,mdss-dsi-bl-max-level = <4095>;
- qcom,mdss-dsi-dma-trigger = <0x04>;
- qcom,mdss-dsi-mdp-trigger = <0x0>;
+ qcom,mdss-dsi-dma-trigger = "trigger_sw";
+ qcom,mdss-dsi-mdp-trigger = "none";
qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
qcom,mdss-dsi-reset-sequence = <1 20>, <0 200>, <1 20>;
};
diff --git a/arch/arm/boot/dts/dsi-panel-nt35521-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-nt35521-720p-video.dtsi
index 9bb11da..8be4e34 100644
--- a/arch/arm/boot/dts/dsi-panel-nt35521-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-nt35521-720p-video.dtsi
@@ -38,10 +38,9 @@
qcom,mdss-dsi-v-top-border = <0>;
qcom,mdss-dsi-v-bottom-border = <0>;
qcom,mdss-dsi-bpp = <24>;
- qcom,mdss-dsi-color-order = <0>;
qcom,mdss-dsi-underflow-color = <0xff>;
qcom,mdss-dsi-border-color = <0>;
- qcom,mdss-dsi-pixel-packing = <0>;
+ qcom,mdss-dsi-pixel-packing = "tight";
qcom,mdss-dsi-on-command = [29 01 00 00 00 00 06 F0 55 AA 52 08 00
29 01 00 00 00 00 03 B1 68 21
23 01 00 00 00 00 02 B5 C8
@@ -252,8 +251,7 @@
qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
qcom,mdss-dsi-h-sync-pulse = <1>;
- qcom,mdss-dsi-traffic-mode = <2>;
- qcom,mdss-dsi-lane-map = <0>;
+ qcom,mdss-dsi-traffic-mode = "burst_mode";
qcom,mdss-dsi-bllp-eof-power-mode;
qcom,mdss-dsi-bllp-power-mode;
qcom,mdss-dsi-lane-0-state;
@@ -265,8 +263,8 @@
qcom,mdss-dsi-t-clk-pre = <0x2D>;
qcom,mdss-dsi-bl-min-level = <1>;
qcom,mdss-dsi-bl-max-level = <255>;
- qcom,mdss-dsi-dma-trigger = <4>;
- qcom,mdss-dsi-mdp-trigger = <0>;
+ qcom,mdss-dsi-dma-trigger = "trigger_sw";
+ qcom,mdss-dsi-mdp-trigger = "none";
qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs";
qcom,mdss-dsi-reset-sequence = <1 20>, <0 1>, <1 20>;
diff --git a/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi b/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi
index a24cb58..d3547d8 100644
--- a/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi
@@ -38,7 +38,6 @@
qcom,mdss-dsi-v-top-border = <0>;
qcom,mdss-dsi-v-bottom-border = <0>;
qcom,mdss-dsi-bpp = <24>;
- qcom,mdss-dsi-color-order = <0>;
qcom,mdss-dsi-underflow-color = <0xff>;
qcom,mdss-dsi-border-color = <0>;
qcom,mdss-dsi-on-command = [29 01 00 00 00 00 02 FF EE
@@ -510,8 +509,7 @@
qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
qcom,mdss-dsi-h-sync-pulse = <1>;
- qcom,mdss-dsi-traffic-mode = <2>;
- qcom,mdss-dsi-lane-map = <0>;
+ qcom,mdss-dsi-traffic-mode = "burst_mode";
qcom,mdss-dsi-bllp-eof-power-mode;
qcom,mdss-dsi-bllp-power-mode;
qcom,mdss-dsi-lane-0-state;
@@ -528,8 +526,8 @@
qcom,mdss-dsi-t-clk-pre = <0x2c>;
qcom,mdss-dsi-bl-min-level = <1>;
qcom,mdss-dsi-bl-max-level = <4095>;
- qcom,mdss-dsi-dma-trigger = <4>;
- qcom,mdss-dsi-mdp-trigger = <0>;
+ qcom,mdss-dsi-dma-trigger = "trigger_sw";
+ qcom,mdss-dsi-mdp-trigger = "none";
qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
qcom,mdss-dsi-reset-sequence = <1 20>, <0 1>, <1 20>;
qcom,mdss-pan-physical-width-dimension = <59>;
diff --git a/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
index 79618b9..8d28996 100644
--- a/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
@@ -38,7 +38,6 @@
qcom,mdss-dsi-v-top-border = <0>;
qcom,mdss-dsi-v-bottom-border = <0>;
qcom,mdss-dsi-bpp = <24>;
- qcom,mdss-dsi-color-order = <0>;
qcom,mdss-dsi-underflow-color = <0xff>;
qcom,mdss-dsi-border-color = <0>;
qcom,mdss-dsi-on-command = [29 01 00 00 00 00 02 FF EE
@@ -511,8 +510,7 @@
qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
qcom,mdss-dsi-h-sync-pulse = <1>;
- qcom,mdss-dsi-traffic-mode = <2>;
- qcom,mdss-dsi-lane-map = <0>;
+ qcom,mdss-dsi-traffic-mode = "burst_mode";
qcom,mdss-dsi-bllp-eof-power-mode;
qcom,mdss-dsi-bllp-power-mode;
qcom,mdss-dsi-lane-0-state;
@@ -524,8 +522,8 @@
qcom,mdss-dsi-t-clk-pre = <0x2c>;
qcom,mdss-dsi-bl-min-level = <1>;
qcom,mdss-dsi-bl-max-level = <4095>;
- qcom,mdss-dsi-dma-trigger = <4>;
- qcom,mdss-dsi-mdp-trigger = <0>;
+ qcom,mdss-dsi-dma-trigger = "trigger_sw";
+ qcom,mdss-dsi-mdp-trigger = "none";
qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
qcom,mdss-dsi-reset-sequence = <1 20>, <0 1>, <1 20>;
qcom,mdss-pan-physical-width-dimension = <59>;
diff --git a/arch/arm/boot/dts/dsi-panel-nt35596-1080p-video.dtsi b/arch/arm/boot/dts/dsi-panel-nt35596-1080p-video.dtsi
index 2312b37..770bac4 100644
--- a/arch/arm/boot/dts/dsi-panel-nt35596-1080p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-nt35596-1080p-video.dtsi
@@ -38,7 +38,6 @@
qcom,mdss-dsi-v-top-border = <0>;
qcom,mdss-dsi-v-bottom-border = <0>;
qcom,mdss-dsi-bpp = <24>;
- qcom,mdss-dsi-color-order = <0>;
qcom,mdss-dsi-underflow-color = <0xff>;
qcom,mdss-dsi-border-color = <0>;
qcom,mdss-dsi-on-command = [29 01 00 00 00 00 02 FF EE
@@ -566,8 +565,7 @@
qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
qcom,mdss-dsi-h-sync-pulse = <1>;
- qcom,mdss-dsi-traffic-mode = <2>;
- qcom,mdss-dsi-lane-map = <0>;
+ qcom,mdss-dsi-traffic-mode = "burst_mode";
qcom,mdss-dsi-bllp-eof-power-mode;
qcom,mdss-dsi-bllp-power-mode;
qcom,mdss-dsi-lane-0-state;
@@ -579,8 +577,8 @@
qcom,mdss-dsi-t-clk-pre = <0x38>;
qcom,mdss-dsi-bl-min-level = <1>;
qcom,mdss-dsi-bl-max-level = <4095>;
- qcom,mdss-dsi-dma-trigger = <4>;
- qcom,mdss-dsi-mdp-trigger = <0>;
+ qcom,mdss-dsi-dma-trigger = "trigger_sw";
+ qcom,mdss-dsi-mdp-trigger = "none";
qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
qcom,mdss-dsi-reset-sequence = <1 20>, <0 1>, <1 20>;
diff --git a/arch/arm/boot/dts/dsi-panel-orise-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-orise-720p-video.dtsi
index 30eda91..5393756 100644
--- a/arch/arm/boot/dts/dsi-panel-orise-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-orise-720p-video.dtsi
@@ -34,7 +34,7 @@
qcom,mdss-pan-dsi-stream = <0>;
qcom,mdss-pan-dsi-mdp-tr = <0x0>;
qcom,mdss-pan-dsi-dma-tr = <0x04>;
- qcom,mdss-pan-dsi-frame-rate = <60>;
+ qcom,mdss-pan-dsi-framerate = <60>;
qcom,panel-phy-regulatorSettings = [03 01 01 00 /* Regualotor settings */
20 00 01];
qcom,panel-phy-timingSettings = [69 29 1f 00 55 55
diff --git a/arch/arm/boot/dts/dsi-panel-otm8018b-fwvga-video.dtsi b/arch/arm/boot/dts/dsi-panel-otm8018b-fwvga-video.dtsi
index 9477c56..8d6e703 100644
--- a/arch/arm/boot/dts/dsi-panel-otm8018b-fwvga-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-otm8018b-fwvga-video.dtsi
@@ -38,7 +38,6 @@
qcom,mdss-dsi-v-top-border = <0>;
qcom,mdss-dsi-v-bottom-border = <0>;
qcom,mdss-dsi-bpp = <24>;
- qcom,mdss-dsi-color-order = <0>;
qcom,mdss-dsi-underflow-color = <0xff>;
qcom,mdss-dsi-border-color = <0>;
qcom,mdss-dsi-on-command = [
@@ -247,8 +246,8 @@
qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
qcom,mdss-dsi-off-command-state = "dsi_lp_mode";
qcom,mdss-dsi-h-sync-pulse = <0>;
- qcom,mdss-dsi-traffic-mode = <1>;
- qcom,mdss-dsi-lane-map = <1>;
+ qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
+ qcom,mdss-dsi-lane-map = "lane_map_3012";
qcom,mdss-dsi-bllp-eof-power-mode;
qcom,mdss-dsi-bllp-power-mode;
qcom,mdss-dsi-lane-0-state;
@@ -256,10 +255,10 @@
qcom,mdss-dsi-panel-timings = [8B 1F 14 00 45 4A 19 23 23 03 04 00];
qcom,mdss-dsi-t-clk-post = <0x04>;
qcom,mdss-dsi-t-clk-pre = <0x1b>;
- qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-min-level = <26>;
qcom,mdss-dsi-bl-max-level = <255>;
- qcom,mdss-dsi-dma-trigger = <4>;
- qcom,mdss-dsi-mdp-trigger = <0>;
+ qcom,mdss-dsi-dma-trigger = "trigger_sw";
+ qcom,mdss-dsi-mdp-trigger = "none";
qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
qcom,mdss-dsi-reset-sequence = <1 20>, <0 2>, <1 20>;
diff --git a/arch/arm/boot/dts/dsi-panel-sharp-qhd-video.dtsi b/arch/arm/boot/dts/dsi-panel-sharp-qhd-video.dtsi
index 285d8fc..d23e3de 100644
--- a/arch/arm/boot/dts/dsi-panel-sharp-qhd-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-sharp-qhd-video.dtsi
@@ -38,7 +38,7 @@
qcom,mdss-dsi-v-top-border = <0>;
qcom,mdss-dsi-v-bottom-border = <0>;
qcom,mdss-dsi-bpp = <24>;
- qcom,mdss-dsi-color-order = <2>;
+ qcom,mdss-dsi-color-order = "rgb_swap_bgr";
qcom,mdss-dsi-underflow-color = <0xff>;
qcom,mdss-dsi-border-color = <0>;
qcom,mdss-dsi-on-command = [05 01 00 00 32 00 02 01 00
@@ -53,8 +53,7 @@
qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
qcom,mdss-dsi-h-sync-pulse = <1>;
- qcom,mdss-dsi-traffic-mode = <0>;
- qcom,mdss-dsi-lane-map = <0>;
+ qcom,mdss-dsi-traffic-mode = "non_burst_sync_pulse";
qcom,mdss-dsi-bllp-eof-power-mode;
qcom,mdss-dsi-bllp-power-mode;
qcom,mdss-dsi-lane-0-state;
@@ -64,8 +63,8 @@
qcom,mdss-dsi-t-clk-pre = <0x1c>;
qcom,mdss-dsi-bl-min-level = <1>;
qcom,mdss-dsi-bl-max-level = <4095>;
- qcom,mdss-dsi-dma-trigger = <4>;
- qcom,mdss-dsi-mdp-trigger = <4>;
+ qcom,mdss-dsi-dma-trigger = "trigger_sw";
+ qcom,mdss-dsi-mdp-trigger = "trigger_sw";
qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
qcom,mdss-dsi-reset-sequence = <1 20>, <0 200>, <1 20>;
diff --git a/arch/arm/boot/dts/dsi-panel-ssd2080m-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-ssd2080m-720p-video.dtsi
index bb8389f..60bba5d 100644
--- a/arch/arm/boot/dts/dsi-panel-ssd2080m-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-ssd2080m-720p-video.dtsi
@@ -30,17 +30,18 @@
qcom,mdss-dsi-h-back-porch = <24>;
qcom,mdss-dsi-h-pulse-width = <14>;
qcom,mdss-dsi-h-sync-skew = <0>;
- qcom,mdss-dsi-v-back-porch = <15>;
- qcom,mdss-dsi-v-front-porch = <12>;
- qcom,mdss-dsi-v-pulse-width = <10>;
+ qcom,mdss-dsi-v-back-porch = <14>;
+ qcom,mdss-dsi-v-front-porch = <30>;
+ qcom,mdss-dsi-v-pulse-width = <2>;
qcom,mdss-dsi-h-left-border = <0>;
qcom,mdss-dsi-h-right-border = <0>;
qcom,mdss-dsi-v-top-border = <0>;
qcom,mdss-dsi-v-bottom-border = <0>;
qcom,mdss-dsi-bpp = <24>;
- qcom,mdss-dsi-color-order = <0>;
+ qcom,mdss-dsi-color-order = "rgb_swap_rgb";
qcom,mdss-dsi-underflow-color = <0xff>;
qcom,mdss-dsi-border-color = <0>;
+ qcom,mdss-dsi-pixel-packing = "tight";
qcom,mdss-dsi-on-command = [15 01 00 00 00 00 02 FF 01
29 01 00 00 00 00 05 C6 63 00 81 31
29 01 00 00 00 00 05 CB E7 80 73 33
@@ -81,40 +82,38 @@
29 01 00 00 00 00 05 F6 00 00 00 00
29 01 00 00 00 00 05 F7 00 00 00 00
29 01 00 00 00 00 03 E1 90 00
- 29 01 00 00 00 00 03 DE 95 CF
+ 29 01 00 00 00 00 07 DE 95 CF E2 CE 11 15
29 01 00 00 00 00 02 CF 46
29 01 00 00 00 00 03 C5 77 47
29 01 00 00 00 00 03 ED 00 20
05 01 00 00 B4 00 02 11 00
05 01 00 00 82 00 02 29 00
15 01 00 00 00 00 02 53 2c];
-
- qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 10 00
- 05 01 00 00 32 00 02 53 00
- 05 01 00 00 00 00 02 c2 00
+ qcom,mdss-dsi-off-command = [15 01 00 00 32 00 02 10 00
+ 15 01 00 00 32 00 02 53 00
+ 15 01 00 00 00 00 02 c2 00
39 01 00 00 00 00 02 cf 40
- 05 01 00 00 50 00 03 de 84 00
+ 15 01 00 00 50 00 03 de 84 00
39 01 00 00 00 00 02 cb 22
- 05 01 00 00 00 00 02 c3 00];
-
+ 15 01 00 00 00 00 02 c3 00];
qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
qcom,mdss-dsi-h-sync-pulse = <1>;
- qcom,mdss-dsi-traffic-mode = <2>;
- qcom,mdss-dsi-lane-map = <0>;
+ qcom,mdss-dsi-traffic-mode = "burst_mode";
+ qcom,mdss-dsi-lane-map = "lane_map_0123";
qcom,mdss-dsi-bllp-eof-power-mode;
qcom,mdss-dsi-lane-0-state;
qcom,mdss-dsi-lane-1-state;
qcom,mdss-dsi-lane-2-state;
qcom,mdss-dsi-lane-3-state;
- qcom,mdss-dsi-panel-timings = [a8 1f 17 00 2f 2d 1c 21 29 03 04 00];
+ qcom,mdss-dsi-panel-timings = [68 1d 15 00 2e 2d 19 1f 24 03 04 00];
qcom,mdss-dsi-t-clk-post = <0x20>;
qcom,mdss-dsi-t-clk-pre = <0x2f>;
qcom,mdss-dsi-bl-min-level = <1>;
qcom,mdss-dsi-bl-max-level = <4095>;
- qcom,mdss-dsi-dma-trigger = <4>;
- qcom,mdss-dsi-mdp-trigger = <0>;
+ qcom,mdss-dsi-dma-trigger = "trigger_sw";
+ qcom,mdss-dsi-mdp-trigger = "none";
qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
- qcom,mdss-dsi-reset-sequence = <1 20>, <0 1>, <1 20>;
+ qcom,mdss-dsi-reset-sequence = <1 20>, <0 2>, <1 20>;
};
};
diff --git a/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
index f7de416..10f53b9 100644
--- a/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
@@ -38,7 +38,6 @@
qcom,mdss-dsi-v-top-border = <0>;
qcom,mdss-dsi-v-bottom-border = <0>;
qcom,mdss-dsi-bpp = <24>;
- qcom,mdss-dsi-color-order = <0>;
qcom,mdss-dsi-underflow-color = <0xff>;
qcom,mdss-dsi-border-color = <0>;
qcom,mdss-dsi-on-command = [23 01 00 00 0a 00 02 b0 00
@@ -74,8 +73,7 @@
qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
qcom,mdss-dsi-h-sync-pulse = <0>;
- qcom,mdss-dsi-traffic-mode = <1>;
- qcom,mdss-dsi-lane-map = <0>;
+ qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
qcom,mdss-dsi-bllp-eof-power-mode;
qcom,mdss-dsi-bllp-power-mode;
qcom,mdss-dsi-lane-0-state;
@@ -87,8 +85,8 @@
qcom,mdss-dsi-t-clk-pre = <0x1b>;
qcom,mdss-dsi-bl-min-level = <1>;
qcom,mdss-dsi-bl-max-level = <4095>;
- qcom,mdss-dsi-dma-trigger = <0x04>;
- qcom,mdss-dsi-mdp-trigger = <0x0>;
+ qcom,mdss-dsi-dma-trigger = "trigger_sw";
+ qcom,mdss-dsi-mdp-trigger = "none";
qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
qcom,mdss-dsi-pan-enable-dynamic-fps;
qcom,mdss-dsi-pan-fps-update = "dfps_suspend_resume_mode";
diff --git a/arch/arm/boot/dts/dsi-panel-truly-wvga-cmd.dtsi b/arch/arm/boot/dts/dsi-panel-truly-wvga-cmd.dtsi
index d170833..168dda4 100644
--- a/arch/arm/boot/dts/dsi-panel-truly-wvga-cmd.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-truly-wvga-cmd.dtsi
@@ -39,7 +39,6 @@
qcom,mdss-dsi-v-top-border = <0>;
qcom,mdss-dsi-v-bottom-border = <0>;
qcom,mdss-dsi-bpp = <24>;
- qcom,mdss-dsi-color-order = <0>;
qcom,mdss-dsi-underflow-color = <0xff>;
qcom,mdss-dsi-border-color = <0>;
qcom,mdss-dsi-on-command = [
@@ -146,8 +145,7 @@
qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
qcom,mdss-dsi-off-command-state = "dsi_lp_mode";
qcom,mdss-dsi-h-sync-pulse = <0>;
- qcom,mdss-dsi-traffic-mode = <1>;
- qcom,mdss-dsi-lane-map = <0>;
+ qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
qcom,mdss-dsi-bllp-eof-power-mode;
qcom,mdss-dsi-bllp-power-mode;
qcom,mdss-dsi-lane-0-state;
@@ -163,8 +161,8 @@
qcom,mdss-dsi-t-clk-pre = <0x1b>;
qcom,mdss-dsi-bl-min-level = <1>;
qcom,mdss-dsi-bl-max-level = <255>;
- qcom,mdss-dsi-dma-trigger = <4>;
- qcom,mdss-dsi-mdp-trigger = <2>;
+ qcom,mdss-dsi-dma-trigger = "trigger_sw";
+ qcom,mdss-dsi-mdp-trigger = "trigger_te";
qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
qcom,mdss-dsi-reset-sequence = <1 20>, <0 2>, <1 20>;
};
diff --git a/arch/arm/boot/dts/dsi-panel-truly-wvga-video.dtsi b/arch/arm/boot/dts/dsi-panel-truly-wvga-video.dtsi
index 546a90f..121e54d 100644
--- a/arch/arm/boot/dts/dsi-panel-truly-wvga-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-truly-wvga-video.dtsi
@@ -39,7 +39,6 @@
qcom,mdss-dsi-v-top-border = <0>;
qcom,mdss-dsi-v-bottom-border = <0>;
qcom,mdss-dsi-bpp = <24>;
- qcom,mdss-dsi-color-order = <0>;
qcom,mdss-dsi-underflow-color = <0xff>;
qcom,mdss-dsi-border-color = <0>;
qcom,mdss-dsi-on-command = [
@@ -150,8 +149,7 @@
qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
qcom,mdss-dsi-off-command-state = "dsi_lp_mode";
qcom,mdss-dsi-h-sync-pulse = <0>;
- qcom,mdss-dsi-traffic-mode = <1>;
- qcom,mdss-dsi-lane-map = <0>;
+ qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
qcom,mdss-dsi-bllp-eof-power-mode;
qcom,mdss-dsi-bllp-power-mode;
qcom,mdss-dsi-lane-0-state;
@@ -161,8 +159,8 @@
qcom,mdss-dsi-t-clk-pre = <0x1b>;
qcom,mdss-dsi-bl-min-level = <1>;
qcom,mdss-dsi-bl-max-level = <255>;
- qcom,mdss-dsi-dma-trigger = <4>;
- qcom,mdss-dsi-mdp-trigger = <0>;
+ qcom,mdss-dsi-dma-trigger = "trigger_sw";
+ qcom,mdss-dsi-mdp-trigger = "none";
qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
qcom,mdss-dsi-reset-sequence = <1 20>, <0 2>, <1 20>;
};
diff --git a/arch/arm/boot/dts/fsm9900.dtsi b/arch/arm/boot/dts/fsm9900.dtsi
index 1c48bf0..705a512 100644
--- a/arch/arm/boot/dts/fsm9900.dtsi
+++ b/arch/arm/boot/dts/fsm9900.dtsi
@@ -85,8 +85,9 @@
#address-cells = <1>;
#size-cells = <0>;
- qcom,ion-heap@30 { /* SYSTEM HEAP */
- reg = <30>;
+ qcom,ion-heap@25 {
+ reg = <25>;
+ qcom,ion-heap-type = "SYSTEM";
};
};
diff --git a/arch/arm/boot/dts/mpq8092-ion.dtsi b/arch/arm/boot/dts/mpq8092-ion.dtsi
index f9f5985..903610d 100644
--- a/arch/arm/boot/dts/mpq8092-ion.dtsi
+++ b/arch/arm/boot/dts/mpq8092-ion.dtsi
@@ -16,16 +16,14 @@
#address-cells = <1>;
#size-cells = <0>;
- qcom,ion-heap@30 { /* SYSTEM HEAP */
- reg = <30>;
- };
-
- qcom,ion-heap@21 { /* SYSTEM CONTIG HEAP */
- reg = <21>;
- };
-
- qcom,ion-heap@25 { /* IOMMU HEAP */
+ qcom,ion-heap@25 {
reg = <25>;
+ qcom,ion-heap-type = "SYSTEM";
+ };
+
+ qcom,ion-heap@21 {
+ reg = <21>;
+ qcom,ion-heap-type = "SYSTEM_CONTIG";
};
};
diff --git a/arch/arm/boot/dts/msm-pm8110.dtsi b/arch/arm/boot/dts/msm-pm8110.dtsi
index 2ccb1fb..20e8a96 100644
--- a/arch/arm/boot/dts/msm-pm8110.dtsi
+++ b/arch/arm/boot/dts/msm-pm8110.dtsi
@@ -328,7 +328,7 @@
qcom,low-voltage-threshold = <3420000>;
qcom,tm-temp-margin = <5000>;
qcom,low-ocv-correction-limit-uv = <100>;
- qcom,high-ocv-correction-limit-uv = <50>;
+ qcom,high-ocv-correction-limit-uv = <250>;
qcom,hold-soc-est = <3>;
qcom,bms-vadc = <&pm8110_vadc>;
qcom,bms-iadc = <&pm8110_iadc>;
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index b9bcd0c..a13e66a 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -206,7 +206,7 @@
qcom,batt-type = <0>;
qcom,tm-temp-margin = <5000>;
qcom,low-ocv-correction-limit-uv = <100>;
- qcom,high-ocv-correction-limit-uv = <50>;
+ qcom,high-ocv-correction-limit-uv = <250>;
qcom,hold-soc-est = <3>;
qcom,low-voltage-threshold = <3420000>;
qcom,bms-vadc = <&pm8226_vadc>;
@@ -860,22 +860,6 @@
qcom,current = <625>;
};
- pm8226_flash1: qcom,flash_1 {
- qcom,max-current = <1000>;
- qcom,default-state = "off";
- qcom,headroom = <3>;
- qcom,duration = <1280>;
- qcom,clamp-curr = <200>;
- qcom,startup-dly = <3>;
- qcom,safety-timer;
- linux,default-trigger =
- "flash1_trigger";
- label = "flash";
- qcom,id = <2>;
- linux,name = "led:flash_1";
- qcom,current = <625>;
- };
-
pm8226_torch: qcom,flash_torch {
qcom,max-current = <200>;
qcom,default-state = "off";
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index b540063..520decd 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -135,7 +135,7 @@
qcom,low-voltage-threshold = <3420000>;
qcom,tm-temp-margin = <5000>;
qcom,low-ocv-correction-limit-uv = <100>;
- qcom,high-ocv-correction-limit-uv = <50>;
+ qcom,high-ocv-correction-limit-uv = <250>;
qcom,hold-soc-est = <3>;
qcom,bms-vadc = <&pm8941_vadc>;
qcom,bms-iadc = <&pm8941_iadc>;
@@ -209,7 +209,9 @@
qcom,resume-soc = <99>;
qcom,tchg-mins = <150>;
qcom,chg-vadc = <&pm8941_vadc>;
+ qcom,chg-iadc = <&pm8941_iadc>;
qcom,chg-adc_tm = <&pm8941_adc_tm>;
+ qcom,ibat-calibration-enabled;
qcom,chgr@1000 {
status = "disabled";
diff --git a/arch/arm/boot/dts/msm-rdbg.dtsi b/arch/arm/boot/dts/msm-rdbg.dtsi
new file mode 100644
index 0000000..f7f52be
--- /dev/null
+++ b/arch/arm/boot/dts/msm-rdbg.dtsi
@@ -0,0 +1,75 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+ smp2pgpio_rdbg_2_in: qcom,smp2pgpio-rdbg-2-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "rdbg";
+ qcom,remote-pid = <2>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_client_rdbg_2_in {
+ compatible = "qcom,smp2pgpio_client_rdbg_2_in";
+ gpios = <&smp2pgpio_rdbg_2_in 0 0>;
+ };
+
+ smp2pgpio_rdbg_2_out: qcom,smp2pgpio-rdbg-2-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "rdbg";
+ qcom,remote-pid = <2>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_client_rdbg_2_out {
+ compatible = "qcom,smp2pgpio_client_rdbg_2_out";
+ gpios = <&smp2pgpio_rdbg_2_out 0 0>;
+ };
+
+ smp2pgpio_rdbg_1_in: qcom,smp2pgpio-rdbg-1-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "rdbg";
+ qcom,remote-pid = <1>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_client_rdbg_1_in {
+ compatible = "qcom,smp2pgpio_client_rdbg_1_in";
+ gpios = <&smp2pgpio_rdbg_1_in 0 0>;
+ };
+
+ smp2pgpio_rdbg_1_out: qcom,smp2pgpio-rdbg-1-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "rdbg";
+ qcom,remote-pid = <1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_client_rdbg_1_out {
+ compatible = "qcom,smp2pgpio_client_rdbg_1_out";
+ gpios = <&smp2pgpio_rdbg_1_out 0 0>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8226-cdp.dtsi b/arch/arm/boot/dts/msm8226-1080p-cdp.dtsi
similarity index 91%
copy from arch/arm/boot/dts/msm8226-cdp.dtsi
copy to arch/arm/boot/dts/msm8226-1080p-cdp.dtsi
index 3ebe225..bb66538 100644
--- a/arch/arm/boot/dts/msm8226-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8226-1080p-cdp.dtsi
@@ -27,13 +27,37 @@
vcc_i2c-supply = <&pm8226_lvs1>;
synaptics,reset-gpio = <&msmgpio 16 0x00>;
synaptics,irq-gpio = <&msmgpio 17 0x2008>;
- synaptics,button-map = <139 102 158>;
+ synaptics,display-coords = <0 0 1079 1919>;
synaptics,i2c-pull-up;
synaptics,power-down;
synaptics,disable-gpios;
};
};
+ gen-vkeys {
+ compatible = "qcom,gen-vkeys";
+ label = "synaptics_rmi4_i2c";
+ qcom,disp-maxx = <1079>;
+ qcom,disp-maxy = <1919>;
+ qcom,panel-maxx = <1079>;
+ qcom,panel-maxy = <2084>;
+ qcom,key-codes = <158 139 102 217>;
+ };
+
+ i2c@f9925000 { /* BLSP1 QUP3 */
+ nfc-nci@0e {
+ compatible = "qcom,nfc-nci";
+ reg = <0x0e>;
+ qcom,irq-gpio = <&msmgpio 21 0x00>;
+ qcom,dis-gpio = <&msmgpio 20 0x00>;
+ qcom,clk-src = "BBCLK2";
+ qcom,clk-en-gpio = <&msmgpio 0 0x00>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <21 0>;
+ qcom,clk-gpio = <&pm8226_gpios 3 0>;
+ };
+ };
+
gpio_keys {
compatible = "gpio-keys";
input-name = "gpio-keys";
@@ -370,6 +394,11 @@
};
gpio@c200 { /* GPIO 3 */
+ qcom,mode = <0>; /* QPNP_PIN_MODE_DIG_IN */
+ qcom,pull = <5>; /* QPNP_PIN_PULL_NO */
+ qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
+ qcom,src-sel = <2>; /* QPNP_PIN_SEL_FUNC_1 */
+ qcom,master-en = <1>;
};
gpio@c300 { /* GPIO 4 */
@@ -464,9 +493,10 @@
};
&mdss_dsi0 {
- qcom,dsi-pref-prim-pan = <&dsi_nt35590_720_vid>;
+ qcom,dsi-pref-prim-pan = <&dsi_jdi_1080_vid>;
+ qcom,platform-enable-gpio = <&msmgpio 109 0>;
};
-&dsi_nt35590_720_vid {
+&dsi_jdi_1080_vid {
qcom,cont-splash-enabled;
};
diff --git a/arch/arm/boot/dts/msm8226-mtp.dtsi b/arch/arm/boot/dts/msm8226-1080p-mtp.dtsi
similarity index 96%
copy from arch/arm/boot/dts/msm8226-mtp.dtsi
copy to arch/arm/boot/dts/msm8226-1080p-mtp.dtsi
index a4bd8fd..31624de 100644
--- a/arch/arm/boot/dts/msm8226-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-1080p-mtp.dtsi
@@ -27,13 +27,23 @@
vcc_i2c-supply = <&pm8226_lvs1>;
synaptics,reset-gpio = <&msmgpio 16 0x00>;
synaptics,irq-gpio = <&msmgpio 17 0x2008>;
- synaptics,button-map = <139 102 158>;
+ synaptics,display-coords = <0 0 1079 1919>;
synaptics,i2c-pull-up;
synaptics,power-down;
synaptics,disable-gpios;
};
};
+ gen-vkeys {
+ compatible = "qcom,gen-vkeys";
+ label = "synaptics_rmi4_i2c";
+ qcom,disp-maxx = <1079>;
+ qcom,disp-maxy = <1919>;
+ qcom,panel-maxx = <1079>;
+ qcom,panel-maxy = <2084>;
+ qcom,key-codes = <158 139 102 217>;
+ };
+
i2c@f9925000 { /* BLSP1 QUP3 */
nfc-nci@0e {
compatible = "qcom,nfc-nci";
@@ -476,12 +486,12 @@
&pm8226_bms {
status = "ok";
+ qcom,battery-data = <&mtp_batterydata>;
qcom,enable-fcc-learning;
qcom,min-fcc-learning-soc = <20>;
qcom,min-fcc-ocv-pc = <30>;
qcom,min-fcc-learning-samples = <5>;
qcom,fcc-resolution = <10>;
- qcom,battery-data = <&mtp_batterydata>;
};
&pm8226_chg {
@@ -497,13 +507,13 @@
&mdss_mdp {
qcom,mdss-pref-prim-intf = "dsi";
- batfet-supply = <&pm8226_chg_batif>;
};
&mdss_dsi0 {
- qcom,dsi-pref-prim-pan = <&dsi_nt35590_720_vid>;
+ qcom,dsi-pref-prim-pan = <&dsi_jdi_1080_vid>;
+ qcom,platform-enable-gpio = <&msmgpio 109 0>;
};
-&dsi_nt35590_720_vid {
+&dsi_jdi_1080_vid {
qcom,cont-splash-enabled;
};
diff --git a/arch/arm/boot/dts/msm8226-cdp.dtsi b/arch/arm/boot/dts/msm8226-720p-cdp.dtsi
similarity index 99%
rename from arch/arm/boot/dts/msm8226-cdp.dtsi
rename to arch/arm/boot/dts/msm8226-720p-cdp.dtsi
index 3ebe225..9a1eb36 100644
--- a/arch/arm/boot/dts/msm8226-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8226-720p-cdp.dtsi
@@ -28,6 +28,7 @@
synaptics,reset-gpio = <&msmgpio 16 0x00>;
synaptics,irq-gpio = <&msmgpio 17 0x2008>;
synaptics,button-map = <139 102 158>;
+ synaptics,fw-image-name = "PR1468813.img";
synaptics,i2c-pull-up;
synaptics,power-down;
synaptics,disable-gpios;
diff --git a/arch/arm/boot/dts/msm8226-mtp.dtsi b/arch/arm/boot/dts/msm8226-720p-mtp.dtsi
similarity index 99%
rename from arch/arm/boot/dts/msm8226-mtp.dtsi
rename to arch/arm/boot/dts/msm8226-720p-mtp.dtsi
index a4bd8fd..7f4f8fc 100644
--- a/arch/arm/boot/dts/msm8226-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-720p-mtp.dtsi
@@ -28,6 +28,7 @@
synaptics,reset-gpio = <&msmgpio 16 0x00>;
synaptics,irq-gpio = <&msmgpio 17 0x2008>;
synaptics,button-map = <139 102 158>;
+ synaptics,fw-image-name = "PR1468813.img";
synaptics,i2c-pull-up;
synaptics,power-down;
synaptics,disable-gpios;
diff --git a/arch/arm/boot/dts/msm8226-bus.dtsi b/arch/arm/boot/dts/msm8226-bus.dtsi
index d87aa3e..74b4a30 100644
--- a/arch/arm/boot/dts/msm8226-bus.dtsi
+++ b/arch/arm/boot/dts/msm8226-bus.dtsi
@@ -78,7 +78,7 @@
mas-vfe {
cell-id = <29>;
label = "mas-vfe";
- qcom,masterp = <16>;
+ qcom,masterp = <7>;
qcom,tier = <2>;
qcom,hw-sel = "NoC";
qcom,perm-mode = "Bypass";
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
index fa5c739..20bb2aa 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
@@ -17,7 +17,7 @@
cell-index = <0>;
compatible = "qcom,camera-led-flash";
qcom,flash-type = <1>;
- qcom,flash-source = <&pm8226_flash0 &pm8226_flash1>;
+ qcom,flash-source = <&pm8226_flash0>;
qcom,torch-source = <&pm8226_torch>;
};
};
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
index 5d1e1c8..07a4383 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
@@ -17,7 +17,7 @@
cell-index = <0>;
compatible = "qcom,camera-led-flash";
qcom,flash-type = <1>;
- qcom,flash-source = <&pm8226_flash0 &pm8226_flash1>;
+ qcom,flash-source = <&pm8226_flash0>;
qcom,torch-source = <&pm8226_torch>;
};
};
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
index fd6d618..0436600 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
@@ -17,7 +17,7 @@
cell-index = <0>;
compatible = "qcom,camera-led-flash";
qcom,flash-type = <1>;
- qcom,flash-source = <&pm8226_flash0 &pm8226_flash1>;
+ qcom,flash-source = <&pm8226_flash0>;
qcom,torch-source = <&pm8226_torch>;
};
};
diff --git a/arch/arm/boot/dts/msm8226-camera.dtsi b/arch/arm/boot/dts/msm8226-camera.dtsi
index 4987dae..3e8444f 100644
--- a/arch/arm/boot/dts/msm8226-camera.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera.dtsi
@@ -136,29 +136,29 @@
};
&master0 {
- qcom,hw-thigh = <78>;
- qcom,hw-tlow = <114>;
- qcom,hw-tsu-sto = <28>;
- qcom,hw-tsu-sta = <28>;
- qcom,hw-thd-dat = <10>;
- qcom,hw-thd-sta = <77>;
- qcom,hw-tbuf = <118>;
+ qcom,hw-thigh = <20>;
+ qcom,hw-tlow = <28>;
+ qcom,hw-tsu-sto = <21>;
+ qcom,hw-tsu-sta = <21>;
+ qcom,hw-thd-dat = <13>;
+ qcom,hw-thd-sta = <18>;
+ qcom,hw-tbuf = <25>;
qcom,hw-scl-stretch-en = <0>;
qcom,hw-trdhld = <6>;
- qcom,hw-tsp = <1>;
+ qcom,hw-tsp = <3>;
status = "ok";
};
&master1 {
- qcom,hw-thigh = <78>;
- qcom,hw-tlow = <114>;
- qcom,hw-tsu-sto = <28>;
- qcom,hw-tsu-sta = <28>;
- qcom,hw-thd-dat = <10>;
- qcom,hw-thd-sta = <77>;
- qcom,hw-tbuf = <118>;
+ qcom,hw-thigh = <20>;
+ qcom,hw-tlow = <28>;
+ qcom,hw-tsu-sto = <21>;
+ qcom,hw-tsu-sta = <21>;
+ qcom,hw-thd-dat = <13>;
+ qcom,hw-thd-sta = <18>;
+ qcom,hw-tbuf = <25>;
qcom,hw-scl-stretch-en = <0>;
qcom,hw-trdhld = <6>;
- qcom,hw-tsp = <1>;
+ qcom,hw-tsp = <3>;
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8226-ion.dtsi b/arch/arm/boot/dts/msm8226-ion.dtsi
index 30c3209..443334e 100644
--- a/arch/arm/boot/dts/msm8226-ion.dtsi
+++ b/arch/arm/boot/dts/msm8226-ion.dtsi
@@ -16,12 +16,14 @@
#address-cells = <1>;
#size-cells = <0>;
- qcom,ion-heap@30 { /* SYSTEM HEAP */
- reg = <30>;
+ qcom,ion-heap@25 {
+ reg = <25>;
+ qcom,ion-heap-type = "SYSTEM";
};
- qcom,ion-heap@21 { /* SYSTEM CONTIG HEAP */
+ qcom,ion-heap@21 {
reg = <21>;
+ qcom,ion-heap-type = "SYSTEM_CONTIG";
};
qcom,ion-heap@8 { /* CP_MM HEAP */
@@ -29,10 +31,8 @@
reg = <8>;
qcom,heap-align = <0x1000>;
linux,contiguous-region = <&secure_mem>;
- };
-
- qcom,ion-heap@25 { /* IOMMU HEAP */
- reg = <25>;
+ qcom,ion-heap-type = "SECURE_DMA";
+ qcom,default-prefetch-size = <0x3c00000>;
};
qcom,ion-heap@22 { /* adsp heap */
@@ -40,12 +40,14 @@
reg = <22>;
qcom,heap-align = <0x1000>;
linux,contiguous-region = <&adsp_mem>;
+ qcom,ion-heap-type = "DMA";
};
qcom,ion-heap@27 { /* QSECOM HEAP */
compatible = "qcom,msm-ion-reserve";
reg = <27>;
linux,contiguous-region = <&qsecom_mem>;
+ qcom,ion-heap-type = "DMA";
};
qcom,ion-heap@28 { /* AUDIO HEAP */
@@ -54,6 +56,7 @@
qcom,heap-align = <0x1000>;
qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
qcom,memory-reservation-size = <0x314000>;
+ qcom,ion-heap-type = "CARVEOUT";
};
qcom,ion-heap@23 { /* OTHER PIL HEAP */
@@ -61,6 +64,7 @@
reg = <23>;
qcom,heap-align = <0x1000>;
qcom,memory-fixed = <0x0dc00000 0x1900000>;
+ qcom,ion-heap-type = "CARVEOUT";
};
};
diff --git a/arch/arm/boot/dts/msm8226-mdss-panels.dtsi b/arch/arm/boot/dts/msm8226-mdss-panels.dtsi
index eeec175..0731a9a 100644
--- a/arch/arm/boot/dts/msm8226-mdss-panels.dtsi
+++ b/arch/arm/boot/dts/msm8226-mdss-panels.dtsi
@@ -16,3 +16,4 @@
/include/ "dsi-panel-nt35596-1080p-video.dtsi"
/include/ "dsi-panel-nt35590-720p-cmd.dtsi"
/include/ "dsi-panel-ssd2080m-720p-video.dtsi"
+/include/ "dsi-panel-jdi-1080p-video.dtsi"
diff --git a/arch/arm/boot/dts/msm8226-mdss.dtsi b/arch/arm/boot/dts/msm8226-mdss.dtsi
index 3e2507ff..38cfe66 100644
--- a/arch/arm/boot/dts/msm8226-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8226-mdss.dtsi
@@ -19,6 +19,8 @@
interrupts = <0 72 0>;
vdd-supply = <&gdsc_mdss>;
+ qcom,max-bandwidth-low-kbps = <1660000>;
+ qcom,max-bandwidth-high-kbps = <1660000>;
qcom,max-clk-rate = <200000000>;
qcom,mdss-pipe-vig-off = <0x00001200>;
qcom,mdss-pipe-rgb-off = <0x00001E00>;
@@ -36,7 +38,7 @@
qcom,mdss-wb-off = <0x00011100 0x00013100>;
qcom,mdss-intf-off = <0x00000000 0x00021300>;
qcom,mdss-rot-block-size = <64>;
- qcom,mdss-smp-mb-per-pipe = <2>;
+ qcom,mdss-smp-mb-per-pipe = <4>;
vdd-cx-supply = <&pm8226_s1_corner>;
qcom,vbif-settings = <0x004 0x00000001>,
diff --git a/arch/arm/boot/dts/msm8226-qrd-skuf.dtsi b/arch/arm/boot/dts/msm8226-qrd-skuf.dtsi
index 66f5095..2e32ac4 100755
--- a/arch/arm/boot/dts/msm8226-qrd-skuf.dtsi
+++ b/arch/arm/boot/dts/msm8226-qrd-skuf.dtsi
@@ -85,25 +85,25 @@
goodix,button-map= <158 102 139>;
goodix,product-id = "915";
goodix,cfg-data0 = [
- 41 D0 02 00 05 05 35 01 01 0F
- 2D 06 50 32 03 05 00 00 00 00
- 00 00 05 18 1A 1E 14 8C 0E 0E
- 3F 3D 2A 09 00 00 00 99 04 1D
- 00 00 00 00 00 00 00 00 00 00
- 00 32 6E 94 D5 01 05 00 00 04
- CE 36 00 B5 3F 00 9E 4A 00 8B
- 57 00 7C 65 00 7C 10 38 68 00
- 56 50 35 66 66 27 00 00 00 00
+ 41 D0 02 00 05 05 35 11 01 0F
+ 2D 06 50 32 03 02 00 00 00 00
+ 00 00 05 18 1A 1E 14 8C 2E 0E
+ 59 5B B2 04 00 00 00 99 03 11
+ 00 1C 00 00 00 00 00 00 00 00
+ 00 53 A6 94 C5 01 05 00 00 08
+ 7F 59 00 71 66 00 64 75 00 58
+ 87 00 4E 9B 00 4E 10 38 68 00
+ 56 45 30 66 66 27 00 00 00 00
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
00 00 02 04 06 08 0A 0C 0E 10
- 12 14 16 18 1A 1C 00 00 00 00
- 00 00 00 00 00 00 00 00 00 00
- 00 00 00 02 04 06 08 0A 0C 0F
+ 12 14 16 18 1A 1C FF FF FF FF
+ FF FF FF FF FF FF FF FF FF FF
+ FF FF 00 02 04 06 08 0A 0C 0F
10 12 13 14 16 18 1C 1D 1E 1F
- 20 21 22 24 26 28 29 2A 00 00
- 00 FF FF FF FF FF FF FF FF FF
- FF FF FF FF A3 01];
+ 20 21 22 24 26 28 29 2A FF FF
+ FF FF FF FF FF FF FF FF FF FF
+ FF FF FF FF 03 01];
goodix,cfg-data1 = [
41 D0 02 00 05 05 35 01 01 C3
2D 06 55 32 03 03 00 00 00 00
@@ -124,6 +124,7 @@
20 21 22 24 26 28 29 2A FF FF
FF FF FF FF FF FF FF FF FF FF
FF FF FF FF 3E 01];
+ goodix,fw_name = "gtp_fw.bin";
};
};
};
diff --git a/arch/arm/boot/dts/msm8226-qrd.dtsi b/arch/arm/boot/dts/msm8226-qrd.dtsi
index eac0bb6..7ff97f6 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8226-qrd.dtsi
@@ -28,6 +28,7 @@
synaptics,reset-gpio = <&msmgpio 16 0x00>;
synaptics,irq-gpio = <&msmgpio 17 0x2008>;
synaptics,button-map = <139 102 158>;
+ synaptics,fw-image-name = "PR1468813.img";
synaptics,i2c-pull-up;
synaptics,power-down;
synaptics,disable-gpios;
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index 23a2158..0146367 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -20,6 +20,7 @@
reg = <0x1700 0x100>;
regulator-min-microvolt = <900000>;
regulator-max-microvolt = <1275000>;
+ qcom,mode = "auto";
};
};
};
@@ -35,11 +36,11 @@
interrupts = <0 15 0>;
regulator-name = "apc_corner";
regulator-min-microvolt = <1>;
- regulator-max-microvolt = <3>;
+ regulator-max-microvolt = <12>;
- qcom,pvs-fuse-redun-sel = <22 24 3 2>;
- qcom,pvs-fuse = <22 6 5>;
- qcom,pvs-fuse-redun = <22 27 5>;
+ qcom,pvs-fuse-redun-sel = <22 24 3 2 0>;
+ qcom,pvs-fuse = <22 6 5 0>;
+ qcom,pvs-fuse-redun = <22 27 5 0>;
qcom,pvs-init-voltage = <1275000 1275000 1275000 1275000 1275000
1275000 1260000 1245000 1230000 1215000
@@ -50,7 +51,7 @@
1275000 1275000>;
qcom,pvs-corner-ceiling-slow = <1050000 1150000 1275000>;
qcom,pvs-corner-ceiling-nom = <1050000 1075000 1200000>;
- qcom,pvs-corner-ceiling-fast = <1050000 1050000 1140000>;
+ qcom,pvs-corner-ceiling-fast = <1050000 1050000 1100000>;
vdd-apc-supply = <&pm8226_s2>;
vdd-mx-supply = <&pm8226_l3_ao>;
@@ -71,17 +72,34 @@
qcom,vdd-apc-step-down-limit = <1>;
qcom,cpr-apc-volt-step = <5000>;
- qcom,cpr-fuse-redun-sel = <138 57 1 1>;
- qcom,cpr-fuse-row = <138>;
+ qcom,cpr-fuse-redun-sel = <138 57 1 1 0>;
+ qcom,cpr-fuse-row = <138 0>;
qcom,cpr-fuse-bp-cpr-disable = <36>;
qcom,cpr-fuse-bp-scheme = <37>;
qcom,cpr-fuse-target-quot = <24 12 0>;
qcom,cpr-fuse-ro-sel = <54 38 41>;
- qcom,cpr-fuse-redun-row = <139>;
+ qcom,cpr-fuse-redun-row = <139 0>;
qcom,cpr-fuse-redun-target-quot = <24 12 0>;
qcom,cpr-fuse-redun-ro-sel = <46 36 39>;
qcom,cpr-enable;
+ qcom,cpr-fuse-cond-min-volt-sel = <54 42 6 7 1>;
+ qcom,cpr-cond-min-voltage = <1140000>;
+ qcom,cpr-fuse-uplift-sel = <22 53 1 0 0>;
+ qcom,cpr-uplift-voltage = <50000>;
+ qcom,cpr-uplift-quotient = <0 0 120>;
+ qcom,cpr-uplift-max-volt = <1350000>;
+ qcom,cpr-uplift-speed-bin = <1>;
+ qcom,speed-bin-fuse-sel = <22 0 3 0>;
+ qcom,cpr-corner-map = <1 1 2 2 3 3 3 3 3 3 3 3>;
+ qcom,cpr-quot-adjust-table =
+ <1 5 450>,
+ <1 6 375>,
+ <1 7 300>,
+ <1 8 225>,
+ <1 9 187>,
+ <1 10 150>,
+ <1 11 75>;
};
};
@@ -336,7 +354,7 @@
pm8226_l16: regulator-l16 {
regulator-name = "8226_l16";
regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3300000>;
+ regulator-max-microvolt = <3350000>;
qcom,init-voltage = <3300000>;
status = "okay";
};
@@ -423,7 +441,7 @@
pm8226_l24: regulator-l24 {
regulator-name = "8226_l24";
regulator-min-microvolt = <1300000>;
- regulator-max-microvolt = <1300000>;
+ regulator-max-microvolt = <1350000>;
qcom,init-voltage = <1300000>;
status = "okay";
};
diff --git a/arch/arm/boot/dts/msm8226-v1-cdp.dts b/arch/arm/boot/dts/msm8226-v1-cdp.dts
index e426a97..4b8cafd 100644
--- a/arch/arm/boot/dts/msm8226-v1-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-v1-cdp.dts
@@ -12,7 +12,7 @@
/dts-v1/;
/include/ "msm8226-v1.dtsi"
-/include/ "msm8226-cdp.dtsi"
+/include/ "msm8226-720p-cdp.dtsi"
/ {
model = "Qualcomm MSM 8226 CDP";
diff --git a/arch/arm/boot/dts/msm8226-v1-mtp.dts b/arch/arm/boot/dts/msm8226-v1-mtp.dts
index 08d7cec..a1e78b7 100644
--- a/arch/arm/boot/dts/msm8226-v1-mtp.dts
+++ b/arch/arm/boot/dts/msm8226-v1-mtp.dts
@@ -12,7 +12,7 @@
/dts-v1/;
/include/ "msm8226-v1.dtsi"
-/include/ "msm8226-mtp.dtsi"
+/include/ "msm8226-720p-mtp.dtsi"
/ {
model = "Qualcomm MSM 8226 MTP";
diff --git a/arch/arm/boot/dts/msm8226-v1-pm.dtsi b/arch/arm/boot/dts/msm8226-v1-pm.dtsi
index 02feec8..a1a8480 100644
--- a/arch/arm/boot/dts/msm8226-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-v1-pm.dtsi
@@ -111,44 +111,68 @@
#address-cells = <1>;
#size-cells = <0>;
- qcom,lpm-level@0 {
- reg = <0x0>;
- qcom,mode = "wfi";
- qcom,l2 = "l2_cache_active";
- qcom,latency-us = <1>;
- qcom,ss-power = <530>;
- qcom,energy-overhead = <52800>;
- qcom,time-overhead = <100>;
+ qcm,cpu-modes {
+ compatible = "qcom,cpu-modes";
+
+ qcom,cpu-modes@0 {
+ qcom,mode = "wfi";
+ qcom,latency-us = <1>;
+ qcom,ss-power = <530>;
+ qcom,energy-overhead = <52800>;
+ qcom,time-overhead = <100>;
+ };
+
+ qcom,cpu-modes@1 {
+ qcom,mode = "standalone_pc";
+ qcom,latency-us = <500>;
+ qcom,ss-power = <410>;
+ qcom,energy-overhead = <603400>;
+ qcom,time-overhead = <1200>;
+ qcom,use-broadcast-timer;
+ };
+
+ qcom,cpu-modes@2 {
+ qcom,mode = "pc";
+ qcom,latency-us = <550>;
+ qcom,ss-power = <372>;
+ qcom,energy-overhead = <700000>;
+ qcom,time-overhead = <1410>;
+ qcom,use-broadcast-timer;
+ };
};
- qcom,lpm-level@1 {
- reg = <0x1>;
- qcom,mode = "standalone_pc";
- qcom,l2 = "l2_cache_active";
- qcom,latency-us = <500>;
- qcom,ss-power = <410>;
- qcom,energy-overhead = <603400>;
- qcom,time-overhead = <1200>;
- };
+ qcom,system-modes {
+ compatible = "qcom,system-modes";
- qcom,lpm-level@2 {
- reg = <0x2>;
- qcom,mode = "pc";
- qcom,l2 = "l2_cache_pc_no_rpm";
- qcom,latency-us = <1000>;
- qcom,ss-power = <315>;
- qcom,energy-overhead = <1027150>;
- qcom,time-overhead = <2400>;
- };
+ qcom,system-modes@0 {
+ qcom,l2 = "l2_cache_gdhs";
+ qcom,latency-us = <10700>;
+ qcom,ss-power = <372>;
+ qcom,energy-overhead = <738750>;
+ qcom,time-overhead = <1410>;
+ qcom,min-cpu-mode= "pc";
+ qcom,sync-cpus;
+ };
- qcom,lpm-level@3 {
- reg = <0x3>;
- qcom,mode = "pc";
- qcom,l2 = "l2_cache_pc";
- qcom,latency-us = <11000>;
- qcom,ss-power = <315>;
- qcom,energy-overhead = <1027150>;
- qcom,time-overhead = <2400>;
+ qcom,system-modes@1 {
+ qcom,l2 = "l2_cache_pc_no_rpm";
+ qcom,latency-us = <1000>;
+ qcom,ss-power = <315>;
+ qcom,energy-overhead = <1027150>;
+ qcom,time-overhead = <2400>;
+ qcom,min-cpu-mode= "standalone_pc";
+ qcom,sync-cpus;
+ };
+
+ qcom,system-modes@2 {
+ qcom,l2 = "l2_cache_pc";
+ qcom,latency-us = <12700>;
+ qcom,ss-power = <315>;
+ qcom,energy-overhead = <1027150>;
+ qcom,time-overhead = <2400>;
+ qcom,min-cpu-mode= "pc";
+ qcom,sync-cpus;
+ };
};
};
@@ -280,6 +304,8 @@
qcom,pc-mode = "tz_l2_int";
qcom,use-sync-timer;
qcom,pc-resets-timer;
+ qcom,cpus-as-clocks;
+ qcom,synced-clocks;
};
qcom,cpu-sleep-status@f9088008{
diff --git a/arch/arm/boot/dts/msm8226-v2-cdp.dts b/arch/arm/boot/dts/msm8226-v2-1080p-cdp.dts
similarity index 92%
copy from arch/arm/boot/dts/msm8226-v2-cdp.dts
copy to arch/arm/boot/dts/msm8226-v2-1080p-cdp.dts
index 3302d26..77cc08c 100644
--- a/arch/arm/boot/dts/msm8226-v2-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-v2-1080p-cdp.dts
@@ -12,13 +12,13 @@
/dts-v1/;
/include/ "msm8226-v2.dtsi"
-/include/ "msm8226-cdp.dtsi"
+/include/ "msm8226-1080p-cdp.dtsi"
/include/ "msm8226-camera-sensor-cdp.dtsi"
/ {
model = "Qualcomm MSM 8226v2 CDP";
compatible = "qcom,msm8226-cdp", "qcom,msm8226", "qcom,cdp";
- qcom,board-id = <1 0>;
+ qcom,board-id = <1 2>;
};
&hsic_host {
diff --git a/arch/arm/boot/dts/msm8226-v2-mtp.dts b/arch/arm/boot/dts/msm8226-v2-1080p-mtp.dts
similarity index 92%
copy from arch/arm/boot/dts/msm8226-v2-mtp.dts
copy to arch/arm/boot/dts/msm8226-v2-1080p-mtp.dts
index 6034107..b12a77d 100644
--- a/arch/arm/boot/dts/msm8226-v2-mtp.dts
+++ b/arch/arm/boot/dts/msm8226-v2-1080p-mtp.dts
@@ -12,11 +12,11 @@
/dts-v1/;
/include/ "msm8226-v2.dtsi"
-/include/ "msm8226-mtp.dtsi"
+/include/ "msm8226-1080p-mtp.dtsi"
/include/ "msm8226-camera-sensor-mtp.dtsi"
/ {
model = "Qualcomm MSM 8226v2 MTP";
compatible = "qcom,msm8226-mtp", "qcom,msm8226", "qcom,mtp";
- qcom,board-id = <8 0>;
+ qcom,board-id = <8 2>;
};
diff --git a/arch/arm/boot/dts/msm8226-v2-cdp.dts b/arch/arm/boot/dts/msm8226-v2-720p-cdp.dts
similarity index 95%
rename from arch/arm/boot/dts/msm8226-v2-cdp.dts
rename to arch/arm/boot/dts/msm8226-v2-720p-cdp.dts
index 3302d26..966ae2b 100644
--- a/arch/arm/boot/dts/msm8226-v2-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-v2-720p-cdp.dts
@@ -12,7 +12,7 @@
/dts-v1/;
/include/ "msm8226-v2.dtsi"
-/include/ "msm8226-cdp.dtsi"
+/include/ "msm8226-720p-cdp.dtsi"
/include/ "msm8226-camera-sensor-cdp.dtsi"
/ {
diff --git a/arch/arm/boot/dts/msm8226-v2-mtp.dts b/arch/arm/boot/dts/msm8226-v2-720p-mtp.dts
similarity index 95%
rename from arch/arm/boot/dts/msm8226-v2-mtp.dts
rename to arch/arm/boot/dts/msm8226-v2-720p-mtp.dts
index 6034107..0768b75 100644
--- a/arch/arm/boot/dts/msm8226-v2-mtp.dts
+++ b/arch/arm/boot/dts/msm8226-v2-720p-mtp.dts
@@ -12,7 +12,7 @@
/dts-v1/;
/include/ "msm8226-v2.dtsi"
-/include/ "msm8226-mtp.dtsi"
+/include/ "msm8226-720p-mtp.dtsi"
/include/ "msm8226-camera-sensor-mtp.dtsi"
/ {
diff --git a/arch/arm/boot/dts/msm8226-v2-pm.dtsi b/arch/arm/boot/dts/msm8226-v2-pm.dtsi
index 31d5a8f..2e9f6db 100644
--- a/arch/arm/boot/dts/msm8226-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-v2-pm.dtsi
@@ -113,54 +113,68 @@
#address-cells = <1>;
#size-cells = <0>;
- qcom,lpm-level@0 {
- reg = <0x0>;
- qcom,mode = "wfi";
- qcom,l2 = "l2_cache_active";
- qcom,latency-us = <1>;
- qcom,ss-power = <530>;
- qcom,energy-overhead = <52800>;
- qcom,time-overhead = <100>;
+ qcm,cpu-modes {
+ compatible = "qcom,cpu-modes";
+
+ qcom,cpu-modes@0 {
+ qcom,mode = "wfi";
+ qcom,latency-us = <1>;
+ qcom,ss-power = <530>;
+ qcom,energy-overhead = <52800>;
+ qcom,time-overhead = <100>;
+ };
+
+ qcom,cpu-modes@1 {
+ qcom,mode = "standalone_pc";
+ qcom,latency-us = <500>;
+ qcom,ss-power = <410>;
+ qcom,energy-overhead = <603400>;
+ qcom,time-overhead = <1200>;
+ qcom,use-broadcast-timer;
+ };
+
+ qcom,cpu-modes@2 {
+ qcom,mode = "pc";
+ qcom,latency-us = <550>;
+ qcom,ss-power = <372>;
+ qcom,energy-overhead = <700000>;
+ qcom,time-overhead = <1410>;
+ qcom,use-broadcast-timer;
+ };
};
- qcom,lpm-level@1 {
- reg = <0x1>;
- qcom,mode = "standalone_pc";
- qcom,l2 = "l2_cache_active";
- qcom,latency-us = <500>;
- qcom,ss-power = <410>;
- qcom,energy-overhead = <603400>;
- qcom,time-overhead = <1200>;
- };
+ qcom,system-modes {
+ compatible = "qcom,system-modes";
- qcom,lpm-level@2 {
- reg = <0x2>;
- qcom,mode = "pc";
- qcom,l2 = "l2_cache_gdhs";
- qcom,latency-us = <10700>;
- qcom,ss-power = <372>;
- qcom,energy-overhead = <738750>;
- qcom,time-overhead = <1410>;
- };
+ qcom,system-modes@0 {
+ qcom,l2 = "l2_cache_gdhs";
+ qcom,latency-us = <10700>;
+ qcom,ss-power = <372>;
+ qcom,energy-overhead = <738750>;
+ qcom,time-overhead = <1410>;
+ qcom,min-cpu-mode= "pc";
+ qcom,sync-cpus;
+ };
- qcom,lpm-level@3 {
- reg = <0x3>;
- qcom,mode = "pc";
- qcom,l2 = "l2_cache_pc_no_rpm";
- qcom,latency-us = <1000>;
- qcom,ss-power = <315>;
- qcom,energy-overhead = <1027150>;
- qcom,time-overhead = <2400>;
- };
+ qcom,system-modes@1 {
+ qcom,l2 = "l2_cache_pc_no_rpm";
+ qcom,latency-us = <1000>;
+ qcom,ss-power = <315>;
+ qcom,energy-overhead = <1027150>;
+ qcom,time-overhead = <2400>;
+ qcom,min-cpu-mode= "standalone_pc";
+ qcom,sync-cpus;
+ };
- qcom,lpm-level@4 {
- reg = <0x4>;
- qcom,mode = "pc";
- qcom,l2 = "l2_cache_pc";
- qcom,latency-us = <11000>;
- qcom,ss-power = <315>;
- qcom,energy-overhead = <1027150>;
- qcom,time-overhead = <2400>;
+ qcom,system-modes@2 {
+ qcom,l2 = "l2_cache_pc";
+ qcom,latency-us = <12700>;
+ qcom,ss-power = <315>;
+ qcom,energy-overhead = <1027150>;
+ qcom,time-overhead = <2400>;
+ qcom,min-cpu-mode= "pc";
+ qcom,sync-cpus;
+ };
};
};
@@ -292,6 +306,8 @@
qcom,pc-mode = "tz_l2_int";
qcom,use-sync-timer;
qcom,pc-resets-timer;
+ qcom,cpus-as-clocks;
+ qcom,synced-clocks;
};
qcom,cpu-sleep-status@f9088008{
diff --git a/arch/arm/boot/dts/msm8226-v2.dtsi b/arch/arm/boot/dts/msm8226-v2.dtsi
index a57adcd..089d415 100644
--- a/arch/arm/boot/dts/msm8226-v2.dtsi
+++ b/arch/arm/boot/dts/msm8226-v2.dtsi
@@ -61,7 +61,7 @@
1140000 1140000>;
qcom,pvs-corner-ceiling-slow = <1050000 1150000 1280000>;
qcom,pvs-corner-ceiling-nom = <1050000 1080000 1200000>;
- qcom,pvs-corner-ceiling-fast = <1050000 1050000 1140000>;
+ qcom,pvs-corner-ceiling-fast = <1050000 1050000 1100000>;
qcom,cpr-step-quotient = <30>;
qcom,cpr-up-threshold = <0>;
qcom,cpr-down-threshold = <5>;
@@ -74,10 +74,52 @@
};
&soc {
- qcom,acpuclk@f9011050 {
+ qcom,clock-a7@f9011050 {
reg = <0xf9011050 0x8>,
<0xfc4b80b0 0x8>;
- reg-names = "rcg_base", "pte_efuse";
+ reg-names = "rcg-base", "efuse";
+ qcom,speed0-bin-v2 =
+ < 0 0>,
+ < 384000000 2>,
+ < 787200000 4>,
+ <1190400000 7>;
+ qcom,speed6-bin-v2 =
+ < 0 0>,
+ < 384000000 2>,
+ < 787200000 4>,
+ <1190400000 7>;
+ qcom,speed2-bin-v2 =
+ < 0 0>,
+ < 384000000 2>,
+ < 787200000 4>,
+ <1401600000 10>;
+ qcom,speed5-bin-v2 =
+ < 0 0>,
+ < 384000000 2>,
+ < 787200000 4>,
+ <1401600000 10>;
+ qcom,speed4-bin-v2 =
+ < 0 0>,
+ < 384000000 2>,
+ < 787200000 4>,
+ <1401600000 10>;
+ qcom,speed7-bin-v2 =
+ < 0 0>,
+ < 384000000 2>,
+ < 787200000 4>,
+ <1401600000 10>;
+ qcom,speed1-bin-v2 =
+ < 0 0>,
+ < 384000000 2>,
+ < 787200000 4>,
+ < 998400000 5>,
+ <1094400000 6>,
+ <1190400000 7>,
+ <1305600000 8>,
+ <1344000000 9>,
+ <1401600000 10>,
+ <1497600000 11>,
+ <1593600000 12>;
};
};
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 51a0795..e0304f5 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -39,7 +39,7 @@
qsecom_mem: qsecom_region {
linux,contiguous-region;
- reg = <0 0x780000>;
+ reg = <0 0xd00000>;
label = "qsecom_mem";
};
};
@@ -57,6 +57,7 @@
/include/ "msm8226-mdss.dtsi"
/include/ "msm8226-coresight.dtsi"
/include/ "msm8226-iommu-domains.dtsi"
+/include/ "msm-rdbg.dtsi"
&soc {
#address-cells = <1>;
@@ -216,13 +217,13 @@
reg = <0xf991f000 0x1000>;
interrupts = <0 109 0>;
status = "disabled";
- };
- serial@f995e000 {
- compatible = "qcom,msm-lsuart-v14";
- reg = <0xf995e000 0x1000>;
- interrupts = <0 114 0>;
- status = "disabled";
+ qcom,msm-bus,name = "blsp1_uart2";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <86 512 0 0>,
+ <86 512 500 800>;
};
qcom,msm-imem@fe805000 {
@@ -281,8 +282,8 @@
qcom,hsusb-otg-phy-type = <2>;
qcom,hsusb-otg-mode = <1>;
qcom,hsusb-otg-otg-control = <2>;
- qcom,hsusb-otg-disable-reset;
qcom,dp-manual-pullup;
+ qcom,ahb-async-bridge-bypass;
qcom,msm-bus,name = "usb";
qcom,msm-bus,num-cases = <3>;
@@ -297,6 +298,7 @@
compatible = "qcom,android-usb";
reg = <0xfe8050c8 0xc8>;
qcom,android-usb-swfi-latency = <1>;
+ qcom,streaming-func = "rndis";
};
hsic_host: hsic@f9a00000 {
@@ -427,19 +429,20 @@
qcom,tapan-codec-9302;
};
- qcom,msm-pcm {
- compatible = "qcom,msm-pcm-dsp";
- qcom,msm-pcm-dsp-id = <0>;
+ qti,msm-pcm {
+ compatible = "qti,msm-pcm-dsp";
+ qti,msm-pcm-dsp-id = <0>;
};
qcom,msm-pcm-routing {
compatible = "qcom,msm-pcm-routing";
};
- qcom,msm-pcm-low-latency {
- compatible = "qcom,msm-pcm-dsp";
- qcom,msm-pcm-dsp-id = <1>;
- qcom,msm-pcm-low-latency;
+ qti,msm-pcm-low-latency {
+ compatible = "qti,msm-pcm-dsp";
+ qti,msm-pcm-dsp-id = <1>;
+ qti,msm-pcm-low-latency;
+ qti,latency-level = "regular";
};
qcom,msm-pcm-lpa {
@@ -724,6 +727,24 @@
compatible = "qcom,bcl";
};
+ rmtfs_sharedmem {
+ compatible = "qcom,sharedmem-uio";
+ reg = <0x0fd80000 0x00180000>;
+ reg-names = "rmtfs";
+ };
+
+ dsp_sharedmem {
+ compatible = "qcom,sharedmem-uio";
+ reg = <0x0fd60000 0x00020000>;
+ reg-names = "rfsa_dsp";
+ };
+
+ mdm_sharedmem {
+ compatible = "qcom,sharedmem-uio";
+ reg = <0x0fd60000 0x00020000>;
+ reg-names = "rfsa_mdm";
+ };
+
sdcc1: qcom,sdcc@f9824000 {
cell-index = <1>; /* SDC1 eMMC slot */
compatible = "qcom,msm-sdcc";
@@ -952,6 +973,9 @@
interrupt-names = "qup_err_intr";
qcom,i2c-bus-freq = <400000>;
qcom,i2c-src-freq = <19200000>;
+ qcom,sda-gpio = <&msmgpio 10 0>;
+ qcom,scl-gpio = <&msmgpio 11 0>;
+ qcom,master-id = <86>;
};
i2c@f9926000 { /* BLSP-1 QUP-4 */
cell-index = <0>;
@@ -980,11 +1004,46 @@
qcom,scl-gpio = <&msmgpio 19 0>;
};
- qcom,acpuclk@f9011050 {
- compatible = "qcom,acpuclk-a7";
+ qcom,clock-a7@f9011050 {
+ compatible = "qcom,clock-a7-8226";
reg = <0xf9011050 0x8>;
- reg-names = "rcg_base";
- a7_cpu-supply = <&apc_vreg_corner>;
+ reg-names = "rcg-base";
+ clock-names = "clk-4", "clk-5";
+ qcom,speed0-bin-v0 =
+ < 0 0>,
+ < 384000000 2>,
+ < 787200000 4>,
+ <1190400000 7>;
+
+ cpu-vdd-supply = <&apc_vreg_corner>;
+ };
+
+ qcom,cpubw {
+ compatible = "qcom,cpubw";
+ qcom,cpu-mem-ports = <1 512>;
+ qcom,bw-tbl =
+ < 1525 /* 200 MHz */ >,
+ < 2441 /* 320 MHz */ >,
+ < 3051 /* 400 MHz */ >,
+ < 4066 /* 533 MHz */ >;
+ };
+
+ qcom,msm-cpufreq@0 {
+ reg = <0 4>;
+ compatible = "qcom,msm-cpufreq";
+ qcom,cpufreq-table =
+ < 300000 1525 >,
+ < 384000 1525 >,
+ < 600000 1525 >,
+ < 787200 3051 >,
+ < 998400 4066 >,
+ < 1094400 4066 >,
+ < 1190400 4066 >,
+ < 1305600 4066 >,
+ < 1344000 4066 >,
+ < 1401600 4066 >,
+ < 1497600 4066 >,
+ < 1593600 4066 >;
};
qcom,ocmem@fdd00000 {
diff --git a/arch/arm/boot/dts/msm8610-bus.dtsi b/arch/arm/boot/dts/msm8610-bus.dtsi
index c6e81d8..54c698c 100644
--- a/arch/arm/boot/dts/msm8610-bus.dtsi
+++ b/arch/arm/boot/dts/msm8610-bus.dtsi
@@ -941,7 +941,7 @@
qcom,thresh = <800000>;
qcom,dual-conf;
qcom,bimc,bw = <300000>;
- qcom,bimc,gp = <5>;
+ qcom,bimc,gp = <5000>;
qcom,bimc,thmp = <50>;
};
diff --git a/arch/arm/boot/dts/msm8610-cdp.dtsi b/arch/arm/boot/dts/msm8610-cdp.dtsi
index 9920f77..04eca14 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8610-cdp.dtsi
@@ -20,7 +20,7 @@
compatible = "atmel,mxt-ts";
reg = <0x4a>;
interrupt-parent = <&msmgpio>;
- interrupts = <1 0x2>;
+ interrupts = <1 0x2002>;
vdd_ana-supply = <&pm8110_l19>;
vcc_i2c-supply = <&pm8110_l14>;
atmel,reset-gpio = <&msmgpio 0 0x00>;
@@ -76,6 +76,21 @@
];
};
};
+
+ synaptics@20 {
+ compatible = "synaptics,rmi4";
+ reg = <0x20>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <1 0x2002>;
+ vdd-supply = <&pm8110_l19>;
+ vcc_i2c-supply = <&pm8110_l14>;
+ synaptics,reset-gpio = <&msmgpio 0 0x00>;
+ synaptics,irq-gpio = <&msmgpio 1 0x2008>;
+ synaptics,button-map = <139 102 158>;
+ synaptics,i2c-pull-up;
+ synaptics,power-down;
+ synaptics,disable-gpios;
+ };
};
gen-vkeys {
@@ -128,7 +143,11 @@
"MIC BIAS External", "Handset Mic",
"MIC BIAS Internal2", "Headset Mic",
"AMIC1", "MIC BIAS External",
- "AMIC2", "MIC BIAS Internal2";
+ "AMIC2", "MIC BIAS Internal2",
+ "MIC BIAS External", "Digital Mic1",
+ "MIC BIAS External", "Digital Mic2",
+ "DMIC1", "MIC BIAS External",
+ "DMIC2", "MIC BIAS External";
qcom,headset-jack-type-NC;
};
};
diff --git a/arch/arm/boot/dts/msm8610-ion.dtsi b/arch/arm/boot/dts/msm8610-ion.dtsi
index 77cd582..601f8ed 100644
--- a/arch/arm/boot/dts/msm8610-ion.dtsi
+++ b/arch/arm/boot/dts/msm8610-ion.dtsi
@@ -16,22 +16,21 @@
#address-cells = <1>;
#size-cells = <0>;
- qcom,ion-heap@30 { /* SYSTEM HEAP */
- reg = <30>;
- };
-
- qcom,ion-heap@21 { /* SYSTEM CONTIG HEAP */
- reg = <21>;
- };
-
- qcom,ion-heap@25 { /* IOMMU HEAP */
+ qcom,ion-heap@25 {
reg = <25>;
+ qcom,ion-heap-type = "SYSTEM";
+ };
+
+ qcom,ion-heap@21 {
+ reg = <21>;
+ qcom,ion-heap-type = "SYSTEM_CONTIG";
};
qcom,ion-heap@27 { /* QSECOM HEAP */
compatible = "qcom,msm-ion-reserve";
reg = <27>;
linux,contiguous-region = <&qsecom_mem>;
+ qcom,ion-heap-type = "DMA";
};
qcom,ion-heap@23 { /* OTHER PIL HEAP */
@@ -39,6 +38,7 @@
reg = <23>;
qcom,heap-align = <0x1000>;
qcom,memory-fixed = <0x0c500000 0x1300000>;
+ qcom,ion-heap-type = "CARVEOUT";
};
qcom,ion-heap@26 { /* MODEM HEAP */
@@ -46,6 +46,7 @@
reg = <26>;
qcom,heap-align = <0x1000>;
qcom,memory-fixed = <0x08800000 0x3d00000>;
+ qcom,ion-heap-type = "CARVEOUT";
};
};
diff --git a/arch/arm/boot/dts/msm8610-mtp.dtsi b/arch/arm/boot/dts/msm8610-mtp.dtsi
index 0244b89..3b0f2a2 100644
--- a/arch/arm/boot/dts/msm8610-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8610-mtp.dtsi
@@ -20,7 +20,7 @@
compatible = "atmel,mxt-ts";
reg = <0x4a>;
interrupt-parent = <&msmgpio>;
- interrupts = <1 0x2>;
+ interrupts = <1 0x2002>;
vdd_ana-supply = <&pm8110_l19>;
vcc_i2c-supply = <&pm8110_l14>;
atmel,reset-gpio = <&msmgpio 0 0x00>;
@@ -76,6 +76,21 @@
];
};
};
+
+ synaptics@20 {
+ compatible = "synaptics,rmi4";
+ reg = <0x20>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <1 0x2002>;
+ vdd-supply = <&pm8110_l19>;
+ vcc_i2c-supply = <&pm8110_l14>;
+ synaptics,reset-gpio = <&msmgpio 0 0x00>;
+ synaptics,irq-gpio = <&msmgpio 1 0x2008>;
+ synaptics,button-map = <139 102 158>;
+ synaptics,i2c-pull-up;
+ synaptics,power-down;
+ synaptics,disable-gpios;
+ };
};
i2c@f9925000 {
@@ -127,7 +142,7 @@
0x2800>;
capella,ps_close_thd_set = <0xa>;
capella,ps_away_thd_set = <0x5>;
- capella,ls_cmd = <0x44>; /* PS_IT=160ms, INT_PERS=2*/
+ capella,ls_cmd = <0x04>; /* ALS_IT=80ms, INT_PERS=2*/
capella,ps_conf1_val = <0x0006>;
capella,ps_conf3_val = <0x3010>;
};
diff --git a/arch/arm/boot/dts/msm8610-qrd-skuaa.dtsi b/arch/arm/boot/dts/msm8610-qrd-skuaa.dtsi
index bb866b2..719830e 100644
--- a/arch/arm/boot/dts/msm8610-qrd-skuaa.dtsi
+++ b/arch/arm/boot/dts/msm8610-qrd-skuaa.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ /* Copyright (c) 2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -33,18 +33,17 @@
<0x44 0x80 0x6a 0x81 0x34 0x82 0x13 0x83 0xffffffff>;
};
- i2c@f9925000 { /* BLSP-1 QUP-3 */
+ i2c@f9924000 { /* BLSP-1 QUP-2 */
nfc-nci@e {
compatible = "qcom,nfc-nci";
reg = <0x0e>;
qcom,irq-gpio = <&msmgpio 77 0x00>;
qcom,dis-gpio = <&msmgpio 93 0x00>;
qcom,clk-en-gpio = <&msmgpio 78 0x00>;
- qcom,clk-src = "GPCLK";
+ qcom,clk-src = "GPCLK2";
interrupt-parent = <&msmgpio>;
interrupts = <77 0>;
qcom,clk-gpio = <&msmgpio 75 0x00>;
- vlogic-supply = <&pm8110_l14>;
};
};
};
diff --git a/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi b/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi
index 08e9be5..a22958a 100644
--- a/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi
+++ b/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi
@@ -67,6 +67,7 @@
goodix,display-coords = <0 0 540 960>;
goodix,button-map= <139 102 158>;
goodix,product-id = "915";
+ goodix,enable-power-off;
goodix,cfg-data0 = [
46 1C 02 C0 03 0A 05 11 01 08
14 3B 46 32 03 05 00 00 00 00
diff --git a/arch/arm/boot/dts/msm8610-qrd.dtsi b/arch/arm/boot/dts/msm8610-qrd.dtsi
index d578ef6..92d1a77 100644
--- a/arch/arm/boot/dts/msm8610-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8610-qrd.dtsi
@@ -102,6 +102,10 @@
linux,default-trigger = "flashlight-trigger";
};
+ qcom,wdt@f9017000 {
+ qcom,bark-time = <13000>;
+ };
+
gpio_keys {
compatible = "gpio-keys";
input-name = "gpio-keys";
@@ -210,8 +214,9 @@
status = "okay";
qcom,led_mpp_2 {
label = "mpp";
- linux,name = "wled-homerow";
- linux-default-trigger = "hr-trigger";
+ linux,name = "button-backlight";
+ linux,default-trigger = "hr-trigger";
+ qcom,current-setting = <20>;
qcom,default-state = "off";
qcom,max-current = <40>;
qcom,id = <6>;
@@ -287,7 +292,7 @@
qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
- qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+ qcom,clk-rates = <400000 25000000 50000000>;
#address-cells = <0>;
interrupt-parent = <&sdhc_2>;
@@ -308,6 +313,7 @@
qcom,chgr@1000 {
status = "ok";
+ qcom,tchg-mins = <250>;
};
qcom,buck@1100 {
diff --git a/arch/arm/boot/dts/msm8610-regulator.dtsi b/arch/arm/boot/dts/msm8610-regulator.dtsi
index f97d991..1340612 100644
--- a/arch/arm/boot/dts/msm8610-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8610-regulator.dtsi
@@ -36,11 +36,11 @@
interrupts = <0 15 0>;
regulator-name = "apc_corner";
regulator-min-microvolt = <1>;
- regulator-max-microvolt = <3>;
+ regulator-max-microvolt = <12>;
- qcom,pvs-fuse-redun-sel = <53 25 3 2>;
- qcom,pvs-fuse = <23 6 5>;
- qcom,pvs-fuse-redun = <61 47 5>;
+ qcom,pvs-fuse-redun-sel = <53 25 3 2 1>;
+ qcom,pvs-fuse = <23 6 5 1>;
+ qcom,pvs-fuse-redun = <61 47 5 1>;
qcom,pvs-init-voltage = <1275000 1275000 1275000 1275000 1275000
1275000 1275000 1275000 1275000 1275000
@@ -49,9 +49,9 @@
1275000 1275000 1275000 1275000 1275000
1275000 1275000 1275000 1275000 1275000
1275000 1275000>;
- qcom,pvs-corner-ceiling-slow = <1150000 1150000 1275000>;
- qcom,pvs-corner-ceiling-nom = <1075000 1075000 1200000>;
- qcom,pvs-corner-ceiling-fast = <1050000 1050000 1140000>;
+ qcom,pvs-corner-ceiling-slow = <1050000 1150000 1275000>;
+ qcom,pvs-corner-ceiling-nom = <1050000 1075000 1275000>;
+ qcom,pvs-corner-ceiling-fast = <1050000 1050000 1275000>;
vdd-apc-supply = <&pm8110_s2>;
vdd-mx-supply = <&pm8110_l3_ao>;
@@ -72,20 +72,20 @@
qcom,vdd-apc-step-down-limit = <1>;
qcom,cpr-apc-volt-step = <5000>;
- qcom,cpr-fuse-redun-sel = <53 25 3 2>;
- qcom,cpr-fuse-row = <61>;
+ qcom,cpr-fuse-redun-sel = <53 25 3 2 1>;
+ qcom,cpr-fuse-row = <61 1>;
qcom,cpr-fuse-bp-cpr-disable = <39>;
qcom,cpr-fuse-bp-scheme = <40>;
qcom,cpr-fuse-target-quot = <27 15 3>;
qcom,cpr-fuse-ro-sel = <47 41 44>;
- qcom,cpr-fuse-redun-row = <52>;
+ qcom,cpr-fuse-redun-row = <52 1>;
qcom,cpr-fuse-redun-bp-cpr-disable = <24>;
qcom,cpr-fuse-redun-bp-scheme = <25>;
qcom,cpr-fuse-redun-target-quot = <32 12 0>;
qcom,cpr-fuse-redun-ro-sel = <44 26 29>;
+ qcom,cpr-corner-map = <1 1 2 2 3 3 3 3 3 3 3 3>;
qcom,cpr-enable;
- qcom,use-tz-api;
};
};
@@ -215,7 +215,7 @@
status = "okay";
pm8110_l5: regulator-l5 {
regulator-min-microvolt = <1300000>;
- regulator-max-microvolt = <1300000>;
+ regulator-max-microvolt = <1350000>;
qcom,init-voltage = <1300000>;
status = "okay";
};
@@ -325,7 +325,7 @@
status = "okay";
pm8110_l16: regulator-l16 {
regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3000000>;
+ regulator-max-microvolt = <3350000>;
qcom,init-voltage = <3000000>;
status = "okay";
};
diff --git a/arch/arm/boot/dts/msm8610-rumi.dts b/arch/arm/boot/dts/msm8610-rumi.dts
index 7f06485..c22b4f28 100644
--- a/arch/arm/boot/dts/msm8610-rumi.dts
+++ b/arch/arm/boot/dts/msm8610-rumi.dts
@@ -17,7 +17,7 @@
/ {
model = "Qualcomm MSM 8610 Rumi";
compatible = "qcom,msm8610-rumi", "qcom,msm8610", "qcom,rumi";
- qcom,msm-id = <147 15 0>;
+ qcom,board-id = <15 0>;
};
&soc {
diff --git a/arch/arm/boot/dts/msm8610-sim.dts b/arch/arm/boot/dts/msm8610-sim.dts
index 33176b9..531ee4b 100644
--- a/arch/arm/boot/dts/msm8610-sim.dts
+++ b/arch/arm/boot/dts/msm8610-sim.dts
@@ -17,7 +17,7 @@
/ {
model = "Qualcomm MSM 8610 Simulator";
compatible = "qcom,msm8610-sim", "qcom,msm8610", "qcom,sim";
- qcom,msm-id = <147 16 0>;
+ qcom,board-id = <16 0>;
};
&soc {
diff --git a/arch/arm/boot/dts/msm8610-v1-cdp.dts b/arch/arm/boot/dts/msm8610-v1-cdp.dts
index beb3976..5a70379 100644
--- a/arch/arm/boot/dts/msm8610-v1-cdp.dts
+++ b/arch/arm/boot/dts/msm8610-v1-cdp.dts
@@ -19,8 +19,7 @@
/ {
model = "Qualcomm MSM 8610 CDP";
compatible = "qcom,msm8610-cdp", "qcom,msm8610", "qcom,cdp";
- qcom,msm-id = <147 1 0>, <165 1 0>, <161 1 0>, <162 1 0>,
- <163 1 0>, <164 1 0>, <166 1 0>;
+ qcom,board-id = <1 0>;
};
diff --git a/arch/arm/boot/dts/msm8610-v1-mtp.dts b/arch/arm/boot/dts/msm8610-v1-mtp.dts
index 82992a3..c8c8d09 100644
--- a/arch/arm/boot/dts/msm8610-v1-mtp.dts
+++ b/arch/arm/boot/dts/msm8610-v1-mtp.dts
@@ -19,8 +19,7 @@
/ {
model = "Qualcomm MSM 8610 MTP";
compatible = "qcom,msm8610-mtp", "qcom,msm8610", "qcom,mtp";
- qcom,msm-id = <147 8 0>, <165 8 0>, <161 8 0>, <162 8 0>,
- <163 8 0>, <164 8 0>, <166 8 0>;
+ qcom,board-id = <8 0>;
};
diff --git a/arch/arm/boot/dts/msm8610-v1-pm.dtsi b/arch/arm/boot/dts/msm8610-v1-pm.dtsi
index 6296692..ea37413 100644
--- a/arch/arm/boot/dts/msm8610-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-v1-pm.dtsi
@@ -56,10 +56,10 @@
qcom,saw2-spm-dly= <0x3c102800>;
qcom,saw2-spm-ctl = <0x8>;
qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
- qcom,saw2-spm-cmd-spc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
- 0b 94 5b 80 10 06 26 30 0f];
- qcom,saw2-spm-cmd-pc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
- 0b 94 5b 80 10 06 26 30 0f];
+ qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
+ 0b 94 5b 80 10 26 30 0f];
+ qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
+ 0b 94 5b 80 10 26 30 0f];
};
qcom,spm@f90b9000 {
@@ -99,6 +99,9 @@
qcom,saw2-spm-cmd-pc = [00 32 b0 10 e0 d0 6b c0 42 f0
11 07 01 b0 50 4e 02 02 c0 d0 12 e0 6b 02 32
50 f0 0f]; /*APCS_PMIC_OFF_L2RAM_OFF*/
+ qcom,saw2-spm-cmd-pc-no-rpm = [00 32 b0 10 e0 d0 6b c0 42 f0
+ 11 03 01 b0 50 4e 02 02 c0 d0 12 e0 6b 02 32
+ 50 f0 0f]; /*APCS_PMIC_OFF_L2RAM_OFF*/
qcom,L2-spm-is-apcs-master;
};
@@ -108,44 +111,68 @@
#address-cells = <1>;
#size-cells = <0>;
- qcom,lpm-level@0 {
- reg = <0x0>;
- qcom,mode = "wfi";
- qcom,l2 = "l2_cache_active";
- qcom,latency-us = <1>;
- qcom,ss-power = <530>;
- qcom,energy-overhead = <52800>;
- qcom,time-overhead = <100>;
+ qcm,cpu-modes {
+ compatible = "qcom,cpu-modes";
+
+ qcom,cpu-modes@0 {
+ qcom,mode = "wfi";
+ qcom,latency-us = <1>;
+ qcom,ss-power = <530>;
+ qcom,energy-overhead = <52800>;
+ qcom,time-overhead = <100>;
+ };
+
+ qcom,cpu-modes@1 {
+ qcom,mode = "standalone_pc";
+ qcom,latency-us = <500>;
+ qcom,ss-power = <410>;
+ qcom,energy-overhead = <603400>;
+ qcom,time-overhead = <1200>;
+ qcom,use-broadcast-timer;
+ };
+
+ qcom,cpu-modes@2 {
+ qcom,mode = "pc";
+ qcom,latency-us = <550>;
+ qcom,ss-power = <372>;
+ qcom,energy-overhead = <700000>;
+ qcom,time-overhead = <1410>;
+ qcom,use-broadcast-timer;
+ };
};
- qcom,lpm-level@1 {
- reg = <0x1>;
- qcom,mode = "standalone_pc";
- qcom,l2 = "l2_cache_active";
- qcom,latency-us = <500>;
- qcom,ss-power = <410>;
- qcom,energy-overhead = <603400>;
- qcom,time-overhead = <1200>;
- };
+ qcom,system-modes {
+ compatible = "qcom,system-modes";
- qcom,lpm-level@2 {
- reg = <0x2>;
- qcom,mode = "pc";
- qcom,l2 = "l2_cache_retention";
- qcom,latency-us = <520>;
- qcom,ss-power = <460>;
- qcom,energy-overhead = <704900>;
- qcom,time-overhead = <1300>;
- };
+ qcom,system-modes@0 {
+ qcom,l2 = "l2_cache_gdhs";
+ qcom,latency-us = <10700>;
+ qcom,ss-power = <372>;
+ qcom,energy-overhead = <738750>;
+ qcom,time-overhead = <1410>;
+ qcom,min-cpu-mode= "pc";
+ qcom,sync-cpus;
+ };
- qcom,lpm-level@3 {
- reg = <0x3>;
- qcom,mode = "pc";
- qcom,l2 = "l2_cache_pc";
- qcom,latency-us = <11700>;
- qcom,ss-power = <315>;
- qcom,energy-overhead = <1027150>;
- qcom,time-overhead = <2400>;
+ qcom,system-modes@1 {
+ qcom,l2 = "l2_cache_pc_no_rpm";
+ qcom,latency-us = <1000>;
+ qcom,ss-power = <315>;
+ qcom,energy-overhead = <1027150>;
+ qcom,time-overhead = <2400>;
+ qcom,min-cpu-mode= "standalone_pc";
+ qcom,sync-cpus;
+ };
+
+ qcom,system-modes@2 {
+ qcom,l2 = "l2_cache_pc";
+ qcom,latency-us = <12700>;
+ qcom,ss-power = <315>;
+ qcom,energy-overhead = <1027150>;
+ qcom,time-overhead = <2400>;
+ qcom,min-cpu-mode= "pc";
+ qcom,sync-cpus;
+ };
};
};
diff --git a/arch/arm/boot/dts/msm8610-v1-qrd-skuab-dvt2.dts b/arch/arm/boot/dts/msm8610-v1-qrd-skuab-dvt2.dts
index 4a08f3f..de48f1f 100644
--- a/arch/arm/boot/dts/msm8610-v1-qrd-skuab-dvt2.dts
+++ b/arch/arm/boot/dts/msm8610-v1-qrd-skuab-dvt2.dts
@@ -33,3 +33,10 @@
&dsi_hx8389b_qhd_vid {
qcom,cont-splash-enabled;
};
+&soc {
+ i2c@f9925000 {
+ fsl@1c {
+ fsl,sensors-position = <7>;
+ };
+ };
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/msm8610-v2-cdp.dts b/arch/arm/boot/dts/msm8610-v2-cdp.dts
index a6d1d9c..447161f 100644
--- a/arch/arm/boot/dts/msm8610-v2-cdp.dts
+++ b/arch/arm/boot/dts/msm8610-v2-cdp.dts
@@ -19,8 +19,7 @@
/ {
model = "Qualcomm MSM 8610v2 CDP";
compatible = "qcom,msm8610-cdp", "qcom,msm8610", "qcom,cdp";
- qcom,msm-id = <147 1 0x10001>, <165 1 0x10001>, <161 1 0x10001>, <162 1 0x10001>,
- <163 1 0x10001>, <164 1 0x10001>, <166 1 0x10001>;
+ qcom,board-id = <1 0>;
};
diff --git a/arch/arm/boot/dts/msm8610-v2-mtp.dts b/arch/arm/boot/dts/msm8610-v2-mtp.dts
index 405a775..77f5276 100644
--- a/arch/arm/boot/dts/msm8610-v2-mtp.dts
+++ b/arch/arm/boot/dts/msm8610-v2-mtp.dts
@@ -19,8 +19,7 @@
/ {
model = "Qualcomm MSM 8610v2 MTP";
compatible = "qcom,msm8610-mtp", "qcom,msm8610", "qcom,mtp";
- qcom,msm-id = <147 8 0x10001>, <165 8 0x10001>, <161 8 0x10001>, <162 8 0x10001>,
- <163 8 0x10001>, <164 8 0x10001>, <166 8 0x10001>;
+ qcom,board-id = <8 0>;
};
diff --git a/arch/arm/boot/dts/msm8610-v2-pm.dtsi b/arch/arm/boot/dts/msm8610-v2-pm.dtsi
index 6c7f2f6..19fb185 100644
--- a/arch/arm/boot/dts/msm8610-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-v2-pm.dtsi
@@ -56,10 +56,10 @@
qcom,saw2-spm-dly= <0x3c102800>;
qcom,saw2-spm-ctl = <0x8>;
qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
- qcom,saw2-spm-cmd-spc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
- 0b 94 5b 80 10 06 26 30 0f];
- qcom,saw2-spm-cmd-pc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
- 0b 94 5b 80 10 06 26 30 0f];
+ qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
+ 0b 94 5b 80 10 26 30 0f];
+ qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
+ 0b 94 5b 80 10 26 30 0f];
};
qcom,spm@f90b9000 {
@@ -101,6 +101,9 @@
qcom,saw2-spm-cmd-pc = [00 32 b0 10 e0 d0 6b c0 42 f0
11 07 01 b0 50 4e 02 02 c0 d0 12 e0 6b 02 32
50 f0 0f]; /*APCS_PMIC_OFF_L2RAM_OFF*/
+ qcom,saw2-spm-cmd-pc-no-rpm = [00 32 b0 10 e0 d0 6b c0 42 f0
+ 11 03 01 b0 50 4e 02 02 c0 d0 12 e0 6b 02 32
+ 50 f0 0f]; /*APCS_PMIC_OFF_L2RAM_OFF*/
qcom,L2-spm-is-apcs-master;
};
@@ -110,44 +113,68 @@
#address-cells = <1>;
#size-cells = <0>;
- qcom,lpm-level@0 {
- reg = <0x0>;
- qcom,mode = "wfi";
- qcom,l2 = "l2_cache_active";
- qcom,latency-us = <1>;
- qcom,ss-power = <530>;
- qcom,energy-overhead = <52800>;
- qcom,time-overhead = <100>;
+ qcm,cpu-modes {
+ compatible = "qcom,cpu-modes";
+
+ qcom,cpu-modes@0 {
+ qcom,mode = "wfi";
+ qcom,latency-us = <1>;
+ qcom,ss-power = <530>;
+ qcom,energy-overhead = <52800>;
+ qcom,time-overhead = <100>;
+ };
+
+ qcom,cpu-modes@1 {
+ qcom,mode = "standalone_pc";
+ qcom,latency-us = <500>;
+ qcom,ss-power = <410>;
+ qcom,energy-overhead = <603400>;
+ qcom,time-overhead = <1200>;
+ qcom,use-broadcast-timer;
+ };
+
+ qcom,cpu-modes@2 {
+ qcom,mode = "pc";
+ qcom,latency-us = <550>;
+ qcom,ss-power = <372>;
+ qcom,energy-overhead = <700000>;
+ qcom,time-overhead = <1410>;
+ qcom,use-broadcast-timer;
+ };
};
- qcom,lpm-level@1 {
- reg = <0x1>;
- qcom,mode = "standalone_pc";
- qcom,l2 = "l2_cache_active";
- qcom,latency-us = <500>;
- qcom,ss-power = <410>;
- qcom,energy-overhead = <603400>;
- qcom,time-overhead = <1200>;
- };
+ qcom,system-modes {
+ compatible = "qcom,system-modes";
- qcom,lpm-level@2 {
- reg = <0x2>;
- qcom,mode = "pc";
- qcom,l2 = "l2_cache_gdhs";
- qcom,latency-us = <10700>;
- qcom,ss-power = <325>;
- qcom,energy-overhead = <441250>;
- qcom,time-overhead = <1020>;
- };
+ qcom,system-modes@0 {
+ qcom,l2 = "l2_cache_gdhs";
+ qcom,latency-us = <10700>;
+ qcom,ss-power = <372>;
+ qcom,energy-overhead = <738750>;
+ qcom,time-overhead = <1410>;
+ qcom,min-cpu-mode= "pc";
+ qcom,sync-cpus;
+ };
- qcom,lpm-level@3 {
- reg = <0x3>;
- qcom,mode = "pc";
- qcom,l2 = "l2_cache_pc";
- qcom,latency-us = <11700>;
- qcom,ss-power = <315>;
- qcom,energy-overhead = <1027150>;
- qcom,time-overhead = <2400>;
+ qcom,system-modes@1 {
+ qcom,l2 = "l2_cache_pc_no_rpm";
+ qcom,latency-us = <1000>;
+ qcom,ss-power = <315>;
+ qcom,energy-overhead = <1027150>;
+ qcom,time-overhead = <2400>;
+ qcom,min-cpu-mode= "standalone_pc";
+ qcom,sync-cpus;
+ };
+
+ qcom,system-modes@2 {
+ qcom,l2 = "l2_cache_pc";
+ qcom,latency-us = <12700>;
+ qcom,ss-power = <315>;
+ qcom,energy-overhead = <1027150>;
+ qcom,time-overhead = <2400>;
+ qcom,min-cpu-mode= "pc";
+ qcom,sync-cpus;
+ };
};
};
@@ -171,24 +198,40 @@
<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
<2 216>, /* tsens_upper_lower_int */
<41 63>, /* dino_gen_purpose_irq35 */
+ <0xff 18>, /* APC_qgicQTmrSecPhysIrptReq */
+ <0xff 19>, /* APC_qgicQTmrNonSecPhysIrptReq */
+ <0xff 35>, /* WDT_barkInt */
+ <0xff 40>, /* qtmr_phy_irq[0] */
+ <0xff 47>, /* rbif_irq[0] */
<0xff 56>, /* q6_wdog_expired_irq */
<0xff 57>, /* mss_to_apps_irq(0) */
<0xff 58>, /* mss_to_apps_irq(1) */
<0xff 59>, /* mss_to_apps_irq(2) */
<0xff 60>, /* mss_to_apps_irq(3) */
<0xff 61>, /* mss_a2_bam_irq */
+ <0xff 65>, /* o_gc_sys_irq[0] */
+ <0xff 74>, /* venus0_mmu_cirpt[1] */
+ <0xff 75>, /* venus0_mmu_cirpt[0] */
+ <0xff 78>, /* mdss_mmu_cirpt[0] */
+ <0xff 79>, /* mdss_mmu_cirpt[1] */
+ <0xff 97>, /* camss_vfe_mmu_cirpt[1] */
+ <0xff 102>, /* camss_jpeg_mmu_cirpt[1] */
+ <0xff 109>, /* ocmem_dm_nonsec_irq */
+ <0xff 131>, /* blsp1_qup_5_irq */
+ <0xff 141>, /* blsp1_uart_3_irq */
+ <0xff 155>, /* sdc1_irq(0) */
+ <0xff 157>, /* sdc2_irq(0) */
+ <0xff 161>, /* lpass_irq_out_spare[4] */
+ <0xff 162>, /* lpass_irq_out_spare[5]*/
+ <0xff 170>, /* sdc1_pwr_cmd_irq */
<0xff 173>, /* o_wcss_apss_smd_hi */
<0xff 174>, /* o_wcss_apss_smd_med */
<0xff 175>, /* o_wcss_apss_smd_low */
<0xff 176>, /* o_wcss_apss_smsm_irq */
<0xff 177>, /* o_wcss_apss_wlan_data_xfer_done */
<0xff 178>, /* o_wcss_apss_wlan_rx_data_avail */
- <0xff 179>, /* o_wcss_apss_asic_intr
+ <0xff 179>, /* o_wcss_apss_asic_intr */
<0xff 181>, /* o_wcss_apss_wdog_bite_and_reset_rdy */
- <0xff 161>, /* lpass_irq_out_spare[4] /
- <0xff 162>, /* lpass_irq_out_spare[5]*/
- <0xff 234>, /* lpass_irq_out_spare[6]*/
- <0xff 235>, /* lpass_irq_out_spare[7]*/
<0xff 188>, /* lpass_irq_out_apcs(0) */
<0xff 189>, /* lpass_irq_out_apcs(1) */
<0xff 190>, /* lpass_irq_out_apcs(2) */
@@ -203,12 +246,16 @@
<0xff 205>, /* rpm_ipc(25) */
<0xff 206>, /* rpm_ipc(26) */
<0xff 207>, /* rpm_ipc(27) */
+ <0xff 234>, /* lpass_irq_out_spare[6]*/
+ <0xff 235>, /* lpass_irq_out_spare[7]*/
+ <0xff 240>, /* summary_irq_kpss */
+ <0xff 253>, /* sdc2_pwr_cmd_irq */
<0xff 258>, /* rpm_ipc(28) */
<0xff 259>, /* rpm_ipc(29) */
- <0xff 275>, /* rpm_ipc(30) */
- <0xff 276>, /* rpm_ipc(31) */
<0xff 269>, /* rpm_wdog_expired_irq */
- <0xff 240>; /* summary_irq_kpss */
+ <0xff 270>, /* blsp1_bam_irq[0] */
+ <0xff 275>, /* rpm_ipc(30) */
+ <0xff 276>; /* rpm_ipc(31) */
qcom,gpio-parent = <&msmgpio>;
qcom,gpio-map = <3 1>,
diff --git a/arch/arm/boot/dts/msm8610-v2-qrd-skuab-dvt2.dts b/arch/arm/boot/dts/msm8610-v2-qrd-skuab-dvt2.dts
index 4735554..2547148 100644
--- a/arch/arm/boot/dts/msm8610-v2-qrd-skuab-dvt2.dts
+++ b/arch/arm/boot/dts/msm8610-v2-qrd-skuab-dvt2.dts
@@ -56,3 +56,26 @@
&dsi_hx8389b_qhd_vid {
qcom,cont-splash-enabled;
};
+
+&soc {
+ i2c@f9925000 {
+ fsl@1c {
+ fsl,sensors-position = <7>;
+ };
+ };
+};
+
+&qrd_batterydata {
+ qcom,rpull-up-kohm = <100>;
+ qcom,vref-batt-therm = <1800000>;
+
+ /include/ "batterydata-qrd-4v2-2200mah.dtsi"
+};
+
+&pm8110_bms {
+ qcom,battery-data = <&qrd_batterydata>;
+};
+
+&pm8110_chg {
+ qcom,battery-data = <&qrd_batterydata>;
+};
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 9406b75..558f8c2 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -43,6 +43,7 @@
/include/ "msm8610-smp2p.dtsi"
/include/ "msm8610-bus.dtsi"
/include/ "msm8610-mdss.dtsi"
+/include/ "msm-rdbg.dtsi"
&soc {
#address-cells = <1>;
@@ -239,6 +240,8 @@
qcom,hsusb-otg-otg-control = <2>;
qcom,hsusb-otg-disable-reset;
qcom,dp-manual-pullup;
+ qcom,ahb-async-bridge-bypass;
+ qcom,disable-retention-with-vdd-min;
qcom,msm-bus,name = "usb2";
qcom,msm-bus,num-cases = <2>;
@@ -253,6 +256,25 @@
compatible = "qcom,android-usb";
reg = <0xfe8050c8 0xc8>;
qcom,android-usb-swfi-latency = <1>;
+ qcom,streaming-func = "rndis";
+ };
+
+ rmtfs_sharedmem {
+ compatible = "qcom,sharedmem-uio";
+ reg = <0x0dc80000 0x00180000>;
+ reg-names = "rmtfs";
+ };
+
+ dsp_sharedmem {
+ compatible = "qcom,sharedmem-uio";
+ reg = <0x0dc60000 0x00020000>;
+ reg-names = "rfsa_dsp";
+ };
+
+ mdm_sharedmem {
+ compatible = "qcom,sharedmem-uio";
+ reg = <0x0dc60000 0x00020000>;
+ reg-names = "rfsa_mdm";
};
sdcc1: qcom,sdcc@f9824000 {
@@ -422,7 +444,6 @@
compatible = "qcom,rpm-smd";
rpm-channel-name = "rpm_requests";
rpm-channel-type = <15>; /* SMD_APPS_RPM */
- rpm-standalone;
};
qcom,bcl {
@@ -510,6 +531,23 @@
qcom,master-id = <86>;
};
+
+ i2c@f9924000 { /* BLSP-1 QUP-3 */
+ cell-index = <2>;
+ compatible = "qcom,i2c-qup";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ reg = <0xf9924000 0x1000>;
+ interrupt-names = "qup_err_intr";
+ interrupts = <0 96 0>;
+ qcom,i2c-bus-freq = <100000>;
+ qcom,i2c-src-freq = <19200000>;
+ qcom,sda-gpio = <&msmgpio 8 0>;
+ qcom,scl-gpio = <&msmgpio 9 0>;
+ qcom,master-id = <86>;
+ };
+
i2c@f9925000 { /* BLSP-1 QUP-3 */
cell-index = <0>;
compatible = "qcom,i2c-qup";
@@ -579,15 +617,16 @@
qcom,model = "msm8x10-snd-card";
};
- qcom,msm-pcm {
- compatible = "qcom,msm-pcm-dsp";
- qcom,msm-pcm-dsp-id = <0>;
+ qti,msm-pcm {
+ compatible = "qti,msm-pcm-dsp";
+ qti,msm-pcm-dsp-id = <0>;
};
- qcom,msm-pcm-low-latency {
- compatible = "qcom,msm-pcm-dsp";
- qcom,msm-pcm-dsp-id = <1>;
- qcom,msm-pcm-low-latency;
+ qti,msm-pcm-low-latency {
+ compatible = "qti,msm-pcm-dsp";
+ qti,msm-pcm-dsp-id = <1>;
+ qti,msm-pcm-low-latency;
+ qti,latency-level = "ultra";
};
qcom,msm-pcm-routing {
@@ -857,8 +896,8 @@
qcom,msm-bus,num-cases = <2>;
qcom,msm-bus,num-paths = <1>;
qcom,msm-bus,vectors-KBps =
- <1 618 0 0>,
- <1 618 0 800>;
+ <54 618 0 0>,
+ <54 618 0 800>;
};
qcom,msm-rtb {
diff --git a/arch/arm/boot/dts/msm8926-cdp.dts b/arch/arm/boot/dts/msm8926-1080p-cdp.dts
similarity index 93%
copy from arch/arm/boot/dts/msm8926-cdp.dts
copy to arch/arm/boot/dts/msm8926-1080p-cdp.dts
index d6e70e6..33e484a 100644
--- a/arch/arm/boot/dts/msm8926-cdp.dts
+++ b/arch/arm/boot/dts/msm8926-1080p-cdp.dts
@@ -13,13 +13,13 @@
/dts-v1/;
/include/ "msm8926.dtsi"
-/include/ "msm8226-cdp.dtsi"
+/include/ "msm8226-1080p-cdp.dtsi"
/include/ "msm8226-camera-sensor-cdp.dtsi"
/ {
model = "Qualcomm MSM 8926 CDP";
compatible = "qcom,msm8926-cdp", "qcom,msm8926", "qcom,cdp";
- qcom,board-id = <1 0>;
+ qcom,board-id = <1 2>;
};
&pm8226_chg {
diff --git a/arch/arm/boot/dts/msm8926-mtp.dts b/arch/arm/boot/dts/msm8926-1080p-mtp.dts
similarity index 92%
copy from arch/arm/boot/dts/msm8926-mtp.dts
copy to arch/arm/boot/dts/msm8926-1080p-mtp.dts
index 624781b..c1217a2 100644
--- a/arch/arm/boot/dts/msm8926-mtp.dts
+++ b/arch/arm/boot/dts/msm8926-1080p-mtp.dts
@@ -13,11 +13,11 @@
/dts-v1/;
/include/ "msm8926.dtsi"
-/include/ "msm8226-mtp.dtsi"
+/include/ "msm8226-1080p-mtp.dtsi"
/include/ "msm8226-camera-sensor-mtp.dtsi"
/ {
model = "Qualcomm MSM 8926 MTP";
compatible = "qcom,msm8926-mtp", "qcom,msm8926", "qcom,mtp";
- qcom,board-id = <8 0>;
+ qcom,board-id = <8 2>;
};
diff --git a/arch/arm/boot/dts/msm8926-cdp.dts b/arch/arm/boot/dts/msm8926-720p-cdp.dts
similarity index 96%
rename from arch/arm/boot/dts/msm8926-cdp.dts
rename to arch/arm/boot/dts/msm8926-720p-cdp.dts
index d6e70e6..80bb5e6 100644
--- a/arch/arm/boot/dts/msm8926-cdp.dts
+++ b/arch/arm/boot/dts/msm8926-720p-cdp.dts
@@ -13,7 +13,7 @@
/dts-v1/;
/include/ "msm8926.dtsi"
-/include/ "msm8226-cdp.dtsi"
+/include/ "msm8226-720p-cdp.dtsi"
/include/ "msm8226-camera-sensor-cdp.dtsi"
/ {
diff --git a/arch/arm/boot/dts/msm8926-mtp.dts b/arch/arm/boot/dts/msm8926-720p-mtp.dts
similarity index 95%
rename from arch/arm/boot/dts/msm8926-mtp.dts
rename to arch/arm/boot/dts/msm8926-720p-mtp.dts
index 624781b..32301fd 100644
--- a/arch/arm/boot/dts/msm8926-mtp.dts
+++ b/arch/arm/boot/dts/msm8926-720p-mtp.dts
@@ -13,7 +13,7 @@
/dts-v1/;
/include/ "msm8926.dtsi"
-/include/ "msm8226-mtp.dtsi"
+/include/ "msm8226-720p-mtp.dtsi"
/include/ "msm8226-camera-sensor-mtp.dtsi"
/ {
diff --git a/arch/arm/boot/dts/msm8926-camera-sensor-qrd.dtsi b/arch/arm/boot/dts/msm8926-camera-sensor-qrd.dtsi
index 9b812da..ac2d908 100644
--- a/arch/arm/boot/dts/msm8926-camera-sensor-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8926-camera-sensor-qrd.dtsi
@@ -17,7 +17,7 @@
cell-index = <0>;
compatible = "qcom,camera-led-flash";
qcom,flash-type = <1>;
- qcom,flash-source = <&pm8226_flash0 &pm8226_flash1>;
+ qcom,flash-source = <&pm8226_flash0>;
qcom,torch-source = <&pm8226_torch>;
};
};
diff --git a/arch/arm/boot/dts/apq8026-v2-mtp.dts b/arch/arm/boot/dts/msm8926-qrd-skug-pvt.dts
similarity index 68%
copy from arch/arm/boot/dts/apq8026-v2-mtp.dts
copy to arch/arm/boot/dts/msm8926-qrd-skug-pvt.dts
index 40856c8..2a45592 100644
--- a/arch/arm/boot/dts/apq8026-v2-mtp.dts
+++ b/arch/arm/boot/dts/msm8926-qrd-skug-pvt.dts
@@ -10,13 +10,18 @@
* GNU General Public License for more details.
*/
-
/dts-v1/;
-/include/ "apq8026-v2.dtsi"
-/include/ "msm8226-mtp.dtsi"
+/include/ "msm8926-qrd-skug.dtsi"
/ {
- model = "Qualcomm APQ 8026v2 MTP";
- compatible = "qcom,apq8026-mtp", "qcom,apq8026", "qcom,mtp";
- qcom,board-id = <8 0>;
+ model = "Qti MSM 8926 QRD SKUG PVT";
+ compatible = "qcom,msm8926-qrd", "qcom,msm8926", "qcom,qrd";
+ qcom,board-id = <0x2000b 5>;
+};
+
+&pm8226_vadc {
+ chan@30 {
+ label = "batt_therm";
+ qcom,scale-function = <9>;
+ };
};
diff --git a/arch/arm/boot/dts/msm8926-qrd-skug.dts b/arch/arm/boot/dts/msm8926-qrd-skug.dts
index 6d907ef..4aab4f9 100644
--- a/arch/arm/boot/dts/msm8926-qrd-skug.dts
+++ b/arch/arm/boot/dts/msm8926-qrd-skug.dts
@@ -11,9 +11,7 @@
*/
/dts-v1/;
-/include/ "msm8926.dtsi"
-/include/ "msm8226-qrd.dtsi"
-/include/ "msm8926-camera-sensor-qrd.dtsi"
+/include/ "msm8926-qrd-skug.dtsi"
/ {
model = "Qualcomm MSM 8926 QRD SKUG";
@@ -21,88 +19,3 @@
qcom,board-id = <11 5>;
};
-&qrd_batterydata {
- qcom,rpull-up-kohm = <100>;
- qcom,vref-batt-therm = <1800000>;
-
- /include/ "batterydata-qrd-4v2-2000mah.dtsi"
-};
-
-&pm8226_bms {
- qcom,battery-data = <&qrd_batterydata>;
-};
-
-&pm8226_chg {
- qcom,battery-data = <&qrd_batterydata>;
-};
-
-&soc {
- i2c@f9927000 { /* BLSP1 QUP5 */
- focaltech@38 {
- compatible = "focaltech,5x06";
- reg = <0x38>;
- interrupt-parent = <&msmgpio>;
- interrupts = <17 0x2>;
- vdd-supply = <&pm8226_l19>;
- vcc_i2c-supply = <&pm8226_lvs1>;
- focaltech,name = "ft5336";
- focaltech,family-id = <0x14>;
- focaltech,reset-gpio = <&msmgpio 16 0x00>;
- focaltech,irq-gpio = <&msmgpio 17 0x00>;
- focaltech,display-coords = <0 0 720 1280>;
- focaltech,panel-coords = <0 0 720 1400>;
- focaltech,button-map= <139 102 158>;
- 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-name = "ft_8926_qrd_fw.bin";
- 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,ignore-id-check;
- };
- };
-
- gen-vkeys {
- compatible = "qcom,gen-vkeys";
- label = "ft5x06_ts";
- qcom,disp-maxx = <720>;
- qcom,disp-maxy = <1280>;
- qcom,panel-maxx = <720>;
- qcom,panel-maxy = <1404>;
- qcom,key-codes = <139 172 158>;
- qcom,y-offset = <0>;
- };
-
- gpio-leds {
- compatible = "gpio-leds";
- keypad-backlight {
- gpios = <&msmgpio 34 0>;
- label = "button-backlight";
- linux,default-trigger = "none";
- };
- };
-};
-
-&spmi_bus {
- qcom,pm8226@0 {
- qcom,leds@a100 {
- status = "disable";
- };
- };
-};
-
-&mdss_dsi0 {
- qcom,dsi-pref-prim-pan = <&dsi_ssd2080m_720_vid>;
-};
-
-&dsi_ssd2080m_720_vid {
- qcom,cont-splash-enabled;
-};
diff --git a/arch/arm/boot/dts/msm8926-qrd-skug.dtsi b/arch/arm/boot/dts/msm8926-qrd-skug.dtsi
new file mode 100644
index 0000000..fea5a9e
--- /dev/null
+++ b/arch/arm/boot/dts/msm8926-qrd-skug.dtsi
@@ -0,0 +1,101 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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/ "msm8926.dtsi"
+/include/ "msm8226-qrd.dtsi"
+/include/ "msm8926-camera-sensor-qrd.dtsi"
+
+&qrd_batterydata {
+ qcom,rpull-up-kohm = <100>;
+ qcom,vref-batt-therm = <1800000>;
+
+ /include/ "batterydata-qrd-4v2-2000mah.dtsi"
+};
+
+&pm8226_bms {
+ qcom,battery-data = <&qrd_batterydata>;
+};
+
+&pm8226_chg {
+ qcom,battery-data = <&qrd_batterydata>;
+};
+
+&soc {
+ i2c@f9927000 { /* BLSP1 QUP5 */
+ focaltech@38 {
+ compatible = "focaltech,5x06";
+ reg = <0x38>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <17 0x2>;
+ vdd-supply = <&pm8226_l19>;
+ vcc_i2c-supply = <&pm8226_lvs1>;
+ focaltech,name = "ft5336";
+ focaltech,family-id = <0x14>;
+ focaltech,reset-gpio = <&msmgpio 16 0x00>;
+ focaltech,irq-gpio = <&msmgpio 17 0x00>;
+ focaltech,display-coords = <0 0 720 1280>;
+ focaltech,panel-coords = <0 0 720 1400>;
+ focaltech,button-map= <139 102 158>;
+ 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-name = "ft_8926_qrd_fw.bin";
+ focaltech,fw-delay-aa-ms = <30>;
+ focaltech,fw-delay-55-ms = <30>;
+ focaltech,fw-upgrade-id1 = <0x11>;
+ focaltech,fw-upgrade-id2 = <0x11>;
+ focaltech,fw-delay-readid-ms = <10>;
+ focaltech,fw-delay-era-flsh-ms = <2000>;
+ focaltech,fw-auto-cal;
+ focaltech,ignore-id-check;
+ };
+ };
+
+ gen-vkeys {
+ compatible = "qcom,gen-vkeys";
+ label = "ft5x06_ts";
+ qcom,disp-maxx = <720>;
+ qcom,disp-maxy = <1280>;
+ qcom,panel-maxx = <720>;
+ qcom,panel-maxy = <1404>;
+ qcom,key-codes = <139 172 158>;
+ qcom,y-offset = <0>;
+ };
+
+ gpio-leds {
+ compatible = "gpio-leds";
+ keypad-backlight {
+ gpios = <&msmgpio 34 0>;
+ label = "button-backlight";
+ linux,default-trigger = "none";
+ };
+ };
+};
+
+&spmi_bus {
+ qcom,pm8226@0 {
+ qcom,leds@a100 {
+ status = "disable";
+ };
+ };
+};
+
+&mdss_dsi0 {
+ qcom,dsi-pref-prim-pan = <&dsi_ssd2080m_720_vid>;
+};
+
+&dsi_ssd2080m_720_vid {
+ qcom,cont-splash-enabled;
+};
diff --git a/arch/arm/boot/dts/msm8926.dtsi b/arch/arm/boot/dts/msm8926.dtsi
index bbddec3..963c1b8 100644
--- a/arch/arm/boot/dts/msm8926.dtsi
+++ b/arch/arm/boot/dts/msm8926.dtsi
@@ -39,10 +39,45 @@
vdd_mss-supply = <&pm8226_s5>;
};
- qcom,acpuclk@f9011050 {
+ qcom,clock-a7@f9011050 {
reg = <0xf9011050 0x8>,
<0xfc4b80b0 0x8>;
- reg-names = "rcg_base", "pte_efuse";
+ reg-names = "rcg-base", "efuse";
+ qcom,speed0-bin-v1 =
+ < 0 0>,
+ < 384000000 1>,
+ < 787200000 2>,
+ <1190400000 3>;
+ qcom,speed6-bin-v1 =
+ < 0 0>,
+ < 384000000 1>,
+ < 787200000 2>,
+ <1190400000 3>;
+ qcom,speed2-bin-v1 =
+ < 0 0>,
+ < 384000000 1>,
+ < 787200000 2>,
+ <1401600000 3>;
+ qcom,speed5-bin-v1 =
+ < 0 0>,
+ < 384000000 1>,
+ < 787200000 2>,
+ <1401600000 3>;
+ qcom,speed4-bin-v1 =
+ < 0 0>,
+ < 384000000 1>,
+ < 787200000 2>,
+ <1401600000 3>;
+ qcom,speed7-bin-v1 =
+ < 0 0>,
+ < 384000000 1>,
+ < 787200000 2>,
+ <1401600000 3>;
+ qcom,speed1-bin-v1 =
+ < 0 0>,
+ < 384000000 1>,
+ < 787200000 2>,
+ <1593600000 3>;
};
qcom,msm-thermal {
@@ -125,11 +160,12 @@
1140000 1140000>;
qcom,pvs-corner-ceiling-slow = <1050000 1150000 1280000>;
qcom,pvs-corner-ceiling-nom = <1050000 1080000 1200000>;
- qcom,pvs-corner-ceiling-fast = <1050000 1050000 1140000>;
+ qcom,pvs-corner-ceiling-fast = <1050000 1050000 1100000>;
qcom,cpr-step-quotient = <30>;
qcom,cpr-up-threshold = <0>;
- qcom,cpr-down-threshold = <5>;
+ qcom,cpr-down-threshold = <1>;
qcom,cpr-apc-volt-step = <10000>;
+ qcom,cpr-quotient-adjustment = <96>;
};
&tsens {
diff --git a/arch/arm/boot/dts/msm8974-bus.dtsi b/arch/arm/boot/dts/msm8974-bus.dtsi
index 609a1b3..af51327 100644
--- a/arch/arm/boot/dts/msm8974-bus.dtsi
+++ b/arch/arm/boot/dts/msm8974-bus.dtsi
@@ -1168,18 +1168,12 @@
qcom,masterp = <0>;
qcom,tier = <2>;
qcom,hw-sel = "BIMC";
- qcom,mode = "Limiter";
+ qcom,mode = "Fixed";
qcom,qport = <0>;
qcom,ws = <10000>;
qcom,mas-hw-id = <0>;
qcom,prio-rd = <0>;
qcom,prio-wr = <0>;
- qcom,mode-thresh = "Fixed";
- qcom,thresh = <2000000>;
- qcom,dual-conf;
- qcom,bimc,bw = <300000>;
- qcom,bimc,gp = <5>;
- qcom,bimc,thmp = <50>;
};
mas-ampss-m1 {
@@ -1188,18 +1182,12 @@
qcom,masterp = <1>;
qcom,tier = <2>;
qcom,hw-sel = "BIMC";
- qcom,mode = "Limiter";
+ qcom,mode = "Fixed";
qcom,qport = <1>;
qcom,ws = <10000>;
qcom,mas-hw-id = <0>;
qcom,prio-rd = <0>;
qcom,prio-wr = <0>;
- qcom,mode-thresh = "Fixed";
- qcom,thresh = <2000000>;
- qcom,dual-conf;
- qcom,bimc,bw = <300000>;
- qcom,bimc,gp = <5>;
- qcom,bimc,thmp = <50>;
};
mas-mss-proc {
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
index 9d44bda..29e2aaa 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
@@ -16,6 +16,7 @@
cell-index = <0>;
compatible = "qcom,camera-led-flash";
qcom,flash-type = <1>;
+ qcom,torch-source = <&pm8941_torch>;
qcom,flash-source = <&pm8941_flash0 &pm8941_flash1>;
};
};
diff --git a/arch/arm/boot/dts/msm8974-gpu.dtsi b/arch/arm/boot/dts/msm8974-gpu.dtsi
index 06b9c18..695e452 100644
--- a/arch/arm/boot/dts/msm8974-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8974-gpu.dtsi
@@ -22,8 +22,7 @@
qcom,chipid = <0x03030000>;
- qcom,initial-pwrlevel = <2>;
- qcom,step-pwrlevel = <2>;
+ qcom,initial-pwrlevel = <1>;
qcom,idle-timeout = <8>; //<HZ/12>
qcom,strtstp-sleepwake;
@@ -31,14 +30,17 @@
/* Bus Scale Settings */
qcom,msm-bus,name = "grp3d";
- qcom,msm-bus,num-cases = <6>;
+ qcom,msm-bus,num-cases = <9>;
qcom,msm-bus,num-paths = <2>;
qcom,msm-bus,vectors-KBps =
<26 512 0 0>, <89 604 0 0>,
+ <26 512 0 1600000>, <89 604 0 3000000>,
<26 512 0 2200000>, <89 604 0 3000000>,
<26 512 0 4000000>, <89 604 0 3000000>,
+ <26 512 0 2200000>, <89 604 0 4500000>,
<26 512 0 4000000>, <89 604 0 4500000>,
<26 512 0 6400000>, <89 604 0 4500000>,
+ <26 512 0 4000000>, <89 604 0 7600000>,
<26 512 0 6400000>, <89 604 0 7600000>;
/* GDSC oxili regulators */
@@ -67,40 +69,26 @@
qcom,gpu-pwrlevel@0 {
reg = <0>;
qcom,gpu-freq = <450000000>;
- qcom,bus-freq = <5>;
+ qcom,bus-freq = <8>;
qcom,io-fraction = <33>;
};
qcom,gpu-pwrlevel@1 {
reg = <1>;
qcom,gpu-freq = <320000000>;
- qcom,bus-freq = <4>;
+ qcom,bus-freq = <5>;
qcom,io-fraction = <66>;
};
qcom,gpu-pwrlevel@2 {
reg = <2>;
- qcom,gpu-freq = <320000000>;
- qcom,bus-freq = <3>;
- qcom,io-fraction = <66>;
- };
-
- qcom,gpu-pwrlevel@3 {
- reg = <3>;
qcom,gpu-freq = <200000000>;
qcom,bus-freq = <2>;
qcom,io-fraction = <100>;
};
- qcom,gpu-pwrlevel@4 {
- reg = <4>;
- qcom,gpu-freq = <200000000>;
- qcom,bus-freq = <1>;
- qcom,io-fraction = <100>;
- };
-
- qcom,gpu-pwrlevel@5 {
- reg = <5>;
+ qcom,gpu-pwrlevel@3 {
+ reg = <3>;
qcom,gpu-freq = <27000000>;
qcom,bus-freq = <0>;
qcom,io-fraction = <0>;
diff --git a/arch/arm/boot/dts/msm8974-ion.dtsi b/arch/arm/boot/dts/msm8974-ion.dtsi
index 455ed2d..6ecb7d3 100644
--- a/arch/arm/boot/dts/msm8974-ion.dtsi
+++ b/arch/arm/boot/dts/msm8974-ion.dtsi
@@ -16,12 +16,14 @@
#address-cells = <1>;
#size-cells = <0>;
- qcom,ion-heap@30 { /* SYSTEM HEAP */
- reg = <30>;
+ qcom,ion-heap@25 {
+ reg = <25>;
+ qcom,ion-heap-type = "SYSTEM";
};
- qcom,ion-heap@21 { /* SYSTEM CONTIG HEAP */
+ qcom,ion-heap@21 {
reg = <21>;
+ qcom,ion-heap-type = "SYSTEM_CONTIG";
};
qcom,ion-heap@8 { /* CP_MM HEAP */
@@ -29,6 +31,8 @@
reg = <8>;
qcom,heap-align = <0x1000>;
linux,contiguous-region = <&secure_mem>;
+ qcom,ion-heap-type = "SECURE_DMA";
+ qcom,default-prefetch-size = <0x6c00000>;
};
qcom,ion-heap@22 { /* adsp heap */
@@ -36,16 +40,14 @@
reg = <22>;
qcom,heap-align = <0x1000>;
linux,contiguous-region = <&adsp_mem>;
- };
-
- qcom,ion-heap@25 { /* IOMMU HEAP */
- reg = <25>;
+ qcom,ion-heap-type = "DMA";
};
qcom,ion-heap@27 { /* QSECOM HEAP */
compatible = "qcom,msm-ion-reserve";
reg = <27>;
linux,contiguous-region = <&qsecom_mem>;
+ qcom,ion-heap-type = "DMA";
};
qcom,ion-heap@28 { /* AUDIO HEAP */
@@ -54,6 +56,7 @@
qcom,heap-align = <0x1000>;
qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
qcom,memory-reservation-size = <0x614000>;
+ qcom,ion-heap-type = "CARVEOUT";
};
qcom,ion-heap@23 { /* OTHER PIL HEAP */
@@ -61,6 +64,7 @@
reg = <23>;
qcom,heap-align = <0x1000>;
qcom,memory-fixed = <0x05d00000 0x1e00000>;
+ qcom,ion-heap-type = "CARVEOUT";
};
};
};
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index ba085a0..922e3e0 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -30,6 +30,11 @@
qcom,panel-pwm-period = <53>;
};
+ qcom,mdss_edp@fd923400 {
+ status = "ok";
+ qcom,cont-splash-enabled;
+ };
+
i2c@f9967000 {
battery@b {
compatible = "ti,bq28400-battery";
diff --git a/arch/arm/boot/dts/msm8974-mdss.dtsi b/arch/arm/boot/dts/msm8974-mdss.dtsi
index c866de7..e409c94 100644
--- a/arch/arm/boot/dts/msm8974-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8974-mdss.dtsi
@@ -19,6 +19,8 @@
interrupts = <0 72 0>;
vdd-supply = <&gdsc_mdss>;
+ qcom,max-bandwidth-low-kbps = <2300000>;
+ qcom,max-bandwidth-high-kbps = <3000000>;
qcom,max-clk-rate = <320000000>;
qcom,mdss-pipe-vig-off = <0x00001200 0x00001600
0x00001A00>;
diff --git a/arch/arm/boot/dts/msm8974-regulator.dtsi b/arch/arm/boot/dts/msm8974-regulator.dtsi
index 344c26f..9b9202e 100644
--- a/arch/arm/boot/dts/msm8974-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974-regulator.dtsi
@@ -289,7 +289,7 @@
status = "okay";
pm8941_l11: regulator-l11 {
regulator-min-microvolt = <1300000>;
- regulator-max-microvolt = <1300000>;
+ regulator-max-microvolt = <1350000>;
qcom,init-voltage = <1300000>;
status = "okay";
};
@@ -376,7 +376,7 @@
status = "okay";
pm8941_l19: regulator-l19 {
regulator-min-microvolt = <2900000>;
- regulator-max-microvolt = <3300000>;
+ regulator-max-microvolt = <3350000>;
qcom,init-voltage = <2900000>;
status = "okay";
};
diff --git a/arch/arm/boot/dts/msm8974-v1-pm.dtsi b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
index 0115d89..179edac 100644
--- a/arch/arm/boot/dts/msm8974-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
@@ -208,10 +208,26 @@
<50 172>, /* usb1_hs_async_wakeup_irq */
<53 104>, /* mdss_irq */
<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
+ <0xff 34>, /* APCC_qgicL2ErrorIrptReq */
+ <0xff 35>, /* WDT_barkInt */
+ <0xff 40>, /* qtimer_phy_irq */
<0xff 57>, /* mss_to_apps_irq(0) */
<0xff 58>, /* mss_to_apps_irq(1) */
<0xff 59>, /* mss_to_apps_irq(2) */
<0xff 60>, /* mss_to_apps_irq(3) */
+ <0xff 74>, /* osmmu_CIrpt[1] */
+ <0xff 75>, /* osmmu_CIrpt[0] */
+ <0xff 77>, /* osmmu_CIrpt[0] */
+ <0xff 78>, /* osmmu_CIrpt[0] */
+ <0xff 79>, /* osmmu_CIrpt[0] */
+ <0xff 94>, /* osmmu_CIrpt[0] */
+ <0xff 99>, /* msm_iommu_pmon_nonsecure_irq */
+ <0xff 102>, /* osmmu_CIrpt[1] */
+ <0xff 109>, /* ocmem_dm_nonsec_irq */
+ <0xff 126>, /* bam_irq[0] */
+ <0xff 155>, /* sdcc_irq[0] */
+ <0xff 163>, /* usb30_ee1_irq */
+ <0xff 170>, /* sdcc_pwr_cmd_irq */
<0xff 173>, /* o_wcss_apss_smd_hi */
<0xff 174>, /* o_wcss_apss_smd_med */
<0xff 175>, /* o_wcss_apss_smd_low */
@@ -230,6 +246,7 @@
<0xff 195>, /* lpass_irq_out_apcs(7) */
<0xff 196>, /* lpass_irq_out_apcs(8) */
<0xff 197>, /* lpass_irq_out_apcs(9) */
+ <0xff 198>, /* coresight-tmc-etr interrupt */
<0xff 200>, /* rpm_ipc(4) */
<0xff 201>, /* rpm_ipc(5) */
<0xff 202>, /* rpm_ipc(6) */
@@ -238,7 +255,10 @@
<0xff 205>, /* rpm_ipc(25) */
<0xff 206>, /* rpm_ipc(26) */
<0xff 207>, /* rpm_ipc(27) */
- <0xff 240>; /* summary_irq_kpss */
+ <0xff 240>, /* summary_irq_kpss */
+ <0xff 268>, /* bam_irq[1] */
+ <0xff 270>, /* bam_irq[0] */
+ <0xff 271>; /* bam_irq[0] */
qcom,gpio-parent = <&msmgpio>;
qcom,gpio-map = <3 102>,
@@ -290,6 +310,7 @@
reg = <0xfe805664 0x40>;
qcom,pc-mode = "tz_l2_int";
qcom,use-sync-timer;
+ qcom,cpus-as-clocks;
};
qcom,cpu-sleep-status@f9088008 {
diff --git a/arch/arm/boot/dts/msm8974-v2-pm.dtsi b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
index 8836975..e2d40f7 100644
--- a/arch/arm/boot/dts/msm8974-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
@@ -130,68 +130,65 @@
compatible = "qcom,lpm-levels";
qcom,default-l2-state = "l2_cache_retention";
#address-cells = <1>;
- #size-cells = <0>;
+ #size-cells = <1>;
- qcom,lpm-level@0 {
- reg = <0x0>;
- qcom,mode = "wfi";
- qcom,l2 = "l2_cache_retention";
- qcom,latency-us = <1>;
- qcom,ss-power = <715>;
- qcom,energy-overhead = <17700>;
- qcom,time-overhead = <2>;
+ qcom,cpu-modes {
+ compatible = "qcom,cpu-modes";
+ qcom,cpu-mode@0 {
+ qcom,mode = "wfi";
+ qcom,latency-us = <1>;
+ qcom,ss-power = <715>;
+ qcom,energy-overhead = <17700>;
+ qcom,time-overhead = <2>;
+ };
+
+ qcom,cpu-mode@1 {
+ qcom,mode = "retention";
+ qcom,latency-us = <35>;
+ qcom,ss-power = <542>;
+ qcom,energy-overhead = <34920>;
+ qcom,time-overhead = <40>;
+ };
+
+ qcom,cpu-mode@2 {
+ qcom,mode = "standalone_pc";
+ qcom,latency-us = <300>;
+ qcom,ss-power = <476>;
+ qcom,energy-overhead = <225300>;
+ qcom,time-overhead = <350>;
+ };
+
+ qcom,cpu-mode@3 {
+ qcom,mode = "pc";
+ qcom,latency-us = <500>;
+ qcom,ss-power = <400>;
+ qcom,energy-overhead = <280000>;
+ qcom,time-overhead = <500>;
+ };
+
};
+ qcom,system-modes {
+ compatible = "qcom,system-modes";
- qcom,lpm-level@1 {
- reg = <0x1>;
- qcom,mode = "retention";
- qcom,l2 = "l2_cache_retention";
- qcom,latency-us = <35>;
- qcom,ss-power = <542>;
- qcom,energy-overhead = <34920>;
- qcom,time-overhead = <40>;
- };
+ qcom,system-mode@0 {
+ qcom,l2 = "l2_cache_gdhs";
+ qcom,latency-us = <20000>;
+ qcom,ss-power = <163>;
+ qcom,energy-overhead = <1577736>;
+ qcom,time-overhead = <5067>;
+ qcom,min-cpu-mode= "pc";
+ qcom,sync-cpus;
+ };
-
- qcom,lpm-level@2 {
- reg = <0x2>;
- qcom,mode = "standalone_pc";
- qcom,l2 = "l2_cache_retention";
- qcom,latency-us = <300>;
- qcom,ss-power = <476>;
- qcom,energy-overhead = <225300>;
- qcom,time-overhead = <350>;
- };
-
- qcom,lpm-level@3 {
- reg = <0x3>;
- qcom,mode = "standalone_pc";
- qcom,l2 = "l2_cache_gdhs";
- qcom,latency-us = <320>;
- qcom,ss-power = <476>;
- qcom,energy-overhead = <225300>;
- qcom,time-overhead = <375>;
- };
-
- qcom,lpm-level@4 {
- reg = <0x4>;
- qcom,mode = "pc";
- qcom,l2 = "l2_cache_gdhs";
- qcom,gpio-detectable;
- qcom,latency-us = <20000>;
- qcom,ss-power = <163>;
- qcom,energy-overhead = <1577736>;
- qcom,time-overhead = <5067>;
- };
-
- qcom,lpm-level@5 {
- reg = <0x5>;
- qcom,mode = "pc";
- qcom,l2 = "l2_cache_pc";
- qcom,latency-us = <30000>;
- qcom,ss-power = <83>;
- qcom,energy-overhead = <2274420>;
- qcom,time-overhead = <6605>;
+ qcom,system-mode@1 {
+ qcom,l2 = "l2_cache_pc";
+ qcom,latency-us = <30000>;
+ qcom,ss-power = <83>;
+ qcom,energy-overhead = <2274420>;
+ qcom,time-overhead = <6605>;
+ qcom,min-cpu-mode = "pc";
+ qcom,sync-cpus;
+ };
};
};
@@ -215,6 +212,9 @@
<50 172>, /* usb1_hs_async_wakeup_irq */
<53 104>, /* mdss_irq */
<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
+ <0xff 34>, /* APCC_qgicL2ErrorIrptReq */
+ <0xff 35>, /* WDT_barkInt */
+ <0xff 40>, /* qtimer_phy_irq */
<0xff 56>, /* modem_watchdog */
<0xff 57>, /* mss_to_apps_irq(0) */
<0xff 58>, /* mss_to_apps_irq(1) */
@@ -222,8 +222,21 @@
<0xff 60>, /* mss_to_apps_irq(3) */
<0xff 61>, /* mss_a2_bam_irq */
<0xff 70>, /* iommu_pmon_nonsecure_irq */
+ <0xff 74>, /* osmmu_CIrpt[1] */
+ <0xff 75>, /* osmmu_CIrpt[0] */
+ <0xff 77>, /* osmmu_CIrpt[0] */
+ <0xff 78>, /* osmmu_CIrpt[0] */
+ <0xff 79>, /* osmmu_CIrpt[0] */
+ <0xff 94>, /* osmmu_CIrpt[0] */
<0xff 97>, /* iommu_nonsecure_irq */
+ <0xff 99>, /* msm_iommu_pmon_nonsecure_irq */
+ <0xff 102>, /* osmmu_CIrpt[1] */
<0xff 105>, /* iommu_pmon_nonsecure_irq */
+ <0xff 109>, /* ocmem_dm_nonsec_irq */
+ <0xff 126>, /* bam_irq[0] */
+ <0xff 155>, /* sdcc_irq[0] */
+ <0xff 163>, /* usb30_ee1_irq */
+ <0xff 170>, /* sdcc_pwr_cmd_irq */
<0xff 173>, /* o_wcss_apss_smd_hi */
<0xff 174>, /* o_wcss_apss_smd_med */
<0xff 175>, /* o_wcss_apss_smd_low */
@@ -231,7 +244,6 @@
<0xff 177>, /* o_wcss_apss_wlan_data_xfer_done */
<0xff 178>, /* o_wcss_apss_wlan_rx_data_avail */
<0xff 179>, /* o_wcss_apss_asic_intr */
-
<0xff 181>, /* wcnss watchdog */
<0xff 188>, /* lpass_irq_out_apcs(0) */
<0xff 189>, /* lpass_irq_out_apcs(1) */
@@ -243,6 +255,7 @@
<0xff 195>, /* lpass_irq_out_apcs(7) */
<0xff 196>, /* lpass_irq_out_apcs(8) */
<0xff 197>, /* lpass_irq_out_apcs(9) */
+ <0xff 198>, /* coresight-tmc-etr interrupt */
<0xff 200>, /* rpm_ipc(4) */
<0xff 201>, /* rpm_ipc(5) */
<0xff 202>, /* rpm_ipc(6) */
@@ -252,7 +265,10 @@
<0xff 206>, /* rpm_ipc(26) */
<0xff 207>, /* rpm_ipc(27) */
<0xff 211>, /* usb_dwc3_otg */
- <0xff 240>; /* summary_irq_kpss */
+ <0xff 240>, /* summary_irq_kpss */
+ <0xff 268>, /* bam_irq[1] */
+ <0xff 270>, /* bam_irq[0] */
+ <0xff 271>; /* bam_irq[0] */
qcom,gpio-parent = <&msmgpio>;
qcom,gpio-map = <3 102>,
@@ -304,6 +320,7 @@
reg = <0xfe805664 0x40>;
qcom,pc-mode = "tz_l2_int";
qcom,use-sync-timer;
+ qcom,cpus-as-clocks;
qcom,pm-snoc-client {
compatible = "qcom,pm-snoc-client";
diff --git a/arch/arm/boot/dts/msm8974-v2.2.dtsi b/arch/arm/boot/dts/msm8974-v2.2.dtsi
index 0ca021b..3ed5720 100644
--- a/arch/arm/boot/dts/msm8974-v2.2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.2.dtsi
@@ -23,20 +23,26 @@
/* Updated chip ID */
qcom,chipid = <0x03030001>;
- qcom,initial-pwrlevel = <4>;
+ qcom,initial-pwrlevel = <2>;
/* Updated bus bandwidth requirements */
qcom,msm-bus,vectors-KBps =
/* Off */
<26 512 0 0>, <89 604 0 0>,
+ /* Sub-SVS / SVS */
+ <26 512 0 1600000>, <89 604 0 3000000>,
/* SVS */
<26 512 0 2400000>, <89 604 0 3000000>,
/* Nominal / SVS */
<26 512 0 4656000>, <89 604 0 3000000>,
+ /* SVS / Nominal */
+ <26 512 0 2400000>, <89 604 0 5120000>,
/* Nominal */
<26 512 0 4656000>, <89 604 0 5120000>,
/* Turbo / Nominal */
<26 512 0 7464000>, <89 604 0 5120000>,
+ /* Nominal / Turbo */
+ <26 512 0 4656000>, <89 604 0 6400000>,
/* Turbo */
<26 512 0 7464000>, <89 604 0 6400000>;
@@ -49,54 +55,33 @@
qcom,gpu-pwrlevel@0 {
reg = <0>;
qcom,gpu-freq = <450000000>;
- qcom,bus-freq = <5>;
+ qcom,bus-freq = <8>;
qcom,io-fraction = <33>;
};
qcom,gpu-pwrlevel@1 {
reg = <1>;
qcom,gpu-freq = <389000000>;
- qcom,bus-freq = <4>;
+ qcom,bus-freq = <5>;
qcom,io-fraction = <33>;
};
qcom,gpu-pwrlevel@2 {
reg = <2>;
- qcom,gpu-freq = <389000000>;
- qcom,bus-freq = <3>;
+ qcom,gpu-freq = <320000000>;
+ qcom,bus-freq = <5>;
qcom,io-fraction = <66>;
};
qcom,gpu-pwrlevel@3 {
reg = <3>;
- qcom,gpu-freq = <320000000>;
- qcom,bus-freq = <4>;
- qcom,io-fraction = <66>;
- };
-
- qcom,gpu-pwrlevel@4 {
- reg = <4>;
- qcom,gpu-freq = <320000000>;
- qcom,bus-freq = <3>;
- qcom,io-fraction = <66>;
- };
-
- qcom,gpu-pwrlevel@5 {
- reg = <5>;
qcom,gpu-freq = <200000000>;
qcom,bus-freq = <2>;
qcom,io-fraction = <100>;
};
- qcom,gpu-pwrlevel@6 {
- reg = <6>;
- qcom,gpu-freq = <200000000>;
- qcom,bus-freq = <1>;
- qcom,io-fraction = <100>;
- };
-
- qcom,gpu-pwrlevel@7 {
- reg = <7>;
+ qcom,gpu-pwrlevel@4 {
+ reg = <4>;
qcom,gpu-freq = <27000000>;
qcom,bus-freq = <0>;
qcom,io-fraction = <0>;
diff --git a/arch/arm/boot/dts/msm8974-v2.dtsi b/arch/arm/boot/dts/msm8974-v2.dtsi
index 0da5658..5607257 100644
--- a/arch/arm/boot/dts/msm8974-v2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.dtsi
@@ -58,14 +58,20 @@
qcom,msm-bus,vectors-KBps =
/* Off */
<26 512 0 0>, <89 604 0 0>,
+ /* Sub-SVS / SVS */
+ <26 512 0 1600000>, <89 604 0 3000000>,
/* SVS */
<26 512 0 2400000>, <89 604 0 3000000>,
/* Nominal / SVS */
- <26 512 0 4656000>, <89 604 0 3000000>,
+ <26 512 0 4912000>, <89 604 0 3000000>,
+ /* SVS / Nominal */
+ <26 512 0 2400000>, <89 604 0 5120000>,
/* Nominal */
- <26 512 0 4656000>, <89 604 0 5120000>,
+ <26 512 0 4912000>, <89 604 0 5120000>,
/* Turbo / Nominal */
<26 512 0 7464000>, <89 604 0 5120000>,
+ /* Nominal / Turbo */
+ <26 512 0 4912000>, <89 604 0 6400000>,
/* Turbo */
<26 512 0 7464000>, <89 604 0 6400000>;
};
@@ -81,6 +87,7 @@
qcom,mdss-has-bwc;
qcom,mdss-has-decimation;
qcom,mdss-ad-off = <0x0013100 0x00013300>;
+ vdd-cx-supply = <&pm8841_s2_corner>;
};
&mdss_hdmi_tx {
@@ -115,7 +122,7 @@
qcom,dec-ocmem-ab-ib = <0 0>,
<176000 519000>,
<456000 519000>,
- <864000 519000>,
+ <864000 629000>,
<1728000 1038000>,
<2766000 1661000>,
<3456000 2076000>,
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 39fb108..4babf11 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -100,6 +100,7 @@
/include/ "msm8974-mdss.dtsi"
/include/ "msm8974-smp2p.dtsi"
/include/ "msm8974-bus.dtsi"
+/include/ "msm-rdbg.dtsi"
&soc {
#address-cells = <1>;
@@ -283,6 +284,24 @@
<87 512 60000 960000>;
};
+ rmtfs_sharedmem {
+ compatible = "qcom,sharedmem-uio";
+ reg = <0x0fd80000 0x00180000>;
+ reg-names = "rmtfs";
+ };
+
+ dsp_sharedmem {
+ compatible = "qcom,sharedmem-uio";
+ reg = <0x0fd60000 0x00020000>;
+ reg-names = "rfsa_dsp";
+ };
+
+ mdm_sharedmem {
+ compatible = "qcom,sharedmem-uio";
+ reg = <0x0fd60000 0x00020000>;
+ reg-names = "rfsa_mdm";
+ };
+
sdcc1: qcom,sdcc@f9824000 {
cell-index = <1>; /* SDC1 eMMC slot */
compatible = "qcom,msm-sdcc";
@@ -741,6 +760,14 @@
sound {
compatible = "qcom,msm8974-audio-taiko";
qcom,model = "msm8974-taiko-snd-card";
+ reg = <0xfe02b000 0x4>,
+ <0xfe02c000 0x4>,
+ <0xfe02d000 0x4>,
+ <0xfe02e000 0x4>;
+ reg-names = "lpaif_pri_mode_muxsel",
+ "lpaif_sec_mode_muxsel",
+ "lpaif_tert_mode_muxsel",
+ "lpaif_quat_mode_muxsel";
qcom,audio-routing =
"RX_BIAS", "MCLK",
@@ -865,25 +892,668 @@
qcom,master-id = <86>;
};
- qcom,acpuclk@f9000000 {
- compatible = "qcom,acpuclk-8974";
- krait0-supply = <&krait0_vreg>;
- krait1-supply = <&krait1_vreg>;
- krait2-supply = <&krait2_vreg>;
- krait3-supply = <&krait3_vreg>;
- krait0_mem-supply = <&pm8841_s1_ao>;
- krait1_mem-supply = <&pm8841_s1_ao>;
- krait2_mem-supply = <&pm8841_s1_ao>;
- krait3_mem-supply = <&pm8841_s1_ao>;
- krait0_dig-supply = <&pm8841_s2_corner_ao>;
- krait1_dig-supply = <&pm8841_s2_corner_ao>;
- krait2_dig-supply = <&pm8841_s2_corner_ao>;
- krait3_dig-supply = <&pm8841_s2_corner_ao>;
- krait0_hfpll-supply = <&pm8941_l12_ao>;
- krait1_hfpll-supply = <&pm8941_l12_ao>;
- krait2_hfpll-supply = <&pm8941_l12_ao>;
- krait3_hfpll-supply = <&pm8941_l12_ao>;
- l2_hfpll-supply = <&pm8941_l12_ao>;
+ qcom,clock-krait@f9016000 {
+ compatible = "qcom,clock-krait-8974";
+ reg = <0xf9016000 0x20>,
+ <0xf908a000 0x20>,
+ <0xf909a000 0x20>,
+ <0xf90aa000 0x20>,
+ <0xf90ba000 0x20>,
+ <0xfc4b80b0 0x08>;
+ reg-names = "hfpll_l2_clk", "hfpll0_clk",
+ "hfpll1_clk", "hfpll2_clk",
+ "hfpll3_clk", "efuse";
+ cpu0-supply = <&krait0_vreg>;
+ cpu1-supply = <&krait1_vreg>;
+ cpu2-supply = <&krait2_vreg>;
+ cpu3-supply = <&krait3_vreg>;
+ l2-dig-supply = <&pm8841_s2_corner_ao>;
+ hfpll-dig-supply = <&pm8841_s2_corner_ao>;
+ hfpll-analog-supply = <&pm8941_l12_ao>;
+ qcom,hfpll-config-val = <0x04D0405D>;
+ qcom,hfpll-user-vco-mask = <0x00100000>;
+
+ qcom,l2-fmax =
+ < 0 0 >,
+ < 576000000 4 /* SVS_SOC */ >,
+ < 1036800000 5 /* NORMAL */ >,
+ < 1728000000 7 /* SUPER_TURBO */ >;
+
+ qcom,speed0-pvs0-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 815000 73 >,
+ < 345600000 825000 85 >,
+ < 422400000 835000 104 >,
+ < 499200000 845000 124 >,
+ < 576000000 855000 144 >,
+ < 652800000 865000 165 >,
+ < 729600000 875000 186 >,
+ < 806400000 890000 208 >,
+ < 883200000 900000 229 >,
+ < 960000000 915000 252 >,
+ < 1036800000 925000 275 >,
+ < 1113600000 940000 298 >,
+ < 1190400000 950000 321 >,
+ < 1267200000 965000 346 >,
+ < 1344000000 980000 371 >,
+ < 1420800000 995000 397 >,
+ < 1497600000 1010000 423 >,
+ < 1574400000 1025000 450 >,
+ < 1651200000 1040000 477 >,
+ < 1728000000 1055000 506 >,
+ < 1804800000 1070000 536 >,
+ < 1881600000 1085000 567 >,
+ < 1958400000 1100000 598 >;
+
+ qcom,speed0-pvs1-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 800000 73 >,
+ < 345600000 810000 85 >,
+ < 422400000 820000 104 >,
+ < 499200000 830000 124 >,
+ < 576000000 840000 144 >,
+ < 652800000 850000 165 >,
+ < 729600000 860000 186 >,
+ < 806400000 875000 208 >,
+ < 883200000 885000 229 >,
+ < 960000000 895000 252 >,
+ < 1036800000 910000 275 >,
+ < 1113600000 920000 298 >,
+ < 1190400000 930000 321 >,
+ < 1267200000 945000 346 >,
+ < 1344000000 960000 371 >,
+ < 1420800000 975000 397 >,
+ < 1497600000 990000 423 >,
+ < 1574400000 1005000 450 >,
+ < 1651200000 1020000 477 >,
+ < 1728000000 1030000 506 >,
+ < 1804800000 1045000 536 >,
+ < 1881600000 1060000 567 >,
+ < 1958400000 1075000 598 >;
+
+ qcom,speed0-pvs2-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 785000 73 >,
+ < 345600000 795000 85 >,
+ < 422400000 805000 104 >,
+ < 499200000 815000 124 >,
+ < 576000000 825000 144 >,
+ < 652800000 835000 165 >,
+ < 729600000 845000 186 >,
+ < 806400000 855000 208 >,
+ < 883200000 865000 229 >,
+ < 960000000 875000 252 >,
+ < 1036800000 890000 275 >,
+ < 1113600000 900000 298 >,
+ < 1190400000 910000 321 >,
+ < 1267200000 925000 346 >,
+ < 1344000000 940000 371 >,
+ < 1420800000 955000 397 >,
+ < 1497600000 970000 423 >,
+ < 1574400000 980000 450 >,
+ < 1651200000 995000 477 >,
+ < 1728000000 1005000 506 >,
+ < 1804800000 1020000 536 >,
+ < 1881600000 1035000 567 >,
+ < 1958400000 1050000 598 >;
+
+ qcom,speed0-pvs3-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 775000 73 >,
+ < 345600000 780000 85 >,
+ < 422400000 790000 104 >,
+ < 499200000 800000 124 >,
+ < 576000000 810000 144 >,
+ < 652800000 820000 165 >,
+ < 729600000 830000 186 >,
+ < 806400000 840000 208 >,
+ < 883200000 850000 229 >,
+ < 960000000 860000 252 >,
+ < 1036800000 875000 275 >,
+ < 1113600000 885000 298 >,
+ < 1190400000 895000 321 >,
+ < 1267200000 910000 346 >,
+ < 1344000000 925000 371 >,
+ < 1420800000 935000 397 >,
+ < 1497600000 950000 423 >,
+ < 1574400000 960000 450 >,
+ < 1651200000 970000 477 >,
+ < 1728000000 985000 506 >,
+ < 1804800000 995000 536 >,
+ < 1881600000 1010000 567 >,
+ < 1958400000 1025000 598 >;
+
+ qcom,speed0-pvs4-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 775000 73 >,
+ < 345600000 775000 85 >,
+ < 422400000 780000 104 >,
+ < 499200000 790000 124 >,
+ < 576000000 800000 144 >,
+ < 652800000 810000 165 >,
+ < 729600000 820000 186 >,
+ < 806400000 830000 208 >,
+ < 883200000 840000 229 >,
+ < 960000000 850000 252 >,
+ < 1036800000 860000 275 >,
+ < 1113600000 870000 298 >,
+ < 1190400000 880000 321 >,
+ < 1267200000 895000 346 >,
+ < 1344000000 910000 371 >,
+ < 1420800000 920000 397 >,
+ < 1497600000 930000 423 >,
+ < 1574400000 940000 450 >,
+ < 1651200000 950000 477 >,
+ < 1728000000 960000 506 >,
+ < 1804800000 975000 536 >,
+ < 1881600000 985000 567 >,
+ < 1958400000 1000000 598 >;
+
+ qcom,speed0-pvs5-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 750000 73 >,
+ < 345600000 760000 85 >,
+ < 422400000 770000 104 >,
+ < 499200000 780000 124 >,
+ < 576000000 790000 144 >,
+ < 652800000 800000 165 >,
+ < 729600000 810000 186 >,
+ < 806400000 820000 208 >,
+ < 883200000 830000 229 >,
+ < 960000000 840000 252 >,
+ < 1036800000 850000 275 >,
+ < 1113600000 860000 298 >,
+ < 1190400000 870000 321 >,
+ < 1267200000 880000 346 >,
+ < 1344000000 890000 371 >,
+ < 1420800000 900000 397 >,
+ < 1497600000 910000 423 >,
+ < 1574400000 920000 450 >,
+ < 1651200000 930000 477 >,
+ < 1728000000 940000 506 >,
+ < 1804800000 955000 536 >,
+ < 1881600000 965000 567 >,
+ < 1958400000 975000 598 >;
+
+ qcom,speed0-pvs6-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 750000 73 >,
+ < 345600000 750000 85 >,
+ < 422400000 760000 104 >,
+ < 499200000 770000 124 >,
+ < 576000000 780000 144 >,
+ < 652800000 790000 165 >,
+ < 729600000 800000 186 >,
+ < 806400000 810000 208 >,
+ < 883200000 820000 229 >,
+ < 960000000 830000 252 >,
+ < 1036800000 840000 275 >,
+ < 1113600000 850000 298 >,
+ < 1190400000 860000 321 >,
+ < 1267200000 870000 346 >,
+ < 1344000000 875000 371 >,
+ < 1420800000 885000 397 >,
+ < 1497600000 895000 423 >,
+ < 1574400000 905000 450 >,
+ < 1651200000 915000 477 >,
+ < 1728000000 920000 506 >,
+ < 1804800000 930000 536 >,
+ < 1881600000 940000 567 >,
+ < 1958400000 950000 598 >;
+
+ qcom,speed2-pvs0-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 800000 72 >,
+ < 345600000 800000 83 >,
+ < 422400000 805000 102 >,
+ < 499200000 815000 121 >,
+ < 576000000 825000 141 >,
+ < 652800000 835000 161 >,
+ < 729600000 845000 181 >,
+ < 806400000 855000 202 >,
+ < 883200000 865000 223 >,
+ < 960000000 875000 245 >,
+ < 1036800000 890000 267 >,
+ < 1113600000 900000 289 >,
+ < 1190400000 915000 313 >,
+ < 1267200000 925000 336 >,
+ < 1344000000 940000 360 >,
+ < 1420800000 950000 383 >,
+ < 1497600000 965000 409 >,
+ < 1574400000 980000 435 >,
+ < 1651200000 995000 461 >,
+ < 1728000000 1010000 488 >,
+ < 1804800000 1025000 516 >,
+ < 1881600000 1040000 543 >,
+ < 1958400000 1055000 573 >,
+ < 2035200000 1070000 604 >,
+ < 2112000000 1085000 636 >,
+ < 2150400000 1100000 656 >;
+
+ qcom,speed2-pvs1-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 800000 72 >,
+ < 345600000 800000 83 >,
+ < 422400000 800000 102 >,
+ < 499200000 800000 121 >,
+ < 576000000 810000 141 >,
+ < 652800000 820000 161 >,
+ < 729600000 830000 181 >,
+ < 806400000 840000 202 >,
+ < 883200000 850000 223 >,
+ < 960000000 860000 245 >,
+ < 1036800000 875000 267 >,
+ < 1113600000 885000 289 >,
+ < 1190400000 895000 313 >,
+ < 1267200000 910000 336 >,
+ < 1344000000 920000 360 >,
+ < 1420800000 930000 383 >,
+ < 1497600000 945000 409 >,
+ < 1574400000 960000 435 >,
+ < 1651200000 975000 461 >,
+ < 1728000000 990000 488 >,
+ < 1804800000 1005000 516 >,
+ < 1881600000 1020000 543 >,
+ < 1958400000 1030000 573 >,
+ < 2035200000 1045000 604 >,
+ < 2112000000 1060000 636 >,
+ < 2150400000 1075000 656 >;
+
+ qcom,speed2-pvs2-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 775000 72 >,
+ < 345600000 775000 83 >,
+ < 422400000 775000 102 >,
+ < 499200000 785000 121 >,
+ < 576000000 795000 141 >,
+ < 652800000 805000 161 >,
+ < 729600000 815000 181 >,
+ < 806400000 825000 202 >,
+ < 883200000 835000 223 >,
+ < 960000000 845000 245 >,
+ < 1036800000 855000 267 >,
+ < 1113600000 865000 289 >,
+ < 1190400000 875000 313 >,
+ < 1267200000 890000 336 >,
+ < 1344000000 900000 360 >,
+ < 1420800000 910000 383 >,
+ < 1497600000 925000 409 >,
+ < 1574400000 940000 435 >,
+ < 1651200000 955000 461 >,
+ < 1728000000 970000 488 >,
+ < 1804800000 980000 516 >,
+ < 1881600000 995000 543 >,
+ < 1958400000 1005000 573 >,
+ < 2035200000 1020000 604 >,
+ < 2112000000 1035000 636 >,
+ < 2150400000 1050000 656 >;
+
+ qcom,speed2-pvs3-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 775000 72 >,
+ < 345600000 775000 83 >,
+ < 422400000 775000 102 >,
+ < 499200000 775000 121 >,
+ < 576000000 780000 141 >,
+ < 652800000 790000 161 >,
+ < 729600000 800000 181 >,
+ < 806400000 810000 202 >,
+ < 883200000 820000 223 >,
+ < 960000000 830000 245 >,
+ < 1036800000 840000 267 >,
+ < 1113600000 850000 289 >,
+ < 1190400000 860000 313 >,
+ < 1267200000 875000 336 >,
+ < 1344000000 885000 360 >,
+ < 1420800000 895000 383 >,
+ < 1497600000 910000 409 >,
+ < 1574400000 925000 435 >,
+ < 1651200000 935000 461 >,
+ < 1728000000 950000 488 >,
+ < 1804800000 960000 516 >,
+ < 1881600000 970000 543 >,
+ < 1958400000 985000 573 >,
+ < 2035200000 995000 604 >,
+ < 2112000000 1010000 636 >,
+ < 2150400000 1025000 656 >;
+
+ qcom,speed2-pvs4-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 775000 72 >,
+ < 345600000 775000 83 >,
+ < 422400000 775000 102 >,
+ < 499200000 775000 121 >,
+ < 576000000 775000 141 >,
+ < 652800000 780000 161 >,
+ < 729600000 790000 181 >,
+ < 806400000 800000 202 >,
+ < 883200000 810000 223 >,
+ < 960000000 820000 245 >,
+ < 1036800000 830000 267 >,
+ < 1113600000 840000 289 >,
+ < 1190400000 850000 313 >,
+ < 1267200000 860000 336 >,
+ < 1344000000 870000 360 >,
+ < 1420800000 880000 383 >,
+ < 1497600000 895000 409 >,
+ < 1574400000 910000 435 >,
+ < 1651200000 920000 461 >,
+ < 1728000000 930000 488 >,
+ < 1804800000 940000 516 >,
+ < 1881600000 950000 543 >,
+ < 1958400000 960000 573 >,
+ < 2035200000 975000 604 >,
+ < 2112000000 985000 636 >,
+ < 2150400000 1000000 656 >;
+
+ qcom,speed2-pvs5-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 750000 72 >,
+ < 345600000 750000 83 >,
+ < 422400000 750000 102 >,
+ < 499200000 750000 121 >,
+ < 576000000 760000 141 >,
+ < 652800000 770000 161 >,
+ < 729600000 780000 181 >,
+ < 806400000 790000 202 >,
+ < 883200000 800000 223 >,
+ < 960000000 810000 245 >,
+ < 1036800000 820000 267 >,
+ < 1113600000 830000 289 >,
+ < 1190400000 840000 313 >,
+ < 1267200000 850000 336 >,
+ < 1344000000 860000 360 >,
+ < 1420800000 870000 383 >,
+ < 1497600000 880000 409 >,
+ < 1574400000 890000 435 >,
+ < 1651200000 900000 461 >,
+ < 1728000000 910000 488 >,
+ < 1804800000 920000 516 >,
+ < 1881600000 930000 543 >,
+ < 1958400000 940000 573 >,
+ < 2035200000 955000 604 >,
+ < 2112000000 965000 636 >,
+ < 2150400000 975000 656 >;
+
+ qcom,speed2-pvs6-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 750000 72 >,
+ < 345600000 750000 83 >,
+ < 422400000 750000 102 >,
+ < 499200000 750000 121 >,
+ < 576000000 750000 141 >,
+ < 652800000 760000 161 >,
+ < 729600000 770000 181 >,
+ < 806400000 780000 202 >,
+ < 883200000 790000 223 >,
+ < 960000000 800000 245 >,
+ < 1036800000 810000 267 >,
+ < 1113600000 820000 289 >,
+ < 1190400000 830000 313 >,
+ < 1267200000 840000 336 >,
+ < 1344000000 850000 360 >,
+ < 1420800000 860000 383 >,
+ < 1497600000 870000 409 >,
+ < 1574400000 875000 435 >,
+ < 1651200000 885000 461 >,
+ < 1728000000 895000 488 >,
+ < 1804800000 905000 516 >,
+ < 1881600000 915000 543 >,
+ < 1958400000 920000 573 >,
+ < 2035200000 930000 604 >,
+ < 2112000000 940000 636 >,
+ < 2150400000 950000 656 >;
+
+ qcom,speed1-pvs0-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 775000 72 >,
+ < 345600000 775000 83 >,
+ < 422400000 775000 101 >,
+ < 499200000 780000 120 >,
+ < 576000000 790000 139 >,
+ < 652800000 800000 159 >,
+ < 729600000 810000 180 >,
+ < 806400000 820000 200 >,
+ < 883200000 830000 221 >,
+ < 960000000 840000 242 >,
+ < 1036800000 850000 264 >,
+ < 1113600000 865000 287 >,
+ < 1190400000 875000 308 >,
+ < 1267200000 890000 333 >,
+ < 1344000000 900000 356 >,
+ < 1420800000 915000 380 >,
+ < 1497600000 925000 404 >,
+ < 1574400000 940000 430 >,
+ < 1651200000 955000 456 >,
+ < 1728000000 970000 482 >,
+ < 1804800000 985000 510 >,
+ < 1881600000 1000000 538 >,
+ < 1958400000 1015000 565 >,
+ < 2035200000 1030000 596 >,
+ < 2112000000 1045000 627 >,
+ < 2188800000 1060000 659 >,
+ < 2265600000 1075000 691 >;
+
+ qcom,speed1-pvs1-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 775000 72 >,
+ < 345600000 775000 83 >,
+ < 422400000 775000 101 >,
+ < 499200000 775000 120 >,
+ < 576000000 775000 139 >,
+ < 652800000 785000 159 >,
+ < 729600000 795000 180 >,
+ < 806400000 805000 200 >,
+ < 883200000 815000 221 >,
+ < 960000000 825000 242 >,
+ < 1036800000 835000 264 >,
+ < 1113600000 850000 287 >,
+ < 1190400000 860000 308 >,
+ < 1267200000 870000 333 >,
+ < 1344000000 885000 356 >,
+ < 1420800000 895000 380 >,
+ < 1497600000 905000 404 >,
+ < 1574400000 920000 430 >,
+ < 1651200000 935000 456 >,
+ < 1728000000 950000 482 >,
+ < 1804800000 965000 510 >,
+ < 1881600000 980000 538 >,
+ < 1958400000 995000 565 >,
+ < 2035200000 1005000 596 >,
+ < 2112000000 1020000 627 >,
+ < 2188800000 1035000 659 >,
+ < 2265600000 1050000 691 >;
+
+ qcom,speed1-pvs2-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 750000 72 >,
+ < 345600000 750000 83 >,
+ < 422400000 750000 101 >,
+ < 499200000 750000 120 >,
+ < 576000000 760000 139 >,
+ < 652800000 770000 159 >,
+ < 729600000 780000 180 >,
+ < 806400000 790000 200 >,
+ < 883200000 800000 221 >,
+ < 960000000 810000 242 >,
+ < 1036800000 820000 264 >,
+ < 1113600000 830000 287 >,
+ < 1190400000 840000 308 >,
+ < 1267200000 850000 333 >,
+ < 1344000000 865000 356 >,
+ < 1420800000 875000 380 >,
+ < 1497600000 885000 404 >,
+ < 1574400000 900000 430 >,
+ < 1651200000 915000 456 >,
+ < 1728000000 930000 482 >,
+ < 1804800000 945000 510 >,
+ < 1881600000 955000 538 >,
+ < 1958400000 970000 565 >,
+ < 2035200000 980000 596 >,
+ < 2112000000 995000 627 >,
+ < 2188800000 1010000 659 >,
+ < 2265600000 1025000 691 >;
+
+ qcom,speed1-pvs3-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 750000 72 >,
+ < 345600000 750000 83 >,
+ < 422400000 750000 101 >,
+ < 499200000 750000 120 >,
+ < 576000000 750000 139 >,
+ < 652800000 755000 159 >,
+ < 729600000 765000 180 >,
+ < 806400000 775000 200 >,
+ < 883200000 785000 221 >,
+ < 960000000 795000 242 >,
+ < 1036800000 805000 264 >,
+ < 1113600000 815000 287 >,
+ < 1190400000 825000 308 >,
+ < 1267200000 835000 333 >,
+ < 1344000000 850000 356 >,
+ < 1420800000 860000 380 >,
+ < 1497600000 870000 404 >,
+ < 1574400000 885000 430 >,
+ < 1651200000 900000 456 >,
+ < 1728000000 910000 482 >,
+ < 1804800000 925000 510 >,
+ < 1881600000 935000 538 >,
+ < 1958400000 945000 565 >,
+ < 2035200000 960000 596 >,
+ < 2112000000 970000 627 >,
+ < 2188800000 985000 659 >,
+ < 2265600000 1000000 691 >;
+
+ qcom,speed1-pvs4-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 750000 72 >,
+ < 345600000 750000 83 >,
+ < 422400000 750000 101 >,
+ < 499200000 750000 120 >,
+ < 576000000 750000 139 >,
+ < 652800000 750000 159 >,
+ < 729600000 755000 180 >,
+ < 806400000 765000 200 >,
+ < 883200000 775000 221 >,
+ < 960000000 785000 242 >,
+ < 1036800000 795000 264 >,
+ < 1113600000 805000 287 >,
+ < 1190400000 815000 308 >,
+ < 1267200000 825000 333 >,
+ < 1344000000 835000 356 >,
+ < 1420800000 845000 380 >,
+ < 1497600000 855000 404 >,
+ < 1574400000 870000 430 >,
+ < 1651200000 885000 456 >,
+ < 1728000000 895000 482 >,
+ < 1804800000 905000 510 >,
+ < 1881600000 915000 538 >,
+ < 1958400000 925000 565 >,
+ < 2035200000 935000 596 >,
+ < 2112000000 950000 627 >,
+ < 2188800000 960000 659 >,
+ < 2265600000 975000 691 >;
+
+ qcom,speed1-pvs5-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 725000 72 >,
+ < 345600000 725000 83 >,
+ < 422400000 725000 101 >,
+ < 499200000 725000 120 >,
+ < 576000000 725000 139 >,
+ < 652800000 735000 159 >,
+ < 729600000 745000 180 >,
+ < 806400000 755000 200 >,
+ < 883200000 765000 221 >,
+ < 960000000 775000 242 >,
+ < 1036800000 785000 264 >,
+ < 1113600000 795000 287 >,
+ < 1190400000 805000 308 >,
+ < 1267200000 815000 333 >,
+ < 1344000000 825000 356 >,
+ < 1420800000 835000 380 >,
+ < 1497600000 845000 404 >,
+ < 1574400000 855000 430 >,
+ < 1651200000 865000 456 >,
+ < 1728000000 875000 482 >,
+ < 1804800000 885000 510 >,
+ < 1881600000 895000 538 >,
+ < 1958400000 905000 565 >,
+ < 2035200000 915000 596 >,
+ < 2112000000 930000 627 >,
+ < 2188800000 940000 659 >,
+ < 2265600000 950000 691 >;
+
+ qcom,speed1-pvs6-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 725000 72 >,
+ < 345600000 725000 83 >,
+ < 422400000 725000 101 >,
+ < 499200000 725000 120 >,
+ < 576000000 725000 139 >,
+ < 652800000 725000 159 >,
+ < 729600000 735000 180 >,
+ < 806400000 745000 200 >,
+ < 883200000 755000 221 >,
+ < 960000000 765000 242 >,
+ < 1036800000 775000 264 >,
+ < 1113600000 785000 287 >,
+ < 1190400000 795000 308 >,
+ < 1267200000 805000 333 >,
+ < 1344000000 815000 356 >,
+ < 1420800000 825000 380 >,
+ < 1497600000 835000 404 >,
+ < 1574400000 845000 430 >,
+ < 1651200000 850000 456 >,
+ < 1728000000 860000 482 >,
+ < 1804800000 870000 510 >,
+ < 1881600000 880000 538 >,
+ < 1958400000 890000 565 >,
+ < 2035200000 895000 596 >,
+ < 2112000000 905000 627 >,
+ < 2188800000 915000 659 >,
+ < 2265600000 925000 691 >;
+ };
+
+ qcom,cpubw {
+ compatible = "qcom,cpubw";
+ qcom,cpu-mem-ports = <1 512>, <2 512>;
+ qcom,bw-tbl =
+ < 572 /* 75 MHz */ >,
+ < 1144 /* 150 MHz */ >,
+ < 1525 /* 200 MHz */ >,
+ < 2342 /* 307 MHz */ >,
+ < 3509 /* 460 MHz */ >,
+ < 4684 /* 614 MHz */ >,
+ < 6103 /* 800 MHz */ >,
+ < 7102 /* 931 MHz */ >;
+ };
+
+ qcom,kraitbw-l2pm {
+ compatible = "qcom,kraitbw-l2pm";
+ interrupts = <0 1 1>;
+ qcom,bytes-per-beat = <8>;
+ };
+
+ qcom,msm-cpufreq@0 {
+ reg = <0 4>;
+ compatible = "qcom,msm-cpufreq";
+ qcom,cpufreq-table =
+ < 300000 300000 572 >,
+ < 422400 422400 1144 >,
+ < 652800 499200 1525 >,
+ < 729600 576000 2342 >,
+ < 883200 576000 2342 >,
+ < 960000 960000 3509 >,
+ < 1036800 1036800 3509 >,
+ < 1190400 1036800 3509 >,
+ < 1267200 1267200 4684 >,
+ < 1497600 1497600 4684 >,
+ < 1574400 1574400 6103 >,
+ < 1728000 1651200 6103 >,
+ < 1958400 1728000 7102 >,
+ < 2265600 1728000 7102 >,
+ < 2457600 1728000 7102 >;
};
usb3: qcom,ssusb@f9200000 {
@@ -978,15 +1648,16 @@
compatible = "qcom,msm-audio-ion";
};
- qcom,msm-pcm {
- compatible = "qcom,msm-pcm-dsp";
- qcom,msm-pcm-dsp-id = <0>;
+ qti,msm-pcm {
+ compatible = "qti,msm-pcm-dsp";
+ qti,msm-pcm-dsp-id = <0>;
};
- qcom,msm-pcm-low-latency {
- compatible = "qcom,msm-pcm-dsp";
- qcom,msm-pcm-dsp-id = <1>;
- qcom,msm-pcm-low-latency;
+ qti,msm-pcm-low-latency {
+ compatible = "qti,msm-pcm-dsp";
+ qti,msm-pcm-dsp-id = <1>;
+ qti,msm-pcm-low-latency;
+ qti,latency-level = "regular";
};
qcom,msm-pcm-routing {
@@ -1034,6 +1705,10 @@
compatible = "qcom,msm-lsm-client";
};
+ qti,msm-pcm-loopback {
+ compatible = "qti,msm-pcm-loopback";
+ };
+
qcom,msm-dai-q6 {
compatible = "qcom,msm-dai-q6";
qcom,msm-dai-q6-sb-0-rx {
@@ -1336,14 +2011,15 @@
qcom,disk-encrypt-pipe-pair = <2>;
qcom,hlos-ce-hw-instance = <1>;
qcom,qsee-ce-hw-instance = <0>;
+ qcom,support-bus-scaling = <1>;
qcom,msm-bus,name = "qseecom-noc";
qcom,msm-bus,num-cases = <4>;
qcom,msm-bus,num-paths = <1>;
qcom,msm-bus,vectors-KBps =
<55 512 0 0>,
- <55 512 3936000 393600>,
- <55 512 3936000 393600>,
- <55 512 3936000 393600>;
+ <55 512 0 0>,
+ <55 512 120000 1200000>,
+ <55 512 393600 3936000>;
};
qcom,wdt@f9017000 {
@@ -1528,6 +2204,10 @@
qcom,hotplug-temp-hysteresis = <20>;
qcom,cpu-sensors = "tsens_tz_sensor5", "tsens_tz_sensor6",
"tsens_tz_sensor7", "tsens_tz_sensor8";
+ qcom,freq-mitigation-temp = <110>;
+ qcom,freq-mitigation-temp-hysteresis = <20>;
+ qcom,freq-mitigation-value = <960000>;
+ qcom,freq-mitigation-control-mask = <0x01>;
qcom,vdd-restriction-temp = <5>;
qcom,vdd-restriction-temp-hysteresis = <10>;
qcom,pmic-sw-mode-temp = <85>;
diff --git a/arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts b/arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts
index fa313bf..6b62391 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts
@@ -22,5 +22,5 @@
};
&sdhc_1 {
- qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+ qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
};
diff --git a/arch/arm/boot/dts/msm8974pro-ion.dtsi b/arch/arm/boot/dts/msm8974pro-ion.dtsi
index 4c427bf..3bb885a 100644
--- a/arch/arm/boot/dts/msm8974pro-ion.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-ion.dtsi
@@ -18,6 +18,7 @@
reg = <23>;
qcom,heap-align = <0x1000>;
qcom,memory-fixed = <0x05a00000 0x2100000>;
+ qcom,ion-heap-type = "CARVEOUT";
};
qcom,ion-heap@26 { /* MODEM HEAP */
@@ -25,6 +26,7 @@
reg = <26>;
qcom,heap-align = <0x1000>;
qcom,memory-fixed = <0x08000000 0x5000000>;
+ qcom,ion-heap-type = "CARVEOUT";
};
};
};
diff --git a/arch/arm/boot/dts/msm8974pro-pm.dtsi b/arch/arm/boot/dts/msm8974pro-pm.dtsi
index 9e1f83f..63cb68b 100644
--- a/arch/arm/boot/dts/msm8974pro-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pm.dtsi
@@ -128,60 +128,69 @@
qcom,lpm-levels {
compatible = "qcom,lpm-levels";
+ qcom,allow-synced-levels;
qcom,default-l2-state = "l2_cache_retention";
#address-cells = <1>;
- #size-cells = <0>;
+ #size-cells = <1>;
- qcom,lpm-level@0 {
- reg = <0x0>;
- qcom,mode = "wfi";
- qcom,l2 = "l2_cache_retention";
- qcom,latency-us = <1>;
- qcom,ss-power = <715>;
- qcom,energy-overhead = <17700>;
- qcom,time-overhead = <2>;
+ qcom,cpu-modes {
+ compatible = "qcom,cpu-modes";
+ qcom,cpu-mode@0 {
+ qcom,mode = "wfi";
+ qcom,latency-us = <1>;
+ qcom,ss-power = <715>;
+ qcom,energy-overhead = <17700>;
+ qcom,time-overhead = <2>;
+ };
+
+ qcom,cpu-mode@1 {
+ qcom,mode = "retention";
+ qcom,latency-us = <35>;
+ qcom,ss-power = <542>;
+ qcom,energy-overhead = <34920>;
+ qcom,time-overhead = <40>;
+ };
+
+ qcom,cpu-mode@2 {
+ qcom,mode = "standalone_pc";
+ qcom,latency-us = <300>;
+ qcom,ss-power = <476>;
+ qcom,energy-overhead = <225300>;
+ qcom,time-overhead = <350>;
+ };
+
+ qcom,cpu-mode@3 {
+ qcom,mode = "pc";
+ qcom,latency-us = <500>;
+ qcom,ss-power = <400>;
+ qcom,energy-overhead = <280000>;
+ qcom,time-overhead = <500>;
+ qcom,use-broadcast-timer;
+ };
+
};
+ qcom,system-modes {
+ compatible = "qcom,system-modes";
- qcom,lpm-level@1 {
- reg = <0x1>;
- qcom,mode = "retention";
- qcom,l2 = "l2_cache_retention";
- qcom,latency-us = <35>;
- qcom,ss-power = <542>;
- qcom,energy-overhead = <34920>;
- qcom,time-overhead = <40>;
- };
+ qcom,system-mode@0 {
+ qcom,l2 = "l2_cache_gdhs";
+ qcom,latency-us = <20000>;
+ qcom,ss-power = <163>;
+ qcom,energy-overhead = <1577736>;
+ qcom,time-overhead = <5067>;
+ qcom,min-cpu-mode= "pc";
+ qcom,sync-cpus;
+ };
-
- qcom,lpm-level@2 {
- reg = <0x2>;
- qcom,mode = "standalone_pc";
- qcom,l2 = "l2_cache_retention";
- qcom,latency-us = <300>;
- qcom,ss-power = <476>;
- qcom,energy-overhead = <225300>;
- qcom,time-overhead = <350>;
- };
-
- qcom,lpm-level@3 {
- reg = <0x3>;
- qcom,mode = "pc";
- qcom,l2 = "l2_cache_gdhs";
- qcom,gpio-detectable;
- qcom,latency-us = <20000>;
- qcom,ss-power = <163>;
- qcom,energy-overhead = <1577736>;
- qcom,time-overhead = <5067>;
- };
-
- qcom,lpm-level@4 {
- reg = <0x4>;
- qcom,mode = "pc";
- qcom,l2 = "l2_cache_pc";
- qcom,latency-us = <30000>;
- qcom,ss-power = <83>;
- qcom,energy-overhead = <2274420>;
- qcom,time-overhead = <6605>;
+ qcom,system-mode@1 {
+ qcom,l2 = "l2_cache_pc";
+ qcom,latency-us = <30000>;
+ qcom,ss-power = <83>;
+ qcom,energy-overhead = <2274420>;
+ qcom,time-overhead = <6605>;
+ qcom,min-cpu-mode = "pc";
+ qcom,sync-cpus;
+ };
};
};
@@ -205,6 +214,13 @@
<50 172>, /* usb1_hs_async_wakeup_irq */
<53 104>, /* mdss_irq */
<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
+ <0xff 18>, /* APCx_qgicQTmrSecPhysIrptReq */
+ <0xff 19>, /* APCx_qgicQTmrSecPhysIrptReq */
+ <0xff 25>, /* APCx_qgicExtFaultIrptReq */
+ <0xff 33>, /*l2_perf_mon*/
+ <0xff 34>, /* APCC_qgicL2ErrorIrptReq */
+ <0xff 35>, /* WDT_barkInt */
+ <0xff 40>, /* qtimer_phy_irq */
<0xff 56>, /* modem_watchdog */
<0xff 57>, /* mss_to_apps_irq(0) */
<0xff 58>, /* mss_to_apps_irq(1) */
@@ -212,8 +228,24 @@
<0xff 60>, /* mss_to_apps_irq(3) */
<0xff 61>, /* mss_a2_bam_irq */
<0xff 70>, /* iommu_pmon_nonsecure_irq */
+ <0xff 74>, /* osmmu_CIrpt[1] */
+ <0xff 75>, /* osmmu_CIrpt[0] */
+ <0xff 77>, /* osmmu_CIrpt[0] */
+ <0xff 78>, /* osmmu_CIrpt[0] */
+ <0xff 79>, /* osmmu_CIrpt[0] */
+ <0xff 94>, /* osmmu_CIrpt[0] */
<0xff 97>, /* iommu_nonsecure_irq */
+ <0xff 99>, /* msm_iommu_pmon_nonsecure_irq */
+ <0xff 102>, /* osmmu_CIrpt[1] */
<0xff 105>, /* iommu_pmon_nonsecure_irq */
+ <0xff 109>, /* ocmem_dm_nonsec_irq */
+ <0xff 126>, /* bam_irq[0] */
+ <0xff 140>, /* uart_dm_intr */
+ <0xff 155>, /* sdcc_irq[0] */
+ <0xff 157>, /* sdcc_irq[0] */
+ <0xff 159>, /* sdcc_irq[0] */
+ <0xff 163>, /* usb30_ee1_irq */
+ <0xff 170>, /* sdcc_pwr_cmd_irq */
<0xff 173>, /* o_wcss_apss_smd_hi */
<0xff 174>, /* o_wcss_apss_smd_med */
<0xff 175>, /* o_wcss_apss_smd_low */
@@ -233,6 +265,7 @@
<0xff 195>, /* lpass_irq_out_apcs(7) */
<0xff 196>, /* lpass_irq_out_apcs(8) */
<0xff 197>, /* lpass_irq_out_apcs(9) */
+ <0xff 198>, /* coresight-tmc-etr interrupt */
<0xff 200>, /* rpm_ipc(4) */
<0xff 201>, /* rpm_ipc(5) */
<0xff 202>, /* rpm_ipc(6) */
@@ -242,7 +275,12 @@
<0xff 206>, /* rpm_ipc(26) */
<0xff 207>, /* rpm_ipc(27) */
<0xff 211>, /* usb_dwc3_otg */
- <0xff 240>; /* summary_irq_kpss */
+ <0xff 240>, /* summary_irq_kpss */
+ <0xff 253>, /* sdcc_pwr_cmd_irq */
+ <0xff 256>, /* sdcc_pwr_cmd_irq */
+ <0xff 268>, /* bam_irq[1] */
+ <0xff 270>, /* bam_irq[0] */
+ <0xff 271>; /* bam_irq[0] */
qcom,gpio-parent = <&msmgpio>;
qcom,gpio-map = <3 102>,
@@ -293,7 +331,6 @@
ranges;
reg = <0xfe805664 0x40>;
qcom,pc-mode = "tz_l2_int";
- qcom,use-sync-timer;
qcom,cpus-as-clocks;
qcom,pm-snoc-client {
diff --git a/arch/arm/boot/dts/msm8974pro-pm8941.dtsi b/arch/arm/boot/dts/msm8974pro-pm8941.dtsi
index 2c06c3c..8b13c9f 100644
--- a/arch/arm/boot/dts/msm8974pro-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pm8941.dtsi
@@ -38,28 +38,32 @@
&krait0_vreg {
regulator-max-microvolt = <1120000>;
- qcom,ldo-delta-voltage = <25000>;
+ qcom,ldo-delta-voltage = <12500>;
};
&krait1_vreg {
regulator-max-microvolt = <1120000>;
- qcom,ldo-delta-voltage = <25000>;
+ qcom,ldo-delta-voltage = <12500>;
};
&krait2_vreg {
regulator-max-microvolt = <1120000>;
- qcom,ldo-delta-voltage = <25000>;
+ qcom,ldo-delta-voltage = <12500>;
};
&krait3_vreg {
regulator-max-microvolt = <1120000>;
- qcom,ldo-delta-voltage = <25000>;
+ qcom,ldo-delta-voltage = <12500>;
};
&tspp {
vdd_cx-supply = <&pm8841_s2_corner>;
};
+&pm8841_s2_corner {
+ qcom,init-smps-mode = <0>; /* Allow AUTO mode for VDD_CX. */
+};
+
&krait_regulator_pmic {
status = "ok";
diff --git a/arch/arm/boot/dts/msm8974pro-pma8084-mtp.dtsi b/arch/arm/boot/dts/msm8974pro-pma8084-mtp.dtsi
old mode 100644
new mode 100755
index d5c1143..a22d806
--- a/arch/arm/boot/dts/msm8974pro-pma8084-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pma8084-mtp.dtsi
@@ -63,6 +63,20 @@
};
};
+ i2c@f9928000 { /* BLSP1 QUP6 */
+ nfc-nci@e {
+ compatible = "qcom,nfc-nci";
+ reg = <0x0e>;
+ qcom,irq-gpio = <&msmgpio 59 0x00>;
+ qcom,dis-gpio = <&pma8084_mpps 7 0>;
+ qcom,clk-src = "BBCLK2";
+ qcom,clk-en-gpio = <&msmgpio 0 0x00>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <59 0>;
+ qcom,clk-gpio = <&pma8084_gpios 10 0>;
+ };
+ };
+
qcom,ssusb@f9200000 {
vbus_dwc3-supply = <&pm8941_mvs1>;
};
@@ -173,9 +187,11 @@
};
gpio@c900 { /* GPIO 10 */
- /* NFC clock request */
- qcom,mode = <0>; /* Digital input */
- qcom,pull = <4>; /* Pull down */
+ /* NFC clk request */
+ qcom,mode = <0>; /* QPNP_PIN_MODE_DIG_IN */
+ qcom,pull = <5>; /* QPNP_PIN_PULL_NO */
+ qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
+ qcom,src-sel = <2>; /* QPNP_PIN_SEL_FUNC_1 */
qcom,master-en = <1>;
};
@@ -188,10 +204,11 @@
};
gpio@cb00 { /* GPIO 12 */
- /* Unused */
- qcom,mode = <1>; /* Digital output */
- qcom,out-strength = <1>; /* Low */
- qcom,src-sel = <2>; /* Function 1 */
+ /* NFC clk request */
+ qcom,mode = <0>; /* QPNP_PIN_MODE_DIG_IN */
+ qcom,pull = <5>; /* QPNP_PIN_PULL_NO */
+ qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
+ qcom,src-sel = <2>; /* QPNP_PIN_SEL_FUNC_1 */
qcom,master-en = <1>;
};
diff --git a/arch/arm/boot/dts/msm8974pro-pma8084-regulator.dtsi b/arch/arm/boot/dts/msm8974pro-pma8084-regulator.dtsi
index 00e3b8b..79d7412 100644
--- a/arch/arm/boot/dts/msm8974pro-pma8084-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pma8084-regulator.dtsi
@@ -494,7 +494,7 @@
qcom,retention-voltage = <675000>;
qcom,ldo-default-voltage = <750000>;
qcom,ldo-threshold-voltage = <850000>;
- qcom,ldo-delta-voltage = <25000>;
+ qcom,ldo-delta-voltage = <12500>;
qcom,cpu-num = <0>;
};
@@ -510,7 +510,7 @@
qcom,retention-voltage = <675000>;
qcom,ldo-default-voltage = <750000>;
qcom,ldo-threshold-voltage = <850000>;
- qcom,ldo-delta-voltage = <25000>;
+ qcom,ldo-delta-voltage = <12500>;
qcom,cpu-num = <1>;
};
@@ -526,7 +526,7 @@
qcom,retention-voltage = <675000>;
qcom,ldo-default-voltage = <750000>;
qcom,ldo-threshold-voltage = <850000>;
- qcom,ldo-delta-voltage = <25000>;
+ qcom,ldo-delta-voltage = <12500>;
qcom,cpu-num = <2>;
};
@@ -542,7 +542,7 @@
qcom,retention-voltage = <675000>;
qcom,ldo-default-voltage = <750000>;
qcom,ldo-threshold-voltage = <850000>;
- qcom,ldo-delta-voltage = <25000>;
+ qcom,ldo-delta-voltage = <12500>;
qcom,cpu-num = <3>;
};
};
diff --git a/arch/arm/boot/dts/msm8974pro-pma8084.dtsi b/arch/arm/boot/dts/msm8974pro-pma8084.dtsi
index cd485c5..c06ebf8 100644
--- a/arch/arm/boot/dts/msm8974pro-pma8084.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pma8084.dtsi
@@ -100,20 +100,10 @@
};
};
- qcom,acpuclk@f9000000 {
- krait0_mem-supply = <&pma8084_s1_ao>;
- krait1_mem-supply = <&pma8084_s1_ao>;
- krait2_mem-supply = <&pma8084_s1_ao>;
- krait3_mem-supply = <&pma8084_s1_ao>;
- krait0_dig-supply = <&pma8084_s2_corner_ao>;
- krait1_dig-supply = <&pma8084_s2_corner_ao>;
- krait2_dig-supply = <&pma8084_s2_corner_ao>;
- krait3_dig-supply = <&pma8084_s2_corner_ao>;
- krait0_hfpll-supply = <&pma8084_l12_ao>;
- krait1_hfpll-supply = <&pma8084_l12_ao>;
- krait2_hfpll-supply = <&pma8084_l12_ao>;
- krait3_hfpll-supply = <&pma8084_l12_ao>;
- l2_hfpll-supply = <&pma8084_l12_ao>;
+ qcom,clock-krait@f9016000 {
+ l2-dig-supply = <&pma8084_s2_corner_ao>;
+ hfpll-dig-supply = <&pma8084_s2_corner_ao>;
+ hfpll-analog-supply = <&pma8084_l12_ao>;
};
qcom,ssusb@f9200000 {
@@ -162,6 +152,9 @@
qcom,msm-thermal {
vdd-dig-supply = <&pma8084_s2_floor_corner>;
vdd-gfx-supply = <&pma8084_s7_floor_corner>;
+ qti,pmic-opt-curr-temp = <85>;
+ qti,pmic-opt-curr-temp-hysteresis = <10>;
+ qti,pmic-opt-curr-regs = "vdd-dig";
/delete-property/ qcom,pmic-sw-mode-temp;
/delete-property/ qcom,pmic-sw-mode-temp-hysteresis;
/delete-property/ qcom,pmic-sw-mode-regs;
@@ -190,10 +183,18 @@
qcom,use-phase-switching;
};
+&mdss_mdp {
+ vdd-cx-supply = <&pma8084_s2_corner>;
+};
+
&tspp {
vdd_cx-supply = <&pma8084_s2_corner>;
};
+&pma8084_s2_corner {
+ qcom,init-smps-mode = <0>; /* Allow AUTO mode for VDD_CX. */
+};
+
&krait_regulator_pmic {
status = "ok";
diff --git a/arch/arm/boot/dts/msm8974pro.dtsi b/arch/arm/boot/dts/msm8974pro.dtsi
old mode 100644
new mode 100755
index 6d5c862..b670cfd
--- a/arch/arm/boot/dts/msm8974pro.dtsi
+++ b/arch/arm/boot/dts/msm8974pro.dtsi
@@ -39,29 +39,1572 @@
/delete-property/ qcom,pmic-sw-mode-temp-hysteresis;
/delete-property/ qcom,pmic-sw-mode-regs;
};
+
+ sound {
+ reg = <0xfe02c000 0x4>,
+ <0xfe02d000 0x4>,
+ <0xfe02e000 0x4>,
+ <0xfe02f000 0x4>;
+ reg-names = "lpaif_pri_mode_muxsel",
+ "lpaif_sec_mode_muxsel",
+ "lpaif_tert_mode_muxsel",
+ "lpaif_quat_mode_muxsel";
+ };
+
+ qcom,clock-krait@f9016000 {
+ qcom,speed1-pvs0-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 775000 74 >,
+ < 345600000 775000 85 >,
+ < 422400000 775000 104 >,
+ < 499200000 780000 124 >,
+ < 576000000 790000 144 >,
+ < 652800000 800000 164 >,
+ < 729600000 810000 184 >,
+ < 806400000 820000 206 >,
+ < 883200000 830000 227 >,
+ < 960000000 840000 249 >,
+ < 1036800000 850000 271 >,
+ < 1113600000 865000 295 >,
+ < 1190400000 875000 318 >,
+ < 1267200000 890000 342 >,
+ < 1344000000 900000 365 >,
+ < 1420800000 915000 392 >,
+ < 1497600000 925000 416 >,
+ < 1574400000 940000 442 >,
+ < 1651200000 955000 469 >,
+ < 1728000000 970000 497 >,
+ < 1804800000 985000 525 >,
+ < 1881600000 1000000 554 >,
+ < 1958400000 1015000 583 >,
+ < 2035200000 1030000 613 >,
+ < 2112000000 1045000 642 >,
+ < 2150400000 1060000 663 >,
+ < 2188800000 1060000 675 >,
+ < 2265600000 1075000 708 >;
+
+ qcom,speed1-pvs1-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 775000 74 >,
+ < 345600000 775000 85 >,
+ < 422400000 775000 104 >,
+ < 499200000 775000 124 >,
+ < 576000000 775000 144 >,
+ < 652800000 785000 164 >,
+ < 729600000 795000 184 >,
+ < 806400000 805000 206 >,
+ < 883200000 815000 227 >,
+ < 960000000 825000 249 >,
+ < 1036800000 835000 271 >,
+ < 1113600000 850000 295 >,
+ < 1190400000 860000 318 >,
+ < 1267200000 870000 342 >,
+ < 1344000000 885000 365 >,
+ < 1420800000 895000 392 >,
+ < 1497600000 905000 416 >,
+ < 1574400000 920000 442 >,
+ < 1651200000 935000 469 >,
+ < 1728000000 950000 497 >,
+ < 1804800000 965000 525 >,
+ < 1881600000 980000 554 >,
+ < 1958400000 995000 583 >,
+ < 2035200000 1005000 613 >,
+ < 2112000000 1020000 642 >,
+ < 2150400000 1035000 663 >,
+ < 2188800000 1035000 675 >,
+ < 2265600000 1050000 708 >;
+
+ qcom,speed1-pvs2-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 750000 74 >,
+ < 345600000 750000 85 >,
+ < 422400000 750000 104 >,
+ < 499200000 750000 124 >,
+ < 576000000 760000 144 >,
+ < 652800000 770000 164 >,
+ < 729600000 780000 184 >,
+ < 806400000 790000 206 >,
+ < 883200000 800000 227 >,
+ < 960000000 810000 249 >,
+ < 1036800000 820000 271 >,
+ < 1113600000 830000 295 >,
+ < 1190400000 840000 318 >,
+ < 1267200000 850000 342 >,
+ < 1344000000 865000 365 >,
+ < 1420800000 875000 392 >,
+ < 1497600000 885000 416 >,
+ < 1574400000 900000 442 >,
+ < 1651200000 915000 469 >,
+ < 1728000000 930000 497 >,
+ < 1804800000 945000 525 >,
+ < 1881600000 955000 554 >,
+ < 1958400000 970000 583 >,
+ < 2035200000 980000 613 >,
+ < 2112000000 995000 642 >,
+ < 2150400000 1010000 663 >,
+ < 2188800000 1010000 675 >,
+ < 2265600000 1025000 708 >;
+
+ qcom,speed1-pvs3-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 750000 74 >,
+ < 345600000 750000 85 >,
+ < 422400000 750000 104 >,
+ < 499200000 750000 124 >,
+ < 576000000 750000 144 >,
+ < 652800000 755000 164 >,
+ < 729600000 765000 184 >,
+ < 806400000 775000 206 >,
+ < 883200000 785000 227 >,
+ < 960000000 795000 249 >,
+ < 1036800000 805000 271 >,
+ < 1113600000 815000 295 >,
+ < 1190400000 825000 318 >,
+ < 1267200000 835000 342 >,
+ < 1344000000 850000 365 >,
+ < 1420800000 860000 392 >,
+ < 1497600000 870000 416 >,
+ < 1574400000 885000 442 >,
+ < 1651200000 900000 469 >,
+ < 1728000000 910000 497 >,
+ < 1804800000 925000 525 >,
+ < 1881600000 935000 554 >,
+ < 1958400000 945000 583 >,
+ < 2035200000 960000 613 >,
+ < 2112000000 970000 642 >,
+ < 2150400000 985000 663 >,
+ < 2188800000 985000 675 >,
+ < 2265600000 1000000 708 >;
+
+ qcom,speed1-pvs4-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 750000 74 >,
+ < 345600000 750000 85 >,
+ < 422400000 750000 104 >,
+ < 499200000 750000 124 >,
+ < 576000000 750000 144 >,
+ < 652800000 750000 164 >,
+ < 729600000 755000 184 >,
+ < 806400000 765000 206 >,
+ < 883200000 775000 227 >,
+ < 960000000 785000 249 >,
+ < 1036800000 795000 271 >,
+ < 1113600000 805000 295 >,
+ < 1190400000 815000 318 >,
+ < 1267200000 825000 342 >,
+ < 1344000000 835000 365 >,
+ < 1420800000 845000 392 >,
+ < 1497600000 855000 416 >,
+ < 1574400000 870000 442 >,
+ < 1651200000 885000 469 >,
+ < 1728000000 895000 497 >,
+ < 1804800000 905000 525 >,
+ < 1881600000 915000 554 >,
+ < 1958400000 925000 583 >,
+ < 2035200000 935000 613 >,
+ < 2112000000 950000 642 >,
+ < 2150400000 960000 663 >,
+ < 2188800000 960000 675 >,
+ < 2265600000 975000 708 >;
+
+ qcom,speed1-pvs5-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 725000 74 >,
+ < 345600000 725000 85 >,
+ < 422400000 725000 104 >,
+ < 499200000 725000 124 >,
+ < 576000000 725000 144 >,
+ < 652800000 735000 164 >,
+ < 729600000 745000 184 >,
+ < 806400000 755000 206 >,
+ < 883200000 765000 227 >,
+ < 960000000 775000 249 >,
+ < 1036800000 785000 271 >,
+ < 1113600000 795000 295 >,
+ < 1190400000 805000 318 >,
+ < 1267200000 815000 342 >,
+ < 1344000000 825000 365 >,
+ < 1420800000 835000 392 >,
+ < 1497600000 845000 416 >,
+ < 1574400000 855000 442 >,
+ < 1651200000 865000 469 >,
+ < 1728000000 875000 497 >,
+ < 1804800000 885000 525 >,
+ < 1881600000 895000 554 >,
+ < 1958400000 905000 583 >,
+ < 2035200000 915000 613 >,
+ < 2112000000 930000 642 >,
+ < 2150400000 940000 663 >,
+ < 2188800000 940000 675 >,
+ < 2265600000 950000 708 >;
+
+ qcom,speed1-pvs6-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 725000 74 >,
+ < 345600000 725000 85 >,
+ < 422400000 725000 104 >,
+ < 499200000 725000 124 >,
+ < 576000000 725000 144 >,
+ < 652800000 725000 164 >,
+ < 729600000 735000 184 >,
+ < 806400000 745000 206 >,
+ < 883200000 755000 227 >,
+ < 960000000 765000 249 >,
+ < 1036800000 775000 271 >,
+ < 1113600000 785000 295 >,
+ < 1190400000 795000 318 >,
+ < 1267200000 805000 342 >,
+ < 1344000000 815000 365 >,
+ < 1420800000 825000 392 >,
+ < 1497600000 835000 416 >,
+ < 1574400000 845000 442 >,
+ < 1651200000 850000 469 >,
+ < 1728000000 860000 497 >,
+ < 1804800000 870000 525 >,
+ < 1881600000 880000 554 >,
+ < 1958400000 890000 583 >,
+ < 2035200000 895000 613 >,
+ < 2112000000 905000 642 >,
+ < 2150400000 915000 663 >,
+ < 2188800000 915000 675 >,
+ < 2265600000 925000 708 >;
+
+ qcom,speed3-pvs0-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 800000 76 >,
+ < 345600000 800000 87 >,
+ < 422400000 800000 106 >,
+ < 499200000 800000 125 >,
+ < 576000000 800000 145 >,
+ < 652800000 810000 165 >,
+ < 729600000 820000 186 >,
+ < 806400000 830000 208 >,
+ < 883200000 840000 229 >,
+ < 960000000 850000 251 >,
+ < 1036800000 860000 273 >,
+ < 1113600000 870000 296 >,
+ < 1190400000 880000 319 >,
+ < 1267200000 890000 342 >,
+ < 1344000000 900000 365 >,
+ < 1420800000 910000 390 >,
+ < 1497600000 920000 415 >,
+ < 1574400000 930000 439 >,
+ < 1651200000 945000 465 >,
+ < 1728000000 960000 493 >,
+ < 1804800000 975000 521 >,
+ < 1881600000 990000 549 >,
+ < 1958400000 1005000 579 >,
+ < 2035200000 1020000 608 >,
+ < 2112000000 1035000 638 >,
+ < 2150400000 1050000 667 >,
+ < 2188800000 1050000 667 >,
+ < 2265600000 1065000 700 >,
+ < 2342400000 1080000 734 >,
+ < 2419200000 1095000 769 >,
+ < 2457600000 1100000 785 >;
+
+ qcom,speed3-pvs1-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 800000 76 >,
+ < 345600000 800000 87 >,
+ < 422400000 800000 106 >,
+ < 499200000 800000 125 >,
+ < 576000000 800000 145 >,
+ < 652800000 800000 165 >,
+ < 729600000 800000 186 >,
+ < 806400000 805000 208 >,
+ < 883200000 815000 229 >,
+ < 960000000 825000 251 >,
+ < 1036800000 835000 273 >,
+ < 1113600000 845000 296 >,
+ < 1190400000 855000 319 >,
+ < 1267200000 865000 342 >,
+ < 1344000000 875000 365 >,
+ < 1420800000 885000 390 >,
+ < 1497600000 895000 415 >,
+ < 1574400000 905000 439 >,
+ < 1651200000 920000 465 >,
+ < 1728000000 935000 493 >,
+ < 1804800000 950000 521 >,
+ < 1881600000 965000 549 >,
+ < 1958400000 980000 579 >,
+ < 2035200000 995000 608 >,
+ < 2112000000 1010000 638 >,
+ < 2150400000 1025000 667 >,
+ < 2188800000 1025000 667 >,
+ < 2265600000 1040000 700 >,
+ < 2342400000 1055000 734 >,
+ < 2419200000 1070000 769 >,
+ < 2457600000 1075000 785 >;
+
+ qcom,speed3-pvs2-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 775000 76 >,
+ < 345600000 775000 87 >,
+ < 422400000 775000 106 >,
+ < 499200000 775000 125 >,
+ < 576000000 775000 145 >,
+ < 652800000 775000 165 >,
+ < 729600000 775000 186 >,
+ < 806400000 780000 208 >,
+ < 883200000 790000 229 >,
+ < 960000000 800000 251 >,
+ < 1036800000 810000 273 >,
+ < 1113600000 820000 296 >,
+ < 1190400000 830000 319 >,
+ < 1267200000 840000 342 >,
+ < 1344000000 850000 365 >,
+ < 1420800000 860000 390 >,
+ < 1497600000 870000 415 >,
+ < 1574400000 880000 439 >,
+ < 1651200000 895000 465 >,
+ < 1728000000 910000 493 >,
+ < 1804800000 925000 521 >,
+ < 1881600000 940000 549 >,
+ < 1958400000 955000 579 >,
+ < 2035200000 970000 608 >,
+ < 2112000000 985000 638 >,
+ < 2150400000 1000000 667 >,
+ < 2188800000 1000000 667 >,
+ < 2265600000 1015000 700 >,
+ < 2342400000 1030000 734 >,
+ < 2419200000 1045000 769 >,
+ < 2457600000 1050000 785 >;
+
+ qcom,speed3-pvs3-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 775000 76 >,
+ < 345600000 775000 87 >,
+ < 422400000 775000 106 >,
+ < 499200000 775000 125 >,
+ < 576000000 775000 145 >,
+ < 652800000 775000 165 >,
+ < 729600000 775000 186 >,
+ < 806400000 775000 208 >,
+ < 883200000 775000 229 >,
+ < 960000000 780000 251 >,
+ < 1036800000 785000 273 >,
+ < 1113600000 795000 296 >,
+ < 1190400000 805000 319 >,
+ < 1267200000 815000 342 >,
+ < 1344000000 825000 365 >,
+ < 1420800000 835000 390 >,
+ < 1497600000 845000 415 >,
+ < 1574400000 855000 439 >,
+ < 1651200000 870000 465 >,
+ < 1728000000 885000 493 >,
+ < 1804800000 900000 521 >,
+ < 1881600000 915000 549 >,
+ < 1958400000 930000 579 >,
+ < 2035200000 945000 608 >,
+ < 2112000000 960000 638 >,
+ < 2150400000 975000 667 >,
+ < 2188800000 975000 667 >,
+ < 2265600000 990000 700 >,
+ < 2342400000 1005000 734 >,
+ < 2419200000 1020000 769 >,
+ < 2457600000 1025000 785 >;
+
+ qcom,speed3-pvs4-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 775000 76 >,
+ < 345600000 775000 87 >,
+ < 422400000 775000 106 >,
+ < 499200000 775000 125 >,
+ < 576000000 775000 145 >,
+ < 652800000 775000 165 >,
+ < 729600000 775000 186 >,
+ < 806400000 775000 208 >,
+ < 883200000 775000 229 >,
+ < 960000000 775000 251 >,
+ < 1036800000 775000 273 >,
+ < 1113600000 775000 296 >,
+ < 1190400000 780000 319 >,
+ < 1267200000 790000 342 >,
+ < 1344000000 800000 365 >,
+ < 1420800000 810000 390 >,
+ < 1497600000 820000 415 >,
+ < 1574400000 830000 439 >,
+ < 1651200000 845000 465 >,
+ < 1728000000 860000 493 >,
+ < 1804800000 875000 521 >,
+ < 1881600000 890000 549 >,
+ < 1958400000 905000 579 >,
+ < 2035200000 920000 608 >,
+ < 2112000000 935000 638 >,
+ < 2150400000 950000 667 >,
+ < 2188800000 950000 667 >,
+ < 2265600000 965000 700 >,
+ < 2342400000 980000 734 >,
+ < 2419200000 995000 769 >,
+ < 2457600000 1000000 785 >;
+
+ qcom,speed3-pvs5-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 750000 76 >,
+ < 345600000 750000 87 >,
+ < 422400000 750000 106 >,
+ < 499200000 750000 125 >,
+ < 576000000 750000 145 >,
+ < 652800000 750000 165 >,
+ < 729600000 750000 186 >,
+ < 806400000 750000 208 >,
+ < 883200000 750000 229 >,
+ < 960000000 750000 251 >,
+ < 1036800000 750000 273 >,
+ < 1113600000 750000 296 >,
+ < 1190400000 760000 319 >,
+ < 1267200000 770000 342 >,
+ < 1344000000 780000 365 >,
+ < 1420800000 790000 390 >,
+ < 1497600000 800000 415 >,
+ < 1574400000 810000 439 >,
+ < 1651200000 820000 465 >,
+ < 1728000000 835000 493 >,
+ < 1804800000 850000 521 >,
+ < 1881600000 865000 549 >,
+ < 1958400000 880000 579 >,
+ < 2035200000 895000 608 >,
+ < 2112000000 910000 638 >,
+ < 2150400000 925000 667 >,
+ < 2188800000 925000 667 >,
+ < 2265600000 940000 700 >,
+ < 2342400000 955000 734 >,
+ < 2419200000 970000 769 >,
+ < 2457600000 975000 785 >;
+
+ qcom,speed3-pvs6-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 750000 76 >,
+ < 345600000 750000 87 >,
+ < 422400000 750000 106 >,
+ < 499200000 750000 125 >,
+ < 576000000 750000 145 >,
+ < 652800000 750000 165 >,
+ < 729600000 750000 186 >,
+ < 806400000 750000 208 >,
+ < 883200000 750000 229 >,
+ < 960000000 750000 251 >,
+ < 1036800000 750000 273 >,
+ < 1113600000 750000 296 >,
+ < 1190400000 750000 319 >,
+ < 1267200000 755000 342 >,
+ < 1344000000 765000 365 >,
+ < 1420800000 775000 390 >,
+ < 1497600000 785000 415 >,
+ < 1574400000 795000 439 >,
+ < 1651200000 805000 465 >,
+ < 1728000000 815000 493 >,
+ < 1804800000 825000 521 >,
+ < 1881600000 840000 549 >,
+ < 1958400000 855000 579 >,
+ < 2035200000 870000 608 >,
+ < 2112000000 885000 638 >,
+ < 2150400000 900000 667 >,
+ < 2188800000 900000 667 >,
+ < 2265600000 915000 700 >,
+ < 2342400000 930000 734 >,
+ < 2419200000 945000 769 >,
+ < 2457600000 950000 785 >;
+
+ qcom,speed1-pvs0-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 800000 76 >,
+ < 345600000 810000 87 >,
+ < 422400000 820000 108 >,
+ < 499200000 830000 129 >,
+ < 576000000 840000 150 >,
+ < 652800000 850000 171 >,
+ < 729600000 860000 193 >,
+ < 806400000 870000 215 >,
+ < 883200000 880000 237 >,
+ < 960000000 890000 260 >,
+ < 1036800000 900000 282 >,
+ < 1113600000 910000 306 >,
+ < 1190400000 920000 330 >,
+ < 1267200000 930000 354 >,
+ < 1344000000 940000 378 >,
+ < 1420800000 955000 404 >,
+ < 1497600000 970000 431 >,
+ < 1574400000 985000 458 >,
+ < 1651200000 1000000 486 >,
+ < 1728000000 1015000 515 >,
+ < 1804800000 1030000 543 >,
+ < 1881600000 1045000 572 >,
+ < 1958400000 1060000 604 >,
+ < 2035200000 1075000 636 >,
+ < 2112000000 1090000 669 >,
+ < 2150400000 1105000 703 >,
+ < 2188800000 1105000 703 >,
+ < 2265600000 1120000 738 >;
+
+ qcom,speed1-pvs1-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 800000 76 >,
+ < 345600000 800000 87 >,
+ < 422400000 810000 108 >,
+ < 499200000 820000 129 >,
+ < 576000000 830000 150 >,
+ < 652800000 840000 171 >,
+ < 729600000 850000 193 >,
+ < 806400000 860000 215 >,
+ < 883200000 870000 237 >,
+ < 960000000 880000 260 >,
+ < 1036800000 890000 282 >,
+ < 1113600000 900000 306 >,
+ < 1190400000 910000 330 >,
+ < 1267200000 920000 354 >,
+ < 1344000000 930000 378 >,
+ < 1420800000 945000 404 >,
+ < 1497600000 960000 431 >,
+ < 1574400000 975000 458 >,
+ < 1651200000 990000 486 >,
+ < 1728000000 1005000 515 >,
+ < 1804800000 1020000 543 >,
+ < 1881600000 1035000 572 >,
+ < 1958400000 1050000 604 >,
+ < 2035200000 1065000 636 >,
+ < 2112000000 1080000 669 >,
+ < 2150400000 1095000 703 >,
+ < 2188800000 1095000 703 >,
+ < 2265600000 1110000 738 >;
+
+ qcom,speed1-pvs2-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 800000 76 >,
+ < 345600000 800000 87 >,
+ < 422400000 800000 108 >,
+ < 499200000 810000 129 >,
+ < 576000000 820000 150 >,
+ < 652800000 830000 171 >,
+ < 729600000 840000 193 >,
+ < 806400000 850000 215 >,
+ < 883200000 860000 237 >,
+ < 960000000 870000 260 >,
+ < 1036800000 880000 282 >,
+ < 1113600000 890000 306 >,
+ < 1190400000 900000 330 >,
+ < 1267200000 910000 354 >,
+ < 1344000000 920000 378 >,
+ < 1420800000 935000 404 >,
+ < 1497600000 950000 431 >,
+ < 1574400000 965000 458 >,
+ < 1651200000 980000 486 >,
+ < 1728000000 995000 515 >,
+ < 1804800000 1010000 543 >,
+ < 1881600000 1025000 572 >,
+ < 1958400000 1040000 604 >,
+ < 2035200000 1055000 636 >,
+ < 2112000000 1070000 669 >,
+ < 2150400000 1085000 703 >,
+ < 2188800000 1085000 703 >,
+ < 2265600000 1100000 738 >;
+
+ qcom,speed1-pvs3-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 800000 76 >,
+ < 345600000 800000 87 >,
+ < 422400000 800000 108 >,
+ < 499200000 800000 129 >,
+ < 576000000 810000 150 >,
+ < 652800000 820000 171 >,
+ < 729600000 830000 193 >,
+ < 806400000 840000 215 >,
+ < 883200000 850000 237 >,
+ < 960000000 860000 260 >,
+ < 1036800000 870000 282 >,
+ < 1113600000 880000 306 >,
+ < 1190400000 890000 330 >,
+ < 1267200000 900000 354 >,
+ < 1344000000 910000 378 >,
+ < 1420800000 925000 404 >,
+ < 1497600000 940000 431 >,
+ < 1574400000 955000 458 >,
+ < 1651200000 970000 486 >,
+ < 1728000000 985000 515 >,
+ < 1804800000 1000000 543 >,
+ < 1881600000 1015000 572 >,
+ < 1958400000 1030000 604 >,
+ < 2035200000 1045000 636 >,
+ < 2112000000 1060000 669 >,
+ < 2150400000 1075000 703 >,
+ < 2188800000 1075000 703 >,
+ < 2265600000 1090000 738 >;
+
+ qcom,speed1-pvs4-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 800000 76 >,
+ < 345600000 800000 87 >,
+ < 422400000 800000 108 >,
+ < 499200000 800000 129 >,
+ < 576000000 800000 150 >,
+ < 652800000 810000 171 >,
+ < 729600000 820000 193 >,
+ < 806400000 830000 215 >,
+ < 883200000 840000 237 >,
+ < 960000000 850000 260 >,
+ < 1036800000 860000 282 >,
+ < 1113600000 870000 306 >,
+ < 1190400000 880000 330 >,
+ < 1267200000 890000 354 >,
+ < 1344000000 900000 378 >,
+ < 1420800000 915000 404 >,
+ < 1497600000 930000 431 >,
+ < 1574400000 945000 458 >,
+ < 1651200000 960000 486 >,
+ < 1728000000 975000 515 >,
+ < 1804800000 990000 543 >,
+ < 1881600000 1005000 572 >,
+ < 1958400000 1020000 604 >,
+ < 2035200000 1035000 636 >,
+ < 2112000000 1050000 669 >,
+ < 2150400000 1065000 703 >,
+ < 2188800000 1065000 703 >,
+ < 2265600000 1080000 738 >;
+
+ qcom,speed1-pvs5-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 800000 76 >,
+ < 345600000 800000 87 >,
+ < 422400000 800000 108 >,
+ < 499200000 800000 129 >,
+ < 576000000 800000 150 >,
+ < 652800000 800000 171 >,
+ < 729600000 810000 193 >,
+ < 806400000 820000 215 >,
+ < 883200000 830000 237 >,
+ < 960000000 840000 260 >,
+ < 1036800000 850000 282 >,
+ < 1113600000 860000 306 >,
+ < 1190400000 870000 330 >,
+ < 1267200000 880000 354 >,
+ < 1344000000 890000 378 >,
+ < 1420800000 905000 404 >,
+ < 1497600000 920000 431 >,
+ < 1574400000 935000 458 >,
+ < 1651200000 950000 486 >,
+ < 1728000000 965000 515 >,
+ < 1804800000 980000 543 >,
+ < 1881600000 995000 572 >,
+ < 1958400000 1010000 604 >,
+ < 2035200000 1025000 636 >,
+ < 2112000000 1040000 669 >,
+ < 2150400000 1055000 703 >,
+ < 2188800000 1055000 703 >,
+ < 2265600000 1070000 738 >;
+
+ qcom,speed1-pvs6-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 775000 76 >,
+ < 345600000 775000 87 >,
+ < 422400000 775000 108 >,
+ < 499200000 775000 129 >,
+ < 576000000 780000 150 >,
+ < 652800000 790000 171 >,
+ < 729600000 800000 193 >,
+ < 806400000 810000 215 >,
+ < 883200000 820000 237 >,
+ < 960000000 830000 260 >,
+ < 1036800000 840000 282 >,
+ < 1113600000 850000 306 >,
+ < 1190400000 860000 330 >,
+ < 1267200000 870000 354 >,
+ < 1344000000 880000 378 >,
+ < 1420800000 895000 404 >,
+ < 1497600000 910000 431 >,
+ < 1574400000 925000 458 >,
+ < 1651200000 940000 486 >,
+ < 1728000000 955000 515 >,
+ < 1804800000 970000 543 >,
+ < 1881600000 985000 572 >,
+ < 1958400000 1000000 604 >,
+ < 2035200000 1015000 636 >,
+ < 2112000000 1030000 669 >,
+ < 2150400000 1045000 703 >,
+ < 2188800000 1045000 703 >,
+ < 2265600000 1060000 738 >;
+
+ qcom,speed1-pvs7-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 775000 76 >,
+ < 345600000 775000 87 >,
+ < 422400000 775000 108 >,
+ < 499200000 775000 129 >,
+ < 576000000 775000 150 >,
+ < 652800000 780000 171 >,
+ < 729600000 790000 193 >,
+ < 806400000 800000 215 >,
+ < 883200000 810000 237 >,
+ < 960000000 820000 260 >,
+ < 1036800000 830000 282 >,
+ < 1113600000 840000 306 >,
+ < 1190400000 850000 330 >,
+ < 1267200000 860000 354 >,
+ < 1344000000 870000 378 >,
+ < 1420800000 885000 404 >,
+ < 1497600000 900000 431 >,
+ < 1574400000 915000 458 >,
+ < 1651200000 930000 486 >,
+ < 1728000000 945000 515 >,
+ < 1804800000 960000 543 >,
+ < 1881600000 975000 572 >,
+ < 1958400000 990000 604 >,
+ < 2035200000 1005000 636 >,
+ < 2112000000 1020000 669 >,
+ < 2150400000 1035000 703 >,
+ < 2188800000 1035000 703 >,
+ < 2265600000 1050000 738 >;
+
+ qcom,speed1-pvs8-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 775000 76 >,
+ < 345600000 775000 87 >,
+ < 422400000 775000 108 >,
+ < 499200000 775000 129 >,
+ < 576000000 775000 150 >,
+ < 652800000 775000 171 >,
+ < 729600000 780000 193 >,
+ < 806400000 790000 215 >,
+ < 883200000 800000 237 >,
+ < 960000000 810000 260 >,
+ < 1036800000 820000 282 >,
+ < 1113600000 830000 306 >,
+ < 1190400000 840000 330 >,
+ < 1267200000 850000 354 >,
+ < 1344000000 860000 378 >,
+ < 1420800000 875000 404 >,
+ < 1497600000 890000 431 >,
+ < 1574400000 905000 458 >,
+ < 1651200000 920000 486 >,
+ < 1728000000 935000 515 >,
+ < 1804800000 950000 543 >,
+ < 1881600000 965000 572 >,
+ < 1958400000 980000 604 >,
+ < 2035200000 995000 636 >,
+ < 2112000000 1010000 669 >,
+ < 2150400000 1025000 703 >,
+ < 2188800000 1025000 703 >,
+ < 2265600000 1040000 738 >;
+
+ qcom,speed1-pvs9-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 775000 76 >,
+ < 345600000 775000 87 >,
+ < 422400000 775000 108 >,
+ < 499200000 775000 129 >,
+ < 576000000 775000 150 >,
+ < 652800000 775000 171 >,
+ < 729600000 775000 193 >,
+ < 806400000 780000 215 >,
+ < 883200000 790000 237 >,
+ < 960000000 800000 260 >,
+ < 1036800000 810000 282 >,
+ < 1113600000 820000 306 >,
+ < 1190400000 830000 330 >,
+ < 1267200000 840000 354 >,
+ < 1344000000 850000 378 >,
+ < 1420800000 865000 404 >,
+ < 1497600000 880000 431 >,
+ < 1574400000 895000 458 >,
+ < 1651200000 910000 486 >,
+ < 1728000000 925000 515 >,
+ < 1804800000 940000 543 >,
+ < 1881600000 955000 572 >,
+ < 1958400000 970000 604 >,
+ < 2035200000 985000 636 >,
+ < 2112000000 1000000 669 >,
+ < 2150400000 1015000 703 >,
+ < 2188800000 1015000 703 >,
+ < 2265600000 1030000 738 >;
+
+ qcom,speed1-pvs10-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 775000 76 >,
+ < 345600000 775000 87 >,
+ < 422400000 775000 108 >,
+ < 499200000 775000 129 >,
+ < 576000000 775000 150 >,
+ < 652800000 775000 171 >,
+ < 729600000 775000 193 >,
+ < 806400000 775000 215 >,
+ < 883200000 780000 237 >,
+ < 960000000 790000 260 >,
+ < 1036800000 800000 282 >,
+ < 1113600000 810000 306 >,
+ < 1190400000 820000 330 >,
+ < 1267200000 830000 354 >,
+ < 1344000000 840000 378 >,
+ < 1420800000 855000 404 >,
+ < 1497600000 870000 431 >,
+ < 1574400000 885000 458 >,
+ < 1651200000 900000 486 >,
+ < 1728000000 915000 515 >,
+ < 1804800000 930000 543 >,
+ < 1881600000 945000 572 >,
+ < 1958400000 960000 604 >,
+ < 2035200000 975000 636 >,
+ < 2112000000 990000 669 >,
+ < 2150400000 1005000 703 >,
+ < 2188800000 1005000 703 >,
+ < 2265600000 1020000 738 >;
+
+ qcom,speed1-pvs11-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 775000 76 >,
+ < 345600000 775000 87 >,
+ < 422400000 775000 108 >,
+ < 499200000 775000 129 >,
+ < 576000000 775000 150 >,
+ < 652800000 775000 171 >,
+ < 729600000 775000 193 >,
+ < 806400000 775000 215 >,
+ < 883200000 775000 237 >,
+ < 960000000 780000 260 >,
+ < 1036800000 790000 282 >,
+ < 1113600000 800000 306 >,
+ < 1190400000 810000 330 >,
+ < 1267200000 820000 354 >,
+ < 1344000000 830000 378 >,
+ < 1420800000 845000 404 >,
+ < 1497600000 860000 431 >,
+ < 1574400000 875000 458 >,
+ < 1651200000 890000 486 >,
+ < 1728000000 905000 515 >,
+ < 1804800000 920000 543 >,
+ < 1881600000 935000 572 >,
+ < 1958400000 950000 604 >,
+ < 2035200000 965000 636 >,
+ < 2112000000 980000 669 >,
+ < 2150400000 995000 703 >,
+ < 2188800000 995000 703 >,
+ < 2265600000 1010000 738 >;
+
+ qcom,speed1-pvs12-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 775000 76 >,
+ < 345600000 775000 87 >,
+ < 422400000 775000 108 >,
+ < 499200000 775000 129 >,
+ < 576000000 775000 150 >,
+ < 652800000 775000 171 >,
+ < 729600000 775000 193 >,
+ < 806400000 775000 215 >,
+ < 883200000 775000 237 >,
+ < 960000000 775000 260 >,
+ < 1036800000 780000 282 >,
+ < 1113600000 790000 306 >,
+ < 1190400000 800000 330 >,
+ < 1267200000 810000 354 >,
+ < 1344000000 820000 378 >,
+ < 1420800000 835000 404 >,
+ < 1497600000 850000 431 >,
+ < 1574400000 865000 458 >,
+ < 1651200000 880000 486 >,
+ < 1728000000 895000 515 >,
+ < 1804800000 910000 543 >,
+ < 1881600000 925000 572 >,
+ < 1958400000 940000 604 >,
+ < 2035200000 955000 636 >,
+ < 2112000000 970000 669 >,
+ < 2150400000 985000 703 >,
+ < 2188800000 985000 703 >,
+ < 2265600000 1000000 738 >;
+
+ qcom,speed1-pvs13-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 775000 76 >,
+ < 345600000 775000 87 >,
+ < 422400000 775000 108 >,
+ < 499200000 775000 129 >,
+ < 576000000 775000 150 >,
+ < 652800000 775000 171 >,
+ < 729600000 775000 193 >,
+ < 806400000 775000 215 >,
+ < 883200000 775000 237 >,
+ < 960000000 775000 260 >,
+ < 1036800000 775000 282 >,
+ < 1113600000 780000 306 >,
+ < 1190400000 790000 330 >,
+ < 1267200000 800000 354 >,
+ < 1344000000 810000 378 >,
+ < 1420800000 825000 404 >,
+ < 1497600000 840000 431 >,
+ < 1574400000 855000 458 >,
+ < 1651200000 870000 486 >,
+ < 1728000000 885000 515 >,
+ < 1804800000 900000 543 >,
+ < 1881600000 915000 572 >,
+ < 1958400000 930000 604 >,
+ < 2035200000 945000 636 >,
+ < 2112000000 960000 669 >,
+ < 2150400000 975000 703 >,
+ < 2188800000 975000 703 >,
+ < 2265600000 990000 738 >;
+
+ qcom,speed1-pvs14-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 750000 76 >,
+ < 345600000 750000 87 >,
+ < 422400000 750000 108 >,
+ < 499200000 750000 129 >,
+ < 576000000 750000 150 >,
+ < 652800000 750000 171 >,
+ < 729600000 750000 193 >,
+ < 806400000 750000 215 >,
+ < 883200000 750000 237 >,
+ < 960000000 750000 260 >,
+ < 1036800000 760000 282 >,
+ < 1113600000 770000 306 >,
+ < 1190400000 780000 330 >,
+ < 1267200000 790000 354 >,
+ < 1344000000 800000 378 >,
+ < 1420800000 815000 404 >,
+ < 1497600000 830000 431 >,
+ < 1574400000 845000 458 >,
+ < 1651200000 860000 486 >,
+ < 1728000000 875000 515 >,
+ < 1804800000 890000 543 >,
+ < 1881600000 905000 572 >,
+ < 1958400000 920000 604 >,
+ < 2035200000 935000 636 >,
+ < 2112000000 950000 669 >,
+ < 2150400000 965000 703 >,
+ < 2188800000 965000 703 >,
+ < 2265600000 980000 738 >;
+
+ qcom,speed1-pvs15-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 750000 76 >,
+ < 345600000 750000 87 >,
+ < 422400000 750000 108 >,
+ < 499200000 750000 129 >,
+ < 576000000 750000 150 >,
+ < 652800000 750000 171 >,
+ < 729600000 750000 193 >,
+ < 806400000 750000 215 >,
+ < 883200000 750000 237 >,
+ < 960000000 750000 260 >,
+ < 1036800000 750000 282 >,
+ < 1113600000 760000 306 >,
+ < 1190400000 770000 330 >,
+ < 1267200000 780000 354 >,
+ < 1344000000 790000 378 >,
+ < 1420800000 805000 404 >,
+ < 1497600000 820000 431 >,
+ < 1574400000 835000 458 >,
+ < 1651200000 850000 486 >,
+ < 1728000000 865000 515 >,
+ < 1804800000 880000 543 >,
+ < 1881600000 895000 572 >,
+ < 1958400000 910000 604 >,
+ < 2035200000 925000 636 >,
+ < 2112000000 940000 669 >,
+ < 2150400000 955000 703 >,
+ < 2188800000 955000 703 >,
+ < 2265600000 970000 738 >;
+
+ qcom,speed3-pvs0-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 800000 76 >,
+ < 345600000 800000 87 >,
+ < 422400000 800000 106 >,
+ < 499200000 810000 126 >,
+ < 576000000 820000 147 >,
+ < 652800000 830000 168 >,
+ < 729600000 840000 189 >,
+ < 806400000 850000 211 >,
+ < 883200000 860000 233 >,
+ < 960000000 870000 256 >,
+ < 1036800000 880000 278 >,
+ < 1113600000 890000 301 >,
+ < 1190400000 900000 324 >,
+ < 1267200000 910000 348 >,
+ < 1344000000 920000 372 >,
+ < 1420800000 930000 396 >,
+ < 1497600000 940000 421 >,
+ < 1574400000 950000 446 >,
+ < 1651200000 965000 473 >,
+ < 1728000000 980000 501 >,
+ < 1804800000 995000 529 >,
+ < 1881600000 1010000 558 >,
+ < 1958400000 1025000 588 >,
+ < 2035200000 1040000 617 >,
+ < 2112000000 1055000 649 >,
+ < 2150400000 1070000 682 >,
+ < 2188800000 1070000 682 >,
+ < 2265600000 1085000 716 >,
+ < 2342400000 1100000 751 >,
+ < 2419200000 1115000 786 >,
+ < 2457600000 1120000 802 >;
+
+ qcom,speed3-pvs1-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 800000 76 >,
+ < 345600000 800000 87 >,
+ < 422400000 800000 106 >,
+ < 499200000 800000 126 >,
+ < 576000000 810000 147 >,
+ < 652800000 820000 168 >,
+ < 729600000 830000 189 >,
+ < 806400000 840000 211 >,
+ < 883200000 850000 233 >,
+ < 960000000 860000 256 >,
+ < 1036800000 870000 278 >,
+ < 1113600000 880000 301 >,
+ < 1190400000 890000 324 >,
+ < 1267200000 900000 348 >,
+ < 1344000000 910000 372 >,
+ < 1420800000 920000 396 >,
+ < 1497600000 930000 421 >,
+ < 1574400000 940000 446 >,
+ < 1651200000 955000 473 >,
+ < 1728000000 970000 501 >,
+ < 1804800000 985000 529 >,
+ < 1881600000 1000000 558 >,
+ < 1958400000 1015000 588 >,
+ < 2035200000 1030000 617 >,
+ < 2112000000 1045000 649 >,
+ < 2150400000 1060000 682 >,
+ < 2188800000 1060000 682 >,
+ < 2265600000 1075000 716 >,
+ < 2342400000 1090000 751 >,
+ < 2419200000 1105000 786 >,
+ < 2457600000 1110000 802 >;
+
+ qcom,speed3-pvs2-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 800000 76 >,
+ < 345600000 800000 87 >,
+ < 422400000 800000 106 >,
+ < 499200000 800000 126 >,
+ < 576000000 800000 147 >,
+ < 652800000 810000 168 >,
+ < 729600000 820000 189 >,
+ < 806400000 830000 211 >,
+ < 883200000 840000 233 >,
+ < 960000000 850000 256 >,
+ < 1036800000 860000 278 >,
+ < 1113600000 870000 301 >,
+ < 1190400000 880000 324 >,
+ < 1267200000 890000 348 >,
+ < 1344000000 900000 372 >,
+ < 1420800000 910000 396 >,
+ < 1497600000 920000 421 >,
+ < 1574400000 930000 446 >,
+ < 1651200000 945000 473 >,
+ < 1728000000 960000 501 >,
+ < 1804800000 975000 529 >,
+ < 1881600000 990000 558 >,
+ < 1958400000 1005000 588 >,
+ < 2035200000 1020000 617 >,
+ < 2112000000 1035000 649 >,
+ < 2150400000 1050000 682 >,
+ < 2188800000 1050000 682 >,
+ < 2265600000 1065000 716 >,
+ < 2342400000 1080000 751 >,
+ < 2419200000 1095000 786 >,
+ < 2457600000 1100000 802 >;
+
+ qcom,speed3-pvs3-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 800000 76 >,
+ < 345600000 800000 87 >,
+ < 422400000 800000 106 >,
+ < 499200000 800000 126 >,
+ < 576000000 800000 147 >,
+ < 652800000 800000 168 >,
+ < 729600000 810000 189 >,
+ < 806400000 820000 211 >,
+ < 883200000 830000 233 >,
+ < 960000000 840000 256 >,
+ < 1036800000 850000 278 >,
+ < 1113600000 860000 301 >,
+ < 1190400000 870000 324 >,
+ < 1267200000 880000 348 >,
+ < 1344000000 890000 372 >,
+ < 1420800000 900000 396 >,
+ < 1497600000 910000 421 >,
+ < 1574400000 920000 446 >,
+ < 1651200000 935000 473 >,
+ < 1728000000 950000 501 >,
+ < 1804800000 965000 529 >,
+ < 1881600000 980000 558 >,
+ < 1958400000 995000 588 >,
+ < 2035200000 1010000 617 >,
+ < 2112000000 1025000 649 >,
+ < 2150400000 1040000 682 >,
+ < 2188800000 1040000 682 >,
+ < 2265600000 1055000 716 >,
+ < 2342400000 1070000 751 >,
+ < 2419200000 1085000 786 >,
+ < 2457600000 1090000 802 >;
+
+ qcom,speed3-pvs4-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 800000 76 >,
+ < 345600000 800000 87 >,
+ < 422400000 800000 106 >,
+ < 499200000 800000 126 >,
+ < 576000000 800000 147 >,
+ < 652800000 800000 168 >,
+ < 729600000 800000 189 >,
+ < 806400000 810000 211 >,
+ < 883200000 820000 233 >,
+ < 960000000 830000 256 >,
+ < 1036800000 840000 278 >,
+ < 1113600000 850000 301 >,
+ < 1190400000 860000 324 >,
+ < 1267200000 870000 348 >,
+ < 1344000000 880000 372 >,
+ < 1420800000 890000 396 >,
+ < 1497600000 900000 421 >,
+ < 1574400000 910000 446 >,
+ < 1651200000 925000 473 >,
+ < 1728000000 940000 501 >,
+ < 1804800000 955000 529 >,
+ < 1881600000 970000 558 >,
+ < 1958400000 985000 588 >,
+ < 2035200000 1000000 617 >,
+ < 2112000000 1015000 649 >,
+ < 2150400000 1030000 682 >,
+ < 2188800000 1030000 682 >,
+ < 2265600000 1045000 716 >,
+ < 2342400000 1060000 751 >,
+ < 2419200000 1075000 786 >,
+ < 2457600000 1080000 802 >;
+
+ qcom,speed3-pvs5-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 800000 76 >,
+ < 345600000 800000 87 >,
+ < 422400000 800000 106 >,
+ < 499200000 800000 126 >,
+ < 576000000 800000 147 >,
+ < 652800000 800000 168 >,
+ < 729600000 800000 189 >,
+ < 806400000 800000 211 >,
+ < 883200000 810000 233 >,
+ < 960000000 820000 256 >,
+ < 1036800000 830000 278 >,
+ < 1113600000 840000 301 >,
+ < 1190400000 850000 324 >,
+ < 1267200000 860000 348 >,
+ < 1344000000 870000 372 >,
+ < 1420800000 880000 396 >,
+ < 1497600000 890000 421 >,
+ < 1574400000 900000 446 >,
+ < 1651200000 915000 473 >,
+ < 1728000000 930000 501 >,
+ < 1804800000 945000 529 >,
+ < 1881600000 960000 558 >,
+ < 1958400000 975000 588 >,
+ < 2035200000 990000 617 >,
+ < 2112000000 1005000 649 >,
+ < 2150400000 1020000 682 >,
+ < 2188800000 1020000 682 >,
+ < 2265600000 1035000 716 >,
+ < 2342400000 1050000 751 >,
+ < 2419200000 1065000 786 >,
+ < 2457600000 1070000 802 >;
+
+ qcom,speed3-pvs6-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 775000 76 >,
+ < 345600000 775000 87 >,
+ < 422400000 775000 106 >,
+ < 499200000 775000 126 >,
+ < 576000000 775000 147 >,
+ < 652800000 775000 168 >,
+ < 729600000 780000 189 >,
+ < 806400000 790000 211 >,
+ < 883200000 800000 233 >,
+ < 960000000 810000 256 >,
+ < 1036800000 820000 278 >,
+ < 1113600000 830000 301 >,
+ < 1190400000 840000 324 >,
+ < 1267200000 850000 348 >,
+ < 1344000000 860000 372 >,
+ < 1420800000 870000 396 >,
+ < 1497600000 880000 421 >,
+ < 1574400000 890000 446 >,
+ < 1651200000 905000 473 >,
+ < 1728000000 920000 501 >,
+ < 1804800000 935000 529 >,
+ < 1881600000 950000 558 >,
+ < 1958400000 965000 588 >,
+ < 2035200000 980000 617 >,
+ < 2112000000 995000 649 >,
+ < 2150400000 1010000 682 >,
+ < 2188800000 1010000 682 >,
+ < 2265600000 1025000 716 >,
+ < 2342400000 1040000 751 >,
+ < 2419200000 1055000 786 >,
+ < 2457600000 1060000 802 >;
+
+ qcom,speed3-pvs7-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 775000 76 >,
+ < 345600000 775000 87 >,
+ < 422400000 775000 106 >,
+ < 499200000 775000 126 >,
+ < 576000000 775000 147 >,
+ < 652800000 775000 168 >,
+ < 729600000 775000 189 >,
+ < 806400000 780000 211 >,
+ < 883200000 790000 233 >,
+ < 960000000 800000 256 >,
+ < 1036800000 810000 278 >,
+ < 1113600000 820000 301 >,
+ < 1190400000 830000 324 >,
+ < 1267200000 840000 348 >,
+ < 1344000000 850000 372 >,
+ < 1420800000 860000 396 >,
+ < 1497600000 870000 421 >,
+ < 1574400000 880000 446 >,
+ < 1651200000 895000 473 >,
+ < 1728000000 910000 501 >,
+ < 1804800000 925000 529 >,
+ < 1881600000 940000 558 >,
+ < 1958400000 955000 588 >,
+ < 2035200000 970000 617 >,
+ < 2112000000 985000 649 >,
+ < 2150400000 1000000 682 >,
+ < 2188800000 1000000 682 >,
+ < 2265600000 1015000 716 >,
+ < 2342400000 1030000 751 >,
+ < 2419200000 1045000 786 >,
+ < 2457600000 1050000 802 >;
+
+ qcom,speed3-pvs8-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 775000 76 >,
+ < 345600000 775000 87 >,
+ < 422400000 775000 106 >,
+ < 499200000 775000 126 >,
+ < 576000000 775000 147 >,
+ < 652800000 775000 168 >,
+ < 729600000 775000 189 >,
+ < 806400000 775000 211 >,
+ < 883200000 780000 233 >,
+ < 960000000 790000 256 >,
+ < 1036800000 800000 278 >,
+ < 1113600000 810000 301 >,
+ < 1190400000 820000 324 >,
+ < 1267200000 830000 348 >,
+ < 1344000000 840000 372 >,
+ < 1420800000 850000 396 >,
+ < 1497600000 860000 421 >,
+ < 1574400000 870000 446 >,
+ < 1651200000 885000 473 >,
+ < 1728000000 900000 501 >,
+ < 1804800000 915000 529 >,
+ < 1881600000 930000 558 >,
+ < 1958400000 945000 588 >,
+ < 2035200000 960000 617 >,
+ < 2112000000 975000 649 >,
+ < 2150400000 990000 682 >,
+ < 2188800000 990000 682 >,
+ < 2265600000 1005000 716 >,
+ < 2342400000 1020000 751 >,
+ < 2419200000 1035000 786 >,
+ < 2457600000 1040000 802 >;
+
+ qcom,speed3-pvs9-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 775000 76 >,
+ < 345600000 775000 87 >,
+ < 422400000 775000 106 >,
+ < 499200000 775000 126 >,
+ < 576000000 775000 147 >,
+ < 652800000 775000 168 >,
+ < 729600000 775000 189 >,
+ < 806400000 775000 211 >,
+ < 883200000 775000 233 >,
+ < 960000000 780000 256 >,
+ < 1036800000 790000 278 >,
+ < 1113600000 800000 301 >,
+ < 1190400000 810000 324 >,
+ < 1267200000 820000 348 >,
+ < 1344000000 830000 372 >,
+ < 1420800000 840000 396 >,
+ < 1497600000 850000 421 >,
+ < 1574400000 860000 446 >,
+ < 1651200000 875000 473 >,
+ < 1728000000 890000 501 >,
+ < 1804800000 905000 529 >,
+ < 1881600000 920000 558 >,
+ < 1958400000 935000 588 >,
+ < 2035200000 950000 617 >,
+ < 2112000000 965000 649 >,
+ < 2150400000 980000 682 >,
+ < 2188800000 980000 682 >,
+ < 2265600000 995000 716 >,
+ < 2342400000 1010000 751 >,
+ < 2419200000 1025000 786 >,
+ < 2457600000 1030000 802 >;
+
+ qcom,speed3-pvs10-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 775000 76 >,
+ < 345600000 775000 87 >,
+ < 422400000 775000 106 >,
+ < 499200000 775000 126 >,
+ < 576000000 775000 147 >,
+ < 652800000 775000 168 >,
+ < 729600000 775000 189 >,
+ < 806400000 775000 211 >,
+ < 883200000 775000 233 >,
+ < 960000000 775000 256 >,
+ < 1036800000 780000 278 >,
+ < 1113600000 790000 301 >,
+ < 1190400000 800000 324 >,
+ < 1267200000 810000 348 >,
+ < 1344000000 820000 372 >,
+ < 1420800000 830000 396 >,
+ < 1497600000 840000 421 >,
+ < 1574400000 850000 446 >,
+ < 1651200000 865000 473 >,
+ < 1728000000 880000 501 >,
+ < 1804800000 895000 529 >,
+ < 1881600000 910000 558 >,
+ < 1958400000 925000 588 >,
+ < 2035200000 940000 617 >,
+ < 2112000000 955000 649 >,
+ < 2150400000 970000 682 >,
+ < 2188800000 970000 682 >,
+ < 2265600000 985000 716 >,
+ < 2342400000 1000000 751 >,
+ < 2419200000 1015000 786 >,
+ < 2457600000 1020000 802 >;
+
+ qcom,speed3-pvs11-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 775000 76 >,
+ < 345600000 775000 87 >,
+ < 422400000 775000 106 >,
+ < 499200000 775000 126 >,
+ < 576000000 775000 147 >,
+ < 652800000 775000 168 >,
+ < 729600000 775000 189 >,
+ < 806400000 775000 211 >,
+ < 883200000 775000 233 >,
+ < 960000000 775000 256 >,
+ < 1036800000 775000 278 >,
+ < 1113600000 780000 301 >,
+ < 1190400000 790000 324 >,
+ < 1267200000 800000 348 >,
+ < 1344000000 810000 372 >,
+ < 1420800000 820000 396 >,
+ < 1497600000 830000 421 >,
+ < 1574400000 840000 446 >,
+ < 1651200000 855000 473 >,
+ < 1728000000 870000 501 >,
+ < 1804800000 885000 529 >,
+ < 1881600000 900000 558 >,
+ < 1958400000 915000 588 >,
+ < 2035200000 930000 617 >,
+ < 2112000000 945000 649 >,
+ < 2150400000 960000 682 >,
+ < 2188800000 960000 682 >,
+ < 2265600000 975000 716 >,
+ < 2342400000 990000 751 >,
+ < 2419200000 1005000 786 >,
+ < 2457600000 1010000 802 >;
+
+ qcom,speed3-pvs12-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 775000 76 >,
+ < 345600000 775000 87 >,
+ < 422400000 775000 106 >,
+ < 499200000 775000 126 >,
+ < 576000000 775000 147 >,
+ < 652800000 775000 168 >,
+ < 729600000 775000 189 >,
+ < 806400000 775000 211 >,
+ < 883200000 775000 233 >,
+ < 960000000 775000 256 >,
+ < 1036800000 775000 278 >,
+ < 1113600000 775000 301 >,
+ < 1190400000 780000 324 >,
+ < 1267200000 790000 348 >,
+ < 1344000000 800000 372 >,
+ < 1420800000 810000 396 >,
+ < 1497600000 820000 421 >,
+ < 1574400000 830000 446 >,
+ < 1651200000 845000 473 >,
+ < 1728000000 860000 501 >,
+ < 1804800000 875000 529 >,
+ < 1881600000 890000 558 >,
+ < 1958400000 905000 588 >,
+ < 2035200000 920000 617 >,
+ < 2112000000 935000 649 >,
+ < 2150400000 950000 682 >,
+ < 2188800000 950000 682 >,
+ < 2265600000 965000 716 >,
+ < 2342400000 980000 751 >,
+ < 2419200000 995000 786 >,
+ < 2457600000 1000000 802 >;
+
+ qcom,speed3-pvs13-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 775000 76 >,
+ < 345600000 775000 87 >,
+ < 422400000 775000 106 >,
+ < 499200000 775000 126 >,
+ < 576000000 775000 147 >,
+ < 652800000 775000 168 >,
+ < 729600000 775000 189 >,
+ < 806400000 775000 211 >,
+ < 883200000 775000 233 >,
+ < 960000000 775000 256 >,
+ < 1036800000 775000 278 >,
+ < 1113600000 775000 301 >,
+ < 1190400000 775000 324 >,
+ < 1267200000 780000 348 >,
+ < 1344000000 790000 372 >,
+ < 1420800000 800000 396 >,
+ < 1497600000 810000 421 >,
+ < 1574400000 820000 446 >,
+ < 1651200000 835000 473 >,
+ < 1728000000 850000 501 >,
+ < 1804800000 865000 529 >,
+ < 1881600000 880000 558 >,
+ < 1958400000 895000 588 >,
+ < 2035200000 910000 617 >,
+ < 2112000000 925000 649 >,
+ < 2150400000 940000 682 >,
+ < 2188800000 940000 682 >,
+ < 2265600000 955000 716 >,
+ < 2342400000 970000 751 >,
+ < 2419200000 985000 786 >,
+ < 2457600000 990000 802 >;
+
+ qcom,speed3-pvs14-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 750000 76 >,
+ < 345600000 750000 87 >,
+ < 422400000 750000 106 >,
+ < 499200000 750000 126 >,
+ < 576000000 750000 147 >,
+ < 652800000 750000 168 >,
+ < 729600000 750000 189 >,
+ < 806400000 750000 211 >,
+ < 883200000 750000 233 >,
+ < 960000000 750000 256 >,
+ < 1036800000 750000 278 >,
+ < 1113600000 750000 301 >,
+ < 1190400000 760000 324 >,
+ < 1267200000 770000 348 >,
+ < 1344000000 780000 372 >,
+ < 1420800000 790000 396 >,
+ < 1497600000 800000 421 >,
+ < 1574400000 810000 446 >,
+ < 1651200000 825000 473 >,
+ < 1728000000 840000 501 >,
+ < 1804800000 855000 529 >,
+ < 1881600000 870000 558 >,
+ < 1958400000 885000 588 >,
+ < 2035200000 900000 617 >,
+ < 2112000000 915000 649 >,
+ < 2150400000 930000 682 >,
+ < 2188800000 930000 682 >,
+ < 2265600000 945000 716 >,
+ < 2342400000 960000 751 >,
+ < 2419200000 975000 786 >,
+ < 2457600000 980000 802 >;
+
+ qcom,speed3-pvs15-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 750000 76 >,
+ < 345600000 750000 87 >,
+ < 422400000 750000 106 >,
+ < 499200000 750000 126 >,
+ < 576000000 750000 147 >,
+ < 652800000 750000 168 >,
+ < 729600000 750000 189 >,
+ < 806400000 750000 211 >,
+ < 883200000 750000 233 >,
+ < 960000000 750000 256 >,
+ < 1036800000 750000 278 >,
+ < 1113600000 750000 301 >,
+ < 1190400000 750000 324 >,
+ < 1267200000 760000 348 >,
+ < 1344000000 770000 372 >,
+ < 1420800000 780000 396 >,
+ < 1497600000 790000 421 >,
+ < 1574400000 800000 446 >,
+ < 1651200000 815000 473 >,
+ < 1728000000 830000 501 >,
+ < 1804800000 845000 529 >,
+ < 1881600000 860000 558 >,
+ < 1958400000 875000 588 >,
+ < 2035200000 890000 617 >,
+ < 2112000000 905000 649 >,
+ < 2150400000 920000 682 >,
+ < 2188800000 920000 682 >,
+ < 2265600000 935000 716 >,
+ < 2342400000 950000 751 >,
+ < 2419200000 965000 786 >,
+ < 2457600000 970000 802 >;
+ };
+
+ i2c@f9928000 { /* BLSP-1 QUP-6 */
+ cell-index = <3>;
+ compatible = "qcom,i2c-qup";
+ reg = <0xf9928000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ interrupts = <0 100 0>;
+ interrupt-names = "qup_err_intr";
+ qcom,i2c-bus-freq = <400000>;
+ qcom,i2c-src-freq = <19200000>;
+ qcom,sda-gpio = <&msmgpio 29 0>;
+ qcom,scl-gpio = <&msmgpio 30 0>;
+ qcom,master-id = <86>;
+ };
};
/* GPU overrides */
&msm_gpu {
/* Updated chip ID */
qcom,chipid = <0x03030002>;
-
- qcom,initial-pwrlevel = <6>;
+ qcom,msm-bus,num-cases = <15>;
+ qcom,bus-control;
+ qcom,initial-pwrlevel = <3>;
/* Updated bus bandwidth requirements */
qcom,msm-bus,vectors-KBps =
/* Off */
<26 512 0 0>, <89 604 0 0>,
+ /* Sub-SVS / SVS */
+ <26 512 0 1600000>, <89 604 0 3200000>,
/* SVS */
- <26 512 0 2400000>, <89 604 0 3000000>,
- /* Nominal / SVS */
- <26 512 0 4656000>, <89 604 0 3000000>,
- /* Nominal */
- <26 512 0 4656000>, <89 604 0 5120000>,
- /* Turbo / Nominal */
- <26 512 0 7464000>, <89 604 0 5120000>,
- /* Turbo */
- <26 512 0 7464000>, <89 604 0 6400000>;
+ <26 512 0 2456000>, <89 604 0 3200000>,
+ /* low Nominal / SVS */
+ <26 512 0 3680000>, <89 604 0 3200000>,
+ /* SVS / low Nominal */
+ <26 512 0 2456000>, <89 604 0 5280000>,
+ /* low Nominal / low Nominal */
+ <26 512 0 3680000>, <89 604 0 5280000>,
+ /* Nominal / low Nominal */
+ <26 512 0 4912000>, <89 604 0 5280000>,
+ /* low Nominal / Nominal */
+ <26 512 0 3680000>, <89 604 0 6224000>,
+ /* Nominal / Nominal */
+ <26 512 0 4912000>, <89 604 0 6224000>,
+ /* low Turbo / Nominal */
+ <26 512 0 6400000>, <89 604 0 6224000>,
+ /* Nominal / low Turbo */
+ <26 512 0 4912000>, <89 604 0 7398000>,
+ /* low Turbo / low Turbo */
+ <26 512 0 6400000>, <89 604 0 7398000>,
+ /* Turbo / low Turbo */
+ <26 512 0 7464000>, <89 604 0 7398000>,
+ /* Nominal / Turbo */
+ <26 512 0 4912000>, <89 604 0 9248000>,
+ /* Turbo / Turbo */
+ <26 512 0 7464000>, <89 604 0 9248000>;
qcom,gpu-pwrlevels {
#address-cells = <1>;
@@ -72,68 +1615,40 @@
qcom,gpu-pwrlevel@0 {
reg = <0>;
qcom,gpu-freq = <578000000>;
- qcom,bus-freq = <5>;
+ qcom,bus-freq = <14>;
qcom,io-fraction = <33>;
};
- qcom,gpu-pwrlevel@1 {
- reg = <1>;
- qcom,gpu-freq = <462400000>;
- qcom,bus-freq = <4>;
- qcom,io-fraction = <33>;
- };
-
- qcom,gpu-pwrlevel@2 {
- reg = <2>;
- qcom,gpu-freq = <462400000>;
- qcom,bus-freq = <3>;
- qcom,io-fraction = <66>;
- };
-
- qcom,gpu-pwrlevel@3 {
- reg = <3>;
- qcom,gpu-freq = <389000000>;
- qcom,bus-freq = <4>;
- qcom,io-fraction = <66>;
- };
-
- qcom,gpu-pwrlevel@4 {
- reg = <4>;
- qcom,gpu-freq = <389000000>;
- qcom,bus-freq = <3>;
- qcom,io-fraction = <66>;
- };
-
- qcom,gpu-pwrlevel@5 {
- reg = <5>;
- qcom,gpu-freq = <330000000>;
- qcom,bus-freq = <4>;
+ qcom,gpu-pwrlevel@1 {
+ reg = <1>;
+ qcom,gpu-freq = <462400000>;
+ qcom,bus-freq = <11>;
qcom,io-fraction = <66>;
};
- qcom,gpu-pwrlevel@6 {
- reg = <6>;
- qcom,gpu-freq = <330000000>;
- qcom,bus-freq = <3>;
+ qcom,gpu-pwrlevel@2 {
+ reg = <2>;
+ qcom,gpu-freq = <389000000>;
+ qcom,bus-freq = <8>;
qcom,io-fraction = <66>;
};
- qcom,gpu-pwrlevel@7 {
- reg = <7>;
+ qcom,gpu-pwrlevel@3 {
+ reg = <3>;
+ qcom,gpu-freq = <320000000>;
+ qcom,bus-freq = <5>;
+ qcom,io-fraction = <100>;
+ };
+
+ qcom,gpu-pwrlevel@4 {
+ reg = <4>;
qcom,gpu-freq = <200000000>;
qcom,bus-freq = <2>;
qcom,io-fraction = <100>;
};
- qcom,gpu-pwrlevel@8 {
- reg = <8>;
- qcom,gpu-freq = <200000000>;
- qcom,bus-freq = <1>;
- qcom,io-fraction = <100>;
- };
-
- qcom,gpu-pwrlevel@9 {
- reg = <9>;
+ qcom,gpu-pwrlevel@5 {
+ reg = <5>;
qcom,gpu-freq = <27000000>;
qcom,bus-freq = <0>;
qcom,io-fraction = <0>;
diff --git a/arch/arm/boot/dts/msm9625-ion.dtsi b/arch/arm/boot/dts/msm9625-ion.dtsi
index 2a3e4b5..3ef0b3f 100644
--- a/arch/arm/boot/dts/msm9625-ion.dtsi
+++ b/arch/arm/boot/dts/msm9625-ion.dtsi
@@ -16,12 +16,9 @@
#address-cells = <1>;
#size-cells = <0>;
- qcom,ion-heap@30 { /* SYSTEM HEAP */
- reg = <30>;
- };
-
- qcom,ion-heap@25 { /* IOMMU HEAP */
+ qcom,ion-heap@25 {
reg = <25>;
+ qcom,ion-heap-type = "SYSTEM";
};
qcom,ion-heap@28 { /* AUDIO HEAP */
@@ -30,6 +27,7 @@
qcom,heap-align = <0x1000>;
qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
qcom,memory-reservation-size = <0xAF000>;
+ qcom,ion-heap-type = "CARVEOUT";
};
};
};
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index 0e7baf1..dee1f68 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -686,9 +686,9 @@
qcom,adsp-state = <2>;
};
- qcom,msm-pcm {
- compatible = "qcom,msm-pcm-dsp";
- qcom,msm-pcm-dsp-id = <0>;
+ qti,msm-pcm {
+ compatible = "qti,msm-pcm-dsp";
+ qti,msm-pcm-dsp-id = <0>;
};
qcom,msm-pcm-routing {
diff --git a/arch/arm/boot/dts/msmsamarium-ion.dtsi b/arch/arm/boot/dts/msmsamarium-ion.dtsi
index ea954b8..167b8b7 100644
--- a/arch/arm/boot/dts/msmsamarium-ion.dtsi
+++ b/arch/arm/boot/dts/msmsamarium-ion.dtsi
@@ -16,16 +16,14 @@
#address-cells = <1>;
#size-cells = <0>;
- qcom,ion-heap@30 { /* SYSTEM HEAP */
- reg = <30>;
- };
-
- qcom,ion-heap@21 { /* SYSTEM CONTIG HEAP */
- reg = <21>;
- };
-
- qcom,ion-heap@25 { /* IOMMU HEAP */
+ qcom,ion-heap@25 {
reg = <25>;
+ qcom,ion-heap-type = "SYSTEM";
+ };
+
+ qcom,ion-heap@21 {
+ reg = <21>;
+ qcom,ion-heap-type = "SYSTEM_CONTIG";
};
};
};
diff --git a/arch/arm/boot/dts/msmsamarium.dtsi b/arch/arm/boot/dts/msmsamarium.dtsi
index a492561..6c55566 100644
--- a/arch/arm/boot/dts/msmsamarium.dtsi
+++ b/arch/arm/boot/dts/msmsamarium.dtsi
@@ -65,6 +65,24 @@
reg = <0xfe805000 0x1000>; /* Address and size of IMEM */
};
+ rmtfs_sharedmem {
+ compatible = "qcom,sharedmem-uio";
+ reg = <0x0fd80000 0x00180000>;
+ reg-names = "rmtfs";
+ };
+
+ dsp_sharedmem {
+ compatible = "qcom,sharedmem-uio";
+ reg = <0x0fd60000 0x00020000>;
+ reg-names = "rfsa_dsp";
+ };
+
+ mdm_sharedmem {
+ compatible = "qcom,sharedmem-uio";
+ reg = <0x0fd60000 0x00020000>;
+ reg-names = "rfsa_mdm";
+ };
+
sdcc1: qcom,sdcc@f9824000 {
cell-index = <1>; /* SDC1 eMMC slot */
compatible = "qcom,msm-sdcc";
diff --git a/arch/arm/configs/apq8084_defconfig b/arch/arm/configs/apq8084_defconfig
index 7c1af1a..823e4f8 100644
--- a/arch/arm/configs/apq8084_defconfig
+++ b/arch/arm/configs/apq8084_defconfig
@@ -90,6 +90,7 @@
CONFIG_AEABI=y
CONFIG_HIGHMEM=y
CONFIG_COMPACTION=y
+CONFIG_ENABLE_VMALLOC_SAVING=y
CONFIG_CC_STACKPROTECTOR=y
CONFIG_CP_ACCESS=y
CONFIG_USE_OF=y
@@ -300,6 +301,11 @@
# CONFIG_LCD_CLASS_DEVICE is not set
CONFIG_BACKLIGHT_CLASS_DEVICE=y
# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_UHID=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_ELECOM=y
CONFIG_USB=y
CONFIG_USB_SUSPEND=y
CONFIG_USB_EHCI_HCD=y
@@ -377,6 +383,7 @@
CONFIG_MAGIC_SYSRQ=y
CONFIG_LOCKUP_DETECTOR=y
# CONFIG_DETECT_HUNG_TASK is not set
+# CONFIG_SYSRQ_SCHED_DEBUG is not set
CONFIG_SCHEDSTATS=y
CONFIG_TIMER_STATS=y
CONFIG_DEBUG_KMEMLEAK=y
diff --git a/arch/arm/configs/fsm9xxx-perf_defconfig b/arch/arm/configs/fsm9xxx-perf_defconfig
index 37c9554..30b2346 100644
--- a/arch/arm/configs/fsm9xxx-perf_defconfig
+++ b/arch/arm/configs/fsm9xxx-perf_defconfig
@@ -185,3 +185,5 @@
CONFIG_CRYPTO_DEV_QCE=y
CONFIG_CRYPTO_DEV_OTA_CRYPTO=y
CONFIG_CRC_CCITT=y
+CONFIG_DEVMEM=n
+CONFIG_DEVKMEM=n
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index 431ac58..9af4009 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -399,3 +399,5 @@
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_USER=y
CONFIG_CRYPTO_TWOFISH=y
+CONFIG_DEVMEM=n
+CONFIG_DEVKMEM=n
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
index 265234b..6c3898c 100644
--- a/arch/arm/configs/msm8226-perf_defconfig
+++ b/arch/arm/configs/msm8226-perf_defconfig
@@ -25,6 +25,7 @@
CONFIG_PANIC_TIMEOUT=5
CONFIG_KALLSYMS_ALL=y
CONFIG_EMBEDDED=y
+# CONFIG_SLUB_DEBUG is not set
CONFIG_PROFILING=y
CONFIG_OPROFILE=m
CONFIG_KPROBES=y
@@ -81,6 +82,7 @@
CONFIG_AEABI=y
CONFIG_HIGHMEM=y
CONFIG_COMPACTION=y
+CONFIG_ENABLE_VMALLOC_SAVING=y
CONFIG_CC_STACKPROTECTOR=y
CONFIG_CP_ACCESS=y
CONFIG_USE_OF=y
@@ -214,6 +216,7 @@
CONFIG_BT_HCISMD=y
CONFIG_CFG80211=y
CONFIG_NL80211_TESTMODE=y
+CONFIG_CFG80211_INTERNAL_REGDB=y
CONFIG_CMA=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
@@ -268,6 +271,7 @@
CONFIG_DIAG_CHAR=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_MSM=y
+CONFIG_MSM_ADSPRPC=y
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_QUP=y
@@ -345,6 +349,8 @@
CONFIG_UHID=y
CONFIG_HID_APPLE=y
CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_ELECOM=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
CONFIG_USB_SUSPEND=y
CONFIG_USB_MON=y
@@ -353,6 +359,7 @@
CONFIG_USB_EHCI_MSM=y
CONFIG_USB_EHCI_MSM_HSIC=y
CONFIG_USB_ACM=y
+CONFIG_USB_CCID_BRIDGE=y
CONFIG_USB_STORAGE=y
CONFIG_USB_STORAGE_DATAFAB=y
CONFIG_USB_STORAGE_FREECOM=y
@@ -394,6 +401,8 @@
CONFIG_RTC_CLASS=y
# CONFIG_RTC_DRV_MSM is not set
CONFIG_RTC_DRV_QPNP=y
+CONFIG_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
CONFIG_STAGING=y
CONFIG_ANDROID=y
CONFIG_ANDROID_BINDER_IPC=y
@@ -424,6 +433,7 @@
CONFIG_NLS_ISO8859_1=y
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SYSRQ_SCHED_DEBUG is not set
CONFIG_SCHEDSTATS=y
CONFIG_TIMER_STATS=y
CONFIG_DEBUG_INFO=y
@@ -451,4 +461,6 @@
CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
CONFIG_TOUCHSCREEN_GT9XX=y
CONFIG_GT9XX_TOUCHPANEL_DRIVER=y
-CONFIG_DEFAULT_ROW=y
+CONFIG_MSM_RDBG=m
+CONFIG_DEVMEM=n
+CONFIG_DEVKMEM=n
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index 55627a3..e14118d 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -82,6 +82,7 @@
CONFIG_AEABI=y
CONFIG_HIGHMEM=y
CONFIG_COMPACTION=y
+CONFIG_ENABLE_VMALLOC_SAVING=y
CONFIG_CC_STACKPROTECTOR=y
CONFIG_CP_ACCESS=y
CONFIG_USE_OF=y
@@ -270,6 +271,7 @@
CONFIG_DIAG_CHAR=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_MSM=y
+CONFIG_MSM_ADSPRPC=y
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_QUP=y
@@ -371,6 +373,8 @@
CONFIG_UHID=y
CONFIG_HID_APPLE=y
CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_ELECOM=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
CONFIG_USB_SUSPEND=y
CONFIG_USB_MON=y
@@ -379,6 +383,7 @@
CONFIG_USB_EHCI_MSM=y
CONFIG_USB_EHCI_MSM_HSIC=y
CONFIG_USB_ACM=y
+CONFIG_USB_CCID_BRIDGE=y
CONFIG_USB_STORAGE=y
CONFIG_USB_STORAGE_DATAFAB=y
CONFIG_USB_STORAGE_FREECOM=y
@@ -420,6 +425,8 @@
CONFIG_RTC_CLASS=y
# CONFIG_RTC_DRV_MSM is not set
CONFIG_RTC_DRV_QPNP=y
+CONFIG_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
CONFIG_STAGING=y
CONFIG_ANDROID=y
CONFIG_ANDROID_BINDER_IPC=y
@@ -464,6 +471,7 @@
CONFIG_NLS_ISO8859_1=y
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SYSRQ_SCHED_DEBUG is not set
CONFIG_SCHEDSTATS=y
CONFIG_TIMER_STATS=y
CONFIG_DEBUG_KMEMLEAK=y
@@ -506,4 +514,4 @@
CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
CONFIG_TOUCHSCREEN_GT9XX=y
CONFIG_GT9XX_TOUCHPANEL_DRIVER=y
-CONFIG_DEFAULT_ROW=y
+CONFIG_MSM_RDBG=m
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index 7ea1bd5..b5119b7 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -64,11 +64,6 @@
CONFIG_MSM_MEMORY_DUMP=y
CONFIG_MSM_DLOAD_MODE=y
CONFIG_MSM_ADSP_LOADER=y
-CONFIG_MSM_OCMEM=y
-CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
-CONFIG_MSM_OCMEM_DEBUG=y
-CONFIG_MSM_OCMEM_NONSECURE=y
-CONFIG_MSM_OCMEM_POWER_DISABLE=y
CONFIG_SENSORS_ADSP=y
CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
CONFIG_MSM_BOOT_STATS=y
@@ -79,9 +74,10 @@
CONFIG_ARM_ARCH_TIMER=y
CONFIG_PREEMPT=y
CONFIG_AEABI=y
-CONFIG_HIGHMEM=y
CONFIG_COMPACTION=y
+CONFIG_KSM=y
CONFIG_CC_STACKPROTECTOR=y
+CONFIG_KSM=y
CONFIG_CP_ACCESS=y
CONFIG_USE_OF=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
@@ -210,7 +206,9 @@
CONFIG_BT_HCISMD=y
CONFIG_CFG80211=y
CONFIG_NL80211_TESTMODE=y
+CONFIG_CFG80211_INTERNAL_REGDB=y
CONFIG_CMA=y
+CONFIG_CMA_SIZE_MBYTES=4
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_QSEECOM=y
@@ -246,6 +244,7 @@
CONFIG_DIAG_CHAR=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_MSM=y
+CONFIG_MSM_ADSPRPC=y
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_QUP=y
@@ -313,10 +312,10 @@
CONFIG_MSM_KGSL=y
CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y
CONFIG_FB=y
-CONFIG_FB_VIRTUAL=y
CONFIG_FB_MSM=y
# CONFIG_FB_MSM_BACKLIGHT is not set
CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_MDP3=y
CONFIG_FB_MSM_MDSS_WRITEBACK=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
# CONFIG_LCD_CLASS_DEVICE is not set
@@ -329,6 +328,8 @@
CONFIG_UHID=y
CONFIG_HID_APPLE=y
CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_ELECOM=y
CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_DEBUG_FILES=y
CONFIG_USB_GADGET_DEBUG_FS=y
@@ -355,7 +356,11 @@
CONFIG_RTC_CLASS=y
# CONFIG_RTC_DRV_MSM is not set
CONFIG_RTC_DRV_QPNP=y
+CONFIG_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
CONFIG_STAGING=y
+CONFIG_ZRAM=y
+CONFIG_ZSMALLOC=y
CONFIG_ANDROID=y
CONFIG_ANDROID_BINDER_IPC=y
CONFIG_ASHMEM=y
@@ -371,6 +376,7 @@
CONFIG_QPNP_VIBRATOR=y
CONFIG_QPNP_REVID=y
CONFIG_MSM_IOMMU_V0=y
+CONFIG_SENSORS=y
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT3_FS=y
@@ -385,6 +391,7 @@
CONFIG_NLS_ISO8859_1=y
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SYSRQ_SCHED_DEBUG is not set
CONFIG_SCHEDSTATS=y
CONFIG_TIMER_STATS=y
CONFIG_DEBUG_INFO=y
@@ -420,3 +427,6 @@
CONFIG_LOGCAT_SIZE=64
CONFIG_SENSORS_CAPELLA_CM36283=y
CONFIG_NFC_QNCI=y
+CONFIG_MSM_RDBG=m
+CONFIG_DEVMEM=n
+CONFIG_DEVKMEM=n
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 8e6f5f9..165b841 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -61,11 +61,6 @@
CONFIG_MSM_MEMORY_DUMP=y
CONFIG_MSM_DLOAD_MODE=y
CONFIG_MSM_ADSP_LOADER=y
-CONFIG_MSM_OCMEM=y
-CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
-CONFIG_MSM_OCMEM_DEBUG=y
-CONFIG_MSM_OCMEM_NONSECURE=y
-CONFIG_MSM_OCMEM_POWER_DISABLE=y
CONFIG_SENSORS_ADSP=y
CONFIG_MSM_RTB=y
CONFIG_MSM_RTB_SEPARATE_CPUS=y
@@ -80,9 +75,10 @@
CONFIG_ARM_ARCH_TIMER=y
CONFIG_PREEMPT=y
CONFIG_AEABI=y
-CONFIG_HIGHMEM=y
CONFIG_COMPACTION=y
+CONFIG_KSM=y
CONFIG_CC_STACKPROTECTOR=y
+CONFIG_KSM=y
CONFIG_CP_ACCESS=y
CONFIG_USE_OF=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
@@ -213,6 +209,7 @@
CONFIG_CFG80211_INTERNAL_REGDB=y
CONFIG_NL80211_TESTMODE=y
CONFIG_CMA=y
+CONFIG_CMA_SIZE_MBYTES=4
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_QSEECOM=y
@@ -248,6 +245,7 @@
CONFIG_DIAG_CHAR=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_MSM=y
+CONFIG_MSM_ADSPRPC=y
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_QUP=y
@@ -339,6 +337,7 @@
CONFIG_FB_MSM=y
# CONFIG_FB_MSM_BACKLIGHT is not set
CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_MDP3=y
CONFIG_FB_MSM_MDSS_WRITEBACK=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
# CONFIG_LCD_CLASS_DEVICE is not set
@@ -351,6 +350,8 @@
CONFIG_UHID=y
CONFIG_HID_APPLE=y
CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_ELECOM=y
CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_DEBUG_FILES=y
CONFIG_USB_GADGET_DEBUG_FS=y
@@ -378,7 +379,11 @@
CONFIG_RTC_CLASS=y
# CONFIG_RTC_DRV_MSM is not set
CONFIG_RTC_DRV_QPNP=y
+CONFIG_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
CONFIG_STAGING=y
+CONFIG_ZRAM=y
+CONFIG_ZSMALLOC=y
CONFIG_ANDROID=y
CONFIG_ANDROID_BINDER_IPC=y
CONFIG_ASHMEM=y
@@ -408,6 +413,7 @@
CONFIG_CORESIGHT_WCN_ETM=y
CONFIG_CORESIGHT_RPM_ETM=y
CONFIG_CORESIGHT_EVENT=m
+CONFIG_SENSORS=y
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT3_FS=y
@@ -422,6 +428,7 @@
CONFIG_NLS_ISO8859_1=y
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SYSRQ_SCHED_DEBUG is not set
CONFIG_SCHEDSTATS=y
CONFIG_TIMER_STATS=y
CONFIG_DEBUG_KMEMLEAK=y
@@ -472,3 +479,4 @@
CONFIG_SENSORS_STK3X1X=y
CONFIG_SENSORS_MMA8X5X=y
CONFIG_SENSORS_CAPELLA_CM36283=y
+CONFIG_MSM_RDBG=m
diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig
index da4de08..b4f21ad 100644
--- a/arch/arm/configs/msm8660-perf_defconfig
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -461,3 +461,5 @@
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=m
CONFIG_CRYPTO_DEV_QCEDEV=m
+CONFIG_DEVMEM=n
+CONFIG_DEVKMEM=n
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 4610597..fd8245f 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -554,3 +554,5 @@
CONFIG_CRYPTO_DEV_QCE=m
CONFIG_CRYPTO_DEV_QCEDEV=m
CONFIG_CRC_CCITT=y
+CONFIG_DEVMEM=n
+CONFIG_DEVKMEM=n
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
old mode 100644
new mode 100755
index fb05a08..737d98d
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -98,12 +98,14 @@
CONFIG_CC_STACKPROTECTOR=y
CONFIG_CP_ACCESS=y
CONFIG_USE_OF=y
+CONFIG_SECURE_TOUCH=y
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_BOOST=y
CONFIG_CPU_IDLE=y
CONFIG_VFP=y
CONFIG_NEON=y
@@ -243,6 +245,7 @@
CONFIG_MSM_BT_POWER=y
CONFIG_CFG80211=y
CONFIG_NL80211_TESTMODE=y
+CONFIG_CFG80211_INTERNAL_REGDB=y
CONFIG_RFKILL=y
CONFIG_GENLOCK=y
CONFIG_GENLOCK_MISCDEVICE=y
@@ -298,6 +301,7 @@
CONFIG_DIAG_CHAR=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_MSM=y
+CONFIG_MSM_ADSPRPC=y
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_QUP=y
@@ -386,6 +390,7 @@
CONFIG_HID_APPLE=y
CONFIG_HID_MAGICMOUSE=y
CONFIG_HID_MICROSOFT=y
+CONFIG_HID_ELECOM=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
CONFIG_USB_SUSPEND=y
CONFIG_USB_XHCI_HCD=y
@@ -435,6 +440,8 @@
CONFIG_RTC_CLASS=y
# CONFIG_RTC_DRV_MSM is not set
CONFIG_RTC_DRV_QPNP=y
+CONFIG_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
CONFIG_STAGING=y
CONFIG_ANDROID=y
CONFIG_ANDROID_BINDER_IPC=y
@@ -472,6 +479,7 @@
CONFIG_NLS_ISO8859_1=y
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SYSRQ_SCHED_DEBUG is not set
CONFIG_SCHEDSTATS=y
CONFIG_TIMER_STATS=y
# CONFIG_DEBUG_PREEMPT is not set
@@ -492,8 +500,12 @@
CONFIG_CRYPTO_MD4=y
CONFIG_CRYPTO_ARC4=y
CONFIG_CRYPTO_TWOFISH=y
+CONFIG_NFC_QNCI=y
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=y
CONFIG_CRYPTO_DEV_QCEDEV=y
CONFIG_SND_SOC_MSM_HDMI_CODEC_RX=y
CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y
+CONFIG_MSM_RDBG=m
+CONFIG_DEVMEM=n
+CONFIG_DEVKMEM=n
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
old mode 100644
new mode 100755
index 8f6f52f..e5be6d5
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -82,7 +82,6 @@
CONFIG_MSM_L1_ERR_LOG=y
CONFIG_MSM_L2_ERP_PRINT_ACCESS_ERRORS=y
CONFIG_MSM_L2_ERP_PORT_PANIC=y
-CONFIG_MSM_L2_ERP_1BIT_PANIC=y
CONFIG_MSM_L2_ERP_2BIT_PANIC=y
CONFIG_MSM_CACHE_DUMP=y
CONFIG_MSM_CACHE_DUMP_ON_PANIC=y
@@ -104,12 +103,14 @@
CONFIG_CC_STACKPROTECTOR=y
CONFIG_CP_ACCESS=y
CONFIG_USE_OF=y
+CONFIG_SECURE_TOUCH=y
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_BOOST=y
CONFIG_CPU_IDLE=y
CONFIG_VFP=y
CONFIG_NEON=y
@@ -306,6 +307,7 @@
CONFIG_DIAG_CHAR=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_MSM=y
+CONFIG_MSM_ADSPRPC=y
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_QUP=y
@@ -394,6 +396,7 @@
CONFIG_HID_APPLE=y
CONFIG_HID_MAGICMOUSE=y
CONFIG_HID_MICROSOFT=y
+CONFIG_HID_ELECOM=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
CONFIG_USB_SUSPEND=y
CONFIG_USB_XHCI_HCD=y
@@ -443,6 +446,8 @@
CONFIG_RTC_CLASS=y
# CONFIG_RTC_DRV_MSM is not set
CONFIG_RTC_DRV_QPNP=y
+CONFIG_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
CONFIG_STAGING=y
CONFIG_ANDROID=y
CONFIG_ANDROID_BINDER_IPC=y
@@ -498,6 +503,7 @@
CONFIG_MAGIC_SYSRQ=y
CONFIG_LOCKUP_DETECTOR=y
# CONFIG_DETECT_HUNG_TASK is not set
+# CONFIG_SYSRQ_SCHED_DEBUG is not set
CONFIG_SCHEDSTATS=y
CONFIG_TIMER_STATS=y
CONFIG_DEBUG_KMEMLEAK=y
@@ -532,8 +538,10 @@
CONFIG_CRYPTO_MD4=y
CONFIG_CRYPTO_ARC4=y
CONFIG_CRYPTO_TWOFISH=y
+CONFIG_NFC_QNCI=y
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=y
CONFIG_CRYPTO_DEV_QCEDEV=y
CONFIG_SND_SOC_MSM_HDMI_CODEC_RX=y
CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y
+CONFIG_MSM_RDBG=m
diff --git a/arch/arm/configs/msm9625-perf_defconfig b/arch/arm/configs/msm9625-perf_defconfig
index 9a5aaf0..4c0a82d 100644
--- a/arch/arm/configs/msm9625-perf_defconfig
+++ b/arch/arm/configs/msm9625-perf_defconfig
@@ -319,3 +319,5 @@
CONFIG_CRC_CCITT=y
CONFIG_LIBCRC32C=y
CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
+CONFIG_DEVMEM=n
+CONFIG_DEVKMEM=n
diff --git a/arch/arm/configs/msmkrypton_defconfig b/arch/arm/configs/msmkrypton_defconfig
index b04acb5..380a730 100644
--- a/arch/arm/configs/msmkrypton_defconfig
+++ b/arch/arm/configs/msmkrypton_defconfig
@@ -133,6 +133,7 @@
CONFIG_NLS_ISO8859_1=y
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SYSRQ_SCHED_DEBUG is not set
CONFIG_SCHEDSTATS=y
CONFIG_TIMER_STATS=y
# CONFIG_DEBUG_PREEMPT is not set
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
index 9ba1436..0e8f4916 100644
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -49,6 +49,13 @@
*
* Unconditionally clean and invalidate the entire cache.
*
+ * flush_kern_louis()
+ *
+ * Flush data cache levels up to the level of unification
+ * inner shareable and invalidate the I-cache.
+ * Only needed from v7 onwards, falls back to flush_cache_all()
+ * for all other processor versions.
+ *
* flush_user_all()
*
* Clean and invalidate all user space cache entries
@@ -112,6 +119,7 @@
struct cpu_cache_fns {
void (*flush_icache_all)(void);
void (*flush_kern_all)(void);
+ void (*flush_kern_louis)(void);
void (*flush_user_all)(void);
void (*flush_user_range)(unsigned long, unsigned long, unsigned int);
@@ -136,6 +144,7 @@
#define __cpuc_flush_icache_all cpu_cache.flush_icache_all
#define __cpuc_flush_kern_all cpu_cache.flush_kern_all
+#define __cpuc_flush_kern_louis cpu_cache.flush_kern_louis
#define __cpuc_flush_user_all cpu_cache.flush_user_all
#define __cpuc_flush_user_range cpu_cache.flush_user_range
#define __cpuc_coherent_kern_range cpu_cache.coherent_kern_range
@@ -158,6 +167,7 @@
extern void __cpuc_flush_icache_all(void);
extern void __cpuc_flush_kern_all(void);
+extern void __cpuc_flush_kern_louis(void);
extern void __cpuc_flush_user_all(void);
extern void __cpuc_flush_user_range(unsigned long, unsigned long, unsigned int);
extern void __cpuc_coherent_kern_range(unsigned long, unsigned long);
@@ -225,6 +235,11 @@
__flush_icache_preferred();
}
+/*
+ * Flush caches up to Level of Unification Inner Shareable
+ */
+#define flush_cache_louis() __cpuc_flush_kern_louis()
+
#define flush_cache_all() __cpuc_flush_kern_all()
static inline void vivt_flush_cache_mm(struct mm_struct *mm)
diff --git a/arch/arm/include/asm/glue-cache.h b/arch/arm/include/asm/glue-cache.h
index 7e30874..2d6a7de 100644
--- a/arch/arm/include/asm/glue-cache.h
+++ b/arch/arm/include/asm/glue-cache.h
@@ -132,6 +132,7 @@
#ifndef MULTI_CACHE
#define __cpuc_flush_icache_all __glue(_CACHE,_flush_icache_all)
#define __cpuc_flush_kern_all __glue(_CACHE,_flush_kern_cache_all)
+#define __cpuc_flush_kern_louis __glue(_CACHE,_flush_kern_cache_louis)
#define __cpuc_flush_user_all __glue(_CACHE,_flush_user_cache_all)
#define __cpuc_flush_user_range __glue(_CACHE,_flush_user_cache_range)
#define __cpuc_coherent_kern_range __glue(_CACHE,_coherent_kern_range)
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
index 92e4f18..8c0a923 100644
--- a/arch/arm/kernel/arch_timer.c
+++ b/arch/arm/kernel/arch_timer.c
@@ -480,7 +480,7 @@
if (!clk)
return -ENOMEM;
- clk->features = CLOCK_EVT_FEAT_ONESHOT;
+ clk->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_DYNIRQ;
clk->name = "arch_mem_timer";
clk->rating = 400;
clk->set_mode = arch_timer_set_mode_mem;
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index e000e5e..edb73b4 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -440,12 +440,18 @@
*/
thumb = handler & 1;
+#if __LINUX_ARM_ARCH__ >= 7
+ /*
+ * Clear the If-Then Thumb-2 execution state
+ * ARM spec requires this to be all 000s in ARM mode
+ * Snapdragon S4/Krait misbehaves on a Thumb=>ARM
+ * signal transition without this.
+ */
+ cpsr &= ~PSR_IT_MASK;
+#endif
+
if (thumb) {
cpsr |= PSR_T_BIT;
-#if __LINUX_ARM_ARCH__ >= 7
- /* clear the If-Then Thumb-2 execution state */
- cpsr &= ~PSR_IT_MASK;
-#endif
} else
cpsr &= ~PSR_T_BIT;
}
diff --git a/arch/arm/kernel/suspend.c b/arch/arm/kernel/suspend.c
index 1794cc3..358bca3 100644
--- a/arch/arm/kernel/suspend.c
+++ b/arch/arm/kernel/suspend.c
@@ -17,6 +17,8 @@
*/
void __cpu_suspend_save(u32 *ptr, u32 ptrsz, u32 sp, u32 *save_ptr)
{
+ u32 *ctx = ptr;
+
*save_ptr = virt_to_phys(ptr);
/* This must correspond to the LDM in cpu_resume() assembly */
@@ -26,7 +28,20 @@
cpu_do_suspend(ptr);
- flush_cache_all();
+ flush_cache_louis();
+
+ /*
+ * flush_cache_louis does not guarantee that
+ * save_ptr and ptr are cleaned to main memory,
+ * just up to the Level of Unification Inner Shareable.
+ * Since the context pointer and context itself
+ * are to be retrieved with the MMU off that
+ * data must be cleaned from all cache levels
+ * to main memory using "area" cache primitives.
+ */
+ __cpuc_flush_dcache_area(ctx, ptrsz);
+ __cpuc_flush_dcache_area(save_ptr, sizeof(*save_ptr));
+
outer_clean_range(*save_ptr, *save_ptr + ptrsz);
outer_clean_range(virt_to_phys(save_ptr),
virt_to_phys(save_ptr) + sizeof(*save_ptr));
diff --git a/arch/arm/lib/memset.S b/arch/arm/lib/memset.S
index 650d592..94b0650 100644
--- a/arch/arm/lib/memset.S
+++ b/arch/arm/lib/memset.S
@@ -14,27 +14,15 @@
.text
.align 5
- .word 0
-
-1: subs r2, r2, #4 @ 1 do we have enough
- blt 5f @ 1 bytes to align with?
- cmp r3, #2 @ 1
- strltb r1, [r0], #1 @ 1
- strleb r1, [r0], #1 @ 1
- strb r1, [r0], #1 @ 1
- add r2, r2, r3 @ 1 (r2 = r2 - (4 - r3))
-/*
- * The pointer is now aligned and the length is adjusted. Try doing the
- * memset again.
- */
ENTRY(memset)
ands r3, r0, #3 @ 1 unaligned?
- bne 1b @ 1
+ mov ip, r0 @ preserve r0 as return value
+ bne 6f @ 1
/*
- * we know that the pointer in r0 is aligned to a word boundary.
+ * we know that the pointer in ip is aligned to a word boundary.
*/
- orr r1, r1, r1, lsl #8
+1: orr r1, r1, r1, lsl #8
orr r1, r1, r1, lsl #16
mov r3, r1
cmp r2, #16
@@ -43,29 +31,28 @@
#if ! CALGN(1)+0
/*
- * We need an extra register for this loop - save the return address and
- * use the LR
+ * We need 2 extra registers for this loop - use r8 and the LR
*/
- str lr, [sp, #-4]!
- mov ip, r1
+ stmfd sp!, {r8, lr}
+ mov r8, r1
mov lr, r1
2: subs r2, r2, #64
- stmgeia r0!, {r1, r3, ip, lr} @ 64 bytes at a time.
- stmgeia r0!, {r1, r3, ip, lr}
- stmgeia r0!, {r1, r3, ip, lr}
- stmgeia r0!, {r1, r3, ip, lr}
+ stmgeia ip!, {r1, r3, r8, lr} @ 64 bytes at a time.
+ stmgeia ip!, {r1, r3, r8, lr}
+ stmgeia ip!, {r1, r3, r8, lr}
+ stmgeia ip!, {r1, r3, r8, lr}
bgt 2b
- ldmeqfd sp!, {pc} @ Now <64 bytes to go.
+ ldmeqfd sp!, {r8, pc} @ Now <64 bytes to go.
/*
* No need to correct the count; we're only testing bits from now on
*/
tst r2, #32
- stmneia r0!, {r1, r3, ip, lr}
- stmneia r0!, {r1, r3, ip, lr}
+ stmneia ip!, {r1, r3, r8, lr}
+ stmneia ip!, {r1, r3, r8, lr}
tst r2, #16
- stmneia r0!, {r1, r3, ip, lr}
- ldr lr, [sp], #4
+ stmneia ip!, {r1, r3, r8, lr}
+ ldmfd sp!, {r8, lr}
#else
@@ -74,54 +61,63 @@
* whole cache lines at once.
*/
- stmfd sp!, {r4-r7, lr}
+ stmfd sp!, {r4-r8, lr}
mov r4, r1
mov r5, r1
mov r6, r1
mov r7, r1
- mov ip, r1
+ mov r8, r1
mov lr, r1
cmp r2, #96
- tstgt r0, #31
+ tstgt ip, #31
ble 3f
- and ip, r0, #31
- rsb ip, ip, #32
- sub r2, r2, ip
- movs ip, ip, lsl #(32 - 4)
- stmcsia r0!, {r4, r5, r6, r7}
- stmmiia r0!, {r4, r5}
- tst ip, #(1 << 30)
- mov ip, r1
- strne r1, [r0], #4
+ and r8, ip, #31
+ rsb r8, r8, #32
+ sub r2, r2, r8
+ movs r8, r8, lsl #(32 - 4)
+ stmcsia ip!, {r4, r5, r6, r7}
+ stmmiia ip!, {r4, r5}
+ tst r8, #(1 << 30)
+ mov r8, r1
+ strne r1, [ip], #4
3: subs r2, r2, #64
- stmgeia r0!, {r1, r3-r7, ip, lr}
- stmgeia r0!, {r1, r3-r7, ip, lr}
+ stmgeia ip!, {r1, r3-r8, lr}
+ stmgeia ip!, {r1, r3-r8, lr}
bgt 3b
- ldmeqfd sp!, {r4-r7, pc}
+ ldmeqfd sp!, {r4-r8, pc}
tst r2, #32
- stmneia r0!, {r1, r3-r7, ip, lr}
+ stmneia ip!, {r1, r3-r8, lr}
tst r2, #16
- stmneia r0!, {r4-r7}
- ldmfd sp!, {r4-r7, lr}
+ stmneia ip!, {r4-r7}
+ ldmfd sp!, {r4-r8, lr}
#endif
4: tst r2, #8
- stmneia r0!, {r1, r3}
+ stmneia ip!, {r1, r3}
tst r2, #4
- strne r1, [r0], #4
+ strne r1, [ip], #4
/*
* When we get here, we've got less than 4 bytes to zero. We
* may have an unaligned pointer as well.
*/
5: tst r2, #2
- strneb r1, [r0], #1
- strneb r1, [r0], #1
+ strneb r1, [ip], #1
+ strneb r1, [ip], #1
tst r2, #1
- strneb r1, [r0], #1
+ strneb r1, [ip], #1
mov pc, lr
+
+6: subs r2, r2, #4 @ 1 do we have enough
+ blt 5b @ 1 bytes to align with?
+ cmp r3, #2 @ 1
+ strltb r1, [ip], #1 @ 1
+ strleb r1, [ip], #1 @ 1
+ strb r1, [ip], #1 @ 1
+ add r2, r2, r3 @ 1 (r2 = r2 - (4 - r3))
+ b 1b
ENDPROC(memset)
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 87c2f8c..f2d65fe 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -261,12 +261,14 @@
select MSM_GPIOMUX
select MULTI_IRQ_HANDLER
select MSM_MULTIMEDIA_USE_ION
+ select PM_DEVFREQ
+ select MSM_DEVFREQ_CPUBW
select MSM_PIL
select MSM_SPM_V2
select MSM_L2_SPM
select MSM_NATIVE_RESTART
select MSM_RESTART_V2
- select MSM_PM8X60 if PM
+ select MSM_PM if PM
select MAY_HAVE_SPARSE_IRQ
select SPARSE_IRQ
select MSM_RPM_SMD
@@ -280,11 +282,11 @@
select MEMORY_HOLE_CARVEOUT
select MSM_RPM_STATS_LOG
select QMI_ENCDEC
- select DONT_MAP_HOLE_AFTER_MEMBANK0
select MSM_ULTRASOUND_B
select MSM_RPM_LOG
select ARCH_WANT_KMAP_ATOMIC_FLUSH
select KRAIT_REGULATOR
+ select ENABLE_VMALLOC_SAVINGS
config ARCH_APQ8084
bool "APQ8084"
@@ -297,7 +299,7 @@
select MULTI_IRQ_HANDLER
select MSM_NATIVE_RESTART
select MSM_RESTART_V2
- select MSM_PM8X60 if PM
+ select MSM_PM if PM
select MAY_HAVE_SPARSE_IRQ
select SPARSE_IRQ
select REGULATOR
@@ -305,16 +307,19 @@
select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE
select ARCH_WANT_KMAP_ATOMIC_FLUSH
select MEMORY_HOLE_CARVEOUT
- select DONT_MAP_HOLE_AFTER_MEMBANK0
select QMI_ENCDEC
select MSM_SPM_V2
select MSM_L2_SPM
- select MSM_PM8X60 if PM
select MSM_RPM_SMD
+ select PM_DEVFREQ
+ select MSM_DEVFREQ_CPUBW
+ select ENABLE_VMALLOC_SAVINGS
config ARCH_MPQ8092
bool "MPQ8092"
select ARCH_MSM_KRAITMP
+ select PM_DEVFREQ
+ select MSM_DEVFREQ_CPUBW
select GPIO_MSM_V3
select ARM_GIC
select MULTI_IRQ_HANDLER
@@ -333,6 +338,8 @@
select MSM_SCM
select MSM_GPIOMUX
select MULTI_IRQ_HANDLER
+ select PM_DEVFREQ
+ select MSM_DEVFREQ_CPUBW
select MSM_PIL
select MSM_NATIVE_RESTART
select MSM_RESTART_V2
@@ -428,13 +435,16 @@
select MSM_NATIVE_RESTART
select MSM_RESTART_V2
select MSM_SPM_V2
- select MSM_PM8X60 if PM
+ select MSM_PM if PM
select MULTI_IRQ_HANDLER
select GPIO_MSM_V3
select MAY_HAVE_SPARSE_IRQ
select SPARSE_IRQ
select MEMORY_HOLE_CARVEOUT
select QMI_ENCDEC
+ select MSM_CORTEX_A7
+ select PM_DEVFREQ
+ select MSM_DEVFREQ_CPUBW
config ARCH_MSM8610
bool "MSM8610"
@@ -458,12 +468,14 @@
select MSM_RPM_SMD
select MSM_SPM_V2
select MSM_L2_SPM
- select MSM_PM8X60 if PM
+ select MSM_PM if PM
select MEMORY_HOLE_CARVEOUT
- select DONT_MAP_HOLE_AFTER_MEMBANK0
select MSM_BUS_SCALING
+ select MSM_CORTEX_A7
select CPU_FREQ_MSM
select CPU_FREQ
+ select PM_DEVFREQ
+ select MSM_DEVFREQ_CPUBW
select MSM_PIL
select MSM_RUN_QUEUE_STATS
select ARM_HAS_SG_CHAIN
@@ -498,12 +510,14 @@
select MSM_RPM_SMD
select MSM_SPM_V2
select MSM_L2_SPM
- select MSM_PM8X60 if PM
+ select MSM_PM if PM
select MEMORY_HOLE_CARVEOUT
- select DONT_MAP_HOLE_AFTER_MEMBANK0
select MSM_BUS_SCALING
+ select MSM_CORTEX_A7
select CPU_FREQ_MSM
select CPU_FREQ
+ select PM_DEVFREQ
+ select MSM_DEVFREQ_CPUBW
select MSM_PIL
select MSM_RUN_QUEUE_STATS
select ARM_HAS_SG_CHAIN
@@ -515,6 +529,7 @@
select MSM_RPM_LOG
select MSM_RPM_STATS_LOG
select ARCH_WANT_KMAP_ATOMIC_FLUSH
+ select ENABLE_VMALLOC_SAVINGS
config ARCH_MSMSAMARIUM
bool "MSMSAMARIUM"
@@ -523,6 +538,8 @@
select ARM_GIC
select CPU_V7
select MSM_SCM
+ select PM_DEVFREQ
+ select MSM_DEVFREQ_CPUBW
select MSM_PIL
select MSM_GPIOMUX
select MULTI_IRQ_HANDLER
@@ -530,7 +547,7 @@
select MSM_L2_SPM
select MSM_NATIVE_RESTART
select MSM_RESTART_V2
- select MSM_PM8X60 if PM
+ select MSM_PM if PM
select MAY_HAVE_SPARSE_IRQ
select SPARSE_IRQ
select ARM_HAS_SG_CHAIN
@@ -572,6 +589,10 @@
config ARCH_MSM_KRAIT
bool
select ARM_L1_CACHE_SHIFT_6
+ select DEVFREQ_GOV_MSM_CPUBW_HWMON
+
+config MSM_CORTEX_A7
+ bool
config MSM_SMP
select HAVE_SMP
@@ -655,7 +676,7 @@
config MSM_LPM_TEST
bool "Low Power Mode test framework"
depends on MSM_RPM || MSM_RPM_SMD
- depends on MSM_PM8X60
+ depends on MSM_PM
help
LPM_TEST is a test framework that assists in exercising the low
power mode algorithm on MSM targets. This test framework tracks
@@ -1558,20 +1579,6 @@
Enables the PCIe functionality by configures PCIe core on
MSM chipset and by enabling the ARM PCI framework extension.
-config MSM_RPC_SDIO_XPRT
- depends on MSM_SDIO_AL
- default y
- bool "MSM SDIO XPRT Layer"
- help
- SDIO Transport Layer for RPC Rouer
-
-config MSM_RPC_SDIO_DEBUG
- depends on MSM_RPC_SDIO_XPRT
- default y
- bool "MSM SDIO XPRT debug support"
- help
- Support for debugging SDIO XPRT
-
config MSM_SMD_DEBUG
depends on MSM_SMD
default y
@@ -1580,21 +1587,6 @@
Support for debugging the SMD for communication
between the ARM9 and ARM11
-config MSM_SDIO_AL
- depends on ((ARCH_MSM7X30 || MACH_MSM8X60_FUSN_FFA || MACH_TYPE_MSM8X60_FUSION) && HAS_WAKELOCK)
- default y
- tristate "SDIO-Abstraction-Layer"
- help
- Support MSM<->MDM Communication over SDIO bus.
- MDM SDIO-Client should have pipes support.
-
-config MSM_SDIO_DMUX
- bool "SDIO Data Mux Driver"
- depends on MSM_SDIO_AL
- default n
- help
- Support Muxed Data Channels over SDIO interface.
-
config MSM_BAM_DMUX
bool "BAM Data Mux Driver"
depends on SPS
@@ -1675,16 +1667,6 @@
If in doubt, say yes.
-config MSM_SDIO_TTY
- bool "SDIO TTY Driver"
- depends on MSM_SDIO_AL
- default n
- help
- Provides a TTY driver SDIO TTY
- This driver can be used by user space
- applications for passing data through the
- SDIO interface.
-
config MSM_SMD_TTY
bool "SMD TTY Driver"
depends on MSM_SMD
@@ -1712,13 +1694,6 @@
If in doubt, say yes.
-config MSM_SDIO_CMUX
- bool "SDIO CMUX Driver"
- depends on MSM_SDIO_AL
- default n
- help
- Provides a Muxed port interface over SDIO QMI
-
config MSM_DSPS
bool "Sensors DSPS driver"
depends on (MSM_PIL && (ARCH_MSM8X60 || ARCH_MSM8960))
@@ -1731,13 +1706,6 @@
The number of clocks and their name may vary between targets.
It also triggers the PIL to load the DSPS firmware.
-config MSM_SDIO_CTL
- bool "SDIO CTL Driver"
- depends on MSM_SDIO_CMUX
- default n
- help
- Provides a binary SDIO control port interface.
-
config MSM_ONCRPCROUTER
depends on MSM_SMD
default n
@@ -1886,15 +1854,6 @@
Collects performance statistics and shows this information
through a debugfs file rmt_storage_stats.
-config MSM_SDIO_SMEM
- depends on MSM_SDIO_AL
- default n
- bool "SDIO SMEM for remote storage"
- help
- Copies data from remote MDM9K memory to local MSM8x60
- memory. Used by remote storage client to shadow
- MDM9K filesystem.
-
config MSM_DALRPC
bool "DAL RPC support"
default n
@@ -1929,6 +1888,20 @@
endif # CPU_FREQ_MSM
+config MSM_DEVFREQ_CPUBW
+ bool "Devfreq device for CPU<->DDR IB/AB BW voting"
+ depends on PM_DEVFREQ
+ select DEVFREQ_GOV_PERFORMANCE
+ select DEVFREQ_GOV_POWERSAVE
+ select DEVFREQ_GOV_USERSPACE
+ select DEVFREQ_GOV_MSM_CPUFREQ
+ default n
+ help
+ Different devfreq governors use this devfreq device to make CPU to
+ DDR IB/AB bandwidth votes. This driver provides a SoC topology
+ agnostic interface to so that some of the devfreq governors can be
+ shared across SoCs.
+
config MSM_AVS_HW
bool "Enable Adaptive Voltage Scaling (AVS)"
default n
@@ -2431,7 +2404,7 @@
depends on PM
bool
-config MSM_PM8X60
+config MSM_PM
depends on PM
bool
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index c44dbc7..9c9fffc 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -23,11 +23,9 @@
endif
obj-y += acpuclock.o
+obj-$(CONFIG_MSM_CORTEX_A7) += clock-a7.o
obj-$(CONFIG_HW_PERF_EVENTS) += perf_trace_counters.o
-obj-$(CONFIG_ARCH_MSM_KRAIT) += acpuclock-krait.o clock-krait.o
-ifdef CONFIG_ARCH_MSM_KRAIT
-obj-$(CONFIG_DEBUG_FS) += acpuclock-krait-debug.o
-endif
+obj-$(CONFIG_ARCH_MSM_KRAIT) += clock-krait.o
obj-$(CONFIG_ARCH_MSM7X27) += acpuclock-7627.o acpuclock-8625q.o clock-pll.o
obj-$(CONFIG_ARCH_MSM_SCORPIONMP) += perf_event_msm_l2.o
ifndef CONFIG_OF
@@ -100,10 +98,6 @@
obj-$(CONFIG_ARCH_FSM9XXX) += sirc-fsm9xxx.o
obj-$(CONFIG_MSM_FIQ_SUPPORT) += fiq_glue.o
obj-$(CONFIG_MACH_TROUT) += board-trout-rfkill.o
-obj-$(CONFIG_MSM_SDIO_AL) += sdio_al.o
-obj-$(CONFIG_MSM_SDIO_AL) += sdio_al_test.o
-obj-$(CONFIG_MSM_SDIO_AL) += sdio_al_dloader.o
-obj-$(CONFIG_MSM_SDIO_DMUX) += sdio_dmux.o
obj-$(CONFIG_MSM_BAM_DMUX) += bam_dmux.o
obj-$(CONFIG_MSM_SMD_LOGGING) += smem_log.o
obj-$(CONFIG_MSM_IPC_LOGGING) += ipc_logging.o
@@ -120,13 +114,10 @@
obj-$(CONFIG_ARCH_MSM9615) += nand_partitions.o
obj-$(CONFIG_ARCH_MSM8625) += nand_partitions.o
obj-$(CONFIG_ARCH_MSM7X27A) += nand_partitions.o
-obj-$(CONFIG_MSM_SDIO_TTY) += sdio_tty.o
obj-$(CONFIG_MSM_SMD_TTY) += smd_tty.o
obj-$(CONFIG_MSM_SMD_QMI) += smd_qmi.o
obj-$(CONFIG_MSM_SMD_PKT) += smd_pkt.o
-obj-$(CONFIG_MSM_SDIO_CMUX) += sdio_cmux.o
obj-$(CONFIG_MSM_DSPS) += msm_dsps.o
-obj-$(CONFIG_MSM_SDIO_CTL) += sdio_ctl.o
obj-$(CONFIG_MSM_SMD_NMEA) += smd_nmea.o
obj-$(CONFIG_MSM_RESET_MODEM) += reset_modem.o
obj-$(CONFIG_MSM_IPC_ROUTER_SMD_XPRT) += ipc_router_smd_xprt.o
@@ -143,7 +134,6 @@
obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_clients.o
obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_xdr.o
obj-$(CONFIG_MSM_ONCRPCROUTER) += rpcrouter_smd_xprt.o
-obj-$(CONFIG_MSM_RPC_SDIO_XPRT) += rpcrouter_sdio_xprt.o
obj-$(CONFIG_MSM_RPC_PING) += ping_mdm_rpc_client.o
obj-$(CONFIG_MSM_RPC_PROC_COMM_TEST) += proc_comm_test.o
obj-$(CONFIG_MSM_RPC_PING) += ping_mdm_rpc_client.o ping_apps_server.o
@@ -161,7 +151,6 @@
obj-$(CONFIG_MSM_AUDIO_QDSP6V2) += qdsp6v2/
obj-$(CONFIG_MSM_HW3D) += hw3d.o
obj-$(CONFIG_PM) += pm-boot.o
-obj-$(CONFIG_MSM_PM8X60) += pm-8x60.o pm-data.o
obj-$(CONFIG_MSM_IDLE_STATS) += pm-stats.o
obj-$(CONFIG_MSM_PM2) += pm2.o
obj-$(CONFIG_MSM_NOPM) += no-pm.o
@@ -207,7 +196,7 @@
endif
obj-$(CONFIG_MSM_SYSMON_COMM) += sysmon.o
-obj-$(CONFIG_CPU_IDLE) += cpuidle.o
+#obj-$(CONFIG_CPU_IDLE) += cpuidle.o
ifdef CONFIG_MSM_CAMERA_V4L2
obj-$(CONFIG_ARCH_MSM8X60) += board-msm8x60-camera.o
@@ -258,12 +247,10 @@
obj-$(CONFIG_MACH_MSM7X25_FFA) += board-msm7x27.o devices-msm7x25.o
obj-$(CONFIG_ARCH_MSM8960) += clock-local.o clock-dss-8960.o clock-8960.o clock-rpm.o clock-pll.o
obj-$(CONFIG_ARCH_MSM8960) += footswitch-8x60.o
-obj-$(CONFIG_ARCH_MSM8960) += acpuclock-8960.o acpuclock-8960ab.o
obj-$(CONFIG_ARCH_MSM8960) += memory_topology.o
obj-$(CONFIG_ARCH_MSM8960) += saw-regulator.o
obj-$(CONFIG_ARCH_MSM8960) += devices-8960.o
obj-$(CONFIG_ARCH_APQ8064) += devices-8960.o devices-8064.o
-obj-$(CONFIG_ARCH_APQ8064) += acpuclock-8064.o
board-8960-all-objs += board-8960.o board-8960-camera.o board-8960-display.o board-8960-pmic.o board-8960-storage.o board-8960-gpiomux.o
board-8930-all-objs += board-8930.o board-8930-camera.o board-8930-display.o board-8930-pmic.o board-8930-storage.o board-8930-gpiomux.o devices-8930.o board-8930-gpu.o
board-8064-all-objs += board-8064.o board-8064-pmic.o board-8064-storage.o board-8064-gpiomux.o board-8064-camera.o board-8064-display.o board-8064-gpu.o
@@ -286,7 +273,7 @@
obj-$(CONFIG_ARCH_APQ8084) += board-8084.o board-8084-gpiomux.o
obj-$(CONFIG_ARCH_APQ8084) += clock-8084.o
obj-$(CONFIG_ARCH_MSM8974) += board-8974.o board-8974-gpiomux.o
-obj-$(CONFIG_ARCH_MSM8974) += acpuclock-8974.o
+obj-$(CONFIG_ARCH_MSM8974) += clock-krait-8974.o
obj-$(CONFIG_ARCH_MSM8974) += clock-local2.o clock-pll.o clock-8974.o clock-rpm.o clock-voter.o clock-mdss-8974.o
obj-$(CONFIG_ARCH_MSM8974) += gdsc.o
obj-$(CONFIG_ARCH_MSM9625) += gdsc.o
@@ -299,7 +286,6 @@
obj-$(CONFIG_ARCH_MSMSAMARIUM) += board-samarium.o board-samarium-gpiomux.o
obj-$(CONFIG_ARCH_MSM9625) += board-9625.o board-9625-gpiomux.o
obj-$(CONFIG_ARCH_MSM9625) += clock-local2.o clock-pll.o clock-9625.o clock-rpm.o clock-voter.o acpuclock-9625.o acpuclock-cortex.o
-obj-$(CONFIG_ARCH_MSM8930) += acpuclock-8930.o acpuclock-8627.o acpuclock-8930aa.o acpuclock-8930ab.o
obj-$(CONFIG_ARCH_MPQ8092) += board-8092.o board-8092-gpiomux.o
obj-$(CONFIG_ARCH_MPQ8092) += clock-8092.o
obj-$(CONFIG_ARCH_MSM8226) += board-8226.o board-8226-gpiomux.o
@@ -311,6 +297,8 @@
obj-$(CONFIG_ARCH_MSM8610) += clock-dsi-8610.o
obj-$(CONFIG_ARCH_MSMKRYPTON) += clock-local2.o clock-pll.o clock-krypton.o clock-rpm.o clock-voter.o
+obj-$(CONFIG_MSM_PM) += msm-pm.o pm-data.o
+
obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire.o board-sapphire-gpio.o
obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-keypad.o board-sapphire-panel.o
obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-mmc.o board-sapphire-wifi.o
@@ -326,7 +314,6 @@
obj-$(CONFIG_HTC_PWRSINK) += htc_pwrsink.o
obj-$(CONFIG_HTC_HEADSET) += htc_headset.o
obj-$(CONFIG_MSM_RMT_STORAGE_CLIENT) += rmt_storage_client.o
-obj-$(CONFIG_MSM_SDIO_SMEM) += sdio_smem.o
obj-$(CONFIG_MSM_RPM) += rpm.o rpm_resources.o
obj-$(CONFIG_MSM_LPM_TEST) += test-lpm.o
obj-$(CONFIG_MSM_RPM_SMD) += rpm-smd.o lpm_levels.o
@@ -426,7 +413,9 @@
obj-$(CONFIG_ARCH_MSM8974) += msm_mpmctr.o
obj-$(CONFIG_MSM_CPR_REGULATOR) += cpr-regulator.o
obj-$(CONFIG_CPU_FREQ_MSM) += cpufreq.o
+obj-$(CONFIG_MSM_DEVFREQ_CPUBW) += devfreq_cpubw.o
obj-$(CONFIG_WALL_CLK) += wallclk.o
obj-$(CONFIG_WALL_CLK_SYSFS) += wallclk_sysfs.o
obj-$(CONFIG_ARCH_RANDOM) += early_random.o
+obj-$(CONFIG_PERFMAP) += perfmap.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index 552ed16..78df289 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -99,28 +99,35 @@
# MSM8226
zreladdr-$(CONFIG_ARCH_MSM8226) := 0x00008000
- dtb-$(CONFIG_ARCH_MSM8226) += msm8226-sim.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += msm8226-fluid.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v1-cdp.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v1-mtp.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v1-qrd-evt.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v1-qrd-dvt.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v2-cdp.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v2-mtp.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v2-qrd-evt.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v2-qrd-dvt.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += msm8926-cdp.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += msm8926-mtp.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += msm8926-qrd.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += msm8926-qrd-skug.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v1-qrd-skuf.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v2-qrd-skuf.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += apq8026-v1-xpm.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += apq8026-v1-cdp.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += apq8026-v1-mtp.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += apq8026-v2-xpm.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += apq8026-v2-cdp.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += apq8026-v2-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8226-sim.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8226-fluid.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v1-cdp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v1-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v1-qrd-evt.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v1-qrd-dvt.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v2-720p-cdp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v2-1080p-cdp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v2-720p-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v2-1080p-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v2-qrd-evt.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v2-qrd-dvt.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8926-720p-cdp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8926-1080p-cdp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8926-720p-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8926-1080p-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8926-qrd.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8926-qrd-skug.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8926-qrd-skug-pvt.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v1-qrd-skuf.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v2-qrd-skuf.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += apq8026-v1-xpm.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += apq8026-v1-cdp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += apq8026-v1-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += apq8026-v2-xpm.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += apq8026-v2-720p-cdp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += apq8026-v2-1080p-cdp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += apq8026-v2-720p-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += apq8026-v2-1080p-mtp.dtb
# FSM9XXX
zreladdr-$(CONFIG_ARCH_FSM9XXX) := 0x10008000
diff --git a/arch/arm/mach-msm/acpuclock-8064.c b/arch/arm/mach-msm/acpuclock-8064.c
deleted file mode 100644
index 8262946..0000000
--- a/arch/arm/mach-msm/acpuclock-8064.c
+++ /dev/null
@@ -1,679 +0,0 @@
-/*
- * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <mach/rpm-regulator.h>
-#include <mach/msm_bus_board.h>
-#include <mach/msm_bus.h>
-
-#include "mach/socinfo.h"
-#include "acpuclock.h"
-#include "acpuclock-krait.h"
-
-static struct hfpll_data hfpll_data __initdata = {
- .mode_offset = 0x00,
- .l_offset = 0x08,
- .m_offset = 0x0C,
- .n_offset = 0x10,
- .config_offset = 0x04,
- .config_val = 0x7845C665,
- .has_droop_ctl = true,
- .droop_offset = 0x14,
- .droop_val = 0x0108C000,
- .low_vdd_l_max = 22,
- .nom_vdd_l_max = 42,
- .vdd[HFPLL_VDD_NONE] = 0,
- .vdd[HFPLL_VDD_LOW] = 945000,
- .vdd[HFPLL_VDD_NOM] = 1050000,
- .vdd[HFPLL_VDD_HIGH] = 1150000,
-};
-
-static struct scalable scalable[] __initdata = {
- [CPU0] = {
- .hfpll_phys_base = 0x00903200,
- .aux_clk_sel_phys = 0x02088014,
- .aux_clk_sel = 3,
- .sec_clk_sel = 2,
- .l2cpmr_iaddr = 0x4501,
- .vreg[VREG_CORE] = { "krait0", 1300000 },
- .vreg[VREG_MEM] = { "krait0_mem", 1150000 },
- .vreg[VREG_DIG] = { "krait0_dig", 1150000 },
- .vreg[VREG_HFPLL_A] = { "krait0_hfpll", 1800000 },
- },
- [CPU1] = {
- .hfpll_phys_base = 0x00903240,
- .aux_clk_sel_phys = 0x02098014,
- .aux_clk_sel = 3,
- .sec_clk_sel = 2,
- .l2cpmr_iaddr = 0x5501,
- .vreg[VREG_CORE] = { "krait1", 1300000 },
- .vreg[VREG_MEM] = { "krait1_mem", 1150000 },
- .vreg[VREG_DIG] = { "krait1_dig", 1150000 },
- .vreg[VREG_HFPLL_A] = { "krait1_hfpll", 1800000 },
- },
- [CPU2] = {
- .hfpll_phys_base = 0x00903280,
- .aux_clk_sel_phys = 0x020A8014,
- .aux_clk_sel = 3,
- .sec_clk_sel = 2,
- .l2cpmr_iaddr = 0x6501,
- .vreg[VREG_CORE] = { "krait2", 1300000 },
- .vreg[VREG_MEM] = { "krait2_mem", 1150000 },
- .vreg[VREG_DIG] = { "krait2_dig", 1150000 },
- .vreg[VREG_HFPLL_A] = { "krait2_hfpll", 1800000 },
- },
- [CPU3] = {
- .hfpll_phys_base = 0x009032C0,
- .aux_clk_sel_phys = 0x020B8014,
- .aux_clk_sel = 3,
- .sec_clk_sel = 2,
- .l2cpmr_iaddr = 0x7501,
- .vreg[VREG_CORE] = { "krait3", 1300000 },
- .vreg[VREG_MEM] = { "krait3_mem", 1150000 },
- .vreg[VREG_DIG] = { "krait3_dig", 1150000 },
- .vreg[VREG_HFPLL_A] = { "krait3_hfpll", 1800000 },
- },
- [L2] = {
- .hfpll_phys_base = 0x00903300,
- .aux_clk_sel_phys = 0x02011028,
- .aux_clk_sel = 3,
- .sec_clk_sel = 2,
- .l2cpmr_iaddr = 0x0500,
- .vreg[VREG_HFPLL_A] = { "l2_hfpll", 1800000 },
- },
-};
-
-/*
- * The correct maximum rate for 8064ab in 600 MHZ.
- * We rely on the RPM rounding requests up here.
-*/
-static struct msm_bus_paths bw_level_tbl[] __initdata = {
- [0] = BW_MBPS(640), /* At least 80 MHz on bus. */
- [1] = BW_MBPS(1064), /* At least 133 MHz on bus. */
- [2] = BW_MBPS(1600), /* At least 200 MHz on bus. */
- [3] = BW_MBPS(2128), /* At least 266 MHz on bus. */
- [4] = BW_MBPS(3200), /* At least 400 MHz on bus. */
- [5] = BW_MBPS(4264), /* At least 533 MHz on bus. */
-};
-
-static struct msm_bus_scale_pdata bus_scale_data __initdata = {
- .usecase = bw_level_tbl,
- .num_usecases = ARRAY_SIZE(bw_level_tbl),
- .active_only = 1,
- .name = "acpuclk-8064",
-};
-
-static struct l2_level l2_freq_tbl[] __initdata = {
- [0] = { { 384000, PLL_8, 0, 0x00 }, 950000, 1050000, 1 },
- [1] = { { 432000, HFPLL, 2, 0x20 }, 1050000, 1050000, 2 },
- [2] = { { 486000, HFPLL, 2, 0x24 }, 1050000, 1050000, 2 },
- [3] = { { 540000, HFPLL, 2, 0x28 }, 1050000, 1050000, 2 },
- [4] = { { 594000, HFPLL, 1, 0x16 }, 1050000, 1050000, 2 },
- [5] = { { 648000, HFPLL, 1, 0x18 }, 1050000, 1050000, 4 },
- [6] = { { 702000, HFPLL, 1, 0x1A }, 1150000, 1150000, 4 },
- [7] = { { 756000, HFPLL, 1, 0x1C }, 1150000, 1150000, 4 },
- [8] = { { 810000, HFPLL, 1, 0x1E }, 1150000, 1150000, 4 },
- [9] = { { 864000, HFPLL, 1, 0x20 }, 1150000, 1150000, 4 },
- [10] = { { 918000, HFPLL, 1, 0x22 }, 1150000, 1150000, 5 },
- [11] = { { 972000, HFPLL, 1, 0x24 }, 1150000, 1150000, 5 },
- [12] = { { 1026000, HFPLL, 1, 0x26 }, 1150000, 1150000, 5 },
- [13] = { { 1080000, HFPLL, 1, 0x28 }, 1150000, 1150000, 5 },
- [14] = { { 1134000, HFPLL, 1, 0x2A }, 1150000, 1150000, 5 },
- { }
-};
-
-static struct acpu_level tbl_slow[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 950000 },
- { 0, { 432000, HFPLL, 2, 0x20 }, L2(5), 975000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 975000 },
- { 0, { 540000, HFPLL, 2, 0x28 }, L2(5), 1000000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 1000000 },
- { 0, { 648000, HFPLL, 1, 0x18 }, L2(5), 1025000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 1025000 },
- { 0, { 756000, HFPLL, 1, 0x1C }, L2(5), 1075000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 1075000 },
- { 0, { 864000, HFPLL, 1, 0x20 }, L2(5), 1100000 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 1100000 },
- { 0, { 972000, HFPLL, 1, 0x24 }, L2(5), 1125000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 1125000 },
- { 0, { 1080000, HFPLL, 1, 0x28 }, L2(14), 1175000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 1175000 },
- { 0, { 1188000, HFPLL, 1, 0x2C }, L2(14), 1200000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 1200000 },
- { 0, { 1296000, HFPLL, 1, 0x30 }, L2(14), 1225000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1225000 },
- { 0, { 1404000, HFPLL, 1, 0x34 }, L2(14), 1237500 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1237500 },
- { 1, { 1512000, HFPLL, 1, 0x38 }, L2(14), 1250000 },
- { 0, { 0 } }
-};
-
-static struct acpu_level tbl_nom[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 900000 },
- { 0, { 432000, HFPLL, 2, 0x20 }, L2(5), 925000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 925000 },
- { 0, { 540000, HFPLL, 2, 0x28 }, L2(5), 950000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 950000 },
- { 0, { 648000, HFPLL, 1, 0x18 }, L2(5), 975000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 975000 },
- { 0, { 756000, HFPLL, 1, 0x1C }, L2(5), 1025000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 1025000 },
- { 0, { 864000, HFPLL, 1, 0x20 }, L2(5), 1050000 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 1050000 },
- { 0, { 972000, HFPLL, 1, 0x24 }, L2(5), 1075000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 1075000 },
- { 0, { 1080000, HFPLL, 1, 0x28 }, L2(14), 1125000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 1125000 },
- { 0, { 1188000, HFPLL, 1, 0x2C }, L2(14), 1150000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 1150000 },
- { 0, { 1296000, HFPLL, 1, 0x30 }, L2(14), 1175000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1175000 },
- { 0, { 1404000, HFPLL, 1, 0x34 }, L2(14), 1187500 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1187500 },
- { 1, { 1512000, HFPLL, 1, 0x38 }, L2(14), 1200000 },
- { 0, { 0 } }
-};
-
-static struct acpu_level tbl_fast[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 850000 },
- { 0, { 432000, HFPLL, 2, 0x20 }, L2(5), 875000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 875000 },
- { 0, { 540000, HFPLL, 2, 0x28 }, L2(5), 900000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 900000 },
- { 0, { 648000, HFPLL, 1, 0x18 }, L2(5), 925000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 925000 },
- { 0, { 756000, HFPLL, 1, 0x1C }, L2(5), 975000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 975000 },
- { 0, { 864000, HFPLL, 1, 0x20 }, L2(5), 1000000 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 1000000 },
- { 0, { 972000, HFPLL, 1, 0x24 }, L2(5), 1025000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 1025000 },
- { 0, { 1080000, HFPLL, 1, 0x28 }, L2(14), 1075000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 1075000 },
- { 0, { 1188000, HFPLL, 1, 0x2C }, L2(14), 1100000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 1100000 },
- { 0, { 1296000, HFPLL, 1, 0x30 }, L2(14), 1125000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1125000 },
- { 0, { 1404000, HFPLL, 1, 0x34 }, L2(14), 1137500 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1137500 },
- { 1, { 1512000, HFPLL, 1, 0x38 }, L2(14), 1150000 },
- { 0, { 0 } }
-};
-
-static struct acpu_level tbl_faster[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 850000 },
- { 0, { 432000, HFPLL, 2, 0x20 }, L2(5), 875000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 875000 },
- { 0, { 540000, HFPLL, 2, 0x28 }, L2(5), 900000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 900000 },
- { 0, { 648000, HFPLL, 1, 0x18 }, L2(5), 925000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 925000 },
- { 0, { 756000, HFPLL, 1, 0x1C }, L2(5), 962500 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 962500 },
- { 0, { 864000, HFPLL, 1, 0x20 }, L2(5), 975000 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 975000 },
- { 0, { 972000, HFPLL, 1, 0x24 }, L2(5), 1000000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 1000000 },
- { 0, { 1080000, HFPLL, 1, 0x28 }, L2(14), 1050000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 1050000 },
- { 0, { 1188000, HFPLL, 1, 0x2C }, L2(14), 1075000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 1075000 },
- { 0, { 1296000, HFPLL, 1, 0x30 }, L2(14), 1100000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1100000 },
- { 0, { 1404000, HFPLL, 1, 0x34 }, L2(14), 1112500 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1112500 },
- { 1, { 1512000, HFPLL, 1, 0x38 }, L2(14), 1125000 },
- { 0, { 0 } }
-};
-
-static struct acpu_level tbl_PVS0_1512MHz[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 950000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 950000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 950000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 962500 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 1000000 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 1025000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 1037500 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 1075000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 1087500 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1125000 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1150000 },
- { 1, { 1512000, HFPLL, 1, 0x38 }, L2(14), 1162500 },
- { 0, { 0 } }
-};
-
-static struct acpu_level tbl_PVS1_1512MHz[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 950000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 950000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 950000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 962500 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 975000 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 1000000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 1012500 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 1037500 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 1050000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1087500 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1112500 },
- { 1, { 1512000, HFPLL, 1, 0x38 }, L2(14), 1125000 },
- { 0, { 0 } }
-};
-
-static struct acpu_level tbl_PVS2_1512MHz[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 925000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 925000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 925000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 925000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 937500 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 950000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 975000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 1000000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 1012500 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1037500 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1075000 },
- { 1, { 1512000, HFPLL, 1, 0x38 }, L2(14), 1087500 },
- { 0, { 0 } }
-};
-
-static struct acpu_level tbl_PVS3_1512MHz[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 900000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 900000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 900000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 900000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 900000 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 925000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 950000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 975000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 987500 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1000000 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1037500 },
- { 1, { 1512000, HFPLL, 1, 0x38 }, L2(14), 1050000 },
- { 0, { 0 } }
-};
-
-static struct acpu_level tbl_PVS4_1512MHz[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 875000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 875000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 875000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 875000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 887500 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 900000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 925000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 950000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 962500 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 975000 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1000000 },
- { 1, { 1512000, HFPLL, 1, 0x38 }, L2(14), 1012500 },
- { 0, { 0 } }
-};
-
-static struct acpu_level tbl_PVS5_1512MHz[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 875000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 875000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 875000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 875000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 887500 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 900000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 925000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 937500 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 950000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 962500 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 987500 },
- { 1, { 1512000, HFPLL, 1, 0x38 }, L2(14), 1000000 },
- { 0, { 0 } }
-};
-
-static struct acpu_level tbl_PVS6_1512MHz[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 875000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 875000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 875000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 875000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 887500 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 900000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 925000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 937500 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 950000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 962500 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 975000 },
- { 1, { 1512000, HFPLL, 1, 0x38 }, L2(14), 987500 },
- { 0, { 0 } }
-};
-
-static struct acpu_level tbl_PVS0_1700MHz[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 950000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 950000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 950000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 962500 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 1000000 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 1025000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 1037500 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 1075000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 1087500 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1125000 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1150000 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1175000 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1225000 },
- { 1, { 1728000, HFPLL, 1, 0x40 }, L2(14), 1250000 },
- { 0, { 0 } }
-};
-
-static struct acpu_level tbl_PVS1_1700MHz[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 950000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 950000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 950000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 962500 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 975000 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 1000000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 1012500 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 1037500 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 1050000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1087500 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1112500 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1150000 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1187500 },
- { 1, { 1728000, HFPLL, 1, 0x40 }, L2(14), 1200000 },
- { 0, { 0 } }
-};
-
-static struct acpu_level tbl_PVS2_1700MHz[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 925000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 925000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 925000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 925000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 937500 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 950000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 975000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 1000000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 1012500 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1037500 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1075000 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1100000 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1137500 },
- { 1, { 1728000, HFPLL, 1, 0x40 }, L2(14), 1162500 },
- { 0, { 0 } }
-};
-
-static struct acpu_level tbl_PVS3_1700MHz[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 900000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 900000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 900000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 900000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 900000 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 925000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 950000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 975000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 987500 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1000000 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1037500 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1062500 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1100000 },
- { 1, { 1728000, HFPLL, 1, 0x40 }, L2(14), 1125000 },
- { 0, { 0 } }
-};
-
-static struct acpu_level tbl_PVS4_1700MHz[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 875000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 875000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 875000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 875000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 887500 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 900000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 925000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 950000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 962500 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 975000 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1000000 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1037500 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1075000 },
- { 1, { 1728000, HFPLL, 1, 0x40 }, L2(14), 1100000 },
- { 0, { 0 } }
-};
-
-static struct acpu_level tbl_PVS5_1700MHz[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 875000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 875000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 875000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 875000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 887500 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 900000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 925000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 937500 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 950000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 962500 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 987500 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1012500 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1050000 },
- { 1, { 1728000, HFPLL, 1, 0x40 }, L2(14), 1075000 },
- { 0, { 0 } }
-};
-
-static struct acpu_level tbl_PVS6_1700MHz[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 875000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 875000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 875000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 875000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 887500 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 900000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 925000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 937500 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 950000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 962500 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 975000 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1000000 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1025000 },
- { 1, { 1728000, HFPLL, 1, 0x40 }, L2(14), 1050000 },
- { 0, { 0 } }
-};
-
-static struct acpu_level tbl_PVS0_2000MHz[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 950000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 950000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 950000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 950000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 962500 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 975000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 1000000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 1025000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 1037500 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1062500 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1100000 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1125000 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1175000 },
- { 1, { 1782000, HFPLL, 1, 0x42 }, L2(14), 1225000 },
- { 1, { 1890000, HFPLL, 1, 0x46 }, L2(14), 1287500 },
- { 0, { 0 } }
-};
-
-static struct acpu_level tbl_PVS1_2000MHz[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 925000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 925000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 925000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 925000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 937500 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 950000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 975000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 1000000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 1012500 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1037500 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1075000 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1100000 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1137500 },
- { 1, { 1782000, HFPLL, 1, 0x42 }, L2(14), 1187500 },
- { 1, { 1890000, HFPLL, 1, 0x46 }, L2(14), 1250000 },
- { 0, { 0 } }
-};
-
-static struct acpu_level tbl_PVS2_2000MHz[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 900000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 900000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 900000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 900000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 912500 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 925000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 950000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 975000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 987500 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1012500 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1050000 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1075000 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1112500 },
- { 1, { 1782000, HFPLL, 1, 0x42 }, L2(14), 1162500 },
- { 1, { 1890000, HFPLL, 1, 0x46 }, L2(14), 1212500 },
- { 0, { 0 } }
-};
-
-static struct acpu_level tbl_PVS3_2000MHz[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 900000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 900000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 900000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 900000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 900000 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 912500 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 937500 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 962500 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 975000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 1000000 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1025000 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1050000 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1087500 },
- { 1, { 1782000, HFPLL, 1, 0x42 }, L2(14), 1137500 },
- { 1, { 1890000, HFPLL, 1, 0x46 }, L2(14), 1175000 },
- { 0, { 0 } }
-};
-
-static struct acpu_level tbl_PVS4_2000MHz[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 875000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 875000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 875000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 875000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 887500 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 900000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 925000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 950000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 962500 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 975000 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 1000000 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1037500 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1075000 },
- { 1, { 1782000, HFPLL, 1, 0x42 }, L2(14), 1112500 },
- { 1, { 1890000, HFPLL, 1, 0x46 }, L2(14), 1150000 },
- { 0, { 0 } }
-};
-
-static struct acpu_level tbl_PVS5_2000MHz[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 875000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 875000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 875000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 875000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 887500 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 900000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 925000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 937500 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 950000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 962500 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 987500 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1012500 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1050000 },
- { 1, { 1782000, HFPLL, 1, 0x42 }, L2(14), 1087500 },
- { 1, { 1890000, HFPLL, 1, 0x46 }, L2(14), 1125000 },
- { 0, { 0 } }
-};
-
-static struct acpu_level tbl_PVS6_2000MHz[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 875000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 875000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 875000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 875000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 887500 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 900000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 925000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(14), 937500 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(14), 950000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(14), 962500 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(14), 975000 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(14), 1000000 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(14), 1025000 },
- { 1, { 1782000, HFPLL, 1, 0x42 }, L2(14), 1062500 },
- { 1, { 1890000, HFPLL, 1, 0x46 }, L2(14), 1100000 },
- { 0, { 0 } }
-};
-
-static struct pvs_table pvs_tables[NUM_SPEED_BINS][NUM_PVS] __initdata = {
- [0][PVS_SLOW] = {tbl_slow, sizeof(tbl_slow), 0 },
- [0][PVS_NOMINAL] = {tbl_nom, sizeof(tbl_nom), 25000 },
- [0][PVS_FAST] = {tbl_fast, sizeof(tbl_fast), 25000 },
- [0][PVS_FASTER] = {tbl_faster, sizeof(tbl_faster), 25000 },
-
- [1][0] = { tbl_PVS0_1700MHz, sizeof(tbl_PVS0_1700MHz), 0 },
- [1][1] = { tbl_PVS1_1700MHz, sizeof(tbl_PVS1_1700MHz), 25000 },
- [1][2] = { tbl_PVS2_1700MHz, sizeof(tbl_PVS2_1700MHz), 25000 },
- [1][3] = { tbl_PVS3_1700MHz, sizeof(tbl_PVS3_1700MHz), 25000 },
- [1][4] = { tbl_PVS4_1700MHz, sizeof(tbl_PVS4_1700MHz), 25000 },
- [1][5] = { tbl_PVS5_1700MHz, sizeof(tbl_PVS5_1700MHz), 25000 },
- [1][6] = { tbl_PVS6_1700MHz, sizeof(tbl_PVS6_1700MHz), 25000 },
-
- [2][0] = { tbl_PVS0_2000MHz, sizeof(tbl_PVS0_2000MHz), 0 },
- [2][1] = { tbl_PVS1_2000MHz, sizeof(tbl_PVS1_2000MHz), 25000 },
- [2][2] = { tbl_PVS2_2000MHz, sizeof(tbl_PVS2_2000MHz), 25000 },
- [2][3] = { tbl_PVS3_2000MHz, sizeof(tbl_PVS3_2000MHz), 25000 },
- [2][4] = { tbl_PVS4_2000MHz, sizeof(tbl_PVS4_2000MHz), 25000 },
- [2][5] = { tbl_PVS5_2000MHz, sizeof(tbl_PVS5_2000MHz), 25000 },
- [2][6] = { tbl_PVS6_2000MHz, sizeof(tbl_PVS6_2000MHz), 25000 },
-
- [14][0] = { tbl_PVS0_1512MHz, sizeof(tbl_PVS0_1512MHz), 0 },
- [14][1] = { tbl_PVS1_1512MHz, sizeof(tbl_PVS1_1512MHz), 25000 },
- [14][2] = { tbl_PVS2_1512MHz, sizeof(tbl_PVS2_1512MHz), 25000 },
- [14][3] = { tbl_PVS3_1512MHz, sizeof(tbl_PVS3_1512MHz), 25000 },
- [14][4] = { tbl_PVS4_1512MHz, sizeof(tbl_PVS4_1512MHz), 25000 },
- [14][5] = { tbl_PVS5_1512MHz, sizeof(tbl_PVS5_1512MHz), 25000 },
- [14][6] = { tbl_PVS6_1512MHz, sizeof(tbl_PVS6_1512MHz), 25000 },
-};
-
-static struct acpuclk_krait_params acpuclk_8064_params __initdata = {
- .scalable = scalable,
- .scalable_size = sizeof(scalable),
- .hfpll_data = &hfpll_data,
- .pvs_tables = pvs_tables,
- .l2_freq_tbl = l2_freq_tbl,
- .l2_freq_tbl_size = sizeof(l2_freq_tbl),
- .bus_scale = &bus_scale_data,
- .pte_efuse_phys = 0x007000C0,
- .get_bin_info = get_krait_bin_format_a,
- .stby_khz = 384000,
-};
-
-static int __init acpuclk_8064_probe(struct platform_device *pdev)
-{
- if (cpu_is_apq8064ab() ||
- SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 2) {
- acpuclk_8064_params.hfpll_data->low_vdd_l_max = 37;
- acpuclk_8064_params.hfpll_data->nom_vdd_l_max = 74;
- }
-
- return acpuclk_krait_init(&pdev->dev, &acpuclk_8064_params);
-}
-
-static struct platform_driver acpuclk_8064_driver = {
- .driver = {
- .name = "acpuclk-8064",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init acpuclk_8064_init(void)
-{
- return platform_driver_probe(&acpuclk_8064_driver,
- acpuclk_8064_probe);
-}
-device_initcall(acpuclk_8064_init);
diff --git a/arch/arm/mach-msm/acpuclock-8226.c b/arch/arm/mach-msm/acpuclock-8226.c
index da3cfba..d42e798 100644
--- a/arch/arm/mach-msm/acpuclock-8226.c
+++ b/arch/arm/mach-msm/acpuclock-8226.c
@@ -60,64 +60,64 @@
};
static struct clkctl_acpu_speed acpu_freq_tbl_8226_1p1[] = {
- { 1, 300000, PLL0, 4, 2, CPR_CORNER_SVS, 0, 4 },
- { 1, 384000, ACPUPLL, 5, 2, CPR_CORNER_SVS, 0, 4 },
- { 1, 600000, PLL0, 4, 0, CPR_CORNER_NORMAL, 0, 6 },
- { 1, 787200, ACPUPLL, 5, 0, CPR_CORNER_NORMAL, 0, 6 },
- { 1, 998400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
- { 1, 1094400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
- { 0, 1190400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
+ { 1, 300000, PLL0, 4, 2, CPR_CORNER_2, 0, 4 },
+ { 1, 384000, ACPUPLL, 5, 2, CPR_CORNER_2, 0, 4 },
+ { 1, 600000, PLL0, 4, 0, CPR_CORNER_4, 0, 6 },
+ { 1, 787200, ACPUPLL, 5, 0, CPR_CORNER_4, 0, 6 },
+ { 1, 998400, ACPUPLL, 5, 0, CPR_CORNER_12, 0, 7 },
+ { 1, 1094400, ACPUPLL, 5, 0, CPR_CORNER_12, 0, 7 },
+ { 0, 1190400, ACPUPLL, 5, 0, CPR_CORNER_12, 0, 7 },
{ 0 }
};
static struct clkctl_acpu_speed acpu_freq_tbl_8226_1p2[] = {
- { 1, 300000, PLL0, 4, 2, CPR_CORNER_SVS, 0, 4 },
- { 1, 384000, ACPUPLL, 5, 2, CPR_CORNER_SVS, 0, 4 },
- { 1, 600000, PLL0, 4, 0, CPR_CORNER_NORMAL, 0, 6 },
- { 1, 787200, ACPUPLL, 5, 0, CPR_CORNER_NORMAL, 0, 6 },
- { 1, 998400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
- { 1, 1094400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
- { 1, 1190400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
+ { 1, 300000, PLL0, 4, 2, CPR_CORNER_2, 0, 4 },
+ { 1, 384000, ACPUPLL, 5, 2, CPR_CORNER_2, 0, 4 },
+ { 1, 600000, PLL0, 4, 0, CPR_CORNER_4, 0, 6 },
+ { 1, 787200, ACPUPLL, 5, 0, CPR_CORNER_4, 0, 6 },
+ { 1, 998400, ACPUPLL, 5, 0, CPR_CORNER_12, 0, 7 },
+ { 1, 1094400, ACPUPLL, 5, 0, CPR_CORNER_12, 0, 7 },
+ { 1, 1190400, ACPUPLL, 5, 0, CPR_CORNER_12, 0, 7 },
{ 0 }
};
static struct clkctl_acpu_speed acpu_freq_tbl_8226_1p4[] = {
- { 1, 300000, PLL0, 4, 2, CPR_CORNER_SVS, 0, 4 },
- { 1, 384000, ACPUPLL, 5, 2, CPR_CORNER_SVS, 0, 4 },
- { 1, 600000, PLL0, 4, 0, CPR_CORNER_NORMAL, 0, 6 },
- { 1, 787200, ACPUPLL, 5, 0, CPR_CORNER_NORMAL, 0, 6 },
- { 1, 998400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
- { 1, 1094400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
- { 1, 1190400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
- { 1, 1305600, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
- { 1, 1344000, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
- { 1, 1401600, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
+ { 1, 300000, PLL0, 4, 2, CPR_CORNER_2, 0, 4 },
+ { 1, 384000, ACPUPLL, 5, 2, CPR_CORNER_2, 0, 4 },
+ { 1, 600000, PLL0, 4, 0, CPR_CORNER_4, 0, 6 },
+ { 1, 787200, ACPUPLL, 5, 0, CPR_CORNER_4, 0, 6 },
+ { 1, 998400, ACPUPLL, 5, 0, CPR_CORNER_12, 0, 7 },
+ { 1, 1094400, ACPUPLL, 5, 0, CPR_CORNER_12, 0, 7 },
+ { 1, 1190400, ACPUPLL, 5, 0, CPR_CORNER_12, 0, 7 },
+ { 1, 1305600, ACPUPLL, 5, 0, CPR_CORNER_12, 0, 7 },
+ { 1, 1344000, ACPUPLL, 5, 0, CPR_CORNER_12, 0, 7 },
+ { 1, 1401600, ACPUPLL, 5, 0, CPR_CORNER_12, 0, 7 },
{ 0 }
};
static struct clkctl_acpu_speed acpu_freq_tbl_8226_1p6[] = {
- { 1, 300000, PLL0, 4, 2, CPR_CORNER_SVS, 0, 4 },
- { 1, 384000, ACPUPLL, 5, 2, CPR_CORNER_SVS, 0, 4 },
- { 1, 600000, PLL0, 4, 0, CPR_CORNER_NORMAL, 0, 6 },
- { 1, 787200, ACPUPLL, 5, 0, CPR_CORNER_NORMAL, 0, 6 },
- { 1, 998400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
- { 1, 1094400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
- { 1, 1190400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
- { 1, 1305600, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
- { 1, 1344000, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
- { 1, 1401600, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
- { 1, 1497600, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
- { 1, 1593600, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
+ { 1, 300000, PLL0, 4, 2, CPR_CORNER_2, 0, 4 },
+ { 1, 384000, ACPUPLL, 5, 2, CPR_CORNER_2, 0, 4 },
+ { 1, 600000, PLL0, 4, 0, CPR_CORNER_4, 0, 6 },
+ { 1, 787200, ACPUPLL, 5, 0, CPR_CORNER_4, 0, 6 },
+ { 1, 998400, ACPUPLL, 5, 0, CPR_CORNER_5, 0, 7 },
+ { 1, 1094400, ACPUPLL, 5, 0, CPR_CORNER_6, 0, 7 },
+ { 1, 1190400, ACPUPLL, 5, 0, CPR_CORNER_7, 0, 7 },
+ { 1, 1305600, ACPUPLL, 5, 0, CPR_CORNER_8, 0, 7 },
+ { 1, 1344000, ACPUPLL, 5, 0, CPR_CORNER_9, 0, 7 },
+ { 1, 1401600, ACPUPLL, 5, 0, CPR_CORNER_10, 0, 7 },
+ { 1, 1497600, ACPUPLL, 5, 0, CPR_CORNER_11, 0, 7 },
+ { 1, 1593600, ACPUPLL, 5, 0, CPR_CORNER_12, 0, 7 },
{ 0 }
};
static struct clkctl_acpu_speed acpu_freq_tbl_8610[] = {
- { 1, 300000, PLL0, 4, 2, CPR_CORNER_SVS, 0, 3 },
- { 1, 384000, ACPUPLL, 5, 2, CPR_CORNER_SVS, 0, 3 },
- { 1, 600000, PLL0, 4, 0, CPR_CORNER_NORMAL, 0, 4 },
- { 1, 787200, ACPUPLL, 5, 0, CPR_CORNER_NORMAL, 0, 4 },
- { 1, 998400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 5 },
- { 1, 1190400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 5 },
+ { 1, 300000, PLL0, 4, 2, CPR_CORNER_2, 0, 3 },
+ { 1, 384000, ACPUPLL, 5, 2, CPR_CORNER_2, 0, 3 },
+ { 1, 600000, PLL0, 4, 0, CPR_CORNER_4, 0, 4 },
+ { 1, 787200, ACPUPLL, 5, 0, CPR_CORNER_4, 0, 4 },
+ { 1, 998400, ACPUPLL, 5, 0, CPR_CORNER_12, 0, 5 },
+ { 1, 1190400, ACPUPLL, 5, 0, CPR_CORNER_12, 0, 5 },
{ 0 }
};
@@ -135,7 +135,7 @@
.freq_tbl = acpu_freq_tbl_8226_1p1,
.pvs_tables = pvs_tables_8226,
.bus_scale = &bus_client_pdata,
- .vdd_max_cpu = CPR_CORNER_TURBO,
+ .vdd_max_cpu = CPR_CORNER_12,
.src_clocks = {
[PLL0].name = "gpll0",
[ACPUPLL].name = "a7sspll",
diff --git a/arch/arm/mach-msm/acpuclock-8627.c b/arch/arm/mach-msm/acpuclock-8627.c
deleted file mode 100644
index 405b26b..0000000
--- a/arch/arm/mach-msm/acpuclock-8627.c
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <mach/rpm-regulator.h>
-#include <mach/msm_bus_board.h>
-#include <mach/msm_bus.h>
-
-#include "acpuclock.h"
-#include "acpuclock-krait.h"
-
-/* Corner type vreg VDD values */
-#define LVL_NONE RPM_VREG_CORNER_NONE
-#define LVL_LOW RPM_VREG_CORNER_LOW
-#define LVL_NOM RPM_VREG_CORNER_NOMINAL
-#define LVL_HIGH RPM_VREG_CORNER_HIGH
-
-static struct hfpll_data hfpll_data __initdata = {
- .mode_offset = 0x00,
- .l_offset = 0x08,
- .m_offset = 0x0C,
- .n_offset = 0x10,
- .config_offset = 0x04,
- .config_val = 0x7845C665,
- .has_droop_ctl = true,
- .droop_offset = 0x14,
- .droop_val = 0x0108C000,
- .low_vdd_l_max = 22,
- .nom_vdd_l_max = 42,
- .vdd[HFPLL_VDD_NONE] = LVL_NONE,
- .vdd[HFPLL_VDD_LOW] = LVL_LOW,
- .vdd[HFPLL_VDD_NOM] = LVL_NOM,
- .vdd[HFPLL_VDD_HIGH] = LVL_HIGH,
-};
-
-static struct scalable scalable[] __initdata = {
- [CPU0] = {
- .hfpll_phys_base = 0x00903200,
- .aux_clk_sel_phys = 0x02088014,
- .aux_clk_sel = 3,
- .sec_clk_sel = 2,
- .l2cpmr_iaddr = 0x4501,
- .vreg[VREG_CORE] = { "krait0", 1300000 },
- .vreg[VREG_MEM] = { "krait0_mem", 1150000 },
- .vreg[VREG_DIG] = { "krait0_dig", 1150000 },
- .vreg[VREG_HFPLL_A] = { "krait0_hfpll", 1800000 },
- },
- [CPU1] = {
- .hfpll_phys_base = 0x00903300,
- .aux_clk_sel_phys = 0x02098014,
- .aux_clk_sel = 3,
- .sec_clk_sel = 2,
- .l2cpmr_iaddr = 0x5501,
- .vreg[VREG_CORE] = { "krait1", 1300000 },
- .vreg[VREG_MEM] = { "krait1_mem", 1150000 },
- .vreg[VREG_DIG] = { "krait1_dig", 1150000 },
- .vreg[VREG_HFPLL_A] = { "krait1_hfpll", 1800000 },
- },
- [L2] = {
- .hfpll_phys_base = 0x00903400,
- .aux_clk_sel_phys = 0x02011028,
- .aux_clk_sel = 3,
- .sec_clk_sel = 2,
- .l2cpmr_iaddr = 0x0500,
- .vreg[VREG_HFPLL_A] = { "l2_hfpll", 1800000 },
- },
-};
-
-static struct msm_bus_paths bw_level_tbl[] __initdata = {
- [0] = BW_MBPS(640), /* At least 80 MHz on bus. */
- [1] = BW_MBPS(1064), /* At least 133 MHz on bus. */
- [2] = BW_MBPS(1600), /* At least 200 MHz on bus. */
- [3] = BW_MBPS(2128), /* At least 266 MHz on bus. */
- [4] = BW_MBPS(3200), /* At least 400 MHz on bus. */
-};
-
-static struct msm_bus_scale_pdata bus_scale_data __initdata = {
- .usecase = bw_level_tbl,
- .num_usecases = ARRAY_SIZE(bw_level_tbl),
- .active_only = 1,
- .name = "acpuclk-8627",
-};
-
-/* TODO: Update vdd_dig, vdd_mem and bw when data is available. */
-static struct l2_level l2_freq_tbl[] __initdata = {
- [0] = { { 384000, PLL_8, 0, 0x00 }, LVL_NOM, 1050000, 1 },
- [1] = { { 432000, HFPLL, 2, 0x20 }, LVL_NOM, 1050000, 1 },
- [2] = { { 486000, HFPLL, 2, 0x24 }, LVL_NOM, 1050000, 1 },
- [3] = { { 540000, HFPLL, 2, 0x28 }, LVL_NOM, 1050000, 2 },
- [4] = { { 594000, HFPLL, 1, 0x16 }, LVL_NOM, 1050000, 2 },
- [5] = { { 648000, HFPLL, 1, 0x18 }, LVL_NOM, 1050000, 2 },
- [6] = { { 702000, HFPLL, 1, 0x1A }, LVL_NOM, 1050000, 3 },
- [7] = { { 756000, HFPLL, 1, 0x1C }, LVL_HIGH, 1150000, 3 },
- [8] = { { 810000, HFPLL, 1, 0x1E }, LVL_HIGH, 1150000, 3 },
- [9] = { { 864000, HFPLL, 1, 0x20 }, LVL_HIGH, 1150000, 4 },
- [10] = { { 918000, HFPLL, 1, 0x22 }, LVL_HIGH, 1150000, 4 },
- [11] = { { 972000, HFPLL, 1, 0x24 }, LVL_HIGH, 1150000, 4 },
- { }
-};
-
-/* TODO: Update core voltages when data is available. */
-static struct acpu_level acpu_freq_tbl[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 900000 },
- { 1, { 432000, HFPLL, 2, 0x20 }, L2(4), 925000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(4), 925000 },
- { 1, { 540000, HFPLL, 2, 0x28 }, L2(4), 937500 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(4), 962500 },
- { 1, { 648000, HFPLL, 1, 0x18 }, L2(8), 987500 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(8), 1000000 },
- { 1, { 756000, HFPLL, 1, 0x1C }, L2(8), 1025000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(8), 1062500 },
- { 1, { 864000, HFPLL, 1, 0x20 }, L2(11), 1062500 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(11), 1087500 },
- { 1, { 972000, HFPLL, 1, 0x24 }, L2(11), 1100000 },
- { 0, { 0 } }
-};
-
-static struct pvs_table pvs_tables[NUM_SPEED_BINS][NUM_PVS] __initdata = {
- [0][PVS_SLOW] = { acpu_freq_tbl, sizeof(acpu_freq_tbl), 0 },
- [0][PVS_NOMINAL] = { acpu_freq_tbl, sizeof(acpu_freq_tbl), 25000 },
- [0][PVS_FAST] = { acpu_freq_tbl, sizeof(acpu_freq_tbl), 25000 },
-};
-
-static struct acpuclk_krait_params acpuclk_8627_params __initdata = {
- .scalable = scalable,
- .scalable_size = sizeof(scalable),
- .hfpll_data = &hfpll_data,
- .pvs_tables = pvs_tables,
- .l2_freq_tbl = l2_freq_tbl,
- .l2_freq_tbl_size = sizeof(l2_freq_tbl),
- .bus_scale = &bus_scale_data,
- .pte_efuse_phys = 0x007000C0,
- .get_bin_info = get_krait_bin_format_a,
- .stby_khz = 384000,
-};
-
-static int __init acpuclk_8627_probe(struct platform_device *pdev)
-{
- return acpuclk_krait_init(&pdev->dev, &acpuclk_8627_params);
-}
-
-static struct platform_driver acpuclk_8627_driver = {
- .driver = {
- .name = "acpuclk-8627",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init acpuclk_8627_init(void)
-{
- return platform_driver_probe(&acpuclk_8627_driver,
- acpuclk_8627_probe);
-}
-device_initcall(acpuclk_8627_init);
diff --git a/arch/arm/mach-msm/acpuclock-8930.c b/arch/arm/mach-msm/acpuclock-8930.c
deleted file mode 100644
index e29d6fe..0000000
--- a/arch/arm/mach-msm/acpuclock-8930.c
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <mach/rpm-regulator.h>
-#include <mach/msm_bus_board.h>
-#include <mach/msm_bus.h>
-
-#include "acpuclock.h"
-#include "acpuclock-krait.h"
-
-/* Corner type vreg VDD values */
-#define LVL_NONE RPM_VREG_CORNER_NONE
-#define LVL_LOW RPM_VREG_CORNER_LOW
-#define LVL_NOM RPM_VREG_CORNER_NOMINAL
-#define LVL_HIGH RPM_VREG_CORNER_HIGH
-
-static struct hfpll_data hfpll_data __initdata = {
- .mode_offset = 0x00,
- .l_offset = 0x08,
- .m_offset = 0x0C,
- .n_offset = 0x10,
- .config_offset = 0x04,
- .config_val = 0x7845C665,
- .has_droop_ctl = true,
- .droop_offset = 0x14,
- .droop_val = 0x0108C000,
- .low_vdd_l_max = 22,
- .nom_vdd_l_max = 42,
- .vdd[HFPLL_VDD_NONE] = LVL_NONE,
- .vdd[HFPLL_VDD_LOW] = LVL_LOW,
- .vdd[HFPLL_VDD_NOM] = LVL_NOM,
- .vdd[HFPLL_VDD_HIGH] = LVL_HIGH,
-};
-
-static struct scalable scalable_pm8917[] __initdata = {
- [CPU0] = {
- .hfpll_phys_base = 0x00903200,
- .aux_clk_sel_phys = 0x02088014,
- .aux_clk_sel = 3,
- .sec_clk_sel = 2,
- .l2cpmr_iaddr = 0x4501,
- .vreg[VREG_CORE] = { "krait0", 1300000 },
- .vreg[VREG_MEM] = { "krait0_mem", 1150000 },
- .vreg[VREG_DIG] = { "krait0_dig", LVL_HIGH},
- .vreg[VREG_HFPLL_A] = { "krait0_s8", 2050000 },
- .vreg[VREG_HFPLL_B] = { "krait0_l23", 1800000 },
- },
- [CPU1] = {
- .hfpll_phys_base = 0x00903300,
- .aux_clk_sel_phys = 0x02098014,
- .aux_clk_sel = 3,
- .sec_clk_sel = 2,
- .l2cpmr_iaddr = 0x5501,
- .vreg[VREG_CORE] = { "krait1", 1300000 },
- .vreg[VREG_MEM] = { "krait1_mem", 1150000 },
- .vreg[VREG_DIG] = { "krait1_dig", LVL_HIGH},
- .vreg[VREG_HFPLL_A] = { "krait1_s8", 2050000 },
- .vreg[VREG_HFPLL_B] = { "krait1_l23", 1800000 },
- },
- [L2] = {
- .hfpll_phys_base = 0x00903400,
- .aux_clk_sel_phys = 0x02011028,
- .aux_clk_sel = 3,
- .sec_clk_sel = 2,
- .l2cpmr_iaddr = 0x0500,
- .vreg[VREG_HFPLL_A] = { "l2_s8", 2050000 },
- .vreg[VREG_HFPLL_B] = { "l2_l23", 1800000 },
- },
-};
-
-static struct scalable scalable[] __initdata = {
- [CPU0] = {
- .hfpll_phys_base = 0x00903200,
- .aux_clk_sel_phys = 0x02088014,
- .aux_clk_sel = 3,
- .sec_clk_sel = 2,
- .l2cpmr_iaddr = 0x4501,
- .vreg[VREG_CORE] = { "krait0", 1300000 },
- .vreg[VREG_MEM] = { "krait0_mem", 1150000 },
- .vreg[VREG_DIG] = { "krait0_dig", LVL_HIGH},
- .vreg[VREG_HFPLL_A] = { "krait0_hfpll", 1800000 },
- },
- [CPU1] = {
- .hfpll_phys_base = 0x00903300,
- .aux_clk_sel_phys = 0x02098014,
- .aux_clk_sel = 3,
- .sec_clk_sel = 2,
- .l2cpmr_iaddr = 0x5501,
- .vreg[VREG_CORE] = { "krait1", 1300000 },
- .vreg[VREG_MEM] = { "krait1_mem", 1150000 },
- .vreg[VREG_DIG] = { "krait1_dig", LVL_HIGH},
- .vreg[VREG_HFPLL_A] = { "krait1_hfpll", 1800000 },
- },
- [L2] = {
- .hfpll_phys_base = 0x00903400,
- .aux_clk_sel_phys = 0x02011028,
- .aux_clk_sel = 3,
- .sec_clk_sel = 2,
- .l2cpmr_iaddr = 0x0500,
- .vreg[VREG_HFPLL_A] = { "l2_hfpll", 1800000 },
- },
-};
-
-static struct msm_bus_paths bw_level_tbl[] __initdata = {
- [0] = BW_MBPS(640), /* At least 80 MHz on bus. */
- [1] = BW_MBPS(1064), /* At least 133 MHz on bus. */
- [2] = BW_MBPS(1600), /* At least 200 MHz on bus. */
- [3] = BW_MBPS(2128), /* At least 266 MHz on bus. */
- [4] = BW_MBPS(3200), /* At least 400 MHz on bus. */
- [5] = BW_MBPS(3600), /* At least 450 MHz on bus. */
- [6] = BW_MBPS(3936), /* At least 492 MHz on bus. */
- [7] = BW_MBPS(4264), /* At least 533 MHz on bus. */
-};
-
-static struct msm_bus_scale_pdata bus_scale_data __initdata = {
- .usecase = bw_level_tbl,
- .num_usecases = ARRAY_SIZE(bw_level_tbl),
- .active_only = 1,
- .name = "acpuclk-8930",
-};
-
-static struct l2_level l2_freq_tbl[] __initdata = {
- [0] = { { 384000, PLL_8, 0, 0x00 }, LVL_LOW, 1050000, 1 },
- [1] = { { 432000, HFPLL, 2, 0x20 }, LVL_NOM, 1050000, 2 },
- [2] = { { 486000, HFPLL, 2, 0x24 }, LVL_NOM, 1050000, 2 },
- [3] = { { 540000, HFPLL, 2, 0x28 }, LVL_NOM, 1050000, 2 },
- [4] = { { 594000, HFPLL, 1, 0x16 }, LVL_NOM, 1050000, 2 },
- [5] = { { 648000, HFPLL, 1, 0x18 }, LVL_NOM, 1050000, 4 },
- [6] = { { 702000, HFPLL, 1, 0x1A }, LVL_NOM, 1050000, 4 },
- [7] = { { 756000, HFPLL, 1, 0x1C }, LVL_HIGH, 1150000, 4 },
- [8] = { { 810000, HFPLL, 1, 0x1E }, LVL_HIGH, 1150000, 4 },
- [9] = { { 864000, HFPLL, 1, 0x20 }, LVL_HIGH, 1150000, 4 },
- [10] = { { 918000, HFPLL, 1, 0x22 }, LVL_HIGH, 1150000, 7 },
- [11] = { { 972000, HFPLL, 1, 0x24 }, LVL_HIGH, 1150000, 7 },
- [12] = { { 1026000, HFPLL, 1, 0x26 }, LVL_HIGH, 1150000, 7 },
- [13] = { { 1080000, HFPLL, 1, 0x28 }, LVL_HIGH, 1150000, 7 },
- [14] = { { 1134000, HFPLL, 1, 0x2A }, LVL_HIGH, 1150000, 7 },
- [15] = { { 1188000, HFPLL, 1, 0x2C }, LVL_HIGH, 1150000, 7 },
- { }
-};
-
-static struct acpu_level acpu_freq_tbl_slow[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 950000 },
- { 0, { 432000, HFPLL, 2, 0x20 }, L2(5), 975000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 975000 },
- { 0, { 540000, HFPLL, 2, 0x28 }, L2(5), 1000000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 1000000 },
- { 0, { 648000, HFPLL, 1, 0x18 }, L2(5), 1025000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 1025000 },
- { 0, { 756000, HFPLL, 1, 0x1C }, L2(10), 1075000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(10), 1075000 },
- { 0, { 864000, HFPLL, 1, 0x20 }, L2(10), 1100000 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(10), 1100000 },
- { 0, { 972000, HFPLL, 1, 0x24 }, L2(10), 1125000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(10), 1125000 },
- { 0, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1175000 },
- { 1, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_nom[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 925000 },
- { 0, { 432000, HFPLL, 2, 0x20 }, L2(5), 950000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 950000 },
- { 0, { 540000, HFPLL, 2, 0x28 }, L2(5), 975000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 975000 },
- { 0, { 648000, HFPLL, 1, 0x18 }, L2(5), 1000000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 1000000 },
- { 0, { 756000, HFPLL, 1, 0x1C }, L2(10), 1050000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(10), 1050000 },
- { 0, { 864000, HFPLL, 1, 0x20 }, L2(10), 1075000 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(10), 1075000 },
- { 0, { 972000, HFPLL, 1, 0x24 }, L2(10), 1100000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(10), 1100000 },
- { 0, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1150000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1150000 },
- { 1, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1175000 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_fast[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 900000 },
- { 0, { 432000, HFPLL, 2, 0x20 }, L2(5), 900000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 900000 },
- { 0, { 540000, HFPLL, 2, 0x28 }, L2(5), 925000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 925000 },
- { 0, { 648000, HFPLL, 1, 0x18 }, L2(5), 950000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 950000 },
- { 0, { 756000, HFPLL, 1, 0x1C }, L2(10), 1000000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(10), 1000000 },
- { 0, { 864000, HFPLL, 1, 0x20 }, L2(10), 1025000 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(10), 1025000 },
- { 0, { 972000, HFPLL, 1, 0x24 }, L2(10), 1050000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(10), 1050000 },
- { 0, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1100000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1100000 },
- { 1, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1125000 },
- { 0, { 0 } }
-};
-
-static struct pvs_table pvs_tables[NUM_SPEED_BINS][NUM_PVS] __initdata = {
-[0][PVS_SLOW] = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow), 0 },
-[0][PVS_NOMINAL] = { acpu_freq_tbl_nom, sizeof(acpu_freq_tbl_nom), 25000 },
-[0][PVS_FAST] = { acpu_freq_tbl_fast, sizeof(acpu_freq_tbl_fast), 25000 },
-};
-
-static struct acpuclk_krait_params acpuclk_8930_params __initdata = {
- .scalable = scalable,
- .scalable_size = sizeof(scalable),
- .hfpll_data = &hfpll_data,
- .pvs_tables = pvs_tables,
- .l2_freq_tbl = l2_freq_tbl,
- .l2_freq_tbl_size = sizeof(l2_freq_tbl),
- .bus_scale = &bus_scale_data,
- .pte_efuse_phys = 0x007000C0,
- .get_bin_info = get_krait_bin_format_a,
- .stby_khz = 384000,
-};
-
-static int __init acpuclk_8930_probe(struct platform_device *pdev)
-{
- struct acpuclk_platform_data *pdata = pdev->dev.platform_data;
- if (pdata && pdata->uses_pm8917)
- acpuclk_8930_params.scalable = scalable_pm8917;
-
- return acpuclk_krait_init(&pdev->dev, &acpuclk_8930_params);
-}
-
-static struct platform_driver acpuclk_8930_driver = {
- .driver = {
- .name = "acpuclk-8930",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init acpuclk_8930_init(void)
-{
- return platform_driver_probe(&acpuclk_8930_driver,
- acpuclk_8930_probe);
-}
-device_initcall(acpuclk_8930_init);
diff --git a/arch/arm/mach-msm/acpuclock-8930aa.c b/arch/arm/mach-msm/acpuclock-8930aa.c
deleted file mode 100644
index c824323..0000000
--- a/arch/arm/mach-msm/acpuclock-8930aa.c
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <mach/rpm-regulator.h>
-#include <mach/msm_bus_board.h>
-#include <mach/msm_bus.h>
-
-#include "acpuclock.h"
-#include "acpuclock-krait.h"
-
-/* Corner type vreg VDD values */
-#define LVL_NONE RPM_VREG_CORNER_NONE
-#define LVL_LOW RPM_VREG_CORNER_LOW
-#define LVL_NOM RPM_VREG_CORNER_NOMINAL
-#define LVL_HIGH RPM_VREG_CORNER_HIGH
-
-static struct hfpll_data hfpll_data __initdata = {
- .mode_offset = 0x00,
- .l_offset = 0x08,
- .m_offset = 0x0C,
- .n_offset = 0x10,
- .config_offset = 0x04,
- .config_val = 0x7845C665,
- .has_droop_ctl = true,
- .droop_offset = 0x14,
- .droop_val = 0x0108C000,
- .low_vdd_l_max = 22,
- .nom_vdd_l_max = 42,
- .vdd[HFPLL_VDD_NONE] = LVL_NONE,
- .vdd[HFPLL_VDD_LOW] = LVL_LOW,
- .vdd[HFPLL_VDD_NOM] = LVL_NOM,
- .vdd[HFPLL_VDD_HIGH] = LVL_HIGH,
-};
-
-static struct scalable scalable[] __initdata = {
- [CPU0] = {
- .hfpll_phys_base = 0x00903200,
- .aux_clk_sel_phys = 0x02088014,
- .aux_clk_sel = 3,
- .sec_clk_sel = 2,
- .l2cpmr_iaddr = 0x4501,
- .vreg[VREG_CORE] = { "krait0", 1300000 },
- .vreg[VREG_MEM] = { "krait0_mem", 1150000 },
- .vreg[VREG_DIG] = { "krait0_dig", LVL_HIGH},
- .vreg[VREG_HFPLL_A] = { "krait0_hfpll", 1800000 },
- },
- [CPU1] = {
- .hfpll_phys_base = 0x00903300,
- .aux_clk_sel_phys = 0x02098014,
- .aux_clk_sel = 3,
- .sec_clk_sel = 2,
- .l2cpmr_iaddr = 0x5501,
- .vreg[VREG_CORE] = { "krait1", 1300000 },
- .vreg[VREG_MEM] = { "krait1_mem", 1150000 },
- .vreg[VREG_DIG] = { "krait1_dig", LVL_HIGH},
- .vreg[VREG_HFPLL_A] = { "krait1_hfpll", 1800000 },
- },
- [L2] = {
- .hfpll_phys_base = 0x00903400,
- .aux_clk_sel_phys = 0x02011028,
- .aux_clk_sel = 3,
- .sec_clk_sel = 2,
- .l2cpmr_iaddr = 0x0500,
- .vreg[VREG_HFPLL_A] = { "l2_hfpll", 1800000 },
- },
-};
-
-static struct msm_bus_paths bw_level_tbl[] __initdata = {
- [0] = BW_MBPS(640), /* At least 80 MHz on bus. */
- [1] = BW_MBPS(1064), /* At least 133 MHz on bus. */
- [2] = BW_MBPS(1600), /* At least 200 MHz on bus. */
- [3] = BW_MBPS(2128), /* At least 266 MHz on bus. */
- [4] = BW_MBPS(3200), /* At least 400 MHz on bus. */
- [5] = BW_MBPS(3600), /* At least 450 MHz on bus. */
- [6] = BW_MBPS(3936), /* At least 492 MHz on bus. */
- [7] = BW_MBPS(4264), /* At least 533 MHz on bus. */
-};
-
-static struct msm_bus_scale_pdata bus_scale_data __initdata = {
- .usecase = bw_level_tbl,
- .num_usecases = ARRAY_SIZE(bw_level_tbl),
- .active_only = 1,
- .name = "acpuclk-8930aa",
-};
-
-static struct l2_level l2_freq_tbl[] __initdata = {
- [0] = { { 384000, PLL_8, 0, 0x00 }, LVL_LOW, 1050000, 1 },
- [1] = { { 432000, HFPLL, 2, 0x20 }, LVL_NOM, 1050000, 2 },
- [2] = { { 486000, HFPLL, 2, 0x24 }, LVL_NOM, 1050000, 2 },
- [3] = { { 540000, HFPLL, 2, 0x28 }, LVL_NOM, 1050000, 2 },
- [4] = { { 594000, HFPLL, 1, 0x16 }, LVL_NOM, 1050000, 2 },
- [5] = { { 648000, HFPLL, 1, 0x18 }, LVL_NOM, 1050000, 4 },
- [6] = { { 702000, HFPLL, 1, 0x1A }, LVL_NOM, 1050000, 4 },
- [7] = { { 756000, HFPLL, 1, 0x1C }, LVL_HIGH, 1150000, 4 },
- [8] = { { 810000, HFPLL, 1, 0x1E }, LVL_HIGH, 1150000, 4 },
- [9] = { { 864000, HFPLL, 1, 0x20 }, LVL_HIGH, 1150000, 4 },
- [10] = { { 918000, HFPLL, 1, 0x22 }, LVL_HIGH, 1150000, 7 },
- [11] = { { 972000, HFPLL, 1, 0x24 }, LVL_HIGH, 1150000, 7 },
- [12] = { { 1026000, HFPLL, 1, 0x26 }, LVL_HIGH, 1150000, 7 },
- [13] = { { 1080000, HFPLL, 1, 0x28 }, LVL_HIGH, 1150000, 7 },
- [14] = { { 1134000, HFPLL, 1, 0x2A }, LVL_HIGH, 1150000, 7 },
- [15] = { { 1188000, HFPLL, 1, 0x2C }, LVL_HIGH, 1150000, 7 },
- { }
-};
-
-static struct acpu_level acpu_freq_tbl_slow[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 950000 },
- { 0, { 432000, HFPLL, 2, 0x20 }, L2(5), 975000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 975000 },
- { 0, { 540000, HFPLL, 2, 0x28 }, L2(5), 1000000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 1000000 },
- { 0, { 648000, HFPLL, 1, 0x18 }, L2(5), 1025000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 1025000 },
- { 0, { 756000, HFPLL, 1, 0x1C }, L2(10), 1075000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(10), 1075000 },
- { 0, { 864000, HFPLL, 1, 0x20 }, L2(10), 1100000 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(10), 1100000 },
- { 0, { 972000, HFPLL, 1, 0x24 }, L2(10), 1125000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(10), 1125000 },
- { 0, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1175000 },
- { 0, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1200000 },
- { 0, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1225000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1225000 },
- { 1, { 1404000, HFPLL, 1, 0x34 }, L2(15), 1237500 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_nom[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 925000 },
- { 0, { 432000, HFPLL, 2, 0x20 }, L2(5), 950000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 950000 },
- { 0, { 540000, HFPLL, 2, 0x28 }, L2(5), 975000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 975000 },
- { 0, { 648000, HFPLL, 1, 0x18 }, L2(5), 1000000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 1000000 },
- { 0, { 756000, HFPLL, 1, 0x1C }, L2(10), 1050000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(10), 1050000 },
- { 0, { 864000, HFPLL, 1, 0x20 }, L2(10), 1075000 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(10), 1075000 },
- { 0, { 972000, HFPLL, 1, 0x24 }, L2(10), 1100000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(10), 1100000 },
- { 0, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1150000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1150000 },
- { 0, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1175000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1175000 },
- { 0, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1200000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1200000 },
- { 1, { 1404000, HFPLL, 1, 0x34 }, L2(15), 1212500 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_fast[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 900000 },
- { 0, { 432000, HFPLL, 2, 0x20 }, L2(5), 900000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 900000 },
- { 0, { 540000, HFPLL, 2, 0x28 }, L2(5), 925000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 925000 },
- { 0, { 648000, HFPLL, 1, 0x18 }, L2(5), 950000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 950000 },
- { 0, { 756000, HFPLL, 1, 0x1C }, L2(10), 1000000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(10), 1000000 },
- { 0, { 864000, HFPLL, 1, 0x20 }, L2(10), 1025000 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(10), 1025000 },
- { 0, { 972000, HFPLL, 1, 0x24 }, L2(10), 1050000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(10), 1050000 },
- { 0, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1100000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1100000 },
- { 0, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1125000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1125000 },
- { 0, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1150000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1150000 },
- { 1, { 1404000, HFPLL, 1, 0x34 }, L2(15), 1162500 },
- { 0, { 0 } }
-};
-
-static struct pvs_table pvs_tables[NUM_SPEED_BINS][NUM_PVS] __initdata = {
-[0][PVS_SLOW] = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow), 0 },
-[0][PVS_NOMINAL] = { acpu_freq_tbl_nom, sizeof(acpu_freq_tbl_nom), 25000 },
-[0][PVS_FAST] = { acpu_freq_tbl_fast, sizeof(acpu_freq_tbl_fast), 25000 },
-};
-
-static struct acpuclk_krait_params acpuclk_8930aa_params __initdata = {
- .scalable = scalable,
- .scalable_size = sizeof(scalable),
- .hfpll_data = &hfpll_data,
- .pvs_tables = pvs_tables,
- .l2_freq_tbl = l2_freq_tbl,
- .l2_freq_tbl_size = sizeof(l2_freq_tbl),
- .bus_scale = &bus_scale_data,
- .pte_efuse_phys = 0x007000C0,
- .get_bin_info = get_krait_bin_format_a,
- .stby_khz = 384000,
-};
-
-static int __init acpuclk_8930aa_probe(struct platform_device *pdev)
-{
- return acpuclk_krait_init(&pdev->dev, &acpuclk_8930aa_params);
-}
-
-static struct platform_driver acpuclk_8930aa_driver = {
- .driver = {
- .name = "acpuclk-8930aa",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init acpuclk_8930aa_init(void)
-{
- return platform_driver_probe(&acpuclk_8930aa_driver,
- acpuclk_8930aa_probe);
-}
-device_initcall(acpuclk_8930aa_init);
diff --git a/arch/arm/mach-msm/acpuclock-8930ab.c b/arch/arm/mach-msm/acpuclock-8930ab.c
deleted file mode 100644
index 7ec267b..0000000
--- a/arch/arm/mach-msm/acpuclock-8930ab.c
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <mach/rpm-regulator.h>
-#include <mach/msm_bus_board.h>
-#include <mach/msm_bus.h>
-
-#include "acpuclock.h"
-#include "acpuclock-krait.h"
-
-/* Corner type vreg VDD values */
-#define LVL_NONE RPM_VREG_CORNER_NONE
-#define LVL_LOW RPM_VREG_CORNER_LOW
-#define LVL_NOM RPM_VREG_CORNER_NOMINAL
-#define LVL_HIGH RPM_VREG_CORNER_HIGH
-
-static struct hfpll_data hfpll_data __initdata = {
- .mode_offset = 0x00,
- .l_offset = 0x08,
- .m_offset = 0x0C,
- .n_offset = 0x10,
- .config_offset = 0x04,
- .config_val = 0x7845C665,
- .has_droop_ctl = true,
- .droop_offset = 0x14,
- .droop_val = 0x0108C000,
- .low_vdd_l_max = 37,
- .nom_vdd_l_max = 74,
- .vdd[HFPLL_VDD_NONE] = LVL_NONE,
- .vdd[HFPLL_VDD_LOW] = LVL_LOW,
- .vdd[HFPLL_VDD_NOM] = LVL_NOM,
- .vdd[HFPLL_VDD_HIGH] = LVL_HIGH,
-};
-
-static struct scalable scalable_pm8917[] __initdata = {
- [CPU0] = {
- .hfpll_phys_base = 0x00903200,
- .aux_clk_sel_phys = 0x02088014,
- .aux_clk_sel = 3,
- .sec_clk_sel = 2,
- .l2cpmr_iaddr = 0x4501,
- .vreg[VREG_CORE] = { "krait0", 1300000 },
- .vreg[VREG_MEM] = { "krait0_mem", 1150000 },
- .vreg[VREG_DIG] = { "krait0_dig", LVL_HIGH},
- .vreg[VREG_HFPLL_A] = { "krait0_s8", 2050000 },
- .vreg[VREG_HFPLL_B] = { "krait0_l23", 1800000 },
- },
- [CPU1] = {
- .hfpll_phys_base = 0x00903300,
- .aux_clk_sel_phys = 0x02098014,
- .aux_clk_sel = 3,
- .sec_clk_sel = 2,
- .l2cpmr_iaddr = 0x5501,
- .vreg[VREG_CORE] = { "krait1", 1300000 },
- .vreg[VREG_MEM] = { "krait1_mem", 1150000 },
- .vreg[VREG_DIG] = { "krait1_dig", LVL_HIGH},
- .vreg[VREG_HFPLL_A] = { "krait1_s8", 2050000 },
- .vreg[VREG_HFPLL_B] = { "krait1_l23", 1800000 },
- },
- [L2] = {
- .hfpll_phys_base = 0x00903400,
- .aux_clk_sel_phys = 0x02011028,
- .aux_clk_sel = 3,
- .sec_clk_sel = 2,
- .l2cpmr_iaddr = 0x0500,
- .vreg[VREG_HFPLL_A] = { "l2_s8", 2050000 },
- .vreg[VREG_HFPLL_B] = { "l2_l23", 1800000 },
- },
-};
-
-static struct scalable scalable[] __initdata = {
- [CPU0] = {
- .hfpll_phys_base = 0x00903200,
- .aux_clk_sel_phys = 0x02088014,
- .aux_clk_sel = 3,
- .sec_clk_sel = 2,
- .l2cpmr_iaddr = 0x4501,
- .vreg[VREG_CORE] = { "krait0", 1300000 },
- .vreg[VREG_MEM] = { "krait0_mem", 1150000 },
- .vreg[VREG_DIG] = { "krait0_dig", LVL_HIGH},
- .vreg[VREG_HFPLL_A] = { "krait0_hfpll", 1800000 },
- },
- [CPU1] = {
- .hfpll_phys_base = 0x00903300,
- .aux_clk_sel_phys = 0x02098014,
- .aux_clk_sel = 3,
- .sec_clk_sel = 2,
- .l2cpmr_iaddr = 0x5501,
- .vreg[VREG_CORE] = { "krait1", 1300000 },
- .vreg[VREG_MEM] = { "krait1_mem", 1150000 },
- .vreg[VREG_DIG] = { "krait1_dig", LVL_HIGH},
- .vreg[VREG_HFPLL_A] = { "krait1_hfpll", 1800000 },
- },
- [L2] = {
- .hfpll_phys_base = 0x00903400,
- .aux_clk_sel_phys = 0x02011028,
- .aux_clk_sel = 3,
- .sec_clk_sel = 2,
- .l2cpmr_iaddr = 0x0500,
- .vreg[VREG_HFPLL_A] = { "l2_hfpll", 1800000 },
- },
-};
-
-static struct msm_bus_paths bw_level_tbl[] __initdata = {
- [0] = BW_MBPS(640), /* At least 80 MHz on bus. */
- [1] = BW_MBPS(1064), /* At least 133 MHz on bus. */
- [2] = BW_MBPS(1600), /* At least 200 MHz on bus. */
- [3] = BW_MBPS(2128), /* At least 266 MHz on bus. */
- [4] = BW_MBPS(3200), /* At least 400 MHz on bus. */
- [5] = BW_MBPS(4800), /* At least 600 MHz on bus. */
-};
-
-static struct msm_bus_scale_pdata bus_scale_data __initdata = {
- .usecase = bw_level_tbl,
- .num_usecases = ARRAY_SIZE(bw_level_tbl),
- .active_only = 1,
- .name = "acpuclk-8930ab",
-};
-
-static struct l2_level l2_freq_tbl[] __initdata = {
- [0] = { { 384000, PLL_8, 0, 0x00 }, LVL_LOW, 1050000, 1 },
- [1] = { { 432000, HFPLL, 2, 0x20 }, LVL_NOM, 1050000, 2 },
- [2] = { { 486000, HFPLL, 2, 0x24 }, LVL_NOM, 1050000, 2 },
- [3] = { { 540000, HFPLL, 2, 0x28 }, LVL_NOM, 1050000, 2 },
- [4] = { { 594000, HFPLL, 1, 0x16 }, LVL_NOM, 1050000, 2 },
- [5] = { { 648000, HFPLL, 1, 0x18 }, LVL_NOM, 1050000, 4 },
- [6] = { { 702000, HFPLL, 1, 0x1A }, LVL_NOM, 1050000, 4 },
- [7] = { { 756000, HFPLL, 1, 0x1C }, LVL_HIGH, 1150000, 4 },
- [8] = { { 810000, HFPLL, 1, 0x1E }, LVL_HIGH, 1150000, 4 },
- [9] = { { 864000, HFPLL, 1, 0x20 }, LVL_HIGH, 1150000, 4 },
- [10] = { { 918000, HFPLL, 1, 0x22 }, LVL_HIGH, 1150000, 5 },
- [11] = { { 972000, HFPLL, 1, 0x24 }, LVL_HIGH, 1150000, 5 },
- [12] = { { 1026000, HFPLL, 1, 0x26 }, LVL_HIGH, 1150000, 5 },
- [13] = { { 1080000, HFPLL, 1, 0x28 }, LVL_HIGH, 1150000, 5 },
- [14] = { { 1134000, HFPLL, 1, 0x2A }, LVL_HIGH, 1150000, 5 },
- [15] = { { 1188000, HFPLL, 1, 0x2C }, LVL_HIGH, 1150000, 5 },
- { }
-};
-
-static struct acpu_level tbl_PVS0_1700MHz[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 1000000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 1000000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 1000000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 1025000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(10), 1050000 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(10), 1075000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(10), 1100000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1125000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1150000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1175000 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1200000 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1225000 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1250000 },
- { 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1275000 },
- { 0, { 0 } }
-};
-
-static struct acpu_level tbl_PVS1_1700MHz[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 975000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 975000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 1000000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 1000000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(10), 1025000 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(10), 1050000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(10), 1075000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1100000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1125000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1150000 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1175000 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1200000 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1225000 },
- { 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1250000 },
- { 0, { 0 } }
-};
-
-static struct acpu_level tbl_PVS2_1700MHz[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 950000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 950000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 950000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 975000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(10), 1000000 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(10), 1025000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(10), 1050000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1075000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1100000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1125000 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1150000 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1175000 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1200000 },
- { 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1225000 },
- { 0, { 0 } }
-};
-
-static struct acpu_level tbl_PVS3_1700MHz[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 925000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 925000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 925000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 950000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(10), 975000 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(10), 1000000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(10), 1025000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1050000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1075000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1100000 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1125000 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1150000 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1175000 },
- { 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1200000 },
- { 0, { 0 } }
-};
-
-static struct acpu_level tbl_PVS4_1700MHz[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 925000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 925000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 925000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 925000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(10), 950000 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(10), 975000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(10), 1000000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1025000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1050000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1075000 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1100000 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1125000 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1150000 },
- { 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1175000 },
- { 0, { 0 } }
-};
-
-static struct acpu_level tbl_PVS5_1700MHz[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 900000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 900000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 900000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 900000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(10), 925000 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(10), 950000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(10), 975000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1000000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1025000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1050000 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1075000 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1100000 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1125000 },
- { 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1150000 },
- { 0, { 0 } }
-};
-
-static struct acpu_level tbl_PVS6_1700MHz[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 875000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 875000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 875000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 875000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(10), 900000 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(10), 925000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(10), 950000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 975000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1000000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1025000 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1050000 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1075000 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1100000 },
- { 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1125000 },
- { 0, { 0 } }
-};
-
-static struct pvs_table pvs_tables[NUM_SPEED_BINS][NUM_PVS] __initdata = {
- [0][0] = { tbl_PVS0_1700MHz, sizeof(tbl_PVS0_1700MHz), 0 },
- [0][1] = { tbl_PVS1_1700MHz, sizeof(tbl_PVS1_1700MHz), 25000 },
- [0][2] = { tbl_PVS2_1700MHz, sizeof(tbl_PVS2_1700MHz), 25000 },
- [0][3] = { tbl_PVS3_1700MHz, sizeof(tbl_PVS3_1700MHz), 25000 },
- [0][4] = { tbl_PVS4_1700MHz, sizeof(tbl_PVS4_1700MHz), 25000 },
- [0][5] = { tbl_PVS5_1700MHz, sizeof(tbl_PVS5_1700MHz), 25000 },
- [0][6] = { tbl_PVS6_1700MHz, sizeof(tbl_PVS6_1700MHz), 25000 },
-};
-
-static struct acpuclk_krait_params acpuclk_8930ab_params __initdata = {
- .scalable = scalable,
- .scalable_size = sizeof(scalable),
- .hfpll_data = &hfpll_data,
- .pvs_tables = pvs_tables,
- .l2_freq_tbl = l2_freq_tbl,
- .l2_freq_tbl_size = sizeof(l2_freq_tbl),
- .bus_scale = &bus_scale_data,
- .pte_efuse_phys = 0x007000C0,
- .get_bin_info = get_krait_bin_format_a,
- .stby_khz = 384000,
-};
-
-static int __init acpuclk_8930ab_probe(struct platform_device *pdev)
-{
- struct acpuclk_platform_data *pdata = pdev->dev.platform_data;
- if (pdata && pdata->uses_pm8917)
- acpuclk_8930ab_params.scalable = scalable_pm8917;
-
- return acpuclk_krait_init(&pdev->dev, &acpuclk_8930ab_params);
-}
-
-static struct platform_driver acpuclk_8930ab_driver = {
- .driver = {
- .name = "acpuclk-8930ab",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init acpuclk_8930ab_init(void)
-{
- return platform_driver_probe(&acpuclk_8930ab_driver,
- acpuclk_8930ab_probe);
-}
-device_initcall(acpuclk_8930ab_init);
diff --git a/arch/arm/mach-msm/acpuclock-8960.c b/arch/arm/mach-msm/acpuclock-8960.c
deleted file mode 100644
index 317729f..0000000
--- a/arch/arm/mach-msm/acpuclock-8960.c
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <mach/rpm-regulator.h>
-#include <mach/msm_bus_board.h>
-#include <mach/msm_bus.h>
-
-#include "acpuclock.h"
-#include "acpuclock-krait.h"
-
-static struct hfpll_data hfpll_data __initdata = {
- .mode_offset = 0x00,
- .l_offset = 0x08,
- .m_offset = 0x0C,
- .n_offset = 0x10,
- .config_offset = 0x04,
- .config_val = 0x7845C665,
- .has_droop_ctl = true,
- .droop_offset = 0x14,
- .droop_val = 0x0108C000,
- .low_vdd_l_max = 22,
- .nom_vdd_l_max = 42,
- .vdd[HFPLL_VDD_NONE] = 0,
- .vdd[HFPLL_VDD_LOW] = 945000,
- .vdd[HFPLL_VDD_NOM] = 1050000,
- .vdd[HFPLL_VDD_HIGH] = 1150000,
-};
-
-static struct scalable scalable[] __initdata = {
- [CPU0] = {
- .hfpll_phys_base = 0x00903200,
- .aux_clk_sel_phys = 0x02088014,
- .aux_clk_sel = 3,
- .sec_clk_sel = 2,
- .l2cpmr_iaddr = 0x4501,
- .vreg[VREG_CORE] = { "krait0", 1300000 },
- .vreg[VREG_MEM] = { "krait0_mem", 1150000 },
- .vreg[VREG_DIG] = { "krait0_dig", 1150000 },
- .vreg[VREG_HFPLL_A] = { "krait0_s8", 2050000 },
- .vreg[VREG_HFPLL_B] = { "krait0_l23", 1800000 },
- },
- [CPU1] = {
- .hfpll_phys_base = 0x00903300,
- .aux_clk_sel_phys = 0x02098014,
- .aux_clk_sel = 3,
- .sec_clk_sel = 2,
- .l2cpmr_iaddr = 0x5501,
- .vreg[VREG_CORE] = { "krait1", 1300000 },
- .vreg[VREG_MEM] = { "krait1_mem", 1150000 },
- .vreg[VREG_DIG] = { "krait1_dig", 1150000 },
- .vreg[VREG_HFPLL_A] = { "krait1_s8", 2050000 },
- .vreg[VREG_HFPLL_B] = { "krait1_l23", 1800000 },
- },
- [L2] = {
- .hfpll_phys_base = 0x00903400,
- .aux_clk_sel_phys = 0x02011028,
- .aux_clk_sel = 3,
- .sec_clk_sel = 2,
- .l2cpmr_iaddr = 0x0500,
- .vreg[VREG_HFPLL_A] = { "l2_s8", 2050000 },
- .vreg[VREG_HFPLL_B] = { "l2_l23", 1800000 },
- },
-};
-
-static struct msm_bus_paths bw_level_tbl[] __initdata = {
- [0] = BW_MBPS(640), /* At least 80 MHz on bus. */
- [1] = BW_MBPS(1064), /* At least 133 MHz on bus. */
- [2] = BW_MBPS(1600), /* At least 200 MHz on bus. */
- [3] = BW_MBPS(2128), /* At least 266 MHz on bus. */
- [4] = BW_MBPS(3200), /* At least 400 MHz on bus. */
- [5] = BW_MBPS(3600), /* At least 450 MHz on bus. */
- [6] = BW_MBPS(3936), /* At least 492 MHz on bus. */
-};
-
-static struct msm_bus_scale_pdata bus_scale_data __initdata = {
- .usecase = bw_level_tbl,
- .num_usecases = ARRAY_SIZE(bw_level_tbl),
- .active_only = 1,
- .name = "acpuclk-8960",
-};
-
-static struct l2_level l2_freq_tbl[] __initdata = {
- [0] = { { 384000, PLL_8, 0, 0x00 }, 1050000, 1050000, 1 },
- [1] = { { 432000, HFPLL, 2, 0x20 }, 1050000, 1050000, 2 },
- [2] = { { 486000, HFPLL, 2, 0x24 }, 1050000, 1050000, 2 },
- [3] = { { 540000, HFPLL, 2, 0x28 }, 1050000, 1050000, 2 },
- [4] = { { 594000, HFPLL, 1, 0x16 }, 1050000, 1050000, 2 },
- [5] = { { 648000, HFPLL, 1, 0x18 }, 1050000, 1050000, 4 },
- [6] = { { 702000, HFPLL, 1, 0x1A }, 1050000, 1050000, 4 },
- [7] = { { 756000, HFPLL, 1, 0x1C }, 1150000, 1150000, 4 },
- [8] = { { 810000, HFPLL, 1, 0x1E }, 1150000, 1150000, 4 },
- [9] = { { 864000, HFPLL, 1, 0x20 }, 1150000, 1150000, 4 },
- [10] = { { 918000, HFPLL, 1, 0x22 }, 1150000, 1150000, 6 },
- [11] = { { 972000, HFPLL, 1, 0x24 }, 1150000, 1150000, 6 },
- [12] = { { 1026000, HFPLL, 1, 0x26 }, 1150000, 1150000, 6 },
- [13] = { { 1080000, HFPLL, 1, 0x28 }, 1150000, 1150000, 6 },
- [14] = { { 1134000, HFPLL, 1, 0x2A }, 1150000, 1150000, 6 },
- [15] = { { 1188000, HFPLL, 1, 0x2C }, 1150000, 1150000, 6 },
- [16] = { { 1242000, HFPLL, 1, 0x2E }, 1150000, 1150000, 6 },
- [17] = { { 1296000, HFPLL, 1, 0x30 }, 1150000, 1150000, 6 },
- [18] = { { 1350000, HFPLL, 1, 0x32 }, 1150000, 1150000, 6 },
- { }
-};
-
-#define AVS(x) .avsdscr_setting = (x)
-
-static struct acpu_level acpu_freq_tbl_slow[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 950000, AVS(0x40001F) },
- { 0, { 432000, HFPLL, 2, 0x20 }, L2(6), 975000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(6), 975000 },
- { 0, { 540000, HFPLL, 2, 0x28 }, L2(6), 1000000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(6), 1000000 },
- { 0, { 648000, HFPLL, 1, 0x18 }, L2(6), 1025000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(6), 1025000 },
- { 0, { 756000, HFPLL, 1, 0x1C }, L2(6), 1075000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(6), 1075000 },
- { 0, { 864000, HFPLL, 1, 0x20 }, L2(6), 1100000 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(6), 1100000 },
- { 0, { 972000, HFPLL, 1, 0x24 }, L2(6), 1125000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(6), 1125000 },
- { 0, { 1080000, HFPLL, 1, 0x28 }, L2(18), 1175000, AVS(0x400015) },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(18), 1175000, AVS(0x400015) },
- { 0, { 1188000, HFPLL, 1, 0x2C }, L2(18), 1200000, AVS(0x400015) },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(18), 1200000, AVS(0x400015) },
- { 0, { 1296000, HFPLL, 1, 0x30 }, L2(18), 1225000, AVS(0x400015) },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(18), 1225000, AVS(0x400015) },
- { 0, { 1404000, HFPLL, 1, 0x34 }, L2(18), 1237500, AVS(0x400015) },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(18), 1237500, AVS(0x100018) },
- { 1, { 1512000, HFPLL, 1, 0x38 }, L2(18), 1250000, AVS(0x400012) },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_nom[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 900000, AVS(0x40007F) },
- { 0, { 432000, HFPLL, 2, 0x20 }, L2(6), 925000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(6), 925000 },
- { 0, { 540000, HFPLL, 2, 0x28 }, L2(6), 950000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(6), 950000 },
- { 0, { 648000, HFPLL, 1, 0x18 }, L2(6), 975000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(6), 975000 },
- { 0, { 756000, HFPLL, 1, 0x1C }, L2(6), 1025000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(6), 1025000 },
- { 0, { 864000, HFPLL, 1, 0x20 }, L2(6), 1050000 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(6), 1050000 },
- { 0, { 972000, HFPLL, 1, 0x24 }, L2(6), 1075000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(6), 1075000 },
- { 0, { 1080000, HFPLL, 1, 0x28 }, L2(18), 1125000, AVS(0x400015) },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(18), 1125000, AVS(0x400015) },
- { 0, { 1188000, HFPLL, 1, 0x2C }, L2(18), 1150000, AVS(0x400015) },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(18), 1150000, AVS(0x400015) },
- { 0, { 1296000, HFPLL, 1, 0x30 }, L2(18), 1175000, AVS(0x400015) },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(18), 1175000, AVS(0x400015) },
- { 0, { 1404000, HFPLL, 1, 0x34 }, L2(18), 1187500, AVS(0x400015) },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(18), 1187500, AVS(0x100018) },
- { 1, { 1512000, HFPLL, 1, 0x38 }, L2(18), 1200000, AVS(0x400012) },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_fast[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 850000, AVS(0x4000FF) },
- { 0, { 432000, HFPLL, 2, 0x20 }, L2(6), 875000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(6), 875000 },
- { 0, { 540000, HFPLL, 2, 0x28 }, L2(6), 900000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(6), 900000 },
- { 0, { 648000, HFPLL, 1, 0x18 }, L2(6), 925000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(6), 925000 },
- { 0, { 756000, HFPLL, 1, 0x1C }, L2(6), 975000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(6), 975000 },
- { 0, { 864000, HFPLL, 1, 0x20 }, L2(6), 1000000 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(6), 1000000 },
- { 0, { 972000, HFPLL, 1, 0x24 }, L2(6), 1025000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(6), 1025000 },
- { 0, { 1080000, HFPLL, 1, 0x28 }, L2(18), 1075000, AVS(0x10001B) },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(18), 1075000, AVS(0x10001B) },
- { 0, { 1188000, HFPLL, 1, 0x2C }, L2(18), 1100000, AVS(0x10001B) },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(18), 1100000, AVS(0x10001B) },
- { 0, { 1296000, HFPLL, 1, 0x30 }, L2(18), 1125000, AVS(0x10001B) },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(18), 1125000, AVS(0x400012) },
- { 0, { 1404000, HFPLL, 1, 0x34 }, L2(18), 1137500, AVS(0x400012) },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(18), 1137500, AVS(0x400012) },
- { 1, { 1512000, HFPLL, 1, 0x38 }, L2(18), 1150000, AVS(0x400012) },
- { 0, { 0 } }
-};
-
-static struct pvs_table pvs_tables[NUM_SPEED_BINS][NUM_PVS] __initdata = {
-[0][PVS_SLOW] = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow), 0 },
-[0][PVS_NOMINAL] = { acpu_freq_tbl_nom, sizeof(acpu_freq_tbl_nom), 25000 },
-[0][PVS_FAST] = { acpu_freq_tbl_fast, sizeof(acpu_freq_tbl_fast), 25000 },
-};
-
-static struct acpuclk_krait_params acpuclk_8960_params __initdata = {
- .scalable = scalable,
- .scalable_size = sizeof(scalable),
- .hfpll_data = &hfpll_data,
- .pvs_tables = pvs_tables,
- .l2_freq_tbl = l2_freq_tbl,
- .l2_freq_tbl_size = sizeof(l2_freq_tbl),
- .bus_scale = &bus_scale_data,
- .pte_efuse_phys = 0x007000C0,
- .get_bin_info = get_krait_bin_format_a,
- .stby_khz = 384000,
-};
-
-static int __init acpuclk_8960_probe(struct platform_device *pdev)
-{
- return acpuclk_krait_init(&pdev->dev, &acpuclk_8960_params);
-}
-
-static struct platform_driver acpuclk_8960_driver = {
- .driver = {
- .name = "acpuclk-8960",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init acpuclk_8960_init(void)
-{
- return platform_driver_probe(&acpuclk_8960_driver, acpuclk_8960_probe);
-}
-device_initcall(acpuclk_8960_init);
diff --git a/arch/arm/mach-msm/acpuclock-8960ab.c b/arch/arm/mach-msm/acpuclock-8960ab.c
deleted file mode 100644
index 0fa2cde..0000000
--- a/arch/arm/mach-msm/acpuclock-8960ab.c
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <mach/rpm-regulator.h>
-#include <mach/msm_bus_board.h>
-#include <mach/msm_bus.h>
-
-#include "acpuclock.h"
-#include "acpuclock-krait.h"
-
-static struct hfpll_data hfpll_data __initdata = {
- .mode_offset = 0x00,
- .l_offset = 0x08,
- .m_offset = 0x0C,
- .n_offset = 0x10,
- .config_offset = 0x04,
- .config_val = 0x7845C665,
- .has_droop_ctl = true,
- .droop_offset = 0x14,
- .droop_val = 0x0108C000,
- .low_vdd_l_max = 37,
- .nom_vdd_l_max = 74,
- .vdd[HFPLL_VDD_NONE] = 0,
- .vdd[HFPLL_VDD_LOW] = 945000,
- .vdd[HFPLL_VDD_NOM] = 1050000,
- .vdd[HFPLL_VDD_HIGH] = 1150000,
-};
-
-static struct scalable scalable[] __initdata = {
- [CPU0] = {
- .hfpll_phys_base = 0x00903200,
- .aux_clk_sel_phys = 0x02088014,
- .aux_clk_sel = 3,
- .sec_clk_sel = 2,
- .l2cpmr_iaddr = 0x4501,
- .vreg[VREG_CORE] = { "krait0", 1300000 },
- .vreg[VREG_MEM] = { "krait0_mem", 1150000 },
- .vreg[VREG_DIG] = { "krait0_dig", 1150000 },
- .vreg[VREG_HFPLL_A] = { "krait0_s8", 2050000 },
- .vreg[VREG_HFPLL_B] = { "krait0_l23", 1800000 },
- },
- [CPU1] = {
- .hfpll_phys_base = 0x00903300,
- .aux_clk_sel_phys = 0x02098014,
- .aux_clk_sel = 3,
- .sec_clk_sel = 2,
- .l2cpmr_iaddr = 0x5501,
- .vreg[VREG_CORE] = { "krait1", 1300000 },
- .vreg[VREG_MEM] = { "krait1_mem", 1150000 },
- .vreg[VREG_DIG] = { "krait1_dig", 1150000 },
- .vreg[VREG_HFPLL_A] = { "krait1_s8", 2050000 },
- .vreg[VREG_HFPLL_B] = { "krait1_l23", 1800000 },
- },
- [L2] = {
- .hfpll_phys_base = 0x00903400,
- .aux_clk_sel_phys = 0x02011028,
- .aux_clk_sel = 3,
- .sec_clk_sel = 2,
- .l2cpmr_iaddr = 0x0500,
- .vreg[VREG_HFPLL_A] = { "l2_s8", 2050000 },
- .vreg[VREG_HFPLL_B] = { "l2_l23", 1800000 },
- },
-};
-
-static struct msm_bus_paths bw_level_tbl[] __initdata = {
- [0] = BW_MBPS(640), /* At least 80 MHz on bus. */
- [1] = BW_MBPS(1064), /* At least 133 MHz on bus. */
- [2] = BW_MBPS(1600), /* At least 200 MHz on bus. */
- [3] = BW_MBPS(2128), /* At least 266 MHz on bus. */
- [4] = BW_MBPS(3200), /* At least 400 MHz on bus. */
- [5] = BW_MBPS(4264), /* At least 533 MHz on bus. */
-};
-
-static struct msm_bus_scale_pdata bus_scale_data __initdata = {
- .usecase = bw_level_tbl,
- .num_usecases = ARRAY_SIZE(bw_level_tbl),
- .active_only = 1,
- .name = "acpuclk-8960ab",
-};
-
-static struct l2_level l2_freq_tbl[] __initdata = {
- [0] = { { 384000, PLL_8, 0, 0x00 }, 1050000, 1050000, 1 },
- [1] = { { 486000, HFPLL, 2, 0x24 }, 1050000, 1050000, 2 },
- [2] = { { 594000, HFPLL, 1, 0x16 }, 1050000, 1050000, 2 },
- [3] = { { 702000, HFPLL, 1, 0x1A }, 1050000, 1050000, 4 },
- [4] = { { 810000, HFPLL, 1, 0x1E }, 1050000, 1050000, 4 },
- [5] = { { 918000, HFPLL, 1, 0x22 }, 1150000, 1150000, 5 },
- [6] = { { 1026000, HFPLL, 1, 0x26 }, 1150000, 1150000, 5 },
- [7] = { { 1134000, HFPLL, 1, 0x2A }, 1150000, 1150000, 5 },
- [8] = { { 1242000, HFPLL, 1, 0x2E }, 1150000, 1150000, 5 },
- [9] = { { 1350000, HFPLL, 1, 0x32 }, 1150000, 1150000, 5 },
- { }
-};
-
-#define AVS(x) .avsdscr_setting = (x)
-
-static struct acpu_level freq_tbl_PVS0[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 950000, AVS(0x70001F) },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(4), 950000, AVS(0x0) },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(4), 975000, AVS(0x0) },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(4), 1000000, AVS(0x0) },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(4), 1025000, AVS(0x0) },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(4), 1050000, AVS(0x0) },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(4), 1075000, AVS(0x0) },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(9), 1100000, AVS(0x70000D) },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(9), 1125000, AVS(0x0) },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(9), 1150000, AVS(0x0) },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(9), 1175000, AVS(0x0) },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(9), 1200000, AVS(0x0) },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(9), 1225000, AVS(0x0) },
- { 1, { 1728000, HFPLL, 1, 0x40 }, L2(9), 1250000, AVS(0x70000B) },
- { 0, { 0 } }
-};
-
-static struct acpu_level freq_tbl_PVS1[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 925000, AVS(0x70001F) },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(4), 925000, AVS(0x0) },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(4), 950000, AVS(0x0) },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(4), 975000, AVS(0x0) },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(4), 1000000, AVS(0x0) },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(4), 1025000, AVS(0x0) },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(4), 1050000, AVS(0x0) },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(9), 1075000, AVS(0x70000D) },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(9), 1100000, AVS(0x0) },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(9), 1125000, AVS(0x0) },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(9), 1150000, AVS(0x0) },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(9), 1175000, AVS(0x0) },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(9), 1200000, AVS(0x0) },
- { 1, { 1728000, HFPLL, 1, 0x40 }, L2(9), 1225000, AVS(0x70000B) },
- { 0, { 0 } }
-};
-
-static struct acpu_level freq_tbl_PVS2[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 900000, AVS(0x70001F) },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(4), 900000, AVS(0x0) },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(4), 925000, AVS(0x0) },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(4), 950000, AVS(0x0) },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(4), 975000, AVS(0x0) },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(4), 1000000, AVS(0x0) },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(4), 1025000, AVS(0x0) },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(9), 1050000, AVS(0x70000D) },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(9), 1075000, AVS(0x0) },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(9), 1100000, AVS(0x0) },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(9), 1125000, AVS(0x0) },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(9), 1150000, AVS(0x0) },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(9), 1175000, AVS(0x0) },
- { 1, { 1728000, HFPLL, 1, 0x40 }, L2(9), 1200000, AVS(0x70000B) },
- { 0, { 0 } }
-};
-
-static struct acpu_level freq_tbl_PVS3[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 900000, AVS(0x70001F) },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(4), 900000, AVS(0x0) },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(4), 900000, AVS(0x0) },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(4), 925000, AVS(0x0) },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(4), 950000, AVS(0x0) },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(4), 975000, AVS(0x0) },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(4), 1000000, AVS(0x0) },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(9), 1025000, AVS(0x70000D) },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(9), 1050000, AVS(0x0) },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(9), 1075000, AVS(0x0) },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(9), 1100000, AVS(0x0) },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(9), 1125000, AVS(0x0) },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(9), 1150000, AVS(0x0) },
- { 1, { 1728000, HFPLL, 1, 0x40 }, L2(9), 1175000, AVS(0x70000B) },
- { 0, { 0 } }
-};
-
-static struct acpu_level freq_tbl_PVS4[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 875000, AVS(0x70001F) },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(4), 875000, AVS(0x0) },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(4), 875000, AVS(0x0) },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(4), 900000, AVS(0x0) },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(4), 925000, AVS(0x0) },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(4), 950000, AVS(0x0) },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(4), 975000, AVS(0x0) },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(9), 1000000, AVS(0x70000D) },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(9), 1025000, AVS(0x0) },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(9), 1050000, AVS(0x0) },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(9), 1075000, AVS(0x0) },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(9), 1100000, AVS(0x0) },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(9), 1125000, AVS(0x0) },
- { 1, { 1728000, HFPLL, 1, 0x40 }, L2(9), 1150000, AVS(0x70000B) },
- { 0, { 0 } }
-};
-
-static struct acpu_level freq_tbl_PVS5[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 875000, AVS(0x70001F) },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(4), 875000, AVS(0x0) },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(4), 875000, AVS(0x0) },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(4), 875000, AVS(0x0) },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(4), 900000, AVS(0x0) },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(4), 925000, AVS(0x0) },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(4), 950000, AVS(0x0) },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(9), 975000, AVS(0x70000D) },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(9), 1000000, AVS(0x0) },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(9), 1025000, AVS(0x0) },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(9), 1050000, AVS(0x0) },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(9), 1075000, AVS(0x0) },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(9), 1100000, AVS(0x0) },
- { 1, { 1728000, HFPLL, 1, 0x40 }, L2(9), 1125000, AVS(0x70000B) },
- { 0, { 0 } }
-};
-
-static struct acpu_level freq_tbl_PVS6[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 850000, AVS(0x70001F) },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(4), 850000, AVS(0x0) },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(4), 850000, AVS(0x0) },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(4), 850000, AVS(0x0) },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(4), 875000, AVS(0x0) },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(4), 900000, AVS(0x0) },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(4), 925000, AVS(0x0) },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(9), 950000, AVS(0x70000D) },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(9), 975000, AVS(0x0) },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(9), 1000000, AVS(0x0) },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(9), 1025000, AVS(0x0) },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(9), 1050000, AVS(0x0) },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(9), 1075000, AVS(0x0) },
- { 1, { 1728000, HFPLL, 1, 0x40 }, L2(9), 1100000, AVS(0x70000B) },
- { 0, { 0 } }
-};
-
-static struct pvs_table pvs_tables[NUM_SPEED_BINS][NUM_PVS] __initdata = {
-[0][0] = { freq_tbl_PVS0, sizeof(freq_tbl_PVS0), 0 },
-[0][1] = { freq_tbl_PVS1, sizeof(freq_tbl_PVS1), 25000 },
-[0][2] = { freq_tbl_PVS2, sizeof(freq_tbl_PVS2), 25000 },
-[0][3] = { freq_tbl_PVS3, sizeof(freq_tbl_PVS3), 25000 },
-[0][4] = { freq_tbl_PVS4, sizeof(freq_tbl_PVS4), 25000 },
-[0][5] = { freq_tbl_PVS5, sizeof(freq_tbl_PVS5), 25000 },
-[0][6] = { freq_tbl_PVS6, sizeof(freq_tbl_PVS6), 25000 },
-};
-
-static struct acpuclk_krait_params acpuclk_8960ab_params __initdata = {
- .scalable = scalable,
- .scalable_size = sizeof(scalable),
- .hfpll_data = &hfpll_data,
- .pvs_tables = pvs_tables,
- .l2_freq_tbl = l2_freq_tbl,
- .l2_freq_tbl_size = sizeof(l2_freq_tbl),
- .bus_scale = &bus_scale_data,
- .pte_efuse_phys = 0x007000C0,
- .get_bin_info = get_krait_bin_format_a,
- .stby_khz = 384000,
-};
-
-static int __init acpuclk_8960ab_probe(struct platform_device *pdev)
-{
- return acpuclk_krait_init(&pdev->dev, &acpuclk_8960ab_params);
-}
-
-static struct platform_driver acpuclk_8960ab_driver = {
- .driver = {
- .name = "acpuclk-8960ab",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init acpuclk_8960ab_init(void)
-{
- return platform_driver_probe(&acpuclk_8960ab_driver,
- acpuclk_8960ab_probe);
-}
-device_initcall(acpuclk_8960ab_init);
diff --git a/arch/arm/mach-msm/acpuclock-8974.c b/arch/arm/mach-msm/acpuclock-8974.c
deleted file mode 100644
index 60be20a..0000000
--- a/arch/arm/mach-msm/acpuclock-8974.c
+++ /dev/null
@@ -1,2657 +0,0 @@
-/*
- * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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/platform_device.h>
-#include <linux/of.h>
-#include <mach/rpm-regulator-smd.h>
-#include <mach/msm_bus_board.h>
-#include <mach/msm_bus.h>
-#include <mach/socinfo.h>
-
-#include "acpuclock.h"
-#include "acpuclock-krait.h"
-
-/* Corner type vreg VDD values */
-#define LVL_NONE RPM_REGULATOR_CORNER_NONE
-#define LVL_LOW RPM_REGULATOR_CORNER_SVS_SOC
-#define LVL_NOM RPM_REGULATOR_CORNER_NORMAL
-#define LVL_HIGH RPM_REGULATOR_CORNER_SUPER_TURBO
-
-static struct hfpll_data hfpll_data __initdata = {
- .mode_offset = 0x00,
- .l_offset = 0x04,
- .m_offset = 0x08,
- .n_offset = 0x0C,
- .has_user_reg = true,
- .user_offset = 0x10,
- .config_offset = 0x14,
- .user_val = 0x8,
- .user_vco_mask = BIT(20),
- .config_val = 0x04D0405D,
- .has_lock_status = true,
- .status_offset = 0x1C,
- .low_vco_l_max = 65,
- .low_vdd_l_max = 52,
- .nom_vdd_l_max = 104,
- .vdd[HFPLL_VDD_NONE] = LVL_NONE,
- .vdd[HFPLL_VDD_LOW] = LVL_LOW,
- .vdd[HFPLL_VDD_NOM] = LVL_NOM,
- .vdd[HFPLL_VDD_HIGH] = LVL_HIGH,
-};
-
-static struct scalable scalable[] __initdata = {
- [CPU0] = {
- .hfpll_phys_base = 0xF908A000,
- .l2cpmr_iaddr = 0x4501,
- .sec_clk_sel = 2,
- .vreg[VREG_CORE] = { "krait0", 1120000 },
- .vreg[VREG_MEM] = { "krait0_mem", 1050000 },
- .vreg[VREG_DIG] = { "krait0_dig", LVL_HIGH },
- .vreg[VREG_HFPLL_A] = { "krait0_hfpll", 1800000 },
- },
- [CPU1] = {
- .hfpll_phys_base = 0xF909A000,
- .l2cpmr_iaddr = 0x5501,
- .sec_clk_sel = 2,
- .vreg[VREG_CORE] = { "krait1", 1120000 },
- .vreg[VREG_MEM] = { "krait1_mem", 1050000 },
- .vreg[VREG_DIG] = { "krait1_dig", LVL_HIGH },
- .vreg[VREG_HFPLL_A] = { "krait1_hfpll", 1800000 },
- },
- [CPU2] = {
- .hfpll_phys_base = 0xF90AA000,
- .l2cpmr_iaddr = 0x6501,
- .sec_clk_sel = 2,
- .vreg[VREG_CORE] = { "krait2", 1120000 },
- .vreg[VREG_MEM] = { "krait2_mem", 1050000 },
- .vreg[VREG_DIG] = { "krait2_dig", LVL_HIGH },
- .vreg[VREG_HFPLL_A] = { "krait2_hfpll", 1800000 },
- },
- [CPU3] = {
- .hfpll_phys_base = 0xF90BA000,
- .l2cpmr_iaddr = 0x7501,
- .sec_clk_sel = 2,
- .vreg[VREG_CORE] = { "krait3", 1120000 },
- .vreg[VREG_MEM] = { "krait3_mem", 1050000 },
- .vreg[VREG_DIG] = { "krait3_dig", LVL_HIGH },
- .vreg[VREG_HFPLL_A] = { "krait3_hfpll", 1800000 },
- },
- [L2] = {
- .hfpll_phys_base = 0xF9016000,
- .l2cpmr_iaddr = 0x0500,
- .sec_clk_sel = 2,
- .vreg[VREG_HFPLL_A] = { "l2_hfpll", 1800000 },
- },
-};
-
-static struct msm_bus_paths bw_level_tbl_v1[] __initdata = {
- [0] = BW_MBPS(600), /* At least 75 MHz on bus. */
- [1] = BW_MBPS(800), /* At least 100 MHz on bus. */
- [2] = BW_MBPS(1200), /* At least 150 MHz on bus. */
- [3] = BW_MBPS(1600), /* At least 200 MHz on bus. */
- [4] = BW_MBPS(2224), /* At least 278 MHz on bus. */
- [5] = BW_MBPS(3200), /* At least 400 MHz on bus. */
- [6] = BW_MBPS(4448), /* At least 556 MHz on bus. */
- [7] = BW_MBPS(6400), /* At least 800 MHz on bus. */
-};
-
-static struct l2_level l2_freq_tbl_v1[] __initdata = {
- [0] = { { 300000, PLL_0, 0, 0 }, LVL_LOW, 950000, 0 },
- [1] = { { 345600, HFPLL, 2, 36 }, LVL_NOM, 950000, 1 },
- [2] = { { 422400, HFPLL, 2, 44 }, LVL_NOM, 950000, 1 },
- [3] = { { 499200, HFPLL, 2, 52 }, LVL_NOM, 950000, 2 },
- [4] = { { 576000, HFPLL, 1, 30 }, LVL_NOM, 950000, 3 },
- [5] = { { 652800, HFPLL, 1, 34 }, LVL_NOM, 950000, 3 },
- [6] = { { 729600, HFPLL, 1, 38 }, LVL_NOM, 950000, 3 },
- [7] = { { 806400, HFPLL, 1, 42 }, LVL_HIGH, 1050000, 4 },
- [8] = { { 883200, HFPLL, 1, 46 }, LVL_HIGH, 1050000, 4 },
- [9] = { { 960000, HFPLL, 1, 50 }, LVL_HIGH, 1050000, 4 },
- [10] = { { 1036800, HFPLL, 1, 54 }, LVL_HIGH, 1050000, 5 },
- [11] = { { 1113600, HFPLL, 1, 58 }, LVL_HIGH, 1050000, 5 },
- [12] = { { 1190400, HFPLL, 1, 62 }, LVL_HIGH, 1050000, 6 },
- [13] = { { 1267200, HFPLL, 1, 66 }, LVL_HIGH, 1050000, 6 },
- [14] = { { 1344000, HFPLL, 1, 70 }, LVL_HIGH, 1050000, 7 },
- [15] = { { 1420800, HFPLL, 1, 74 }, LVL_HIGH, 1050000, 7 },
- [16] = { { 1497600, HFPLL, 1, 78 }, LVL_HIGH, 1050000, 7 },
- { }
-};
-
-static struct acpu_level acpu_freq_tbl_v1_pvs0[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 825000, 73 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(3), 825000, 85 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(3), 825000, 104 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(6), 825000, 124 },
- { 1, { 576000, HFPLL, 1, 30 }, L2(6), 825000, 144 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(7), 825000, 165 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(7), 825000, 186 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(10), 835000, 208 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(10), 845000, 229 },
- { 0, { 960000, HFPLL, 1, 50 }, L2(10), 860000, 252 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 880000, 275 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(12), 905000, 298 },
- { 0, { 1190400, HFPLL, 1, 62 }, L2(12), 920000, 321 },
- { 0, { 1267200, HFPLL, 1, 66 }, L2(12), 940000, 346 },
- { 1, { 1344000, HFPLL, 1, 70 }, L2(12), 960000, 371 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(16), 980000, 397 },
- { 0, { 1497600, HFPLL, 1, 78 }, L2(16), 995000, 423 },
- { 0, { 1574400, HFPLL, 1, 82 }, L2(16), 1015000, 450 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(16), 1030000, 477 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(16), 1050000, 506 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_v1_pvs1[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 825000, 73 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(3), 825000, 85 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(3), 825000, 104 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(6), 825000, 124 },
- { 1, { 576000, HFPLL, 1, 30 }, L2(6), 825000, 144 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(7), 825000, 165 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(7), 825000, 186 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(10), 835000, 208 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(10), 845000, 229 },
- { 0, { 960000, HFPLL, 1, 50 }, L2(10), 860000, 252 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 880000, 275 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(12), 905000, 298 },
- { 0, { 1190400, HFPLL, 1, 62 }, L2(12), 920000, 321 },
- { 0, { 1267200, HFPLL, 1, 66 }, L2(12), 940000, 346 },
- { 1, { 1344000, HFPLL, 1, 70 }, L2(12), 960000, 371 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(16), 980000, 397 },
- { 0, { 1497600, HFPLL, 1, 78 }, L2(16), 995000, 423 },
- { 0, { 1574400, HFPLL, 1, 82 }, L2(16), 1015000, 450 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(16), 1030000, 477 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(16), 1050000, 506 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_v1_pvs2[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 825000, 73 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(3), 825000, 85 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(3), 825000, 104 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(6), 825000, 124 },
- { 1, { 576000, HFPLL, 1, 30 }, L2(6), 825000, 144 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(7), 825000, 165 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(7), 825000, 186 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(10), 825000, 208 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(10), 825000, 229 },
- { 0, { 960000, HFPLL, 1, 50 }, L2(10), 835000, 252 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 855000, 275 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(12), 875000, 298 },
- { 0, { 1190400, HFPLL, 1, 62 }, L2(12), 895000, 321 },
- { 0, { 1267200, HFPLL, 1, 66 }, L2(12), 915000, 346 },
- { 1, { 1344000, HFPLL, 1, 70 }, L2(12), 930000, 371 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(16), 945000, 397 },
- { 0, { 1497600, HFPLL, 1, 78 }, L2(16), 960000, 423 },
- { 0, { 1574400, HFPLL, 1, 82 }, L2(16), 975000, 450 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(16), 990000, 477 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(16), 1000000, 506 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_v1_pvs3[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 825000, 73 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(3), 825000, 85 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(3), 825000, 104 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(6), 825000, 124 },
- { 1, { 576000, HFPLL, 1, 30 }, L2(6), 825000, 144 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(7), 825000, 165 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(7), 825000, 186 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(10), 825000, 208 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(10), 825000, 229 },
- { 0, { 960000, HFPLL, 1, 50 }, L2(10), 835000, 252 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 855000, 275 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(12), 875000, 298 },
- { 0, { 1190400, HFPLL, 1, 62 }, L2(12), 895000, 321 },
- { 0, { 1267200, HFPLL, 1, 66 }, L2(12), 915000, 346 },
- { 1, { 1344000, HFPLL, 1, 70 }, L2(12), 930000, 371 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(16), 945000, 397 },
- { 0, { 1497600, HFPLL, 1, 78 }, L2(16), 960000, 423 },
- { 0, { 1574400, HFPLL, 1, 82 }, L2(16), 975000, 450 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(16), 990000, 477 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(16), 1000000, 506 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_v1_pvs4[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 825000, 73 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(3), 825000, 85 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(3), 825000, 104 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(6), 825000, 124 },
- { 1, { 576000, HFPLL, 1, 30 }, L2(6), 825000, 144 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(7), 825000, 165 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(7), 825000, 186 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(10), 825000, 208 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(10), 825000, 229 },
- { 0, { 960000, HFPLL, 1, 50 }, L2(10), 825000, 252 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 825000, 275 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(12), 835000, 298 },
- { 0, { 1190400, HFPLL, 1, 62 }, L2(12), 855000, 321 },
- { 0, { 1267200, HFPLL, 1, 66 }, L2(12), 870000, 346 },
- { 1, { 1344000, HFPLL, 1, 70 }, L2(12), 885000, 371 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(16), 900000, 397 },
- { 0, { 1497600, HFPLL, 1, 78 }, L2(16), 910000, 423 },
- { 0, { 1574400, HFPLL, 1, 82 }, L2(16), 925000, 450 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(16), 940000, 477 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(16), 950000, 506 },
- { 0, { 0 } }
-};
-
-static struct msm_bus_paths bw_level_tbl_v2[] __initdata = {
- [0] = BW_MBPS(600), /* At least 75 MHz on bus. */
- [1] = BW_MBPS(800), /* At least 100 MHz on bus. */
- [2] = BW_MBPS(1200), /* At least 150 MHz on bus. */
- [3] = BW_MBPS(1600), /* At least 200 MHz on bus. */
- [4] = BW_MBPS(2456), /* At least 307 MHz on bus. */
- [5] = BW_MBPS(3680), /* At least 460 MHz on bus. */
- [6] = BW_MBPS(4912), /* At least 614 MHz on bus. */
- [7] = BW_MBPS(6400), /* At least 800 MHz on bus. */
- [8] = BW_MBPS(7448), /* At least 931 MHz on bus. */
-};
-
-static struct l2_level l2_freq_tbl_v2[] __initdata = {
- [0] = { { 300000, PLL_0, 0, 0 }, LVL_LOW, 950000, 0 },
- [1] = { { 345600, HFPLL, 2, 36 }, LVL_LOW, 950000, 1 },
- [2] = { { 422400, HFPLL, 2, 44 }, LVL_LOW, 950000, 2 },
- [3] = { { 499200, HFPLL, 2, 52 }, LVL_LOW, 950000, 3 },
- [4] = { { 576000, HFPLL, 1, 30 }, LVL_LOW, 950000, 4 },
- [5] = { { 652800, HFPLL, 1, 34 }, LVL_NOM, 950000, 4 },
- [6] = { { 729600, HFPLL, 1, 38 }, LVL_NOM, 950000, 4 },
- [7] = { { 806400, HFPLL, 1, 42 }, LVL_NOM, 950000, 4 },
- [8] = { { 883200, HFPLL, 1, 46 }, LVL_NOM, 950000, 5 },
- [9] = { { 960000, HFPLL, 1, 50 }, LVL_NOM, 950000, 5 },
- [10] = { { 1036800, HFPLL, 1, 54 }, LVL_NOM, 950000, 5 },
- [11] = { { 1113600, HFPLL, 1, 58 }, LVL_HIGH, 1050000, 6 },
- [12] = { { 1190400, HFPLL, 1, 62 }, LVL_HIGH, 1050000, 6 },
- [13] = { { 1267200, HFPLL, 1, 66 }, LVL_HIGH, 1050000, 6 },
- [14] = { { 1344000, HFPLL, 1, 70 }, LVL_HIGH, 1050000, 6 },
- [15] = { { 1420800, HFPLL, 1, 74 }, LVL_HIGH, 1050000, 6 },
- [16] = { { 1497600, HFPLL, 1, 78 }, LVL_HIGH, 1050000, 6 },
- [17] = { { 1574400, HFPLL, 1, 82 }, LVL_HIGH, 1050000, 7 },
- [18] = { { 1651200, HFPLL, 1, 86 }, LVL_HIGH, 1050000, 7 },
- [19] = { { 1728000, HFPLL, 1, 90 }, LVL_HIGH, 1050000, 8 },
- { }
-};
-
-static struct acpu_level acpu_freq_tbl_2g_pvs0[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 815000, 73 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 825000, 85 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 835000, 104 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 845000, 124 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 855000, 144 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 865000, 165 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 875000, 186 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 890000, 208 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 900000, 229 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 915000, 252 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 925000, 275 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 940000, 298 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 950000, 321 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 965000, 346 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 980000, 371 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 995000, 397 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 1010000, 423 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 1025000, 450 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 1040000, 477 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 1055000, 506 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 1070000, 536 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 1085000, 567 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1100000, 598 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_2g_pvs1[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 800000, 73 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 810000, 85 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 820000, 104 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 830000, 124 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 840000, 144 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 850000, 165 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 860000, 186 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 875000, 208 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 885000, 229 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 895000, 252 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 910000, 275 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 920000, 298 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 930000, 321 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 945000, 346 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 960000, 371 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 975000, 397 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 990000, 423 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 1005000, 450 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 1020000, 477 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 1030000, 506 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 1045000, 536 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 1060000, 567 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1075000, 598 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_2g_pvs2[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 785000, 73 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 795000, 85 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 805000, 104 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 815000, 124 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 825000, 144 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 835000, 165 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 845000, 186 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 855000, 208 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 865000, 229 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 875000, 252 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 890000, 275 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 900000, 298 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 910000, 321 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 925000, 346 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 940000, 371 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 955000, 397 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 970000, 423 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 980000, 450 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 995000, 477 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 1005000, 506 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 1020000, 536 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 1035000, 567 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1050000, 598 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_2g_pvs3[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 775000, 73 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 780000, 85 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 790000, 104 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 800000, 124 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 810000, 144 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 820000, 165 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 830000, 186 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 840000, 208 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 850000, 229 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 860000, 252 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 875000, 275 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 885000, 298 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 895000, 321 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 910000, 346 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 925000, 371 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 935000, 397 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 950000, 423 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 960000, 450 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 970000, 477 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 985000, 506 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 995000, 536 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 1010000, 567 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1025000, 598 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_2g_pvs4[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 775000, 73 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 775000, 85 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 780000, 104 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 790000, 124 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 800000, 144 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 810000, 165 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 820000, 186 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 830000, 208 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 840000, 229 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 850000, 252 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 860000, 275 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 870000, 298 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 880000, 321 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 895000, 346 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 910000, 371 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 920000, 397 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 930000, 423 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 940000, 450 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 950000, 477 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 960000, 506 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 975000, 536 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 985000, 567 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1000000, 598 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_2g_pvs5[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 750000, 73 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 760000, 85 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 770000, 104 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 780000, 124 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 790000, 144 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 800000, 165 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 810000, 186 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 820000, 208 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 830000, 229 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 840000, 252 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 850000, 275 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 860000, 298 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 870000, 321 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 880000, 346 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 890000, 371 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 900000, 397 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 910000, 423 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 920000, 450 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 930000, 477 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 940000, 506 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 955000, 536 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 965000, 567 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 975000, 598 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_2g_pvs6[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 750000, 73 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 750000, 85 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 760000, 104 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 770000, 124 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 780000, 144 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 790000, 165 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 800000, 186 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 810000, 208 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 820000, 229 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 830000, 252 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 840000, 275 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 850000, 298 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 860000, 321 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 870000, 346 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 875000, 371 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 885000, 397 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 895000, 423 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 905000, 450 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 915000, 477 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 920000, 506 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 930000, 536 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 940000, 567 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 950000, 598 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_2p2g_pvs0[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 800000, 72 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 800000, 83 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 805000, 102 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 815000, 121 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 825000, 141 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 835000, 161 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 845000, 181 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 855000, 202 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 865000, 223 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 875000, 245 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 890000, 267 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 900000, 289 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 915000, 313 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 925000, 336 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 940000, 360 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 950000, 383 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 965000, 409 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 980000, 435 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 995000, 461 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 1010000, 488 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 1025000, 516 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 1040000, 543 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1055000, 573 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1070000, 604 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1085000, 636 },
- { 1, { 2150400, HFPLL, 1, 112 }, L2(19), 1100000, 656 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_2p2g_pvs1[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 800000, 72 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 800000, 83 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 800000, 102 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 800000, 121 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 810000, 141 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 820000, 161 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 830000, 181 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 840000, 202 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 850000, 223 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 860000, 245 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 875000, 267 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 885000, 289 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 895000, 313 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 910000, 336 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 920000, 360 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 930000, 383 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 945000, 409 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 960000, 435 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 975000, 461 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 990000, 488 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 1005000, 516 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 1020000, 543 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1030000, 573 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1045000, 604 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1060000, 636 },
- { 1, { 2150400, HFPLL, 1, 112 }, L2(19), 1075000, 656 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_2p2g_pvs2[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 775000, 72 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 775000, 83 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 775000, 102 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 785000, 121 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 795000, 141 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 805000, 161 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 815000, 181 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 825000, 202 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 835000, 223 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 845000, 245 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 855000, 267 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 865000, 289 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 875000, 313 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 890000, 336 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 900000, 360 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 910000, 383 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 925000, 409 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 940000, 435 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 955000, 461 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 970000, 488 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 980000, 516 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 995000, 543 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1005000, 573 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1020000, 604 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1035000, 636 },
- { 1, { 2150400, HFPLL, 1, 112 }, L2(19), 1050000, 656 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_2p2g_pvs3[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 775000, 72 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 775000, 83 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 775000, 102 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 775000, 121 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 780000, 141 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 790000, 161 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 800000, 181 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 810000, 202 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 820000, 223 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 830000, 245 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 840000, 267 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 850000, 289 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 860000, 313 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 875000, 336 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 885000, 360 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 895000, 383 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 910000, 409 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 925000, 435 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 935000, 461 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 950000, 488 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 960000, 516 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 970000, 543 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 985000, 573 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 995000, 604 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1010000, 636 },
- { 1, { 2150400, HFPLL, 1, 112 }, L2(19), 1025000, 656 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_2p2g_pvs4[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 775000, 72 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 775000, 83 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 775000, 102 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 775000, 121 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 775000, 141 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 780000, 161 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 790000, 181 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 800000, 202 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 810000, 223 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 820000, 245 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 830000, 267 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 840000, 289 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 850000, 313 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 860000, 336 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 870000, 360 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 880000, 383 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 895000, 409 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 910000, 435 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 920000, 461 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 930000, 488 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 940000, 516 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 950000, 543 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 960000, 573 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 975000, 604 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 985000, 636 },
- { 1, { 2150400, HFPLL, 1, 112 }, L2(19), 1000000, 656 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_2p2g_pvs5[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 750000, 72 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 750000, 83 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 750000, 102 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 750000, 121 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 760000, 141 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 770000, 161 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 780000, 181 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 790000, 202 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 800000, 223 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 810000, 245 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 820000, 267 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 830000, 289 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 840000, 313 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 850000, 336 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 860000, 360 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 870000, 383 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 880000, 409 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 890000, 435 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 900000, 461 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 910000, 488 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 920000, 516 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 930000, 543 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 940000, 573 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 955000, 604 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 965000, 636 },
- { 1, { 2150400, HFPLL, 1, 112 }, L2(19), 975000, 656 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_2p2g_pvs6[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 750000, 72 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 750000, 83 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 750000, 102 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 750000, 121 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 750000, 141 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 760000, 161 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 770000, 181 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 780000, 202 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 790000, 223 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 800000, 245 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 810000, 267 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 820000, 289 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 830000, 313 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 840000, 336 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 850000, 360 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 860000, 383 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 870000, 409 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 875000, 435 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 885000, 461 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 895000, 488 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 905000, 516 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 915000, 543 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 920000, 573 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 930000, 604 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 940000, 636 },
- { 1, { 2150400, HFPLL, 1, 112 }, L2(19), 950000, 656 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_2p3g_pvs0[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 800000, 72 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 800000, 83 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 800000, 101 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 805000, 120 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 815000, 139 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 825000, 159 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 835000, 180 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 845000, 200 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 855000, 221 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 865000, 242 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 875000, 264 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 890000, 287 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 900000, 308 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 915000, 333 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 925000, 356 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 940000, 380 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 950000, 404 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 965000, 430 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 980000, 456 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 995000, 482 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 1010000, 510 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 1025000, 538 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1040000, 565 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1055000, 596 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1070000, 627 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1085000, 659 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1100000, 691 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_2p3g_pvs1[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 800000, 72 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 800000, 83 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 800000, 101 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 800000, 120 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 800000, 139 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 810000, 159 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 820000, 180 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 830000, 200 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 840000, 221 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 850000, 242 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 860000, 264 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 875000, 287 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 885000, 308 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 895000, 333 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 910000, 356 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 920000, 380 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 930000, 404 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 945000, 430 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 960000, 456 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 975000, 482 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 990000, 510 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 1005000, 538 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1020000, 565 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1030000, 596 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1045000, 627 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1060000, 659 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1075000, 691 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_2p3g_pvs2[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 775000, 72 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 775000, 83 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 775000, 101 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 775000, 120 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 785000, 139 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 795000, 159 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 805000, 180 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 815000, 200 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 825000, 221 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 835000, 242 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 845000, 264 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 855000, 287 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 865000, 308 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 875000, 333 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 890000, 356 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 900000, 380 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 910000, 404 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 925000, 430 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 940000, 456 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 955000, 482 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 970000, 510 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 980000, 538 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 995000, 565 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1005000, 596 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1020000, 627 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1035000, 659 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1050000, 691 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_2p3g_pvs3[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 775000, 72 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 775000, 83 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 775000, 101 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 775000, 120 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 775000, 139 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 780000, 159 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 790000, 180 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 800000, 200 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 810000, 221 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 820000, 242 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 830000, 264 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 840000, 287 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 850000, 308 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 860000, 333 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 875000, 356 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 885000, 380 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 895000, 404 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 910000, 430 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 925000, 456 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 935000, 482 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 950000, 510 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 960000, 538 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 970000, 565 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 985000, 596 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 995000, 627 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1010000, 659 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1025000, 691 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_2p3g_pvs4[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 775000, 72 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 775000, 83 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 775000, 101 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 775000, 120 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 775000, 139 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 775000, 159 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 780000, 180 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 790000, 200 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 800000, 221 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 810000, 242 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 820000, 264 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 830000, 287 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 840000, 308 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 850000, 333 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 860000, 356 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 870000, 380 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 880000, 404 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 895000, 430 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 910000, 456 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 920000, 482 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 930000, 510 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 940000, 538 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 950000, 565 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 960000, 596 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 975000, 627 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 985000, 659 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1000000, 691 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_2p3g_pvs5[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 750000, 72 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 750000, 83 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 750000, 101 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 750000, 120 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 750000, 139 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 760000, 159 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 770000, 180 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 780000, 200 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 790000, 221 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 800000, 242 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 810000, 264 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 820000, 287 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 830000, 308 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 840000, 333 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 850000, 356 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 860000, 380 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 870000, 404 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 880000, 430 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 890000, 456 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 900000, 482 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 910000, 510 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 920000, 538 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 930000, 565 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 940000, 596 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 955000, 627 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 965000, 659 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 975000, 691 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_2p3g_pvs6[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 750000, 72 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 750000, 83 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 750000, 101 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 750000, 120 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 750000, 139 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 750000, 159 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 760000, 180 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 770000, 200 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 780000, 221 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 790000, 242 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 800000, 264 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 810000, 287 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 820000, 308 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 830000, 333 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 840000, 356 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 850000, 380 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 860000, 404 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 870000, 430 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 875000, 456 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 885000, 482 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 895000, 510 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 905000, 538 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 915000, 565 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 920000, 596 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 930000, 627 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 940000, 659 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 950000, 691 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev0_2p3g_pvs0[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 775000, 74 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 775000, 85 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 775000, 104 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 780000, 124 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 790000, 144 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 800000, 164 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 810000, 184 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 820000, 206 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 830000, 227 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 840000, 249 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 850000, 271 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 865000, 295 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 875000, 318 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 890000, 342 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 900000, 365 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 915000, 392 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 925000, 416 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 940000, 442 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 955000, 469 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 970000, 497 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 985000, 525 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 1000000, 554 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1015000, 583 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1030000, 613 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1045000, 642 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1060000, 663 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1060000, 675 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1075000, 708 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev0_2p3g_pvs1[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 775000, 74 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 775000, 85 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 775000, 104 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 775000, 124 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 775000, 144 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 785000, 164 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 795000, 184 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 805000, 206 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 815000, 227 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 825000, 249 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 835000, 271 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 850000, 295 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 860000, 318 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 870000, 342 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 885000, 365 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 895000, 392 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 905000, 416 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 920000, 442 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 935000, 469 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 950000, 497 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 965000, 525 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 980000, 554 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 995000, 583 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1005000, 613 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1020000, 642 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1035000, 663 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1035000, 675 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1050000, 708 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev0_2p3g_pvs2[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 750000, 74 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 750000, 85 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 750000, 104 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 750000, 124 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 760000, 144 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 770000, 164 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 780000, 184 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 790000, 206 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 800000, 227 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 810000, 249 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 820000, 271 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 830000, 295 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 840000, 318 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 850000, 342 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 865000, 365 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 875000, 392 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 885000, 416 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 900000, 442 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 915000, 469 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 930000, 497 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 945000, 525 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 955000, 554 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 970000, 583 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 980000, 613 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 995000, 642 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1010000, 663 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1010000, 675 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1025000, 708 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev0_2p3g_pvs3[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 750000, 74 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 750000, 85 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 750000, 104 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 750000, 124 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 750000, 144 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 755000, 164 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 765000, 184 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 775000, 206 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 785000, 227 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 795000, 249 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 805000, 271 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 815000, 295 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 825000, 318 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 835000, 342 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 850000, 365 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 860000, 392 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 870000, 416 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 885000, 442 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 900000, 469 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 910000, 497 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 925000, 525 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 935000, 554 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 945000, 583 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 960000, 613 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 970000, 642 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 985000, 663 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 985000, 675 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1000000, 708 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev0_2p3g_pvs4[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 750000, 74 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 750000, 85 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 750000, 104 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 750000, 124 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 750000, 144 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 750000, 164 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 755000, 184 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 765000, 206 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 775000, 227 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 785000, 249 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 795000, 271 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 805000, 295 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 815000, 318 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 825000, 342 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 835000, 365 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 845000, 392 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 855000, 416 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 870000, 442 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 885000, 469 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 895000, 497 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 905000, 525 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 915000, 554 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 925000, 583 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 935000, 613 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 950000, 642 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 960000, 663 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 960000, 675 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 975000, 708 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev0_2p3g_pvs5[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 725000, 74 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 725000, 85 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 725000, 104 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 725000, 124 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 725000, 144 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 735000, 164 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 745000, 184 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 755000, 206 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 765000, 227 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 775000, 249 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 785000, 271 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 795000, 295 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 805000, 318 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 815000, 342 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 825000, 365 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 835000, 392 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 845000, 416 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 855000, 442 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 865000, 469 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 875000, 497 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 885000, 525 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 895000, 554 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 905000, 583 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 915000, 613 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 930000, 642 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 940000, 663 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 940000, 675 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 950000, 708 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev0_2p3g_pvs6[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 725000, 74 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 725000, 85 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 725000, 104 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 725000, 124 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 725000, 144 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 725000, 164 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 735000, 184 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 745000, 206 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 755000, 227 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 765000, 249 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 775000, 271 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 785000, 295 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 795000, 318 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 805000, 342 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 815000, 365 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 825000, 392 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 835000, 416 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 845000, 442 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 850000, 469 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 860000, 497 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 870000, 525 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 880000, 554 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 890000, 583 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 895000, 613 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 905000, 642 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 915000, 663 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 915000, 675 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 925000, 708 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev0_2p5g_pvs0[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 800000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 800000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 800000, 106 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 800000, 125 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 800000, 145 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 810000, 165 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 820000, 186 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 830000, 208 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 840000, 229 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 850000, 251 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 860000, 273 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 870000, 296 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 880000, 319 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 890000, 342 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 900000, 365 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 910000, 390 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 920000, 415 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 930000, 439 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 945000, 465 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 960000, 493 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 975000, 521 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 990000, 549 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1005000, 579 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1020000, 608 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1035000, 638 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1050000, 667 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1050000, 667 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1065000, 700 },
- { 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1080000, 734 },
- { 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1095000, 769 },
- { 1, { 2457600, HFPLL, 1, 128 }, L2(19), 1100000, 785 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev0_2p5g_pvs1[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 800000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 800000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 800000, 106 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 800000, 125 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 800000, 145 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 800000, 165 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 800000, 186 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 805000, 208 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 815000, 229 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 825000, 251 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 835000, 273 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 845000, 296 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 855000, 319 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 865000, 342 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 875000, 365 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 885000, 390 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 895000, 415 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 905000, 439 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 920000, 465 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 935000, 493 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 950000, 521 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 965000, 549 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 980000, 579 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 995000, 608 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1010000, 638 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1025000, 667 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1025000, 667 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1040000, 700 },
- { 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1055000, 734 },
- { 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1070000, 769 },
- { 1, { 2457600, HFPLL, 1, 128 }, L2(19), 1075000, 785 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev0_2p5g_pvs2[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 775000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 775000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 775000, 106 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 775000, 125 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 775000, 145 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 775000, 165 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 775000, 186 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 780000, 208 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 790000, 229 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 800000, 251 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 810000, 273 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 820000, 296 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 830000, 319 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 840000, 342 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 850000, 365 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 860000, 390 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 870000, 415 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 880000, 439 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 895000, 465 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 910000, 493 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 925000, 521 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 940000, 549 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 955000, 579 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 970000, 608 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 985000, 638 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1000000, 667 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1000000, 667 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1015000, 700 },
- { 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1030000, 734 },
- { 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1045000, 769 },
- { 1, { 2457600, HFPLL, 1, 128 }, L2(19), 1050000, 785 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev0_2p5g_pvs3[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 775000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 775000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 775000, 106 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 775000, 125 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 775000, 145 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 775000, 165 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 775000, 186 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 775000, 208 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 775000, 229 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 780000, 251 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 785000, 273 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 795000, 296 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 805000, 319 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 815000, 342 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 825000, 365 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 835000, 390 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 845000, 415 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 855000, 439 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 870000, 465 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 885000, 493 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 900000, 521 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 915000, 549 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 930000, 579 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 945000, 608 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 960000, 638 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 975000, 667 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 975000, 667 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 990000, 700 },
- { 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1005000, 734 },
- { 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1020000, 769 },
- { 1, { 2457600, HFPLL, 1, 128 }, L2(19), 1025000, 785 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev0_2p5g_pvs4[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 775000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 775000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 775000, 106 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 775000, 125 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 775000, 145 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 775000, 165 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 775000, 186 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 775000, 208 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 775000, 229 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 775000, 251 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 775000, 273 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 775000, 296 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 780000, 319 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 790000, 342 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 800000, 365 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 810000, 390 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 820000, 415 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 830000, 439 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 845000, 465 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 860000, 493 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 875000, 521 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 890000, 549 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 905000, 579 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 920000, 608 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 935000, 638 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 950000, 667 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 950000, 667 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 965000, 700 },
- { 0, { 2342400, HFPLL, 1, 122 }, L2(19), 980000, 734 },
- { 0, { 2419200, HFPLL, 1, 126 }, L2(19), 995000, 769 },
- { 1, { 2457600, HFPLL, 1, 128 }, L2(19), 1000000, 785 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev0_2p5g_pvs5[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 750000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 750000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 750000, 106 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 750000, 125 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 750000, 145 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 750000, 165 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 750000, 186 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 750000, 208 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 750000, 229 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 750000, 251 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 750000, 273 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 750000, 296 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 760000, 319 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 770000, 342 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 780000, 365 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 790000, 390 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 800000, 415 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 810000, 439 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 820000, 465 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 835000, 493 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 850000, 521 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 865000, 549 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 880000, 579 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 895000, 608 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 910000, 638 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 925000, 667 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 925000, 667 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 940000, 700 },
- { 0, { 2342400, HFPLL, 1, 122 }, L2(19), 955000, 734 },
- { 0, { 2419200, HFPLL, 1, 126 }, L2(19), 970000, 769 },
- { 1, { 2457600, HFPLL, 1, 128 }, L2(19), 975000, 785 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev0_2p5g_pvs6[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 750000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 750000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 750000, 106 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 750000, 125 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 750000, 145 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 750000, 165 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 750000, 186 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 750000, 208 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 750000, 229 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 750000, 251 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 750000, 273 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 750000, 296 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 750000, 319 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 755000, 342 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 765000, 365 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 775000, 390 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 785000, 415 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 795000, 439 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 805000, 465 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 815000, 493 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 825000, 521 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 840000, 549 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 855000, 579 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 870000, 608 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 885000, 638 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 900000, 667 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 900000, 667 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 915000, 700 },
- { 0, { 2342400, HFPLL, 1, 122 }, L2(19), 930000, 734 },
- { 0, { 2419200, HFPLL, 1, 126 }, L2(19), 945000, 769 },
- { 1, { 2457600, HFPLL, 1, 128 }, L2(19), 950000, 785 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev1_2p5g_pvs0[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 800000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 800000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 800000, 106 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 810000, 126 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 820000, 147 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 830000, 168 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 840000, 189 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 850000, 211 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 860000, 233 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 870000, 256 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 880000, 278 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 890000, 301 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 900000, 324 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 910000, 348 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 920000, 372 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 930000, 396 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 940000, 421 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 950000, 446 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 965000, 473 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 980000, 501 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 995000, 529 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 1010000, 558 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1025000, 588 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1040000, 617 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1055000, 649 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1070000, 682 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1070000, 682 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1085000, 716 },
- { 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1100000, 751 },
- { 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1115000, 786 },
- { 1, { 2457600, HFPLL, 1, 128 }, L2(19), 1120000, 802 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev1_2p5g_pvs1[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 800000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 800000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 800000, 106 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 800000, 126 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 810000, 147 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 820000, 168 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 830000, 189 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 840000, 211 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 850000, 233 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 860000, 256 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 870000, 278 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 880000, 301 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 890000, 324 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 900000, 348 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 910000, 372 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 920000, 396 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 930000, 421 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 940000, 446 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 955000, 473 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 970000, 501 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 985000, 529 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 1000000, 558 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1015000, 588 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1030000, 617 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1045000, 649 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1060000, 682 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1060000, 682 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1075000, 716 },
- { 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1090000, 751 },
- { 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1105000, 786 },
- { 1, { 2457600, HFPLL, 1, 128 }, L2(19), 1110000, 802 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev1_2p5g_pvs2[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 800000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 800000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 800000, 106 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 800000, 126 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 800000, 147 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 810000, 168 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 820000, 189 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 830000, 211 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 840000, 233 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 850000, 256 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 860000, 278 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 870000, 301 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 880000, 324 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 890000, 348 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 900000, 372 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 910000, 396 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 920000, 421 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 930000, 446 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 945000, 473 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 960000, 501 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 975000, 529 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 990000, 558 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1005000, 588 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1020000, 617 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1035000, 649 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1050000, 682 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1050000, 682 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1065000, 716 },
- { 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1080000, 751 },
- { 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1095000, 786 },
- { 1, { 2457600, HFPLL, 1, 128 }, L2(19), 1100000, 802 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev1_2p5g_pvs3[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 800000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 800000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 800000, 106 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 800000, 126 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 800000, 147 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 800000, 168 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 810000, 189 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 820000, 211 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 830000, 233 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 840000, 256 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 850000, 278 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 860000, 301 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 870000, 324 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 880000, 348 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 890000, 372 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 900000, 396 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 910000, 421 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 920000, 446 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 935000, 473 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 950000, 501 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 965000, 529 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 980000, 558 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 995000, 588 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1010000, 617 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1025000, 649 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1040000, 682 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1040000, 682 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1055000, 716 },
- { 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1070000, 751 },
- { 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1085000, 786 },
- { 1, { 2457600, HFPLL, 1, 128 }, L2(19), 1090000, 802 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev1_2p5g_pvs4[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 800000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 800000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 800000, 106 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 800000, 126 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 800000, 147 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 800000, 168 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 800000, 189 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 810000, 211 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 820000, 233 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 830000, 256 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 840000, 278 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 850000, 301 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 860000, 324 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 870000, 348 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 880000, 372 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 890000, 396 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 900000, 421 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 910000, 446 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 925000, 473 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 940000, 501 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 955000, 529 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 970000, 558 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 985000, 588 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1000000, 617 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1015000, 649 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1030000, 682 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1030000, 682 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1045000, 716 },
- { 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1060000, 751 },
- { 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1075000, 786 },
- { 1, { 2457600, HFPLL, 1, 128 }, L2(19), 1080000, 802 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev1_2p5g_pvs5[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 800000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 800000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 800000, 106 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 800000, 126 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 800000, 147 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 800000, 168 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 800000, 189 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 800000, 211 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 810000, 233 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 820000, 256 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 830000, 278 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 840000, 301 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 850000, 324 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 860000, 348 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 870000, 372 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 880000, 396 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 890000, 421 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 900000, 446 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 915000, 473 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 930000, 501 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 945000, 529 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 960000, 558 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 975000, 588 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 990000, 617 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1005000, 649 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1020000, 682 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1020000, 682 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1035000, 716 },
- { 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1050000, 751 },
- { 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1065000, 786 },
- { 1, { 2457600, HFPLL, 1, 128 }, L2(19), 1070000, 802 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev1_2p5g_pvs6[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 775000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 775000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 775000, 106 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 775000, 126 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 775000, 147 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 775000, 168 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 780000, 189 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 790000, 211 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 800000, 233 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 810000, 256 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 820000, 278 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 830000, 301 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 840000, 324 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 850000, 348 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 860000, 372 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 870000, 396 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 880000, 421 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 890000, 446 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 905000, 473 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 920000, 501 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 935000, 529 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 950000, 558 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 965000, 588 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 980000, 617 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 995000, 649 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1010000, 682 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1010000, 682 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1025000, 716 },
- { 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1040000, 751 },
- { 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1055000, 786 },
- { 1, { 2457600, HFPLL, 1, 128 }, L2(19), 1060000, 802 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev1_2p5g_pvs7[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 775000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 775000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 775000, 106 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 775000, 126 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 775000, 147 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 775000, 168 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 775000, 189 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 780000, 211 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 790000, 233 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 800000, 256 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 810000, 278 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 820000, 301 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 830000, 324 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 840000, 348 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 850000, 372 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 860000, 396 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 870000, 421 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 880000, 446 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 895000, 473 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 910000, 501 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 925000, 529 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 940000, 558 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 955000, 588 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 970000, 617 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 985000, 649 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1000000, 682 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1000000, 682 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1015000, 716 },
- { 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1030000, 751 },
- { 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1045000, 786 },
- { 1, { 2457600, HFPLL, 1, 128 }, L2(19), 1050000, 802 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev1_2p5g_pvs8[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 775000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 775000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 775000, 106 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 775000, 126 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 775000, 147 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 775000, 168 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 775000, 189 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 775000, 211 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 780000, 233 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 790000, 256 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 800000, 278 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 810000, 301 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 820000, 324 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 830000, 348 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 840000, 372 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 850000, 396 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 860000, 421 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 870000, 446 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 885000, 473 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 900000, 501 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 915000, 529 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 930000, 558 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 945000, 588 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 960000, 617 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 975000, 649 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 990000, 682 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 990000, 682 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1005000, 716 },
- { 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1020000, 751 },
- { 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1035000, 786 },
- { 1, { 2457600, HFPLL, 1, 128 }, L2(19), 1040000, 802 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev1_2p5g_pvs9[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 775000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 775000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 775000, 106 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 775000, 126 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 775000, 147 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 775000, 168 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 775000, 189 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 775000, 211 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 775000, 233 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 780000, 256 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 790000, 278 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 800000, 301 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 810000, 324 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 820000, 348 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 830000, 372 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 840000, 396 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 850000, 421 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 860000, 446 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 875000, 473 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 890000, 501 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 905000, 529 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 920000, 558 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 935000, 588 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 950000, 617 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 965000, 649 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 980000, 682 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 980000, 682 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 995000, 716 },
- { 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1010000, 751 },
- { 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1025000, 786 },
- { 1, { 2457600, HFPLL, 1, 128 }, L2(19), 1030000, 802 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev1_2p5g_pvs10[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 775000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 775000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 775000, 106 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 775000, 126 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 775000, 147 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 775000, 168 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 775000, 189 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 775000, 211 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 775000, 233 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 775000, 256 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 780000, 278 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 790000, 301 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 800000, 324 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 810000, 348 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 820000, 372 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 830000, 396 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 840000, 421 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 850000, 446 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 865000, 473 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 880000, 501 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 895000, 529 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 910000, 558 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 925000, 588 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 940000, 617 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 955000, 649 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 970000, 682 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 970000, 682 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 985000, 716 },
- { 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1000000, 751 },
- { 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1015000, 786 },
- { 1, { 2457600, HFPLL, 1, 128 }, L2(19), 1020000, 802 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev1_2p5g_pvs11[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 775000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 775000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 775000, 106 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 775000, 126 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 775000, 147 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 775000, 168 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 775000, 189 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 775000, 211 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 775000, 233 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 775000, 256 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 775000, 278 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 780000, 301 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 790000, 324 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 800000, 348 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 810000, 372 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 820000, 396 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 830000, 421 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 840000, 446 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 855000, 473 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 870000, 501 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 885000, 529 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 900000, 558 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 915000, 588 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 930000, 617 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 945000, 649 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 960000, 682 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 960000, 682 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 975000, 716 },
- { 0, { 2342400, HFPLL, 1, 122 }, L2(19), 990000, 751 },
- { 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1005000, 786 },
- { 1, { 2457600, HFPLL, 1, 128 }, L2(19), 1010000, 802 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev1_2p5g_pvs12[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 775000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 775000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 775000, 106 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 775000, 126 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 775000, 147 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 775000, 168 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 775000, 189 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 775000, 211 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 775000, 233 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 775000, 256 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 775000, 278 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 775000, 301 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 780000, 324 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 790000, 348 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 800000, 372 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 810000, 396 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 820000, 421 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 830000, 446 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 845000, 473 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 860000, 501 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 875000, 529 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 890000, 558 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 905000, 588 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 920000, 617 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 935000, 649 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 950000, 682 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 950000, 682 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 965000, 716 },
- { 0, { 2342400, HFPLL, 1, 122 }, L2(19), 980000, 751 },
- { 0, { 2419200, HFPLL, 1, 126 }, L2(19), 995000, 786 },
- { 1, { 2457600, HFPLL, 1, 128 }, L2(19), 1000000, 802 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev1_2p5g_pvs13[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 775000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 775000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 775000, 106 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 775000, 126 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 775000, 147 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 775000, 168 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 775000, 189 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 775000, 211 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 775000, 233 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 775000, 256 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 775000, 278 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 775000, 301 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 775000, 324 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 780000, 348 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 790000, 372 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 800000, 396 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 810000, 421 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 820000, 446 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 835000, 473 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 850000, 501 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 865000, 529 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 880000, 558 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 895000, 588 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 910000, 617 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 925000, 649 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 940000, 682 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 940000, 682 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 955000, 716 },
- { 0, { 2342400, HFPLL, 1, 122 }, L2(19), 970000, 751 },
- { 0, { 2419200, HFPLL, 1, 126 }, L2(19), 985000, 786 },
- { 1, { 2457600, HFPLL, 1, 128 }, L2(19), 990000, 802 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev1_2p5g_pvs14[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 750000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 750000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 750000, 106 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 750000, 126 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 750000, 147 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 750000, 168 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 750000, 189 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 750000, 211 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 750000, 233 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 750000, 256 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 750000, 278 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 750000, 301 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 760000, 324 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 770000, 348 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 780000, 372 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 790000, 396 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 800000, 421 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 810000, 446 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 825000, 473 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 840000, 501 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 855000, 529 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 870000, 558 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 885000, 588 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 900000, 617 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 915000, 649 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 930000, 682 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 930000, 682 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 945000, 716 },
- { 0, { 2342400, HFPLL, 1, 122 }, L2(19), 960000, 751 },
- { 0, { 2419200, HFPLL, 1, 126 }, L2(19), 975000, 786 },
- { 1, { 2457600, HFPLL, 1, 128 }, L2(19), 980000, 802 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev1_2p5g_pvs15[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 750000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 750000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 750000, 106 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 750000, 126 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 750000, 147 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 750000, 168 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 750000, 189 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 750000, 211 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 750000, 233 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 750000, 256 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 750000, 278 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 750000, 301 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 750000, 324 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 760000, 348 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 770000, 372 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 780000, 396 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 790000, 421 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 800000, 446 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 815000, 473 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 830000, 501 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 845000, 529 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 860000, 558 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 875000, 588 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 890000, 617 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 905000, 649 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 920000, 682 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 920000, 682 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 935000, 716 },
- { 0, { 2342400, HFPLL, 1, 122 }, L2(19), 950000, 751 },
- { 0, { 2419200, HFPLL, 1, 126 }, L2(19), 965000, 786 },
- { 1, { 2457600, HFPLL, 1, 128 }, L2(19), 970000, 802 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev1_2p3g_pvs0[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 800000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 810000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 820000, 108 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 830000, 129 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 840000, 150 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 850000, 171 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 860000, 193 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 870000, 215 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 880000, 237 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 890000, 260 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 900000, 282 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 910000, 306 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 920000, 330 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 930000, 354 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 940000, 378 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 955000, 404 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 970000, 431 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 985000, 458 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 1000000, 486 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 1015000, 515 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 1030000, 543 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 1045000, 572 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1060000, 604 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1075000, 636 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1090000, 669 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1105000, 703 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1105000, 703 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1120000, 738 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev1_2p3g_pvs1[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 800000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 800000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 810000, 108 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 820000, 129 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 830000, 150 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 840000, 171 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 850000, 193 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 860000, 215 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 870000, 237 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 880000, 260 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 890000, 282 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 900000, 306 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 910000, 330 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 920000, 354 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 930000, 378 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 945000, 404 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 960000, 431 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 975000, 458 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 990000, 486 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 1005000, 515 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 1020000, 543 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 1035000, 572 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1050000, 604 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1065000, 636 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1080000, 669 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1095000, 703 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1095000, 703 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1110000, 738 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev1_2p3g_pvs2[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 800000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 800000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 800000, 108 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 810000, 129 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 820000, 150 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 830000, 171 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 840000, 193 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 850000, 215 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 860000, 237 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 870000, 260 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 880000, 282 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 890000, 306 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 900000, 330 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 910000, 354 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 920000, 378 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 935000, 404 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 950000, 431 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 965000, 458 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 980000, 486 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 995000, 515 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 1010000, 543 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 1025000, 572 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1040000, 604 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1055000, 636 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1070000, 669 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1085000, 703 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1085000, 703 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1100000, 738 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev1_2p3g_pvs3[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 800000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 800000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 800000, 108 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 800000, 129 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 810000, 150 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 820000, 171 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 830000, 193 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 840000, 215 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 850000, 237 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 860000, 260 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 870000, 282 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 880000, 306 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 890000, 330 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 900000, 354 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 910000, 378 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 925000, 404 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 940000, 431 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 955000, 458 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 970000, 486 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 985000, 515 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 1000000, 543 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 1015000, 572 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1030000, 604 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1045000, 636 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1060000, 669 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1075000, 703 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1075000, 703 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1090000, 738 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev1_2p3g_pvs4[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 800000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 800000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 800000, 108 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 800000, 129 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 800000, 150 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 810000, 171 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 820000, 193 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 830000, 215 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 840000, 237 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 850000, 260 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 860000, 282 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 870000, 306 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 880000, 330 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 890000, 354 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 900000, 378 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 915000, 404 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 930000, 431 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 945000, 458 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 960000, 486 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 975000, 515 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 990000, 543 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 1005000, 572 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1020000, 604 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1035000, 636 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1050000, 669 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1065000, 703 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1065000, 703 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1080000, 738 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev1_2p3g_pvs5[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 800000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 800000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 800000, 108 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 800000, 129 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 800000, 150 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 800000, 171 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 810000, 193 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 820000, 215 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 830000, 237 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 840000, 260 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 850000, 282 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 860000, 306 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 870000, 330 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 880000, 354 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 890000, 378 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 905000, 404 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 920000, 431 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 935000, 458 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 950000, 486 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 965000, 515 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 980000, 543 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 995000, 572 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1010000, 604 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1025000, 636 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1040000, 669 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1055000, 703 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1055000, 703 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1070000, 738 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev1_2p3g_pvs6[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 775000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 775000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 775000, 108 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 775000, 129 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 780000, 150 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 790000, 171 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 800000, 193 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 810000, 215 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 820000, 237 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 830000, 260 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 840000, 282 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 850000, 306 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 860000, 330 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 870000, 354 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 880000, 378 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 895000, 404 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 910000, 431 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 925000, 458 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 940000, 486 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 955000, 515 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 970000, 543 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 985000, 572 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1000000, 604 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1015000, 636 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1030000, 669 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1045000, 703 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1045000, 703 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1060000, 738 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev1_2p3g_pvs7[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 775000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 775000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 775000, 108 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 775000, 129 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 775000, 150 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 780000, 171 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 790000, 193 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 800000, 215 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 810000, 237 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 820000, 260 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 830000, 282 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 840000, 306 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 850000, 330 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 860000, 354 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 870000, 378 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 885000, 404 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 900000, 431 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 915000, 458 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 930000, 486 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 945000, 515 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 960000, 543 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 975000, 572 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 990000, 604 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1005000, 636 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1020000, 669 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1035000, 703 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1035000, 703 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1050000, 738 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev1_2p3g_pvs8[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 775000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 775000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 775000, 108 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 775000, 129 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 775000, 150 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 775000, 171 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 780000, 193 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 790000, 215 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 800000, 237 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 810000, 260 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 820000, 282 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 830000, 306 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 840000, 330 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 850000, 354 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 860000, 378 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 875000, 404 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 890000, 431 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 905000, 458 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 920000, 486 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 935000, 515 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 950000, 543 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 965000, 572 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 980000, 604 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 995000, 636 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1010000, 669 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1025000, 703 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1025000, 703 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1040000, 738 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev1_2p3g_pvs9[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 775000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 775000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 775000, 108 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 775000, 129 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 775000, 150 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 775000, 171 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 775000, 193 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 780000, 215 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 790000, 237 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 800000, 260 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 810000, 282 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 820000, 306 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 830000, 330 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 840000, 354 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 850000, 378 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 865000, 404 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 880000, 431 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 895000, 458 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 910000, 486 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 925000, 515 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 940000, 543 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 955000, 572 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 970000, 604 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 985000, 636 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1000000, 669 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1015000, 703 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1015000, 703 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1030000, 738 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev1_2p3g_pvs10[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 775000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 775000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 775000, 108 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 775000, 129 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 775000, 150 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 775000, 171 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 775000, 193 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 775000, 215 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 780000, 237 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 790000, 260 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 800000, 282 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 810000, 306 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 820000, 330 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 830000, 354 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 840000, 378 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 855000, 404 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 870000, 431 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 885000, 458 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 900000, 486 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 915000, 515 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 930000, 543 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 945000, 572 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 960000, 604 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 975000, 636 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 990000, 669 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1005000, 703 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1005000, 703 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1020000, 738 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev1_2p3g_pvs11[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 775000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 775000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 775000, 108 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 775000, 129 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 775000, 150 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 775000, 171 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 775000, 193 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 775000, 215 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 775000, 237 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 780000, 260 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 790000, 282 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 800000, 306 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 810000, 330 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 820000, 354 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 830000, 378 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 845000, 404 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 860000, 431 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 875000, 458 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 890000, 486 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 905000, 515 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 920000, 543 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 935000, 572 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 950000, 604 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 965000, 636 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 980000, 669 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 995000, 703 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 995000, 703 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1010000, 738 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev1_2p3g_pvs12[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 775000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 775000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 775000, 108 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 775000, 129 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 775000, 150 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 775000, 171 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 775000, 193 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 775000, 215 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 775000, 237 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 775000, 260 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 780000, 282 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 790000, 306 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 800000, 330 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 810000, 354 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 820000, 378 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 835000, 404 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 850000, 431 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 865000, 458 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 880000, 486 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 895000, 515 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 910000, 543 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 925000, 572 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 940000, 604 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 955000, 636 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 970000, 669 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 985000, 703 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 985000, 703 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1000000, 738 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev1_2p3g_pvs13[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 775000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 775000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 775000, 108 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 775000, 129 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 775000, 150 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 775000, 171 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 775000, 193 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 775000, 215 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 775000, 237 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 775000, 260 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 775000, 282 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 780000, 306 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 790000, 330 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 800000, 354 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 810000, 378 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 825000, 404 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 840000, 431 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 855000, 458 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 870000, 486 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 885000, 515 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 900000, 543 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 915000, 572 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 930000, 604 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 945000, 636 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 960000, 669 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 975000, 703 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 975000, 703 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 990000, 738 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev1_2p3g_pvs14[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 750000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 750000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 750000, 108 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 750000, 129 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 750000, 150 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 750000, 171 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 750000, 193 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 750000, 215 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 750000, 237 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 750000, 260 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 760000, 282 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 770000, 306 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 780000, 330 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 790000, 354 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 800000, 378 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 815000, 404 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 830000, 431 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 845000, 458 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 860000, 486 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 875000, 515 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 890000, 543 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 905000, 572 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 920000, 604 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 935000, 636 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 950000, 669 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 965000, 703 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 965000, 703 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 980000, 738 },
- { 0, { 0 } }
-};
-
-static struct acpu_level pro_rev1_2p3g_pvs15[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 750000, 76 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(1), 750000, 87 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(2), 750000, 108 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(2), 750000, 129 },
- { 0, { 576000, HFPLL, 1, 30 }, L2(3), 750000, 150 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(3), 750000, 171 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(4), 750000, 193 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(4), 750000, 215 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(4), 750000, 237 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(9), 750000, 260 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 750000, 282 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(10), 760000, 306 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(10), 770000, 330 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(13), 780000, 354 },
- { 0, { 1344000, HFPLL, 1, 70 }, L2(14), 790000, 378 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(15), 805000, 404 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 820000, 431 },
- { 1, { 1574400, HFPLL, 1, 82 }, L2(17), 835000, 458 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(17), 850000, 486 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(18), 865000, 515 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(18), 880000, 543 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(18), 895000, 572 },
- { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 910000, 604 },
- { 0, { 2035200, HFPLL, 1, 106 }, L2(19), 925000, 636 },
- { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 940000, 669 },
- { 0, { 2150400, HFPLL, 1, 112 }, L2(19), 955000, 703 },
- { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 955000, 703 },
- { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 970000, 738 },
- { 0, { 0 } }
-};
-
-static struct pvs_table pvs_v1[NUM_PVS_REVS][NUM_SPEED_BINS][NUM_PVS] __initdata = {
- /* 8974v1 1.7GHz Parts */
- [0][0][0] = { acpu_freq_tbl_v1_pvs0, sizeof(acpu_freq_tbl_v1_pvs0) },
- [0][0][1] = { acpu_freq_tbl_v1_pvs1, sizeof(acpu_freq_tbl_v1_pvs1) },
- [0][0][2] = { acpu_freq_tbl_v1_pvs2, sizeof(acpu_freq_tbl_v1_pvs2) },
- [0][0][3] = { acpu_freq_tbl_v1_pvs3, sizeof(acpu_freq_tbl_v1_pvs3) },
- [0][0][4] = { acpu_freq_tbl_v1_pvs4, sizeof(acpu_freq_tbl_v1_pvs4) },
-};
-
-static struct pvs_table pvs_v2[NUM_PVS_REVS][NUM_SPEED_BINS][NUM_PVS] __initdata = {
- /* 8974v2 2.0GHz Parts */
- [0][0][0] = { acpu_freq_tbl_2g_pvs0, sizeof(acpu_freq_tbl_2g_pvs0) },
- [0][0][1] = { acpu_freq_tbl_2g_pvs1, sizeof(acpu_freq_tbl_2g_pvs1) },
- [0][0][2] = { acpu_freq_tbl_2g_pvs2, sizeof(acpu_freq_tbl_2g_pvs2) },
- [0][0][3] = { acpu_freq_tbl_2g_pvs3, sizeof(acpu_freq_tbl_2g_pvs3) },
- [0][0][4] = { acpu_freq_tbl_2g_pvs4, sizeof(acpu_freq_tbl_2g_pvs4) },
- [0][0][5] = { acpu_freq_tbl_2g_pvs5, sizeof(acpu_freq_tbl_2g_pvs5) },
- [0][0][6] = { acpu_freq_tbl_2g_pvs6, sizeof(acpu_freq_tbl_2g_pvs6) },
- [0][0][7] = { acpu_freq_tbl_2g_pvs6, sizeof(acpu_freq_tbl_2g_pvs6) },
-
- /* 8974v2 2.3GHz Parts */
- [0][1][0] = { acpu_freq_tbl_2p3g_pvs0, sizeof(acpu_freq_tbl_2p3g_pvs0) },
- [0][1][1] = { acpu_freq_tbl_2p3g_pvs1, sizeof(acpu_freq_tbl_2p3g_pvs1) },
- [0][1][2] = { acpu_freq_tbl_2p3g_pvs2, sizeof(acpu_freq_tbl_2p3g_pvs2) },
- [0][1][3] = { acpu_freq_tbl_2p3g_pvs3, sizeof(acpu_freq_tbl_2p3g_pvs3) },
- [0][1][4] = { acpu_freq_tbl_2p3g_pvs4, sizeof(acpu_freq_tbl_2p3g_pvs4) },
- [0][1][5] = { acpu_freq_tbl_2p3g_pvs5, sizeof(acpu_freq_tbl_2p3g_pvs5) },
- [0][1][6] = { acpu_freq_tbl_2p3g_pvs6, sizeof(acpu_freq_tbl_2p3g_pvs6) },
- [0][1][7] = { acpu_freq_tbl_2p3g_pvs6, sizeof(acpu_freq_tbl_2p3g_pvs6) },
-
- /* 8974v2 2.2GHz Parts */
- [0][2][0] = { acpu_freq_tbl_2p2g_pvs0, sizeof(acpu_freq_tbl_2p2g_pvs0) },
- [0][2][1] = { acpu_freq_tbl_2p2g_pvs1, sizeof(acpu_freq_tbl_2p2g_pvs1) },
- [0][2][2] = { acpu_freq_tbl_2p2g_pvs2, sizeof(acpu_freq_tbl_2p2g_pvs2) },
- [0][2][3] = { acpu_freq_tbl_2p2g_pvs3, sizeof(acpu_freq_tbl_2p2g_pvs3) },
- [0][2][4] = { acpu_freq_tbl_2p2g_pvs4, sizeof(acpu_freq_tbl_2p2g_pvs4) },
- [0][2][5] = { acpu_freq_tbl_2p2g_pvs5, sizeof(acpu_freq_tbl_2p2g_pvs5) },
- [0][2][6] = { acpu_freq_tbl_2p2g_pvs6, sizeof(acpu_freq_tbl_2p2g_pvs6) },
- [0][2][7] = { acpu_freq_tbl_2p2g_pvs6, sizeof(acpu_freq_tbl_2p2g_pvs6) },
-};
-
-static struct pvs_table pvs_pro[NUM_PVS_REVS][NUM_SPEED_BINS][NUM_PVS] __initdata = {
- /* 2.0 GHz is not used on 8974Pro */
- [0][0][0] = { acpu_freq_tbl_2g_pvs0, sizeof(acpu_freq_tbl_2g_pvs0) },
- [0][0][1] = { acpu_freq_tbl_2g_pvs1, sizeof(acpu_freq_tbl_2g_pvs1) },
- [0][0][2] = { acpu_freq_tbl_2g_pvs2, sizeof(acpu_freq_tbl_2g_pvs2) },
- [0][0][3] = { acpu_freq_tbl_2g_pvs3, sizeof(acpu_freq_tbl_2g_pvs3) },
- [0][0][4] = { acpu_freq_tbl_2g_pvs4, sizeof(acpu_freq_tbl_2g_pvs4) },
- [0][0][5] = { acpu_freq_tbl_2g_pvs5, sizeof(acpu_freq_tbl_2g_pvs5) },
- [0][0][6] = { acpu_freq_tbl_2g_pvs6, sizeof(acpu_freq_tbl_2g_pvs6) },
- [0][0][7] = { acpu_freq_tbl_2g_pvs6, sizeof(acpu_freq_tbl_2g_pvs6) },
-
- /* 8974Pro AB 2.3GHz */
- [0][1][0] = { pro_rev0_2p3g_pvs0, sizeof(pro_rev0_2p3g_pvs0) },
- [0][1][1] = { pro_rev0_2p3g_pvs1, sizeof(pro_rev0_2p3g_pvs1) },
- [0][1][2] = { pro_rev0_2p3g_pvs2, sizeof(pro_rev0_2p3g_pvs2) },
- [0][1][3] = { pro_rev0_2p3g_pvs3, sizeof(pro_rev0_2p3g_pvs3) },
- [0][1][4] = { pro_rev0_2p3g_pvs4, sizeof(pro_rev0_2p3g_pvs4) },
- [0][1][5] = { pro_rev0_2p3g_pvs5, sizeof(pro_rev0_2p3g_pvs5) },
- [0][1][6] = { pro_rev0_2p3g_pvs6, sizeof(pro_rev0_2p3g_pvs6) },
- [0][1][7] = { pro_rev0_2p3g_pvs6, sizeof(pro_rev0_2p3g_pvs6) },
-
- /* 2.2GHz is not used on 8974Pro */
- [0][2][0] = { acpu_freq_tbl_2p2g_pvs0, sizeof(acpu_freq_tbl_2p2g_pvs0) },
- [0][2][1] = { acpu_freq_tbl_2p2g_pvs1, sizeof(acpu_freq_tbl_2p2g_pvs1) },
- [0][2][2] = { acpu_freq_tbl_2p2g_pvs2, sizeof(acpu_freq_tbl_2p2g_pvs2) },
- [0][2][3] = { acpu_freq_tbl_2p2g_pvs3, sizeof(acpu_freq_tbl_2p2g_pvs3) },
- [0][2][4] = { acpu_freq_tbl_2p2g_pvs4, sizeof(acpu_freq_tbl_2p2g_pvs4) },
- [0][2][5] = { acpu_freq_tbl_2p2g_pvs5, sizeof(acpu_freq_tbl_2p2g_pvs5) },
- [0][2][6] = { acpu_freq_tbl_2p2g_pvs6, sizeof(acpu_freq_tbl_2p2g_pvs6) },
- [0][2][7] = { acpu_freq_tbl_2p2g_pvs6, sizeof(acpu_freq_tbl_2p2g_pvs6) },
-
- /* 8974Pro AC 2.5GHz */
- [0][3][0] = { pro_rev0_2p5g_pvs0, sizeof(pro_rev0_2p5g_pvs0) },
- [0][3][1] = { pro_rev0_2p5g_pvs1, sizeof(pro_rev0_2p5g_pvs1) },
- [0][3][2] = { pro_rev0_2p5g_pvs2, sizeof(pro_rev0_2p5g_pvs2) },
- [0][3][3] = { pro_rev0_2p5g_pvs3, sizeof(pro_rev0_2p5g_pvs3) },
- [0][3][4] = { pro_rev0_2p5g_pvs4, sizeof(pro_rev0_2p5g_pvs4) },
- [0][3][5] = { pro_rev0_2p5g_pvs5, sizeof(pro_rev0_2p5g_pvs5) },
- [0][3][6] = { pro_rev0_2p5g_pvs6, sizeof(pro_rev0_2p5g_pvs6) },
- [0][3][7] = { pro_rev0_2p5g_pvs6, sizeof(pro_rev0_2p5g_pvs6) },
-
- /* 8974Pro AB 2.3GHz */
- [1][1][0] = { pro_rev1_2p3g_pvs0, sizeof(pro_rev1_2p3g_pvs0) },
- [1][1][1] = { pro_rev1_2p3g_pvs1, sizeof(pro_rev1_2p3g_pvs1) },
- [1][1][2] = { pro_rev1_2p3g_pvs2, sizeof(pro_rev1_2p3g_pvs2) },
- [1][1][3] = { pro_rev1_2p3g_pvs3, sizeof(pro_rev1_2p3g_pvs3) },
- [1][1][4] = { pro_rev1_2p3g_pvs4, sizeof(pro_rev1_2p3g_pvs4) },
- [1][1][5] = { pro_rev1_2p3g_pvs5, sizeof(pro_rev1_2p3g_pvs5) },
- [1][1][6] = { pro_rev1_2p3g_pvs6, sizeof(pro_rev1_2p3g_pvs6) },
- [1][1][7] = { pro_rev1_2p3g_pvs7, sizeof(pro_rev1_2p3g_pvs7) },
- [1][1][8] = { pro_rev1_2p3g_pvs8, sizeof(pro_rev1_2p3g_pvs8) },
- [1][1][9] = { pro_rev1_2p3g_pvs9, sizeof(pro_rev1_2p3g_pvs9) },
- [1][1][10] = { pro_rev1_2p3g_pvs10, sizeof(pro_rev1_2p3g_pvs10) },
- [1][1][11] = { pro_rev1_2p3g_pvs11, sizeof(pro_rev1_2p3g_pvs11) },
- [1][1][12] = { pro_rev1_2p3g_pvs12, sizeof(pro_rev1_2p3g_pvs12) },
- [1][1][13] = { pro_rev1_2p3g_pvs13, sizeof(pro_rev1_2p3g_pvs13) },
- [1][1][14] = { pro_rev1_2p3g_pvs14, sizeof(pro_rev1_2p3g_pvs14) },
- [1][1][15] = { pro_rev1_2p3g_pvs15, sizeof(pro_rev1_2p3g_pvs15) },
-
- /* 8974Pro AC 2.5GHz */
- [1][3][0] = { pro_rev1_2p5g_pvs0, sizeof(pro_rev1_2p5g_pvs0) },
- [1][3][1] = { pro_rev1_2p5g_pvs1, sizeof(pro_rev1_2p5g_pvs1) },
- [1][3][2] = { pro_rev1_2p5g_pvs2, sizeof(pro_rev1_2p5g_pvs2) },
- [1][3][3] = { pro_rev1_2p5g_pvs3, sizeof(pro_rev1_2p5g_pvs3) },
- [1][3][4] = { pro_rev1_2p5g_pvs4, sizeof(pro_rev1_2p5g_pvs4) },
- [1][3][5] = { pro_rev1_2p5g_pvs5, sizeof(pro_rev1_2p5g_pvs5) },
- [1][3][6] = { pro_rev1_2p5g_pvs6, sizeof(pro_rev1_2p5g_pvs6) },
- [1][3][7] = { pro_rev1_2p5g_pvs7, sizeof(pro_rev1_2p5g_pvs7) },
- [1][3][8] = { pro_rev1_2p5g_pvs8, sizeof(pro_rev1_2p5g_pvs8) },
- [1][3][9] = { pro_rev1_2p5g_pvs9, sizeof(pro_rev1_2p5g_pvs9) },
- [1][3][10] = { pro_rev1_2p5g_pvs10, sizeof(pro_rev1_2p5g_pvs10) },
- [1][3][11] = { pro_rev1_2p5g_pvs11, sizeof(pro_rev1_2p5g_pvs11) },
- [1][3][12] = { pro_rev1_2p5g_pvs12, sizeof(pro_rev1_2p5g_pvs12) },
- [1][3][13] = { pro_rev1_2p5g_pvs13, sizeof(pro_rev1_2p5g_pvs13) },
- [1][3][14] = { pro_rev1_2p5g_pvs14, sizeof(pro_rev1_2p5g_pvs14) },
- [1][3][15] = { pro_rev1_2p5g_pvs15, sizeof(pro_rev1_2p5g_pvs15) },
-};
-
-static struct msm_bus_scale_pdata bus_scale_data __initdata = {
- .usecase = bw_level_tbl_v2,
- .num_usecases = ARRAY_SIZE(bw_level_tbl_v2),
- .active_only = 1,
- .name = "acpuclk-8974",
-};
-
-static struct acpuclk_krait_params acpuclk_8974_params __initdata = {
- .scalable = scalable,
- .scalable_size = sizeof(scalable),
- .hfpll_data = &hfpll_data,
- .pvs_tables = pvs_v2,
- .l2_freq_tbl = l2_freq_tbl_v2,
- .l2_freq_tbl_size = sizeof(l2_freq_tbl_v2),
- .bus_scale = &bus_scale_data,
- .pte_efuse_phys = 0xFC4B80B0,
- .get_bin_info = get_krait_bin_format_b,
- .stby_khz = 300000,
-};
-
-static void __init apply_pro_bringup_workaround(void)
-{
- acpuclk_8974_params.pvs_tables = pvs_pro;
-}
-
-static void __init apply_v1_l2_workaround(void)
-{
- static struct l2_level resticted_l2_tbl[] __initdata = {
- [0] = { { 300000, PLL_0, 0, 0 }, LVL_LOW, 1050000, 0 },
- [1] = { { 1497600, HFPLL, 1, 78 }, LVL_HIGH, 1050000, 7 },
- { }
- };
- struct acpu_level *l;
- int s, p, r;
-
- for (r = 0; r < NUM_PVS_REVS; r++)
- for (s = 0; s < NUM_SPEED_BINS; s++)
- for (p = 0; p < NUM_PVS; p++) {
- l = pvs_v1[r][s][p].table;
- for (; l && l->speed.khz; l++)
- l->l2_level = l->l2_level > 5 ? 1 : 0;
- }
-
- acpuclk_8974_params.l2_freq_tbl = resticted_l2_tbl;
- acpuclk_8974_params.l2_freq_tbl_size = sizeof(resticted_l2_tbl);
-}
-
-#define cpu_is_msm8974pro() (cpu_is_msm8974pro_aa() || cpu_is_msm8974pro_ab() \
- || cpu_is_msm8974pro_ac())
-
-static int __init acpuclk_8974_probe(struct platform_device *pdev)
-{
- if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 1
- && cpu_is_msm8974()) {
- acpuclk_8974_params.pvs_tables = pvs_v1;
- acpuclk_8974_params.l2_freq_tbl = l2_freq_tbl_v1;
- bus_scale_data.usecase = bw_level_tbl_v1;
- bus_scale_data.num_usecases = ARRAY_SIZE(bw_level_tbl_v1);
- acpuclk_8974_params.l2_freq_tbl_size = sizeof(l2_freq_tbl_v1);
-
- /*
- * 8974 hardware revisions older than v1.2 may experience L2
- * parity errors when running at some performance points between
- * 300MHz and 1497.6MHz (non-inclusive), or when vdd_mx is less
- * than 1.05V. Restrict L2 operation to safe performance points
- * on these devices.
- */
- if (SOCINFO_VERSION_MINOR(socinfo_get_version()) < 2)
- apply_v1_l2_workaround();
- }
-
- if (cpu_is_msm8974pro())
- apply_pro_bringup_workaround();
-
- return acpuclk_krait_init(&pdev->dev, &acpuclk_8974_params);
-}
-
-static struct of_device_id acpuclk_8974_match_table[] = {
- { .compatible = "qcom,acpuclk-8974" },
- {}
-};
-
-static struct platform_driver acpuclk_8974_driver = {
- .driver = {
- .name = "acpuclk-8974",
- .of_match_table = acpuclk_8974_match_table,
- .owner = THIS_MODULE,
- },
-};
-
-static int __init acpuclk_8974_init(void)
-{
- return platform_driver_probe(&acpuclk_8974_driver,
- acpuclk_8974_probe);
-}
-device_initcall(acpuclk_8974_init);
diff --git a/arch/arm/mach-msm/acpuclock-cortex.c b/arch/arm/mach-msm/acpuclock-cortex.c
index baa1c7b..f2818af 100644
--- a/arch/arm/mach-msm/acpuclock-cortex.c
+++ b/arch/arm/mach-msm/acpuclock-cortex.c
@@ -340,7 +340,7 @@
/* Construct the freq_table tables from priv->freq_tbl. */
for (i = 0; priv->freq_tbl[i].khz != 0
- && freq_cnt < ARRAY_SIZE(freq_table); i++) {
+ && freq_cnt < ARRAY_SIZE(freq_table) - 1; i++) {
if (!priv->freq_tbl[i].use_for_scaling)
continue;
freq_table[freq_cnt].index = freq_cnt;
diff --git a/arch/arm/mach-msm/acpuclock-krait-debug.c b/arch/arm/mach-msm/acpuclock-krait-debug.c
deleted file mode 100644
index f11b9fc..0000000
--- a/arch/arm/mach-msm/acpuclock-krait-debug.c
+++ /dev/null
@@ -1,387 +0,0 @@
-/*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#define pr_fmt(fmt) "%s: " fmt, __func__
-
-#include <linux/kernel.h>
-#include <linux/io.h>
-#include <linux/debugfs.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/err.h>
-#include <linux/errno.h>
-#include <linux/cpu.h>
-#include <linux/smp.h>
-
-#include <mach/msm_bus.h>
-#include <mach/msm-krait-l2-accessors.h>
-
-#include "acpuclock-krait.h"
-
-static struct drv_data *drv;
-static DEFINE_MUTEX(debug_lock);
-
-struct acg_action {
- bool set;
- bool enable;
-};
-static int l2_acg_en_val;
-static struct dentry *base_dir;
-static struct dentry *sc_dir[MAX_SCALABLES];
-
-static void cpu_action(void *info)
-{
- struct acg_action *action = info;
-
- u32 val;
- asm volatile ("mrc p15, 7, %[cpmr0], c15, c0, 5\n\t"
- : [cpmr0]"=r" (val));
- if (action->set) {
- if (action->enable)
- val &= ~BIT(0);
- else
- val |= BIT(0);
- asm volatile ("mcr p15, 7, %[cpmr0], c15, c0, 5\n\t"
- : : [cpmr0]"r" (val));
- } else {
- action->enable = !(val & BIT(0));
- }
-}
-
-/* Disable auto clock-gating for a scalable. */
-static void disable_acg(int sc_id)
-{
- u32 regval;
-
- if (sc_id == L2) {
- regval = get_l2_indirect_reg(drv->scalable[sc_id].l2cpmr_iaddr);
- l2_acg_en_val = regval & (0x3 << 10);
- regval |= (0x3 << 10);
- set_l2_indirect_reg(drv->scalable[sc_id].l2cpmr_iaddr, regval);
- } else {
- struct acg_action action = { .set = true, .enable = false };
- smp_call_function_single(sc_id, cpu_action, &action, 1);
- }
-}
-
-/* Enable auto clock-gating for a scalable. */
-static void enable_acg(int sc_id)
-{
- u32 regval;
-
- if (sc_id == L2) {
- regval = get_l2_indirect_reg(drv->scalable[sc_id].l2cpmr_iaddr);
- regval &= ~(0x3 << 10);
- regval |= l2_acg_en_val;
- set_l2_indirect_reg(drv->scalable[sc_id].l2cpmr_iaddr, regval);
- } else {
- struct acg_action action = { .set = true, .enable = true };
- smp_call_function_single(sc_id, cpu_action, &action, 1);
- }
-}
-
-/* Check if auto clock-gating for a scalable. */
-static bool acg_is_enabled(int sc_id)
-{
- u32 regval;
-
- if (sc_id == L2) {
- regval = get_l2_indirect_reg(drv->scalable[sc_id].l2cpmr_iaddr);
- return ((regval >> 10) & 0x3) != 0x3;
- } else {
- struct acg_action action = { .set = false };
- smp_call_function_single(sc_id, cpu_action, &action, 1);
- return action.enable;
- }
-}
-
-/* Enable/Disable auto clock gating. */
-static int acg_set(void *data, u64 val)
-{
- int ret = 0;
- int sc_id = (int)data;
-
- mutex_lock(&debug_lock);
- get_online_cpus();
- if (!sc_dir[sc_id]) {
- ret = -ENODEV;
- goto out;
- }
-
- if (val == 0 && acg_is_enabled(sc_id))
- disable_acg(sc_id);
- else if (val == 1)
- enable_acg(sc_id);
-out:
- put_online_cpus();
- mutex_unlock(&debug_lock);
-
- return ret;
-}
-
-/* Get auto clock-gating state. */
-static int acg_get(void *data, u64 *val)
-{
- int ret = 0;
- int sc_id = (int)data;
-
- mutex_lock(&debug_lock);
- get_online_cpus();
- if (!sc_dir[sc_id]) {
- ret = -ENODEV;
- goto out;
- }
-
- *val = acg_is_enabled(sc_id);
-out:
- put_online_cpus();
- mutex_unlock(&debug_lock);
-
- return ret;
-}
-DEFINE_SIMPLE_ATTRIBUTE(acgd_fops, acg_get, acg_set, "%lld\n");
-
-/* Get the rate */
-static int rate_get(void *data, u64 *val)
-{
- int sc_id = (int)data;
- *val = drv->scalable[sc_id].cur_speed->khz;
- return 0;
-}
-DEFINE_SIMPLE_ATTRIBUTE(rate_fops, rate_get, NULL, "%lld\n");
-
-/* Get the HFPLL's L-value. */
-static int hfpll_l_get(void *data, u64 *val)
-{
- int sc_id = (int)data;
- *val = drv->scalable[sc_id].cur_speed->pll_l_val;
- return 0;
-}
-DEFINE_SIMPLE_ATTRIBUTE(hfpll_l_fops, hfpll_l_get, NULL, "%lld\n");
-
-/* Get the L2 rate vote. */
-static int l2_vote_get(void *data, u64 *val)
-{
- int level, sc_id = (int)data;
-
- level = drv->scalable[sc_id].l2_vote;
- *val = drv->l2_freq_tbl[level].speed.khz;
-
- return 0;
-}
-DEFINE_SIMPLE_ATTRIBUTE(l2_vote_fops, l2_vote_get, NULL, "%lld\n");
-
-/* Get the bandwidth vote. */
-static int bw_vote_get(void *data, u64 *val)
-{
- struct l2_level *l;
-
- l = container_of(drv->scalable[L2].cur_speed,
- struct l2_level, speed);
- *val = drv->bus_scale->usecase[l->bw_level].vectors->ib;
-
- return 0;
-}
-DEFINE_SIMPLE_ATTRIBUTE(bw_vote_fops, bw_vote_get, NULL, "%lld\n");
-
-/* Get the name of the currently-selected clock source. */
-static int src_name_show(struct seq_file *m, void *unused)
-{
- const char *const src_names[NUM_SRC_ID] = {
- [PLL_0] = "PLL0",
- [HFPLL] = "HFPLL",
- [PLL_8] = "PLL8",
- };
- int src, sc_id = (int)m->private;
-
- src = drv->scalable[sc_id].cur_speed->src;
- if (src > ARRAY_SIZE(src_names))
- return -EINVAL;
-
- seq_printf(m, "%s\n", src_names[src]);
-
- return 0;
-}
-
-static int src_name_open(struct inode *inode, struct file *file)
-{
- return single_open(file, src_name_show, inode->i_private);
-}
-
-static const struct file_operations src_name_fops = {
- .open = src_name_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release,
-};
-
-/* Get speed_bin ID */
-static int speed_bin_get(void *data, u64 *val)
-{
- *val = drv->speed_bin;
- return 0;
-}
-DEFINE_SIMPLE_ATTRIBUTE(speed_bin_fops, speed_bin_get, NULL, "%lld\n");
-
-/* Get pvs_bin ID */
-static int pvs_bin_get(void *data, u64 *val)
-{
- *val = drv->pvs_bin;
- return 0;
-}
-DEFINE_SIMPLE_ATTRIBUTE(pvs_bin_fops, pvs_bin_get, NULL, "%lld\n");
-
-/* Get boost_uv */
-static int boost_get(void *data, u64 *val)
-{
- *val = drv->boost_uv;
- return 0;
-}
-DEFINE_SIMPLE_ATTRIBUTE(boost_fops, boost_get, NULL, "%lld\n");
-
-static int acpu_table_show(struct seq_file *m, void *unused)
-{
- const struct acpu_level *level;
-
- seq_printf(m, "CPU_KHz PLL_L_Val L2_KHz VDD_Dig VDD_Mem ");
- seq_printf(m, "BW_Mbps VDD_Core UA_Core AVS\n");
-
- for (level = drv->acpu_freq_tbl; level->speed.khz != 0; level++) {
-
- const struct l2_level *l2 =
- &drv->l2_freq_tbl[level->l2_level];
- u32 bw = drv->bus_scale->usecase[l2->bw_level].vectors[0].ib;
-
- if (!level->use_for_scaling)
- continue;
-
- /* CPU speed information */
- seq_printf(m, "%7lu %9u ",
- level->speed.khz,
- level->speed.pll_l_val);
-
- /* L2 level information */
- seq_printf(m, "%7lu %7d %7d %7u ",
- l2->speed.khz,
- l2->vdd_dig,
- l2->vdd_mem,
- bw / 1000000);
-
- /* Core voltage information */
- seq_printf(m, "%8d %7d %3d\n",
- level->vdd_core,
- level->ua_core,
- level->avsdscr_setting);
- }
-
- return 0;
-}
-
-static int acpu_table_open(struct inode *inode, struct file *file)
-{
- return single_open(file, acpu_table_show, inode->i_private);
-}
-
-static const struct file_operations acpu_table_fops = {
- .open = acpu_table_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release,
-};
-
-static void __cpuinit add_scalable_dir(int sc_id)
-{
- char sc_name[8];
-
- if (sc_id == L2)
- snprintf(sc_name, sizeof(sc_name), "l2");
- else
- snprintf(sc_name, sizeof(sc_name), "cpu%d", sc_id);
-
- sc_dir[sc_id] = debugfs_create_dir(sc_name, base_dir);
- if (!sc_dir[sc_id])
- return;
-
- debugfs_create_file("auto_gating", S_IRUGO | S_IWUSR,
- sc_dir[sc_id], (void *)sc_id, &acgd_fops);
-
- debugfs_create_file("rate", S_IRUGO,
- sc_dir[sc_id], (void *)sc_id, &rate_fops);
-
- debugfs_create_file("hfpll_l", S_IRUGO,
- sc_dir[sc_id], (void *)sc_id, &hfpll_l_fops);
-
- debugfs_create_file("src", S_IRUGO,
- sc_dir[sc_id], (void *)sc_id, &src_name_fops);
-
- if (sc_id == L2)
- debugfs_create_file("bw_ib_vote", S_IRUGO,
- sc_dir[sc_id], (void *)sc_id, &bw_vote_fops);
- else
- debugfs_create_file("l2_vote", S_IRUGO,
- sc_dir[sc_id], (void *)sc_id, &l2_vote_fops);
-}
-
-static void __cpuinit remove_scalable_dir(int sc_id)
-{
- debugfs_remove_recursive(sc_dir[sc_id]);
- sc_dir[sc_id] = NULL;
-}
-
-static int __cpuinit debug_cpu_callback(struct notifier_block *nfb,
- unsigned long action, void *hcpu)
-{
- int cpu = (int)hcpu;
-
- switch (action & ~CPU_TASKS_FROZEN) {
- case CPU_DOWN_FAILED:
- case CPU_UP_PREPARE:
- add_scalable_dir(cpu);
- break;
- case CPU_UP_CANCELED:
- case CPU_DOWN_PREPARE:
- remove_scalable_dir(cpu);
- break;
- default:
- break;
- }
-
- return NOTIFY_OK;
-}
-
-static struct notifier_block __cpuinitdata debug_cpu_notifier = {
- .notifier_call = debug_cpu_callback,
-};
-
-void __init acpuclk_krait_debug_init(struct drv_data *drv_data)
-{
- int cpu;
- drv = drv_data;
-
- base_dir = debugfs_create_dir("acpuclk", NULL);
- if (!base_dir)
- return;
-
- debugfs_create_file("speed_bin", S_IRUGO, base_dir, NULL,
- &speed_bin_fops);
- debugfs_create_file("pvs_bin", S_IRUGO, base_dir, NULL, &pvs_bin_fops);
- debugfs_create_file("boost_uv", S_IRUGO, base_dir, NULL, &boost_fops);
- debugfs_create_file("acpu_table", S_IRUGO, base_dir, NULL,
- &acpu_table_fops);
-
- for_each_online_cpu(cpu)
- add_scalable_dir(cpu);
- add_scalable_dir(L2);
-
- register_hotcpu_notifier(&debug_cpu_notifier);
-}
diff --git a/arch/arm/mach-msm/acpuclock-krait.c b/arch/arm/mach-msm/acpuclock-krait.c
deleted file mode 100644
index cf3fac0..0000000
--- a/arch/arm/mach-msm/acpuclock-krait.c
+++ /dev/null
@@ -1,1243 +0,0 @@
-/*
- * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/delay.h>
-#include <linux/mutex.h>
-#include <linux/err.h>
-#include <linux/errno.h>
-#include <linux/cpufreq.h>
-#include <linux/cpu.h>
-#include <linux/regulator/consumer.h>
-#include <linux/iopoll.h>
-
-#include <asm/mach-types.h>
-#include <asm/cpu.h>
-
-#include <mach/board.h>
-#include <mach/msm_iomap.h>
-#include <mach/socinfo.h>
-#include <mach/msm-krait-l2-accessors.h>
-#include <mach/rpm-regulator.h>
-#include <mach/rpm-regulator-smd.h>
-#include <mach/msm_bus.h>
-#include <mach/msm_dcvs.h>
-
-#include "acpuclock.h"
-#include "acpuclock-krait.h"
-#include "avs.h"
-
-/* MUX source selects. */
-#define PRI_SRC_SEL_SEC_SRC 0
-#define PRI_SRC_SEL_HFPLL 1
-#define PRI_SRC_SEL_HFPLL_DIV2 2
-
-static DEFINE_MUTEX(driver_lock);
-static DEFINE_SPINLOCK(l2_lock);
-
-static struct drv_data drv;
-
-static unsigned long acpuclk_krait_get_rate(int cpu)
-{
- return drv.scalable[cpu].cur_speed->khz;
-}
-
-struct set_clk_src_args {
- struct scalable *sc;
- u32 src_sel;
-};
-
-static void __set_pri_clk_src(struct scalable *sc, u32 pri_src_sel)
-{
- u32 regval;
-
- regval = get_l2_indirect_reg(sc->l2cpmr_iaddr);
- regval &= ~0x3;
- regval |= pri_src_sel;
- if (sc != &drv.scalable[L2]) {
- regval &= ~(0x3 << 8);
- regval |= pri_src_sel << 8;
- }
- set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
- /* Wait for switch to complete. */
- mb();
- udelay(1);
-}
-
-static void __set_cpu_pri_clk_src(void *data)
-{
- struct set_clk_src_args *args = data;
- __set_pri_clk_src(args->sc, args->src_sel);
-}
-
-/* Select a source on the primary MUX. */
-static void set_pri_clk_src(struct scalable *sc, u32 pri_src_sel)
-{
- int cpu = sc - drv.scalable;
- if (sc != &drv.scalable[L2] && cpu_online(cpu)) {
- struct set_clk_src_args args = {
- .sc = sc,
- .src_sel = pri_src_sel,
- };
- smp_call_function_single(cpu, __set_cpu_pri_clk_src, &args, 1);
- } else {
- __set_pri_clk_src(sc, pri_src_sel);
- }
-}
-
-/* Select a source on the secondary MUX. */
-static void __cpuinit set_sec_clk_src(struct scalable *sc, u32 sec_src_sel)
-{
- u32 regval;
-
- regval = get_l2_indirect_reg(sc->l2cpmr_iaddr);
- regval &= ~(0x3 << 2);
- regval |= sec_src_sel << 2;
- if (sc != &drv.scalable[L2]) {
- regval &= ~(0x3 << 10);
- regval |= sec_src_sel << 10;
- }
- set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
- /* Wait for switch to complete. */
- mb();
- udelay(1);
-}
-
-static int enable_rpm_vreg(struct vreg *vreg)
-{
- int ret = 0;
-
- if (vreg->rpm_reg) {
- ret = rpm_regulator_enable(vreg->rpm_reg);
- if (ret)
- dev_err(drv.dev, "%s regulator enable failed (%d)\n",
- vreg->name, ret);
- }
-
- return ret;
-}
-
-static void disable_rpm_vreg(struct vreg *vreg)
-{
- int rc;
-
- if (vreg->rpm_reg) {
- rc = rpm_regulator_disable(vreg->rpm_reg);
- if (rc)
- dev_err(drv.dev, "%s regulator disable failed (%d)\n",
- vreg->name, rc);
- }
-}
-
-/* Enable an already-configured HFPLL. */
-static void hfpll_enable(struct scalable *sc, bool skip_regulators)
-{
- if (!skip_regulators) {
- /* Enable regulators required by the HFPLL. */
- enable_rpm_vreg(&sc->vreg[VREG_HFPLL_A]);
- enable_rpm_vreg(&sc->vreg[VREG_HFPLL_B]);
- }
-
- /* Disable PLL bypass mode. */
- writel_relaxed(0x2, sc->hfpll_base + drv.hfpll_data->mode_offset);
-
- /*
- * H/W requires a 5us delay between disabling the bypass and
- * de-asserting the reset. Delay 10us just to be safe.
- */
- mb();
- udelay(10);
-
- /* De-assert active-low PLL reset. */
- writel_relaxed(0x6, sc->hfpll_base + drv.hfpll_data->mode_offset);
-
- /* Wait for PLL to lock. */
- if (drv.hfpll_data->has_lock_status) {
- u32 regval;
- readl_tight_poll(sc->hfpll_base + drv.hfpll_data->status_offset,
- regval, regval & BIT(16));
- } else {
- mb();
- udelay(60);
- }
-
- /* Enable PLL output. */
- writel_relaxed(0x7, sc->hfpll_base + drv.hfpll_data->mode_offset);
-}
-
-/* Disable a HFPLL for power-savings or while it's being reprogrammed. */
-static void hfpll_disable(struct scalable *sc, bool skip_regulators)
-{
- /*
- * Disable the PLL output, disable test mode, enable the bypass mode,
- * and assert the reset.
- */
- writel_relaxed(0, sc->hfpll_base + drv.hfpll_data->mode_offset);
-
- if (!skip_regulators) {
- /* Remove voltage votes required by the HFPLL. */
- disable_rpm_vreg(&sc->vreg[VREG_HFPLL_B]);
- disable_rpm_vreg(&sc->vreg[VREG_HFPLL_A]);
- }
-}
-
-/* Program the HFPLL rate. Assumes HFPLL is already disabled. */
-static void hfpll_set_rate(struct scalable *sc, const struct core_speed *tgt_s)
-{
- void __iomem *base = sc->hfpll_base;
- u32 regval;
-
- writel_relaxed(tgt_s->pll_l_val, base + drv.hfpll_data->l_offset);
-
- if (drv.hfpll_data->has_user_reg) {
- regval = readl_relaxed(base + drv.hfpll_data->user_offset);
- if (tgt_s->pll_l_val <= drv.hfpll_data->low_vco_l_max)
- regval &= ~drv.hfpll_data->user_vco_mask;
- else
- regval |= drv.hfpll_data->user_vco_mask;
- writel_relaxed(regval, base + drv.hfpll_data->user_offset);
- }
-}
-
-/* Return the L2 speed that should be applied. */
-static unsigned int compute_l2_level(struct scalable *sc, unsigned int vote_l)
-{
- unsigned int new_l = 0;
- int cpu;
-
- /* Find max L2 speed vote. */
- sc->l2_vote = vote_l;
- for_each_present_cpu(cpu)
- new_l = max(new_l, drv.scalable[cpu].l2_vote);
-
- return new_l;
-}
-
-/* Update the bus bandwidth request. */
-static void set_bus_bw(unsigned int bw)
-{
- int ret;
-
- /* Update bandwidth if request has changed. This may sleep. */
- ret = msm_bus_scale_client_update_request(drv.bus_perf_client, bw);
- if (ret)
- dev_err(drv.dev, "bandwidth request failed (%d)\n", ret);
-}
-
-/* Set the CPU or L2 clock speed. */
-static void set_speed(struct scalable *sc, const struct core_speed *tgt_s,
- bool skip_regulators)
-{
- const struct core_speed *strt_s = sc->cur_speed;
-
- if (strt_s == tgt_s)
- return;
-
- if (strt_s->src == HFPLL && tgt_s->src == HFPLL) {
- /*
- * Move to an always-on source running at a frequency
- * that does not require an elevated CPU voltage.
- */
- set_pri_clk_src(sc, PRI_SRC_SEL_SEC_SRC);
-
- /* Re-program HFPLL. */
- hfpll_disable(sc, true);
- hfpll_set_rate(sc, tgt_s);
- hfpll_enable(sc, true);
-
- /* Move to HFPLL. */
- set_pri_clk_src(sc, tgt_s->pri_src_sel);
- } else if (strt_s->src == HFPLL && tgt_s->src != HFPLL) {
- set_pri_clk_src(sc, tgt_s->pri_src_sel);
- hfpll_disable(sc, skip_regulators);
- } else if (strt_s->src != HFPLL && tgt_s->src == HFPLL) {
- hfpll_set_rate(sc, tgt_s);
- hfpll_enable(sc, skip_regulators);
- set_pri_clk_src(sc, tgt_s->pri_src_sel);
- }
-
- sc->cur_speed = tgt_s;
-}
-
-struct vdd_data {
- int vdd_mem;
- int vdd_dig;
- int vdd_core;
- int ua_core;
-};
-
-/* Apply any per-cpu voltage increases. */
-static int increase_vdd(int cpu, struct vdd_data *data,
- enum setrate_reason reason)
-{
- struct scalable *sc = &drv.scalable[cpu];
- int rc;
-
- /*
- * Increase vdd_mem active-set before vdd_dig.
- * vdd_mem should be >= vdd_dig.
- */
- if (data->vdd_mem > sc->vreg[VREG_MEM].cur_vdd) {
- rc = rpm_regulator_set_voltage(sc->vreg[VREG_MEM].rpm_reg,
- data->vdd_mem, sc->vreg[VREG_MEM].max_vdd);
- if (rc) {
- dev_err(drv.dev,
- "vdd_mem (cpu%d) increase failed (%d)\n",
- cpu, rc);
- return rc;
- }
- sc->vreg[VREG_MEM].cur_vdd = data->vdd_mem;
- }
-
- /* Increase vdd_dig active-set vote. */
- if (data->vdd_dig > sc->vreg[VREG_DIG].cur_vdd) {
- rc = rpm_regulator_set_voltage(sc->vreg[VREG_DIG].rpm_reg,
- data->vdd_dig, sc->vreg[VREG_DIG].max_vdd);
- if (rc) {
- dev_err(drv.dev,
- "vdd_dig (cpu%d) increase failed (%d)\n",
- cpu, rc);
- return rc;
- }
- sc->vreg[VREG_DIG].cur_vdd = data->vdd_dig;
- }
-
- /* Increase current request. */
- if (data->ua_core > sc->vreg[VREG_CORE].cur_ua) {
- rc = regulator_set_optimum_mode(sc->vreg[VREG_CORE].reg,
- data->ua_core);
- if (rc < 0) {
- dev_err(drv.dev, "regulator_set_optimum_mode(%s) failed (%d)\n",
- sc->vreg[VREG_CORE].name, rc);
- return rc;
- }
- sc->vreg[VREG_CORE].cur_ua = data->ua_core;
- }
-
- /*
- * Update per-CPU core voltage. Don't do this for the hotplug path for
- * which it should already be correct. Attempting to set it is bad
- * because we don't know what CPU we are running on at this point, but
- * the CPU regulator API requires we call it from the affected CPU.
- */
- if (data->vdd_core > sc->vreg[VREG_CORE].cur_vdd
- && reason != SETRATE_HOTPLUG) {
- rc = regulator_set_voltage(sc->vreg[VREG_CORE].reg,
- data->vdd_core, sc->vreg[VREG_CORE].max_vdd);
- if (rc) {
- dev_err(drv.dev,
- "vdd_core (cpu%d) increase failed (%d)\n",
- cpu, rc);
- return rc;
- }
- sc->vreg[VREG_CORE].cur_vdd = data->vdd_core;
- }
-
- return 0;
-}
-
-/* Apply any per-cpu voltage decreases. */
-static void decrease_vdd(int cpu, struct vdd_data *data,
- enum setrate_reason reason)
-{
- struct scalable *sc = &drv.scalable[cpu];
- int ret;
-
- /*
- * Update per-CPU core voltage. This must be called on the CPU
- * that's being affected. Don't do this in the hotplug remove path,
- * where the rail is off and we're executing on the other CPU.
- */
- if (data->vdd_core < sc->vreg[VREG_CORE].cur_vdd
- && reason != SETRATE_HOTPLUG) {
- ret = regulator_set_voltage(sc->vreg[VREG_CORE].reg,
- data->vdd_core, sc->vreg[VREG_CORE].max_vdd);
- if (ret) {
- dev_err(drv.dev,
- "vdd_core (cpu%d) decrease failed (%d)\n",
- cpu, ret);
- return;
- }
- sc->vreg[VREG_CORE].cur_vdd = data->vdd_core;
- }
-
- /* Decrease current request. */
- if (data->ua_core < sc->vreg[VREG_CORE].cur_ua) {
- ret = regulator_set_optimum_mode(sc->vreg[VREG_CORE].reg,
- data->ua_core);
- if (ret < 0) {
- dev_err(drv.dev, "regulator_set_optimum_mode(%s) failed (%d)\n",
- sc->vreg[VREG_CORE].name, ret);
- return;
- }
- sc->vreg[VREG_CORE].cur_ua = data->ua_core;
- }
-
- /* Decrease vdd_dig active-set vote. */
- if (data->vdd_dig < sc->vreg[VREG_DIG].cur_vdd) {
- ret = rpm_regulator_set_voltage(sc->vreg[VREG_DIG].rpm_reg,
- data->vdd_dig, sc->vreg[VREG_DIG].max_vdd);
- if (ret) {
- dev_err(drv.dev,
- "vdd_dig (cpu%d) decrease failed (%d)\n",
- cpu, ret);
- return;
- }
- sc->vreg[VREG_DIG].cur_vdd = data->vdd_dig;
- }
-
- /*
- * Decrease vdd_mem active-set after vdd_dig.
- * vdd_mem should be >= vdd_dig.
- */
- if (data->vdd_mem < sc->vreg[VREG_MEM].cur_vdd) {
- ret = rpm_regulator_set_voltage(sc->vreg[VREG_MEM].rpm_reg,
- data->vdd_mem, sc->vreg[VREG_MEM].max_vdd);
- if (ret) {
- dev_err(drv.dev,
- "vdd_mem (cpu%d) decrease failed (%d)\n",
- cpu, ret);
- return;
- }
- sc->vreg[VREG_MEM].cur_vdd = data->vdd_mem;
- }
-}
-
-static int calculate_vdd_mem(const struct acpu_level *tgt)
-{
- return drv.l2_freq_tbl[tgt->l2_level].vdd_mem;
-}
-
-static int get_src_dig(const struct core_speed *s)
-{
- const int *hfpll_vdd = drv.hfpll_data->vdd;
- const u32 low_vdd_l_max = drv.hfpll_data->low_vdd_l_max;
- const u32 nom_vdd_l_max = drv.hfpll_data->nom_vdd_l_max;
-
- if (s->src != HFPLL)
- return hfpll_vdd[HFPLL_VDD_NONE];
- else if (s->pll_l_val > nom_vdd_l_max)
- return hfpll_vdd[HFPLL_VDD_HIGH];
- else if (s->pll_l_val > low_vdd_l_max)
- return hfpll_vdd[HFPLL_VDD_NOM];
- else
- return hfpll_vdd[HFPLL_VDD_LOW];
-}
-
-static int calculate_vdd_dig(const struct acpu_level *tgt)
-{
- int l2_pll_vdd_dig, cpu_pll_vdd_dig;
-
- l2_pll_vdd_dig = get_src_dig(&drv.l2_freq_tbl[tgt->l2_level].speed);
- cpu_pll_vdd_dig = get_src_dig(&tgt->speed);
-
- return max(drv.l2_freq_tbl[tgt->l2_level].vdd_dig,
- max(l2_pll_vdd_dig, cpu_pll_vdd_dig));
-}
-
-static bool enable_boost = true;
-module_param_named(boost, enable_boost, bool, S_IRUGO | S_IWUSR);
-
-static int calculate_vdd_core(const struct acpu_level *tgt)
-{
- return tgt->vdd_core + (enable_boost ? drv.boost_uv : 0);
-}
-
-static DEFINE_MUTEX(l2_regulator_lock);
-static int l2_vreg_count;
-
-static int enable_l2_regulators(void)
-{
- int ret = 0;
-
- mutex_lock(&l2_regulator_lock);
- if (l2_vreg_count == 0) {
- ret = enable_rpm_vreg(&drv.scalable[L2].vreg[VREG_HFPLL_A]);
- if (ret)
- goto out;
- ret = enable_rpm_vreg(&drv.scalable[L2].vreg[VREG_HFPLL_B]);
- if (ret) {
- disable_rpm_vreg(&drv.scalable[L2].vreg[VREG_HFPLL_A]);
- goto out;
- }
- }
- l2_vreg_count++;
-out:
- mutex_unlock(&l2_regulator_lock);
-
- return ret;
-}
-
-static void disable_l2_regulators(void)
-{
- mutex_lock(&l2_regulator_lock);
-
- if (WARN(!l2_vreg_count, "L2 regulator votes are unbalanced!"))
- goto out;
-
- if (l2_vreg_count == 1) {
- disable_rpm_vreg(&drv.scalable[L2].vreg[VREG_HFPLL_B]);
- disable_rpm_vreg(&drv.scalable[L2].vreg[VREG_HFPLL_A]);
- }
- l2_vreg_count--;
-out:
- mutex_unlock(&l2_regulator_lock);
-}
-
-/* Set the CPU's clock rate and adjust the L2 rate, voltage and BW requests. */
-static int acpuclk_krait_set_rate(int cpu, unsigned long rate,
- enum setrate_reason reason)
-{
- const struct core_speed *strt_acpu_s, *tgt_acpu_s;
- const struct acpu_level *tgt;
- int tgt_l2_l;
- enum src_id prev_l2_src = NUM_SRC_ID;
- struct vdd_data vdd_data;
- bool skip_regulators;
- int rc = 0;
-
- if (cpu > num_possible_cpus())
- return -EINVAL;
-
- if (reason == SETRATE_CPUFREQ || reason == SETRATE_HOTPLUG)
- mutex_lock(&driver_lock);
-
- strt_acpu_s = drv.scalable[cpu].cur_speed;
-
- /* Return early if rate didn't change. */
- if (rate == strt_acpu_s->khz)
- goto out;
-
- /* Find target frequency. */
- for (tgt = drv.acpu_freq_tbl; tgt->speed.khz != 0; tgt++) {
- if (tgt->speed.khz == rate) {
- tgt_acpu_s = &tgt->speed;
- break;
- }
- }
- if (tgt->speed.khz == 0) {
- rc = -EINVAL;
- goto out;
- }
-
- /* Calculate voltage requirements for the current CPU. */
- vdd_data.vdd_mem = calculate_vdd_mem(tgt);
- vdd_data.vdd_dig = calculate_vdd_dig(tgt);
- vdd_data.vdd_core = calculate_vdd_core(tgt);
- vdd_data.ua_core = tgt->ua_core;
-
- /* Disable AVS before voltage switch */
- if (reason == SETRATE_CPUFREQ && drv.scalable[cpu].avs_enabled) {
- AVS_DISABLE(cpu);
- drv.scalable[cpu].avs_enabled = false;
- }
-
- /* Increase VDD levels if needed. */
- if (reason == SETRATE_CPUFREQ || reason == SETRATE_HOTPLUG) {
- rc = increase_vdd(cpu, &vdd_data, reason);
- if (rc)
- goto out;
-
- prev_l2_src =
- drv.l2_freq_tbl[drv.scalable[cpu].l2_vote].speed.src;
- /* Vote for the L2 regulators here if necessary. */
- if (drv.l2_freq_tbl[tgt->l2_level].speed.src == HFPLL) {
- rc = enable_l2_regulators();
- if (rc)
- goto out;
- }
- }
-
- dev_dbg(drv.dev, "Switching from ACPU%d rate %lu KHz -> %lu KHz\n",
- cpu, strt_acpu_s->khz, tgt_acpu_s->khz);
-
- /*
- * If we are setting the rate as part of power collapse or in the resume
- * path after power collapse, skip the vote for the HFPLL regulators,
- * which are active-set-only votes that will be removed when apps enters
- * its sleep set. This is needed to avoid voting for regulators with
- * sleeping APIs from an atomic context.
- */
- skip_regulators = (reason == SETRATE_PC);
-
- /* Set the new CPU speed. */
- set_speed(&drv.scalable[cpu], tgt_acpu_s, skip_regulators);
-
- /*
- * Update the L2 vote and apply the rate change. A spinlock is
- * necessary to ensure L2 rate is calculated and set atomically
- * with the CPU frequency, even if acpuclk_krait_set_rate() is
- * called from an atomic context and the driver_lock mutex is not
- * acquired.
- */
- spin_lock(&l2_lock);
- tgt_l2_l = compute_l2_level(&drv.scalable[cpu], tgt->l2_level);
- set_speed(&drv.scalable[L2],
- &drv.l2_freq_tbl[tgt_l2_l].speed, true);
- spin_unlock(&l2_lock);
-
- /* Nothing else to do for power collapse or SWFI. */
- if (reason == SETRATE_PC || reason == SETRATE_SWFI)
- goto out;
-
- /*
- * Remove the vote for the L2 HFPLL regulators only if the L2
- * was already on an HFPLL source.
- */
- if (prev_l2_src == HFPLL)
- disable_l2_regulators();
-
- /* Update bus bandwith request. */
- set_bus_bw(drv.l2_freq_tbl[tgt_l2_l].bw_level);
-
- /* Drop VDD levels if we can. */
- decrease_vdd(cpu, &vdd_data, reason);
-
- /* Re-enable AVS */
- if (reason == SETRATE_CPUFREQ && tgt->avsdscr_setting) {
- AVS_ENABLE(cpu, tgt->avsdscr_setting);
- drv.scalable[cpu].avs_enabled = true;
- }
-
- dev_dbg(drv.dev, "ACPU%d speed change complete\n", cpu);
-
-out:
- if (reason == SETRATE_CPUFREQ || reason == SETRATE_HOTPLUG)
- mutex_unlock(&driver_lock);
- return rc;
-}
-
-static struct acpuclk_data acpuclk_krait_data = {
- .set_rate = acpuclk_krait_set_rate,
- .get_rate = acpuclk_krait_get_rate,
-};
-
-/* Initialize a HFPLL at a given rate and enable it. */
-static void __cpuinit hfpll_init(struct scalable *sc,
- const struct core_speed *tgt_s)
-{
- dev_dbg(drv.dev, "Initializing HFPLL%d\n", sc - drv.scalable);
-
- /* Disable the PLL for re-programming. */
- hfpll_disable(sc, true);
-
- /* Configure PLL parameters for integer mode. */
- writel_relaxed(drv.hfpll_data->config_val,
- sc->hfpll_base + drv.hfpll_data->config_offset);
- writel_relaxed(0, sc->hfpll_base + drv.hfpll_data->m_offset);
- writel_relaxed(1, sc->hfpll_base + drv.hfpll_data->n_offset);
- if (drv.hfpll_data->has_user_reg)
- writel_relaxed(drv.hfpll_data->user_val,
- sc->hfpll_base + drv.hfpll_data->user_offset);
-
- /* Program droop controller, if supported */
- if (drv.hfpll_data->has_droop_ctl)
- writel_relaxed(drv.hfpll_data->droop_val,
- sc->hfpll_base + drv.hfpll_data->droop_offset);
-
- /* Set an initial PLL rate. */
- hfpll_set_rate(sc, tgt_s);
-}
-
-static int __cpuinit rpm_regulator_init(struct scalable *sc, enum vregs vreg,
- int vdd, bool enable)
-{
- int ret;
-
- if (!sc->vreg[vreg].name)
- return 0;
-
- sc->vreg[vreg].rpm_reg = rpm_regulator_get(drv.dev,
- sc->vreg[vreg].name);
- if (IS_ERR(sc->vreg[vreg].rpm_reg)) {
- ret = PTR_ERR(sc->vreg[vreg].rpm_reg);
- dev_err(drv.dev, "rpm_regulator_get(%s) failed (%d)\n",
- sc->vreg[vreg].name, ret);
- goto err_get;
- }
-
- ret = rpm_regulator_set_voltage(sc->vreg[vreg].rpm_reg, vdd,
- sc->vreg[vreg].max_vdd);
- if (ret) {
- dev_err(drv.dev, "%s initialization failed (%d)\n",
- sc->vreg[vreg].name, ret);
- goto err_conf;
- }
- sc->vreg[vreg].cur_vdd = vdd;
-
- if (enable) {
- ret = enable_rpm_vreg(&sc->vreg[vreg]);
- if (ret)
- goto err_conf;
- }
-
- return 0;
-
-err_conf:
- rpm_regulator_put(sc->vreg[vreg].rpm_reg);
-err_get:
- return ret;
-}
-
-static void __cpuinit rpm_regulator_cleanup(struct scalable *sc,
- enum vregs vreg)
-{
- if (!sc->vreg[vreg].rpm_reg)
- return;
-
- disable_rpm_vreg(&sc->vreg[vreg]);
- rpm_regulator_put(sc->vreg[vreg].rpm_reg);
-}
-
-/* Voltage regulator initialization. */
-static int __cpuinit regulator_init(struct scalable *sc,
- const struct acpu_level *acpu_level)
-{
- int ret, vdd_mem, vdd_dig, vdd_core;
-
- vdd_mem = calculate_vdd_mem(acpu_level);
- ret = rpm_regulator_init(sc, VREG_MEM, vdd_mem, true);
- if (ret)
- goto err_mem;
-
- vdd_dig = calculate_vdd_dig(acpu_level);
- ret = rpm_regulator_init(sc, VREG_DIG, vdd_dig, true);
- if (ret)
- goto err_dig;
-
- ret = rpm_regulator_init(sc, VREG_HFPLL_A,
- sc->vreg[VREG_HFPLL_A].max_vdd, false);
- if (ret)
- goto err_hfpll_a;
- ret = rpm_regulator_init(sc, VREG_HFPLL_B,
- sc->vreg[VREG_HFPLL_B].max_vdd, false);
- if (ret)
- goto err_hfpll_b;
-
- /* Setup Krait CPU regulators and initial core voltage. */
- sc->vreg[VREG_CORE].reg = regulator_get(drv.dev,
- sc->vreg[VREG_CORE].name);
- if (IS_ERR(sc->vreg[VREG_CORE].reg)) {
- ret = PTR_ERR(sc->vreg[VREG_CORE].reg);
- dev_err(drv.dev, "regulator_get(%s) failed (%d)\n",
- sc->vreg[VREG_CORE].name, ret);
- goto err_core_get;
- }
- ret = regulator_set_optimum_mode(sc->vreg[VREG_CORE].reg,
- acpu_level->ua_core);
- if (ret < 0) {
- dev_err(drv.dev, "regulator_set_optimum_mode(%s) failed (%d)\n",
- sc->vreg[VREG_CORE].name, ret);
- goto err_core_conf;
- }
- sc->vreg[VREG_CORE].cur_ua = acpu_level->ua_core;
- vdd_core = calculate_vdd_core(acpu_level);
- ret = regulator_set_voltage(sc->vreg[VREG_CORE].reg, vdd_core,
- sc->vreg[VREG_CORE].max_vdd);
- if (ret) {
- dev_err(drv.dev, "regulator_set_voltage(%s) (%d)\n",
- sc->vreg[VREG_CORE].name, ret);
- goto err_core_conf;
- }
- sc->vreg[VREG_CORE].cur_vdd = vdd_core;
- ret = regulator_enable(sc->vreg[VREG_CORE].reg);
- if (ret) {
- dev_err(drv.dev, "regulator_enable(%s) failed (%d)\n",
- sc->vreg[VREG_CORE].name, ret);
- goto err_core_conf;
- }
-
- /*
- * Increment the L2 HFPLL regulator refcount if _this_ CPU's frequency
- * requires a corresponding target L2 frequency that needs the L2 to
- * run off of an HFPLL.
- */
- if (drv.l2_freq_tbl[acpu_level->l2_level].speed.src == HFPLL)
- l2_vreg_count++;
-
- return 0;
-
-err_core_conf:
- regulator_put(sc->vreg[VREG_CORE].reg);
-err_core_get:
- rpm_regulator_cleanup(sc, VREG_HFPLL_B);
-err_hfpll_b:
- rpm_regulator_cleanup(sc, VREG_HFPLL_A);
-err_hfpll_a:
- rpm_regulator_cleanup(sc, VREG_DIG);
-err_dig:
- rpm_regulator_cleanup(sc, VREG_MEM);
-err_mem:
- return ret;
-}
-
-static void __cpuinit regulator_cleanup(struct scalable *sc)
-{
- regulator_disable(sc->vreg[VREG_CORE].reg);
- regulator_put(sc->vreg[VREG_CORE].reg);
- rpm_regulator_cleanup(sc, VREG_HFPLL_B);
- rpm_regulator_cleanup(sc, VREG_HFPLL_A);
- rpm_regulator_cleanup(sc, VREG_DIG);
- rpm_regulator_cleanup(sc, VREG_MEM);
-}
-
-/* Set initial rate for a given core. */
-static int __cpuinit init_clock_sources(struct scalable *sc,
- const struct core_speed *tgt_s)
-{
- u32 regval;
- void __iomem *aux_reg;
-
- /* Program AUX source input to the secondary MUX. */
- if (sc->aux_clk_sel_phys) {
- aux_reg = ioremap(sc->aux_clk_sel_phys, 4);
- if (!aux_reg)
- return -ENOMEM;
- writel_relaxed(sc->aux_clk_sel, aux_reg);
- iounmap(aux_reg);
- }
-
- /* Switch away from the HFPLL while it's re-initialized. */
- set_sec_clk_src(sc, sc->sec_clk_sel);
- set_pri_clk_src(sc, PRI_SRC_SEL_SEC_SRC);
- hfpll_init(sc, tgt_s);
-
- /* Set PRI_SRC_SEL_HFPLL_DIV2 divider to div-2. */
- regval = get_l2_indirect_reg(sc->l2cpmr_iaddr);
- regval &= ~(0x3 << 6);
- if (sc != &drv.scalable[L2])
- regval &= ~(0x3 << 14);
- set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
-
- /* Enable and switch to the target clock source. */
- if (tgt_s->src == HFPLL)
- hfpll_enable(sc, false);
- set_pri_clk_src(sc, tgt_s->pri_src_sel);
- sc->cur_speed = tgt_s;
-
- return 0;
-}
-
-static void __cpuinit fill_cur_core_speed(struct core_speed *s,
- struct scalable *sc)
-{
- s->pri_src_sel = get_l2_indirect_reg(sc->l2cpmr_iaddr) & 0x3;
- s->pll_l_val = readl_relaxed(sc->hfpll_base + drv.hfpll_data->l_offset);
-}
-
-static bool __cpuinit speed_equal(const struct core_speed *s1,
- const struct core_speed *s2)
-{
- return (s1->pri_src_sel == s2->pri_src_sel &&
- s1->pll_l_val == s2->pll_l_val);
-}
-
-static const struct acpu_level __cpuinit *find_cur_acpu_level(int cpu)
-{
- struct scalable *sc = &drv.scalable[cpu];
- const struct acpu_level *l;
- struct core_speed cur_speed;
-
- fill_cur_core_speed(&cur_speed, sc);
- for (l = drv.acpu_freq_tbl; l->speed.khz != 0; l++)
- if (speed_equal(&l->speed, &cur_speed))
- return l;
- return NULL;
-}
-
-static const struct l2_level __init *find_cur_l2_level(void)
-{
- struct scalable *sc = &drv.scalable[L2];
- const struct l2_level *l;
- struct core_speed cur_speed;
-
- fill_cur_core_speed(&cur_speed, sc);
- for (l = drv.l2_freq_tbl; l->speed.khz != 0; l++)
- if (speed_equal(&l->speed, &cur_speed))
- return l;
- return NULL;
-}
-
-static const struct acpu_level __cpuinit *find_min_acpu_level(void)
-{
- struct acpu_level *l;
-
- for (l = drv.acpu_freq_tbl; l->speed.khz != 0; l++)
- if (l->use_for_scaling)
- return l;
-
- return NULL;
-}
-
-static int __cpuinit per_cpu_init(int cpu)
-{
- struct scalable *sc = &drv.scalable[cpu];
- const struct acpu_level *acpu_level;
- int ret;
-
- sc->hfpll_base = ioremap(sc->hfpll_phys_base, SZ_32);
- if (!sc->hfpll_base) {
- ret = -ENOMEM;
- goto err_ioremap;
- }
-
- acpu_level = find_cur_acpu_level(cpu);
- if (!acpu_level) {
- acpu_level = find_min_acpu_level();
- if (!acpu_level) {
- ret = -ENODEV;
- goto err_table;
- }
- dev_dbg(drv.dev, "CPU%d is running at an unknown rate. Defaulting to %lu KHz.\n",
- cpu, acpu_level->speed.khz);
- } else {
- dev_dbg(drv.dev, "CPU%d is running at %lu KHz\n", cpu,
- acpu_level->speed.khz);
- }
-
- ret = regulator_init(sc, acpu_level);
- if (ret)
- goto err_regulators;
-
- ret = init_clock_sources(sc, &acpu_level->speed);
- if (ret)
- goto err_clocks;
-
- sc->l2_vote = acpu_level->l2_level;
- sc->initialized = true;
-
- return 0;
-
-err_clocks:
- regulator_cleanup(sc);
-err_regulators:
-err_table:
- iounmap(sc->hfpll_base);
-err_ioremap:
- return ret;
-}
-
-/* Register with bus driver. */
-static void __init bus_init(const struct l2_level *l2_level)
-{
- int ret;
-
- drv.bus_perf_client = msm_bus_scale_register_client(drv.bus_scale);
- if (!drv.bus_perf_client) {
- dev_err(drv.dev, "unable to register bus client\n");
- BUG();
- }
-
- ret = msm_bus_scale_client_update_request(drv.bus_perf_client,
- l2_level->bw_level);
- if (ret)
- dev_err(drv.dev, "initial bandwidth req failed (%d)\n", ret);
-}
-
-#ifdef CONFIG_CPU_FREQ_MSM
-static struct cpufreq_frequency_table freq_table[NR_CPUS][35];
-
-static void __init cpufreq_table_init(void)
-{
- int cpu;
- int freq_cnt = 0;
-
- for_each_possible_cpu(cpu) {
- int i;
- /* Construct the freq_table tables from acpu_freq_tbl. */
- for (i = 0, freq_cnt = 0; drv.acpu_freq_tbl[i].speed.khz != 0
- && freq_cnt < ARRAY_SIZE(*freq_table); i++) {
- if (drv.acpu_freq_tbl[i].use_for_scaling) {
- freq_table[cpu][freq_cnt].index = freq_cnt;
- freq_table[cpu][freq_cnt].frequency
- = drv.acpu_freq_tbl[i].speed.khz;
- freq_cnt++;
- }
- }
- /* freq_table not big enough to store all usable freqs. */
- BUG_ON(drv.acpu_freq_tbl[i].speed.khz != 0);
-
- freq_table[cpu][freq_cnt].index = freq_cnt;
- freq_table[cpu][freq_cnt].frequency = CPUFREQ_TABLE_END;
-
- /* Register table with CPUFreq. */
- cpufreq_frequency_table_get_attr(freq_table[cpu], cpu);
- }
-
- dev_info(drv.dev, "CPU Frequencies Supported: %d\n", freq_cnt);
-}
-#else
-static void __init cpufreq_table_init(void) {}
-#endif
-
-static void __init dcvs_freq_init(void)
-{
- int i;
-
- for (i = 0; drv.acpu_freq_tbl[i].speed.khz != 0; i++)
- if (drv.acpu_freq_tbl[i].use_for_scaling)
- msm_dcvs_register_cpu_freq(
- drv.acpu_freq_tbl[i].speed.khz,
- drv.acpu_freq_tbl[i].vdd_core / 1000);
-}
-
-static int __cpuinit acpuclk_cpu_callback(struct notifier_block *nfb,
- unsigned long action, void *hcpu)
-{
- static int prev_khz[NR_CPUS];
- int rc, cpu = (int)hcpu;
- struct scalable *sc = &drv.scalable[cpu];
- unsigned long hot_unplug_khz = acpuclk_krait_data.power_collapse_khz;
-
- switch (action & ~CPU_TASKS_FROZEN) {
- case CPU_DEAD:
- prev_khz[cpu] = acpuclk_krait_get_rate(cpu);
- /* Fall through. */
- case CPU_UP_CANCELED:
- acpuclk_krait_set_rate(cpu, hot_unplug_khz, SETRATE_HOTPLUG);
-
- regulator_disable(sc->vreg[VREG_CORE].reg);
- regulator_set_optimum_mode(sc->vreg[VREG_CORE].reg, 0);
- regulator_set_voltage(sc->vreg[VREG_CORE].reg, 0,
- sc->vreg[VREG_CORE].max_vdd);
- break;
- case CPU_UP_PREPARE:
- if (!sc->initialized) {
- rc = per_cpu_init(cpu);
- if (rc)
- return NOTIFY_BAD;
- break;
- }
- if (WARN_ON(!prev_khz[cpu]))
- return NOTIFY_BAD;
-
- rc = regulator_set_voltage(sc->vreg[VREG_CORE].reg,
- sc->vreg[VREG_CORE].cur_vdd,
- sc->vreg[VREG_CORE].max_vdd);
- if (rc < 0)
- return NOTIFY_BAD;
- rc = regulator_set_optimum_mode(sc->vreg[VREG_CORE].reg,
- sc->vreg[VREG_CORE].cur_ua);
- if (rc < 0)
- return NOTIFY_BAD;
- rc = regulator_enable(sc->vreg[VREG_CORE].reg);
- if (rc < 0)
- return NOTIFY_BAD;
-
- acpuclk_krait_set_rate(cpu, prev_khz[cpu], SETRATE_HOTPLUG);
- break;
- default:
- break;
- }
-
- return NOTIFY_OK;
-}
-
-static struct notifier_block __cpuinitdata acpuclk_cpu_notifier = {
- .notifier_call = acpuclk_cpu_callback,
-};
-
-static const int __init krait_needs_vmin(void)
-{
- switch (read_cpuid_id()) {
- case 0x511F04D0: /* KR28M2A20 */
- case 0x511F04D1: /* KR28M2A21 */
- case 0x510F06F0: /* KR28M4A10 */
- return 1;
- default:
- return 0;
- };
-}
-
-static void __init krait_apply_vmin(struct acpu_level *tbl)
-{
- for (; tbl->speed.khz != 0; tbl++) {
- if (tbl->vdd_core < 1150000)
- tbl->vdd_core = 1150000;
- tbl->avsdscr_setting = 0;
- }
-}
-
-void __init get_krait_bin_format_a(void __iomem *base, struct bin_info *bin)
-{
- u32 pte_efuse = readl_relaxed(base);
-
- bin->speed = pte_efuse & 0xF;
- if (bin->speed == 0xF)
- bin->speed = (pte_efuse >> 4) & 0xF;
- bin->speed_valid = bin->speed != 0xF;
-
- bin->pvs = (pte_efuse >> 10) & 0x7;
- if (bin->pvs == 0x7)
- bin->pvs = (pte_efuse >> 13) & 0x7;
- bin->pvs_valid = bin->pvs != 0x7;
-}
-
-void __init get_krait_bin_format_b(void __iomem *base, struct bin_info *bin)
-{
- u32 pte_efuse, redundant_sel;
-
- pte_efuse = readl_relaxed(base);
- redundant_sel = (pte_efuse >> 24) & 0x7;
- bin->pvs_rev = (pte_efuse >> 4) & 0x3;
- bin->speed = pte_efuse & 0x7;
- /* PVS number is in bits 31, 8, 7, 6 */
- bin->pvs = ((pte_efuse >> 28) & 0x8) | ((pte_efuse >> 6) & 0x7);
-
- switch (redundant_sel) {
- case 1:
- bin->speed = (pte_efuse >> 27) & 0xF;
- break;
- case 2:
- bin->pvs = (pte_efuse >> 27) & 0xF;
- break;
- }
- bin->speed_valid = true;
-
- /* Check PVS_BLOW_STATUS */
- pte_efuse = readl_relaxed(base + 0x4);
- bin->pvs_valid = !!(pte_efuse & BIT(21));
-}
-
-static struct pvs_table * __init select_freq_plan(
- const struct acpuclk_krait_params *params)
-{
- void __iomem *pte_efuse_base;
- struct bin_info bin;
-
- pte_efuse_base = ioremap(params->pte_efuse_phys, 8);
- if (!pte_efuse_base) {
- dev_err(drv.dev, "Unable to map PTE eFuse base\n");
- return NULL;
- }
- params->get_bin_info(pte_efuse_base, &bin);
- iounmap(pte_efuse_base);
-
- if (bin.speed_valid) {
- drv.speed_bin = bin.speed;
- dev_info(drv.dev, "SPEED BIN: %d\n", drv.speed_bin);
- } else {
- drv.speed_bin = 0;
- dev_warn(drv.dev, "SPEED BIN: Defaulting to %d\n",
- drv.speed_bin);
- }
-
- if (bin.pvs_valid) {
- drv.pvs_bin = bin.pvs;
- dev_info(drv.dev, "ACPU PVS: %d\n", drv.pvs_bin);
- drv.pvs_rev = bin.pvs_rev;
- dev_info(drv.dev, "ACPU PVS REVISION: %d\n", drv.pvs_rev);
- } else {
- drv.pvs_bin = 0;
- dev_warn(drv.dev, "ACPU PVS: Defaulting to %d\n",
- drv.pvs_bin);
- }
-
- return ¶ms->pvs_tables[drv.pvs_rev][drv.speed_bin][drv.pvs_bin];
-}
-
-static void __init drv_data_init(struct device *dev,
- const struct acpuclk_krait_params *params)
-{
- struct pvs_table *pvs;
-
- drv.dev = dev;
- drv.scalable = kmemdup(params->scalable, params->scalable_size,
- GFP_KERNEL);
- BUG_ON(!drv.scalable);
-
- drv.hfpll_data = kmemdup(params->hfpll_data, sizeof(*drv.hfpll_data),
- GFP_KERNEL);
- BUG_ON(!drv.hfpll_data);
-
- drv.l2_freq_tbl = kmemdup(params->l2_freq_tbl, params->l2_freq_tbl_size,
- GFP_KERNEL);
- BUG_ON(!drv.l2_freq_tbl);
-
- drv.bus_scale = kmemdup(params->bus_scale, sizeof(*drv.bus_scale),
- GFP_KERNEL);
- BUG_ON(!drv.bus_scale);
- drv.bus_scale->usecase = kmemdup(drv.bus_scale->usecase,
- drv.bus_scale->num_usecases * sizeof(*drv.bus_scale->usecase),
- GFP_KERNEL);
- BUG_ON(!drv.bus_scale->usecase);
-
- pvs = select_freq_plan(params);
- BUG_ON(!pvs->table);
-
- drv.acpu_freq_tbl = kmemdup(pvs->table, pvs->size, GFP_KERNEL);
- BUG_ON(!drv.acpu_freq_tbl);
- drv.boost_uv = pvs->boost_uv;
-
- acpuclk_krait_data.power_collapse_khz = params->stby_khz;
- acpuclk_krait_data.wait_for_irq_khz = params->stby_khz;
-}
-
-static void __init hw_init(void)
-{
- struct scalable *l2 = &drv.scalable[L2];
- const struct l2_level *l2_level;
- int cpu, rc;
-
- if (krait_needs_vmin())
- krait_apply_vmin(drv.acpu_freq_tbl);
-
- l2->hfpll_base = ioremap(l2->hfpll_phys_base, SZ_32);
- BUG_ON(!l2->hfpll_base);
-
- rc = rpm_regulator_init(l2, VREG_HFPLL_A,
- l2->vreg[VREG_HFPLL_A].max_vdd, false);
- BUG_ON(rc);
- rc = rpm_regulator_init(l2, VREG_HFPLL_B,
- l2->vreg[VREG_HFPLL_B].max_vdd, false);
- BUG_ON(rc);
-
- l2_level = find_cur_l2_level();
- if (!l2_level) {
- l2_level = drv.l2_freq_tbl;
- dev_dbg(drv.dev, "L2 is running at an unknown rate. Defaulting to %lu KHz.\n",
- l2_level->speed.khz);
- } else {
- dev_dbg(drv.dev, "L2 is running at %lu KHz\n",
- l2_level->speed.khz);
- }
-
- rc = init_clock_sources(l2, &l2_level->speed);
- BUG_ON(rc);
-
- for_each_online_cpu(cpu) {
- rc = per_cpu_init(cpu);
- BUG_ON(rc);
- }
-
- bus_init(l2_level);
-}
-
-int __init acpuclk_krait_init(struct device *dev,
- const struct acpuclk_krait_params *params)
-{
- drv_data_init(dev, params);
- hw_init();
-
- cpufreq_table_init();
- dcvs_freq_init();
- acpuclk_register(&acpuclk_krait_data);
- register_hotcpu_notifier(&acpuclk_cpu_notifier);
-
- acpuclk_krait_debug_init(&drv);
-
- return 0;
-}
diff --git a/arch/arm/mach-msm/acpuclock-krait.h b/arch/arm/mach-msm/acpuclock-krait.h
deleted file mode 100644
index 4eff45d..0000000
--- a/arch/arm/mach-msm/acpuclock-krait.h
+++ /dev/null
@@ -1,353 +0,0 @@
-/*
- * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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 __ARCH_ARM_MACH_MSM_ACPUCLOCK_KRAIT_H
-#define __ARCH_ARM_MACH_MSM_ACPUCLOCK_KRAIT_H
-
-#define L2(x) (x)
-#define BW_MBPS(_bw) \
- { \
- .vectors = (struct msm_bus_vectors[]){ \
- {\
- .src = MSM_BUS_MASTER_AMPSS_M0, \
- .dst = MSM_BUS_SLAVE_EBI_CH0, \
- .ib = (_bw) * 1000000ULL, \
- }, \
- { \
- .src = MSM_BUS_MASTER_AMPSS_M1, \
- .dst = MSM_BUS_SLAVE_EBI_CH0, \
- .ib = (_bw) * 1000000ULL, \
- }, \
- }, \
- .num_paths = 2, \
- }
-
-/**
- * src_id - Clock source IDs.
- */
-enum src_id {
- PLL_0 = 0,
- HFPLL,
- PLL_8,
- NUM_SRC_ID
-};
-
-/**
- * enum pvs - IDs to distinguish between CPU frequency tables.
- */
-enum pvs {
- PVS_SLOW = 0,
- PVS_NOMINAL = 1,
- PVS_FAST = 3,
- PVS_FASTER = 4,
- NUM_PVS = 16
-};
-
-/**
- * The maximum number of PVS revisions.
- */
-#define NUM_PVS_REVS (4)
-
-/**
- * The maximum number of speed bins.
- */
-#define NUM_SPEED_BINS (16)
-
-/**
- * enum scalables - IDs of frequency scalable hardware blocks.
- */
-enum scalables {
- CPU0 = 0,
- CPU1,
- CPU2,
- CPU3,
- L2,
- MAX_SCALABLES
-};
-
-
-/**
- * enum hfpll_vdd_level - IDs of HFPLL voltage levels.
- */
-enum hfpll_vdd_levels {
- HFPLL_VDD_NONE,
- HFPLL_VDD_LOW,
- HFPLL_VDD_NOM,
- HFPLL_VDD_HIGH,
- NUM_HFPLL_VDD
-};
-
-/**
- * enum vregs - IDs of voltage regulators.
- */
-enum vregs {
- VREG_CORE,
- VREG_MEM,
- VREG_DIG,
- VREG_HFPLL_A,
- VREG_HFPLL_B,
- NUM_VREG
-};
-
-/**
- * struct vreg - Voltage regulator data.
- * @name: Name of requlator.
- * @max_vdd: Limit the maximum-settable voltage.
- * @reg: Regulator handle.
- * @rpm_reg: RPM Regulator handle.
- * @cur_vdd: Last-set voltage in uV.
- * @cur_ua: Last-set current in uA.
- */
-struct vreg {
- const char *name;
- const int max_vdd;
- struct regulator *reg;
- struct rpm_regulator *rpm_reg;
- int cur_vdd;
- int cur_ua;
-};
-
-/**
- * struct core_speed - Clock tree and configuration parameters.
- * @khz: Clock rate in KHz.
- * @src: Clock source ID.
- * @pri_src_sel: Input to select on the primary MUX.
- * @pll_l_val: HFPLL "L" value to be applied when an HFPLL source is selected.
- */
-struct core_speed {
- unsigned long khz;
- int src;
- u32 pri_src_sel;
- u32 pll_l_val;
-};
-
-/**
- * struct l2_level - L2 clock rate and associated voltage and b/w requirements.
- * @speed: L2 clock configuration.
- * @vdd_dig: vdd_dig voltage in uV.
- * @vdd_mem: vdd_mem voltage in uV.
- * @bw_level: Bandwidth performance level number.
- */
-struct l2_level {
- const struct core_speed speed;
- const int vdd_dig;
- const int vdd_mem;
- const unsigned int bw_level;
-};
-
-/**
- * struct acpu_level - CPU clock rate and L2 rate and voltage requirements.
- * @use_for_scaling: Flag indicating whether or not the level should be used.
- * @speed: CPU clock configuration.
- * @l2_level: L2 configuration to use.
- * @vdd_core: CPU core voltage in uV.
- * @ua_core: CPU core current consumption in uA.
- * @avsdscr_setting: AVS DSCR configuration.
- */
-struct acpu_level {
- const int use_for_scaling;
- const struct core_speed speed;
- unsigned int l2_level;
- int vdd_core;
- int ua_core;
- unsigned int avsdscr_setting;
-};
-
-/**
- * struct hfpll_data - Descriptive data of HFPLL hardware.
- * @mode_offset: Mode register offset from base address.
- * @l_offset: "L" value register offset from base address.
- * @m_offset: "M" value register offset from base address.
- * @n_offset: "N" value register offset from base address.
- * @config_offset: Configuration register offset from base address.
- * @config_val: Value to initialize the @config_offset register to.
- * @has_user_reg: Indicates the presence of an addition config register.
- * @user_offset: User register offset from base address, if applicable.
- * @user_val: Value to initialize the @user_offset register to.
- * @user_vco_mask: Bit in the @user_offset to enable high-frequency VCO mode.
- * @has_droop_ctl: Indicates the presence of a voltage droop controller.
- * @has_lock_status: Indicates the presence of a lock status bit.
- * @droop_offset: Droop controller register offset from base address.
- * @droop_val: Value to initialize the @config_offset register to.
- * @status_offset: PLL status register offset.
- * @low_vdd_l_max: Maximum "L" value supported at HFPLL_VDD_LOW.
- * @nom_vdd_l_max: Maximum "L" value supported at HFPLL_VDD_NOM.
- * @low_vco_l_max: Maximum "L" value supported in low-frequency VCO mode.
- * @vdd: voltage requirements for each VDD level for the L2 PLL.
- */
-struct hfpll_data {
- const u32 mode_offset;
- const u32 l_offset;
- const u32 m_offset;
- const u32 n_offset;
- const u32 config_offset;
- const u32 config_val;
- const bool has_user_reg;
- const u32 user_offset;
- const u32 user_val;
- const u32 user_vco_mask;
- const bool has_droop_ctl;
- const bool has_lock_status;
- const u32 droop_offset;
- const u32 droop_val;
- const u32 status_offset;
- u32 low_vdd_l_max;
- u32 nom_vdd_l_max;
- const u32 low_vco_l_max;
- const int vdd[NUM_HFPLL_VDD];
-};
-
-/**
- * struct scalable - Register locations and state associated with a scalable HW.
- * @hfpll_phys_base: Physical base address of HFPLL register.
- * @hfpll_base: Virtual base address of HFPLL registers.
- * @aux_clk_sel_phys: Physical address of auxiliary MUX.
- * @aux_clk_sel: Auxiliary mux input to select at boot.
- * @sec_clk_sel: Secondary mux input to select at boot.
- * @l2cpmr_iaddr: Indirect address of the CPMR MUX/divider CP15 register.
- * @cur_speed: Pointer to currently-set speed.
- * @l2_vote: L2 performance level vote associate with the current CPU speed.
- * @vreg: Array of voltage regulators needed by the scalable.
- * @initialized: Flag set to true when per_cpu_init() has been called.
- * @avs_enabled: True if avs is enabled for the scalabale. False otherwise.
- */
-struct scalable {
- const phys_addr_t hfpll_phys_base;
- void __iomem *hfpll_base;
- const phys_addr_t aux_clk_sel_phys;
- const u32 aux_clk_sel;
- const u32 sec_clk_sel;
- const u32 l2cpmr_iaddr;
- const struct core_speed *cur_speed;
- unsigned int l2_vote;
- struct vreg vreg[NUM_VREG];
- bool initialized;
- bool avs_enabled;
-};
-
-/**
- * struct bin_info - Hardware speed and voltage binning info.
- * @speed_valid: @speed field is valid
- * @pvs_valid: @pvs field is valid
- * @speed: Speed bin ID
- * @pvs: PVS bin ID
- * @pvs_rev: PVS revision ID
- */
-struct bin_info {
- bool speed_valid;
- bool pvs_valid;
- int speed;
- int pvs;
- int pvs_rev;
-};
-
-/**
- * struct pvs_table - CPU performance level table and size.
- * @table: CPU performance level table
- * @size: sizeof(@table)
- * @boost_uv: Voltage boost amount
- */
-struct pvs_table {
- struct acpu_level *table;
- size_t size;
- int boost_uv;
-};
-
-/**
- * struct acpuclk_krait_params - SoC specific driver parameters.
- * @scalable: Array of scalables.
- * @scalable_size: Size of @scalable.
- * @hfpll_data: HFPLL configuration data.
- * @pvs_tables: 2D array of CPU frequency tables.
- * @l2_freq_tbl: L2 frequency table.
- * @l2_freq_tbl_size: Size of @l2_freq_tbl.
- * @pte_efuse_phys: Physical address of PTE EFUSE.
- * @get_bin_info: Function to populate bin_info from pte_efuse.
- * @bus_scale: MSM bus driver parameters.
- * @stby_khz: KHz value corresponding to an always-on clock source.
- */
-struct acpuclk_krait_params {
- struct scalable *scalable;
- size_t scalable_size;
- struct hfpll_data *hfpll_data;
- struct pvs_table (*pvs_tables)[NUM_SPEED_BINS][NUM_PVS];
- struct l2_level *l2_freq_tbl;
- size_t l2_freq_tbl_size;
- phys_addr_t pte_efuse_phys;
- void (*get_bin_info)(void __iomem *base, struct bin_info *bin);
- struct msm_bus_scale_pdata *bus_scale;
- unsigned long stby_khz;
-};
-
-/**
- * struct drv_data - Driver state
- * @acpu_freq_tbl: CPU frequency table.
- * @l2_freq_tbl: L2 frequency table.
- * @scalable: Array of scalables (CPUs and L2).
- * @hfpll_data: High-frequency PLL data.
- * @bus_perf_client: Bus driver client handle.
- * @bus_scale: Bus driver scaling data.
- * @boost_uv: Voltage boost amount
- * @speed_bin: Speed bin ID.
- * @pvs_bin: PVS bin ID.
- * @pvs_bin: PVS revision ID.
- * @dev: Device.
- */
-struct drv_data {
- struct acpu_level *acpu_freq_tbl;
- const struct l2_level *l2_freq_tbl;
- struct scalable *scalable;
- struct hfpll_data *hfpll_data;
- u32 bus_perf_client;
- struct msm_bus_scale_pdata *bus_scale;
- int boost_uv;
- int speed_bin;
- int pvs_bin;
- int pvs_rev;
- struct device *dev;
-};
-
-/**
- * struct acpuclk_platform_data - PMIC configuration data.
- * @uses_pm8917: Boolean indicates presence of pm8917.
- */
-struct acpuclk_platform_data {
- bool uses_pm8917;
-};
-
-/**
- * get_krait_bin_format_a - Populate bin_info from a 'Format A' pte_efuse
- */
-void __init get_krait_bin_format_a(void __iomem *base, struct bin_info *bin);
-
-/**
- * get_krait_bin_format_b - Populate bin_info from a 'Format B' pte_efuse
- */
-void __init get_krait_bin_format_b(void __iomem *base, struct bin_info *bin);
-
-/**
- * acpuclk_krait_init - Initialize the Krait CPU clock driver give SoC params.
- */
-extern int acpuclk_krait_init(struct device *dev,
- const struct acpuclk_krait_params *params);
-
-#ifdef CONFIG_DEBUG_FS
-/**
- * acpuclk_krait_debug_init - Initialize debugfs interface.
- */
-extern void __init acpuclk_krait_debug_init(struct drv_data *drv);
-#else
-static inline void acpuclk_krait_debug_init(void) { }
-#endif
-
-#endif
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 6281395..b618cd4 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -28,6 +28,7 @@
#include <linux/wakelock.h>
#include <linux/kfifo.h>
#include <linux/of.h>
+#include <linux/srcu.h>
#include <mach/msm_ipc_logging.h>
#include <mach/sps.h>
#include <mach/bam_dmux.h>
@@ -36,19 +37,12 @@
#include <mach/socinfo.h>
#include <mach/subsystem_restart.h>
+#include "bam_dmux_private.h"
+
#define BAM_CH_LOCAL_OPEN 0x1
#define BAM_CH_REMOTE_OPEN 0x2
#define BAM_CH_IN_RESET 0x4
-#define BAM_MUX_HDR_MAGIC_NO 0x33fc
-
-#define BAM_MUX_HDR_CMD_DATA 0
-#define BAM_MUX_HDR_CMD_OPEN 1
-#define BAM_MUX_HDR_CMD_CLOSE 2
-#define BAM_MUX_HDR_CMD_STATUS 3 /* unused */
-#define BAM_MUX_HDR_CMD_OPEN_NO_A2_PC 4
-
-
#define LOW_WATERMARK 2
#define HIGH_WATERMARK 4
#define DEFAULT_POLLING_MIN_SLEEP (950)
@@ -58,20 +52,47 @@
static int msm_bam_dmux_debug_enable;
module_param_named(debug_enable, msm_bam_dmux_debug_enable,
int, S_IRUGO | S_IWUSR | S_IWGRP);
-static int POLLING_MIN_SLEEP = 950;
+static int POLLING_MIN_SLEEP = 2950;
module_param_named(min_sleep, POLLING_MIN_SLEEP,
int, S_IRUGO | S_IWUSR | S_IWGRP);
-static int POLLING_MAX_SLEEP = 1050;
+static int POLLING_MAX_SLEEP = 3050;
module_param_named(max_sleep, POLLING_MAX_SLEEP,
int, S_IRUGO | S_IWUSR | S_IWGRP);
-static int POLLING_INACTIVITY = 40;
+static int POLLING_INACTIVITY = 1;
module_param_named(inactivity, POLLING_INACTIVITY,
int, S_IRUGO | S_IWUSR | S_IWGRP);
-static int bam_adaptive_timer_enabled = 1;
+static int bam_adaptive_timer_enabled;
module_param_named(adaptive_timer_enabled,
bam_adaptive_timer_enabled,
int, S_IRUGO | S_IWUSR | S_IWGRP);
+static struct bam_ops_if bam_default_ops = {
+ /* smsm */
+ .smsm_change_state_ptr = &smsm_change_state,
+ .smsm_get_state_ptr = &smsm_get_state,
+ .smsm_state_cb_register_ptr = &smsm_state_cb_register,
+ .smsm_state_cb_deregister_ptr = &smsm_state_cb_deregister,
+
+ /* sps */
+ .sps_connect_ptr = &sps_connect,
+ .sps_disconnect_ptr = &sps_disconnect,
+ .sps_register_bam_device_ptr = &sps_register_bam_device,
+ .sps_deregister_bam_device_ptr = &sps_deregister_bam_device,
+ .sps_alloc_endpoint_ptr = &sps_alloc_endpoint,
+ .sps_free_endpoint_ptr = &sps_free_endpoint,
+ .sps_set_config_ptr = &sps_set_config,
+ .sps_get_config_ptr = &sps_get_config,
+ .sps_device_reset_ptr = &sps_device_reset,
+ .sps_register_event_ptr = &sps_register_event,
+ .sps_transfer_one_ptr = &sps_transfer_one,
+ .sps_get_iovec_ptr = &sps_get_iovec,
+ .sps_get_unused_desc_num_ptr = &sps_get_unused_desc_num,
+
+ .dma_to = DMA_TO_DEVICE,
+ .dma_from = DMA_FROM_DEVICE,
+};
+static struct bam_ops_if *bam_ops = &bam_default_ops;
+
#if defined(DEBUG)
static uint32_t bam_dmux_read_cnt;
static uint32_t bam_dmux_write_cnt;
@@ -151,29 +172,10 @@
int use_wm;
};
-struct tx_pkt_info {
- struct sk_buff *skb;
- dma_addr_t dma_address;
- char is_cmd;
- uint32_t len;
- struct work_struct work;
- struct list_head list_node;
- unsigned ts_sec;
- unsigned long ts_nsec;
-};
-
-struct rx_pkt_info {
- struct sk_buff *skb;
- dma_addr_t dma_address;
- struct work_struct work;
- struct list_head list_node;
-};
-
#define A2_NUM_PIPES 6
#define A2_SUMMING_THRESHOLD 4096
#define A2_PHYS_BASE 0x124C2000
#define A2_PHYS_SIZE 0x2000
-#define BUFFER_SIZE 2048
#define DEFAULT_NUM_BUFFERS 32
#ifndef A2_BAM_IRQ
@@ -210,26 +212,20 @@
static DEFINE_SPINLOCK(bam_tx_pool_spinlock);
static DEFINE_MUTEX(bam_pdev_mutexlock);
-struct bam_mux_hdr {
- uint16_t magic_num;
- uint8_t reserved;
- uint8_t cmd;
- uint8_t pad_len;
- uint8_t ch_id;
- uint16_t pkt_len;
-};
-
static void notify_all(int event, unsigned long data);
static void bam_mux_write_done(struct work_struct *work);
static void handle_bam_mux_cmd(struct work_struct *work);
static void rx_timer_work_func(struct work_struct *work);
+static void queue_rx_work_func(struct work_struct *work);
static DECLARE_WORK(rx_timer_work, rx_timer_work_func);
-static struct delayed_work queue_rx_work;
+static DECLARE_WORK(queue_rx_work, queue_rx_work_func);
static struct workqueue_struct *bam_mux_rx_workqueue;
static struct workqueue_struct *bam_mux_tx_workqueue;
+static struct srcu_struct bam_dmux_srcu;
+
/* A2 power collaspe */
#define UL_TIMEOUT_DELAY 1000 /* in ms */
#define ENABLE_DISCONNECT_ACK 0x1
@@ -390,7 +386,7 @@
spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
}
-static void queue_rx(void)
+static void __queue_rx(gfp_t alloc_flags)
{
void *ptr;
struct rx_pkt_info *info;
@@ -405,29 +401,29 @@
if (in_global_reset)
goto fail;
- info = kmalloc(sizeof(struct rx_pkt_info),
- GFP_NOWAIT | __GFP_NOWARN);
+ info = kmalloc(sizeof(struct rx_pkt_info), alloc_flags);
if (!info) {
DMUX_LOG_KERR(
- "%s: unable to alloc rx_pkt_info, will retry later\n",
- __func__);
+ "%s: unable to alloc rx_pkt_info w/ flags %x, will retry later\n",
+ __func__,
+ alloc_flags);
goto fail;
}
INIT_WORK(&info->work, handle_bam_mux_cmd);
- info->skb = __dev_alloc_skb(BUFFER_SIZE,
- GFP_NOWAIT | __GFP_NOWARN);
+ info->skb = __dev_alloc_skb(BUFFER_SIZE, alloc_flags);
if (info->skb == NULL) {
DMUX_LOG_KERR(
- "%s: unable to alloc skb, will retry later\n",
- __func__);
+ "%s: unable to alloc skb w/ flags %x, will retry later\n",
+ __func__,
+ alloc_flags);
goto fail_info;
}
ptr = skb_put(info->skb, BUFFER_SIZE);
info->dma_address = dma_map_single(NULL, ptr, BUFFER_SIZE,
- DMA_FROM_DEVICE);
+ bam_ops->dma_from);
if (info->dma_address == 0 || info->dma_address == ~0) {
DMUX_LOG_KERR("%s: dma_map_single failure %p for %p\n",
__func__, (void *)info->dma_address, ptr);
@@ -437,8 +433,8 @@
mutex_lock(&bam_rx_pool_mutexlock);
list_add_tail(&info->list_node, &bam_rx_pool);
rx_len_cached = ++bam_rx_pool_len;
- ret = sps_transfer_one(bam_rx_pipe, info->dma_address,
- BUFFER_SIZE, info, 0);
+ ret = bam_ops->sps_transfer_one_ptr(bam_rx_pipe,
+ info->dma_address, BUFFER_SIZE, info, 0);
if (ret) {
list_del(&info->list_node);
rx_len_cached = --bam_rx_pool_len;
@@ -447,7 +443,7 @@
__func__, ret);
dma_unmap_single(NULL, info->dma_address, BUFFER_SIZE,
- DMA_FROM_DEVICE);
+ bam_ops->dma_from);
goto fail_skb;
}
@@ -463,15 +459,30 @@
kfree(info);
fail:
- if (rx_len_cached == 0 && !in_global_reset) {
+ if (!in_global_reset) {
DMUX_LOG_KERR("%s: rescheduling\n", __func__);
- schedule_delayed_work(&queue_rx_work, msecs_to_jiffies(100));
+ schedule_work(&queue_rx_work);
}
}
+static void queue_rx(void)
+{
+ /*
+ * Hot path. Delays waiting for the allocation to find memory if its
+ * not immediately available, and delays from logging allocation
+ * failures which cannot be tolerated at this time.
+ */
+ __queue_rx(GFP_NOWAIT | __GFP_NOWARN);
+}
+
static void queue_rx_work_func(struct work_struct *work)
{
- queue_rx();
+ /*
+ * Cold path. Delays can be tolerated. Use of GFP_KERNEL should
+ * guarentee the requested memory will be found, after some ammount of
+ * delay.
+ */
+ __queue_rx(GFP_KERNEL);
}
static void bam_mux_process_data(struct sk_buff *rx_skb)
@@ -535,7 +546,8 @@
info = container_of(work, struct rx_pkt_info, work);
rx_skb = info->skb;
- dma_unmap_single(NULL, info->dma_address, BUFFER_SIZE, DMA_FROM_DEVICE);
+ dma_unmap_single(NULL, info->dma_address, BUFFER_SIZE,
+ bam_ops->dma_from);
kfree(info);
rx_hdr = (struct bam_mux_hdr *)rx_skb->data;
@@ -644,7 +656,7 @@
}
dma_address = dma_map_single(NULL, data, len,
- DMA_TO_DEVICE);
+ bam_ops->dma_to);
if (!dma_address) {
pr_err("%s: dma_map_single() failed\n", __func__);
kfree(pkt);
@@ -659,7 +671,7 @@
INIT_WORK(&pkt->work, bam_mux_write_done);
spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
list_add_tail(&pkt->list_node, &bam_tx_pool);
- rc = sps_transfer_one(bam_tx_pipe, dma_address, len,
+ rc = bam_ops->sps_transfer_one_ptr(bam_tx_pipe, dma_address, len,
pkt, SPS_IOVEC_FLAG_EOT);
if (rc) {
DMUX_LOG_KERR("%s sps_transfer_one failed rc=%d\n",
@@ -669,7 +681,7 @@
spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
dma_unmap_single(NULL, pkt->dma_address,
pkt->len,
- DMA_TO_DEVICE);
+ bam_ops->dma_to);
kfree(pkt);
} else {
spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
@@ -746,6 +758,7 @@
struct sk_buff *new_skb = NULL;
dma_addr_t dma_address;
struct tx_pkt_info *pkt;
+ int rcu_id;
if (id >= BAM_DMUX_NUM_CHANNELS)
return -EINVAL;
@@ -754,11 +767,19 @@
if (!bam_mux_initialized)
return -ENODEV;
+ rcu_id = srcu_read_lock(&bam_dmux_srcu);
+ if (in_global_reset) {
+ BAM_DMUX_LOG("%s: In SSR... ch_id[%d]\n", __func__, id);
+ srcu_read_unlock(&bam_dmux_srcu, rcu_id);
+ return -EFAULT;
+ }
+
DBG("%s: writing to ch %d len %d\n", __func__, id, skb->len);
spin_lock_irqsave(&bam_ch[id].lock, flags);
if (!bam_ch_is_open(id)) {
spin_unlock_irqrestore(&bam_ch[id].lock, flags);
pr_err("%s: port not open: %d\n", __func__, bam_ch[id].status);
+ srcu_read_unlock(&bam_dmux_srcu, rcu_id);
return -ENODEV;
}
@@ -766,6 +787,7 @@
(bam_ch[id].num_tx_pkts >= HIGH_WATERMARK)) {
spin_unlock_irqrestore(&bam_ch[id].lock, flags);
pr_err("%s: watermark exceeded: %d\n", __func__, id);
+ srcu_read_unlock(&bam_dmux_srcu, rcu_id);
return -EAGAIN;
}
spin_unlock_irqrestore(&bam_ch[id].lock, flags);
@@ -774,8 +796,10 @@
if (!bam_is_connected) {
read_unlock(&ul_wakeup_lock);
ul_wakeup();
- if (unlikely(in_global_reset == 1))
+ if (unlikely(in_global_reset == 1)) {
+ srcu_read_unlock(&bam_dmux_srcu, rcu_id);
return -EFAULT;
+ }
read_lock(&ul_wakeup_lock);
notify_all(BAM_DMUX_UL_CONNECTED, (unsigned long)(NULL));
}
@@ -820,7 +844,7 @@
}
dma_address = dma_map_single(NULL, skb->data, skb->len,
- DMA_TO_DEVICE);
+ bam_ops->dma_to);
if (!dma_address) {
pr_err("%s: dma_map_single() failed\n", __func__);
goto write_fail3;
@@ -832,7 +856,7 @@
INIT_WORK(&pkt->work, bam_mux_write_done);
spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
list_add_tail(&pkt->list_node, &bam_tx_pool);
- rc = sps_transfer_one(bam_tx_pipe, dma_address, skb->len,
+ rc = bam_ops->sps_transfer_one_ptr(bam_tx_pipe, dma_address, skb->len,
pkt, SPS_IOVEC_FLAG_EOT);
if (rc) {
DMUX_LOG_KERR("%s sps_transfer_one failed rc=%d\n",
@@ -841,7 +865,7 @@
DBG_INC_TX_SPS_FAILURE_CNT();
spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
dma_unmap_single(NULL, pkt->dma_address,
- pkt->skb->len, DMA_TO_DEVICE);
+ pkt->skb->len, bam_ops->dma_to);
kfree(pkt);
if (new_skb)
dev_kfree_skb_any(new_skb);
@@ -853,6 +877,7 @@
}
ul_packet_written = 1;
read_unlock(&ul_wakeup_lock);
+ srcu_read_unlock(&bam_dmux_srcu, rcu_id);
return rc;
write_fail3:
@@ -863,6 +888,7 @@
dev_kfree_skb_any(new_skb);
write_fail:
read_unlock(&ul_wakeup_lock);
+ srcu_read_unlock(&bam_dmux_srcu, rcu_id);
return -ENOMEM;
}
@@ -1049,14 +1075,14 @@
* Attempt to enable interrupts - if this fails,
* continue polling and we will retry later.
*/
- ret = sps_get_config(bam_rx_pipe, &cur_rx_conn);
+ ret = bam_ops->sps_get_config_ptr(bam_rx_pipe, &cur_rx_conn);
if (ret) {
pr_err("%s: sps_get_config() failed %d\n", __func__, ret);
goto fail;
}
rx_register_event.options = SPS_O_EOT;
- ret = sps_register_event(bam_rx_pipe, &rx_register_event);
+ ret = bam_ops->sps_register_event_ptr(bam_rx_pipe, &rx_register_event);
if (ret) {
pr_err("%s: sps_register_event() failed %d\n", __func__, ret);
goto fail;
@@ -1064,7 +1090,7 @@
cur_rx_conn.options = SPS_O_AUTO_ENABLE |
SPS_O_EOT | SPS_O_ACK_TRANSFERS;
- ret = sps_set_config(bam_rx_pipe, &cur_rx_conn);
+ ret = bam_ops->sps_set_config_ptr(bam_rx_pipe, &cur_rx_conn);
if (ret) {
pr_err("%s: sps_set_config() failed %d\n", __func__, ret);
goto fail;
@@ -1075,7 +1101,7 @@
/* handle any rx packets before interrupt was enabled */
while (bam_connection_is_active && !polling_mode) {
- ret = sps_get_iovec(bam_rx_pipe, &iov);
+ ret = bam_ops->sps_get_iovec_ptr(bam_rx_pipe, &iov);
if (ret) {
pr_err("%s: sps_get_iovec failed %d\n",
__func__, ret);
@@ -1160,7 +1186,7 @@
return;
}
- ret = sps_get_iovec(bam_rx_pipe, &iov);
+ ret = bam_ops->sps_get_iovec_ptr(bam_rx_pipe, &iov);
if (ret) {
DMUX_LOG_KERR("%s: sps_get_iovec failed %d\n",
__func__, ret);
@@ -1209,7 +1235,7 @@
if (bam_adaptive_timer_enabled) {
usleep_range(rx_timer_interval, rx_timer_interval + 50);
- ret = sps_get_unused_desc_num(bam_rx_pipe,
+ ret = bam_ops->sps_get_unused_desc_num_ptr(bam_rx_pipe,
&buffs_unused);
if (ret) {
@@ -1261,11 +1287,11 @@
if (!pkt->is_cmd)
dma_unmap_single(NULL, pkt->dma_address,
pkt->skb->len,
- DMA_TO_DEVICE);
+ bam_ops->dma_to);
else
dma_unmap_single(NULL, pkt->dma_address,
pkt->len,
- DMA_TO_DEVICE);
+ bam_ops->dma_to);
queue_work(bam_mux_tx_workqueue, &pkt->work);
break;
default:
@@ -1288,7 +1314,8 @@
case SPS_EVENT_EOT:
/* attempt to disable interrupts in this pipe */
if (!polling_mode) {
- ret = sps_get_config(bam_rx_pipe, &cur_rx_conn);
+ ret = bam_ops->sps_get_config_ptr(bam_rx_pipe,
+ &cur_rx_conn);
if (ret) {
pr_err("%s: sps_get_config() failed %d, interrupts"
" not disabled\n", __func__, ret);
@@ -1296,7 +1323,8 @@
}
cur_rx_conn.options = SPS_O_AUTO_ENABLE |
SPS_O_ACK_TRANSFERS | SPS_O_POLL;
- ret = sps_set_config(bam_rx_pipe, &cur_rx_conn);
+ ret = bam_ops->sps_set_config_ptr(bam_rx_pipe,
+ &cur_rx_conn);
if (ret) {
pr_err("%s: sps_set_config() failed %d, interrupts"
" not disabled\n", __func__, ret);
@@ -1476,9 +1504,11 @@
bam_dmux_uplink_vote = vote;
if (vote)
- smsm_change_state(SMSM_APPS_STATE, 0, SMSM_A2_POWER_CONTROL);
+ bam_ops->smsm_change_state_ptr(SMSM_APPS_STATE,
+ 0, SMSM_A2_POWER_CONTROL);
else
- smsm_change_state(SMSM_APPS_STATE, SMSM_A2_POWER_CONTROL, 0);
+ bam_ops->smsm_change_state_ptr(SMSM_APPS_STATE,
+ SMSM_A2_POWER_CONTROL, 0);
}
/*
@@ -1747,29 +1777,31 @@
if (!power_management_only_mode) {
if (ssr_skipped_disconnect) {
/* delayed to here to prevent bus stall */
- sps_disconnect(bam_tx_pipe);
- sps_disconnect(bam_rx_pipe);
+ bam_ops->sps_disconnect_ptr(bam_tx_pipe);
+ bam_ops->sps_disconnect_ptr(bam_rx_pipe);
__memzero(rx_desc_mem_buf.base, rx_desc_mem_buf.size);
__memzero(tx_desc_mem_buf.base, tx_desc_mem_buf.size);
}
ssr_skipped_disconnect = 0;
- i = sps_device_reset(a2_device_handle);
+ i = bam_ops->sps_device_reset_ptr(a2_device_handle);
if (i)
pr_err("%s: device reset failed rc = %d\n", __func__,
i);
- i = sps_connect(bam_tx_pipe, &tx_connection);
+ i = bam_ops->sps_connect_ptr(bam_tx_pipe, &tx_connection);
if (i)
pr_err("%s: tx connection failed rc = %d\n", __func__,
i);
- i = sps_connect(bam_rx_pipe, &rx_connection);
+ i = bam_ops->sps_connect_ptr(bam_rx_pipe, &rx_connection);
if (i)
pr_err("%s: rx connection failed rc = %d\n", __func__,
i);
- i = sps_register_event(bam_tx_pipe, &tx_register_event);
+ i = bam_ops->sps_register_event_ptr(bam_tx_pipe,
+ &tx_register_event);
if (i)
pr_err("%s: tx event reg failed rc = %d\n", __func__,
i);
- i = sps_register_event(bam_rx_pipe, &rx_register_event);
+ i = bam_ops->sps_register_event_ptr(bam_rx_pipe,
+ &rx_register_event);
if (i)
pr_err("%s: rx event reg failed rc = %d\n", __func__,
i);
@@ -1823,9 +1855,9 @@
if (!power_management_only_mode) {
if (likely(!in_ssr)) {
BAM_DMUX_LOG("%s: disconnect tx\n", __func__);
- sps_disconnect(bam_tx_pipe);
+ bam_ops->sps_disconnect_ptr(bam_tx_pipe);
BAM_DMUX_LOG("%s: disconnect rx\n", __func__);
- sps_disconnect(bam_rx_pipe);
+ bam_ops->sps_disconnect_ptr(bam_rx_pipe);
__memzero(rx_desc_mem_buf.base, rx_desc_mem_buf.size);
__memzero(tx_desc_mem_buf.base, tx_desc_mem_buf.size);
BAM_DMUX_LOG("%s: device reset\n", __func__);
@@ -1842,7 +1874,7 @@
list_del(node);
info = container_of(node, struct rx_pkt_info, list_node);
dma_unmap_single(NULL, info->dma_address, BUFFER_SIZE,
- DMA_FROM_DEVICE);
+ bam_ops->dma_from);
dev_kfree_skb_any(info->skb);
kfree(info);
}
@@ -1957,9 +1989,12 @@
* because a watchdog crash from a bus stall would likely occur.
*/
if (code == SUBSYS_BEFORE_SHUTDOWN) {
+ BAM_DMUX_LOG("%s: begin\n", __func__);
in_global_reset = 1;
in_ssr = 1;
- BAM_DMUX_LOG("%s: begin\n", __func__);
+ /* wait till all bam_dmux writes completes */
+ synchronize_srcu(&bam_dmux_srcu);
+ BAM_DMUX_LOG("%s: ssr signaling complete\n", __func__);
flush_workqueue(bam_mux_rx_workqueue);
}
if (code != SUBSYS_AFTER_SHUTDOWN)
@@ -2008,12 +2043,12 @@
if (!info->is_cmd) {
dma_unmap_single(NULL, info->dma_address,
info->skb->len,
- DMA_TO_DEVICE);
+ bam_ops->dma_to);
dev_kfree_skb_any(info->skb);
} else {
dma_unmap_single(NULL, info->dma_address,
info->len,
- DMA_TO_DEVICE);
+ bam_ops->dma_to);
kfree(info->skb);
}
kfree(info);
@@ -2053,20 +2088,20 @@
if (cpu_is_msm9615() || satellite_mode)
a2_props.manage = SPS_BAM_MGR_DEVICE_REMOTE;
/* need to free on tear down */
- ret = sps_register_bam_device(&a2_props, &h);
+ ret = bam_ops->sps_register_bam_device_ptr(&a2_props, &h);
if (ret < 0) {
pr_err("%s: register bam error %d\n", __func__, ret);
goto register_bam_failed;
}
a2_device_handle = h;
- bam_tx_pipe = sps_alloc_endpoint();
+ bam_tx_pipe = bam_ops->sps_alloc_endpoint_ptr();
if (bam_tx_pipe == NULL) {
pr_err("%s: tx alloc endpoint failed\n", __func__);
ret = -ENOMEM;
goto tx_alloc_endpoint_failed;
}
- ret = sps_get_config(bam_tx_pipe, &tx_connection);
+ ret = bam_ops->sps_get_config_ptr(bam_tx_pipe, &tx_connection);
if (ret) {
pr_err("%s: tx get config failed %d\n", __func__, ret);
goto tx_get_config_failed;
@@ -2091,19 +2126,19 @@
tx_connection.desc = tx_desc_mem_buf;
tx_connection.event_thresh = 0x10;
- ret = sps_connect(bam_tx_pipe, &tx_connection);
+ ret = bam_ops->sps_connect_ptr(bam_tx_pipe, &tx_connection);
if (ret < 0) {
pr_err("%s: tx connect error %d\n", __func__, ret);
goto tx_connect_failed;
}
- bam_rx_pipe = sps_alloc_endpoint();
+ bam_rx_pipe = bam_ops->sps_alloc_endpoint_ptr();
if (bam_rx_pipe == NULL) {
pr_err("%s: rx alloc endpoint failed\n", __func__);
ret = -ENOMEM;
goto rx_alloc_endpoint_failed;
}
- ret = sps_get_config(bam_rx_pipe, &rx_connection);
+ ret = bam_ops->sps_get_config_ptr(bam_rx_pipe, &rx_connection);
if (ret) {
pr_err("%s: rx get config failed %d\n", __func__, ret);
goto rx_get_config_failed;
@@ -2129,7 +2164,7 @@
rx_connection.desc = rx_desc_mem_buf;
rx_connection.event_thresh = 0x10;
- ret = sps_connect(bam_rx_pipe, &rx_connection);
+ ret = bam_ops->sps_connect_ptr(bam_rx_pipe, &rx_connection);
if (ret < 0) {
pr_err("%s: rx connect error %d\n", __func__, ret);
goto rx_connect_failed;
@@ -2140,7 +2175,7 @@
tx_register_event.xfer_done = NULL;
tx_register_event.callback = bam_mux_tx_notify;
tx_register_event.user = NULL;
- ret = sps_register_event(bam_tx_pipe, &tx_register_event);
+ ret = bam_ops->sps_register_event_ptr(bam_tx_pipe, &tx_register_event);
if (ret < 0) {
pr_err("%s: tx register event error %d\n", __func__, ret);
goto rx_event_reg_failed;
@@ -2151,7 +2186,7 @@
rx_register_event.xfer_done = NULL;
rx_register_event.callback = bam_mux_rx_notify;
rx_register_event.user = NULL;
- ret = sps_register_event(bam_rx_pipe, &rx_register_event);
+ ret = bam_ops->sps_register_event_ptr(bam_rx_pipe, &rx_register_event);
if (ret < 0) {
pr_err("%s: tx register event error %d\n", __func__, ret);
goto rx_event_reg_failed;
@@ -2171,22 +2206,22 @@
return 0;
rx_event_reg_failed:
- sps_disconnect(bam_rx_pipe);
+ bam_ops->sps_disconnect_ptr(bam_rx_pipe);
rx_connect_failed:
dma_free_coherent(NULL, rx_desc_mem_buf.size, rx_desc_mem_buf.base,
rx_desc_mem_buf.phys_base);
rx_mem_failed:
rx_get_config_failed:
- sps_free_endpoint(bam_rx_pipe);
+ bam_ops->sps_free_endpoint_ptr(bam_rx_pipe);
rx_alloc_endpoint_failed:
- sps_disconnect(bam_tx_pipe);
+ bam_ops->sps_disconnect_ptr(bam_tx_pipe);
tx_connect_failed:
dma_free_coherent(NULL, tx_desc_mem_buf.size, tx_desc_mem_buf.base,
tx_desc_mem_buf.phys_base);
tx_get_config_failed:
- sps_free_endpoint(bam_tx_pipe);
+ bam_ops->sps_free_endpoint_ptr(bam_tx_pipe);
tx_alloc_endpoint_failed:
- sps_deregister_bam_device(h);
+ bam_ops->sps_deregister_bam_device_ptr(h);
/*
* sps_deregister_bam_device() calls iounmap. calling iounmap on the
* same handle below will cause a crash, so skip it if we've freed
@@ -2224,7 +2259,7 @@
a2_props.summing_threshold = A2_SUMMING_THRESHOLD;
if (cpu_is_msm9615() || satellite_mode)
a2_props.manage = SPS_BAM_MGR_DEVICE_REMOTE;
- ret = sps_register_bam_device(&a2_props, &h);
+ ret = bam_ops->sps_register_bam_device_ptr(&a2_props, &h);
if (ret < 0) {
pr_err("%s: register bam error %d\n", __func__, ret);
goto register_bam_failed;
@@ -2276,7 +2311,7 @@
BAM_DMUX_LOG("%s: apps ack %d->%d\n", __func__,
clear_bit & 0x1, ~clear_bit & 0x1);
- smsm_change_state(SMSM_APPS_STATE,
+ bam_ops->smsm_change_state_ptr(SMSM_APPS_STATE,
clear_bit & SMSM_A2_POWER_CONTROL_ACK,
~clear_bit & SMSM_A2_POWER_CONTROL_ACK);
clear_bit = ~clear_bit;
@@ -2333,6 +2368,51 @@
complete_all(&ul_wakeup_ack_completion);
}
+/**
+ * msm_bam_dmux_set_bam_ops() - sets the bam_ops
+ * @ops: bam_ops_if to set
+ *
+ * Sets bam_ops to allow switching of runtime behavior. Preconditon, bam dmux
+ * must be in an idle state. If input ops is NULL, then bam_ops will be
+ * restored to their default state.
+ */
+void msm_bam_dmux_set_bam_ops(struct bam_ops_if *ops)
+{
+ if (ops != NULL)
+ bam_ops = ops;
+ else
+ bam_ops = &bam_default_ops;
+}
+EXPORT_SYMBOL(msm_bam_dmux_set_bam_ops);
+
+/**
+ * msm_bam_dmux_deinit() - puts bam dmux into a deinited state
+ *
+ * Puts bam dmux into a deinitialized state by simulating an ssr.
+ */
+void msm_bam_dmux_deinit(void)
+{
+ restart_notifier_cb(NULL, SUBSYS_BEFORE_SHUTDOWN, NULL);
+ restart_notifier_cb(NULL, SUBSYS_AFTER_SHUTDOWN, NULL);
+}
+EXPORT_SYMBOL(msm_bam_dmux_deinit);
+
+/**
+ * msm_bam_dmux_reinit() - reinitializes bam dmux
+ */
+void msm_bam_dmux_reinit(void)
+{
+ bam_ops->smsm_state_cb_register_ptr(SMSM_MODEM_STATE,
+ SMSM_A2_POWER_CONTROL,
+ bam_dmux_smsm_cb, NULL);
+ bam_ops->smsm_state_cb_register_ptr(SMSM_MODEM_STATE,
+ SMSM_A2_POWER_CONTROL_ACK,
+ bam_dmux_smsm_ack_cb, NULL);
+ bam_mux_initialized = 0;
+ bam_init();
+}
+EXPORT_SYMBOL(msm_bam_dmux_reinit);
+
static int bam_dmux_probe(struct platform_device *pdev)
{
int rc;
@@ -2432,11 +2512,12 @@
init_completion(&shutdown_completion);
complete_all(&shutdown_completion);
INIT_DELAYED_WORK(&ul_timeout_work, ul_timeout);
- INIT_DELAYED_WORK(&queue_rx_work, queue_rx_work_func);
wake_lock_init(&bam_wakelock, WAKE_LOCK_SUSPEND, "bam_dmux_wakelock");
+ init_srcu_struct(&bam_dmux_srcu);
- rc = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_A2_POWER_CONTROL,
- bam_dmux_smsm_cb, NULL);
+ rc = bam_ops->smsm_state_cb_register_ptr(SMSM_MODEM_STATE,
+ SMSM_A2_POWER_CONTROL,
+ bam_dmux_smsm_cb, NULL);
if (rc) {
destroy_workqueue(bam_mux_rx_workqueue);
@@ -2445,13 +2526,14 @@
return -ENOMEM;
}
- rc = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_A2_POWER_CONTROL_ACK,
- bam_dmux_smsm_ack_cb, NULL);
+ rc = bam_ops->smsm_state_cb_register_ptr(SMSM_MODEM_STATE,
+ SMSM_A2_POWER_CONTROL_ACK,
+ bam_dmux_smsm_ack_cb, NULL);
if (rc) {
destroy_workqueue(bam_mux_rx_workqueue);
destroy_workqueue(bam_mux_tx_workqueue);
- smsm_state_cb_deregister(SMSM_MODEM_STATE,
+ bam_ops->smsm_state_cb_deregister_ptr(SMSM_MODEM_STATE,
SMSM_A2_POWER_CONTROL,
bam_dmux_smsm_cb, NULL);
pr_err("%s: smsm ack cb register failed, rc: %d\n", __func__,
@@ -2461,8 +2543,10 @@
return -ENOMEM;
}
- if (smsm_get_state(SMSM_MODEM_STATE) & SMSM_A2_POWER_CONTROL)
- bam_dmux_smsm_cb(NULL, 0, smsm_get_state(SMSM_MODEM_STATE));
+ if (bam_ops->smsm_get_state_ptr(SMSM_MODEM_STATE) &
+ SMSM_A2_POWER_CONTROL)
+ bam_dmux_smsm_cb(NULL, 0,
+ bam_ops->smsm_get_state_ptr(SMSM_MODEM_STATE));
return 0;
}
diff --git a/arch/arm/mach-msm/bam_dmux_private.h b/arch/arm/mach-msm/bam_dmux_private.h
new file mode 100644
index 0000000..871dd64
--- /dev/null
+++ b/arch/arm/mach-msm/bam_dmux_private.h
@@ -0,0 +1,173 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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 _BAM_DMUX_PRIVATE_H
+#define _BAM_DMUX_PRIVATE_H
+
+#include <linux/types.h>
+#include <linux/dma-mapping.h>
+
+#include <mach/sps.h>
+
+#define BAM_MUX_HDR_MAGIC_NO 0x33fc
+#define BAM_MUX_HDR_CMD_DATA 0
+#define BAM_MUX_HDR_CMD_OPEN 1
+#define BAM_MUX_HDR_CMD_CLOSE 2
+#define BAM_MUX_HDR_CMD_STATUS 3 /* unused */
+#define BAM_MUX_HDR_CMD_OPEN_NO_A2_PC 4
+#define BUFFER_SIZE 2048
+
+/**
+ * struct bam_ops_if - collection of function pointers to allow swappable
+ * runtime functionality
+ * @smsm_change_state_ptr: pointer to smsm_change_state function
+ * @smsm_get_state_ptr: pointer to smsm_get_state function
+ * @smsm_state_cb_register_ptr: pointer to smsm_state_cb_register function
+ * @smsm_state_cb_deregister_ptr: pointer to smsm_state_cb_deregister function
+ * @sps_connect_ptr: pointer to sps_connect function
+ * @sps_disconnect_ptr: pointer to sps_disconnect function
+ * @sps_register_bam_device_ptr: pointer to sps_register_bam_device
+ * @sps_deregister_bam_device_ptr: pointer to sps_deregister_bam_device
+ * function
+ * @sps_alloc_endpoint_ptr: pointer to sps_alloc_endpoint function
+ * @sps_free_endpoint_ptr: pointer to sps_free_endpoint function
+ * @sps_set_config_ptr: pointer to sps_set_config function
+ * @sps_get_config_ptr: pointer to sps_get_config function
+ * @sps_device_reset_ptr: pointer to sps_device_reset function
+ * @sps_register_event_ptr: pointer to sps_register_event function
+ * @sps_transfer_one_ptr: pointer to sps_transfer_one function
+ * @sps_get_iovec_ptr: pointer to sps_get_iovec function
+ * @sps_get_unused_desc_num_ptr: pointer to sps_get_unused_desc_num function
+ * @dma_to: enum for the direction of dma operations to device
+ * @dma_from: enum for the direction of dma operations from device
+ *
+ * This struct contains the interface from bam_dmux to smsm and sps. The
+ * pointers can be swapped out at run time to provide different functionality.
+ */
+struct bam_ops_if {
+ /* smsm */
+ int (*smsm_change_state_ptr)(uint32_t smsm_entry,
+ uint32_t clear_mask, uint32_t set_mask);
+
+ uint32_t (*smsm_get_state_ptr)(uint32_t smsm_entry);
+
+ int (*smsm_state_cb_register_ptr)(uint32_t smsm_entry, uint32_t mask,
+ void (*notify)(void *, uint32_t old_state, uint32_t new_state),
+ void *data);
+
+ int (*smsm_state_cb_deregister_ptr)(uint32_t smsm_entry, uint32_t mask,
+ void (*notify)(void *, uint32_t, uint32_t), void *data);
+
+ /* sps */
+ int (*sps_connect_ptr)(struct sps_pipe *h, struct sps_connect *connect);
+
+ int (*sps_disconnect_ptr)(struct sps_pipe *h);
+
+ int (*sps_register_bam_device_ptr)(
+ const struct sps_bam_props *bam_props,
+ u32 *dev_handle);
+
+ int (*sps_deregister_bam_device_ptr)(u32 dev_handle);
+
+ struct sps_pipe *(*sps_alloc_endpoint_ptr)(void);
+
+ int (*sps_free_endpoint_ptr)(struct sps_pipe *h);
+
+ int (*sps_set_config_ptr)(struct sps_pipe *h,
+ struct sps_connect *config);
+
+ int (*sps_get_config_ptr)(struct sps_pipe *h,
+ struct sps_connect *config);
+
+ int (*sps_device_reset_ptr)(u32 dev);
+
+ int (*sps_register_event_ptr)(struct sps_pipe *h,
+ struct sps_register_event *reg);
+
+ int (*sps_transfer_one_ptr)(struct sps_pipe *h,
+ u32 addr, u32 size,
+ void *user, u32 flags);
+
+ int (*sps_get_iovec_ptr)(struct sps_pipe *h,
+ struct sps_iovec *iovec);
+
+ int (*sps_get_unused_desc_num_ptr)(struct sps_pipe *h,
+ u32 *desc_num);
+
+ enum dma_data_direction dma_to;
+
+ enum dma_data_direction dma_from;
+};
+
+/**
+ * struct bam_mux_hdr - struct which contains bam dmux header info
+ * @magic_num: magic number placed at start to ensure that it is actually a
+ * valid bam dmux header
+ * @reserved: for later use
+ * @cmd: the command
+ * @pad_len: the length of padding
+ * @ch_id: the id of the bam dmux channel that this is sent on
+ * @pkt_len: the length of the packet that this is the header of
+ */
+struct bam_mux_hdr {
+ uint16_t magic_num;
+ uint8_t reserved;
+ uint8_t cmd;
+ uint8_t pad_len;
+ uint8_t ch_id;
+ uint16_t pkt_len;
+};
+
+/**
+ * struct rx_pkt_info - struct describing an rx packet
+ * @skb: socket buffer containing the packet
+ * @dma_address: dma mapped address of the packet
+ * @work: work_struct for processing the packet
+ * @list_node: list_head for placing this on a list
+ */
+struct rx_pkt_info {
+ struct sk_buff *skb;
+ dma_addr_t dma_address;
+ struct work_struct work;
+ struct list_head list_node;
+};
+
+/**
+ * struct tx_pkt_info - struct describing a tx packet
+ * @skb: socket buffer containing the packet
+ * @dma_address: dma mapped address of the packet
+ * @is_cmd: signifies whether this is a command or data packet
+ * @len: length og the packet
+ * @work: work_struct for processing this packet
+ * @list_node: list_head for placing this on a list
+ * @ts_sec: seconds portion of the timestamp
+ * @ts_nsec: nanoseconds portion of the timestamp
+ *
+ */
+struct tx_pkt_info {
+ struct sk_buff *skb;
+ dma_addr_t dma_address;
+ char is_cmd;
+ uint32_t len;
+ struct work_struct work;
+ struct list_head list_node;
+ unsigned ts_sec;
+ unsigned long ts_nsec;
+};
+
+void msm_bam_dmux_set_bam_ops(struct bam_ops_if *ops);
+
+void msm_bam_dmux_deinit(void);
+
+void msm_bam_dmux_reinit(void);
+
+#endif /* _BAM_DMUX_PRIVATE_H */
diff --git a/arch/arm/mach-msm/board-8226-gpiomux.c b/arch/arm/mach-msm/board-8226-gpiomux.c
index 4dcbc3a..9767746 100644
--- a/arch/arm/mach-msm/board-8226-gpiomux.c
+++ b/arch/arm/mach-msm/board-8226-gpiomux.c
@@ -185,7 +185,14 @@
static struct msm_gpiomux_config msm_lcd_configs[] __initdata = {
{
- .gpio = 25,
+ .gpio = 25, /* LCD Reset */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &lcd_rst_act_cfg,
+ [GPIOMUX_SUSPENDED] = &lcd_rst_sus_cfg,
+ },
+ },
+ {
+ .gpio = 109, /* LCD Enable */
.settings = {
[GPIOMUX_ACTIVE] = &lcd_rst_act_cfg,
[GPIOMUX_SUSPENDED] = &lcd_rst_sus_cfg,
@@ -303,13 +310,13 @@
static struct gpiomux_setting goodix_ldo_en_sus_cfg = {
.func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_6MA,
- .pull = GPIOMUX_PULL_UP,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
};
static struct gpiomux_setting goodix_int_act_cfg = {
.func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_8MA,
+ .drv = GPIOMUX_DRV_6MA,
.pull = GPIOMUX_PULL_UP,
};
@@ -321,14 +328,14 @@
static struct gpiomux_setting goodix_reset_act_cfg = {
.func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_8MA,
+ .drv = GPIOMUX_DRV_6MA,
.pull = GPIOMUX_PULL_UP,
};
static struct gpiomux_setting goodix_reset_sus_cfg = {
.func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_8MA,
- .pull = GPIOMUX_PULL_UP,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
};
static struct msm_gpiomux_config msm_skuf_blsp_configs[] __initdata = {
diff --git a/arch/arm/mach-msm/board-8226.c b/arch/arm/mach-msm/board-8226.c
index aff2d75..5244918 100644
--- a/arch/arm/mach-msm/board-8226.c
+++ b/arch/arm/mach-msm/board-8226.c
@@ -82,6 +82,8 @@
"msm_sdcc.2", NULL),
OF_DEV_AUXDATA("qcom,sdhci-msm", 0xF9864900, \
"msm_sdcc.3", NULL),
+ OF_DEV_AUXDATA("qcom,hsic-host", 0xF9A00000, "msm_hsic_host", NULL),
+
{}
};
diff --git a/arch/arm/mach-msm/board-8610-gpiomux.c b/arch/arm/mach-msm/board-8610-gpiomux.c
index b5ea3a5..affe6bd 100644
--- a/arch/arm/mach-msm/board-8610-gpiomux.c
+++ b/arch/arm/mach-msm/board-8610-gpiomux.c
@@ -252,6 +252,30 @@
},
};
+static struct gpiomux_setting gpio_i2c_nfc_pvt_config = {
+ .func = GPIOMUX_FUNC_5, /*active 1*/ /* 0 */
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+ };
+
+static struct msm_gpiomux_config msm_nfc_configs[] __initdata = {
+ {
+ .gpio = 8, /* BLSP1 QUP2 I2C_SDA */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &gpio_i2c_nfc_pvt_config,
+ [GPIOMUX_SUSPENDED] = &gpio_i2c_nfc_pvt_config,
+ },
+ },
+ {
+ .gpio = 9, /* BLSP1 QUP2 I2C_SCL */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &gpio_i2c_nfc_pvt_config,
+ [GPIOMUX_SUSPENDED] = &gpio_i2c_nfc_pvt_config,
+ },
+ },
+};
+
+
static struct msm_gpiomux_config msm_atmel_configs[] __initdata = {
{
.gpio = 0, /* TOUCH RESET */
@@ -427,6 +451,16 @@
},
};
+static struct msm_gpiomux_config msm_non_qrd_configs[] __initdata = {
+ {
+ .gpio = 8, /* CAM1_STANDBY_N */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[3],
+ [GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
+ },
+ },
+};
+
static struct msm_gpiomux_config msm_sensor_configs[] __initdata = {
{
.gpio = 13, /* CAM_MCLK0 */
@@ -597,6 +631,28 @@
},
};
+static struct gpiomux_setting gpio_cdc_dmic_cfg = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_4MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+
+static struct msm_gpiomux_config msm_cdc_dmic_configs[] __initdata = {
+ {
+ .gpio = 100, /* DMIC CLK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_cdc_dmic_cfg,
+ },
+ },
+ {
+ .gpio = 101, /* DMIC DATA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_cdc_dmic_cfg,
+ },
+ },
+};
+
void __init msm8610_init_gpiomux(void)
{
int rc;
@@ -625,7 +681,16 @@
msm_gpiomux_install(msm_sensor_configs, ARRAY_SIZE(msm_sensor_configs));
msm_gpiomux_install(msm_gpio_int_configs,
ARRAY_SIZE(msm_gpio_int_configs));
- if (of_board_is_qrd())
+ if (of_board_is_qrd()) {
msm_gpiomux_install(msm_interrupt_configs,
ARRAY_SIZE(msm_interrupt_configs));
+ msm_gpiomux_install(msm_nfc_configs,
+ ARRAY_SIZE(msm_nfc_configs));
+ } else {
+ msm_gpiomux_install(msm_non_qrd_configs,
+ ARRAY_SIZE(msm_non_qrd_configs));
+ }
+ if (of_board_is_cdp())
+ msm_gpiomux_install(msm_cdc_dmic_configs,
+ ARRAY_SIZE(msm_cdc_dmic_configs));
}
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index d79464a..2050f38 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -98,7 +98,6 @@
#include "pm-boot.h"
#include "msm_watchdog.h"
#include "board-8930.h"
-#include "acpuclock-krait.h"
#include "platsmp.h"
static struct platform_device msm_fm_platform_init = {
@@ -2655,8 +2654,6 @@
/* Modify platform data values to match requirements for PM8917. */
static void __init msm8930_pm8917_pdata_fixup(void)
{
- struct acpuclk_platform_data *pdata;
-
msm8930_pm8917_wcd9xxx_pdata_fixup(&sitar_platform_data);
msm8930_pm8917_wcd9xxx_pdata_fixup(&sitar1p1_platform_data);
@@ -2672,12 +2669,6 @@
msm8930_device_rpm_regulator.dev.platform_data
= &msm8930_pm8917_rpm_regulator_pdata;
-
- pdata = msm8930_device_acpuclk.dev.platform_data;
- pdata->uses_pm8917 = true;
-
- pdata = msm8930ab_device_acpuclk.dev.platform_data;
- pdata->uses_pm8917 = true;
}
static void __init msm8930ab_update_retention_spm(void)
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
old mode 100644
new mode 100755
index c35a607..8ab916c
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -640,6 +640,18 @@
[GPIOMUX_SUSPENDED] = &gpio_uart_config,
},
},
+ { /* NFC */
+ .gpio = 29, /* BLSP1 QUP6 I2C_DAT */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+ },
+ },
+ { /* NFC */
+ .gpio = 30, /* BLSP1 QUP6 I2C_CLK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+ },
+ },
{
.gpio = 53, /* BLSP2 QUP4 SPI_DATA_MOSI */
.settings = {
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index 80a957f..7b13bbc 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -108,6 +108,11 @@
msm_thermal_device_init();
}
+static struct of_dev_auxdata msm_hsic_host_adata[] = {
+ OF_DEV_AUXDATA("qcom,hsic-host", 0xF9A00000, "msm_hsic_host", NULL),
+ {}
+};
+
static struct of_dev_auxdata msm8974_auxdata_lookup[] __initdata = {
OF_DEV_AUXDATA("qcom,hsusb-otg", 0xF9A55000, \
"msm_otg", NULL),
@@ -148,6 +153,8 @@
"qcrypto.0", NULL),
OF_DEV_AUXDATA("qcom,hsic-host", 0xF9A00000, \
"msm_hsic_host", NULL),
+ OF_DEV_AUXDATA("qcom,hsic-smsc-hub", 0, "msm_smsc_hub",
+ msm_hsic_host_adata),
{}
};
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index a883e39..3c5ddc5 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -694,6 +694,7 @@
F_GCC( 56000000, gpll0, 1, 7, 75),
F_GCC( 58982400, gpll0, 1, 1536, 15625),
F_GCC( 60000000, gpll0, 10, 0, 0),
+ F_GCC( 63160000, gpll0, 9.5, 0, 0),
F_END
};
@@ -1278,6 +1279,7 @@
.en_mask = BIT(5),
.base = &virt_bases[GCC_BASE],
.c = {
+ .parent = &ce1_clk_src.c,
.dbg_name = "gcc_ce1_clk",
.ops = &clk_ops_vote,
CLK_INIT(gcc_ce1_clk.c),
@@ -3163,6 +3165,8 @@
CLK_LOOKUP("xo", xo_a_clk.c, "f9011050.qcom,acpuclk"),
CLK_LOOKUP("gpll0", gpll0_ao.c, "f9011050.qcom,acpuclk"),
CLK_LOOKUP("a7sspll", a7sspll.c, "f9011050.qcom,acpuclk"),
+ CLK_LOOKUP("clk-4", gpll0_ao.c, "f9011050.qcom,clock-a7"),
+ CLK_LOOKUP("clk-5", a7sspll.c, "f9011050.qcom,clock-a7"),
CLK_LOOKUP("kpss_ahb", kpss_ahb_clk_src.c, ""),
/* WCNSS CLOCKS */
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index 45a6b89..c7bf92c 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -24,6 +24,7 @@
#include <mach/rpm-regulator-smd.h>
#include <mach/socinfo.h>
#include <mach/rpm-smd.h>
+#include <mach/clock-generic.h>
#include "clock-local2.h"
#include "clock-pll.h"
@@ -676,6 +677,7 @@
F( 960000, gcc_xo, 10, 1, 2),
F( 4800000, gcc_xo, 4, 0, 0),
F( 9600000, gcc_xo, 2, 0, 0),
+ F(12000000, gpll0, 10, 1, 5),
F(15000000, gpll0, 10, 1, 4),
F(19200000, gcc_xo, 1, 0, 0),
F(25000000, gpll0, 12, 1, 2),
@@ -782,6 +784,7 @@
F(56000000, gpll0, 1, 7, 75),
F(58982400, gpll0, 1, 1536, 15625),
F(60000000, gpll0, 10, 0, 0),
+ F(63160000, gpll0, 9.5, 0, 0),
F_END,
};
@@ -1283,6 +1286,7 @@
.en_mask = BIT(5),
.base = &virt_bases[GCC_BASE],
.c = {
+ .parent = &ce1_clk_src.c,
.dbg_name = "gcc_ce1_clk",
.ops = &clk_ops_vote,
CLK_INIT(gcc_ce1_clk.c),
@@ -2018,111 +2022,111 @@
},
};
-static struct cam_mux_clk csi0phy_cam_mux_clk = {
- .enable_reg = MMSS_CAMSS_MISC,
- .enable_mask = BIT(11),
- .select_reg = MMSS_CAMSS_MISC,
- .select_mask = BIT(9),
- .sources = (struct mux_source[]) {
- { &csi0phy_clk.c, 0 },
- { &csi1phy_clk.c, BIT(9) },
- { 0 },
- },
+static struct mux_clk csi0phy_cam_mux_clk = {
+ .ops = &mux_reg_ops,
+ .en_mask = BIT(11),
+ .mask = 0x1,
+ .shift = 9,
+ .offset = MMSS_CAMSS_MISC,
+ MUX_SRC_LIST(
+ { &csi0phy_clk.c, 0 },
+ { &csi1phy_clk.c, 1 },
+ ),
.base = &virt_bases[MMSS_BASE],
.c = {
.dbg_name = "csi0phy_cam_mux_clk",
- .ops = &clk_ops_cam_mux,
+ .ops = &clk_ops_gen_mux,
CLK_INIT(csi0phy_cam_mux_clk.c),
},
};
-static struct cam_mux_clk csi1phy_cam_mux_clk = {
- .enable_reg = MMSS_CAMSS_MISC,
- .enable_mask = BIT(10),
- .select_reg = MMSS_CAMSS_MISC,
- .select_mask = BIT(8),
- .sources = (struct mux_source[]) {
- { &csi0phy_clk.c, 0 },
- { &csi1phy_clk.c, BIT(8) },
- { 0 },
- },
+static struct mux_clk csi1phy_cam_mux_clk = {
+ .ops = &mux_reg_ops,
+ .en_mask = BIT(10),
+ .mask = 0x1,
+ .shift = 8,
+ .offset = MMSS_CAMSS_MISC,
+ MUX_SRC_LIST(
+ { &csi0phy_clk.c, 0 },
+ { &csi1phy_clk.c, 1 },
+ ),
.base = &virt_bases[MMSS_BASE],
.c = {
.dbg_name = "csi1phy_cam_mux_clk",
- .ops = &clk_ops_cam_mux,
+ .ops = &clk_ops_gen_mux,
CLK_INIT(csi1phy_cam_mux_clk.c),
},
};
-static struct cam_mux_clk csi0pix_cam_mux_clk = {
- .enable_reg = MMSS_CAMSS_MISC,
- .enable_mask = BIT(7),
- .select_reg = MMSS_CAMSS_MISC,
- .select_mask = BIT(3),
- .sources = (struct mux_source[]) {
- { &csi0pix_clk.c, 0 },
- { &csi1pix_clk.c, BIT(3) },
- { 0 },
- },
+static struct mux_clk csi0pix_cam_mux_clk = {
+ .ops = &mux_reg_ops,
+ .en_mask = BIT(7),
+ .mask = 0x1,
+ .shift = 3,
+ .offset = MMSS_CAMSS_MISC,
+ MUX_SRC_LIST(
+ { &csi0pix_clk.c, 0 },
+ { &csi1pix_clk.c, 1 },
+ ),
.base = &virt_bases[MMSS_BASE],
.c = {
.dbg_name = "csi0pix_cam_mux_clk",
- .ops = &clk_ops_cam_mux,
+ .ops = &clk_ops_gen_mux,
CLK_INIT(csi0pix_cam_mux_clk.c),
},
};
-static struct cam_mux_clk rdi2_cam_mux_clk = {
- .enable_reg = MMSS_CAMSS_MISC,
- .enable_mask = BIT(6),
- .select_reg = MMSS_CAMSS_MISC,
- .select_mask = BIT(2),
- .sources = (struct mux_source[]) {
- { &csi0rdi_clk.c, 0 },
- { &csi1rdi_clk.c, BIT(2) },
- { 0 },
- },
+static struct mux_clk rdi2_cam_mux_clk = {
+ .ops = &mux_reg_ops,
+ .en_mask = BIT(6),
+ .mask = 0x1,
+ .shift = 2,
+ .offset = MMSS_CAMSS_MISC,
+ MUX_SRC_LIST(
+ { &csi0rdi_clk.c, 0 },
+ { &csi1rdi_clk.c, 1 },
+ ),
.base = &virt_bases[MMSS_BASE],
.c = {
.dbg_name = "rdi2_cam_mux_clk",
- .ops = &clk_ops_cam_mux,
+ .ops = &clk_ops_gen_mux,
CLK_INIT(rdi2_cam_mux_clk.c),
},
};
-static struct cam_mux_clk rdi1_cam_mux_clk = {
- .enable_reg = MMSS_CAMSS_MISC,
- .enable_mask = BIT(5),
- .select_reg = MMSS_CAMSS_MISC,
- .select_mask = BIT(1),
- .sources = (struct mux_source[]) {
- { &csi0rdi_clk.c, 0 },
- { &csi1rdi_clk.c, BIT(1) },
- { 0 },
- },
+static struct mux_clk rdi1_cam_mux_clk = {
+ .ops = &mux_reg_ops,
+ .en_mask = BIT(5),
+ .mask = 0x1,
+ .shift = 1,
+ .offset = MMSS_CAMSS_MISC,
+ MUX_SRC_LIST(
+ { &csi0rdi_clk.c, 0 },
+ { &csi1rdi_clk.c, 1 },
+ ),
.base = &virt_bases[MMSS_BASE],
.c = {
.dbg_name = "rdi1_cam_mux_clk",
- .ops = &clk_ops_cam_mux,
+ .ops = &clk_ops_gen_mux,
CLK_INIT(rdi1_cam_mux_clk.c),
},
};
-static struct cam_mux_clk rdi0_cam_mux_clk = {
- .enable_reg = MMSS_CAMSS_MISC,
- .enable_mask = BIT(4),
- .select_reg = MMSS_CAMSS_MISC,
- .select_mask = BIT(0),
- .sources = (struct mux_source[]) {
- { &csi0rdi_clk.c, 0 },
- { &csi1rdi_clk.c, BIT(0) },
- { 0 },
- },
+static struct mux_clk rdi0_cam_mux_clk = {
+ .ops = &mux_reg_ops,
+ .en_mask = BIT(4),
+ .mask = 0x1,
+ .shift = 0,
+ .offset = MMSS_CAMSS_MISC,
+ MUX_SRC_LIST(
+ { &csi0rdi_clk.c, 0 },
+ { &csi1rdi_clk.c, 1 },
+ ),
.base = &virt_bases[MMSS_BASE],
.c = {
.dbg_name = "rdi0_cam_mux_clk",
- .ops = &clk_ops_cam_mux,
+ .ops = &clk_ops_gen_mux,
CLK_INIT(rdi0_cam_mux_clk.c),
},
};
@@ -2892,12 +2896,13 @@
CLK_LOOKUP("core_clk_src", sdcc2_apps_clk_src.c, ""),
CLK_LOOKUP("core_clk_src", usb_hs_system_clk_src.c, ""),
CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9923000.i2c"),
+ CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9924000.i2c"),
CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9925000.i2c"),
CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9927000.i2c"),
CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9926000.spi"),
CLK_LOOKUP("core_clk", gcc_blsp1_qup1_i2c_apps_clk.c, "f9923000.i2c"),
CLK_LOOKUP("core_clk", gcc_blsp1_qup1_spi_apps_clk.c, ""),
- CLK_LOOKUP("core_clk", gcc_blsp1_qup2_i2c_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup2_i2c_apps_clk.c, "f9924000.i2c"),
CLK_LOOKUP("core_clk", gcc_blsp1_qup2_spi_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup3_i2c_apps_clk.c, "f9925000.i2c"),
CLK_LOOKUP("core_clk", gcc_blsp1_qup3_spi_apps_clk.c, ""),
@@ -2922,6 +2927,7 @@
CLK_LOOKUP("iface_clk", gcc_copss_smmu_ahb_clk.c, ""),
CLK_LOOKUP("iface_clk", gcc_lpss_smmu_ahb_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_gp1_clk.c, "0-000e"),
+ CLK_LOOKUP("core_clk_pvt", gcc_gp1_clk.c, "2-000e"),
CLK_LOOKUP("core_clk", gcc_gp2_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_gp3_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_lpass_q6_axi_clk.c, ""),
@@ -3040,10 +3046,12 @@
"fda00c00.qcom,csiphy"),
CLK_LOOKUP("csiphy_timer_clk", csi0phytimer_clk.c,
"fda00c00.qcom,csiphy"),
+ CLK_LOOKUP("csi_ahb_clk", csi_ahb_clk.c, "fda00c00.qcom,csiphy"),
CLK_LOOKUP("csiphy_timer_src_clk", csi1phytimer_clk_src.c,
"fda01000.qcom,csiphy"),
CLK_LOOKUP("csiphy_timer_clk", csi1phytimer_clk.c,
"fda01000.qcom,csiphy"),
+ CLK_LOOKUP("csi_ahb_clk", csi_ahb_clk.c, "fda01000.qcom,csiphy"),
/* CSID clocks */
CLK_LOOKUP("csi_clk", csi0_clk.c, "fda00000.qcom,csid"),
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
old mode 100644
new mode 100755
index 03fcb25..6ae909b
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -541,7 +541,8 @@
#define gpll1_hsic_source_val 4
#define cxo_lpass_source_val 0
#define gpll0_lpass_source_val 5
-#define edppll_270_mm_source_val 4
+#define edp_mainlink_mm_source_val 4
+#define edp_pixel_mm_source_val 5
#define edppll_350_mm_source_val 4
#define dsipll_750_mm_source_val 1
#define dsipll0_byte_mm_source_val 1
@@ -578,10 +579,10 @@
| BVAL(10, 8, s##_mm_source_val), \
}
-#define F_HDMI(f, s, div, m, n) \
+#define F_EDP(f, s, div, m, n) \
{ \
.freq_hz = (f), \
- .src_clk = &s##_clk_src, \
+ .src_clk = &s##_clk_src.c, \
.m_val = (m), \
.n_val = ~((n)-(m)) * !!(n), \
.d_val = ~(n),\
@@ -3181,40 +3182,42 @@
};
static struct clk_freq_tbl ftbl_mdss_edplink_clk[] = {
- F_MDSS(162000000, edppll_270, 2, 0, 0),
- F_MDSS(270000000, edppll_270, 11, 0, 0),
+ F_EDP(162000000, edp_mainlink, 1, 0, 0),
+ F_EDP(270000000, edp_mainlink, 1, 0, 0),
F_END
};
static struct rcg_clk edplink_clk_src = {
.cmd_rcgr_reg = EDPLINK_CMD_RCGR,
- .set_rate = set_rate_hid,
.freq_tbl = ftbl_mdss_edplink_clk,
.current_freq = &rcg_dummy_freq,
.base = &virt_bases[MMSS_BASE],
.c = {
.dbg_name = "edplink_clk_src",
- .ops = &clk_ops_rcg,
+ .ops = &clk_ops_rcg_edp,
VDD_DIG_FMAX_MAP2(LOW, 135000000, NOMINAL, 270000000),
CLK_INIT(edplink_clk_src.c),
},
};
-static struct clk_freq_tbl ftbl_mdss_edppixel_clk[] = {
- F_MDSS(138500000, edppll_350, 2, 0, 0),
- F_MDSS(350000000, edppll_350, 11, 0, 0),
+static struct clk_freq_tbl edp_pixel_freq_tbl[] = {
+ {
+ .src_clk = &edp_pixel_clk_src.c,
+ .div_src_val = BVAL(10, 8, edp_pixel_mm_source_val)
+ | BVAL(4, 0, 0),
+ },
F_END
};
static struct rcg_clk edppixel_clk_src = {
.cmd_rcgr_reg = EDPPIXEL_CMD_RCGR,
.set_rate = set_rate_mnd,
- .freq_tbl = ftbl_mdss_edppixel_clk,
- .current_freq = &rcg_dummy_freq,
+ .current_freq = edp_pixel_freq_tbl,
.base = &virt_bases[MMSS_BASE],
.c = {
+ .parent = &edp_pixel_clk_src.c,
.dbg_name = "edppixel_clk_src",
- .ops = &clk_ops_rcg_mnd,
+ .ops = &clk_ops_edppixel,
VDD_DIG_FMAX_MAP2(LOW, 175000000, NOMINAL, 350000000),
CLK_INIT(edppixel_clk_src.c),
},
@@ -3253,60 +3256,19 @@
},
};
-static int hdmi_pll_clk_enable(struct clk *c)
-{
- return hdmi_pll_enable();
-}
-
-static void hdmi_pll_clk_disable(struct clk *c)
-{
- hdmi_pll_disable();
-}
-
-static int hdmi_pll_clk_set_rate(struct clk *c, unsigned long rate)
-{
- return hdmi_pll_set_rate(rate);
-}
-
-static struct clk_ops clk_ops_hdmi_pll = {
- .enable = hdmi_pll_clk_enable,
- .disable = hdmi_pll_clk_disable,
- .set_rate = hdmi_pll_clk_set_rate,
-};
-
-static struct clk hdmipll_clk_src = {
- .parent = &cxo_clk_src.c,
- .dbg_name = "hdmipll_clk_src",
- .ops = &clk_ops_hdmi_pll,
- CLK_INIT(hdmipll_clk_src),
-};
-
static struct clk_freq_tbl ftbl_mdss_extpclk_clk[] = {
- /*
- * The zero rate is required since suspend/resume wipes out the HDMI PHY
- * registers. This entry allows the HDMI driver to switch the cached
- * rate to zero before suspend and back to the real rate after resume.
- */
- F_HDMI( 0, hdmipll, 1, 0, 0),
- F_HDMI( 25200000, hdmipll, 1, 0, 0),
- F_HDMI( 27000000, hdmipll, 1, 0, 0),
- F_HDMI( 27030000, hdmipll, 1, 0, 0),
- F_HDMI( 65000000, hdmipll, 1, 0, 0),
- F_HDMI( 74250000, hdmipll, 1, 0, 0),
- F_HDMI(108000000, hdmipll, 1, 0, 0),
- F_HDMI(148500000, hdmipll, 1, 0, 0),
- F_HDMI(268500000, hdmipll, 1, 0, 0),
- F_HDMI(297000000, hdmipll, 1, 0, 0),
+ F_MM(148500000, hdmipll, 1, 0, 0),
F_END
};
static struct rcg_clk extpclk_clk_src = {
.cmd_rcgr_reg = EXTPCLK_CMD_RCGR,
.freq_tbl = ftbl_mdss_extpclk_clk,
- .current_freq = &rcg_dummy_freq,
+ .current_freq = ftbl_mdss_extpclk_clk,
.base = &virt_bases[MMSS_BASE],
.c = {
.dbg_name = "extpclk_clk_src",
+ .parent = &hdmipll_clk_src.c,
.ops = &clk_ops_rcg_hdmi,
VDD_DIG_FMAX_MAP2(LOW, 148500000, NOMINAL, 297000000),
CLK_INIT(extpclk_clk_src.c),
@@ -4950,11 +4912,14 @@
CLK_LOOKUP("xo", cxo_dwc3_clk.c, "msm_dwc3"),
CLK_LOOKUP("xo", cxo_ehci_host_clk.c, "msm_ehci_host"),
CLK_LOOKUP("xo", cxo_lpm_clk.c, "fc4281d0.qcom,mpm"),
-
+ CLK_LOOKUP("ref_clk", cxo_d1_a_pin.c, "3-000e"),
+ CLK_LOOKUP("ref_clk_rf", cxo_a2_a_pin.c, "3-000e"),
CLK_LOOKUP("measure", measure_clk.c, "debug"),
+ CLK_LOOKUP("hfpll_src", cxo_a_clk_src.c, "f9016000.qcom,clock-krait"),
+ CLK_LOOKUP("aux_clk", gpll0_ao_clk_src.c,
+ "f9016000.qcom,clock-krait"),
CLK_LOOKUP("gpll0", gpll0_clk_src.c, ""),
- CLK_LOOKUP("gpll0_ao", gpll0_ao_clk_src.c, ""),
CLK_LOOKUP("dma_bam_pclk", gcc_bam_dma_ahb_clk.c, "msm_sps"),
CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f991f000.serial"),
@@ -4972,7 +4937,11 @@
CLK_LOOKUP("core_clk", gcc_blsp1_qup4_spi_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup5_i2c_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup5_spi_apps_clk.c, ""),
- CLK_LOOKUP("core_clk", gcc_blsp1_qup6_i2c_apps_clk.c, ""),
+
+ /* I2C Clocks nfc */
+ CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9928000.i2c"),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup6_i2c_apps_clk.c, "f9928000.i2c"),
+
CLK_LOOKUP("core_clk", gcc_blsp1_qup6_spi_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_uart1_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_uart2_apps_clk.c, "f991e000.serial"),
diff --git a/arch/arm/mach-msm/clock-a7.c b/arch/arm/mach-msm/clock-a7.c
new file mode 100644
index 0000000..d09e4b6
--- /dev/null
+++ b/arch/arm/mach-msm/clock-a7.c
@@ -0,0 +1,388 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of.h>
+
+#include <mach/clock-generic.h>
+#include "clock-local2.h"
+
+#define UPDATE_CHECK_MAX_LOOPS 200
+
+struct cortex_reg_data {
+ u32 cmd_offset;
+ u32 update_mask;
+ u32 poll_mask;
+};
+
+#define DIV_REG(x) ((x)->base + (x)->div_offset)
+#define SRC_REG(x) ((x)->base + (x)->src_offset)
+#define CMD_REG(x) ((x)->base + \
+ ((struct cortex_reg_data *)(x)->priv)->cmd_offset)
+
+static int update_config(struct mux_div_clk *md)
+{
+ u32 regval, count;
+ struct cortex_reg_data *r = md->priv;
+
+ /* Update the configuration */
+ regval = readl_relaxed(CMD_REG(md));
+ regval |= r->update_mask;
+ writel_relaxed(regval, CMD_REG(md));
+
+ /* Wait for update to take effect */
+ for (count = UPDATE_CHECK_MAX_LOOPS; count > 0; count--) {
+ if (!(readl_relaxed(CMD_REG(md)) &
+ r->poll_mask))
+ return 0;
+ udelay(1);
+ }
+
+ CLK_WARN(&md->c, true, "didn't update its configuration.");
+
+ return -EINVAL;
+}
+
+static void cortex_get_config(struct mux_div_clk *md, u32 *src_sel, u32 *div)
+{
+ u32 regval;
+
+ regval = readl_relaxed(DIV_REG(md));
+ regval &= (md->div_mask << md->div_shift);
+ *div = regval >> md->div_shift;
+ *div = max((u32)1, (*div + 1) / 2);
+
+ regval = readl_relaxed(SRC_REG(md));
+ regval &= (md->src_mask << md->src_shift);
+ *src_sel = regval >> md->src_shift;
+}
+
+static int cortex_set_config(struct mux_div_clk *md, u32 src_sel, u32 div)
+{
+ u32 regval;
+
+ div = div ? ((2 * div) - 1) : 0;
+ regval = readl_relaxed(DIV_REG(md));
+ regval &= ~(md->div_mask << md->div_shift);
+ regval |= div << md->div_shift;
+ writel_relaxed(regval, DIV_REG(md));
+
+ regval = readl_relaxed(SRC_REG(md));
+ regval &= ~(md->src_mask << md->src_shift);
+ regval |= src_sel << md->src_shift;
+ writel_relaxed(regval, SRC_REG(md));
+
+ return update_config(md);
+}
+
+static int cortex_enable(struct mux_div_clk *md)
+{
+ u32 src_sel = parent_to_src_sel(md->parents, md->num_parents,
+ md->c.parent);
+ return cortex_set_config(md, src_sel, md->data.div);
+}
+
+static void cortex_disable(struct mux_div_clk *md)
+{
+ u32 src_sel = parent_to_src_sel(md->parents, md->num_parents,
+ md->safe_parent);
+ cortex_set_config(md, src_sel, md->safe_div);
+}
+
+static bool cortex_is_enabled(struct mux_div_clk *md)
+{
+ return true;
+}
+
+struct mux_div_ops cortex_mux_div_ops = {
+ .set_src_div = cortex_set_config,
+ .get_src_div = cortex_get_config,
+ .is_enabled = cortex_is_enabled,
+ .enable = cortex_enable,
+ .disable = cortex_disable,
+};
+
+static struct cortex_reg_data a7ssmux_priv = {
+ .cmd_offset = 0x0,
+ .update_mask = BIT(0),
+ .poll_mask = BIT(0),
+};
+
+DEFINE_VDD_REGS_INIT(vdd_cpu, 1);
+
+static struct mux_div_clk a7ssmux = {
+ .ops = &cortex_mux_div_ops,
+ .safe_freq = 300000000,
+ .data = {
+ .max_div = 8,
+ .min_div = 1,
+ },
+ .c = {
+ .dbg_name = "a7ssmux",
+ .ops = &clk_ops_mux_div_clk,
+ .vdd_class = &vdd_cpu,
+ CLK_INIT(a7ssmux.c),
+ },
+ .parents = (struct clk_src[8]) {},
+ .priv = &a7ssmux_priv,
+ .div_offset = 0x4,
+ .div_mask = BM(4, 0),
+ .div_shift = 0,
+ .src_offset = 0x4,
+ .src_mask = BM(10, 8) >> 8,
+ .src_shift = 8,
+};
+
+static struct clk_lookup clock_tbl_a7[] = {
+ CLK_LOOKUP("cpu0_clk", a7ssmux.c, "0.qcom,msm-cpufreq"),
+ CLK_LOOKUP("cpu0_clk", a7ssmux.c, "fe805664.qcom,pm-8x60"),
+};
+
+static int of_get_fmax_vdd_class(struct platform_device *pdev, struct clk *c,
+ char *prop_name)
+{
+ struct device_node *of = pdev->dev.of_node;
+ int prop_len, i;
+ struct clk_vdd_class *vdd = c->vdd_class;
+ u32 *array;
+
+ if (!of_find_property(of, prop_name, &prop_len)) {
+ dev_err(&pdev->dev, "missing %s\n", prop_name);
+ return -EINVAL;
+ }
+
+ prop_len /= sizeof(u32);
+ if (prop_len % 2) {
+ dev_err(&pdev->dev, "bad length %d\n", prop_len);
+ return -EINVAL;
+ }
+
+ prop_len /= 2;
+ vdd->level_votes = devm_kzalloc(&pdev->dev, prop_len * sizeof(int),
+ GFP_KERNEL);
+ if (!vdd->level_votes)
+ return -ENOMEM;
+
+ vdd->vdd_uv = devm_kzalloc(&pdev->dev, prop_len * sizeof(int),
+ GFP_KERNEL);
+ if (!vdd->vdd_uv)
+ return -ENOMEM;
+
+ c->fmax = devm_kzalloc(&pdev->dev, prop_len * sizeof(unsigned long),
+ GFP_KERNEL);
+ if (!c->fmax)
+ return -ENOMEM;
+
+ array = devm_kzalloc(&pdev->dev,
+ prop_len * sizeof(u32) * 2, GFP_KERNEL);
+ if (!array)
+ return -ENOMEM;
+
+ of_property_read_u32_array(of, prop_name, array, prop_len * 2);
+ for (i = 0; i < prop_len; i++) {
+ c->fmax[i] = array[2 * i];
+ vdd->vdd_uv[i] = array[2 * i + 1];
+ }
+
+ devm_kfree(&pdev->dev, array);
+ vdd->num_levels = prop_len;
+ vdd->cur_level = prop_len;
+ c->num_fmax = prop_len;
+ return 0;
+}
+
+static void get_speed_bin(struct platform_device *pdev, int *bin, int *version)
+{
+ struct resource *res;
+ void __iomem *base;
+ u32 pte_efuse, redundant_sel, valid;
+
+ *bin = 0;
+ *version = 0;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "efuse");
+ if (!res) {
+ dev_info(&pdev->dev,
+ "No speed/PVS binning available. Defaulting to 0!\n");
+ return;
+ }
+
+ base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!base) {
+ dev_warn(&pdev->dev,
+ "Unable to read efuse data. Defaulting to 0!\n");
+ return;
+ }
+
+ pte_efuse = readl_relaxed(base);
+ devm_iounmap(&pdev->dev, base);
+
+ redundant_sel = (pte_efuse >> 24) & 0x7;
+ *bin = pte_efuse & 0x7;
+ valid = (pte_efuse >> 3) & 0x1;
+ *version = (pte_efuse >> 4) & 0x3;
+
+ if (redundant_sel == 1)
+ *bin = (pte_efuse >> 27) & 0x7;
+
+ if (!valid) {
+ dev_info(&pdev->dev, "Speed bin not set. Defaulting to 0!\n");
+ *bin = 0;
+ } else {
+ dev_info(&pdev->dev, "Speed bin: %d\n", *bin);
+ }
+
+ dev_info(&pdev->dev, "PVS version: %d\n", *version);
+
+ return;
+}
+
+static int of_get_clk_src(struct platform_device *pdev, struct clk_src *parents)
+{
+ struct device_node *of = pdev->dev.of_node;
+ int num_parents, i, j, index;
+ struct clk *c;
+ char clk_name[] = "clk-x";
+
+ num_parents = of_property_count_strings(of, "clock-names");
+ if (num_parents <= 0 || num_parents > 8) {
+ dev_err(&pdev->dev, "missing clock-names\n");
+ return -EINVAL;
+ }
+
+ j = 0;
+ for (i = 0; i < 8; i++) {
+ snprintf(clk_name, ARRAY_SIZE(clk_name), "clk-%d", i);
+ index = of_property_match_string(of, "clock-names", clk_name);
+ if (IS_ERR_VALUE(index))
+ continue;
+
+ parents[j].sel = i;
+ parents[j].src = c = devm_clk_get(&pdev->dev, clk_name);
+ if (IS_ERR(c)) {
+ if (c != ERR_PTR(-EPROBE_DEFER))
+ dev_err(&pdev->dev, "clk_get: %s\n fail",
+ clk_name);
+ return PTR_ERR(c);
+ }
+ j++;
+ }
+
+ return num_parents;
+}
+
+static int clock_a7_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ int speed_bin = 0, version = 0, rc;
+ unsigned long rate, aux_rate;
+ struct clk *aux_clk, *main_pll;
+ char prop_name[] = "qcom,speedX-bin-vX";
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rcg-base");
+ if (!res) {
+ dev_err(&pdev->dev, "missing rcg-base\n");
+ return -EINVAL;
+ }
+ a7ssmux.base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!a7ssmux.base) {
+ dev_err(&pdev->dev, "ioremap failed for rcg-base\n");
+ return -ENOMEM;
+ }
+
+ vdd_cpu.regulator[0] = devm_regulator_get(&pdev->dev, "cpu-vdd");
+ if (IS_ERR(vdd_cpu.regulator[0])) {
+ if (PTR_ERR(vdd_cpu.regulator[0]) != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "unable to get regulator\n");
+ return PTR_ERR(vdd_cpu.regulator[0]);
+ }
+
+ a7ssmux.num_parents = of_get_clk_src(pdev, a7ssmux.parents);
+ if (IS_ERR_VALUE(a7ssmux.num_parents))
+ return a7ssmux.num_parents;
+
+ get_speed_bin(pdev, &speed_bin, &version);
+
+ snprintf(prop_name, ARRAY_SIZE(prop_name),
+ "qcom,speed%d-bin-v%d", speed_bin, version);
+ rc = of_get_fmax_vdd_class(pdev, &a7ssmux.c, prop_name);
+ if (rc) {
+ /* Fall back to most conservative PVS table */
+ dev_err(&pdev->dev, "Unable to load voltage plan %s!\n",
+ prop_name);
+ rc = of_get_fmax_vdd_class(pdev, &a7ssmux.c,
+ "qcom,speed0-bin-v0");
+ if (rc) {
+ dev_err(&pdev->dev,
+ "Unable to load safe voltage plan\n");
+ return rc;
+ }
+ dev_info(&pdev->dev, "Safe voltage plan loaded.\n");
+ }
+
+ rc = msm_clock_register(clock_tbl_a7, ARRAY_SIZE(clock_tbl_a7));
+ if (rc) {
+ dev_err(&pdev->dev, "msm_clock_register failed\n");
+ return rc;
+ }
+
+ /* Force a PLL reconfiguration */
+ aux_clk = a7ssmux.parents[0].src;
+ main_pll = a7ssmux.parents[1].src;
+
+ aux_rate = clk_get_rate(aux_clk);
+ rate = clk_get_rate(&a7ssmux.c);
+ clk_set_rate(&a7ssmux.c, aux_rate);
+ clk_set_rate(main_pll, clk_round_rate(main_pll, 1));
+ clk_set_rate(&a7ssmux.c, rate);
+
+ /*
+ * We don't want the CPU clocks to be turned off at late init
+ * if CPUFREQ or HOTPLUG configs are disabled. So, bump up the
+ * refcount of these clocks. Any cpufreq/hotplug manager can assume
+ * that the clocks have already been prepared and enabled by the time
+ * they take over.
+ */
+ WARN(clk_prepare_enable(&a7ssmux.c),
+ "Unable to turn on CPU clock");
+ return 0;
+}
+
+static struct of_device_id clock_a7_match_table[] = {
+ {.compatible = "qcom,clock-a7-8226"},
+ {}
+};
+
+static struct platform_driver clock_a7_driver = {
+ .driver = {
+ .name = "clock-a7",
+ .of_match_table = clock_a7_match_table,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init clock_a7_init(void)
+{
+ return platform_driver_probe(&clock_a7_driver, clock_a7_probe);
+}
+device_initcall(clock_a7_init);
diff --git a/arch/arm/mach-msm/clock-debug.c b/arch/arm/mach-msm/clock-debug.c
index 35917c3..c3b7229 100644
--- a/arch/arm/mach-msm/clock-debug.c
+++ b/arch/arm/mach-msm/clock-debug.c
@@ -23,6 +23,7 @@
#include <linux/clkdev.h>
#include <linux/uaccess.h>
#include <linux/mutex.h>
+#include <linux/io.h>
#include <mach/clk-provider.h>
@@ -412,6 +413,56 @@
.write = clock_parent_write,
};
+void clk_debug_print_hw(struct clk *clk, struct seq_file *f)
+{
+ void __iomem *base;
+ struct clk_register_data *regs;
+ u32 i, j, size;
+
+ if (IS_ERR_OR_NULL(clk))
+ return;
+
+ clk_debug_print_hw(clk->parent, f);
+
+ clock_debug_output(f, false, "%s\n", clk->dbg_name);
+
+ if (!clk->ops->list_registers)
+ return;
+
+ j = 0;
+ base = clk->ops->list_registers(clk, j, ®s, &size);
+ while (!IS_ERR(base)) {
+ for (i = 0; i < size; i++) {
+ u32 val = readl_relaxed(base + regs[i].offset);
+ clock_debug_output(f, false, "%20s: 0x%.8x\n",
+ regs[i].name, val);
+ }
+ j++;
+ base = clk->ops->list_registers(clk, j, ®s, &size);
+ }
+}
+
+static int print_hw_show(struct seq_file *m, void *unused)
+{
+ struct clk *c = m->private;
+ clk_debug_print_hw(c, m);
+
+ return 0;
+}
+
+static int print_hw_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, print_hw_show, inode->i_private);
+}
+
+static const struct file_operations clock_print_hw_fops = {
+ .open = print_hw_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+
static int clock_debug_add(struct clk *clock)
{
char temp[50], *ptr;
@@ -463,6 +514,10 @@
&clock_parent_fops))
goto error;
+ if (!debugfs_create_file("print", S_IRUGO, clk_dir, clock,
+ &clock_print_hw_fops))
+ goto error;
+
return 0;
error:
debugfs_remove_recursive(clk_dir);
diff --git a/arch/arm/mach-msm/clock-generic.c b/arch/arm/mach-msm/clock-generic.c
index b0d32a0..c7d24a8 100644
--- a/arch/arm/mach-msm/clock-generic.c
+++ b/arch/arm/mach-msm/clock-generic.c
@@ -14,20 +14,21 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/err.h>
-
#include <linux/clk.h>
+#include <linux/io.h>
+
#include <mach/clk-provider.h>
#include <mach/clock-generic.h>
/* ==================== Mux clock ==================== */
-static int parent_to_src_sel(struct mux_clk *mux, struct clk *p)
+int parent_to_src_sel(struct clk_src *parents, int num_parents, struct clk *p)
{
int i;
- for (i = 0; i < mux->num_parents; i++) {
- if (mux->parents[i].src == p)
- return mux->parents[i].sel;
+ for (i = 0; i < num_parents; i++) {
+ if (parents[i].src == p)
+ return parents[i].sel;
}
return -EINVAL;
@@ -36,11 +37,26 @@
static int mux_set_parent(struct clk *c, struct clk *p)
{
struct mux_clk *mux = to_mux_clk(c);
- int sel = parent_to_src_sel(mux, p);
+ int sel = parent_to_src_sel(mux->parents, mux->num_parents, p);
struct clk *old_parent;
- int rc = 0;
+ int rc = 0, i;
unsigned long flags;
+ if (sel < 0 && mux->rec_set_par) {
+ for (i = 0; i < mux->num_parents; i++) {
+ rc = clk_set_parent(mux->parents[i].src, p);
+ if (!rc) {
+ sel = mux->parents[i].sel;
+ /*
+ * This is necessary to ensure prepare/enable
+ * counts get propagated correctly.
+ */
+ p = mux->parents[i].src;
+ break;
+ }
+ }
+ }
+
if (sel < 0)
return sel;
@@ -54,6 +70,7 @@
old_parent = c->parent;
c->parent = p;
+ c->rate = clk_get_rate(p);
__clk_post_reparent(c, old_parent, &flags);
return 0;
@@ -68,23 +85,17 @@
{
struct mux_clk *mux = to_mux_clk(c);
int i;
- unsigned long prate, max_prate = 0, rrate = ULONG_MAX;
+ unsigned long prate, rrate = 0;
for (i = 0; i < mux->num_parents; i++) {
prate = clk_round_rate(mux->parents[i].src, rate);
- if (IS_ERR_VALUE(prate))
- continue;
- if (prate < rate) {
- max_prate = max(prate, max_prate);
- continue;
- }
-
- rrate = min(rrate, prate);
+ if (is_better_rate(rate, rrate, prate))
+ rrate = prate;
}
- if (rrate == ULONG_MAX)
- rrate = max_prate;
+ if (!rrate)
+ return -EINVAL;
- return rrate ? rrate : -EINVAL;
+ return rrate;
}
static int mux_set_rate(struct clk *c, unsigned long rate)
@@ -136,7 +147,8 @@
set_par_fail:
clk_set_rate(new_parent, new_par_curr_rate);
set_rate_fail:
- WARN(mux->ops->set_mux_sel(mux, parent_to_src_sel(mux, c->parent)),
+ WARN(mux->ops->set_mux_sel(mux,
+ parent_to_src_sel(mux->parents, mux->num_parents, c->parent)),
"Set rate failed for %s. Also in bad state!\n", c->dbg_name);
return rc;
}
@@ -176,7 +188,8 @@
struct mux_clk *mux = to_mux_clk(c);
c->rate = clk_get_rate(c->parent);
- mux->safe_sel = parent_to_src_sel(mux, mux->safe_parent);
+ mux->safe_sel = parent_to_src_sel(mux->parents, mux->num_parents,
+ mux->safe_parent);
if (mux->en_mask && mux->ops && mux->ops->is_enabled)
return mux->ops->is_enabled(mux)
@@ -205,30 +218,30 @@
.get_parent = mux_get_parent,
};
-
/* ==================== Divider clock ==================== */
-static long __div_round_rate(struct clk *c, unsigned long rate, int *best_div)
+static long __div_round_rate(struct div_data *data, unsigned long rate,
+ struct clk *parent, unsigned int *best_div, unsigned long *best_prate)
{
- struct div_clk *d = to_div_clk(c);
- unsigned int div, min_div, max_div;
- unsigned long p_rrate, rrate = ULONG_MAX;
+ unsigned int div, min_div, max_div, _best_div = 1;
+ unsigned long prate, _best_prate = 0, rrate = 0;
rate = max(rate, 1UL);
- if (!d->ops || !d->ops->set_div)
- min_div = max_div = d->div;
- else {
- min_div = max(d->min_div, 1U);
- max_div = min(d->max_div, (unsigned int) (ULONG_MAX / rate));
- }
+ min_div = max(data->min_div, 1U);
+ max_div = min(data->max_div, (unsigned int) (ULONG_MAX / rate));
for (div = min_div; div <= max_div; div++) {
- p_rrate = clk_round_rate(c->parent, rate * div);
- if (IS_ERR_VALUE(p_rrate))
+ prate = clk_round_rate(parent, rate * div);
+ if (IS_ERR_VALUE(prate))
break;
- p_rrate /= div;
+ if (is_better_rate(rate, rrate, prate / div)) {
+ rrate = prate / div;
+ _best_div = div;
+ _best_prate = prate;
+ }
+
/*
* Trying higher dividers is only going to ask the parent for
* a higher rate. If it can't even output a rate higher than
@@ -236,42 +249,38 @@
* going to be able to output an even higher rate required
* for a higher divider. So, stop trying higher dividers.
*/
- if (p_rrate < rate) {
- if (rrate == ULONG_MAX) {
- rrate = p_rrate;
- if (best_div)
- *best_div = div;
- }
+ if (prate / div < rate)
break;
- }
- if (p_rrate < rrate) {
- rrate = p_rrate;
- if (best_div)
- *best_div = div;
- }
- if (rrate <= rate + d->rate_margin)
+ if (rrate <= rate + data->rate_margin)
break;
}
- if (rrate == ULONG_MAX)
+ if (!rrate)
return -EINVAL;
+ if (best_div)
+ *best_div = _best_div;
+ if (best_prate)
+ *best_prate = _best_prate;
return rrate;
}
static long div_round_rate(struct clk *c, unsigned long rate)
{
- return __div_round_rate(c, rate, NULL);
+ struct div_clk *d = to_div_clk(c);
+
+ return __div_round_rate(&d->data, rate, c->parent, NULL, NULL);
}
static int div_set_rate(struct clk *c, unsigned long rate)
{
struct div_clk *d = to_div_clk(c);
int div, rc = 0;
- long rrate, old_prate;
+ long rrate, old_prate, new_prate;
+ struct div_data *data = &d->data;
- rrate = __div_round_rate(c, rate, &div);
+ rrate = __div_round_rate(data, rate, c->parent, &div, &new_prate);
if (rrate != rate)
return -EINVAL;
@@ -281,22 +290,22 @@
* !d->ops and return an error. __div_round_rate() ensures div ==
* d->div if !d->ops.
*/
- if (div > d->div)
+ if (div > data->div)
rc = d->ops->set_div(d, div);
if (rc)
return rc;
old_prate = clk_get_rate(c->parent);
- rc = clk_set_rate(c->parent, rate * div);
+ rc = clk_set_rate(c->parent, new_prate);
if (rc)
goto set_rate_fail;
- if (div < d->div)
+ if (div < data->div)
rc = d->ops->set_div(d, div);
if (rc)
goto div_dec_fail;
- d->div = div;
+ data->div = div;
return 0;
@@ -304,8 +313,8 @@
WARN(clk_set_rate(c->parent, old_prate),
"Set rate failed for %s. Also in bad state!\n", c->dbg_name);
set_rate_fail:
- if (div > d->div)
- WARN(d->ops->set_div(d, d->div),
+ if (div > data->div)
+ WARN(d->ops->set_div(d, data->div),
"Set rate failed for %s. Also in bad state!\n",
c->dbg_name);
return rc;
@@ -329,11 +338,16 @@
static enum handoff div_handoff(struct clk *c)
{
struct div_clk *d = to_div_clk(c);
+ unsigned int div = d->data.div;
if (d->ops && d->ops->get_div)
- d->div = max(d->ops->get_div(d), 1);
- d->div = max(d->div, 1U);
- c->rate = clk_get_rate(c->parent) / d->div;
+ div = max(d->ops->get_div(d), 1);
+ div = max(div, 1U);
+ c->rate = clk_get_rate(c->parent) / div;
+
+ if (!d->ops || !d->ops->set_div)
+ d->data.min_div = d->data.max_div = div;
+ d->data.div = div;
if (d->en_mask && d->ops && d->ops->is_enabled)
return d->ops->is_enabled(d)
@@ -369,12 +383,8 @@
rate = max(rate, 1UL);
- if (!d->ops || !d->ops->set_div)
- min_div = max_div = d->div;
- else {
- min_div = d->min_div;
- max_div = d->max_div;
- }
+ min_div = d->data.min_div;
+ max_div = d->data.max_div;
p_rate = clk_get_rate(c->parent);
div = p_rate / rate;
@@ -401,28 +411,320 @@
if (rrate != rate)
return -EINVAL;
- if (div == d->div)
+ if (div == d->data.div)
return 0;
/*
* For fixed divider clock we don't want to return an error if the
* requested rate matches the achievable rate. So, don't check for
* !d->ops and return an error. __slave_div_round_rate() ensures
- * div == d->div if !d->ops.
+ * div == d->data.div if !d->ops.
*/
rc = d->ops->set_div(d, div);
if (rc)
return rc;
- d->div = div;
+ d->data.div = div;
return 0;
}
+static unsigned long slave_div_get_rate(struct clk *c)
+{
+ struct div_clk *d = to_div_clk(c);
+ if (!d->data.div)
+ return 0;
+ return clk_get_rate(c->parent) / d->data.div;
+}
+
struct clk_ops clk_ops_slave_div = {
.enable = div_enable,
.disable = div_disable,
.round_rate = slave_div_round_rate,
.set_rate = slave_div_set_rate,
+ .get_rate = slave_div_get_rate,
.handoff = div_handoff,
};
+
+
+/**
+ * External clock
+ * Some clock controllers have input clock signal that come from outside the
+ * clock controller. That input clock signal might then be used as a source for
+ * several clocks inside the clock controller. This external clock
+ * implementation models this input clock signal by just passing on the requests
+ * to the clock's parent, the original external clock source. The driver for the
+ * clock controller should clk_get() the original external clock in the probe
+ * function and set is as a parent to this external clock..
+ */
+
+static long ext_round_rate(struct clk *c, unsigned long rate)
+{
+ return clk_round_rate(c->parent, rate);
+}
+
+static int ext_set_rate(struct clk *c, unsigned long rate)
+{
+ return clk_set_rate(c->parent, rate);
+}
+
+static unsigned long ext_get_rate(struct clk *c)
+{
+ return clk_get_rate(c->parent);
+}
+
+static int ext_set_parent(struct clk *c, struct clk *p)
+{
+ return clk_set_parent(c->parent, p);
+}
+
+static enum handoff ext_handoff(struct clk *c)
+{
+ c->rate = clk_get_rate(c->parent);
+ /* Similar reasoning applied in div_handoff, see comment there. */
+ return HANDOFF_DISABLED_CLK;
+}
+
+struct clk_ops clk_ops_ext = {
+ .handoff = ext_handoff,
+ .round_rate = ext_round_rate,
+ .set_rate = ext_set_rate,
+ .get_rate = ext_get_rate,
+ .set_parent = ext_set_parent,
+};
+
+
+/* ==================== Mux_div clock ==================== */
+
+static int mux_div_clk_enable(struct clk *c)
+{
+ struct mux_div_clk *md = to_mux_div_clk(c);
+
+ if (md->ops->enable)
+ return md->ops->enable(md);
+ return 0;
+}
+
+static void mux_div_clk_disable(struct clk *c)
+{
+ struct mux_div_clk *md = to_mux_div_clk(c);
+
+ if (md->ops->disable)
+ return md->ops->disable(md);
+}
+
+static long __mux_div_round_rate(struct clk *c, unsigned long rate,
+ struct clk **best_parent, int *best_div, unsigned long *best_prate)
+{
+ struct mux_div_clk *md = to_mux_div_clk(c);
+ unsigned int i;
+ unsigned long rrate, best = 0, _best_div = 0, _best_prate = 0;
+ struct clk *_best_parent = 0;
+
+ for (i = 0; i < md->num_parents; i++) {
+ int div;
+ unsigned long prate;
+
+ rrate = __div_round_rate(&md->data, rate, md->parents[i].src,
+ &div, &prate);
+
+ if (is_better_rate(rate, best, rrate)) {
+ best = rrate;
+ _best_div = div;
+ _best_prate = prate;
+ _best_parent = md->parents[i].src;
+ }
+
+ if (rate <= rrate && rrate <= rate + md->data.rate_margin)
+ break;
+ }
+
+ if (best_div)
+ *best_div = _best_div;
+ if (best_prate)
+ *best_prate = _best_prate;
+ if (best_parent)
+ *best_parent = _best_parent;
+
+ if (best)
+ return best;
+ return -EINVAL;
+}
+
+static long mux_div_clk_round_rate(struct clk *c, unsigned long rate)
+{
+ return __mux_div_round_rate(c, rate, NULL, NULL, NULL);
+}
+
+/* requires enable lock to be held */
+static int __set_src_div(struct mux_div_clk *md, struct clk *parent, u32 div)
+{
+ u32 rc = 0, src_sel;
+
+ src_sel = parent_to_src_sel(md->parents, md->num_parents, parent);
+ /*
+ * If the clock is disabled, don't change to the new settings until
+ * the clock is reenabled
+ */
+ if (md->c.count)
+ rc = md->ops->set_src_div(md, src_sel, div);
+ if (!rc) {
+ md->data.div = div;
+ md->src_sel = src_sel;
+ }
+
+ return rc;
+}
+
+static int set_src_div(struct mux_div_clk *md, struct clk *parent, u32 div)
+{
+ unsigned long flags;
+ u32 rc;
+
+ spin_lock_irqsave(&md->c.lock, flags);
+ rc = __set_src_div(md, parent, div);
+ spin_unlock_irqrestore(&md->c.lock, flags);
+
+ return rc;
+}
+
+/* Must be called after handoff to ensure parent clock rates are initialized */
+static int safe_parent_init_once(struct clk *c)
+{
+ unsigned long rrate;
+ u32 best_div;
+ struct clk *best_parent;
+ struct mux_div_clk *md = to_mux_div_clk(c);
+
+ if (IS_ERR(md->safe_parent))
+ return -EINVAL;
+ if (!md->safe_freq || md->safe_parent)
+ return 0;
+
+ rrate = __mux_div_round_rate(c, md->safe_freq, &best_parent,
+ &best_div, NULL);
+
+ if (rrate == md->safe_freq) {
+ md->safe_div = best_div;
+ md->safe_parent = best_parent;
+ } else {
+ md->safe_parent = ERR_PTR(-EINVAL);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int mux_div_clk_set_rate(struct clk *c, unsigned long rate)
+{
+ struct mux_div_clk *md = to_mux_div_clk(c);
+ unsigned long flags, rrate;
+ unsigned long new_prate, old_prate;
+ struct clk *old_parent, *new_parent;
+ u32 new_div, old_div;
+ int rc;
+
+ rc = safe_parent_init_once(c);
+ if (rc)
+ return rc;
+
+ rrate = __mux_div_round_rate(c, rate, &new_parent, &new_div,
+ &new_prate);
+ if (rrate != rate)
+ return -EINVAL;
+
+ old_parent = c->parent;
+ old_div = md->data.div;
+ old_prate = clk_get_rate(c->parent);
+
+ /* Refer to the description of safe_freq in clock-generic.h */
+ if (md->safe_freq)
+ rc = set_src_div(md, md->safe_parent, md->safe_div);
+
+ else if (new_parent == old_parent && new_div >= old_div) {
+ /*
+ * If both the parent_rate and divider changes, there may be an
+ * intermediate frequency generated. Ensure this intermediate
+ * frequency is less than both the new rate and previous rate.
+ */
+ rc = set_src_div(md, old_parent, new_div);
+ }
+ if (rc)
+ return rc;
+
+ rc = clk_set_rate(new_parent, new_prate);
+ if (rc) {
+ pr_err("failed to set %s to %ld\n",
+ new_parent->dbg_name, new_prate);
+ goto err_set_rate;
+ }
+
+ rc = __clk_pre_reparent(c, new_parent, &flags);
+ if (rc)
+ goto err_pre_reparent;
+
+ /* Set divider and mux src atomically */
+ rc = __set_src_div(md, new_parent, new_div);
+ if (rc)
+ goto err_set_src_div;
+
+ c->parent = new_parent;
+
+ __clk_post_reparent(c, old_parent, &flags);
+ return 0;
+
+err_set_src_div:
+ /* Not switching to new_parent, so disable it */
+ __clk_post_reparent(c, new_parent, &flags);
+err_pre_reparent:
+ rc = clk_set_rate(old_parent, old_prate);
+ WARN(rc, "%s: error changing parent (%s) rate to %ld\n",
+ c->dbg_name, old_parent->dbg_name, old_prate);
+err_set_rate:
+ rc = set_src_div(md, old_parent, old_div);
+ WARN(rc, "%s: error changing back to original div (%d) and parent (%s)\n",
+ c->dbg_name, old_div, old_parent->dbg_name);
+
+ return rc;
+}
+
+static struct clk *mux_div_clk_get_parent(struct clk *c)
+{
+ struct mux_div_clk *md = to_mux_div_clk(c);
+ u32 i, div, src_sel;
+
+ md->ops->get_src_div(md, &src_sel, &div);
+
+ md->data.div = div;
+ md->src_sel = src_sel;
+
+ for (i = 0; i < md->num_parents; i++) {
+ if (md->parents[i].sel == src_sel)
+ return md->parents[i].src;
+ }
+
+ return NULL;
+}
+
+static enum handoff mux_div_clk_handoff(struct clk *c)
+{
+ struct mux_div_clk *md = to_mux_div_clk(c);
+ unsigned long parent_rate;
+
+ parent_rate = clk_get_rate(c->parent);
+ c->rate = parent_rate / md->data.div;
+
+ if (!md->ops->is_enabled)
+ return HANDOFF_DISABLED_CLK;
+ if (md->ops->is_enabled(md))
+ return HANDOFF_ENABLED_CLK;
+ return HANDOFF_DISABLED_CLK;
+}
+
+struct clk_ops clk_ops_mux_div_clk = {
+ .enable = mux_div_clk_enable,
+ .disable = mux_div_clk_disable,
+ .set_rate = mux_div_clk_set_rate,
+ .round_rate = mux_div_clk_round_rate,
+ .get_parent = mux_div_clk_get_parent,
+ .handoff = mux_div_clk_handoff,
+};
diff --git a/arch/arm/mach-msm/clock-krait-8974.c b/arch/arm/mach-msm/clock-krait-8974.c
new file mode 100644
index 0000000..4f133fc
--- /dev/null
+++ b/arch/arm/mach-msm/clock-krait-8974.c
@@ -0,0 +1,817 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of.h>
+#include <linux/cpumask.h>
+
+#include <asm/cputype.h>
+
+#include <mach/rpm-regulator-smd.h>
+#include <mach/clk-provider.h>
+#include <mach/clock-generic.h>
+#include <mach/clk.h>
+#include "clock-krait.h"
+#include "clock.h"
+
+/* Clock inputs coming into Krait subsystem */
+DEFINE_FIXED_DIV_CLK(hfpll_src_clk, 1, NULL);
+DEFINE_FIXED_DIV_CLK(acpu_aux_clk, 2, NULL);
+
+static int hfpll_uv[] = {
+ RPM_REGULATOR_CORNER_NONE, 0,
+ RPM_REGULATOR_CORNER_SVS_SOC, 1800000,
+ RPM_REGULATOR_CORNER_NORMAL, 1800000,
+ RPM_REGULATOR_CORNER_SUPER_TURBO, 1800000,
+};
+static DEFINE_VDD_REGULATORS(vdd_hfpll, ARRAY_SIZE(hfpll_uv)/2, 2,
+ hfpll_uv, NULL);
+
+static unsigned long hfpll_fmax[] = { 0, 998400000, 1996800000, 2900000000UL };
+
+static struct hfpll_data hdata = {
+ .mode_offset = 0x0,
+ .l_offset = 0x4,
+ .m_offset = 0x8,
+ .n_offset = 0xC,
+ .user_offset = 0x10,
+ .config_offset = 0x14,
+ .status_offset = 0x1C,
+
+ .user_val = 0x8,
+ .low_vco_max_rate = 1248000000,
+ .min_rate = 537600000UL,
+ .max_rate = 2900000000UL,
+};
+
+static struct hfpll_clk hfpll0_clk = {
+ .d = &hdata,
+ .src_rate = 19200000,
+ .c = {
+ .parent = &hfpll_src_clk.c,
+ .dbg_name = "hfpll0_clk",
+ .ops = &clk_ops_hfpll,
+ .vdd_class = &vdd_hfpll,
+ .fmax = hfpll_fmax,
+ .num_fmax = ARRAY_SIZE(hfpll_fmax),
+ CLK_INIT(hfpll0_clk.c),
+ },
+};
+
+DEFINE_KPSS_DIV2_CLK(hfpll0_div_clk, &hfpll0_clk.c, 0x4501, true);
+
+static struct hfpll_clk hfpll1_clk = {
+ .d = &hdata,
+ .src_rate = 19200000,
+ .c = {
+ .parent = &hfpll_src_clk.c,
+ .dbg_name = "hfpll1_clk",
+ .ops = &clk_ops_hfpll,
+ .vdd_class = &vdd_hfpll,
+ .fmax = hfpll_fmax,
+ .num_fmax = ARRAY_SIZE(hfpll_fmax),
+ CLK_INIT(hfpll1_clk.c),
+ },
+};
+
+DEFINE_KPSS_DIV2_CLK(hfpll1_div_clk, &hfpll1_clk.c, 0x5501, true);
+
+static struct hfpll_clk hfpll2_clk = {
+ .d = &hdata,
+ .src_rate = 19200000,
+ .c = {
+ .parent = &hfpll_src_clk.c,
+ .dbg_name = "hfpll2_clk",
+ .ops = &clk_ops_hfpll,
+ .vdd_class = &vdd_hfpll,
+ .fmax = hfpll_fmax,
+ .num_fmax = ARRAY_SIZE(hfpll_fmax),
+ CLK_INIT(hfpll2_clk.c),
+ },
+};
+
+DEFINE_KPSS_DIV2_CLK(hfpll2_div_clk, &hfpll2_clk.c, 0x6501, true);
+
+static struct hfpll_clk hfpll3_clk = {
+ .d = &hdata,
+ .src_rate = 19200000,
+ .c = {
+ .parent = &hfpll_src_clk.c,
+ .dbg_name = "hfpll3_clk",
+ .ops = &clk_ops_hfpll,
+ .vdd_class = &vdd_hfpll,
+ .fmax = hfpll_fmax,
+ .num_fmax = ARRAY_SIZE(hfpll_fmax),
+ CLK_INIT(hfpll3_clk.c),
+ },
+};
+
+DEFINE_KPSS_DIV2_CLK(hfpll3_div_clk, &hfpll3_clk.c, 0x7501, true);
+
+static struct hfpll_clk hfpll_l2_clk = {
+ .d = &hdata,
+ .src_rate = 19200000,
+ .c = {
+ .parent = &hfpll_src_clk.c,
+ .dbg_name = "hfpll_l2_clk",
+ .ops = &clk_ops_hfpll,
+ .vdd_class = &vdd_hfpll,
+ .fmax = hfpll_fmax,
+ .num_fmax = ARRAY_SIZE(hfpll_fmax),
+ CLK_INIT(hfpll_l2_clk.c),
+ },
+};
+
+DEFINE_KPSS_DIV2_CLK(hfpll_l2_div_clk, &hfpll_l2_clk.c, 0x500, false);
+
+#define SEC_MUX_COMMON_DATA \
+ .safe_parent = &acpu_aux_clk.c, \
+ .ops = &clk_mux_ops_kpss, \
+ .mask = 0x3, \
+ .shift = 2, \
+ MUX_SRC_LIST( \
+ {&acpu_aux_clk.c, 2}, \
+ {NULL /* QSB */, 0}, \
+ )
+
+static struct mux_clk krait0_sec_mux_clk = {
+ .offset = 0x4501,
+ .priv = (void *) true,
+ SEC_MUX_COMMON_DATA,
+ .c = {
+ .dbg_name = "krait0_sec_mux_clk",
+ .ops = &clk_ops_gen_mux,
+ CLK_INIT(krait0_sec_mux_clk.c),
+ },
+};
+
+static struct mux_clk krait1_sec_mux_clk = {
+ .offset = 0x5501,
+ .priv = (void *) true,
+ SEC_MUX_COMMON_DATA,
+ .c = {
+ .dbg_name = "krait1_sec_mux_clk",
+ .ops = &clk_ops_gen_mux,
+ CLK_INIT(krait1_sec_mux_clk.c),
+ },
+};
+
+static struct mux_clk krait2_sec_mux_clk = {
+ .offset = 0x6501,
+ .priv = (void *) true,
+ SEC_MUX_COMMON_DATA,
+ .c = {
+ .dbg_name = "krait2_sec_mux_clk",
+ .ops = &clk_ops_gen_mux,
+ CLK_INIT(krait2_sec_mux_clk.c),
+ },
+};
+
+static struct mux_clk krait3_sec_mux_clk = {
+ .offset = 0x7501,
+ .priv = (void *) true,
+ SEC_MUX_COMMON_DATA,
+ .c = {
+ .dbg_name = "krait3_sec_mux_clk",
+ .ops = &clk_ops_gen_mux,
+ CLK_INIT(krait3_sec_mux_clk.c),
+ },
+};
+
+static struct mux_clk l2_sec_mux_clk = {
+ .offset = 0x500,
+ SEC_MUX_COMMON_DATA,
+ .c = {
+ .dbg_name = "l2_sec_mux_clk",
+ .ops = &clk_ops_gen_mux,
+ CLK_INIT(l2_sec_mux_clk.c),
+ },
+};
+
+#define PRI_MUX_COMMON_DATA \
+ .ops = &clk_mux_ops_kpss, \
+ .mask = 0x3, \
+ .shift = 0
+
+static struct mux_clk krait0_pri_mux_clk = {
+ .offset = 0x4501,
+ .priv = (void *) true,
+ MUX_SRC_LIST(
+ { &hfpll0_clk.c, 1 },
+ { &hfpll0_div_clk.c, 2 },
+ { &krait0_sec_mux_clk.c, 0 },
+ ),
+ .safe_parent = &krait0_sec_mux_clk.c,
+ PRI_MUX_COMMON_DATA,
+ .c = {
+ .dbg_name = "krait0_pri_mux_clk",
+ .ops = &clk_ops_gen_mux,
+ CLK_INIT(krait0_pri_mux_clk.c),
+ },
+};
+
+static struct mux_clk krait1_pri_mux_clk = {
+ .offset = 0x5501,
+ .priv = (void *) true,
+ MUX_SRC_LIST(
+ { &hfpll1_clk.c, 1 },
+ { &hfpll1_div_clk.c, 2 },
+ { &krait1_sec_mux_clk.c, 0 },
+ ),
+ .safe_parent = &krait1_sec_mux_clk.c,
+ PRI_MUX_COMMON_DATA,
+ .c = {
+ .dbg_name = "krait1_pri_mux_clk",
+ .ops = &clk_ops_gen_mux,
+ CLK_INIT(krait1_pri_mux_clk.c),
+ },
+};
+
+static struct mux_clk krait2_pri_mux_clk = {
+ .offset = 0x6501,
+ .priv = (void *) true,
+ MUX_SRC_LIST(
+ { &hfpll2_clk.c, 1 },
+ { &hfpll2_div_clk.c, 2 },
+ { &krait2_sec_mux_clk.c, 0 },
+ ),
+ .safe_parent = &krait2_sec_mux_clk.c,
+ PRI_MUX_COMMON_DATA,
+ .c = {
+ .dbg_name = "krait2_pri_mux_clk",
+ .ops = &clk_ops_gen_mux,
+ CLK_INIT(krait2_pri_mux_clk.c),
+ },
+};
+
+static struct mux_clk krait3_pri_mux_clk = {
+ .offset = 0x7501,
+ .priv = (void *) true,
+ MUX_SRC_LIST(
+ { &hfpll3_clk.c, 1 },
+ { &hfpll3_div_clk.c, 2 },
+ { &krait3_sec_mux_clk.c, 0 },
+ ),
+ .safe_parent = &krait3_sec_mux_clk.c,
+ PRI_MUX_COMMON_DATA,
+ .c = {
+ .dbg_name = "krait3_pri_mux_clk",
+ .ops = &clk_ops_gen_mux,
+ CLK_INIT(krait3_pri_mux_clk.c),
+ },
+};
+
+static struct mux_clk l2_pri_mux_clk = {
+ .offset = 0x500,
+ MUX_SRC_LIST(
+ {&hfpll_l2_clk.c, 1 },
+ {&hfpll_l2_div_clk.c, 2},
+ {&l2_sec_mux_clk.c, 0}
+ ),
+ .safe_parent = &l2_sec_mux_clk.c,
+ PRI_MUX_COMMON_DATA,
+ .c = {
+ .dbg_name = "l2_pri_mux_clk",
+ .ops = &clk_ops_gen_mux,
+ CLK_INIT(l2_pri_mux_clk.c),
+ },
+};
+
+static struct avs_data avs_table;
+
+static DEFINE_VDD_REGS_INIT(vdd_krait0, 1);
+static DEFINE_VDD_REGS_INIT(vdd_krait1, 1);
+static DEFINE_VDD_REGS_INIT(vdd_krait2, 1);
+static DEFINE_VDD_REGS_INIT(vdd_krait3, 1);
+static DEFINE_VDD_REGS_INIT(vdd_l2, 1);
+
+/*
+ * This clock is mostly a dummy clock in the sense it can't really gate the
+ * CPU/L2 clocks or affect their frequency. It exists solely to:
+ *
+ * - Capture the PVS requirements for each CPU.
+ * - Implement HW clock gating disable ops needed for measuring the freq of
+ * Krait/L2 properly.
+ * - Implement AVS requirement.
+ */
+static struct kpss_core_clk krait0_clk = {
+ .id = 0,
+ .avs_tbl = &avs_table,
+ .c = {
+ .parent = &krait0_pri_mux_clk.c,
+ .dbg_name = "krait0_clk",
+ .ops = &clk_ops_kpss_cpu,
+ .vdd_class = &vdd_krait0,
+ CLK_INIT(krait0_clk.c),
+ },
+};
+
+static struct kpss_core_clk krait1_clk = {
+ .id = 1,
+ .avs_tbl = &avs_table,
+ .c = {
+ .parent = &krait1_pri_mux_clk.c,
+ .dbg_name = "krait1_clk",
+ .ops = &clk_ops_kpss_cpu,
+ .vdd_class = &vdd_krait1,
+ CLK_INIT(krait1_clk.c),
+ },
+};
+
+static struct kpss_core_clk krait2_clk = {
+ .id = 2,
+ .avs_tbl = &avs_table,
+ .c = {
+ .parent = &krait2_pri_mux_clk.c,
+ .dbg_name = "krait2_clk",
+ .ops = &clk_ops_kpss_cpu,
+ .vdd_class = &vdd_krait2,
+ CLK_INIT(krait2_clk.c),
+ },
+};
+
+static struct kpss_core_clk krait3_clk = {
+ .id = 3,
+ .avs_tbl = &avs_table,
+ .c = {
+ .parent = &krait3_pri_mux_clk.c,
+ .dbg_name = "krait3_clk",
+ .ops = &clk_ops_kpss_cpu,
+ .vdd_class = &vdd_krait3,
+ CLK_INIT(krait3_clk.c),
+ },
+};
+
+static struct kpss_core_clk l2_clk = {
+ .cp15_iaddr = 0x0500,
+ .c = {
+ .parent = &l2_pri_mux_clk.c,
+ .dbg_name = "l2_clk",
+ .ops = &clk_ops_kpss_l2,
+ .vdd_class = &vdd_l2,
+ CLK_INIT(l2_clk.c),
+ },
+};
+
+static struct clk_lookup kpss_clocks_8974[] = {
+ CLK_LOOKUP("", hfpll_src_clk.c, ""),
+ CLK_LOOKUP("", acpu_aux_clk.c, ""),
+ CLK_LOOKUP("", hfpll0_clk.c, ""),
+ CLK_LOOKUP("", hfpll0_div_clk.c, ""),
+ CLK_LOOKUP("", hfpll0_clk.c, ""),
+ CLK_LOOKUP("", hfpll1_div_clk.c, ""),
+ CLK_LOOKUP("", hfpll1_clk.c, ""),
+ CLK_LOOKUP("", hfpll2_div_clk.c, ""),
+ CLK_LOOKUP("", hfpll2_clk.c, ""),
+ CLK_LOOKUP("", hfpll3_div_clk.c, ""),
+ CLK_LOOKUP("", hfpll3_clk.c, ""),
+ CLK_LOOKUP("", hfpll_l2_div_clk.c, ""),
+ CLK_LOOKUP("", hfpll_l2_clk.c, ""),
+ CLK_LOOKUP("", krait0_sec_mux_clk.c, ""),
+ CLK_LOOKUP("", krait1_sec_mux_clk.c, ""),
+ CLK_LOOKUP("", krait2_sec_mux_clk.c, ""),
+ CLK_LOOKUP("", krait3_sec_mux_clk.c, ""),
+ CLK_LOOKUP("", l2_sec_mux_clk.c, ""),
+ CLK_LOOKUP("", krait0_pri_mux_clk.c, ""),
+ CLK_LOOKUP("", krait1_pri_mux_clk.c, ""),
+ CLK_LOOKUP("", krait2_pri_mux_clk.c, ""),
+ CLK_LOOKUP("", krait3_pri_mux_clk.c, ""),
+ CLK_LOOKUP("", l2_pri_mux_clk.c, ""),
+ CLK_LOOKUP("l2_clk", l2_clk.c, "0.qcom,msm-cpufreq"),
+ CLK_LOOKUP("cpu0_clk", krait0_clk.c, "0.qcom,msm-cpufreq"),
+ CLK_LOOKUP("cpu1_clk", krait1_clk.c, "0.qcom,msm-cpufreq"),
+ CLK_LOOKUP("cpu2_clk", krait2_clk.c, "0.qcom,msm-cpufreq"),
+ CLK_LOOKUP("cpu3_clk", krait3_clk.c, "0.qcom,msm-cpufreq"),
+ CLK_LOOKUP("l2_clk", l2_clk.c, "fe805664.qcom,pm-8x60"),
+ CLK_LOOKUP("cpu0_clk", krait0_clk.c, "fe805664.qcom,pm-8x60"),
+ CLK_LOOKUP("cpu1_clk", krait1_clk.c, "fe805664.qcom,pm-8x60"),
+ CLK_LOOKUP("cpu2_clk", krait2_clk.c, "fe805664.qcom,pm-8x60"),
+ CLK_LOOKUP("cpu3_clk", krait3_clk.c, "fe805664.qcom,pm-8x60"),
+};
+
+static struct clk *cpu_clk[] = {
+ &krait0_clk.c,
+ &krait1_clk.c,
+ &krait2_clk.c,
+ &krait3_clk.c,
+};
+
+static void get_krait_bin_format_b(struct platform_device *pdev,
+ int *speed, int *pvs, int *pvs_ver)
+{
+ u32 pte_efuse, redundant_sel;
+ struct resource *res;
+ void __iomem *base;
+
+ *speed = 0;
+ *pvs = 0;
+ *pvs_ver = 0;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "efuse");
+ if (!res) {
+ dev_info(&pdev->dev,
+ "No speed/PVS binning available. Defaulting to 0!\n");
+ return;
+ }
+
+ base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!base) {
+ dev_warn(&pdev->dev,
+ "Unable to read efuse data. Defaulting to 0!\n");
+ return;
+ }
+
+ pte_efuse = readl_relaxed(base);
+ redundant_sel = (pte_efuse >> 24) & 0x7;
+ *speed = pte_efuse & 0x7;
+ /* 4 bits of PVS are in efuse register bits 31, 8-6. */
+ *pvs = ((pte_efuse >> 28) & 0x8) | ((pte_efuse >> 6) & 0x7);
+ *pvs_ver = (pte_efuse >> 4) & 0x3;
+
+ switch (redundant_sel) {
+ case 1:
+ *speed = (pte_efuse >> 27) & 0xF;
+ break;
+ case 2:
+ *pvs = (pte_efuse >> 27) & 0xF;
+ break;
+ }
+
+ /* Check SPEED_BIN_BLOW_STATUS */
+ if (pte_efuse & BIT(3)) {
+ dev_info(&pdev->dev, "Speed bin: %d\n", *speed);
+ } else {
+ dev_warn(&pdev->dev, "Speed bin not set. Defaulting to 0!\n");
+ *speed = 0;
+ }
+
+ /* Check PVS_BLOW_STATUS */
+ pte_efuse = readl_relaxed(base + 0x4) & BIT(21);
+ if (pte_efuse) {
+ dev_info(&pdev->dev, "PVS bin: %d\n", *pvs);
+ } else {
+ dev_warn(&pdev->dev, "PVS bin not set. Defaulting to 0!\n");
+ *pvs = 0;
+ }
+
+ dev_info(&pdev->dev, "PVS version: %d\n", *pvs_ver);
+
+ devm_iounmap(&pdev->dev, base);
+}
+
+static int parse_tbl(struct device *dev, char *prop, int num_cols,
+ u32 **col1, u32 **col2, u32 **col3)
+{
+ int ret, prop_len, num_rows, i, j, k;
+ u32 *prop_data;
+ u32 *col[num_cols];
+
+ if (!of_find_property(dev->of_node, prop, &prop_len))
+ return -EINVAL;
+
+ prop_len /= sizeof(*prop_data);
+
+ if (prop_len % num_cols || prop_len == 0)
+ return -EINVAL;
+
+ num_rows = prop_len / num_cols;
+
+ prop_data = devm_kzalloc(dev, prop_len * sizeof(*prop_data),
+ GFP_KERNEL);
+ if (!prop_data)
+ return -ENOMEM;
+
+ for (i = 0; i < num_cols; i++) {
+ col[i] = devm_kzalloc(dev, num_rows * sizeof(u32), GFP_KERNEL);
+ if (!col[i])
+ return -ENOMEM;
+ }
+
+ ret = of_property_read_u32_array(dev->of_node, prop, prop_data,
+ prop_len);
+ if (ret)
+ return ret;
+
+ k = 0;
+ for (i = 0; i < num_rows; i++) {
+ for (j = 0; j < num_cols; j++)
+ col[j][i] = prop_data[k++];
+ }
+ if (col1)
+ *col1 = col[0];
+ if (col2)
+ *col2 = col[1];
+ if (col3)
+ *col3 = col[2];
+
+ devm_kfree(dev, prop_data);
+
+ return num_rows;
+}
+
+static int clk_init_vdd_class(struct device *dev, struct clk *clk, int num,
+ unsigned long *fmax, int *uv, int *ua)
+{
+ struct clk_vdd_class *vdd = clk->vdd_class;
+
+ vdd->level_votes = devm_kzalloc(dev, num * sizeof(int), GFP_KERNEL);
+ if (!vdd->level_votes) {
+ dev_err(dev, "Out of memory!\n");
+ return -ENOMEM;
+ }
+ vdd->num_levels = num;
+ vdd->cur_level = num;
+ vdd->vdd_uv = uv;
+ vdd->vdd_ua = ua;
+ clk->fmax = fmax;
+ clk->num_fmax = num;
+
+ return 0;
+}
+
+static int hfpll_base_init(struct platform_device *pdev, struct hfpll_clk *h)
+{
+ struct resource *res;
+ struct device *dev = &pdev->dev;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, h->c.dbg_name);
+ if (!res) {
+ dev_err(dev, "%s base addr not found!\n", h->c.dbg_name);
+ return -EINVAL;
+ }
+ h->base = devm_ioremap(dev, res->start, resource_size(res));
+ if (!h->base) {
+ dev_err(dev, "%s ioremap failed!\n", h->c.dbg_name);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+static bool enable_boost;
+module_param_named(boost, enable_boost, bool, S_IRUGO | S_IWUSR);
+
+static void krait_update_uv(int *uv, int num, int boost_uv)
+{
+ int i;
+
+ switch (read_cpuid_id()) {
+ case 0x511F04D0: /* KR28M2A20 */
+ case 0x511F04D1: /* KR28M2A21 */
+ case 0x510F06F0: /* KR28M4A10 */
+ for (i = 0; i < num; i++)
+ uv[i] = max(1150000, uv[i]);
+ };
+
+ if (enable_boost) {
+ for (i = 0; i < num; i++)
+ uv[i] += boost_uv;
+ }
+}
+
+static char table_name[] = "qcom,speedXX-pvsXX-bin-vXX";
+module_param_string(table_name, table_name, sizeof(table_name), S_IRUGO);
+static unsigned int pvs_config_ver;
+module_param(pvs_config_ver, uint, S_IRUGO);
+
+static int clock_krait_8974_driver_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct clk *c;
+ int speed, pvs, pvs_ver, config_ver, rows, cpu;
+ unsigned long *freq, cur_rate, aux_rate;
+ int *uv, *ua;
+ u32 *dscr, vco_mask, config_val;
+ int ret;
+
+ vdd_l2.regulator[0] = devm_regulator_get(dev, "l2-dig");
+ if (IS_ERR(vdd_l2.regulator[0])) {
+ dev_err(dev, "Unable to get l2-dig regulator!\n");
+ return PTR_ERR(vdd_l2.regulator[0]);
+ }
+
+ vdd_hfpll.regulator[0] = devm_regulator_get(dev, "hfpll-dig");
+ if (IS_ERR(vdd_hfpll.regulator[0])) {
+ dev_err(dev, "Unable to get hfpll-dig regulator!\n");
+ return PTR_ERR(vdd_hfpll.regulator[0]);
+ }
+
+ vdd_hfpll.regulator[1] = devm_regulator_get(dev, "hfpll-analog");
+ if (IS_ERR(vdd_hfpll.regulator[1])) {
+ dev_err(dev, "Unable to get hfpll-analog regulator!\n");
+ return PTR_ERR(vdd_hfpll.regulator[1]);
+ }
+
+ vdd_krait0.regulator[0] = devm_regulator_get(dev, "cpu0");
+ if (IS_ERR(vdd_krait0.regulator[0])) {
+ dev_err(dev, "Unable to get cpu0 regulator!\n");
+ return PTR_ERR(vdd_krait0.regulator[0]);
+ }
+
+ vdd_krait1.regulator[0] = devm_regulator_get(dev, "cpu1");
+ if (IS_ERR(vdd_krait1.regulator[0])) {
+ dev_err(dev, "Unable to get cpu1 regulator!\n");
+ return PTR_ERR(vdd_krait1.regulator[0]);
+ }
+
+ vdd_krait2.regulator[0] = devm_regulator_get(dev, "cpu2");
+ if (IS_ERR(vdd_krait2.regulator[0])) {
+ dev_err(dev, "Unable to get cpu2 regulator!\n");
+ return PTR_ERR(vdd_krait2.regulator[0]);
+ }
+
+ vdd_krait3.regulator[0] = devm_regulator_get(dev, "cpu3");
+ if (IS_ERR(vdd_krait3.regulator[0])) {
+ dev_err(dev, "Unable to get cpu3 regulator!\n");
+ return PTR_ERR(vdd_krait3.regulator[0]);
+ }
+
+ c = devm_clk_get(dev, "hfpll_src");
+ if (IS_ERR(c)) {
+ dev_err(dev, "Unable to get HFPLL source\n");
+ return PTR_ERR(c);
+ }
+ hfpll_src_clk.c.parent = c;
+
+ c = devm_clk_get(dev, "aux_clk");
+ if (IS_ERR(c)) {
+ dev_err(dev, "Unable to get AUX source\n");
+ return PTR_ERR(c);
+ }
+ acpu_aux_clk.c.parent = c;
+
+ if (hfpll_base_init(pdev, &hfpll0_clk))
+ return -EINVAL;
+ if (hfpll_base_init(pdev, &hfpll1_clk))
+ return -EINVAL;
+ if (hfpll_base_init(pdev, &hfpll2_clk))
+ return -EINVAL;
+ if (hfpll_base_init(pdev, &hfpll3_clk))
+ return -EINVAL;
+ if (hfpll_base_init(pdev, &hfpll_l2_clk))
+ return -EINVAL;
+
+ ret = of_property_read_u32(dev->of_node, "qcom,hfpll-config-val",
+ &config_val);
+ if (!ret)
+ hdata.config_val = config_val;
+
+ ret = of_property_read_u32(dev->of_node, "qcom,hfpll-user-vco-mask",
+ &vco_mask);
+ if (!ret)
+ hdata.user_vco_mask = vco_mask;
+
+ ret = of_property_read_u32(dev->of_node, "qcom,pvs-config-ver",
+ &config_ver);
+ if (!ret) {
+ pvs_config_ver = config_ver;
+ dev_info(&pdev->dev, "PVS config version: %d\n", config_ver);
+ }
+
+ get_krait_bin_format_b(pdev, &speed, &pvs, &pvs_ver);
+ snprintf(table_name, ARRAY_SIZE(table_name),
+ "qcom,speed%d-pvs%d-bin-v%d", speed, pvs, pvs_ver);
+
+ rows = parse_tbl(dev, table_name, 3,
+ (u32 **) &freq, (u32 **) &uv, (u32 **) &ua);
+ if (rows < 0) {
+ /* Fall back to most conservative PVS table */
+ dev_err(dev, "Unable to load voltage plan %s!\n", table_name);
+ ret = parse_tbl(dev, "qcom,speed0-pvs0-bin-v0", 3,
+ (u32 **) &freq, (u32 **) &uv, (u32 **) &ua);
+ if (ret < 0) {
+ dev_err(dev, "Unable to load safe voltage plan\n");
+ return rows;
+ } else {
+ dev_info(dev, "Safe voltage plan loaded.\n");
+ pvs = 0;
+ rows = ret;
+ }
+ }
+
+ krait_update_uv(uv, rows, pvs ? 25000 : 0);
+
+ if (clk_init_vdd_class(dev, &krait0_clk.c, rows, freq, uv, ua))
+ return -ENOMEM;
+ if (clk_init_vdd_class(dev, &krait1_clk.c, rows, freq, uv, ua))
+ return -ENOMEM;
+ if (clk_init_vdd_class(dev, &krait2_clk.c, rows, freq, uv, ua))
+ return -ENOMEM;
+ if (clk_init_vdd_class(dev, &krait3_clk.c, rows, freq, uv, ua))
+ return -ENOMEM;
+
+ /* AVS is optional */
+ rows = parse_tbl(dev, "qcom,avs-tbl", 2, (u32 **) &freq, &dscr, NULL);
+ if (rows > 0) {
+ avs_table.rate = freq;
+ avs_table.dscr = dscr;
+ avs_table.num = rows;
+ }
+
+ rows = parse_tbl(dev, "qcom,l2-fmax", 2, (u32 **) &freq, (u32 **) &uv,
+ NULL);
+ if (rows < 0) {
+ dev_err(dev, "Unable to find L2 Fmax table!\n");
+ return rows;
+ }
+
+ if (clk_init_vdd_class(dev, &l2_clk.c, rows, freq, uv, NULL))
+ return -ENOMEM;
+
+ msm_clock_register(kpss_clocks_8974, ARRAY_SIZE(kpss_clocks_8974));
+
+ /*
+ * We don't want the CPU or L2 clocks to be turned off at late init
+ * if CPUFREQ or HOTPLUG configs are disabled. So, bump up the
+ * refcount of these clocks. Any cpufreq/hotplug manager can assume
+ * that the clocks have already been prepared and enabled by the time
+ * they take over.
+ */
+ for_each_online_cpu(cpu) {
+ clk_prepare_enable(&l2_clk.c);
+ WARN(clk_prepare_enable(cpu_clk[cpu]),
+ "Unable to turn on CPU%d clock", cpu);
+ }
+
+ /*
+ * Force reinit of HFPLLs and muxes to overwrite any potential
+ * incorrect configuration of HFPLLs and muxes by the bootloader.
+ * While at it, also make sure the cores are running at known rates
+ * and print the current rate.
+ *
+ * The clocks are set to aux clock rate first to make sure the
+ * secondary mux is not sourcing off of QSB. The rate is then set to
+ * two different rates to force a HFPLL reinit under all
+ * circumstances.
+ */
+ cur_rate = clk_get_rate(&l2_clk.c);
+ aux_rate = clk_get_rate(&acpu_aux_clk.c);
+ if (!cur_rate) {
+ pr_info("L2 @ unknown rate. Forcing new rate.\n");
+ cur_rate = aux_rate;
+ }
+ clk_set_rate(&l2_clk.c, aux_rate);
+ clk_set_rate(&l2_clk.c, clk_round_rate(&l2_clk.c, 1));
+ clk_set_rate(&l2_clk.c, cur_rate);
+ pr_info("L2 @ %lu KHz\n", clk_get_rate(&l2_clk.c) / 1000);
+ for_each_possible_cpu(cpu) {
+ struct clk *c = cpu_clk[cpu];
+ cur_rate = clk_get_rate(c);
+ if (!cur_rate) {
+ pr_info("CPU%d @ unknown rate. Forcing new rate.\n",
+ cpu);
+ cur_rate = aux_rate;
+ }
+ clk_set_rate(c, aux_rate);
+ clk_set_rate(c, clk_round_rate(c, 1));
+ clk_set_rate(c, clk_round_rate(c, cur_rate));
+ pr_info("CPU%d @ %lu KHz\n", cpu, clk_get_rate(c) / 1000);
+ }
+
+ return 0;
+}
+
+static struct of_device_id match_table[] = {
+ { .compatible = "qcom,clock-krait-8974" },
+ {}
+};
+
+static struct platform_driver clock_krait_8974_driver = {
+ .probe = clock_krait_8974_driver_probe,
+ .driver = {
+ .name = "clock-krait-8974",
+ .of_match_table = match_table,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init clock_krait_8974_init(void)
+{
+ return platform_driver_register(&clock_krait_8974_driver);
+}
+module_init(clock_krait_8974_init);
+
+static void __exit clock_krait_8974_exit(void)
+{
+ platform_driver_unregister(&clock_krait_8974_driver);
+}
+module_exit(clock_krait_8974_exit);
+
+MODULE_DESCRIPTION("Krait CPU clock driver for 8974");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/clock-krait.c b/arch/arm/mach-msm/clock-krait.c
index b96ba62..cdd53e5 100644
--- a/arch/arm/mach-msm/clock-krait.c
+++ b/arch/arm/mach-msm/clock-krait.c
@@ -29,6 +29,7 @@
static DEFINE_SPINLOCK(kpss_clock_reg_lock);
+#define LPL_SHIFT 8
static void __kpss_mux_set_sel(struct mux_clk *mux, int sel)
{
unsigned long flags;
@@ -38,6 +39,10 @@
regval = get_l2_indirect_reg(mux->offset);
regval &= ~(mux->mask << mux->shift);
regval |= (sel & mux->mask) << mux->shift;
+ if (mux->priv) {
+ regval &= ~(mux->mask << (mux->shift + LPL_SHIFT));
+ regval |= (sel & mux->mask) << (mux->shift + LPL_SHIFT);
+ }
set_l2_indirect_reg(mux->offset, regval);
spin_unlock_irqrestore(&kpss_clock_reg_lock, flags);
@@ -95,8 +100,10 @@
spin_lock_irqsave(&kpss_clock_reg_lock, flags);
regval = get_l2_indirect_reg(div->offset);
- val = (regval >> div->shift) && div->mask;
+ val = (regval >> div->shift) & div->mask;
regval &= ~(div->mask << div->shift);
+ if (div->priv)
+ regval &= ~(div->mask << (div->shift + LPL_SHIFT));
set_l2_indirect_reg(div->offset, regval);
spin_unlock_irqrestore(&kpss_clock_reg_lock, flags);
@@ -123,7 +130,8 @@
return;
/* Configure PLL parameters for integer mode. */
- writel_relaxed(hd->config_val, h->base + hd->config_offset);
+ if (hd->config_val)
+ writel_relaxed(hd->config_val, h->base + hd->config_offset);
writel_relaxed(0, h->base + hd->m_offset);
writel_relaxed(1, h->base + hd->n_offset);
@@ -134,7 +142,7 @@
rate = readl_relaxed(h->base + hd->l_offset) * h->src_rate;
/* Pick the right VCO. */
- if (rate > hd->low_vco_max_rate)
+ if (hd->user_vco_mask && rate > hd->low_vco_max_rate)
regval |= hd->user_vco_mask;
writel_relaxed(regval, h->base + hd->user_offset);
}
@@ -243,7 +251,7 @@
hfpll_clk_disable(c);
/* Pick the right VCO. */
- if (hd->user_offset) {
+ if (hd->user_offset && hd->user_vco_mask) {
u32 regval;
regval = readl_relaxed(h->base + hd->user_offset);
if (rate <= hd->low_vco_max_rate)
@@ -394,9 +402,6 @@
struct kpss_core_clk *cpu = to_kpss_core_clk(c);
u32 dscr = find_dscr(cpu->avs_tbl, c->rate);
- if (!c->prepare_count)
- return -ENODEV;
-
if (dscr)
AVS_DISABLE(cpu->id);
return 0;
@@ -412,9 +417,6 @@
static int kpss_core_set_rate(struct clk *c, unsigned long rate)
{
- if (!c->prepare_count)
- return -ENODEV;
-
return clk_set_rate(c->parent, rate);
}
diff --git a/arch/arm/mach-msm/clock-krait.h b/arch/arm/mach-msm/clock-krait.h
index 2691a8c..07b72d5 100644
--- a/arch/arm/mach-msm/clock-krait.h
+++ b/arch/arm/mach-msm/clock-krait.h
@@ -20,15 +20,18 @@
extern struct clk_mux_ops clk_mux_ops_kpss;
extern struct clk_div_ops clk_div_ops_kpss_div2;
-#define DEFINE_KPSS_DIV2_CLK(clk_name, _parent, _offset) \
+#define DEFINE_KPSS_DIV2_CLK(clk_name, _parent, _offset, _lf_tree) \
static struct div_clk clk_name = { \
- .div = 2, \
- .min_div = 2, \
- .max_div = 2, \
+ .data = { \
+ .div = 2, \
+ .min_div = 2, \
+ .max_div = 2, \
+ }, \
.ops = &clk_div_ops_kpss_div2, \
.offset = _offset, \
.mask = 0x3, \
.shift = 6, \
+ .priv = (void *) _lf_tree, \
.c = { \
.parent = _parent, \
.dbg_name = #clk_name, \
@@ -49,9 +52,9 @@
const u32 status_offset;
const u32 droop_val;
- const u32 config_val;
+ u32 config_val;
const u32 user_val;
- const u32 user_vco_mask;
+ u32 user_vco_mask;
unsigned long low_vco_max_rate;
unsigned long min_rate;
diff --git a/arch/arm/mach-msm/clock-krypton.c b/arch/arm/mach-msm/clock-krypton.c
index 176dc32..2b529b0 100644
--- a/arch/arm/mach-msm/clock-krypton.c
+++ b/arch/arm/mach-msm/clock-krypton.c
@@ -515,6 +515,7 @@
F( 56000000, gpll0, 1, 7, 75),
F( 58982400, gpll0, 1, 1536, 15625),
F( 60000000, gpll0, 10, 0, 0),
+ F( 63160000, gpll0, 9.5, 0, 0),
F_END
};
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index 4488869..e3693ee 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -25,6 +25,7 @@
#include <mach/clk.h>
#include <mach/clk-provider.h>
+#include <mach/clock-generic.h>
#include "clock-local2.h"
@@ -640,6 +641,74 @@
return HANDOFF_ENABLED_CLK;
}
+struct frac_entry {
+ int num;
+ int den;
+};
+
+static struct frac_entry frac_table_675m[] = { /* link rate of 270M */
+ {52, 295}, /* 119 M */
+ {11, 57}, /* 130.25 M */
+ {63, 307}, /* 138.50 M */
+ {11, 50}, /* 148.50 M */
+ {47, 206}, /* 154 M */
+ {31, 100}, /* 205.25 M */
+ {107, 269}, /* 268.50 M */
+ {0, 0},
+};
+
+static struct frac_entry frac_table_810m[] = { /* Link rate of 162M */
+ {31, 211}, /* 119 M */
+ {32, 199}, /* 130.25 M */
+ {63, 307}, /* 138.50 M */
+ {11, 60}, /* 148.50 M */
+ {50, 263}, /* 154 M */
+ {31, 120}, /* 205.25 M */
+ {119, 359}, /* 268.50 M */
+ {0, 0},
+};
+
+static int set_rate_edp_pixel(struct clk *clk, unsigned long rate)
+{
+ struct rcg_clk *rcg = to_rcg_clk(clk);
+ struct clk_freq_tbl *pixel_freq = rcg->current_freq;
+ struct frac_entry *frac;
+ int delta = 100000;
+ s64 request;
+ s64 src_rate;
+
+ src_rate = clk_get_rate(clk->parent);
+
+ if (src_rate == 810000000)
+ frac = frac_table_810m;
+ else
+ frac = frac_table_675m;
+
+ while (frac->num) {
+ request = rate;
+ request *= frac->den;
+ request = div_s64(request, frac->num);
+ if ((src_rate < (request - delta)) ||
+ (src_rate > (request + delta))) {
+ frac++;
+ continue;
+ }
+
+ pixel_freq->div_src_val &= ~BM(4, 0);
+ if (frac->den == frac->num) {
+ pixel_freq->m_val = 0;
+ pixel_freq->n_val = 0;
+ } else {
+ pixel_freq->m_val = frac->num;
+ pixel_freq->n_val = ~(frac->den - frac->num);
+ pixel_freq->d_val = ~frac->den;
+ }
+ set_rate_mnd(rcg, pixel_freq);
+ return 0;
+ }
+ return -EINVAL;
+}
+
enum handoff byte_rcg_handoff(struct clk *clk)
{
struct rcg_clk *rcg = to_rcg_clk(clk);
@@ -774,175 +843,120 @@
*/
static int rcg_clk_set_rate_hdmi(struct clk *c, unsigned long rate)
{
- struct clk_freq_tbl *nf;
struct rcg_clk *rcg = to_rcg_clk(c);
+ struct clk_freq_tbl *nf = rcg->freq_tbl;
int rc;
- for (nf = rcg->freq_tbl; nf->freq_hz != rate; nf++)
- if (nf->freq_hz == FREQ_END) {
- rc = -EINVAL;
- goto out;
- }
-
rc = clk_set_rate(nf->src_clk, rate);
if (rc < 0)
goto out;
set_rate_hid(rcg, nf);
rcg->current_freq = nf;
- c->parent = nf->src_clk;
out:
return rc;
}
-
-#define ENABLE_REG(x) (*(x)->base + (x)->enable_reg)
-#define SELECT_REG(x) (*(x)->base + (x)->select_reg)
-
-/*
- * mux clock functions
- */
-static void cam_mux_clk_halt_check(void)
+static struct clk *edp_clk_get_parent(struct clk *c)
{
- /* Ensure that the delay starts after the mux disable/enable. */
- mb();
- udelay(HALT_CHECK_DELAY_US);
+ struct rcg_clk *rcg = to_rcg_clk(c);
+ struct clk *clk;
+ struct clk_freq_tbl *freq;
+ uint32_t rate;
+
+ /* Figure out what rate the rcg is running at */
+ for (freq = rcg->freq_tbl; freq->freq_hz != FREQ_END; freq++) {
+ clk = freq->src_clk;
+ if (clk && clk->ops->get_rate) {
+ rate = clk->ops->get_rate(clk);
+ if (rate == freq->freq_hz)
+ break;
+ }
+ }
+
+ /* No known frequency found */
+ if (freq->freq_hz == FREQ_END)
+ return NULL;
+
+ rcg->current_freq = freq;
+ return freq->src_clk;
}
-static int cam_mux_clk_enable(struct clk *c)
+static struct clk *rcg_hdmi_clk_get_parent(struct clk *c)
{
- unsigned long flags;
+ struct rcg_clk *rcg = to_rcg_clk(c);
+ struct clk_freq_tbl *freq = rcg->freq_tbl;
+ u32 cmd_rcgr_regval;
+
+ /* Is there a pending configuration? */
+ cmd_rcgr_regval = readl_relaxed(CMD_RCGR_REG(rcg));
+ if (cmd_rcgr_regval & CMD_RCGR_CONFIG_DIRTY_MASK)
+ return NULL;
+
+ rcg->current_freq->freq_hz = clk_get_rate(c->parent);
+
+ return freq->src_clk;
+}
+
+static DEFINE_SPINLOCK(mux_reg_lock);
+
+static int mux_reg_enable(struct mux_clk *clk)
+{
u32 regval;
- struct cam_mux_clk *mux = to_cam_mux_clk(c);
+ unsigned long flags;
+ u32 offset = clk->en_reg ? clk->en_offset : clk->offset;
- spin_lock_irqsave(&local_clock_reg_lock, flags);
- regval = readl_relaxed(ENABLE_REG(mux));
- regval |= mux->enable_mask;
- writel_relaxed(regval, ENABLE_REG(mux));
- spin_unlock_irqrestore(&local_clock_reg_lock, flags);
-
- /* Wait for clock to enable before continuing. */
- cam_mux_clk_halt_check();
+ spin_lock_irqsave(&mux_reg_lock, flags);
+ regval = readl_relaxed(*clk->base + offset);
+ regval |= clk->en_mask;
+ writel_relaxed(regval, *clk->base + offset);
+ /* Ensure enable request goes through before returning */
+ mb();
+ spin_unlock_irqrestore(&mux_reg_lock, flags);
return 0;
}
-static void cam_mux_clk_disable(struct clk *c)
+static void mux_reg_disable(struct mux_clk *clk)
{
- unsigned long flags;
- struct cam_mux_clk *mux = to_cam_mux_clk(c);
u32 regval;
+ unsigned long flags;
+ u32 offset = clk->en_reg ? clk->en_offset : clk->offset;
- spin_lock_irqsave(&local_clock_reg_lock, flags);
- regval = readl_relaxed(ENABLE_REG(mux));
- regval &= ~mux->enable_mask;
- writel_relaxed(regval, ENABLE_REG(mux));
- spin_unlock_irqrestore(&local_clock_reg_lock, flags);
-
- /* Wait for clock to disable before continuing. */
- cam_mux_clk_halt_check();
+ spin_lock_irqsave(&mux_reg_lock, flags);
+ regval = readl_relaxed(*clk->base + offset);
+ regval &= ~clk->en_mask;
+ writel_relaxed(regval, *clk->base + offset);
+ spin_unlock_irqrestore(&mux_reg_lock, flags);
}
-static int mux_source_switch(struct cam_mux_clk *mux, struct mux_source *dest)
+static int mux_reg_set_mux_sel(struct mux_clk *clk, int sel)
{
- unsigned long flags;
u32 regval;
- int ret = 0;
+ unsigned long flags;
- ret = __clk_pre_reparent(&mux->c, dest->clk, &flags);
- if (ret)
- goto out;
-
- regval = readl_relaxed(SELECT_REG(mux));
- regval &= ~mux->select_mask;
- regval |= dest->select_val;
- writel_relaxed(regval, SELECT_REG(mux));
-
- /* Make sure switch request goes through before proceeding. */
+ spin_lock_irqsave(&mux_reg_lock, flags);
+ regval = readl_relaxed(*clk->base + clk->offset);
+ regval &= ~(clk->mask << clk->shift);
+ regval |= (sel & clk->mask) << clk->shift;
+ writel_relaxed(regval, *clk->base + clk->offset);
+ /* Ensure switch request goes through before returning */
mb();
-
- __clk_post_reparent(&mux->c, mux->c.parent, &flags);
-out:
- return ret;
-}
-
-static int cam_mux_clk_set_parent(struct clk *c, struct clk *parent)
-{
- struct cam_mux_clk *mux = to_cam_mux_clk(c);
- struct mux_source *dest = NULL;
- int ret;
-
- if (!mux->sources || !parent)
- return -EPERM;
-
- dest = mux->sources;
-
- while (dest->clk) {
- if (dest->clk == parent)
- break;
- dest++;
- }
-
- if (!dest->clk)
- return -EPERM;
-
- ret = mux_source_switch(mux, dest);
- if (ret)
- return ret;
-
- mux->c.rate = clk_get_rate(dest->clk);
+ spin_unlock_irqrestore(&mux_reg_lock, flags);
return 0;
}
-static enum handoff cam_mux_clk_handoff(struct clk *c)
+static int mux_reg_get_mux_sel(struct mux_clk *clk)
{
- struct cam_mux_clk *mux = to_cam_mux_clk(c);
- u32 mask = mux->enable_mask;
- u32 regval = readl_relaxed(ENABLE_REG(mux));
-
- c->rate = clk_get_rate(c->parent);
-
- if (mask == (regval & mask))
- return HANDOFF_ENABLED_CLK;
-
- return HANDOFF_DISABLED_CLK;
+ u32 regval = readl_relaxed(*clk->base + clk->offset);
+ return !!((regval >> clk->shift) & clk->mask);
}
-static struct clk *cam_mux_clk_get_parent(struct clk *c)
+static bool mux_reg_is_enabled(struct mux_clk *clk)
{
- struct cam_mux_clk *mux = to_cam_mux_clk(c);
- struct mux_source *parent = NULL;
- u32 regval = readl_relaxed(SELECT_REG(mux));
-
- if (!mux->sources)
- return ERR_PTR(-EPERM);
-
- parent = mux->sources;
-
- while (parent->clk) {
- if ((regval & mux->select_mask) == parent->select_val)
- return parent->clk;
-
- parent++;
- }
-
- return ERR_PTR(-EPERM);
-}
-
-static long cam_mux_clk_list_rate(struct clk *c, unsigned n)
-{
- struct cam_mux_clk *mux = to_cam_mux_clk(c);
- int i;
-
- for (i = 0; i < n; i++)
- if (!mux->sources[i].clk)
- break;
-
- if (!mux->sources[i].clk)
- return -ENXIO;
-
- return clk_get_rate(mux->sources[i].clk);
+ u32 regval = readl_relaxed(*clk->base + clk->offset);
+ return !!(regval & clk->en_mask);
}
struct clk_ops clk_ops_empty;
@@ -973,6 +987,14 @@
.handoff = pixel_rcg_handoff,
};
+struct clk_ops clk_ops_edppixel = {
+ .enable = rcg_clk_prepare,
+ .set_rate = set_rate_edp_pixel,
+ .list_rate = rcg_clk_list_rate,
+ .round_rate = rcg_clk_round_rate,
+ .handoff = pixel_rcg_handoff,
+};
+
struct clk_ops clk_ops_byte = {
.enable = rcg_clk_prepare,
.set_rate = set_rate_byte,
@@ -987,7 +1009,16 @@
.list_rate = rcg_clk_list_rate,
.round_rate = rcg_clk_round_rate,
.handoff = rcg_clk_handoff,
- .get_parent = rcg_clk_get_parent,
+ .get_parent = rcg_hdmi_clk_get_parent,
+};
+
+struct clk_ops clk_ops_rcg_edp = {
+ .enable = rcg_clk_prepare,
+ .set_rate = rcg_clk_set_rate_hdmi,
+ .list_rate = rcg_clk_list_rate,
+ .round_rate = rcg_clk_round_rate,
+ .handoff = rcg_clk_handoff,
+ .get_parent = edp_clk_get_parent,
};
struct clk_ops clk_ops_branch = {
@@ -1009,13 +1040,10 @@
.handoff = local_vote_clk_handoff,
};
-struct clk_ops clk_ops_cam_mux = {
- .enable = cam_mux_clk_enable,
- .disable = cam_mux_clk_disable,
- .set_parent = cam_mux_clk_set_parent,
- .get_parent = cam_mux_clk_get_parent,
- .handoff = cam_mux_clk_handoff,
- .list_rate = cam_mux_clk_list_rate,
+struct clk_mux_ops mux_reg_ops = {
+ .enable = mux_reg_enable,
+ .disable = mux_reg_disable,
+ .set_mux_sel = mux_reg_set_mux_sel,
+ .get_mux_sel = mux_reg_get_mux_sel,
+ .is_enabled = mux_reg_is_enabled,
};
-
-
diff --git a/arch/arm/mach-msm/clock-local2.h b/arch/arm/mach-msm/clock-local2.h
index cee5b8c..35fb6fa 100644
--- a/arch/arm/mach-msm/clock-local2.h
+++ b/arch/arm/mach-msm/clock-local2.h
@@ -157,38 +157,6 @@
return container_of(clk, struct measure_clk, c);
}
-struct mux_source {
- struct clk *const clk;
- const u32 select_val;
-};
-
-/**
- * struct cam_mux_clk - branch clock
- * @c: clk
- * @enable_reg: register that contains the enable bit(s) for the mux
- * @select_reg: register that contains the source selection bits for the mux
- * @enable_mask: mask that enables the mux
- * @select_mask: mask for the source selection bits
- * @sources: list of mux sources
- * @base: pointer to base address of ioremapped registers.
- */
-struct cam_mux_clk {
- struct clk c;
- const u32 enable_reg;
- const u32 select_reg;
- const u32 enable_mask;
- const u32 select_mask;
-
- struct mux_source *sources;
-
- void *const __iomem *base;
-};
-
-static inline struct cam_mux_clk *to_cam_mux_clk(struct clk *clk)
-{
- return container_of(clk, struct cam_mux_clk, c);
-}
-
/*
* Generic set-rate implementations
*/
@@ -200,15 +168,17 @@
*/
extern spinlock_t local_clock_reg_lock;
-extern struct clk_ops clk_ops_cam_mux;
extern struct clk_ops clk_ops_empty;
extern struct clk_ops clk_ops_rcg;
extern struct clk_ops clk_ops_rcg_mnd;
extern struct clk_ops clk_ops_branch;
extern struct clk_ops clk_ops_vote;
extern struct clk_ops clk_ops_rcg_hdmi;
+extern struct clk_ops clk_ops_rcg_edp;
extern struct clk_ops clk_ops_byte;
extern struct clk_ops clk_ops_pixel;
+extern struct clk_mux_ops mux_reg_ops;
+extern struct clk_ops clk_ops_edppixel;
enum handoff pixel_rcg_handoff(struct clk *clk);
enum handoff byte_rcg_handoff(struct clk *clk);
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index cf2df18..3ea719f 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -37,6 +37,9 @@
#define DSI_PHY_PHYS 0xFD922A00
#define DSI_PHY_SIZE 0x000000D4
+#define EDP_PHY_PHYS 0xFD923A00
+#define EDP_PHY_SIZE 0x000000D4
+
#define HDMI_PHY_PHYS 0xFD922500
#define HDMI_PHY_SIZE 0x0000007C
@@ -148,11 +151,13 @@
#define PLL_POLL_MAX_READS 10
#define PLL_POLL_TIMEOUT_US 50
+#define SEQ_M_MAX_COUNTER 7
static long vco_cached_rate;
static unsigned char *mdss_dsi_base;
static unsigned char *gdsc_base;
static struct clk *mdss_ahb_clk;
+static unsigned char *mdss_edp_base;
static void __iomem *hdmi_phy_base;
static void __iomem *hdmi_phy_pll_base;
@@ -167,23 +172,71 @@
(!(readl_relaxed(gdsc_base) & BIT(0)));
}
-void hdmi_pll_disable(void)
+/* Auto PLL calibaration */
+static int mdss_ahb_clk_enable(int enable)
{
- clk_enable(mdss_ahb_clk);
+ int rc = 0;
+
+ /* todo: Ideally, we should enable/disable GDSC whenever we are
+ * attempting to enable/disable MDSS AHB clock.
+ * For now, just return error if GDSC is not enabled.
+ */
+ if (!mdss_gdsc_enabled()) {
+ pr_err("%s: mdss GDSC is not enabled\n", __func__);
+ return -EPERM;
+ }
+
+ if (enable)
+ rc = clk_prepare_enable(mdss_ahb_clk);
+ else
+ clk_disable_unprepare(mdss_ahb_clk);
+
+ return rc;
+}
+
+static void hdmi_vco_disable(struct clk *c)
+{
+ u32 rc;
+
+ if (!mdss_gdsc_enabled()) {
+ pr_err("%s: mdss GDSC is not enabled\n", __func__);
+ return;
+ }
+
+ rc = clk_enable(mdss_ahb_clk);
+ if (rc) {
+ pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+ __func__, rc);
+ return;
+ }
+
REG_W(0x0, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
udelay(5);
REG_W(0x0, hdmi_phy_base + HDMI_PHY_GLB_CFG);
+
clk_disable(mdss_ahb_clk);
hdmi_pll_on = 0;
-} /* hdmi_pll_disable */
+} /* hdmi_vco_disable */
-int hdmi_pll_enable(void)
+static int hdmi_vco_enable(struct clk *c)
{
u32 status;
+ u32 rc;
u32 max_reads, timeout_us;
- clk_enable(mdss_ahb_clk);
+ if (!mdss_gdsc_enabled()) {
+ pr_err("%s: mdss GDSC is not enabled\n", __func__);
+ return -EPERM;
+ }
+
+ rc = clk_enable(mdss_ahb_clk);
+ if (rc) {
+ pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
/* Global Enable */
REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
/* Power up power gen */
@@ -208,7 +261,7 @@
status, ((status & BIT(0)) == 1), max_reads, timeout_us)) {
pr_err("%s: hdmi phy pll status=%x failed to Lock\n",
__func__, status);
- hdmi_pll_disable();
+ hdmi_vco_disable(c);
clk_disable(mdss_ahb_clk);
return -EINVAL;
}
@@ -222,7 +275,7 @@
status, ((status & BIT(0)) == 1), max_reads, timeout_us)) {
pr_err("%s: hdmi phy status=%x failed to Lock\n",
__func__, status);
- hdmi_pll_disable();
+ hdmi_vco_disable(c);
clk_disable(mdss_ahb_clk);
return -EINVAL;
}
@@ -232,25 +285,173 @@
hdmi_pll_on = 1;
return 0;
-} /* hdmi_pll_enable */
+} /* hdmi_vco_enable */
-int hdmi_pll_set_rate(unsigned long rate)
+static inline struct hdmi_pll_vco_clk *to_hdmi_vco_clk(struct clk *clk)
+{
+ return container_of(clk, struct hdmi_pll_vco_clk, c);
+}
+
+static void hdmi_phy_pll_calculator(u32 vco_freq)
+{
+ u32 ref_clk = 19200000;
+ u32 sdm_mode = 1;
+ u32 ref_clk_multiplier = sdm_mode == 1 ? 2 : 1;
+ u32 int_ref_clk_freq = ref_clk * ref_clk_multiplier;
+ u32 fbclk_pre_div = 1;
+ u32 ssc_mode = 0;
+ u32 kvco = 270;
+ u32 vdd = 95;
+ u32 ten_power_six = 1000000;
+ u32 ssc_ds_ppm = ssc_mode ? 5000 : 0;
+ u32 sdm_res = 16;
+ u32 ssc_tri_step = 32;
+ u32 ssc_freq = 2;
+ u64 ssc_ds = vco_freq * ssc_ds_ppm;
+ u32 div_in_freq = vco_freq / fbclk_pre_div;
+ u64 dc_offset = (div_in_freq / int_ref_clk_freq - 1) *
+ ten_power_six * 10;
+ u32 ssc_kdiv = (int_ref_clk_freq / ssc_freq) -
+ ten_power_six;
+ u64 sdm_freq_seed;
+ u32 ssc_tri_inc;
+ u64 fb_div_n;
+
+ u32 val;
+
+ pr_debug("%s: vco_freq = %u\n", __func__, vco_freq);
+
+ do_div(ssc_ds, (u64)ten_power_six);
+
+ fb_div_n = (u64)div_in_freq * (u64)ten_power_six * 10;
+ do_div(fb_div_n, int_ref_clk_freq);
+
+ sdm_freq_seed = ((fb_div_n - dc_offset - ten_power_six * 10) *
+ (1 << sdm_res) * 10) + 5;
+ do_div(sdm_freq_seed, ((u64)ten_power_six * 100));
+
+ ssc_tri_inc = (u32)ssc_ds;
+ ssc_tri_inc = (ssc_tri_inc / int_ref_clk_freq) * (1 << 16) /
+ ssc_tri_step;
+
+ val = (ref_clk_multiplier == 2 ? 1 : 0) +
+ ((fbclk_pre_div == 2 ? 1 : 0) * 16);
+ pr_debug("%s: HDMI_UNI_PLL_REFCLK_CFG = 0x%x\n", __func__, val);
+ REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CFG);
+
+ REG_W(0x02, hdmi_phy_pll_base + HDMI_UNI_PLL_CHFPUMP_CFG);
+ REG_W(0x19, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
+ REG_W(0x04, hdmi_phy_pll_base + HDMI_UNI_PLL_VREG_CFG);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_PWRGEN_CFG);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
+ REG_W(0x0E, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFR_CFG);
+ REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC1_CFG);
+ REG_W(0x0D, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC2_CFG);
+
+ do_div(dc_offset, (u64)ten_power_six * 10);
+ val = sdm_mode == 0 ? 64 + dc_offset : 0;
+ pr_debug("%s: HDMI_UNI_PLL_SDM_CFG0 = 0x%x\n", __func__, val);
+ REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
+
+ val = 64 + dc_offset;
+ pr_debug("%s: HDMI_UNI_PLL_SDM_CFG1 = 0x%x\n", __func__, val);
+ REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
+
+ val = sdm_freq_seed & 0xFF;
+ pr_debug("%s: HDMI_UNI_PLL_SDM_CFG2 = 0x%x\n", __func__, val);
+ REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
+
+ val = (sdm_freq_seed >> 8) & 0xFF;
+ pr_debug("%s: HDMI_UNI_PLL_SDM_CFG3 = 0x%x\n", __func__, val);
+ REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
+
+ val = (sdm_freq_seed >> 16) & 0xFF;
+ pr_debug("%s: HDMI_UNI_PLL_SDM_CFG4 = 0x%x\n", __func__, val);
+ REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG4);
+
+ val = (ssc_mode == 0 ? 128 : 0) + (ssc_kdiv / ten_power_six);
+ pr_debug("%s: HDMI_UNI_PLL_SSC_CFG0 = 0x%x\n", __func__, val);
+ REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_SSC_CFG0);
+
+ val = ssc_tri_inc & 0xFF;
+ pr_debug("%s: HDMI_UNI_PLL_SSC_CFG1 = 0x%x\n", __func__, val);
+ REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_SSC_CFG1);
+
+ val = (ssc_tri_inc >> 8) & 0xFF;
+ pr_debug("%s: HDMI_UNI_PLL_SSC_CFG2 = 0x%x\n", __func__, val);
+ REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_SSC_CFG2);
+
+ pr_debug("%s: HDMI_UNI_PLL_SSC_CFG3 = 0x%x\n", __func__, ssc_tri_step);
+ REG_W(ssc_tri_step, hdmi_phy_pll_base + HDMI_UNI_PLL_SSC_CFG3);
+
+ REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
+ REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
+ REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
+ REG_W(0x0A, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG0);
+ REG_W(0x04, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG1);
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG3);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG4);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG5);
+
+ val = (kvco * vdd * 10000) / 6;
+ val += 500000;
+ val /= ten_power_six;
+ pr_debug("%s: HDMI_UNI_PLL_CAL_CFG6 = 0x%x\n", __func__, val);
+ REG_W(val & 0xFF, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG6);
+
+ val = (kvco * vdd * 10000) / 6;
+ val -= ten_power_six;
+ val /= ten_power_six;
+ val = (val >> 8) & 0xFF;
+ pr_debug("%s: HDMI_UNI_PLL_CAL_CFG7 = 0x%x\n", __func__, val);
+ REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG7);
+
+ val = (ref_clk * 5) / ten_power_six;
+ pr_debug("%s: HDMI_UNI_PLL_CAL_CFG8 = 0x%x\n", __func__, val);
+ REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG8);
+
+ val = ((ref_clk * 5) / ten_power_six) >> 8;
+ pr_debug("%s: HDMI_UNI_PLL_CAL_CFG9 = 0x%x\n", __func__, val);
+ REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG9);
+
+ vco_freq /= ten_power_six;
+ val = vco_freq & 0xFF;
+ pr_debug("%s: HDMI_UNI_PLL_CAL_CFG10 = 0x%x\n", __func__, val);
+ REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);
+
+ val = vco_freq >> 8;
+ pr_debug("%s: HDMI_UNI_PLL_CAL_CFG11 = 0x%x\n", __func__, val);
+ REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
+} /* hdmi_phy_pll_calculator */
+
+static int hdmi_vco_set_rate(struct clk *c, unsigned long rate)
{
unsigned int set_power_dwn = 0;
+ int rc = 0;
+
+ struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c);
if (hdmi_pll_on) {
- hdmi_pll_disable();
+ hdmi_vco_disable(c);
set_power_dwn = 1;
}
- clk_enable(mdss_ahb_clk);
+ rc = mdss_ahb_clk_enable(1);
+ if (rc) {
+ pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
pr_debug("%s: rate=%ld\n", __func__, rate);
+
switch (rate) {
case 0:
- /* This case is needed for suspend/resume. */
- break;
+ break;
- case 25200000:
+ case 756000000:
/* 640x480p60 */
REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
@@ -267,7 +468,6 @@
REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
- REG_W(0x03, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
@@ -295,7 +495,7 @@
udelay(200);
break;
- case 27000000:
+ case 810000000:
/* 576p50/576i50 case */
REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
@@ -312,7 +512,6 @@
REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
REG_W(0X1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
- REG_W(0x03, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
@@ -340,7 +539,7 @@
udelay(200);
break;
- case 27030000:
+ case 810900000:
/* 480p60/480i60 case */
REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
@@ -357,7 +556,6 @@
REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
- REG_W(0x03, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
@@ -384,7 +582,7 @@
REG_W(0x05, hdmi_phy_base + HDMI_PHY_TXCAL_CFG3);
udelay(200);
break;
- case 65000000:
+ case 650000000:
REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CFG);
@@ -400,7 +598,6 @@
REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
- REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
@@ -427,7 +624,7 @@
REG_W(0x05, hdmi_phy_base + HDMI_PHY_TXCAL_CFG3);
udelay(200);
break;
- case 74250000:
+ case 742500000:
/*
* 720p60/720p50/1080i60/1080i50
* 1080p24/1080p30/1080p25 case
@@ -447,7 +644,6 @@
REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
- REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
@@ -475,7 +671,7 @@
udelay(200);
break;
- case 108000000:
+ case 1080000000:
REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CFG);
@@ -491,7 +687,6 @@
REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
- REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
@@ -519,51 +714,7 @@
udelay(200);
break;
- case 148500000:
- REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
- REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
- REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CFG);
- REG_W(0x19, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
- REG_W(0x0E, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFR_CFG);
- REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC1_CFG);
- REG_W(0x0D, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC2_CFG);
- REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
- REG_W(0x52, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
- REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
- REG_W(0x56, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
- REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG4);
- REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
- REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
- REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
- REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
- REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
- REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
- REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
- REG_W(0x60, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG8);
- REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG9);
- REG_W(0xE6, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);
- REG_W(0x02, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
- REG_W(0x1F, hdmi_phy_base + HDMI_PHY_PD_CTRL0);
- udelay(50);
-
- REG_W(0x0F, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
- REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL1);
- REG_W(0x10, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
- REG_W(0xDB, hdmi_phy_base + HDMI_PHY_ANA_CFG0);
- REG_W(0x43, hdmi_phy_base + HDMI_PHY_ANA_CFG1);
- REG_W(0x02, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
- REG_W(0x00, hdmi_phy_base + HDMI_PHY_ANA_CFG3);
- REG_W(0x04, hdmi_phy_pll_base + HDMI_UNI_PLL_VREG_CFG);
- REG_W(0xD0, hdmi_phy_base + HDMI_PHY_DCC_CFG0);
- REG_W(0x1A, hdmi_phy_base + HDMI_PHY_DCC_CFG1);
- REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG0);
- REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG1);
- REG_W(0x02, hdmi_phy_base + HDMI_PHY_TXCAL_CFG2);
- REG_W(0x05, hdmi_phy_base + HDMI_PHY_TXCAL_CFG3);
- udelay(200);
- break;
-
- case 268500000:
+ case 1342500000:
REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CFG);
@@ -579,7 +730,6 @@
REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
- REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
@@ -607,7 +757,7 @@
udelay(200);
break;
- case 297000000:
+ case 1485000000:
REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CFG);
@@ -623,7 +773,6 @@
REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
- REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
@@ -652,40 +801,68 @@
break;
default:
- pr_err("%s: not supported rate=%ld\n", __func__, rate);
+ pr_debug("%s: Use pll settings calculator for rate=%ld\n",
+ __func__, rate);
+
+ REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
+ hdmi_phy_pll_calculator(rate);
+ REG_W(0x1F, hdmi_phy_base + HDMI_PHY_PD_CTRL0);
+ udelay(50);
+
+ REG_W(0x0F, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL1);
+ REG_W(0x10, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+ REG_W(0xDB, hdmi_phy_base + HDMI_PHY_ANA_CFG0);
+ REG_W(0x43, hdmi_phy_base + HDMI_PHY_ANA_CFG1);
+
+ if (rate < 825000000) {
+ REG_W(0x01, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_ANA_CFG3);
+ } else if (rate >= 825000000 && rate < 1342500000) {
+ REG_W(0x05, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+ REG_W(0x03, hdmi_phy_base + HDMI_PHY_ANA_CFG3);
+ } else {
+ REG_W(0x06, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+ REG_W(0x03, hdmi_phy_base + HDMI_PHY_ANA_CFG3);
+ }
+
+ REG_W(0x04, hdmi_phy_pll_base + HDMI_UNI_PLL_VREG_CFG);
+ REG_W(0xD0, hdmi_phy_base + HDMI_PHY_DCC_CFG0);
+ REG_W(0x1A, hdmi_phy_base + HDMI_PHY_DCC_CFG1);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG0);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG1);
+
+ if (rate < 825000000)
+ REG_W(0x01, hdmi_phy_base + HDMI_PHY_TXCAL_CFG2);
+ else
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG2);
+
+ REG_W(0x05, hdmi_phy_base + HDMI_PHY_TXCAL_CFG3);
+ REG_W(0x62, hdmi_phy_base + HDMI_PHY_BIST_PATN0);
+ REG_W(0x03, hdmi_phy_base + HDMI_PHY_BIST_PATN1);
+ REG_W(0x69, hdmi_phy_base + HDMI_PHY_BIST_PATN2);
+ REG_W(0x02, hdmi_phy_base + HDMI_PHY_BIST_PATN3);
+
+ udelay(200);
+
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_BIST_CFG1);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_BIST_CFG0);
}
/* Make sure writes complete before disabling iface clock */
mb();
- clk_disable(mdss_ahb_clk);
+ mdss_ahb_clk_enable(0);
if (set_power_dwn)
- hdmi_pll_enable();
+ hdmi_vco_enable(c);
+
+ vco->rate = rate;
+ vco->rate_set = true;
return 0;
} /* hdmi_pll_set_rate */
-/* Auto PLL calibaration */
-int mdss_ahb_clk_enable(int enable)
-{
- int rc = 0;
-
- /* todo: Ideally, we should enable/disable GDSC whenever we are
- * attempting to enable/disable MDSS AHB clock.
- * For now, just return error if GDSC is not enabled.
- */
- if (!mdss_gdsc_enabled())
- return -EPERM;
-
- if (enable)
- rc = clk_prepare_enable(mdss_ahb_clk);
- else
- clk_disable_unprepare(mdss_ahb_clk);
-
- return rc;
-}
-
int set_byte_mux_sel(struct mux_clk *clk, int sel)
{
pr_debug("%s: byte mux set to %s mode\n", __func__,
@@ -727,7 +904,7 @@
{
struct div_clk *div = to_div_clk(c);
/* Restore the divider's value */
- return div->ops->set_div(div, div->div);
+ return div->ops->set_div(div, div->data.div);
}
int mux_prepare(struct clk *c)
@@ -858,12 +1035,12 @@
static void dsi_pll_toggle_lock_detect(void)
{
DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG2,
- 0x05);
+ 0x0d);
DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG2,
- 0x04);
+ 0x0c);
udelay(1);
DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG2,
- 0x05);
+ 0x0d);
}
static int dsi_pll_lock_status(void)
@@ -917,24 +1094,25 @@
* the updates to take effect. These delays are necessary for the
* PLL to successfully lock
*/
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG1, 0x34);
DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
udelay(200);
DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
udelay(200);
DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
- udelay(1000);
+ udelay(600);
pll_locked = dsi_pll_toggle_lock_detect_and_check_status();
- for (i = 0; (i < 4) && !pll_locked; i++) {
+ for (i = 0; (i < SEQ_M_MAX_COUNTER) && !pll_locked; i++) {
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_PWRGEN_CFG,
+ 0x00);
+ udelay(50);
DSS_REG_W(mdss_dsi_base,
- DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x07);
- if (i != 0)
- DSS_REG_W(mdss_dsi_base,
- DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG1, 0x34);
- udelay(1);
+ DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
+ udelay(100);
DSS_REG_W(mdss_dsi_base,
DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
- udelay(1000);
+ udelay(600);
pll_locked = dsi_pll_toggle_lock_detect_and_check_status();
}
@@ -958,6 +1136,8 @@
* the updates to take effect. These delays are necessary for the
* PLL to successfully lock
*/
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_PWRGEN_CFG, 0x00);
+ udelay(50);
DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
udelay(200);
DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
@@ -969,7 +1149,7 @@
DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x07);
udelay(200);
DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
- udelay(1000);
+ udelay(600);
pll_locked = dsi_pll_toggle_lock_detect_and_check_status();
pr_debug("%s: PLL status = %s\n", __func__,
@@ -989,6 +1169,8 @@
* the updates to take effect. These delays are necessary for the
* PLL to successfully lock
*/
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_PWRGEN_CFG, 0x00);
+ udelay(50);
DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
udelay(200);
DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
@@ -998,7 +1180,7 @@
DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0d);
udelay(200);
DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
- udelay(1000);
+ udelay(600);
pll_locked = dsi_pll_toggle_lock_detect_and_check_status();
pr_debug("%s: PLL status = %s\n", __func__,
@@ -1018,12 +1200,14 @@
* the updates to take effect. These delays are necessary for the
* PLL to successfully lock
*/
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_PWRGEN_CFG, 0x00);
+ udelay(50);
DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
udelay(200);
DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
udelay(200);
DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
- udelay(1000);
+ udelay(600);
pll_locked = dsi_pll_toggle_lock_detect_and_check_status();
pr_debug("%s: PLL status = %s\n", __func__,
@@ -1043,6 +1227,8 @@
* the updates to take effect. These delays are necessary for the
* PLL to successfully lock
*/
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_PWRGEN_CFG, 0x00);
+ udelay(50);
DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
udelay(200);
DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
@@ -1050,7 +1236,7 @@
DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0d);
udelay(1);
DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
- udelay(1000);
+ udelay(600);
pll_locked = dsi_pll_toggle_lock_detect_and_check_status();
pr_debug("%s: PLL status = %s\n", __func__,
@@ -1082,10 +1268,10 @@
for (i = 0; i < 3; i++) {
/* DSI Uniphy lock detect setting */
DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG2,
- 0x04);
+ 0x0c);
udelay(100);
DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG2,
- 0x05);
+ 0x0d);
udelay(500);
/* poll for PLL ready status */
max_reads = 5;
@@ -1283,7 +1469,7 @@
DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CHGPUMP_CFG, 0x02);
DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG3, 0x2b);
DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG4, 0x66);
- DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG2, 0x05);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG2, 0x0d);
DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG1,
(u32)(sdm_cfg1 & 0xff));
@@ -1302,7 +1488,7 @@
DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_VCOLPF_CFG, 0x71);
DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG0,
(u32)sdm_cfg0);
- DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG0, 0x0a);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG0, 0x12);
DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG6, 0x30);
DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG7, 0x00);
DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG8, 0x60);
@@ -1464,13 +1650,14 @@
.ref_clk_rate = 19200000,
.min_rate = 350000000,
.max_rate = 750000000,
- .pll_en_seq_cnt = 6,
+ .pll_en_seq_cnt = 7,
.pll_enable_seqs[0] = dsi_pll_enable_seq_m,
- .pll_enable_seqs[1] = dsi_pll_enable_seq_d,
+ .pll_enable_seqs[1] = dsi_pll_enable_seq_m,
.pll_enable_seqs[2] = dsi_pll_enable_seq_d,
- .pll_enable_seqs[3] = dsi_pll_enable_seq_f1,
- .pll_enable_seqs[4] = dsi_pll_enable_seq_c,
- .pll_enable_seqs[5] = dsi_pll_enable_seq_e,
+ .pll_enable_seqs[3] = dsi_pll_enable_seq_d,
+ .pll_enable_seqs[4] = dsi_pll_enable_seq_f1,
+ .pll_enable_seqs[5] = dsi_pll_enable_seq_c,
+ .pll_enable_seqs[6] = dsi_pll_enable_seq_e,
.lpfr_lut_size = 10,
.lpfr_lut = (struct lpfr_cfg[]){
{479500000, 8},
@@ -1492,8 +1679,10 @@
};
struct div_clk analog_postdiv_clk_8226 = {
- .max_div = 255,
- .min_div = 1,
+ .data = {
+ .max_div = 255,
+ .min_div = 1,
+ },
.ops = &analog_postdiv_ops,
.c = {
.parent = &dsi_vco_clk_8226.c,
@@ -1506,7 +1695,11 @@
struct div_clk indirect_path_div2_clk_8226 = {
.ops = &fixed_2div_ops,
- .div = 2,
+ .data = {
+ .div = 2,
+ .min_div = 2,
+ .max_div = 2,
+ },
.c = {
.parent = &analog_postdiv_clk_8226.c,
.dbg_name = "indirect_path_div2_clk",
@@ -1517,8 +1710,10 @@
};
struct div_clk pixel_clk_src_8226 = {
- .max_div = 255,
- .min_div = 1,
+ .data = {
+ .max_div = 255,
+ .min_div = 1,
+ },
.ops = &digital_postdiv_ops,
.c = {
.parent = &dsi_vco_clk_8226.c,
@@ -1546,8 +1741,10 @@
struct div_clk byte_clk_src_8226 = {
.ops = &fixed_4div_ops,
- .min_div = 4,
- .max_div = 4,
+ .data = {
+ .min_div = 4,
+ .max_div = 4,
+ },
.c = {
.parent = &byte_mux_8226.c,
.dbg_name = "byte_clk_src",
@@ -1585,8 +1782,10 @@
};
struct div_clk analog_postdiv_clk_8974 = {
- .max_div = 255,
- .min_div = 1,
+ .data = {
+ .max_div = 255,
+ .min_div = 1,
+ },
.ops = &analog_postdiv_ops,
.c = {
.parent = &dsi_vco_clk_8974.c,
@@ -1599,7 +1798,11 @@
struct div_clk indirect_path_div2_clk_8974 = {
.ops = &fixed_2div_ops,
- .div = 2,
+ .data = {
+ .div = 2,
+ .min_div = 2,
+ .max_div = 2,
+ },
.c = {
.parent = &analog_postdiv_clk_8974.c,
.dbg_name = "indirect_path_div2_clk",
@@ -1610,8 +1813,10 @@
};
struct div_clk pixel_clk_src_8974 = {
- .max_div = 255,
- .min_div = 1,
+ .data = {
+ .max_div = 255,
+ .min_div = 1,
+ },
.ops = &digital_postdiv_ops,
.c = {
.parent = &dsi_vco_clk_8974.c,
@@ -1639,8 +1844,10 @@
struct div_clk byte_clk_src_8974 = {
.ops = &fixed_4div_ops,
- .min_div = 4,
- .max_div = 4,
+ .data = {
+ .min_div = 4,
+ .max_div = 4,
+ },
.c = {
.parent = &byte_mux_8974.c,
.dbg_name = "byte_clk_src",
@@ -1649,6 +1856,744 @@
},
};
+static inline struct edp_pll_vco_clk *to_edp_vco_clk(struct clk *clk)
+{
+ return container_of(clk, struct edp_pll_vco_clk, c);
+}
+
+static int edp_vco_set_rate(struct clk *c, unsigned long vco_rate)
+{
+ struct edp_pll_vco_clk *vco = to_edp_vco_clk(c);
+ int rc = 0;
+
+ pr_debug("%s: vco_rate=%d\n", __func__, (int)vco_rate);
+
+ rc = mdss_ahb_clk_enable(1);
+ if (rc) {
+ pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+ __func__, rc);
+ rc = -EINVAL;
+ }
+ if (vco_rate == 810000000) {
+ DSS_REG_W(mdss_edp_base, 0x0c, 0x18);
+ /* UNIPHY_PLL_LKDET_CFG2 */
+ DSS_REG_W(mdss_edp_base, 0x64, 0x05);
+ /* UNIPHY_PLL_REFCLK_CFG */
+ DSS_REG_W(mdss_edp_base, 0x00, 0x00);
+ /* UNIPHY_PLL_SDM_CFG0 */
+ DSS_REG_W(mdss_edp_base, 0x38, 0x36);
+ /* UNIPHY_PLL_SDM_CFG1 */
+ DSS_REG_W(mdss_edp_base, 0x3c, 0x69);
+ /* UNIPHY_PLL_SDM_CFG2 */
+ DSS_REG_W(mdss_edp_base, 0x40, 0xff);
+ /* UNIPHY_PLL_SDM_CFG3 */
+ DSS_REG_W(mdss_edp_base, 0x44, 0x2f);
+ /* UNIPHY_PLL_SDM_CFG4 */
+ DSS_REG_W(mdss_edp_base, 0x48, 0x00);
+ /* UNIPHY_PLL_SSC_CFG0 */
+ DSS_REG_W(mdss_edp_base, 0x4c, 0x80);
+ /* UNIPHY_PLL_SSC_CFG1 */
+ DSS_REG_W(mdss_edp_base, 0x50, 0x00);
+ /* UNIPHY_PLL_SSC_CFG2 */
+ DSS_REG_W(mdss_edp_base, 0x54, 0x00);
+ /* UNIPHY_PLL_SSC_CFG3 */
+ DSS_REG_W(mdss_edp_base, 0x58, 0x00);
+ /* UNIPHY_PLL_CAL_CFG0 */
+ DSS_REG_W(mdss_edp_base, 0x6c, 0x0a);
+ /* UNIPHY_PLL_CAL_CFG2 */
+ DSS_REG_W(mdss_edp_base, 0x74, 0x01);
+ /* UNIPHY_PLL_CAL_CFG6 */
+ DSS_REG_W(mdss_edp_base, 0x84, 0x5a);
+ /* UNIPHY_PLL_CAL_CFG7 */
+ DSS_REG_W(mdss_edp_base, 0x88, 0x0);
+ /* UNIPHY_PLL_CAL_CFG8 */
+ DSS_REG_W(mdss_edp_base, 0x8c, 0x60);
+ /* UNIPHY_PLL_CAL_CFG9 */
+ DSS_REG_W(mdss_edp_base, 0x90, 0x0);
+ /* UNIPHY_PLL_CAL_CFG10 */
+ DSS_REG_W(mdss_edp_base, 0x94, 0x2a);
+ /* UNIPHY_PLL_CAL_CFG11 */
+ DSS_REG_W(mdss_edp_base, 0x98, 0x3);
+ /* UNIPHY_PLL_LKDET_CFG0 */
+ DSS_REG_W(mdss_edp_base, 0x5c, 0x10);
+ /* UNIPHY_PLL_LKDET_CFG1 */
+ DSS_REG_W(mdss_edp_base, 0x60, 0x1a);
+ /* UNIPHY_PLL_POSTDIV1_CFG */
+ DSS_REG_W(mdss_edp_base, 0x04, 0x00);
+ /* UNIPHY_PLL_POSTDIV3_CFG */
+ DSS_REG_W(mdss_edp_base, 0x28, 0x00);
+ } else if (vco_rate == 1350000000) {
+ /* UNIPHY_PLL_LKDET_CFG2 */
+ DSS_REG_W(mdss_edp_base, 0x64, 0x05);
+ /* UNIPHY_PLL_REFCLK_CFG */
+ DSS_REG_W(mdss_edp_base, 0x00, 0x01);
+ /* UNIPHY_PLL_SDM_CFG0 */
+ DSS_REG_W(mdss_edp_base, 0x38, 0x36);
+ /* UNIPHY_PLL_SDM_CFG1 */
+ DSS_REG_W(mdss_edp_base, 0x3c, 0x62);
+ /* UNIPHY_PLL_SDM_CFG2 */
+ DSS_REG_W(mdss_edp_base, 0x40, 0x00);
+ /* UNIPHY_PLL_SDM_CFG3 */
+ DSS_REG_W(mdss_edp_base, 0x44, 0x28);
+ /* UNIPHY_PLL_SDM_CFG4 */
+ DSS_REG_W(mdss_edp_base, 0x48, 0x00);
+ /* UNIPHY_PLL_SSC_CFG0 */
+ DSS_REG_W(mdss_edp_base, 0x4c, 0x80);
+ /* UNIPHY_PLL_SSC_CFG1 */
+ DSS_REG_W(mdss_edp_base, 0x50, 0x00);
+ /* UNIPHY_PLL_SSC_CFG2 */
+ DSS_REG_W(mdss_edp_base, 0x54, 0x00);
+ /* UNIPHY_PLL_SSC_CFG3 */
+ DSS_REG_W(mdss_edp_base, 0x58, 0x00);
+ /* UNIPHY_PLL_CAL_CFG0 */
+ DSS_REG_W(mdss_edp_base, 0x6c, 0x0a);
+ /* UNIPHY_PLL_CAL_CFG2 */
+ DSS_REG_W(mdss_edp_base, 0x74, 0x01);
+ /* UNIPHY_PLL_CAL_CFG6 */
+ DSS_REG_W(mdss_edp_base, 0x84, 0x5a);
+ /* UNIPHY_PLL_CAL_CFG7 */
+ DSS_REG_W(mdss_edp_base, 0x88, 0x0);
+ /* UNIPHY_PLL_CAL_CFG8 */
+ DSS_REG_W(mdss_edp_base, 0x8c, 0x60);
+ /* UNIPHY_PLL_CAL_CFG9 */
+ DSS_REG_W(mdss_edp_base, 0x90, 0x0);
+ /* UNIPHY_PLL_CAL_CFG10 */
+ DSS_REG_W(mdss_edp_base, 0x94, 0x46);
+ /* UNIPHY_PLL_CAL_CFG11 */
+ DSS_REG_W(mdss_edp_base, 0x98, 0x5);
+ /* UNIPHY_PLL_LKDET_CFG0 */
+ DSS_REG_W(mdss_edp_base, 0x5c, 0x10);
+ /* UNIPHY_PLL_LKDET_CFG1 */
+ DSS_REG_W(mdss_edp_base, 0x60, 0x1a);
+ /* UNIPHY_PLL_POSTDIV1_CFG */
+ DSS_REG_W(mdss_edp_base, 0x04, 0x00);
+ /* UNIPHY_PLL_POSTDIV3_CFG */
+ DSS_REG_W(mdss_edp_base, 0x28, 0x00);
+ } else {
+ pr_err("%s: rate=%d is NOT supported\n", __func__,
+ (int)vco_rate);
+ vco_rate = 0;
+ rc = -EINVAL;
+ }
+
+ DSS_REG_W(mdss_edp_base, 0x20, 0x01); /* UNIPHY_PLL_GLB_CFG */
+ udelay(100);
+ DSS_REG_W(mdss_edp_base, 0x20, 0x05); /* UNIPHY_PLL_GLB_CFG */
+ udelay(100);
+ DSS_REG_W(mdss_edp_base, 0x20, 0x07); /* UNIPHY_PLL_GLB_CFG */
+ udelay(100);
+ DSS_REG_W(mdss_edp_base, 0x20, 0x0f); /* UNIPHY_PLL_GLB_CFG */
+ udelay(100);
+ mdss_ahb_clk_enable(0);
+
+ vco->rate = vco_rate;
+
+ return rc;
+}
+
+static int edp_pll_ready_poll(void)
+{
+ int cnt;
+ u32 status;
+
+ /* ahb clock should be enabled by caller */
+ cnt = 100;
+ while (cnt--) {
+ udelay(100);
+ status = DSS_REG_R(mdss_edp_base, 0xc0);
+ status &= 0x01;
+ if (status)
+ break;
+ }
+ pr_debug("%s: cnt=%d status=%d\n", __func__, cnt, (int)status);
+
+ if (status)
+ return 1;
+
+ pr_err("%s: PLL NOT ready\n", __func__);
+ return 0;
+}
+
+static int edp_vco_enable(struct clk *c)
+{
+ int i, ready;
+ int rc = 0;
+
+ if (!mdss_gdsc_enabled()) {
+ pr_err("%s: mdss GDSC is not enabled\n", __func__);
+ return -EPERM;
+ }
+
+ /* called from enable, irq disable. can not call clk_prepare */
+ rc = clk_enable(mdss_ahb_clk);
+ if (rc) {
+ pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ for (i = 0; i < 3; i++) {
+ ready = edp_pll_ready_poll();
+ if (ready)
+ break;
+ DSS_REG_W(mdss_edp_base, 0x20, 0x01); /* UNIPHY_PLL_GLB_CFG */
+ udelay(100);
+ DSS_REG_W(mdss_edp_base, 0x20, 0x05); /* UNIPHY_PLL_GLB_CFG */
+ udelay(100);
+ DSS_REG_W(mdss_edp_base, 0x20, 0x07); /* UNIPHY_PLL_GLB_CFG */
+ udelay(100);
+ DSS_REG_W(mdss_edp_base, 0x20, 0x0f); /* UNIPHY_PLL_GLB_CFG */
+ udelay(100);
+ }
+ clk_disable(mdss_ahb_clk);
+
+ if (ready) {
+ pr_debug("%s: EDP PLL locked\n", __func__);
+ return 0;
+ }
+
+ pr_err("%s: EDP PLL failed to lock\n", __func__);
+ return -EINVAL;
+}
+
+static void edp_vco_disable(struct clk *c)
+{
+ int rc = 0;
+
+ if (!mdss_gdsc_enabled()) {
+ pr_err("%s: mdss GDSC is not enabled\n", __func__);
+ return;
+ }
+
+ /* called from unprepare which is not atomic */
+ rc = mdss_ahb_clk_enable(1);
+ if (rc) {
+ pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+ __func__, rc);
+ return;
+ }
+
+ DSS_REG_W(mdss_edp_base, 0x20, 0x00);
+
+ mdss_ahb_clk_enable(0);
+
+ pr_debug("%s: EDP PLL Disabled\n", __func__);
+ return;
+}
+
+static unsigned long edp_vco_get_rate(struct clk *c)
+{
+ struct edp_pll_vco_clk *vco = to_edp_vco_clk(c);
+ u32 pll_status, div2;
+ int rc;
+
+ rc = mdss_ahb_clk_enable(1);
+ if (rc) {
+ pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+ if (vco->rate == 0) {
+ pll_status = DSS_REG_R(mdss_edp_base, 0xc0);
+ if (pll_status & 0x01) {
+ div2 = DSS_REG_R(mdss_edp_base, 0x24);
+ if (div2 & 0x01)
+ vco->rate = 1350000000;
+ else
+ vco->rate = 810000000;
+ }
+ }
+ mdss_ahb_clk_enable(0);
+
+ pr_debug("%s: rate=%d\n", __func__, (int)vco->rate);
+
+ return vco->rate;
+}
+
+static long edp_vco_round_rate(struct clk *c, unsigned long rate)
+{
+ struct edp_pll_vco_clk *vco = to_edp_vco_clk(c);
+ unsigned long rrate = -ENOENT;
+ unsigned long *lp;
+
+ lp = vco->rate_list;
+ while (*lp) {
+ rrate = *lp;
+ if (rate <= rrate)
+ break;
+ lp++;
+ }
+
+ pr_debug("%s: rrate=%d\n", __func__, (int)rrate);
+
+ return rrate;
+}
+
+static int edp_vco_prepare(struct clk *c)
+{
+ struct edp_pll_vco_clk *vco = to_edp_vco_clk(c);
+
+ pr_debug("%s: rate=%d\n", __func__, (int)vco->rate);
+
+ return edp_vco_set_rate(c, vco->rate);
+}
+
+static void edp_vco_unprepare(struct clk *c)
+{
+ struct edp_pll_vco_clk *vco = to_edp_vco_clk(c);
+
+ pr_debug("%s: rate=%d\n", __func__, (int)vco->rate);
+
+ edp_vco_disable(c);
+}
+
+static int edp_pll_lock_status(void)
+{
+ u32 status;
+ int pll_locked = 0;
+ int rc;
+
+ rc = mdss_ahb_clk_enable(1);
+ if (rc) {
+ pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+ /* poll for PLL ready status */
+ if (readl_poll_timeout_noirq((mdss_edp_base + 0xc0),
+ status, ((status & BIT(0)) == 1),
+ PLL_POLL_MAX_READS, PLL_POLL_TIMEOUT_US)) {
+ pr_debug("%s: EDP PLL status=%x failed to Lock\n",
+ __func__, status);
+ pll_locked = 0;
+ } else {
+ pll_locked = 1;
+ }
+ mdss_ahb_clk_enable(0);
+
+ return pll_locked;
+}
+
+static enum handoff edp_vco_handoff(struct clk *c)
+{
+ enum handoff ret = HANDOFF_DISABLED_CLK;
+
+ if (edp_pll_lock_status()) {
+ c->rate = edp_vco_get_rate(c);
+ ret = HANDOFF_ENABLED_CLK;
+ }
+
+ pr_debug("%s: done, ret=%d\n", __func__, ret);
+ return ret;
+}
+
+/* edp vco rate */
+static unsigned long edp_vco_rate_list[] = {
+ 810000000, 1350000000, 0};
+
+struct clk_ops edp_vco_clk_ops = {
+ .enable = edp_vco_enable,
+ .set_rate = edp_vco_set_rate,
+ .get_rate = edp_vco_get_rate,
+ .round_rate = edp_vco_round_rate,
+ .prepare = edp_vco_prepare,
+ .unprepare = edp_vco_unprepare,
+ .handoff = edp_vco_handoff,
+};
+
+struct edp_pll_vco_clk edp_vco_clk = {
+ .ref_clk_rate = 19200000,
+ .rate = 0,
+ .rate_list = edp_vco_rate_list,
+ .c = {
+ .dbg_name = "edp_vco_clk",
+ .ops = &edp_vco_clk_ops,
+ CLK_INIT(edp_vco_clk.c),
+ },
+};
+
+static unsigned long edp_mainlink_get_rate(struct clk *c)
+{
+ struct div_clk *mclk = to_div_clk(c);
+ struct clk *pclk;
+ unsigned long rate = 0;
+
+ pclk = clk_get_parent(c);
+
+ if (pclk->ops->get_rate) {
+ rate = pclk->ops->get_rate(pclk);
+ rate /= mclk->data.div;
+ }
+
+ pr_debug("%s: rate=%d div=%d\n", __func__, (int)rate, mclk->data.div);
+
+ return rate;
+}
+
+static struct clk_ops edp_mainlink_clk_src_ops;
+static struct clk_div_ops fixed_5div_ops; /* null ops */
+
+struct div_clk edp_mainlink_clk_src = {
+ .ops = &fixed_5div_ops,
+ .data = {
+ .div = 5,
+ },
+ .c = {
+ .parent = &edp_vco_clk.c,
+ .dbg_name = "edp_mainlink_clk_src",
+ .ops = &edp_mainlink_clk_src_ops,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(edp_mainlink_clk_src.c),
+ }
+};
+
+
+static struct clk_ops edp_pixel_clk_ops;
+
+/*
+ * this rate is from pll to clock controller
+ * output from pll to CC has two possibilities
+ * 1: if mainlink rate is 270M, then 675M
+ * 2: if mainlink rate is 162M, then 810M
+ */
+static int edp_pixel_set_div(struct div_clk *clk, int div)
+{
+ int rc = 0;
+
+ rc = mdss_ahb_clk_enable(1);
+ if (rc) {
+ pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ pr_debug("%s: div=%d\n", __func__, div);
+ DSS_REG_W(mdss_edp_base, 0x24, (div - 1)); /* UNIPHY_PLL_POSTDIV2_CFG */
+
+ mdss_ahb_clk_enable(0);
+ return 0;
+}
+
+static int edp_pixel_get_div(struct div_clk *clk)
+{
+ int div = 0;
+
+ if (mdss_ahb_clk_enable(1)) {
+ pr_debug("%s: Failed to enable mdss ahb clock\n", __func__);
+ return 1;
+ }
+ div = DSS_REG_R(mdss_edp_base, 0x24); /* UNIPHY_PLL_POSTDIV2_CFG */
+ div &= 0x01;
+ pr_debug("%s: div=%d\n", __func__, div);
+ mdss_ahb_clk_enable(0);
+ return div + 1;
+}
+
+static struct clk_div_ops edp_pixel_ops = {
+ .set_div = edp_pixel_set_div,
+ .get_div = edp_pixel_get_div,
+};
+
+struct div_clk edp_pixel_clk_src = {
+ .data = {
+ .max_div = 2,
+ .min_div = 1,
+ },
+ .ops = &edp_pixel_ops,
+ .c = {
+ .parent = &edp_vco_clk.c,
+ .dbg_name = "edp_pixel_clk_src",
+ .ops = &edp_pixel_clk_ops,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(edp_pixel_clk_src.c),
+ },
+};
+
+/* HDMI PLL DIV CLK */
+
+static unsigned long hdmi_vco_get_rate(struct clk *c)
+{
+ unsigned long freq = 0;
+
+ if (mdss_ahb_clk_enable(1)) {
+ pr_err("%s: Failed to enable mdss ahb clock\n", __func__);
+ return freq;
+ }
+
+ freq = DSS_REG_R(hdmi_phy_pll_base, HDMI_UNI_PLL_CAL_CFG11) << 8 |
+ DSS_REG_R(hdmi_phy_pll_base, HDMI_UNI_PLL_CAL_CFG10);
+
+ switch (freq) {
+ case 742:
+ freq = 742500000;
+ break;
+ case 810:
+ if (DSS_REG_R(hdmi_phy_pll_base, HDMI_UNI_PLL_SDM_CFG3) == 0x18)
+ freq = 810000000;
+ else
+ freq = 810900000;
+ break;
+ case 1342:
+ freq = 1342500000;
+ break;
+ default:
+ freq *= 1000000;
+ }
+
+ mdss_ahb_clk_enable(0);
+
+ return freq;
+}
+
+static long hdmi_vco_round_rate(struct clk *c, unsigned long rate)
+{
+ unsigned long rrate = rate;
+ struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c);
+
+ if (rate < vco->min_rate)
+ rrate = vco->min_rate;
+ if (rate > vco->max_rate)
+ rrate = vco->max_rate;
+
+ pr_debug("%s: rrate=%ld\n", __func__, rrate);
+
+ return rrate;
+}
+
+static int hdmi_vco_prepare(struct clk *c)
+{
+ struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c);
+ int ret = 0;
+
+ pr_debug("%s: rate=%ld\n", __func__, vco->rate);
+
+ if (!vco->rate_set && vco->rate)
+ ret = hdmi_vco_set_rate(c, vco->rate);
+
+ if (!ret)
+ ret = clk_prepare(mdss_ahb_clk);
+
+ return ret;
+}
+
+static void hdmi_vco_unprepare(struct clk *c)
+{
+ struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c);
+
+ vco->rate_set = false;
+
+ clk_unprepare(mdss_ahb_clk);
+}
+
+static int hdmi_pll_lock_status(void)
+{
+ u32 status;
+ int pll_locked = 0;
+ int rc;
+
+ rc = mdss_ahb_clk_enable(1);
+ if (rc) {
+ pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+ __func__, rc);
+ return 0;
+ }
+ /* poll for PLL ready status */
+ if (readl_poll_timeout_noirq((hdmi_phy_base + HDMI_PHY_STATUS),
+ status, ((status & BIT(0)) == 1),
+ PLL_POLL_MAX_READS, PLL_POLL_TIMEOUT_US)) {
+ pr_debug("%s: HDMI PLL status=%x failed to Lock\n",
+ __func__, status);
+ pll_locked = 0;
+ } else {
+ pll_locked = 1;
+ }
+ mdss_ahb_clk_enable(0);
+
+ return pll_locked;
+}
+
+static enum handoff hdmi_vco_handoff(struct clk *c)
+{
+ enum handoff ret = HANDOFF_DISABLED_CLK;
+
+ if (hdmi_pll_lock_status()) {
+ c->rate = hdmi_vco_get_rate(c);
+ ret = HANDOFF_ENABLED_CLK;
+ }
+
+ pr_debug("%s: done, ret=%d\n", __func__, ret);
+ return ret;
+}
+
+static struct clk_ops hdmi_vco_clk_ops = {
+ .enable = hdmi_vco_enable,
+ .set_rate = hdmi_vco_set_rate,
+ .get_rate = hdmi_vco_get_rate,
+ .round_rate = hdmi_vco_round_rate,
+ .prepare = hdmi_vco_prepare,
+ .unprepare = hdmi_vco_unprepare,
+ .disable = hdmi_vco_disable,
+ .handoff = hdmi_vco_handoff,
+};
+
+static struct hdmi_pll_vco_clk hdmi_vco_clk = {
+ .min_rate = 600000000,
+ .max_rate = 1800000000,
+ .c = {
+ .dbg_name = "hdmi_vco_clk",
+ .ops = &hdmi_vco_clk_ops,
+ CLK_INIT(hdmi_vco_clk.c),
+ },
+};
+
+struct div_clk hdmipll_div1_clk = {
+ .data = {
+ .div = 1,
+ .min_div = 1,
+ .max_div = 1,
+ },
+ .c = {
+ .parent = &hdmi_vco_clk.c,
+ .dbg_name = "hdmipll_div1_clk",
+ .ops = &clk_ops_div,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(hdmipll_div1_clk.c),
+ },
+};
+
+struct div_clk hdmipll_div2_clk = {
+ .data = {
+ .div = 2,
+ .min_div = 2,
+ .max_div = 2,
+ },
+ .c = {
+ .parent = &hdmi_vco_clk.c,
+ .dbg_name = "hdmipll_div2_clk",
+ .ops = &clk_ops_div,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(hdmipll_div2_clk.c),
+ },
+};
+
+struct div_clk hdmipll_div4_clk = {
+ .data = {
+ .div = 4,
+ .min_div = 4,
+ .max_div = 4,
+ },
+ .c = {
+ .parent = &hdmi_vco_clk.c,
+ .dbg_name = "hdmipll_div4_clk",
+ .ops = &clk_ops_div,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(hdmipll_div4_clk.c),
+ },
+};
+
+struct div_clk hdmipll_div6_clk = {
+ .data = {
+ .div = 6,
+ .min_div = 6,
+ .max_div = 6,
+ },
+ .c = {
+ .parent = &hdmi_vco_clk.c,
+ .dbg_name = "hdmipll_div6_clk",
+ .ops = &clk_ops_div,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(hdmipll_div6_clk.c),
+ },
+};
+
+static int hdmipll_set_mux_sel(struct mux_clk *clk, int mux_sel)
+{
+ int rc;
+
+ if (!mdss_gdsc_enabled()) {
+ pr_err("%s: mdss GDSC is not enabled\n", __func__);
+ return -EPERM;
+ }
+
+ rc = clk_enable(mdss_ahb_clk);
+ if (rc) {
+ pr_err("%s: Failed to enable mdss ahb clock\n", __func__);
+ return rc;
+ }
+
+ pr_debug("%s: mux_sel=%d\n", __func__, mux_sel);
+ DSS_REG_W(hdmi_phy_pll_base, HDMI_UNI_PLL_POSTDIV1_CFG, mux_sel);
+
+ clk_disable(mdss_ahb_clk);
+
+ return 0;
+}
+
+static int hdmipll_get_mux_sel(struct mux_clk *clk)
+{
+ int mux_sel = 0;
+
+ if (mdss_ahb_clk_enable(1)) {
+ pr_err("%s: Failed to enable mdss ahb clock\n", __func__);
+ return mux_sel;
+ }
+
+ mux_sel = DSS_REG_R(hdmi_phy_pll_base, HDMI_UNI_PLL_POSTDIV1_CFG);
+ mux_sel &= 0x03;
+ pr_debug("%s: mux_sel=%d\n", __func__, mux_sel);
+
+ mdss_ahb_clk_enable(0);
+
+ return mux_sel;
+}
+
+static struct clk_mux_ops hdmipll_mux_ops = {
+ .set_mux_sel = hdmipll_set_mux_sel,
+ .get_mux_sel = hdmipll_get_mux_sel,
+};
+
+static struct clk_ops hdmi_mux_ops;
+
+static int hdmi_mux_prepare(struct clk *c)
+{
+ int ret = 0;
+
+ if (c && c->ops && c->ops->set_rate)
+ ret = c->ops->set_rate(c, c->rate);
+
+ return ret;
+}
+
+static struct mux_clk hdmipll_mux_clk = {
+ MUX_SRC_LIST(
+ { &hdmipll_div1_clk.c, 0 },
+ { &hdmipll_div2_clk.c, 1 },
+ { &hdmipll_div4_clk.c, 2 },
+ { &hdmipll_div6_clk.c, 3 },
+ ),
+ .ops = &hdmipll_mux_ops,
+ .c = {
+ .parent = &hdmipll_div1_clk.c,
+ .dbg_name = "hdmipll_mux_clk",
+ .ops = &hdmi_mux_ops,
+ CLK_INIT(hdmipll_mux_clk.c),
+ },
+};
+
+struct div_clk hdmipll_clk_src = {
+ .data = {
+ .div = 5,
+ .min_div = 5,
+ .max_div = 5,
+ },
+ .c = {
+ .parent = &hdmipll_mux_clk.c,
+ .dbg_name = "hdmipll_clk_src",
+ .ops = &clk_ops_div,
+ CLK_INIT(hdmipll_clk_src.c),
+ },
+};
+
void __init mdss_clk_ctrl_pre_init(struct clk *ahb_clk)
{
BUG_ON(ahb_clk == NULL);
@@ -1671,6 +2616,10 @@
if (!hdmi_phy_pll_base)
pr_err("%s: unable to ioremap hdmi phy pll base", __func__);
+ mdss_edp_base = ioremap(EDP_PHY_PHYS, EDP_PHY_SIZE);
+ if (!mdss_edp_base)
+ pr_err("%s: unable to remap edp base", __func__);
+
pixel_clk_src_ops = clk_ops_slave_div;
pixel_clk_src_ops.prepare = div_prepare;
@@ -1682,5 +2631,14 @@
byte_mux_clk_ops = clk_ops_gen_mux;
byte_mux_clk_ops.prepare = mux_prepare;
-}
+ edp_mainlink_clk_src_ops = clk_ops_div;
+ edp_mainlink_clk_src_ops.get_parent = clk_get_parent;
+ edp_mainlink_clk_src_ops.get_rate = edp_mainlink_get_rate;
+
+ edp_pixel_clk_ops = clk_ops_slave_div;
+ edp_pixel_clk_ops.prepare = div_prepare;
+
+ hdmi_mux_ops = clk_ops_gen_mux;
+ hdmi_mux_ops.prepare = hdmi_mux_prepare;
+}
diff --git a/arch/arm/mach-msm/clock-mdss-8974.h b/arch/arm/mach-msm/clock-mdss-8974.h
index 9fd3026..f9286f1 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.h
+++ b/arch/arm/mach-msm/clock-mdss-8974.h
@@ -22,9 +22,23 @@
void mdss_clk_ctrl_pre_init(struct clk *ahb_clk);
void mdss_clk_ctrl_post_init(void);
-int hdmi_pll_enable(void);
-void hdmi_pll_disable(void);
-int hdmi_pll_set_rate(unsigned long rate);
+
+struct hdmi_pll_vco_clk {
+ unsigned long rate; /* current vco rate */
+ unsigned long min_rate; /* min vco rate */
+ unsigned long max_rate; /* max vco rate */
+ bool rate_set;
+
+ struct clk c;
+};
+
+struct edp_pll_vco_clk {
+ unsigned long ref_clk_rate;
+ unsigned long rate; /* vco rate */
+ unsigned long *rate_list;
+
+ struct clk c;
+};
struct lpfr_cfg {
unsigned long vco_rate;
@@ -57,4 +71,8 @@
extern struct mux_clk byte_mux_8226;
extern struct div_clk byte_clk_src_8226;
+extern struct div_clk edp_mainlink_clk_src;
+extern struct div_clk edp_pixel_clk_src;
+extern struct div_clk hdmipll_clk_src;
+
#endif
diff --git a/arch/arm/mach-msm/clock-pll.c b/arch/arm/mach-msm/clock-pll.c
index a251784..c08df46 100644
--- a/arch/arm/mach-msm/clock-pll.c
+++ b/arch/arm/mach-msm/clock-pll.c
@@ -304,6 +304,22 @@
return HANDOFF_ENABLED_CLK;
}
+static long local_pll_clk_round_rate(struct clk *c, unsigned long rate)
+{
+ struct pll_freq_tbl *nf;
+ struct pll_clk *pll = to_pll_clk(c);
+
+ if (!pll->freq_tbl)
+ return -EINVAL;
+
+ for (nf = pll->freq_tbl; nf->freq_hz != PLL_FREQ_END; nf++)
+ if (nf->freq_hz >= rate)
+ return nf->freq_hz;
+
+ nf--;
+ return nf->freq_hz;
+}
+
static int local_pll_clk_set_rate(struct clk *c, unsigned long rate)
{
struct pll_freq_tbl *nf;
@@ -426,6 +442,7 @@
.enable = sr2_pll_clk_enable,
.disable = local_pll_clk_disable,
.set_rate = local_pll_clk_set_rate,
+ .round_rate = local_pll_clk_round_rate,
.handoff = local_pll_clk_handoff,
};
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index e3c11c5..f7ee79c 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -63,36 +63,44 @@
/* Update voltage level given the current votes. */
static int update_vdd(struct clk_vdd_class *vdd_class)
{
- int level, rc = 0, i;
+ int level, rc = 0, i, ignore;
struct regulator **r = vdd_class->regulator;
int *uv = vdd_class->vdd_uv;
int *ua = vdd_class->vdd_ua;
int n_reg = vdd_class->num_regulators;
+ int cur_lvl = vdd_class->cur_level;
int max_lvl = vdd_class->num_levels - 1;
- int lvl_base;
+ int cur_base = cur_lvl * n_reg;
+ int new_base;
+ /* aggregate votes */
for (level = max_lvl; level > 0; level--)
if (vdd_class->level_votes[level])
break;
- if (level == vdd_class->cur_level)
+ if (level == cur_lvl)
return 0;
max_lvl = max_lvl * n_reg;
- lvl_base = level * n_reg;
+ new_base = level * n_reg;
for (i = 0; i < vdd_class->num_regulators; i++) {
- rc = regulator_set_voltage(r[i], uv[lvl_base + i],
+ rc = regulator_set_voltage(r[i], uv[new_base + i],
uv[max_lvl + i]);
if (rc)
goto set_voltage_fail;
- if (!ua)
- continue;
-
- rc = regulator_set_optimum_mode(r[i], ua[lvl_base + i]);
- rc = rc > 0 ? 0 : rc;
+ if (ua) {
+ rc = regulator_set_optimum_mode(r[i], ua[new_base + i]);
+ rc = rc > 0 ? 0 : rc;
+ if (rc)
+ goto set_mode_fail;
+ }
+ if (cur_lvl == 0 || cur_lvl == vdd_class->num_levels)
+ rc = regulator_enable(r[i]);
+ else if (level == 0)
+ rc = regulator_disable(r[i]);
if (rc)
- goto set_mode_fail;
+ goto enable_disable_fail;
}
if (vdd_class->set_vdd && !vdd_class->num_regulators)
rc = vdd_class->set_vdd(vdd_class, level);
@@ -102,20 +110,29 @@
return rc;
-set_mode_fail:
- regulator_set_voltage(r[i], uv[vdd_class->cur_level * n_reg + i],
- uv[max_lvl + i]);
-
-set_voltage_fail:
- lvl_base = vdd_class->cur_level * n_reg;
- for (i--; i >= 0; i--) {
- regulator_set_voltage(r[i], uv[lvl_base + i], uv[max_lvl + i]);
-
- if (!ua)
- continue;
- regulator_set_optimum_mode(r[i], ua[lvl_base + i]);
+enable_disable_fail:
+ /*
+ * set_optimum_mode could use voltage to derive mode. Restore
+ * previous voltage setting for r[i] first.
+ */
+ if (ua) {
+ regulator_set_voltage(r[i], uv[cur_base + i], uv[max_lvl + i]);
+ regulator_set_optimum_mode(r[i], ua[cur_base + i]);
}
+set_mode_fail:
+ regulator_set_voltage(r[i], uv[cur_base + i], uv[max_lvl + i]);
+
+set_voltage_fail:
+ for (i--; i >= 0; i--) {
+ regulator_set_voltage(r[i], uv[cur_base + i], uv[max_lvl + i]);
+ if (ua)
+ regulator_set_optimum_mode(r[i], ua[cur_base + i]);
+ if (cur_lvl == 0 || cur_lvl == vdd_class->num_levels)
+ regulator_disable(r[i]);
+ else if (level == 0)
+ ignore = regulator_enable(r[i]);
+ }
return rc;
}
@@ -527,13 +544,26 @@
long clk_round_rate(struct clk *clk, unsigned long rate)
{
+ long rrate;
+ unsigned long fmax = 0, i;
+
if (IS_ERR_OR_NULL(clk))
return -EINVAL;
if (!clk->ops->round_rate)
return -ENOSYS;
- return clk->ops->round_rate(clk, rate);
+ for (i = 0; i < clk->num_fmax; i++)
+ fmax = max(fmax, clk->fmax[i]);
+
+ if (!fmax)
+ fmax = ULONG_MAX;
+
+ rate = min(rate, fmax);
+ rrate = clk->ops->round_rate(clk, rate);
+ if (rrate > fmax)
+ return -EINVAL;
+ return rrate;
}
EXPORT_SYMBOL(clk_round_rate);
@@ -553,15 +583,16 @@
{
int rc = 0;
+ if (!clk->ops->set_parent && clk->parent == parent)
+ return 0;
+
if (!clk->ops->set_parent)
return -ENOSYS;
mutex_lock(&clk->prepare_lock);
- if (clk->parent == parent)
+ if (clk->parent == parent && !(clk->flags & CLKFLAG_NO_RATE_CACHE))
goto out;
rc = clk->ops->set_parent(clk, parent);
- if (!rc)
- clk->parent = parent;
out:
mutex_unlock(&clk->prepare_lock);
@@ -607,7 +638,6 @@
static void vdd_class_init(struct clk_vdd_class *vdd)
{
struct handoff_vdd *v;
- int i;
if (!vdd)
return;
@@ -621,9 +651,6 @@
if (vote_vdd_level(vdd, vdd->num_levels - 1))
pr_err("failed to vote for %s\n", vdd->class_name);
- for (i = 0; i < vdd->num_regulators; i++)
- regulator_enable(vdd->regulator[i]);
-
v = kmalloc(sizeof(*v), GFP_KERNEL);
if (!v) {
pr_err("Unable to kmalloc. %s will be stuck at max.\n",
diff --git a/arch/arm/mach-msm/cpr-regulator.c b/arch/arm/mach-msm/cpr-regulator.c
index 6ddf340..28afc91 100644
--- a/arch/arm/mach-msm/cpr-regulator.c
+++ b/arch/arm/mach-msm/cpr-regulator.c
@@ -32,6 +32,10 @@
/* Register Offsets for RB-CPR and Bit Definitions */
+/* RBCPR Version Register */
+#define REG_RBCPR_VERSION 0
+#define RBCPR_VER_2 0x02
+
/* RBCPR Gate Count and Target Registers */
#define REG_RBCPR_GCNT_TARGET(n) (0x60 + 4 * n)
@@ -130,6 +134,16 @@
#define BYTES_PER_FUSE_ROW 8
+#define FLAGS_IGNORE_1ST_IRQ_STATUS BIT(0)
+#define FLAGS_SET_MIN_VOLTAGE BIT(1)
+#define FLAGS_UPLIFT_QUOT_VOLT BIT(2)
+
+struct quot_adjust_info {
+ int speed_bin;
+ int virtual_corner;
+ int quot_adjust;
+};
+
enum voltage_change_dir {
NO_CHANGE,
DOWN,
@@ -149,14 +163,11 @@
/* Process voltage parameters */
u32 pvs_init_v[CPR_PVS_EFUSE_BINS_MAX];
- u32 pvs_corner_v[NUM_APC_PVS][CPR_CORNER_MAX];
+ u32 pvs_corner_v[NUM_APC_PVS][CPR_FUSE_CORNER_MAX];
/* Process voltage variables */
u32 pvs_bin;
u32 process;
-
- /* Control parameter to read efuse parameters by trustzone API */
- bool use_tz_api;
-
+ u32 speed_bin;
/* APC voltage regulator */
struct regulator *vdd_apc;
@@ -170,8 +181,8 @@
u64 cpr_fuse_bits;
bool cpr_fuse_disable;
bool cpr_fuse_local;
- int cpr_fuse_target_quot[CPR_CORNER_MAX];
- int cpr_fuse_ro_sel[CPR_CORNER_MAX];
+ int cpr_fuse_target_quot[CPR_FUSE_CORNER_MAX];
+ int cpr_fuse_ro_sel[CPR_FUSE_CORNER_MAX];
int gcnt;
unsigned int cpr_irq;
@@ -179,13 +190,13 @@
phys_addr_t rbcpr_clk_addr;
struct mutex cpr_mutex;
- int ceiling_volt[CPR_CORNER_MAX];
- int floor_volt[CPR_CORNER_MAX];
- int last_volt[CPR_CORNER_MAX];
+ int ceiling_volt[CPR_FUSE_CORNER_MAX];
+ int floor_volt[CPR_FUSE_CORNER_MAX];
+ int *last_volt;
int step_volt;
- int save_ctl[CPR_CORNER_MAX];
- int save_irq[CPR_CORNER_MAX];
+ int *save_ctl;
+ int *save_irq;
u32 save_regs[CPR_NUM_SAVE_REGS];
u32 save_reg_val[CPR_NUM_SAVE_REGS];
@@ -204,6 +215,11 @@
u32 gcnt_time_us;
u32 vdd_apc_step_up_limit;
u32 vdd_apc_step_down_limit;
+ u32 flags;
+ int *corner_map;
+ u32 num_corners;
+ int *quot_adjust;
+ u32 quotient_adjustment;
};
#define CPR_DEBUG_MASK_IRQ BIT(0)
@@ -228,7 +244,8 @@
} while (0)
-static u64 cpr_read_efuse_row(struct cpr_regulator *cpr_vreg, u32 row_num)
+static u64 cpr_read_efuse_row(struct cpr_regulator *cpr_vreg, u32 row_num,
+ bool use_tz_api)
{
int rc;
u64 efuse_bits;
@@ -242,7 +259,7 @@
u32 status;
} rsp;
- if (cpr_vreg->use_tz_api != true) {
+ if (!use_tz_api) {
efuse_bits = readll_relaxed(cpr_vreg->efuse_base
+ row_num * BYTES_PER_FUSE_ROW);
return efuse_bits;
@@ -325,9 +342,11 @@
static void cpr_ctl_enable(struct cpr_regulator *cpr_vreg, int corner)
{
u32 val;
+ int fuse_corner = cpr_vreg->corner_map[corner];
if (cpr_is_allowed(cpr_vreg) &&
- (cpr_vreg->ceiling_volt[corner] > cpr_vreg->floor_volt[corner]))
+ (cpr_vreg->ceiling_volt[fuse_corner] >
+ cpr_vreg->floor_volt[fuse_corner]))
val = RBCPR_CTL_LOOP_EN;
else
val = 0;
@@ -371,9 +390,12 @@
static void cpr_corner_restore(struct cpr_regulator *cpr_vreg, int corner)
{
u32 gcnt, ctl, irq, ro_sel;
+ int fuse_corner = cpr_vreg->corner_map[corner];
- ro_sel = cpr_vreg->cpr_fuse_ro_sel[corner];
- gcnt = cpr_vreg->gcnt | cpr_vreg->cpr_fuse_target_quot[corner];
+ ro_sel = cpr_vreg->cpr_fuse_ro_sel[fuse_corner];
+ gcnt = cpr_vreg->gcnt | (cpr_vreg->cpr_fuse_target_quot[fuse_corner] -
+ cpr_vreg->quot_adjust[corner]);
+
cpr_write(cpr_vreg, REG_RBCPR_GCNT_TARGET(ro_sel), gcnt);
ctl = cpr_vreg->save_ctl[corner];
cpr_write(cpr_vreg, REG_RBCPR_CTL, ctl);
@@ -411,8 +433,9 @@
goto _exit;
}
- cpr_debug("%d -> %d [corner=%d]\n",
- old_cpr_enable, cpr_enable, the_cpr->corner);
+ cpr_debug("%d -> %d [corner=%d, fuse_corner=%d]\n",
+ old_cpr_enable, cpr_enable, the_cpr->corner,
+ the_cpr->corner_map[the_cpr->corner]);
if (the_cpr->cpr_fuse_disable) {
/* Already disabled */
@@ -458,17 +481,18 @@
static int cpr_mx_get(struct cpr_regulator *cpr_vreg, int corner, int apc_volt)
{
int vdd_mx;
+ int fuse_corner = cpr_vreg->corner_map[corner];
switch (cpr_vreg->vdd_mx_vmin_method) {
case VDD_MX_VMIN_APC:
vdd_mx = apc_volt;
break;
case VDD_MX_VMIN_APC_CORNER_CEILING:
- vdd_mx = cpr_vreg->ceiling_volt[corner];
+ vdd_mx = cpr_vreg->ceiling_volt[fuse_corner];
break;
case VDD_MX_VMIN_APC_SLOW_CORNER_CEILING:
vdd_mx = cpr_vreg->pvs_corner_v[APC_PVS_SLOW]
- [CPR_CORNER_TURBO];
+ [CPR_FUSE_CORNER_TURBO];
break;
case VDD_MX_VMIN_MX_VMAX:
vdd_mx = cpr_vreg->vdd_mx_vmax;
@@ -485,15 +509,19 @@
int vdd_mx_vmin)
{
int rc;
+ int fuse_corner = cpr_vreg->corner_map[corner];
rc = regulator_set_voltage(cpr_vreg->vdd_mx, vdd_mx_vmin,
cpr_vreg->vdd_mx_vmax);
- cpr_debug("[corner:%d] %d uV\n", corner, vdd_mx_vmin);
- if (!rc)
+ cpr_debug("[corner:%d, fuse_corner:%d] %d uV\n", corner,
+ fuse_corner, vdd_mx_vmin);
+
+ if (!rc) {
cpr_vreg->vdd_mx_vmin = vdd_mx_vmin;
- else
- pr_err("set: vdd_mx [%d] = %d uV: rc=%d\n",
- corner, vdd_mx_vmin, rc);
+ } else {
+ pr_err("set: vdd_mx [corner:%d, fuse_corner:%d] = %d uV failed: rc=%d\n",
+ corner, fuse_corner, vdd_mx_vmin, rc);
+ }
return rc;
}
@@ -531,9 +559,11 @@
enum voltage_change_dir dir)
{
u32 reg_val, error_steps, reg_mask;
- int last_volt, new_volt, corner;
+ int last_volt, new_volt, corner, fuse_corner;
+ u32 gcnt, quot;
corner = cpr_vreg->corner;
+ fuse_corner = cpr_vreg->corner_map[corner];
reg_val = cpr_read(cpr_vreg, REG_RBCPR_RESULT_0);
@@ -541,18 +571,27 @@
& RBCPR_RESULT0_ERROR_STEPS_MASK;
last_volt = cpr_vreg->last_volt[corner];
- cpr_debug_irq("last_volt[corner:%d] = %d uV\n", corner, last_volt);
+ cpr_debug_irq("last_volt[corner:%d, fuse_corner:%d] = %d uV\n", corner,
+ fuse_corner, last_volt);
+
+ gcnt = cpr_read(cpr_vreg, REG_RBCPR_GCNT_TARGET
+ (cpr_vreg->cpr_fuse_ro_sel[fuse_corner]));
+ quot = gcnt & ((1 << RBCPR_GCNT_TARGET_GCNT_SHIFT) - 1);
if (dir == UP) {
cpr_debug_irq("Up: cpr status = 0x%08x (error_steps=%d)\n",
reg_val, error_steps);
- if (last_volt >= cpr_vreg->ceiling_volt[corner]) {
- cpr_debug_irq("[corn:%d] @ ceiling: %d >= %d: NACK\n",
- corner, last_volt,
- cpr_vreg->ceiling_volt[corner]);
+ if (last_volt >= cpr_vreg->ceiling_volt[fuse_corner]) {
+ cpr_debug_irq(
+ "[corn:%d, fuse_corn:%d] @ ceiling: %d >= %d: NACK\n",
+ corner, fuse_corner, last_volt,
+ cpr_vreg->ceiling_volt[fuse_corner]);
cpr_irq_clr_nack(cpr_vreg);
+ cpr_debug_irq("gcnt = 0x%08x (quot = %d)\n", gcnt,
+ quot);
+
/* Maximize the UP threshold */
reg_mask = RBCPR_CTL_UP_THRESHOLD_MASK <<
RBCPR_CTL_UP_THRESHOLD_SHIFT;
@@ -570,11 +609,12 @@
/* Calculate new voltage */
new_volt = last_volt + (error_steps * cpr_vreg->step_volt);
- if (new_volt > cpr_vreg->ceiling_volt[corner]) {
+ if (new_volt > cpr_vreg->ceiling_volt[fuse_corner]) {
cpr_debug_irq("new_volt(%d) >= ceiling(%d): Clamp\n",
new_volt,
- cpr_vreg->ceiling_volt[corner]);
- new_volt = cpr_vreg->ceiling_volt[corner];
+ cpr_vreg->ceiling_volt[fuse_corner]);
+
+ new_volt = cpr_vreg->ceiling_volt[fuse_corner];
}
if (cpr_scale_voltage(cpr_vreg, corner, new_volt, dir)) {
@@ -583,13 +623,9 @@
}
cpr_vreg->last_volt[corner] = new_volt;
- /* Restore default threshold for DOWN */
- reg_mask = RBCPR_CTL_DN_THRESHOLD_MASK <<
- RBCPR_CTL_DN_THRESHOLD_SHIFT;
- reg_val = cpr_vreg->down_threshold <<
- RBCPR_CTL_DN_THRESHOLD_SHIFT;
- /* and disable auto nack down */
- reg_mask |= RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN;
+ /* Disable auto nack down */
+ reg_mask = RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN;
+ reg_val = 0;
cpr_ctl_modify(cpr_vreg, reg_mask, reg_val);
@@ -599,26 +635,26 @@
/* Ack */
cpr_irq_clr_ack(cpr_vreg);
- cpr_debug_irq("UP: -> new_volt[corner:%d] = %d uV\n",
- corner, new_volt);
+ cpr_debug_irq(
+ "UP: -> new_volt[corner:%d, fuse_corner:%d] = %d uV\n",
+ corner, fuse_corner, new_volt);
} else if (dir == DOWN) {
cpr_debug_irq("Down: cpr status = 0x%08x (error_steps=%d)\n",
reg_val, error_steps);
- if (last_volt <= cpr_vreg->floor_volt[corner]) {
- cpr_debug_irq("[corn:%d] @ floor: %d <= %d: NACK\n",
- corner, last_volt,
- cpr_vreg->floor_volt[corner]);
+ if (last_volt <= cpr_vreg->floor_volt[fuse_corner]) {
+ cpr_debug_irq(
+ "[corn:%d, fuse_corner:%d] @ floor: %d <= %d: NACK\n",
+ corner, fuse_corner, last_volt,
+ cpr_vreg->floor_volt[fuse_corner]);
cpr_irq_clr_nack(cpr_vreg);
- /* Maximize the DOWN threshold */
- reg_mask = RBCPR_CTL_DN_THRESHOLD_MASK <<
- RBCPR_CTL_DN_THRESHOLD_SHIFT;
- reg_val = reg_mask;
+ cpr_debug_irq("gcnt = 0x%08x (quot = %d)\n", gcnt,
+ quot);
/* Enable auto nack down */
- reg_mask |= RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN;
- reg_val |= RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN;
+ reg_mask = RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN;
+ reg_val = RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN;
cpr_ctl_modify(cpr_vreg, reg_mask, reg_val);
@@ -637,11 +673,11 @@
/* Calculte new voltage */
new_volt = last_volt - (error_steps * cpr_vreg->step_volt);
- if (new_volt < cpr_vreg->floor_volt[corner]) {
+ if (new_volt < cpr_vreg->floor_volt[fuse_corner]) {
cpr_debug_irq("new_volt(%d) < floor(%d): Clamp\n",
new_volt,
- cpr_vreg->floor_volt[corner]);
- new_volt = cpr_vreg->floor_volt[corner];
+ cpr_vreg->floor_volt[fuse_corner]);
+ new_volt = cpr_vreg->floor_volt[fuse_corner];
}
if (cpr_scale_voltage(cpr_vreg, corner, new_volt, dir)) {
@@ -660,8 +696,9 @@
/* Ack */
cpr_irq_clr_ack(cpr_vreg);
- cpr_debug_irq("DOWN: -> new_volt[corner:%d] = %d uV\n",
- corner, new_volt);
+ cpr_debug_irq(
+ "DOWN: -> new_volt[corner:%d, fuse_corner:%d] = %d uV\n",
+ corner, fuse_corner, new_volt);
}
}
@@ -673,6 +710,9 @@
mutex_lock(&cpr_vreg->cpr_mutex);
reg_val = cpr_read(cpr_vreg, REG_RBIF_IRQ_STATUS);
+ if (cpr_vreg->flags & FLAGS_IGNORE_1ST_IRQ_STATUS)
+ reg_val = cpr_read(cpr_vreg, REG_RBIF_IRQ_STATUS);
+
cpr_debug_irq("IRQ_STATUS = 0x%02X\n", reg_val);
if (!cpr_is_allowed(cpr_vreg)) {
@@ -780,6 +820,7 @@
int rc;
int new_volt;
enum voltage_change_dir change_dir = NO_CHANGE;
+ int fuse_corner = cpr_vreg->corner_map[corner];
mutex_lock(&cpr_vreg->cpr_mutex);
@@ -787,10 +828,12 @@
cpr_ctl_disable(cpr_vreg);
new_volt = cpr_vreg->last_volt[corner];
} else {
- new_volt = cpr_vreg->pvs_corner_v[cpr_vreg->process][corner];
+ new_volt = cpr_vreg->pvs_corner_v
+ [cpr_vreg->process][fuse_corner];
}
- cpr_debug("[corner:%d] = %d uV\n", corner, new_volt);
+ cpr_debug("[corner:%d, fuse_corner:%d] = %d uV\n", corner, fuse_corner,
+ new_volt);
if (corner > cpr_vreg->corner)
change_dir = UP;
@@ -883,11 +926,13 @@
#define cpr_regulator_resume NULL
#endif
-static int __devinit cpr_config(struct cpr_regulator *cpr_vreg)
+static int __devinit cpr_config(struct cpr_regulator *cpr_vreg,
+ struct device *dev)
{
int i;
u32 val, gcnt, reg;
void __iomem *rbcpr_clk;
+ int size;
/* Use 19.2 MHz clock for CPR. */
rbcpr_clk = ioremap(cpr_vreg->rbcpr_clk_addr, 4);
@@ -958,38 +1003,78 @@
cpr_vreg->save_regs[5] = REG_RBIF_IRQ_EN(cpr_vreg->irq_line);
cpr_vreg->save_regs[6] = REG_RBCPR_CTL;
cpr_vreg->save_regs[7] = REG_RBCPR_GCNT_TARGET
- (cpr_vreg->cpr_fuse_ro_sel[CPR_CORNER_SVS]);
+ (cpr_vreg->cpr_fuse_ro_sel[CPR_FUSE_CORNER_SVS]);
cpr_vreg->save_regs[8] = REG_RBCPR_GCNT_TARGET
- (cpr_vreg->cpr_fuse_ro_sel[CPR_CORNER_NORMAL]);
+ (cpr_vreg->cpr_fuse_ro_sel[CPR_FUSE_CORNER_NORMAL]);
cpr_vreg->save_regs[9] = REG_RBCPR_GCNT_TARGET
- (cpr_vreg->cpr_fuse_ro_sel[CPR_CORNER_TURBO]);
+ (cpr_vreg->cpr_fuse_ro_sel[CPR_FUSE_CORNER_TURBO]);
cpr_irq_set(cpr_vreg, CPR_INT_DEFAULT);
- cpr_corner_save(cpr_vreg, CPR_CORNER_SVS);
- cpr_corner_save(cpr_vreg, CPR_CORNER_NORMAL);
- cpr_corner_save(cpr_vreg, CPR_CORNER_TURBO);
+ val = cpr_read(cpr_vreg, REG_RBCPR_VERSION);
+ if (val <= RBCPR_VER_2)
+ cpr_vreg->flags |= FLAGS_IGNORE_1ST_IRQ_STATUS;
+
+ size = cpr_vreg->num_corners + 1;
+ cpr_vreg->save_ctl = devm_kzalloc(dev, sizeof(int) * size, GFP_KERNEL);
+ cpr_vreg->save_irq = devm_kzalloc(dev, sizeof(int) * size, GFP_KERNEL);
+ if (!cpr_vreg->save_ctl || !cpr_vreg->save_irq)
+ return -ENOMEM;
+
+ for (i = 1; i < size; i++)
+ cpr_corner_save(cpr_vreg, i);
return 0;
}
-static int __devinit cpr_is_fuse_redundant(struct cpr_regulator *cpr_vreg,
- u32 redun_sel[4])
+static int __devinit cpr_fuse_is_setting_expected(struct cpr_regulator *cpr_vreg,
+ u32 sel_array[5])
{
u64 fuse_bits;
- int redundant;
+ u32 ret;
- fuse_bits = cpr_read_efuse_row(cpr_vreg, redun_sel[0]);
- fuse_bits = (fuse_bits >> redun_sel[1]) & ((1 << redun_sel[2]) - 1);
- if (fuse_bits == redun_sel[3])
- redundant = 1;
+ fuse_bits = cpr_read_efuse_row(cpr_vreg, sel_array[0], sel_array[4]);
+ ret = (fuse_bits >> sel_array[1]) & ((1 << sel_array[2]) - 1);
+ if (ret == sel_array[3])
+ ret = 1;
else
- redundant = 0;
+ ret = 0;
- pr_info("[row:%d] = 0x%llx @%d:%d = %d?: redundant=%d\n",
- redun_sel[0], fuse_bits,
- redun_sel[1], redun_sel[2], redun_sel[3], redundant);
- return redundant;
+ pr_info("[row:%d] = 0x%llx @%d:%d == %d ?: %s\n",
+ sel_array[0], fuse_bits,
+ sel_array[1], sel_array[2],
+ sel_array[3],
+ (ret == 1) ? "yes" : "no");
+ return ret;
+}
+
+static int cpr_voltage_uplift_wa_inc_volt(struct cpr_regulator *cpr_vreg,
+ struct device_node *of_node)
+{
+ u32 uplift_voltage;
+ u32 uplift_max_volt = 0;
+ int rc, i;
+
+ rc = of_property_read_u32(of_node,
+ "qcom,cpr-uplift-voltage", &uplift_voltage);
+ if (rc < 0) {
+ pr_err("cpr-uplift-voltage is missing, rc = %d", rc);
+ return rc;
+ }
+ rc = of_property_read_u32(of_node,
+ "qcom,cpr-uplift-max-volt", &uplift_max_volt);
+ if (rc < 0) {
+ pr_err("cpr-uplift-max-volt is missing, rc = %d", rc);
+ return rc;
+ }
+
+ for (i = 0; i < CPR_PVS_EFUSE_BINS_MAX; i++) {
+ cpr_vreg->pvs_init_v[i] += uplift_voltage;
+ if (cpr_vreg->pvs_init_v[i] > uplift_max_volt)
+ cpr_vreg->pvs_init_v[i] = uplift_max_volt;
+ }
+
+ return rc;
}
static int __devinit cpr_pvs_init(struct platform_device *pdev,
@@ -998,30 +1083,30 @@
struct device_node *of_node = pdev->dev.of_node;
u64 efuse_bits;
int rc, process;
- u32 pvs_fuse[3], pvs_fuse_redun_sel[4];
- u32 init_v;
+ u32 pvs_fuse[4], pvs_fuse_redun_sel[5];
+ u32 init_v, quot_adjust;
bool redundant;
size_t pvs_bins;
rc = of_property_read_u32_array(of_node, "qcom,pvs-fuse-redun-sel",
- pvs_fuse_redun_sel, 4);
+ pvs_fuse_redun_sel, 5);
if (rc < 0) {
pr_err("pvs-fuse-redun-sel missing: rc=%d\n", rc);
return rc;
}
- redundant = cpr_is_fuse_redundant(cpr_vreg, pvs_fuse_redun_sel);
+ redundant = cpr_fuse_is_setting_expected(cpr_vreg, pvs_fuse_redun_sel);
if (redundant) {
rc = of_property_read_u32_array(of_node, "qcom,pvs-fuse-redun",
- pvs_fuse, 3);
+ pvs_fuse, 4);
if (rc < 0) {
pr_err("pvs-fuse-redun missing: rc=%d\n", rc);
return rc;
}
} else {
rc = of_property_read_u32_array(of_node, "qcom,pvs-fuse",
- pvs_fuse, 3);
+ pvs_fuse, 4);
if (rc < 0) {
pr_err("pvs-fuse missing: rc=%d\n", rc);
return rc;
@@ -1030,7 +1115,7 @@
/* Construct PVS process # from the efuse bits */
- efuse_bits = cpr_read_efuse_row(cpr_vreg, pvs_fuse[0]);
+ efuse_bits = cpr_read_efuse_row(cpr_vreg, pvs_fuse[0], pvs_fuse[3]);
cpr_vreg->pvs_bin = (efuse_bits >> pvs_fuse[1]) &
((1 << pvs_fuse[2]) - 1);
@@ -1043,18 +1128,28 @@
return rc;
}
+ if (cpr_vreg->flags & FLAGS_UPLIFT_QUOT_VOLT) {
+ rc = cpr_voltage_uplift_wa_inc_volt(cpr_vreg, of_node);
+ if (rc < 0) {
+ pr_err("pvs volt uplift wa apply failed: %d", rc);
+ return rc;
+ }
+ }
+
init_v = cpr_vreg->pvs_init_v[cpr_vreg->pvs_bin];
for (process = NUM_APC_PVS - 1; process > APC_PVS_NO; process--) {
- if (init_v <= cpr_vreg->pvs_corner_v[process][CPR_CORNER_TURBO])
+ if (init_v <= cpr_vreg->pvs_corner_v
+ [process][CPR_FUSE_CORNER_TURBO])
break;
}
if (process == APC_PVS_NO) {
process = APC_PVS_SLOW;
- cpr_vreg->pvs_corner_v[process][CPR_CORNER_TURBO] = init_v;
+ cpr_vreg->pvs_corner_v[process][CPR_FUSE_CORNER_TURBO] = init_v;
cpr_vreg->ceiling_max = init_v;
} else if (process == APC_PVS_FAST &&
- init_v < cpr_vreg->pvs_corner_v[APC_PVS_FAST][CPR_CORNER_SVS]) {
+ init_v < cpr_vreg->pvs_corner_v
+ [APC_PVS_FAST][CPR_FUSE_CORNER_SVS]) {
process = APC_PVS_SLOW;
}
@@ -1062,10 +1157,15 @@
pvs_fuse[0], efuse_bits, pvs_fuse[2],
cpr_vreg->pvs_bin, process);
pr_info("pvs initial turbo voltage_= from %u to %u\n",
- init_v, cpr_vreg->pvs_corner_v[process][CPR_CORNER_TURBO]);
+ init_v, cpr_vreg->pvs_corner_v[process][CPR_FUSE_CORNER_TURBO]);
cpr_vreg->process = process;
+ rc = of_property_read_u32(of_node,
+ "qcom,cpr-quotient-adjustment", "_adjust);
+ if (!rc)
+ cpr_vreg->quotient_adjustment = quot_adjust;
+
return 0;
}
@@ -1143,38 +1243,157 @@
}
}
+static int cpr_voltage_uplift_wa_inc_quot(struct cpr_regulator *cpr_vreg,
+ struct device_node *of_node)
+{
+ u32 delta_quot[3];
+ int rc, i;
+
+ rc = of_property_read_u32_array(of_node,
+ "qcom,cpr-uplift-quotient", delta_quot, 3);
+ if (rc < 0) {
+ pr_err("cpr-uplift-quotient is missing: %d", rc);
+ return rc;
+ }
+ for (i = CPR_FUSE_CORNER_SVS; i < CPR_FUSE_CORNER_MAX; i++)
+ cpr_vreg->cpr_fuse_target_quot[i] += delta_quot[i-1];
+ return rc;
+}
+
+static int cpr_get_of_corner_mappings(struct cpr_regulator *cpr_vreg,
+ struct device *dev)
+{
+ int rc = 0;
+ int i, size, stripe_size;
+ struct property *prop;
+ u32 *tmp;
+ bool corners_mapped;
+
+ prop = of_find_property(dev->of_node, "qcom,cpr-corner-map", NULL);
+
+ if (prop) {
+ size = prop->length / sizeof(u32);
+ corners_mapped = true;
+ } else {
+ size = CPR_FUSE_CORNER_MAX - 1;
+ corners_mapped = false;
+ }
+
+ cpr_vreg->corner_map = devm_kzalloc(dev, sizeof(int) * (size + 1),
+ GFP_KERNEL);
+ if (!cpr_vreg->corner_map) {
+ pr_err("Can't allocate cpr_vreg->corner_map memory\n");
+ return -ENOMEM;
+ }
+ cpr_vreg->num_corners = size;
+
+ if (!corners_mapped) {
+ for (i = CPR_FUSE_CORNER_SVS; i < CPR_FUSE_CORNER_MAX; i++)
+ cpr_vreg->corner_map[i] = i;
+ } else {
+ rc = of_property_read_u32_array(dev->of_node,
+ "qcom,cpr-corner-map", &cpr_vreg->corner_map[1], size);
+
+ if (rc) {
+ pr_err("qcom,cpr-corner-map missing, rc = %d", rc);
+ return rc;
+ }
+ }
+
+ cpr_vreg->quot_adjust = devm_kzalloc(dev,
+ sizeof(int) * (cpr_vreg->num_corners + 1),
+ GFP_KERNEL);
+ if (!cpr_vreg->quot_adjust) {
+ pr_err("Can't allocate cpr_vreg->quot_adjust memory\n");
+ return -ENOMEM;
+ }
+
+ prop = of_find_property(dev->of_node, "qcom,cpr-quot-adjust-table",
+ NULL);
+
+ if (prop) {
+ if (!corners_mapped) {
+ pr_err("qcom,cpr-corner-map missing\n");
+ return -EINVAL;
+ }
+
+ size = prop->length / sizeof(u32);
+ tmp = kzalloc(sizeof(u32) * size, GFP_KERNEL);
+ if (!tmp)
+ return -ENOMEM;
+
+ rc = of_property_read_u32_array(dev->of_node,
+ "qcom,cpr-quot-adjust-table", tmp, size);
+ if (rc) {
+ pr_err("qcom,cpr-quot-adjust-table missing, rc = %d",
+ rc);
+ kfree(tmp);
+ return rc;
+ }
+
+ stripe_size = sizeof(struct quot_adjust_info) / sizeof(int);
+
+ if ((size % stripe_size) != 0) {
+ pr_err("qcom,cpr-quot-adjust-table data is not correct");
+ kfree(tmp);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < size; i += stripe_size) {
+ if (tmp[i] == cpr_vreg->speed_bin) {
+ if (tmp[i + 1] >= 1 &&
+ tmp[i + 1] <=
+ cpr_vreg->num_corners) {
+ cpr_vreg->quot_adjust[tmp[i + 1]] =
+ tmp[i + 2];
+ } else {
+ pr_err("qcom,cpr-quot-adjust-table data is not correct");
+ kfree(tmp);
+ return -EINVAL;
+ }
+ }
+ }
+
+ kfree(tmp);
+ }
+
+ return 0;
+}
+
static int __devinit cpr_init_cpr_efuse(struct platform_device *pdev,
struct cpr_regulator *cpr_vreg)
{
struct device_node *of_node = pdev->dev.of_node;
int i, rc = 0;
bool redundant;
- u32 cpr_fuse_redun_sel[4];
+ u32 cpr_fuse_redun_sel[5];
char *targ_quot_str, *ro_sel_str;
- u32 cpr_fuse_row;
+ u32 cpr_fuse_row[2];
u32 bp_cpr_disable, bp_scheme;
- int bp_target_quot[CPR_CORNER_MAX];
- int bp_ro_sel[CPR_CORNER_MAX];
+ int bp_target_quot[CPR_FUSE_CORNER_MAX];
+ int bp_ro_sel[CPR_FUSE_CORNER_MAX];
u32 ro_sel, val;
u64 fuse_bits, fuse_bits_2;
rc = of_property_read_u32_array(of_node, "qcom,cpr-fuse-redun-sel",
- cpr_fuse_redun_sel, 4);
+ cpr_fuse_redun_sel, 5);
if (rc < 0) {
pr_err("cpr-fuse-redun-sel missing: rc=%d\n", rc);
return rc;
}
- redundant = cpr_is_fuse_redundant(cpr_vreg, cpr_fuse_redun_sel);
+ redundant = cpr_fuse_is_setting_expected(cpr_vreg, cpr_fuse_redun_sel);
if (redundant) {
- CPR_PROP_READ_U32(of_node, "cpr-fuse-redun-row",
- &cpr_fuse_row, rc);
+ rc = of_property_read_u32_array(of_node,
+ "qcom,cpr-fuse-redun-row",
+ cpr_fuse_row, 2);
targ_quot_str = "qcom,cpr-fuse-redun-target-quot";
ro_sel_str = "qcom,cpr-fuse-redun-ro-sel";
} else {
- CPR_PROP_READ_U32(of_node, "cpr-fuse-row",
- &cpr_fuse_row, rc);
+ rc = of_property_read_u32_array(of_node,
+ "qcom,cpr-fuse-row",
+ cpr_fuse_row, 2);
targ_quot_str = "qcom,cpr-fuse-target-quot";
ro_sel_str = "qcom,cpr-fuse-ro-sel";
}
@@ -1183,8 +1402,8 @@
rc = of_property_read_u32_array(of_node,
targ_quot_str,
- &bp_target_quot[CPR_CORNER_SVS],
- CPR_CORNER_MAX - CPR_CORNER_SVS);
+ &bp_target_quot[CPR_FUSE_CORNER_SVS],
+ CPR_FUSE_CORNER_MAX - CPR_FUSE_CORNER_SVS);
if (rc < 0) {
pr_err("missing %s: rc=%d\n", targ_quot_str, rc);
return rc;
@@ -1192,16 +1411,17 @@
rc = of_property_read_u32_array(of_node,
ro_sel_str,
- &bp_ro_sel[CPR_CORNER_SVS],
- CPR_CORNER_MAX - CPR_CORNER_SVS);
+ &bp_ro_sel[CPR_FUSE_CORNER_SVS],
+ CPR_FUSE_CORNER_MAX - CPR_FUSE_CORNER_SVS);
if (rc < 0) {
pr_err("missing %s: rc=%d\n", ro_sel_str, rc);
return rc;
}
/* Read the control bits of eFuse */
- fuse_bits = cpr_read_efuse_row(cpr_vreg, cpr_fuse_row);
- pr_info("[row:%d] = 0x%llx\n", cpr_fuse_row, fuse_bits);
+ fuse_bits = cpr_read_efuse_row(cpr_vreg, cpr_fuse_row[0],
+ cpr_fuse_row[1]);
+ pr_info("[row:%d] = 0x%llx\n", cpr_fuse_row[0], fuse_bits);
if (redundant) {
if (of_property_read_bool(of_node,
@@ -1216,21 +1436,23 @@
return rc;
fuse_bits_2 = fuse_bits;
} else {
- u32 temp_row;
+ u32 temp_row[2];
/* Use original fuse if no optional property */
CPR_PROP_READ_U32(of_node, "cpr-fuse-bp-cpr-disable",
&bp_cpr_disable, rc);
CPR_PROP_READ_U32(of_node, "cpr-fuse-bp-scheme",
&bp_scheme, rc);
- CPR_PROP_READ_U32(of_node, "cpr-fuse-row",
- &temp_row, rc);
+ rc = of_property_read_u32_array(of_node,
+ "qcom,cpr-fuse-row",
+ temp_row, 2);
if (rc)
return rc;
- fuse_bits_2 = cpr_read_efuse_row(cpr_vreg, temp_row);
+ fuse_bits_2 = cpr_read_efuse_row(cpr_vreg, temp_row[0],
+ temp_row[1]);
pr_info("[original row:%d] = 0x%llx\n",
- temp_row, fuse_bits_2);
+ temp_row[0], fuse_bits_2);
}
} else {
CPR_PROP_READ_U32(of_node, "cpr-fuse-bp-cpr-disable",
@@ -1248,17 +1470,30 @@
pr_info("disable = %d, local = %d\n",
cpr_vreg->cpr_fuse_disable, cpr_vreg->cpr_fuse_local);
- for (i = CPR_CORNER_SVS; i < CPR_CORNER_MAX; i++) {
+ for (i = CPR_FUSE_CORNER_SVS; i < CPR_FUSE_CORNER_MAX; i++) {
ro_sel = (fuse_bits >> bp_ro_sel[i])
& CPR_FUSE_RO_SEL_BITS_MASK;
val = (fuse_bits >> bp_target_quot[i])
& CPR_FUSE_TARGET_QUOT_BITS_MASK;
+ val += cpr_vreg->quotient_adjustment;
cpr_vreg->cpr_fuse_target_quot[i] = val;
cpr_vreg->cpr_fuse_ro_sel[i] = ro_sel;
pr_info("Corner[%d]: ro_sel = %d, target quot = %d\n",
i, ro_sel, val);
}
+ if (cpr_vreg->flags & FLAGS_UPLIFT_QUOT_VOLT) {
+ cpr_voltage_uplift_wa_inc_quot(cpr_vreg, of_node);
+ for (i = CPR_FUSE_CORNER_SVS; i < CPR_FUSE_CORNER_MAX; i++) {
+ pr_info("Corner[%d]: uplifted target quot = %d\n",
+ i, cpr_vreg->cpr_fuse_target_quot[i]);
+ }
+ }
+
+ rc = cpr_get_of_corner_mappings(cpr_vreg, &pdev->dev);
+ if (rc)
+ return rc;
+
cpr_vreg->cpr_fuse_bits = fuse_bits;
if (!cpr_vreg->cpr_fuse_bits) {
cpr_vreg->cpr_fuse_disable = 1;
@@ -1268,10 +1503,12 @@
int *quot = cpr_vreg->cpr_fuse_target_quot;
bool valid_fuse = true;
- if ((quot[CPR_CORNER_TURBO] > quot[CPR_CORNER_NORMAL]) &&
- (quot[CPR_CORNER_NORMAL] > quot[CPR_CORNER_SVS])) {
- if ((quot[CPR_CORNER_TURBO] -
- quot[CPR_CORNER_NORMAL])
+ if ((quot[CPR_FUSE_CORNER_TURBO] >
+ quot[CPR_FUSE_CORNER_NORMAL]) &&
+ (quot[CPR_FUSE_CORNER_NORMAL] >
+ quot[CPR_FUSE_CORNER_SVS])) {
+ if ((quot[CPR_FUSE_CORNER_TURBO] -
+ quot[CPR_FUSE_CORNER_NORMAL])
<= CPR_FUSE_MIN_QUOT_DIFF)
valid_fuse = false;
} else {
@@ -1287,18 +1524,27 @@
return 0;
}
-static int __devinit cpr_init_cpr_voltages(struct cpr_regulator *cpr_vreg)
+static int __devinit cpr_init_cpr_voltages(struct cpr_regulator *cpr_vreg,
+ struct device *dev)
{
int i;
+ int size = cpr_vreg->num_corners + 1;
+
+ cpr_vreg->last_volt = devm_kzalloc(dev, sizeof(int) * size, GFP_KERNEL);
+ if (!cpr_vreg->last_volt)
+ return -EINVAL;
/* Construct CPR voltage limits */
- for (i = CPR_CORNER_SVS; i < CPR_CORNER_MAX; i++) {
+ for (i = CPR_FUSE_CORNER_SVS; i < CPR_FUSE_CORNER_MAX; i++) {
cpr_vreg->floor_volt[i] =
cpr_vreg->pvs_corner_v[APC_PVS_FAST][i];
cpr_vreg->ceiling_volt[i] =
cpr_vreg->pvs_corner_v[APC_PVS_SLOW][i];
- cpr_vreg->last_volt[i] =
- cpr_vreg->pvs_corner_v[cpr_vreg->process][i];
+ }
+
+ for (i = 1; i < size; i++) {
+ cpr_vreg->last_volt[i] = cpr_vreg->pvs_corner_v
+ [cpr_vreg->process][cpr_vreg->corner_map[i]];
}
return 0;
@@ -1398,7 +1644,9 @@
resource_size(res));
/* Init all voltage set points of APC regulator for CPR */
- cpr_init_cpr_voltages(cpr_vreg);
+ rc = cpr_init_cpr_voltages(cpr_vreg, &pdev->dev);
+ if (rc)
+ return rc;
/* Init CPR configuration parameters */
rc = cpr_init_cpr_parameters(pdev, cpr_vreg);
@@ -1413,7 +1661,7 @@
}
/* Configure CPR HW but keep it disabled */
- rc = cpr_config(cpr_vreg);
+ rc = cpr_config(cpr_vreg, &pdev->dev);
if (rc)
return rc;
@@ -1452,11 +1700,6 @@
return -EINVAL;
}
- if (of_property_read_bool(pdev->dev.of_node, "qcom,use-tz-api"))
- cpr_vreg->use_tz_api = true;
- else
- cpr_vreg->use_tz_api = false;
-
return 0;
}
@@ -1465,16 +1708,86 @@
iounmap(cpr_vreg->efuse_base);
}
+static void cpr_parse_cond_min_volt_fuse(struct cpr_regulator *cpr_vreg,
+ struct device_node *of_node)
+{
+ int rc;
+ u32 fuse_sel[5];
+ /*
+ * Restrict all pvs corner voltages to a minimum value of
+ * qcom,cpr-cond-min-voltage if the fuse defined in
+ * qcom,cpr-fuse-cond-min-volt-sel does not read back with
+ * the expected value.
+ */
+ rc = of_property_read_u32_array(of_node,
+ "qcom,cpr-fuse-cond-min-volt-sel", fuse_sel, 5);
+ if (!rc) {
+ if (!cpr_fuse_is_setting_expected(cpr_vreg, fuse_sel))
+ cpr_vreg->flags |= FLAGS_SET_MIN_VOLTAGE;
+ }
+}
+
+static void cpr_parse_speed_bin_fuse(struct cpr_regulator *cpr_vreg,
+ struct device_node *of_node)
+{
+ int rc;
+ u64 fuse_bits;
+ u32 fuse_sel[4];
+ u32 speed_bits;
+
+ rc = of_property_read_u32_array(of_node,
+ "qcom,speed-bin-fuse-sel", fuse_sel, 4);
+
+ if (!rc) {
+ fuse_bits = cpr_read_efuse_row(cpr_vreg,
+ fuse_sel[0], fuse_sel[3]);
+ speed_bits = (fuse_bits >> fuse_sel[1]) &
+ ((1 << fuse_sel[2]) - 1);
+ pr_info("[row: %d]: 0x%llx, speed_bits = %d\n",
+ fuse_sel[0], fuse_bits, speed_bits);
+ cpr_vreg->speed_bin = speed_bits;
+ } else {
+ cpr_vreg->speed_bin = UINT_MAX;
+ }
+}
+
+static int cpr_voltage_uplift_enable_check(struct cpr_regulator *cpr_vreg,
+ struct device_node *of_node)
+{
+ int rc;
+ u32 fuse_sel[5];
+ u32 uplift_speed_bin;
+
+ rc = of_property_read_u32_array(of_node,
+ "qcom,cpr-fuse-uplift-sel", fuse_sel, 5);
+ if (!rc) {
+ rc = of_property_read_u32(of_node,
+ "qcom,cpr-uplift-speed-bin",
+ &uplift_speed_bin);
+ if (rc < 0) {
+ pr_err("qcom,cpr-uplift-speed-bin missing\n");
+ return rc;
+ }
+ if (cpr_fuse_is_setting_expected(cpr_vreg, fuse_sel)
+ && (uplift_speed_bin == cpr_vreg->speed_bin)
+ && !(cpr_vreg->flags & FLAGS_SET_MIN_VOLTAGE)) {
+ cpr_vreg->flags |= FLAGS_UPLIFT_QUOT_VOLT;
+ }
+ }
+ return 0;
+}
+
static int __devinit cpr_voltage_plan_init(struct platform_device *pdev,
struct cpr_regulator *cpr_vreg)
{
struct device_node *of_node = pdev->dev.of_node;
- int rc, i;
+ int rc, i, j;
+ u32 min_uv = 0;
rc = of_property_read_u32_array(of_node,
"qcom,pvs-corner-ceiling-slow",
- &cpr_vreg->pvs_corner_v[APC_PVS_SLOW][CPR_CORNER_SVS],
- CPR_CORNER_MAX - CPR_CORNER_SVS);
+ &cpr_vreg->pvs_corner_v[APC_PVS_SLOW][CPR_FUSE_CORNER_SVS],
+ CPR_FUSE_CORNER_MAX - CPR_FUSE_CORNER_SVS);
if (rc < 0) {
pr_err("pvs-corner-ceiling-slow missing: rc=%d\n", rc);
return rc;
@@ -1482,8 +1795,8 @@
rc = of_property_read_u32_array(of_node,
"qcom,pvs-corner-ceiling-nom",
- &cpr_vreg->pvs_corner_v[APC_PVS_NOM][CPR_CORNER_SVS],
- CPR_CORNER_MAX - CPR_CORNER_SVS);
+ &cpr_vreg->pvs_corner_v[APC_PVS_NOM][CPR_FUSE_CORNER_SVS],
+ CPR_FUSE_CORNER_MAX - CPR_FUSE_CORNER_SVS);
if (rc < 0) {
pr_err("pvs-corner-ceiling-norm missing: rc=%d\n", rc);
return rc;
@@ -1491,22 +1804,39 @@
rc = of_property_read_u32_array(of_node,
"qcom,pvs-corner-ceiling-fast",
- &cpr_vreg->pvs_corner_v[APC_PVS_FAST][CPR_CORNER_SVS],
- CPR_CORNER_MAX - CPR_CORNER_SVS);
+ &cpr_vreg->pvs_corner_v[APC_PVS_FAST][CPR_FUSE_CORNER_SVS],
+ CPR_FUSE_CORNER_MAX - CPR_FUSE_CORNER_SVS);
if (rc < 0) {
pr_err("pvs-corner-ceiling-fast missing: rc=%d\n", rc);
return rc;
}
+ cpr_parse_cond_min_volt_fuse(cpr_vreg, of_node);
+ cpr_parse_speed_bin_fuse(cpr_vreg, of_node);
+ rc = cpr_voltage_uplift_enable_check(cpr_vreg, of_node);
+ if (rc < 0) {
+ pr_err("voltage uplift enable check failed, %d\n", rc);
+ return rc;
+ }
+ if (cpr_vreg->flags & FLAGS_SET_MIN_VOLTAGE) {
+ of_property_read_u32(of_node, "qcom,cpr-cond-min-voltage",
+ &min_uv);
+ for (i = APC_PVS_SLOW; i < NUM_APC_PVS; i++)
+ for (j = CPR_FUSE_CORNER_SVS; j < CPR_FUSE_CORNER_MAX;
+ j++)
+ if (cpr_vreg->pvs_corner_v[i][j] < min_uv)
+ cpr_vreg->pvs_corner_v[i][j] = min_uv;
+ }
+
/* Set ceiling max and use it for APC_PVS_NO */
cpr_vreg->ceiling_max =
- cpr_vreg->pvs_corner_v[APC_PVS_SLOW][CPR_CORNER_TURBO];
+ cpr_vreg->pvs_corner_v[APC_PVS_SLOW][CPR_FUSE_CORNER_TURBO];
for (i = APC_PVS_SLOW; i < NUM_APC_PVS; i++) {
pr_info("[%d] [%d %d %d] uV\n", i,
- cpr_vreg->pvs_corner_v[i][CPR_CORNER_SVS],
- cpr_vreg->pvs_corner_v[i][CPR_CORNER_NORMAL],
- cpr_vreg->pvs_corner_v[i][CPR_CORNER_TURBO]);
+ cpr_vreg->pvs_corner_v[i][CPR_FUSE_CORNER_SVS],
+ cpr_vreg->pvs_corner_v[i][CPR_FUSE_CORNER_NORMAL],
+ cpr_vreg->pvs_corner_v[i][CPR_FUSE_CORNER_TURBO]);
}
return 0;
diff --git a/arch/arm/mach-msm/cpufreq.c b/arch/arm/mach-msm/cpufreq.c
index a6c86af..0978a2d 100644
--- a/arch/arm/mach-msm/cpufreq.c
+++ b/arch/arm/mach-msm/cpufreq.c
@@ -27,17 +27,39 @@
#include <linux/cpumask.h>
#include <linux/sched.h>
#include <linux/suspend.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
#include <trace/events/power.h>
#include <mach/socinfo.h>
#include <mach/cpufreq.h>
#include "acpuclock.h"
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <asm/div64.h>
+#endif
+
+static DEFINE_MUTEX(l2bw_lock);
+
+static struct clk *cpu_clk[NR_CPUS];
+static struct clk *l2_clk;
+static unsigned int freq_index[NR_CPUS];
+static unsigned int max_freq_index;
+static struct cpufreq_frequency_table *freq_table;
+static unsigned int *l2_khz;
+static bool is_clk;
+static bool is_sync;
+static unsigned long *mem_bw;
+
struct cpufreq_work_struct {
struct work_struct work;
struct cpufreq_policy *policy;
struct completion complete;
int frequency;
+ unsigned int index;
int status;
};
@@ -51,37 +73,50 @@
static DEFINE_PER_CPU(struct cpufreq_suspend_t, cpufreq_suspend);
-struct cpu_freq {
- uint32_t max;
- uint32_t min;
- uint32_t allowed_max;
- uint32_t allowed_min;
- uint32_t limits_init;
-};
+unsigned long msm_cpufreq_get_bw(void)
+{
+ return mem_bw[max_freq_index];
+}
-static DEFINE_PER_CPU(struct cpu_freq, cpu_freq_info);
+static void update_l2_bw(int *also_cpu)
+{
+ int rc = 0, cpu;
+ unsigned int index = 0;
-static int set_cpu_freq(struct cpufreq_policy *policy, unsigned int new_freq)
+ mutex_lock(&l2bw_lock);
+
+ if (also_cpu)
+ index = freq_index[*also_cpu];
+
+ for_each_online_cpu(cpu) {
+ index = max(index, freq_index[cpu]);
+ }
+
+ if (l2_clk)
+ rc = clk_set_rate(l2_clk, l2_khz[index] * 1000);
+ if (rc) {
+ pr_err("Error setting L2 clock rate!\n");
+ goto out;
+ }
+
+ max_freq_index = index;
+ rc = devfreq_msm_cpufreq_update_bw();
+ if (rc)
+ pr_err("Unable to update BW (%d)\n", rc);
+
+out:
+ mutex_unlock(&l2bw_lock);
+}
+
+static int set_cpu_freq(struct cpufreq_policy *policy, unsigned int new_freq,
+ unsigned int index)
{
int ret = 0;
int saved_sched_policy = -EINVAL;
int saved_sched_rt_prio = -EINVAL;
struct cpufreq_freqs freqs;
- struct cpu_freq *limit = &per_cpu(cpu_freq_info, policy->cpu);
struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
- if (limit->limits_init) {
- if (new_freq > limit->allowed_max) {
- new_freq = limit->allowed_max;
- pr_debug("max: limiting freq to %d\n", new_freq);
- }
-
- if (new_freq < limit->allowed_min) {
- new_freq = limit->allowed_min;
- pr_debug("min: limiting freq to %d\n", new_freq);
- }
- }
-
freqs.old = policy->cur;
freqs.new = new_freq;
freqs.cpu = policy->cpu;
@@ -100,7 +135,18 @@
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
trace_cpu_frequency_switch_start(freqs.old, freqs.new, policy->cpu);
- ret = acpuclk_set_rate(policy->cpu, new_freq, SETRATE_CPUFREQ);
+ if (is_clk) {
+ unsigned long rate = new_freq * 1000;
+ rate = clk_round_rate(cpu_clk[policy->cpu], rate);
+ ret = clk_set_rate(cpu_clk[policy->cpu], rate);
+ if (!ret) {
+ freq_index[policy->cpu] = index;
+ update_l2_bw(NULL);
+ }
+ } else {
+ ret = acpuclk_set_rate(policy->cpu, new_freq, SETRATE_CPUFREQ);
+ }
+
if (!ret) {
trace_cpu_frequency_switch_end(policy->cpu);
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
@@ -119,7 +165,8 @@
struct cpufreq_work_struct *cpu_work =
container_of(work, struct cpufreq_work_struct, work);
- cpu_work->status = set_cpu_freq(cpu_work->policy, cpu_work->frequency);
+ cpu_work->status = set_cpu_freq(cpu_work->policy, cpu_work->frequency,
+ cpu_work->index);
complete(&cpu_work->complete);
}
@@ -157,6 +204,7 @@
cpu_work = &per_cpu(cpufreq_work, policy->cpu);
cpu_work->policy = policy;
cpu_work->frequency = table[index].frequency;
+ cpu_work->index = table[index].index;
cpu_work->status = -ENODEV;
cancel_work_sync(&cpu_work->work);
@@ -180,70 +228,12 @@
static unsigned int msm_cpufreq_get_freq(unsigned int cpu)
{
+ if (is_clk)
+ return clk_get_rate(cpu_clk[cpu]) / 1000;
+
return acpuclk_get_rate(cpu);
}
-static inline int msm_cpufreq_limits_init(void)
-{
- int cpu = 0;
- int i = 0;
- struct cpufreq_frequency_table *table = NULL;
- uint32_t min = (uint32_t) -1;
- uint32_t max = 0;
- struct cpu_freq *limit = NULL;
-
- for_each_possible_cpu(cpu) {
- limit = &per_cpu(cpu_freq_info, cpu);
- table = cpufreq_frequency_get_table(cpu);
- if (table == NULL) {
- pr_err("%s: error reading cpufreq table for cpu %d\n",
- __func__, cpu);
- continue;
- }
- for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
- if (table[i].frequency > max)
- max = table[i].frequency;
- if (table[i].frequency < min)
- min = table[i].frequency;
- }
- limit->allowed_min = min;
- limit->allowed_max = max;
- limit->min = min;
- limit->max = max;
- limit->limits_init = 1;
- }
-
- return 0;
-}
-
-int msm_cpufreq_set_freq_limits(uint32_t cpu, uint32_t min, uint32_t max)
-{
- struct cpu_freq *limit = &per_cpu(cpu_freq_info, cpu);
-
- if (!limit->limits_init)
- msm_cpufreq_limits_init();
-
- if ((min != MSM_CPUFREQ_NO_LIMIT) &&
- min >= limit->min && min <= limit->max)
- limit->allowed_min = min;
- else
- limit->allowed_min = limit->min;
-
-
- if ((max != MSM_CPUFREQ_NO_LIMIT) &&
- max <= limit->max && max >= limit->min)
- limit->allowed_max = max;
- else
- limit->allowed_max = limit->max;
-
- pr_debug("%s: Limiting cpu %d min = %d, max = %d\n",
- __func__, cpu,
- limit->allowed_min, limit->allowed_max);
-
- return 0;
-}
-EXPORT_SYMBOL(msm_cpufreq_set_freq_limits);
-
static int __cpuinit msm_cpufreq_init(struct cpufreq_policy *policy)
{
int cur_freq;
@@ -261,7 +251,7 @@
* same frequency. Hence set the cpumask to all cpu.
*/
if (cpu_is_msm8625() || cpu_is_msm8625q() || cpu_is_msm8226()
- || cpu_is_msm8610())
+ || cpu_is_msm8610() || (is_clk && is_sync))
cpumask_setall(policy->cpus);
if (cpufreq_frequency_table_cpuinfo(policy, table)) {
@@ -275,7 +265,11 @@
policy->max = CONFIG_MSM_CPU_FREQ_MAX;
#endif
- cur_freq = acpuclk_get_rate(policy->cpu);
+ if (is_clk)
+ cur_freq = clk_get_rate(cpu_clk[policy->cpu])/1000;
+ else
+ cur_freq = acpuclk_get_rate(policy->cpu);
+
if (cpufreq_frequency_table_target(policy, table, cur_freq,
CPUFREQ_RELATION_H, &index) &&
cpufreq_frequency_table_target(policy, table, cur_freq,
@@ -288,7 +282,7 @@
* Call set_cpu_freq unconditionally so that when cpu is set to
* online, frequency limit will always be updated.
*/
- ret = set_cpu_freq(policy, table[index].frequency);
+ ret = set_cpu_freq(policy, table[index].frequency, table[index].index);
if (ret)
return ret;
pr_debug("cpufreq: cpu%d init at %d switching to %d\n",
@@ -309,22 +303,45 @@
unsigned long action, void *hcpu)
{
unsigned int cpu = (unsigned long)hcpu;
+ int rc;
- switch (action) {
+ switch (action & ~CPU_TASKS_FROZEN) {
case CPU_ONLINE:
- case CPU_ONLINE_FROZEN:
per_cpu(cpufreq_suspend, cpu).device_suspended = 0;
break;
case CPU_DOWN_PREPARE:
- case CPU_DOWN_PREPARE_FROZEN:
mutex_lock(&per_cpu(cpufreq_suspend, cpu).suspend_mutex);
per_cpu(cpufreq_suspend, cpu).device_suspended = 1;
mutex_unlock(&per_cpu(cpufreq_suspend, cpu).suspend_mutex);
break;
case CPU_DOWN_FAILED:
- case CPU_DOWN_FAILED_FROZEN:
per_cpu(cpufreq_suspend, cpu).device_suspended = 0;
break;
+ /*
+ * Scale down clock/power of CPU that is dead and scale it back up
+ * before the CPU is brought up.
+ */
+ case CPU_DEAD:
+ case CPU_UP_CANCELED:
+ if (is_clk) {
+ clk_disable_unprepare(cpu_clk[cpu]);
+ clk_disable_unprepare(l2_clk);
+ update_l2_bw(NULL);
+ }
+ break;
+ case CPU_UP_PREPARE:
+ if (is_clk) {
+ rc = clk_prepare_enable(l2_clk);
+ if (rc < 0)
+ return NOTIFY_BAD;
+ rc = clk_prepare_enable(cpu_clk[cpu]);
+ if (rc < 0)
+ return NOTIFY_BAD;
+ update_l2_bw(&cpu);
+ }
+ break;
+ default:
+ break;
}
return NOTIFY_OK;
@@ -380,6 +397,196 @@
.attr = msm_freq_attr,
};
+#define PROP_TBL "qcom,cpufreq-table"
+static int cpufreq_parse_dt(struct device *dev)
+{
+ int ret, len, nf, num_cols = 2, i, j;
+ u32 *data;
+
+ if (l2_clk)
+ num_cols++;
+
+ /* Parse CPU freq -> L2/Mem BW map table. */
+ if (!of_find_property(dev->of_node, PROP_TBL, &len))
+ return -EINVAL;
+ len /= sizeof(*data);
+
+ if (len % num_cols || len == 0)
+ return -EINVAL;
+ nf = len / num_cols;
+
+ data = devm_kzalloc(dev, len * sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ ret = of_property_read_u32_array(dev->of_node, PROP_TBL, data, len);
+ if (ret)
+ return ret;
+
+ /* Allocate all data structures. */
+ freq_table = devm_kzalloc(dev, (nf + 1) * sizeof(*freq_table),
+ GFP_KERNEL);
+ mem_bw = devm_kzalloc(dev, nf * sizeof(*mem_bw), GFP_KERNEL);
+
+ if (!freq_table || !mem_bw)
+ return -ENOMEM;
+
+ if (l2_clk) {
+ l2_khz = devm_kzalloc(dev, nf * sizeof(*l2_khz), GFP_KERNEL);
+ if (!l2_khz)
+ return -ENOMEM;
+ }
+
+ j = 0;
+ for (i = 0; i < nf; i++) {
+ unsigned long f;
+
+ f = clk_round_rate(cpu_clk[0], data[j++] * 1000);
+ if (IS_ERR_VALUE(f))
+ break;
+ f /= 1000;
+
+ /*
+ * Check if this is the last feasible frequency in the table.
+ *
+ * The table listing frequencies higher than what the HW can
+ * support is not an error since the table might be shared
+ * across CPUs in different speed bins. It's also not
+ * sufficient to check if the rounded rate is lower than the
+ * requested rate as it doesn't cover the following example:
+ *
+ * Table lists: 2.2 GHz and 2.5 GHz.
+ * Rounded rate returns: 2.2 GHz and 2.3 GHz.
+ *
+ * In this case, we can CPUfreq to use 2.2 GHz and 2.3 GHz
+ * instead of rejecting the 2.5 GHz table entry.
+ */
+ if (i > 0 && f <= freq_table[i-1].frequency)
+ break;
+
+ freq_table[i].index = i;
+ freq_table[i].frequency = f;
+
+ if (l2_clk) {
+ f = clk_round_rate(l2_clk, data[j++] * 1000);
+ if (IS_ERR_VALUE(f)) {
+ pr_err("Error finding L2 rate for CPU %d KHz\n",
+ freq_table[i].frequency);
+ freq_table[i].frequency = CPUFREQ_ENTRY_INVALID;
+ } else {
+ f /= 1000;
+ l2_khz[i] = f;
+ }
+ }
+
+ mem_bw[i] = data[j++];
+ }
+
+ freq_table[i].index = i;
+ freq_table[i].frequency = CPUFREQ_TABLE_END;
+
+ devm_kfree(dev, data);
+
+ return 0;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static int msm_cpufreq_show(struct seq_file *m, void *unused)
+{
+ unsigned int i, cpu_freq;
+
+ if (!freq_table)
+ return 0;
+
+ seq_printf(m, "%10s%10s", "CPU (KHz)", "L2 (KHz)");
+ seq_printf(m, "%12s\n", "Mem (MBps)");
+
+ for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
+ cpu_freq = freq_table[i].frequency;
+ if (cpu_freq == CPUFREQ_ENTRY_INVALID)
+ continue;
+ seq_printf(m, "%10d", cpu_freq);
+ seq_printf(m, "%10d", l2_khz ? l2_khz[i] : cpu_freq);
+ seq_printf(m, "%12lu", mem_bw[i]);
+ seq_printf(m, "\n");
+ }
+ return 0;
+}
+
+static int msm_cpufreq_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, msm_cpufreq_show, inode->i_private);
+}
+
+const struct file_operations msm_cpufreq_fops = {
+ .open = msm_cpufreq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+#endif
+
+static int __init msm_cpufreq_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ char clk_name[] = "cpu??_clk";
+ struct clk *c;
+ int cpu, ret;
+
+ l2_clk = devm_clk_get(dev, "l2_clk");
+ if (IS_ERR(l2_clk))
+ l2_clk = NULL;
+
+ for_each_possible_cpu(cpu) {
+ snprintf(clk_name, sizeof(clk_name), "cpu%d_clk", cpu);
+ c = devm_clk_get(dev, clk_name);
+ if (!IS_ERR(c))
+ cpu_clk[cpu] = c;
+ else
+ is_sync = true;
+ }
+
+ if (!cpu_clk[0])
+ return -ENODEV;
+
+ ret = cpufreq_parse_dt(dev);
+ if (ret)
+ return ret;
+
+ for_each_possible_cpu(cpu) {
+ cpufreq_frequency_table_get_attr(freq_table, cpu);
+ }
+
+ ret = register_devfreq_msm_cpufreq();
+ if (ret) {
+ pr_err("devfreq governor registration failed\n");
+ return ret;
+ }
+
+ is_clk = true;
+
+#ifdef CONFIG_DEBUG_FS
+ if (!debugfs_create_file("msm_cpufreq", S_IRUGO, NULL, NULL,
+ &msm_cpufreq_fops))
+ return -ENOMEM;
+#endif
+
+ return 0;
+}
+
+static struct of_device_id match_table[] = {
+ { .compatible = "qcom,msm-cpufreq" },
+ {}
+};
+
+static struct platform_driver msm_cpufreq_plat_driver = {
+ .driver = {
+ .name = "msm-cpufreq",
+ .of_match_table = match_table,
+ .owner = THIS_MODULE,
+ },
+};
+
static int __init msm_cpufreq_register(void)
{
int cpu;
@@ -389,9 +596,9 @@
per_cpu(cpufreq_suspend, cpu).device_suspended = 0;
}
+ platform_driver_probe(&msm_cpufreq_plat_driver, msm_cpufreq_probe);
msm_cpufreq_wq = alloc_workqueue("msm-cpufreq", WQ_HIGHPRI, 0);
register_hotcpu_notifier(&msm_cpufreq_cpu_notifier);
-
return cpufreq_register_driver(&msm_cpufreq_driver);
}
diff --git a/arch/arm/mach-msm/cpuidle.c b/arch/arm/mach-msm/cpuidle.c
index 7c06268..c480e56 100644
--- a/arch/arm/mach-msm/cpuidle.c
+++ b/arch/arm/mach-msm/cpuidle.c
@@ -112,8 +112,8 @@
continue;
state = &msm_cpuidle_driver.states[state_count];
- snprintf(state->name, CPUIDLE_NAME_LEN, cstate->name);
- snprintf(state->desc, CPUIDLE_DESC_LEN, cstate->desc);
+ snprintf(state->name, CPUIDLE_NAME_LEN, "%s", cstate->name);
+ snprintf(state->desc, CPUIDLE_DESC_LEN, "%s", cstate->desc);
state->flags = 0;
state->exit_latency = 0;
state->power_usage = 0;
diff --git a/arch/arm/mach-msm/devfreq_cpubw.c b/arch/arm/mach-msm/devfreq_cpubw.c
new file mode 100644
index 0000000..20cabc2
--- /dev/null
+++ b/arch/arm/mach-msm/devfreq_cpubw.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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) "cpubw: " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/ktime.h>
+#include <linux/time.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <linux/devfreq.h>
+#include <linux/of.h>
+#include <trace/events/power.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+
+/* Has to be ULL to prevent overflow where this macro is used. */
+#define MBYTE (1ULL << 20)
+#define MAX_PATHS 2
+
+static struct msm_bus_vectors vectors[MAX_PATHS * 2];
+static struct msm_bus_paths bw_levels[] = {
+ { .vectors = &vectors[0] },
+ { .vectors = &vectors[MAX_PATHS] },
+};
+static struct msm_bus_scale_pdata bw_data = {
+ .usecase = bw_levels,
+ .num_usecases = ARRAY_SIZE(bw_levels),
+ .name = "devfreq_cpubw",
+ .active_only = 1,
+};
+static int num_paths;
+static u32 bus_client;
+
+static int set_bw(int new_ib, int new_ab)
+{
+ static int cur_idx, cur_ab, cur_ib;
+ int i, ret;
+
+ if (cur_ib == new_ib && cur_ab == new_ab)
+ return 0;
+
+ i = (cur_idx + 1) % ARRAY_SIZE(bw_levels);
+
+ bw_levels[i].vectors[0].ib = new_ib * MBYTE;
+ bw_levels[i].vectors[0].ab = new_ab / num_paths * MBYTE;
+ bw_levels[i].vectors[1].ib = new_ib * MBYTE;
+ bw_levels[i].vectors[1].ab = new_ab / num_paths * MBYTE;
+
+ pr_debug("BW MBps: AB: %d IB: %d\n", new_ab, new_ib);
+
+ ret = msm_bus_scale_client_update_request(bus_client, i);
+ if (ret) {
+ pr_err("bandwidth request failed (%d)\n", ret);
+ } else {
+ cur_idx = i;
+ cur_ib = new_ib;
+ cur_ab = new_ab;
+ }
+
+ return ret;
+}
+
+static void find_freq(struct devfreq_dev_profile *p, unsigned long *freq,
+ u32 flags)
+{
+ int i;
+ unsigned long atmost, atleast, f;
+
+ atmost = p->freq_table[0];
+ atleast = p->freq_table[p->max_state-1];
+ for (i = 0; i < p->max_state; i++) {
+ f = p->freq_table[i];
+ if (f <= *freq)
+ atmost = max(f, atmost);
+ if (f >= *freq)
+ atleast = min(f, atleast);
+ }
+
+ if (flags & DEVFREQ_FLAG_LEAST_UPPER_BOUND)
+ *freq = atmost;
+ else
+ *freq = atleast;
+}
+
+struct devfreq_dev_profile cpubw_profile;
+static long gov_ab;
+
+int cpubw_target(struct device *dev, unsigned long *freq, u32 flags)
+{
+ find_freq(&cpubw_profile, freq, flags);
+ return set_bw(*freq, gov_ab);
+}
+
+static struct devfreq_governor_data gov_data[] = {
+ { .name = "performance" },
+ { .name = "powersave" },
+ { .name = "userspace" },
+ { .name = "msm_cpufreq" },
+ { .name = "cpubw_hwmon", .data = &gov_ab },
+};
+
+struct devfreq_dev_profile cpubw_profile = {
+ .polling_ms = 50,
+ .target = cpubw_target,
+ .governor_data = gov_data,
+ .num_governor_data = ARRAY_SIZE(gov_data),
+};
+
+#define PROP_PORTS "qcom,cpu-mem-ports"
+#define PROP_TBL "qcom,bw-tbl"
+
+static int __init cpubw_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct devfreq_dev_profile *p = &cpubw_profile;
+ struct devfreq *df;
+ u32 *data, ports[MAX_PATHS * 2];
+ int ret, len, i;
+
+ if (of_find_property(dev->of_node, PROP_PORTS, &len)) {
+ len /= sizeof(ports[0]);
+ if (len % 2 || len > ARRAY_SIZE(ports)) {
+ dev_err(dev, "Unexpected number of ports\n");
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32_array(dev->of_node, PROP_PORTS,
+ ports, len);
+ if (ret)
+ return ret;
+
+ num_paths = len / 2;
+ } else {
+ return -EINVAL;
+ }
+
+ for (i = 0; i < num_paths; i++) {
+ bw_levels[0].vectors[i].src = ports[2 * i];
+ bw_levels[0].vectors[i].dst = ports[2 * i + 1];
+ bw_levels[1].vectors[i].src = ports[2 * i];
+ bw_levels[1].vectors[i].dst = ports[2 * i + 1];
+ }
+ bw_levels[0].num_paths = num_paths;
+ bw_levels[1].num_paths = num_paths;
+
+ if (of_find_property(dev->of_node, PROP_TBL, &len)) {
+ len /= sizeof(*data);
+ data = devm_kzalloc(dev, len * sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ p->freq_table = devm_kzalloc(dev,
+ len * sizeof(*p->freq_table),
+ GFP_KERNEL);
+ if (!p->freq_table)
+ return -ENOMEM;
+
+ ret = of_property_read_u32_array(dev->of_node, PROP_TBL,
+ data, len);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < len; i++)
+ p->freq_table[i] = data[i];
+ p->max_state = len;
+ }
+
+ bus_client = msm_bus_scale_register_client(&bw_data);
+ if (!bus_client) {
+ dev_err(dev, "Unable to register bus client\n");
+ return -ENODEV;
+ }
+
+ df = devfreq_add_device(dev, &cpubw_profile, "msm_cpufreq", NULL);
+ if (IS_ERR(df)) {
+ msm_bus_scale_unregister_client(bus_client);
+ return PTR_ERR(df);
+ }
+
+ return 0;
+}
+
+static struct of_device_id match_table[] = {
+ { .compatible = "qcom,cpubw" },
+ {}
+};
+
+static struct platform_driver cpubw_driver = {
+ .driver = {
+ .name = "cpubw",
+ .of_match_table = match_table,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init cpubw_init(void)
+{
+ platform_driver_probe(&cpubw_driver, cpubw_probe);
+ return 0;
+}
+device_initcall(cpubw_init);
+
+MODULE_DESCRIPTION("CPU DDR bandwidth voting driver MSM CPUs");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index c4fe0df..94040b6 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -31,7 +31,6 @@
#include "rpm_stats.h"
#include "rpm_rbcpr_stats.h"
#include "footswitch.h"
-#include "acpuclock-krait.h"
#include "pm.h"
#ifdef CONFIG_MSM_MPM
@@ -675,16 +674,9 @@
.id = -1,
};
-static struct acpuclk_platform_data acpuclk_8930_pdata = {
- .uses_pm8917 = false,
-};
-
struct platform_device msm8930_device_acpuclk = {
.name = "acpuclk-8930",
.id = -1,
- .dev = {
- .platform_data = &acpuclk_8930_pdata,
- },
};
struct platform_device msm8930aa_device_acpuclk = {
@@ -692,16 +684,9 @@
.id = -1,
};
-static struct acpuclk_platform_data acpuclk_8930ab_pdata = {
- .uses_pm8917 = false,
-};
-
struct platform_device msm8930ab_device_acpuclk = {
.name = "acpuclk-8930ab",
.id = -1,
- .dev = {
- .platform_data = &acpuclk_8930ab_pdata,
- },
};
static struct fs_driver_data gfx3d_fs_data = {
diff --git a/arch/arm/mach-msm/hotplug.c b/arch/arm/mach-msm/hotplug.c
index 20e3c3b..174a50a 100644
--- a/arch/arm/mach-msm/hotplug.c
+++ b/arch/arm/mach-msm/hotplug.c
@@ -11,6 +11,7 @@
#include <linux/errno.h>
#include <linux/smp.h>
#include <linux/cpu.h>
+#include <linux/ratelimit.h>
#include <asm/cacheflush.h>
#include <asm/smp_plat.h>
@@ -150,6 +151,29 @@
.notifier_call = hotplug_rtb_callback,
};
+static int hotplug_cpu_check_callback(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ int cpu = (int)hcpu;
+
+ switch (action & (~CPU_TASKS_FROZEN)) {
+ case CPU_DOWN_PREPARE:
+ if (cpu == 0) {
+ pr_err_ratelimited("CPU0 hotplug is not supported\n");
+ return NOTIFY_BAD;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+static struct notifier_block hotplug_cpu_check_notifier = {
+ .notifier_call = hotplug_cpu_check_callback,
+ .priority = INT_MAX,
+};
+
int msm_platform_secondary_init(unsigned int cpu)
{
int ret;
@@ -170,6 +194,12 @@
static int __init init_hotplug(void)
{
- return register_hotcpu_notifier(&hotplug_rtb_notifier);
+ int rc;
+
+ rc = register_hotcpu_notifier(&hotplug_rtb_notifier);
+ if (rc)
+ return rc;
+
+ return register_hotcpu_notifier(&hotplug_cpu_check_notifier);
}
early_initcall(init_hotplug);
diff --git a/arch/arm/mach-msm/hsic_sysmon_test.c b/arch/arm/mach-msm/hsic_sysmon_test.c
index fac6575..a910cd26 100644
--- a/arch/arm/mach-msm/hsic_sysmon_test.c
+++ b/arch/arm/mach-msm/hsic_sysmon_test.c
@@ -63,9 +63,13 @@
if (!dev)
return -ENODEV;
+ /* Add check for user buf count greater than RD_BUF_SIZE */
+ if (count > RD_BUF_SIZE)
+ count = RD_BUF_SIZE;
+
if (copy_from_user(dev->buf, ubuf, count)) {
pr_err("error copying for writing");
- return 0;
+ return -EFAULT;
}
ret = hsic_sysmon_write(id, dev->buf, count, 1000);
diff --git a/arch/arm/mach-msm/idle-macros.S b/arch/arm/mach-msm/idle-macros.S
deleted file mode 100644
index 3d0c937..0000000
--- a/arch/arm/mach-msm/idle-macros.S
+++ /dev/null
@@ -1,153 +0,0 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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 <asm/hardware/cache-l2x0.h>
-
-/* Add 300 NOPs after 'wfi' for 8x25 target */
-.macro DELAY_8x25, rept
-#ifdef CONFIG_ARCH_MSM8625
- .rept \rept
- nop
- .endr
-#endif
-.endm
-
-/* Switch between smp_to_amp/amp_to_smp configuration */
-.macro SET_SMP_COHERENCY, on = 0
- ldr r0, =target_type
- ldr r0, [r0]
- mov r1, #TARGET_IS_8625
- cmp r0, r1
- bne skip\@
- mrc p15, 0, r0, c1, c0, 1 /* read ACTLR register */
- .if \on
- orr r0, r0, #(1 << 6) /* Set the SMP bit in ACTLR */
- .else
- bic r0, r0, #(1 << 6) /* Clear the SMP bit */
- .endif
- mcr p15, 0, r0, c1, c0, 1 /* write ACTLR register */
- isb
-skip\@:
-.endm
-
-/*
- * Enable the "L2" cache, not require to restore the controller registers
- */
-.macro ENABLE_8x25_L2
- ldr r0, =target_type
- ldr r0, [r0]
- mov r1, #TARGET_IS_8625
- cmp r0, r1
- bne skip_enable\@
- ldr r0, =apps_power_collapse
- ldr r0, [r0]
- cmp r0, #POWER_COLLAPSED
- bne skip_enable\@
- ldr r0, =l2x0_base_addr
- ldr r0, [r0]
- mov r1, #0x1
- str r1, [r0, #L2X0_CTRL]
- dmb
-skip_enable\@:
-.endm
-
-/*
- * Perform the required operation
- * operation: type of operation on l2 cache (e.g: clean&inv or inv)
- * l2_enable: enable or disable
- */
-.macro DO_CACHE_OPERATION, operation, l2_enable
- ldr r2, =l2x0_base_addr
- ldr r2, [r2]
- ldr r0, =0xffff
- str r0, [r2, #\operation]
-wait\@:
- ldr r0, [r2, #\operation]
- ldr r1, =0xffff
- ands r0, r0, r1
- bne wait\@
-l2x_sync\@:
- mov r0, #0x0
- str r0, [r2, #L2X0_CACHE_SYNC]
-sync\@:
- ldr r0, [r2, #L2X0_CACHE_SYNC]
- ands r0, r0, #0x1
- bne sync\@
- mov r1, #\l2_enable
- str r1, [r2, #L2X0_CTRL]
-.endm
-
-/*
- * Clean and invalidate the L2 cache.
- * 1. Check the target type
- * 2. Check whether we are coming from PC are not
- * 3. Save 'aux', 'data latency', & 'prefetch ctlr' registers
- * 4. Start L2 clean & invalidation operation
- * 5. Disable the L2 cache
- */
-.macro SUSPEND_8x25_L2
- ldr r0, =target_type
- ldr r0, [r0]
- mov r1, #TARGET_IS_8625
- cmp r0, r1
- bne skip_suspend\@
- ldr r0, =apps_power_collapse
- ldr r0, [r0]
- cmp r0, #POWER_COLLAPSED
- bne skip_suspend\@
- ldr r0, =l2x0_saved_ctrl_reg_val
- ldr r1, =l2x0_base_addr
- ldr r1, [r1]
- ldr r2, [r1, #L2X0_AUX_CTRL]
- str r2, [r0, #0x0] /* store aux_ctlr reg value */
- ldr r2, [r1, #L2X0_DATA_LATENCY_CTRL]
- str r2, [r0, #0x4] /* store data latency reg value */
- ldr r2, [r1, #L2X0_PREFETCH_CTRL]
- str r2, [r0, #0x8] /* store prefetch_ctlr reg value */
- DO_CACHE_OPERATION L2X0_CLEAN_INV_WAY OFF
- dmb
-skip_suspend\@:
-.endm
-
-/*
- * Coming back from a successful PC
- * 1. Check the target type
- * 2. Check whether we are going to PC are not
- * 3. Disable the L2 cache
- * 4. Restore 'aux', 'data latency', & 'prefetch ctlr' reg
- * 5. Invalidate the cache
- * 6. Enable the L2 cache
- */
-.macro RESUME_8x25_L2
- ldr r0, =target_type
- ldr r0, [r0]
- mov r1, #TARGET_IS_8625
- cmp r0, r1
- bne skip_resume\@
- ldr r0, =apps_power_collapse
- ldr r0, [r0]
- cmp r0, #POWER_COLLAPSED
- bne skip_resume\@
- ldr r1, =l2x0_base_addr
- ldr r1, [r1]
- mov r0, #0x0
- str r0, [r1, #L2X0_CTRL]
- ldr r0, =l2x0_saved_ctrl_reg_val
- ldr r2, [r0, #0x0]
- str r2, [r1, #L2X0_AUX_CTRL] /* restore aux_ctlr reg value */
- ldr r2, [r0, #0x4]
- str r2, [r1, #L2X0_DATA_LATENCY_CTRL]
- ldr r2, [r0, #0x8]
- str r2, [r1, #L2X0_PREFETCH_CTRL]
- DO_CACHE_OPERATION L2X0_INV_WAY ON
-skip_resume\@:
-.endm
diff --git a/arch/arm/mach-msm/idle-v7.S b/arch/arm/mach-msm/idle-v7.S
index f8a32b4..a133470 100644
--- a/arch/arm/mach-msm/idle-v7.S
+++ b/arch/arm/mach-msm/idle-v7.S
@@ -19,356 +19,7 @@
#include <linux/threads.h>
#include <asm/assembler.h>
-#include "idle.h"
-#include "idle-macros.S"
-
-#ifdef CONFIG_MSM_SCM
-#define SCM_SVC_BOOT 0x1
-#define SCM_CMD_TERMINATE_PC 0x2
-#define SCM_CMD_CORE_HOTPLUGGED 0x10
-#endif
-
-ENTRY(msm_arch_idle)
-#ifdef CONFIG_ARCH_MSM_KRAIT
- mrc p15, 0, r0, c0, c0, 0
- bic r1, r0, #0xff
- movw r2, #0x0400
- movt r2, #0x511F
- movw r3, #0x0600
- movt r3, #0x510F
- cmp r2, r1
- cmpne r3, r1
- bne go_wfi
-
- mrs r0, cpsr
- cpsid if
-
- mrc p15, 7, r1, c15, c0, 5
- bic r2, r1, #0x20000
- mcr p15, 7, r2, c15, c0, 5
- isb
-
-go_wfi:
- wfi
- bne wfi_done
- mcr p15, 7, r1, c15, c0, 5
- isb
- msr cpsr_c, r0
-
-wfi_done:
- bx lr
-#else
- wfi
-#ifdef CONFIG_ARCH_MSM8X60
- mrc p14, 1, r1, c1, c5, 4 /* read ETM PDSR to clear sticky bit */
- mrc p14, 0, r1, c1, c5, 4 /* read DBG PRSR to clear sticky bit */
- isb
-#endif
- bx lr
-#endif
-ENTRY(msm_pm_pc_hotplug)
- stmfd sp!, {lr}
-#if defined(CONFIG_MSM_FIQ_SUPPORT)
- cpsid f
-#endif
-
-#if defined(CONFIG_MSM_JTAG) || defined(CONFIG_MSM_JTAG_MM)
- bl msm_jtag_save_state
-#endif
- mov r1, #0
- mcr p15, 2, r1, c0, c0, 0 /*CCSELR*/
- isb
- mrc p15, 1, r1, c0, c0, 0 /*CCSIDR*/
- mov r2, #1
- and r1, r2, r1, ASR #30 /* Check if the cache is write back */
- cmp r1, #1
- bleq v7_flush_kern_cache_all
-
- mrc p15, 0, r0, c0, c0, 5 /* MPIDR */
- and r0, r0, #15 /* what CPU am I */
-
- ldr r1, =msm_pc_debug_counters /*load the IMEM debug location */
- ldr r1, [r1]
- cmp r1, #0
- beq skip_hp_debug1
- add r1, r1, r0, LSL #4 /* debug location for this CPU */
- ldr r2, [r1]
- add r2, #1
- str r2, [r1]
-skip_hp_debug1:
-
-#ifdef CONFIG_MSM_SCM
- ldr r0, =SCM_SVC_BOOT
- ldr r1, =SCM_CMD_TERMINATE_PC
- ldr r2, =SCM_CMD_CORE_HOTPLUGGED
- bl scm_call_atomic1
-#else
- mrc p15, 0, r3, c1, c0, 0 /* read current CR */
- bic r0, r3, #(1 << 2) /* clear dcache bit */
- bic r0, r0, #(1 << 12) /* clear icache bit */
- mcr p15, 0, r0, c1, c0, 0 /* disable d/i cache */
- isb
- wfi
- mcr p15, 0, r3, c1, c0, 0 /* restore d/i cache */
- isb
-#endif
-
-#if defined(CONFIG_MSM_FIQ_SUPPORT)
- cpsie f
-#endif
- mrc p15, 0, r0, c0, c0, 5 /* MPIDR */
- and r0, r0, #15 /* what CPU am I */
-
- ldr r1, =msm_pc_debug_counters /*load the IMEM debug location */
- ldr r1, [r1]
- cmp r1, #0
- beq skip_hp_debug2
- add r1, r1, r0, LSL #4 /* debug location for this CPU */
- add r1, #8
- ldr r2, [r1]
- add r2, #1
- str r2, [r1]
-skip_hp_debug2:
-#if defined(CONFIG_MSM_JTAG) || defined(CONFIG_MSM_JTAG_MM)
- bl msm_jtag_restore_state
-#endif
- mov r0, #0 /* return power collapse failed */
- ldmfd sp!, {lr}
- bx lr
-
-ENTRY(msm_pm_collapse)
-#if defined(CONFIG_MSM_FIQ_SUPPORT)
- cpsid f
-#endif
-
- ldr r0, =msm_saved_state /* address of msm_saved_state ptr */
- ldr r0, [r0] /* load ptr */
-#if (NR_CPUS >= 2)
- mrc p15, 0, r1, c0, c0, 5 /* MPIDR */
- ands r1, r1, #15 /* What CPU am I */
- mov r2, #CPU_SAVED_STATE_SIZE
- mul r1, r1, r2
- add r0, r0, r1
-#endif
-
- stmia r0!, {r4-r14}
- mrc p15, 0, r1, c1, c0, 0 /* MMU control */
- mrc p15, 0, r2, c2, c0, 0 /* TTBR0 */
- mrc p15, 0, r3, c3, c0, 0 /* dacr */
-#ifdef CONFIG_ARCH_MSM_SCORPION
- /* This instruction is not valid for non scorpion processors */
- mrc p15, 3, r4, c15, c0, 3 /* L2CR1 is the L2 cache control reg 1 */
-#endif
- mrc p15, 0, r5, c10, c2, 0 /* PRRR */
- mrc p15, 0, r6, c10, c2, 1 /* NMRR */
- mrc p15, 0, r7, c1, c0, 1 /* ACTLR */
- mrc p15, 0, r8, c2, c0, 1 /* TTBR1 */
- mrc p15, 0, r9, c13, c0, 3 /* TPIDRURO */
- mrc p15, 0, ip, c13, c0, 1 /* context ID */
- stmia r0!, {r1-r9, ip}
-
-#if defined(CONFIG_MSM_JTAG) || defined(CONFIG_MSM_JTAG_MM)
- bl msm_jtag_save_state
-#endif
-
- ldr r0, =msm_pm_flush_l2_flag
- ldr r0, [r0]
- mov r1, #0
- mcr p15, 2, r1, c0, c0, 0 /*CCSELR*/
- isb
- mrc p15, 1, r1, c0, c0, 0 /*CCSIDR*/
- mov r2, #1
- and r1, r2, r1, ASR #30 /* Check if the cache is write back */
- orr r1, r0, r1
- cmp r1, #1
- bne skip
- bl v7_flush_dcache_all
- ldr r1, =msm_pm_flush_l2_fn
- ldr r1, [r1]
- cmp r1, #0
- blxne r1
-
-skip:
- ldr r1, =msm_pm_disable_l2_fn
- ldr r1, [r1]
- cmp r1, #0
- blxne r1
- dmb
-
- mrc p15, 0, r0, c0, c0, 5 /* MPIDR */
- and r0, r0, #15 /* what CPU am I */
-
- ldr r1, =msm_pc_debug_counters /*load the IMEM debug location */
- ldr r1, [r1]
- cmp r1, #0
- beq skip_pc_debug1
- add r1, r1, r0, LSL #4 /* debug location for this CPU */
- ldr r2, [r1]
- add r2, #1
- str r2, [r1]
-skip_pc_debug1:
-
-#ifdef CONFIG_MSM_SCM
- ldr r0, =SCM_SVC_BOOT
- ldr r1, =SCM_CMD_TERMINATE_PC
- ldr r2, =msm_pm_flush_l2_flag
- ldr r2, [r2]
- bl scm_call_atomic1
-#else
- mrc p15, 0, r4, c1, c0, 0 /* read current CR */
- bic r0, r4, #(1 << 2) /* clear dcache bit */
- bic r0, r0, #(1 << 12) /* clear icache bit */
- mcr p15, 0, r0, c1, c0, 0 /* disable d/i cache */
- isb
-
- SUSPEND_8x25_L2
- SET_SMP_COHERENCY OFF
- wfi
- DELAY_8x25 300
-
- mcr p15, 0, r4, c1, c0, 0 /* restore d/i cache */
- isb
- ENABLE_8x25_L2 /* enable only l2, no need to restore the reg back */
- SET_SMP_COHERENCY ON
-#endif
-
-#if defined(CONFIG_MSM_FIQ_SUPPORT)
- cpsie f
-#endif
- mrc p15, 0, r0, c0, c0, 5 /* MPIDR */
- and r0, r0, #15 /* what CPU am I */
-
- ldr r1, =msm_pc_debug_counters /*load the IMEM debug location */
- ldr r1, [r1]
- cmp r1, #0
- beq skip_pc_debug2
- add r1, r1, r0, LSL #4 /* debug location for this CPU */
- add r1, #8
- ldr r2, [r1]
- add r2, #1
- str r2, [r1]
-
-skip_pc_debug2:
- ldr r1, =msm_pm_enable_l2_fn
- ldr r1, [r1]
- cmp r1, #0
- blxne r1
- dmb
-
-#if defined(CONFIG_MSM_JTAG) || defined(CONFIG_MSM_JTAG_MM)
- bl msm_jtag_restore_state
-#endif
- ldr r0, =msm_saved_state /* address of msm_saved_state ptr */
- ldr r0, [r0] /* load ptr */
-#if (NR_CPUS >= 2)
- mrc p15, 0, r1, c0, c0, 5 /* MPIDR */
- ands r1, r1, #15 /* What CPU am I */
- mov r2, #CPU_SAVED_STATE_SIZE
- mul r2, r2, r1
- add r0, r0, r2
-#endif
- ldmfd r0, {r4-r14} /* restore registers */
- mov r0, #0 /* return power collapse failed */
- bx lr
-
-ENTRY(msm_pm_collapse_exit)
-#if 0 /* serial debug */
- mov r0, #0x80000016
- mcr p15, 0, r0, c15, c2, 4
- mov r0, #0xA9000000
- add r0, r0, #0x00A00000 /* UART1 */
- /*add r0, r0, #0x00C00000*/ /* UART3 */
- mov r1, #'A'
- str r1, [r0, #0x00C]
-#endif
- ldr r1, =msm_saved_state_phys
- ldr r2, =msm_pm_collapse_exit
- adr r3, msm_pm_collapse_exit
- add r1, r1, r3
- sub r1, r1, r2
- ldr r1, [r1]
- add r1, r1, #CPU_SAVED_STATE_SIZE
-#if (NR_CPUS >= 2)
- mrc p15, 0, r2, c0, c0, 5 /* MPIDR */
- ands r2, r2, #15 /* What CPU am I */
- mov r3, #CPU_SAVED_STATE_SIZE
- mul r2, r2, r3
- add r1, r1, r2
-#endif
-
- ldmdb r1!, {r2-r11}
- mcr p15, 0, r4, c3, c0, 0 /* dacr */
- mcr p15, 0, r3, c2, c0, 0 /* TTBR0 */
-#ifdef CONFIG_ARCH_MSM_SCORPION
- /* This instruction is not valid for non scorpion processors */
- mcr p15, 3, r5, c15, c0, 3 /* L2CR1 */
-#endif
- mcr p15, 0, r6, c10, c2, 0 /* PRRR */
- mcr p15, 0, r7, c10, c2, 1 /* NMRR */
- mcr p15, 0, r8, c1, c0, 1 /* ACTLR */
- mcr p15, 0, r9, c2, c0, 1 /* TTBR1 */
- mcr p15, 0, r10, c13, c0, 3 /* TPIDRURO */
- mcr p15, 0, r11, c13, c0, 1 /* context ID */
- isb
- ldmdb r1!, {r4-r14}
- ldr r0, =msm_pm_pc_pgd
- ldr r1, =msm_pm_collapse_exit
- adr r3, msm_pm_collapse_exit
- add r0, r0, r3
- sub r0, r0, r1
- ldr r0, [r0]
- mrc p15, 0, r1, c2, c0, 0 /* save current TTBR0 */
- and r3, r1, #0x7f /* mask to get TTB flags */
- orr r0, r0, r3 /* add TTB flags to switch TTBR value */
- mcr p15, 0, r0, c2, c0, 0 /* temporary switch TTBR0 */
- isb
- mcr p15, 0, r2, c1, c0, 0 /* MMU control */
- isb
-msm_pm_mapped_pa:
- /* Switch to virtual */
- ldr r0, =msm_pm_pa_to_va
- mov pc, r0
-msm_pm_pa_to_va:
- mcr p15, 0, r1, c2, c0, 0 /* restore TTBR0 */
- isb
- mcr p15, 0, r3, c8, c7, 0 /* UTLBIALL */
- mcr p15, 0, r3, c7, c5, 6 /* BPIALL */
- dsb
- isb
-
-#ifdef CONFIG_ARCH_MSM_KRAIT
- mrc p15, 0, r1, c0, c0, 0
- ldr r3, =0xff00fc00
- and r3, r1, r3
- ldr r1, =0x51000400
- cmp r3, r1
- mrceq p15, 7, r3, c15, c0, 2
- biceq r3, r3, #0x400
- mcreq p15, 7, r3, c15, c0, 2
-#else
- RESUME_8x25_L2
- SET_SMP_COHERENCY ON
-#endif
-
- ldr r1, =msm_pm_enable_l2_fn
- ldr r1, [r1]
- cmp r1, #0
- stmfd sp!, {lr}
- blxne r1
- dmb
-#if defined(CONFIG_MSM_JTAG) || defined(CONFIG_MSM_JTAG_MM)
- bl msm_jtag_restore_state
-#endif
- ldmfd sp!, {lr}
- mov r0, #1
- bx lr
- nop
- nop
- nop
- nop
- nop
-1: b 1b
-
+ .arm
ENTRY(msm_pm_boot_entry)
mrc p15, 0, r0, c0, c0, 5 /* MPIDR */
and r0, r0, #15 /* what CPU am I */
@@ -398,80 +49,14 @@
add r1, r1, r0, LSL #2 /* locate boot vector for our cpu */
ldr pc, [r1] /* jump */
-ENTRY(msm_pm_set_l2_flush_flag)
- ldr r1, =msm_pm_flush_l2_flag
- str r0, [r1]
- bx lr
-
-ENTRY(msm_pm_get_l2_flush_flag)
- ldr r1, =msm_pm_flush_l2_flag
- ldr r0, [r1]
- bx lr
+3: .long .
.data
- .globl msm_pm_pc_pgd
-msm_pm_pc_pgd:
- .long 0x0
-
- .globl msm_saved_state
-msm_saved_state:
- .long 0x0
-
- .globl msm_saved_state_phys
-msm_saved_state_phys:
- .long 0x0
-
.globl msm_pm_boot_vector
msm_pm_boot_vector:
.space 4 * NR_CPUS
- .globl target_type
-target_type:
- .long 0x0
-
- .globl apps_power_collapse
-apps_power_collapse:
- .long 0x0
-
- .globl l2x0_base_addr
-l2x0_base_addr:
- .long 0x0
-
.globl msm_pc_debug_counters_phys
msm_pc_debug_counters_phys:
.long 0x0
-
- .globl msm_pc_debug_counters
-msm_pc_debug_counters:
- .long 0x0
-
- .globl msm_pm_enable_l2_fn
-msm_pm_enable_l2_fn:
- .long 0x0
-
- .globl msm_pm_disable_l2_fn
-msm_pm_disable_l2_fn:
- .long 0x0
-
- .globl msm_pm_flush_l2_fn
-msm_pm_flush_l2_fn:
- .long 0x0
-
-/*
- * Default the l2 flush flag to 1 so that caches are flushed during power
- * collapse unless the L2 driver decides to flush them only during L2
- * Power collapse.
- */
-msm_pm_flush_l2_flag:
- .long 0x1
-
-/*
- * Save & restore l2x0 registers while system is entering and resuming
- * from Power Collapse.
- * 1. aux_ctrl_save (0x0)
- * 2. data_latency_ctrl (0x4)
- * 3. prefetch control (0x8)
- */
-l2x0_saved_ctrl_reg_val:
- .space 4 * 3
diff --git a/arch/arm/mach-msm/idle.h b/arch/arm/mach-msm/idle.h
index 72f1a03..0fb96c3 100644
--- a/arch/arm/mach-msm/idle.h
+++ b/arch/arm/mach-msm/idle.h
@@ -14,49 +14,13 @@
#ifndef _ARCH_ARM_MACH_MSM_IDLE_H_
#define _ARCH_ARM_MACH_MSM_IDLE_H_
-/* 11 general purpose registers (r4-r14), 10 cp15 registers */
-#define CPU_SAVED_STATE_SIZE (4 * 11 + 4 * 10)
-
-#define ON 1
-#define OFF 0
-#define TARGET_IS_8625 1
-#define POWER_COLLAPSED 1
-
-#ifndef __ASSEMBLY__
-
-int msm_arch_idle(void);
-int msm_pm_collapse(void);
-int msm_pm_pc_hotplug(void);
-void msm_pm_collapse_exit(void);
-extern void *msm_saved_state;
-extern void (*msm_pm_disable_l2_fn)(void);
-extern void (*msm_pm_enable_l2_fn)(void);
-extern void (*msm_pm_flush_l2_fn)(void);
-extern unsigned long msm_saved_state_phys;
-
#ifdef CONFIG_CPU_V7
-void msm_pm_boot_entry(void);
-void msm_pm_set_l2_flush_flag(unsigned int flag);
-int msm_pm_get_l2_flush_flag(void);
-extern unsigned long msm_pm_pc_pgd;
extern unsigned long msm_pm_boot_vector[NR_CPUS];
-extern uint32_t target_type;
-extern uint32_t apps_power_collapse;
-extern uint32_t *l2x0_base_addr;
+void msm_pm_boot_entry(void);
#else
-static inline void msm_pm_set_l2_flush_flag(unsigned int flag)
-{
- /* empty */
-}
static inline void msm_pm_boot_entry(void)
{
/* empty */
}
-static inline void msm_pm_write_boot_vector(unsigned int cpu,
- unsigned long address)
-{
- /* empty */
-}
-#endif
#endif
#endif
diff --git a/arch/arm/mach-msm/include/mach/clk-provider.h b/arch/arm/mach-msm/include/mach/clk-provider.h
index 75dc240..4529a81 100644
--- a/arch/arm/mach-msm/include/mach/clk-provider.h
+++ b/arch/arm/mach-msm/include/mach/clk-provider.h
@@ -17,11 +17,13 @@
#define __MACH_CLK_PROVIDER_H
#include <linux/types.h>
+#include <linux/err.h>
#include <linux/list.h>
#include <linux/clkdev.h>
#include <linux/spinlock.h>
#include <linux/mutex.h>
#include <linux/regulator/consumer.h>
+#include <linux/seq_file.h>
#include <mach/clk.h>
/*
@@ -40,6 +42,21 @@
#define ENABLE_VOTED 4 /* Bit pol: 1 = running; delay on disable */
#define DELAY 5 /* No bit to check, just delay */
+struct clk_register_data {
+ char *name;
+ u32 offset;
+};
+#ifdef CONFIG_DEBUG_FS
+void clk_debug_print_hw(struct clk *clk, struct seq_file *f);
+#else
+static inline void clk_debug_print_hw(struct clk *clk, struct seq_file *f) {}
+#endif
+
+#define CLK_WARN(clk, cond, fmt, ...) do { \
+ clk_debug_print_hw(clk, NULL); \
+ WARN(cond, "%s: " fmt, (clk)->dbg_name, ##__VA_ARGS__); \
+} while (0)
+
/**
* struct clk_vdd_class - Voltage scaling class
* @class_name: name of the class
@@ -93,6 +110,14 @@
.lock = __MUTEX_INITIALIZER(_name.lock) \
}
+#define DEFINE_VDD_REGS_INIT(_name, _num_regulators) \
+ struct clk_vdd_class _name = { \
+ .class_name = #_name, \
+ .regulator = (struct regulator * [_num_regulators]) {}, \
+ .num_regulators = _num_regulators, \
+ .lock = __MUTEX_INITIALIZER(_name.lock) \
+ }
+
enum handoff {
HANDOFF_ENABLED_CLK,
HANDOFF_DISABLED_CLK,
@@ -120,6 +145,8 @@
int (*set_parent)(struct clk *clk, struct clk *parent);
struct clk *(*get_parent)(struct clk *clk);
bool (*is_local)(struct clk *clk);
+ void __iomem *(*list_registers)(struct clk *clk, int n,
+ struct clk_register_data **regs, u32 *size);
};
/**
@@ -188,4 +215,13 @@
#define CLK_LOOKUP(con, c, dev) { .con_id = con, .clk = &c, .dev_id = dev }
+static inline bool is_better_rate(unsigned long req, unsigned long best,
+ unsigned long new)
+{
+ if (IS_ERR_VALUE(new))
+ return false;
+
+ return (req <= new && new < best) || (best < req && best < new);
+}
+
#endif
diff --git a/arch/arm/mach-msm/include/mach/clock-generic.h b/arch/arm/mach-msm/include/mach/clock-generic.h
index f6feda0..30a2b93 100644
--- a/arch/arm/mach-msm/include/mach/clock-generic.h
+++ b/arch/arm/mach-msm/include/mach/clock-generic.h
@@ -46,10 +46,14 @@
struct clk *safe_parent;
int safe_sel;
struct clk_mux_ops *ops;
+ /* Recursively search for the requested parent. */
+ bool rec_set_par;
/* Fields not used by helper function. */
void *const __iomem *base;
u32 offset;
+ u32 en_offset;
+ int en_reg;
u32 mask;
u32 shift;
u32 en_mask;
@@ -63,6 +67,8 @@
return container_of(c, struct mux_clk, c);
}
+int parent_to_src_sel(struct clk_src *parents, int num_parents, struct clk *p);
+
extern struct clk_ops clk_ops_gen_mux;
/* ==================== Divider clock ==================== */
@@ -77,11 +83,16 @@
void (*disable)(struct div_clk *clk);
};
+struct div_data {
+ unsigned int div;
+ unsigned int min_div;
+ unsigned int max_div;
+ unsigned long rate_margin;
+};
+
struct div_clk {
- unsigned int div;
- unsigned int min_div;
- unsigned int max_div;
- unsigned long rate_margin;
+ struct div_data data;
+
/* Optional */
struct clk_div_ops *ops;
@@ -103,9 +114,17 @@
extern struct clk_ops clk_ops_div;
extern struct clk_ops clk_ops_slave_div;
+struct ext_clk {
+ struct clk c;
+};
+
+extern struct clk_ops clk_ops_ext;
+
#define DEFINE_FIXED_DIV_CLK(clk_name, _div, _parent) \
static struct div_clk clk_name = { \
- .div = _div, \
+ .data = { \
+ .div = _div, \
+ }, \
.c = { \
.parent = _parent, \
.dbg_name = #clk_name, \
@@ -116,7 +135,9 @@
#define DEFINE_FIXED_SLAVE_DIV_CLK(clk_name, _div, _parent) \
static struct div_clk clk_name = { \
- .div = _div, \
+ .data = { \
+ .div = _div, \
+ }, \
.c = { \
.parent = _parent, \
.dbg_name = #clk_name, \
@@ -125,4 +146,90 @@
} \
}
+#define DEFINE_EXT_CLK(clk_name, _parent) \
+static struct ext_clk clk_name = { \
+ .c = { \
+ .parent = _parent, \
+ .dbg_name = #clk_name, \
+ .ops = &clk_ops_ext, \
+ CLK_INIT(clk_name.c), \
+ } \
+}
+
+/* ==================== Mux Div clock ==================== */
+
+struct mux_div_clk;
+
+/*
+ * struct mux_div_ops
+ * the enable and disable ops are optional.
+ */
+
+struct mux_div_ops {
+ int (*set_src_div)(struct mux_div_clk *, u32 src_sel, u32 div);
+ void (*get_src_div)(struct mux_div_clk *, u32 *src_sel, u32 *div);
+ int (*enable)(struct mux_div_clk *);
+ void (*disable)(struct mux_div_clk *);
+ bool (*is_enabled)(struct mux_div_clk *);
+};
+
+/*
+ * struct mux_div_clk - combined mux/divider clock
+ * @priv
+ parameters needed by ops
+ * @safe_freq
+ when switching rates from A to B, the mux div clock will
+ instead switch from A -> safe_freq -> B. This allows the
+ mux_div clock to change rates while enabled, even if this
+ behavior is not supported by the parent clocks.
+
+ If changing the rate of parent A also causes the rate of
+ parent B to change, then safe_freq must be defined.
+
+ safe_freq is expected to have a source clock which is always
+ on and runs at only one rate.
+ * @parents
+ list of parents and mux indicies
+ * @ops
+ function pointers for hw specific operations
+ * @src_sel
+ the mux index which will be used if the clock is enabled.
+ */
+
+struct mux_div_clk {
+ /* Required parameters */
+ struct mux_div_ops *ops;
+ struct div_data data;
+ struct clk_src *parents;
+ u32 num_parents;
+
+ struct clk c;
+
+ /* Internal */
+ u32 src_sel;
+
+ /* Optional parameters */
+ void *priv;
+ void __iomem *base;
+ u32 div_mask;
+ u32 div_offset;
+ u32 div_shift;
+ u32 src_mask;
+ u32 src_offset;
+ u32 src_shift;
+ u32 en_mask;
+ u32 en_offset;
+
+ u32 safe_div;
+ struct clk *safe_parent;
+ unsigned long safe_freq;
+};
+
+static inline struct mux_div_clk *to_mux_div_clk(struct clk *clk)
+{
+ return container_of(clk, struct mux_div_clk, c);
+}
+
+extern struct clk_ops clk_ops_mux_div_clk;
+
#endif
diff --git a/arch/arm/mach-msm/include/mach/cpufreq.h b/arch/arm/mach-msm/include/mach/cpufreq.h
index 1a6f2d9..46872d7 100644
--- a/arch/arm/mach-msm/include/mach/cpufreq.h
+++ b/arch/arm/mach-msm/include/mach/cpufreq.h
@@ -1,4 +1,5 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/*
+ * Copyright (c) 2013 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -9,34 +10,30 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
+#ifndef __MACH_CPUFREQ_H
+#define __MACH_CPUFREQ_H
-#ifndef __ARCH_ARM_MACH_MSM_MACH_CPUFREQ_H
-#define __ARCH_ARM_MACH_MSM_MACH_CPUFREQ_H
-
-#define MSM_CPUFREQ_NO_LIMIT 0xFFFFFFFF
-
-#ifdef CONFIG_CPU_FREQ_MSM
-
-/**
- * msm_cpufreq_set_freq_limit() - Set max/min freq limits on cpu
- *
- * @cpu: The cpu core for which the limits apply
- * @max: The max frequency allowed
- * @min: The min frequency allowed
- *
- * If the @max or @min is set to MSM_CPUFREQ_NO_LIMIT, the limit
- * will default to the CPUFreq limit.
- *
- * returns 0 on success, errno on failure
- */
-extern int msm_cpufreq_set_freq_limits(
- uint32_t cpu, uint32_t min, uint32_t max);
+#if defined(CONFIG_DEVFREQ_GOV_MSM_CPUFREQ)
+extern int devfreq_msm_cpufreq_update_bw(void);
+extern int register_devfreq_msm_cpufreq(void);
#else
-static inline int msm_cpufreq_set_freq_limits(
- uint32_t cpu, uint32_t min, uint32_t max)
+static int devfreq_msm_cpufreq_update_bw(void)
{
- return -ENOSYS;
+ return 0;
+}
+static int register_devfreq_msm_cpufreq(void)
+{
+ return 0;
}
#endif
-#endif /* __ARCH_ARM_MACH_MSM_MACH_CPUFREQ_H */
+#if defined(CONFIG_CPU_FREQ_MSM)
+extern unsigned long msm_cpufreq_get_bw(void);
+#else
+extern unsigned long msm_cpufreq_get_bw(void)
+{
+ return ULONG_MAX;
+}
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/kgsl.h b/arch/arm/mach-msm/include/mach/kgsl.h
index 2d7e8df..f398652 100644
--- a/arch/arm/mach-msm/include/mach/kgsl.h
+++ b/arch/arm/mach-msm/include/mach/kgsl.h
@@ -81,9 +81,9 @@
int (*set_grp_async)(void);
unsigned int idle_timeout;
bool strtstp_sleepwake;
+ bool bus_control;
unsigned int clk_map;
unsigned int idle_needed;
- unsigned int step_mul;
struct msm_bus_scale_pdata *bus_scale_table;
struct kgsl_device_iommu_data *iommu_data;
int iommu_count;
diff --git a/arch/arm/mach-msm/include/mach/mpm.h b/arch/arm/mach-msm/include/mach/mpm.h
index e76a6a9..abfac48 100644
--- a/arch/arm/mach-msm/include/mach/mpm.h
+++ b/arch/arm/mach-msm/include/mach/mpm.h
@@ -112,11 +112,13 @@
* @sclk_count: wakeup time in sclk counts for programmed RPM wakeup
* @from_idle: indicates if the sytem is entering low power mode as a part of
* suspend/idle task.
+ * @cpumask: the next cpu to wakeup.
*
* Low power management code calls into this API to configure the MPM to
* monitor the active irqs before going to sleep.
*/
-void msm_mpm_enter_sleep(uint32_t sclk_count, bool from_idle);
+void msm_mpm_enter_sleep(uint32_t sclk_count, bool from_idle,
+ const struct cpumask *cpumask);
/**
* msm_mpm_exit_sleep() -Called from PM code after resuming from low power mode
*
@@ -159,7 +161,8 @@
{ return false; }
static inline bool msm_mpm_gpio_irqs_detectable(bool from_idle)
{ return false; }
-static inline void msm_mpm_enter_sleep(uint32_t sclk_count, bool from_idle) {}
+static inline void msm_mpm_enter_sleep(uint32_t sclk_count, bool from_idle
+ const struct cpumask *cpumask) {}
static inline void msm_mpm_exit_sleep(bool from_idle) {}
static inline void __init of_mpm_init(struct device_node *node) {}
#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_smd.h b/arch/arm/mach-msm/include/mach/msm_smd.h
index cd07662..e3bd488 100644
--- a/arch/arm/mach-msm/include/mach/msm_smd.h
+++ b/arch/arm/mach-msm/include/mach/msm_smd.h
@@ -24,6 +24,7 @@
#include <mach/msm_smem.h>
typedef struct smd_channel smd_channel_t;
+struct cpumask;
#define SMD_MAX_CH_NAME_LEN 20 /* includes null char at end */
@@ -217,13 +218,15 @@
* particular channel.
* @ch: open channel handle to use for the edge
* @mask: 1 = mask interrupts; 0 = unmask interrupts
+ * @cpumask cpumask for the next cpu scheduled to be woken up
* @returns: 0 for success; < 0 for failure
*
* Note that this enables/disables all interrupts from the remote subsystem for
* all channels. As such, it should be used with care and only for specific
* use cases such as power-collapse sequencing.
*/
-int smd_mask_receive_interrupt(smd_channel_t *ch, bool mask);
+int smd_mask_receive_interrupt(smd_channel_t *ch, bool mask,
+ const struct cpumask *cpumask);
/* Starts a packet transaction. The size of the packet may exceed the total
* size of the smd ring buffer.
@@ -411,7 +414,8 @@
{
}
-static inline int smd_mask_receive_interrupt(smd_channel_t *ch, bool mask)
+static inline int smd_mask_receive_interrupt(smd_channel_t *ch, bool mask,
+ struct cpumask *cpumask)
{
return -ENODEV;
}
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/rtac.h b/arch/arm/mach-msm/include/mach/qdsp6v2/rtac.h
index 0a1cdd4..42cf6f9 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/rtac.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/rtac.h
@@ -45,7 +45,7 @@
};
void rtac_add_adm_device(u32 port_id, u32 copp_id, u32 path_id, u32 popp_id);
-void rtac_remove_adm_device(u32 port_id);
+void rtac_remove_adm_device(u32 port_id, u32 copp_id);
void rtac_remove_popp_from_adm_devices(u32 popp_id);
void rtac_add_voice(u32 cvs_handle, u32 cvp_handle, u32 rx_afe_port,
u32 tx_afe_port, u32 session_id);
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h b/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
index 2e15cae..9a27fd2 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
@@ -73,7 +73,8 @@
#define USF_TSC_PTR_EVENT_IND 1
#define USF_MOUSE_EVENT_IND 2
#define USF_KEYBOARD_EVENT_IND 3
-#define USF_MAX_EVENT_IND 4
+#define USF_TSC_EXT_EVENT_IND 4
+#define USF_MAX_EVENT_IND 5
/* Types of events, produced by the calculators */
#define USF_NO_EVENT 0
@@ -81,10 +82,12 @@
#define USF_TSC_PTR_EVENT (1 << USF_TSC_PTR_EVENT_IND)
#define USF_MOUSE_EVENT (1 << USF_MOUSE_EVENT_IND)
#define USF_KEYBOARD_EVENT (1 << USF_KEYBOARD_EVENT_IND)
+#define USF_TSC_EXT_EVENT (1 << USF_TSC_EXT_EVENT_IND)
#define USF_ALL_EVENTS (USF_TSC_EVENT |\
USF_TSC_PTR_EVENT |\
USF_MOUSE_EVENT |\
- USF_KEYBOARD_EVENT)
+ USF_KEYBOARD_EVENT |\
+ USF_TSC_EXT_EVENT)
/* min, max array dimension */
#define MIN_MAX_DIM 2
@@ -146,6 +149,8 @@
int tsc_y_tilt[MIN_MAX_DIM];
/* Touch screen pressure limits: min & max; for input module */
int tsc_pressure[MIN_MAX_DIM];
+ /* The requested side buttons bitmap */
+ uint16_t req_side_buttons_bitmap;
/* Bitmap of types of events (USF_X_EVENT), produced by calculator */
uint16_t event_types;
/* Input event source */
@@ -174,6 +179,8 @@
int inclinations[TILTS_DIM];
/* [0-1023] (10bits); 0 - pen up */
uint32_t pressure;
+/* Bitmap for side button state. 1 - down, 0 - up */
+ uint16_t side_buttons_state_bitmap;
};
/* Mouse buttons, supported by USF */
diff --git a/arch/arm/mach-msm/iommu_domains.c b/arch/arm/mach-msm/iommu_domains.c
index 20a5249..1d5e0d9 100644
--- a/arch/arm/mach-msm/iommu_domains.c
+++ b/arch/arm/mach-msm/iommu_domains.c
@@ -553,7 +553,8 @@
ida_simple_remove(&domain_nums, data->domain_num);
for (i = 0; i < data->npools; ++i)
- gen_pool_destroy(data->pools[i].gpool);
+ if (data->pools[i].gpool)
+ gen_pool_destroy(data->pools[i].gpool);
kfree(data->pools);
kfree(data);
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index ce66531..6bb4011 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -434,7 +434,7 @@
unsigned int len)
{
struct sk_buff *temp;
- int offset = 0, buf_len = 0, copy_len;
+ unsigned int offset = 0, buf_len = 0, copy_len;
void *buf;
if (!skb_head) {
diff --git a/arch/arm/mach-msm/ipc_socket.c b/arch/arm/mach-msm/ipc_socket.c
index bdda546..5aa6c93 100644
--- a/arch/arm/mach-msm/ipc_socket.c
+++ b/arch/arm/mach-msm/ipc_socket.c
@@ -589,17 +589,24 @@
};
static const struct proto_ops msm_ipc_proto_ops = {
- .owner = THIS_MODULE,
.family = AF_MSM_IPC,
+ .owner = THIS_MODULE,
+ .release = msm_ipc_router_close,
.bind = msm_ipc_router_bind,
.connect = sock_no_connect,
+ .socketpair = sock_no_socketpair,
+ .accept = sock_no_accept,
+ .getname = sock_no_getname,
+ .poll = msm_ipc_router_poll,
+ .ioctl = msm_ipc_router_ioctl,
+ .listen = sock_no_listen,
+ .shutdown = sock_no_shutdown,
+ .setsockopt = sock_no_setsockopt,
+ .getsockopt = sock_no_getsockopt,
.sendmsg = msm_ipc_router_sendmsg,
.recvmsg = msm_ipc_router_recvmsg,
- .ioctl = msm_ipc_router_ioctl,
- .poll = msm_ipc_router_poll,
- .setsockopt = sock_no_setsockopt,
- .getsockopt = sock_no_getsockopt,
- .release = msm_ipc_router_close,
+ .mmap = sock_no_mmap,
+ .sendpage = sock_no_sendpage,
};
static struct proto msm_ipc_proto = {
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index 4fee0ae..f4456c0 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -222,6 +222,7 @@
int ldo_threshold_uV;
int ldo_delta_uV;
int cpu_num;
+ bool ldo_disable;
int coeff1;
int coeff2;
bool reg_en;
@@ -656,6 +657,9 @@
{
struct krait_power_vreg *kvreg = info;
+ if (kvreg->ldo_disable)
+ return;
+
/*
* if the krait is in ldo mode and a voltage change is requested on the
* ldo switch to using hs before changing ldo voltage
@@ -1052,6 +1056,7 @@
(int)action, cpu, cpu_online(cpu));
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_UP_PREPARE:
+ case CPU_UP_CANCELED:
mutex_lock(&pvreg->krait_power_vregs_lock);
kvreg->force_bhs = true;
/*
@@ -1062,7 +1067,6 @@
__switch_to_using_bhs(kvreg);
mutex_unlock(&pvreg->krait_power_vregs_lock);
break;
- case CPU_UP_CANCELED:
case CPU_ONLINE:
mutex_lock(&pvreg->krait_power_vregs_lock);
kvreg->force_bhs = false;
@@ -1173,6 +1177,9 @@
& readl_relaxed(kvreg->reg_base + CPU_PWR_CTL);
kvreg->online_at_probe
= online ? (WAIT_FOR_LOAD | WAIT_FOR_VOLTAGE) : 0x0;
+
+ if (online)
+ kvreg->force_bhs = false;
}
static void glb_init(void __iomem *apcs_gcc_base)
@@ -1197,6 +1204,7 @@
int headroom_uV, retention_uV, ldo_default_uV, ldo_threshold_uV;
int ldo_delta_uV;
int cpu_num;
+ bool ldo_disable = false;
if (pdev->dev.of_node) {
/* Get init_data from device tree. */
@@ -1280,6 +1288,9 @@
pr_err("bad cpu-num= %d specified\n", cpu_num);
return -EINVAL;
}
+
+ ldo_disable = of_property_read_bool(pdev->dev.of_node,
+ "qcom,ldo-disable");
}
if (!init_data) {
@@ -1333,6 +1344,8 @@
kvreg->ldo_threshold_uV = ldo_threshold_uV;
kvreg->ldo_delta_uV = ldo_delta_uV;
kvreg->cpu_num = cpu_num;
+ kvreg->ldo_disable = ldo_disable;
+ kvreg->force_bhs = true;
platform_set_drvdata(pdev, kvreg);
@@ -1623,6 +1636,12 @@
void *mdd_base;
struct krait_power_vreg *kvreg;
+ if (version == 0) {
+ gcc_base_ptr = ioremap_nocache(GCC_BASE, SZ_4K);
+ version = readl_relaxed(gcc_base_ptr + VERSION);
+ iounmap(gcc_base_ptr);
+ }
+
/* Turn on the BHS, turn off LDO Bypass and power down LDO */
reg_val = BHS_CNT_DEFAULT << BHS_CNT_BIT_POS
| LDO_PWR_DWN_MASK
@@ -1630,23 +1649,14 @@
| BHS_EN_MASK;
writel_relaxed(reg_val, base_ptr + APC_PWR_GATE_CTL);
- if (version == 0) {
- gcc_base_ptr = ioremap_nocache(GCC_BASE, SZ_4K);
- version = readl_relaxed(gcc_base_ptr + VERSION);
- iounmap(gcc_base_ptr);
- }
+ /* complete the above write before the delay */
+ mb();
+ /* wait for the bhs to settle */
+ udelay(BHS_SETTLING_DELAY_US);
- /* Turn on the BHS segments only for version < 2 */
- if (version <= KPSS_VERSION_2P0) {
- /* complete the above write before the delay */
- mb();
- /* wait for the bhs to settle */
- udelay(BHS_SETTLING_DELAY_US);
-
- /* Turn on BHS segments */
- reg_val |= BHS_SEG_EN_DEFAULT << BHS_SEG_EN_BIT_POS;
- writel_relaxed(reg_val, base_ptr + APC_PWR_GATE_CTL);
- }
+ /* Turn on BHS segments */
+ reg_val |= BHS_SEG_EN_DEFAULT << BHS_SEG_EN_BIT_POS;
+ writel_relaxed(reg_val, base_ptr + APC_PWR_GATE_CTL);
/* complete the above write before the delay */
mb();
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
index 249a334..06160f7 100644
--- a/arch/arm/mach-msm/lpm_levels.c
+++ b/arch/arm/mach-msm/lpm_levels.c
@@ -19,73 +19,115 @@
#include <linux/mutex.h>
#include <linux/cpu.h>
#include <linux/of.h>
+#include <linux/hrtimer.h>
+#include <linux/ktime.h>
+#include <linux/tick.h>
+#include <linux/suspend.h>
+#include <linux/pm_qos.h>
+#include <linux/of_platform.h>
#include <mach/mpm.h>
+#include <mach/cpuidle.h>
+#include <mach/event_timer.h>
#include "pm.h"
#include "rpm-notifier.h"
#include "spm.h"
#include "idle.h"
+#define SCLK_HZ (32768)
+
enum {
MSM_LPM_LVL_DBG_SUSPEND_LIMITS = BIT(0),
MSM_LPM_LVL_DBG_IDLE_LIMITS = BIT(1),
};
-enum {
- MSM_SCM_L2_ON = 0,
- MSM_SCM_L2_OFF = 1,
- MSM_SCM_L2_GDHS = 3,
-};
-
-struct msm_rpmrs_level {
- enum msm_pm_sleep_mode sleep_mode;
- uint32_t l2_cache;
- bool available;
+struct power_params {
uint32_t latency_us;
- uint32_t steady_state_power;
+ uint32_t ss_power;
uint32_t energy_overhead;
uint32_t time_overhead_us;
+ uint32_t target_residency_us;
};
+struct lpm_cpu_level {
+ const char *name;
+ enum msm_pm_sleep_mode mode;
+ struct power_params pwr;
+ bool use_bc_timer;
+ bool sync;
+};
+
+struct lpm_system_level {
+ const char *name;
+ uint32_t l2_mode;
+ struct power_params pwr;
+ enum msm_pm_sleep_mode min_cpu_mode;
+ int num_cpu_votes;
+ bool notify_rpm;
+ bool available;
+ bool sync;
+};
+
+struct lpm_system_state {
+ struct lpm_cpu_level *cpu_level;
+ int num_cpu_levels;
+ struct lpm_system_level *system_level;
+ int num_system_levels;
+ enum msm_pm_sleep_mode sync_cpu_mode;
+ int last_entered_cluster_index;
+ bool allow_synched_levels;
+ bool no_l2_saw;
+ struct spinlock sync_lock;
+ int num_cores_in_sync;
+};
+
+static struct lpm_system_state sys_state;
+static bool suspend_in_progress;
+
struct lpm_lookup_table {
uint32_t modes;
const char *mode_name;
};
-static void msm_lpm_level_update(void);
-
-static int msm_lpm_cpu_callback(struct notifier_block *cpu_nb,
+static void lpm_system_level_update(void);
+static void setup_broadcast_timer(void *arg);
+static int lpm_cpu_callback(struct notifier_block *cpu_nb,
unsigned long action, void *hcpu);
-static struct notifier_block __refdata msm_lpm_cpu_nblk = {
- .notifier_call = msm_lpm_cpu_callback,
+static struct notifier_block __refdata lpm_cpu_nblk = {
+ .notifier_call = lpm_cpu_callback,
};
static uint32_t allowed_l2_mode;
static uint32_t sysfs_dbg_l2_mode = MSM_SPM_L2_MODE_POWER_COLLAPSE;
static uint32_t default_l2_mode;
-static bool no_l2_saw;
-static ssize_t msm_lpm_levels_attr_show(
+static ssize_t lpm_levels_attr_show(
struct kobject *kobj, struct kobj_attribute *attr, char *buf);
-static ssize_t msm_lpm_levels_attr_store(struct kobject *kobj,
+static ssize_t lpm_levels_attr_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count);
-#define ADJUST_LATENCY(x) \
- ((x == MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE) ?\
- (num_online_cpus()) / 2 : 0)
-static int msm_lpm_lvl_dbg_msk;
+static int lpm_lvl_dbg_msk;
module_param_named(
- debug_mask, msm_lpm_lvl_dbg_msk, int, S_IRUGO | S_IWUSR | S_IWGRP
+ debug_mask, lpm_lvl_dbg_msk, int, S_IRUGO | S_IWUSR | S_IWGRP
);
-static struct msm_rpmrs_level *msm_lpm_levels;
-static int msm_lpm_level_count;
+static bool menu_select;
+module_param_named(
+ menu_select, menu_select, bool, S_IRUGO | S_IWUSR | S_IWGRP
+);
+
+static int msm_pm_sleep_time_override;
+module_param_named(sleep_time_override,
+ msm_pm_sleep_time_override, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+static int num_powered_cores;
+static struct hrtimer lpm_hrtimer;
static struct kobj_attribute lpm_l2_kattr = __ATTR(l2, S_IRUGO|S_IWUSR,\
- msm_lpm_levels_attr_show, msm_lpm_levels_attr_store);
+ lpm_levels_attr_show, lpm_levels_attr_store);
static struct attribute *lpm_levels_attr[] = {
&lpm_l2_kattr.attr,
@@ -97,7 +139,7 @@
};
/* SYSFS */
-static ssize_t msm_lpm_levels_attr_show(
+static ssize_t lpm_levels_attr_show(
struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
struct kernel_param kp;
@@ -115,7 +157,7 @@
return rc;
}
-static ssize_t msm_lpm_levels_attr_store(struct kobject *kobj,
+static ssize_t lpm_levels_attr_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count)
{
struct kernel_param kp;
@@ -128,58 +170,42 @@
return rc;
sysfs_dbg_l2_mode = temp;
- msm_lpm_level_update();
+ lpm_system_level_update();
return count;
}
-static int msm_pm_get_sleep_mode_value(struct device_node *node,
- const char *key, uint32_t *sleep_mode_val)
+static int msm_pm_get_sleep_mode_value(const char *mode_name)
{
- int i;
- struct lpm_lookup_table {
- uint32_t modes;
- const char *mode_name;
- };
struct lpm_lookup_table pm_sm_lookup[] = {
{MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT,
"wfi"},
- {MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT,
- "ramp_down_and_wfi"},
{MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE,
"standalone_pc"},
{MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
"pc"},
{MSM_PM_SLEEP_MODE_RETENTION,
"retention"},
- {MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND,
- "pc_suspend"},
- {MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN,
- "pc_no_xo_shutdown"}
};
- int ret;
- const char *mode_name;
+ int i;
+ int ret = -EINVAL;
- ret = of_property_read_string(node, key, &mode_name);
- if (!ret) {
- ret = -EINVAL;
- for (i = 0; i < ARRAY_SIZE(pm_sm_lookup); i++) {
- if (!strcmp(mode_name, pm_sm_lookup[i].mode_name)) {
- *sleep_mode_val = pm_sm_lookup[i].modes;
- ret = 0;
- break;
- }
+ for (i = 0; i < ARRAY_SIZE(pm_sm_lookup); i++) {
+ if (!strcmp(mode_name, pm_sm_lookup[i].mode_name)) {
+ ret = pm_sm_lookup[i].modes;
+ break;
}
}
return ret;
}
-static int msm_lpm_set_l2_mode(int sleep_mode)
+static int lpm_set_l2_mode(struct lpm_system_state *system_state,
+ int sleep_mode)
{
int lpm = sleep_mode;
int rc = 0;
- if (no_l2_saw)
+ if (system_state->no_l2_saw)
goto bail_set_l2_mode;
msm_pm_set_l2_flush_flag(MSM_SCM_L2_ON);
@@ -209,244 +235,341 @@
WARN_ON_ONCE(1);
else
pr_err("%s: Failed to set L2 low power mode %d, ERR %d",
- __func__, lpm, rc);
+ __func__, lpm, rc);
}
-
bail_set_l2_mode:
return rc;
}
-static void msm_lpm_level_update(void)
+static void lpm_system_level_update(void)
{
- int lpm_level;
- struct msm_rpmrs_level *level = NULL;
+ int i;
+ struct lpm_system_level *l = NULL;
uint32_t max_l2_mode;
static DEFINE_MUTEX(lpm_lock);
mutex_lock(&lpm_lock);
+ if (num_powered_cores == 1)
+ allowed_l2_mode = MSM_SPM_L2_MODE_POWER_COLLAPSE;
+ else if (sys_state.allow_synched_levels)
+ allowed_l2_mode = MSM_SPM_L2_MODE_POWER_COLLAPSE;
+ else
+ allowed_l2_mode = default_l2_mode;
max_l2_mode = min(allowed_l2_mode, sysfs_dbg_l2_mode);
- for (lpm_level = 0; lpm_level < msm_lpm_level_count; lpm_level++) {
- level = &msm_lpm_levels[lpm_level];
- level->available = !(level->l2_cache > max_l2_mode);
+ for (i = 0; i < sys_state.num_system_levels; i++) {
+ l = &sys_state.system_level[i];
+ l->available = !(l->l2_mode > max_l2_mode);
}
mutex_unlock(&lpm_lock);
}
-int msm_lpm_enter_sleep(uint32_t sclk_count, void *limits,
- bool from_idle, bool notify_rpm)
+static int lpm_system_mode_select(
+ struct lpm_system_state *system_state,
+ uint32_t sleep_us, bool from_idle)
{
- int ret = 0;
- int debug_mask;
- uint32_t l2 = *(uint32_t *)limits;
+ int best_level = -1;
+ int i;
+ uint32_t best_level_pwr = ~0UL;
+ uint32_t pwr;
+ uint32_t latency_us = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
- if (from_idle)
- debug_mask = msm_lpm_lvl_dbg_msk &
- MSM_LPM_LVL_DBG_IDLE_LIMITS;
- else
- debug_mask = msm_lpm_lvl_dbg_msk &
- MSM_LPM_LVL_DBG_SUSPEND_LIMITS;
+ if (!system_state->system_level)
+ return -EINVAL;
- if (debug_mask)
- pr_info("%s(): l2:%d", __func__, l2);
+ for (i = 0; i < system_state->num_system_levels; i++) {
+ struct lpm_system_level *system_level =
+ &system_state->system_level[i];
+ struct power_params *pwr_param = &system_level->pwr;
- ret = msm_lpm_set_l2_mode(l2);
+ if (!system_level->available)
+ continue;
- if (ret) {
- if (ret == -ENXIO)
- ret = 0;
- else {
- pr_warn("%s(): Failed to set L2 SPM Mode %d",
- __func__, l2);
- goto bail;
+ if (system_level->sync &&
+ system_level->num_cpu_votes != num_powered_cores)
+ continue;
+
+ if (latency_us < pwr_param->latency_us && from_idle)
+ continue;
+
+ if (sleep_us < pwr_param->time_overhead_us)
+ continue;
+
+ /*
+ * After the suspend prepare notifications its possible
+ * for the CPU to enter a system sleep mode. But MPM would have
+ * already requested a XO clock based on the wakeup irqs. To
+ * prevent suspend votes from being overriden by idle irqs, MPM
+ * doesn't send an updated MPM vote after suspend_prepare
+ * callback.
+ * To ensure that XO sleep vote isn't used if and when the
+ * device enters idle PC after suspend prepare callback,
+ * disallow any low power modes that notifies RPM after suspend
+ * prepare function is called
+ */
+ if (suspend_in_progress && system_level->notify_rpm &&
+ from_idle)
+ continue;
+
+ if ((sleep_us >> 10) > pwr_param->time_overhead_us) {
+ pwr = pwr_param->ss_power;
+ } else {
+ pwr = pwr_param->ss_power;
+ pwr -= (pwr_param->time_overhead_us
+ * pwr_param->ss_power) / sleep_us;
+ pwr += pwr_param->energy_overhead / sleep_us;
+ }
+
+ if (best_level_pwr >= pwr) {
+ best_level = i;
+ best_level_pwr = pwr;
}
}
+ return best_level;
+}
- if (notify_rpm) {
- ret = msm_rpm_enter_sleep(debug_mask);
+static void lpm_system_prepare(struct lpm_system_state *system_state,
+ int index, bool from_idle)
+{
+ struct lpm_system_level *lvl;
+ struct clock_event_device *bc = tick_get_broadcast_device()->evtdev;
+ uint32_t sclk;
+ int64_t us = (~0ULL);
+ int dbg_mask;
+ int ret;
+ const struct cpumask *nextcpu;
+
+ spin_lock(&system_state->sync_lock);
+ if (num_powered_cores != system_state->num_cores_in_sync) {
+ spin_unlock(&system_state->sync_lock);
+ return;
+ }
+
+ if (from_idle) {
+ dbg_mask = lpm_lvl_dbg_msk & MSM_LPM_LVL_DBG_IDLE_LIMITS;
+ us = ktime_to_us(ktime_sub(bc->next_event, ktime_get()));
+ nextcpu = bc->cpumask;
+ } else {
+ dbg_mask = lpm_lvl_dbg_msk & MSM_LPM_LVL_DBG_SUSPEND_LIMITS;
+ nextcpu = cpumask_of(smp_processor_id());
+ }
+
+ lvl = &system_state->system_level[index];
+
+ ret = lpm_set_l2_mode(system_state, lvl->l2_mode);
+
+ if (ret && ret != -ENXIO) {
+ pr_warn("%s(): Cannot set L2 Mode %d, ret:%d\n",
+ __func__, lvl->l2_mode, ret);
+ goto bail_system_sleep;
+ }
+
+ if (lvl->notify_rpm) {
+ ret = msm_rpm_enter_sleep(dbg_mask, nextcpu);
if (ret) {
- pr_warn("%s(): RPM failed to enter sleep err:%d\n",
- __func__, ret);
- goto bail;
+ pr_err("rpm_enter_sleep() failed with rc = %d\n", ret);
+ goto bail_system_sleep;
}
- msm_mpm_enter_sleep(sclk_count, from_idle);
+
+ if (!from_idle)
+ us = USEC_PER_SEC * msm_pm_sleep_time_override;
+
+ do_div(us, USEC_PER_SEC/SCLK_HZ);
+ sclk = (uint32_t)us;
+ msm_mpm_enter_sleep(sclk, from_idle, nextcpu);
}
-bail:
- return ret;
-}
-
-static void msm_lpm_exit_sleep(void *limits, bool from_idle,
- bool notify_rpm, bool collapsed)
-{
-
- msm_lpm_set_l2_mode(default_l2_mode);
-
- if (notify_rpm) {
- msm_mpm_exit_sleep(from_idle);
- msm_rpm_exit_sleep();
- }
-}
-
-void msm_lpm_show_resources(void)
-{
- /* TODO */
+ system_state->last_entered_cluster_index = index;
+ spin_unlock(&system_state->sync_lock);
return;
+
+bail_system_sleep:
+ if (default_l2_mode != system_state->system_level[index].l2_mode)
+ lpm_set_l2_mode(system_state, default_l2_mode);
+ spin_unlock(&system_state->sync_lock);
+}
+
+static void lpm_system_unprepare(struct lpm_system_state *system_state,
+ int cpu_index, bool from_idle)
+{
+ int index, i;
+ struct lpm_cpu_level *cpu_level = &system_state->cpu_level[cpu_index];
+ bool first_core_up;
+
+ if (cpu_level->mode < system_state->sync_cpu_mode)
+ return;
+
+ spin_lock(&system_state->sync_lock);
+
+ first_core_up = (system_state->num_cores_in_sync == num_powered_cores);
+
+ system_state->num_cores_in_sync--;
+
+ if (!system_state->system_level)
+ goto unlock_and_return;
+
+ index = system_state->last_entered_cluster_index;
+
+ for (i = 0; i < system_state->num_system_levels; i++) {
+ struct lpm_system_level *system_lvl
+ = &system_state->system_level[i];
+ if (cpu_level->mode >= system_lvl->min_cpu_mode)
+ system_lvl->num_cpu_votes--;
+ }
+
+ if (!first_core_up)
+ goto unlock_and_return;
+
+ if (default_l2_mode != system_state->system_level[index].l2_mode)
+ lpm_set_l2_mode(system_state, default_l2_mode);
+
+ if (system_state->system_level[index].notify_rpm) {
+ msm_rpm_exit_sleep();
+ msm_mpm_exit_sleep(from_idle);
+ }
+unlock_and_return:
+ spin_unlock(&system_state->sync_lock);
}
s32 msm_cpuidle_get_deep_idle_latency(void)
{
int i;
- struct msm_rpmrs_level *level = msm_lpm_levels, *best = level;
+ struct lpm_cpu_level *level = sys_state.cpu_level;
if (!level)
return 0;
- for (i = 0; i < msm_lpm_level_count; i++, level++) {
- if (!level->available)
- continue;
- if (level->sleep_mode != MSM_PM_SLEEP_MODE_POWER_COLLAPSE)
- continue;
- /* Pick the first power collapse mode by default */
- if (best->sleep_mode != MSM_PM_SLEEP_MODE_POWER_COLLAPSE)
- best = level;
- /* Find the lowest latency for power collapse */
- if (level->latency_us < best->latency_us)
- best = level;
+ for (i = 0; i < sys_state.num_cpu_levels; i++, level++) {
+ if (level->mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE)
+ break;
}
- return best->latency_us - 1;
+
+ if (i == sys_state.num_cpu_levels)
+ return 0;
+ else
+ return level->pwr.latency_us;
}
-static int msm_lpm_cpu_callback(struct notifier_block *cpu_nb,
+static int lpm_cpu_callback(struct notifier_block *cpu_nb,
unsigned long action, void *hcpu)
{
- switch (action) {
+ switch (action & ~CPU_TASKS_FROZEN) {
case CPU_UP_PREPARE:
- case CPU_UP_PREPARE_FROZEN:
- allowed_l2_mode = default_l2_mode;
- msm_lpm_level_update();
+ ++num_powered_cores;
+ lpm_system_level_update();
break;
- case CPU_DEAD_FROZEN:
case CPU_DEAD:
case CPU_UP_CANCELED:
- case CPU_UP_CANCELED_FROZEN:
- if (num_online_cpus() == 1)
- allowed_l2_mode = MSM_SPM_L2_MODE_POWER_COLLAPSE;
- msm_lpm_level_update();
+ num_powered_cores = num_online_cpus();
+ lpm_system_level_update();
+ break;
+ case CPU_ONLINE:
+ smp_call_function_single((unsigned long)hcpu,
+ setup_broadcast_timer, (void *)true, 1);
+ break;
+ default:
break;
}
return NOTIFY_OK;
}
-static void *msm_lpm_lowest_limits(bool from_idle,
- enum msm_pm_sleep_mode sleep_mode,
- struct msm_pm_time_params *time_param, uint32_t *power)
+static enum hrtimer_restart lpm_hrtimer_cb(struct hrtimer *h)
{
- unsigned int cpu = smp_processor_id();
- struct msm_rpmrs_level *best_level = NULL;
- uint32_t best_level_pwr = 0;
- uint32_t pwr;
+ return HRTIMER_NORESTART;
+}
+
+static void msm_pm_set_timer(uint32_t modified_time_us)
+{
+ u64 modified_time_ns = modified_time_us * NSEC_PER_USEC;
+ ktime_t modified_ktime = ns_to_ktime(modified_time_ns);
+ lpm_hrtimer.function = lpm_hrtimer_cb;
+ hrtimer_start(&lpm_hrtimer, modified_ktime, HRTIMER_MODE_REL_PINNED);
+}
+
+static noinline int lpm_cpu_power_select(struct cpuidle_device *dev, int *index)
+{
+ int best_level = -1;
+ uint32_t best_level_pwr = ~0UL;
+ uint32_t latency_us = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
+ uint32_t sleep_us =
+ (uint32_t)(ktime_to_us(tick_nohz_get_sleep_length()));
+ uint32_t modified_time_us = 0;
+ uint32_t next_event_us = 0;
+ uint32_t power;
int i;
- bool modify_event_timer;
- uint32_t next_wakeup_us = time_param->sleep_us;
- uint32_t lvl_latency_us = 0;
- uint32_t lvl_overhead_us = 0;
- uint32_t lvl_overhead_energy = 0;
- if (!msm_lpm_levels)
- return NULL;
+ if (!sys_state.cpu_level)
+ return -EINVAL;
- for (i = 0; i < msm_lpm_level_count; i++) {
- struct msm_rpmrs_level *level = &msm_lpm_levels[i];
+ if (!dev->cpu)
+ next_event_us = (uint32_t)(ktime_to_us(get_next_event_time()));
- modify_event_timer = false;
+ for (i = 0; i < sys_state.num_cpu_levels; i++) {
+ struct lpm_cpu_level *level = &sys_state.cpu_level[i];
+ struct power_params *pwr = &level->pwr;
+ uint32_t next_wakeup_us = sleep_us;
+ enum msm_pm_sleep_mode mode = level->mode;
+ bool allow;
- if (!level->available)
+ if (level->sync && num_online_cpus() > 1
+ && !sys_state.allow_synched_levels)
continue;
- if (sleep_mode != level->sleep_mode)
+ allow = msm_cpu_pm_check_mode(dev->cpu, mode, true);
+
+ if (!allow)
continue;
- lvl_latency_us =
- level->latency_us + (level->latency_us *
- ADJUST_LATENCY(sleep_mode));
-
- lvl_overhead_us =
- level->time_overhead_us + (level->time_overhead_us *
- ADJUST_LATENCY(sleep_mode));
-
- lvl_overhead_energy =
- level->energy_overhead + level->energy_overhead *
- ADJUST_LATENCY(sleep_mode);
-
- if (time_param->latency_us < lvl_latency_us)
+ if (latency_us < pwr->latency_us)
continue;
- if (time_param->next_event_us &&
- time_param->next_event_us < lvl_latency_us)
- continue;
+ if (next_event_us)
+ if (next_event_us < pwr->latency_us)
+ continue;
- if (time_param->next_event_us) {
- if ((time_param->next_event_us < time_param->sleep_us)
- || ((time_param->next_event_us - lvl_latency_us) <
- time_param->sleep_us)) {
- modify_event_timer = true;
- next_wakeup_us = time_param->next_event_us -
- lvl_latency_us;
+ if (((next_event_us - pwr->latency_us) < sleep_us)
+ || (next_event_us < sleep_us)) {
+ next_wakeup_us = next_event_us
+ - pwr->latency_us;
}
- }
- if (next_wakeup_us <= lvl_overhead_us)
+ if (next_wakeup_us <= pwr->time_overhead_us)
continue;
- if ((MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE == sleep_mode)
- || (MSM_PM_SLEEP_MODE_POWER_COLLAPSE == sleep_mode))
- if (!cpu && msm_rpm_waiting_for_ack())
+ if ((MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE == mode)
+ || (MSM_PM_SLEEP_MODE_POWER_COLLAPSE == mode))
+ if (!dev->cpu && msm_rpm_waiting_for_ack())
break;
- if (next_wakeup_us <= 1) {
- pwr = lvl_overhead_energy;
- } else if (next_wakeup_us <= lvl_overhead_us) {
- pwr = lvl_overhead_energy / next_wakeup_us;
- } else if ((next_wakeup_us >> 10)
- > lvl_overhead_us) {
- pwr = level->steady_state_power;
+ if ((next_wakeup_us >> 10) > pwr->latency_us) {
+ power = pwr->ss_power;
} else {
- pwr = level->steady_state_power;
- pwr -= (lvl_overhead_us *
- level->steady_state_power) /
- next_wakeup_us;
- pwr += lvl_overhead_energy / next_wakeup_us;
+ power = pwr->ss_power;
+ power -= (pwr->latency_us * pwr->ss_power)
+ / next_wakeup_us;
+ power += pwr->energy_overhead / next_wakeup_us;
}
- if (!best_level || (best_level_pwr >= pwr)) {
- best_level = level;
- best_level_pwr = pwr;
- if (power)
- *power = pwr;
- if (modify_event_timer &&
- (sleep_mode !=
- MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT))
- time_param->modified_time_us =
- time_param->next_event_us -
- lvl_latency_us;
+ if (best_level_pwr >= power) {
+ best_level = i;
+ best_level_pwr = power;
+ if (next_event_us < sleep_us &&
+ (mode != MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT))
+ modified_time_us = next_event_us
+ - pwr->latency_us;
else
- time_param->modified_time_us = 0;
+ modified_time_us = 0;
}
}
- return best_level ? &best_level->l2_cache : NULL;
+ if (modified_time_us && !dev->cpu)
+ msm_pm_set_timer(modified_time_us);
+
+ return best_level;
}
-static struct msm_pm_sleep_ops msm_lpm_ops = {
- .lowest_limits = msm_lpm_lowest_limits,
- .enter_sleep = msm_lpm_enter_sleep,
- .exit_sleep = msm_lpm_exit_sleep,
-};
-
-static int msm_lpm_get_l2_cache_value(struct device_node *node,
- char *key, uint32_t *l2_val)
+static int lpm_get_l2_cache_value(const char *l2_str)
{
int i;
struct lpm_lookup_table l2_mode_lookup[] = {
@@ -456,24 +579,14 @@
{MSM_SPM_L2_MODE_RETENTION, "l2_cache_retention"},
{MSM_SPM_L2_MODE_DISABLED, "l2_cache_active"}
};
- const char *l2_str;
- int ret;
- ret = of_property_read_string(node, key, &l2_str);
- if (!ret) {
- ret = -EINVAL;
- for (i = 0; i < ARRAY_SIZE(l2_mode_lookup); i++) {
- if (!strcmp(l2_str, l2_mode_lookup[i].mode_name)) {
- *l2_val = l2_mode_lookup[i].modes;
- ret = 0;
- break;
- }
- }
- }
- return ret;
+ for (i = 0; i < ARRAY_SIZE(l2_mode_lookup); i++)
+ if (!strcmp(l2_str, l2_mode_lookup[i].mode_name))
+ return l2_mode_lookup[i].modes;
+ return -EINVAL;
}
-static int __devinit msm_lpm_levels_sysfs_add(void)
+static int lpm_levels_sysfs_add(void)
{
struct kobject *module_kobj = NULL;
struct kobject *low_power_kobj = NULL;
@@ -500,126 +613,548 @@
if (rc) {
if (low_power_kobj) {
sysfs_remove_group(low_power_kobj,
- &lpm_levels_attr_grp);
+ &lpm_levels_attr_grp);
kobject_del(low_power_kobj);
}
}
return rc;
}
-
-static int __devinit msm_lpm_levels_probe(struct platform_device *pdev)
+static int lpm_cpu_menu_select(struct cpuidle_device *dev, int *index)
{
- struct msm_rpmrs_level *levels = NULL;
- struct msm_rpmrs_level *level = NULL;
+ int j;
+
+ for (; *index >= 0; (*index)--) {
+ int mode = 0;
+ bool allow = false;
+
+ allow = msm_cpu_pm_check_mode(dev->cpu, mode, true);
+
+ if (!allow)
+ continue;
+
+ for (j = sys_state.num_cpu_levels; j >= 0; j--) {
+ struct lpm_cpu_level *l = &sys_state.cpu_level[j];
+ if (mode == l->mode)
+ return j;
+ }
+ }
+ return -EPERM;
+}
+
+static inline void lpm_cpu_prepare(struct lpm_system_state *system_state,
+ int cpu_index, bool from_idle)
+{
+ struct lpm_cpu_level *cpu_level = &system_state->cpu_level[cpu_index];
+ unsigned int cpu = smp_processor_id();
+
+ /* Use broadcast timer for aggregating sleep mode within a cluster.
+ * A broadcast timer could be used because of harware restriction or
+ * to ensure that we BC timer is used incase a cpu mode could trigger
+ * a cluster level sleep
+ */
+ if (from_idle && (cpu_level->use_bc_timer ||
+ (cpu_level->mode >= system_state->sync_cpu_mode)))
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu);
+}
+
+static inline void lpm_cpu_unprepare(struct lpm_system_state *system_state,
+ int cpu_index, bool from_idle)
+{
+ struct lpm_cpu_level *cpu_level = &system_state->cpu_level[cpu_index];
+ unsigned int cpu = smp_processor_id();
+
+ if (from_idle && (cpu_level->use_bc_timer ||
+ (cpu_level->mode >= system_state->sync_cpu_mode)))
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu);
+}
+
+static int lpm_system_select(struct lpm_system_state *system_state,
+ int cpu_index, bool from_idle)
+{
+ uint64_t us = (~0ULL);
+ struct clock_event_device *ed;
+ struct lpm_cpu_level *cpu_level = &system_state->cpu_level[cpu_index];
+ int i;
+ bool last_core_down;
+
+ if (cpu_level->mode < system_state->sync_cpu_mode)
+ return -EINVAL;
+
+ spin_lock(&system_state->sync_lock);
+
+ last_core_down =
+ (++system_state->num_cores_in_sync == num_powered_cores);
+
+ if (!system_state->system_level) {
+ spin_unlock(&system_state->sync_lock);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < system_state->num_system_levels; i++) {
+ struct lpm_system_level *system_lvl =
+ &system_state->system_level[i];
+ if (cpu_level->mode >= system_lvl->min_cpu_mode)
+ system_lvl->num_cpu_votes++;
+ }
+ spin_unlock(&system_state->sync_lock);
+
+ if (!last_core_down)
+ return -EBUSY;
+
+ ed = tick_get_broadcast_device()->evtdev;
+ if (!ed)
+ return -EINVAL;
+
+ if (from_idle)
+ us = ktime_to_us(ktime_sub(ed->next_event, ktime_get()));
+ else
+ us = (~0ULL);
+
+ return lpm_system_mode_select(system_state, (uint32_t)(us), from_idle);
+}
+
+static void lpm_enter_low_power(struct lpm_system_state *system_state,
+ int cpu_index, bool from_idle)
+{
+ int idx;
+ struct lpm_cpu_level *cpu_level = &system_state->cpu_level[cpu_index];
+
+ cpu_level = &system_state->cpu_level[cpu_index];
+
+ lpm_cpu_prepare(system_state, cpu_index, from_idle);
+
+ idx = lpm_system_select(system_state, cpu_index, from_idle);
+
+ if (idx >= 0)
+ lpm_system_prepare(system_state, idx, from_idle);
+
+ msm_cpu_pm_enter_sleep(cpu_level->mode, from_idle);
+
+ lpm_system_unprepare(system_state, cpu_index, from_idle);
+
+ lpm_cpu_unprepare(system_state, cpu_index, from_idle);
+}
+
+static int lpm_cpuidle_enter(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index)
+{
+ int64_t time = ktime_to_ns(ktime_get());
+ int idx;
+
+ idx = menu_select ? lpm_cpu_menu_select(dev, &index) :
+ lpm_cpu_power_select(dev, &index);
+ if (idx < 0) {
+ local_irq_enable();
+ return -EPERM;
+ }
+
+ lpm_enter_low_power(&sys_state, idx, true);
+
+ time = ktime_to_ns(ktime_get()) - time;
+ do_div(time, 1000);
+ dev->last_residency = (int)time;
+ local_irq_enable();
+ return index;
+}
+
+static int lpm_suspend_enter(suspend_state_t state)
+{
+ int i;
+
+ for (i = sys_state.num_cpu_levels - 1; i >= 0; i--) {
+ bool allow = msm_cpu_pm_check_mode(smp_processor_id(),
+ sys_state.cpu_level[i].mode, false);
+ if (allow)
+ break;
+ }
+
+ if (i < 0)
+ return -EINVAL;
+
+ lpm_enter_low_power(&sys_state, i, false);
+
+ return 0;
+}
+
+static int lpm_suspend_prepare(void)
+{
+ suspend_in_progress = true;
+ msm_mpm_suspend_prepare();
+ return 0;
+}
+
+static void lpm_suspend_wake(void)
+{
+ msm_mpm_suspend_wake();
+ suspend_in_progress = false;
+}
+
+static struct platform_device lpm_dev = {
+ .name = "msm_pm",
+ .id = -1,
+};
+
+static const struct platform_suspend_ops lpm_suspend_ops = {
+ .enter = lpm_suspend_enter,
+ .valid = suspend_valid_only_mem,
+ .prepare_late = lpm_suspend_prepare,
+ .wake = lpm_suspend_wake,
+};
+
+static void setup_broadcast_timer(void *arg)
+{
+ unsigned long reason = (unsigned long)arg;
+ int cpu = smp_processor_id();
+
+ reason = reason ?
+ CLOCK_EVT_NOTIFY_BROADCAST_ON : CLOCK_EVT_NOTIFY_BROADCAST_OFF;
+
+ clockevents_notify(reason, &cpu);
+}
+
+static struct cpuidle_driver msm_cpuidle_driver = {
+ .name = "msm_idle",
+ .owner = THIS_MODULE,
+};
+
+static void lpm_cpuidle_init(void)
+{
+ int i = 0;
+ int state_count = 0;
+
+ if (!sys_state.cpu_level)
+ return;
+ BUG_ON(sys_state.num_cpu_levels > CPUIDLE_STATE_MAX);
+
+ for (i = 0; i < sys_state.num_cpu_levels; i++) {
+ struct cpuidle_state *st = &msm_cpuidle_driver.states[i];
+ struct lpm_cpu_level *cpu_level = &sys_state.cpu_level[i];
+ snprintf(st->name, CPUIDLE_NAME_LEN, "C%u\n", i);
+ snprintf(st->desc, CPUIDLE_DESC_LEN, cpu_level->name);
+ st->flags = 0;
+ st->exit_latency = cpu_level->pwr.latency_us;
+ st->power_usage = cpu_level->pwr.ss_power;
+ st->target_residency = 0;
+ st->enter = lpm_cpuidle_enter;
+ state_count++;
+ }
+ msm_cpuidle_driver.state_count = state_count;
+ msm_cpuidle_driver.safe_state_index = 0;
+
+ if (cpuidle_register(&msm_cpuidle_driver, NULL))
+ pr_err("%s(): Failed to register CPUIDLE device\n", __func__);
+}
+
+static int lpm_parse_power_params(struct device_node *node,
+ struct power_params *pwr)
+{
+ char *key;
+ int ret;
+
+ key = "qcom,latency-us";
+ ret = of_property_read_u32(node, key, &pwr->latency_us);
+ if (ret)
+ goto fail;
+
+ key = "qcom,ss-power";
+ ret = of_property_read_u32(node, key, &pwr->ss_power);
+ if (ret)
+ goto fail;
+
+ key = "qcom,energy-overhead";
+ ret = of_property_read_u32(node, key, &pwr->energy_overhead);
+ if (ret)
+ goto fail;
+
+ key = "qcom,time-overhead";
+ ret = of_property_read_u32(node, key, &pwr->time_overhead_us);
+ if (ret)
+ goto fail;
+fail:
+ if (ret)
+ pr_err("%s(): Error reading %s\n", __func__, key);
+ return ret;
+}
+
+static int lpm_cpu_probe(struct platform_device *pdev)
+{
+ struct lpm_cpu_level *level = NULL, *l;
struct device_node *node = NULL;
- char *key = NULL;
- uint32_t val = 0;
- int ret = 0;
- uint32_t num_levels = 0;
- int idx = 0;
+ int num_levels = 0;
+ char *key;
+ int ret;
for_each_child_of_node(pdev->dev.of_node, node)
num_levels++;
- levels = kzalloc(num_levels * sizeof(struct msm_rpmrs_level),
+ level = kzalloc(num_levels * sizeof(struct lpm_cpu_level),
GFP_KERNEL);
- if (!levels)
+
+ if (!level)
return -ENOMEM;
+ l = &level[0];
for_each_child_of_node(pdev->dev.of_node, node) {
- level = &levels[idx++];
- level->available = false;
key = "qcom,mode";
- ret = msm_pm_get_sleep_mode_value(node, key, &val);
- if (ret)
+ ret = of_property_read_string(node, key, &l->name);
+
+ if (ret) {
+ pr_err("%s(): Cannot read cpu mode%s\n", __func__, key);
goto fail;
- level->sleep_mode = val;
+ }
+
+ l->mode = msm_pm_get_sleep_mode_value(l->name);
+
+ if (l->mode < 0) {
+ pr_err("%s():Cannot parse cpu mode:%s\n", __func__,
+ l->name);
+ goto fail;
+ }
+
+ if (l->mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE)
+ l->sync = true;
+
+ key = "qcom,use-broadcast-timer";
+ l->use_bc_timer = of_property_read_bool(node, key);
+
+ ret = lpm_parse_power_params(node, &l->pwr);
+ if (ret) {
+ pr_err("%s(): cannot Parse power params\n", __func__);
+ goto fail;
+ }
+ l++;
+ }
+ sys_state.cpu_level = level;
+ sys_state.num_cpu_levels = num_levels;
+ return ret;
+fail:
+ kfree(level);
+ return ret;
+}
+
+static int lpm_system_probe(struct platform_device *pdev)
+{
+ struct lpm_system_level *level = NULL, *l;
+ int num_levels = 0;
+ struct device_node *node;
+ char *key;
+ int ret;
+
+ for_each_child_of_node(pdev->dev.of_node, node)
+ num_levels++;
+
+ level = kzalloc(num_levels * sizeof(struct lpm_system_level),
+ GFP_KERNEL);
+
+ if (!level)
+ return -ENOMEM;
+
+ l = &level[0];
+ for_each_child_of_node(pdev->dev.of_node, node) {
key = "qcom,l2";
- ret = msm_lpm_get_l2_cache_value(node, key, &val);
- if (ret)
+ ret = of_property_read_string(node, key, &l->name);
+ if (ret) {
+ pr_err("%s(): Failed to read L2 mode\n", __func__);
goto fail;
- level->l2_cache = val;
+ }
- key = "qcom,latency-us";
- ret = of_property_read_u32(node, key, &val);
- if (ret)
+ l->l2_mode = lpm_get_l2_cache_value(l->name);
+
+ if (l->l2_mode < 0) {
+ pr_err("%s(): Failed to read l2 cache mode\n",
+ __func__);
goto fail;
- level->latency_us = val;
+ }
- key = "qcom,ss-power";
- ret = of_property_read_u32(node, key, &val);
- if (ret)
+ if (l->l2_mode == MSM_SPM_L2_MODE_GDHS ||
+ l->l2_mode == MSM_SPM_L2_MODE_POWER_COLLAPSE)
+ l->notify_rpm = true;
+
+ if (l->l2_mode >= MSM_SPM_L2_MODE_GDHS)
+ l->sync = true;
+
+ ret = lpm_parse_power_params(node, &l->pwr);
+ if (ret) {
+ pr_err("%s(): Failed to parse power params\n",
+ __func__);
goto fail;
- level->steady_state_power = val;
+ }
- key = "qcom,energy-overhead";
- ret = of_property_read_u32(node, key, &val);
- if (ret)
- goto fail;
- level->energy_overhead = val;
+ key = "qcom,sync-cpus";
+ l->sync = of_property_read_bool(node, key);
- key = "qcom,time-overhead";
- ret = of_property_read_u32(node, key, &val);
- if (ret)
- goto fail;
- level->time_overhead_us = val;
+ if (l->sync) {
+ const char *name;
- level->available = true;
+ key = "qcom,min-cpu-mode";
+ ret = of_property_read_string(node, key, &name);
+ if (ret) {
+ pr_err("%s(): Required key %snot found\n",
+ __func__, name);
+ goto fail;
+ }
+
+ l->min_cpu_mode = msm_pm_get_sleep_mode_value(name);
+
+ if (l->min_cpu_mode < 0) {
+ pr_err("%s(): Cannot parse cpu mode:%s\n",
+ __func__, name);
+ goto fail;
+ }
+
+ if (l->min_cpu_mode < sys_state.sync_cpu_mode)
+ sys_state.sync_cpu_mode = l->min_cpu_mode;
+ }
+
+ l++;
}
+ sys_state.system_level = level;
+ sys_state.num_system_levels = num_levels;
+ return ret;
+fail:
+ kfree(level);
+ return ret;
+}
+
+static int lpm_probe(struct platform_device *pdev)
+{
+ struct device_node *node = NULL;
+ char *key = NULL;
+ int ret;
node = pdev->dev.of_node;
+
+ key = "qcom,allow-synced-levels";
+ sys_state.allow_synched_levels = of_property_read_bool(node, key);
+
key = "qcom,no-l2-saw";
- no_l2_saw = of_property_read_bool(node, key);
+ sys_state.no_l2_saw = of_property_read_bool(node, key);
- msm_lpm_levels = levels;
- msm_lpm_level_count = idx;
+ sys_state.sync_cpu_mode = MSM_PM_SLEEP_MODE_NR;
+ spin_lock_init(&sys_state.sync_lock);
+ sys_state.num_cores_in_sync = 0;
- if (num_online_cpus() == 1)
- allowed_l2_mode = MSM_SPM_L2_MODE_POWER_COLLAPSE;
+ ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+
+ if (ret)
+ goto fail;
/* Do the following two steps only if L2 SAW is present */
- if (!no_l2_saw) {
- key = "qcom,default-l2-state";
- if (msm_lpm_get_l2_cache_value(node, key, &default_l2_mode))
- goto fail;
+ num_powered_cores = num_online_cpus();
- if (msm_lpm_levels_sysfs_add())
+ if (!sys_state.no_l2_saw) {
+ int ret;
+ const char *l2;
+ key = "qcom,default-l2-state";
+ ret = of_property_read_string(node, key, &l2);
+ if (ret) {
+ pr_err("%s(): Failed to read default L2 mode\n",
+ __func__);
goto fail;
- register_hotcpu_notifier(&msm_lpm_cpu_nblk);
- msm_pm_set_l2_flush_flag(0);
+ }
+
+ default_l2_mode = lpm_get_l2_cache_value(l2);
+ if (default_l2_mode < 0) {
+ pr_err("%s(): Unable to parse default L2 mode\n",
+ __func__);
+ goto fail;
+ }
+
+ if (lpm_levels_sysfs_add())
+ goto fail;
+ msm_pm_set_l2_flush_flag(MSM_SCM_L2_ON);
} else {
- msm_pm_set_l2_flush_flag(1);
+ msm_pm_set_l2_flush_flag(MSM_SCM_L2_OFF);
default_l2_mode = MSM_SPM_L2_MODE_POWER_COLLAPSE;
}
- msm_lpm_level_update();
- msm_pm_set_sleep_ops(&msm_lpm_ops);
+ get_cpu();
+ on_each_cpu(setup_broadcast_timer, (void *)true, 1);
+ put_cpu();
+
+ register_hotcpu_notifier(&lpm_cpu_nblk);
+
+ lpm_system_level_update();
+ platform_device_register(&lpm_dev);
+ suspend_set_ops(&lpm_suspend_ops);
+ hrtimer_init(&lpm_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ lpm_cpuidle_init();
return 0;
fail:
pr_err("%s: Error in name %s key %s\n", __func__, node->full_name, key);
- kfree(levels);
return -EFAULT;
}
-static struct of_device_id msm_lpm_levels_match_table[] = {
+static struct of_device_id cpu_modes_mtch_tbl[] = {
+ {.compatible = "qcom,cpu-modes"},
+ {},
+};
+
+static struct platform_driver cpu_modes_driver = {
+ .probe = lpm_cpu_probe,
+ .driver = {
+ .name = "cpu-modes",
+ .owner = THIS_MODULE,
+ .of_match_table = cpu_modes_mtch_tbl,
+ },
+};
+
+static struct of_device_id system_modes_mtch_tbl[] = {
+ {.compatible = "qcom,system-modes"},
+ {},
+};
+
+static struct platform_driver system_modes_driver = {
+ .probe = lpm_system_probe,
+ .driver = {
+ .name = "system-modes",
+ .owner = THIS_MODULE,
+ .of_match_table = system_modes_mtch_tbl,
+ },
+};
+
+static struct of_device_id lpm_levels_match_table[] = {
{.compatible = "qcom,lpm-levels"},
{},
};
-static struct platform_driver msm_lpm_levels_driver = {
- .probe = msm_lpm_levels_probe,
+static struct platform_driver lpm_levels_driver = {
+ .probe = lpm_probe,
.driver = {
.name = "lpm-levels",
.owner = THIS_MODULE,
- .of_match_table = msm_lpm_levels_match_table,
+ .of_match_table = lpm_levels_match_table,
},
};
-static int __init msm_lpm_levels_module_init(void)
+static int __init lpm_levels_module_init(void)
{
- return platform_driver_register(&msm_lpm_levels_driver);
+ int rc;
+ rc = platform_driver_register(&cpu_modes_driver);
+ if (rc) {
+ pr_err("Error registering %s\n", cpu_modes_driver.driver.name);
+ goto fail;
+ }
+
+ rc = platform_driver_register(&system_modes_driver);
+ if (rc) {
+ platform_driver_unregister(&cpu_modes_driver);
+ pr_err("Error registering %s\n",
+ system_modes_driver.driver.name);
+ goto fail;
+ }
+
+ rc = platform_driver_register(&lpm_levels_driver);
+ if (rc) {
+ platform_driver_unregister(&cpu_modes_driver);
+ platform_driver_unregister(&system_modes_driver);
+ pr_err("Error registering %s\n",
+ lpm_levels_driver.driver.name);
+ }
+fail:
+ return rc;
}
-late_initcall(msm_lpm_levels_module_init);
+late_initcall(lpm_levels_module_init);
diff --git a/arch/arm/mach-msm/mpm-of.c b/arch/arm/mach-msm/mpm-of.c
index e364393..5b351b4 100644
--- a/arch/arm/mach-msm/mpm-of.c
+++ b/arch/arm/mach-msm/mpm-of.c
@@ -505,7 +505,9 @@
return msm_mpm_interrupts_detectable(MSM_MPM_GIC_IRQ_DOMAIN,
from_idle);
}
-void msm_mpm_enter_sleep(uint32_t sclk_count, bool from_idle)
+
+void msm_mpm_enter_sleep(uint32_t sclk_count, bool from_idle,
+ const struct cpumask *cpumask)
{
cycle_t wakeup = (u64)sclk_count * ARCH_TIMER_HZ;
@@ -522,6 +524,7 @@
}
msm_mpm_set(wakeup, !from_idle);
+ irq_set_affinity(msm_mpm_dev_data.mpm_ipc_irq, cpumask);
}
void msm_mpm_exit_sleep(bool from_idle)
diff --git a/arch/arm/mach-msm/msm-pm.c b/arch/arm/mach-msm/msm-pm.c
new file mode 100644
index 0000000..fab86d3
--- /dev/null
+++ b/arch/arm/mach-msm/msm-pm.c
@@ -0,0 +1,1247 @@
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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/debugfs.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/io.h>
+#include <linux/ktime.h>
+#include <linux/smp.h>
+#include <linux/tick.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/cpu_pm.h>
+#include <asm/uaccess.h>
+#include <asm/suspend.h>
+#include <asm/cacheflush.h>
+#include <asm/outercache.h>
+#include <mach/scm.h>
+#include <mach/msm_bus.h>
+#include <mach/jtag.h>
+#include "acpuclock.h"
+#include "avs.h"
+#include "idle.h"
+#include "pm.h"
+#include "scm-boot.h"
+#include "spm.h"
+#include "pm-boot.h"
+
+#define CREATE_TRACE_POINTS
+#include <mach/trace_msm_low_power.h>
+
+#define SCM_CMD_TERMINATE_PC (0x2)
+#define SCM_CMD_CORE_HOTPLUGGED (0x10)
+
+#define GET_CPU_OF_ATTR(attr) \
+ (container_of(attr, struct msm_pm_kobj_attribute, ka)->cpu)
+
+#define SCLK_HZ (32768)
+
+#define MAX_BUF_SIZE 512
+
+static int msm_pm_debug_mask = 1;
+module_param_named(
+ debug_mask, msm_pm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
+);
+
+static bool use_acpuclk_apis;
+
+enum {
+ MSM_PM_DEBUG_SUSPEND = BIT(0),
+ MSM_PM_DEBUG_POWER_COLLAPSE = BIT(1),
+ MSM_PM_DEBUG_SUSPEND_LIMITS = BIT(2),
+ MSM_PM_DEBUG_CLOCK = BIT(3),
+ MSM_PM_DEBUG_RESET_VECTOR = BIT(4),
+ MSM_PM_DEBUG_IDLE_CLK = BIT(5),
+ MSM_PM_DEBUG_IDLE = BIT(6),
+ MSM_PM_DEBUG_IDLE_LIMITS = BIT(7),
+ MSM_PM_DEBUG_HOTPLUG = BIT(8),
+};
+
+enum msm_pc_count_offsets {
+ MSM_PC_ENTRY_COUNTER,
+ MSM_PC_EXIT_COUNTER,
+ MSM_PC_FALLTHRU_COUNTER,
+ MSM_PC_NUM_COUNTERS,
+};
+
+enum {
+ MSM_PM_MODE_ATTR_SUSPEND,
+ MSM_PM_MODE_ATTR_IDLE,
+ MSM_PM_MODE_ATTR_NR,
+};
+
+static char *msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_NR] = {
+ [MSM_PM_MODE_ATTR_SUSPEND] = "suspend_enabled",
+ [MSM_PM_MODE_ATTR_IDLE] = "idle_enabled",
+};
+
+struct msm_pm_kobj_attribute {
+ unsigned int cpu;
+ struct kobj_attribute ka;
+};
+
+struct msm_pm_sysfs_sleep_mode {
+ struct kobject *kobj;
+ struct attribute_group attr_group;
+ struct attribute *attrs[MSM_PM_MODE_ATTR_NR + 1];
+ struct msm_pm_kobj_attribute kas[MSM_PM_MODE_ATTR_NR];
+};
+
+static char *msm_pm_sleep_mode_labels[MSM_PM_SLEEP_MODE_NR] = {
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = "power_collapse",
+ [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT] = "wfi",
+ [MSM_PM_SLEEP_MODE_RETENTION] = "retention",
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE] =
+ "standalone_power_collapse",
+};
+
+static bool msm_pm_ldo_retention_enabled = true;
+static bool msm_no_ramp_down_pc;
+static struct msm_pm_sleep_status_data *msm_pm_slp_sts;
+DEFINE_PER_CPU(struct clk *, cpu_clks);
+static struct clk *l2_clk;
+
+static void (*msm_pm_disable_l2_fn)(void);
+static void (*msm_pm_enable_l2_fn)(void);
+static void (*msm_pm_flush_l2_fn)(void);
+static void __iomem *msm_pc_debug_counters;
+
+/*
+ * Default the l2 flush flag to OFF so the caches are flushed during power
+ * collapse unless the explicitly voted by lpm driver.
+ */
+static enum msm_pm_l2_scm_flag msm_pm_flush_l2_flag = MSM_SCM_L2_OFF;
+
+void msm_pm_set_l2_flush_flag(enum msm_pm_l2_scm_flag flag)
+{
+ msm_pm_flush_l2_flag = flag;
+}
+EXPORT_SYMBOL(msm_pm_set_l2_flush_flag);
+
+static enum msm_pm_l2_scm_flag msm_pm_get_l2_flush_flag(void)
+{
+ return msm_pm_flush_l2_flag;
+}
+
+static cpumask_t retention_cpus;
+static DEFINE_SPINLOCK(retention_lock);
+
+static int msm_pm_get_pc_mode(struct device_node *node,
+ const char *key, uint32_t *pc_mode_val)
+{
+ struct pc_mode_of {
+ uint32_t mode;
+ char *mode_name;
+ };
+ int i;
+ struct pc_mode_of pc_modes[] = {
+ {MSM_PM_PC_TZ_L2_INT, "tz_l2_int"},
+ {MSM_PM_PC_NOTZ_L2_EXT, "no_tz_l2_ext"},
+ {MSM_PM_PC_TZ_L2_EXT , "tz_l2_ext"} };
+ int ret;
+ const char *pc_mode_str;
+ *pc_mode_val = MSM_PM_PC_TZ_L2_INT;
+
+ ret = of_property_read_string(node, key, &pc_mode_str);
+ if (!ret) {
+ ret = -EINVAL;
+ for (i = 0; i < ARRAY_SIZE(pc_modes); i++) {
+ if (!strncmp(pc_mode_str, pc_modes[i].mode_name,
+ strlen(pc_modes[i].mode_name))) {
+ *pc_mode_val = pc_modes[i].mode;
+ ret = 0;
+ break;
+ }
+ }
+ } else {
+ pr_debug("%s: Cannot read %s,defaulting to 0", __func__, key);
+ ret = 0;
+ }
+ return ret;
+}
+
+/*
+ * Write out the attribute.
+ */
+static ssize_t msm_pm_mode_attr_show(
+ struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+ int ret = -EINVAL;
+ int i;
+
+ for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
+ struct kernel_param kp;
+ unsigned int cpu;
+ struct msm_pm_platform_data *mode;
+
+ if (msm_pm_sleep_mode_labels[i] == NULL)
+ continue;
+
+ if (strcmp(kobj->name, msm_pm_sleep_mode_labels[i]))
+ continue;
+
+ cpu = GET_CPU_OF_ATTR(attr);
+ mode = &msm_pm_sleep_modes[MSM_PM_MODE(cpu, i)];
+
+ if (!strcmp(attr->attr.name,
+ msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_SUSPEND])) {
+ u32 arg = mode->suspend_enabled;
+ kp.arg = &arg;
+ ret = param_get_ulong(buf, &kp);
+ } else if (!strcmp(attr->attr.name,
+ msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_IDLE])) {
+ u32 arg = mode->idle_enabled;
+ kp.arg = &arg;
+ ret = param_get_ulong(buf, &kp);
+ }
+
+ break;
+ }
+
+ if (ret > 0) {
+ strlcat(buf, "\n", PAGE_SIZE);
+ ret++;
+ }
+
+ return ret;
+}
+
+static ssize_t msm_pm_mode_attr_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ int ret = -EINVAL;
+ int i;
+
+ for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
+ struct kernel_param kp;
+ unsigned int cpu;
+ struct msm_pm_platform_data *mode;
+
+ if (msm_pm_sleep_mode_labels[i] == NULL)
+ continue;
+
+ if (strcmp(kobj->name, msm_pm_sleep_mode_labels[i]))
+ continue;
+
+ cpu = GET_CPU_OF_ATTR(attr);
+ mode = &msm_pm_sleep_modes[MSM_PM_MODE(cpu, i)];
+
+ if (!strcmp(attr->attr.name,
+ msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_SUSPEND])) {
+ kp.arg = &mode->suspend_enabled;
+ ret = param_set_byte(buf, &kp);
+ } else if (!strcmp(attr->attr.name,
+ msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_IDLE])) {
+ kp.arg = &mode->idle_enabled;
+ ret = param_set_byte(buf, &kp);
+ }
+
+ break;
+ }
+
+ return ret ? ret : count;
+}
+
+static int msm_pm_mode_sysfs_add_cpu(
+ unsigned int cpu, struct kobject *modes_kobj)
+{
+ char cpu_name[8];
+ struct kobject *cpu_kobj;
+ struct msm_pm_sysfs_sleep_mode *mode = NULL;
+ int i, j, k;
+ int ret;
+
+ snprintf(cpu_name, sizeof(cpu_name), "cpu%u", cpu);
+ cpu_kobj = kobject_create_and_add(cpu_name, modes_kobj);
+ if (!cpu_kobj) {
+ pr_err("%s: cannot create %s kobject\n", __func__, cpu_name);
+ ret = -ENOMEM;
+ goto mode_sysfs_add_cpu_exit;
+ }
+
+ for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
+ int idx = MSM_PM_MODE(cpu, i);
+
+ if ((!msm_pm_sleep_modes[idx].suspend_supported)
+ && (!msm_pm_sleep_modes[idx].idle_supported))
+ continue;
+
+ if (!msm_pm_sleep_mode_labels[i] ||
+ !msm_pm_sleep_mode_labels[i][0])
+ continue;
+
+ mode = kzalloc(sizeof(*mode), GFP_KERNEL);
+ if (!mode) {
+ pr_err("%s: cannot allocate memory for attributes\n",
+ __func__);
+ ret = -ENOMEM;
+ goto mode_sysfs_add_cpu_exit;
+ }
+
+ mode->kobj = kobject_create_and_add(
+ msm_pm_sleep_mode_labels[i], cpu_kobj);
+ if (!mode->kobj) {
+ pr_err("%s: cannot create kobject\n", __func__);
+ ret = -ENOMEM;
+ goto mode_sysfs_add_cpu_exit;
+ }
+
+ for (k = 0, j = 0; k < MSM_PM_MODE_ATTR_NR; k++) {
+ if ((k == MSM_PM_MODE_ATTR_IDLE) &&
+ !msm_pm_sleep_modes[idx].idle_supported)
+ continue;
+ if ((k == MSM_PM_MODE_ATTR_SUSPEND) &&
+ !msm_pm_sleep_modes[idx].suspend_supported)
+ continue;
+ sysfs_attr_init(&mode->kas[j].ka.attr);
+ mode->kas[j].cpu = cpu;
+ mode->kas[j].ka.attr.mode = 0644;
+ mode->kas[j].ka.show = msm_pm_mode_attr_show;
+ mode->kas[j].ka.store = msm_pm_mode_attr_store;
+ mode->kas[j].ka.attr.name = msm_pm_mode_attr_labels[k];
+ mode->attrs[j] = &mode->kas[j].ka.attr;
+ j++;
+ }
+ mode->attrs[j] = NULL;
+
+ mode->attr_group.attrs = mode->attrs;
+ ret = sysfs_create_group(mode->kobj, &mode->attr_group);
+ if (ret) {
+ pr_err("%s: cannot create kobject attribute group\n",
+ __func__);
+ goto mode_sysfs_add_cpu_exit;
+ }
+ }
+
+ ret = 0;
+
+mode_sysfs_add_cpu_exit:
+ if (ret) {
+ if (mode && mode->kobj)
+ kobject_del(mode->kobj);
+ kfree(mode);
+ }
+
+ return ret;
+}
+
+int msm_pm_mode_sysfs_add(void)
+{
+ struct kobject *module_kobj;
+ struct kobject *modes_kobj;
+ unsigned int cpu;
+ int ret;
+
+ module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
+ if (!module_kobj) {
+ pr_err("%s: cannot find kobject for module %s\n",
+ __func__, KBUILD_MODNAME);
+ ret = -ENOENT;
+ goto mode_sysfs_add_exit;
+ }
+
+ modes_kobj = kobject_create_and_add("modes", module_kobj);
+ if (!modes_kobj) {
+ pr_err("%s: cannot create modes kobject\n", __func__);
+ ret = -ENOMEM;
+ goto mode_sysfs_add_exit;
+ }
+
+ for_each_possible_cpu(cpu) {
+ ret = msm_pm_mode_sysfs_add_cpu(cpu, modes_kobj);
+ if (ret)
+ goto mode_sysfs_add_exit;
+ }
+
+ ret = 0;
+
+mode_sysfs_add_exit:
+ return ret;
+}
+
+static inline void msm_arch_idle(void)
+{
+ mb();
+ wfi();
+}
+
+static bool msm_pm_is_L1_writeback(void)
+{
+ u32 sel = 0, cache_id;
+
+ asm volatile ("mcr p15, 2, %[ccselr], c0, c0, 0\n\t"
+ "isb\n\t"
+ "mrc p15, 1, %[ccsidr], c0, c0, 0\n\t"
+ :[ccsidr]"=r" (cache_id)
+ :[ccselr]"r" (sel)
+ );
+ return cache_id & BIT(31);
+}
+
+static enum msm_pm_time_stats_id msm_pm_swfi(bool from_idle)
+{
+ msm_arch_idle();
+ return MSM_PM_STAT_IDLE_WFI;
+}
+
+static enum msm_pm_time_stats_id msm_pm_retention(bool from_idle)
+{
+ int ret = 0;
+ int cpu = smp_processor_id();
+ int saved_rate = 0;
+ struct clk *cpu_clk = per_cpu(cpu_clks, cpu);
+
+ spin_lock(&retention_lock);
+
+ if (!msm_pm_ldo_retention_enabled)
+ goto bailout;
+
+ cpumask_set_cpu(cpu, &retention_cpus);
+ spin_unlock(&retention_lock);
+
+ if (use_acpuclk_apis)
+ saved_rate = acpuclk_power_collapse();
+ else
+ clk_disable(cpu_clk);
+
+ ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_POWER_RETENTION, false);
+ WARN_ON(ret);
+
+ msm_arch_idle();
+
+ if (use_acpuclk_apis) {
+ if (acpuclk_set_rate(cpu, saved_rate, SETRATE_PC))
+ pr_err("%s(): Error setting acpuclk_set_rate\n",
+ __func__);
+ } else {
+ if (clk_enable(cpu_clk))
+ pr_err("%s(): Error restoring cpu clk\n", __func__);
+ }
+
+ spin_lock(&retention_lock);
+ cpumask_clear_cpu(cpu, &retention_cpus);
+bailout:
+ spin_unlock(&retention_lock);
+
+ ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
+ WARN_ON(ret);
+
+ return MSM_PM_STAT_RETENTION;
+}
+
+static inline void msm_pc_inc_debug_count(uint32_t cpu,
+ enum msm_pc_count_offsets offset)
+{
+ uint32_t cnt;
+
+ if (!msm_pc_debug_counters)
+ return;
+
+ cnt = readl_relaxed(msm_pc_debug_counters + cpu * 4 + offset * 4);
+ writel_relaxed(++cnt, msm_pc_debug_counters + cpu * 4 + offset * 4);
+ mb();
+}
+
+static bool msm_pm_pc_hotplug(void)
+{
+ uint32_t cpu = smp_processor_id();
+
+ if (msm_pm_is_L1_writeback())
+ flush_cache_louis();
+
+ msm_pc_inc_debug_count(cpu, MSM_PC_ENTRY_COUNTER);
+
+ scm_call_atomic1(SCM_SVC_BOOT, SCM_CMD_TERMINATE_PC,
+ SCM_CMD_CORE_HOTPLUGGED);
+
+ /* Should not return here */
+ msm_pc_inc_debug_count(cpu, MSM_PC_FALLTHRU_COUNTER);
+ return 0;
+}
+
+static int msm_pm_collapse(unsigned long unused)
+{
+ uint32_t cpu = smp_processor_id();
+
+ if (msm_pm_get_l2_flush_flag() == MSM_SCM_L2_OFF) {
+ flush_cache_all();
+ if (msm_pm_flush_l2_fn)
+ msm_pm_flush_l2_fn();
+ } else if (msm_pm_is_L1_writeback())
+ flush_cache_louis();
+
+ if (msm_pm_disable_l2_fn)
+ msm_pm_disable_l2_fn();
+
+ msm_pc_inc_debug_count(cpu, MSM_PC_ENTRY_COUNTER);
+
+ scm_call_atomic1(SCM_SVC_BOOT, SCM_CMD_TERMINATE_PC,
+ msm_pm_get_l2_flush_flag());
+
+ msm_pc_inc_debug_count(cpu, MSM_PC_FALLTHRU_COUNTER);
+
+ if (msm_pm_enable_l2_fn)
+ msm_pm_enable_l2_fn();
+
+ return 0;
+}
+
+static bool __ref msm_pm_spm_power_collapse(
+ unsigned int cpu, bool from_idle, bool notify_rpm)
+{
+ void *entry;
+ bool collapsed = 0;
+ int ret;
+ bool save_cpu_regs = !cpu || from_idle;
+
+ if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
+ pr_info("CPU%u: %s: notify_rpm %d\n",
+ cpu, __func__, (int) notify_rpm);
+
+ if (from_idle)
+ cpu_pm_enter();
+
+ ret = msm_spm_set_low_power_mode(
+ MSM_SPM_MODE_POWER_COLLAPSE, notify_rpm);
+ WARN_ON(ret);
+
+ entry = save_cpu_regs ? cpu_resume : msm_secondary_startup;
+
+ msm_pm_boot_config_before_pc(cpu, virt_to_phys(entry));
+
+ if (MSM_PM_DEBUG_RESET_VECTOR & msm_pm_debug_mask)
+ pr_info("CPU%u: %s: program vector to %p\n",
+ cpu, __func__, entry);
+
+ msm_jtag_save_state();
+
+ collapsed = save_cpu_regs ?
+ !cpu_suspend(0, msm_pm_collapse) : msm_pm_pc_hotplug();
+
+ msm_jtag_restore_state();
+
+ if (collapsed) {
+ cpu_init();
+ local_fiq_enable();
+ }
+
+ msm_pm_boot_config_after_pc(cpu);
+
+ if (from_idle)
+ cpu_pm_exit();
+
+ if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
+ pr_info("CPU%u: %s: msm_pm_collapse returned, collapsed %d\n",
+ cpu, __func__, collapsed);
+
+ ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
+ WARN_ON(ret);
+ return collapsed;
+}
+
+static enum msm_pm_time_stats_id msm_pm_power_collapse_standalone(
+ bool from_idle)
+{
+ unsigned int cpu = smp_processor_id();
+ unsigned int avsdscr;
+ unsigned int avscsr;
+ bool collapsed;
+
+ avsdscr = avs_get_avsdscr();
+ avscsr = avs_get_avscsr();
+ avs_set_avscsr(0); /* Disable AVS */
+
+ collapsed = msm_pm_spm_power_collapse(cpu, from_idle, false);
+
+ avs_set_avsdscr(avsdscr);
+ avs_set_avscsr(avscsr);
+ return collapsed ? MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE :
+ MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE;
+}
+
+static int ramp_down_last_cpu(int cpu)
+{
+ struct clk *cpu_clk = per_cpu(cpu_clks, cpu);
+ int ret = 0;
+
+ if (use_acpuclk_apis) {
+ ret = acpuclk_power_collapse();
+ if (MSM_PM_DEBUG_CLOCK & msm_pm_debug_mask)
+ pr_info("CPU%u: %s: change clk rate(old rate = %d)\n",
+ cpu, __func__, ret);
+ } else {
+ clk_disable(cpu_clk);
+ clk_disable(l2_clk);
+ }
+ return ret;
+}
+
+static int ramp_up_first_cpu(int cpu, int saved_rate)
+{
+ struct clk *cpu_clk = per_cpu(cpu_clks, cpu);
+ int rc = 0;
+
+ if (MSM_PM_DEBUG_CLOCK & msm_pm_debug_mask)
+ pr_info("CPU%u: %s: restore clock rate\n",
+ cpu, __func__);
+
+ if (use_acpuclk_apis) {
+ rc = acpuclk_set_rate(cpu, saved_rate, SETRATE_PC);
+ if (rc)
+ pr_err("CPU:%u: Error restoring cpu clk\n", cpu);
+ } else {
+ if (l2_clk) {
+ rc = clk_enable(l2_clk);
+ if (rc)
+ pr_err("%s(): Error restoring l2 clk\n",
+ __func__);
+ }
+
+ if (cpu_clk) {
+ int ret = clk_enable(cpu_clk);
+
+ if (ret) {
+ pr_err("%s(): Error restoring cpu clk\n",
+ __func__);
+ return ret;
+ }
+ }
+ }
+
+ return rc;
+}
+
+static enum msm_pm_time_stats_id msm_pm_power_collapse(bool from_idle)
+{
+ unsigned int cpu = smp_processor_id();
+ unsigned long saved_acpuclk_rate = 0;
+ unsigned int avsdscr;
+ unsigned int avscsr;
+ bool collapsed;
+
+ if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
+ pr_info("CPU%u: %s: idle %d\n",
+ cpu, __func__, (int)from_idle);
+
+ if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
+ pr_info("CPU%u: %s: pre power down\n", cpu, __func__);
+
+ avsdscr = avs_get_avsdscr();
+ avscsr = avs_get_avscsr();
+ avs_set_avscsr(0); /* Disable AVS */
+
+ if (cpu_online(cpu) && !msm_no_ramp_down_pc)
+ saved_acpuclk_rate = ramp_down_last_cpu(cpu);
+
+ collapsed = msm_pm_spm_power_collapse(cpu, from_idle, true);
+
+ if (cpu_online(cpu) && !msm_no_ramp_down_pc)
+ ramp_up_first_cpu(cpu, saved_acpuclk_rate);
+
+ avs_set_avsdscr(avsdscr);
+ avs_set_avscsr(avscsr);
+
+ if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
+ pr_info("CPU%u: %s: post power up\n", cpu, __func__);
+
+ if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
+ pr_info("CPU%u: %s: return\n", cpu, __func__);
+ return collapsed ? MSM_PM_STAT_IDLE_POWER_COLLAPSE :
+ MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE;
+}
+/******************************************************************************
+ * External Idle/Suspend Functions
+ *****************************************************************************/
+
+void arch_idle(void)
+{
+ return;
+}
+
+static inline void msm_pm_ftrace_lpm_enter(unsigned int cpu,
+ uint32_t latency, uint32_t sleep_us,
+ uint32_t wake_up,
+ enum msm_pm_sleep_mode mode)
+{
+ switch (mode) {
+ case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
+ trace_msm_pm_enter_wfi(cpu, latency, sleep_us, wake_up);
+ break;
+ case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
+ trace_msm_pm_enter_spc(cpu, latency, sleep_us, wake_up);
+ break;
+ case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
+ trace_msm_pm_enter_pc(cpu, latency, sleep_us, wake_up);
+ break;
+ case MSM_PM_SLEEP_MODE_RETENTION:
+ trace_msm_pm_enter_ret(cpu, latency, sleep_us, wake_up);
+ break;
+ default:
+ break;
+ }
+}
+
+static inline void msm_pm_ftrace_lpm_exit(unsigned int cpu,
+ enum msm_pm_sleep_mode mode,
+ bool success)
+{
+ switch (mode) {
+ case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
+ trace_msm_pm_exit_wfi(cpu, success);
+ break;
+ case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
+ trace_msm_pm_exit_spc(cpu, success);
+ break;
+ case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
+ trace_msm_pm_exit_pc(cpu, success);
+ break;
+ case MSM_PM_SLEEP_MODE_RETENTION:
+ trace_msm_pm_exit_ret(cpu, success);
+ break;
+ default:
+ break;
+ }
+}
+
+static enum msm_pm_time_stats_id (*execute[MSM_PM_SLEEP_MODE_NR])(bool idle) = {
+ [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT] = msm_pm_swfi,
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE] =
+ msm_pm_power_collapse_standalone,
+ [MSM_PM_SLEEP_MODE_RETENTION] = msm_pm_retention,
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = msm_pm_power_collapse,
+};
+
+bool msm_cpu_pm_check_mode(unsigned int cpu, enum msm_pm_sleep_mode mode,
+ bool from_idle)
+{
+ int idx = MSM_PM_MODE(cpu, mode);
+ struct msm_pm_platform_data *d = &msm_pm_sleep_modes[idx];
+
+ if ((mode == MSM_PM_SLEEP_MODE_RETENTION)
+ && !msm_pm_ldo_retention_enabled)
+ return false;
+
+ if (from_idle)
+ return d->idle_enabled && d->idle_supported;
+ else
+ return d->suspend_enabled && d->suspend_supported;
+}
+
+int msm_cpu_pm_enter_sleep(enum msm_pm_sleep_mode mode, bool from_idle)
+{
+ int64_t time;
+ bool collapsed = 1;
+ int exit_stat = -1;
+
+ if (MSM_PM_DEBUG_IDLE & msm_pm_debug_mask)
+ pr_info("CPU%u: %s: mode %d\n",
+ smp_processor_id(), __func__, mode);
+ if (!from_idle)
+ pr_info("CPU%u: %s mode:%d\n",
+ smp_processor_id(), __func__, mode);
+
+ time = sched_clock();
+ if (execute[mode])
+ exit_stat = execute[mode](from_idle);
+ time = sched_clock() - time;
+ if (from_idle)
+ msm_pm_ftrace_lpm_exit(smp_processor_id(), mode, collapsed);
+ else
+ exit_stat = MSM_PM_STAT_SUSPEND;
+ if (exit_stat >= 0)
+ msm_pm_add_stat(exit_stat, time);
+ do_div(time, 1000);
+ return collapsed;
+}
+
+int msm_pm_wait_cpu_shutdown(unsigned int cpu)
+{
+ int timeout = 10;
+
+ if (!msm_pm_slp_sts)
+ return 0;
+ if (!msm_pm_slp_sts[cpu].base_addr)
+ return 0;
+ while (timeout--) {
+ /*
+ * Check for the SPM of the core being hotplugged to set
+ * its sleep state.The SPM sleep state indicates that the
+ * core has been power collapsed.
+ */
+ int acc_sts = __raw_readl(msm_pm_slp_sts[cpu].base_addr);
+
+ if (acc_sts & msm_pm_slp_sts[cpu].mask)
+ return 0;
+ udelay(100);
+ }
+
+ pr_info("%s(): Timed out waiting for CPU %u SPM to enter sleep state",
+ __func__, cpu);
+ return -EBUSY;
+}
+
+void msm_pm_cpu_enter_lowpower(unsigned int cpu)
+{
+ int i;
+ bool allow[MSM_PM_SLEEP_MODE_NR];
+
+ for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
+ struct msm_pm_platform_data *mode;
+
+ mode = &msm_pm_sleep_modes[MSM_PM_MODE(cpu, i)];
+ allow[i] = mode->suspend_supported && mode->suspend_enabled;
+ }
+
+ if (MSM_PM_DEBUG_HOTPLUG & msm_pm_debug_mask)
+ pr_notice("CPU%u: %s: shutting down cpu\n", cpu, __func__);
+
+ if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE])
+ msm_pm_power_collapse(false);
+ else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE])
+ msm_pm_power_collapse_standalone(false);
+ else if (allow[MSM_PM_SLEEP_MODE_RETENTION])
+ msm_pm_retention(false);
+ else
+ msm_pm_swfi(false);
+}
+
+static void msm_pm_ack_retention_disable(void *data)
+{
+ /*
+ * This is a NULL function to ensure that the core has woken up
+ * and is safe to disable retention.
+ */
+}
+/**
+ * msm_pm_enable_retention() - Disable/Enable retention on all cores
+ * @enable: Enable/Disable retention
+ *
+ */
+void msm_pm_enable_retention(bool enable)
+{
+ if (enable == msm_pm_ldo_retention_enabled)
+ return;
+
+ msm_pm_ldo_retention_enabled = enable;
+
+ /*
+ * If retention is being disabled, wakeup all online core to ensure
+ * that it isn't executing retention. Offlined cores need not be woken
+ * up as they enter the deepest sleep mode, namely RPM assited power
+ * collapse
+ */
+ if (!enable) {
+ preempt_disable();
+ smp_call_function_many(&retention_cpus,
+ msm_pm_ack_retention_disable,
+ NULL, true);
+ preempt_enable();
+ }
+}
+EXPORT_SYMBOL(msm_pm_enable_retention);
+
+static int msm_pm_snoc_client_probe(struct platform_device *pdev)
+{
+ int rc = 0;
+ static struct msm_bus_scale_pdata *msm_pm_bus_pdata;
+ static uint32_t msm_pm_bus_client;
+
+ msm_pm_bus_pdata = msm_bus_cl_get_pdata(pdev);
+
+ if (msm_pm_bus_pdata) {
+ msm_pm_bus_client =
+ msm_bus_scale_register_client(msm_pm_bus_pdata);
+
+ if (!msm_pm_bus_client) {
+ pr_err("%s: Failed to register SNOC client", __func__);
+ rc = -ENXIO;
+ goto snoc_cl_probe_done;
+ }
+
+ rc = msm_bus_scale_client_update_request(msm_pm_bus_client, 1);
+
+ if (rc)
+ pr_err("%s: Error setting bus rate", __func__);
+ }
+
+snoc_cl_probe_done:
+ return rc;
+}
+
+static int msm_cpu_status_probe(struct platform_device *pdev)
+{
+ struct msm_pm_sleep_status_data *pdata;
+ char *key;
+ u32 cpu;
+
+ if (!pdev)
+ return -EFAULT;
+
+ msm_pm_slp_sts = devm_kzalloc(&pdev->dev,
+ sizeof(*msm_pm_slp_sts) * num_possible_cpus(),
+ GFP_KERNEL);
+
+ if (!msm_pm_slp_sts)
+ return -ENOMEM;
+
+ if (pdev->dev.of_node) {
+ struct resource *res;
+ u32 offset;
+ int rc;
+ u32 mask;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ key = "qcom,cpu-alias-addr";
+ rc = of_property_read_u32(pdev->dev.of_node, key, &offset);
+
+ if (rc)
+ return -ENODEV;
+
+ key = "qcom,sleep-status-mask";
+ rc = of_property_read_u32(pdev->dev.of_node, key, &mask);
+
+ if (rc)
+ return -ENODEV;
+
+ for_each_possible_cpu(cpu) {
+ phys_addr_t base_c = res->start + cpu * offset;
+ msm_pm_slp_sts[cpu].base_addr =
+ devm_ioremap(&pdev->dev, base_c,
+ resource_size(res));
+ msm_pm_slp_sts[cpu].mask = mask;
+
+ if (!msm_pm_slp_sts[cpu].base_addr)
+ return -ENOMEM;
+ }
+ } else {
+ pdata = pdev->dev.platform_data;
+ if (!pdev->dev.platform_data)
+ return -EINVAL;
+
+ for_each_possible_cpu(cpu) {
+ msm_pm_slp_sts[cpu].base_addr =
+ pdata->base_addr + cpu * pdata->cpu_offset;
+ msm_pm_slp_sts[cpu].mask = pdata->mask;
+ }
+ }
+
+ return 0;
+};
+
+static struct of_device_id msm_slp_sts_match_tbl[] = {
+ {.compatible = "qcom,cpu-sleep-status"},
+ {},
+};
+
+static struct platform_driver msm_cpu_status_driver = {
+ .probe = msm_cpu_status_probe,
+ .driver = {
+ .name = "cpu_slp_status",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_slp_sts_match_tbl,
+ },
+};
+
+static struct of_device_id msm_snoc_clnt_match_tbl[] = {
+ {.compatible = "qcom,pm-snoc-client"},
+ {},
+};
+
+static struct platform_driver msm_cpu_pm_snoc_client_driver = {
+ .probe = msm_pm_snoc_client_probe,
+ .driver = {
+ .name = "pm_snoc_client",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_snoc_clnt_match_tbl,
+ },
+};
+
+static int msm_pm_init(void)
+{
+ enum msm_pm_time_stats_id enable_stats[] = {
+ MSM_PM_STAT_IDLE_WFI,
+ MSM_PM_STAT_RETENTION,
+ MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE,
+ MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE,
+ MSM_PM_STAT_IDLE_POWER_COLLAPSE,
+ MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE,
+ MSM_PM_STAT_SUSPEND,
+ };
+ msm_pm_mode_sysfs_add();
+ msm_pm_add_stats(enable_stats, ARRAY_SIZE(enable_stats));
+
+ return 0;
+}
+
+static void msm_pm_set_flush_fn(uint32_t pc_mode)
+{
+ msm_pm_disable_l2_fn = NULL;
+ msm_pm_enable_l2_fn = NULL;
+ msm_pm_flush_l2_fn = outer_flush_all;
+
+ if (pc_mode == MSM_PM_PC_NOTZ_L2_EXT) {
+ msm_pm_disable_l2_fn = outer_disable;
+ msm_pm_enable_l2_fn = outer_resume;
+ }
+}
+
+struct msm_pc_debug_counters_buffer {
+ void __iomem *reg;
+ u32 len;
+ char buf[MAX_BUF_SIZE];
+};
+
+static inline u32 msm_pc_debug_counters_read_register(
+ void __iomem *reg, int index , int offset)
+{
+ return readl_relaxed(reg + (index * 4 + offset) * 4);
+}
+
+static char *counter_name[] = {
+ "PC Entry Counter",
+ "Warmboot Entry Counter",
+ "PC Bailout Counter"
+};
+
+static int msm_pc_debug_counters_copy(
+ struct msm_pc_debug_counters_buffer *data)
+{
+ int j;
+ u32 stat;
+ unsigned int cpu;
+
+ for_each_possible_cpu(cpu) {
+ data->len += scnprintf(data->buf + data->len,
+ sizeof(data->buf)-data->len,
+ "CPU%d\n", cpu);
+
+ for (j = 0; j < MSM_PC_NUM_COUNTERS; j++) {
+ stat = msm_pc_debug_counters_read_register(
+ data->reg, cpu, j);
+ data->len += scnprintf(data->buf + data->len,
+ sizeof(data->buf)-data->len,
+ "\t%s : %d\n", counter_name[j],
+ stat);
+ }
+
+ }
+
+ return data->len;
+}
+
+static int msm_pc_debug_counters_file_read(struct file *file,
+ char __user *bufu, size_t count, loff_t *ppos)
+{
+ struct msm_pc_debug_counters_buffer *data;
+
+ data = file->private_data;
+
+ if (!data)
+ return -EINVAL;
+
+ if (!bufu || count < 0)
+ return -EINVAL;
+
+ if (!access_ok(VERIFY_WRITE, bufu, count))
+ return -EFAULT;
+
+ if (*ppos >= data->len && data->len == 0)
+ data->len = msm_pc_debug_counters_copy(data);
+
+ return simple_read_from_buffer(bufu, count, ppos,
+ data->buf, data->len);
+}
+
+static int msm_pc_debug_counters_file_open(struct inode *inode,
+ struct file *file)
+{
+ struct msm_pc_debug_counters_buffer *buf;
+ void __iomem *msm_pc_debug_counters_reg;
+
+ msm_pc_debug_counters_reg = inode->i_private;
+
+ if (!msm_pc_debug_counters_reg)
+ return -EINVAL;
+
+ file->private_data = kzalloc(
+ sizeof(struct msm_pc_debug_counters_buffer), GFP_KERNEL);
+
+ if (!file->private_data) {
+ pr_err("%s: ERROR kmalloc failed to allocate %d bytes\n",
+ __func__, sizeof(struct msm_pc_debug_counters_buffer));
+
+ return -ENOMEM;
+ }
+
+ buf = file->private_data;
+ buf->reg = msm_pc_debug_counters_reg;
+
+ return 0;
+}
+
+static int msm_pc_debug_counters_file_close(struct inode *inode,
+ struct file *file)
+{
+ kfree(file->private_data);
+ return 0;
+}
+
+static const struct file_operations msm_pc_debug_counters_fops = {
+ .open = msm_pc_debug_counters_file_open,
+ .read = msm_pc_debug_counters_file_read,
+ .release = msm_pc_debug_counters_file_close,
+ .llseek = no_llseek,
+};
+
+static int msm_pm_clk_init(struct platform_device *pdev)
+{
+ bool synced_clocks;
+ u32 cpu;
+ char clk_name[] = "cpu??_clk";
+ bool cpu_as_clocks;
+ char *key;
+
+ key = "qcom,cpus-as-clocks";
+ cpu_as_clocks = of_property_read_bool(pdev->dev.of_node, key);
+
+ if (!cpu_as_clocks) {
+ use_acpuclk_apis = true;
+ return 0;
+ }
+
+ key = "qcom,synced-clocks";
+ synced_clocks = of_property_read_bool(pdev->dev.of_node, key);
+
+ for_each_possible_cpu(cpu) {
+ struct clk *clk;
+ snprintf(clk_name, sizeof(clk_name), "cpu%d_clk", cpu);
+ clk = devm_clk_get(&pdev->dev, clk_name);
+ if (IS_ERR(clk)) {
+ if (cpu && synced_clocks)
+ return 0;
+ else
+ return PTR_ERR(clk);
+ }
+ per_cpu(cpu_clks, cpu) = clk;
+ }
+
+ if (synced_clocks)
+ return 0;
+
+ l2_clk = devm_clk_get(&pdev->dev, "l2_clk");
+
+ return PTR_RET(l2_clk);
+}
+
+static int msm_cpu_pm_probe(struct platform_device *pdev)
+{
+ char *key = NULL;
+ struct dentry *dent = NULL;
+ struct resource *res = NULL;
+ int i;
+ struct msm_pm_init_data_type pdata_local;
+ int ret = 0;
+
+ memset(&pdata_local, 0, sizeof(struct msm_pm_init_data_type));
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return 0;
+ msm_pc_debug_counters_phys = res->start;
+ WARN_ON(resource_size(res) < SZ_64);
+ msm_pc_debug_counters = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (msm_pc_debug_counters) {
+ for (i = 0; i < resource_size(res)/4; i++)
+ __raw_writel(0, msm_pc_debug_counters + i * 4);
+
+ dent = debugfs_create_file("pc_debug_counter", S_IRUGO, NULL,
+ msm_pc_debug_counters,
+ &msm_pc_debug_counters_fops);
+ if (!dent)
+ pr_err("%s: ERROR debugfs_create_file failed\n",
+ __func__);
+ } else {
+ msm_pc_debug_counters = 0;
+ msm_pc_debug_counters_phys = 0;
+ }
+
+ if (pdev->dev.of_node) {
+ enum msm_pm_pc_mode_type pc_mode;
+
+ ret = msm_pm_clk_init(pdev);
+ if (ret) {
+ pr_info("msm_pm_clk_init returned error\n");
+ return ret;
+ }
+
+ key = "qcom,pc-mode";
+ ret = msm_pm_get_pc_mode(pdev->dev.of_node, key, &pc_mode);
+ if (ret) {
+ pr_debug("%s: Error reading key %s", __func__, key);
+ return -EINVAL;
+ }
+ msm_pm_set_flush_fn(pc_mode);
+ }
+
+ msm_pm_init();
+ if (pdev->dev.of_node)
+ of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+
+ return ret;
+}
+
+static struct of_device_id msm_cpu_pm_table[] = {
+ {.compatible = "qcom,pm-8x60"},
+ {},
+};
+
+static struct platform_driver msm_cpu_pm_driver = {
+ .probe = msm_cpu_pm_probe,
+ .driver = {
+ .name = "pm-8x60",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_cpu_pm_table,
+ },
+};
+
+static int __init msm_cpu_pm_init(void)
+{
+ int rc;
+
+ cpumask_clear(&retention_cpus);
+
+ rc = platform_driver_register(&msm_cpu_pm_snoc_client_driver);
+
+ if (rc) {
+ pr_err("%s(): failed to register driver %s\n", __func__,
+ msm_cpu_pm_snoc_client_driver.driver.name);
+ return rc;
+ }
+
+ return platform_driver_register(&msm_cpu_pm_driver);
+}
+device_initcall(msm_cpu_pm_init);
+
+void __init msm_pm_sleep_status_init(void)
+{
+ platform_driver_register(&msm_cpu_status_driver);
+}
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
index 8b64653..c745f92 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
@@ -1578,15 +1578,16 @@
static void set_qos_bw_regs(void __iomem *baddr, uint32_t mas_index,
int32_t th, int32_t tm, int32_t tl, uint32_t gp,
- uint32_t gc, bool bke_en)
+ uint32_t gc)
{
int32_t reg_val, val;
+ int32_t bke_reg_val;
int16_t val2;
/* Disable BKE before writing to registers as per spec */
- reg_val = readl_relaxed(M_BKE_EN_ADDR(baddr, mas_index)) &
+ bke_reg_val = readl_relaxed(M_BKE_EN_ADDR(baddr, mas_index)) &
M_BKE_EN_RMSK;
- writel_relaxed((reg_val & ~(M_BKE_EN_EN_BMSK)),
+ writel_relaxed((bke_reg_val & ~(M_BKE_EN_EN_BMSK)),
M_BKE_EN_ADDR(baddr, mas_index));
/* Write values of registers calculated */
@@ -1624,8 +1625,7 @@
/* Set BKE enable to the value it was */
reg_val = readl_relaxed(M_BKE_EN_ADDR(baddr, mas_index)) &
M_BKE_EN_RMSK;
- val = bke_en << M_BKE_EN_EN_SHFT;
- writel_relaxed(((reg_val & ~(M_BKE_EN_EN_BMSK)) | (val &
+ writel_relaxed(((reg_val & ~(M_BKE_EN_EN_BMSK)) | (bke_reg_val &
M_BKE_EN_EN_BMSK)), M_BKE_EN_ADDR(baddr, mas_index));
/* Ensure that all bandwidth register writes have completed
* before returning
@@ -1651,7 +1651,7 @@
/* Only calculate if there's a requested bandwidth and window */
if (qbw->bw && qbw->ws) {
int64_t th, tm, tl;
- uint32_t gp, gc, data_width;
+ uint32_t gp, gc;
int64_t gp_nominal, gp_required, gp_calc, data, temp;
int64_t win = qbw->ws * binfo->qos_freq;
temp = win;
@@ -1666,16 +1666,7 @@
* Calculate max window size, defined by bw request.
* Units: (KHz, MB/s)
*/
- data_width = (readl_relaxed(M_CONFIG_INFO_2_ADDR(
- binfo->base, mas_index)) &
- M_CONFIG_INFO_2_M_DATA_WIDTH_BMSK) >>
- M_CONFIG_INFO_2_M_DATA_WIDTH_SHFT;
-
- /* If unspecified, use data-width 8 by default */
- if (!data_width)
- data_width = 8;
-
- gp_calc = MAX_GC * data_width * binfo->qos_freq * 1000;
+ gp_calc = MAX_GC * binfo->qos_freq * 1000;
gp_required = gp_calc;
bimc_div(&gp_required, qbw->bw);
@@ -1684,7 +1675,7 @@
/* Calculate bandwith in grants and ceil. */
temp = qbw->bw * gp;
- data = data_width * binfo->qos_freq * 1000;
+ data = binfo->qos_freq * 1000;
bimc_div(&temp, data);
gc = min_t(int64_t, MAX_GC, temp);
@@ -1704,12 +1695,10 @@
mas_index, th, tm);
MSM_BUS_DBG("BIMC: tl: %llu gp:%u gc: %u bke_en: %u\n",
tl, gp, gc, bke_en);
- set_qos_bw_regs(binfo->base, mas_index, th, tm, tl, gp,
- gc, bke_en);
+ set_qos_bw_regs(binfo->base, mas_index, th, tm, tl, gp, gc);
} else
/* Clear bandwidth registers */
- set_qos_bw_regs(binfo->base, mas_index, 0, 0, 0, 0, 0,
- bke_en);
+ set_qos_bw_regs(binfo->base, mas_index, 0, 0, 0, 0, 0);
}
static int msm_bus_bimc_allocate_commit_data(struct msm_bus_fabric_registration
@@ -1816,16 +1805,27 @@
kfree(cd);
}
-static void bke_switch(void __iomem *baddr, uint32_t mas_index, bool req)
+static void bke_switch(
+ void __iomem *baddr, uint32_t mas_index, bool req, int mode)
{
uint32_t reg_val, val;
val = req << M_BKE_EN_EN_SHFT;
reg_val = readl_relaxed(M_BKE_EN_ADDR(baddr, mas_index)) &
M_BKE_EN_RMSK;
+ if (val == reg_val)
+ return;
+
+ if (!req && mode == BIMC_QOS_MODE_FIXED)
+ set_qos_mode(baddr, mas_index, 1, 1, 1);
+
writel_relaxed(((reg_val & ~(M_BKE_EN_EN_BMSK)) | (val &
M_BKE_EN_EN_BMSK)), M_BKE_EN_ADDR(baddr, mas_index));
+ /* Make sure BKE on/off goes through before changing priorities */
wmb();
+
+ if (req)
+ set_qos_mode(baddr, mas_index, 0, 0, 0);
}
static void msm_bus_bimc_config_master(
@@ -1854,13 +1854,13 @@
case BIMC_QOS_MODE_FIXED:
for (i = 0; i < ports; i++)
bke_switch(binfo->base, info->node_info->qport[i],
- BKE_OFF);
+ BKE_OFF, mode);
break;
case BIMC_QOS_MODE_REGULATOR:
case BIMC_QOS_MODE_LIMITER:
for (i = 0; i < ports; i++)
bke_switch(binfo->base, info->node_info->qport[i],
- BKE_ON);
+ BKE_ON, mode);
break;
default:
break;
@@ -1969,8 +1969,8 @@
static void bimc_set_static_qos_bw(struct msm_bus_bimc_info *binfo,
int mport, struct msm_bus_bimc_qos_bw *qbw)
{
- int32_t bw_MBps, thh = 0, thm, thl, gc;
- int16_t gp;
+ int32_t bw_mbps, thh = 0, thm, thl, gc;
+ int32_t gp;
u64 temp;
if (binfo->qos_freq == 0) {
@@ -1986,17 +1986,17 @@
/* Convert bandwidth to MBPS */
temp = qbw->bw;
bimc_div(&temp, 1000000);
- bw_MBps = temp;
+ bw_mbps = temp;
/* Grant period in clock cycles
* Grant period from bandwidth structure
- * is in micro seconds, QoS freq is in KHz.
+ * is in nano seconds, QoS freq is in KHz.
* Divide by 1000 to get clock cycles */
- gp = (binfo->qos_freq * qbw->gp) / 1000;
+ gp = (binfo->qos_freq * qbw->gp) / (1000 * NSEC_PER_USEC);
/* Grant count = BW in MBps * Grant period
* in micro seconds */
- gc = bw_MBps * qbw->gp;
+ gc = bw_mbps * (qbw->gp / NSEC_PER_USEC);
/* Medium threshold = -((Medium Threshold percentage *
* Grant count) / 100) */
@@ -2007,8 +2007,10 @@
thl = -gc;
qbw->thl = thl;
- set_qos_bw_regs(binfo->base, mport, thh, thm, thl, gp,
- gc, 1);
+ MSM_BUS_DBG("%s: BKE parameters: gp %d, gc %d, thm %d thl %d thh %d",
+ __func__, gp, gc, thm, thl, thh);
+
+ set_qos_bw_regs(binfo->base, mport, thh, thm, thl, gp, gc);
}
static void bimc_init_mas_reg(struct msm_bus_bimc_info *binfo,
diff --git a/arch/arm/mach-msm/msm_watchdog_v2.c b/arch/arm/mach-msm/msm_watchdog_v2.c
index 52e94e6..ead2e95 100644
--- a/arch/arm/mach-msm/msm_watchdog_v2.c
+++ b/arch/arm/mach-msm/msm_watchdog_v2.c
@@ -68,7 +68,7 @@
/*
* On the kernel command line specify
- * msm_watchdog.enable=1 to enable the watchdog
+ * msm_watchdog_v2.enable=1 to enable the watchdog
* By default watchdog is turned on
*/
static int enable = 1;
@@ -76,7 +76,7 @@
/*
* On the kernel command line specify
- * msm_watchdog.WDT_HZ=<clock val in HZ> to set Watchdog
+ * msm_watchdog_v2.WDT_HZ=<clock val in HZ> to set Watchdog
* ticks. By default it is set to 32765.
*/
static long WDT_HZ = 32765;
diff --git a/arch/arm/mach-msm/pil-msa.c b/arch/arm/mach-msm/pil-msa.c
index 3a26af9..76afe6c 100644
--- a/arch/arm/mach-msm/pil-msa.c
+++ b/arch/arm/mach-msm/pil-msa.c
@@ -233,18 +233,17 @@
if (drv->self_auth) {
ret = pil_msa_wait_for_mba_ready(drv);
if (ret)
- goto err_auth;
+ goto err_q6v5_reset;
}
drv->is_booted = true;
return 0;
-err_auth:
- pil_q6v5_shutdown(pil);
err_q6v5_reset:
pil_msa_pbl_disable_clks(drv);
err_clks:
+ writel_relaxed(1, drv->restart_reg);
pil_msa_pbl_power_down(drv);
err_power:
return ret;
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
deleted file mode 100644
index af21584..0000000
--- a/arch/arm/mach-msm/pm-8x60.c
+++ /dev/null
@@ -1,1751 +0,0 @@
-/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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/dma-mapping.h>
-#include <linux/debugfs.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/completion.h>
-#include <linux/cpuidle.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/ktime.h>
-#include <linux/pm.h>
-#include <linux/pm_qos.h>
-#include <linux/smp.h>
-#include <linux/suspend.h>
-#include <linux/tick.h>
-#include <linux/delay.h>
-#include <linux/platform_device.h>
-#include <linux/of_platform.h>
-#include <linux/regulator/krait-regulator.h>
-#include <linux/cpu.h>
-#include <mach/msm_iomap.h>
-#include <mach/socinfo.h>
-#include <mach/system.h>
-#include <mach/scm.h>
-#include <mach/socinfo.h>
-#define CREATE_TRACE_POINTS
-#include <mach/trace_msm_low_power.h>
-#include <mach/msm-krait-l2-accessors.h>
-#include <mach/msm_bus.h>
-#include <mach/mpm.h>
-#include <asm/cacheflush.h>
-#include <asm/hardware/gic.h>
-#include <asm/pgtable.h>
-#include <asm/pgalloc.h>
-#include <asm/outercache.h>
-#ifdef CONFIG_VFP
-#include <asm/vfp.h>
-#endif
-#include "acpuclock.h"
-#include "clock.h"
-#include "avs.h"
-#include <mach/cpuidle.h>
-#include "idle.h"
-#include "pm.h"
-#include "scm-boot.h"
-#include "spm.h"
-#include "timer.h"
-#include "pm-boot.h"
-#include <mach/event_timer.h>
-#include <linux/cpu_pm.h>
-
-#define SCM_L2_RETENTION (0x2)
-#define SCM_CMD_TERMINATE_PC (0x2)
-
-#define GET_CPU_OF_ATTR(attr) \
- (container_of(attr, struct msm_pm_kobj_attribute, ka)->cpu)
-
-#define SCLK_HZ (32768)
-
-#define NUM_OF_COUNTERS 3
-#define MAX_BUF_SIZE 512
-
-static int msm_pm_debug_mask = 1;
-module_param_named(
- debug_mask, msm_pm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
-);
-
-static int msm_pm_sleep_time_override;
-module_param_named(sleep_time_override,
- msm_pm_sleep_time_override, int, S_IRUGO | S_IWUSR | S_IWGRP);
-
-enum {
- MSM_PM_DEBUG_SUSPEND = BIT(0),
- MSM_PM_DEBUG_POWER_COLLAPSE = BIT(1),
- MSM_PM_DEBUG_SUSPEND_LIMITS = BIT(2),
- MSM_PM_DEBUG_CLOCK = BIT(3),
- MSM_PM_DEBUG_RESET_VECTOR = BIT(4),
- MSM_PM_DEBUG_IDLE_CLK = BIT(5),
- MSM_PM_DEBUG_IDLE = BIT(6),
- MSM_PM_DEBUG_IDLE_LIMITS = BIT(7),
- MSM_PM_DEBUG_HOTPLUG = BIT(8),
-};
-
-enum {
- MSM_PM_MODE_ATTR_SUSPEND,
- MSM_PM_MODE_ATTR_IDLE,
- MSM_PM_MODE_ATTR_NR,
-};
-
-static char *msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_NR] = {
- [MSM_PM_MODE_ATTR_SUSPEND] = "suspend_enabled",
- [MSM_PM_MODE_ATTR_IDLE] = "idle_enabled",
-};
-
-struct msm_pm_kobj_attribute {
- unsigned int cpu;
- struct kobj_attribute ka;
-};
-
-struct msm_pm_sysfs_sleep_mode {
- struct kobject *kobj;
- struct attribute_group attr_group;
- struct attribute *attrs[MSM_PM_MODE_ATTR_NR + 1];
- struct msm_pm_kobj_attribute kas[MSM_PM_MODE_ATTR_NR];
-};
-
-static char *msm_pm_sleep_mode_labels[MSM_PM_SLEEP_MODE_NR] = {
- [MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = "power_collapse",
- [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT] = "wfi",
- [MSM_PM_SLEEP_MODE_RETENTION] = "retention",
- [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE] =
- "standalone_power_collapse",
-};
-
-static struct hrtimer pm_hrtimer;
-static struct msm_pm_sleep_ops pm_sleep_ops;
-static bool msm_pm_ldo_retention_enabled = true;
-static bool msm_pm_use_sync_timer;
-static struct msm_pm_cp15_save_data cp15_data;
-static bool msm_pm_retention_calls_tz;
-static bool msm_no_ramp_down_pc;
-static struct msm_pm_sleep_status_data *msm_pm_slp_sts;
-static bool msm_pm_pc_reset_timer;
-
-static int msm_pm_get_pc_mode(struct device_node *node,
- const char *key, uint32_t *pc_mode_val)
-{
- struct pc_mode_of {
- uint32_t mode;
- char *mode_name;
- };
- int i;
- struct pc_mode_of pc_modes[] = {
- {MSM_PM_PC_TZ_L2_INT, "tz_l2_int"},
- {MSM_PM_PC_NOTZ_L2_EXT, "no_tz_l2_ext"},
- {MSM_PM_PC_TZ_L2_EXT , "tz_l2_ext"} };
- int ret;
- const char *pc_mode_str;
-
- ret = of_property_read_string(node, key, &pc_mode_str);
- if (ret) {
- pr_debug("%s: Cannot read %s,defaulting to 0", __func__, key);
- pc_mode_val = MSM_PM_PC_TZ_L2_INT;
- ret = 0;
- } else {
- ret = -EINVAL;
- for (i = 0; i < ARRAY_SIZE(pc_modes); i++) {
- if (!strncmp(pc_mode_str, pc_modes[i].mode_name,
- strlen(pc_modes[i].mode_name))) {
- *pc_mode_val = pc_modes[i].mode;
- ret = 0;
- break;
- }
- }
- }
- return ret;
-}
-
-/*
- * Write out the attribute.
- */
-static ssize_t msm_pm_mode_attr_show(
- struct kobject *kobj, struct kobj_attribute *attr, char *buf)
-{
- int ret = -EINVAL;
- int i;
-
- for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
- struct kernel_param kp;
- unsigned int cpu;
- struct msm_pm_platform_data *mode;
-
- if (msm_pm_sleep_mode_labels[i] == NULL)
- continue;
-
- if (strcmp(kobj->name, msm_pm_sleep_mode_labels[i]))
- continue;
-
- cpu = GET_CPU_OF_ATTR(attr);
- mode = &msm_pm_sleep_modes[MSM_PM_MODE(cpu, i)];
-
- if (!strcmp(attr->attr.name,
- msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_SUSPEND])) {
- u32 arg = mode->suspend_enabled;
- kp.arg = &arg;
- ret = param_get_ulong(buf, &kp);
- } else if (!strcmp(attr->attr.name,
- msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_IDLE])) {
- u32 arg = mode->idle_enabled;
- kp.arg = &arg;
- ret = param_get_ulong(buf, &kp);
- }
-
- break;
- }
-
- if (ret > 0) {
- strlcat(buf, "\n", PAGE_SIZE);
- ret++;
- }
-
- return ret;
-}
-
-static ssize_t msm_pm_mode_attr_store(struct kobject *kobj,
- struct kobj_attribute *attr, const char *buf, size_t count)
-{
- int ret = -EINVAL;
- int i;
-
- for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
- struct kernel_param kp;
- unsigned int cpu;
- struct msm_pm_platform_data *mode;
-
- if (msm_pm_sleep_mode_labels[i] == NULL)
- continue;
-
- if (strcmp(kobj->name, msm_pm_sleep_mode_labels[i]))
- continue;
-
- cpu = GET_CPU_OF_ATTR(attr);
- mode = &msm_pm_sleep_modes[MSM_PM_MODE(cpu, i)];
-
- if (!strcmp(attr->attr.name,
- msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_SUSPEND])) {
- kp.arg = &mode->suspend_enabled;
- ret = param_set_byte(buf, &kp);
- } else if (!strcmp(attr->attr.name,
- msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_IDLE])) {
- kp.arg = &mode->idle_enabled;
- ret = param_set_byte(buf, &kp);
- }
-
- break;
- }
-
- return ret ? ret : count;
-}
-
-static int __devinit msm_pm_mode_sysfs_add_cpu(
- unsigned int cpu, struct kobject *modes_kobj)
-{
- char cpu_name[8];
- struct kobject *cpu_kobj;
- struct msm_pm_sysfs_sleep_mode *mode = NULL;
- int i, j, k;
- int ret;
-
- snprintf(cpu_name, sizeof(cpu_name), "cpu%u", cpu);
- cpu_kobj = kobject_create_and_add(cpu_name, modes_kobj);
- if (!cpu_kobj) {
- pr_err("%s: cannot create %s kobject\n", __func__, cpu_name);
- ret = -ENOMEM;
- goto mode_sysfs_add_cpu_exit;
- }
-
- for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
- int idx = MSM_PM_MODE(cpu, i);
-
- if ((!msm_pm_sleep_modes[idx].suspend_supported)
- && (!msm_pm_sleep_modes[idx].idle_supported))
- continue;
-
- if (!msm_pm_sleep_mode_labels[i] ||
- !msm_pm_sleep_mode_labels[i][0])
- continue;
-
- mode = kzalloc(sizeof(*mode), GFP_KERNEL);
- if (!mode) {
- pr_err("%s: cannot allocate memory for attributes\n",
- __func__);
- ret = -ENOMEM;
- goto mode_sysfs_add_cpu_exit;
- }
-
- mode->kobj = kobject_create_and_add(
- msm_pm_sleep_mode_labels[i], cpu_kobj);
- if (!mode->kobj) {
- pr_err("%s: cannot create kobject\n", __func__);
- ret = -ENOMEM;
- goto mode_sysfs_add_cpu_exit;
- }
-
- for (k = 0, j = 0; k < MSM_PM_MODE_ATTR_NR; k++) {
- if ((k == MSM_PM_MODE_ATTR_IDLE) &&
- !msm_pm_sleep_modes[idx].idle_supported)
- continue;
- if ((k == MSM_PM_MODE_ATTR_SUSPEND) &&
- !msm_pm_sleep_modes[idx].suspend_supported)
- continue;
- sysfs_attr_init(&mode->kas[j].ka.attr);
- mode->kas[j].cpu = cpu;
- mode->kas[j].ka.attr.mode = 0644;
- mode->kas[j].ka.show = msm_pm_mode_attr_show;
- mode->kas[j].ka.store = msm_pm_mode_attr_store;
- mode->kas[j].ka.attr.name = msm_pm_mode_attr_labels[k];
- mode->attrs[j] = &mode->kas[j].ka.attr;
- j++;
- }
- mode->attrs[j] = NULL;
-
- mode->attr_group.attrs = mode->attrs;
- ret = sysfs_create_group(mode->kobj, &mode->attr_group);
- if (ret) {
- pr_err("%s: cannot create kobject attribute group\n",
- __func__);
- goto mode_sysfs_add_cpu_exit;
- }
- }
-
- ret = 0;
-
-mode_sysfs_add_cpu_exit:
- if (ret) {
- if (mode && mode->kobj)
- kobject_del(mode->kobj);
- kfree(mode);
- }
-
- return ret;
-}
-
-int __devinit msm_pm_mode_sysfs_add(void)
-{
- struct kobject *module_kobj;
- struct kobject *modes_kobj;
- unsigned int cpu;
- int ret;
-
- module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
- if (!module_kobj) {
- pr_err("%s: cannot find kobject for module %s\n",
- __func__, KBUILD_MODNAME);
- ret = -ENOENT;
- goto mode_sysfs_add_exit;
- }
-
- modes_kobj = kobject_create_and_add("modes", module_kobj);
- if (!modes_kobj) {
- pr_err("%s: cannot create modes kobject\n", __func__);
- ret = -ENOMEM;
- goto mode_sysfs_add_exit;
- }
-
- for_each_possible_cpu(cpu) {
- ret = msm_pm_mode_sysfs_add_cpu(cpu, modes_kobj);
- if (ret)
- goto mode_sysfs_add_exit;
- }
-
- ret = 0;
-
-mode_sysfs_add_exit:
- return ret;
-}
-
-/*
- * Configure hardware registers in preparation for Apps power down.
- */
-static void msm_pm_config_hw_before_power_down(void)
-{
- return;
-}
-
-/*
- * Clear hardware registers after Apps powers up.
- */
-static void msm_pm_config_hw_after_power_up(void)
-{
-}
-
-/*
- * Configure hardware registers in preparation for SWFI.
- */
-static void msm_pm_config_hw_before_swfi(void)
-{
- return;
-}
-
-/*
- * Configure/Restore hardware registers in preparation for Retention.
- */
-
-static void msm_pm_config_hw_after_retention(void)
-{
- int ret;
-
- ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
- WARN_ON(ret);
-}
-
-static void msm_pm_config_hw_before_retention(void)
-{
- return;
-}
-
-static void msm_pm_save_cpu_reg(void)
-{
- int i;
-
- /* Only on core0 */
- if (smp_processor_id())
- return;
-
- /**
- * On some targets, L2 PC will turn off may reset the core
- * configuration for the mux and the default may not make the core
- * happy when it resumes.
- * Save the active vdd, and set the core vdd to QSB max vdd, so that
- * when the core resumes, it is capable of supporting the current QSB
- * rate. Then restore the active vdd before switching the acpuclk rate.
- */
- if (msm_pm_get_l2_flush_flag() == 1) {
- cp15_data.active_vdd = msm_spm_get_vdd(0);
- for (i = 0; i < cp15_data.reg_saved_state_size; i++)
- cp15_data.reg_val[i] =
- get_l2_indirect_reg(
- cp15_data.reg_data[i]);
- msm_spm_set_vdd(0, cp15_data.qsb_pc_vdd);
- }
-}
-
-static void msm_pm_restore_cpu_reg(void)
-{
- int i;
-
- /* Only on core0 */
- if (smp_processor_id())
- return;
-
- if (msm_pm_get_l2_flush_flag() == 1) {
- for (i = 0; i < cp15_data.reg_saved_state_size; i++)
- set_l2_indirect_reg(
- cp15_data.reg_data[i],
- cp15_data.reg_val[i]);
- msm_spm_set_vdd(0, cp15_data.active_vdd);
- }
-}
-
-static void msm_pm_swfi(void)
-{
- msm_pm_config_hw_before_swfi();
- msm_arch_idle();
-}
-
-static void msm_pm_retention(void)
-{
- int ret = 0;
-
- msm_pm_config_hw_before_retention();
- ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_POWER_RETENTION, false);
- WARN_ON(ret);
-
- if (msm_pm_retention_calls_tz)
- scm_call_atomic1(SCM_SVC_BOOT, SCM_CMD_TERMINATE_PC,
- SCM_L2_RETENTION);
- else
- msm_arch_idle();
-
- msm_pm_config_hw_after_retention();
-}
-
-static bool __ref msm_pm_spm_power_collapse(
- unsigned int cpu, bool from_idle, bool notify_rpm)
-{
- void *entry;
- bool collapsed = 0;
- int ret;
- bool save_cpu_regs = !cpu || from_idle;
- unsigned int saved_gic_cpu_ctrl;
-
- saved_gic_cpu_ctrl = readl_relaxed(MSM_QGIC_CPU_BASE + GIC_CPU_CTRL);
- mb();
-
- if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
- pr_info("CPU%u: %s: notify_rpm %d\n",
- cpu, __func__, (int) notify_rpm);
-
- if (from_idle == true)
- cpu_pm_enter();
-
- ret = msm_spm_set_low_power_mode(
- MSM_SPM_MODE_POWER_COLLAPSE, notify_rpm);
- WARN_ON(ret);
-
- entry = save_cpu_regs ? msm_pm_collapse_exit : msm_secondary_startup;
-
- msm_pm_boot_config_before_pc(cpu, virt_to_phys(entry));
-
- if (MSM_PM_DEBUG_RESET_VECTOR & msm_pm_debug_mask)
- pr_info("CPU%u: %s: program vector to %p\n",
- cpu, __func__, entry);
- if (from_idle && msm_pm_pc_reset_timer)
- clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu);
-
-#ifdef CONFIG_VFP
- vfp_pm_suspend();
-#endif
- collapsed = save_cpu_regs ? msm_pm_collapse() : msm_pm_pc_hotplug();
-
- if (from_idle && msm_pm_pc_reset_timer)
- clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu);
-
- msm_pm_boot_config_after_pc(cpu);
-
- if (collapsed) {
-#ifdef CONFIG_VFP
- vfp_pm_resume();
-#endif
- cpu_init();
- writel(0xF0, MSM_QGIC_CPU_BASE + GIC_CPU_PRIMASK);
- writel_relaxed(saved_gic_cpu_ctrl,
- MSM_QGIC_CPU_BASE + GIC_CPU_CTRL);
- mb();
- local_fiq_enable();
- }
-
- if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
- pr_info("CPU%u: %s: msm_pm_collapse returned, collapsed %d\n",
- cpu, __func__, collapsed);
-
- ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
- WARN_ON(ret);
-
- if (from_idle == true)
- cpu_pm_exit();
-
- return collapsed;
-}
-
-static bool msm_pm_power_collapse_standalone(bool from_idle)
-{
- unsigned int cpu = smp_processor_id();
- unsigned int avsdscr;
- unsigned int avscsr;
- bool collapsed;
-
- avsdscr = avs_get_avsdscr();
- avscsr = avs_get_avscsr();
- avs_set_avscsr(0); /* Disable AVS */
-
- collapsed = msm_pm_spm_power_collapse(cpu, from_idle, false);
-
- avs_set_avsdscr(avsdscr);
- avs_set_avscsr(avscsr);
- return collapsed;
-}
-
-static bool msm_pm_power_collapse(bool from_idle)
-{
- unsigned int cpu = smp_processor_id();
- unsigned long saved_acpuclk_rate = 0;
- unsigned int avsdscr;
- unsigned int avscsr;
- bool collapsed;
-
- if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
- pr_info("CPU%u: %s: idle %d\n",
- cpu, __func__, (int)from_idle);
-
- msm_pm_config_hw_before_power_down();
- if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
- pr_info("CPU%u: %s: pre power down\n", cpu, __func__);
-
- avsdscr = avs_get_avsdscr();
- avscsr = avs_get_avscsr();
- avs_set_avscsr(0); /* Disable AVS */
-
- if (cpu_online(cpu) && !msm_no_ramp_down_pc)
- saved_acpuclk_rate = acpuclk_power_collapse();
-
- if (MSM_PM_DEBUG_CLOCK & msm_pm_debug_mask)
- pr_info("CPU%u: %s: change clock rate (old rate = %lu)\n",
- cpu, __func__, saved_acpuclk_rate);
-
- if (cp15_data.save_cp15)
- msm_pm_save_cpu_reg();
-
- collapsed = msm_pm_spm_power_collapse(cpu, from_idle, true);
-
- if (cp15_data.save_cp15)
- msm_pm_restore_cpu_reg();
-
- if (cpu_online(cpu)) {
- if (MSM_PM_DEBUG_CLOCK & msm_pm_debug_mask)
- pr_info("CPU%u: %s: restore clock rate to %lu\n",
- cpu, __func__, saved_acpuclk_rate);
- if (!msm_no_ramp_down_pc &&
- acpuclk_set_rate(cpu, saved_acpuclk_rate, SETRATE_PC)
- < 0)
- pr_err("CPU%u: %s: failed to restore clock rate(%lu)\n",
- cpu, __func__, saved_acpuclk_rate);
- } else {
- unsigned int gic_dist_enabled;
- unsigned int gic_dist_pending;
- gic_dist_enabled = readl_relaxed(
- MSM_QGIC_DIST_BASE + GIC_DIST_ENABLE_CLEAR);
- gic_dist_pending = readl_relaxed(
- MSM_QGIC_DIST_BASE + GIC_DIST_PENDING_SET);
- mb();
- gic_dist_pending &= gic_dist_enabled;
-
- if (gic_dist_pending)
- pr_err("CPU %d interrupted during hotplug.Pending int 0x%x\n",
- cpu, gic_dist_pending);
- }
-
-
- avs_set_avsdscr(avsdscr);
- avs_set_avscsr(avscsr);
- msm_pm_config_hw_after_power_up();
- if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
- pr_info("CPU%u: %s: post power up\n", cpu, __func__);
-
- if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
- pr_info("CPU%u: %s: return\n", cpu, __func__);
- return collapsed;
-}
-
-static int64_t msm_pm_timer_enter_idle(void)
-{
- if (msm_pm_use_sync_timer)
- return ktime_to_ns(tick_nohz_get_sleep_length());
-
- return msm_timer_enter_idle();
-}
-
-static void msm_pm_timer_exit_idle(bool timer_halted)
-{
- if (msm_pm_use_sync_timer)
- return;
-
- msm_timer_exit_idle((int) timer_halted);
-}
-
-static int64_t msm_pm_timer_enter_suspend(int64_t *period)
-{
- int64_t time = 0;
-
- if (msm_pm_use_sync_timer) {
- struct timespec ts;
- getnstimeofday(&ts);
- return timespec_to_ns(&ts);
- }
-
- time = msm_timer_get_sclk_time(period);
- if (!time)
- pr_err("%s: Unable to read sclk.\n", __func__);
-
- return time;
-}
-
-static int64_t msm_pm_timer_exit_suspend(int64_t time, int64_t period)
-{
- if (msm_pm_use_sync_timer) {
- struct timespec ts;
- getnstimeofday(&ts);
-
- return timespec_to_ns(&ts) - time;
- }
-
- if (time != 0) {
- int64_t end_time = msm_timer_get_sclk_time(NULL);
- if (end_time != 0) {
- time = end_time - time;
- if (time < 0)
- time += period;
- } else
- time = 0;
- }
-
- return time;
-}
-
-/**
- * pm_hrtimer_cb() : Callback function for hrtimer created if the
- * core needs to be awake to handle an event.
- * @hrtimer : Pointer to hrtimer
- */
-static enum hrtimer_restart pm_hrtimer_cb(struct hrtimer *hrtimer)
-{
- return HRTIMER_NORESTART;
-}
-
-/**
- * msm_pm_set_timer() : Set an hrtimer to wakeup the core in time
- * to handle an event.
- */
-static void msm_pm_set_timer(uint32_t modified_time_us)
-{
- u64 modified_time_ns = modified_time_us * NSEC_PER_USEC;
- ktime_t modified_ktime = ns_to_ktime(modified_time_ns);
- pm_hrtimer.function = pm_hrtimer_cb;
- hrtimer_start(&pm_hrtimer, modified_ktime, HRTIMER_MODE_REL);
-}
-
-/******************************************************************************
- * External Idle/Suspend Functions
- *****************************************************************************/
-
-void arch_idle(void)
-{
- return;
-}
-
-static inline void msm_pm_ftrace_lpm_enter(unsigned int cpu,
- uint32_t latency, uint32_t sleep_us,
- uint32_t wake_up,
- enum msm_pm_sleep_mode mode)
-{
- switch (mode) {
- case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
- trace_msm_pm_enter_wfi(cpu, latency, sleep_us, wake_up);
- break;
- case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
- trace_msm_pm_enter_spc(cpu, latency, sleep_us, wake_up);
- break;
- case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
- trace_msm_pm_enter_pc(cpu, latency, sleep_us, wake_up);
- break;
- case MSM_PM_SLEEP_MODE_RETENTION:
- trace_msm_pm_enter_ret(cpu, latency, sleep_us, wake_up);
- break;
- default:
- break;
- }
-}
-
-static inline void msm_pm_ftrace_lpm_exit(unsigned int cpu,
- enum msm_pm_sleep_mode mode,
- bool success)
-{
- switch (mode) {
- case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
- trace_msm_pm_exit_wfi(cpu, success);
- break;
- case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
- trace_msm_pm_exit_spc(cpu, success);
- break;
- case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
- trace_msm_pm_exit_pc(cpu, success);
- break;
- case MSM_PM_SLEEP_MODE_RETENTION:
- trace_msm_pm_exit_ret(cpu, success);
- break;
- default:
- break;
- }
-}
-
-static int msm_pm_idle_prepare(struct cpuidle_device *dev,
- struct cpuidle_driver *drv, int index,
- void **msm_pm_idle_rs_limits)
-{
- int i;
- unsigned int power_usage = -1;
- int ret = MSM_PM_SLEEP_MODE_NOT_SELECTED;
- uint32_t modified_time_us = 0;
- struct msm_pm_time_params time_param;
-
- time_param.latency_us =
- (uint32_t) pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
- time_param.sleep_us =
- (uint32_t) (ktime_to_us(tick_nohz_get_sleep_length())
- & UINT_MAX);
- time_param.modified_time_us = 0;
-
- if (!dev->cpu)
- time_param.next_event_us =
- (uint32_t) (ktime_to_us(get_next_event_time())
- & UINT_MAX);
- else
- time_param.next_event_us = 0;
-
- for (i = 0; i < dev->state_count; i++) {
- struct cpuidle_state *state = &drv->states[i];
- struct cpuidle_state_usage *st_usage = &dev->states_usage[i];
- enum msm_pm_sleep_mode mode;
- bool allow;
- uint32_t power;
- int idx;
- void *rs_limits = NULL;
-
- mode = (enum msm_pm_sleep_mode) cpuidle_get_statedata(st_usage);
- idx = MSM_PM_MODE(dev->cpu, mode);
-
- allow = msm_pm_sleep_modes[idx].idle_enabled &&
- msm_pm_sleep_modes[idx].idle_supported;
-
- switch (mode) {
- case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
- if (num_online_cpus() > 1)
- allow = false;
- break;
- case MSM_PM_SLEEP_MODE_RETENTION:
- /*
- * The Krait BHS regulator doesn't have enough head
- * room to drive the retention voltage on LDO and so
- * has disabled retention
- */
- if (!msm_pm_ldo_retention_enabled)
- allow = false;
-
- if (msm_pm_retention_calls_tz && num_online_cpus() > 1)
- allow = false;
- break;
- case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
- case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
- break;
- default:
- allow = false;
- break;
- }
-
- if (!allow)
- continue;
-
- if (pm_sleep_ops.lowest_limits)
- rs_limits = pm_sleep_ops.lowest_limits(true,
- mode, &time_param, &power);
-
- if (MSM_PM_DEBUG_IDLE & msm_pm_debug_mask)
- pr_info("CPU%u:%s:%s, latency %uus, slp %uus, lim %p\n",
- dev->cpu, __func__, state->desc,
- time_param.latency_us,
- time_param.sleep_us, rs_limits);
- if (!rs_limits)
- continue;
-
- if (power < power_usage) {
- power_usage = power;
- modified_time_us = time_param.modified_time_us;
- ret = mode;
- *msm_pm_idle_rs_limits = rs_limits;
- }
-
- }
-
- if (modified_time_us && !dev->cpu)
- msm_pm_set_timer(modified_time_us);
-
- msm_pm_ftrace_lpm_enter(dev->cpu, time_param.latency_us,
- time_param.sleep_us, time_param.next_event_us,
- ret);
-
- return ret;
-}
-
-enum msm_pm_sleep_mode msm_pm_idle_enter(struct cpuidle_device *dev,
- struct cpuidle_driver *drv, int index)
-{
- int64_t time;
- bool collapsed = 1;
- int exit_stat = -1;
- enum msm_pm_sleep_mode sleep_mode;
- void *msm_pm_idle_rs_limits = NULL;
- uint32_t sleep_delay = 1;
- int ret = -ENODEV;
- int notify_rpm = false;
- bool timer_halted = false;
-
- sleep_mode = msm_pm_idle_prepare(dev, drv, index,
- &msm_pm_idle_rs_limits);
-
- if (!msm_pm_idle_rs_limits) {
- sleep_mode = MSM_PM_SLEEP_MODE_NOT_SELECTED;
- goto cpuidle_enter_bail;
- }
-
- if (MSM_PM_DEBUG_IDLE & msm_pm_debug_mask)
- pr_info("CPU%u: %s: mode %d\n",
- smp_processor_id(), __func__, sleep_mode);
-
- time = ktime_to_ns(ktime_get());
-
- if (sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) {
- int64_t ns = msm_pm_timer_enter_idle();
- notify_rpm = true;
- do_div(ns, NSEC_PER_SEC / SCLK_HZ);
- sleep_delay = (uint32_t)ns;
-
- if (sleep_delay == 0) /* 0 would mean infinite time */
- sleep_delay = 1;
- }
-
- if (pm_sleep_ops.enter_sleep)
- ret = pm_sleep_ops.enter_sleep(sleep_delay,
- msm_pm_idle_rs_limits, true, notify_rpm);
- if (ret)
- goto cpuidle_enter_bail;
-
- switch (sleep_mode) {
- case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
- msm_pm_swfi();
- exit_stat = MSM_PM_STAT_IDLE_WFI;
- break;
-
- case MSM_PM_SLEEP_MODE_RETENTION:
- msm_pm_retention();
- exit_stat = MSM_PM_STAT_RETENTION;
- break;
-
- case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
- collapsed = msm_pm_power_collapse_standalone(true);
- if (collapsed)
- exit_stat = MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE;
- else
- exit_stat
- = MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE;
- break;
-
- case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
- if (MSM_PM_DEBUG_IDLE_CLK & msm_pm_debug_mask)
- clock_debug_print_enabled();
-
- collapsed = msm_pm_power_collapse(true);
- timer_halted = true;
-
- if (collapsed)
- exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
- else
- exit_stat = MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE;
-
- msm_pm_timer_exit_idle(timer_halted);
- break;
-
- case MSM_PM_SLEEP_MODE_NOT_SELECTED:
- goto cpuidle_enter_bail;
- break;
-
- default:
- __WARN();
- goto cpuidle_enter_bail;
- break;
- }
-
- if (pm_sleep_ops.exit_sleep)
- pm_sleep_ops.exit_sleep(msm_pm_idle_rs_limits, true,
- notify_rpm, collapsed);
-
- time = ktime_to_ns(ktime_get()) - time;
- msm_pm_ftrace_lpm_exit(smp_processor_id(), sleep_mode, collapsed);
- if (exit_stat >= 0)
- msm_pm_add_stat(exit_stat, time);
- do_div(time, 1000);
- dev->last_residency = (int) time;
- return sleep_mode;
-
-cpuidle_enter_bail:
- dev->last_residency = 0;
- if (sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE)
- msm_pm_timer_exit_idle(timer_halted);
- sleep_mode = MSM_PM_SLEEP_MODE_NOT_SELECTED;
- return sleep_mode;
-}
-
-int msm_pm_wait_cpu_shutdown(unsigned int cpu)
-{
- int timeout = 0;
-
- if (!msm_pm_slp_sts)
- return 0;
- if (!msm_pm_slp_sts[cpu].base_addr)
- return 0;
- while (1) {
- /*
- * Check for the SPM of the core being hotplugged to set
- * its sleep state.The SPM sleep state indicates that the
- * core has been power collapsed.
- */
- int acc_sts = __raw_readl(msm_pm_slp_sts[cpu].base_addr);
-
- if (acc_sts & msm_pm_slp_sts[cpu].mask)
- return 0;
- udelay(100);
- WARN(++timeout == 20, "CPU%u didn't collape within 2ms\n",
- cpu);
- }
-
- return -EBUSY;
-}
-
-void msm_pm_cpu_enter_lowpower(unsigned int cpu)
-{
- int i;
- bool allow[MSM_PM_SLEEP_MODE_NR];
-
- for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
- struct msm_pm_platform_data *mode;
-
- mode = &msm_pm_sleep_modes[MSM_PM_MODE(cpu, i)];
- allow[i] = mode->suspend_supported && mode->suspend_enabled;
- }
-
- if (MSM_PM_DEBUG_HOTPLUG & msm_pm_debug_mask)
- pr_notice("CPU%u: %s: shutting down cpu\n", cpu, __func__);
-
- if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE])
- msm_pm_power_collapse(false);
- else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE])
- msm_pm_power_collapse_standalone(false);
- else if (allow[MSM_PM_SLEEP_MODE_RETENTION])
- msm_pm_retention();
- else
- msm_pm_swfi();
-}
-
-static void msm_pm_ack_retention_disable(void *data)
-{
- /*
- * This is a NULL function to ensure that the core has woken up
- * and is safe to disable retention.
- */
-}
-/**
- * msm_pm_enable_retention() - Disable/Enable retention on all cores
- * @enable: Enable/Disable retention
- *
- */
-void msm_pm_enable_retention(bool enable)
-{
- if (enable == msm_pm_ldo_retention_enabled)
- return;
-
- msm_pm_ldo_retention_enabled = enable;
- /*
- * If retention is being disabled, wakeup all online core to ensure
- * that it isn't executing retention. Offlined cores need not be woken
- * up as they enter the deepest sleep mode, namely RPM assited power
- * collapse
- */
- if (!enable) {
- preempt_disable();
- smp_call_function_many(cpu_online_mask,
- msm_pm_ack_retention_disable,
- NULL, true);
- preempt_enable();
-
-
- }
-}
-EXPORT_SYMBOL(msm_pm_enable_retention);
-
-static int64_t suspend_time, suspend_period;
-static int collapsed;
-static int suspend_power_collapsed;
-
-static int msm_pm_enter(suspend_state_t state)
-{
- bool allow[MSM_PM_SLEEP_MODE_NR];
- int i;
- struct msm_pm_time_params time_param;
-
- time_param.latency_us = -1;
- time_param.sleep_us = -1;
- time_param.next_event_us = 0;
-
- if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
- pr_info("%s\n", __func__);
-
- if (smp_processor_id()) {
- __WARN();
- goto enter_exit;
- }
-
-
- for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
- struct msm_pm_platform_data *mode;
-
- mode = &msm_pm_sleep_modes[MSM_PM_MODE(0, i)];
- allow[i] = mode->suspend_supported && mode->suspend_enabled;
- }
-
- if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE]) {
- void *rs_limits = NULL;
- int ret = -ENODEV;
- uint32_t power;
- uint32_t msm_pm_max_sleep_time = 0;
-
- if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
- pr_info("%s: power collapse\n", __func__);
-
- clock_debug_print_enabled();
-
- if (msm_pm_sleep_time_override > 0) {
- int64_t ns = NSEC_PER_SEC *
- (int64_t) msm_pm_sleep_time_override;
- do_div(ns, NSEC_PER_SEC / SCLK_HZ);
- msm_pm_max_sleep_time = (uint32_t) ns;
- }
-
- if (pm_sleep_ops.lowest_limits)
- rs_limits = pm_sleep_ops.lowest_limits(false,
- MSM_PM_SLEEP_MODE_POWER_COLLAPSE, &time_param, &power);
-
- if (rs_limits) {
- if (pm_sleep_ops.enter_sleep)
- ret = pm_sleep_ops.enter_sleep(
- msm_pm_max_sleep_time,
- rs_limits, false, true);
- if (!ret) {
- collapsed = msm_pm_power_collapse(false);
- if (pm_sleep_ops.exit_sleep) {
- pm_sleep_ops.exit_sleep(rs_limits,
- false, true, collapsed);
- }
- }
- } else {
- pr_err("%s: cannot find the lowest power limit\n",
- __func__);
- }
- suspend_power_collapsed = true;
- } else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
- if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
- pr_info("%s: standalone power collapse\n", __func__);
- msm_pm_power_collapse_standalone(false);
- } else if (allow[MSM_PM_SLEEP_MODE_RETENTION]) {
- if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
- pr_info("%s: retention\n", __func__);
- msm_pm_retention();
- } else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT]) {
- if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
- pr_info("%s: swfi\n", __func__);
- msm_pm_swfi();
- }
-
-enter_exit:
- if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
- pr_info("%s: return\n", __func__);
-
- return 0;
-}
-
-void msm_pm_set_sleep_ops(struct msm_pm_sleep_ops *ops)
-{
- if (ops)
- pm_sleep_ops = *ops;
-}
-
-static int msm_suspend_prepare(void)
-{
- suspend_time = msm_pm_timer_enter_suspend(&suspend_period);
- msm_mpm_suspend_prepare();
- return 0;
-}
-
-static void msm_suspend_wake(void)
-{
- msm_mpm_suspend_wake();
- if (suspend_power_collapsed) {
- suspend_time = msm_pm_timer_exit_suspend(suspend_time,
- suspend_period);
- if (collapsed)
- msm_pm_add_stat(MSM_PM_STAT_SUSPEND, suspend_time);
- else
- msm_pm_add_stat(MSM_PM_STAT_FAILED_SUSPEND,
- suspend_time);
- suspend_power_collapsed = false;
- }
-}
-
-static const struct platform_suspend_ops msm_pm_ops = {
- .enter = msm_pm_enter,
- .valid = suspend_valid_only_mem,
- .prepare_late = msm_suspend_prepare,
- .wake = msm_suspend_wake,
-};
-
-static int __devinit msm_pm_snoc_client_probe(struct platform_device *pdev)
-{
- int rc = 0;
- static struct msm_bus_scale_pdata *msm_pm_bus_pdata;
- static uint32_t msm_pm_bus_client;
-
- msm_pm_bus_pdata = msm_bus_cl_get_pdata(pdev);
-
- if (msm_pm_bus_pdata) {
- msm_pm_bus_client =
- msm_bus_scale_register_client(msm_pm_bus_pdata);
-
- if (!msm_pm_bus_client) {
- pr_err("%s: Failed to register SNOC client",
- __func__);
- rc = -ENXIO;
- goto snoc_cl_probe_done;
- }
-
- rc = msm_bus_scale_client_update_request(msm_pm_bus_client, 1);
-
- if (rc)
- pr_err("%s: Error setting bus rate", __func__);
- }
-
-snoc_cl_probe_done:
- return rc;
-}
-
-static int __devinit msm_cpu_status_probe(struct platform_device *pdev)
-{
- struct msm_pm_sleep_status_data *pdata;
- char *key;
- u32 cpu;
-
- if (!pdev)
- return -EFAULT;
-
- msm_pm_slp_sts =
- kzalloc(sizeof(*msm_pm_slp_sts) * num_possible_cpus(),
- GFP_KERNEL);
-
- if (!msm_pm_slp_sts)
- return -ENOMEM;
-
- if (pdev->dev.of_node) {
- struct resource *res;
- u32 offset;
- int rc;
- u32 mask;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- goto fail_free_mem;
-
- key = "qcom,cpu-alias-addr";
- rc = of_property_read_u32(pdev->dev.of_node, key, &offset);
-
- if (rc)
- goto fail_free_mem;
-
- key = "qcom,sleep-status-mask";
- rc = of_property_read_u32(pdev->dev.of_node, key,
- &mask);
- if (rc)
- goto fail_free_mem;
-
- for_each_possible_cpu(cpu) {
- msm_pm_slp_sts[cpu].base_addr =
- ioremap(res->start + cpu * offset,
- resource_size(res));
- msm_pm_slp_sts[cpu].mask = mask;
-
- if (!msm_pm_slp_sts[cpu].base_addr)
- goto failed_of_node;
- }
-
- } else {
- pdata = pdev->dev.platform_data;
- if (!pdev->dev.platform_data)
- goto fail_free_mem;
-
- for_each_possible_cpu(cpu) {
- msm_pm_slp_sts[cpu].base_addr =
- pdata->base_addr + cpu * pdata->cpu_offset;
- msm_pm_slp_sts[cpu].mask = pdata->mask;
- }
- }
-
- return 0;
-
-failed_of_node:
- pr_info("%s(): Failed to key=%s\n", __func__, key);
- for_each_possible_cpu(cpu) {
- if (msm_pm_slp_sts[cpu].base_addr)
- iounmap(msm_pm_slp_sts[cpu].base_addr);
- }
-fail_free_mem:
- kfree(msm_pm_slp_sts);
- return -EINVAL;
-
-};
-
-static struct of_device_id msm_slp_sts_match_tbl[] = {
- {.compatible = "qcom,cpu-sleep-status"},
- {},
-};
-
-static struct platform_driver msm_cpu_status_driver = {
- .probe = msm_cpu_status_probe,
- .driver = {
- .name = "cpu_slp_status",
- .owner = THIS_MODULE,
- .of_match_table = msm_slp_sts_match_tbl,
- },
-};
-
-static struct of_device_id msm_snoc_clnt_match_tbl[] = {
- {.compatible = "qcom,pm-snoc-client"},
- {},
-};
-
-static struct platform_driver msm_cpu_pm_snoc_client_driver = {
- .probe = msm_pm_snoc_client_probe,
- .driver = {
- .name = "pm_snoc_client",
- .owner = THIS_MODULE,
- .of_match_table = msm_snoc_clnt_match_tbl,
- },
-};
-
-#ifdef CONFIG_ARM_LPAE
-static int msm_pm_idmap_add_pmd(pud_t *pud, unsigned long addr,
- unsigned long end, unsigned long prot)
-{
- pmd_t *pmd;
- unsigned long next;
-
- if (pud_none_or_clear_bad(pud) || (pud_val(*pud) & L_PGD_SWAPPER)) {
- pmd = pmd_alloc_one(&init_mm, addr);
- if (!pmd)
- return -ENOMEM;
-
- pud_populate(&init_mm, pud, pmd);
- pmd += pmd_index(addr);
- } else {
- pmd = pmd_offset(pud, addr);
- }
-
- do {
- next = pmd_addr_end(addr, end);
- *pmd = __pmd((addr & PMD_MASK) | prot);
- flush_pmd_entry(pmd);
- } while (pmd++, addr = next, addr != end);
-
- return 0;
-}
-#else /* !CONFIG_ARM_LPAE */
-static int msm_pm_idmap_add_pmd(pud_t *pud, unsigned long addr,
- unsigned long end, unsigned long prot)
-{
- pmd_t *pmd = pmd_offset(pud, addr);
-
- addr = (addr & PMD_MASK) | prot;
- pmd[0] = __pmd(addr);
- addr += SECTION_SIZE;
- pmd[1] = __pmd(addr);
- flush_pmd_entry(pmd);
-
- return 0;
-}
-#endif /* CONFIG_ARM_LPAE */
-
-static int msm_pm_idmap_add_pud(pgd_t *pgd, unsigned long addr,
- unsigned long end,
- unsigned long prot)
-{
- pud_t *pud = pud_offset(pgd, addr);
- unsigned long next;
- int ret;
-
- do {
- next = pud_addr_end(addr, end);
- ret = msm_pm_idmap_add_pmd(pud, addr, next, prot);
- if (ret)
- return ret;
- } while (pud++, addr = next, addr != end);
-
- return 0;
-}
-
-static int msm_pm_add_idmap(pgd_t *pgd, unsigned long addr,
- unsigned long end,
- unsigned long prot)
-{
- unsigned long next;
- int ret;
-
- pgd += pgd_index(addr);
- do {
- next = pgd_addr_end(addr, end);
- ret = msm_pm_idmap_add_pud(pgd, addr, next, prot);
- if (ret)
- return ret;
- } while (pgd++, addr = next, addr != end);
-
- return 0;
-}
-
-static int msm_pm_setup_pagetable(void)
-{
- pgd_t *pc_pgd;
- unsigned long exit_phys;
- unsigned long end;
- int ret;
-
- /* Page table for cores to come back up safely. */
- pc_pgd = pgd_alloc(&init_mm);
- if (!pc_pgd)
- return -ENOMEM;
-
- exit_phys = virt_to_phys(msm_pm_collapse_exit);
-
- /*
- * Make the (hopefully) reasonable assumption that the code size of
- * msm_pm_collapse_exit won't be more than a section in size
- */
- end = exit_phys + SECTION_SIZE;
-
- ret = msm_pm_add_idmap(pc_pgd, exit_phys, end,
- PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AF);
-
- if (ret)
- return ret;
-
- msm_pm_pc_pgd = virt_to_phys(pc_pgd);
- clean_caches((unsigned long)&msm_pm_pc_pgd, sizeof(msm_pm_pc_pgd),
- virt_to_phys(&msm_pm_pc_pgd));
-
- return 0;
-}
-
-static int __init msm_pm_setup_saved_state(void)
-{
- int ret;
- dma_addr_t temp_phys;
-
- ret = msm_pm_setup_pagetable();
- if (ret)
- return ret;
-
- msm_saved_state = dma_zalloc_coherent(NULL, CPU_SAVED_STATE_SIZE *
- num_possible_cpus(),
- &temp_phys, 0);
-
- if (!msm_saved_state)
- return -ENOMEM;
-
- /*
- * Explicitly cast here since msm_saved_state_phys is defined
- * in assembly and we want to avoid any kind of truncation
- * or endian problems.
- */
- msm_saved_state_phys = (unsigned long)temp_phys;
-
- return 0;
-}
-arch_initcall(msm_pm_setup_saved_state);
-
-static void setup_broadcast_timer(void *arg)
-{
- int cpu = smp_processor_id();
-
- clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &cpu);
-}
-
-static int setup_broadcast_cpuhp_notify(struct notifier_block *n,
- unsigned long action, void *hcpu)
-{
- int cpu = (unsigned long)hcpu;
-
- switch (action & ~CPU_TASKS_FROZEN) {
- case CPU_ONLINE:
- smp_call_function_single(cpu, setup_broadcast_timer, NULL, 1);
- break;
- }
-
- return NOTIFY_OK;
-}
-
-static struct notifier_block setup_broadcast_notifier = {
- .notifier_call = setup_broadcast_cpuhp_notify,
-};
-
-static int __init msm_pm_init(void)
-{
- enum msm_pm_time_stats_id enable_stats[] = {
- MSM_PM_STAT_IDLE_WFI,
- MSM_PM_STAT_RETENTION,
- MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE,
- MSM_PM_STAT_IDLE_POWER_COLLAPSE,
- MSM_PM_STAT_SUSPEND,
- };
- msm_pm_mode_sysfs_add();
- msm_pm_add_stats(enable_stats, ARRAY_SIZE(enable_stats));
- suspend_set_ops(&msm_pm_ops);
- hrtimer_init(&pm_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- msm_cpuidle_init();
-
- if (msm_pm_pc_reset_timer) {
- on_each_cpu(setup_broadcast_timer, NULL, 1);
- register_cpu_notifier(&setup_broadcast_notifier);
- }
-
- return 0;
-}
-
-static void __devinit msm_pm_set_flush_fn(uint32_t pc_mode)
-{
- msm_pm_disable_l2_fn = NULL;
- msm_pm_enable_l2_fn = NULL;
- msm_pm_flush_l2_fn = outer_flush_all;
-
- if (pc_mode == MSM_PM_PC_NOTZ_L2_EXT) {
- msm_pm_disable_l2_fn = outer_disable;
- msm_pm_enable_l2_fn = outer_resume;
- }
-}
-
-struct msm_pc_debug_counters_buffer {
- void __iomem *reg;
- u32 len;
- char buf[MAX_BUF_SIZE];
-};
-
-static inline u32 msm_pc_debug_counters_read_register(
- void __iomem *reg, int index , int offset)
-{
- return readl_relaxed(reg + (index * 4 + offset) * 4);
-}
-
-static char *counter_name[] = {
- "PC Entry Counter",
- "Warmboot Entry Counter",
- "PC Bailout Counter"
-};
-
-static int msm_pc_debug_counters_copy(
- struct msm_pc_debug_counters_buffer *data)
-{
- int j;
- u32 stat;
- unsigned int cpu;
-
- for_each_possible_cpu(cpu) {
- data->len += scnprintf(data->buf + data->len,
- sizeof(data->buf)-data->len,
- "CPU%d\n", cpu);
-
- for (j = 0; j < NUM_OF_COUNTERS; j++) {
- stat = msm_pc_debug_counters_read_register(
- data->reg, cpu, j);
- data->len += scnprintf(data->buf + data->len,
- sizeof(data->buf)-data->len,
- "\t%s : %d\n", counter_name[j],
- stat);
- }
-
- }
-
- return data->len;
-}
-
-static int msm_pc_debug_counters_file_read(struct file *file,
- char __user *bufu, size_t count, loff_t *ppos)
-{
- struct msm_pc_debug_counters_buffer *data;
-
- data = file->private_data;
-
- if (!data)
- return -EINVAL;
-
- if (!bufu)
- return -EINVAL;
-
- if (!access_ok(VERIFY_WRITE, bufu, count))
- return -EFAULT;
-
- if (*ppos >= data->len && data->len == 0)
- data->len = msm_pc_debug_counters_copy(data);
-
- return simple_read_from_buffer(bufu, count, ppos,
- data->buf, data->len);
-}
-
-static int msm_pc_debug_counters_file_open(struct inode *inode,
- struct file *file)
-{
- struct msm_pc_debug_counters_buffer *buf;
- void __iomem *msm_pc_debug_counters_reg;
-
- msm_pc_debug_counters_reg = inode->i_private;
-
- if (!msm_pc_debug_counters_reg)
- return -EINVAL;
-
- file->private_data = kzalloc(
- sizeof(struct msm_pc_debug_counters_buffer), GFP_KERNEL);
-
- if (!file->private_data) {
- pr_err("%s: ERROR kmalloc failed to allocate %d bytes\n",
- __func__, sizeof(struct msm_pc_debug_counters_buffer));
-
- return -ENOMEM;
- }
-
- buf = file->private_data;
- buf->reg = msm_pc_debug_counters_reg;
-
- return 0;
-}
-
-static int msm_pc_debug_counters_file_close(struct inode *inode,
- struct file *file)
-{
- kfree(file->private_data);
- return 0;
-}
-
-static const struct file_operations msm_pc_debug_counters_fops = {
- .open = msm_pc_debug_counters_file_open,
- .read = msm_pc_debug_counters_file_read,
- .release = msm_pc_debug_counters_file_close,
- .llseek = no_llseek,
-};
-
-static int __devinit msm_pm_8x60_probe(struct platform_device *pdev)
-{
- char *key = NULL;
- struct dentry *dent = NULL;
- struct resource *res = NULL;
- int i ;
- struct msm_pm_init_data_type pdata_local;
- int ret = 0;
-
- memset(&pdata_local, 0, sizeof(struct msm_pm_init_data_type));
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res) {
- msm_pc_debug_counters_phys = res->start;
- WARN_ON(resource_size(res) < SZ_64);
- msm_pc_debug_counters = devm_ioremap(&pdev->dev, res->start,
- resource_size(res));
- if (msm_pc_debug_counters)
- for (i = 0; i < resource_size(res)/4; i++)
- __raw_writel(0, msm_pc_debug_counters + i * 4);
-
- }
-
- if (!msm_pc_debug_counters) {
- msm_pc_debug_counters = 0;
- msm_pc_debug_counters_phys = 0;
- } else {
- dent = debugfs_create_file("pc_debug_counter", S_IRUGO, NULL,
- msm_pc_debug_counters,
- &msm_pc_debug_counters_fops);
- if (!dent)
- pr_err("%s: ERROR debugfs_create_file failed\n",
- __func__);
- }
-
- if (!pdev->dev.of_node) {
- struct msm_pm_init_data_type *d = pdev->dev.platform_data;
-
- if (!d)
- goto pm_8x60_probe_done;
-
- memcpy(&pdata_local, d, sizeof(struct msm_pm_init_data_type));
-
- } else {
- key = "qcom,pc-mode";
- ret = msm_pm_get_pc_mode(pdev->dev.of_node,
- key,
- &pdata_local.pc_mode);
- if (ret) {
- pr_debug("%s: Error reading key %s",
- __func__, key);
- return -EINVAL;
- }
-
- key = "qcom,use-sync-timer";
- pdata_local.use_sync_timer =
- of_property_read_bool(pdev->dev.of_node, key);
-
- key = "qcom,saw-turns-off-pll";
- msm_no_ramp_down_pc = of_property_read_bool(pdev->dev.of_node,
- key);
-
- key = "qcom,pc-resets-timer";
- msm_pm_pc_reset_timer = of_property_read_bool(
- pdev->dev.of_node, key);
- }
-
- if (pdata_local.cp15_data.reg_data &&
- pdata_local.cp15_data.reg_saved_state_size > 0) {
- cp15_data.reg_data = kzalloc(sizeof(uint32_t) *
- pdata_local.cp15_data.reg_saved_state_size,
- GFP_KERNEL);
- if (!cp15_data.reg_data)
- return -ENOMEM;
-
- cp15_data.reg_val = kzalloc(sizeof(uint32_t) *
- pdata_local.cp15_data.reg_saved_state_size,
- GFP_KERNEL);
- if (cp15_data.reg_val)
- return -ENOMEM;
-
- memcpy(cp15_data.reg_data, pdata_local.cp15_data.reg_data,
- pdata_local.cp15_data.reg_saved_state_size *
- sizeof(uint32_t));
- }
-
- msm_pm_set_flush_fn(pdata_local.pc_mode);
- msm_pm_use_sync_timer = pdata_local.use_sync_timer;
- msm_pm_retention_calls_tz = pdata_local.retention_calls_tz;
-
-pm_8x60_probe_done:
- msm_pm_init();
- if (pdev->dev.of_node)
- of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
-
- return ret;
-}
-
-static struct of_device_id msm_pm_8x60_table[] = {
- {.compatible = "qcom,pm-8x60"},
- {},
-};
-
-static struct platform_driver msm_pm_8x60_driver = {
- .probe = msm_pm_8x60_probe,
- .driver = {
- .name = "pm-8x60",
- .owner = THIS_MODULE,
- .of_match_table = msm_pm_8x60_table,
- },
-};
-
-static int __init msm_pm_8x60_init(void)
-{
- int rc;
-
- rc = platform_driver_register(&msm_cpu_pm_snoc_client_driver);
-
- if (rc) {
- pr_err("%s(): failed to register driver %s\n", __func__,
- msm_cpu_pm_snoc_client_driver.driver.name);
- return rc;
- }
-
- return platform_driver_register(&msm_pm_8x60_driver);
-}
-device_initcall(msm_pm_8x60_init);
-
-void __init msm_pm_sleep_status_init(void)
-{
- platform_driver_register(&msm_cpu_status_driver);
-}
diff --git a/arch/arm/mach-msm/pm-data.c b/arch/arm/mach-msm/pm-data.c
index f41c569..04f4237 100644
--- a/arch/arm/mach-msm/pm-data.c
+++ b/arch/arm/mach-msm/pm-data.c
@@ -43,7 +43,7 @@
},
[MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)] = {
- .idle_supported = 0,
+ .idle_supported = 1,
.suspend_supported = 1,
.idle_enabled = 0,
.suspend_enabled = 1,
@@ -71,7 +71,7 @@
},
[MSM_PM_MODE(2, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)] = {
- .idle_supported = 0,
+ .idle_supported = 1,
.suspend_supported = 1,
.idle_enabled = 0,
.suspend_enabled = 1,
@@ -99,7 +99,7 @@
},
[MSM_PM_MODE(3, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)] = {
- .idle_supported = 0,
+ .idle_supported = 1,
.suspend_supported = 1,
.idle_enabled = 0,
.suspend_enabled = 1,
diff --git a/arch/arm/mach-msm/pm-stats.c b/arch/arm/mach-msm/pm-stats.c
index ac4ed25..c4e52be 100644
--- a/arch/arm/mach-msm/pm-stats.c
+++ b/arch/arm/mach-msm/pm-stats.c
@@ -36,72 +36,132 @@
struct msm_pm_time_stats stats[MSM_PM_STAT_COUNT];
};
+static struct msm_pm_time_stats suspend_stats;
+
static DEFINE_SPINLOCK(msm_pm_stats_lock);
static DEFINE_PER_CPU_SHARED_ALIGNED(
struct msm_pm_cpu_time_stats, msm_pm_stats);
-
/*
- * Add the given time data to the statistics collection.
+ * Function to update stats
*/
-void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t)
+static void update_stats(struct msm_pm_time_stats *stats, int64_t t)
{
- unsigned long flags;
- struct msm_pm_time_stats *stats;
int64_t bt;
int i;
- spin_lock_irqsave(&msm_pm_stats_lock, flags);
- stats = __get_cpu_var(msm_pm_stats).stats;
+ if (!stats)
+ return;
- if (!stats[id].enabled)
- goto add_bail;
-
- stats[id].total_time += t;
- stats[id].count++;
+ stats->total_time += t;
+ stats->count++;
bt = t;
- do_div(bt, stats[id].first_bucket_time);
+ do_div(bt, stats->first_bucket_time);
if (bt < 1ULL << (CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT *
- (CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1)))
+ (CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1)))
i = DIV_ROUND_UP(fls((uint32_t)bt),
- CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT);
+ CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT);
else
i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
if (i >= CONFIG_MSM_IDLE_STATS_BUCKET_COUNT)
i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
- stats[id].bucket[i]++;
+ stats->bucket[i]++;
- if (t < stats[id].min_time[i] || !stats[id].max_time[i])
- stats[id].min_time[i] = t;
- if (t > stats[id].max_time[i])
- stats[id].max_time[i] = t;
+ if (t < stats->min_time[i] || !stats->max_time[i])
+ stats->min_time[i] = t;
+ if (t > stats->max_time[i])
+ stats->max_time[i] = t;
+}
+/*
+ * Add the given time data to the statistics collection.
+ */
+void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t)
+{
+ struct msm_pm_time_stats *stats;
+ unsigned long flags;
+
+ spin_lock_irqsave(&msm_pm_stats_lock, flags);
+ if (id == MSM_PM_STAT_SUSPEND) {
+ stats = &suspend_stats;
+ } else {
+ stats = __get_cpu_var(msm_pm_stats).stats;
+ if (!stats[id].enabled)
+ goto add_bail;
+ stats = &stats[id];
+ }
+ update_stats(stats, t);
add_bail:
spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
}
-/*
- * Write out the power management statistics.
- */
-
-static int msm_pm_stats_show(struct seq_file *m, void *v)
+static void stats_show(struct seq_file *m,
+ struct msm_pm_time_stats *stats,
+ int cpu, int suspend)
{
- int cpu;
+ int64_t bucket_time;
+ int64_t s;
+ uint32_t ns;
+ int i;
int bucket_count = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
int bucket_shift = CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT;
- for_each_possible_cpu(cpu) {
- unsigned long flags;
- struct msm_pm_time_stats *stats;
- int i, id;
- int64_t bucket_time;
- int64_t s;
- uint32_t ns;
+ if (!stats || !m)
+ return;
- spin_lock_irqsave(&msm_pm_stats_lock, flags);
+ s = stats->total_time;
+ ns = do_div(s, NSEC_PER_SEC);
+ if (suspend)
+ seq_printf(m,
+ "%s:\n"
+ " count: %7d\n"
+ " total_time: %lld.%09u\n",
+ stats->name,
+ stats->count,
+ s, ns);
+ else
+ seq_printf(m,
+ "[cpu %u] %s:\n"
+ " count: %7d\n"
+ " total_time: %lld.%09u\n",
+ cpu, stats->name,
+ stats->count,
+ s, ns);
+
+ bucket_time = stats->first_bucket_time;
+ for (i = 0; i < bucket_count; i++) {
+ s = bucket_time;
+ ns = do_div(s, NSEC_PER_SEC);
+ seq_printf(m,
+ " <%6lld.%09u: %7d (%lld-%lld)\n",
+ s, ns, stats->bucket[i],
+ stats->min_time[i],
+ stats->max_time[i]);
+ bucket_time <<= bucket_shift;
+ }
+
+ seq_printf(m, " >=%6lld.%09u: %7d (%lld-%lld)\n",
+ s, ns, stats->bucket[i],
+ stats->min_time[i],
+ stats->max_time[i]);
+}
+/*
+ * Write out the power management statistics.
+ */
+static int msm_pm_stats_show(struct seq_file *m, void *v)
+{
+ int cpu;
+ int id;
+ unsigned long flags;
+
+ spin_lock_irqsave(&msm_pm_stats_lock, flags);
+
+ for_each_possible_cpu(cpu) {
+ struct msm_pm_time_stats *stats;
+
stats = per_cpu(msm_pm_stats, cpu).stats;
for (id = 0; id < MSM_PM_STAT_COUNT; id++) {
@@ -109,38 +169,14 @@
if (!stats[id].enabled)
continue;
- s = stats[id].total_time;
- ns = do_div(s, NSEC_PER_SEC);
- seq_printf(m,
- "[cpu %u] %s:\n"
- " count: %7d\n"
- " total_time: %lld.%09u\n",
- cpu, stats[id].name,
- stats[id].count,
- s, ns);
+ if (id == MSM_PM_STAT_SUSPEND)
+ continue;
- bucket_time = stats[id].first_bucket_time;
- for (i = 0; i < bucket_count; i++) {
- s = bucket_time;
- ns = do_div(s, NSEC_PER_SEC);
- seq_printf(m,
- " <%6lld.%09u: %7d (%lld-%lld)\n",
- s, ns, stats[id].bucket[i],
- stats[id].min_time[i],
- stats[id].max_time[i]);
-
- bucket_time <<= bucket_shift;
- }
-
- seq_printf(m, " >=%6lld.%09u: %7d (%lld-%lld)\n",
- s, ns, stats[id].bucket[i],
- stats[id].min_time[i],
- stats[id].max_time[i]);
+ stats_show(m, &stats[id], cpu, false);
}
-
- spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
}
-
+ stats_show(m, &suspend_stats, cpu, true);
+ spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
return 0;
}
@@ -259,14 +295,6 @@
first_bucket_time =
CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
- stats[MSM_PM_STAT_SUSPEND].name = "suspend";
- stats[MSM_PM_STAT_SUSPEND].first_bucket_time =
- CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET;
-
- stats[MSM_PM_STAT_FAILED_SUSPEND].name = "failed-suspend";
- stats[MSM_PM_STAT_FAILED_SUSPEND].first_bucket_time =
- CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
stats[MSM_PM_STAT_NOT_IDLE].name = "not-idle";
stats[MSM_PM_STAT_NOT_IDLE].first_bucket_time =
CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
@@ -275,6 +303,9 @@
stats[enable_stats[i]].enabled = true;
}
+ suspend_stats.name = "system_suspend";
+ suspend_stats.first_bucket_time =
+ CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET;
d_entry = proc_create_data("msm_pm_stats", S_IRUGO | S_IWUSR | S_IWGRP,
NULL, &msm_pm_stats_fops, NULL);
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
index f2fc80b..a20b36e 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -27,33 +27,20 @@
#define msm_secondary_startup NULL
#endif
-DECLARE_PER_CPU(int, power_collapsed);
-
-struct msm_pm_irq_calls {
- unsigned int (*irq_pending)(void);
- int (*idle_sleep_allowed)(void);
- void (*enter_sleep1)(bool modem_wake, int from_idle, uint32_t
- *irq_mask);
- int (*enter_sleep2)(bool modem_wake, int from_idle);
- void (*exit_sleep1)(uint32_t irq_mask, uint32_t wakeup_reason,
- uint32_t pending_irqs);
- void (*exit_sleep2)(uint32_t irq_mask, uint32_t wakeup_reason,
- uint32_t pending_irqs);
- void (*exit_sleep3)(uint32_t irq_mask, uint32_t wakeup_reason,
- uint32_t pending_irqs);
+enum msm_pm_sleep_mode {
+ MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT,
+ MSM_PM_SLEEP_MODE_RETENTION,
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE,
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+ MSM_PM_SLEEP_MODE_NR,
+ MSM_PM_SLEEP_MODE_NOT_SELECTED,
};
-enum msm_pm_sleep_mode {
- MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT = 0,
- MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT = 1,
- MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE = 2,
- MSM_PM_SLEEP_MODE_POWER_COLLAPSE = 3,
- MSM_PM_SLEEP_MODE_APPS_SLEEP = 4,
- MSM_PM_SLEEP_MODE_RETENTION = MSM_PM_SLEEP_MODE_APPS_SLEEP,
- MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND = 5,
- MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN = 6,
- MSM_PM_SLEEP_MODE_NR = 7,
- MSM_PM_SLEEP_MODE_NOT_SELECTED,
+enum msm_pm_l2_scm_flag {
+ MSM_SCM_L2_ON = 0,
+ MSM_SCM_L2_OFF = 1,
+ MSM_SCM_L2_RET = 2,
+ MSM_SCM_L2_GDHS = 3,
};
#define MSM_PM_MODE(cpu, mode_nr) ((cpu) * MSM_PM_SLEEP_MODE_NR + (mode_nr))
@@ -84,16 +71,6 @@
extern struct msm_pm_platform_data msm_pm_sleep_modes[];
-struct msm_pm_sleep_ops {
- void *(*lowest_limits)(bool from_idle,
- enum msm_pm_sleep_mode sleep_mode,
- struct msm_pm_time_params *time_param, uint32_t *power);
- int (*enter_sleep)(uint32_t sclk_count, void *limits,
- bool from_idle, bool notify_rpm);
- void (*exit_sleep)(void *limits, bool from_idle,
- bool notify_rpm, bool collapsed);
-};
-
enum msm_pm_pc_mode_type {
MSM_PM_PC_TZ_L2_INT, /*Power collapse terminates in TZ;
integrated L2 cache controller */
@@ -103,20 +80,8 @@
external L2 cache controller */
};
-struct msm_pm_cp15_save_data {
- bool save_cp15;
- uint32_t active_vdd;
- uint32_t qsb_pc_vdd;
- uint32_t reg_saved_state_size;
- uint32_t *reg_data;
- uint32_t *reg_val;
-};
-
struct msm_pm_init_data_type {
enum msm_pm_pc_mode_type pc_mode;
- bool retention_calls_tz;
- struct msm_pm_cp15_save_data cp15_data;
- bool use_sync_timer;
};
struct msm_pm_cpr_ops {
@@ -127,21 +92,37 @@
void msm_pm_set_platform_data(struct msm_pm_platform_data *data, int count);
enum msm_pm_sleep_mode msm_pm_idle_enter(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index);
-void msm_pm_set_irq_extns(struct msm_pm_irq_calls *irq_calls);
void msm_pm_cpu_enter_lowpower(unsigned int cpu);
void __init msm_pm_set_tz_retention_flag(unsigned int flag);
void msm_pm_enable_retention(bool enable);
-#ifdef CONFIG_MSM_PM8X60
+#if defined(CONFIG_MSM_PM)
void msm_pm_set_rpm_wakeup_irq(unsigned int irq);
-void msm_pm_set_sleep_ops(struct msm_pm_sleep_ops *ops);
int msm_pm_wait_cpu_shutdown(unsigned int cpu);
+int msm_cpu_pm_enter_sleep(enum msm_pm_sleep_mode mode, bool from_idle);
void __init msm_pm_sleep_status_init(void);
+void msm_pm_set_l2_flush_flag(enum msm_pm_l2_scm_flag flag);
+bool msm_cpu_pm_check_mode(unsigned int cpu, enum msm_pm_sleep_mode mode,
+ bool from_idle);
+int msm_cpu_pm_enter_sleep(enum msm_pm_sleep_mode mode, bool from_idle);
#else
static inline void msm_pm_set_rpm_wakeup_irq(unsigned int irq) {}
-static inline void msm_pm_set_sleep_ops(struct msm_pm_sleep_ops *ops) {}
static inline int msm_pm_wait_cpu_shutdown(unsigned int cpu) { return 0; }
+static inline int msm_cpu_pm_enter_sleep(enum msm_pm_sleep_mode mode,
+ bool from_idle)
+{
+ return -ENODEV;
+}
static inline void msm_pm_sleep_status_init(void) {};
+static inline void msm_pm_set_l2_flush_flag(unsigned int flag)
+{
+ /* empty */
+}
+bool msm_cpu_pm_check_mode(unsigned int cpu, enum msm_pm_sleep_mode mode,
+ bool from_idle)
+{
+ return false;
+}
#endif
#ifdef CONFIG_HOTPLUG_CPU
int msm_platform_secondary_init(unsigned int cpu);
@@ -174,6 +155,5 @@
#endif
void msm_pm_set_cpr_ops(struct msm_pm_cpr_ops *ops);
-extern void *msm_pc_debug_counters;
extern unsigned long msm_pc_debug_counters_phys;
#endif /* __ARCH_ARM_MACH_MSM_PM_H */
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_dev_ctl.c b/arch/arm/mach-msm/qdsp6v2/audio_dev_ctl.c
deleted file mode 100644
index 8aacb56..0000000
--- a/arch/arm/mach-msm/qdsp6v2/audio_dev_ctl.c
+++ /dev/null
@@ -1,1731 +0,0 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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/fs.h>
-#include <linux/miscdevice.h>
-#include <linux/msm_audio.h>
-#include <linux/slab.h>
-#include <linux/wait.h>
-#include <linux/sched.h>
-#include <linux/workqueue.h>
-#include <asm/uaccess.h>
-#include <asm/atomic.h>
-#include <mach/qdsp6v2/audio_dev_ctl.h>
-#include <mach/debug_mm.h>
-#include <mach/qdsp6v2/q6voice.h>
-#include <sound/apr_audio.h>
-#include <sound/q6adm.h>
-
-#ifndef MAX
-#define MAX(x, y) (((x) > (y)) ? (x) : (y))
-#endif
-
-
-static DEFINE_MUTEX(session_lock);
-static struct workqueue_struct *msm_reset_device_work_queue;
-static void reset_device_work(struct work_struct *work);
-static DECLARE_WORK(msm_reset_device_work, reset_device_work);
-
-struct audio_dev_ctrl_state {
- struct msm_snddev_info *devs[AUDIO_DEV_CTL_MAX_DEV];
- u32 num_dev;
- atomic_t opened;
- struct msm_snddev_info *voice_rx_dev;
- struct msm_snddev_info *voice_tx_dev;
- wait_queue_head_t wait;
-};
-
-static struct audio_dev_ctrl_state audio_dev_ctrl;
-struct event_listner event;
-
-struct session_freq {
- int freq;
- int evt;
-};
-
-struct audio_routing_info {
- unsigned short mixer_mask[MAX_SESSIONS];
- unsigned short audrec_mixer_mask[MAX_SESSIONS];
- struct session_freq dec_freq[MAX_SESSIONS];
- struct session_freq enc_freq[MAX_SESSIONS];
- unsigned int copp_list[MAX_SESSIONS][AFE_MAX_PORTS];
- int voice_tx_dev_id;
- int voice_rx_dev_id;
- int voice_tx_sample_rate;
- int voice_rx_sample_rate;
- signed int voice_tx_vol;
- signed int voice_rx_vol;
- int tx_mute;
- int rx_mute;
- int voice_state;
- struct mutex copp_list_mutex;
- struct mutex adm_mutex;
-};
-
-static struct audio_routing_info routing_info;
-
-struct audio_copp_topology {
- struct mutex lock;
- int session_cnt;
- int session_id[MAX_SESSIONS];
- int topolog_id[MAX_SESSIONS];
-};
-static struct audio_copp_topology adm_tx_topology_tbl;
-
-int msm_reset_all_device(void)
-{
- int rc = 0;
- int dev_id = 0;
- struct msm_snddev_info *dev_info = NULL;
-
- for (dev_id = 0; dev_id < audio_dev_ctrl.num_dev; dev_id++) {
- dev_info = audio_dev_ctrl_find_dev(dev_id);
- if (IS_ERR(dev_info)) {
- pr_err("%s:pass invalid dev_id\n", __func__);
- rc = PTR_ERR(dev_info);
- return rc;
- }
- if (!dev_info->opened)
- continue;
- pr_debug("%s:Resetting device %d active on COPP %d"
- "with %lld as routing\n", __func__,
- dev_id, dev_info->copp_id, dev_info->sessions);
- broadcast_event(AUDDEV_EVT_REL_PENDING,
- dev_id,
- SESSION_IGNORE);
- rc = dev_info->dev_ops.close(dev_info);
- if (rc < 0) {
- pr_err("%s:Snd device failed close!\n", __func__);
- return rc;
- } else {
- dev_info->opened = 0;
- broadcast_event(AUDDEV_EVT_DEV_RLS,
- dev_id,
- SESSION_IGNORE);
-
- if (dev_info->copp_id == VOICE_PLAYBACK_TX)
- voice_start_playback(0);
- }
- dev_info->sessions = 0;
- }
- msm_clear_all_session();
- return 0;
-}
-EXPORT_SYMBOL(msm_reset_all_device);
-
-static void reset_device_work(struct work_struct *work)
-{
- msm_reset_all_device();
-}
-
-int reset_device(void)
-{
- queue_work(msm_reset_device_work_queue, &msm_reset_device_work);
- return 0;
-}
-EXPORT_SYMBOL(reset_device);
-
-int msm_set_copp_id(int session_id, int copp_id)
-{
- int rc = 0;
- int index;
-
- if (session_id < 1 || session_id > 8)
- return -EINVAL;
- if (afe_validate_port(copp_id) < 0)
- return -EINVAL;
-
- index = afe_get_port_index(copp_id);
- if (index < 0 || index > AFE_MAX_PORTS)
- return -EINVAL;
- pr_debug("%s: session[%d] copp_id[%d] index[%d]\n", __func__,
- session_id, copp_id, index);
- mutex_lock(&routing_info.copp_list_mutex);
- if (routing_info.copp_list[session_id][index] == COPP_IGNORE)
- routing_info.copp_list[session_id][index] = copp_id;
- mutex_unlock(&routing_info.copp_list_mutex);
-
- return rc;
-}
-EXPORT_SYMBOL(msm_set_copp_id);
-
-int msm_clear_copp_id(int session_id, int copp_id)
-{
- int rc = 0;
- int index = afe_get_port_index(copp_id);
-
- if (session_id < 1 || session_id > 8)
- return -EINVAL;
- pr_debug("%s: session[%d] copp_id[%d] index[%d]\n", __func__,
- session_id, copp_id, index);
- mutex_lock(&routing_info.copp_list_mutex);
- if (routing_info.copp_list[session_id][index] == copp_id)
- routing_info.copp_list[session_id][index] = COPP_IGNORE;
-#ifdef CONFIG_MSM8X60_RTAC
- rtac_remove_adm_device(copp_id, session_id);
-#endif
- mutex_unlock(&routing_info.copp_list_mutex);
-
- return rc;
-}
-EXPORT_SYMBOL(msm_clear_copp_id);
-
-int msm_clear_session_id(int session_id)
-{
- int rc = 0;
- int i = 0;
- if (session_id < 1 || session_id > 8)
- return -EINVAL;
- pr_debug("%s: session[%d]\n", __func__, session_id);
- mutex_lock(&routing_info.adm_mutex);
- mutex_lock(&routing_info.copp_list_mutex);
- for (i = 0; i < AFE_MAX_PORTS; i++) {
- if (routing_info.copp_list[session_id][i] != COPP_IGNORE) {
- rc = adm_close(routing_info.copp_list[session_id][i]);
- if (rc < 0) {
- pr_err("%s: adm close fail port[%d] rc[%d]\n",
- __func__,
- routing_info.copp_list[session_id][i],
- rc);
- continue;
- }
-#ifdef CONFIG_MSM8X60_RTAC
- rtac_remove_adm_device(
- routing_info.copp_list[session_id][i], session_id);
-#endif
- routing_info.copp_list[session_id][i] = COPP_IGNORE;
- rc = 0;
- }
- }
- mutex_unlock(&routing_info.copp_list_mutex);
- mutex_unlock(&routing_info.adm_mutex);
-
- return rc;
-}
-EXPORT_SYMBOL(msm_clear_session_id);
-
-int msm_clear_all_session()
-{
- int rc = 0;
- int i = 0, j = 0;
- pr_info("%s:\n", __func__);
- mutex_lock(&routing_info.adm_mutex);
- mutex_lock(&routing_info.copp_list_mutex);
- for (j = 1; j < MAX_SESSIONS; j++) {
- for (i = 0; i < AFE_MAX_PORTS; i++) {
- if (routing_info.copp_list[j][i] != COPP_IGNORE) {
- rc = adm_close(
- routing_info.copp_list[j][i]);
- if (rc < 0) {
- pr_err("%s: adm close fail copp[%d]"
- "session[%d] rc[%d]\n",
- __func__,
- routing_info.copp_list[j][i],
- j, rc);
- continue;
- }
- routing_info.copp_list[j][i] = COPP_IGNORE;
- rc = 0;
- }
- }
- }
- mutex_unlock(&routing_info.copp_list_mutex);
- mutex_unlock(&routing_info.adm_mutex);
- return rc;
-}
-EXPORT_SYMBOL(msm_clear_all_session);
-
-int msm_get_voice_state(void)
-{
- pr_debug("voice state %d\n", routing_info.voice_state);
- return routing_info.voice_state;
-}
-EXPORT_SYMBOL(msm_get_voice_state);
-
-int msm_set_voice_mute(int dir, int mute, u32 session_id)
-{
- pr_debug("dir %x mute %x\n", dir, mute);
- if (dir == DIR_TX) {
- routing_info.tx_mute = mute;
- broadcast_event(AUDDEV_EVT_DEVICE_VOL_MUTE_CHG,
- routing_info.voice_tx_dev_id, session_id);
- } else
- return -EPERM;
- return 0;
-}
-EXPORT_SYMBOL(msm_set_voice_mute);
-
-int msm_set_voice_vol(int dir, s32 volume, u32 session_id)
-{
- if (dir == DIR_TX) {
- routing_info.voice_tx_vol = volume;
- broadcast_event(AUDDEV_EVT_DEVICE_VOL_MUTE_CHG,
- routing_info.voice_tx_dev_id,
- session_id);
- } else if (dir == DIR_RX) {
- routing_info.voice_rx_vol = volume;
- broadcast_event(AUDDEV_EVT_DEVICE_VOL_MUTE_CHG,
- routing_info.voice_rx_dev_id,
- session_id);
- } else
- return -EINVAL;
- return 0;
-}
-EXPORT_SYMBOL(msm_set_voice_vol);
-
-void msm_snddev_register(struct msm_snddev_info *dev_info)
-{
- mutex_lock(&session_lock);
- if (audio_dev_ctrl.num_dev < AUDIO_DEV_CTL_MAX_DEV) {
- audio_dev_ctrl.devs[audio_dev_ctrl.num_dev] = dev_info;
- /* roughly 0 DB for digital gain
- * If default gain is not desirable, it is expected that
- * application sets desired gain before activating sound
- * device
- */
- dev_info->dev_volume = 75;
- dev_info->sessions = 0x0;
- dev_info->usage_count = 0;
- audio_dev_ctrl.num_dev++;
- } else
- pr_err("%s: device registry max out\n", __func__);
- mutex_unlock(&session_lock);
-}
-EXPORT_SYMBOL(msm_snddev_register);
-
-int msm_snddev_devcount(void)
-{
- return audio_dev_ctrl.num_dev;
-}
-EXPORT_SYMBOL(msm_snddev_devcount);
-
-int msm_snddev_query(int dev_id)
-{
- if (dev_id <= audio_dev_ctrl.num_dev)
- return 0;
- return -ENODEV;
-}
-EXPORT_SYMBOL(msm_snddev_query);
-
-int msm_snddev_is_set(int popp_id, int copp_id)
-{
- return routing_info.mixer_mask[popp_id] & (0x1 << copp_id);
-}
-EXPORT_SYMBOL(msm_snddev_is_set);
-
-unsigned short msm_snddev_route_enc(int enc_id)
-{
- if (enc_id >= MAX_SESSIONS)
- return -EINVAL;
- return routing_info.audrec_mixer_mask[enc_id];
-}
-EXPORT_SYMBOL(msm_snddev_route_enc);
-
-unsigned short msm_snddev_route_dec(int popp_id)
-{
- if (popp_id >= MAX_SESSIONS)
- return -EINVAL;
- return routing_info.mixer_mask[popp_id];
-}
-EXPORT_SYMBOL(msm_snddev_route_dec);
-
-/*To check one->many case*/
-int msm_check_multicopp_per_stream(int session_id,
- struct route_payload *payload)
-{
- int i = 0;
- int flag = 0;
- pr_debug("%s: session_id=%d\n", __func__, session_id);
- mutex_lock(&routing_info.copp_list_mutex);
- for (i = 0; i < AFE_MAX_PORTS; i++) {
- if (routing_info.copp_list[session_id][i] == COPP_IGNORE)
- continue;
- else {
- pr_debug("Device enabled\n");
- payload->copp_ids[flag++] =
- routing_info.copp_list[session_id][i];
- }
- }
- mutex_unlock(&routing_info.copp_list_mutex);
- if (flag > 1) {
- pr_debug("Multiple copp per stream case num_copps=%d\n", flag);
- } else {
- pr_debug("Stream routed to single copp\n");
- }
- payload->num_copps = flag;
- return flag;
-}
-
-int msm_snddev_set_dec(int popp_id, int copp_id, int set,
- int rate, int mode)
-{
- int rc = 0, i = 0, num_copps;
- struct route_payload payload;
-
- if ((popp_id >= MAX_SESSIONS) || (popp_id <= 0)) {
- pr_err("%s: Invalid session id %d\n", __func__, popp_id);
- return 0;
- }
-
- mutex_lock(&routing_info.adm_mutex);
- if (set) {
- rc = adm_open(copp_id, ADM_PATH_PLAYBACK, rate, mode,
- DEFAULT_COPP_TOPOLOGY);
- if (rc < 0) {
- pr_err("%s: adm open fail rc[%d]\n", __func__, rc);
- rc = -EINVAL;
- mutex_unlock(&routing_info.adm_mutex);
- return rc;
- }
- msm_set_copp_id(popp_id, copp_id);
- pr_debug("%s:Session id=%d copp_id=%d\n",
- __func__, popp_id, copp_id);
- memset(payload.copp_ids, COPP_IGNORE,
- (sizeof(unsigned int) * AFE_MAX_PORTS));
- num_copps = msm_check_multicopp_per_stream(popp_id, &payload);
- /* Multiple streams per copp is handled, one stream at a time */
- rc = adm_matrix_map(popp_id, ADM_PATH_PLAYBACK, num_copps,
- payload.copp_ids, copp_id);
- if (rc < 0) {
- pr_err("%s: matrix map failed rc[%d]\n",
- __func__, rc);
- adm_close(copp_id);
- rc = -EINVAL;
- mutex_unlock(&routing_info.adm_mutex);
- return rc;
- }
-#ifdef CONFIG_MSM8X60_RTAC
- for (i = 0; i < num_copps; i++)
- rtac_add_adm_device(payload.copp_ids[i], popp_id);
-#endif
- } else {
- for (i = 0; i < AFE_MAX_PORTS; i++) {
- if (routing_info.copp_list[popp_id][i] == copp_id) {
- rc = adm_close(copp_id);
- if (rc < 0) {
- pr_err("%s: adm close fail copp[%d]"
- "rc[%d]\n",
- __func__, copp_id, rc);
- rc = -EINVAL;
- mutex_unlock(&routing_info.adm_mutex);
- return rc;
- }
- msm_clear_copp_id(popp_id, copp_id);
- break;
- }
- }
- }
-
- if (copp_id == VOICE_PLAYBACK_TX) {
- /* Signal uplink playback. */
- rc = voice_start_playback(set);
- }
- mutex_unlock(&routing_info.adm_mutex);
- return rc;
-}
-EXPORT_SYMBOL(msm_snddev_set_dec);
-
-
-static int check_tx_copp_topology(int session_id)
-{
- int cnt;
- int ret_val = -ENOENT;
-
- cnt = adm_tx_topology_tbl.session_cnt;
- if (cnt) {
- do {
- if (adm_tx_topology_tbl.session_id[cnt-1]
- == session_id)
- ret_val = cnt-1;
- } while (--cnt);
- }
-
- return ret_val;
-}
-
-static int add_to_tx_topology_lists(int session_id, int topology)
-{
- int idx = 0, tbl_idx;
- int ret_val = -ENOSPC;
-
- mutex_lock(&adm_tx_topology_tbl.lock);
-
- tbl_idx = check_tx_copp_topology(session_id);
- if (tbl_idx == -ENOENT) {
- while (adm_tx_topology_tbl.session_id[idx++])
- ;
- tbl_idx = idx-1;
- }
-
- if (tbl_idx < MAX_SESSIONS) {
- adm_tx_topology_tbl.session_id[tbl_idx] = session_id;
- adm_tx_topology_tbl.topolog_id[tbl_idx] = topology;
- adm_tx_topology_tbl.session_cnt++;
-
- ret_val = 0;
- }
- mutex_unlock(&adm_tx_topology_tbl.lock);
- return ret_val;
-}
-
-static void remove_from_tx_topology_lists(int session_id)
-{
- int tbl_idx;
-
- mutex_lock(&adm_tx_topology_tbl.lock);
- tbl_idx = check_tx_copp_topology(session_id);
- if (tbl_idx != -ENOENT) {
-
- adm_tx_topology_tbl.session_cnt--;
- adm_tx_topology_tbl.session_id[tbl_idx] = 0;
- adm_tx_topology_tbl.topolog_id[tbl_idx] = 0;
- }
- mutex_unlock(&adm_tx_topology_tbl.lock);
-}
-
-int auddev_cfg_tx_copp_topology(int session_id, int cfg)
-{
- int ret = 0;
-
- if (cfg == DEFAULT_COPP_TOPOLOGY)
- remove_from_tx_topology_lists(session_id);
- else {
- switch (cfg) {
- case VPM_TX_SM_ECNS_COPP_TOPOLOGY:
- case VPM_TX_DM_FLUENCE_COPP_TOPOLOGY:
- ret = add_to_tx_topology_lists(session_id, cfg);
- break;
-
- default:
- ret = -ENODEV;
- break;
- }
- }
- return ret;
-}
-
-int msm_snddev_set_enc(int popp_id, int copp_id, int set,
- int rate, int mode)
-{
- int topology;
- int tbl_idx;
- int rc = 0, i = 0;
- mutex_lock(&routing_info.adm_mutex);
- if (set) {
- mutex_lock(&adm_tx_topology_tbl.lock);
- tbl_idx = check_tx_copp_topology(popp_id);
- if (tbl_idx == -ENOENT)
- topology = DEFAULT_COPP_TOPOLOGY;
- else {
- topology = adm_tx_topology_tbl.topolog_id[tbl_idx];
- rate = 16000;
- }
- mutex_unlock(&adm_tx_topology_tbl.lock);
- rc = adm_open(copp_id, ADM_PATH_LIVE_REC, rate, mode, topology);
- if (rc < 0) {
- pr_err("%s: adm open fail rc[%d]\n", __func__, rc);
- rc = -EINVAL;
- goto fail_cmd;
- }
-
- rc = adm_matrix_map(popp_id, ADM_PATH_LIVE_REC, 1,
- (unsigned int *)&copp_id, copp_id);
- if (rc < 0) {
- pr_err("%s: matrix map failed rc[%d]\n", __func__, rc);
- adm_close(copp_id);
- rc = -EINVAL;
- goto fail_cmd;
- }
- msm_set_copp_id(popp_id, copp_id);
-#ifdef CONFIG_MSM8X60_RTAC
- rtac_add_adm_device(copp_id, popp_id);
-#endif
-
- } else {
- for (i = 0; i < AFE_MAX_PORTS; i++) {
- if (routing_info.copp_list[popp_id][i] == copp_id) {
- rc = adm_close(copp_id);
- if (rc < 0) {
- pr_err("%s: adm close fail copp[%d]"
- "rc[%d]\n",
- __func__, copp_id, rc);
- rc = -EINVAL;
- goto fail_cmd;
- }
- msm_clear_copp_id(popp_id, copp_id);
- break;
- }
- }
- }
-fail_cmd:
- mutex_unlock(&routing_info.adm_mutex);
- return rc;
-}
-EXPORT_SYMBOL(msm_snddev_set_enc);
-
-int msm_device_is_voice(int dev_id)
-{
- if ((dev_id == routing_info.voice_rx_dev_id)
- || (dev_id == routing_info.voice_tx_dev_id))
- return 0;
- else
- return -EINVAL;
-}
-EXPORT_SYMBOL(msm_device_is_voice);
-
-int msm_set_voc_route(struct msm_snddev_info *dev_info,
- int stream_type, int dev_id)
-{
- int rc = 0;
- u64 session_mask = 0;
-
- mutex_lock(&session_lock);
- switch (stream_type) {
- case AUDIO_ROUTE_STREAM_VOICE_RX:
- if (audio_dev_ctrl.voice_rx_dev)
- audio_dev_ctrl.voice_rx_dev->sessions &= ~0xFFFF;
-
- if (!(dev_info->capability & SNDDEV_CAP_RX) |
- !(dev_info->capability & SNDDEV_CAP_VOICE)) {
- rc = -EINVAL;
- break;
- }
- audio_dev_ctrl.voice_rx_dev = dev_info;
- if (audio_dev_ctrl.voice_rx_dev) {
- session_mask =
- ((u64)0x1) << (MAX_BIT_PER_CLIENT * \
- ((int)AUDDEV_CLNT_VOC-1));
- audio_dev_ctrl.voice_rx_dev->sessions |=
- session_mask;
- }
- routing_info.voice_rx_dev_id = dev_id;
- break;
- case AUDIO_ROUTE_STREAM_VOICE_TX:
- if (audio_dev_ctrl.voice_tx_dev)
- audio_dev_ctrl.voice_tx_dev->sessions &= ~0xFFFF;
-
- if (!(dev_info->capability & SNDDEV_CAP_TX) |
- !(dev_info->capability & SNDDEV_CAP_VOICE)) {
- rc = -EINVAL;
- break;
- }
-
- audio_dev_ctrl.voice_tx_dev = dev_info;
- if (audio_dev_ctrl.voice_rx_dev) {
- session_mask =
- ((u64)0x1) << (MAX_BIT_PER_CLIENT * \
- ((int)AUDDEV_CLNT_VOC-1));
- audio_dev_ctrl.voice_tx_dev->sessions |=
- session_mask;
- }
- routing_info.voice_tx_dev_id = dev_id;
- break;
- default:
- rc = -EINVAL;
- }
- mutex_unlock(&session_lock);
- return rc;
-}
-EXPORT_SYMBOL(msm_set_voc_route);
-
-void msm_release_voc_thread(void)
-{
- wake_up(&audio_dev_ctrl.wait);
-}
-EXPORT_SYMBOL(msm_release_voc_thread);
-
-int msm_snddev_get_enc_freq(session_id)
-{
- return routing_info.enc_freq[session_id].freq;
-}
-EXPORT_SYMBOL(msm_snddev_get_enc_freq);
-
-int msm_get_voc_freq(int *tx_freq, int *rx_freq)
-{
- *tx_freq = routing_info.voice_tx_sample_rate;
- *rx_freq = routing_info.voice_rx_sample_rate;
- return 0;
-}
-EXPORT_SYMBOL(msm_get_voc_freq);
-
-int msm_get_voc_route(u32 *rx_id, u32 *tx_id)
-{
- int rc = 0;
-
- if (!rx_id || !tx_id)
- return -EINVAL;
-
- mutex_lock(&session_lock);
- if (!audio_dev_ctrl.voice_rx_dev || !audio_dev_ctrl.voice_tx_dev) {
- rc = -ENODEV;
- mutex_unlock(&session_lock);
- return rc;
- }
-
- *rx_id = audio_dev_ctrl.voice_rx_dev->acdb_id;
- *tx_id = audio_dev_ctrl.voice_tx_dev->acdb_id;
-
- mutex_unlock(&session_lock);
-
- return rc;
-}
-EXPORT_SYMBOL(msm_get_voc_route);
-
-struct msm_snddev_info *audio_dev_ctrl_find_dev(u32 dev_id)
-{
- struct msm_snddev_info *info;
-
- if ((audio_dev_ctrl.num_dev - 1) < dev_id) {
- info = ERR_PTR(-ENODEV);
- goto error;
- }
-
- info = audio_dev_ctrl.devs[dev_id];
-error:
- return info;
-
-}
-EXPORT_SYMBOL(audio_dev_ctrl_find_dev);
-
-int snddev_voice_set_volume(int vol, int path)
-{
- if (audio_dev_ctrl.voice_rx_dev
- && audio_dev_ctrl.voice_tx_dev) {
- if (path)
- audio_dev_ctrl.voice_tx_dev->dev_volume = vol;
- else
- audio_dev_ctrl.voice_rx_dev->dev_volume = vol;
- } else
- return -ENODEV;
- return 0;
-}
-EXPORT_SYMBOL(snddev_voice_set_volume);
-
-static int audio_dev_ctrl_get_devices(struct audio_dev_ctrl_state *dev_ctrl,
- void __user *arg)
-{
- int rc = 0;
- u32 index;
- struct msm_snd_device_list work_list;
- struct msm_snd_device_info *work_tbl;
-
- if (copy_from_user(&work_list, arg, sizeof(work_list))) {
- rc = -EFAULT;
- goto error;
- }
-
- if (work_list.num_dev > dev_ctrl->num_dev) {
- rc = -EINVAL;
- goto error;
- }
-
- work_tbl = kmalloc(work_list.num_dev *
- sizeof(struct msm_snd_device_info), GFP_KERNEL);
- if (!work_tbl) {
- rc = -ENOMEM;
- goto error;
- }
-
- for (index = 0; index < dev_ctrl->num_dev; index++) {
- work_tbl[index].dev_id = index;
- work_tbl[index].dev_cap = dev_ctrl->devs[index]->capability;
- strlcpy(work_tbl[index].dev_name, dev_ctrl->devs[index]->name,
- 64);
- }
-
- if (copy_to_user((void *) (work_list.list), work_tbl,
- work_list.num_dev * sizeof(struct msm_snd_device_info)))
- rc = -EFAULT;
- kfree(work_tbl);
-error:
- return rc;
-}
-
-
-int auddev_register_evt_listner(u32 evt_id, u32 clnt_type, u32 clnt_id,
- void (*listner)(u32 evt_id,
- union auddev_evt_data *evt_payload,
- void *private_data),
- void *private_data)
-{
- int rc;
- struct msm_snd_evt_listner *callback = NULL;
- struct msm_snd_evt_listner *new_cb;
-
- new_cb = kzalloc(sizeof(struct msm_snd_evt_listner), GFP_KERNEL);
- if (!new_cb) {
- pr_err("No memory to add new listener node\n");
- return -ENOMEM;
- }
-
- mutex_lock(&session_lock);
- new_cb->cb_next = NULL;
- new_cb->auddev_evt_listener = listner;
- new_cb->evt_id = evt_id;
- new_cb->clnt_type = clnt_type;
- new_cb->clnt_id = clnt_id;
- new_cb->private_data = private_data;
- if (event.cb == NULL) {
- event.cb = new_cb;
- new_cb->cb_prev = NULL;
- } else {
- callback = event.cb;
- for (; ;) {
- if (callback->cb_next == NULL)
- break;
- else {
- callback = callback->cb_next;
- continue;
- }
- }
- callback->cb_next = new_cb;
- new_cb->cb_prev = callback;
- }
- event.num_listner++;
- mutex_unlock(&session_lock);
- rc = 0;
- return rc;
-}
-EXPORT_SYMBOL(auddev_register_evt_listner);
-
-int auddev_unregister_evt_listner(u32 clnt_type, u32 clnt_id)
-{
- struct msm_snd_evt_listner *callback = event.cb;
- struct msm_snddev_info *info;
- u64 session_mask = 0;
- int i = 0;
-
- mutex_lock(&session_lock);
- while (callback != NULL) {
- if ((callback->clnt_type == clnt_type)
- && (callback->clnt_id == clnt_id))
- break;
- callback = callback->cb_next;
- }
- if (callback == NULL) {
- mutex_unlock(&session_lock);
- return -EINVAL;
- }
-
- if ((callback->cb_next == NULL) && (callback->cb_prev == NULL))
- event.cb = NULL;
- else if (callback->cb_next == NULL)
- callback->cb_prev->cb_next = NULL;
- else if (callback->cb_prev == NULL) {
- callback->cb_next->cb_prev = NULL;
- event.cb = callback->cb_next;
- } else {
- callback->cb_prev->cb_next = callback->cb_next;
- callback->cb_next->cb_prev = callback->cb_prev;
- }
- kfree(callback);
-
- session_mask = (((u64)0x1) << clnt_id) << (MAX_BIT_PER_CLIENT * \
- ((int)clnt_type-1));
- for (i = 0; i < audio_dev_ctrl.num_dev; i++) {
- info = audio_dev_ctrl.devs[i];
- info->sessions &= ~session_mask;
- }
- mutex_unlock(&session_lock);
- return 0;
-}
-EXPORT_SYMBOL(auddev_unregister_evt_listner);
-
-int msm_snddev_withdraw_freq(u32 session_id, u32 capability, u32 clnt_type)
-{
- int i = 0;
- struct msm_snddev_info *info;
- u64 session_mask = 0;
-
- if ((clnt_type == AUDDEV_CLNT_VOC) && (session_id != 0))
- return -EINVAL;
- if ((clnt_type == AUDDEV_CLNT_DEC)
- && (session_id >= MAX_SESSIONS))
- return -EINVAL;
- if ((clnt_type == AUDDEV_CLNT_ENC)
- && (session_id >= MAX_SESSIONS))
- return -EINVAL;
-
- session_mask = (((u64)0x1) << session_id) << (MAX_BIT_PER_CLIENT * \
- ((int)clnt_type-1));
-
- for (i = 0; i < audio_dev_ctrl.num_dev; i++) {
- info = audio_dev_ctrl.devs[i];
- if ((info->sessions & session_mask)
- && (info->capability & capability)) {
- if (!(info->sessions & ~(session_mask)))
- info->set_sample_rate = 0;
- }
- }
- if (clnt_type == AUDDEV_CLNT_DEC)
- routing_info.dec_freq[session_id].freq
- = 0;
- else if (clnt_type == AUDDEV_CLNT_ENC)
- routing_info.enc_freq[session_id].freq
- = 0;
- else if (capability == SNDDEV_CAP_TX)
- routing_info.voice_tx_sample_rate = 0;
- else
- routing_info.voice_rx_sample_rate = 48000;
- return 0;
-}
-
-int msm_snddev_request_freq(int *freq, u32 session_id,
- u32 capability, u32 clnt_type)
-{
- int i = 0;
- int rc = 0;
- struct msm_snddev_info *info;
- u32 set_freq;
- u64 session_mask = 0;
- u64 clnt_type_mask = 0;
-
- pr_debug(": clnt_type 0x%08x\n", clnt_type);
-
- if ((clnt_type == AUDDEV_CLNT_VOC) && (session_id != 0))
- return -EINVAL;
- if ((clnt_type == AUDDEV_CLNT_DEC)
- && (session_id >= MAX_SESSIONS))
- return -EINVAL;
- if ((clnt_type == AUDDEV_CLNT_ENC)
- && (session_id >= MAX_SESSIONS))
- return -EINVAL;
- session_mask = (((u64)0x1) << session_id) << (MAX_BIT_PER_CLIENT * \
- ((int)clnt_type-1));
- clnt_type_mask = (0xFFFF << (MAX_BIT_PER_CLIENT * (clnt_type-1)));
- if (!(*freq == 8000) && !(*freq == 11025) &&
- !(*freq == 12000) && !(*freq == 16000) &&
- !(*freq == 22050) && !(*freq == 24000) &&
- !(*freq == 32000) && !(*freq == 44100) &&
- !(*freq == 48000))
- return -EINVAL;
-
- for (i = 0; i < audio_dev_ctrl.num_dev; i++) {
- info = audio_dev_ctrl.devs[i];
- if ((info->sessions & session_mask)
- && (info->capability & capability)) {
- rc = 0;
- if ((info->sessions & ~clnt_type_mask)
- && ((*freq != 8000) && (*freq != 16000)
- && (*freq != 48000))) {
- if (clnt_type == AUDDEV_CLNT_ENC) {
- routing_info.enc_freq[session_id].freq
- = 0;
- return -EPERM;
- } else if (clnt_type == AUDDEV_CLNT_DEC) {
- routing_info.dec_freq[session_id].freq
- = 0;
- return -EPERM;
- }
- }
- if (*freq == info->set_sample_rate) {
- rc = info->set_sample_rate;
- continue;
- }
- set_freq = MAX(*freq, info->set_sample_rate);
-
-
- if (clnt_type == AUDDEV_CLNT_DEC) {
- routing_info.dec_freq[session_id].evt = 1;
- routing_info.dec_freq[session_id].freq
- = set_freq;
- } else if (clnt_type == AUDDEV_CLNT_ENC) {
- routing_info.enc_freq[session_id].evt = 1;
- routing_info.enc_freq[session_id].freq
- = set_freq;
- } else if (capability == SNDDEV_CAP_TX)
- routing_info.voice_tx_sample_rate = set_freq;
-
- rc = set_freq;
- info->set_sample_rate = set_freq;
- *freq = info->set_sample_rate;
-
- if (info->opened) {
- broadcast_event(AUDDEV_EVT_FREQ_CHG, i,
- SESSION_IGNORE);
- set_freq = info->dev_ops.set_freq(info,
- set_freq);
- broadcast_event(AUDDEV_EVT_DEV_RDY, i,
- SESSION_IGNORE);
- }
- }
- pr_debug("info->set_sample_rate = %d\n", info->set_sample_rate);
- pr_debug("routing_info.enc_freq.freq = %d\n",
- routing_info.enc_freq[session_id].freq);
- }
- return rc;
-}
-EXPORT_SYMBOL(msm_snddev_request_freq);
-
-int msm_snddev_enable_sidetone(u32 dev_id, u32 enable, uint16_t gain)
-{
- int rc;
- struct msm_snddev_info *dev_info;
-
- pr_debug("dev_id %d enable %d\n", dev_id, enable);
-
- dev_info = audio_dev_ctrl_find_dev(dev_id);
-
- if (IS_ERR(dev_info)) {
- pr_err("bad dev_id %d\n", dev_id);
- rc = -EINVAL;
- } else if (!dev_info->dev_ops.enable_sidetone) {
- pr_debug("dev %d no sidetone support\n", dev_id);
- rc = -EPERM;
- } else
- rc = dev_info->dev_ops.enable_sidetone(dev_info, enable, gain);
-
- return rc;
-}
-EXPORT_SYMBOL(msm_snddev_enable_sidetone);
-
-int msm_enable_incall_recording(int popp_id, int rec_mode, int rate,
- int channel_mode)
-{
- int rc = 0;
- unsigned int port_id[2];
- port_id[0] = VOICE_RECORD_TX;
- port_id[1] = VOICE_RECORD_RX;
-
- pr_debug("%s: popp_id %d, rec_mode %d, rate %d, channel_mode %d\n",
- __func__, popp_id, rec_mode, rate, channel_mode);
-
- mutex_lock(&routing_info.adm_mutex);
-
- if (rec_mode == VOC_REC_UPLINK) {
- rc = afe_start_pseudo_port(port_id[0]);
- if (rc < 0) {
- pr_err("%s: Error %d in Tx pseudo port start\n",
- __func__, rc);
-
- goto fail_cmd;
- }
-
- rc = adm_open(port_id[0], ADM_PATH_LIVE_REC, rate, channel_mode,
- DEFAULT_COPP_TOPOLOGY);
- if (rc < 0) {
- pr_err("%s: Error %d in ADM open %d\n",
- __func__, rc, port_id[0]);
-
- goto fail_cmd;
- }
-
- rc = adm_matrix_map(popp_id, ADM_PATH_LIVE_REC, 1,
- &port_id[0], port_id[0]);
- if (rc < 0) {
- pr_err("%s: Error %d in ADM matrix map %d\n",
- __func__, rc, port_id[0]);
-
- goto fail_cmd;
- }
-
- msm_set_copp_id(popp_id, port_id[0]);
-
- } else if (rec_mode == VOC_REC_DOWNLINK) {
- rc = afe_start_pseudo_port(port_id[1]);
- if (rc < 0) {
- pr_err("%s: Error %d in Rx pseudo port start\n",
- __func__, rc);
-
- goto fail_cmd;
- }
-
- rc = adm_open(port_id[1], ADM_PATH_LIVE_REC, rate, channel_mode,
- DEFAULT_COPP_TOPOLOGY);
- if (rc < 0) {
- pr_err("%s: Error %d in ADM open %d\n",
- __func__, rc, port_id[1]);
-
- goto fail_cmd;
- }
-
- rc = adm_matrix_map(popp_id, ADM_PATH_LIVE_REC, 1,
- &port_id[1], port_id[1]);
- if (rc < 0) {
- pr_err("%s: Error %d in ADM matrix map %d\n",
- __func__, rc, port_id[1]);
-
- goto fail_cmd;
- }
-
- msm_set_copp_id(popp_id, port_id[1]);
-
- } else if (rec_mode == VOC_REC_BOTH) {
- rc = afe_start_pseudo_port(port_id[0]);
- if (rc < 0) {
- pr_err("%s: Error %d in Tx pseudo port start\n",
- __func__, rc);
-
- goto fail_cmd;
- }
-
- rc = adm_open(port_id[0], ADM_PATH_LIVE_REC, rate, channel_mode,
- DEFAULT_COPP_TOPOLOGY);
- if (rc < 0) {
- pr_err("%s: Error %d in ADM open %d\n",
- __func__, rc, port_id[0]);
-
- goto fail_cmd;
- }
-
- msm_set_copp_id(popp_id, port_id[0]);
-
- rc = afe_start_pseudo_port(port_id[1]);
- if (rc < 0) {
- pr_err("%s: Error %d in Rx pseudo port start\n",
- __func__, rc);
-
- goto fail_cmd;
- }
-
- rc = adm_open(port_id[1], ADM_PATH_LIVE_REC, rate, channel_mode,
- DEFAULT_COPP_TOPOLOGY);
- if (rc < 0) {
- pr_err("%s: Error %d in ADM open %d\n",
- __func__, rc, port_id[0]);
-
- goto fail_cmd;
- }
-
- rc = adm_matrix_map(popp_id, ADM_PATH_LIVE_REC, 2,
- &port_id[0], port_id[1]);
- if (rc < 0) {
- pr_err("%s: Error %d in ADM matrix map\n",
- __func__, rc);
-
- goto fail_cmd;
- }
-
- msm_set_copp_id(popp_id, port_id[1]);
- } else {
- pr_err("%s Unknown rec_mode %d\n", __func__, rec_mode);
-
- goto fail_cmd;
- }
-
- rc = voice_start_record(rec_mode, 1);
-
-fail_cmd:
- mutex_unlock(&routing_info.adm_mutex);
- return rc;
-}
-
-int msm_disable_incall_recording(uint32_t popp_id, uint32_t rec_mode)
-{
- int rc = 0;
- uint32_t port_id[2];
- port_id[0] = VOICE_RECORD_TX;
- port_id[1] = VOICE_RECORD_RX;
-
- pr_debug("%s: popp_id %d, rec_mode %d\n", __func__, popp_id, rec_mode);
-
- mutex_lock(&routing_info.adm_mutex);
-
- rc = voice_start_record(rec_mode, 0);
- if (rc < 0) {
- pr_err("%s: Error %d stopping record\n", __func__, rc);
-
- goto fail_cmd;
- }
-
- if (rec_mode == VOC_REC_UPLINK) {
- rc = adm_close(port_id[0]);
- if (rc < 0) {
- pr_err("%s: Error %d in ADM close %d\n",
- __func__, rc, port_id[0]);
-
- goto fail_cmd;
- }
-
- msm_clear_copp_id(popp_id, port_id[0]);
-
- rc = afe_stop_pseudo_port(port_id[0]);
- if (rc < 0) {
- pr_err("%s: Error %d in Tx pseudo port stop\n",
- __func__, rc);
- goto fail_cmd;
- }
-
- } else if (rec_mode == VOC_REC_DOWNLINK) {
- rc = adm_close(port_id[1]);
- if (rc < 0) {
- pr_err("%s: Error %d in ADM close %d\n",
- __func__, rc, port_id[1]);
-
- goto fail_cmd;
- }
-
- msm_clear_copp_id(popp_id, port_id[1]);
-
- rc = afe_stop_pseudo_port(port_id[1]);
- if (rc < 0) {
- pr_err("%s: Error %d in Rx pseudo port stop\n",
- __func__, rc);
- goto fail_cmd;
- }
- } else if (rec_mode == VOC_REC_BOTH) {
- rc = adm_close(port_id[0]);
- if (rc < 0) {
- pr_err("%s: Error %d in ADM close %d\n",
- __func__, rc, port_id[0]);
-
- goto fail_cmd;
- }
-
- msm_clear_copp_id(popp_id, port_id[0]);
-
- rc = afe_stop_pseudo_port(port_id[0]);
- if (rc < 0) {
- pr_err("%s: Error %d in Tx pseudo port stop\n",
- __func__, rc);
- goto fail_cmd;
- }
-
- rc = adm_close(port_id[1]);
- if (rc < 0) {
- pr_err("%s: Error %d in ADM close %d\n",
- __func__, rc, port_id[1]);
-
- goto fail_cmd;
- }
-
- msm_clear_copp_id(popp_id, port_id[1]);
-
- rc = afe_stop_pseudo_port(port_id[1]);
- if (rc < 0) {
- pr_err("%s: Error %d in Rx pseudo port stop\n",
- __func__, rc);
- goto fail_cmd;
- }
- } else {
- pr_err("%s Unknown rec_mode %d\n", __func__, rec_mode);
-
- goto fail_cmd;
- }
-
-fail_cmd:
- mutex_unlock(&routing_info.adm_mutex);
- return rc;
-}
-
-static long audio_dev_ctrl_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- int rc = 0;
- struct audio_dev_ctrl_state *dev_ctrl = file->private_data;
-
- mutex_lock(&session_lock);
- switch (cmd) {
- case AUDIO_GET_NUM_SND_DEVICE:
- rc = put_user(dev_ctrl->num_dev, (uint32_t __user *) arg);
- break;
- case AUDIO_GET_SND_DEVICES:
- rc = audio_dev_ctrl_get_devices(dev_ctrl, (void __user *) arg);
- break;
- case AUDIO_ENABLE_SND_DEVICE: {
- struct msm_snddev_info *dev_info;
- u32 dev_id;
-
- if (get_user(dev_id, (u32 __user *) arg)) {
- rc = -EFAULT;
- break;
- }
- dev_info = audio_dev_ctrl_find_dev(dev_id);
- if (IS_ERR(dev_info))
- rc = PTR_ERR(dev_info);
- else {
- rc = dev_info->dev_ops.open(dev_info);
- if (!rc)
- dev_info->opened = 1;
- wake_up(&audio_dev_ctrl.wait);
- }
- break;
-
- }
-
- case AUDIO_DISABLE_SND_DEVICE: {
- struct msm_snddev_info *dev_info;
- u32 dev_id;
-
- if (get_user(dev_id, (u32 __user *) arg)) {
- rc = -EFAULT;
- break;
- }
- dev_info = audio_dev_ctrl_find_dev(dev_id);
- if (IS_ERR(dev_info))
- rc = PTR_ERR(dev_info);
- else {
- rc = dev_info->dev_ops.close(dev_info);
- dev_info->opened = 0;
- }
- break;
- }
-
- case AUDIO_ROUTE_STREAM: {
- struct msm_audio_route_config route_cfg;
- struct msm_snddev_info *dev_info;
-
- if (copy_from_user(&route_cfg, (void __user *) arg,
- sizeof(struct msm_audio_route_config))) {
- rc = -EFAULT;
- break;
- }
- pr_debug("%s: route cfg %d %d type\n", __func__,
- route_cfg.dev_id, route_cfg.stream_type);
- dev_info = audio_dev_ctrl_find_dev(route_cfg.dev_id);
- if (IS_ERR(dev_info)) {
- pr_err("%s: pass invalid dev_id\n", __func__);
- rc = PTR_ERR(dev_info);
- break;
- }
-
- switch (route_cfg.stream_type) {
-
- case AUDIO_ROUTE_STREAM_VOICE_RX:
- if (!(dev_info->capability & SNDDEV_CAP_RX) |
- !(dev_info->capability & SNDDEV_CAP_VOICE)) {
- rc = -EINVAL;
- break;
- }
- dev_ctrl->voice_rx_dev = dev_info;
- break;
- case AUDIO_ROUTE_STREAM_VOICE_TX:
- if (!(dev_info->capability & SNDDEV_CAP_TX) |
- !(dev_info->capability & SNDDEV_CAP_VOICE)) {
- rc = -EINVAL;
- break;
- }
- dev_ctrl->voice_tx_dev = dev_info;
- break;
- }
- break;
- }
-
- default:
- rc = -EINVAL;
- }
- mutex_unlock(&session_lock);
- return rc;
-}
-
-static int audio_dev_ctrl_open(struct inode *inode, struct file *file)
-{
- pr_debug("open audio_dev_ctrl\n");
- atomic_inc(&audio_dev_ctrl.opened);
- file->private_data = &audio_dev_ctrl;
- return 0;
-}
-
-static int audio_dev_ctrl_release(struct inode *inode, struct file *file)
-{
- pr_debug("release audio_dev_ctrl\n");
- atomic_dec(&audio_dev_ctrl.opened);
- return 0;
-}
-
-static const struct file_operations audio_dev_ctrl_fops = {
- .owner = THIS_MODULE,
- .open = audio_dev_ctrl_open,
- .release = audio_dev_ctrl_release,
- .unlocked_ioctl = audio_dev_ctrl_ioctl,
-};
-
-
-struct miscdevice audio_dev_ctrl_misc = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = "msm_audio_dev_ctrl",
- .fops = &audio_dev_ctrl_fops,
-};
-
-/* session id is 64 bit routing mask per device
- * 0-15 for voice clients
- * 16-31 for Decoder clients
- * 32-47 for Encoder clients
- * 48-63 Do not care
- */
-void broadcast_event(u32 evt_id, u32 dev_id, u64 session_id)
-{
- int clnt_id = 0, i;
- union auddev_evt_data *evt_payload;
- struct msm_snd_evt_listner *callback;
- struct msm_snddev_info *dev_info = NULL;
- u64 session_mask = 0;
- static int pending_sent;
-
- pr_debug(": evt_id = %d\n", evt_id);
-
- if ((evt_id != AUDDEV_EVT_START_VOICE)
- && (evt_id != AUDDEV_EVT_END_VOICE)
- && (evt_id != AUDDEV_EVT_STREAM_VOL_CHG)
- && (evt_id != AUDDEV_EVT_VOICE_STATE_CHG)) {
- dev_info = audio_dev_ctrl_find_dev(dev_id);
- if (IS_ERR(dev_info)) {
- pr_err("%s: pass invalid dev_id(%d)\n",
- __func__, dev_id);
- return;
- }
- }
-
- if (event.cb != NULL)
- callback = event.cb;
- else
- return;
- mutex_lock(&session_lock);
-
- if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
- routing_info.voice_state = dev_id;
-
- evt_payload = kzalloc(sizeof(union auddev_evt_data),
- GFP_KERNEL);
-
- if (evt_payload == NULL) {
- pr_err("broadcast_event: cannot allocate memory\n");
- mutex_unlock(&session_lock);
- return;
- }
- for (; ;) {
- if (!(evt_id & callback->evt_id)) {
- if (callback->cb_next == NULL)
- break;
- else {
- callback = callback->cb_next;
- continue;
- }
- }
- clnt_id = callback->clnt_id;
- memset(evt_payload, 0, sizeof(union auddev_evt_data));
-
- if ((evt_id == AUDDEV_EVT_START_VOICE)
- || (evt_id == AUDDEV_EVT_END_VOICE)
- || evt_id == AUDDEV_EVT_DEVICE_VOL_MUTE_CHG)
- goto skip_check;
- if (callback->clnt_type == AUDDEV_CLNT_AUDIOCAL)
- goto aud_cal;
-
- session_mask = (((u64)0x1) << clnt_id)
- << (MAX_BIT_PER_CLIENT * \
- ((int)callback->clnt_type-1));
-
- if ((evt_id == AUDDEV_EVT_STREAM_VOL_CHG) || \
- (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)) {
- pr_debug("AUDDEV_EVT_STREAM_VOL_CHG or\
- AUDDEV_EVT_VOICE_STATE_CHG\n");
- goto volume_strm;
- }
-
- pr_debug("dev_info->sessions = %llu\n", dev_info->sessions);
-
- if ((!session_id && !(dev_info->sessions & session_mask)) ||
- (session_id && ((dev_info->sessions & session_mask) !=
- session_id))) {
- if (callback->cb_next == NULL)
- break;
- else {
- callback = callback->cb_next;
- continue;
- }
- }
- if (evt_id == AUDDEV_EVT_DEV_CHG_VOICE)
- goto voc_events;
-
-volume_strm:
- if (callback->clnt_type == AUDDEV_CLNT_DEC) {
- pr_debug("AUDDEV_CLNT_DEC\n");
- if (evt_id == AUDDEV_EVT_STREAM_VOL_CHG) {
- pr_debug("clnt_id = %d, session_id = %llu\n",
- clnt_id, session_id);
- if (session_mask != session_id)
- goto sent_dec;
- else
- evt_payload->session_vol =
- msm_vol_ctl.volume;
- } else if (evt_id == AUDDEV_EVT_FREQ_CHG) {
- if (routing_info.dec_freq[clnt_id].evt) {
- routing_info.dec_freq[clnt_id].evt
- = 0;
- goto sent_dec;
- } else if (routing_info.dec_freq[clnt_id].freq
- == dev_info->set_sample_rate)
- goto sent_dec;
- else {
- evt_payload->freq_info.sample_rate
- = dev_info->set_sample_rate;
- evt_payload->freq_info.dev_type
- = dev_info->capability;
- evt_payload->freq_info.acdb_dev_id
- = dev_info->acdb_id;
- }
- } else if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
- evt_payload->voice_state =
- routing_info.voice_state;
- else
- evt_payload->routing_id = dev_info->copp_id;
- callback->auddev_evt_listener(
- evt_id,
- evt_payload,
- callback->private_data);
-sent_dec:
- if ((evt_id != AUDDEV_EVT_STREAM_VOL_CHG) &&
- (evt_id != AUDDEV_EVT_VOICE_STATE_CHG))
- routing_info.dec_freq[clnt_id].freq
- = dev_info->set_sample_rate;
-
- if (callback->cb_next == NULL)
- break;
- else {
- callback = callback->cb_next;
- continue;
- }
- }
- if (callback->clnt_type == AUDDEV_CLNT_ENC) {
- pr_debug("AUDDEV_CLNT_ENC\n");
- if (evt_id == AUDDEV_EVT_FREQ_CHG) {
- if (routing_info.enc_freq[clnt_id].evt) {
- routing_info.enc_freq[clnt_id].evt
- = 0;
- goto sent_enc;
- } else {
- evt_payload->freq_info.sample_rate
- = dev_info->set_sample_rate;
- evt_payload->freq_info.dev_type
- = dev_info->capability;
- evt_payload->freq_info.acdb_dev_id
- = dev_info->acdb_id;
- }
- } else if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
- evt_payload->voice_state =
- routing_info.voice_state;
- else
- evt_payload->routing_id = dev_info->copp_id;
- callback->auddev_evt_listener(
- evt_id,
- evt_payload,
- callback->private_data);
-sent_enc:
- if (callback->cb_next == NULL)
- break;
- else {
- callback = callback->cb_next;
- continue;
- }
- }
-aud_cal:
- if (callback->clnt_type == AUDDEV_CLNT_AUDIOCAL) {
- pr_debug("AUDDEV_CLNT_AUDIOCAL\n");
- if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
- evt_payload->voice_state =
- routing_info.voice_state;
- else if (!dev_info->sessions)
- goto sent_aud_cal;
- else {
- evt_payload->audcal_info.dev_id =
- dev_info->copp_id;
- evt_payload->audcal_info.acdb_id =
- dev_info->acdb_id;
- evt_payload->audcal_info.dev_type =
- (dev_info->capability & SNDDEV_CAP_TX) ?
- SNDDEV_CAP_TX : SNDDEV_CAP_RX;
- evt_payload->audcal_info.sample_rate =
- dev_info->set_sample_rate ?
- dev_info->set_sample_rate :
- dev_info->sample_rate;
- }
- callback->auddev_evt_listener(
- evt_id,
- evt_payload,
- callback->private_data);
-
-sent_aud_cal:
- if (callback->cb_next == NULL)
- break;
- else {
- callback = callback->cb_next;
- continue;
- }
- }
-skip_check:
-voc_events:
- if (callback->clnt_type == AUDDEV_CLNT_VOC) {
- pr_debug("AUDDEV_CLNT_VOC\n");
- if (evt_id == AUDDEV_EVT_DEV_RLS) {
- if (!pending_sent)
- goto sent_voc;
- else
- pending_sent = 0;
- }
- if (evt_id == AUDDEV_EVT_REL_PENDING)
- pending_sent = 1;
-
- if (evt_id == AUDDEV_EVT_DEVICE_VOL_MUTE_CHG) {
- evt_payload->voc_vm_info.voice_session_id =
- session_id;
-
- if (dev_info->capability & SNDDEV_CAP_TX) {
- evt_payload->voc_vm_info.dev_type =
- SNDDEV_CAP_TX;
- evt_payload->voc_vm_info.acdb_dev_id =
- dev_info->acdb_id;
- evt_payload->
- voc_vm_info.dev_vm_val.mute =
- routing_info.tx_mute;
- } else {
- evt_payload->voc_vm_info.dev_type =
- SNDDEV_CAP_RX;
- evt_payload->voc_vm_info.acdb_dev_id =
- dev_info->acdb_id;
- evt_payload->
- voc_vm_info.dev_vm_val.vol =
- routing_info.voice_rx_vol;
- }
- } else if ((evt_id == AUDDEV_EVT_START_VOICE)
- || (evt_id == AUDDEV_EVT_END_VOICE)) {
- memset(evt_payload, 0,
- sizeof(union auddev_evt_data));
-
- evt_payload->voice_session_id = session_id;
- } else if (evt_id == AUDDEV_EVT_FREQ_CHG) {
- if (routing_info.voice_tx_sample_rate
- != dev_info->set_sample_rate) {
- routing_info.voice_tx_sample_rate
- = dev_info->set_sample_rate;
- evt_payload->freq_info.sample_rate
- = dev_info->set_sample_rate;
- evt_payload->freq_info.dev_type
- = dev_info->capability;
- evt_payload->freq_info.acdb_dev_id
- = dev_info->acdb_id;
- } else
- goto sent_voc;
- } else if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
- evt_payload->voice_state =
- routing_info.voice_state;
- else {
- evt_payload->voc_devinfo.dev_type =
- (dev_info->capability & SNDDEV_CAP_TX) ?
- SNDDEV_CAP_TX : SNDDEV_CAP_RX;
- evt_payload->voc_devinfo.acdb_dev_id =
- dev_info->acdb_id;
- evt_payload->voc_devinfo.dev_port_id =
- dev_info->copp_id;
- evt_payload->voc_devinfo.dev_sample =
- dev_info->set_sample_rate ?
- dev_info->set_sample_rate :
- dev_info->sample_rate;
- evt_payload->voc_devinfo.dev_id = dev_id;
- if (dev_info->capability & SNDDEV_CAP_RX) {
- for (i = 0; i < VOC_RX_VOL_ARRAY_NUM;
- i++) {
- evt_payload->
- voc_devinfo.max_rx_vol[i] =
- dev_info->max_voc_rx_vol[i];
- evt_payload
- ->voc_devinfo.min_rx_vol[i] =
- dev_info->min_voc_rx_vol[i];
- }
- }
- }
- callback->auddev_evt_listener(
- evt_id,
- evt_payload,
- callback->private_data);
- if (evt_id == AUDDEV_EVT_DEV_RLS)
- dev_info->sessions &= ~(0xFFFF);
-sent_voc:
- if (callback->cb_next == NULL)
- break;
- else {
- callback = callback->cb_next;
- continue;
- }
- }
- }
- kfree(evt_payload);
- mutex_unlock(&session_lock);
-}
-EXPORT_SYMBOL(broadcast_event);
-
-
-void mixer_post_event(u32 evt_id, u32 id)
-{
-
- pr_debug("evt_id = %d\n", evt_id);
- switch (evt_id) {
- case AUDDEV_EVT_DEV_CHG_VOICE: /* Called from Voice_route */
- broadcast_event(AUDDEV_EVT_DEV_CHG_VOICE, id, SESSION_IGNORE);
- break;
- case AUDDEV_EVT_DEV_RDY:
- broadcast_event(AUDDEV_EVT_DEV_RDY, id, SESSION_IGNORE);
- break;
- case AUDDEV_EVT_DEV_RLS:
- broadcast_event(AUDDEV_EVT_DEV_RLS, id, SESSION_IGNORE);
- break;
- case AUDDEV_EVT_REL_PENDING:
- broadcast_event(AUDDEV_EVT_REL_PENDING, id, SESSION_IGNORE);
- break;
- case AUDDEV_EVT_DEVICE_VOL_MUTE_CHG:
- broadcast_event(AUDDEV_EVT_DEVICE_VOL_MUTE_CHG, id,
- SESSION_IGNORE);
- break;
- case AUDDEV_EVT_STREAM_VOL_CHG:
- broadcast_event(AUDDEV_EVT_STREAM_VOL_CHG, id,
- SESSION_IGNORE);
- break;
- case AUDDEV_EVT_START_VOICE:
- broadcast_event(AUDDEV_EVT_START_VOICE,
- id, SESSION_IGNORE);
- break;
- case AUDDEV_EVT_END_VOICE:
- broadcast_event(AUDDEV_EVT_END_VOICE,
- id, SESSION_IGNORE);
- break;
- case AUDDEV_EVT_FREQ_CHG:
- broadcast_event(AUDDEV_EVT_FREQ_CHG, id, SESSION_IGNORE);
- break;
- default:
- break;
- }
-}
-EXPORT_SYMBOL(mixer_post_event);
-
-static int __init audio_dev_ctrl_init(void)
-{
- init_waitqueue_head(&audio_dev_ctrl.wait);
-
- event.cb = NULL;
- msm_reset_device_work_queue = create_workqueue("reset_device");
- if (msm_reset_device_work_queue == NULL)
- return -ENOMEM;
- atomic_set(&audio_dev_ctrl.opened, 0);
- audio_dev_ctrl.num_dev = 0;
- audio_dev_ctrl.voice_tx_dev = NULL;
- audio_dev_ctrl.voice_rx_dev = NULL;
- routing_info.voice_state = VOICE_STATE_INVALID;
-
- mutex_init(&adm_tx_topology_tbl.lock);
- mutex_init(&routing_info.copp_list_mutex);
- mutex_init(&routing_info.adm_mutex);
-
- memset(routing_info.copp_list, COPP_IGNORE,
- (sizeof(unsigned int) * MAX_SESSIONS * AFE_MAX_PORTS));
- return misc_register(&audio_dev_ctrl_misc);
-}
-
-static void __exit audio_dev_ctrl_exit(void)
-{
- destroy_workqueue(msm_reset_device_work_queue);
-}
-module_init(audio_dev_ctrl_init);
-module_exit(audio_dev_ctrl_exit);
-
-MODULE_DESCRIPTION("MSM 8K Audio Device Control driver");
-MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils.c b/arch/arm/mach-msm/qdsp6v2/audio_utils.c
index 85af4a7..2f1ff3e 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils.c
@@ -99,7 +99,7 @@
int audio_in_disable(struct q6audio_in *audio)
{
int rc = 0;
- if (audio->opened) {
+ if (!audio->stopped) {
audio->enabled = 0;
audio->opened = 0;
pr_debug("%s:session id %d: inbytes[%d] insamples[%d]\n",
@@ -393,7 +393,7 @@
uint32_t mfield_size = (audio->buf_cfg.meta_info_enable == 0) ? 0 :
(sizeof(unsigned char) +
(sizeof(struct meta_out_dsp)*(audio->buf_cfg.frames_per_buf)));
-
+ memset(&meta, 0, sizeof(meta));
pr_debug("%s:session id %d: read - %d\n", __func__, audio->ac->session,
count);
if (!audio->enabled)
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
index a1463bc..5bdd10a 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
@@ -179,6 +179,16 @@
pr_err("%s[%p]: pause cmd failed rc=%d\n",
__func__, audio, rc);
+ if (rc == 0) {
+ /* Send suspend only if pause was successful */
+ rc = q6asm_cmd(audio->ac, CMD_SUSPEND);
+ if (rc < 0)
+ pr_err("%s[%p]: suspend cmd failed rc=%d\n",
+ __func__, audio, rc);
+ } else
+ pr_err("%s[%p]: not sending suspend since pause failed\n",
+ __func__, audio);
+
} else
pr_err("%s[%p]: Driver not enabled\n", __func__, audio);
return rc;
@@ -1189,6 +1199,7 @@
case AUDIO_GET_STATS: {
struct msm_audio_stats stats;
uint64_t timestamp;
+ memset(&stats, 0, sizeof(struct msm_audio_stats));
stats.byte_count = atomic_read(&audio->in_bytes);
stats.sample_count = atomic_read(&audio->in_samples);
rc = q6asm_get_session_time(audio->ac, ×tamp);
diff --git a/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c b/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c
deleted file mode 100644
index c6def46..0000000
--- a/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c
+++ /dev/null
@@ -1,464 +0,0 @@
-/* Copyright (c) 2011, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#define pr_fmt(fmt) "%s: " fmt, __func__
-
-#include <linux/fs.h>
-#include <linux/module.h>
-#include <linux/miscdevice.h>
-#include <linux/mutex.h>
-#include <linux/sched.h>
-#include <linux/wait.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/uaccess.h>
-#include <linux/dma-mapping.h>
-#include <linux/msm_audio.h>
-#include <mach/msm_hdmi_audio.h>
-#include <mach/audio_dma_msm8k.h>
-#include <sound/dai.h>
-#include <mach/qdsp6v2/q6core.h>
-
-#define DMA_ALLOC_BUF_SZ (SZ_4K * 16)
-
-#define HDMI_AUDIO_FIFO_WATER_MARK 4
-
-struct audio_buffer {
- dma_addr_t phys;
- void *data;
- uint32_t size;
- uint32_t used; /* 1 = CPU is waiting for DMA to consume this buf */
- uint32_t actual_size; /* actual number of bytes read by DMA */
-};
-
-struct lpa_if {
- struct mutex lock;
- struct msm_audio_config cfg;
- struct audio_buffer audio_buf[6];
- int cpu_buf; /* next buffer the CPU will touch */
- int dma_buf; /* next buffer the DMA will touch */
- u8 *buffer;
- dma_addr_t buffer_phys;
- u32 dma_ch;
- wait_queue_head_t wait;
- u32 config;
- u32 dma_period_sz;
- unsigned int num_periods;
-};
-
-static struct lpa_if *lpa_if_ptr;
-
-static unsigned int dma_buf_index;
-
-static irqreturn_t lpa_if_irq(int intrsrc, void *data)
-{
- struct lpa_if *lpa_if = data;
- int dma_ch = 0;
- unsigned int pending;
-
- if (lpa_if)
- dma_ch = lpa_if->dma_ch;
- else {
- pr_err("invalid lpa_if\n");
- return IRQ_NONE;
- }
-
- pending = (intrsrc
- & (UNDER_CH(dma_ch) | PER_CH(dma_ch) | ERR_CH(dma_ch)));
-
- if (pending & UNDER_CH(dma_ch))
- pr_err("under run\n");
- if (pending & ERR_CH(dma_ch))
- pr_err("DMA %x Master Error\n", dma_ch);
-
- if (pending & PER_CH(dma_ch)) {
-
- lpa_if->audio_buf[lpa_if->dma_buf].used = 0;
-
- pr_debug("dma_buf %d used %d\n", lpa_if->dma_buf,
- lpa_if->audio_buf[lpa_if->dma_buf].used);
- lpa_if->dma_buf++;
- lpa_if->dma_buf = lpa_if->dma_buf % lpa_if->cfg.buffer_count;
-
- if (lpa_if->dma_buf == lpa_if->cpu_buf)
- pr_err("Err:both dma_buf and cpu_buf are on same index\n");
- wake_up(&lpa_if->wait);
- }
- return IRQ_HANDLED;
-}
-
-
-int lpa_if_start(struct lpa_if *lpa_if)
-{
- pr_debug("buf1 0x%x, buf2 0x%x dma_ch %d\n",
- (unsigned int)lpa_if->audio_buf[0].data,
- (unsigned int)lpa_if->audio_buf[1].data, lpa_if->dma_ch);
-
- dai_start_hdmi(lpa_if->dma_ch);
-
- hdmi_audio_enable(1, HDMI_AUDIO_FIFO_WATER_MARK);
-
- hdmi_audio_packet_enable(1);
- return 0;
-}
-
-int lpa_if_config(struct lpa_if *lpa_if)
-{
- struct dai_dma_params dma_params;
-
- dma_params.src_start = lpa_if->buffer_phys;
- dma_params.buffer = lpa_if->buffer;
- dma_params.buffer_size = lpa_if->dma_period_sz * lpa_if->num_periods;
- dma_params.period_size = lpa_if->dma_period_sz;
- dma_params.channels = 2;
-
- lpa_if->dma_ch = 4;
- dai_set_params(lpa_if->dma_ch, &dma_params);
-
- register_dma_irq_handler(lpa_if->dma_ch, lpa_if_irq, (void *)lpa_if);
-
- mb();
- pr_debug("lpa_if 0x%08x buf_vir 0x%08x buf_phys 0x%08x "
- "config %u\n", (u32)lpa_if, (u32) (lpa_if->buffer),
- lpa_if->buffer_phys, lpa_if->config);
-
- pr_debug("user_buf_cnt %u user_buf_size %u\n",
- lpa_if->cfg.buffer_count, lpa_if->cfg.buffer_size);
-
- lpa_if->config = 1;
-
- lpa_if_start(lpa_if);
-
- return 0;
-}
-
-
-static long lpa_if_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct lpa_if *lpa_if = file->private_data;
- int rc = 0;
- unsigned int i;
- pr_debug("cmd %u\n", cmd);
-
- mutex_lock(&lpa_if->lock);
-
- switch (cmd) {
- case AUDIO_START:
- pr_debug("AUDIO_START\n");
-
- if (dma_buf_index == 2) {
- if (!lpa_if->config) {
- rc = lpa_if_config(lpa_if);
- if (rc)
- pr_err("lpa_if_config failed\n");
- }
- } else {
- pr_err("did not receved two buffer for "
- "AUDIO_STAR\n");
- rc = -EPERM;
- }
- break;
-
- case AUDIO_STOP:
- pr_debug("AUDIO_STOP\n");
- break;
-
- case AUDIO_FLUSH:
- pr_debug("AUDIO_FLUSH\n");
- break;
-
-
- case AUDIO_GET_CONFIG:
- pr_debug("AUDIO_GET_CONFIG\n");
- if (copy_to_user((void *)arg, &lpa_if->cfg,
- sizeof(struct msm_audio_config))) {
- rc = -EFAULT;
- }
- break;
- case AUDIO_SET_CONFIG: {
- /* Setting default rate as 48khz */
- unsigned int cur_sample_rate =
- HDMI_SAMPLE_RATE_48KHZ;
- struct msm_audio_config config;
-
- pr_debug("AUDIO_SET_CONFIG\n");
- if (copy_from_user(&config, (void *)arg, sizeof(config))) {
- rc = -EFAULT;
- break;
- }
- lpa_if->dma_period_sz = config.buffer_size;
- if ((lpa_if->dma_period_sz * lpa_if->num_periods) >
- DMA_ALLOC_BUF_SZ) {
- pr_err("Dma buffer size greater than allocated size\n");
- return -EINVAL;
- }
- pr_debug("Dma_period_sz %d\n", lpa_if->dma_period_sz);
- if (lpa_if->dma_period_sz < (2 * SZ_4K))
- lpa_if->num_periods = 6;
- pr_debug("No. of Periods %d\n", lpa_if->num_periods);
-
- lpa_if->cfg.buffer_count = lpa_if->num_periods;
- lpa_if->cfg.buffer_size = lpa_if->dma_period_sz *
- lpa_if->num_periods;
-
- for (i = 0; i < lpa_if->cfg.buffer_count; i++) {
- lpa_if->audio_buf[i].phys =
- lpa_if->buffer_phys + i * lpa_if->dma_period_sz;
- lpa_if->audio_buf[i].data =
- lpa_if->buffer + i * lpa_if->dma_period_sz;
- lpa_if->audio_buf[i].size = lpa_if->dma_period_sz;
- lpa_if->audio_buf[i].used = 0;
- }
-
- pr_debug("Sample rate %d\n", config.sample_rate);
- switch (config.sample_rate) {
- case 48000:
- cur_sample_rate = HDMI_SAMPLE_RATE_48KHZ;
- break;
- case 44100:
- cur_sample_rate = HDMI_SAMPLE_RATE_44_1KHZ;
- break;
- case 32000:
- cur_sample_rate = HDMI_SAMPLE_RATE_32KHZ;
- break;
- case 88200:
- cur_sample_rate = HDMI_SAMPLE_RATE_88_2KHZ;
- break;
- case 96000:
- cur_sample_rate = HDMI_SAMPLE_RATE_96KHZ;
- break;
- case 176400:
- cur_sample_rate = HDMI_SAMPLE_RATE_176_4KHZ;
- break;
- case 192000:
- cur_sample_rate = HDMI_SAMPLE_RATE_192KHZ;
- break;
- default:
- cur_sample_rate = HDMI_SAMPLE_RATE_48KHZ;
- }
- if (cur_sample_rate != hdmi_msm_audio_get_sample_rate())
- hdmi_msm_audio_sample_rate_reset(cur_sample_rate);
- else
- pr_debug("Previous sample rate and current"
- "sample rate are same\n");
- break;
- }
- default:
- pr_err("UnKnown Ioctl\n");
- rc = -EINVAL;
- }
-
- mutex_unlock(&lpa_if->lock);
-
- return rc;
-}
-
-
-static int lpa_if_open(struct inode *inode, struct file *file)
-{
- pr_debug("\n");
-
- file->private_data = lpa_if_ptr;
- dma_buf_index = 0;
- lpa_if_ptr->cpu_buf = 2;
- lpa_if_ptr->dma_buf = 0;
- lpa_if_ptr->num_periods = 4;
-
- core_req_bus_bandwith(AUDIO_IF_BUS_ID, 100000, 0);
- mb();
-
- return 0;
-}
-
-static inline int rt_policy(int policy)
-{
- if (unlikely(policy == SCHED_FIFO) || unlikely(policy == SCHED_RR))
- return 1;
- return 0;
-}
-
-static inline int task_has_rt_policy(struct task_struct *p)
-{
- return rt_policy(p->policy);
-}
-static ssize_t lpa_if_write(struct file *file, const char __user *buf,
- size_t count, loff_t *pos)
-{
- struct lpa_if *lpa_if = file->private_data;
- struct audio_buffer *ab;
- const char __user *start = buf;
- int xfer, rc;
- struct sched_param s = { .sched_priority = 1 };
- int old_prio = current->rt_priority;
- int old_policy = current->policy;
- int cap_nice = cap_raised(current_cap(), CAP_SYS_NICE);
-
- /* just for this write, set us real-time */
- if (!task_has_rt_policy(current)) {
- struct cred *new = prepare_creds();
- cap_raise(new->cap_effective, CAP_SYS_NICE);
- commit_creds(new);
- if ((sched_setscheduler(current, SCHED_RR, &s)) < 0)
- pr_err("sched_setscheduler failed\n");
- }
- mutex_lock(&lpa_if->lock);
-
- if (dma_buf_index < 2) {
-
- ab = lpa_if->audio_buf + dma_buf_index;
-
- if (copy_from_user(ab->data, buf, count)) {
- pr_err("copy from user failed\n");
- rc = 0;
- goto end;
-
- }
- mb();
- pr_debug("prefill: count %u audio_buf[%u].size %u\n",
- count, dma_buf_index, ab->size);
-
- ab->used = 1;
- dma_buf_index++;
- rc = count;
- goto end;
- }
-
- if (lpa_if->config != 1) {
- pr_err("AUDIO_START did not happen\n");
- rc = 0;
- goto end;
- }
-
- while (count > 0) {
-
- ab = lpa_if->audio_buf + lpa_if->cpu_buf;
-
- rc = wait_event_timeout(lpa_if->wait, (ab->used == 0), 10 * HZ);
- if (!rc) {
- pr_err("wait_event_timeout failed\n");
- rc = buf - start;
- goto end;
- }
-
- xfer = count;
-
- if (xfer > lpa_if->dma_period_sz)
- xfer = lpa_if->dma_period_sz;
-
- if (copy_from_user(ab->data, buf, xfer)) {
- pr_err("copy from user failed\n");
- rc = buf - start;
- goto end;
- }
-
- mb();
- buf += xfer;
- count -= xfer;
- ab->used = 1;
-
- pr_debug("xfer %d, size %d, used %d cpu_buf %d\n",
- xfer, ab->size, ab->used, lpa_if->cpu_buf);
- lpa_if->cpu_buf++;
- lpa_if->cpu_buf = lpa_if->cpu_buf % lpa_if->cfg.buffer_count;
- }
- rc = buf - start;
-end:
- mutex_unlock(&lpa_if->lock);
- /* restore old scheduling policy */
- if (!rt_policy(old_policy)) {
- struct sched_param v = { .sched_priority = old_prio };
- if ((sched_setscheduler(current, old_policy, &v)) < 0)
- pr_err("sched_setscheduler failed\n");
- if (likely(!cap_nice)) {
- struct cred *new = prepare_creds();
- cap_lower(new->cap_effective, CAP_SYS_NICE);
- commit_creds(new);
- }
- }
- return rc;
-}
-
-static int lpa_if_release(struct inode *inode, struct file *file)
-{
- struct lpa_if *lpa_if = file->private_data;
-
- hdmi_audio_packet_enable(0);
-
- wait_for_dma_cnt_stop(lpa_if->dma_ch);
-
- hdmi_audio_enable(0, HDMI_AUDIO_FIFO_WATER_MARK);
-
- if (lpa_if->config) {
- unregister_dma_irq_handler(lpa_if->dma_ch);
- dai_stop_hdmi(lpa_if->dma_ch);
- lpa_if->config = 0;
- }
- core_req_bus_bandwith(AUDIO_IF_BUS_ID, 0, 0);
-
- if (hdmi_msm_audio_get_sample_rate() != HDMI_SAMPLE_RATE_48KHZ)
- hdmi_msm_audio_sample_rate_reset(HDMI_SAMPLE_RATE_48KHZ);
-
- return 0;
-}
-
-static const struct file_operations lpa_if_fops = {
- .owner = THIS_MODULE,
- .open = lpa_if_open,
- .write = lpa_if_write,
- .release = lpa_if_release,
- .unlocked_ioctl = lpa_if_ioctl,
-};
-
-struct miscdevice lpa_if_misc = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = "msm_lpa_if_out",
- .fops = &lpa_if_fops,
-};
-
-static int __init lpa_if_init(void)
-{
- int rc;
-
- lpa_if_ptr = kzalloc(sizeof(struct lpa_if), GFP_KERNEL);
- if (!lpa_if_ptr) {
- pr_info("No mem for lpa-if\n");
- return -ENOMEM;
- }
-
- mutex_init(&lpa_if_ptr->lock);
- init_waitqueue_head(&lpa_if_ptr->wait);
-
- lpa_if_ptr->buffer = dma_alloc_coherent(NULL, DMA_ALLOC_BUF_SZ,
- &(lpa_if_ptr->buffer_phys), GFP_KERNEL);
- if (!lpa_if_ptr->buffer) {
- pr_err("dma_alloc_coherent failed\n");
- kfree(lpa_if_ptr);
- return -ENOMEM;
- }
-
- pr_info("lpa_if_ptr 0x%08x buf_vir 0x%08x buf_phy 0x%08x "
- " buf_zise %u\n", (u32)lpa_if_ptr,
- (u32)(lpa_if_ptr->buffer), lpa_if_ptr->buffer_phys,
- DMA_ALLOC_BUF_SZ);
-
- rc = misc_register(&lpa_if_misc);
- if (rc < 0) {
- pr_err("misc_register failed\n");
-
- dma_free_coherent(NULL, DMA_ALLOC_BUF_SZ, lpa_if_ptr->buffer,
- lpa_if_ptr->buffer_phys);
- kfree(lpa_if_ptr);
- }
- return rc;
-}
-
-device_initcall(lpa_if_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c b/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c
index 0a50bcc..fc6de64 100644
--- a/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c
+++ b/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c
@@ -269,6 +269,7 @@
} else {
ion_phys_addr_t phys_addr;
size_t phys_len;
+ size_t va_len = 0;
pr_debug("%s: page is NULL\n", __func__);
ret = ion_phys(ab->client, ab->handle, &phys_addr, &phys_len);
@@ -282,6 +283,12 @@
vma, (unsigned int)vma->vm_start,
(unsigned int)vma->vm_end, vma->vm_pgoff,
(unsigned long int)vma->vm_page_prot);
+ va_len = vma->vm_end - vma->vm_start;
+ if ((offset > phys_len) || (va_len > phys_len-offset)) {
+ pr_err("wrong offset size %ld, lens= %d, va_len=%d\n",
+ offset, phys_len, va_len);
+ return -EINVAL;
+ }
ret = remap_pfn_range(vma, vma->vm_start,
__phys_to_pfn(phys_addr) + vma->vm_pgoff,
vma->vm_end - vma->vm_start,
@@ -321,6 +328,11 @@
ion_phys_addr_t *paddr, size_t *pa_len, void **vaddr)
{
int rc = 0;
+ if (!name || !client || !handle || !paddr || !vaddr || !pa_len) {
+ pr_err("%s: Invalid params\n", __func__);
+ rc = -EINVAL;
+ goto err;
+ }
/* client is already created for legacy and given*/
/* name should be audio_acdb_client or Audio_Dec_Client,
bufsz should be 0 and fd shouldn't be 0 as of now
@@ -331,14 +343,16 @@
if (IS_ERR_OR_NULL((void *)(*handle))) {
pr_err("%s: ion import dma buffer failed\n",
__func__);
- goto err_ion_handle;
- }
+ rc = -EINVAL;
+ goto err_destroy_client;
+ }
if (ionflag != NULL) {
rc = ion_handle_get_flags(client, *handle, ionflag);
if (rc) {
pr_err("%s: could not get flags for the handle\n",
__func__);
+ rc = -EINVAL;
goto err_ion_handle;
}
}
@@ -347,6 +361,7 @@
if (rc) {
pr_err("%s: ION Get Physical for AUDIO failed, rc = %d\n",
__func__, rc);
+ rc = -EINVAL;
goto err_ion_handle;
}
@@ -354,6 +369,7 @@
*vaddr = ion_map_kernel(client, *handle);
if (IS_ERR_OR_NULL((void *)*vaddr)) {
pr_err("%s: ION memory mapping for AUDIO failed\n", __func__);
+ rc = -EINVAL;
goto err_ion_handle;
}
@@ -364,8 +380,12 @@
err_ion_handle:
ion_free(client, *handle);
- return -EINVAL;
-
+err_destroy_client:
+ msm_audio_ion_client_destroy(client);
+ client = NULL;
+ *handle = NULL;
+err:
+ return rc;
}
int msm_audio_ion_free_legacy(struct ion_client *client,
diff --git a/arch/arm/mach-msm/qdsp6v2/pcm_in.c b/arch/arm/mach-msm/qdsp6v2/pcm_in.c
index 0db4894..cf7548d 100644
--- a/arch/arm/mach-msm/qdsp6v2/pcm_in.c
+++ b/arch/arm/mach-msm/qdsp6v2/pcm_in.c
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2009 Google, Inc.
* Copyright (C) 2009 HTC Corporation
- * Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2013, 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
@@ -256,6 +256,7 @@
}
case AUDIO_GET_CONFIG: {
struct msm_audio_config config;
+ memset(&config, 0, sizeof(config));
config.buffer_size = pcm->buffer_size;
config.buffer_count = pcm->buffer_count;
config.sample_rate = pcm->sample_rate;
diff --git a/arch/arm/mach-msm/qdsp6v2/pcm_in_proxy.c b/arch/arm/mach-msm/qdsp6v2/pcm_in_proxy.c
index 5faee21..f7bf1ae 100644
--- a/arch/arm/mach-msm/qdsp6v2/pcm_in_proxy.c
+++ b/arch/arm/mach-msm/qdsp6v2/pcm_in_proxy.c
@@ -1,5 +1,5 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -475,6 +475,7 @@
}
case AUDIO_GET_CONFIG: {
struct msm_audio_config config;
+ memset(&config, 0, sizeof(config));
config.buffer_size = pcm->buffer_size;
config.buffer_count = pcm->buffer_count;
config.sample_rate = pcm->sample_rate;
diff --git a/arch/arm/mach-msm/qdsp6v2/q6audio_v2_aio.c b/arch/arm/mach-msm/qdsp6v2/q6audio_v2_aio.c
index 4681437..21040b1 100644
--- a/arch/arm/mach-msm/qdsp6v2/q6audio_v2_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/q6audio_v2_aio.c
@@ -108,9 +108,7 @@
break;
case RESET_EVENTS:
pr_debug("%s: Received opcode:0x%x\n", __func__, opcode);
- audio->event_abort = 1;
audio->stopped = 1;
- audio->enabled = 0;
wake_up(&audio->event_wait);
break;
default:
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h
index bf47366..7ab4ec3 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h
@@ -26,6 +26,8 @@
#define FORMAT_USPS_EPOS 0x00000000
#define FORMAT_USRAW 0x00000001
#define FORMAT_USPROX 0x00000002
+#define FORMAT_USGES_SYNC 0x00000003
+#define FORMAT_USRAW_SYNC 0x00000004
#define INVALID_FORMAT 0xffffffff
#define IN 0x000
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
index 1ea213a..a18d0f3 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
@@ -27,8 +27,8 @@
#include "usfcdev.h"
/* The driver version*/
-#define DRV_VERSION "1.4.2"
-#define USF_VERSION_ID 0x0142
+#define DRV_VERSION "1.5.1"
+#define USF_VERSION_ID 0x0151
/* Standard timeout in the asynchronous ops */
#define USF_TIMEOUT_JIFFIES (1*HZ) /* 1 sec */
@@ -51,12 +51,19 @@
#define Y_IND 1
#define Z_IND 2
+/* Shared memory limits */
+/* max_buf_size = (port_size(65535*2) * port_num(8) * group_size(3) */
+#define USF_MAX_BUF_SIZE 3145680
+#define USF_MAX_BUF_NUM 32
+
/* Place for opreation result, received from QDSP6 */
#define APR_RESULT_IND 1
/* Place for US detection result, received from QDSP6 */
#define APR_US_DETECT_RESULT_IND 0
+#define BITS_IN_BYTE 8
+
/* The driver states */
enum usf_state_type {
USF_IDLE_STATE,
@@ -117,6 +124,8 @@
uint16_t conflicting_event_types;
/* Bitmap of types of events from devs, conflicting with USF */
uint16_t conflicting_event_filters;
+ /* The requested side buttons bitmap */
+ uint16_t req_side_buttons_bitmap;
};
struct usf_input_dev_type {
@@ -146,6 +155,12 @@
0, /* US_INPUT_SRC_UNDEF */
};
+/* Supported buttons container */
+static const int s_button_map[] = {
+ BTN_STYLUS,
+ BTN_STYLUS2
+};
+
/* The opened devices container */
static int s_opened_devs[MAX_DEVS_NUMBER];
@@ -176,14 +191,35 @@
struct us_input_info_type *input_info,
const char *name)
{
+ int i = 0;
+ int num_side_buttons = min(ARRAY_SIZE(s_button_map),
+ sizeof(input_info->req_side_buttons_bitmap) *
+ BITS_IN_BYTE);
+ uint16_t max_side_button_bitmap = ((1 << ARRAY_SIZE(s_button_map)) - 1);
struct input_dev *in_dev = allocate_dev(ind, name);
-
if (in_dev == NULL)
return -ENOMEM;
+ if (input_info->req_side_buttons_bitmap > max_side_button_bitmap) {
+ pr_err("%s: Requested side buttons[%d] exceeds max side buttons available[%d]\n",
+ __func__,
+ input_info->req_side_buttons_bitmap,
+ max_side_button_bitmap);
+ return -EINVAL;
+ }
+
usf_info->input_ifs[ind] = in_dev;
+ usf_info->req_side_buttons_bitmap =
+ input_info->req_side_buttons_bitmap;
in_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
in_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+
+ for (i = 0; i < num_side_buttons; i++)
+ if (input_info->req_side_buttons_bitmap & (1 << i))
+ in_dev->keybit[BIT_WORD(s_button_map[i])] |=
+ BIT_MASK(s_button_map[i]);
+
input_set_abs_params(in_dev, ABS_X,
input_info->tsc_x_dim[MIN_IND],
input_info->tsc_x_dim[MAX_IND],
@@ -260,6 +296,11 @@
struct usf_event_type *event)
{
+ int i = 0;
+ int num_side_buttons = min(ARRAY_SIZE(s_button_map),
+ sizeof(usf_info->req_side_buttons_bitmap) *
+ BITS_IN_BYTE);
+
struct input_dev *input_if = usf_info->input_ifs[if_ind];
struct point_event_type *pe = &(event->event_data.point_event);
@@ -273,19 +314,27 @@
input_report_abs(input_if, ABS_PRESSURE, pe->pressure);
input_report_key(input_if, BTN_TOUCH, !!(pe->pressure));
+ for (i = 0; i < num_side_buttons; i++) {
+ uint16_t mask = (1 << i),
+ btn_state = !!(pe->side_buttons_state_bitmap & mask);
+ if (usf_info->req_side_buttons_bitmap & mask)
+ input_report_key(input_if, s_button_map[i], btn_state);
+ }
+
if (usf_info->event_src)
input_report_key(input_if, usf_info->event_src, 1);
input_sync(input_if);
- pr_debug("%s: TSC event: xyz[%d;%d;%d], incl[%d;%d], pressure[%d]\n",
+ pr_debug("%s: TSC event: xyz[%d;%d;%d], incl[%d;%d], pressure[%d], side_buttons[%d]\n",
__func__,
pe->coordinates[X_IND],
pe->coordinates[Y_IND],
pe->coordinates[Z_IND],
pe->inclinations[X_IND],
pe->inclinations[Y_IND],
- pe->pressure);
+ pe->pressure,
+ pe->side_buttons_state_bitmap);
}
static void notify_mouse_event(struct usf_type *usf_info,
@@ -338,6 +387,8 @@
prepare_mouse_input_device, notify_mouse_event},
{USF_KEYBOARD_EVENT, "usf_kb",
prepare_keyboard_input_device, notify_key_event},
+ {USF_TSC_EXT_EVENT, "usf_tsc_ext",
+ prepare_tsc_input_device, notify_tsc_event},
};
static void usf_rx_cb(uint32_t opcode, uint32_t token,
@@ -436,6 +487,15 @@
(config == NULL))
return -EINVAL;
+ if ((config->buf_size == 0) ||
+ (config->buf_size > USF_MAX_BUF_SIZE) ||
+ (config->buf_num == 0) ||
+ (config->buf_num > USF_MAX_BUF_NUM)) {
+ pr_err("%s: wrong params: buf_size=%d; buf_num=%d\n",
+ __func__, config->buf_size, config->buf_num);
+ return -EINVAL;
+ }
+
data_map_size = sizeof(usf_xx->encdec_cfg.cfg_common.data_map);
min_map_size = min(data_map_size, config->port_cnt);
@@ -748,6 +808,7 @@
{
uint32_t timeout = 0;
struct us_detect_info_type detect_info;
+ struct usm_session_cmd_detect_info *p_allocated_memory = NULL;
struct usm_session_cmd_detect_info usm_detect_info;
struct usm_session_cmd_detect_info *p_usm_detect_info =
&usm_detect_info;
@@ -774,12 +835,13 @@
uint8_t *p_data = NULL;
detect_info_size += detect_info.params_data_size;
- p_usm_detect_info = kzalloc(detect_info_size, GFP_KERNEL);
- if (p_usm_detect_info == NULL) {
+ p_allocated_memory = kzalloc(detect_info_size, GFP_KERNEL);
+ if (p_allocated_memory == NULL) {
pr_err("%s: detect_info[%d] allocation failed\n",
__func__, detect_info_size);
return -ENOMEM;
}
+ p_usm_detect_info = p_allocated_memory;
p_data = (uint8_t *)p_usm_detect_info +
sizeof(struct usm_session_cmd_detect_info);
@@ -789,7 +851,7 @@
if (rc) {
pr_err("%s: copy params from user; rc=%d\n",
__func__, rc);
- kfree(p_usm_detect_info);
+ kfree(p_allocated_memory);
return -EFAULT;
}
p_usm_detect_info->algorithm_cfg_size =
@@ -806,9 +868,7 @@
p_usm_detect_info,
detect_info_size);
if (rc || (detect_info.detect_timeout == USF_NO_WAIT_TIMEOUT)) {
- if (detect_info_size >
- sizeof(struct usm_session_cmd_detect_info))
- kfree(p_usm_detect_info);
+ kfree(p_allocated_memory);
return rc;
}
@@ -828,25 +888,24 @@
USF_US_DETECT_UNDEF),
timeout);
/* In the case of timeout, "no US" is assumed */
- if (rc < 0) {
+ if (rc < 0)
pr_err("%s: Getting US detection failed rc[%d]\n",
__func__, rc);
- return rc;
+ else {
+ usf->usf_rx.us_detect_type = usf->usf_tx.us_detect_type;
+ detect_info.is_us =
+ (usf_xx->us_detect_type == USF_US_DETECT_YES);
+ rc = copy_to_user((void __user *)arg,
+ &detect_info,
+ sizeof(detect_info));
+ if (rc) {
+ pr_err("%s: copy detect_info to user; rc=%d\n",
+ __func__, rc);
+ rc = -EFAULT;
+ }
}
- usf->usf_rx.us_detect_type = usf->usf_tx.us_detect_type;
- detect_info.is_us = (usf_xx->us_detect_type == USF_US_DETECT_YES);
- rc = copy_to_user((void __user *)arg,
- &detect_info,
- sizeof(detect_info));
- if (rc) {
- pr_err("%s: copy detect_info to user; rc=%d\n",
- __func__, rc);
- rc = -EFAULT;
- }
-
- if (detect_info_size > sizeof(struct usm_session_cmd_detect_info))
- kfree(p_usm_detect_info);
+ kfree(p_allocated_memory);
return rc;
} /* usf_set_us_detection */
@@ -947,16 +1006,14 @@
if (rc)
return rc;
- if (usf_xx->buffer_size && usf_xx->buffer_count) {
- rc = q6usm_us_client_buf_alloc(
- IN,
- usf_xx->usc,
- usf_xx->buffer_size,
- usf_xx->buffer_count);
- if (rc) {
- (void)q6usm_cmd(usf_xx->usc, CMD_CLOSE);
- return rc;
- }
+ rc = q6usm_us_client_buf_alloc(
+ IN,
+ usf_xx->usc,
+ usf_xx->buffer_size,
+ usf_xx->buffer_count);
+ if (rc) {
+ (void)q6usm_cmd(usf_xx->usc, CMD_CLOSE);
+ return rc;
}
rc = q6usm_dec_cfg_blk(usf_xx->usc,
@@ -1175,10 +1232,15 @@
return -EFAULT;
}
- /* version_info.buf is pointer to place for the version string */
+ if (version_info.buf_size < sizeof(DRV_VERSION)) {
+ pr_err("%s: buf_size (%d) < version string size (%d)\n",
+ __func__, version_info.buf_size, sizeof(DRV_VERSION));
+ return -EINVAL;
+ }
+
rc = copy_to_user(version_info.pbuf,
DRV_VERSION,
- version_info.buf_size);
+ sizeof(DRV_VERSION));
if (rc) {
pr_err("%s: copy to version_info.pbuf; rc=%d\n",
__func__, rc);
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/usfcdev.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/usfcdev.c
index 1299b96..578a6e5 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/usfcdev.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/usfcdev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -24,8 +24,6 @@
#define SLOT_CMD_ID 0
#define MAX_RETRIES 10
-
-
enum usdev_event_status {
USFCDEV_EVENT_ENABLED,
USFCDEV_EVENT_DISABLING,
@@ -98,8 +96,14 @@
},
};
-/* For each event type, one conflicting device (and handle) is supported */
-static struct input_handle s_usfc_handles[MAX_EVENT_TYPE_NUM] = {
+/*
+ * For each event type, there are a number conflicting devices (handles)
+ * The first registered device (primary) is real TSC device; it's mandatory
+ * Optionally, later registered devices are simulated ones.
+ * They are dynamically managed
+ * The primary device's handles are stored in the below static array
+ */
+static struct input_handle s_usfc_primary_handles[MAX_EVENT_TYPE_NUM] = {
{ /* TSC handle */
.handler = &s_usfc_handlers[TSC_EVENT_TYPE_IND],
.name = "usfc_tsc_handle",
@@ -142,22 +146,48 @@
{
int ret = 0;
uint16_t ind = handler->minor;
+ struct input_handle *usfc_handle = NULL;
- s_usfc_handles[ind].dev = dev;
- ret = input_register_handle(&s_usfc_handles[ind]);
- if (ret) {
+ if (s_usfc_primary_handles[ind].dev == NULL) {
+ pr_debug("%s: primary device; ind=%d\n",
+ __func__,
+ ind);
+ usfc_handle = &s_usfc_primary_handles[ind];
+ } else {
+ pr_debug("%s: secondary device; ind=%d\n",
+ __func__,
+ ind);
+ usfc_handle = kzalloc(sizeof(struct input_handle),
+ GFP_KERNEL);
+ if (!usfc_handle) {
+ pr_err("%s: memory allocation failed; ind=%d\n",
+ __func__,
+ ind);
+ return -ENOMEM;
+ }
+ usfc_handle->handler = &s_usfc_handlers[ind];
+ usfc_handle->name = s_usfc_primary_handles[ind].name;
+ }
+ usfc_handle->dev = dev;
+ ret = input_register_handle(usfc_handle);
+ pr_debug("%s: name=[%s]; ind=%d; dev=0x%p\n",
+ __func__,
+ dev->name,
+ ind,
+ usfc_handle->dev);
+ if (ret)
pr_err("%s: input_register_handle[%d] failed: ret=%d\n",
__func__,
ind,
ret);
- } else {
- ret = input_open_device(&s_usfc_handles[ind]);
+ else {
+ ret = input_open_device(usfc_handle);
if (ret) {
pr_err("%s: input_open_device[%d] failed: ret=%d\n",
__func__,
ind,
ret);
- input_unregister_handle(&s_usfc_handles[ind]);
+ input_unregister_handle(usfc_handle);
} else
pr_debug("%s: device[%d] is opened\n",
__func__,
@@ -169,10 +199,18 @@
static void usfcdev_disconnect(struct input_handle *handle)
{
+ int ind = handle->handler->minor;
+
+ input_close_device(handle);
input_unregister_handle(handle);
- pr_debug("%s: handle[%d] is disconnect\n",
+ pr_debug("%s: handle[%d], name=[%s] is disconnected\n",
__func__,
- handle->handler->minor);
+ ind,
+ handle->dev->name);
+ if (s_usfc_primary_handles[ind].dev == handle->dev)
+ s_usfc_primary_handles[ind].dev = NULL;
+ else
+ kfree(handle);
}
static bool usfcdev_filter(struct input_handle *handle,
@@ -297,8 +335,13 @@
event_type_ind);
return;
}
-
- dev = s_usfc_handles[event_type_ind].dev;
+ /* Only primary device must exist */
+ dev = s_usfc_primary_handles[event_type_ind].dev;
+ if (dev == NULL) {
+ pr_err("%s: NULL primary device\n",
+ __func__);
+ return;
+ }
for (i = 0; i < ARRAY_SIZE(initial_clear_cmds); i++)
usfcdev_send_cmd(dev, initial_clear_cmds[i]);
@@ -307,7 +350,7 @@
/* Send commands to free all slots */
for (i = 0; i < dev->mtsize; i++) {
s_usfcdev_events[event_type_ind].interleaved = false;
- if (input_mt_get_value(&(dev->mt[i]), ABS_MT_TRACKING_ID) < 0) {
+ if (input_mt_get_value(&dev->mt[i], ABS_MT_TRACKING_ID) < 0) {
pr_debug("%s: skipping slot %d",
__func__, i);
continue;
@@ -323,7 +366,7 @@
--i;
continue;
}
- pr_warning("%s: index(%d) reached max retires",
+ pr_warn("%s: index(%d) reached max retires",
__func__, i);
}
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
index fe7c8c2..51a51c5 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
@@ -628,6 +628,12 @@
case FORMAT_USPROX:
int_format = US_PROX_FORMAT_V2;
break;
+ case FORMAT_USGES_SYNC:
+ int_format = US_GES_SYNC_FORMAT;
+ break;
+ case FORMAT_USRAW_SYNC:
+ int_format = US_RAW_SYNC_FORMAT;
+ break;
default:
pr_err("%s: Invalid format[%d]\n", __func__, ext_format);
break;
diff --git a/arch/arm/mach-msm/restart.c b/arch/arm/mach-msm/restart.c
index 37fd650..a96b02f 100644
--- a/arch/arm/mach-msm/restart.c
+++ b/arch/arm/mach-msm/restart.c
@@ -115,6 +115,10 @@
__raw_writel(EMERGENCY_DLOAD_MAGIC3,
emergency_dload_mode_addr +
(2 * sizeof(unsigned int)));
+
+ /* Need disable the pmic wdt, then the emergency dload mode
+ * will not auto reset. */
+ qpnp_pon_wd_config(0);
mb();
}
}
@@ -276,6 +280,8 @@
__raw_writel(0x77665500, restart_reason);
} else if (!strncmp(cmd, "recovery", 8)) {
__raw_writel(0x77665502, restart_reason);
+ } else if (!strcmp(cmd, "rtc")) {
+ __raw_writel(0x77665503, restart_reason);
} else if (!strncmp(cmd, "oem-", 4)) {
unsigned long code;
code = simple_strtoul(cmd + 4, NULL, 16) & 0xff;
diff --git a/arch/arm/mach-msm/rpcrouter_sdio_xprt.c b/arch/arm/mach-msm/rpcrouter_sdio_xprt.c
deleted file mode 100644
index e9818e5..0000000
--- a/arch/arm/mach-msm/rpcrouter_sdio_xprt.c
+++ /dev/null
@@ -1,655 +0,0 @@
-/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-/*
- * RPCROUTER SDIO XPRT module.
- */
-
-#include <linux/platform_device.h>
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/fs.h>
-#include <linux/err.h>
-#include <linux/sched.h>
-#include <linux/poll.h>
-#include <linux/wakelock.h>
-#include <asm/uaccess.h>
-#include <linux/slab.h>
-
-#include <mach/sdio_al.h>
-#include "smd_rpcrouter.h"
-
-enum {
- MSM_SDIO_XPRT_DEBUG = 1U << 0,
- MSM_SDIO_XPRT_INFO = 1U << 1,
-};
-
-static int msm_sdio_xprt_debug_mask;
-module_param_named(debug_mask, msm_sdio_xprt_debug_mask,
- int, S_IRUGO | S_IWUSR | S_IWGRP);
-
-#if defined(CONFIG_MSM_RPC_SDIO_DEBUG)
-#define SDIO_XPRT_DBG(x...) do { \
- if (msm_sdio_xprt_debug_mask & MSM_SDIO_XPRT_DEBUG) \
- printk(KERN_DEBUG x); \
- } while (0)
-
-#define SDIO_XPRT_INFO(x...) do { \
- if (msm_sdio_xprt_debug_mask & MSM_SDIO_XPRT_INFO) \
- printk(KERN_INFO x); \
- } while (0)
-#else
-#define SDIO_XPRT_DBG(x...) do { } while (0)
-#define SDIO_XPRT_INFO(x...) do { } while (0)
-#endif
-
-#define MAX_SDIO_WRITE_RETRY 5
-#define SDIO_BUF_SIZE (RPCROUTER_MSGSIZE_MAX + sizeof(struct rr_header) - 8)
-#define NUM_SDIO_BUFS 20
-#define MAX_TX_BUFS 10
-#define MAX_RX_BUFS 10
-
-struct sdio_xprt {
- struct sdio_channel *handle;
-
- struct list_head write_list;
- spinlock_t write_list_lock;
-
- struct list_head read_list;
- spinlock_t read_list_lock;
-
- struct list_head free_list;
- spinlock_t free_list_lock;
-
- struct wake_lock read_wakelock;
-};
-
-struct rpcrouter_sdio_xprt {
- struct rpcrouter_xprt xprt;
- struct sdio_xprt *channel;
-};
-
-static struct rpcrouter_sdio_xprt sdio_remote_xprt;
-
-static void sdio_xprt_read_data(struct work_struct *work);
-static DECLARE_DELAYED_WORK(work_read_data, sdio_xprt_read_data);
-static struct workqueue_struct *sdio_xprt_read_workqueue;
-
-struct sdio_buf_struct {
- struct list_head list;
- uint32_t size;
- uint32_t read_index;
- uint32_t write_index;
- unsigned char data[SDIO_BUF_SIZE];
-};
-
-static void sdio_xprt_write_data(struct work_struct *work);
-static DECLARE_WORK(work_write_data, sdio_xprt_write_data);
-static wait_queue_head_t write_avail_wait_q;
-static uint32_t num_free_bufs;
-static uint32_t num_tx_bufs;
-static uint32_t num_rx_bufs;
-
-static DEFINE_MUTEX(modem_reset_lock);
-static uint32_t modem_reset;
-
-static void free_sdio_xprt(struct sdio_xprt *chnl)
-{
- struct sdio_buf_struct *buf;
- unsigned long flags;
-
- if (!chnl) {
- printk(KERN_ERR "Invalid chnl to free\n");
- return;
- }
-
- spin_lock_irqsave(&chnl->free_list_lock, flags);
- while (!list_empty(&chnl->free_list)) {
- buf = list_first_entry(&chnl->free_list,
- struct sdio_buf_struct, list);
- list_del(&buf->list);
- kfree(buf);
- }
- num_free_bufs = 0;
- spin_unlock_irqrestore(&chnl->free_list_lock, flags);
-
- spin_lock_irqsave(&chnl->write_list_lock, flags);
- while (!list_empty(&chnl->write_list)) {
- buf = list_first_entry(&chnl->write_list,
- struct sdio_buf_struct, list);
- list_del(&buf->list);
- kfree(buf);
- }
- num_tx_bufs = 0;
- spin_unlock_irqrestore(&chnl->write_list_lock, flags);
-
- spin_lock_irqsave(&chnl->read_list_lock, flags);
- while (!list_empty(&chnl->read_list)) {
- buf = list_first_entry(&chnl->read_list,
- struct sdio_buf_struct, list);
- list_del(&buf->list);
- kfree(buf);
- }
- num_rx_bufs = 0;
- spin_unlock_irqrestore(&chnl->read_list_lock, flags);
- wake_unlock(&chnl->read_wakelock);
-}
-
-static struct sdio_buf_struct *alloc_from_free_list(struct sdio_xprt *chnl)
-{
- struct sdio_buf_struct *buf;
- unsigned long flags;
-
- spin_lock_irqsave(&chnl->free_list_lock, flags);
- if (list_empty(&chnl->free_list)) {
- spin_unlock_irqrestore(&chnl->free_list_lock, flags);
- SDIO_XPRT_DBG("%s: Free list empty\n", __func__);
- return NULL;
- }
- buf = list_first_entry(&chnl->free_list, struct sdio_buf_struct, list);
- list_del(&buf->list);
- num_free_bufs--;
- spin_unlock_irqrestore(&chnl->free_list_lock, flags);
-
- buf->size = 0;
- buf->read_index = 0;
- buf->write_index = 0;
-
- return buf;
-}
-
-static void return_to_free_list(struct sdio_xprt *chnl,
- struct sdio_buf_struct *buf)
-{
- unsigned long flags;
-
- if (!chnl || !buf) {
- pr_err("%s: Invalid chnl or buf\n", __func__);
- return;
- }
-
- buf->size = 0;
- buf->read_index = 0;
- buf->write_index = 0;
-
- spin_lock_irqsave(&chnl->free_list_lock, flags);
- list_add_tail(&buf->list, &chnl->free_list);
- num_free_bufs++;
- spin_unlock_irqrestore(&chnl->free_list_lock, flags);
-
-}
-
-static int rpcrouter_sdio_remote_read_avail(void)
-{
- int read_avail = 0;
- unsigned long flags;
- struct sdio_buf_struct *buf;
-
- spin_lock_irqsave(&sdio_remote_xprt.channel->read_list_lock, flags);
- list_for_each_entry(buf, &sdio_remote_xprt.channel->read_list, list) {
- read_avail += buf->size;
- }
- spin_unlock_irqrestore(&sdio_remote_xprt.channel->read_list_lock,
- flags);
- return read_avail;
-}
-
-static int rpcrouter_sdio_remote_read(void *data, uint32_t len)
-{
- struct sdio_buf_struct *buf;
- unsigned char *buf_data;
- unsigned long flags;
-
- SDIO_XPRT_DBG("sdio_xprt Called %s\n", __func__);
- if (len < 0 || !data)
- return -EINVAL;
- else if (len == 0)
- return 0;
-
- spin_lock_irqsave(&sdio_remote_xprt.channel->read_list_lock, flags);
- if (list_empty(&sdio_remote_xprt.channel->read_list)) {
- spin_unlock_irqrestore(
- &sdio_remote_xprt.channel->read_list_lock, flags);
- return -EINVAL;
- }
-
- buf = list_first_entry(&sdio_remote_xprt.channel->read_list,
- struct sdio_buf_struct, list);
- if (buf->size < len) {
- spin_unlock_irqrestore(
- &sdio_remote_xprt.channel->read_list_lock, flags);
- return -EINVAL;
- }
-
- buf_data = buf->data + buf->read_index;
- memcpy(data, buf_data, len);
- buf->read_index += len;
- buf->size -= len;
- if (buf->size == 0) {
- list_del(&buf->list);
- num_rx_bufs--;
- return_to_free_list(sdio_remote_xprt.channel, buf);
- }
-
- if (list_empty(&sdio_remote_xprt.channel->read_list))
- wake_unlock(&sdio_remote_xprt.channel->read_wakelock);
- spin_unlock_irqrestore(&sdio_remote_xprt.channel->read_list_lock,
- flags);
- return len;
-}
-
-static int rpcrouter_sdio_remote_write_avail(void)
-{
- uint32_t write_avail = 0;
- unsigned long flags;
-
- SDIO_XPRT_DBG("sdio_xprt Called %s\n", __func__);
- spin_lock_irqsave(&sdio_remote_xprt.channel->write_list_lock, flags);
- write_avail = (MAX_TX_BUFS - num_tx_bufs) * SDIO_BUF_SIZE;
- spin_unlock_irqrestore(&sdio_remote_xprt.channel->write_list_lock,
- flags);
- return write_avail;
-}
-
-static int rpcrouter_sdio_remote_write(void *data, uint32_t len,
- enum write_data_type type)
-{
- unsigned long flags;
- static struct sdio_buf_struct *buf;
- unsigned char *buf_data;
-
- switch (type) {
- case HEADER:
- spin_lock_irqsave(&sdio_remote_xprt.channel->write_list_lock,
- flags);
- if (num_tx_bufs == MAX_TX_BUFS) {
- spin_unlock_irqrestore(
- &sdio_remote_xprt.channel->write_list_lock,
- flags);
- return -ENOMEM;
- }
- spin_unlock_irqrestore(
- &sdio_remote_xprt.channel->write_list_lock, flags);
-
- SDIO_XPRT_DBG("sdio_xprt WRITE HEADER %s\n", __func__);
- buf = alloc_from_free_list(sdio_remote_xprt.channel);
- if (!buf) {
- pr_err("%s: alloc_from_free_list failed\n", __func__);
- return -ENOMEM;
- }
- buf_data = buf->data + buf->write_index;
- memcpy(buf_data, data, len);
- buf->write_index += len;
- buf->size += len;
- return len;
- case PACKMARK:
- SDIO_XPRT_DBG("sdio_xprt WRITE PACKMARK %s\n", __func__);
- if (!buf) {
- pr_err("%s: HEADER not written or alloc failed\n",
- __func__);
- return -ENOMEM;
- }
- buf_data = buf->data + buf->write_index;
- memcpy(buf_data, data, len);
- buf->write_index += len;
- buf->size += len;
- return len;
- case PAYLOAD:
- SDIO_XPRT_DBG("sdio_xprt WRITE PAYLOAD %s\n", __func__);
- if (!buf) {
- pr_err("%s: HEADER not written or alloc failed\n",
- __func__);
- return -ENOMEM;
- }
- buf_data = buf->data + buf->write_index;
- memcpy(buf_data, data, len);
- buf->write_index += len;
- buf->size += len;
-
- SDIO_XPRT_DBG("sdio_xprt flush %d bytes\n", buf->size);
- spin_lock_irqsave(&sdio_remote_xprt.channel->write_list_lock,
- flags);
- list_add_tail(&buf->list,
- &sdio_remote_xprt.channel->write_list);
- num_tx_bufs++;
- spin_unlock_irqrestore(
- &sdio_remote_xprt.channel->write_list_lock, flags);
- queue_work(sdio_xprt_read_workqueue, &work_write_data);
- buf = NULL;
- return len;
- default:
- return -EINVAL;
- }
-}
-
-static void sdio_xprt_write_data(struct work_struct *work)
-{
- int rc = 0, sdio_write_retry = 0;
- unsigned long flags;
- struct sdio_buf_struct *buf;
-
- mutex_lock(&modem_reset_lock);
- if (modem_reset) {
- mutex_unlock(&modem_reset_lock);
- return;
- }
-
- spin_lock_irqsave(&sdio_remote_xprt.channel->write_list_lock, flags);
- while (!list_empty(&sdio_remote_xprt.channel->write_list)) {
- buf = list_first_entry(&sdio_remote_xprt.channel->write_list,
- struct sdio_buf_struct, list);
- list_del(&buf->list);
- spin_unlock_irqrestore(
- &sdio_remote_xprt.channel->write_list_lock, flags);
- mutex_unlock(&modem_reset_lock);
-
- wait_event(write_avail_wait_q,
- (!(modem_reset) && (sdio_write_avail(
- sdio_remote_xprt.channel->handle) >=
- buf->size)));
-
- mutex_lock(&modem_reset_lock);
- while (!(modem_reset) &&
- ((rc = sdio_write(sdio_remote_xprt.channel->handle,
- buf->data, buf->size)) < 0) &&
- (sdio_write_retry++ < MAX_SDIO_WRITE_RETRY)) {
- printk(KERN_ERR "sdio_write failed with RC %d\n", rc);
- mutex_unlock(&modem_reset_lock);
- msleep(250);
- mutex_lock(&modem_reset_lock);
- }
- if (modem_reset) {
- mutex_unlock(&modem_reset_lock);
- kfree(buf);
- return;
- } else {
- return_to_free_list(sdio_remote_xprt.channel, buf);
- }
-
- if (!rc)
- SDIO_XPRT_DBG("sdio_write %d bytes completed\n",
- buf->size);
-
- spin_lock_irqsave(&sdio_remote_xprt.channel->write_list_lock,
- flags);
- num_tx_bufs--;
- }
- spin_unlock_irqrestore(&sdio_remote_xprt.channel->write_list_lock,
- flags);
- mutex_unlock(&modem_reset_lock);
-}
-
-static int rpcrouter_sdio_remote_close(void)
-{
- SDIO_XPRT_DBG("sdio_xprt Called %s\n", __func__);
- flush_workqueue(sdio_xprt_read_workqueue);
- sdio_close(sdio_remote_xprt.channel->handle);
- free_sdio_xprt(sdio_remote_xprt.channel);
- return 0;
-}
-
-static void sdio_xprt_read_data(struct work_struct *work)
-{
- int size = 0, read_avail;
- unsigned long flags;
- struct sdio_buf_struct *buf;
- SDIO_XPRT_DBG("sdio_xprt Called %s\n", __func__);
-
- mutex_lock(&modem_reset_lock);
- while (!(modem_reset) &&
- ((read_avail =
- sdio_read_avail(sdio_remote_xprt.channel->handle)) > 0)) {
- spin_lock_irqsave(&sdio_remote_xprt.channel->read_list_lock,
- flags);
- if (num_rx_bufs == MAX_RX_BUFS) {
- spin_unlock_irqrestore(
- &sdio_remote_xprt.channel->read_list_lock,
- flags);
- queue_delayed_work(sdio_xprt_read_workqueue,
- &work_read_data,
- msecs_to_jiffies(100));
- break;
- }
- spin_unlock_irqrestore(
- &sdio_remote_xprt.channel->read_list_lock, flags);
-
- buf = alloc_from_free_list(sdio_remote_xprt.channel);
- if (!buf) {
- SDIO_XPRT_DBG("%s: Failed to alloc_from_free_list"
- " Try again later\n", __func__);
- queue_delayed_work(sdio_xprt_read_workqueue,
- &work_read_data,
- msecs_to_jiffies(100));
- break;
- }
-
- size = sdio_read(sdio_remote_xprt.channel->handle,
- buf->data, read_avail);
- if (size < 0) {
- printk(KERN_ERR "sdio_read failed,"
- " read %d bytes, expected %d\n",
- size, read_avail);
- return_to_free_list(sdio_remote_xprt.channel, buf);
- queue_delayed_work(sdio_xprt_read_workqueue,
- &work_read_data,
- msecs_to_jiffies(100));
- break;
- }
-
- if (size == 0)
- size = read_avail;
-
- buf->size = size;
- buf->write_index = size;
- spin_lock_irqsave(&sdio_remote_xprt.channel->read_list_lock,
- flags);
- list_add_tail(&buf->list,
- &sdio_remote_xprt.channel->read_list);
- num_rx_bufs++;
- spin_unlock_irqrestore(
- &sdio_remote_xprt.channel->read_list_lock, flags);
- wake_lock(&sdio_remote_xprt.channel->read_wakelock);
- }
-
- if (!modem_reset && !list_empty(&sdio_remote_xprt.channel->read_list))
- msm_rpcrouter_xprt_notify(&sdio_remote_xprt.xprt,
- RPCROUTER_XPRT_EVENT_DATA);
- mutex_unlock(&modem_reset_lock);
-}
-
-static void rpcrouter_sdio_remote_notify(void *_dev, unsigned event)
-{
- if (event == SDIO_EVENT_DATA_READ_AVAIL) {
- SDIO_XPRT_DBG("%s Received Notify"
- "SDIO_EVENT_DATA_READ_AVAIL\n", __func__);
- queue_delayed_work(sdio_xprt_read_workqueue,
- &work_read_data, 0);
- }
- if (event == SDIO_EVENT_DATA_WRITE_AVAIL) {
- SDIO_XPRT_DBG("%s Received Notify"
- "SDIO_EVENT_DATA_WRITE_AVAIL\n", __func__);
- wake_up(&write_avail_wait_q);
- }
-}
-
-static int allocate_sdio_xprt(struct sdio_xprt **sdio_xprt_chnl)
-{
- struct sdio_buf_struct *buf;
- struct sdio_xprt *chnl;
- int i;
- unsigned long flags;
- int rc = -ENOMEM;
-
- if (!(*sdio_xprt_chnl)) {
- chnl = kmalloc(sizeof(struct sdio_xprt), GFP_KERNEL);
- if (!chnl) {
- printk(KERN_ERR "sdio_xprt channel"
- " allocation failed\n");
- return rc;
- }
-
- spin_lock_init(&chnl->write_list_lock);
- spin_lock_init(&chnl->read_list_lock);
- spin_lock_init(&chnl->free_list_lock);
-
- INIT_LIST_HEAD(&chnl->write_list);
- INIT_LIST_HEAD(&chnl->read_list);
- INIT_LIST_HEAD(&chnl->free_list);
- wake_lock_init(&chnl->read_wakelock,
- WAKE_LOCK_SUSPEND, "rpc_sdio_xprt_read");
- } else {
- chnl = *sdio_xprt_chnl;
- }
-
- for (i = 0; i < NUM_SDIO_BUFS; i++) {
- buf = kzalloc(sizeof(struct sdio_buf_struct), GFP_KERNEL);
- if (!buf) {
- printk(KERN_ERR "sdio_buf_struct alloc failed\n");
- goto alloc_failure;
- }
- spin_lock_irqsave(&chnl->free_list_lock, flags);
- list_add_tail(&buf->list, &chnl->free_list);
- spin_unlock_irqrestore(&chnl->free_list_lock, flags);
- }
- num_free_bufs = NUM_SDIO_BUFS;
-
- *sdio_xprt_chnl = chnl;
- return 0;
-
-alloc_failure:
- spin_lock_irqsave(&chnl->free_list_lock, flags);
- while (!list_empty(&chnl->free_list)) {
- buf = list_first_entry(&chnl->free_list,
- struct sdio_buf_struct,
- list);
- list_del(&buf->list);
- kfree(buf);
- }
- spin_unlock_irqrestore(&chnl->free_list_lock, flags);
- wake_lock_destroy(&chnl->read_wakelock);
-
- kfree(chnl);
- *sdio_xprt_chnl = NULL;
- return rc;
-}
-
-static int rpcrouter_sdio_remote_probe(struct platform_device *pdev)
-{
- int rc;
-
- SDIO_XPRT_INFO("%s Called\n", __func__);
-
- mutex_lock(&modem_reset_lock);
- if (!modem_reset) {
- sdio_xprt_read_workqueue =
- create_singlethread_workqueue("sdio_xprt");
- if (!sdio_xprt_read_workqueue) {
- mutex_unlock(&modem_reset_lock);
- return -ENOMEM;
- }
-
- sdio_remote_xprt.xprt.name = "rpcrotuer_sdio_xprt";
- sdio_remote_xprt.xprt.read_avail =
- rpcrouter_sdio_remote_read_avail;
- sdio_remote_xprt.xprt.read = rpcrouter_sdio_remote_read;
- sdio_remote_xprt.xprt.write_avail =
- rpcrouter_sdio_remote_write_avail;
- sdio_remote_xprt.xprt.write = rpcrouter_sdio_remote_write;
- sdio_remote_xprt.xprt.close = rpcrouter_sdio_remote_close;
- sdio_remote_xprt.xprt.priv = NULL;
-
- init_waitqueue_head(&write_avail_wait_q);
- }
- modem_reset = 0;
-
- rc = allocate_sdio_xprt(&sdio_remote_xprt.channel);
- if (rc) {
- destroy_workqueue(sdio_xprt_read_workqueue);
- mutex_unlock(&modem_reset_lock);
- return rc;
- }
-
- /* Open up SDIO channel */
- rc = sdio_open("SDIO_RPC", &sdio_remote_xprt.channel->handle, NULL,
- rpcrouter_sdio_remote_notify);
-
- if (rc < 0) {
- free_sdio_xprt(sdio_remote_xprt.channel);
- destroy_workqueue(sdio_xprt_read_workqueue);
- mutex_unlock(&modem_reset_lock);
- return rc;
- }
- mutex_unlock(&modem_reset_lock);
-
- msm_rpcrouter_xprt_notify(&sdio_remote_xprt.xprt,
- RPCROUTER_XPRT_EVENT_OPEN);
-
- SDIO_XPRT_INFO("%s Completed\n", __func__);
-
- return 0;
-}
-
-static int rpcrouter_sdio_remote_remove(struct platform_device *pdev)
-{
- SDIO_XPRT_INFO("%s Called\n", __func__);
-
- mutex_lock(&modem_reset_lock);
- modem_reset = 1;
- wake_up(&write_avail_wait_q);
- free_sdio_xprt(sdio_remote_xprt.channel);
- mutex_unlock(&modem_reset_lock);
-
- msm_rpcrouter_xprt_notify(&sdio_remote_xprt.xprt,
- RPCROUTER_XPRT_EVENT_CLOSE);
-
- SDIO_XPRT_INFO("%s Completed\n", __func__);
-
- return 0;
-}
-
-/*Remove this platform driver after mainline of SDIO_AL update*/
-static struct platform_driver rpcrouter_sdio_remote_driver = {
- .probe = rpcrouter_sdio_remote_probe,
- .driver = {
- .name = "SDIO_AL",
- .owner = THIS_MODULE,
- },
-};
-
-static struct platform_driver rpcrouter_sdio_driver = {
- .probe = rpcrouter_sdio_remote_probe,
- .remove = rpcrouter_sdio_remote_remove,
- .driver = {
- .name = "SDIO_RPC",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init rpcrouter_sdio_init(void)
-{
- int rc;
- msm_sdio_xprt_debug_mask = 0x2;
- rc = platform_driver_register(&rpcrouter_sdio_remote_driver);
- if (rc < 0)
- return rc;
- return platform_driver_register(&rpcrouter_sdio_driver);
-}
-
-module_init(rpcrouter_sdio_init);
-MODULE_DESCRIPTION("RPC Router SDIO XPRT");
-MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/rpm-notifier.h b/arch/arm/mach-msm/rpm-notifier.h
index 16de77e..1f4fdab 100644
--- a/arch/arm/mach-msm/rpm-notifier.h
+++ b/arch/arm/mach-msm/rpm-notifier.h
@@ -42,10 +42,11 @@
* msm_rpm_enter_sleep - Notify RPM driver to prepare for entering sleep
*
* @bool - flag to enable print contents of sleep buffer.
+ * @cpumask - cpumask of next wakeup cpu
*
* return 0 on success errno on failure.
*/
-int msm_rpm_enter_sleep(bool print);
+int msm_rpm_enter_sleep(bool print, const struct cpumask *cpumask);
/**
* msm_rpm_exit_sleep - Notify RPM driver about resuming from power collapse
diff --git a/arch/arm/mach-msm/rpm-regulator-smd.c b/arch/arm/mach-msm/rpm-regulator-smd.c
index 923e647..7995e9a 100644
--- a/arch/arm/mach-msm/rpm-regulator-smd.c
+++ b/arch/arm/mach-msm/rpm-regulator-smd.c
@@ -864,7 +864,7 @@
load_mA = params[RPM_REGULATOR_PARAM_CURRENT].max;
rpm_vreg_lock(reg->rpm_vreg);
- RPM_VREG_SET_PARAM(reg, CURRENT, MICRO_TO_MILLI(load_uA));
+ RPM_VREG_SET_PARAM(reg, CURRENT, load_mA);
rpm_vreg_unlock(reg->rpm_vreg);
return (load_uA >= reg->rpm_vreg->hpm_min_load)
@@ -917,7 +917,6 @@
if (priv_reg == NULL) {
vreg_err(framework_reg, "could not allocate memory for "
"regulator\n");
- rpm_vreg_unlock(rpm_vreg);
return ERR_PTR(-ENOMEM);
}
@@ -930,7 +929,6 @@
vreg_err(framework_reg, "could not allocate memory for "
"regulator_dev\n");
kfree(priv_reg);
- rpm_vreg_unlock(rpm_vreg);
return ERR_PTR(-ENOMEM);
}
priv_reg->rdev->reg_data = priv_reg;
@@ -1266,14 +1264,16 @@
{
struct device *dev = &pdev->dev;
struct rpm_regulator *reg;
+ struct rpm_vreg *rpm_vreg;
reg = platform_get_drvdata(pdev);
if (reg) {
- rpm_vreg_lock(reg->rpm_vreg);
+ rpm_vreg = reg->rpm_vreg;
+ rpm_vreg_lock(rpm_vreg);
regulator_unregister(reg->rdev);
list_del(®->list);
kfree(reg);
- rpm_vreg_unlock(reg->rpm_vreg);
+ rpm_vreg_unlock(rpm_vreg);
} else {
dev_err(dev, "%s: drvdata missing\n", __func__);
return -EINVAL;
diff --git a/arch/arm/mach-msm/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c
index ccab6e2..2a01a36 100644
--- a/arch/arm/mach-msm/rpm-smd.c
+++ b/arch/arm/mach-msm/rpm-smd.c
@@ -130,8 +130,7 @@
bool valid;
};
static struct rb_root tr_root = RB_ROOT;
-
-static int msm_rpm_send_smd_buffer(char *buf, int size, bool noirq);
+static int msm_rpm_send_smd_buffer(char *buf, uint32_t size, bool noirq);
static uint32_t msm_rpm_get_next_msg_id(void);
static inline unsigned int get_rsc_type(char *buf)
@@ -187,7 +186,8 @@
static void delete_kvp(char *msg, struct kvp *d)
{
struct kvp *n;
- int dec, size;
+ int dec;
+ uint32_t size;
n = get_next_kvp(d);
dec = (void *)n - (void *)d;
@@ -206,7 +206,7 @@
static void add_kvp(char *buf, struct kvp *n)
{
- int inc = sizeof(*n) + n->s;
+ uint32_t inc = sizeof(*n) + n->s;
BUG_ON((get_req_len(buf) + inc) > MAX_SLEEP_BUFFER);
memcpy(buf + get_buf_len(buf), n, inc);
@@ -311,7 +311,7 @@
}
}
-int msm_rpm_smd_buffer_request(char *buf, int size, gfp_t flag)
+int msm_rpm_smd_buffer_request(char *buf, uint32_t size, gfp_t flag)
{
struct slp_buf *slp;
static DEFINE_SPINLOCK(slp_buffer_lock);
@@ -367,7 +367,7 @@
pos += scnprintf(buf + pos, buflen - pos, " id = 0%x",
get_rsc_id(s->buf));
for_each_kvp(s->buf, e) {
- int i;
+ uint32_t i;
char *data = get_data(e);
memcpy(ch, &e->k, sizeof(u32));
@@ -482,14 +482,17 @@
static int msm_rpm_add_kvp_data_common(struct msm_rpm_request *handle,
uint32_t key, const uint8_t *data, int size, bool noirq)
{
- int i;
- int data_size, msg_size;
+ uint32_t i;
+ uint32_t data_size, msg_size;
if (!handle) {
pr_err("%s(): Invalid handle\n", __func__);
return -EINVAL;
}
+ if (size < 0)
+ return -EINVAL;
+
data_size = ALIGN(size, SZ_4);
msg_size = data_size + sizeof(struct rpm_request_header);
@@ -813,7 +816,7 @@
static int msm_rpm_read_smd_data(char *buf)
{
- int pkt_sz;
+ uint32_t pkt_sz;
int bytes_read = 0;
pkt_sz = smd_cur_packet_size(msm_rpm_data.ch_info);
@@ -867,7 +870,8 @@
size_t buflen = DEBUG_PRINT_BUFFER_SIZE;
char name[5];
u32 value;
- int i, j, prev_valid;
+ uint32_t i;
+ int j, prev_valid;
int valid_count = 0;
int pos = 0;
@@ -992,7 +996,7 @@
pos += scnprintf(buf + pos, buflen - pos, "\n");
printk(buf);
}
-static int msm_rpm_send_smd_buffer(char *buf, int size, bool noirq)
+static int msm_rpm_send_smd_buffer(char *buf, uint32_t size, bool noirq)
{
unsigned long flags;
int ret;
@@ -1027,8 +1031,9 @@
int msg_type, bool noirq)
{
uint8_t *tmpbuff;
- int i, ret, msg_size;
-
+ int ret;
+ uint32_t i;
+ uint32_t msg_size;
int req_hdr_sz, msg_hdr_sz;
if (!cdata->msg_hdr.data_len)
@@ -1287,14 +1292,14 @@
* During power collapse, the rpm driver disables the SMD interrupts to make
* sure that the interrupt doesn't wakes us from sleep.
*/
-int msm_rpm_enter_sleep(bool print)
+int msm_rpm_enter_sleep(bool print, const struct cpumask *cpumask)
{
if (standalone)
return 0;
msm_rpm_flush_requests(print);
- return smd_mask_receive_interrupt(msm_rpm_data.ch_info, true);
+ return smd_mask_receive_interrupt(msm_rpm_data.ch_info, true, cpumask);
}
EXPORT_SYMBOL(msm_rpm_enter_sleep);
@@ -1307,7 +1312,7 @@
if (standalone)
return;
- smd_mask_receive_interrupt(msm_rpm_data.ch_info, false);
+ smd_mask_receive_interrupt(msm_rpm_data.ch_info, false, NULL);
}
EXPORT_SYMBOL(msm_rpm_exit_sleep);
diff --git a/arch/arm/mach-msm/rpm_stats.c b/arch/arm/mach-msm/rpm_stats.c
index cb8ed19..1447854 100644
--- a/arch/arm/mach-msm/rpm_stats.c
+++ b/arch/arm/mach-msm/rpm_stats.c
@@ -54,7 +54,7 @@
u32 num_records;
u32 read_idx;
u32 len;
- char buf[256];
+ char buf[320];
struct msm_rpmstats_platform_data *platform_data;
};
@@ -64,7 +64,8 @@
u64 last_entered_at;
u64 last_exited_at;
u64 accumulated;
- u32 reserved[4];
+ u32 client_votes;
+ u32 reserved[3];
};
static inline u64 get_time_in_sec(u64 counter)
@@ -98,10 +99,12 @@
actual_last_sleep = get_time_in_msec(data->accumulated);
return snprintf(buf , buflength,
- "RPM Mode:%s\n\t count:%d\n time in last mode(msec):%llu\n"
- "time since last mode(sec):%llu\n actual last sleep(msec):%llu\n",
+ "RPM Mode:%s\n\t count:%d\ntime in last mode(msec):%llu\n"
+ "time since last mode(sec):%llu\nactual last sleep(msec):%llu\n"
+ "client votes: %#010x\n\n",
stat_type, data->count, time_in_last_mode,
- time_since_last_mode, actual_last_sleep);
+ time_since_last_mode, actual_last_sleep,
+ data->client_votes);
}
static inline u32 msm_rpmstats_read_long_register_v2(void __iomem *regbase,
@@ -147,6 +150,9 @@
data.accumulated = msm_rpmstats_read_quad_register_v2(reg,
i, offsetof(struct msm_rpm_stats_data_v2,
accumulated));
+ data.client_votes = msm_rpmstats_read_long_register_v2(reg,
+ i, offsetof(struct msm_rpm_stats_data_v2,
+ client_votes));
length += msm_rpmstats_append_data_to_buf(prvdata->buf + length,
&data, sizeof(prvdata->buf) - length);
prvdata->read_idx++;
diff --git a/arch/arm/mach-msm/sdio_al.c b/arch/arm/mach-msm/sdio_al.c
deleted file mode 100644
index bcfc556..0000000
--- a/arch/arm/mach-msm/sdio_al.c
+++ /dev/null
@@ -1,4365 +0,0 @@
-/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-/*
- * SDIO-Abstraction-Layer Module.
- *
- * To be used with Qualcomm's SDIO-Client connected to this host.
- */
-#include "sdio_al_private.h"
-
-#include <linux/module.h>
-#include <linux/scatterlist.h>
-#include <linux/workqueue.h>
-#include <linux/wait.h>
-#include <linux/delay.h>
-#include <linux/fs.h>
-#include <linux/slab.h>
-#include <linux/wakelock.h>
-#include <linux/mmc/core.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/mmc.h>
-#include <linux/mmc/sdio.h>
-#include <linux/mmc/sdio_func.h>
-#include <linux/mmc/sdio_ids.h>
-#include <linux/gpio.h>
-#include <linux/dma-mapping.h>
-#include <linux/earlysuspend.h>
-#include <linux/debugfs.h>
-#include <linux/uaccess.h>
-#include <linux/syscalls.h>
-#include <linux/time.h>
-#include <linux/spinlock.h>
-
-#include <mach/dma.h>
-#include <mach/gpio.h>
-#include <mach/subsystem_notif.h>
-
-#include "../../../drivers/mmc/host/msm_sdcc.h"
-
-/**
- * Func#0 has SDIO standard registers
- * Func#1 is for Mailbox.
- * Functions 2..7 are for channels.
- * Currently only functions 2..5 are active due to SDIO-Client
- * number of pipes.
- *
- */
-#define SDIO_AL_MAX_CHANNELS 6
-
-/** Func 1..5 */
-#define SDIO_AL_MAX_FUNCS (SDIO_AL_MAX_CHANNELS+1)
-#define SDIO_AL_WAKEUP_FUNC 6
-
-/** Number of SDIO-Client pipes */
-#define SDIO_AL_MAX_PIPES 16
-#define SDIO_AL_ACTIVE_PIPES 8
-
-/** CMD53/CMD54 Block size */
-#define SDIO_AL_BLOCK_SIZE 256
-
-/** Func#1 hardware Mailbox base address */
-#define HW_MAILBOX_ADDR 0x1000
-
-/** Func#1 peer sdioc software version.
- * The header is duplicated also to the mailbox of the other
- * functions. It can be used before other functions are enabled. */
-#define SDIOC_SW_HEADER_ADDR 0x0400
-
-/** Func#2..7 software Mailbox base address at 16K */
-#define SDIOC_SW_MAILBOX_ADDR 0x4000
-
-/** Some Mailbox registers address, written by host for
- control */
-#define PIPES_THRESHOLD_ADDR 0x01000
-
-#define PIPES_0_7_IRQ_MASK_ADDR 0x01048
-
-#define PIPES_8_15_IRQ_MASK_ADDR 0x0104C
-
-#define FUNC_1_4_MASK_IRQ_ADDR 0x01040
-#define FUNC_5_7_MASK_IRQ_ADDR 0x01044
-#define FUNC_1_4_USER_IRQ_ADDR 0x01050
-#define FUNC_5_7_USER_IRQ_ADDR 0x01054
-
-#define EOT_PIPES_ENABLE 0x00
-
-/** Maximum read/write data available is SDIO-Client limitation */
-#define MAX_DATA_AVAILABLE (16*1024)
-#define INVALID_DATA_AVAILABLE (0x8000)
-
-/** SDIO-Client HW threshold to generate interrupt to the
- * SDIO-Host on write available bytes.
- */
-#define DEFAULT_WRITE_THRESHOLD (1024)
-
-/** SDIO-Client HW threshold to generate interrupt to the
- * SDIO-Host on read available bytes, for streaming (non
- * packet) rx data.
- */
-#define DEFAULT_READ_THRESHOLD (1024)
-#define LOW_LATENCY_THRESHOLD (1)
-
-/* Extra bytes to ensure getting the rx threshold interrupt on stream channels
- when restoring the threshold after sleep */
-#define THRESHOLD_CHANGE_EXTRA_BYTES (100)
-
-/** SW threshold to trigger reading the mailbox. */
-#define DEFAULT_MIN_WRITE_THRESHOLD (1024)
-#define DEFAULT_MIN_WRITE_THRESHOLD_STREAMING (1600)
-
-#define THRESHOLD_DISABLE_VAL (0xFFFFFFFF)
-
-/** Mailbox polling time for packet channels */
-#define DEFAULT_POLL_DELAY_MSEC 10
-/** Mailbox polling time for streaming channels */
-#define DEFAULT_POLL_DELAY_NOPACKET_MSEC 30
-
-/** The SDIO-Client prepares N buffers of size X per Tx pipe.
- * Even when the transfer fills a partial buffer,
- * that buffer becomes unusable for the next transfer. */
-#define DEFAULT_PEER_TX_BUF_SIZE (128)
-
-#define ROUND_UP(x, n) (((x + n - 1) / n) * n)
-
-/** Func#2..7 FIFOs are r/w via
- sdio_readsb() & sdio_writesb(),when inc_addr=0 */
-#define PIPE_RX_FIFO_ADDR 0x00
-#define PIPE_TX_FIFO_ADDR 0x00
-
-/** Inactivity time to go to sleep in mseconds */
-#define INACTIVITY_TIME_MSEC 30
-#define INITIAL_INACTIVITY_TIME_MSEC 5000
-
-/** Context validity check */
-#define SDIO_AL_SIGNATURE 0xAABBCCDD
-
-/* Vendor Specific Command */
-#define SD_IO_RW_EXTENDED_QCOM 54
-
-#define TIME_TO_WAIT_US 500
-#define SDIO_CLOSE_FLUSH_TIMEOUT_MSEC (10000)
-#define RX_FLUSH_BUFFER_SIZE (16*1024)
-
-#define SDIO_TEST_POSTFIX "_TEST"
-
-#define DATA_DEBUG(x, y...) \
- do { \
- if (sdio_al->debug.debug_data_on) \
- pr_info(y); \
- sdio_al_log(x, y); \
- } while (0)
-
-#define LPM_DEBUG(x, y...) \
- do { \
- if (sdio_al->debug.debug_lpm_on) \
- pr_info(y); \
- sdio_al_log(x, y); \
- } while (0)
-
-#define sdio_al_loge(x, y...) \
- do { \
- pr_err(y); \
- sdio_al_log(x, y); \
- } while (0)
-
-#define sdio_al_logi(x, y...) \
- do { \
- pr_info(y); \
- sdio_al_log(x, y); \
- } while (0)
-
-#define CLOSE_DEBUG(x, y...) \
- do { \
- if (sdio_al->debug.debug_close_on) \
- pr_info(y); \
- sdio_al_log(x, y); \
- } while (0)
-
-/* The index of the SDIO card used for the sdio_al_dloader */
-#define SDIO_BOOTLOADER_CARD_INDEX 1
-
-
-/* SDIO card state machine */
-enum sdio_al_device_state {
- CARD_INSERTED,
- CARD_REMOVED,
- MODEM_RESTART
-};
-
-struct sdio_al_debug {
- u8 debug_lpm_on;
- u8 debug_data_on;
- u8 debug_close_on;
- struct dentry *sdio_al_debug_root;
- struct dentry *sdio_al_debug_lpm_on;
- struct dentry *sdio_al_debug_data_on;
- struct dentry *sdio_al_debug_close_on;
- struct dentry *sdio_al_debug_info;
- struct dentry *sdio_al_debug_log_buffers[MAX_NUM_OF_SDIO_DEVICES + 1];
-};
-
-/* Polling time for the inactivity timer for devices that doesn't have
- * a streaming channel
- */
-#define SDIO_AL_POLL_TIME_NO_STREAMING 30
-
-#define CHAN_TO_FUNC(x) ((x) + 2 - 1)
-
-/**
- * Mailbox structure.
- * The Mailbox is located on the SDIO-Client Function#1.
- * The mailbox size is 128 bytes, which is one block.
- * The mailbox allows the host ton:
- * 1. Get the number of available bytes on the pipes.
- * 2. Enable/Disable SDIO-Client interrupt, related to pipes.
- * 3. Set the Threshold for generating interrupt.
- *
- */
-struct sdio_mailbox {
- u32 pipe_bytes_threshold[SDIO_AL_MAX_PIPES]; /* Addr 0x1000 */
-
- /* Mask USER interrupts generated towards host - Addr 0x1040 */
- u32 mask_irq_func_1:8; /* LSB */
- u32 mask_irq_func_2:8;
- u32 mask_irq_func_3:8;
- u32 mask_irq_func_4:8;
-
- u32 mask_irq_func_5:8;
- u32 mask_irq_func_6:8;
- u32 mask_irq_func_7:8;
- u32 mask_mutex_irq:8;
-
- /* Mask PIPE interrupts generated towards host - Addr 0x1048 */
- u32 mask_eot_pipe_0_7:8;
- u32 mask_thresh_above_limit_pipe_0_7:8;
- u32 mask_overflow_pipe_0_7:8;
- u32 mask_underflow_pipe_0_7:8;
-
- u32 mask_eot_pipe_8_15:8;
- u32 mask_thresh_above_limit_pipe_8_15:8;
- u32 mask_overflow_pipe_8_15:8;
- u32 mask_underflow_pipe_8_15:8;
-
- /* Status of User interrupts generated towards host - Addr 0x1050 */
- u32 user_irq_func_1:8;
- u32 user_irq_func_2:8;
- u32 user_irq_func_3:8;
- u32 user_irq_func_4:8;
-
- u32 user_irq_func_5:8;
- u32 user_irq_func_6:8;
- u32 user_irq_func_7:8;
- u32 user_mutex_irq:8;
-
- /* Status of PIPE interrupts generated towards host */
- /* Note: All sources are cleared once they read. - Addr 0x1058 */
- u32 eot_pipe_0_7:8;
- u32 thresh_above_limit_pipe_0_7:8;
- u32 overflow_pipe_0_7:8;
- u32 underflow_pipe_0_7:8;
-
- u32 eot_pipe_8_15:8;
- u32 thresh_above_limit_pipe_8_15:8;
- u32 overflow_pipe_8_15:8;
- u32 underflow_pipe_8_15:8;
-
- u16 pipe_bytes_avail[SDIO_AL_MAX_PIPES];
-};
-
-/** Track pending Rx Packet size */
-struct rx_packet_size {
- u32 size; /* in bytes */
- struct list_head list;
-};
-
-#define PEER_SDIOC_SW_MAILBOX_SIGNATURE 0xFACECAFE
-#define PEER_SDIOC_SW_MAILBOX_UT_SIGNATURE 0x5D107E57
-#define PEER_SDIOC_SW_MAILBOX_BOOT_SIGNATURE 0xDEADBEEF
-
-/* Allow support in old sdio version */
-#define PEER_SDIOC_OLD_VERSION_MAJOR 0x0002
-#define INVALID_SDIO_CHAN 0xFF
-
-/**
- * Peer SDIO-Client software header.
- */
-struct peer_sdioc_sw_header {
- u32 signature;
- u32 version;
- u32 max_channels;
- char channel_names[SDIO_AL_MAX_CHANNELS][PEER_CHANNEL_NAME_SIZE];
- u32 reserved[23];
-};
-
-struct peer_sdioc_boot_sw_header {
- u32 signature;
- u32 version;
- u32 boot_ch_num;
- u32 reserved[29]; /* 32 - previous fields */
-};
-
-/**
- * Peer SDIO-Client software mailbox.
- */
-struct peer_sdioc_sw_mailbox {
- struct peer_sdioc_sw_header sw_header;
- struct peer_sdioc_channel_config ch_config[SDIO_AL_MAX_CHANNELS];
-};
-
-#define SDIO_AL_DEBUG_LOG_SIZE 3000
-struct sdio_al_local_log {
- char buffer[SDIO_AL_DEBUG_LOG_SIZE];
- unsigned int buf_cur_pos;
- spinlock_t log_lock;
-};
-
-#define SDIO_AL_DEBUG_TMP_LOG_SIZE 250
-static int sdio_al_log(struct sdio_al_local_log *, const char *fmt, ...);
-
-/**
- * SDIO Abstraction Layer driver context.
- *
- * @pdata -
- * @debug -
- * @devices - an array of the the devices claimed by sdio_al
- * @unittest_mode - a flag to indicate if sdio_al is in
- * unittest mode
- * @bootloader_dev - the device which is used for the
- * bootloader
- * @subsys_notif_handle - handle for modem restart
- * notifications
- *
- */
-struct sdio_al {
- struct sdio_al_local_log gen_log;
- struct sdio_al_local_log device_log[MAX_NUM_OF_SDIO_DEVICES];
- struct sdio_al_platform_data *pdata;
- struct sdio_al_debug debug;
- struct sdio_al_device *devices[MAX_NUM_OF_SDIO_DEVICES];
- int unittest_mode;
- struct sdio_al_device *bootloader_dev;
- void *subsys_notif_handle;
- int sdioc_major;
- int skip_print_info;
-};
-
-struct sdio_al_work {
- struct work_struct work;
- struct sdio_al_device *sdio_al_dev;
-};
-
-
-/**
- * SDIO Abstraction Layer device context.
- *
- * @card - card claimed.
- *
- * @mailbox - A shadow of the SDIO-Client mailbox.
- *
- * @channel - Channels context.
- *
- * @workqueue - workqueue to read the mailbox and handle
- * pending requests. Reading the mailbox should not happen
- * in interrupt context.
- *
- * @work - work to submit to workqueue.
- *
- * @is_ready - driver is ready.
- *
- * @ask_mbox - Flag to request reading the mailbox,
- * for different reasons.
- *
- * @wake_lock - Lock when can't sleep.
- *
- * @lpm_chan - Channel to use for LPM (low power mode)
- * communication.
- *
- * @is_ok_to_sleep - Mark if driver is OK with going to sleep
- * (no pending transactions).
- *
- * @inactivity_time - time allowed to be in inactivity before
- * going to sleep
- *
- * @timer - timer to use for polling the mailbox.
- *
- * @poll_delay_msec - timer delay for polling the mailbox.
- *
- * @is_err - error detected.
- *
- * @signature - Context Validity Check.
- *
- * @flashless_boot_on - flag to indicate if sdio_al is in
- * flshless boot mode
- *
- */
-struct sdio_al_device {
- struct sdio_al_local_log *dev_log;
- struct mmc_card *card;
- struct mmc_host *host;
- struct sdio_mailbox *mailbox;
- struct sdio_channel channel[SDIO_AL_MAX_CHANNELS];
-
- struct peer_sdioc_sw_header *sdioc_sw_header;
- struct peer_sdioc_boot_sw_header *sdioc_boot_sw_header;
-
- struct workqueue_struct *workqueue;
- struct sdio_al_work sdio_al_work;
- struct sdio_al_work boot_work;
-
- int is_ready;
-
- wait_queue_head_t wait_mbox;
- int ask_mbox;
- int bootloader_done;
-
- struct wake_lock wake_lock;
- int lpm_chan;
- int is_ok_to_sleep;
- unsigned long inactivity_time;
-
- struct timer_list timer;
- u32 poll_delay_msec;
- int is_timer_initialized;
-
- int is_err;
-
- u32 signature;
-
- unsigned int is_suspended;
-
- int flashless_boot_on;
- int ch_close_supported;
- int state;
- int (*lpm_callback)(void *, int);
-
- int print_after_interrupt;
-
- u8 *rx_flush_buf;
-};
-
-/*
- * Host operation:
- * lower 16bits are operation code
- * upper 16bits are operation state
- */
-#define PEER_OPERATION(op_code , op_state) ((op_code) | ((op_state) << 16))
-#define GET_PEER_OPERATION_CODE(op) ((op) & 0xffff)
-#define GET_PEER_OPERATION_STATE(op) ((op) >> 16)
-
-enum peer_op_code {
- PEER_OP_CODE_CLOSE = 1
-};
-
-enum peer_op_state {
- PEER_OP_STATE_INIT = 0,
- PEER_OP_STATE_START = 1
-};
-
-
-/*
- * On the kernel command line specify
- * sdio_al.debug_lpm_on=1 to enable the LPM debug messages
- * By default the LPM debug messages are turned off
- */
-static int debug_lpm_on;
-module_param(debug_lpm_on, int, 0);
-
-/*
- * On the kernel command line specify
- * sdio_al.debug_data_on=1 to enable the DATA debug messages
- * By default the DATA debug messages are turned off
- */
-static int debug_data_on;
-module_param(debug_data_on, int, 0);
-
-/*
- * Enables / disables open close debug messages
- */
-static int debug_close_on = 1;
-module_param(debug_close_on, int, 0);
-
-/** The driver context */
-static struct sdio_al *sdio_al;
-
-/* Static functions declaration */
-static int enable_eot_interrupt(struct sdio_al_device *sdio_al_dev,
- int pipe_index, int enable);
-static int enable_threshold_interrupt(struct sdio_al_device *sdio_al_dev,
- int pipe_index, int enable);
-static void sdio_func_irq(struct sdio_func *func);
-static void sdio_al_timer_handler(unsigned long data);
-static int get_min_poll_time_msec(struct sdio_al_device *sdio_al_dev);
-static u32 check_pending_rx_packet(struct sdio_channel *ch, u32 eot);
-static u32 remove_handled_rx_packet(struct sdio_channel *ch);
-static int set_pipe_threshold(struct sdio_al_device *sdio_al_dev,
- int pipe_index, int threshold);
-static int sdio_al_wake_up(struct sdio_al_device *sdio_al_dev,
- u32 not_from_int, struct sdio_channel *ch);
-static int sdio_al_client_setup(struct sdio_al_device *sdio_al_dev);
-static int enable_mask_irq(struct sdio_al_device *sdio_al_dev,
- int func_num, int enable, u8 bit_offset);
-static int sdio_al_enable_func_retry(struct sdio_func *func, const char *name);
-static void sdio_al_print_info(void);
-static int sdio_read_internal(struct sdio_channel *ch, void *data, int len);
-static int sdio_read_from_closed_ch(struct sdio_channel *ch, int len);
-static void stop_and_del_timer(struct sdio_al_device *sdio_al_dev);
-
-#define SDIO_AL_ERR(func) \
- do { \
- printk_once(KERN_ERR MODULE_NAME \
- ":In Error state, ignore %s\n", \
- func); \
- sdio_al_print_info(); \
- } while (0)
-
-#ifdef CONFIG_DEBUG_FS
-static int debug_info_open(struct inode *inode, struct file *file)
-{
- file->private_data = inode->i_private;
- return 0;
-}
-
-static ssize_t debug_info_write(struct file *file,
- const char __user *buf, size_t count, loff_t *ppos)
-{
- sdio_al_print_info();
- return 1;
-}
-
-const struct file_operations debug_info_ops = {
- .open = debug_info_open,
- .write = debug_info_write,
-};
-
-struct debugfs_blob_wrapper sdio_al_dbgfs_log[MAX_NUM_OF_SDIO_DEVICES + 1];
-
-/*
-*
-* Trigger on/off for debug messages
-* for trigger off the data messages debug level use:
-* echo 0 > /sys/kernel/debugfs/sdio_al/debug_data_on
-* for trigger on the data messages debug level use:
-* echo 1 > /sys/kernel/debugfs/sdio_al/debug_data_on
-* for trigger off the lpm messages debug level use:
-* echo 0 > /sys/kernel/debugfs/sdio_al/debug_lpm_on
-* for trigger on the lpm messages debug level use:
-* echo 1 > /sys/kernel/debugfs/sdio_al/debug_lpm_on
-*/
-static int sdio_al_debugfs_init(void)
-{
- int i, blob_errs = 0;
-
- sdio_al->debug.sdio_al_debug_root = debugfs_create_dir("sdio_al", NULL);
- if (!sdio_al->debug.sdio_al_debug_root)
- return -ENOENT;
-
- sdio_al->debug.sdio_al_debug_lpm_on = debugfs_create_u8("debug_lpm_on",
- S_IRUGO | S_IWUGO,
- sdio_al->debug.sdio_al_debug_root,
- &sdio_al->debug.debug_lpm_on);
-
- sdio_al->debug.sdio_al_debug_data_on = debugfs_create_u8(
- "debug_data_on",
- S_IRUGO | S_IWUGO,
- sdio_al->debug.sdio_al_debug_root,
- &sdio_al->debug.debug_data_on);
-
- sdio_al->debug.sdio_al_debug_close_on = debugfs_create_u8(
- "debug_close_on",
- S_IRUGO | S_IWUGO,
- sdio_al->debug.sdio_al_debug_root,
- &sdio_al->debug.debug_close_on);
-
- sdio_al->debug.sdio_al_debug_info = debugfs_create_file(
- "sdio_debug_info",
- S_IRUGO | S_IWUGO,
- sdio_al->debug.sdio_al_debug_root,
- NULL,
- &debug_info_ops);
-
- for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; ++i) {
- char temp[18];
-
- scnprintf(temp, 18, "sdio_al_log_dev_%d", i + 1);
- sdio_al->debug.sdio_al_debug_log_buffers[i] =
- debugfs_create_blob(temp,
- S_IRUGO | S_IWUGO,
- sdio_al->debug.sdio_al_debug_root,
- &sdio_al_dbgfs_log[i]);
- }
-
- sdio_al->debug.sdio_al_debug_log_buffers[MAX_NUM_OF_SDIO_DEVICES] =
- debugfs_create_blob("sdio_al_gen_log",
- S_IRUGO | S_IWUGO,
- sdio_al->debug.sdio_al_debug_root,
- &sdio_al_dbgfs_log[MAX_NUM_OF_SDIO_DEVICES]);
-
- for (i = 0; i < (MAX_NUM_OF_SDIO_DEVICES + 1); ++i) {
- if (!sdio_al->debug.sdio_al_debug_log_buffers[i]) {
- pr_err(MODULE_NAME ": Failed to create debugfs buffer"
- " entry for "
- "sdio_al->debug.sdio_al_debug_log_buffers[%d]",
- i);
- blob_errs = 1;
- }
- }
-
- if (blob_errs) {
- for (i = 0; i < (MAX_NUM_OF_SDIO_DEVICES + 1); ++i)
- if (sdio_al->debug.sdio_al_debug_log_buffers[i])
- debugfs_remove(
- sdio_al->
- debug.sdio_al_debug_log_buffers[i]);
- }
-
-
- if ((!sdio_al->debug.sdio_al_debug_data_on) &&
- (!sdio_al->debug.sdio_al_debug_lpm_on) &&
- (!sdio_al->debug.sdio_al_debug_close_on) &&
- (!sdio_al->debug.sdio_al_debug_info) &&
- blob_errs) {
- debugfs_remove(sdio_al->debug.sdio_al_debug_root);
- sdio_al->debug.sdio_al_debug_root = NULL;
- return -ENOENT;
- }
-
- sdio_al_dbgfs_log[MAX_NUM_OF_SDIO_DEVICES].data =
- sdio_al->gen_log.buffer;
- sdio_al_dbgfs_log[MAX_NUM_OF_SDIO_DEVICES].size =
- SDIO_AL_DEBUG_LOG_SIZE;
-
- return 0;
-}
-
-static void sdio_al_debugfs_cleanup(void)
-{
- int i;
-
- debugfs_remove(sdio_al->debug.sdio_al_debug_lpm_on);
- debugfs_remove(sdio_al->debug.sdio_al_debug_data_on);
- debugfs_remove(sdio_al->debug.sdio_al_debug_close_on);
- debugfs_remove(sdio_al->debug.sdio_al_debug_info);
-
- for (i = 0; i < (MAX_NUM_OF_SDIO_DEVICES + 1); ++i)
- debugfs_remove(sdio_al->debug.sdio_al_debug_log_buffers[i]);
-
- debugfs_remove(sdio_al->debug.sdio_al_debug_root);
-}
-#endif
-
-static int sdio_al_log(struct sdio_al_local_log *log, const char *fmt, ...)
-{
- va_list args;
- int r;
- char *tp, *log_buf;
- unsigned int *log_cur_pos;
- struct timeval kt;
- unsigned long flags;
- static char sdio_al_log_tmp[SDIO_AL_DEBUG_TMP_LOG_SIZE];
-
- spin_lock_irqsave(&log->log_lock, flags);
-
- kt = ktime_to_timeval(ktime_get());
- r = scnprintf(sdio_al_log_tmp, SDIO_AL_DEBUG_TMP_LOG_SIZE,
- "[%8ld.%6ld] ", kt.tv_sec, kt.tv_usec);
-
- va_start(args, fmt);
- r += vscnprintf(&sdio_al_log_tmp[r], (SDIO_AL_DEBUG_TMP_LOG_SIZE - r),
- fmt, args);
- va_end(args);
-
- log_buf = log->buffer;
- log_cur_pos = &(log->buf_cur_pos);
-
- for (tp = sdio_al_log_tmp; tp < (sdio_al_log_tmp + r); tp++) {
- log_buf[(*log_cur_pos)++] = *tp;
- if ((*log_cur_pos) == SDIO_AL_DEBUG_LOG_SIZE)
- *log_cur_pos = 0;
- }
-
- spin_unlock_irqrestore(&log->log_lock, flags);
-
- return r;
-}
-
-static int sdio_al_verify_func1(struct sdio_al_device *sdio_al_dev,
- char const *func)
-{
- if (sdio_al_dev == NULL) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
- "sdio_al_dev\n", func);
- return -ENODEV;
- }
-
- if (sdio_al_dev->signature != SDIO_AL_SIGNATURE) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: Invalid "
- "signature\n", func);
- return -ENODEV;
- }
-
- if (!sdio_al_dev->card) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: NULL "
- "card\n", func);
- return -ENODEV;
- }
- if (!sdio_al_dev->card->sdio_func[0]) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: NULL "
- "func1\n", func);
- return -ENODEV;
- }
- return 0;
-}
-
-static int sdio_al_claim_mutex(struct sdio_al_device *sdio_al_dev,
- char const *func)
-{
- if (!sdio_al_dev) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
- "device\n", func);
- return -ENODEV;
- }
-
- if (sdio_al_dev->signature != SDIO_AL_SIGNATURE) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: Invalid "
- "device signature\n", func);
- return -ENODEV;
- }
-
- if (!sdio_al_dev->host) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: NULL "
- "host\n", func);
- return -ENODEV;
- }
-
- mmc_claim_host(sdio_al_dev->host);
-
- return 0;
-}
-
-static int sdio_al_release_mutex(struct sdio_al_device *sdio_al_dev,
- char const *func)
-{
- if (!sdio_al_dev) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
- "device\n", func);
- return -ENODEV;
- }
-
- if (sdio_al_dev->signature != SDIO_AL_SIGNATURE) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: Invalid "
- "device signature\n", func);
- return -ENODEV;
- }
-
- if (!sdio_al_dev->host) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: NULL "
- "host\n", func);
- return -ENODEV;
- }
-
- mmc_release_host(sdio_al_dev->host);
-
- return 0;
-}
-
-static int sdio_al_claim_mutex_and_verify_dev(
- struct sdio_al_device *sdio_al_dev,
- char const *func)
-{
- if (sdio_al_claim_mutex(sdio_al_dev, __func__))
- return -ENODEV;
-
- if (sdio_al_dev->state != CARD_INSERTED) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: Invalid "
- "device state %d\n", func, sdio_al_dev->state);
- sdio_al_release_mutex(sdio_al_dev, __func__);
- return -ENODEV;
- }
-
- return 0;
-}
-
-static void sdio_al_get_into_err_state(struct sdio_al_device *sdio_al_dev)
-{
- if ((!sdio_al) || (!sdio_al_dev))
- return;
-
- sdio_al_dev->is_err = true;
- sdio_al->debug.debug_data_on = 0;
- sdio_al->debug.debug_lpm_on = 0;
- sdio_al_print_info();
-}
-
-void sdio_al_register_lpm_cb(void *device_handle,
- int(*lpm_callback)(void *, int))
-{
- struct sdio_al_device *sdio_al_dev =
- (struct sdio_al_device *) device_handle;
-
- if (!sdio_al_dev) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s - "
- "device_handle is NULL\n", __func__);
- return;
- }
-
- if (lpm_callback) {
- sdio_al_dev->lpm_callback = lpm_callback;
- lpm_callback((void *)sdio_al_dev,
- sdio_al_dev->is_ok_to_sleep);
- }
-
- LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": %s - device %d "
- "registered for wakeup callback\n", __func__,
- sdio_al_dev->host->index);
-}
-
-void sdio_al_unregister_lpm_cb(void *device_handle)
-{
- struct sdio_al_device *sdio_al_dev =
- (struct sdio_al_device *) device_handle;
-
- if (!sdio_al_dev) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s - "
- "device_handle is NULL\n", __func__);
- return;
- }
-
- sdio_al_dev->lpm_callback = NULL;
- LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": %s - device %d "
- "unregister for wakeup callback\n", __func__,
- sdio_al_dev->host->index);
-}
-
-static void sdio_al_vote_for_sleep(struct sdio_al_device *sdio_al_dev,
- int is_vote_for_sleep)
-{
- pr_debug(MODULE_NAME ": %s()", __func__);
-
- if (!sdio_al_dev) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s - sdio_al_dev"
- " is NULL\n", __func__);
- return;
- }
-
- if (is_vote_for_sleep) {
- pr_debug(MODULE_NAME ": %s - sdio vote for Sleep", __func__);
- wake_unlock(&sdio_al_dev->wake_lock);
- } else {
- pr_debug(MODULE_NAME ": %s - sdio vote against sleep",
- __func__);
- wake_lock(&sdio_al_dev->wake_lock);
- }
-
- if (sdio_al_dev->lpm_callback != NULL) {
- LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": %s - "
- "is_vote_for_sleep=%d for card#%d, "
- "calling callback...", __func__,
- is_vote_for_sleep,
- sdio_al_dev->host->index);
- sdio_al_dev->lpm_callback((void *)sdio_al_dev,
- is_vote_for_sleep);
- }
-}
-
-/**
- * Write SDIO-Client lpm information
- * Should only be called with host claimed.
- */
-static int write_lpm_info(struct sdio_al_device *sdio_al_dev)
-{
- struct sdio_func *lpm_func = NULL;
- int offset = offsetof(struct peer_sdioc_sw_mailbox, ch_config)+
- sizeof(struct peer_sdioc_channel_config) *
- sdio_al_dev->lpm_chan+
- offsetof(struct peer_sdioc_channel_config, is_host_ok_to_sleep);
- int ret;
-
- if (sdio_al_dev->lpm_chan == INVALID_SDIO_CHAN) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Invalid "
- "lpm_chan for card %d\n",
- sdio_al_dev->host->index);
- return -EINVAL;
- }
-
- if (!sdio_al_dev->card ||
- !sdio_al_dev->card->sdio_func[sdio_al_dev->lpm_chan+1]) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": NULL card or lpm_func\n");
- return -ENODEV;
- }
- lpm_func = sdio_al_dev->card->sdio_func[sdio_al_dev->lpm_chan+1];
-
- pr_debug(MODULE_NAME ":write_lpm_info is_ok_to_sleep=%d, device %d\n",
- sdio_al_dev->is_ok_to_sleep,
- sdio_al_dev->host->index);
-
- ret = sdio_memcpy_toio(lpm_func, SDIOC_SW_MAILBOX_ADDR+offset,
- &sdio_al_dev->is_ok_to_sleep, sizeof(u32));
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":failed to "
- "write lpm info for card %d\n",
- sdio_al_dev->host->index);
- return ret;
- }
-
- return 0;
-}
-
-/* Set inactivity counter to intial value to allow clients come up */
-static inline void start_inactive_time(struct sdio_al_device *sdio_al_dev)
-{
- sdio_al_dev->inactivity_time = jiffies +
- msecs_to_jiffies(INITIAL_INACTIVITY_TIME_MSEC);
-}
-
-static inline void restart_inactive_time(struct sdio_al_device *sdio_al_dev)
-{
- sdio_al_dev->inactivity_time = jiffies +
- msecs_to_jiffies(INACTIVITY_TIME_MSEC);
-}
-
-static inline int is_inactive_time_expired(struct sdio_al_device *sdio_al_dev)
-{
- return time_after(jiffies, sdio_al_dev->inactivity_time);
-}
-
-
-static int is_user_irq_enabled(struct sdio_al_device *sdio_al_dev,
- int func_num)
-{
- int ret = 0;
- struct sdio_func *func1;
- u32 user_irq = 0;
- u32 addr = 0;
- u32 offset = 0;
- u32 masked_user_irq = 0;
-
- if (sdio_al_verify_func1(sdio_al_dev, __func__))
- return 0;
- func1 = sdio_al_dev->card->sdio_func[0];
-
- if (func_num < 4) {
- addr = FUNC_1_4_USER_IRQ_ADDR;
- offset = func_num * 8;
- } else {
- addr = FUNC_5_7_USER_IRQ_ADDR;
- offset = (func_num - 4) * 8;
- }
-
- user_irq = sdio_readl(func1, addr, &ret);
- if (ret) {
- pr_debug(MODULE_NAME ":read_user_irq fail\n");
- return 0;
- }
-
- masked_user_irq = (user_irq >> offset) && 0xFF;
- if (masked_user_irq == 0x1) {
- sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":user_irq "
- "enabled\n");
- return 1;
- }
-
- return 0;
-}
-
-static void sdio_al_sleep(struct sdio_al_device *sdio_al_dev,
- struct mmc_host *host)
-{
- int i;
-
- /* Go to sleep */
- pr_debug(MODULE_NAME ":Inactivity timer expired."
- " Going to sleep\n");
- /* Stop mailbox timer */
- stop_and_del_timer(sdio_al_dev);
- /* Make sure we get interrupt for non-packet-mode right away */
- for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
- struct sdio_channel *ch = &sdio_al_dev->channel[i];
- if ((ch->state != SDIO_CHANNEL_STATE_OPEN) &&
- (ch->state != SDIO_CHANNEL_STATE_CLOSED)) {
- pr_debug(MODULE_NAME ":continue for channel %s in"
- " state %d\n", ch->name, ch->state);
- continue;
- }
- if (ch->is_packet_mode == false) {
- ch->read_threshold = LOW_LATENCY_THRESHOLD;
- set_pipe_threshold(sdio_al_dev,
- ch->rx_pipe_index,
- ch->read_threshold);
- }
- }
- /* Prevent modem to go to sleep until we get the PROG_DONE on
- the dummy CMD52 */
- msmsdcc_set_pwrsave(sdio_al_dev->host, 0);
- /* Mark HOST_OK_TOSLEEP */
- sdio_al_dev->is_ok_to_sleep = 1;
- write_lpm_info(sdio_al_dev);
-
- msmsdcc_lpm_enable(host);
- LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":Finished sleep sequence"
- " for card %d. Sleep now.\n",
- sdio_al_dev->host->index);
- /* Release wakelock */
- sdio_al_vote_for_sleep(sdio_al_dev, 1);
-}
-
-
-/**
- * Read SDIO-Client Mailbox from Function#1.thresh_pipe
- *
- * The mailbox contain the bytes available per pipe,
- * and the End-Of-Transfer indication per pipe (if available).
- *
- * WARNING: Each time the Mailbox is read from the client, the
- * read_bytes_avail is incremented with another pending
- * transfer. Therefore, a pending rx-packet should be added to a
- * list before the next read of the mailbox.
- *
- * This function should run from a workqueue context since it
- * notifies the clients.
- *
- * This function assumes that sdio_al_claim_mutex was called before
- * calling it.
- *
- */
-static int read_mailbox(struct sdio_al_device *sdio_al_dev, int from_isr)
-{
- int ret;
- struct sdio_func *func1 = NULL;
- struct sdio_mailbox *mailbox = sdio_al_dev->mailbox;
- struct mmc_host *host = sdio_al_dev->host;
- u32 new_write_avail = 0;
- u32 old_write_avail = 0;
- u32 any_read_avail = 0;
- u32 any_write_pending = 0;
- int i;
- u32 rx_notify_bitmask = 0;
- u32 tx_notify_bitmask = 0;
- u32 eot_pipe = 0;
- u32 thresh_pipe = 0;
- u32 overflow_pipe = 0;
- u32 underflow_pipe = 0;
- u32 thresh_intr_mask = 0;
- int is_closing = 0;
-
- if (sdio_al_dev->is_err) {
- SDIO_AL_ERR(__func__);
- return 0;
- }
-
- if (sdio_al_verify_func1(sdio_al_dev, __func__))
- return -ENODEV;
- func1 = sdio_al_dev->card->sdio_func[0];
-
- pr_debug(MODULE_NAME ":start %s from_isr = %d for card %d.\n"
- , __func__, from_isr, sdio_al_dev->host->index);
-
- pr_debug(MODULE_NAME ":before sdio_memcpy_fromio.\n");
- memset(mailbox, 0, sizeof(struct sdio_mailbox));
- ret = sdio_memcpy_fromio(func1, mailbox,
- HW_MAILBOX_ADDR, sizeof(*mailbox));
- pr_debug(MODULE_NAME ":after sdio_memcpy_fromio.\n");
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to read "
- "Mailbox for card %d, goto error state\n",
- sdio_al_dev->host->index);
- sdio_al_get_into_err_state(sdio_al_dev);
- goto exit_err;
- }
-
- eot_pipe = (mailbox->eot_pipe_0_7) |
- (mailbox->eot_pipe_8_15<<8);
- thresh_pipe = (mailbox->thresh_above_limit_pipe_0_7) |
- (mailbox->thresh_above_limit_pipe_8_15<<8);
-
- overflow_pipe = (mailbox->overflow_pipe_0_7) |
- (mailbox->overflow_pipe_8_15<<8);
- underflow_pipe = mailbox->underflow_pipe_0_7 |
- (mailbox->underflow_pipe_8_15<<8);
- thresh_intr_mask =
- (mailbox->mask_thresh_above_limit_pipe_0_7) |
- (mailbox->mask_thresh_above_limit_pipe_8_15<<8);
-
- if (overflow_pipe || underflow_pipe)
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Mailbox ERROR "
- "overflow=0x%x, underflow=0x%x\n",
- overflow_pipe, underflow_pipe);
-
- /* In case of modem reset we would like to read the daya from the modem
- to clear the interrupts but do not process it */
- if (sdio_al_dev->state != CARD_INSERTED) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sdio_al_device"
- " (card %d) is in invalid state %d\n",
- sdio_al_dev->host->index,
- sdio_al_dev->state);
- return -ENODEV;
- }
-
- pr_debug(MODULE_NAME ":card %d: eot=0x%x, thresh=0x%x\n",
- sdio_al_dev->host->index,
- eot_pipe, thresh_pipe);
-
- /* Scan for Rx Packets available and update read available bytes */
- for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
- struct sdio_channel *ch = &sdio_al_dev->channel[i];
- u32 old_read_avail;
- u32 read_avail;
- u32 new_packet_size = 0;
-
- if (ch->state == SDIO_CHANNEL_STATE_CLOSING)
- is_closing = true; /* used to prevent sleep */
-
- old_read_avail = ch->read_avail;
- read_avail = mailbox->pipe_bytes_avail[ch->rx_pipe_index];
-
- if ((ch->state == SDIO_CHANNEL_STATE_CLOSED) &&
- (read_avail > 0)) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ":%s: Invalid read_avail 0x%x, for CLOSED ch %s\n",
- __func__, read_avail, ch->name);
- sdio_read_from_closed_ch(ch, read_avail);
- }
- if ((ch->state != SDIO_CHANNEL_STATE_OPEN) &&
- (ch->state != SDIO_CHANNEL_STATE_CLOSING))
- continue;
-
- if (read_avail > INVALID_DATA_AVAILABLE) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ":Invalid read_avail 0x%x for pipe %d\n",
- read_avail, ch->rx_pipe_index);
- continue;
- }
- any_read_avail |= read_avail | old_read_avail;
- ch->statistics.last_any_read_avail = any_read_avail;
- ch->statistics.last_read_avail = read_avail;
- ch->statistics.last_old_read_avail = old_read_avail;
-
- if (ch->is_packet_mode) {
- if ((eot_pipe & (1<<ch->rx_pipe_index)) &&
- sdio_al_dev->print_after_interrupt) {
- LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME
- ":Interrupt on ch %s, "
- "card %d", ch->name,
- sdio_al_dev->host->index);
- }
- new_packet_size = check_pending_rx_packet(ch, eot_pipe);
- } else {
- if ((thresh_pipe & (1<<ch->rx_pipe_index)) &&
- sdio_al_dev->print_after_interrupt) {
- LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME
- ":Interrupt on ch %s, "
- "card %d", ch->name,
- sdio_al_dev->host->index);
- }
- ch->read_avail = read_avail;
-
- /*
- * Restore default thresh for non packet channels.
- * in case it IS low latency channel then read_threshold
- * and def_read_threshold are both
- * LOW_LATENCY_THRESHOLD
- */
- if ((ch->read_threshold != ch->def_read_threshold) &&
- (read_avail >= ch->threshold_change_cnt)) {
- if (!ch->is_low_latency_ch) {
- ch->read_threshold =
- ch->def_read_threshold;
- set_pipe_threshold(sdio_al_dev,
- ch->rx_pipe_index,
- ch->read_threshold);
- }
- }
- }
-
- if ((ch->is_packet_mode) && (new_packet_size > 0)) {
- rx_notify_bitmask |= (1<<ch->num);
- ch->statistics.total_notifs++;
- }
-
- if ((!ch->is_packet_mode) && (ch->read_avail > 0) &&
- (old_read_avail == 0)) {
- rx_notify_bitmask |= (1<<ch->num);
- ch->statistics.total_notifs++;
- }
- }
- sdio_al_dev->print_after_interrupt = 0;
-
- /* Update Write available */
- for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
- struct sdio_channel *ch = &sdio_al_dev->channel[i];
-
- if ((ch->state != SDIO_CHANNEL_STATE_OPEN) &&
- (ch->state != SDIO_CHANNEL_STATE_CLOSING))
- continue;
-
- new_write_avail = mailbox->pipe_bytes_avail[ch->tx_pipe_index];
-
- if (new_write_avail > INVALID_DATA_AVAILABLE) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ":Invalid write_avail 0x%x for pipe %d\n",
- new_write_avail, ch->tx_pipe_index);
- continue;
- }
-
- old_write_avail = ch->write_avail;
- ch->write_avail = new_write_avail;
-
- if ((old_write_avail <= ch->min_write_avail) &&
- (new_write_avail >= ch->min_write_avail))
- tx_notify_bitmask |= (1<<ch->num);
-
- /* There is not enough write avail for this channel.
- We need to keep reading mailbox to wait for the appropriate
- write avail and cannot sleep. Ignore SMEM channel that has
- only one direction. */
- if (strncmp(ch->name, "SDIO_SMEM", CHANNEL_NAME_SIZE))
- any_write_pending |=
- (new_write_avail < ch->ch_config.max_tx_threshold);
- }
- /* notify clients */
- for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
- struct sdio_channel *ch = &sdio_al_dev->channel[i];
-
- if ((ch->state != SDIO_CHANNEL_STATE_OPEN) ||
- (ch->notify == NULL))
- continue;
-
- if (rx_notify_bitmask & (1<<ch->num))
- ch->notify(ch->priv,
- SDIO_EVENT_DATA_READ_AVAIL);
-
- if (tx_notify_bitmask & (1<<ch->num))
- ch->notify(ch->priv,
- SDIO_EVENT_DATA_WRITE_AVAIL);
- }
-
-
- if ((rx_notify_bitmask == 0) && (tx_notify_bitmask == 0) &&
- !any_read_avail && !any_write_pending) {
- DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":Nothing to "
- "Notify for card %d, is_closing=%d\n",
- sdio_al_dev->host->index, is_closing);
- if (is_closing)
- restart_inactive_time(sdio_al_dev);
- else if (is_inactive_time_expired(sdio_al_dev))
- sdio_al_sleep(sdio_al_dev, host);
- } else {
- DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":Notify bitmask"
- " for card %d rx=0x%x, tx=0x%x.\n",
- sdio_al_dev->host->index,
- rx_notify_bitmask, tx_notify_bitmask);
- /* Restart inactivity timer if any activity on the channel */
- restart_inactive_time(sdio_al_dev);
- }
-
- pr_debug(MODULE_NAME ":end %s.\n", __func__);
-
-exit_err:
- return ret;
-}
-
-/**
- * Check pending rx packet when reading the mailbox.
- */
-static u32 check_pending_rx_packet(struct sdio_channel *ch, u32 eot)
-{
- u32 rx_pending;
- u32 rx_avail;
- u32 new_packet_size = 0;
- struct sdio_al_device *sdio_al_dev = ch->sdio_al_dev;
-
-
- if (sdio_al_dev == NULL) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": NULL sdio_al_dev"
- " for channel %s\n", ch->name);
- return -EINVAL;
- }
-
- mutex_lock(&ch->ch_lock);
-
- rx_pending = ch->rx_pending_bytes;
- rx_avail = sdio_al_dev->mailbox->pipe_bytes_avail[ch->rx_pipe_index];
-
- pr_debug(MODULE_NAME ":pipe %d of card %d rx_avail=0x%x, "
- "rx_pending=0x%x\n",
- ch->rx_pipe_index, sdio_al_dev->host->index, rx_avail,
- rx_pending);
-
-
- /* new packet detected */
- if (eot & (1<<ch->rx_pipe_index)) {
- struct rx_packet_size *p = NULL;
- new_packet_size = rx_avail - rx_pending;
-
- if ((rx_avail <= rx_pending)) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": Invalid new packet size."
- " rx_avail=%d.\n", rx_avail);
- new_packet_size = 0;
- goto exit_err;
- }
-
- p = kzalloc(sizeof(*p), GFP_KERNEL);
- if (p == NULL) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": failed to allocate item for "
- "rx_pending list. rx_avail=%d, "
- "rx_pending=%d.\n",
- rx_avail, rx_pending);
- new_packet_size = 0;
- goto exit_err;
- }
- p->size = new_packet_size;
- /* Add new packet as last */
- list_add_tail(&p->list, &ch->rx_size_list_head);
- ch->rx_pending_bytes += new_packet_size;
-
- if (ch->read_avail == 0)
- ch->read_avail = new_packet_size;
- }
-
-exit_err:
- mutex_unlock(&ch->ch_lock);
-
- return new_packet_size;
-}
-
-
-
-/**
- * Remove first pending packet from the list.
- */
-static u32 remove_handled_rx_packet(struct sdio_channel *ch)
-{
- struct rx_packet_size *p = NULL;
-
- mutex_lock(&ch->ch_lock);
-
- ch->rx_pending_bytes -= ch->read_avail;
-
- if (!list_empty(&ch->rx_size_list_head)) {
- p = list_first_entry(&ch->rx_size_list_head,
- struct rx_packet_size, list);
- list_del(&p->list);
- kfree(p);
- } else {
- sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME ":%s: ch "
- "%s: unexpected empty list!!\n",
- __func__, ch->name);
- }
-
- if (list_empty(&ch->rx_size_list_head)) {
- ch->read_avail = 0;
- } else {
- p = list_first_entry(&ch->rx_size_list_head,
- struct rx_packet_size, list);
- ch->read_avail = p->size;
- }
-
- mutex_unlock(&ch->ch_lock);
-
- return ch->read_avail;
-}
-
-
-/**
- * Bootloader worker function.
- *
- * @note: clear the bootloader_done flag only after reading the
- * mailbox, to ignore more requests while reading the mailbox.
- */
-static void boot_worker(struct work_struct *work)
-{
- int ret = 0;
- int func_num = 0;
- int i;
- struct sdio_al_device *sdio_al_dev = NULL;
- struct sdio_al_work *sdio_al_work = container_of(work,
- struct sdio_al_work,
- work);
-
- if (sdio_al_work == NULL) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
- "sdio_al_work\n", __func__);
- return;
- }
-
- sdio_al_dev = sdio_al_work->sdio_al_dev;
- if (sdio_al_dev == NULL) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
- "sdio_al_dev\n", __func__);
- return;
- }
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":Bootloader Worker Started"
- ", wait for bootloader_done event..\n");
- wait_event(sdio_al_dev->wait_mbox,
- sdio_al_dev->bootloader_done);
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":Got bootloader_done "
- "event..\n");
- /* Do polling until MDM is up */
- for (i = 0; i < 5000; ++i) {
- if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
- return;
- if (is_user_irq_enabled(sdio_al_dev, func_num)) {
- sdio_al_release_mutex(sdio_al_dev, __func__);
- sdio_al_dev->bootloader_done = 0;
- ret = sdio_al_client_setup(sdio_al_dev);
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": sdio_al_client_setup failed, "
- "for card %d ret=%d\n",
- sdio_al_dev->host->index, ret);
- sdio_al_get_into_err_state(sdio_al_dev);
- }
- goto done;
- }
- sdio_al_release_mutex(sdio_al_dev, __func__);
- msleep(100);
- }
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Timeout waiting for "
- "user_irq for card %d\n",
- sdio_al_dev->host->index);
- sdio_al_get_into_err_state(sdio_al_dev);
-
-done:
- pr_debug(MODULE_NAME ":Boot Worker for card %d Exit!\n",
- sdio_al_dev->host->index);
-}
-
-/**
- * Worker function.
- *
- * @note: clear the ask_mbox flag only after
- * reading the mailbox, to ignore more requests while
- * reading the mailbox.
- */
-static void worker(struct work_struct *work)
-{
- int ret = 0;
- struct sdio_al_device *sdio_al_dev = NULL;
- struct sdio_al_work *sdio_al_work = container_of(work,
- struct sdio_al_work,
- work);
- if (sdio_al_work == NULL) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": worker: NULL "
- "sdio_al_work\n");
- return;
- }
-
- sdio_al_dev = sdio_al_work->sdio_al_dev;
- if (sdio_al_dev == NULL) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": worker: NULL "
- "sdio_al_dev\n");
- return;
- }
- pr_debug(MODULE_NAME ":Worker Started..\n");
- while ((sdio_al_dev->is_ready) && (ret == 0)) {
- pr_debug(MODULE_NAME ":Wait for read mailbox request..\n");
- wait_event(sdio_al_dev->wait_mbox, sdio_al_dev->ask_mbox);
- if (!sdio_al_dev->is_ready)
- break;
- if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
- break;
- if (sdio_al_dev->is_ok_to_sleep) {
- ret = sdio_al_wake_up(sdio_al_dev, 1, NULL);
- if (ret) {
- sdio_al_release_mutex(sdio_al_dev, __func__);
- return;
- }
- }
- ret = read_mailbox(sdio_al_dev, false);
- sdio_al_release_mutex(sdio_al_dev, __func__);
- sdio_al_dev->ask_mbox = false;
- }
-
- pr_debug(MODULE_NAME ":Worker Exit!\n");
-}
-
-/**
- * Write command using CMD54 rather than CMD53.
- * Writing with CMD54 generate EOT interrupt at the
- * SDIO-Client.
- * Based on mmc_io_rw_extended()
- */
-static int sdio_write_cmd54(struct mmc_card *card, unsigned fn,
- unsigned addr, const u8 *buf,
- unsigned blocks, unsigned blksz)
-{
- struct mmc_request mrq;
- struct mmc_command cmd;
- struct mmc_data data;
- struct scatterlist sg;
- int incr_addr = 1; /* MUST */
- int write = 1;
-
- BUG_ON(!card);
- BUG_ON(fn > 7);
- BUG_ON(blocks == 1 && blksz > 512);
- WARN_ON(blocks == 0);
- WARN_ON(blksz == 0);
-
- write = true;
- pr_debug(MODULE_NAME ":sdio_write_cmd54()"
- "fn=%d,buf=0x%x,blocks=%d,blksz=%d\n",
- fn, (u32) buf, blocks, blksz);
-
- memset(&mrq, 0, sizeof(struct mmc_request));
- memset(&cmd, 0, sizeof(struct mmc_command));
- memset(&data, 0, sizeof(struct mmc_data));
-
- mrq.cmd = &cmd;
- mrq.data = &data;
-
- cmd.opcode = SD_IO_RW_EXTENDED_QCOM;
-
- cmd.arg = write ? 0x80000000 : 0x00000000;
- cmd.arg |= fn << 28;
- cmd.arg |= incr_addr ? 0x04000000 : 0x00000000;
- cmd.arg |= addr << 9;
- if (blocks == 1 && blksz <= 512)
- cmd.arg |= (blksz == 512) ? 0 : blksz; /* byte mode */
- else
- cmd.arg |= 0x08000000 | blocks; /* block mode */
- cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC;
-
- data.blksz = blksz;
- data.blocks = blocks;
- data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
- data.sg = &sg;
- data.sg_len = 1;
-
- sg_init_one(&sg, buf, blksz * blocks);
-
- mmc_set_data_timeout(&data, card);
-
- mmc_wait_for_req(card->host, &mrq);
-
- if (cmd.error)
- return cmd.error;
- if (data.error)
- return data.error;
-
- if (mmc_host_is_spi(card->host)) {
- /* host driver already reported errors */
- } else {
- if (cmd.resp[0] & R5_ERROR) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME
- ":%s: R5_ERROR for card %d",
- __func__, card->host->index);
- return -EIO;
- }
- if (cmd.resp[0] & R5_FUNCTION_NUMBER) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME
- ":%s: R5_FUNCTION_NUMBER for card %d",
- __func__, card->host->index);
- return -EINVAL;
- }
- if (cmd.resp[0] & R5_OUT_OF_RANGE) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME
- ":%s: R5_OUT_OF_RANGE for card %d",
- __func__, card->host->index);
- return -ERANGE;
- }
- }
-
- return 0;
-}
-
-
-/**
- * Write data to channel.
- * Handle different data size types.
- *
- */
-static int sdio_ch_write(struct sdio_channel *ch, const u8 *buf, u32 len)
-{
- int ret = 0;
- unsigned blksz = ch->func->cur_blksize;
- int blocks = len / blksz;
- int remain_bytes = len % blksz;
- struct mmc_card *card = NULL;
- u32 fn = ch->func->num;
-
- if (!ch) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
- "channel\n", __func__);
- return -ENODEV;
- }
-
- if (!ch->sdio_al_dev) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
- "sdio_al_dev\n", __func__);
- return -ENODEV;
- }
-
- if (len == 0) {
- sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME ":channel "
- "%s trying to write 0 bytes\n", ch->name);
- return -EINVAL;
- }
-
- card = ch->func->card;
-
- if (remain_bytes) {
- /* CMD53 */
- if (blocks) {
- ret = sdio_memcpy_toio(ch->func, PIPE_TX_FIFO_ADDR,
- (void *) buf, blocks*blksz);
- if (ret != 0) {
- sdio_al_loge(ch->sdio_al_dev->dev_log,
- MODULE_NAME ":%s: sdio_memcpy_toio "
- "failed for channel %s\n",
- __func__, ch->name);
- sdio_al_get_into_err_state(ch->sdio_al_dev);
- return ret;
- }
- }
-
- buf += (blocks*blksz);
-
- ret = sdio_write_cmd54(card, fn, PIPE_TX_FIFO_ADDR,
- buf, 1, remain_bytes);
- } else {
- ret = sdio_write_cmd54(card, fn, PIPE_TX_FIFO_ADDR,
- buf, blocks, blksz);
- }
-
- if (ret != 0) {
- sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME ":%s: "
- "sdio_write_cmd54 failed for channel %s\n",
- __func__, ch->name);
- ch->sdio_al_dev->is_err = true;
- return ret;
- }
-
- return ret;
-}
-
-static int sdio_al_bootloader_completed(void)
-{
- int i;
-
- pr_debug(MODULE_NAME ":sdio_al_bootloader_completed was called\n");
-
- for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; ++i) {
- struct sdio_al_device *dev = NULL;
- if (sdio_al->devices[i] == NULL)
- continue;
- dev = sdio_al->devices[i];
- dev->bootloader_done = 1;
- wake_up(&dev->wait_mbox);
- }
-
- return 0;
-}
-
-static int sdio_al_wait_for_bootloader_comp(struct sdio_al_device *sdio_al_dev)
-{
- int ret = 0;
-
- if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
- return -ENODEV;
-
- /*
- * Enable function 0 interrupt mask to allow 9k to raise this interrupt
- * in power-up. When sdio_downloader will notify its completion
- * we will poll on this interrupt to wait for 9k power-up
- */
- ret = enable_mask_irq(sdio_al_dev, 0, 1, 0);
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": Enable_mask_irq for card %d failed, "
- "ret=%d\n",
- sdio_al_dev->host->index, ret);
- sdio_al_release_mutex(sdio_al_dev, __func__);
- return ret;
- }
-
- sdio_al_release_mutex(sdio_al_dev, __func__);
-
- /*
- * Start bootloader worker that will wait for the bootloader
- * completion
- */
- sdio_al_dev->boot_work.sdio_al_dev = sdio_al_dev;
- INIT_WORK(&sdio_al_dev->boot_work.work, boot_worker);
- sdio_al_dev->bootloader_done = 0;
- queue_work(sdio_al_dev->workqueue, &sdio_al_dev->boot_work.work);
-
- return 0;
-}
-
-static int sdio_al_bootloader_setup(void)
-{
- int ret = 0;
- struct sdio_al_device *bootloader_dev = sdio_al->bootloader_dev;
- struct sdio_func *func1 = NULL;
-
- if (sdio_al_claim_mutex_and_verify_dev(bootloader_dev, __func__))
- return -ENODEV;
-
- if (bootloader_dev->flashless_boot_on) {
- sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ":Already "
- "in boot process.\n");
- sdio_al_release_mutex(bootloader_dev, __func__);
- return 0;
- }
-
- bootloader_dev->sdioc_boot_sw_header
- = kzalloc(sizeof(*bootloader_dev->sdioc_boot_sw_header),
- GFP_KERNEL);
- if (bootloader_dev->sdioc_boot_sw_header == NULL) {
- sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ":fail to "
- "allocate sdioc boot sw header.\n");
- sdio_al_release_mutex(bootloader_dev, __func__);
- return -ENOMEM;
- }
-
- if (sdio_al_verify_func1(bootloader_dev, __func__)) {
- sdio_al_release_mutex(bootloader_dev, __func__);
- goto exit_err;
- }
- func1 = bootloader_dev->card->sdio_func[0];
-
- ret = sdio_memcpy_fromio(func1,
- bootloader_dev->sdioc_boot_sw_header,
- SDIOC_SW_HEADER_ADDR,
- sizeof(struct peer_sdioc_boot_sw_header));
- if (ret) {
- sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ":fail to "
- "read sdioc boot sw header.\n");
- sdio_al_release_mutex(bootloader_dev, __func__);
- goto exit_err;
- }
-
- if (bootloader_dev->sdioc_boot_sw_header->signature !=
- (u32) PEER_SDIOC_SW_MAILBOX_BOOT_SIGNATURE) {
- sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ":invalid "
- "mailbox signature 0x%x.\n",
- bootloader_dev->sdioc_boot_sw_header->signature);
- sdio_al_release_mutex(bootloader_dev, __func__);
- ret = -EINVAL;
- goto exit_err;
- }
-
- /* Upper byte has to be equal - no backward compatibility for unequal */
- if ((bootloader_dev->sdioc_boot_sw_header->version >> 16) !=
- (sdio_al->pdata->peer_sdioc_boot_version_major)) {
- sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ": HOST(0x%x)"
- " and CLIENT(0x%x) SDIO_AL BOOT VERSION don't match\n",
- ((sdio_al->pdata->peer_sdioc_boot_version_major<<16)+
- sdio_al->pdata->peer_sdioc_boot_version_minor),
- bootloader_dev->sdioc_boot_sw_header->version);
- sdio_al_release_mutex(bootloader_dev, __func__);
- ret = -EIO;
- goto exit_err;
- }
-
- sdio_al_logi(bootloader_dev->dev_log, MODULE_NAME ": SDIOC BOOT SW "
- "version 0x%x\n",
- bootloader_dev->sdioc_boot_sw_header->version);
-
- bootloader_dev->flashless_boot_on = true;
-
- sdio_al_release_mutex(bootloader_dev, __func__);
-
- ret = sdio_al_wait_for_bootloader_comp(bootloader_dev);
- if (ret) {
- sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME
- ": sdio_al_wait_for_bootloader_comp failed, "
- "err=%d\n", ret);
- goto exit_err;
- }
-
- ret = sdio_downloader_setup(bootloader_dev->card, 1,
- bootloader_dev->sdioc_boot_sw_header->boot_ch_num,
- sdio_al_bootloader_completed);
-
- if (ret) {
- sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME
- ": sdio_downloader_setup failed, err=%d\n", ret);
- goto exit_err;
- }
-
- sdio_al_logi(bootloader_dev->dev_log, MODULE_NAME ":In Flashless boot,"
- " waiting for its completion\n");
-
-
-exit_err:
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":free "
- "sdioc_boot_sw_header.\n");
- kfree(bootloader_dev->sdioc_boot_sw_header);
- bootloader_dev->sdioc_boot_sw_header = NULL;
- bootloader_dev = NULL;
-
- return ret;
-}
-
-
-/**
- * Read SDIO-Client software header
- *
- */
-static int read_sdioc_software_header(struct sdio_al_device *sdio_al_dev,
- struct peer_sdioc_sw_header *header)
-{
- int ret;
- int i;
- int test_version = 0;
- int sdioc_test_version = 0;
- struct sdio_func *func1 = NULL;
-
- pr_debug(MODULE_NAME ":reading sdioc sw header.\n");
-
- if (sdio_al_verify_func1(sdio_al_dev, __func__))
- return -ENODEV;
-
- func1 = sdio_al_dev->card->sdio_func[0];
-
- ret = sdio_memcpy_fromio(func1, header,
- SDIOC_SW_HEADER_ADDR, sizeof(*header));
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":fail to read "
- "sdioc sw header.\n");
- goto exit_err;
- }
-
- if (header->signature == (u32)PEER_SDIOC_SW_MAILBOX_UT_SIGNATURE) {
- sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":SDIOC SW "
- "unittest signature. 0x%x\n",
- header->signature);
- sdio_al->unittest_mode = true;
- /* Verify test code compatibility with the modem */
- sdioc_test_version = (header->version & 0xFF00) >> 8;
- test_version = sdio_al->pdata->peer_sdioc_version_minor >> 8;
- if (test_version != sdioc_test_version) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": HOST(0x%x) and CLIENT(0x%x) "
- "testing VERSION don't match\n",
- test_version,
- sdioc_test_version);
- msleep(500);
- BUG();
- }
- }
-
- if ((header->signature != (u32) PEER_SDIOC_SW_MAILBOX_SIGNATURE) &&
- (header->signature != (u32) PEER_SDIOC_SW_MAILBOX_UT_SIGNATURE)) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":SDIOC SW "
- "invalid signature. 0x%x\n", header->signature);
- goto exit_err;
- }
- /* Upper byte has to be equal - no backward compatibility for unequal */
- sdio_al->sdioc_major = header->version >> 16;
- if (sdio_al->pdata->allow_sdioc_version_major_2) {
- if ((sdio_al->sdioc_major !=
- sdio_al->pdata->peer_sdioc_version_major) &&
- (sdio_al->sdioc_major != PEER_SDIOC_OLD_VERSION_MAJOR)) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": HOST(0x%x) and CLIENT(0x%x) "
- "SDIO_AL VERSION don't match\n",
- ((sdio_al->pdata->peer_sdioc_version_major<<16)+
- sdio_al->pdata->peer_sdioc_version_minor),
- header->version);
- goto exit_err;
- }
- } else {
- if (sdio_al->sdioc_major !=
- sdio_al->pdata->peer_sdioc_version_major) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": HOST(0x%x) and CLIENT(0x%x) "
- "SDIO_AL VERSION don't match\n",
- ((sdio_al->pdata->peer_sdioc_version_major<<16)+
- sdio_al->pdata->peer_sdioc_version_minor),
- header->version);
- goto exit_err;
- }
- }
- sdio_al_dev->ch_close_supported = (header->version & 0x000F) >=
- (sdio_al->pdata->peer_sdioc_version_minor & 0xF);
-
- sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":SDIOC SW version 0x%x,"
- " sdio_al major 0x%x minor 0x%x\n", header->version,
- sdio_al->sdioc_major,
- sdio_al->pdata->peer_sdioc_version_minor);
-
- sdio_al_dev->flashless_boot_on = false;
- for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
- struct sdio_channel *ch = &sdio_al_dev->channel[i];
-
- /* Set default values */
- ch->read_threshold = DEFAULT_READ_THRESHOLD;
- ch->write_threshold = DEFAULT_WRITE_THRESHOLD;
- ch->min_write_avail = DEFAULT_MIN_WRITE_THRESHOLD;
- ch->is_packet_mode = true;
- ch->peer_tx_buf_size = DEFAULT_PEER_TX_BUF_SIZE;
- ch->poll_delay_msec = 0;
-
- ch->num = i;
- ch->func = NULL;
- ch->rx_pipe_index = ch->num*2;
- ch->tx_pipe_index = ch->num*2+1;
-
- memset(ch->name, 0, sizeof(ch->name));
-
- if (header->channel_names[i][0]) {
- memcpy(ch->name, SDIO_PREFIX,
- strlen(SDIO_PREFIX));
- memcpy(ch->name + strlen(SDIO_PREFIX),
- header->channel_names[i],
- PEER_CHANNEL_NAME_SIZE);
-
- ch->state = SDIO_CHANNEL_STATE_IDLE;
- ch->sdio_al_dev = sdio_al_dev;
- if (sdio_al_dev->card->sdio_func[ch->num+1]) {
- ch->func =
- sdio_al_dev->card->sdio_func[ch->num+1];
- } else {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": NULL func for channel %s\n",
- ch->name);
- goto exit_err;
- }
- } else {
- ch->state = SDIO_CHANNEL_STATE_INVALID;
- }
-
- sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":Channel=%s, "
- "state=%d\n", ch->name, ch->state);
- }
-
- return 0;
-
-exit_err:
- sdio_al_get_into_err_state(sdio_al_dev);
- memset(header, 0, sizeof(*header));
-
- return -EIO;
-}
-
-/**
- * Read SDIO-Client channel configuration
- *
- */
-static int read_sdioc_channel_config(struct sdio_channel *ch)
-{
- int ret;
- struct peer_sdioc_sw_mailbox *sw_mailbox = NULL;
- struct peer_sdioc_channel_config *ch_config = NULL;
- struct sdio_al_device *sdio_al_dev = ch->sdio_al_dev;
-
- if (sdio_al_dev == NULL) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": NULL sdio_al_dev"
- " for channel %s\n", ch->name);
- return -EINVAL;
- }
-
- if (sdio_al_dev->sdioc_sw_header->version == 0)
- return -1;
-
- pr_debug(MODULE_NAME ":reading sw mailbox %s channel.\n", ch->name);
-
- sw_mailbox = kzalloc(sizeof(*sw_mailbox), GFP_KERNEL);
- if (sw_mailbox == NULL)
- return -ENOMEM;
-
- ret = sdio_memcpy_fromio(ch->func, sw_mailbox,
- SDIOC_SW_MAILBOX_ADDR, sizeof(*sw_mailbox));
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":fail to read "
- "sw mailbox.\n");
- goto exit_err;
- }
-
- ch_config = &sw_mailbox->ch_config[ch->num];
- memcpy(&ch->ch_config, ch_config,
- sizeof(struct peer_sdioc_channel_config));
-
- if (!ch_config->is_ready) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sw mailbox "
- "channel not ready.\n");
- goto exit_err;
- }
-
- ch->read_threshold = LOW_LATENCY_THRESHOLD;
- ch->is_low_latency_ch = ch_config->is_low_latency_ch;
- /* Threshold on 50% of the maximum size , sdioc uses double-buffer */
- ch->write_threshold = (ch_config->max_tx_threshold * 5) / 10;
- ch->threshold_change_cnt = ch->ch_config.max_rx_threshold -
- ch->read_threshold + THRESHOLD_CHANGE_EXTRA_BYTES;
-
- if (ch->is_low_latency_ch)
- ch->def_read_threshold = LOW_LATENCY_THRESHOLD;
- else /* Aggregation up to 90% of the maximum size */
- ch->def_read_threshold = (ch_config->max_rx_threshold * 9) / 10;
-
- ch->is_packet_mode = ch_config->is_packet_mode;
- if (!ch->is_packet_mode) {
- ch->poll_delay_msec = DEFAULT_POLL_DELAY_NOPACKET_MSEC;
- ch->min_write_avail = DEFAULT_MIN_WRITE_THRESHOLD_STREAMING;
- }
- /* The max_packet_size is set by the modem in version 3 and on */
- if (sdio_al->sdioc_major > PEER_SDIOC_OLD_VERSION_MAJOR)
- ch->min_write_avail = ch_config->max_packet_size;
-
- if (ch->min_write_avail > ch->write_threshold)
- ch->min_write_avail = ch->write_threshold;
-
- CLOSE_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":ch %s "
- "read_threshold=%d, write_threshold=%d,"
- " min_write_avail=%d, max_rx_threshold=%d,"
- " max_tx_threshold=%d\n", ch->name, ch->read_threshold,
- ch->write_threshold, ch->min_write_avail,
- ch_config->max_rx_threshold,
- ch_config->max_tx_threshold);
-
- ch->peer_tx_buf_size = ch_config->tx_buf_size;
-
- kfree(sw_mailbox);
-
- return 0;
-
-exit_err:
- sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":Reading SW Mailbox "
- "error.\n");
- kfree(sw_mailbox);
-
- return -1;
-}
-
-
-/**
- * Enable/Disable EOT interrupt of a pipe.
- *
- */
-static int enable_eot_interrupt(struct sdio_al_device *sdio_al_dev,
- int pipe_index, int enable)
-{
- int ret = 0;
- struct sdio_func *func1;
- u32 mask;
- u32 pipe_mask;
- u32 addr;
-
- if (sdio_al_verify_func1(sdio_al_dev, __func__))
- return -ENODEV;
- func1 = sdio_al_dev->card->sdio_func[0];
-
- if (pipe_index < 8) {
- addr = PIPES_0_7_IRQ_MASK_ADDR;
- pipe_mask = (1<<pipe_index);
- } else {
- addr = PIPES_8_15_IRQ_MASK_ADDR;
- pipe_mask = (1<<(pipe_index-8));
- }
-
- mask = sdio_readl(func1, addr, &ret);
- if (ret) {
- pr_debug(MODULE_NAME ":enable_eot_interrupt fail\n");
- goto exit_err;
- }
-
- if (enable)
- mask &= (~pipe_mask); /* 0 = enable */
- else
- mask |= (pipe_mask); /* 1 = disable */
-
- sdio_writel(func1, mask, addr, &ret);
-
-exit_err:
- return ret;
-}
-
-
-/**
- * Enable/Disable mask interrupt of a function.
- *
- */
-static int enable_mask_irq(struct sdio_al_device *sdio_al_dev,
- int func_num, int enable, u8 bit_offset)
-{
- int ret = 0;
- struct sdio_func *func1 = NULL;
- u32 mask = 0;
- u32 func_mask = 0;
- u32 addr = 0;
- u32 offset = 0;
-
- if (sdio_al_verify_func1(sdio_al_dev, __func__))
- return -ENODEV;
- func1 = sdio_al_dev->card->sdio_func[0];
-
- if (func_num < 4) {
- addr = FUNC_1_4_MASK_IRQ_ADDR;
- offset = func_num * 8 + bit_offset;
- } else {
- addr = FUNC_5_7_MASK_IRQ_ADDR;
- offset = (func_num - 4) * 8 + bit_offset;
- }
-
- func_mask = 1<<offset;
-
- mask = sdio_readl(func1, addr, &ret);
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": "
- "enable_mask_irq fail\n");
- goto exit_err;
- }
-
- if (enable)
- mask &= (~func_mask); /* 0 = enable */
- else
- mask |= (func_mask); /* 1 = disable */
-
- pr_debug(MODULE_NAME ":enable_mask_irq, writing mask = 0x%x\n", mask);
-
- sdio_writel(func1, mask, addr, &ret);
-
-exit_err:
- return ret;
-}
-
-/**
- * Enable/Disable Threshold interrupt of a pipe.
- *
- */
-static int enable_threshold_interrupt(struct sdio_al_device *sdio_al_dev,
- int pipe_index, int enable)
-{
- int ret = 0;
- struct sdio_func *func1;
- u32 mask;
- u32 pipe_mask;
- u32 addr;
-
- if (sdio_al_verify_func1(sdio_al_dev, __func__))
- return -ENODEV;
- func1 = sdio_al_dev->card->sdio_func[0];
-
- if (pipe_index < 8) {
- addr = PIPES_0_7_IRQ_MASK_ADDR;
- pipe_mask = (1<<pipe_index);
- } else {
- addr = PIPES_8_15_IRQ_MASK_ADDR;
- pipe_mask = (1<<(pipe_index-8));
- }
-
- mask = sdio_readl(func1, addr, &ret);
- if (ret) {
- pr_debug(MODULE_NAME ":enable_threshold_interrupt fail\n");
- goto exit_err;
- }
-
- pipe_mask = pipe_mask<<8; /* Threshold bits 8..15 */
- if (enable)
- mask &= (~pipe_mask); /* 0 = enable */
- else
- mask |= (pipe_mask); /* 1 = disable */
-
- sdio_writel(func1, mask, addr, &ret);
-
-exit_err:
- return ret;
-}
-
-/**
- * Set the threshold to trigger interrupt from SDIO-Card on
- * pipe available bytes.
- *
- */
-static int set_pipe_threshold(struct sdio_al_device *sdio_al_dev,
- int pipe_index, int threshold)
-{
- int ret = 0;
- struct sdio_func *func1;
-
- if (sdio_al_verify_func1(sdio_al_dev, __func__))
- return -ENODEV;
- func1 = sdio_al_dev->card->sdio_func[0];
-
- sdio_writel(func1, threshold,
- PIPES_THRESHOLD_ADDR+pipe_index*4, &ret);
- if (ret)
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": "
- "set_pipe_threshold err=%d\n", -ret);
-
- return ret;
-}
-
-/**
- * Enable func w/ retries
- *
- */
-static int sdio_al_enable_func_retry(struct sdio_func *func, const char *name)
-{
- int ret, i;
- for (i = 0; i < 200; i++) {
- ret = sdio_enable_func(func);
- if (ret) {
- pr_debug(MODULE_NAME ":retry enable %s func#%d "
- "ret=%d\n",
- name, func->num, ret);
- msleep(10);
- } else
- break;
- }
-
- return ret;
-}
-
-/**
- * Open Channel
- *
- * 1. Init Channel Context.
- * 2. Init the Channel SDIO-Function.
- * 3. Init the Channel Pipes on Mailbox.
- */
-static int open_channel(struct sdio_channel *ch)
-{
- int ret = 0;
- struct sdio_al_device *sdio_al_dev = ch->sdio_al_dev;
-
- if (sdio_al_dev == NULL) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": NULL "
- "sdio_al_dev for channel %s\n", ch->name);
- return -EINVAL;
- }
-
- /* Init channel Context */
- /** Func#1 is reserved for mailbox */
- ch->func = sdio_al_dev->card->sdio_func[ch->num+1];
- ch->rx_pipe_index = ch->num*2;
- ch->tx_pipe_index = ch->num*2+1;
- ch->signature = SDIO_AL_SIGNATURE;
-
- ch->total_rx_bytes = 0;
- ch->total_tx_bytes = 0;
-
- ch->write_avail = 0;
- ch->read_avail = 0;
- ch->rx_pending_bytes = 0;
-
- mutex_init(&ch->ch_lock);
-
- pr_debug(MODULE_NAME ":open_channel %s func#%d\n",
- ch->name, ch->func->num);
-
- INIT_LIST_HEAD(&(ch->rx_size_list_head));
-
- /* Init SDIO Function */
- ret = sdio_al_enable_func_retry(ch->func, ch->name);
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": "
- "sdio_enable_func() err=%d\n", -ret);
- goto exit_err;
- }
-
- /* Note: Patch Func CIS tuple issue */
- ret = sdio_set_block_size(ch->func, SDIO_AL_BLOCK_SIZE);
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": "
- "sdio_set_block_size()failed, err=%d\n", -ret);
- goto exit_err;
- }
-
- ch->func->max_blksize = SDIO_AL_BLOCK_SIZE;
-
- sdio_set_drvdata(ch->func, ch);
-
- /* Get channel parameters from the peer SDIO-Client */
- read_sdioc_channel_config(ch);
-
- /* Set Pipes Threshold on Mailbox */
- ret = set_pipe_threshold(sdio_al_dev,
- ch->rx_pipe_index, ch->read_threshold);
- if (ret)
- goto exit_err;
- ret = set_pipe_threshold(sdio_al_dev,
- ch->tx_pipe_index, ch->write_threshold);
- if (ret)
- goto exit_err;
-
- /* Set flag before interrupts are enabled to allow notify */
- ch->state = SDIO_CHANNEL_STATE_OPEN;
- pr_debug(MODULE_NAME ":channel %s is in OPEN state now\n", ch->name);
-
- sdio_al_dev->poll_delay_msec = get_min_poll_time_msec(sdio_al_dev);
-
- /* lpm mechanism lives under the assumption there is always a timer */
- /* Check if need to start the timer */
- if ((sdio_al_dev->poll_delay_msec) &&
- (sdio_al_dev->is_timer_initialized == false)) {
-
- init_timer(&sdio_al_dev->timer);
- sdio_al_dev->timer.data = (unsigned long) sdio_al_dev;
- sdio_al_dev->timer.function = sdio_al_timer_handler;
- sdio_al_dev->timer.expires = jiffies +
- msecs_to_jiffies(sdio_al_dev->poll_delay_msec);
- add_timer(&sdio_al_dev->timer);
- sdio_al_dev->is_timer_initialized = true;
- }
-
- /* Enable Pipes Interrupts */
- enable_eot_interrupt(sdio_al_dev, ch->rx_pipe_index, true);
- enable_eot_interrupt(sdio_al_dev, ch->tx_pipe_index, true);
-
- enable_threshold_interrupt(sdio_al_dev, ch->rx_pipe_index, true);
- enable_threshold_interrupt(sdio_al_dev, ch->tx_pipe_index, true);
-
-exit_err:
-
- return ret;
-}
-
-/**
- * Ask the worker to read the mailbox.
- */
-static void ask_reading_mailbox(struct sdio_al_device *sdio_al_dev)
-{
- if (!sdio_al_dev->ask_mbox) {
- pr_debug(MODULE_NAME ":ask_reading_mailbox for card %d\n",
- sdio_al_dev->host->index);
- sdio_al_dev->ask_mbox = true;
- wake_up(&sdio_al_dev->wait_mbox);
- }
-}
-
-/**
- * Start the timer
- */
-static void start_timer(struct sdio_al_device *sdio_al_dev)
-{
- if ((sdio_al_dev->poll_delay_msec) &&
- (sdio_al_dev->state == CARD_INSERTED)) {
- sdio_al_dev->timer.expires = jiffies +
- msecs_to_jiffies(sdio_al_dev->poll_delay_msec);
- add_timer(&sdio_al_dev->timer);
- }
-}
-
-/**
- * Restart(postpone) the already working timer
- */
-static void restart_timer(struct sdio_al_device *sdio_al_dev)
-{
- if ((sdio_al_dev->poll_delay_msec) &&
- (sdio_al_dev->state == CARD_INSERTED)) {
- ulong expires = jiffies +
- msecs_to_jiffies(sdio_al_dev->poll_delay_msec);
- mod_timer(&sdio_al_dev->timer, expires);
- }
-}
-
-/**
- * Stop and delete the timer
- */
-static void stop_and_del_timer(struct sdio_al_device *sdio_al_dev)
-{
- if (sdio_al_dev->is_timer_initialized) {
- sdio_al_dev->poll_delay_msec = 0;
- del_timer_sync(&sdio_al_dev->timer);
- }
-}
-
-/**
- * Do the wakup sequence.
- * This function should be called after claiming the host!
- * The caller is responsible for releasing the host.
- *
- * Wake up sequence
- * 1. Get lock
- * 2. Enable wake up function if needed
- * 3. Mark NOT OK to sleep and write it
- * 4. Restore default thresholds
- * 5. Start the mailbox and inactivity timer again
- */
-static int sdio_al_wake_up(struct sdio_al_device *sdio_al_dev,
- u32 not_from_int, struct sdio_channel *ch)
-{
- int ret = 0;
- struct sdio_func *wk_func = NULL;
- unsigned long time_to_wait;
- struct mmc_host *host = sdio_al_dev->host;
-
- if (sdio_al_dev->is_err) {
- SDIO_AL_ERR(__func__);
- return -ENODEV;
- }
-
- if (!sdio_al_dev->is_ok_to_sleep) {
- LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":card %d "
- "already awake, no need to wake up\n",
- sdio_al_dev->host->index);
- return 0;
- }
-
- /* Wake up sequence */
- if (not_from_int) {
- if (ch) {
- LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": Wake up"
- " card %d (not by interrupt), ch %s",
- sdio_al_dev->host->index,
- ch->name);
- } else {
- LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": Wake up"
- " card %d (not by interrupt)",
- sdio_al_dev->host->index);
- }
- } else {
- LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": Wake up card "
- "%d by interrupt",
- sdio_al_dev->host->index);
- sdio_al_dev->print_after_interrupt = 1;
- }
-
- sdio_al_vote_for_sleep(sdio_al_dev, 0);
-
- msmsdcc_lpm_disable(host);
- msmsdcc_set_pwrsave(host, 0);
- /* Poll the GPIO */
- time_to_wait = jiffies + msecs_to_jiffies(1000);
- while (time_before(jiffies, time_to_wait)) {
- if (sdio_al->pdata->get_mdm2ap_status())
- break;
- udelay(TIME_TO_WAIT_US);
- }
-
- pr_debug(MODULE_NAME ":GPIO mdm2ap_status=%d\n",
- sdio_al->pdata->get_mdm2ap_status());
-
- /* Here get_mdm2ap_status() returning 0 is not an error condition */
- if (sdio_al->pdata->get_mdm2ap_status() == 0)
- LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": "
- "get_mdm2ap_status() is 0\n");
-
- /* Enable Wake up Function */
- if (!sdio_al_dev->card ||
- !sdio_al_dev->card->sdio_func[SDIO_AL_WAKEUP_FUNC-1]) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": NULL card or wk_func\n");
- return -ENODEV;
- }
- wk_func = sdio_al_dev->card->sdio_func[SDIO_AL_WAKEUP_FUNC-1];
- ret = sdio_al_enable_func_retry(wk_func, "wakeup func");
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": "
- "sdio_enable_func() err=%d\n", -ret);
- goto error_exit;
- }
- /* Mark NOT OK_TOSLEEP */
- sdio_al_dev->is_ok_to_sleep = 0;
- ret = write_lpm_info(sdio_al_dev);
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": "
- "write_lpm_info() failed, err=%d\n", -ret);
- sdio_al_dev->is_ok_to_sleep = 1;
- sdio_disable_func(wk_func);
- goto error_exit;
- }
- sdio_disable_func(wk_func);
-
- /* Start the timer again*/
- restart_inactive_time(sdio_al_dev);
- sdio_al_dev->poll_delay_msec = get_min_poll_time_msec(sdio_al_dev);
- start_timer(sdio_al_dev);
-
- LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME "Finished Wake up sequence"
- " for card %d", sdio_al_dev->host->index);
-
- msmsdcc_set_pwrsave(host, 1);
- pr_debug(MODULE_NAME ":Turn clock off\n");
-
- return ret;
-error_exit:
- sdio_al_vote_for_sleep(sdio_al_dev, 1);
- msmsdcc_set_pwrsave(host, 1);
- WARN_ON(ret);
- sdio_al_get_into_err_state(sdio_al_dev);
- return ret;
-}
-
-
-/**
- * SDIO Function Interrupt handler.
- *
- * Interrupt shall be triggered by SDIO-Client when:
- * 1. End-Of-Transfer (EOT) detected in packet mode.
- * 2. Bytes-available reached the threshold.
- *
- * Reading the mailbox clears the EOT/Threshold interrupt
- * source.
- * The interrupt source should be cleared before this ISR
- * returns. This ISR is called from IRQ Thread and not
- * interrupt, so it may sleep.
- *
- */
-static void sdio_func_irq(struct sdio_func *func)
-{
- struct sdio_al_device *sdio_al_dev = sdio_get_drvdata(func);
-
- pr_debug(MODULE_NAME ":start %s.\n", __func__);
-
- if (sdio_al_dev == NULL) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": NULL device");
- return;
- }
-
- if (sdio_al_dev->is_ok_to_sleep)
- sdio_al_wake_up(sdio_al_dev, 0, NULL);
- else
- restart_timer(sdio_al_dev);
-
- read_mailbox(sdio_al_dev, true);
-
- pr_debug(MODULE_NAME ":end %s.\n", __func__);
-}
-
-/**
- * Timer Expire Handler
- *
- */
-static void sdio_al_timer_handler(unsigned long data)
-{
- struct sdio_al_device *sdio_al_dev = (struct sdio_al_device *)data;
- if (sdio_al_dev == NULL) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": NULL "
- "sdio_al_dev for data %lu\n", data);
- return;
- }
- if (sdio_al_dev->state != CARD_INSERTED) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": sdio_al_dev "
- "is in invalid state %d\n", sdio_al_dev->state);
- return;
- }
- pr_debug(MODULE_NAME " Timer Expired\n");
-
- ask_reading_mailbox(sdio_al_dev);
-
- restart_timer(sdio_al_dev);
-}
-
-/**
- * Driver Setup.
- *
- */
-static int sdio_al_setup(struct sdio_al_device *sdio_al_dev)
-{
- int ret = 0;
- struct mmc_card *card = sdio_al_dev->card;
- struct sdio_func *func1 = NULL;
- int i = 0;
- int fn = 0;
-
- if (sdio_al_verify_func1(sdio_al_dev, __func__))
- return -ENODEV;
- func1 = card->sdio_func[0];
-
- sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":sdio_al_setup for "
- "card %d\n", sdio_al_dev->host->index);
-
- ret = sdio_al->pdata->config_mdm2ap_status(1);
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME "Could not "
- "request GPIO\n");
- return ret;
- }
-
- INIT_WORK(&sdio_al_dev->sdio_al_work.work, worker);
- /* disable all pipes interrupts before claim irq.
- since all are enabled by default. */
- for (i = 0 ; i < SDIO_AL_MAX_PIPES; i++) {
- enable_eot_interrupt(sdio_al_dev, i, false);
- enable_threshold_interrupt(sdio_al_dev, i, false);
- }
-
- /* Disable all SDIO Functions before claim irq. */
- for (fn = 1 ; fn <= card->sdio_funcs; fn++)
- sdio_disable_func(card->sdio_func[fn-1]);
-
- sdio_set_drvdata(func1, sdio_al_dev);
- sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":claim IRQ for card "
- "%d\n", sdio_al_dev->host->index);
-
- ret = sdio_claim_irq(func1, sdio_func_irq);
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to claim"
- " IRQ for card %d\n",
- sdio_al_dev->host->index);
- return ret;
- }
-
- sdio_al_dev->is_ready = true;
-
- /* Start worker before interrupt might happen */
- queue_work(sdio_al_dev->workqueue, &sdio_al_dev->sdio_al_work.work);
-
- start_inactive_time(sdio_al_dev);
-
- pr_debug(MODULE_NAME ":Ready.\n");
-
- return 0;
-}
-
-/**
- * Driver Tear-Down.
- *
- */
-static void sdio_al_tear_down(void)
-{
- int i, j;
- struct sdio_al_device *sdio_al_dev = NULL;
- struct sdio_func *func1;
-
- for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; ++i) {
- if (sdio_al->devices[i] == NULL)
- continue;
- sdio_al_dev = sdio_al->devices[i];
-
- if (sdio_al_dev->is_ready) {
- sdio_al_dev->is_ready = false; /* Flag worker to exit */
- sdio_al_dev->ask_mbox = false;
- ask_reading_mailbox(sdio_al_dev); /* Wakeup worker */
- /* allow gracefully exit of the worker thread */
- msleep(100);
-
- flush_workqueue(sdio_al_dev->workqueue);
- destroy_workqueue(sdio_al_dev->workqueue);
-
- sdio_al_vote_for_sleep(sdio_al_dev, 1);
-
- if (!sdio_al_claim_mutex_and_verify_dev(sdio_al_dev,
- __func__)) {
- if (!sdio_al_dev->card ||
- !sdio_al_dev->card->sdio_func[0]) {
- sdio_al_loge(sdio_al_dev->dev_log,
- MODULE_NAME
- ": %s: Invalid func1",
- __func__);
- return;
- }
- func1 = sdio_al_dev->card->sdio_func[0];
- sdio_release_irq(func1);
- sdio_disable_func(func1);
- sdio_al_release_mutex(sdio_al_dev, __func__);
- }
- }
-
- for (j = 0; j < SDIO_AL_MAX_CHANNELS; j++)
- sdio_al_dev->channel[j].signature = 0x0;
- sdio_al_dev->signature = 0;
-
- kfree(sdio_al_dev->sdioc_sw_header);
- kfree(sdio_al_dev->mailbox);
- kfree(sdio_al_dev->rx_flush_buf);
- kfree(sdio_al_dev);
- }
-
- sdio_al->pdata->config_mdm2ap_status(0);
-}
-
-/**
- * Find channel by name.
- *
- */
-static struct sdio_channel *find_channel_by_name(const char *name)
-{
- struct sdio_channel *ch = NULL;
- int i, j;
- struct sdio_al_device *sdio_al_dev = NULL;
-
- for (j = 0; j < MAX_NUM_OF_SDIO_DEVICES; ++j) {
- if (sdio_al->devices[j] == NULL)
- continue;
- sdio_al_dev = sdio_al->devices[j];
- for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
- if (sdio_al_dev->channel[i].state ==
- SDIO_CHANNEL_STATE_INVALID)
- continue;
- if (strncmp(sdio_al_dev->channel[i].name, name,
- CHANNEL_NAME_SIZE) == 0) {
- ch = &sdio_al_dev->channel[i];
- break;
- }
- }
- if (ch != NULL)
- break;
- }
-
- return ch;
-}
-
-/**
- * Find the minimal poll time.
- *
- */
-static int get_min_poll_time_msec(struct sdio_al_device *sdio_sl_dev)
-{
- int i;
- int poll_delay_msec = 0x0FFFFFFF;
-
- for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++)
- if ((sdio_sl_dev->channel[i].state ==
- SDIO_CHANNEL_STATE_OPEN) &&
- (sdio_sl_dev->channel[i].poll_delay_msec > 0) &&
- (sdio_sl_dev->channel[i].poll_delay_msec < poll_delay_msec))
- poll_delay_msec =
- sdio_sl_dev->channel[i].poll_delay_msec;
-
- if (poll_delay_msec == 0x0FFFFFFF)
- poll_delay_msec = SDIO_AL_POLL_TIME_NO_STREAMING;
-
- pr_debug(MODULE_NAME ":poll delay time is %d msec\n", poll_delay_msec);
-
- return poll_delay_msec;
-}
-
-/**
- * Open SDIO Channel.
- *
- * Enable the channel.
- * Set the channel context.
- * Trigger reading the mailbox to check available bytes.
- *
- */
-int sdio_open(const char *name, struct sdio_channel **ret_ch, void *priv,
- void (*notify)(void *priv, unsigned ch_event))
-{
- int ret = 0;
- struct sdio_channel *ch = NULL;
- struct sdio_al_device *sdio_al_dev = NULL;
-
- *ret_ch = NULL; /* default */
-
- ch = find_channel_by_name(name);
- if (ch == NULL) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":Can't find "
- "channel name %s\n", name);
- return -EINVAL;
- }
-
- sdio_al_dev = ch->sdio_al_dev;
- if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
- return -ENODEV;
-
- if ((ch->state != SDIO_CHANNEL_STATE_IDLE) &&
- (ch->state != SDIO_CHANNEL_STATE_CLOSED)) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Wrong ch %s "
- "state %d\n", name, ch->state);
- ret = -EPERM;
- goto exit_err;
- }
-
- if (sdio_al_dev->is_err) {
- SDIO_AL_ERR(__func__);
- ret = -ENODEV;
- goto exit_err;
- }
-
- ret = sdio_al_wake_up(sdio_al_dev, 1, ch);
- if (ret)
- goto exit_err;
-
- ch->notify = notify;
- ch->priv = priv;
-
- /* Note: Set caller returned context before interrupts are enabled */
- *ret_ch = ch;
-
- ret = open_channel(ch);
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sdio_open %s "
- "err=%d\n", name, -ret);
- goto exit_err;
- }
-
- CLOSE_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":sdio_open %s "
- "completed OK\n", name);
- if (sdio_al_dev->lpm_chan == INVALID_SDIO_CHAN) {
- if (sdio_al->sdioc_major == PEER_SDIOC_OLD_VERSION_MAJOR) {
- if (!ch->is_packet_mode) {
- sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME
- ":setting channel %s as "
- "lpm_chan\n", name);
- sdio_al_dev->lpm_chan = ch->num;
- }
- } else {
- sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ": "
- "setting channel %s as lpm_chan\n",
- name);
- sdio_al_dev->lpm_chan = ch->num;
- }
- }
-
-exit_err:
- sdio_al_release_mutex(sdio_al_dev, __func__);
- return ret;
-}
-EXPORT_SYMBOL(sdio_open);
-
-/**
- * Request peer operation
- * note: sanity checks of parameters done by caller
- * called under bus locked
- */
-static int peer_set_operation(u32 opcode,
- struct sdio_al_device *sdio_al_dev,
- struct sdio_channel *ch)
-{
- int ret;
- int offset;
- struct sdio_func *wk_func = NULL;
- u32 peer_operation;
- int loop_count = 0;
-
- if (!sdio_al_dev->card ||
- !sdio_al_dev->card->sdio_func[SDIO_AL_WAKEUP_FUNC-1]) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": NULL card or wk_func\n");
- ret = -ENODEV;
- goto exit;
- }
- wk_func = sdio_al_dev->card->sdio_func[SDIO_AL_WAKEUP_FUNC-1];
-
- /* calculate offset of peer_operation field in sw mailbox struct */
- offset = offsetof(struct peer_sdioc_sw_mailbox, ch_config) +
- sizeof(struct peer_sdioc_channel_config) * ch->num +
- offsetof(struct peer_sdioc_channel_config, peer_operation);
-
- ret = sdio_al_wake_up(sdio_al_dev, 1, ch);
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to "
- "wake up\n");
- goto exit;
- }
- /* request operation from MDM peer */
- peer_operation = PEER_OPERATION(opcode, PEER_OP_STATE_INIT);
- ret = sdio_memcpy_toio(ch->func, SDIOC_SW_MAILBOX_ADDR+offset,
- &peer_operation, sizeof(u32));
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":failed to "
- "request close operation\n");
- goto exit;
- }
- ret = sdio_al_enable_func_retry(wk_func, "wk_func");
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to enable"
- " Func#%d\n", wk_func->num);
- goto exit;
- }
- pr_debug(MODULE_NAME ":%s: wk_func enabled on ch %s\n",
- __func__, ch->name);
- /* send "start" operation to MDM */
- peer_operation = PEER_OPERATION(opcode, PEER_OP_STATE_START);
- ret = sdio_memcpy_toio(ch->func, SDIOC_SW_MAILBOX_ADDR+offset,
- &peer_operation, sizeof(u32));
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":failed to "
- "send start close operation\n");
- goto exit;
- }
- ret = sdio_disable_func(wk_func);
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to "
- "disable Func#%d\n", wk_func->num);
- goto exit;
- }
- /* poll for peer operation ack */
- while (peer_operation != 0) {
- ret = sdio_memcpy_fromio(ch->func,
- &peer_operation,
- SDIOC_SW_MAILBOX_ADDR+offset,
- sizeof(u32));
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ":failed to request ack on close"
- " operation, loop_count = %d\n",
- loop_count);
- goto exit;
- }
- loop_count++;
- if (loop_count > 10) {
- sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":%s: "
- "peer_operation=0x%x wait loop"
- " %d on ch %s\n", __func__,
- peer_operation, loop_count, ch->name);
- }
- }
-exit:
- return ret;
-}
-
-static int channel_close(struct sdio_channel *ch, int flush_flag)
-{
- int ret;
- struct sdio_al_device *sdio_al_dev = NULL;
- int flush_len;
- ulong flush_expires;
-
- if (!ch) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
- "channel\n", __func__);
- return -ENODEV;
- }
-
- if (!ch->func) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: NULL func"
- " on channel:%d\n", __func__, ch->num);
- return -ENODEV;
- }
-
- sdio_al_dev = ch->sdio_al_dev;
- if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
- return -ENODEV;
-
- if (!sdio_al_dev->ch_close_supported) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: Not "
- "supported by mdm, ch %s\n",
- __func__, ch->name);
- ret = -ENOTSUPP;
- goto error_exit;
- }
-
- if (sdio_al_dev->is_err) {
- SDIO_AL_ERR(__func__);
- ret = -ENODEV;
- goto error_exit;
- }
- if (ch->state != SDIO_CHANNEL_STATE_OPEN) {
- sdio_al_loge(sdio_al_dev->dev_log,
- MODULE_NAME ":%s: ch %s is not in "
- "open state (%d)\n",
- __func__, ch->name, ch->state);
- ret = -ENODEV;
- goto error_exit;
- }
- ch->state = SDIO_CHANNEL_STATE_CLOSING;
- ret = peer_set_operation(PEER_OP_CODE_CLOSE, sdio_al_dev, ch);
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: "
- "peer_set_operation() failed: %d\n",
- __func__, ret);
- ret = -ENODEV;
- goto error_exit;
- }
- /* udate poll time for opened channels */
- if (ch->poll_delay_msec > 0) {
- sdio_al_dev->poll_delay_msec =
- get_min_poll_time_msec(sdio_al_dev);
- }
- sdio_al_release_mutex(ch->sdio_al_dev, __func__);
-
- flush_expires = jiffies +
- msecs_to_jiffies(SDIO_CLOSE_FLUSH_TIMEOUT_MSEC);
- /* flush rx packets of the channel */
- if (flush_flag) {
- do {
- while (ch->read_avail > 0) {
- flush_len = ch->read_avail;
- ret = sdio_read_internal(ch,
- sdio_al_dev->rx_flush_buf,
- flush_len);
- if (ret) {
- sdio_al_loge(&sdio_al->gen_log,
- MODULE_NAME ":%s sdio_read"
- " failed: %d, ch %s\n",
- __func__, ret,
- ch->name);
- return ret;
- }
-
- if (time_after(jiffies, flush_expires) != 0) {
- sdio_al_loge(&sdio_al->gen_log,
- MODULE_NAME ":%s flush rx "
- "packets timeout: ch %s\n",
- __func__, ch->name);
- sdio_al_get_into_err_state(sdio_al_dev);
- return -EBUSY;
- }
- }
- msleep(100);
- if (ch->signature != SDIO_AL_SIGNATURE) {
- sdio_al_loge(&sdio_al->gen_log,
- MODULE_NAME ":%s: after sleep,"
- " invalid signature"
- " 0x%x\n", __func__,
- ch->signature);
- return -ENODEV;
- }
- if (sdio_al_claim_mutex_and_verify_dev(ch->sdio_al_dev,
- __func__))
- return -ENODEV;
-
- ret = read_mailbox(sdio_al_dev, false);
- if (ret) {
- sdio_al_loge(&sdio_al->gen_log,
- MODULE_NAME ":%s: failed to"
- " read mailbox", __func__);
- goto error_exit;
- }
- sdio_al_release_mutex(ch->sdio_al_dev, __func__);
- } while (ch->read_avail > 0);
- }
- if (sdio_al_claim_mutex_and_verify_dev(ch->sdio_al_dev,
- __func__))
- return -ENODEV;
- /* disable function to be able to open the channel again */
- ret = sdio_disable_func(ch->func);
- if (ret) {
- sdio_al_loge(&sdio_al->gen_log,
- MODULE_NAME ":Fail to disable Func#%d\n",
- ch->func->num);
- goto error_exit;
- }
- ch->state = SDIO_CHANNEL_STATE_CLOSED;
- CLOSE_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":%s: Ch %s closed "
- "successfully\n", __func__, ch->name);
-
-error_exit:
- sdio_al_release_mutex(ch->sdio_al_dev, __func__);
-
- return ret;
-}
-
-/**
- * Close SDIO Channel.
- *
- */
-int sdio_close(struct sdio_channel *ch)
-{
- return channel_close(ch, true);
-}
-EXPORT_SYMBOL(sdio_close);
-
-/**
- * Get the number of available bytes to write.
- *
- */
-int sdio_write_avail(struct sdio_channel *ch)
-{
- if (!ch) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
- "channel\n", __func__);
- return -ENODEV;
- }
- if (ch->signature != SDIO_AL_SIGNATURE) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: "
- "Invalid signature 0x%x\n", __func__,
- ch->signature);
- return -ENODEV;
- }
- if (ch->state != SDIO_CHANNEL_STATE_OPEN) {
- sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME ":%s: "
- "channel %s state is not open (%d)\n",
- __func__, ch->name, ch->state);
- return -ENODEV;
- }
- pr_debug(MODULE_NAME ":sdio_write_avail %s 0x%x\n",
- ch->name, ch->write_avail);
-
- return ch->write_avail;
-}
-EXPORT_SYMBOL(sdio_write_avail);
-
-/**
- * Get the number of available bytes to read.
- *
- */
-int sdio_read_avail(struct sdio_channel *ch)
-{
- if (!ch) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
- "channel\n", __func__);
- return -ENODEV;
- }
- if (ch->signature != SDIO_AL_SIGNATURE) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: "
- "Invalid signature 0x%x\n", __func__,
- ch->signature);
- return -ENODEV;
- }
- if (ch->state != SDIO_CHANNEL_STATE_OPEN) {
- sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME ":%s: "
- "channel %s state is not open (%d)\n",
- __func__, ch->name, ch->state);
- return -ENODEV;
- }
- pr_debug(MODULE_NAME ":sdio_read_avail %s 0x%x\n",
- ch->name, ch->read_avail);
-
- return ch->read_avail;
-}
-EXPORT_SYMBOL(sdio_read_avail);
-
-static int sdio_read_from_closed_ch(struct sdio_channel *ch, int len)
-{
- int ret = 0;
- struct sdio_al_device *sdio_al_dev = NULL;
-
- if (!ch) {
- sdio_al_loge(ch->sdio_al_dev->dev_log,
- MODULE_NAME ":%s: NULL channel\n", __func__);
- return -ENODEV;
- }
-
- sdio_al_dev = ch->sdio_al_dev;
- if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
- return -ENODEV;
-
- ret = sdio_memcpy_fromio(ch->func, sdio_al_dev->rx_flush_buf,
- PIPE_RX_FIFO_ADDR, len);
-
- if (ret) {
- sdio_al_loge(ch->sdio_al_dev->dev_log,
- MODULE_NAME ":ch %s: %s err=%d, len=%d\n",
- ch->name, __func__, -ret, len);
- sdio_al_dev->is_err = true;
- sdio_al_release_mutex(sdio_al_dev, __func__);
- return ret;
- }
-
- restart_inactive_time(sdio_al_dev);
-
- sdio_al_release_mutex(sdio_al_dev, __func__);
-
- return 0;
-}
-
-/**
- * Internal read from SDIO Channel.
- *
- * Reading from the pipe will trigger interrupt if there are
- * other pending packets on the SDIO-Client.
- *
- */
-static int sdio_read_internal(struct sdio_channel *ch, void *data, int len)
-{
- int ret = 0;
- struct sdio_al_device *sdio_al_dev = NULL;
-
- if (!ch) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
- "channel\n", __func__);
- return -ENODEV;
- }
- if (!data) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL data\n",
- __func__);
- return -ENODEV;
- }
- if (len == 0) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":channel %s trying"
- " to read 0 bytes\n", ch->name);
- return -EINVAL;
- }
-
- if (ch->signature != SDIO_AL_SIGNATURE) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: Invalid "
- "signature 0x%x\n", __func__, ch->signature);
- return -ENODEV;
- }
-
- sdio_al_dev = ch->sdio_al_dev;
- if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
- return -ENODEV;
-
- if (sdio_al_dev->is_err) {
- SDIO_AL_ERR(__func__);
- ret = -ENODEV;
- goto exit;
- }
-
- /* lpm policy says we can't go to sleep when we have pending rx data,
- so either we had rx interrupt and woken up, or we never went to
- sleep */
- if (sdio_al_dev->is_ok_to_sleep) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: called "
- "when is_ok_to_sleep is set for ch %s, len=%d,"
- " last_any_read_avail=%d, last_read_avail=%d, "
- "last_old_read_avail=%d", __func__, ch->name,
- len, ch->statistics.last_any_read_avail,
- ch->statistics.last_read_avail,
- ch->statistics.last_old_read_avail);
- }
- BUG_ON(sdio_al_dev->is_ok_to_sleep);
-
- if ((ch->state != SDIO_CHANNEL_STATE_OPEN) &&
- (ch->state != SDIO_CHANNEL_STATE_CLOSING)) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s wrong "
- "channel %s state %d\n",
- __func__, ch->name, ch->state);
- ret = -EINVAL;
- goto exit;
- }
-
- DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":start ch %s read %d "
- "avail %d.\n", ch->name, len, ch->read_avail);
-
- restart_inactive_time(sdio_al_dev);
-
- if ((ch->is_packet_mode) && (len != ch->read_avail)) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sdio_read ch "
- "%s len != read_avail\n", ch->name);
- ret = -EINVAL;
- goto exit;
- }
-
- if (len > ch->read_avail) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":ERR ch %s: "
- "reading more bytes (%d) than the avail(%d).\n",
- ch->name, len, ch->read_avail);
- ret = -ENOMEM;
- goto exit;
- }
-
- ret = sdio_memcpy_fromio(ch->func, data, PIPE_RX_FIFO_ADDR, len);
-
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":ch %s: "
- "sdio_read err=%d, len=%d, read_avail=%d, "
- "last_read_avail=%d, last_old_read_avail=%d\n",
- ch->name, -ret, len, ch->read_avail,
- ch->statistics.last_read_avail,
- ch->statistics.last_old_read_avail);
- sdio_al_get_into_err_state(sdio_al_dev);
- goto exit;
- }
-
- ch->statistics.total_read_times++;
-
- /* Remove handled packet from the list regardless if ret is ok */
- if (ch->is_packet_mode)
- remove_handled_rx_packet(ch);
- else
- ch->read_avail -= len;
-
- ch->total_rx_bytes += len;
- DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":end ch %s read %d "
- "avail %d total %d.\n", ch->name, len,
- ch->read_avail, ch->total_rx_bytes);
-
- if ((ch->read_avail == 0) && !(ch->is_packet_mode))
- ask_reading_mailbox(sdio_al_dev);
-
-exit:
- sdio_al_release_mutex(sdio_al_dev, __func__);
-
- return ret;
-}
-
-/**
- * Read from SDIO Channel.
- *
- * Reading from the pipe will trigger interrupt if there are
- * other pending packets on the SDIO-Client.
- *
- */
-int sdio_read(struct sdio_channel *ch, void *data, int len)
-{
- if (!ch) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
- "channel\n", __func__);
- return -ENODEV;
- }
- if (ch->signature != SDIO_AL_SIGNATURE) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: "
- "Invalid signature 0x%x\n", __func__, ch->signature);
- return -ENODEV;
- }
- if (ch->state == SDIO_CHANNEL_STATE_OPEN) {
- return sdio_read_internal(ch, data, len);
- } else {
- sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME
- ":%s: Invalid channel %s state %d\n",
- __func__, ch->name, ch->state);
- }
- return -ENODEV;
-}
-EXPORT_SYMBOL(sdio_read);
-
-/**
- * Write to SDIO Channel.
- *
- */
-int sdio_write(struct sdio_channel *ch, const void *data, int len)
-{
- int ret = 0;
- struct sdio_al_device *sdio_al_dev = NULL;
-
- if (!ch) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
- "channel\n", __func__);
- return -ENODEV;
- }
- if (!data) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL data\n",
- __func__);
- return -ENODEV;
- }
- if (len == 0) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":channel %s trying"
- " to write 0 bytes\n", ch->name);
- return -EINVAL;
- }
-
- if (ch->signature != SDIO_AL_SIGNATURE) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: Invalid "
- "signature 0x%x\n", __func__, ch->signature);
- return -ENODEV;
- }
-
- sdio_al_dev = ch->sdio_al_dev;
- if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
- return -ENODEV;
-
- WARN_ON(len > ch->write_avail);
-
- if (sdio_al_dev->is_err) {
- SDIO_AL_ERR(__func__);
- ret = -ENODEV;
- goto exit;
- }
-
- if (ch->state != SDIO_CHANNEL_STATE_OPEN) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":writing to "
- "closed channel %s\n", ch->name);
- ret = -EINVAL;
- goto exit;
- }
-
- if (sdio_al_dev->is_ok_to_sleep) {
- ret = sdio_al_wake_up(sdio_al_dev, 1, ch);
- if (ret)
- goto exit;
- } else {
- restart_inactive_time(sdio_al_dev);
- }
-
- DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":start ch %s write %d "
- "avail %d.\n", ch->name, len, ch->write_avail);
-
- if (len > ch->write_avail) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":ERR ch %s: "
- "write more bytes (%d) than available %d.\n",
- ch->name, len, ch->write_avail);
- ret = -ENOMEM;
- goto exit;
- }
-
- ret = sdio_ch_write(ch, data, len);
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sdio_write "
- "on channel %s err=%d\n", ch->name, -ret);
- goto exit;
- }
-
- ch->total_tx_bytes += len;
- DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":end ch %s write %d "
- "avail %d total %d.\n", ch->name, len,
- ch->write_avail, ch->total_tx_bytes);
-
- /* Round up to whole buffer size */
- len = ROUND_UP(len, ch->peer_tx_buf_size);
- /* Protect from wraparound */
- len = min(len, (int) ch->write_avail);
- ch->write_avail -= len;
-
- if (ch->write_avail < ch->min_write_avail)
- ask_reading_mailbox(sdio_al_dev);
-
-exit:
- sdio_al_release_mutex(sdio_al_dev, __func__);
-
- return ret;
-}
-EXPORT_SYMBOL(sdio_write);
-
-static int __devinit msm_sdio_al_probe(struct platform_device *pdev)
-{
- if (!sdio_al) {
- pr_err(MODULE_NAME ": %s: NULL sdio_al\n", __func__);
- return -ENODEV;
- }
-
- sdio_al->pdata = pdev->dev.platform_data;
- return 0;
-}
-
-static int __devexit msm_sdio_al_remove(struct platform_device *pdev)
-{
- return 0;
-}
-
-static void sdio_al_close_all_channels(struct sdio_al_device *sdio_al_dev)
-{
- int j;
- int ret;
- struct sdio_channel *ch = NULL;
-
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s", __func__);
-
- if (!sdio_al_dev) {
- sdio_al_loge(sdio_al_dev->dev_log,
- MODULE_NAME ": %s: NULL device", __func__);
- return;
- }
- for (j = 0; j < SDIO_AL_MAX_CHANNELS; j++) {
- ch = &sdio_al_dev->channel[j];
-
- if (ch->state == SDIO_CHANNEL_STATE_OPEN) {
- sdio_al_loge(sdio_al_dev->dev_log,
- MODULE_NAME ": %s: Call to sdio_close() for"
- " ch %s\n", __func__, ch->name);
- ret = channel_close(ch, false);
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log,
- MODULE_NAME ": %s: failed sdio_close()"
- " for ch %s (%d)\n",
- __func__, ch->name, ret);
- }
- } else {
- pr_debug(MODULE_NAME ": %s: skip sdio_close() ch %s"
- " (state=%d)\n", __func__,
- ch->name, ch->state);
- }
- }
-}
-
-static void sdio_al_invalidate_sdio_clients(struct sdio_al_device *sdio_al_dev,
- struct platform_device **pdev_arr)
-{
- int j;
-
- pr_debug(MODULE_NAME ": %s: Notifying SDIO clients for card %d",
- __func__, sdio_al_dev->host->index);
- for (j = 0; j < SDIO_AL_MAX_CHANNELS; ++j) {
- if (sdio_al_dev->channel[j].state ==
- SDIO_CHANNEL_STATE_INVALID)
- continue;
- pdev_arr[j] = sdio_al_dev->channel[j].pdev;
- sdio_al_dev->channel[j].signature = 0x0;
- sdio_al_dev->channel[j].state =
- SDIO_CHANNEL_STATE_INVALID;
- }
-}
-
-static void sdio_al_modem_reset_operations(struct sdio_al_device
- *sdio_al_dev)
-{
- int ret = 0;
- struct platform_device *pdev_arr[SDIO_AL_MAX_CHANNELS];
- int j;
-
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s", __func__);
-
- if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
- return;
-
- if (sdio_al_dev->state == CARD_REMOVED) {
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: "
- "card %d is already removed", __func__,
- sdio_al_dev->host->index);
- goto exit_err;
- }
-
- if (sdio_al_dev->state == MODEM_RESTART) {
- sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ": %s: "
- "card %d was already notified for modem reset",
- __func__, sdio_al_dev->host->index);
- goto exit_err;
- }
-
- sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ": %s: Set the "
- "state to MODEM_RESTART for card %d",
- __func__, sdio_al_dev->host->index);
- sdio_al_dev->state = MODEM_RESTART;
- sdio_al_dev->is_ready = false;
-
- /* Stop mailbox timer */
- stop_and_del_timer(sdio_al_dev);
-
- if ((sdio_al_dev->is_ok_to_sleep) &&
- (!sdio_al_dev->is_err)) {
- pr_debug(MODULE_NAME ": %s: wakeup modem for "
- "card %d", __func__,
- sdio_al_dev->host->index);
- ret = sdio_al_wake_up(sdio_al_dev, 1, NULL);
- }
-
- if (!ret && (!sdio_al_dev->is_err) && sdio_al_dev->card &&
- sdio_al_dev->card->sdio_func[0]) {
- sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME
- ": %s: sdio_release_irq for card %d",
- __func__,
- sdio_al_dev->host->index);
- sdio_release_irq(sdio_al_dev->card->sdio_func[0]);
- }
-
- memset(pdev_arr, 0, sizeof(pdev_arr));
- sdio_al_invalidate_sdio_clients(sdio_al_dev, pdev_arr);
-
- sdio_al_release_mutex(sdio_al_dev, __func__);
-
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: Notifying SDIO "
- "clients for card %d",
- __func__, sdio_al_dev->host->index);
- for (j = 0; j < SDIO_AL_MAX_CHANNELS; j++) {
- if (!pdev_arr[j])
- continue;
- platform_device_unregister(pdev_arr[j]);
- }
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: Finished Notifying "
- "SDIO clients for card %d",
- __func__, sdio_al_dev->host->index);
-
- return;
-
-exit_err:
- sdio_al_release_mutex(sdio_al_dev, __func__);
- return;
-}
-
-#ifdef CONFIG_MSM_SUBSYSTEM_RESTART
-static void sdio_al_reset(void)
-{
- int i;
- struct sdio_al_device *sdio_al_dev;
-
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s", __func__);
-
- for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; i++) {
- if (sdio_al->devices[i] == NULL) {
- pr_debug(MODULE_NAME ": %s: NULL device in index %d",
- __func__, i);
- continue;
- }
- sdio_al_dev = sdio_al->devices[i];
- sdio_al_modem_reset_operations(sdio_al->devices[i]);
- }
-
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s completed", __func__);
-}
-#endif
-
-static void msm_sdio_al_shutdown(struct platform_device *pdev)
-{
- int i;
- struct sdio_al_device *sdio_al_dev;
-
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME
- "Initiating msm_sdio_al_shutdown...");
-
- for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; i++) {
- if (sdio_al->devices[i] == NULL) {
- pr_debug(MODULE_NAME ": %s: NULL device in index %d",
- __func__, i);
- continue;
- }
- sdio_al_dev = sdio_al->devices[i];
-
- if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
- return;
-
- if (sdio_al_dev->ch_close_supported)
- sdio_al_close_all_channels(sdio_al_dev);
-
- sdio_al_release_mutex(sdio_al_dev, __func__);
-
- sdio_al_modem_reset_operations(sdio_al_dev);
- }
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: "
- "msm_sdio_al_shutdown complete.", __func__);
-}
-
-static struct platform_driver msm_sdio_al_driver = {
- .probe = msm_sdio_al_probe,
- .remove = __exit_p(msm_sdio_al_remove),
- .shutdown = msm_sdio_al_shutdown,
- .driver = {
- .name = "msm_sdio_al",
- },
-};
-
-/**
- * Initialize SDIO_AL channels.
- *
- */
-static int init_channels(struct sdio_al_device *sdio_al_dev)
-{
- int ret = 0;
- int i;
-
- if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
- return -ENODEV;
-
- ret = read_sdioc_software_header(sdio_al_dev,
- sdio_al_dev->sdioc_sw_header);
- if (ret)
- goto exit;
-
- ret = sdio_al_setup(sdio_al_dev);
- if (ret)
- goto exit;
-
- for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
- int ch_name_size;
- if (sdio_al_dev->channel[i].state == SDIO_CHANNEL_STATE_INVALID)
- continue;
- if (sdio_al->unittest_mode) {
- memset(sdio_al_dev->channel[i].ch_test_name, 0,
- sizeof(sdio_al_dev->channel[i].ch_test_name));
- ch_name_size = strnlen(sdio_al_dev->channel[i].name,
- CHANNEL_NAME_SIZE);
- strncpy(sdio_al_dev->channel[i].ch_test_name,
- sdio_al_dev->channel[i].name,
- ch_name_size);
- strncat(sdio_al_dev->channel[i].ch_test_name +
- ch_name_size,
- SDIO_TEST_POSTFIX,
- SDIO_TEST_POSTFIX_SIZE);
- pr_debug(MODULE_NAME ":pdev.name = %s\n",
- sdio_al_dev->channel[i].ch_test_name);
- sdio_al_dev->channel[i].pdev = platform_device_alloc(
- sdio_al_dev->channel[i].ch_test_name, -1);
- } else {
- pr_debug(MODULE_NAME ":pdev.name = %s\n",
- sdio_al_dev->channel[i].name);
- sdio_al_dev->channel[i].pdev = platform_device_alloc(
- sdio_al_dev->channel[i].name, -1);
- }
- if (!sdio_al_dev->channel[i].pdev) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ":NULL platform device for ch %s",
- sdio_al_dev->channel[i].name);
- sdio_al_dev->channel[i].state =
- SDIO_CHANNEL_STATE_INVALID;
- continue;
- }
- ret = platform_device_add(sdio_al_dev->channel[i].pdev);
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ":platform_device_add failed, "
- "ret=%d\n", ret);
- sdio_al_dev->channel[i].state =
- SDIO_CHANNEL_STATE_INVALID;
- }
- }
-
-exit:
- sdio_al_release_mutex(sdio_al_dev, __func__);
- return ret;
-}
-
-/**
- * Initialize SDIO_AL channels according to the client setup.
- * This function also check if the client is in boot mode and
- * flashless boot is required to be activated or the client is
- * up and running.
- *
- */
-static int sdio_al_client_setup(struct sdio_al_device *sdio_al_dev)
-{
- int ret = 0;
- struct sdio_func *func1;
- int signature = 0;
-
- if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
- return -ENODEV;
-
- if (!sdio_al_dev->card || !sdio_al_dev->card->sdio_func[0]) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":NULL card or "
- "func1\n");
- sdio_al_release_mutex(sdio_al_dev, __func__);
- return -ENODEV;
- }
- func1 = sdio_al_dev->card->sdio_func[0];
-
- /* Read the header signature to determine the status of the MDM
- * SDIO Client
- */
- signature = sdio_readl(func1, SDIOC_SW_HEADER_ADDR, &ret);
- sdio_al_release_mutex(sdio_al_dev, __func__);
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":fail to read "
- "signature from sw header.\n");
- return ret;
- }
-
- switch (signature) {
- case PEER_SDIOC_SW_MAILBOX_BOOT_SIGNATURE:
- if (sdio_al_dev == sdio_al->bootloader_dev) {
- sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":setup "
- "bootloader on card %d\n",
- sdio_al_dev->host->index);
- return sdio_al_bootloader_setup();
- } else {
- sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":wait "
- "for bootloader completion "
- "on card %d\n",
- sdio_al_dev->host->index);
- return sdio_al_wait_for_bootloader_comp(sdio_al_dev);
- }
- case PEER_SDIOC_SW_MAILBOX_SIGNATURE:
- case PEER_SDIOC_SW_MAILBOX_UT_SIGNATURE:
- return init_channels(sdio_al_dev);
- default:
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Invalid "
- "signature 0x%x\n", signature);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static void clean_sdio_al_device_data(struct sdio_al_device *sdio_al_dev)
-{
- sdio_al_dev->is_ready = 0;
- sdio_al_dev->bootloader_done = 0;
- sdio_al_dev->lpm_chan = 0;
- sdio_al_dev->is_ok_to_sleep = 0;
- sdio_al_dev->inactivity_time = 0;
- sdio_al_dev->poll_delay_msec = 0;
- sdio_al_dev->is_timer_initialized = 0;
- sdio_al_dev->is_err = 0;
- sdio_al_dev->is_suspended = 0;
- sdio_al_dev->flashless_boot_on = 0;
- sdio_al_dev->ch_close_supported = 0;
- sdio_al_dev->print_after_interrupt = 0;
- memset(sdio_al_dev->sdioc_sw_header, 0,
- sizeof(*sdio_al_dev->sdioc_sw_header));
- memset(sdio_al_dev->mailbox, 0, sizeof(*sdio_al_dev->mailbox));
- memset(sdio_al_dev->rx_flush_buf, 0,
- sizeof(*sdio_al_dev->rx_flush_buf));
-}
-
-/*
- * SDIO driver functions
- */
-static int sdio_al_sdio_probe(struct sdio_func *func,
- const struct sdio_device_id *sdio_dev_id)
-{
- int ret = 0;
- struct sdio_al_device *sdio_al_dev = NULL;
- int i;
- struct mmc_card *card = NULL;
-
- if (!func) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL func\n",
- __func__);
- return -ENODEV;
- }
- card = func->card;
-
- if (!card) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL card\n",
- __func__);
- return -ENODEV;
- }
-
- if (!card->sdio_func[0]) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
- "func1\n",
- __func__);
- return -ENODEV;
- }
-
- if (card->sdio_funcs < SDIO_AL_MAX_FUNCS) {
- dev_info(&card->dev,
- "SDIO-functions# %d less than expected.\n",
- card->sdio_funcs);
- return -ENODEV;
- }
-
- /* Check if there is already a device for this card */
- for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; ++i) {
- if (sdio_al->devices[i] == NULL)
- continue;
- if (sdio_al->devices[i]->host == card->host) {
- sdio_al_dev = sdio_al->devices[i];
- if (sdio_al_dev->state == CARD_INSERTED)
- return 0;
- clean_sdio_al_device_data(sdio_al_dev);
- break;
- }
- }
-
- if (!sdio_al_dev) {
- sdio_al_dev = kzalloc(sizeof(struct sdio_al_device),
- GFP_KERNEL);
- if (sdio_al_dev == NULL)
- return -ENOMEM;
-
- for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES ; ++i)
- if (sdio_al->devices[i] == NULL) {
- sdio_al->devices[i] = sdio_al_dev;
- sdio_al_dev->dev_log = &sdio_al->device_log[i];
- spin_lock_init(&sdio_al_dev->dev_log->log_lock);
- #ifdef CONFIG_DEBUG_FS
- sdio_al_dbgfs_log[i].data =
- sdio_al_dev->dev_log->buffer;
- sdio_al_dbgfs_log[i].size =
- SDIO_AL_DEBUG_LOG_SIZE;
- #endif
- break;
- }
- if (i == MAX_NUM_OF_SDIO_DEVICES) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":No space "
- "in devices array for the device\n");
- return -ENOMEM;
- }
- }
-
- dev_info(&card->dev, "SDIO Card claimed.\n");
- sdio_al->skip_print_info = 0;
-
- sdio_al_dev->state = CARD_INSERTED;
-
- if (card->host->index == SDIO_BOOTLOADER_CARD_INDEX)
- sdio_al->bootloader_dev = sdio_al_dev;
-
- sdio_al_dev->is_ready = false;
-
- sdio_al_dev->signature = SDIO_AL_SIGNATURE;
-
- sdio_al_dev->is_suspended = 0;
- sdio_al_dev->is_timer_initialized = false;
-
- sdio_al_dev->lpm_chan = INVALID_SDIO_CHAN;
-
- sdio_al_dev->card = card;
- sdio_al_dev->host = card->host;
-
- if (!sdio_al_dev->mailbox) {
- sdio_al_dev->mailbox = kzalloc(sizeof(struct sdio_mailbox),
- GFP_KERNEL);
- if (sdio_al_dev->mailbox == NULL)
- return -ENOMEM;
- }
-
- if (!sdio_al_dev->sdioc_sw_header) {
- sdio_al_dev->sdioc_sw_header
- = kzalloc(sizeof(*sdio_al_dev->sdioc_sw_header),
- GFP_KERNEL);
- if (sdio_al_dev->sdioc_sw_header == NULL)
- return -ENOMEM;
- }
-
- if (!sdio_al_dev->rx_flush_buf) {
- sdio_al_dev->rx_flush_buf = kzalloc(RX_FLUSH_BUFFER_SIZE,
- GFP_KERNEL);
- if (sdio_al_dev->rx_flush_buf == NULL) {
- sdio_al_loge(&sdio_al->gen_log,
- MODULE_NAME ":Fail to allocate "
- "rx_flush_buf for card %d\n",
- card->host->index);
- return -ENOMEM;
- }
- }
-
- sdio_al_dev->timer.data = (unsigned long)sdio_al_dev;
-
- wake_lock_init(&sdio_al_dev->wake_lock, WAKE_LOCK_SUSPEND, MODULE_NAME);
- /* Don't allow sleep until all required clients register */
- sdio_al_vote_for_sleep(sdio_al_dev, 0);
-
- if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
- return -ENODEV;
-
- /* Init Func#1 */
- ret = sdio_al_enable_func_retry(card->sdio_func[0], "Init Func#1");
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to "
- "enable Func#%d\n", card->sdio_func[0]->num);
- goto exit;
- }
-
- /* Patch Func CIS tuple issue */
- ret = sdio_set_block_size(card->sdio_func[0], SDIO_AL_BLOCK_SIZE);
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to set "
- "block size, Func#%d\n", card->sdio_func[0]->num);
- goto exit;
- }
- sdio_al_dev->card->sdio_func[0]->max_blksize = SDIO_AL_BLOCK_SIZE;
-
- sdio_al_dev->workqueue = create_singlethread_workqueue("sdio_al_wq");
- sdio_al_dev->sdio_al_work.sdio_al_dev = sdio_al_dev;
- init_waitqueue_head(&sdio_al_dev->wait_mbox);
-
- ret = sdio_al_client_setup(sdio_al_dev);
-
-exit:
- sdio_al_release_mutex(sdio_al_dev, __func__);
- return ret;
-}
-
-static void sdio_al_sdio_remove(struct sdio_func *func)
-{
- struct sdio_al_device *sdio_al_dev = NULL;
- int i;
- struct mmc_card *card = NULL;
- struct platform_device *pdev_arr[SDIO_AL_MAX_CHANNELS];
-
- if (!func) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL func\n",
- __func__);
- return;
- }
- card = func->card;
-
- if (!card) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL card\n",
- __func__);
- return;
- }
-
- /* Find the sdio_al_device of this card */
- for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; ++i) {
- if (sdio_al->devices[i] == NULL)
- continue;
- if (sdio_al->devices[i]->card == card) {
- sdio_al_dev = sdio_al->devices[i];
- break;
- }
- }
- if (sdio_al_dev == NULL) {
- pr_debug(MODULE_NAME ":%s :NULL sdio_al_dev for card %d\n",
- __func__, card->host->index);
- return;
- }
-
- if (sdio_al_claim_mutex(sdio_al_dev, __func__))
- return;
-
- if (sdio_al_dev->state == CARD_REMOVED) {
- sdio_al_release_mutex(sdio_al_dev, __func__);
- return;
- }
-
- if (!card->sdio_func[0]) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
- "func1\n", __func__);
- sdio_al_release_mutex(sdio_al_dev, __func__);
- return;
- }
-
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s for card %d\n",
- __func__, card->host->index);
-
- sdio_al_dev->state = CARD_REMOVED;
-
- memset(pdev_arr, 0, sizeof(pdev_arr));
- sdio_al_invalidate_sdio_clients(sdio_al_dev, pdev_arr);
-
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s: ask_reading_mailbox "
- "for card %d\n", __func__, card->host->index);
- sdio_al_dev->is_ready = false; /* Flag worker to exit */
- sdio_al_dev->ask_mbox = false;
- ask_reading_mailbox(sdio_al_dev); /* Wakeup worker */
-
- stop_and_del_timer(sdio_al_dev);
-
- sdio_al_release_mutex(sdio_al_dev, __func__);
-
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: Notifying SDIO "
- "clients for card %d",
- __func__, sdio_al_dev->host->index);
- for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
- if (!pdev_arr[i])
- continue;
- platform_device_unregister(pdev_arr[i]);
- }
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: Finished Notifying "
- "SDIO clients for card %d",
- __func__, sdio_al_dev->host->index);
-
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s: vote for sleep for "
- "card %d\n", __func__, card->host->index);
- sdio_al_vote_for_sleep(sdio_al_dev, 1);
-
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s: flush_workqueue for "
- "card %d\n", __func__, card->host->index);
- flush_workqueue(sdio_al_dev->workqueue);
- destroy_workqueue(sdio_al_dev->workqueue);
- wake_lock_destroy(&sdio_al_dev->wake_lock);
-
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s: sdio card %d removed."
- "\n", __func__, card->host->index);
-}
-
-static void sdio_print_mailbox(char *prefix_str, struct sdio_mailbox *mailbox)
-{
- int k = 0;
- char buf[256];
- char buf1[10];
-
- if (!mailbox) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": mailbox is "
- "NULL\n");
- return;
- }
-
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: pipes 0_7: eot=0x%x,"
- " thresh=0x%x, overflow=0x%x, "
- "underflow=0x%x, mask_thresh=0x%x\n",
- prefix_str, mailbox->eot_pipe_0_7,
- mailbox->thresh_above_limit_pipe_0_7,
- mailbox->overflow_pipe_0_7,
- mailbox->underflow_pipe_0_7,
- mailbox->mask_thresh_above_limit_pipe_0_7);
-
- memset(buf, 0, sizeof(buf));
- strncat(buf, ": bytes_avail:", sizeof(buf));
-
- for (k = 0 ; k < SDIO_AL_ACTIVE_PIPES ; ++k) {
- snprintf(buf1, sizeof(buf1), "%d, ",
- mailbox->pipe_bytes_avail[k]);
- strncat(buf, buf1, sizeof(buf));
- }
-
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME "%s", buf);
-}
-
-static void sdio_al_print_info(void)
-{
- int i = 0;
- int j = 0;
- int ret = 0;
- struct sdio_mailbox *mailbox = NULL;
- struct sdio_mailbox *hw_mailbox = NULL;
- struct peer_sdioc_channel_config *ch_config = NULL;
- struct sdio_func *func1 = NULL;
- struct sdio_func *lpm_func = NULL;
- int offset = 0;
- int is_ok_to_sleep = 0;
- char buf[50];
-
- if (sdio_al->skip_print_info == 1)
- return;
-
- sdio_al->skip_print_info = 1;
-
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s - SDIO DEBUG INFO\n",
- __func__);
-
- if (!sdio_al) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s - ERROR - "
- "sdio_al is NULL\n", __func__);
- return;
- }
-
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": GPIO mdm2ap_status=%d\n",
- sdio_al->pdata->get_mdm2ap_status());
-
- for (j = 0 ; j < MAX_NUM_OF_SDIO_DEVICES ; ++j) {
- struct sdio_al_device *sdio_al_dev = sdio_al->devices[j];
-
- if (sdio_al_dev == NULL) {
- continue;
- }
-
- if (!sdio_al_dev->host) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": Host"
- " is NULL\n);");
- continue;
- }
-
- snprintf(buf, sizeof(buf), "Card#%d: Shadow HW MB",
- sdio_al_dev->host->index);
-
- /* printing Shadowing HW Mailbox*/
- mailbox = sdio_al_dev->mailbox;
- sdio_print_mailbox(buf, mailbox);
-
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": Card#%d: "
- "is_ok_to_sleep=%d\n",
- sdio_al_dev->host->index,
- sdio_al_dev->is_ok_to_sleep);
-
-
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": Card#%d: "
- "Shadow channels SW MB:",
- sdio_al_dev->host->index);
-
- /* printing Shadowing SW Mailbox per channel*/
- for (i = 0 ; i < SDIO_AL_MAX_CHANNELS ; ++i) {
- struct sdio_channel *ch = &sdio_al_dev->channel[i];
-
- if (ch == NULL) {
- continue;
- }
-
- if (ch->state == SDIO_CHANNEL_STATE_INVALID)
- continue;
-
- ch_config = &sdio_al_dev->channel[i].ch_config;
-
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": Ch %s: max_rx_thres=0x%x, "
- "max_tx_thres=0x%x, tx_buf=0x%x, "
- "is_packet_mode=%d, "
- "max_packet=0x%x, min_write=0x%x",
- ch->name, ch_config->max_rx_threshold,
- ch_config->max_tx_threshold,
- ch_config->tx_buf_size,
- ch_config->is_packet_mode,
- ch_config->max_packet_size,
- ch->min_write_avail);
-
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": total_rx=0x%x, total_tx=0x%x, "
- "read_avail=0x%x, write_avail=0x%x, "
- "rx_pending=0x%x, num_reads=0x%x, "
- "num_notifs=0x%x", ch->total_rx_bytes,
- ch->total_tx_bytes, ch->read_avail,
- ch->write_avail, ch->rx_pending_bytes,
- ch->statistics.total_read_times,
- ch->statistics.total_notifs);
- } /* end loop over all channels */
-
- } /* end loop over all devices */
-
- /* reading from client and printing is_host_ok_to_sleep per device */
- for (j = 0 ; j < MAX_NUM_OF_SDIO_DEVICES ; ++j) {
- struct sdio_al_device *sdio_al_dev = sdio_al->devices[j];
-
- if (sdio_al_verify_func1(sdio_al_dev, __func__))
- continue;
-
- if (!sdio_al_dev->host) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": Host is NULL");
- continue;
- }
-
- if (sdio_al_dev->lpm_chan == INVALID_SDIO_CHAN) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": %s - for Card#%d, is lpm_chan=="
- "INVALID_SDIO_CHAN. continuing...",
- __func__, sdio_al_dev->host->index);
- continue;
- }
-
- offset = offsetof(struct peer_sdioc_sw_mailbox, ch_config)+
- sizeof(struct peer_sdioc_channel_config) *
- sdio_al_dev->lpm_chan+
- offsetof(struct peer_sdioc_channel_config, is_host_ok_to_sleep);
-
- lpm_func = sdio_al_dev->card->sdio_func[sdio_al_dev->
- lpm_chan+1];
- if (!lpm_func) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": %s - lpm_func is NULL for card#%d"
- " continuing...\n", __func__,
- sdio_al_dev->host->index);
- continue;
- }
-
- if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
- return;
- ret = sdio_memcpy_fromio(lpm_func,
- &is_ok_to_sleep,
- SDIOC_SW_MAILBOX_ADDR+offset,
- sizeof(int));
- sdio_al_release_mutex(sdio_al_dev, __func__);
-
- if (ret)
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": %s - fail to read "
- "is_HOST_ok_to_sleep from mailbox for card %d",
- __func__, sdio_al_dev->host->index);
- else
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": Card#%d: "
- "is_HOST_ok_to_sleep=%d\n",
- sdio_al_dev->host->index,
- is_ok_to_sleep);
- }
-
- for (j = 0 ; j < MAX_NUM_OF_SDIO_DEVICES ; ++j) {
- struct sdio_al_device *sdio_al_dev = sdio_al->devices[j];
-
- if (!sdio_al_dev)
- continue;
-
- /* Reading HW Mailbox */
- hw_mailbox = sdio_al_dev->mailbox;
-
- if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
- return;
-
- if (!sdio_al_dev->card || !sdio_al_dev->card->sdio_func[0]) {
- sdio_al_release_mutex(sdio_al_dev, __func__);
- return;
- }
- func1 = sdio_al_dev->card->sdio_func[0];
- ret = sdio_memcpy_fromio(func1, hw_mailbox,
- HW_MAILBOX_ADDR, sizeof(*hw_mailbox));
- sdio_al_release_mutex(sdio_al_dev, __func__);
-
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": fail to read "
- "mailbox for card#%d. "
- "continuing...\n",
- sdio_al_dev->host->index);
- continue;
- }
-
- snprintf(buf, sizeof(buf), "Card#%d: Current HW MB",
- sdio_al_dev->host->index);
-
- /* Printing HW Mailbox */
- sdio_print_mailbox(buf, hw_mailbox);
- }
-}
-
-static struct sdio_device_id sdio_al_sdioid[] = {
- {.class = 0, .vendor = 0x70, .device = 0x2460},
- {.class = 0, .vendor = 0x70, .device = 0x0460},
- {.class = 0, .vendor = 0x70, .device = 0x23F1},
- {.class = 0, .vendor = 0x70, .device = 0x23F0},
- {}
-};
-
-static struct sdio_driver sdio_al_sdiofn_driver = {
- .name = "sdio_al_sdiofn",
- .id_table = sdio_al_sdioid,
- .probe = sdio_al_sdio_probe,
- .remove = sdio_al_sdio_remove,
-};
-
-#ifdef CONFIG_MSM_SUBSYSTEM_RESTART
-/*
- * Callback for notifications from restart mudule.
- * This function handles only the BEFORE_RESTART notification.
- * Stop all the activity on the card and notify our clients.
- */
-static int sdio_al_subsys_notifier_cb(struct notifier_block *this,
- unsigned long notif_type,
- void *data)
-{
- if (notif_type != SUBSYS_BEFORE_SHUTDOWN) {
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: got "
- "notification %ld", __func__, notif_type);
- return NOTIFY_DONE;
- }
-
- sdio_al_reset();
- return NOTIFY_OK;
-}
-
-static struct notifier_block sdio_al_nb = {
- .notifier_call = sdio_al_subsys_notifier_cb,
-};
-#endif
-
-/**
- * Module Init.
- *
- * @warn: allocate sdio_al context before registering driver.
- *
- */
-static int __init sdio_al_init(void)
-{
- int ret = 0;
- int i;
-
- pr_debug(MODULE_NAME ":sdio_al_init\n");
-
- pr_info(MODULE_NAME ":SDIO-AL SW version %s\n",
- DRV_VERSION);
-
- sdio_al = kzalloc(sizeof(struct sdio_al), GFP_KERNEL);
- if (sdio_al == NULL)
- return -ENOMEM;
-
- for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES ; ++i)
- sdio_al->devices[i] = NULL;
-
- sdio_al->unittest_mode = false;
-
- sdio_al->debug.debug_lpm_on = debug_lpm_on;
- sdio_al->debug.debug_data_on = debug_data_on;
- sdio_al->debug.debug_close_on = debug_close_on;
-
-#ifdef CONFIG_DEBUG_FS
- sdio_al_debugfs_init();
-#endif
-
-
-#ifdef CONFIG_MSM_SUBSYSTEM_RESTART
- sdio_al->subsys_notif_handle = subsys_notif_register_notifier(
- "external_modem", &sdio_al_nb);
-#endif
-
- ret = platform_driver_register(&msm_sdio_al_driver);
- if (ret) {
- pr_err(MODULE_NAME ": platform_driver_register failed: %d\n",
- ret);
- goto exit;
- }
-
- sdio_register_driver(&sdio_al_sdiofn_driver);
-
- spin_lock_init(&sdio_al->gen_log.log_lock);
-
-exit:
- if (ret)
- kfree(sdio_al);
- return ret;
-}
-
-/**
- * Module Exit.
- *
- * Free allocated memory.
- * Disable SDIO-Card.
- * Unregister driver.
- *
- */
-static void __exit sdio_al_exit(void)
-{
- if (sdio_al == NULL)
- return;
-
- pr_debug(MODULE_NAME ":sdio_al_exit\n");
-
-#ifdef CONFIG_MSM_SUBSYSTEM_RESTART
- subsys_notif_unregister_notifier(
- sdio_al->subsys_notif_handle, &sdio_al_nb);
-#endif
-
- sdio_al_tear_down();
-
- sdio_unregister_driver(&sdio_al_sdiofn_driver);
-
- kfree(sdio_al);
-
-#ifdef CONFIG_DEBUG_FS
- sdio_al_debugfs_cleanup();
-#endif
-
- platform_driver_unregister(&msm_sdio_al_driver);
-
- pr_debug(MODULE_NAME ":sdio_al_exit complete\n");
-}
-
-module_init(sdio_al_init);
-module_exit(sdio_al_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("SDIO Abstraction Layer");
-MODULE_AUTHOR("Amir Samuelov <amirs@codeaurora.org>");
-MODULE_VERSION(DRV_VERSION);
-
diff --git a/arch/arm/mach-msm/sdio_al_dloader.c b/arch/arm/mach-msm/sdio_al_dloader.c
deleted file mode 100644
index f3effa8..0000000
--- a/arch/arm/mach-msm/sdio_al_dloader.c
+++ /dev/null
@@ -1,2574 +0,0 @@
-/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-/*
- * SDIO-Downloader
- *
- * To be used with Qualcomm's SDIO-Client connected to this host.
- */
-
-/* INCLUDES */
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/wakelock.h>
-#include <linux/workqueue.h>
-#include <linux/mmc/card.h>
-#include <linux/dma-mapping.h>
-#include <mach/dma.h>
-#include <linux/mmc/sdio_func.h>
-#include "sdio_al_private.h"
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/kthread.h>
-#include <linux/version.h>
-#include <linux/errno.h>
-#include <linux/debugfs.h>
-
-/* DEFINES AND MACROS */
-#define MAX_NUM_DEVICES 1
-#define TTY_SDIO_DEV "tty_sdio_0"
-#define TTY_SDIO_DEV_TEST "tty_sdio_test_0"
-#define SDIOC_MAILBOX_ADDRESS 0
-#define SDIO_DL_BLOCK_SIZE 512
-#define SDIO_DL_MAIN_THREAD_NAME "sdio_tty_main_thread"
-#define SDIOC_DL_BUFF_ADDRESS 0
-#define SDIOC_UP_BUFF_ADDRESS 0x4
-#define SDIOC_DL_BUFF_SIZE_OFFSET 0x8
-#define SDIOC_UP_BUFF_SIZE_OFFSET 0xC
-#define SDIOC_DL_WR_PTR 0x10
-#define SDIOC_DL_RD_PTR 0x14
-#define SDIOC_UL_WR_PTR 0x18
-#define SDIOC_UL_RD_PTR 0x1C
-#define SDIOC_EXIT_PTR 0x20
-#define SDIOC_OP_MODE_PTR 0x24
-#define SDIOC_PTRS_OFFSET 0x10
-#define SDIOC_PTR_REGS_SIZE 0x10
-#define SDIOC_CFG_REGS_SIZE 0x10
-#define WRITE_RETRIES 0xFFFFFFFF
-#define INPUT_SPEED 4800
-#define OUTPUT_SPEED 4800
-#define SDIOC_EXIT_CODE 0xDEADDEAD
-#define SLEEP_MS 10
-#define PRINTING_GAP 200
-#define TIMER_DURATION 10
-#define PUSH_TIMER_DURATION 5000
-#define MULTIPLE_RATIO 1
-#define MS_IN_SEC 1000
-#define BITS_IN_BYTE 8
-#define BYTES_IN_KB 1024
-#define WRITE_TILL_END_RETRIES 5
-#define SDIO_DLD_NORMAL_MODE_NAME "SDIO DLD NORMAL MODE"
-#define SDIO_DLD_BOOT_TEST_MODE_NAME "SDIO DLD BOOT TEST MODE"
-#define SDIO_DLD_AMSS_TEST_MODE_NAME "SDIO DLD AMSS TEST MODE"
-#define TEST_NAME_MAX_SIZE 30
-#define PUSH_STRING
-#define SDIO_DLD_OUTGOING_BUFFER_SIZE (48*1024*MULTIPLE_RATIO)
-
-/* FORWARD DECLARATIONS */
-static int sdio_dld_open(struct tty_struct *tty, struct file *file);
-static void sdio_dld_close(struct tty_struct *tty, struct file *file);
-static int sdio_dld_write_callback(struct tty_struct *tty,
- const unsigned char *buf, int count);
-static int sdio_dld_write_room(struct tty_struct *tty);
-static int sdio_dld_main_task(void *card);
-static void sdio_dld_print_info(void);
-#ifdef CONFIG_DEBUG_FS
-static int sdio_dld_debug_info_open(struct inode *inode, struct file *file);
-static ssize_t sdio_dld_debug_info_write(struct file *file,
- const char __user *buf, size_t count, loff_t *ppos);
-#endif
-
-static void sdio_dld_tear_down(struct work_struct *work);
-DECLARE_WORK(cleanup, sdio_dld_tear_down);
-
-/* STRUCTURES AND TYPES */
-enum sdio_dld_op_mode {
- SDIO_DLD_NO_MODE = 0,
- SDIO_DLD_NORMAL_MODE = 1,
- SDIO_DLD_BOOT_TEST_MODE = 2,
- SDIO_DLD_AMSS_TEST_MODE = 3,
- SDIO_DLD_NUM_OF_MODES,
-};
-
-struct sdioc_reg_sequential_chunk_ptrs {
- unsigned int dl_wr_ptr;
- unsigned int dl_rd_ptr;
- unsigned int up_wr_ptr;
- unsigned int up_rd_ptr;
-};
-
-struct sdioc_reg_sequential_chunk_cfg {
- unsigned int dl_buff_address;
- unsigned int up_buff_address;
- unsigned int dl_buff_size;
- unsigned int ul_buff_size;
-};
-
-struct sdioc_reg {
- unsigned int reg_val;
- unsigned int reg_offset;
-};
-
-struct sdioc_reg_chunk {
- struct sdioc_reg dl_buff_address;
- struct sdioc_reg up_buff_address;
- struct sdioc_reg dl_buff_size;
- struct sdioc_reg ul_buff_size;
- struct sdioc_reg dl_wr_ptr;
- struct sdioc_reg dl_rd_ptr;
- struct sdioc_reg up_wr_ptr;
- struct sdioc_reg up_rd_ptr;
- struct sdioc_reg good_to_exit_ptr;
-};
-
-struct sdio_data {
- char *data;
- int offset_read_p;
- int offset_write_p;
- int buffer_size;
- int num_of_bytes_in_use;
-};
-
-struct sdio_dld_data {
- struct sdioc_reg_chunk sdioc_reg;
- struct sdio_data incoming_data;
- struct sdio_data outgoing_data;
-};
-
-struct sdio_dld_wait_event {
- wait_queue_head_t wait_event;
- int wake_up_signal;
-};
-
-struct sdio_dld_task {
- struct task_struct *dld_task;
- const char *task_name;
- struct sdio_dld_wait_event exit_wait;
- atomic_t please_close;
-};
-
-#ifdef CONFIG_DEBUG_FS
-struct sdio_dloader_debug {
- struct dentry *sdio_dld_debug_root;
- struct dentry *sdio_al_dloader;
-};
-
-const struct file_operations sdio_dld_debug_info_ops = {
- .open = sdio_dld_debug_info_open,
- .write = sdio_dld_debug_info_write,
-};
-#endif
-
-struct sdio_downloader {
- int sdioc_boot_func;
- struct sdio_dld_wait_event write_callback_event;
- struct sdio_dld_task dld_main_thread;
- struct tty_driver *tty_drv;
- struct tty_struct *tty_str;
- struct sdio_dld_data sdio_dloader_data;
- struct mmc_card *card;
- int(*done_callback)(void);
- struct sdio_dld_wait_event main_loop_event;
- struct timer_list timer;
- unsigned int poll_ms;
- struct timer_list push_timer;
- unsigned int push_timer_ms;
- enum sdio_dld_op_mode op_mode;
- char op_mode_name[TEST_NAME_MAX_SIZE];
-};
-
-struct sdio_dld_global_info {
- int global_bytes_write_toio;
- int global_bytes_write_tty;
- int global_bytes_read_fromio;
- int global_bytes_push_tty;
- u64 start_time;
- u64 end_time;
- u64 delta_jiffies;
- unsigned int time_msec;
- unsigned int throughput;
- int cl_dl_wr_ptr;
- int cl_dl_rd_ptr;
- int cl_up_wr_ptr;
- int cl_up_rd_ptr;
- int host_read_ptr;
- int host_write_ptr;
- int cl_dl_buffer_size;
- int cl_up_buffer_size;
- int host_outgoing_buffer_size;
- int cl_dl_buffer_address;
- int cl_up_buffer_address;
-};
-
-static const struct tty_operations sdio_dloader_tty_ops = {
- .open = sdio_dld_open,
- .close = sdio_dld_close,
- .write = sdio_dld_write_callback,
- .write_room = sdio_dld_write_room,
-};
-
-/* GLOBAL VARIABLES */
-struct sdio_downloader *sdio_dld;
-struct sdio_dld_global_info sdio_dld_info;
-static char outgoing_data_buffer[SDIO_DLD_OUTGOING_BUFFER_SIZE];
-
-static DEFINE_SPINLOCK(lock1);
-static unsigned long lock_flags1;
-static DEFINE_SPINLOCK(lock2);
-static unsigned long lock_flags2;
-
-static atomic_t sdio_dld_in_use = ATOMIC_INIT(0);
-static atomic_t sdio_dld_setup_done = ATOMIC_INIT(0);
-
-/*
- * sdio_op_mode sets the operation mode of the sdio_dloader -
- * it may be in NORMAL_MODE, BOOT_TEST_MODE or AMSS_TEST_MODE
- */
-static int sdio_op_mode = (int)SDIO_DLD_NORMAL_MODE;
-module_param(sdio_op_mode, int, 0);
-
-#ifdef CONFIG_DEBUG_FS
-
-struct sdio_dloader_debug sdio_dld_debug;
-
-#define ARR_SIZE 30000
-#define SDIO_DLD_DEBUGFS_INIT_VALUE 87654321
-#define SDIO_DLD_DEBUGFS_CASE_1_CODE 11111111
-#define SDIO_DLD_DEBUGFS_CASE_2_CODE 22222222
-#define SDIO_DLD_DEBUGFS_CASE_3_CODE 33333333
-#define SDIO_DLD_DEBUGFS_CASE_4_CODE 44444444
-#define SDIO_DLD_DEBUGFS_CASE_5_CODE 55555555
-#define SDIO_DLD_DEBUGFS_CASE_6_CODE 66666666
-#define SDIO_DLD_DEBUGFS_CASE_7_CODE 77777777
-#define SDIO_DLD_DEBUGFS_CASE_8_CODE 88888888
-#define SDIO_DLD_DEBUGFS_CASE_9_CODE 99999999
-#define SDIO_DLD_DEBUGFS_CASE_10_CODE 10101010
-#define SDIO_DLD_DEBUGFS_CASE_11_CODE 11001100
-#define SDIO_DLD_DEBUGFS_CASE_12_CODE 12001200
-#define SDIO_DLD_DEBUGFS_LOOP_WAIT 7
-#define SDIO_DLD_DEBUGFS_LOOP_WAKEUP 8
-#define SDIO_DLD_DEBUGFS_CB_WAIT 3
-#define SDIO_DLD_DEBUGFS_CB_WAKEUP 4
-
-static int curr_index;
-struct ptrs {
- int h_w_ptr;
- int h_r_ptr;
- int c_u_w_ptr;
- int c_u_r_ptr;
- int code;
- int h_has_to_send;
- int c_has_to_receive;
- int min_of;
- int reserve2;
- int tty_count;
- int write_tty;
- int write_toio;
- int loop_wait_wake;
- int cb_wait_wake;
- int c_d_w_ptr;
- int c_d_r_ptr;
- int to_read;
- int push_to_tty;
- int global_tty_send;
- int global_sdio_send;
- int global_tty_received;
- int global_sdio_received;
- int reserve22;
- int reserve23;
- int reserve24;
- int reserve25;
- int reserve26;
- int reserve27;
- int reserve28;
- int reserve29;
- int reserve30;
- int reserve31;
-};
-
-struct global_data {
- int curr_i;
- int duration_ms;
- int global_bytes_sent;
- int throughput_Mbs;
- int host_outgoing_buffer_size_KB;
- int client_up_buffer_size_KB;
- int client_dl_buffer_size_KB;
- int client_dl_buffer_address;
- int client_up_buffer_address;
- int global_bytes_received;
- int global_bytes_pushed;
- int reserve11;
- int reserve12;
- int reserve13;
- int reserve14;
- int reserve15;
- int reserve16;
- int reserve17;
- int reserve18;
- int reserve19;
- int reserve20;
- int reserve21;
- int reserve22;
- int reserve23;
- int reserve24;
- int reserve25;
- int reserve26;
- int reserve27;
- int reserve28;
- int reserve29;
- int reserve30;
- int reserve31;
- struct ptrs ptr_array[ARR_SIZE];
-};
-
-static struct global_data gd;
-static struct debugfs_blob_wrapper blob;
-static struct dentry *root;
-static struct dentry *dld;
-
-struct debugfs_global {
- int global_8k_has;
- int global_9k_has;
- int global_min;
- int global_count;
- int global_write_tty;
- int global_write_toio;
- int global_bytes_cb_tty;
- int global_to_read;
- int global_push_to_tty;
- int global_tty_send;
- int global_sdio_send;
- int global_sdio_received;
- int global_tty_push;
-};
-
-static struct debugfs_global debugfs_glob;
-
-static void update_standard_fields(int index)
-{
-
- gd.ptr_array[index].global_tty_send =
- sdio_dld_info.global_bytes_write_tty;
- gd.ptr_array[index].global_sdio_send =
- sdio_dld_info.global_bytes_write_toio;
- gd.ptr_array[index].global_tty_received =
- sdio_dld_info.global_bytes_push_tty;
- gd.ptr_array[index].global_sdio_received =
- sdio_dld_info.global_bytes_read_fromio;
-}
-
-static void update_gd(int code)
-{
- struct sdioc_reg_chunk *reg_str =
- &sdio_dld->sdio_dloader_data.sdioc_reg;
- struct sdio_data *outgoing = &sdio_dld->sdio_dloader_data.outgoing_data;
- int index = curr_index%ARR_SIZE;
-
- gd.curr_i = curr_index;
- gd.duration_ms = 0;
- gd.global_bytes_sent = 0;
- gd.throughput_Mbs = 0;
- gd.host_outgoing_buffer_size_KB = 0;
- gd.client_up_buffer_size_KB = 0;
- gd.client_dl_buffer_size_KB = 0;
- gd.client_dl_buffer_address = 0;
- gd.client_up_buffer_address = 0;
- gd.global_bytes_received = 0;
- gd.global_bytes_pushed = 0;
- gd.reserve11 = 0;
- gd.reserve12 = 0;
- gd.reserve13 = 0;
- gd.reserve14 = 0;
- gd.reserve15 = 0;
- gd.reserve16 = 0;
- gd.reserve17 = 0;
- gd.reserve18 = 0;
- gd.reserve19 = 0;
- gd.reserve20 = 0;
- gd.reserve21 = 0;
- gd.reserve22 = 0;
- gd.reserve23 = 0;
- gd.reserve24 = 0;
- gd.reserve25 = 0;
- gd.reserve26 = 0;
- gd.reserve27 = 0;
- gd.reserve28 = 0;
- gd.reserve29 = 0;
- gd.reserve30 = 0;
- gd.reserve31 = 0;
-
- gd.ptr_array[index].h_w_ptr = SDIO_DLD_DEBUGFS_INIT_VALUE; /*0*/
- gd.ptr_array[index].h_r_ptr = SDIO_DLD_DEBUGFS_INIT_VALUE; /*1*/
- gd.ptr_array[index].c_u_w_ptr = SDIO_DLD_DEBUGFS_INIT_VALUE; /*2*/
- gd.ptr_array[index].c_u_r_ptr = SDIO_DLD_DEBUGFS_INIT_VALUE; /*3*/
- gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_INIT_VALUE; /*4*/
- gd.ptr_array[index].h_has_to_send = SDIO_DLD_DEBUGFS_INIT_VALUE;/*5*/
- gd.ptr_array[index].c_has_to_receive =
- SDIO_DLD_DEBUGFS_INIT_VALUE; /*6*/
- gd.ptr_array[index].min_of = SDIO_DLD_DEBUGFS_INIT_VALUE; /*7*/
- gd.ptr_array[index].reserve2 = SDIO_DLD_DEBUGFS_INIT_VALUE; /*8*/
- gd.ptr_array[index].tty_count = SDIO_DLD_DEBUGFS_INIT_VALUE; /*9*/
- gd.ptr_array[index].write_tty = SDIO_DLD_DEBUGFS_INIT_VALUE; /*A*/
- gd.ptr_array[index].write_toio = SDIO_DLD_DEBUGFS_INIT_VALUE; /*B*/
- gd.ptr_array[index].loop_wait_wake =
- SDIO_DLD_DEBUGFS_INIT_VALUE; /*C*/
- gd.ptr_array[index].cb_wait_wake = SDIO_DLD_DEBUGFS_INIT_VALUE; /*D*/
- gd.ptr_array[index].c_d_w_ptr = SDIO_DLD_DEBUGFS_INIT_VALUE; /*E*/
- gd.ptr_array[index].c_d_r_ptr = SDIO_DLD_DEBUGFS_INIT_VALUE; /*F*/
- gd.ptr_array[index].to_read =
- SDIO_DLD_DEBUGFS_INIT_VALUE; /*0x10*/
- gd.ptr_array[index].push_to_tty =
- SDIO_DLD_DEBUGFS_INIT_VALUE; /*0x11*/
- gd.ptr_array[index].global_tty_send =
- SDIO_DLD_DEBUGFS_INIT_VALUE; /*0x12*/
- gd.ptr_array[index].global_sdio_send =
- SDIO_DLD_DEBUGFS_INIT_VALUE; /*0x13*/
- gd.ptr_array[index].global_tty_received =
- SDIO_DLD_DEBUGFS_INIT_VALUE; /*0x14*/
- gd.ptr_array[index].global_sdio_received =
- SDIO_DLD_DEBUGFS_INIT_VALUE; /*0x15*/
- gd.ptr_array[index].reserve22 = SDIO_DLD_DEBUGFS_INIT_VALUE;
- gd.ptr_array[index].reserve23 = SDIO_DLD_DEBUGFS_INIT_VALUE;
- gd.ptr_array[index].reserve24 = SDIO_DLD_DEBUGFS_INIT_VALUE;
- gd.ptr_array[index].reserve25 = SDIO_DLD_DEBUGFS_INIT_VALUE;
- gd.ptr_array[index].reserve26 = SDIO_DLD_DEBUGFS_INIT_VALUE;
- gd.ptr_array[index].reserve27 = SDIO_DLD_DEBUGFS_INIT_VALUE;
- gd.ptr_array[index].reserve28 = SDIO_DLD_DEBUGFS_INIT_VALUE;
- gd.ptr_array[index].reserve29 = SDIO_DLD_DEBUGFS_INIT_VALUE;
- gd.ptr_array[index].reserve30 = SDIO_DLD_DEBUGFS_INIT_VALUE;
- gd.ptr_array[index].reserve31 = SDIO_DLD_DEBUGFS_INIT_VALUE;
-
- switch (code) {
- case SDIO_DLD_DEBUGFS_CASE_1_CODE:
- gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_1_CODE;
- gd.ptr_array[index].h_w_ptr = outgoing->offset_write_p;
- gd.ptr_array[index].h_r_ptr = outgoing->offset_read_p;
- gd.ptr_array[index].c_u_w_ptr = reg_str->up_wr_ptr.reg_val;
- gd.ptr_array[index].c_u_r_ptr = reg_str->up_rd_ptr.reg_val;
- gd.ptr_array[index].c_d_w_ptr = reg_str->dl_wr_ptr.reg_val;
- gd.ptr_array[index].c_d_r_ptr = reg_str->dl_rd_ptr.reg_val;
- break;
-
- case SDIO_DLD_DEBUGFS_CASE_2_CODE:
- gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_2_CODE;
- gd.ptr_array[index].c_u_r_ptr = reg_str->up_rd_ptr.reg_val;
- gd.ptr_array[index].c_u_w_ptr = reg_str->up_wr_ptr.reg_val;
- gd.ptr_array[index].h_has_to_send = debugfs_glob.global_8k_has;
- gd.ptr_array[index].c_has_to_receive =
- debugfs_glob.global_9k_has;
- gd.ptr_array[index].min_of = debugfs_glob.global_min;
- break;
-
- case SDIO_DLD_DEBUGFS_CASE_3_CODE:
- gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_3_CODE;
- gd.ptr_array[index].h_w_ptr = outgoing->offset_write_p;
- gd.ptr_array[index].h_r_ptr = outgoing->offset_read_p;
- gd.ptr_array[index].write_tty = debugfs_glob.global_write_tty;
- break;
-
- case SDIO_DLD_DEBUGFS_CASE_4_CODE:
- gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_4_CODE;
- gd.ptr_array[index].h_w_ptr = outgoing->offset_write_p;
- gd.ptr_array[index].h_r_ptr = outgoing->offset_read_p;
- gd.ptr_array[index].c_u_r_ptr = reg_str->up_rd_ptr.reg_val;
- gd.ptr_array[index].c_u_w_ptr = reg_str->up_wr_ptr.reg_val;
- gd.ptr_array[index].write_toio =
- debugfs_glob.global_write_toio;
- break;
-
- case SDIO_DLD_DEBUGFS_CASE_5_CODE:
- gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_5_CODE;
- gd.ptr_array[index].tty_count = debugfs_glob.global_count;
- break;
-
- case SDIO_DLD_DEBUGFS_CASE_6_CODE:
- gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_6_CODE;
- gd.ptr_array[index].loop_wait_wake = 7;
- break;
-
- case SDIO_DLD_DEBUGFS_CASE_7_CODE:
- gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_7_CODE;
- gd.ptr_array[index].loop_wait_wake = 8;
- break;
-
- case SDIO_DLD_DEBUGFS_CASE_8_CODE:
- gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_8_CODE;
- gd.ptr_array[index].cb_wait_wake = 3;
- break;
-
- case SDIO_DLD_DEBUGFS_CASE_9_CODE:
- gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_9_CODE;
- gd.ptr_array[index].cb_wait_wake = 4;
- break;
-
- case SDIO_DLD_DEBUGFS_CASE_10_CODE:
- gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_10_CODE;
- gd.ptr_array[index].cb_wait_wake =
- debugfs_glob.global_bytes_cb_tty;
- break;
-
- case SDIO_DLD_DEBUGFS_CASE_11_CODE:
- gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_11_CODE;
- gd.ptr_array[index].to_read = debugfs_glob.global_to_read;
- break;
-
- case SDIO_DLD_DEBUGFS_CASE_12_CODE:
- gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_12_CODE;
- gd.ptr_array[index].push_to_tty =
- debugfs_glob.global_push_to_tty;
- break;
-
- default:
- break;
- }
- update_standard_fields(index);
- curr_index++;
-}
-
-static int bootloader_debugfs_init(void)
-{
- /* /sys/kernel/debug/bootloader there will be dld_arr file */
- root = debugfs_create_dir("bootloader", NULL);
- if (!root) {
- pr_info(MODULE_NAME ": %s - creating root dir "
- "failed\n", __func__);
- return -ENODEV;
- }
-
- blob.data = &gd;
- blob.size = sizeof(struct global_data);
- dld = debugfs_create_blob("dld_arr", S_IRUGO, root, &blob);
- if (!dld) {
- debugfs_remove_recursive(root);
- pr_err(MODULE_NAME ": %s, failed to create debugfs entry\n",
- __func__);
- return -ENODEV;
- }
-
- return 0;
-}
-
-/*
-* for triggering the sdio_dld info use:
-* echo 1 > /sys/kernel/debug/sdio_al_dld/sdio_al_dloader_info
-*/
-static int sdio_dld_debug_init(void)
-{
- sdio_dld_debug.sdio_dld_debug_root =
- debugfs_create_dir("sdio_al_dld", NULL);
- if (!sdio_dld_debug.sdio_dld_debug_root) {
- pr_err(MODULE_NAME ": %s - Failed to create folder. "
- "sdio_dld_debug_root is NULL",
- __func__);
- return -ENOENT;
- }
-
- sdio_dld_debug.sdio_al_dloader = debugfs_create_file(
- "sdio_al_dloader_info",
- S_IRUGO | S_IWUGO,
- sdio_dld_debug.sdio_dld_debug_root,
- NULL,
- &sdio_dld_debug_info_ops);
-
- if (!sdio_dld_debug.sdio_al_dloader) {
- pr_err(MODULE_NAME ": %s - Failed to create a file. "
- "sdio_al_dloader is NULL",
- __func__);
- debugfs_remove(sdio_dld_debug.sdio_dld_debug_root);
- sdio_dld_debug.sdio_dld_debug_root = NULL;
- return -ENOENT;
- }
-
- return 0;
-}
-
-static int sdio_dld_debug_info_open(struct inode *inode, struct file *file)
-{
- file->private_data = inode->i_private;
- return 0;
-}
-
-static ssize_t sdio_dld_debug_info_write(struct file *file,
- const char __user *buf, size_t count, loff_t *ppos)
-{
- sdio_dld_print_info();
- return count;
-}
-#endif /* CONFIG_DEBUG_FS */
-
-static void sdio_dld_print_info(void)
-{
-
- sdio_dld_info.end_time = get_jiffies_64(); /* read the current time */
- sdio_dld_info.delta_jiffies =
- sdio_dld_info.end_time - sdio_dld_info.start_time;
- sdio_dld_info.time_msec = jiffies_to_msecs(sdio_dld_info.delta_jiffies);
-
- sdio_dld_info.throughput = sdio_dld_info.global_bytes_write_toio *
- BITS_IN_BYTE / sdio_dld_info.time_msec;
- sdio_dld_info.throughput /= MS_IN_SEC;
-
- pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - DURATION IN MSEC = %d\n",
- __func__,
- sdio_dld_info.time_msec);
-
- pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - BYTES WRITTEN ON SDIO BUS "
- "= %d...BYTES SENT BY TTY = %d",
- __func__,
- sdio_dld_info.global_bytes_write_toio,
- sdio_dld_info.global_bytes_write_tty);
-
- pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - BYTES RECEIVED ON SDIO BUS "
- "= %d...BYTES SENT TO TTY = %d",
- __func__,
- sdio_dld_info.global_bytes_read_fromio,
- sdio_dld_info.global_bytes_push_tty);
-
- pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - THROUGHPUT=%d Mbit/Sec",
- __func__, sdio_dld_info.throughput);
-
- pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - CLIENT DL_BUFFER_SIZE=%d"
- " KB..CLIENT UL_BUFFER=%d KB\n",
- __func__,
- sdio_dld_info.cl_dl_buffer_size/BYTES_IN_KB,
- sdio_dld_info.cl_up_buffer_size/BYTES_IN_KB);
-
- pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - HOST OUTGOING BUFFER_SIZE"
- "=%d KB",
- __func__,
- sdio_dld_info.host_outgoing_buffer_size/BYTES_IN_KB);
-
- pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - CLIENT DL BUFFER "
- "ADDRESS = 0x%x", __func__,
- sdio_dld_info.cl_dl_buffer_address);
-
- pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - CLIENT UP BUFFER "
- "ADDRESS = 0x%x",
- __func__,
- sdio_dld_info.cl_up_buffer_address);
-
- pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - CLIENT - UPLINK BUFFER - "
- "READ POINTER = %d", __func__,
- sdio_dld_info.cl_up_rd_ptr);
-
- pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - CLIENT - UPLINK BUFFER - "
- "WRITE POINTER = %d", __func__,
- sdio_dld_info.cl_up_wr_ptr);
-
- pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - CLIENT - DOWNLINK BUFFER - "
- "READ POINTER = %d", __func__,
- sdio_dld_info.cl_dl_rd_ptr);
-
- pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - CLIENT - DOWNLINK BUFFER - "
- "WRITE POINTER = %d", __func__,
- sdio_dld_info.cl_dl_wr_ptr);
-
- pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - HOST - OUTGOING BUFFER - "
- "READ POINTER = %d", __func__,
- sdio_dld_info.host_read_ptr);
-
- pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - HOST - OUTGOING BUFFER - "
- "WRITE POINTER = %d", __func__,
- sdio_dld_info.host_write_ptr);
-
- pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - END DEBUG INFO", __func__);
-}
-
-/**
- * sdio_dld_set_op_mode
- * sets the op_mode and the name of the op_mode. Also, in case
- * it's invalid mode sets op_mode to SDIO_DLD_NORMAL_MODE
- *
- * @op_mode: the operation mode to be set
- * @return NONE
- */
-static void sdio_dld_set_op_mode(enum sdio_dld_op_mode op_mode)
-{
- sdio_dld->op_mode = op_mode;
-
- switch (op_mode) {
- case SDIO_DLD_NORMAL_MODE:
- memcpy(sdio_dld->op_mode_name,
- SDIO_DLD_NORMAL_MODE_NAME, TEST_NAME_MAX_SIZE);
- break;
- case SDIO_DLD_BOOT_TEST_MODE:
- memcpy(sdio_dld->op_mode_name,
- SDIO_DLD_BOOT_TEST_MODE_NAME, TEST_NAME_MAX_SIZE);
- break;
- case SDIO_DLD_AMSS_TEST_MODE:
- memcpy(sdio_dld->op_mode_name,
- SDIO_DLD_AMSS_TEST_MODE_NAME, TEST_NAME_MAX_SIZE);
- break;
- default:
- sdio_dld->op_mode = SDIO_DLD_NORMAL_MODE;
- pr_err(MODULE_NAME ": %s - Invalid Op_Mode = %d. Settings "
- "Op_Mode to default - NORMAL_MODE\n",
- __func__, op_mode);
- memcpy(sdio_dld->op_mode_name,
- SDIO_DLD_NORMAL_MODE_NAME, TEST_NAME_MAX_SIZE);
- break;
- }
-
- if (sdio_dld->op_mode_name != NULL) {
- pr_info(MODULE_NAME ": %s - FLASHLESS BOOT - Op_Mode is set to "
- "%s\n", __func__, sdio_dld->op_mode_name);
- } else {
- pr_info(MODULE_NAME ": %s - FLASHLESS BOOT - op_mode_name is "
- "NULL\n", __func__);
- }
-}
-
-/**
- * sdio_dld_allocate_local_buffers
- * allocates local outgoing and incoming buffers and also sets
- * threshold for outgoing data.
- *
- * @return 0 on success or negative value on error.
- */
-static int sdio_dld_allocate_local_buffers(void)
-{
- struct sdioc_reg_chunk *reg_str = &sdio_dld->sdio_dloader_data.
- sdioc_reg;
- struct sdio_data *outgoing = &sdio_dld->sdio_dloader_data.outgoing_data;
- struct sdio_data *incoming = &sdio_dld->sdio_dloader_data.incoming_data;
-
- incoming->data =
- kzalloc(reg_str->dl_buff_size.reg_val, GFP_KERNEL);
-
- if (!incoming->data) {
- pr_err(MODULE_NAME ": %s - param ""incoming->data"" is NULL. "
- "Couldn't allocate incoming_data local buffer\n",
- __func__);
- return -ENOMEM;
- }
-
- incoming->buffer_size = reg_str->dl_buff_size.reg_val;
-
- outgoing->data = outgoing_data_buffer;
-
- outgoing->buffer_size = SDIO_DLD_OUTGOING_BUFFER_SIZE;
-
- if (outgoing->buffer_size !=
- reg_str->ul_buff_size.reg_val*MULTIPLE_RATIO) {
- pr_err(MODULE_NAME ": %s - HOST outgoing buffer size (%d bytes)"
- "must be a multiple of ClIENT uplink buffer size (%d "
- "bytes). HOST_SIZE == n*CLIENT_SIZE.(n=1,2,3...)\n",
- __func__,
- SDIO_DLD_OUTGOING_BUFFER_SIZE,
- reg_str->ul_buff_size.reg_val);
- kfree(incoming->data);
- return -EINVAL;
- }
-
- /* keep sdio_dld_info up to date */
- sdio_dld_info.host_outgoing_buffer_size = outgoing->buffer_size;
-
- return 0;
-}
-
-/**
- * sdio_dld_dealloc_local_buffers frees incoming and outgoing
- * buffers.
- *
- * @return None.
- */
-static void sdio_dld_dealloc_local_buffers(void)
-{
- kfree((void *)sdio_dld->sdio_dloader_data.incoming_data.data);
-}
-
-/**
- * mailbox_to_seq_chunk_read_cfg
- * reads 4 configuration registers of mailbox from str_func, as
- * a sequentail chunk in memory, and updates global struct
- * accordingly.
- *
- * @str_func: a pointer to func struct.
- * @return 0 on success or negative value on error.
- */
-static int mailbox_to_seq_chunk_read_cfg(struct sdio_func *str_func)
-{
- struct sdioc_reg_sequential_chunk_cfg seq_chunk;
- struct sdioc_reg_chunk *reg = &sdio_dld->sdio_dloader_data.sdioc_reg;
- int status = 0;
-
- if (!str_func) {
- pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- sdio_claim_host(str_func);
-
- /* reading SDIOC_MAILBOX_SIZE bytes from SDIOC_MAILBOX_ADDRESS */
- status = sdio_memcpy_fromio(str_func,
- (void *)&seq_chunk,
- SDIOC_MAILBOX_ADDRESS,
- SDIOC_CFG_REGS_SIZE);
- if (status) {
- pr_err(MODULE_NAME ": %s - sdio_memcpy_fromio()"
- " READING CFG MAILBOX failed. status=%d.\n",
- __func__, status);
- }
-
- sdio_release_host(str_func);
-
- reg->dl_buff_address.reg_val = seq_chunk.dl_buff_address;
- reg->up_buff_address.reg_val = seq_chunk.up_buff_address;
- reg->dl_buff_size.reg_val = seq_chunk.dl_buff_size;
- reg->ul_buff_size.reg_val = seq_chunk.ul_buff_size;
-
- /* keep sdio_dld_info up to date */
- sdio_dld_info.cl_dl_buffer_size = seq_chunk.dl_buff_size;
- sdio_dld_info.cl_up_buffer_size = seq_chunk.ul_buff_size;
- sdio_dld_info.cl_dl_buffer_address = seq_chunk.dl_buff_address;
- sdio_dld_info.cl_up_buffer_address = seq_chunk.up_buff_address;
-
- return status;
-}
-
-/**
- * mailbox_to_seq_chunk_read_ptrs
- * reads 4 pointers registers of mailbox from str_func, as a
- * sequentail chunk in memory, and updates global struct
- * accordingly.
- *
- * @str_func: a pointer to func struct.
- * @return 0 on success or negative value on error.
- */
-static int mailbox_to_seq_chunk_read_ptrs(struct sdio_func *str_func)
-{
- struct sdioc_reg_sequential_chunk_ptrs seq_chunk;
- struct sdioc_reg_chunk *reg = &sdio_dld->sdio_dloader_data.sdioc_reg;
- int status = 0;
-
- struct sdio_data *outgoing = &sdio_dld->sdio_dloader_data.outgoing_data;
- static int counter = 1;
- static int offset_write_p;
- static int offset_read_p;
- static int up_wr_ptr;
- static int up_rd_ptr;
- static int dl_wr_ptr;
- static int dl_rd_ptr;
-
- if (!str_func) {
- pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- sdio_claim_host(str_func);
-
- /* reading SDIOC_MAILBOX_SIZE bytes from SDIOC_MAILBOX_ADDRESS */
- status = sdio_memcpy_fromio(str_func,
- (void *)&seq_chunk,
- SDIOC_PTRS_OFFSET,
- SDIOC_PTR_REGS_SIZE);
- if (status) {
- pr_err(MODULE_NAME ": %s - sdio_memcpy_fromio()"
- " READING PTRS MAILBOX failed. status=%d.\n",
- __func__, status);
- }
-
- sdio_release_host(str_func);
-
- reg->dl_rd_ptr.reg_val = seq_chunk.dl_rd_ptr;
- reg->dl_wr_ptr.reg_val = seq_chunk.dl_wr_ptr;
- reg->up_rd_ptr.reg_val = seq_chunk.up_rd_ptr;
- reg->up_wr_ptr.reg_val = seq_chunk.up_wr_ptr;
-
- /* keeping sdio_dld_info up to date */
- sdio_dld_info.cl_dl_rd_ptr = seq_chunk.dl_rd_ptr;
- sdio_dld_info.cl_dl_wr_ptr = seq_chunk.dl_wr_ptr;
- sdio_dld_info.cl_up_rd_ptr = seq_chunk.up_rd_ptr;
- sdio_dld_info.cl_up_wr_ptr = seq_chunk.up_wr_ptr;
-
-
- /* DEBUG - if there was a change in value */
- if ((offset_write_p != outgoing->offset_write_p) ||
- (offset_read_p != outgoing->offset_read_p) ||
- (up_wr_ptr != reg->up_wr_ptr.reg_val) ||
- (up_rd_ptr != reg->up_rd_ptr.reg_val) ||
- (dl_wr_ptr != reg->dl_wr_ptr.reg_val) ||
- (dl_rd_ptr != reg->dl_rd_ptr.reg_val) ||
- (counter % PRINTING_GAP == 0)) {
- counter = 1;
- pr_debug(MODULE_NAME ": %s MailBox pointers: BLOCK_SIZE=%d, "
- "hw=%d, hr=%d, cuw=%d, cur=%d, cdw=%d, cdr=%d\n",
- __func__,
- SDIO_DL_BLOCK_SIZE,
- outgoing->offset_write_p,
- outgoing->offset_read_p,
- reg->up_wr_ptr.reg_val,
- reg->up_rd_ptr.reg_val,
- reg->dl_wr_ptr.reg_val,
- reg->dl_rd_ptr.reg_val);
-
-#ifdef CONFIG_DEBUG_FS
- update_gd(SDIO_DLD_DEBUGFS_CASE_1_CODE);
-#endif
- /* update static variables */
- offset_write_p = outgoing->offset_write_p;
- offset_read_p = outgoing->offset_read_p;
- up_wr_ptr = reg->up_wr_ptr.reg_val;
- up_rd_ptr = reg->up_rd_ptr.reg_val;
- dl_wr_ptr = reg->dl_wr_ptr.reg_val;
- dl_rd_ptr = reg->dl_rd_ptr.reg_val;
- } else {
- counter++;
- }
- return status;
-}
-
-/**
- * sdio_dld_init_func
- * enables the sdio func, and sets the func block size.
- *
- * @str_func: a pointer to func struct.
- * @return 0 on success or negative value on error.
- */
-static int sdio_dld_init_func(struct sdio_func *str_func)
-{
- int status1 = 0;
- int status2 = 0;
-
- if (!str_func) {
- pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- sdio_claim_host(str_func);
-
- status1 = sdio_enable_func(str_func);
- if (status1) {
- sdio_release_host(str_func);
- pr_err(MODULE_NAME ": %s - sdio_enable_func() failed. "
- "status=%d\n", __func__, status1);
- return status1;
- }
-
- status2 = sdio_set_block_size(str_func, SDIO_DL_BLOCK_SIZE);
- if (status2) {
- pr_err(MODULE_NAME ": %s - sdio_set_block_size() failed. "
- "status=%d\n", __func__, status2);
- status1 = sdio_disable_func(str_func);
- if (status1) {
- pr_err(MODULE_NAME ": %s - sdio_disable_func() "
- "failed. status=%d\n", __func__, status1);
- }
- sdio_release_host(str_func);
- return status2;
- }
-
- sdio_release_host(str_func);
- str_func->max_blksize = SDIO_DL_BLOCK_SIZE;
- return 0;
-}
-
-/**
- * sdio_dld_allocate_buffers
- * initializes the sdio func, and then reads the mailbox, in
- * order to allocate incoming and outgoing buffers according to
- * the size that was read from the mailbox.
- *
- * @str_func: a pointer to func struct.
- * @return 0 on success or negative value on error.
- */
-static int sdio_dld_allocate_buffers(struct sdio_func *str_func)
-{
- int status = 0;
-
- if (!str_func) {
- pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- status = mailbox_to_seq_chunk_read_cfg(str_func);
- if (status) {
- pr_err(MODULE_NAME ": %s - Failure in Function "
- "mailbox_to_seq_chunk_read_cfg(). status=%d\n",
- __func__, status);
- return status;
- }
-
- status = sdio_dld_allocate_local_buffers();
- if (status) {
- pr_err(MODULE_NAME ": %s - Failure in Function "
- "sdio_dld_allocate_local_buffers(). status=%d\n",
- __func__, status);
- return status;
- }
- return 0;
-}
-
-/**
- * sdio_dld_create_thread
- * creates thread and wakes it up.
- *
- * @return 0 on success or negative value on error.
- */
-static int sdio_dld_create_thread(void)
-{
- sdio_dld->dld_main_thread.task_name = SDIO_DL_MAIN_THREAD_NAME;
-
- sdio_dld->dld_main_thread.dld_task =
- kthread_create(sdio_dld_main_task,
- (void *)(sdio_dld->card),
- sdio_dld->dld_main_thread.task_name);
-
- if (IS_ERR(sdio_dld->dld_main_thread.dld_task)) {
- pr_err(MODULE_NAME ": %s - kthread_create() failed\n",
- __func__);
- return -ENOMEM;
- }
- wake_up_process(sdio_dld->dld_main_thread.dld_task);
- return 0;
-}
-
-/**
- * start_timer
- * sets the timer and starts.
- *
- * @timer: the timer to configure and add
- * @ms: the ms until it expires
- * @return None.
- */
-static void start_timer(struct timer_list *timer, unsigned int ms)
-{
- if ((ms == 0) || (timer == NULL)) {
- pr_err(MODULE_NAME ": %s - invalid parameter", __func__);
- } else {
- timer->expires = jiffies +
- msecs_to_jiffies(ms);
- add_timer(timer);
- }
-}
-
-/**
- * sdio_dld_timer_handler
- * this is the timer handler. whenever it is invoked, it wakes
- * up the main loop task, and the write callback, and starts
- * the timer again.
- *
- * @data: a pointer to the tty device driver structure.
- * @return None.
- */
-
-static void sdio_dld_timer_handler(unsigned long data)
-{
- pr_debug(MODULE_NAME " Timer Expired\n");
- spin_lock_irqsave(&lock2, lock_flags2);
- if (sdio_dld->main_loop_event.wake_up_signal == 0) {
- sdio_dld->main_loop_event.wake_up_signal = 1;
- wake_up(&sdio_dld->main_loop_event.wait_event);
- }
- spin_unlock_irqrestore(&lock2, lock_flags2);
-
- sdio_dld->write_callback_event.wake_up_signal = 1;
- wake_up(&sdio_dld->write_callback_event.wait_event);
-
- start_timer(&sdio_dld->timer, sdio_dld->poll_ms);
-}
-
-/**
- * sdio_dld_push_timer_handler
- * this is a timer handler of the push_timer.
- *
- * @data: a pointer to the tty device driver structure.
- * @return None.
- */
-static void sdio_dld_push_timer_handler(unsigned long data)
-{
- pr_err(MODULE_NAME " %s - Push Timer Expired... Trying to "
- "push data to TTY Core for over then %d ms.\n",
- __func__, sdio_dld->push_timer_ms);
-}
-
-/**
- * sdio_dld_open
- * this is the open callback of the tty driver.
- * it initializes the sdio func, allocates the buffers, and
- * creates the main thread.
- *
- * @tty: a pointer to the tty struct.
- * @file: file descriptor.
- * @return 0 on success or negative value on error.
- */
-static int sdio_dld_open(struct tty_struct *tty, struct file *file)
-{
- int status = 0;
- int func_in_array =
- REAL_FUNC_TO_FUNC_IN_ARRAY(sdio_dld->sdioc_boot_func);
- struct sdio_func *str_func = sdio_dld->card->sdio_func[func_in_array];
-
- if (atomic_read(&sdio_dld_in_use) == 1)
- return -EBUSY;
-
- atomic_set(&sdio_dld_in_use, 1);
- sdio_dld->tty_str = tty;
- sdio_dld->tty_str->low_latency = 1;
- sdio_dld->tty_str->icanon = 0;
- set_bit(TTY_NO_WRITE_SPLIT, &sdio_dld->tty_str->flags);
-
- pr_info(MODULE_NAME ": %s, TTY DEVICE FOR FLASHLESS BOOT OPENED\n",
- __func__);
- sdio_dld_info.start_time = get_jiffies_64(); /* read the current time */
-
- if (!tty) {
- pr_err(MODULE_NAME ": %s - param ""tty"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- if (!str_func) {
- pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- atomic_set(&sdio_dld->dld_main_thread.please_close, 0);
- sdio_dld->dld_main_thread.exit_wait.wake_up_signal = 0;
-
- status = sdio_dld_allocate_buffers(str_func);
- if (status) {
- pr_err(MODULE_NAME ": %s, failed in "
- "sdio_dld_allocate_buffers(). status=%d\n",
- __func__, status);
- return status;
- }
-
- /* init waiting event of the write callback */
- init_waitqueue_head(&sdio_dld->write_callback_event.wait_event);
-
- /* init waiting event of the main loop */
- init_waitqueue_head(&sdio_dld->main_loop_event.wait_event);
-
- /* configure and init the timer */
- sdio_dld->poll_ms = TIMER_DURATION;
- init_timer(&sdio_dld->timer);
- sdio_dld->timer.data = (unsigned long) sdio_dld;
- sdio_dld->timer.function = sdio_dld_timer_handler;
- sdio_dld->timer.expires = jiffies +
- msecs_to_jiffies(sdio_dld->poll_ms);
- add_timer(&sdio_dld->timer);
-
- sdio_dld->push_timer_ms = PUSH_TIMER_DURATION;
- init_timer(&sdio_dld->push_timer);
- sdio_dld->push_timer.data = (unsigned long) sdio_dld;
- sdio_dld->push_timer.function = sdio_dld_push_timer_handler;
-
- status = sdio_dld_create_thread();
- if (status) {
- del_timer_sync(&sdio_dld->timer);
- del_timer_sync(&sdio_dld->push_timer);
- sdio_dld_dealloc_local_buffers();
- pr_err(MODULE_NAME ": %s, failed in sdio_dld_create_thread()."
- "status=%d\n", __func__, status);
- return status;
- }
- return 0;
-}
-
-/**
- * sdio_dld_close
- * this is the close callback of the tty driver. it requests
- * the main thread to exit, and waits for notification of it.
- * it also de-allocates the buffers, and unregisters the tty
- * driver and device.
- *
- * @tty: a pointer to the tty struct.
- * @file: file descriptor.
- * @return None.
- */
-static void sdio_dld_close(struct tty_struct *tty, struct file *file)
-{
- struct sdioc_reg_chunk *reg = &sdio_dld->sdio_dloader_data.sdioc_reg;
-
- /* informing the SDIOC that it can exit boot phase */
- sdio_dld->sdio_dloader_data.sdioc_reg.good_to_exit_ptr.reg_val =
- SDIOC_EXIT_CODE;
-
- atomic_set(&sdio_dld->dld_main_thread.please_close, 1);
-
- pr_debug(MODULE_NAME ": %s - CLOSING - WAITING...", __func__);
-
- wait_event(sdio_dld->dld_main_thread.exit_wait.wait_event,
- sdio_dld->dld_main_thread.exit_wait.wake_up_signal);
- pr_debug(MODULE_NAME ": %s - CLOSING - WOKE UP...", __func__);
-
-#ifdef CONFIG_DEBUG_FS
- gd.curr_i = curr_index;
- gd.duration_ms = sdio_dld_info.time_msec;
- gd.global_bytes_sent = sdio_dld_info.global_bytes_write_toio;
- gd.global_bytes_received = 0;
- gd.throughput_Mbs = sdio_dld_info.throughput;
- gd.host_outgoing_buffer_size_KB = sdio_dld->sdio_dloader_data.
- outgoing_data.buffer_size/BYTES_IN_KB;
- gd.client_up_buffer_size_KB = reg->ul_buff_size.reg_val/BYTES_IN_KB;
- gd.client_dl_buffer_size_KB = reg->dl_buff_size.reg_val/BYTES_IN_KB;
- gd.client_dl_buffer_address = reg->dl_buff_address.reg_val;
- gd.client_up_buffer_address = reg->up_buff_address.reg_val;
- gd.global_bytes_received = sdio_dld_info.global_bytes_read_fromio;
- gd.global_bytes_pushed = sdio_dld_info.global_bytes_push_tty;
-#endif
-
- /* saving register values before deallocating sdio_dld
- in order to use it in sdio_dld_print_info() through shell command */
- sdio_dld_info.cl_dl_rd_ptr = reg->dl_rd_ptr.reg_val;
- sdio_dld_info.cl_dl_wr_ptr = reg->dl_wr_ptr.reg_val;
- sdio_dld_info.cl_up_rd_ptr = reg->up_rd_ptr.reg_val;
- sdio_dld_info.cl_up_wr_ptr = reg->up_wr_ptr.reg_val;
-
- sdio_dld_info.host_read_ptr =
- sdio_dld->sdio_dloader_data.outgoing_data.offset_read_p;
-
- sdio_dld_info.host_write_ptr =
- sdio_dld->sdio_dloader_data.outgoing_data.offset_write_p;
-
- sdio_dld_info.cl_dl_buffer_size =
- sdio_dld->sdio_dloader_data.sdioc_reg.dl_buff_size.reg_val;
-
- sdio_dld_info.cl_up_buffer_size =
- sdio_dld->sdio_dloader_data.sdioc_reg.ul_buff_size.reg_val;
-
- sdio_dld_info.host_outgoing_buffer_size =
- sdio_dld->sdio_dloader_data.outgoing_data.buffer_size;
-
- sdio_dld_info.cl_dl_buffer_address =
- sdio_dld->sdio_dloader_data.sdioc_reg.dl_buff_address.reg_val;
-
- sdio_dld_info.cl_up_buffer_address =
- sdio_dld->sdio_dloader_data.sdioc_reg.up_buff_address.reg_val;
-
- sdio_dld_print_info();
-
- if (sdio_dld->done_callback)
- sdio_dld->done_callback();
-
- schedule_work(&cleanup);
- pr_info(MODULE_NAME ": %s - Bootloader done, returning...", __func__);
-}
-
-/**
- * writing_size_to_buf
- * writes from src buffer into dest buffer. if dest buffer
- * reaches its end, rollover happens.
- *
- * @dest: destination buffer.
- * @src: source buffer.
- * @dest_wr_ptr: writing pointer in destination buffer.
- * @dest_size: destination buffer size.
- * @dest_rd_ptr: reading pointer in destination buffer.
- * @size_to_write: size of bytes to write.
- * @return -how many bytes actually written to destination
- * buffer.
- *
- * ONLY destination buffer is treated as cyclic buffer.
- */
-static int writing_size_to_buf(char *dest,
- const unsigned char *src,
- int *dest_wr_ptr,
- int dest_size,
- int dest_rd_ptr,
- int size_to_write)
-{
- int actually_written = 0;
- int size_to_add = *dest_wr_ptr;
-
- if (!dest) {
- pr_err(MODULE_NAME ": %s - param ""dest"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- if (!src) {
- pr_err(MODULE_NAME ": %s - param ""src"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- if (!dest_wr_ptr) {
- pr_err(MODULE_NAME ": %s - param ""dest_wr_ptr"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- for (actually_written = 0 ;
- actually_written < size_to_write ; ++actually_written) {
- /* checking if buffer is full */
- if (((size_to_add + 1) % dest_size) == dest_rd_ptr) {
- *dest_wr_ptr = size_to_add;
- return actually_written;
- }
-
- dest[size_to_add] = src[actually_written];
- size_to_add = (size_to_add+1)%dest_size;
- }
-
- *dest_wr_ptr = size_to_add;
-
- return actually_written;
-}
-
-/**
- * sdioc_bytes_till_end_of_buffer - this routine calculates how many bytes are
- * empty/in use. if calculation requires rap around - it will ignore the rap
- * around and will do the calculation untill the end of the buffer
- *
- * @write_ptr: writing pointer.
- * @read_ptr: reading pointer.
- * @total_size: buffer size.
- * @free_bytes: return value-how many free bytes.
- * @bytes_in_use: return value-how many bytes in use.
- * @return 0 on success or negative value on error.
- *
- * buffer is treated as a cyclic buffer.
- */
-static int sdioc_bytes_till_end_of_buffer(int write_ptr,
- int read_ptr,
- int total_size,
- int *free_bytes,
- int *bytes_in_use)
-{
- if (!free_bytes) {
- pr_err(MODULE_NAME ": %s - param ""free_bytes"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- if (!bytes_in_use) {
- pr_err(MODULE_NAME ": %s - param ""bytes_in_use"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- if (write_ptr >= read_ptr) {
- if (read_ptr == 0)
- *free_bytes = total_size - write_ptr - 1;
- else
- *free_bytes = total_size - write_ptr;
- *bytes_in_use = write_ptr - read_ptr;
- } else {
- *bytes_in_use = total_size - read_ptr;
- *free_bytes = read_ptr - write_ptr - 1;
- }
-
- return 0;
-}
-
-/**
- * sdioc_bytes_free_in_buffer
- * this routine calculates how many bytes are free in a buffer
- * and how many are in use, according to its reading and
- * writing pointer offsets.
- *
- * @write_ptr: writing pointer.
- * @read_ptr: reading pointer.
- * @total_size: buffer size.
- * @free_bytes: return value-how many free bytes in buffer.
- * @bytes_in_use: return value-how many bytes in use in buffer.
- * @return 0 on success or negative value on error.
- *
- * buffer is treated as a cyclic buffer.
- */
-static int sdioc_bytes_free_in_buffer(int write_ptr,
- int read_ptr,
- int total_size,
- int *free_bytes,
- int *bytes_in_use)
-{
- if (!free_bytes) {
- pr_err(MODULE_NAME ": %s - param ""free_bytes"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- if (!bytes_in_use) {
- pr_err(MODULE_NAME ": %s - param ""bytes_in_use"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- /* if pointers equel - buffers are empty. nothing to read/write */
-
- if (write_ptr >= read_ptr)
- *bytes_in_use = write_ptr - read_ptr;
- else
- *bytes_in_use = total_size - (read_ptr - write_ptr);
-
- *free_bytes = total_size - *bytes_in_use - 1;
-
- return 0;
-}
-
-/*
-* sdio_dld_write_room
-*
-* This is the write_room function of the tty driver.
-*
-* @tty: pointer to tty struct.
-* @return free bytes for write.
-*
-*/
-static int sdio_dld_write_room(struct tty_struct *tty)
-{
- return sdio_dld->sdio_dloader_data.outgoing_data.buffer_size;
-}
-
-/**
- * sdio_dld_write_callback
- * this is the write callback of the tty driver.
- *
- * @tty: pointer to tty struct.
- * @buf: buffer to write from.
- * @count: number of bytes to write.
- * @return bytes written or negative value on error.
- *
- * if destination buffer has not enough room for the incoming
- * data, returns an error.
- */
-static int sdio_dld_write_callback(struct tty_struct *tty,
- const unsigned char *buf, int count)
-{
- struct sdio_data *outgoing = &sdio_dld->sdio_dloader_data.outgoing_data;
- int dst_free_bytes = 0;
- int dummy = 0;
- int status = 0;
- int bytes_written = 0;
- int total_written = 0;
- static int write_retry;
- int pending_to_write = count;
-
-#ifdef CONFIG_DEBUG_FS
- debugfs_glob.global_count = count;
- update_gd(SDIO_DLD_DEBUGFS_CASE_5_CODE);
-#endif
-
- pr_debug(MODULE_NAME ": %s - WRITING CALLBACK CALLED WITH %d bytes\n",
- __func__, count);
-
- if (!outgoing->data) {
- pr_err(MODULE_NAME ": %s - param ""outgoing->data"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- pr_debug(MODULE_NAME ": %s - WRITE CALLBACK size to write to outgoing"
- " buffer %d\n", __func__, count);
-
- /* as long as there is something to write to outgoing buffer */
- do {
- int bytes_to_write = 0;
- status = sdioc_bytes_free_in_buffer(
- outgoing->offset_write_p,
- outgoing->offset_read_p,
- outgoing->buffer_size,
- &dst_free_bytes,
- &dummy);
-
- if (status) {
- pr_err(MODULE_NAME ": %s - Failure in Function "
- "sdioc_bytes_free_in_buffer(). status=%d\n",
- __func__, status);
- return status;
- }
-
- /*
- * if there is free room in outgoing buffer
- * lock mutex and request trigger notification from the main
- * task. unlock mutex, and wait for sinal
- */
- if (dst_free_bytes > 0) {
- write_retry = 0;
- /*
- * if there is more data to write to outgoing buffer
- * than it can receive, wait for signal from main task
- */
- if (pending_to_write > dst_free_bytes) {
-
- /* sampling updated dst_free_bytes */
- status = sdioc_bytes_free_in_buffer(
- outgoing->offset_write_p,
- outgoing->offset_read_p,
- outgoing->buffer_size,
- &dst_free_bytes,
- &dummy);
-
- if (status) {
- pr_err(MODULE_NAME ": %s - Failure in "
- "Function "
- "sdioc_bytes_free_in_buffer(). "
- "status=%d\n", __func__, status);
- return status;
- }
- }
-
- bytes_to_write = min(pending_to_write, dst_free_bytes);
- bytes_written =
- writing_size_to_buf(outgoing->data,
- buf+total_written,
- &outgoing->offset_write_p,
- outgoing->buffer_size,
- outgoing->offset_read_p,
- bytes_to_write);
-
- /* keeping sdio_dld_info up to date */
- sdio_dld_info.host_write_ptr =
- sdio_dld->sdio_dloader_data.
- outgoing_data.offset_write_p;
-
-#ifdef CONFIG_DEBUG_FS
- debugfs_glob.global_write_tty = bytes_written;
- update_gd(SDIO_DLD_DEBUGFS_CASE_3_CODE);
-#endif
- sdio_dld_info.global_bytes_write_tty += bytes_written;
-
- spin_lock_irqsave(&lock2, lock_flags2);
- if (sdio_dld->main_loop_event.wake_up_signal == 0) {
- sdio_dld->main_loop_event.wake_up_signal = 1;
- wake_up(&sdio_dld->main_loop_event.wait_event);
- }
- spin_unlock_irqrestore(&lock2, lock_flags2);
-
- /*
- * although outgoing buffer has enough room, writing
- * failed
- */
- if (bytes_written != bytes_to_write) {
- pr_err(MODULE_NAME ": %s - couldn't write "
- "%d bytes to " "outgoing buffer."
- "bytes_written=%d\n",
- __func__, bytes_to_write,
- bytes_written);
- return -EIO;
- }
-
- total_written += bytes_written;
- pending_to_write -= bytes_written;
- outgoing->num_of_bytes_in_use += bytes_written;
-
- pr_debug(MODULE_NAME ": %s - WRITE CHUNK to outgoing "
- "buffer. pending_to_write=%d, "
- "outgoing_free_bytes=%d, "
- "bytes_written=%d\n",
- __func__,
- pending_to_write,
- dst_free_bytes,
- bytes_written);
-
- } else {
- write_retry++;
-
- pr_debug(MODULE_NAME ": %s - WRITE CALLBACK - NO ROOM."
- " pending_to_write=%d, write_retry=%d\n",
- __func__,
- pending_to_write,
- write_retry);
-
- spin_lock_irqsave(&lock1, lock_flags1);
- sdio_dld->write_callback_event.wake_up_signal = 0;
- spin_unlock_irqrestore(&lock1, lock_flags1);
-
- pr_debug(MODULE_NAME ": %s - WRITE CALLBACK - "
- "WAITING...", __func__);
-#ifdef CONFIG_DEBUG_FS
- update_gd(SDIO_DLD_DEBUGFS_CASE_8_CODE);
-#endif
- wait_event(sdio_dld->write_callback_event.wait_event,
- sdio_dld->write_callback_event.
- wake_up_signal);
-#ifdef CONFIG_DEBUG_FS
- update_gd(SDIO_DLD_DEBUGFS_CASE_9_CODE);
-#endif
- pr_debug(MODULE_NAME ": %s - WRITE CALLBACK - "
- "WOKE UP...", __func__);
- }
- } while (pending_to_write > 0 && write_retry < WRITE_RETRIES);
-
- if (pending_to_write > 0) {
-
- pr_err(MODULE_NAME ": %s - WRITE CALLBACK - pending data is "
- "%d out of %d > 0. total written in this "
- "callback = %d\n",
- __func__, pending_to_write, count, total_written);
- }
-
- if (write_retry == WRITE_RETRIES) {
- pr_err(MODULE_NAME ": %s, write_retry=%d= max\n",
- __func__, write_retry);
- }
-
-#ifdef CONFIG_DEBUG_FS
- debugfs_glob.global_bytes_cb_tty = total_written;
- update_gd(SDIO_DLD_DEBUGFS_CASE_10_CODE);
-#endif
-
- return total_written;
-}
-
-/**
- * sdio_memcpy_fromio_wrapper -
- * reads from sdioc, and updats the sdioc registers according
- * to how many bytes were actually read.
- *
- * @str_func: a pointer to func struct.
- * @client_rd_ptr: sdioc value of downlink read ptr.
- * @client_wr_ptr: sdioc value of downlink write ptr.
- * @buffer_to_store: buffer to store incoming data.
- * @address_to_read: address to start reading from in sdioc.
- * @size_to_read: size of bytes to read.
- * @client_buffer_size: sdioc downlink buffer size.
- * @return 0 on success or negative value on error.
- */
-static int sdio_memcpy_fromio_wrapper(struct sdio_func *str_func,
- unsigned int client_rd_ptr,
- unsigned int client_wr_ptr,
- void *buffer_to_store,
- unsigned int address_to_read_from,
- int size_to_read,
- int client_buffer_size)
-{
- int status = 0;
- struct sdioc_reg_chunk *reg_str =
- &sdio_dld->sdio_dloader_data.sdioc_reg;
-
- if (!str_func) {
- pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- if (!buffer_to_store) {
- pr_err(MODULE_NAME ": %s - param ""buffer_to_store"" is "
- "NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- if (size_to_read < 0) {
- pr_err(MODULE_NAME ": %s - invalid size to read=%d\n",
- __func__, size_to_read);
- return -EINVAL;
- }
-
- sdio_claim_host(str_func);
-
- pr_debug(MODULE_NAME ": %s, READING DATA - from add %d, "
- "size_to_read=%d\n",
- __func__, address_to_read_from, size_to_read);
-
- status = sdio_memcpy_fromio(str_func,
- (void *)buffer_to_store,
- address_to_read_from,
- size_to_read);
- if (status) {
- pr_err(MODULE_NAME ": %s - sdio_memcpy_fromio()"
- " DATA failed. status=%d.\n",
- __func__, status);
- sdio_release_host(str_func);
- return status;
- }
-
- /* updating an offset according to cyclic buffer size */
- reg_str->dl_rd_ptr.reg_val =
- (reg_str->dl_rd_ptr.reg_val + size_to_read) %
- client_buffer_size;
- /* keeping sdio_dld_info up to date */
- sdio_dld_info.cl_dl_rd_ptr = reg_str->dl_rd_ptr.reg_val;
-
- status = sdio_memcpy_toio(str_func,
- reg_str->dl_rd_ptr.reg_offset,
- (void *)®_str->dl_rd_ptr.reg_val,
- sizeof(reg_str->dl_rd_ptr.reg_val));
-
- if (status) {
- pr_err(MODULE_NAME ": %s - sdio_memcpy_toio() "
- "UPDATE PTR failed. status=%d.\n",
- __func__, status);
- }
-
- sdio_release_host(str_func);
- return status;
-}
-
-/**
- * sdio_memcpy_toio_wrapper
- * writes to sdioc, and updats the sdioc registers according
- * to how many bytes were actually read.
- *
- * @str_func: a pointer to func struct.
- * @client_wr_ptr: sdioc downlink write ptr.
- * @h_read_ptr: host incoming read ptrs
- * @buf_write_from: buffer to write from.
- * @bytes_to_write: number of bytes to write.
- * @return 0 on success or negative value on error.
- */
-static int sdio_memcpy_toio_wrapper(struct sdio_func *str_func,
- unsigned int client_wr_ptr,
- unsigned int h_read_ptr,
- void *buf_write_from,
- int bytes_to_write)
-{
- int status = 0;
- struct sdioc_reg_chunk *reg_str =
- &sdio_dld->sdio_dloader_data.sdioc_reg;
- struct sdio_data *outgoing = &sdio_dld->sdio_dloader_data.outgoing_data;
-
- if (!str_func) {
- pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- if (!buf_write_from) {
- pr_err(MODULE_NAME ": %s - param ""buf_write_from"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- sdio_claim_host(str_func);
-
- pr_debug(MODULE_NAME ": %s, WRITING DATA TOIO to address 0x%x, "
- "bytes_to_write=%d\n",
- __func__,
- reg_str->up_buff_address.reg_val + reg_str->up_wr_ptr.reg_val,
- bytes_to_write);
-
- status = sdio_memcpy_toio(str_func,
- reg_str->up_buff_address.reg_val +
- reg_str->up_wr_ptr.reg_val,
- (void *) (outgoing->data + h_read_ptr),
- bytes_to_write);
-
- if (status) {
- pr_err(MODULE_NAME ": %s - sdio_memcpy_toio() "
- "DATA failed. status=%d.\n", __func__, status);
- sdio_release_host(str_func);
- return status;
- }
-
- sdio_dld_info.global_bytes_write_toio += bytes_to_write;
- outgoing->num_of_bytes_in_use -= bytes_to_write;
-
- /*
- * if writing to client succeeded, then
- * 1. update the client up_wr_ptr
- * 2. update the host outgoing rd ptr
- **/
- reg_str->up_wr_ptr.reg_val =
- ((reg_str->up_wr_ptr.reg_val + bytes_to_write) %
- reg_str->ul_buff_size.reg_val);
-
- /* keeping sdio_dld_info up to date */
- sdio_dld_info.cl_up_wr_ptr = reg_str->up_wr_ptr.reg_val;
-
- outgoing->offset_read_p =
- ((outgoing->offset_read_p + bytes_to_write) %
- outgoing->buffer_size);
-
- /* keeping sdio_dld_info up to date*/
- sdio_dld_info.host_read_ptr = outgoing->offset_read_p;
-
-#ifdef CONFIG_DEBUG_FS
- debugfs_glob.global_write_toio = bytes_to_write;
- update_gd(SDIO_DLD_DEBUGFS_CASE_4_CODE);
-#endif
-
- /* updating uplink write pointer according to size that was written */
- status = sdio_memcpy_toio(str_func,
- reg_str->up_wr_ptr.reg_offset,
- (void *)(®_str->up_wr_ptr.reg_val),
- sizeof(reg_str->up_wr_ptr.reg_val));
- if (status) {
- pr_err(MODULE_NAME ": %s - sdio_memcpy_toio() "
- "UPDATE PTR failed. status=%d.\n",
- __func__, status);
- }
-
- sdio_release_host(str_func);
- return status;
-}
-
-/**
- * sdio_dld_read
- * reads from sdioc
- *
- * @client_rd_ptr: sdioc downlink read ptr.
- * @client_wr_ptr: sdioc downlink write ptr.
- * @reg_str: sdioc register shadowing struct.
- * @str_func: a pointer to func struct.
- * @bytes_read:how many bytes read.
- * @return 0 on success or negative value on error.
- */
-static int sdio_dld_read(unsigned int client_rd_ptr,
- unsigned int client_wr_ptr,
- struct sdioc_reg_chunk *reg_str,
- struct sdio_func *str_func,
- int *bytes_read)
-{
- int status = 0;
- struct sdio_data *incoming = &sdio_dld->sdio_dloader_data.incoming_data;
-
- if (!reg_str) {
- pr_err(MODULE_NAME ": %s - param ""reg_str"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- if (!str_func) {
- pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- if (!bytes_read) {
- pr_err(MODULE_NAME ": %s - param ""bytes_read"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- /* there is data to read in ONE chunk */
- if (client_wr_ptr > client_rd_ptr) {
- status = sdio_memcpy_fromio_wrapper(
- str_func,
- client_rd_ptr,
- client_wr_ptr,
- (void *)incoming->data,
- reg_str->dl_buff_address.reg_val + client_rd_ptr,
- client_wr_ptr - client_rd_ptr,
- reg_str->dl_buff_size.reg_val);
-
- if (status) {
- pr_err(MODULE_NAME ": %s - Failure in Function "
- "sdio_memcpy_fromio_wrapper(). "
- "SINGLE CHUNK READ. status=%d\n",
- __func__, status);
- return status;
- }
-
- incoming->num_of_bytes_in_use += client_wr_ptr - client_rd_ptr;
- *bytes_read = client_wr_ptr - client_rd_ptr;
-
-#ifdef CONFIG_DEBUG_FS
- debugfs_glob.global_to_read =
- client_wr_ptr - client_rd_ptr;
- update_gd(SDIO_DLD_DEBUGFS_CASE_11_CODE);
-#endif
- }
-
- /* there is data to read in TWO chunks */
- else {
- int dl_buf_size = reg_str->dl_buff_size.reg_val;
- int tail_size = dl_buf_size - client_rd_ptr;
-
- /* reading chunk#1: from rd_ptr to the end of the buffer */
- status = sdio_memcpy_fromio_wrapper(
- str_func,
- client_rd_ptr,
- dl_buf_size,
- (void *)incoming->data,
- reg_str->dl_buff_address.reg_val + client_rd_ptr,
- tail_size,
- dl_buf_size);
-
- if (status) {
- pr_err(MODULE_NAME ": %s - Failure in Function "
- "sdio_memcpy_fromio_wrapper(). "
- "1 of 2 CHUNKS READ. status=%d\n",
- __func__, status);
- return status;
- }
-
- incoming->num_of_bytes_in_use += tail_size;
- *bytes_read = tail_size;
-
-#ifdef CONFIG_DEBUG_FS
- debugfs_glob.global_to_read = tail_size;
- update_gd(SDIO_DLD_DEBUGFS_CASE_11_CODE);
-#endif
-
- /* reading chunk#2: reading from beginning buffer */
- status = sdio_memcpy_fromio_wrapper(
- str_func,
- client_rd_ptr,
- client_wr_ptr,
- (void *)(incoming->data + tail_size),
- reg_str->dl_buff_address.reg_val,
- client_wr_ptr,
- reg_str->dl_buff_size.reg_val);
-
- if (status) {
- pr_err(MODULE_NAME ": %s - Failure in Function "
- "sdio_memcpy_fromio_wrapper(). "
- "2 of 2 CHUNKS READ. status=%d\n",
- __func__, status);
- return status;
- }
-
- incoming->num_of_bytes_in_use += client_wr_ptr;
- *bytes_read += client_wr_ptr;
-
-#ifdef CONFIG_DEBUG_FS
- debugfs_glob.global_to_read = client_wr_ptr;
- update_gd(SDIO_DLD_DEBUGFS_CASE_11_CODE);
-#endif
- }
- return 0;
-}
-
-/**
- * sdio_dld_main_task
- * sdio downloader main task. reads mailboxf checks if there is
- * anything to read, checks if host has anything to
- * write.
- *
- * @card: a pointer to mmc_card.
- * @return 0 on success or negative value on error.
- */
-static int sdio_dld_main_task(void *card)
-{
- int status = 0;
- struct tty_struct *tty = sdio_dld->tty_str;
- struct sdioc_reg_chunk *reg_str =
- &sdio_dld->sdio_dloader_data.sdioc_reg;
- int func = sdio_dld->sdioc_boot_func;
- struct sdio_func *str_func = NULL;
- struct sdio_data *outgoing = &sdio_dld->sdio_dloader_data.outgoing_data;
- struct sdio_data *incoming = &sdio_dld->sdio_dloader_data.incoming_data;
- struct sdio_dld_task *task = &sdio_dld->dld_main_thread;
- int retries = 0;
-#ifdef PUSH_STRING
- int bytes_pushed = 0;
-#endif
-
- msleep(SLEEP_MS);
-
- if (!card) {
- pr_err(MODULE_NAME ": %s - param ""card"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- if (!tty) {
- pr_err(MODULE_NAME ": %s - param ""tty"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- str_func = ((struct mmc_card *)card)->
- sdio_func[REAL_FUNC_TO_FUNC_IN_ARRAY(func)];
-
- if (!str_func) {
- pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- while (true) {
- /* client pointers for both buffers */
- int client_ul_wr_ptr = 0;
- int client_ul_rd_ptr = 0;
- int client_dl_wr_ptr = 0;
- int client_dl_rd_ptr = 0;
-
- /* host pointer for outgoing buffer */
- int h_out_wr_ptr = 0;
- int h_out_rd_ptr = 0;
-
- int h_bytes_rdy_wr = 0;
- int c_bytes_rdy_rcve = 0;
-
- int need_to_write = 0;
- int need_to_read = 0;
-
- /*
- * forever, checking for signal to die, then read MailBox.
- * if nothing to read or nothing to write to client, sleep,
- * and again read MailBox
- */
- do {
- int dummy = 0;
-
- /* checking if a signal to die was sent */
- if (atomic_read(&task->please_close) == 1) {
-
- pr_debug(MODULE_NAME ": %s - 0x%x was written "
- "to 9K\n", __func__, SDIOC_EXIT_CODE);
-
- sdio_claim_host(str_func);
-
- /* returned value is not checked on purpose */
- sdio_memcpy_toio(
- str_func,
- reg_str->good_to_exit_ptr.reg_offset,
- (void *)®_str->good_to_exit_ptr.
- reg_val,
- sizeof(reg_str->good_to_exit_ptr.
- reg_val));
-
- sdio_release_host(str_func);
-
- task->exit_wait.wake_up_signal = 1;
- wake_up(&task->exit_wait.wait_event);
- return 0;
- }
-
- status = mailbox_to_seq_chunk_read_ptrs(str_func);
- if (status) {
- pr_err(MODULE_NAME ": %s - Failure in Function "
- "mailbox_to_seq_chunk_read_ptrs(). "
- "status=%d\n", __func__, status);
- return status;
- }
-
- /* calculate how many bytes the host has send */
- h_out_wr_ptr = outgoing->offset_write_p;
- h_out_rd_ptr = outgoing->offset_read_p;
-
- status = sdioc_bytes_till_end_of_buffer(
- h_out_wr_ptr,
- h_out_rd_ptr,
- outgoing->buffer_size,
- &dummy,
- &h_bytes_rdy_wr);
-
- if (status) {
- pr_err(MODULE_NAME ": %s - Failure in Function "
- "sdioc_bytes_till_end_of_buffer(). "
- "status=%d\n", __func__, status);
- return status;
- }
-
- /* is there something to read from client */
- client_dl_wr_ptr = reg_str->dl_wr_ptr.reg_val;
- client_dl_rd_ptr = reg_str->dl_rd_ptr.reg_val;
-
- if (client_dl_rd_ptr != client_dl_wr_ptr)
- need_to_read = 1;
-
- /*
- * calculate how many bytes the client can receive
- * from host
- */
- client_ul_wr_ptr = reg_str->up_wr_ptr.reg_val;
- client_ul_rd_ptr = reg_str->up_rd_ptr.reg_val;
-
- status = sdioc_bytes_till_end_of_buffer(
- client_ul_wr_ptr,
- client_ul_rd_ptr,
- reg_str->ul_buff_size.reg_val,
- &c_bytes_rdy_rcve,
- &dummy);
-
- if (status) {
- pr_err(MODULE_NAME ": %s - Failure in Function "
- "sdioc_bytes_till_end_of_buffer(). "
- "status=%d\n", __func__, status);
- return status;
- }
-
- /* if host has anything to write */
- if (h_bytes_rdy_wr > 0)
- need_to_write = 1;
-
- if (need_to_write || need_to_read)
- break;
-
- spin_lock_irqsave(&lock2, lock_flags2);
- sdio_dld->main_loop_event.wake_up_signal = 0;
- spin_unlock_irqrestore(&lock2, lock_flags2);
-
- pr_debug(MODULE_NAME ": %s - MAIN LOOP - WAITING...\n",
- __func__);
-#ifdef CONFIG_DEBUG_FS
- update_gd(SDIO_DLD_DEBUGFS_CASE_6_CODE);
-#endif
- wait_event(sdio_dld->main_loop_event.wait_event,
- sdio_dld->main_loop_event.wake_up_signal);
-#ifdef CONFIG_DEBUG_FS
- update_gd(SDIO_DLD_DEBUGFS_CASE_7_CODE);
-#endif
-
- pr_debug(MODULE_NAME ": %s - MAIN LOOP - WOKE UP...\n",
- __func__);
-
- } while (1);
-
- /* CHECK IF THERE IS ANYTHING TO READ IN CLIENT */
- if (need_to_read) {
-#ifdef PUSH_STRING
- int num_push = 0;
- int left = 0;
- int bytes_read;
-#else
- int i;
-#endif
- need_to_read = 0;
-
- status = sdio_dld_read(client_dl_rd_ptr,
- client_dl_wr_ptr,
- reg_str,
- str_func,
- &bytes_read);
-
- if (status) {
- pr_err(MODULE_NAME ": %s - Failure in Function "
- "sdio_dld_read(). status=%d\n",
- __func__, status);
- return status;
- }
-
- sdio_dld_info.global_bytes_read_fromio +=
- bytes_read;
-
- bytes_pushed = 0;
-#ifdef PUSH_STRING
- left = incoming->num_of_bytes_in_use;
- start_timer(&sdio_dld->push_timer,
- sdio_dld->push_timer_ms);
- do {
- num_push = tty_insert_flip_string(
- tty,
- incoming->data+bytes_pushed,
- left);
-
- bytes_pushed += num_push;
- left -= num_push;
- tty_flip_buffer_push(tty);
- } while (left != 0);
-
- del_timer(&sdio_dld->push_timer);
-
- if (bytes_pushed != incoming->num_of_bytes_in_use) {
- pr_err(MODULE_NAME ": %s - failed\n",
- __func__);
- }
-#else
- pr_debug(MODULE_NAME ": %s - NEED TO READ %d\n",
- __func__, incoming->num_of_bytes_in_use);
-
- for (i = 0 ; i < incoming->num_of_bytes_in_use ; ++i) {
- int err = 0;
- err = tty_insert_flip_char(tty,
- incoming->data[i],
- TTY_NORMAL);
- tty_flip_buffer_push(tty);
- }
-
- pr_debug(MODULE_NAME ": %s - JUST READ\n", __func__);
-#endif /*PUSH_STRING*/
- sdio_dld_info.global_bytes_push_tty +=
- incoming->num_of_bytes_in_use;
-#ifdef CONFIG_DEBUG_FS
- debugfs_glob.global_push_to_tty = bytes_read;
- update_gd(SDIO_DLD_DEBUGFS_CASE_12_CODE);
-#endif
- incoming->num_of_bytes_in_use = 0;
- tty_flip_buffer_push(tty);
- }
-
- /* CHECK IF THERE IS ANYTHING TO WRITE IN HOST AND HOW MUCH */
- if (need_to_write) {
- int dummy = 0;
-
- do {
- int bytes_to_write = min(c_bytes_rdy_rcve,
- h_bytes_rdy_wr);
-
- /*
- * in case nothing to send or no room to
- * receive
- */
- if (bytes_to_write == 0)
- break;
-
- if (client_ul_rd_ptr == 0 &&
- (client_ul_rd_ptr != client_ul_wr_ptr))
- break;
-
- /*
- * if client_rd_ptr points to start, but there
- * is data to read wait until WRITE_TILL_END
- * before writing a chunk of data, to avoid
- * writing until (BUF_SIZE - 1), because it will
- * yield an extra write of "1" bytes
- */
- if (client_ul_rd_ptr == 0 &&
- (client_ul_rd_ptr != client_ul_wr_ptr) &&
- retries < WRITE_TILL_END_RETRIES) {
- retries++;
- break;
- }
- retries = 0;
-
-#ifdef CONFIG_DEBUG_FS
- debugfs_glob.global_8k_has = h_bytes_rdy_wr;
- debugfs_glob.global_9k_has = c_bytes_rdy_rcve;
- debugfs_glob.global_min = bytes_to_write;
- update_gd(SDIO_DLD_DEBUGFS_CASE_2_CODE);
-#endif
- need_to_write = 0;
-
- pr_debug(MODULE_NAME ": %s - NEED TO WRITE "
- "TOIO %d\n",
- __func__, bytes_to_write);
-
- status = sdio_memcpy_toio_wrapper(
- str_func,
- reg_str->up_wr_ptr.reg_val,
- outgoing->offset_read_p,
- (void *)((char *)outgoing->data +
- outgoing->offset_read_p),
- bytes_to_write);
-
- if (status) {
- pr_err(MODULE_NAME ": %s - Failure in "
- "Function "
- "sdio_memcpy_toio_wrapper(). "
- "SINGLE CHUNK WRITE. "
- "status=%d\n",
- __func__, status);
- return status;
- }
-
- sdio_claim_host(str_func);
-
- status = sdio_memcpy_fromio(
- str_func,
- (void *)®_str->up_rd_ptr.reg_val,
- SDIOC_UL_RD_PTR,
- sizeof(reg_str->up_rd_ptr.reg_val));
-
- if (status) {
- pr_err(MODULE_NAME ": %s - "
- "sdio_memcpy_fromio() "
- "failed. status=%d\n",
- __func__, status);
- sdio_release_host(str_func);
-
- return status;
- }
-
- sdio_release_host(str_func);
-
- spin_lock_irqsave(&lock1, lock_flags1);
- if (sdio_dld->write_callback_event.
- wake_up_signal == 0) {
- sdio_dld->write_callback_event.
- wake_up_signal = 1;
- wake_up(&sdio_dld->
- write_callback_event.
- wait_event);
- }
-
- spin_unlock_irqrestore(&lock1, lock_flags1);
- client_ul_wr_ptr = reg_str->up_wr_ptr.reg_val;
- client_ul_rd_ptr = reg_str->up_rd_ptr.reg_val;
-
- status = sdioc_bytes_till_end_of_buffer(
- client_ul_wr_ptr,
- client_ul_rd_ptr,
- reg_str->ul_buff_size.reg_val,
- &c_bytes_rdy_rcve,
- &dummy);
-
- /* calculate how many bytes host has to send */
- h_out_wr_ptr = outgoing->offset_write_p;
- h_out_rd_ptr = outgoing->offset_read_p;
-
- status = sdioc_bytes_till_end_of_buffer(
- h_out_wr_ptr,
- h_out_rd_ptr,
- outgoing->buffer_size,
- &dummy,
- &h_bytes_rdy_wr);
-
- } while (h_out_wr_ptr != h_out_rd_ptr);
- }
- }
- return 0;
-}
-
-/**
- * sdio_dld_init_global
- * initialization of sdio_dld global struct
- *
- * @card: a pointer to mmc_card.
- * @return 0 on success or negative value on error.
- */
-static int sdio_dld_init_global(struct mmc_card *card,
- int(*done)(void))
-{
- if (!card) {
- pr_err(MODULE_NAME ": %s - param ""card"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- if (!done) {
- pr_err(MODULE_NAME ": %s - param ""done"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- sdio_dld->done_callback = done;
- sdio_dld->card = card;
- init_waitqueue_head(&sdio_dld->dld_main_thread.exit_wait.wait_event);
- sdio_dld->write_callback_event.wake_up_signal = 1;
- sdio_dld->main_loop_event.wake_up_signal = 1;
-
- sdio_dld->sdio_dloader_data.sdioc_reg.dl_buff_size.reg_offset =
- SDIOC_DL_BUFF_SIZE_OFFSET;
-
- sdio_dld->sdio_dloader_data.sdioc_reg.dl_rd_ptr.reg_offset =
- SDIOC_DL_RD_PTR;
-
- sdio_dld->sdio_dloader_data.sdioc_reg.dl_wr_ptr.reg_offset =
- SDIOC_DL_WR_PTR;
-
- sdio_dld->sdio_dloader_data.sdioc_reg.ul_buff_size.reg_offset =
- SDIOC_UP_BUFF_SIZE_OFFSET;
-
- sdio_dld->sdio_dloader_data.sdioc_reg.up_rd_ptr.reg_offset =
- SDIOC_UL_RD_PTR;
-
- sdio_dld->sdio_dloader_data.sdioc_reg.up_wr_ptr.reg_offset =
- SDIOC_UL_WR_PTR;
-
- sdio_dld->sdio_dloader_data.sdioc_reg.good_to_exit_ptr.reg_offset =
- SDIOC_EXIT_PTR;
-
- sdio_dld->sdio_dloader_data.sdioc_reg.dl_buff_address.reg_offset =
- SDIOC_DL_BUFF_ADDRESS;
-
- sdio_dld->sdio_dloader_data.sdioc_reg.up_buff_address.reg_offset =
- SDIOC_UP_BUFF_ADDRESS;
-
- sdio_dld_set_op_mode(SDIO_DLD_NORMAL_MODE);
-
- return 0;
-}
-
-/**
- * sdio_downloader_setup
- * initializes the TTY driver
- *
- * @card: a pointer to mmc_card.
- * @num_of_devices: number of devices.
- * @channel_number: channel number.
- * @return 0 on success or negative value on error.
- *
- * The TTY stack needs to know in advance how many devices it should
- * plan to manage. Use this call to set up the ports that will
- * be exported through SDIO.
- */
-int sdio_downloader_setup(struct mmc_card *card,
- unsigned int num_of_devices,
- int channel_number,
- int(*done)(void))
-{
- int status = 0;
- int result = 0;
- int func_in_array = 0;
- struct sdio_func *str_func = NULL;
- struct device *tty_dev;
-
- if (atomic_read(&sdio_dld_in_use) == 1)
- return -EBUSY;
-
- /*
- * If the setup is already complete tear down the existing
- * one and reinitialize. This might happen during modem restarts
- * in boot phase.
- */
- if (atomic_read(&sdio_dld_setup_done) == 1)
- sdio_dld_tear_down(NULL);
-
- if (num_of_devices == 0 || num_of_devices > MAX_NUM_DEVICES) {
- pr_err(MODULE_NAME ": %s - invalid number of devices\n",
- __func__);
- return -EINVAL;
- }
-
- if (!card) {
- pr_err(MODULE_NAME ": %s - param ""card"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- if (!done) {
- pr_err(MODULE_NAME ": %s - param ""done"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- sdio_dld = kzalloc(sizeof(struct sdio_downloader), GFP_KERNEL);
- if (!sdio_dld) {
- pr_err(MODULE_NAME ": %s - couldn't allocate sdio_dld data "
- "structure.", __func__);
- return -ENOMEM;
- }
-
-#ifdef CONFIG_DEBUG_FS
- bootloader_debugfs_init();
-#endif /* CONFIG_DEBUG_FS */
-
- status = sdio_dld_init_global(card, done);
-
- if (status) {
- pr_err(MODULE_NAME ": %s - Failure in Function "
- "sdio_dld_init_global(). status=%d\n",
- __func__, status);
- kfree(sdio_dld);
- return status;
- }
-
- sdio_dld->tty_drv = alloc_tty_driver(num_of_devices);
-
- if (!sdio_dld->tty_drv) {
- pr_err(MODULE_NAME ": %s - param ""sdio_dld->tty_drv"" is "
- "NULL.\n", __func__);
- kfree(sdio_dld);
- return -EINVAL;
- }
-
- sdio_dld_set_op_mode((enum sdio_dld_op_mode)sdio_op_mode);
-
- /* according to op_mode, a different tty device is created */
- if (sdio_dld->op_mode == SDIO_DLD_BOOT_TEST_MODE)
- sdio_dld->tty_drv->name = TTY_SDIO_DEV_TEST;
- else
- sdio_dld->tty_drv->name = TTY_SDIO_DEV;
-
- sdio_dld->tty_drv->owner = THIS_MODULE;
- sdio_dld->tty_drv->driver_name = "SDIO_Dloader";
-
- /* uses dynamically assigned dev_t values */
- sdio_dld->tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
- sdio_dld->tty_drv->subtype = SERIAL_TYPE_NORMAL;
- sdio_dld->tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV
- | TTY_DRIVER_RESET_TERMIOS;
-
- /* initializing the tty driver */
- sdio_dld->tty_drv->init_termios = tty_std_termios;
- sdio_dld->tty_drv->init_termios.c_cflag =
- B4800 | CS8 | CREAD | HUPCL | CLOCAL;
- sdio_dld->tty_drv->init_termios.c_ispeed = INPUT_SPEED;
- sdio_dld->tty_drv->init_termios.c_ospeed = OUTPUT_SPEED;
-
- tty_set_operations(sdio_dld->tty_drv, &sdio_dloader_tty_ops);
-
- status = tty_register_driver(sdio_dld->tty_drv);
- if (status) {
- put_tty_driver(sdio_dld->tty_drv);
- pr_err(MODULE_NAME ": %s - tty_register_driver() failed\n",
- __func__);
-
- sdio_dld->tty_drv = NULL;
- kfree(sdio_dld);
- return status;
- }
-
- tty_dev = tty_register_device(sdio_dld->tty_drv, 0, NULL);
- if (IS_ERR(tty_dev)) {
- pr_err(MODULE_NAME ": %s - tty_register_device() "
- "failed\n", __func__);
- tty_unregister_driver(sdio_dld->tty_drv);
- put_tty_driver(sdio_dld->tty_drv);
- kfree(sdio_dld);
- return PTR_ERR(tty_dev);
- }
-
- sdio_dld->sdioc_boot_func = SDIOC_CHAN_TO_FUNC_NUM(channel_number);
- func_in_array = REAL_FUNC_TO_FUNC_IN_ARRAY(sdio_dld->sdioc_boot_func);
- str_func = sdio_dld->card->sdio_func[func_in_array];
- status = sdio_dld_init_func(str_func);
- if (status) {
- pr_err(MODULE_NAME ": %s - Failure in Function "
- "sdio_dld_init_func(). status=%d\n",
- __func__, status);
- goto exit_err;
- }
-
-#ifdef CONFIG_DEBUG_FS
- sdio_dld_debug_init();
-#endif
-
- sdio_claim_host(str_func);
-
- /*
- * notifing the client by writing what mode we are by writing
- * to a special register
- */
- status = sdio_memcpy_toio(str_func,
- SDIOC_OP_MODE_PTR,
- (void *)&sdio_dld->op_mode,
- sizeof(sdio_dld->op_mode));
-
- sdio_release_host(str_func);
-
- if (status) {
- pr_err(MODULE_NAME ": %s - sdio_memcpy_toio() "
- "writing to OP_MODE_REGISTER failed. "
- "status=%d.\n",
- __func__, status);
- goto exit_err;
- }
-
- atomic_set(&sdio_dld_setup_done, 1);
- return 0;
-
-exit_err:
- tty_unregister_device(sdio_dld->tty_drv, 0);
- result = tty_unregister_driver(sdio_dld->tty_drv);
- if (result)
- pr_err(MODULE_NAME ": %s - tty_unregister_driver() "
- "failed. result=%d\n", __func__, -result);
- put_tty_driver(sdio_dld->tty_drv);
- kfree(sdio_dld);
- atomic_set(&sdio_dld_setup_done, 0);
- return status;
-}
-
-static void sdio_dld_tear_down(struct work_struct *work)
-{
- int status = 0;
-
- if (atomic_read(&sdio_dld_in_use) == 1) {
- del_timer_sync(&sdio_dld->timer);
- del_timer_sync(&sdio_dld->push_timer);
- sdio_dld_dealloc_local_buffers();
- }
-
- tty_unregister_device(sdio_dld->tty_drv, 0);
-
- status = tty_unregister_driver(sdio_dld->tty_drv);
- if (status) {
- pr_err(MODULE_NAME ": %s - tty_unregister_driver() failed\n",
- __func__);
- }
-
- put_tty_driver(sdio_dld->tty_drv);
- kfree(sdio_dld);
- atomic_set(&sdio_dld_in_use, 0);
- atomic_set(&sdio_dld_setup_done, 0);
-}
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("SDIO Downloader");
-MODULE_AUTHOR("Yaniv Gardi <ygardi@codeaurora.org>");
-MODULE_VERSION(DRV_VERSION);
-
diff --git a/arch/arm/mach-msm/sdio_al_private.h b/arch/arm/mach-msm/sdio_al_private.h
deleted file mode 100644
index 3a5ab79..0000000
--- a/arch/arm/mach-msm/sdio_al_private.h
+++ /dev/null
@@ -1,267 +0,0 @@
-/* Copyright (c) 2011, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-/*
- * SDIO-Abstraction-Layer internal interface.
- */
-
-#ifndef __SDIO_AL_PRIVATE__
-#define __SDIO_AL_PRIVATE__
-
-#include <linux/mmc/card.h>
-#include <linux/platform_device.h>
-#include <mach/sdio_al.h>
-
-#define DRV_VERSION "1.30"
-#define MODULE_NAME "sdio_al"
-#define SDIOC_CHAN_TO_FUNC_NUM(x) ((x)+2)
-#define REAL_FUNC_TO_FUNC_IN_ARRAY(x) ((x)-1)
-#define SDIO_PREFIX "SDIO_"
-#define PEER_CHANNEL_NAME_SIZE 4
-#define CHANNEL_NAME_SIZE (sizeof(SDIO_PREFIX) + PEER_CHANNEL_NAME_SIZE)
-#define SDIO_TEST_POSTFIX_SIZE 5
-#define MAX_NUM_OF_SDIO_DEVICES 2
-#define TEST_CH_NAME_SIZE (CHANNEL_NAME_SIZE + SDIO_TEST_POSTFIX_SIZE)
-
-struct sdio_al_device; /* Forward Declaration */
-
-enum sdio_channel_state {
- SDIO_CHANNEL_STATE_INVALID, /* before reading software header */
- SDIO_CHANNEL_STATE_IDLE, /* channel valid, not opened */
- SDIO_CHANNEL_STATE_CLOSED, /* was closed */
- SDIO_CHANNEL_STATE_OPEN, /* opened */
- SDIO_CHANNEL_STATE_CLOSING, /* during flush, when closing */
-};
-/**
- * Peer SDIO-Client channel configuration.
- *
- * @is_ready - channel is ready and the data is valid.
- *
- * @max_rx_threshold - maximum rx threshold, according to the
- * total buffers size on the peer pipe.
- * @max_tx_threshold - maximum tx threshold, according to the
- * total buffers size on the peer pipe.
- * @tx_buf_size - size of a single buffer on the peer pipe; a
- * transfer smaller than the buffer size still
- * make the buffer unusable for the next transfer.
- * @max_packet_size
- * @is_host_ok_to_sleep - Host marks this bit when it's okay to
- * sleep (no pending transactions)
- */
-struct peer_sdioc_channel_config {
- u32 is_ready;
- u32 max_rx_threshold; /* Downlink */
- u32 max_tx_threshold; /* Uplink */
- u32 tx_buf_size;
- u32 max_packet_size;
- u32 is_host_ok_to_sleep;
- u32 is_packet_mode;
- u32 peer_operation;
- u32 is_low_latency_ch;
- u32 reserved[23];
-};
-
-
-/**
- * Peer SDIO-Client channel statsitics.
- *
- * @last_any_read_avail - the last read avail in all the
- * channels including this channel.
- * @last_read_avail - the last read_avail that was read from HW
- * mailbox.
- * @last_old_read_avail - the last read_avail channel shadow.
- * @total_notifs - the total number of read notifications sent
- * to this channel client
- * @total_read_times - the total number of successful sdio_read
- * calls for this channel
- */
-struct sdio_channel_statistics {
- int last_any_read_avail;
- int last_read_avail;
- int last_old_read_avail;
- int total_notifs;
- int total_read_times;
-};
-
-/**
- * SDIO Channel context.
- *
- * @name - channel name. Used by the caller to open the
- * channel.
- *
- * @read_threshold - Threshold on SDIO-Client mailbox for Rx
- * Data available bytes. When the limit exceed
- * the SDIO-Client generates an interrupt to the
- * host.
- *
- * @write_threshold - Threshold on SDIO-Client mailbox for Tx
- * Data available bytes. When the limit exceed
- * the SDIO-Client generates an interrupt to the
- * host.
- *
- * @def_read_threshold - Default theshold on SDIO-Client for Rx
- *
- * @min_write_avail - Threshold of minimal available bytes
- * to write. Below that threshold the host
- * will initiate reading the mailbox.
- *
- * @poll_delay_msec - Delay between polling the mailbox. When
- * the SDIO-Client doesn't generates EOT
- * interrupt for Rx Available bytes, the host
- * should poll the SDIO-Client mailbox.
- *
- * @is_packet_mode - The host get interrupt when a packet is
- * available at the SDIO-client (pipe EOT
- * indication).
- *
- * @num - channel number.
- *
- * @notify - Client's callback. Should not call sdio read/write.
- *
- * @priv - Client's private context, provided to callback.
- *
- * @is_valid - Channel is used (we have a list of
- * SDIO_AL_MAX_CHANNELS and not all of them are in
- * use).
- *
- * @is_open - Channel is open.
- *
- * @func - SDIO Function handle.
- *
- * @rx_pipe_index - SDIO-Client Pipe Index for Rx Data.
- *
- * @tx_pipe_index - SDIO-Client Pipe Index for Tx Data.
- *
- * @ch_lock - Channel lock to protect channel specific Data
- *
- * @rx_pending_bytes - Total number of Rx pending bytes, at Rx
- * packet list. Maximum of 16KB-1 limited by
- * SDIO-Client specification.
- *
- * @read_avail - Available bytes to read.
- *
- * @write_avail - Available bytes to write.
- *
- * @rx_size_list_head - The head of Rx Pending Packets List.
- *
- * @pdev - platform device - clients to probe for the sdio-al.
- *
- * @signature - Context Validity check.
- *
- * @sdio_al_dev - a pointer to the sdio_al_device instance of
- * this channel
- *
- * @statistics - channel statistics
- *
- */
-struct sdio_channel {
- /* Channel Configuration Parameters*/
- char name[CHANNEL_NAME_SIZE];
- char ch_test_name[TEST_CH_NAME_SIZE];
- int read_threshold;
- int write_threshold;
- int def_read_threshold;
- int threshold_change_cnt;
- int min_write_avail;
- int poll_delay_msec;
- int is_packet_mode;
- int is_low_latency_ch;
-
- struct peer_sdioc_channel_config ch_config;
-
- /* Channel Info */
- int num;
-
- void (*notify)(void *priv, unsigned channel_event);
- void *priv;
-
- int state;
-
- struct sdio_func *func;
-
- int rx_pipe_index;
- int tx_pipe_index;
-
- struct mutex ch_lock;
-
- u32 read_avail;
- u32 write_avail;
-
- u32 peer_tx_buf_size;
-
- u16 rx_pending_bytes;
-
- struct list_head rx_size_list_head;
-
- struct platform_device *pdev;
-
- u32 total_rx_bytes;
- u32 total_tx_bytes;
-
- u32 signature;
-
- struct sdio_al_device *sdio_al_dev;
-
- struct sdio_channel_statistics statistics;
-};
-
-/**
- * sdio_downloader_setup
- * initializes the TTY driver
- *
- * @card: a pointer to mmc_card.
- * @num_of_devices: number of devices.
- * @channel_number: channel number.
- * @return 0 on success or negative value on error.
- *
- * The TTY stack needs to know in advance how many devices it should
- * plan to manage. Use this call to set up the ports that will
- * be exported through SDIO.
- */
-int sdio_downloader_setup(struct mmc_card *card,
- unsigned int num_of_devices,
- int func_number,
- int(*func)(void));
-
-/**
- * test_channel_init
- * initializes a test channel
- *
- * @name: the channel name.
- * @return 0 on success or negative value on error.
- *
- */
-int test_channel_init(char *name);
-
-/**
- * sdio_al_register_lpm_cb
- * Allow the sdio_al test to register for lpm voting
- * notifications
- *
- * @device_handle: the device handle.
- * @wakeup_callback: callback function to be called when voting.
- *
- */
-void sdio_al_register_lpm_cb(void *device_handle,
- int(*lpm_callback)(void *, int));
-
-/**
- * sdio_al_unregister_lpm_cb
- * Allow the sdio_al test to unregister for lpm voting
- * notifications
- *
- * @device_handle: the device handle.
- *
- */
-void sdio_al_unregister_lpm_cb(void *device_handle);
-
-#endif /* __SDIO_AL_PRIVATE__ */
diff --git a/arch/arm/mach-msm/sdio_al_test.c b/arch/arm/mach-msm/sdio_al_test.c
deleted file mode 100644
index 2c9f675..0000000
--- a/arch/arm/mach-msm/sdio_al_test.c
+++ /dev/null
@@ -1,6500 +0,0 @@
-/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-/*
- * SDIO-Abstraction-Layer Test Module.
- *
- */
-
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/workqueue.h>
-#include <linux/fs.h>
-#include <linux/cdev.h>
-#include <linux/sched.h>
-#include <linux/wait.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/random.h>
-#include <linux/platform_device.h>
-#include <mach/sdio_smem.h>
-#include <linux/wakelock.h>
-#include <linux/uaccess.h>
-
-#include "sdio_al_private.h"
-#include <linux/debugfs.h>
-
-#include <linux/kthread.h>
-enum lpm_test_msg_type {
- LPM_NO_MSG, /* 0 */
- LPM_MSG_SEND, /* 1 */
- LPM_MSG_REC, /* 2 */
- LPM_SLEEP, /* 3 */
- LPM_WAKEUP, /* 4 */
- LPM_NOTIFY /* 5 */
-};
-
-#define LPM_NO_MSG_NAME "LPM No Event"
-#define LPM_MSG_SEND_NAME "LPM Send Msg Event"
-#define LPM_MSG_REC_NAME "LPM Receive Msg Event"
-#define LPM_SLEEP_NAME "LPM Sleep Event"
-#define LPM_WAKEUP_NAME "LPM Wakeup Event"
-
-/** Module name string */
-#define TEST_MODULE_NAME "sdio_al_test"
-
-#define TEST_SIGNATURE 0x12345678
-#define TEST_CONFIG_SIGNATURE 0xBEEFCAFE
-
-#define MAX_XFER_SIZE (16*1024)
-#define SMEM_MAX_XFER_SIZE 0xBC000
-#define A2_MIN_PACKET_SIZE 5
-#define RMNT_PACKET_SIZE (4*1024)
-#define DUN_PACKET_SIZE (2*1024)
-#define CSVT_PACKET_SIZE 1700
-
-#define TEST_DBG(x...) if (test_ctx->runtime_debug) pr_info(x)
-
-#define LPM_TEST_NUM_OF_PACKETS 100
-#define LPM_MAX_OPEN_CHAN_PER_DEV 4
-#define LPM_ARRAY_SIZE (7*LPM_TEST_NUM_OF_PACKETS*LPM_MAX_OPEN_CHAN_PER_DEV)
-#define SDIO_LPM_TEST "sdio_lpm_test_reading_task"
-#define LPM_TEST_CONFIG_SIGNATURE 0xDEADBABE
-#define LPM_MSG_NAME_SIZE 20
-#define MAX_STR_SIZE 10
-#define MAX_AVG_RTT_TIME_USEC 2500
-#define SDIO_RMNT_RTT_PACKET_SIZE 32
-#define SDIO_CSVT_RTT_PACKET_SIZE 1900
-
-#define A2_HEADER_OVERHEAD 8
-
-enum rx_process_state {
- RX_PROCESS_PACKET_INIT,
- RX_PROCESS_A2_HEADER,
- RX_PROCESS_PACKET_DATA,
-};
-
-enum sdio_test_case_type {
- SDIO_TEST_LOOPBACK_HOST,
- SDIO_TEST_LOOPBACK_CLIENT,
- SDIO_TEST_LPM_HOST_WAKER,
- SDIO_TEST_LPM_CLIENT_WAKER,
- SDIO_TEST_LPM_RANDOM,
- SDIO_TEST_HOST_SENDER_NO_LP,
- SDIO_TEST_CLOSE_CHANNEL,
- SDIO_TEST_A2_VALIDATION,
- /* The following tests are not part of the 9k tests and should be
- * kept last in case new tests are added
- */
- SDIO_TEST_PERF,
- SDIO_TEST_RTT,
- SDIO_TEST_MODEM_RESET,
-};
-
-struct lpm_task {
- struct task_struct *lpm_task;
- const char *task_name;
-};
-
-struct lpm_entry_type {
- enum lpm_test_msg_type msg_type;
- char msg_name[LPM_MSG_NAME_SIZE];
- u32 counter;
- u32 current_ms;
- u32 read_avail_mask;
- char chan_name[CHANNEL_NAME_SIZE];
-};
-
-struct lpm_msg {
- u32 signature;
- u32 counter;
- u32 reserve1;
- u32 reserve2;
-};
-
-struct test_config_msg {
- u32 signature;
- u32 test_case;
- u32 test_param;
- u32 num_packets;
- u32 num_iterations;
-};
-
-struct test_result_msg {
- u32 signature;
- u32 is_successful;
-};
-
-struct test_work {
- struct work_struct work;
- struct test_channel *test_ch;
-};
-
-enum sdio_channels_ids {
- SDIO_RPC,
- SDIO_QMI,
- SDIO_RMNT,
- SDIO_DIAG,
- SDIO_DUN,
- SDIO_SMEM,
- SDIO_CSVT,
- SDIO_MAX_CHANNELS
-};
-
-enum sdio_test_results {
- TEST_NO_RESULT,
- TEST_FAILED,
- TEST_PASSED
-};
-
-enum sdio_lpm_vote_state {
- SDIO_NO_VOTE,
- SDIO_VOTE_FOR_SLEEP,
- SDIO_VOTE_AGAINST_SLEEP
-};
-
-struct sdio_test_device {
- int open_channels_counter_to_recv;
- int open_channels_counter_to_send;
- struct lpm_entry_type *lpm_arr;
- int array_size;
- void *sdio_al_device;
- spinlock_t lpm_array_lock;
- unsigned long lpm_array_lock_flags;
- u32 next_avail_entry_in_array;
- struct lpm_task lpm_test_task;
- u32 next_mask_id;
- u32 read_avail_mask;
- int modem_result_per_dev;
- int final_result_per_dev;
-};
-
-struct test_channel {
- struct sdio_channel *ch;
-
- char name[CHANNEL_NAME_SIZE];
- int ch_id;
-
- struct sdio_test_device *test_device;
-
- u32 *buf;
- u32 buf_size;
-
- struct workqueue_struct *workqueue;
- struct test_work test_work;
-
- u32 rx_bytes;
- u32 tx_bytes;
-
- wait_queue_head_t wait_q;
- atomic_t rx_notify_count;
- atomic_t tx_notify_count;
- atomic_t any_notify_count;
- atomic_t wakeup_client;
- atomic_t card_detected_event;
-
- int wait_counter;
-
- int is_used;
- int test_type;
- int ch_ready;
-
- struct test_config_msg config_msg;
-
- int test_completed;
- int test_result;
- struct timer_list timer;
- int timer_interval_ms;
-
- struct timer_list timeout_timer;
- int timeout_ms;
- void *sdio_al_device;
- int is_ok_to_sleep;
- unsigned int packet_length;
- int random_packet_size;
- int next_index_in_sent_msg_per_chan;
- int channel_mask_id;
- int modem_result_per_chan;
- int notify_counter_per_chan;
- int max_burst_size; /* number of writes before close/open */
- int card_removed;
-};
-
-struct sdio_al_test_debug {
- u32 dun_throughput;
- u32 rmnt_throughput;
- struct dentry *debug_root;
- struct dentry *debug_test_result;
- struct dentry *debug_dun_throughput;
- struct dentry *debug_rmnt_throughput;
- struct dentry *rpc_sender_test;
- struct dentry *rpc_qmi_diag_sender_test;
- struct dentry *smem_test;
- struct dentry *smem_rpc_test;
- struct dentry *rmnet_a2_validation_test;
- struct dentry *dun_a2_validation_test;
- struct dentry *rmnet_a2_perf_test;
- struct dentry *dun_a2_perf_test;
- struct dentry *csvt_a2_perf_test;
- struct dentry *rmnet_dun_a2_perf_test;
- struct dentry *rpc_sender_rmnet_a2_perf_test;
- struct dentry *all_channels_test;
- struct dentry *host_sender_no_lp_diag_test;
- struct dentry *host_sender_no_lp_diag_rpc_test;
- struct dentry *rmnet_small_packets_test;
- struct dentry *rmnet_rtt_test;
- struct dentry *csvt_rtt_test;
- struct dentry *modem_reset_rpc_test;
- struct dentry *modem_reset_rmnet_test;
- struct dentry *modem_reset_channels_4bit_dev_test;
- struct dentry *modem_reset_channels_8bit_dev_test;
- struct dentry *modem_reset_all_channels_test;
- struct dentry *open_close_test;
- struct dentry *open_close_dun_rmnet_test;
- struct dentry *close_chan_lpm_test;
- struct dentry *lpm_test_client_wakes_host_test;
- struct dentry *lpm_test_host_wakes_client_test;
- struct dentry *lpm_test_random_single_channel_test;
- struct dentry *lpm_test_random_multi_channel_test;
-};
-
-struct test_context {
- dev_t dev_num;
- struct device *dev;
- struct cdev *cdev;
- int number_of_active_devices;
- int max_number_of_devices;
-
- struct sdio_test_device test_dev_arr[MAX_NUM_OF_SDIO_DEVICES];
-
- struct test_channel *test_ch;
-
- struct test_channel *test_ch_arr[SDIO_MAX_CHANNELS];
-
- long testcase;
-
- const char *name;
-
- int exit_flag;
-
- u32 signature;
-
- int runtime_debug;
-
- struct platform_device *smem_pdev;
- struct sdio_smem_client *sdio_smem;
- int smem_was_init;
- u8 *smem_buf;
- uint32_t smem_counter;
-
- struct platform_device *csvt_app_pdev;
-
- wait_queue_head_t wait_q;
- int test_completed;
- int test_result;
- struct sdio_al_test_debug debug;
-
- struct wake_lock wake_lock;
-
- unsigned int lpm_pseudo_random_seed;
-};
-
-/* FORWARD DECLARATIONS */
-static int set_params_loopback_9k(struct test_channel *tch);
-static int set_params_smem_test(struct test_channel *tch);
-static int set_params_a2_validation(struct test_channel *tch);
-static int set_params_a2_perf(struct test_channel *tch);
-static int set_params_8k_sender_no_lp(struct test_channel *tch);
-static int set_params_a2_small_pkts(struct test_channel *tch);
-static int set_params_rtt(struct test_channel *tch);
-static int set_params_loopback_9k_close(struct test_channel *tch);
-static int close_channel_lpm_test(int channel_num);
-static int set_params_lpm_test(struct test_channel *tch,
- enum sdio_test_case_type test,
- int timer_interval_ms);
-static void set_pseudo_random_seed(void);
-static int set_params_modem_reset(struct test_channel *tch);
-static int test_start(void);
-static void rx_cleanup(struct test_channel *test_ch, int *rx_packet_count);
-static void sdio_al_test_cleanup_channels(void);
-static void notify(void *priv, unsigned channel_event);
-#ifdef CONFIG_MSM_SDIO_SMEM
-static int sdio_smem_open(struct sdio_smem_client *sdio_smem);
-#endif
-
-/*
- * Seed for pseudo random time sleeping in Random LPM test.
- * If not set, current time in jiffies is used.
- */
-static unsigned int seed;
-module_param(seed, int, 0);
-static struct test_context *test_ctx;
-
-static void sdio_al_test_initial_dev_and_chan(struct test_context *test_ctx)
-{
- int i = 0;
-
- if (!test_ctx) {
- pr_err(TEST_MODULE_NAME ":%s - test_ctx is NULL.\n", __func__);
- return;
- }
-
- for (i = 0 ; i < MAX_NUM_OF_SDIO_DEVICES ; ++i)
- test_ctx->test_dev_arr[i].sdio_al_device = NULL;
-
- for (i = 0; i < SDIO_MAX_CHANNELS; i++) {
- struct test_channel *tch = test_ctx->test_ch_arr[i];
- if (!tch)
- continue;
- tch->is_used = 0;
- }
-
- sdio_al_test_cleanup_channels();
-}
-
-#ifdef CONFIG_DEBUG_FS
-
-static int message_repeat;
-
-static int sdio_al_test_extract_number(const char __user *buf,
- size_t count)
-{
- int ret = 0;
- int number = -1;
- char local_buf[MAX_STR_SIZE] = {0};
- char *start = NULL;
-
- if (count > MAX_STR_SIZE) {
- pr_err(TEST_MODULE_NAME ": %s - MAX_STR_SIZE(%d) < count(%d). "
- "Please choose smaller number\n",
- __func__, MAX_STR_SIZE, (int)count);
- return -EINVAL;
- }
-
- if (copy_from_user(local_buf, buf, count)) {
- pr_err(TEST_MODULE_NAME ": %s - copy_from_user() failed\n",
- __func__);
- return -EINVAL;
- }
-
- /* adding null termination to the string */
- local_buf[count] = '\0';
-
- /* stripping leading and trailing white spaces */
- start = strstrip(local_buf);
-
- ret = kstrtoint(start, 10, &number);
-
- if (ret) {
- pr_err(TEST_MODULE_NAME " : %s - kstrtoint() failed\n",
- __func__);
- return ret;
- }
-
- return number;
-}
-
-static int sdio_al_test_open(struct inode *inode, struct file *file)
-{
- file->private_data = inode->i_private;
- message_repeat = 1;
- return 0;
-}
-
-static void sdio_al_test_cleanup_channels(void)
-{
- int channel_num;
- int dummy = 0;
-
- for (channel_num = 0 ; channel_num < SDIO_MAX_CHANNELS ;
- ++channel_num) {
- if (channel_num == SDIO_SMEM)
- continue;
-
- rx_cleanup(test_ctx->test_ch_arr[channel_num], &dummy);
- }
-
- return;
-}
-
-/* RPC SENDER TEST */
-static ssize_t rpc_sender_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- RPC SENDER TEST --\n");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_RPC]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t rpc_sender_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nRPC_SENDER_TEST\n"
- "===============\n"
- "Description:\n"
- "TBD\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations rpc_sender_test_ops = {
- .open = sdio_al_test_open,
- .write = rpc_sender_test_write,
- .read = rpc_sender_test_read,
-};
-
-/* RPC, QMI & DIAG SENDER TEST */
-static ssize_t rpc_qmi_diag_sender_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- RPC, QMI AND DIAG SENDER TEST --\n");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_RPC]);
- set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_QMI]);
- set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_DIAG]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t rpc_qmi_diag_sender_test_read(struct file *file,
- char __user
- *buffer, size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nRPC_QMI_DIAG_SENDER_TEST\n"
- "========================\n"
- "Description:\n"
- "TBD\n");
-
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations rpc_qmi_diag_sender_test_ops = {
- .open = sdio_al_test_open,
- .write = rpc_qmi_diag_sender_test_write,
- .read = rpc_qmi_diag_sender_test_read,
-};
-
-/* SMEM TEST */
-static ssize_t smem_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- SMEM TEST --\n");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_smem_test(test_ctx->test_ch_arr[SDIO_SMEM]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t smem_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nSMEM_TEST\n"
- "=========\n"
- "Description:\n"
- "TBD\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations smem_test_ops = {
- .open = sdio_al_test_open,
- .write = smem_test_write,
- .read = smem_test_read,
-};
-
-/* SMEM & RPC TEST */
-static ssize_t smem_rpc_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- SMEM AND RPC TEST --\n");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_RPC]);
- set_params_smem_test(test_ctx->test_ch_arr[SDIO_SMEM]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t smem_rpc_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nSMEM_RPC_TEST\n"
- "=============\n"
- "Description:\n"
- "TBD\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations smem_rpc_test_ops = {
- .open = sdio_al_test_open,
- .write = smem_rpc_test_write,
- .read = smem_rpc_test_read,
-};
-
-/* RMNET A2 VALIDATION TEST */
-static ssize_t rmnet_a2_validation_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- RMNET A2 VALIDATION TEST --\n");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_a2_validation(test_ctx->test_ch_arr[SDIO_RMNT]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t rmnet_a2_validation_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nRMNET_A2_VALIDATION_TEST\n"
- "=========================\n"
- "Description:\n"
- "In this test, the HOST sends multiple packets to the\n"
- "CLIENT and validates the packets loop backed from A2\n"
- "for the RMNET channel.\n\n"
- "END OF DESCRIPTION\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations rmnet_a2_validation_test_ops = {
- .open = sdio_al_test_open,
- .write = rmnet_a2_validation_test_write,
- .read = rmnet_a2_validation_test_read,
-};
-
-/* DUN A2 VALIDATION TEST */
-static ssize_t dun_a2_validation_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- DUN A2 VALIDATION TEST --\n");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_a2_validation(test_ctx->test_ch_arr[SDIO_DUN]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t dun_a2_validation_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nDUN_A2_VALIDATION_TEST\n"
- "=========================\n"
- "Description:\n"
- "In this test, the HOST sends multiple packets to the\n"
- "CLIENT and validates the packets loop backed from A2\n"
- "for the DUN channel.\n\n"
- "END OF DESCRIPTION\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations dun_a2_validation_test_ops = {
- .open = sdio_al_test_open,
- .write = dun_a2_validation_test_write,
- .read = dun_a2_validation_test_read,
-};
-
-/* RMNET A2 PERFORMANCE TEST */
-static ssize_t rmnet_a2_perf_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- RMNET A2 PERFORMANCE TEST --\n");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_a2_perf(test_ctx->test_ch_arr[SDIO_RMNT]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t rmnet_a2_perf_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nRMNET_A2_PERFORMANCE_TEST\n"
- "=========================\n"
- "Description:\n"
- "TBD\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations rmnet_a2_perf_test_ops = {
- .open = sdio_al_test_open,
- .write = rmnet_a2_perf_test_write,
- .read = rmnet_a2_perf_test_read,
-};
-
-/* DUN A2 PERFORMANCE TEST */
-static ssize_t dun_a2_perf_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- DUN A2 PERFORMANCE TEST --\n");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_a2_perf(test_ctx->test_ch_arr[SDIO_DUN]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t dun_a2_perf_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nDUN_A2_PERFORMANCE_TEST\n"
- "=======================\n"
- "Description:\n"
- "TBD\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations dun_a2_perf_test_ops = {
- .open = sdio_al_test_open,
- .write = dun_a2_perf_test_write,
- .read = dun_a2_perf_test_read,
-};
-
-/* CSVT A2 PERFORMANCE TEST */
-static ssize_t csvt_a2_perf_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- CSVT A2 PERFORMANCE TEST --\n");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_a2_perf(test_ctx->test_ch_arr[SDIO_CSVT]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t csvt_a2_perf_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nCSVT_A2_PERFORMANCE_TEST\n"
- "========================\n"
- "Description:\n"
- "Loopback test on the CSVT Channel, in order to check "
- "throughput performance.\n"
- "Packet size that are sent on the CSVT channel in this "
- "test is %d.bytes\n\n"
- "END OF DESCRIPTION\n", CSVT_PACKET_SIZE);
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations csvt_a2_perf_test_ops = {
- .open = sdio_al_test_open,
- .write = csvt_a2_perf_test_write,
- .read = csvt_a2_perf_test_read,
-};
-
-/* RMNET DUN A2 PERFORMANCE TEST */
-static ssize_t rmnet_dun_a2_perf_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- RMNET AND DUN A2 PERFORMANCE TEST --\n");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_a2_perf(test_ctx->test_ch_arr[SDIO_RMNT]);
- set_params_a2_perf(test_ctx->test_ch_arr[SDIO_DUN]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t rmnet_dun_a2_perf_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nRMNET_DUN_A2_PERFORMANCE_TEST\n"
- "=============================\n"
- "Description:\n"
- "TBD\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations rmnet_dun_a2_perf_test_ops = {
- .open = sdio_al_test_open,
- .write = rmnet_dun_a2_perf_test_write,
- .read = rmnet_dun_a2_perf_test_read,
-};
-
-/* RPC SENDER & RMNET A2 PERFORMANCE TEST */
-static ssize_t rpc_sender_rmnet_a2_perf_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "--RPC SENDER AND RMNET A2 "
- "PERFORMANCE --\n");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_RPC]);
- set_params_a2_perf(test_ctx->test_ch_arr[SDIO_RMNT]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t rpc_sender_rmnet_a2_perf_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nRPC_SENDER_RMNET_A2_PERFORMANCE_TEST\n"
- "====================================\n"
- "Description:\n"
- "TBD\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations rpc_sender_rmnet_a2_perf_test_ops = {
- .open = sdio_al_test_open,
- .write = rpc_sender_rmnet_a2_perf_test_write,
- .read = rpc_sender_rmnet_a2_perf_test_read,
-};
-
-/* ALL CHANNELS TEST */
-static ssize_t all_channels_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- ALL THE CHANNELS TEST --\n");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_RPC]);
- set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_QMI]);
- set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_DIAG]);
- set_params_a2_perf(test_ctx->test_ch_arr[SDIO_RMNT]);
- set_params_a2_perf(test_ctx->test_ch_arr[SDIO_DUN]);
- set_params_smem_test(test_ctx->test_ch_arr[SDIO_SMEM]);
- set_params_a2_perf(test_ctx->test_ch_arr[SDIO_CSVT]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t all_channels_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nALL_CHANNELS_TEST\n"
- "=================\n"
- "Description:\n"
- "TBD\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations all_channels_test_ops = {
- .open = sdio_al_test_open,
- .write = all_channels_test_write,
- .read = all_channels_test_read,
-};
-
-/* HOST SENDER NO LP DIAG TEST */
-static ssize_t host_sender_no_lp_diag_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- HOST SENDER NO LP FOR DIAG TEST --");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_8k_sender_no_lp(test_ctx->test_ch_arr[SDIO_DIAG]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t host_sender_no_lp_diag_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nHOST_SENDER_NO_LP_DIAG_TEST\n"
- "===========================\n"
- "Description:\n"
- "TBD\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations host_sender_no_lp_diag_test_ops = {
- .open = sdio_al_test_open,
- .write = host_sender_no_lp_diag_test_write,
- .read = host_sender_no_lp_diag_test_read,
-};
-
-/* HOST SENDER NO LP DIAG, RPC TEST */
-static ssize_t host_sender_no_lp_diag_rpc_test_write(
- struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- HOST SENDER NO LP FOR DIAG, RPC "
- "TEST --");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_8k_sender_no_lp(test_ctx->test_ch_arr[SDIO_DIAG]);
- set_params_8k_sender_no_lp(test_ctx->test_ch_arr[SDIO_RPC]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t host_sender_no_lp_diag_rpc_test_read(
- struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nHOST_SENDER_NO_LP_DIAG_RPC_TEST\n"
- "===================================\n"
- "Description:\n"
- "TBD\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations host_sender_no_lp_diag_rpc_test_ops = {
- .open = sdio_al_test_open,
- .write = host_sender_no_lp_diag_rpc_test_write,
- .read = host_sender_no_lp_diag_rpc_test_read,
-};
-
-/* RMNET SMALL PACKETS TEST */
-static ssize_t rmnet_small_packets_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- RMNET SMALL PACKETS (5-128) TEST --");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_a2_small_pkts(test_ctx->test_ch_arr[SDIO_RMNT]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t rmnet_small_packets_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nRMNET_SMALL_PACKETS_TEST\n"
- "========================\n"
- "Description:\n"
- "TBD\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations rmnet_small_packets_test_ops = {
- .open = sdio_al_test_open,
- .write = rmnet_small_packets_test_write,
- .read = rmnet_small_packets_test_read,
-};
-
-/* RMNET RTT TEST */
-static ssize_t rmnet_rtt_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- RMNET RTT TEST --");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_rtt(test_ctx->test_ch_arr[SDIO_RMNT]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t rmnet_rtt_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nRMNET_RTT_TEST\n"
- "==============\n"
- "Description:\n"
- "TBD\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations rmnet_rtt_test_ops = {
- .open = sdio_al_test_open,
- .write = rmnet_rtt_test_write,
- .read = rmnet_rtt_test_read,
-};
-
-/* CSVT RTT TEST */
-static ssize_t csvt_rtt_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- CSVT RTT TEST --");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_rtt(test_ctx->test_ch_arr[SDIO_CSVT]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t csvt_rtt_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nCSVT_RTT_TEST\n"
- "==============\n"
- "Description:\n"
- "In this test the HOST send a message of %d bytes "
- "to the CLIENT\n\n"
- "END OF DESCRIPTION\n", SDIO_CSVT_RTT_PACKET_SIZE);
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations csvt_rtt_test_ops = {
- .open = sdio_al_test_open,
- .write = csvt_rtt_test_write,
- .read = csvt_rtt_test_read,
-};
-
-/* MODEM RESET RPC TEST */
-static ssize_t modem_reset_rpc_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- MODEM RESET - RPC CHANNEL TEST --");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_modem_reset(test_ctx->test_ch_arr[SDIO_RPC]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t modem_reset_rpc_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nMODEM_RESET_RPC_TEST\n"
- "====================\n"
- "Description:\n"
- "TBD\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations modem_reset_rpc_test_ops = {
- .open = sdio_al_test_open,
- .write = modem_reset_rpc_test_write,
- .read = modem_reset_rpc_test_read,
-};
-
-/* MODEM RESET RMNET TEST */
-static ssize_t modem_reset_rmnet_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- MODEM RESET - RMNT CHANNEL TEST --");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_modem_reset(test_ctx->test_ch_arr[SDIO_RMNT]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t modem_reset_rmnet_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nMODEM_RESET_RMNET_TEST\n"
- "======================\n"
- "Description:\n"
- "TBD\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations modem_reset_rmnet_test_ops = {
- .open = sdio_al_test_open,
- .write = modem_reset_rmnet_test_write,
- .read = modem_reset_rmnet_test_read,
-};
-
-/* MODEM RESET - CHANNELS IN 4BIT DEVICE TEST */
-static ssize_t modem_reset_channels_4bit_dev_test_write(
- struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- MODEM RESET - ALL CHANNELS IN "
- "4BIT DEVICE TEST --");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_modem_reset(test_ctx->test_ch_arr[SDIO_RPC]);
- set_params_modem_reset(test_ctx->test_ch_arr[SDIO_QMI]);
- set_params_modem_reset(test_ctx->test_ch_arr[SDIO_DIAG]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t modem_reset_channels_4bit_dev_test_read(
- struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nMODEM_RESET_CHANNELS_4BIT_DEV_TEST\n"
- "==================================\n"
- "Description:\n"
- "TBD\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations modem_reset_channels_4bit_dev_test_ops = {
- .open = sdio_al_test_open,
- .write = modem_reset_channels_4bit_dev_test_write,
- .read = modem_reset_channels_4bit_dev_test_read,
-};
-
-/* MODEM RESET - CHANNELS IN 8BIT DEVICE TEST */
-static ssize_t modem_reset_channels_8bit_dev_test_write(
- struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- MODEM RESET - ALL CHANNELS IN "
- "8BIT DEVICE TEST --");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_modem_reset(test_ctx->test_ch_arr[SDIO_RMNT]);
- set_params_modem_reset(test_ctx->test_ch_arr[SDIO_DUN]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t modem_reset_channels_8bit_dev_test_read(
- struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nMODEM_RESET_CHANNELS_8BIT_DEV_TEST\n"
- "==================================\n"
- "Description:\n"
- "TBD\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations modem_reset_channels_8bit_dev_test_ops = {
- .open = sdio_al_test_open,
- .write = modem_reset_channels_8bit_dev_test_write,
- .read = modem_reset_channels_8bit_dev_test_read,
-};
-
-/* MODEM RESET - ALL CHANNELS TEST */
-static ssize_t modem_reset_all_channels_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- MODEM RESET - ALL CHANNELS TEST --");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_modem_reset(test_ctx->test_ch_arr[SDIO_RPC]);
- set_params_modem_reset(test_ctx->test_ch_arr[SDIO_QMI]);
- set_params_modem_reset(test_ctx->test_ch_arr[SDIO_DIAG]);
- set_params_modem_reset(test_ctx->test_ch_arr[SDIO_RMNT]);
- set_params_modem_reset(test_ctx->test_ch_arr[SDIO_DUN]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t modem_reset_all_channels_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nMODEM_RESET_ALL_CHANNELS_TEST\n"
- "=============================\n"
- "Description:\n"
- "TBD\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations modem_reset_all_channels_test_ops = {
- .open = sdio_al_test_open,
- .write = modem_reset_all_channels_test_write,
- .read = modem_reset_all_channels_test_read,
-};
-
-/* HOST SENDER WITH OPEN/CLOSE TEST */
-static ssize_t open_close_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- struct test_channel **ch_arr = test_ctx->test_ch_arr;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- HOST SENDER WITH OPEN/CLOSE TEST --");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_loopback_9k_close(ch_arr[SDIO_DIAG]);
- set_params_loopback_9k_close(ch_arr[SDIO_RPC]);
- set_params_loopback_9k_close(ch_arr[SDIO_SMEM]);
- set_params_loopback_9k_close(ch_arr[SDIO_QMI]);
- set_params_loopback_9k_close(ch_arr[SDIO_RMNT]);
- set_params_loopback_9k_close(ch_arr[SDIO_DUN]);
- set_params_loopback_9k_close(ch_arr[SDIO_CSVT]);
-
- ret = test_start();
-
- if (ret)
- break;
-
- pr_info(TEST_MODULE_NAME " -- correctness test for"
- "DIAG ");
- set_params_loopback_9k(ch_arr[SDIO_DIAG]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t open_close_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nOPEN_CLOSE_TEST\n"
- "============================\n"
- "Description:\n"
- "In this test the host sends 5k packets to the modem in the "
- "following sequence: Send a random burst of packets on "
- "Diag and Rmnet channels, read 0 or a random number "
- "of packets, close and re-open the channel. At the end of the "
- "test, the channel is verified by running a loopback test\n\n"
- "END OF DESCRIPTION\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations open_close_test_ops = {
- .open = sdio_al_test_open,
- .write = open_close_test_write,
- .read = open_close_test_read,
-};
-
-/* HOST SENDER WITH OPEN/CLOSE FOR DUN & RMNET TEST */
-static ssize_t open_close_dun_rmnet_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- struct test_channel **ch_arr = test_ctx->test_ch_arr;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- HOST SENDER WITH OPEN/CLOSE FOR "
- "DUN AND RMNET TEST --");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_loopback_9k_close(ch_arr[SDIO_DUN]);
- set_params_loopback_9k_close(ch_arr[SDIO_RMNT]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t open_close_dun_rmnet_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nOPEN_CLOSE_DUN_RMNET_TEST\n"
- "============================\n"
- "Description:\n"
- "In this test the host sends 5k packets to the modem in the "
- "following sequence: Send a random burst of packets on "
- "DUN and Rmnet channels, read 0 or a random number "
- "of packets, close and re-open the channel.\n\n"
- "END OF DESCRIPTION\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations open_close_dun_rmnet_test_ops = {
- .open = sdio_al_test_open,
- .write = open_close_dun_rmnet_test_write,
- .read = open_close_dun_rmnet_test_read,
-};
-
-/* CLOSE CHANNEL & LPM TEST HOST WAKES THE CLIENT TEST */
-static ssize_t close_chan_lpm_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int channel_num = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- CLOSE CHANNEL & LPM TEST "
- "HOST WAKES THE CLIENT TEST --\n");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- for (channel_num = 0 ; channel_num < SDIO_MAX_CHANNELS ;
- channel_num++) {
-
- ret = close_channel_lpm_test(channel_num);
-
- if (ret)
- break;
-
- set_params_lpm_test(test_ctx->test_ch_arr[SDIO_RPC],
- SDIO_TEST_LPM_HOST_WAKER, 120);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- if (ret) {
- pr_err(TEST_MODULE_NAME " -- Close channel & LPM Test "
- "FAILED: %d --\n", ret);
- } else {
- pr_err(TEST_MODULE_NAME " -- Close channel & LPM Test "
- "PASSED\n");
- }
- }
-
- return count;
-}
-
-static ssize_t close_chan_lpm_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nCLOSE_CHAN_LPM_TEST\n"
- "===================\n"
- "Description:\n"
- "TBD\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations close_chan_lpm_test_ops = {
- .open = sdio_al_test_open,
- .write = close_chan_lpm_test_write,
- .read = close_chan_lpm_test_read,
-};
-
-/* LPM TEST FOR DEVICE 1. CLIENT WAKES THE HOST TEST */
-static ssize_t lpm_test_client_wakes_host_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- LPM TEST FOR DEVICE 1. CLIENT "
- "WAKES THE HOST TEST --\n");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_lpm_test(test_ctx->test_ch_arr[SDIO_RPC],
- SDIO_TEST_LPM_CLIENT_WAKER, 90);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t lpm_test_client_wakes_host_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nLPM_TEST_CLIENT_WAKES_HOST_TEST\n"
- "===============================\n"
- "Description:\n"
- "In this test, the HOST is going into LPM mode,\n"
- "and the CLIENT is responsible to send it a message\n"
- "in order to wake it up\n\n"
- "END OF DESCRIPTION\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations lpm_test_client_wakes_host_test_ops = {
- .open = sdio_al_test_open,
- .write = lpm_test_client_wakes_host_test_write,
- .read = lpm_test_client_wakes_host_test_read,
-};
-
-/* LPM TEST FOR DEVICE 1. HOST WAKES THE CLIENT TEST */
-static ssize_t lpm_test_host_wakes_client_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- LPM TEST FOR DEVICE 1. HOST "
- "WAKES THE CLIENT TEST --\n");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_lpm_test(test_ctx->test_ch_arr[SDIO_RPC],
- SDIO_TEST_LPM_HOST_WAKER, 120);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t lpm_test_host_wakes_client_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nLPM_TEST_HOST_WAKES_CLIENT_TEST\n"
- "===============================\n"
- "Description:\n"
- "In this test, the CLIENT goes into LPM mode, and the\n"
- "HOST is responsible to send it a message\n"
- "in order to wake it up\n\n"
- "END OF DESCRIPTION\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations lpm_test_host_wakes_client_test_ops = {
- .open = sdio_al_test_open,
- .write = lpm_test_host_wakes_client_test_write,
- .read = lpm_test_host_wakes_client_test_read,
-};
-
-/* LPM TEST RANDOM, SINGLE CHANNEL TEST */
-static ssize_t lpm_test_random_single_channel_test_write(
- struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- LPM TEST RANDOM SINGLE "
- "CHANNEL TEST --\n");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_pseudo_random_seed();
- set_params_lpm_test(test_ctx->test_ch_arr[SDIO_RPC],
- SDIO_TEST_LPM_RANDOM, 0);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t lpm_test_random_single_channel_test_read(
- struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nLPM_TEST_RANDOM_SINGLE_CHANNEL_TEST\n"
- "===================================\n"
- "Description:\n"
- "In this test, the HOST and CLIENT "
- "send messages to each other,\n"
- "random in time, over RPC channel only.\n"
- "All events are being recorded, and later on,\n"
- "they are being analysed by the HOST and by the CLIENT\n,"
- "in order to check if the LPM mechanism worked properly,\n"
- "meaning:"
- " When all the relevant conditions are met, a device should:\n"
- "1. Go to sleep\n"
- "2. Wake up\n"
- "3. Stay awake\n\n"
- "END OF DESCRIPTION\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations lpm_test_random_single_channel_test_ops = {
- .open = sdio_al_test_open,
- .write = lpm_test_random_single_channel_test_write,
- .read = lpm_test_random_single_channel_test_read,
-};
-
-/* LPM TEST RANDOM, MULTI CHANNEL TEST */
-static ssize_t lpm_test_random_multi_channel_test_write(
- struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- LPM TEST RANDOM MULTI CHANNEL TEST --\n");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_pseudo_random_seed();
-
- set_params_lpm_test(test_ctx->test_ch_arr[SDIO_RPC],
- SDIO_TEST_LPM_RANDOM, 0);
- set_params_lpm_test(test_ctx->test_ch_arr[SDIO_DIAG],
- SDIO_TEST_LPM_RANDOM, 0);
- set_params_lpm_test(test_ctx->test_ch_arr[SDIO_QMI],
- SDIO_TEST_LPM_RANDOM, 0);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t lpm_test_random_multi_channel_test_read(
- struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nLPM_TEST_RANDOM_MULTI_CHANNEL_TEST\n"
- "==================================\n"
- "Description:\n"
- "In this test, the HOST and CLIENT "
- "send messages to each other,\n"
- "random in time, over RPC, QMI AND DIAG channels\n"
- "(i.e, on both SDIO devices).\n"
- "All events are being recorded, and later on,\n"
- "they are being analysed by the HOST and by the CLIENT,\n"
- "in order to check if the LPM mechanism worked properly,\n"
- "meaning:"
- " When all the relevant conditions are met, a device should:\n"
- "1. Go to sleep\n"
- "2. Wake up\n"
- "3. Stay awake\n\n"
- "END OF DESCRIPTION\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations lpm_test_random_multi_channel_test_ops = {
- .open = sdio_al_test_open,
- .write = lpm_test_random_multi_channel_test_write,
- .read = lpm_test_random_multi_channel_test_read,
-};
-
-static int sdio_al_test_debugfs_init(void)
-{
- test_ctx->debug.debug_root = debugfs_create_dir("sdio_al_test",
- NULL);
- if (!test_ctx->debug.debug_root)
- return -ENOENT;
-
- test_ctx->debug.debug_test_result = debugfs_create_u32(
- "test_result",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- &test_ctx->test_result);
-
- test_ctx->debug.debug_dun_throughput = debugfs_create_u32(
- "dun_throughput",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- &test_ctx->debug.dun_throughput);
-
- test_ctx->debug.debug_rmnt_throughput = debugfs_create_u32(
- "rmnt_throughput",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- &test_ctx->debug.rmnt_throughput);
-
- test_ctx->debug.rpc_sender_test =
- debugfs_create_file("10_rpc_sender_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &rpc_sender_test_ops);
-
- test_ctx->debug.rpc_qmi_diag_sender_test =
- debugfs_create_file("20_rpc_qmi_diag_sender_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &rpc_qmi_diag_sender_test_ops);
-
- test_ctx->debug.rmnet_a2_validation_test =
- debugfs_create_file("30_rmnet_a2_validation_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &rmnet_a2_validation_test_ops);
-
- test_ctx->debug.dun_a2_validation_test =
- debugfs_create_file("40_dun_a2_validation_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &dun_a2_validation_test_ops);
-
- test_ctx->debug.rmnet_a2_perf_test =
- debugfs_create_file("50_rmnet_a2_perf_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &rmnet_a2_perf_test_ops);
-
- test_ctx->debug.dun_a2_perf_test =
- debugfs_create_file("60_dun_a2_perf_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &dun_a2_perf_test_ops);
-
- test_ctx->debug.csvt_a2_perf_test =
- debugfs_create_file("71_csvt_a2_perf_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &csvt_a2_perf_test_ops);
-
- test_ctx->debug.rmnet_dun_a2_perf_test =
- debugfs_create_file("70_rmnet_dun_a2_perf_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &rmnet_dun_a2_perf_test_ops);
-
- test_ctx->debug.rpc_sender_rmnet_a2_perf_test =
- debugfs_create_file("80_rpc_sender_rmnet_a2_perf_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &rpc_sender_rmnet_a2_perf_test_ops);
-
- test_ctx->debug.smem_test =
- debugfs_create_file("90_smem_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &smem_test_ops);
-
- test_ctx->debug.smem_rpc_test =
- debugfs_create_file("100_smem_rpc_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &smem_rpc_test_ops);
-
- test_ctx->debug.all_channels_test =
- debugfs_create_file("150_all_channels_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &all_channels_test_ops);
-
- test_ctx->debug.host_sender_no_lp_diag_test =
- debugfs_create_file("160_host_sender_no_lp_diag_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &host_sender_no_lp_diag_test_ops);
-
- test_ctx->debug.host_sender_no_lp_diag_rpc_test =
- debugfs_create_file("170_host_sender_no_lp_diag_rpc_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &host_sender_no_lp_diag_rpc_test_ops);
-
- test_ctx->debug.rmnet_small_packets_test =
- debugfs_create_file("180_rmnet_small_packets_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &rmnet_small_packets_test_ops);
-
- test_ctx->debug.rmnet_rtt_test =
- debugfs_create_file("190_rmnet_rtt_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &rmnet_rtt_test_ops);
-
- test_ctx->debug.csvt_rtt_test =
- debugfs_create_file("191_csvt_rtt_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &csvt_rtt_test_ops);
-
- test_ctx->debug.modem_reset_rpc_test =
- debugfs_create_file("220_modem_reset_rpc_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &modem_reset_rpc_test_ops);
-
- test_ctx->debug.modem_reset_rmnet_test =
- debugfs_create_file("230_modem_reset_rmnet_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &modem_reset_rmnet_test_ops);
-
- test_ctx->debug.modem_reset_channels_4bit_dev_test =
- debugfs_create_file("240_modem_reset_channels_4bit_dev_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &modem_reset_channels_4bit_dev_test_ops);
-
- test_ctx->debug.modem_reset_channels_8bit_dev_test =
- debugfs_create_file("250_modem_reset_channels_8bit_dev_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &modem_reset_channels_8bit_dev_test_ops);
-
- test_ctx->debug.modem_reset_all_channels_test =
- debugfs_create_file("260_modem_reset_all_channels_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &modem_reset_all_channels_test_ops);
-
- test_ctx->debug.open_close_test =
- debugfs_create_file("270_open_close_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &open_close_test_ops);
-
- test_ctx->debug.open_close_dun_rmnet_test =
- debugfs_create_file("271_open_close_dun_rmnet_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &open_close_dun_rmnet_test_ops);
-
- test_ctx->debug.close_chan_lpm_test =
- debugfs_create_file("280_close_chan_lpm_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &close_chan_lpm_test_ops);
-
- test_ctx->debug.lpm_test_client_wakes_host_test =
- debugfs_create_file("600_lpm_test_client_wakes_host_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &lpm_test_client_wakes_host_test_ops);
-
- test_ctx->debug.lpm_test_host_wakes_client_test =
- debugfs_create_file("610_lpm_test_host_wakes_client_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &lpm_test_host_wakes_client_test_ops);
-
- test_ctx->debug.lpm_test_random_single_channel_test =
- debugfs_create_file("620_lpm_test_random_single_channel_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &lpm_test_random_single_channel_test_ops);
-
- test_ctx->debug.lpm_test_random_multi_channel_test =
- debugfs_create_file("630_lpm_test_random_multi_channel_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &lpm_test_random_multi_channel_test_ops);
-
- if ((!test_ctx->debug.debug_dun_throughput) &&
- (!test_ctx->debug.debug_rmnt_throughput)) {
- debugfs_remove_recursive(test_ctx->debug.debug_root);
- test_ctx->debug.debug_root = NULL;
- return -ENOENT;
- }
- return 0;
-}
-
-static void sdio_al_test_debugfs_cleanup(void)
-{
- debugfs_remove(test_ctx->debug.debug_dun_throughput);
- debugfs_remove(test_ctx->debug.debug_rmnt_throughput);
- debugfs_remove(test_ctx->debug.debug_root);
-}
-#endif
-
-static int channel_name_to_id(char *name)
-{
- pr_info(TEST_MODULE_NAME "%s: channel name %s\n",
- __func__, name);
-
- if (!strncmp(name, "SDIO_RPC_TEST",
- strnlen("SDIO_RPC_TEST", CHANNEL_NAME_SIZE)))
- return SDIO_RPC;
- else if (!strncmp(name, "SDIO_QMI_TEST",
- strnlen("SDIO_QMI_TEST", TEST_CH_NAME_SIZE)))
- return SDIO_QMI;
- else if (!strncmp(name, "SDIO_RMNT_TEST",
- strnlen("SDIO_RMNT_TEST", TEST_CH_NAME_SIZE)))
- return SDIO_RMNT;
- else if (!strncmp(name, "SDIO_DIAG_TEST",
- strnlen("SDIO_DIAG", TEST_CH_NAME_SIZE)))
- return SDIO_DIAG;
- else if (!strncmp(name, "SDIO_DUN_TEST",
- strnlen("SDIO_DUN_TEST", TEST_CH_NAME_SIZE)))
- return SDIO_DUN;
- else if (!strncmp(name, "SDIO_SMEM_TEST",
- strnlen("SDIO_SMEM_TEST", TEST_CH_NAME_SIZE)))
- return SDIO_SMEM;
- else if (!strncmp(name, "SDIO_CSVT_TEST",
- strnlen("SDIO_CSVT_TEST", TEST_CH_NAME_SIZE)))
- return SDIO_CSVT;
- else
- return SDIO_MAX_CHANNELS;
-
- return SDIO_MAX_CHANNELS;
-}
-
-/**
- * Allocate and add SDIO_SMEM platform device
- */
-#ifdef CONFIG_MSM_SDIO_SMEM
-static int add_sdio_smem(void)
-{
- int ret = 0;
-
- test_ctx->smem_pdev = platform_device_alloc("SDIO_SMEM", -1);
- ret = platform_device_add(test_ctx->smem_pdev);
- if (ret) {
- pr_err(TEST_MODULE_NAME ": platform_device_add failed, "
- "ret=%d\n", ret);
- return ret;
- }
- return 0;
-}
-#endif
-
-static int open_sdio_ch(struct test_channel *tch)
-{
- int ret = 0;
-
- if (!tch) {
- pr_err(TEST_MODULE_NAME ": %s NULL tch\n", __func__);
- return -EINVAL;
- }
-
- if (!tch->ch_ready) {
- TEST_DBG(TEST_MODULE_NAME ":openning channel %s\n",
- tch->name);
- if (tch->ch_id == SDIO_SMEM) {
-#ifdef CONFIG_MSM_SDIO_SMEM
- if (!test_ctx->smem_pdev)
- ret = add_sdio_smem();
- else
- ret = sdio_smem_open(test_ctx->sdio_smem);
- if (ret) {
- pr_err(TEST_MODULE_NAME
- ":openning channel %s failed\n",
- tch->name);
- tch->ch_ready = false;
- return -EINVAL;
- }
-#endif
- } else {
- tch->ch_ready = true;
- ret = sdio_open(tch->name , &tch->ch, tch,
- notify);
- if (ret) {
- pr_err(TEST_MODULE_NAME
- ":openning channel %s failed\n",
- tch->name);
- tch->ch_ready = false;
- return -EINVAL;
- }
- }
- }
- return ret;
-}
-
-static int close_sdio_ch(struct test_channel *tch)
-{
- int ret = 0;
-
- if (!tch) {
- pr_err(TEST_MODULE_NAME ": %s NULL tch\n", __func__);
- return -EINVAL;
- }
-
- if (tch->ch_id == SDIO_SMEM) {
-#ifdef CONFIG_MSM_SDIO_SMEM
- TEST_DBG(TEST_MODULE_NAME":%s closing channel %s",
- __func__, tch->name);
- ret = sdio_smem_unregister_client();
- test_ctx->smem_counter = 0;
-#endif
- } else {
- ret = sdio_close(tch->ch);
- }
-
- if (ret) {
- pr_err(TEST_MODULE_NAME":%s close channel %s"
- " failed\n", __func__, tch->name);
- } else {
- TEST_DBG(TEST_MODULE_NAME":%s close channel %s"
- " success\n", __func__, tch->name);
- tch->ch_ready = false;
- }
- return ret;
-}
-
-/**
- * Config message
- */
-
-static void send_config_msg(struct test_channel *test_ch)
-{
- int ret = 0 ;
- u32 write_avail = 0;
- int size = sizeof(test_ch->config_msg);
-
- pr_debug(TEST_MODULE_NAME "%s\n", __func__);
-
- memcpy(test_ch->buf, (void *)&test_ch->config_msg, size);
-
- if (test_ctx->exit_flag) {
- pr_info(TEST_MODULE_NAME ":Exit Test.\n");
- return;
- }
-
- pr_info(TEST_MODULE_NAME ":Sending the config message.\n");
-
- /* wait for data ready event */
- write_avail = sdio_write_avail(test_ch->ch);
- pr_debug(TEST_MODULE_NAME ":write_avail=%d\n", write_avail);
- if (write_avail < size) {
- wait_event(test_ch->wait_q,
- atomic_read(&test_ch->tx_notify_count));
- atomic_dec(&test_ch->tx_notify_count);
- }
-
- write_avail = sdio_write_avail(test_ch->ch);
- pr_debug(TEST_MODULE_NAME ":write_avail=%d\n", write_avail);
- if (write_avail < size) {
- pr_info(TEST_MODULE_NAME ":not enough write avail.\n");
- return;
- }
-
- ret = sdio_write(test_ch->ch, test_ch->buf, size);
- if (ret)
- pr_err(TEST_MODULE_NAME ":%s sdio_write err=%d.\n",
- __func__, -ret);
- else
- pr_info(TEST_MODULE_NAME ":%s sent config_msg successfully.\n",
- __func__);
-}
-
-/**
- * Loopback Test
- */
-static void loopback_test(struct test_channel *test_ch)
-{
- int ret = 0 ;
- u32 read_avail = 0;
- u32 write_avail = 0;
-
- while (1) {
-
- if (test_ctx->exit_flag) {
- pr_info(TEST_MODULE_NAME ":Exit Test.\n");
- return;
- }
-
- TEST_DBG(TEST_MODULE_NAME "--LOOPBACK WAIT FOR EVENT--.\n");
- /* wait for data ready event */
- wait_event(test_ch->wait_q,
- atomic_read(&test_ch->rx_notify_count));
- atomic_dec(&test_ch->rx_notify_count);
-
- read_avail = sdio_read_avail(test_ch->ch);
- if (read_avail == 0)
- continue;
-
-
- write_avail = sdio_write_avail(test_ch->ch);
- if (write_avail < read_avail) {
- pr_info(TEST_MODULE_NAME
- ":not enough write avail.\n");
- continue;
- }
-
- ret = sdio_read(test_ch->ch, test_ch->buf, read_avail);
- if (ret) {
- pr_info(TEST_MODULE_NAME
- ":worker, sdio_read err=%d.\n", -ret);
- continue;
- }
- test_ch->rx_bytes += read_avail;
-
- TEST_DBG(TEST_MODULE_NAME ":worker total rx bytes = 0x%x.\n",
- test_ch->rx_bytes);
-
-
- ret = sdio_write(test_ch->ch,
- test_ch->buf, read_avail);
- if (ret) {
- pr_info(TEST_MODULE_NAME
- ":loopback sdio_write err=%d.\n",
- -ret);
- continue;
- }
- test_ch->tx_bytes += read_avail;
-
- TEST_DBG(TEST_MODULE_NAME
- ":loopback total tx bytes = 0x%x.\n",
- test_ch->tx_bytes);
- } /* end of while */
-}
-
-/**
- * Check if all tests completed
- */
-static void check_test_completion(void)
-{
- int i;
-
- for (i = 0; i < SDIO_MAX_CHANNELS; i++) {
- struct test_channel *tch = test_ctx->test_ch_arr[i];
-
- if ((!tch) || (!tch->is_used) || (!tch->ch_ready))
- continue;
- if (!tch->test_completed) {
- pr_info(TEST_MODULE_NAME ": %s - Channel %s test is "
- "not completed", __func__, tch->name);
- return;
- }
- }
- pr_info(TEST_MODULE_NAME ": %s - Test is completed", __func__);
- test_ctx->test_completed = 1;
- wake_up(&test_ctx->wait_q);
-}
-
-static int pseudo_random_seed(unsigned int *seed_number)
-{
- if (!seed_number)
- return 0;
-
- *seed_number = (unsigned int)(((unsigned long)*seed_number *
- (unsigned long)1103515367) + 35757);
- return (int)((*seed_number / (64*1024)) % 500);
-}
-
-/* this function must be locked before accessing it */
-static void lpm_test_update_entry(struct test_channel *tch,
- enum lpm_test_msg_type msg_type,
- char *msg_name,
- int counter)
-{
- u32 index = 0;
- static int print_full = 1;
- struct sdio_test_device *test_device;
-
- if (!tch) {
- pr_err(TEST_MODULE_NAME ": %s - NULL test channel\n", __func__);
- return;
- }
-
- test_device = tch->test_device;
-
- if (!test_device) {
- pr_err(TEST_MODULE_NAME ": %s - NULL test device\n", __func__);
- return;
- }
-
- if (!test_device->lpm_arr) {
- pr_err(TEST_MODULE_NAME ": %s - NULL lpm_arr\n", __func__);
- return;
- }
-
- if (test_device->next_avail_entry_in_array >=
- test_device->array_size) {
- pr_err(TEST_MODULE_NAME ": %s - lpm array is full",
- __func__);
-
- if (print_full) {
- print_hex_dump(KERN_INFO, TEST_MODULE_NAME ": lpm_arr:",
- 0, 32, 2,
- (void *)test_device->lpm_arr,
- sizeof(test_device->lpm_arr), false);
- print_full = 0;
- }
- return;
- }
-
- index = test_device->next_avail_entry_in_array;
- if ((msg_type == LPM_MSG_SEND) || (msg_type == LPM_MSG_REC))
- test_device->lpm_arr[index].counter = counter;
- else
- test_device->lpm_arr[index].counter = 0;
-
- test_device->lpm_arr[index].msg_type = msg_type;
- memcpy(test_device->lpm_arr[index].msg_name, msg_name,
- LPM_MSG_NAME_SIZE);
- test_device->lpm_arr[index].current_ms =
- jiffies_to_msecs(get_jiffies_64());
-
- test_device->lpm_arr[index].read_avail_mask =
- test_device->read_avail_mask;
-
- if ((msg_type == LPM_SLEEP) || (msg_type == LPM_WAKEUP))
- memcpy(test_device->lpm_arr[index].chan_name, "DEVICE ",
- CHANNEL_NAME_SIZE);
- else
- memcpy(test_device->lpm_arr[index].chan_name, tch->name,
- CHANNEL_NAME_SIZE);
-
- test_device->next_avail_entry_in_array++;
-}
-
-static int wait_for_result_msg(struct test_channel *test_ch)
-{
- u32 read_avail = 0;
- int ret = 0;
-
- pr_info(TEST_MODULE_NAME ": %s - START, channel %s\n",
- __func__, test_ch->name);
-
- while (1) {
- read_avail = sdio_read_avail(test_ch->ch);
-
- if (read_avail == 0) {
- pr_info(TEST_MODULE_NAME
- ": read_avail is 0 for chan %s\n",
- test_ch->name);
- wait_event(test_ch->wait_q,
- atomic_read(&test_ch->rx_notify_count));
- atomic_dec(&test_ch->rx_notify_count);
- continue;
- }
-
- memset(test_ch->buf, 0x00, test_ch->buf_size);
-
- ret = sdio_read(test_ch->ch, test_ch->buf, read_avail);
- if (ret) {
- pr_info(TEST_MODULE_NAME ": sdio_read for chan"
- "%s failed, err=%d.\n",
- test_ch->name, -ret);
- goto exit_err;
- }
-
- if (test_ch->buf[0] != TEST_CONFIG_SIGNATURE) {
- pr_info(TEST_MODULE_NAME ": Not a test_result "
- "signature. expected 0x%x. received 0x%x "
- "for chan %s\n",
- TEST_CONFIG_SIGNATURE,
- test_ch->buf[0],
- test_ch->name);
- continue;
- } else {
- pr_info(TEST_MODULE_NAME ": Signature is "
- "TEST_CONFIG_SIGNATURE as expected for"
- "channel %s\n", test_ch->name);
- break;
- }
- }
-
- return test_ch->buf[1];
-
-exit_err:
- return 0;
-}
-
-static void print_random_lpm_test_array(struct sdio_test_device *test_dev)
-{
- int i;
-
- if (!test_dev) {
- pr_err(TEST_MODULE_NAME ": %s - NULL test device\n", __func__);
- return;
- }
-
- for (i = 0 ; i < test_dev->next_avail_entry_in_array ; ++i) {
- if (i == 0)
- pr_err(TEST_MODULE_NAME ": index %4d, chan=%2s, "
- "code=%1d=%4s, msg#%1d, ms from before=-1, "
- "read_mask=0x%d, ms=%2u",
- i,
- test_dev->lpm_arr[i].chan_name,
- test_dev->lpm_arr[i].msg_type,
- test_dev->lpm_arr[i].msg_name,
- test_dev->lpm_arr[i].counter,
- test_dev->lpm_arr[i].read_avail_mask,
- test_dev->lpm_arr[i].current_ms);
- else
- pr_err(TEST_MODULE_NAME ": index "
- "%4d, %2s, code=%1d=%4s, msg#%1d, ms from "
- "before=%2u, read_mask=0x%d, ms=%2u",
- i,
- test_dev->lpm_arr[i].chan_name,
- test_dev->lpm_arr[i].msg_type,
- test_dev->lpm_arr[i].msg_name,
- test_dev->lpm_arr[i].counter,
- test_dev->lpm_arr[i].current_ms -
- test_dev->lpm_arr[i-1].current_ms,
- test_dev->lpm_arr[i].read_avail_mask,
- test_dev->lpm_arr[i].current_ms);
-
- udelay(1000);
- }
-}
-
-static int check_random_lpm_test_array(struct sdio_test_device *test_dev)
-{
- int i = 0, j = 0;
- unsigned int delta_ms = 0;
- int arr_ind = 0;
- int ret = 0;
- int notify_counter = 0;
- int sleep_counter = 0;
- int wakeup_counter = 0;
- int lpm_activity_counter = 0;
-
- if (!test_dev) {
- pr_err(TEST_MODULE_NAME ": %s - NULL test device\n", __func__);
- return -ENODEV;
- }
-
- for (i = 0; i < test_dev->next_avail_entry_in_array; i++) {
- notify_counter = 0;
- sleep_counter = 0;
- wakeup_counter = 0;
-
- if ((test_dev->lpm_arr[i].msg_type == LPM_MSG_SEND) ||
- (test_dev->lpm_arr[i].msg_type == LPM_MSG_REC)) {
- /* find the next message in the array */
- arr_ind = test_dev->next_avail_entry_in_array;
- for (j = i+1; j < arr_ind; j++) {
- if ((test_dev->lpm_arr[j].msg_type ==
- LPM_MSG_SEND) ||
- (test_dev->lpm_arr[j].msg_type ==
- LPM_MSG_REC) ||
- (test_dev->lpm_arr[j].msg_type ==
- LPM_NOTIFY))
- break;
- if (test_dev->lpm_arr[j].msg_type ==
- LPM_SLEEP)
- sleep_counter++;
- if (test_dev->lpm_arr[j].msg_type ==
- LPM_WAKEUP)
- wakeup_counter++;
- }
- if (j == arr_ind) {
- ret = 0;
- break;
- }
-
- delta_ms = test_dev->lpm_arr[j].current_ms -
- test_dev->lpm_arr[i].current_ms;
- if (delta_ms < 30) {
- if ((sleep_counter == 0)
- && (wakeup_counter == 0)) {
- continue;
- } else {
- pr_err(TEST_MODULE_NAME "%s: lpm "
- "activity while delta is less "
- "than 30, i=%d, j=%d, "
- "sleep_counter=%d, "
- "wakeup_counter=%d",
- __func__, i, j,
- sleep_counter, wakeup_counter);
- ret = -ENODEV;
- break;
- }
- } else {
- if ((delta_ms > 90) &&
- (test_dev->lpm_arr[i].
- read_avail_mask == 0)) {
- if (j != i+3) {
- pr_err(TEST_MODULE_NAME
- "%s: unexpected "
- "lpm activity "
- "while delta is "
- "bigger than "
- "90, i=%d, "
- "j=%d, "
- "notify_counter"
- "=%d",
- __func__, i, j,
- notify_counter);
- ret = -ENODEV;
- break;
- }
- lpm_activity_counter++;
- }
- }
- }
- }
-
- pr_info(TEST_MODULE_NAME ": %s - lpm_activity_counter=%d",
- __func__, lpm_activity_counter);
-
- return ret;
-}
-
-static int lpm_test_main_task(void *ptr)
-{
- u32 read_avail = 0;
- int last_msg_index = 0;
- struct test_channel *test_ch = (struct test_channel *)ptr;
- struct sdio_test_device *test_dev;
- struct lpm_msg lpm_msg;
- int ret = 0;
- int host_result = 0;
-
- if (!test_ch) {
- pr_err(TEST_MODULE_NAME ": %s - NULL channel\n", __func__);
- return -ENODEV;
- }
-
- pr_err(TEST_MODULE_NAME ": %s - STARTED. channel %s\n",
- __func__, test_ch->name);
-
- test_dev = test_ch->test_device;
-
- if (!test_dev) {
- pr_err(TEST_MODULE_NAME ": %s - NULL Test Device\n", __func__);
- return -ENODEV;
- }
-
- while (last_msg_index < test_ch->config_msg.num_packets - 1) {
-
- TEST_DBG(TEST_MODULE_NAME ": %s - "
- "IN LOOP last_msg_index=%d\n",
- __func__, last_msg_index);
-
- read_avail = sdio_read_avail(test_ch->ch);
- if (read_avail == 0) {
- TEST_DBG(TEST_MODULE_NAME
- ":read_avail 0 for chan %s, "
- "wait for event\n",
- test_ch->name);
- wait_event(test_ch->wait_q,
- atomic_read(&test_ch->rx_notify_count));
- atomic_dec(&test_ch->rx_notify_count);
-
- read_avail = sdio_read_avail(test_ch->ch);
- if (read_avail == 0) {
- pr_err(TEST_MODULE_NAME
- ":read_avail size %d for chan %s not as"
- " expected\n",
- read_avail, test_ch->name);
- continue;
- }
- }
-
- memset(test_ch->buf, 0x00, sizeof(test_ch->buf));
-
- ret = sdio_read(test_ch->ch, test_ch->buf, read_avail);
- if (ret) {
- pr_info(TEST_MODULE_NAME ":sdio_read for chan %s"
- " err=%d.\n", test_ch->name, -ret);
- goto exit_err;
- }
-
- memcpy((void *)&lpm_msg, test_ch->buf, sizeof(lpm_msg));
-
- /*
- * when reading from channel, we want to turn off the bit
- * mask that implies that there is pending data on that channel
- */
- if (test_ch->test_device != NULL) {
- spin_lock_irqsave(&test_dev->lpm_array_lock,
- test_dev->lpm_array_lock_flags);
-
- test_ch->notify_counter_per_chan--;
-
- /*
- * if the channel has no pending data, turn off the
- * pending data bit mask of the channel
- */
- if (test_ch->notify_counter_per_chan == 0) {
- test_ch->test_device->read_avail_mask =
- test_ch->test_device->read_avail_mask &
- ~test_ch->channel_mask_id;
- }
-
- last_msg_index = lpm_msg.counter;
- lpm_test_update_entry(test_ch,
- LPM_MSG_REC,
- "RECEIVE",
- last_msg_index);
-
- spin_unlock_irqrestore(&test_dev->lpm_array_lock,
- test_dev->lpm_array_lock_flags);
- }
- }
-
- pr_info(TEST_MODULE_NAME ":%s: Finished to recieve all (%d) "
- "packets from the modem %s. Waiting for result_msg",
- __func__, test_ch->config_msg.num_packets, test_ch->name);
-
- /* Wait for the resault message from the modem */
- test_ch->modem_result_per_chan = wait_for_result_msg(test_ch);
-
- /*
- * the DEVICE modem result is a failure if one of the channels on
- * that device, got modem_result = 0. this is why we bitwise "AND" each
- * time another channel completes its task
- */
- test_dev->modem_result_per_dev &= test_ch->modem_result_per_chan;
-
- /*
- * when reading from channel, we want to turn off the bit
- * mask that implies that there is pending data on that channel
- */
- spin_lock_irqsave(&test_dev->lpm_array_lock,
- test_dev->lpm_array_lock_flags);
-
- test_dev->open_channels_counter_to_recv--;
-
- /* turning off the read_avail bit of the channel */
- test_ch->test_device->read_avail_mask =
- test_ch->test_device->read_avail_mask &
- ~test_ch->channel_mask_id;
-
- spin_unlock_irqrestore(&test_dev->lpm_array_lock,
- test_dev->lpm_array_lock_flags);
-
- /* Wait for all the packets to be sent to the modem */
- while (1) {
- spin_lock_irqsave(&test_dev->lpm_array_lock,
- test_dev->lpm_array_lock_flags);
-
- if (test_ch->next_index_in_sent_msg_per_chan >=
- test_ch->config_msg.num_packets - 1) {
-
- spin_unlock_irqrestore(&test_dev->lpm_array_lock,
- test_dev->lpm_array_lock_flags);
- break;
- } else {
- pr_info(TEST_MODULE_NAME ":%s: Didn't finished to send "
- "all packets, "
- "next_index_in_sent_msg_per_chan = %d ",
- __func__,
- test_ch->next_index_in_sent_msg_per_chan);
- }
- spin_unlock_irqrestore(&test_dev->lpm_array_lock,
- test_dev->lpm_array_lock_flags);
- msleep(60);
- }
-
- /*
- * if device has still open channels to test, then the test on the
- * device is still running but the test on current channel is completed
- */
- if (test_dev->open_channels_counter_to_recv != 0 ||
- test_dev->open_channels_counter_to_send != 0) {
- test_ch->test_completed = 1;
- return 0;
- } else {
- test_ctx->number_of_active_devices--;
- sdio_al_unregister_lpm_cb(test_ch->sdio_al_device);
-
- if (test_ch->test_type == SDIO_TEST_LPM_RANDOM)
- host_result = check_random_lpm_test_array(test_dev);
-
- if (host_result ||
- !test_dev->modem_result_per_dev ||
- test_ctx->runtime_debug)
- print_random_lpm_test_array(test_dev);
-
- pr_info(TEST_MODULE_NAME ": %s - host_result=%d.(0 for "
- "SUCCESS) device_modem_result=%d (1 for SUCCESS)",
- __func__, host_result, test_dev->modem_result_per_dev);
-
- test_ch->test_completed = 1;
- if (test_dev->modem_result_per_dev && !host_result) {
- pr_info(TEST_MODULE_NAME ": %s - Random LPM "
- "TEST_PASSED for device %d of %d\n",
- __func__,
- (test_ctx->max_number_of_devices-
- test_ctx->number_of_active_devices),
- test_ctx->max_number_of_devices);
- test_dev->final_result_per_dev = 1; /* PASSED */
- } else {
- pr_info(TEST_MODULE_NAME ": %s - Random LPM "
- "TEST_FAILED for device %d of %d\n",
- __func__,
- (test_ctx->max_number_of_devices-
- test_ctx->number_of_active_devices),
- test_ctx->max_number_of_devices);
- test_dev->final_result_per_dev = 0; /* FAILED */
- }
-
- check_test_completion();
-
- kfree(test_ch->test_device->lpm_arr);
-
- return 0;
- }
-
-exit_err:
- pr_info(TEST_MODULE_NAME ": TEST FAIL for chan %s.\n",
- test_ch->name);
- test_ch->test_completed = 1;
- test_dev->open_channels_counter_to_recv--;
- test_dev->next_avail_entry_in_array = 0;
- test_ch->next_index_in_sent_msg_per_chan = 0;
- test_ch->test_result = TEST_FAILED;
- check_test_completion();
- return -ENODEV;
-}
-
-static int lpm_test_create_read_thread(struct test_channel *test_ch)
-{
- struct sdio_test_device *test_dev;
-
- pr_info(TEST_MODULE_NAME ": %s - STARTED channel %s\n",
- __func__, test_ch->name);
-
- if (!test_ch) {
- pr_err(TEST_MODULE_NAME ": %s - NULL test channel\n", __func__);
- return -ENODEV;
- }
-
- test_dev = test_ch->test_device;
-
- if (!test_dev) {
- pr_err(TEST_MODULE_NAME ": %s - NULL test device\n", __func__);
- return -ENODEV;
- }
-
- test_dev->lpm_test_task.task_name = SDIO_LPM_TEST;
-
- test_dev->lpm_test_task.lpm_task =
- kthread_create(lpm_test_main_task,
- (void *)(test_ch),
- test_dev->lpm_test_task.task_name);
-
- if (IS_ERR(test_dev->lpm_test_task.lpm_task)) {
- pr_err(TEST_MODULE_NAME ": %s - kthread_create() failed\n",
- __func__);
- return -ENOMEM;
- }
-
- wake_up_process(test_dev->lpm_test_task.lpm_task);
-
- return 0;
-}
-
-static void lpm_continuous_rand_test(struct test_channel *test_ch)
-{
- unsigned int local_ms = 0;
- int ret = 0;
- unsigned int write_avail = 0;
- struct sdio_test_device *test_dev;
-
- pr_info(MODULE_NAME ": %s - STARTED\n", __func__);
-
- if (!test_ch) {
- pr_err(TEST_MODULE_NAME ": %s - NULL channel\n", __func__);
- return;
- }
-
- test_dev = test_ch->test_device;
-
- if (!test_dev) {
- pr_err(TEST_MODULE_NAME ": %s - NULL Test Device\n", __func__);
- return;
- }
-
- ret = lpm_test_create_read_thread(test_ch);
- if (ret != 0) {
- pr_err(TEST_MODULE_NAME ": %s - failed to create lpm reading "
- "thread", __func__);
- }
-
- while (1) {
-
- struct lpm_msg msg;
- u32 ret = 0;
-
- /* sleeping period is dependent on number of open channels */
- test_ch->config_msg.test_param =
- test_ctx->lpm_pseudo_random_seed;
-
- local_ms = test_dev->open_channels_counter_to_send *
- test_ctx->lpm_pseudo_random_seed;
- TEST_DBG(TEST_MODULE_NAME ":%s: SLEEPING for %d ms",
- __func__, local_ms);
- msleep(local_ms);
-
- msg.counter = test_ch->next_index_in_sent_msg_per_chan;
- msg.signature = LPM_TEST_CONFIG_SIGNATURE;
- msg.reserve1 = 0;
- msg.reserve2 = 0;
-
- /* wait for data ready event */
- write_avail = sdio_write_avail(test_ch->ch);
- pr_debug(TEST_MODULE_NAME ": %s: write_avail=%d\n",
- __func__, write_avail);
- if (write_avail < sizeof(msg)) {
- wait_event(test_ch->wait_q,
- atomic_read(&test_ch->tx_notify_count));
- atomic_dec(&test_ch->tx_notify_count);
- }
-
- write_avail = sdio_write_avail(test_ch->ch);
- if (write_avail < sizeof(msg)) {
- pr_info(TEST_MODULE_NAME ": %s: not enough write "
- "avail.\n", __func__);
- break;
- }
-
- ret = sdio_write(test_ch->ch, (u32 *)&msg, sizeof(msg));
- if (ret)
- pr_err(TEST_MODULE_NAME ":%s: sdio_write err=%d.\n",
- __func__, -ret);
-
- TEST_DBG(TEST_MODULE_NAME ": %s: for chan %s, write, "
- "msg # %d\n",
- __func__,
- test_ch->name,
- test_ch->next_index_in_sent_msg_per_chan);
-
- if (test_ch->test_type == SDIO_TEST_LPM_RANDOM) {
- spin_lock_irqsave(&test_dev->lpm_array_lock,
- test_dev->lpm_array_lock_flags);
- lpm_test_update_entry(test_ch, LPM_MSG_SEND,
- "SEND ",
- test_ch->
- next_index_in_sent_msg_per_chan);
-
- test_ch->next_index_in_sent_msg_per_chan++;
-
- if (test_ch->next_index_in_sent_msg_per_chan ==
- test_ch->config_msg.num_packets) {
- spin_unlock_irqrestore(
- &test_dev->lpm_array_lock,
- test_dev->lpm_array_lock_flags);
- break;
- }
-
- spin_unlock_irqrestore(&test_dev->lpm_array_lock,
- test_dev->lpm_array_lock_flags);
- }
- }
-
- spin_lock_irqsave(&test_dev->lpm_array_lock,
- test_dev->lpm_array_lock_flags);
- test_dev->open_channels_counter_to_send--;
- spin_unlock_irqrestore(&test_dev->lpm_array_lock,
- test_dev->lpm_array_lock_flags);
-
- pr_info(TEST_MODULE_NAME ": %s: - Finished to send all (%d) "
- "packets to the modem on channel %s",
- __func__, test_ch->config_msg.num_packets, test_ch->name);
-
- return;
-}
-
-static void lpm_test(struct test_channel *test_ch)
-{
- pr_info(TEST_MODULE_NAME ": %s - START channel %s\n", __func__,
- test_ch->name);
-
- if (!test_ch) {
- pr_err(TEST_MODULE_NAME ": %s - NULL test channel\n", __func__);
- return;
- }
-
- test_ch->modem_result_per_chan = wait_for_result_msg(test_ch);
- pr_debug(TEST_MODULE_NAME ": %s - delete the timeout timer\n",
- __func__);
- del_timer_sync(&test_ch->timeout_timer);
-
- if (test_ch->modem_result_per_chan == 0) {
- pr_err(TEST_MODULE_NAME ": LPM TEST - Client didn't sleep. "
- "Result Msg - is_successful=%d\n", test_ch->buf[1]);
- goto exit_err;
- } else {
- pr_info(TEST_MODULE_NAME ": %s -"
- "LPM 9K WAS SLEEPING - PASS\n", __func__);
- if (test_ch->test_result == TEST_PASSED) {
- pr_info(TEST_MODULE_NAME ": LPM TEST_PASSED\n");
- test_ch->test_completed = 1;
- check_test_completion();
- } else {
- pr_err(TEST_MODULE_NAME ": LPM TEST - Host didn't "
- "sleep. Client slept\n");
- goto exit_err;
- }
- }
-
- return;
-
-exit_err:
- pr_info(TEST_MODULE_NAME ": TEST FAIL for chan %s.\n",
- test_ch->name);
- test_ch->test_completed = 1;
- test_ch->test_result = TEST_FAILED;
- check_test_completion();
- return;
-}
-
-
-/**
- * LPM Test while the host wakes up the modem
- */
-static void lpm_test_host_waker(struct test_channel *test_ch)
-{
- pr_info(TEST_MODULE_NAME ": %s - START\n", __func__);
- wait_event(test_ch->wait_q, atomic_read(&test_ch->wakeup_client));
- atomic_set(&test_ch->wakeup_client, 0);
-
- pr_info(TEST_MODULE_NAME ": %s - Sending the config_msg to wakeup "
- " the client\n", __func__);
- send_config_msg(test_ch);
-
- lpm_test(test_ch);
-}
-
-/**
- * Writes number of packets into test channel
- * @test_ch: test channel control struct
- * @burst_size: number of packets to send
- */
-static int write_packet_burst(struct test_channel *test_ch,
- int burst_size)
-{
- int ret = 0;
- int packet_count = 0;
- unsigned int random_num = 0;
- int size = test_ch->packet_length; /* first packet size */
- u32 write_avail = 0;
-
- while (packet_count < burst_size) {
- /* wait for data ready event */
- write_avail = sdio_write_avail(test_ch->ch);
- TEST_DBG(TEST_MODULE_NAME ":%s write_avail=%d,size=%d on chan"
- " %s\n", __func__,
- write_avail, size, test_ch->name);
- if (write_avail < size) {
- TEST_DBG(TEST_MODULE_NAME ":%s wait for event on"
- " chan %s\n", __func__, test_ch->name);
- wait_event(test_ch->wait_q,
- atomic_read(&test_ch->tx_notify_count));
- atomic_dec(&test_ch->tx_notify_count);
- }
- write_avail = sdio_write_avail(test_ch->ch);
- if (write_avail < size) {
- pr_info(TEST_MODULE_NAME ":%s not enough write"
- " avail %d, need %d on chan %s\n",
- __func__, write_avail, size,
- test_ch->name);
- continue;
- }
- ret = sdio_write(test_ch->ch, test_ch->buf, size);
- if (ret) {
- pr_err(TEST_MODULE_NAME ":%s sdio_write "
- "failed (%d) on chan %s\n", __func__,
- ret, test_ch->name);
- break;
- }
- udelay(1000); /*low bus usage while running number of channels*/
- TEST_DBG(TEST_MODULE_NAME ":%s() successfully write %d bytes"
- ", packet_count=%d on chan %s\n", __func__,
- size, packet_count, test_ch->name);
- test_ch->tx_bytes += size;
- packet_count++;
- /* get next packet size */
- random_num = get_random_int();
- size = (random_num % test_ch->packet_length) + 1;
- }
- return ret;
-}
-
-/**
- * Reads packet from test channel and checks that packet number
- * encoded into the packet is equal to packet_counter
- * This function is applicable for packet mode channels only
- *
- * @test_ch: test channel
- * @size: expected packet size
- * @packet_counter: number to validate readed packet
- */
-static int read_data_from_packet_ch(struct test_channel *test_ch,
- unsigned int size,
- int packet_counter)
-{
- u32 read_avail = 0;
- int ret = 0;
-
- if (!test_ch || !test_ch->ch) {
- pr_err(TEST_MODULE_NAME
- ":%s: NULL channel\n", __func__);
- return -EINVAL;
- }
-
- if (!test_ch->ch->is_packet_mode) {
- pr_err(TEST_MODULE_NAME
- ":%s:not packet mode ch %s\n",
- __func__, test_ch->name);
- return -EINVAL;
- }
- read_avail = sdio_read_avail(test_ch->ch);
- /* wait for read data ready event */
- if (read_avail < size) {
- TEST_DBG(TEST_MODULE_NAME ":%s() wait for rx data on "
- "chan %s\n", __func__, test_ch->name);
- wait_event(test_ch->wait_q,
- atomic_read(&test_ch->rx_notify_count));
- atomic_dec(&test_ch->rx_notify_count);
- }
- read_avail = sdio_read_avail(test_ch->ch);
- TEST_DBG(TEST_MODULE_NAME ":%s read_avail=%d bytes on chan %s\n",
- __func__, read_avail, test_ch->name);
-
- if (read_avail != size) {
- pr_err(TEST_MODULE_NAME
- ":read_avail size %d for chan %s not as "
- "expected size %d\n",
- read_avail, test_ch->name, size);
- return -EINVAL;
- }
-
- ret = sdio_read(test_ch->ch, test_ch->buf, read_avail);
- if (ret) {
- pr_err(TEST_MODULE_NAME ":%s() sdio_read for chan %s (%d)\n",
- __func__, test_ch->name, -ret);
- return ret;
- }
- if ((test_ch->buf[0] != packet_counter) && (size != 1)) {
- pr_err(TEST_MODULE_NAME ":Read WRONG DATA"
- " for chan %s, size=%d\n",
- test_ch->name, size);
- return -EINVAL;
- }
- return 0;
-}
-
-
-/**
- * Reads packet from test channel and checks that packet number
- * encoded into the packet is equal to packet_counter
- * This function is applicable for streaming mode channels only
- *
- * @test_ch: test channel
- * @size: expected packet size
- * @packet_counter: number to validate readed packet
- */
-static int read_data_from_stream_ch(struct test_channel *test_ch,
- unsigned int size,
- int packet_counter)
-{
- u32 read_avail = 0;
- int ret = 0;
-
- if (!test_ch || !test_ch->ch) {
- pr_err(TEST_MODULE_NAME
- ":%s: NULL channel\n", __func__);
- return -EINVAL;
- }
-
- if (test_ch->ch->is_packet_mode) {
- pr_err(TEST_MODULE_NAME
- ":%s:not streaming mode ch %s\n",
- __func__, test_ch->name);
- return -EINVAL;
- }
- read_avail = sdio_read_avail(test_ch->ch);
- /* wait for read data ready event */
- if (read_avail < size) {
- TEST_DBG(TEST_MODULE_NAME ":%s() wait for rx data on "
- "chan %s\n", __func__, test_ch->name);
- wait_event(test_ch->wait_q,
- atomic_read(&test_ch->rx_notify_count));
- atomic_dec(&test_ch->rx_notify_count);
- }
- read_avail = sdio_read_avail(test_ch->ch);
- TEST_DBG(TEST_MODULE_NAME ":%s read_avail=%d bytes on chan %s\n",
- __func__, read_avail, test_ch->name);
-
- if (read_avail < size) {
- pr_err(TEST_MODULE_NAME
- ":read_avail size %d for chan %s not as "
- "expected size %d\n",
- read_avail, test_ch->name, size);
- return -EINVAL;
- }
-
- ret = sdio_read(test_ch->ch, test_ch->buf, size + A2_HEADER_OVERHEAD);
- if (ret) {
- pr_err(TEST_MODULE_NAME ":%s() sdio_read for chan %s (%d)\n",
- __func__, test_ch->name, -ret);
- return ret;
- }
- if ((test_ch->buf[A2_HEADER_OVERHEAD/4] != packet_counter) &&
- (size != 1)) {
- pr_err(TEST_MODULE_NAME ":Read WRONG DATA"
- " for chan %s, size=%d, packet_counter=%d\n",
- test_ch->name, size, packet_counter);
- print_hex_dump(KERN_INFO, TEST_MODULE_NAME ": rmnet:",
- 0, 32, 2,
- (void *)test_ch->buf,
- size + A2_HEADER_OVERHEAD, false);
- return -EINVAL;
- }
- return 0;
-}
-
-/**
- * Test close channel feature for SDIO_SMEM channel:
- * close && re-open the SDIO_SMEM channel.
- */
-#ifdef CONFIG_MSM_SDIO_SMEM
-static void open_close_smem_test(struct test_channel *test_ch)
-{
- int i = 0;
- int ret = 0;
-
- pr_info(TEST_MODULE_NAME ":%s\n", __func__);
-
- for (i = 0; i < 100 ; ++i) {
- ret = close_sdio_ch(test_ch);
- if (ret) {
- pr_err(TEST_MODULE_NAME ":%s close_sdio_ch for ch %s"
- " failed\n",
- __func__, test_ch->name);
- goto exit_err;
- }
- ret = open_sdio_ch(test_ch);
- if (ret) {
- pr_err(TEST_MODULE_NAME ":%s open_sdio_ch for ch %s "
- " failed\n",
- __func__, test_ch->name);
- goto exit_err;
- }
- }
-
- pr_info(TEST_MODULE_NAME ":%s TEST PASS for chan %s.\n", __func__,
- test_ch->name);
- test_ch->test_completed = 1;
- test_ch->test_result = TEST_PASSED;
- check_test_completion();
- return;
-exit_err:
- pr_info(TEST_MODULE_NAME ":%s TEST FAIL for chan %s.\n", __func__,
- test_ch->name);
- test_ch->test_completed = 1;
- test_ch->test_result = TEST_FAILED;
- check_test_completion();
- return;
-}
-#endif
-
-/**
- * Test close channel feature:
- * 1. write random packet number into channel
- * 2. read some data from channel (do this only for second half of
- * requested packets to send).
- * 3. close && re-open then repeat 1.
- *
- * Total packets to send: test_ch->config_msg.num_packets.
- * Burst size is random in [1..test_ch->max_burst_size] range
- * Packet size is random in [1..test_ch->packet_length]
- */
-static void open_close_test(struct test_channel *test_ch)
-{
- int ret = 0;
- u32 read_avail = 0;
- int total_packet_count = 0;
- int size = 0;
- u16 *buf16 = NULL;
- int i;
- int max_packet_count = 0;
- unsigned int random_num = 0;
- int curr_burst_size = 0;
-
- if (!test_ch || !test_ch->ch) {
- pr_err(TEST_MODULE_NAME ":%s NULL channel\n",
- __func__);
- return;
- }
-
- curr_burst_size = test_ch->max_burst_size;
- size = test_ch->packet_length;
- buf16 = (u16 *) test_ch->buf;
-
- /* the test sends configured number of packets in
- 2 portions: first without reading between write bursts,
- second with it */
- max_packet_count = test_ch->config_msg.num_packets / 2;
-
- pr_info(TEST_MODULE_NAME ":%s channel %s, total packets:%d,"
- " max packet size %d, max burst size:%d\n",
- __func__, test_ch->name,
- test_ch->config_msg.num_packets, test_ch->packet_length,
- test_ch->max_burst_size);
- for (i = 0 ; i < size / 2 ; i++)
- buf16[i] = (u16) (i & 0xFFFF);
-
- for (i = 0; i < 2 ; i++) {
- total_packet_count = 0;
- while (total_packet_count < max_packet_count) {
- if (test_ctx->exit_flag) {
- pr_info(TEST_MODULE_NAME ":%s exit test\n",
- __func__);
- return;
- }
- test_ch->buf[0] = total_packet_count;
- random_num = get_random_int();
- curr_burst_size = (random_num %
- test_ch->max_burst_size) + 1;
-
- /* limit burst size to send
- * no more than configured packets */
- if (curr_burst_size + total_packet_count >
- max_packet_count) {
- curr_burst_size = max_packet_count -
- total_packet_count;
- }
- TEST_DBG(TEST_MODULE_NAME ":%s Current burst size:%d"
- " on chan %s\n", __func__,
- curr_burst_size, test_ch->name);
- ret = write_packet_burst(test_ch, curr_burst_size);
- if (ret) {
- pr_err(TEST_MODULE_NAME ":%s write burst failed (%d), ch %s\n",
- __func__, ret, test_ch->name);
- goto exit_err;
- }
- if (i > 0) {
- /* read from channel */
- if (test_ch->ch->is_packet_mode)
- ret = read_data_from_packet_ch(test_ch,
- size,
- total_packet_count);
- else
- ret = read_data_from_stream_ch(test_ch,
- size,
- total_packet_count);
- if (ret) {
- pr_err(TEST_MODULE_NAME ":%s read"
- " failed:%d, chan %s\n",
- __func__, ret,
- test_ch->name);
- goto exit_err;
- }
- }
- TEST_DBG(TEST_MODULE_NAME ":%s before close, ch %s\n",
- __func__, test_ch->name);
- ret = close_sdio_ch(test_ch);
- if (ret) {
- pr_err(TEST_MODULE_NAME":%s close channel %s"
- " failed (%d)\n",
- __func__, test_ch->name, ret);
- goto exit_err;
- } else {
- TEST_DBG(TEST_MODULE_NAME":%s close channel %s"
- " success\n", __func__,
- test_ch->name);
- total_packet_count += curr_burst_size;
- atomic_set(&test_ch->rx_notify_count, 0);
- atomic_set(&test_ch->tx_notify_count, 0);
- atomic_set(&test_ch->any_notify_count, 0);
- }
- TEST_DBG(TEST_MODULE_NAME ":%s before open, ch %s\n",
- __func__, test_ch->name);
- ret = open_sdio_ch(test_ch);
- if (ret) {
- pr_err(TEST_MODULE_NAME":%s open channel %s"
- " failed (%d)\n",
- __func__, test_ch->name, ret);
- goto exit_err;
- } else {
- read_avail = sdio_read_avail(test_ch->ch);
- if (read_avail > 0) {
- pr_err(TEST_MODULE_NAME": after open"
- " ch %s read_availis not zero"
- " (%d bytes)\n",
- test_ch->name, read_avail);
- goto exit_err;
- }
- }
- TEST_DBG(TEST_MODULE_NAME ":%s total tx = %d,"
- " packet# = %d, size = %d for ch %s\n",
- __func__, test_ch->tx_bytes,
- total_packet_count, size,
- test_ch->name);
- } /* end of while */
- }
- pr_info(TEST_MODULE_NAME ":%s Test end: total rx bytes = 0x%x,"
- " total tx bytes = 0x%x for chan %s\n", __func__,
- test_ch->rx_bytes, test_ch->tx_bytes, test_ch->name);
- pr_info(TEST_MODULE_NAME ":%s TEST PASS for chan %s.\n", __func__,
- test_ch->name);
- test_ch->test_completed = 1;
- test_ch->test_result = TEST_PASSED;
- check_test_completion();
- return;
-exit_err:
- pr_info(TEST_MODULE_NAME ":%s TEST FAIL for chan %s.\n", __func__,
- test_ch->name);
- test_ch->test_completed = 1;
- test_ch->test_result = TEST_FAILED;
- check_test_completion();
- return;
-}
-
-/**
- * sender Test
- */
-static void sender_test(struct test_channel *test_ch)
-{
- int ret = 0 ;
- u32 read_avail = 0;
- u32 write_avail = 0;
- int packet_count = 0;
- int size = 512;
- u16 *buf16 = (u16 *) test_ch->buf;
- int i;
- int max_packet_count = 10000;
- int random_num = 0;
-
- max_packet_count = test_ch->config_msg.num_packets;
-
- for (i = 0 ; i < size / 2 ; i++)
- buf16[i] = (u16) (i & 0xFFFF);
-
-
- pr_info(TEST_MODULE_NAME
- ":SENDER TEST START for chan %s\n", test_ch->name);
-
- while (packet_count < max_packet_count) {
-
- if (test_ctx->exit_flag) {
- pr_info(TEST_MODULE_NAME ":Exit Test.\n");
- return;
- }
-
- random_num = get_random_int();
- size = (random_num % test_ch->packet_length) + 1;
-
- TEST_DBG(TEST_MODULE_NAME "SENDER WAIT FOR EVENT for chan %s\n",
- test_ch->name);
-
- /* wait for data ready event */
- write_avail = sdio_write_avail(test_ch->ch);
- TEST_DBG(TEST_MODULE_NAME ":write_avail=%d\n", write_avail);
- if (write_avail < size) {
- wait_event(test_ch->wait_q,
- atomic_read(&test_ch->tx_notify_count));
- atomic_dec(&test_ch->tx_notify_count);
- }
-
- write_avail = sdio_write_avail(test_ch->ch);
- TEST_DBG(TEST_MODULE_NAME ":write_avail=%d\n", write_avail);
- if (write_avail < size) {
- pr_info(TEST_MODULE_NAME ":not enough write avail.\n");
- continue;
- }
-
- test_ch->buf[0] = packet_count;
-
- ret = sdio_write(test_ch->ch, test_ch->buf, size);
- if (ret) {
- pr_info(TEST_MODULE_NAME ":sender sdio_write err=%d.\n",
- -ret);
- goto exit_err;
- }
-
- /* wait for read data ready event */
- TEST_DBG(TEST_MODULE_NAME ":sender wait for rx data for "
- "chan %s\n",
- test_ch->name);
- read_avail = sdio_read_avail(test_ch->ch);
- wait_event(test_ch->wait_q,
- atomic_read(&test_ch->rx_notify_count));
- atomic_dec(&test_ch->rx_notify_count);
-
- read_avail = sdio_read_avail(test_ch->ch);
-
- if (read_avail != size) {
- pr_info(TEST_MODULE_NAME
- ":read_avail size %d for chan %s not as "
- "expected size %d.\n",
- read_avail, test_ch->name, size);
- goto exit_err;
- }
-
- memset(test_ch->buf, 0x00, size);
-
- ret = sdio_read(test_ch->ch, test_ch->buf, size);
- if (ret) {
- pr_info(TEST_MODULE_NAME ":sender sdio_read for chan %s"
- " err=%d.\n",
- test_ch->name, -ret);
- goto exit_err;
- }
-
-
- if ((test_ch->buf[0] != packet_count) && (size != 1)) {
- pr_info(TEST_MODULE_NAME ":sender sdio_read WRONG DATA"
- " for chan %s, size=%d\n",
- test_ch->name, size);
- goto exit_err;
- }
-
- test_ch->tx_bytes += size;
- test_ch->rx_bytes += size;
- packet_count++;
-
- TEST_DBG(TEST_MODULE_NAME
- ":sender total rx bytes = 0x%x , packet#=%d, size=%d"
- " for chan %s\n",
- test_ch->rx_bytes, packet_count, size, test_ch->name);
- TEST_DBG(TEST_MODULE_NAME
- ":sender total tx bytes = 0x%x , packet#=%d, size=%d"
- " for chan %s\n",
- test_ch->tx_bytes, packet_count, size, test_ch->name);
-
- } /* end of while */
-
- pr_info(TEST_MODULE_NAME
- ":SENDER TEST END: total rx bytes = 0x%x, "
- " total tx bytes = 0x%x for chan %s\n",
- test_ch->rx_bytes, test_ch->tx_bytes, test_ch->name);
-
- pr_info(TEST_MODULE_NAME ": TEST PASS for chan %s.\n",
- test_ch->name);
- test_ch->test_completed = 1;
- test_ch->test_result = TEST_PASSED;
- check_test_completion();
- return;
-
-exit_err:
- pr_info(TEST_MODULE_NAME ": TEST FAIL for chan %s.\n",
- test_ch->name);
- test_ch->test_completed = 1;
- test_ch->test_result = TEST_FAILED;
- check_test_completion();
- return;
-}
-
-/**
- * A2 Perf Test
- */
-static void a2_performance_test(struct test_channel *test_ch)
-{
- int ret = 0 ;
- u32 read_avail = 0;
- u32 write_avail = 0;
- int tx_packet_count = 0;
- int rx_packet_count = 0;
- int size = 0;
- u16 *buf16 = (u16 *) test_ch->buf;
- int i;
- int total_bytes = 0;
- int max_packets = 10000;
- u32 packet_size = test_ch->buf_size;
- int rand_size = 0;
-
- u64 start_jiffy, end_jiffy, delta_jiffies;
- unsigned int time_msec = 0;
- u32 throughput = 0;
-
- max_packets = test_ch->config_msg.num_packets;
- packet_size = test_ch->packet_length;
-
- for (i = 0; i < packet_size / 2; i++)
- buf16[i] = (u16) (i & 0xFFFF);
-
- pr_info(TEST_MODULE_NAME ": A2 PERFORMANCE TEST START for chan %s\n",
- test_ch->name);
-
- start_jiffy = get_jiffies_64(); /* read the current time */
-
- while (tx_packet_count < max_packets) {
-
- if (test_ctx->exit_flag) {
- pr_info(TEST_MODULE_NAME ":Exit Test.\n");
- return;
- }
-
- if (test_ch->random_packet_size) {
- rand_size = get_random_int();
- packet_size = (rand_size % test_ch->packet_length) + 1;
- if (packet_size < A2_MIN_PACKET_SIZE)
- packet_size = A2_MIN_PACKET_SIZE;
- }
-
- /* wait for data ready event */
- /* use a func to avoid compiler optimizations */
- write_avail = sdio_write_avail(test_ch->ch);
- read_avail = sdio_read_avail(test_ch->ch);
- TEST_DBG(TEST_MODULE_NAME ":channel %s, write_avail=%d, "
- "read_avail=%d for chan %s\n",
- test_ch->name, write_avail, read_avail,
- test_ch->name);
- if ((write_avail == 0) && (read_avail == 0)) {
- wait_event(test_ch->wait_q,
- atomic_read(&test_ch->any_notify_count));
- atomic_set(&test_ch->any_notify_count, 0);
- }
-
- write_avail = sdio_write_avail(test_ch->ch);
- TEST_DBG(TEST_MODULE_NAME ":channel %s, write_avail=%d\n",
- test_ch->name, write_avail);
- if (write_avail > 0) {
- size = min(packet_size, write_avail) ;
- TEST_DBG(TEST_MODULE_NAME ":tx size = %d for chan %s\n",
- size, test_ch->name);
- test_ch->buf[0] = tx_packet_count;
- test_ch->buf[(size/4)-1] = tx_packet_count;
-
- ret = sdio_write(test_ch->ch, test_ch->buf, size);
- if (ret) {
- pr_info(TEST_MODULE_NAME ":sdio_write err=%d"
- " for chan %s\n",
- -ret, test_ch->name);
- goto exit_err;
- }
- tx_packet_count++;
- test_ch->tx_bytes += size;
- }
-
- read_avail = sdio_read_avail(test_ch->ch);
- TEST_DBG(TEST_MODULE_NAME ":channel %s, read_avail=%d\n",
- test_ch->name, read_avail);
- if (read_avail > 0) {
- size = min(packet_size, read_avail);
- pr_debug(TEST_MODULE_NAME ":rx size = %d.\n", size);
- ret = sdio_read(test_ch->ch, test_ch->buf, size);
- if (ret) {
- pr_info(TEST_MODULE_NAME ": sdio_read size %d "
- " err=%d"
- " for chan %s\n",
- size, -ret, test_ch->name);
- goto exit_err;
- }
- rx_packet_count++;
- test_ch->rx_bytes += size;
- }
-
- TEST_DBG(TEST_MODULE_NAME
- ":total rx bytes = %d , rx_packet#=%d"
- " for chan %s\n",
- test_ch->rx_bytes, rx_packet_count, test_ch->name);
- TEST_DBG(TEST_MODULE_NAME
- ":total tx bytes = %d , tx_packet#=%d"
- " for chan %s\n",
- test_ch->tx_bytes, tx_packet_count, test_ch->name);
-
- } /* while (tx_packet_count < max_packets ) */
-
- end_jiffy = get_jiffies_64(); /* read the current time */
-
- delta_jiffies = end_jiffy - start_jiffy;
- time_msec = jiffies_to_msecs(delta_jiffies);
-
- pr_info(TEST_MODULE_NAME ":total rx bytes = 0x%x , rx_packet#=%d for"
- " chan %s.\n",
- test_ch->rx_bytes, rx_packet_count, test_ch->name);
- pr_info(TEST_MODULE_NAME ":total tx bytes = 0x%x , tx_packet#=%d"
- " for chan %s.\n",
- test_ch->tx_bytes, tx_packet_count, test_ch->name);
-
- total_bytes = (test_ch->tx_bytes + test_ch->rx_bytes);
- pr_err(TEST_MODULE_NAME ":total bytes = %d, time msec = %d"
- " for chan %s\n",
- total_bytes , (int) time_msec, test_ch->name);
-
- if (!test_ch->random_packet_size) {
- if (time_msec) {
- throughput = (total_bytes / time_msec) * 8 / 1000;
- pr_err(TEST_MODULE_NAME ": %s - Performance = "
- "%d Mbit/sec for chan %s\n",
- __func__, throughput, test_ch->name);
- } else {
- pr_err(TEST_MODULE_NAME ": %s - time_msec = 0 Couldn't "
- "calculate performence for chan %s\n",
- __func__, test_ch->name);
- }
-
- }
-
-#ifdef CONFIG_DEBUG_FS
- switch (test_ch->ch_id) {
- case SDIO_DUN:
- test_ctx->debug.dun_throughput = throughput;
- break;
- case SDIO_RMNT:
- test_ctx->debug.rmnt_throughput = throughput;
- break;
- default:
- pr_err(TEST_MODULE_NAME "No debugfs for this channel "
- "throughput");
- }
-#endif
-
- pr_err(TEST_MODULE_NAME ": A2 PERFORMANCE TEST END for chan %s.\n",
- test_ch->name);
-
- pr_err(TEST_MODULE_NAME ": TEST PASS for chan %s\n", test_ch->name);
- test_ch->test_completed = 1;
- test_ch->test_result = TEST_PASSED;
- check_test_completion();
- return;
-
-exit_err:
- pr_err(TEST_MODULE_NAME ": TEST FAIL for chan %s\n", test_ch->name);
- test_ch->test_completed = 1;
- test_ch->test_result = TEST_FAILED;
- check_test_completion();
- return;
-}
-
-/**
- * rx_cleanup
- * This function reads all the messages sent by the modem until
- * the read_avail is 0 after 1 second of sleep.
- * The function returns the number of packets that was received.
- */
-static void rx_cleanup(struct test_channel *test_ch, int *rx_packet_count)
-{
- int read_avail = 0;
- int ret = 0;
- int counter = 0;
-
- if (!test_ch || !test_ch->ch) {
- pr_err(TEST_MODULE_NAME ":%s NULL channel\n",
- __func__);
- return;
- }
-
- read_avail = sdio_read_avail(test_ch->ch);
- TEST_DBG(TEST_MODULE_NAME ":channel %s, read_avail=%d\n",
- test_ch->name, read_avail);
-
- /* If no pending messages, wait to see if the modem sends data */
- if (read_avail == 0) {
- msleep(1000);
- read_avail = sdio_read_avail(test_ch->ch);
- }
-
- while ((read_avail > 0) && (counter < 10)) {
- TEST_DBG(TEST_MODULE_NAME ": read_avail=%d for ch %s\n",
- read_avail, test_ch->name);
-
- ret = sdio_read(test_ch->ch, test_ch->buf, read_avail);
- if (ret) {
- pr_info(TEST_MODULE_NAME ": sdio_read size %d "
- " err=%d for chan %s\n",
- read_avail, -ret, test_ch->name);
- break;
- }
- (*rx_packet_count)++;
- test_ch->rx_bytes += read_avail;
- read_avail = sdio_read_avail(test_ch->ch);
- if (read_avail == 0) {
- msleep(1000);
- counter++;
- read_avail = sdio_read_avail(test_ch->ch);
- }
- }
- pr_info(TEST_MODULE_NAME ": finished cleanup for ch %s, "
- "rx_packet_count=%d, total rx bytes=%d\n",
- test_ch->name, *rx_packet_count, test_ch->rx_bytes);
-}
-
-
-/**
- * A2 RTT Test
- * This function sends a packet and calculate the RTT time of
- * this packet.
- * The test also calculte Min, Max and Average RTT
- */
-static void a2_rtt_test(struct test_channel *test_ch)
-{
- int ret = 0 ;
- u32 read_avail = 0;
- u32 write_avail = 0;
- int tx_packet_count = 0;
- int rx_packet_count = 0;
- u16 *buf16 = NULL;
- int i;
- int max_packets = 0;
- u32 packet_size = 0;
- s64 start_time, end_time;
- int delta_usec = 0;
- int time_average = 0;
- int min_delta_usec = 0xFFFF;
- int max_delta_usec = 0;
- int total_time = 0;
- int expected_read_size = 0;
- int delay_ms = 0;
- int slow_rtt_counter = 0;
- int read_avail_so_far = 0;
-
- if (test_ch) {
- /*
- * Cleanup the pending RX data (such as loopback of the
- * config msg)
- */
- rx_cleanup(test_ch, &rx_packet_count);
- rx_packet_count = 0;
- } else {
- return;
- }
-
- max_packets = test_ch->config_msg.num_packets;
- packet_size = test_ch->packet_length;
- buf16 = (u16 *) test_ch->buf;
-
- for (i = 0; i < packet_size / 2; i++)
- buf16[i] = (u16) (i & 0xFFFF);
-
- pr_info(TEST_MODULE_NAME ": A2 RTT TEST START for chan %s\n",
- test_ch->name);
-
- switch (test_ch->ch_id) {
- case SDIO_RMNT:
- delay_ms = 100;
- break;
- case SDIO_CSVT:
- delay_ms = 0;
- break;
- default:
- pr_err(TEST_MODULE_NAME ": %s - ch_id invalid.\n",
- __func__);
- return;
- }
-
- while (tx_packet_count < max_packets) {
- if (test_ctx->exit_flag) {
- pr_info(TEST_MODULE_NAME ":Exit Test.\n");
- return;
- }
- start_time = 0;
- end_time = 0;
- read_avail_so_far = 0;
-
- if (delay_ms)
- msleep(delay_ms);
-
- /* wait for data ready event */
- write_avail = sdio_write_avail(test_ch->ch);
- TEST_DBG(TEST_MODULE_NAME ":ch %s: write_avail=%d\n",
- test_ch->name, write_avail);
- if (write_avail == 0) {
- wait_event(test_ch->wait_q,
- atomic_read(&test_ch->tx_notify_count));
- atomic_dec(&test_ch->tx_notify_count);
- }
-
- write_avail = sdio_write_avail(test_ch->ch);
- TEST_DBG(TEST_MODULE_NAME ":channel %s, write_avail=%d\n",
- test_ch->name, write_avail);
- if (write_avail > 0) {
- TEST_DBG(TEST_MODULE_NAME ":tx size = %d for chan %s\n",
- packet_size, test_ch->name);
- test_ch->buf[0] = tx_packet_count;
-
- start_time = ktime_to_us(ktime_get());
- ret = sdio_write(test_ch->ch, test_ch->buf,
- packet_size);
- if (ret) {
- pr_err(TEST_MODULE_NAME ":sdio_write err=%d"
- " for chan %s\n",
- -ret, test_ch->name);
- goto exit_err;
- }
- tx_packet_count++;
- test_ch->tx_bytes += packet_size;
- } else {
- pr_err(TEST_MODULE_NAME ": Invalid write_avail"
- " %d for chan %s\n",
- write_avail, test_ch->name);
- goto exit_err;
- }
-
- expected_read_size = packet_size + A2_HEADER_OVERHEAD;
-
- while (read_avail_so_far < expected_read_size) {
-
- read_avail = sdio_read_avail(test_ch->ch);
-
- if (!read_avail) {
- wait_event(test_ch->wait_q,
- atomic_read(&test_ch->
- rx_notify_count));
-
- atomic_dec(&test_ch->rx_notify_count);
- continue;
- }
-
- read_avail_so_far += read_avail;
-
- if (read_avail_so_far > expected_read_size) {
- pr_err(TEST_MODULE_NAME ": %s - Invalid "
- "read_avail(%d) read_avail_so_far(%d) "
- "can't be larger than "
- "expected_read_size(%d).",
- __func__,
- read_avail,
- read_avail_so_far,
- expected_read_size);
- goto exit_err;
- }
-
- /*
- * must read entire pending bytes, so later, we will
- * get a notification when more data arrives
- */
- ret = sdio_read(test_ch->ch, test_ch->buf,
- read_avail);
-
- if (ret) {
- pr_info(TEST_MODULE_NAME ": sdio_read size %d "
- " err=%d for chan %s\n",
- read_avail, -ret,
- test_ch->name);
- goto exit_err;
- }
- }
-
- end_time = ktime_to_us(ktime_get());
- rx_packet_count++;
- test_ch->rx_bytes += expected_read_size;
-
- delta_usec = (int)(end_time - start_time);
- total_time += delta_usec;
- if (delta_usec < min_delta_usec)
- min_delta_usec = delta_usec;
- if (delta_usec > max_delta_usec)
- max_delta_usec = delta_usec;
-
- /* checking the RTT per channel criteria */
- if (delta_usec > MAX_AVG_RTT_TIME_USEC) {
- pr_err(TEST_MODULE_NAME ": %s - "
- "msg # %d - rtt time (%d usec) is "
- "longer than %d usec\n",
- __func__,
- tx_packet_count,
- delta_usec,
- MAX_AVG_RTT_TIME_USEC);
- slow_rtt_counter++;
- }
-
- TEST_DBG(TEST_MODULE_NAME
- ":RTT time=%d for packet #%d for chan %s\n",
- delta_usec, tx_packet_count, test_ch->name);
- } /* while (tx_packet_count < max_packets ) */
-
- pr_info(TEST_MODULE_NAME ": %s - tx_packet_count = %d\n",
- __func__, tx_packet_count);
-
- pr_info(TEST_MODULE_NAME ": %s - total rx bytes = 0x%x, "
- "rx_packet# = %d for chan %s.\n",
- __func__, test_ch->rx_bytes, rx_packet_count, test_ch->name);
-
- pr_info(TEST_MODULE_NAME ": %s - total tx bytes = 0x%x, "
- "tx_packet# = %d for chan %s.\n",
- __func__, test_ch->tx_bytes, tx_packet_count, test_ch->name);
-
- pr_info(TEST_MODULE_NAME ": %s - slow_rtt_counter = %d for "
- "chan %s.\n",
- __func__, slow_rtt_counter, test_ch->name);
-
- if (tx_packet_count) {
- time_average = total_time / tx_packet_count;
- pr_info(TEST_MODULE_NAME ":Average RTT time = %d for chan %s\n",
- time_average, test_ch->name);
- } else {
- pr_err(TEST_MODULE_NAME ": %s - tx_packet_count=0. couldn't "
- "calculate average rtt time", __func__);
- }
-
- pr_info(TEST_MODULE_NAME ":MIN RTT time = %d for chan %s\n",
- min_delta_usec, test_ch->name);
- pr_info(TEST_MODULE_NAME ":MAX RTT time = %d for chan %s\n",
- max_delta_usec, test_ch->name);
-
- pr_info(TEST_MODULE_NAME ": A2 RTT TEST END for chan %s.\n",
- test_ch->name);
-
- if (ret)
- goto exit_err;
-
- if (time_average == 0 || time_average > MAX_AVG_RTT_TIME_USEC) {
- pr_err(TEST_MODULE_NAME ": %s - average_time = %d. Invalid "
- "value",
- __func__, time_average);
- goto exit_err;
-
- }
-
- pr_info(TEST_MODULE_NAME ": TEST PASS for chan %s\n", test_ch->name);
- test_ch->test_completed = 1;
- test_ch->test_result = TEST_PASSED;
- check_test_completion();
- return;
-
-exit_err:
- pr_err(TEST_MODULE_NAME ": TEST FAIL for chan %s\n", test_ch->name);
- test_ch->test_completed = 1;
- test_ch->test_result = TEST_FAILED;
- check_test_completion();
- return;
-}
-
-/**
- * Process Rx Data - Helper for A2 Validation Test
- * @test_ch(in/out) : Test channel that contains Rx data buffer to process.
- *
- * @rx_unprocessed_bytes(in) : Number of bytes to process in the buffer.
- *
- * @rx_process_packet_state(in/out) :
- * Current processing state (used to identify what to process
- * next in a partial packet)
- *
- * @rx_packet_size(in/out) :
- * Number of bytes remaining in the packet to be processed.
- *
- * @rx_packet_count(in/out) :
- * Number of packets processed.
- */
-static int process_rx_data(struct test_channel *test_ch,
- u32 rx_unprocessed_bytes,
- int *rx_process_packet_state,
- u16 *rx_packet_size,
- int *rx_packet_count)
-{
- u8 *buf = (u8 *)test_ch->buf;
- int eop = 0;
- int i = 0;
- int ret = 0;
- u32 *ptr = 0;
- u16 size = 0;
-
- /* process rx data */
- while (rx_unprocessed_bytes) {
- TEST_DBG(TEST_MODULE_NAME ": unprocessed bytes : %u\n",
- rx_unprocessed_bytes);
-
- switch (*rx_process_packet_state) {
- case RX_PROCESS_PACKET_INIT:
- /* process the A2 header */
- TEST_DBG(TEST_MODULE_NAME ": "
- "RX_PROCESS_PACKET_INIT\n");
- *rx_process_packet_state = RX_PROCESS_PACKET_INIT;
- if (rx_unprocessed_bytes < 4)
- break;
-
- i += 4;
- rx_unprocessed_bytes -= 4;
-
- case RX_PROCESS_A2_HEADER:
- /* process the rest of A2 header */
- TEST_DBG(TEST_MODULE_NAME ": RX_PROCESS_A2_HEADER\n");
- *rx_process_packet_state = RX_PROCESS_A2_HEADER;
- if (rx_unprocessed_bytes < 4)
- break;
-
- ptr = (u32 *)&buf[i];
- /*
- * upper 2 bytes of the last 4 bytes of A2 header
- * contains the size of the packet
- */
- *rx_packet_size = *ptr >> 0x10;
-
- i += 4;
- rx_unprocessed_bytes -= 4;
-
- case RX_PROCESS_PACKET_DATA:
- /* process the2_2_ packet data */
- TEST_DBG(TEST_MODULE_NAME ": RX_PROCESS_PACKET_DATA "
- "- packet size - %u\n", *rx_packet_size);
- *rx_process_packet_state = RX_PROCESS_PACKET_DATA;
-
- size = *rx_packet_size;
- if (*rx_packet_size <= rx_unprocessed_bytes) {
- eop = *rx_packet_size;
- *rx_packet_size = 0;
- } else {
- eop = rx_unprocessed_bytes;
- *rx_packet_size = *rx_packet_size -
- rx_unprocessed_bytes;
- }
-
- /* no more bytes available to process */
- if (!eop)
- break;
- /*
- * end of packet is starting from
- * the current position
- */
- eop = eop + i;
- TEST_DBG(TEST_MODULE_NAME ": size - %u, "
- "packet size - %u eop - %d\n",
- size, *rx_packet_size, eop);
-
- /* validate the data */
- for (; i < eop; i++) {
- if (buf[i] != (test_ch->rx_bytes % 256)) {
- pr_err(TEST_MODULE_NAME ": "
- "Corrupt data. buf:%u, "
- "data:%u\n", buf[i],
- test_ch->rx_bytes % 256);
- ret = -EINVAL;
- goto err;
- }
- rx_unprocessed_bytes--;
- test_ch->rx_bytes++;
- }
-
- /* have more data to be processed */
- if (*rx_packet_size)
- break;
-
- /*
- * A2 sends data in 4 byte alignment,
- * skip the padding
- */
- if (size % 4) {
- i += 4 - (size % 4);
- rx_unprocessed_bytes -= 4 - (size % 4);
- }
- *rx_packet_count = *rx_packet_count + 1;
-
- /* re init the state to process new packet */
- *rx_process_packet_state = RX_PROCESS_PACKET_INIT;
- break;
- default:
- pr_err(TEST_MODULE_NAME ": Invalid case: %d\n",
- *rx_process_packet_state);
- ret = -EINVAL;
- goto err;
- }
- TEST_DBG(TEST_MODULE_NAME ": Continue processing "
- "if more data is available\n");
- }
-
-err:
- return ret;
-}
-
-/**
- * A2 Validation Test
- * Send packets and validate the returned packets.
- * Transmit one packet at a time, while process multiple rx
- * packets in a single transaction.
- * A transaction is of size min(random number, write_avail).
- * A packet consists of a min of 1 byte to channel supported max.
- */
-static void a2_validation_test(struct test_channel *test_ch)
-{
- int ret = 0 ;
- u32 read_avail = 0;
- u32 write_avail = 0;
- int tx_packet_count = 0;
- int rx_packet_count = 0;
- int initial_rx_packet_count = 0;
- u32 size = 0;
- u8 *buf8 = (u8 *)test_ch->buf;
- int i = 0;
- int max_packets = test_ch->config_msg.num_packets;
- u16 tx_packet_size = 0;
- u16 rx_packet_size = 0;
- u32 random_num = 0;
- int rx_process_packet_state = RX_PROCESS_PACKET_INIT;
-
- pr_info(TEST_MODULE_NAME ": A2 VALIDATION TEST START for chan %s\n",
- test_ch->name);
-
- /* Wait for the initial rx messages before starting the test. */
- rx_cleanup(test_ch, &initial_rx_packet_count);
-
- test_ch->tx_bytes = 0;
- test_ch->rx_bytes = 0;
-
- /* Continue till we have transmitted and received all packets */
- while ((tx_packet_count < max_packets) ||
- (rx_packet_count < max_packets)) {
-
- if (test_ctx->exit_flag) {
- pr_info(TEST_MODULE_NAME ":Exit Test.\n");
- return;
- }
-
- random_num = get_random_int();
- size = (random_num % test_ch->packet_length) + 1;
- TEST_DBG(TEST_MODULE_NAME ": Random tx packet size =%u", size);
-
- /*
- * wait for data ready event
- * use a func to avoid compiler optimizations
- */
- write_avail = sdio_write_avail(test_ch->ch);
- read_avail = sdio_read_avail(test_ch->ch);
- TEST_DBG(TEST_MODULE_NAME ": write_avail=%d, "
- "read_avail=%d for chan %s\n",
- write_avail, read_avail, test_ch->name);
-
- if ((write_avail == 0) && (read_avail == 0)) {
- wait_event(test_ch->wait_q,
- atomic_read(&test_ch->any_notify_count));
- atomic_set(&test_ch->any_notify_count, 0);
- }
-
- /* Transmit data */
- write_avail = sdio_write_avail(test_ch->ch);
- if ((tx_packet_count < max_packets) && (write_avail > 0)) {
- tx_packet_size = min(size, write_avail) ;
- TEST_DBG(TEST_MODULE_NAME ": tx size = %u, "
- "write_avail = %u tx_packet# = %d\n",
- tx_packet_size, write_avail,
- tx_packet_count);
- memset(test_ch->buf, 0, test_ch->buf_size);
- /* populate the buffer */
- for (i = 0; i < tx_packet_size; i++) {
- buf8[i] = test_ch->tx_bytes % 256;
- test_ch->tx_bytes++;
- }
-
- ret = sdio_write(test_ch->ch, test_ch->buf,
- tx_packet_size);
- if (ret) {
- pr_err(TEST_MODULE_NAME ":sdio_write err=%d"
- " for chan %s\n",
- -ret, test_ch->name);
- goto exit_err;
- }
- tx_packet_count++;
- }
-
- /* Receive data */
- read_avail = sdio_read_avail(test_ch->ch);
- if (read_avail > 0) {
- TEST_DBG(TEST_MODULE_NAME ": rx size = %u, "
- "rx_packet#=%d.\n",
- read_avail, rx_packet_count);
- memset(test_ch->buf, 0, test_ch->buf_size);
-
- ret = sdio_read(test_ch->ch, test_ch->buf,
- read_avail);
- if (ret) {
- pr_err(TEST_MODULE_NAME ": sdio_read "
- "size %d err=%d for chan %s\n",
- size, -ret, test_ch->name);
- goto exit_err;
- }
-
- /* Process data */
- ret = process_rx_data(test_ch, read_avail,
- &rx_process_packet_state,
- &rx_packet_size,
- &rx_packet_count);
-
- if (ret != 0)
- goto exit_err;
- }
- TEST_DBG(TEST_MODULE_NAME ": Continue loop ...\n");
- }
-
- if (test_ch->tx_bytes != test_ch->rx_bytes) {
- pr_err(TEST_MODULE_NAME ": Total number of bytes "
- "transmitted (%u) does not match the total "
- "number of bytes received (%u).", test_ch->tx_bytes,
- test_ch->rx_bytes);
- goto exit_err;
- }
-
- pr_info(TEST_MODULE_NAME ": A2 VALIDATION TEST END for chan %s.\n",
- test_ch->name);
-
- pr_info(TEST_MODULE_NAME ": TEST PASS for chan %s\n", test_ch->name);
- test_ch->test_completed = 1;
- test_ch->test_result = TEST_PASSED;
- check_test_completion();
- return;
-
-exit_err:
- pr_info(TEST_MODULE_NAME ": TEST FAIL for chan %s\n", test_ch->name);
- test_ch->test_completed = 1;
- test_ch->test_result = TEST_FAILED;
- check_test_completion();
- return;
-}
-
-/**
- * sender No loopback Test
- */
-static void sender_no_loopback_test(struct test_channel *test_ch)
-{
- int ret = 0 ;
- u32 write_avail = 0;
- int packet_count = 0;
- int size = 512;
- u16 *buf16 = (u16 *) test_ch->buf;
- int i;
- int max_packet_count = 10000;
- unsigned int random_num = 0;
-
- max_packet_count = test_ch->config_msg.num_packets;
-
- for (i = 0 ; i < size / 2 ; i++)
- buf16[i] = (u16) (i & 0xFFFF);
-
- pr_info(TEST_MODULE_NAME
- ":SENDER NO LP TEST START for chan %s\n", test_ch->name);
-
- while (packet_count < max_packet_count) {
-
- if (test_ctx->exit_flag) {
- pr_info(TEST_MODULE_NAME ":Exit Test.\n");
- return;
- }
-
- random_num = get_random_int();
- size = (random_num % test_ch->packet_length) + 1;
-
- TEST_DBG(TEST_MODULE_NAME ":SENDER WAIT FOR EVENT "
- "for chan %s\n",
- test_ch->name);
-
- /* wait for data ready event */
- write_avail = sdio_write_avail(test_ch->ch);
- TEST_DBG(TEST_MODULE_NAME ":write_avail=%d\n", write_avail);
- if (write_avail < size) {
- wait_event(test_ch->wait_q,
- atomic_read(&test_ch->tx_notify_count));
- atomic_dec(&test_ch->tx_notify_count);
- }
-
- write_avail = sdio_write_avail(test_ch->ch);
- TEST_DBG(TEST_MODULE_NAME ":write_avail=%d\n", write_avail);
- if (write_avail < size) {
- pr_info(TEST_MODULE_NAME ":not enough write avail.\n");
- continue;
- }
-
- test_ch->buf[0] = packet_count;
-
- ret = sdio_write(test_ch->ch, test_ch->buf, size);
- if (ret) {
- pr_info(TEST_MODULE_NAME ":sender sdio_write err=%d.\n",
- -ret);
- goto exit_err;
- }
-
- test_ch->tx_bytes += size;
- packet_count++;
-
- TEST_DBG(TEST_MODULE_NAME
- ":sender total tx bytes = 0x%x , packet#=%d, size=%d"
- " for chan %s\n",
- test_ch->tx_bytes, packet_count, size, test_ch->name);
-
- } /* end of while */
-
- pr_info(TEST_MODULE_NAME
- ":SENDER TEST END: total tx bytes = 0x%x, "
- " for chan %s\n",
- test_ch->tx_bytes, test_ch->name);
-
- test_ch->modem_result_per_chan = wait_for_result_msg(test_ch);
-
- if (test_ch->modem_result_per_chan) {
- pr_info(TEST_MODULE_NAME ": TEST PASS for chan %s.\n",
- test_ch->name);
- test_ch->test_result = TEST_PASSED;
- } else {
- pr_info(TEST_MODULE_NAME ": TEST FAILURE for chan %s.\n",
- test_ch->name);
- test_ch->test_result = TEST_FAILED;
- }
- test_ch->test_completed = 1;
- check_test_completion();
- return;
-
-exit_err:
- pr_info(TEST_MODULE_NAME ": TEST FAIL for chan %s.\n",
- test_ch->name);
- test_ch->test_completed = 1;
- test_ch->test_result = TEST_FAILED;
- check_test_completion();
- return;
-}
-
-
-/**
- * Modem reset Test
- * The test verifies that it finished sending all the packets
- * while there might be modem reset in the middle
- */
-static void modem_reset_test(struct test_channel *test_ch)
-{
- int ret = 0 ;
- u32 read_avail = 0;
- u32 write_avail = 0;
- int tx_packet_count = 0;
- int rx_packet_count = 0;
- int size = 0;
- u16 *buf16 = (u16 *) test_ch->buf;
- int i;
- int max_packets = 10000;
- u32 packet_size = test_ch->buf_size;
- int is_err = 0;
-
- max_packets = test_ch->config_msg.num_packets;
- packet_size = test_ch->packet_length;
-
- for (i = 0; i < packet_size / 2; i++)
- buf16[i] = (u16) (i & 0xFFFF);
-
- pr_info(TEST_MODULE_NAME ": Modem Reset TEST START for chan %s\n",
- test_ch->name);
-
- while (tx_packet_count < max_packets) {
-
- if (test_ctx->exit_flag) {
- pr_info(TEST_MODULE_NAME ":Exit Test.\n");
- return;
- }
-
- if (test_ch->card_removed) {
- pr_info(TEST_MODULE_NAME ": card removal was detected "
- "for chan %s, tx_total=0x%x\n",
- test_ch->name, test_ch->tx_bytes);
- wait_event(test_ch->wait_q,
- atomic_read(&test_ch->card_detected_event));
- atomic_set(&test_ch->card_detected_event, 0);
- pr_info(TEST_MODULE_NAME ": card_detected_event "
- "for chan %s\n", test_ch->name);
- if (test_ch->card_removed)
- continue;
- is_err = 0;
- /* Need to wait for the modem to be ready */
- msleep(5000);
- pr_info(TEST_MODULE_NAME ": sending the config message "
- "for chan %s\n", test_ch->name);
- send_config_msg(test_ch);
- }
-
- /* wait for data ready event */
- /* use a func to avoid compiler optimizations */
- write_avail = sdio_write_avail(test_ch->ch);
- read_avail = sdio_read_avail(test_ch->ch);
- TEST_DBG(TEST_MODULE_NAME ":channel %s, write_avail=%d, "
- "read_avail=%d for chan %s\n",
- test_ch->name, write_avail, read_avail,
- test_ch->name);
- if ((write_avail == 0) && (read_avail == 0)) {
- wait_event(test_ch->wait_q,
- atomic_read(&test_ch->any_notify_count));
- atomic_set(&test_ch->any_notify_count, 0);
- }
- if (atomic_read(&test_ch->card_detected_event)) {
- atomic_set(&test_ch->card_detected_event, 0);
- pr_info(TEST_MODULE_NAME ": card_detected_event "
- "for chan %s, tx_total=0x%x\n",
- test_ch->name, test_ch->tx_bytes);
- if (test_ch->card_removed)
- continue;
- /* Need to wait for the modem to be ready */
- msleep(5000);
- is_err = 0;
- pr_info(TEST_MODULE_NAME ": sending the config message "
- "for chan %s\n", test_ch->name);
- send_config_msg(test_ch);
- }
-
- write_avail = sdio_write_avail(test_ch->ch);
- TEST_DBG(TEST_MODULE_NAME ":channel %s, write_avail=%d\n",
- test_ch->name, write_avail);
- if (write_avail > 0) {
- size = min(packet_size, write_avail) ;
- pr_debug(TEST_MODULE_NAME ":tx size = %d for chan %s\n",
- size, test_ch->name);
- test_ch->buf[0] = tx_packet_count;
- test_ch->buf[(size/4)-1] = tx_packet_count;
-
- TEST_DBG(TEST_MODULE_NAME ":channel %s, sdio_write, "
- "size=%d\n", test_ch->name, size);
- if (is_err) {
- msleep(100);
- continue;
- }
- ret = sdio_write(test_ch->ch, test_ch->buf, size);
- if (ret) {
- pr_info(TEST_MODULE_NAME ":sdio_write err=%d"
- " for chan %s\n",
- -ret, test_ch->name);
- is_err = 1;
- msleep(20);
- continue;
- }
- tx_packet_count++;
- test_ch->tx_bytes += size;
- test_ch->config_msg.num_packets--;
- }
-
- read_avail = sdio_read_avail(test_ch->ch);
- TEST_DBG(TEST_MODULE_NAME ":channel %s, read_avail=%d\n",
- test_ch->name, read_avail);
- if (read_avail > 0) {
- size = min(packet_size, read_avail);
- pr_debug(TEST_MODULE_NAME ":rx size = %d.\n", size);
- TEST_DBG(TEST_MODULE_NAME ":channel %s, sdio_read, "
- "size=%d\n", test_ch->name, size);
- if (is_err) {
- msleep(100);
- continue;
- }
- ret = sdio_read(test_ch->ch, test_ch->buf, size);
- if (ret) {
- pr_info(TEST_MODULE_NAME ": sdio_read size %d "
- " err=%d"
- " for chan %s\n",
- size, -ret, test_ch->name);
- is_err = 1;
- msleep(20);
- continue;
- }
- rx_packet_count++;
- test_ch->rx_bytes += size;
- }
-
- TEST_DBG(TEST_MODULE_NAME
- ":total rx bytes = %d , rx_packet#=%d"
- " for chan %s\n",
- test_ch->rx_bytes, rx_packet_count, test_ch->name);
- TEST_DBG(TEST_MODULE_NAME
- ":total tx bytes = %d , tx_packet#=%d"
- " for chan %s\n",
- test_ch->tx_bytes, tx_packet_count, test_ch->name);
-
- udelay(500);
-
- } /* while (tx_packet_count < max_packets ) */
-
- pr_info(TEST_MODULE_NAME ":total rx bytes = 0x%x , rx_packet#=%d for"
- " chan %s.\n",
- test_ch->rx_bytes, rx_packet_count, test_ch->name);
- pr_info(TEST_MODULE_NAME ":total tx bytes = 0x%x , tx_packet#=%d"
- " for chan %s.\n",
- test_ch->tx_bytes, tx_packet_count, test_ch->name);
-
- pr_err(TEST_MODULE_NAME ": Modem Reset TEST END for chan %s.\n",
- test_ch->name);
-
- pr_err(TEST_MODULE_NAME ": TEST PASS for chan %s\n", test_ch->name);
- test_ch->test_completed = 1;
- test_ch->test_result = TEST_PASSED;
- check_test_completion();
- return;
-}
-
-/**
- * Worker thread to handle the tests types
- */
-static void worker(struct work_struct *work)
-{
- struct test_channel *test_ch = NULL;
- struct test_work *test_work = container_of(work,
- struct test_work,
- work);
- int test_type = 0;
-
- test_ch = test_work->test_ch;
-
- if (test_ch == NULL) {
- pr_err(TEST_MODULE_NAME ":NULL test_ch\n");
- return;
- }
-
- test_type = test_ch->test_type;
-
- switch (test_type) {
- case SDIO_TEST_LOOPBACK_HOST:
- loopback_test(test_ch);
- break;
- case SDIO_TEST_LOOPBACK_CLIENT:
- sender_test(test_ch);
- break;
- case SDIO_TEST_PERF:
- a2_performance_test(test_ch);
- break;
- case SDIO_TEST_LPM_CLIENT_WAKER:
- lpm_test(test_ch);
- break;
- case SDIO_TEST_LPM_HOST_WAKER:
- lpm_test_host_waker(test_ch);
- break;
- case SDIO_TEST_HOST_SENDER_NO_LP:
- sender_no_loopback_test(test_ch);
- break;
- case SDIO_TEST_LPM_RANDOM:
- lpm_continuous_rand_test(test_ch);
- break;
- case SDIO_TEST_RTT:
- a2_rtt_test(test_ch);
- break;
- case SDIO_TEST_CLOSE_CHANNEL:
- if (test_ch->ch_id != SDIO_SMEM)
- open_close_test(test_ch);
- break;
- case SDIO_TEST_MODEM_RESET:
- modem_reset_test(test_ch);
- break;
- case SDIO_TEST_A2_VALIDATION:
- a2_validation_test(test_ch);
- break;
- default:
- pr_err(TEST_MODULE_NAME ":Bad Test type = %d.\n",
- (int) test_type);
- }
-}
-
-
-/**
- * Notification Callback
- *
- * Notify the worker
- *
- */
-static void notify(void *priv, unsigned channel_event)
-{
- struct test_channel *test_ch = (struct test_channel *) priv;
-
- pr_debug(TEST_MODULE_NAME ": %s - notify event=%d.\n",
- __func__, channel_event);
-
- if (test_ch->ch == NULL) {
- pr_info(TEST_MODULE_NAME ": %s - notify before ch ready.\n",
- __func__);
- return;
- }
-
- switch (channel_event) {
- case SDIO_EVENT_DATA_READ_AVAIL:
- atomic_inc(&test_ch->rx_notify_count);
- atomic_set(&test_ch->any_notify_count, 1);
- TEST_DBG(TEST_MODULE_NAME ": %s - SDIO_EVENT_DATA_READ_AVAIL, "
- "any_notify_count=%d, rx_notify_count=%d\n",
- __func__,
- atomic_read(&test_ch->any_notify_count),
- atomic_read(&test_ch->rx_notify_count));
- /*
- * when there is pending data on a channel we would like to
- * turn on the bit mask that implies that there is pending
- * data for that channel on that deivce
- */
- if (test_ch->test_device != NULL &&
- test_ch->test_type == SDIO_TEST_LPM_RANDOM) {
- spin_lock_irqsave(&test_ch->test_device->lpm_array_lock,
- test_ch->test_device->
- lpm_array_lock_flags);
- test_ch->test_device->read_avail_mask |=
- test_ch->channel_mask_id;
- test_ch->notify_counter_per_chan++;
-
- lpm_test_update_entry(test_ch, LPM_NOTIFY, "NOTIFY", 0);
- spin_unlock_irqrestore(&test_ch->test_device->
- lpm_array_lock,
- test_ch->test_device->
- lpm_array_lock_flags);
- }
- break;
-
- case SDIO_EVENT_DATA_WRITE_AVAIL:
- atomic_inc(&test_ch->tx_notify_count);
- atomic_set(&test_ch->any_notify_count, 1);
- TEST_DBG(TEST_MODULE_NAME ": %s - SDIO_EVENT_DATA_WRITE_AVAIL, "
- "any_notify_count=%d, tx_notify_count=%d\n",
- __func__,
- atomic_read(&test_ch->any_notify_count),
- atomic_read(&test_ch->tx_notify_count));
- break;
-
- default:
- BUG();
- }
- wake_up(&test_ch->wait_q);
-
-}
-
-#ifdef CONFIG_MSM_SDIO_SMEM
-static int sdio_smem_test_cb(int event)
-{
- struct test_channel *tch = test_ctx->test_ch_arr[SDIO_SMEM];
- int i;
- int *smem_buf = (int *)test_ctx->smem_buf;
- uint32_t val = 0;
- int ret = 0;
-
- pr_debug(TEST_MODULE_NAME ":%s: Received event %d\n", __func__, event);
-
- if (!tch) {
- pr_err(TEST_MODULE_NAME ": %s NULL tch\n", __func__);
- return -EINVAL;
- }
-
- switch (event) {
- case SDIO_SMEM_EVENT_READ_DONE:
- tch->rx_bytes += SMEM_MAX_XFER_SIZE;
- for (i = 0; i < SMEM_MAX_XFER_SIZE;) {
- val = (int)*smem_buf;
- if ((val != test_ctx->smem_counter) && tch->is_used) {
- pr_err(TEST_MODULE_NAME ":%s: Invalid value %d "
- "expected %d in smem arr",
- __func__, val, test_ctx->smem_counter);
- pr_err(TEST_MODULE_NAME ":SMEM test FAILED\n");
- tch->test_completed = 1;
- tch->test_result = TEST_FAILED;
- check_test_completion();
- ret = -EINVAL;
- goto exit;
- }
- i += 4;
- smem_buf++;
- test_ctx->smem_counter++;
- }
- if (tch->rx_bytes >= 40000000) {
- if ((!tch->test_completed) && tch->is_used) {
- pr_info(TEST_MODULE_NAME ":SMEM test PASSED\n");
- tch->test_completed = 1;
- tch->test_result = TEST_PASSED;
- check_test_completion();
- }
- }
- break;
- case SDIO_SMEM_EVENT_READ_ERR:
- if (tch->is_used) {
- pr_err(TEST_MODULE_NAME ":Read overflow, "
- "SMEM test FAILED\n");
- tch->test_completed = 1;
- tch->test_result = TEST_FAILED;
- ret = -EIO;
- }
- break;
- default:
- if (tch->is_used) {
- pr_err(TEST_MODULE_NAME ":Unhandled event %d\n", event);
- ret = -EINVAL;
- }
- break;
- }
-exit:
- return ret;
-}
-
-static int sdio_smem_open(struct sdio_smem_client *sdio_smem)
-{
- int ret = 0;
-
- if (!sdio_smem) {
- pr_info(TEST_MODULE_NAME "%s: NULL sdio_smem_client\n",
- __func__);
- return -EINVAL;
- }
-
- if (test_ctx->test_ch_arr[SDIO_SMEM]->ch_ready) {
- pr_info(TEST_MODULE_NAME "%s: SDIO_SMEM channel is already opened\n",
- __func__);
- return 0;
- }
-
- test_ctx->test_ch_arr[SDIO_SMEM]->ch_ready = 1;
- sdio_smem->buf = test_ctx->smem_buf;
- sdio_smem->size = SMEM_MAX_XFER_SIZE;
- sdio_smem->cb_func = sdio_smem_test_cb;
- ret = sdio_smem_register_client();
- if (ret)
- pr_info(TEST_MODULE_NAME "%s: Error (%d) registering sdio_smem "
- "test client\n",
- __func__, ret);
-
- return ret;
-}
-
-static int sdio_smem_test_probe(struct platform_device *pdev)
-{
- test_ctx->sdio_smem = container_of(pdev, struct sdio_smem_client,
- plat_dev);
-
- return sdio_smem_open(test_ctx->sdio_smem);
-}
-
-static struct platform_driver sdio_smem_client_drv = {
- .probe = sdio_smem_test_probe,
- .driver = {
- .name = "SDIO_SMEM_CLIENT",
- .owner = THIS_MODULE,
- },
-};
-#endif
-
-static void sdio_test_lpm_timeout_handler(unsigned long data)
-{
- struct test_channel *tch = (struct test_channel *)data;
-
- pr_info(TEST_MODULE_NAME ": %s - LPM TEST TIMEOUT Expired after "
- "%d ms\n", __func__, tch->timeout_ms);
- tch->test_completed = 1;
- pr_info(TEST_MODULE_NAME ": %s - tch->test_result = TEST_FAILED\n",
- __func__);
- tch->test_completed = 1;
- tch->test_result = TEST_FAILED;
- check_test_completion();
- return;
-}
-
-static void sdio_test_lpm_timer_handler(unsigned long data)
-{
- struct test_channel *tch = (struct test_channel *)data;
-
- pr_info(TEST_MODULE_NAME ": %s - LPM TEST Timer Expired after "
- "%d ms\n", __func__, tch->timer_interval_ms);
-
- if (!tch) {
- pr_err(TEST_MODULE_NAME ": %s - LPM TEST FAILED. "
- "tch is NULL\n", __func__);
- return;
- }
-
- if (!tch->ch) {
- pr_err(TEST_MODULE_NAME ": %s - LPM TEST FAILED. tch->ch "
- "is NULL\n", __func__);
- tch->test_result = TEST_FAILED;
- return;
- }
-
- /* Verfiy that we voted for sleep */
- if (tch->is_ok_to_sleep) {
- tch->test_result = TEST_PASSED;
- pr_info(TEST_MODULE_NAME ": %s - 8K voted for sleep\n",
- __func__);
- } else {
- tch->test_result = TEST_FAILED;
- pr_info(TEST_MODULE_NAME ": %s - 8K voted against sleep\n",
- __func__);
-
- }
-
- sdio_al_unregister_lpm_cb(tch->sdio_al_device);
-
- if (tch->test_type == SDIO_TEST_LPM_HOST_WAKER) {
- atomic_set(&tch->wakeup_client, 1);
- wake_up(&tch->wait_q);
- }
-}
-
-int sdio_test_wakeup_callback(void *device_handle, int is_vote_for_sleep)
-{
- int i = 0;
-
- TEST_DBG(TEST_MODULE_NAME ": %s is_vote_for_sleep=%d!!!",
- __func__, is_vote_for_sleep);
-
- for (i = 0; i < SDIO_MAX_CHANNELS; i++) {
- struct test_channel *tch = test_ctx->test_ch_arr[i];
-
- if ((!tch) || (!tch->is_used) || (!tch->ch_ready))
- continue;
- if (tch->sdio_al_device == device_handle) {
- tch->is_ok_to_sleep = is_vote_for_sleep;
-
- if (tch->test_type == SDIO_TEST_LPM_RANDOM) {
- spin_lock_irqsave(&tch->test_device->
- lpm_array_lock,
- tch->test_device->
- lpm_array_lock_flags);
- if (is_vote_for_sleep == 1)
- lpm_test_update_entry(tch,
- LPM_SLEEP,
- "SLEEP ", 0);
- else
- lpm_test_update_entry(tch,
- LPM_WAKEUP,
- "WAKEUP", 0);
-
- spin_unlock_irqrestore(&tch->test_device->
- lpm_array_lock,
- tch->test_device->
- lpm_array_lock_flags);
- break;
- }
- }
- }
-
- return 0;
-}
-
-static int sdio_test_find_dev(struct test_channel *tch)
-{
- int j;
- int null_index = -1;
-
- for (j = 0 ; j < MAX_NUM_OF_SDIO_DEVICES; ++j) {
-
- struct sdio_test_device *test_dev =
- &test_ctx->test_dev_arr[j];
-
- if (test_dev->sdio_al_device == NULL) {
- if (null_index == -1)
- null_index = j;
- continue;
- }
-
- if (test_dev->sdio_al_device ==
- tch->ch->sdio_al_dev) {
- test_dev->open_channels_counter_to_recv++;
- test_dev->open_channels_counter_to_send++;
- tch->test_device = test_dev;
- /* setting mask id for pending data for
- this channel */
- tch->channel_mask_id = test_dev->next_mask_id;
- test_dev->next_mask_id *= 2;
- pr_info(TEST_MODULE_NAME ": %s - channel %s "
- "got read_mask_id = 0x%x. device "
- "next_mask_id=0x%x",
- __func__, tch->name, tch->channel_mask_id,
- test_dev->next_mask_id);
- break;
- }
- }
-
- /*
- * happens ones a new device is "discovered" while testing. i.e
- * if testing a few channels, a new deivce will be "discovered" once
- * the first channel of a device is being tested
- */
- if (j == MAX_NUM_OF_SDIO_DEVICES) {
-
- struct sdio_test_device *test_dev =
- &test_ctx->
- test_dev_arr[null_index];
- test_dev->sdio_al_device =
- tch->ch->sdio_al_dev;
-
- test_ctx->number_of_active_devices++;
- test_ctx->max_number_of_devices++;
- test_dev->open_channels_counter_to_recv++;
- test_dev->open_channels_counter_to_send++;
- test_dev->next_avail_entry_in_array = 0;
- tch->test_device = test_dev;
- tch->test_device->array_size =
- LPM_ARRAY_SIZE;
- test_dev->modem_result_per_dev = 1;
- tch->modem_result_per_chan = 0;
- test_dev->next_avail_entry_in_array = 0;
-
- spin_lock_init(&test_dev->
- lpm_array_lock);
-
- if (tch->test_type == SDIO_TEST_LPM_RANDOM) {
- pr_err(MODULE_NAME ": %s - "
- "Allocating Msg Array for "
- "Maximum open channels for device (%d) "
- "Channels. Array has %d entries",
- __func__,
- LPM_MAX_OPEN_CHAN_PER_DEV,
- test_dev->array_size);
-
- test_dev->lpm_arr =
- kzalloc(sizeof(
- struct lpm_entry_type) *
- tch->
- test_device->array_size,
- GFP_KERNEL);
-
- if (!test_dev->lpm_arr) {
- pr_err(MODULE_NAME ": %s - "
- "lpm_arr is NULL",
- __func__);
- return -ENOMEM;
- }
- }
-
- /*
- * in new device, initialize next_mask_id, and setting
- * mask_id to the channel
- */
- test_dev->next_mask_id = 0x1;
- tch->channel_mask_id = test_dev->next_mask_id;
- test_dev->next_mask_id *= 2;
- pr_info(TEST_MODULE_NAME ": %s - channel %s got "
- "read_mask_id = 0x%x. device next_mask_id=0x%x",
- __func__,
- tch->name,
- tch->channel_mask_id,
- test_dev->next_mask_id);
- }
-
- return 0;
-}
-
-static void check_test_result(void)
-{
- int result = 1;
- int i = 0;
-
- test_ctx->max_number_of_devices = 0;
-
- pr_info(TEST_MODULE_NAME ": %s - Woke Up\n", __func__);
-
- for (i = 0; i < SDIO_MAX_CHANNELS; i++) {
- struct test_channel *tch = test_ctx->test_ch_arr[i];
-
- if ((!tch) || (!tch->is_used) || (!tch->ch_ready))
- continue;
-
- if (tch->test_type == SDIO_TEST_LPM_RANDOM)
- result &= tch->test_device->final_result_per_dev;
- else
- if (tch->test_result == TEST_FAILED) {
- pr_info(TEST_MODULE_NAME ": %s - "
- "Test FAILED\n", __func__);
- test_ctx->test_result = TEST_FAILED;
- pr_err(TEST_MODULE_NAME ": %s - "
- "test_result %d",
- __func__, test_ctx->test_result);
- return;
- }
- }
-
- if (result == 0) {
- pr_info(TEST_MODULE_NAME ": %s - Test FAILED\n", __func__);
- test_ctx->test_result = TEST_FAILED;
- pr_err(TEST_MODULE_NAME ": %s - "
- "test_result %d",
- __func__, test_ctx->test_result);
- return;
- }
-
- pr_info(TEST_MODULE_NAME ": %s - Test PASSED", __func__);
- test_ctx->test_result = TEST_PASSED;
- pr_err(TEST_MODULE_NAME ": %s - "
- "test_result %d",
- __func__, test_ctx->test_result);
- return;
-}
-
-/**
- * Test Main
- */
-static int test_start(void)
-{
- int ret = -ENOMEM;
- int i;
-
- pr_debug(TEST_MODULE_NAME ":Starting Test ....\n");
-
- test_ctx->test_completed = 0;
- test_ctx->test_result = TEST_NO_RESULT;
- test_ctx->debug.dun_throughput = 0;
- test_ctx->debug.rmnt_throughput = 0;
- test_ctx->number_of_active_devices = 0;
-
- pr_err(TEST_MODULE_NAME ": %s - test_result %d",
- __func__, test_ctx->test_result);
-
- memset(test_ctx->test_dev_arr, 0,
- sizeof(struct sdio_test_device)*MAX_NUM_OF_SDIO_DEVICES);
-
- /* Open The Channels */
- for (i = 0; i < SDIO_MAX_CHANNELS; i++) {
- struct test_channel *tch = test_ctx->test_ch_arr[i];
-
- if ((!tch) || (!tch->is_used))
- continue;
-
- tch->rx_bytes = 0;
- tch->tx_bytes = 0;
-
- atomic_set(&tch->tx_notify_count, 0);
- atomic_set(&tch->rx_notify_count, 0);
- atomic_set(&tch->any_notify_count, 0);
- atomic_set(&tch->wakeup_client, 0);
-
- /* in case there are values left from previous tests */
- tch->notify_counter_per_chan = 0;
- tch->next_index_in_sent_msg_per_chan = 0;
-
- memset(tch->buf, 0x00, tch->buf_size);
- tch->test_result = TEST_NO_RESULT;
-
- tch->test_completed = 0;
-
- ret = open_sdio_ch(tch);
- if (ret)
- continue;
-
- if (tch->ch_id != SDIO_SMEM) {
- ret = sdio_test_find_dev(tch);
-
- if (ret) {
- pr_err(TEST_MODULE_NAME ": %s - "
- "sdio_test_find_dev() returned with "
- "error", __func__);
- return -ENODEV;
- }
-
- tch->sdio_al_device = tch->ch->sdio_al_dev;
- }
-
- if ((tch->test_type == SDIO_TEST_LPM_HOST_WAKER) ||
- (tch->test_type == SDIO_TEST_LPM_CLIENT_WAKER) ||
- (tch->test_type == SDIO_TEST_LPM_RANDOM))
- sdio_al_register_lpm_cb(tch->sdio_al_device,
- sdio_test_wakeup_callback);
- }
-
- /*
- * make some space between opening the channels and sending the
- * config messages
- */
- msleep(100);
-
- /*
- * try to delay send_config_msg of all channels to after the point
- * when we open them all
- */
- for (i = 0; i < SDIO_MAX_CHANNELS; i++) {
- struct test_channel *tch = test_ctx->test_ch_arr[i];
-
- if ((!tch) || (!tch->is_used))
- continue;
-
- if ((tch->ch_ready) && (tch->ch_id != SDIO_SMEM))
- send_config_msg(tch);
-
- if ((tch->test_type == SDIO_TEST_LPM_HOST_WAKER) ||
- (tch->test_type == SDIO_TEST_LPM_CLIENT_WAKER) ||
- (tch->test_type == SDIO_TEST_LPM_RANDOM)) {
- if (tch->timer_interval_ms > 0) {
- pr_info(TEST_MODULE_NAME ": %s - init timer, "
- "ms=%d\n",
- __func__, tch->timer_interval_ms);
- init_timer(&tch->timer);
- tch->timer.data = (unsigned long)tch;
- tch->timer.function =
- sdio_test_lpm_timer_handler;
- tch->timer.expires = jiffies +
- msecs_to_jiffies(tch->timer_interval_ms);
- add_timer(&tch->timer);
- }
- }
- }
-
- pr_debug(TEST_MODULE_NAME ":queue_work..\n");
- for (i = 0; i < SDIO_MAX_CHANNELS; i++) {
- struct test_channel *tch = test_ctx->test_ch_arr[i];
-
- if ((!tch) || (!tch->is_used) || (!tch->ch_ready))
- continue;
-
- if (tch->ch_id == SDIO_SMEM) {
-#ifdef CONFIG_MSM_SDIO_SMEM
- if (tch->test_type == SDIO_TEST_CLOSE_CHANNEL)
- open_close_smem_test(tch);
-#endif
- } else {
- queue_work(tch->workqueue, &tch->test_work.work);
- }
-
- }
-
- pr_info(TEST_MODULE_NAME ": %s - Waiting for the test completion\n",
- __func__);
-
- wait_event(test_ctx->wait_q, test_ctx->test_completed);
- check_test_result();
-
- /*
- * Close the channels and zero the is_used flag so that if the modem
- * will be reset after the test completion we won't re-open
- * the channels
- */
- for (i = 0; i < SDIO_MAX_CHANNELS; i++) {
- struct test_channel *tch = test_ctx->test_ch_arr[i];
-
- if ((!tch) || (!tch->is_used))
- continue;
- if (!tch->ch_ready) {
- tch->is_used = 0;
- continue;
- }
-
- close_sdio_ch(tch);
- tch->is_used = 0;
- }
-
- if (test_ctx->test_result == TEST_PASSED)
- return 0;
- else
- return -EINVAL;
-}
-
-static int set_params_loopback_9k(struct test_channel *tch)
-{
- if (!tch) {
- pr_err(TEST_MODULE_NAME ":NULL channel\n");
- return -EINVAL;
- }
- tch->is_used = 1;
- tch->test_type = SDIO_TEST_LOOPBACK_CLIENT;
- tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
- tch->config_msg.test_case = SDIO_TEST_LOOPBACK_CLIENT;
- tch->config_msg.num_packets = 10000;
- tch->config_msg.num_iterations = 1;
-
- tch->packet_length = 512;
- if (tch->ch_id == SDIO_RPC)
- tch->packet_length = 128;
- tch->timer_interval_ms = 0;
-
- return 0;
-}
-static int set_params_loopback_9k_close(struct test_channel *tch)
-{
- if (!tch) {
- pr_err(TEST_MODULE_NAME ":NULL channel\n");
- return -EINVAL;
- }
- tch->is_used = 1;
- tch->test_type = SDIO_TEST_CLOSE_CHANNEL;
- tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
- tch->config_msg.test_case = SDIO_TEST_LOOPBACK_CLIENT;
- tch->config_msg.num_packets = 5000;
- tch->config_msg.num_iterations = 1;
- tch->max_burst_size = 10;
- switch (tch->ch_id) {
- case SDIO_DUN:
- case SDIO_RPC:
- tch->packet_length = 128; /* max is 2K*/
- break;
- case SDIO_DIAG:
- case SDIO_RMNT:
- default:
- tch->packet_length = 512; /* max is 4k */
- }
- tch->timer_interval_ms = 0;
- return 0;
-}
-static int set_params_a2_perf(struct test_channel *tch)
-{
- if (!tch) {
- pr_err(TEST_MODULE_NAME ":NULL channel\n");
- return -EINVAL;
- }
- tch->is_used = 1;
- tch->test_type = SDIO_TEST_PERF;
- tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
- tch->config_msg.test_case = SDIO_TEST_LOOPBACK_CLIENT;
-
- switch (tch->ch_id) {
- case SDIO_DIAG:
- tch->packet_length = 512;
- break;
- case SDIO_DUN:
- tch->packet_length = DUN_PACKET_SIZE;
- break;
- case SDIO_CSVT:
- tch->packet_length = CSVT_PACKET_SIZE;
- break;
- default:
- tch->packet_length = MAX_XFER_SIZE;
- break;
- }
-
- pr_info(TEST_MODULE_NAME ": %s: packet_length=%d", __func__,
- tch->packet_length);
-
- tch->config_msg.num_packets = 10000;
- tch->config_msg.num_iterations = 1;
- tch->random_packet_size = 0;
-
- tch->timer_interval_ms = 0;
-
- return 0;
-}
-
-static int set_params_rtt(struct test_channel *tch)
-{
- if (!tch) {
- pr_err(TEST_MODULE_NAME ":NULL channel\n");
- return -EINVAL;
- }
- tch->is_used = 1;
- tch->test_type = SDIO_TEST_RTT;
- tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
- tch->config_msg.test_case = SDIO_TEST_LOOPBACK_CLIENT;
-
- switch (tch->ch_id) {
- case SDIO_RMNT:
- tch->packet_length = SDIO_RMNT_RTT_PACKET_SIZE;
- break;
- case SDIO_CSVT:
- tch->packet_length = SDIO_CSVT_RTT_PACKET_SIZE;
- break;
- default:
- pr_err(TEST_MODULE_NAME ": %s - ch_id invalid.\n", __func__);
- return -EINVAL;
- }
-
- pr_info(TEST_MODULE_NAME ": %s: packet_length=%d", __func__,
- tch->packet_length);
-
- tch->config_msg.num_packets = 200;
- tch->config_msg.num_iterations = 1;
- tch->random_packet_size = 0;
-
- tch->timer_interval_ms = 0;
-
- return 0;
-}
-
-static int set_params_a2_small_pkts(struct test_channel *tch)
-{
- if (!tch) {
- pr_err(TEST_MODULE_NAME ":NULL channel\n");
- return -EINVAL;
- }
- tch->is_used = 1;
- tch->test_type = SDIO_TEST_PERF;
- tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
- tch->config_msg.test_case = SDIO_TEST_LOOPBACK_CLIENT;
- tch->packet_length = 128;
-
- tch->config_msg.num_packets = 1000000;
- tch->config_msg.num_iterations = 1;
- tch->random_packet_size = 1;
-
- tch->timer_interval_ms = 0;
-
- return 0;
-}
-
-static int set_params_modem_reset(struct test_channel *tch)
-{
- if (!tch) {
- pr_err(TEST_MODULE_NAME ":NULL channel\n");
- return -EINVAL;
- }
- tch->is_used = 1;
- tch->test_type = SDIO_TEST_MODEM_RESET;
- tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
- tch->config_msg.test_case = SDIO_TEST_LOOPBACK_CLIENT;
- tch->packet_length = 512;
- if (tch->ch_id == SDIO_RPC)
- tch->packet_length = 128;
- else if ((tch->ch_id == SDIO_RMNT) || (tch->ch_id == SDIO_DUN))
- tch->packet_length = MAX_XFER_SIZE;
-
- tch->config_msg.num_packets = 50000;
- tch->config_msg.num_iterations = 1;
-
- tch->timer_interval_ms = 0;
-
- return 0;
-}
-
-static int set_params_a2_validation(struct test_channel *tch)
-{
- if (!tch) {
- pr_err(TEST_MODULE_NAME ":NULL channel\n");
- return -EINVAL;
- }
- tch->is_used = 1;
- tch->test_type = SDIO_TEST_A2_VALIDATION;
- tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
- tch->config_msg.test_case = SDIO_TEST_LOOPBACK_CLIENT;
-
- if (tch->ch_id == SDIO_RMNT)
- tch->packet_length = RMNT_PACKET_SIZE;
- else if (tch->ch_id == SDIO_DUN)
- tch->packet_length = DUN_PACKET_SIZE;
- else
- tch->packet_length = MAX_XFER_SIZE;
-
- tch->config_msg.num_packets = 10000;
- tch->config_msg.num_iterations = 1;
- tch->timer_interval_ms = 0;
-
- return 0;
-}
-
-static int set_params_smem_test(struct test_channel *tch)
-{
- if (!tch) {
- pr_err(TEST_MODULE_NAME ":NULL channel\n");
- return -EINVAL;
- }
- tch->is_used = 1;
- tch->timer_interval_ms = 0;
-
- return 0;
-}
-
-static int set_params_lpm_test(struct test_channel *tch,
- enum sdio_test_case_type test,
- int timer_interval_ms)
-{
- static int first_time = 1;
- if (!tch) {
- pr_err(TEST_MODULE_NAME ": %s - NULL channel\n", __func__);
- return -EINVAL;
- }
-
- tch->is_used = 1;
- tch->test_type = test;
- tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
- tch->config_msg.test_case = test;
- tch->config_msg.num_packets = LPM_TEST_NUM_OF_PACKETS;
- tch->config_msg.num_iterations = 1;
- tch->timer_interval_ms = timer_interval_ms;
- tch->timeout_ms = 10000;
-
- tch->packet_length = 0;
- if (test != SDIO_TEST_LPM_RANDOM) {
- init_timer(&tch->timeout_timer);
- tch->timeout_timer.data = (unsigned long)tch;
- tch->timeout_timer.function = sdio_test_lpm_timeout_handler;
- tch->timeout_timer.expires = jiffies +
- msecs_to_jiffies(tch->timeout_ms);
- add_timer(&tch->timeout_timer);
- pr_info(TEST_MODULE_NAME ": %s - Initiated LPM TIMEOUT TIMER."
- "set to %d ms\n",
- __func__, tch->timeout_ms);
- }
-
- if (first_time) {
- pr_info(TEST_MODULE_NAME ": %s - wake_lock_init() called\n",
- __func__);
- wake_lock_init(&test_ctx->wake_lock,
- WAKE_LOCK_SUSPEND, TEST_MODULE_NAME);
- first_time = 0;
- }
-
- pr_info(TEST_MODULE_NAME ": %s - wake_lock() for the TEST is "
- "called channel %s. to prevent real sleeping\n",
- __func__, tch->name);
- wake_lock(&test_ctx->wake_lock);
-
- return 0;
-}
-
-static int set_params_8k_sender_no_lp(struct test_channel *tch)
-{
- if (!tch) {
- pr_err(TEST_MODULE_NAME ":NULL channel\n");
- return -EINVAL;
- }
- tch->is_used = 1;
- tch->test_type = SDIO_TEST_HOST_SENDER_NO_LP;
- tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
- tch->config_msg.test_case = SDIO_TEST_HOST_SENDER_NO_LP;
- tch->config_msg.num_packets = 1000;
- tch->config_msg.num_iterations = 1;
-
- tch->packet_length = 512;
- if (tch->ch_id == SDIO_RPC)
- tch->packet_length = 128;
- tch->timer_interval_ms = 0;
-
- return 0;
-}
-
-static void set_pseudo_random_seed(void)
-{
- /* Set the seed accoring to the kernel command parameters if any or
- get a random value */
- if (seed != 0) {
- test_ctx->lpm_pseudo_random_seed = seed;
- } else {
- test_ctx->lpm_pseudo_random_seed =
- (unsigned int)(get_jiffies_64() & 0xFFFF);
- test_ctx->lpm_pseudo_random_seed =
- pseudo_random_seed(&test_ctx->lpm_pseudo_random_seed);
- }
-
- pr_info(TEST_MODULE_NAME ":%s: seed is %u",
- __func__, test_ctx->lpm_pseudo_random_seed);
-}
-
-/*
- for each channel
- 1. open channel
- 2. close channel
-*/
-static int close_channel_lpm_test(int channel_num)
-{
- int ret = 0;
- struct test_channel *tch = NULL;
- tch = test_ctx->test_ch_arr[channel_num];
-
- if (!tch) {
- pr_info(TEST_MODULE_NAME ":%s ch#%d is NULL\n",
- __func__, channel_num);
- return 0;
- }
-
- ret = open_sdio_ch(tch);
- if (ret) {
- pr_err(TEST_MODULE_NAME":%s open channel %s"
- " failed\n", __func__, tch->name);
- return ret;
- } else {
- pr_info(TEST_MODULE_NAME":%s open channel %s"
- " success\n", __func__, tch->name);
- }
- ret = close_sdio_ch(tch);
- if (ret) {
- pr_err(TEST_MODULE_NAME":%s close channel %s"
- " failed\n", __func__, tch->name);
- return ret;
- } else {
- pr_info(TEST_MODULE_NAME":%s close channel %s"
- " success\n", __func__, tch->name);
- }
-
- tch->is_used = 0;
-
- return ret;
-}
-
-/**
- * Write File.
- *
- * @note Trigger the test from user space by:
- * echo 1 > /dev/sdio_al_test
- *
- */
-ssize_t test_write(struct file *filp, const char __user *buf, size_t size,
- loff_t *f_pos)
-{
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- if (strict_strtol(buf, 10, &test_ctx->testcase))
- return -EINVAL;
-
- switch (test_ctx->testcase) {
- case 98:
- pr_info(TEST_MODULE_NAME " set runtime debug on");
- test_ctx->runtime_debug = 1;
- return size;
- case 99:
- pr_info(TEST_MODULE_NAME " set runtime debug off");
- test_ctx->runtime_debug = 0;
- return size;
- default:
- pr_info(TEST_MODULE_NAME ":Bad Test number = %d.\n",
- (int)test_ctx->testcase);
- return size;
- }
-
- return size;
-}
-
-/**
- * Test Channel Init.
- */
-int test_channel_init(char *name)
-{
- struct test_channel *test_ch;
- int ch_id = 0;
- int ret;
-
- pr_debug(TEST_MODULE_NAME ":%s.\n", __func__);
- pr_info(TEST_MODULE_NAME ": init test channel %s.\n", name);
-
- ch_id = channel_name_to_id(name);
- pr_debug(TEST_MODULE_NAME ":id = %d.\n", ch_id);
- if (test_ctx->test_ch_arr[ch_id] == NULL) {
- test_ch = kzalloc(sizeof(*test_ch), GFP_KERNEL);
- if (test_ch == NULL) {
- pr_err(TEST_MODULE_NAME ":kzalloc err for allocating "
- "test_ch %s.\n",
- name);
- return -ENOMEM;
- }
- test_ctx->test_ch_arr[ch_id] = test_ch;
-
- test_ch->ch_id = ch_id;
-
- strncpy(test_ch->name, name,
- strnlen(name, TEST_CH_NAME_SIZE)-SDIO_TEST_POSTFIX_SIZE);
-
- test_ch->buf_size = MAX_XFER_SIZE;
-
- test_ch->buf = kzalloc(test_ch->buf_size, GFP_KERNEL);
- if (test_ch->buf == NULL) {
- kfree(test_ch);
- test_ctx->test_ch = NULL;
- return -ENOMEM;
- }
-
- if (test_ch->ch_id == SDIO_SMEM) {
- test_ctx->smem_buf = kzalloc(SMEM_MAX_XFER_SIZE,
- GFP_KERNEL);
- if (test_ctx->smem_buf == NULL) {
- pr_err(TEST_MODULE_NAME ":%s: Unable to "
- "allocate smem buf\n",
- __func__);
- kfree(test_ch);
- test_ctx->test_ch = NULL;
- return -ENOMEM;
- }
-
-#ifdef CONFIG_MSM_SDIO_SMEM
- ret = platform_driver_register(&sdio_smem_client_drv);
- if (ret) {
- pr_err(TEST_MODULE_NAME ":%s: Unable to "
- "register sdio smem "
- "test client\n",
- __func__);
- return ret;
- }
-#endif
- } else {
- test_ch->workqueue =
- create_singlethread_workqueue(test_ch->name);
- test_ch->test_work.test_ch = test_ch;
- INIT_WORK(&test_ch->test_work.work, worker);
-
- init_waitqueue_head(&test_ch->wait_q);
- }
- } else {
- test_ch = test_ctx->test_ch_arr[ch_id];
- pr_info(TEST_MODULE_NAME ":%s: ch %s was detected again\n",
- __func__, test_ch->name);
- test_ch->card_removed = 0;
- if ((test_ch->is_used) &&
- (test_ch->test_type == SDIO_TEST_MODEM_RESET)) {
- if (test_ch->ch_id == SDIO_SMEM) {
-#ifdef CONFIG_MSM_SDIO_SMEM
- ret = add_sdio_smem();
- if (ret) {
- test_ch->ch_ready = false;
- return 0;
- }
-#endif
- } else {
- ret = open_sdio_ch(test_ch);
- if (ret) {
- pr_info(TEST_MODULE_NAME
- ":%s: open channel %s failed\n",
- __func__, test_ch->name);
- return 0;
- }
- ret = sdio_test_find_dev(test_ch);
-
- if (ret) {
- pr_err(TEST_MODULE_NAME ": %s - "
- "sdio_test_find_dev() returned "
- "with error", __func__);
- return -ENODEV;
- }
-
- test_ch->sdio_al_device =
- test_ch->ch->sdio_al_dev;
- }
- atomic_set(&test_ch->card_detected_event, 1);
- wake_up(&test_ch->wait_q);
- }
- }
-
- return 0;
-}
-
-static int sdio_test_channel_probe(struct platform_device *pdev)
-{
- if (!pdev)
- return -EIO;
- return test_channel_init((char *)pdev->name);
-}
-
-static int sdio_test_channel_remove(struct platform_device *pdev)
-{
- int ch_id;
-
- if (!pdev)
- return -EIO;
-
- ch_id = channel_name_to_id((char *)pdev->name);
- if (test_ctx->test_ch_arr[ch_id] == NULL)
- return 0;
-
- pr_info(TEST_MODULE_NAME "%s: remove ch %s\n",
- __func__, test_ctx->test_ch_arr[ch_id]->name);
-
- if ((ch_id == SDIO_SMEM) && (test_ctx->smem_pdev)) {
- platform_device_unregister(test_ctx->smem_pdev);
- test_ctx->smem_pdev = NULL;
- }
-
- test_ctx->test_ch_arr[ch_id]->ch_ready = 0;
- test_ctx->test_ch_arr[ch_id]->card_removed = 1;
-
- return 0;
-
-}
-
-static int sdio_test_channel_csvt_probe(struct platform_device *pdev)
-{
- int ret = 0;
-
- if (!pdev)
- return -ENODEV;
-
- test_ctx->csvt_app_pdev = platform_device_alloc("SDIO_CSVT_TEST_APP",
- -1);
- ret = platform_device_add(test_ctx->csvt_app_pdev);
- if (ret) {
- pr_err(MODULE_NAME ":platform_device_add failed, "
- "ret=%d\n", ret);
- return ret;
- }
-
- return sdio_test_channel_probe(pdev);
-}
-
-static int sdio_test_channel_csvt_remove(struct platform_device *pdev)
-{
- if (!pdev)
- return -ENODEV;
-
- platform_device_unregister(test_ctx->csvt_app_pdev);
-
- return sdio_test_channel_remove(pdev);
-}
-
-static struct platform_driver sdio_rpc_drv = {
- .probe = sdio_test_channel_probe,
- .remove = sdio_test_channel_remove,
- .driver = {
- .name = "SDIO_RPC_TEST",
- .owner = THIS_MODULE,
- },
-};
-
-static struct platform_driver sdio_qmi_drv = {
- .probe = sdio_test_channel_probe,
- .remove = sdio_test_channel_remove,
- .driver = {
- .name = "SDIO_QMI_TEST",
- .owner = THIS_MODULE,
- },
-};
-
-static struct platform_driver sdio_diag_drv = {
- .probe = sdio_test_channel_probe,
- .remove = sdio_test_channel_remove,
- .driver = {
- .name = "SDIO_DIAG_TEST",
- .owner = THIS_MODULE,
- },
-};
-
-static struct platform_driver sdio_smem_drv = {
- .probe = sdio_test_channel_probe,
- .remove = sdio_test_channel_remove,
- .driver = {
- .name = "SDIO_SMEM_TEST",
- .owner = THIS_MODULE,
- },
-};
-
-static struct platform_driver sdio_rmnt_drv = {
- .probe = sdio_test_channel_probe,
- .remove = sdio_test_channel_remove,
- .driver = {
- .name = "SDIO_RMNT_TEST",
- .owner = THIS_MODULE,
- },
-};
-
-static struct platform_driver sdio_dun_drv = {
- .probe = sdio_test_channel_probe,
- .remove = sdio_test_channel_remove,
- .driver = {
- .name = "SDIO_DUN_TEST",
- .owner = THIS_MODULE,
- },
-};
-
-static struct platform_driver sdio_csvt_drv = {
- .probe = sdio_test_channel_csvt_probe,
- .remove = sdio_test_channel_csvt_remove,
- .driver = {
- .name = "SDIO_CSVT_TEST",
- .owner = THIS_MODULE,
- },
-};
-
-static struct class *test_class;
-
-const struct file_operations test_fops = {
- .owner = THIS_MODULE,
- .write = test_write,
-};
-
-/**
- * Module Init.
- */
-static int __init test_init(void)
-{
- int ret;
-
- pr_debug(TEST_MODULE_NAME ":test_init.\n");
-
- test_ctx = kzalloc(sizeof(struct test_context), GFP_KERNEL);
-
- if (test_ctx == NULL) {
- pr_err(TEST_MODULE_NAME ":kzalloc err.\n");
- return -ENOMEM;
- }
- test_ctx->test_ch = NULL;
- test_ctx->signature = TEST_SIGNATURE;
-
- test_ctx->name = "UNKNOWN";
-
- init_waitqueue_head(&test_ctx->wait_q);
-
-#ifdef CONFIG_DEBUG_FS
- sdio_al_test_debugfs_init();
-#endif
-
- test_class = class_create(THIS_MODULE, TEST_MODULE_NAME);
-
- ret = alloc_chrdev_region(&test_ctx->dev_num, 0, 1, TEST_MODULE_NAME);
- if (ret) {
- pr_err(TEST_MODULE_NAME "alloc_chrdev_region err.\n");
- return -ENODEV;
- }
-
- test_ctx->dev = device_create(test_class, NULL, test_ctx->dev_num,
- test_ctx, TEST_MODULE_NAME);
- if (IS_ERR(test_ctx->dev)) {
- pr_err(TEST_MODULE_NAME ":device_create err.\n");
- return -ENODEV;
- }
-
- test_ctx->cdev = cdev_alloc();
- if (test_ctx->cdev == NULL) {
- pr_err(TEST_MODULE_NAME ":cdev_alloc err.\n");
- return -ENODEV;
- }
- cdev_init(test_ctx->cdev, &test_fops);
- test_ctx->cdev->owner = THIS_MODULE;
-
- ret = cdev_add(test_ctx->cdev, test_ctx->dev_num, 1);
- if (ret)
- pr_err(TEST_MODULE_NAME ":cdev_add err=%d\n", -ret);
- else
- pr_debug(TEST_MODULE_NAME ":SDIO-AL-Test init OK..\n");
-
- platform_driver_register(&sdio_rpc_drv);
- platform_driver_register(&sdio_qmi_drv);
- platform_driver_register(&sdio_diag_drv);
- platform_driver_register(&sdio_smem_drv);
- platform_driver_register(&sdio_rmnt_drv);
- platform_driver_register(&sdio_dun_drv);
- platform_driver_register(&sdio_csvt_drv);
-
- return ret;
-}
-
-/**
- * Module Exit.
- */
-static void __exit test_exit(void)
-{
- int i;
-
- pr_debug(TEST_MODULE_NAME ":test_exit.\n");
-
- test_ctx->exit_flag = true;
-
- msleep(100); /* allow gracefully exit of the worker thread */
-
- cdev_del(test_ctx->cdev);
- device_destroy(test_class, test_ctx->dev_num);
- unregister_chrdev_region(test_ctx->dev_num, 1);
-
- platform_driver_unregister(&sdio_rpc_drv);
- platform_driver_unregister(&sdio_qmi_drv);
- platform_driver_unregister(&sdio_diag_drv);
- platform_driver_unregister(&sdio_smem_drv);
- platform_driver_unregister(&sdio_rmnt_drv);
- platform_driver_unregister(&sdio_dun_drv);
- platform_driver_unregister(&sdio_csvt_drv);
-
- for (i = 0; i < SDIO_MAX_CHANNELS; i++) {
- struct test_channel *tch = test_ctx->test_ch_arr[i];
- if (!tch)
- continue;
- kfree(tch->buf);
- kfree(tch);
- }
-
-#ifdef CONFIG_DEBUG_FS
- sdio_al_test_debugfs_cleanup();
-#endif
-
- kfree(test_ctx);
-
- pr_debug(TEST_MODULE_NAME ":test_exit complete.\n");
-}
-
-module_init(test_init);
-module_exit(test_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("SDIO_AL Test");
-MODULE_AUTHOR("Amir Samuelov <amirs@codeaurora.org>");
-
-
diff --git a/arch/arm/mach-msm/sdio_cmux.c b/arch/arm/mach-msm/sdio_cmux.c
deleted file mode 100644
index 48ca6b7..0000000
--- a/arch/arm/mach-msm/sdio_cmux.c
+++ /dev/null
@@ -1,901 +0,0 @@
-/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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 DEBUG
-
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <linux/mutex.h>
-#include <linux/uaccess.h>
-#include <linux/workqueue.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/termios.h>
-#include <linux/debugfs.h>
-#include <linux/moduleparam.h>
-
-#include <mach/sdio_al.h>
-#include <mach/sdio_cmux.h>
-
-#include "modem_notifier.h"
-
-#define MAX_WRITE_RETRY 5
-#define MAGIC_NO_V1 0x33FC
-
-static int msm_sdio_cmux_debug_mask;
-module_param_named(debug_mask, msm_sdio_cmux_debug_mask,
- int, S_IRUGO | S_IWUSR | S_IWGRP);
-
-enum cmd_type {
- DATA = 0,
- OPEN,
- CLOSE,
- STATUS,
- NUM_CMDS
-};
-
-#define DSR_POS 0x1
-#define CTS_POS 0x2
-#define RI_POS 0x4
-#define CD_POS 0x8
-
-struct sdio_cmux_ch {
- int lc_id;
-
- struct mutex lc_lock;
- wait_queue_head_t open_wait_queue;
- int is_remote_open;
- int is_local_open;
- int is_channel_reset;
-
- char local_status;
- char remote_status;
-
- struct mutex tx_lock;
- struct list_head tx_list;
-
- void *priv;
- struct mutex rx_cb_lock;
- void (*receive_cb)(void *, int, void *);
- void (*write_done)(void *, int, void *);
- void (*status_callback)(int, void *);
-} logical_ch[SDIO_CMUX_NUM_CHANNELS];
-
-struct sdio_cmux_hdr {
- uint16_t magic_no;
- uint8_t status; /* This field is reserved for commands other
- * than STATUS */
- uint8_t cmd;
- uint8_t pad_bytes;
- uint8_t lc_id;
- uint16_t pkt_len;
-};
-
-struct sdio_cmux_pkt {
- struct sdio_cmux_hdr *hdr;
- void *data;
-};
-
-struct sdio_cmux_list_elem {
- struct list_head list;
- struct sdio_cmux_pkt cmux_pkt;
-};
-
-#define logical_ch_is_local_open(x) \
- (logical_ch[(x)].is_local_open)
-
-#define logical_ch_is_remote_open(x) \
- (logical_ch[(x)].is_remote_open)
-
-static void sdio_cdemux_fn(struct work_struct *work);
-static DECLARE_WORK(sdio_cdemux_work, sdio_cdemux_fn);
-static struct workqueue_struct *sdio_cdemux_wq;
-
-static DEFINE_MUTEX(write_lock);
-static uint32_t bytes_to_write;
-static DEFINE_MUTEX(temp_rx_lock);
-static LIST_HEAD(temp_rx_list);
-
-static void sdio_cmux_fn(struct work_struct *work);
-static DECLARE_WORK(sdio_cmux_work, sdio_cmux_fn);
-static struct workqueue_struct *sdio_cmux_wq;
-
-static struct sdio_channel *sdio_qmi_chl;
-static uint32_t sdio_cmux_inited;
-
-static uint32_t abort_tx;
-static DEFINE_MUTEX(modem_reset_lock);
-
-static DEFINE_MUTEX(probe_lock);
-
-enum {
- MSM_SDIO_CMUX_DEBUG = 1U << 0,
- MSM_SDIO_CMUX_DUMP_BUFFER = 1U << 1,
-};
-
-static struct platform_device sdio_ctl_dev = {
- .name = "SDIO_CTL",
- .id = -1,
-};
-
-#if defined(DEBUG)
-#define D_DUMP_BUFFER(prestr, cnt, buf) \
-do { \
- if (msm_sdio_cmux_debug_mask & MSM_SDIO_CMUX_DUMP_BUFFER) { \
- int i; \
- pr_debug("%s", prestr); \
- for (i = 0; i < cnt; i++) \
- pr_info("%.2x", buf[i]); \
- pr_debug("\n"); \
- } \
-} while (0)
-
-#define D(x...) \
-do { \
- if (msm_sdio_cmux_debug_mask & MSM_SDIO_CMUX_DEBUG) \
- pr_debug(x); \
-} while (0)
-
-#else
-#define D_DUMP_BUFFER(prestr, cnt, buf) do {} while (0)
-#define D(x...) do {} while (0)
-#endif
-
-static int sdio_cmux_ch_alloc(int id)
-{
- if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS) {
- pr_err("%s: Invalid lc_id - %d\n", __func__, id);
- return -EINVAL;
- }
-
- logical_ch[id].lc_id = id;
- mutex_init(&logical_ch[id].lc_lock);
- init_waitqueue_head(&logical_ch[id].open_wait_queue);
- logical_ch[id].is_remote_open = 0;
- logical_ch[id].is_local_open = 0;
- logical_ch[id].is_channel_reset = 0;
-
- INIT_LIST_HEAD(&logical_ch[id].tx_list);
- mutex_init(&logical_ch[id].tx_lock);
-
- logical_ch[id].priv = NULL;
- mutex_init(&logical_ch[id].rx_cb_lock);
- logical_ch[id].receive_cb = NULL;
- logical_ch[id].write_done = NULL;
- return 0;
-}
-
-static int sdio_cmux_ch_clear_and_signal(int id)
-{
- struct sdio_cmux_list_elem *list_elem;
-
- if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS) {
- pr_err("%s: Invalid lc_id - %d\n", __func__, id);
- return -EINVAL;
- }
-
- mutex_lock(&logical_ch[id].lc_lock);
- logical_ch[id].is_remote_open = 0;
- mutex_lock(&logical_ch[id].tx_lock);
- while (!list_empty(&logical_ch[id].tx_list)) {
- list_elem = list_first_entry(&logical_ch[id].tx_list,
- struct sdio_cmux_list_elem,
- list);
- list_del(&list_elem->list);
- kfree(list_elem->cmux_pkt.hdr);
- kfree(list_elem);
- }
- mutex_unlock(&logical_ch[id].tx_lock);
- mutex_lock(&logical_ch[id].rx_cb_lock);
- if (logical_ch[id].receive_cb)
- logical_ch[id].receive_cb(NULL, 0, logical_ch[id].priv);
- mutex_unlock(&logical_ch[id].rx_cb_lock);
- if (logical_ch[id].write_done)
- logical_ch[id].write_done(NULL, 0, logical_ch[id].priv);
- mutex_unlock(&logical_ch[id].lc_lock);
- wake_up(&logical_ch[id].open_wait_queue);
- return 0;
-}
-
-static int sdio_cmux_write_cmd(const int id, enum cmd_type type)
-{
- int write_size = 0;
- void *write_data = NULL;
- struct sdio_cmux_list_elem *list_elem;
-
- if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS) {
- pr_err("%s: Invalid lc_id - %d\n", __func__, id);
- return -EINVAL;
- }
-
- if (type < 0 || type > NUM_CMDS) {
- pr_err("%s: Invalid cmd - %d\n", __func__, type);
- return -EINVAL;
- }
-
- write_size = sizeof(struct sdio_cmux_hdr);
- list_elem = kmalloc(sizeof(struct sdio_cmux_list_elem), GFP_KERNEL);
- if (!list_elem) {
- pr_err("%s: list_elem alloc failed\n", __func__);
- return -ENOMEM;
- }
-
- write_data = kmalloc(write_size, GFP_KERNEL);
- if (!write_data) {
- pr_err("%s: write_data alloc failed\n", __func__);
- kfree(list_elem);
- return -ENOMEM;
- }
-
- list_elem->cmux_pkt.hdr = (struct sdio_cmux_hdr *)write_data;
- list_elem->cmux_pkt.data = NULL;
-
- list_elem->cmux_pkt.hdr->lc_id = (uint8_t)id;
- list_elem->cmux_pkt.hdr->pkt_len = (uint16_t)0;
- list_elem->cmux_pkt.hdr->cmd = (uint8_t)type;
- list_elem->cmux_pkt.hdr->status = (uint8_t)0;
- if (type == STATUS)
- list_elem->cmux_pkt.hdr->status = logical_ch[id].local_status;
- list_elem->cmux_pkt.hdr->pad_bytes = (uint8_t)0;
- list_elem->cmux_pkt.hdr->magic_no = (uint16_t)MAGIC_NO_V1;
-
- mutex_lock(&logical_ch[id].tx_lock);
- list_add_tail(&list_elem->list, &logical_ch[id].tx_list);
- mutex_unlock(&logical_ch[id].tx_lock);
-
- mutex_lock(&write_lock);
- bytes_to_write += write_size;
- mutex_unlock(&write_lock);
- queue_work(sdio_cmux_wq, &sdio_cmux_work);
-
- return 0;
-}
-
-int sdio_cmux_open(const int id,
- void (*receive_cb)(void *, int, void *),
- void (*write_done)(void *, int, void *),
- void (*status_callback)(int, void *),
- void *priv)
-{
- int r;
- struct sdio_cmux_list_elem *list_elem, *list_elem_tmp;
-
- if (!sdio_cmux_inited)
- return -ENODEV;
- if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS) {
- pr_err("%s: Invalid id - %d\n", __func__, id);
- return -EINVAL;
- }
-
- r = wait_event_timeout(logical_ch[id].open_wait_queue,
- logical_ch[id].is_remote_open, (1 * HZ));
- if (r < 0) {
- pr_err("ERROR %s: wait_event_timeout() failed for"
- " ch%d with rc %d\n", __func__, id, r);
- return r;
- }
- if (r == 0) {
- pr_err("ERROR %s: Wait Timed Out for ch%d\n", __func__, id);
- return -ETIMEDOUT;
- }
-
- mutex_lock(&logical_ch[id].lc_lock);
- if (!logical_ch[id].is_remote_open) {
- pr_err("%s: Remote ch%d not opened\n", __func__, id);
- mutex_unlock(&logical_ch[id].lc_lock);
- return -EINVAL;
- }
- if (logical_ch[id].is_local_open) {
- mutex_unlock(&logical_ch[id].lc_lock);
- return 0;
- }
- logical_ch[id].is_local_open = 1;
- logical_ch[id].priv = priv;
- logical_ch[id].write_done = write_done;
- logical_ch[id].status_callback = status_callback;
- mutex_lock(&logical_ch[id].rx_cb_lock);
- logical_ch[id].receive_cb = receive_cb;
- if (logical_ch[id].receive_cb) {
- mutex_lock(&temp_rx_lock);
- list_for_each_entry_safe(list_elem, list_elem_tmp,
- &temp_rx_list, list) {
- if ((int)list_elem->cmux_pkt.hdr->lc_id == id) {
- logical_ch[id].receive_cb(
- list_elem->cmux_pkt.data,
- (int)list_elem->cmux_pkt.hdr->pkt_len,
- logical_ch[id].priv);
- list_del(&list_elem->list);
- kfree(list_elem->cmux_pkt.hdr);
- kfree(list_elem);
- }
- }
- mutex_unlock(&temp_rx_lock);
- }
- mutex_unlock(&logical_ch[id].rx_cb_lock);
- mutex_unlock(&logical_ch[id].lc_lock);
- sdio_cmux_write_cmd(id, OPEN);
- return 0;
-}
-EXPORT_SYMBOL(sdio_cmux_open);
-
-int sdio_cmux_close(int id)
-{
- struct sdio_cmux_ch *ch;
-
- if (!sdio_cmux_inited)
- return -ENODEV;
- if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS) {
- pr_err("%s: Invalid channel close\n", __func__);
- return -EINVAL;
- }
-
- ch = &logical_ch[id];
- mutex_lock(&ch->lc_lock);
- mutex_lock(&logical_ch[id].rx_cb_lock);
- ch->receive_cb = NULL;
- mutex_unlock(&logical_ch[id].rx_cb_lock);
- mutex_lock(&ch->tx_lock);
- ch->write_done = NULL;
- mutex_unlock(&ch->tx_lock);
- ch->is_local_open = 0;
- ch->priv = NULL;
- mutex_unlock(&ch->lc_lock);
- sdio_cmux_write_cmd(ch->lc_id, CLOSE);
- return 0;
-}
-EXPORT_SYMBOL(sdio_cmux_close);
-
-int sdio_cmux_write_avail(int id)
-{
- int write_avail;
-
- mutex_lock(&logical_ch[id].lc_lock);
- if (logical_ch[id].is_channel_reset) {
- mutex_unlock(&logical_ch[id].lc_lock);
- return -ENETRESET;
- }
- mutex_unlock(&logical_ch[id].lc_lock);
- write_avail = sdio_write_avail(sdio_qmi_chl);
- return write_avail - bytes_to_write;
-}
-EXPORT_SYMBOL(sdio_cmux_write_avail);
-
-int sdio_cmux_write(int id, void *data, int len)
-{
- struct sdio_cmux_list_elem *list_elem;
- uint32_t write_size;
- void *write_data = NULL;
- struct sdio_cmux_ch *ch;
- int ret;
-
- if (!sdio_cmux_inited)
- return -ENODEV;
- if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS) {
- pr_err("%s: Invalid channel id %d\n", __func__, id);
- return -ENODEV;
- }
-
- ch = &logical_ch[id];
- if (len <= 0) {
- pr_err("%s: Invalid len %d bytes to write\n",
- __func__, len);
- return -EINVAL;
- }
-
- write_size = sizeof(struct sdio_cmux_hdr) + len;
- list_elem = kmalloc(sizeof(struct sdio_cmux_list_elem), GFP_KERNEL);
- if (!list_elem) {
- pr_err("%s: list_elem alloc failed\n", __func__);
- return -ENOMEM;
- }
-
- write_data = kmalloc(write_size, GFP_KERNEL);
- if (!write_data) {
- pr_err("%s: write_data alloc failed\n", __func__);
- kfree(list_elem);
- return -ENOMEM;
- }
-
- list_elem->cmux_pkt.hdr = (struct sdio_cmux_hdr *)write_data;
- list_elem->cmux_pkt.data = (void *)((char *)write_data +
- sizeof(struct sdio_cmux_hdr));
- memcpy(list_elem->cmux_pkt.data, data, len);
-
- list_elem->cmux_pkt.hdr->lc_id = (uint8_t)ch->lc_id;
- list_elem->cmux_pkt.hdr->pkt_len = (uint16_t)len;
- list_elem->cmux_pkt.hdr->cmd = (uint8_t)DATA;
- list_elem->cmux_pkt.hdr->status = (uint8_t)0;
- list_elem->cmux_pkt.hdr->pad_bytes = (uint8_t)0;
- list_elem->cmux_pkt.hdr->magic_no = (uint16_t)MAGIC_NO_V1;
-
- mutex_lock(&ch->lc_lock);
- if (!ch->is_remote_open || !ch->is_local_open) {
- pr_err("%s: Local ch%d sending data before sending/receiving"
- " OPEN command\n", __func__, ch->lc_id);
- if (ch->is_channel_reset)
- ret = -ENETRESET;
- else
- ret = -ENODEV;
- mutex_unlock(&ch->lc_lock);
- kfree(write_data);
- kfree(list_elem);
- return ret;
- }
- mutex_lock(&ch->tx_lock);
- list_add_tail(&list_elem->list, &ch->tx_list);
- mutex_unlock(&ch->tx_lock);
- mutex_unlock(&ch->lc_lock);
-
- mutex_lock(&write_lock);
- bytes_to_write += write_size;
- mutex_unlock(&write_lock);
- queue_work(sdio_cmux_wq, &sdio_cmux_work);
-
- return len;
-}
-EXPORT_SYMBOL(sdio_cmux_write);
-
-int is_remote_open(int id)
-{
- if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS)
- return -ENODEV;
-
- return logical_ch_is_remote_open(id);
-}
-EXPORT_SYMBOL(is_remote_open);
-
-int sdio_cmux_is_channel_reset(int id)
-{
- int ret;
- if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS)
- return -ENODEV;
-
- mutex_lock(&logical_ch[id].lc_lock);
- ret = logical_ch[id].is_channel_reset;
- mutex_unlock(&logical_ch[id].lc_lock);
- return ret;
-}
-EXPORT_SYMBOL(sdio_cmux_is_channel_reset);
-
-int sdio_cmux_tiocmget(int id)
-{
- int ret = (logical_ch[id].remote_status & DSR_POS ? TIOCM_DSR : 0) |
- (logical_ch[id].remote_status & CTS_POS ? TIOCM_CTS : 0) |
- (logical_ch[id].remote_status & CD_POS ? TIOCM_CD : 0) |
- (logical_ch[id].remote_status & RI_POS ? TIOCM_RI : 0) |
- (logical_ch[id].local_status & CTS_POS ? TIOCM_RTS : 0) |
- (logical_ch[id].local_status & DSR_POS ? TIOCM_DTR : 0);
- return ret;
-}
-EXPORT_SYMBOL(sdio_cmux_tiocmget);
-
-int sdio_cmux_tiocmset(int id, unsigned int set, unsigned int clear)
-{
- if (set & TIOCM_DTR)
- logical_ch[id].local_status |= DSR_POS;
-
- if (set & TIOCM_RTS)
- logical_ch[id].local_status |= CTS_POS;
-
- if (clear & TIOCM_DTR)
- logical_ch[id].local_status &= ~DSR_POS;
-
- if (clear & TIOCM_RTS)
- logical_ch[id].local_status &= ~CTS_POS;
-
- sdio_cmux_write_cmd(id, STATUS);
- return 0;
-}
-EXPORT_SYMBOL(sdio_cmux_tiocmset);
-
-static int copy_packet(void *pkt, int size)
-{
- struct sdio_cmux_list_elem *list_elem = NULL;
- void *temp_pkt = NULL;
-
- list_elem = kmalloc(sizeof(struct sdio_cmux_list_elem), GFP_KERNEL);
- if (!list_elem) {
- pr_err("%s: list_elem alloc failed\n", __func__);
- return -ENOMEM;
- }
- temp_pkt = kmalloc(size, GFP_KERNEL);
- if (!temp_pkt) {
- pr_err("%s: temp_pkt alloc failed\n", __func__);
- kfree(list_elem);
- return -ENOMEM;
- }
-
- memcpy(temp_pkt, pkt, size);
- list_elem->cmux_pkt.hdr = temp_pkt;
- list_elem->cmux_pkt.data = (void *)((char *)temp_pkt +
- sizeof(struct sdio_cmux_hdr));
- mutex_lock(&temp_rx_lock);
- list_add_tail(&list_elem->list, &temp_rx_list);
- mutex_unlock(&temp_rx_lock);
- return 0;
-}
-
-static int process_cmux_pkt(void *pkt, int size)
-{
- struct sdio_cmux_hdr *mux_hdr;
- uint32_t id, data_size;
- void *data;
- char *dump_buf = (char *)pkt;
-
- D_DUMP_BUFFER("process_cmux_pkt:", size, dump_buf);
- mux_hdr = (struct sdio_cmux_hdr *)pkt;
- switch (mux_hdr->cmd) {
- case OPEN:
- id = (uint32_t)(mux_hdr->lc_id);
- D("%s: Received OPEN command for ch%d\n", __func__, id);
- mutex_lock(&logical_ch[id].lc_lock);
- logical_ch[id].is_remote_open = 1;
- if (logical_ch[id].is_channel_reset) {
- sdio_cmux_write_cmd(id, OPEN);
- logical_ch[id].is_channel_reset = 0;
- }
- mutex_unlock(&logical_ch[id].lc_lock);
- wake_up(&logical_ch[id].open_wait_queue);
- break;
-
- case CLOSE:
- id = (uint32_t)(mux_hdr->lc_id);
- D("%s: Received CLOSE command for ch%d\n", __func__, id);
- sdio_cmux_ch_clear_and_signal(id);
- break;
-
- case DATA:
- id = (uint32_t)(mux_hdr->lc_id);
- D("%s: Received DATA for ch%d\n", __func__, id);
- /*Channel is not locally open & if single packet received
- then drop it*/
- mutex_lock(&logical_ch[id].lc_lock);
- if (!logical_ch[id].is_remote_open) {
- mutex_unlock(&logical_ch[id].lc_lock);
- pr_err("%s: Remote Ch%d sent data before sending/"
- "receiving OPEN command\n", __func__, id);
- return -ENODEV;
- }
-
- data = (void *)((char *)pkt + sizeof(struct sdio_cmux_hdr));
- data_size = (int)(((struct sdio_cmux_hdr *)pkt)->pkt_len);
- mutex_unlock(&logical_ch[id].lc_lock);
- /*
- * The lc_lock is released before the call to receive_cb
- * to avoid a dead lock where in the receive_cb would call a
- * function that tries to acquire a rx_lock which is already
- * acquired by a Thread that is waiting on lc_lock.
- */
- mutex_lock(&logical_ch[id].rx_cb_lock);
- if (logical_ch[id].receive_cb)
- logical_ch[id].receive_cb(data, data_size,
- logical_ch[id].priv);
- else
- copy_packet(pkt, size);
- mutex_unlock(&logical_ch[id].rx_cb_lock);
- break;
-
- case STATUS:
- id = (uint32_t)(mux_hdr->lc_id);
- D("%s: Received STATUS command for ch%d\n", __func__, id);
- if (logical_ch[id].remote_status != mux_hdr->status) {
- mutex_lock(&logical_ch[id].lc_lock);
- logical_ch[id].remote_status = mux_hdr->status;
- mutex_unlock(&logical_ch[id].lc_lock);
- if (logical_ch[id].status_callback)
- logical_ch[id].status_callback(
- sdio_cmux_tiocmget(id),
- logical_ch[id].priv);
- }
- break;
- }
- return 0;
-}
-
-static void parse_cmux_data(void *data, int size)
-{
- int data_parsed = 0, pkt_size;
- char *temp_ptr;
-
- D("Entered %s\n", __func__);
- temp_ptr = (char *)data;
- while (data_parsed < size) {
- pkt_size = sizeof(struct sdio_cmux_hdr) +
- (int)(((struct sdio_cmux_hdr *)temp_ptr)->pkt_len);
- D("Parsed %d bytes, Current Pkt Size %d bytes,"
- " Total size %d bytes\n", data_parsed, pkt_size, size);
- process_cmux_pkt((void *)temp_ptr, pkt_size);
- data_parsed += pkt_size;
- temp_ptr += pkt_size;
- }
-
- kfree(data);
-}
-
-static void sdio_cdemux_fn(struct work_struct *work)
-{
- int r = 0, read_avail = 0;
- void *cmux_data;
-
- while (1) {
- read_avail = sdio_read_avail(sdio_qmi_chl);
- if (read_avail < 0) {
- pr_err("%s: sdio_read_avail failed with rc %d\n",
- __func__, read_avail);
- return;
- }
-
- if (read_avail == 0) {
- D("%s: Nothing to read\n", __func__);
- return;
- }
-
- D("%s: kmalloc %d bytes\n", __func__, read_avail);
- cmux_data = kmalloc(read_avail, GFP_KERNEL);
- if (!cmux_data) {
- pr_err("%s: kmalloc Failed\n", __func__);
- return;
- }
-
- D("%s: sdio_read %d bytes\n", __func__, read_avail);
- r = sdio_read(sdio_qmi_chl, cmux_data, read_avail);
- if (r < 0) {
- pr_err("%s: sdio_read failed with rc %d\n",
- __func__, r);
- kfree(cmux_data);
- return;
- }
-
- parse_cmux_data(cmux_data, read_avail);
- }
- return;
-}
-
-static void sdio_cmux_fn(struct work_struct *work)
-{
- int i, r = 0;
- void *write_data;
- uint32_t write_size, write_avail, write_retry = 0;
- int bytes_written;
- struct sdio_cmux_list_elem *list_elem = NULL;
- struct sdio_cmux_ch *ch;
-
- for (i = 0; i < SDIO_CMUX_NUM_CHANNELS; ++i) {
- ch = &logical_ch[i];
- bytes_written = 0;
- mutex_lock(&ch->tx_lock);
- while (!list_empty(&ch->tx_list)) {
- list_elem = list_first_entry(&ch->tx_list,
- struct sdio_cmux_list_elem,
- list);
- list_del(&list_elem->list);
- mutex_unlock(&ch->tx_lock);
-
- write_data = (void *)list_elem->cmux_pkt.hdr;
- write_size = sizeof(struct sdio_cmux_hdr) +
- (uint32_t)list_elem->cmux_pkt.hdr->pkt_len;
-
- mutex_lock(&modem_reset_lock);
- while (!(abort_tx) &&
- ((write_avail = sdio_write_avail(sdio_qmi_chl))
- < write_size)) {
- mutex_unlock(&modem_reset_lock);
- pr_err("%s: sdio_write_avail %d bytes, "
- "write size %d bytes. Waiting...\n",
- __func__, write_avail, write_size);
- msleep(250);
- mutex_lock(&modem_reset_lock);
- }
- while (!(abort_tx) &&
- ((r = sdio_write(sdio_qmi_chl,
- write_data, write_size)) < 0)
- && (r != -ENODEV)
- && (write_retry++ < MAX_WRITE_RETRY)) {
- mutex_unlock(&modem_reset_lock);
- pr_err("%s: sdio_write failed with rc %d."
- "Retrying...", __func__, r);
- msleep(250);
- mutex_lock(&modem_reset_lock);
- }
- if (!r && !abort_tx) {
- D("%s: sdio_write_completed %dbytes\n",
- __func__, write_size);
- bytes_written += write_size;
- } else if (r == -ENODEV) {
- pr_err("%s: aborting_tx because sdio_write"
- " returned %d\n", __func__, r);
- r = 0;
- abort_tx = 1;
- }
- mutex_unlock(&modem_reset_lock);
- kfree(list_elem->cmux_pkt.hdr);
- kfree(list_elem);
- mutex_lock(&write_lock);
- bytes_to_write -= write_size;
- mutex_unlock(&write_lock);
- mutex_lock(&ch->tx_lock);
- }
- if (ch->write_done)
- ch->write_done(NULL, bytes_written, ch->priv);
- mutex_unlock(&ch->tx_lock);
- }
- return;
-}
-
-static void sdio_qmi_chl_notify(void *priv, unsigned event)
-{
- if (event == SDIO_EVENT_DATA_READ_AVAIL) {
- D("%s: Received SDIO_EVENT_DATA_READ_AVAIL\n", __func__);
- queue_work(sdio_cdemux_wq, &sdio_cdemux_work);
- }
-}
-
-#ifdef CONFIG_DEBUG_FS
-
-static int debug_tbl(char *buf, int max)
-{
- int i = 0;
- int j;
-
- for (j = 0; j < SDIO_CMUX_NUM_CHANNELS; ++j) {
- i += scnprintf(buf + i, max - i,
- "ch%02d local open=%s remote open=%s\n",
- j, logical_ch_is_local_open(j) ? "Y" : "N",
- logical_ch_is_remote_open(j) ? "Y" : "N");
- }
-
- return i;
-}
-
-#define DEBUG_BUFMAX 4096
-static char debug_buffer[DEBUG_BUFMAX];
-
-static ssize_t debug_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- int (*fill)(char *buf, int max) = file->private_data;
- int bsize = fill(debug_buffer, DEBUG_BUFMAX);
- return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
-}
-
-static int debug_open(struct inode *inode, struct file *file)
-{
- file->private_data = inode->i_private;
- return 0;
-}
-
-
-static const struct file_operations debug_ops = {
- .read = debug_read,
- .open = debug_open,
-};
-
-static void debug_create(const char *name, mode_t mode,
- struct dentry *dent,
- int (*fill)(char *buf, int max))
-{
- debugfs_create_file(name, mode, dent, fill, &debug_ops);
-}
-
-#endif
-
-static int sdio_cmux_probe(struct platform_device *pdev)
-{
- int i, r;
-
- mutex_lock(&probe_lock);
- D("%s Begins\n", __func__);
- if (sdio_cmux_inited) {
- mutex_lock(&modem_reset_lock);
- r = sdio_open("SDIO_QMI", &sdio_qmi_chl, NULL,
- sdio_qmi_chl_notify);
- if (r < 0) {
- mutex_unlock(&modem_reset_lock);
- pr_err("%s: sdio_open() failed\n", __func__);
- goto error0;
- }
- abort_tx = 0;
- mutex_unlock(&modem_reset_lock);
- mutex_unlock(&probe_lock);
- return 0;
- }
-
- for (i = 0; i < SDIO_CMUX_NUM_CHANNELS; ++i)
- sdio_cmux_ch_alloc(i);
- INIT_LIST_HEAD(&temp_rx_list);
-
- sdio_cmux_wq = create_singlethread_workqueue("sdio_cmux");
- if (IS_ERR(sdio_cmux_wq)) {
- pr_err("%s: create_singlethread_workqueue() ENOMEM\n",
- __func__);
- r = -ENOMEM;
- goto error0;
- }
-
- sdio_cdemux_wq = create_singlethread_workqueue("sdio_cdemux");
- if (IS_ERR(sdio_cdemux_wq)) {
- pr_err("%s: create_singlethread_workqueue() ENOMEM\n",
- __func__);
- r = -ENOMEM;
- goto error1;
- }
-
- r = sdio_open("SDIO_QMI", &sdio_qmi_chl, NULL, sdio_qmi_chl_notify);
- if (r < 0) {
- pr_err("%s: sdio_open() failed\n", __func__);
- goto error2;
- }
-
- platform_device_register(&sdio_ctl_dev);
- sdio_cmux_inited = 1;
- D("SDIO Control MUX Driver Initialized.\n");
- mutex_unlock(&probe_lock);
- return 0;
-
-error2:
- destroy_workqueue(sdio_cdemux_wq);
-error1:
- destroy_workqueue(sdio_cmux_wq);
-error0:
- mutex_unlock(&probe_lock);
- return r;
-}
-
-static int sdio_cmux_remove(struct platform_device *pdev)
-{
- int i;
-
- mutex_lock(&modem_reset_lock);
- abort_tx = 1;
-
- for (i = 0; i < SDIO_CMUX_NUM_CHANNELS; ++i) {
- mutex_lock(&logical_ch[i].lc_lock);
- logical_ch[i].is_channel_reset = 1;
- mutex_unlock(&logical_ch[i].lc_lock);
- sdio_cmux_ch_clear_and_signal(i);
- }
- sdio_qmi_chl = NULL;
- mutex_unlock(&modem_reset_lock);
-
- return 0;
-}
-
-static struct platform_driver sdio_cmux_driver = {
- .probe = sdio_cmux_probe,
- .remove = sdio_cmux_remove,
- .driver = {
- .name = "SDIO_QMI",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init sdio_cmux_init(void)
-{
-#ifdef CONFIG_DEBUG_FS
- struct dentry *dent;
-
- dent = debugfs_create_dir("sdio_cmux", 0);
- if (!IS_ERR(dent))
- debug_create("tbl", 0444, dent, debug_tbl);
-#endif
-
- msm_sdio_cmux_debug_mask = 0;
- return platform_driver_register(&sdio_cmux_driver);
-}
-
-module_init(sdio_cmux_init);
-MODULE_DESCRIPTION("MSM SDIO Control MUX");
-MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/sdio_ctl.c b/arch/arm/mach-msm/sdio_ctl.c
deleted file mode 100644
index cacdce9..0000000
--- a/arch/arm/mach-msm/sdio_ctl.c
+++ /dev/null
@@ -1,575 +0,0 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-/*
- * SDIO Control Driver -- Provides a binary SDIO muxed control port
- * interface.
- */
-
-#include <linux/cdev.h>
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <linux/mutex.h>
-#include <linux/uaccess.h>
-#include <linux/workqueue.h>
-#include <linux/poll.h>
-#include <asm/ioctls.h>
-#include <linux/platform_device.h>
-#include <mach/msm_smd.h>
-#include <mach/sdio_al.h>
-#include <mach/sdio_cmux.h>
-#include "modem_notifier.h"
-#include <linux/slab.h>
-
-#define MAX_WRITE_RETRY 5
-#define MAGIC_NO_V1 0x33FC
-#define NUM_SDIO_CTL_PORTS 10
-#define DEVICE_NAME "sdioctl"
-#define MAX_BUF_SIZE 2048
-#define DEBUG
-
-static int msm_sdio_ctl_debug_mask;
-module_param_named(debug_mask, msm_sdio_ctl_debug_mask,
- int, S_IRUGO | S_IWUSR | S_IWGRP);
-
-struct sdio_ctl_dev {
- int id;
- char name[9];
- struct cdev cdev;
- struct device *devicep;
- struct mutex dev_lock;
- int ref_count;
-
- struct mutex rx_lock;
- uint32_t read_avail;
- struct list_head rx_list;
-
- wait_queue_head_t read_wait_queue;
- wait_queue_head_t write_wait_queue;
-} *sdio_ctl_devp[NUM_SDIO_CTL_PORTS];
-
-struct sdio_ctl_pkt {
- int data_size;
- void *data;
-};
-
-struct sdio_ctl_list_elem {
- struct list_head list;
- struct sdio_ctl_pkt ctl_pkt;
-};
-
-struct class *sdio_ctl_classp;
-static dev_t sdio_ctl_number;
-static uint32_t sdio_ctl_inited;
-
-enum {
- MSM_SDIO_CTL_DEBUG = 1U << 0,
- MSM_SDIO_CTL_DUMP_BUFFER = 1U << 1,
-};
-
-#if defined(DEBUG)
-#define D_DUMP_BUFFER(prestr, cnt, buf) \
-do { \
- if (msm_sdio_ctl_debug_mask & MSM_SDIO_CTL_DUMP_BUFFER) { \
- int i; \
- pr_info("%s", prestr); \
- for (i = 0; i < cnt; i++) \
- pr_info("%.2x", buf[i]); \
- pr_info("\n"); \
- } \
-} while (0)
-
-#define D(x...) \
-do { \
- if (msm_sdio_ctl_debug_mask & MSM_SDIO_CTL_DEBUG) \
- pr_info(x); \
-} while (0)
-
-#else
-#define D_DUMP_BUFFER(prestr, cnt, buf) do {} while (0)
-#define D(x...) do {} while (0)
-#endif
-
-static uint32_t cmux_ch_id[] = {
- SDIO_CMUX_DATA_CTL_0,
- SDIO_CMUX_DATA_CTL_1,
- SDIO_CMUX_DATA_CTL_2,
- SDIO_CMUX_DATA_CTL_3,
- SDIO_CMUX_DATA_CTL_4,
- SDIO_CMUX_DATA_CTL_5,
- SDIO_CMUX_DATA_CTL_6,
- SDIO_CMUX_DATA_CTL_7,
- SDIO_CMUX_USB_CTL_0,
- SDIO_CMUX_CSVT_CTL_0
-};
-
-static int get_ctl_dev_index(int id)
-{
- int dev_index;
- for (dev_index = 0; dev_index < NUM_SDIO_CTL_PORTS; dev_index++) {
- if (cmux_ch_id[dev_index] == id)
- return dev_index;
- }
- return -ENODEV;
-}
-
-static void sdio_ctl_receive_cb(void *data, int size, void *priv)
-{
- struct sdio_ctl_list_elem *list_elem = NULL;
- int id = ((struct sdio_ctl_dev *)(priv))->id;
- int dev_index;
-
- if (id < 0 || id > cmux_ch_id[NUM_SDIO_CTL_PORTS - 1])
- return;
- dev_index = get_ctl_dev_index(id);
- if (dev_index < 0) {
- pr_err("%s: Ch%d is not exported to user-space\n",
- __func__, id);
- return;
- }
-
- if (!data || size <= 0) {
- wake_up(&sdio_ctl_devp[dev_index]->read_wait_queue);
- return;
- }
-
- list_elem = kmalloc(sizeof(struct sdio_ctl_list_elem), GFP_KERNEL);
- if (!list_elem) {
- pr_err("%s: list_elem alloc failed\n", __func__);
- return;
- }
-
- list_elem->ctl_pkt.data = kmalloc(size, GFP_KERNEL);
- if (!list_elem->ctl_pkt.data) {
- pr_err("%s: list_elem->data alloc failed\n", __func__);
- kfree(list_elem);
- return;
- }
- memcpy(list_elem->ctl_pkt.data, data, size);
- list_elem->ctl_pkt.data_size = size;
- mutex_lock(&sdio_ctl_devp[dev_index]->rx_lock);
- list_add_tail(&list_elem->list, &sdio_ctl_devp[dev_index]->rx_list);
- sdio_ctl_devp[dev_index]->read_avail += size;
- mutex_unlock(&sdio_ctl_devp[dev_index]->rx_lock);
- wake_up(&sdio_ctl_devp[dev_index]->read_wait_queue);
-}
-
-static void sdio_ctl_write_done(void *data, int size, void *priv)
-{
- int id = ((struct sdio_ctl_dev *)(priv))->id;
- int dev_index;
- if (id < 0 || id > cmux_ch_id[NUM_SDIO_CTL_PORTS - 1])
- return;
-
- dev_index = get_ctl_dev_index(id);
- if (dev_index < 0) {
- pr_err("%s: Ch%d is not exported to user-space\n",
- __func__, id);
- return;
- }
- wake_up(&sdio_ctl_devp[dev_index]->write_wait_queue);
-}
-
-static long sdio_ctl_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- int ret;
- struct sdio_ctl_dev *sdio_ctl_devp;
-
- sdio_ctl_devp = file->private_data;
- if (!sdio_ctl_devp)
- return -ENODEV;
-
- switch (cmd) {
- case TIOCMGET:
- ret = sdio_cmux_tiocmget(sdio_ctl_devp->id);
- break;
- case TIOCMSET:
- ret = sdio_cmux_tiocmset(sdio_ctl_devp->id, arg, ~arg);
- break;
- default:
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-static unsigned int sdio_ctl_poll(struct file *file, poll_table *wait)
-{
- struct sdio_ctl_dev *sdio_ctl_devp;
- unsigned int mask = 0;
-
- sdio_ctl_devp = file->private_data;
- if (!sdio_ctl_devp) {
- pr_err("%s: on a NULL device\n", __func__);
- return POLLERR;
- }
-
- poll_wait(file, &sdio_ctl_devp->read_wait_queue, wait);
- mutex_lock(&sdio_ctl_devp->rx_lock);
- if (sdio_cmux_is_channel_reset(sdio_ctl_devp->id)) {
- mutex_unlock(&sdio_ctl_devp->rx_lock);
- pr_err("%s notifying reset for sdio_ctl_dev id:%d\n",
- __func__, sdio_ctl_devp->id);
- return POLLERR;
- }
-
- if (sdio_ctl_devp->read_avail > 0)
- mask |= POLLIN | POLLRDNORM;
-
- mutex_unlock(&sdio_ctl_devp->rx_lock);
-
- return mask;
-}
-
-ssize_t sdio_ctl_read(struct file *file,
- char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int r = 0, id, bytes_to_read;
- struct sdio_ctl_dev *sdio_ctl_devp;
- struct sdio_ctl_list_elem *list_elem = NULL;
-
- sdio_ctl_devp = file->private_data;
-
- if (!sdio_ctl_devp)
- return -ENODEV;
-
- D("%s: read from ch%d\n", __func__, sdio_ctl_devp->id);
-
- id = sdio_ctl_devp->id;
- mutex_lock(&sdio_ctl_devp->rx_lock);
- while (sdio_ctl_devp->read_avail <= 0) {
- mutex_unlock(&sdio_ctl_devp->rx_lock);
- r = wait_event_interruptible(sdio_ctl_devp->read_wait_queue,
- sdio_ctl_devp->read_avail > 0 ||
- !is_remote_open(id));
- if (sdio_cmux_is_channel_reset(id))
- return -ENETRESET;
-
- if (!is_remote_open(id))
- return -ENODEV;
-
- if (r < 0) {
- /* qualify error message */
- /* we get this anytime a signal comes in */
- if (r != -ERESTARTSYS)
- pr_err("ERROR:%s: wait_event_interruptible "
- "ret %i\n", __func__, r);
- return r;
- }
- mutex_lock(&sdio_ctl_devp->rx_lock);
- }
-
- if (list_empty(&sdio_ctl_devp->rx_list)) {
- mutex_unlock(&sdio_ctl_devp->rx_lock);
- D("%s: Nothing in ch%d's rx_list\n", __func__,
- sdio_ctl_devp->id);
- return -EAGAIN;
- }
-
- list_elem = list_first_entry(&sdio_ctl_devp->rx_list,
- struct sdio_ctl_list_elem, list);
- bytes_to_read = (uint32_t)(list_elem->ctl_pkt.data_size);
- if (bytes_to_read > count) {
- mutex_unlock(&sdio_ctl_devp->rx_lock);
- pr_err("%s: Packet size %d > buf size %d\n", __func__,
- bytes_to_read, count);
- return -ENOMEM;
- }
-
- if (copy_to_user(buf, list_elem->ctl_pkt.data, bytes_to_read)) {
- mutex_unlock(&sdio_ctl_devp->rx_lock);
- pr_err("%s: copy_to_user failed for ch%d\n", __func__,
- sdio_ctl_devp->id);
- return -EFAULT;
- }
- sdio_ctl_devp->read_avail -= bytes_to_read;
- list_del(&list_elem->list);
- kfree(list_elem->ctl_pkt.data);
- kfree(list_elem);
- mutex_unlock(&sdio_ctl_devp->rx_lock);
- D("%s: Returning %d bytes to ch%d\n", __func__,
- bytes_to_read, sdio_ctl_devp->id);
- return bytes_to_read;
-}
-
-
-ssize_t sdio_ctl_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int r = 0, id;
- char *temp_buf;
- struct sdio_ctl_dev *sdio_ctl_devp;
-
- if (count <= 0)
- return -EINVAL;
-
- sdio_ctl_devp = file->private_data;
- if (!sdio_ctl_devp)
- return -ENODEV;
-
- D("%s: writing %i bytes on ch%d\n",
- __func__, count, sdio_ctl_devp->id);
- id = sdio_ctl_devp->id;
- mutex_lock(&sdio_ctl_devp->dev_lock);
- while (sdio_cmux_write_avail(id) < count) {
- mutex_unlock(&sdio_ctl_devp->dev_lock);
- r = wait_event_interruptible(sdio_ctl_devp->write_wait_queue,
- sdio_cmux_write_avail(id) >= count
- || !is_remote_open(id));
-
- if (sdio_cmux_is_channel_reset(id))
- return -ENETRESET;
-
- if (!is_remote_open(id))
- return -ENODEV;
-
- if (r < 0) {
- /* qualify error message */
- /* we get this anytime a signal comes in */
- if (r != -ERESTARTSYS)
- pr_err("ERROR:%s: wait_event_interruptible "
- "ret %i\n", __func__, r);
- return r;
- }
- mutex_lock(&sdio_ctl_devp->dev_lock);
- }
-
- temp_buf = kmalloc(count, GFP_KERNEL);
- if (!temp_buf) {
- mutex_unlock(&sdio_ctl_devp->dev_lock);
- pr_err("%s: temp_buf alloc failed\n", __func__);
- return -ENOMEM;
- }
-
- if (copy_from_user(temp_buf, buf, count)) {
- mutex_unlock(&sdio_ctl_devp->dev_lock);
- pr_err("%s: copy_from_user failed\n", __func__);
- kfree(temp_buf);
- return -EFAULT;
- }
-
- r = sdio_cmux_write(id, (void *)temp_buf, count);
- kfree(temp_buf);
- mutex_unlock(&sdio_ctl_devp->dev_lock);
- return r;
-}
-
-
-int sdio_ctl_open(struct inode *inode, struct file *file)
-{
- int r = 0;
- struct sdio_ctl_dev *sdio_ctl_devp;
-
- if (!sdio_ctl_inited)
- return -EIO;
-
- sdio_ctl_devp = container_of(inode->i_cdev, struct sdio_ctl_dev, cdev);
-
- if (!sdio_ctl_devp)
- return -ENODEV;
-
- D("%s called on sdioctl%d device\n", __func__, sdio_ctl_devp->id);
- r = sdio_cmux_open(sdio_ctl_devp->id, sdio_ctl_receive_cb,
- sdio_ctl_write_done, NULL,
- sdio_ctl_devp);
- if (r < 0) {
- pr_err("ERROR %s: sdio_cmux_open failed with rc %d\n",
- __func__, r);
- return r;
- }
-
- mutex_lock(&sdio_ctl_devp->dev_lock);
- sdio_ctl_devp->ref_count++;
- mutex_unlock(&sdio_ctl_devp->dev_lock);
-
- file->private_data = sdio_ctl_devp;
- return 0;
-}
-
-int sdio_ctl_release(struct inode *inode, struct file *file)
-{
- struct sdio_ctl_dev *sdio_ctl_devp;
- struct sdio_ctl_list_elem *list_elem = NULL;
-
- sdio_ctl_devp = file->private_data;
- if (!sdio_ctl_devp)
- return -EINVAL;
-
- D("%s called on sdioctl%d device\n", __func__, sdio_ctl_devp->id);
-
- mutex_lock(&sdio_ctl_devp->dev_lock);
- if (sdio_ctl_devp->ref_count > 0) {
- sdio_ctl_devp->ref_count--;
- if (!sdio_ctl_devp->ref_count) {
- mutex_lock(&sdio_ctl_devp->rx_lock);
- while (!list_empty(&sdio_ctl_devp->rx_list)) {
- list_elem = list_first_entry(
- &sdio_ctl_devp->rx_list,
- struct sdio_ctl_list_elem,
- list);
- list_del(&list_elem->list);
- kfree(list_elem->ctl_pkt.data);
- kfree(list_elem);
- }
- sdio_ctl_devp->read_avail = 0;
- mutex_unlock(&sdio_ctl_devp->rx_lock);
- sdio_cmux_close(sdio_ctl_devp->id);
- }
- }
- mutex_unlock(&sdio_ctl_devp->dev_lock);
-
- file->private_data = NULL;
- return 0;
-}
-
-static const struct file_operations sdio_ctl_fops = {
- .owner = THIS_MODULE,
- .open = sdio_ctl_open,
- .release = sdio_ctl_release,
- .read = sdio_ctl_read,
- .write = sdio_ctl_write,
- .poll = sdio_ctl_poll,
- .unlocked_ioctl = sdio_ctl_ioctl,
-};
-
-static int sdio_ctl_probe(struct platform_device *pdev)
-{
- int i;
- int r;
-
- pr_info("%s Begins\n", __func__);
- for (i = 0; i < NUM_SDIO_CTL_PORTS; ++i) {
- sdio_ctl_devp[i] = kzalloc(sizeof(struct sdio_ctl_dev),
- GFP_KERNEL);
- if (IS_ERR(sdio_ctl_devp[i])) {
- pr_err("ERROR:%s kmalloc() ENOMEM\n", __func__);
- r = -ENOMEM;
- goto error0;
- }
-
- sdio_ctl_devp[i]->id = cmux_ch_id[i];
- sdio_ctl_devp[i]->ref_count = 0;
-
- mutex_init(&sdio_ctl_devp[i]->dev_lock);
- init_waitqueue_head(&sdio_ctl_devp[i]->read_wait_queue);
- init_waitqueue_head(&sdio_ctl_devp[i]->write_wait_queue);
- mutex_init(&sdio_ctl_devp[i]->rx_lock);
- INIT_LIST_HEAD(&sdio_ctl_devp[i]->rx_list);
- sdio_ctl_devp[i]->read_avail = 0;
- }
-
- r = alloc_chrdev_region(&sdio_ctl_number, 0, NUM_SDIO_CTL_PORTS,
- DEVICE_NAME);
- if (IS_ERR_VALUE(r)) {
- pr_err("ERROR:%s: alloc_chrdev_region() ret %i.\n",
- __func__, r);
- goto error0;
- }
-
- sdio_ctl_classp = class_create(THIS_MODULE, DEVICE_NAME);
- if (IS_ERR(sdio_ctl_classp)) {
- pr_err("ERROR:%s: class_create() ENOMEM\n", __func__);
- r = -ENOMEM;
- goto error1;
- }
-
- for (i = 0; i < NUM_SDIO_CTL_PORTS; ++i) {
- cdev_init(&sdio_ctl_devp[i]->cdev, &sdio_ctl_fops);
- sdio_ctl_devp[i]->cdev.owner = THIS_MODULE;
-
- r = cdev_add(&sdio_ctl_devp[i]->cdev, (sdio_ctl_number + i),
- 1);
-
- if (IS_ERR_VALUE(r)) {
- pr_err("%s: cdev_add() ret %i\n", __func__, r);
- kfree(sdio_ctl_devp[i]);
- goto error2;
- }
-
- sdio_ctl_devp[i]->devicep =
- device_create(sdio_ctl_classp, NULL,
- (sdio_ctl_number + i), NULL,
- DEVICE_NAME "%d", cmux_ch_id[i]);
-
- if (IS_ERR(sdio_ctl_devp[i]->devicep)) {
- pr_err("%s: device_create() ENOMEM\n", __func__);
- r = -ENOMEM;
- cdev_del(&sdio_ctl_devp[i]->cdev);
- kfree(sdio_ctl_devp[i]);
- goto error2;
- }
- }
-
- sdio_ctl_inited = 1;
- D("SDIO Control Port Driver Initialized.\n");
- return 0;
-
-error2:
- while (--i >= 0) {
- cdev_del(&sdio_ctl_devp[i]->cdev);
- device_destroy(sdio_ctl_classp,
- MKDEV(MAJOR(sdio_ctl_number), i));
- }
-
- class_destroy(sdio_ctl_classp);
- i = NUM_SDIO_CTL_PORTS;
-error1:
- unregister_chrdev_region(MAJOR(sdio_ctl_number), NUM_SDIO_CTL_PORTS);
-error0:
- while (--i >= 0)
- kfree(sdio_ctl_devp[i]);
- return r;
-}
-
-static int sdio_ctl_remove(struct platform_device *pdev)
-{
- int i;
-
- for (i = 0; i < NUM_SDIO_CTL_PORTS; ++i) {
- cdev_del(&sdio_ctl_devp[i]->cdev);
- kfree(sdio_ctl_devp[i]);
- device_destroy(sdio_ctl_classp,
- MKDEV(MAJOR(sdio_ctl_number), i));
- }
- class_destroy(sdio_ctl_classp);
- unregister_chrdev_region(MAJOR(sdio_ctl_number), NUM_SDIO_CTL_PORTS);
-
- return 0;
-}
-
-static struct platform_driver sdio_ctl_driver = {
- .probe = sdio_ctl_probe,
- .remove = sdio_ctl_remove,
- .driver = {
- .name = "SDIO_CTL",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init sdio_ctl_init(void)
-{
- msm_sdio_ctl_debug_mask = 0;
- return platform_driver_register(&sdio_ctl_driver);
-}
-
-module_init(sdio_ctl_init);
-MODULE_DESCRIPTION("MSM SDIO Control Port");
-MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/sdio_dmux.c b/arch/arm/mach-msm/sdio_dmux.c
deleted file mode 100644
index c6d665d..0000000
--- a/arch/arm/mach-msm/sdio_dmux.c
+++ /dev/null
@@ -1,925 +0,0 @@
-/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-/*
- * SDIO DMUX module.
- */
-
-#define DEBUG
-
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/platform_device.h>
-#include <linux/sched.h>
-#include <linux/skbuff.h>
-#include <linux/wakelock.h>
-#include <linux/debugfs.h>
-#include <linux/smp.h>
-#include <linux/cpumask.h>
-
-#include <mach/sdio_al.h>
-#include <mach/sdio_dmux.h>
-
-#define SDIO_CH_LOCAL_OPEN 0x1
-#define SDIO_CH_REMOTE_OPEN 0x2
-#define SDIO_CH_IN_RESET 0x4
-
-#define SDIO_MUX_HDR_MAGIC_NO 0x33fc
-
-#define SDIO_MUX_HDR_CMD_DATA 0
-#define SDIO_MUX_HDR_CMD_OPEN 1
-#define SDIO_MUX_HDR_CMD_CLOSE 2
-
-#define LOW_WATERMARK 2
-#define HIGH_WATERMARK 4
-
-static int msm_sdio_dmux_debug_enable;
-module_param_named(debug_enable, msm_sdio_dmux_debug_enable,
- int, S_IRUGO | S_IWUSR | S_IWGRP);
-
-#if defined(DEBUG)
-static uint32_t sdio_dmux_read_cnt;
-static uint32_t sdio_dmux_write_cnt;
-static uint32_t sdio_dmux_write_cpy_cnt;
-static uint32_t sdio_dmux_write_cpy_bytes;
-
-#define DBG(x...) do { \
- if (msm_sdio_dmux_debug_enable) \
- pr_debug(x); \
- } while (0)
-
-#define DBG_INC_READ_CNT(x) do { \
- sdio_dmux_read_cnt += (x); \
- if (msm_sdio_dmux_debug_enable) \
- pr_debug("%s: total read bytes %u\n", \
- __func__, sdio_dmux_read_cnt); \
- } while (0)
-
-#define DBG_INC_WRITE_CNT(x) do { \
- sdio_dmux_write_cnt += (x); \
- if (msm_sdio_dmux_debug_enable) \
- pr_debug("%s: total written bytes %u\n", \
- __func__, sdio_dmux_write_cnt); \
- } while (0)
-
-#define DBG_INC_WRITE_CPY(x) do { \
- sdio_dmux_write_cpy_bytes += (x); \
- sdio_dmux_write_cpy_cnt++; \
- if (msm_sdio_dmux_debug_enable) \
- pr_debug("%s: total write copy cnt %u, bytes %u\n", \
- __func__, sdio_dmux_write_cpy_cnt, \
- sdio_dmux_write_cpy_bytes); \
- } while (0)
-#else
-#define DBG(x...) do { } while (0)
-#define DBG_INC_READ_CNT(x...) do { } while (0)
-#define DBG_INC_WRITE_CNT(x...) do { } while (0)
-#define DBG_INC_WRITE_CPY(x...) do { } while (0)
-#endif
-
-struct sdio_ch_info {
- uint32_t status;
- void (*receive_cb)(void *, struct sk_buff *);
- void (*write_done)(void *, struct sk_buff *);
- void *priv;
- spinlock_t lock;
- int num_tx_pkts;
- int use_wm;
-};
-
-static struct sk_buff_head sdio_mux_write_pool;
-static spinlock_t sdio_mux_write_lock;
-
-static struct sdio_channel *sdio_mux_ch;
-static struct sdio_ch_info sdio_ch[SDIO_DMUX_NUM_CHANNELS];
-struct wake_lock sdio_mux_ch_wakelock;
-static int sdio_mux_initialized;
-static int fatal_error;
-
-struct sdio_mux_hdr {
- uint16_t magic_num;
- uint8_t reserved;
- uint8_t cmd;
- uint8_t pad_len;
- uint8_t ch_id;
- uint16_t pkt_len;
-};
-
-struct sdio_partial_pkt_info {
- uint32_t valid;
- struct sk_buff *skb;
- struct sdio_mux_hdr *hdr;
-};
-
-static void sdio_mux_read_data(struct work_struct *work);
-static void sdio_mux_write_data(struct work_struct *work);
-static void sdio_mux_send_open_cmd(uint32_t id);
-
-static DEFINE_MUTEX(sdio_mux_lock);
-static DECLARE_WORK(work_sdio_mux_read, sdio_mux_read_data);
-static DECLARE_WORK(work_sdio_mux_write, sdio_mux_write_data);
-static DECLARE_DELAYED_WORK(delayed_work_sdio_mux_write, sdio_mux_write_data);
-
-static struct workqueue_struct *sdio_mux_workqueue;
-static struct sdio_partial_pkt_info sdio_partial_pkt;
-
-#define sdio_ch_is_open(x) \
- (sdio_ch[(x)].status == (SDIO_CH_LOCAL_OPEN | SDIO_CH_REMOTE_OPEN))
-
-#define sdio_ch_is_local_open(x) \
- (sdio_ch[(x)].status & SDIO_CH_LOCAL_OPEN)
-
-#define sdio_ch_is_remote_open(x) \
- (sdio_ch[(x)].status & SDIO_CH_REMOTE_OPEN)
-
-#define sdio_ch_is_in_reset(x) \
- (sdio_ch[(x)].status & SDIO_CH_IN_RESET)
-
-static inline void skb_set_data(struct sk_buff *skb,
- unsigned char *data,
- unsigned int len)
-{
- /* panic if tail > end */
- skb->data = data;
- skb->tail = skb->data + len;
- skb->len = len;
- skb->truesize = len + sizeof(struct sk_buff);
-}
-
-static void sdio_mux_save_partial_pkt(struct sdio_mux_hdr *hdr,
- struct sk_buff *skb_mux)
-{
- struct sk_buff *skb;
-
- /* i think we can avoid cloning here */
- skb = skb_clone(skb_mux, GFP_KERNEL);
- if (!skb) {
- pr_err("%s: cannot clone skb\n", __func__);
- return;
- }
-
- /* protect? */
- skb_set_data(skb, (unsigned char *)hdr,
- skb->tail - (unsigned char *)hdr);
- sdio_partial_pkt.skb = skb;
- sdio_partial_pkt.valid = 1;
- DBG("%s: head %p data %p tail %p end %p len %d\n", __func__,
- skb->head, skb->data, skb->tail, skb->end, skb->len);
- return;
-}
-
-static void *handle_sdio_mux_data(struct sdio_mux_hdr *hdr,
- struct sk_buff *skb_mux)
-{
- struct sk_buff *skb;
- void *rp = (void *)hdr;
- unsigned long flags;
-
- /* protect? */
- rp += sizeof(*hdr);
- if (rp < (void *)skb_mux->tail)
- rp += (hdr->pkt_len + hdr->pad_len);
-
- if (rp > (void *)skb_mux->tail) {
- /* partial packet */
- sdio_mux_save_partial_pkt(hdr, skb_mux);
- goto packet_done;
- }
-
- DBG("%s: hdr %p next %p tail %p pkt_size %d\n",
- __func__, hdr, rp, skb_mux->tail, hdr->pkt_len + hdr->pad_len);
-
- skb = skb_clone(skb_mux, GFP_KERNEL);
- if (!skb) {
- pr_err("%s: cannot clone skb\n", __func__);
- goto packet_done;
- }
-
- skb_set_data(skb, (unsigned char *)(hdr + 1), hdr->pkt_len);
- DBG("%s: head %p data %p tail %p end %p len %d\n",
- __func__, skb->head, skb->data, skb->tail, skb->end, skb->len);
-
- /* probably we should check channel status */
- /* discard packet early if local side not open */
- spin_lock_irqsave(&sdio_ch[hdr->ch_id].lock, flags);
- if (sdio_ch[hdr->ch_id].receive_cb)
- sdio_ch[hdr->ch_id].receive_cb(sdio_ch[hdr->ch_id].priv, skb);
- else
- dev_kfree_skb_any(skb);
- spin_unlock_irqrestore(&sdio_ch[hdr->ch_id].lock, flags);
-
-packet_done:
- return rp;
-}
-
-static void *handle_sdio_mux_command(struct sdio_mux_hdr *hdr,
- struct sk_buff *skb_mux)
-{
- void *rp;
- unsigned long flags;
- int send_open = 0;
-
- DBG("%s: cmd %d ch %d\n", __func__, hdr->cmd, hdr->ch_id);
- switch (hdr->cmd) {
- case SDIO_MUX_HDR_CMD_DATA:
- rp = handle_sdio_mux_data(hdr, skb_mux);
- break;
- case SDIO_MUX_HDR_CMD_OPEN:
- spin_lock_irqsave(&sdio_ch[hdr->ch_id].lock, flags);
- sdio_ch[hdr->ch_id].status |= SDIO_CH_REMOTE_OPEN;
- sdio_ch[hdr->ch_id].num_tx_pkts = 0;
-
- if (sdio_ch_is_in_reset(hdr->ch_id)) {
- DBG("%s: in reset - sending open cmd\n", __func__);
- sdio_ch[hdr->ch_id].status &= ~SDIO_CH_IN_RESET;
- send_open = 1;
- }
-
- /* notify client so it can update its status */
- if (sdio_ch[hdr->ch_id].receive_cb)
- sdio_ch[hdr->ch_id].receive_cb(
- sdio_ch[hdr->ch_id].priv, NULL);
-
- if (sdio_ch[hdr->ch_id].write_done)
- sdio_ch[hdr->ch_id].write_done(
- sdio_ch[hdr->ch_id].priv, NULL);
- spin_unlock_irqrestore(&sdio_ch[hdr->ch_id].lock, flags);
- rp = hdr + 1;
- if (send_open)
- sdio_mux_send_open_cmd(hdr->ch_id);
-
- break;
- case SDIO_MUX_HDR_CMD_CLOSE:
- /* probably should drop pending write */
- spin_lock_irqsave(&sdio_ch[hdr->ch_id].lock, flags);
- sdio_ch[hdr->ch_id].status &= ~SDIO_CH_REMOTE_OPEN;
- spin_unlock_irqrestore(&sdio_ch[hdr->ch_id].lock, flags);
- rp = hdr + 1;
- break;
- default:
- rp = hdr + 1;
- }
-
- return rp;
-}
-
-static void *handle_sdio_partial_pkt(struct sk_buff *skb_mux)
-{
- struct sk_buff *p_skb;
- struct sdio_mux_hdr *p_hdr;
- void *ptr, *rp = skb_mux->data;
-
- /* protoect? */
- if (sdio_partial_pkt.valid) {
- p_skb = sdio_partial_pkt.skb;
-
- ptr = skb_push(skb_mux, p_skb->len);
- memcpy(ptr, p_skb->data, p_skb->len);
- sdio_partial_pkt.skb = NULL;
- sdio_partial_pkt.valid = 0;
- dev_kfree_skb_any(p_skb);
-
- DBG("%s: head %p data %p tail %p end %p len %d\n", __func__,
- skb_mux->head, skb_mux->data, skb_mux->tail,
- skb_mux->end, skb_mux->len);
-
- p_hdr = (struct sdio_mux_hdr *)skb_mux->data;
- rp = handle_sdio_mux_command(p_hdr, skb_mux);
- }
- return rp;
-}
-
-static void sdio_mux_read_data(struct work_struct *work)
-{
- struct sk_buff *skb_mux;
- void *ptr = 0;
- int sz, rc, len = 0;
- struct sdio_mux_hdr *hdr;
- static int workqueue_pinned;
-
- if (!workqueue_pinned) {
- struct cpumask cpus;
-
- cpumask_clear(&cpus);
- cpumask_set_cpu(0, &cpus);
-
- if (sched_setaffinity(current->pid, &cpus))
- pr_err("%s: sdio_dmux set CPU affinity failed\n",
- __func__);
- workqueue_pinned = 1;
- }
-
- DBG("%s: reading\n", __func__);
- /* should probably have a separate read lock */
- mutex_lock(&sdio_mux_lock);
- sz = sdio_read_avail(sdio_mux_ch);
- DBG("%s: read avail %d\n", __func__, sz);
- if (sz <= 0) {
- if (sz)
- pr_err("%s: read avail failed %d\n", __func__, sz);
- mutex_unlock(&sdio_mux_lock);
- return;
- }
-
- /* net_ip_aling is probably not required */
- if (sdio_partial_pkt.valid)
- len = sdio_partial_pkt.skb->len;
-
- /* If allocation fails attempt to get a smaller chunk of mem */
- do {
- skb_mux = __dev_alloc_skb(sz + NET_IP_ALIGN + len, GFP_KERNEL);
- if (skb_mux)
- break;
-
- pr_err("%s: cannot allocate skb of size:%d + "
- "%d (NET_SKB_PAD)\n", __func__,
- sz + NET_IP_ALIGN + len, NET_SKB_PAD);
- /* the skb structure adds NET_SKB_PAD bytes to the memory
- * request, which may push the actual request above PAGE_SIZE
- * in that case, we need to iterate one more time to make sure
- * we get the memory request under PAGE_SIZE
- */
- if (sz + NET_IP_ALIGN + len + NET_SKB_PAD <= PAGE_SIZE) {
- pr_err("%s: allocation failed\n", __func__);
- mutex_unlock(&sdio_mux_lock);
- return;
- }
- sz /= 2;
- } while (1);
-
- skb_reserve(skb_mux, NET_IP_ALIGN + len);
- ptr = skb_put(skb_mux, sz);
-
- /* half second wakelock is fine? */
- wake_lock_timeout(&sdio_mux_ch_wakelock, HZ / 2);
- rc = sdio_read(sdio_mux_ch, ptr, sz);
- DBG("%s: read %d\n", __func__, rc);
- if (rc) {
- pr_err("%s: sdio read failed %d\n", __func__, rc);
- dev_kfree_skb_any(skb_mux);
- mutex_unlock(&sdio_mux_lock);
- queue_work(sdio_mux_workqueue, &work_sdio_mux_read);
- return;
- }
- mutex_unlock(&sdio_mux_lock);
-
- DBG_INC_READ_CNT(sz);
- DBG("%s: head %p data %p tail %p end %p len %d\n", __func__,
- skb_mux->head, skb_mux->data, skb_mux->tail,
- skb_mux->end, skb_mux->len);
-
- /* move to a separate function */
- /* probably do skb_pull instead of pointer adjustment */
- hdr = handle_sdio_partial_pkt(skb_mux);
- while ((void *)hdr < (void *)skb_mux->tail) {
-
- if (((void *)hdr + sizeof(*hdr)) > (void *)skb_mux->tail) {
- /* handle partial header */
- sdio_mux_save_partial_pkt(hdr, skb_mux);
- break;
- }
-
- if (hdr->magic_num != SDIO_MUX_HDR_MAGIC_NO) {
- pr_err("%s: packet error\n", __func__);
- break;
- }
-
- hdr = handle_sdio_mux_command(hdr, skb_mux);
- }
- dev_kfree_skb_any(skb_mux);
-
- DBG("%s: read done\n", __func__);
- queue_work(sdio_mux_workqueue, &work_sdio_mux_read);
-}
-
-static int sdio_mux_write(struct sk_buff *skb)
-{
- int rc, sz;
-
- mutex_lock(&sdio_mux_lock);
- sz = sdio_write_avail(sdio_mux_ch);
- DBG("%s: avail %d len %d\n", __func__, sz, skb->len);
- if (skb->len <= sz) {
- rc = sdio_write(sdio_mux_ch, skb->data, skb->len);
- DBG("%s: write returned %d\n", __func__, rc);
- if (rc == 0)
- DBG_INC_WRITE_CNT(skb->len);
- } else
- rc = -ENOMEM;
-
- mutex_unlock(&sdio_mux_lock);
- return rc;
-}
-
-static int sdio_mux_write_cmd(void *data, uint32_t len)
-{
- int avail, rc;
- for (;;) {
- mutex_lock(&sdio_mux_lock);
- avail = sdio_write_avail(sdio_mux_ch);
- DBG("%s: avail %d len %d\n", __func__, avail, len);
- if (avail >= len) {
- rc = sdio_write(sdio_mux_ch, data, len);
- DBG("%s: write returned %d\n", __func__, rc);
- if (!rc) {
- DBG_INC_WRITE_CNT(len);
- break;
- }
- }
- mutex_unlock(&sdio_mux_lock);
- msleep(250);
- }
- mutex_unlock(&sdio_mux_lock);
- return 0;
-}
-
-static void sdio_mux_send_open_cmd(uint32_t id)
-{
- struct sdio_mux_hdr hdr = {
- .magic_num = SDIO_MUX_HDR_MAGIC_NO,
- .cmd = SDIO_MUX_HDR_CMD_OPEN,
- .reserved = 0,
- .ch_id = id,
- .pkt_len = 0,
- .pad_len = 0
- };
-
- sdio_mux_write_cmd((void *)&hdr, sizeof(hdr));
-}
-
-static void sdio_mux_write_data(struct work_struct *work)
-{
- int rc, reschedule = 0;
- int notify = 0;
- struct sk_buff *skb;
- unsigned long flags;
- int avail;
- int ch_id;
-
- spin_lock_irqsave(&sdio_mux_write_lock, flags);
- while ((skb = __skb_dequeue(&sdio_mux_write_pool))) {
- ch_id = ((struct sdio_mux_hdr *)skb->data)->ch_id;
-
- avail = sdio_write_avail(sdio_mux_ch);
- if (avail < skb->len) {
- /* we may have to wait for write avail
- * notification from sdio al
- */
- DBG("%s: sdio_write_avail(%d) < skb->len(%d)\n",
- __func__, avail, skb->len);
-
- reschedule = 1;
- break;
- }
- spin_unlock_irqrestore(&sdio_mux_write_lock, flags);
- rc = sdio_mux_write(skb);
- spin_lock_irqsave(&sdio_mux_write_lock, flags);
- if (rc == 0) {
-
- spin_lock(&sdio_ch[ch_id].lock);
- sdio_ch[ch_id].num_tx_pkts--;
- spin_unlock(&sdio_ch[ch_id].lock);
-
- if (sdio_ch[ch_id].write_done)
- sdio_ch[ch_id].write_done(
- sdio_ch[ch_id].priv, skb);
- else
- dev_kfree_skb_any(skb);
- } else if (rc == -EAGAIN || rc == -ENOMEM) {
- /* recoverable error - retry again later */
- reschedule = 1;
- break;
- } else if (rc == -ENODEV) {
- /*
- * sdio_al suffered some kind of fatal error
- * prevent future writes and clean up pending ones
- */
- fatal_error = 1;
- do {
- ch_id = ((struct sdio_mux_hdr *)
- skb->data)->ch_id;
- spin_lock(&sdio_ch[ch_id].lock);
- sdio_ch[ch_id].num_tx_pkts--;
- spin_unlock(&sdio_ch[ch_id].lock);
- dev_kfree_skb_any(skb);
- } while ((skb = __skb_dequeue(&sdio_mux_write_pool)));
- spin_unlock_irqrestore(&sdio_mux_write_lock, flags);
- return;
- } else {
- /* unknown error condition - drop the
- * skb and reschedule for the
- * other skb's
- */
- pr_err("%s: sdio_mux_write error %d"
- " for ch %d, skb=%p\n",
- __func__, rc, ch_id, skb);
- notify = 1;
- break;
- }
- }
-
- if (reschedule) {
- if (sdio_ch_is_in_reset(ch_id)) {
- notify = 1;
- } else {
- __skb_queue_head(&sdio_mux_write_pool, skb);
- queue_delayed_work(sdio_mux_workqueue,
- &delayed_work_sdio_mux_write,
- msecs_to_jiffies(250)
- );
- }
- }
-
- if (notify) {
- spin_lock(&sdio_ch[ch_id].lock);
- sdio_ch[ch_id].num_tx_pkts--;
- spin_unlock(&sdio_ch[ch_id].lock);
-
- if (sdio_ch[ch_id].write_done)
- sdio_ch[ch_id].write_done(
- sdio_ch[ch_id].priv, skb);
- else
- dev_kfree_skb_any(skb);
- }
- spin_unlock_irqrestore(&sdio_mux_write_lock, flags);
-}
-
-int msm_sdio_is_channel_in_reset(uint32_t id)
-{
- int rc = 0;
-
- if (id >= SDIO_DMUX_NUM_CHANNELS)
- return -EINVAL;
-
- if (sdio_ch_is_in_reset(id))
- rc = 1;
-
- return rc;
-}
-
-int msm_sdio_dmux_write(uint32_t id, struct sk_buff *skb)
-{
- int rc = 0;
- struct sdio_mux_hdr *hdr;
- unsigned long flags;
- struct sk_buff *new_skb;
-
- if (id >= SDIO_DMUX_NUM_CHANNELS)
- return -EINVAL;
- if (!skb)
- return -EINVAL;
- if (!sdio_mux_initialized)
- return -ENODEV;
- if (fatal_error)
- return -ENODEV;
-
- DBG("%s: writing to ch %d len %d\n", __func__, id, skb->len);
- spin_lock_irqsave(&sdio_ch[id].lock, flags);
- if (sdio_ch_is_in_reset(id)) {
- spin_unlock_irqrestore(&sdio_ch[id].lock, flags);
- pr_err("%s: port is in reset: %d\n", __func__,
- sdio_ch[id].status);
- return -ENETRESET;
- }
- if (!sdio_ch_is_local_open(id)) {
- spin_unlock_irqrestore(&sdio_ch[id].lock, flags);
- pr_err("%s: port not open: %d\n", __func__, sdio_ch[id].status);
- return -ENODEV;
- }
- if (sdio_ch[id].use_wm &&
- (sdio_ch[id].num_tx_pkts >= HIGH_WATERMARK)) {
- spin_unlock_irqrestore(&sdio_ch[id].lock, flags);
- pr_err("%s: watermark exceeded: %d\n", __func__, id);
- return -EAGAIN;
- }
- spin_unlock_irqrestore(&sdio_ch[id].lock, flags);
-
- spin_lock_irqsave(&sdio_mux_write_lock, flags);
- /* if skb do not have any tailroom for padding,
- copy the skb into a new expanded skb */
- if ((skb->len & 0x3) && (skb_tailroom(skb) < (4 - (skb->len & 0x3)))) {
- /* revisit, probably dev_alloc_skb and memcpy is effecient */
- new_skb = skb_copy_expand(skb, skb_headroom(skb),
- 4 - (skb->len & 0x3), GFP_ATOMIC);
- if (new_skb == NULL) {
- pr_err("%s: cannot allocate skb\n", __func__);
- rc = -ENOMEM;
- goto write_done;
- }
- dev_kfree_skb_any(skb);
- skb = new_skb;
- DBG_INC_WRITE_CPY(skb->len);
- }
-
- hdr = (struct sdio_mux_hdr *)skb_push(skb, sizeof(struct sdio_mux_hdr));
-
- /* caller should allocate for hdr and padding
- hdr is fine, padding is tricky */
- hdr->magic_num = SDIO_MUX_HDR_MAGIC_NO;
- hdr->cmd = SDIO_MUX_HDR_CMD_DATA;
- hdr->reserved = 0;
- hdr->ch_id = id;
- hdr->pkt_len = skb->len - sizeof(struct sdio_mux_hdr);
- if (skb->len & 0x3)
- skb_put(skb, 4 - (skb->len & 0x3));
-
- hdr->pad_len = skb->len - (sizeof(struct sdio_mux_hdr) + hdr->pkt_len);
-
- DBG("%s: data %p, tail %p skb len %d pkt len %d pad len %d\n",
- __func__, skb->data, skb->tail, skb->len,
- hdr->pkt_len, hdr->pad_len);
- __skb_queue_tail(&sdio_mux_write_pool, skb);
-
- spin_lock(&sdio_ch[id].lock);
- sdio_ch[id].num_tx_pkts++;
- spin_unlock(&sdio_ch[id].lock);
-
- queue_work(sdio_mux_workqueue, &work_sdio_mux_write);
-
-write_done:
- spin_unlock_irqrestore(&sdio_mux_write_lock, flags);
- return rc;
-}
-
-int msm_sdio_dmux_open(uint32_t id, void *priv,
- void (*receive_cb)(void *, struct sk_buff *),
- void (*write_done)(void *, struct sk_buff *))
-{
- unsigned long flags;
-
- DBG("%s: opening ch %d\n", __func__, id);
- if (!sdio_mux_initialized)
- return -ENODEV;
- if (id >= SDIO_DMUX_NUM_CHANNELS)
- return -EINVAL;
-
- spin_lock_irqsave(&sdio_ch[id].lock, flags);
- if (sdio_ch_is_local_open(id)) {
- pr_info("%s: Already opened %d\n", __func__, id);
- spin_unlock_irqrestore(&sdio_ch[id].lock, flags);
- goto open_done;
- }
-
- sdio_ch[id].receive_cb = receive_cb;
- sdio_ch[id].write_done = write_done;
- sdio_ch[id].priv = priv;
- sdio_ch[id].status |= SDIO_CH_LOCAL_OPEN;
- sdio_ch[id].num_tx_pkts = 0;
- sdio_ch[id].use_wm = 0;
- spin_unlock_irqrestore(&sdio_ch[id].lock, flags);
-
- sdio_mux_send_open_cmd(id);
-
-open_done:
- pr_info("%s: opened ch %d\n", __func__, id);
- return 0;
-}
-
-int msm_sdio_dmux_close(uint32_t id)
-{
- struct sdio_mux_hdr hdr;
- unsigned long flags;
-
- if (id >= SDIO_DMUX_NUM_CHANNELS)
- return -EINVAL;
- DBG("%s: closing ch %d\n", __func__, id);
- if (!sdio_mux_initialized)
- return -ENODEV;
- spin_lock_irqsave(&sdio_ch[id].lock, flags);
-
- sdio_ch[id].receive_cb = NULL;
- sdio_ch[id].priv = NULL;
- sdio_ch[id].status &= ~SDIO_CH_LOCAL_OPEN;
- sdio_ch[id].status &= ~SDIO_CH_IN_RESET;
- spin_unlock_irqrestore(&sdio_ch[id].lock, flags);
-
- hdr.magic_num = SDIO_MUX_HDR_MAGIC_NO;
- hdr.cmd = SDIO_MUX_HDR_CMD_CLOSE;
- hdr.reserved = 0;
- hdr.ch_id = id;
- hdr.pkt_len = 0;
- hdr.pad_len = 0;
-
- sdio_mux_write_cmd((void *)&hdr, sizeof(hdr));
-
- pr_info("%s: closed ch %d\n", __func__, id);
- return 0;
-}
-
-static void sdio_mux_notify(void *_dev, unsigned event)
-{
- DBG("%s: event %d notified\n", __func__, event);
-
- /* write avail may not be enouogh for a packet, but should be fine */
- if ((event == SDIO_EVENT_DATA_WRITE_AVAIL) &&
- sdio_write_avail(sdio_mux_ch))
- queue_work(sdio_mux_workqueue, &work_sdio_mux_write);
-
- if ((event == SDIO_EVENT_DATA_READ_AVAIL) &&
- sdio_read_avail(sdio_mux_ch))
- queue_work(sdio_mux_workqueue, &work_sdio_mux_read);
-}
-
-int msm_sdio_dmux_is_ch_full(uint32_t id)
-{
- unsigned long flags;
- int ret;
-
- if (id >= SDIO_DMUX_NUM_CHANNELS)
- return -EINVAL;
-
- spin_lock_irqsave(&sdio_ch[id].lock, flags);
- sdio_ch[id].use_wm = 1;
- ret = sdio_ch[id].num_tx_pkts >= HIGH_WATERMARK;
- DBG("%s: ch %d num tx pkts=%d, HWM=%d\n", __func__,
- id, sdio_ch[id].num_tx_pkts, ret);
- if (!sdio_ch_is_local_open(id)) {
- ret = -ENODEV;
- pr_err("%s: port not open: %d\n", __func__, sdio_ch[id].status);
- }
- spin_unlock_irqrestore(&sdio_ch[id].lock, flags);
-
- return ret;
-}
-
-int msm_sdio_dmux_is_ch_low(uint32_t id)
-{
- int ret;
-
- if (id >= SDIO_DMUX_NUM_CHANNELS)
- return -EINVAL;
-
- sdio_ch[id].use_wm = 1;
- ret = sdio_ch[id].num_tx_pkts <= LOW_WATERMARK;
- DBG("%s: ch %d num tx pkts=%d, LWM=%d\n", __func__,
- id, sdio_ch[id].num_tx_pkts, ret);
- if (!sdio_ch_is_local_open(id)) {
- ret = -ENODEV;
- pr_err("%s: port not open: %d\n", __func__, sdio_ch[id].status);
- }
-
- return ret;
-}
-
-#ifdef CONFIG_DEBUG_FS
-
-static int debug_tbl(char *buf, int max)
-{
- int i = 0;
- int j;
-
- for (j = 0; j < SDIO_DMUX_NUM_CHANNELS; ++j) {
- i += scnprintf(buf + i, max - i,
- "ch%02d local open=%s remote open=%s\n",
- j, sdio_ch_is_local_open(j) ? "Y" : "N",
- sdio_ch_is_remote_open(j) ? "Y" : "N");
- }
-
- return i;
-}
-
-#define DEBUG_BUFMAX 4096
-static char debug_buffer[DEBUG_BUFMAX];
-
-static ssize_t debug_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- int (*fill)(char *buf, int max) = file->private_data;
- int bsize = fill(debug_buffer, DEBUG_BUFMAX);
- return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
-}
-
-static int debug_open(struct inode *inode, struct file *file)
-{
- file->private_data = inode->i_private;
- return 0;
-}
-
-
-static const struct file_operations debug_ops = {
- .read = debug_read,
- .open = debug_open,
-};
-
-static void debug_create(const char *name, mode_t mode,
- struct dentry *dent,
- int (*fill)(char *buf, int max))
-{
- debugfs_create_file(name, mode, dent, fill, &debug_ops);
-}
-
-#endif
-
-static int sdio_dmux_probe(struct platform_device *pdev)
-{
- int rc;
-
- DBG("%s probe called\n", __func__);
-
- if (!sdio_mux_initialized) {
- sdio_mux_workqueue = create_singlethread_workqueue("sdio_dmux");
- if (!sdio_mux_workqueue)
- return -ENOMEM;
-
- skb_queue_head_init(&sdio_mux_write_pool);
- spin_lock_init(&sdio_mux_write_lock);
-
- for (rc = 0; rc < SDIO_DMUX_NUM_CHANNELS; ++rc)
- spin_lock_init(&sdio_ch[rc].lock);
-
-
- wake_lock_init(&sdio_mux_ch_wakelock, WAKE_LOCK_SUSPEND,
- "sdio_dmux");
- }
-
- rc = sdio_open("SDIO_RMNT", &sdio_mux_ch, NULL, sdio_mux_notify);
- if (rc < 0) {
- pr_err("%s: sido open failed %d\n", __func__, rc);
- wake_lock_destroy(&sdio_mux_ch_wakelock);
- destroy_workqueue(sdio_mux_workqueue);
- sdio_mux_initialized = 0;
- return rc;
- }
-
- fatal_error = 0;
- sdio_mux_initialized = 1;
- return 0;
-}
-
-static int sdio_dmux_remove(struct platform_device *pdev)
-{
- int i;
- unsigned long ch_lock_flags;
- unsigned long write_lock_flags;
- struct sk_buff *skb;
-
- DBG("%s remove called\n", __func__);
- if (!sdio_mux_initialized)
- return 0;
-
- /* set reset state for any open channels */
- for (i = 0; i < SDIO_DMUX_NUM_CHANNELS; ++i) {
- spin_lock_irqsave(&sdio_ch[i].lock, ch_lock_flags);
- if (sdio_ch_is_open(i)) {
- sdio_ch[i].status |= SDIO_CH_IN_RESET;
- sdio_ch[i].status &= ~SDIO_CH_REMOTE_OPEN;
-
- /* notify client so it can update its status */
- if (sdio_ch[i].receive_cb)
- sdio_ch[i].receive_cb(
- sdio_ch[i].priv, NULL);
- }
- spin_unlock_irqrestore(&sdio_ch[i].lock, ch_lock_flags);
- }
-
- /* cancel any pending writes */
- spin_lock_irqsave(&sdio_mux_write_lock, write_lock_flags);
- while ((skb = __skb_dequeue(&sdio_mux_write_pool))) {
- i = ((struct sdio_mux_hdr *)skb->data)->ch_id;
- if (sdio_ch[i].write_done)
- sdio_ch[i].write_done(
- sdio_ch[i].priv, skb);
- else
- dev_kfree_skb_any(skb);
- }
- spin_unlock_irqrestore(&sdio_mux_write_lock,
- write_lock_flags);
-
- return 0;
-}
-
-static struct platform_driver sdio_dmux_driver = {
- .probe = sdio_dmux_probe,
- .remove = sdio_dmux_remove,
- .driver = {
- .name = "SDIO_RMNT",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init sdio_dmux_init(void)
-{
-#ifdef CONFIG_DEBUG_FS
- struct dentry *dent;
-
- dent = debugfs_create_dir("sdio_dmux", 0);
- if (!IS_ERR(dent))
- debug_create("tbl", 0444, dent, debug_tbl);
-#endif
- return platform_driver_register(&sdio_dmux_driver);
-}
-
-module_init(sdio_dmux_init);
-MODULE_DESCRIPTION("MSM SDIO DMUX");
-MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/sdio_smem.c b/arch/arm/mach-msm/sdio_smem.c
deleted file mode 100644
index edc0d23..0000000
--- a/arch/arm/mach-msm/sdio_smem.c
+++ /dev/null
@@ -1,175 +0,0 @@
-/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#define pr_fmt(fmt) "%s: " fmt, __func__
-
-#include <linux/sched.h>
-#include <linux/wait.h>
-#include <linux/workqueue.h>
-#include <linux/module.h>
-#include <mach/sdio_al.h>
-#include <mach/sdio_smem.h>
-
-static void sdio_smem_read(struct work_struct *work);
-
-static struct sdio_channel *channel;
-static struct workqueue_struct *workq;
-static DECLARE_WORK(work_read, sdio_smem_read);
-static DECLARE_WAIT_QUEUE_HEAD(waitq);
-static int bytes_avail;
-static int sdio_ch_opened;
-
-static void sdio_smem_release(struct device *dev)
-{
- pr_debug("sdio smem released\n");
-}
-
-static struct sdio_smem_client client;
-
-static void sdio_smem_read(struct work_struct *work)
-{
- int err;
- int read_avail;
- char *data = client.buf;
-
- if (!sdio_ch_opened)
- return;
-
- read_avail = sdio_read_avail(channel);
- if (read_avail > bytes_avail ||
- read_avail < 0) {
- pr_err("Error: read_avail=%d bytes_avail=%d\n",
- read_avail, bytes_avail);
- goto read_err;
- }
-
- if (read_avail == 0)
- return;
-
- err = sdio_read(channel,
- &data[client.size - bytes_avail],
- read_avail);
- if (err) {
- pr_err("sdio_read error (%d)", err);
- goto read_err;
- }
-
- bytes_avail -= read_avail;
- pr_debug("read %d bytes (bytes_avail = %d)\n",
- read_avail, bytes_avail);
-
- if (!bytes_avail) {
- bytes_avail = client.size;
- err = client.cb_func(SDIO_SMEM_EVENT_READ_DONE);
- }
- if (err)
- pr_err("error (%d) on callback\n", err);
-
- return;
-
-read_err:
- if (sdio_ch_opened)
- client.cb_func(SDIO_SMEM_EVENT_READ_ERR);
- return;
-}
-
-static void sdio_smem_notify(void *priv, unsigned event)
-{
- pr_debug("%d event received\n", event);
-
- if (event == SDIO_EVENT_DATA_READ_AVAIL ||
- event == SDIO_EVENT_DATA_WRITE_AVAIL)
- queue_work(workq, &work_read);
-}
-
-int sdio_smem_register_client(void)
-{
- int err = 0;
-
- if (!client.buf || !client.size || !client.cb_func)
- return -EINVAL;
-
- pr_debug("buf = %p\n", client.buf);
- pr_debug("size = 0x%x\n", client.size);
-
- bytes_avail = client.size;
- workq = create_singlethread_workqueue("sdio_smem");
- if (!workq)
- return -ENOMEM;
-
- sdio_ch_opened = 1;
- err = sdio_open("SDIO_SMEM", &channel, NULL, sdio_smem_notify);
- if (err) {
- sdio_ch_opened = 0;
- pr_err("sdio_open error (%d)\n", err);
- destroy_workqueue(workq);
- return err;
- }
- pr_debug("SDIO SMEM channel opened\n");
- return err;
-}
-
-int sdio_smem_unregister_client(void)
-{
- int err = 0;
-
- sdio_ch_opened = 0;
- err = sdio_close(channel);
- if (err) {
- pr_err("sdio_close error (%d)\n", err);
- return err;
- }
- pr_debug("SDIO SMEM channel closed\n");
- flush_workqueue(workq);
- destroy_workqueue(workq);
- bytes_avail = 0;
- client.buf = NULL;
- client.cb_func = NULL;
- client.size = 0;
-
- return 0;
-}
-
-static int sdio_smem_probe(struct platform_device *pdev)
-{
- client.plat_dev.name = "SDIO_SMEM_CLIENT";
- client.plat_dev.id = -1;
- client.plat_dev.dev.release = sdio_smem_release;
-
- return platform_device_register(&client.plat_dev);
-}
-
-static int sdio_smem_remove(struct platform_device *pdev)
-{
- platform_device_unregister(&client.plat_dev);
- memset(&client, 0, sizeof(client));
- sdio_ch_opened = 0;
- return 0;
-}
-static struct platform_driver sdio_smem_drv = {
- .probe = sdio_smem_probe,
- .remove = sdio_smem_remove,
- .driver = {
- .name = "SDIO_SMEM",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init sdio_smem_init(void)
-{
- return platform_driver_register(&sdio_smem_drv);
-};
-
-module_init(sdio_smem_init);
-
-MODULE_DESCRIPTION("SDIO SMEM");
-MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/sdio_tty.c b/arch/arm/mach-msm/sdio_tty.c
deleted file mode 100644
index c4b7673..0000000
--- a/arch/arm/mach-msm/sdio_tty.c
+++ /dev/null
@@ -1,824 +0,0 @@
-/* Copyright (c) 2011, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/wait.h>
-#include <linux/workqueue.h>
-#include <linux/platform_device.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/module.h>
-#include <linux/debugfs.h>
-#include <mach/sdio_al.h>
-
-#define INPUT_SPEED 4800
-#define OUTPUT_SPEED 4800
-#define SDIO_TTY_MODULE_NAME "sdio_tty"
-#define SDIO_TTY_MAX_PACKET_SIZE 4096
-#define MAX_SDIO_TTY_DRV 1
-#define MAX_SDIO_TTY_DEVS 2
-#define MAX_SDIO_TTY_DEV_NAME_SIZE 25
-
-/* Configurations per channel device */
-/* CSVT */
-#define SDIO_TTY_CSVT_DEV "sdio_tty_csvt_0"
-#define SDIO_TTY_CSVT_TEST_DEV "sdio_tty_csvt_test_0"
-#define SDIO_TTY_CH_CSVT "SDIO_CSVT"
-
-enum sdio_tty_state {
- TTY_INITIAL = 0,
- TTY_REGISTERED = 1,
- TTY_OPENED = 2,
- TTY_CLOSED = 3,
-};
-
-enum sdio_tty_devices {
- SDIO_CSVT,
- SDIO_CSVT_TEST_APP,
-};
-
-static const struct platform_device_id sdio_tty_id_table[] = {
- { "SDIO_CSVT", SDIO_CSVT },
- { "SDIO_CSVT_TEST_APP", SDIO_CSVT_TEST_APP },
- { },
-};
-MODULE_DEVICE_TABLE(platform, sdio_tty_id_table);
-
-struct sdio_tty {
- struct sdio_channel *ch;
- char *sdio_ch_name;
- char tty_dev_name[MAX_SDIO_TTY_DEV_NAME_SIZE];
- int device_id;
- struct workqueue_struct *workq;
- struct work_struct work_read;
- wait_queue_head_t waitq;
- struct tty_driver *tty_drv;
- struct tty_struct *tty_str;
- int debug_msg_on;
- char *read_buf;
- enum sdio_tty_state sdio_tty_state;
- int is_sdio_open;
- int tty_open_count;
- int total_rx;
- int total_tx;
-};
-
-static struct sdio_tty *sdio_tty[MAX_SDIO_TTY_DEVS];
-
-#ifdef CONFIG_DEBUG_FS
-struct dentry *sdio_tty_debug_root;
-struct dentry *sdio_tty_debug_info;
-#endif
-
-#define DEBUG_MSG(sdio_tty_drv, x...) if (sdio_tty_drv->debug_msg_on) pr_info(x)
-
-/*
- * Enable sdio_tty debug messages
- * By default the sdio_tty debug messages are turned off
- */
-static int csvt_debug_msg_on;
-module_param(csvt_debug_msg_on, int, 0);
-
-static void sdio_tty_read(struct work_struct *work)
-{
- int ret = 0;
- int read_avail = 0;
- int left = 0;
- int total_push = 0;
- int num_push = 0;
- struct sdio_tty *sdio_tty_drv = NULL;
-
- sdio_tty_drv = container_of(work, struct sdio_tty, work_read);
-
- if (!sdio_tty_drv) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty", __func__);
- return ;
- }
-
- if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_state = %d",
- __func__, sdio_tty_drv->sdio_tty_state);
- return;
- }
-
- if (!sdio_tty_drv->read_buf) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL read_buf for dev %s",
- __func__, sdio_tty_drv->tty_dev_name);
- return;
- }
-
- /* Read the data from the SDIO channel as long as there is available
- data */
- while (1) {
- if (test_bit(TTY_THROTTLED, &sdio_tty_drv->tty_str->flags)) {
- DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME
- ": %s: TTY_THROTTLED bit is set for "
- "dev %s, exit", __func__,
- sdio_tty_drv->tty_dev_name);
- return;
- }
-
- total_push = 0;
- read_avail = sdio_read_avail(sdio_tty_drv->ch);
-
- DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME
- ": %s: read_avail is %d for dev %s", __func__,
- read_avail, sdio_tty_drv->tty_dev_name);
-
- if (read_avail == 0) {
- DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME
- ": %s: read_avail is 0 for dev %s",
- __func__, sdio_tty_drv->tty_dev_name);
- return;
- }
-
- if (read_avail > SDIO_TTY_MAX_PACKET_SIZE) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: read_avail(%d) is "
- "bigger than SDIO_TTY_MAX_PACKET_SIZE(%d) "
- "for dev %s", __func__, read_avail,
- SDIO_TTY_MAX_PACKET_SIZE,
- sdio_tty_drv->tty_dev_name);
- return;
- }
-
- ret = sdio_read(sdio_tty_drv->ch,
- sdio_tty_drv->read_buf,
- read_avail);
- if (ret < 0) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_read error(%d) "
- "for dev %s", __func__, ret,
- sdio_tty_drv->tty_dev_name);
- return;
- }
-
- left = read_avail;
- do {
- num_push = tty_insert_flip_string(
- sdio_tty_drv->tty_str,
- sdio_tty_drv->read_buf+total_push,
- left);
- total_push += num_push;
- left -= num_push;
- tty_flip_buffer_push(sdio_tty_drv->tty_str);
- } while (left != 0);
-
- if (total_push != read_avail) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: failed, total_push"
- "(%d) != read_avail(%d) for dev %s\n",
- __func__, total_push, read_avail,
- sdio_tty_drv->tty_dev_name);
- }
-
- tty_flip_buffer_push(sdio_tty_drv->tty_str);
- sdio_tty_drv->total_rx += read_avail;
-
- DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: Rx: %d, "
- "Total Rx = %d bytes for dev %s", __func__,
- read_avail, sdio_tty_drv->total_rx,
- sdio_tty_drv->tty_dev_name);
- }
-}
-
-/**
- * sdio_tty_write_room
- *
- * This is the write_room function of the tty driver.
- *
- * @tty: pointer to tty struct.
- * @return free bytes for write.
- *
- */
-static int sdio_tty_write_room(struct tty_struct *tty)
-{
- int write_avail = 0;
- struct sdio_tty *sdio_tty_drv = NULL;
-
- if (!tty) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty", __func__);
- return -ENODEV;
- }
- sdio_tty_drv = tty->driver_data;
- if (!sdio_tty_drv) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
- __func__);
- return -ENODEV;
- }
-
- if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_state = %d",
- __func__, sdio_tty_drv->sdio_tty_state);
- return -EPERM;
- }
-
- write_avail = sdio_write_avail(sdio_tty_drv->ch);
- DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: write_avail=%d "
- "for dev %s", __func__, write_avail,
- sdio_tty_drv->tty_dev_name);
-
- return write_avail;
-}
-
-/**
- * sdio_tty_write_callback
- * this is the write callback of the tty driver.
- *
- * @tty: pointer to tty struct.
- * @buf: buffer to write from.
- * @count: number of bytes to write.
- * @return bytes written or negative value on error.
- *
- * if destination buffer has not enough room for the incoming
- * data, writes the possible amount of bytes .
- */
-static int sdio_tty_write_callback(struct tty_struct *tty,
- const unsigned char *buf, int count)
-{
- int write_avail = 0;
- int len = count;
- int ret = 0;
- struct sdio_tty *sdio_tty_drv = NULL;
-
- if (!tty) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty", __func__);
- return -ENODEV;
- }
- sdio_tty_drv = tty->driver_data;
- if (!sdio_tty_drv) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
- __func__);
- return -ENODEV;
- }
-
- if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_state = %d",
- __func__, sdio_tty_drv->sdio_tty_state);
- return -EPERM;
- }
-
- DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: Write Callback "
- "called with %d bytes for dev %s\n", __func__, count,
- sdio_tty_drv->tty_dev_name);
- write_avail = sdio_write_avail(sdio_tty_drv->ch);
- if (write_avail == 0) {
- DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: "
- "write_avail is 0 for dev %s\n",
- __func__, sdio_tty_drv->tty_dev_name);
- return 0;
- }
- if (write_avail > SDIO_TTY_MAX_PACKET_SIZE) {
- DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: "
- "write_avail(%d) is bigger than max packet "
- "size(%d) for dev %s, setting to "
- "max_packet_size\n", __func__, write_avail,
- SDIO_TTY_MAX_PACKET_SIZE,
- sdio_tty_drv->tty_dev_name);
- write_avail = SDIO_TTY_MAX_PACKET_SIZE;
- }
- if (write_avail < count) {
- DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: "
- "write_avail(%d) is smaller than required(%d) "
- "for dev %s, writing only %d bytes\n",
- __func__, write_avail, count,
- sdio_tty_drv->tty_dev_name, write_avail);
- len = write_avail;
- }
- ret = sdio_write(sdio_tty_drv->ch, buf, len);
- if (ret) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_write failed for "
- "dev %s, ret=%d\n", __func__,
- sdio_tty_drv->tty_dev_name, ret);
- return 0;
- }
-
- sdio_tty_drv->total_tx += len;
-
- DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: Tx: %d, "
- "Total Tx = %d for dev %s", __func__, len,
- sdio_tty_drv->total_tx, sdio_tty_drv->tty_dev_name);
- return len;
-}
-
-static void sdio_tty_notify(void *priv, unsigned event)
-{
- struct sdio_tty *sdio_tty_drv = priv;
-
- if (!sdio_tty_drv) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
- __func__);
- }
-
- if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_state = %d",
- __func__, sdio_tty_drv->sdio_tty_state);
- return;
- }
-
- DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: event %d "
- "received for dev %s\n", __func__, event,
- sdio_tty_drv->tty_dev_name);
-
- if (event == SDIO_EVENT_DATA_READ_AVAIL)
- queue_work(sdio_tty_drv->workq, &sdio_tty_drv->work_read);
-}
-
-/**
- * sdio_tty_open
- * This is the open callback of the tty driver. it opens
- * the sdio channel, and creates the workqueue.
- *
- * @tty: a pointer to the tty struct.
- * @file: file descriptor.
- * @return 0 on success or negative value on error.
- */
-static int sdio_tty_open(struct tty_struct *tty, struct file *file)
-{
- int ret = 0;
- int i = 0;
- struct sdio_tty *sdio_tty_drv = NULL;
-
- if (!tty) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty", __func__);
- return -ENODEV;
- }
-
- for (i = 0; i < MAX_SDIO_TTY_DEVS; i++) {
- if (sdio_tty[i] == NULL)
- continue;
- if (!strncmp(sdio_tty[i]->tty_dev_name, tty->name,
- MAX_SDIO_TTY_DEV_NAME_SIZE)) {
- sdio_tty_drv = sdio_tty[i];
- break;
- }
- }
-
- if (!sdio_tty_drv) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
- __func__);
- return -ENODEV;
- }
-
- sdio_tty_drv->tty_open_count++;
- if (sdio_tty_drv->sdio_tty_state == TTY_OPENED) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: tty dev(%s) is already open",
- __func__, sdio_tty_drv->tty_dev_name);
- return -EBUSY;
- }
-
- tty->driver_data = sdio_tty_drv;
-
- sdio_tty_drv->tty_str = tty;
- sdio_tty_drv->tty_str->low_latency = 1;
- sdio_tty_drv->tty_str->icanon = 0;
- set_bit(TTY_NO_WRITE_SPLIT, &sdio_tty_drv->tty_str->flags);
-
- sdio_tty_drv->read_buf = kzalloc(SDIO_TTY_MAX_PACKET_SIZE, GFP_KERNEL);
- if (sdio_tty_drv->read_buf == NULL) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: failed to allocate read_buf "
- "for dev %s", __func__, sdio_tty_drv->tty_dev_name);
- return -ENOMEM;
- }
-
- sdio_tty_drv->workq = create_singlethread_workqueue("sdio_tty_read");
- if (!sdio_tty_drv->workq) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: failed to create workq "
- "for dev %s", __func__, sdio_tty_drv->tty_dev_name);
- return -ENOMEM;
- }
-
- if (!sdio_tty_drv->is_sdio_open) {
- ret = sdio_open(sdio_tty_drv->sdio_ch_name, &sdio_tty_drv->ch,
- sdio_tty_drv, sdio_tty_notify);
- if (ret < 0) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_open err=%d "
- "for dev %s\n", __func__, ret,
- sdio_tty_drv->tty_dev_name);
- destroy_workqueue(sdio_tty_drv->workq);
- return ret;
- }
-
- pr_info(SDIO_TTY_MODULE_NAME ": %s: SDIO_TTY channel(%s) "
- "opened\n", __func__, sdio_tty_drv->sdio_ch_name);
-
- sdio_tty_drv->is_sdio_open = 1;
- } else {
- /* If SDIO channel is already open try to read the data
- * from the modem
- */
- queue_work(sdio_tty_drv->workq, &sdio_tty_drv->work_read);
-
- }
-
- sdio_tty_drv->sdio_tty_state = TTY_OPENED;
-
- pr_info(SDIO_TTY_MODULE_NAME ": %s: TTY device(%s) opened\n",
- __func__, sdio_tty_drv->tty_dev_name);
-
- return ret;
-}
-
-/**
- * sdio_tty_close
- * This is the close callback of the tty driver. it requests
- * the main thread to exit, and waits for notification of it.
- * it also de-allocates the buffers, and unregisters the tty
- * driver and device.
- *
- * @tty: a pointer to the tty struct.
- * @file: file descriptor.
- * @return None.
- */
-static void sdio_tty_close(struct tty_struct *tty, struct file *file)
-{
- struct sdio_tty *sdio_tty_drv = NULL;
-
- if (!tty) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty", __func__);
- return;
- }
- sdio_tty_drv = tty->driver_data;
- if (!sdio_tty_drv) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
- __func__);
- return;
- }
- if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: trying to close a "
- "TTY device that was not opened\n", __func__);
- return;
- }
- if (--sdio_tty_drv->tty_open_count != 0)
- return;
-
- flush_workqueue(sdio_tty_drv->workq);
- destroy_workqueue(sdio_tty_drv->workq);
-
- kfree(sdio_tty_drv->read_buf);
- sdio_tty_drv->read_buf = NULL;
-
- sdio_tty_drv->sdio_tty_state = TTY_CLOSED;
-
- pr_info(SDIO_TTY_MODULE_NAME ": %s: SDIO_TTY device(%s) closed\n",
- __func__, sdio_tty_drv->tty_dev_name);
-}
-
-static void sdio_tty_unthrottle(struct tty_struct *tty)
-{
- struct sdio_tty *sdio_tty_drv = NULL;
-
- if (!tty) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty", __func__);
- return;
- }
- sdio_tty_drv = tty->driver_data;
- if (!sdio_tty_drv) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
- __func__);
- return;
- }
-
- if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_state = %d",
- __func__, sdio_tty_drv->sdio_tty_state);
- return;
- }
-
- queue_work(sdio_tty_drv->workq, &sdio_tty_drv->work_read);
- return;
-}
-
-static const struct tty_operations sdio_tty_ops = {
- .open = sdio_tty_open,
- .close = sdio_tty_close,
- .write = sdio_tty_write_callback,
- .write_room = sdio_tty_write_room,
- .unthrottle = sdio_tty_unthrottle,
-};
-
-int sdio_tty_init_tty(char *tty_name, char *sdio_ch_name,
- enum sdio_tty_devices device_id, int debug_msg_on)
-{
- int ret = 0;
- int i = 0;
- struct device *tty_dev = NULL;
- struct sdio_tty *sdio_tty_drv = NULL;
-
- sdio_tty_drv = kzalloc(sizeof(struct sdio_tty), GFP_KERNEL);
- if (sdio_tty_drv == NULL) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: failed to allocate sdio_tty "
- "for dev %s", __func__, tty_name);
- return -ENOMEM;
- }
-
- for (i = 0; i < MAX_SDIO_TTY_DEVS; i++) {
- if (sdio_tty[i] == NULL) {
- sdio_tty[i] = sdio_tty_drv;
- break;
- }
- }
-
- if (i == MAX_SDIO_TTY_DEVS) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: tty dev(%s) creation failed,"
- " max limit(%d) reached.", __func__, tty_name,
- MAX_SDIO_TTY_DEVS);
- kfree(sdio_tty_drv);
- return -ENODEV;
- }
-
- snprintf(sdio_tty_drv->tty_dev_name, MAX_SDIO_TTY_DEV_NAME_SIZE,
- "%s%d", tty_name, 0);
- sdio_tty_drv->sdio_ch_name = sdio_ch_name;
- sdio_tty_drv->device_id = device_id;
- pr_info(SDIO_TTY_MODULE_NAME ": %s: dev=%s, id=%d, channel=%s\n",
- __func__, sdio_tty_drv->tty_dev_name, sdio_tty_drv->device_id,
- sdio_tty_drv->sdio_ch_name);
-
- INIT_WORK(&sdio_tty_drv->work_read, sdio_tty_read);
-
- sdio_tty_drv->tty_drv = alloc_tty_driver(MAX_SDIO_TTY_DRV);
-
- if (!sdio_tty_drv->tty_drv) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s - tty_drv is NULL for dev %s",
- __func__, sdio_tty_drv->tty_dev_name);
- kfree(sdio_tty_drv);
- return -ENODEV;
- }
-
- sdio_tty_drv->tty_drv->name = tty_name;
- sdio_tty_drv->tty_drv->owner = THIS_MODULE;
- sdio_tty_drv->tty_drv->driver_name = "SDIO_tty";
- /* uses dynamically assigned dev_t values */
- sdio_tty_drv->tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
- sdio_tty_drv->tty_drv->subtype = SERIAL_TYPE_NORMAL;
- sdio_tty_drv->tty_drv->flags = TTY_DRIVER_REAL_RAW
- | TTY_DRIVER_DYNAMIC_DEV
- | TTY_DRIVER_RESET_TERMIOS;
-
- /* initializing the tty driver */
- sdio_tty_drv->tty_drv->init_termios = tty_std_termios;
- sdio_tty_drv->tty_drv->init_termios.c_cflag =
- B4800 | CS8 | CREAD | HUPCL | CLOCAL;
- sdio_tty_drv->tty_drv->init_termios.c_ispeed = INPUT_SPEED;
- sdio_tty_drv->tty_drv->init_termios.c_ospeed = OUTPUT_SPEED;
-
- tty_set_operations(sdio_tty_drv->tty_drv, &sdio_tty_ops);
-
- ret = tty_register_driver(sdio_tty_drv->tty_drv);
- if (ret) {
- put_tty_driver(sdio_tty_drv->tty_drv);
- pr_err(SDIO_TTY_MODULE_NAME ": %s: tty_register_driver() "
- "failed for dev %s\n", __func__,
- sdio_tty_drv->tty_dev_name);
-
- sdio_tty_drv->tty_drv = NULL;
- kfree(sdio_tty_drv);
- return -ENODEV;
- }
-
- tty_dev = tty_register_device(sdio_tty_drv->tty_drv, 0, NULL);
- if (IS_ERR(tty_dev)) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: tty_register_device() "
- "failed for dev %s\n", __func__,
- sdio_tty_drv->tty_dev_name);
- tty_unregister_driver(sdio_tty_drv->tty_drv);
- put_tty_driver(sdio_tty_drv->tty_drv);
- kfree(sdio_tty_drv);
- return -ENODEV;
- }
-
- sdio_tty_drv->sdio_tty_state = TTY_REGISTERED;
- if (debug_msg_on) {
- pr_info(SDIO_TTY_MODULE_NAME ": %s: turn on debug msg for %s",
- __func__, sdio_tty_drv->tty_dev_name);
- sdio_tty_drv->debug_msg_on = debug_msg_on;
- }
- return 0;
-}
-
-int sdio_tty_uninit_tty(void *sdio_tty_handle)
-{
- int ret = 0;
- int i = 0;
- struct sdio_tty *sdio_tty_drv = sdio_tty_handle;
-
- if (!sdio_tty_drv) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
- __func__);
- return -ENODEV;
- }
- if (sdio_tty_drv->sdio_tty_state == TTY_OPENED) {
- flush_workqueue(sdio_tty_drv->workq);
- destroy_workqueue(sdio_tty_drv->workq);
-
- kfree(sdio_tty_drv->read_buf);
- sdio_tty_drv->read_buf = NULL;
- }
-
- if (sdio_tty_drv->sdio_tty_state != TTY_INITIAL) {
- tty_unregister_device(sdio_tty_drv->tty_drv, 0);
-
- ret = tty_unregister_driver(sdio_tty_drv->tty_drv);
- if (ret) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: "
- "tty_unregister_driver() failed for dev %s\n",
- __func__, sdio_tty_drv->tty_dev_name);
- }
- put_tty_driver(sdio_tty_drv->tty_drv);
- sdio_tty_drv->sdio_tty_state = TTY_INITIAL;
- sdio_tty_drv->tty_drv = NULL;
- }
-
- for (i = 0; i < MAX_SDIO_TTY_DEVS; i++) {
- if (sdio_tty[i] == NULL)
- continue;
- if (sdio_tty[i]->device_id == sdio_tty_drv->device_id) {
- sdio_tty[i] = NULL;
- break;
- }
- }
-
- DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: Freeing sdio_tty "
- "structure, dev=%s", __func__,
- sdio_tty_drv->tty_dev_name);
- kfree(sdio_tty_drv);
-
- return 0;
-}
-
-static int sdio_tty_probe(struct platform_device *pdev)
-{
- const struct platform_device_id *id = platform_get_device_id(pdev);
- enum sdio_tty_devices device_id = id->driver_data;
- char *device_name = NULL;
- char *channel_name = NULL;
- int debug_msg_on = 0;
- int ret = 0;
-
- pr_debug(SDIO_TTY_MODULE_NAME ": %s for %s", __func__, pdev->name);
-
- switch (device_id) {
- case SDIO_CSVT:
- device_name = SDIO_TTY_CSVT_DEV;
- channel_name = SDIO_TTY_CH_CSVT;
- debug_msg_on = csvt_debug_msg_on;
- break;
- case SDIO_CSVT_TEST_APP:
- device_name = SDIO_TTY_CSVT_TEST_DEV;
- channel_name = SDIO_TTY_CH_CSVT;
- debug_msg_on = csvt_debug_msg_on;
- break;
- default:
- pr_err(SDIO_TTY_MODULE_NAME ": %s Invalid device:%s, id:%d",
- __func__, pdev->name, device_id);
- ret = -ENODEV;
- break;
- }
-
- if (device_name) {
- ret = sdio_tty_init_tty(device_name, channel_name,
- device_id, debug_msg_on);
- if (ret) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_init_tty "
- "failed for dev:%s", __func__, device_name);
- }
- }
- return ret;
-}
-
-static int sdio_tty_remove(struct platform_device *pdev)
-{
- const struct platform_device_id *id = platform_get_device_id(pdev);
- enum sdio_tty_devices device_id = id->driver_data;
- struct sdio_tty *sdio_tty_drv = NULL;
- int i = 0;
- int ret = 0;
-
- pr_debug(SDIO_TTY_MODULE_NAME ": %s for %s", __func__, pdev->name);
-
- for (i = 0; i < MAX_SDIO_TTY_DEVS; i++) {
- if (sdio_tty[i] == NULL)
- continue;
- if (sdio_tty[i]->device_id == device_id) {
- sdio_tty_drv = sdio_tty[i];
- break;
- }
- }
-
- if (!sdio_tty_drv) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
- __func__);
- return -ENODEV;
- }
-
- ret = sdio_tty_uninit_tty(sdio_tty_drv);
- if (ret) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_uninit_tty "
- "failed for %s", __func__, pdev->name);
- }
- return ret;
-}
-
-static struct platform_driver sdio_tty_pdrv = {
- .probe = sdio_tty_probe,
- .remove = sdio_tty_remove,
- .id_table = sdio_tty_id_table,
- .driver = {
- .name = "SDIO_TTY",
- .owner = THIS_MODULE,
- },
-};
-
-#ifdef CONFIG_DEBUG_FS
-void sdio_tty_print_info(void)
-{
- int i = 0;
-
- for (i = 0; i < MAX_SDIO_TTY_DEVS; i++) {
- if (sdio_tty[i] == NULL)
- continue;
- pr_info(SDIO_TTY_MODULE_NAME ": %s: Total Rx=%d, Tx = %d "
- "for dev %s", __func__, sdio_tty[i]->total_rx,
- sdio_tty[i]->total_tx, sdio_tty[i]->tty_dev_name);
- }
-}
-
-static int tty_debug_info_open(struct inode *inode, struct file *file)
-{
- file->private_data = inode->i_private;
- return 0;
-}
-
-static ssize_t tty_debug_info_write(struct file *file,
- const char __user *buf, size_t count, loff_t *ppos)
-{
- sdio_tty_print_info();
- return count;
-}
-
-const struct file_operations tty_debug_info_ops = {
- .open = tty_debug_info_open,
- .write = tty_debug_info_write,
-};
-#endif
-
-/*
- * Module Init.
- *
- * Register SDIO TTY driver.
- *
- */
-static int __init sdio_tty_init(void)
-{
- int ret = 0;
-
- ret = platform_driver_register(&sdio_tty_pdrv);
- if (ret) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: platform_driver_register "
- "failed", __func__);
- }
-#ifdef CONFIG_DEBUG_FS
- else {
- sdio_tty_debug_root = debugfs_create_dir("sdio_tty", NULL);
- if (sdio_tty_debug_root) {
- sdio_tty_debug_info = debugfs_create_file(
- "sdio_tty_debug",
- S_IRUGO | S_IWUGO,
- sdio_tty_debug_root,
- NULL,
- &tty_debug_info_ops);
- }
- }
-#endif
- return ret;
-};
-
-/*
- * Module Exit.
- *
- * Unregister SDIO TTY driver.
- *
- */
-static void __exit sdio_tty_exit(void)
-{
-#ifdef CONFIG_DEBUG_FS
- debugfs_remove(sdio_tty_debug_info);
- debugfs_remove(sdio_tty_debug_root);
-#endif
- platform_driver_unregister(&sdio_tty_pdrv);
-}
-
-module_init(sdio_tty_init);
-module_exit(sdio_tty_exit);
-
-MODULE_DESCRIPTION("SDIO TTY");
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Maya Erez <merez@codeaurora.org>");
diff --git a/arch/arm/mach-msm/sensors_adsp.c b/arch/arm/mach-msm/sensors_adsp.c
index 1534358..ad19e16 100644
--- a/arch/arm/mach-msm/sensors_adsp.c
+++ b/arch/arm/mach-msm/sensors_adsp.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This 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 <mach/msm_bus.h>
#include <mach/msm_bus_board.h>
+#define CLASS_NAME "ssc"
#define DRV_NAME "sensors"
#define DRV_VERSION "1.00"
@@ -355,6 +356,7 @@
if (temp == NULL) {
pr_err("%s: allocation failure\n", __func__);
rv = -ENOMEM;
+ goto out;
}
hdr->dst_module = SNS_OCMEM_MODULE_ADSP;
@@ -387,6 +389,7 @@
kfree(temp);
+out:
return rv;
}
@@ -874,7 +877,7 @@
vectors = ocmem_get_vectors(SNS_OCMEM_CLIENT_ID, sns_ctl.buf);
if ((vectors != NULL)) {
- memcpy(&msg.vectors, vectors, sizeof(vectors));
+ memcpy(&msg.vectors, vectors, sizeof(*vectors));
/* TODO: set vectors_len */
msg.vectors_valid = true;
msg.vectors_len = 0;
@@ -1077,7 +1080,7 @@
static int sensors_adsp_probe(struct platform_device *pdev)
{
int ret = 0;
- sns_ctl.dev_class = class_create(THIS_MODULE, DRV_NAME);
+ sns_ctl.dev_class = class_create(THIS_MODULE, CLASS_NAME);
if (sns_ctl.dev_class == NULL) {
pr_err("%s: class_create fail.\n", __func__);
goto res_err;
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index 110ab87..1241e44 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -2247,13 +2247,15 @@
* particular channel.
* @ch: open channel handle to use for the edge
* @mask: 1 = mask interrupts; 0 = unmask interrupts
+ * @cpumask cpumask for the next cpu scheduled to be woken up
* @returns: 0 for success; < 0 for failure
*
* Note that this enables/disables all interrupts from the remote subsystem for
* all channels. As such, it should be used with care and only for specific
* use cases such as power-collapse sequencing.
*/
-int smd_mask_receive_interrupt(smd_channel_t *ch, bool mask)
+int smd_mask_receive_interrupt(smd_channel_t *ch, bool mask,
+ const struct cpumask *cpumask)
{
struct irq_chip *irq_chip;
struct irq_data *irq_data;
@@ -2282,6 +2284,8 @@
SMD_POWER_INFO("SMD Masking interrupts from %s\n",
edge_to_pids[ch->type].subsys_name);
irq_chip->irq_mask(irq_data);
+ if (cpumask)
+ irq_set_affinity(int_cfg->irq_id, cpumask);
} else {
SMD_POWER_INFO("SMD Unmasking interrupts from %s\n",
edge_to_pids[ch->type].subsys_name);
@@ -3243,7 +3247,7 @@
*/
void smd_set_edge_subsys_name(uint32_t edge, const char *subsys_name)
{
- if (edge <= ARRAY_SIZE(edge_to_pids))
+ if (edge < ARRAY_SIZE(edge_to_pids))
strlcpy(edge_to_pids[edge].subsys_name,
subsys_name, SMD_MAX_CH_NAME_LEN);
else
@@ -3258,7 +3262,7 @@
*/
void smd_set_edge_initialized(uint32_t edge)
{
- if (edge <= ARRAY_SIZE(edge_to_pids))
+ if (edge < ARRAY_SIZE(edge_to_pids))
edge_to_pids[edge].initialized = true;
else
pr_err("%s: Invalid edge type[%d]\n", __func__, edge);
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 8af3890..e7cec58 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -36,7 +36,6 @@
#define SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE 128
#define SMEM_IMAGE_VERSION_SIZE 4096
#define SMEM_IMAGE_VERSION_NAME_SIZE 75
-#define SMEM_IMAGE_VERSION_NAME_OFFSET 3
#define SMEM_IMAGE_VERSION_VARIANT_SIZE 20
#define SMEM_IMAGE_VERSION_VARIANT_OFFSET 75
#define SMEM_IMAGE_VERSION_OEM_SIZE 32
@@ -859,8 +858,7 @@
return snprintf(buf, SMEM_IMAGE_VERSION_NAME_SIZE, "Unknown");
}
string_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
- string_address += SMEM_IMAGE_VERSION_NAME_OFFSET;
- return snprintf(buf, SMEM_IMAGE_VERSION_NAME_SIZE, "%-.72s\n",
+ return snprintf(buf, SMEM_IMAGE_VERSION_NAME_SIZE, "%-.75s\n",
string_address);
}
@@ -1080,7 +1078,7 @@
msm_get_image_crm_version, msm_set_image_crm_version);
static struct device_attribute select_image =
- __ATTR(select_image, S_IRUGO | S_IWUGO,
+ __ATTR(select_image, S_IRUGO | S_IWUSR,
msm_get_image_number, msm_select_image);
static struct sysdev_class soc_sysdev_class = {
diff --git a/arch/arm/mach-msm/spm.h b/arch/arm/mach-msm/spm.h
index 1769402..2946689 100644
--- a/arch/arm/mach-msm/spm.h
+++ b/arch/arm/mach-msm/spm.h
@@ -28,43 +28,6 @@
MSM_SPM_L2_MODE_POWER_COLLAPSE,
};
-#if defined(CONFIG_MSM_SPM_V1)
-
-enum {
- MSM_SPM_REG_SAW_AVS_CTL,
- MSM_SPM_REG_SAW_CFG,
- MSM_SPM_REG_SAW_SPM_CTL,
- MSM_SPM_REG_SAW_SPM_SLP_TMR_DLY,
- MSM_SPM_REG_SAW_SPM_WAKE_TMR_DLY,
- MSM_SPM_REG_SAW_SLP_CLK_EN,
- MSM_SPM_REG_SAW_SLP_HSFS_PRECLMP_EN,
- MSM_SPM_REG_SAW_SLP_HSFS_POSTCLMP_EN,
- MSM_SPM_REG_SAW_SLP_CLMP_EN,
- MSM_SPM_REG_SAW_SLP_RST_EN,
- MSM_SPM_REG_SAW_SPM_MPM_CFG,
- MSM_SPM_REG_NR_INITIALIZE,
-
- MSM_SPM_REG_SAW_VCTL = MSM_SPM_REG_NR_INITIALIZE,
- MSM_SPM_REG_SAW_STS,
- MSM_SPM_REG_SAW_SPM_PMIC_CTL,
- MSM_SPM_REG_NR
-};
-
-struct msm_spm_platform_data {
- void __iomem *reg_base_addr;
- uint32_t reg_init_values[MSM_SPM_REG_NR_INITIALIZE];
-
- uint8_t awake_vlevel;
- uint8_t retention_vlevel;
- uint8_t collapse_vlevel;
- uint8_t retention_mid_vlevel;
- uint8_t collapse_mid_vlevel;
-
- uint32_t vctl_timeout_us;
-};
-
-#elif defined(CONFIG_MSM_SPM_V2)
-
enum {
MSM_SPM_REG_SAW2_CFG,
MSM_SPM_REG_SAW2_AVS_CTL,
@@ -122,9 +85,8 @@
uint32_t num_modes;
struct msm_spm_seq_entry *modes;
};
-#endif
-#if defined(CONFIG_MSM_SPM_V1) || defined(CONFIG_MSM_SPM_V2)
+#if defined(CONFIG_MSM_SPM_V2)
/* Public functions */
@@ -187,7 +149,7 @@
return -ENOSYS;
}
#endif /* defined(CONFIG_MSM_L2_SPM) */
-#else /* defined(CONFIG_MSM_SPM_V1) || defined(CONFIG_MSM_SPM_V2) */
+#else /* defined(CONFIG_MSM_SPM_V2) */
static inline int msm_spm_set_low_power_mode(unsigned int mode, bool notify_rpm)
{
return -ENOSYS;
@@ -218,5 +180,5 @@
return -ENOSYS;
}
-#endif /*defined(CONFIG_MSM_SPM_V1) || defined (CONFIG_MSM_SPM_V2) */
+#endif /* defined (CONFIG_MSM_SPM_V2) */
#endif /* __ARCH_ARM_MACH_MSM_SPM_H */
diff --git a/arch/arm/mach-msm/test-lpm.c b/arch/arm/mach-msm/test-lpm.c
index 031b2dc..790c909 100644
--- a/arch/arm/mach-msm/test-lpm.c
+++ b/arch/arm/mach-msm/test-lpm.c
@@ -121,9 +121,6 @@
case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
strlcat(nm, "WFI ", BUF_SIZE);
break;
- case MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT:
- strlcat(nm, "WFI voltage Rampdown ", BUF_SIZE);
- break;
case MSM_PM_SLEEP_MODE_RETENTION:
strlcat(nm, "Retention ", BUF_SIZE);
break;
@@ -133,9 +130,6 @@
case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
strlcat(nm, "Idle Power collapse ", BUF_SIZE);
break;
- case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND:
- strlcat(nm, "Suspend Power collapse ", BUF_SIZE);
- break;
default:
strlcat(nm, "Invalid Mode ", BUF_SIZE);
break;
diff --git a/arch/arm/mm/cache-fa.S b/arch/arm/mm/cache-fa.S
index 0720163..e505bef 100644
--- a/arch/arm/mm/cache-fa.S
+++ b/arch/arm/mm/cache-fa.S
@@ -240,6 +240,9 @@
mov pc, lr
ENDPROC(fa_dma_unmap_area)
+ .globl fa_flush_kern_cache_louis
+ .equ fa_flush_kern_cache_louis, fa_flush_kern_cache_all
+
__INITDATA
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
diff --git a/arch/arm/mm/cache-v3.S b/arch/arm/mm/cache-v3.S
index c2301f2..d99c00c 100644
--- a/arch/arm/mm/cache-v3.S
+++ b/arch/arm/mm/cache-v3.S
@@ -127,6 +127,9 @@
ENDPROC(v3_dma_unmap_area)
ENDPROC(v3_dma_map_area)
+ .globl v3_flush_kern_cache_louis
+ .equ v3_flush_kern_cache_louis, v3_flush_kern_cache_all
+
__INITDATA
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
diff --git a/arch/arm/mm/cache-v4.S b/arch/arm/mm/cache-v4.S
index fd9bb7a..548b892a 100644
--- a/arch/arm/mm/cache-v4.S
+++ b/arch/arm/mm/cache-v4.S
@@ -139,6 +139,9 @@
ENDPROC(v4_dma_unmap_area)
ENDPROC(v4_dma_map_area)
+ .globl v4_flush_kern_cache_louis
+ .equ v4_flush_kern_cache_louis, v4_flush_kern_cache_all
+
__INITDATA
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
diff --git a/arch/arm/mm/cache-v4wb.S b/arch/arm/mm/cache-v4wb.S
index 4f2c141..63b7e49 100644
--- a/arch/arm/mm/cache-v4wb.S
+++ b/arch/arm/mm/cache-v4wb.S
@@ -251,6 +251,9 @@
mov pc, lr
ENDPROC(v4wb_dma_unmap_area)
+ .globl v4wb_flush_kern_cache_louis
+ .equ v4wb_flush_kern_cache_louis, v4wb_flush_kern_cache_all
+
__INITDATA
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
diff --git a/arch/arm/mm/cache-v4wt.S b/arch/arm/mm/cache-v4wt.S
index 4d7b467..198d424 100644
--- a/arch/arm/mm/cache-v4wt.S
+++ b/arch/arm/mm/cache-v4wt.S
@@ -195,6 +195,9 @@
ENDPROC(v4wt_dma_unmap_area)
ENDPROC(v4wt_dma_map_area)
+ .globl v4wt_flush_kern_cache_louis
+ .equ v4wt_flush_kern_cache_louis, v4wt_flush_kern_cache_all
+
__INITDATA
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
diff --git a/arch/arm/mm/cache-v6.S b/arch/arm/mm/cache-v6.S
index 2edb6f6..6a5674d 100644
--- a/arch/arm/mm/cache-v6.S
+++ b/arch/arm/mm/cache-v6.S
@@ -345,6 +345,9 @@
mov pc, lr
ENDPROC(v6_dma_unmap_area)
+ .globl v6_flush_kern_cache_louis
+ .equ v6_flush_kern_cache_louis, v6_flush_kern_cache_all
+
__INITDATA
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S
index a655d3d..df79627 100644
--- a/arch/arm/mm/cache-v7.S
+++ b/arch/arm/mm/cache-v7.S
@@ -32,6 +32,24 @@
mov pc, lr
ENDPROC(v7_flush_icache_all)
+ /*
+ * v7_flush_dcache_louis()
+ *
+ * Flush the D-cache up to the Level of Unification Inner Shareable
+ *
+ * Corrupted registers: r0-r7, r9-r11 (r6 only in Thumb mode)
+ */
+
+ENTRY(v7_flush_dcache_louis)
+ dmb @ ensure ordering with previous memory accesses
+ mrc p15, 1, r0, c0, c0, 1 @ read clidr, r0 = clidr
+ ands r3, r0, #0xe00000 @ extract LoUIS from clidr
+ mov r3, r3, lsr #20 @ r3 = LoUIS * 2
+ moveq pc, lr @ return if level == 0
+ mov r10, #0 @ r10 (starting level) = 0
+ b loop1 @ start flushing cache levels
+ENDPROC(v7_flush_dcache_louis)
+
/*
* v7_flush_dcache_all()
*
@@ -119,6 +137,24 @@
mov pc, lr
ENDPROC(v7_flush_kern_cache_all)
+ /*
+ * v7_flush_kern_cache_louis(void)
+ *
+ * Flush the data cache up to Level of Unification Inner Shareable.
+ * Invalidate the I-cache to the point of unification.
+ */
+ENTRY(v7_flush_kern_cache_louis)
+ ARM( stmfd sp!, {r4-r5, r7, r9-r11, lr} )
+ THUMB( stmfd sp!, {r4-r7, r9-r11, lr} )
+ bl v7_flush_dcache_louis
+ mov r0, #0
+ ALT_SMP(mcr p15, 0, r0, c7, c1, 0) @ invalidate I-cache inner shareable
+ ALT_UP(mcr p15, 0, r0, c7, c5, 0) @ I+BTB cache invalidate
+ ARM( ldmfd sp!, {r4-r5, r7, r9-r11, lr} )
+ THUMB( ldmfd sp!, {r4-r7, r9-r11, lr} )
+ mov pc, lr
+ENDPROC(v7_flush_kern_cache_louis)
+
/*
* v7_flush_cache_all()
*
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 34ae4e6..ac6ccf3b 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -885,8 +885,9 @@
MLM(VMALLOC_START, VMALLOC_END),
MLM(PAGE_OFFSET, (unsigned long)high_memory));
#endif
-#ifdef CONFIG_HIGHMEM
+
printk(KERN_NOTICE
+#ifdef CONFIG_HIGHMEM
" pkmap : 0x%08lx - 0x%08lx (%4ld MB)\n"
#endif
#ifdef CONFIG_MODULES
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index a1a2e51..669b10e 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -1500,7 +1500,9 @@
vm->flags = VM_LOWMEM | VM_ARM_STATIC_MAPPING;
vm->flags |= VM_ARM_MTYPE(type);
vm->caller = map_lowmem;
- vm_area_add_early(vm++);
+ vm_area_add_early(vm);
+ mark_vmalloc_reserved_area(vm->addr, vm->size);
+ vm++;
}
}
diff --git a/arch/arm/mm/proc-arm1020.S b/arch/arm/mm/proc-arm1020.S
index 2349513..c11e32e 100644
--- a/arch/arm/mm/proc-arm1020.S
+++ b/arch/arm/mm/proc-arm1020.S
@@ -367,6 +367,9 @@
mov pc, lr
ENDPROC(arm1020_dma_unmap_area)
+ .globl arm1020_flush_kern_cache_louis
+ .equ arm1020_flush_kern_cache_louis, arm1020_flush_kern_cache_all
+
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
define_cache_functions arm1020
diff --git a/arch/arm/mm/proc-arm1020e.S b/arch/arm/mm/proc-arm1020e.S
index c244b06..9624a35 100644
--- a/arch/arm/mm/proc-arm1020e.S
+++ b/arch/arm/mm/proc-arm1020e.S
@@ -353,6 +353,9 @@
mov pc, lr
ENDPROC(arm1020e_dma_unmap_area)
+ .globl arm1020e_flush_kern_cache_louis
+ .equ arm1020e_flush_kern_cache_louis, arm1020e_flush_kern_cache_all
+
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
define_cache_functions arm1020e
diff --git a/arch/arm/mm/proc-arm1022.S b/arch/arm/mm/proc-arm1022.S
index 38fe22e..f2b45ee 100644
--- a/arch/arm/mm/proc-arm1022.S
+++ b/arch/arm/mm/proc-arm1022.S
@@ -342,6 +342,9 @@
mov pc, lr
ENDPROC(arm1022_dma_unmap_area)
+ .globl arm1022_flush_kern_cache_louis
+ .equ arm1022_flush_kern_cache_louis, arm1022_flush_kern_cache_all
+
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
define_cache_functions arm1022
diff --git a/arch/arm/mm/proc-arm1026.S b/arch/arm/mm/proc-arm1026.S
index 3eb9c3c..95934d2 100644
--- a/arch/arm/mm/proc-arm1026.S
+++ b/arch/arm/mm/proc-arm1026.S
@@ -336,6 +336,9 @@
mov pc, lr
ENDPROC(arm1026_dma_unmap_area)
+ .globl arm1026_flush_kern_cache_louis
+ .equ arm1026_flush_kern_cache_louis, arm1026_flush_kern_cache_all
+
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
define_cache_functions arm1026
diff --git a/arch/arm/mm/proc-arm920.S b/arch/arm/mm/proc-arm920.S
index cb941ae..ed3acd4 100644
--- a/arch/arm/mm/proc-arm920.S
+++ b/arch/arm/mm/proc-arm920.S
@@ -318,6 +318,9 @@
mov pc, lr
ENDPROC(arm920_dma_unmap_area)
+ .globl arm920_flush_kern_cache_louis
+ .equ arm920_flush_kern_cache_louis, arm920_flush_kern_cache_all
+
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
define_cache_functions arm920
#endif
diff --git a/arch/arm/mm/proc-arm922.S b/arch/arm/mm/proc-arm922.S
index 4ec0e07..142bace 100644
--- a/arch/arm/mm/proc-arm922.S
+++ b/arch/arm/mm/proc-arm922.S
@@ -320,6 +320,9 @@
mov pc, lr
ENDPROC(arm922_dma_unmap_area)
+ .globl arm922_flush_kern_cache_louis
+ .equ arm922_flush_kern_cache_louis, arm922_flush_kern_cache_all
+
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
define_cache_functions arm922
#endif
diff --git a/arch/arm/mm/proc-arm925.S b/arch/arm/mm/proc-arm925.S
index 9dccd9a..3028390 100644
--- a/arch/arm/mm/proc-arm925.S
+++ b/arch/arm/mm/proc-arm925.S
@@ -375,6 +375,9 @@
mov pc, lr
ENDPROC(arm925_dma_unmap_area)
+ .globl arm925_flush_kern_cache_louis
+ .equ arm925_flush_kern_cache_louis, arm925_flush_kern_cache_all
+
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
define_cache_functions arm925
diff --git a/arch/arm/mm/proc-arm926.S b/arch/arm/mm/proc-arm926.S
index 820259b..1f99b46 100644
--- a/arch/arm/mm/proc-arm926.S
+++ b/arch/arm/mm/proc-arm926.S
@@ -338,6 +338,9 @@
mov pc, lr
ENDPROC(arm926_dma_unmap_area)
+ .globl arm926_flush_kern_cache_louis
+ .equ arm926_flush_kern_cache_louis, arm926_flush_kern_cache_all
+
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
define_cache_functions arm926
diff --git a/arch/arm/mm/proc-arm940.S b/arch/arm/mm/proc-arm940.S
index 9fdc0a1..e5af959 100644
--- a/arch/arm/mm/proc-arm940.S
+++ b/arch/arm/mm/proc-arm940.S
@@ -267,6 +267,9 @@
mov pc, lr
ENDPROC(arm940_dma_unmap_area)
+ .globl arm940_flush_kern_cache_louis
+ .equ arm940_flush_kern_cache_louis, arm940_flush_kern_cache_all
+
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
define_cache_functions arm940
diff --git a/arch/arm/mm/proc-arm946.S b/arch/arm/mm/proc-arm946.S
index f684cfe..3599b37 100644
--- a/arch/arm/mm/proc-arm946.S
+++ b/arch/arm/mm/proc-arm946.S
@@ -309,6 +309,9 @@
mov pc, lr
ENDPROC(arm946_dma_unmap_area)
+ .globl arm946_flush_kern_cache_louis
+ .equ arm946_flush_kern_cache_louis, arm946_flush_kern_cache_all
+
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
define_cache_functions arm946
diff --git a/arch/arm/mm/proc-feroceon.S b/arch/arm/mm/proc-feroceon.S
index ba3c500..26a9984 100644
--- a/arch/arm/mm/proc-feroceon.S
+++ b/arch/arm/mm/proc-feroceon.S
@@ -414,6 +414,9 @@
mov pc, lr
ENDPROC(feroceon_dma_unmap_area)
+ .globl feroceon_flush_kern_cache_louis
+ .equ feroceon_flush_kern_cache_louis, feroceon_flush_kern_cache_all
+
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
define_cache_functions feroceon
diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S
index 5829bb3..2ea177a 100644
--- a/arch/arm/mm/proc-macros.S
+++ b/arch/arm/mm/proc-macros.S
@@ -299,6 +299,7 @@
ENTRY(\name\()_cache_fns)
.long \name\()_flush_icache_all
.long \name\()_flush_kern_cache_all
+ .long \name\()_flush_kern_cache_louis
.long \name\()_flush_user_cache_all
.long \name\()_flush_user_cache_range
.long \name\()_coherent_kern_range
diff --git a/arch/arm/mm/proc-mohawk.S b/arch/arm/mm/proc-mohawk.S
index cdfedc5..224d0f5 100644
--- a/arch/arm/mm/proc-mohawk.S
+++ b/arch/arm/mm/proc-mohawk.S
@@ -302,6 +302,9 @@
mov pc, lr
ENDPROC(mohawk_dma_unmap_area)
+ .globl mohawk_flush_kern_cache_louis
+ .equ mohawk_flush_kern_cache_louis, mohawk_flush_kern_cache_all
+
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
define_cache_functions mohawk
diff --git a/arch/arm/mm/proc-xsc3.S b/arch/arm/mm/proc-xsc3.S
index b0d5786..eb93d64 100644
--- a/arch/arm/mm/proc-xsc3.S
+++ b/arch/arm/mm/proc-xsc3.S
@@ -337,6 +337,9 @@
mov pc, lr
ENDPROC(xsc3_dma_unmap_area)
+ .globl xsc3_flush_kern_cache_louis
+ .equ xsc3_flush_kern_cache_louis, xsc3_flush_kern_cache_all
+
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
define_cache_functions xsc3
diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S
index 4ffebaa..b5ea31d 100644
--- a/arch/arm/mm/proc-xscale.S
+++ b/arch/arm/mm/proc-xscale.S
@@ -410,6 +410,9 @@
mov pc, lr
ENDPROC(xscale_dma_unmap_area)
+ .globl xscale_flush_kern_cache_louis
+ .equ xscale_flush_kern_cache_louis, xscale_flush_kern_cache_all
+
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
define_cache_functions xscale
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index 1d12b07..9a1a2eb 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -85,6 +85,7 @@
}
#ifdef CONFIG_SMP
thread->vfpstate.hard.cpu = NR_CPUS;
+ vfp_current_hw_state[cpu] = NULL;
#endif
}
diff --git a/arch/sparc/mm/init_32.c b/arch/sparc/mm/init_32.c
index c5f9021..fbf4eeb 100644
--- a/arch/sparc/mm/init_32.c
+++ b/arch/sparc/mm/init_32.c
@@ -77,7 +77,7 @@
printk("Mem-info:\n");
show_free_areas(filter);
printk("Free swap: %6ldkB\n",
- nr_swap_pages << (PAGE_SHIFT-10));
+ get_nr_swap_pages() << (PAGE_SHIFT-10));
printk("%ld pages of RAM\n", totalram_pages);
printk("%ld free pages\n", nr_free_pages());
#if 0 /* undefined pgtable_cache_size, pgd_cache_size */
diff --git a/arch/tile/mm/pgtable.c b/arch/tile/mm/pgtable.c
index 2410aa8..ea7dd38 100644
--- a/arch/tile/mm/pgtable.c
+++ b/arch/tile/mm/pgtable.c
@@ -61,7 +61,7 @@
global_page_state(NR_PAGETABLE),
global_page_state(NR_BOUNCE),
global_page_state(NR_FILE_PAGES),
- nr_swap_pages);
+ get_nr_swap_pages());
for_each_zone(zone) {
unsigned long flags, order, total = 0, largest_order = -1;
diff --git a/drivers/Kconfig b/drivers/Kconfig
index adead10..72440c9 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -152,4 +152,6 @@
source "drivers/bif/Kconfig"
+source "drivers/sensors/Kconfig"
+
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index d55b035..867be8a 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -144,3 +144,4 @@
obj-$(CONFIG_CORESIGHT) += coresight/
obj-$(CONFIG_BIF) += bif/
+obj-$(CONFIG_SENSORS) += sensors/
diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index 45c9023..885721f 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -447,6 +447,13 @@
}
core_initcall(cma_init_reserved_areas);
+phys_addr_t cma_get_base(struct device *dev)
+{
+ struct cma *cma = dev_get_cma_area(dev);
+
+ return cma->base_pfn << PAGE_SHIFT;
+}
+
/**
* dma_alloc_from_contiguous() - allocate pages from contiguous area
* @dev: Pointer to device for which the allocation is performed.
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index e2864ec..a5748fb 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -650,21 +650,13 @@
different function.
config MSM_ADSPRPC
- tristate "Qualcomm ADSP RPC driver"
- depends on MSM_AUDIO_QDSP6 || MSM_AUDIO_QDSP6V2
- default m
- help
- Provides a communication mechanism that allows for clients to
- make remote method invocations across processor boundary to
- applications DSP processor. Say M if you want to enable this
- module.
-
-config MMC_GENERIC_CSDIO
- tristate "Generic sdio driver"
- default n
+ tristate "Qualcomm ADSP RPC driver"
+ depends on MSM_AUDIO_QDSP6 || MSM_AUDIO_QDSP6V2
help
- SDIO function driver that extends SDIO card as character device
- in user space.
+ Provides a communication mechanism that allows for clients to
+ make remote method invocations across processor boundary to
+ applications DSP processor. Say M if you want to enable this
+ module.
config CSDIO_VENDOR_ID
hex "Card VendorId"
@@ -681,6 +673,13 @@
help
Enter device id for targeted sdio device, this may be overwritten by
module parameters.
-.
+
+config MSM_RDBG
+ tristate "Qualcomm Remote debug driver"
+ depends on MSM_AUDIO_QDSP6 || MSM_AUDIO_QDSP6V2
+ help
+ Implements a shared memory based transport mechanism that allows
+ for a debugger running on a host PC to communicate with a remote
+ stub running on peripheral subsystems such as the ADSP, MODEM etc.
endmenu
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 8032f0b..292cc99 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -65,6 +65,6 @@
obj-$(CONFIG_TILE_SROM) += tile-srom.o
obj-$(CONFIG_MSM_ROTATOR) += msm_rotator.o
-obj-$(CONFIG_MMC_GENERIC_CSDIO) += csdio.o
obj-$(CONFIG_DIAG_CHAR) += diag/
obj-$(CONFIG_MSM_ADSPRPC) += adsprpc.o
+obj-$(CONFIG_MSM_RDBG) += rdbg.o
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 4507f80..cc8cf47 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -33,6 +33,7 @@
#include <linux/device.h>
#include <linux/of.h>
#include <linux/iommu.h>
+#include <linux/kref.h>
#ifndef ION_ADSPRPC_HEAP_ID
#define ION_ADSPRPC_HEAP_ID ION_AUDIO_HEAP_ID
@@ -124,16 +125,38 @@
return n;
}
+struct fastrpc_buf {
+ struct ion_handle *handle;
+ void *virt;
+ ion_phys_addr_t phys;
+ int size;
+ int used;
+};
+
+struct smq_context_list;
+
struct smq_invoke_ctx {
+ struct hlist_node hn;
struct completion work;
int retval;
- atomic_t free;
+ int pid;
+ remote_arg_t *pra;
+ remote_arg_t *rpra;
+ struct fastrpc_buf obuf;
+ struct fastrpc_buf *abufs;
+ struct fastrpc_device *dev;
+ struct fastrpc_apps *apps;
+ int *fds;
+ struct ion_handle **handles;
+ int nbufs;
+ bool smmu;
+ uint32_t sc;
};
struct smq_context_list {
- struct smq_invoke_ctx *ls;
- int size;
- int last;
+ struct hlist_head pending;
+ struct hlist_head interrupted;
+ spinlock_t hlock;
};
struct fastrpc_smmu {
@@ -152,9 +175,11 @@
struct class *class;
struct device *dev;
struct fastrpc_smmu smmu;
+ struct mutex smd_mutex;
dev_t dev_no;
spinlock_t wrlock;
spinlock_t hlock;
+ struct kref kref;
struct hlist_head htbl[RPC_HASH_SZ];
};
@@ -162,22 +187,16 @@
struct hlist_node hn;
struct ion_handle *handle;
void *virt;
+ ion_phys_addr_t phys;
uint32_t vaddrin;
uint32_t vaddrout;
int size;
};
-struct fastrpc_buf {
- struct ion_handle *handle;
- void *virt;
- ion_phys_addr_t phys;
- int size;
- int used;
-};
-
struct file_data {
spinlock_t hlock;
struct hlist_head hlst;
+ uint32_t mode;
};
struct fastrpc_device {
@@ -198,7 +217,7 @@
me->smmu.domain_id, 0);
buf->phys = 0;
}
- if (buf->virt) {
+ if (!IS_ERR_OR_NULL(buf->virt)) {
ion_unmap_kernel(me->iclient, buf->handle);
buf->virt = 0;
}
@@ -211,7 +230,12 @@
{
struct fastrpc_apps *me = &gfa;
if (!IS_ERR_OR_NULL(map->handle)) {
- if (map->virt) {
+ if (me->smmu.enabled && map->phys) {
+ ion_unmap_iommu(me->iclient, map->handle,
+ me->smmu.domain_id, 0);
+ map->phys = 0;
+ }
+ if (!IS_ERR_OR_NULL(map->virt)) {
ion_unmap_kernel(me->iclient, map->handle);
map->virt = 0;
}
@@ -230,13 +254,15 @@
unsigned long len;
buf->handle = 0;
buf->virt = 0;
+ buf->phys = 0;
heap = me->smmu.enabled ? ION_HEAP(ION_IOMMU_HEAP_ID) :
ION_HEAP(ION_ADSP_HEAP_ID) | ION_HEAP(ION_AUDIO_HEAP_ID);
buf->handle = ion_alloc(clnt, buf->size, SZ_4K, heap, ION_FLAG_CACHED);
VERIFY(err, 0 == IS_ERR_OR_NULL(buf->handle));
if (err)
goto bail;
- VERIFY(err, 0 != (buf->virt = ion_map_kernel(clnt, buf->handle)));
+ buf->virt = ion_map_kernel(clnt, buf->handle);
+ VERIFY(err, 0 == IS_ERR_OR_NULL(buf->virt));
if (err)
goto bail;
if (me->smmu.enabled) {
@@ -250,9 +276,6 @@
VERIFY(err, 0 != (sg = ion_sg_table(clnt, buf->handle)));
if (err)
goto bail;
- VERIFY(err, 1 == sg->nents);
- if (err)
- goto bail;
buf->phys = sg_dma_address(sg->sgl);
}
bail:
@@ -261,65 +284,186 @@
return err;
}
-static int context_list_ctor(struct smq_context_list *me, int size)
+static int context_restore_interrupted(struct fastrpc_apps *me,
+ struct fastrpc_ioctl_invoke_fd *invokefd,
+ struct smq_invoke_ctx **po)
{
int err = 0;
- VERIFY(err, 0 != (me->ls = kzalloc(size, GFP_KERNEL)));
- if (err)
- goto bail;
- me->size = size / sizeof(*me->ls);
- me->last = 0;
- bail:
+ struct smq_invoke_ctx *ctx = 0, *ictx = 0;
+ struct hlist_node *pos, *n;
+ struct fastrpc_ioctl_invoke *invoke = &invokefd->inv;
+ spin_lock(&me->clst.hlock);
+ hlist_for_each_entry_safe(ictx, pos, n, &me->clst.interrupted, hn) {
+ if (ictx->pid == current->pid) {
+ if (invoke->sc != ictx->sc)
+ err = -1;
+ else {
+ ctx = ictx;
+ hlist_del(&ctx->hn);
+ hlist_add_head(&ctx->hn, &me->clst.pending);
+ }
+ break;
+ }
+ }
+ spin_unlock(&me->clst.hlock);
+ if (ctx)
+ *po = ctx;
return err;
}
-static void context_list_dtor(struct smq_context_list *me)
+static int context_alloc(struct fastrpc_apps *me, uint32_t kernel,
+ struct fastrpc_ioctl_invoke_fd *invokefd,
+ struct smq_invoke_ctx **po)
{
- kfree(me->ls);
-}
+ int err = 0, bufs, size = 0;
+ struct smq_invoke_ctx *ctx = 0;
+ struct smq_context_list *clst = &me->clst;
+ struct fastrpc_ioctl_invoke *invoke = &invokefd->inv;
-static void context_list_alloc_ctx(struct smq_context_list *me,
- struct smq_invoke_ctx **po)
-{
- int i = me->last;
- struct smq_invoke_ctx *ctx;
-
- for (;;) {
- i = i % me->size;
- ctx = &me->ls[i];
- if (atomic_read(&ctx->free) == 0)
- if (atomic_cmpxchg(&ctx->free, 0, 1) == 0)
- break;
- i++;
+ bufs = REMOTE_SCALARS_INBUFS(invoke->sc) +
+ REMOTE_SCALARS_OUTBUFS(invoke->sc);
+ if (bufs) {
+ size = bufs * sizeof(*ctx->pra);
+ if (invokefd->fds)
+ size = size + bufs * sizeof(*ctx->fds) +
+ bufs * sizeof(*ctx->handles);
}
- me->last = i;
+
+ VERIFY(err, 0 != (ctx = kzalloc(sizeof(*ctx) + size, GFP_KERNEL)));
+ if (err)
+ goto bail;
+
+ INIT_HLIST_NODE(&ctx->hn);
+ ctx->pra = (remote_arg_t *)(&ctx[1]);
+ ctx->fds = invokefd->fds == 0 ? 0 : (int *)(&ctx->pra[bufs]);
+ ctx->handles = invokefd->fds == 0 ? 0 :
+ (struct ion_handle **)(&ctx->fds[bufs]);
+ if (!kernel) {
+ VERIFY(err, 0 == copy_from_user(ctx->pra, invoke->pra,
+ bufs * sizeof(*ctx->pra)));
+ if (err)
+ goto bail;
+ } else {
+ memmove(ctx->pra, invoke->pra, bufs * sizeof(*ctx->pra));
+ }
+
+ if (invokefd->fds) {
+ if (!kernel) {
+ VERIFY(err, 0 == copy_from_user(ctx->fds, invokefd->fds,
+ bufs * sizeof(*ctx->fds)));
+ if (err)
+ goto bail;
+ } else {
+ memmove(ctx->fds, invokefd->fds,
+ bufs * sizeof(*ctx->fds));
+ }
+ }
+ ctx->sc = invoke->sc;
ctx->retval = -1;
+ ctx->pid = current->pid;
+ ctx->apps = me;
init_completion(&ctx->work);
+ spin_lock(&clst->hlock);
+ hlist_add_head(&ctx->hn, &clst->pending);
+ spin_unlock(&clst->hlock);
+
*po = ctx;
+bail:
+ if (ctx && err)
+ kfree(ctx);
+ return err;
}
-static void context_free(struct smq_invoke_ctx *me)
+static void context_save_interrupted(struct smq_invoke_ctx *ctx)
{
- if (me)
- atomic_set(&me->free, 0);
+ struct smq_context_list *clst = &ctx->apps->clst;
+ spin_lock(&clst->hlock);
+ hlist_del(&ctx->hn);
+ hlist_add_head(&ctx->hn, &clst->interrupted);
+ spin_unlock(&clst->hlock);
}
-static void context_notify_user(struct smq_invoke_ctx *me, int retval)
+static void add_dev(struct fastrpc_apps *me, struct fastrpc_device *dev);
+
+static void context_free(struct smq_invoke_ctx *ctx, bool lock)
{
- me->retval = retval;
- complete(&me->work);
+ struct smq_context_list *clst = &ctx->apps->clst;
+ struct fastrpc_apps *apps = ctx->apps;
+ struct ion_client *clnt = apps->iclient;
+ struct fastrpc_smmu *smmu = &apps->smmu;
+ struct fastrpc_buf *b;
+ int i, bufs;
+ if (ctx->smmu) {
+ bufs = REMOTE_SCALARS_INBUFS(ctx->sc) +
+ REMOTE_SCALARS_OUTBUFS(ctx->sc);
+ if (ctx->fds) {
+ for (i = 0; i < bufs; i++)
+ if (!IS_ERR_OR_NULL(ctx->handles[i])) {
+ ion_unmap_iommu(clnt, ctx->handles[i],
+ smmu->domain_id, 0);
+ ion_free(clnt, ctx->handles[i]);
+ }
+ }
+ iommu_detach_group(smmu->domain, smmu->group);
+ }
+ for (i = 0, b = ctx->abufs; i < ctx->nbufs; ++i, ++b)
+ free_mem(b);
+
+ kfree(ctx->abufs);
+ if (ctx->dev) {
+ add_dev(apps, ctx->dev);
+ if (ctx->obuf.handle != ctx->dev->buf.handle)
+ free_mem(&ctx->obuf);
+ }
+ if (lock)
+ spin_lock(&clst->hlock);
+ hlist_del(&ctx->hn);
+ if (lock)
+ spin_unlock(&clst->hlock);
+ kfree(ctx);
+}
+
+static void context_notify_user(struct smq_invoke_ctx *ctx, int retval)
+{
+ ctx->retval = retval;
+ complete(&ctx->work);
}
static void context_notify_all_users(struct smq_context_list *me)
{
- int i;
-
- if (!me->ls)
- return;
- for (i = 0; i < me->size; ++i) {
- if (atomic_read(&me->ls[i].free) != 0)
- complete(&me->ls[i].work);
+ struct smq_invoke_ctx *ictx = 0;
+ struct hlist_node *pos, *n;
+ spin_lock(&me->hlock);
+ hlist_for_each_entry_safe(ictx, pos, n, &me->pending, hn) {
+ complete(&ictx->work);
}
+ hlist_for_each_entry_safe(ictx, pos, n, &me->interrupted, hn) {
+ complete(&ictx->work);
+ }
+ spin_unlock(&me->hlock);
+
+}
+
+static void context_list_ctor(struct smq_context_list *me)
+{
+ INIT_HLIST_HEAD(&me->interrupted);
+ INIT_HLIST_HEAD(&me->pending);
+ spin_lock_init(&me->hlock);
+}
+
+static void context_list_dtor(struct fastrpc_apps *me,
+ struct smq_context_list *clst)
+{
+ struct smq_invoke_ctx *ictx = 0;
+ struct hlist_node *pos, *n;
+ spin_lock(&clst->hlock);
+ hlist_for_each_entry_safe(ictx, pos, n, &clst->interrupted, hn) {
+ context_free(ictx, 0);
+ }
+ hlist_for_each_entry_safe(ictx, pos, n, &clst->pending, hn) {
+ context_free(ictx, 0);
+ }
+ spin_unlock(&clst->hlock);
}
static int get_page_list(uint32_t kernel, uint32_t sc, remote_arg_t *pra,
@@ -355,6 +499,9 @@
list[i].num = 0;
list[i].pgidx = 0;
len = pra[i].buf.len;
+ VERIFY(err, len >= 0);
+ if (err)
+ goto bail;
if (!len)
continue;
buf = pra[i].buf.pv;
@@ -395,13 +542,12 @@
static int get_args(uint32_t kernel, uint32_t sc, remote_arg_t *pra,
remote_arg_t *rpra, remote_arg_t *upra,
struct fastrpc_buf *ibuf, struct fastrpc_buf **abufs,
- int *nbufs, int *fds)
+ int *nbufs, int *fds, struct ion_handle **handles)
{
struct fastrpc_apps *me = &gfa;
struct smq_invoke_buf *list;
struct fastrpc_buf *pbuf = ibuf, *obufs = 0;
struct smq_phy_page *pages;
- struct ion_handle **handles = NULL;
void *args;
int i, rlen, size, used, inh, bufs = 0, err = 0;
int inbufs = REMOTE_SCALARS_INBUFS(sc);
@@ -413,8 +559,6 @@
used = ALIGN(pbuf->used, BALIGN);
args = (void *)((char *)pbuf->virt + used);
rlen = pbuf->size - used;
- if (fds)
- handles = (struct ion_handle **)(fds + inbufs + outbufs);
for (i = 0; i < inbufs + outbufs; ++i) {
rpra[i].buf.len = pra[i].buf.len;
@@ -609,7 +753,6 @@
struct fastrpc_apps *me = &gfa;
smd_close(me->chan);
- context_list_dtor(&me->clst);
ion_client_destroy(me->iclient);
me->iclient = 0;
me->chan = 0;
@@ -661,16 +804,15 @@
spin_lock_init(&me->hlock);
spin_lock_init(&me->wrlock);
init_completion(&me->work);
+ mutex_init(&me->smd_mutex);
+ context_list_ctor(&me->clst);
for (i = 0; i < RPC_HASH_SZ; ++i)
INIT_HLIST_HEAD(&me->htbl[i]);
- VERIFY(err, 0 == context_list_ctor(&me->clst, SZ_4K));
- if (err)
- goto context_list_bail;
me->iclient = msm_ion_client_create(ION_HEAP_CARVEOUT_MASK,
DEVICE_NAME);
VERIFY(err, 0 == IS_ERR_OR_NULL(me->iclient));
if (err)
- goto ion_bail;
+ goto bail;
node = of_find_compatible_node(NULL, NULL,
"qcom,msm-audio-ion");
if (node)
@@ -687,26 +829,11 @@
if (me->smmu.domain_id >= 0)
me->smmu.enabled = enabled;
}
- VERIFY(err, 0 == smd_named_open_on_edge(FASTRPC_SMD_GUID,
- SMD_APPS_QDSP, &me->chan,
- me, smd_event_handler));
- if (err)
- goto smd_bail;
- VERIFY(err, 0 != wait_for_completion_timeout(&me->work,
- RPC_TIMEOUT));
- if (err)
- goto completion_bail;
}
return 0;
-completion_bail:
- smd_close(me->chan);
-smd_bail:
- ion_client_destroy(me->iclient);
-ion_bail:
- context_list_dtor(&me->clst);
-context_list_bail:
+bail:
return err;
}
@@ -790,96 +917,88 @@
static int fastrpc_release_current_dsp_process(void);
-static int fastrpc_internal_invoke(struct fastrpc_apps *me, uint32_t kernel,
- struct fastrpc_ioctl_invoke *invoke, remote_arg_t *pra,
- int *fds)
+static int fastrpc_internal_invoke(struct fastrpc_apps *me, uint32_t mode,
+ uint32_t kernel,
+ struct fastrpc_ioctl_invoke_fd *invokefd)
{
- remote_arg_t *rpra = 0;
- struct fastrpc_device *dev = 0;
struct smq_invoke_ctx *ctx = 0;
- struct fastrpc_buf obuf, *abufs = 0, *b;
- struct ion_handle **handles = NULL;
+ struct fastrpc_ioctl_invoke *invoke = &invokefd->inv;
int interrupted = 0;
- uint32_t sc;
- int i, bufs, nbufs = 0, err = 0;
+ int err = 0;
- sc = invoke->sc;
- obuf.handle = 0;
+ if (!kernel) {
+ VERIFY(err, 0 == context_restore_interrupted(me, invokefd,
+ &ctx));
+ if (err)
+ goto bail;
+ if (ctx)
+ goto wait;
+ }
+
+ VERIFY(err, 0 == context_alloc(me, kernel, invokefd, &ctx));
+ if (err)
+ goto bail;
+
if (me->smmu.enabled) {
VERIFY(err, 0 == iommu_attach_group(me->smmu.domain,
me->smmu.group));
if (err)
- return err;
+ goto bail;
+ ctx->smmu = 1;
}
- if (REMOTE_SCALARS_LENGTH(sc)) {
- VERIFY(err, 0 == get_dev(me, &dev));
+ if (REMOTE_SCALARS_LENGTH(ctx->sc)) {
+ VERIFY(err, 0 == get_dev(me, &ctx->dev));
if (err)
goto bail;
- VERIFY(err, 0 == get_page_list(kernel, sc, pra, &dev->buf,
- &obuf));
+ VERIFY(err, 0 == get_page_list(kernel, ctx->sc, ctx->pra,
+ &ctx->dev->buf, &ctx->obuf));
if (err)
goto bail;
- rpra = (remote_arg_t *)obuf.virt;
- VERIFY(err, 0 == get_args(kernel, sc, pra, rpra, invoke->pra,
- &obuf, &abufs, &nbufs, fds));
+ ctx->rpra = (remote_arg_t *)ctx->obuf.virt;
+ VERIFY(err, 0 == get_args(kernel, ctx->sc, ctx->pra, ctx->rpra,
+ invoke->pra, &ctx->obuf, &ctx->abufs,
+ &ctx->nbufs, ctx->fds, ctx->handles));
if (err)
goto bail;
}
- context_list_alloc_ctx(&me->clst, &ctx);
- inv_args_pre(sc, rpra);
- VERIFY(err, 0 == fastrpc_invoke_send(me, kernel, invoke->handle, sc,
- ctx, &obuf));
+ inv_args_pre(ctx->sc, ctx->rpra);
+ if (FASTRPC_MODE_SERIAL == mode)
+ inv_args(ctx->sc, ctx->rpra, ctx->obuf.used);
+ VERIFY(err, 0 == fastrpc_invoke_send(me, kernel, invoke->handle,
+ ctx->sc, ctx, &ctx->obuf));
if (err)
goto bail;
- inv_args(sc, rpra, obuf.used);
- VERIFY(err, 0 == (interrupted =
- wait_for_completion_interruptible(&ctx->work)));
- if (err)
- goto bail;
+ if (FASTRPC_MODE_PARALLEL == mode)
+ inv_args(ctx->sc, ctx->rpra, ctx->obuf.used);
+ wait:
+ if (kernel)
+ wait_for_completion(&ctx->work);
+ else {
+ interrupted = wait_for_completion_interruptible(&ctx->work);
+ VERIFY(err, 0 == (err = interrupted));
+ if (err)
+ goto bail;
+ }
VERIFY(err, 0 == (err = ctx->retval));
if (err)
goto bail;
- VERIFY(err, 0 == put_args(kernel, sc, pra, rpra, invoke->pra));
+ VERIFY(err, 0 == put_args(kernel, ctx->sc, ctx->pra, ctx->rpra,
+ invoke->pra));
if (err)
goto bail;
bail:
- if (interrupted) {
- if (!kernel)
- (void)fastrpc_release_current_dsp_process();
- wait_for_completion(&ctx->work);
- }
- context_free(ctx);
-
- if (me->smmu.enabled) {
- bufs = REMOTE_SCALARS_LENGTH(sc);
- if (fds) {
- handles = (struct ion_handle **)(fds + bufs);
- for (i = 0; i < bufs; i++)
- if (!IS_ERR_OR_NULL(handles[i])) {
- ion_unmap_iommu(me->iclient, handles[i],
- me->smmu.domain_id, 0);
- ion_free(me->iclient, handles[i]);
- }
- }
- iommu_detach_group(me->smmu.domain, me->smmu.group);
- }
- for (i = 0, b = abufs; i < nbufs; ++i, ++b)
- free_mem(b);
-
- kfree(abufs);
- if (dev) {
- add_dev(me, dev);
- if (obuf.handle != dev->buf.handle)
- free_mem(&obuf);
- }
+ if (ctx && interrupted == -ERESTARTSYS)
+ context_save_interrupted(ctx);
+ else if (ctx)
+ context_free(ctx, 1);
return err;
}
static int fastrpc_create_current_dsp_process(void)
{
int err = 0;
- struct fastrpc_ioctl_invoke ioctl;
+ struct fastrpc_ioctl_invoke_fd ioctl;
struct fastrpc_apps *me = &gfa;
remote_arg_t ra[1];
int tgid = 0;
@@ -887,10 +1006,12 @@
tgid = current->tgid;
ra[0].buf.pv = &tgid;
ra[0].buf.len = sizeof(tgid);
- ioctl.handle = 1;
- ioctl.sc = REMOTE_SCALARS_MAKE(0, 1, 0);
- ioctl.pra = ra;
- VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 1, &ioctl, ra, 0)));
+ ioctl.inv.handle = 1;
+ ioctl.inv.sc = REMOTE_SCALARS_MAKE(0, 1, 0);
+ ioctl.inv.pra = ra;
+ ioctl.fds = 0;
+ VERIFY(err, 0 == (err = fastrpc_internal_invoke(me,
+ FASTRPC_MODE_PARALLEL, 1, &ioctl)));
return err;
}
@@ -898,17 +1019,19 @@
{
int err = 0;
struct fastrpc_apps *me = &gfa;
- struct fastrpc_ioctl_invoke ioctl;
+ struct fastrpc_ioctl_invoke_fd ioctl;
remote_arg_t ra[1];
int tgid = 0;
tgid = current->tgid;
ra[0].buf.pv = &tgid;
ra[0].buf.len = sizeof(tgid);
- ioctl.handle = 1;
- ioctl.sc = REMOTE_SCALARS_MAKE(1, 1, 0);
- ioctl.pra = ra;
- VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 1, &ioctl, ra, 0)));
+ ioctl.inv.handle = 1;
+ ioctl.inv.sc = REMOTE_SCALARS_MAKE(1, 1, 0);
+ ioctl.inv.pra = ra;
+ ioctl.fds = 0;
+ VERIFY(err, 0 == (err = fastrpc_internal_invoke(me,
+ FASTRPC_MODE_PARALLEL, 1, &ioctl)));
return err;
}
@@ -917,7 +1040,7 @@
struct smq_phy_page *pages,
int num)
{
- struct fastrpc_ioctl_invoke ioctl;
+ struct fastrpc_ioctl_invoke_fd ioctl;
remote_arg_t ra[3];
int err = 0;
struct {
@@ -943,10 +1066,12 @@
ra[2].buf.pv = &routargs;
ra[2].buf.len = sizeof(routargs);
- ioctl.handle = 1;
- ioctl.sc = REMOTE_SCALARS_MAKE(2, 2, 1);
- ioctl.pra = ra;
- VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 1, &ioctl, ra, 0)));
+ ioctl.inv.handle = 1;
+ ioctl.inv.sc = REMOTE_SCALARS_MAKE(2, 2, 1);
+ ioctl.inv.pra = ra;
+ ioctl.fds = 0;
+ VERIFY(err, 0 == (err = fastrpc_internal_invoke(me,
+ FASTRPC_MODE_PARALLEL, 1, &ioctl)));
mmap->vaddrout = routargs.vaddrout;
if (err)
goto bail;
@@ -957,7 +1082,7 @@
static int fastrpc_munmap_on_dsp(struct fastrpc_apps *me,
struct fastrpc_ioctl_munmap *munmap)
{
- struct fastrpc_ioctl_invoke ioctl;
+ struct fastrpc_ioctl_invoke_fd ioctl;
remote_arg_t ra[1];
int err = 0;
struct {
@@ -972,10 +1097,12 @@
ra[0].buf.pv = &inargs;
ra[0].buf.len = sizeof(inargs);
- ioctl.handle = 1;
- ioctl.sc = REMOTE_SCALARS_MAKE(3, 1, 0);
- ioctl.pra = ra;
- VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 1, &ioctl, ra, 0)));
+ ioctl.inv.handle = 1;
+ ioctl.inv.sc = REMOTE_SCALARS_MAKE(3, 1, 0);
+ ioctl.inv.pra = ra;
+ ioctl.fds = 0;
+ VERIFY(err, 0 == (err = fastrpc_internal_invoke(me,
+ FASTRPC_MODE_PARALLEL, 1, &ioctl)));
return err;
}
@@ -1017,7 +1144,7 @@
struct fastrpc_mmap *map = 0;
struct smq_phy_page *pages = 0;
void *buf;
- int len;
+ unsigned long len;
int num;
int err = 0;
@@ -1028,7 +1155,8 @@
VERIFY(err, 0 == IS_ERR_OR_NULL(map->handle));
if (err)
goto bail;
- VERIFY(err, 0 != (map->virt = ion_map_kernel(clnt, map->handle)));
+ map->virt = ion_map_kernel(clnt, map->handle);
+ VERIFY(err, 0 == IS_ERR_OR_NULL(map->virt));
if (err)
goto bail;
buf = (void *)mmap->vaddrin;
@@ -1037,9 +1165,22 @@
VERIFY(err, 0 != (pages = kzalloc(num * sizeof(*pages), GFP_KERNEL)));
if (err)
goto bail;
- VERIFY(err, 0 < (num = buf_get_pages(buf, len, num, 1, pages, num)));
- if (err)
- goto bail;
+
+ if (me->smmu.enabled) {
+ VERIFY(err, 0 == ion_map_iommu(clnt, map->handle,
+ me->smmu.domain_id, 0,
+ SZ_4K, 0, &map->phys, &len, 0, 0));
+ if (err)
+ goto bail;
+ pages->addr = map->phys;
+ pages->size = len;
+ num = 1;
+ } else {
+ VERIFY(err, 0 < (num = buf_get_pages(buf, len, num, 1,
+ pages, num)));
+ if (err)
+ goto bail;
+ }
VERIFY(err, 0 == fastrpc_mmap_on_dsp(me, mmap, pages, num));
if (err)
@@ -1087,13 +1228,26 @@
return;
}
+static void fastrpc_channel_close(struct kref *kref)
+{
+ struct fastrpc_apps *me = &gfa;
+
+ smd_close(me->chan);
+ me->chan = 0;
+ mutex_unlock(&me->smd_mutex);
+ pr_info("'closed /dev/%s c %d 0'\n", DEVICE_NAME,
+ MAJOR(me->dev_no));
+}
+
static int fastrpc_device_release(struct inode *inode, struct file *file)
{
struct file_data *fdata = (struct file_data *)file->private_data;
+ struct fastrpc_apps *me = &gfa;
+
(void)fastrpc_release_current_dsp_process();
cleanup_current_dev();
if (fdata) {
- struct fastrpc_mmap *map;
+ struct fastrpc_mmap *map = 0;
struct hlist_node *n, *pos;
file->private_data = 0;
hlist_for_each_entry_safe(map, pos, n, &fdata->hlst, hn) {
@@ -1102,6 +1256,8 @@
kfree(map);
}
kfree(fdata);
+ kref_put_mutex(&me->kref, fastrpc_channel_close,
+ &me->smd_mutex);
}
return 0;
}
@@ -1109,6 +1265,25 @@
static int fastrpc_device_open(struct inode *inode, struct file *filp)
{
int err = 0;
+ struct fastrpc_apps *me = &gfa;
+
+ mutex_lock(&me->smd_mutex);
+ if (kref_get_unless_zero(&me->kref) == 0) {
+ VERIFY(err, 0 == smd_named_open_on_edge(FASTRPC_SMD_GUID,
+ SMD_APPS_QDSP, &me->chan,
+ me, smd_event_handler));
+ if (err)
+ goto smd_bail;
+ VERIFY(err, 0 != wait_for_completion_timeout(&me->work,
+ RPC_TIMEOUT));
+ if (err)
+ goto completion_bail;
+ kref_init(&me->kref);
+ pr_info("'opened /dev/%s c %d 0'\n", DEVICE_NAME,
+ MAJOR(me->dev_no));
+ }
+ mutex_unlock(&me->smd_mutex);
+
filp->private_data = 0;
if (0 != try_module_get(THIS_MODULE)) {
struct file_data *fdata = 0;
@@ -1130,10 +1305,19 @@
if (err) {
cleanup_current_dev();
kfree(fdata);
+ kref_put_mutex(&me->kref, fastrpc_channel_close,
+ &me->smd_mutex);
}
module_put(THIS_MODULE);
}
return err;
+
+completion_bail:
+ smd_close(me->chan);
+ me->chan = 0;
+smd_bail:
+ mutex_unlock(&me->smd_mutex);
+ return err;
}
@@ -1142,48 +1326,23 @@
{
struct fastrpc_apps *me = &gfa;
struct fastrpc_ioctl_invoke_fd invokefd;
- struct fastrpc_ioctl_invoke *invoke = &invokefd.inv;
struct fastrpc_ioctl_mmap mmap;
struct fastrpc_ioctl_munmap munmap;
- remote_arg_t *pra = 0;
void *param = (char *)ioctl_param;
struct file_data *fdata = (struct file_data *)file->private_data;
- int *fds = 0;
- int bufs, size = 0, err = 0;
+ int size = 0, err = 0;
switch (ioctl_num) {
case FASTRPC_IOCTL_INVOKE_FD:
case FASTRPC_IOCTL_INVOKE:
invokefd.fds = 0;
size = (ioctl_num == FASTRPC_IOCTL_INVOKE) ?
- sizeof(*invoke) : sizeof(invokefd);
+ sizeof(invokefd.inv) : sizeof(invokefd);
VERIFY(err, 0 == copy_from_user(&invokefd, param, size));
if (err)
goto bail;
- bufs = REMOTE_SCALARS_INBUFS(invoke->sc) +
- REMOTE_SCALARS_OUTBUFS(invoke->sc);
- if (bufs) {
- size = bufs * sizeof(*pra);
- if (invokefd.fds)
- size = size + bufs * sizeof(*fds) +
- bufs * sizeof(struct ion_handle *);
- VERIFY(err, 0 != (pra = kzalloc(size, GFP_KERNEL)));
- if (err)
- goto bail;
- }
- VERIFY(err, 0 == copy_from_user(pra, invoke->pra,
- bufs * sizeof(*pra)));
- if (err)
- goto bail;
- if (invokefd.fds) {
- fds = (int *)(pra + bufs);
- VERIFY(err, 0 == copy_from_user(fds, invokefd.fds,
- bufs * sizeof(*fds)));
- if (err)
- goto bail;
- }
- VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 0, invoke,
- pra, fds)));
+ VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, fdata->mode,
+ 0, &invokefd)));
if (err)
goto bail;
break;
@@ -1210,12 +1369,22 @@
if (err)
goto bail;
break;
+ case FASTRPC_IOCTL_SETMODE:
+ switch ((uint32_t)ioctl_param) {
+ case FASTRPC_MODE_PARALLEL:
+ case FASTRPC_MODE_SERIAL:
+ fdata->mode = (uint32_t)ioctl_param;
+ break;
+ default:
+ err = -ENOTTY;
+ break;
+ }
+ break;
default:
err = -ENOTTY;
break;
}
bail:
- kfree(pra);
return err;
}
@@ -1242,7 +1411,7 @@
VERIFY(err, 0 == cdev_add(&me->cdev, MKDEV(MAJOR(me->dev_no), 0), 1));
if (err)
goto cdev_init_bail;
- me->class = class_create(THIS_MODULE, "chardrv");
+ me->class = class_create(THIS_MODULE, "fastrpc");
VERIFY(err, !IS_ERR(me->class));
if (err)
goto class_create_bail;
@@ -1251,7 +1420,6 @@
VERIFY(err, !IS_ERR(me->dev));
if (err)
goto device_create_bail;
- pr_info("'created /dev/%s c %d 0'\n", DEVICE_NAME, MAJOR(me->dev_no));
return 0;
@@ -1271,7 +1439,9 @@
{
struct fastrpc_apps *me = &gfa;
+ context_list_dtor(me, &me->clst);
fastrpc_deinit();
+ cleanup_current_dev();
device_destroy(me->class, MKDEV(MAJOR(me->dev_no), 0));
class_destroy(me->class);
cdev_del(&me->cdev);
diff --git a/drivers/char/adsprpc_shared.h b/drivers/char/adsprpc_shared.h
index da70eb5..f5d7450 100644
--- a/drivers/char/adsprpc_shared.h
+++ b/drivers/char/adsprpc_shared.h
@@ -20,9 +20,16 @@
#define FASTRPC_IOCTL_MMAP _IOWR('R', 2, struct fastrpc_ioctl_mmap)
#define FASTRPC_IOCTL_MUNMAP _IOWR('R', 3, struct fastrpc_ioctl_munmap)
#define FASTRPC_IOCTL_INVOKE_FD _IOWR('R', 4, struct fastrpc_ioctl_invoke_fd)
+#define FASTRPC_IOCTL_SETMODE _IOWR('R', 5, uint32_t)
#define FASTRPC_SMD_GUID "fastrpcsmd-apps-dsp"
#define DEVICE_NAME "adsprpc-smd"
+/* Driver should operate in parallel with the co-processor */
+#define FASTRPC_MODE_PARALLEL 0
+
+/* Driver should operate in serial mode with the co-processor */
+#define FASTRPC_MODE_SERIAL 1
+
/* Retrives number of input buffers from the scalars parameter */
#define REMOTE_SCALARS_INBUFS(sc) (((sc) >> 16) & 0x0ff)
diff --git a/drivers/char/csdio.c b/drivers/char/csdio.c
deleted file mode 100644
index 85306d3..0000000
--- a/drivers/char/csdio.c
+++ /dev/null
@@ -1,1074 +0,0 @@
-/*
- * Copyright (c) 2010, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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/moduleparam.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/mutex.h>
-#include <linux/serial_reg.h>
-#include <linux/circ_buf.h>
-#include <linux/gfp.h>
-#include <linux/uaccess.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-
-/* Char device */
-#include <linux/cdev.h>
-#include <linux/fs.h>
-
-/* Sdio device */
-#include <linux/mmc/core.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/sdio.h>
-#include <linux/mmc/sdio_func.h>
-#include <linux/mmc/sdio_ids.h>
-
-#include <linux/csdio.h>
-
-#define FALSE 0
-#define TRUE 1
-
-#define VERSION "0.5"
-#define CSDIO_NUM_OF_SDIO_FUNCTIONS 7
-#define CSDIO_DEV_NAME "csdio"
-#define TP_DEV_NAME CSDIO_DEV_NAME"f"
-#define CSDIO_DEV_PERMISSIONS 0666
-
-#define CSDIO_SDIO_BUFFER_SIZE (64*512)
-
-int csdio_major;
-int csdio_minor;
-int csdio_transport_nr_devs = CSDIO_NUM_OF_SDIO_FUNCTIONS;
-static uint csdio_vendor_id;
-static uint csdio_device_id;
-static char *host_name;
-
-static struct csdio_func_t {
- struct sdio_func *m_func;
- int m_enabled;
- struct cdev m_cdev; /* char device structure */
- struct device *m_device;
- u32 m_block_size;
-} *g_csdio_func_table[CSDIO_NUM_OF_SDIO_FUNCTIONS] = {0};
-
-struct csdio_t {
- struct cdev m_cdev;
- struct device *m_device;
- struct class *m_driver_class;
- struct fasync_struct *m_async_queue;
- unsigned char m_current_irq_mask; /* currently enabled irqs */
- struct mmc_host *m_host;
- unsigned int m_num_of_func;
-} g_csdio;
-
-struct csdio_file_descriptor {
- struct csdio_func_t *m_port;
- u32 m_block_mode;/* data tran. byte(0)/block(1) */
- u32 m_op_code; /* address auto increment flag */
- u32 m_address;
-};
-
-static void *g_sdio_buffer;
-
-/*
- * Open and release
- */
-static int csdio_transport_open(struct inode *inode, struct file *filp)
-{
- int ret = 0;
- struct csdio_func_t *port = NULL; /* device information */
- struct sdio_func *func = NULL;
- struct csdio_file_descriptor *descriptor = NULL;
-
- port = container_of(inode->i_cdev, struct csdio_func_t, m_cdev);
- func = port->m_func;
- descriptor = kzalloc(sizeof(struct csdio_file_descriptor), GFP_KERNEL);
- if (!descriptor) {
- ret = -ENOMEM;
- goto exit;
- }
-
- pr_info(TP_DEV_NAME"%d: open: func=%p, port=%p\n",
- func->num, func, port);
- sdio_claim_host(func);
- ret = sdio_enable_func(func);
- if (ret) {
- pr_err(TP_DEV_NAME"%d:Enable func failed (%d)\n",
- func->num, ret);
- ret = -EIO;
- goto free_descriptor;
- }
- descriptor->m_port = port;
- filp->private_data = descriptor;
- goto release_host;
-
-free_descriptor:
- kfree(descriptor);
-release_host:
- sdio_release_host(func);
-exit:
- return ret;
-}
-
-static int csdio_transport_release(struct inode *inode, struct file *filp)
-{
- int ret = 0;
- struct csdio_file_descriptor *descriptor = filp->private_data;
- struct csdio_func_t *port = descriptor->m_port;
- struct sdio_func *func = port->m_func;
-
- pr_info(TP_DEV_NAME"%d: release\n", func->num);
- sdio_claim_host(func);
- ret = sdio_disable_func(func);
- if (ret) {
- pr_err(TP_DEV_NAME"%d:Disable func failed(%d)\n",
- func->num, ret);
- ret = -EIO;
- }
- sdio_release_host(func);
- kfree(descriptor);
- return ret;
-}
-
-/*
- * Data management: read and write
- */
-static ssize_t csdio_transport_read(struct file *filp,
- char __user *buf,
- size_t count,
- loff_t *f_pos)
-{
- ssize_t ret = 0;
- struct csdio_file_descriptor *descriptor = filp->private_data;
- struct csdio_func_t *port = descriptor->m_port;
- struct sdio_func *func = port->m_func;
- size_t t_count = count;
-
- if (descriptor->m_block_mode) {
- pr_info(TP_DEV_NAME "%d: CMD53 read, Md:%d, Addr:0x%04X,"
- " Un:%d (Bl:%d, BlSz:%d)\n", func->num,
- descriptor->m_block_mode,
- descriptor->m_address,
- count*port->m_block_size,
- count, port->m_block_size);
- /* recalculate size */
- count *= port->m_block_size;
- }
- sdio_claim_host(func);
- if (descriptor->m_op_code) {
- /* auto increment */
- ret = sdio_memcpy_fromio(func, g_sdio_buffer,
- descriptor->m_address, count);
- } else { /* FIFO */
- ret = sdio_readsb(func, g_sdio_buffer,
- descriptor->m_address, count);
- }
- sdio_release_host(func);
- if (!ret) {
- if (copy_to_user(buf, g_sdio_buffer, count))
- ret = -EFAULT;
- else
- ret = t_count;
- }
- if (ret < 0) {
- pr_err(TP_DEV_NAME "%d: CMD53 read failed (%d)"
- "(Md:%d, Addr:0x%04X, Sz:%d)\n",
- func->num, ret,
- descriptor->m_block_mode,
- descriptor->m_address, count);
- }
- return ret;
-}
-
-static ssize_t csdio_transport_write(struct file *filp,
- const char __user *buf,
- size_t count,
- loff_t *f_pos)
-{
- ssize_t ret = 0;
- struct csdio_file_descriptor *descriptor = filp->private_data;
- struct csdio_func_t *port = descriptor->m_port;
- struct sdio_func *func = port->m_func;
- size_t t_count = count;
-
- if (descriptor->m_block_mode)
- count *= port->m_block_size;
-
- if (copy_from_user(g_sdio_buffer, buf, count)) {
- pr_err(TP_DEV_NAME"%d:copy_from_user failed\n", func->num);
- ret = -EFAULT;
- } else {
- sdio_claim_host(func);
- if (descriptor->m_op_code) {
- /* auto increment */
- ret = sdio_memcpy_toio(func, descriptor->m_address,
- g_sdio_buffer, count);
- } else {
- /* FIFO */
- ret = sdio_writesb(func, descriptor->m_address,
- g_sdio_buffer, count);
- }
- sdio_release_host(func);
- if (!ret) {
- ret = t_count;
- } else {
- pr_err(TP_DEV_NAME "%d: CMD53 write failed (%d)"
- "(Md:%d, Addr:0x%04X, Sz:%d)\n",
- func->num, ret, descriptor->m_block_mode,
- descriptor->m_address, count);
- }
- }
- return ret;
-}
-
-/* disable interrupt for sdio client */
-static int disable_sdio_client_isr(struct sdio_func *func)
-{
- int ret;
-
- /* disable for all functions, to restore interrupts
- * use g_csdio.m_current_irq_mask */
- sdio_f0_writeb(func, 0, SDIO_CCCR_IENx, &ret);
- if (ret)
- pr_err(CSDIO_DEV_NAME" Can't sdio_f0_writeb (%d)\n", ret);
-
- return ret;
-}
-
-/*
- * This handles the interrupt from SDIO.
- */
-static void csdio_sdio_irq(struct sdio_func *func)
-{
- int ret;
-
- pr_info(CSDIO_DEV_NAME" csdio_sdio_irq: func=%d\n", func->num);
- ret = disable_sdio_client_isr(func);
- if (ret) {
- pr_err(CSDIO_DEV_NAME" Can't disable client isr(%d)\n", ret);
- return;
- }
- /* signal asynchronous readers */
- if (g_csdio.m_async_queue)
- kill_fasync(&g_csdio.m_async_queue, SIGIO, POLL_IN);
-}
-
-/*
- * The ioctl() implementation
- */
-static int csdio_transport_ioctl(struct inode *inode,
- struct file *filp,
- unsigned int cmd,
- unsigned long arg)
-{
- int err = 0;
- int ret = 0;
- struct csdio_file_descriptor *descriptor = filp->private_data;
- struct csdio_func_t *port = descriptor->m_port;
- struct sdio_func *func = port->m_func;
-
- /* extract the type and number bitfields
- sanity check: return ENOTTY (inappropriate ioctl) before
- access_ok()
- */
- if ((_IOC_TYPE(cmd) != CSDIO_IOC_MAGIC) ||
- (_IOC_NR(cmd) > CSDIO_IOC_MAXNR)) {
- pr_err(TP_DEV_NAME "Wrong ioctl command parameters\n");
- ret = -ENOTTY;
- goto exit;
- }
-
- /* the direction is a bitmask, and VERIFY_WRITE catches R/W
- * transfers. `Type' is user-oriented, while access_ok is
- kernel-oriented, so the concept of "read" and "write" is reversed
- */
- if (_IOC_DIR(cmd) & _IOC_READ) {
- err = !access_ok(VERIFY_WRITE, (void __user *)arg,
- _IOC_SIZE(cmd));
- } else {
- if (_IOC_DIR(cmd) & _IOC_WRITE) {
- err = !access_ok(VERIFY_READ, (void __user *)arg,
- _IOC_SIZE(cmd));
- }
- }
- if (err) {
- pr_err(TP_DEV_NAME "Wrong ioctl access direction\n");
- ret = -EFAULT;
- goto exit;
- }
-
- switch (cmd) {
- case CSDIO_IOC_SET_OP_CODE:
- {
- pr_info(TP_DEV_NAME"%d:SET_OP_CODE=%d\n",
- func->num, descriptor->m_op_code);
- ret = get_user(descriptor->m_op_code,
- (unsigned char __user *)arg);
- if (ret) {
- pr_err(TP_DEV_NAME"%d:SET_OP_CODE get data"
- " from user space failed(%d)\n",
- func->num, ret);
- ret = -ENOTTY;
- break;
- }
- }
- break;
- case CSDIO_IOC_FUNCTION_SET_BLOCK_SIZE:
- {
- unsigned block_size;
-
- ret = get_user(block_size, (unsigned __user *)arg);
- if (ret) {
- pr_err(TP_DEV_NAME"%d:SET_BLOCK_SIZE get data"
- " from user space failed(%d)\n",
- func->num, ret);
- ret = -ENOTTY;
- break;
- }
- pr_info(TP_DEV_NAME"%d:SET_BLOCK_SIZE=%d\n",
- func->num, block_size);
- sdio_claim_host(func);
- ret = sdio_set_block_size(func, block_size);
- if (!ret) {
- port->m_block_size = block_size;
- } else {
- pr_err(TP_DEV_NAME"%d:SET_BLOCK_SIZE set block"
- " size to %d failed (%d)\n",
- func->num, block_size, ret);
- ret = -ENOTTY;
- break;
- }
- sdio_release_host(func);
- }
- break;
- case CSDIO_IOC_SET_BLOCK_MODE:
- {
- pr_info(TP_DEV_NAME"%d:SET_BLOCK_MODE=%d\n",
- func->num, descriptor->m_block_mode);
- ret = get_user(descriptor->m_block_mode,
- (unsigned char __user *)arg);
- if (ret) {
- pr_err(TP_DEV_NAME"%d:SET_BLOCK_MODE get data"
- " from user space failed\n",
- func->num);
- ret = -ENOTTY;
- break;
- }
- }
- break;
- case CSDIO_IOC_CMD52:
- {
- struct csdio_cmd52_ctrl_t cmd52ctrl;
- int cmd52ret;
-
- if (copy_from_user(&cmd52ctrl,
- (const unsigned char __user *)arg,
- sizeof(cmd52ctrl))) {
- pr_err(TP_DEV_NAME"%d:IOC_CMD52 get data"
- " from user space failed\n",
- func->num);
- ret = -ENOTTY;
- break;
- }
- sdio_claim_host(func);
- if (cmd52ctrl.m_write)
- sdio_writeb(func, cmd52ctrl.m_data,
- cmd52ctrl.m_address, &cmd52ret);
- else
- cmd52ctrl.m_data = sdio_readb(func,
- cmd52ctrl.m_address, &cmd52ret);
-
- cmd52ctrl.m_ret = cmd52ret;
- sdio_release_host(func);
- if (cmd52ctrl.m_ret)
- pr_err(TP_DEV_NAME"%d:IOC_CMD52 failed (%d)\n",
- func->num, cmd52ctrl.m_ret);
-
- if (copy_to_user((unsigned char __user *)arg,
- &cmd52ctrl,
- sizeof(cmd52ctrl))) {
- pr_err(TP_DEV_NAME"%d:IOC_CMD52 put data"
- " to user space failed\n",
- func->num);
- ret = -ENOTTY;
- break;
- }
- }
- break;
- case CSDIO_IOC_CMD53:
- {
- struct csdio_cmd53_ctrl_t csdio_cmd53_ctrl;
-
- if (copy_from_user(&csdio_cmd53_ctrl,
- (const char __user *)arg,
- sizeof(csdio_cmd53_ctrl))) {
- ret = -EPERM;
- pr_err(TP_DEV_NAME"%d:"
- "Get data from user space failed\n",
- func->num);
- break;
- }
- descriptor->m_block_mode =
- csdio_cmd53_ctrl.m_block_mode;
- descriptor->m_op_code = csdio_cmd53_ctrl.m_op_code;
- descriptor->m_address = csdio_cmd53_ctrl.m_address;
- }
- break;
- case CSDIO_IOC_CONNECT_ISR:
- {
- pr_info(CSDIO_DEV_NAME" SDIO_CONNECT_ISR"
- " func=%d, csdio_sdio_irq=%x\n",
- func->num, (unsigned int)csdio_sdio_irq);
- sdio_claim_host(func);
- ret = sdio_claim_irq(func, csdio_sdio_irq);
- sdio_release_host(func);
- if (ret) {
- pr_err(CSDIO_DEV_NAME" SDIO_CONNECT_ISR"
- " claim irq failed(%d)\n", ret);
- } else {
- /* update current irq mask for disable/enable */
- g_csdio.m_current_irq_mask |= (1 << func->num);
- }
- }
- break;
- case CSDIO_IOC_DISCONNECT_ISR:
- {
- pr_info(CSDIO_DEV_NAME " SDIO_DISCONNECT_ISR func=%d\n",
- func->num);
- sdio_claim_host(func);
- sdio_release_irq(func);
- sdio_release_host(func);
- /* update current irq mask for disable/enable */
- g_csdio.m_current_irq_mask &= ~(1 << func->num);
- }
- break;
- default: /* redundant, as cmd was checked against MAXNR */
- pr_warning(TP_DEV_NAME"%d: Redundant IOCTL\n",
- func->num);
- ret = -ENOTTY;
- }
-exit:
- return ret;
-}
-
-static const struct file_operations csdio_transport_fops = {
- .owner = THIS_MODULE,
- .read = csdio_transport_read,
- .write = csdio_transport_write,
- .ioctl = csdio_transport_ioctl,
- .open = csdio_transport_open,
- .release = csdio_transport_release,
-};
-
-static void csdio_transport_cleanup(struct csdio_func_t *port)
-{
- int devno = MKDEV(csdio_major, csdio_minor + port->m_func->num);
- device_destroy(g_csdio.m_driver_class, devno);
- port->m_device = NULL;
- cdev_del(&port->m_cdev);
-}
-
-#if defined(CONFIG_DEVTMPFS)
-static inline int csdio_cdev_update_permissions(
- const char *devname, int dev_minor)
-{
- return 0;
-}
-#else
-static int csdio_cdev_update_permissions(
- const char *devname, int dev_minor)
-{
- int ret = 0;
- mm_segment_t fs;
- struct file *file;
- struct inode *inode;
- struct iattr newattrs;
- int mode = CSDIO_DEV_PERMISSIONS;
- char dev_file[64];
-
- fs = get_fs();
- set_fs(get_ds());
-
- snprintf(dev_file, sizeof(dev_file), "/dev/%s%d",
- devname, dev_minor);
- file = filp_open(dev_file, O_RDWR, 0);
- if (IS_ERR(file)) {
- ret = -EFAULT;
- goto exit;
- }
-
- inode = file->f_path.dentry->d_inode;
-
- mutex_lock(&inode->i_mutex);
- newattrs.ia_mode =
- (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
- newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
- ret = notify_change(file->f_path.dentry, &newattrs);
- mutex_unlock(&inode->i_mutex);
-
- filp_close(file, NULL);
-
-exit:
- set_fs(fs);
- return ret;
-}
-#endif
-
-static struct device *csdio_cdev_init(struct cdev *char_dev,
- const struct file_operations *file_op, int dev_minor,
- const char *devname, struct device *parent)
-{
- int ret = 0;
- struct device *new_device = NULL;
- dev_t devno = MKDEV(csdio_major, dev_minor);
-
- /* Initialize transport device */
- cdev_init(char_dev, file_op);
- char_dev->owner = THIS_MODULE;
- char_dev->ops = file_op;
- ret = cdev_add(char_dev, devno, 1);
-
- /* Fail gracefully if need be */
- if (ret) {
- pr_warning("Error %d adding CSDIO char device '%s%d'",
- ret, devname, dev_minor);
- goto exit;
- }
- pr_info("'%s%d' char driver registered\n", devname, dev_minor);
-
- /* create a /dev entry for transport drivers */
- new_device = device_create(g_csdio.m_driver_class, parent, devno, NULL,
- "%s%d", devname, dev_minor);
- if (!new_device) {
- pr_err("Can't create device node '/dev/%s%d'\n",
- devname, dev_minor);
- goto cleanup;
- }
- /* no irq attached */
- g_csdio.m_current_irq_mask = 0;
-
- if (csdio_cdev_update_permissions(devname, dev_minor)) {
- pr_warning("%s%d: Unable to update access permissions of the"
- " '/dev/%s%d'\n",
- devname, dev_minor, devname, dev_minor);
- }
-
- pr_info("%s%d: Device node '/dev/%s%d' created successfully\n",
- devname, dev_minor, devname, dev_minor);
- goto exit;
-cleanup:
- cdev_del(char_dev);
-exit:
- return new_device;
-}
-
-/* Looks for first non empty function, returns NULL otherwise */
-static struct sdio_func *get_active_func(void)
-{
- int i;
-
- for (i = 0; i < CSDIO_NUM_OF_SDIO_FUNCTIONS; i++) {
- if (g_csdio_func_table[i])
- return g_csdio_func_table[i]->m_func;
- }
- return NULL;
-}
-
-static ssize_t
-show_vdd(struct device *dev, struct device_attribute *attr, char *buf)
-{
- if (NULL == g_csdio.m_host)
- return snprintf(buf, PAGE_SIZE, "N/A\n");
- return snprintf(buf, PAGE_SIZE, "%d\n",
- g_csdio.m_host->ios.vdd);
-}
-
-static int
-set_vdd_helper(int value)
-{
- struct mmc_ios *ios = NULL;
-
- if (NULL == g_csdio.m_host) {
- pr_err("%s0: Set VDD, no MMC host assigned\n", CSDIO_DEV_NAME);
- return -ENXIO;
- }
-
- mmc_claim_host(g_csdio.m_host);
- ios = &g_csdio.m_host->ios;
- ios->vdd = value;
- g_csdio.m_host->ops->set_ios(g_csdio.m_host, ios);
- mmc_release_host(g_csdio.m_host);
- return 0;
-}
-
-static ssize_t
-set_vdd(struct device *dev, struct device_attribute *att,
- const char *buf, size_t count)
-{
- int value = 0;
-
- sscanf(buf, "%d", &value);
- if (set_vdd_helper(value))
- return -ENXIO;
- return count;
-}
-
-static DEVICE_ATTR(vdd, S_IRUGO | S_IWUSR,
- show_vdd, set_vdd);
-
-static struct attribute *dev_attrs[] = {
- &dev_attr_vdd.attr,
- NULL,
-};
-
-static struct attribute_group dev_attr_grp = {
- .attrs = dev_attrs,
-};
-
-/*
- * The ioctl() implementation for control device
- */
-static int csdio_ctrl_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- int err = 0;
- int ret = 0;
-
- pr_info("CSDIO ctrl ioctl.\n");
-
- /* extract the type and number bitfields
- sanity check: return ENOTTY (inappropriate ioctl) before
- access_ok()
- */
- if ((_IOC_TYPE(cmd) != CSDIO_IOC_MAGIC) ||
- (_IOC_NR(cmd) > CSDIO_IOC_MAXNR)) {
- pr_err(CSDIO_DEV_NAME "Wrong ioctl command parameters\n");
- ret = -ENOTTY;
- goto exit;
- }
-
- /* the direction is a bitmask, and VERIFY_WRITE catches R/W
- transfers. `Type' is user-oriented, while access_ok is
- kernel-oriented, so the concept of "read" and "write" is reversed
- */
- if (_IOC_DIR(cmd) & _IOC_READ) {
- err = !access_ok(VERIFY_WRITE, (void __user *)arg,
- _IOC_SIZE(cmd));
- } else {
- if (_IOC_DIR(cmd) & _IOC_WRITE)
- err = !access_ok(VERIFY_READ, (void __user *)arg,
- _IOC_SIZE(cmd));
- }
- if (err) {
- pr_err(CSDIO_DEV_NAME "Wrong ioctl access direction\n");
- ret = -EFAULT;
- goto exit;
- }
-
- switch (cmd) {
- case CSDIO_IOC_ENABLE_HIGHSPEED_MODE:
- pr_info(CSDIO_DEV_NAME" ENABLE_HIGHSPEED_MODE\n");
- break;
- case CSDIO_IOC_SET_DATA_TRANSFER_CLOCKS:
- {
- struct mmc_host *host = g_csdio.m_host;
- struct mmc_ios *ios = NULL;
-
- if (NULL == host) {
- pr_err("%s0: "
- "CSDIO_IOC_SET_DATA_TRANSFER_CLOCKS,"
- " no MMC host assigned\n",
- CSDIO_DEV_NAME);
- ret = -EFAULT;
- goto exit;
- }
- ios = &host->ios;
-
- mmc_claim_host(host);
- ret = get_user(host->ios.clock,
- (unsigned int __user *)arg);
- if (ret) {
- pr_err(CSDIO_DEV_NAME
- " get data from user space failed\n");
- } else {
- pr_err(CSDIO_DEV_NAME
- "SET_DATA_TRANSFER_CLOCKS(%d-%d)(%d)\n",
- host->f_min, host->f_max,
- host->ios.clock);
- host->ops->set_ios(host, ios);
- }
- mmc_release_host(host);
- }
- break;
- case CSDIO_IOC_ENABLE_ISR:
- {
- int ret;
- unsigned char reg;
- struct sdio_func *func = get_active_func();
-
- if (!func) {
- pr_err(CSDIO_DEV_NAME " CSDIO_IOC_ENABLE_ISR"
- " no active sdio function\n");
- ret = -EFAULT;
- goto exit;
- }
- pr_info(CSDIO_DEV_NAME
- " CSDIO_IOC_ENABLE_ISR func=%d\n",
- func->num);
- reg = g_csdio.m_current_irq_mask | 1;
-
- sdio_claim_host(func);
- sdio_f0_writeb(func, reg, SDIO_CCCR_IENx, &ret);
- sdio_release_host(func);
- if (ret) {
- pr_err(CSDIO_DEV_NAME
- " Can't sdio_f0_writeb (%d)\n",
- ret);
- goto exit;
- }
- }
- break;
- case CSDIO_IOC_DISABLE_ISR:
- {
- int ret;
- struct sdio_func *func = get_active_func();
- if (!func) {
- pr_err(CSDIO_DEV_NAME " CSDIO_IOC_ENABLE_ISR"
- " no active sdio function\n");
- ret = -EFAULT;
- goto exit;
- }
- pr_info(CSDIO_DEV_NAME
- " CSDIO_IOC_DISABLE_ISR func=%p\n",
- func);
-
- sdio_claim_host(func);
- ret = disable_sdio_client_isr(func);
- sdio_release_host(func);
- if (ret) {
- pr_err("%s0: Can't disable client isr (%d)\n",
- CSDIO_DEV_NAME, ret);
- goto exit;
- }
- }
- break;
- case CSDIO_IOC_SET_VDD:
- {
- unsigned int vdd = 0;
-
- ret = get_user(vdd, (unsigned int __user *)arg);
- if (ret) {
- pr_err("%s0: CSDIO_IOC_SET_VDD,"
- " get data from user space failed\n",
- CSDIO_DEV_NAME);
- goto exit;
- }
- pr_info(CSDIO_DEV_NAME" CSDIO_IOC_SET_VDD - %d\n", vdd);
-
- ret = set_vdd_helper(vdd);
- if (ret)
- goto exit;
- }
- break;
- case CSDIO_IOC_GET_VDD:
- {
- if (NULL == g_csdio.m_host) {
- pr_err("%s0: CSDIO_IOC_GET_VDD,"
- " no MMC host assigned\n",
- CSDIO_DEV_NAME);
- ret = -EFAULT;
- goto exit;
- }
- ret = put_user(g_csdio.m_host->ios.vdd,
- (unsigned short __user *)arg);
- if (ret) {
- pr_err("%s0: CSDIO_IOC_GET_VDD, put data"
- " to user space failed\n",
- CSDIO_DEV_NAME);
- goto exit;
- }
- }
- break;
- default: /* redundant, as cmd was checked against MAXNR */
- pr_warning(CSDIO_DEV_NAME" Redundant IOCTL\n");
- ret = -ENOTTY;
- }
-exit:
- return ret;
-}
-
-static int csdio_ctrl_fasync(int fd, struct file *filp, int mode)
-{
- pr_info(CSDIO_DEV_NAME
- " csdio_ctrl_fasync: fd=%d, filp=%p, mode=%d\n",
- fd, filp, mode);
- return fasync_helper(fd, filp, mode, &g_csdio.m_async_queue);
-}
-
-/*
- * Open and close
- */
-static int csdio_ctrl_open(struct inode *inode, struct file *filp)
-{
- int ret = 0;
- struct csdio_t *csdio_ctrl_drv = NULL; /* device information */
-
- pr_info("CSDIO ctrl open.\n");
- csdio_ctrl_drv = container_of(inode->i_cdev, struct csdio_t, m_cdev);
- filp->private_data = csdio_ctrl_drv; /* for other methods */
- return ret;
-}
-
-static int csdio_ctrl_release(struct inode *inode, struct file *filp)
-{
- pr_info("CSDIO ctrl release.\n");
- /* remove this filp from the asynchronously notified filp's */
- csdio_ctrl_fasync(-1, filp, 0);
- return 0;
-}
-
-static const struct file_operations csdio_ctrl_fops = {
- .owner = THIS_MODULE,
- .ioctl = csdio_ctrl_ioctl,
- .open = csdio_ctrl_open,
- .release = csdio_ctrl_release,
- .fasync = csdio_ctrl_fasync,
-};
-
-static int csdio_probe(struct sdio_func *func,
- const struct sdio_device_id *id)
-{
- struct csdio_func_t *port;
- int ret = 0;
- struct mmc_host *host = func->card->host;
-
- if (NULL != g_csdio.m_host && g_csdio.m_host != host) {
- pr_info("%s: Device is on unexpected host\n",
- CSDIO_DEV_NAME);
- ret = -ENODEV;
- goto exit;
- }
-
- /* enforce single instance policy */
- if (g_csdio_func_table[func->num-1]) {
- pr_err("%s - only single SDIO device supported",
- sdio_func_id(func));
- ret = -EEXIST;
- goto exit;
- }
-
- port = kzalloc(sizeof(struct csdio_func_t), GFP_KERNEL);
- if (!port) {
- pr_err("Can't allocate memory\n");
- ret = -ENOMEM;
- goto exit;
- }
-
- /* initialize SDIO side */
- port->m_func = func;
- sdio_set_drvdata(func, port);
-
- pr_info("%s - SDIO device found. Function %d\n",
- sdio_func_id(func), func->num);
-
- port->m_device = csdio_cdev_init(&port->m_cdev, &csdio_transport_fops,
- csdio_minor + port->m_func->num,
- TP_DEV_NAME, &port->m_func->dev);
-
- /* create appropriate char device */
- if (!port->m_device)
- goto free;
-
- if (0 == g_csdio.m_num_of_func && NULL == host_name)
- g_csdio.m_host = host;
- g_csdio.m_num_of_func++;
- g_csdio_func_table[func->num-1] = port;
- port->m_enabled = TRUE;
- goto exit;
-free:
- kfree(port);
-exit:
- return ret;
-}
-
-static void csdio_remove(struct sdio_func *func)
-{
- struct csdio_func_t *port = sdio_get_drvdata(func);
-
- csdio_transport_cleanup(port);
- sdio_claim_host(func);
- sdio_release_irq(func);
- sdio_disable_func(func);
- sdio_release_host(func);
- kfree(port);
- g_csdio_func_table[func->num-1] = NULL;
- g_csdio.m_num_of_func--;
- if (0 == g_csdio.m_num_of_func && NULL == host_name)
- g_csdio.m_host = NULL;
- pr_info("%s%d: Device removed (%s). Function %d\n",
- CSDIO_DEV_NAME, func->num, sdio_func_id(func), func->num);
-}
-
-/* CONFIG_CSDIO_VENDOR_ID and CONFIG_CSDIO_DEVICE_ID are defined in Kconfig.
- * Use kernel configuration to change the values or overwrite them through
- * module parameters */
-static struct sdio_device_id csdio_ids[] = {
- { SDIO_DEVICE(CONFIG_CSDIO_VENDOR_ID, CONFIG_CSDIO_DEVICE_ID) },
- { /* end: all zeroes */},
-};
-
-MODULE_DEVICE_TABLE(sdio, csdio_ids);
-
-static struct sdio_driver csdio_driver = {
- .probe = csdio_probe,
- .remove = csdio_remove,
- .name = "csdio",
- .id_table = csdio_ids,
-};
-
-static void __exit csdio_exit(void)
-{
- dev_t devno = MKDEV(csdio_major, csdio_minor);
-
- sdio_unregister_driver(&csdio_driver);
- sysfs_remove_group(&g_csdio.m_device->kobj, &dev_attr_grp);
- kfree(g_sdio_buffer);
- device_destroy(g_csdio.m_driver_class, devno);
- cdev_del(&g_csdio.m_cdev);
- class_destroy(g_csdio.m_driver_class);
- unregister_chrdev_region(devno, csdio_transport_nr_devs);
- pr_info("%s: Exit driver module\n", CSDIO_DEV_NAME);
-}
-
-static char *csdio_devnode(struct device *dev, mode_t *mode)
-{
- *mode = CSDIO_DEV_PERMISSIONS;
- return NULL;
-}
-
-static int __init csdio_init(void)
-{
- int ret = 0;
- dev_t devno = 0;
-
- pr_info("Init CSDIO driver module.\n");
-
- /* Get a range of minor numbers to work with, asking for a dynamic */
- /* major unless directed otherwise at load time. */
- if (csdio_major) {
- devno = MKDEV(csdio_major, csdio_minor);
- ret = register_chrdev_region(devno, csdio_transport_nr_devs,
- CSDIO_DEV_NAME);
- } else {
- ret = alloc_chrdev_region(&devno, csdio_minor,
- csdio_transport_nr_devs, CSDIO_DEV_NAME);
- csdio_major = MAJOR(devno);
- }
- if (ret < 0) {
- pr_err("CSDIO: can't get major %d\n", csdio_major);
- goto exit;
- }
- pr_info("CSDIO char driver major number is %d\n", csdio_major);
-
- /* kernel module got parameters: overwrite vendor and device id's */
- if ((csdio_vendor_id != 0) && (csdio_device_id != 0)) {
- csdio_ids[0].vendor = (u16)csdio_vendor_id;
- csdio_ids[0].device = (u16)csdio_device_id;
- }
-
- /* prepare create /dev/... instance */
- g_csdio.m_driver_class = class_create(THIS_MODULE, CSDIO_DEV_NAME);
- if (IS_ERR(g_csdio.m_driver_class)) {
- ret = -ENOMEM;
- pr_err(CSDIO_DEV_NAME " class_create failed\n");
- goto unregister_region;
- }
- g_csdio.m_driver_class->devnode = csdio_devnode;
-
- /* create CSDIO ctrl driver */
- g_csdio.m_device = csdio_cdev_init(&g_csdio.m_cdev,
- &csdio_ctrl_fops, csdio_minor, CSDIO_DEV_NAME, NULL);
- if (!g_csdio.m_device) {
- pr_err("%s: Unable to create ctrl driver\n",
- CSDIO_DEV_NAME);
- goto destroy_class;
- }
-
- g_sdio_buffer = kmalloc(CSDIO_SDIO_BUFFER_SIZE, GFP_KERNEL);
- if (!g_sdio_buffer) {
- pr_err("Unable to allocate %d bytes\n", CSDIO_SDIO_BUFFER_SIZE);
- ret = -ENOMEM;
- goto destroy_cdev;
- }
-
- ret = sysfs_create_group(&g_csdio.m_device->kobj, &dev_attr_grp);
- if (ret) {
- pr_err("%s: Unable to create device attribute\n",
- CSDIO_DEV_NAME);
- goto free_sdio_buff;
- }
-
- g_csdio.m_num_of_func = 0;
- g_csdio.m_host = NULL;
-
- if (NULL != host_name) {
- struct device *dev = bus_find_device_by_name(&platform_bus_type,
- NULL, host_name);
- if (NULL != dev) {
- g_csdio.m_host = dev_get_drvdata(dev);
- } else {
- pr_err("%s: Host '%s' doesn't exist!\n", CSDIO_DEV_NAME,
- host_name);
- }
- }
-
- pr_info("%s: Match with VendorId=0x%X, DeviceId=0x%X, Host = %s\n",
- CSDIO_DEV_NAME, csdio_device_id, csdio_vendor_id,
- (NULL == host_name) ? "Any" : host_name);
-
- /* register sdio driver */
- ret = sdio_register_driver(&csdio_driver);
- if (ret) {
- pr_err("%s: Unable to register as SDIO driver\n",
- CSDIO_DEV_NAME);
- goto remove_group;
- }
-
- goto exit;
-
-remove_group:
- sysfs_remove_group(&g_csdio.m_device->kobj, &dev_attr_grp);
-free_sdio_buff:
- kfree(g_sdio_buffer);
-destroy_cdev:
- cdev_del(&g_csdio.m_cdev);
-destroy_class:
- class_destroy(g_csdio.m_driver_class);
-unregister_region:
- unregister_chrdev_region(devno, csdio_transport_nr_devs);
-exit:
- return ret;
-}
-module_param(csdio_vendor_id, uint, S_IRUGO);
-module_param(csdio_device_id, uint, S_IRUGO);
-module_param(host_name, charp, S_IRUGO);
-
-module_init(csdio_init);
-module_exit(csdio_exit);
-
-MODULE_AUTHOR("The Linux Foundation");
-MODULE_DESCRIPTION("CSDIO device driver version " VERSION);
-MODULE_VERSION(VERSION);
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 97dc26d..414207f 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -124,45 +124,135 @@
return 0;
}
+static struct dci_pkt_req_entry_t *diag_register_dci_transaction(int uid)
+{
+ struct dci_pkt_req_entry_t *entry = NULL;
+ entry = kzalloc(sizeof(struct dci_pkt_req_entry_t), GFP_KERNEL);
+ if (!entry)
+ return NULL;
+
+ mutex_lock(&driver->dci_mutex);
+ driver->dci_tag++;
+ entry->pid = current->tgid;
+ entry->uid = uid;
+ entry->tag = driver->dci_tag;
+ list_add_tail(&entry->track, &driver->dci_req_list);
+ mutex_unlock(&driver->dci_mutex);
+
+ return entry;
+}
+
+static struct dci_pkt_req_entry_t *diag_dci_get_request_entry(int tag)
+{
+ struct list_head *start, *temp;
+ struct dci_pkt_req_entry_t *entry = NULL;
+ list_for_each_safe(start, temp, &driver->dci_req_list) {
+ entry = list_entry(start, struct dci_pkt_req_entry_t, track);
+ if (entry->tag == tag)
+ return entry;
+ }
+ return NULL;
+}
+
+static int diag_dci_remove_req_entry(unsigned char *buf, int len,
+ struct dci_pkt_req_entry_t *entry)
+{
+ uint16_t rsp_count = 0, delayed_rsp_id = 0;
+ if (!buf || len <= 0 || !entry) {
+ pr_err("diag: In %s, invalid input buf: %p, len: %d, entry: %p\n",
+ __func__, buf, len, entry);
+ return -EIO;
+ }
+
+ /* It is an immediate response, delete it from the table */
+ if (*buf != 0x80) {
+ list_del(&entry->track);
+ kfree(entry);
+ return 1;
+ }
+
+ /* It is a delayed response. Check if the length is valid */
+ if (len < MIN_DELAYED_RSP_LEN) {
+ pr_err("diag: Invalid delayed rsp packet length %d\n", len);
+ return -EINVAL;
+ }
+
+ /*
+ * If the delayed response id field (uint16_t at byte 8) is 0 then
+ * there is only one response and we can remove the request entry.
+ */
+ delayed_rsp_id = *(uint16_t *)(buf + 8);
+ if (delayed_rsp_id == 0) {
+ list_del(&entry->track);
+ kfree(entry);
+ return 1;
+ }
+
+ /*
+ * Check the response count field (uint16 at byte 10). The request
+ * entry can be deleted it it is the last response in the sequence.
+ * It is the last response in the sequence if the response count
+ * is 1 or if the signed bit gets dropped.
+ */
+ rsp_count = *(uint16_t *)(buf + 10);
+ if (rsp_count > 0 && rsp_count < 0x1000) {
+ list_del(&entry->track);
+ kfree(entry);
+ return 1;
+ }
+
+ return 0;
+}
+
void extract_dci_pkt_rsp(struct diag_smd_info *smd_info, unsigned char *buf)
{
- int i = 0, index = -1, cmd_code_len = 1;
- int curr_client_pid = 0, write_len;
+ int i = 0, cmd_code_len = 1;
+ int curr_client_pid = 0, write_len, *tag = NULL;
struct diag_dci_client_tbl *entry;
void *temp_buf = NULL;
- uint8_t recv_pkt_cmd_code;
-
+ uint8_t recv_pkt_cmd_code, delete_flag = 0;
+ struct dci_pkt_req_entry_t *req_entry = NULL;
recv_pkt_cmd_code = *(uint8_t *)(buf+4);
if (recv_pkt_cmd_code != DCI_PKT_RSP_CODE)
cmd_code_len = 4; /* delayed response */
write_len = (int)(*(uint16_t *)(buf+2)) - cmd_code_len;
-
- pr_debug("diag: len = %d\n", write_len);
- /* look up DCI client with tag */
- for (i = 0; i < dci_max_reg; i++) {
- if (driver->req_tracking_tbl[i].tag ==
- *(int *)(buf+(4+cmd_code_len))) {
- *(int *)(buf+4+cmd_code_len) =
- driver->req_tracking_tbl[i].uid;
- curr_client_pid =
- driver->req_tracking_tbl[i].pid;
- index = i;
- break;
- }
+ if (write_len <= 0) {
+ pr_err("diag: Invalid length in %s, write_len: %d",
+ __func__, write_len);
+ return;
}
- if (index == -1) {
+ pr_debug("diag: len = %d\n", write_len);
+ tag = (int *)(buf + (4 + cmd_code_len)); /* Retrieve the Tag field */
+ req_entry = diag_dci_get_request_entry(*tag);
+ if (!req_entry) {
pr_alert("diag: No matching PID for DCI data\n");
return;
}
+ *tag = req_entry->uid;
+ curr_client_pid = req_entry->pid;
+
+ /* Remove the headers and send only the response to this function */
+ delete_flag = diag_dci_remove_req_entry(buf + 8 + cmd_code_len,
+ write_len - 4,
+ req_entry);
+ if (delete_flag < 0)
+ return;
+
/* Using PID of client process, find client buffer */
i = diag_dci_find_client_index(curr_client_pid);
if (i != DCI_CLIENT_INDEX_INVALID) {
/* copy pkt rsp in client buf */
entry = &(driver->dci_client_tbl[i]);
mutex_lock(&entry->data_mutex);
- if (DCI_CHK_CAPACITY(entry, 8+write_len)) {
+ /*
+ * Check if we can fit the data in the rsp buffer. The total
+ * length of the rsp is the rsp length (write_len) +
+ * DCI_PKT_RSP_TYPE header (int) + field for length (int) +
+ * delete_flag (uint8_t)
+ */
+ if (DCI_CHK_CAPACITY(entry, 9+write_len)) {
pr_alert("diag: create capacity for pkt rsp\n");
- entry->total_capacity += 8+write_len;
+ entry->total_capacity += 9+write_len;
temp_buf = krealloc(entry->dci_data,
entry->total_capacity, GFP_KERNEL);
if (!temp_buf) {
@@ -179,13 +269,12 @@
*(int *)(entry->dci_data+entry->data_len)
= write_len;
entry->data_len += 4;
+ *(uint8_t *)(entry->dci_data + entry->data_len) = delete_flag;
+ entry->data_len += sizeof(uint8_t);
memcpy(entry->dci_data+entry->data_len,
buf+4+cmd_code_len, write_len);
entry->data_len += write_len;
mutex_unlock(&entry->data_mutex);
- /* delete immediate response entry */
- if (smd_info->buf_in_1[8+cmd_code_len] != 0x80)
- driver->req_tracking_tbl[index].pid = 0;
}
}
@@ -298,17 +387,23 @@
void extract_dci_log(unsigned char *buf)
{
- uint16_t log_code, item_num;
+ uint16_t log_code, item_num, log_length;
uint8_t equip_id, *log_mask_ptr, byte_mask;
unsigned int i, byte_index, byte_offset = 0;
struct diag_dci_client_tbl *entry;
+ log_length = *(uint16_t *)(buf + 2);
log_code = *(uint16_t *)(buf + 6);
equip_id = LOG_GET_EQUIP_ID(log_code);
item_num = LOG_GET_ITEM_NUM(log_code);
byte_index = item_num/8 + 2;
byte_mask = 0x01 << (item_num % 8);
+ if (log_length > USHRT_MAX - 4) {
+ pr_err("diag: Integer overflow in %s, log_len:%d",
+ __func__, log_length);
+ return;
+ }
byte_offset = (equip_id * 514) + byte_index;
if (byte_offset >= DCI_LOG_MASK_SIZE) {
pr_err("diag: Invalid byte_offset %d in dci log\n",
@@ -345,8 +440,8 @@
*(int *)(entry->dci_data+entry->data_len) =
DCI_LOG_TYPE;
memcpy(entry->dci_data + entry->data_len + 4,
- buf + 4, *(uint16_t *)(buf + 2));
- entry->data_len += 4 + *(uint16_t *)(buf + 2);
+ buf + 4, log_length);
+ entry->data_len += 4 + log_length;
}
mutex_unlock(&entry->data_mutex);
mutex_unlock(&dci_health_mutex);
@@ -419,6 +514,8 @@
/* Notify the DCI process that the peripheral DCI Channel is up */
for (i = 0; i < MAX_DCI_CLIENTS; i++) {
+ if (!driver->dci_client_tbl[i].client)
+ continue;
if (driver->dci_client_tbl[i].list & peripheral_mask) {
info.si_signo = driver->dci_client_tbl[i].signal_type;
stat = send_sig_info(
@@ -431,8 +528,8 @@
} /* end of loop for all DCI clients */
}
-int diag_send_dci_pkt(struct diag_master_table entry, unsigned char *buf,
- int len, int index)
+static int diag_send_dci_pkt(struct diag_master_table entry, unsigned char *buf,
+ int len, int tag)
{
int i, status = 0;
unsigned int read_len = 0;
@@ -457,8 +554,7 @@
driver->apps_dci_buf[1] = 1; /* version */
*(uint16_t *)(driver->apps_dci_buf + 2) = len + 4 + 1; /* length */
driver->apps_dci_buf[4] = DCI_PKT_RSP_CODE;
- *(int *)(driver->apps_dci_buf + 5) =
- driver->req_tracking_tbl[index].tag;
+ *(int *)(driver->apps_dci_buf + 5) = tag;
for (i = 0; i < len; i++)
driver->apps_dci_buf[i+9] = *(buf+i);
read_len += len;
@@ -492,42 +588,17 @@
return status;
}
-int diag_register_dci_transaction(int uid)
-{
- int i, new_dci_client = 1, ret = -1;
-
- for (i = 0; i < dci_max_reg; i++) {
- if (driver->req_tracking_tbl[i].pid == current->tgid) {
- new_dci_client = 0;
- break;
- }
- }
- mutex_lock(&driver->dci_mutex);
- /* Make an entry in kernel DCI table */
- driver->dci_tag++;
- for (i = 0; i < dci_max_reg; i++) {
- if (driver->req_tracking_tbl[i].pid == 0) {
- driver->req_tracking_tbl[i].pid = current->tgid;
- driver->req_tracking_tbl[i].uid = uid;
- driver->req_tracking_tbl[i].tag = driver->dci_tag;
- ret = i;
- break;
- }
- }
- mutex_unlock(&driver->dci_mutex);
- return ret;
-}
-
int diag_process_dci_transaction(unsigned char *buf, int len)
{
unsigned char *temp = buf;
uint16_t subsys_cmd_code, log_code, item_num;
- int subsys_id, cmd_code, ret = -1, index = -1, found = 0;
+ int subsys_id, cmd_code, ret = -1, found = 0;
struct diag_master_table entry;
int count, set_mask, num_codes, bit_index, event_id, offset = 0, i;
unsigned int byte_index, read_len = 0;
uint8_t equip_id, *log_mask_ptr, *head_log_mask_ptr, byte_mask;
uint8_t *event_mask_ptr;
+ struct dci_pkt_req_entry_t *req_entry = NULL;
if (!driver->smd_dci[MODEM_DATA].ch) {
pr_err("diag: DCI smd channel for peripheral %d not valid for dci updates\n",
@@ -548,8 +619,8 @@
return -EIO;
}
/* enter this UID into kernel table and return index */
- index = diag_register_dci_transaction(*(int *)temp);
- if (index < 0) {
+ req_entry = diag_register_dci_transaction(*(int *)temp);
+ if (!req_entry) {
pr_alert("diag: registering new DCI transaction failed\n");
return DIAG_DCI_NO_REG;
}
@@ -579,7 +650,8 @@
entry.cmd_code_lo <= subsys_cmd_code &&
entry.cmd_code_hi >= subsys_cmd_code) {
ret = diag_send_dci_pkt(entry, buf,
- len, index);
+ len,
+ req_entry->tag);
} else if (entry.cmd_code == 255
&& cmd_code == 75) {
if (entry.subsys_id == subsys_id &&
@@ -588,7 +660,8 @@
entry.cmd_code_hi >=
subsys_cmd_code) {
ret = diag_send_dci_pkt(entry,
- buf, len, index);
+ buf, len,
+ req_entry->tag);
}
} else if (entry.cmd_code == 255 &&
entry.subsys_id == 255) {
@@ -596,7 +669,8 @@
entry.cmd_code_hi >=
cmd_code) {
ret = diag_send_dci_pkt(entry,
- buf, len, index);
+ buf, len,
+ req_entry->tag);
}
}
}
@@ -881,7 +955,7 @@
void *buf = driver->buf_event_mask_update;
int header_size = sizeof(struct diag_ctrl_event_mask);
int wr_size = -ENOMEM, retry_count = 0, timer;
- int ret = DIAG_DCI_NO_ERROR;
+ int ret = DIAG_DCI_NO_ERROR, i;
mutex_lock(&driver->diag_cntl_mutex);
/* send event mask update */
@@ -889,8 +963,14 @@
driver->event_mask->data_len = 7 + DCI_EVENT_MASK_SIZE;
driver->event_mask->stream_id = DCI_MASK_STREAM;
driver->event_mask->status = 3; /* status for valid mask */
- driver->event_mask->event_config = 1; /* event config */
+ driver->event_mask->event_config = 0; /* event config */
driver->event_mask->event_mask_size = DCI_EVENT_MASK_SIZE;
+ for (i = 0; i < DCI_EVENT_MASK_SIZE; i++) {
+ if (dci_cumulative_event_mask[i] != 0) {
+ driver->event_mask->event_config = 1;
+ break;
+ }
+ }
memcpy(buf, driver->event_mask, header_size);
memcpy(buf+header_size, dci_cumulative_event_mask, DCI_EVENT_MASK_SIZE);
if (ch) {
@@ -1225,13 +1305,6 @@
goto err;
}
}
-
- if (driver->req_tracking_tbl == NULL) {
- driver->req_tracking_tbl = kzalloc(dci_max_reg *
- sizeof(struct dci_pkt_req_tracking_tbl), GFP_KERNEL);
- if (driver->req_tracking_tbl == NULL)
- goto err;
- }
if (driver->apps_dci_buf == NULL) {
driver->apps_dci_buf = kzalloc(APPS_BUF_SIZE, GFP_KERNEL);
if (driver->apps_dci_buf == NULL)
@@ -1244,6 +1317,7 @@
goto err;
}
driver->diag_dci_wq = create_singlethread_workqueue("diag_dci_wq");
+ INIT_LIST_HEAD(&driver->dci_req_list);
success = platform_driver_register(&msm_diag_dci_driver);
if (success) {
pr_err("diag: Could not register DCI driver\n");
@@ -1259,7 +1333,6 @@
return DIAG_DCI_NO_ERROR;
err:
pr_err("diag: Could not initialize diag DCI buffers");
- kfree(driver->req_tracking_tbl);
kfree(driver->dci_client_tbl);
kfree(driver->apps_dci_buf);
for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++)
@@ -1300,7 +1373,7 @@
platform_driver_unregister(&msm_diag_dci_cmd_driver);
}
- kfree(driver->req_tracking_tbl);
+
kfree(driver->dci_client_tbl);
kfree(driver->apps_dci_buf);
mutex_destroy(&driver->dci_mutex);
diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h
index e2c4158..c9be39a 100644
--- a/drivers/char/diag/diag_dci.h
+++ b/drivers/char/diag/diag_dci.h
@@ -24,7 +24,7 @@
#define DISABLE_LOG_MASK 0
#define MAX_EVENT_SIZE 512
#define DCI_CLIENT_INDEX_INVALID -1
-#define DCI_PKT_REQ_MIN_LEN 8
+#define DCI_PKT_REQ_MIN_LEN 5
#define DCI_LOG_CON_MIN_LEN 14
#define DCI_EVENT_CON_MIN_LEN 16
@@ -42,15 +42,18 @@
#define DCI_MAX_LOG_CODES 16
#define DCI_MAX_ITEMS_PER_LOG_CODE 512
+#define MIN_DELAYED_RSP_LEN 12
+
extern unsigned int dci_max_reg;
extern unsigned int dci_max_clients;
extern struct mutex dci_health_mutex;
-struct dci_pkt_req_tracking_tbl {
+struct dci_pkt_req_entry_t {
int pid;
int uid;
int tag;
-};
+ struct list_head track;
+} __packed;
struct diag_dci_client_tbl {
struct task_struct *client;
@@ -115,8 +118,6 @@
int diag_process_smd_dci_read_data(struct diag_smd_info *smd_info, void *buf,
int recd_bytes);
int diag_process_dci_transaction(unsigned char *buf, int len);
-int diag_send_dci_pkt(struct diag_master_table entry, unsigned char *buf,
- int len, int index);
void extract_dci_pkt_rsp(struct diag_smd_info *smd_info, unsigned char *buf);
int diag_dci_find_client_index(int client_id);
/* DCI Log streaming functions */
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index 69e6250..c28b3bd 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -229,83 +229,90 @@
static void diag_disable_log_mask(void)
{
int i = 0;
- struct mask_info *parse_ptr = (struct mask_info *)(driver->log_masks);
+ struct diag_log_mask_t *log_item = NULL;
- pr_debug("diag: disable log masks\n");
- mutex_lock(&driver->diagchar_mutex);
- for (i = 0; i < MAX_EQUIP_ID; i++) {
- pr_debug("diag: equip id %d\n", parse_ptr->equip_id);
- if (!(parse_ptr->equip_id)) /* Reached a null entry */
- break;
- memset(driver->log_masks + parse_ptr->index, 0,
- (parse_ptr->num_items + 7)/8);
- parse_ptr++;
- }
+ mutex_lock(&driver->log_mask_mutex);
+ log_item = (struct diag_log_mask_t *)driver->log_masks;
+ for (i = 0; i < MAX_EQUIP_ID; i++, log_item++)
+ memset(log_item->ptr, 0, MAX_ITEMS_PER_EQUIP_ID);
+
driver->log_status = DIAG_CTRL_MASK_ALL_DISABLED;
- mutex_unlock(&driver->diagchar_mutex);
+ mutex_unlock(&driver->log_mask_mutex);
}
-int chk_equip_id_and_mask(int equip_id, uint8_t *buf)
+static int copy_log_mask_equip(int equip_id, uint8_t *buf)
{
- int i = 0, flag = 0, num_items, offset;
- unsigned char *ptr_data;
- struct mask_info *ptr = (struct mask_info *)(driver->log_masks);
+ int i, ret = 0;
+ uint8_t *temp = buf;
+ struct diag_log_mask_t *log_item = NULL;
+ uint32_t mask_size = 0;
- pr_debug("diag: received equip id = %d\n", equip_id);
- /* Check if this is valid equipment ID */
- for (i = 0; i < MAX_EQUIP_ID; i++) {
- if ((ptr->equip_id == equip_id) && (ptr->index != 0)) {
- offset = ptr->index;
- num_items = ptr->num_items;
- flag = 1;
+ if (!buf)
+ return ret;
+
+ log_item = (struct diag_log_mask_t *)driver->log_masks;
+ for (i = 0; i < MAX_EQUIP_ID; i++, log_item++) {
+ if (log_item->equip_id != equip_id)
+ continue;
+ *(int *)temp = log_item->equip_id;
+ temp += sizeof(int);
+ *(int *)(temp) = log_item->num_items;
+ temp += sizeof(int);
+ mask_size = LOG_ITEMS_TO_SIZE(log_item->num_items);
+ if (mask_size > MAX_ITEMS_PER_EQUIP_ID) {
+ pr_err("diag: Invalid length: %d in %s, perimissible: %d",
+ mask_size, __func__, MAX_ITEMS_PER_EQUIP_ID);
break;
}
- ptr++;
+ if (mask_size > 0) {
+ memcpy(temp, log_item->ptr, mask_size);
+ /*
+ * Return the total number of bytes copied = size of
+ * equip_id (int) + size of num_items (int) + mask_size
+ */
+ ret = (2 * sizeof(int)) + mask_size;
+ }
+ break;
}
- if (!flag)
- return -EPERM;
- ptr_data = driver->log_masks + offset;
- memcpy(buf, ptr_data, (num_items+7)/8);
- return 0;
+
+ return ret;
}
static void diag_update_log_mask(int equip_id, uint8_t *buf, int num_items)
{
- uint8_t *temp = buf;
int i = 0;
- unsigned char *ptr_data;
- int offset = (sizeof(struct mask_info))*MAX_EQUIP_ID;
- struct mask_info *ptr = (struct mask_info *)(driver->log_masks);
+ struct diag_log_mask_t *log_item = NULL;
+ uint32_t mask_size = 0;
- pr_debug("diag: received equip id = %d\n", equip_id);
- mutex_lock(&driver->diagchar_mutex);
- /* Check if we already know index of this equipment ID */
- for (i = 0; i < MAX_EQUIP_ID; i++) {
- if ((ptr->equip_id == equip_id) && (ptr->index != 0)) {
- offset = ptr->index;
- break;
- }
- if ((ptr->equip_id == 0) && (ptr->index == 0)) {
- /* Reached a null entry */
- ptr->equip_id = equip_id;
- ptr->num_items = num_items;
- ptr->index = driver->log_masks_length;
- offset = driver->log_masks_length;
- driver->log_masks_length += ((num_items+7)/8);
- break;
- }
- ptr++;
+ mutex_lock(&driver->log_mask_mutex);
+ driver->log_status = DIAG_CTRL_MASK_INVALID;
+ if (!buf || (equip_id < 0 || equip_id >= MAX_EQUIP_ID) ||
+ num_items < 1) {
+ pr_err("diag: Invalid params in %s, buf: %x equip_id: %d, num_items: %d\n",
+ __func__, (unsigned int)buf, equip_id, num_items);
+ mutex_unlock(&driver->log_mask_mutex);
+ return;
}
- ptr_data = driver->log_masks + offset;
- if (CHK_OVERFLOW(driver->log_masks, ptr_data, driver->log_masks
- + LOG_MASK_SIZE, (num_items+7)/8)) {
- memcpy(ptr_data, temp, (num_items+7)/8);
+ mask_size = LOG_ITEMS_TO_SIZE(num_items);
+ if (mask_size > MAX_ITEMS_PER_EQUIP_ID) {
+ pr_err("diag: In %s, Invalid mask_size %d\n", __func__,
+ mask_size);
+ mutex_unlock(&driver->log_mask_mutex);
+ return;
+ }
+
+ log_item = (struct diag_log_mask_t *)driver->log_masks;
+ for (i = 0; i < MAX_EQUIP_ID; i++, log_item++) {
+ if (log_item->equip_id != equip_id)
+ continue;
+ /* Found the equip id */
+ log_item->num_items = num_items;
+ if (mask_size > 0)
+ memcpy(log_item->ptr, buf, mask_size);
driver->log_status = DIAG_CTRL_MASK_VALID;
- } else {
- pr_err("diag: Not enough buffer space for LOG_MASK\n");
- driver->log_status = DIAG_CTRL_MASK_INVALID;
+ break;
}
- mutex_unlock(&driver->diagchar_mutex);
+ mutex_unlock(&driver->log_mask_mutex);
}
void diag_mask_update_fn(struct work_struct *work)
@@ -335,72 +342,76 @@
void diag_send_log_mask_update(smd_channel_t *ch, int equip_id)
{
void *buf = driver->buf_log_mask_update;
- int header_size = sizeof(struct diag_ctrl_log_mask);
- struct mask_info *ptr = (struct mask_info *)driver->log_masks;
- int i, size, wr_size = -ENOMEM, retry_count = 0;
+ struct diag_log_mask_t *log_item = NULL;
+ struct diag_ctrl_log_mask ctrl_pkt;
+ uint32_t log_mask_size = 0;
+ int wr_size = -ENOMEM, retry_count = 0;
+ int i, header_size, send_once = 0;
+ header_size = sizeof(struct diag_ctrl_log_mask);
+ log_item = (struct diag_log_mask_t *)driver->log_masks;
mutex_lock(&driver->diag_cntl_mutex);
- for (i = 0; i < MAX_EQUIP_ID; i++) {
- size = (ptr->num_items+7)/8;
- /* reached null entry */
- if ((ptr->equip_id == 0) && (ptr->index == 0))
- break;
- driver->log_mask->cmd_type = DIAG_CTRL_MSG_LOG_MASK;
- driver->log_mask->num_items = ptr->num_items;
- driver->log_mask->data_len = 11 + size;
- driver->log_mask->stream_id = 1; /* 2, if dual stream */
- driver->log_mask->equip_id = ptr->equip_id;
- driver->log_mask->status = driver->log_status;
+ for (i = 0; i < MAX_EQUIP_ID; i++, log_item++) {
+ if (equip_id != i && equip_id != ALL_EQUIP_ID)
+ continue;
+ log_mask_size = LOG_ITEMS_TO_SIZE(log_item->num_items);
+ ctrl_pkt.cmd_type = DIAG_CTRL_MSG_LOG_MASK;
+ ctrl_pkt.data_len = 11 + log_mask_size;
+ ctrl_pkt.stream_id = 1;
+ ctrl_pkt.status = driver->log_status;
switch (driver->log_status) {
case DIAG_CTRL_MASK_ALL_DISABLED:
- driver->log_mask->log_mask_size = 0;
+ ctrl_pkt.equip_id = 0;
+ ctrl_pkt.num_items = 0;
+ ctrl_pkt.log_mask_size = 0;
+ send_once = 1;
break;
case DIAG_CTRL_MASK_ALL_ENABLED:
- driver->log_mask->log_mask_size = 0;
+ ctrl_pkt.equip_id = 0;
+ ctrl_pkt.num_items = 0;
+ ctrl_pkt.log_mask_size = 0;
+ send_once = 1;
break;
case DIAG_CTRL_MASK_VALID:
- driver->log_mask->log_mask_size = size;
+ ctrl_pkt.equip_id = i;
+ ctrl_pkt.num_items = log_item->num_items;
+ ctrl_pkt.log_mask_size = log_mask_size;
+ send_once = 0;
break;
default:
- /* Log status is not set or the buffer is corrupted */
pr_err("diag: In %s, invalid status %d", __func__,
- driver->log_status);
- driver->log_mask->status = DIAG_CTRL_MASK_INVALID;
- }
-
- if (driver->log_mask->status == DIAG_CTRL_MASK_INVALID) {
+ driver->log_status);
mutex_unlock(&driver->diag_cntl_mutex);
return;
}
- /* send only desired update, NOT ALL */
- if (equip_id == ALL_EQUIP_ID || equip_id ==
- driver->log_mask->equip_id) {
- memcpy(buf, driver->log_mask, header_size);
- if (driver->log_status == DIAG_CTRL_MASK_VALID)
- memcpy(buf + header_size,
- driver->log_masks+ptr->index, size);
- if (ch) {
- while (retry_count < 3) {
- wr_size = smd_write(ch, buf,
- header_size + size);
- if (wr_size == -ENOMEM) {
- retry_count++;
- usleep_range(10000, 10100);
- } else
- break;
- }
- if (wr_size != header_size + size)
- pr_err("diag: log mask update failed %d, tried %d",
- wr_size, header_size + size);
- else
- pr_debug("diag: updated log equip ID %d,len %d\n",
- driver->log_mask->equip_id,
- driver->log_mask->log_mask_size);
- } else
- pr_err("diag: ch not valid for log update\n");
+ memcpy(buf, &ctrl_pkt, header_size);
+ if (log_mask_size > 0) {
+ memcpy(buf + header_size, log_item->ptr,
+ log_mask_size);
}
- ptr++;
+
+ if (ch) {
+ while (retry_count < 3) {
+ wr_size = smd_write(ch, buf,
+ header_size + log_mask_size);
+ if (wr_size == -ENOMEM) {
+ retry_count++;
+ usleep_range(10000, 10100);
+ } else
+ break;
+ }
+ if (wr_size != header_size + log_mask_size)
+ pr_err("diag: log mask update failed %d, tried %d",
+ wr_size, header_size + log_mask_size);
+ else
+ pr_debug("diag: updated log equip ID %d,len %d\n",
+ i, log_mask_size);
+ } else
+ pr_err("diag: ch not valid for log update\n");
+ if (send_once)
+ break;
}
+
mutex_unlock(&driver->diag_cntl_mutex);
}
@@ -623,7 +634,7 @@
int ssid_first, ssid_last, ssid_range;
int rt_mask, rt_first_ssid, rt_last_ssid, rt_mask_size;
uint8_t *rt_mask_ptr;
- int equip_id, num_items;
+ int equip_id, copy_len;
#if defined(CONFIG_DIAG_OVER_USB)
int payload_length;
#endif
@@ -631,7 +642,6 @@
/* Set log masks */
if (*buf == 0x73 && *(int *)(buf+4) == 3) {
buf += 8;
- /* Read Equip ID and pass as first param below*/
diag_update_log_mask(*(int *)buf, buf+8, *(int *)(buf+4));
diag_update_userspace_clients(LOG_MASKS_TYPE);
#if defined(CONFIG_DIAG_OVER_USB)
@@ -639,7 +649,8 @@
driver->apps_rsp_buf[0] = 0x73;
*(int *)(driver->apps_rsp_buf + 4) = 0x3; /* op. ID */
*(int *)(driver->apps_rsp_buf + 8) = 0x0; /* success */
- payload_length = 8 + ((*(int *)(buf + 4)) + 7)/8;
+ payload_length = 8 +
+ LOG_ITEMS_TO_SIZE(*(int *)(buf + 4));
if (payload_length > APPS_BUF_SIZE - 12) {
pr_err("diag: log masks: buffer overflow\n");
return -EIO;
@@ -663,20 +674,16 @@
if (!(driver->smd_data[MODEM_DATA].ch) &&
chk_apps_only()) {
equip_id = *(int *)(buf + 8);
- num_items = *(int *)(buf + 12);
driver->apps_rsp_buf[0] = 0x73;
driver->apps_rsp_buf[1] = 0x0;
driver->apps_rsp_buf[2] = 0x0;
driver->apps_rsp_buf[3] = 0x0;
*(int *)(driver->apps_rsp_buf + 4) = 0x4;
- if (!chk_equip_id_and_mask(equip_id,
- driver->apps_rsp_buf+20))
- *(int *)(driver->apps_rsp_buf + 8) = 0x0;
- else
- *(int *)(driver->apps_rsp_buf + 8) = 0x1;
- *(int *)(driver->apps_rsp_buf + 12) = equip_id;
- *(int *)(driver->apps_rsp_buf + 16) = num_items;
- encode_rsp_and_send(20+(num_items+7)/8-1);
+ copy_len = copy_log_mask_equip(equip_id,
+ driver->apps_rsp_buf + 12);
+ *(int *)(driver->apps_rsp_buf + 8) =
+ (copy_len == 0) ? 1 : 0;
+ encode_rsp_and_send(12 + copy_len);
return 0;
}
#endif
@@ -858,6 +865,19 @@
return packet_type;
}
+static void diag_log_mask_init(void)
+{
+ struct diag_log_mask_t *log_item = NULL;
+ uint8_t i;
+
+ mutex_init(&driver->log_mask_mutex);
+ log_item = (struct diag_log_mask_t *)driver->log_masks;
+ for (i = 0; i < MAX_EQUIP_ID; i++, log_item++) {
+ log_item->equip_id = i;
+ log_item->num_items = LOG_GET_ITEM_NUM(log_code_last_tbl[i]);
+ }
+}
+
void diag_masks_init(void)
{
driver->event_status = DIAG_CTRL_MASK_INVALID;
@@ -936,7 +956,7 @@
goto err;
kmemleak_not_leak(driver->log_masks);
}
- driver->log_masks_length = (sizeof(struct mask_info))*MAX_EQUIP_ID;
+ diag_log_mask_init();
if (driver->event_masks == NULL) {
driver->event_masks = kzalloc(EVENT_MASK_SIZE, GFP_KERNEL);
if (driver->event_masks == NULL)
diff --git a/drivers/char/diag/diag_masks.h b/drivers/char/diag/diag_masks.h
index c66a4b6..856d4fc 100644
--- a/drivers/char/diag/diag_masks.h
+++ b/drivers/char/diag/diag_masks.h
@@ -15,7 +15,12 @@
#include "diagfwd.h"
-int chk_equip_id_and_mask(int equip_id, uint8_t *buf);
+struct diag_log_mask_t {
+ uint8_t equip_id;
+ uint32_t num_items;
+ uint8_t ptr[MAX_ITEMS_PER_EQUIP_ID];
+} __packed;
+
void diag_send_event_mask_update(smd_channel_t *, int num_bytes);
void diag_send_msg_mask_update(smd_channel_t *, int ssid_first,
int ssid_last, int proc);
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 9d9d89b..606953d 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -82,11 +82,14 @@
* And there are MSG_MASK_TBL_CNT rows.
*/
#define MSG_MASK_SIZE ((MAX_SSID_PER_RANGE+3) * 4 * MSG_MASK_TBL_CNT)
-#define LOG_MASK_SIZE 8000
+#define MAX_EQUIP_ID 16
+#define MAX_ITEMS_PER_EQUIP_ID 512
+#define LOG_MASK_ITEM_SIZE (5 + MAX_ITEMS_PER_EQUIP_ID)
+#define LOG_MASK_SIZE (MAX_EQUIP_ID * LOG_MASK_ITEM_SIZE)
#define EVENT_MASK_SIZE 1000
#define USER_SPACE_DATA 8192
#define PKT_SIZE 4096
-#define MAX_EQUIP_ID 15
+
#define DIAG_CTRL_MSG_LOG_MASK 9
#define DIAG_CTRL_MSG_EVENT_MASK 10
#define DIAG_CTRL_MSG_F3_MASK 11
@@ -298,7 +301,7 @@
/* Whether or not the peripheral supports STM */
int peripheral_supports_stm[NUM_SMD_CONTROL_CHANNELS];
/* DCI related variables */
- struct dci_pkt_req_tracking_tbl *req_tracking_tbl;
+ struct list_head dci_req_list;
struct diag_dci_client_tbl *dci_client_tbl;
int dci_tag;
int dci_client_id;
@@ -334,6 +337,7 @@
struct diag_ctrl_log_mask *log_mask;
struct diag_ctrl_msg_mask *msg_mask;
struct diag_ctrl_feature_mask *feature_mask;
+ struct mutex log_mask_mutex;
/* State for diag forwarding */
struct diag_smd_info smd_data[NUM_SMD_DATA_CHANNELS];
struct diag_smd_info smd_cntl[NUM_SMD_CONTROL_CHANNELS];
@@ -344,6 +348,7 @@
int separate_cmdrsp[NUM_SMD_CONTROL_CHANNELS];
unsigned char *usb_buf_out;
unsigned char *apps_rsp_buf;
+ unsigned char *user_space_data_buf;
/* buffer for updating mask to peripherals */
unsigned char *buf_msg_mask_update;
unsigned char *buf_log_mask_update;
@@ -380,7 +385,6 @@
uint8_t msg_status;
uint8_t *log_masks;
uint8_t log_status;
- int log_masks_length;
uint8_t *event_masks;
uint8_t event_status;
uint8_t log_on_demand_support;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 19ff6f4..002bd0c 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -878,6 +878,8 @@
struct diag_log_event_stats le_stats;
struct diagpkt_delay_params delay_params;
struct real_time_vote_t rt_vote;
+ struct list_head *start, *req_temp;
+ struct dci_pkt_req_entry_t *req_entry = NULL;
switch (iocmd) {
case DIAG_IOCTL_COMMAND_REG:
@@ -993,10 +995,16 @@
}
result = i;
/* Delete this process from DCI table */
- for (i = 0; i < dci_max_reg; i++)
- if (driver->req_tracking_tbl[i].pid ==
- current->tgid)
- driver->req_tracking_tbl[i].pid = 0;
+ list_for_each_safe(start, req_temp,
+ &driver->dci_req_list) {
+ req_entry = list_entry(start,
+ struct dci_pkt_req_entry_t,
+ track);
+ if (req_entry->pid == current->tgid) {
+ list_del(&req_entry->track);
+ kfree(req_entry);
+ }
+ }
driver->dci_client_tbl[result].client = NULL;
kfree(driver->dci_client_tbl[result].dci_data);
driver->dci_client_tbl[result].dci_data = NULL;
@@ -1109,7 +1117,7 @@
case DIAG_IOCTL_VOTE_REAL_TIME:
if (copy_from_user(&rt_vote, (void *)ioarg, sizeof(struct
real_time_vote_t)))
- result = -EFAULT;
+ return -EFAULT;
driver->real_time_update_busy++;
if (rt_vote.proc == DIAG_PROC_DCI) {
diag_dci_set_real_time(current->tgid,
@@ -1485,26 +1493,25 @@
return err;
}
if (pkt_type == CALLBACK_DATA_TYPE) {
- if (payload_size > itemsize) {
+ if (payload_size > driver->itemsize) {
pr_err("diag: Dropping packet, packet payload size crosses 4KB limit. Current payload size %d\n",
payload_size);
driver->dropped_count++;
return -EBADMSG;
}
- mutex_lock(&driver->diagchar_mutex);
buf_copy = diagmem_alloc(driver, payload_size, POOL_TYPE_COPY);
if (!buf_copy) {
driver->dropped_count++;
- mutex_unlock(&driver->diagchar_mutex);
return -ENOMEM;
}
err = copy_from_user(buf_copy, buf + 4, payload_size);
if (err) {
pr_err("diag: copy failed for user space data\n");
- ret = -EIO;
- goto fail_free_copy;
+ diagmem_free(driver, buf_copy, POOL_TYPE_COPY);
+ buf_copy = NULL;
+ return -EIO;
}
/* Check for proc_type */
remote_proc = diag_get_remote(*(int *)buf_copy);
@@ -1513,7 +1520,9 @@
wait_event_interruptible(driver->wait_q,
(driver->in_busy_pktdata == 0));
ret = diag_process_apps_pkt(buf_copy, payload_size);
- goto fail_free_copy;
+ diagmem_free(driver, buf_copy, POOL_TYPE_COPY);
+ buf_copy = NULL;
+ return ret;
}
/* The packet is for the remote processor */
token_offset = 4;
@@ -1526,7 +1535,7 @@
1 + payload_size);
send.terminate = 1;
-
+ mutex_lock(&driver->diagchar_mutex);
if (!buf_hdlc)
buf_hdlc = diagmem_alloc(driver, HDLC_OUT_BUF_SIZE,
POOL_TYPE_HDLC);
@@ -1608,22 +1617,15 @@
goto fail_free_hdlc;
}
if (pkt_type == USER_SPACE_DATA_TYPE) {
- user_space_data = diagmem_alloc(driver, payload_size,
- POOL_TYPE_USER);
- if (!user_space_data) {
- driver->dropped_count++;
- return -ENOMEM;
- }
- err = copy_from_user(user_space_data, buf + 4,
+ err = copy_from_user(driver->user_space_data_buf, buf + 4,
payload_size);
if (err) {
pr_err("diag: copy failed for user space data\n");
- diagmem_free(driver, user_space_data, POOL_TYPE_USER);
- user_space_data = NULL;
return -EIO;
}
/* Check for proc_type */
- remote_proc = diag_get_remote(*(int *)user_space_data);
+ remote_proc =
+ diag_get_remote(*(int *)driver->user_space_data_buf);
if (remote_proc) {
token_offset = 4;
@@ -1633,12 +1635,9 @@
/* Check masks for On-Device logging */
if (driver->mask_check) {
- if (!mask_request_validate(user_space_data +
+ if (!mask_request_validate(driver->user_space_data_buf +
token_offset)) {
pr_alert("diag: mask request Invalid\n");
- diagmem_free(driver, user_space_data,
- POOL_TYPE_USER);
- user_space_data = NULL;
return -EFAULT;
}
}
@@ -1646,7 +1645,7 @@
#ifdef DIAG_DEBUG
pr_debug("diag: user space data %d\n", payload_size);
for (i = 0; i < payload_size; i++)
- pr_debug("\t %x", *((user_space_data
+ pr_debug("\t %x", *((driver->user_space_data_buf
+ token_offset)+i));
#endif
#ifdef CONFIG_DIAG_SDIO_PIPE
@@ -1657,7 +1656,7 @@
payload_size));
if (driver->sdio_ch && (payload_size > 0)) {
sdio_write(driver->sdio_ch, (void *)
- (user_space_data + token_offset),
+ (driver->user_space_data_buf + token_offset),
payload_size);
}
}
@@ -1688,8 +1687,8 @@
diag_hsic[index].in_busy_hsic_read_on_device =
0;
err = diag_bridge_write(index,
- user_space_data + token_offset,
- payload_size);
+ driver->user_space_data_buf +
+ token_offset, payload_size);
if (err) {
pr_err("diag: err sending mask to MDM: %d\n",
err);
@@ -1710,14 +1709,12 @@
&& driver->lcid) {
if (payload_size > 0) {
err = msm_smux_write(driver->lcid, NULL,
- user_space_data + token_offset,
+ driver->user_space_data_buf +
+ token_offset,
payload_size);
if (err) {
pr_err("diag:send mask to MDM err %d",
err);
- diagmem_free(driver, user_space_data,
- POOL_TYPE_USER);
- user_space_data = NULL;
return err;
}
}
@@ -1726,9 +1723,8 @@
/* send masks to 8k now */
if (!remote_proc)
diag_process_hdlc((void *)
- (user_space_data + token_offset), payload_size);
- diagmem_free(driver, user_space_data, POOL_TYPE_USER);
- user_space_data = NULL;
+ (driver->user_space_data_buf + token_offset),
+ payload_size);
return 0;
}
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index cdd315e..395bea0 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -1051,9 +1051,10 @@
return is_mode_reset;
}
-void diag_send_data(struct diag_master_table entry, unsigned char *buf,
+int diag_send_data(struct diag_master_table entry, unsigned char *buf,
int len, int type)
{
+ int success = 1;
driver->pkt_length = len;
/* If the process_id corresponds to an apps process */
@@ -1069,13 +1070,19 @@
if (entry.client_id < NUM_SMD_DATA_CHANNELS) {
struct diag_smd_info *smd_info;
int index = entry.client_id;
+ if (!driver->rcvd_feature_mask[
+ entry.client_id]) {
+ pr_debug("diag: In %s, feature mask for peripheral: %d not received yet\n",
+ __func__, entry.client_id);
+ return 0;
+ }
/*
* Mode reset should work even if
* modem is down
*/
if ((index == MODEM_DATA) &&
diag_check_mode_reset(buf)) {
- return;
+ return 1;
}
smd_info = (driver->separate_cmdrsp[index] &&
index < NUM_SMD_CMD_CHANNELS) ?
@@ -1095,9 +1102,12 @@
} else {
pr_alert("diag: In %s, incorrect channel: %d",
__func__, entry.client_id);
+ success = 0;
}
}
}
+
+ return success;
}
void diag_process_stm_mask(uint8_t cmd, uint8_t data_mask, int data_type,
@@ -1191,6 +1201,7 @@
unsigned char *temp = buf;
int data_type;
int mask_ret;
+ int status = 0;
#if defined(CONFIG_DIAG_OVER_USB)
unsigned char *ptr;
#endif
@@ -1217,14 +1228,15 @@
pr_debug("diag: %d %d %d", cmd_code, subsys_id, subsys_cmd_code);
for (i = 0; i < diag_max_reg; i++) {
entry = driver->table[i];
- if (entry.process_id != NO_PROCESS &&
- driver->rcvd_feature_mask[entry.client_id]) {
+ if (entry.process_id != NO_PROCESS) {
if (entry.cmd_code == cmd_code && entry.subsys_id ==
subsys_id && entry.cmd_code_lo <=
subsys_cmd_code &&
entry.cmd_code_hi >= subsys_cmd_code) {
- diag_send_data(entry, buf, len, data_type);
- packet_type = 0;
+ status = diag_send_data(entry, buf, len,
+ data_type);
+ if (status)
+ packet_type = 0;
} else if (entry.cmd_code == 255
&& cmd_code == 75) {
if (entry.subsys_id ==
@@ -1233,9 +1245,10 @@
subsys_cmd_code &&
entry.cmd_code_hi >=
subsys_cmd_code) {
- diag_send_data(entry, buf, len,
- data_type);
- packet_type = 0;
+ status = diag_send_data(entry, buf,
+ len, data_type);
+ if (status)
+ packet_type = 0;
}
} else if (entry.cmd_code == 255 &&
entry.subsys_id == 255) {
@@ -1243,9 +1256,10 @@
cmd_code &&
entry.
cmd_code_hi >= cmd_code) {
- diag_send_data(entry, buf, len,
+ status = diag_send_data(entry, buf, len,
data_type);
- packet_type = 0;
+ if (status)
+ packet_type = 0;
}
}
}
@@ -1280,22 +1294,38 @@
driver->apps_rsp_buf[0] = 0x73;
*(int *)(driver->apps_rsp_buf + 4) = 0x1; /* operation ID */
*(int *)(driver->apps_rsp_buf + 8) = 0x0; /* success code */
- *(int *)(driver->apps_rsp_buf + 12) = LOG_GET_ITEM_NUM(LOG_0);
- *(int *)(driver->apps_rsp_buf + 16) = LOG_GET_ITEM_NUM(LOG_1);
- *(int *)(driver->apps_rsp_buf + 20) = LOG_GET_ITEM_NUM(LOG_2);
- *(int *)(driver->apps_rsp_buf + 24) = LOG_GET_ITEM_NUM(LOG_3);
- *(int *)(driver->apps_rsp_buf + 28) = LOG_GET_ITEM_NUM(LOG_4);
- *(int *)(driver->apps_rsp_buf + 32) = LOG_GET_ITEM_NUM(LOG_5);
- *(int *)(driver->apps_rsp_buf + 36) = LOG_GET_ITEM_NUM(LOG_6);
- *(int *)(driver->apps_rsp_buf + 40) = LOG_GET_ITEM_NUM(LOG_7);
- *(int *)(driver->apps_rsp_buf + 44) = LOG_GET_ITEM_NUM(LOG_8);
- *(int *)(driver->apps_rsp_buf + 48) = LOG_GET_ITEM_NUM(LOG_9);
- *(int *)(driver->apps_rsp_buf + 52) = LOG_GET_ITEM_NUM(LOG_10);
- *(int *)(driver->apps_rsp_buf + 56) = LOG_GET_ITEM_NUM(LOG_11);
- *(int *)(driver->apps_rsp_buf + 60) = LOG_GET_ITEM_NUM(LOG_12);
- *(int *)(driver->apps_rsp_buf + 64) = LOG_GET_ITEM_NUM(LOG_13);
- *(int *)(driver->apps_rsp_buf + 68) = LOG_GET_ITEM_NUM(LOG_14);
- *(int *)(driver->apps_rsp_buf + 72) = LOG_GET_ITEM_NUM(LOG_15);
+ *(int *)(driver->apps_rsp_buf + 12) =
+ LOG_GET_ITEM_NUM(log_code_last_tbl[0]);
+ *(int *)(driver->apps_rsp_buf + 16) =
+ LOG_GET_ITEM_NUM(log_code_last_tbl[1]);
+ *(int *)(driver->apps_rsp_buf + 20) =
+ LOG_GET_ITEM_NUM(log_code_last_tbl[2]);
+ *(int *)(driver->apps_rsp_buf + 24) =
+ LOG_GET_ITEM_NUM(log_code_last_tbl[3]);
+ *(int *)(driver->apps_rsp_buf + 28) =
+ LOG_GET_ITEM_NUM(log_code_last_tbl[4]);
+ *(int *)(driver->apps_rsp_buf + 32) =
+ LOG_GET_ITEM_NUM(log_code_last_tbl[5]);
+ *(int *)(driver->apps_rsp_buf + 36) =
+ LOG_GET_ITEM_NUM(log_code_last_tbl[6]);
+ *(int *)(driver->apps_rsp_buf + 40) =
+ LOG_GET_ITEM_NUM(log_code_last_tbl[7]);
+ *(int *)(driver->apps_rsp_buf + 44) =
+ LOG_GET_ITEM_NUM(log_code_last_tbl[8]);
+ *(int *)(driver->apps_rsp_buf + 48) =
+ LOG_GET_ITEM_NUM(log_code_last_tbl[9]);
+ *(int *)(driver->apps_rsp_buf + 52) =
+ LOG_GET_ITEM_NUM(log_code_last_tbl[10]);
+ *(int *)(driver->apps_rsp_buf + 56) =
+ LOG_GET_ITEM_NUM(log_code_last_tbl[11]);
+ *(int *)(driver->apps_rsp_buf + 60) =
+ LOG_GET_ITEM_NUM(log_code_last_tbl[12]);
+ *(int *)(driver->apps_rsp_buf + 64) =
+ LOG_GET_ITEM_NUM(log_code_last_tbl[13]);
+ *(int *)(driver->apps_rsp_buf + 68) =
+ LOG_GET_ITEM_NUM(log_code_last_tbl[14]);
+ *(int *)(driver->apps_rsp_buf + 72) =
+ LOG_GET_ITEM_NUM(log_code_last_tbl[15]);
encode_rsp_and_send(75);
return 0;
}
@@ -2450,7 +2480,7 @@
driver->buf_tbl_size = (buf_tbl_size < driver->poolsize_hdlc) ?
driver->poolsize_hdlc : buf_tbl_size;
driver->supports_separate_cmdrsp = device_supports_separate_cmdrsp();
- driver->supports_apps_hdlc_encoding = 0;
+ driver->supports_apps_hdlc_encoding = 1;
mutex_init(&driver->diag_hdlc_mutex);
mutex_init(&driver->diag_cntl_mutex);
@@ -2490,6 +2520,12 @@
&& (driver->hdlc_buf = kzalloc(HDLC_MAX, GFP_KERNEL)) == NULL)
goto err;
kmemleak_not_leak(driver->hdlc_buf);
+ if (driver->user_space_data_buf == NULL)
+ driver->user_space_data_buf = kzalloc(USER_SPACE_DATA,
+ GFP_KERNEL);
+ if (driver->user_space_data_buf == NULL)
+ goto err;
+ kmemleak_not_leak(driver->user_space_data_buf);
if (driver->client_map == NULL &&
(driver->client_map = kzalloc
((driver->num_clients) * sizeof(struct diag_client_map),
@@ -2577,6 +2613,7 @@
kfree(driver->pkt_buf);
kfree(driver->usb_read_ptr);
kfree(driver->apps_rsp_buf);
+ kfree(driver->user_space_data_buf);
if (driver->diag_wq)
destroy_workqueue(driver->diag_wq);
}
@@ -2616,5 +2653,6 @@
kfree(driver->pkt_buf);
kfree(driver->usb_read_ptr);
kfree(driver->apps_rsp_buf);
+ kfree(driver->user_space_data_buf);
destroy_workqueue(driver->diag_wq);
}
diff --git a/drivers/char/hw_random/msm_rng.c b/drivers/char/hw_random/msm_rng.c
index 369477f..4118a7a 100644
--- a/drivers/char/hw_random/msm_rng.c
+++ b/drivers/char/hw_random/msm_rng.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -25,6 +25,9 @@
#include <mach/msm_iomap.h>
#include <mach/socinfo.h>
#include <mach/msm_bus.h>
+#include <linux/qrng.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
#define DRIVER_NAME "msm_rng"
@@ -51,6 +54,29 @@
uint32_t qrng_perf_client;
};
+struct msm_rng_device msm_rng_device_info;
+
+static long msm_rng_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ long ret = 0;
+
+ pr_debug("ioctl: cmd = %d\n", cmd);
+ switch (cmd) {
+ case QRNG_IOCTL_RESET_BUS_BANDWIDTH:
+ pr_info("calling msm_rng_bus_scale(LOW)\n");
+ ret = msm_bus_scale_client_update_request(
+ msm_rng_device_info.qrng_perf_client, 0);
+ if (ret)
+ pr_err("failed qrng_reset_bus_bw, ret = %ld\n", ret);
+ break;
+ default:
+ pr_err("Unsupported IOCTL call");
+ break;
+ }
+ return ret;
+}
+
static int msm_rng_read(struct hwrng *rng, void *data, size_t max, bool wait)
{
struct msm_rng_device *msm_rng_dev;
@@ -79,12 +105,6 @@
dev_err(&pdev->dev, "failed to enable clock in callback\n");
return 0;
}
- if (msm_rng_dev->qrng_perf_client) {
- ret = msm_bus_scale_client_update_request(
- msm_rng_dev->qrng_perf_client, 1);
- if (ret)
- pr_err("bus_scale_client_update_req failed!\n");
- }
/* read random data from h/w */
do {
/* check status bit if data is available */
@@ -104,9 +124,6 @@
if ((maxsize - currsize) < 4)
break;
} while (currsize < maxsize);
- if (msm_rng_dev->qrng_perf_client)
- ret = msm_bus_scale_client_update_request(
- msm_rng_dev->qrng_perf_client, 0);
/* vote to turn off clock */
clk_disable_unprepare(msm_rng_dev->prng_clk);
@@ -161,19 +178,24 @@
mb();
}
clk_disable_unprepare(msm_rng_dev->prng_clk);
- if (msm_rng_dev->qrng_perf_client)
- ret = msm_bus_scale_client_update_request(
- msm_rng_dev->qrng_perf_client, 0);
-
return 0;
}
+static const struct file_operations msm_rng_fops = {
+ .unlocked_ioctl = msm_rng_ioctl,
+};
+static struct class *msm_rng_class;
+static struct cdev msm_rng_cdev;
+
static int __devinit msm_rng_probe(struct platform_device *pdev)
{
struct resource *res;
struct msm_rng_device *msm_rng_dev = NULL;
void __iomem *base = NULL;
int error = 0;
+ int ret = 0;
+ struct device *dev;
+
struct msm_bus_scale_pdata *qrng_platform_support = NULL;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -220,6 +242,8 @@
qrng_platform_support = msm_bus_cl_get_pdata(pdev);
msm_rng_dev->qrng_perf_client = msm_bus_scale_register_client(
qrng_platform_support);
+ msm_rng_device_info.qrng_perf_client =
+ msm_rng_dev->qrng_perf_client;
if (!msm_rng_dev->qrng_perf_client)
pr_err("Unable to register bus client\n");
}
@@ -238,9 +262,27 @@
error = -EPERM;
goto rollback_clk;
}
+ ret = register_chrdev(QRNG_IOC_MAGIC, DRIVER_NAME, &msm_rng_fops);
- return 0;
+ msm_rng_class = class_create(THIS_MODULE, "msm-rng");
+ if (IS_ERR(msm_rng_class)) {
+ pr_err("class_create failed\n");
+ return PTR_ERR(msm_rng_class);
+ }
+ dev = device_create(msm_rng_class, NULL, MKDEV(QRNG_IOC_MAGIC, 0),
+ NULL, "msm-rng");
+ if (IS_ERR(dev)) {
+ pr_err("Device create failed\n");
+ error = PTR_ERR(dev);
+ goto unregister_chrdev;
+ }
+ cdev_init(&msm_rng_cdev, &msm_rng_fops);
+
+ return ret;
+
+unregister_chrdev:
+ unregister_chrdev(QRNG_IOC_MAGIC, DRIVER_NAME);
rollback_clk:
clk_put(msm_rng_dev->prng_clk);
err_clk_get:
@@ -254,7 +296,7 @@
static int __devexit msm_rng_remove(struct platform_device *pdev)
{
struct msm_rng_device *msm_rng_dev = platform_get_drvdata(pdev);
-
+ unregister_chrdev(QRNG_IOC_MAGIC, DRIVER_NAME);
hwrng_unregister(&msm_rng);
clk_put(msm_rng_dev->prng_clk);
iounmap(msm_rng_dev->base);
diff --git a/drivers/char/rdbg.c b/drivers/char/rdbg.c
new file mode 100644
index 0000000..dbbf4b0
--- /dev/null
+++ b/drivers/char/rdbg.c
@@ -0,0 +1,1150 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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/types.h>
+#include <linux/cdev.h>
+#include <linux/gfp.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/completion.h>
+#include <linux/of_gpio.h>
+#include <linux/mutex.h>
+#include <mach/msm_smsm.h>
+#include <linux/uaccess.h>
+#include <asm/system.h>
+
+#define SMP2P_NUM_PROCS 8
+
+#define SM_VERSION 1
+#define SM_BLOCKSIZE 128
+
+#define SMQ_MAGIC_INIT 0xFF00FF00
+#define SMQ_MAGIC_PRODUCER (SMQ_MAGIC_INIT | 0x1)
+#define SMQ_MAGIC_CONSUMER (SMQ_MAGIC_INIT | 0x2)
+
+enum SMQ_STATUS {
+ SMQ_SUCCESS = 0,
+ SMQ_ENOMEMORY = -1,
+ SMQ_EBADPARM = -2,
+ SMQ_UNDERFLOW = -3,
+ SMQ_OVERFLOW = -4
+};
+
+enum smq_type {
+ PRODUCER = 1,
+ CONSUMER = 2,
+ INVALID = 3
+};
+
+struct smq_block_map {
+ uint32_t index_read;
+ uint32_t num_blocks;
+ uint8_t *map;
+};
+
+struct smq_node {
+ uint16_t index_block;
+ uint16_t num_blocks;
+} __attribute__ ((__packed__));
+
+struct smq_hdr {
+ uint8_t producer_version;
+ uint8_t consumer_version;
+} __attribute__ ((__packed__));
+
+struct smq_out_state {
+ uint32_t init;
+ uint32_t index_check_queue_for_reset;
+ uint32_t index_sent_write;
+ uint32_t index_free_read;
+} __attribute__ ((__packed__));
+
+struct smq_out {
+ struct smq_out_state s;
+ struct smq_node sent[1];
+};
+
+struct smq_in_state {
+ uint32_t init;
+ uint32_t index_check_queue_for_reset_ack;
+ uint32_t index_sent_read;
+ uint32_t index_free_write;
+} __attribute__ ((__packed__));
+
+struct smq_in {
+ struct smq_in_state s;
+ struct smq_node free[1];
+};
+
+struct smq {
+ struct smq_hdr *hdr;
+ struct smq_out *out;
+ struct smq_in *in;
+ uint8_t *blocks;
+ uint32_t num_blocks;
+ struct mutex *lock;
+ uint32_t initialized;
+ struct smq_block_map block_map;
+ enum smq_type type;
+};
+
+struct gpio_info {
+ int gpio_base_id;
+ int irq_base_id;
+};
+
+struct rdbg_data {
+ struct device *device;
+ struct completion work;
+ struct gpio_info in;
+ struct gpio_info out;
+ bool device_initialized;
+ int gpio_out_offset;
+ bool device_opened;
+ void *smem_addr;
+ size_t smem_size;
+ struct smq producer_smrb;
+ struct smq consumer_smrb;
+ struct mutex write_mutex;
+};
+
+struct rdbg_device {
+ struct cdev cdev;
+ struct class *class;
+ dev_t dev_no;
+ int num_devices;
+ struct rdbg_data *rdbg_data;
+};
+
+static struct rdbg_device g_rdbg_instance = {
+ { {0} },
+ NULL,
+ 0,
+ SMP2P_NUM_PROCS,
+ NULL
+};
+
+struct processor_specific_info {
+ char *name;
+ unsigned int smem_buffer_addr;
+ size_t smem_buffer_size;
+};
+
+static struct processor_specific_info proc_info[SMP2P_NUM_PROCS] = {
+ {0}, /*APPS*/
+ {"rdbg_modem", 0, 0}, /*MODEM*/
+ {"rdbg_adsp", SMEM_LC_DEBUGGER, 16*1024}, /*ADSP*/
+ {0}, /*SMP2P_RESERVED_PROC_1*/
+ {"rdbg_wcnss", 0, 0}, /*WCNSS*/
+ {0}, /*SMP2P_RESERVED_PROC_2*/
+ {0}, /*SMP2P_POWER_PROC*/
+ {0} /*SMP2P_REMOTE_MOCK_PROC*/
+};
+
+static int smq_blockmap_get(struct smq_block_map *block_map,
+ uint32_t *block_index, uint32_t n)
+{
+ uint32_t start;
+ uint32_t mark = 0;
+ uint32_t found = 0;
+ uint32_t i = 0;
+
+ start = block_map->index_read;
+
+ if (n == 1) {
+ do {
+ if (!block_map->map[block_map->index_read]) {
+ *block_index = block_map->index_read;
+ block_map->map[block_map->index_read] = 1;
+ block_map->index_read++;
+ block_map->index_read %= block_map->num_blocks;
+ return SMQ_SUCCESS;
+ }
+ block_map->index_read++;
+ } while (start != (block_map->index_read %=
+ block_map->num_blocks));
+ } else {
+ mark = block_map->num_blocks;
+
+ do {
+ if (!block_map->map[block_map->index_read]) {
+ if (mark > block_map->index_read) {
+ mark = block_map->index_read;
+ start = block_map->index_read;
+ found = 0;
+ }
+
+ found++;
+ if (found == n) {
+ *block_index = mark;
+ for (i = 0; i < n; i++)
+ block_map->map[mark + i] =
+ (uint8_t)(n - i);
+ block_map->index_read += block_map->map
+ [block_map->index_read] - 1;
+ return SMQ_SUCCESS;
+ }
+ } else {
+ found = 0;
+ block_map->index_read += block_map->map
+ [block_map->index_read] - 1;
+ mark = block_map->num_blocks;
+ }
+ block_map->index_read++;
+ } while (start != (block_map->index_read %=
+ block_map->num_blocks));
+ }
+
+ return SMQ_ENOMEMORY;
+}
+
+static void smq_blockmap_put(struct smq_block_map *block_map, uint32_t i)
+{
+ uint32_t num_blocks = block_map->map[i];
+
+ while (num_blocks--) {
+ block_map->map[i] = 0;
+ i++;
+ }
+}
+
+static int smq_blockmap_reset(struct smq_block_map *block_map)
+{
+ if (!block_map->map)
+ return SMQ_ENOMEMORY;
+ memset(block_map->map, 0 , block_map->num_blocks + 1);
+ block_map->index_read = 0;
+
+ return SMQ_SUCCESS;
+}
+
+static int smq_blockmap_ctor(struct smq_block_map *block_map,
+ uint32_t num_blocks)
+{
+ if (num_blocks <= 1)
+ return SMQ_ENOMEMORY;
+
+ block_map->map = kcalloc(num_blocks, sizeof(uint8_t), GFP_KERNEL);
+ if (!block_map->map)
+ return SMQ_ENOMEMORY;
+
+ block_map->num_blocks = num_blocks - 1;
+ smq_blockmap_reset(block_map);
+
+ return SMQ_SUCCESS;
+}
+
+static void smq_blockmap_dtor(struct smq_block_map *block_map)
+{
+ kfree(block_map->map);
+ block_map->map = NULL;
+}
+
+static int smq_free(struct smq *smq, void *data)
+{
+ struct smq_node node;
+ uint32_t index_block;
+ int err = SMQ_SUCCESS;
+
+ if (smq->lock)
+ mutex_lock(smq->lock);
+
+ if ((SM_VERSION != smq->hdr->producer_version) &&
+ (SMQ_MAGIC_PRODUCER != smq->out->s.init)) {
+ err = SMQ_UNDERFLOW;
+ goto bail;
+ }
+
+ index_block = ((uint8_t *)data - smq->blocks) / SM_BLOCKSIZE;
+ if (index_block >= smq->num_blocks) {
+ err = SMQ_EBADPARM;
+ goto bail;
+ }
+
+ node.index_block = (uint16_t)index_block;
+ node.num_blocks = 0;
+ *((struct smq_node *)(smq->in->free + smq->in->
+ s.index_free_write)) = node;
+
+ smq->in->s.index_free_write = (smq->in->s.index_free_write + 1)
+ % smq->num_blocks;
+
+bail:
+ if (smq->lock)
+ mutex_unlock(smq->lock);
+ return err;
+}
+
+static int smq_receive(struct smq *smq, void **pp, int *pnsize, int *pbmore)
+{
+ struct smq_node *node;
+ int err = SMQ_SUCCESS;
+ int more = 0;
+
+ if ((SM_VERSION != smq->hdr->producer_version) &&
+ (SMQ_MAGIC_PRODUCER != smq->out->s.init))
+ return SMQ_UNDERFLOW;
+
+ if (smq->in->s.index_sent_read == smq->out->s.index_sent_write) {
+ err = SMQ_UNDERFLOW;
+ goto bail;
+ }
+
+ node = (struct smq_node *)(smq->out->sent + smq->in->s.index_sent_read);
+ if (node->index_block >= smq->num_blocks) {
+ err = SMQ_EBADPARM;
+ goto bail;
+ }
+
+ smq->in->s.index_sent_read = (smq->in->s.index_sent_read + 1)
+ % smq->num_blocks;
+
+ *pp = smq->blocks + (node->index_block * SM_BLOCKSIZE);
+ *pnsize = SM_BLOCKSIZE * node->num_blocks;
+ rmb();
+ if (smq->in->s.index_sent_read != smq->out->s.index_sent_write)
+ more = 1;
+
+bail:
+ *pbmore = more;
+ return err;
+}
+
+static int smq_alloc_send(struct smq *smq, const uint8_t *pcb, int nsize)
+{
+ void *pv = 0;
+ int num_blocks;
+ uint32_t index_block = 0;
+ int err = SMQ_SUCCESS;
+ struct smq_node *node = NULL;
+
+ mutex_lock(smq->lock);
+
+ if ((SMQ_MAGIC_CONSUMER == smq->in->s.init) &&
+ (SM_VERSION == smq->hdr->consumer_version)) {
+ if (smq->out->s.index_check_queue_for_reset ==
+ smq->in->s.index_check_queue_for_reset_ack) {
+ while (smq->out->s.index_free_read !=
+ smq->in->s.index_free_write) {
+ node = (struct smq_node *)(
+ smq->in->free +
+ smq->out->s.index_free_read);
+ if (node->index_block >= smq->num_blocks) {
+ err = SMQ_EBADPARM;
+ goto bail;
+ }
+
+ smq->out->s.index_free_read =
+ (smq->out->s.index_free_read + 1)
+ % smq->num_blocks;
+
+ smq_blockmap_put(&smq->block_map,
+ node->index_block);
+ rmb();
+ }
+ }
+ }
+
+ num_blocks = ALIGN(nsize, SM_BLOCKSIZE)/SM_BLOCKSIZE;
+ err = smq_blockmap_get(&smq->block_map, &index_block, num_blocks);
+ if (SMQ_SUCCESS != err)
+ goto bail;
+
+ pv = smq->blocks + (SM_BLOCKSIZE * index_block);
+
+ err = copy_from_user((void *)pv, (void *)pcb, nsize);
+ if (0 != err)
+ goto bail;
+
+ ((struct smq_node *)(smq->out->sent +
+ smq->out->s.index_sent_write))->index_block
+ = (uint16_t)index_block;
+ ((struct smq_node *)(smq->out->sent +
+ smq->out->s.index_sent_write))->num_blocks
+ = (uint16_t)num_blocks;
+
+ smq->out->s.index_sent_write = (smq->out->s.index_sent_write + 1)
+ % smq->num_blocks;
+
+bail:
+ if (SMQ_SUCCESS != err) {
+ if (pv)
+ smq_blockmap_put(&smq->block_map, index_block);
+ }
+ mutex_unlock(smq->lock);
+ return err;
+}
+
+static int smq_reset_producer_queue_internal(struct smq *smq,
+ uint32_t reset_num)
+{
+ int retval = 0;
+ uint32_t i;
+
+ if (PRODUCER != smq->type)
+ goto bail;
+
+ mutex_lock(smq->lock);
+ if (smq->out->s.index_check_queue_for_reset != reset_num) {
+ smq->out->s.index_check_queue_for_reset = reset_num;
+ for (i = 0; i < smq->num_blocks; i++)
+ (smq->out->sent + i)->index_block = 0xFFFF;
+
+ smq_blockmap_reset(&smq->block_map);
+ smq->out->s.index_sent_write = 0;
+ smq->out->s.index_free_read = 0;
+ retval = 1;
+ }
+ mutex_unlock(smq->lock);
+
+bail:
+ return retval;
+}
+
+static int smq_check_queue_reset(struct smq *p_cons, struct smq *p_prod)
+{
+ int retval = 0;
+ uint32_t reset_num, i;
+
+ if ((CONSUMER != p_cons->type) ||
+ (SMQ_MAGIC_PRODUCER != p_cons->out->s.init) ||
+ (SM_VERSION != p_cons->hdr->producer_version))
+ goto bail;
+
+ reset_num = p_cons->out->s.index_check_queue_for_reset;
+ if (p_cons->in->s.index_check_queue_for_reset_ack != reset_num) {
+ p_cons->in->s.index_check_queue_for_reset_ack = reset_num;
+ for (i = 0; i < p_cons->num_blocks; i++)
+ (p_cons->in->free + i)->index_block = 0xFFFF;
+
+ p_cons->in->s.index_sent_read = 0;
+ p_cons->in->s.index_free_write = 0;
+
+ retval = smq_reset_producer_queue_internal(p_prod, reset_num);
+ }
+
+bail:
+ return retval;
+}
+
+static int check_subsystem_debug_enabled(void *base_addr, int size)
+{
+ int num_blocks;
+ uint8_t *pb_orig;
+ uint8_t *pb;
+ struct smq smq;
+ int err = 0;
+
+ pb = pb_orig = (uint8_t *)base_addr;
+ pb += sizeof(struct smq_hdr);
+ pb = PTR_ALIGN(pb, 8);
+ size -= pb - (uint8_t *)pb_orig;
+ num_blocks = (int)((size - sizeof(struct smq_out_state) -
+ sizeof(struct smq_in_state))/(SM_BLOCKSIZE +
+ sizeof(struct smq_node) * 2));
+ if (0 >= num_blocks) {
+ err = SMQ_EBADPARM;
+ goto bail;
+ }
+
+ pb += num_blocks * SM_BLOCKSIZE;
+ smq.out = (struct smq_out *)pb;
+ pb += sizeof(struct smq_out_state) + (num_blocks *
+ sizeof(struct smq_node));
+ smq.in = (struct smq_in *)pb;
+
+ if (SMQ_MAGIC_CONSUMER != smq.in->s.init) {
+ pr_err("%s, smq in consumer not initialized", __func__);
+ err = -ECOMM;
+ }
+
+bail:
+ return err;
+}
+
+static void smq_dtor(struct smq *smq)
+{
+ if (SMQ_MAGIC_INIT == smq->initialized) {
+ switch (smq->type) {
+ case PRODUCER:
+ smq->out->s.init = 0;
+ smq_blockmap_dtor(&smq->block_map);
+ break;
+ case CONSUMER:
+ smq->in->s.init = 0;
+ break;
+ default:
+ case INVALID:
+ break;
+ }
+
+ smq->initialized = 0;
+ }
+}
+
+/*
+ * The shared memory is used as a circular ring buffer in each direction.
+ * Thus we have a bi-directional shared memory channel between the AP
+ * and a subsystem. We call this SMQ. Each memory channel contains a header,
+ * data and a control mechanism that is used to synchronize read and write
+ * of data between the AP and the remote subsystem.
+ *
+ * Overall SMQ memory view:
+ *
+ * +------------------------------------------------+
+ * | SMEM buffer |
+ * |-----------------------+------------------------|
+ * |Producer: LA | Producer: Remote |
+ * |Consumer: Remote | subsystem |
+ * | subsystem | Consumer: LA |
+ * | | |
+ * | Producer| Consumer|
+ * +-----------------------+------------------------+
+ * | |
+ * | |
+ * | +--------------------------------------+
+ * | |
+ * | |
+ * v v
+ * +--------------------------------------------------------------+
+ * | Header | Data | Control |
+ * +-----------+---+---+---+-----+----+--+--+-----+---+--+--+-----+
+ * | | b | b | b | | S |n |n | | S |n |n | |
+ * | Producer | l | l | l | | M |o |o | | M |o |o | |
+ * | Ver | o | o | o | | Q |d |d | | Q |d |d | |
+ * |-----------| c | c | c | ... | |e |e | ... | |e |e | ... |
+ * | | k | k | k | | O | | | | I | | | |
+ * | Consumer | | | | | u |0 |1 | | n |0 |1 | |
+ * | Ver | 0 | 1 | 2 | | t | | | | | | | |
+ * +-----------+---+---+---+-----+----+--+--+-----+---+--+--+-----+
+ * | |
+ * + |
+ * |
+ * +------------------------+
+ * |
+ * v
+ * +----+----+----+----+
+ * | SMQ Nodes |
+ * |----|----|----|----|
+ * Node # | 0 | 1 | 2 | ...|
+ * |----|----|----|----|
+ * Starting Block Index # | 0 | 3 | 8 | ...|
+ * |----|----|----|----|
+ * # of blocks | 3 | 5 | 1 | ...|
+ * +----+----+----+----+
+ *
+ * Header: Contains version numbers for software compatibility to ensure
+ * that both producers and consumers on the AP and subsystems know how to
+ * read from and write to the queue.
+ * Both the producer and consumer versions are 1.
+ * +---------+-------------------+
+ * | Size | Field |
+ * +---------+-------------------+
+ * | 1 byte | Producer Version |
+ * +---------+-------------------+
+ * | 1 byte | Consumer Version |
+ * +---------+-------------------+
+ *
+ * Data: The data portion contains multiple blocks [0..N] of a fixed size.
+ * The block size SM_BLOCKSIZE is fixed to 128 bytes for header version #1.
+ * Payload sent from the debug agent app is split (if necessary) and placed
+ * in these blocks. The first data block is placed at the next 8 byte aligned
+ * address after the header.
+ *
+ * The number of blocks for a given SMEM allocation is derived as follows:
+ * Number of Blocks = ((Total Size - Alignment - Size of Header
+ * - Size of SMQIn - Size of SMQOut)/(SM_BLOCKSIZE))
+ *
+ * The producer maintains a private block map of each of these blocks to
+ * determine which of these blocks in the queue is available and which are free.
+ *
+ * Control:
+ * The control portion contains a list of nodes [0..N] where N is number
+ * of available data blocks. Each node identifies the data
+ * block indexes that contain a particular debug message to be transfered,
+ * and the number of blocks it took to hold the contents of the message.
+ *
+ * Each node has the following structure:
+ * +---------+-------------------+
+ * | Size | Field |
+ * +---------+-------------------+
+ * | 2 bytes |Staring Block Index|
+ * +---------+-------------------+
+ * | 2 bytes |Number of Blocks |
+ * +---------+-------------------+
+ *
+ * The producer and the consumer update different parts of the control channel
+ * (SMQOut / SMQIn) respectively. Each of these control data structures contains
+ * information about the last node that was written / read, and the actual nodes
+ * that were written/read.
+ *
+ * SMQOut Structure (R/W by producer, R by consumer):
+ * +---------+-------------------+
+ * | Size | Field |
+ * +---------+-------------------+
+ * | 4 bytes | Magic Init Number |
+ * +---------+-------------------+
+ * | 4 bytes | Reset |
+ * +---------+-------------------+
+ * | 4 bytes | Last Sent Index |
+ * +---------+-------------------+
+ * | 4 bytes | Index Free Read |
+ * +---------+-------------------+
+ *
+ * SMQIn Structure (R/W by consumer, R by producer):
+ * +---------+-------------------+
+ * | Size | Field |
+ * +---------+-------------------+
+ * | 4 bytes | Magic Init Number |
+ * +---------+-------------------+
+ * | 4 bytes | Reset ACK |
+ * +---------+-------------------+
+ * | 4 bytes | Last Read Index |
+ * +---------+-------------------+
+ * | 4 bytes | Index Free Write |
+ * +---------+-------------------+
+ *
+ * Magic Init Number:
+ * Both SMQ Out and SMQ In initialize this field with a predefined magic
+ * number so as to make sure that both the consumer and producer blocks
+ * have fully initialized and have valid data in the shared memory control area.
+ * Producer Magic #: 0xFF00FF01
+ * Consumer Magic #: 0xFF00FF02
+ */
+static int smq_ctor(struct smq *smq, void *base_addr, int size,
+ enum smq_type type, struct mutex *lock_ptr)
+{
+ int num_blocks;
+ uint8_t *pb_orig;
+ uint8_t *pb;
+ uint32_t i;
+ int err;
+
+ if (SMQ_MAGIC_INIT == smq->initialized) {
+ err = SMQ_EBADPARM;
+ goto bail;
+ }
+
+ if (!base_addr || !size) {
+ err = SMQ_EBADPARM;
+ goto bail;
+ }
+
+ if (type == PRODUCER)
+ smq->lock = lock_ptr;
+
+ pb_orig = (uint8_t *)base_addr;
+ smq->hdr = (struct smq_hdr *)pb_orig;
+ pb = pb_orig;
+ pb += sizeof(struct smq_hdr);
+ pb = PTR_ALIGN(pb, 8);
+ size -= pb - (uint8_t *)pb_orig;
+ num_blocks = (int)((size - sizeof(struct smq_out_state) -
+ sizeof(struct smq_in_state))/(SM_BLOCKSIZE +
+ sizeof(struct smq_node) * 2));
+ if (0 >= num_blocks) {
+ err = SMQ_ENOMEMORY;
+ goto bail;
+ }
+
+ smq->blocks = pb;
+ smq->num_blocks = num_blocks;
+ pb += num_blocks * SM_BLOCKSIZE;
+ smq->out = (struct smq_out *)pb;
+ pb += sizeof(struct smq_out_state) + (num_blocks *
+ sizeof(struct smq_node));
+ smq->in = (struct smq_in *)pb;
+ smq->type = type;
+ if (PRODUCER == type) {
+ smq->hdr->producer_version = SM_VERSION;
+ for (i = 0; i < smq->num_blocks; i++)
+ (smq->out->sent + i)->index_block = 0xFFFF;
+
+ err = smq_blockmap_ctor(&smq->block_map, smq->num_blocks);
+ if (SMQ_SUCCESS != err)
+ goto bail;
+
+ smq->out->s.index_sent_write = 0;
+ smq->out->s.index_free_read = 0;
+ if (smq->out->s.init == SMQ_MAGIC_PRODUCER) {
+ smq->out->s.index_check_queue_for_reset += 1;
+ } else {
+ smq->out->s.index_check_queue_for_reset = 1;
+ smq->out->s.init = SMQ_MAGIC_PRODUCER;
+ }
+ } else {
+ smq->hdr->consumer_version = SM_VERSION;
+ for (i = 0; i < smq->num_blocks; i++)
+ (smq->in->free + i)->index_block = 0xFFFF;
+
+ smq->in->s.index_sent_read = 0;
+ smq->in->s.index_free_write = 0;
+ if (smq->out->s.init == SMQ_MAGIC_PRODUCER) {
+ smq->in->s.index_check_queue_for_reset_ack =
+ smq->out->s.index_check_queue_for_reset;
+ } else {
+ smq->in->s.index_check_queue_for_reset_ack = 0;
+ }
+
+ smq->in->s.init = SMQ_MAGIC_CONSUMER;
+ }
+ smq->initialized = SMQ_MAGIC_INIT;
+ err = SMQ_SUCCESS;
+
+bail:
+ return err;
+}
+
+static void send_interrupt_to_subsystem(struct rdbg_data *rdbgdata)
+{
+ int offset = rdbgdata->gpio_out_offset;
+ int val = 1 ^ gpio_get_value(rdbgdata->out.gpio_base_id + offset);
+ gpio_set_value(rdbgdata->out.gpio_base_id + offset, val);
+ rdbgdata->gpio_out_offset = (offset + 1) % 32;
+
+ dev_dbg(rdbgdata->device, "%s: sent interrupt %d to subsystem",
+ __func__, val);
+}
+
+static irqreturn_t on_interrupt_from(int irq, void *ptr)
+{
+ struct rdbg_data *rdbgdata = (struct rdbg_data *) ptr;
+
+ dev_dbg(rdbgdata->device, "%s: Received interrupt %d from subsystem",
+ __func__, irq);
+
+ complete(&(rdbgdata->work));
+ return IRQ_HANDLED;
+}
+
+static int initialize_smq(struct rdbg_data *rdbgdata)
+{
+ int err = 0;
+
+ if (smq_ctor(&(rdbgdata->producer_smrb), (void *)(rdbgdata->smem_addr),
+ ((rdbgdata->smem_size)/2), PRODUCER, &rdbgdata->write_mutex)) {
+ dev_err(rdbgdata->device, "%s: smq producer allocation failed",
+ __func__);
+ err = -ENOMEM;
+ goto bail;
+ }
+
+ if (smq_ctor(&(rdbgdata->consumer_smrb), (void *)((uint32_t)
+ (rdbgdata->smem_addr) + ((rdbgdata->smem_size)/2)),
+ ((rdbgdata->smem_size)/2), CONSUMER, NULL)) {
+ dev_err(rdbgdata->device, "%s: smq conmsumer allocation failed",
+ __func__);
+ err = -ENOMEM;
+ }
+
+bail:
+ return err;
+
+}
+
+static int rdbg_open(struct inode *inode, struct file *filp)
+{
+ int device_id = -1;
+ struct rdbg_device *device = &g_rdbg_instance;
+ struct rdbg_data *rdbgdata = NULL;
+ int err = 0;
+
+ if (!inode || !device->rdbg_data) {
+ pr_err("Memory not allocated yet");
+ err = -ENODEV;
+ goto bail;
+ }
+
+ device_id = MINOR(inode->i_rdev);
+ rdbgdata = &device->rdbg_data[device_id];
+
+ if (rdbgdata->device_opened) {
+ dev_err(rdbgdata->device, "%s: Device already opened",
+ __func__);
+ err = -EEXIST;
+ goto bail;
+ }
+
+ rdbgdata->smem_size = proc_info[device_id].smem_buffer_size;
+ if (!rdbgdata->smem_size) {
+ dev_err(rdbgdata->device, "%s: smem not initialized", __func__);
+ err = -ENOMEM;
+ goto bail;
+ }
+
+ rdbgdata->smem_addr = smem_alloc(proc_info[device_id].smem_buffer_addr,
+ rdbgdata->smem_size);
+ if (!rdbgdata->smem_addr) {
+ dev_err(rdbgdata->device, "%s: Could not allocate smem memory",
+ __func__);
+ err = -ENOMEM;
+ goto bail;
+ }
+ dev_dbg(rdbgdata->device, "%s: SMEM address=0x%x smem_size=%d",
+ __func__, (unsigned int)rdbgdata->smem_addr,
+ rdbgdata->smem_size);
+
+ if (check_subsystem_debug_enabled(rdbgdata->smem_addr,
+ rdbgdata->smem_size/2)) {
+ dev_err(rdbgdata->device, "%s: Subsystem %s is not debug enabled",
+ __func__, proc_info[device_id].name);
+ err = -ECOMM;
+ goto bail;
+ }
+
+ init_completion(&rdbgdata->work);
+
+ err = request_irq(rdbgdata->in.irq_base_id, on_interrupt_from,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ proc_info[device_id].name,
+ (void *)&device->rdbg_data[device_id]);
+ if (err) {
+ dev_err(rdbgdata->device,
+ "%s: Failed to register interrupt.Err=%d,irqid=%d.",
+ __func__, err, rdbgdata->in.irq_base_id);
+ goto irq_bail;
+ }
+
+ err = enable_irq_wake(rdbgdata->in.irq_base_id);
+ if (err < 0) {
+ dev_dbg(rdbgdata->device, "enable_irq_wake() failed with err=%d",
+ err);
+ err = 0;
+ }
+
+ mutex_init(&rdbgdata->write_mutex);
+
+ err = initialize_smq(rdbgdata);
+ if (err) {
+ dev_err(rdbgdata->device, "Error initializing smq. Err=%d",
+ err);
+ goto smq_bail;
+ }
+
+ rdbgdata->device_opened = 1;
+
+ filp->private_data = (void *)rdbgdata;
+
+ return 0;
+
+smq_bail:
+ smq_dtor(&(rdbgdata->producer_smrb));
+ smq_dtor(&(rdbgdata->consumer_smrb));
+ mutex_destroy(&rdbgdata->write_mutex);
+irq_bail:
+ free_irq(rdbgdata->in.irq_base_id, (void *)
+ &device->rdbg_data[device_id]);
+bail:
+ return err;
+}
+
+static int rdbg_release(struct inode *inode, struct file *filp)
+{
+ int device_id = -1;
+ struct rdbg_device *rdbgdevice = &g_rdbg_instance;
+ struct rdbg_data *rdbgdata = NULL;
+ int err = 0;
+
+ if (!inode || !rdbgdevice->rdbg_data) {
+ pr_err("Memory not allocated yet");
+ err = -ENODEV;
+ goto bail;
+ }
+
+ device_id = MINOR(inode->i_rdev);
+ rdbgdata = &rdbgdevice->rdbg_data[device_id];
+
+ if (rdbgdata->device_opened == 1) {
+ dev_dbg(rdbgdata->device, "%s: Destroying %s.", __func__,
+ proc_info[device_id].name);
+ rdbgdata->device_opened = 0;
+ complete(&(rdbgdata->work));
+ free_irq(rdbgdata->in.irq_base_id, (void *)
+ &rdbgdevice->rdbg_data[device_id]);
+ if (rdbgdevice->rdbg_data[device_id].producer_smrb.initialized)
+ smq_dtor(&(rdbgdevice->rdbg_data[device_id].
+ producer_smrb));
+ if (rdbgdevice->rdbg_data[device_id].consumer_smrb.initialized)
+ smq_dtor(&(rdbgdevice->rdbg_data[device_id].
+ consumer_smrb));
+ mutex_destroy(&rdbgdata->write_mutex);
+ }
+
+ filp->private_data = NULL;
+
+bail:
+ return err;
+}
+
+static ssize_t rdbg_read(struct file *filp, char __user *buf, size_t size,
+ loff_t *offset)
+{
+ int err = 0;
+ struct rdbg_data *rdbgdata = filp->private_data;
+ void *p_sent_buffer = NULL;
+ int nsize = 0;
+ int more = 0;
+
+ if (!rdbgdata) {
+ pr_err("Invalid argument");
+ err = -EINVAL;
+ goto bail;
+ }
+
+ dev_dbg(rdbgdata->device, "%s: In receive", __func__);
+ err = wait_for_completion_interruptible(&(rdbgdata->work));
+ if (err) {
+ dev_err(rdbgdata->device, "%s: Error in wait", __func__);
+ goto bail;
+ }
+
+ smq_check_queue_reset(&(rdbgdata->consumer_smrb),
+ &(rdbgdata->producer_smrb));
+ if (SMQ_SUCCESS != smq_receive(&(rdbgdata->consumer_smrb),
+ &p_sent_buffer, &nsize, &more)) {
+ dev_err(rdbgdata->device, "%s: Error in smq_recv(). Err code = %d",
+ __func__, err);
+ err = -ENODATA;
+ goto bail;
+ }
+
+ size = ((size < nsize) ? size : nsize);
+ err = copy_to_user(buf, p_sent_buffer, size);
+ if (err != 0) {
+ dev_err(rdbgdata->device, "%s: Error in copy_to_user(). Err code = %d",
+ __func__, err);
+ err = -ENODATA;
+ goto bail;
+ }
+
+ smq_free(&(rdbgdata->consumer_smrb), p_sent_buffer);
+ err = size;
+ dev_dbg(rdbgdata->device, "%s: Read data to buffer with address 0x%x",
+ __func__, (unsigned int) buf);
+
+bail:
+ dev_dbg(rdbgdata->device, "%s: Returning from receive", __func__);
+ return err;
+}
+
+static ssize_t rdbg_write(struct file *filp, const char __user *buf,
+ size_t size, loff_t *offset)
+{
+ int err = 0;
+ struct rdbg_data *rdbgdata = filp->private_data;
+
+ if (!rdbgdata) {
+ pr_err("Invalid argument");
+ err = -EINVAL;
+ goto bail;
+ }
+
+ if (smq_alloc_send(&(rdbgdata->producer_smrb), buf, size)) {
+ dev_err(rdbgdata->device, "%s, Error sending", __func__);
+ err = -ECOMM;
+ goto bail;
+ }
+ send_interrupt_to_subsystem(rdbgdata);
+
+ err = size;
+
+bail:
+ return err;
+}
+
+
+static const struct file_operations rdbg_fops = {
+ .open = rdbg_open,
+ .read = rdbg_read,
+ .write = rdbg_write,
+ .release = rdbg_release,
+};
+
+static int register_smp2p(char *node_name, struct gpio_info *gpio_info_ptr)
+{
+ struct device_node *node = NULL;
+ int cnt = 0;
+ int id = 0;
+
+ node = of_find_compatible_node(NULL, NULL, node_name);
+ if (node) {
+ cnt = of_gpio_count(node);
+ if (cnt && gpio_info_ptr) {
+ id = of_get_gpio(node, 0);
+ gpio_info_ptr->gpio_base_id = id;
+ gpio_info_ptr->irq_base_id = gpio_to_irq(id);
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+static int __init rdbg_init(void)
+{
+ int err = 0;
+ struct rdbg_device *rdbgdevice = &g_rdbg_instance;
+ int minor = 0;
+ int major = 0;
+ int minor_nodes_created = 0;
+
+ char *rdbg_compatible_string = "qcom,smp2pgpio_client_rdbg_";
+ int max_len = strlen(rdbg_compatible_string) + strlen("xx_out");
+
+ char *node_name = kcalloc(max_len, sizeof(char), GFP_KERNEL);
+
+ if (!node_name) {
+ pr_err("Not enough memory");
+ err = -ENOMEM;
+ goto bail;
+ }
+
+ if (rdbgdevice->num_devices < 1 ||
+ rdbgdevice->num_devices > SMP2P_NUM_PROCS) {
+ pr_err("rgdb: invalid num_devices");
+ err = -EDOM;
+ goto name_bail;
+ }
+
+ rdbgdevice->rdbg_data = kcalloc(rdbgdevice->num_devices,
+ sizeof(struct rdbg_data), GFP_KERNEL);
+ if (!rdbgdevice->rdbg_data) {
+ pr_err("Not enough memory for rdbg devices");
+ err = -ENOMEM;
+ goto name_bail;
+ }
+
+ err = alloc_chrdev_region(&rdbgdevice->dev_no, 0,
+ rdbgdevice->num_devices, "rdbgctl");
+ if (err) {
+ pr_err("Error in alloc_chrdev_region.");
+ goto data_bail;
+ }
+ major = MAJOR(rdbgdevice->dev_no);
+
+ cdev_init(&rdbgdevice->cdev, &rdbg_fops);
+ rdbgdevice->cdev.owner = THIS_MODULE;
+ err = cdev_add(&rdbgdevice->cdev, MKDEV(major, 0),
+ rdbgdevice->num_devices);
+ if (err) {
+ pr_err("Error in cdev_add");
+ goto chrdev_bail;
+ }
+
+ rdbgdevice->class = class_create(THIS_MODULE, "rdbg");
+ if (IS_ERR(rdbgdevice->class)) {
+ err = PTR_ERR(rdbgdevice->class);
+ pr_err("Error in class_create");
+ goto cdev_bail;
+ }
+
+ for (minor = 0; minor < rdbgdevice->num_devices; minor++) {
+ if (!proc_info[minor].name)
+ continue;
+
+ if (snprintf(node_name, max_len, "%s%d_in",
+ rdbg_compatible_string, minor) <= 0) {
+ pr_err("Error in snprintf");
+ err = -ENOMEM;
+ goto device_bail;
+ }
+
+ if (register_smp2p(node_name,
+ &rdbgdevice->rdbg_data[minor].in)) {
+ pr_debug("No incoming device tree entry found for %s",
+ proc_info[minor].name);
+ continue;
+ }
+
+ if (snprintf(node_name, max_len, "%s%d_out",
+ rdbg_compatible_string, minor) <= 0) {
+ pr_err("Error in snprintf");
+ err = -ENOMEM;
+ goto device_bail;
+ }
+
+ if (register_smp2p(node_name,
+ &rdbgdevice->rdbg_data[minor].out)) {
+ pr_err("No outgoing device tree entry found for %s",
+ proc_info[minor].name);
+ err = -EINVAL;
+ goto device_bail;
+ }
+
+ rdbgdevice->rdbg_data[minor].device = device_create(
+ rdbgdevice->class, NULL, MKDEV(major, minor),
+ NULL, "%s", proc_info[minor].name);
+ if (IS_ERR(rdbgdevice->rdbg_data[minor].device)) {
+ err = PTR_ERR(rdbgdevice->rdbg_data[minor].device);
+ pr_err("Error in device_create");
+ goto device_bail;
+ }
+ rdbgdevice->rdbg_data[minor].device_initialized = 1;
+ minor_nodes_created++;
+ dev_dbg(rdbgdevice->rdbg_data[minor].device,
+ "%s: created /dev/%s c %d %d'", __func__,
+ proc_info[minor].name, major, minor);
+ }
+
+ if (!minor_nodes_created) {
+ pr_err("No device tree entries found");
+ err = -EINVAL;
+ goto class_bail;
+ }
+
+ goto name_bail;
+
+device_bail:
+ for (--minor; minor >= 0; minor--) {
+ if (rdbgdevice->rdbg_data[minor].device_initialized)
+ device_destroy(rdbgdevice->class,
+ MKDEV(MAJOR(rdbgdevice->dev_no), minor));
+ }
+class_bail:
+ class_destroy(rdbgdevice->class);
+cdev_bail:
+ cdev_del(&rdbgdevice->cdev);
+chrdev_bail:
+ unregister_chrdev_region(rdbgdevice->dev_no, rdbgdevice->num_devices);
+data_bail:
+ kfree(rdbgdevice->rdbg_data);
+name_bail:
+ kfree(node_name);
+bail:
+ return err;
+}
+
+static void __exit rdbg_exit(void)
+{
+ struct rdbg_device *rdbgdevice = &g_rdbg_instance;
+ int minor;
+
+ for (minor = 0; minor < rdbgdevice->num_devices; minor++) {
+ if (rdbgdevice->rdbg_data[minor].device_initialized) {
+ device_destroy(rdbgdevice->class,
+ MKDEV(MAJOR(rdbgdevice->dev_no), minor));
+ }
+ }
+ class_destroy(rdbgdevice->class);
+ cdev_del(&rdbgdevice->cdev);
+ unregister_chrdev_region(rdbgdevice->dev_no, 1);
+ kfree(rdbgdevice->rdbg_data);
+}
+
+module_init(rdbg_init);
+module_exit(rdbg_exit);
+
+MODULE_DESCRIPTION("rdbg module");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 46756c5..83ab92b 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -1,5 +1,5 @@
# CPUfreq core
-obj-$(CONFIG_CPU_FREQ) += cpufreq.o
+obj-$(CONFIG_CPU_FREQ) += cpufreq.o cpu-boost.o
# CPUfreq stats
obj-$(CONFIG_CPU_FREQ_STAT) += cpufreq_stats.o
diff --git a/drivers/cpufreq/cpu-boost.c b/drivers/cpufreq/cpu-boost.c
new file mode 100644
index 0000000..8cd5ef9
--- /dev/null
+++ b/drivers/cpufreq/cpu-boost.c
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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) "cpu-boost: " fmt
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/notifier.h>
+#include <linux/cpufreq.h>
+#include <linux/sched.h>
+#include <linux/jiffies.h>
+#include <linux/kthread.h>
+#include <linux/moduleparam.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/time.h>
+
+struct cpu_sync {
+ struct task_struct *thread;
+ wait_queue_head_t sync_wq;
+ struct delayed_work boost_rem;
+ struct delayed_work input_boost_rem;
+ int cpu;
+ spinlock_t lock;
+ bool pending;
+ int src_cpu;
+ unsigned int boost_min;
+ unsigned int input_boost_min;
+};
+
+static DEFINE_PER_CPU(struct cpu_sync, sync_info);
+static struct workqueue_struct *cpu_boost_wq;
+
+static struct work_struct input_boost_work;
+
+static unsigned int boost_ms;
+module_param(boost_ms, uint, 0644);
+
+static unsigned int sync_threshold;
+module_param(sync_threshold, uint, 0644);
+
+static unsigned int input_boost_freq;
+module_param(input_boost_freq, uint, 0644);
+
+static unsigned int input_boost_ms = 40;
+module_param(input_boost_ms, uint, 0644);
+
+static u64 last_input_time;
+#define MIN_INPUT_INTERVAL (150 * USEC_PER_MSEC)
+
+/*
+ * The CPUFREQ_ADJUST notifier is used to override the current policy min to
+ * make sure policy min >= boost_min. The cpufreq framework then does the job
+ * of enforcing the new policy.
+ */
+static int boost_adjust_notify(struct notifier_block *nb, unsigned long val, void *data)
+{
+ struct cpufreq_policy *policy = data;
+ unsigned int cpu = policy->cpu;
+ struct cpu_sync *s = &per_cpu(sync_info, cpu);
+ unsigned int b_min = s->boost_min;
+ unsigned int ib_min = s->input_boost_min;
+ unsigned int min;
+
+ if (val != CPUFREQ_ADJUST)
+ return NOTIFY_OK;
+
+ if (!b_min && !ib_min)
+ return NOTIFY_OK;
+
+ min = max(b_min, ib_min);
+
+ pr_debug("CPU%u policy min before boost: %u kHz\n",
+ cpu, policy->min);
+ pr_debug("CPU%u boost min: %u kHz\n", cpu, min);
+
+ cpufreq_verify_within_limits(policy, min, UINT_MAX);
+
+ pr_debug("CPU%u policy min after boost: %u kHz\n",
+ cpu, policy->min);
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block boost_adjust_nb = {
+ .notifier_call = boost_adjust_notify,
+};
+
+static void do_boost_rem(struct work_struct *work)
+{
+ struct cpu_sync *s = container_of(work, struct cpu_sync,
+ boost_rem.work);
+
+ pr_debug("Removing boost for CPU%d\n", s->cpu);
+ s->boost_min = 0;
+ /* Force policy re-evaluation to trigger adjust notifier. */
+ cpufreq_update_policy(s->cpu);
+}
+
+static void do_input_boost_rem(struct work_struct *work)
+{
+ struct cpu_sync *s = container_of(work, struct cpu_sync,
+ input_boost_rem.work);
+
+ pr_debug("Removing input boost for CPU%d\n", s->cpu);
+ s->input_boost_min = 0;
+ /* Force policy re-evaluation to trigger adjust notifier. */
+ cpufreq_update_policy(s->cpu);
+}
+
+static int boost_mig_sync_thread(void *data)
+{
+ int dest_cpu = (int) data;
+ int src_cpu, ret;
+ struct cpu_sync *s = &per_cpu(sync_info, dest_cpu);
+ struct cpufreq_policy dest_policy;
+ struct cpufreq_policy src_policy;
+ unsigned long flags;
+
+ while(1) {
+ wait_event(s->sync_wq, s->pending || kthread_should_stop());
+
+ if (kthread_should_stop())
+ break;
+
+ spin_lock_irqsave(&s->lock, flags);
+ s->pending = false;
+ src_cpu = s->src_cpu;
+ spin_unlock_irqrestore(&s->lock, flags);
+
+ ret = cpufreq_get_policy(&src_policy, src_cpu);
+ if (ret)
+ continue;
+
+ ret = cpufreq_get_policy(&dest_policy, dest_cpu);
+ if (ret)
+ continue;
+
+ if (dest_policy.cur >= src_policy.cur ) {
+ pr_debug("No sync. CPU%d@%dKHz >= CPU%d@%dKHz\n",
+ dest_cpu, dest_policy.cur, src_cpu, src_policy.cur);
+ continue;
+ }
+
+ if (sync_threshold && (dest_policy.cur >= sync_threshold))
+ continue;
+
+ cancel_delayed_work_sync(&s->boost_rem);
+ if (sync_threshold) {
+ if (src_policy.cur >= sync_threshold)
+ s->boost_min = sync_threshold;
+ else
+ s->boost_min = src_policy.cur;
+ } else {
+ s->boost_min = src_policy.cur;
+ }
+ /* Force policy re-evaluation to trigger adjust notifier. */
+ cpufreq_update_policy(dest_cpu);
+ queue_delayed_work_on(s->cpu, cpu_boost_wq,
+ &s->boost_rem, msecs_to_jiffies(boost_ms));
+ }
+
+ return 0;
+}
+
+static int boost_migration_notify(struct notifier_block *nb,
+ unsigned long dest_cpu, void *arg)
+{
+ unsigned long flags;
+ struct cpu_sync *s = &per_cpu(sync_info, dest_cpu);
+
+ if (!boost_ms)
+ return NOTIFY_OK;
+
+ pr_debug("Migration: CPU%d --> CPU%d\n", (int) arg, (int) dest_cpu);
+ spin_lock_irqsave(&s->lock, flags);
+ s->pending = true;
+ s->src_cpu = (int) arg;
+ spin_unlock_irqrestore(&s->lock, flags);
+ wake_up(&s->sync_wq);
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block boost_migration_nb = {
+ .notifier_call = boost_migration_notify,
+};
+
+static void do_input_boost(struct work_struct *work)
+{
+ unsigned int i, ret;
+ struct cpu_sync *i_sync_info;
+ struct cpufreq_policy policy;
+
+ for_each_online_cpu(i) {
+
+ i_sync_info = &per_cpu(sync_info, i);
+ ret = cpufreq_get_policy(&policy, i);
+ if (ret)
+ continue;
+ if (policy.cur >= input_boost_freq)
+ continue;
+
+ cancel_delayed_work_sync(&i_sync_info->input_boost_rem);
+ i_sync_info->input_boost_min = input_boost_freq;
+ cpufreq_update_policy(i);
+ queue_delayed_work_on(i_sync_info->cpu, cpu_boost_wq,
+ &i_sync_info->input_boost_rem,
+ msecs_to_jiffies(input_boost_ms));
+ }
+}
+
+static void cpuboost_input_event(struct input_handle *handle,
+ unsigned int type, unsigned int code, int value)
+{
+ u64 now;
+
+ if (!input_boost_freq)
+ return;
+
+ now = ktime_to_us(ktime_get());
+ if (now - last_input_time < MIN_INPUT_INTERVAL)
+ return;
+
+ if (work_pending(&input_boost_work))
+ return;
+
+ queue_work(cpu_boost_wq, &input_boost_work);
+ last_input_time = ktime_to_us(ktime_get());
+}
+
+static int cpuboost_input_connect(struct input_handler *handler,
+ struct input_dev *dev, const struct input_device_id *id)
+{
+ struct input_handle *handle;
+ int error;
+
+ handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
+ if (!handle)
+ return -ENOMEM;
+
+ handle->dev = dev;
+ handle->handler = handler;
+ handle->name = "cpufreq";
+
+ error = input_register_handle(handle);
+ if (error)
+ goto err2;
+
+ error = input_open_device(handle);
+ if (error)
+ goto err1;
+
+ return 0;
+err1:
+ input_unregister_handle(handle);
+err2:
+ kfree(handle);
+ return error;
+}
+
+static void cpuboost_input_disconnect(struct input_handle *handle)
+{
+ input_close_device(handle);
+ input_unregister_handle(handle);
+ kfree(handle);
+}
+
+static const struct input_device_id cpuboost_ids[] = {
+ /* multi-touch touchscreen */
+ {
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
+ INPUT_DEVICE_ID_MATCH_ABSBIT,
+ .evbit = { BIT_MASK(EV_ABS) },
+ .absbit = { [BIT_WORD(ABS_MT_POSITION_X)] =
+ BIT_MASK(ABS_MT_POSITION_X) |
+ BIT_MASK(ABS_MT_POSITION_Y) },
+ },
+ /* touchpad */
+ {
+ .flags = INPUT_DEVICE_ID_MATCH_KEYBIT |
+ INPUT_DEVICE_ID_MATCH_ABSBIT,
+ .keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) },
+ .absbit = { [BIT_WORD(ABS_X)] =
+ BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) },
+ },
+ /* Keypad */
+ {
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+ .evbit = { BIT_MASK(EV_KEY) },
+ },
+ { },
+};
+
+static struct input_handler cpuboost_input_handler = {
+ .event = cpuboost_input_event,
+ .connect = cpuboost_input_connect,
+ .disconnect = cpuboost_input_disconnect,
+ .name = "cpu-boost",
+ .id_table = cpuboost_ids,
+};
+
+static int cpu_boost_init(void)
+{
+ int cpu, ret;
+ struct cpu_sync *s;
+
+ cpufreq_register_notifier(&boost_adjust_nb, CPUFREQ_POLICY_NOTIFIER);
+
+ cpu_boost_wq = alloc_workqueue("cpuboost_wq", WQ_HIGHPRI, 0);
+ if (!cpu_boost_wq)
+ return -EFAULT;
+
+ INIT_WORK(&input_boost_work, do_input_boost);
+
+ for_each_possible_cpu(cpu) {
+ s = &per_cpu(sync_info, cpu);
+ s->cpu = cpu;
+ init_waitqueue_head(&s->sync_wq);
+ spin_lock_init(&s->lock);
+ INIT_DELAYED_WORK(&s->boost_rem, do_boost_rem);
+ INIT_DELAYED_WORK(&s->input_boost_rem, do_input_boost_rem);
+ s->thread = kthread_run(boost_mig_sync_thread, (void *)cpu,
+ "boost_sync/%d", cpu);
+ }
+ atomic_notifier_chain_register(&migration_notifier_head,
+ &boost_migration_nb);
+
+ ret = input_register_handler(&cpuboost_input_handler);
+ return 0;
+}
+late_initcall(cpu_boost_init);
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 975a42f..4605685 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -1726,7 +1726,8 @@
memcpy(&policy->cpuinfo, &data->cpuinfo,
sizeof(struct cpufreq_cpuinfo));
- if (policy->min > data->max || policy->max < data->min) {
+ if (policy->min > data->user_policy.max
+ || policy->max < data->user_policy.min) {
ret = -EINVAL;
goto error_out;
}
diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c
index 7d1952c..45a41eb 100644
--- a/drivers/cpufreq/cpufreq_interactive.c
+++ b/drivers/cpufreq/cpufreq_interactive.c
@@ -29,6 +29,7 @@
#include <linux/workqueue.h>
#include <linux/kthread.h>
#include <linux/slab.h>
+#include <linux/kernel_stat.h>
#include <asm/cputime.h>
#define CREATE_TRACE_POINTS
@@ -52,6 +53,7 @@
u64 hispeed_validate_time;
struct rw_semaphore enable_sem;
int governor_enabled;
+ int prev_load;
};
static DEFINE_PER_CPU(struct cpufreq_interactive_cpuinfo, cpuinfo);
@@ -69,6 +71,9 @@
#define DEFAULT_GO_HISPEED_LOAD 99
static unsigned long go_hispeed_load = DEFAULT_GO_HISPEED_LOAD;
+/* Sampling down factor to be applied to min_sample_time at max freq */
+static unsigned int sampling_down_factor;
+
/* Target load. Lower values result in higher CPU speeds. */
#define DEFAULT_TARGET_LOAD 90
static unsigned int default_target_loads[] = {DEFAULT_TARGET_LOAD};
@@ -88,12 +93,19 @@
#define DEFAULT_TIMER_RATE (20 * USEC_PER_MSEC)
static unsigned long timer_rate = DEFAULT_TIMER_RATE;
+/* Busy SDF parameters*/
+#define MIN_BUSY_TIME (100 * USEC_PER_MSEC)
+
/*
* Wait this long before raising speed above hispeed, by default a single
* timer interval.
*/
#define DEFAULT_ABOVE_HISPEED_DELAY DEFAULT_TIMER_RATE
-static unsigned long above_hispeed_delay_val = DEFAULT_ABOVE_HISPEED_DELAY;
+static unsigned int default_above_hispeed_delay[] = {
+ DEFAULT_ABOVE_HISPEED_DELAY };
+static spinlock_t above_hispeed_delay_lock;
+static unsigned int *above_hispeed_delay = default_above_hispeed_delay;
+static int nabove_hispeed_delay = ARRAY_SIZE(default_above_hispeed_delay);
/* Non-zero means indefinite speed boost active */
static int boost_val;
@@ -109,6 +121,18 @@
#define DEFAULT_TIMER_SLACK (4 * DEFAULT_TIMER_RATE)
static int timer_slack_val = DEFAULT_TIMER_SLACK;
+static bool io_is_busy;
+
+/*
+ * If the max load among other CPUs is higher than up_threshold_any_cpu_load
+ * and if the highest frequency among the other CPUs is higher than
+ * up_threshold_any_cpu_freq then do not let the frequency to drop below
+ * sync_freq
+ */
+static unsigned int up_threshold_any_cpu_load;
+static unsigned int sync_freq;
+static unsigned int up_threshold_any_cpu_freq;
+
static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
unsigned int event);
@@ -122,27 +146,110 @@
.owner = THIS_MODULE,
};
+static inline cputime64_t get_cpu_idle_time_jiffy(unsigned int cpu,
+ cputime64_t *wall)
+{
+ u64 idle_time;
+ u64 cur_wall_time;
+ u64 busy_time;
+
+ cur_wall_time = jiffies64_to_cputime64(get_jiffies_64());
+
+ busy_time = kcpustat_cpu(cpu).cpustat[CPUTIME_USER];
+ busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SYSTEM];
+ busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_IRQ];
+ busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SOFTIRQ];
+ busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_STEAL];
+ busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_NICE];
+
+ idle_time = cur_wall_time - busy_time;
+ if (wall)
+ *wall = jiffies_to_usecs(cur_wall_time);
+
+ return jiffies_to_usecs(idle_time);
+}
+
+static inline cputime64_t get_cpu_idle_time(unsigned int cpu,
+ cputime64_t *wall)
+{
+ u64 idle_time = get_cpu_idle_time_us(cpu, wall);
+
+ if (idle_time == -1ULL)
+ idle_time = get_cpu_idle_time_jiffy(cpu, wall);
+ else if (!io_is_busy)
+ idle_time += get_cpu_iowait_time_us(cpu, wall);
+
+ return idle_time;
+}
+
static void cpufreq_interactive_timer_resched(
struct cpufreq_interactive_cpuinfo *pcpu)
{
- unsigned long expires = jiffies + usecs_to_jiffies(timer_rate);
+ unsigned long expires;
unsigned long flags;
+ spin_lock_irqsave(&pcpu->load_lock, flags);
+ pcpu->time_in_idle =
+ get_cpu_idle_time(smp_processor_id(),
+ &pcpu->time_in_idle_timestamp);
+ pcpu->cputime_speedadj = 0;
+ pcpu->cputime_speedadj_timestamp = pcpu->time_in_idle_timestamp;
+ expires = jiffies + usecs_to_jiffies(timer_rate);
mod_timer_pinned(&pcpu->cpu_timer, expires);
+
if (timer_slack_val >= 0 && pcpu->target_freq > pcpu->policy->min) {
expires += usecs_to_jiffies(timer_slack_val);
mod_timer_pinned(&pcpu->cpu_slack_timer, expires);
}
+ spin_unlock_irqrestore(&pcpu->load_lock, flags);
+}
+
+/* The caller shall take enable_sem write semaphore to avoid any timer race.
+ * The cpu_timer and cpu_slack_timer must be deactivated when calling this
+ * function.
+ */
+static void cpufreq_interactive_timer_start(int cpu)
+{
+ struct cpufreq_interactive_cpuinfo *pcpu = &per_cpu(cpuinfo, cpu);
+ unsigned long expires = jiffies + usecs_to_jiffies(timer_rate);
+ unsigned long flags;
+
+ pcpu->cpu_timer.expires = expires;
+ add_timer_on(&pcpu->cpu_timer, cpu);
+ if (timer_slack_val >= 0 && pcpu->target_freq > pcpu->policy->min) {
+ expires += usecs_to_jiffies(timer_slack_val);
+ pcpu->cpu_slack_timer.expires = expires;
+ add_timer_on(&pcpu->cpu_slack_timer, cpu);
+ }
+
spin_lock_irqsave(&pcpu->load_lock, flags);
pcpu->time_in_idle =
- get_cpu_idle_time_us(smp_processor_id(),
- &pcpu->time_in_idle_timestamp);
+ get_cpu_idle_time(cpu, &pcpu->time_in_idle_timestamp);
pcpu->cputime_speedadj = 0;
pcpu->cputime_speedadj_timestamp = pcpu->time_in_idle_timestamp;
spin_unlock_irqrestore(&pcpu->load_lock, flags);
}
+static unsigned int freq_to_above_hispeed_delay(unsigned int freq)
+{
+ int i;
+ unsigned int ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&above_hispeed_delay_lock, flags);
+
+ for (i = 0; i < nabove_hispeed_delay - 1 &&
+ freq >= above_hispeed_delay[i+1]; i += 2)
+ ;
+
+ ret = above_hispeed_delay[i];
+ ret = (ret > (1 * USEC_PER_MSEC)) ? (ret - (1 * USEC_PER_MSEC)) : ret;
+
+ spin_unlock_irqrestore(&above_hispeed_delay_lock, flags);
+ return ret;
+}
+
static unsigned int freq_to_targetload(unsigned int freq)
{
int i;
@@ -185,9 +292,10 @@
* than or equal to the target load.
*/
- cpufreq_frequency_table_target(
- pcpu->policy, pcpu->freq_table, loadadjfreq / tl,
- CPUFREQ_RELATION_L, &index);
+ if (cpufreq_frequency_table_target(
+ pcpu->policy, pcpu->freq_table, loadadjfreq / tl,
+ CPUFREQ_RELATION_L, &index))
+ break;
freq = pcpu->freq_table[index].frequency;
if (freq > prevfreq) {
@@ -199,10 +307,11 @@
* Find the highest frequency that is less
* than freqmax.
*/
- cpufreq_frequency_table_target(
- pcpu->policy, pcpu->freq_table,
- freqmax - 1, CPUFREQ_RELATION_H,
- &index);
+ if (cpufreq_frequency_table_target(
+ pcpu->policy, pcpu->freq_table,
+ freqmax - 1, CPUFREQ_RELATION_H,
+ &index))
+ break;
freq = pcpu->freq_table[index].frequency;
if (freq == freqmin) {
@@ -225,10 +334,11 @@
* Find the lowest frequency that is higher
* than freqmin.
*/
- cpufreq_frequency_table_target(
- pcpu->policy, pcpu->freq_table,
- freqmin + 1, CPUFREQ_RELATION_L,
- &index);
+ if (cpufreq_frequency_table_target(
+ pcpu->policy, pcpu->freq_table,
+ freqmin + 1, CPUFREQ_RELATION_L,
+ &index))
+ break;
freq = pcpu->freq_table[index].frequency;
/*
@@ -256,10 +366,15 @@
unsigned int delta_time;
u64 active_time;
- now_idle = get_cpu_idle_time_us(cpu, &now);
+ now_idle = get_cpu_idle_time(cpu, &now);
delta_idle = (unsigned int)(now_idle - pcpu->time_in_idle);
delta_time = (unsigned int)(now - pcpu->time_in_idle_timestamp);
- active_time = delta_time - delta_idle;
+
+ if (delta_time <= delta_idle)
+ active_time = 0;
+ else
+ active_time = delta_time - delta_idle;
+
pcpu->cputime_speedadj += active_time * pcpu->policy->cur;
pcpu->time_in_idle = now_idle;
@@ -280,6 +395,10 @@
unsigned int index;
unsigned long flags;
bool boosted;
+ unsigned long mod_min_sample_time;
+ int i, max_load;
+ unsigned int max_freq;
+ struct cpufreq_interactive_cpuinfo *picpu;
if (!down_read_trylock(&pcpu->enable_sem))
return;
@@ -298,6 +417,7 @@
do_div(cputime_speedadj, delta_time);
loadadjfreq = (unsigned int)cputime_speedadj * 100;
cpu_load = loadadjfreq / pcpu->target_freq;
+ pcpu->prev_load = cpu_load;
boosted = boost_val || now < boostpulse_endtime;
if (cpu_load >= go_hispeed_load || boosted) {
@@ -311,11 +431,33 @@
}
} else {
new_freq = choose_freq(pcpu, loadadjfreq);
+
+ if (sync_freq && new_freq < sync_freq) {
+
+ max_load = 0;
+ max_freq = 0;
+
+ for_each_online_cpu(i) {
+ picpu = &per_cpu(cpuinfo, i);
+
+ if (i == data || picpu->prev_load <
+ up_threshold_any_cpu_load)
+ continue;
+
+ max_load = max(max_load, picpu->prev_load);
+ max_freq = max(max_freq, picpu->policy->cur);
+ }
+
+ if (max_freq > up_threshold_any_cpu_freq &&
+ max_load >= up_threshold_any_cpu_load)
+ new_freq = sync_freq;
+ }
}
if (pcpu->target_freq >= hispeed_freq &&
new_freq > pcpu->target_freq &&
- now - pcpu->hispeed_validate_time < above_hispeed_delay_val) {
+ now - pcpu->hispeed_validate_time <
+ freq_to_above_hispeed_delay(pcpu->target_freq)) {
trace_cpufreq_interactive_notyet(
data, cpu_load, pcpu->target_freq,
pcpu->policy->cur, new_freq);
@@ -326,11 +468,8 @@
if (cpufreq_frequency_table_target(pcpu->policy, pcpu->freq_table,
new_freq, CPUFREQ_RELATION_L,
- &index)) {
- pr_warn_once("timer %d: cpufreq_frequency_table_target error\n",
- (int) data);
+ &index))
goto rearm;
- }
new_freq = pcpu->freq_table[index].frequency;
@@ -338,8 +477,13 @@
* Do not scale below floor_freq unless we have been at or above the
* floor frequency for the minimum sample time since last validated.
*/
+ if (sampling_down_factor && pcpu->policy->cur == pcpu->policy->max)
+ mod_min_sample_time = sampling_down_factor;
+ else
+ mod_min_sample_time = min_sample_time;
+
if (new_freq < pcpu->floor_freq) {
- if (now - pcpu->floor_validate_time < min_sample_time) {
+ if (now - pcpu->floor_validate_time < mod_min_sample_time) {
trace_cpufreq_interactive_notyet(
data, cpu_load, pcpu->target_freq,
pcpu->policy->cur, new_freq);
@@ -398,6 +542,7 @@
struct cpufreq_interactive_cpuinfo *pcpu =
&per_cpu(cpuinfo, smp_processor_id());
int pending;
+ u64 now;
if (!down_read_trylock(&pcpu->enable_sem))
return;
@@ -417,8 +562,17 @@
* min indefinitely. This should probably be a quirk of
* the CPUFreq driver.
*/
- if (!pending)
+ if (!pending) {
cpufreq_interactive_timer_resched(pcpu);
+
+ now = ktime_to_us(ktime_get());
+ if ((pcpu->policy->cur == pcpu->policy->max) &&
+ (now - pcpu->hispeed_validate_time) >
+ MIN_BUSY_TIME) {
+ pcpu->floor_validate_time = now;
+ }
+
+ }
}
up_read(&pcpu->enable_sem);
@@ -565,9 +719,19 @@
for_each_cpu(cpu, pcpu->policy->cpus) {
struct cpufreq_interactive_cpuinfo *pjcpu =
&per_cpu(cpuinfo, cpu);
+ if (cpu != freq->cpu) {
+ if (!down_read_trylock(&pjcpu->enable_sem))
+ continue;
+ if (!pjcpu->governor_enabled) {
+ up_read(&pjcpu->enable_sem);
+ continue;
+ }
+ }
spin_lock_irqsave(&pjcpu->load_lock, flags);
update_load(cpu);
spin_unlock_irqrestore(&pjcpu->load_lock, flags);
+ if (cpu != freq->cpu)
+ up_read(&pjcpu->enable_sem);
}
up_read(&pcpu->enable_sem);
@@ -579,6 +743,51 @@
.notifier_call = cpufreq_interactive_notifier,
};
+static unsigned int *get_tokenized_data(const char *buf, int *num_tokens)
+{
+ const char *cp;
+ int i;
+ int ntokens = 1;
+ unsigned int *tokenized_data;
+ int err = -EINVAL;
+
+ cp = buf;
+ while ((cp = strpbrk(cp + 1, " :")))
+ ntokens++;
+
+ if (!(ntokens & 0x1))
+ goto err;
+
+ tokenized_data = kmalloc(ntokens * sizeof(unsigned int), GFP_KERNEL);
+ if (!tokenized_data) {
+ err = -ENOMEM;
+ goto err;
+ }
+
+ cp = buf;
+ i = 0;
+ while (i < ntokens) {
+ if (sscanf(cp, "%u", &tokenized_data[i++]) != 1)
+ goto err_kfree;
+
+ cp = strpbrk(cp, " :");
+ if (!cp)
+ break;
+ cp++;
+ }
+
+ if (i != ntokens)
+ goto err_kfree;
+
+ *num_tokens = ntokens;
+ return tokenized_data;
+
+err_kfree:
+ kfree(tokenized_data);
+err:
+ return ERR_PTR(err);
+}
+
static ssize_t show_target_loads(
struct kobject *kobj, struct attribute *attr, char *buf)
{
@@ -592,7 +801,7 @@
ret += sprintf(buf + ret, "%u%s", target_loads[i],
i & 0x1 ? ":" : " ");
- ret += sprintf(buf + ret, "\n");
+ ret += sprintf(buf + --ret, "\n");
spin_unlock_irqrestore(&target_loads_lock, flags);
return ret;
}
@@ -601,40 +810,13 @@
struct kobject *kobj, struct attribute *attr, const char *buf,
size_t count)
{
- int ret;
- const char *cp;
+ int ntokens;
unsigned int *new_target_loads = NULL;
- int ntokens = 1;
- int i;
unsigned long flags;
- cp = buf;
- while ((cp = strpbrk(cp + 1, " :")))
- ntokens++;
-
- if (!(ntokens & 0x1))
- goto err_inval;
-
- new_target_loads = kmalloc(ntokens * sizeof(unsigned int), GFP_KERNEL);
- if (!new_target_loads) {
- ret = -ENOMEM;
- goto err;
- }
-
- cp = buf;
- i = 0;
- while (i < ntokens) {
- if (sscanf(cp, "%u", &new_target_loads[i++]) != 1)
- goto err_inval;
-
- cp = strpbrk(cp, " :");
- if (!cp)
- break;
- cp++;
- }
-
- if (i != ntokens)
- goto err_inval;
+ new_target_loads = get_tokenized_data(buf, &ntokens);
+ if (IS_ERR(new_target_loads))
+ return PTR_RET(new_target_loads);
spin_lock_irqsave(&target_loads_lock, flags);
if (target_loads != default_target_loads)
@@ -643,18 +825,56 @@
ntarget_loads = ntokens;
spin_unlock_irqrestore(&target_loads_lock, flags);
return count;
-
-err_inval:
- ret = -EINVAL;
-err:
- kfree(new_target_loads);
- return ret;
}
static struct global_attr target_loads_attr =
__ATTR(target_loads, S_IRUGO | S_IWUSR,
show_target_loads, store_target_loads);
+static ssize_t show_above_hispeed_delay(
+ struct kobject *kobj, struct attribute *attr, char *buf)
+{
+ int i;
+ ssize_t ret = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&above_hispeed_delay_lock, flags);
+
+ for (i = 0; i < nabove_hispeed_delay; i++)
+ ret += sprintf(buf + ret, "%u%s", above_hispeed_delay[i],
+ i & 0x1 ? ":" : " ");
+
+ ret += sprintf(buf + --ret, "\n");
+ spin_unlock_irqrestore(&above_hispeed_delay_lock, flags);
+ return ret;
+}
+
+static ssize_t store_above_hispeed_delay(
+ struct kobject *kobj, struct attribute *attr, const char *buf,
+ size_t count)
+{
+ int ntokens;
+ unsigned int *new_above_hispeed_delay = NULL;
+ unsigned long flags;
+
+ new_above_hispeed_delay = get_tokenized_data(buf, &ntokens);
+ if (IS_ERR(new_above_hispeed_delay))
+ return PTR_RET(new_above_hispeed_delay);
+
+ spin_lock_irqsave(&above_hispeed_delay_lock, flags);
+ if (above_hispeed_delay != default_above_hispeed_delay)
+ kfree(above_hispeed_delay);
+ above_hispeed_delay = new_above_hispeed_delay;
+ nabove_hispeed_delay = ntokens;
+ spin_unlock_irqrestore(&above_hispeed_delay_lock, flags);
+ return count;
+
+}
+
+static struct global_attr above_hispeed_delay_attr =
+ __ATTR(above_hispeed_delay, S_IRUGO | S_IWUSR,
+ show_above_hispeed_delay, store_above_hispeed_delay);
+
static ssize_t show_hispeed_freq(struct kobject *kobj,
struct attribute *attr, char *buf)
{
@@ -678,6 +898,29 @@
static struct global_attr hispeed_freq_attr = __ATTR(hispeed_freq, 0644,
show_hispeed_freq, store_hispeed_freq);
+static ssize_t show_sampling_down_factor(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ return sprintf(buf, "%u\n", sampling_down_factor);
+}
+
+static ssize_t store_sampling_down_factor(struct kobject *kobj,
+ struct attribute *attr, const char *buf,
+ size_t count)
+{
+ int ret;
+ long unsigned int val;
+
+ ret = strict_strtoul(buf, 0, &val);
+ if (ret < 0)
+ return ret;
+ sampling_down_factor = val;
+ return count;
+}
+
+static struct global_attr sampling_down_factor_attr =
+ __ATTR(sampling_down_factor, 0644,
+ show_sampling_down_factor, store_sampling_down_factor);
static ssize_t show_go_hispeed_load(struct kobject *kobj,
struct attribute *attr, char *buf)
@@ -723,28 +966,6 @@
static struct global_attr min_sample_time_attr = __ATTR(min_sample_time, 0644,
show_min_sample_time, store_min_sample_time);
-static ssize_t show_above_hispeed_delay(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- return sprintf(buf, "%lu\n", above_hispeed_delay_val);
-}
-
-static ssize_t store_above_hispeed_delay(struct kobject *kobj,
- struct attribute *attr,
- const char *buf, size_t count)
-{
- int ret;
- unsigned long val;
-
- ret = strict_strtoul(buf, 0, &val);
- if (ret < 0)
- return ret;
- above_hispeed_delay_val = val;
- return count;
-}
-
-define_one_global_rw(above_hispeed_delay);
-
static ssize_t show_timer_rate(struct kobject *kobj,
struct attribute *attr, char *buf)
{
@@ -862,17 +1083,114 @@
define_one_global_rw(boostpulse_duration);
+static ssize_t show_io_is_busy(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ return sprintf(buf, "%u\n", io_is_busy);
+}
+
+static ssize_t store_io_is_busy(struct kobject *kobj,
+ struct attribute *attr, const char *buf, size_t count)
+{
+ int ret;
+ unsigned long val;
+
+ ret = kstrtoul(buf, 0, &val);
+ if (ret < 0)
+ return ret;
+ io_is_busy = val;
+ return count;
+}
+
+static struct global_attr io_is_busy_attr = __ATTR(io_is_busy, 0644,
+ show_io_is_busy, store_io_is_busy);
+
+static ssize_t show_sync_freq(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ return sprintf(buf, "%u\n", sync_freq);
+}
+
+static ssize_t store_sync_freq(struct kobject *kobj,
+ struct attribute *attr, const char *buf, size_t count)
+{
+ int ret;
+ unsigned long val;
+
+ ret = kstrtoul(buf, 0, &val);
+ if (ret < 0)
+ return ret;
+ sync_freq = val;
+ return count;
+}
+
+static struct global_attr sync_freq_attr = __ATTR(sync_freq, 0644,
+ show_sync_freq, store_sync_freq);
+
+static ssize_t show_up_threshold_any_cpu_load(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%u\n", up_threshold_any_cpu_load);
+}
+
+static ssize_t store_up_threshold_any_cpu_load(struct kobject *kobj,
+ struct attribute *attr, const char *buf, size_t count)
+{
+ int ret;
+ unsigned long val;
+
+ ret = kstrtoul(buf, 0, &val);
+ if (ret < 0)
+ return ret;
+ up_threshold_any_cpu_load = val;
+ return count;
+}
+
+static struct global_attr up_threshold_any_cpu_load_attr =
+ __ATTR(up_threshold_any_cpu_load, 0644,
+ show_up_threshold_any_cpu_load,
+ store_up_threshold_any_cpu_load);
+
+static ssize_t show_up_threshold_any_cpu_freq(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%u\n", up_threshold_any_cpu_freq);
+}
+
+static ssize_t store_up_threshold_any_cpu_freq(struct kobject *kobj,
+ struct attribute *attr, const char *buf, size_t count)
+{
+ int ret;
+ unsigned long val;
+
+ ret = kstrtoul(buf, 0, &val);
+ if (ret < 0)
+ return ret;
+ up_threshold_any_cpu_freq = val;
+ return count;
+}
+
+static struct global_attr up_threshold_any_cpu_freq_attr =
+ __ATTR(up_threshold_any_cpu_freq, 0644,
+ show_up_threshold_any_cpu_freq,
+ store_up_threshold_any_cpu_freq);
+
static struct attribute *interactive_attributes[] = {
&target_loads_attr.attr,
+ &above_hispeed_delay_attr.attr,
&hispeed_freq_attr.attr,
&go_hispeed_load_attr.attr,
- &above_hispeed_delay.attr,
&min_sample_time_attr.attr,
&timer_rate_attr.attr,
&timer_slack.attr,
&boost.attr,
&boostpulse.attr,
&boostpulse_duration.attr,
+ &io_is_busy_attr.attr,
+ &sampling_down_factor_attr.attr,
+ &sync_freq_attr.attr,
+ &up_threshold_any_cpu_load_attr.attr,
+ &up_threshold_any_cpu_freq_attr.attr,
NULL,
};
@@ -922,8 +1240,6 @@
hispeed_freq = policy->max;
for_each_cpu(j, policy->cpus) {
- unsigned long expires;
-
pcpu = &per_cpu(cpuinfo, j);
pcpu->policy = policy;
pcpu->target_freq = policy->cur;
@@ -934,14 +1250,7 @@
pcpu->hispeed_validate_time =
pcpu->floor_validate_time;
down_write(&pcpu->enable_sem);
- expires = jiffies + usecs_to_jiffies(timer_rate);
- pcpu->cpu_timer.expires = expires;
- add_timer_on(&pcpu->cpu_timer, j);
- if (timer_slack_val >= 0) {
- expires += usecs_to_jiffies(timer_slack_val);
- pcpu->cpu_slack_timer.expires = expires;
- add_timer_on(&pcpu->cpu_slack_timer, j);
- }
+ cpufreq_interactive_timer_start(j);
pcpu->governor_enabled = 1;
up_write(&pcpu->enable_sem);
}
@@ -1000,6 +1309,33 @@
else if (policy->min > policy->cur)
__cpufreq_driver_target(policy,
policy->min, CPUFREQ_RELATION_L);
+ for_each_cpu(j, policy->cpus) {
+ pcpu = &per_cpu(cpuinfo, j);
+
+ /* hold write semaphore to avoid race */
+ down_write(&pcpu->enable_sem);
+ if (pcpu->governor_enabled == 0) {
+ up_write(&pcpu->enable_sem);
+ continue;
+ }
+
+ /* update target_freq firstly */
+ if (policy->max < pcpu->target_freq)
+ pcpu->target_freq = policy->max;
+ else if (policy->min > pcpu->target_freq)
+ pcpu->target_freq = policy->min;
+
+ /* Reschedule timer.
+ * Delete the timers, else the timer callback may
+ * return without re-arm the timer when failed
+ * acquire the semaphore. This race may cause timer
+ * stopped unexpectedly.
+ */
+ del_timer_sync(&pcpu->cpu_timer);
+ del_timer_sync(&pcpu->cpu_slack_timer);
+ cpufreq_interactive_timer_start(j);
+ up_write(&pcpu->enable_sem);
+ }
break;
}
return 0;
@@ -1029,6 +1365,7 @@
spin_lock_init(&target_loads_lock);
spin_lock_init(&speedchange_cpumask_lock);
+ spin_lock_init(&above_hispeed_delay_lock);
mutex_init(&gov_lock);
speedchange_task =
kthread_create(cpufreq_interactive_speedchange_task, NULL,
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index af494c6..8f7d39c 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -318,6 +318,7 @@
show_one(down_differential, down_differential);
show_one(sampling_down_factor, sampling_down_factor);
show_one(ignore_nice_load, ignore_nice);
+show_one(down_differential_multi_core, down_differential_multi_core);
show_one(optimal_freq, optimal_freq);
show_one(up_threshold_any_cpu_load, up_threshold_any_cpu_load);
show_one(sync_freq, sync_freq);
@@ -437,6 +438,20 @@
return count;
}
+static ssize_t store_down_differential_multi_core(struct kobject *a,
+ struct attribute *b, const char *buf, size_t count)
+{
+ unsigned int input;
+ int ret;
+
+ ret = sscanf(buf, "%u", &input);
+ if (ret != 1)
+ return -EINVAL;
+ dbs_tuners_ins.down_differential_multi_core = input;
+ return count;
+}
+
+
static ssize_t store_optimal_freq(struct kobject *a, struct attribute *b,
const char *buf, size_t count)
{
@@ -625,10 +640,13 @@
cpumask_set_cpu(cpu, &cpus_timer_done);
if (dbs_info->cur_policy) {
+ dbs_timer_exit(dbs_info);
/* restart dbs timer */
+ mutex_lock(&dbs_info->timer_mutex);
dbs_timer_init(dbs_info);
/* Enable frequency synchronization
* of CPUs */
+ mutex_unlock(&dbs_info->timer_mutex);
atomic_set(&dbs_info->sync_enabled, 1);
}
skip_this_cpu:
@@ -692,6 +710,7 @@
define_one_global_rw(ignore_nice_load);
define_one_global_rw(powersave_bias);
define_one_global_rw(up_threshold_multi_core);
+define_one_global_rw(down_differential_multi_core);
define_one_global_rw(optimal_freq);
define_one_global_rw(up_threshold_any_cpu_load);
define_one_global_rw(sync_freq);
@@ -707,6 +726,7 @@
&powersave_bias.attr,
&io_is_busy.attr,
&up_threshold_multi_core.attr,
+ &down_differential_multi_core.attr,
&optimal_freq.attr,
&up_threshold_any_cpu_load.attr,
&sync_freq.attr,
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index e81cfda..d048a91 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -23,6 +23,7 @@
#include "cpuidle.h"
DEFINE_PER_CPU(struct cpuidle_device *, cpuidle_devices);
+DEFINE_PER_CPU(struct cpuidle_device, cpuidle_dev);
DEFINE_MUTEX(cpuidle_lock);
LIST_HEAD(cpuidle_detected_devices);
@@ -484,6 +485,77 @@
EXPORT_SYMBOL_GPL(cpuidle_unregister_device);
+/*
+ * cpuidle_unregister: unregister a driver and the devices. This function
+ * can be used only if the driver has been previously registered through
+ * the cpuidle_register function.
+ *
+ * @drv: a valid pointer to a struct cpuidle_driver
+ */
+void cpuidle_unregister(struct cpuidle_driver *drv)
+{
+ int cpu;
+ struct cpuidle_device *device;
+
+ for_each_possible_cpu(cpu) {
+ device = &per_cpu(cpuidle_dev, cpu);
+ cpuidle_unregister_device(device);
+ }
+
+ cpuidle_unregister_driver(drv);
+}
+EXPORT_SYMBOL_GPL(cpuidle_unregister);
+
+/**
+ * cpuidle_register: registers the driver and the cpu devices with the
+ * coupled_cpus passed as parameter. This function is used for all common
+ * initialization pattern there are in the arch specific drivers. The
+ * devices is globally defined in this file.
+ *
+ * @drv : a valid pointer to a struct cpuidle_driver
+ * @coupled_cpus: a cpumask for the coupled states
+ *
+ * Returns 0 on success, < 0 otherwise
+ */
+int cpuidle_register(struct cpuidle_driver *drv,
+ const struct cpumask *const coupled_cpus)
+{
+ int ret, cpu;
+ struct cpuidle_device *device;
+
+ ret = cpuidle_register_driver(drv);
+ if (ret) {
+ pr_err("failed to register cpuidle driver\n");
+ return ret;
+ }
+
+ for_each_possible_cpu(cpu) {
+ device = &per_cpu(cpuidle_dev, cpu);
+ device->cpu = cpu;
+
+#ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED
+ /*
+ * On multiplatform for ARM, the coupled idle states could
+ * enabled in the kernel even if the cpuidle driver does not
+ * use it. Note, coupled_cpus is a struct copy.
+ */
+ if (coupled_cpus)
+ device->coupled_cpus = *coupled_cpus;
+#endif
+ ret = cpuidle_register_device(device);
+ if (!ret)
+ continue;
+
+ pr_err("Failed to register cpuidle device for cpu%d\n", cpu);
+
+ cpuidle_unregister(drv);
+ break;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cpuidle_register);
+
#ifdef CONFIG_SMP
static void smp_callback(void *v)
diff --git a/drivers/crypto/msm/qce.c b/drivers/crypto/msm/qce.c
index 7778477..8037187 100644
--- a/drivers/crypto/msm/qce.c
+++ b/drivers/crypto/msm/qce.c
@@ -1949,6 +1949,12 @@
else
q_req->cryptlen = areq->cryptlen - authsize;
+ if ((q_req->cryptlen > ULONG_MAX - ivsize) ||
+ (q_req->cryptlen + ivsize > ULONG_MAX - areq->assoclen)) {
+ pr_err("Integer overflow on total aead req length.\n");
+ return -EINVAL;
+ }
+
totallen = q_req->cryptlen + ivsize + areq->assoclen;
pad_len = ALIGN(totallen, ADM_CE_BLOCK_SIZE) - totallen;
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 4c05978..a4154c1 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -43,13 +43,17 @@
#define QCE_MAX_NUM_DSCR 0x500
#define QCE_SECTOR_SIZE 0x200
-static DEFINE_MUTEX(bam_register_cnt);
+static DEFINE_MUTEX(bam_register_lock);
struct bam_registration_info {
+ struct list_head qlist;
uint32_t handle;
uint32_t cnt;
+ uint32_t bam_mem;
+ void __iomem *bam_iobase;
+ bool support_cmd_dscr;
};
-static struct bam_registration_info bam_registry;
-static bool ce_bam_registered;
+static LIST_HEAD(qce50_bam_list);
+
/*
* CE HW device structure.
* Each engine has an instance of the structure.
@@ -58,11 +62,14 @@
*/
struct qce_device {
struct device *pdev; /* Handle to platform_device structure */
+ struct bam_registration_info *pbam;
unsigned char *coh_vmem; /* Allocated coherent virtual memory */
dma_addr_t coh_pmem; /* Allocated coherent physical memory */
int memsize; /* Memory allocated */
- int is_shared; /* CE HW is shared */
+ uint32_t bam_mem; /* bam physical address, from DT */
+ uint32_t bam_mem_size; /* bam io size, from DT */
+ int is_shared; /* CE HW is shared */
bool support_cmd_dscr;
bool support_hw_key;
@@ -2162,25 +2169,93 @@
sps_connect_info->desc.phys_base);
sps_free_endpoint(sps_pipe_info);
}
-/**
- * Initialize SPS HW connected with CE core
- *
- * This function register BAM HW resources with
- * SPS driver and then initialize 2 SPS endpoints
- *
- * This function should only be called once typically
- * during driver probe.
- *
- * @pce_dev - Pointer to qce_device structure
- *
- * @return - 0 if successful else negative value.
- *
- */
-static int qce_sps_init(struct qce_device *pce_dev)
+
+static void qce_sps_release_bam(struct qce_device *pce_dev)
+{
+ struct bam_registration_info *pbam;
+
+ mutex_lock(&bam_register_lock);
+ pbam = pce_dev->pbam;
+ if (pbam == NULL)
+ goto ret;
+
+ pbam->cnt--;
+ if (pbam->cnt > 0)
+ goto ret;
+
+ if (pce_dev->ce_sps.bam_handle) {
+ sps_deregister_bam_device(pce_dev->ce_sps.bam_handle);
+
+ pr_debug("deregister bam handle %x\n",
+ pce_dev->ce_sps.bam_handle);
+ pce_dev->ce_sps.bam_handle = 0;
+ }
+ iounmap(pbam->bam_iobase);
+ pr_debug("delete bam 0x%x\n", pbam->bam_mem);
+ list_del(&pbam->qlist);
+ kfree(pbam);
+
+ pce_dev->pbam = NULL;
+ret:
+ mutex_unlock(&bam_register_lock);
+}
+
+static int qce_sps_get_bam(struct qce_device *pce_dev)
{
int rc = 0;
struct sps_bam_props bam = {0};
- bool register_bam = false;
+ struct bam_registration_info *pbam = NULL;
+ struct bam_registration_info *p;
+ uint32_t bam_cfg = 0 ;
+
+
+ mutex_lock(&bam_register_lock);
+
+ list_for_each_entry(p, &qce50_bam_list, qlist) {
+ if (p->bam_mem == pce_dev->bam_mem) {
+ pbam = p; /* found */
+ break;
+ }
+ }
+
+ if (pbam) {
+ pr_debug("found bam 0x%x\n", pbam->bam_mem);
+ pbam->cnt++;
+ pce_dev->ce_sps.bam_handle = pbam->handle;
+ pce_dev->ce_sps.bam_mem = pbam->bam_mem;
+ pce_dev->ce_sps.bam_iobase = pbam->bam_iobase;
+ pce_dev->pbam = pbam;
+ pce_dev->support_cmd_dscr = pbam->support_cmd_dscr;
+ goto ret;
+ }
+
+ pbam = kzalloc(sizeof(struct bam_registration_info), GFP_KERNEL);
+ if (!pbam) {
+ pr_err("qce50 Memory allocation of bam FAIL, error %ld\n",
+ PTR_ERR(pbam));
+
+ rc = -ENOMEM;
+ goto ret;
+ }
+ pbam->cnt = 1;
+ pbam->bam_mem = pce_dev->bam_mem;
+ pbam->bam_iobase = ioremap_nocache(pce_dev->bam_mem,
+ pce_dev->bam_mem_size);
+ if (!pbam->bam_iobase) {
+ kfree(pbam);
+ rc = -ENOMEM;
+ pr_err("Can not map BAM io memory\n");
+ goto ret;
+ }
+ pce_dev->ce_sps.bam_mem = pbam->bam_mem;
+ pce_dev->ce_sps.bam_iobase = pbam->bam_iobase;
+ pbam->handle = 0;
+ pr_debug("allocate bam 0x%x\n", pbam->bam_mem);
+ bam_cfg = readl_relaxed(pce_dev->ce_sps.bam_iobase +
+ CRYPTO_BAM_CNFG_BITS_REG);
+ pbam->support_cmd_dscr = (bam_cfg & CRYPTO_BAM_CD_ENABLE_MASK) ?
+ true : false;
+ pce_dev->support_cmd_dscr = pbam->support_cmd_dscr;
bam.phys_addr = pce_dev->ce_sps.bam_mem;
bam.virt_addr = pce_dev->ce_sps.bam_iobase;
@@ -2212,27 +2287,46 @@
pr_debug("bam physical base=0x%x\n", (u32)bam.phys_addr);
pr_debug("bam virtual base=0x%x\n", (u32)bam.virt_addr);
- mutex_lock(&bam_register_cnt);
- if (ce_bam_registered == false) {
- bam_registry.handle = 0;
- bam_registry.cnt = 0;
+ /* Register CE Peripheral BAM device to SPS driver */
+ rc = sps_register_bam_device(&bam, &pbam->handle);
+ if (rc) {
+ pr_err("sps_register_bam_device() failed! err=%d", rc);
+ rc = -EIO;
+ iounmap(pbam->bam_iobase);
+ kfree(pbam);
+ goto ret;
}
- if ((bam_registry.handle == 0) && (bam_registry.cnt == 0)) {
- /* Register CE Peripheral BAM device to SPS driver */
- rc = sps_register_bam_device(&bam, &bam_registry.handle);
- if (rc) {
- mutex_unlock(&bam_register_cnt);
- pr_err("sps_register_bam_device() failed! err=%d", rc);
- return -EIO;
- }
- bam_registry.cnt++;
- register_bam = true;
- ce_bam_registered = true;
- } else {
- bam_registry.cnt++;
- }
- mutex_unlock(&bam_register_cnt);
- pce_dev->ce_sps.bam_handle = bam_registry.handle;
+
+ pce_dev->pbam = pbam;
+ list_add_tail(&pbam->qlist, &qce50_bam_list);
+ pce_dev->ce_sps.bam_handle = pbam->handle;
+
+ret:
+ mutex_unlock(&bam_register_lock);
+
+ return rc;
+}
+/**
+ * Initialize SPS HW connected with CE core
+ *
+ * This function register BAM HW resources with
+ * SPS driver and then initialize 2 SPS endpoints
+ *
+ * This function should only be called once typically
+ * during driver probe.
+ *
+ * @pce_dev - Pointer to qce_device structure
+ *
+ * @return - 0 if successful else negative value.
+ *
+ */
+static int qce_sps_init(struct qce_device *pce_dev)
+{
+ int rc = 0;
+
+ rc = qce_sps_get_bam(pce_dev);
+ if (rc)
+ return rc;
pr_debug("BAM device registered. bam_handle=0x%x",
pce_dev->ce_sps.bam_handle);
@@ -2253,14 +2347,7 @@
sps_connect_consumer_err:
qce_sps_exit_ep_conn(pce_dev, &pce_dev->ce_sps.producer);
sps_connect_producer_err:
- if (register_bam) {
- mutex_lock(&bam_register_cnt);
- sps_deregister_bam_device(pce_dev->ce_sps.bam_handle);
- ce_bam_registered = false;
- bam_registry.handle = 0;
- bam_registry.cnt = 0;
- mutex_unlock(&bam_register_cnt);
- }
+ qce_sps_release_bam(pce_dev);
return rc;
}
@@ -2280,17 +2367,7 @@
{
qce_sps_exit_ep_conn(pce_dev, &pce_dev->ce_sps.consumer);
qce_sps_exit_ep_conn(pce_dev, &pce_dev->ce_sps.producer);
- mutex_lock(&bam_register_cnt);
- if ((bam_registry.handle != 0) && (bam_registry.cnt == 1)) {
- sps_deregister_bam_device(pce_dev->ce_sps.bam_handle);
- bam_registry.cnt = 0;
- bam_registry.handle = 0;
- }
- if ((bam_registry.handle != 0) && (bam_registry.cnt > 1))
- bam_registry.cnt--;
- mutex_unlock(&bam_register_cnt);
-
- iounmap(pce_dev->ce_sps.bam_iobase);
+ qce_sps_release_bam(pce_dev);
}
static void _aead_sps_producer_callback(struct sps_event_notify *notify)
@@ -4069,22 +4146,15 @@
resource = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"crypto-bam-base");
if (resource) {
- pce_dev->ce_sps.bam_mem = resource->start;
- pce_dev->ce_sps.bam_iobase = ioremap_nocache(resource->start,
- resource_size(resource));
- if (!pce_dev->ce_sps.bam_iobase) {
- rc = -ENOMEM;
- pr_err("Can not map BAM io memory\n");
- goto err_getting_bam_info;
- }
+ pce_dev->bam_mem = resource->start;
+ pce_dev->bam_mem_size = resource_size(resource);
} else {
pr_err("CRYPTO BAM mem unavailable.\n");
rc = -ENODEV;
goto err_getting_bam_info;
}
- pr_warn("ce_bam_phy_reg_base=0x%x ", pce_dev->ce_sps.bam_mem);
- pr_warn("ce_bam_virt_reg_base=0x%x\n",
- (uint32_t)pce_dev->ce_sps.bam_iobase);
+ pr_warn("ce_bam_phy_reg_base=0x%x ", pce_dev->bam_mem);
+
resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (resource) {
pce_dev->ce_sps.bam_irq = resource->start;
@@ -4250,7 +4320,6 @@
void *qce_open(struct platform_device *pdev, int *rc)
{
struct qce_device *pce_dev;
- uint32_t bam_cfg = 0 ;
pce_dev = kzalloc(sizeof(struct qce_device), GFP_KERNEL);
if (!pce_dev) {
@@ -4293,15 +4362,9 @@
}
*rc = 0;
- bam_cfg = readl_relaxed(pce_dev->ce_sps.bam_iobase +
- CRYPTO_BAM_CNFG_BITS_REG);
- pce_dev->support_cmd_dscr = (bam_cfg & CRYPTO_BAM_CD_ENABLE_MASK) ?
- true : false;
qce_init_ce_cfg_val(pce_dev);
- qce_setup_ce_sps_data(pce_dev);
qce_sps_init(pce_dev);
-
-
+ qce_setup_ce_sps_data(pce_dev);
qce_disable_clk(pce_dev);
return pce_dev;
@@ -4313,8 +4376,6 @@
dma_free_coherent(pce_dev->pdev, pce_dev->memsize,
pce_dev->coh_vmem, pce_dev->coh_pmem);
err_iobase:
- if (pce_dev->ce_sps.bam_iobase)
- iounmap(pce_dev->ce_sps.bam_iobase);
if (pce_dev->iobase)
iounmap(pce_dev->iobase);
err_pce_dev:
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index 81a90fe..4845f11 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -1339,7 +1339,7 @@
areq->cipher_op_req.vbuf.src[0].len))
return -EFAULT;
- k_align_src += areq->cipher_op_req.vbuf.src[0].len;
+ k_align_src += byteoffset + areq->cipher_op_req.vbuf.src[0].len;
for (i = 1; i < areq->cipher_op_req.entries; i++) {
user_src =
@@ -1602,11 +1602,6 @@
static int qcedev_check_cipher_key(struct qcedev_cipher_op_req *req,
struct qcedev_control *podev)
{
-
- if (req->encklen < 0) {
- pr_err("%s: Invalid key size: %d\n", __func__, req->encklen);
- return -EINVAL;
- }
/* if intending to use HW key make sure key fields are set
* correctly and HW key is indeed supported in target
*/
@@ -1701,6 +1696,13 @@
goto error;
}
}
+
+ if (req->data_len < req->byteoffset) {
+ pr_err("%s: req data length %u is less than byteoffset %u\n",
+ __func__, req->data_len, req->byteoffset);
+ goto error;
+ }
+
/* Ensure zer ivlen for ECB mode */
if (req->ivlen > 0) {
if ((req->mode == QCEDEV_AES_MODE_ECB) ||
@@ -1716,16 +1718,28 @@
}
}
/* Check for sum of all dst length is equal to data_len */
- for (i = 0; (i < QCEDEV_MAX_BUFFERS) && (total < req->data_len); i++)
+ for (i = 0; (i < QCEDEV_MAX_BUFFERS) && (total < req->data_len); i++) {
+ if (req->vbuf.dst[i].len > ULONG_MAX - total) {
+ pr_err("%s: Integer overflow on total req dst vbuf length\n",
+ __func__);
+ goto error;
+ }
total += req->vbuf.dst[i].len;
+ }
if (total != req->data_len) {
pr_err("%s: Total (i=%d) dst(%d) buf size != data_len (%d)\n",
__func__, i, total, req->data_len);
goto error;
}
/* Check for sum of all src length is equal to data_len */
- for (i = 0, total = 0; i < req->entries; i++)
+ for (i = 0, total = 0; i < req->entries; i++) {
+ if (req->vbuf.src[i].len > ULONG_MAX - total) {
+ pr_err("%s: Integer overflow on total req src vbuf length\n",
+ __func__);
+ goto error;
+ }
total += req->vbuf.src[i].len;
+ }
if (total != req->data_len) {
pr_err("%s: Total src(%d) buf size != data_len (%d)\n",
__func__, total, req->data_len);
@@ -1781,8 +1795,15 @@
}
/* Check for sum of all src length is equal to data_len */
- for (i = 0, total = 0; i < req->entries; i++)
+ for (i = 0, total = 0; i < req->entries; i++) {
+ if (req->data[i].len > ULONG_MAX - total) {
+ pr_err("%s: Integer overflow on total req buf length\n",
+ __func__);
+ goto sha_error;
+ }
total += req->data[i].len;
+ }
+
if (total != req->data_len) {
pr_err("%s: Total src(%d) buf size != data_len (%d)\n",
__func__, total, req->data_len);
@@ -2112,21 +2133,21 @@
int len = 0;
pstat = &_qcedev_stat;
- len = snprintf(_debug_read_buf, DEBUG_MAX_RW_BUF - 1,
+ len = scnprintf(_debug_read_buf, DEBUG_MAX_RW_BUF - 1,
"\nQualcomm QCE dev driver %d Statistics:\n",
id + 1);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" Encryption operation success : %d\n",
pstat->qcedev_enc_success);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" Encryption operation fail : %d\n",
pstat->qcedev_enc_fail);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" Decryption operation success : %d\n",
pstat->qcedev_dec_success);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" Encryption operation fail : %d\n",
pstat->qcedev_dec_fail);
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index ae57d6c..6606706 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -409,7 +409,7 @@
{
int i;
- for (i = 0; nbytes > 0; i++, sg = scatterwalk_sg_next(sg))
+ for (i = 0; nbytes > 0 && sg != NULL; i++, sg = scatterwalk_sg_next(sg))
nbytes -= sg->length;
return i;
@@ -628,98 +628,98 @@
int len = 0;
pstat = &_qcrypto_stat;
- len = snprintf(_debug_read_buf, DEBUG_MAX_RW_BUF - 1,
+ len = scnprintf(_debug_read_buf, DEBUG_MAX_RW_BUF - 1,
"\nQualcomm crypto accelerator %d Statistics:\n",
id + 1);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" ABLK AES CIPHER encryption : %d\n",
pstat->ablk_cipher_aes_enc);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" ABLK AES CIPHER decryption : %d\n",
pstat->ablk_cipher_aes_dec);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" ABLK DES CIPHER encryption : %d\n",
pstat->ablk_cipher_des_enc);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" ABLK DES CIPHER decryption : %d\n",
pstat->ablk_cipher_des_dec);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" ABLK 3DES CIPHER encryption : %d\n",
pstat->ablk_cipher_3des_enc);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" ABLK 3DES CIPHER decryption : %d\n",
pstat->ablk_cipher_3des_dec);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" ABLK CIPHER operation success: %d\n",
pstat->ablk_cipher_op_success);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" ABLK CIPHER operation fail : %d\n",
pstat->ablk_cipher_op_fail);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" AEAD SHA1-AES encryption : %d\n",
pstat->aead_sha1_aes_enc);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" AEAD SHA1-AES decryption : %d\n",
pstat->aead_sha1_aes_dec);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" AEAD SHA1-DES encryption : %d\n",
pstat->aead_sha1_des_enc);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" AEAD SHA1-DES decryption : %d\n",
pstat->aead_sha1_des_dec);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" AEAD SHA1-3DES encryption : %d\n",
pstat->aead_sha1_3des_enc);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" AEAD SHA1-3DES decryption : %d\n",
pstat->aead_sha1_3des_dec);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" AEAD CCM-AES encryption : %d\n",
pstat->aead_ccm_aes_enc);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" AEAD CCM-AES decryption : %d\n",
pstat->aead_ccm_aes_dec);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" AEAD operation success : %d\n",
pstat->aead_op_success);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" AEAD operation fail : %d\n",
pstat->aead_op_fail);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" AEAD bad message : %d\n",
pstat->aead_bad_msg);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" SHA1 digest : %d\n",
pstat->sha1_digest);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" SHA256 digest : %d\n",
pstat->sha256_digest);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" SHA operation fail : %d\n",
pstat->sha_op_fail);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" SHA operation success : %d\n",
pstat->sha_op_success);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" SHA1 HMAC digest : %d\n",
pstat->sha1_hmac_digest);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" SHA256 HMAC digest : %d\n",
pstat->sha256_hmac_digest);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" SHA HMAC operation fail : %d\n",
pstat->sha_hmac_op_fail);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" SHA HMAC operation success : %d\n",
pstat->sha_hmac_op_success);
return len;
@@ -1423,8 +1423,20 @@
rctx->orig_src = req->src;
rctx->orig_dst = req->dst;
+
+ if ((MAX_ALIGN_SIZE*2 > ULONG_MAX - req->assoclen) ||
+ ((MAX_ALIGN_SIZE*2 + req->assoclen) >
+ ULONG_MAX - qreq.authsize) ||
+ ((MAX_ALIGN_SIZE*2 + req->assoclen +
+ qreq.authsize) >
+ ULONG_MAX - req->cryptlen)) {
+ pr_err("Integer overflow on aead req length.\n");
+ return -EINVAL;
+ }
+
rctx->data = kzalloc((req->cryptlen + qreq.assoclen +
- qreq.authsize + 64*2), GFP_ATOMIC);
+ qreq.authsize + MAX_ALIGN_SIZE*2),
+ GFP_ATOMIC);
if (rctx->data == NULL) {
pr_err("Mem Alloc fail rctx->data, err %ld\n",
PTR_ERR(rctx->data));
@@ -1486,6 +1498,16 @@
* include assoicated data, ciphering data stream,
* generated MAC, and CCM padding.
*/
+ if ((MAX_ALIGN_SIZE * 2 > ULONG_MAX - req->assoclen) ||
+ ((MAX_ALIGN_SIZE * 2 + req->assoclen) >
+ ULONG_MAX - qreq.ivsize) ||
+ ((MAX_ALIGN_SIZE * 2 + req->assoclen
+ + qreq.ivsize)
+ > ULONG_MAX - req->cryptlen)) {
+ pr_err("Integer overflow on aead req length.\n");
+ return -EINVAL;
+ }
+
rctx->data = kzalloc(
(req->cryptlen +
req->assoclen +
diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig
index 1c63b70..ca7953d 100644
--- a/drivers/devfreq/Kconfig
+++ b/drivers/devfreq/Kconfig
@@ -63,6 +63,33 @@
Otherwise, the governor does not change the frequnecy
given at the initialization.
+config DEVFREQ_GOV_MSM_ADRENO_TZ
+ tristate "MSM Adreno Trustzone"
+ depends on MSM_KGSL && MSM_SCM
+ help
+ Trustzone based governor for the Adreno GPU.
+ Sets the frequency using a "on-demand" algorithm.
+ This governor is unlikely to be useful for other devices.
+
+config DEVFREQ_GOV_MSM_CPUFREQ
+ bool "MSM CPUfreq"
+ depends on CPU_FREQ_MSM
+ help
+ MSM CPUfreq based governor for CPU bandwidth voting. Sets the CPU
+ to DDR BW vote based on the current CPU frequency. This governor
+ is unlikely to be useful for non-MSM devices.
+
+config DEVFREQ_GOV_MSM_CPUBW_HWMON
+ tristate "HW monitor based governor for CPUBW"
+ depends on ARCH_MSM_KRAIT
+ help
+ HW monitor based governor for CPU to DDR bandwidth voting. This
+ goveror currently supports only Krait L2 PM counters. Sets the CPU
+ BW vote by using L2 PM counters to monitor the Krait's use of DDR.
+ Since this governor uses some of the PM counters it can conflict
+ with existing profiling tools. This governor is unlikely to be
+ useful for other devices.
+
comment "DEVFREQ Drivers"
config ARM_EXYNOS4_BUS_DEVFREQ
diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile
index 8c46423..e06ed9f 100644
--- a/drivers/devfreq/Makefile
+++ b/drivers/devfreq/Makefile
@@ -3,6 +3,9 @@
obj-$(CONFIG_DEVFREQ_GOV_PERFORMANCE) += governor_performance.o
obj-$(CONFIG_DEVFREQ_GOV_POWERSAVE) += governor_powersave.o
obj-$(CONFIG_DEVFREQ_GOV_USERSPACE) += governor_userspace.o
+obj-$(CONFIG_DEVFREQ_GOV_MSM_ADRENO_TZ) += governor_msm_adreno_tz.o
+obj-$(CONFIG_DEVFREQ_GOV_MSM_CPUFREQ) += governor_msm_cpufreq.o
+obj-$(CONFIG_DEVFREQ_GOV_MSM_CPUBW_HWMON) += governor_cpubw_hwmon.o
# DEVFREQ Drivers
obj-$(CONFIG_ARM_EXYNOS4_BUS_DEVFREQ) += exynos4_bus.o
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index dadf87c..9e49b3e 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -187,7 +187,7 @@
return -EINVAL;
/* Reevaluate the proper frequency */
- err = devfreq->governor->get_target_freq(devfreq, &freq);
+ err = devfreq->governor->get_target_freq(devfreq, &freq, &flags);
if (err)
return err;
@@ -459,7 +459,7 @@
return NULL;
for (i = 0; i < profile->num_governor_data; i++) {
- if (!strncmp(governor_name, profile->governor_data[i].name,
+ if (strncmp(governor_name, profile->governor_data[i].name,
DEVFREQ_NAME_LEN) == 0) {
data = profile->governor_data[i].data;
break;
diff --git a/drivers/devfreq/governor_cpubw_hwmon.c b/drivers/devfreq/governor_cpubw_hwmon.c
new file mode 100644
index 0000000..fb5a562
--- /dev/null
+++ b/drivers/devfreq/governor_cpubw_hwmon.c
@@ -0,0 +1,461 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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) "cpubw-hwmon: " fmt
+
+#include <linux/kernel.h>
+#include <asm/sizes.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/ktime.h>
+#include <linux/time.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/devfreq.h>
+#include "governor.h"
+
+#include <mach/msm-krait-l2-accessors.h>
+
+#define L2PMRESR2 0x412
+#define L2PMCR 0x400
+#define L2PMCNTENCLR 0x402
+#define L2PMCNTENSET 0x403
+#define L2PMINTENCLR 0x404
+#define L2PMINTENSET 0x405
+#define L2PMOVSR 0x406
+#define L2PMOVSSET 0x407
+#define L2PMnEVCNTCR(n) (0x420 + n * 0x10)
+#define L2PMnEVCNTR(n) (0x421 + n * 0x10)
+#define L2PMnEVCNTSR(n) (0x422 + n * 0x10)
+#define L2PMnEVFILTER(n) (0x423 + n * 0x10)
+#define L2PMnEVTYPER(n) (0x424 + n * 0x10)
+
+#define show_attr(name) \
+static ssize_t show_##name(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+{ \
+ return sprintf(buf, "%u\n", name); \
+}
+
+#define store_attr(name, _min, _max) \
+static ssize_t store_##name(struct device *dev, \
+ struct device_attribute *attr, const char *buf, \
+ size_t count) \
+{ \
+ int ret; \
+ unsigned int val; \
+ ret = sscanf(buf, "%u", &val); \
+ if (ret != 1) \
+ return -EINVAL; \
+ val = max(val, _min); \
+ val = min(val, _max); \
+ name = val; \
+ return count; \
+}
+
+#define gov_attr(__attr, min, max) \
+show_attr(__attr) \
+store_attr(__attr, min, max) \
+static DEVICE_ATTR(__attr, 0644, show_##__attr, store_##__attr)
+
+
+static int l2pm_irq;
+static unsigned int bytes_per_beat;
+static unsigned int sample_ms = 50;
+static unsigned int tolerance_percent = 10;
+static unsigned int guard_band_mbps = 100;
+static unsigned int decay_rate = 90;
+static unsigned int io_percent = 15;
+static unsigned int bw_step = 200;
+
+static u32 prev_r_start_val;
+static u32 prev_w_start_val;
+static unsigned long prev_ab;
+static ktime_t prev_ts;
+
+#define RD_MON 0
+#define WR_MON 1
+static void mon_init(void)
+{
+ /* Set up counters 0/1 to count write/read beats */
+ set_l2_indirect_reg(L2PMRESR2, 0x8B0B0000);
+ set_l2_indirect_reg(L2PMnEVCNTCR(RD_MON), 0x0);
+ set_l2_indirect_reg(L2PMnEVCNTCR(WR_MON), 0x0);
+ set_l2_indirect_reg(L2PMnEVCNTR(RD_MON), 0xFFFFFFFF);
+ set_l2_indirect_reg(L2PMnEVCNTR(WR_MON), 0xFFFFFFFF);
+ set_l2_indirect_reg(L2PMnEVFILTER(RD_MON), 0xF003F);
+ set_l2_indirect_reg(L2PMnEVFILTER(WR_MON), 0xF003F);
+ set_l2_indirect_reg(L2PMnEVTYPER(RD_MON), 0xA);
+ set_l2_indirect_reg(L2PMnEVTYPER(WR_MON), 0xB);
+}
+
+static void global_mon_enable(bool en)
+{
+ u32 regval;
+
+ /* Global counter enable */
+ regval = get_l2_indirect_reg(L2PMCR);
+ if (en)
+ regval |= BIT(0);
+ else
+ regval &= ~BIT(0);
+ set_l2_indirect_reg(L2PMCR, regval);
+}
+
+static void mon_enable(int n)
+{
+ /* Clear previous overflow state for event counter n */
+ set_l2_indirect_reg(L2PMOVSR, BIT(n));
+
+ /* Enable event counter n */
+ set_l2_indirect_reg(L2PMCNTENSET, BIT(n));
+}
+
+static void mon_disable(int n)
+{
+ /* Disable event counter n */
+ set_l2_indirect_reg(L2PMCNTENCLR, BIT(n));
+}
+
+static void mon_irq_enable(int n, bool en)
+{
+ if (en)
+ set_l2_indirect_reg(L2PMINTENSET, BIT(n));
+ else
+ set_l2_indirect_reg(L2PMINTENCLR, BIT(n));
+}
+
+/* Returns start counter value to be used with mon_get_mbps() */
+static u32 mon_set_limit_mbyte(int n, unsigned int mbytes)
+{
+ u32 regval, beats;
+
+ beats = mult_frac(mbytes, SZ_1M, bytes_per_beat);
+ regval = 0xFFFFFFFF - beats;
+ set_l2_indirect_reg(L2PMnEVCNTR(n), regval);
+ pr_debug("EV%d MB: %d, start val: %x\n", n, mbytes, regval);
+
+ return regval;
+}
+
+long mon_get_count(int n, u32 start_val)
+{
+ u32 overflow, count;
+
+ count = get_l2_indirect_reg(L2PMnEVCNTR(n));
+ overflow = get_l2_indirect_reg(L2PMOVSR);
+
+ pr_debug("EV%d ov: %x, cnt: %x\n", n, overflow, count);
+
+ if (overflow & BIT(n))
+ return 0xFFFFFFFF - start_val + count;
+ else
+ return count - start_val;
+}
+
+/* Returns MBps of read/writes for the sampling window. */
+unsigned int beats_to_mbps(long long beats, unsigned int us)
+{
+ beats *= USEC_PER_SEC;
+ beats *= bytes_per_beat;
+ do_div(beats, us);
+ beats = DIV_ROUND_UP_ULL(beats, SZ_1M);
+
+ return beats;
+}
+
+static int to_limit(int mbps)
+{
+ mbps *= (100 + tolerance_percent) * sample_ms;
+ mbps /= 100;
+ mbps = DIV_ROUND_UP(mbps, MSEC_PER_SEC);
+ return mbps;
+}
+
+unsigned long measure_bw_and_set_irq(void)
+{
+ long r_mbps, w_mbps, mbps;
+ ktime_t ts;
+ unsigned int us;
+
+ /*
+ * Since we are stopping the counters, we don't want this short work
+ * to be interrupted by other tasks and cause the measurements to be
+ * wrong. Not blocking interrupts to avoid affecting interrupt
+ * latency and since they should be short anyway because they run in
+ * atomic context.
+ */
+ preempt_disable();
+
+ ts = ktime_get();
+ us = ktime_to_us(ktime_sub(ts, prev_ts));
+ if (!us)
+ us = 1;
+
+ mon_disable(RD_MON);
+ mon_disable(WR_MON);
+
+ r_mbps = mon_get_count(RD_MON, prev_r_start_val);
+ r_mbps = beats_to_mbps(r_mbps, us);
+ w_mbps = mon_get_count(WR_MON, prev_w_start_val);
+ w_mbps = beats_to_mbps(w_mbps, us);
+
+ prev_r_start_val = mon_set_limit_mbyte(RD_MON, to_limit(r_mbps));
+ prev_w_start_val = mon_set_limit_mbyte(WR_MON, to_limit(w_mbps));
+ prev_ts = ts;
+
+ mon_enable(RD_MON);
+ mon_enable(WR_MON);
+
+ preempt_enable();
+
+ mbps = r_mbps + w_mbps;
+ pr_debug("R/W/BW/us = %ld/%ld/%ld/%d\n", r_mbps, w_mbps, mbps, us);
+
+ return mbps;
+}
+
+static void compute_bw(int mbps, unsigned long *freq, unsigned long *ab)
+{
+ int new_bw;
+
+ mbps += guard_band_mbps;
+
+ if (mbps > prev_ab) {
+ new_bw = mbps;
+ } else {
+ new_bw = mbps * decay_rate + prev_ab * (100 - decay_rate);
+ new_bw /= 100;
+ }
+
+ *ab = roundup(mbps, bw_step);
+ *freq = roundup((mbps * 100) / io_percent, bw_step);
+}
+
+#define TOO_SOON_US (1 * USEC_PER_MSEC)
+static irqreturn_t mon_intr_handler(int irq, void *dev)
+{
+ struct devfreq *df = dev;
+ ktime_t ts;
+ unsigned int us;
+ u32 regval;
+ int ret;
+
+ regval = get_l2_indirect_reg(L2PMOVSR);
+ pr_debug("Got interrupt: %x\n", regval);
+
+ devfreq_monitor_stop(df);
+
+ /*
+ * Don't recalc bandwidth if the interrupt comes right after a
+ * previous bandwidth calculation. This is done for two reasons:
+ *
+ * 1. Sampling the BW during a very short duration can result in a
+ * very inaccurate measurement due to very short bursts.
+ * 2. This can only happen if the limit was hit very close to the end
+ * of the previous sample period. Which means the current BW
+ * estimate is not very off and doesn't need to be readjusted.
+ */
+ ts = ktime_get();
+ us = ktime_to_us(ktime_sub(ts, prev_ts));
+ if (us > TOO_SOON_US) {
+ mutex_lock(&df->lock);
+ ret = update_devfreq(df);
+ if (ret)
+ pr_err("Unable to update freq on IRQ!\n");
+ mutex_unlock(&df->lock);
+ }
+
+ devfreq_monitor_start(df);
+
+ return IRQ_HANDLED;
+}
+
+static int start_monitoring(struct devfreq *df)
+{
+ int ret, mbyte;
+
+ ret = request_threaded_irq(l2pm_irq, NULL, mon_intr_handler,
+ IRQF_ONESHOT | IRQF_SHARED,
+ "cpubw_hwmon", df);
+ if (ret) {
+ pr_err("Unable to register interrupt handler\n");
+ return ret;
+ }
+
+ mon_init();
+ mon_disable(RD_MON);
+ mon_disable(WR_MON);
+
+ mbyte = (df->previous_freq * io_percent) / (2 * 100);
+ prev_r_start_val = mon_set_limit_mbyte(RD_MON, mbyte);
+ prev_w_start_val = mon_set_limit_mbyte(WR_MON, mbyte);
+ prev_ts = ktime_get();
+ prev_ab = 0;
+
+ mon_irq_enable(RD_MON, true);
+ mon_irq_enable(WR_MON, true);
+ mon_enable(RD_MON);
+ mon_enable(WR_MON);
+ global_mon_enable(true);
+
+ return 0;
+}
+
+static void stop_monitoring(struct devfreq *df)
+{
+ global_mon_enable(false);
+ mon_disable(RD_MON);
+ mon_disable(WR_MON);
+ mon_irq_enable(RD_MON, false);
+ mon_irq_enable(WR_MON, false);
+
+ disable_irq(l2pm_irq);
+ free_irq(l2pm_irq, df);
+}
+
+static int devfreq_cpubw_hwmon_get_freq(struct devfreq *df,
+ unsigned long *freq,
+ u32 *flag)
+{
+ unsigned long mbps;
+
+ mbps = measure_bw_and_set_irq();
+ compute_bw(mbps, freq, df->data);
+ prev_ab = *(unsigned long *) df->data;
+
+ return 0;
+}
+
+gov_attr(sample_ms, 10U, 500U);
+gov_attr(tolerance_percent, 0U, 30U);
+gov_attr(guard_band_mbps, 0U, 2000U);
+gov_attr(decay_rate, 0U, 100U);
+gov_attr(io_percent, 1U, 100U);
+gov_attr(bw_step, 50U, 1000U);
+
+static struct attribute *dev_attr[] = {
+ &dev_attr_sample_ms.attr,
+ &dev_attr_tolerance_percent.attr,
+ &dev_attr_guard_band_mbps.attr,
+ &dev_attr_decay_rate.attr,
+ &dev_attr_io_percent.attr,
+ &dev_attr_bw_step.attr,
+ NULL,
+};
+
+static struct attribute_group dev_attr_group = {
+ .name = "cpubw_hwmon",
+ .attrs = dev_attr,
+};
+
+static int devfreq_cpubw_hwmon_ev_handler(struct devfreq *df,
+ unsigned int event, void *data)
+{
+ int ret;
+
+ switch (event) {
+ case DEVFREQ_GOV_START:
+ ret = start_monitoring(df);
+ if (ret)
+ return ret;
+ ret = sysfs_create_group(&df->dev.kobj, &dev_attr_group);
+ if (ret)
+ return ret;
+ devfreq_monitor_start(df);
+ pr_debug("Enabled CPU BW HW monitor governor\n");
+ break;
+
+ case DEVFREQ_GOV_STOP:
+ sysfs_remove_group(&df->dev.kobj, &dev_attr_group);
+ devfreq_monitor_stop(df);
+ *(unsigned long *)df->data = 0;
+ stop_monitoring(df);
+ pr_debug("Disabled CPU BW HW monitor governor\n");
+ break;
+
+ case DEVFREQ_GOV_INTERVAL:
+ devfreq_interval_update(df, (unsigned int *)data);
+ break;
+ }
+
+ return 0;
+}
+
+static struct devfreq_governor devfreq_cpubw_hwmon = {
+ .name = "cpubw_hwmon",
+ .get_target_freq = devfreq_cpubw_hwmon_get_freq,
+ .event_handler = devfreq_cpubw_hwmon_ev_handler,
+};
+
+static int cpubw_hwmon_driver_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ int ret;
+
+ l2pm_irq = platform_get_irq(pdev, 0);
+ if (l2pm_irq < 0) {
+ pr_err("Unable to get IRQ number\n");
+ return l2pm_irq;
+ }
+
+ ret = of_property_read_u32(dev->of_node, "qcom,bytes-per-beat",
+ &bytes_per_beat);
+ if (ret) {
+ pr_err("Unable to read bytes per beat\n");
+ return ret;
+ }
+
+ ret = devfreq_add_governor(&devfreq_cpubw_hwmon);
+ if (ret) {
+ pr_err("devfreq governor registration failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct of_device_id match_table[] = {
+ { .compatible = "qcom,kraitbw-l2pm" },
+ {}
+};
+
+static struct platform_driver cpubw_hwmon_driver = {
+ .probe = cpubw_hwmon_driver_probe,
+ .driver = {
+ .name = "kraitbw-l2pm",
+ .of_match_table = match_table,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init cpubw_hwmon_init(void)
+{
+ return platform_driver_register(&cpubw_hwmon_driver);
+}
+module_init(cpubw_hwmon_init);
+
+static void __exit cpubw_hwmon_exit(void)
+{
+ platform_driver_unregister(&cpubw_hwmon_driver);
+}
+module_exit(cpubw_hwmon_exit);
+
+MODULE_DESCRIPTION("HW monitor based CPU DDR bandwidth voting driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/devfreq/governor_msm_adreno_tz.c b/drivers/devfreq/governor_msm_adreno_tz.c
new file mode 100644
index 0000000..8c97fe9
--- /dev/null
+++ b/drivers/devfreq/governor_msm_adreno_tz.c
@@ -0,0 +1,361 @@
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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/errno.h>
+#include <linux/module.h>
+#include <linux/devfreq.h>
+#include <linux/math64.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/ftrace.h>
+#include <linux/msm_adreno_devfreq.h>
+#include <mach/scm.h>
+#include "governor.h"
+
+static DEFINE_SPINLOCK(tz_lock);
+
+/*
+ * FLOOR is 5msec to capture up to 3 re-draws
+ * per frame for 60fps content.
+ */
+#define FLOOR 5000
+#define LONG_FLOOR 50000
+#define HIST 5
+#define TARGET 80
+#define CAP 75
+
+/*
+ * CEILING is 50msec, larger than any standard
+ * frame length, but less than the idle timer.
+ */
+#define CEILING 50000
+#define TZ_RESET_ID 0x3
+#define TZ_UPDATE_ID 0x4
+#define TZ_INIT_ID 0x6
+
+#define TAG "msm_adreno_tz: "
+
+/* Trap into the TrustZone, and call funcs there. */
+static int __secure_tz_entry2(u32 cmd, u32 val1, u32 val2)
+{
+ int ret;
+ spin_lock(&tz_lock);
+ /* sync memory before sending the commands to tz*/
+ __iowmb();
+ ret = scm_call_atomic2(SCM_SVC_IO, cmd, val1, val2);
+ spin_unlock(&tz_lock);
+ return ret;
+}
+
+static int __secure_tz_entry3(u32 cmd, u32 val1, u32 val2, u32 val3)
+{
+ int ret;
+ spin_lock(&tz_lock);
+ /* sync memory before sending the commands to tz*/
+ __iowmb();
+ ret = scm_call_atomic3(SCM_SVC_IO, cmd, val1, val2, val3);
+ spin_unlock(&tz_lock);
+ return ret;
+}
+
+static void _update_cutoff(struct devfreq_msm_adreno_tz_data *priv,
+ unsigned int norm_max)
+{
+ int i;
+
+ priv->bus.max = norm_max;
+ for (i = 0; i < priv->bus.num; i++) {
+ priv->bus.up[i] = priv->bus.p_up[i] * norm_max / 100;
+ priv->bus.down[i] = priv->bus.p_down[i] * norm_max / 100;
+ }
+}
+
+static int tz_get_target_freq(struct devfreq *devfreq, unsigned long *freq,
+ u32 *flag)
+{
+ int result = 0;
+ struct devfreq_msm_adreno_tz_data *priv = devfreq->data;
+ struct devfreq_dev_status stats;
+ struct xstats b;
+ int val, level = 0;
+ int act_level;
+ int norm_cycles;
+ int gpu_percent;
+
+ if (priv->bus.num)
+ stats.private_data = &b;
+ else
+ stats.private_data = NULL;
+ result = devfreq->profile->get_dev_status(devfreq->dev.parent, &stats);
+ if (result) {
+ pr_err(TAG "get_status failed %d\n", result);
+ return result;
+ }
+
+ *freq = stats.current_frequency;
+ *flag = 0;
+ priv->bin.total_time += stats.total_time;
+ priv->bin.busy_time += stats.busy_time;
+ if (priv->bus.num) {
+ priv->bus.total_time += stats.total_time;
+ priv->bus.gpu_time += stats.busy_time;
+ priv->bus.ram_time += b.ram_time;
+ priv->bus.ram_time += b.ram_wait;
+ }
+
+ /*
+ * Do not waste CPU cycles running this algorithm if
+ * the GPU just started, or if less than FLOOR time
+ * has passed since the last run.
+ */
+ if ((stats.total_time == 0) ||
+ (priv->bin.total_time < FLOOR)) {
+ return 1;
+ }
+
+ level = devfreq_get_freq_level(devfreq, stats.current_frequency);
+
+ if (level < 0) {
+ pr_err(TAG "bad freq %ld\n", stats.current_frequency);
+ return level;
+ }
+
+ /*
+ * If there is an extended block of busy processing,
+ * increase frequency. Otherwise run the normal algorithm.
+ */
+ if (priv->bin.busy_time > CEILING) {
+ val = -1 * level;
+ } else {
+ val = __secure_tz_entry3(TZ_UPDATE_ID,
+ level,
+ priv->bin.total_time,
+ priv->bin.busy_time);
+ }
+ priv->bin.total_time = 0;
+ priv->bin.busy_time = 0;
+
+ /*
+ * If the decision is to move to a different level, make sure the GPU
+ * frequency changes.
+ */
+ if (val) {
+ level += val;
+ level = max(level, 0);
+ level = min_t(int, level, devfreq->profile->max_state);
+ goto clear;
+ }
+
+ if (priv->bus.total_time < LONG_FLOOR)
+ goto end;
+ norm_cycles = (unsigned int)priv->bus.ram_time /
+ (unsigned int) priv->bus.total_time;
+ gpu_percent = (100 * (unsigned int)priv->bus.gpu_time) /
+ (unsigned int) priv->bus.total_time;
+ /*
+ * If there's a new high watermark, update the cutoffs and send the
+ * FAST hint. Otherwise check the current value against the current
+ * cutoffs.
+ */
+ if (norm_cycles > priv->bus.max) {
+ _update_cutoff(priv, norm_cycles);
+ *flag = DEVFREQ_FLAG_FAST_HINT;
+ } else {
+ /*
+ * Normalize by gpu_time unless it is a small fraction of
+ * the total time interval.
+ */
+ norm_cycles = (100 * norm_cycles) / TARGET;
+ act_level = priv->bus.index[level] + b.mod;
+ act_level = (act_level < 0) ? 0 : act_level;
+ act_level = (act_level >= priv->bus.num) ?
+ (priv->bus.num - 1) : act_level;
+ if (norm_cycles > priv->bus.up[act_level] &&
+ gpu_percent > CAP)
+ *flag = DEVFREQ_FLAG_FAST_HINT;
+ else if (norm_cycles < priv->bus.down[act_level] && level)
+ *flag = DEVFREQ_FLAG_SLOW_HINT;
+ }
+
+clear:
+ priv->bus.total_time = 0;
+ priv->bus.gpu_time = 0;
+ priv->bus.ram_time = 0;
+
+end:
+ *freq = devfreq->profile->freq_table[level];
+ return 0;
+}
+
+static int tz_notify(struct notifier_block *nb, unsigned long type, void *devp)
+{
+ int result = 0;
+ struct devfreq *devfreq = devp;
+
+ switch (type) {
+ case ADRENO_DEVFREQ_NOTIFY_IDLE:
+ case ADRENO_DEVFREQ_NOTIFY_RETIRE:
+ mutex_lock(&devfreq->lock);
+ result = update_devfreq(devfreq);
+ mutex_unlock(&devfreq->lock);
+ break;
+ /* ignored by this governor */
+ case ADRENO_DEVFREQ_NOTIFY_SUBMIT:
+ default:
+ break;
+ }
+ return notifier_from_errno(result);
+}
+
+static int tz_start(struct devfreq *devfreq)
+{
+ struct devfreq_msm_adreno_tz_data *priv;
+ unsigned int tz_pwrlevels[MSM_ADRENO_MAX_PWRLEVELS + 1];
+ unsigned int t1, t2 = 2 * HIST;
+ int i, out, ret;
+
+ if (devfreq->data == NULL) {
+ pr_err(TAG "data is required for this governor\n");
+ return -EINVAL;
+ }
+
+ priv = devfreq->data;
+ priv->nb.notifier_call = tz_notify;
+
+ out = 1;
+ if (devfreq->profile->max_state < MSM_ADRENO_MAX_PWRLEVELS) {
+ for (i = 0; i < devfreq->profile->max_state; i++)
+ tz_pwrlevels[out++] = devfreq->profile->freq_table[i];
+ tz_pwrlevels[0] = i;
+ } else {
+ pr_err(TAG "tz_pwrlevels[] is too short\n");
+ return -EINVAL;
+ }
+
+ ret = scm_call(SCM_SVC_DCVS, TZ_INIT_ID, tz_pwrlevels,
+ sizeof(tz_pwrlevels), NULL, 0);
+
+ if (ret != 0)
+ pr_err(TAG "tz_init failed\n");
+
+ /* Set up the cut-over percentages for the bus calculation. */
+ if (priv->bus.num) {
+ for (i = 0; i < priv->bus.num; i++) {
+ t1 = (u32)(100 * priv->bus.ib[i]) /
+ (u32)priv->bus.ib[priv->bus.num - 1];
+ priv->bus.p_up[i] = t1 - HIST;
+ priv->bus.p_down[i] = t2 - 2 * HIST;
+ t2 = t1;
+ }
+ /* Set the upper-most and lower-most bounds correctly. */
+ priv->bus.p_down[0] = 0;
+ priv->bus.p_down[1] = (priv->bus.p_down[1] > (2 * HIST)) ?
+ priv->bus.p_down[1] : (2 * HIST);
+ if (priv->bus.num - 1 >= 0)
+ priv->bus.p_up[priv->bus.num - 1] = 100;
+ _update_cutoff(priv, priv->bus.max);
+ }
+
+ return kgsl_devfreq_add_notifier(devfreq->dev.parent, &priv->nb);
+}
+
+static int tz_stop(struct devfreq *devfreq)
+{
+ struct devfreq_msm_adreno_tz_data *priv = devfreq->data;
+
+ kgsl_devfreq_del_notifier(devfreq->dev.parent, &priv->nb);
+ return 0;
+}
+
+
+static int tz_resume(struct devfreq *devfreq)
+{
+ struct devfreq_dev_profile *profile = devfreq->profile;
+ unsigned long freq;
+
+ freq = profile->initial_freq;
+
+ return profile->target(devfreq->dev.parent, &freq, 0);
+}
+
+static int tz_suspend(struct devfreq *devfreq)
+{
+ struct devfreq_msm_adreno_tz_data *priv = devfreq->data;
+
+ __secure_tz_entry2(TZ_RESET_ID, 0, 0);
+
+ priv->bin.total_time = 0;
+ priv->bin.busy_time = 0;
+ priv->bus.total_time = 0;
+ priv->bus.gpu_time = 0;
+ priv->bus.ram_time = 0;
+ return 0;
+}
+
+static int tz_handler(struct devfreq *devfreq, unsigned int event, void *data)
+{
+ int result;
+ BUG_ON(devfreq == NULL);
+
+ switch (event) {
+ case DEVFREQ_GOV_START:
+ result = tz_start(devfreq);
+ break;
+
+ case DEVFREQ_GOV_STOP:
+ result = tz_stop(devfreq);
+ break;
+
+ case DEVFREQ_GOV_SUSPEND:
+ result = tz_suspend(devfreq);
+ break;
+
+ case DEVFREQ_GOV_RESUME:
+ result = tz_resume(devfreq);
+ break;
+
+ case DEVFREQ_GOV_INTERVAL:
+ /* ignored, this governor doesn't use polling */
+ default:
+ result = 0;
+ break;
+ }
+
+ return result;
+}
+
+static struct devfreq_governor msm_adreno_tz = {
+ .name = "msm-adreno-tz",
+ .get_target_freq = tz_get_target_freq,
+ .event_handler = tz_handler,
+};
+
+static int __init msm_adreno_tz_init(void)
+{
+ return devfreq_add_governor(&msm_adreno_tz);
+}
+subsys_initcall(msm_adreno_tz_init);
+
+static void __exit msm_adreno_tz_exit(void)
+{
+ int ret;
+ ret = devfreq_remove_governor(&msm_adreno_tz);
+ if (ret)
+ pr_err(TAG "failed to remove governor %d\n", ret);
+
+ return;
+}
+
+module_exit(msm_adreno_tz_exit);
+
+MODULE_LICENSE("GPLv2");
diff --git a/drivers/devfreq/governor_msm_cpufreq.c b/drivers/devfreq/governor_msm_cpufreq.c
new file mode 100644
index 0000000..9b13e26
--- /dev/null
+++ b/drivers/devfreq/governor_msm_cpufreq.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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/devfreq.h>
+#include <mach/cpufreq.h>
+#include "governor.h"
+
+DEFINE_MUTEX(df_lock);
+static struct devfreq *df;
+
+static int devfreq_msm_cpufreq_get_freq(struct devfreq *df,
+ unsigned long *freq,
+ u32 *flag)
+{
+ *freq = msm_cpufreq_get_bw();
+ return 0;
+}
+
+int devfreq_msm_cpufreq_update_bw(void)
+{
+ int ret = 0;
+
+ mutex_lock(&df_lock);
+ if (df) {
+ mutex_lock(&df->lock);
+ ret = update_devfreq(df);
+ mutex_unlock(&df->lock);
+ }
+ mutex_unlock(&df_lock);
+ return ret;
+}
+
+static int devfreq_msm_cpufreq_ev_handler(struct devfreq *devfreq,
+ unsigned int event, void *data)
+{
+ int ret;
+
+ switch (event) {
+ case DEVFREQ_GOV_START:
+ mutex_lock(&df_lock);
+ df = devfreq;
+ mutex_unlock(&df_lock);
+
+ ret = devfreq_msm_cpufreq_update_bw();
+ if (ret) {
+ pr_err("Unable to update BW! Gov start failed!\n");
+ return ret;
+ }
+
+ devfreq_monitor_stop(df);
+ pr_debug("Enabled MSM CPUfreq governor\n");
+ break;
+
+ case DEVFREQ_GOV_STOP:
+ mutex_lock(&df_lock);
+ df = NULL;
+ mutex_unlock(&df_lock);
+
+ pr_debug("Disabled MSM CPUfreq governor\n");
+ break;
+ }
+
+ return 0;
+}
+
+static struct devfreq_governor devfreq_msm_cpufreq = {
+ .name = "msm_cpufreq",
+ .get_target_freq = devfreq_msm_cpufreq_get_freq,
+ .event_handler = devfreq_msm_cpufreq_ev_handler,
+};
+
+int register_devfreq_msm_cpufreq(void)
+{
+ return devfreq_add_governor(&devfreq_msm_cpufreq);
+}
diff --git a/drivers/devfreq/governor_performance.c b/drivers/devfreq/governor_performance.c
index bc7da1e..af2edc2 100644
--- a/drivers/devfreq/governor_performance.c
+++ b/drivers/devfreq/governor_performance.c
@@ -14,7 +14,8 @@
#include "governor.h"
static int devfreq_performance_func(struct devfreq *df,
- unsigned long *freq)
+ unsigned long *freq,
+ u32 *flag)
{
/*
* target callback should be able to get floor value as
diff --git a/drivers/devfreq/governor_powersave.c b/drivers/devfreq/governor_powersave.c
index 6d43685..57f3738 100644
--- a/drivers/devfreq/governor_powersave.c
+++ b/drivers/devfreq/governor_powersave.c
@@ -14,7 +14,8 @@
#include "governor.h"
static int devfreq_powersave_func(struct devfreq *df,
- unsigned long *freq)
+ unsigned long *freq,
+ u32 *flag)
{
/*
* target callback should be able to get ceiling value as
diff --git a/drivers/devfreq/governor_simpleondemand.c b/drivers/devfreq/governor_simpleondemand.c
index 0720ba8..bb29360 100644
--- a/drivers/devfreq/governor_simpleondemand.c
+++ b/drivers/devfreq/governor_simpleondemand.c
@@ -19,7 +19,8 @@
#define DFSO_UPTHRESHOLD (90)
#define DFSO_DOWNDIFFERENCTIAL (5)
static int devfreq_simple_ondemand_func(struct devfreq *df,
- unsigned long *freq)
+ unsigned long *freq,
+ u32 *flag)
{
struct devfreq_dev_status stat;
int err = df->profile->get_dev_status(df->dev.parent, &stat);
diff --git a/drivers/devfreq/governor_userspace.c b/drivers/devfreq/governor_userspace.c
index 35de6e8..4fbde04 100644
--- a/drivers/devfreq/governor_userspace.c
+++ b/drivers/devfreq/governor_userspace.c
@@ -22,7 +22,8 @@
bool valid;
};
-static int devfreq_userspace_func(struct devfreq *df, unsigned long *freq)
+static int devfreq_userspace_func(struct devfreq *df, unsigned long *freq,
+ u32 *flag)
{
struct userspace_data *data = df->data;
diff --git a/drivers/gpu/ion/Makefile b/drivers/gpu/ion/Makefile
index 0e460c8..108abe6 100644
--- a/drivers/gpu/ion/Makefile
+++ b/drivers/gpu/ion/Makefile
@@ -2,4 +2,4 @@
ion_carveout_heap.o ion_chunk_heap.o
obj-$(CONFIG_CMA) += ion_cma_heap.o ion_cma_secure_heap.o
obj-$(CONFIG_ION_TEGRA) += tegra/
-obj-$(CONFIG_ION_MSM) += ion_iommu_heap.o ion_cp_heap.o ion_removed_heap.o msm/
+obj-$(CONFIG_ION_MSM) += ion_cp_heap.o ion_removed_heap.o msm/
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 6777dae..514385c 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -24,19 +24,19 @@
#include <linux/ion.h>
#include <linux/kthread.h>
#include <linux/list.h>
+#include <linux/list_sort.h>
#include <linux/memblock.h>
#include <linux/miscdevice.h>
#include <linux/export.h>
#include <linux/mm.h>
#include <linux/mm_types.h>
#include <linux/rbtree.h>
-#include <linux/rtmutex.h>
-#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h>
#include <linux/debugfs.h>
#include <linux/dma-buf.h>
+#include <linux/idr.h>
#include <linux/msm_ion.h>
#include <trace/events/kmem.h>
@@ -62,6 +62,8 @@
unsigned long arg);
struct rb_root clients;
struct dentry *debug_root;
+ struct dentry *heaps_debug_root;
+ struct dentry *clients_debug_root;
};
/**
@@ -69,6 +71,7 @@
* @node: node in the tree of all clients
* @dev: backpointer to ion device
* @handles: an rb tree of all the handles in this client
+ * @idr: an idr space for allocating handle ids
* @lock: lock protecting the tree of handles
* @name: used for debugging
* @task: used for debugging
@@ -81,6 +84,7 @@
struct rb_node node;
struct ion_device *dev;
struct rb_root handles;
+ struct idr idr;
struct mutex lock;
char *name;
struct task_struct *task;
@@ -95,7 +99,7 @@
* @buffer: pointer to the buffer
* @node: node in the client's handle rbtree
* @kmap_cnt: count of times this client has mapped to kernel
- * @dmap_cnt: count of times this client has mapped for dma
+ * @id: client-unique id allocated by client->idr
*
* Modifications to node, map_cnt or mapping should be protected by the
* lock in the client. Other fields are never changed after initialization.
@@ -106,6 +110,7 @@
struct ion_buffer *buffer;
struct rb_node node;
unsigned int kmap_cnt;
+ int id;
};
bool ion_buffer_fault_user_mappings(struct ion_buffer *buffer)
@@ -147,7 +152,6 @@
static int ion_buffer_alloc_dirty(struct ion_buffer *buffer);
-static bool ion_heap_drain_freelist(struct ion_heap *heap);
/* this function should only be called while dev->lock is held */
static struct ion_buffer *ion_buffer_create(struct ion_heap *heap,
struct ion_device *dev,
@@ -174,7 +178,7 @@
if (!(heap->flags & ION_HEAP_FLAG_DEFER_FREE))
goto err2;
- ion_heap_drain_freelist(heap);
+ ion_heap_freelist_drain(heap, 0);
ret = heap->ops->allocate(heap, buffer, len, align,
flags);
if (ret)
@@ -242,7 +246,7 @@
buffer->heap->ops->unsecure_buffer(buffer, 1);
}
-static void _ion_buffer_destroy(struct ion_buffer *buffer)
+void ion_buffer_destroy(struct ion_buffer *buffer)
{
if (WARN_ON(buffer->kmap_cnt > 0))
buffer->heap->ops->unmap_kernel(buffer->heap, buffer);
@@ -255,7 +259,7 @@
kfree(buffer);
}
-static void ion_buffer_destroy(struct kref *kref)
+static void _ion_buffer_destroy(struct kref *kref)
{
struct ion_buffer *buffer = container_of(kref, struct ion_buffer, ref);
struct ion_heap *heap = buffer->heap;
@@ -265,14 +269,10 @@
rb_erase(&buffer->node, &dev->buffers);
mutex_unlock(&dev->buffer_lock);
- if (heap->flags & ION_HEAP_FLAG_DEFER_FREE) {
- rt_mutex_lock(&heap->lock);
- list_add(&buffer->list, &heap->free_list);
- rt_mutex_unlock(&heap->lock);
- wake_up(&heap->waitqueue);
- return;
- }
- _ion_buffer_destroy(buffer);
+ if (heap->flags & ION_HEAP_FLAG_DEFER_FREE)
+ ion_heap_freelist_add(heap, buffer);
+ else
+ ion_buffer_destroy(buffer);
}
static void ion_buffer_get(struct ion_buffer *buffer)
@@ -282,7 +282,7 @@
static int ion_buffer_put(struct ion_buffer *buffer)
{
- return kref_put(&buffer->ref, ion_buffer_destroy);
+ return kref_put(&buffer->ref, _ion_buffer_destroy);
}
static void ion_buffer_add_to_handle(struct ion_buffer *buffer)
@@ -347,6 +347,7 @@
ion_handle_kmap_put(handle);
mutex_unlock(&buffer->lock);
+ idr_remove(&client->idr, handle->id);
if (!RB_EMPTY_NODE(&handle->node))
rb_erase(&handle->node, &client->handles);
@@ -366,9 +367,16 @@
kref_get(&handle->ref);
}
-static int ion_handle_put(struct ion_handle *handle)
+int ion_handle_put(struct ion_handle *handle)
{
- return kref_put(&handle->ref, ion_handle_destroy);
+ struct ion_client *client = handle->client;
+ int ret;
+
+ mutex_lock(&client->lock);
+ ret = kref_put(&handle->ref, ion_handle_destroy);
+ mutex_unlock(&client->lock);
+
+ return ret;
}
static struct ion_handle *ion_handle_lookup(struct ion_client *client,
@@ -378,36 +386,52 @@
for (n = rb_first(&client->handles); n; n = rb_next(n)) {
struct ion_handle *handle = rb_entry(n, struct ion_handle,
- node);
+ node);
if (handle->buffer == buffer)
return handle;
}
return NULL;
}
-static bool ion_handle_validate(struct ion_client *client, struct ion_handle *handle)
+struct ion_handle *ion_handle_get_by_id(struct ion_client *client,
+ int id)
{
- struct rb_node *n = client->handles.rb_node;
+ struct ion_handle *handle;
- while (n) {
- struct ion_handle *handle_node = rb_entry(n, struct ion_handle,
- node);
- if (handle < handle_node)
- n = n->rb_left;
- else if (handle > handle_node)
- n = n->rb_right;
- else
- return true;
- }
- return false;
+ mutex_lock(&client->lock);
+ handle = idr_find(&client->idr, id);
+ if (handle)
+ ion_handle_get(handle);
+ mutex_unlock(&client->lock);
+
+ return handle ? handle : ERR_PTR(-EINVAL);
}
-static void ion_handle_add(struct ion_client *client, struct ion_handle *handle)
+static bool ion_handle_validate(struct ion_client *client, struct ion_handle *handle)
{
+ WARN_ON(!mutex_is_locked(&client->lock));
+ return (idr_find(&client->idr, handle->id) == handle);
+}
+
+static int ion_handle_add(struct ion_client *client, struct ion_handle *handle)
+{
+ int rc;
struct rb_node **p = &client->handles.rb_node;
struct rb_node *parent = NULL;
struct ion_handle *entry;
+ do {
+ int id;
+ rc = idr_pre_get(&client->idr, GFP_KERNEL);
+ if (!rc)
+ return -ENOMEM;
+ rc = idr_get_new_above(&client->idr, handle, 1, &id);
+ handle->id = id;
+ } while (rc == -EAGAIN);
+
+ if (rc < 0)
+ return rc;
+
while (*p) {
parent = *p;
entry = rb_entry(parent, struct ion_handle, node);
@@ -422,6 +446,8 @@
rb_link_node(&handle->node, parent, p);
rb_insert_color(&handle->node, &client->handles);
+
+ return 0;
}
struct ion_handle *ion_alloc(struct ion_client *client, size_t len,
@@ -432,6 +458,7 @@
struct ion_device *dev = client->dev;
struct ion_buffer *buffer = NULL;
struct ion_heap *heap;
+ int ret;
unsigned long secure_allocation = flags & ION_FLAG_SECURE;
const unsigned int MAX_DBG_STR_LEN = 64;
char dbg_str[MAX_DBG_STR_LEN];
@@ -522,12 +549,16 @@
*/
ion_buffer_put(buffer);
- if (!IS_ERR(handle)) {
- mutex_lock(&client->lock);
- ion_handle_add(client, handle);
- mutex_unlock(&client->lock);
- }
+ if (IS_ERR(handle))
+ return handle;
+ mutex_lock(&client->lock);
+ ret = ion_handle_add(client, handle);
+ mutex_unlock(&client->lock);
+ if (ret) {
+ ion_handle_put(handle);
+ handle = ERR_PTR(ret);
+ }
return handle;
}
@@ -546,8 +577,8 @@
mutex_unlock(&client->lock);
return;
}
- ion_handle_put(handle);
mutex_unlock(&client->lock);
+ ion_handle_put(handle);
}
EXPORT_SYMBOL(ion_free);
@@ -708,6 +739,35 @@
.release = single_release,
};
+static bool startswith(const char *string, const char *prefix)
+{
+ size_t l1 = strlen(string);
+ size_t l2 = strlen(prefix);
+ return strncmp(string, prefix, min(l1, l2)) == 0;
+}
+
+static int ion_get_client_serial(const struct rb_root *root,
+ const unsigned char *name)
+{
+ int serial = -1;
+ struct rb_node *node;
+ for (node = rb_first(root); node; node = rb_next(node)) {
+ int n;
+ char *serial_string;
+ struct ion_client *client = rb_entry(node, struct ion_client,
+ node);
+ if (!startswith(client->name, name))
+ continue;
+ serial_string = strrchr(client->name, '-');
+ if (!serial_string)
+ continue;
+ serial_string++;
+ sscanf(serial_string, "%d", &n);
+ serial = max(serial, n);
+ }
+ return serial + 1;
+}
+
struct ion_client *ion_client_create(struct ion_device *dev,
const char *name)
{
@@ -717,13 +777,16 @@
struct rb_node *parent = NULL;
struct ion_client *entry;
pid_t pid;
- unsigned int name_len;
+ int name_len;
+ int client_serial;
if (!name) {
pr_err("%s: Name cannot be null\n", __func__);
return ERR_PTR(-EINVAL);
}
name_len = strnlen(name, 64);
+ /* add some space to accommodate the serial number suffix */
+ name_len = min(64, name_len + 11);
get_task_struct(current->group_leader);
task_lock(current->group_leader);
@@ -747,6 +810,7 @@
client->dev = dev;
client->handles = RB_ROOT;
+ idr_init(&client->idr);
mutex_init(&client->lock);
client->name = kzalloc(name_len+1, GFP_KERNEL);
@@ -754,14 +818,14 @@
put_task_struct(current->group_leader);
kfree(client);
return ERR_PTR(-ENOMEM);
- } else {
- strlcpy(client->name, name, name_len+1);
}
client->task = task;
client->pid = pid;
down_write(&dev->lock);
+ client_serial = ion_get_client_serial(&dev->clients, name);
+ snprintf(client->name, name_len, "%s-%d", name, client_serial);
p = &dev->clients.rb_node;
while (*p) {
parent = *p;
@@ -776,9 +840,16 @@
rb_insert_color(&client->node, &dev->clients);
- client->debug_root = debugfs_create_file(name, 0664,
- dev->debug_root, client,
- &debug_client_fops);
+ client->debug_root = debugfs_create_file(client->name, 0664,
+ dev->clients_debug_root,
+ client, &debug_client_fops);
+ if (!client->debug_root) {
+ char buf[256], *path;
+ path = dentry_path(dev->clients_debug_root, buf, 256);
+ pr_err("Failed to created client debugfs at %s/%s\n",
+ path, client->name);
+ }
+
up_write(&dev->lock);
return client;
@@ -796,6 +867,10 @@
node);
ion_handle_destroy(&handle->ref);
}
+
+ idr_remove_all(&client->idr);
+ idr_destroy(&client->idr);
+
down_write(&dev->lock);
if (client->task)
put_task_struct(client->task);
@@ -1140,14 +1215,15 @@
mutex_lock(&client->lock);
valid_handle = ion_handle_validate(client, handle);
- mutex_unlock(&client->lock);
if (!valid_handle) {
WARN(1, "%s: invalid handle passed to share.\n", __func__);
+ mutex_unlock(&client->lock);
return ERR_PTR(-EINVAL);
}
-
buffer = handle->buffer;
ion_buffer_get(buffer);
+ mutex_unlock(&client->lock);
+
dmabuf = dma_buf_export(buffer, &dma_buf_ops, buffer->size, O_RDWR);
if (IS_ERR(dmabuf)) {
ion_buffer_put(buffer);
@@ -1180,6 +1256,7 @@
struct dma_buf *dmabuf;
struct ion_buffer *buffer;
struct ion_handle *handle;
+ int ret;
dmabuf = dma_buf_get(fd);
if (IS_ERR_OR_NULL(dmabuf))
@@ -1199,14 +1276,24 @@
handle = ion_handle_lookup(client, buffer);
if (!IS_ERR_OR_NULL(handle)) {
ion_handle_get(handle);
+ mutex_unlock(&client->lock);
goto end;
}
+ mutex_unlock(&client->lock);
+
handle = ion_handle_create(client, buffer);
if (IS_ERR_OR_NULL(handle))
goto end;
- ion_handle_add(client, handle);
-end:
+
+ mutex_lock(&client->lock);
+ ret = ion_handle_add(client, handle);
mutex_unlock(&client->lock);
+ if (ret) {
+ ion_handle_put(handle);
+ handle = ERR_PTR(ret);
+ }
+
+end:
dma_buf_put(dmabuf);
return handle;
}
@@ -1244,17 +1331,20 @@
case ION_IOC_ALLOC:
{
struct ion_allocation_data data;
+ struct ion_handle *handle;
if (copy_from_user(&data, (void __user *)arg, sizeof(data)))
return -EFAULT;
- data.handle = ion_alloc(client, data.len, data.align,
+ handle = ion_alloc(client, data.len, data.align,
data.heap_mask, data.flags);
- if (IS_ERR(data.handle))
- return PTR_ERR(data.handle);
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+
+ data.handle = (ion_user_handle_t)handle->id;
if (copy_to_user((void __user *)arg, &data, sizeof(data))) {
- ion_free(client, data.handle);
+ ion_free(client, handle);
return -EFAULT;
}
break;
@@ -1262,28 +1352,31 @@
case ION_IOC_FREE:
{
struct ion_handle_data data;
- bool valid;
+ struct ion_handle *handle;
if (copy_from_user(&data, (void __user *)arg,
sizeof(struct ion_handle_data)))
return -EFAULT;
- mutex_lock(&client->lock);
- valid = ion_handle_validate(client, data.handle);
- mutex_unlock(&client->lock);
- if (!valid)
- return -EINVAL;
- ion_free(client, data.handle);
+ handle = ion_handle_get_by_id(client, (int)data.handle);
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+ ion_free(client, handle);
+ ion_handle_put(handle);
break;
}
case ION_IOC_SHARE:
case ION_IOC_MAP:
{
struct ion_fd_data data;
+ struct ion_handle *handle;
if (copy_from_user(&data, (void __user *)arg, sizeof(data)))
return -EFAULT;
- data.fd = ion_share_dma_buf_fd(client, data.handle);
-
+ handle = ion_handle_get_by_id(client, (int)data.handle);
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+ data.fd = ion_share_dma_buf_fd(client, handle);
+ ion_handle_put(handle);
if (copy_to_user((void __user *)arg, &data, sizeof(data)))
return -EFAULT;
if (data.fd < 0)
@@ -1293,15 +1386,17 @@
case ION_IOC_IMPORT:
{
struct ion_fd_data data;
+ struct ion_handle *handle;
int ret = 0;
if (copy_from_user(&data, (void __user *)arg,
sizeof(struct ion_fd_data)))
return -EFAULT;
- data.handle = ion_import_dma_buf(client, data.fd);
- if (IS_ERR(data.handle)) {
- ret = PTR_ERR(data.handle);
- data.handle = NULL;
- }
+ handle = ion_import_dma_buf(client, data.fd);
+ if (IS_ERR(handle))
+ ret = PTR_ERR(handle);
+ else
+ data.handle = (ion_user_handle_t)handle->id;
+
if (copy_to_user((void __user *)arg, &data,
sizeof(struct ion_fd_data)))
return -EFAULT;
@@ -1397,134 +1492,89 @@
}
/**
- * Searches through a clients handles to find if the buffer is owned
- * by this client. Used for debug output.
- * @param client pointer to candidate owner of buffer
- * @param buf pointer to buffer that we are trying to find the owner of
- * @return 1 if found, 0 otherwise
- */
-static int ion_debug_find_buffer_owner(const struct ion_client *client,
- const struct ion_buffer *buf)
-{
- struct rb_node *n;
-
- for (n = rb_first(&client->handles); n; n = rb_next(n)) {
- const struct ion_handle *handle = rb_entry(n,
- const struct ion_handle,
- node);
- if (handle->buffer == buf)
- return 1;
- }
- return 0;
-}
-
-/**
- * Adds mem_map_data pointer to the tree of mem_map
- * Used for debug output.
- * @param mem_map The mem_map tree
- * @param data The new data to add to the tree
- */
-static void ion_debug_mem_map_add(struct rb_root *mem_map,
- struct mem_map_data *data)
-{
- struct rb_node **p = &mem_map->rb_node;
- struct rb_node *parent = NULL;
- struct mem_map_data *entry;
-
- while (*p) {
- parent = *p;
- entry = rb_entry(parent, struct mem_map_data, node);
-
- if (data->addr < entry->addr) {
- p = &(*p)->rb_left;
- } else if (data->addr > entry->addr) {
- p = &(*p)->rb_right;
- } else {
- pr_err("%s: mem_map_data already found.", __func__);
- BUG();
- }
- }
- rb_link_node(&data->node, parent, p);
- rb_insert_color(&data->node, mem_map);
-}
-
-/**
- * Search for an owner of a buffer by iterating over all ION clients.
- * @param dev ion device containing pointers to all the clients.
- * @param buffer pointer to buffer we are trying to find the owner of.
- * @return name of owner.
- */
-const char *ion_debug_locate_owner(const struct ion_device *dev,
- const struct ion_buffer *buffer)
-{
- struct rb_node *j;
- const char *client_name = NULL;
-
- for (j = rb_first(&dev->clients); j && !client_name;
- j = rb_next(j)) {
- struct ion_client *client = rb_entry(j, struct ion_client,
- node);
- if (ion_debug_find_buffer_owner(client, buffer))
- client_name = client->name;
- }
- return client_name;
-}
-
-/**
* Create a mem_map of the heap.
* @param s seq_file to log error message to.
* @param heap The heap to create mem_map for.
* @param mem_map The mem map to be created.
*/
void ion_debug_mem_map_create(struct seq_file *s, struct ion_heap *heap,
- struct rb_root *mem_map)
+ struct list_head *mem_map)
{
struct ion_device *dev = heap->dev;
- struct rb_node *n;
+ struct rb_node *cnode;
size_t size;
+ struct ion_client *client;
if (!heap->ops->phys)
return;
- for (n = rb_first(&dev->buffers); n; n = rb_next(n)) {
- struct ion_buffer *buffer =
- rb_entry(n, struct ion_buffer, node);
- if (buffer->heap->id == heap->id) {
- struct mem_map_data *data =
- kzalloc(sizeof(*data), GFP_KERNEL);
- if (!data) {
- seq_printf(s, "ERROR: out of memory. "
- "Part of memory map will not be logged\n");
- break;
- }
+ down_read(&dev->lock);
+ for (cnode = rb_first(&dev->clients); cnode; cnode = rb_next(cnode)) {
+ struct rb_node *hnode;
+ client = rb_entry(cnode, struct ion_client, node);
- buffer->heap->ops->phys(buffer->heap, buffer,
- &(data->addr), &size);
- data->size = (unsigned long) size;
- data->addr_end = data->addr + data->size - 1;
- data->client_name = ion_debug_locate_owner(dev, buffer);
- ion_debug_mem_map_add(mem_map, data);
+ mutex_lock(&client->lock);
+ for (hnode = rb_first(&client->handles);
+ hnode;
+ hnode = rb_next(hnode)) {
+ struct ion_handle *handle = rb_entry(
+ hnode, struct ion_handle, node);
+ if (handle->buffer->heap == heap) {
+ struct mem_map_data *data =
+ kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ goto inner_error;
+ heap->ops->phys(heap, handle->buffer,
+ &(data->addr), &size);
+ data->size = (unsigned long) size;
+ data->addr_end = data->addr + data->size - 1;
+ data->client_name = kstrdup(client->name,
+ GFP_KERNEL);
+ if (!data->client_name) {
+ kfree(data);
+ goto inner_error;
+ }
+ list_add(&data->node, mem_map);
+ }
}
+ mutex_unlock(&client->lock);
}
+ up_read(&dev->lock);
+ return;
+
+inner_error:
+ seq_puts(s,
+ "ERROR: out of memory. Part of memory map will not be logged\n");
+ mutex_unlock(&client->lock);
+ up_read(&dev->lock);
}
/**
* Free the memory allocated by ion_debug_mem_map_create
* @param mem_map The mem map to free.
*/
-static void ion_debug_mem_map_destroy(struct rb_root *mem_map)
+static void ion_debug_mem_map_destroy(struct list_head *mem_map)
{
if (mem_map) {
- struct rb_node *n;
- while ((n = rb_first(mem_map)) != 0) {
- struct mem_map_data *data =
- rb_entry(n, struct mem_map_data, node);
- rb_erase(&data->node, mem_map);
+ struct mem_map_data *data, *tmp;
+ list_for_each_entry_safe(data, tmp, mem_map, node) {
+ list_del(&data->node);
+ kfree(data->client_name);
kfree(data);
}
}
}
+static int mem_map_cmp(void *priv, struct list_head *a, struct list_head *b)
+{
+ struct mem_map_data *d1, *d2;
+ d1 = list_entry(a, struct mem_map_data, node);
+ d2 = list_entry(b, struct mem_map_data, node);
+ if (d1->addr == d2->addr)
+ return d1->size - d2->size;
+ return d1->addr - d2->addr;
+}
+
/**
* Print heap debug information.
* @param s seq_file to log message to.
@@ -1533,8 +1583,9 @@
static void ion_heap_print_debug(struct seq_file *s, struct ion_heap *heap)
{
if (heap->ops->print_debug) {
- struct rb_root mem_map = RB_ROOT;
+ struct list_head mem_map = LIST_HEAD_INIT(mem_map);
ion_debug_mem_map_create(s, heap, &mem_map);
+ list_sort(NULL, &mem_map, mem_map_cmp);
heap->ops->print_debug(heap, s, &mem_map);
ion_debug_mem_map_destroy(&mem_map);
}
@@ -1551,6 +1602,7 @@
seq_printf(s, "%16.s %16.s %16.s\n", "client", "pid", "size");
seq_printf(s, "----------------------------------------------------\n");
+ down_read(&dev->lock);
for (n = rb_first(&dev->clients); n; n = rb_next(n)) {
struct ion_client *client = rb_entry(n, struct ion_client,
node);
@@ -1568,6 +1620,7 @@
client->pid, size);
}
}
+ up_read(&dev->lock);
seq_printf(s, "----------------------------------------------------\n");
seq_printf(s, "orphaned allocations (info is from last known client):"
"\n");
@@ -1611,87 +1664,89 @@
.release = single_release,
};
-static size_t ion_heap_free_list_is_empty(struct ion_heap *heap)
+#ifdef DEBUG_HEAP_SHRINKER
+static int debug_shrink_set(void *data, u64 val)
{
- bool is_empty;
+ struct ion_heap *heap = data;
+ struct shrink_control sc;
+ int objs;
- rt_mutex_lock(&heap->lock);
- is_empty = list_empty(&heap->free_list);
- rt_mutex_unlock(&heap->lock);
+ sc.gfp_mask = -1;
+ sc.nr_to_scan = 0;
- return is_empty;
+ if (!val)
+ return 0;
+
+ objs = heap->shrinker.shrink(&heap->shrinker, &sc);
+ sc.nr_to_scan = objs;
+
+ heap->shrinker.shrink(&heap->shrinker, &sc);
+ return 0;
}
-static int ion_heap_deferred_free(void *data)
+static int debug_shrink_get(void *data, u64 *val)
{
- struct ion_heap *heap = data;
+ struct ion_heap *heap = data;
+ struct shrink_control sc;
+ int objs;
- while (true) {
- struct ion_buffer *buffer;
+ sc.gfp_mask = -1;
+ sc.nr_to_scan = 0;
- wait_event_freezable(heap->waitqueue,
- !ion_heap_free_list_is_empty(heap));
-
- rt_mutex_lock(&heap->lock);
- if (list_empty(&heap->free_list)) {
- rt_mutex_unlock(&heap->lock);
- continue;
- }
- buffer = list_first_entry(&heap->free_list, struct ion_buffer,
- list);
- list_del(&buffer->list);
- rt_mutex_unlock(&heap->lock);
- _ion_buffer_destroy(buffer);
- }
-
- return 0;
+ objs = heap->shrinker.shrink(&heap->shrinker, &sc);
+ *val = objs;
+ return 0;
}
-static bool ion_heap_drain_freelist(struct ion_heap *heap)
-{
- struct ion_buffer *buffer, *tmp;
-
- if (ion_heap_free_list_is_empty(heap))
- return false;
- rt_mutex_lock(&heap->lock);
- list_for_each_entry_safe(buffer, tmp, &heap->free_list, list) {
- list_del(&buffer->list);
- _ion_buffer_destroy(buffer);
- }
- BUG_ON(!list_empty(&heap->free_list));
- rt_mutex_unlock(&heap->lock);
-
-
- return true;
-}
+DEFINE_SIMPLE_ATTRIBUTE(debug_shrink_fops, debug_shrink_get,
+ debug_shrink_set, "%llu\n");
+#endif
void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap)
{
- struct sched_param param = { .sched_priority = 0 };
+ struct dentry *debug_file;
if (!heap->ops->allocate || !heap->ops->free || !heap->ops->map_dma ||
!heap->ops->unmap_dma)
pr_err("%s: can not add heap with invalid ops struct.\n",
__func__);
- if (heap->flags & ION_HEAP_FLAG_DEFER_FREE) {
- INIT_LIST_HEAD(&heap->free_list);
- rt_mutex_init(&heap->lock);
- init_waitqueue_head(&heap->waitqueue);
- heap->task = kthread_run(ion_heap_deferred_free, heap,
- "%s", heap->name);
- sched_setscheduler(heap->task, SCHED_IDLE, ¶m);
- if (IS_ERR(heap->task))
- pr_err("%s: creating thread for deferred free failed\n",
- __func__);
- }
+ if (heap->flags & ION_HEAP_FLAG_DEFER_FREE)
+ ion_heap_init_deferred_free(heap);
heap->dev = dev;
down_write(&dev->lock);
- plist_node_init(&heap->node, heap->id);
+ /* use negative heap->id to reverse the priority -- when traversing
+ the list later attempt higher id numbers first */
+ plist_node_init(&heap->node, -heap->id);
plist_add(&heap->node, &dev->heaps);
- debugfs_create_file(heap->name, 0664, dev->debug_root, heap,
- &debug_heap_fops);
+ debug_file = debugfs_create_file(heap->name, 0664,
+ dev->heaps_debug_root, heap,
+ &debug_heap_fops);
+
+ if (!debug_file) {
+ char buf[256], *path;
+ path = dentry_path(dev->heaps_debug_root, buf, 256);
+ pr_err("Failed to created heap debugfs at %s/%s\n",
+ path, heap->name);
+ }
+
+#ifdef DEBUG_HEAP_SHRINKER
+ if (heap->shrinker.shrink) {
+ char debug_name[64];
+
+ snprintf(debug_name, 64, "%s_shrink", heap->name);
+ debug_file = debugfs_create_file(
+ debug_name, 0644, dev->heaps_debug_root, heap,
+ &debug_shrink_fops);
+ if (!debug_file) {
+ char buf[256], *path;
+ path = dentry_path(dev->heaps_debug_root, buf, 256);
+ pr_err("Failed to created heap shrinker debugfs at %s/%s\n",
+ path, debug_name);
+ }
+ }
+#endif
up_write(&dev->lock);
}
@@ -1789,6 +1844,28 @@
}
EXPORT_SYMBOL(ion_secure_heap);
+int ion_walk_heaps(struct ion_client *client, int heap_id, void *data,
+ int (*f)(struct ion_heap *heap, void *data))
+{
+ int ret_val = -EINVAL;
+ struct ion_heap *heap;
+ struct ion_device *dev = client->dev;
+ /*
+ * traverse the list of heaps available in this system
+ * and find the heap that is specified.
+ */
+ down_write(&dev->lock);
+ plist_for_each_entry(heap, &dev->heaps, node) {
+ if (ION_HEAP(heap->id) != heap_id)
+ continue;
+ ret_val = f(heap, data);
+ break;
+ }
+ up_write(&dev->lock);
+ return ret_val;
+}
+EXPORT_SYMBOL(ion_walk_heaps);
+
int ion_unsecure_heap(struct ion_device *dev, int heap_id, int version,
void *data)
{
@@ -1839,8 +1916,21 @@
}
idev->debug_root = debugfs_create_dir("ion", NULL);
- if (IS_ERR_OR_NULL(idev->debug_root))
- pr_err("ion: failed to create debug files.\n");
+ if (!idev->debug_root) {
+ pr_err("ion: failed to create debugfs root directory.\n");
+ goto debugfs_done;
+ }
+ idev->heaps_debug_root = debugfs_create_dir("heaps", idev->debug_root);
+ if (!idev->heaps_debug_root) {
+ pr_err("ion: failed to create debugfs heaps directory.\n");
+ goto debugfs_done;
+ }
+ idev->clients_debug_root = debugfs_create_dir("clients",
+ idev->debug_root);
+ if (!idev->clients_debug_root)
+ pr_err("ion: failed to create debugfs clients directory.\n");
+
+debugfs_done:
idev->custom_ioctl = custom_ioctl;
idev->buffers = RB_ROOT;
@@ -1854,6 +1944,7 @@
void ion_device_destroy(struct ion_device *dev)
{
misc_deregister(&dev->dev);
+ debugfs_remove_recursive(dev->debug_root);
/* XXX need to free the heaps and clients ? */
kfree(dev);
}
diff --git a/drivers/gpu/ion/ion_carveout_heap.c b/drivers/gpu/ion/ion_carveout_heap.c
index 08921299..d25e928 100644
--- a/drivers/gpu/ion/ion_carveout_heap.c
+++ b/drivers/gpu/ion/ion_carveout_heap.c
@@ -162,7 +162,7 @@
}
static int ion_carveout_print_debug(struct ion_heap *heap, struct seq_file *s,
- const struct rb_root *mem_map)
+ const struct list_head *mem_map)
{
struct ion_carveout_heap *carveout_heap =
container_of(heap, struct ion_carveout_heap, heap);
@@ -176,16 +176,14 @@
unsigned long size = carveout_heap->total_size;
unsigned long end = base+size;
unsigned long last_end = base;
- struct rb_node *n;
+ struct mem_map_data *data;
seq_printf(s, "\nMemory Map\n");
seq_printf(s, "%16.s %14.s %14.s %14.s\n",
"client", "start address", "end address",
"size (hex)");
- for (n = rb_first(mem_map); n; n = rb_next(n)) {
- struct mem_map_data *data =
- rb_entry(n, struct mem_map_data, node);
+ list_for_each_entry(data, mem_map, node) {
const char *client_name = "(null)";
if (last_end < data->addr) {
diff --git a/drivers/gpu/ion/ion_cma_heap.c b/drivers/gpu/ion/ion_cma_heap.c
index b24b2bd..d4bbab7 100644
--- a/drivers/gpu/ion/ion_cma_heap.c
+++ b/drivers/gpu/ion/ion_cma_heap.c
@@ -180,19 +180,17 @@
}
static int ion_cma_print_debug(struct ion_heap *heap, struct seq_file *s,
- const struct rb_root *mem_map)
+ const struct list_head *mem_map)
{
if (mem_map) {
- struct rb_node *n;
+ struct mem_map_data *data;
seq_printf(s, "\nMemory Map\n");
seq_printf(s, "%16.s %14.s %14.s %14.s\n",
"client", "start address", "end address",
"size (hex)");
- for (n = rb_first(mem_map); n; n = rb_next(n)) {
- struct mem_map_data *data =
- rb_entry(n, struct mem_map_data, node);
+ list_for_each_entry(data, mem_map, node) {
const char *client_name = "(null)";
diff --git a/drivers/gpu/ion/ion_cma_secure_heap.c b/drivers/gpu/ion/ion_cma_secure_heap.c
index 90451ca..d375c00 100644
--- a/drivers/gpu/ion/ion_cma_secure_heap.c
+++ b/drivers/gpu/ion/ion_cma_secure_heap.c
@@ -38,19 +38,72 @@
* This needs to come first for compatibility with the secure buffer API
*/
struct ion_cp_buffer secure;
- void *cpu_addr;
- dma_addr_t handle;
+ dma_addr_t phys;
struct sg_table *table;
bool is_cached;
};
+struct ion_cma_alloc_chunk {
+ void *cpu_addr;
+ struct list_head entry;
+ dma_addr_t handle;
+ unsigned long chunk_size;
+ atomic_t cnt;
+};
+
+struct ion_cma_secure_heap {
+ struct device *dev;
+ /*
+ * Protects against races between threads allocating memory/adding to
+ * pool at the same time. (e.g. thread 1 adds to pool, thread 2
+ * allocates thread 1's memory before thread 1 knows it needs to
+ * allocate more.
+ * Admittedly this is fairly coarse grained right now but the chance for
+ * contention on this lock is unlikely right now. This can be changed if
+ * this ever changes in the future
+ */
+ struct mutex alloc_lock;
+ /*
+ * protects the list of memory chunks in this pool
+ */
+ struct mutex chunk_lock;
+ struct ion_heap heap;
+ /*
+ * Bitmap for allocation. This contains the aggregate of all chunks. */
+ unsigned long *bitmap;
+ /*
+ * List of all allocated chunks
+ *
+ * This is where things get 'clever'. Individual allocations from
+ * dma_alloc_coherent must be allocated and freed in one chunk.
+ * We don't just want to limit the allocations to those confined
+ * within a single chunk (if clients allocate n small chunks we would
+ * never be able to use the combined size). The bitmap allocator is
+ * used to find the contiguous region and the parts of the chunks are
+ * marked off as used. The chunks won't be freed in the shrinker until
+ * the usage is actually zero.
+ */
+ struct list_head chunks;
+ int npages;
+ ion_phys_addr_t base;
+ struct work_struct work;
+ unsigned long last_alloc;
+ struct shrinker shrinker;
+ atomic_t total_allocated;
+ atomic_t total_pool_size;
+ unsigned long heap_size;
+ unsigned long default_prefetch_size;
+};
+
+static void ion_secure_pool_pages(struct work_struct *work);
+
/*
* Create scatter-list for the already allocated DMA buffer.
* This function could be replace by dma_common_get_sgtable
* as soon as it will avalaible.
*/
int ion_secure_cma_get_sgtable(struct device *dev, struct sg_table *sgt,
- void *cpu_addr, dma_addr_t handle, size_t size)
+ dma_addr_t handle, size_t size)
{
struct page *page = phys_to_page(handle);
int ret;
@@ -64,47 +117,364 @@
return 0;
}
+static int ion_secure_cma_add_to_pool(
+ struct ion_cma_secure_heap *sheap,
+ unsigned long len)
+{
+ void *cpu_addr;
+ dma_addr_t handle;
+ DEFINE_DMA_ATTRS(attrs);
+ int ret = 0;
+ struct ion_cma_alloc_chunk *chunk;
+
+ mutex_lock(&sheap->chunk_lock);
+
+ chunk = kzalloc(sizeof(*chunk), GFP_KERNEL);
+ if (!chunk) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &attrs);
+
+ cpu_addr = dma_alloc_attrs(sheap->dev, len, &handle, GFP_KERNEL,
+ &attrs);
+
+ if (!cpu_addr) {
+ ret = -ENOMEM;
+ goto out_free;
+ }
+
+ chunk->cpu_addr = cpu_addr;
+ chunk->handle = handle;
+ chunk->chunk_size = len;
+ atomic_set(&chunk->cnt, 0);
+ list_add(&chunk->entry, &sheap->chunks);
+ atomic_add(len, &sheap->total_pool_size);
+ /* clear the bitmap to indicate this region can be allocated from */
+ bitmap_clear(sheap->bitmap, (handle - sheap->base) >> PAGE_SHIFT,
+ len >> PAGE_SHIFT);
+ goto out;
+
+out_free:
+ kfree(chunk);
+out:
+ mutex_unlock(&sheap->chunk_lock);
+ return ret;
+}
+
+static void ion_secure_pool_pages(struct work_struct *work)
+{
+ struct ion_cma_secure_heap *sheap = container_of(work,
+ struct ion_cma_secure_heap, work);
+
+ ion_secure_cma_add_to_pool(sheap, sheap->last_alloc);
+}
+/*
+ * @s1: start of the first region
+ * @l1: length of the first region
+ * @s2: start of the second region
+ * @l2: length of the second region
+ *
+ * Returns the total number of bytes that intersect.
+ *
+ * s1 is the region we are trying to clear so s2 may be subsumed by s1 but the
+ * maximum size to clear should only ever be l1
+ *
+ */
+static unsigned int intersect(unsigned long s1, unsigned long l1,
+ unsigned long s2, unsigned long l2)
+{
+ unsigned long base1 = s1;
+ unsigned long end1 = s1 + l1;
+ unsigned long base2 = s2;
+ unsigned long end2 = s2 + l2;
+
+ /* Case 0: The regions don't overlap at all */
+ if (!(base1 < end2 && base2 < end1))
+ return 0;
+
+ /* Case 1: region 2 is subsumed by region 1 */
+ if (base1 <= base2 && end2 <= end1)
+ return l2;
+
+ /* case 2: region 1 is subsumed by region 2 */
+ if (base2 <= base1 && end1 <= end2)
+ return l1;
+
+ /* case 3: region1 overlaps region2 on the bottom */
+ if (base2 < end1 && base2 > base1)
+ return end1 - base2;
+
+ /* case 4: region 2 overlaps region1 on the bottom */
+ if (base1 < end2 && base1 > base2)
+ return end2 - base1;
+
+ pr_err("Bad math! Did not detect chunks correctly! %lx %lx %lx %lx\n",
+ s1, l1, s2, l2);
+ BUG();
+}
+
+int ion_secure_cma_prefetch(struct ion_heap *heap, void *data)
+{
+ unsigned long len = (unsigned long)data;
+ struct ion_cma_secure_heap *sheap =
+ container_of(heap, struct ion_cma_secure_heap, heap);
+ unsigned long diff;
+
+ if ((int) heap->type != ION_HEAP_TYPE_SECURE_DMA)
+ return -EINVAL;
+
+ if (len == 0)
+ len = sheap->default_prefetch_size;
+
+ /*
+ * Only prefetch as much space as there is left in the pool so
+ * check against the current free size of the heap.
+ * This is slightly racy if someone else is allocating at the same
+ * time. CMA has a restricted size for the heap so worst case
+ * the prefetch doesn't work because the allocation fails.
+ */
+ diff = sheap->heap_size - atomic_read(&sheap->total_pool_size);
+
+ if (len > diff)
+ len = diff;
+
+ sheap->last_alloc = len;
+ schedule_work(&sheap->work);
+
+ return 0;
+}
+
+static void bad_math_dump(unsigned long len, int total_overlap,
+ struct ion_cma_secure_heap *sheap,
+ bool alloc, dma_addr_t paddr)
+{
+ struct list_head *entry;
+
+ pr_err("Bad math! expected total was %lx actual was %x\n",
+ len, total_overlap);
+ pr_err("attempted %s address was %pa len %lx\n",
+ alloc ? "allocation" : "free", &paddr, len);
+ pr_err("chunks:\n");
+ list_for_each(entry, &sheap->chunks) {
+ struct ion_cma_alloc_chunk *chunk =
+ container_of(entry,
+ struct ion_cma_alloc_chunk, entry);
+ pr_info("--- pa %pa len %lx\n",
+ &chunk->handle, chunk->chunk_size);
+ }
+ BUG();
+
+}
+
+static int ion_secure_cma_alloc_from_pool(
+ struct ion_cma_secure_heap *sheap,
+ dma_addr_t *phys,
+ unsigned long len)
+{
+ dma_addr_t paddr;
+ unsigned long page_no;
+ int ret = 0;
+ int total_overlap = 0;
+ struct list_head *entry;
+
+ mutex_lock(&sheap->chunk_lock);
+
+ page_no = bitmap_find_next_zero_area(sheap->bitmap,
+ sheap->npages, 0, len >> PAGE_SHIFT, 0);
+ if (page_no >= sheap->npages) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ bitmap_set(sheap->bitmap, page_no, len >> PAGE_SHIFT);
+ paddr = sheap->base + (page_no << PAGE_SHIFT);
+
+
+ list_for_each(entry, &sheap->chunks) {
+ struct ion_cma_alloc_chunk *chunk = container_of(entry,
+ struct ion_cma_alloc_chunk, entry);
+ int overlap = intersect(chunk->handle,
+ chunk->chunk_size, paddr, len);
+
+ atomic_add(overlap, &chunk->cnt);
+ total_overlap += overlap;
+ }
+
+ if (total_overlap != len)
+ bad_math_dump(len, total_overlap, sheap, 1, paddr);
+
+ *phys = paddr;
+out:
+ mutex_unlock(&sheap->chunk_lock);
+ return ret;
+}
+
+static void ion_secure_cma_free_chunk(struct ion_cma_secure_heap *sheap,
+ struct ion_cma_alloc_chunk *chunk)
+{
+ /* This region is 'allocated' and not available to allocate from */
+ bitmap_set(sheap->bitmap, (chunk->handle - sheap->base) >> PAGE_SHIFT,
+ chunk->chunk_size >> PAGE_SHIFT);
+ dma_free_coherent(sheap->dev, chunk->chunk_size, chunk->cpu_addr,
+ chunk->handle);
+ atomic_sub(chunk->chunk_size, &sheap->total_pool_size);
+ list_del(&chunk->entry);
+ kfree(chunk);
+
+}
+
+int ion_secure_cma_drain_pool(struct ion_heap *heap, void *unused)
+{
+ struct ion_cma_secure_heap *sheap =
+ container_of(heap, struct ion_cma_secure_heap, heap);
+ struct list_head *entry, *_n;
+
+ mutex_lock(&sheap->chunk_lock);
+ list_for_each_safe(entry, _n, &sheap->chunks) {
+ struct ion_cma_alloc_chunk *chunk = container_of(entry,
+ struct ion_cma_alloc_chunk, entry);
+
+ if (atomic_read(&chunk->cnt) == 0)
+ ion_secure_cma_free_chunk(sheap, chunk);
+ }
+ mutex_unlock(&sheap->chunk_lock);
+
+ return 0;
+}
+
+static int ion_secure_cma_shrinker(struct shrinker *shrinker,
+ struct shrink_control *sc)
+{
+ struct ion_cma_secure_heap *sheap = container_of(shrinker,
+ struct ion_cma_secure_heap, shrinker);
+ int nr_to_scan = sc->nr_to_scan;
+ struct list_head *entry, *_n;
+
+ if (nr_to_scan == 0)
+ return atomic_read(&sheap->total_pool_size);
+
+ /*
+ * CMA pages can only be used for movable allocation so don't free if
+ * the allocation isn't movable
+ */
+ if (!(sc->gfp_mask & __GFP_MOVABLE))
+ return atomic_read(&sheap->total_pool_size);
+
+ /*
+ * Allocation path may recursively call the shrinker. Don't shrink if
+ * that happens.
+ */
+ if (!mutex_trylock(&sheap->chunk_lock))
+ return -1;
+
+ list_for_each_safe(entry, _n, &sheap->chunks) {
+ struct ion_cma_alloc_chunk *chunk = container_of(entry,
+ struct ion_cma_alloc_chunk, entry);
+
+ if (nr_to_scan < 0)
+ break;
+
+ if (atomic_read(&chunk->cnt) == 0) {
+ nr_to_scan -= chunk->chunk_size;
+ ion_secure_cma_free_chunk(sheap, chunk);
+ }
+ }
+ mutex_unlock(&sheap->chunk_lock);
+
+ return atomic_read(&sheap->total_pool_size);
+}
+
+static void ion_secure_cma_free_from_pool(struct ion_cma_secure_heap *sheap,
+ dma_addr_t handle,
+ unsigned long len)
+{
+ struct list_head *entry, *_n;
+ int total_overlap = 0;
+
+ mutex_lock(&sheap->chunk_lock);
+ bitmap_clear(sheap->bitmap, (handle - sheap->base) >> PAGE_SHIFT,
+ len >> PAGE_SHIFT);
+
+ list_for_each_safe(entry, _n, &sheap->chunks) {
+ struct ion_cma_alloc_chunk *chunk = container_of(entry,
+ struct ion_cma_alloc_chunk, entry);
+ int overlap = intersect(chunk->handle,
+ chunk->chunk_size, handle, len);
+
+ /*
+ * Don't actually free this from the pool list yet, let either
+ * an explicit drain call or the shrinkers take care of the
+ * pool.
+ */
+ atomic_sub_return(overlap, &chunk->cnt);
+ BUG_ON(atomic_read(&chunk->cnt) < 0);
+
+ total_overlap += overlap;
+ }
+
+ BUG_ON(atomic_read(&sheap->total_pool_size) < 0);
+
+ if (total_overlap != len)
+ bad_math_dump(len, total_overlap, sheap, 0, handle);
+
+ mutex_unlock(&sheap->chunk_lock);
+}
+
/* ION CMA heap operations functions */
static struct ion_secure_cma_buffer_info *__ion_secure_cma_allocate(
struct ion_heap *heap, struct ion_buffer *buffer,
unsigned long len, unsigned long align,
unsigned long flags)
{
- struct device *dev = heap->priv;
+ struct ion_cma_secure_heap *sheap =
+ container_of(heap, struct ion_cma_secure_heap, heap);
struct ion_secure_cma_buffer_info *info;
- DEFINE_DMA_ATTRS(attrs);
- dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &attrs);
+ int ret;
- dev_dbg(dev, "Request buffer allocation len %ld\n", len);
+ dev_dbg(sheap->dev, "Request buffer allocation len %ld\n", len);
info = kzalloc(sizeof(struct ion_secure_cma_buffer_info), GFP_KERNEL);
if (!info) {
- dev_err(dev, "Can't allocate buffer info\n");
+ dev_err(sheap->dev, "Can't allocate buffer info\n");
return ION_CMA_ALLOCATE_FAILED;
}
- info->cpu_addr = dma_alloc_attrs(dev, len, &(info->handle), GFP_KERNEL,
- &attrs);
+ mutex_lock(&sheap->alloc_lock);
+ ret = ion_secure_cma_alloc_from_pool(sheap, &info->phys, len);
- if (!info->cpu_addr) {
- dev_err(dev, "Fail to allocate buffer\n");
- goto err;
+ if (ret) {
+ ret = ion_secure_cma_add_to_pool(sheap, len);
+ if (ret) {
+ dev_err(sheap->dev, "Fail to allocate buffer\n");
+ goto err;
+ }
+ ret = ion_secure_cma_alloc_from_pool(sheap, &info->phys, len);
+ if (ret) {
+ /*
+ * We just added memory to the pool, we shouldn't be
+ * failing to get memory
+ */
+ BUG();
+ }
}
+ mutex_unlock(&sheap->alloc_lock);
+ atomic_add(len, &sheap->total_allocated);
info->table = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
if (!info->table) {
- dev_err(dev, "Fail to allocate sg table\n");
+ dev_err(sheap->dev, "Fail to allocate sg table\n");
goto err;
}
- ion_secure_cma_get_sgtable(dev,
- info->table, info->cpu_addr, info->handle, len);
+ ion_secure_cma_get_sgtable(sheap->dev,
+ info->table, info->phys, len);
- info->secure.buffer = info->handle;
+ info->secure.buffer = info->phys;
/* keep this for memory release */
buffer->priv_virt = info;
- dev_dbg(dev, "Allocate buffer %p\n", buffer);
+ dev_dbg(sheap->dev, "Allocate buffer %p\n", buffer);
return info;
err:
@@ -167,16 +537,18 @@
static void ion_secure_cma_free(struct ion_buffer *buffer)
{
- struct device *dev = buffer->heap->priv;
+ struct ion_cma_secure_heap *sheap =
+ container_of(buffer->heap, struct ion_cma_secure_heap, heap);
struct ion_secure_cma_buffer_info *info = buffer->priv_virt;
- dev_dbg(dev, "Release buffer %p\n", buffer);
-
+ dev_dbg(sheap->dev, "Release buffer %p\n", buffer);
ion_cp_unsecure_buffer(buffer, 1);
+ atomic_sub(buffer->size, &sheap->total_allocated);
+ BUG_ON(atomic_read(&sheap->total_allocated) < 0);
/* release memory */
- dma_free_coherent(dev, buffer->size, info->cpu_addr, info->handle);
- sg_free_table(info->table);
+ ion_secure_cma_free_from_pool(sheap, info->phys, buffer->size);
/* release sg table */
+ sg_free_table(info->table);
kfree(info->table);
kfree(info);
}
@@ -184,13 +556,14 @@
static int ion_secure_cma_phys(struct ion_heap *heap, struct ion_buffer *buffer,
ion_phys_addr_t *addr, size_t *len)
{
- struct device *dev = heap->priv;
+ struct ion_cma_secure_heap *sheap =
+ container_of(heap, struct ion_cma_secure_heap, heap);
struct ion_secure_cma_buffer_info *info = buffer->priv_virt;
- dev_dbg(dev, "Return buffer %p physical address 0x%pa\n", buffer,
- &info->handle);
+ dev_dbg(sheap->dev, "Return buffer %p physical address 0x%pa\n", buffer,
+ &info->phys);
- *addr = info->handle;
+ *addr = info->phys;
*len = buffer->size;
return 0;
@@ -234,19 +607,20 @@
}
static int ion_secure_cma_print_debug(struct ion_heap *heap, struct seq_file *s,
- const struct rb_root *mem_map)
+ const struct list_head *mem_map)
{
+ struct ion_cma_secure_heap *sheap =
+ container_of(heap, struct ion_cma_secure_heap, heap);
+
if (mem_map) {
- struct rb_node *n;
+ struct mem_map_data *data;
seq_printf(s, "\nMemory Map\n");
seq_printf(s, "%16.s %14.s %14.s %14.s\n",
"client", "start address", "end address",
"size (hex)");
- for (n = rb_first(mem_map); n; n = rb_next(n)) {
- struct mem_map_data *data =
- rb_entry(n, struct mem_map_data, node);
+ list_for_each_entry(data, mem_map, node) {
const char *client_name = "(null)";
@@ -259,6 +633,10 @@
data->size, data->size);
}
}
+ seq_printf(s, "Total allocated: %x\n",
+ atomic_read(&sheap->total_allocated));
+ seq_printf(s, "Total pool size: %x\n",
+ atomic_read(&sheap->total_pool_size));
return 0;
}
@@ -278,22 +656,53 @@
struct ion_heap *ion_secure_cma_heap_create(struct ion_platform_heap *data)
{
- struct ion_heap *heap;
+ struct ion_cma_secure_heap *sheap;
+ int map_size = BITS_TO_LONGS(data->size >> PAGE_SHIFT) * sizeof(long);
- heap = kzalloc(sizeof(struct ion_heap), GFP_KERNEL);
-
- if (!heap)
+ sheap = kzalloc(sizeof(*sheap), GFP_KERNEL);
+ if (!sheap)
return ERR_PTR(-ENOMEM);
- heap->ops = &ion_secure_cma_ops;
- /* set device as private heaps data, later it will be
- * used to make the link with reserved CMA memory */
- heap->priv = data->priv;
- heap->type = ION_HEAP_TYPE_SECURE_DMA;
- return heap;
+ sheap->dev = data->priv;
+ mutex_init(&sheap->chunk_lock);
+ mutex_init(&sheap->alloc_lock);
+ sheap->heap.ops = &ion_secure_cma_ops;
+ sheap->heap.type = ION_HEAP_TYPE_SECURE_DMA;
+ sheap->npages = data->size >> PAGE_SHIFT;
+ sheap->base = data->base;
+ sheap->heap_size = data->size;
+ sheap->bitmap = kmalloc(map_size, GFP_KERNEL);
+ INIT_LIST_HEAD(&sheap->chunks);
+ INIT_WORK(&sheap->work, ion_secure_pool_pages);
+ sheap->shrinker.seeks = DEFAULT_SEEKS;
+ sheap->shrinker.batch = 0;
+ sheap->shrinker.shrink = ion_secure_cma_shrinker;
+ sheap->default_prefetch_size = sheap->heap_size;
+ register_shrinker(&sheap->shrinker);
+
+ if (!sheap->bitmap) {
+ kfree(sheap);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ if (data->extra_data) {
+ struct ion_cma_pdata *extra = data->extra_data;
+ sheap->default_prefetch_size = extra->default_prefetch_size;
+ }
+
+ /*
+ * we initially mark everything in the allocator as being free so that
+ * allocations can come in later
+ */
+ bitmap_fill(sheap->bitmap, sheap->npages);
+
+ return &sheap->heap;
}
void ion_secure_cma_heap_destroy(struct ion_heap *heap)
{
- kfree(heap);
+ struct ion_cma_secure_heap *sheap =
+ container_of(heap, struct ion_cma_secure_heap, heap);
+
+ kfree(sheap);
}
diff --git a/drivers/gpu/ion/ion_cp_heap.c b/drivers/gpu/ion/ion_cp_heap.c
index f2f4fad..8cb90e5 100644
--- a/drivers/gpu/ion/ion_cp_heap.c
+++ b/drivers/gpu/ion/ion_cp_heap.c
@@ -622,7 +622,7 @@
}
static int ion_cp_print_debug(struct ion_heap *heap, struct seq_file *s,
- const struct rb_root *mem_map)
+ const struct list_head *mem_map)
{
unsigned long total_alloc;
unsigned long total_size;
@@ -651,16 +651,14 @@
unsigned long size = cp_heap->total_size;
unsigned long end = base+size;
unsigned long last_end = base;
- struct rb_node *n;
+ struct mem_map_data *data;
seq_printf(s, "\nMemory Map\n");
seq_printf(s, "%16.s %14.s %14.s %14.s\n",
"client", "start address", "end address",
"size (hex)");
- for (n = rb_first(mem_map); n; n = rb_next(n)) {
- struct mem_map_data *data =
- rb_entry(n, struct mem_map_data, node);
+ list_for_each_entry(data, mem_map, node) {
const char *client_name = "(null)";
if (last_end < data->addr) {
diff --git a/drivers/gpu/ion/ion_heap.c b/drivers/gpu/ion/ion_heap.c
index 3d37541..73dd868 100644
--- a/drivers/gpu/ion/ion_heap.c
+++ b/drivers/gpu/ion/ion_heap.c
@@ -16,10 +16,16 @@
*/
#include <linux/err.h>
+#include <linux/freezer.h>
#include <linux/ion.h>
+#include <linux/kthread.h>
#include <linux/mm.h>
+#include <linux/rtmutex.h>
+#include <linux/sched.h>
#include <linux/scatterlist.h>
#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/highmem.h>
#include "ion_priv.h"
void *ion_heap_map_kernel(struct ion_heap *heap,
@@ -94,9 +100,149 @@
return 0;
}
+#define MAX_VMAP_RETRIES 10
+
+/**
+ * An optimized page-zero'ing function. vmaps arrays of pages in large
+ * chunks to minimize the number of memsets and vmaps/vunmaps.
+ *
+ * Note that the `pages' array should be composed of all 4K pages.
+ */
+int ion_heap_pages_zero(struct page **pages, int num_pages)
+{
+ int i, j, k, npages_to_vmap;
+ void *ptr = NULL;
+ /*
+ * It's cheaper just to use writecombine memory and skip the
+ * cache vs. using a cache memory and trying to flush it afterwards
+ */
+ pgprot_t pgprot = pgprot_writecombine(pgprot_kernel);
+
+ /*
+ * As an optimization, we manually zero out all of the pages
+ * in one fell swoop here. To safeguard against insufficient
+ * vmalloc space, we only vmap `npages_to_vmap' at a time,
+ * starting with a conservative estimate of 1/8 of the total
+ * number of vmalloc pages available.
+ */
+ npages_to_vmap = ((VMALLOC_END - VMALLOC_START)/8)
+ >> PAGE_SHIFT;
+ for (i = 0; i < num_pages; i += npages_to_vmap) {
+ npages_to_vmap = min(npages_to_vmap, num_pages - i);
+ for (j = 0; j < MAX_VMAP_RETRIES && npages_to_vmap;
+ ++j) {
+ ptr = vmap(&pages[i], npages_to_vmap,
+ VM_IOREMAP, pgprot);
+ if (ptr)
+ break;
+ else
+ npages_to_vmap >>= 1;
+ }
+ if (!ptr)
+ return -ENOMEM;
+
+ memset(ptr, 0, npages_to_vmap * PAGE_SIZE);
+ /*
+ * invalidate the cache to pick up the zeroing
+ */
+ for (k = 0; k < npages_to_vmap; k++) {
+ void *p = kmap_atomic(pages[i + k]);
+ phys_addr_t phys = page_to_phys(
+ pages[i + k]);
+
+ dmac_inv_range(p, p + PAGE_SIZE);
+ outer_inv_range(phys, phys + PAGE_SIZE);
+ kunmap_atomic(p);
+ }
+ vunmap(ptr);
+ }
+
+ return 0;
+}
+
+static int ion_heap_alloc_pages_mem(int page_tbl_size,
+ struct pages_mem *pages_mem)
+{
+ struct page **pages;
+ pages_mem->free_fn = kfree;
+ if (page_tbl_size > SZ_8K) {
+ /*
+ * Do fallback to ensure we have a balance between
+ * performance and availability.
+ */
+ pages = kmalloc(page_tbl_size,
+ __GFP_COMP | __GFP_NORETRY |
+ __GFP_NO_KSWAPD | __GFP_NOWARN);
+ if (!pages) {
+ pages = vmalloc(page_tbl_size);
+ pages_mem->free_fn = vfree;
+ }
+ } else {
+ pages = kmalloc(page_tbl_size, GFP_KERNEL);
+ }
+
+ if (!pages)
+ return -ENOMEM;
+
+ pages_mem->pages = pages;
+ return 0;
+}
+
+static void ion_heap_free_pages_mem(struct pages_mem *pages_mem)
+{
+ pages_mem->free_fn(pages_mem->pages);
+}
+
+int ion_heap_high_order_page_zero(struct page *page, int order)
+{
+ int i, ret;
+ struct pages_mem pages_mem;
+ int npages = 1 << order;
+ int page_tbl_size = sizeof(struct page *) * npages;
+
+ if (ion_heap_alloc_pages_mem(page_tbl_size, &pages_mem))
+ return -ENOMEM;
+
+ for (i = 0; i < (1 << order); ++i)
+ pages_mem.pages[i] = page + i;
+
+ ret = ion_heap_pages_zero(pages_mem.pages, npages);
+ ion_heap_free_pages_mem(&pages_mem);
+ return ret;
+}
+
int ion_heap_buffer_zero(struct ion_buffer *buffer)
{
struct sg_table *table = buffer->sg_table;
+ struct scatterlist *sg;
+ int i, j, ret = 0, npages = 0, page_tbl_size = 0;
+ struct pages_mem pages_mem;
+
+ for_each_sg(table->sgl, sg, table->nents, i) {
+ unsigned long len = sg_dma_len(sg);
+ int nrpages = len >> PAGE_SHIFT;
+ page_tbl_size += sizeof(struct page *) * nrpages;
+ }
+
+ if (ion_heap_alloc_pages_mem(page_tbl_size, &pages_mem))
+ return -ENOMEM;
+
+ for_each_sg(table->sgl, sg, table->nents, i) {
+ struct page *page = sg_page(sg);
+ unsigned long len = sg_dma_len(sg);
+
+ for (j = 0; j < len / PAGE_SIZE; j++)
+ pages_mem.pages[npages++] = page + j;
+ }
+
+ ret = ion_heap_pages_zero(pages_mem.pages, npages);
+ ion_heap_free_pages_mem(&pages_mem);
+ return ret;
+}
+
+int ion_heap_buffer_zero_old(struct ion_buffer *buffer)
+{
+ struct sg_table *table = buffer->sg_table;
pgprot_t pgprot;
struct scatterlist *sg;
struct vm_struct *vm_struct;
@@ -131,6 +277,122 @@
return ret;
}
+void ion_heap_free_page(struct ion_buffer *buffer, struct page *page,
+ unsigned int order)
+{
+ int i;
+
+ if (!ion_buffer_fault_user_mappings(buffer)) {
+ __free_pages(page, order);
+ return;
+ }
+ for (i = 0; i < (1 << order); i++)
+ __free_page(page + i);
+}
+
+void ion_heap_freelist_add(struct ion_heap *heap, struct ion_buffer * buffer)
+{
+ rt_mutex_lock(&heap->lock);
+ list_add(&buffer->list, &heap->free_list);
+ heap->free_list_size += buffer->size;
+ rt_mutex_unlock(&heap->lock);
+ wake_up(&heap->waitqueue);
+}
+
+size_t ion_heap_freelist_size(struct ion_heap *heap)
+{
+ size_t size;
+
+ rt_mutex_lock(&heap->lock);
+ size = heap->free_list_size;
+ rt_mutex_unlock(&heap->lock);
+
+ return size;
+}
+
+static size_t _ion_heap_freelist_drain(struct ion_heap *heap, size_t size,
+ bool skip_pools)
+{
+ struct ion_buffer *buffer, *tmp;
+ size_t total_drained = 0;
+
+ if (ion_heap_freelist_size(heap) == 0)
+ return 0;
+
+ rt_mutex_lock(&heap->lock);
+ if (size == 0)
+ size = heap->free_list_size;
+
+ list_for_each_entry_safe(buffer, tmp, &heap->free_list, list) {
+ if (total_drained >= size)
+ break;
+ list_del(&buffer->list);
+ ion_buffer_destroy(buffer);
+ heap->free_list_size -= buffer->size;
+ if (skip_pools)
+ buffer->flags |= ION_FLAG_FREED_FROM_SHRINKER;
+ total_drained += buffer->size;
+ }
+ rt_mutex_unlock(&heap->lock);
+
+ return total_drained;
+}
+
+size_t ion_heap_freelist_drain(struct ion_heap *heap, size_t size)
+{
+ return _ion_heap_freelist_drain(heap, size, false);
+}
+
+size_t ion_heap_freelist_drain_from_shrinker(struct ion_heap *heap, size_t size)
+{
+ return _ion_heap_freelist_drain(heap, size, true);
+}
+
+int ion_heap_deferred_free(void *data)
+{
+ struct ion_heap *heap = data;
+
+ while (true) {
+ struct ion_buffer *buffer;
+
+ wait_event_freezable(heap->waitqueue,
+ ion_heap_freelist_size(heap) > 0);
+
+ rt_mutex_lock(&heap->lock);
+ if (list_empty(&heap->free_list)) {
+ rt_mutex_unlock(&heap->lock);
+ continue;
+ }
+ buffer = list_first_entry(&heap->free_list, struct ion_buffer,
+ list);
+ list_del(&buffer->list);
+ heap->free_list_size -= buffer->size;
+ rt_mutex_unlock(&heap->lock);
+ ion_buffer_destroy(buffer);
+ }
+
+ return 0;
+}
+
+int ion_heap_init_deferred_free(struct ion_heap *heap)
+{
+ struct sched_param param = { .sched_priority = 0 };
+
+ INIT_LIST_HEAD(&heap->free_list);
+ heap->free_list_size = 0;
+ rt_mutex_init(&heap->lock);
+ init_waitqueue_head(&heap->waitqueue);
+ heap->task = kthread_run(ion_heap_deferred_free, heap,
+ "%s", heap->name);
+ sched_setscheduler(heap->task, SCHED_IDLE, ¶m);
+ if (IS_ERR(heap->task)) {
+ pr_err("%s: creating thread for deferred free failed\n",
+ __func__);
+ return PTR_RET(heap->task);
+ }
+ return 0;
+}
+
struct ion_heap *ion_heap_create(struct ion_platform_heap *heap_data)
{
struct ion_heap *heap = NULL;
diff --git a/drivers/gpu/ion/ion_iommu_heap.c b/drivers/gpu/ion/ion_iommu_heap.c
deleted file mode 100644
index d9e9e09..0000000
--- a/drivers/gpu/ion/ion_iommu_heap.c
+++ /dev/null
@@ -1,588 +0,0 @@
-/*
- * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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/err.h>
-#include <linux/io.h>
-#include <linux/msm_ion.h>
-#include <linux/mm.h>
-#include <linux/highmem.h>
-#include <linux/scatterlist.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/iommu.h>
-#include <linux/pfn.h>
-#include <linux/dma-mapping.h>
-#include "ion_priv.h"
-
-#include <asm/mach/map.h>
-#include <asm/page.h>
-#include <asm/cacheflush.h>
-#include <mach/iommu_domains.h>
-#include <trace/events/kmem.h>
-
-struct ion_iommu_heap {
- struct ion_heap heap;
- struct ion_page_pool **cached_pools;
- struct ion_page_pool **uncached_pools;
-};
-
-/*
- * We will attempt to allocate high-order pages and store those in an
- * sg_list. However, some APIs expect an array of struct page * where
- * each page is of size PAGE_SIZE. We use this extra structure to
- * carry around an array of such pages (derived from the high-order
- * pages with nth_page).
- */
-struct ion_iommu_priv_data {
- struct page **pages;
- unsigned int pages_uses_vmalloc;
- int nrpages;
- unsigned long size;
-};
-
-#define MAX_VMAP_RETRIES 10
-#define BAD_ORDER -1
-
-static const unsigned int orders[] = {9, 8, 4, 0};
-static const int num_orders = ARRAY_SIZE(orders);
-static unsigned int low_gfp_flags = __GFP_HIGHMEM | GFP_KERNEL | __GFP_ZERO;
-static unsigned int high_gfp_flags = (__GFP_HIGHMEM | __GFP_NORETRY
- | __GFP_NO_KSWAPD | __GFP_NOWARN |
- __GFP_IO | __GFP_FS | __GFP_ZERO);
-
-struct page_info {
- struct page *page;
- unsigned int order;
- struct list_head list;
-};
-
-static int order_to_index(unsigned int order)
-{
- int i;
- for (i = 0; i < num_orders; i++)
- if (order == orders[i])
- return i;
- BUG();
- return BAD_ORDER;
-}
-
-static unsigned int order_to_size(int order)
-{
- return PAGE_SIZE << order;
-}
-
-static struct page_info *alloc_largest_available(struct ion_iommu_heap *heap,
- unsigned long size,
- unsigned int max_order,
- unsigned long flags)
-{
- struct page *page;
- struct page_info *info;
- int i;
-
- for (i = 0; i < num_orders; i++) {
- gfp_t gfp;
- int idx = order_to_index(orders[i]);
- struct ion_page_pool *pool;
-
- if (idx == BAD_ORDER)
- continue;
-
- if (ION_IS_CACHED(flags)) {
- pool = heap->cached_pools[idx];
- BUG_ON(!pool);
- } else {
- pool = heap->uncached_pools[idx];
- BUG_ON(!pool);
- }
-
- if (size < order_to_size(orders[i]))
- continue;
- if (max_order < orders[i])
- continue;
-
- if (orders[i]) {
- gfp = high_gfp_flags;
- } else {
- gfp = low_gfp_flags;
- }
- trace_alloc_pages_iommu_start(gfp, orders[i]);
- if (flags & ION_FLAG_POOL_FORCE_ALLOC)
- page = alloc_pages(gfp, orders[i]);
- else
- page = ion_page_pool_alloc(pool);
- trace_alloc_pages_iommu_end(gfp, orders[i]);
- if (!page) {
- trace_alloc_pages_iommu_fail(gfp, orders[i]);
- continue;
- }
-
- info = kmalloc(sizeof(struct page_info), GFP_KERNEL);
- if (info) {
- info->page = page;
- info->order = orders[i];
- }
- return info;
- }
- return NULL;
-}
-
-static int ion_iommu_buffer_zero(struct ion_iommu_priv_data *data,
- bool is_cached)
-{
- int i, j, k;
- unsigned int npages_to_vmap;
- unsigned int total_pages;
- void *ptr = NULL;
- /*
- * It's cheaper just to use writecombine memory and skip the
- * cache vs. using a cache memory and trying to flush it afterwards
- */
- pgprot_t pgprot = pgprot_writecombine(pgprot_kernel);
-
- /*
- * As an optimization, we manually zero out all of the
- * pages in one fell swoop here. To safeguard against
- * insufficient vmalloc space, we only vmap
- * `npages_to_vmap' at a time, starting with a
- * conservative estimate of 1/8 of the total number of
- * vmalloc pages available. Note that the `pages'
- * array is composed of all 4K pages, irrespective of
- * the size of the pages on the sg list.
- */
- npages_to_vmap = ((VMALLOC_END - VMALLOC_START)/8)
- >> PAGE_SHIFT;
- total_pages = data->nrpages;
- for (i = 0; i < total_pages; i += npages_to_vmap) {
- npages_to_vmap = min(npages_to_vmap, total_pages - i);
- for (j = 0; j < MAX_VMAP_RETRIES && npages_to_vmap;
- ++j) {
- ptr = vmap(&data->pages[i], npages_to_vmap,
- VM_IOREMAP, pgprot);
- if (ptr)
- break;
- else
- npages_to_vmap >>= 1;
- }
- if (!ptr)
- return -ENOMEM;
-
- memset(ptr, 0, npages_to_vmap * PAGE_SIZE);
- if (is_cached) {
- /*
- * invalidate the cache to pick up the zeroing
- */
- for (k = 0; k < npages_to_vmap; k++) {
- void *p = kmap_atomic(data->pages[i + k]);
- phys_addr_t phys = page_to_phys(
- data->pages[i + k]);
-
- dmac_inv_range(p, p + PAGE_SIZE);
- outer_inv_range(phys, phys + PAGE_SIZE);
- kunmap_atomic(p);
- }
- }
- vunmap(ptr);
- }
-
- return 0;
-}
-
-static int ion_iommu_heap_allocate(struct ion_heap *heap,
- struct ion_buffer *buffer,
- unsigned long size, unsigned long align,
- unsigned long flags)
-{
- int ret, i;
- struct list_head pages_list;
- struct page_info *info, *tmp_info;
- struct ion_iommu_priv_data *data = NULL;
- struct ion_iommu_heap *iommu_heap =
- container_of(heap, struct ion_iommu_heap, heap);
-
- if (msm_use_iommu()) {
- struct scatterlist *sg;
- struct sg_table *table;
- int j;
- unsigned int num_large_pages = 0;
- unsigned long size_remaining = PAGE_ALIGN(size);
- unsigned int max_order = ION_IS_CACHED(flags) ? 0 : orders[0];
- unsigned int page_tbl_size;
-
- data = kmalloc(sizeof(*data), GFP_KERNEL);
- if (!data)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&pages_list);
- while (size_remaining > 0) {
- info = alloc_largest_available(iommu_heap,
- size_remaining,
- max_order,
- flags);
- if (!info) {
- ret = -ENOMEM;
- goto err_free_data;
- }
- list_add_tail(&info->list, &pages_list);
- size_remaining -= order_to_size(info->order);
- max_order = info->order;
- num_large_pages++;
- }
-
- data->size = PFN_ALIGN(size);
- data->nrpages = data->size >> PAGE_SHIFT;
- data->pages_uses_vmalloc = 0;
- page_tbl_size = sizeof(struct page *) * data->nrpages;
-
- if (page_tbl_size > SZ_8K) {
- /*
- * Do fallback to ensure we have a balance between
- * performance and availability.
- */
- data->pages = kmalloc(page_tbl_size,
- __GFP_COMP | __GFP_NORETRY |
- __GFP_NO_KSWAPD | __GFP_NOWARN);
- if (!data->pages) {
- data->pages = vmalloc(page_tbl_size);
- data->pages_uses_vmalloc = 1;
- }
- } else {
- data->pages = kmalloc(page_tbl_size, GFP_KERNEL);
- }
- if (!data->pages) {
- ret = -ENOMEM;
- goto err_free_data;
- }
-
- table = buffer->sg_table =
- kzalloc(sizeof(struct sg_table), GFP_KERNEL);
-
- if (!table) {
- ret = -ENOMEM;
- goto err1;
- }
- ret = sg_alloc_table(table, num_large_pages, GFP_KERNEL);
- if (ret)
- goto err2;
-
- i = 0;
- sg = table->sgl;
- list_for_each_entry_safe(info, tmp_info, &pages_list, list) {
- struct page *page = info->page;
- sg_set_page(sg, page, order_to_size(info->order), 0);
- sg_dma_address(sg) = sg_phys(sg);
- sg = sg_next(sg);
- for (j = 0; j < (1 << info->order); ++j)
- data->pages[i++] = nth_page(page, j);
- list_del(&info->list);
- kfree(info);
- }
-
-
- if (flags & ION_FLAG_POOL_FORCE_ALLOC) {
- ret = ion_iommu_buffer_zero(data, ION_IS_CACHED(flags));
- if (ret) {
- pr_err("Couldn't vmap the pages for zeroing\n");
- goto err3;
- }
-
-
- if (!ION_IS_CACHED(flags))
- dma_sync_sg_for_device(NULL, table->sgl,
- table->nents,
- DMA_BIDIRECTIONAL);
-
- }
- buffer->priv_virt = data;
- return 0;
-
- } else {
- return -ENOMEM;
- }
-
-
-err3:
- sg_free_table(buffer->sg_table);
-err2:
- kfree(buffer->sg_table);
- buffer->sg_table = 0;
-err1:
- if (data->pages_uses_vmalloc)
- vfree(data->pages);
- else
- kfree(data->pages);
-err_free_data:
- kfree(data);
-
- list_for_each_entry_safe(info, tmp_info, &pages_list, list) {
- if (info->page)
- __free_pages(info->page, info->order);
- list_del(&info->list);
- kfree(info);
- }
- return ret;
-}
-
-static void ion_iommu_heap_free(struct ion_buffer *buffer)
-{
- int i;
- struct scatterlist *sg;
- struct sg_table *table = buffer->sg_table;
- struct ion_iommu_priv_data *data = buffer->priv_virt;
- bool cached = ion_buffer_cached(buffer);
- struct ion_iommu_heap *iommu_heap =
- container_of(buffer->heap, struct ion_iommu_heap, heap);
-
- if (!table)
- return;
- if (!data)
- return;
-
- if (!(buffer->flags & ION_FLAG_POOL_FORCE_ALLOC))
- ion_iommu_buffer_zero(data, ION_IS_CACHED(buffer->flags));
-
- for_each_sg(table->sgl, sg, table->nents, i) {
- int order = get_order(sg_dma_len(sg));
- int idx = order_to_index(order);
- struct ion_page_pool *pool;
-
- if (idx == BAD_ORDER) {
- WARN_ON(1);
- continue;
- }
-
- if (cached)
- pool = iommu_heap->cached_pools[idx];
- else
- pool = iommu_heap->uncached_pools[idx];
-
- if (buffer->flags & ION_FLAG_POOL_FORCE_ALLOC)
- __free_pages(sg_page(sg), order);
- else
- ion_page_pool_free(pool, sg_page(sg));
- }
-
- sg_free_table(table);
- kfree(table);
- table = 0;
- if (data->pages_uses_vmalloc)
- vfree(data->pages);
- else
- kfree(data->pages);
- kfree(data);
-}
-
-void *ion_iommu_heap_map_kernel(struct ion_heap *heap,
- struct ion_buffer *buffer)
-{
- struct ion_iommu_priv_data *data = buffer->priv_virt;
- pgprot_t page_prot = PAGE_KERNEL;
-
- if (!data)
- return NULL;
-
- if (!ION_IS_CACHED(buffer->flags))
- page_prot = pgprot_writecombine(page_prot);
-
- buffer->vaddr = vmap(data->pages, data->nrpages, VM_IOREMAP, page_prot);
-
- return buffer->vaddr;
-}
-
-void ion_iommu_heap_unmap_kernel(struct ion_heap *heap,
- struct ion_buffer *buffer)
-{
- if (!buffer->vaddr)
- return;
-
- vunmap(buffer->vaddr);
- buffer->vaddr = NULL;
-}
-
-int ion_iommu_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer,
- struct vm_area_struct *vma)
-{
- struct sg_table *table = buffer->sg_table;
- unsigned long addr = vma->vm_start;
- unsigned long offset = vma->vm_pgoff * PAGE_SIZE;
- struct scatterlist *sg;
- int i;
-
- if (!ION_IS_CACHED(buffer->flags))
- vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
-
- for_each_sg(table->sgl, sg, table->nents, i) {
- struct page *page = sg_page(sg);
- unsigned long remainder = vma->vm_end - addr;
- unsigned long len = sg_dma_len(sg);
-
- if (offset >= sg_dma_len(sg)) {
- offset -= sg_dma_len(sg);
- continue;
- } else if (offset) {
- page += offset / PAGE_SIZE;
- len = sg_dma_len(sg) - offset;
- offset = 0;
- }
- len = min(len, remainder);
- remap_pfn_range(vma, addr, page_to_pfn(page), len,
- vma->vm_page_prot);
- addr += len;
- if (addr >= vma->vm_end)
- return 0;
- }
- return 0;
-}
-
-static struct sg_table *ion_iommu_heap_map_dma(struct ion_heap *heap,
- struct ion_buffer *buffer)
-{
- return buffer->sg_table;
-}
-
-static void ion_iommu_heap_unmap_dma(struct ion_heap *heap,
- struct ion_buffer *buffer)
-{
-}
-
-static int ion_iommu_heap_debug_show(struct ion_heap *heap, struct seq_file *s,
- void *unused)
-{
-
- struct ion_iommu_heap *iommu_heap = container_of(heap,
- struct ion_iommu_heap,
- heap);
- int i;
- unsigned long total = 0;
-
- seq_printf(s, "Cached Pools:\n");
- for (i = 0; i < num_orders; i++) {
- struct ion_page_pool *pool = iommu_heap->cached_pools[i];
- seq_printf(s, "%d order %u highmem pages in pool = %lx total\n",
- pool->high_count, pool->order,
- (1 << pool->order) * PAGE_SIZE * pool->high_count);
- seq_printf(s, "%d order %u lowmem pages in pool = %lx total\n",
- pool->low_count, pool->order,
- (1 << pool->order) * PAGE_SIZE * pool->low_count);
-
- total += (1 << pool->order) * PAGE_SIZE *
- (pool->low_count + pool->high_count);
- }
-
- seq_printf(s, "Uncached Pools:\n");
- for (i = 0; i < num_orders; i++) {
- struct ion_page_pool *pool = iommu_heap->uncached_pools[i];
- seq_printf(s, "%d order %u highmem pages in pool = %lx total\n",
- pool->high_count, pool->order,
- (1 << pool->order) * PAGE_SIZE * pool->high_count);
- seq_printf(s, "%d order %u lowmem pages in pool = %lx total\n",
- pool->low_count, pool->order,
- (1 << pool->order) * PAGE_SIZE * pool->low_count);
-
- total += (1 << pool->order) * PAGE_SIZE *
- (pool->low_count + pool->high_count);
- }
- seq_printf(s, "Total bytes in pool: %lx\n", total);
- return 0;
-}
-
-static struct ion_heap_ops iommu_heap_ops = {
- .allocate = ion_iommu_heap_allocate,
- .free = ion_iommu_heap_free,
- .map_user = ion_iommu_heap_map_user,
- .map_kernel = ion_iommu_heap_map_kernel,
- .unmap_kernel = ion_iommu_heap_unmap_kernel,
- .map_dma = ion_iommu_heap_map_dma,
- .unmap_dma = ion_iommu_heap_unmap_dma,
-};
-
-struct ion_heap *ion_iommu_heap_create(struct ion_platform_heap *heap_data)
-{
- struct ion_iommu_heap *iommu_heap;
- int i;
-
- iommu_heap = kzalloc(sizeof(struct ion_iommu_heap), GFP_KERNEL);
- if (!iommu_heap)
- return ERR_PTR(-ENOMEM);
-
- iommu_heap->heap.ops = &iommu_heap_ops;
- iommu_heap->heap.type = ION_HEAP_TYPE_IOMMU;
- iommu_heap->uncached_pools = kzalloc(
- sizeof(struct ion_page_pool *) * num_orders,
- GFP_KERNEL);
- if (!iommu_heap->uncached_pools)
- goto err_alloc_uncached_pools;
-
- iommu_heap->cached_pools = kzalloc(
- sizeof(struct ion_page_pool *) * num_orders,
- GFP_KERNEL);
-
- if (!iommu_heap->cached_pools)
- goto err_alloc_cached_pools;
-
- for (i = 0; i < num_orders; i++) {
- struct ion_page_pool *pool;
- gfp_t gfp_flags;
-
- if (orders[i])
- gfp_flags = high_gfp_flags | __GFP_ZERO;
- else
- gfp_flags = low_gfp_flags | __GFP_ZERO;
- pool = ion_page_pool_create(gfp_flags, orders[i]);
- if (!pool)
- goto err_create_cached_pool;
- iommu_heap->cached_pools[i] = pool;
- }
-
- for (i = 0; i < num_orders; i++) {
- struct ion_page_pool *pool;
- gfp_t gfp_flags;
-
- if (orders[i])
- gfp_flags = high_gfp_flags | __GFP_ZERO;
- else
- gfp_flags = low_gfp_flags | __GFP_ZERO;
- pool = ion_page_pool_create(gfp_flags, orders[i]);
- if (!pool)
- goto err_create_uncached_pool;
- iommu_heap->uncached_pools[i] = pool;
- }
- iommu_heap->heap.debug_show = ion_iommu_heap_debug_show;
- return &iommu_heap->heap;
-
-err_create_uncached_pool:
- for (i = 0; i < num_orders; i++)
- if (iommu_heap->cached_pools[i])
- ion_page_pool_destroy(iommu_heap->uncached_pools[i]);
-
-
-err_create_cached_pool:
- for (i = 0; i < num_orders; i++)
- if (iommu_heap->uncached_pools[i])
- ion_page_pool_destroy(iommu_heap->cached_pools[i]);
-
- kfree(iommu_heap->cached_pools);
-err_alloc_cached_pools:
- kfree(iommu_heap->uncached_pools);
-err_alloc_uncached_pools:
- kfree(iommu_heap);
- return ERR_PTR(-ENOMEM);
-}
-
-void ion_iommu_heap_destroy(struct ion_heap *heap)
-{
- struct ion_iommu_heap *iommu_heap =
- container_of(heap, struct ion_iommu_heap, heap);
-
- kfree(iommu_heap);
- iommu_heap = NULL;
-}
diff --git a/drivers/gpu/ion/ion_page_pool.c b/drivers/gpu/ion/ion_page_pool.c
index 495dd24..cc2a36d 100644
--- a/drivers/gpu/ion/ion_page_pool.c
+++ b/drivers/gpu/ion/ion_page_pool.c
@@ -21,14 +21,9 @@
#include <linux/list.h>
#include <linux/module.h>
#include <linux/slab.h>
-#include <linux/shrinker.h>
+#include <linux/vmalloc.h>
#include "ion_priv.h"
-/* #define DEBUG_PAGE_POOL_SHRINKER */
-
-static struct plist_head pools = PLIST_HEAD_INIT(pools);
-static struct shrinker shrinker;
-
struct ion_page_pool_item {
struct page *page;
struct list_head list;
@@ -36,18 +31,27 @@
static void *ion_page_pool_alloc_pages(struct ion_page_pool *pool)
{
- struct page *page = alloc_pages(pool->gfp_mask, pool->order);
+ struct page *page;
struct scatterlist sg;
+ page = alloc_pages(pool->gfp_mask & ~__GFP_ZERO, pool->order);
+
if (!page)
return NULL;
+ if (pool->gfp_mask & __GFP_ZERO)
+ if (ion_heap_high_order_page_zero(page, pool->order))
+ goto error_free_pages;
+
sg_init_table(&sg, 1);
sg_set_page(&sg, page, PAGE_SIZE << pool->order, 0);
sg_dma_address(&sg) = sg_phys(&sg);
dma_sync_sg_for_device(NULL, &sg, 1, DMA_BIDIRECTIONAL);
return page;
+error_free_pages:
+ __free_pages(page, pool->order);
+ return NULL;
}
static void ion_page_pool_free_pages(struct ion_page_pool *pool,
@@ -128,110 +132,46 @@
ion_page_pool_free_pages(pool, page);
}
-#ifdef DEBUG_PAGE_POOL_SHRINKER
-static int debug_drop_pools_set(void *data, u64 val)
+static int ion_page_pool_total(struct ion_page_pool *pool, bool high)
{
- struct shrink_control sc;
- int objs;
-
- sc.gfp_mask = -1;
- sc.nr_to_scan = 0;
-
- if (!val)
- return 0;
-
- objs = shrinker.shrink(&shrinker, &sc);
- sc.nr_to_scan = objs;
-
- shrinker.shrink(&shrinker, &sc);
- return 0;
-}
-
-static int debug_drop_pools_get(void *data, u64 *val)
-{
- struct shrink_control sc;
- int objs;
-
- sc.gfp_mask = -1;
- sc.nr_to_scan = 0;
-
- objs = shrinker.shrink(&shrinker, &sc);
- *val = objs;
- return 0;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(debug_drop_pools_fops, debug_drop_pools_get,
- debug_drop_pools_set, "%llu\n");
-
-static int debug_grow_pools_set(void *data, u64 val)
-{
- struct ion_page_pool *pool;
- struct page *page;
-
- plist_for_each_entry(pool, &pools, list) {
- if (val != pool->list.prio)
- continue;
- page = ion_page_pool_alloc_pages(pool);
- if (page)
- ion_page_pool_add(pool, page);
- }
-
- return 0;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(debug_grow_pools_fops, debug_drop_pools_get,
- debug_grow_pools_set, "%llu\n");
-#endif
-
-static int ion_page_pool_total(bool high)
-{
- struct ion_page_pool *pool;
int total = 0;
- plist_for_each_entry(pool, &pools, list) {
- total += high ? (pool->high_count + pool->low_count) *
- (1 << pool->order) :
+ total += high ? (pool->high_count + pool->low_count) *
+ (1 << pool->order) :
pool->low_count * (1 << pool->order);
- }
return total;
}
-static int ion_page_pool_shrink(struct shrinker *shrinker,
- struct shrink_control *sc)
+int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask,
+ int nr_to_scan)
{
- struct ion_page_pool *pool;
int nr_freed = 0;
int i;
bool high;
- int nr_to_scan = sc->nr_to_scan;
- if (sc->gfp_mask & __GFP_HIGHMEM)
- high = true;
+ high = gfp_mask & __GFP_HIGHMEM;
if (nr_to_scan == 0)
- return ion_page_pool_total(high);
+ return ion_page_pool_total(pool, high);
- plist_for_each_entry(pool, &pools, list) {
- for (i = 0; i < nr_to_scan; i++) {
- struct page *page;
+ for (i = 0; i < nr_to_scan; i++) {
+ struct page *page;
- mutex_lock(&pool->mutex);
- if (high && pool->high_count) {
- page = ion_page_pool_remove(pool, true);
- } else if (pool->low_count) {
- page = ion_page_pool_remove(pool, false);
- } else {
- mutex_unlock(&pool->mutex);
- break;
- }
+ mutex_lock(&pool->mutex);
+ if (high && pool->high_count) {
+ page = ion_page_pool_remove(pool, true);
+ } else if (pool->low_count) {
+ page = ion_page_pool_remove(pool, false);
+ } else {
mutex_unlock(&pool->mutex);
- ion_page_pool_free_pages(pool, page);
- nr_freed += (1 << pool->order);
+ break;
}
- nr_to_scan -= i;
+ mutex_unlock(&pool->mutex);
+ ion_page_pool_free_pages(pool, page);
+ nr_freed += (1 << pool->order);
}
- return ion_page_pool_total(high);
+ return nr_freed;
}
struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order)
@@ -248,35 +188,22 @@
pool->order = order;
mutex_init(&pool->mutex);
plist_node_init(&pool->list, order);
- plist_add(&pool->list, &pools);
return pool;
}
void ion_page_pool_destroy(struct ion_page_pool *pool)
{
- plist_del(&pool->list, &pools);
kfree(pool);
}
static int __init ion_page_pool_init(void)
{
- shrinker.shrink = ion_page_pool_shrink;
- shrinker.seeks = DEFAULT_SEEKS;
- shrinker.batch = 0;
- register_shrinker(&shrinker);
-#ifdef DEBUG_PAGE_POOL_SHRINKER
- debugfs_create_file("ion_pools_shrink", 0644, NULL, NULL,
- &debug_drop_pools_fops);
- debugfs_create_file("ion_pools_grow", 0644, NULL, NULL,
- &debug_grow_pools_fops);
-#endif
return 0;
}
static void __exit ion_page_pool_exit(void)
{
- unregister_shrinker(&shrinker);
}
module_init(ion_page_pool_init);
diff --git a/drivers/gpu/ion/ion_priv.h b/drivers/gpu/ion/ion_priv.h
index e3fbbda..c57efc1 100644
--- a/drivers/gpu/ion/ion_priv.h
+++ b/drivers/gpu/ion/ion_priv.h
@@ -85,11 +85,16 @@
char task_comm[TASK_COMM_LEN];
pid_t pid;
};
+void ion_buffer_destroy(struct ion_buffer *buffer);
/**
* struct ion_heap_ops - ops to operate on a given heap
* @allocate: allocate memory
- * @free: free memory
+ * @free: free memory. Will be called with
+ * ION_FLAG_FREED_FROM_SHRINKER set in buffer flags when
+ * called from a shrinker. In that case, the pages being
+ * free'd must be truly free'd back to the system, not put
+ * in a page pool or otherwise cached.
* @phys get physical address of a buffer (only define on
* physically contiguous heaps)
* @map_dma map the memory for dma to a scatterlist
@@ -115,7 +120,7 @@
struct vm_area_struct *vma);
void (*unmap_user) (struct ion_heap *mapper, struct ion_buffer *buffer);
int (*print_debug)(struct ion_heap *heap, struct seq_file *s,
- const struct rb_root *mem_map);
+ const struct list_head *mem_map);
int (*secure_heap)(struct ion_heap *heap, int version, void *data);
int (*unsecure_heap)(struct ion_heap *heap, int version, void *data);
int (*secure_buffer)(struct ion_buffer *buffer, int version,
@@ -139,8 +144,13 @@
* allocating. These are specified by platform data and
* MUST be unique
* @name: used for debugging
+ * @shrinker: a shrinker for the heap, if the heap caches system
+ * memory, it must define a shrinker to return it on low
+ * memory conditions, this includes system memory cached
+ * in the deferred free lists for heaps that support it
* @priv: private heap data
* @free_list: free list head if deferred free is used
+ * @free_list_size size of the deferred free list in bytes
* @lock: protects the free list
* @waitqueue: queue to wait on from deferred free thread
* @task: task struct of deferred free thread
@@ -160,8 +170,10 @@
unsigned long flags;
unsigned int id;
const char *name;
+ struct shrinker shrinker;
void *priv;
struct list_head free_list;
+ size_t free_list_size;
struct rt_mutex lock;
wait_queue_head_t waitqueue;
struct task_struct *task;
@@ -209,6 +221,11 @@
*/
void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap);
+struct pages_mem {
+ struct page **pages;
+ void (*free_fn) (const void *);
+};
+
/**
* some helpers for common operations on buffers using the sg_table
* and vaddr fields
@@ -217,7 +234,69 @@
void ion_heap_unmap_kernel(struct ion_heap *, struct ion_buffer *);
int ion_heap_map_user(struct ion_heap *, struct ion_buffer *,
struct vm_area_struct *);
+int ion_heap_pages_zero(struct page **pages, int num_pages);
int ion_heap_buffer_zero(struct ion_buffer *buffer);
+int ion_heap_high_order_page_zero(struct page *page, int order);
+
+/**
+ * ion_heap_init_deferred_free -- initialize deferred free functionality
+ * @heap: the heap
+ *
+ * If a heap sets the ION_HEAP_FLAG_DEFER_FREE flag this function will
+ * be called to setup deferred frees. Calls to free the buffer will
+ * return immediately and the actual free will occur some time later
+ */
+int ion_heap_init_deferred_free(struct ion_heap *heap);
+
+/**
+ * ion_heap_freelist_add - add a buffer to the deferred free list
+ * @heap: the heap
+ * @buffer: the buffer
+ *
+ * Adds an item to the deferred freelist.
+ */
+void ion_heap_freelist_add(struct ion_heap *heap, struct ion_buffer *buffer);
+
+/**
+ * ion_heap_freelist_drain - drain the deferred free list
+ * @heap: the heap
+ * @size: ammount of memory to drain in bytes
+ *
+ * Drains the indicated amount of memory from the deferred freelist immediately.
+ * Returns the total amount freed. The total freed may be higher depending
+ * on the size of the items in the list, or lower if there is insufficient
+ * total memory on the freelist.
+ */
+size_t ion_heap_freelist_drain(struct ion_heap *heap, size_t size);
+
+/**
+ * ion_heap_freelist_drain_from_shrinker - drain the deferred free
+ * list, skipping any heap-specific
+ * pooling or caching mechanisms
+ *
+ * @heap: the heap
+ * @size: amount of memory to drain in bytes
+ *
+ * Drains the indicated amount of memory from the deferred freelist immediately.
+ * Returns the total amount freed. The total freed may be higher depending
+ * on the size of the items in the list, or lower if there is insufficient
+ * total memory on the freelist.
+ *
+ * Unlike with @ion_heap_freelist_drain, don't put any pages back into
+ * page pools or otherwise cache the pages. Everything must be
+ * genuinely free'd back to the system. If you're free'ing from a
+ * shrinker you probably want to use this. Note that this relies on
+ * the heap.ops.free callback honoring the
+ * ION_FLAG_FREED_FROM_SHRINKER flag.
+ */
+size_t ion_heap_freelist_drain_from_shrinker(struct ion_heap *heap,
+ size_t size);
+
+/**
+ * ion_heap_freelist_size - returns the size of the freelist in bytes
+ * @heap: the heap
+ */
+size_t ion_heap_freelist_size(struct ion_heap *heap);
/**
@@ -288,8 +367,6 @@
struct list_head high_items;
struct list_head low_items;
struct mutex mutex;
- void *(*alloc)(struct ion_page_pool *pool);
- void (*free)(struct ion_page_pool *pool, struct page *page);
gfp_t gfp_mask;
unsigned int order;
struct plist_node list;
@@ -300,4 +377,22 @@
void *ion_page_pool_alloc(struct ion_page_pool *);
void ion_page_pool_free(struct ion_page_pool *, struct page *);
+/** ion_page_pool_shrink - shrinks the size of the memory cached in the pool
+ * @pool: the pool
+ * @gfp_mask: the memory type to reclaim
+ * @nr_to_scan: number of items to shrink in pages
+ *
+ * returns the number of items freed in pages
+ */
+int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask,
+ int nr_to_scan);
+
+int ion_walk_heaps(struct ion_client *client, int heap_id, void *data,
+ int (*f)(struct ion_heap *heap, void *data));
+
+struct ion_handle *ion_handle_get_by_id(struct ion_client *client,
+ int id);
+
+int ion_handle_put(struct ion_handle *handle);
+
#endif /* _ION_PRIV_H */
diff --git a/drivers/gpu/ion/ion_removed_heap.c b/drivers/gpu/ion/ion_removed_heap.c
index 84d8d37..94d4a25 100644
--- a/drivers/gpu/ion/ion_removed_heap.c
+++ b/drivers/gpu/ion/ion_removed_heap.c
@@ -233,7 +233,7 @@
}
static int ion_removed_print_debug(struct ion_heap *heap, struct seq_file *s,
- const struct rb_root *mem_map)
+ const struct list_head *mem_map)
{
struct ion_removed_heap *removed_heap =
container_of(heap, struct ion_removed_heap, heap);
@@ -247,16 +247,14 @@
unsigned long size = removed_heap->total_size;
unsigned long end = base+size;
unsigned long last_end = base;
- struct rb_node *n;
+ struct mem_map_data *data;
seq_printf(s, "\nMemory Map\n");
seq_printf(s, "%16.s %14.s %14.s %14.s\n",
"client", "start address", "end address",
"size (hex)");
- for (n = rb_first(mem_map); n; n = rb_next(n)) {
- struct mem_map_data *data =
- rb_entry(n, struct mem_map_data, node);
+ list_for_each_entry(data, mem_map, node) {
const char *client_name = "(null)";
if (last_end < data->addr) {
diff --git a/drivers/gpu/ion/ion_system_heap.c b/drivers/gpu/ion/ion_system_heap.c
index 44bb86f..be1a89c 100644
--- a/drivers/gpu/ion/ion_system_heap.c
+++ b/drivers/gpu/ion/ion_system_heap.c
@@ -53,7 +53,8 @@
struct ion_system_heap {
struct ion_heap heap;
- struct ion_page_pool **pools;
+ struct ion_page_pool **uncached_pools;
+ struct ion_page_pool **cached_pools;
};
struct page_info {
@@ -68,29 +69,14 @@
{
bool cached = ion_buffer_cached(buffer);
bool split_pages = ion_buffer_fault_user_mappings(buffer);
- struct ion_page_pool *pool = heap->pools[order_to_index(order)];
struct page *page;
+ struct ion_page_pool *pool;
- if (!cached) {
- page = ion_page_pool_alloc(pool);
- } else {
- struct scatterlist sg;
- gfp_t gfp_flags = low_order_gfp_flags;
-
- if (order > 4)
- gfp_flags = high_order_gfp_flags;
- trace_alloc_pages_sys_start(gfp_flags, order);
- page = alloc_pages(gfp_flags, order);
- trace_alloc_pages_sys_end(gfp_flags, order);
- if (!page) {
- trace_alloc_pages_sys_fail(gfp_flags, order);
- return 0;
- }
- sg_init_table(&sg, 1);
- sg_set_page(&sg, page, PAGE_SIZE << order, 0);
- sg_dma_address(&sg) = sg_phys(&sg);
- dma_sync_sg_for_device(NULL, &sg, 1, DMA_BIDIRECTIONAL);
- }
+ if (!cached)
+ pool = heap->uncached_pools[order_to_index(order)];
+ else
+ pool = heap->cached_pools[order_to_index(order)];
+ page = ion_page_pool_alloc(pool);
if (!page)
return 0;
@@ -107,14 +93,20 @@
bool split_pages = ion_buffer_fault_user_mappings(buffer);
int i;
- if (!cached) {
- struct ion_page_pool *pool = heap->pools[order_to_index(order)];
+ if ((buffer->flags & ION_FLAG_FREED_FROM_SHRINKER)) {
+ if (split_pages) {
+ for (i = 0; i < (1 << order); i++)
+ __free_page(page + i);
+ } else {
+ __free_pages(page, order);
+ }
+ } else {
+ struct ion_page_pool *pool;
+ if (cached)
+ pool = heap->cached_pools[order_to_index(order)];
+ else
+ pool = heap->uncached_pools[order_to_index(order)];
ion_page_pool_free(pool, page);
- } else if (split_pages) {
- for (i = 0; i < (1 << order); i++)
- __free_page(page + i);
- } else {
- __free_pages(page, order);
}
}
@@ -212,7 +204,7 @@
err1:
kfree(table);
err:
- list_for_each_entry(info, &pages, list) {
+ list_for_each_entry_safe(info, tmp_info, &pages, list) {
free_buffer_page(sys_heap, buffer, info->page, info->order);
kfree(info);
}
@@ -226,14 +218,11 @@
struct ion_system_heap,
heap);
struct sg_table *table = buffer->sg_table;
- bool cached = ion_buffer_cached(buffer);
struct scatterlist *sg;
LIST_HEAD(pages);
int i;
- /* uncached pages come from the page pools, zero them before returning
- for security purposes (other allocations are zerod at alloc time */
- if (!cached)
+ if (!(buffer->flags & ION_FLAG_FREED_FROM_SHRINKER))
ion_heap_buffer_zero(buffer);
for_each_sg(table->sgl, sg, table->nents, i)
@@ -265,6 +254,56 @@
.map_user = ion_heap_map_user,
};
+static int ion_system_heap_shrink(struct shrinker *shrinker,
+ struct shrink_control *sc) {
+
+ struct ion_heap *heap = container_of(shrinker, struct ion_heap,
+ shrinker);
+ struct ion_system_heap *sys_heap = container_of(heap,
+ struct ion_system_heap,
+ heap);
+ int nr_total = 0;
+ int nr_freed = 0;
+ int i;
+
+ if (sc->nr_to_scan == 0)
+ goto end;
+
+ /* shrink the free list first, no point in zeroing the memory if
+ we're just going to reclaim it. Also, skip any possible
+ page pooling */
+ nr_freed += ion_heap_freelist_drain_from_shrinker(
+ heap, sc->nr_to_scan * PAGE_SIZE) / PAGE_SIZE;
+
+ if (nr_freed >= sc->nr_to_scan)
+ goto end;
+
+ for (i = 0; i < num_orders; i++) {
+ nr_freed += ion_page_pool_shrink(sys_heap->uncached_pools[i],
+ sc->gfp_mask, sc->nr_to_scan);
+ if (nr_freed >= sc->nr_to_scan)
+ goto end;
+
+ nr_freed += ion_page_pool_shrink(sys_heap->cached_pools[i],
+ sc->gfp_mask, sc->nr_to_scan);
+ if (nr_freed >= sc->nr_to_scan)
+ goto end;
+ }
+
+end:
+ /* total number of items is whatever the page pools are holding
+ plus whatever's in the freelist */
+ for (i = 0; i < num_orders; i++) {
+ nr_total += ion_page_pool_shrink(
+ sys_heap->uncached_pools[i], sc->gfp_mask, 0);
+ nr_total += ion_page_pool_shrink(
+ sys_heap->cached_pools[i], sc->gfp_mask, 0);
+ }
+ nr_total += ion_heap_freelist_size(heap) / PAGE_SIZE;
+ return nr_total;
+
+}
+
static int ion_system_heap_debug_show(struct ion_heap *heap, struct seq_file *s,
void *unused)
{
@@ -274,32 +313,51 @@
heap);
int i;
for (i = 0; i < num_orders; i++) {
- struct ion_page_pool *pool = sys_heap->pools[i];
- seq_printf(s, "%d order %u highmem pages in pool = %lu total\n",
- pool->high_count, pool->order,
- (1 << pool->order) * PAGE_SIZE * pool->high_count);
- seq_printf(s, "%d order %u lowmem pages in pool = %lu total\n",
- pool->low_count, pool->order,
- (1 << pool->order) * PAGE_SIZE * pool->low_count);
+ struct ion_page_pool *pool = sys_heap->uncached_pools[i];
+ seq_printf(s,
+ "%d order %u highmem pages in uncached pool = %lu total\n",
+ pool->high_count, pool->order,
+ (1 << pool->order) * PAGE_SIZE * pool->high_count);
+ seq_printf(s,
+ "%d order %u lowmem pages in uncached pool = %lu total\n",
+ pool->low_count, pool->order,
+ (1 << pool->order) * PAGE_SIZE * pool->low_count);
}
+
+ for (i = 0; i < num_orders; i++) {
+ struct ion_page_pool *pool = sys_heap->cached_pools[i];
+ seq_printf(s,
+ "%d order %u highmem pages in cached pool = %lu total\n",
+ pool->high_count, pool->order,
+ (1 << pool->order) * PAGE_SIZE * pool->high_count);
+ seq_printf(s,
+ "%d order %u lowmem pages in cached pool = %lu total\n",
+ pool->low_count, pool->order,
+ (1 << pool->order) * PAGE_SIZE * pool->low_count);
+ }
+
return 0;
}
-struct ion_heap *ion_system_heap_create(struct ion_platform_heap *unused)
-{
- struct ion_system_heap *heap;
- int i;
- heap = kzalloc(sizeof(struct ion_system_heap), GFP_KERNEL);
- if (!heap)
- return ERR_PTR(-ENOMEM);
- heap->heap.ops = &system_heap_ops;
- heap->heap.type = ION_HEAP_TYPE_SYSTEM;
- heap->heap.flags = ION_HEAP_FLAG_DEFER_FREE;
- heap->pools = kzalloc(sizeof(struct ion_page_pool *) * num_orders,
- GFP_KERNEL);
- if (!heap->pools)
- goto err_alloc_pools;
+static void ion_system_heap_destroy_pools(struct ion_page_pool **pools)
+{
+ int i;
+ for (i = 0; i < num_orders; i++)
+ if (pools[i])
+ ion_page_pool_destroy(pools[i]);
+}
+
+/**
+ * ion_system_heap_create_pools - Creates pools for all orders
+ *
+ * If this fails you don't need to destroy any pools. It's all or
+ * nothing. If it succeeds you'll eventually need to use
+ * ion_system_heap_destroy_pools to destroy the pools.
+ */
+static int ion_system_heap_create_pools(struct ion_page_pool **pools)
+{
+ int i;
for (i = 0; i < num_orders; i++) {
struct ion_page_pool *pool;
gfp_t gfp_flags = low_order_gfp_flags;
@@ -309,16 +367,54 @@
pool = ion_page_pool_create(gfp_flags, orders[i]);
if (!pool)
goto err_create_pool;
- heap->pools[i] = pool;
+ pools[i] = pool;
}
+ return 0;
+err_create_pool:
+ ion_system_heap_destroy_pools(pools);
+ return 1;
+}
+
+struct ion_heap *ion_system_heap_create(struct ion_platform_heap *unused)
+{
+ struct ion_system_heap *heap;
+ int pools_size = sizeof(struct ion_page_pool *) * num_orders;
+
+ heap = kzalloc(sizeof(struct ion_system_heap), GFP_KERNEL);
+ if (!heap)
+ return ERR_PTR(-ENOMEM);
+ heap->heap.ops = &system_heap_ops;
+ heap->heap.type = ION_HEAP_TYPE_SYSTEM;
+ heap->heap.flags = ION_HEAP_FLAG_DEFER_FREE;
+
+ heap->uncached_pools = kzalloc(pools_size, GFP_KERNEL);
+ if (!heap->uncached_pools)
+ goto err_alloc_uncached_pools;
+
+ heap->cached_pools = kzalloc(pools_size, GFP_KERNEL);
+ if (!heap->cached_pools)
+ goto err_alloc_cached_pools;
+
+ if (ion_system_heap_create_pools(heap->uncached_pools))
+ goto err_create_uncached_pools;
+
+ if (ion_system_heap_create_pools(heap->cached_pools))
+ goto err_create_cached_pools;
+
+ heap->heap.shrinker.shrink = ion_system_heap_shrink;
+ heap->heap.shrinker.seeks = DEFAULT_SEEKS;
+ heap->heap.shrinker.batch = 0;
+ register_shrinker(&heap->heap.shrinker);
heap->heap.debug_show = ion_system_heap_debug_show;
return &heap->heap;
-err_create_pool:
- for (i = 0; i < num_orders; i++)
- if (heap->pools[i])
- ion_page_pool_destroy(heap->pools[i]);
- kfree(heap->pools);
-err_alloc_pools:
+
+err_create_cached_pools:
+ ion_system_heap_destroy_pools(heap->uncached_pools);
+err_create_uncached_pools:
+ kfree(heap->cached_pools);
+err_alloc_cached_pools:
+ kfree(heap->uncached_pools);
+err_alloc_uncached_pools:
kfree(heap);
return ERR_PTR(-ENOMEM);
}
@@ -328,36 +424,82 @@
struct ion_system_heap *sys_heap = container_of(heap,
struct ion_system_heap,
heap);
- int i;
- for (i = 0; i < num_orders; i++)
- ion_page_pool_destroy(sys_heap->pools[i]);
- kfree(sys_heap->pools);
+ ion_system_heap_destroy_pools(sys_heap->uncached_pools);
+ ion_system_heap_destroy_pools(sys_heap->cached_pools);
+ kfree(sys_heap->uncached_pools);
+ kfree(sys_heap->cached_pools);
kfree(sys_heap);
}
+struct kmalloc_buffer_info {
+ struct sg_table *table;
+ void *vaddr;
+};
+
static int ion_system_contig_heap_allocate(struct ion_heap *heap,
struct ion_buffer *buffer,
unsigned long len,
unsigned long align,
unsigned long flags)
{
- buffer->priv_virt = kzalloc(len, GFP_KERNEL);
- if (!buffer->priv_virt)
- return -ENOMEM;
+ int ret;
+ struct kmalloc_buffer_info *info;
+
+ info = kmalloc(sizeof(struct kmalloc_buffer_info), GFP_KERNEL);
+ if (!info) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ info->table = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
+ if (!info->table) {
+ ret = -ENOMEM;
+ goto kfree_info;
+ }
+
+ ret = sg_alloc_table(info->table, 1, GFP_KERNEL);
+ if (ret)
+ goto kfree_table;
+
+ info->vaddr = kzalloc(len, GFP_KERNEL);
+ if (!info->vaddr) {
+ ret = -ENOMEM;
+ goto sg_free_table;
+ }
+
+ sg_set_page(info->table->sgl, virt_to_page(info->vaddr), len,
+ 0);
+ sg_dma_address(info->table->sgl) = virt_to_phys(info->vaddr);
+ dma_sync_sg_for_device(NULL, info->table->sgl, 1, DMA_BIDIRECTIONAL);
+
+ buffer->priv_virt = info;
return 0;
+
+sg_free_table:
+ sg_free_table(info->table);
+kfree_table:
+ kfree(info->table);
+kfree_info:
+ kfree(info);
+out:
+ return ret;
}
void ion_system_contig_heap_free(struct ion_buffer *buffer)
{
- kfree(buffer->priv_virt);
+ struct kmalloc_buffer_info *info = buffer->priv_virt;
+ sg_free_table(info->table);
+ kfree(info->table);
+ kfree(info->vaddr);
}
static int ion_system_contig_heap_phys(struct ion_heap *heap,
struct ion_buffer *buffer,
ion_phys_addr_t *addr, size_t *len)
{
- *addr = virt_to_phys(buffer->priv_virt);
+ struct kmalloc_buffer_info *info = buffer->priv_virt;
+ *addr = virt_to_phys(info->vaddr);
*len = buffer->size;
return 0;
}
@@ -365,27 +507,13 @@
struct sg_table *ion_system_contig_heap_map_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
{
- struct sg_table *table;
- int ret;
-
- table = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
- if (!table)
- return ERR_PTR(-ENOMEM);
- ret = sg_alloc_table(table, 1, GFP_KERNEL);
- if (ret) {
- kfree(table);
- return ERR_PTR(ret);
- }
- sg_set_page(table->sgl, virt_to_page(buffer->priv_virt), buffer->size,
- 0);
- return table;
+ struct kmalloc_buffer_info *info = buffer->priv_virt;
+ return info->table;
}
void ion_system_contig_heap_unmap_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
{
- sg_free_table(buffer->sg_table);
- kfree(buffer->sg_table);
}
static struct ion_heap_ops kmalloc_ops = {
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index 118c39a..a6fc3d5 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -19,6 +19,7 @@
#include <linux/memory_alloc.h>
#include <linux/of.h>
#include <linux/of_platform.h>
+#include <linux/of_address.h>
#include <linux/mm.h>
#include <linux/mm_types.h>
#include <linux/sched.h>
@@ -26,6 +27,7 @@
#include <linux/uaccess.h>
#include <linux/memblock.h>
#include <linux/dma-mapping.h>
+#include <linux/dma-contiguous.h>
#include <mach/ion.h>
#include <mach/msm_memtypes.h>
#include <asm/cacheflush.h>
@@ -51,74 +53,56 @@
static struct ion_heap_desc ion_heap_meta[] = {
{
.id = ION_SYSTEM_HEAP_ID,
- .type = ION_HEAP_TYPE_SYSTEM,
- .name = ION_VMALLOC_HEAP_NAME,
+ .name = ION_SYSTEM_HEAP_NAME,
},
{
.id = ION_SYSTEM_CONTIG_HEAP_ID,
- .type = ION_HEAP_TYPE_SYSTEM_CONTIG,
.name = ION_KMALLOC_HEAP_NAME,
},
{
.id = ION_CP_MM_HEAP_ID,
- .type = ION_HEAP_TYPE_SECURE_DMA,
.name = ION_MM_HEAP_NAME,
.permission_type = IPT_TYPE_MM_CARVEOUT,
},
{
.id = ION_MM_FIRMWARE_HEAP_ID,
- .type = ION_HEAP_TYPE_CARVEOUT,
.name = ION_MM_FIRMWARE_HEAP_NAME,
},
{
.id = ION_CP_MFC_HEAP_ID,
- .type = ION_HEAP_TYPE_CP,
.name = ION_MFC_HEAP_NAME,
.permission_type = IPT_TYPE_MFC_SHAREDMEM,
},
{
.id = ION_SF_HEAP_ID,
- .type = ION_HEAP_TYPE_CARVEOUT,
.name = ION_SF_HEAP_NAME,
},
{
- .id = ION_IOMMU_HEAP_ID,
- .type = ION_HEAP_TYPE_IOMMU,
- .name = ION_IOMMU_HEAP_NAME,
- },
- {
.id = ION_QSECOM_HEAP_ID,
- .type = ION_HEAP_TYPE_DMA,
.name = ION_QSECOM_HEAP_NAME,
},
{
.id = ION_AUDIO_HEAP_ID,
- .type = ION_HEAP_TYPE_CARVEOUT,
.name = ION_AUDIO_HEAP_NAME,
},
{
.id = ION_PIL1_HEAP_ID,
- .type = ION_HEAP_TYPE_CARVEOUT,
.name = ION_PIL1_HEAP_NAME,
},
{
.id = ION_PIL2_HEAP_ID,
- .type = ION_HEAP_TYPE_CARVEOUT,
.name = ION_PIL2_HEAP_NAME,
},
{
.id = ION_CP_WB_HEAP_ID,
- .type = ION_HEAP_TYPE_CP,
.name = ION_WB_HEAP_NAME,
},
{
.id = ION_CAMERA_HEAP_ID,
- .type = ION_HEAP_TYPE_CARVEOUT,
.name = ION_CAMERA_HEAP_NAME,
},
{
.id = ION_ADSP_HEAP_ID,
- .type = ION_HEAP_TYPE_DMA,
.name = ION_ADSP_HEAP_NAME,
}
};
@@ -127,6 +111,16 @@
struct ion_client *msm_ion_client_create(unsigned int heap_mask,
const char *name)
{
+ /*
+ * The assumption is that if there is a NULL device, the ion
+ * driver has not yet probed.
+ */
+ if (idev == NULL)
+ return ERR_PTR(-EPROBE_DEFER);
+
+ if (IS_ERR(idev))
+ return (struct ion_client *)idev;
+
return ion_client_create(idev, name);
}
EXPORT_SYMBOL(msm_ion_client_create);
@@ -560,7 +554,8 @@
}
#ifdef CONFIG_OF
-static int msm_init_extra_data(struct ion_platform_heap *heap,
+static int msm_init_extra_data(struct device_node *node,
+ struct ion_platform_heap *heap,
const struct ion_heap_desc *heap_desc)
{
int ret = 0;
@@ -586,6 +581,28 @@
ret = -ENOMEM;
break;
}
+ case ION_HEAP_TYPE_SECURE_DMA:
+ {
+ unsigned int val;
+
+ ret = of_property_read_u32(node,
+ "qcom,default-prefetch-size", &val);
+
+ if (!ret) {
+ heap->extra_data = kzalloc(sizeof(struct ion_cma_pdata),
+ GFP_KERNEL);
+
+ if (!heap->extra_data) {
+ ret = -ENOMEM;
+ } else {
+ struct ion_cma_pdata *extra = heap->extra_data;
+ extra->default_prefetch_size = val;
+ }
+ } else {
+ ret = 0;
+ }
+ break;
+ }
default:
heap->extra_data = 0;
break;
@@ -593,16 +610,60 @@
return ret;
}
-static int msm_ion_populate_heap(struct ion_platform_heap *heap)
+#define MAKE_HEAP_TYPE_MAPPING(h) { .name = #h, \
+ .heap_type = ION_HEAP_TYPE_##h, }
+
+static struct heap_types_info {
+ const char *name;
+ int heap_type;
+} heap_types_info[] = {
+ MAKE_HEAP_TYPE_MAPPING(SYSTEM),
+ MAKE_HEAP_TYPE_MAPPING(SYSTEM_CONTIG),
+ MAKE_HEAP_TYPE_MAPPING(CARVEOUT),
+ MAKE_HEAP_TYPE_MAPPING(CHUNK),
+ MAKE_HEAP_TYPE_MAPPING(DMA),
+ MAKE_HEAP_TYPE_MAPPING(CP),
+ MAKE_HEAP_TYPE_MAPPING(SECURE_DMA),
+ MAKE_HEAP_TYPE_MAPPING(REMOVED),
+};
+
+static int msm_ion_get_heap_type_from_dt_node(struct device_node *node,
+ int *heap_type)
+{
+ const char *name;
+ int i, ret = -EINVAL;
+ ret = of_property_read_string(node, "qcom,ion-heap-type", &name);
+ if (ret)
+ goto out;
+ for (i = 0; i < ARRAY_SIZE(heap_types_info); ++i) {
+ if (!strcmp(heap_types_info[i].name, name)) {
+ *heap_type = heap_types_info[i].heap_type;
+ ret = 0;
+ goto out;
+ }
+ }
+ WARN(1, "Unknown heap type: %s. You might need to update heap_types_info in %s",
+ name, __FILE__);
+out:
+ return ret;
+}
+
+static int msm_ion_populate_heap(struct device_node *node,
+ struct ion_platform_heap *heap)
{
unsigned int i;
- int ret = -EINVAL;
+ int ret = -EINVAL, heap_type = -1;
unsigned int len = ARRAY_SIZE(ion_heap_meta);
for (i = 0; i < len; ++i) {
if (ion_heap_meta[i].id == heap->id) {
heap->name = ion_heap_meta[i].name;
- heap->type = ion_heap_meta[i].type;
- ret = msm_init_extra_data(heap, &ion_heap_meta[i]);
+ ret = msm_ion_get_heap_type_from_dt_node(node,
+ &heap_type);
+ if (ret)
+ break;
+ heap->type = heap_type;
+ ret = msm_init_extra_data(node, heap,
+ &ion_heap_meta[i]);
break;
}
}
@@ -664,6 +725,7 @@
int ret = 0;
u32 out_values[2];
const char *memory_name_prop;
+ struct device_node *pnode;
ret = of_property_read_u32(node, "qcom,memory-reservation-size", &val);
if (!ret) {
@@ -685,14 +747,33 @@
__func__);
ret = -EINVAL;
}
- } else {
- ret = of_property_read_u32_array(node, "qcom,memory-fixed",
- out_values, 2);
- if (!ret)
- heap->size = out_values[1];
- else
- ret = 0;
+ goto out;
}
+
+ ret = of_property_read_u32_array(node, "qcom,memory-fixed",
+ out_values, 2);
+ if (!ret) {
+ heap->size = out_values[1];
+ goto out;
+ }
+
+ pnode = of_parse_phandle(node, "linux,contiguous-region", 0);
+ if (pnode != NULL) {
+ const u32 *addr;
+ u64 size;
+
+ addr = of_get_address(pnode, 0, &size, NULL);
+ if (!addr) {
+ of_node_put(pnode);
+ ret = -EINVAL;
+ goto out;
+ }
+ heap->size = (u32) size;
+ ret = 0;
+ of_node_put(pnode);
+ }
+
+ ret = 0;
out:
return ret;
}
@@ -702,11 +783,19 @@
{
u32 out_values[2];
int ret = 0;
+ struct device_node *pnode;
ret = of_property_read_u32_array(node, "qcom,memory-fixed",
out_values, 2);
if (!ret)
heap->base = out_values[0];
+
+ pnode = of_parse_phandle(node, "linux,contiguous-region", 0);
+ if (pnode != NULL) {
+ heap->base = cma_get_base(heap->priv);
+ of_node_put(pnode);
+ }
+
return;
}
@@ -793,7 +882,7 @@
}
pdata->heaps[idx].id = val;
- ret = msm_ion_populate_heap(&pdata->heaps[idx]);
+ ret = msm_ion_populate_heap(node, &pdata->heaps[idx]);
if (ret)
goto free_heaps;
@@ -884,11 +973,18 @@
sizeof(struct ion_flush_data)))
return -EFAULT;
- if (!data.handle) {
+ if (data.handle > 0) {
+ handle = ion_handle_get_by_id(client, (int)data.handle);
+ if (IS_ERR(handle)) {
+ pr_info("%s: Could not find handle: %d\n",
+ __func__, (int)data.handle);
+ return PTR_ERR(handle);
+ }
+ } else {
handle = ion_import_dma_buf(client, data.fd);
if (IS_ERR(handle)) {
- pr_info("%s: Could not import handle: %d\n",
- __func__, (int)handle);
+ pr_info("%s: Could not import handle: %p\n",
+ __func__, handle);
return -EINVAL;
}
}
@@ -899,29 +995,46 @@
end = (unsigned long) data.vaddr + data.length;
if (start && check_vaddr_bounds(start, end)) {
- up_read(&mm->mmap_sem);
pr_err("%s: virtual address %p is out of bounds\n",
__func__, data.vaddr);
- if (!data.handle)
- ion_free(client, handle);
- return -EINVAL;
+ ret = -EINVAL;
+ } else {
+ ret = ion_do_cache_op(client, handle, data.vaddr,
+ data.offset, data.length, cmd);
}
-
- ret = ion_do_cache_op(client,
- data.handle ? data.handle : handle,
- data.vaddr, data.offset, data.length,
- cmd);
-
up_read(&mm->mmap_sem);
- if (!data.handle)
- ion_free(client, handle);
+ ion_free(client, handle);
if (ret < 0)
return ret;
break;
-
}
+ case ION_IOC_PREFETCH:
+ {
+ struct ion_prefetch_data data;
+
+ if (copy_from_user(&data, (void __user *)arg,
+ sizeof(struct ion_prefetch_data)))
+ return -EFAULT;
+
+ ion_walk_heaps(client, data.heap_id, (void *)data.len,
+ ion_secure_cma_prefetch);
+ break;
+ }
+ case ION_IOC_DRAIN:
+ {
+ struct ion_prefetch_data data;
+
+ if (copy_from_user(&data, (void __user *)arg,
+ sizeof(struct ion_prefetch_data)))
+ return -EFAULT;
+
+ ion_walk_heaps(client, data.heap_id, (void *)data.len,
+ ion_secure_cma_drain_pool);
+ break;
+ }
+
default:
return -ENOTTY;
}
@@ -933,9 +1046,6 @@
struct ion_heap *heap = NULL;
switch ((int)heap_data->type) {
- case ION_HEAP_TYPE_IOMMU:
- heap = ion_iommu_heap_create(heap_data);
- break;
case ION_HEAP_TYPE_CP:
heap = ion_cp_heap_create(heap_data);
break;
@@ -975,9 +1085,6 @@
return;
switch ((int)heap->type) {
- case ION_HEAP_TYPE_IOMMU:
- ion_iommu_heap_destroy(heap);
- break;
case ION_HEAP_TYPE_CP:
ion_cp_heap_destroy(heap);
break;
@@ -999,6 +1106,7 @@
static int msm_ion_probe(struct platform_device *pdev)
{
+ static struct ion_device *new_dev;
struct ion_platform_data *pdata;
unsigned int pdata_needs_to_be_freed;
int err = -1;
@@ -1024,9 +1132,14 @@
goto out;
}
- idev = ion_device_create(msm_ion_custom_ioctl);
- if (IS_ERR_OR_NULL(idev)) {
- err = PTR_ERR(idev);
+ new_dev = ion_device_create(msm_ion_custom_ioctl);
+ if (IS_ERR_OR_NULL(new_dev)) {
+ /*
+ * set this to the ERR to indicate to the clients
+ * that Ion failed to probe.
+ */
+ idev = new_dev;
+ err = PTR_ERR(new_dev);
goto freeheaps;
}
@@ -1053,13 +1166,18 @@
heap_data->name);
}
- ion_device_add_heap(idev, heaps[i]);
+ ion_device_add_heap(new_dev, heaps[i]);
}
check_for_heap_overlap(pdata->heaps, num_heaps);
if (pdata_needs_to_be_freed)
free_pdata(pdata);
- platform_set_drvdata(pdev, idev);
+ platform_set_drvdata(pdev, new_dev);
+ /*
+ * intentionally set this at the very end to allow probes to be deferred
+ * completely until Ion is setup
+ */
+ idev = new_dev;
return 0;
freeheaps:
diff --git a/drivers/gpu/ion/msm_ion_priv.h b/drivers/gpu/ion/msm_ion_priv.h
index 2de4e8a..83cc7b5 100644
--- a/drivers/gpu/ion/msm_ion_priv.h
+++ b/drivers/gpu/ion/msm_ion_priv.h
@@ -21,14 +21,14 @@
#include <linux/kref.h>
#include <linux/mm_types.h>
#include <linux/mutex.h>
-#include <linux/rbtree.h>
+#include <linux/types.h>
#include <linux/ion.h>
#include <linux/iommu.h>
#include <linux/seq_file.h>
/**
* struct mem_map_data - represents information about the memory map for a heap
- * @node: rb node used to store in the tree of mem_map_data
+ * @node: list node used to store in the list of mem_map_data
* @addr: start address of memory region.
* @addr: end address of memory region.
* @size: size of memory region
@@ -36,7 +36,7 @@
*
*/
struct mem_map_data {
- struct rb_node node;
+ struct list_head node;
ion_phys_addr_t addr;
ion_phys_addr_t addr_end;
unsigned long size;
@@ -55,6 +55,24 @@
struct ion_heap *ion_secure_cma_heap_create(struct ion_platform_heap *);
void ion_secure_cma_heap_destroy(struct ion_heap *);
+
+int ion_secure_cma_prefetch(struct ion_heap *heap, void *data);
+
+int ion_secure_cma_drain_pool(struct ion_heap *heap, void *unused);
+
+#else
+static inline int ion_secure_cma_prefetch(struct ion_heap *heap, void *data)
+{
+ return -ENODEV;
+}
+
+static inline int ion_secure_cma_drain_pool(struct ion_heap *heap, void *unused)
+{
+ return -ENODEV;
+}
+
+
+
#endif
struct ion_heap *ion_removed_heap_create(struct ion_platform_heap *);
diff --git a/drivers/gpu/msm/Kconfig b/drivers/gpu/msm/Kconfig
index ba63fbc..2576386 100644
--- a/drivers/gpu/msm/Kconfig
+++ b/drivers/gpu/msm/Kconfig
@@ -4,6 +4,10 @@
depends on ARCH_MSM && !ARCH_MSM7X00A && !ARCH_MSM7X25
select GENERIC_ALLOCATOR
select FW_LOADER
+ select PM_DEVFREQ
+ select DEVFREQ_GOV_SIMPLE_ONDEMAND
+ select DEVFREQ_GOV_PERFORMANCE
+ select DEVFREQ_GOV_MSM_ADRENO_TZ
---help---
3D graphics driver. Required to use hardware accelerated
OpenGL ES 2.0 and 1.1.
@@ -60,6 +64,17 @@
default y
depends on MSM_KGSL && !ARCH_MSM7X27 && !ARCH_MSM7X27A && !(ARCH_QSD8X50 && !MSM_SOC_REV_A)
+config MSM_ADRENO_DEFAULT_GOVERNOR
+ string "devfreq governor for the adreno core"
+ default "msm-adreno-tz" if DEVFREQ_GOV_MSM_ADRENO_TZ
+ default "simple_ondemand"
+ depends on MSM_KGSL
+
+config MSM_Z180_DEFAULT_GOVERNOR
+ string "devfreq governor for the z180 core(s)"
+ default "performance"
+ depends on MSM_KGSL_2D
+
config MSM_KGSL_DRM
bool "Build a DRM interface for the MSM_KGSL driver"
depends on MSM_KGSL && DRM
diff --git a/drivers/gpu/msm/Makefile b/drivers/gpu/msm/Makefile
index aac183b..14e07e5 100644
--- a/drivers/gpu/msm/Makefile
+++ b/drivers/gpu/msm/Makefile
@@ -15,8 +15,6 @@
msm_kgsl_core-$(CONFIG_DEBUG_FS) += kgsl_debugfs.o
msm_kgsl_core-$(CONFIG_MSM_KGSL_CFF_DUMP) += kgsl_cffdump.o
msm_kgsl_core-$(CONFIG_MSM_KGSL_DRM) += kgsl_drm.o
-msm_kgsl_core-$(CONFIG_MSM_SCM) += kgsl_pwrscale_trustzone.o
-msm_kgsl_core-$(CONFIG_MSM_SLEEP_STATS_DEVICE) += kgsl_pwrscale_idlestats.o
msm_kgsl_core-$(CONFIG_SYNC) += kgsl_sync.o
msm_adreno-y += \
diff --git a/drivers/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h
index 676f46d..758d5c5 100644
--- a/drivers/gpu/msm/a3xx_reg.h
+++ b/drivers/gpu/msm/a3xx_reg.h
@@ -775,6 +775,9 @@
#define SP0_ICL1_MISSES 0x1A
#define SP_FS_CFLOW_INSTRUCTIONS 0x0C
+/* COUNTABLE FOR TSE PERFCOUNTER */
+#define TSE_INPUT_PRIM_NUM 0x0
+
/* VBIF PERFCOUNTER ENA/CLR values */
#define VBIF_PERF_CNT_0 BIT(0)
#define VBIF_PERF_CNT_1 BIT(1)
@@ -789,6 +792,7 @@
#define VBIF_PERF_CNT_1_SEL_MASK 0x7f00
/* VBIF countables */
+#define VBIF_AXI_TOTAL_BEATS 85
#define VBIF_DDR_TOTAL_CYCLES 110
#endif
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index a271388..eba60ea 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -19,6 +19,7 @@
#include <linux/of_device.h>
#include <linux/delay.h>
#include <linux/of_coresight.h>
+#include <linux/input.h>
#include <mach/socinfo.h>
#include <mach/msm_bus_board.h>
@@ -77,11 +78,38 @@
#define KGSL_LOG_LEVEL_DEFAULT 3
+static void adreno_start_work(struct work_struct *work);
+static void adreno_input_work(struct work_struct *work);
+
+/*
+ * The default values for the simpleondemand governor are 90 and 5,
+ * we use different values here.
+ * They have to be tuned and compare with the tz governor anyway.
+ */
+static struct devfreq_simple_ondemand_data adreno_ondemand_data = {
+ .upthreshold = 80,
+ .downdifferential = 20,
+};
+
+static struct devfreq_msm_adreno_tz_data adreno_tz_data = {
+ .bus = {
+ .max = 450,
+ },
+ .device_id = KGSL_DEVICE_3D0,
+};
+
+static const struct devfreq_governor_data adreno_governors[] = {
+ { .name = "simple_ondemand", .data = &adreno_ondemand_data },
+ { .name = "msm-adreno-tz", .data = &adreno_tz_data },
+};
+
static const struct kgsl_functable adreno_functable;
static struct adreno_device device_3d0 = {
.dev = {
KGSL_DEVICE_COMMON_INIT(device_3d0.dev),
+ .pwrscale = KGSL_PWRSCALE_INIT(adreno_governors,
+ ARRAY_SIZE(adreno_governors)),
.name = DEVICE_3D0_NAME,
.id = KGSL_DEVICE_3D0,
.mh = {
@@ -123,10 +151,16 @@
.ft_pf_policy = KGSL_FT_PAGEFAULT_DEFAULT_POLICY,
.fast_hang_detect = 1,
.long_ib_detect = 1,
+ .start_work = __WORK_INITIALIZER(device_3d0.start_work,
+ adreno_start_work),
+ .input_work = __WORK_INITIALIZER(device_3d0.input_work,
+ adreno_input_work),
};
unsigned int ft_detect_regs[FT_DETECT_REGS_COUNT];
+static struct workqueue_struct *adreno_wq;
+
/*
* This is the master list of all GPU cores that are supported by this
* driver.
@@ -220,6 +254,122 @@
512, 0, 2, SZ_128K, 0x3FF037, 0x3FF016 },
};
+/* Nice level for the higher priority GPU start thread */
+static unsigned int _wake_nice = -7;
+
+/* Number of milliseconds to stay active active after a wake on touch */
+static unsigned int _wake_timeout = 100;
+
+/*
+ * A workqueue callback responsible for actually turning on the GPU after a
+ * touch event. kgsl_pwrctrl_wake() is used without any active_count protection
+ * to avoid the need to maintain state. Either somebody will start using the
+ * GPU or the idle timer will fire and put the GPU back into slumber
+ */
+static void adreno_input_work(struct work_struct *work)
+{
+ struct adreno_device *adreno_dev = container_of(work,
+ struct adreno_device, input_work);
+ struct kgsl_device *device = &adreno_dev->dev;
+
+ mutex_lock(&device->mutex);
+
+ device->flags |= KGSL_FLAG_WAKE_ON_TOUCH;
+
+ /*
+ * Don't schedule adreno_start in a high priority workqueue, we are
+ * already in a workqueue which should be sufficient
+ */
+ kgsl_pwrctrl_wake(device, 0);
+
+ /*
+ * When waking up from a touch event we want to stay active long enough
+ * for the user to send a draw command. The default idle timer timeout
+ * is shorter than we want so go ahead and push the idle timer out
+ * further for this special case
+ */
+ mod_timer(&device->idle_timer,
+ jiffies + msecs_to_jiffies(_wake_timeout));
+ mutex_unlock(&device->mutex);
+}
+
+/*
+ * Process input events and schedule work if needed. At this point we are only
+ * interested in groking EV_ABS touchscreen events
+ */
+static void adreno_input_event(struct input_handle *handle, unsigned int type,
+ unsigned int code, int value)
+{
+ struct kgsl_device *device = handle->handler->private;
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
+ /*
+ * Only queue the work under certain circumstances: we have to be in
+ * slumber, the event has to be EV_EBS and we had to have processed an
+ * IB since the last time we called wake on touch.
+ */
+ if ((type == EV_ABS) &&
+ !(device->flags & KGSL_FLAG_WAKE_ON_TOUCH) &&
+ (device->state == KGSL_STATE_SLUMBER))
+ schedule_work(&adreno_dev->input_work);
+}
+
+static int adreno_input_connect(struct input_handler *handler,
+ struct input_dev *dev, const struct input_device_id *id)
+{
+ struct input_handle *handle;
+ int ret;
+
+ handle = kzalloc(sizeof(*handle), GFP_KERNEL);
+ if (handle == NULL)
+ return -ENOMEM;
+
+ handle->dev = dev;
+ handle->handler = handler;
+ handle->name = handler->name;
+
+ ret = input_register_handle(handle);
+ if (ret) {
+ kfree(handle);
+ return ret;
+ }
+
+ ret = input_open_device(handle);
+ if (ret) {
+ input_unregister_handle(handle);
+ kfree(handle);
+ }
+
+ return ret;
+}
+
+static void adreno_input_disconnect(struct input_handle *handle)
+{
+ input_close_device(handle);
+ input_unregister_handle(handle);
+ kfree(handle);
+}
+
+/*
+ * We are only interested in EV_ABS events so only register handlers for those
+ * input devices that have EV_ABS events
+ */
+static const struct input_device_id adreno_input_ids[] = {
+ {
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+ .evbit = { BIT_MASK(EV_ABS) },
+ },
+ { },
+};
+
+static struct input_handler adreno_input_handler = {
+ .event = adreno_input_event,
+ .connect = adreno_input_connect,
+ .disconnect = adreno_input_disconnect,
+ .name = "kgsl",
+ .id_table = adreno_input_ids,
+};
+
/**
* adreno_perfcounter_init: Reserve kernel performance counters
* @device: device to configure
@@ -476,6 +626,18 @@
return 0;
}
+static inline void refcount_group(struct adreno_perfcount_group *group,
+ unsigned int reg, unsigned int flags, unsigned int *lo)
+{
+ if (flags & PERFCOUNTER_FLAG_KERNEL)
+ group->regs[reg].kernelcount++;
+ else
+ group->regs[reg].usercount++;
+
+ if (lo)
+ *lo = group->regs[reg].offset;
+}
+
/**
* adreno_perfcounter_get: Try to put a countable in an available counter
* @adreno_dev: Adreno device to configure
@@ -495,7 +657,7 @@
{
struct adreno_perfcounters *counters = adreno_dev->gpudev->perfcounters;
struct adreno_perfcount_group *group;
- unsigned int i, empty = -1;
+ unsigned int empty = -1;
int ret = 0;
/* always clear return variables */
@@ -510,26 +672,41 @@
group = &(counters->groups[groupid]);
- /*
- * Check if the countable is already associated with a counter.
- * Refcount and return the offset, otherwise, try and find an empty
- * counter and assign the countable to it.
- */
- for (i = 0; i < group->reg_count; i++) {
- if (group->regs[i].countable == countable) {
- /* Countable already associated with counter */
- if (flags & PERFCOUNTER_FLAG_KERNEL)
- group->regs[i].kernelcount++;
- else
- group->regs[i].usercount++;
+ if (group->flags & ADRENO_PERFCOUNTER_GROUP_FIXED) {
+ /*
+ * In fixed groups the countable equals the fixed register the
+ * user wants. First make sure it is in range
+ */
- if (offset)
- *offset = group->regs[i].offset;
- return 0;
- } else if (group->regs[i].countable ==
+ if (countable >= group->reg_count)
+ return -EINVAL;
+
+ /* If it is already reserved, just increase the refcounts */
+ if ((group->regs[countable].kernelcount != 0) ||
+ (group->regs[countable].usercount != 0)) {
+ refcount_group(group, countable, flags, offset);
+ return 0;
+ }
+
+ empty = countable;
+ } else {
+ unsigned int i;
+
+ /*
+ * Check if the countable is already associated with a counter.
+ * Refcount and return the offset, otherwise, try and find an
+ * empty counter and assign the countable to it.
+ */
+
+ for (i = 0; i < group->reg_count; i++) {
+ if (group->regs[i].countable == countable) {
+ refcount_group(group, i, flags, offset);
+ return 0;
+ } else if (group->regs[i].countable ==
KGSL_PERFCOUNTER_NOT_USED) {
- /* keep track of unused counter */
- empty = i;
+ /* keep track of unused counter */
+ empty = i;
+ }
}
}
@@ -616,6 +793,33 @@
return -EINVAL;
}
+/**
+ * adreno_perfcounter_restore() - Restore performance counters
+ * @adreno_dev: adreno device to configure
+ *
+ * Load the physical performance counters with 64 bit value which are
+ * saved on GPU power collapse.
+ */
+static inline void adreno_perfcounter_restore(struct adreno_device *adreno_dev)
+{
+ if (adreno_dev->gpudev->perfcounter_restore)
+ adreno_dev->gpudev->perfcounter_restore(adreno_dev);
+}
+
+/**
+ * adreno_perfcounter_save() - Save performance counters
+ * @adreno_dev: adreno device to configure
+ *
+ * Save the performance counter values before GPU power collapse.
+ * The saved values are restored on restart.
+ * This ensures physical counters are coherent across power-collapse.
+ */
+static inline void adreno_perfcounter_save(struct adreno_device *adreno_dev)
+{
+ if (adreno_dev->gpudev->perfcounter_save)
+ adreno_dev->gpudev->perfcounter_save(adreno_dev);
+}
+
static irqreturn_t adreno_irq_handler(struct kgsl_device *device)
{
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
@@ -631,8 +835,6 @@
kgsl_mmu_unmap(pagetable, &rb->buffer_desc);
- kgsl_mmu_unmap(pagetable, &rb->memptrs_desc);
-
kgsl_mmu_unmap(pagetable, &device->memstore);
kgsl_mmu_unmap(pagetable, &adreno_dev->pwron_fixup);
@@ -653,14 +855,11 @@
/*
* ALERT: Order of these mapping is important to
- * Keep the most used entries like memptrs, memstore
+ * Keep the most used entries like memstore
* and mmu setstate memory by TLB prefetcher.
*/
if (!result)
- result = kgsl_mmu_map_global(pagetable, &rb->memptrs_desc);
-
- if (!result)
result = kgsl_mmu_map_global(pagetable, &device->memstore);
if (!result)
@@ -955,11 +1154,10 @@
num_iommu_units = kgsl_mmu_get_num_iommu_units(&device->mmu);
context = kgsl_context_get(device, context_id);
- if (context == NULL) {
- kgsl_mmu_device_setstate(&device->mmu, KGSL_CONTEXT_INVALID);
- return -EINVAL;
+ if (!context) {
+ kgsl_mmu_device_setstate(&device->mmu, flags);
+ return 0;
}
-
adreno_ctx = ADRENO_CONTEXT(context);
result = kgsl_mmu_enable_clk(&device->mmu, KGSL_IOMMU_CONTEXT_USER);
@@ -1364,15 +1562,6 @@
&pdata->init_level))
pdata->init_level = 1;
- /*
- * qcom,step-pwrlevel isn't required so don't spam the kernel log
- * if it isn't found
- */
-
- if (of_property_read_u32(parent, "qcom,step-pwrlevel",
- &pdata->step_mul))
- pdata->step_mul = 1;
-
if (pdata->init_level < 0 || pdata->init_level > pdata->num_levels) {
KGSL_CORE_ERR("Initial power level out of range\n");
pdata->init_level = 1;
@@ -1506,6 +1695,9 @@
pdata->strtstp_sleepwake = of_property_read_bool(pdev->dev.of_node,
"qcom,strtstp-sleepwake");
+ pdata->bus_control = of_property_read_bool(pdev->dev.of_node,
+ "qcom,bus-control");
+
if (adreno_of_read_property(pdev->dev.of_node, "qcom,clk-map",
&pdata->clk_map))
goto err;
@@ -1635,14 +1827,23 @@
adreno_ft_init_sysfs(device);
- kgsl_pwrscale_init(device);
- kgsl_pwrscale_attach_policy(device, ADRENO_DEFAULT_PWRSCALE_POLICY);
+ kgsl_pwrscale_init(&pdev->dev, CONFIG_MSM_ADRENO_DEFAULT_GOVERNOR);
+
device->flags &= ~KGSL_FLAGS_SOFT_RESET;
pdata = kgsl_device_get_drvdata(device);
adreno_coresight_init(pdev);
+ adreno_input_handler.private = device;
+
+ /*
+ * It isn't fatal if we cannot register the input handler. Sad,
+ * perhaps, but not fatal
+ */
+ if (input_register_handler(&adreno_input_handler))
+ KGSL_DRV_ERR(device, "Unable to register the input handler\n");
+
return 0;
error_close_device:
@@ -1663,10 +1864,11 @@
device = (struct kgsl_device *)pdev->id_entry->driver_data;
adreno_dev = ADRENO_DEVICE(device);
+ input_unregister_handler(&adreno_input_handler);
+
adreno_coresight_remove(pdev);
adreno_profile_close(device);
- kgsl_pwrscale_detach_policy(device);
kgsl_pwrscale_close(device);
adreno_dispatcher_close(adreno_dev);
@@ -1685,6 +1887,9 @@
int i;
int ret;
+ /* Make a high priority workqueue for starting the GPU */
+ adreno_wq = alloc_workqueue("adreno", WQ_HIGHPRI | WQ_UNBOUND, 1);
+
kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
/*
* initialization only needs to be done once initially until
@@ -1761,10 +1966,17 @@
return ret;
}
-static int adreno_start(struct kgsl_device *device)
+/**
+ * _adreno_start - Power up the GPU and prepare to accept commands
+ * @adreno_dev: Pointer to an adreno_device structure
+ *
+ * The core function that powers up and initalizes the GPU. This function is
+ * called at init and after coming out of SLUMBER
+ */
+static int _adreno_start(struct adreno_device *adreno_dev)
{
+ struct kgsl_device *device = &adreno_dev->dev;
int status = -EINVAL;
- struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
unsigned int state = device->state;
unsigned int regulator_left_on = 0;
@@ -1817,6 +2029,9 @@
adreno_dev->gpudev->soft_reset(adreno_dev);
}
+ /* Restore performance counter registers with saved values */
+ adreno_perfcounter_restore(adreno_dev);
+
/* Start the GPU */
adreno_dev->gpudev->start(adreno_dev);
@@ -1836,6 +2051,8 @@
device->reset_counter++;
+ set_bit(ADRENO_DEVICE_STARTED, &adreno_dev->priv);
+
return 0;
error_rb_stop:
@@ -1854,6 +2071,76 @@
return status;
}
+static int _status;
+
+/**
+ * _adreno_start_work() - Work handler for the low latency adreno_start
+ * @work: Pointer to the work_struct for
+ *
+ * The work callbak for the low lantecy GPU start - this executes the core
+ * _adreno_start function in the workqueue.
+ */
+static void adreno_start_work(struct work_struct *work)
+{
+ struct adreno_device *adreno_dev = container_of(work,
+ struct adreno_device, start_work);
+ struct kgsl_device *device = &adreno_dev->dev;
+
+ /* Nice ourselves to be higher priority but not too high priority */
+ set_user_nice(current, _wake_nice);
+
+ mutex_lock(&device->mutex);
+ /*
+ * If adreno start is already called, no need to call it again
+ * it can lead to unpredictable behavior if we try to start
+ * the device that is already started.
+ * Below is the sequence of events that can go bad without the check
+ * 1) thread 1 calls adreno_start to be scheduled on high priority wq
+ * 2) thread 2 calls adreno_start with normal priority
+ * 3) thread 1 after checking the device to be in slumber state gives
+ * up mutex to be scheduled on high priority wq
+ * 4) thread 2 after checking the device to be in slumber state gets
+ * the mutex and finishes adreno_start before thread 1 is scheduled
+ * on high priority wq.
+ * 5) thread 1 gets scheduled on high priority wq and executes
+ * adreno_start again. This leads to unpredictable behavior.
+ */
+ if (!test_bit(ADRENO_DEVICE_STARTED, &adreno_dev->priv))
+ _status = _adreno_start(adreno_dev);
+ else
+ _status = 0;
+ mutex_unlock(&device->mutex);
+}
+
+/**
+ * adreno_start() - Power up and initialize the GPU
+ * @device: Pointer to the KGSL device to power up
+ * @priority: Boolean flag to specify of the start should be scheduled in a low
+ * latency work queue
+ *
+ * Power up the GPU and initialize it. If priority is specified then queue the
+ * start function in a high priority queue for lower latency.
+ */
+static int adreno_start(struct kgsl_device *device, int priority)
+{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
+ /* No priority (normal latency) call the core start function directly */
+ if (!priority)
+ return _adreno_start(adreno_dev);
+
+ /*
+ * If priority is specified (low latency) then queue the work in a
+ * higher priority work queue and wait for it to finish
+ */
+ queue_work(adreno_wq, &adreno_dev->start_work);
+ mutex_unlock(&device->mutex);
+ flush_work(&adreno_dev->start_work);
+ mutex_lock(&device->mutex);
+
+ return _status;
+}
+
static int adreno_stop(struct kgsl_device *device)
{
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
@@ -1874,11 +2161,16 @@
adreno_ocmem_gmem_free(adreno_dev);
+ /* Save physical performance counter values before GPU power down*/
+ adreno_perfcounter_save(adreno_dev);
+
/* Power down the device */
kgsl_pwrctrl_disable(device);
kgsl_cffdump_close(device);
+ clear_bit(ADRENO_DEVICE_STARTED, &adreno_dev->priv);
+
return 0;
}
@@ -1908,7 +2200,7 @@
/* Keep trying to start the device until it works */
for (i = 0; i < NUM_TIMES_RESET_RETRY; i++) {
- ret = adreno_start(device);
+ ret = adreno_start(device, 0);
if (!ret)
break;
@@ -2090,12 +2382,29 @@
const char *buf, size_t count)
{
struct adreno_device *adreno_dev = _get_adreno_dev(dev);
- int ret;
+ int ret, tmp;
+
if (adreno_dev == NULL)
return 0;
mutex_lock(&adreno_dev->dev.mutex);
+
+ tmp = adreno_dev->fast_hang_detect;
+
ret = _ft_sysfs_store(buf, count, &adreno_dev->fast_hang_detect);
+
+ if (tmp != adreno_dev->fast_hang_detect) {
+ if (adreno_dev->fast_hang_detect) {
+ if (adreno_dev->gpudev->fault_detect_start)
+ adreno_dev->gpudev->fault_detect_start(
+ adreno_dev);
+ } else {
+ if (adreno_dev->gpudev->fault_detect_stop)
+ adreno_dev->gpudev->fault_detect_stop(
+ adreno_dev);
+ }
+ }
+
mutex_unlock(&adreno_dev->dev.mutex);
return ret;
@@ -2166,6 +2475,36 @@
(adreno_dev->long_ib_detect ? 1 : 0));
}
+/**
+ * _wake_timeout_store() - Store the amount of time to extend idle check after
+ * wake on touch
+ * @dev: device ptr
+ * @attr: Device attribute
+ * @buf: value to write
+ * @count: size of the value to write
+ *
+ */
+static ssize_t _wake_timeout_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return _ft_sysfs_store(buf, count, &_wake_timeout);
+}
+
+/**
+ * _wake_timeout_show() - Show the amount of time idle check gets extended
+ * after wake on touch
+ * detect policy
+ * @dev: device ptr
+ * @attr: Device attribute
+ * @buf: value read
+ */
+static ssize_t _wake_timeout_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", _wake_timeout);
+}
#define FT_DEVICE_ATTR(name) \
DEVICE_ATTR(name, 0644, _ ## name ## _show, _ ## name ## _store);
@@ -2175,12 +2514,16 @@
FT_DEVICE_ATTR(ft_fast_hang_detect);
FT_DEVICE_ATTR(ft_long_ib_detect);
+static DEVICE_INT_ATTR(wake_nice, 0644, _wake_nice);
+static FT_DEVICE_ATTR(wake_timeout);
const struct device_attribute *ft_attr_list[] = {
&dev_attr_ft_policy,
&dev_attr_ft_pagefault_policy,
&dev_attr_ft_fast_hang_detect,
&dev_attr_ft_long_ib_detect,
+ &dev_attr_wake_nice.attr,
+ &dev_attr_wake_timeout,
NULL,
};
@@ -2316,11 +2659,19 @@
if (enable) {
device->pwrctrl.ctrl_flags = 0;
adreno_dev->fast_hang_detect = 1;
+
+ if (adreno_dev->gpudev->fault_detect_start)
+ adreno_dev->gpudev->fault_detect_start(
+ adreno_dev);
+
kgsl_pwrscale_enable(device);
} else {
- kgsl_pwrctrl_wake(device);
+ kgsl_pwrctrl_wake(device, 0);
device->pwrctrl.ctrl_flags = KGSL_PWR_ON;
adreno_dev->fast_hang_detect = 0;
+ if (adreno_dev->gpudev->fault_detect_stop)
+ adreno_dev->gpudev->fault_detect_stop(
+ adreno_dev);
kgsl_pwrscale_disable(device);
}
@@ -2403,9 +2754,15 @@
/* Make sure we are totally awake */
kgsl_pwrctrl_enable(device);
+ /* save physical performance counter values before GPU soft reset */
+ adreno_perfcounter_save(adreno_dev);
+
/* Reset the GPU */
adreno_dev->gpudev->soft_reset(adreno_dev);
+ /* Restore physical performance counter values after soft reset */
+ adreno_perfcounter_restore(adreno_dev);
+
/* Reinitialize the GPU */
adreno_dev->gpudev->start(adreno_dev);
@@ -2580,9 +2937,6 @@
if (kgsl_gpuaddr_in_memdesc(&ringbuffer->buffer_desc, gpuaddr, size))
return &ringbuffer->buffer_desc;
- if (kgsl_gpuaddr_in_memdesc(&ringbuffer->memptrs_desc, gpuaddr, size))
- return &ringbuffer->memptrs_desc;
-
if (kgsl_gpuaddr_in_memdesc(&device->memstore, gpuaddr, size))
return &device->memstore;
@@ -2842,10 +3196,10 @@
}
-static inline s64 adreno_ticks_to_us(u32 ticks, u32 gpu_freq)
+static inline s64 adreno_ticks_to_us(u32 ticks, u32 freq)
{
- gpu_freq /= 1000000;
- return ticks / gpu_freq;
+ freq /= 1000000;
+ return ticks / freq;
}
static void adreno_power_stats(struct kgsl_device *device,
@@ -2853,32 +3207,21 @@
{
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
- unsigned int cycles = 0;
+ struct adreno_busy_data busy_data;
+ memset(stats, 0, sizeof(*stats));
/*
* Get the busy cycles counted since the counter was last reset.
* If we're not currently active, there shouldn't have been
* any cycles since the last time this function was called.
*/
if (device->state == KGSL_STATE_ACTIVE)
- cycles = adreno_dev->gpudev->busy_cycles(adreno_dev);
+ adreno_dev->gpudev->busy_cycles(adreno_dev, &busy_data);
- /*
- * In order to calculate idle you have to have run the algorithm
- * at least once to get a start time.
- */
- if (pwr->time != 0) {
- s64 tmp = ktime_to_us(ktime_get());
- stats->total_time = tmp - pwr->time;
- pwr->time = tmp;
- stats->busy_time = adreno_ticks_to_us(cycles, device->pwrctrl.
- pwrlevels[device->pwrctrl.active_pwrlevel].
- gpu_freq);
- } else {
- stats->total_time = 0;
- stats->busy_time = 0;
- pwr->time = ktime_to_us(ktime_get());
- }
+ stats->busy_time = adreno_ticks_to_us(busy_data.gpu_busy,
+ kgsl_pwrctrl_active_freq(pwr));
+ stats->ram_time = busy_data.vbif_ram_cycles;
+ stats->ram_wait = busy_data.vbif_starved_ram;
}
void adreno_irqctrl(struct kgsl_device *device, int state)
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 418d230..800caf1 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -62,6 +62,7 @@
#define ADRENO_DEFAULT_PWRSCALE_POLICY NULL
#endif
+void adreno_debugfs_init(struct kgsl_device *device);
#define ADRENO_ISTORE_START 0x5000 /* Istore offset */
@@ -148,6 +149,12 @@
struct adreno_gpudev;
+struct adreno_busy_data {
+ unsigned int gpu_busy;
+ unsigned int vbif_ram_cycles;
+ unsigned int vbif_starved_ram;
+};
+
struct adreno_device {
struct kgsl_device dev; /* Must be first field in this struct */
unsigned long priv;
@@ -188,11 +195,15 @@
unsigned int gpulist_index;
struct ocmem_buf *ocmem_hdl;
unsigned int ocmem_base;
- unsigned int gpu_cycles;
struct adreno_profile profile;
struct kgsl_memdesc pwron_fixup;
unsigned int pwron_fixup_dwords;
struct adreno_dispatcher dispatcher;
+ struct adreno_busy_data busy_data;
+
+ struct work_struct start_work;
+ struct work_struct input_work;
+ unsigned int ram_cycles_lo;
};
/**
@@ -205,6 +216,7 @@
ADRENO_DEVICE_PWRON = 0,
ADRENO_DEVICE_PWRON_FIXUP = 1,
ADRENO_DEVICE_INITIALIZED = 2,
+ ADRENO_DEVICE_STARTED = 3,
};
#define PERFCOUNTER_FLAG_NONE 0x0
@@ -220,6 +232,7 @@
* @offset: register hardware offset
* @load_bit: The bit number in LOAD register which corresponds to this counter
* @select: The countable register offset
+ * @value: The 64 bit countable register value
*/
struct adreno_perfcount_register {
unsigned int countable;
@@ -228,6 +241,7 @@
unsigned int offset;
int load_bit;
unsigned int select;
+ uint64_t value;
};
/**
@@ -240,8 +254,19 @@
struct adreno_perfcount_register *regs;
unsigned int reg_count;
const char *name;
+ unsigned long flags;
};
+/*
+ * ADRENO_PERFCOUNTER_GROUP_FIXED indicates that a perfcounter group is fixed -
+ * instead of having configurable countables like the other groups, registers in
+ * fixed groups have a hardwired countable. So when the user requests a
+ * countable in one of these groups, that countable should be used as the
+ * register offset to return
+ */
+
+#define ADRENO_PERFCOUNTER_GROUP_FIXED BIT(0)
+
/**
* adreno_perfcounts: all available perfcounter groups
* @groups: available groups for this device
@@ -253,7 +278,11 @@
};
#define ADRENO_PERFCOUNTER_GROUP(core, name) { core##_perfcounters_##name, \
- ARRAY_SIZE(core##_perfcounters_##name), __stringify(name) }
+ ARRAY_SIZE(core##_perfcounters_##name), __stringify(name), 0 }
+
+#define ADRENO_PERFCOUNTER_GROUP_FLAGS(core, name, flags) \
+ { core##_perfcounters_##name, \
+ ARRAY_SIZE(core##_perfcounters_##name), __stringify(name), flags }
/**
* adreno_regs: List of registers that are used in kgsl driver for all
@@ -350,12 +379,18 @@
int (*rb_init)(struct adreno_device *, struct adreno_ringbuffer *);
int (*perfcounter_init)(struct adreno_device *);
void (*perfcounter_close)(struct adreno_device *);
+ void (*perfcounter_save)(struct adreno_device *);
+ void (*perfcounter_restore)(struct adreno_device *);
+ void (*fault_detect_start)(struct adreno_device *);
+ void (*fault_detect_stop)(struct adreno_device *);
void (*start)(struct adreno_device *);
- unsigned int (*busy_cycles)(struct adreno_device *);
int (*perfcounter_enable)(struct adreno_device *, unsigned int group,
unsigned int counter, unsigned int countable);
+ void (*busy_cycles)(struct adreno_device *, struct adreno_busy_data *);
uint64_t (*perfcounter_read)(struct adreno_device *adreno_dev,
unsigned int group, unsigned int counter);
+ void (*perfcounter_write)(struct adreno_device *adreno_dev,
+ unsigned int group, unsigned int counter);
int (*coresight_enable) (struct kgsl_device *device);
void (*coresight_disable) (struct kgsl_device *device);
void (*coresight_config_debug_reg) (struct kgsl_device *device,
@@ -364,7 +399,7 @@
void (*postmortem_dump)(struct adreno_device *adreno_dev);
};
-#define FT_DETECT_REGS_COUNT 12
+#define FT_DETECT_REGS_COUNT 14
struct log_field {
bool show;
@@ -845,4 +880,19 @@
return 0;
}
+/**
+ * adreno_get_rptr() - Get the current ringbuffer read pointer
+ * @rb: Pointer the ringbuffer to query
+ *
+ * Get the current read pointer from the GPU register.
+ */
+static inline unsigned int
+adreno_get_rptr(struct adreno_ringbuffer *rb)
+{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device);
+ unsigned int result;
+ adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_RPTR, &result);
+ return result;
+}
+
#endif /*__ADRENO_H */
diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c
index 24a0933..622350d3 100644
--- a/drivers/gpu/msm/adreno_a2xx.c
+++ b/drivers/gpu/msm/adreno_a2xx.c
@@ -1971,17 +1971,19 @@
return 0;
}
-static unsigned int a2xx_busy_cycles(struct adreno_device *adreno_dev)
+static void a2xx_busy_cycles(struct adreno_device *adreno_dev,
+ struct adreno_busy_data *data)
{
struct kgsl_device *device = &adreno_dev->dev;
- unsigned int reg, val;
+ unsigned int reg;
+ memset(data, 0, sizeof(*data));
/* Freeze the counter */
kgsl_regwrite(device, REG_CP_PERFMON_CNTL,
REG_PERF_MODE_CNT | REG_PERF_STATE_FREEZE);
/* Get the value */
- kgsl_regread(device, REG_RBBM_PERFCOUNTER1_LO, &val);
+ kgsl_regread(device, REG_RBBM_PERFCOUNTER1_LO, &data->gpu_busy);
/* Reset the counter */
kgsl_regwrite(device, REG_CP_PERFMON_CNTL,
@@ -1994,7 +1996,6 @@
kgsl_regwrite(device, REG_CP_PERFMON_CNTL,
REG_PERF_MODE_CNT | REG_PERF_STATE_ENABLE);
- return val;
}
static void a2xx_gmeminit(struct adreno_device *adreno_dev)
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index df1794f..3d4c66a 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -95,6 +95,11 @@
#define _SET(_shift, _val) ((_val) << (_shift))
+/* EN/CLR mask for the VBIF counters we care about */
+#define VBIF_PERF_MASK (VBIF_PERF_CNT_0 | VBIF_PERF_PWR_CNT_0)
+#define RBBM_PERF_ENABLE_MASK (RBBM_RBBM_CTL_ENABLE_PWR_CTR1)
+#define RBBM_PERF_RESET_MASK (RBBM_RBBM_CTL_RESET_PWR_CTR1)
+
/*
****************************************************************************
*
@@ -3376,6 +3381,136 @@
return (((uint64_t) hi) << 32) | lo;
}
+/*
+ * values cannot be loaded into physical performance
+ * counters belonging to these groups.
+ */
+static inline int loadable_perfcounter_group(unsigned int groupid)
+{
+ return ((groupid == KGSL_PERFCOUNTER_GROUP_VBIF_PWR) ||
+ (groupid == KGSL_PERFCOUNTER_GROUP_VBIF) ||
+ (groupid == KGSL_PERFCOUNTER_GROUP_PWR)) ? 0 : 1;
+}
+
+/*
+ * Return true if the countable is used and not broken
+ */
+static inline int active_countable(unsigned int countable)
+{
+ return ((countable != KGSL_PERFCOUNTER_NOT_USED) &&
+ (countable != KGSL_PERFCOUNTER_BROKEN));
+}
+
+/**
+ * a3xx_perfcounter_save() - Save the physical performance counter values
+ * @adreno_dev - Adreno device whose registers need to be saved
+ *
+ * Read all the physical performance counter's values and save them
+ * before GPU power collapse.
+ */
+static void a3xx_perfcounter_save(struct adreno_device *adreno_dev)
+{
+ struct adreno_perfcounters *counters = adreno_dev->gpudev->perfcounters;
+ struct adreno_perfcount_group *group;
+ unsigned int regid, groupid;
+
+ for (groupid = 0; groupid < counters->group_count; groupid++) {
+ if (!loadable_perfcounter_group(groupid))
+ continue;
+
+ group = &(counters->groups[groupid]);
+
+ /* group/counter iterator */
+ for (regid = 0; regid < group->reg_count; regid++) {
+ if (!active_countable(group->regs[regid].countable))
+ continue;
+
+ group->regs[regid].value =
+ adreno_dev->gpudev->perfcounter_read(
+ adreno_dev, groupid, regid);
+ }
+ }
+}
+
+/**
+ * a3xx_perfcounter_write() - Write the physical performance counter values.
+ * @adreno_dev - Adreno device whose registers are to be written to.
+ * @group - group to which the physical counter belongs to.
+ * @counter - register id of the physical counter to which the value is
+ * written to.
+ *
+ * This function loads the 64 bit saved value into the particular physical
+ * counter by enabling the corresponding bit in A3XX_RBBM_PERFCTR_LOAD_CMD*
+ * register.
+ */
+static void a3xx_perfcounter_write(struct adreno_device *adreno_dev,
+ unsigned int group, unsigned int counter)
+{
+ struct kgsl_device *device = &(adreno_dev->dev);
+ struct adreno_perfcount_register *reg;
+ unsigned int val;
+
+ reg = &(adreno_dev->gpudev->perfcounters->groups[group].regs[counter]);
+
+ /* Clear the load cmd registers */
+ kgsl_regwrite(device, A3XX_RBBM_PERFCTR_LOAD_CMD0, 0);
+ kgsl_regwrite(device, A3XX_RBBM_PERFCTR_LOAD_CMD1, 0);
+
+ /* Write the saved value to PERFCTR_LOAD_VALUE* registers. */
+ kgsl_regwrite(device, A3XX_RBBM_PERFCTR_LOAD_VALUE_LO,
+ (uint32_t)reg->value);
+ kgsl_regwrite(device, A3XX_RBBM_PERFCTR_LOAD_VALUE_HI,
+ (uint32_t)(reg->value >> 32));
+
+ /*
+ * Set the load bit in PERFCTR_LOAD_CMD for the physical counter
+ * we want to restore. The value in PERFCTR_LOAD_VALUE* is loaded
+ * into the corresponding physical counter.
+ */
+ if (reg->load_bit < 32) {
+ val = 1 << reg->load_bit;
+ kgsl_regwrite(device, A3XX_RBBM_PERFCTR_LOAD_CMD0, val);
+ } else {
+ val = 1 << (reg->load_bit - 32);
+ kgsl_regwrite(device, A3XX_RBBM_PERFCTR_LOAD_CMD1, val);
+ }
+}
+
+/**
+ * a3xx_perfcounter_restore() - Restore the physical performance counter values.
+ * @adreno_dev - Adreno device whose registers are to be restored.
+ *
+ * This function together with a3xx_perfcounter_save make sure that performance
+ * counters are coherent across GPU power collapse.
+ */
+static void a3xx_perfcounter_restore(struct adreno_device *adreno_dev)
+{
+ struct kgsl_device *device = &adreno_dev->dev;
+ struct adreno_perfcounters *counters = adreno_dev->gpudev->perfcounters;
+ struct adreno_perfcount_group *group;
+ unsigned int regid, groupid;
+
+ for (groupid = 0; groupid < counters->group_count; groupid++) {
+ if (!loadable_perfcounter_group(groupid))
+ continue;
+
+ group = &(counters->groups[groupid]);
+
+ /* group/counter iterator */
+ for (regid = 0; regid < group->reg_count; regid++) {
+ if (!active_countable(group->regs[regid].countable))
+ continue;
+
+ a3xx_perfcounter_write(adreno_dev, groupid, regid);
+ }
+ }
+
+ /* Clear the load cmd registers */
+ kgsl_regwrite(device, A3XX_RBBM_PERFCTR_LOAD_CMD0, 0);
+ kgsl_regwrite(device, A3XX_RBBM_PERFCTR_LOAD_CMD1, 0);
+
+}
+
#define A3XX_IRQ_CALLBACK(_c) { .func = _c }
#define A3XX_INT_MASK \
@@ -3474,32 +3609,63 @@
return (status & A3XX_INT_MASK) ? 1 : 0;
}
-static unsigned int a3xx_busy_cycles(struct adreno_device *adreno_dev)
+static unsigned int counter_delta(struct adreno_device *adreno_dev,
+ unsigned int reg, unsigned int *counter)
{
struct kgsl_device *device = &adreno_dev->dev;
unsigned int val;
unsigned int ret = 0;
/* Read the value */
- kgsl_regread(device, A3XX_RBBM_PERFCTR_PWR_1_LO, &val);
+ if (reg == ADRENO_REG_RBBM_PERFCTR_PWR_1_LO)
+ adreno_readreg(adreno_dev, reg, &val);
+ else
+ kgsl_regread(device, reg, &val);
/* Return 0 for the first read */
- if (adreno_dev->gpu_cycles != 0) {
- if (val < adreno_dev->gpu_cycles)
- ret = (0xFFFFFFFF - adreno_dev->gpu_cycles) + val;
+ if (*counter != 0) {
+ if (val < *counter)
+ ret = (0xFFFFFFFF - *counter) + val;
else
- ret = val - adreno_dev->gpu_cycles;
+ ret = val - *counter;
}
- adreno_dev->gpu_cycles = val;
+ *counter = val;
return ret;
}
+/*
+ * a3xx_busy_cycles() - Returns number of gpu cycles
+ * @adreno_dev: Pointer to device ehose cycles are checked
+ *
+ * Returns number of busy cycles since the last time this function is called
+ * Function is common between a3xx and a4xx devices
+ */
+void a3xx_busy_cycles(struct adreno_device *adreno_dev,
+ struct adreno_busy_data *data)
+{
+ struct adreno_busy_data *busy = &adreno_dev->busy_data;
+ struct kgsl_device *device = &adreno_dev->dev;
+
+ memset(data, 0, sizeof(*data));
+
+ data->gpu_busy = counter_delta(adreno_dev,
+ ADRENO_REG_RBBM_PERFCTR_PWR_1_LO,
+ &busy->gpu_busy);
+ if (device->pwrctrl.bus_control) {
+ data->vbif_ram_cycles = counter_delta(adreno_dev,
+ adreno_dev->ram_cycles_lo,
+ &busy->vbif_ram_cycles);
+ data->vbif_starved_ram = counter_delta(adreno_dev,
+ A3XX_VBIF_PERF_PWR_CNT0_LO,
+ &busy->vbif_starved_ram);
+ }
+}
+
struct a3xx_vbif_data {
unsigned int reg;
unsigned int val;
};
-
/* VBIF registers start after 0x3000 so use 0x0 as end of list marker */
static struct a3xx_vbif_data a305_vbif[] = {
/* Set up 16 deep read/write request queues */
@@ -3779,9 +3945,11 @@
ADRENO_PERFCOUNTER_GROUP(a3xx, tp),
ADRENO_PERFCOUNTER_GROUP(a3xx, sp),
ADRENO_PERFCOUNTER_GROUP(a3xx, rb),
- ADRENO_PERFCOUNTER_GROUP(a3xx, pwr),
+ ADRENO_PERFCOUNTER_GROUP_FLAGS(a3xx, pwr,
+ ADRENO_PERFCOUNTER_GROUP_FIXED),
ADRENO_PERFCOUNTER_GROUP(a3xx, vbif),
- ADRENO_PERFCOUNTER_GROUP(a3xx, vbif_pwr),
+ ADRENO_PERFCOUNTER_GROUP_FLAGS(a3xx, vbif_pwr,
+ ADRENO_PERFCOUNTER_GROUP_FIXED),
};
static struct adreno_perfcounters a3xx_perfcounters = {
@@ -3789,85 +3957,154 @@
ARRAY_SIZE(a3xx_perfcounter_groups),
};
-/*
- * a3xx_perfcounter_close() - Return counters that were initialized in
+static inline int _get_counter(struct adreno_device *adreno_dev,
+ int group, int countable, unsigned int *lo,
+ unsigned int *hi)
+{
+ int ret = 0;
+
+ if (*lo == 0) {
+ *hi = 0;
+
+ ret = adreno_perfcounter_get(adreno_dev, group, countable,
+ lo, PERFCOUNTER_FLAG_KERNEL);
+
+ if (ret == 0)
+ *hi = *lo + 1;
+ else {
+ struct kgsl_device *device = &adreno_dev->dev;
+
+ KGSL_DRV_ERR(device,
+ "Unable to allocate fault detect performance counter %d/%d\n",
+ group, countable);
+ KGSL_DRV_ERR(device,
+ "GPU fault detect will be less reliable\n");
+ }
+ }
+
+ return ret;
+}
+
+static inline void _put_counter(struct adreno_device *adreno_dev,
+ int group, int countable, unsigned int *lo,
+ unsigned int *hi)
+{
+ if (*lo != 0) {
+ adreno_perfcounter_put(adreno_dev, group, countable,
+ PERFCOUNTER_FLAG_KERNEL);
+ }
+
+ *lo = 0;
+ *hi = 0;
+}
+
+/**
+ * a3xx_fault_detect_start() - Allocate performance counters used for fast fault
+ * detection
+ * @adreno_dev: Pointer to an adreno_device structure
+ *
+ * Allocate the series of performance counters that should be periodically
+ * checked to verify that the GPU is still moving
+ */
+void a3xx_fault_detect_start(struct adreno_device *adreno_dev)
+{
+ _get_counter(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
+ SP_ALU_ACTIVE_CYCLES,
+ &ft_detect_regs[6], &ft_detect_regs[7]);
+
+ _get_counter(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
+ SP0_ICL1_MISSES,
+ &ft_detect_regs[8], &ft_detect_regs[9]);
+
+ _get_counter(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
+ SP_FS_CFLOW_INSTRUCTIONS,
+ &ft_detect_regs[10], &ft_detect_regs[11]);
+
+ _get_counter(adreno_dev, KGSL_PERFCOUNTER_GROUP_TSE,
+ TSE_INPUT_PRIM_NUM,
+ &ft_detect_regs[12], &ft_detect_regs[13]);
+}
+/**
+ * a3xx_fault_detect_stop() - Release performance counters used for fast fault
+ * detection
+ * @adreno_dev: Pointer to an adreno_device structure
+ *
+ * Release the counters allocated in a3xx_fault_detect_start
+ */
+void a3xx_fault_detect_stop(struct adreno_device *adreno_dev)
+{
+ _put_counter(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
+ SP_ALU_ACTIVE_CYCLES,
+ &ft_detect_regs[6], &ft_detect_regs[7]);
+
+ _put_counter(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
+ SP0_ICL1_MISSES,
+ &ft_detect_regs[8], &ft_detect_regs[9]);
+
+ _put_counter(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
+ SP_FS_CFLOW_INSTRUCTIONS,
+ &ft_detect_regs[10], &ft_detect_regs[11]);
+
+ _put_counter(adreno_dev, KGSL_PERFCOUNTER_GROUP_TSE,
+ TSE_INPUT_PRIM_NUM,
+ &ft_detect_regs[12], &ft_detect_regs[13]);
+}
+
+/**
+ * a3xx_perfcounter_close() - Put counters that were initialized in
* a3xx_perfcounter_init
- * @adreno_dev: The device for which counters were initialized
+ * @adreno_dev: Pointer to an adreno_device structure
*/
static void a3xx_perfcounter_close(struct adreno_device *adreno_dev)
{
- adreno_perfcounter_put(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
- SP_FS_FULL_ALU_INSTRUCTIONS,
+ adreno_perfcounter_put(adreno_dev, KGSL_PERFCOUNTER_GROUP_PWR, 1,
PERFCOUNTER_FLAG_KERNEL);
- adreno_perfcounter_put(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
- SP_FS_CFLOW_INSTRUCTIONS,
+
+ adreno_perfcounter_put(adreno_dev, KGSL_PERFCOUNTER_GROUP_VBIF_PWR, 0,
PERFCOUNTER_FLAG_KERNEL);
- adreno_perfcounter_put(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
- SP0_ICL1_MISSES,
- PERFCOUNTER_FLAG_KERNEL);
- adreno_perfcounter_put(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
- SP_ALU_ACTIVE_CYCLES,
- PERFCOUNTER_FLAG_KERNEL);
+
+ adreno_perfcounter_put(adreno_dev, KGSL_PERFCOUNTER_GROUP_VBIF,
+ VBIF_AXI_TOTAL_BEATS, PERFCOUNTER_FLAG_KERNEL);
+
+ if (adreno_dev->fast_hang_detect)
+ a3xx_fault_detect_stop(adreno_dev);
}
+/**
+ * a3xx_perfcounter_init() - Allocate performance counters for use in the kernel
+ * @adreno_dev: Pointer to an adreno_device structure
+ */
static int a3xx_perfcounter_init(struct adreno_device *adreno_dev)
{
int ret;
+ struct kgsl_device *device = &adreno_dev->dev;
/* SP[3] counter is broken on a330 so disable it if a330 device */
if (adreno_is_a330(adreno_dev))
a3xx_perfcounters_sp[3].countable = KGSL_PERFCOUNTER_BROKEN;
- /*
- * Set SP to count SP_ALU_ACTIVE_CYCLES, it includes
- * all ALU instruction execution regardless precision or shader ID.
- * Set SP to count SP0_ICL1_MISSES, It counts
- * USP L1 instruction miss request.
- * Set SP to count SP_FS_FULL_ALU_INSTRUCTIONS, it
- * counts USP flow control instruction execution.
- * we will use this to augment our hang detection
- */
- if (adreno_dev->fast_hang_detect) {
- ret = adreno_perfcounter_get(adreno_dev,
- KGSL_PERFCOUNTER_GROUP_SP,
- SP_ALU_ACTIVE_CYCLES, &ft_detect_regs[6],
- PERFCOUNTER_FLAG_KERNEL);
- if (ret)
- goto err;
- ft_detect_regs[7] = ft_detect_regs[6] + 1;
- ret = adreno_perfcounter_get(adreno_dev,
- KGSL_PERFCOUNTER_GROUP_SP,
- SP0_ICL1_MISSES, &ft_detect_regs[8],
- PERFCOUNTER_FLAG_KERNEL);
- if (ret)
- goto err;
- ft_detect_regs[9] = ft_detect_regs[8] + 1;
- ret = adreno_perfcounter_get(adreno_dev,
- KGSL_PERFCOUNTER_GROUP_SP,
- SP_FS_CFLOW_INSTRUCTIONS, &ft_detect_regs[10],
- PERFCOUNTER_FLAG_KERNEL);
- if (ret)
- goto err;
- ft_detect_regs[11] = ft_detect_regs[10] + 1;
- }
-
- ret = adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
- SP_FS_FULL_ALU_INSTRUCTIONS, NULL, PERFCOUNTER_FLAG_KERNEL);
- if (ret)
- goto err;
+ if (adreno_dev->fast_hang_detect)
+ a3xx_fault_detect_start(adreno_dev);
/* Reserve and start countable 1 in the PWR perfcounter group */
ret = adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_PWR, 1,
NULL, PERFCOUNTER_FLAG_KERNEL);
- if (ret)
- goto err;
+
+ if (device->pwrctrl.bus_control) {
+ /* VBIF waiting for RAM */
+ ret |= adreno_perfcounter_get(adreno_dev,
+ KGSL_PERFCOUNTER_GROUP_VBIF_PWR, 0,
+ NULL, PERFCOUNTER_FLAG_KERNEL);
+ /* VBIF DDR cycles */
+ ret |= adreno_perfcounter_get(adreno_dev,
+ KGSL_PERFCOUNTER_GROUP_VBIF,
+ VBIF_AXI_TOTAL_BEATS,
+ &adreno_dev->ram_cycles_lo,
+ PERFCOUNTER_FLAG_KERNEL);
+ }
/* Default performance counter profiling to false */
adreno_dev->profile.enabled = false;
return ret;
-
-err:
- a3xx_perfcounter_close(adreno_dev);
- return ret;
}
/**
@@ -3973,12 +4210,9 @@
/* Turn on performance counters */
kgsl_regwrite(device, A3XX_RBBM_PERFCTR_CTL, 0x01);
- /* Turn on the GPU busy counter and let it run free */
-
- adreno_dev->gpu_cycles = 0;
-
/* the CP_DEBUG register offset and value are same as A2XX */
kgsl_regwrite(device, REG_CP_DEBUG, A2XX_CP_DEBUG_DEFAULT);
+ memset(&adreno_dev->busy_data, 0, sizeof(adreno_dev->busy_data));
}
/**
@@ -4345,6 +4579,8 @@
.rb_init = a3xx_rb_init,
.perfcounter_init = a3xx_perfcounter_init,
.perfcounter_close = a3xx_perfcounter_close,
+ .perfcounter_save = a3xx_perfcounter_save,
+ .perfcounter_restore = a3xx_perfcounter_restore,
.irq_control = a3xx_irq_control,
.irq_handler = a3xx_irq_handler,
.irq_pending = a3xx_irq_pending,
@@ -4353,9 +4589,12 @@
.snapshot = a3xx_snapshot,
.perfcounter_enable = a3xx_perfcounter_enable,
.perfcounter_read = a3xx_perfcounter_read,
+ .perfcounter_write = a3xx_perfcounter_write,
.coresight_enable = a3xx_coresight_enable,
.coresight_disable = a3xx_coresight_disable,
.coresight_config_debug_reg = a3xx_coresight_config_debug_reg,
+ .fault_detect_start = a3xx_fault_detect_start,
+ .fault_detect_stop = a3xx_fault_detect_stop,
.soft_reset = a3xx_soft_reset,
.postmortem_dump = a3xx_postmortem_dump,
};
diff --git a/drivers/gpu/msm/adreno_coresight.c b/drivers/gpu/msm/adreno_coresight.c
index 1b827ff..d0ba145 100644
--- a/drivers/gpu/msm/adreno_coresight.c
+++ b/drivers/gpu/msm/adreno_coresight.c
@@ -55,7 +55,12 @@
int adreno_coresight_enable(struct coresight_device *csdev)
{
struct kgsl_device *device = dev_get_drvdata(csdev->dev.parent);
- struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct adreno_device *adreno_dev;
+
+ if (device == NULL)
+ return -ENODEV;
+
+ adreno_dev = ADRENO_DEVICE(device);
/* Check if coresight compatible device, return error otherwise */
if (adreno_dev->gpudev->coresight_enable)
@@ -80,7 +85,12 @@
void adreno_coresight_disable(struct coresight_device *csdev)
{
struct kgsl_device *device = dev_get_drvdata(csdev->dev.parent);
- struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct adreno_device *adreno_dev;
+
+ if (device == NULL)
+ return;
+
+ adreno_dev = ADRENO_DEVICE(device);
/* Check if coresight compatible device, bail otherwise */
if (adreno_dev->gpudev->coresight_disable)
@@ -134,6 +144,10 @@
struct kgsl_device *device = dev_get_drvdata(dev->parent);
struct coresight_attr *csight_attr = container_of(attr,
struct coresight_attr, attr);
+
+ if (device == NULL)
+ return -ENODEV;
+
return coresight_read_reg(device, csight_attr->regname, buf);
}
@@ -142,11 +156,16 @@
const char *buf, size_t size)
{
struct kgsl_device *device = dev_get_drvdata(dev->parent);
- struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct adreno_device *adreno_dev;
struct coresight_attr *csight_attr = container_of(attr,
struct coresight_attr, attr);
unsigned int regval = 0;
+ if (device == NULL)
+ return -ENODEV;
+
+ adreno_dev = ADRENO_DEVICE(device);
+
regval = coresight_convert_reg(buf);
if (adreno_dev->gpudev->coresight_config_debug_reg)
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index 2da36b6..a39ceef 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -1515,8 +1515,14 @@
*/
void adreno_dispatcher_start(struct kgsl_device *device)
{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
complete_all(&device->cmdbatch_gate);
+ /* a305b & a305c GPUs are slower than a330 and needs a larger timer */
+ if (adreno_is_a305b(adreno_dev) || adreno_is_a305c(adreno_dev))
+ _fault_timer_interval = 200;
+
/* Schedule the work loop to get things going */
adreno_dispatcher_schedule(device);
}
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index 8ff07ac..6007a3f 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -589,7 +589,6 @@
int adreno_context_restore(struct adreno_device *adreno_dev,
struct adreno_context *context)
{
- int ret;
struct kgsl_device *device;
unsigned int cmds[5];
@@ -597,6 +596,7 @@
return -EINVAL;
device = &adreno_dev->dev;
+
/* write the context identifier to the ringbuffer */
cmds[0] = cp_nop_packet(1);
cmds[1] = KGSL_CONTEXT_TO_MEM_IDENTIFIER;
@@ -604,14 +604,8 @@
cmds[3] = device->memstore.gpuaddr +
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, current_context);
cmds[4] = context->base.id;
- ret = adreno_ringbuffer_issuecmds(device, context, KGSL_CMD_FLAGS_NONE,
- cmds, 5);
- if (ret)
- return ret;
-
- return kgsl_mmu_setstate(&device->mmu,
- context->base.proc_priv->pagetable,
- context->base.id);
+ return adreno_ringbuffer_issuecmds(device, context,
+ KGSL_CMD_FLAGS_NONE, cmds, 5);
}
@@ -710,9 +704,6 @@
return ret;
}
- /* Put the old instance of the active drawctxt */
- kgsl_context_put(&adreno_dev->drawctxt_active->base);
- adreno_dev->drawctxt_active = NULL;
}
/* Get a refcount to the new instance */
@@ -720,6 +711,11 @@
if (!_kgsl_context_get(&drawctxt->base))
return -EINVAL;
+ ret = kgsl_mmu_setstate(&device->mmu,
+ drawctxt->base.proc_priv->pagetable,
+ adreno_dev->drawctxt_active ?
+ adreno_dev->drawctxt_active->base.id :
+ KGSL_CONTEXT_INVALID);
/* Set the new context */
ret = drawctxt->ops->restore(adreno_dev, drawctxt);
if (ret) {
@@ -737,9 +733,11 @@
*/
ret = kgsl_mmu_setstate(&device->mmu,
device->mmu.defaultpagetable,
- KGSL_CONTEXT_INVALID);
+ adreno_dev->drawctxt_active->base.id);
}
-
+ /* Put the old instance of the active drawctxt */
+ if (adreno_dev->drawctxt_active)
+ kgsl_context_put(&adreno_dev->drawctxt_active->base);
adreno_dev->drawctxt_active = drawctxt;
return 0;
}
diff --git a/drivers/gpu/msm/adreno_profile.c b/drivers/gpu/msm/adreno_profile.c
index 8d3efd6..28fd6d6 100644
--- a/drivers/gpu/msm/adreno_profile.c
+++ b/drivers/gpu/msm/adreno_profile.c
@@ -441,6 +441,11 @@
profile, *(ptr + buf_off++));
if (assigns_list == NULL) {
*log_ptr = (unsigned int) -1;
+
+ shared_buf_inc(profile->shared_size,
+ &profile->shared_tail,
+ SIZE_SHARED_ENTRY(cnt));
+
goto err;
} else {
*log_ptr = assigns_list->groupid << 16 |
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index a43bd54..1383a20 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -368,61 +368,26 @@
*/
void _ringbuffer_setup_common(struct adreno_ringbuffer *rb)
{
- union reg_cp_rb_cntl cp_rb_cntl;
- unsigned int rb_cntl;
struct kgsl_device *device = rb->device;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- kgsl_sharedmem_set(rb->device, &rb->memptrs_desc, 0, 0,
- sizeof(struct kgsl_rbmemptrs));
-
kgsl_sharedmem_set(rb->device, &rb->buffer_desc, 0, 0xAA,
(rb->sizedwords << 2));
- if (adreno_is_a2xx(adreno_dev)) {
- kgsl_regwrite(device, REG_CP_RB_WPTR_BASE,
- (rb->memptrs_desc.gpuaddr
- + GSL_RB_MEMPTRS_WPTRPOLL_OFFSET));
-
- /* setup WPTR delay */
- kgsl_regwrite(device, REG_CP_RB_WPTR_DELAY,
- 0 /*0x70000010 */);
- }
-
- /*setup REG_CP_RB_CNTL */
- adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_CNTL, &rb_cntl);
- cp_rb_cntl.val = rb_cntl;
-
/*
* The size of the ringbuffer in the hardware is the log2
- * representation of the size in quadwords (sizedwords / 2)
+ * representation of the size in quadwords (sizedwords / 2).
+ * Also disable the host RPTR shadow register as it might be unreliable
+ * in certain circumstances.
*/
- cp_rb_cntl.f.rb_bufsz = ilog2(rb->sizedwords >> 1);
- /*
- * Specify the quadwords to read before updating mem RPTR.
- * Like above, pass the log2 representation of the blocksize
- * in quadwords.
- */
- cp_rb_cntl.f.rb_blksz = ilog2(KGSL_RB_BLKSIZE >> 3);
-
- if (adreno_is_a2xx(adreno_dev)) {
- /* WPTR polling */
- cp_rb_cntl.f.rb_poll_en = GSL_RB_CNTL_POLL_EN;
- }
-
- /* mem RPTR writebacks */
- cp_rb_cntl.f.rb_no_update = GSL_RB_CNTL_NO_UPDATE;
-
- adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_CNTL, cp_rb_cntl.val);
+ adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_CNTL,
+ (ilog2(rb->sizedwords >> 1) & 0x3F) |
+ (1 << 27));
adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_BASE,
rb->buffer_desc.gpuaddr);
- adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_RPTR_ADDR,
- rb->memptrs_desc.gpuaddr +
- GSL_RB_MEMPTRS_RPTR_OFFSET);
-
if (adreno_is_a2xx(adreno_dev)) {
/* explicitly clear all cp interrupts */
kgsl_regwrite(device, REG_CP_INT_ACK, 0xFFFFFFFF);
@@ -621,20 +586,6 @@
return status;
}
- /* allocate memory for polling and timestamps */
- /* This really can be at 4 byte alignment boundry but for using MMU
- * we need to make it at page boundary */
- status = kgsl_allocate_contiguous(&rb->memptrs_desc,
- sizeof(struct kgsl_rbmemptrs));
-
- if (status != 0) {
- adreno_ringbuffer_close(rb);
- return status;
- }
-
- /* overlay structure on memptrs memory */
- rb->memptrs = (struct kgsl_rbmemptrs *) rb->memptrs_desc.hostptr;
-
rb->global_ts = 0;
return 0;
@@ -645,7 +596,6 @@
struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device);
kgsl_sharedmem_free(&rb->buffer_desc);
- kgsl_sharedmem_free(&rb->memptrs_desc);
kfree(adreno_dev->pfp_fw);
kfree(adreno_dev->pm4_fw);
@@ -1156,6 +1106,13 @@
/* wait for the suspend gate */
wait_for_completion(&device->cmdbatch_gate);
+ /*
+ * Clear the wake on touch bit to indicate an IB has been submitted
+ * since the last time we set it
+ */
+
+ device->flags &= ~KGSL_FLAG_WAKE_ON_TOUCH;
+
/* Queue the command in the ringbuffer */
ret = adreno_dispatcher_queue_cmd(adreno_dev, drawctxt, cmdbatch,
timestamp);
diff --git a/drivers/gpu/msm/adreno_ringbuffer.h b/drivers/gpu/msm/adreno_ringbuffer.h
index eee4127..697e113 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.h
+++ b/drivers/gpu/msm/adreno_ringbuffer.h
@@ -19,7 +19,6 @@
*/
#define KGSL_RB_SIZE (32 * 1024)
-#define KGSL_RB_BLKSIZE 16
/* CP timestamp register */
#define REG_CP_TIMESTAMP REG_SCRATCH_REG0
@@ -28,27 +27,12 @@
struct kgsl_device;
struct kgsl_device_private;
-#define GSL_RB_MEMPTRS_SCRATCH_COUNT 8
-struct kgsl_rbmemptrs {
- int rptr;
- int wptr_poll;
-};
-
-#define GSL_RB_MEMPTRS_RPTR_OFFSET \
- (offsetof(struct kgsl_rbmemptrs, rptr))
-
-#define GSL_RB_MEMPTRS_WPTRPOLL_OFFSET \
- (offsetof(struct kgsl_rbmemptrs, wptr_poll))
-
struct adreno_ringbuffer {
struct kgsl_device *device;
uint32_t flags;
struct kgsl_memdesc buffer_desc;
- struct kgsl_memdesc memptrs_desc;
- struct kgsl_rbmemptrs *memptrs;
-
/*ringbuffer size */
unsigned int sizedwords;
@@ -70,25 +54,6 @@
/* enable timestamp (...scratch0) memory shadowing */
#define GSL_RB_MEMPTRS_SCRATCH_MASK 0x1
-/* mem rptr */
-#define GSL_RB_CNTL_NO_UPDATE 0x0 /* enable */
-
-/**
- * adreno_get_rptr - Get the current ringbuffer read pointer
- * @rb - the ringbuffer
- *
- * Get the current read pointer, which is written by the GPU.
- */
-static inline unsigned int
-adreno_get_rptr(struct adreno_ringbuffer *rb)
-{
- unsigned int result = rb->memptrs->rptr;
- rmb();
- return result;
-}
-
-#define GSL_RB_CNTL_POLL_EN 0x0 /* disable */
-
/*
* protected mode error checking below register address 0x800
* note: if CP_INTERRUPT packet is used then checking needs
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index fe6b34c..9aefda6 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -60,6 +60,9 @@
struct sg_table *table;
};
+static void kgsl_put_process_private(struct kgsl_device *device,
+ struct kgsl_process_private *private);
+
static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry);
static void
@@ -341,14 +344,19 @@
*/
static int
kgsl_mem_entry_attach_process(struct kgsl_mem_entry *entry,
- struct kgsl_process_private *process)
+ struct kgsl_device_private *dev_priv)
{
int ret;
+ struct kgsl_process_private *process = dev_priv->process_priv;
+
+ ret = kref_get_unless_zero(&process->refcount);
+ if (!ret)
+ return -EBADF;
while (1) {
if (idr_pre_get(&process->mem_idr, GFP_KERNEL) == 0) {
ret = -ENOMEM;
- goto err;
+ goto err_put_proc_priv;
}
spin_lock(&process->mem_lock);
@@ -359,9 +367,10 @@
if (ret == 0)
break;
else if (ret != -EAGAIN)
- goto err;
+ goto err_put_proc_priv;
}
entry->priv = process;
+ entry->dev_priv = dev_priv;
spin_lock(&process->mem_lock);
ret = kgsl_mem_entry_track_gpuaddr(process, entry);
@@ -369,14 +378,17 @@
idr_remove(&process->mem_idr, entry->id);
spin_unlock(&process->mem_lock);
if (ret)
- goto err;
+ goto err_put_proc_priv;
/* map the memory after unlocking if gpuaddr has been assigned */
if (entry->memdesc.gpuaddr) {
ret = kgsl_mmu_map(process->pagetable, &entry->memdesc);
if (ret)
kgsl_mem_entry_detach_process(entry);
}
-err:
+ return ret;
+
+err_put_proc_priv:
+ kgsl_put_process_private(dev_priv->device, process);
return ret;
}
@@ -399,6 +411,7 @@
entry->priv->stats[entry->memtype].cur -= entry->memdesc.size;
spin_unlock(&entry->priv->mem_lock);
+ kgsl_put_process_private(entry->dev_priv->device, entry->priv);
entry->priv = NULL;
}
@@ -605,7 +618,6 @@
static int kgsl_suspend_device(struct kgsl_device *device, pm_message_t state)
{
int status = -EINVAL;
- struct kgsl_pwrscale_policy *policy_saved;
if (!device)
return -EINVAL;
@@ -613,8 +625,6 @@
KGSL_PWR_WARN(device, "suspend start\n");
mutex_lock(&device->mutex);
- policy_saved = device->pwrscale.policy;
- device->pwrscale.policy = NULL;
kgsl_pwrctrl_request_state(device, KGSL_STATE_SUSPEND);
/* Tell the device to drain the submission queue */
@@ -659,7 +669,7 @@
goto end;
}
kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
- device->pwrscale.policy = policy_saved;
+ kgsl_pwrscale_sleep(device);
status = 0;
end:
@@ -767,11 +777,6 @@
*/
static void kgsl_destroy_process_private(struct kref *kref)
{
-
- struct kgsl_mem_entry *entry = NULL;
- int next = 0;
-
-
struct kgsl_process_private *private = container_of(kref,
struct kgsl_process_private, refcount);
@@ -795,20 +800,6 @@
if (private->debug_root)
debugfs_remove_recursive(private->debug_root);
- while (1) {
- spin_lock(&private->mem_lock);
- entry = idr_get_next(&private->mem_idr, &next);
- spin_unlock(&private->mem_lock);
- if (entry == NULL)
- break;
- kgsl_mem_entry_put(entry);
- /*
- * Always start back at the beginning, to
- * ensure all entries are removed,
- * like list_for_each_entry_safe.
- */
- next = 0;
- }
idr_destroy(&private->mem_idr);
kgsl_mmu_putpagetable(private->pagetable);
@@ -953,6 +944,7 @@
struct kgsl_process_private *private = dev_priv->process_priv;
struct kgsl_device *device = dev_priv->device;
struct kgsl_context *context;
+ struct kgsl_mem_entry *entry;
int next = 0;
filep->private_data = NULL;
@@ -981,6 +973,25 @@
next = next + 1;
}
+ next = 0;
+ while (1) {
+ spin_lock(&private->mem_lock);
+ entry = idr_get_next(&private->mem_idr, &next);
+ spin_unlock(&private->mem_lock);
+ if (entry == NULL)
+ break;
+ /*
+ * If the free pending flag is not set it means that user space
+ * did not free it's reference to this entry, in that case
+ * free a reference to this entry, other references are from
+ * within kgsl so they will be freed eventually by kgsl
+ */
+ if (entry->dev_priv == dev_priv && !entry->pending_free) {
+ entry->pending_free = 1;
+ kgsl_mem_entry_put(entry);
+ }
+ next = next + 1;
+ }
/*
* Clean up any to-be-freed entries that belong to this
* process and this device. This is done after the context
@@ -1017,7 +1028,7 @@
if (result)
goto err;
- result = device->ftbl->start(device);
+ result = device->ftbl->start(device, 0);
if (result)
goto err;
/*
@@ -2743,7 +2754,7 @@
/* echo back flags */
param->flags = entry->memdesc.flags;
- result = kgsl_mem_entry_attach_process(entry, private);
+ result = kgsl_mem_entry_attach_process(entry, dev_priv);
if (result)
goto error_attach;
@@ -2867,7 +2878,7 @@
bool full_flush = false;
if (param->id_list == NULL || param->count == 0
- || param->count > (UINT_MAX/sizeof(unsigned int)))
+ || param->count > (PAGE_SIZE / sizeof(unsigned int)))
return -EINVAL;
id_list = kzalloc(param->count * sizeof(unsigned int), GFP_KERNEL);
@@ -3031,7 +3042,7 @@
if (result)
return result;
- result = kgsl_mem_entry_attach_process(entry, private);
+ result = kgsl_mem_entry_attach_process(entry, dev_priv);
if (result != 0)
goto err;
@@ -3064,7 +3075,7 @@
if (result != 0)
goto err;
- result = kgsl_mem_entry_attach_process(entry, private);
+ result = kgsl_mem_entry_attach_process(entry, dev_priv);
if (result != 0)
goto err;
@@ -4054,7 +4065,7 @@
del_timer_sync(&device->idle_timer);
/* Force on the clocks */
- kgsl_pwrctrl_wake(device);
+ kgsl_pwrctrl_wake(device, 0);
/* Disable the irq */
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index ee7a485..6da4a86 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -200,6 +200,7 @@
struct kgsl_process_private *priv;
/* Initialized to 0, set to 1 when entry is marked for freeing */
int pending_free;
+ struct kgsl_device_private *dev_priv;
};
#ifdef CONFIG_MSM_KGSL_MMU_PAGE_FAULT
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index f87c64c..7fc6fae 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -62,6 +62,8 @@
#define KGSL_EVENT_TIMESTAMP_RETIRED 0
#define KGSL_EVENT_CANCELLED 1
+#define KGSL_FLAG_WAKE_ON_TOUCH BIT(0)
+
/*
* "list" of event types for ftrace symbolic magic
*/
@@ -91,7 +93,7 @@
bool (*isidle) (struct kgsl_device *device);
int (*suspend_context) (struct kgsl_device *device);
int (*init) (struct kgsl_device *device);
- int (*start) (struct kgsl_device *device);
+ int (*start) (struct kgsl_device *device, int priority);
int (*stop) (struct kgsl_device *device);
int (*getproperty) (struct kgsl_device *device,
enum kgsl_property_type type, void *value,
@@ -292,7 +294,6 @@
struct list_head events;
struct list_head events_pending_list;
unsigned int events_last_timestamp;
- s64 on_time;
/* Postmortem Control switches */
int pm_regs_enabled;
@@ -418,11 +419,6 @@
struct kgsl_process_private *process_priv;
};
-struct kgsl_power_stats {
- s64 total_time;
- s64 busy_time;
-};
-
struct kgsl_device *kgsl_get_device(int dev_idx);
int kgsl_add_event(struct kgsl_device *device, u32 id, u32 ts,
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 8ed29fb..96ff1b8 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -17,6 +17,7 @@
#include <linux/pm_runtime.h>
#include <mach/msm_iomap.h>
#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
#include <linux/ktime.h>
#include <linux/delay.h>
@@ -123,13 +124,37 @@
return level;
}
+void kgsl_pwrctrl_buslevel_update(struct kgsl_device *device,
+ bool on)
+{
+ struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+ int cur = pwr->pwrlevels[pwr->active_pwrlevel].bus_freq;
+ int buslevel = 0;
+ if (!pwr->pcl)
+ return;
+ /* the bus should be ON to update the active frequency */
+ if (on && !(test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->power_flags)))
+ return;
+ /*
+ * If the bus should remain on calculate our request and submit it,
+ * otherwise request bus level 0, off.
+ */
+ if (on) {
+ buslevel = min_t(int, pwr->pwrlevels[0].bus_freq,
+ cur + pwr->bus_mod);
+ buslevel = max_t(int, buslevel, 1);
+ }
+ msm_bus_scale_client_update_request(pwr->pcl, buslevel);
+ trace_kgsl_pwrlevel(device, pwr->active_pwrlevel, buslevel);
+}
+EXPORT_SYMBOL(kgsl_pwrctrl_buslevel_update);
+
void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device,
unsigned int new_level)
{
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
struct kgsl_pwrlevel *pwrlevel;
- int delta;
- int level;
+ int delta, level;
/* Adjust the power level to the current constraints */
new_level = _adjust_pwrlevel(pwr, new_level);
@@ -150,16 +175,13 @@
*/
pwr->active_pwrlevel = new_level;
+ pwr->bus_mod = 0;
pwrlevel = &pwr->pwrlevels[pwr->active_pwrlevel];
- if (test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->power_flags)) {
-
- if (pwr->pcl)
- msm_bus_scale_client_update_request(pwr->pcl,
- pwrlevel->bus_freq);
- else if (pwr->ebi1_clk)
+ kgsl_pwrctrl_buslevel_update(device, true);
+ if (test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->power_flags))
+ if (pwr->ebi1_clk)
clk_set_rate(pwr->ebi1_clk, pwrlevel->bus_freq);
- }
if (test_bit(KGSL_PWRFLAGS_CLK_ON, &pwr->power_flags) ||
(device->state == KGSL_STATE_NAP)) {
@@ -226,11 +248,8 @@
* a policy only change the active clock if it is higher then the new
* thermal level
*/
-
- if (device->pwrscale.policy == NULL ||
- pwr->thermal_pwrlevel > pwr->active_pwrlevel)
+ if (pwr->thermal_pwrlevel > pwr->active_pwrlevel)
kgsl_pwrctrl_pwrlevel_change(device, pwr->thermal_pwrlevel);
-
mutex_unlock(&device->mutex);
return count;
@@ -285,11 +304,8 @@
* If there is no policy then move to max by default. Otherwise only
* move max if the current level happens to be higher then the new max
*/
-
- if (device->pwrscale.policy == NULL ||
- (max_level > pwr->active_pwrlevel))
+ if (max_level > pwr->active_pwrlevel)
kgsl_pwrctrl_pwrlevel_change(device, max_level);
-
mutex_unlock(&device->mutex);
return count;
@@ -479,8 +495,7 @@
if (device == NULL)
return 0;
pwr = &device->pwrctrl;
- return snprintf(buf, PAGE_SIZE, "%d\n",
- pwr->pwrlevels[pwr->active_pwrlevel].gpu_freq);
+ return snprintf(buf, PAGE_SIZE, "%ld\n", kgsl_pwrctrl_active_freq(pwr));
}
static int kgsl_pwrctrl_idle_timer_store(struct device *dev,
@@ -742,6 +757,42 @@
return __force_on_store(dev, attr, buf, count, KGSL_PWRFLAGS_POWER_ON);
}
+static ssize_t kgsl_pwrctrl_bus_split_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct kgsl_device *device = kgsl_device_from_dev(dev);
+ if (device == NULL)
+ return 0;
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ device->pwrctrl.bus_control);
+}
+
+static ssize_t kgsl_pwrctrl_bus_split_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ char temp[20];
+ unsigned long val;
+ struct kgsl_device *device = kgsl_device_from_dev(dev);
+ int rc;
+
+ if (device == NULL)
+ return 0;
+
+ snprintf(temp, sizeof(temp), "%.*s",
+ (int)min(count, sizeof(temp) - 1), buf);
+ rc = kstrtoul(temp, 0, &val);
+ if (rc)
+ return rc;
+
+ mutex_lock(&device->mutex);
+ device->pwrctrl.bus_control = val ? true : false;
+ mutex_unlock(&device->mutex);
+
+ return count;
+}
+
DEVICE_ATTR(gpuclk, 0644, kgsl_pwrctrl_gpuclk_show, kgsl_pwrctrl_gpuclk_store);
DEVICE_ATTR(max_gpuclk, 0644, kgsl_pwrctrl_max_gpuclk_show,
kgsl_pwrctrl_max_gpuclk_store);
@@ -781,6 +832,9 @@
DEVICE_ATTR(force_rail_on, 0644,
kgsl_pwrctrl_force_rail_on_show,
kgsl_pwrctrl_force_rail_on_store);
+DEVICE_ATTR(bus_split, 0644,
+ kgsl_pwrctrl_bus_split_show,
+ kgsl_pwrctrl_bus_split_store);
static const struct device_attribute *pwrctrl_attr_list[] = {
&dev_attr_gpuclk,
@@ -798,6 +852,7 @@
&dev_attr_force_clk_on,
&dev_attr_force_bus_on,
&dev_attr_force_rail_on,
+ &dev_attr_bus_split,
NULL
};
@@ -924,9 +979,7 @@
clk_set_rate(pwr->ebi1_clk, 0);
clk_disable_unprepare(pwr->ebi1_clk);
}
- if (pwr->pcl)
- msm_bus_scale_client_update_request(pwr->pcl,
- 0);
+ kgsl_pwrctrl_buslevel_update(device, false);
}
} else if (state == KGSL_PWRFLAGS_ON) {
if (!test_and_set_bit(KGSL_PWRFLAGS_AXI_ON,
@@ -938,10 +991,7 @@
pwr->pwrlevels[pwr->active_pwrlevel].
bus_freq);
}
- if (pwr->pcl)
- msm_bus_scale_client_update_request(pwr->pcl,
- pwr->pwrlevels[pwr->active_pwrlevel].
- bus_freq);
+ kgsl_pwrctrl_buslevel_update(device, true);
}
}
}
@@ -1011,7 +1061,7 @@
int kgsl_pwrctrl_init(struct kgsl_device *device)
{
- int i, result = 0;
+ int i, k, m, n = 0, result = 0;
struct clk *clk;
struct platform_device *pdev =
container_of(device->parentdev, struct platform_device, dev);
@@ -1092,26 +1142,61 @@
clk_set_rate(pwr->ebi1_clk,
pwr->pwrlevels[pwr->active_pwrlevel].
bus_freq);
- if (pdata->bus_scale_table != NULL) {
- pwr->pcl = msm_bus_scale_register_client(pdata->
- bus_scale_table);
- if (!pwr->pcl) {
- KGSL_PWR_ERR(device,
- "msm_bus_scale_register_client failed: "
- "id %d table %p", device->id,
- pdata->bus_scale_table);
- result = -EINVAL;
- goto done;
- }
- }
-
- /* Set the power level step multiplier with 1 as the default */
- pwr->step_mul = pdata->step_mul ? pdata->step_mul : 1;
/* Set the CPU latency to 501usec to allow low latency PC modes */
pwr->pm_qos_latency = 501;
pm_runtime_enable(device->parentdev);
+
+ if (pdata->bus_scale_table == NULL)
+ return result;
+
+ pwr->pcl = msm_bus_scale_register_client(pdata->
+ bus_scale_table);
+ if (!pwr->pcl) {
+ KGSL_PWR_ERR(device,
+ "msm_bus_scale_register_client failed: "
+ "id %d table %p", device->id,
+ pdata->bus_scale_table);
+ result = -EINVAL;
+ goto done;
+ }
+
+ /* Set if independent bus BW voting is supported */
+ pwr->bus_control = pdata->bus_control;
+ /*
+ * Pull the BW vote out of the bus table. They will be used to
+ * calculate the ratio between the votes.
+ */
+ for (i = 0; i < pdata->bus_scale_table->num_usecases; i++) {
+ struct msm_bus_paths *usecase =
+ &pdata->bus_scale_table->usecase[i];
+ struct msm_bus_vectors *vector = &usecase->vectors[0];
+ if (vector->dst == MSM_BUS_SLAVE_EBI_CH0 &&
+ vector->ib != 0) {
+ for (k = 0; k < n; k++)
+ if (vector->ib == pwr->bus_ib[k])
+ break;
+ /* if this is a new ib value, save it */
+ if (k == n) {
+ pwr->bus_ib[k] = vector->ib;
+ n++;
+ /* find which pwrlevels use this ib */
+ for (m = 0; m < pwr->num_pwrlevels - 1; m++) {
+ if (pdata->bus_scale_table->
+ usecase[pwr->pwrlevels[m].
+ bus_freq].vectors[0].ib
+ == vector->ib)
+ pwr->bus_index[m] = k;
+ }
+ printk("kgsl bus ib [%d] = %llu\n", k, vector->ib);
+ }
+ }
+ }
+
+ for (m = 0; m < pwr->num_pwrlevels - 1; m++)
+ printk("kgsl bus index is %d for pwrlevel %d\n", pwr->bus_index[m], m);
+
return result;
clk_err:
@@ -1179,7 +1264,7 @@
mutex_lock(&device->mutex);
- kgsl_pwrscale_idle(device);
+ kgsl_pwrscale_update(device);
if (device->state == KGSL_STATE_ACTIVE
|| device->state == KGSL_STATE_NAP) {
@@ -1275,12 +1360,25 @@
static int
_nap(struct kgsl_device *device)
{
+ struct kgsl_power_stats stats;
+
switch (device->state) {
case KGSL_STATE_ACTIVE:
if (!device->ftbl->isidle(device)) {
kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
return -EBUSY;
}
+
+ /*
+ * Read HW busy counters before going to NAP state.
+ * The data might be used by power scale governors
+ * independently of the HW activity. For example
+ * the simple-on-demand governor will get the latest
+ * busy_time data even if the gpu isn't active.
+ */
+ device->ftbl->power_stats(device, &stats);
+ device->pwrscale.accum_stats.busy_time += stats.busy_time;
+
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF, KGSL_STATE_NAP);
kgsl_pwrctrl_set_state(device, KGSL_STATE_NAP);
@@ -1300,7 +1398,7 @@
{
kgsl_pwrctrl_busy_time(device, false);
device->pwrctrl.clk_stats.start = ktime_set(0, 0);
- device->pwrctrl.time = 0;
+
kgsl_pwrscale_sleep(device);
}
@@ -1398,9 +1496,16 @@
}
EXPORT_SYMBOL(kgsl_pwrctrl_sleep);
-/******************************************************************/
-/* Caller must hold the device mutex. */
-int kgsl_pwrctrl_wake(struct kgsl_device *device)
+/**
+ * kgsl_pwrctrl_wake() - Power up the GPU from a slumber/sleep state
+ * @device - Pointer to the kgsl_device struct
+ * @priority - Boolean flag to indicate that the GPU start should be run in the
+ * higher priority thread
+ *
+ * Resume the GPU from a lower power state to ACTIVE. The caller to this
+ * fucntion must host the kgsl_device mutex.
+ */
+int kgsl_pwrctrl_wake(struct kgsl_device *device, int priority)
{
int status = 0;
unsigned int context_id;
@@ -1411,7 +1516,8 @@
kgsl_pwrctrl_request_state(device, KGSL_STATE_ACTIVE);
switch (device->state) {
case KGSL_STATE_SLUMBER:
- status = device->ftbl->start(device);
+ status = device->ftbl->start(device, priority);
+
if (status) {
kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
KGSL_DRV_ERR(device, "start failed %d\n", status);
@@ -1465,7 +1571,7 @@
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
/* Order pwrrail/clk sequence based upon platform */
kgsl_pwrctrl_pwrrail(device, KGSL_PWRFLAGS_ON);
- kgsl_pwrctrl_pwrlevel_change(device, pwr->default_pwrlevel);
+ kgsl_pwrctrl_pwrlevel_change(device, pwr->active_pwrlevel);
kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_ON, KGSL_STATE_ACTIVE);
kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_ON);
}
@@ -1544,7 +1650,7 @@
wait_for_completion(&device->hwaccess_gate);
mutex_lock(&device->mutex);
- ret = kgsl_pwrctrl_wake(device);
+ ret = kgsl_pwrctrl_wake(device, 1);
}
if (ret == 0)
atomic_inc(&device->active_cnt);
@@ -1591,8 +1697,6 @@
BUG_ON(!mutex_is_locked(&device->mutex));
BUG_ON(atomic_read(&device->active_cnt) == 0);
- kgsl_pwrscale_idle(device);
-
if (atomic_dec_and_test(&device->active_cnt)) {
if (device->state == KGSL_STATE_ACTIVE &&
device->requested_state == KGSL_STATE_NONE) {
@@ -1602,6 +1706,8 @@
mod_timer(&device->idle_timer,
jiffies + device->pwrctrl.interval_timeout);
+ } else {
+ kgsl_pwrscale_update(device);
}
trace_kgsl_active_count(device,
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index 9f18160..6ec809d 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -64,7 +64,9 @@
* @clk_stats - structure of clock statistics
* @pm_qos_req_dma - the power management quality of service structure
* @pm_qos_latency - allowed CPU latency in microseconds
- * @step_mul - multiplier for moving between power levels
+ * @bus_control - true if the bus calculation is independent
+ * @bus_index - default bus index into the bus_ib table
+ * @bus_ib - the set of unique ib requests needed for the bus calculation
*/
struct kgsl_pwrctrl {
@@ -88,12 +90,14 @@
uint32_t pcl;
unsigned int idle_needed;
const char *irq_name;
- s64 time;
+ bool irq_last;
struct kgsl_clk_stats clk_stats;
struct pm_qos_request pm_qos_req_dma;
unsigned int pm_qos_latency;
- unsigned int step_mul;
- unsigned int irq_last;
+ bool bus_control;
+ int bus_mod;
+ unsigned int bus_index[KGSL_MAX_PWRLEVELS];
+ uint64_t bus_ib[KGSL_MAX_PWRLEVELS];
};
void kgsl_pwrctrl_irq(struct kgsl_device *device, int state);
@@ -103,9 +107,11 @@
void kgsl_idle_check(struct work_struct *work);
void kgsl_pre_hwaccess(struct kgsl_device *device);
int kgsl_pwrctrl_sleep(struct kgsl_device *device);
-int kgsl_pwrctrl_wake(struct kgsl_device *device);
+int kgsl_pwrctrl_wake(struct kgsl_device *device, int priority);
void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device,
unsigned int level);
+void kgsl_pwrctrl_buslevel_update(struct kgsl_device *device,
+ bool on);
int kgsl_pwrctrl_init_sysfs(struct kgsl_device *device);
void kgsl_pwrctrl_uninit_sysfs(struct kgsl_device *device);
void kgsl_pwrctrl_enable(struct kgsl_device *device);
@@ -117,6 +123,18 @@
return (clk != NULL) ? clk_get_rate(clk) : 0;
}
+/*
+ * kgsl_pwrctrl_active_freq - get currently configured frequency
+ * @pwr: kgsl_pwrctrl structure for the device
+ *
+ * Returns the currently configured frequency for the device.
+ */
+static inline unsigned long
+kgsl_pwrctrl_active_freq(struct kgsl_pwrctrl *pwr)
+{
+ return pwr->pwrlevels[pwr->active_pwrlevel].gpu_freq;
+}
+
void kgsl_pwrctrl_set_state(struct kgsl_device *device, unsigned int state);
void kgsl_pwrctrl_request_state(struct kgsl_device *device, unsigned int state);
diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c
index 47554c4..52732cf 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.c
+++ b/drivers/gpu/msm/kgsl_pwrscale.c
@@ -14,364 +14,497 @@
#include <linux/export.h>
#include <linux/kernel.h>
-#include <asm/page.h>
-
#include "kgsl.h"
#include "kgsl_pwrscale.h"
#include "kgsl_device.h"
+#include "kgsl_trace.h"
-struct kgsl_pwrscale_attribute {
- struct attribute attr;
- ssize_t (*show)(struct kgsl_device *device, char *buf);
- ssize_t (*store)(struct kgsl_device *device, const char *buf,
- size_t count);
-};
+#define FAST_BUS 1
+#define SLOW_BUS -1
-#define to_pwrscale(k) container_of(k, struct kgsl_pwrscale, kobj)
-#define pwrscale_to_device(p) container_of(p, struct kgsl_device, pwrscale)
-#define to_device(k) container_of(k, struct kgsl_device, pwrscale_kobj)
-#define to_pwrscale_attr(a) \
-container_of(a, struct kgsl_pwrscale_attribute, attr)
-#define to_policy_attr(a) \
-container_of(a, struct kgsl_pwrscale_policy_attribute, attr)
+static void do_devfreq_suspend(struct work_struct *work);
+static void do_devfreq_resume(struct work_struct *work);
+static void do_devfreq_notify(struct work_struct *work);
-#define PWRSCALE_ATTR(_name, _mode, _show, _store) \
-struct kgsl_pwrscale_attribute pwrscale_attr_##_name = \
-__ATTR(_name, _mode, _show, _store)
-
-/* Master list of available policies */
-
-static struct kgsl_pwrscale_policy *kgsl_pwrscale_policies[] = {
-#ifdef CONFIG_MSM_SCM
- &kgsl_pwrscale_policy_tz,
-#endif
-#ifdef CONFIG_MSM_SLEEP_STATS_DEVICE
- &kgsl_pwrscale_policy_idlestats,
-#endif
- NULL
-};
-
-static ssize_t pwrscale_policy_store(struct kgsl_device *device,
- const char *buf, size_t count)
-{
- int i;
- struct kgsl_pwrscale_policy *policy = NULL;
-
- /* The special keyword none allows the user to detach all
- policies */
- if (!strncmp("none", buf, 4)) {
- kgsl_pwrscale_detach_policy(device);
- return count;
- }
-
- for (i = 0; kgsl_pwrscale_policies[i]; i++) {
- if (!strncmp(kgsl_pwrscale_policies[i]->name, buf,
- strnlen(kgsl_pwrscale_policies[i]->name,
- PAGE_SIZE))) {
- policy = kgsl_pwrscale_policies[i];
- break;
- }
- }
-
- if (policy)
- if (kgsl_pwrscale_attach_policy(device, policy))
- return -EIO;
-
- return count;
-}
-
-static ssize_t pwrscale_policy_show(struct kgsl_device *device, char *buf)
-{
- int ret;
-
- if (device->pwrscale.policy) {
- ret = snprintf(buf, PAGE_SIZE, "%s",
- device->pwrscale.policy->name);
- if (device->pwrscale.enabled == 0)
- ret += snprintf(buf + ret, PAGE_SIZE - ret,
- " (disabled)");
- ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
- } else
- ret = snprintf(buf, PAGE_SIZE, "none\n");
-
- return ret;
-}
-
-PWRSCALE_ATTR(policy, 0664, pwrscale_policy_show, pwrscale_policy_store);
-
-static ssize_t pwrscale_avail_policies_show(struct kgsl_device *device,
- char *buf)
-{
- int i, ret = 0;
-
- for (i = 0; kgsl_pwrscale_policies[i]; i++) {
- ret += snprintf(buf + ret, PAGE_SIZE - ret, "%s ",
- kgsl_pwrscale_policies[i]->name);
- }
-
- ret += snprintf(buf + ret, PAGE_SIZE - ret, "none\n");
- return ret;
-}
-PWRSCALE_ATTR(avail_policies, 0444, pwrscale_avail_policies_show, NULL);
-
-static struct attribute *pwrscale_attrs[] = {
- &pwrscale_attr_policy.attr,
- &pwrscale_attr_avail_policies.attr,
- NULL
-};
-
-static ssize_t policy_sysfs_show(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- struct kgsl_pwrscale *pwrscale = to_pwrscale(kobj);
- struct kgsl_device *device = pwrscale_to_device(pwrscale);
- struct kgsl_pwrscale_policy_attribute *pattr = to_policy_attr(attr);
- ssize_t ret;
-
- if (pattr->show)
- ret = pattr->show(device, pwrscale, buf);
- else
- ret = -EIO;
-
- return ret;
-}
-
-static ssize_t policy_sysfs_store(struct kobject *kobj,
- struct attribute *attr,
- const char *buf, size_t count)
-{
- struct kgsl_pwrscale *pwrscale = to_pwrscale(kobj);
- struct kgsl_device *device = pwrscale_to_device(pwrscale);
- struct kgsl_pwrscale_policy_attribute *pattr = to_policy_attr(attr);
- ssize_t ret;
-
- if (pattr->store)
- ret = pattr->store(device, pwrscale, buf, count);
- else
- ret = -EIO;
-
- return ret;
-}
-
-static void policy_sysfs_release(struct kobject *kobj)
-{
-}
-
-static ssize_t pwrscale_sysfs_show(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- struct kgsl_device *device = to_device(kobj);
- struct kgsl_pwrscale_attribute *pattr = to_pwrscale_attr(attr);
- ssize_t ret;
-
- if (pattr->show)
- ret = pattr->show(device, buf);
- else
- ret = -EIO;
-
- return ret;
-}
-
-static ssize_t pwrscale_sysfs_store(struct kobject *kobj,
- struct attribute *attr,
- const char *buf, size_t count)
-{
- struct kgsl_device *device = to_device(kobj);
- struct kgsl_pwrscale_attribute *pattr = to_pwrscale_attr(attr);
- ssize_t ret;
-
- if (pattr->store)
- ret = pattr->store(device, buf, count);
- else
- ret = -EIO;
-
- return ret;
-}
-
-static void pwrscale_sysfs_release(struct kobject *kobj)
-{
-}
-
-static const struct sysfs_ops policy_sysfs_ops = {
- .show = policy_sysfs_show,
- .store = policy_sysfs_store
-};
-
-static const struct sysfs_ops pwrscale_sysfs_ops = {
- .show = pwrscale_sysfs_show,
- .store = pwrscale_sysfs_store
-};
-
-static struct kobj_type ktype_pwrscale_policy = {
- .sysfs_ops = &policy_sysfs_ops,
- .default_attrs = NULL,
- .release = policy_sysfs_release
-};
-
-static struct kobj_type ktype_pwrscale = {
- .sysfs_ops = &pwrscale_sysfs_ops,
- .default_attrs = pwrscale_attrs,
- .release = pwrscale_sysfs_release
-};
-
-#define PWRSCALE_ACTIVE(_d) \
- ((_d)->pwrscale.policy && (_d)->pwrscale.enabled)
-
+/*
+ * kgsl_pwrscale_sleep - notify governor that device is going off
+ * @device: The device
+ *
+ * Called shortly after all pending work is completed.
+ */
void kgsl_pwrscale_sleep(struct kgsl_device *device)
{
- if (PWRSCALE_ACTIVE(device) && device->pwrscale.policy->sleep)
- device->pwrscale.policy->sleep(device, &device->pwrscale);
+ BUG_ON(!mutex_is_locked(&device->mutex));
+ if (!device->pwrscale.enabled)
+ return;
+ device->pwrscale.time = device->pwrscale.on_time = 0;
+
+ /* to call devfreq_suspend_device() from a kernel thread */
+ queue_work(device->pwrscale.devfreq_wq,
+ &device->pwrscale.devfreq_suspend_ws);
}
EXPORT_SYMBOL(kgsl_pwrscale_sleep);
+/*
+ * kgsl_pwrscale_wake - notify governor that device is going on
+ * @device: The device
+ *
+ * Called when the device is returning to an active state.
+ */
void kgsl_pwrscale_wake(struct kgsl_device *device)
{
- if (PWRSCALE_ACTIVE(device) && device->pwrscale.policy->wake)
- device->pwrscale.policy->wake(device, &device->pwrscale);
+ struct kgsl_power_stats stats;
+ BUG_ON(!mutex_is_locked(&device->mutex));
+
+ if (!device->pwrscale.enabled)
+ return;
+ /* clear old stats before waking */
+ memset(&device->pwrscale.accum_stats, 0,
+ sizeof(device->pwrscale.accum_stats));
+
+ /* and any hw activity from waking up*/
+ device->ftbl->power_stats(device, &stats);
+
+ device->pwrscale.time = ktime_to_us(ktime_get());
+
+ device->pwrscale.next_governor_call = 0;
+
+ /* to call devfreq_resume_device() from a kernel thread */
+ queue_work(device->pwrscale.devfreq_wq,
+ &device->pwrscale.devfreq_resume_ws);
}
EXPORT_SYMBOL(kgsl_pwrscale_wake);
+/*
+ * kgsl_pwrscale_busy - update pwrscale state for new work
+ * @device: The device
+ *
+ * Called when new work is submitted to the device.
+ * This function must be called with the device mutex locked.
+ */
void kgsl_pwrscale_busy(struct kgsl_device *device)
{
- if (PWRSCALE_ACTIVE(device) && device->pwrscale.policy->busy)
- device->pwrscale.policy->busy(device,
- &device->pwrscale);
+ BUG_ON(!mutex_is_locked(&device->mutex));
+ if (!device->pwrscale.enabled)
+ return;
+ if (device->pwrscale.on_time == 0)
+ device->pwrscale.on_time = ktime_to_us(ktime_get());
}
EXPORT_SYMBOL(kgsl_pwrscale_busy);
-void kgsl_pwrscale_idle(struct kgsl_device *device)
+/*
+ * kgsl_pwrscale_update - update device busy statistics
+ * @device: The device
+ *
+ * Read hardware busy counters when the device is likely to be
+ * on and accumulate the results between devfreq get_dev_status
+ * calls. This is limits the need to turn on clocks to read these
+ * values for governors that run independently of hardware
+ * activity (for example, by time based polling).
+ */
+void kgsl_pwrscale_update(struct kgsl_device *device)
{
- if (PWRSCALE_ACTIVE(device) && device->pwrscale.policy->idle)
- if (device->state == KGSL_STATE_ACTIVE)
- device->pwrscale.policy->idle(device,
- &device->pwrscale);
-}
-EXPORT_SYMBOL(kgsl_pwrscale_idle);
+ struct kgsl_power_stats stats;
+ BUG_ON(!mutex_is_locked(&device->mutex));
+ if (!device->pwrscale.enabled)
+ return;
+
+ if (device->pwrscale.next_governor_call == 0)
+ device->pwrscale.next_governor_call = jiffies;
+
+ if (time_before(jiffies, device->pwrscale.next_governor_call))
+ return;
+
+ device->pwrscale.next_governor_call = jiffies
+ + msecs_to_jiffies(KGSL_GOVERNOR_CALL_INTERVAL);
+
+ if (device->state == KGSL_STATE_ACTIVE) {
+ device->ftbl->power_stats(device, &stats);
+ device->pwrscale.accum_stats.busy_time += stats.busy_time;
+ device->pwrscale.accum_stats.ram_time += stats.ram_time;
+ device->pwrscale.accum_stats.ram_wait += stats.ram_wait;
+ }
+
+ /* to call srcu_notifier_call_chain() from a kernel thread */
+ if (device->requested_state != KGSL_STATE_SLUMBER)
+ queue_work(device->pwrscale.devfreq_wq,
+ &device->pwrscale.devfreq_notify_ws);
+}
+EXPORT_SYMBOL(kgsl_pwrscale_update);
+
+/*
+ * kgsl_pwrscale_disable - temporarily disable the governor
+ * @device: The device
+ *
+ * Temporarily disable the governor, to prevent interference
+ * with profiling tools that expect a fixed clock frequency.
+ * This function must be called with the device mutex locked.
+ */
void kgsl_pwrscale_disable(struct kgsl_device *device)
{
- device->pwrscale.enabled = 0;
+ BUG_ON(!mutex_is_locked(&device->mutex));
+
+ if (device->pwrscale.enabled) {
+ queue_work(device->pwrscale.devfreq_wq,
+ &device->pwrscale.devfreq_suspend_ws);
+ device->pwrscale.enabled = false;
+ kgsl_pwrctrl_pwrlevel_change(device, KGSL_PWRLEVEL_TURBO);
+ }
}
EXPORT_SYMBOL(kgsl_pwrscale_disable);
+/*
+ * kgsl_pwrscale_enable - re-enable the governor
+ * @device: The device
+ *
+ * Reenable the governor after a kgsl_pwrscale_disable() call.
+ * This function must be called with the device mutex locked.
+ */
void kgsl_pwrscale_enable(struct kgsl_device *device)
{
- device->pwrscale.enabled = 1;
+ BUG_ON(!mutex_is_locked(&device->mutex));
+
+ if (!device->pwrscale.enabled) {
+ device->pwrscale.enabled = true;
+ queue_work(device->pwrscale.devfreq_wq,
+ &device->pwrscale.devfreq_resume_ws);
+ }
}
EXPORT_SYMBOL(kgsl_pwrscale_enable);
-int kgsl_pwrscale_policy_add_files(struct kgsl_device *device,
- struct kgsl_pwrscale *pwrscale,
- struct attribute_group *attr_group)
+/*
+ * kgsl_devfreq_target - devfreq_dev_profile.target callback
+ * @dev: see devfreq.h
+ * @freq: see devfreq.h
+ * @flags: see devfreq.h
+ *
+ * This function expects the device mutex to be unlocked.
+ */
+int kgsl_devfreq_target(struct device *dev, unsigned long *freq, u32 flags)
{
- int ret;
+ struct kgsl_device *device = dev_get_drvdata(dev);
+ struct kgsl_pwrctrl *pwr;
+ int level, i, b;
+ unsigned long cur_freq;
- ret = kobject_add(&pwrscale->kobj, &device->pwrscale_kobj,
- "%s", pwrscale->policy->name);
+ if (device == NULL)
+ return -ENODEV;
+ if (freq == NULL)
+ return -EINVAL;
+ if (!device->pwrscale.enabled)
+ return 0;
- if (ret)
- return ret;
+ pwr = &device->pwrctrl;
- ret = sysfs_create_group(&pwrscale->kobj, attr_group);
+ mutex_lock(&device->mutex);
+ cur_freq = kgsl_pwrctrl_active_freq(pwr);
+ level = pwr->active_pwrlevel;
- if (ret) {
- kobject_del(&pwrscale->kobj);
- kobject_put(&pwrscale->kobj);
- }
-
- return ret;
-}
-
-void kgsl_pwrscale_policy_remove_files(struct kgsl_device *device,
- struct kgsl_pwrscale *pwrscale,
- struct attribute_group *attr_group)
-{
- sysfs_remove_group(&pwrscale->kobj, attr_group);
- kobject_del(&pwrscale->kobj);
- kobject_put(&pwrscale->kobj);
-}
-
-static void _kgsl_pwrscale_detach_policy(struct kgsl_device *device)
-{
- if (device->pwrscale.policy != NULL) {
- device->pwrscale.policy->close(device, &device->pwrscale);
-
+ if (*freq != cur_freq) {
+ level = pwr->max_pwrlevel;
+ for (i = pwr->min_pwrlevel; i >= pwr->max_pwrlevel; i--)
+ if (*freq <= pwr->pwrlevels[i].gpu_freq) {
+ level = i;
+ break;
+ }
+ } else if (flags && pwr->bus_control) {
/*
- * Try to set max pwrlevel which will be limited to thermal by
- * kgsl_pwrctrl_pwrlevel_change if thermal is indeed lower
+ * Signal for faster or slower bus. If KGSL isn't already
+ * running at the desired speed for the given level, modify
+ * its vote.
*/
-
- kgsl_pwrctrl_pwrlevel_change(device,
- device->pwrctrl.max_pwrlevel);
- device->pwrctrl.default_pwrlevel =
- device->pwrctrl.max_pwrlevel;
+ b = pwr->bus_mod;
+ if ((flags & DEVFREQ_FLAG_FAST_HINT) &&
+ (pwr->bus_mod != FAST_BUS))
+ pwr->bus_mod = (pwr->bus_mod == SLOW_BUS) ?
+ 0 : FAST_BUS;
+ else if ((flags & DEVFREQ_FLAG_SLOW_HINT) &&
+ (pwr->bus_mod != SLOW_BUS))
+ pwr->bus_mod = (pwr->bus_mod == FAST_BUS) ?
+ 0 : SLOW_BUS;
+ if (pwr->bus_mod != b)
+ kgsl_pwrctrl_buslevel_update(device, true);
}
- device->pwrscale.policy = NULL;
-}
-void kgsl_pwrscale_detach_policy(struct kgsl_device *device)
-{
- mutex_lock(&device->mutex);
- _kgsl_pwrscale_detach_policy(device);
+ kgsl_pwrctrl_pwrlevel_change(device, level);
+ *freq = kgsl_pwrctrl_active_freq(pwr);
+
mutex_unlock(&device->mutex);
+ return 0;
}
-EXPORT_SYMBOL(kgsl_pwrscale_detach_policy);
+EXPORT_SYMBOL(kgsl_devfreq_target);
-int kgsl_pwrscale_attach_policy(struct kgsl_device *device,
- struct kgsl_pwrscale_policy *policy)
+/*
+ * kgsl_devfreq_get_dev_status - devfreq_dev_profile.get_dev_status callback
+ * @dev: see devfreq.h
+ * @freq: see devfreq.h
+ * @flags: see devfreq.h
+ *
+ * This function expects the device mutex to be unlocked.
+ */
+int kgsl_devfreq_get_dev_status(struct device *dev,
+ struct devfreq_dev_status *stat)
{
- int ret = 0;
+ struct kgsl_device *device = dev_get_drvdata(dev);
+ struct kgsl_pwrscale *pwrscale;
+ s64 tmp;
+
+ if (device == NULL)
+ return -ENODEV;
+ if (stat == NULL)
+ return -EINVAL;
+
+ pwrscale = &device->pwrscale;
mutex_lock(&device->mutex);
-
- if (device->pwrscale.policy == policy)
- goto done;
-
- if (device->pwrctrl.num_pwrlevels < 3) {
- ret = -EINVAL;
- goto done;
+ /* make sure we don't turn on clocks just to read stats */
+ if (device->state == KGSL_STATE_ACTIVE) {
+ struct kgsl_power_stats extra;
+ device->ftbl->power_stats(device, &extra);
+ device->pwrscale.accum_stats.busy_time += extra.busy_time;
+ device->pwrscale.accum_stats.ram_time += extra.ram_time;
+ device->pwrscale.accum_stats.ram_wait += extra.ram_wait;
}
- if (device->pwrscale.policy != NULL)
- _kgsl_pwrscale_detach_policy(device);
+ tmp = ktime_to_us(ktime_get());
+ stat->total_time = tmp - pwrscale->time;
+ pwrscale->time = tmp;
- device->pwrscale.policy = policy;
+ stat->busy_time = pwrscale->accum_stats.busy_time;
- device->pwrctrl.default_pwrlevel =
- device->pwrctrl.init_pwrlevel;
- /* Pwrscale is enabled by default at attach time */
- kgsl_pwrscale_enable(device);
+ stat->current_frequency = kgsl_pwrctrl_active_freq(&device->pwrctrl);
- if (policy) {
- ret = device->pwrscale.policy->init(device, &device->pwrscale);
- if (ret)
- device->pwrscale.policy = NULL;
+ if (stat->private_data) {
+ struct xstats *b = (struct xstats *)stat->private_data;
+ b->ram_time = device->pwrscale.accum_stats.ram_time;
+ b->ram_wait = device->pwrscale.accum_stats.ram_wait;
+ b->mod = device->pwrctrl.bus_mod;
}
-done:
+ trace_kgsl_pwrstats(device, stat->total_time, &pwrscale->accum_stats);
+ memset(&pwrscale->accum_stats, 0, sizeof(pwrscale->accum_stats));
+
mutex_unlock(&device->mutex);
- return ret;
+ return 0;
}
-EXPORT_SYMBOL(kgsl_pwrscale_attach_policy);
+EXPORT_SYMBOL(kgsl_devfreq_get_dev_status);
-int kgsl_pwrscale_init(struct kgsl_device *device)
+/*
+ * kgsl_devfreq_get_cur_freq - devfreq_dev_profile.get_cur_freq callback
+ * @dev: see devfreq.h
+ * @freq: see devfreq.h
+ * @flags: see devfreq.h
+ *
+ * This function expects the device mutex to be unlocked.
+ */
+int kgsl_devfreq_get_cur_freq(struct device *dev, unsigned long *freq)
{
+ struct kgsl_device *device = dev_get_drvdata(dev);
+
+ if (device == NULL)
+ return -ENODEV;
+ if (freq == NULL)
+ return -EINVAL;
+
+ mutex_lock(&device->mutex);
+ *freq = kgsl_pwrctrl_active_freq(&device->pwrctrl);
+ mutex_unlock(&device->mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL(kgsl_devfreq_get_cur_freq);
+
+/*
+ * kgsl_devfreq_add_notifier - add a fine grained notifier.
+ * @dev: The device
+ * @nb: Notifier block that will recieve updates.
+ *
+ * Add a notifier to recieve ADRENO_DEVFREQ_NOTIFY_* events
+ * from the device.
+ */
+int kgsl_devfreq_add_notifier(struct device *dev, struct notifier_block *nb)
+{
+ struct kgsl_device *device = dev_get_drvdata(dev);
+
+ if (device == NULL)
+ return -ENODEV;
+
+ if (nb == NULL)
+ return -EINVAL;
+
+ return srcu_notifier_chain_register(&device->pwrscale.nh, nb);
+}
+
+void kgsl_pwrscale_idle(struct kgsl_device *device)
+{
+ BUG_ON(!mutex_is_locked(&device->mutex));
+ queue_work(device->pwrscale.devfreq_wq,
+ &device->pwrscale.devfreq_notify_ws);
+}
+EXPORT_SYMBOL(kgsl_pwrscale_idle);
+
+/*
+ * kgsl_devfreq_del_notifier - remove a fine grained notifier.
+ * @dev: The device
+ * @nb: The notifier block.
+ *
+ * Remove a notifier registered with kgsl_devfreq_add_notifier().
+ */
+int kgsl_devfreq_del_notifier(struct device *dev, struct notifier_block *nb)
+{
+ struct kgsl_device *device = dev_get_drvdata(dev);
+
+ if (device == NULL)
+ return -ENODEV;
+
+ if (nb == NULL)
+ return -EINVAL;
+
+ return srcu_notifier_chain_unregister(&device->pwrscale.nh, nb);
+}
+EXPORT_SYMBOL(kgsl_devfreq_del_notifier);
+
+/*
+ * kgsl_pwrscale_init - Initialize pwrscale.
+ * @dev: The device
+ * @governor: The initial governor to use.
+ *
+ * Initialize devfreq and any non-constant profile data.
+ */
+int kgsl_pwrscale_init(struct device *dev, const char *governor)
+{
+ struct kgsl_device *device;
+ struct kgsl_pwrscale *pwrscale;
+ struct kgsl_pwrctrl *pwr;
+ struct devfreq *devfreq;
+ struct devfreq_dev_profile *profile;
+ struct devfreq_msm_adreno_tz_data *data;
+ int i, out = 0;
int ret;
- ret = kobject_init_and_add(&device->pwrscale_kobj, &ktype_pwrscale,
- &device->dev->kobj, "pwrscale");
+ device = dev_get_drvdata(dev);
+ if (device == NULL)
+ return -ENODEV;
- if (ret)
- return ret;
+ pwrscale = &device->pwrscale;
+ pwr = &device->pwrctrl;
+ profile = &pwrscale->profile;
- kobject_init(&device->pwrscale.kobj, &ktype_pwrscale_policy);
- return ret;
+ srcu_init_notifier_head(&pwrscale->nh);
+
+ profile->initial_freq =
+ pwr->pwrlevels[pwr->default_pwrlevel].gpu_freq;
+ /* Let's start with 10 ms and tune in later */
+ profile->polling_ms = 10;
+
+ /* do not include the 'off' level or duplicate freq. levels */
+ for (i = 0; i < (pwr->num_pwrlevels - 1); i++)
+ pwrscale->freq_table[out++] = pwr->pwrlevels[i].gpu_freq;
+
+ profile->max_state = out;
+ /* link storage array to the devfreq profile pointer */
+ profile->freq_table = pwrscale->freq_table;
+
+ /* if there is only 1 freq, no point in running a governor */
+ if (profile->max_state == 1)
+ governor = "performance";
+
+ /* initialize any governor specific data here */
+ for (i = 0; i < profile->num_governor_data; i++) {
+ if (strncmp("msm-adreno-tz",
+ profile->governor_data[i].name,
+ DEVFREQ_NAME_LEN) == 0) {
+ data = (struct devfreq_msm_adreno_tz_data *)
+ profile->governor_data[i].data;
+ /*
+ * If there is a separate GX power rail, allow
+ * independent modification to its voltage through
+ * the bus bandwidth vote.
+ */
+ if (pwr->bus_control) {
+ out = 0;
+ while (pwr->bus_ib[out]) {
+ pwr->bus_ib[out] =
+ pwr->bus_ib[out] >> 20;
+ out++;
+ }
+ data->bus.num = out;
+ data->bus.ib = &pwr->bus_ib[0];
+ data->bus.index = &pwr->bus_index[0];
+ printk("kgsl: num bus is %d\n", out);
+ } else {
+ data->bus.num = 0;
+ }
+ }
+ }
+
+ devfreq = devfreq_add_device(dev, &pwrscale->profile, governor, NULL);
+ if (IS_ERR(devfreq))
+ return PTR_ERR(devfreq);
+
+ pwrscale->devfreq = devfreq;
+
+ ret = sysfs_create_link(&device->dev->kobj,
+ &devfreq->dev.kobj, "devfreq");
+
+ pwrscale->devfreq_wq = create_freezable_workqueue("kgsl_devfreq_wq");
+ INIT_WORK(&pwrscale->devfreq_suspend_ws, do_devfreq_suspend);
+ INIT_WORK(&pwrscale->devfreq_resume_ws, do_devfreq_resume);
+ INIT_WORK(&pwrscale->devfreq_notify_ws, do_devfreq_notify);
+
+ pwrscale->next_governor_call = 0;
+
+ return 0;
}
EXPORT_SYMBOL(kgsl_pwrscale_init);
+/*
+ * kgsl_pwrscale_close - clean up pwrscale
+ * @device: the device
+ *
+ * This function should be called with the device mutex locked.
+ */
void kgsl_pwrscale_close(struct kgsl_device *device)
{
- kobject_put(&device->pwrscale_kobj);
+ struct kgsl_pwrscale *pwrscale;
+
+ BUG_ON(!mutex_is_locked(&device->mutex));
+
+ pwrscale = &device->pwrscale;
+ flush_workqueue(pwrscale->devfreq_wq);
+ destroy_workqueue(pwrscale->devfreq_wq);
+ devfreq_remove_device(device->pwrscale.devfreq);
+ device->pwrscale.devfreq = NULL;
+ srcu_cleanup_notifier_head(&device->pwrscale.nh);
}
EXPORT_SYMBOL(kgsl_pwrscale_close);
+
+static void do_devfreq_suspend(struct work_struct *work)
+{
+ struct kgsl_pwrscale *pwrscale = container_of(work,
+ struct kgsl_pwrscale, devfreq_suspend_ws);
+ struct devfreq *devfreq = pwrscale->devfreq;
+
+ devfreq_suspend_device(devfreq);
+}
+
+static void do_devfreq_resume(struct work_struct *work)
+{
+ struct kgsl_pwrscale *pwrscale = container_of(work,
+ struct kgsl_pwrscale, devfreq_resume_ws);
+ struct devfreq *devfreq = pwrscale->devfreq;
+
+ devfreq_resume_device(devfreq);
+}
+
+static void do_devfreq_notify(struct work_struct *work)
+{
+ struct kgsl_pwrscale *pwrscale = container_of(work,
+ struct kgsl_pwrscale, devfreq_notify_ws);
+ struct devfreq *devfreq = pwrscale->devfreq;
+ srcu_notifier_call_chain(&pwrscale->nh,
+ ADRENO_DEVFREQ_NOTIFY_RETIRE,
+ devfreq);
+}
diff --git a/drivers/gpu/msm/kgsl_pwrscale.h b/drivers/gpu/msm/kgsl_pwrscale.h
index f17b394..866964c 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.h
+++ b/drivers/gpu/msm/kgsl_pwrscale.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -14,68 +14,58 @@
#ifndef __KGSL_PWRSCALE_H
#define __KGSL_PWRSCALE_H
-struct kgsl_pwrscale;
+#include <linux/devfreq.h>
+#include <linux/msm_adreno_devfreq.h>
-struct kgsl_pwrscale_policy {
- const char *name;
- int (*init)(struct kgsl_device *device,
- struct kgsl_pwrscale *pwrscale);
- void (*close)(struct kgsl_device *device,
- struct kgsl_pwrscale *pwrscale);
- void (*idle)(struct kgsl_device *device,
- struct kgsl_pwrscale *pwrscale);
- void (*busy)(struct kgsl_device *device,
- struct kgsl_pwrscale *pwrscale);
- void (*sleep)(struct kgsl_device *device,
- struct kgsl_pwrscale *pwrscale);
- void (*wake)(struct kgsl_device *device,
- struct kgsl_pwrscale *pwrscale);
+/* devfreq governor call window in msec */
+#define KGSL_GOVERNOR_CALL_INTERVAL 5
+
+struct kgsl_power_stats {
+ u64 busy_time;
+ u64 ram_time;
+ u64 ram_wait;
};
struct kgsl_pwrscale {
- struct kgsl_pwrscale_policy *policy;
- struct kobject kobj;
- void *priv;
- int enabled;
+ struct devfreq *devfreq;
+ struct devfreq_dev_profile profile;
+ unsigned int freq_table[KGSL_MAX_PWRLEVELS];
+ char last_governor[DEVFREQ_NAME_LEN];
+ struct kgsl_power_stats accum_stats;
+ bool enabled;
+ s64 time;
+ s64 on_time;
+ struct srcu_notifier_head nh;
+ struct workqueue_struct *devfreq_wq;
+ struct work_struct devfreq_suspend_ws;
+ struct work_struct devfreq_resume_ws;
+ struct work_struct devfreq_notify_ws;
+ unsigned long next_governor_call;
};
-struct kgsl_pwrscale_policy_attribute {
- struct attribute attr;
- ssize_t (*show)(struct kgsl_device *device,
- struct kgsl_pwrscale *pwrscale, char *buf);
- ssize_t (*store)(struct kgsl_device *device,
- struct kgsl_pwrscale *pwrscale, const char *buf,
- size_t count);
-};
-
-#define PWRSCALE_POLICY_ATTR(_name, _mode, _show, _store) \
- struct kgsl_pwrscale_policy_attribute policy_attr_##_name = \
- __ATTR(_name, _mode, _show, _store)
-
-extern struct kgsl_pwrscale_policy kgsl_pwrscale_policy_tz;
-extern struct kgsl_pwrscale_policy kgsl_pwrscale_policy_idlestats;
-extern struct kgsl_pwrscale_policy kgsl_pwrscale_policy_msm;
-
-int kgsl_pwrscale_init(struct kgsl_device *device);
+int kgsl_pwrscale_init(struct device *dev, const char *governor);
void kgsl_pwrscale_close(struct kgsl_device *device);
-int kgsl_pwrscale_attach_policy(struct kgsl_device *device,
- struct kgsl_pwrscale_policy *policy);
-void kgsl_pwrscale_detach_policy(struct kgsl_device *device);
-
-void kgsl_pwrscale_idle(struct kgsl_device *device);
+void kgsl_pwrscale_update(struct kgsl_device *device);
void kgsl_pwrscale_busy(struct kgsl_device *device);
+void kgsl_pwrscale_idle(struct kgsl_device *device);
void kgsl_pwrscale_sleep(struct kgsl_device *device);
void kgsl_pwrscale_wake(struct kgsl_device *device);
void kgsl_pwrscale_enable(struct kgsl_device *device);
void kgsl_pwrscale_disable(struct kgsl_device *device);
-int kgsl_pwrscale_policy_add_files(struct kgsl_device *device,
- struct kgsl_pwrscale *pwrscale,
- struct attribute_group *attr_group);
+int kgsl_devfreq_target(struct device *dev, unsigned long *freq, u32 flags);
+int kgsl_devfreq_get_dev_status(struct device *, struct devfreq_dev_status *);
+int kgsl_devfreq_get_cur_freq(struct device *dev, unsigned long *freq);
-void kgsl_pwrscale_policy_remove_files(struct kgsl_device *device,
- struct kgsl_pwrscale *pwrscale,
- struct attribute_group *attr_group);
+#define KGSL_PWRSCALE_INIT(_gov_list, _num_gov) { \
+ .enabled = true, \
+ .profile = { \
+ .target = kgsl_devfreq_target, \
+ .get_dev_status = kgsl_devfreq_get_dev_status, \
+ .get_cur_freq = kgsl_devfreq_get_cur_freq, \
+ .governor_data = (_gov_list), \
+ .num_governor_data = (_num_gov), \
+ } }
#endif
diff --git a/drivers/gpu/msm/kgsl_pwrscale_idlestats.c b/drivers/gpu/msm/kgsl_pwrscale_idlestats.c
deleted file mode 100644
index c3188a5..0000000
--- a/drivers/gpu/msm/kgsl_pwrscale_idlestats.c
+++ /dev/null
@@ -1,232 +0,0 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/slab.h>
-#include <linux/timer.h>
-#include <linux/idle_stats_device.h>
-#include <linux/cpufreq.h>
-#include <linux/notifier.h>
-#include <linux/cpumask.h>
-#include <linux/tick.h>
-
-#include "kgsl.h"
-#include "kgsl_pwrscale.h"
-#include "kgsl_device.h"
-
-#define MAX_CORES 4
-struct _cpu_info {
- spinlock_t lock;
- struct notifier_block cpu_nb;
- u64 start[MAX_CORES];
- u64 end[MAX_CORES];
- int curr_freq[MAX_CORES];
- int max_freq[MAX_CORES];
-};
-
-struct idlestats_priv {
- char name[32];
- struct msm_idle_stats_device idledev;
- struct kgsl_device *device;
- struct msm_idle_pulse pulse;
- struct _cpu_info cpu_info;
-};
-
-static int idlestats_cpufreq_notifier(
- struct notifier_block *nb,
- unsigned long val, void *data)
-{
- struct _cpu_info *cpu = container_of(nb,
- struct _cpu_info, cpu_nb);
- struct cpufreq_freqs *freq = data;
-
- if (val != CPUFREQ_POSTCHANGE)
- return 0;
-
- spin_lock(&cpu->lock);
- if (freq->cpu < num_possible_cpus())
- cpu->curr_freq[freq->cpu] = freq->new / 1000;
- spin_unlock(&cpu->lock);
-
- return 0;
-}
-
-static void idlestats_get_sample(struct msm_idle_stats_device *idledev,
- struct msm_idle_pulse *pulse)
-{
- struct kgsl_power_stats stats;
- struct idlestats_priv *priv = container_of(idledev,
- struct idlestats_priv, idledev);
- struct kgsl_device *device = priv->device;
- struct kgsl_pwrctrl *pwr = &device->pwrctrl;
-
- mutex_lock(&device->mutex);
- /* If the GPU is asleep, don't wake it up - assume that we
- are idle */
-
- if (device->state == KGSL_STATE_ACTIVE) {
- device->ftbl->power_stats(device, &stats);
- pulse->busy_start_time = pwr->time - stats.busy_time;
- pulse->busy_interval = stats.busy_time;
- } else {
- pulse->busy_start_time = pwr->time;
- pulse->busy_interval = 0;
- }
- pulse->wait_interval = 0;
- mutex_unlock(&device->mutex);
-}
-
-static void idlestats_busy(struct kgsl_device *device,
- struct kgsl_pwrscale *pwrscale)
-{
- struct idlestats_priv *priv = pwrscale->priv;
- struct kgsl_power_stats stats;
- int i, busy, nr_cpu = 1;
-
- if (priv->pulse.busy_start_time != 0) {
- priv->pulse.wait_interval = 0;
- /* Calculate the total CPU busy time for this GPU pulse */
- for (i = 0; i < num_possible_cpus(); i++) {
- spin_lock(&priv->cpu_info.lock);
- if (cpu_online(i)) {
- priv->cpu_info.end[i] =
- (u64)ktime_to_us(ktime_get()) -
- get_cpu_idle_time_us(i, NULL);
- busy = priv->cpu_info.end[i] -
- priv->cpu_info.start[i];
- /* Normalize the busy time by frequency */
- busy = priv->cpu_info.curr_freq[i] *
- (busy / priv->cpu_info.max_freq[i]);
- priv->pulse.wait_interval += busy;
- nr_cpu++;
- }
- spin_unlock(&priv->cpu_info.lock);
- }
- priv->pulse.wait_interval /= nr_cpu;
-
- /* This is called from within a mutex protected function, so
- no additional locking required */
- device->ftbl->power_stats(device, &stats);
-
- /* If total_time is zero, then we don't have
- any interesting statistics to store */
- if (stats.total_time == 0) {
- priv->pulse.busy_start_time = 0;
- return;
- }
-
- priv->pulse.busy_interval = stats.busy_time;
- msm_idle_stats_idle_end(&priv->idledev, &priv->pulse);
- }
- priv->pulse.busy_start_time = ktime_to_us(ktime_get());
-}
-
-static void idlestats_idle(struct kgsl_device *device,
- struct kgsl_pwrscale *pwrscale)
-{
- int i, nr_cpu;
- struct idlestats_priv *priv = pwrscale->priv;
-
- nr_cpu = num_possible_cpus();
- for (i = 0; i < nr_cpu; i++)
- if (cpu_online(i))
- priv->cpu_info.start[i] =
- (u64)ktime_to_us(ktime_get()) -
- get_cpu_idle_time_us(i, NULL);
-
- msm_idle_stats_idle_start(&priv->idledev);
-}
-
-static void idlestats_sleep(struct kgsl_device *device,
- struct kgsl_pwrscale *pwrscale)
-{
- struct idlestats_priv *priv = pwrscale->priv;
- msm_idle_stats_update_event(&priv->idledev,
- MSM_IDLE_STATS_EVENT_IDLE_TIMER_EXPIRED);
-}
-
-static void idlestats_wake(struct kgsl_device *device,
- struct kgsl_pwrscale *pwrscale)
-{
- /* Use highest perf level on wake-up from
- sleep for better performance */
- kgsl_pwrctrl_pwrlevel_change(device, KGSL_PWRLEVEL_TURBO);
-}
-
-static int idlestats_init(struct kgsl_device *device,
- struct kgsl_pwrscale *pwrscale)
-{
- struct idlestats_priv *priv;
- struct cpufreq_policy cpu_policy;
- int ret, i;
-
- priv = pwrscale->priv = kzalloc(sizeof(struct idlestats_priv),
- GFP_KERNEL);
- if (pwrscale->priv == NULL)
- return -ENOMEM;
-
- snprintf(priv->name, sizeof(priv->name), "idle_stats_%s",
- device->name);
-
- priv->device = device;
-
- priv->idledev.name = (const char *) priv->name;
- priv->idledev.get_sample = idlestats_get_sample;
-
- spin_lock_init(&priv->cpu_info.lock);
- priv->cpu_info.cpu_nb.notifier_call =
- idlestats_cpufreq_notifier;
- ret = cpufreq_register_notifier(&priv->cpu_info.cpu_nb,
- CPUFREQ_TRANSITION_NOTIFIER);
- if (ret)
- goto err;
- for (i = 0; i < num_possible_cpus(); i++) {
- cpufreq_frequency_table_cpuinfo(&cpu_policy,
- cpufreq_frequency_get_table(i));
- priv->cpu_info.max_freq[i] = cpu_policy.max / 1000;
- priv->cpu_info.curr_freq[i] = cpu_policy.max / 1000;
- }
- ret = msm_idle_stats_register_device(&priv->idledev);
-err:
- if (ret) {
- kfree(pwrscale->priv);
- pwrscale->priv = NULL;
- }
-
- return ret;
-}
-
-static void idlestats_close(struct kgsl_device *device,
- struct kgsl_pwrscale *pwrscale)
-{
- struct idlestats_priv *priv = pwrscale->priv;
-
- if (pwrscale->priv == NULL)
- return;
-
- cpufreq_unregister_notifier(&priv->cpu_info.cpu_nb,
- CPUFREQ_TRANSITION_NOTIFIER);
- msm_idle_stats_deregister_device(&priv->idledev);
-
- kfree(pwrscale->priv);
- pwrscale->priv = NULL;
-}
-
-struct kgsl_pwrscale_policy kgsl_pwrscale_policy_idlestats = {
- .name = "idlestats",
- .init = idlestats_init,
- .idle = idlestats_idle,
- .busy = idlestats_busy,
- .sleep = idlestats_sleep,
- .wake = idlestats_wake,
- .close = idlestats_close
-};
diff --git a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
deleted file mode 100644
index 7f8a6b1..0000000
--- a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
+++ /dev/null
@@ -1,269 +0,0 @@
-/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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/export.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/io.h>
-#include <linux/spinlock.h>
-#include <mach/socinfo.h>
-#include <mach/scm.h>
-
-#include "kgsl.h"
-#include "kgsl_pwrscale.h"
-#include "kgsl_device.h"
-
-#define TZ_GOVERNOR_PERFORMANCE 0
-#define TZ_GOVERNOR_ONDEMAND 1
-
-struct tz_priv {
- int governor;
- struct kgsl_power_stats bin;
- unsigned int idle_dcvs;
-};
-spinlock_t tz_lock;
-
-/* FLOOR is 5msec to capture up to 3 re-draws
- * per frame for 60fps content.
- */
-#define FLOOR 5000
-/* CEILING is 50msec, larger than any standard
- * frame length, but less than the idle timer.
- */
-#define CEILING 50000
-#define TZ_RESET_ID 0x3
-#define TZ_UPDATE_ID 0x4
-#define TZ_INIT_ID 0x6
-
-/* Trap into the TrustZone, and call funcs there. */
-static int __secure_tz_entry2(u32 cmd, u32 val1, u32 val2)
-{
- int ret;
- spin_lock(&tz_lock);
- /* sync memory before sending the commands to tz*/
- __iowmb();
- ret = scm_call_atomic2(SCM_SVC_IO, cmd, val1, val2);
- spin_unlock(&tz_lock);
- return ret;
-}
-
-static int __secure_tz_entry3(u32 cmd, u32 val1, u32 val2,
- u32 val3)
-{
- int ret;
- spin_lock(&tz_lock);
- /* sync memory before sending the commands to tz*/
- __iowmb();
- ret = scm_call_atomic3(SCM_SVC_IO, cmd, val1, val2,
- val3);
- spin_unlock(&tz_lock);
- return ret;
-}
-
-static ssize_t tz_governor_show(struct kgsl_device *device,
- struct kgsl_pwrscale *pwrscale,
- char *buf)
-{
- struct tz_priv *priv = pwrscale->priv;
- int ret;
-
- if (priv->governor == TZ_GOVERNOR_ONDEMAND)
- ret = snprintf(buf, 10, "ondemand\n");
- else
- ret = snprintf(buf, 13, "performance\n");
-
- return ret;
-}
-
-static ssize_t tz_governor_store(struct kgsl_device *device,
- struct kgsl_pwrscale *pwrscale,
- const char *buf, size_t count)
-{
- char str[20];
- struct tz_priv *priv = pwrscale->priv;
- struct kgsl_pwrctrl *pwr = &device->pwrctrl;
- int ret;
-
- ret = sscanf(buf, "%20s", str);
- if (ret != 1)
- return -EINVAL;
-
- mutex_lock(&device->mutex);
-
- if (!strncmp(str, "ondemand", 8))
- priv->governor = TZ_GOVERNOR_ONDEMAND;
- else if (!strncmp(str, "performance", 11))
- priv->governor = TZ_GOVERNOR_PERFORMANCE;
-
- if (priv->governor == TZ_GOVERNOR_PERFORMANCE) {
- kgsl_pwrctrl_pwrlevel_change(device, pwr->max_pwrlevel);
- pwr->default_pwrlevel = pwr->max_pwrlevel;
- } else {
- pwr->default_pwrlevel = pwr->init_pwrlevel;
- }
-
- mutex_unlock(&device->mutex);
- return count;
-}
-
-PWRSCALE_POLICY_ATTR(governor, 0644, tz_governor_show, tz_governor_store);
-
-static struct attribute *tz_attrs[] = {
- &policy_attr_governor.attr,
- NULL
-};
-
-static struct attribute_group tz_attr_group = {
- .attrs = tz_attrs,
-};
-
-static void tz_wake(struct kgsl_device *device, struct kgsl_pwrscale *pwrscale)
-{
- struct tz_priv *priv = pwrscale->priv;
- if (device->state != KGSL_STATE_NAP &&
- priv->governor == TZ_GOVERNOR_ONDEMAND)
- kgsl_pwrctrl_pwrlevel_change(device,
- device->pwrctrl.default_pwrlevel);
-}
-
-static void tz_idle(struct kgsl_device *device, struct kgsl_pwrscale *pwrscale)
-{
- struct kgsl_pwrctrl *pwr = &device->pwrctrl;
- struct tz_priv *priv = pwrscale->priv;
- struct kgsl_power_stats stats;
- int val, idle;
-
- /* In "performance" mode the clock speed always stays
- the same */
- if (priv->governor == TZ_GOVERNOR_PERFORMANCE)
- return;
-
- device->ftbl->power_stats(device, &stats);
- priv->bin.total_time += stats.total_time;
- priv->bin.busy_time += stats.busy_time;
- /* Do not waste CPU cycles running this algorithm if
- * the GPU just started, or if less than FLOOR time
- * has passed since the last run.
- */
- if ((stats.total_time == 0) ||
- (priv->bin.total_time < FLOOR))
- return;
-
- /* If there is an extended block of busy processing, set
- * frequency to turbo. Otherwise run the normal algorithm.
- */
- if (priv->bin.busy_time > CEILING) {
- val = 0;
- kgsl_pwrctrl_pwrlevel_change(device,
- KGSL_PWRLEVEL_TURBO);
- } else if (priv->idle_dcvs) {
- idle = priv->bin.total_time - priv->bin.busy_time;
- idle = (idle > 0) ? idle : 0;
- val = __secure_tz_entry2(TZ_UPDATE_ID, idle, device->id);
- } else {
- if (pwr->step_mul > 1)
- val = __secure_tz_entry3(TZ_UPDATE_ID,
- (pwr->active_pwrlevel + 1)/2,
- priv->bin.total_time, priv->bin.busy_time);
- else
- val = __secure_tz_entry3(TZ_UPDATE_ID,
- pwr->active_pwrlevel,
- priv->bin.total_time, priv->bin.busy_time);
- }
-
- priv->bin.total_time = 0;
- priv->bin.busy_time = 0;
-
- /* If the decision is to move to a lower level, make sure the GPU
- * frequency drops.
- */
- if (val > 0)
- val *= pwr->step_mul;
- if (val)
- kgsl_pwrctrl_pwrlevel_change(device,
- pwr->active_pwrlevel + val);
-}
-
-static void tz_busy(struct kgsl_device *device,
- struct kgsl_pwrscale *pwrscale)
-{
- device->on_time = ktime_to_us(ktime_get());
-}
-
-static void tz_sleep(struct kgsl_device *device,
- struct kgsl_pwrscale *pwrscale)
-{
- struct tz_priv *priv = pwrscale->priv;
-
- __secure_tz_entry2(TZ_RESET_ID, 0, 0);
- priv->bin.total_time = 0;
- priv->bin.busy_time = 0;
-}
-
-#ifdef CONFIG_MSM_SCM
-static int tz_init(struct kgsl_device *device, struct kgsl_pwrscale *pwrscale)
-{
- int i = 0, j = 1, ret = 0;
- struct tz_priv *priv;
- struct kgsl_pwrctrl *pwr = &device->pwrctrl;
- unsigned int tz_pwrlevels[KGSL_MAX_PWRLEVELS + 1];
-
- priv = pwrscale->priv = kzalloc(sizeof(struct tz_priv), GFP_KERNEL);
- if (pwrscale->priv == NULL)
- return -ENOMEM;
- priv->idle_dcvs = 0;
- priv->governor = TZ_GOVERNOR_ONDEMAND;
- spin_lock_init(&tz_lock);
- kgsl_pwrscale_policy_add_files(device, pwrscale, &tz_attr_group);
- for (i = 0; i < pwr->num_pwrlevels - 1; i++) {
- if (i == 0)
- tz_pwrlevels[j] = pwr->pwrlevels[i].gpu_freq;
- else if (pwr->pwrlevels[i].gpu_freq !=
- pwr->pwrlevels[i - 1].gpu_freq) {
- j++;
- tz_pwrlevels[j] = pwr->pwrlevels[i].gpu_freq;
- }
- }
- tz_pwrlevels[0] = j;
- ret = scm_call(SCM_SVC_DCVS, TZ_INIT_ID, tz_pwrlevels,
- sizeof(tz_pwrlevels), NULL, 0);
- if (ret) {
- KGSL_DRV_ERR(device, "Fall back to idle based GPU DCVS algo");
- priv->idle_dcvs = 1;
- }
- return 0;
-}
-#else
-static int tz_init(struct kgsl_device *device, struct kgsl_pwrscale *pwrscale)
-{
- return -EINVAL;
-}
-#endif /* CONFIG_MSM_SCM */
-
-static void tz_close(struct kgsl_device *device, struct kgsl_pwrscale *pwrscale)
-{
- kgsl_pwrscale_policy_remove_files(device, pwrscale, &tz_attr_group);
- kfree(pwrscale->priv);
- pwrscale->priv = NULL;
-}
-
-struct kgsl_pwrscale_policy kgsl_pwrscale_policy_tz = {
- .name = "trustzone",
- .init = tz_init,
- .busy = tz_busy,
- .idle = tz_idle,
- .sleep = tz_sleep,
- .wake = tz_wake,
- .close = tz_close
-};
-EXPORT_SYMBOL(kgsl_pwrscale_policy_tz);
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index d031d5e..d3adf84 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -591,7 +591,6 @@
sglen_alloc = PAGE_ALIGN(size) >> PAGE_SHIFT;
- memdesc->size = size;
memdesc->pagetable = pagetable;
memdesc->ops = &kgsl_page_alloc_ops;
@@ -654,6 +653,14 @@
continue;
}
+ /*
+ * Update sglen and memdesc size,as requested allocation
+ * not served fully. So that they can be correctly freed
+ * in kgsl_sharedmem_free().
+ */
+ memdesc->sglen = sglen;
+ memdesc->size = (size - len);
+
KGSL_CORE_ERR(
"Out of memory: only allocated %dKB of %dKB requested\n",
(size - len) >> 10, size >> 10);
@@ -670,6 +677,7 @@
}
memdesc->sglen = sglen;
+ memdesc->size = size;
/*
* All memory that goes to the user has to be zeroed out before it gets
@@ -716,15 +724,15 @@
outer_cache_range_op_sg(memdesc->sg, memdesc->sglen,
KGSL_CACHE_OP_FLUSH);
- KGSL_STATS_ADD(size, kgsl_driver.stats.page_alloc,
- kgsl_driver.stats.page_alloc_max);
-
order = get_order(size);
if (order < 16)
kgsl_driver.stats.histogram[order]++;
done:
+ KGSL_STATS_ADD(memdesc->size, kgsl_driver.stats.page_alloc,
+ kgsl_driver.stats.page_alloc_max);
+
if ((memdesc->sglen_alloc * sizeof(struct page *)) > PAGE_SIZE)
vfree(pages);
else
diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h
index 3986c61..f0114ad 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.h
+++ b/drivers/gpu/msm/kgsl_sharedmem.h
@@ -141,6 +141,9 @@
static inline void *kgsl_sg_alloc(unsigned int sglen)
{
+ if ((sglen == 0) || (sglen >= ULONG_MAX / sizeof(struct scatterlist)))
+ return NULL;
+
if ((sglen * sizeof(struct scatterlist)) < PAGE_SIZE)
return kzalloc(sglen * sizeof(struct scatterlist), GFP_KERNEL);
else
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
index 5f39b8b..c737cc8 100644
--- a/drivers/gpu/msm/kgsl_trace.h
+++ b/drivers/gpu/msm/kgsl_trace.h
@@ -796,6 +796,37 @@
)
);
+
+TRACE_EVENT(kgsl_pwrstats,
+ TP_PROTO(struct kgsl_device *device, s64 time,
+ struct kgsl_power_stats *pstats),
+
+ TP_ARGS(device, time, pstats),
+
+ TP_STRUCT__entry(
+ __string(device_name, device->name)
+ __field(s64, total_time)
+ __field(u64, busy_time)
+ __field(u64, ram_time)
+ __field(u64, ram_wait)
+ ),
+
+ TP_fast_assign(
+ __assign_str(device_name, device->name);
+ __entry->total_time = time;
+ __entry->busy_time = pstats->busy_time;
+ __entry->ram_time = pstats->ram_time;
+ __entry->ram_wait = pstats->ram_wait;
+ ),
+
+ TP_printk(
+ "d_name=%s total=%lld busy=%lld ram_time=%lld ram_wait=%lld",
+ __get_str(device_name), __entry->total_time, __entry->busy_time,
+ __entry->ram_time, __entry->ram_wait
+ )
+);
+
+
#endif /* _KGSL_TRACE_H */
/* This part must be outside protection */
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index ae7aee0..270a7a6 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -94,7 +94,7 @@
#define Z180_CMDWINDOW_ADDR_SHIFT 8
static int z180_init(struct kgsl_device *device);
-static int z180_start(struct kgsl_device *device);
+static int z180_start(struct kgsl_device *device, int priority);
static int z180_stop(struct kgsl_device *device);
static int z180_wait(struct kgsl_device *device,
struct kgsl_context *context,
@@ -559,8 +559,7 @@
if (status)
goto error_close_ringbuffer;
- kgsl_pwrscale_init(device);
- kgsl_pwrscale_attach_policy(device, Z180_DEFAULT_PWRSCALE_POLICY);
+ kgsl_pwrscale_init(&pdev->dev, CONFIG_MSM_Z180_DEFAULT_GOVERNOR);
return status;
@@ -595,7 +594,7 @@
return 0;
}
-static int z180_start(struct kgsl_device *device)
+static int z180_start(struct kgsl_device *device, int priority)
{
int status = 0;
@@ -955,18 +954,16 @@
static void z180_power_stats(struct kgsl_device *device,
struct kgsl_power_stats *stats)
{
- struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+ struct kgsl_pwrscale *pwrscale = &device->pwrscale;
s64 tmp = ktime_to_us(ktime_get());
- if (pwr->time == 0) {
- pwr->time = tmp;
- stats->total_time = 0;
+ memset(stats, 0, sizeof(stats));
+ if (pwrscale->on_time == 0) {
+ pwrscale->on_time = tmp;
stats->busy_time = 0;
} else {
- stats->total_time = tmp - pwr->time;
- pwr->time = tmp;
- stats->busy_time = tmp - device->on_time;
- device->on_time = tmp;
+ stats->busy_time = tmp - pwrscale->on_time;
+ pwrscale->on_time = tmp;
}
}
diff --git a/drivers/gpu/msm/z180.h b/drivers/gpu/msm/z180.h
index a36e92d..5b54445 100644
--- a/drivers/gpu/msm/z180.h
+++ b/drivers/gpu/msm/z180.h
@@ -26,8 +26,6 @@
#define Z180_DEVICE(device) \
KGSL_CONTAINER_OF(device, struct z180_device, dev)
-#define Z180_DEFAULT_PWRSCALE_POLICY NULL
-
/* Wait a maximum of 10 seconds when trying to idle the core */
#define Z180_IDLE_TIMEOUT (20 * 1000)
diff --git a/drivers/hwmon/epm_adc.c b/drivers/hwmon/epm_adc.c
index f7cf2df..2f5ed9d 100644
--- a/drivers/hwmon/epm_adc.c
+++ b/drivers/hwmon/epm_adc.c
@@ -888,6 +888,12 @@
init_resp->num_dev = rx_buf[6];
init_resp->num_channel = rx_buf[7];
+ pr_debug("EPM PSOC response for hello command: resp_cmd:0x%x\n",
+ rx_buf[0]);
+ pr_debug("EPM PSOC version:0x%x\n", rx_buf[1]);
+ pr_debug("EPM PSOC firmware version:0x%x\n",
+ rx_buf[6] | rx_buf[5] | rx_buf[4] | rx_buf[3]);
+
return rc;
}
diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c
index 9e0be59..6a52aa3 100644
--- a/drivers/hwmon/qpnp-adc-common.c
+++ b/drivers/hwmon/qpnp-adc-common.c
@@ -238,6 +238,60 @@
{800, 549},
};
+static const struct qpnp_vadc_map_pt adcmap_qrd_skug_btm_threshold[] = {
+ {-200, 1338},
+ {-180, 1307},
+ {-160, 1276},
+ {-140, 1244},
+ {-120, 1213},
+ {-100, 1182},
+ {-80, 1151},
+ {-60, 1121},
+ {-40, 1092},
+ {-20, 1063},
+ {0, 1035},
+ {20, 1008},
+ {40, 982},
+ {60, 957},
+ {80, 933},
+ {100, 910},
+ {120, 889},
+ {140, 868},
+ {160, 848},
+ {180, 830},
+ {200, 812},
+ {220, 795},
+ {240, 780},
+ {260, 765},
+ {280, 751},
+ {300, 738},
+ {320, 726},
+ {340, 714},
+ {360, 704},
+ {380, 694},
+ {400, 684},
+ {420, 675},
+ {440, 667},
+ {460, 659},
+ {480, 652},
+ {500, 645},
+ {520, 639},
+ {540, 633},
+ {560, 627},
+ {580, 622},
+ {600, 617},
+ {620, 613},
+ {640, 608},
+ {660, 604},
+ {680, 600},
+ {700, 597},
+ {720, 593},
+ {740, 590},
+ {760, 587},
+ {780, 585},
+ {800, 582},
+};
+
/* Voltage to temperature */
static const struct qpnp_vadc_map_pt adcmap_100k_104ef_104fb[] = {
{1758, -40},
@@ -612,6 +666,24 @@
}
EXPORT_SYMBOL(qpnp_adc_scale_qrd_skuaa_batt_therm);
+int32_t qpnp_adc_scale_qrd_skug_batt_therm(struct qpnp_vadc_chip *chip,
+ int32_t adc_code,
+ const struct qpnp_adc_properties *adc_properties,
+ const struct qpnp_vadc_chan_properties *chan_properties,
+ struct qpnp_vadc_result *adc_chan_result)
+{
+ int64_t bat_voltage = 0;
+
+ bat_voltage = qpnp_adc_scale_ratiometric_calib(adc_code,
+ adc_properties, chan_properties);
+
+ return qpnp_adc_map_temp_voltage(
+ adcmap_qrd_skug_btm_threshold,
+ ARRAY_SIZE(adcmap_qrd_skug_btm_threshold),
+ bat_voltage,
+ &adc_chan_result->physical);
+}
+EXPORT_SYMBOL(qpnp_adc_scale_qrd_skug_batt_therm);
int32_t qpnp_adc_scale_therm_pu1(struct qpnp_vadc_chip *chip,
int32_t adc_code,
const struct qpnp_adc_properties *adc_properties,
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
index adaff41..9839595 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -147,7 +147,6 @@
struct list_head list;
int64_t die_temp;
struct delayed_work iadc_work;
- struct mutex iadc_vadc_lock;
bool iadc_mode_sel;
struct qpnp_iadc_comp iadc_comp;
struct qpnp_vadc_chip *vadc_dev;
@@ -1012,12 +1011,10 @@
if (qpnp_iadc_is_valid(iadc) < 0)
return -EPROBE_DEFER;
- if (!iadc->iadc_mode_sel) {
- rc = qpnp_check_pmic_temp(iadc);
- if (rc) {
- pr_err("Error checking pmic therm temp\n");
- return rc;
- }
+ rc = qpnp_check_pmic_temp(iadc);
+ if (rc) {
+ pr_err("Error checking pmic therm temp\n");
+ return rc;
}
mutex_lock(&iadc->adc->adc_lock);
@@ -1121,24 +1118,21 @@
enum qpnp_iadc_channels i_channel, struct qpnp_iadc_result *i_result,
enum qpnp_vadc_channels v_channel, struct qpnp_vadc_result *v_result)
{
- int rc = 0;
+ int rc = 0, mode_sel = 0, num = 0, rsense_n_ohms = 0, sign = 0;
+ uint16_t raw_data;
+ int32_t rsense_u_ohms = 0;
+ int64_t result_current;
if (qpnp_iadc_is_valid(iadc) < 0)
return -EPROBE_DEFER;
- mutex_lock(&iadc->iadc_vadc_lock);
+ mutex_lock(&iadc->adc->adc_lock);
if (iadc->iadc_poll_eoc) {
pr_debug("acquiring iadc eoc wakelock\n");
pm_stay_awake(iadc->dev);
}
- rc = qpnp_check_pmic_temp(iadc);
- if (rc) {
- pr_err("PMIC die temp check failed\n");
- goto fail;
- }
-
iadc->iadc_mode_sel = true;
rc = qpnp_vadc_iadc_sync_request(iadc->vadc_dev, v_channel);
@@ -1147,11 +1141,43 @@
goto fail;
}
- rc = qpnp_iadc_read(iadc, i_channel, i_result);
- if (rc)
- pr_err("Configuring IADC failed\n");
- /* Intentional fall through to release VADC */
+ rc = qpnp_iadc_configure(iadc, i_channel, &raw_data, mode_sel);
+ if (rc < 0) {
+ pr_err("qpnp adc result read failed with %d\n", rc);
+ goto fail_release_vadc;
+ }
+ rc = qpnp_iadc_get_rsense(iadc, &rsense_n_ohms);
+ pr_debug("current raw:0%x and rsense:%d\n",
+ raw_data, rsense_n_ohms);
+ rsense_u_ohms = rsense_n_ohms/1000;
+ num = raw_data - iadc->adc->calib.offset_raw;
+ if (num < 0) {
+ sign = 1;
+ num = -num;
+ }
+
+ i_result->result_uv = (num * QPNP_ADC_GAIN_NV)/
+ (iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw);
+ result_current = i_result->result_uv;
+ result_current *= QPNP_IADC_NANO_VOLTS_FACTOR;
+ /* Intentional fall through. Process the result w/o comp */
+ do_div(result_current, rsense_u_ohms);
+
+ if (sign) {
+ i_result->result_uv = -i_result->result_uv;
+ result_current = -result_current;
+ }
+ result_current *= -1;
+ rc = qpnp_iadc_comp_result(iadc, &result_current);
+ if (rc < 0)
+ pr_err("Error during compensating the IADC\n");
+ rc = 0;
+ result_current *= -1;
+
+ i_result->result_ua = (int32_t) result_current;
+
+fail_release_vadc:
rc = qpnp_vadc_iadc_sync_complete_request(iadc->vadc_dev, v_channel,
v_result);
if (rc)
@@ -1163,7 +1189,7 @@
pr_debug("releasing iadc eoc wakelock\n");
pm_relax(iadc->dev);
}
- mutex_unlock(&iadc->iadc_vadc_lock);
+ mutex_unlock(&iadc->adc->adc_lock);
return rc;
}
@@ -1306,7 +1332,6 @@
goto fail;
}
- mutex_init(&iadc->iadc_vadc_lock);
INIT_WORK(&iadc->trigger_completion_work, qpnp_iadc_trigger_completion);
INIT_DELAYED_WORK(&iadc->iadc_work, qpnp_iadc_work);
rc = qpnp_iadc_comp_info(iadc);
@@ -1347,7 +1372,6 @@
int i = 0;
cancel_delayed_work(&iadc->iadc_work);
- mutex_destroy(&iadc->iadc_vadc_lock);
for_each_child_of_node(node, child) {
device_remove_file(&spmi->dev,
&iadc->sens_attr[i].dev_attr);
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index b2b846a..fb882b3 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -129,6 +129,7 @@
[SCALE_THERM_150K_PULLUP] = {qpnp_adc_scale_therm_pu1},
[SCALE_QRD_BATT_THERM] = {qpnp_adc_scale_qrd_batt_therm},
[SCALE_QRD_SKUAA_BATT_THERM] = {qpnp_adc_scale_qrd_skuaa_batt_therm},
+ [SCALE_QRD_SKUG_BATT_THERM] = {qpnp_adc_scale_qrd_skug_batt_therm},
};
static int32_t qpnp_vadc_read_reg(struct qpnp_vadc_chip *vadc, int16_t reg,
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 74a252f..57aa835 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -192,6 +192,10 @@
struct qup_i2c_clk_path_vote clk_path_vote;
};
+#ifdef CONFIG_PM
+static int i2c_qup_pm_resume_runtime(struct device *device);
+#endif
+
#ifdef DEBUG
static void
qup_print_status(struct qup_i2c_dev *dev)
@@ -944,7 +948,13 @@
long timeout;
int err;
- pm_runtime_get_sync(dev->dev);
+ /* Alternate if runtime power management is disabled */
+ if (!pm_runtime_enabled(dev->dev)) {
+ dev_dbg(dev->dev, "Runtime PM is disabled\n");
+ i2c_qup_pm_resume_runtime(dev->dev);
+ } else {
+ pm_runtime_get_sync(dev->dev);
+ }
mutex_lock(&dev->mlock);
if (dev->suspended) {
@@ -1754,22 +1764,24 @@
if (!pm_runtime_enabled(device) || !pm_runtime_suspended(device)) {
dev_dbg(device, "system suspend");
i2c_qup_pm_suspend_runtime(device);
+ /*
+ * set the device's runtime PM status to 'suspended'
+ */
+ pm_runtime_disable(device);
+ pm_runtime_set_suspended(device);
+ pm_runtime_enable(device);
}
return 0;
}
static int qup_i2c_resume(struct device *device)
{
- int ret = 0;
- if (!pm_runtime_enabled(device) || !pm_runtime_suspended(device)) {
- dev_dbg(device, "system resume");
- ret = i2c_qup_pm_resume_runtime(device);
- if (!ret) {
- pm_runtime_mark_last_busy(device);
- pm_request_autosuspend(device);
- }
- return ret;
- }
+ /*
+ * Rely on runtime-PM to call resume in case it is enabled
+ * Even if it's not enabled, rely on 1st client transaction to do
+ * clock ON and gpio configuration
+ */
+ dev_dbg(device, "system resume");
return 0;
}
#endif /* CONFIG_PM */
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 8921c61..b773e1b 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -1574,9 +1574,11 @@
* Keys that have been pressed at suspend time are unlikely
* to be still pressed when we resume.
*/
- spin_lock_irq(&dev->event_lock);
- input_dev_release_keys(dev);
- spin_unlock_irq(&dev->event_lock);
+ if (!test_bit(INPUT_PROP_NO_DUMMY_RELEASE, dev->propbit)) {
+ spin_lock_irq(&dev->event_lock);
+ input_dev_release_keys(dev);
+ spin_unlock_irq(&dev->event_lock);
+ }
}
mutex_unlock(&dev->mutex);
diff --git a/drivers/input/misc/bmp18x-core.c b/drivers/input/misc/bmp18x-core.c
index 4b5b710..ae98469 100644
--- a/drivers/input/misc/bmp18x-core.c
+++ b/drivers/input/misc/bmp18x-core.c
@@ -50,6 +50,7 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/input.h>
+#include <linux/sensors.h>
#include <linux/workqueue.h>
#include <linux/module.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
@@ -87,6 +88,7 @@
struct device *dev;
struct mutex lock;
struct bmp18x_calibration_data calibration;
+ struct sensors_classdev cdev;
u8 oversampling_setting;
u8 sw_oversampling_setting;
u32 raw_temperature;
@@ -103,6 +105,24 @@
u32 enable;
};
+static struct sensors_classdev sensors_cdev = {
+ .name = "bmp18x-pressure",
+ .vendor = "Bosch",
+ .version = 1,
+ .handle = SENSORS_PRESSURE_HANDLE,
+ .type = SENSOR_TYPE_PRESSURE,
+ .max_range = "1100.0",
+ .resolution = "0.01",
+ .sensor_power = "0.67",
+ .min_delay = 20000, /* microsecond */
+ .fifo_reserved_event_count = 0,
+ .fifo_max_event_count = 0,
+ .enabled = 0,
+ .delay_msec = 200, /* millisecond */
+ .sensors_enable = NULL,
+ .sensors_poll_delay = NULL,
+};
+
#ifdef CONFIG_HAS_EARLYSUSPEND
static void bmp18x_early_suspend(struct early_suspend *h);
static void bmp18x_late_resume(struct early_suspend *h);
@@ -388,6 +408,19 @@
static DEVICE_ATTR(sw_oversampling, S_IWUSR | S_IRUGO,
show_sw_oversampling, set_sw_oversampling);
+static ssize_t bmp18x_poll_delay_set(struct sensors_classdev *sensors_cdev,
+ unsigned int delay_msec)
+{
+ struct bmp18x_data *data = container_of(sensors_cdev,
+ struct bmp18x_data, cdev);
+ mutex_lock(&data->lock);
+ data->delay = delay_msec;
+ mutex_unlock(&data->lock);
+
+ return 0;
+}
+
+
static ssize_t show_delay(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -401,17 +434,43 @@
{
struct bmp18x_data *data = dev_get_drvdata(dev);
unsigned long delay;
- int success = kstrtoul(buf, 10, &delay);
- if (success == 0) {
- mutex_lock(&data->lock);
- data->delay = delay;
- mutex_unlock(&data->lock);
- }
- return success;
+ int err = kstrtoul(buf, 10, &delay);
+ if (err < 0)
+ return err;
+
+ err = bmp18x_poll_delay_set(&data->cdev, delay);
+ if (err < 0)
+ return err;
+
+ return count;
}
-static DEVICE_ATTR(delay, S_IWUSR | S_IRUGO,
+
+static DEVICE_ATTR(poll_delay, S_IWUSR | S_IRUGO,
show_delay, set_delay);
+static ssize_t bmp18x_enable_set(struct sensors_classdev *sensors_cdev,
+ unsigned int enabled)
+{
+ struct bmp18x_data *data = container_of(sensors_cdev,
+ struct bmp18x_data, cdev);
+ struct device *dev = data->dev;
+
+ mutex_lock(&data->lock);
+ data->enable = enabled ? 1 : 0;
+
+ if (data->enable) {
+ bmp18x_enable(dev);
+ schedule_delayed_work(&data->work,
+ msecs_to_jiffies(data->delay));
+ } else {
+ cancel_delayed_work_sync(&data->work);
+ bmp18x_disable(dev);
+ }
+ mutex_unlock(&data->lock);
+
+ return 0;
+}
+
static ssize_t show_enable(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -425,24 +484,17 @@
{
struct bmp18x_data *data = dev_get_drvdata(dev);
unsigned long enable;
- int success = kstrtoul(buf, 10, &enable);
- if (success == 0) {
- mutex_lock(&data->lock);
- data->enable = enable ? 1 : 0;
+ int err = kstrtoul(buf, 10, &enable);
+ if (err < 0)
+ return err;
- if (data->enable) {
- bmp18x_enable(dev);
- schedule_delayed_work(&data->work,
- msecs_to_jiffies(data->delay));
- } else {
- cancel_delayed_work_sync(&data->work);
- bmp18x_disable(dev);
- }
- mutex_unlock(&data->lock);
+ err = bmp18x_enable_set(&data->cdev, enable);
+ if (err < 0)
+ return err;
- }
return count;
}
+
static DEVICE_ATTR(enable, S_IWUSR | S_IRUGO,
show_enable, set_enable);
@@ -484,7 +536,7 @@
&dev_attr_pressure0_input.attr,
&dev_attr_oversampling.attr,
&dev_attr_sw_oversampling.attr,
- &dev_attr_delay.attr,
+ &dev_attr_poll_delay.attr,
&dev_attr_enable.attr,
NULL
};
@@ -612,6 +664,16 @@
err = sysfs_create_group(&data->input->dev.kobj, &bmp18x_attr_group);
if (err)
goto error_sysfs;
+
+ data->cdev = sensors_cdev;
+ data->cdev.sensors_enable = bmp18x_enable_set;
+ data->cdev.sensors_poll_delay = bmp18x_poll_delay_set;
+ err = sensors_classdev_register(&data->input->dev, &data->cdev);
+ if (err) {
+ pr_err("class device create failed: %d\n", err);
+ goto error_class_sysfs;
+ }
+
/* workqueue init */
INIT_DELAYED_WORK(&data->work, bmp18x_work_func);
data->delay = BMP_DELAY_DEFAULT;
@@ -627,6 +689,8 @@
dev_info(dev, "Succesfully initialized bmp18x!\n");
return 0;
+error_class_sysfs:
+ sysfs_remove_group(&data->input->dev.kobj, &bmp18x_attr_group);
error_sysfs:
bmp18x_input_delete(data);
exit_free:
diff --git a/drivers/input/misc/cm36283.c b/drivers/input/misc/cm36283.c
index 17127a8..a7b4735 100644
--- a/drivers/input/misc/cm36283.c
+++ b/drivers/input/misc/cm36283.c
@@ -3,7 +3,7 @@
* Copyright (C) 2012 Capella Microsystems Inc.
* Author: Frank Hsieh <pengyueh@gmail.com>
*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, 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
@@ -17,9 +17,9 @@
*/
#include <linux/delay.h>
-#include <linux/earlysuspend.h>
#include <linux/i2c.h>
#include <linux/input.h>
+#include <linux/sensors.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/platform_device.h>
@@ -63,6 +63,43 @@
#define CM36283_PS_MAX_POLL_DELAY 1000
#define CM36283_PS_DEFAULT_POLL_DELAY 100
+static struct sensors_classdev sensors_light_cdev = {
+ .name = "cm36283-light",
+ .vendor = "Capella",
+ .version = 1,
+ .handle = SENSORS_LIGHT_HANDLE,
+ .type = SENSOR_TYPE_LIGHT,
+ .max_range = "6553",
+ .resolution = "0.0125",
+ .sensor_power = "0.15",
+ .min_delay = 0,
+ .fifo_reserved_event_count = 0,
+ .fifo_max_event_count = 0,
+ .enabled = 0,
+ .delay_msec = CM36283_LS_DEFAULT_POLL_DELAY,
+ .sensors_enable = NULL,
+ .sensors_poll_delay = NULL,
+};
+
+static struct sensors_classdev sensors_proximity_cdev = {
+ .name = "cm36283-proximity",
+ .vendor = "Capella",
+ .version = 1,
+ .handle = SENSORS_PROXIMITY_HANDLE,
+ .type = SENSOR_TYPE_PROXIMITY,
+ .max_range = "5.0",
+ .resolution = "5.0",
+ .sensor_power = "0.18",
+ .min_delay = 0,
+ .fifo_reserved_event_count = 0,
+ .fifo_max_event_count = 0,
+ .enabled = 0,
+ .delay_msec = CM36283_PS_DEFAULT_POLL_DELAY,
+ .sensors_enable = NULL,
+ .sensors_poll_delay = NULL,
+};
+
+
static const int als_range[] = {
[CM36283_ALS_IT0] = 6554,
[CM36283_ALS_IT1] = 3277,
@@ -88,7 +125,6 @@
struct input_dev *ls_input_dev;
struct input_dev *ps_input_dev;
- struct early_suspend early_suspend;
struct i2c_client *i2c_client;
struct workqueue_struct *lp_wq;
@@ -131,6 +167,8 @@
struct regulator *vio;
struct delayed_work ldwork;
struct delayed_work pdwork;
+ struct sensors_classdev als_cdev;
+ struct sensors_classdev ps_cdev;
};
struct cm36283_info *lp_info;
int fLevel=-1;
@@ -612,12 +650,6 @@
.unlocked_ioctl = psensor_ioctl
};
-struct miscdevice psensor_misc = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = "proximity",
- .fops = &psensor_fops
-};
-
void lightsensor_set_kvalue(struct cm36283_info *lpi)
{
if (!lpi) {
@@ -674,17 +706,9 @@
{
int ret = -EIO;
unsigned int delay;
-
- mutex_lock(&als_enable_mutex);
- if (lpi->als_enable) {
- dev_err(&lpi->i2c_client->dev, "%s: already enabled\n",
- __func__);
- ret = 0;
- } else {
- ret = control_and_report(lpi, CONTROL_ALS, 1, 0);
- }
-
+ mutex_lock(&als_enable_mutex);
+ ret = control_and_report(lpi, CONTROL_ALS, 1, 0);
mutex_unlock(&als_enable_mutex);
delay = atomic_read(&lpi->ls_poll_delay);
@@ -773,13 +797,6 @@
.unlocked_ioctl = lightsensor_ioctl
};
-static struct miscdevice lightsensor_misc = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = "lightsensor",
- .fops = &lightsensor_fops
-};
-
-
static ssize_t ps_adc_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -799,6 +816,21 @@
return ret;
}
+static int ps_enable_set(struct sensors_classdev *sensors_cdev,
+ unsigned int enable)
+{
+ struct cm36283_info *lpi = container_of(sensors_cdev,
+ struct cm36283_info, ps_cdev);
+ int ret;
+
+ if (enable)
+ ret = psensor_enable(lpi);
+ else
+ ret = psensor_disable(lpi);
+
+ return ret;
+}
+
static ssize_t ps_enable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
@@ -824,7 +856,6 @@
return count;
}
-static DEVICE_ATTR(ps_adc, 0664, ps_adc_show, ps_enable_store);
static ssize_t ps_parameters_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -868,10 +899,6 @@
return count;
}
-static DEVICE_ATTR(ps_parameters, 0664,
- ps_parameters_show, ps_parameters_store);
-
-
static ssize_t ps_conf_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -897,7 +924,6 @@
return count;
}
-static DEVICE_ATTR(ps_conf, 0664, ps_conf_show, ps_conf_store);
static ssize_t ps_thd_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -926,7 +952,6 @@
return count;
}
-static DEVICE_ATTR(ps_thd, 0664, ps_thd_show, ps_thd_store);
static ssize_t ps_hw_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -949,7 +974,6 @@
return count;
}
-static DEVICE_ATTR(ps_hw, 0664, ps_hw_show, ps_hw_store);
static ssize_t ls_adc_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -963,7 +987,26 @@
return ret;
}
-static DEVICE_ATTR(ls_adc, 0664, ls_adc_show, NULL);
+static int ls_enable_set(struct sensors_classdev *sensors_cdev,
+ unsigned int enable)
+{
+ struct cm36283_info *lpi = container_of(sensors_cdev,
+ struct cm36283_info, als_cdev);
+ int ret;
+
+ if (enable)
+ ret = lightsensor_enable(lpi);
+ else
+ ret = lightsensor_disable(lpi);
+
+ if (ret < 0) {
+ dev_err(&lpi->i2c_client->dev, "%s: set auto light sensor fail\n",
+ __func__);
+ return -EIO;
+ }
+
+ return 0;
+}
static ssize_t ls_enable_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -1006,15 +1049,15 @@
lpi->ls_calibrate);
dev_dbg(&lpi->i2c_client->dev, "ls_auto:0x%x\n", ls_auto);
- if (ret < 0)
+ if (ret < 0) {
dev_err(&lpi->i2c_client->dev, "%s: set auto light sensor fail\n",
__func__);
+ return ret;
+ }
return count;
}
-static DEVICE_ATTR(ls_auto, 0664,
- ls_enable_show, ls_enable_store);
static ssize_t ls_kadc_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -1057,7 +1100,6 @@
return count;
}
-static DEVICE_ATTR(ls_kadc, 0664, ls_kadc_show, ls_kadc_store);
static ssize_t ls_gadc_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -1097,7 +1139,6 @@
return count;
}
-static DEVICE_ATTR(ls_gadc, 0664, ls_gadc_show, ls_gadc_store);
static ssize_t ls_adc_table_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -1148,9 +1189,6 @@
return count;
}
-static DEVICE_ATTR(ls_adc_table, 0664,
- ls_adc_table_show, ls_adc_table_store);
-
static ssize_t ls_conf_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -1172,7 +1210,6 @@
_cm36283_I2C_Write_Word(lpi->slave_addr, ALS_CONF, lpi->ls_cmd);
return count;
}
-static DEVICE_ATTR(ls_conf, 0664, ls_conf_show, ls_conf_store);
static ssize_t ls_poll_delay_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -1199,8 +1236,20 @@
return count;
}
-static DEVICE_ATTR(ls_poll_delay, 0664, ls_poll_delay_show,
- ls_poll_delay_store);
+static int ls_poll_delay_set(struct sensors_classdev *sensors_cdev,
+ unsigned int delay_msec)
+{
+ struct cm36283_info *lpi = container_of(sensors_cdev,
+ struct cm36283_info, als_cdev);
+
+ if ((delay_msec < CM36283_LS_MIN_POLL_DELAY) ||
+ (delay_msec > CM36283_LS_MAX_POLL_DELAY))
+ return -EINVAL;
+
+ atomic_set(&lpi->ls_poll_delay, delay_msec);
+
+ return 0;
+}
static ssize_t ps_poll_delay_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -1227,8 +1276,19 @@
return count;
}
-static DEVICE_ATTR(ps_poll_delay, 0664, ps_poll_delay_show,
- ps_poll_delay_store);
+static int ps_poll_delay_set(struct sensors_classdev *sensors_cdev,
+ unsigned int delay_msec)
+{
+ struct cm36283_info *lpi = container_of(sensors_cdev,
+ struct cm36283_info, als_cdev);
+
+ if ((delay_msec < CM36283_PS_MIN_POLL_DELAY) ||
+ (delay_msec > CM36283_PS_MAX_POLL_DELAY))
+ return -EINVAL;
+
+ atomic_set(&lpi->ps_poll_delay, delay_msec);
+ return 0;
+}
static ssize_t ls_fLevel_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -1251,7 +1311,6 @@
fLevel=-1;
return count;
}
-static DEVICE_ATTR(ls_flevel, 0664, ls_fLevel_show, ls_fLevel_store);
static int lightsensor_setup(struct cm36283_info *lpi)
{
@@ -1266,6 +1325,7 @@
return -ENOMEM;
}
lpi->ls_input_dev->name = "cm36283-ls";
+ lpi->ls_input_dev->id.bustype = BUS_I2C;
set_bit(EV_ABS, lpi->ls_input_dev->evbit);
range = get_als_range();
@@ -1278,17 +1338,8 @@
goto err_free_ls_input_device;
}
- ret = misc_register(&lightsensor_misc);
- if (ret < 0) {
- pr_err("[LS][CM36283 error]%s: can not register ls misc device\n",
- __func__);
- goto err_unregister_ls_input_device;
- }
-
return ret;
-err_unregister_ls_input_device:
- input_unregister_device(lpi->ls_input_dev);
err_free_ls_input_device:
input_free_device(lpi->ls_input_dev);
return ret;
@@ -1306,6 +1357,7 @@
return -ENOMEM;
}
lpi->ps_input_dev->name = "cm36283-ps";
+ lpi->ps_input_dev->id.bustype = BUS_I2C;
set_bit(EV_ABS, lpi->ps_input_dev->evbit);
input_set_abs_params(lpi->ps_input_dev, ABS_DISTANCE, 0, 1, 0, 0);
@@ -1317,18 +1369,8 @@
goto err_free_ps_input_device;
}
- ret = misc_register(&psensor_misc);
- if (ret < 0) {
- pr_err(
- "[PS][CM36283 error]%s: could not register ps misc device\n",
- __func__);
- goto err_unregister_ps_input_device;
- }
-
return ret;
-err_unregister_ps_input_device:
- input_unregister_device(lpi->ps_input_dev);
err_free_ps_input_device:
input_free_device(lpi->ps_input_dev);
return ret;
@@ -1404,29 +1446,6 @@
return ret;
}
-#ifdef CONFIG_HAS_EARLYSUSPEND
-static void cm36283_early_suspend(struct early_suspend *h)
-{
- struct cm36283_info *lpi = lp_info;
-
- D("[LS][CM36283] %s\n", __func__);
-
- if (lpi->als_enable)
- lightsensor_disable(lpi);
-
-}
-
-static void cm36283_late_resume(struct early_suspend *h)
-{
- struct cm36283_info *lpi = lp_info;
-
- D("[LS][CM36283] %s\n", __func__);
-
- if (!lpi->als_enable)
- lightsensor_enable(lpi);
-}
-#endif
-
static int cm36283_parse_dt(struct device *dev,
struct cm36283_platform_data *pdata)
{
@@ -1499,6 +1518,59 @@
return 0;
}
+static int create_sysfs_interfaces(struct device *dev,
+ struct device_attribute *attributes, int len)
+{
+ int i;
+ int err;
+ for (i = 0; i < len; i++) {
+ err = device_create_file(dev, attributes + i);
+ if (err)
+ goto error;
+ }
+ return 0;
+
+error:
+ for (; i >= 0; i--)
+ device_remove_file(dev, attributes + i);
+ dev_err(dev, "%s:Unable to create interface\n", __func__);
+ return err;
+}
+
+static int remove_sysfs_interfaces(struct device *dev,
+ struct device_attribute *attributes, int len)
+{
+ int i;
+ for (i = 0; i < len; i++)
+ device_remove_file(dev, attributes + i);
+ return 0;
+}
+
+static struct device_attribute light_attr[] = {
+ __ATTR(ls_adc, 0664, ls_adc_show, NULL),
+ __ATTR(ls_kadc, 0664, ls_kadc_show, ls_kadc_store),
+ __ATTR(ls_gadc, 0664, ls_gadc_show, ls_gadc_store),
+ __ATTR(ls_conf, 0664, ls_conf_show, ls_conf_store),
+ __ATTR(ls_adc_table, 0664,
+ ls_adc_table_show, ls_adc_table_store),
+ __ATTR(poll_delay, 0664, ls_poll_delay_show,
+ ls_poll_delay_store),
+ __ATTR(enable, 0664,
+ ls_enable_show, ls_enable_store),
+};
+
+static struct device_attribute proximity_attr[] = {
+ __ATTR(enable, 0664, ps_adc_show, ps_enable_store),
+ __ATTR(ps_parameters, 0664,
+ ps_parameters_show, ps_parameters_store),
+ __ATTR(ps_conf, 0664, ps_conf_show, ps_conf_store),
+ __ATTR(ps_hw, 0664, ps_hw_show, ps_hw_store),
+ __ATTR(ps_thd, 0664, ps_thd_show, ps_thd_store),
+ __ATTR(poll_delay, 0664, ps_poll_delay_show,
+ ps_poll_delay_store),
+ __ATTR(ls_flevel, 0664, ls_fLevel_show, ls_fLevel_store),
+};
+
static int cm36283_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -1565,7 +1637,7 @@
__func__, lpi->ls_cmd);
if (pdata->ls_cmd == 0) {
- lpi->ls_cmd = CM36283_ALS_IT_160ms | CM36283_ALS_GAIN_2;
+ lpi->ls_cmd = CM36283_ALS_IT_80ms | CM36283_ALS_GAIN_2;
}
lp_info = lpi;
@@ -1582,17 +1654,17 @@
mutex_init(&ps_get_adc_mutex);
- //SET LUX STEP FACTOR HERE
- // if adc raw value one step = 5/100 = 1/20 = 0.05 lux
- // the following will set the factor 0.05 = 1/20
- // and lpi->golden_adc = 1;
- // set als_kadc = (ALS_CALIBRATED <<16) | 20;
+ /*
+ * SET LUX STEP FACTOR HERE
+ * if adc raw value one step = 5/100 = 1/20 = 0.05 lux
+ * the following will set the factor 0.05 = 1/20
+ * and lpi->golden_adc = 1;
+ * set als_kadc = (ALS_CALIBRATED << 16) | 20;
+ */
- als_kadc = (ALS_CALIBRATED <<16) | 20;
- lpi->golden_adc = 1;
-
- //ls calibrate always set to 1
- lpi->ls_calibrate = 1;
+ als_kadc = (ALS_CALIBRATED << 16) | 10;
+ lpi->golden_adc = 100;
+ lpi->ls_calibrate = 0;
lightsensor_set_kvalue(lpi);
ret = lightsensor_update_table(lpi);
@@ -1636,99 +1708,37 @@
goto err_psensor_setup;
}
- lpi->cm36283_class = class_create(THIS_MODULE, "optical_sensors");
- if (IS_ERR(lpi->cm36283_class)) {
- ret = PTR_ERR(lpi->cm36283_class);
- lpi->cm36283_class = NULL;
- goto err_create_class;
+ ret = create_sysfs_interfaces(&lpi->ls_input_dev->dev, light_attr,
+ ARRAY_SIZE(light_attr));
+ if (ret < 0) {
+ dev_err(&client->dev, "failed to create sysfs\n");
+ goto err_input_cleanup;
}
- lpi->ls_dev = device_create(lpi->cm36283_class,
- NULL, 0, "%s", "lightsensor");
- if (unlikely(IS_ERR(lpi->ls_dev))) {
- ret = PTR_ERR(lpi->ls_dev);
- lpi->ls_dev = NULL;
- goto err_create_ls_device;
+ ret = create_sysfs_interfaces(&lpi->ps_input_dev->dev, proximity_attr,
+ ARRAY_SIZE(proximity_attr));
+ if (ret < 0) {
+ dev_err(&client->dev, "failed to create sysfs\n");
+ goto err_light_sysfs_cleanup;
}
- /* register the attributes */
- ret = device_create_file(lpi->ls_dev, &dev_attr_ls_adc);
+ lpi->als_cdev = sensors_light_cdev;
+ lpi->als_cdev.sensors_enable = ls_enable_set;
+ lpi->als_cdev.sensors_poll_delay = ls_poll_delay_set;
+ lpi->als_cdev.min_delay = CM36283_LS_MIN_POLL_DELAY * 1000;
+
+ lpi->ps_cdev = sensors_proximity_cdev;
+ lpi->ps_cdev.sensors_enable = ps_enable_set;
+ lpi->ps_cdev.sensors_poll_delay = ps_poll_delay_set;
+ lpi->ps_cdev.min_delay = CM36283_PS_MIN_POLL_DELAY * 1000;
+
+ ret = sensors_classdev_register(&client->dev, &lpi->als_cdev);
if (ret)
- goto err_create_ls_device_file;
+ goto err_proximity_sysfs_cleanup;
- /* register the attributes */
- ret = device_create_file(lpi->ls_dev, &dev_attr_ls_auto);
+ ret = sensors_classdev_register(&client->dev, &lpi->ps_cdev);
if (ret)
- goto err_create_ls_device_file;
-
- /* register the attributes */
- ret = device_create_file(lpi->ls_dev, &dev_attr_ls_kadc);
- if (ret)
- goto err_create_ls_device_file;
-
- ret = device_create_file(lpi->ls_dev, &dev_attr_ls_gadc);
- if (ret)
- goto err_create_ls_device_file;
-
- ret = device_create_file(lpi->ls_dev, &dev_attr_ls_adc_table);
- if (ret)
- goto err_create_ls_device_file;
-
- ret = device_create_file(lpi->ls_dev, &dev_attr_ls_conf);
- if (ret)
- goto err_create_ls_device_file;
-
- ret = device_create_file(lpi->ls_dev, &dev_attr_ls_flevel);
- if (ret)
- goto err_create_ls_device_file;
-
- ret = device_create_file(lpi->ls_dev, &dev_attr_ls_poll_delay);
- if (ret)
- goto err_create_ls_device_file;
-
- lpi->ps_dev = device_create(lpi->cm36283_class,
- NULL, 0, "%s", "proximity");
- if (unlikely(IS_ERR(lpi->ps_dev))) {
- ret = PTR_ERR(lpi->ps_dev);
- lpi->ps_dev = NULL;
- goto err_create_ps_device;
- }
-
- /* register the attributes */
- ret = device_create_file(lpi->ps_dev, &dev_attr_ps_adc);
- if (ret)
- goto err_create_ps_device_file;
-
- ret = device_create_file(lpi->ps_dev,
- &dev_attr_ps_parameters);
- if (ret)
- goto err_create_ps_device_file;
-
- /* register the attributes */
- ret = device_create_file(lpi->ps_dev, &dev_attr_ps_conf);
- if (ret)
- goto err_create_ps_device_file;
-
- /* register the attributes */
- ret = device_create_file(lpi->ps_dev, &dev_attr_ps_thd);
- if (ret)
- goto err_create_ps_device_file;
-
- ret = device_create_file(lpi->ps_dev, &dev_attr_ps_hw);
- if (ret)
- goto err_create_ps_device_file;
-
- ret = device_create_file(lpi->ps_dev, &dev_attr_ps_poll_delay);
- if (ret)
- goto err_create_ps_device_file;
-
-#ifdef CONFIG_HAS_EARLYSUSPEND
- lpi->early_suspend.level =
- EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
- lpi->early_suspend.suspend = cm36283_early_suspend;
- lpi->early_suspend.resume = cm36283_late_resume;
- register_early_suspend(&lpi->early_suspend);
-#endif
+ goto err_create_class_sysfs;
mutex_init(&wq_lock);
INIT_DELAYED_WORK(&lpi->ldwork, lsensor_delay_work_handler);
@@ -1736,20 +1746,18 @@
dev_dbg(&lpi->i2c_client->dev, "%s: Probe success!\n", __func__);
return ret;
-
-err_create_ps_device_file:
- device_unregister(lpi->ps_dev);
-err_create_ps_device:
-err_create_ls_device_file:
- device_unregister(lpi->ls_dev);
-err_create_ls_device:
- class_destroy(lpi->cm36283_class);
-err_create_class:
- misc_deregister(&psensor_misc);
+err_create_class_sysfs:
+ sensors_classdev_unregister(&lpi->als_cdev);
+err_proximity_sysfs_cleanup:
+ remove_sysfs_interfaces(&lpi->ps_input_dev->dev, proximity_attr,
+ ARRAY_SIZE(proximity_attr));
+err_light_sysfs_cleanup:
+ remove_sysfs_interfaces(&lpi->ls_input_dev->dev, light_attr,
+ ARRAY_SIZE(light_attr));
+err_input_cleanup:
input_unregister_device(lpi->ps_input_dev);
input_free_device(lpi->ps_input_dev);
err_psensor_setup:
- misc_deregister(&lightsensor_misc);
input_unregister_device(lpi->ls_input_dev);
input_free_device(lpi->ls_input_dev);
err_lightsensor_setup:
@@ -2009,27 +2017,40 @@
struct cm36283_info *lpi = lp_info;
if (lpi->als_enable) {
- lightsensor_disable(lpi);
+ if (lightsensor_disable(lpi))
+ goto out;
lpi->als_enable = 1;
}
- cm36283_power_set(lpi, 0);
+ if (cm36283_power_set(lpi, 0))
+ goto out;
return 0;
+
+out:
+ dev_err(&lpi->i2c_client->dev, "%s:failed during resume operation.\n",
+ __func__);
+ return -EIO;
}
static int cm36283_resume(struct device *dev)
{
struct cm36283_info *lpi = lp_info;
- cm36283_power_set(lpi, 1);
+ if (cm36283_power_set(lpi, 1))
+ goto out;
if (lpi->als_enable) {
- cm36283_setup(lpi);
- lightsensor_setup(lpi);
- psensor_setup(lpi);
- lightsensor_enable(lpi);
+ ls_initial_cmd(lpi);
+ psensor_initial_cmd(lpi);
+ if (lightsensor_enable(lpi))
+ goto out;
}
return 0;
+
+out:
+ dev_err(&lpi->i2c_client->dev, "%s:failed during resume operation.\n",
+ __func__);
+ return -EIO;
}
#endif
diff --git a/drivers/input/misc/kxtj9.c b/drivers/input/misc/kxtj9.c
index f879d78..0883ac5 100644
--- a/drivers/input/misc/kxtj9.c
+++ b/drivers/input/misc/kxtj9.c
@@ -20,6 +20,7 @@
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/input.h>
+#include <linux/sensors.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -79,6 +80,25 @@
* The following table lists the maximum appropriate poll interval for each
* available output data rate.
*/
+
+static struct sensors_classdev sensors_cdev = {
+ .name = "kxtj9-accel",
+ .vendor = "Kionix",
+ .version = 1,
+ .handle = 0,
+ .type = 1,
+ .max_range = "19.6",
+ .resolution = "0.01",
+ .sensor_power = "0.2",
+ .min_delay = 2000, /* microsecond */
+ .fifo_reserved_event_count = 0,
+ .fifo_max_event_count = 0,
+ .enabled = 0,
+ .delay_msec = 200, /* millisecond */
+ .sensors_enable = NULL,
+ .sensors_poll_delay = NULL,
+};
+
static const struct {
unsigned int cutoff;
u8 mask;
@@ -108,6 +128,7 @@
bool power_enabled;
struct regulator *vdd;
struct regulator *vio;
+ struct sensors_classdev cdev;
};
static int kxtj9_i2c_read(struct kxtj9_data *tj9, u8 addr, u8 *data, int len)
@@ -415,19 +436,16 @@
}
}
- tj9->enable = true;
return 0;
fail:
kxtj9_device_power_off(tj9);
- tj9->enable = false;
return err;
}
static void kxtj9_disable(struct kxtj9_data *tj9)
{
kxtj9_device_power_off(tj9);
- tj9->enable = false;
}
@@ -473,6 +491,36 @@
return 0;
}
+static int kxtj9_enable_set(struct sensors_classdev *sensors_cdev,
+ unsigned int enabled)
+{
+ struct kxtj9_data *tj9 = container_of(sensors_cdev,
+ struct kxtj9_data, cdev);
+ struct input_dev *input_dev = tj9->input_dev;
+
+ mutex_lock(&input_dev->mutex);
+
+ if (enabled == 0) {
+ disable_irq(tj9->client->irq);
+ kxtj9_disable(tj9);
+ tj9->enable = false;
+ } else if (enabled == 1) {
+ if (!kxtj9_enable(tj9)) {
+ enable_irq(tj9->client->irq);
+ tj9->enable = true;
+ }
+ } else {
+ dev_err(&tj9->client->dev,
+ "Invalid value of input, input=%d\n", enabled);
+ mutex_unlock(&input_dev->mutex);
+ return -EINVAL;
+ }
+
+ mutex_unlock(&input_dev->mutex);
+
+ return 0;
+}
+
static ssize_t kxtj9_enable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -488,28 +536,16 @@
{
struct i2c_client *client = to_i2c_client(dev);
struct kxtj9_data *tj9 = i2c_get_clientdata(client);
- struct input_dev *input_dev = tj9->input_dev;
unsigned long data;
int error;
error = kstrtoul(buf, 10, &data);
- if (error)
+ if (error < 0)
return error;
- mutex_lock(&input_dev->mutex);
- disable_irq(client->irq);
- if (data == 0)
- kxtj9_disable(tj9);
- else if (data == 1)
- kxtj9_enable(tj9);
- else {
- dev_err(&tj9->client->dev,
- "Invalid value of input, input=%ld\n", data);
- }
-
- enable_irq(client->irq);
- mutex_unlock(&input_dev->mutex);
-
+ error = kxtj9_enable_set(&tj9->cdev, data);
+ if (error < 0)
+ return error;
return count;
}
@@ -526,6 +562,29 @@
* will be responsible for retrieving data from the input node at the desired
* interval.
*/
+static int kxtj9_poll_delay_set(struct sensors_classdev *sensors_cdev,
+ unsigned int delay_msec)
+{
+ struct kxtj9_data *tj9 = container_of(sensors_cdev,
+ struct kxtj9_data, cdev);
+ struct input_dev *input_dev = tj9->input_dev;
+
+ /* Lock the device to prevent races with open/close (and itself) */
+ mutex_lock(&input_dev->mutex);
+
+ if (tj9->enable)
+ disable_irq(tj9->client->irq);
+
+ tj9->last_poll_interval = max(delay_msec, tj9->pdata.min_interval);
+
+ if (tj9->enable) {
+ kxtj9_update_odr(tj9, tj9->last_poll_interval);
+ enable_irq(tj9->client->irq);
+ }
+ mutex_unlock(&input_dev->mutex);
+
+ return 0;
+}
/* Returns currently selected poll interval (in ms) */
static ssize_t kxtj9_get_poll_delay(struct device *dev,
@@ -544,7 +603,6 @@
{
struct i2c_client *client = to_i2c_client(dev);
struct kxtj9_data *tj9 = i2c_get_clientdata(client);
- struct input_dev *input_dev = tj9->input_dev;
unsigned int interval;
int error;
@@ -552,22 +610,9 @@
if (error < 0)
return error;
- /* Lock the device to prevent races with open/close (and itself) */
- mutex_lock(&input_dev->mutex);
-
- disable_irq(client->irq);
-
- /*
- * Set current interval to the greater of the minimum interval or
- * the requested interval
- */
- tj9->last_poll_interval = max(interval, tj9->pdata.min_interval);
-
- kxtj9_update_odr(tj9, tj9->last_poll_interval);
-
- enable_irq(client->irq);
- mutex_unlock(&input_dev->mutex);
-
+ error = kxtj9_poll_delay_set(&tj9->cdev, interval);
+ if (error < 0)
+ return error;
return count;
}
@@ -584,7 +629,6 @@
.attrs = kxtj9_attributes
};
-
#ifdef CONFIG_INPUT_KXTJ9_POLLED_MODE
static void kxtj9_poll(struct input_polled_dev *dev)
{
@@ -840,6 +884,18 @@
tj9->ctrl_reg1 = tj9->pdata.res_ctl | tj9->pdata.g_range;
tj9->last_poll_interval = tj9->pdata.init_interval;
+ tj9->cdev = sensors_cdev;
+ /* The min_delay is used by userspace and the unit is microsecond. */
+ tj9->cdev.min_delay = tj9->pdata.min_interval * 1000;
+ tj9->cdev.delay_msec = tj9->pdata.init_interval;
+ tj9->cdev.sensors_enable = kxtj9_enable_set;
+ tj9->cdev.sensors_poll_delay = kxtj9_poll_delay_set;
+ err = sensors_classdev_register(&client->dev, &tj9->cdev);
+ if (err) {
+ dev_err(&client->dev, "class device create failed: %d\n", err);
+ goto err_power_off;
+ }
+
if (client->irq) {
/* If in irq mode, populate INT_CTRL_REG1 and enable DRDY. */
tj9->int_ctrl |= KXTJ9_IEN | KXTJ9_IEA | KXTJ9_IEL;
@@ -847,7 +903,7 @@
err = kxtj9_setup_input_device(tj9);
if (err)
- goto err_power_off;
+ goto err_class_sysfs;
err = request_threaded_irq(client->irq, NULL, kxtj9_isr,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
@@ -857,6 +913,8 @@
goto err_destroy_input;
}
+ disable_irq(tj9->client->irq);
+
err = sysfs_create_group(&client->dev.kobj, &kxtj9_attribute_group);
if (err) {
dev_err(&client->dev, "sysfs create failed: %d\n", err);
@@ -866,7 +924,7 @@
} else {
err = kxtj9_setup_polled_device(tj9);
if (err)
- goto err_power_off;
+ goto err_class_sysfs;
}
dev_dbg(&client->dev, "%s: kxtj9_probe OK.\n", __func__);
@@ -877,6 +935,8 @@
free_irq(client->irq, tj9);
err_destroy_input:
input_unregister_device(tj9->input_dev);
+err_class_sysfs:
+ sensors_classdev_unregister(&tj9->cdev);
err_power_off:
kxtj9_device_power_off(tj9);
err_power_deinit:
@@ -923,7 +983,7 @@
mutex_lock(&input_dev->mutex);
- if (input_dev->users)
+ if (input_dev->users && tj9->enable)
kxtj9_disable(tj9);
mutex_unlock(&input_dev->mutex);
@@ -939,7 +999,7 @@
mutex_lock(&input_dev->mutex);
- if (input_dev->users)
+ if (input_dev->users && tj9->enable)
kxtj9_enable(tj9);
mutex_unlock(&input_dev->mutex);
diff --git a/drivers/input/misc/mma8x5x.c b/drivers/input/misc/mma8x5x.c
index a325d54..0fc5693 100644
--- a/drivers/input/misc/mma8x5x.c
+++ b/drivers/input/misc/mma8x5x.c
@@ -2,7 +2,7 @@
* mma8x5x.c - Linux kernel modules for 3-Axis Orientation/Motion
* Detection Sensor MMA8451/MMA8452/MMA8453
*
- * Copyright (c) 2013, The Linux Foundation. All Rights Reserved.
+ * Copyright (c) 2013-2014, The Linux Foundation. All Rights Reserved.
* Linux Foundation chooses to take subject only to the GPLv2 license
* terms, and distributes only under these terms.
* Copyright (C) 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved.
@@ -27,6 +27,7 @@
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/input-polldev.h>
+#include <linux/sensors.h>
#include <linux/regulator/consumer.h>
#include <linux/of_gpio.h>
@@ -37,10 +38,10 @@
#define MMA8652_ID 0x4A
#define MMA8653_ID 0x5A
-
+/* Polling delay in msecs */
#define POLL_INTERVAL_MIN 1
-#define POLL_INTERVAL_MAX 500
-#define POLL_INTERVAL 100 /* msecs */
+#define POLL_INTERVAL_MAX 10000
+#define POLL_INTERVAL 100
/* if sensor is standby ,set POLL_STOP_TIME to slow down the poll */
#define POLL_STOP_TIME 10000
@@ -53,6 +54,25 @@
#define MMA8X5X_BUF_SIZE 7
#define MMA_SHUTTEDDOWN (1 << 31)
+#define MMA_STATE_MASK (~MMA_SHUTTEDDOWN)
+
+static struct sensors_classdev sensors_cdev = {
+ .name = "mma8x5x-accel",
+ .vendor = "Freescale",
+ .version = 1,
+ .handle = SENSORS_ACCELERATION_HANDLE,
+ .type = SENSOR_TYPE_ACCELEROMETER,
+ .max_range = "19.6",
+ .resolution = "0.01",
+ .sensor_power = "0.2",
+ .min_delay = 2000,
+ .fifo_reserved_event_count = 0,
+ .fifo_max_event_count = 0,
+ .enabled = 0,
+ .delay_msec = POLL_INTERVAL,
+ .sensors_enable = NULL,
+ .sensors_poll_delay = NULL,
+};
struct sensor_regulator {
struct regulator *vreg;
@@ -146,12 +166,14 @@
struct i2c_client *client;
struct input_polled_dev *poll_dev;
struct mutex data_lock;
+ struct sensors_classdev cdev;
int active;
int position;
u8 chip_id;
int mode;
int int_pin;
u32 int_flags;
+ int poll_delay;
};
/* Addresses scanned */
static const unsigned short normal_i2c[] = {0x1c, 0x1d, I2C_CLIENT_END};
@@ -349,13 +371,13 @@
struct input_polled_dev *poll_dev = pdata->poll_dev;
struct mma8x5x_data_axis data;
mutex_lock(&pdata->data_lock);
- if (pdata->active == MMA_STANDBY) {
+ if ((pdata->active & MMA_STATE_MASK) == MMA_STANDBY) {
poll_dev->poll_interval = POLL_STOP_TIME;
/* if standby ,set as 10s to slow the poll. */
goto out;
} else {
if (poll_dev->poll_interval == POLL_STOP_TIME)
- poll_dev->poll_interval = POLL_INTERVAL;
+ poll_dev->poll_interval = pdata->poll_delay;
}
if (mma8x5x_read_data(pdata->client, &data) != 0)
goto out;
@@ -374,6 +396,79 @@
mma8x5x_report_data(pdata);
}
+static int mma8x5x_enable_set(struct sensors_classdev *sensors_cdev,
+ unsigned int enable)
+{
+ struct mma8x5x_data *pdata = container_of(sensors_cdev,
+ struct mma8x5x_data, cdev);
+ struct i2c_client *client = pdata->client;
+ int ret;
+ u8 val = 0;
+
+ mutex_lock(&pdata->data_lock);
+ if (enable) {
+ if (pdata->active & MMA_SHUTTEDDOWN) {
+ ret = mma8x5x_config_regulator(client, 1);
+ if (ret)
+ goto err_failed;
+
+ ret = mma8x5x_device_start(client);
+ if (ret)
+ goto err_failed;
+
+ pdata->active &= ~MMA_SHUTTEDDOWN;
+ }
+ if (pdata->active == MMA_STANDBY) {
+ val = i2c_smbus_read_byte_data(client,
+ MMA8X5X_CTRL_REG1);
+ if (val < 0) {
+ dev_err(&client->dev, "read device state failed!");
+ ret = val;
+ goto err_failed;
+ }
+
+ ret = i2c_smbus_write_byte_data(client,
+ MMA8X5X_CTRL_REG1, val | 0x01);
+ if (ret) {
+ dev_err(&client->dev, "change device state failed!");
+ goto err_failed;
+ }
+ pdata->active = MMA_ACTIVED;
+ dev_dbg(&client->dev, "%s:mma enable setting active.\n",
+ __func__);
+ }
+ } else if (enable == 0) {
+ if (pdata->active == MMA_ACTIVED) {
+ val = i2c_smbus_read_byte_data(client,
+ MMA8X5X_CTRL_REG1);
+ if (val < 0) {
+ dev_err(&client->dev, "read device state failed!");
+ ret = val;
+ goto err_failed;
+ }
+
+ ret = i2c_smbus_write_byte_data(client,
+ MMA8X5X_CTRL_REG1, val & 0xFE);
+ if (ret) {
+ dev_err(&client->dev, "change device state failed!");
+ goto err_failed;
+ }
+
+ pdata->active = MMA_STANDBY;
+ dev_dbg(&client->dev, "%s:mma enable setting inactive.\n",
+ __func__);
+ }
+ if (!mma8x5x_config_regulator(client, 0))
+ pdata->active |= MMA_SHUTTEDDOWN;
+ }
+ mutex_unlock(&pdata->data_lock);
+ return 0;
+
+err_failed:
+ mutex_unlock(&pdata->data_lock);
+ return ret;
+}
+
static ssize_t mma8x5x_enable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -399,77 +494,17 @@
{
struct input_polled_dev *poll_dev = dev_get_drvdata(dev);
struct mma8x5x_data *pdata = (struct mma8x5x_data *)(poll_dev->private);
- struct i2c_client *client = pdata->client;
int ret;
unsigned long enable;
- u8 val = 0;
ret = kstrtoul(buf, 10, &enable);
if (ret)
return ret;
- mutex_lock(&pdata->data_lock);
enable = (enable > 0) ? 1 : 0;
- if (enable) {
- if (pdata->active & MMA_SHUTTEDDOWN) {
- ret = mma8x5x_config_regulator(client, 1);
- if (ret)
- goto err_failed;
-
- ret = mma8x5x_device_start(client);
- if (ret)
- goto err_failed;
-
- pdata->active &= ~MMA_SHUTTEDDOWN;
- }
- if (pdata->active == MMA_STANDBY) {
- val = i2c_smbus_read_byte_data(client,
- MMA8X5X_CTRL_REG1);
- if (val < 0) {
- dev_err(dev, "read device state failed!");
- ret = val;
- goto err_failed;
- }
-
- ret = i2c_smbus_write_byte_data(client,
- MMA8X5X_CTRL_REG1, val | 0x01);
- if (ret) {
- dev_err(dev, "change device state failed!");
- goto err_failed;
- }
- pdata->active = MMA_ACTIVED;
- dev_dbg(dev, "%s:mma enable setting active.\n",
- __func__);
- }
- } else if (enable == 0) {
- if (pdata->active == MMA_ACTIVED) {
- val = i2c_smbus_read_byte_data(client,
- MMA8X5X_CTRL_REG1);
- if (val < 0) {
- dev_err(dev, "read device state failed!");
- ret = val;
- goto err_failed;
- }
-
- ret = i2c_smbus_write_byte_data(client,
- MMA8X5X_CTRL_REG1, val & 0xFE);
- if (ret) {
- dev_err(dev, "change device state failed!");
- goto err_failed;
- }
-
- pdata->active = MMA_STANDBY;
- dev_dbg(dev, "%s:mma enable setting inactive.\n",
- __func__);
- }
- if (!mma8x5x_config_regulator(client, 0))
- pdata->active |= MMA_SHUTTEDDOWN;
- }
- mutex_unlock(&pdata->data_lock);
+ ret = mma8x5x_enable_set(&pdata->cdev, enable);
+ if (ret < 0)
+ return ret;
return count;
-
-err_failed:
- mutex_unlock(&pdata->data_lock);
- return ret;
}
static ssize_t mma8x5x_position_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -500,14 +535,60 @@
return count;
}
+static int mma8x5x_poll_delay_set(struct sensors_classdev *sensors_cdev,
+ unsigned int delay_ms)
+{
+ struct mma8x5x_data *pdata = container_of(sensors_cdev,
+ struct mma8x5x_data, cdev);
+
+ mutex_lock(&pdata->data_lock);
+ pdata->poll_delay = delay_ms;
+ pdata->poll_dev->poll_interval = pdata->poll_delay;
+ mutex_unlock(&pdata->data_lock);
+
+ return 0;
+}
+
+static ssize_t mma8x5x_poll_delay_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct input_polled_dev *poll_dev = dev_get_drvdata(dev);
+ struct mma8x5x_data *pdata = (struct mma8x5x_data *)(poll_dev->private);
+ return snprintf(buf, PAGE_SIZE, "%d\n", pdata->poll_delay);
+}
+
+static ssize_t mma8x5x_poll_delay_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct input_polled_dev *poll_dev = dev_get_drvdata(dev);
+ struct mma8x5x_data *pdata = (struct mma8x5x_data *)(poll_dev->private);
+ int interval;
+ int ret;
+ ret = kstrtoint(buf, 10, &interval);
+ if (ret)
+ return ret;
+ if (interval <= POLL_INTERVAL_MIN)
+ interval = POLL_INTERVAL_MIN;
+ if (interval > POLL_INTERVAL_MAX)
+ interval = POLL_INTERVAL_MAX;
+
+ mma8x5x_poll_delay_set(&pdata->cdev, interval);
+
+ return count;
+}
+
static DEVICE_ATTR(enable, S_IWUSR | S_IRUGO,
mma8x5x_enable_show, mma8x5x_enable_store);
static DEVICE_ATTR(position, S_IWUSR | S_IRUGO,
mma8x5x_position_show, mma8x5x_position_store);
+static DEVICE_ATTR(poll_delay, S_IWUSR | S_IRUGO,
+ mma8x5x_poll_delay_show, mma8x5x_poll_delay_store);
static struct attribute *mma8x5x_attributes[] = {
&dev_attr_enable.attr,
&dev_attr_position.attr,
+ &dev_attr_poll_delay.attr,
NULL
};
@@ -606,6 +687,7 @@
pdata->client = client;
pdata->chip_id = chip_id;
pdata->mode = MODE_2G;
+ pdata->poll_delay = POLL_INTERVAL;
mutex_init(&pdata->data_lock);
i2c_set_clientdata(client, pdata);
@@ -643,11 +725,24 @@
result = -EINVAL;
goto err_create_sysfs;
}
+ pdata->cdev = sensors_cdev;
+ pdata->cdev.min_delay = POLL_INTERVAL_MIN * 1000;
+ pdata->cdev.delay_msec = poll_dev->poll_interval;
+ pdata->cdev.sensors_enable = mma8x5x_enable_set;
+ pdata->cdev.sensors_poll_delay = mma8x5x_poll_delay_set;
+ result = sensors_classdev_register(&client->dev, &pdata->cdev);
+ if (result) {
+ dev_err(&client->dev, "create class device file failed!\n");
+ result = -EINVAL;
+ goto err_create_class_sysfs;
+ }
dev_info(&client->dev,
"%s:mma8x5x device driver probe successfully, position =%d\n",
__func__, pdata->position);
return 0;
+err_create_class_sysfs:
+ sysfs_remove_group(&idev->dev.kobj, &mma8x5x_attr_group);
err_create_sysfs:
input_unregister_polled_device(pdata->poll_dev);
err_register_polled_device:
diff --git a/drivers/input/misc/mpu3050.c b/drivers/input/misc/mpu3050.c
index 642975d..039e078 100644
--- a/drivers/input/misc/mpu3050.c
+++ b/drivers/input/misc/mpu3050.c
@@ -37,6 +37,7 @@
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/input.h>
+#include <linux/sensors.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
@@ -121,6 +122,7 @@
struct input_dev *idev;
struct mpu3050_gyro_platform_data *platform_data;
struct delayed_work input_work;
+ struct sensors_classdev cdev;
u32 use_poll;
u32 poll_interval;
u32 dlpf_index;
@@ -128,6 +130,24 @@
u32 enable;
};
+static struct sensors_classdev sensors_cdev = {
+ .name = "mpu3050-gyro",
+ .vendor = "Invensense",
+ .version = 1,
+ .handle = SENSORS_GYROSCOPE_HANDLE,
+ .type = SENSOR_TYPE_GYROSCOPE,
+ .max_range = "35.0",
+ .resolution = "0.06",
+ .sensor_power = "0.2",
+ .min_delay = 2000,
+ .fifo_reserved_event_count = 0,
+ .fifo_max_event_count = 0,
+ .enabled = 0,
+ .delay_msec = MPU3050_DEFAULT_POLL_INTERVAL,
+ .sensors_enable = NULL,
+ .sensors_poll_delay = NULL,
+};
+
struct sensor_regulator {
struct regulator *vreg;
const char *name;
@@ -243,6 +263,40 @@
return rc;
}
+static int mpu3050_poll_delay_set(struct sensors_classdev *sensors_cdev,
+ unsigned int delay_msec)
+{
+ struct mpu3050_sensor *sensor = container_of(sensors_cdev,
+ struct mpu3050_sensor, cdev);
+ unsigned int dlpf_index;
+ u8 divider, reg;
+ int ret;
+
+ dlpf_index = interval_to_dlpf_cfg(delay_msec);
+ divider = delay_msec * dlpf_table[dlpf_index].sample_rate - 1;
+
+ if (sensor->dlpf_index != dlpf_index) {
+ /* Set low pass filter and full scale */
+ reg = dlpf_table[dlpf_index].cfg;
+ reg |= MPU3050_DEFAULT_FS_RANGE << 3;
+ reg |= MPU3050_EXT_SYNC_NONE << 5;
+ ret = i2c_smbus_write_byte_data(sensor->client,
+ MPU3050_DLPF_FS_SYNC, reg);
+ if (!ret)
+ sensor->dlpf_index = dlpf_index;
+ }
+
+ if (sensor->poll_interval != delay_msec) {
+ /* Output frequency divider. The poll interval */
+ ret = i2c_smbus_write_byte_data(sensor->client,
+ MPU3050_SMPLRT_DIV, divider);
+ if (!ret)
+ sensor->poll_interval = delay_msec;
+ }
+
+ return 0;
+}
+
/**
* mpu3050_attr_get_polling_rate - get the sampling rate
*/
@@ -265,8 +319,6 @@
{
struct mpu3050_sensor *sensor = dev_get_drvdata(dev);
unsigned long interval_ms;
- unsigned int dlpf_index;
- u8 divider, reg;
int ret;
if (kstrtoul(buf, 10, &interval_ms))
@@ -275,29 +327,39 @@
(interval_ms > MPU3050_MAX_POLL_INTERVAL))
return -EINVAL;
- dlpf_index = interval_to_dlpf_cfg(interval_ms);
- divider = interval_ms * dlpf_table[dlpf_index].sample_rate - 1;
+ ret = mpu3050_poll_delay_set(&sensor->cdev, interval_ms);
- if (sensor->dlpf_index != dlpf_index) {
- /* Set low pass filter and full scale */
- reg = dlpf_table[dlpf_index].cfg;
- reg |= MPU3050_DEFAULT_FS_RANGE << 3;
- reg |= MPU3050_EXT_SYNC_NONE << 5;
- ret = i2c_smbus_write_byte_data(sensor->client,
- MPU3050_DLPF_FS_SYNC, reg);
- if (ret == 0)
- sensor->dlpf_index = dlpf_index;
+ return ret < 0 ? ret : size;
+}
+static int mpu3050_enable_set(struct sensors_classdev *sensors_cdev,
+ unsigned int enabled)
+{
+ struct mpu3050_sensor *sensor = container_of(sensors_cdev,
+ struct mpu3050_sensor, cdev);
+
+
+ if (enabled && (!sensor->enable)) {
+ sensor->enable = enabled;
+ pm_runtime_get_sync(sensor->dev);
+ if (sensor->use_poll)
+ schedule_delayed_work(&sensor->input_work,
+ msecs_to_jiffies(sensor->poll_interval));
+ else
+ enable_irq(sensor->client->irq);
+ } else if (!enabled && sensor->enable) {
+ if (sensor->use_poll)
+ cancel_delayed_work_sync(&sensor->input_work);
+ else
+ disable_irq(sensor->client->irq);
+ pm_runtime_put_sync(sensor->dev);
+ sensor->enable = enabled;
+ } else {
+ dev_warn(&sensor->client->dev,
+ "ignore enable state change from %d to %d\n",
+ sensor->enable, enabled);
}
- if (sensor->poll_interval != interval_ms) {
- /* Output frequency divider. The poll interval */
- ret = i2c_smbus_write_byte_data(sensor->client,
- MPU3050_SMPLRT_DIV, divider);
- if (ret == 0)
- sensor->poll_interval = interval_ms;
- }
-
- return size;
+ return 0;
}
/**
@@ -310,32 +372,14 @@
{
struct mpu3050_sensor *sensor = dev_get_drvdata(dev);
unsigned long val;
+ int err;
if (kstrtoul(buf, 10, &val))
return -EINVAL;
- sensor->enable = (u32)val == 0 ? 0 : 1;
- if (sensor->enable) {
- pm_runtime_get_sync(sensor->dev);
- gpio_set_value(sensor->enable_gpio, 1);
- if (sensor->use_poll)
- schedule_delayed_work(&sensor->input_work,
- msecs_to_jiffies(sensor->poll_interval));
- else {
- i2c_smbus_write_byte_data(sensor->client,
- MPU3050_INT_CFG,
- MPU3050_ACTIVE_LOW |
- MPU3050_OPEN_DRAIN |
- MPU3050_RAW_RDY_EN);
- enable_irq(sensor->client->irq);
- }
- } else {
- if (sensor->use_poll)
- cancel_delayed_work_sync(&sensor->input_work);
- else
- disable_irq(sensor->client->irq);
- gpio_set_value(sensor->enable_gpio, 0);
- pm_runtime_put(sensor->dev);
- }
+ err = mpu3050_enable_set(&sensor->cdev, val);
+ if (err < 0)
+ return err;
+
return count;
}
@@ -470,54 +514,6 @@
}
/**
- * mpu3050_input_open - called on input event open
- * @input: input dev of opened device
- *
- * The input layer calls this function when input event is opened. The
- * function will push the device to resume. Then, the device is ready
- * to provide data.
- */
-static int mpu3050_input_open(struct input_dev *input)
-{
- struct mpu3050_sensor *sensor = input_get_drvdata(input);
- int error;
-
- pm_runtime_get_sync(sensor->dev);
-
- /* Enable interrupts */
- error = i2c_smbus_write_byte_data(sensor->client, MPU3050_INT_CFG,
- MPU3050_ACTIVE_LOW |
- MPU3050_OPEN_DRAIN |
- MPU3050_RAW_RDY_EN);
- if (error < 0) {
- pm_runtime_put(sensor->dev);
- return error;
- }
- if (sensor->use_poll)
- schedule_delayed_work(&sensor->input_work,
- msecs_to_jiffies(sensor->poll_interval));
-
- return 0;
-}
-
-/**
- * mpu3050_input_close - called on input event close
- * @input: input dev of closed device
- *
- * The input layer calls this function when input event is closed. The
- * function will push the device to suspend.
- */
-static void mpu3050_input_close(struct input_dev *input)
-{
- struct mpu3050_sensor *sensor = input_get_drvdata(input);
-
- if (sensor->use_poll)
- cancel_delayed_work_sync(&sensor->input_work);
-
- pm_runtime_put(sensor->dev);
-}
-
-/**
* mpu3050_interrupt_thread - handle an IRQ
* @irq: interrupt numner
* @data: the sensor
@@ -573,18 +569,12 @@
*
* Called during device probe; configures the sampling method.
*/
-static int __devinit mpu3050_hw_init(struct mpu3050_sensor *sensor)
+static int mpu3050_hw_init(struct mpu3050_sensor *sensor)
{
struct i2c_client *client = sensor->client;
int ret;
u8 reg;
- /* Reset */
- ret = i2c_smbus_write_byte_data(client, MPU3050_PWR_MGM,
- MPU3050_PWR_MGM_RESET);
- if (ret < 0)
- return ret;
-
ret = i2c_smbus_read_byte_data(client, MPU3050_PWR_MGM);
if (ret < 0)
return ret;
@@ -609,6 +599,16 @@
if (ret < 0)
return ret;
+ /* Enable interrupts */
+ if (!sensor->use_poll) {
+ reg = MPU3050_ACTIVE_LOW;
+ reg |= MPU3050_OPEN_DRAIN;
+ reg |= MPU3050_RAW_RDY_EN;
+ ret = i2c_smbus_write_byte_data(client, MPU3050_INT_CFG, reg);
+ if (ret < 0)
+ return ret;
+ }
+
return 0;
}
#ifdef CONFIG_OF
@@ -708,6 +708,19 @@
sensor->enable_gpio = -EINVAL;
}
+ sensor->cdev = sensors_cdev;
+ sensor->cdev.min_delay = MPU3050_MIN_POLL_INTERVAL;
+ sensor->cdev.delay_msec = sensor->poll_interval;
+ sensor->cdev.sensors_enable = mpu3050_enable_set;
+ sensor->cdev.sensors_poll_delay = mpu3050_poll_delay_set;
+ ret = sensors_classdev_register(&client->dev, &sensor->cdev);
+
+ if (ret) {
+ dev_err(&client->dev, "class device create failed: %d\n", ret);
+ error = -EINVAL;
+ goto err_free_mem;
+ }
+
if (gpio_is_valid(sensor->enable_gpio)) {
ret = gpio_request(sensor->enable_gpio, "GYRO_EN_PM");
gpio_direction_output(sensor->enable_gpio, 1);
@@ -719,7 +732,7 @@
if (ret < 0) {
dev_err(&client->dev, "failed to detect device\n");
error = -ENXIO;
- goto err_free_mem;
+ goto err_class_sysfs;
}
for (i = 0; i < ARRAY_SIZE(mpu3050_chip_ids); i++)
@@ -729,15 +742,12 @@
if (i == ARRAY_SIZE(mpu3050_chip_ids)) {
dev_err(&client->dev, "unsupported chip id\n");
error = -ENXIO;
- goto err_free_mem;
+ goto err_class_sysfs;
}
idev->name = "MPU3050";
idev->id.bustype = BUS_I2C;
- idev->open = mpu3050_input_open;
- idev->close = mpu3050_input_close;
-
input_set_capability(idev, EV_ABS, ABS_MISC);
input_set_abs_params(idev, ABS_X,
MPU3050_MIN_VALUE, MPU3050_MAX_VALUE, 0, 0);
@@ -798,6 +808,9 @@
disable_irq(client->irq);
}
+ sensor->enable = 0;
+ mpu3050_set_power_mode(client, 0);
+
error = input_register_device(idev);
if (error) {
dev_err(&client->dev, "failed to register input device\n");
@@ -826,6 +839,8 @@
gpio_free(sensor->platform_data->gpio_int);
err_pm_set_suspended:
pm_runtime_set_suspended(&client->dev);
+err_class_sysfs:
+ sensors_classdev_unregister(&sensor->cdev);
err_free_mem:
input_free_device(idev);
kfree(sensor);
@@ -870,10 +885,11 @@
struct i2c_client *client = to_i2c_client(dev);
struct mpu3050_sensor *sensor = i2c_get_clientdata(client);
- if (!sensor->use_poll)
- disable_irq(client->irq);
-
- mpu3050_set_power_mode(client, 0);
+ if (sensor->enable) {
+ if (!sensor->use_poll)
+ disable_irq(client->irq);
+ mpu3050_set_power_mode(client, 0);
+ }
return 0;
}
@@ -889,16 +905,64 @@
struct i2c_client *client = to_i2c_client(dev);
struct mpu3050_sensor *sensor = i2c_get_clientdata(client);
- mpu3050_set_power_mode(client, 1);
+ if (sensor->enable) {
+ mpu3050_set_power_mode(client, 1);
+ mpu3050_hw_init(sensor);
+ if (!sensor->use_poll)
+ enable_irq(client->irq);
+ }
- if (!sensor->use_poll)
- enable_irq(client->irq);
+ return 0;
+}
+
+/**
+ * mpu3050_runtime_suspend - called on device enters runtime suspend
+ * @dev: device being suspended
+ *
+ * Put the device into sleep mode.
+ */
+static int mpu3050_runtime_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct mpu3050_sensor *sensor = i2c_get_clientdata(client);
+
+ if (sensor->enable)
+ mpu3050_set_power_mode(client, 0);
+
+ return 0;
+}
+
+/**
+ * mpu3050_runtime_resume - called on device enters runtime resume
+ * @dev: device being resumed
+ *
+ * Put the device into powered mode.
+ */
+static int mpu3050_runtime_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct mpu3050_sensor *sensor = i2c_get_clientdata(client);
+
+ if (sensor->enable) {
+ mpu3050_set_power_mode(client, 1);
+ mpu3050_hw_init(sensor);
+ }
return 0;
}
#endif
-static UNIVERSAL_DEV_PM_OPS(mpu3050_pm, mpu3050_suspend, mpu3050_resume, NULL);
+static const struct dev_pm_ops mpu3050_pm = {
+ .runtime_suspend = mpu3050_runtime_suspend,
+ .runtime_resume = mpu3050_runtime_resume,
+ .runtime_idle = NULL,
+ .suspend = mpu3050_suspend,
+ .resume = mpu3050_resume,
+ .freeze = mpu3050_suspend,
+ .thaw = mpu3050_resume,
+ .poweroff = mpu3050_suspend,
+ .restore = mpu3050_resume,
+};
static const struct i2c_device_id mpu3050_ids[] = {
{ "mpu3050", 0 },
diff --git a/drivers/input/misc/stk3x1x.c b/drivers/input/misc/stk3x1x.c
index b753d55..f9d3478 100644
--- a/drivers/input/misc/stk3x1x.c
+++ b/drivers/input/misc/stk3x1x.c
@@ -32,6 +32,7 @@
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/input.h>
+#include <linux/sensors.h>
#include <linux/workqueue.h>
#include <linux/irq.h>
#include <linux/delay.h>
@@ -63,8 +64,6 @@
#define STK_POLL_PS
#define STK_POLL_ALS /* ALS interrupt is valid only when STK_PS_INT_MODE = 1 or 4*/
-#define STK_DEBUG_PRINTF
-
/* Define Register Map */
#define STK_STATE_REG 0x00
#define STK_PSCTRL_REG 0x01
@@ -181,6 +180,43 @@
#define STK_FIR_LEN 16
#define MAX_FIR_LEN 32
+
+static struct sensors_classdev sensors_light_cdev = {
+ .name = "stk3x1x-light",
+ .vendor = "Sensortek",
+ .version = 1,
+ .handle = SENSORS_LIGHT_HANDLE,
+ .type = SENSOR_TYPE_LIGHT,
+ .max_range = "6500",
+ .resolution = "0.0625",
+ .sensor_power = "0.09",
+ .min_delay = (MIN_ALS_POLL_DELAY_NS / 1000), /* us */
+ .fifo_reserved_event_count = 0,
+ .fifo_max_event_count = 0,
+ .enabled = 0,
+ .delay_msec = 200,
+ .sensors_enable = NULL,
+ .sensors_poll_delay = NULL,
+};
+
+static struct sensors_classdev sensors_proximity_cdev = {
+ .name = "stk3x1x-proximity",
+ .vendor = "Sensortek",
+ .version = 1,
+ .handle = SENSORS_PROXIMITY_HANDLE,
+ .type = SENSOR_TYPE_PROXIMITY,
+ .max_range = "5.0",
+ .resolution = "5.0",
+ .sensor_power = "0.1",
+ .min_delay = 0,
+ .fifo_reserved_event_count = 0,
+ .fifo_max_event_count = 0,
+ .enabled = 0,
+ .delay_msec = 200,
+ .sensors_enable = NULL,
+ .sensors_poll_delay = NULL,
+};
+
struct data_filter {
u16 raw[MAX_FIR_LEN];
int sum;
@@ -191,6 +227,8 @@
struct stk3x1x_data {
struct i2c_client *client;
struct stk3x1x_platform_data *pdata;
+ struct sensors_classdev als_cdev;
+ struct sensors_classdev ps_cdev;
#if (!defined(STK_POLL_PS) || !defined(STK_POLL_ALS))
int32_t irq;
struct work_struct stk_work;
@@ -208,7 +246,7 @@
int32_t ps_distance_last;
bool ps_enabled;
struct wake_lock ps_wakelock;
- struct work_struct stk_ps_work;
+ struct work_struct stk_ps_work;
struct workqueue_struct *stk_ps_wq;
#ifdef STK_POLL_PS
struct wake_lock ps_nosuspend_wl;
@@ -291,11 +329,11 @@
for (i=1,j=0;i<LUX_THD_TABLE_SIZE;i++,j++)
{
alscode = stk_lux2alscode(ps_data, lux_threshold_table[j]);
- printk(KERN_INFO "alscode[%d]=%d\n",i,alscode);
+ dev_dbg(&ps_data->client->dev, "alscode[%d]=%d\n", i, alscode);
code_threshold_table[i] = (uint16_t)(alscode);
}
code_threshold_table[i] = 0xffff;
- printk(KERN_INFO "alscode[%d]=%d\n",i,alscode);
+ dev_dbg(&ps_data->client->dev, "alscode[%d]=%d\n", i, alscode);
}
static uint32_t stk_get_lux_interval_index(uint16_t alscode)
@@ -428,7 +466,6 @@
printk(KERN_ERR "%s: read i2c error, err=%d\n", __func__, err2);
return -1;
}
- printk(KERN_INFO "%s: PID=0x%x, RID=0x%x\n", __func__, err1, err2);
if(err2 == 0xC0)
printk(KERN_INFO "%s: RID=0xC0!!!!!!!!!!!!!\n", __func__);
@@ -655,7 +692,9 @@
input_sync(ps_data->ps_input_dev);
wake_lock_timeout(&ps_data->ps_wakelock, 3*HZ);
reading = stk3x1x_get_ps_reading(ps_data);
- printk(KERN_INFO "%s: ps input event=%d, ps code = %d\n",__func__, near_far_state, reading);
+ dev_dbg(&ps_data->client->dev,
+ "%s: ps input event=%d, ps code = %d\n",
+ __func__, near_far_state, reading);
#endif /* #ifndef STK_POLL_PS */
}
else
@@ -874,6 +913,21 @@
return scnprintf(buf, PAGE_SIZE, "%d\n", reading);
}
+static ssize_t stk_als_enable_set(struct sensors_classdev *sensors_cdev,
+ unsigned int enabled)
+{
+ struct stk3x1x_data *als_data = container_of(sensors_cdev,
+ struct stk3x1x_data, als_cdev);
+ int err;
+
+ mutex_lock(&als_data->io_lock);
+ err = stk3x1x_enable_als(als_data, enabled);
+ mutex_unlock(&als_data->io_lock);
+
+ if (err < 0)
+ return err;
+ return 0;
+}
static ssize_t stk_als_enable_show(struct device *dev, struct device_attribute *attr, char *buf)
{
@@ -905,7 +959,7 @@
printk(KERN_ERR "%s, invalid value %d\n", __func__, *buf);
return -EINVAL;
}
- printk(KERN_INFO "%s: Enable ALS : %d\n", __func__, en);
+ dev_dbg(dev, "%s: Enable ALS : %d\n", __func__, en);
mutex_lock(&ps_data->io_lock);
stk3x1x_enable_als(ps_data, en);
mutex_unlock(&ps_data->io_lock);
@@ -941,7 +995,7 @@
input_report_abs(ps_data->als_input_dev, ABS_MISC, value);
input_sync(ps_data->als_input_dev);
mutex_unlock(&ps_data->io_lock);
- printk(KERN_INFO "%s: als input event %ld lux\n",__func__, value);
+ dev_dbg(dev, "%s: als input event %ld lux\n", __func__, value);
return size;
}
@@ -979,7 +1033,8 @@
static ssize_t stk_als_delay_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
- return scnprintf(buf, PAGE_SIZE, "%lld\n", ktime_to_ns(ps_data->als_poll_delay));
+ return scnprintf(buf, PAGE_SIZE, "%u\n",
+ (u32)ktime_to_ms(ps_data->als_poll_delay));
}
static inline void stk_als_delay_store_fir(struct stk3x1x_data *ps_data)
@@ -988,34 +1043,48 @@
ps_data->fir.idx = 0;
ps_data->fir.sum = 0;
}
+
+static ssize_t stk_als_poll_delay_set(struct sensors_classdev *sensors_cdev,
+ unsigned int delay_msec)
+{
+ struct stk3x1x_data *als_data = container_of(sensors_cdev,
+ struct stk3x1x_data, als_cdev);
+ uint64_t value = 0;
+
+ value = delay_msec * 1000000;
+
+ if (value < MIN_ALS_POLL_DELAY_NS)
+ value = MIN_ALS_POLL_DELAY_NS;
+
+ mutex_lock(&als_data->io_lock);
+ if (value != ktime_to_ns(als_data->als_poll_delay))
+ als_data->als_poll_delay = ns_to_ktime(value);
+
+ if (als_data->use_fir)
+ stk_als_delay_store_fir(als_data);
+
+ mutex_unlock(&als_data->io_lock);
+
+ return 0;
+}
+
static ssize_t stk_als_delay_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
uint64_t value = 0;
int ret;
- struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ struct stk3x1x_data *als_data = dev_get_drvdata(dev);
ret = kstrtoull(buf, 10, &value);
if(ret < 0)
{
- printk(KERN_ERR "%s:kstrtoull failed, ret=0x%x\n",
- __func__, ret);
+ dev_err(dev, "%s:kstrtoull failed, ret=0x%x\n", __func__, ret);
return ret;
}
#ifdef STK_DEBUG_PRINTF
- printk(KERN_INFO "%s: set als poll delay=%lld\n", __func__, value);
+ dev_dbg(dev, "%s: set als poll delay=%lld\n", __func__, value);
#endif
- if(value < MIN_ALS_POLL_DELAY_NS)
- {
- printk(KERN_ERR "%s: delay is too small\n", __func__);
- value = MIN_ALS_POLL_DELAY_NS;
- }
- mutex_lock(&ps_data->io_lock);
- if(value != ktime_to_ns(ps_data->als_poll_delay))
- ps_data->als_poll_delay = ns_to_ktime(value);
-
- if (ps_data->use_fir)
- stk_als_delay_store_fir(ps_data);
-
- mutex_unlock(&ps_data->io_lock);
+ ret = stk_als_poll_delay_set(&als_data->als_cdev, value);
+ if (ret < 0)
+ return ret;
return size;
}
@@ -1106,6 +1175,22 @@
return scnprintf(buf, PAGE_SIZE, "%d\n", reading);
}
+static ssize_t stk_ps_enable_set(struct sensors_classdev *sensors_cdev,
+ unsigned int enabled)
+{
+ struct stk3x1x_data *ps_data = container_of(sensors_cdev,
+ struct stk3x1x_data, ps_cdev);
+ int err;
+
+ mutex_lock(&ps_data->io_lock);
+ err = stk3x1x_enable_ps(ps_data, enabled);
+ mutex_unlock(&ps_data->io_lock);
+
+ if (err < 0)
+ return err;
+ return 0;
+}
+
static ssize_t stk_ps_enable_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int32_t enable, ret;
@@ -1136,7 +1221,7 @@
printk(KERN_ERR "%s, invalid value %d\n", __func__, *buf);
return -EINVAL;
}
- printk(KERN_INFO "%s: Enable PS : %d\n", __func__, en);
+ dev_dbg(dev, "%s: Enable PS : %d\n", __func__, en);
mutex_lock(&ps_data->io_lock);
stk3x1x_enable_ps(ps_data, en);
mutex_unlock(&ps_data->io_lock);
@@ -1170,7 +1255,7 @@
printk(KERN_ERR "%s, invalid value %d\n", __func__, *buf);
return -EINVAL;
}
- printk(KERN_INFO "%s: Enable PS ASO : %d\n", __func__, en);
+ dev_dbg(dev, "%s: Enable PS ASO : %d\n", __func__, en);
ret = i2c_smbus_read_byte_data(ps_data->client, STK_STATE_REG);
if (ret < 0)
@@ -1258,7 +1343,7 @@
input_sync(ps_data->ps_input_dev);
mutex_unlock(&ps_data->io_lock);
wake_lock_timeout(&ps_data->ps_wakelock, 3*HZ);
- printk(KERN_INFO "%s: ps input event %d cm\n",__func__, dist);
+ dev_dbg(dev, "%s: ps input event %d cm\n", __func__, dist);
return scnprintf(buf, PAGE_SIZE, "%d\n", dist);
}
@@ -1281,7 +1366,7 @@
input_sync(ps_data->ps_input_dev);
mutex_unlock(&ps_data->io_lock);
wake_lock_timeout(&ps_data->ps_wakelock, 3*HZ);
- printk(KERN_INFO "%s: ps input event %ld cm\n",__func__, value);
+ dev_dbg(dev, "%s: ps input event %ld cm\n", __func__, value);
return size;
}
@@ -1477,7 +1562,7 @@
}
else
{
- printk(KERN_INFO "reg[0x%2X]=0x%2X\n", cnt, ps_reg[cnt]);
+ dev_dbg(dev, "reg[0x%2X]=0x%2X\n", cnt, ps_reg[cnt]);
}
}
ps_reg[cnt] = i2c_smbus_read_byte_data(ps_data->client, STK_PDT_ID_REG);
@@ -1487,7 +1572,7 @@
printk( KERN_ERR "all_reg_show:i2c_smbus_read_byte_data fail, ret=%d", ps_reg[cnt]);
return -EINVAL;
}
- printk( KERN_INFO "reg[0x%x]=0x%2X\n", STK_PDT_ID_REG, ps_reg[cnt]);
+ dev_dbg(dev, "reg[0x%x]=0x%2X\n", STK_PDT_ID_REG, ps_reg[cnt]);
cnt++;
ps_reg[cnt] = i2c_smbus_read_byte_data(ps_data->client, STK_RSRVD_REG);
if(ps_reg[cnt] < 0)
@@ -1496,7 +1581,7 @@
printk( KERN_ERR "all_reg_show:i2c_smbus_read_byte_data fail, ret=%d", ps_reg[cnt]);
return -EINVAL;
}
- printk( KERN_INFO "reg[0x%x]=0x%2X\n", STK_RSRVD_REG, ps_reg[cnt]);
+ dev_dbg(dev, "reg[0x%x]=0x%2X\n", STK_RSRVD_REG, ps_reg[cnt]);
mutex_unlock(&ps_data->io_lock);
return scnprintf(buf, PAGE_SIZE, "%2X %2X %2X %2X %2X,%2X %2X %2X %2X %2X,%2X %2X %2X %2X %2X,%2X %2X %2X %2X %2X,%2X %2X %2X %2X %2X,%2X %2X\n",
@@ -1559,8 +1644,7 @@
__func__, ret);
return ret;
}
- printk(KERN_INFO "%s: write reg 0x%x=0x%x\n", __func__, addr, cmd);
-
+ dev_dbg(dev, "%s: write reg 0x%x=0x%x\n", __func__, addr, cmd);
addr_u8 = (u8) addr;
cmd_u8 = (u8) cmd;
//mutex_lock(&ps_data->io_lock);
@@ -1658,7 +1742,6 @@
input_report_abs(ps_data->als_input_dev, ABS_MISC, ps_data->als_lux_last);
input_sync(ps_data->als_input_dev);
mutex_unlock(&ps_data->io_lock);
- //printk(KERN_INFO "%s: als input event %d lux\n",__func__, ps_data->als_lux_last);
}
#endif
@@ -1918,7 +2001,6 @@
int err;
#endif
- printk(KERN_INFO "%s", __func__);
mutex_lock(&ps_data->io_lock);
if(ps_data->als_enabled)
{
@@ -1946,7 +2028,6 @@
int err;
#endif
- printk(KERN_INFO "%s", __func__);
mutex_lock(&ps_data->io_lock);
if(ps_data->als_enabled)
stk3x1x_enable_als(ps_data, 1);
@@ -2363,6 +2444,20 @@
ps_data->stk_early_suspend.resume = stk3x1x_late_resume;
register_early_suspend(&ps_data->stk_early_suspend);
#endif
+ /* make sure everything is ok before registering the class device */
+ ps_data->als_cdev = sensors_light_cdev;
+ ps_data->als_cdev.sensors_enable = stk_als_enable_set;
+ ps_data->als_cdev.sensors_poll_delay = stk_als_poll_delay_set;
+ err = sensors_classdev_register(&client->dev, &ps_data->als_cdev);
+ if (err)
+ goto err_power_on;
+
+ ps_data->ps_cdev = sensors_proximity_cdev;
+ ps_data->ps_cdev.sensors_enable = stk_ps_enable_set;
+ err = sensors_classdev_register(&client->dev, &ps_data->ps_cdev);
+ if (err)
+ goto err_class_sysfs;
+
/* enable device power only when it is enabled */
err = stk3x1x_power_ctl(ps_data, false);
if (err)
@@ -2373,6 +2468,9 @@
err_init_all_setting:
stk3x1x_power_ctl(ps_data, false);
+ sensors_classdev_unregister(&ps_data->ps_cdev);
+err_class_sysfs:
+ sensors_classdev_unregister(&ps_data->als_cdev);
err_power_on:
stk3x1x_power_init(ps_data, false);
err_power_init:
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 9b0c5c7..1e08169 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -110,6 +110,18 @@
To compile this driver as a module, choose M here: the
module will be called atmel_mxt_ts.
+config TOUCHSCREEN_ATMEL_MAXTOUCH_TS
+ tristate "Atmel Maxtouch Touchscreen Family"
+ depends on I2C
+ help
+ Say Y here if you have Atmel MaXTouch Touchscreen
+ using i2c connected to your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called atmel_maxtouch_ts.
+
config TOUCHSCREEN_AUO_PIXCIR
tristate "AUO in-cell touchscreen using Pixcir ICs"
depends on I2C
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 3acc612..2b98145 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -14,6 +14,7 @@
obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o
obj-$(CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH) += atmel_maxtouch.o
obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT) += atmel_mxt_ts.o
+obj-$(CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH_TS) += atmel_maxtouch_ts.o
obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o
obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR) += auo-pixcir-ts.o
obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 3731561..b79ab7a 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -2049,14 +2049,17 @@
return scnprintf(buf, PAGE_SIZE, "%u", val);
}
-static DEVICE_ATTR(secure_touch_enable, 0666, mxt_secure_touch_enable_show,
- mxt_secure_touch_enable_store);
-static DEVICE_ATTR(secure_touch, 0444, mxt_secure_touch_show, NULL);
+static DEVICE_ATTR(secure_touch_enable, S_IRUGO | S_IWUSR | S_IWGRP ,
+ mxt_secure_touch_enable_show,
+ mxt_secure_touch_enable_store);
+static DEVICE_ATTR(secure_touch, S_IRUGO, mxt_secure_touch_show, NULL);
#endif
-static DEVICE_ATTR(object, 0444, mxt_object_show, NULL);
-static DEVICE_ATTR(update_fw, 0664, NULL, mxt_update_fw_store);
-static DEVICE_ATTR(force_cfg_update, 0664, NULL, mxt_force_cfg_update_store);
+static DEVICE_ATTR(object, S_IRUGO, mxt_object_show, NULL);
+static DEVICE_ATTR(update_fw, S_IWUSR | S_IWGRP , NULL, mxt_update_fw_store);
+static DEVICE_ATTR(force_cfg_update, S_IWUSR | S_IWGRP ,
+ NULL,
+ mxt_force_cfg_update_store);
static struct attribute *mxt_attrs[] = {
&dev_attr_object.attr,
diff --git a/drivers/input/touchscreen/cyttsp-i2c-qc.c b/drivers/input/touchscreen/cyttsp-i2c-qc.c
index 6c4e6b7..2b1360e 100644
--- a/drivers/input/touchscreen/cyttsp-i2c-qc.c
+++ b/drivers/input/touchscreen/cyttsp-i2c-qc.c
@@ -2873,6 +2873,21 @@
return rc;
}
+static void cyttsp_release_all(struct cyttsp *ts)
+{
+ int id;
+
+ for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
+ input_mt_slot(ts->input, id);
+ input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, 0);
+ }
+
+ input_report_key(ts->input, BTN_TOUCH, 0);
+ input_report_key(ts->input, BTN_TOOL_FINGER, 0);
+
+ input_sync(ts->input);
+}
+
/* Function to manage power-on resume */
static int cyttsp_resume(struct device *dev)
{
@@ -2978,6 +2993,8 @@
else
disable_irq(ts->client->irq);
+ cyttsp_release_all(ts);
+
if (!(retval < CY_OK)) {
if (ts->platform_data->use_sleep &&
(ts->platform_data->power_state == CY_ACTIVE_STATE)) {
diff --git a/drivers/input/touchscreen/ft5x06_ts.c b/drivers/input/touchscreen/ft5x06_ts.c
index ef76e69..4b8a3d4 100644
--- a/drivers/input/touchscreen/ft5x06_ts.c
+++ b/drivers/input/touchscreen/ft5x06_ts.c
@@ -131,8 +131,9 @@
#define FT_FW_PKT_DLY_MS 20
#define FT_FW_LAST_PKT 0x6ffa
#define FT_EARSE_DLY_MS 100
+#define FT_55_AA_DLY_NS 5000
-#define FT_UPGRADE_LOOP 10
+#define FT_UPGRADE_LOOP 30
#define FT_CAL_START 0x04
#define FT_CAL_FIN 0x00
#define FT_CAL_STORE 0x05
@@ -142,6 +143,30 @@
#define FT_INFO_MAX_LEN 512
+#define FT_BLOADER_SIZE_OFF 12
+#define FT_BLOADER_NEW_SIZE 30
+#define FT_DATA_LEN_OFF_OLD_FW 8
+#define FT_DATA_LEN_OFF_NEW_FW 14
+#define FT_FINISHING_PKT_LEN_OLD_FW 6
+#define FT_FINISHING_PKT_LEN_NEW_FW 12
+#define FT_MAGIC_BLOADER_Z7 0x7bfa
+#define FT_MAGIC_BLOADER_LZ4 0x6ffa
+#define FT_MAGIC_BLOADER_GZF_30 0x7ff4
+#define FT_MAGIC_BLOADER_GZF 0x7bf4
+
+enum {
+ FT_BLOADER_VERSION_LZ4 = 0,
+ FT_BLOADER_VERSION_Z7 = 1,
+ FT_BLOADER_VERSION_GZF = 2,
+};
+
+enum {
+ FT_FT5336_FAMILY_ID_0x11 = 0x11,
+ FT_FT5336_FAMILY_ID_0x12 = 0x12,
+ FT_FT5336_FAMILY_ID_0x13 = 0x13,
+ FT_FT5336_FAMILY_ID_0x14 = 0x14,
+};
+
#define FT_STORE_TS_INFO(buf, id, name, max_tch, group_id, fw_vkey_support, \
fw_name, fw_maj, fw_min, fw_sub_min) \
snprintf(buf, FT_INFO_MAX_LEN, \
@@ -645,11 +670,20 @@
u8 reset_reg;
u8 w_buf[FT_MAX_WR_BUF] = {0}, r_buf[FT_MAX_RD_BUF] = {0};
u8 pkt_buf[FT_FW_PKT_LEN + FT_FW_PKT_META_LEN];
- int rc, i, j, temp;
+ int i, j, temp;
u32 pkt_num, pkt_len;
+ u8 is_5336_new_bootloader = false;
+ u8 is_5336_fwsize_30 = false;
u8 fw_ecc;
+ /* determine firmware size */
+ if (*(data + data_len - FT_BLOADER_SIZE_OFF) == FT_BLOADER_NEW_SIZE)
+ is_5336_fwsize_30 = true;
+ else
+ is_5336_fwsize_30 = false;
+
for (i = 0, j = 0; i < FT_UPGRADE_LOOP; i++) {
+ msleep(FT_EARSE_DLY_MS);
/* reset - write 0xaa and 0x55 to reset register */
if (ts_data->family_id == FT6X06_ID)
reset_reg = FT_RST_CMD_REG2;
@@ -660,16 +694,17 @@
msleep(info.delay_aa);
ft5x0x_write_reg(client, reset_reg, FT_UPGRADE_55);
- msleep(info.delay_55);
+ if (i <= (FT_UPGRADE_LOOP / 2))
+ msleep(info.delay_55 + i * 3);
+ else
+ msleep(info.delay_55 - (i - (FT_UPGRADE_LOOP / 2)) * 2);
/* Enter upgrade mode */
w_buf[0] = FT_UPGRADE_55;
- w_buf[1] = FT_UPGRADE_AA;
- do {
- j++;
- rc = ft5x06_i2c_write(client, w_buf, 2);
- msleep(FT_RETRY_DLY);
- } while (rc <= 0 && j < FT_MAX_TRIES);
+ ft5x06_i2c_write(client, w_buf, 1);
+ usleep(FT_55_AA_DLY_NS);
+ w_buf[0] = FT_UPGRADE_AA;
+ ft5x06_i2c_write(client, w_buf, 1);
/* check READ_ID */
msleep(info.delay_readid);
@@ -682,7 +717,9 @@
if (r_buf[0] != info.upgrade_id_1
|| r_buf[1] != info.upgrade_id_2) {
- dev_err(&client->dev, "Upgrade ID mismatch(%d)\n", i);
+ dev_err(&client->dev, "Upgrade ID mismatch(%d), IC=0x%x 0x%x, info=0x%x 0x%x\n",
+ i, r_buf[0], r_buf[1],
+ info.upgrade_id_1, info.upgrade_id_2);
} else
break;
}
@@ -692,17 +729,44 @@
return -EIO;
}
+ w_buf[0] = 0xcd;
+ ft5x06_i2c_read(client, w_buf, 1, r_buf, 1);
+
+ if (r_buf[0] <= 4)
+ is_5336_new_bootloader = FT_BLOADER_VERSION_LZ4;
+ else if (r_buf[0] == 7)
+ is_5336_new_bootloader = FT_BLOADER_VERSION_Z7;
+ else if (r_buf[0] >= 0x0f &&
+ ((ts_data->family_id == FT_FT5336_FAMILY_ID_0x11) ||
+ (ts_data->family_id == FT_FT5336_FAMILY_ID_0x12) ||
+ (ts_data->family_id == FT_FT5336_FAMILY_ID_0x13) ||
+ (ts_data->family_id == FT_FT5336_FAMILY_ID_0x14)))
+ is_5336_new_bootloader = FT_BLOADER_VERSION_GZF;
+ else
+ is_5336_new_bootloader = FT_BLOADER_VERSION_LZ4;
+
+ dev_dbg(&client->dev, "bootloader type=%d, r_buf=0x%x, family_id=0x%x\n",
+ is_5336_new_bootloader, r_buf[0], ts_data->family_id);
+ /* is_5336_new_bootloader = FT_BLOADER_VERSION_GZF; */
+
/* erase app and panel paramenter area */
w_buf[0] = FT_ERASE_APP_REG;
ft5x06_i2c_write(client, w_buf, 1);
msleep(info.delay_erase_flash);
- w_buf[0] = FT_ERASE_PANEL_REG;
- ft5x06_i2c_write(client, w_buf, 1);
+ if (is_5336_fwsize_30) {
+ w_buf[0] = FT_ERASE_PANEL_REG;
+ ft5x06_i2c_write(client, w_buf, 1);
+ }
msleep(FT_EARSE_DLY_MS);
/* program firmware */
- data_len = data_len - 8;
+ if (is_5336_new_bootloader == FT_BLOADER_VERSION_LZ4
+ || is_5336_new_bootloader == FT_BLOADER_VERSION_Z7)
+ data_len = data_len - FT_DATA_LEN_OFF_OLD_FW;
+ else
+ data_len = data_len - FT_DATA_LEN_OFF_NEW_FW;
+
pkt_num = (data_len) / FT_FW_PKT_LEN;
pkt_len = FT_FW_PKT_LEN;
pkt_buf[0] = FT_FW_START_REG;
@@ -745,17 +809,45 @@
}
/* send the finishing packet */
- for (i = 0; i < 6; i++) {
- temp = FT_FW_LAST_PKT + i;
- pkt_buf[2] = (u8) (temp >> 8);
- pkt_buf[3] = (u8) temp;
- temp = 1;
- pkt_buf[4] = (u8) (temp >> 8);
- pkt_buf[5] = (u8) temp;
- pkt_buf[6] = data[data_len + i];
- fw_ecc ^= pkt_buf[6];
- ft5x06_i2c_write(client, pkt_buf, temp + FT_FW_PKT_META_LEN);
- msleep(FT_FW_PKT_DLY_MS);
+ if (is_5336_new_bootloader == FT_BLOADER_VERSION_LZ4 ||
+ is_5336_new_bootloader == FT_BLOADER_VERSION_Z7) {
+ for (i = 0; i < FT_FINISHING_PKT_LEN_OLD_FW; i++) {
+ if (is_5336_new_bootloader == FT_BLOADER_VERSION_Z7)
+ temp = FT_MAGIC_BLOADER_Z7 + i;
+ else if (is_5336_new_bootloader ==
+ FT_BLOADER_VERSION_LZ4)
+ temp = FT_MAGIC_BLOADER_LZ4 + i;
+ pkt_buf[2] = (u8)(temp >> 8);
+ pkt_buf[3] = (u8)temp;
+ temp = 1;
+ pkt_buf[4] = (u8)(temp >> 8);
+ pkt_buf[5] = (u8)temp;
+ pkt_buf[6] = data[data_len + i];
+ fw_ecc ^= pkt_buf[6];
+
+ ft5x06_i2c_write(client,
+ pkt_buf, temp + FT_FW_PKT_META_LEN);
+ msleep(FT_FW_PKT_DLY_MS);
+ }
+ } else if (is_5336_new_bootloader == FT_BLOADER_VERSION_GZF) {
+ for (i = 0; i < FT_FINISHING_PKT_LEN_NEW_FW; i++) {
+ if (is_5336_fwsize_30)
+ temp = FT_MAGIC_BLOADER_GZF_30 + i;
+ else
+ temp = FT_MAGIC_BLOADER_GZF + i;
+ pkt_buf[2] = (u8)(temp >> 8);
+ pkt_buf[3] = (u8)temp;
+ temp = 1;
+ pkt_buf[4] = (u8)(temp >> 8);
+ pkt_buf[5] = (u8)temp;
+ pkt_buf[6] = data[data_len + i];
+ fw_ecc ^= pkt_buf[6];
+
+ ft5x06_i2c_write(client,
+ pkt_buf, temp + FT_FW_PKT_META_LEN);
+ msleep(FT_FW_PKT_DLY_MS);
+
+ }
}
/* verify checksum */
@@ -1451,11 +1543,12 @@
goto free_reset_gpio;
}
- data->family_id = reg_value;
+ data->family_id = pdata->family_id;
err = request_threaded_irq(client->irq, NULL,
- ft5x06_ts_interrupt, pdata->irqflags,
- client->dev.driver->name, data);
+ ft5x06_ts_interrupt,
+ pdata->irqflags | IRQF_ONESHOT,
+ client->dev.driver->name, data);
if (err) {
dev_err(&client->dev, "request irq failed\n");
goto free_reset_gpio;
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx.c b/drivers/input/touchscreen/gt9xx/gt9xx.c
index 8b08ac9..6d4c638 100644
--- a/drivers/input/touchscreen/gt9xx/gt9xx.c
+++ b/drivers/input/touchscreen/gt9xx/gt9xx.c
@@ -95,6 +95,8 @@
static void gtp_reset_guitar(struct goodix_ts_data *ts, int ms);
static void gtp_int_sync(struct goodix_ts_data *ts, int ms);
static int gtp_i2c_test(struct i2c_client *client);
+static int goodix_power_off(struct goodix_ts_data *ts);
+static int goodix_power_on(struct goodix_ts_data *ts);
#if defined(CONFIG_FB)
static int fb_notifier_callback(struct notifier_block *self,
@@ -751,16 +753,13 @@
return ret;
}
#else
-/*******************************************************
-Function:
- Enter sleep mode.
-Input:
- ts: private data.
-Output:
- Executive outcomes.
- 1: succeed, otherwise failed.
-*******************************************************/
-static s8 gtp_enter_sleep(struct goodix_ts_data *ts)
+/**
+ * gtp_enter_sleep - Enter sleep mode
+ * @ts: driver private data
+ *
+ * Returns zero on success, else an error.
+ */
+static u8 gtp_enter_sleep(struct goodix_ts_data *ts)
{
int ret = -1;
s8 retry = 0;
@@ -769,20 +768,37 @@
(u8)GTP_REG_SLEEP, 5};
ret = gpio_direction_output(ts->pdata->irq_gpio, 0);
- usleep(5000);
- while (retry++ < 5) {
- ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
- if (ret > 0) {
- dev_dbg(&ts->client->dev,
- "GTP enter sleep!");
+ if (ret)
+ dev_err(&ts->client->dev,
+ "GTP sleep: Cannot reconfig gpio %d.\n",
+ ts->pdata->irq_gpio);
+ if (ts->pdata->enable_power_off) {
+ ret = gpio_direction_output(ts->pdata->reset_gpio, 0);
+ if (ret)
+ dev_err(&ts->client->dev,
+ "GTP sleep: Cannot reconfig gpio %d.\n",
+ ts->pdata->reset_gpio);
+ ret = goodix_power_off(ts);
+ if (ret) {
+ dev_err(&ts->client->dev, "GTP power off failed.\n");
return ret;
}
- msleep(20);
+ return 0;
+ } else {
+ usleep(5000);
+ while (retry++ < 5) {
+ ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
+ if (ret == 1) {
+ dev_dbg(&ts->client->dev, "GTP enter sleep!");
+ return 0;
+ }
+ msleep(20);
+ }
+ dev_err(&ts->client->dev, "GTP send sleep cmd failed.\n");
+ return ret;
}
- dev_err(&ts->client->dev, "GTP send sleep cmd failed.\n");
- return ret;
}
-#endif
+#endif /* !GTP_SLIDE_WAKEUP */
/*******************************************************
Function:
@@ -798,17 +814,36 @@
u8 retry = 0;
s8 ret = -1;
-#if GTP_POWER_CTRL_SLEEP
- gtp_reset_guitar(ts, 20);
+ if (ts->pdata->enable_power_off) {
+ ret = gpio_direction_output(ts->pdata->irq_gpio, 0);
+ if (ret)
+ dev_err(&ts->client->dev,
+ "GTP wakeup: Cannot reconfig gpio %d.\n",
+ ts->pdata->irq_gpio);
+ ret = gpio_direction_output(ts->pdata->reset_gpio, 0);
+ if (ret)
+ dev_err(&ts->client->dev,
+ "GTP wakeup: Cannot reconfig gpio %d.\n",
+ ts->pdata->reset_gpio);
+ ret = goodix_power_on(ts);
+ if (ret) {
+ dev_err(&ts->client->dev, "GTP power on failed.\n");
+ return 0;
+ }
- ret = gtp_send_cfg(ts);
- if (ret > 0) {
+ gtp_reset_guitar(ts, 20);
+
+ ret = gtp_send_cfg(ts);
+ if (ret <= 0) {
+ dev_err(&ts->client->dev,
+ "GTP wakeup sleep failed.\n");
+ return ret;
+ }
+
dev_dbg(&ts->client->dev,
- "Wakeup sleep send config success.");
- return 1;
- }
-#else
- while (retry++ < 10) {
+ "Wakeup sleep send config success.");
+ } else {
+err_retry:
#if GTP_SLIDE_WAKEUP
/* wakeup not by slide */
if (DOZE_WAKEUP != doze_status)
@@ -825,7 +860,7 @@
}
#endif
ret = gtp_i2c_test(ts->client);
- if (ret > 0) {
+ if (ret == 2) {
dev_dbg(&ts->client->dev, "GTP wakeup sleep.");
#if (!GTP_SLIDE_WAKEUP)
if (chip_gt9xxs == 0) {
@@ -839,10 +874,10 @@
return ret;
}
gtp_reset_guitar(ts, 20);
+ if (retry++ < 10)
+ goto err_retry;
+ dev_err(&ts->client->dev, "GTP wakeup sleep failed.\n");
}
-#endif
-
- dev_err(&ts->client->dev, "GTP wakeup sleep failed.\n");
return ret;
}
#endif /* !CONFIG_HAS_EARLYSUSPEND && !CONFIG_FB*/
@@ -1055,9 +1090,7 @@
dev_info(&client->dev, "Goodix Product ID = %s\n", product_id);
- if (!IS_ERR(ts->pdata->product_id))
- ret = strcmp(product_id, ts->pdata->product_id);
-
+ ret = strcmp(product_id, ts->pdata->product_id);
if (ret != 0)
return -EINVAL;
@@ -1103,53 +1136,70 @@
struct i2c_client *client = ts->client;
struct goodix_ts_platform_data *pdata = ts->pdata;
int ret;
+
if (gpio_is_valid(pdata->irq_gpio)) {
ret = gpio_request(pdata->irq_gpio, "goodix_ts_irq_gpio");
if (ret) {
- dev_err(&client->dev, "irq gpio request failed\n");
- goto pwr_off;
+ dev_err(&client->dev, "Unable to request irq gpio [%d]\n",
+ pdata->irq_gpio);
+ goto err_pwr_off;
}
ret = gpio_direction_input(pdata->irq_gpio);
if (ret) {
- dev_err(&client->dev,
- "set_direction for irq gpio failed\n");
- goto free_irq_gpio;
+ dev_err(&client->dev, "Unable to set direction for irq gpio [%d]\n",
+ pdata->irq_gpio);
+ goto err_free_irq_gpio;
}
} else {
- dev_err(&client->dev, "irq gpio is invalid!\n");
+ dev_err(&client->dev, "Invalid irq gpio [%d]!\n",
+ pdata->irq_gpio);
ret = -EINVAL;
- goto free_irq_gpio;
+ goto err_pwr_off;
}
if (gpio_is_valid(pdata->reset_gpio)) {
- ret = gpio_request(pdata->reset_gpio, "goodix_ts__reset_gpio");
+ ret = gpio_request(pdata->reset_gpio, "goodix_ts_reset_gpio");
if (ret) {
- dev_err(&client->dev, "reset gpio request failed\n");
- goto free_irq_gpio;
+ dev_err(&client->dev, "Unable to request reset gpio [%d]\n",
+ pdata->reset_gpio);
+ goto err_free_irq_gpio;
}
ret = gpio_direction_output(pdata->reset_gpio, 0);
if (ret) {
- dev_err(&client->dev,
- "set_direction for reset gpio failed\n");
- goto free_reset_gpio;
+ dev_err(&client->dev, "Unable to set direction for reset gpio [%d]\n",
+ pdata->reset_gpio);
+ goto err_free_reset_gpio;
}
} else {
- dev_err(&client->dev, "reset gpio is invalid!\n");
+ dev_err(&client->dev, "Invalid irq gpio [%d]!\n",
+ pdata->reset_gpio);
ret = -EINVAL;
- goto free_reset_gpio;
+ goto err_free_irq_gpio;
}
- gpio_direction_input(pdata->reset_gpio);
+ /* IRQ GPIO is an input signal, but we are setting it to output
+ * direction and pulling it down, to comply with power up timing
+ * requirements, mentioned in power up timing section of device
+ * datasheet.
+ */
+ ret = gpio_direction_output(pdata->irq_gpio, 0);
+ if (ret)
+ dev_warn(&client->dev,
+ "pull down interrupt gpio failed\n");
+ ret = gpio_direction_output(pdata->reset_gpio, 0);
+ if (ret)
+ dev_warn(&client->dev,
+ "pull down reset gpio failed\n");
return ret;
-free_reset_gpio:
+err_free_reset_gpio:
if (gpio_is_valid(pdata->reset_gpio))
gpio_free(pdata->reset_gpio);
-free_irq_gpio:
+err_free_irq_gpio:
if (gpio_is_valid(pdata->irq_gpio))
gpio_free(pdata->irq_gpio);
-pwr_off:
+err_pwr_off:
return ret;
}
@@ -1167,7 +1217,8 @@
int ret;
const u8 irq_table[] = GTP_IRQ_TAB;
- ret = request_irq(ts->client->irq, goodix_ts_irq_handler,
+ ret = request_threaded_irq(ts->client->irq, NULL,
+ goodix_ts_irq_handler,
irq_table[ts->int_trigger_type],
ts->client->name, ts);
if (ret) {
@@ -1292,6 +1343,12 @@
{
int ret;
+ if (ts->power_on) {
+ dev_info(&ts->client->dev,
+ "Device already power on\n");
+ return 0;
+ }
+
if (!IS_ERR(ts->avdd)) {
ret = reg_set_optimum_mode_check(ts->avdd,
GOODIX_VDD_LOAD_MAX_UA);
@@ -1358,6 +1415,7 @@
}
}
+ ts->power_on = true;
return 0;
err_enable_vcc_i2c:
@@ -1376,6 +1434,7 @@
regulator_disable(ts->avdd);
err_enable_avdd:
err_set_opt_avdd:
+ ts->power_on = false;
return ret;
}
@@ -1389,6 +1448,12 @@
{
int ret;
+ if (!ts->power_on) {
+ dev_info(&ts->client->dev,
+ "Device already power off\n");
+ return 0;
+ }
+
if (!IS_ERR(ts->vcc_i2c)) {
ret = regulator_set_voltage(ts->vcc_i2c, 0,
GOODIX_I2C_VTG_MAX_UV);
@@ -1421,6 +1486,7 @@
"Regulator avdd disable failed ret=%d\n", ret);
}
+ ts->power_on = false;
return 0;
}
@@ -1473,6 +1539,50 @@
return 0;
}
+static ssize_t gtp_fw_name_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct goodix_ts_data *ts = dev_get_drvdata(dev);
+
+ if (!strlen(ts->fw_name))
+ return snprintf(buf, GTP_FW_NAME_MAXSIZE - 1,
+ "No fw name has been given.");
+ else
+ return snprintf(buf, GTP_FW_NAME_MAXSIZE - 1,
+ "%s\n", ts->fw_name);
+}
+
+static ssize_t gtp_fw_name_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct goodix_ts_data *ts = dev_get_drvdata(dev);
+
+ if (size > GTP_FW_NAME_MAXSIZE - 1) {
+ dev_err(dev, "FW name size exceeds the limit.");
+ return -EINVAL;
+ }
+
+ strlcpy(ts->fw_name, buf, size);
+ if (ts->fw_name[size-1] == '\n')
+ ts->fw_name[size-1] = '\0';
+
+ return size;
+}
+
+static DEVICE_ATTR(fw_name, (S_IRUGO | S_IWUSR | S_IWGRP),
+ gtp_fw_name_show,
+ gtp_fw_name_store);
+
+static struct attribute *gtp_attrs[] = {
+ &dev_attr_fw_name.attr,
+ NULL
+};
+
+static const struct attribute_group gtp_attr_grp = {
+ .attrs = gtp_attrs,
+};
+
static int goodix_ts_get_dt_coords(struct device *dev, char *name,
struct goodix_ts_platform_data *pdata)
{
@@ -1536,6 +1646,9 @@
pdata->no_force_update = of_property_read_bool(np,
"goodix,no-force-update");
+
+ pdata->enable_power_off = of_property_read_bool(np,
+ "goodix,enable-power-off");
/* reset, irq gpio info */
pdata->reset_gpio = of_get_named_gpio_flags(np, "reset-gpios",
0, &pdata->reset_gpio_flags);
@@ -1549,8 +1662,17 @@
rc = of_property_read_string(np, "goodix,product-id",
&pdata->product_id);
- if (rc < 0 || strlen(pdata->product_id) > GTP_PRODUCT_ID_MAXSIZE)
- return rc;
+ if (rc && (rc != -EINVAL)) {
+ dev_err(dev, "Failed to parse product_id.");
+ return -EINVAL;
+ }
+
+ rc = of_property_read_string(np, "goodix,fw_name",
+ &pdata->fw_name);
+ if (rc && (rc != -EINVAL)) {
+ dev_err(dev, "Failed to parse firmware name.\n");
+ return -EINVAL;
+ }
prop = of_find_property(np, "goodix,button-map", NULL);
if (prop) {
@@ -1662,11 +1784,18 @@
spin_lock_init(&ts->irq_lock);
i2c_set_clientdata(client, ts);
ts->gtp_rawdiff_mode = 0;
+ ts->power_on = false;
+
+ ret = gtp_request_io_port(ts);
+ if (ret) {
+ dev_err(&client->dev, "GTP request IO port failed.\n");
+ goto exit_free_client_data;
+ }
ret = goodix_power_init(ts);
if (ret) {
dev_err(&client->dev, "GTP power init failed\n");
- goto exit_free_client_data;
+ goto exit_free_io_port;
}
ret = goodix_power_on(ts);
@@ -1675,26 +1804,24 @@
goto exit_deinit_power;
}
- ret = gtp_request_io_port(ts);
- if (ret) {
- dev_err(&client->dev, "GTP request IO port failed.\n");
- goto exit_power_off;
- }
-
gtp_reset_guitar(ts, 20);
ret = gtp_i2c_test(client);
if (ret != 2) {
dev_err(&client->dev, "I2C communication ERROR!\n");
- goto exit_free_io_port;
+ goto exit_power_off;
}
+ if (pdata->fw_name)
+ strlcpy(ts->fw_name, pdata->fw_name,
+ strlen(pdata->fw_name) + 1);
+
#if GTP_AUTO_UPDATE
ret = gup_init_update_proc(ts);
if (ret < 0) {
dev_err(&client->dev,
"GTP Create firmware update thread error.\n");
- goto exit_free_io_port;
+ goto exit_power_off;
}
#endif
@@ -1711,7 +1838,9 @@
dev_err(&client->dev, "GTP request input dev failed.\n");
goto exit_free_inputdev;
}
+ input_set_drvdata(ts->input_dev, ts);
+ mutex_init(&ts->lock);
#if defined(CONFIG_FB)
ts->fb_notif.notifier_call = fb_notifier_callback;
ret = fb_register_client(&ts->fb_notif);
@@ -1754,9 +1883,16 @@
#if GTP_ESD_PROTECT
gtp_esd_switch(client, SWITCH_ON);
#endif
+ ret = sysfs_create_group(&client->dev.kobj, >p_attr_grp);
+ if (ret < 0) {
+ dev_err(&client->dev, "sys file creation failed.\n");
+ goto exit_free_irq;
+ }
+
init_done = true;
return 0;
exit_free_irq:
+ mutex_destroy(&ts->lock);
#if defined(CONFIG_FB)
if (fb_unregister_client(&ts->fb_notif))
dev_err(&client->dev,
@@ -1779,15 +1915,15 @@
}
exit_free_inputdev:
kfree(ts->config_data);
+exit_power_off:
+ goodix_power_off(ts);
+exit_deinit_power:
+ goodix_power_deinit(ts);
exit_free_io_port:
if (gpio_is_valid(pdata->reset_gpio))
gpio_free(pdata->reset_gpio);
if (gpio_is_valid(pdata->irq_gpio))
gpio_free(pdata->irq_gpio);
-exit_power_off:
- goodix_power_off(ts);
-exit_deinit_power:
- goodix_power_deinit(ts);
exit_free_client_data:
i2c_set_clientdata(client, NULL);
kfree(ts);
@@ -1806,6 +1942,8 @@
{
struct goodix_ts_data *ts = i2c_get_clientdata(client);
+ sysfs_remove_group(&ts->input_dev->dev.kobj, >p_attr_grp);
+
#if defined(CONFIG_FB)
if (fb_unregister_client(&ts->fb_notif))
dev_err(&client->dev,
@@ -1813,6 +1951,7 @@
#elif defined(CONFIG_HAS_EARLYSUSPEND)
unregister_early_suspend(&ts->early_suspend);
#endif
+ mutex_destroy(&ts->lock);
#if GTP_CREATE_WR_NODE
uninit_wr_node();
@@ -1864,10 +2003,12 @@
Output:
None.
*******************************************************/
-static void goodix_ts_suspend(struct goodix_ts_data *ts)
+static int goodix_ts_suspend(struct device *dev)
{
- int ret = -1, i;
+ struct goodix_ts_data *ts = dev_get_drvdata(dev);
+ int ret = 0, i;
+ mutex_lock(&ts->lock);
#if GTP_ESD_PROTECT
ts->gtp_is_suspend = 1;
gtp_esd_switch(ts->client, SWITCH_OFF);
@@ -1894,6 +2035,9 @@
* delay 48 + 10ms to ensure reliability
*/
msleep(58);
+ mutex_unlock(&ts->lock);
+
+ return ret;
}
/*******************************************************
@@ -1904,17 +2048,19 @@
Output:
None.
*******************************************************/
-static void goodix_ts_resume(struct goodix_ts_data *ts)
+static int goodix_ts_resume(struct device *dev)
{
- int ret = -1;
+ struct goodix_ts_data *ts = dev_get_drvdata(dev);
+ int ret = 0;
+ mutex_lock(&ts->lock);
ret = gtp_wakeup_sleep(ts);
#if GTP_SLIDE_WAKEUP
doze_status = DOZE_DISABLED;
#endif
- if (ret < 0)
+ if (ret <= 0)
dev_err(&ts->client->dev, "GTP resume failed.\n");
if (ts->use_irq)
@@ -1927,6 +2073,9 @@
ts->gtp_is_suspend = 0;
gtp_esd_switch(ts->client, SWITCH_ON);
#endif
+ mutex_unlock(&ts->lock);
+
+ return ret;
}
#if defined(CONFIG_FB)
@@ -1942,9 +2091,9 @@
ts && ts->client) {
blank = evdata->data;
if (*blank == FB_BLANK_UNBLANK)
- goodix_ts_resume(ts);
+ goodix_ts_resume(&ts->client->dev);
else if (*blank == FB_BLANK_POWERDOWN)
- goodix_ts_suspend(ts);
+ goodix_ts_suspend(&ts->client->dev);
}
return 0;
@@ -1963,7 +2112,7 @@
struct goodix_ts_data *ts;
ts = container_of(h, struct goodix_ts_data, early_suspend);
- goodix_ts_suspend(ts);
+ goodix_ts_suspend(&ts->client->dev);
return;
}
@@ -2117,6 +2266,16 @@
}
#endif
+#if (!defined(CONFIG_FB) && !defined(CONFIG_HAS_EARLYSUSPEND))
+static const struct dev_pm_ops goodix_ts_dev_pm_ops = {
+ .suspend = goodix_ts_suspend,
+ .resume = goodix_ts_resume,
+};
+#else
+static const struct dev_pm_ops goodix_ts_dev_pm_ops = {
+};
+#endif
+
static const struct i2c_device_id goodix_ts_id[] = {
{ GTP_I2C_NAME, 0 },
{ }
@@ -2139,6 +2298,9 @@
.name = GTP_I2C_NAME,
.owner = THIS_MODULE,
.of_match_table = goodix_match_table,
+#if CONFIG_PM
+ .pm = &goodix_ts_dev_pm_ops,
+#endif
},
};
@@ -2175,7 +2337,7 @@
i2c_del_driver(&goodix_ts_driver);
}
-late_initcall(goodix_ts_init);
+module_init(goodix_ts_init);
module_exit(goodix_ts_exit);
MODULE_DESCRIPTION("GTP Series Driver");
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx.h b/drivers/input/touchscreen/gt9xx/gt9xx.h
index 1fdbfa3..1d31f2a 100644
--- a/drivers/input/touchscreen/gt9xx/gt9xx.h
+++ b/drivers/input/touchscreen/gt9xx/gt9xx.h
@@ -36,6 +36,7 @@
#include <linux/regulator/consumer.h>
#include <linux/firmware.h>
#include <linux/debugfs.h>
+#include <linux/mutex.h>
#if defined(CONFIG_FB)
#include <linux/notifier.h>
@@ -46,12 +47,15 @@
#endif
#define GOODIX_MAX_CFG_GROUP 6
+#define GTP_FW_NAME_MAXSIZE 50
+
struct goodix_ts_platform_data {
int irq_gpio;
u32 irq_gpio_flags;
int reset_gpio;
u32 reset_gpio_flags;
const char *product_id;
+ const char *fw_name;
u32 x_max;
u32 y_max;
u32 x_min;
@@ -62,6 +66,7 @@
u32 panel_maxy;
bool no_force_update;
bool i2c_pull_up;
+ bool enable_power_off;
size_t config_data_len[GOODIX_MAX_CFG_GROUP];
u8 *config_data[GOODIX_MAX_CFG_GROUP];
};
@@ -73,6 +78,7 @@
struct hrtimer timer;
struct workqueue_struct *goodix_wq;
struct work_struct work;
+ char fw_name[GTP_FW_NAME_MAXSIZE];
s32 irq_is_disabled;
s32 use_irq;
u16 abs_x_max;
@@ -89,6 +95,8 @@
u8 fixed_cfg;
u8 esd_running;
u8 fw_error;
+ bool power_on;
+ struct mutex lock;
struct regulator *avdd;
struct regulator *vdd;
struct regulator *vcc_i2c;
@@ -107,7 +115,6 @@
#define GTP_CHANGE_X2Y 0
#define GTP_DRIVER_SEND_CFG 1
#define GTP_HAVE_TOUCH_KEY 1
-#define GTP_POWER_CTRL_SLEEP 0
/* auto updated by .bin file as default */
#define GTP_AUTO_UPDATE 0
@@ -119,6 +126,7 @@
#define GTP_ESD_PROTECT 0
#define GTP_WITH_PEN 0
+/* This cannot work when enable-power-off is on */
#define GTP_SLIDE_WAKEUP 0
/* double-click wakeup, function together with GTP_SLIDE_WAKEUP */
#define GTP_DBL_CLK_WAKEUP 0
diff --git a/drivers/input/touchscreen/synaptics_fw_update.c b/drivers/input/touchscreen/synaptics_fw_update.c
index 70c1307..7da0376 100644
--- a/drivers/input/touchscreen/synaptics_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_fw_update.c
@@ -352,8 +352,7 @@
(data->options_firmware_id == (1 << OPTION_BUILD_INFO));
if (img->is_contain_build_info) {
- img->firmware_id = extract_uint(data->firmware_id);
- img->package_id = (data->pkg_id_rev_msb << 8) |
+ img->package_id = (data->pkg_id_msb << 8) |
data->pkg_id_lsb;
img->package_revision_id = (data->pkg_id_rev_msb << 8) |
data->pkg_id_rev_lsb;
@@ -2054,26 +2053,26 @@
__ATTR(fw_name, S_IRUGO | S_IWUSR | S_IWGRP,
fwu_sysfs_image_name_show,
fwu_sysfs_image_name_store),
- __ATTR(force_update_fw, S_IRUGO | S_IWUSR | S_IWGRP,
- synaptics_rmi4_show_error,
+ __ATTR(force_update_fw, S_IWUSR | S_IWGRP,
+ NULL,
fwu_sysfs_force_reflash_store),
- __ATTR(update_fw, S_IRUGO | S_IWUSR | S_IWGRP,
- synaptics_rmi4_show_error,
+ __ATTR(update_fw, S_IWUSR | S_IWGRP,
+ NULL,
fwu_sysfs_do_reflash_store),
- __ATTR(writeconfig, S_IRUGO | S_IWUSR | S_IWGRP,
- synaptics_rmi4_show_error,
+ __ATTR(writeconfig, S_IWUSR | S_IWGRP,
+ NULL,
fwu_sysfs_write_config_store),
- __ATTR(writelockdown, S_IRUGO | S_IWUSR | S_IWGRP,
- synaptics_rmi4_show_error,
+ __ATTR(writelockdown, S_IWUSR | S_IWGRP,
+ NULL,
fwu_sysfs_write_lockdown_store),
- __ATTR(readconfig, S_IRUGO | S_IWUSR | S_IWGRP,
- synaptics_rmi4_show_error,
+ __ATTR(readconfig, S_IWUSR | S_IWGRP,
+ NULL,
fwu_sysfs_read_config_store),
- __ATTR(configarea, S_IRUGO | S_IWUSR | S_IWGRP,
- synaptics_rmi4_show_error,
+ __ATTR(configarea, S_IWUSR | S_IWGRP,
+ NULL,
fwu_sysfs_config_area_store),
- __ATTR(imagesize, S_IRUGO | S_IWUSR | S_IWGRP,
- synaptics_rmi4_show_error,
+ __ATTR(imagesize, S_IWUSR | S_IWGRP,
+ NULL,
fwu_sysfs_image_size_store),
__ATTR(blocksize, S_IRUGO,
fwu_sysfs_block_size_show,
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
index d21b6c1..7152ec8 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.c
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
@@ -67,10 +67,10 @@
#define F11_STD_CTRL_LEN 10
#define F11_STD_DATA_LEN 12
-#define NORMAL_OPERATION (0 << 0)
-#define SENSOR_SLEEP (1 << 0)
-#define NO_SLEEP_OFF (0 << 2)
-#define NO_SLEEP_ON (1 << 2)
+#define NORMAL_OPERATION 0
+#define SENSOR_SLEEP 1
+#define NO_SLEEP_OFF 0
+#define NO_SLEEP_ON 1
enum device_status {
STATUS_NO_ERROR = 0x00,
@@ -111,6 +111,13 @@
static int synaptics_rmi4_reset_device(struct synaptics_rmi4_data *rmi4_data);
+static void synaptics_rmi4_sensor_wake(struct synaptics_rmi4_data *rmi4_data);
+
+static void synaptics_rmi4_sensor_sleep(struct synaptics_rmi4_data *rmi4_data);
+
+static int synaptics_rmi4_check_configuration(struct synaptics_rmi4_data
+ *rmi4_data);
+
#ifdef CONFIG_PM
static int synaptics_rmi4_suspend(struct device *dev);
@@ -392,8 +399,8 @@
synaptics_rmi4_full_pm_cycle_show,
synaptics_rmi4_full_pm_cycle_store),
#endif
- __ATTR(reset, S_IRUGO | S_IWUSR | S_IWGRP,
- synaptics_rmi4_show_error,
+ __ATTR(reset, S_IWUSR | S_IWGRP,
+ NULL,
synaptics_rmi4_f01_reset_store),
__ATTR(productinfo, S_IRUGO,
synaptics_rmi4_f01_productinfo_show,
@@ -600,6 +607,7 @@
if (rmi4_data->button_0d_enabled == input)
return count;
+ mutex_lock(&rmi->support_fn_list_mutex);
if (!list_empty(&rmi->support_fn_list)) {
list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
if (fhandler->fn_number == SYNAPTICS_RMI4_F1A) {
@@ -611,7 +619,7 @@
&intr_enable,
sizeof(intr_enable));
if (retval < 0)
- return retval;
+ goto exit;
if (input == 1)
intr_enable |= fhandler->intr_mask;
@@ -624,14 +632,17 @@
&intr_enable,
sizeof(intr_enable));
if (retval < 0)
- return retval;
+ goto exit;
}
}
}
-
+ mutex_unlock(&rmi->support_fn_list_mutex);
rmi4_data->button_0d_enabled = input;
return count;
+exit:
+ mutex_unlock(&rmi->support_fn_list_mutex);
+ return retval;
}
static ssize_t synaptics_rmi4_flipx_show(struct device *dev,
@@ -1306,6 +1317,7 @@
* Traverse the function handler list and service the source(s)
* of the interrupt accordingly.
*/
+ mutex_lock(&rmi->support_fn_list_mutex);
if (!list_empty(&rmi->support_fn_list)) {
list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
if (fhandler->num_of_data_sources) {
@@ -1317,6 +1329,7 @@
}
}
}
+ mutex_unlock(&rmi->support_fn_list_mutex);
mutex_lock(&exp_fn_list_mutex);
if (!list_empty(&exp_fn_list)) {
@@ -2051,6 +2064,32 @@
return 0;
}
+/*
+* This function checks whether the fhandler already existis in the
+* support_fn_list or not.
+* If it exists then return 1 as found or return 0 as not found.
+*
+* Called by synaptics_rmi4_query_device().
+*/
+static int synaptics_rmi4_check_fn_list(struct synaptics_rmi4_data *rmi4_data,
+ struct synaptics_rmi4_fn *fhandler)
+{
+ int found = 0;
+ struct synaptics_rmi4_fn *new_fhandler;
+ struct synaptics_rmi4_device_info *rmi;
+
+ rmi = &(rmi4_data->rmi4_mod_info);
+
+ mutex_lock(&rmi->support_fn_list_mutex);
+ if (!list_empty(&rmi->support_fn_list))
+ list_for_each_entry(new_fhandler, &rmi->support_fn_list, link)
+ if (new_fhandler->fn_number == fhandler->fn_number)
+ found = 1;
+ mutex_unlock(&rmi->support_fn_list_mutex);
+
+ return found;
+}
+
/**
* synaptics_rmi4_query_device()
*
@@ -2066,7 +2105,7 @@
*/
static int synaptics_rmi4_query_device(struct synaptics_rmi4_data *rmi4_data)
{
- int retval;
+ int retval, found;
unsigned char ii;
unsigned char page_number;
unsigned char intr_count = 0;
@@ -2080,8 +2119,6 @@
rmi = &(rmi4_data->rmi4_mod_info);
- INIT_LIST_HEAD(&rmi->support_fn_list);
-
/* Scan the page description tables of the pages to service */
for (page_number = 0; page_number < PAGES_TO_SERVICE; page_number++) {
for (pdt_entry_addr = PDT_START; pdt_entry_addr > PDT_END;
@@ -2096,7 +2133,7 @@
return retval;
fhandler = NULL;
-
+ found = 0;
if (rmi_fd.fn_number == 0) {
dev_dbg(&rmi4_data->i2c_client->dev,
"%s: Reached end of PDT\n",
@@ -2215,8 +2252,31 @@
intr_count += (rmi_fd.intr_src_count & MASK_3BIT);
if (fhandler && rmi_fd.intr_src_count) {
- list_add_tail(&fhandler->link,
- &rmi->support_fn_list);
+ /* Want to check whether the fhandler already
+ exists in the support_fn_list or not.
+ If not found then add it to the list, otherwise
+ free the memory allocated to it.
+ */
+ found = synaptics_rmi4_check_fn_list(rmi4_data,
+ fhandler);
+
+ if (!found) {
+ mutex_lock(&rmi->support_fn_list_mutex);
+ list_add_tail(&fhandler->link,
+ &rmi->support_fn_list);
+ mutex_unlock(
+ &rmi->support_fn_list_mutex);
+ } else {
+ if (fhandler->fn_number ==
+ SYNAPTICS_RMI4_F1A) {
+ synaptics_rmi4_f1a_kfree(
+ fhandler);
+ } else {
+ kfree(fhandler->data);
+ kfree(fhandler->extra);
+ }
+ kfree(fhandler);
+ }
}
}
}
@@ -2233,20 +2293,25 @@
* Map out the interrupt bit masks for the interrupt sources
* from the registered function handlers.
*/
+ mutex_lock(&rmi->support_fn_list_mutex);
if (!list_empty(&rmi->support_fn_list)) {
list_for_each_entry(fhandler, &rmi->support_fn_list, link)
data_sources += fhandler->num_of_data_sources;
}
+ mutex_unlock(&rmi->support_fn_list_mutex);
+
if (data_sources) {
+ mutex_lock(&rmi->support_fn_list_mutex);
if (!list_empty(&rmi->support_fn_list)) {
list_for_each_entry(fhandler,
&rmi->support_fn_list, link) {
if (fhandler->num_of_data_sources) {
rmi4_data->intr_mask[fhandler->intr_reg_num] |=
- fhandler->intr_mask;
+ fhandler->intr_mask;
}
}
}
+ mutex_unlock(&rmi->support_fn_list_mutex);
}
/* Enable the interrupt sources */
@@ -2359,6 +2424,8 @@
}
}
+ INIT_LIST_HEAD(&rmi->support_fn_list);
+
retval = synaptics_rmi4_query_device(rmi4_data);
if (retval < 0) {
dev_err(&rmi4_data->i2c_client->dev,
@@ -2851,6 +2918,9 @@
init_waitqueue_head(&rmi4_data->wait);
mutex_init(&(rmi4_data->rmi4_io_ctrl_mutex));
+ INIT_LIST_HEAD(&rmi->support_fn_list);
+ mutex_init(&rmi->support_fn_list_mutex);
+
retval = synaptics_rmi4_query_device(rmi4_data);
if (retval < 0) {
dev_err(&client->dev,
@@ -2904,12 +2974,14 @@
i2c_set_clientdata(client, rmi4_data);
f1a = NULL;
+ mutex_lock(&rmi->support_fn_list_mutex);
if (!list_empty(&rmi->support_fn_list)) {
list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
if (fhandler->fn_number == SYNAPTICS_RMI4_F1A)
f1a = fhandler->data;
}
}
+ mutex_unlock(&rmi->support_fn_list_mutex);
if (f1a) {
for (ii = 0; ii < f1a->valid_button_count; ii++) {
@@ -2987,6 +3059,9 @@
goto err_sysfs;
}
}
+
+ synaptics_rmi4_sensor_wake(rmi4_data);
+
retval = synaptics_rmi4_irq_enable(rmi4_data, true);
if (retval < 0) {
dev_err(&client->dev,
@@ -2995,6 +3070,12 @@
goto err_sysfs;
}
+ retval = synaptics_rmi4_check_configuration(rmi4_data);
+ if (retval < 0) {
+ dev_err(&client->dev, "Failed to check configuration\n");
+ return retval;
+ }
+
return retval;
err_sysfs:
@@ -3013,6 +3094,7 @@
input_unregister_device(rmi4_data->input_dev);
err_register_input:
+ mutex_lock(&rmi->support_fn_list_mutex);
if (!list_empty(&rmi->support_fn_list)) {
list_for_each_entry_safe(fhandler, next_fhandler,
&rmi->support_fn_list, link) {
@@ -3025,6 +3107,7 @@
kfree(fhandler);
}
}
+ mutex_unlock(&rmi->support_fn_list_mutex);
err_free_gpios:
if (gpio_is_valid(rmi4_data->board->reset_gpio))
gpio_free(rmi4_data->board->reset_gpio);
@@ -3080,6 +3163,7 @@
input_unregister_device(rmi4_data->input_dev);
+ mutex_lock(&rmi->support_fn_list_mutex);
if (!list_empty(&rmi->support_fn_list)) {
list_for_each_entry_safe(fhandler, next_fhandler,
&rmi->support_fn_list, link) {
@@ -3092,6 +3176,7 @@
kfree(fhandler);
}
}
+ mutex_unlock(&rmi->support_fn_list_mutex);
if (gpio_is_valid(rmi4_data->board->reset_gpio))
gpio_free(rmi4_data->board->reset_gpio);
@@ -3175,6 +3260,12 @@
return;
}
+ if (device_ctrl.nosleep == NO_SLEEP_OFF &&
+ device_ctrl.sleep_mode == NORMAL_OPERATION) {
+ rmi4_data->sensor_sleep = false;
+ return;
+ }
+
device_ctrl.sleep_mode = NORMAL_OPERATION;
device_ctrl.nosleep = NO_SLEEP_OFF;
@@ -3558,6 +3649,22 @@
static const struct dev_pm_ops synaptics_rmi4_dev_pm_ops = {
};
#endif
+#else
+static void synaptics_rmi4_sensor_wake(struct synaptics_rmi4_data *rmi4_data)
+{
+ return;
+};
+
+static void synaptics_rmi4_sensor_sleep(struct synaptics_rmi4_data *rmi4_data)
+{
+ return;
+};
+
+static int synaptics_rmi4_check_configuration(struct synaptics_rmi4_data
+ *rmi4_data)
+{
+ return 0;
+};
#endif
static const struct i2c_device_id synaptics_rmi4_id_table[] = {
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.h b/drivers/input/touchscreen/synaptics_i2c_rmi4.h
index ef39bb7..df227fb 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.h
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.h
@@ -161,6 +161,7 @@
unsigned char product_id_string[SYNAPTICS_RMI4_PRODUCT_ID_SIZE + 1];
unsigned char build_id[SYNAPTICS_RMI4_BUILD_ID_SIZE];
unsigned char config_id[3];
+ struct mutex support_fn_list_mutex;
struct list_head support_fn_list;
};
@@ -286,14 +287,6 @@
void (*func_attn)(struct synaptics_rmi4_data *rmi4_data,
unsigned char intr_mask));
-static inline ssize_t synaptics_rmi4_show_error(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- dev_warn(dev, "%s Attempted to read from write-only attribute %s\n",
- __func__, attr->attr.name);
- return -EPERM;
-}
-
static inline ssize_t synaptics_rmi4_store_error(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
diff --git a/drivers/input/touchscreen/synaptics_rmi_dev.c b/drivers/input/touchscreen/synaptics_rmi_dev.c
index c60ca23..7abd909 100644
--- a/drivers/input/touchscreen/synaptics_rmi_dev.c
+++ b/drivers/input/touchscreen/synaptics_rmi_dev.c
@@ -73,19 +73,19 @@
};
static struct device_attribute attrs[] = {
- __ATTR(open, S_IRUGO | S_IWUSR | S_IWGRP,
- synaptics_rmi4_show_error,
+ __ATTR(open, S_IWUSR | S_IWGRP,
+ NULL,
rmidev_sysfs_open_store),
- __ATTR(release, S_IRUGO | S_IWUSR | S_IWGRP,
- synaptics_rmi4_show_error,
+ __ATTR(release, S_IWUSR | S_IWGRP,
+ NULL,
rmidev_sysfs_release_store),
- __ATTR(address, S_IRUGO | S_IWUSR | S_IWGRP,
- synaptics_rmi4_show_error,
+ __ATTR(address, S_IWUSR | S_IWGRP,
+ NULL,
rmidev_sysfs_address_store),
- __ATTR(length, S_IRUGO | S_IWUSR | S_IWGRP,
- synaptics_rmi4_show_error,
+ __ATTR(length, S_IWUSR | S_IWGRP,
+ NULL,
rmidev_sysfs_length_store),
- __ATTR(data, (S_IRUGO | S_IWUSR | S_IWGRP),
+ __ATTR(data, (S_IWUSR | S_IWGRP),
rmidev_sysfs_data_show,
rmidev_sysfs_data_store),
};
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index 8ae5671..da90440 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -255,7 +255,7 @@
WLED_OVP_35V,
WLED_OVP_32V,
WLED_OVP_29V,
- WLED_OVP_37V,
+ WLED_OVP_27V,
};
enum flash_headroom {
@@ -713,7 +713,7 @@
duty_us = (led->mpp_cfg->pwm_cfg->pwm_period_us *
led->cdev.brightness) / LED_FULL;
/*config pwm for brightness scaling*/
- rc = pwm_config(led->mpp_cfg->pwm_cfg->pwm_dev,
+ rc = pwm_config_us(led->mpp_cfg->pwm_cfg->pwm_dev,
duty_us,
led->mpp_cfg->pwm_cfg->pwm_period_us);
if (rc < 0) {
@@ -1239,7 +1239,7 @@
if (led->kpdbl_cfg->pwm_cfg->mode == PWM_MODE) {
duty_us = (led->kpdbl_cfg->pwm_cfg->pwm_period_us *
led->cdev.brightness) / KPDBL_MAX_LEVEL;
- rc = pwm_config(led->kpdbl_cfg->pwm_cfg->pwm_dev,
+ rc = pwm_config_us(led->kpdbl_cfg->pwm_cfg->pwm_dev,
duty_us,
led->kpdbl_cfg->pwm_cfg->pwm_period_us);
if (rc < 0) {
@@ -1261,7 +1261,7 @@
led->kpdbl_cfg->pwm_cfg->default_mode;
if (led->kpdbl_cfg->always_on) {
- rc = pwm_config(led->kpdbl_cfg->pwm_cfg->pwm_dev, 0,
+ rc = pwm_config_us(led->kpdbl_cfg->pwm_cfg->pwm_dev, 0,
led->kpdbl_cfg->pwm_cfg->pwm_period_us);
if (rc < 0) {
dev_err(&led->spmi_dev->dev,
@@ -1310,7 +1310,8 @@
if (led->rgb_cfg->pwm_cfg->mode == PWM_MODE) {
duty_us = (led->rgb_cfg->pwm_cfg->pwm_period_us *
led->cdev.brightness) / LED_FULL;
- rc = pwm_config(led->rgb_cfg->pwm_cfg->pwm_dev, duty_us,
+ rc = pwm_config_us(led->rgb_cfg->pwm_cfg->pwm_dev,
+ duty_us,
led->rgb_cfg->pwm_cfg->pwm_period_us);
if (rc < 0) {
dev_err(&led->spmi_dev->dev,
@@ -1495,7 +1496,7 @@
num_wled_strings = led->wled_cfg->num_strings;
/* verify ranges */
- if (led->wled_cfg->ovp_val > WLED_OVP_37V) {
+ if (led->wled_cfg->ovp_val > WLED_OVP_27V) {
dev_err(&led->spmi_dev->dev, "Invalid ovp value\n");
return -EINVAL;
}
@@ -2761,7 +2762,7 @@
rc = of_property_read_u32(node, "qcom,duration", &val);
if (!rc)
- led->flash_cfg->duration = (((u8) val) - 10) / 10;
+ led->flash_cfg->duration = (u8)((val - 10) / 10);
else if (rc == -EINVAL)
led->flash_cfg->duration = FLASH_DURATION_200ms;
else
@@ -3439,10 +3440,15 @@
return 0;
}
+
+#ifdef CONFIG_OF
static struct of_device_id spmi_match_table[] = {
- { .compatible = "qcom,leds-qpnp",
- }
+ { .compatible = "qcom,leds-qpnp",},
+ { },
};
+#else
+#define spmi_match_table NULL
+#endif
static struct spmi_driver qpnp_leds_driver = {
.driver = {
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index a1cac54..937fb8c 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -899,7 +899,9 @@
} else {
int i;
+ spin_lock(&dmxdev->dvr_in_lock);
dmxdev->dvr_in_exit = 1;
+ spin_unlock(&dmxdev->dvr_in_lock);
wake_up_all(&dmxdev->dvr_cmd_buffer.queue);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
index 2be1f01..a85f853 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
@@ -122,6 +122,8 @@
{
int i, rc = -1;
struct msm_isp_buffer_mapped_info *mapped_info;
+ struct buffer_cmd *buf_pending = NULL;
+
for (i = 0; i < v4l2_buf->length; i++) {
mapped_info = &buf_info->mapped_info[i];
mapped_info->handle =
@@ -144,6 +146,15 @@
mapped_info->paddr += v4l2_buf->m.planes[i].data_offset;
CDBG("%s: plane: %d addr:%lu\n",
__func__, i, mapped_info->paddr);
+
+ buf_pending = kzalloc(sizeof(struct buffer_cmd), GFP_ATOMIC);
+ if (!buf_pending) {
+ pr_err("No free memory for buf_pending\n");
+ return rc;
+ }
+
+ buf_pending->mapped_info = mapped_info;
+ list_add_tail(&buf_pending->list, &buf_mgr->buffer_q);
}
buf_info->num_planes = v4l2_buf->length;
return 0;
@@ -163,11 +174,26 @@
{
int i;
struct msm_isp_buffer_mapped_info *mapped_info;
+ struct buffer_cmd *buf_pending = NULL;
+
for (i = 0; i < buf_info->num_planes; i++) {
mapped_info = &buf_info->mapped_info[i];
- ion_unmap_iommu(buf_mgr->client, mapped_info->handle,
- buf_mgr->iommu_domain_num, 0);
- ion_free(buf_mgr->client, mapped_info->handle);
+
+ list_for_each_entry(buf_pending, &buf_mgr->buffer_q, list) {
+ if (!buf_pending)
+ break;
+
+ if (buf_pending->mapped_info == mapped_info) {
+ ion_unmap_iommu(buf_mgr->client,
+ mapped_info->handle,
+ buf_mgr->iommu_domain_num, 0);
+ ion_free(buf_mgr->client, mapped_info->handle);
+
+ list_del_init(&buf_pending->list);
+ kfree(buf_pending);
+ break;
+ }
+ }
}
return;
}
@@ -348,11 +374,14 @@
if (bufq->buf_type == ISP_SHARE_BUF) {
temp_buf_info = kzalloc(
sizeof(struct msm_isp_buffer), GFP_ATOMIC);
- temp_buf_info->buf_reuse_flag = 1;
- temp_buf_info->buf_used[id] = 1;
- temp_buf_info->buf_get_count = 1;
- list_add_tail(&temp_buf_info->share_list,
- &bufq->share_head);
+ if (temp_buf_info) {
+ temp_buf_info->buf_reuse_flag = 1;
+ temp_buf_info->buf_used[id] = 1;
+ temp_buf_info->buf_get_count = 1;
+ list_add_tail(&temp_buf_info->share_list,
+ &bufq->share_head);
+ } else
+ rc = -ENOMEM;
}
} else {
(*buf_info)->state = MSM_ISP_BUFFER_STATE_DEQUEUED;
@@ -586,7 +615,7 @@
}
} else {
bufq = msm_isp_get_bufq(buf_mgr, info->handle);
- if (BUF_SRC(bufq->stream_id)) {
+ if (bufq && BUF_SRC(bufq->stream_id)) {
rc = msm_isp_put_buf(buf_mgr,
info->handle, info->buf_idx);
if (rc < 0) {
@@ -691,6 +720,7 @@
if (!bufq->bufq_handle)
continue;
msm_isp_buf_unprepare(buf_mgr, bufq->bufq_handle);
+
kfree(bufq->bufs);
msm_isp_free_buf_handle(buf_mgr, bufq->bufq_handle);
}
@@ -739,9 +769,10 @@
pr_err("Invalid buffer queue number\n");
return rc;
}
-
CDBG("%s: E\n", __func__);
+
msm_isp_attach_ctx(buf_mgr);
+ INIT_LIST_HEAD(&buf_mgr->buffer_q);
buf_mgr->num_buf_q = num_buf_q;
buf_mgr->bufq =
kzalloc(sizeof(struct msm_isp_bufq) * num_buf_q,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h
index 6d6ff9d..d8d3ba2 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h
@@ -44,6 +44,11 @@
struct ion_handle *handle;
};
+struct buffer_cmd {
+ struct list_head list;
+ struct msm_isp_buffer_mapped_info *mapped_info;
+};
+
struct msm_isp_buffer {
/*Common Data structure*/
int num_planes;
@@ -138,6 +143,7 @@
int num_iommu_ctx;
struct device *iommu_ctx[2];
+ struct list_head buffer_q;
};
int msm_isp_create_isp_buf_mgr(struct msm_isp_buf_mgr *buf_mgr,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
index 2c5e136..80a0073 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
@@ -140,6 +140,7 @@
&vfe_vb2_ops, &vfe_layout);
if (rc < 0) {
pr_err("%s: Unable to create buffer manager\n", __func__);
+ msm_sd_unregister(&vfe_dev->subdev);
kfree(vfe_dev);
return -EINVAL;
}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
index 87bffde..9dd0085 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -106,7 +106,7 @@
uint32_t reload_mask);
void (*enable_wm) (struct vfe_device *vfe_dev,
uint8_t wm_idx, uint8_t enable);
- void (*cfg_io_format) (struct vfe_device *vfe_dev,
+ int32_t (*cfg_io_format) (struct vfe_device *vfe_dev,
enum msm_vfe_axi_stream_src stream_src,
uint32_t io_format);
void (*cfg_framedrop) (struct vfe_device *vfe_dev,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
index a8da26d..410fe8f 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -74,6 +74,8 @@
goto fs_failed;
}
}
+ else
+ goto fs_failed;
rc = msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe32_1_clk_info,
vfe_dev->vfe_clk, ARRAY_SIZE(msm_vfe32_1_clk_info), 1);
@@ -495,12 +497,17 @@
}
}
-static void msm_vfe32_cfg_io_format(struct vfe_device *vfe_dev,
+static int32_t msm_vfe32_cfg_io_format(struct vfe_device *vfe_dev,
enum msm_vfe_axi_stream_src stream_src, uint32_t io_format)
{
int bpp, bpp_reg = 0, pack_fmt = 0, pack_reg = 0;
uint32_t io_format_reg;
bpp = msm_isp_get_bit_per_pixel(io_format);
+ if (bpp < 0) {
+ pr_err("%s:%d invalid io_format %d bpp %d", __func__, __LINE__,
+ io_format, bpp);
+ return -EINVAL;
+ }
switch (bpp) {
case 8:
@@ -512,6 +519,9 @@
case 12:
bpp_reg = 1 << 1;
break;
+ default:
+ pr_err("%s:%d invalid bpp %d", __func__, __LINE__, bpp);
+ return -EINVAL;
}
if (stream_src == IDEAL_RAW) {
@@ -537,7 +547,7 @@
break;
default:
pr_err("%s: invalid pack fmt!\n", __func__);
- return;
+ return -EINVAL;
}
}
@@ -558,9 +568,10 @@
case RDI_INTF_2:
default:
pr_err("%s: Invalid stream source\n", __func__);
- return;
+ return -EINVAL;
}
msm_camera_io_w(io_format_reg, vfe_dev->vfe_base + 0x6F8);
+ return 0;
}
static void msm_vfe32_cfg_camif(struct vfe_device *vfe_dev,
@@ -620,7 +631,10 @@
msm_camera_io_w_mb(0x0, vfe_dev->vfe_base + 0x1E0);
vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0;
} else if (update_state == DISABLE_CAMIF_IMMEDIATELY) {
- msm_camera_io_w_mb(0x2, vfe_dev->vfe_base + 0x1E0);
+ msm_camera_io_w_mb(0x6, vfe_dev->vfe_base + 0x1E0);
+ vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev);
+ vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev);
+ vfe_dev->hw_info->vfe_ops.core_ops.init_hw_reg(vfe_dev);
vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0;
}
}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index 9047c40..8c7890d 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -268,6 +268,8 @@
goto fs_failed;
}
}
+ else
+ goto fs_failed;
rc = msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe40_clk_info,
vfe_dev->vfe_clk, ARRAY_SIZE(msm_vfe40_clk_info), 1);
@@ -459,54 +461,62 @@
{
uint32_t error_status1 = vfe_dev->error_info.error_mask1;
if (error_status1 & (1 << 0))
- pr_err("%s: camif error status: 0x%x\n",
+ pr_err_ratelimited("%s: camif error status: 0x%x\n",
__func__, vfe_dev->error_info.camif_status);
if (error_status1 & (1 << 1))
- pr_err("%s: stats bhist overwrite\n", __func__);
+ pr_err_ratelimited("%s: stats bhist overwrite\n", __func__);
if (error_status1 & (1 << 2))
- pr_err("%s: stats cs overwrite\n", __func__);
+ pr_err_ratelimited("%s: stats cs overwrite\n", __func__);
if (error_status1 & (1 << 3))
- pr_err("%s: stats ihist overwrite\n", __func__);
+ pr_err_ratelimited("%s: stats ihist overwrite\n", __func__);
if (error_status1 & (1 << 4))
- pr_err("%s: realign buf y overflow\n", __func__);
+ pr_err_ratelimited("%s: realign buf y overflow\n", __func__);
if (error_status1 & (1 << 5))
- pr_err("%s: realign buf cb overflow\n", __func__);
+ pr_err_ratelimited("%s: realign buf cb overflow\n", __func__);
if (error_status1 & (1 << 6))
- pr_err("%s: realign buf cr overflow\n", __func__);
+ pr_err_ratelimited("%s: realign buf cr overflow\n", __func__);
if (error_status1 & (1 << 7)) {
- pr_err("%s: violation\n", __func__);
+ pr_err_ratelimited("%s: violation\n", __func__);
msm_vfe40_process_violation_status(vfe_dev);
}
if (error_status1 & (1 << 9))
- pr_err("%s: image master 0 bus overflow\n", __func__);
+ pr_err_ratelimited("%s: image master 0 bus overflow\n",
+ __func__);
if (error_status1 & (1 << 10))
- pr_err("%s: image master 1 bus overflow\n", __func__);
+ pr_err_ratelimited("%s: image master 1 bus overflow\n",
+ __func__);
if (error_status1 & (1 << 11))
- pr_err("%s: image master 2 bus overflow\n", __func__);
+ pr_err_ratelimited("%s: image master 2 bus overflow\n",
+ __func__);
if (error_status1 & (1 << 12))
- pr_err("%s: image master 3 bus overflow\n", __func__);
+ pr_err_ratelimited("%s: image master 3 bus overflow\n",
+ __func__);
if (error_status1 & (1 << 13))
- pr_err("%s: image master 4 bus overflow\n", __func__);
+ pr_err_ratelimited("%s: image master 4 bus overflow\n",
+ __func__);
if (error_status1 & (1 << 14))
- pr_err("%s: image master 5 bus overflow\n", __func__);
+ pr_err_ratelimited("%s: image master 5 bus overflow\n",
+ __func__);
if (error_status1 & (1 << 15))
- pr_err("%s: image master 6 bus overflow\n", __func__);
+ pr_err_ratelimited("%s: image master 6 bus overflow\n",
+ __func__);
if (error_status1 & (1 << 16))
- pr_err("%s: status be bus overflow\n", __func__);
+ pr_err_ratelimited("%s: status be bus overflow\n", __func__);
if (error_status1 & (1 << 17))
- pr_err("%s: status bg bus overflow\n", __func__);
+ pr_err_ratelimited("%s: status bg bus overflow\n", __func__);
if (error_status1 & (1 << 18))
- pr_err("%s: status bf bus overflow\n", __func__);
+ pr_err_ratelimited("%s: status bf bus overflow\n", __func__);
if (error_status1 & (1 << 19))
- pr_err("%s: status awb bus overflow\n", __func__);
+ pr_err_ratelimited("%s: status awb bus overflow\n", __func__);
if (error_status1 & (1 << 20))
- pr_err("%s: status rs bus overflow\n", __func__);
+ pr_err_ratelimited("%s: status rs bus overflow\n", __func__);
if (error_status1 & (1 << 21))
- pr_err("%s: status cs bus overflow\n", __func__);
+ pr_err_ratelimited("%s: status cs bus overflow\n", __func__);
if (error_status1 & (1 << 22))
- pr_err("%s: status ihist bus overflow\n", __func__);
+ pr_err_ratelimited("%s: status ihist bus overflow\n", __func__);
if (error_status1 & (1 << 23))
- pr_err("%s: status skin bhist bus overflow\n", __func__);
+ pr_err_ratelimited("%s: status skin bhist bus overflow\n",
+ __func__);
}
static void msm_vfe40_read_irq_status(struct vfe_device *vfe_dev,
@@ -724,13 +734,18 @@
VFE40_WM_BASE(stream_info->wm[i]) + 0x1C);
}
-static void msm_vfe40_cfg_io_format(struct vfe_device *vfe_dev,
+static int32_t msm_vfe40_cfg_io_format(struct vfe_device *vfe_dev,
enum msm_vfe_axi_stream_src stream_src, uint32_t io_format)
{
int bpp, bpp_reg = 0, pack_reg = 0;
enum msm_isp_pack_fmt pack_fmt = 0;
uint32_t io_format_reg; /*io format register bit*/
bpp = msm_isp_get_bit_per_pixel(io_format);
+ if (bpp < 0) {
+ pr_err("%s:%d invalid io_format %d bpp %d", __func__, __LINE__,
+ io_format, bpp);
+ return -EINVAL;
+ }
switch (bpp) {
case 8:
@@ -742,6 +757,9 @@
case 12:
bpp_reg = 1 << 1;
break;
+ default:
+ pr_err("%s:%d invalid bpp %d", __func__, __LINE__, bpp);
+ return -EINVAL;
}
if (stream_src == IDEAL_RAW) {
@@ -768,7 +786,7 @@
break;
default:
pr_err("%s: invalid pack fmt!\n", __func__);
- return;
+ return -EINVAL;
}
}
@@ -789,9 +807,10 @@
case RDI_INTF_2:
default:
pr_err("%s: Invalid stream source\n", __func__);
- return;
+ return -EINVAL;
}
msm_camera_io_w(io_format_reg, vfe_dev->vfe_base + 0x54);
+ return 0;
}
static void msm_vfe40_cfg_camif(struct vfe_device *vfe_dev,
@@ -866,7 +885,10 @@
msm_camera_io_w_mb(0x0, vfe_dev->vfe_base + 0x2F4);
vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0;
} else if (update_state == DISABLE_CAMIF_IMMEDIATELY) {
- msm_camera_io_w_mb(0x2, vfe_dev->vfe_base + 0x2F4);
+ msm_camera_io_w_mb(0x6, vfe_dev->vfe_base + 0x2F4);
+ vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev);
+ vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev);
+ vfe_dev->hw_info->vfe_ops.core_ops.init_hw_reg(vfe_dev);
vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0;
}
}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index 4f3094a..97b6347 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -68,9 +68,17 @@
struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
{
int rc = -1, i;
- struct msm_vfe_axi_stream *stream_info =
- &axi_data->stream_info[
- HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)];
+ struct msm_vfe_axi_stream *stream_info = NULL;
+ uint32_t idx = 0;
+
+ if (NULL == stream_cfg_cmd || NULL == axi_data)
+ return rc;
+
+ idx = HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle);
+ if (idx < MAX_NUM_STREAM)
+ stream_info = &axi_data->stream_info[idx];
+ else
+ return rc;
switch (stream_cfg_cmd->output_format) {
case V4L2_PIX_FMT_SBGGR8:
@@ -318,7 +326,8 @@
stream_info->state == PAUSED ||
stream_info->state == RESUME_PENDING ||
stream_info->state == RESUMING) &&
- stream_cfg_cmd->cmd == STOP_STREAM) {
+ (stream_cfg_cmd->cmd == STOP_STREAM ||
+ stream_cfg_cmd->cmd == STOP_IMMEDIATELY)) {
stream_info->state = ACTIVE;
} else {
pr_err("%s: Invalid stream state: %d\n",
@@ -427,11 +436,22 @@
struct msm_vfe_axi_shared_data *axi_data,
struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
{
- struct msm_vfe_axi_stream *stream_info =
- &axi_data->stream_info[
- HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)];
- uint32_t framedrop_period = msm_isp_get_framedrop_period(
- stream_cfg_cmd->frame_skip_pattern);
+ struct msm_vfe_axi_stream *stream_info = NULL;
+ uint32_t framedrop_period = 0;
+ uint8_t idx = 0;
+
+ if (NULL == axi_data || NULL == stream_cfg_cmd)
+ return;
+
+ idx = HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle);
+
+ if (idx < MAX_NUM_STREAM)
+ stream_info = &axi_data->stream_info[idx];
+ else
+ return;
+
+ framedrop_period = msm_isp_get_framedrop_period(
+ stream_cfg_cmd->frame_skip_pattern);
if (stream_cfg_cmd->frame_skip_pattern == SKIP_ALL)
stream_info->framedrop_pattern = 0x0;
@@ -519,8 +539,17 @@
io_format = stream_info->output_format;
}
- vfe_dev->hw_info->vfe_ops.axi_ops.cfg_io_format(
+ rc = vfe_dev->hw_info->vfe_ops.axi_ops.cfg_io_format(
vfe_dev, stream_info->stream_src, io_format);
+ if (rc) {
+ pr_err("%s: cfg io format failed\n", __func__);
+ msm_isp_axi_free_wm(&vfe_dev->axi_data,
+ stream_info);
+ msm_isp_axi_destroy_stream(&vfe_dev->axi_data,
+ HANDLE_TO_IDX(
+ stream_cfg_cmd->axi_stream_handle));
+ return rc;
+ }
}
msm_isp_calculate_framedrop(&vfe_dev->axi_data, stream_cfg_cmd);
@@ -654,7 +683,9 @@
}
}
- if (vfe_dev->axi_data.pipeline_update == DISABLE_CAMIF) {
+ if (vfe_dev->axi_data.pipeline_update == DISABLE_CAMIF ||
+ (vfe_dev->axi_data.pipeline_update ==
+ DISABLE_CAMIF_IMMEDIATELY)) {
vfe_dev->hw_info->vfe_ops.stats_ops.
enable_module(vfe_dev, 0xFF, 0);
vfe_dev->axi_data.pipeline_update = NO_UPDATE;
@@ -760,8 +791,9 @@
rc = vfe_dev->buf_mgr->ops->get_buf(vfe_dev->buf_mgr,
vfe_dev->pdev->id, bufq_handle, &buf);
if (rc < 0) {
- vfe_dev->error_info.
- stream_framedrop_count[stream_idx]++;
+ if(stream_idx < MAX_NUM_STREAM)
+ vfe_dev->error_info.
+ stream_framedrop_count[stream_idx]++;
return rc;
}
@@ -865,6 +897,10 @@
(cur_pix_stream_cnt - pix_stream_cnt) == 0 &&
stream_cfg_cmd->cmd == STOP_STREAM)
return DISABLE_CAMIF;
+ else if (cur_pix_stream_cnt &&
+ (cur_pix_stream_cnt - pix_stream_cnt) == 0 &&
+ stream_cfg_cmd->cmd == STOP_IMMEDIATELY)
+ return DISABLE_CAMIF_IMMEDIATELY;
}
return NO_UPDATE;
}
@@ -1153,8 +1189,14 @@
* since for burst case, write masters already skip
* all frames.
*/
+ if (stream_info->stream_src == RDI_INTF_0 ||
+ stream_info->stream_src == RDI_INTF_1 ||
+ stream_info->stream_src == RDI_INTF_2)
+ wait_for_complete = 1;
+ else {
msm_isp_axi_stream_enable_cfg(vfe_dev, stream_info);
stream_info->state = INACTIVE;
+ }
} else {
wait_for_complete = 1;
}
@@ -1170,6 +1212,9 @@
if (camif_update == DISABLE_CAMIF)
vfe_dev->hw_info->vfe_ops.core_ops.
update_camif_state(vfe_dev, DISABLE_CAMIF);
+ else if (camif_update == DISABLE_CAMIF_IMMEDIATELY)
+ vfe_dev->hw_info->vfe_ops.core_ops.
+ update_camif_state(vfe_dev, DISABLE_CAMIF_IMMEDIATELY);
msm_isp_update_camif_output_count(vfe_dev, stream_cfg_cmd);
for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
index b479857..8b83144 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
@@ -39,8 +39,9 @@
rc = vfe_dev->buf_mgr->ops->get_buf(vfe_dev->buf_mgr,
vfe_dev->pdev->id, bufq_handle, &buf);
if (rc < 0) {
- vfe_dev->error_info.stats_framedrop_count[
- STATS_IDX(stream_info->stream_handle)]++;
+ uint8_t idx = STATS_IDX(stream_info->stream_handle);
+ if (idx < MSM_ISP_STATS_MAX)
+ vfe_dev->error_info.stats_framedrop_count[idx]++;
return rc;
}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index 5f36a4a..a12c692 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -77,6 +77,25 @@
.name = "msm_camera_isp",
};
+static void msm_isp_print_fourcc_error(const char *origin,
+ uint32_t fourcc_format)
+{
+ int i;
+ char text[5];
+ text[4] = '\0';
+ for (i = 0; i < 4; i++) {
+ text[i] = (char)(((fourcc_format) >> (i * 8)) & 0xFF);
+ if ((text[i] < '0') || (text[i] > 'z')) {
+ pr_err("%s: Invalid output format %d (unprintable)\n",
+ origin, fourcc_format);
+ return;
+ }
+ }
+ pr_err("%s: Invalid output format %s\n",
+ origin, text);
+ return;
+}
+
int msm_isp_init_bandwidth_mgr(enum msm_isp_hw_client client)
{
int rc = 0;
@@ -258,6 +277,43 @@
return rc;
}
+static int msm_isp_get_max_clk_rate(struct vfe_device *vfe_dev, long *rate)
+{
+ int clk_idx = 0;
+ unsigned long max_value = ~0;
+ long round_rate = 0;
+
+ if (!vfe_dev || !rate) {
+ pr_err("%s:%d failed: vfe_dev %p rate %p\n", __func__, __LINE__,
+ vfe_dev, rate);
+ return -EINVAL;
+ }
+
+ *rate = 0;
+ if (!vfe_dev->hw_info) {
+ pr_err("%s:%d failed: vfe_dev->hw_info %p\n", __func__,
+ __LINE__, vfe_dev->hw_info);
+ return -EINVAL;
+ }
+
+ clk_idx = vfe_dev->hw_info->vfe_clk_idx;
+ if (clk_idx >= ARRAY_SIZE(vfe_dev->vfe_clk)) {
+ pr_err("%s:%d failed: clk_idx %d max array size %d\n",
+ __func__, __LINE__, clk_idx,
+ ARRAY_SIZE(vfe_dev->vfe_clk));
+ return -EINVAL;
+ }
+
+ round_rate = clk_round_rate(vfe_dev->vfe_clk[clk_idx], max_value);
+ if (round_rate < 0) {
+ pr_err("%s: Invalid vfe clock rate\n", __func__);
+ return -EINVAL;
+ }
+
+ *rate = round_rate;
+ return 0;
+}
+
static int msm_isp_set_clk_rate(struct vfe_device *vfe_dev, long *rate)
{
int rc = 0;
@@ -513,7 +569,9 @@
}
lo_tbl_ptr = cfg_data +
reg_cfg_cmd->u.dmi_info.lo_tbl_offset/4;
-
+ if (reg_cfg_cmd->cmd_type == VFE_WRITE_DMI_64BIT)
+ reg_cfg_cmd->u.dmi_info.len =
+ reg_cfg_cmd->u.dmi_info.len / 2;
for (i = 0; i < reg_cfg_cmd->u.dmi_info.len/4; i++) {
lo_val = *lo_tbl_ptr++;
if (reg_cfg_cmd->cmd_type == VFE_WRITE_DMI_16BIT) {
@@ -597,6 +655,23 @@
case GET_SOC_HW_VER:
*cfg_data = vfe_dev->soc_hw_version;
break;
+ case GET_MAX_CLK_RATE: {
+ int rc = 0;
+
+ if (cmd_len < sizeof(unsigned long)) {
+ pr_err("%s:%d failed: invalid cmd len %d exp %d\n",
+ __func__, __LINE__, cmd_len,
+ sizeof(unsigned long));
+ return -EINVAL;
+ }
+ rc = msm_isp_get_max_clk_rate(vfe_dev,
+ (unsigned long *)cfg_data);
+ if (rc < 0) {
+ pr_err("%s:%d failed: rc %d\n", __func__, __LINE__, rc);
+ return -EINVAL;
+ }
+ break;
+ }
}
return 0;
}
@@ -621,6 +696,12 @@
goto reg_cfg_failed;
}
+ if (!proc_cmd->cmd_len) {
+ pr_err("%s: Passed cmd_len as 0\n", __func__);
+ rc = -EINVAL;
+ goto cfg_data_failed;
+ }
+
cfg_data = kzalloc(proc_cmd->cmd_len, GFP_KERNEL);
if (!cfg_data) {
pr_err("%s: cfg_data alloc failed\n", __func__);
@@ -727,7 +808,7 @@
break;
/*TD: Add more image format*/
default:
- pr_err("%s: Invalid output format\n", __func__);
+ msm_isp_print_fourcc_error(__func__, output_format);
break;
}
return val;
@@ -763,7 +844,7 @@
case V4L2_PIX_FMT_QRGGB12:
return QCOM;
default:
- pr_err("%s: Invalid output format\n", __func__);
+ msm_isp_print_fourcc_error(__func__, output_format);
break;
}
return -EINVAL;
@@ -772,6 +853,10 @@
int msm_isp_get_bit_per_pixel(uint32_t output_format)
{
switch (output_format) {
+ case V4L2_PIX_FMT_Y4:
+ return 4;
+ case V4L2_PIX_FMT_Y6:
+ return 6;
case V4L2_PIX_FMT_SBGGR8:
case V4L2_PIX_FMT_SGBRG8:
case V4L2_PIX_FMT_SGRBG8:
@@ -782,6 +867,29 @@
case V4L2_PIX_FMT_QRGGB8:
case V4L2_PIX_FMT_JPEG:
case V4L2_PIX_FMT_META:
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_NV14:
+ case V4L2_PIX_FMT_NV41:
+ case V4L2_PIX_FMT_YVU410:
+ case V4L2_PIX_FMT_YVU420:
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_YYUV:
+ case V4L2_PIX_FMT_YVYU:
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_VYUY:
+ case V4L2_PIX_FMT_YUV422P:
+ case V4L2_PIX_FMT_YUV411P:
+ case V4L2_PIX_FMT_Y41P:
+ case V4L2_PIX_FMT_YUV444:
+ case V4L2_PIX_FMT_YUV555:
+ case V4L2_PIX_FMT_YUV565:
+ case V4L2_PIX_FMT_YUV32:
+ case V4L2_PIX_FMT_YUV410:
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_GREY:
+ case V4L2_PIX_FMT_PAL8:
+ case MSM_V4L2_PIX_FMT_META:
return 8;
case V4L2_PIX_FMT_SBGGR10:
case V4L2_PIX_FMT_SGBRG10:
@@ -791,6 +899,8 @@
case V4L2_PIX_FMT_QGBRG10:
case V4L2_PIX_FMT_QGRBG10:
case V4L2_PIX_FMT_QRGGB10:
+ case V4L2_PIX_FMT_Y10:
+ case V4L2_PIX_FMT_Y10BPACK:
return 10;
case V4L2_PIX_FMT_SBGGR12:
case V4L2_PIX_FMT_SGBRG12:
@@ -800,21 +910,17 @@
case V4L2_PIX_FMT_QGBRG12:
case V4L2_PIX_FMT_QGRBG12:
case V4L2_PIX_FMT_QRGGB12:
+ case V4L2_PIX_FMT_Y12:
return 12;
- case V4L2_PIX_FMT_NV12:
- case V4L2_PIX_FMT_NV21:
- case V4L2_PIX_FMT_NV14:
- case V4L2_PIX_FMT_NV41:
- return 8;
case V4L2_PIX_FMT_NV16:
case V4L2_PIX_FMT_NV61:
+ case V4L2_PIX_FMT_Y16:
return 16;
/*TD: Add more image format*/
default:
- pr_err("%s: Invalid output format\n", __func__);
- break;
+ msm_isp_print_fourcc_error(__func__, output_format);
+ return -EINVAL;
}
- return -EINVAL;
}
void msm_isp_update_error_frame_count(struct vfe_device *vfe_dev)
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
old mode 100644
new mode 100755
index 89016ec..c4a23ca
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
@@ -200,17 +200,17 @@
ispif->base + ISPIF_VFE_m_INTF_CMD_0(i));
msm_camera_io_w(ISPIF_STOP_INTF_IMMEDIATELY,
ispif->base + ISPIF_VFE_m_INTF_CMD_1(i));
-
+ pr_debug("%s: base %lx", __func__, (unsigned long)ispif->base);
msm_camera_io_w(0, ispif->base +
ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 0));
msm_camera_io_w(0, ispif->base +
ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 1));
msm_camera_io_w(0, ispif->base +
- ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 0));
+ ISPIF_VFE_m_RDI_INTF_n_CID_MASK(i, 0));
msm_camera_io_w(0, ispif->base +
- ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 1));
+ ISPIF_VFE_m_RDI_INTF_n_CID_MASK(i, 1));
msm_camera_io_w(0, ispif->base +
- ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 2));
+ ISPIF_VFE_m_RDI_INTF_n_CID_MASK(i, 2));
msm_camera_io_w(0, ispif->base +
ISPIF_VFE_m_PIX_INTF_n_CROP(i, 0));
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_common.h b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_common.h
index 04af6b6..634beca 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_common.h
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_common.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -20,7 +20,7 @@
#endif
#define JPEG_PR_ERR pr_err
-#define JPEG_DBG_HIGH pr_err
+#define JPEG_DBG_HIGH pr_debug
enum JPEG_MODE {
JPEG_MODE_DISABLE,
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c
index 0a0fa04..44a4014 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -216,15 +216,15 @@
if (pingpong_index == 0) {
hw_cmd_p = &hw_cmd_we_ping_update[0];
hw_cmd_p->data = p_input->y_buffer_addr;
- JPEG_PR_ERR("%s Output pln0 buffer address is %x\n", __func__,
+ JPEG_DBG_HIGH("%s Output pln0 buffer address is %x\n", __func__,
p_input->y_buffer_addr);
msm_jpeg_hw_write(hw_cmd_p++, base);
hw_cmd_p->data = p_input->cbcr_buffer_addr;
- JPEG_PR_ERR("%s Output pln1 buffer address is %x\n", __func__,
+ JPEG_DBG_HIGH("%s Output pln1 buffer address is %x\n", __func__,
p_input->cbcr_buffer_addr);
msm_jpeg_hw_write(hw_cmd_p++, base);
hw_cmd_p->data = p_input->pln2_addr;
- JPEG_PR_ERR("%s Output pln2 buffer address is %x\n", __func__,
+ JPEG_DBG_HIGH("%s Output pln2 buffer address is %x\n", __func__,
p_input->pln2_addr);
msm_jpeg_hw_write(hw_cmd_p++, base);
}
@@ -337,6 +337,11 @@
__LINE__, hw_cmd_p->offset, max_size);
return -EFAULT;
}
+ if (hw_cmd_p->offset & 0x3) {
+ JPEG_PR_ERR("%s:%d] %d Invalid alignment\n", __func__,
+ __LINE__, hw_cmd_p->offset);
+ return -EFAULT;
+ }
switch (hw_cmd_p->type) {
case MSM_JPEG_HW_CMD_TYPE_READ:
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
index d6fa2b0..407b81f 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
@@ -28,6 +28,24 @@
#include "msm_jpeg_common.h"
#include "msm_jpeg_hw.h"
+int msm_jpeg_platform_set_clk_rate(struct msm_jpeg_device *pgmn_dev,
+ long clk_rate)
+{
+ int rc = 0;
+ struct clk *jpeg_clk;
+
+ jpeg_clk = clk_get(&pgmn_dev->pdev->dev, "core_clk");
+ if (IS_ERR(jpeg_clk)) {
+ JPEG_PR_ERR("%s get failed\n", "core_clk");
+ rc = PTR_ERR(jpeg_clk);
+ return rc;
+ }
+
+ rc = clk_set_rate(jpeg_clk, clk_rate);
+
+ return rc;
+}
+
void msm_jpeg_platform_p2v(struct msm_jpeg_device *pgmn_dev, struct file *file,
struct ion_handle **ionhandle, int domain_num)
{
@@ -135,8 +153,8 @@
{
.src = MSM_BUS_MASTER_JPEG,
.dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = JPEG_CLK_RATE * 2.5,
- .ib = JPEG_CLK_RATE * 2.5,
+ .ab = JPEG_MAX_CLK_RATE * 2.5,
+ .ib = JPEG_MAX_CLK_RATE * 2.5,
},
};
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.h b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.h
index a14b8ee..7be9e19 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.h
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.h
@@ -20,7 +20,10 @@
#include <mach/iommu.h>
#include "msm_jpeg_sync.h"
#define JPEG_CLK_RATE 266670000
+#define JPEG_MAX_CLK_RATE 320000000
+int msm_jpeg_platform_set_clk_rate(struct msm_jpeg_device *pgmn_dev,
+ long clk_rate);
void msm_jpeg_platform_p2v(struct msm_jpeg_device *pgmn_dev, struct file *file,
struct ion_handle **ionhandle, int domain_num);
uint32_t msm_jpeg_platform_v2p(struct msm_jpeg_device *pgmn_dev, int fd,
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c
index 80ff9e5..5cc51ff 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c
@@ -669,6 +669,8 @@
JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
return -EFAULT;
}
+ } else {
+ return is_copy_to_user;
}
return 0;
@@ -804,6 +806,36 @@
return 0;
}
+int msm_jpeg_ioctl_set_clk_rate(struct msm_jpeg_device *pgmn_dev,
+ unsigned long arg)
+{
+ long clk_rate;
+ int rc;
+
+ if ((pgmn_dev->state != MSM_JPEG_INIT) &&
+ (pgmn_dev->state != MSM_JPEG_RESET)) {
+ JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+ if (get_user(clk_rate, (long __user *)arg)) {
+ JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+ JPEG_DBG("%s:%d] Requested clk rate %ld\n", __func__, __LINE__,
+ clk_rate);
+ if (clk_rate < 0) {
+ JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+ rc = msm_jpeg_platform_set_clk_rate(pgmn_dev, clk_rate);
+ if (rc < 0) {
+ JPEG_PR_ERR("%s: clk failed rc = %d\n", __func__, rc);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
long __msm_jpeg_ioctl(struct msm_jpeg_device *pgmn_dev,
unsigned int cmd, unsigned long arg)
{
@@ -873,6 +905,9 @@
rc = msm_jpeg_ioctl_test_dump_region(pgmn_dev, arg);
break;
+ case MSM_JPEG_IOCTL_SET_CLK_RATE:
+ rc = msm_jpeg_ioctl_set_clk_rate(pgmn_dev, arg);
+ break;
default:
JPEG_PR_ERR(KERN_INFO "%s:%d] cmd = %d not supported\n",
__func__, __LINE__, _IOC_NR(cmd));
diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c
index efa3ad0..8a2c8e5 100644
--- a/drivers/media/platform/msm/camera_v2/msm.c
+++ b/drivers/media/platform/msm/camera_v2/msm.c
@@ -438,7 +438,7 @@
static inline int __msm_destroy_session_streams(void *d1, void *d2)
{
struct msm_stream *stream = d1;
-
+ pr_err("%s: Destroyed here due to list is not empty\n", __func__);
INIT_LIST_HEAD(&stream->queued_list);
return 0;
}
@@ -1001,8 +1001,10 @@
video_set_drvdata(pvdev->vdev, pvdev);
msm_session_q = kzalloc(sizeof(*msm_session_q), GFP_KERNEL);
- if (WARN_ON(!msm_session_q))
- goto v4l2_fail;
+ if (WARN_ON(!msm_session_q)) {
+ rc = -ENOMEM;
+ goto session_fail;
+ }
msm_init_queue(msm_session_q);
spin_lock_init(&msm_eventq_lock);
@@ -1010,6 +1012,8 @@
INIT_LIST_HEAD(&ordered_sd_list);
goto probe_end;
+session_fail:
+ video_unregister_device(pvdev->vdev);
v4l2_fail:
v4l2_device_unregister(pvdev->vdev->v4l2_dev);
register_fail:
diff --git a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
index 154ee87..cb8fcdd 100644
--- a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
@@ -100,6 +100,55 @@
return ret;
}
+static void msm_buf_mngr_sd_shutdown(struct msm_buf_mngr_device *buf_mngr_dev)
+{
+ unsigned long flags;
+ struct msm_get_bufs *bufs, *save;
+
+ spin_lock_irqsave(&buf_mngr_dev->buf_q_spinlock, flags);
+ if (!list_empty(&buf_mngr_dev->buf_qhead)) {
+ list_for_each_entry_safe(bufs,
+ save, &buf_mngr_dev->buf_qhead, entry) {
+ pr_err("%s: Error delete invalid bufs =%x, ses_id=%d, str_id=%d, idx=%d\n",
+ __func__, (unsigned int)bufs, bufs->session_id,
+ bufs->stream_id, bufs->vb2_buf->v4l2_buf.index);
+ list_del_init(&bufs->entry);
+ kfree(bufs);
+ }
+ }
+ spin_unlock_irqrestore(&buf_mngr_dev->buf_q_spinlock, flags);
+}
+
+static int msm_generic_buf_mngr_open(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ int rc = 0;
+ struct msm_buf_mngr_device *buf_mngr_dev = v4l2_get_subdevdata(sd);
+ if (!buf_mngr_dev) {
+ pr_err("%s buf manager device NULL\n", __func__);
+ rc = -ENODEV;
+ return rc;
+ }
+ buf_mngr_dev->msm_buf_mngr_open_cnt++;
+ return rc;
+}
+
+static int msm_generic_buf_mngr_close(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ int rc = 0;
+ struct msm_buf_mngr_device *buf_mngr_dev = v4l2_get_subdevdata(sd);
+ if (!buf_mngr_dev) {
+ pr_err("%s buf manager device NULL\n", __func__);
+ rc = -ENODEV;
+ return rc;
+ }
+ buf_mngr_dev->msm_buf_mngr_open_cnt--;
+ if (buf_mngr_dev->msm_buf_mngr_open_cnt == 0)
+ msm_buf_mngr_sd_shutdown(buf_mngr_dev);
+ return rc;
+}
+
static long msm_buf_mngr_subdev_ioctl(struct v4l2_subdev *sd,
unsigned int cmd, void *arg)
{
@@ -123,6 +172,15 @@
case VIDIOC_MSM_BUF_MNGR_PUT_BUF:
rc = msm_buf_mngr_put_buf(buf_mngr_dev, argp);
break;
+ case VIDIOC_MSM_BUF_MNGR_INIT:
+ rc = msm_generic_buf_mngr_open(sd, NULL);
+ break;
+ case VIDIOC_MSM_BUF_MNGR_DEINIT:
+ rc = msm_generic_buf_mngr_close(sd, NULL);
+ break;
+ case MSM_SD_SHUTDOWN:
+ msm_buf_mngr_sd_shutdown(buf_mngr_dev);
+ break;
default:
return -ENOIOCTLCMD;
}
@@ -133,6 +191,12 @@
.ioctl = msm_buf_mngr_subdev_ioctl,
};
+static const struct v4l2_subdev_internal_ops
+ msm_generic_buf_mngr_subdev_internal_ops = {
+ .open = msm_generic_buf_mngr_open,
+ .close = msm_generic_buf_mngr_close,
+};
+
static const struct v4l2_subdev_ops msm_buf_mngr_subdev_ops = {
.core = &msm_buf_mngr_subdev_core_ops,
};
@@ -162,6 +226,8 @@
msm_buf_mngr_dev->subdev.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
msm_buf_mngr_dev->subdev.sd.entity.group_id =
MSM_CAMERA_SUBDEV_BUF_MNGR;
+ msm_buf_mngr_dev->subdev.sd.internal_ops =
+ &msm_generic_buf_mngr_subdev_internal_ops;
msm_buf_mngr_dev->subdev.close_seq = MSM_SD_CLOSE_4TH_CATEGORY;
rc = msm_sd_register(&msm_buf_mngr_dev->subdev);
if (rc != 0) {
diff --git a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.h b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.h
index 56886cd..49fad22 100644
--- a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.h
+++ b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.h
@@ -36,5 +36,6 @@
spinlock_t buf_q_spinlock;
struct msm_sd_subdev subdev;
struct msm_sd_req_vb2_q vb2_ops;
+ uint32_t msm_buf_mngr_open_cnt;
};
#endif
diff --git a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c
index 8fa8f8d..0fbaeca 100644
--- a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c
+++ b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c
@@ -251,6 +251,7 @@
unsigned long flags;
struct msm_vb2_buffer *msm_vb2;
struct msm_stream *stream;
+ struct vb2_buffer *vb2_buf = NULL;
int rc = 0;
stream = msm_get_stream(session_id, stream_id);
@@ -258,6 +259,18 @@
return 0;
spin_lock_irqsave(&stream->stream_lock, flags);
if (vb) {
+ list_for_each_entry(msm_vb2, &(stream->queued_list), list) {
+ vb2_buf = &(msm_vb2->vb2_buf);
+ if (vb2_buf == vb)
+ break;
+ }
+ if (vb2_buf != vb) {
+ pr_err("%s:%d VB buffer is INVALID vb=%x, ses_id=%d, str_id=%d\n",
+ __func__, __LINE__, (unsigned int)vb,
+ session_id, stream_id);
+ rc = -EINVAL;
+ goto out;
+ }
msm_vb2 =
container_of(vb, struct msm_vb2_buffer, vb2_buf);
/* put buf before buf done */
@@ -268,10 +281,11 @@
} else
rc = -EINVAL;
} else {
- pr_err("%s: VB buffer is null\n", __func__);
+ pr_err("%s:%d VB buffer is NULL for ses_id=%d, str_id=%d\n",
+ __func__, __LINE__, session_id, stream_id);
rc = -EINVAL;
}
-
+out:
spin_unlock_irqrestore(&stream->stream_lock, flags);
return rc;
}
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index 8b8d23b..10a0085 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -57,18 +57,19 @@
};
struct msm_cpp_timer_t {
- uint8_t used;
+ atomic_t used;
struct msm_cpp_timer_data_t data;
struct timer_list cpp_timer;
};
-struct msm_cpp_timer_t cpp_timers[2];
-static int del_timer_idx;
-static int set_timer_idx;
+struct msm_cpp_timer_t cpp_timer;
/* dump the frame command before writing to the hardware */
#define MSM_CPP_DUMP_FRM_CMD 0
+static int msm_cpp_buffer_ops(struct cpp_device *cpp_dev,
+ uint32_t buff_mgr_ops, struct msm_buf_mngr_info *buff_mgr_info);
+
#if CONFIG_MSM_CPP_DBG
#define CPP_DBG(fmt, args...) pr_err(fmt, ##args)
#else
@@ -596,24 +597,20 @@
if (msg_id == MSM_CPP_MSG_ID_FRAME_ACK) {
CPP_DBG("Frame done!!\n");
/* delete CPP timer */
- CPP_DBG("delete timer %d.\n",
- del_timer_idx);
- timer = &cpp_timers[del_timer_idx];
+ CPP_DBG("delete timer.\n");
+ timer = &cpp_timer;
+ atomic_set(&timer->used, 0);
del_timer(&timer->cpp_timer);
- timer->used = 0;
timer->data.processed_frame = NULL;
- del_timer_idx = 1 - del_timer_idx;
msm_cpp_notify_frame_done(cpp_dev);
} else if (msg_id ==
MSM_CPP_MSG_ID_FRAME_NACK) {
pr_err("NACK error from hw!!\n");
- CPP_DBG("delete timer %d.\n",
- del_timer_idx);
- timer = &cpp_timers[del_timer_idx];
+ CPP_DBG("delete timer.\n");
+ timer = &cpp_timer;
+ atomic_set(&timer->used, 0);
del_timer(&timer->cpp_timer);
- timer->used = 0;
timer->data.processed_frame = NULL;
- del_timer_idx = 1 - del_timer_idx;
msm_cpp_notify_frame_done(cpp_dev);
}
i += cmd_len + 2;
@@ -720,6 +717,14 @@
goto req_irq_fail;
}
cpp_dev->buf_mgr_subdev = msm_buf_mngr_get_subdev();
+
+ rc = msm_cpp_buffer_ops(cpp_dev,
+ VIDIOC_MSM_BUF_MNGR_INIT, NULL);
+ if (rc < 0) {
+ pr_err("buf mngr init failed\n");
+ free_irq(cpp_dev->irq->start, cpp_dev);
+ goto req_irq_fail;
+ }
}
cpp_dev->hw_info.cpp_hw_version =
@@ -763,7 +768,12 @@
static void cpp_release_hardware(struct cpp_device *cpp_dev)
{
+ int32_t rc;
if (cpp_dev->state != CPP_STATE_BOOT) {
+ rc = msm_cpp_buffer_ops(cpp_dev,
+ VIDIOC_MSM_BUF_MNGR_DEINIT, NULL);
+ if (rc < 0)
+ pr_err("error in buf mngr deinit rc=%d\n", rc);
free_irq(cpp_dev->irq->start, cpp_dev);
tasklet_kill(&cpp_dev->cpp_tasklet);
atomic_set(&cpp_dev->irq_cnt, 0);
@@ -813,7 +823,7 @@
/*Start firmware loading*/
msm_cpp_write(MSM_CPP_CMD_FW_LOAD, cpp_dev->base);
- msm_cpp_write(MSM_CPP_END_ADDRESS, cpp_dev->base);
+ msm_cpp_write(fw->size, cpp_dev->base);
msm_cpp_write(MSM_CPP_START_ADDRESS, cpp_dev->base);
if (ptr_bin) {
@@ -926,35 +936,35 @@
cpp_dev->cpp_open_cnt--;
if (cpp_dev->cpp_open_cnt == 0) {
- pr_err("%s: irq_status: 0x%x\n", __func__,
+ pr_debug("irq_status: 0x%x\n",
msm_camera_io_r(cpp_dev->cpp_hw_base + 0x4));
- pr_err("%s: DEBUG_SP: 0x%x\n", __func__,
+ pr_debug("DEBUG_SP: 0x%x\n",
msm_camera_io_r(cpp_dev->cpp_hw_base + 0x40));
- pr_err("%s: DEBUG_T: 0x%x\n", __func__,
+ pr_debug("DEBUG_T: 0x%x\n",
msm_camera_io_r(cpp_dev->cpp_hw_base + 0x44));
- pr_err("%s: DEBUG_N: 0x%x\n", __func__,
+ pr_debug("DEBUG_N: 0x%x\n",
msm_camera_io_r(cpp_dev->cpp_hw_base + 0x48));
- pr_err("%s: DEBUG_R: 0x%x\n", __func__,
+ pr_debug("DEBUG_R: 0x%x\n",
msm_camera_io_r(cpp_dev->cpp_hw_base + 0x4C));
- pr_err("%s: DEBUG_OPPC: 0x%x\n", __func__,
+ pr_debug("DEBUG_OPPC: 0x%x\n",
msm_camera_io_r(cpp_dev->cpp_hw_base + 0x50));
- pr_err("%s: DEBUG_MO: 0x%x\n", __func__,
+ pr_debug("DEBUG_MO: 0x%x\n",
msm_camera_io_r(cpp_dev->cpp_hw_base + 0x54));
- pr_err("%s: DEBUG_TIMER0: 0x%x\n", __func__,
+ pr_debug("DEBUG_TIMER0: 0x%x\n",
msm_camera_io_r(cpp_dev->cpp_hw_base + 0x60));
- pr_err("%s: DEBUG_TIMER1: 0x%x\n", __func__,
+ pr_debug("DEBUG_TIMER1: 0x%x\n",
msm_camera_io_r(cpp_dev->cpp_hw_base + 0x64));
- pr_err("%s: DEBUG_GPI: 0x%x\n", __func__,
+ pr_debug("DEBUG_GPI: 0x%x\n",
msm_camera_io_r(cpp_dev->cpp_hw_base + 0x70));
- pr_err("%s: DEBUG_GPO: 0x%x\n", __func__,
+ pr_debug("DEBUG_GPO: 0x%x\n",
msm_camera_io_r(cpp_dev->cpp_hw_base + 0x74));
- pr_err("%s: DEBUG_T0: 0x%x\n", __func__,
+ pr_debug("DEBUG_T0: 0x%x\n",
msm_camera_io_r(cpp_dev->cpp_hw_base + 0x80));
- pr_err("%s: DEBUG_R0: 0x%x\n", __func__,
+ pr_debug("DEBUG_R0: 0x%x\n",
msm_camera_io_r(cpp_dev->cpp_hw_base + 0x84));
- pr_err("%s: DEBUG_T1: 0x%x\n", __func__,
+ pr_debug("DEBUG_T1: 0x%x\n",
msm_camera_io_r(cpp_dev->cpp_hw_base + 0x88));
- pr_err("%s: DEBUG_R1: 0x%x\n", __func__,
+ pr_debug("DEBUG_R1: 0x%x\n",
msm_camera_io_r(cpp_dev->cpp_hw_base + 0x8C));
msm_camera_io_w(0x0, cpp_dev->base + MSM_CPP_MICRO_CLKEN_CTL);
cpp_deinit_mem(cpp_dev);
@@ -1077,97 +1087,62 @@
{
int ret;
uint32_t i = 0;
- struct msm_cpp_frame_info_t *this_frame =
- cpp_timers[del_timer_idx].data.processed_frame;
- struct msm_cpp_frame_info_t *second_frame = NULL;
+ struct msm_cpp_frame_info_t *this_frame = NULL;
- pr_err("cpp_timer_callback called idx:%d. (jiffies=%lu)\n",
- del_timer_idx, jiffies);
- if (!work || !this_frame) {
- pr_err("Invalid work:%p, this_frame:%p, del_idx:%d\n",
- work, this_frame, del_timer_idx);
+ pr_err("cpp_timer_callback called. (jiffies=%lu)\n",
+ jiffies);
+ if (!work) {
+ pr_err("Invalid work:%p\n", work);
return;
}
- pr_err("fatal: cpp_timer expired for identity=0x%x, frame_id=%03d",
- this_frame->identity, this_frame->frame_id);
- cpp_timers[del_timer_idx].used = 0;
- cpp_timers[del_timer_idx].data.processed_frame = NULL;
- del_timer_idx = 1 - del_timer_idx;
-
- if (cpp_timers[del_timer_idx].used == 1) {
- pr_err("deleting cpp_timer %d.\n", del_timer_idx);
- del_timer(&cpp_timers[del_timer_idx].cpp_timer);
- cpp_timers[del_timer_idx].used = 0;
- second_frame = cpp_timers[del_timer_idx].data.processed_frame;
- cpp_timers[del_timer_idx].data.processed_frame = NULL;
- del_timer_idx = 1 - del_timer_idx;
+ if (!atomic_read(&cpp_timer.used)) {
+ pr_err("Delayed trigger, IRQ serviced\n");
+ return;
}
- disable_irq(cpp_timers[del_timer_idx].data.cpp_dev->irq->start);
+ disable_irq(cpp_timer.data.cpp_dev->irq->start);
pr_err("Reloading firmware\n");
- cpp_load_fw(cpp_timers[del_timer_idx].data.cpp_dev, NULL);
+ cpp_load_fw(cpp_timer.data.cpp_dev, NULL);
pr_err("Firmware loading done\n");
- enable_irq(cpp_timers[del_timer_idx].data.cpp_dev->irq->start);
- msm_camera_io_w_mb(0x8, cpp_timers[del_timer_idx].data.cpp_dev->base +
+ enable_irq(cpp_timer.data.cpp_dev->irq->start);
+ msm_camera_io_w_mb(0x8, cpp_timer.data.cpp_dev->base +
MSM_CPP_MICRO_IRQGEN_MASK);
msm_camera_io_w_mb(0xFFFF,
- cpp_timers[del_timer_idx].data.cpp_dev->base +
+ cpp_timer.data.cpp_dev->base +
MSM_CPP_MICRO_IRQGEN_CLR);
- cpp_timers[set_timer_idx].data.processed_frame = this_frame;
- cpp_timers[set_timer_idx].used = 1;
- pr_err("ReInstalling cpp_timer %d\n", set_timer_idx);
- setup_timer(&cpp_timers[set_timer_idx].cpp_timer, cpp_timer_callback,
- (unsigned long)&cpp_timers[0]);
+ if (!atomic_read(&cpp_timer.used)) {
+ pr_err("Delayed trigger, IRQ serviced\n");
+ return;
+ }
+
+ this_frame = cpp_timer.data.processed_frame;
+ pr_err("ReInstalling cpp_timer\n");
+ setup_timer(&cpp_timer.cpp_timer, cpp_timer_callback,
+ (unsigned long)&cpp_timer);
pr_err("Starting timer to fire in %d ms. (jiffies=%lu)\n",
CPP_CMD_TIMEOUT_MS, jiffies);
- ret = mod_timer(&cpp_timers[set_timer_idx].cpp_timer,
+ ret = mod_timer(&cpp_timer.cpp_timer,
jiffies + msecs_to_jiffies(CPP_CMD_TIMEOUT_MS));
if (ret)
pr_err("error in mod_timer\n");
- set_timer_idx = 1 - set_timer_idx;
- pr_err("Rescheduling for identity=0x%x, frame_id=%03d",
+ pr_err("Rescheduling for identity=0x%x, frame_id=%03d\n",
this_frame->identity, this_frame->frame_id);
- msm_cpp_write(0x6, cpp_timers[set_timer_idx].data.cpp_dev->base);
+ msm_cpp_write(0x6, cpp_timer.data.cpp_dev->base);
msm_cpp_dump_frame_cmd(this_frame->cpp_cmd_msg,
this_frame->msg_len);
for (i = 0; i < this_frame->msg_len; i++)
msm_cpp_write(this_frame->cpp_cmd_msg[i],
- cpp_timers[set_timer_idx].data.cpp_dev->base);
-
-
- if (second_frame != NULL) {
- cpp_timers[set_timer_idx].data.processed_frame = second_frame;
- cpp_timers[set_timer_idx].used = 1;
- pr_err("ReInstalling cpp_timer %d\n", set_timer_idx);
- setup_timer(&cpp_timers[set_timer_idx].cpp_timer,
- cpp_timer_callback, (unsigned long)&cpp_timers[0]);
- pr_err("Starting timer to fire in %d ms. (jiffies=%lu)\n",
- CPP_CMD_TIMEOUT_MS, jiffies);
- ret = mod_timer(&cpp_timers[set_timer_idx].cpp_timer,
- jiffies + msecs_to_jiffies(CPP_CMD_TIMEOUT_MS));
- if (ret)
- pr_err("error in mod_timer\n");
-
- set_timer_idx = 1 - set_timer_idx;
- pr_err("Rescheduling for identity=0x%x, frame_id=%03d",
- second_frame->identity, second_frame->frame_id);
- msm_cpp_write(0x6,
- cpp_timers[set_timer_idx].data.cpp_dev->base);
- msm_cpp_dump_frame_cmd(second_frame->cpp_cmd_msg,
- second_frame->msg_len);
- for (i = 0; i < second_frame->msg_len; i++)
- msm_cpp_write(second_frame->cpp_cmd_msg[i],
- cpp_timers[set_timer_idx].data.cpp_dev->base);
- }
+ cpp_timer.data.cpp_dev->base);
+ return;
}
void cpp_timer_callback(unsigned long data)
{
struct msm_cpp_work_t *work =
- cpp_timers[set_timer_idx].data.cpp_dev->work;
- queue_work(cpp_timers[set_timer_idx].data.cpp_dev->timer_wq,
+ cpp_timer.data.cpp_dev->work;
+ queue_work(cpp_timer.data.cpp_dev->timer_wq,
(struct work_struct *)work);
}
@@ -1184,21 +1159,19 @@
msm_enqueue(&cpp_dev->processing_q,
&frame_qcmd->list_frame);
- cpp_timers[set_timer_idx].data.processed_frame = process_frame;
- cpp_timers[set_timer_idx].used = 1;
+ cpp_timer.data.processed_frame = process_frame;
+ atomic_set(&cpp_timer.used, 1);
/* install timer for cpp timeout */
- CPP_DBG("Installing cpp_timer %d\n", set_timer_idx);
- setup_timer(&cpp_timers[set_timer_idx].cpp_timer,
- cpp_timer_callback, (unsigned long)&cpp_timers[0]);
+ CPP_DBG("Installing cpp_timer\n");
+ setup_timer(&cpp_timer.cpp_timer,
+ cpp_timer_callback, (unsigned long)&cpp_timer);
CPP_DBG("Starting timer to fire in %d ms. (jiffies=%lu)\n",
CPP_CMD_TIMEOUT_MS, jiffies);
- ret = mod_timer(&cpp_timers[set_timer_idx].cpp_timer,
+ ret = mod_timer(&cpp_timer.cpp_timer,
jiffies + msecs_to_jiffies(CPP_CMD_TIMEOUT_MS));
if (ret)
pr_err("error in mod_timer\n");
- set_timer_idx = 1 - set_timer_idx;
-
msm_cpp_write(0x6, cpp_dev->base);
msm_cpp_dump_frame_cmd(process_frame->cpp_cmd_msg,
process_frame->msg_len);
@@ -1235,7 +1208,7 @@
uint32_t *cpp_frame_msg;
unsigned long in_phyaddr, out_phyaddr0, out_phyaddr1;
uint16_t num_stripes = 0;
- struct msm_buf_mngr_info buff_mgr_info;
+ struct msm_buf_mngr_info buff_mgr_info, dup_buff_mgr_info;
struct msm_cpp_frame_info_t *u_frame_info =
(struct msm_cpp_frame_info_t *)ioctl_ptr->ioctl_ptr;
int32_t status = 0;
@@ -1285,8 +1258,8 @@
in_phyaddr = msm_cpp_fetch_buffer_info(cpp_dev,
&new_frame->input_buffer_info,
- ((new_frame->identity >> 16) & 0xFFFF),
- (new_frame->identity & 0xFFFF), &in_fd);
+ ((new_frame->input_buffer_info.identity >> 16) & 0xFFFF),
+ (new_frame->input_buffer_info.identity & 0xFFFF), &in_fd);
if (!in_phyaddr) {
pr_err("error gettting input physical address\n");
rc = -EINVAL;
@@ -1322,19 +1295,20 @@
new_frame->duplicate_identity);
memset(&new_frame->output_buffer_info[1], 0,
sizeof(struct msm_cpp_buffer_info_t));
- memset(&buff_mgr_info, 0, sizeof(struct msm_buf_mngr_info));
- buff_mgr_info.session_id =
+ memset(&dup_buff_mgr_info, 0, sizeof(struct msm_buf_mngr_info));
+ dup_buff_mgr_info.session_id =
((new_frame->duplicate_identity >> 16) & 0xFFFF);
- buff_mgr_info.stream_id =
+ dup_buff_mgr_info.stream_id =
(new_frame->duplicate_identity & 0xFFFF);
rc = msm_cpp_buffer_ops(cpp_dev, VIDIOC_MSM_BUF_MNGR_GET_BUF,
- &buff_mgr_info);
+ &dup_buff_mgr_info);
if (rc < 0) {
rc = -EAGAIN;
pr_debug("error getting buffer rc:%d\n", rc);
- goto ERROR2;
+ goto ERROR3;
}
- new_frame->output_buffer_info[1].index = buff_mgr_info.index;
+ new_frame->output_buffer_info[1].index =
+ dup_buff_mgr_info.index;
out_phyaddr1 = msm_cpp_fetch_buffer_info(cpp_dev,
&new_frame->output_buffer_info[1],
((new_frame->duplicate_identity >> 16) & 0xFFFF),
@@ -1343,6 +1317,8 @@
if (!out_phyaddr1) {
pr_err("error gettting output physical address\n");
rc = -EINVAL;
+ msm_cpp_buffer_ops(cpp_dev, VIDIOC_MSM_BUF_MNGR_PUT_BUF,
+ &dup_buff_mgr_info);
goto ERROR3;
}
/* set duplicate enable bit */
@@ -1712,6 +1688,7 @@
struct cpp_device *cpp_dev = v4l2_get_subdevdata(sd);
struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg;
struct msm_cpp_frame_info_t inst_info;
+ memset(&inst_info, 0, sizeof(struct msm_cpp_frame_info_t));
for (i = 0; i < MAX_ACTIVE_CPP_INSTANCE; i++) {
if (cpp_dev->cpp_subscribe_list[i].vfh == vfh) {
inst_info.inst_id = i;
@@ -1887,13 +1864,16 @@
cpp_dev->timer_wq = create_workqueue("msm_cpp_workqueue");
cpp_dev->work = kmalloc(sizeof(struct msm_cpp_work_t),
GFP_KERNEL);
+ if (!cpp_dev->work) {
+ pr_err("cpp_dev->work is NULL\n");
+ rc = -ENOMEM;
+ goto ERROR3;
+ }
INIT_WORK((struct work_struct *)cpp_dev->work, msm_cpp_do_timeout_work);
cpp_dev->cpp_open_cnt = 0;
cpp_dev->is_firmware_loaded = 0;
- cpp_timers[0].data.cpp_dev = cpp_dev;
- cpp_timers[1].data.cpp_dev = cpp_dev;
- cpp_timers[0].used = 0;
- cpp_timers[1].used = 0;
+ cpp_timer.data.cpp_dev = cpp_dev;
+ atomic_set(&cpp_timer.used, 0);
cpp_dev->fw_name_bin = NULL;
return rc;
ERROR3:
diff --git a/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c b/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c
index dc29199..8d14363 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c
@@ -691,43 +691,47 @@
if (queue->len > 0) {
frame_qcmd = msm_dequeue(queue, list_frame);
- processed_frame = frame_qcmd->command;
- do_gettimeofday(&(processed_frame->out_time));
- kfree(frame_qcmd);
- event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_ATOMIC);
- if (!event_qcmd) {
- pr_err("%s: Insufficient memory\n", __func__);
- return -ENOMEM;
- }
- atomic_set(&event_qcmd->on_heap, 1);
- event_qcmd->command = processed_frame;
- VPE_DBG("fid %d\n", processed_frame->frame_id);
- msm_enqueue(&vpe_dev->eventData_q, &event_qcmd->list_eventdata);
+ if(frame_qcmd) {
+ processed_frame = frame_qcmd->command;
+ do_gettimeofday(&(processed_frame->out_time));
+ kfree(frame_qcmd);
+ event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_ATOMIC);
+ if (!event_qcmd) {
+ pr_err("%s: Insufficient memory\n", __func__);
+ return -ENOMEM;
+ }
+ atomic_set(&event_qcmd->on_heap, 1);
+ event_qcmd->command = processed_frame;
+ VPE_DBG("fid %d\n", processed_frame->frame_id);
+ msm_enqueue(&vpe_dev->eventData_q, &event_qcmd->list_eventdata);
- if (!processed_frame->output_buffer_info.processed_divert) {
- memset(&buff_mgr_info, 0 ,
- sizeof(buff_mgr_info));
- buff_mgr_info.session_id =
- ((processed_frame->identity >> 16) & 0xFFFF);
- buff_mgr_info.stream_id =
- (processed_frame->identity & 0xFFFF);
- buff_mgr_info.frame_id = processed_frame->frame_id;
- buff_mgr_info.timestamp = processed_frame->timestamp;
- buff_mgr_info.index =
- processed_frame->output_buffer_info.index;
- rc = msm_vpe_buffer_ops(vpe_dev,
+ if (!processed_frame->output_buffer_info.processed_divert) {
+ memset(&buff_mgr_info, 0 ,
+ sizeof(buff_mgr_info));
+ buff_mgr_info.session_id =
+ ((processed_frame->identity >> 16) & 0xFFFF);
+ buff_mgr_info.stream_id =
+ (processed_frame->identity & 0xFFFF);
+ buff_mgr_info.frame_id = processed_frame->frame_id;
+ buff_mgr_info.timestamp = processed_frame->timestamp;
+ buff_mgr_info.index =
+ processed_frame->output_buffer_info.index;
+ rc = msm_vpe_buffer_ops(vpe_dev,
VIDIOC_MSM_BUF_MNGR_BUF_DONE,
&buff_mgr_info);
- if (rc < 0) {
- pr_err("%s: error doing VIDIOC_MSM_BUF_MNGR_BUF_DONE\n",
- __func__);
- rc = -EINVAL;
+ if (rc < 0) {
+ pr_err("%s: error doing VIDIOC_MSM_BUF_MNGR_BUF_DONE\n",
+ __func__);
+ rc = -EINVAL;
+ }
}
- }
- v4l2_evt.id = processed_frame->inst_id;
- v4l2_evt.type = V4L2_EVENT_VPE_FRAME_DONE;
- v4l2_event_queue(vpe_dev->msm_sd.sd.devnode, &v4l2_evt);
+ v4l2_evt.id = processed_frame->inst_id;
+ v4l2_evt.type = V4L2_EVENT_VPE_FRAME_DONE;
+ v4l2_event_queue(vpe_dev->msm_sd.sd.devnode, &v4l2_evt);
+ }
+ else
+ rc = -EFAULT;
}
return rc;
}
@@ -1368,6 +1372,8 @@
struct msm_vpe_frame_info_t *process_frame;
VPE_DBG("VIDIOC_MSM_VPE_GET_EVENTPAYLOAD\n");
event_qcmd = msm_dequeue(queue, list_eventdata);
+ if (NULL == event_qcmd)
+ break;
process_frame = event_qcmd->command;
VPE_DBG("fid %d\n", process_frame->frame_id);
if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
index bb2b074..ea16ebd 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
@@ -254,6 +254,9 @@
int32_t num_steps = move_params->num_steps;
struct msm_camera_i2c_reg_setting reg_setting;
+ curr_lens_pos = a_ctrl->step_position_table[a_ctrl->curr_step_pos];
+ move_params->curr_lens_pos = curr_lens_pos;
+
if (copy_from_user(&ringing_params_kernel,
&(move_params->ringing_params[a_ctrl->curr_region_index]),
sizeof(struct damping_params_t))) {
@@ -267,7 +270,6 @@
if (dest_step_pos == a_ctrl->curr_step_pos)
return rc;
- curr_lens_pos = a_ctrl->step_position_table[a_ctrl->curr_step_pos];
a_ctrl->i2c_tbl_index = 0;
CDBG("curr_step_pos =%d dest_step_pos =%d curr_lens_pos=%d\n",
a_ctrl->curr_step_pos, dest_step_pos, curr_lens_pos);
@@ -305,6 +307,7 @@
a_ctrl->curr_step_pos = target_step_pos;
}
+ move_params->curr_lens_pos = curr_lens_pos;
reg_setting.reg_setting = a_ctrl->i2c_reg_tbl;
reg_setting.data_type = a_ctrl->i2c_data_type;
reg_setting.size = a_ctrl->i2c_tbl_index;
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
old mode 100644
new mode 100755
index 9384a5b..d8608ae
--- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
@@ -177,6 +177,7 @@
static struct msm_cam_clk_info csiphy_8610_clk_info[] = {
{"csiphy_timer_src_clk", 200000000},
{"csiphy_timer_clk", -1},
+ {"csi_ahb_clk", -1},
};
static struct msm_cam_clk_info csiphy_8974_clk_info[] = {
diff --git a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
index 45db19c..69c1faa 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
@@ -809,6 +809,7 @@
e_ctrl->is_supported = 0;
if (!of_node) {
pr_err("%s dev.of_node NULL\n", __func__);
+ kfree(e_ctrl);
return -EINVAL;
}
@@ -817,6 +818,7 @@
CDBG("cell-index %d, rc %d\n", pdev->id, rc);
if (rc < 0) {
pr_err("failed rc %d\n", rc);
+ kfree(e_ctrl);
return rc;
}
e_ctrl->subdev_id = pdev->id;
@@ -826,12 +828,14 @@
CDBG("qcom,cci-master %d, rc %d\n", e_ctrl->cci_master, rc);
if (rc < 0) {
pr_err("%s failed rc %d\n", __func__, rc);
+ kfree(e_ctrl);
return rc;
}
rc = of_property_read_u32(of_node, "qcom,slave-addr",
&temp);
if (rc < 0) {
pr_err("%s failed rc %d\n", __func__, rc);
+ kfree(e_ctrl);
return rc;
}
@@ -844,6 +848,7 @@
struct msm_camera_cci_client), GFP_KERNEL);
if (!e_ctrl->i2c_client.cci_client) {
pr_err("%s failed no memory\n", __func__);
+ kfree(e_ctrl);
return -ENOMEM;
}
@@ -936,6 +941,7 @@
kfree(e_ctrl->eboard_info);
cciclient_free:
kfree(e_ctrl->i2c_client.cci_client);
+ kfree(e_ctrl);
return rc;
}
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h
index 9f3a81c..a4d7f15 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h
@@ -53,9 +53,11 @@
const char *flash_trigger_name[MAX_LED_TRIGGERS];
struct led_trigger *flash_trigger[MAX_LED_TRIGGERS];
uint32_t flash_op_current[MAX_LED_TRIGGERS];
+ uint32_t flash_max_current[MAX_LED_TRIGGERS];
const char *torch_trigger_name;
struct led_trigger *torch_trigger;
uint32_t torch_op_current;
+ uint32_t torch_max_current;
void *data;
uint32_t num_sources;
enum msm_camera_device_type_t flash_device_type;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
index 01d2c13..b88ac00 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
@@ -51,6 +51,7 @@
int rc = 0;
struct msm_camera_led_cfg_t *cfg = (struct msm_camera_led_cfg_t *)data;
uint32_t i;
+ uint32_t curr_l, max_curr_l;
CDBG("called led_state %d\n", cfg->cfgtype);
if (!fctrl) {
@@ -68,18 +69,38 @@
break;
case MSM_CAMERA_LED_LOW:
- if (fctrl->torch_trigger)
+ if (fctrl->torch_trigger) {
+ max_curr_l = fctrl->torch_max_current;
+ if (cfg->torch_current > 0 &&
+ cfg->torch_current < max_curr_l) {
+ curr_l = cfg->torch_current;
+ } else {
+ curr_l = fctrl->torch_op_current;
+ pr_err("LED current clamped to %d\n",
+ curr_l);
+ }
led_trigger_event(fctrl->torch_trigger,
- fctrl->torch_op_current);
+ curr_l);
+ }
break;
case MSM_CAMERA_LED_HIGH:
if (fctrl->torch_trigger)
led_trigger_event(fctrl->torch_trigger, 0);
for (i = 0; i < fctrl->num_sources; i++)
- if (fctrl->flash_trigger[i])
+ if (fctrl->flash_trigger[i]) {
+ max_curr_l = fctrl->flash_max_current[i];
+ if (cfg->flash_current[i] > 0 &&
+ cfg->flash_current[i] < max_curr_l) {
+ curr_l = cfg->flash_current[i];
+ } else {
+ curr_l = fctrl->flash_op_current[i];
+ pr_err("LED current clamped to %d\n",
+ curr_l);
+ }
led_trigger_event(fctrl->flash_trigger[i],
- fctrl->flash_op_current[i]);
+ curr_l);
+ }
break;
case MSM_CAMERA_LED_INIT:
@@ -116,7 +137,7 @@
static int32_t msm_led_trigger_probe(struct platform_device *pdev)
{
- int32_t rc = 0, i = 0;
+ int32_t rc = 0, rc_1 = 0, i = 0;
struct device_node *of_node = pdev->dev.of_node;
struct device_node *flash_src_node = NULL;
uint32_t count = 0;
@@ -181,7 +202,10 @@
rc = of_property_read_u32(flash_src_node,
"qcom,current",
&fctrl.flash_op_current[i]);
- if (rc < 0) {
+ rc_1 = of_property_read_u32(flash_src_node,
+ "qcom,max-current",
+ &fctrl.flash_max_current[i]);
+ if ((rc < 0) || (rc_1 < 0)) {
pr_err("current: read failed\n");
of_node_put(flash_src_node);
continue;
@@ -229,7 +253,11 @@
rc = of_property_read_u32(flash_src_node,
"qcom,current",
&fctrl.torch_op_current);
- if (rc < 0) {
+ rc_1 = of_property_read_u32(flash_src_node,
+ "qcom,max-current",
+ &fctrl.torch_max_current);
+
+ if ((rc < 0) || (rc_1 < 0)) {
pr_err("current: read failed\n");
goto torch_failed;
}
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c
index 484dd69..336c922 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c
@@ -669,7 +669,9 @@
}
gpio_set_value_cansleep(
ctrl->gpio_conf->gpio_num_info->gpio_num
- [power_setting->seq_val], GPIOF_OUT_INIT_LOW);
+ [power_setting->seq_val],
+ ctrl->gpio_conf->gpio_num_info->gpio_num
+ [power_setting->config_val]);
break;
case SENSOR_VREG:
if (power_setting->seq_val >= CAM_VREG_MAX) {
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
index 0083378..03145c8 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
@@ -1797,6 +1797,8 @@
(struct msm_sensor_ctrl_t *)data;
struct msm_camera_cci_client *cci_client = NULL;
uint32_t session_id;
+ unsigned long mount_pos;
+
s_ctrl->pdev = pdev;
s_ctrl->dev = &pdev->dev;
CDBG("%s called data %p\n", __func__, data);
@@ -1862,6 +1864,11 @@
s_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_SENSOR;
s_ctrl->msm_sd.sd.entity.name =
s_ctrl->msm_sd.sd.name;
+ mount_pos = s_ctrl->sensordata->sensor_init_params->position;
+ mount_pos = mount_pos << 8;
+ mount_pos = mount_pos |
+ (s_ctrl->sensordata->sensor_init_params->sensor_mount_angle / 90);
+ s_ctrl->msm_sd.sd.entity.flags = mount_pos;
rc = camera_init_v4l2(&s_ctrl->pdev->dev, &session_id);
CDBG("%s rc %d session_id %d\n", __func__, rc, session_id);
@@ -1880,6 +1887,8 @@
{
int rc = 0;
uint32_t session_id;
+ unsigned long mount_pos;
+
CDBG("%s %s_i2c_probe called\n", __func__, client->name);
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
pr_err("%s %s i2c_check_functionality failed\n",
@@ -1976,6 +1985,12 @@
s_ctrl->msm_sd.sd.entity.name =
s_ctrl->msm_sd.sd.name;
+ mount_pos = s_ctrl->sensordata->sensor_init_params->position;
+ mount_pos = mount_pos << 8;
+ mount_pos = mount_pos |
+ (s_ctrl->sensordata->sensor_init_params->sensor_mount_angle / 90);
+ s_ctrl->msm_sd.sd.entity.flags = mount_pos;
+
rc = camera_init_v4l2(&s_ctrl->sensor_i2c_client->client->dev,
&session_id);
CDBG("%s rc %d session_id %d\n", __func__, rc, session_id);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/sp1628.c b/drivers/media/platform/msm/camera_v2/sensor/sp1628.c
old mode 100644
new mode 100755
index 82e4b7c..9a422c0
--- a/drivers/media/platform/msm/camera_v2/sensor/sp1628.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/sp1628.c
@@ -866,6 +866,42 @@
}
break;
}
+ case CFG_SET_SATURATION: {
+
+ break;
+ }
+ case CFG_SET_CONTRAST: {
+
+ break;
+ }
+ case CFG_SET_SHARPNESS: {
+
+ break;
+ }
+ case CFG_SET_ISO: {
+
+ break;
+ }
+ case CFG_SET_EXPOSURE_COMPENSATION: {
+
+ break;
+ }
+ case CFG_SET_EFFECT: {
+
+ break;
+ }
+ case CFG_SET_ANTIBANDING: {
+
+ break;
+ }
+ case CFG_SET_BESTSHOT_MODE: {
+
+ break;
+ }
+ case CFG_SET_WHITE_BALANCE: {
+
+ break;
+ }
default:
rc = -EFAULT;
break;
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
index e3a539c..5694658 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
@@ -1933,7 +1933,7 @@
spin_lock(&feed_data->video_buffer_lock);
if (feed_data->video_buffer == NULL) {
- MPQ_DVB_ERR_PRINT(
+ MPQ_DVB_DBG_PRINT(
"%s: video_buffer released\n",
__func__);
spin_unlock(&feed_data->video_buffer_lock);
@@ -2328,7 +2328,7 @@
stream_buffer = feed_data->video_buffer;
if (stream_buffer == NULL) {
- MPQ_DVB_ERR_PRINT("%s: video_buffer released\n", __func__);
+ MPQ_DVB_DBG_PRINT("%s: video_buffer released\n", __func__);
spin_unlock(&feed_data->video_buffer_lock);
return;
}
@@ -2405,7 +2405,7 @@
stream_buffer = feed_data->video_buffer;
if (stream_buffer == NULL) {
- MPQ_DVB_ERR_PRINT("%s: video_buffer released\n", __func__);
+ MPQ_DVB_DBG_PRINT("%s: video_buffer released\n", __func__);
spin_unlock(&feed_data->video_buffer_lock);
return;
}
@@ -2495,7 +2495,7 @@
stream_buffer = feed_data->video_buffer;
if (stream_buffer == NULL) {
- MPQ_DVB_ERR_PRINT(
+ MPQ_DVB_DBG_PRINT(
"%s: video_buffer released\n",
__func__);
spin_unlock(&feed_data->video_buffer_lock);
@@ -2792,7 +2792,8 @@
&(meta_data.info.framing.pts_dts_info));
mpq_dmx_save_pts_dts(feed_data);
- packet.raw_data_len = feed_data->pending_pattern_len;
+ packet.raw_data_len = feed_data->pending_pattern_len -
+ framing_res.info[i].used_prefix_size;
packet.raw_data_offset = feed_data->frame_offset;
meta_data.info.framing.pattern_type =
feed_data->last_framing_match_type;
@@ -2835,11 +2836,51 @@
feed->data_ready_cb.ts(&feed->feed.ts, &data);
- feed_data->pending_pattern_len = 0;
mpq_streambuffer_get_data_rw_offset(
feed_data->video_buffer,
NULL,
&feed_data->frame_offset);
+
+ /*
+ * In linear buffers, after writing the packet
+ * we switched over to a new linear buffer for the new
+ * frame. In that case, we should re-write the prefix
+ * of the existing frame if any exists.
+ */
+ if ((MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR ==
+ feed_data->video_buffer->mode) &&
+ framing_res.info[i].used_prefix_size) {
+ ret = mpq_streambuffer_data_write(stream_buffer,
+ feed_data->prev_pattern +
+ DVB_DMX_MAX_PATTERN_LEN -
+ framing_res.info[i].used_prefix_size,
+ framing_res.info[i].used_prefix_size);
+
+ if (ret < 0) {
+ feed_data->pending_pattern_len = 0;
+ mpq_demux->decoder_drop_count +=
+ framing_res.info[i].used_prefix_size;
+ feed_data->ts_dropped_bytes +=
+ framing_res.info[i].used_prefix_size;
+ } else {
+ feed_data->pending_pattern_len =
+ framing_res.info[i].used_prefix_size;
+ }
+ } else {
+ s32 offset = (s32)feed_data->frame_offset;
+ u32 buff_size =
+ feed_data->video_buffer->buffers[0].size;
+
+ offset -= framing_res.info[i].used_prefix_size;
+ offset += (offset < 0) ? buff_size : 0;
+ feed_data->pending_pattern_len =
+ framing_res.info[i].used_prefix_size;
+
+ if (MPQ_STREAMBUFFER_BUFFER_MODE_RING ==
+ feed_data->video_buffer->mode) {
+ feed_data->frame_offset = (u32)offset;
+ }
+ }
}
/* save the last match for next time */
@@ -2856,11 +2897,23 @@
feed_data->prev_stc = curr_stc;
feed_data->first_prefix_size = 0;
+ /*
+ * Save the trailing of the TS packet as we might have a pattern
+ * split that we need to re-use when closing the next
+ * video linear buffer.
+ */
+ if (MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR ==
+ feed_data->video_buffer->mode)
+ memcpy(feed_data->prev_pattern,
+ buf + 188 - DVB_DMX_MAX_PATTERN_LEN,
+ DVB_DMX_MAX_PATTERN_LEN);
+
if (pending_data_len) {
ret = mpq_streambuffer_data_write(
stream_buffer,
(buf + ts_payload_offset + bytes_written),
pending_data_len);
+
if (ret < 0) {
mpq_demux->decoder_drop_count += pending_data_len;
feed_data->ts_dropped_bytes += pending_data_len;
@@ -2905,7 +2958,7 @@
spin_lock(&feed_data->video_buffer_lock);
stream_buffer = feed_data->video_buffer;
if (stream_buffer == NULL) {
- MPQ_DVB_ERR_PRINT(
+ MPQ_DVB_DBG_PRINT(
"%s: video_buffer released\n",
__func__);
spin_unlock(&feed_data->video_buffer_lock);
@@ -3268,7 +3321,7 @@
stream_buffer = feed_data->video_buffer;
if (stream_buffer == NULL) {
- MPQ_DVB_ERR_PRINT("%s: video_buffer released\n", __func__);
+ MPQ_DVB_DBG_PRINT("%s: video_buffer released\n", __func__);
spin_unlock(&feed_data->video_buffer_lock);
return 0;
}
@@ -3911,6 +3964,58 @@
}
EXPORT_SYMBOL(mpq_dmx_set_cipher_ops);
+static int mpq_sdmx_invalidate_buffer(struct mpq_feed *mpq_feed)
+{
+ struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed;
+ struct mpq_video_feed_info *feed_data;
+ struct dvb_ringbuffer *buffer;
+ struct ion_handle *ion_handle;
+ int ret = 0;
+ int i;
+
+ if (!dvb_dmx_is_video_feed(feed)) {
+ if (dvb_dmx_is_sec_feed(feed) ||
+ dvb_dmx_is_pcr_feed(feed)) {
+ buffer = (struct dvb_ringbuffer *)
+ &mpq_feed->sdmx_buf;
+ ion_handle = mpq_feed->sdmx_buf_handle;
+ } else {
+ buffer = (struct dvb_ringbuffer *)
+ feed->feed.ts.buffer.ringbuff;
+ ion_handle = feed->feed.ts.buffer.priv_handle;
+ }
+
+ ret = msm_ion_do_cache_op(mpq_feed->mpq_demux->ion_client,
+ ion_handle, buffer->data,
+ buffer->size, ION_IOC_INV_CACHES);
+ if (ret)
+ MPQ_DVB_ERR_PRINT(
+ "%s: msm_ion_do_cache_op failed, ret = %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ /* Video buffers */
+ feed_data = &mpq_feed->video_info;
+ for (i = 0; i < feed_data->buffer_desc.decoder_buffers_num; i++) {
+ if (feed_data->buffer_desc.desc[i].base) {
+ /* Non-secured buffer */
+ ret = msm_ion_do_cache_op(
+ mpq_feed->mpq_demux->ion_client,
+ feed_data->buffer_desc.ion_handle[i],
+ feed_data->buffer_desc.desc[i].base,
+ feed_data->buffer_desc.desc[i].size,
+ ION_IOC_INV_CACHES);
+ if (ret)
+ MPQ_DVB_ERR_PRINT(
+ "%s: msm_ion_do_cache_op failed, ret = %d\n",
+ __func__, ret);
+ }
+ }
+
+ return ret;
+}
+
static void mpq_sdmx_prepare_filter_status(struct mpq_demux *mpq_demux,
struct sdmx_filter_status *filter_sts,
struct mpq_feed *mpq_feed)
@@ -3960,7 +4065,7 @@
spin_lock(&mpq_feed->video_info.video_buffer_lock);
sbuff = feed_data->video_buffer;
if (sbuff == NULL) {
- MPQ_DVB_ERR_PRINT(
+ MPQ_DVB_DBG_PRINT(
"%s: video_buffer released\n",
__func__);
spin_unlock(&feed_data->video_buffer_lock);
@@ -4036,6 +4141,13 @@
__func__);
return ret;
}
+
+ if (mpq_feed->sdmx_filter_handle ==
+ SDMX_INVALID_FILTER_HANDLE) {
+ MPQ_DVB_DBG_PRINT("%s: filter was stopped\n",
+ __func__);
+ return -ENODEV;
+ }
}
if (mpq_feed->sdmx_buf.pread + header->payload_length <
@@ -4089,6 +4201,13 @@
mutex_lock(&mpq_demux->mutex);
+ if (mpq_feed->sdmx_filter_handle ==
+ SDMX_INVALID_FILTER_HANDLE) {
+ MPQ_DVB_DBG_PRINT("%s: filter was stopped\n",
+ __func__);
+ return -ENODEV;
+ }
+
return ret;
}
@@ -4449,13 +4568,21 @@
sbuf = mpq_feed->video_info.video_buffer;
if (sbuf == NULL) {
- MPQ_DVB_ERR_PRINT(
+ MPQ_DVB_DBG_PRINT(
"%s: video_buffer released\n",
__func__);
spin_unlock(&mpq_feed->video_info.video_buffer_lock);
return;
}
+ if (!header.payload_length) {
+ MPQ_DVB_DBG_PRINT(
+ "%s: warnning - video frame with 0 length, dropping\n",
+ __func__);
+ spin_unlock(&mpq_feed->video_info.video_buffer_lock);
+ continue;
+ }
+
packet.raw_data_len = header.payload_length;
packet.user_data_len = sizeof(meta_data);
mpq_streambuffer_get_buffer_handle(sbuf, 0,
@@ -4682,6 +4809,9 @@
mpq_feed->session_id))
continue;
+ /* Invalidate output buffer before processing the results */
+ mpq_sdmx_invalidate_buffer(mpq_feed);
+
if (sts->error_indicators & SDMX_FILTER_ERR_MD_BUF_FULL)
MPQ_DVB_ERR_PRINT(
"%s: meta-data buff for pid %d overflowed!\n",
@@ -4756,7 +4886,6 @@
for (i = 0; i < MPQ_MAX_DMX_FILES; i++) {
mpq_feed = &mpq_demux->feeds[i];
if ((mpq_feed->sdmx_filter_handle != SDMX_INVALID_FILTER_HANDLE)
- && (mpq_feed->dvb_demux_feed->state == DMX_STATE_GO)
&& (!mpq_feed->secondary_feed)) {
sts = mpq_demux->sdmx_filters_state.status +
filter_index;
@@ -4875,6 +5004,10 @@
const char *buf,
size_t count)
{
+ struct ion_handle *ion_handle =
+ mpq_demux->demux.dmx.dvr_input.priv_handle;
+ struct dvb_ringbuffer *rbuf = (struct dvb_ringbuffer *)
+ mpq_demux->demux.dmx.dvr_input.ringbuff;
struct sdmx_buff_descr buf_desc;
u32 read_offset;
int ret;
@@ -4893,6 +5026,19 @@
}
read_offset = mpq_demux->demux.dmx.dvr_input.ringbuff->pread;
+
+ /*
+ * We must flush the buffer before SDMX starts reading from it
+ * so that it gets a valid data in memory.
+ */
+ ret = msm_ion_do_cache_op(mpq_demux->ion_client,
+ ion_handle, rbuf->data,
+ rbuf->size, ION_IOC_CLEAN_CACHES);
+ if (ret)
+ MPQ_DVB_ERR_PRINT(
+ "%s: msm_ion_do_cache_op failed, ret = %d\n",
+ __func__, ret);
+
return mpq_sdmx_process(mpq_demux, &buf_desc, count,
read_offset, mpq_demux->demux.ts_packet_size);
}
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.h b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.h
index adc4261..b362c5b 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.h
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.h
@@ -238,6 +238,7 @@
* with this stream buffer.
* @patterns: pointer to the framing patterns to look for.
* @patterns_num: number of framing patterns.
+ * @prev_pattern: holds the trailing data of the last processed video packet.
* @frame_offset: Saves data buffer offset to which a new frame will be written
* @last_pattern_offset: Holds the previous pattern offset
* @pending_pattern_len: Accumulated number of data bytes that will be
@@ -288,6 +289,7 @@
const struct dvb_dmx_video_patterns
*patterns[DVB_DMX_MAX_SEARCH_PATTERN_NUM];
int patterns_num;
+ char prev_pattern[DVB_DMX_MAX_PATTERN_LEN];
u32 frame_offset;
u32 last_pattern_offset;
u32 pending_pattern_len;
diff --git a/drivers/media/platform/msm/vcap/Kconfig b/drivers/media/platform/msm/vcap/Kconfig
index 2bdcfbd..db3bc47 100644
--- a/drivers/media/platform/msm/vcap/Kconfig
+++ b/drivers/media/platform/msm/vcap/Kconfig
@@ -1,7 +1,6 @@
config MSM_VCAP
tristate "Qualcomm MSM VCAP"
depends on VIDEO_DEV && VIDEO_V4L2
- default y
---help---
Enables VCAP driver. This device allows for video capture and
video processing using the v4l2 api
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index 30ada3e..4da0f6f 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -553,6 +553,7 @@
pkt->alloc_len = output_frame->alloc_len;
pkt->filled_len = output_frame->filled_len;
pkt->offset = output_frame->offset;
+ pkt->rgData[0] = output_frame->extradata_size;
dprintk(VIDC_DBG, "### Q OUTPUT BUFFER ###: %d, %d, %d\n",
pkt->alloc_len, pkt->filled_len, pkt->offset);
@@ -564,7 +565,7 @@
u32 session_id, struct vidc_seq_hdr *seq_hdr)
{
int rc = 0;
- if (!pkt || !session_id || seq_hdr)
+ if (!pkt || !session_id || !seq_hdr)
return -EINVAL;
pkt->size = sizeof(struct hfi_cmd_session_parse_sequence_header_packet);
@@ -803,7 +804,8 @@
pkt->rg_property_data[0] =
HFI_PROPERTY_PARAM_VDEC_PICTURE_TYPE_DECODE;
hfi = (struct hfi_enable_picture *) &pkt->rg_property_data[1];
- hfi->picture_type = (u32) pdata;
+ hfi->picture_type =
+ ((struct hfi_enable_picture *)pdata)->picture_type;
pkt->size += sizeof(u32) * 2;
break;
}
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index abdb039..189fca0 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -263,7 +263,9 @@
break;
case HFI_EVENT_RELEASE_BUFFER_REFERENCE:
dprintk(VIDC_INFO, "HFI_EVENT_RELEASE_BUFFER_REFERENCE\n");
- hfi_process_evt_release_buffer_ref(callback, device_id, pkt);
+ if (!validate_session_pkt(sessions, sess, session_lock))
+ hfi_process_evt_release_buffer_ref(callback,
+ device_id, pkt);
break;
default:
dprintk(VIDC_WARN, "hal_process_event_notify:unkown_event_id");
@@ -1183,42 +1185,78 @@
callback(SESSION_GET_SEQ_HDR_DONE, &data_done);
}
-void hfi_process_sys_property_info(
- struct hfi_property_sys_image_version_info_type *pkt)
+static void hfi_process_sys_get_prop_image_version(
+ struct hfi_msg_sys_property_info_packet *pkt)
{
int i = 0;
u32 smem_block_size = 0;
u8 *smem_table_ptr;
char version[256];
+ const u32 version_string_size = 128;
const u32 smem_image_index_venus = 14 * 128;
+ u8 *str_image_version;
+ int req_bytes;
- if (!pkt || !pkt->string_size) {
+ req_bytes = pkt->size - sizeof(*pkt);
+ if (req_bytes < version_string_size ||
+ !pkt->rg_property_data[1] ||
+ pkt->num_properties > 1) {
+ dprintk(VIDC_ERR,
+ "hfi_process_sys_get_prop_image_version:bad_pkt: %d",
+ req_bytes);
+ return;
+ }
+ str_image_version = (u8 *)&pkt->rg_property_data[1];
+ /*
+ * The version string returned by firmware includes null
+ * characters at the start and in between. Replace the null
+ * characters with space, to print the version info.
+ */
+ for (i = 0; i < version_string_size; i++) {
+ if (str_image_version[i] != '\0')
+ version[i] = str_image_version[i];
+ else
+ version[i] = ' ';
+ }
+ version[i] = '\0';
+ dprintk(VIDC_DBG, "F/W version: %s\n", version);
+
+ smem_table_ptr = smem_get_entry(SMEM_IMAGE_VERSION_TABLE,
+ &smem_block_size);
+ if (smem_table_ptr &&
+ ((smem_image_index_venus +
+ version_string_size) <= smem_block_size))
+ memcpy(smem_table_ptr + smem_image_index_venus,
+ str_image_version, version_string_size);
+}
+
+static void hfi_process_sys_property_info(
+ struct hfi_msg_sys_property_info_packet *pkt)
+{
+ if (!pkt) {
dprintk(VIDC_ERR, "%s: invalid param\n", __func__);
return;
}
-
- if (pkt->string_size < sizeof(version)) {
- /*
- * The version string returned by firmware includes null
- * characters at the start and in between. Replace the null
- * characters with space, to print the version info.
- */
- for (i = 0; i < pkt->string_size; i++) {
- if (pkt->str_image_version[i] != '\0')
- version[i] = pkt->str_image_version[i];
- else
- version[i] = ' ';
- }
- version[i] = '\0';
- dprintk(VIDC_DBG, "F/W version: %s\n", version);
+ if (pkt->size < sizeof(*pkt)) {
+ dprintk(VIDC_ERR,
+ "hfi_process_sys_property_info: bad_pkt_size\n");
+ return;
+ }
+ if (pkt->num_properties == 0) {
+ dprintk(VIDC_ERR,
+ "hfi_process_sys_property_info: no_properties\n");
+ return;
}
- smem_table_ptr = smem_get_entry(SMEM_IMAGE_VERSION_TABLE,
- &smem_block_size);
- if (smem_table_ptr &&
- ((smem_image_index_venus + 128) <= smem_block_size))
- memcpy(smem_table_ptr + smem_image_index_venus,
- (u8 *)pkt->str_image_version, 128);
+ switch (pkt->rg_property_data[0]) {
+ case HFI_PROPERTY_SYS_IMAGE_VERSION:
+ hfi_process_sys_get_prop_image_version(pkt);
+ break;
+ default:
+ dprintk(VIDC_ERR,
+ "hfi_process_sys_property_info:unknown_prop_id: %d\n",
+ pkt->rg_property_data[0]);
+ }
}
u32 hfi_process_msg_packet(
@@ -1263,7 +1301,7 @@
break;
case HFI_MSG_SYS_PROPERTY_INFO:
hfi_process_sys_property_info(
- (struct hfi_property_sys_image_version_info_type *)
+ (struct hfi_msg_sys_property_info_packet *)
msg_hdr);
break;
case HFI_MSG_SYS_SESSION_END_DONE:
diff --git a/drivers/media/platform/msm/vidc/msm_smem.c b/drivers/media/platform/msm/vidc/msm_smem.c
index 5140a03..9604a09 100644
--- a/drivers/media/platform/msm/vidc/msm_smem.c
+++ b/drivers/media/platform/msm/vidc/msm_smem.c
@@ -171,8 +171,10 @@
mem->smem_priv = hndl;
mem->device_addr = iova;
mem->size = buffer_size;
- dprintk(VIDC_DBG, "NOTE: Buffer device address: 0x%lx, size: %d\n",
- mem->device_addr, mem->size);
+ dprintk(VIDC_DBG,
+ "%s: ion_handle = 0x%p, fd = %d, device_addr = 0x%x, size = %d, kvaddr = 0x%p, buffer_type = %d\n",
+ __func__, mem->smem_priv, fd, (u32)mem->device_addr,
+ mem->size, mem->kvaddr, mem->buffer_type);
return rc;
fail_device_address:
ion_free(client->clnt, hndl);
@@ -241,10 +243,11 @@
goto fail_device_address;
}
mem->device_addr = iova;
- dprintk(VIDC_DBG,
- "device_address = 0x%lx, kvaddr = 0x%p, size = %d\n",
- mem->device_addr, mem->kvaddr, size);
mem->size = size;
+ dprintk(VIDC_DBG,
+ "%s: ion_handle = 0x%p, device_addr = 0x%x, size = %d, kvaddr = 0x%p, buffer_type = %d\n",
+ __func__, mem->smem_priv, (u32)mem->device_addr,
+ mem->size, mem->kvaddr, mem->buffer_type);
return rc;
fail_device_address:
ion_unmap_kernel(client->clnt, hndl);
@@ -258,6 +261,10 @@
{
int domain, partition, rc;
+ dprintk(VIDC_DBG,
+ "%s: ion_handle = 0x%p, device_addr = 0x%x, size = %d, kvaddr = 0x%p, buffer_type = %d\n",
+ __func__, mem->smem_priv, (u32)mem->device_addr,
+ mem->size, mem->kvaddr, mem->buffer_type);
rc = msm_smem_get_domain_partition((void *)client, mem->flags,
mem->buffer_type, &domain, &partition);
if (rc) {
diff --git a/drivers/media/platform/msm/vidc/msm_smem.h b/drivers/media/platform/msm/vidc/msm_smem.h
index 7bd6443..ca92e73 100644
--- a/drivers/media/platform/msm/vidc/msm_smem.h
+++ b/drivers/media/platform/msm/vidc/msm_smem.h
@@ -28,41 +28,6 @@
SMEM_SECURE = ION_FLAG_SECURE,
};
-/* NOTE: if you change this enum you MUST update the
- * "buffer-type-tz-usage-table" for any affected target
- * in arch/arm/boot/dts/<arch>.dtsi
- */
-enum hal_buffer {
- HAL_BUFFER_INPUT = 0x1,
- HAL_BUFFER_OUTPUT = 0x2,
- HAL_BUFFER_OUTPUT2 = 0x4,
- HAL_BUFFER_EXTRADATA_INPUT = 0x8,
- HAL_BUFFER_EXTRADATA_OUTPUT = 0x10,
- HAL_BUFFER_EXTRADATA_OUTPUT2 = 0x20,
- HAL_BUFFER_INTERNAL_SCRATCH = 0x40,
- HAL_BUFFER_INTERNAL_SCRATCH_1 = 0x80,
- HAL_BUFFER_INTERNAL_SCRATCH_2 = 0x100,
- HAL_BUFFER_INTERNAL_PERSIST = 0x200,
- HAL_BUFFER_INTERNAL_PERSIST_1 = 0x400,
- HAL_BUFFER_INTERNAL_CMD_QUEUE = 0x800,
-};
-
-struct msm_smem {
- int mem_type;
- size_t size;
- void *kvaddr;
- unsigned long device_addr;
- u32 flags;
- void *smem_priv;
- enum hal_buffer buffer_type;
-};
-
-enum smem_cache_ops {
- SMEM_CACHE_CLEAN,
- SMEM_CACHE_INVALIDATE,
- SMEM_CACHE_CLEAN_INVALIDATE,
-};
-
void *msm_smem_new_client(enum smem_type mtype,
struct msm_vidc_platform_resources *res);
struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags,
@@ -73,7 +38,6 @@
enum smem_cache_ops);
struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset,
enum hal_buffer buffer_type);
-int msm_smem_clean_invalidate(void *clt, struct msm_smem *mem);
int msm_smem_get_domain_partition(void *clt, u32 flags, enum hal_buffer
buffer_type, int *domain_num, int *partition_num);
#endif
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index f4fdfe7..7e24510 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -22,7 +22,7 @@
#define MSM_VDEC_DVC_NAME "msm_vdec_8974"
#define MIN_NUM_OUTPUT_BUFFERS 4
#define MAX_NUM_OUTPUT_BUFFERS 6
-#define DEFAULT_CONCEAL_COLOR 0x0
+#define DEFAULT_VIDEO_CONCEAL_COLOR_BLACK 0x8080
#define TZ_INFO_GET_FEATURE_VERSION_ID 0x3
#define TZ_DYNAMIC_BUFFER_FEATURE_ID 12
@@ -323,6 +323,16 @@
.qmenu = NULL,
.cluster = 0,
},
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR,
+ .name = "Picture concealed color",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0x0,
+ .maximum = 0xffffff,
+ .default_value = DEFAULT_VIDEO_CONCEAL_COLOR_BLACK,
+ .step = 1,
+ .cluster = 0,
+ },
};
#define NUM_CTRLS ARRAY_SIZE(msm_vdec_ctrls)
@@ -686,6 +696,7 @@
int msm_vdec_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
{
const struct msm_vidc_format *fmt = NULL;
+ unsigned int *plane_sizes = NULL;
struct hfi_device *hdev;
int stride, scanlines;
int extra_idx = 0;
@@ -741,9 +752,19 @@
goto exit;
}
if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ plane_sizes =
+ &inst->bufq[OUTPUT_PORT].vb2_bufq.plane_sizes[0];
for (i = 0; i < fmt->num_planes; ++i) {
- f->fmt.pix_mp.plane_fmt[i].sizeimage =
- inst->bufq[OUTPUT_PORT].vb2_bufq.plane_sizes[i];
+ if (plane_sizes[i] == 0) {
+ f->fmt.pix_mp.plane_fmt[i].sizeimage =
+ fmt->get_frame_size(i,
+ inst->capability.height.max,
+ inst->capability.width.max);
+ plane_sizes[i] =
+ f->fmt.pix_mp.plane_fmt[i].sizeimage;
+ } else
+ f->fmt.pix_mp.plane_fmt[i].sizeimage =
+ plane_sizes[i];
}
} else {
switch (fmt->fourcc) {
@@ -960,6 +981,20 @@
rc = -EINVAL;
goto err_invalid_fmt;
}
+ rc = msm_comm_try_state(inst, MSM_VIDC_CORE_INIT_DONE);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to initialize instance\n");
+ goto err_invalid_fmt;
+ }
+ if (!(get_hal_codec_type(fmt->fourcc) &
+ inst->core->dec_codec_supported)) {
+ dprintk(VIDC_ERR,
+ "Codec(0x%x) is not present in the supported codecs list(0x%x)\n",
+ get_hal_codec_type(fmt->fourcc),
+ inst->core->dec_codec_supported);
+ rc = -EINVAL;
+ goto err_invalid_fmt;
+ }
inst->fmts[fmt->type] = fmt;
rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
if (rc) {
@@ -979,8 +1014,10 @@
inst->capability.height.max,
inst->capability.width.max);
- if (f->fmt.pix_mp.plane_fmt[0].sizeimage > max_input_size)
+ if (f->fmt.pix_mp.plane_fmt[0].sizeimage > max_input_size ||
+ f->fmt.pix_mp.plane_fmt[0].sizeimage == 0) {
f->fmt.pix_mp.plane_fmt[0].sizeimage = max_input_size;
+ }
f->fmt.pix_mp.num_planes = fmt->num_planes;
for (i = 0; i < fmt->num_planes; ++i) {
@@ -1298,7 +1335,6 @@
{
struct msm_vidc_inst *inst;
int rc = 0;
- int pdata = DEFAULT_CONCEAL_COLOR;
struct hfi_device *hdev;
if (!q || !q->drv_priv) {
dprintk(VIDC_ERR, "Invalid input, q = %p\n", q);
@@ -1316,10 +1352,6 @@
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
if (inst->bufq[CAPTURE_PORT].vb2_bufq.streaming)
rc = start_streaming(inst);
- rc = call_hfi_op(hdev, session_set_property,
- (void *) inst->session,
- HAL_PARAM_VDEC_CONCEAL_COLOR,
- (void *) &pdata);
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
if (inst->bufq[OUTPUT_PORT].vb2_bufq.streaming)
@@ -1389,7 +1421,19 @@
}
switch (dec->cmd) {
case V4L2_DEC_QCOM_CMD_FLUSH:
+ if (core->state != VIDC_CORE_INVALID &&
+ inst->state == MSM_VIDC_CORE_INVALID) {
+ rc = msm_comm_recover_from_session_error(inst);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "Failed to recover from session_error: %d\n",
+ rc);
+ }
rc = msm_comm_flush(inst, dec->flags);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to flush buffers: %d\n", rc);
+ }
break;
case V4L2_DEC_CMD_STOP:
if (core->state != VIDC_CORE_INVALID &&
@@ -1711,6 +1755,11 @@
break;
}
break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR:
+ property_id = HAL_PARAM_VDEC_CONCEAL_COLOR;
+ property_val = ctrl->val;
+ pdata = &property_val;
+ break;
default:
break;
}
@@ -1807,7 +1856,7 @@
int msm_vdec_ctrl_init(struct msm_vidc_inst *inst)
{
int idx = 0;
- struct v4l2_ctrl_config ctrl_cfg;
+ struct v4l2_ctrl_config ctrl_cfg = {0};
int ret_val = 0;
ret_val = v4l2_ctrl_handler_init(&inst->ctrl_handler, NUM_CTRLS);
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index f9b5519..c0bf32c 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -2662,7 +2662,7 @@
{
int idx = 0;
- struct v4l2_ctrl_config ctrl_cfg;
+ struct v4l2_ctrl_config ctrl_cfg = {0};
int ret_val = 0;
ret_val = v4l2_ctrl_handler_init(&inst->ctrl_handler, NUM_CTRLS);
if (ret_val) {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 6ed94e4..a9521a1 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -356,7 +356,7 @@
struct v4l2_plane *p, enum hal_buffer buffer_type)
{
struct msm_smem *handle = NULL;
- handle = msm_smem_user_to_kernel(inst->mem_client,
+ handle = msm_comm_smem_user_to_kernel(inst,
p->reserved[0],
p->reserved[1],
buffer_type);
@@ -365,7 +365,7 @@
"%s: Failed to get device buffer address\n", __func__);
return NULL;
}
- if (msm_smem_cache_operations(inst->mem_client, handle,
+ if (msm_comm_smem_cache_operations(inst, handle,
SMEM_CACHE_CLEAN))
dprintk(VIDC_WARN,
"CACHE Clean failed: %d, %d, %d\n",
@@ -489,6 +489,7 @@
temp->handle[plane]->device_addr + binfo->buff_off[i];
b->m.planes[i].m.userptr = binfo->device_addr[i];
binfo->mapped[i] = false;
+ binfo->handle[i] = temp->handle[i];
} else {
if (inst->map_output_buffer) {
binfo->handle[i] =
@@ -498,9 +499,6 @@
rc = -EINVAL;
goto exit;
}
- dprintk(VIDC_DBG,
- "[MAP] - mapped handle[%d] = %p fd[%d] = %d",
- i, binfo->handle[i], i, binfo->fd[i]);
binfo->mapped[i] = true;
binfo->device_addr[i] =
binfo->handle[i]->device_addr +
@@ -511,10 +509,6 @@
binfo->device_addr[i] =
b->m.planes[i].m.userptr;
}
- dprintk(VIDC_DBG, "Registering buffer: %d, %d, %d\n",
- b->m.planes[i].reserved[0],
- b->m.planes[i].reserved[1],
- b->m.planes[i].length);
}
/* We maintain one ref count for all planes*/
if ((i == 0) && is_dynamic_output_buffer_mode(b, inst)) {
@@ -522,8 +516,12 @@
if (rc < 0)
return rc;
}
+ dprintk(VIDC_DBG,
+ "%s: [MAP] binfo = %p, handle[%d] = %p, device_addr = 0x%x, fd = %d, offset = %d, mapped = %d\n",
+ __func__, binfo, i, binfo->handle[i],
+ binfo->device_addr[i], binfo->fd[i],
+ binfo->buff_off[i], binfo->mapped[i]);
}
- dprintk(VIDC_DBG, "[MAP] Adding binfo = %p to list\n", binfo);
mutex_lock(&inst->lock);
list_add_tail(&binfo->list, &inst->registered_bufs);
mutex_unlock(&inst->lock);
@@ -570,6 +568,11 @@
goto exit;
for (i = 0; i < temp->num_planes; i++) {
+ dprintk(VIDC_DBG,
+ "%s: [UNMAP] binfo = %p, handle[%d] = %p, device_addr = 0x%x, fd = %d, offset = %d, mapped = %d\n",
+ __func__, temp, i, temp->handle[i],
+ temp->device_addr[i], temp->fd[i],
+ temp->buff_off[i], temp->mapped[i]);
/*
* Unmap the handle only if the buffer has been mapped and no
* other buffer has a reference to this buffer.
@@ -584,7 +587,7 @@
dprintk(VIDC_DBG,
"[UNMAP] - handle[%d] = %p fd[%d] = %d",
i, temp->handle[i], i, temp->fd[i]);
- msm_smem_free(inst->mem_client,
+ msm_comm_smem_free(inst,
temp->handle[i]);
}
@@ -660,7 +663,7 @@
for (i = 0; i < binfo->num_planes; i++) {
if (binfo->handle[i]) {
- rc = msm_smem_cache_operations(inst->mem_client,
+ rc = msm_comm_smem_cache_operations(inst,
binfo->handle[i], SMEM_CACHE_INVALIDATE);
if (rc) {
dprintk(VIDC_ERR,
@@ -668,7 +671,8 @@
__func__, rc);
return -EINVAL;
}
- }
+ } else
+ dprintk(VIDC_ERR, "%s: WARN: NULL handle", __func__);
}
return 0;
}
@@ -713,6 +717,8 @@
return -EINVAL;
list_for_each_safe(ptr, next, &inst->registered_bufs) {
+ bool release_buf = false;
+ mutex_lock(&inst->lock);
bi = list_entry(ptr, struct buffer_info, list);
if (bi->type == buffer_type) {
buffer_info.type = bi->type;
@@ -730,27 +736,44 @@
buffer_info.m.planes[i].length);
}
buffer_info.length = bi->num_planes;
- if (inst->session_type == MSM_VIDC_DECODER)
- rc = msm_vdec_release_buf(instance,
- &buffer_info);
- if (inst->session_type == MSM_VIDC_ENCODER)
- rc = msm_venc_release_buf(instance,
- &buffer_info);
- if (rc)
- dprintk(VIDC_ERR,
- "Failed Release buffer: %d, %d, %d\n",
- buffer_info.m.planes[0].reserved[0],
- buffer_info.m.planes[0].reserved[1],
- buffer_info.m.planes[0].length);
+ release_buf = true;
+ }
+ mutex_unlock(&inst->lock);
+ if (!release_buf)
+ continue;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ rc = msm_vdec_release_buf(instance,
+ &buffer_info);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ rc = msm_venc_release_buf(instance,
+ &buffer_info);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "Failed Release buffer: %d, %d, %d\n",
+ buffer_info.m.planes[0].reserved[0],
+ buffer_info.m.planes[0].reserved[1],
+ buffer_info.m.planes[0].length);
+ }
+ mutex_lock(&inst->lock);
+ list_for_each_safe(ptr, next, &inst->registered_bufs) {
+ bi = list_entry(ptr, struct buffer_info, list);
+ if (bi->type == buffer_type) {
list_del(&bi->list);
for (i = 0; i < bi->num_planes; i++) {
- if (bi->handle[i])
- msm_smem_free(inst->mem_client,
+ if (bi->handle[i] && bi->mapped[i]) {
+ dprintk(VIDC_DBG,
+ "%s: [UNMAP] binfo = %p, handle[%d] = %p, device_addr = 0x%x, fd = %d, offset = %d, mapped = %d\n",
+ __func__, bi, i, bi->handle[i],
+ bi->device_addr[i], bi->fd[i],
+ bi->buff_off[i], bi->mapped[i]);
+ msm_comm_smem_free(inst,
bi->handle[i]);
+ }
}
kfree(bi);
}
}
+ mutex_unlock(&inst->lock);
return rc;
}
@@ -824,7 +847,7 @@
if ((inst->fmts[OUTPUT_PORT]->fourcc ==
V4L2_PIX_FMT_HEVC_HYBRID) && binfo->handle[i] &&
(b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) {
- rc = msm_smem_cache_operations(inst->mem_client,
+ rc = msm_comm_smem_cache_operations(inst,
binfo->handle[i], SMEM_CACHE_INVALIDATE);
if (rc) {
dprintk(VIDC_ERR,
@@ -835,7 +858,7 @@
if (binfo->handle[i] &&
(b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) {
- rc = msm_smem_cache_operations(inst->mem_client,
+ rc = msm_comm_smem_cache_operations(inst,
binfo->handle[i], SMEM_CACHE_CLEAN);
if (rc) {
dprintk(VIDC_ERR,
@@ -970,6 +993,57 @@
fsize->stepwise.step_height = capability->height.step_size;
return 0;
}
+
+struct msm_smem *msm_vidc_smem_alloc(void *instance,
+ size_t size, u32 align, u32 flags,
+ enum hal_buffer buffer_type, int map_kernel)
+{
+ return msm_comm_smem_alloc((struct msm_vidc_inst *)instance,
+ size, align, flags, buffer_type, map_kernel);
+
+}
+
+void msm_vidc_smem_free(void *instance, struct msm_smem *mem)
+{
+ msm_comm_smem_free((struct msm_vidc_inst *)instance, mem);
+}
+
+int msm_vidc_smem_cache_operations(void *instance, struct msm_smem *mem,
+ enum smem_cache_ops cache_ops)
+{
+ return msm_comm_smem_cache_operations(
+ (struct msm_vidc_inst *)instance, mem, cache_ops);
+}
+
+struct msm_smem *msm_vidc_smem_user_to_kernel(void *instance, int fd,
+ u32 offset, enum hal_buffer buffer_type)
+{
+ return msm_comm_smem_user_to_kernel(
+ (struct msm_vidc_inst *)instance,
+ fd, offset, buffer_type);
+}
+
+int msm_vidc_smem_get_domain_partition(void *instance, u32 flags,
+ enum hal_buffer buffer_type, int *domain_num,
+ int *partition_num)
+{
+ return msm_comm_smem_get_domain_partition(
+ (struct msm_vidc_inst *)instance,
+ flags, buffer_type, domain_num, partition_num);
+}
+
+void *msm_vidc_smem_get_client(void *instance)
+{
+ struct msm_vidc_inst *inst = instance;
+
+ if (!inst || !inst->mem_client) {
+ dprintk(VIDC_ERR, "%s: invalid instance or client = %p %p\n",
+ __func__, inst, inst->mem_client);
+ return NULL;
+ }
+
+ return inst->mem_client;
+}
static void *vidc_get_userptr(void *alloc_ctx, unsigned long vaddr,
unsigned long size, int write)
{
@@ -1014,8 +1088,6 @@
{
int rc = 0;
struct msm_vidc_inst *vidc_inst = (struct msm_vidc_inst *)inst;
- spin_lock_init(&pvdev->fh_lock);
- INIT_LIST_HEAD(&pvdev->fh_list);
v4l2_fh_init(&vidc_inst->event_handler, pvdev);
v4l2_fh_add(&vidc_inst->event_handler);
@@ -1189,7 +1261,7 @@
list);
list_del(&buf->list);
mutex_unlock(&inst->lock);
- msm_smem_free(inst->mem_client, buf->handle);
+ msm_comm_smem_free(inst, buf->handle);
kfree(buf);
mutex_lock(&inst->lock);
}
@@ -1200,7 +1272,7 @@
list);
list_del(&buf->list);
mutex_unlock(&inst->lock);
- msm_smem_free(inst->mem_client, buf->handle);
+ msm_comm_smem_free(inst, buf->handle);
kfree(buf);
mutex_lock(&inst->lock);
}
@@ -1211,14 +1283,14 @@
list);
list_del(&buf->list);
mutex_unlock(&inst->lock);
- msm_smem_free(inst->mem_client, buf->handle);
+ msm_comm_smem_free(inst, buf->handle);
kfree(buf);
mutex_lock(&inst->lock);
}
}
if (inst->extradata_handle) {
mutex_unlock(&inst->lock);
- msm_smem_free(inst->mem_client, inst->extradata_handle);
+ msm_comm_smem_free(inst, inst->extradata_handle);
mutex_lock(&inst->lock);
}
mutex_unlock(&inst->lock);
@@ -1240,6 +1312,7 @@
if (!inst)
return -EINVAL;
+ v4l2_fh_del(&inst->event_handler);
list_for_each_safe(ptr, next, &inst->registered_bufs) {
bi = list_entry(ptr, struct buffer_info, list);
if (bi->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
@@ -1247,8 +1320,7 @@
for (i = 0; (i < bi->num_planes)
&& (i < VIDEO_MAX_PLANES); i++) {
if (bi->handle[i])
- msm_smem_free(inst->mem_client,
- bi->handle[i]);
+ msm_comm_smem_free(inst, bi->handle[i]);
}
kfree(bi);
}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 42460fa..8921b13 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -277,14 +277,17 @@
dprintk(VIDC_ERR, "Wrong device_id received\n");
return;
}
- dprintk(VIDC_DBG, "index = %d\n", index);
- dprintk(VIDC_DBG, "ptr = %p\n", &(core->completions[index]));
- complete(&(core->completions[index]));
sys_init_msg = response->data;
if (!sys_init_msg) {
dprintk(VIDC_ERR, "sys_init_done message not proper\n");
return;
}
+ core->enc_codec_supported = sys_init_msg->enc_codec_supported;
+ core->dec_codec_supported = sys_init_msg->dec_codec_supported;
+ dprintk(VIDC_DBG, "supported_codecs: enc = 0x%x, dec = 0x%x\n",
+ core->enc_codec_supported, core->dec_codec_supported);
+ dprintk(VIDC_DBG, "ptr[%d] = %p\n", index, &(core->completions[index]));
+ complete(&(core->completions[index]));
}
static void handle_session_release_buf_done(enum command_response cmd,
@@ -516,6 +519,14 @@
event_notify->packet_buffer,
event_notify->exra_data_buffer);
+ if (inst->state == MSM_VIDC_CORE_INVALID ||
+ inst->core->state ==
+ VIDC_CORE_INVALID) {
+ dprintk(VIDC_DBG,
+ "Event release buf ref received in invalid state - discard\n");
+ return;
+ }
+
/*
* Get the buffer_info entry for the
* device address.
@@ -765,6 +776,7 @@
mutex_lock(&core->lock);
core->state = VIDC_CORE_INVALID;
mutex_unlock(&core->lock);
+ mutex_lock(&core->sync_lock);
list_for_each_entry(inst, &core->instances,
list) {
mutex_lock(&inst->lock);
@@ -786,6 +798,7 @@
msm_vidc_queue_v4l2_event(inst,
V4L2_EVENT_MSM_VIDC_SYS_ERROR);
}
+ mutex_unlock(&core->sync_lock);
} else {
dprintk(VIDC_ERR,
"Got SYS_ERR but unable to identify core");
@@ -813,6 +826,7 @@
mutex_lock(&core->lock);
core->state = VIDC_CORE_INVALID;
mutex_unlock(&core->lock);
+ mutex_lock(&core->sync_lock);
list_for_each_entry(inst, &core->instances, list) {
if (inst) {
msm_vidc_queue_v4l2_event(inst,
@@ -834,6 +848,7 @@
mutex_unlock(&inst->lock);
}
}
+ mutex_unlock(&core->sync_lock);
}
static void handle_session_close(enum command_response cmd, void *data)
@@ -937,6 +952,12 @@
V4L2_QCOM_BUF_DATA_CORRUPT;
}
}
+ dprintk(VIDC_DBG,
+ "Got ebd from hal: device_addr: 0x%x, alloc: %d, status: 0x%x, pic_type: 0x%x, flags: 0x%x\n",
+ (u32)empty_buf_done->packet_buffer,
+ empty_buf_done->alloc_len, empty_buf_done->status,
+ empty_buf_done->picture_type, empty_buf_done->flags);
+
mutex_lock(&inst->bufq[OUTPUT_PORT].lock);
vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
mutex_unlock(&inst->bufq[OUTPUT_PORT].lock);
@@ -1095,6 +1116,7 @@
struct vb2_buffer *vb = NULL;
struct vidc_hal_fbd *fill_buf_done;
enum hal_buffer buffer_type;
+ int64_t time_usec = 0;
if (!response) {
dprintk(VIDC_ERR, "Invalid response from vidc_hal\n");
@@ -1134,7 +1156,7 @@
if (!(fill_buf_done->flags1 &
HAL_BUFFERFLAG_TIMESTAMPINVALID) &&
fill_buf_done->filled_len1) {
- int64_t time_usec = fill_buf_done->timestamp_hi;
+ time_usec = fill_buf_done->timestamp_hi;
time_usec = (time_usec << 32) |
fill_buf_done->timestamp_lo;
vb->v4l2_buf.timestamp =
@@ -1187,10 +1209,14 @@
msm_vidc_debugfs_update(inst,
MSM_VIDC_DEBUGFS_EVENT_FBD);
- dprintk(VIDC_DBG, "Filled length = %d; offset = %d; flags %x\n",
- vb->v4l2_planes[0].bytesused,
- vb->v4l2_planes[0].data_offset,
- vb->v4l2_buf.flags);
+ dprintk(VIDC_DBG,
+ "Got fbd from hal: device_addr: 0x%x, alloc: %d, filled: %d, offset: %d, ts: %lld, flags: 0x%x, crop: %d %d %d %d, pic_type: 0x%x\n",
+ (u32)fill_buf_done->packet_buffer1, fill_buf_done->alloc_len1,
+ fill_buf_done->filled_len1, fill_buf_done->offset1, time_usec,
+ fill_buf_done->flags1, fill_buf_done->start_x_coord,
+ fill_buf_done->start_y_coord, fill_buf_done->frame_width,
+ fill_buf_done->frame_height, fill_buf_done->picture_type);
+
mutex_lock(&inst->bufq[CAPTURE_PORT].lock);
vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
mutex_unlock(&inst->bufq[CAPTURE_PORT].lock);
@@ -1594,7 +1620,7 @@
return domain;
}
-static enum hal_video_codec get_hal_codec_type(int fourcc)
+enum hal_video_codec get_hal_codec_type(int fourcc)
{
enum hal_video_codec codec;
dprintk(VIDC_DBG, "codec is 0x%x", fourcc);
@@ -1994,7 +2020,7 @@
if (output_buf->buffer_size) {
for (i = 0; i < output_buf->buffer_count_actual;
i++) {
- handle = msm_smem_alloc(inst->mem_client,
+ handle = msm_comm_smem_alloc(inst,
buffer_size, 1, smem_flags,
buffer_type, 0);
if (!handle) {
@@ -2003,7 +2029,7 @@
rc = -ENOMEM;
goto err_no_mem;
}
- rc = msm_smem_cache_operations(inst->mem_client,
+ rc = msm_comm_smem_cache_operations(inst,
handle, SMEM_CACHE_CLEAN);
if (rc) {
dprintk(VIDC_WARN,
@@ -2048,7 +2074,7 @@
fail_set_buffers:
kfree(binfo);
fail_kzalloc:
- msm_smem_free(inst->mem_client, handle);
+ msm_comm_smem_free(inst, handle);
err_no_mem:
return rc;
}
@@ -2085,7 +2111,7 @@
if (scratch_buf->buffer_size) {
for (i = 0; i < scratch_buf->buffer_count_actual;
i++) {
- handle = msm_smem_alloc(inst->mem_client,
+ handle = msm_comm_smem_alloc(inst,
scratch_buf->buffer_size, 1, smem_flags,
buffer_type, 0);
if (!handle) {
@@ -2094,7 +2120,7 @@
rc = -ENOMEM;
goto err_no_mem;
}
- rc = msm_smem_cache_operations(inst->mem_client,
+ rc = msm_comm_smem_cache_operations(inst,
handle, SMEM_CACHE_CLEAN);
if (rc) {
dprintk(VIDC_WARN,
@@ -2130,7 +2156,7 @@
fail_set_buffers:
kfree(binfo);
fail_kzalloc:
- msm_smem_free(inst->mem_client, handle);
+ msm_comm_smem_free(inst, handle);
err_no_mem:
return rc;
}
@@ -2172,7 +2198,7 @@
if (persist_buf->buffer_size) {
for (i = 0; i < persist_buf->buffer_count_actual; i++) {
- handle = msm_smem_alloc(inst->mem_client,
+ handle = msm_comm_smem_alloc(inst,
persist_buf->buffer_size, 1, smem_flags,
buffer_type, 0);
if (!handle) {
@@ -2181,7 +2207,7 @@
rc = -ENOMEM;
goto err_no_mem;
}
- rc = msm_smem_cache_operations(inst->mem_client,
+ rc = msm_comm_smem_cache_operations(inst,
handle, SMEM_CACHE_CLEAN);
if (rc) {
dprintk(VIDC_WARN,
@@ -2217,7 +2243,7 @@
fail_set_buffers:
kfree(binfo);
fail_kzalloc:
- msm_smem_free(inst->mem_client, handle);
+ msm_comm_smem_free(inst, handle);
err_no_mem:
return rc;
}
@@ -2426,11 +2452,10 @@
V4L2_QCOM_BUF_TIMESTAMP_INVALID)
frame_data.timestamp = LLONG_MAX;
dprintk(VIDC_DBG,
- "Sending etb to hal: device_addr: 0x%x"
- "Alloc: %d, filled: %d, offset: %d\n",
- frame_data.device_addr,
- frame_data.alloc_len, frame_data.filled_len,
- frame_data.offset);
+ "Sending etb to hal: device_addr: 0x%x, alloc: %d, filled: %d, offset: %d, ts: %lld, flags = 0x%x\n",
+ frame_data.device_addr, frame_data.alloc_len,
+ frame_data.filled_len, frame_data.offset,
+ frame_data.timestamp, frame_data.flags);
rc = call_hfi_op(hdev, session_etb, (void *)
inst->session, &frame_data);
if (!rc)
@@ -2448,15 +2473,17 @@
extra_idx =
EXTRADATA_IDX(inst->fmts[CAPTURE_PORT]->num_planes);
if (extra_idx && (extra_idx < VIDEO_MAX_PLANES) &&
- vb->v4l2_planes[extra_idx].m.userptr)
+ vb->v4l2_planes[extra_idx].m.userptr) {
frame_data.extradata_addr =
vb->v4l2_planes[extra_idx].m.userptr;
+ frame_data.extradata_size =
+ vb->v4l2_planes[extra_idx].length;
+ }
dprintk(VIDC_DBG,
- "Sending ftb to hal: Alloc: %d :filled: %d",
- frame_data.alloc_len, frame_data.filled_len);
- dprintk(VIDC_DBG,
- " extradata_addr: %d\n",
- frame_data.extradata_addr);
+ "Sending ftb to hal: device_addr: 0x%x, alloc: %d, buffer_type: %d, ts: %lld, flags = 0x%x\n",
+ frame_data.device_addr, frame_data.alloc_len,
+ frame_data.buffer_type, frame_data.timestamp,
+ frame_data.flags);
if (!inst->ftb_count &&
inst->session_type == MSM_VIDC_ENCODER) {
seq_hdr.seq_hdr = (u8 *) vb->v4l2_planes[0].
@@ -2472,9 +2499,9 @@
} else {
rc = call_hfi_op(hdev, session_ftb,
(void *) inst->session, &frame_data);
- if (!rc)
- msm_vidc_debugfs_update(inst,
- MSM_VIDC_DEBUGFS_EVENT_FTB);
+ if (!rc)
+ msm_vidc_debugfs_update(inst,
+ MSM_VIDC_DEBUGFS_EVENT_FTB);
}
inst->ftb_count++;
} else {
@@ -2586,7 +2613,7 @@
}
list_del(&buf->list);
mutex_unlock(&inst->lock);
- msm_smem_free(inst->mem_client, buf->handle);
+ msm_comm_smem_free(inst, buf->handle);
kfree(buf);
mutex_lock(&inst->lock);
}
@@ -2657,7 +2684,7 @@
}
list_del(&buf->list);
mutex_unlock(&inst->lock);
- msm_smem_free(inst->mem_client, buf->handle);
+ msm_comm_smem_free(inst, buf->handle);
kfree(buf);
mutex_lock(&inst->lock);
}
@@ -2728,7 +2755,7 @@
}
list_del(&buf->list);
mutex_unlock(&inst->lock);
- msm_smem_free(inst->mem_client, buf->handle);
+ msm_comm_smem_free(inst, buf->handle);
kfree(buf);
mutex_lock(&inst->lock);
}
@@ -2980,6 +3007,9 @@
dprintk(VIDC_INFO, "Input only flush not supported\n");
return 0;
}
+ mutex_lock(&inst->sync_lock);
+ msm_comm_flush_dynamic_buffers(inst);
+ mutex_unlock(&inst->sync_lock);
if (inst->state == MSM_VIDC_CORE_INVALID ||
core->state == VIDC_CORE_INVALID) {
dprintk(VIDC_ERR,
@@ -2990,7 +3020,6 @@
}
mutex_lock(&inst->sync_lock);
- msm_comm_flush_dynamic_buffers(inst);
if (inst->in_reconfig && !ip_flush && op_flush) {
if (!list_empty(&inst->pendingq)) {
/*Execution can never reach here since port reconfig
@@ -3142,7 +3171,7 @@
{
int rc = 0;
struct hfi_device *hdev;
- if (!core && !core->device) {
+ if (!core || !core->device) {
dprintk(VIDC_WARN, "Invalid parameters: %p\n", core);
return -EINVAL;
}
@@ -3158,10 +3187,12 @@
int num_mbs_per_sec = 0;
if (inst->state == MSM_VIDC_OPEN_DONE) {
+ mutex_lock(&inst->core->sync_lock);
num_mbs_per_sec = msm_comm_get_load(inst->core,
MSM_VIDC_DECODER);
num_mbs_per_sec += msm_comm_get_load(inst->core,
MSM_VIDC_ENCODER);
+ mutex_unlock(&inst->core->sync_lock);
if (num_mbs_per_sec > inst->core->resources.max_load) {
dprintk(VIDC_ERR,
"H/w is overloaded. needed: %d max: %d\n",
@@ -3334,3 +3365,85 @@
change_inst_state(inst, MSM_VIDC_CLOSE_DONE);
return rc;
}
+
+static inline int power_on_for_smem(struct msm_vidc_inst *inst)
+{
+ struct hfi_device *hdev = NULL;
+ int rc = 0;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s: invalid inst handle\n", __func__);
+ return -EINVAL;
+ }
+ hdev = inst->core->device;
+ rc = call_hfi_op(hdev, power_enable, hdev->hfi_device_data);
+ if (rc)
+ dprintk(VIDC_ERR, "%s: failed to power on fw\n", __func__);
+ return rc;
+}
+
+struct msm_smem *msm_comm_smem_alloc(struct msm_vidc_inst *inst,
+ size_t size, u32 align, u32 flags,
+ enum hal_buffer buffer_type, int map_kernel)
+{
+ if (!inst) {
+ dprintk(VIDC_ERR, "%s: invalid inst: %p\n", __func__, inst);
+ return NULL;
+ }
+ if (power_on_for_smem(inst))
+ return NULL;
+
+ return msm_smem_alloc(inst->mem_client, size, align,
+ flags, buffer_type, map_kernel);
+}
+
+void msm_comm_smem_free(struct msm_vidc_inst *inst, struct msm_smem *mem)
+{
+ if (!inst || !mem) {
+ dprintk(VIDC_ERR,
+ "%s: invalid params: %p %p\n", __func__, inst, mem);
+ return;
+ }
+ if (power_on_for_smem(inst))
+ return;
+
+ return msm_smem_free(inst->mem_client, mem);
+}
+
+int msm_comm_smem_cache_operations(struct msm_vidc_inst *inst,
+ struct msm_smem *mem, enum smem_cache_ops cache_ops)
+{
+ if (!inst || !mem) {
+ dprintk(VIDC_ERR,
+ "%s: invalid params: %p %p\n", __func__, inst, mem);
+ return -EINVAL;
+ }
+ return msm_smem_cache_operations(inst->mem_client, mem, cache_ops);
+}
+
+struct msm_smem *msm_comm_smem_user_to_kernel(struct msm_vidc_inst *inst,
+ int fd, u32 offset, enum hal_buffer buffer_type)
+{
+ if (!inst) {
+ dprintk(VIDC_ERR, "%s: invalid inst: %p\n", __func__, inst);
+ return NULL;
+ }
+ if (power_on_for_smem(inst))
+ return NULL;
+
+ return msm_smem_user_to_kernel(inst->mem_client,
+ fd, offset, buffer_type);
+}
+
+int msm_comm_smem_get_domain_partition(struct msm_vidc_inst *inst,
+ u32 flags, enum hal_buffer buffer_type,
+ int *domain_num, int *partition_num)
+{
+ if (!inst || !domain_num || !partition_num) {
+ dprintk(VIDC_ERR, "%s: invalid params: %p %p %p\n",
+ __func__, inst, domain_num, partition_num);
+ return -EINVAL;
+ }
+ return msm_smem_get_domain_partition(inst->mem_client, flags,
+ buffer_type, domain_num, partition_num);
+}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h
index 195fa7e..e2f7b61 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h
@@ -52,5 +52,16 @@
int msm_comm_recover_from_session_error(struct msm_vidc_inst *inst);
enum multi_stream msm_comm_get_stream_output_mode(struct msm_vidc_inst *inst);
enum hal_buffer msm_comm_get_hal_output_buffer(struct msm_vidc_inst *inst);
-
+struct msm_smem *msm_comm_smem_alloc(struct msm_vidc_inst *inst,
+ size_t size, u32 align, u32 flags,
+ enum hal_buffer buffer_type, int map_kernel);
+void msm_comm_smem_free(struct msm_vidc_inst *inst, struct msm_smem *mem);
+int msm_comm_smem_cache_operations(struct msm_vidc_inst *inst,
+ struct msm_smem *mem, enum smem_cache_ops cache_ops);
+struct msm_smem *msm_comm_smem_user_to_kernel(struct msm_vidc_inst *inst,
+ int fd, u32 offset, enum hal_buffer buffer_type);
+int msm_comm_smem_get_domain_partition(struct msm_vidc_inst *inst,
+ u32 flags, enum hal_buffer buffer_type,
+ int *domain_num, int *partition_num);
+enum hal_video_codec get_hal_codec_type(int fourcc);
#endif
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index 2b1471c..e4f920f 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -207,6 +207,8 @@
struct completion completions[SYS_MSG_END - SYS_MSG_START + 1];
enum msm_vidc_hfi_type hfi_type;
struct msm_vidc_platform_resources resources;
+ u32 enc_codec_supported;
+ u32 dec_codec_supported;
};
struct msm_vidc_inst {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
index 394ecdc5..ecfff85 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
@@ -289,7 +289,7 @@
bus_pdata->usecase[i].vectors = kzalloc(
sizeof(*bus_pdata->usecase[i].vectors) * num_ports,
GFP_KERNEL);
- if (!bus_pdata->usecase) {
+ if (!bus_pdata->usecase[i].vectors) {
dprintk(VIDC_ERR,
"%s Failed to alloc bus_pdata usecase\n",
__func__);
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.c b/drivers/media/platform/msm/vidc/q6_hfi.c
index 7c99ec3..8e91f34 100644
--- a/drivers/media/platform/msm/vidc/q6_hfi.c
+++ b/drivers/media/platform/msm/vidc/q6_hfi.c
@@ -560,17 +560,28 @@
dprintk(VIDC_ERR, "session_init: failed to create packet");
goto err_session_init;
}
+ /*
+ * Add session id to the list entry and then send the apr pkt.
+ * This will avoid scenarios where apr_send_pkt is taking more
+ * time and Q6 is returning an ack even before the session id
+ * gets added to the session list.
+ */
+ mutex_lock(&dev->session_lock);
+ list_add_tail(&new_session->list, &dev->sess_head);
+ mutex_unlock(&dev->session_lock);
rc = apr_send_pkt(dev->apr, (uint32_t *)&apr);
if (rc != apr.hdr.pkt_size) {
dprintk(VIDC_ERR, "%s: apr_send_pkt failed rc: %d",
__func__, rc);
+ /* Delete the session id as the send pkt is not successful */
+ mutex_lock(&dev->session_lock);
+ list_del(&new_session->list);
+ mutex_unlock(&dev->session_lock);
rc = -EBADE;
goto err_session_init;
}
- mutex_lock(&dev->session_lock);
- list_add_tail(&new_session->list, &dev->sess_head);
- mutex_unlock(&dev->session_lock);
+
return new_session;
err_session_init:
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 916df1d..7f09b24 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-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -25,10 +25,12 @@
#include <mach/subsystem_restart.h>
#include <mach/msm_smem.h>
#include <asm/memory.h>
+#include <linux/iopoll.h>
#include "hfi_packetization.h"
#include "venus_hfi.h"
#include "vidc_hfi_io.h"
#include "msm_vidc_debug.h"
+#include <linux/iopoll.h>
#define FIRMWARE_SIZE 0X00A00000
#define REG_ADDR_OFFSET_BITMASK 0x000FFFFF
@@ -65,6 +67,9 @@
#define TZBSP_VIDEO_SET_STATE 0xa
+/* Poll interval in uS */
+#define POLL_INTERVAL_US 50
+
enum tzbsp_video_state {
TZBSP_VIDEO_STATE_SUSPEND = 0,
TZBSP_VIDEO_STATE_RESUME
@@ -75,6 +80,11 @@
u32 spare; /*reserved for future, should be zero*/
};
+
+static inline int venus_hfi_clk_gating_off(struct venus_hfi_device *device);
+
+static int venus_hfi_power_enable(void *dev);
+
static void venus_hfi_dump_packet(u8 *packet)
{
u32 c = 0, packet_size = *(u32 *)packet;
@@ -402,21 +412,24 @@
return rc;
}
-static int venus_hfi_alloc(void *mem, void *clnt, u32 size, u32 align,
- u32 flags, u32 usage)
+static int venus_hfi_alloc(struct venus_hfi_device *dev, void *mem,
+ u32 size, u32 align, u32 flags, u32 usage)
{
- struct vidc_mem_addr *vmem;
- struct msm_smem *alloc;
+ struct vidc_mem_addr *vmem = NULL;
+ struct msm_smem *alloc = NULL;
int rc = 0;
- if (!mem || !clnt || !size) {
+ if (!dev || !dev->hal_client || !mem || !size) {
dprintk(VIDC_ERR, "Invalid Params");
return -EINVAL;
}
+
vmem = (struct vidc_mem_addr *)mem;
dprintk(VIDC_INFO, "start to alloc: size:%d, Flags: %d", size, flags);
- alloc = msm_smem_alloc(clnt, size, align, flags, usage, 1);
+ venus_hfi_power_enable(dev);
+
+ alloc = msm_smem_alloc(dev->hal_client, size, align, flags, usage, 1);
dprintk(VIDC_DBG, "Alloc done");
if (!alloc) {
dprintk(VIDC_ERR, "Alloc failed\n");
@@ -425,7 +438,7 @@
}
dprintk(VIDC_DBG, "venus_hfi_alloc:ptr=%p,size=%d",
alloc->kvaddr, size);
- rc = msm_smem_cache_operations(clnt, alloc,
+ rc = msm_smem_cache_operations(dev->hal_client, alloc,
SMEM_CACHE_CLEAN);
if (rc) {
dprintk(VIDC_WARN, "Failed to clean cache\n");
@@ -440,9 +453,14 @@
return rc;
}
-static void venus_hfi_free(struct smem_client *clnt, struct msm_smem *mem)
+static void venus_hfi_free(struct venus_hfi_device *dev, struct msm_smem *mem)
{
- msm_smem_free(clnt, mem);
+ if (!dev || !mem) {
+ dprintk(VIDC_ERR, "invalid param %p %p\n", dev, mem);
+ return;
+ }
+ venus_hfi_power_enable(dev);
+ msm_smem_free(dev->hal_client, mem);
}
static void venus_hfi_write_register(struct venus_hfi_device *device, u32 reg,
@@ -511,7 +529,7 @@
u32 ctrl_status = 0, count = 0, rc = 0;
int max_tries = 100;
venus_hfi_write_register(device,
- VIDC_WRAPPER_INTR_MASK, 0x8, 0);
+ VIDC_WRAPPER_INTR_MASK, VIDC_WRAPPER_INTR_MASK_A2HVCODEC_BMSK, 0);
venus_hfi_write_register(device,
VIDC_CPU_CS_SCIACMDARG3, 1, 0);
@@ -865,6 +883,34 @@
static DECLARE_COMPLETION(pc_prep_done);
+static int venus_hfi_halt_axi(struct venus_hfi_device *device)
+{
+ u32 reg;
+ int rc = 0;
+ if (!device) {
+ dprintk(VIDC_ERR, "Invalid input: %p\n", device);
+ return -EINVAL;
+ }
+ if (venus_hfi_clk_gating_off(device)) {
+ dprintk(VIDC_ERR, "Failed to turn off clk gating\n");
+ return -EIO;
+ }
+ /* Halt AXI and AXI OCMEM VBIF Access */
+ reg = venus_hfi_read_register(device, VENUS_VBIF_AXI_HALT_CTRL0);
+ reg |= VENUS_VBIF_AXI_HALT_CTRL0_HALT_REQ;
+ venus_hfi_write_register(device, VENUS_VBIF_AXI_HALT_CTRL0, reg, 0);
+
+ /* Request for AXI bus port halt */
+ rc = readl_poll_timeout((u32)device->hal_data->register_base_addr
+ + VENUS_VBIF_AXI_HALT_CTRL1,
+ reg, reg & VENUS_VBIF_AXI_HALT_CTRL1_HALT_ACK,
+ POLL_INTERVAL_US,
+ VENUS_VBIF_AXI_HALT_ACK_TIMEOUT_US);
+ if (rc)
+ dprintk(VIDC_WARN, "AXI bus port halt timeout\n");
+ return rc;
+}
+
static inline int venus_hfi_power_off(struct venus_hfi_device *device)
{
int rc = 0;
@@ -972,6 +1018,22 @@
return rc;
}
+static int venus_hfi_power_enable(void *dev)
+{
+ int rc = 0;
+ struct venus_hfi_device *device = dev;
+ if (!device) {
+ dprintk(VIDC_ERR, "Invalid params: %p\n", device);
+ return -EINVAL;
+ }
+ mutex_lock(&device->clk_pwr_lock);
+ if (!device->power_enabled)
+ rc = venus_hfi_power_on(device);
+ mutex_unlock(&device->clk_pwr_lock);
+
+ return rc;
+}
+
static void venus_hfi_pm_hndlr(struct work_struct *work);
static DECLARE_DELAYED_WORK(venus_hfi_pm_work, venus_hfi_pm_hndlr);
@@ -1000,6 +1062,8 @@
dprintk(VIDC_ERR, "Failed venus clock enable");
goto fail_clk_power_on;
}
+ venus_hfi_write_register(device,
+ VIDC_WRAPPER_INTR_MASK, VIDC_WRAPPER_INTR_MASK_A2HVCODEC_BMSK, 0);
}
already_enabled:
device->clocks_enabled = 1;
@@ -1057,30 +1121,32 @@
dprintk(VIDC_ERR, "cannot write to shared Q's");
goto err_q_null;
}
- mutex_lock(&device->clk_pwr_lock);
- result = venus_hfi_clk_gating_off(device);
- if (result) {
- dprintk(VIDC_ERR, "%s : Clock enable failed\n",
- __func__);
- goto err_q_write;
- }
- result = venus_hfi_scale_clocks(device, device->clk_load);
- if (result) {
- dprintk(VIDC_ERR, "Clock scaling failed\n");
- goto err_q_write;
- }
if (!venus_hfi_write_queue(q_info, (u8 *)pkt, &rx_req_is_set)) {
+ mutex_lock(&device->clk_pwr_lock);
+ result = venus_hfi_clk_gating_off(device);
+ if (result) {
+ dprintk(VIDC_ERR, "%s : Clock enable failed\n",
+ __func__);
+ mutex_unlock(&device->clk_pwr_lock);
+ goto err_q_write;
+ }
+ result = venus_hfi_scale_clocks(device, device->clk_load);
+ if (result) {
+ dprintk(VIDC_ERR, "Clock scaling failed\n");
+ mutex_unlock(&device->clk_pwr_lock);
+ goto err_q_write;
+ }
if (rx_req_is_set)
venus_hfi_write_register(
device,
VIDC_CPU_IC_SOFTINT,
1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT, 0);
result = 0;
+ mutex_unlock(&device->clk_pwr_lock);
} else {
dprintk(VIDC_ERR, "venus_hfi_iface_cmdq_write:queue_full");
}
err_q_write:
- mutex_unlock(&device->clk_pwr_lock);
err_q_null:
mutex_unlock(&device->write_lock);
return result;
@@ -1104,26 +1170,27 @@
goto read_error_null;
}
q_info = &device->iface_queues[VIDC_IFACEQ_MSGQ_IDX];
- mutex_lock(&device->clk_pwr_lock);
- rc = venus_hfi_clk_gating_off(device);
- if (rc) {
- dprintk(VIDC_ERR,
- "%s : Clock enable failed\n", __func__);
- goto read_error;
- }
if (!venus_hfi_read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) {
+ mutex_lock(&device->clk_pwr_lock);
+ rc = venus_hfi_clk_gating_off(device);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s : Clock enable failed\n", __func__);
+ mutex_unlock(&device->clk_pwr_lock);
+ goto read_error;
+ }
if (tx_req_is_set)
venus_hfi_write_register(
device,
VIDC_CPU_IC_SOFTINT,
1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT, 0);
rc = 0;
+ mutex_unlock(&device->clk_pwr_lock);
} else {
dprintk(VIDC_INFO, "venus_hfi_iface_msgq_read:queue_empty");
rc = -ENODATA;
}
read_error:
- mutex_unlock(&device->clk_pwr_lock);
read_error_null:
mutex_unlock(&device->read_lock);
return rc;
@@ -1146,27 +1213,28 @@
rc = -ENODATA;
goto dbg_error_null;
}
- mutex_lock(&device->clk_pwr_lock);
- rc = venus_hfi_clk_gating_off(device);
- if (rc) {
- dprintk(VIDC_ERR,
- "%s : Clock enable failed\n", __func__);
- goto dbg_error;
- }
q_info = &device->iface_queues[VIDC_IFACEQ_DBGQ_IDX];
if (!venus_hfi_read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) {
+ mutex_lock(&device->clk_pwr_lock);
+ rc = venus_hfi_clk_gating_off(device);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s : Clock enable failed\n", __func__);
+ mutex_unlock(&device->clk_pwr_lock);
+ goto dbg_error;
+ }
if (tx_req_is_set)
venus_hfi_write_register(
device,
VIDC_CPU_IC_SOFTINT,
1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT, 0);
rc = 0;
+ mutex_unlock(&device->clk_pwr_lock);
} else {
dprintk(VIDC_INFO, "venus_hfi_iface_dbgq_read:queue_empty");
rc = -ENODATA;
}
dbg_error:
- mutex_unlock(&device->clk_pwr_lock);
dbg_error_null:
mutex_unlock(&device->read_lock);
return rc;
@@ -1213,10 +1281,10 @@
(unsigned long)(mem_map[i].virtual_addr),
domain, partition, SZ_4K);
}
- venus_hfi_free(device->hal_client, device->qdss.mem_data);
+ venus_hfi_free(device, device->qdss.mem_data);
}
- venus_hfi_free(device->hal_client, device->iface_q_table.mem_data);
- venus_hfi_free(device->hal_client, device->sfr.mem_data);
+ venus_hfi_free(device, device->iface_q_table.mem_data);
+ venus_hfi_free(device, device->sfr.mem_data);
for (i = 0; i < VIDC_IFACEQ_NUMQ; i++) {
device->iface_queues[i].q_hdr = NULL;
@@ -1251,7 +1319,7 @@
for (i = 0; i < num_entries; i++) {
rc = msm_iommu_map_contig_buffer(venus_qdss_entries[i][0],
- domain, 1 , venus_qdss_entries[i][1],
+ domain, partition, venus_qdss_entries[i][1],
SZ_4K, 0, &iova);
if (rc) {
dprintk(VIDC_ERR,
@@ -1292,8 +1360,8 @@
int num_entries = sizeof(venus_qdss_entries)/(2 * sizeof(u32));
int domain, partition;
mem_addr = &dev->mem_addr;
- rc = venus_hfi_alloc((void *) mem_addr,
- dev->hal_client, QUEUE_SIZE, 1, 0,
+ rc = venus_hfi_alloc(dev, (void *) mem_addr,
+ QUEUE_SIZE, 1, 0,
HAL_BUFFER_INTERNAL_CMD_QUEUE);
if (rc) {
dprintk(VIDC_ERR, "iface_q_table_alloc_fail");
@@ -1319,8 +1387,8 @@
venus_hfi_set_queue_hdr_defaults(iface_q->q_hdr);
}
- rc = venus_hfi_alloc((void *) mem_addr,
- dev->hal_client, QDSS_SIZE, 1, 0,
+ rc = venus_hfi_alloc(dev, (void *) mem_addr,
+ QDSS_SIZE, 1, 0,
HAL_BUFFER_INTERNAL_CMD_QUEUE);
if (rc) {
dprintk(VIDC_WARN,
@@ -1332,8 +1400,8 @@
dev->qdss.mem_size = QDSS_SIZE;
dev->qdss.mem_data = mem_addr->mem_data;
}
- rc = venus_hfi_alloc((void *) mem_addr,
- dev->hal_client, SFR_SIZE, 1, 0,
+ rc = venus_hfi_alloc(dev, (void *) mem_addr,
+ SFR_SIZE, 1, 0,
HAL_BUFFER_INTERNAL_CMD_QUEUE);
if (rc) {
dprintk(VIDC_WARN, "sfr_alloc_fail: SFR not will work");
@@ -1398,7 +1466,7 @@
if (rc) {
dprintk(VIDC_ERR,
"IOMMU mapping failed, Freeing qdss memdata");
- venus_hfi_free(dev->hal_client, dev->qdss.mem_data);
+ venus_hfi_free(dev, dev->qdss.mem_data);
dev->qdss.mem_data = NULL;
}
if (!IS_ERR_OR_NULL(dev->qdss.align_device_addr))
@@ -1567,6 +1635,60 @@
return 0;
}
+static int venus_hfi_get_q_size(struct venus_hfi_device *dev,
+ unsigned int q_index)
+{
+ struct hfi_queue_header *queue;
+ struct vidc_iface_q_info *q_info;
+ u32 write_ptr, read_ptr;
+ u32 rc = 0;
+ if (q_index >= VIDC_IFACEQ_NUMQ) {
+ dprintk(VIDC_ERR, "Invalid q index: %d\n", q_index);
+ return -ENOENT;
+ }
+
+ q_info = &dev->iface_queues[q_index];
+ if (!q_info) {
+ dprintk(VIDC_ERR, "cannot read shared Q's");
+ return -ENOENT;
+ }
+ queue = (struct hfi_queue_header *) q_info->q_hdr;
+ if (!queue) {
+ dprintk(VIDC_ERR, "queue not present");
+ return -ENOENT;
+ }
+ write_ptr = (u32)queue->qhdr_write_idx;
+ read_ptr = (u32)queue->qhdr_read_idx;
+ rc = read_ptr - write_ptr;
+ return rc;
+}
+
+static inline void venus_hfi_clk_gating_on(struct venus_hfi_device *device)
+{
+ if (!device) {
+ dprintk(VIDC_ERR, "Invalid params: %p\n", device);
+ return;
+ }
+ if (!device->clocks_enabled) {
+ dprintk(VIDC_DBG, "Clocks are already disabled");
+ goto already_disabled;
+ }
+ /*SYS Idle should be last message so mask any further interrupts
+ * until clocks are enabled again.*/
+ if (!venus_hfi_get_q_size(device, VIDC_IFACEQ_MSGQ_IDX)) {
+ venus_hfi_write_register(device,
+ VIDC_WRAPPER_INTR_MASK,
+ VIDC_WRAPPER_INTR_MASK_A2HVCODEC_BMSK |
+ VIDC_WRAPPER_INTR_MASK_A2HCPU_BMSK, 0);
+ }
+ venus_hfi_clk_disable(device);
+ if (!queue_delayed_work(device->venus_pm_workq, &venus_hfi_pm_work,
+ msecs_to_jiffies(msm_vidc_pwr_collapse_delay)))
+ dprintk(VIDC_DBG, "PM work already scheduled\n");
+already_disabled:
+ device->clocks_enabled = 0;
+}
+
static void venus_hfi_core_clear_interrupt(struct venus_hfi_device *device)
{
u32 intr_status = 0;
@@ -1574,13 +1696,14 @@
if (!device->callback)
return;
+
+ mutex_lock(&device->write_lock);
mutex_lock(&device->clk_pwr_lock);
rc = venus_hfi_clk_gating_off(device);
if (rc) {
dprintk(VIDC_ERR,
"%s : Clock enable failed\n", __func__);
- mutex_unlock(&device->clk_pwr_lock);
- return;
+ goto err_clk_gating_off;
}
intr_status = venus_hfi_read_register(
device,
@@ -1603,8 +1726,10 @@
VIDC_CPU_CS_A2HSOFTINTCLR, 1, 0);
venus_hfi_write_register(device,
VIDC_WRAPPER_INTR_CLEAR, intr_status, 0);
- mutex_unlock(&device->clk_pwr_lock);
dprintk(VIDC_DBG, "Cleared WRAPPER/A2H interrupt");
+err_clk_gating_off:
+ mutex_unlock(&device->clk_pwr_lock);
+ mutex_unlock(&device->write_lock);
}
static int venus_hfi_core_set_resource(void *device,
@@ -2321,26 +2446,6 @@
device->callback(SYS_WATCHDOG_TIMEOUT, &cmd_done);
}
-static int venus_hfi_is_cmd_pending(struct venus_hfi_device *dev)
-{
- struct hfi_queue_header *queue;
- struct vidc_iface_q_info *q_info;
- u32 write_ptr, read_ptr;
- u32 rc = 0;
- q_info = &dev->iface_queues[VIDC_IFACEQ_CMDQ_IDX];
- if (!q_info)
- dprintk(VIDC_ERR, "cannot read shared Q's");
- queue = (struct hfi_queue_header *) q_info->q_hdr;
- if (!queue) {
- dprintk(VIDC_ERR, "queue not present");
- return -ENOENT;
- }
- write_ptr = (u32)queue->qhdr_write_idx;
- read_ptr = (u32)queue->qhdr_read_idx;
- rc = read_ptr - write_ptr;
- return rc;
-}
-
static int venus_hfi_core_pc_prep(void *device)
{
struct hfi_cmd_sys_pc_prep_packet pkt;
@@ -2408,24 +2513,6 @@
mutex_unlock(&device->clk_pwr_lock);
}
-static inline void venus_hfi_clk_gating_on(struct venus_hfi_device *device)
-{
- if (!device) {
- dprintk(VIDC_ERR, "Invalid params: %p\n", device);
- return;
- }
- if (!device->clocks_enabled) {
- dprintk(VIDC_DBG, "Clocks are already disabled");
- goto already_disabled;
- }
- venus_hfi_clk_disable(device);
- if (!queue_delayed_work(device->venus_pm_workq, &venus_hfi_pm_work,
- msecs_to_jiffies(msm_vidc_pwr_collapse_delay)))
- dprintk(VIDC_DBG, "PM work already scheduled\n");
-already_disabled:
- device->clocks_enabled = 0;
-}
-
static int venus_hfi_try_clk_gating(struct venus_hfi_device *device)
{
int rc = 0;
@@ -2436,7 +2523,7 @@
}
mutex_lock(&device->write_lock);
mutex_lock(&device->clk_pwr_lock);
- rc = venus_hfi_is_cmd_pending(device);
+ rc = venus_hfi_get_q_size(device, VIDC_IFACEQ_CMDQ_IDX);
ctrl_status = venus_hfi_read_register(
device,
VIDC_CPU_CS_SCIACMDARG0);
@@ -2506,10 +2593,12 @@
(struct hfi_msg_sys_debug_packet *) packet;
dprintk(VIDC_FW, "FW-SAYS: %s", pkt->rg_msg_data);
}
- if (rc == HFI_MSG_SYS_IDLE)
+ if (rc == HFI_MSG_SYS_IDLE) {
+ dprintk(VIDC_DBG, "Received HFI_MSG_SYS_IDLE\n");
rc = venus_hfi_try_clk_gating(device);
- else if (rc == HFI_MSG_SYS_PC_PREP_DONE) {
- dprintk(VIDC_DBG, "Received HFI_MSG_SYS_PC_PREP_DONE");
+ } else if (rc == HFI_MSG_SYS_PC_PREP_DONE) {
+ dprintk(VIDC_DBG,
+ "Received HFI_MSG_SYS_PC_PREP_DONE\n");
rc = venus_hfi_try_clk_gating(device);
if (rc)
dprintk(VIDC_ERR,
@@ -2985,9 +3074,10 @@
ocmem->vidc_ocmem_nb.notifier_call = venus_hfi_ocmem_notify_handler;
ocmem->handle =
ocmem_notifier_register(OCMEM_VIDEO, &ocmem->vidc_ocmem_nb);
- if (!ocmem->handle) {
- dprintk(VIDC_WARN, "Failed to register OCMEM notifier.");
- dprintk(VIDC_INFO, " Performance will be impacted\n");
+ if (IS_ERR_OR_NULL(ocmem->handle)) {
+ dprintk(VIDC_WARN,
+ "Failed to register OCMEM notifier. Performance might be impacted\n");
+ ocmem->handle = NULL;
}
}
@@ -3258,15 +3348,21 @@
if (device->resources.fw.cookie) {
flush_workqueue(device->vidc_workq);
flush_workqueue(device->venus_pm_workq);
+ subsystem_put(device->resources.fw.cookie);
+ venus_hfi_interface_queues_release(dev);
+ /* IOMMU operations need to be done before AXI halt.*/
+ venus_hfi_iommu_detach(device);
+ /* Halt the AXI to make sure there are no pending transactions.
+ * Clocks should be unprepared after making sure axi is halted.
+ */
+ if(venus_hfi_halt_axi(device))
+ dprintk(VIDC_WARN, "Failed to halt AXI\n");
venus_hfi_disable_clks(device);
mutex_lock(&device->clk_pwr_lock);
- subsystem_put(device->resources.fw.cookie);
regulator_disable(device->gdsc);
device->power_enabled = 0;
--device->pwr_cnt;
mutex_unlock(&device->clk_pwr_lock);
- venus_hfi_interface_queues_release(dev);
- venus_hfi_iommu_detach(device);
device->resources.fw.cookie = NULL;
}
}
@@ -3559,6 +3655,7 @@
hdev->get_stride_scanline = venus_hfi_get_stride_scanline;
hdev->capability_check = venus_hfi_capability_check;
hdev->get_core_capabilities = venus_hfi_get_core_capabilities;
+ hdev->power_enable = venus_hfi_power_enable;
}
int venus_hfi_initialize(struct hfi_device *hdev, u32 device_id,
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index cc07806..846171e 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -862,6 +862,7 @@
u32 mark_target;
u32 mark_data;
u32 clnt_data;
+ u32 extradata_size;
};
struct vidc_seq_hdr {
@@ -1129,6 +1130,7 @@
u32 *max_width, u32 *max_height);
int (*session_clean)(void *sess);
int (*get_core_capabilities)(void);
+ int (*power_enable)(void *dev);
};
typedef void (*hfi_cmd_response_callback) (enum command_response cmd,
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_io.h b/drivers/media/platform/msm/vidc/vidc_hfi_io.h
index 6377fbf..b811948 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_io.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_io.h
@@ -88,8 +88,10 @@
#define VIDC_WRAPPER_INTR_MASK (VIDC_WRAPPER_BASE_OFFS + 0x10)
#define VIDC_WRAPPER_INTR_MASK_A2HWD_BMSK 0x10
#define VIDC_WRAPPER_INTR_MASK_A2HWD_SHFT 0x4
-#define VIDC_WRAPPER_INTR_MASK_A2H_BMSK 0x4
-#define VIDC_WRAPPER_INTR_MASK_A2H_SHFT 0x2
+#define VIDC_WRAPPER_INTR_MASK_A2HVCODEC_BMSK 0x8
+#define VIDC_WRAPPER_INTR_MASK_A2HVCODEC_SHFT 0x3
+#define VIDC_WRAPPER_INTR_MASK_A2HCPU_BMSK 0x4
+#define VIDC_WRAPPER_INTR_MASK_A2HCPU_SHFT 0x2
#define VIDC_WRAPPER_INTR_CLEAR (VIDC_WRAPPER_BASE_OFFS + 0x14)
#define VIDC_WRAPPER_INTR_CLEAR_A2HWD_BMSK 0x10
@@ -131,6 +133,15 @@
#define VIDC_VBIF_AT_OLD_HIGH (VIDC_VBIF_BASE_OFFS + 0xC08)
#define VIDC_VBIF_AT_NEW_BASE (VIDC_VBIF_BASE_OFFS + 0xC10)
#define VIDC_VBIF_AT_NEW_HIGH (VIDC_VBIF_BASE_OFFS + 0xC18)
+#define VENUS_VBIF_AXI_HALT_CTRL0 (VIDC_VBIF_BASE_OFFS + 0x208)
+#define VENUS_VBIF_AXI_HALT_CTRL1 (VIDC_VBIF_BASE_OFFS + 0x20C)
+
+#define VENUS_VBIF_AXI_HALT_CTRL0_HALT_REQ BIT(0)
+#define VENUS_VBIF_AXI_HALT_CTRL1_HALT_ACK BIT(0)
+#define VENUS_VBIF_AXI_HALT_ACK_TIMEOUT_US 500000
+/* Poll interval in uS */
+#define POLL_INTERVAL_US 50
+
#define VIDC_VENUS0_WRAPPER_VBIF_REQ_PRIORITY \
(VIDC_WRAPPER_BASE_OFFS + 0x20)
diff --git a/drivers/media/platform/msm/wfd/vsg-subdev.c b/drivers/media/platform/msm/wfd/vsg-subdev.c
index c20250e..1f827bb 100644
--- a/drivers/media/platform/msm/wfd/vsg-subdev.c
+++ b/drivers/media/platform/msm/wfd/vsg-subdev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -23,6 +23,8 @@
#define DEFAULT_MAX_FRAME_INTERVAL (1*NSEC_PER_SEC)
#define DEFAULT_MODE ((enum vsg_modes)VSG_MODE_CFR)
#define MAX_BUFS_BUSY_WITH_ENC 5
+#define TICKS_PER_TIMEOUT 2
+
static void vsg_reset_timer(struct hrtimer *timer, ktime_t time)
{
@@ -120,9 +122,10 @@
INIT_LIST_HEAD(&buf_info->node);
ktime_get_ts(&buf_info->time);
- vsg_reset_timer(&context->threshold_timer, ns_to_ktime(
- context->max_frame_interval));
-
+ if (work->work_delayed) {
+ buf_info->time = timespec_sub(buf_info->time,
+ context->delayed_frame_interval);
+ }
temp = NULL;
list_for_each_entry(temp, &context->busy_queue.node, node) {
if (mdp_buf_info_equals(&temp->mdp_buf_info,
@@ -233,6 +236,7 @@
INIT_WORK(&new_work->work, vsg_work_func);
new_work->context = context;
+ new_work->work_delayed = work->work_delayed;
queue_work(context->work_queue, &new_work->work);
}
@@ -245,25 +249,43 @@
{
struct vsg_context *context = NULL;
struct vsg_work *task = NULL;
-
- task = kzalloc(sizeof(*task), GFP_ATOMIC);
+ int64_t max_frame_interval = 0;
context = container_of(timer, struct vsg_context,
threshold_timer);
+
+ if (!context) {
+ WFD_MSG_ERR("Context not proper in %s", __func__);
+ goto threshold_err_no_context;
+ }
+ max_frame_interval = context->max_frame_interval;
+ if (list_empty(&context->free_queue.node) && !context->vsync_wait) {
+ context->vsync_wait = true;
+ max_frame_interval = context->max_frame_interval /
+ TICKS_PER_TIMEOUT;
+ goto restart_timer;
+ } else if (context->vsync_wait) {
+ max_frame_interval = context->max_frame_interval /
+ TICKS_PER_TIMEOUT;
+ context->vsync_wait = false;
+ }
+
+ task = kzalloc(sizeof(*task), GFP_ATOMIC);
if (!task) {
WFD_MSG_ERR("Out of memory in %s", __func__);
goto threshold_err_bad_param;
- } else if (!context) {
- WFD_MSG_ERR("Context not proper in %s", __func__);
- goto threshold_err_no_context;
}
INIT_WORK(&task->work, vsg_timer_helper_func);
task->context = context;
+ task->work_delayed = false;
+ if (max_frame_interval < context->max_frame_interval)
+ task->work_delayed = true;
queue_work(context->work_queue, &task->work);
+restart_timer:
threshold_err_bad_param:
hrtimer_forward_now(&context->threshold_timer, ns_to_ktime(
- context->max_frame_interval));
+ max_frame_interval));
return HRTIMER_RESTART;
threshold_err_no_context:
return HRTIMER_NORESTART;
@@ -298,6 +320,7 @@
context->last_buffer = NULL;
context->mode = DEFAULT_MODE;
context->state = VSG_STATE_NONE;
+ context->vsync_wait = false;
mutex_init(&context->mutex);
sd->dev_priv = context;
@@ -568,7 +591,8 @@
context->max_frame_interval, interval);
context->max_frame_interval = interval;
}
-
+ context->delayed_frame_interval =
+ ns_to_timespec(context->frame_interval / TICKS_PER_TIMEOUT);
mutex_unlock(&context->mutex);
return 0;
}
diff --git a/drivers/media/platform/msm/wfd/vsg-subdev.h b/drivers/media/platform/msm/wfd/vsg-subdev.h
index 3347e5b..bbaced1 100644
--- a/drivers/media/platform/msm/wfd/vsg-subdev.h
+++ b/drivers/media/platform/msm/wfd/vsg-subdev.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -56,7 +56,7 @@
};
struct vsg_context {
- struct vsg_buf_info free_queue, busy_queue;
+ struct vsg_buf_info free_queue, busy_queue;
struct vsg_msg_ops vmops;
/* All time related values below in nanosecs */
int64_t frame_interval, max_frame_interval, frame_interval_variance;
@@ -66,11 +66,14 @@
struct vsg_buf_info *last_buffer;
int mode;
int state;
+ bool vsync_wait;
+ struct timespec delayed_frame_interval;
};
struct vsg_work {
struct vsg_context *context;
struct work_struct work;
+ bool work_delayed;
};
struct vsg_encode_work {
diff --git a/drivers/media/radio/radio-iris-transport.c b/drivers/media/radio/radio-iris-transport.c
index 9a9b385..d3fe11c 100644
--- a/drivers/media/radio/radio-iris-transport.c
+++ b/drivers/media/radio/radio-iris-transport.c
@@ -105,6 +105,7 @@
skb = alloc_skb(len, GFP_ATOMIC);
if (!skb) {
FMDERR("Memory not allocated for the socket");
+ kfree(worker);
return;
}
@@ -153,7 +154,13 @@
struct radio_hci_dev *hdev;
int rc;
+ if (hsmd == NULL)
+ return -ENODEV;
+
hdev = kmalloc(sizeof(struct radio_hci_dev), GFP_KERNEL);
+ if (hdev == NULL)
+ return -ENODEV;
+
hsmd->hdev = hdev;
tasklet_init(&hsmd->rx_task, radio_hci_smd_recv_event,
(unsigned long) hsmd);
@@ -166,6 +173,8 @@
if (rc < 0) {
FMDERR("Cannot open the command channel");
+ hsmd->hdev = NULL;
+ kfree(hdev);
return -ENODEV;
}
@@ -173,6 +182,9 @@
if (radio_hci_register_dev(hdev) < 0) {
FMDERR("Can't register HCI device");
+ smd_close(hsmd->fm_channel);
+ hsmd->hdev = NULL;
+ kfree(hdev);
return -ENODEV;
}
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index 9e25e42..9f18508 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -88,7 +88,7 @@
struct radio_hci_dev *fm_hdev;
- struct v4l2_capability *g_cap;
+ struct v4l2_capability g_cap;
struct v4l2_control *g_ctl;
struct hci_fm_mute_mode_req mute_mode;
@@ -496,17 +496,29 @@
static void iris_q_event(struct iris_device *radio,
enum iris_evt_t event)
{
- struct kfifo *data_b = &radio->data_buf[IRIS_BUF_EVENTS];
+ struct kfifo *data_b;
unsigned char evt = event;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR(":radio is null");
+ return;
+ }
+
+ data_b = &radio->data_buf[IRIS_BUF_EVENTS];
if (kfifo_in_locked(data_b, &evt, 1, &radio->buf_lock[IRIS_BUF_EVENTS]))
wake_up_interruptible(&radio->event_queue);
}
static int hci_send_frame(struct sk_buff *skb)
{
- struct radio_hci_dev *hdev = (struct radio_hci_dev *) skb->dev;
+ struct radio_hci_dev *hdev;
- if (!hdev) {
+ if (unlikely(skb == NULL)) {
+ FMDERR("%s, socket buffer is null\n", __func__);
+ return -EINVAL;
+ }
+ hdev = (struct radio_hci_dev *) skb->dev;
+ if (unlikely(!hdev)) {
kfree_skb(skb);
return -ENODEV;
}
@@ -521,6 +533,11 @@
{
struct radio_hci_dev *hdev = (struct radio_hci_dev *) arg;
struct sk_buff *skb;
+
+ if (unlikely(hdev == NULL)) {
+ FMDERR("%s, HCI Device is null\n", __func__);
+ return;
+ }
if (!(atomic_read(&hdev->cmd_cnt))
&& time_after(jiffies, hdev->cmd_last_tx + HZ)) {
FMDERR("%s command tx timeout", hdev->name);
@@ -548,6 +565,10 @@
struct radio_hci_dev *hdev = (struct radio_hci_dev *) arg;
struct sk_buff *skb;
+ if (unlikely(hdev == NULL)) {
+ FMDERR("%s, HCI Device is null\n", __func__);
+ return;
+ }
read_lock(&hci_task_lock);
skb = skb_dequeue(&hdev->rx_q);
@@ -582,8 +603,6 @@
skb_queue_head_init(&hdev->cmd_q);
skb_queue_head_init(&hdev->raw_q);
- if (!radio)
- FMDERR(":radio is null");
radio->fm_hdev = hdev;
@@ -613,8 +632,14 @@
int radio_hci_recv_frame(struct sk_buff *skb)
{
- struct radio_hci_dev *hdev = (struct radio_hci_dev *) skb->dev;
- if (!hdev) {
+ struct radio_hci_dev *hdev;
+
+ if (unlikely(skb == NULL)) {
+ FMDERR("%s, socket buffer is null\n", __func__);
+ return -EINVAL;
+ }
+ hdev = (struct radio_hci_dev *) skb->dev;
+ if (unlikely(!hdev)) {
FMDERR("%s hdev is null while receiving frame", hdev->name);
kfree_skb(skb);
return -ENXIO;
@@ -636,6 +661,10 @@
struct sk_buff *skb;
int ret = 0;
+ if (unlikely(hdev == NULL)) {
+ FMDERR("%s, hci device is null\n", __func__);
+ return -EINVAL;
+ }
skb = alloc_skb(len, GFP_ATOMIC);
if (!skb) {
FMDERR("%s no memory for command", hdev->name);
@@ -674,6 +703,10 @@
struct iris_device *radio = video_get_drvdata(video_get_dev());
__u16 opcode = 0;
+ if (unlikely(radio == NULL)) {
+ FMDERR(":radio is null");
+ return -EINVAL;
+ }
opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
HCI_FM_SET_INTERNAL_TONE_GENRATOR);
return radio_hci_send_cmd(hdev, opcode,
@@ -737,6 +770,10 @@
struct hci_fm_recv_conf_req *recv_conf_req =
(struct hci_fm_recv_conf_req *) param;
+ if (recv_conf_req == NULL) {
+ FMDERR("%s, recv conf is null\n", __func__);
+ return -EINVAL;
+ }
opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
HCI_OCF_FM_SET_RECV_CONF_REQ);
return radio_hci_send_cmd(hdev, opcode, sizeof((*recv_conf_req)),
@@ -751,6 +788,11 @@
struct hci_fm_trans_conf_req_struct *trans_conf_req =
(struct hci_fm_trans_conf_req_struct *) param;
+ if (trans_conf_req == NULL) {
+ FMDERR("%s, tx conf is null\n", __func__);
+ return -EINVAL;
+ }
+
opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
HCI_OCF_FM_SET_TRANS_CONF_REQ);
return radio_hci_send_cmd(hdev, opcode, sizeof((*trans_conf_req)),
@@ -774,6 +816,10 @@
struct hci_fm_mute_mode_req *mute_mode_req =
(struct hci_fm_mute_mode_req *) param;
+ if (mute_mode_req == NULL) {
+ FMDERR("%s, mute mode is null\n", __func__);
+ return -EINVAL;
+ }
opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
HCI_OCF_FM_SET_MUTE_MODE_REQ);
return radio_hci_send_cmd(hdev, opcode, sizeof((*mute_mode_req)),
@@ -788,6 +834,10 @@
struct hci_fm_tx_ps *tx_ps_req =
(struct hci_fm_tx_ps *) param;
+ if (tx_ps_req == NULL) {
+ FMDERR("%s, tx ps req is null\n", __func__);
+ return -EINVAL;
+ }
opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
HCI_OCF_FM_RDS_PS_REQ);
@@ -802,6 +852,10 @@
struct hci_fm_tx_rt *tx_rt_req =
(struct hci_fm_tx_rt *) param;
+ if (tx_rt_req == NULL) {
+ FMDERR("%s, tx rt req is null\n", __func__);
+ return -EINVAL;
+ }
opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
HCI_OCF_FM_RDS_RT_REQ);
@@ -815,6 +869,11 @@
__u16 opcode = 0;
struct hci_fm_stereo_mode_req *stereo_mode_req =
(struct hci_fm_stereo_mode_req *) param;
+
+ if (stereo_mode_req == NULL) {
+ FMDERR("%s, stere mode req is null\n", __func__);
+ return -EINVAL;
+ }
opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
HCI_OCF_FM_SET_STEREO_MODE_REQ);
return radio_hci_send_cmd(hdev, opcode, sizeof((*stereo_mode_req)),
@@ -904,6 +963,10 @@
struct hci_fm_search_station_req *srch_stations =
(struct hci_fm_search_station_req *) param;
+ if (srch_stations == NULL) {
+ FMDERR("%s, search station param is null\n", __func__);
+ return -EINVAL;
+ }
opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
HCI_OCF_FM_SEARCH_STATIONS);
return radio_hci_send_cmd(hdev, opcode, sizeof((*srch_stations)),
@@ -917,6 +980,10 @@
struct hci_fm_search_rds_station_req *srch_stations =
(struct hci_fm_search_rds_station_req *) param;
+ if (srch_stations == NULL) {
+ FMDERR("%s, rds stations param is null\n", __func__);
+ return -EINVAL;
+ }
opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
HCI_OCF_FM_SEARCH_RDS_STATIONS);
return radio_hci_send_cmd(hdev, opcode, sizeof((*srch_stations)),
@@ -930,6 +997,10 @@
struct hci_fm_search_station_list_req *srch_list =
(struct hci_fm_search_station_list_req *) param;
+ if (srch_list == NULL) {
+ FMDERR("%s, search list param is null\n", __func__);
+ return -EINVAL;
+ }
opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
HCI_OCF_FM_SEARCH_STATIONS_LIST);
return radio_hci_send_cmd(hdev, opcode, sizeof((*srch_list)),
@@ -954,6 +1025,10 @@
struct hci_fm_rds_grp_req *fm_grp_mask =
(struct hci_fm_rds_grp_req *)param;
+ if (fm_grp_mask == NULL) {
+ FMDERR("%s, grp mask param is null\n", __func__);
+ return -EINVAL;
+ }
opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
HCI_OCF_FM_RDS_GRP);
return radio_hci_send_cmd(hdev, opcode, sizeof(*fm_grp_mask),
@@ -992,6 +1067,10 @@
struct hci_fm_def_data_rd_req *def_data_rd =
(struct hci_fm_def_data_rd_req *) param;
+ if (def_data_rd == NULL) {
+ FMDERR("%s, def data read param is null\n", __func__);
+ return -EINVAL;
+ }
opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
HCI_OCF_FM_DEFAULT_DATA_READ);
return radio_hci_send_cmd(hdev, opcode, sizeof((*def_data_rd)),
@@ -1005,6 +1084,10 @@
struct hci_fm_def_data_wr_req *def_data_wr =
(struct hci_fm_def_data_wr_req *) param;
+ if (def_data_wr == NULL) {
+ FMDERR("%s, def data write param is null\n", __func__);
+ return -EINVAL;
+ }
opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
HCI_OCF_FM_DEFAULT_DATA_WRITE);
@@ -1074,6 +1157,10 @@
__u16 opcode = 0;
struct hci_fm_riva_data *peek_data = (struct hci_fm_riva_data *)param;
+ if (peek_data == NULL) {
+ FMDERR("%s, peek data param is null\n", __func__);
+ return -EINVAL;
+ }
opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
HCI_OCF_FM_PEEK_DATA);
return radio_hci_send_cmd(hdev, opcode, sizeof((*peek_data)),
@@ -1085,6 +1172,10 @@
__u16 opcode = 0;
struct hci_fm_riva_poke *poke_data = (struct hci_fm_riva_poke *) param;
+ if (poke_data == NULL) {
+ FMDERR("%s, poke data param is null\n", __func__);
+ return -EINVAL;
+ }
opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
HCI_OCF_FM_POKE_DATA);
return radio_hci_send_cmd(hdev, opcode, sizeof((*poke_data)),
@@ -1097,6 +1188,10 @@
__u16 opcode = 0;
struct hci_fm_ssbi_peek *ssbi_peek = (struct hci_fm_ssbi_peek *) param;
+ if (ssbi_peek == NULL) {
+ FMDERR("%s, ssbi peek param is null\n", __func__);
+ return -EINVAL;
+ }
opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
HCI_OCF_FM_SSBI_PEEK_REG);
return radio_hci_send_cmd(hdev, opcode, sizeof((*ssbi_peek)),
@@ -1109,6 +1204,10 @@
__u16 opcode = 0;
struct hci_fm_ssbi_req *ssbi_poke = (struct hci_fm_ssbi_req *) param;
+ if (ssbi_poke == NULL) {
+ FMDERR("%s, ssbi poke param is null\n", __func__);
+ return -EINVAL;
+ }
opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
HCI_OCF_FM_SSBI_POKE_REG);
return radio_hci_send_cmd(hdev, opcode, sizeof((*ssbi_poke)),
@@ -1130,7 +1229,13 @@
{
struct hci_fm_ch_det_threshold *ch_det_th =
(struct hci_fm_ch_det_threshold *) param;
- u16 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+ u16 opcode;
+
+ if (ch_det_th == NULL) {
+ FMDERR("%s, channel det thrshld is null\n", __func__);
+ return -EINVAL;
+ }
+ opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
HCI_OCF_FM_SET_CH_DET_THRESHOLD);
return radio_hci_send_cmd(hdev, opcode, sizeof((*ch_det_th)),
ch_det_th);
@@ -1144,7 +1249,7 @@
return radio_hci_send_cmd(hdev, opcode, 0, NULL);
}
-static int radio_hci_err(__u16 code)
+static int radio_hci_err(__u32 code)
{
switch (code) {
case 0:
@@ -1174,9 +1279,13 @@
unsigned long param, __u32 timeout)
{
int err = 0;
-
DECLARE_WAITQUEUE(wait, current);
+ if (unlikely(hdev == NULL)) {
+ FMDERR("%s, hci dev is null\n", __func__);
+ return -EINVAL;
+ }
+
mutex_lock(&iris_fm);
hdev->req_status = HCI_REQ_PEND;
@@ -1199,11 +1308,6 @@
case HCI_REQ_STATUS:
err = radio_hci_err(hdev->req_result);
break;
-
- case HCI_REQ_CANCELED:
- err = -hdev->req_result;
- break;
-
default:
err = -ETIMEDOUT;
break;
@@ -1230,7 +1334,13 @@
static inline int hci_conf_event_mask(__u8 *arg,
struct radio_hci_dev *hdev)
{
- u8 event_mask = *arg;
+ u8 event_mask;
+
+ if (arg == NULL) {
+ FMDERR("%s, arg is null\n", __func__);
+ return -EINVAL;
+ }
+ event_mask = *arg;
return radio_hci_request(hdev, hci_fm_set_event_mask,
event_mask, RADIO_HCI_TIMEOUT);
}
@@ -1261,8 +1371,13 @@
static int hci_fm_tune_station(__u32 *arg, struct radio_hci_dev *hdev)
{
int ret = 0;
- __u32 tune_freq = *arg;
+ __u32 tune_freq;
+ if (arg == NULL) {
+ FMDERR("%s, arg is null\n", __func__);
+ return -EINVAL;
+ }
+ tune_freq = *arg;
ret = radio_hci_request(hdev, hci_fm_tune_station_req, tune_freq,
RADIO_HCI_TIMEOUT);
@@ -1296,8 +1411,13 @@
static int hci_fm_set_antenna(__u8 *arg, struct radio_hci_dev *hdev)
{
int ret = 0;
- __u8 antenna = *arg;
+ __u8 antenna;
+ if (arg == NULL) {
+ FMDERR("%s, arg is null\n", __func__);
+ return -EINVAL;
+ }
+ antenna = *arg;
ret = radio_hci_request(hdev, hci_fm_set_antenna_req, antenna,
RADIO_HCI_TIMEOUT);
@@ -1308,8 +1428,13 @@
struct radio_hci_dev *hdev)
{
int ret = 0;
- __u8 sig_threshold = *arg;
+ __u8 sig_threshold;
+ if (arg == NULL) {
+ FMDERR("%s, arg is null\n", __func__);
+ return -EINVAL;
+ }
+ sig_threshold = *arg;
ret = radio_hci_request(hdev, hci_fm_set_sig_threshold_req,
sig_threshold, RADIO_HCI_TIMEOUT);
@@ -1368,8 +1493,13 @@
static int hci_fm_rds_grps_process(__u32 *arg, struct radio_hci_dev *hdev)
{
int ret = 0;
- __u32 fm_grps_process = *arg;
+ __u32 fm_grps_process;
+ if (arg == NULL) {
+ FMDERR("%s, arg is null\n", __func__);
+ return -EINVAL;
+ }
+ fm_grps_process = *arg;
ret = radio_hci_request(hdev, hci_fm_rds_grp_process_req,
fm_grps_process, RADIO_HCI_TIMEOUT);
@@ -1401,8 +1531,13 @@
int hci_fm_do_calibration(__u8 *arg, struct radio_hci_dev *hdev)
{
int ret = 0;
- __u8 mode = *arg;
+ __u8 mode;
+ if (arg == NULL) {
+ FMDERR("%s, arg is null\n", __func__);
+ return -EINVAL;
+ }
+ mode = *arg;
ret = radio_hci_request(hdev, hci_fm_do_calibration_req, mode,
RADIO_HCI_TIMEOUT);
@@ -1412,7 +1547,13 @@
static int hci_read_grp_counters(__u8 *arg, struct radio_hci_dev *hdev)
{
int ret = 0;
- __u8 reset_counters = *arg;
+ __u8 reset_counters;
+
+ if (arg == NULL) {
+ FMDERR("%s, arg is null\n", __func__);
+ return -EINVAL;
+ }
+ reset_counters = *arg;
ret = radio_hci_request(hdev, hci_read_grp_counters_req,
reset_counters, RADIO_HCI_TIMEOUT);
@@ -1422,7 +1563,14 @@
static int hci_set_notch_filter(__u8 *arg, struct radio_hci_dev *hdev)
{
int ret = 0;
- __u8 notch_filter = *arg;
+ __u8 notch_filter;
+
+ if (arg == NULL) {
+ FMDERR("%s, arg is null\n", __func__);
+ return -EINVAL;
+ }
+
+ notch_filter = *arg;
ret = radio_hci_request(hdev, hci_set_notch_filter_req,
notch_filter, RADIO_HCI_TIMEOUT);
@@ -1496,8 +1644,8 @@
opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
HCI_OCF_FM_SET_CALIBRATION);
- return radio_hci_send_cmd(hdev, opcode, sizeof(*cal_req),
- cal_req);
+ return radio_hci_send_cmd(hdev, opcode,
+ sizeof(hci_fm_set_cal_req_proc), cal_req);
}
static int hci_fm_do_cal_req(struct radio_hci_dev *hdev,
@@ -1614,6 +1762,11 @@
static void radio_hci_req_complete(struct radio_hci_dev *hdev, int result)
{
+
+ if (unlikely(hdev == NULL)) {
+ FMDERR("%s, hci device is null\n", __func__);
+ return;
+ }
hdev->req_result = result;
hdev->req_status = HCI_REQ_DONE;
wake_up_interruptible(&hdev->req_wait_q);
@@ -1621,6 +1774,10 @@
static void radio_hci_status_complete(struct radio_hci_dev *hdev, int result)
{
+ if (unlikely(hdev == NULL)) {
+ FMDERR("%s, hci device is null\n", __func__);
+ return;
+ }
hdev->req_result = result;
hdev->req_status = HCI_REQ_STATUS;
wake_up_interruptible(&hdev->req_wait_q);
@@ -1628,10 +1785,13 @@
static void hci_cc_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
{
- __u8 status = *((__u8 *) skb->data);
+ __u8 status;
- if (status)
+ if (unlikely(skb == NULL)) {
+ FMDERR("%s, socket buffer is null\n", __func__);
return;
+ }
+ status = *((__u8 *) skb->data);
radio_hci_req_complete(hdev, status);
}
@@ -1639,9 +1799,20 @@
static void hci_cc_fm_disable_rsp(struct radio_hci_dev *hdev,
struct sk_buff *skb)
{
- __u8 status = *((__u8 *) skb->data);
+ __u8 status;
struct iris_device *radio = video_get_drvdata(video_get_dev());
+ if (unlikely(radio == NULL)) {
+ FMDERR(":radio is null");
+ return;
+ }
+
+ if (unlikely(skb == NULL)) {
+ FMDERR("%s, socket buffer is null\n", __func__);
+ return;
+ }
+
+ status = *((__u8 *) skb->data);
if ((radio->mode == FM_TURNING_OFF) && (status == 0)) {
iris_q_event(radio, IRIS_EVT_RADIO_DISABLED);
radio_hci_req_complete(hdev, status);
@@ -1651,40 +1822,71 @@
} else if ((radio->mode == FM_RECV) || (radio->mode == FM_TRANS)) {
iris_q_event(radio, IRIS_EVT_RADIO_DISABLED);
radio->mode = FM_OFF;
+ } else if ((radio->mode == FM_TURNING_OFF) && (status != 0)) {
+ radio_hci_req_complete(hdev, status);
}
}
static void hci_cc_conf_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_fm_conf_rsp *rsp = (void *)skb->data;
+ struct hci_fm_conf_rsp *rsp;
struct iris_device *radio = video_get_drvdata(video_get_dev());
- if (rsp->status)
+ if (unlikely(radio == NULL)) {
+ FMDERR(":radio is null");
return;
-
- radio->recv_conf = rsp->recv_conf_rsp;
+ }
+ if (unlikely(skb == NULL)) {
+ FMDERR("%s, socket buffer is null\n", __func__);
+ return;
+ }
+ rsp = (struct hci_fm_conf_rsp *)skb->data;
+ if (!rsp->status)
+ radio->recv_conf = rsp->recv_conf_rsp;
radio_hci_req_complete(hdev, rsp->status);
}
static void hci_cc_fm_trans_get_conf_rsp(struct radio_hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_fm_get_trans_conf_rsp *rsp = (void *)skb->data;
+ struct hci_fm_get_trans_conf_rsp *rsp;
struct iris_device *radio = video_get_drvdata(video_get_dev());
- if (rsp->status)
+ if (unlikely(radio == NULL)) {
+ FMDERR(":radio is null");
return;
- memcpy((void *)&radio->trans_conf, (void*)&rsp->trans_conf_rsp,
+ }
+ if (unlikely(skb == NULL)) {
+ FMDERR("%s, socket buffer is null\n", __func__);
+ return;
+ }
+
+ rsp = (struct hci_fm_get_trans_conf_rsp *)skb->data;
+ if (!rsp->status)
+ memcpy((void *)&radio->trans_conf,
+ (void *)&rsp->trans_conf_rsp,
sizeof(rsp->trans_conf_rsp));
+
radio_hci_req_complete(hdev, rsp->status);
}
static void hci_cc_fm_enable_rsp(struct radio_hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_fm_conf_rsp *rsp = (void *)skb->data;
+ struct hci_fm_conf_rsp *rsp;
struct iris_device *radio = video_get_drvdata(video_get_dev());
+ if (unlikely(radio == NULL)) {
+ FMDERR(":radio is null");
+ return;
+ }
+
+ if (unlikely(skb == NULL)) {
+ FMDERR("%s, socket buffer is null\n", __func__);
+ return;
+ }
+
+ rsp = (struct hci_fm_conf_rsp *)skb->data;
if (rsp->status) {
radio_hci_req_complete(hdev, rsp->status);
return;
@@ -1704,13 +1906,21 @@
static void hci_cc_fm_trans_set_conf_rsp(struct radio_hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_fm_conf_rsp *rsp = (void *)skb->data;
+ struct hci_fm_conf_rsp *rsp;
struct iris_device *radio = video_get_drvdata(video_get_dev());
- if (rsp->status)
+ if (unlikely(radio == NULL)) {
+ FMDERR(":radio is null");
return;
+ }
- iris_q_event(radio, HCI_EV_CMD_COMPLETE);
+ if (unlikely(skb == NULL)) {
+ FMDERR("%s, socket buffer is null\n", __func__);
+ return;
+ }
+ rsp = (struct hci_fm_conf_rsp *)skb->data;
+ if (!rsp->status)
+ iris_q_event(radio, HCI_EV_CMD_COMPLETE);
radio_hci_req_complete(hdev, rsp->status);
}
@@ -1719,20 +1929,41 @@
static void hci_cc_sig_threshold_rsp(struct radio_hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_fm_sig_threshold_rsp *rsp = (void *)skb->data;
+ struct hci_fm_sig_threshold_rsp *rsp;
struct iris_device *radio = video_get_drvdata(video_get_dev());
- if (rsp->status)
+ if (unlikely(radio == NULL)) {
+ FMDERR(":radio is null");
return;
+ }
+ if (unlikely(skb == NULL)) {
+ FMDERR("%s, socket buffer is null\n", __func__);
+ return;
+ }
- memcpy(&radio->sig_th, rsp, sizeof(struct hci_fm_sig_threshold_rsp));
+ rsp = (struct hci_fm_sig_threshold_rsp *)skb->data;
+ if (!rsp->status)
+ memcpy(&radio->sig_th, rsp,
+ sizeof(struct hci_fm_sig_threshold_rsp));
+
radio_hci_req_complete(hdev, rsp->status);
}
static void hci_cc_station_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
{
struct iris_device *radio = video_get_drvdata(video_get_dev());
- struct hci_fm_station_rsp *rsp = (void *)skb->data;
+ struct hci_fm_station_rsp *rsp;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR(":radio is null");
+ return;
+ }
+ if (unlikely(skb == NULL)) {
+ FMDERR("%s, socket buffer is null\n", __func__);
+ return;
+ }
+
+ rsp = (struct hci_fm_station_rsp *)skb->data;
radio->fm_st_rsp = *(rsp);
/* Tune is always succesful */
@@ -1741,45 +1972,67 @@
static void hci_cc_prg_srv_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_fm_prgm_srv_rsp *rsp = (void *)skb->data;
+ struct hci_fm_prgm_srv_rsp *rsp;
- if (rsp->status)
+ if (unlikely(skb == NULL)) {
+ FMDERR("%s, socket buffer is null\n", __func__);
return;
+ }
+
+ rsp = (struct hci_fm_prgm_srv_rsp *)skb->data;
radio_hci_req_complete(hdev, rsp->status);
}
static void hci_cc_rd_txt_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_fm_radio_txt_rsp *rsp = (void *)skb->data;
+ struct hci_fm_radio_txt_rsp *rsp;
- if (rsp->status)
+ if (unlikely(skb == NULL)) {
+ FMDERR("%s, socket buffer is null\n", __func__);
return;
+ }
+ rsp = (struct hci_fm_radio_txt_rsp *)skb->data;
radio_hci_req_complete(hdev, rsp->status);
}
static void hci_cc_af_list_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_fm_af_list_rsp *rsp = (void *)skb->data;
+ struct hci_fm_af_list_rsp *rsp;
- if (rsp->status)
+ if (unlikely(skb == NULL)) {
+ FMDERR("%s, socket buffer is null\n", __func__);
return;
+ }
+ rsp = (struct hci_fm_af_list_rsp *)skb->data;
radio_hci_req_complete(hdev, rsp->status);
}
static void hci_cc_feature_list_rsp(struct radio_hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_fm_feature_list_rsp *rsp = (void *)skb->data;
+ struct v4l2_capability *v4l_cap;
+ struct hci_fm_feature_list_rsp *rsp;
struct iris_device *radio = video_get_drvdata(video_get_dev());
- struct v4l2_capability *v4l_cap = radio->g_cap;
- if (rsp->status)
+ if (unlikely(radio == NULL)) {
+ FMDERR(":radio is null");
return;
- v4l_cap->capabilities = (rsp->feature_mask & 0x000002) |
- (rsp->feature_mask & 0x000001);
+ }
+
+ if (unlikely(skb == NULL)) {
+ FMDERR("%s, socket buffer is null\n", __func__);
+ return;
+ }
+
+ rsp = (struct hci_fm_feature_list_rsp *)skb->data;
+ v4l_cap = &radio->g_cap;
+
+ if (!rsp->status)
+ v4l_cap->capabilities = (rsp->feature_mask & 0x000002) |
+ (rsp->feature_mask & 0x000001);
radio_hci_req_complete(hdev, rsp->status);
}
@@ -1788,19 +2041,33 @@
struct sk_buff *skb)
{
struct iris_device *radio = video_get_drvdata(video_get_dev());
- struct hci_fm_dbg_param_rsp *rsp = (void *)skb->data;
- radio->st_dbg_param = *(rsp);
+ struct hci_fm_dbg_param_rsp *rsp;
- if (radio->st_dbg_param.status)
+ if (unlikely(radio == NULL)) {
+ FMDERR(":radio is null");
return;
+ }
+ if (unlikely(skb == NULL)) {
+ FMDERR("%s, socket buffer is null\n", __func__);
+ return;
+ }
+
+ rsp = (struct hci_fm_dbg_param_rsp *)skb->data;
+ radio->st_dbg_param = *(rsp);
radio_hci_req_complete(hdev, radio->st_dbg_param.status);
}
static void iris_q_evt_data(struct iris_device *radio,
char *data, int len, int event)
{
- struct kfifo *data_b = &radio->data_buf[event];
+ struct kfifo *data_b;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR(":radio is null");
+ return;
+ }
+ data_b = &radio->data_buf[event];
if (kfifo_in_locked(data_b, data, len, &radio->buf_lock[event]))
wake_up_interruptible(&radio->event_queue);
}
@@ -1809,41 +2076,55 @@
struct sk_buff *skb)
{
struct iris_device *radio = video_get_drvdata(video_get_dev());
- __u8 status = *((__u8 *) skb->data);
+ __u8 status;
int len;
char *data;
- if (status)
- return;
- len = skb->data[RIVA_PEEK_LEN_OFSET] + RIVA_PEEK_PARAM;
- data = kmalloc(len, GFP_ATOMIC);
-
- if (!data) {
- FMDERR("Memory allocation failed");
+ if (unlikely(skb == NULL)) {
+ FMDERR("%s, socket buffer is null\n", __func__);
return;
}
+ status = *((__u8 *) skb->data);
+ if (!status) {
+ len = skb->data[RIVA_PEEK_LEN_OFSET] + RIVA_PEEK_PARAM;
+ data = kmalloc(len, GFP_ATOMIC);
- memcpy(data, &skb->data[PEEK_DATA_OFSET], len);
- iris_q_evt_data(radio, data, len, IRIS_BUF_PEEK);
+ if (data != NULL) {
+ memcpy(data, &skb->data[PEEK_DATA_OFSET], len);
+ iris_q_evt_data(radio, data, len, IRIS_BUF_PEEK);
+ kfree(data);
+ } else {
+ FMDERR("Memory allocation failed");
+ }
+ }
+
radio_hci_req_complete(hdev, status);
- kfree(data);
-
}
static void hci_cc_riva_read_default_rsp(struct radio_hci_dev *hdev,
struct sk_buff *skb)
{
struct iris_device *radio = video_get_drvdata(video_get_dev());
- __u8 status = *((__u8 *) skb->data);
+ __u8 status;
__u8 len;
- if (status)
+ if (unlikely(radio == NULL)) {
+ FMDERR(":radio is null");
return;
- len = skb->data[1];
-
- memset(&radio->default_data, 0 , sizeof(struct hci_fm_data_rd_rsp));
- memcpy(&radio->default_data, &skb->data[0], len+2);
- iris_q_evt_data(radio, &skb->data[0], len+2, IRIS_BUF_RD_DEFAULT);
+ }
+ if (unlikely(skb == NULL)) {
+ FMDERR("%s, socket buffer is null\n", __func__);
+ return;
+ }
+ status = *((__u8 *) skb->data);
+ if (!status) {
+ len = skb->data[1];
+ memset(&radio->default_data, 0,
+ sizeof(struct hci_fm_data_rd_rsp));
+ memcpy(&radio->default_data, &skb->data[0], len+2);
+ iris_q_evt_data(radio, &skb->data[0], len+2,
+ IRIS_BUF_RD_DEFAULT);
+ }
radio_hci_req_complete(hdev, status);
}
@@ -1851,41 +2132,53 @@
struct sk_buff *skb)
{
struct iris_device *radio = video_get_drvdata(video_get_dev());
- __u8 status = *((__u8 *) skb->data);
+ __u8 status;
char *data;
- if (status)
- return;
- data = kmalloc(SSBI_PEEK_LEN, GFP_ATOMIC);
- if (!data) {
- FMDERR("Memory allocation failed");
+ if (unlikely(skb == NULL)) {
+ FMDERR("%s, socket buffer is null\n", __func__);
return;
}
+ status = *((__u8 *) skb->data);
+ if (!status) {
+ data = kmalloc(SSBI_PEEK_LEN, GFP_ATOMIC);
+ if (data != NULL) {
+ data[0] = skb->data[PEEK_DATA_OFSET];
+ iris_q_evt_data(radio, data, SSBI_PEEK_LEN,
+ IRIS_BUF_SSBI_PEEK);
+ kfree(data);
+ } else {
+ FMDERR("Memory allocation failed");
+ }
+ }
- data[0] = skb->data[PEEK_DATA_OFSET];
- iris_q_evt_data(radio, data, SSBI_PEEK_LEN, IRIS_BUF_SSBI_PEEK);
radio_hci_req_complete(hdev, status);
- kfree(data);
}
static void hci_cc_rds_grp_cntrs_rsp(struct radio_hci_dev *hdev,
struct sk_buff *skb)
{
struct iris_device *radio = video_get_drvdata(video_get_dev());
- __u8 status = *((__u8 *) skb->data);
+ __u8 status;
char *data;
- if (status)
- return;
- data = kmalloc(RDS_GRP_CNTR_LEN, GFP_ATOMIC);
- if (!data) {
- FMDERR("memory allocation failed");
+
+ if (unlikely(skb == NULL)) {
+ FMDERR("%s, socket buffer is null\n", __func__);
return;
}
- memcpy(data, &skb->data[1], RDS_GRP_CNTR_LEN);
- iris_q_evt_data(radio, data, RDS_GRP_CNTR_LEN, IRIS_BUF_RDS_CNTRS);
+ status = *((__u8 *) skb->data);
+ if (!status) {
+ data = kmalloc(RDS_GRP_CNTR_LEN, GFP_ATOMIC);
+ if (data != NULL) {
+ memcpy(data, &skb->data[1], RDS_GRP_CNTR_LEN);
+ iris_q_evt_data(radio, data, RDS_GRP_CNTR_LEN,
+ IRIS_BUF_RDS_CNTRS);
+ kfree(data);
+ } else {
+ FMDERR("memory allocation failed");
+ }
+ }
radio_hci_req_complete(hdev, status);
- kfree(data);
-
}
static void hci_cc_do_calibration_rsp(struct radio_hci_dev *hdev,
@@ -1893,22 +2186,23 @@
{
struct iris_device *radio = video_get_drvdata(video_get_dev());
static struct hci_cc_do_calibration_rsp rsp ;
+
+ if (unlikely(skb == NULL)) {
+ FMDERR("%s, socket buffer is null\n", __func__);
+ return;
+ }
+
rsp.status = skb->data[0];
rsp.mode = skb->data[CALIB_MODE_OFSET];
- if (rsp.status) {
- FMDERR("status = %d", rsp.status);
- return;
- }
- if (rsp.mode == PROCS_CALIB_MODE) {
- memcpy(&rsp.data[0], &skb->data[CALIB_DATA_OFSET],
+ if (!rsp.status) {
+ if (rsp.mode == PROCS_CALIB_MODE) {
+ memcpy(&rsp.data[0], &skb->data[CALIB_DATA_OFSET],
PROCS_CALIB_SIZE);
- iris_q_evt_data(radio, rsp.data, PROCS_CALIB_SIZE,
+ iris_q_evt_data(radio, rsp.data, PROCS_CALIB_SIZE,
IRIS_BUF_CAL_DATA);
- } else {
- return;
+ }
}
-
radio_hci_req_complete(hdev, rsp.status);
}
@@ -1916,22 +2210,37 @@
struct sk_buff *skb)
{
struct iris_device *radio = video_get_drvdata(video_get_dev());
- u8 status = skb->data[0];
- if (status) {
- FMDERR("status = %d", status);
+ u8 status;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR(":radio is null");
return;
}
- memcpy(&radio->ch_det_threshold, &skb->data[1],
- sizeof(struct hci_fm_ch_det_threshold));
+ if (unlikely(skb == NULL)) {
+ FMDERR("%s, socket buffer is null\n", __func__);
+ return;
+ }
+ status = skb->data[0];
+ if (!status)
+ memcpy(&radio->ch_det_threshold, &skb->data[1],
+ sizeof(struct hci_fm_ch_det_threshold));
+
radio_hci_req_complete(hdev, status);
}
static inline void hci_cmd_complete_event(struct radio_hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_ev_cmd_complete *cmd_compl_ev = (void *) skb->data;
+ struct hci_ev_cmd_complete *cmd_compl_ev;
__u16 opcode;
+
+ if (unlikely(skb == NULL)) {
+ FMDERR("%s, socket buffer is null\n", __func__);
+ return;
+ }
+
+ cmd_compl_ev = (struct hci_ev_cmd_complete *)skb->data;
skb_pull(skb, sizeof(*cmd_compl_ev));
opcode = __le16_to_cpu(cmd_compl_ev->cmd_opcode);
@@ -2050,6 +2359,10 @@
int i;
struct iris_device *radio = video_get_drvdata(video_get_dev());
+ if (unlikely(radio == NULL)) {
+ FMDERR(":radio is null");
+ return;
+ }
memcpy(&radio->fm_st_rsp.station_rsp, &skb->data[0],
sizeof(struct hci_ev_tune_status));
iris_q_event(radio, IRIS_EVT_TUNE_SUCC);
@@ -2078,6 +2391,7 @@
struct sk_buff *skb)
{
struct iris_device *radio = video_get_drvdata(video_get_dev());
+ radio->search_on = 0;
iris_q_event(radio, IRIS_EVT_SEEK_COMPLETE);
}
@@ -2092,6 +2406,15 @@
int abs_freq;
int len;
+ if (unlikely(radio == NULL)) {
+ FMDERR(":radio is null");
+ return;
+ }
+
+ if (unlikely(skb == NULL)) {
+ FMDERR("%s, socket buffer is null\n", __func__);
+ return;
+ }
ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
if (!ev) {
FMDERR("Memory allocation failed");
@@ -2130,7 +2453,13 @@
struct sk_buff *skb)
{
struct iris_device *radio = video_get_drvdata(video_get_dev());
- __u8 st_status = *((__u8 *) skb->data);
+ __u8 st_status;
+
+ if (unlikely(skb == NULL)) {
+ FMDERR("%s, socket buffer is null\n", __func__);
+ return;
+ }
+ st_status = *((__u8 *) skb->data);
if (st_status)
iris_q_event(radio, IRIS_EVT_STEREO);
else
@@ -2150,6 +2479,16 @@
radio = video_get_drvdata(video_get_dev());
index = RDSGRP_DATA_OFFSET;
+ if (unlikely(radio == NULL)) {
+ FMDERR(":radio is null");
+ return;
+ }
+
+ if (unlikely(skb == NULL)) {
+ FMDERR("%s, socket buffer is null\n", __func__);
+ return;
+ }
+
for (blocknum = 0; blocknum < RDS_BLOCKS_NUM; blocknum++) {
temp.rdsBlk[blocknum].rdsLsb =
(skb->data[index]);
@@ -2220,6 +2559,10 @@
unsigned short int info_byte = 0;
unsigned short int byte_pair_index;
+ if (rds_buf == NULL) {
+ FMDERR("%s, rds buffer is null\n", __func__);
+ return;
+ }
byte_pair_index = AGT(rds_buf->rdsBlk[1].rdsLsb);
if (byte_pair_index == 0) {
c_byt_pair_index = 0;
@@ -2402,6 +2745,10 @@
int len = 0;
char *data;
+ if (unlikely(skb == NULL)) {
+ FMDERR("%s, socket buffer is null\n", __func__);
+ return;
+ }
iris_q_event(radio, IRIS_EVT_NEW_RT_RDS);
while ((skb->data[len+RDS_OFFSET] != 0x0d) && (len < MAX_RT_LENGTH))
@@ -2432,6 +2779,10 @@
struct iris_device *radio = video_get_drvdata(video_get_dev());
struct hci_ev_af_list ev;
+ if (unlikely(skb == NULL)) {
+ FMDERR("%s, socket buffer is null\n", __func__);
+ return;
+ }
ev.tune_freq = *((int *) &skb->data[0]);
ev.pi_code = *((__le16 *) &skb->data[PI_CODE_OFFSET]);
ev.af_size = skb->data[AF_SIZE_OFFSET];
@@ -2450,7 +2801,14 @@
struct sk_buff *skb)
{
struct iris_device *radio = video_get_drvdata(video_get_dev());
- __u8 rds_status = skb->data[0];
+ __u8 rds_status;
+
+ if (unlikely(skb == NULL)) {
+ FMDERR("%s, socket buffer is null\n", __func__);
+ return;
+ }
+
+ rds_status = skb->data[0];
if (rds_status)
iris_q_event(radio, IRIS_EVT_RDS_AVAIL);
@@ -2462,7 +2820,13 @@
struct sk_buff *skb)
{
struct iris_device *radio = video_get_drvdata(video_get_dev());
- u8 serv_avble = skb->data[0];
+ u8 serv_avble;
+
+ if (unlikely(skb == NULL)) {
+ FMDERR("%s, socket buffer is null\n", __func__);
+ return;
+ }
+ serv_avble = skb->data[0];
if (serv_avble)
iris_q_event(radio, IRIS_EVT_ABOVE_TH);
else
@@ -2556,9 +2920,17 @@
static int iris_search(struct iris_device *radio, int on, int dir)
{
int retval = 0;
- enum search_t srch = radio->g_search_mode & SRCH_MODE;
- radio->search_on = on;
+ enum search_t srch;
+ int saved_val;
+ if (unlikely(radio == NULL)) {
+ FMDERR(":radio is null");
+ return -EINVAL;
+ }
+
+ srch = radio->g_search_mode & SRCH_MODE;
+ saved_val = radio->search_on;
+ radio->search_on = on;
if (on) {
switch (srch) {
case SCAN_FOR_STRONG:
@@ -2592,6 +2964,8 @@
retval = hci_cmd(HCI_FM_CANCEL_SEARCH_CMD, radio->fm_hdev);
}
+ if (retval < 0)
+ radio->search_on = saved_val;
return retval;
}
@@ -2600,6 +2974,12 @@
int rds_grps_proc = 0x00;
int retval = 0;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR(":radio is null");
+ return -EINVAL;
+ }
+
if (radio->power_mode != power_mode) {
if (power_mode) {
@@ -2638,12 +3018,22 @@
static int iris_recv_set_region(struct iris_device *radio, int req_region)
{
int retval;
+ int saved_val;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR(":radio is null");
+ return -EINVAL;
+ }
+ saved_val = radio->region;
radio->region = req_region;
retval = hci_set_fm_recv_conf(
&radio->recv_conf,
radio->fm_hdev);
+ if (retval < 0)
+ radio->region = saved_val;
+
return retval;
}
@@ -2651,11 +3041,22 @@
static int iris_trans_set_region(struct iris_device *radio, int req_region)
{
int retval;
+ int saved_val;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR(":radio is null");
+ return -EINVAL;
+ }
+
+ saved_val = radio->region;
radio->region = req_region;
retval = hci_set_fm_trans_conf(
&radio->trans_conf,
radio->fm_hdev);
+
+ if (retval < 0)
+ radio->region = saved_val;
return retval;
}
@@ -2664,6 +3065,11 @@
{
int retval;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR(":radio is null");
+ return -EINVAL;
+ }
retval = hci_fm_tune_station(&freq, radio->fm_hdev);
if (retval < 0)
FMDERR("Error while setting the frequency : %d\n", retval);
@@ -2677,6 +3083,10 @@
unsigned char i;
int retval = -EINVAL;
+ if (unlikely(qc == NULL)) {
+ FMDERR("%s, query ctrl is null\n", __func__);
+ return retval;
+ }
for (i = 0; i < ARRAY_SIZE(iris_v4l2_queryctrl); i++) {
if (qc->id && qc->id == iris_v4l2_queryctrl[i].id) {
memcpy(qc, &(iris_v4l2_queryctrl[i]), sizeof(*qc));
@@ -2693,6 +3103,11 @@
char cal_mode = 0x00;
int retval = 0x00;
+ if (unlikely(radio == NULL)) {
+ FMDERR(":radio is null");
+ return -EINVAL;
+ }
+
cal_mode = PROCS_CALIB_MODE;
radio->mode = FM_CALIB;
retval = hci_cmd(HCI_FM_ENABLE_RECV_CMD,
@@ -2727,23 +3142,46 @@
struct hci_fm_def_data_rd_req rd;
int lsb, msb;
+ if (unlikely(radio == NULL)) {
+ FMDERR(":radio is null");
+ retval = -EINVAL;
+ goto END;
+ }
+
+ if (unlikely(ctrl == NULL)) {
+ FMDERR("%s, v4l2 ctrl is null\n", __func__);
+ retval = -EINVAL;
+ goto END;
+ }
switch (ctrl->id) {
case V4L2_CID_AUDIO_VOLUME:
break;
case V4L2_CID_AUDIO_MUTE:
- ctrl->value = radio->mute_mode.hard_mute;
+ if (is_valid_hard_mute(radio->mute_mode.hard_mute))
+ ctrl->value = radio->mute_mode.hard_mute;
+ else
+ retval = -EINVAL;
break;
case V4L2_CID_PRIVATE_IRIS_SRCHMODE:
- ctrl->value = radio->g_search_mode;
+ if (is_valid_srch_mode(radio->g_search_mode))
+ ctrl->value = radio->g_search_mode;
+ else
+ retval = -EINVAL;
break;
case V4L2_CID_PRIVATE_IRIS_SCANDWELL:
- ctrl->value = radio->g_scan_time;
+ if (is_valid_scan_dwell_prd(radio->g_scan_time))
+ ctrl->value = radio->g_scan_time;
+ else
+ retval = -EINVAL;
break;
case V4L2_CID_PRIVATE_IRIS_SRCHON:
ctrl->value = radio->search_on;
break;
case V4L2_CID_PRIVATE_IRIS_STATE:
- ctrl->value = radio->mode;
+ if (is_valid_fm_state(radio->mode))
+ ctrl->value = radio->mode;
+ else
+ retval = -EINVAL;
break;
case V4L2_CID_PRIVATE_IRIS_IOVERC:
retval = hci_cmd(HCI_FM_STATION_DBG_PARAM_CMD, radio->fm_hdev);
@@ -2753,68 +3191,115 @@
break;
case V4L2_CID_PRIVATE_IRIS_INTDET:
retval = hci_cmd(HCI_FM_STATION_DBG_PARAM_CMD, radio->fm_hdev);
- if (retval < 0)
- return retval;
- ctrl->value = radio->st_dbg_param.in_det_out;
+ if (retval == 0)
+ ctrl->value = radio->st_dbg_param.in_det_out;
+ else
+ retval = -EINVAL;
break;
case V4L2_CID_PRIVATE_IRIS_REGION:
ctrl->value = radio->region;
break;
case V4L2_CID_PRIVATE_IRIS_SIGNAL_TH:
retval = hci_cmd(HCI_FM_GET_SIGNAL_TH_CMD, radio->fm_hdev);
- if (retval < 0) {
- FMDERR("Error in get signal threshold %d\n", retval);
- return retval;
- }
- ctrl->value = radio->sig_th.sig_threshold;
+ if ((retval == 0) &&
+ is_valid_sig_th(radio->sig_th.sig_threshold))
+ ctrl->value = radio->sig_th.sig_threshold;
+ else
+ retval = -EINVAL;
break;
case V4L2_CID_PRIVATE_IRIS_SRCH_PTY:
- ctrl->value = radio->srch_rds.srch_pty;
+ if (is_valid_pty(radio->srch_rds.srch_pty))
+ ctrl->value = radio->srch_rds.srch_pty;
+ else
+ retval = -EINVAL;
break;
case V4L2_CID_PRIVATE_IRIS_SRCH_PI:
- ctrl->value = radio->srch_rds.srch_pi;
+ if (is_valid_pi(radio->srch_rds.srch_pi))
+ ctrl->value = radio->srch_rds.srch_pi;
+ else
+ retval = -EINVAL;
break;
case V4L2_CID_PRIVATE_IRIS_SRCH_CNT:
- ctrl->value = radio->srch_st_result.num_stations_found;
+ if (is_valid_srch_station_cnt(
+ radio->srch_st_result.num_stations_found))
+ ctrl->value = radio->srch_st_result.num_stations_found;
+ else
+ retval = -EINVAL;
break;
case V4L2_CID_PRIVATE_IRIS_EMPHASIS:
if (radio->mode == FM_RECV) {
- ctrl->value = radio->recv_conf.emphasis;
+ retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
+ radio->fm_hdev);
+ if ((retval == 0) &&
+ is_valid_emphasis(radio->recv_conf.emphasis))
+ ctrl->value = radio->recv_conf.emphasis;
+ else
+ retval = -EINVAL;
} else if (radio->mode == FM_TRANS) {
- ctrl->value = radio->trans_conf.emphasis;
+ retval = hci_cmd(HCI_FM_GET_TX_CONFIG,
+ radio->fm_hdev);
+ if ((retval == 0) &&
+ is_valid_emphasis(radio->trans_conf.emphasis))
+ ctrl->value = radio->trans_conf.emphasis;
+ else
+ retval = -EINVAL;
} else {
- FMDERR("Error in radio mode"
- " %d\n", retval);
- return -EINVAL;
+ retval = -EINVAL;
+ FMDERR("Error in radio mode"" %d\n", retval);
}
break;
case V4L2_CID_PRIVATE_IRIS_RDS_STD:
if (radio->mode == FM_RECV) {
- ctrl->value = radio->recv_conf.rds_std;
+ retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
+ radio->fm_hdev);
+ if ((retval == 0) &&
+ is_valid_rds_std(radio->recv_conf.rds_std))
+ ctrl->value = radio->recv_conf.rds_std;
+ else
+ retval = -EINVAL;
} else if (radio->mode == FM_TRANS) {
- ctrl->value = radio->trans_conf.rds_std;
+ retval = hci_cmd(HCI_FM_GET_TX_CONFIG,
+ radio->fm_hdev);
+ if ((retval == 0) &&
+ is_valid_rds_std(radio->trans_conf.rds_std))
+ ctrl->value = radio->trans_conf.rds_std;
+ else
+ retval = -EINVAL;
} else {
+ retval = -EINVAL;
FMDERR("Error in radio mode"
" %d\n", retval);
- return -EINVAL;
}
break;
case V4L2_CID_PRIVATE_IRIS_SPACING:
if (radio->mode == FM_RECV) {
- ctrl->value = radio->recv_conf.ch_spacing;
+ retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
+ radio->fm_hdev);
+ if ((retval == 0) &&
+ is_valid_chan_spacing(
+ radio->recv_conf.ch_spacing))
+ ctrl->value = radio->recv_conf.ch_spacing;
+ else
+ retval = -EINVAL;
} else {
+ retval = -EINVAL;
FMDERR("Error in radio mode"
" %d\n", retval);
- return -EINVAL;
}
break;
case V4L2_CID_PRIVATE_IRIS_RDSON:
if (radio->mode == FM_RECV) {
- ctrl->value = radio->recv_conf.rds_std;
+ retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
+ radio->fm_hdev);
+ if ((retval == 0) &&
+ is_valid_rds_std(radio->recv_conf.rds_std))
+ ctrl->value = radio->recv_conf.rds_std;
+ else
+ retval = -EINVAL;
} else {
+ retval = -EINVAL;
FMDERR("Error in radio mode"
" %d\n", retval);
- return -EINVAL;
}
break;
case V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK:
@@ -2834,7 +3319,12 @@
ctrl->value = radio->g_antenna;
break;
case V4L2_CID_PRIVATE_IRIS_SOFT_MUTE:
- ctrl->value = radio->mute_mode.soft_mute;
+ retval = hci_cmd(HCI_FM_STATION_DBG_PARAM_CMD, radio->fm_hdev);
+ if ((retval == 0) &&
+ is_valid_soft_mute(radio->mute_mode.soft_mute))
+ ctrl->value = radio->mute_mode.soft_mute;
+ else
+ retval = -EINVAL;
break;
case V4L2_CID_PRIVATE_IRIS_DO_CALIBRATION:
retval = iris_do_calibration(radio);
@@ -2843,47 +3333,30 @@
if (radio->mode == FM_RECV) {
retval = hci_cmd(HCI_FM_GET_STATION_PARAM_CMD,
radio->fm_hdev);
- if (retval < 0) {
- FMDERR("Get SINR Failed");
- return retval;
- }
- ctrl->value = radio->fm_st_rsp.station_rsp.sinr;
-
+ if (retval == 0)
+ ctrl->value = radio->fm_st_rsp.station_rsp.sinr;
} else
retval = -EINVAL;
break;
case V4L2_CID_PRIVATE_INTF_HIGH_THRESHOLD:
retval = hci_cmd(HCI_FM_GET_DET_CH_TH_CMD, radio->fm_hdev);
- if (retval < 0) {
- FMDERR("Get High det threshold failed %x", retval);
- return retval;
- }
- ctrl->value = radio->ch_det_threshold.high_th;
+ if (retval == 0)
+ ctrl->value = radio->ch_det_threshold.high_th;
break;
case V4L2_CID_PRIVATE_INTF_LOW_THRESHOLD:
retval = hci_cmd(HCI_FM_GET_DET_CH_TH_CMD, radio->fm_hdev);
- if (retval < 0) {
- FMDERR("Get Low det threshold failed %x", retval);
- return retval;
- }
- ctrl->value = radio->ch_det_threshold.low_th;
+ if (retval == 0)
+ ctrl->value = radio->ch_det_threshold.low_th;
break;
case V4L2_CID_PRIVATE_SINR_THRESHOLD:
retval = hci_cmd(HCI_FM_GET_DET_CH_TH_CMD, radio->fm_hdev);
- if (retval < 0) {
- FMDERR("Get SINR threshold failed %x", retval);
- return retval;
- }
- ctrl->value = radio->ch_det_threshold.sinr;
+ if (retval == 0)
+ ctrl->value = radio->ch_det_threshold.sinr;
break;
case V4L2_CID_PRIVATE_SINR_SAMPLES:
retval = hci_cmd(HCI_FM_GET_DET_CH_TH_CMD, radio->fm_hdev);
- if (retval < 0) {
- FMDERR("Get SINR samples failed %x", retval);
- return retval;
- }
-
- ctrl->value = radio->ch_det_threshold.sinr_samples;
+ if (retval == 0)
+ ctrl->value = radio->ch_det_threshold.sinr_samples;
break;
case V4L2_CID_PRIVATE_VALID_CHANNEL:
ctrl->value = radio->is_station_valid;
@@ -2895,13 +3368,11 @@
rd.param = 0;
retval = hci_def_data_read(&rd, radio->fm_hdev);
- if (retval < 0) {
- FMDERR("Get AF Jump Threshold failed %x", retval);
- return retval;
+ if (retval == 0) {
+ lsb = radio->default_data.data[AF_RMSSI_TH_LSB_OFFSET];
+ msb = radio->default_data.data[AF_RMSSI_TH_MSB_OFFSET];
+ ctrl->value = ((msb << 8) | lsb);
}
- lsb = radio->default_data.data[AF_RMSSI_TH_LSB_OFFSET];
- msb = radio->default_data.data[AF_RMSSI_TH_MSB_OFFSET];
- ctrl->value = ((msb << 8) | lsb);
break;
case V4L2_CID_PRIVATE_AF_RMSSI_SAMPLES:
rd.mode = FM_RDS_CNFG_MODE;
@@ -2910,11 +3381,9 @@
rd.param = 0;
retval = hci_def_data_read(&rd, radio->fm_hdev);
- if (retval < 0) {
- FMDERR("Get AF jump rmssi samples failed %x", retval);
- return retval;
- }
- ctrl->value = radio->default_data.data[AF_RMSSI_SAMPLES_OFFSET];
+ if (retval == 0)
+ ctrl->value =
+ radio->default_data.data[AF_RMSSI_SAMPLES_OFFSET];
break;
case V4L2_CID_PRIVATE_GOOD_CH_RMSSI_TH:
rd.mode = FM_RX_CONFG_MODE;
@@ -2923,13 +3392,12 @@
rd.param = 0;
retval = hci_def_data_read(&rd, radio->fm_hdev);
- if (retval < 0) {
- FMDERR("get good channel rmssi th failed %x", retval);
- return retval;
+ if (retval == 0) {
+ ctrl->value =
+ radio->default_data.data[GD_CH_RMSSI_TH_OFFSET];
+ if (ctrl->value > MAX_GD_CH_RMSSI_TH)
+ ctrl->value -= 256;
}
- ctrl->value = radio->default_data.data[GD_CH_RMSSI_TH_OFFSET];
- if (ctrl->value > MAX_GD_CH_RMSSI_TH)
- ctrl->value -= 256;
break;
case V4L2_CID_PRIVATE_SRCHALGOTYPE:
rd.mode = FM_RX_CONFG_MODE;
@@ -2938,11 +3406,9 @@
rd.param = 0;
retval = hci_def_data_read(&rd, radio->fm_hdev);
- if (retval < 0) {
- FMDERR("get search algo type failed %x", retval);
- return retval;
- }
- ctrl->value = radio->default_data.data[SRCH_ALGO_TYPE_OFFSET];
+ if (retval == 0)
+ ctrl->value =
+ radio->default_data.data[SRCH_ALGO_TYPE_OFFSET];
break;
case V4L2_CID_PRIVATE_SINRFIRSTSTAGE:
rd.mode = FM_RX_CONFG_MODE;
@@ -2951,13 +3417,12 @@
rd.param = 0;
retval = hci_def_data_read(&rd, radio->fm_hdev);
- if (retval < 0) {
- FMDERR("default data read failed %x", retval);
- return retval;
+ if (retval == 0) {
+ ctrl->value =
+ radio->default_data.data[SINRFIRSTSTAGE_OFFSET];
+ if (ctrl->value > MAX_SINR_FIRSTSTAGE)
+ ctrl->value -= 256;
}
- ctrl->value = radio->default_data.data[SINRFIRSTSTAGE_OFFSET];
- if (ctrl->value > MAX_SINR_FIRSTSTAGE)
- ctrl->value -= 256;
break;
case V4L2_CID_PRIVATE_RMSSIFIRSTSTAGE:
rd.mode = FM_RX_CONFG_MODE;
@@ -2966,13 +3431,12 @@
rd.param = 0;
retval = hci_def_data_read(&rd, radio->fm_hdev);
- if (retval < 0) {
- FMDERR("default data read failed %x", retval);
- return retval;
+ if (retval == 0) {
+ ctrl->value =
+ radio->default_data.data[RMSSIFIRSTSTAGE_OFFSET];
+ if (ctrl->value > MAX_RMSSI_FIRSTSTAGE)
+ ctrl->value -= 256;
}
- ctrl->value = radio->default_data.data[RMSSIFIRSTSTAGE_OFFSET];
- if (ctrl->value > MAX_RMSSI_FIRSTSTAGE)
- ctrl->value -= 256;
break;
case V4L2_CID_PRIVATE_CF0TH12:
rd.mode = FM_RX_CONFG_MODE;
@@ -2981,26 +3445,31 @@
rd.param = 0;
retval = hci_def_data_read(&rd, radio->fm_hdev);
- if (retval < 0) {
- FMDERR("default data read failed %x", retval);
- return retval;
+ if (retval == 0) {
+ ctrl->value =
+ radio->default_data.data[CF0TH12_BYTE1_OFFSET];
+ cf0 = radio->default_data.data[CF0TH12_BYTE2_OFFSET];
+ ctrl->value |= (cf0 << 8);
+ cf0 = radio->default_data.data[CF0TH12_BYTE3_OFFSET];
+ ctrl->value |= (cf0 << 16);
+ cf0 = radio->default_data.data[CF0TH12_BYTE4_OFFSET];
+ if (cf0 > 127)
+ cf0 -= 256;
+ ctrl->value |= (cf0 << 24);
}
- ctrl->value = radio->default_data.data[CF0TH12_BYTE1_OFFSET];
- cf0 = radio->default_data.data[CF0TH12_BYTE2_OFFSET];
- ctrl->value |= (cf0 << 8);
- cf0 = radio->default_data.data[CF0TH12_BYTE3_OFFSET];
- ctrl->value |= (cf0 << 16);
- cf0 = radio->default_data.data[CF0TH12_BYTE4_OFFSET];
- if (cf0 > 127)
- cf0 -= 256;
- ctrl->value |= (cf0 << 24);
break;
default:
retval = -EINVAL;
+ break;
}
+
+END:
+ if (retval > 0)
+ retval = -EINVAL;
if (retval < 0)
FMDERR("get control failed with %d, id: %d\n",
retval, ctrl->id);
+
return retval;
}
@@ -3012,19 +3481,38 @@
struct iris_device *radio = video_get_drvdata(video_devdata(file));
struct hci_fm_def_data_rd_req default_data_rd;
+ if (unlikely(radio == NULL)) {
+ FMDERR(":radio is null");
+ retval = -EINVAL;
+ goto END;
+ }
+
+ if (unlikely((ctrl == NULL)) || unlikely((ctrl->count == 0))
+ || unlikely((ctrl->controls == NULL))) {
+ FMDERR("%s, invalid v4l2 ctrl\n", __func__);
+ retval = -EINVAL;
+ goto END;
+ }
switch ((ctrl->controls[0]).id) {
case V4L2_CID_PRIVATE_IRIS_READ_DEFAULT:
data = (ctrl->controls[0]).string;
memset(&default_data_rd, 0, sizeof(default_data_rd));
if (copy_from_user(&default_data_rd.mode, data,
- sizeof(default_data_rd)))
- return -EFAULT;
+ sizeof(default_data_rd))) {
+ retval = -EFAULT;
+ goto END;
+ }
retval = hci_def_data_read(&default_data_rd, radio->fm_hdev);
break;
default:
retval = -EINVAL;
+ break;
}
+END:
+ if (retval > 0)
+ retval = -EINVAL;
+
return retval;
}
@@ -3032,7 +3520,7 @@
struct v4l2_ext_controls *ctrl)
{
int retval = 0;
- int bytes_to_copy;
+ size_t bytes_to_copy;
struct hci_fm_tx_ps tx_ps;
struct hci_fm_tx_rt tx_rt;
struct hci_fm_def_data_wr_req default_data;
@@ -3041,46 +3529,72 @@
struct iris_device *radio = video_get_drvdata(video_devdata(file));
char *data = NULL;
+ if (unlikely(radio == NULL)) {
+ FMDERR(":radio is null");
+ retval = -EINVAL;
+ goto END;
+ }
+
+ if (unlikely((ctrl == NULL)) || unlikely((ctrl->count == 0))
+ || unlikely((ctrl->controls == NULL))) {
+ FMDERR("%s, invalid v4l2 ctrl\n", __func__);
+ retval = -EINVAL;
+ goto END;
+ }
+
switch ((ctrl->controls[0]).id) {
case V4L2_CID_RDS_TX_PS_NAME:
FMDBG("In V4L2_CID_RDS_TX_PS_NAME\n");
/*Pass a sample PS string */
memset(tx_ps.ps_data, 0, MAX_PS_LENGTH);
- bytes_to_copy = min((int)(ctrl->controls[0]).size,
- MAX_PS_LENGTH);
+ bytes_to_copy = min(ctrl->controls[0].size,
+ (size_t)MAX_PS_LENGTH);
data = (ctrl->controls[0]).string;
if (copy_from_user(tx_ps.ps_data,
- data, bytes_to_copy))
- return -EFAULT;
- tx_ps.ps_control = 0x01;
- tx_ps.pi = radio->pi;
- tx_ps.pty = radio->pty;
- tx_ps.ps_repeatcount = radio->ps_repeatcount;
- tx_ps.ps_num = (bytes_to_copy / PS_STRING_LEN);
+ data, bytes_to_copy)) {
+ FMDERR("%s: copy from user for tx ps name failed\n",
+ __func__);
+ retval = -EFAULT;
+ goto END;
+ } else {
+ tx_ps.ps_control = 0x01;
+ tx_ps.pi = radio->pi;
+ tx_ps.pty = radio->pty;
+ tx_ps.ps_repeatcount = radio->ps_repeatcount;
+ tx_ps.ps_num = (bytes_to_copy / PS_STRING_LEN);
- retval = radio_hci_request(radio->fm_hdev, hci_trans_ps_req,
- (unsigned long)&tx_ps, RADIO_HCI_TIMEOUT);
+ retval = radio_hci_request(radio->fm_hdev,
+ hci_trans_ps_req,
+ (unsigned long)&tx_ps,
+ RADIO_HCI_TIMEOUT);
+ }
break;
case V4L2_CID_RDS_TX_RADIO_TEXT:
bytes_to_copy =
- min((int)(ctrl->controls[0]).size, MAX_RT_LENGTH);
+ min((ctrl->controls[0]).size, (size_t)MAX_RT_LENGTH);
data = (ctrl->controls[0]).string;
memset(tx_rt.rt_data, 0, MAX_RT_LENGTH);
if (copy_from_user(tx_rt.rt_data,
- data, bytes_to_copy))
- return -EFAULT;
+ data, bytes_to_copy)) {
+ FMDERR("%s: copy from user for tx rt failed\n",
+ __func__);
+ retval = -EFAULT;
+ goto END;
+ } else {
+ tx_rt.rt_control = 0x01;
+ tx_rt.pi = radio->pi;
+ tx_rt.pty = radio->pty;
+ tx_rt.rt_len = bytes_to_copy;
- tx_rt.rt_control = 0x01;
- tx_rt.pi = radio->pi;
- tx_rt.pty = radio->pty;
- tx_rt.rt_len = bytes_to_copy;
-
- retval = radio_hci_request(radio->fm_hdev, hci_trans_rt_req,
- (unsigned long)&tx_rt, RADIO_HCI_TIMEOUT);
+ retval = radio_hci_request(radio->fm_hdev,
+ hci_trans_rt_req,
+ (unsigned long)&tx_rt,
+ RADIO_HCI_TIMEOUT);
+ }
break;
case V4L2_CID_PRIVATE_IRIS_WRITE_DEFAULT:
data = (ctrl->controls[0]).string;
@@ -3095,7 +3609,8 @@
*/
if (ctrl->controls[0].size > (DEFAULT_DATA_SIZE + 2)) {
pr_err("%s: Default data buffer overflow!\n", __func__);
- return -EINVAL;
+ retval = -EINVAL;
+ goto END;
}
/* copy only 'size' bytes of data as requested by user */
@@ -3104,7 +3619,8 @@
if (retval > 0) {
pr_err("%s: Failed to copy %d bytes of default data"
" passed by user\n", __func__, retval);
- return -EFAULT;
+ retval = -EFAULT;
+ goto END;
}
FMDBG("%s: XFR Mode\t: 0x%x\n", __func__, default_data.mode);
FMDBG("%s: XFR Data Length\t: %d\n", __func__,
@@ -3119,7 +3635,8 @@
if (default_data.length != (ctrl->controls[0].size - 2)) {
pr_err("%s: Invalid 'length' parameter passed for "
"actual xfr data\n", __func__);
- return -EINVAL;
+ retval = -EINVAL;
+ goto END;
}
retval = hci_def_data_write(&default_data, radio->fm_hdev);
break;
@@ -3128,24 +3645,32 @@
bytes_to_copy = (ctrl->controls[0]).size;
if (bytes_to_copy < PROCS_CALIB_SIZE) {
FMDERR("data is less than required size");
- return -EFAULT;
+ retval = -EFAULT;
+ goto END;
}
memset(proc_cal_req.data, 0, PROCS_CALIB_SIZE);
proc_cal_req.mode = PROCS_CALIB_MODE;
if (copy_from_user(&proc_cal_req.data[0],
- data, sizeof(proc_cal_req.data)))
- return -EFAULT;
+ data, sizeof(proc_cal_req.data))) {
+ retval = -EFAULT;
+ goto END;
+ }
retval = radio_hci_request(radio->fm_hdev,
hci_fm_set_cal_req_proc,
(unsigned long)&proc_cal_req,
RADIO_HCI_TIMEOUT);
- if (retval < 0)
- FMDERR("Set Process calibration failed %d", retval);
break;
default:
FMDBG("Shouldn't reach here\n");
retval = -1;
+ goto END;
+ break;
}
+
+END:
+ if (retval > 0)
+ retval = -EINVAL;
+
return retval;
}
@@ -3156,6 +3681,7 @@
int retval = 0;
unsigned int rds_grps_proc = 0;
__u8 temp_val = 0;
+ int saved_val;
unsigned long arg = 0;
struct hci_fm_tx_ps tx_ps = {0};
struct hci_fm_tx_rt tx_rt = {0};
@@ -3164,32 +3690,71 @@
char sinr_th, sinr;
__u8 intf_det_low_th, intf_det_high_th, intf_det_out;
+ if (unlikely(radio == NULL)) {
+ FMDERR(":radio is null");
+ retval = -EINVAL;
+ goto END;
+ }
+
+ if (unlikely(ctrl == NULL)) {
+ FMDERR("%s, v4l2 ctrl is null\n", __func__);
+ retval = -EINVAL;
+ goto END;
+ }
switch (ctrl->id) {
case V4L2_CID_PRIVATE_IRIS_TX_TONE:
+ if (!is_valid_tone(ctrl->value)) {
+ retval = -EINVAL;
+ FMDERR("%s: tone value is not valid\n", __func__);
+ goto END;
+ }
+ saved_val = radio->tone_freq;
radio->tone_freq = ctrl->value;
retval = radio_hci_request(radio->fm_hdev,
hci_fm_tone_generator, arg,
msecs_to_jiffies(RADIO_HCI_TIMEOUT));
- if (retval < 0)
+ if (retval < 0) {
FMDERR("Error while setting the tone %d", retval);
+ radio->tone_freq = saved_val;
+ }
break;
case V4L2_CID_AUDIO_VOLUME:
break;
case V4L2_CID_AUDIO_MUTE:
+ if (!is_valid_hard_mute(ctrl->value)) {
+ retval = -EINVAL;
+ FMDERR("%s: hard mute value is not valid\n", __func__);
+ goto END;
+ }
+ saved_val = radio->mute_mode.hard_mute;
radio->mute_mode.hard_mute = ctrl->value;
radio->mute_mode.soft_mute = IOC_SFT_MUTE;
retval = hci_set_fm_mute_mode(
&radio->mute_mode,
radio->fm_hdev);
- if (retval < 0)
+ if (retval < 0) {
FMDERR("Error while set FM hard mute"" %d\n",
- retval);
+ retval);
+ radio->mute_mode.hard_mute = saved_val;
+ }
break;
case V4L2_CID_PRIVATE_IRIS_SRCHMODE:
- radio->g_search_mode = ctrl->value;
+ if (is_valid_srch_mode(ctrl->value)) {
+ radio->g_search_mode = ctrl->value;
+ } else {
+ FMDERR("%s: srch mode is not valid\n", __func__);
+ retval = -EINVAL;
+ goto END;
+ }
break;
case V4L2_CID_PRIVATE_IRIS_SCANDWELL:
- radio->g_scan_time = ctrl->value;
+ if (is_valid_scan_dwell_prd(ctrl->value)) {
+ radio->g_scan_time = ctrl->value;
+ } else {
+ FMDERR("%s: scandwell period is not valid\n", __func__);
+ retval = -EINVAL;
+ goto END;
+ }
break;
case V4L2_CID_PRIVATE_IRIS_SRCHON:
iris_search(radio, ctrl->value, SRCH_DIR_UP);
@@ -3197,8 +3762,12 @@
case V4L2_CID_PRIVATE_IRIS_STATE:
switch (ctrl->value) {
case FM_RECV:
- if (is_enable_rx_possible(radio) != 0)
- return -EINVAL;
+ if (is_enable_rx_possible(radio) != 0) {
+ FMDERR("%s: fm is not in proper state\n",
+ __func__);
+ retval = -EINVAL;
+ goto END;
+ }
radio->mode = FM_RECV_TURNING_ON;
retval = hci_cmd(HCI_FM_ENABLE_RECV_CMD,
radio->fm_hdev);
@@ -3206,14 +3775,16 @@
FMDERR("Error while enabling RECV FM"
" %d\n", retval);
radio->mode = FM_OFF;
- return retval;
+ goto END;
} else {
initialise_recv(radio);
}
break;
case FM_TRANS:
- if (is_enable_tx_possible(radio) != 0)
- return -EINVAL;
+ if (is_enable_tx_possible(radio) != 0) {
+ retval = -EINVAL;
+ goto END;
+ }
radio->mode = FM_TRANS_TURNING_ON;
retval = hci_cmd(HCI_FM_ENABLE_TRANS_CMD,
radio->fm_hdev);
@@ -3221,7 +3792,7 @@
FMDERR("Error while enabling TRANS FM"
" %d\n", retval);
radio->mode = FM_OFF;
- return retval;
+ goto END;
} else {
initialise_trans(radio);
}
@@ -3237,7 +3808,7 @@
FMDERR("Err on disable recv FM"
" %d\n", retval);
radio->mode = FM_RECV;
- return retval;
+ goto END;
}
break;
case FM_TRANS:
@@ -3249,7 +3820,7 @@
FMDERR("Err disabling trans FM"
" %d\n", retval);
radio->mode = FM_TRANS;
- return retval;
+ goto END;
}
break;
default:
@@ -3264,136 +3835,236 @@
if (radio->mode == FM_RECV) {
retval = iris_recv_set_region(radio, ctrl->value);
} else {
- if (radio->mode == FM_TRANS)
+ if (radio->mode == FM_TRANS) {
retval = iris_trans_set_region(radio,
ctrl->value);
- else
+ } else {
+ FMDERR("%s: fm is not in proper state\n",
+ __func__);
retval = -EINVAL;
+ goto END;
+ }
}
break;
case V4L2_CID_PRIVATE_IRIS_SIGNAL_TH:
+ if (!is_valid_sig_th(ctrl->value)) {
+ retval = -EINVAL;
+ FMDERR("%s: sig threshold is not valid\n", __func__);
+ goto END;
+ }
temp_val = ctrl->value;
retval = hci_fm_set_signal_threshold(
&temp_val,
radio->fm_hdev);
if (retval < 0) {
FMDERR("Error while setting signal threshold\n");
- break;
+ goto END;
}
break;
case V4L2_CID_PRIVATE_IRIS_SRCH_PTY:
- radio->srch_rds.srch_pty = ctrl->value;
- radio->srch_st_list.srch_pty = ctrl->value;
+ if (is_valid_pty(ctrl->value)) {
+ radio->srch_rds.srch_pty = ctrl->value;
+ radio->srch_st_list.srch_pty = ctrl->value;
+ } else {
+ FMDERR("%s: pty is not valid\n", __func__);
+ retval = -EINVAL;
+ goto END;
+ }
break;
case V4L2_CID_PRIVATE_IRIS_SRCH_PI:
- radio->srch_rds.srch_pi = ctrl->value;
+ if (is_valid_pi(ctrl->value)) {
+ radio->srch_rds.srch_pi = ctrl->value;
+ } else {
+ retval = -EINVAL;
+ FMDERR("%s: Pi is not valid\n", __func__);
+ goto END;
+ }
break;
case V4L2_CID_PRIVATE_IRIS_SRCH_CNT:
- radio->srch_st_list.srch_list_max = ctrl->value;
+ if (is_valid_srch_station_cnt(ctrl->value)) {
+ radio->srch_st_list.srch_list_max = ctrl->value;
+ } else {
+ retval = -EINVAL;
+ FMDERR("%s: srch station count is not valid\n",
+ __func__);
+ goto END;
+ }
break;
case V4L2_CID_PRIVATE_IRIS_SPACING:
+ if (!is_valid_chan_spacing(ctrl->value)) {
+ retval = -EINVAL;
+ FMDERR("%s: channel spacing is not valid\n", __func__);
+ goto END;
+ }
if (radio->mode == FM_RECV) {
+ saved_val = radio->recv_conf.ch_spacing;
radio->recv_conf.ch_spacing = ctrl->value;
retval = hci_set_fm_recv_conf(
&radio->recv_conf,
radio->fm_hdev);
- if (retval < 0)
+ if (retval < 0) {
FMDERR("Error in setting channel spacing");
+ radio->recv_conf.ch_spacing = saved_val;
+ goto END;
+ }
}
break;
case V4L2_CID_PRIVATE_IRIS_EMPHASIS:
+ if (!is_valid_emphasis(ctrl->value)) {
+ retval = -EINVAL;
+ FMDERR("%s, emphasis is not valid\n", __func__);
+ goto END;
+ }
switch (radio->mode) {
case FM_RECV:
+ saved_val = radio->recv_conf.emphasis;
radio->recv_conf.emphasis = ctrl->value;
retval = hci_set_fm_recv_conf(
&radio->recv_conf,
radio->fm_hdev);
- if (retval < 0)
+ if (retval < 0) {
FMDERR("Error in setting emphasis");
+ radio->recv_conf.emphasis = saved_val;
+ goto END;
+ }
break;
case FM_TRANS:
+ saved_val = radio->trans_conf.emphasis;
radio->trans_conf.emphasis = ctrl->value;
retval = hci_set_fm_trans_conf(
&radio->trans_conf,
radio->fm_hdev);
- if (retval < 0)
+ if (retval < 0) {
FMDERR("Error in setting emphasis");
+ radio->trans_conf.emphasis = saved_val;
+ goto END;
+ }
break;
default:
retval = -EINVAL;
+ FMDERR("%s, FM is not in proper state\n", __func__);
+ goto END;
+ break;
}
break;
case V4L2_CID_PRIVATE_IRIS_RDS_STD:
+ if (!is_valid_rds_std(ctrl->value)) {
+ retval = -EINVAL;
+ FMDERR("%s: rds std is not valid\n", __func__);
+ goto END;
+ }
switch (radio->mode) {
case FM_RECV:
+ saved_val = radio->recv_conf.rds_std;
radio->recv_conf.rds_std = ctrl->value;
retval = hci_set_fm_recv_conf(
&radio->recv_conf,
radio->fm_hdev);
- if (retval < 0)
+ if (retval < 0) {
FMDERR("Error in rds_std");
+ radio->recv_conf.rds_std = saved_val;
+ goto END;
+ }
break;
case FM_TRANS:
+ saved_val = radio->trans_conf.rds_std;
radio->trans_conf.rds_std = ctrl->value;
retval = hci_set_fm_trans_conf(
&radio->trans_conf,
radio->fm_hdev);
- if (retval < 0)
+ if (retval < 0) {
FMDERR("Error in rds_Std");
+ radio->trans_conf.rds_std = saved_val;
+ goto END;
+ }
break;
default:
retval = -EINVAL;
+ FMDERR("%s: fm is not in proper state\n", __func__);
+ goto END;
+ break;
}
break;
case V4L2_CID_PRIVATE_IRIS_RDSON:
+ if (!is_valid_rds_std(ctrl->value)) {
+ retval = -EINVAL;
+ FMDERR("%s: rds std is not valid\n", __func__);
+ goto END;
+ }
switch (radio->mode) {
case FM_RECV:
+ saved_val = radio->recv_conf.rds_std;
radio->recv_conf.rds_std = ctrl->value;
retval = hci_set_fm_recv_conf(
&radio->recv_conf,
radio->fm_hdev);
- if (retval < 0)
+ if (retval < 0) {
FMDERR("Error in rds_std");
+ radio->recv_conf.rds_std = saved_val;
+ goto END;
+ }
break;
case FM_TRANS:
+ saved_val = radio->trans_conf.rds_std;
radio->trans_conf.rds_std = ctrl->value;
retval = hci_set_fm_trans_conf(
&radio->trans_conf,
radio->fm_hdev);
- if (retval < 0)
+ if (retval < 0) {
FMDERR("Error in rds_Std");
+ radio->trans_conf.rds_std = saved_val;
+ goto END;
+ }
break;
default:
retval = -EINVAL;
+ FMDERR("%s: fm is not in proper state\n", __func__);
+ goto END;
+ break;
}
break;
case V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK:
+ saved_val = radio->rds_grp.rds_grp_enable_mask;
grp_mask = (grp_mask | oda_agt | ctrl->value);
radio->rds_grp.rds_grp_enable_mask = grp_mask;
radio->rds_grp.rds_buf_size = 1;
radio->rds_grp.en_rds_change_filter = 0;
retval = hci_fm_rds_grp(&radio->rds_grp, radio->fm_hdev);
- if (retval < 0)
+ if (retval < 0) {
FMDERR("error in setting group mask\n");
+ radio->rds_grp.rds_grp_enable_mask = saved_val;
+ goto END;
+ }
break;
case V4L2_CID_PRIVATE_IRIS_RDSGROUP_PROC:
+ saved_val = radio->g_rds_grp_proc_ps;
rds_grps_proc = radio->g_rds_grp_proc_ps | ctrl->value;
radio->g_rds_grp_proc_ps = (rds_grps_proc >> RDS_CONFIG_OFFSET);
retval = hci_fm_rds_grps_process(
&radio->g_rds_grp_proc_ps,
radio->fm_hdev);
+ if (retval < 0) {
+ radio->g_rds_grp_proc_ps = saved_val;
+ goto END;
+ }
break;
case V4L2_CID_PRIVATE_IRIS_RDSD_BUF:
radio->rds_grp.rds_buf_size = ctrl->value;
break;
case V4L2_CID_PRIVATE_IRIS_PSALL:
+ saved_val = radio->g_rds_grp_proc_ps;
rds_grps_proc = (ctrl->value << RDS_CONFIG_OFFSET);
radio->g_rds_grp_proc_ps |= rds_grps_proc;
retval = hci_fm_rds_grps_process(
&radio->g_rds_grp_proc_ps,
radio->fm_hdev);
+ if (retval < 0) {
+ radio->g_rds_grp_proc_ps = saved_val;
+ goto END;
+ }
break;
case V4L2_CID_PRIVATE_IRIS_AF_JUMP:
+ saved_val = radio->g_rds_grp_proc_ps;
/*Clear the current AF jump settings*/
radio->g_rds_grp_proc_ps &= ~(1 << RDS_AF_JUMP_OFFSET);
radio->af_jump_bit = ctrl->value;
@@ -3403,24 +4074,45 @@
retval = hci_fm_rds_grps_process(
&radio->g_rds_grp_proc_ps,
radio->fm_hdev);
+ if (retval < 0) {
+ radio->g_rds_grp_proc_ps = saved_val;
+ goto END;
+ }
break;
case V4L2_CID_PRIVATE_IRIS_LP_MODE:
set_low_power_mode(radio, ctrl->value);
break;
case V4L2_CID_PRIVATE_IRIS_ANTENNA:
+ if (!is_valid_antenna(ctrl->value)) {
+ retval = -EINVAL;
+ FMDERR("%s: antenna type is not valid\n", __func__);
+ goto END;
+ }
temp_val = ctrl->value;
retval = hci_fm_set_antenna(&temp_val, radio->fm_hdev);
if (retval < 0) {
FMDERR("Set Antenna failed retval = %x", retval);
- return retval;
+ goto END;
}
radio->g_antenna = ctrl->value;
break;
case V4L2_CID_RDS_TX_PTY:
- radio->pty = ctrl->value;
+ if (is_valid_pty(ctrl->value)) {
+ radio->pty = ctrl->value;
+ } else {
+ retval = -EINVAL;
+ FMDERR("%s: pty is not valid\n", __func__);
+ goto END;
+ }
break;
case V4L2_CID_RDS_TX_PI:
- radio->pi = ctrl->value;
+ if (is_valid_pi(ctrl->value)) {
+ radio->pi = ctrl->value;
+ } else {
+ retval = -EINVAL;
+ FMDERR("%s: pi is not valid\n", __func__);
+ goto END;
+ }
break;
case V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_PS_NAME:
tx_ps.ps_control = 0x00;
@@ -3433,7 +4125,13 @@
(unsigned long)&tx_rt, RADIO_HCI_TIMEOUT);
break;
case V4L2_CID_PRIVATE_IRIS_TX_SETPSREPEATCOUNT:
- radio->ps_repeatcount = ctrl->value;
+ if (is_valid_ps_repeat_cnt(ctrl->value)) {
+ radio->ps_repeatcount = ctrl->value;
+ } else {
+ retval = -EINVAL;
+ FMDERR("%s: ps repeat count is not valid\n", __func__);
+ goto END;
+ }
break;
case V4L2_CID_TUNE_POWER_LEVEL:
if (ctrl->value > FM_TX_PWR_LVL_MAX)
@@ -3448,8 +4146,8 @@
retval = hci_def_data_read(&rd, radio->fm_hdev);
if (retval < 0) {
FMDERR("Default data read failed for PHY_CFG %d\n",
- retval);
- break;
+ retval);
+ goto END;
}
memset(&wrd, 0, sizeof(wrd));
wrd.mode = FM_TX_PHY_CFG_MODE;
@@ -3461,40 +4159,58 @@
retval = hci_def_data_write(&wrd, radio->fm_hdev);
if (retval < 0)
FMDERR("Default write failed for PHY_TXGAIN %d\n",
- retval);
+ retval);
break;
case V4L2_CID_PRIVATE_IRIS_SOFT_MUTE:
+ if (!is_valid_soft_mute(ctrl->value)) {
+ retval = -EINVAL;
+ FMDERR("%s: soft mute is not valid\n", __func__);
+ goto END;
+ }
+ saved_val = radio->mute_mode.soft_mute;
radio->mute_mode.soft_mute = ctrl->value;
retval = hci_set_fm_mute_mode(
&radio->mute_mode,
radio->fm_hdev);
- if (retval < 0)
+ if (retval < 0) {
FMDERR("Error while setting FM soft mute"" %d\n",
- retval);
+ retval);
+ radio->mute_mode.soft_mute = saved_val;
+ goto END;
+ }
break;
case V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_ADDR:
radio->riva_data_req.cmd_params.start_addr = ctrl->value;
break;
case V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_LEN:
- if ((ctrl->value > 0) &&
- (ctrl->value <= MAX_RIVA_PEEK_RSP_SIZE)) {
+ if (is_valid_peek_len(ctrl->value)) {
radio->riva_data_req.cmd_params.length = ctrl->value;
} else {
- FMDERR("Length %d is more than the buffer size %d\n",
- ctrl->value, MAX_RIVA_PEEK_RSP_SIZE);
retval = -EINVAL;
+ FMDERR("%s: riva access len is not valid\n", __func__);
+ goto END;
}
break;
case V4L2_CID_PRIVATE_IRIS_RIVA_POKE:
- if (radio->riva_data_req.cmd_params.length <= MAX_RIVA_PEEK_RSP_SIZE) {
- memcpy(radio->riva_data_req.data, (void *)ctrl->value,
- radio->riva_data_req.cmd_params.length);
- radio->riva_data_req.cmd_params.subopcode = RIVA_POKE_OPCODE;
- retval = hci_poke_data(&radio->riva_data_req , radio->fm_hdev);
+ if (radio->riva_data_req.cmd_params.length <=
+ MAX_RIVA_PEEK_RSP_SIZE) {
+ retval = copy_from_user(
+ radio->riva_data_req.data,
+ (void *)ctrl->value,
+ radio->riva_data_req.cmd_params.length);
+ if (retval != 0) {
+ retval = -retval;
+ goto END;
+ }
+ radio->riva_data_req.cmd_params.subopcode =
+ RIVA_POKE_OPCODE;
+ retval = hci_poke_data(
+ &radio->riva_data_req,
+ radio->fm_hdev);
} else {
- FMDERR("Can not copy into driver's buffer. Length %d is more than"
- "the buffer size %d\n", ctrl->value, MAX_RIVA_PEEK_RSP_SIZE);
+ FMDERR("Can not copy into driver's buffer.\n");
retval = -EINVAL;
+ goto END;
}
break;
case V4L2_CID_PRIVATE_IRIS_SSBI_ACCS_ADDR:
@@ -3515,80 +4231,133 @@
hci_ssbi_peek_reg(&radio->ssbi_peek_reg, radio->fm_hdev);
break;
case V4L2_CID_PRIVATE_IRIS_RDS_GRP_COUNTERS:
- temp_val = ctrl->value;
- hci_read_grp_counters(&temp_val, radio->fm_hdev);
+ if (is_valid_reset_cntr(ctrl->value)) {
+ temp_val = ctrl->value;
+ hci_read_grp_counters(&temp_val, radio->fm_hdev);
+ } else {
+ FMDERR("%s: reset counter value is not valid\n",
+ __func__);
+ retval = -EINVAL;
+ goto END;
+ }
break;
case V4L2_CID_PRIVATE_IRIS_HLSI:
+ if (!is_valid_hlsi(ctrl->value)) {
+ FMDERR("%s: hlsi value is not valid\n", __func__);
+ retval = -EINVAL;
+ goto END;
+ }
retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
radio->fm_hdev);
if (retval)
- break;
+ goto END;
+ saved_val = radio->recv_conf.hlsi;
radio->recv_conf.hlsi = ctrl->value;
retval = hci_set_fm_recv_conf(
&radio->recv_conf,
radio->fm_hdev);
+ if (retval < 0)
+ radio->recv_conf.hlsi = saved_val;
break;
case V4L2_CID_PRIVATE_IRIS_SET_NOTCH_FILTER:
- temp_val = ctrl->value;
- retval = hci_set_notch_filter(&temp_val, radio->fm_hdev);
+ if (is_valid_notch_filter(ctrl->value)) {
+ temp_val = ctrl->value;
+ retval = hci_set_notch_filter(&temp_val,
+ radio->fm_hdev);
+ } else {
+ FMDERR("%s: notch filter is not valid\n", __func__);
+ retval = -EINVAL;
+ goto END;
+ }
break;
case V4L2_CID_PRIVATE_INTF_HIGH_THRESHOLD:
+ if (!is_valid_intf_det_hgh_th(ctrl->value)) {
+ FMDERR("%s: intf high threshold is not valid\n",
+ __func__);
+ retval = -EINVAL;
+ goto END;
+ }
retval = hci_cmd(HCI_FM_GET_DET_CH_TH_CMD, radio->fm_hdev);
if (retval < 0) {
FMDERR("Failed to get chnl det thresholds %d", retval);
- return retval;
+ goto END;
}
+ saved_val = radio->ch_det_threshold.high_th;
radio->ch_det_threshold.high_th = ctrl->value;
retval = hci_set_ch_det_thresholds_req(&radio->ch_det_threshold,
radio->fm_hdev);
if (retval < 0) {
FMDERR("Failed to set High det threshold %d ", retval);
- return retval;
+ radio->ch_det_threshold.high_th = saved_val;
+ goto END;
}
break;
case V4L2_CID_PRIVATE_INTF_LOW_THRESHOLD:
+ if (!is_valid_intf_det_low_th(ctrl->value)) {
+ FMDERR("%s: intf det low threshold is not valid\n",
+ __func__);
+ retval = -EINVAL;
+ goto END;
+ }
retval = hci_cmd(HCI_FM_GET_DET_CH_TH_CMD, radio->fm_hdev);
if (retval < 0) {
FMDERR("Failed to get chnl det thresholds %d", retval);
- return retval;
+ goto END;
}
+ saved_val = radio->ch_det_threshold.low_th;
radio->ch_det_threshold.low_th = ctrl->value;
retval = hci_set_ch_det_thresholds_req(&radio->ch_det_threshold,
radio->fm_hdev);
if (retval < 0) {
FMDERR("Failed to Set Low det threshold %d", retval);
- return retval;
+ radio->ch_det_threshold.low_th = saved_val;
+ goto END;
}
break;
case V4L2_CID_PRIVATE_SINR_THRESHOLD:
+ if (!is_valid_sinr_th(ctrl->value)) {
+ FMDERR("%s: sinr threshold is not valid\n", __func__);
+ retval = -EINVAL;
+ goto END;
+ }
retval = hci_cmd(HCI_FM_GET_DET_CH_TH_CMD, radio->fm_hdev);
if (retval < 0) {
FMDERR("Failed to get chnl det thresholds %d", retval);
- return retval;
+ goto END;
}
+ saved_val = radio->ch_det_threshold.sinr;
radio->ch_det_threshold.sinr = ctrl->value;
retval = hci_set_ch_det_thresholds_req(&radio->ch_det_threshold,
radio->fm_hdev);
if (retval < 0) {
FMDERR("Failed to set SINR threshold %d", retval);
- return retval;
+ radio->ch_det_threshold.sinr = saved_val;
+ goto END;
}
break;
case V4L2_CID_PRIVATE_SINR_SAMPLES:
+ if (!is_valid_sinr_samples(ctrl->value)) {
+ FMDERR("%s: sinr samples count is not valid\n",
+ __func__);
+ retval = -EINVAL;
+ goto END;
+ }
retval = hci_cmd(HCI_FM_GET_DET_CH_TH_CMD, radio->fm_hdev);
if (retval < 0) {
FMDERR("Failed to get chnl det thresholds %d", retval);
- return retval;
+ goto END;
}
+ saved_val = radio->ch_det_threshold.sinr_samples;
radio->ch_det_threshold.sinr_samples = ctrl->value;
retval = hci_set_ch_det_thresholds_req(&radio->ch_det_threshold,
radio->fm_hdev);
if (retval < 0) {
FMDERR("Failed to set SINR samples %d", retval);
- return retval;
+ radio->ch_det_threshold.sinr_samples = saved_val;
+ goto END;
}
break;
@@ -3635,18 +4404,23 @@
if (retval < 0) {
FMDERR("%s: Failed to determine channel's validity\n",
__func__);
- return retval;
+ goto END;
} else {
sinr_th = radio->ch_det_threshold.sinr;
intf_det_low_th = radio->ch_det_threshold.low_th;
intf_det_high_th = radio->ch_det_threshold.high_th;
}
-
+ if (!is_valid_sinr_th(sinr_th) ||
+ !is_valid_intf_det_low_th(intf_det_low_th) ||
+ !is_valid_intf_det_hgh_th(intf_det_high_th)) {
+ retval = -EINVAL;
+ goto END;
+ }
retval = hci_cmd(HCI_FM_GET_STATION_PARAM_CMD, radio->fm_hdev);
if (retval < 0) {
FMDERR("%s: Failed to determine channel's validity\n",
__func__);
- return retval;
+ goto END;
} else
sinr = radio->fm_st_rsp.station_rsp.sinr;
@@ -3654,7 +4428,7 @@
if (retval < 0) {
FMDERR("%s: Failed to determine channel's validity\n",
__func__);
- return retval;
+ goto END;
} else
intf_det_out = radio->st_dbg_param.in_det_out;
@@ -3673,7 +4447,7 @@
retval = hci_def_data_read(&rd, radio->fm_hdev);
if (retval < 0) {
FMDERR("default data read failed %x", retval);
- return retval;
+ goto END;
}
wrd.mode = FM_RDS_CNFG_MODE;
wrd.length = FM_RDS_CNFG_LEN;
@@ -3694,7 +4468,7 @@
retval = hci_def_data_read(&rd, radio->fm_hdev);
if (retval < 0) {
FMDERR("default data read failed %x", retval);
- return retval;
+ goto END;
}
wrd.mode = FM_RDS_CNFG_MODE;
wrd.length = FM_RDS_CNFG_LEN;
@@ -3714,7 +4488,7 @@
retval = hci_def_data_read(&rd, radio->fm_hdev);
if (retval < 0) {
FMDERR("default data read failed %x", retval);
- return retval;
+ goto END;
}
wrd.mode = FM_RX_CONFG_MODE;
wrd.length = FM_RX_CNFG_LEN;
@@ -3734,7 +4508,7 @@
retval = hci_def_data_read(&rd, radio->fm_hdev);
if (retval < 0) {
FMDERR("default data read failed %x", retval);
- return retval;
+ goto END;
}
wrd.mode = FM_RX_CONFG_MODE;
wrd.length = FM_RX_CNFG_LEN;
@@ -3754,7 +4528,7 @@
retval = hci_def_data_read(&rd, radio->fm_hdev);
if (retval < 0) {
FMDERR("default data read failed %x", retval);
- return retval;
+ goto END;
}
wrd.mode = FM_RX_CONFG_MODE;
wrd.length = FM_RX_CNFG_LEN;
@@ -3774,7 +4548,7 @@
retval = hci_def_data_read(&rd, radio->fm_hdev);
if (retval < 0) {
FMDERR("default data read failed %x", retval);
- return retval;
+ goto END;
}
wrd.mode = FM_RX_CONFG_MODE;
wrd.length = FM_RX_CNFG_LEN;
@@ -3794,7 +4568,7 @@
retval = hci_def_data_read(&rd, radio->fm_hdev);
if (retval < 0) {
FMDERR("default data read failed %x", retval);
- return retval;
+ goto END;
}
wrd.mode = FM_RX_CONFG_MODE;
wrd.length = FM_RX_CNFG_LEN;
@@ -3817,7 +4591,7 @@
retval = hci_def_data_read(&rd, radio->fm_hdev);
if (retval < 0) {
FMDERR("default data read failed for PS0 %x", retval);
- return retval;
+ goto END;
}
wrd.mode = RDS_PS0_XFR_MODE;
wrd.length = RDS_PS0_LEN;
@@ -3831,7 +4605,13 @@
break;
default:
retval = -EINVAL;
+ break;
}
+
+END:
+ if (retval > 0)
+ retval = -EINVAL;
+
return retval;
}
@@ -3846,6 +4626,10 @@
/* Pass the mode of SPUR_CLK */
default_data.mode = CKK_SPUR;
+ if (unlikely(radio == NULL)) {
+ FMDERR(":radio is null");
+ return -EINVAL;
+ }
temp = radio->spur_table_size;
for (cnt = 0; cnt < (temp / 5); cnt++) {
offset = 0;
@@ -3916,6 +4700,14 @@
int retval;
struct iris_device *radio = video_get_drvdata(video_devdata(file));
+ if (unlikely(radio == NULL)) {
+ FMDERR(":radio is null");
+ return -EINVAL;
+ }
+ if (unlikely(tuner == NULL)) {
+ FMDERR("%s, tuner is null\n", __func__);
+ return -EINVAL;
+ }
if (tuner->index > 0) {
FMDERR("Invalid Tuner Index");
return -EINVAL;
@@ -3959,6 +4751,17 @@
{
struct iris_device *radio = video_get_drvdata(video_devdata(file));
int retval = 0;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR(":radio is null");
+ return -EINVAL;
+ }
+
+ if (unlikely(tuner == NULL)) {
+ FMDERR("%s, tuner is null\n", __func__);
+ return -EINVAL;
+ }
+
if (tuner->index > 0)
return -EINVAL;
@@ -4008,8 +4811,18 @@
{
struct iris_device *radio = video_get_drvdata(video_devdata(file));
int retval = -1;
- freq->frequency = freq->frequency / TUNE_PARAM;
+ u32 f;
+ if (unlikely(freq == NULL)) {
+ FMDERR("%s, v4l2 freq is null\n", __func__);
+ return -EINVAL;
+ }
+ f = (freq->frequency / TUNE_PARAM);
+
+ if (unlikely(radio == NULL)) {
+ FMDERR(":radio is null");
+ return -EINVAL;
+ }
if (freq->type != V4L2_TUNER_RADIO)
return -EINVAL;
@@ -4026,7 +4839,7 @@
radio->fm_hdev);
}
- retval = iris_set_freq(radio, freq->frequency);
+ retval = iris_set_freq(radio, f);
if (radio->mode == FM_TRANS
&& radio->trans_conf.rds_std == 2
@@ -4125,6 +4938,11 @@
{
struct iris_device *radio = video_get_drvdata(video_devdata(file));
int dir;
+
+ if (unlikely(seek == NULL)) {
+ FMDERR("%s, v4l2_hw_freq_seek is null\n", __func__);
+ return -EINVAL;
+ }
if (seek->seek_upward)
dir = SRCH_DIR_UP;
else
@@ -4137,10 +4955,23 @@
{
struct iris_device *radio;
radio = video_get_drvdata(video_devdata(file));
+
+ if (unlikely(radio == NULL)) {
+ FMDERR(":radio is null");
+ return -EINVAL;
+ }
+ if (unlikely(capability == NULL)) {
+ FMDERR("%s, capability struct is null\n", __func__);
+ return -EINVAL;
+ }
strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
- capability->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
- radio->g_cap = capability;
+
+ strlcpy(radio->g_cap.driver, DRIVER_NAME, sizeof(radio->g_cap.driver));
+ strlcpy(radio->g_cap.card, DRIVER_CARD, sizeof(radio->g_cap.card));
+
+ radio->g_cap.capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ capability->capabilities = radio->g_cap.capabilities;
return 0;
}
@@ -4148,6 +4979,11 @@
{
int retval;
+ if (unlikely(radio == NULL)) {
+ FMDERR(":radio is null");
+ return -EINVAL;
+ }
+
radio->mute_mode.soft_mute = CTRL_ON;
retval = hci_set_fm_mute_mode(&radio->mute_mode,
radio->fm_hdev);
@@ -4185,7 +5021,14 @@
static int initialise_trans(struct iris_device *radio)
{
- int retval = hci_cmd(HCI_FM_GET_TX_CONFIG, radio->fm_hdev);
+ int retval;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR(":radio is null");
+ return -EINVAL;
+ }
+
+ retval = hci_cmd(HCI_FM_GET_TX_CONFIG, radio->fm_hdev);
if (retval < 0)
FMDERR("get frequency failed %d\n", retval);
@@ -4196,6 +5039,11 @@
{
int retval = 1;
+ if (unlikely(radio == NULL)) {
+ FMDERR(":radio is null");
+ return -EINVAL;
+ }
+
if (radio->mode == FM_OFF || radio->mode == FM_RECV)
retval = 0;
@@ -4294,11 +5142,11 @@
if (kfifo_alloc_rc != 0) {
FMDERR("failed allocating buffers %d\n",
kfifo_alloc_rc);
- for (; i > -1; i--) {
+ for (; i > -1; i--)
kfifo_free(&radio->data_buf[i]);
- kfree(radio);
- return -ENOMEM;
- }
+ video_device_release(radio->videodev);
+ kfree(radio);
+ return -ENOMEM;
}
}
@@ -4326,8 +5174,17 @@
} else {
priv_videodev = kzalloc(sizeof(struct video_device),
GFP_KERNEL);
- memcpy(priv_videodev, radio->videodev,
- sizeof(struct video_device));
+ if (priv_videodev != NULL) {
+ memcpy(priv_videodev, radio->videodev,
+ sizeof(struct video_device));
+ } else {
+ video_unregister_device(radio->videodev);
+ video_device_release(radio->videodev);
+ for (; i > -1; i--)
+ kfifo_free(&radio->data_buf[i]);
+ kfree(radio);
+ return -ENOMEM;
+ }
}
return 0;
}
@@ -4338,6 +5195,10 @@
int i;
struct iris_device *radio = platform_get_drvdata(pdev);
+ if (radio == NULL) {
+ FMDERR(":radio is null");
+ return -EINVAL;
+ }
video_unregister_device(radio->videodev);
for (i = 0; i < IRIS_BUF_MAX; i++)
diff --git a/drivers/media/radio/radio-tavarua.c b/drivers/media/radio/radio-tavarua.c
index e0a99e2..c44e2a5 100644
--- a/drivers/media/radio/radio-tavarua.c
+++ b/drivers/media/radio/radio-tavarua.c
@@ -185,6 +185,10 @@
if (bahama_present == -ENODEV)
return -ENODEV;
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
if (bahama_present)
radio->marimba->mod_id = SLAVE_ID_BAHAMA_FM;
else
@@ -216,6 +220,11 @@
* (otherwise, it may have already been there and will not be added a second
* time).
*/
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
queue_delayed_work(radio->wqueue, &radio->work,
msecs_to_jiffies(TAVARUA_DELAY));
return IRQ_HANDLED;
@@ -243,6 +252,12 @@
unsigned char offset, int len)
{
int retval = 0, i = 0;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
retval = set_fm_slave_id(radio);
if (retval == -ENODEV)
@@ -282,6 +297,12 @@
unsigned char offset, unsigned char value)
{
int retval;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
retval = set_fm_slave_id(radio);
if (retval == -ENODEV)
@@ -322,6 +343,12 @@
int i;
int retval;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
retval = set_fm_slave_id(radio);
if (retval == -ENODEV)
@@ -358,6 +385,11 @@
*/
static int read_data_blocks(struct tavarua_device *radio, unsigned char offset)
{
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
/* read all 3 RDS blocks */
return tavarua_read_registers(radio, offset, RDS_BLOCK*4);
}
@@ -376,10 +408,17 @@
*/
static void tavarua_rds_read(struct tavarua_device *radio)
{
- struct kfifo *rds_buf = &radio->data_buf[TAVARUA_BUF_RAW_RDS];
+ struct kfifo *rds_buf;
unsigned char blocknum;
unsigned char tmp[3];
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return;
+ }
+
+ rds_buf = &radio->data_buf[TAVARUA_BUF_RAW_RDS];
+
if (read_data_blocks(radio, RAW_RDS) < 0)
return;
/* copy all four RDS blocks to internal buffer */
@@ -430,6 +469,12 @@
static int request_read_xfr(struct tavarua_device *radio,
enum tavarua_xfr_ctrl_t mode){
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
tavarua_write_register(radio, XFRCTRL, mode);
msleep(TAVARUA_DELAY);
return 0;
@@ -457,8 +502,17 @@
static int copy_from_xfr(struct tavarua_device *radio,
enum tavarua_buf_t buf_type, unsigned int n){
- struct kfifo *data_fifo = &radio->data_buf[buf_type];
- unsigned char *xfr_regs = &radio->registers[XFRCTRL+1];
+ struct kfifo *data_fifo;
+ unsigned char *xfr_regs;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ data_fifo = &radio->data_buf[buf_type];
+ xfr_regs = &radio->registers[XFRCTRL+1];
+
kfifo_in_locked(data_fifo, xfr_regs, n, &radio->buf_lock[buf_type]);
return 0;
}
@@ -496,6 +550,12 @@
char *buf, int len)
{
char buffer[len+1];
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
memcpy(buffer+1, buf, len);
/* buffer[0] corresponds to XFRCTRL register
set the CTRL bit to 1 for write mode
@@ -520,6 +580,11 @@
static int xfr_intf_own(struct tavarua_device *radio)
{
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
mutex_lock(&radio->lock);
if (radio->xfr_in_progress) {
radio->pending_xfrs[TAVARUA_XFR_SYNC] = 1;
@@ -552,6 +617,12 @@
enum tavarua_xfr_ctrl_t xfr_type, unsigned char *buf)
{
int retval;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
retval = xfr_intf_own(radio);
if (retval < 0)
return retval;
@@ -590,6 +661,17 @@
enum tavarua_xfr_ctrl_t xfr_type, unsigned char *buf)
{
int retval;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(buf == NULL)) {
+ FMDERR("%s:buf is null", __func__);
+ return -EINVAL;
+ }
+
retval = xfr_intf_own(radio);
if (retval < 0)
return retval;
@@ -627,6 +709,12 @@
{
int i;
enum tavarua_xfr_t xfr;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return;
+ }
+
for (i = 0; i < TAVARUA_XFR_MAX; i++) {
if (radio->pending_xfrs[i]) {
radio->xfr_in_progress = 1;
@@ -681,8 +769,16 @@
enum tavarua_evt_t event)
{
- struct kfifo *data_b = &radio->data_buf[TAVARUA_BUF_EVENTS];
+ struct kfifo *data_b;
unsigned char evt = event;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return;
+ }
+
+ data_b = &radio->data_buf[TAVARUA_BUF_EVENTS];
+
FMDBG("updating event_q with event %x\n", event);
if (kfifo_in_locked(data_b, &evt, 1, &radio->buf_lock[TAVARUA_BUF_EVENTS]))
wake_up_interruptible(&radio->event_queue);
@@ -707,12 +803,18 @@
static void tavarua_start_xfr(struct tavarua_device *radio,
enum tavarua_xfr_t pending_id, enum tavarua_xfr_ctrl_t xfr_id)
{
- if (radio->xfr_in_progress)
- radio->pending_xfrs[pending_id] = 1;
- else {
- radio->xfr_in_progress = 1;
- request_read_xfr(radio, xfr_id);
- }
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return;
+ }
+
+ if (radio->xfr_in_progress)
+ radio->pending_xfrs[pending_id] = 1;
+ else {
+ radio->xfr_in_progress = 1;
+ request_read_xfr(radio, xfr_id);
+ }
}
/*=============================================================================
@@ -739,6 +841,12 @@
int i;
int retval, adj_channel_tune_req = 0;
unsigned char xfr_status;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return;
+ }
+
if (!radio->handle_irq) {
FMDBG("IRQ happend, but I wont handle it\n");
return;
@@ -1143,15 +1251,34 @@
*/
static void read_int_stat(struct work_struct *work)
{
- struct tavarua_device *radio = container_of(work,
- struct tavarua_device, work.work);
+ struct tavarua_device *radio;
+
+ if (unlikely(work == NULL)) {
+ FMDERR("%s:work is null", __func__);
+ return;
+ }
+
+ radio = container_of(work, struct tavarua_device, work.work);
+
tavarua_handle_interrupts(radio);
}
static void fm_shutdown(struct work_struct *work)
{
- struct tavarua_device *radio = container_of(work,
- struct tavarua_device, work.work);
+ struct tavarua_device *radio;
+
+ if (unlikely(work == NULL)) {
+ FMDERR("%s:work is null", __func__);
+ return;
+ }
+
+ radio = container_of(work, struct tavarua_device, work.work);
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return;
+ }
+
FMDERR("%s: Releasing the FM I2S GPIO\n", __func__);
if (radio->pdata->config_i2s_gpio != NULL)
radio->pdata->config_i2s_gpio(FM_I2S_OFF);
@@ -1178,9 +1305,14 @@
static int tavarua_request_irq(struct tavarua_device *radio)
{
int retval;
- int irq = radio->pdata->irq;
- if (radio == NULL)
+ int irq;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
return -EINVAL;
+ }
+
+ irq = radio->pdata->irq;
/* A workqueue created with create_workqueue() will have one worker thread
* for each CPU on the system; create_singlethread_workqueue(), instead,
@@ -1237,8 +1369,12 @@
static int tavarua_disable_irq(struct tavarua_device *radio)
{
int irq;
- if (!radio)
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
return -EINVAL;
+ }
+
irq = radio->pdata->irq;
disable_irq_wake(irq);
free_irq(irq, radio);
@@ -1255,6 +1391,11 @@
unsigned int rdsMask = 0;
unsigned char value = 0;
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
adie_type_bahma = is_bahama();
switch (region) {
@@ -1435,9 +1576,17 @@
*/
static int tavarua_search(struct tavarua_device *radio, int on, int dir)
{
- enum search_t srch = radio->registers[SRCHCTRL] & SRCH_MODE;
+ enum search_t srch;
FMDBG("In tavarua_search\n");
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ srch = radio->registers[SRCHCTRL] & SRCH_MODE;
+
if (on) {
radio->registers[SRCHRDS1] = 0x00;
radio->registers[SRCHRDS2] = 0x00;
@@ -1503,6 +1652,11 @@
enum tavarua_region_t region = req_region;
unsigned char adie_type_bahma;
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
adie_type_bahma = is_bahama();
/* Set freq band */
@@ -1671,6 +1825,17 @@
unsigned short chan;
unsigned int band_bottom;
unsigned int spacing;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(freq == NULL)) {
+ FMDERR("%s:freq is null", __func__);
+ return -EINVAL;
+ }
+
band_bottom = radio->region_params.band_low;
spacing = 0.100 * FREQ_MUL;
/* read channel */
@@ -1716,6 +1881,12 @@
unsigned char cmd[] = {0x00, 0x00};
unsigned int spacing;
int retval;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
band_bottom = radio->region_params.band_low;
spacing = 0.100 * FREQ_MUL;
if ((freq % 1600) == 800) {
@@ -1760,8 +1931,19 @@
size_t count, loff_t *ppos)
{
struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
- struct kfifo *rds_buf = &radio->data_buf[TAVARUA_BUF_RAW_RDS];
+ struct kfifo *rds_buf;
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(buf == NULL)) {
+ FMDERR("%s:buf is null", __func__);
+ return -EINVAL;
+ }
+
+ rds_buf = &radio->data_buf[TAVARUA_BUF_RAW_RDS];
/* block if no new data available */
while (!kfifo_len(rds_buf)) {
if (file->f_flags & O_NONBLOCK)
@@ -1810,6 +1992,17 @@
int bytes_left;
int chunk_index = 0;
unsigned char tx_data[XFR_REG_NUM];
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(data == NULL)) {
+ FMDERR("%s:data is null", __func__);
+ return -EINVAL;
+ }
+
/* Disable TX of this type first */
switch (radio->tx_mode) {
case TAVARUA_TX_RT:
@@ -1897,6 +2090,11 @@
char buffer[] = {0x00, 0x48, 0x8A, 0x8E, 0x97, 0xB7};
int bahama_present = -ENODEV;
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
INIT_DELAYED_WORK(&radio->work, read_int_stat);
if (!atomic_dec_and_test(&radio->users)) {
pr_err("%s: Device already in use."
@@ -2518,6 +2716,16 @@
{
struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(capability == NULL)) {
+ FMDERR("%s:capability is null", __func__);
+ return -EINVAL;
+ }
+
strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
sprintf(capability->bus_info, "I2C");
@@ -2553,6 +2761,12 @@
unsigned char i;
int retval = -EINVAL;
+ if (unlikely(qc == NULL)) {
+ FMDERR("%s:qc is null", __func__);
+ return -EINVAL;
+ }
+
+
for (i = 0; i < ARRAY_SIZE(tavarua_v4l2_queryctrl); i++) {
if (qc->id && qc->id == tavarua_v4l2_queryctrl[i].id) {
memcpy(qc, &(tavarua_v4l2_queryctrl[i]), sizeof(*qc));
@@ -2574,6 +2788,11 @@
int index = 0, offset = 0, addr = 0x0, val = 0;
int retval = 0, temp = 0, cnt = 0, j = 0;
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
memset(xfr_buf, 0x0, XFR_REG_NUM);
/* Read the SPUR Table Size */
@@ -2651,6 +2870,15 @@
unsigned char xfr_buf[XFR_REG_NUM + 1];
int retval = 0, temp = 0;
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(buf == NULL)) {
+ FMDERR("%s:buf is null", __func__);
+ return -EINVAL;
+ }
/* zero initialize the buffer */
memset(xfr_buf, 0x0, XFR_REG_NUM);
@@ -2725,6 +2953,11 @@
int ct = 0;
unsigned char size = 0;
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
/*
Poking the MPX_DCC_BYPASS register to freeze the
value of MPX_DCC from changing while we access it
@@ -2844,6 +3077,16 @@
signed char ioc;
unsigned char size = 0;
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(ctrl == NULL)) {
+ FMDERR("%s:ctrl is null", __func__);
+ return -EINVAL;
+ }
+
switch (ctrl->id) {
case V4L2_CID_AUDIO_VOLUME:
break;
@@ -3051,7 +3294,7 @@
int retval = 0;
int bytes_to_copy;
int bytes_copied = 0;
- int bytes_left = 0;
+ __u32 bytes_left = 0;
int chunk_index = 0;
char tx_data[XFR_REG_NUM];
struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
@@ -3059,6 +3302,18 @@
int extra_name_byte = 0;
int name_bytes = 0;
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(ctrl == NULL) ||
+ unlikely(ctrl->controls == NULL) ||
+ unlikely(ctrl->count <= 0)) {
+ FMDERR("%s:ctrl is null", __func__);
+ return -EINVAL;
+ }
+
switch ((ctrl->controls[0]).id) {
case V4L2_CID_RDS_TX_PS_NAME: {
FMDBG("In V4L2_CID_RDS_TX_PS_NAME\n");
@@ -3066,15 +3321,15 @@
chunk_index = 0;
bytes_copied = 0;
- bytes_left = min((int)(ctrl->controls[0]).size,
- MAX_PS_LENGTH);
+ bytes_left = min((ctrl->controls[0]).size,
+ (__u32)MAX_PS_LENGTH);
data = (ctrl->controls[0]).string;
/* send payload to FM hardware */
while (bytes_left) {
chunk_index++;
FMDBG("chunk is %d", chunk_index);
- bytes_to_copy = min(bytes_left, XFR_REG_NUM);
+ bytes_to_copy = min(bytes_left, (__u32)XFR_REG_NUM);
/*Clear the tx_data */
memset(tx_data, 0, XFR_REG_NUM);
if (copy_from_user(tx_data,
@@ -3116,12 +3371,12 @@
FMDBG("Passed RT String : %s\n",
(ctrl->controls[0]).string);
bytes_left =
- min((int)(ctrl->controls[0]).size, MAX_RT_LENGTH);
+ min((ctrl->controls[0]).size, (__u32)MAX_RT_LENGTH);
data = (ctrl->controls[0]).string;
/* send payload to FM hardware */
while (bytes_left) {
chunk_index++;
- bytes_to_copy = min(bytes_left, XFR_REG_NUM);
+ bytes_to_copy = min(bytes_left, (__u32)XFR_REG_NUM);
memset(tx_data, 0, XFR_REG_NUM);
if (copy_from_user(tx_data,
data + bytes_copied, bytes_to_copy))
@@ -3191,6 +3446,16 @@
unsigned int freq = 0, mpx_dcc = 0;
unsigned long curr = 0, prev = 0;
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(ctrl == NULL)) {
+ FMDERR("%s:ctrl is null", __func__);
+ return -EINVAL;
+ }
+
memset(xfr_buf, 0x0, XFR_REG_NUM);
switch (ctrl->id) {
@@ -3797,6 +4062,16 @@
char rmssi = 0;
unsigned char size = 0;
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(tuner == NULL)) {
+ FMDERR("%s:tuner is null", __func__);
+ return -EINVAL;
+ }
+
if (tuner->index > 0)
return -EINVAL;
@@ -3863,6 +4138,17 @@
struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
int retval;
int audmode;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(tuner == NULL)) {
+ FMDERR("%s:tuner is null", __func__);
+ return -EINVAL;
+ }
+
if (tuner->index > 0)
return -EINVAL;
@@ -3910,6 +4196,17 @@
struct v4l2_frequency *freq)
{
struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(freq == NULL)) {
+ FMDERR("%s:freq is null", __func__);
+ return -EINVAL;
+ }
+
freq->type = V4L2_TUNER_RADIO;
return tavarua_get_freq(radio, freq);
@@ -3945,6 +4242,16 @@
FMDBG("%s\n", __func__);
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(freq == NULL)) {
+ FMDERR("%s:freq is null", __func__);
+ return -EINVAL;
+ }
+
if (freq->type != V4L2_TUNER_RADIO)
return -EINVAL;
@@ -4108,6 +4415,17 @@
{
struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
int dir;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(seek == NULL)) {
+ FMDERR("%s:seek is null", __func__);
+ return -EINVAL;
+ }
+
if (seek->seek_upward)
dir = SRCH_DIR_UP;
else
@@ -4159,6 +4477,11 @@
int retval;
unsigned char int_ctrl[XFR_REG_NUM];
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
if (!radio->lp_mode)
return 0;
@@ -4222,6 +4545,12 @@
{
unsigned char lpm_buf[XFR_REG_NUM];
int retval;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
if (radio->lp_mode)
return 0;
FMDBG("%s\n", __func__);
@@ -4270,6 +4599,12 @@
int retval;
FMDBG("%s <%d>\n", __func__, state);
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
/* set geographic region */
radio->region_params.region = TAVARUA_REGION_US;
@@ -4305,6 +4640,12 @@
int retval;
int users = 0;
printk(KERN_INFO DRIVER_NAME "%s: radio suspend\n\n", __func__);
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
if (radio) {
users = atomic_read(&radio->users);
if (!users) {
@@ -4336,6 +4677,12 @@
int retval;
int users = 0;
printk(KERN_INFO DRIVER_NAME "%s: radio resume\n\n", __func__);
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
if (radio) {
users = atomic_read(&radio->users);
@@ -4380,8 +4727,12 @@
struct tavarua_device *radio = private_data;
int rx_on = radio->registers[RDCTRL] & FM_RECV;
int retval = 0;
- if (!radio)
- return -ENOMEM;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
/* RX */
FMDBG("%s: digital: %d analog: %d\n", __func__, digital_on, analog_on);
if ((radio->pdata != NULL) && (radio->pdata->config_i2s_gpio != NULL)) {
@@ -4466,9 +4817,15 @@
struct marimba_fm_platform_data *tavarua_pdata;
struct tavarua_device *radio;
- int retval;
- int i;
+ int retval = 0;
+ int i = 0, j = 0;
FMDBG("%s: probe called\n", __func__);
+
+ if (unlikely(pdev == NULL)) {
+ FMDERR("%s:pdev is null", __func__);
+ return -EINVAL;
+ }
+
/* private data allocation */
radio = kzalloc(sizeof(struct tavarua_device), GFP_KERNEL);
if (!radio) {
@@ -4480,6 +4837,7 @@
tavarua_pdata = pdev->dev.platform_data;
radio->pdata = tavarua_pdata;
radio->dev = &pdev->dev;
+ radio->wqueue = NULL;
platform_set_drvdata(pdev, radio);
/* video device allocation */
@@ -4509,15 +4867,16 @@
if (kfifo_alloc_rc!=0) {
printk(KERN_ERR "%s: failed allocating buffers %d\n",
__func__, kfifo_alloc_rc);
- goto err_bufs;
+ retval = -ENOMEM;
+ goto err_all;
}
}
/* initializing the device count */
atomic_set(&radio->users, 1);
radio->xfr_in_progress = 0;
radio->xfr_bytes_left = 0;
- for (i = 0; i < TAVARUA_XFR_MAX; i++)
- radio->pending_xfrs[i] = 0;
+ for (j = 0; j < TAVARUA_XFR_MAX; j++)
+ radio->pending_xfrs[j] = 0;
/* init transmit data */
radio->tx_mode = TAVARUA_TX_RT;
@@ -4548,11 +4907,14 @@
/*Start the worker thread for event handling and register read_int_stat
as worker function*/
radio->wqueue = create_singlethread_workqueue("kfmradio");
- if (!radio->wqueue)
- return -ENOMEM;
+ if (!radio->wqueue) {
+ retval = -ENOMEM;
+ goto err_all;
+ }
/* register video device */
- if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
+ retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr);
+ if (retval != 0) {
printk(KERN_WARNING DRIVER_NAME
": Could not register video device\n");
goto err_all;
@@ -4562,9 +4924,11 @@
err_all:
video_device_release(radio->videodev);
-err_bufs:
- for (; i > -1; i--)
+ if (radio->wqueue)
+ destroy_workqueue(radio->wqueue);
+ for (i--; i >= 0; i--) {
kfifo_free(&radio->data_buf[i]);
+ }
err_radio:
kfree(radio);
err_initial:
@@ -4586,6 +4950,11 @@
int i;
struct tavarua_device *radio = platform_get_drvdata(pdev);
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
/* disable irq */
tavarua_disable_irq(radio);
diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c
index 9dd06ee..127a231 100644
--- a/drivers/media/video/v4l2-ctrls.c
+++ b/drivers/media/video/v4l2-ctrls.c
@@ -310,6 +310,7 @@
"Scalable High",
"Scalable High Intra",
"Multiview High",
+ "Constrained High",
NULL,
};
static const char * const vui_sar_idc[] = {
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 907ce7c..64053de 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -1673,10 +1673,8 @@
wcd9xxx->slim_device_bootup = false;
return 0;
}
- ret = wcd9xxx_reset(wcd9xxx);
- if (ret)
- pr_err("%s: Resetting Codec failed\n", __func__);
+ dev_info(wcd9xxx->dev, "%s: codec bring up\n", __func__);
wcd9xxx_bring_up(wcd9xxx);
ret = wcd9xxx_irq_init(wcd9xxx_res);
if (ret) {
@@ -1688,6 +1686,25 @@
return ret;
}
+static int wcd9xxx_slim_device_reset(struct slim_device *sldev)
+{
+ int ret;
+ struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
+ if (!wcd9xxx) {
+ pr_err("%s: wcd9xxx is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ dev_info(wcd9xxx->dev, "%s: device reset\n", __func__);
+ if (wcd9xxx->slim_device_bootup)
+ return 0;
+ ret = wcd9xxx_reset(wcd9xxx);
+ if (ret)
+ dev_err(wcd9xxx->dev, "%s: Resetting Codec failed\n", __func__);
+
+ return ret;
+}
+
static int wcd9xxx_slim_device_up(struct slim_device *sldev)
{
struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
@@ -1695,7 +1712,7 @@
pr_err("%s: wcd9xxx is NULL\n", __func__);
return -EINVAL;
}
- dev_dbg(wcd9xxx->dev, "%s: device up\n", __func__);
+ dev_info(wcd9xxx->dev, "%s: slim device up\n", __func__);
return wcd9xxx_device_up(wcd9xxx);
}
@@ -1703,6 +1720,7 @@
{
struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
+ dev_info(wcd9xxx->dev, "%s: device down\n", __func__);
if (!wcd9xxx) {
pr_err("%s: wcd9xxx is NULL\n", __func__);
return -EINVAL;
@@ -1826,6 +1844,7 @@
.resume = wcd9xxx_slim_resume,
.suspend = wcd9xxx_slim_suspend,
.device_up = wcd9xxx_slim_device_up,
+ .reset_device = wcd9xxx_slim_device_reset,
.device_down = wcd9xxx_slim_device_down,
};
@@ -1845,6 +1864,7 @@
.resume = wcd9xxx_slim_resume,
.suspend = wcd9xxx_slim_suspend,
.device_up = wcd9xxx_slim_device_up,
+ .reset_device = wcd9xxx_slim_device_reset,
.device_down = wcd9xxx_slim_device_down,
};
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index a30607c..c5c0ce8 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -91,7 +91,6 @@
static struct class *driver_class;
static dev_t qseecom_device_no;
-static struct cdev qseecom_cdev;
static DEFINE_MUTEX(qsee_bw_mutex);
static DEFINE_MUTEX(app_access_lock);
@@ -100,7 +99,7 @@
struct qseecom_registered_listener_list {
struct list_head list;
struct qseecom_register_listener_req svc;
- u8 *sb_reg_req;
+ uint32_t user_virt_sb_base;
u8 *sb_virt;
s32 sb_phys;
size_t sb_length;
@@ -162,6 +161,7 @@
uint32_t qsee_perf_client;
struct qseecom_clk qsee;
struct qseecom_clk ce_drv;
+ struct cdev cdev;
};
struct qseecom_client_handle {
@@ -251,6 +251,12 @@
break;
}
spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
+
+ if ((entry != NULL) && (entry->svc.listener_id != listener_id)) {
+ pr_err("Service id: %u is not found\n", listener_id);
+ return NULL;
+ }
+
return entry;
}
@@ -313,6 +319,10 @@
pr_err("copy_from_user failed\n");
return ret;
}
+ if (!access_ok(VERIFY_WRITE, (void __user *)rcvd_lstnr.virt_sb_base,
+ rcvd_lstnr.sb_size))
+ return -EFAULT;
+
data->listener.id = 0;
if (!__qseecom_is_svc_unique(data, &rcvd_lstnr)) {
pr_err("Service is not unique and is already registered\n");
@@ -330,6 +340,7 @@
new_entry->svc.listener_id = rcvd_lstnr.listener_id;
new_entry->sb_length = rcvd_lstnr.sb_size;
+ new_entry->user_virt_sb_base = rcvd_lstnr.virt_sb_base;
if (__qseecom_set_sb_memory(new_entry, data, &rcvd_lstnr)) {
pr_err("qseecom_set_sb_memoryfailed\n");
kzfree(new_entry);
@@ -440,6 +451,10 @@
req.ifd_data_fd, req.sb_len, req.virt_sb_base);
return -EFAULT;
}
+ if (!access_ok(VERIFY_WRITE, (void __user *)req.virt_sb_base,
+ req.sb_len))
+ return -EFAULT;
+
/* Get the handle of the shared fd */
data->client.ihandle = ion_import_dma_buf(qseecom.ion_clnt,
req.ifd_data_fd);
@@ -494,6 +509,11 @@
}
spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
flags);
+
+ if (ptr_svc == NULL) {
+ pr_err("Listener Svc %d does not exist\n", lstnr);
+ return -EINVAL;
+ }
if (ptr_svc->svc.listener_id != lstnr) {
pr_warning("Service requested for does on exist\n");
return -ERESTARTSYS;
@@ -850,19 +870,54 @@
return data->client.sb_phys + (virt - data->client.user_virt_sb_base);
}
+static uint32_t __qseecom_uvirt_to_kvirt(struct qseecom_dev_handle *data,
+ uint32_t virt)
+{
+ return (uint32_t)data->client.sb_virt +
+ (virt - data->client.user_virt_sb_base);
+}
+
int __qseecom_process_rpmb_svc_cmd(struct qseecom_dev_handle *data_ptr,
struct qseecom_send_svc_cmd_req *req_ptr,
struct qseecom_client_send_service_ireq *send_svc_ireq_ptr)
{
int ret = 0;
+ void *req_buf = NULL;
+
if ((req_ptr == NULL) || (send_svc_ireq_ptr == NULL)) {
pr_err("Error with pointer: req_ptr = %p, send_svc_ptr = %p\n",
req_ptr, send_svc_ireq_ptr);
return -EINVAL;
}
+
+ if ((!req_ptr->cmd_req_buf) || (!req_ptr->resp_buf)) {
+ pr_err("Invalid req/resp buffer, exiting\n");
+ return -EINVAL;
+ }
+
+ if (((uint32_t)req_ptr->cmd_req_buf <
+ data_ptr->client.user_virt_sb_base)
+ || ((uint32_t)req_ptr->cmd_req_buf >=
+ (data_ptr->client.user_virt_sb_base +
+ data_ptr->client.sb_length))) {
+ pr_err("cmd buffer address not within shared bufffer\n");
+ return -EINVAL;
+ }
+
+
+ if (((uint32_t)req_ptr->resp_buf < data_ptr->client.user_virt_sb_base)
+ || ((uint32_t)req_ptr->resp_buf >=
+ (data_ptr->client.user_virt_sb_base +
+ data_ptr->client.sb_length))){
+ pr_err("response buffer address not within shared bufffer\n");
+ return -EINVAL;
+ }
+
+ req_buf = data_ptr->client.sb_virt;
+
send_svc_ireq_ptr->qsee_cmd_id = req_ptr->cmd_id;
send_svc_ireq_ptr->key_type =
- ((struct qseecom_rpmb_provision_key *)req_ptr->cmd_req_buf)->key_type;
+ ((struct qseecom_rpmb_provision_key *)req_buf)->key_type;
send_svc_ireq_ptr->req_len = req_ptr->cmd_req_len;
send_svc_ireq_ptr->rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data_ptr,
(uint32_t)req_ptr->resp_buf));
@@ -1063,8 +1118,6 @@
if (ret)
return ret;
- pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
- req.resp_len, req.resp_buf);
return ret;
}
@@ -1232,6 +1285,24 @@
pr_err("copy_from_user failed\n");
return ret;
}
+
+ if (req.cmd_req_buf == NULL || req.resp_buf == NULL) {
+ pr_err("cmd buffer or response buffer is null\n");
+ return -EINVAL;
+ }
+ if (((uint32_t)req.cmd_req_buf < data->client.user_virt_sb_base) ||
+ ((uint32_t)req.cmd_req_buf >= (data->client.user_virt_sb_base +
+ data->client.sb_length))) {
+ pr_err("cmd buffer address not within shared bufffer\n");
+ return -EINVAL;
+ }
+
+ if (((uint32_t)req.resp_buf < data->client.user_virt_sb_base) ||
+ ((uint32_t)req.resp_buf >= (data->client.user_virt_sb_base +
+ data->client.sb_length))){
+ pr_err("response buffer address not within shared bufffer\n");
+ return -EINVAL;
+ }
send_cmd_req.cmd_req_buf = req.cmd_req_buf;
send_cmd_req.cmd_req_len = req.cmd_req_len;
send_cmd_req.resp_buf = req.resp_buf;
@@ -1245,6 +1316,11 @@
return -EINVAL;
}
}
+ req.cmd_req_buf = (void *)__qseecom_uvirt_to_kvirt(data,
+ (uint32_t)req.cmd_req_buf);
+ req.resp_buf = (void *)__qseecom_uvirt_to_kvirt(data,
+ (uint32_t)req.resp_buf);
+
ret = __qseecom_update_cmd_buf(&req, false, data, false);
if (ret)
return ret;
@@ -1254,8 +1330,7 @@
ret = __qseecom_update_cmd_buf(&req, true, data, false);
if (ret)
return ret;
- pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
- req.resp_len, req.resp_buf);
+
return ret;
}
@@ -1273,6 +1348,11 @@
struct qseecom_registered_listener_list *this_lstnr;
this_lstnr = __qseecom_find_svc(data->listener.id);
+ if (!this_lstnr) {
+ pr_err("Invalid listener ID\n");
+ return -ENODATA;
+ }
+
while (1) {
if (wait_event_freezable(this_lstnr->rcv_req_wq,
__qseecom_listener_has_rcvd_req(data,
@@ -1836,11 +1916,20 @@
{
struct qseecom_send_modfd_listener_resp resp;
int i;
+ struct qseecom_registered_listener_list *this_lstnr = NULL;
if (copy_from_user(&resp, argp, sizeof(resp))) {
pr_err("copy_from_user failed");
return -EINVAL;
}
+ this_lstnr = __qseecom_find_svc(data->listener.id);
+ if (this_lstnr == NULL)
+ return -EINVAL;
+
+ if (resp.resp_buf_ptr == NULL) {
+ pr_err("Invalid resp_buf_ptr\n");
+ return -EINVAL;
+ }
/* validate offsets */
for (i = 0; i < MAX_ION_FD; i++) {
if (resp.ifd_data[i].cmd_buf_offset >= resp.resp_len) {
@@ -1849,6 +1938,17 @@
return -EINVAL;
}
}
+
+ if (((uint32_t)resp.resp_buf_ptr <
+ this_lstnr->user_virt_sb_base)
+ || ((uint32_t)resp.resp_buf_ptr >=
+ (this_lstnr->user_virt_sb_base +
+ this_lstnr->sb_length))) {
+ pr_err("resp_buf_ptr address not within shared buffer\n");
+ return -EINVAL;
+ }
+ resp.resp_buf_ptr = (uint32_t)this_lstnr->sb_virt +
+ (resp.resp_buf_ptr - this_lstnr->user_virt_sb_base);
__qseecom_update_cmd_buf(&resp, false, data, true);
qseecom.send_resp_flag = 1;
wake_up_interruptible(&qseecom.send_resp_wq);
@@ -3330,7 +3430,7 @@
if (IS_ERR(driver_class)) {
rc = -ENOMEM;
pr_err("class_create failed %d\n", rc);
- goto unregister_chrdev_region;
+ goto exit_unreg_chrdev_region;
}
class_dev = device_create(driver_class, NULL, qseecom_device_no, NULL,
@@ -3338,16 +3438,16 @@
if (!class_dev) {
pr_err("class_device_create failed %d\n", rc);
rc = -ENOMEM;
- goto class_destroy;
+ goto exit_destroy_class;
}
- cdev_init(&qseecom_cdev, &qseecom_fops);
- qseecom_cdev.owner = THIS_MODULE;
+ cdev_init(&qseecom.cdev, &qseecom_fops);
+ qseecom.cdev.owner = THIS_MODULE;
- rc = cdev_add(&qseecom_cdev, MKDEV(MAJOR(qseecom_device_no), 0), 1);
+ rc = cdev_add(&qseecom.cdev, MKDEV(MAJOR(qseecom_device_no), 0), 1);
if (rc < 0) {
pr_err("cdev_add failed %d\n", rc);
- goto err;
+ goto exit_destroy_device;
}
INIT_LIST_HEAD(&qseecom.registered_listener_list_head);
@@ -3363,7 +3463,7 @@
&qsee_not_legacy, sizeof(qsee_not_legacy));
if (rc) {
pr_err("Failed to retrieve QSEOS version information %d\n", rc);
- goto err;
+ goto exit_del_cdev;
}
if (qsee_not_legacy) {
uint32_t feature = 10;
@@ -3373,14 +3473,14 @@
&qseecom.qsee_version, sizeof(qseecom.qsee_version));
if (rc) {
pr_err("Failed to get QSEE version info %d\n", rc);
- goto err;
+ goto exit_del_cdev;
}
qseecom.qseos_version = QSEOS_VERSION_14;
} else {
pr_err("QSEE legacy version is not supported:");
pr_err("Support for TZ1.3 and earlier is deprecated\n");
rc = -EINVAL;
- goto err;
+ goto exit_del_cdev;
}
qseecom.commonlib_loaded = false;
qseecom.pdev = class_dev;
@@ -3389,7 +3489,7 @@
if (qseecom.ion_clnt == NULL) {
pr_err("Ion client cannot be created\n");
rc = -ENOMEM;
- goto err;
+ goto exit_del_cdev;
}
/* register client for bus scaling */
@@ -3401,7 +3501,7 @@
pr_err("Fail to get disk-encrypt pipe pair information.\n");
qseecom.ce_info.disk_encrypt_pipe = 0xff;
rc = -EINVAL;
- goto err;
+ goto exit_destroy_ion_client;
} else {
pr_warn("bam_pipe_pair=0x%x",
qseecom.ce_info.disk_encrypt_pipe);
@@ -3413,7 +3513,7 @@
pr_err("Fail to get qsee ce hw instance information.\n");
qseecom.ce_info.qsee_ce_hw_instance = 0xff;
rc = -EINVAL;
- goto err;
+ goto exit_destroy_ion_client;
} else {
pr_warn("qsee-ce-hw-instance=0x%x",
qseecom.ce_info.qsee_ce_hw_instance);
@@ -3425,7 +3525,7 @@
pr_err("Fail to get hlos ce hw instance information.\n");
qseecom.ce_info.hlos_ce_hw_instance = 0xff;
rc = -EINVAL;
- goto err;
+ goto exit_destroy_ion_client;
} else {
pr_warn("hlos-ce-hw-instance=0x%x",
qseecom.ce_info.hlos_ce_hw_instance);
@@ -3436,13 +3536,13 @@
ret = __qseecom_init_clk(CLK_QSEE);
if (ret)
- goto err;
+ goto exit_destroy_ion_client;
if (qseecom.qsee.instance != qseecom.ce_drv.instance) {
ret = __qseecom_init_clk(CLK_CE_DRV);
if (ret) {
__qseecom_deinit_clk(CLK_QSEE);
- goto err;
+ goto exit_destroy_ion_client;
}
} else {
struct qseecom_clk *qclk;
@@ -3472,7 +3572,7 @@
} else {
pr_err("Fail to get secure app region info\n");
rc = -EINVAL;
- goto err;
+ goto exit_destroy_ion_client;
}
rc = scm_call(SCM_SVC_TZSCHEDULER, 1, &req, sizeof(req),
&resp, sizeof(resp));
@@ -3480,7 +3580,7 @@
pr_err("send secapp reg fail %d resp.res %d\n",
rc, resp.result);
rc = -EINVAL;
- goto err;
+ goto exit_destroy_ion_client;
}
}
} else {
@@ -3494,11 +3594,16 @@
if (!qseecom.qsee_perf_client)
pr_err("Unable to register bus client\n");
return 0;
-err:
+
+exit_destroy_ion_client:
+ ion_client_destroy(qseecom.ion_clnt);
+exit_del_cdev:
+ cdev_del(&qseecom.cdev);
+exit_destroy_device:
device_destroy(driver_class, qseecom_device_no);
-class_destroy:
+exit_destroy_class:
class_destroy(driver_class);
-unregister_chrdev_region:
+exit_unreg_chrdev_region:
unregister_chrdev_region(qseecom_device_no, 1);
return rc;
}
@@ -3509,69 +3614,64 @@
unsigned long flags = 0;
int ret = 0;
- if (pdev->dev.platform_data != NULL)
- msm_bus_scale_unregister_client(qseecom.qsee_perf_client);
-
spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
- kclient = list_entry((&qseecom.registered_kclient_list_head)->next,
- struct qseecom_registered_kclient_list, list);
- if (list_empty(&kclient->list)) {
- spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock,
- flags);
- return 0;
- }
+
list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
- list) {
- if (kclient)
- list_del(&kclient->list);
- break;
- }
- spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
+ list) {
+ if (!kclient)
+ goto exit_irqrestore;
+ /* Break the loop if client handle is NULL */
+ if (!kclient->handle)
+ goto exit_free_kclient;
- while (kclient->handle != NULL) {
+ if (list_empty(&kclient->list))
+ goto exit_free_kc_handle;
+
+ list_del(&kclient->list);
ret = qseecom_unload_app(kclient->handle->dev);
- if (ret == 0) {
+ if (!ret) {
kzfree(kclient->handle->dev);
kzfree(kclient->handle);
kzfree(kclient);
}
- spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
- kclient = list_entry(
- (&qseecom.registered_kclient_list_head)->next,
- struct qseecom_registered_kclient_list, list);
- if (list_empty(&kclient->list)) {
- spin_unlock_irqrestore(
- &qseecom.registered_kclient_list_lock, flags);
- return 0;
- }
- list_for_each_entry(kclient,
- &qseecom.registered_kclient_list_head, list) {
- if (kclient)
- list_del(&kclient->list);
- break;
- }
- spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock,
- flags);
- if (!kclient) {
- ret = 0;
- break;
- }
}
- if (qseecom.qseos_version > QSEEE_VERSION_00)
+
+exit_free_kc_handle:
+ kzfree(kclient->handle);
+exit_free_kclient:
+ kzfree(kclient);
+exit_irqrestore:
+ spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
+
+ if (qseecom.qseos_version > QSEEE_VERSION_00)
qseecom_unload_commonlib_image();
if (qseecom.qsee_perf_client)
msm_bus_scale_client_update_request(qseecom.qsee_perf_client,
0);
+ if (pdev->dev.platform_data != NULL)
+ msm_bus_scale_unregister_client(qseecom.qsee_perf_client);
+
/* register client for bus scaling */
if (pdev->dev.of_node) {
__qseecom_deinit_clk(CLK_QSEE);
if (qseecom.qsee.instance != qseecom.ce_drv.instance)
__qseecom_deinit_clk(CLK_CE_DRV);
}
+
+ ion_client_destroy(qseecom.ion_clnt);
+
+ cdev_del(&qseecom.cdev);
+
+ device_destroy(driver_class, qseecom_device_no);
+
+ class_destroy(driver_class);
+
+ unregister_chrdev_region(qseecom_device_no, 1);
+
return ret;
-};
+}
static struct of_device_id qseecom_match[] = {
{
@@ -3597,10 +3697,7 @@
static void __devexit qseecom_exit(void)
{
- device_destroy(driver_class, qseecom_device_no);
- class_destroy(driver_class);
- unregister_chrdev_region(qseecom_device_no, 1);
- ion_client_destroy(qseecom.ion_clnt);
+ platform_driver_unregister(&qseecom_plat_driver);
}
MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/smsc_hub.c b/drivers/misc/smsc_hub.c
index 0147e66..6f98dc7 100644
--- a/drivers/misc/smsc_hub.c
+++ b/drivers/misc/smsc_hub.c
@@ -385,26 +385,27 @@
static int __devinit smsc_hub_probe(struct platform_device *pdev)
{
int ret = 0;
- const struct smsc_hub_platform_data *pdata;
+ struct smsc_hub_platform_data *pdata;
struct device_node *node = pdev->dev.of_node;
struct i2c_adapter *i2c_adap;
struct i2c_board_info i2c_info;
+ struct of_dev_auxdata *hsic_host_auxdata;
if (pdev->dev.of_node) {
dev_dbg(&pdev->dev, "device tree enabled\n");
- pdev->dev.platform_data = msm_hub_dt_to_pdata(pdev);
- if (IS_ERR(pdev->dev.platform_data))
- return PTR_ERR(pdev->dev.platform_data);
-
- dev_set_name(&pdev->dev, smsc_hub_driver.driver.name);
+ hsic_host_auxdata = dev_get_platdata(&pdev->dev);
+ pdata = msm_hub_dt_to_pdata(pdev);
+ if (IS_ERR(pdata))
+ return PTR_ERR(pdata);
+ } else {
+ pdata = pdev->dev.platform_data;
}
- if (!pdev->dev.platform_data) {
+ if (!pdata) {
dev_err(&pdev->dev, "No platform data\n");
return -ENODEV;
}
- pdata = pdev->dev.platform_data;
if (!pdata->hub_reset)
return -EINVAL;
@@ -413,7 +414,7 @@
return -ENOMEM;
smsc_hub->dev = &pdev->dev;
- smsc_hub->pdata = pdev->dev.platform_data;
+ smsc_hub->pdata = pdata;
smsc_hub->hub_vbus_reg = devm_regulator_get(&pdev->dev, "hub_vbus");
ret = PTR_ERR(smsc_hub->hub_vbus_reg);
@@ -494,7 +495,7 @@
i2c_put_adapter(i2c_adap);
i2c_add_fail:
- ret = of_platform_populate(node, NULL, NULL, &pdev->dev);
+ ret = of_platform_populate(node, NULL, hsic_host_auxdata, &pdev->dev);
if (ret) {
dev_err(&pdev->dev, "failed to add child node, ret=%d\n", ret);
goto uninit_gpio;
@@ -523,7 +524,7 @@
{
const struct smsc_hub_platform_data *pdata;
- pdata = pdev->dev.platform_data;
+ pdata = smsc_hub->pdata;
if (smsc_hub->client) {
i2c_unregister_device(smsc_hub->client);
smsc_hub->client = NULL;
diff --git a/drivers/misc/tspp.c b/drivers/misc/tspp.c
index 36bdf45..19f26f2 100644
--- a/drivers/misc/tspp.c
+++ b/drivers/misc/tspp.c
@@ -1706,6 +1706,8 @@
dma_free_coherent(NULL, config->desc.size, config->desc.base,
config->desc.phys_base);
+ sps_free_endpoint(channel->pipe);
+
tspp_destroy_buffers(channel_id, channel);
if (channel->dma_pool) {
dma_pool_destroy(channel->dma_pool);
@@ -1821,7 +1823,7 @@
}
if (filter->priority >= TSPP_NUM_PRIORITIES) {
- pr_err("tspp invalid source");
+ pr_err("tspp invalid filter priority");
return -ENOSR;
}
@@ -1950,6 +1952,10 @@
pr_err("tspp_remove: can't find device %i", dev);
return -ENODEV;
}
+ if (filter->priority >= TSPP_NUM_PRIORITIES) {
+ pr_err("tspp invalid filter priority");
+ return -ENOSR;
+ }
channel = &pdev->channels[channel_id];
src = channel->src;
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 743668b..ff3e4ac 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -3073,6 +3073,8 @@
MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
MMC_FIXUP("VZL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
+ MMC_FIXUP(CID_NAME_ANY, CID_MANFID_HYNIX, CID_OEMID_ANY, add_quirk_mmc,
+ MMC_QUIRK_BROKEN_DATA_TIMEOUT),
END_FIXUP
};
diff --git a/drivers/mmc/card/mmc_block_test.c b/drivers/mmc/card/mmc_block_test.c
index 39296ef..5cc2806 100644
--- a/drivers/mmc/card/mmc_block_test.c
+++ b/drivers/mmc/card/mmc_block_test.c
@@ -2285,6 +2285,9 @@
size_t count,
loff_t *offset)
{
+ if (!access_ok(VERIFY_WRITE, buffer, count))
+ return count;
+
memset((void *)buffer, 0, count);
snprintf(buffer, count,
@@ -2383,6 +2386,9 @@
size_t count,
loff_t *offset)
{
+ if (!access_ok(VERIFY_WRITE, buffer, count))
+ return count;
+
memset((void *)buffer, 0, count);
snprintf(buffer, count,
@@ -2491,6 +2497,9 @@
size_t count,
loff_t *offset)
{
+ if (!access_ok(VERIFY_WRITE, buffer, count))
+ return count;
+
memset((void *)buffer, 0, count);
snprintf(buffer, count,
@@ -2605,6 +2614,9 @@
size_t count,
loff_t *offset)
{
+ if (!access_ok(VERIFY_WRITE, buffer, count))
+ return count;
+
memset((void *)buffer, 0, count);
snprintf(buffer, count,
@@ -2730,6 +2742,9 @@
size_t count,
loff_t *offset)
{
+ if (!access_ok(VERIFY_WRITE, buffer, count))
+ return count;
+
memset((void *)buffer, 0, count);
snprintf(buffer, count,
@@ -2818,6 +2833,9 @@
size_t count,
loff_t *offset)
{
+ if (!access_ok(VERIFY_WRITE, buffer, count))
+ return count;
+
memset((void *)buffer, 0, count);
snprintf(buffer, count,
@@ -2978,6 +2996,9 @@
size_t count,
loff_t *offset)
{
+ if (!access_ok(VERIFY_WRITE, buffer, count))
+ return count;
+
memset((void *)buffer, 0, count);
snprintf(buffer, count,
@@ -3051,6 +3072,9 @@
size_t count,
loff_t *offset)
{
+ if (!access_ok(VERIFY_WRITE, buffer, count))
+ return count;
+
memset((void *)buffer, 0, count);
snprintf(buffer, count,
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index eb5d365..b36faff 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -414,14 +414,12 @@
#endif
mmc_init_context_info(card->host);
- if (mmc_use_core_runtime_pm(card->host)) {
- ret = pm_runtime_set_active(&card->dev);
- if (ret)
- pr_err("%s: %s: failed setting runtime active: ret: %d\n",
- mmc_hostname(card->host), __func__, ret);
- else if (!mmc_card_sdio(card))
- pm_runtime_enable(&card->dev);
- }
+ ret = pm_runtime_set_active(&card->dev);
+ if (ret)
+ pr_err("%s: %s: failed setting runtime active: ret: %d\n",
+ mmc_hostname(card->host), __func__, ret);
+ else if (!mmc_card_sdio(card) && mmc_use_core_runtime_pm(card->host))
+ pm_runtime_enable(&card->dev);
ret = device_add(&card->dev);
if (ret)
@@ -469,6 +467,7 @@
}
kfree(card->wr_pack_stats.packing_events);
+ kfree(card->cached_ext_csd);
put_device(&card->dev);
}
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 293033b..94a13f9 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -61,6 +61,7 @@
/* Flushing a large amount of cached data may take a long time. */
#define MMC_FLUSH_REQ_TIMEOUT_MS 90000 /* msec */
+#define MMC_CACHE_DISBALE_TIMEOUT_MS 180000 /* msec */
static struct workqueue_struct *workqueue;
@@ -744,7 +745,11 @@
*/
mmc_update_clk_scaling(host);
err = mmc_stop_request(host);
- if (err && !context_info->is_done_rcv) {
+ if (err == MMC_BLK_NO_REQ_TO_STOP) {
+ pending_is_urgent = true;
+ /* wait for done/new/urgent event */
+ continue;
+ } else if (err && !context_info->is_done_rcv) {
err = MMC_BLK_ABORT;
break;
}
@@ -890,7 +895,9 @@
mmc_post_req(host, host->areq->mrq, 0);
host->areq = NULL;
if (areq) {
- if (!(areq->cmd_flags & REQ_URGENT)) {
+ if (!(areq->cmd_flags & (REQ_URGENT
+ | REQ_FUA
+ | REQ_FLUSH))) {
areq->reinsert_req(areq);
mmc_post_req(host, areq->mrq, 0);
} else {
@@ -1302,6 +1309,11 @@
data->timeout_ns = 4000000000u; /* 4s */
data->timeout_clks = 0;
}
+ /* Some emmc cards require a longer read/write time */
+ if (card->quirks & MMC_QUIRK_BROKEN_DATA_TIMEOUT) {
+ if (data->timeout_ns < 4000000000u)
+ data->timeout_ns = 4000000000u; /* 4s */
+ }
}
EXPORT_SYMBOL(mmc_set_data_timeout);
@@ -3136,6 +3148,7 @@
return;
mmc_bus_get(host);
+ mmc_rpm_hold(host, &host->class_dev);
/*
* if there is a _removable_ card registered, check whether it is
@@ -3168,10 +3181,13 @@
/* if there still is a card present, stop here */
if (host->bus_ops != NULL) {
+ mmc_rpm_release(host, &host->class_dev);
mmc_bus_put(host);
goto out;
}
+ mmc_rpm_release(host, &host->class_dev);
+
/*
* Only we can add a new handler, so it's safe to
* release the lock here.
@@ -3389,14 +3405,14 @@
if (card->ext_csd.cache_ctrl ^ enable) {
if (!enable)
- timeout = MMC_FLUSH_REQ_TIMEOUT_MS;
+ timeout = MMC_CACHE_DISBALE_TIMEOUT_MS;
err = mmc_switch_ignore_timeout(card,
EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_CACHE_CTRL, enable, timeout);
if (err == -ETIMEDOUT && !enable) {
- pr_debug("%s:cache disable operation timeout\n",
+ pr_err("%s:cache disable operation timeout\n",
mmc_hostname(card->host));
rc = mmc_interrupt_hpi(card);
if (rc)
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 903decf..4ec8941 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -15,6 +15,7 @@
#include <linux/slab.h>
#include <linux/stat.h>
#include <linux/fault-inject.h>
+#include <linux/uaccess.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
@@ -392,6 +393,9 @@
if (!card)
return cnt;
+ if (!access_ok(VERIFY_WRITE, ubuf, cnt))
+ return cnt;
+
if (!card->wr_pack_stats.print_in_read)
return 0;
@@ -532,6 +536,9 @@
if (!card)
return cnt;
+ if (!access_ok(VERIFY_READ, ubuf, cnt))
+ return cnt;
+
sscanf(ubuf, "%d", &value);
if (value) {
mmc_blk_init_packed_statistics(card);
@@ -571,6 +578,9 @@
if (!card)
return cnt;
+ if (!access_ok(VERIFY_WRITE, ubuf, cnt))
+ return cnt;
+
bkops_stats = &card->bkops_info.bkops_stats;
if (!bkops_stats->print_stats)
@@ -637,6 +647,9 @@
if (!card)
return cnt;
+ if (!access_ok(VERIFY_READ, ubuf, cnt))
+ return cnt;
+
bkops_stats = &card->bkops_info.bkops_stats;
sscanf(ubuf, "%d", &value);
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index edd6a5d..c7fa876 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -78,7 +78,7 @@
struct mmc_host *host = cls_dev_to_mmc_host(dev);
int ret = 0;
- if (!mmc_use_core_runtime_pm(host))
+ if (!mmc_use_core_pm(host))
return 0;
if (!pm_runtime_suspended(dev)) {
@@ -95,7 +95,7 @@
struct mmc_host *host = cls_dev_to_mmc_host(dev);
int ret = 0;
- if (!mmc_use_core_runtime_pm(host))
+ if (!mmc_use_core_pm(host))
return 0;
if (!pm_runtime_suspended(dev)) {
@@ -686,14 +686,13 @@
WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) &&
!host->ops->enable_sdio_irq);
- if (mmc_use_core_runtime_pm(host)) {
- err = pm_runtime_set_active(&host->class_dev);
- if (err)
- pr_err("%s: %s: failed setting runtime active: err: %d\n",
- mmc_hostname(host), __func__, err);
- else
- pm_runtime_enable(&host->class_dev);
- }
+ err = pm_runtime_set_active(&host->class_dev);
+ if (err)
+ pr_err("%s: %s: failed setting runtime active: err: %d\n",
+ mmc_hostname(host), __func__, err);
+ else if (mmc_use_core_runtime_pm(host))
+ pm_runtime_enable(&host->class_dev);
+
err = device_add(&host->class_dev);
if (err)
return err;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 997e14b..b295bb8 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1189,9 +1189,9 @@
mmc_set_timing(card->host, MMC_TIMING_LEGACY);
mmc_set_clock(card->host, MMC_HIGH_26_MAX_DTR);
- err = mmc_select_hs(card, &card->cached_ext_csd);
+ err = mmc_select_hs(card, card->cached_ext_csd);
} else {
- err = mmc_select_hs400(card, &card->cached_ext_csd);
+ err = mmc_select_hs400(card, card->cached_ext_csd);
}
return err;
@@ -1439,7 +1439,7 @@
err = mmc_get_ext_csd(card, &ext_csd);
if (err)
goto free_card;
- memcpy(&card->cached_ext_csd, ext_csd, sizeof(card->ext_csd));
+ card->cached_ext_csd = ext_csd;
err = mmc_read_ext_csd(card, ext_csd);
if (err)
goto free_card;
@@ -1637,15 +1637,12 @@
if (!oldcard)
host->card = card;
- mmc_free_ext_csd(ext_csd);
return 0;
free_card:
if (!oldcard)
mmc_remove_card(card);
err:
- mmc_free_ext_csd(ext_csd);
-
return err;
}
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 95f0a04..c335be1 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -6962,7 +6962,7 @@
static const struct of_device_id msmsdcc_dt_match[] = {
{.compatible = "qcom,msm-sdcc"},
-
+ { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index b93eaf4..4d3a560 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -317,6 +317,7 @@
bool tuning_done;
bool calibration_done;
u8 saved_tuning_phase;
+ atomic_t controller_clock;
};
enum vdd_io_level {
@@ -2213,6 +2214,50 @@
return sel_clk;
}
+static int sdhci_msm_enable_controller_clock(struct sdhci_host *host)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ int rc = 0;
+
+ if (atomic_read(&msm_host->controller_clock))
+ return 0;
+
+ sdhci_msm_bus_voting(host, 1);
+
+ if (!IS_ERR(msm_host->pclk)) {
+ rc = clk_prepare_enable(msm_host->pclk);
+ if (rc) {
+ pr_err("%s: %s: failed to enable the pclk with error %d\n",
+ mmc_hostname(host->mmc), __func__, rc);
+ goto remove_vote;
+ }
+ }
+
+ rc = clk_prepare_enable(msm_host->clk);
+ if (rc) {
+ pr_err("%s: %s: failed to enable the host-clk with error %d\n",
+ mmc_hostname(host->mmc), __func__, rc);
+ goto disable_pclk;
+ }
+
+ atomic_set(&msm_host->controller_clock, 1);
+ pr_debug("%s: %s: enabled controller clock\n",
+ mmc_hostname(host->mmc), __func__);
+ goto out;
+
+disable_pclk:
+ if (!IS_ERR(msm_host->pclk))
+ clk_disable_unprepare(msm_host->pclk);
+remove_vote:
+ if (msm_host->msm_bus_vote.client_handle)
+ sdhci_msm_bus_cancel_work_and_set_vote(host, 0);
+out:
+ return rc;
+}
+
+
+
static int sdhci_msm_prepare_clocks(struct sdhci_host *host, bool enable)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -2223,36 +2268,32 @@
pr_debug("%s: request to enable clocks\n",
mmc_hostname(host->mmc));
- sdhci_msm_bus_voting(host, 1);
+ /*
+ * The bus-width or the clock rate might have changed
+ * after controller clocks are enbaled, update bus vote
+ * in such case.
+ */
+ if (atomic_read(&msm_host->controller_clock))
+ sdhci_msm_bus_voting(host, 1);
+
+ rc = sdhci_msm_enable_controller_clock(host);
+ if (rc)
+ goto remove_vote;
if (!IS_ERR_OR_NULL(msm_host->bus_clk)) {
rc = clk_prepare_enable(msm_host->bus_clk);
if (rc) {
pr_err("%s: %s: failed to enable the bus-clock with error %d\n",
mmc_hostname(host->mmc), __func__, rc);
- goto remove_vote;
+ goto disable_controller_clk;
}
}
- if (!IS_ERR(msm_host->pclk)) {
- rc = clk_prepare_enable(msm_host->pclk);
- if (rc) {
- pr_err("%s: %s: failed to enable the pclk with error %d\n",
- mmc_hostname(host->mmc), __func__, rc);
- goto disable_bus_clk;
- }
- }
- rc = clk_prepare_enable(msm_host->clk);
- if (rc) {
- pr_err("%s: %s: failed to enable the host-clk with error %d\n",
- mmc_hostname(host->mmc), __func__, rc);
- goto disable_pclk;
- }
if (!IS_ERR(msm_host->ff_clk)) {
rc = clk_prepare_enable(msm_host->ff_clk);
if (rc) {
pr_err("%s: %s: failed to enable the ff_clk with error %d\n",
mmc_hostname(host->mmc), __func__, rc);
- goto disable_clk;
+ goto disable_bus_clk;
}
}
if (!IS_ERR(msm_host->sleep_clk)) {
@@ -2280,6 +2321,7 @@
if (!IS_ERR_OR_NULL(msm_host->bus_clk))
clk_disable_unprepare(msm_host->bus_clk);
+ atomic_set(&msm_host->controller_clock, 0);
sdhci_msm_bus_voting(host, 0);
}
atomic_set(&msm_host->clks_on, enable);
@@ -2287,15 +2329,15 @@
disable_ff_clk:
if (!IS_ERR_OR_NULL(msm_host->ff_clk))
clk_disable_unprepare(msm_host->ff_clk);
-disable_clk:
- if (!IS_ERR_OR_NULL(msm_host->clk))
- clk_disable_unprepare(msm_host->clk);
-disable_pclk:
- if (!IS_ERR_OR_NULL(msm_host->pclk))
- clk_disable_unprepare(msm_host->pclk);
disable_bus_clk:
if (!IS_ERR_OR_NULL(msm_host->bus_clk))
clk_disable_unprepare(msm_host->bus_clk);
+disable_controller_clk:
+ if (!IS_ERR_OR_NULL(msm_host->clk))
+ clk_disable_unprepare(msm_host->clk);
+ if (!IS_ERR_OR_NULL(msm_host->pclk))
+ clk_disable_unprepare(msm_host->pclk);
+ atomic_set(&msm_host->controller_clock, 0);
remove_vote:
if (msm_host->msm_bus_vote.client_handle)
sdhci_msm_bus_cancel_work_and_set_vote(host, 0);
@@ -2558,6 +2600,7 @@
.get_min_clock = sdhci_msm_get_min_clock,
.get_max_clock = sdhci_msm_get_max_clock,
.disable_data_xfer = sdhci_msm_disable_data_xfer,
+ .enable_controller_clock = sdhci_msm_enable_controller_clock,
};
static int __devinit sdhci_msm_probe(struct platform_device *pdev)
@@ -2637,6 +2680,7 @@
if (ret)
goto bus_clk_disable;
}
+ atomic_set(&msm_host->controller_clock, 1);
/* Setup SDC MMC clock */
msm_host->clk = devm_clk_get(&pdev->dev, "core_clk");
@@ -2840,6 +2884,7 @@
msm_host->mmc->caps2 |= MMC_CAP2_CLK_SCALE;
msm_host->mmc->caps2 |= MMC_CAP2_STOP_REQUEST;
msm_host->mmc->caps2 |= MMC_CAP2_ASYNC_SDIO_IRQ_4BIT_MODE;
+ msm_host->mmc->caps2 |= MMC_CAP2_CORE_PM;
msm_host->mmc->pm_caps |= MMC_PM_KEEP_POWER;
if (msm_host->pdata->nonremovable)
@@ -2896,7 +2941,7 @@
if (ret)
pr_err("%s: %s: pm_runtime_set_active failed: err: %d\n",
mmc_hostname(host->mmc), __func__, ret);
- else
+ else if (mmc_use_core_runtime_pm(host->mmc))
pm_runtime_enable(&pdev->dev);
/* Successful initialization */
@@ -3068,6 +3113,7 @@
#endif
static const struct of_device_id sdhci_msm_dt_match[] = {
{.compatible = "qcom,sdhci-msm"},
+ { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, sdhci_msm_dt_match);
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 758a79e..24b7d04 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -27,6 +27,7 @@
#include <linux/mmc/mmc.h>
#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
#include "sdhci.h"
@@ -1570,6 +1571,7 @@
unsigned long flags;
int vdd_bit = -1;
u8 ctrl;
+ int ret;
mutex_lock(&host->ios_mutex);
if (host->flags & SDHCI_DEVICE_DEAD) {
@@ -1582,6 +1584,29 @@
if (ios->clock)
sdhci_set_clock(host, ios->clock);
+ /*
+ * The controller clocks may be off during power-up and we may end up
+ * enabling card clock before giving power to the card. Hence, during
+ * MMC_POWER_UP enable the controller clock and turn-on the regulators.
+ * The mmc_power_up would provide the necessary delay before turning on
+ * the clocks to the card.
+ */
+ if (ios->power_mode & MMC_POWER_UP) {
+ if (host->ops->enable_controller_clock) {
+ ret = host->ops->enable_controller_clock(host);
+ if (ret) {
+ pr_err("%s: enabling controller clock: failed: %d\n",
+ mmc_hostname(host->mmc), ret);
+ } else {
+ vdd_bit = sdhci_set_power(host, ios->vdd);
+
+ if (host->vmmc && vdd_bit != -1)
+ mmc_regulator_set_ocr(host->mmc,
+ host->vmmc,
+ vdd_bit);
+ }
+ }
+ }
spin_lock_irqsave(&host->lock, flags);
if (!host->clock) {
spin_unlock_irqrestore(&host->lock, flags);
@@ -1590,14 +1615,16 @@
}
spin_unlock_irqrestore(&host->lock, flags);
- if (ios->power_mode & (MMC_POWER_UP | MMC_POWER_ON))
+ if (!host->ops->enable_controller_clock && (ios->power_mode &
+ (MMC_POWER_UP |
+ MMC_POWER_ON))) {
vdd_bit = sdhci_set_power(host, ios->vdd);
- if (host->vmmc && vdd_bit != -1)
- mmc_regulator_set_ocr(host->mmc, host->vmmc, vdd_bit);
+ if (host->vmmc && vdd_bit != -1)
+ mmc_regulator_set_ocr(host->mmc, host->vmmc, vdd_bit);
+ }
spin_lock_irqsave(&host->lock, flags);
-
if (host->ops->platform_send_init_74_clocks)
host->ops->platform_send_init_74_clocks(host, ios->power_mode);
@@ -2223,10 +2250,13 @@
struct sdhci_host *host = mmc_priv(mmc);
unsigned long flags;
struct mmc_data *data;
+ int ret = 0;
spin_lock_irqsave(&host->lock, flags);
- if (!host->mrq || !host->data)
+ if (!host->mrq || !host->data) {
+ ret = MMC_BLK_NO_REQ_TO_STOP;
goto out;
+ }
data = host->data;
@@ -2252,7 +2282,7 @@
host->data = NULL;
out:
spin_unlock_irqrestore(&host->lock, flags);
- return 0;
+ return ret;
}
static unsigned int sdhci_get_xfer_remain(struct mmc_host *mmc)
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 3db99c4..db4806d 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -295,6 +295,7 @@
unsigned int (*get_max_segments)(void);
void (*platform_bus_voting)(struct sdhci_host *host, u32 enable);
void (*disable_data_xfer)(struct sdhci_host *host);
+ int (*enable_controller_clock)(struct sdhci_host *host);
};
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
diff --git a/drivers/mtd/devices/msm_qpic_nand.c b/drivers/mtd/devices/msm_qpic_nand.c
index 7f02187..2e06b42 100644
--- a/drivers/mtd/devices/msm_qpic_nand.c
+++ b/drivers/mtd/devices/msm_qpic_nand.c
@@ -1919,7 +1919,7 @@
buf = (uint8_t *)dma_buffer + sizeof(*dma_buffer);
cmd = dma_buffer->cmd;
- memset(&data, 0, sizeof(struct msm_nand_erase_reg_data));
+ memset(&data, 0, sizeof(struct msm_nand_blk_isbad_data));
data.cfg.cmd = MSM_NAND_CMD_PAGE_READ_ALL;
data.cfg.cfg0 = chip->cfg0_raw & ~(7U << CW_PER_PAGE);
data.cfg.cfg1 = chip->cfg1_raw;
diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c
index 10dea37..bd4ecf3 100644
--- a/drivers/net/wireless/ath/regd.c
+++ b/drivers/net/wireless/ath/regd.c
@@ -520,6 +520,7 @@
*/
regd = ath_world_regdomain(reg);
wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
+ wiphy->country_ie_pref = NL80211_COUNTRY_IE_FOLLOW_POWER;
} else {
/*
* This gets applied in the case of the absence of CRDA,
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 8dc30ee..68819a6 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -45,11 +45,13 @@
#endif
#define DEVICE "wcnss_wlan"
+#define CTRL_DEVICE "wcnss_ctrl"
#define VERSION "1.01"
#define WCNSS_PIL_DEVICE "wcnss"
/* module params */
#define WCNSS_CONFIG_UNSPECIFIED (-1)
+#define UINT32_MAX (0xFFFFFFFFU)
static int has_48mhz_xo = WCNSS_CONFIG_UNSPECIFIED;
module_param(has_48mhz_xo, int, S_IWUSR | S_IRUGO);
@@ -142,6 +144,7 @@
#define MSM_PRONTO_PLL_BASE 0xfb21b1c0
#define PRONTO_PLL_STATUS_OFFSET 0x1c
+#define MSM_PRONTO_TXP_STATUS 0xfb08040c
#define MSM_PRONTO_TXP_PHY_ABORT 0xfb080488
#define MSM_PRONTO_BRDG_ERR_SRC 0xfb080fb0
@@ -154,6 +157,15 @@
#define WCNSS_CTRL_CHANNEL "WCNSS_CTRL"
#define WCNSS_MAX_FRAME_SIZE (4*1024)
#define WCNSS_VERSION_LEN 30
+#define WCNSS_MAX_BUILD_VER_LEN 256
+#define WCNSS_MAX_CMD_LEN (128)
+#define WCNSS_MIN_CMD_LEN (3)
+#define WCNSS_MIN_SERIAL_LEN (6)
+
+/* control messages from userspace */
+#define WCNSS_USR_CTRL_MSG_START 0x00000000
+#define WCNSS_USR_SERIAL_NUM (WCNSS_USR_CTRL_MSG_START + 1)
+#define WCNSS_USR_HAS_CAL_DATA (WCNSS_USR_CTRL_MSG_START + 2)
/* message types */
#define WCNSS_CTRL_MSG_START 0x01000000
@@ -166,7 +178,11 @@
#define WCNSS_CALDATA_DNLD_REQ (WCNSS_CTRL_MSG_START + 6)
#define WCNSS_CALDATA_DNLD_RSP (WCNSS_CTRL_MSG_START + 7)
#define WCNSS_VBATT_LEVEL_IND (WCNSS_CTRL_MSG_START + 8)
+#define WCNSS_BUILD_VER_REQ (WCNSS_CTRL_MSG_START + 9)
+#define WCNSS_BUILD_VER_RSP (WCNSS_CTRL_MSG_START + 10)
+/* max 20mhz channel count */
+#define WCNSS_MAX_CH_NUM 45
#define VALID_VERSION(version) \
((strncmp(version, "INVALID", WCNSS_VERSION_LEN)) ? 1 : 0)
@@ -339,10 +355,10 @@
void __iomem *pronto_ccpu_base;
void __iomem *pronto_saw2_base;
void __iomem *pronto_pll_base;
+ void __iomem *wlan_tx_status;
void __iomem *wlan_tx_phy_aborts;
void __iomem *wlan_brdg_err_source;
void __iomem *fiq_reg;
- int ssr_boot;
int nv_downloaded;
unsigned char *fw_cal_data;
unsigned char *user_cal_data;
@@ -351,16 +367,20 @@
int fw_cal_available;
int user_cal_read;
int user_cal_available;
- int user_cal_rcvd;
+ u32 user_cal_rcvd;
int user_cal_exp_size;
int device_opened;
int iris_xo_mode_set;
int fw_vbatt_state;
+ int ctrl_device_opened;
struct mutex dev_lock;
+ struct mutex ctrl_lock;
wait_queue_head_t read_wait;
struct qpnp_adc_tm_btm_param vbat_monitor_params;
struct qpnp_adc_tm_chip *adc_tm_dev;
struct mutex vbat_monitor_mutex;
+ u16 unsafe_ch_count;
+ u16 unsafe_ch_list[WCNSS_MAX_CH_NUM];
} *penv = NULL;
static ssize_t wcnss_serial_number_show(struct device *dev,
@@ -515,6 +535,10 @@
pr_info_ratelimited("%s: PRONTO_PMU_SOFT_RESET %08x\n",
__func__, reg);
+ reg_addr = penv->pronto_saw2_base + PRONTO_SAW2_SPM_STS_OFFSET;
+ reg = readl_relaxed(reg_addr);
+ pr_info_ratelimited("%s: PRONTO_SAW2_SPM_STS %08x\n", __func__, reg);
+
reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_GDSCR_OFFSET;
reg = readl_relaxed(reg_addr);
pr_info_ratelimited("%s: PRONTO_PMU_COM_GDSCR %08x\n",
@@ -563,10 +587,6 @@
reg = readl_relaxed(reg_addr);
pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR2 %08x\n", __func__, reg);
- reg_addr = penv->pronto_saw2_base + PRONTO_SAW2_SPM_STS_OFFSET;
- reg = readl_relaxed(reg_addr);
- pr_info_ratelimited("%s: PRONTO_SAW2_SPM_STS %08x\n", __func__, reg);
-
reg_addr = penv->pronto_pll_base + PRONTO_PLL_STATUS_OFFSET;
reg = readl_relaxed(reg_addr);
pr_info_ratelimited("%s: PRONTO_PLL_STATUS %08x\n", __func__, reg);
@@ -664,6 +684,8 @@
reg = readl_relaxed(penv->wlan_brdg_err_source);
pr_info_ratelimited("%s: WLAN_BRDG_ERR_SOURCE %08x\n", __func__, reg);
+ reg = readl_relaxed(penv->wlan_tx_status);
+ pr_info_ratelimited("%s: WLAN_TX_STATUS %08x\n", __func__, reg);
}
EXPORT_SYMBOL(wcnss_pronto_log_debug_regs);
@@ -755,8 +777,6 @@
case SMD_EVENT_CLOSE:
pr_debug("wcnss: closing WCNSS SMD channel :%s",
WCNSS_CTRL_CHANNEL);
- /* This SMD is closed only during SSR */
- penv->ssr_boot = true;
penv->nv_downloaded = 0;
break;
@@ -1161,6 +1181,35 @@
}
EXPORT_SYMBOL(wcnss_get_wlan_rx_buff_count);
+int wcnss_set_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 ch_count)
+{
+ if (penv && unsafe_ch_list &&
+ (ch_count <= WCNSS_MAX_CH_NUM)) {
+ memcpy((char *)penv->unsafe_ch_list,
+ (char *)unsafe_ch_list, ch_count * sizeof(u16));
+ penv->unsafe_ch_count = ch_count;
+ return 0;
+ } else
+ return -ENODEV;
+}
+EXPORT_SYMBOL(wcnss_set_wlan_unsafe_channel);
+
+int wcnss_get_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 buffer_size,
+ u16 *ch_count)
+{
+ if (penv) {
+ if (buffer_size < penv->unsafe_ch_count * sizeof(u16))
+ return -ENODEV;
+ memcpy((char *)unsafe_ch_list,
+ (char *)penv->unsafe_ch_list,
+ penv->unsafe_ch_count * sizeof(u16));
+ *ch_count = penv->unsafe_ch_count;
+ return 0;
+ } else
+ return -ENODEV;
+}
+EXPORT_SYMBOL(wcnss_get_wlan_unsafe_channel);
+
static int wcnss_smd_tx(void *data, int len)
{
int ret = 0;
@@ -1348,6 +1397,17 @@
goto exit;
}
+ if (penv->fw_cal_available) {
+ /* ignore cal upload from SSR */
+ smd_read(penv->smd_ch, NULL, calhdr.frag_size);
+ penv->fw_cal_exp_frag++;
+ if (calhdr.msg_flags & LAST_FRAGMENT) {
+ penv->fw_cal_exp_frag = 0;
+ goto exit;
+ }
+ return;
+ }
+
if (0 == calhdr.frag_number) {
if (calhdr.total_size > MAX_CALIBRATED_DATA_SIZE) {
pr_err("wcnss: Invalid cal data size %d",
@@ -1411,7 +1471,9 @@
int len = 0;
int rc = 0;
unsigned char buf[sizeof(struct wcnss_version)];
+ unsigned char build[WCNSS_MAX_BUILD_VER_LEN+1];
struct smd_msg_hdr *phdr;
+ struct smd_msg_hdr smd_msg;
struct wcnss_version *pversion;
int hw_type;
unsigned char fw_status = 0;
@@ -1468,6 +1530,12 @@
break;
case WCNSS_PRONTO_HW:
+ smd_msg.msg_type = WCNSS_BUILD_VER_REQ;
+ 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__);
+
/* 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");
@@ -1482,6 +1550,21 @@
}
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);
+ return;
+ }
+ rc = smd_read(penv->smd_ch, build, len);
+ if (rc < len) {
+ pr_err("wcnss: incomplete data read from smd\n");
+ return;
+ }
+ build[len] = 0;
+ pr_info("wcnss: build version %s\n", build);
+ break;
+
case WCNSS_NVBIN_DNLD_RSP:
penv->nv_downloaded = true;
fw_status = wcnss_fw_status();
@@ -1498,7 +1581,6 @@
break;
case WCNSS_CALDATA_UPLD_REQ:
- penv->fw_cal_available = 0;
extract_cal_data(len);
break;
@@ -1748,21 +1830,12 @@
while (!penv->user_cal_available && retry++ < 5)
msleep(500);
}
-
- /* only cal data is sent during ssr (if available) */
- if (penv->fw_cal_available && penv->ssr_boot) {
- pr_info_ratelimited("wcnss: cal download during SSR, using fw cal");
- wcnss_caldata_dnld(penv->fw_cal_data, penv->fw_cal_rcvd, false);
- return;
-
- } else if (penv->user_cal_available && penv->ssr_boot) {
- pr_info_ratelimited("wcnss: cal download during SSR, using user cal");
- wcnss_caldata_dnld(penv->user_cal_data,
- penv->user_cal_rcvd, false);
- return;
+ if (penv->fw_cal_available) {
+ pr_info_ratelimited("wcnss: 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 during cold boot, using user cal");
+ pr_info_ratelimited("wcnss: cal download, using user cal");
wcnss_caldata_dnld(penv->user_cal_data,
penv->user_cal_rcvd, true);
}
@@ -1794,6 +1867,80 @@
.notifier_call = wcnss_pm_notify,
};
+static int wcnss_ctrl_open(struct inode *inode, struct file *file)
+{
+ int rc = 0;
+
+ if (!penv || penv->ctrl_device_opened)
+ return -EFAULT;
+
+ penv->ctrl_device_opened = 1;
+
+ return rc;
+}
+
+
+void process_usr_ctrl_cmd(u8 *buf, size_t len)
+{
+ u16 cmd = buf[0] << 8 | buf[1];
+
+ switch (cmd) {
+
+ case WCNSS_USR_SERIAL_NUM:
+ if (WCNSS_MIN_SERIAL_LEN > len) {
+ pr_err("%s: Invalid serial number\n", __func__);
+ return;
+ }
+ penv->serial_number = buf[2] << 24 | buf[3] << 16
+ | buf[4] << 8 | buf[5];
+ break;
+
+ case WCNSS_USR_HAS_CAL_DATA:
+ if (1 < buf[2])
+ pr_err("%s: Invalid data for cal %d\n", __func__,
+ buf[2]);
+ has_calibrated_data = buf[2];
+ break;
+
+ default:
+ pr_err("%s: Invalid command %d\n", __func__, cmd);
+ break;
+ }
+}
+
+static ssize_t wcnss_ctrl_write(struct file *fp, const char __user
+ *user_buffer, size_t count, loff_t *position)
+{
+ int rc = 0;
+ u8 buf[WCNSS_MAX_CMD_LEN];
+
+ if (!penv || !penv->ctrl_device_opened || WCNSS_MAX_CMD_LEN < count
+ || WCNSS_MIN_CMD_LEN > count)
+ return -EFAULT;
+
+ mutex_lock(&penv->ctrl_lock);
+ rc = copy_from_user(buf, user_buffer, count);
+ if (0 == rc)
+ process_usr_ctrl_cmd(buf, count);
+
+ mutex_unlock(&penv->ctrl_lock);
+
+ return rc;
+}
+
+
+static const struct file_operations wcnss_ctrl_fops = {
+ .owner = THIS_MODULE,
+ .open = wcnss_ctrl_open,
+ .write = wcnss_ctrl_write,
+};
+
+static struct miscdevice wcnss_usr_ctrl = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = CTRL_DEVICE,
+ .fops = &wcnss_ctrl_fops,
+};
+
static int
wcnss_trigger_config(struct platform_device *pdev)
{
@@ -1965,7 +2112,12 @@
pr_err("%s: ioremap wlan BRDG ERR failed\n", __func__);
goto fail_ioremap8;
}
-
+ penv->wlan_tx_status = ioremap(MSM_PRONTO_TXP_STATUS, SZ_8);
+ if (!penv->wlan_tx_status) {
+ ret = -ENOMEM;
+ pr_err("%s: ioremap wlan TX STATUS failed\n", __func__);
+ goto fail_ioremap9;
+ }
}
penv->adc_tm_dev = qpnp_get_adc_tm(&penv->pdev->dev, "wcnss");
if (IS_ERR(penv->adc_tm_dev)) {
@@ -1991,6 +2143,9 @@
fail_pil:
if (penv->riva_ccu_base)
iounmap(penv->riva_ccu_base);
+ if (penv->wlan_tx_status)
+ iounmap(penv->wlan_tx_status);
+fail_ioremap9:
if (penv->wlan_brdg_err_source)
iounmap(penv->wlan_brdg_err_source);
fail_ioremap8:
@@ -2098,7 +2253,7 @@
*user_buffer, size_t count, loff_t *position)
{
int rc = 0;
- int size = 0;
+ size_t size = 0;
if (!penv || !penv->device_opened || penv->user_cal_available)
return -EFAULT;
@@ -2106,7 +2261,7 @@
if (penv->user_cal_rcvd == 0 && count >= 4
&& !penv->user_cal_data) {
rc = copy_from_user((void *)&size, user_buffer, 4);
- if (size > MAX_CALIBRATED_DATA_SIZE) {
+ if (!size || size > MAX_CALIBRATED_DATA_SIZE) {
pr_err(DEVICE " invalid size to write %d\n", size);
return -EFAULT;
}
@@ -2125,7 +2280,8 @@
} else if (penv->user_cal_rcvd == 0 && count < 4)
return -EFAULT;
- if (MAX_CALIBRATED_DATA_SIZE < count + penv->user_cal_rcvd) {
+ if ((UINT32_MAX - count < penv->user_cal_rcvd) ||
+ MAX_CALIBRATED_DATA_SIZE < count + penv->user_cal_rcvd) {
pr_err(DEVICE " invalid size to write %d\n", count +
penv->user_cal_rcvd);
rc = -ENOMEM;
@@ -2187,6 +2343,7 @@
}
mutex_init(&penv->dev_lock);
+ mutex_init(&penv->ctrl_lock);
mutex_init(&penv->vbat_monitor_mutex);
init_waitqueue_head(&penv->read_wait);
@@ -2199,6 +2356,9 @@
* place
*/
pr_info(DEVICE " probed in built-in mode\n");
+
+ misc_register(&wcnss_usr_ctrl);
+
return misc_register(&wcnss_misc);
}
diff --git a/drivers/nfc/nfc-nci.c b/drivers/nfc/nfc-nci.c
index 043f9bc..99e17a6 100644
--- a/drivers/nfc/nfc-nci.c
+++ b/drivers/nfc/nfc-nci.c
@@ -757,7 +757,8 @@
r = of_property_read_string(np, "qcom,clk-src", &pdata->clk_src);
- if (!strcmp(pdata->clk_src, "GPCLK"))
+ if ((!strcmp(pdata->clk_src, "GPCLK")) ||
+ (!strcmp(pdata->clk_src, "GPCLK2")))
pdata->clk_src_gpio = of_get_named_gpio(np,
"qcom,clk-en-gpio", 0);
@@ -874,6 +875,14 @@
} else {
goto err_dis_gpio;
}
+ } else if (!strcmp(platform_data->clk_src, "GPCLK2")) {
+ if (gpio_is_valid(platform_data->clk_src_gpio)) {
+ nfc_clk = clk_get(&client->dev, "core_clk_pvt");
+ if (nfc_clk == NULL)
+ goto err_dis_gpio;
+ } else {
+ goto err_dis_gpio;
+ }
} else {
nfc_clk = NULL;
}
@@ -974,7 +983,8 @@
r = gpio_direction_input(platform_data->dis_gpio);
if (r)
dev_err(&client->dev, "nfc-nci probe: Unable to set direction\n");
- if (!strcmp(platform_data->clk_src, "GPCLK")) {
+ if ((!strcmp(platform_data->clk_src, "GPCLK")) ||
+ (!strcmp(platform_data->clk_src, "GPCLK2"))) {
r = gpio_direction_input(platform_data->clk_src_gpio);
if (r)
dev_err(&client->dev, "nfc-nci probe: Unable to set direction\n");
diff --git a/drivers/of/of_batterydata.c b/drivers/of/of_batterydata.c
index b0d40f1..32aae74 100644
--- a/drivers/of/of_batterydata.c
+++ b/drivers/of/of_batterydata.c
@@ -228,7 +228,7 @@
OF_PROP_READ(batt_data->rbatt_capacitive_mohm,
"rbatt-capacitive-mohm", node, rc, false);
OF_PROP_READ(batt_data->flat_ocv_threshold_uv,
- "flat-ocv-threshold", node, rc, true);
+ "flat-ocv-threshold-uv", node, rc, true);
OF_PROP_READ(batt_data->max_voltage_uv,
"max-voltage-uv", node, rc, true);
OF_PROP_READ(batt_data->cutoff_uv, "v-cutoff-uv", node, rc, true);
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index 5f0ba94..9ccb993 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -327,10 +327,9 @@
for(; lookup->compatible != NULL; lookup++) {
if (!of_device_is_compatible(np, lookup->compatible))
continue;
- if (of_address_to_resource(np, 0, &res))
- continue;
- if (res.start != lookup->phys_addr)
- continue;
+ if (!of_address_to_resource(np, 0, &res))
+ if (res.start != lookup->phys_addr)
+ continue;
pr_debug("%s: devname=%s\n", np->full_name, lookup->name);
return lookup;
}
diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c
index 6a16cf3..1ef1f1b 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -963,7 +963,7 @@
enum ipa_pipe_mem_type mem_type;
if (!pipe_connection || !node)
- goto err;
+ return -EINVAL;
key = "qcom,src-bam-physical-address";
rc = of_property_read_u32(node, key, &val);
diff --git a/drivers/platform/msm/ipa/ipa_flt.c b/drivers/platform/msm/ipa/ipa_flt.c
index 2d75141..c3db716 100644
--- a/drivers/platform/msm/ipa/ipa_flt.c
+++ b/drivers/platform/msm/ipa/ipa_flt.c
@@ -802,8 +802,11 @@
IPADBG("reset flt ip=%d\n", ip);
list_for_each_entry_safe(entry, next, &tbl->head_flt_rule_list, link) {
node = ipa_search(&ipa_ctx->flt_rule_hdl_tree, (u32)entry);
- if (node == NULL)
+ if (node == NULL) {
WARN_ON(1);
+ mutex_unlock(&ipa_ctx->lock);
+ return -EFAULT;
+ }
if ((ip == IPA_IP_v4 &&
entry->rule.attrib.attrib_mask == IPA_FLT_PROTOCOL &&
@@ -833,8 +836,11 @@
link) {
node = ipa_search(&ipa_ctx->flt_rule_hdl_tree,
(u32)entry);
- if (node == NULL)
+ if (node == NULL) {
WARN_ON(1);
+ mutex_unlock(&ipa_ctx->lock);
+ return -EFAULT;
+ }
list_del(&entry->link);
entry->tbl->rule_cnt--;
if (entry->rt_tbl)
diff --git a/drivers/platform/msm/ipa/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_hdr.c
index 9618da2..54cbf5f 100644
--- a/drivers/platform/msm/ipa/ipa_hdr.c
+++ b/drivers/platform/msm/ipa/ipa_hdr.c
@@ -450,8 +450,11 @@
continue;
node = ipa_search(&ipa_ctx->hdr_hdl_tree, (u32) entry);
- if (node == NULL)
+ if (node == NULL) {
WARN_ON(1);
+ mutex_unlock(&ipa_ctx->lock);
+ return -EFAULT;
+ }
list_del(&entry->link);
entry->cookie = 0;
kmem_cache_free(ipa_ctx->hdr_cache, entry);
diff --git a/drivers/platform/msm/ipa/ipa_rt.c b/drivers/platform/msm/ipa/ipa_rt.c
index 8d6d5e6..f453010 100644
--- a/drivers/platform/msm/ipa/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_rt.c
@@ -843,8 +843,11 @@
&tbl->head_rt_rule_list, link) {
node = ipa_search(&ipa_ctx->rt_rule_hdl_tree,
(u32)rule);
- if (node == NULL)
+ if (node == NULL) {
WARN_ON(1);
+ mutex_unlock(&ipa_ctx->lock);
+ return -EFAULT;
+ }
/*
* for the "default" routing tbl, remove all but the
@@ -866,8 +869,11 @@
}
node = ipa_search(&ipa_ctx->rt_tbl_hdl_tree, (u32)tbl);
- if (node == NULL)
+ if (node == NULL) {
WARN_ON(1);
+ mutex_unlock(&ipa_ctx->lock);
+ return -EFAULT;
+ }
/* do not remove the "default" routing tbl which has index 0 */
if (tbl->idx != 0) {
diff --git a/drivers/platform/msm/ipa/teth_bridge.c b/drivers/platform/msm/ipa/teth_bridge.c
index b3a6b17..79ec0c0 100644
--- a/drivers/platform/msm/ipa/teth_bridge.c
+++ b/drivers/platform/msm/ipa/teth_bridge.c
@@ -1780,7 +1780,7 @@
break;
}
- if (caps.num_protocols < teth_ctx->aggr_caps->num_protocols) {
+ if (caps.num_protocols != teth_ctx->aggr_caps->num_protocols) {
caps.num_protocols = teth_ctx->aggr_caps->num_protocols;
if (copy_to_user((struct teth_aggr_capabilities *)arg,
&caps,
diff --git a/drivers/platform/msm/qpnp-clkdiv.c b/drivers/platform/msm/qpnp-clkdiv.c
index c55ed09..696c84f 100644
--- a/drivers/platform/msm/qpnp-clkdiv.c
+++ b/drivers/platform/msm/qpnp-clkdiv.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -202,6 +202,7 @@
if (!res) {
dev_err(&spmi->dev, "%s: unable to get device reg resource\n",
__func__);
+ return -EINVAL;
}
q_clkdiv->slave = spmi->sid;
diff --git a/drivers/platform/msm/qpnp-power-on.c b/drivers/platform/msm/qpnp-power-on.c
index 50d5f7b..507d02c 100644
--- a/drivers/platform/msm/qpnp-power-on.c
+++ b/drivers/platform/msm/qpnp-power-on.c
@@ -50,6 +50,8 @@
#define QPNP_PON_KPDPWR_RESIN_S2_CNTL2(base) (base + 0x4B)
#define QPNP_PON_PS_HOLD_RST_CTL(base) (base + 0x5A)
#define QPNP_PON_PS_HOLD_RST_CTL2(base) (base + 0x5B)
+#define QPNP_PON_WD_RST_S2_CTL(base) (base + 0x56)
+#define QPNP_PON_WD_RST_S2_CTL2(base) (base + 0x57)
#define QPNP_PON_TRIGGER_EN(base) (base + 0x80)
#define QPNP_PON_S3_DBC_CTL(base) (base + 0x75)
@@ -73,6 +75,7 @@
#define QPNP_PON_RESIN_BARK_N_SET BIT(4)
#define QPNP_PON_KPDPWR_RESIN_BARK_N_SET BIT(5)
+#define QPNP_PON_WD_EN BIT(7)
#define QPNP_PON_RESET_EN BIT(7)
#define QPNP_PON_POWER_OFF_MASK 0xF
@@ -270,6 +273,32 @@
EXPORT_SYMBOL(qpnp_pon_is_warm_reset);
/**
+ * qpnp_pon_wd_config - Disable the wd in a warm reset.
+ * @enable: to enable or disable the PON watch dog
+ *
+ * Returns = 0 for operate successfully, < 0 for errors
+ */
+int qpnp_pon_wd_config(bool enable)
+{
+ struct qpnp_pon *pon = sys_reset_dev;
+ int rc = 0;
+
+ if (!pon)
+ return -EPROBE_DEFER;
+
+ rc = qpnp_pon_masked_write(pon, QPNP_PON_WD_RST_S2_CTL2(pon->base),
+ QPNP_PON_WD_EN, enable ? QPNP_PON_WD_EN : 0);
+ if (rc)
+ dev_err(&pon->spmi->dev,
+ "Unable to write to addr=%x, rc(%d)\n",
+ QPNP_PON_WD_RST_S2_CTL2(pon->base), rc);
+
+ return rc;
+}
+EXPORT_SYMBOL(qpnp_pon_wd_config);
+
+
+/**
* qpnp_pon_trigger_config - Configures (enable/disable) the PON trigger source
* @pon_src: PON source to be configured
* @enable: to enable or disable the PON trigger
@@ -705,6 +734,8 @@
pon->pon_input->phys = "qpnp_pon/input0";
}
+ /* don't send dummy release event when system resumes */
+ __set_bit(INPUT_PROP_NO_DUMMY_RELEASE, pon->pon_input->propbit);
input_set_capability(pon->pon_input, EV_KEY, cfg->key_code);
return 0;
@@ -1116,8 +1147,8 @@
}
static struct of_device_id spmi_match_table[] = {
- { .compatible = "qcom,qpnp-power-on",
- }
+ { .compatible = "qcom,qpnp-power-on", },
+ {}
};
static struct spmi_driver qpnp_pon_driver = {
diff --git a/drivers/platform/msm/qpnp-pwm.c b/drivers/platform/msm/qpnp-pwm.c
index 7d26bef..588afc6 100644
--- a/drivers/platform/msm/qpnp-pwm.c
+++ b/drivers/platform/msm/qpnp-pwm.c
@@ -208,6 +208,12 @@
#define QPNP_PWM_SIZE_8_BIT 8
#define QPNP_PWM_SIZE_9_BIT 9
+/* Supported time levels */
+enum time_level {
+ LVL_NSEC,
+ LVL_USEC,
+};
+
/* LPG revisions */
enum qpnp_lpg_revision {
QPNP_LPG_REVISION_0 = 0x0,
@@ -305,8 +311,8 @@
bool in_use;
const char *lable;
int pwm_value;
- int pwm_period;
- int pwm_duty;
+ int pwm_period; /* in microseconds */
+ int pwm_duty; /* in microseconds */
struct pwm_period_config period;
int force_pwm_size;
};
@@ -425,8 +431,9 @@
* This is the formula to figure out m for the best pre-divide and clock:
* (PWM Period / N) = (Pre-divide * Clock Period) * 2^m
*/
-static void qpnp_lpg_calc_period(unsigned int period_us,
- struct pwm_device *pwm)
+static void qpnp_lpg_calc_period(enum time_level tm_lvl,
+ unsigned int period_value,
+ struct pwm_device *pwm)
{
int n, m, clk, div;
int best_m, best_div, best_clk;
@@ -443,14 +450,18 @@
else
n = 6;
- if (period_us < ((unsigned)(-1) / NSEC_PER_USEC)) {
- period_n = (period_us * NSEC_PER_USEC) >> n;
+ if (tm_lvl == LVL_USEC) {
+ if (period_value < ((unsigned)(-1) / NSEC_PER_USEC)) {
+ period_n = (period_value * NSEC_PER_USEC) >> n;
+ } else {
+ if (qpnp_check_gpled_lpg_channel(id))
+ n = 8;
+ else
+ n = 9;
+ period_n = (period_value >> n) * NSEC_PER_USEC;
+ }
} else {
- if (qpnp_check_gpled_lpg_channel(id))
- n = 8;
- else
- n = 9;
- period_n = (period_us >> n) * NSEC_PER_USEC;
+ period_n = period_value >> n;
}
if (force_pwm_size != 0) {
@@ -520,20 +531,20 @@
}
static void qpnp_lpg_calc_pwm_value(struct pwm_device *pwm,
- unsigned int period_us,
- unsigned int duty_us)
+ unsigned int period_value,
+ unsigned int duty_value)
{
unsigned int max_pwm_value, tmp;
struct qpnp_pwm_config *pwm_config = &pwm->pwm_config;
/* Figure out pwm_value with overflow handling */
tmp = 1 << (sizeof(tmp) * 8 - pwm_config->period.pwm_size);
- if (duty_us < tmp) {
- tmp = duty_us << pwm_config->period.pwm_size;
- pwm_config->pwm_value = tmp / period_us;
+ if (duty_value < tmp) {
+ tmp = duty_value << pwm_config->period.pwm_size;
+ pwm_config->pwm_value = tmp / period_value;
} else {
- tmp = period_us >> pwm_config->period.pwm_size;
- pwm_config->pwm_value = duty_us / tmp;
+ tmp = period_value >> pwm_config->period.pwm_size;
+ pwm_config->pwm_value = duty_value / tmp;
}
max_pwm_value = (1 << pwm_config->period.pwm_size) - 1;
if (pwm_config->pwm_value > max_pwm_value)
@@ -1083,25 +1094,36 @@
return rc;
}
-static int _pwm_config(struct pwm_device *pwm, int duty_us, int period_us)
+static int _pwm_config(struct pwm_device *pwm,
+ enum time_level tm_lvl,
+ int duty_value, int period_value)
{
struct qpnp_pwm_config *pwm_config;
struct qpnp_lpg_chip *chip;
struct pwm_period_config *period;
- int rc;
+ int period_us, duty_us;
+ int rc;
chip = pwm->chip;
pwm_config = &pwm->pwm_config;
period = &pwm_config->period;
+ if (tm_lvl == LVL_USEC) {
+ period_us = period_value;
+ duty_us = duty_value;
+ } else {
+ period_us = period_value / NSEC_PER_USEC;
+ duty_us = duty_value / NSEC_PER_USEC;
+ }
+
if (pwm_config->pwm_period != period_us) {
- qpnp_lpg_calc_period(period_us, pwm);
+ qpnp_lpg_calc_period(tm_lvl, period_value, pwm);
qpnp_lpg_save_period(pwm);
pwm_config->pwm_period = period_us;
}
pwm_config->pwm_duty = duty_us;
- qpnp_lpg_calc_pwm_value(pwm, period_us, duty_us);
+ qpnp_lpg_calc_pwm_value(pwm, period_value, duty_value);
rc = qpnp_lpg_save_pwm_value(pwm);
if (rc) {
@@ -1124,8 +1146,9 @@
return rc;
}
- pr_debug("duty/period=%u/%u usec: pwm_value=%d (of %d)\n",
+ pr_debug("duty/period=%u/%u %s: pwm_value=%d (of %d)\n",
(unsigned)duty_us, (unsigned)period_us,
+ (tm_lvl == LVL_USEC) ? "usec" : "nsec",
pwm_config->pwm_value, 1 << period->pwm_size);
return 0;
@@ -1151,7 +1174,7 @@
period = &pwm_config->period;
if (pwm_config->pwm_period != period_us) {
- qpnp_lpg_calc_period(period_us, pwm);
+ qpnp_lpg_calc_period(LVL_USEC, period_us, pwm);
qpnp_lpg_save_period(pwm);
pwm_config->pwm_period = period_us;
}
@@ -1302,10 +1325,41 @@
/**
* pwm_config - change a PWM device configuration
* @pwm: the PWM device
+ * @period_ns: period in nanoseconds
+ * @duty_ns: duty cycle in nanoseconds
+ */
+int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
+{
+ int rc;
+ unsigned long flags;
+
+ if (pwm == NULL || IS_ERR(pwm) || duty_ns > period_ns ||
+ (unsigned)period_ns < PM_PWM_PERIOD_MIN * NSEC_PER_USEC) {
+ pr_err("Invalid pwm handle or parameters\n");
+ return -EINVAL;
+ }
+
+ if (!pwm->pwm_config.in_use)
+ return -EINVAL;
+
+ spin_lock_irqsave(&pwm->chip->lpg_lock, flags);
+ rc = _pwm_config(pwm, LVL_NSEC, duty_ns, period_ns);
+ spin_unlock_irqrestore(&pwm->chip->lpg_lock, flags);
+
+ if (rc)
+ pr_err("Failed to configure PWM mode\n");
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(pwm_config);
+
+/**
+ * pwm_config_us - change a PWM device configuration
+ * @pwm: the PWM device
* @period_us: period in microseconds
* @duty_us: duty cycle in microseconds
*/
-int pwm_config(struct pwm_device *pwm, int duty_us, int period_us)
+int pwm_config_us(struct pwm_device *pwm, int duty_us, int period_us)
{
int rc;
unsigned long flags;
@@ -1322,7 +1376,7 @@
return -EINVAL;
spin_lock_irqsave(&pwm->chip->lpg_lock, flags);
- rc = _pwm_config(pwm, duty_us, period_us);
+ rc = _pwm_config(pwm, LVL_USEC, duty_us, period_us);
spin_unlock_irqrestore(&pwm->chip->lpg_lock, flags);
if (rc)
@@ -1330,7 +1384,7 @@
return rc;
}
-EXPORT_SYMBOL_GPL(pwm_config);
+EXPORT_SYMBOL_GPL(pwm_config_us);
/**
* pwm_enable - start a PWM output toggling
@@ -1627,7 +1681,8 @@
return rc;
}
- rc = _pwm_config(pwm_dev, pwm_dev->pwm_config.pwm_duty, period);
+ rc = _pwm_config(pwm_dev, LVL_USEC,
+ pwm_dev->pwm_config.pwm_duty, period);
return rc;
}
diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c
index 4f10cf8..55a5a2d 100644
--- a/drivers/platform/msm/sps/sps.c
+++ b/drivers/platform/msm/sps/sps.c
@@ -184,6 +184,11 @@
return -EFAULT;
}
+ if (buf_size_kb > (INT_MAX/SZ_1K)) {
+ pr_err("sps:debugfs: buffer size is too large\n");
+ return -EFAULT;
+ }
+
new_buf_size = buf_size_kb * SZ_1K;
if (debugfs_record_enabled) {
@@ -664,6 +669,11 @@
return SPS_ERROR;
}
+ if (sps == NULL || !sps->is_ready) {
+ SPS_DBG2("sps:%s:sps driver is not ready.\n", __func__);
+ return -EPROBE_DEFER;
+ }
+
mutex_lock(&sps->lock);
/* Search for the target BAM device */
bam = sps_h2bam(dev);
@@ -1100,6 +1110,11 @@
SPS_DBG("sps:%s.", __func__);
+ if (sps == NULL || !sps->is_ready) {
+ SPS_DBG2("sps:%s:sps driver is not ready.\n", __func__);
+ return -EPROBE_DEFER;
+ }
+
if (handle == NULL) {
SPS_ERR("sps:%s:handle is NULL.\n", __func__);
return SPS_ERROR;
@@ -1142,6 +1157,11 @@
return SPS_ERROR;
}
+ if (sps == NULL || !sps->is_ready) {
+ SPS_DBG2("sps:%s:sps driver is not ready.\n", __func__);
+ return -EPROBE_DEFER;
+ }
+
if (use_offset) {
if ((addr + size) <= sps->pipemem_size)
mem_buffer->phys_base = sps->pipemem_phys_base + addr;
@@ -1752,6 +1772,11 @@
return SPS_ERROR;
}
+ if (sps == NULL || !sps->is_ready) {
+ SPS_DBG2("sps:%s:sps driver is not ready.\n", __func__);
+ return -EPROBE_DEFER;
+ }
+
mutex_lock(&sps->lock);
/* Search for the target BAM device */
bam = sps_h2bam(dev);
@@ -1997,8 +2022,10 @@
SPS_DBG("sps:%s.", __func__);
- if (!sps->is_ready)
+ if (sps == NULL || !sps->is_ready) {
+ SPS_DBG2("sps:%s:sps driver is not ready.\n", __func__);
return -EPROBE_DEFER;
+ }
if (clk_on == true) {
SPS_DBG("sps:vote for bam dma clk.\n");
@@ -2039,8 +2066,10 @@
return SPS_ERROR;
}
- if (sps == NULL)
- return SPS_ERROR;
+ if (sps == NULL) {
+ SPS_DBG2("sps:%s:sps driver is not ready.\n", __func__);
+ return -EPROBE_DEFER;
+ }
/* BAM-DMA is registered internally during power-up */
if ((!sps->is_ready) && !(bam_props->options & SPS_BAM_OPT_BAMDMA)) {
@@ -2505,59 +2534,68 @@
goto device_create_err;
}
- sps->dfab_clk = clk_get(sps->dev, "dfab_clk");
- if (IS_ERR(sps->dfab_clk)) {
- if (IS_ERR(sps->dfab_clk) == -EPROBE_DEFER)
- ret = -EPROBE_DEFER;
- else
- SPS_ERR("sps:fail to get dfab_clk.");
- goto clk_err;
- } else {
- ret = clk_set_rate(sps->dfab_clk, 64000000);
- if (ret) {
- SPS_ERR("sps:failed to set dfab_clk rate.");
- clk_put(sps->dfab_clk);
- goto clk_err;
- }
- }
+ if (pdev->dev.of_node)
+ sps->dev->of_node = pdev->dev.of_node;
if (!d_type) {
sps->pmem_clk = clk_get(sps->dev, "mem_clk");
if (IS_ERR(sps->pmem_clk)) {
- if (IS_ERR(sps->pmem_clk) == -EPROBE_DEFER)
+ if (PTR_ERR(sps->pmem_clk) == -EPROBE_DEFER)
ret = -EPROBE_DEFER;
else
SPS_ERR("sps:fail to get pmem_clk.");
- goto clk_err;
+ goto pmem_clk_err;
} else {
ret = clk_prepare_enable(sps->pmem_clk);
if (ret) {
SPS_ERR("sps:failed to enable pmem_clk.");
- goto clk_err;
+ goto pmem_clk_en_err;
}
}
}
#ifdef CONFIG_SPS_SUPPORT_BAMDMA
+ sps->dfab_clk = clk_get(sps->dev, "dfab_clk");
+ if (IS_ERR(sps->dfab_clk)) {
+ if (PTR_ERR(sps->dfab_clk) == -EPROBE_DEFER)
+ ret = -EPROBE_DEFER;
+ else
+ SPS_ERR("sps:fail to get dfab_clk.");
+ goto dfab_clk_err;
+ } else {
+ ret = clk_set_rate(sps->dfab_clk, 64000000);
+ if (ret) {
+ SPS_ERR("sps:failed to set dfab_clk rate.");
+ clk_put(sps->dfab_clk);
+ goto dfab_clk_err;
+ }
+ }
+
sps->bamdma_clk = clk_get(sps->dev, "dma_bam_pclk");
if (IS_ERR(sps->bamdma_clk)) {
- if (IS_ERR(sps->bamdma_clk) == -EPROBE_DEFER)
+ if (PTR_ERR(sps->bamdma_clk) == -EPROBE_DEFER)
ret = -EPROBE_DEFER;
else
SPS_ERR("sps:fail to get bamdma_clk.");
- goto clk_err;
+ clk_put(sps->dfab_clk);
+ goto dfab_clk_err;
} else {
ret = clk_prepare_enable(sps->bamdma_clk);
if (ret) {
SPS_ERR("sps:failed to enable bamdma_clk. ret=%d", ret);
- goto clk_err;
+ clk_put(sps->bamdma_clk);
+ clk_put(sps->dfab_clk);
+ goto dfab_clk_err;
}
}
ret = clk_prepare_enable(sps->dfab_clk);
if (ret) {
SPS_ERR("sps:failed to enable dfab_clk. ret=%d", ret);
- goto clk_err;
+ clk_disable_unprepare(sps->bamdma_clk);
+ clk_put(sps->bamdma_clk);
+ clk_put(sps->dfab_clk);
+ goto dfab_clk_err;
}
#endif
ret = sps_device_init();
@@ -2566,8 +2604,10 @@
#ifdef CONFIG_SPS_SUPPORT_BAMDMA
clk_disable_unprepare(sps->dfab_clk);
clk_disable_unprepare(sps->bamdma_clk);
+ clk_put(sps->bamdma_clk);
+ clk_put(sps->dfab_clk);
#endif
- goto sps_device_init_err;
+ goto dfab_clk_err;
}
#ifdef CONFIG_SPS_SUPPORT_BAMDMA
clk_disable_unprepare(sps->dfab_clk);
@@ -2578,8 +2618,13 @@
SPS_INFO("sps:sps is ready.");
return 0;
-clk_err:
-sps_device_init_err:
+dfab_clk_err:
+ if (!d_type)
+ clk_disable_unprepare(sps->pmem_clk);
+pmem_clk_en_err:
+ if (!d_type)
+ clk_put(sps->pmem_clk);
+pmem_clk_err:
device_destroy(sps->dev_class, sps->dev_num);
device_create_err:
unregister_chrdev_region(sps->dev_num, 1);
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index b918110..4688514 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -152,6 +152,7 @@
POWER_SUPPLY_ATTR(current_max),
POWER_SUPPLY_ATTR(input_current_max),
POWER_SUPPLY_ATTR(input_current_trim),
+ POWER_SUPPLY_ATTR(input_current_settled),
POWER_SUPPLY_ATTR(current_now),
POWER_SUPPLY_ATTR(current_avg),
POWER_SUPPLY_ATTR(power_now),
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 9727787..85a70ea 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -765,10 +765,22 @@
return get_battery_status(chip) == POWER_SUPPLY_STATUS_FULL;
}
+#define BAT_PRES_BIT BIT(7)
static bool is_battery_present(struct qpnp_bms_chip *chip)
{
union power_supply_propval ret = {0,};
+ int rc;
+ u8 batt_pres;
+ /* first try to use the batt_pres register if given */
+ if (chip->batt_pres_addr) {
+ rc = qpnp_read_wrapper(chip, &batt_pres,
+ chip->batt_pres_addr, 1);
+ if (!rc && (batt_pres & BAT_PRES_BIT))
+ return true;
+ else
+ return false;
+ }
if (chip->batt_psy == NULL)
chip->batt_psy = power_supply_get_by_name("battery");
if (chip->batt_psy) {
@@ -922,14 +934,67 @@
}
}
+#define SIGN(x) ((x) < 0 ? -1 : 1)
+#define UV_PER_SPIN 50000
+static int find_ocv_for_pc(struct qpnp_bms_chip *chip, int batt_temp, int pc)
+{
+ int new_pc;
+ int batt_temp_degc = batt_temp / 10;
+ int ocv_mv;
+ int delta_mv = 5;
+ int max_spin_count;
+ int count = 0;
+ int sign, new_sign;
+
+ ocv_mv = interpolate_ocv(chip->pc_temp_ocv_lut, batt_temp_degc, pc);
+
+ new_pc = interpolate_pc(chip->pc_temp_ocv_lut, batt_temp_degc, ocv_mv);
+ pr_debug("test revlookup pc = %d for ocv = %d\n", new_pc, ocv_mv);
+ max_spin_count = 1 + (chip->max_voltage_uv - chip->v_cutoff_uv)
+ / UV_PER_SPIN;
+ sign = SIGN(pc - new_pc);
+
+ while (abs(new_pc - pc) != 0 && count < max_spin_count) {
+ /*
+ * If the newly interpolated pc is larger than the lookup pc,
+ * the ocv should be reduced and vice versa
+ */
+ new_sign = SIGN(pc - new_pc);
+ /*
+ * If the sign has changed, then we have passed the lookup pc.
+ * reduce the ocv step size to get finer results.
+ *
+ * If we have already reduced the ocv step size and still
+ * passed the lookup pc, just stop and use the current ocv.
+ * This can only happen if the batterydata profile is
+ * non-monotonic anyways.
+ */
+ if (new_sign != sign) {
+ if (delta_mv > 1)
+ delta_mv = 1;
+ else
+ break;
+ }
+ sign = new_sign;
+
+ ocv_mv = ocv_mv + delta_mv * sign;
+ new_pc = interpolate_pc(chip->pc_temp_ocv_lut,
+ batt_temp_degc, ocv_mv);
+ pr_debug("test revlookup pc = %d for ocv = %d\n",
+ new_pc, ocv_mv);
+ count++;
+ }
+
+ return ocv_mv * 1000;
+}
+
#define OCV_RAW_UNINITIALIZED 0xFFFF
#define MIN_OCV_UV 2000000
static int read_soc_params_raw(struct qpnp_bms_chip *chip,
struct raw_soc_params *raw,
int batt_temp)
{
- int warm_reset;
- int rc;
+ int warm_reset, rc;
mutex_lock(&chip->bms_output_lock);
@@ -977,8 +1042,8 @@
chip->done_charging = false;
/* if we just finished charging, reset CC and fake 100% */
chip->ocv_reading_at_100 = raw->last_good_ocv_raw;
- chip->last_ocv_uv = chip->max_voltage_uv;
- raw->last_good_ocv_uv = chip->max_voltage_uv;
+ chip->last_ocv_uv = find_ocv_for_pc(chip, batt_temp, 100);
+ raw->last_good_ocv_uv = chip->last_ocv_uv;
raw->cc = 0;
raw->shdw_cc = 0;
reset_cc(chip, CLEAR_CC | CLEAR_SHDW_CC);
@@ -1355,60 +1420,6 @@
return pc;
}
-#define SIGN(x) ((x) < 0 ? -1 : 1)
-#define UV_PER_SPIN 50000
-static int find_ocv_for_pc(struct qpnp_bms_chip *chip, int batt_temp, int pc)
-{
- int new_pc;
- int batt_temp_degc = batt_temp / 10;
- int ocv_mv;
- int delta_mv = 5;
- int max_spin_count;
- int count = 0;
- int sign, new_sign;
-
- ocv_mv = interpolate_ocv(chip->pc_temp_ocv_lut, batt_temp_degc, pc);
-
- new_pc = interpolate_pc(chip->pc_temp_ocv_lut, batt_temp_degc, ocv_mv);
- pr_debug("test revlookup pc = %d for ocv = %d\n", new_pc, ocv_mv);
- max_spin_count = 1 + (chip->max_voltage_uv - chip->v_cutoff_uv)
- / UV_PER_SPIN;
- sign = SIGN(pc - new_pc);
-
- while (abs(new_pc - pc) != 0 && count < max_spin_count) {
- /*
- * If the newly interpolated pc is larger than the lookup pc,
- * the ocv should be reduced and vice versa
- */
- new_sign = SIGN(pc - new_pc);
- /*
- * If the sign has changed, then we have passed the lookup pc.
- * reduce the ocv step size to get finer results.
- *
- * If we have already reduced the ocv step size and still
- * passed the lookup pc, just stop and use the current ocv.
- * This can only happen if the batterydata profile is
- * non-monotonic anyways.
- */
- if (new_sign != sign) {
- if (delta_mv > 1)
- delta_mv = 1;
- else
- break;
- }
- sign = new_sign;
-
- ocv_mv = ocv_mv + delta_mv * sign;
- new_pc = interpolate_pc(chip->pc_temp_ocv_lut,
- batt_temp_degc, ocv_mv);
- pr_debug("test revlookup pc = %d for ocv = %d\n",
- new_pc, ocv_mv);
- count++;
- }
-
- return ocv_mv * 1000;
-}
-
static int get_current_time(unsigned long *now_tm_sec)
{
struct rtc_time tm;
@@ -1677,10 +1688,13 @@
rc = qpnp_write_wrapper(chip, &temp, chip->base + IAVG_STORAGE_REG, 1);
- /* don't store soc if temperature is below 5degC */
+ /* store an invalid soc if temperature is below 5degC */
if (batt_temp > IGNORE_SOC_TEMP_DECIDEG)
qpnp_masked_write_base(chip, chip->soc_storage_addr,
SOC_STORAGE_MASK, (soc + 1) << 1);
+ else
+ qpnp_masked_write_base(chip, chip->soc_storage_addr,
+ SOC_STORAGE_MASK, SOC_STORAGE_MASK);
}
static int scale_soc_while_chg(struct qpnp_bms_chip *chip, int chg_time_sec,
@@ -1817,8 +1831,15 @@
chip->catch_up_time_sec,
soc, chip->last_soc);
- soc_change = min((int)abs(chip->last_soc - soc),
- time_since_last_change_sec / SOC_CHANGE_PER_SEC);
+ /* if the battery is close to cutoff allow more change */
+ if (wake_lock_active(&chip->low_voltage_wake_lock))
+ soc_change = min((int)abs(chip->last_soc - soc),
+ time_since_last_change_sec);
+ else
+ soc_change = min((int)abs(chip->last_soc - soc),
+ time_since_last_change_sec
+ / SOC_CHANGE_PER_SEC);
+
if (chip->last_soc_unbound) {
chip->last_soc_unbound = false;
} else {
@@ -1876,7 +1897,7 @@
if (batt_terminal_uv >= chip->max_voltage_uv - VDD_MAX_ERR) {
chip->soc_at_cv = soc;
chip->prev_chg_soc = soc;
- chip->ibat_at_cv_ua = ibat_ua;
+ chip->ibat_at_cv_ua = params->iavg_ua;
pr_debug("CC_TO_CV ibat_ua = %d CHG SOC %d\n",
ibat_ua, soc);
} else {
@@ -1927,7 +1948,7 @@
soc_ibat = bound_soc(linear_interpolate(chip->soc_at_cv,
chip->ibat_at_cv_ua,
100, -1 * chip->chg_term_ua,
- ibat_ua));
+ params->iavg_ua));
weight_ibat = bound_soc(linear_interpolate(1, chip->soc_at_cv,
100, 100, chip->prev_chg_soc));
weight_cc = 100 - weight_ibat;
@@ -1994,7 +2015,7 @@
}
}
-#define NO_ADJUST_HIGH_SOC_THRESHOLD 90
+#define NO_ADJUST_HIGH_SOC_THRESHOLD 98
static int adjust_soc(struct qpnp_bms_chip *chip, struct soc_params *params,
int soc, int batt_temp)
{
@@ -2050,9 +2071,10 @@
* because we might pull it low
* and cause a bad user experience
*/
- if (soc_est == soc
- || soc_est > chip->adjust_soc_low_threshold
- || soc >= NO_ADJUST_HIGH_SOC_THRESHOLD)
+ if (!wake_lock_active(&chip->low_voltage_wake_lock) &&
+ (soc_est == soc
+ || soc_est > chip->adjust_soc_low_threshold
+ || soc >= NO_ADJUST_HIGH_SOC_THRESHOLD))
goto out;
if (chip->last_soc_est == -EINVAL)
@@ -2097,8 +2119,11 @@
pr_debug("new delta ocv = %d\n", delta_ocv_uv);
}
- if (wake_lock_active(&chip->low_voltage_wake_lock))
+ if (wake_lock_active(&chip->low_voltage_wake_lock)) {
+ /* when in the cutoff region, do not correct upwards */
+ delta_ocv_uv = max(0, delta_ocv_uv);
goto skip_limits;
+ }
if (chip->last_ocv_uv > chip->flat_ocv_threshold_uv)
correction_limit_uv = chip->high_ocv_correction_limit_uv;
@@ -2246,6 +2271,8 @@
qpnp_write_wrapper(chip, (u8 *)&ocv_raw,
chip->base + BMS1_OCV_THR0, 2);
+ enable_bms_irq(&chip->ocv_thr_irq);
+ enable_bms_irq(&chip->sw_cc_thr_irq);
pr_debug("current sw_cc_raw = 0x%llx, current ocv = 0x%hx\n",
current_shdw_cc_raw, (uint16_t)current_ocv_raw);
pr_debug("target_cc_uah = %lld, raw64 = 0x%llx, raw 36 = 0x%llx, ocv_raw = 0x%hx\n",
@@ -2254,6 +2281,7 @@
(uint16_t)ocv_raw);
}
+#define BAD_SOC_THRESH -10
static int calculate_raw_soc(struct qpnp_bms_chip *chip,
struct raw_soc_params *raw,
struct soc_params *params,
@@ -2270,7 +2298,7 @@
soc = DIV_ROUND_CLOSEST((remaining_usable_charge_uah * 100),
(params->fcc_uah - params->uuc_uah));
- if (chip->first_time_calc_soc && soc < 0) {
+ if (chip->first_time_calc_soc && soc > BAD_SOC_THRESH && soc < 0) {
/*
* first time calcualtion and the pon ocv is too low resulting
* in a bad soc. Adjust ocv to get 0 soc
@@ -2295,7 +2323,7 @@
if (soc > 100)
soc = 100;
- if (soc < 0) {
+ if (soc > BAD_SOC_THRESH && soc < 0) {
pr_debug("bad rem_usb_chg = %d rem_chg %d, cc_uah %d, unusb_chg %d\n",
remaining_usable_charge_uah,
params->ocv_charge_uah,
@@ -2376,9 +2404,13 @@
* If the battery is full, configure the cc threshold so the system
* wakes up after SoC changes
*/
- if (is_battery_full(chip))
+ if (is_battery_full(chip)) {
configure_soc_wakeup(chip, ¶ms,
batt_temp, bound_soc(new_calculated_soc - 1));
+ } else {
+ disable_bms_irq(&chip->ocv_thr_irq);
+ disable_bms_irq(&chip->sw_cc_thr_irq);
+ }
done_calculating:
mutex_lock(&chip->last_soc_mutex);
previous_soc = chip->calculated_soc;
@@ -3220,8 +3252,6 @@
if (status == POWER_SUPPLY_STATUS_FULL) {
pr_debug("battery full\n");
- enable_bms_irq(&chip->ocv_thr_irq);
- enable_bms_irq(&chip->sw_cc_thr_irq);
recalculate_soc(chip);
} else if (chip->battery_status
== POWER_SUPPLY_STATUS_FULL) {
@@ -3488,7 +3518,7 @@
|| shutdown_soc_out_of_limit) {
chip->battery_removed = true;
chip->shutdown_soc_invalid = true;
- chip->shutdown_iavg_ma = 0;
+ chip->shutdown_iavg_ma = MIN_IAVG_MA;
pr_debug("Ignoring shutdown SoC: invalid = %d, offmode = %d, out_of_limit = %d\n",
invalid_stored_soc, offmode_battery_replaced,
shutdown_soc_out_of_limit);
@@ -3520,6 +3550,7 @@
struct qpnp_bms_chip *chip = _chip;
pr_debug("sw_cc_thr irq triggered\n");
+ disable_bms_irq(&chip->sw_cc_thr_irq);
bms_stay_awake(&chip->soc_wake_source);
schedule_work(&chip->recalc_work);
return IRQ_HANDLED;
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index a65ac5b..32623f4 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -70,8 +70,9 @@
#define CHGR_IBAT_TERM_CHGR 0x5B
#define CHGR_IBAT_TERM_BMS 0x5C
#define CHGR_VBAT_DET 0x5D
+#define CHGR_TTRKL_MAX_EN 0x5E
#define CHGR_TTRKL_MAX 0x5F
-#define CHGR_TTRKL_MAX_EN 0x60
+#define CHGR_TCHG_MAX_EN 0x60
#define CHGR_TCHG_MAX 0x61
#define CHGR_CHG_WDOG_TIME 0x62
#define CHGR_CHG_WDOG_DLY 0x63
@@ -101,6 +102,7 @@
#define BUCK_VCHG_OV 0x77
#define BUCK_TEST_SMBC_MODES 0xE6
#define BUCK_CTRL_TRIM1 0xF1
+#define BUCK_CTRL_TRIM3 0xF3
#define SEC_ACCESS 0xD0
#define BAT_IF_VREF_BAT_THM_CTRL 0x4A
#define BAT_IF_BPD_CTRL 0x48
@@ -310,6 +312,9 @@
bool btc_disabled;
bool use_default_batt_values;
bool duty_cycle_100p;
+ bool ibat_calibration_enabled;
+ bool aicl_settled;
+ bool use_external_rsense;
unsigned int bpd_detection;
unsigned int max_bat_chg_current;
unsigned int warm_bat_chg_ma;
@@ -335,6 +340,7 @@
unsigned int cold_batt_p;
int warm_bat_decidegc;
int cool_bat_decidegc;
+ int fake_battery_soc;
unsigned int safe_current;
unsigned int revision;
unsigned int type;
@@ -362,6 +368,7 @@
bool batfet_ext_en;
struct work_struct batfet_lcl_work;
struct qpnp_vadc_chip *vadc_dev;
+ struct qpnp_iadc_chip *iadc_dev;
struct qpnp_adc_tm_chip *adc_tm_dev;
struct mutex jeita_configure_lock;
spinlock_t usbin_health_monitor_lock;
@@ -369,6 +376,7 @@
struct alarm reduce_power_stage_alarm;
struct work_struct reduce_power_stage_work;
bool power_stage_workaround_running;
+ bool power_stage_workaround_enable;
};
@@ -420,6 +428,16 @@
return -EINVAL;
}
+static bool
+is_within_range(int value, int left, int right)
+{
+ if (left >= right && left >= value && value >= right)
+ return 1;
+ if (left <= right && left <= value && value <= right)
+ return 1;
+ return 0;
+}
+
static int
qpnp_chg_read(struct qpnp_chg_chip *chip, u8 *val,
u16 base, int count)
@@ -622,6 +640,22 @@
return (usbin_valid_rt_sts & USB_VALID_BIT) ? 1 : 0;
}
+static bool
+qpnp_chg_is_ibat_loop_active(struct qpnp_chg_chip *chip)
+{
+ int rc;
+ u8 buck_sts;
+
+ rc = qpnp_chg_read(chip, &buck_sts,
+ INT_RT_STS(chip->buck_base), 1);
+ if (rc) {
+ pr_err("failed to read buck RT status rc=%d\n", rc);
+ return 0;
+ }
+
+ return !!(buck_sts & IBAT_LOOP_IRQ);
+}
+
#define USB_VALID_MASK 0xC0
#define USB_COARSE_DET 0x10
#define USB_VALID_UVP_VALUE 0x00
@@ -798,13 +832,12 @@
int rc = 0;
u8 usb_reg = 0, temp = 8;
- if (mA < QPNP_CHG_I_MAX_MIN_100
- || mA > QPNP_CHG_I_MAX_MAX_MA) {
+ if (mA < 0 || mA > QPNP_CHG_I_MAX_MAX_MA) {
pr_err("bad mA=%d asked to set\n", mA);
return -EINVAL;
}
- if (mA == QPNP_CHG_I_MAX_MIN_100) {
+ if (mA <= QPNP_CHG_I_MAX_MIN_100) {
usb_reg = 0x00;
pr_debug("current=%d setting %02x\n", mA, usb_reg);
return qpnp_chg_write(chip, &usb_reg,
@@ -1155,9 +1188,16 @@
qpnp_chg_usb_chg_gone_irq_handler(int irq, void *_chip)
{
struct qpnp_chg_chip *chip = _chip;
+ u8 usb_sts;
+ int rc;
+
+ rc = qpnp_chg_read(chip, &usb_sts,
+ INT_RT_STS(chip->usb_chgpth_base), 1);
+ if (rc)
+ pr_err("failed to read usb_chgpth_sts rc=%d\n", rc);
pr_debug("chg_gone triggered\n");
- if (qpnp_chg_is_usb_chg_plugged_in(chip)) {
+ if (qpnp_chg_is_usb_chg_plugged_in(chip) && (usb_sts & CHG_GONE_IRQ)) {
qpnp_chg_charge_en(chip, 0);
qpnp_chg_force_run_on_batt(chip, 1);
schedule_delayed_work(&chip->arb_stop_work,
@@ -1244,6 +1284,21 @@
return 0;
}
+static int
+qpnp_chg_vddmax_get(struct qpnp_chg_chip *chip)
+{
+ int rc;
+ u8 vddmax = 0;
+
+ rc = qpnp_chg_read(chip, &vddmax, chip->chgr_base + CHGR_VDD_MAX, 1);
+ if (rc) {
+ pr_err("Failed to write vddmax: %d\n", rc);
+ return rc;
+ }
+
+ return QPNP_CHG_V_MIN_MV + (int)vddmax * QPNP_CHG_V_STEP_MV;
+}
+
/* JEITA compliance logic */
static void
qpnp_chg_set_appropriate_vddmax(struct qpnp_chg_chip *chip)
@@ -1403,10 +1458,10 @@
(chip->usb_valid_check_ovp)) {
usbin_health =
qpnp_chg_check_usbin_health(chip);
- if (chip->usbin_health != usbin_health) {
+ if ((chip->usbin_health != usbin_health)
+ && (usbin_health == USBIN_OVP)) {
chip->usbin_health = usbin_health;
- if (usbin_health == USBIN_OVP)
- psy_health_sts =
+ psy_health_sts =
POWER_SUPPLY_HEALTH_OVERVOLTAGE;
power_supply_set_health_state(
chip->usb_psy,
@@ -1419,8 +1474,10 @@
qpnp_chg_set_appropriate_vddmax(chip);
chip->chg_done = false;
}
- qpnp_chg_usb_suspend_enable(chip, 1);
+ qpnp_chg_usb_suspend_enable(chip, 0);
+ qpnp_chg_iusbmax_set(chip, QPNP_CHG_I_MAX_MIN_100);
chip->prev_usb_max_ma = -EINVAL;
+ chip->aicl_settled = false;
} else {
/* when OVP clamped usbin, and then decrease
* the charger voltage to lower than the OVP
@@ -1431,10 +1488,10 @@
(chip->usb_valid_check_ovp)) {
usbin_health =
qpnp_chg_check_usbin_health(chip);
- if (chip->usbin_health != usbin_health) {
+ if ((chip->usbin_health != usbin_health)
+ && (usbin_health == USBIN_OK)) {
chip->usbin_health = usbin_health;
- if (usbin_health == USBIN_OK)
- psy_health_sts =
+ psy_health_sts =
POWER_SUPPLY_HEALTH_GOOD;
power_supply_set_health_state(
chip->usb_psy,
@@ -1655,9 +1712,11 @@
case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL:
case POWER_SUPPLY_PROP_INPUT_CURRENT_MAX:
case POWER_SUPPLY_PROP_INPUT_CURRENT_TRIM:
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED:
case POWER_SUPPLY_PROP_VOLTAGE_MIN:
case POWER_SUPPLY_PROP_COOL_TEMP:
case POWER_SUPPLY_PROP_WARM_TEMP:
+ case POWER_SUPPLY_PROP_CAPACITY:
return 1;
default:
break;
@@ -1768,6 +1827,7 @@
POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_INPUT_CURRENT_MAX,
POWER_SUPPLY_PROP_INPUT_CURRENT_TRIM,
+ POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED,
POWER_SUPPLY_PROP_VOLTAGE_MIN,
POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION,
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
@@ -2012,6 +2072,9 @@
union power_supply_propval ret = {0,};
int battery_status, bms_status, soc, charger_in;
+ if (chip->fake_battery_soc >= 0)
+ return chip->fake_battery_soc;
+
if (chip->use_default_batt_values || !get_prop_batt_present(chip))
return DEFAULT_CAPACITY;
@@ -2029,6 +2092,8 @@
if (battery_status != POWER_SUPPLY_STATUS_CHARGING
&& bms_status != POWER_SUPPLY_STATUS_CHARGING
&& charger_in
+ && !chip->bat_is_cool
+ && !chip->bat_is_warm
&& !chip->resuming_charging
&& !chip->charging_disabled
&& chip->soc_resume_limit
@@ -2132,7 +2197,8 @@
if (ret.intval <= 2 && !chip->use_default_batt_values &&
get_prop_batt_present(chip)) {
- qpnp_chg_usb_suspend_enable(chip, 1);
+ if (ret.intval == 2)
+ qpnp_chg_usb_suspend_enable(chip, 1);
qpnp_chg_iusbmax_set(chip, QPNP_CHG_I_MAX_MIN_100);
} else {
qpnp_chg_usb_suspend_enable(chip, 0);
@@ -2151,7 +2217,8 @@
if ((chip->flags & POWER_STAGE_WA)
&& ((ret.intval / 1000) > USB_WALL_THRESHOLD_MA)
- && !chip->power_stage_workaround_running) {
+ && !chip->power_stage_workaround_running
+ && chip->power_stage_workaround_enable) {
chip->power_stage_workaround_running = true;
pr_debug("usb wall chg inserted starting power stage workaround charger_monitor = %d\n",
charger_monitor);
@@ -2241,6 +2308,9 @@
case POWER_SUPPLY_PROP_INPUT_CURRENT_TRIM:
val->intval = qpnp_chg_iusb_trim_get(chip);
break;
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED:
+ val->intval = chip->aicl_settled;
+ break;
case POWER_SUPPLY_PROP_VOLTAGE_MIN:
val->intval = qpnp_chg_vinmin_get(chip) * 1000;
break;
@@ -2347,22 +2417,63 @@
QPNP_CHG_I_MASK, temp, 1);
}
+static int
+qpnp_chg_ibatmax_get(struct qpnp_chg_chip *chip, int *chg_current)
+{
+ int rc;
+ u8 temp;
+
+ *chg_current = 0;
+ rc = qpnp_chg_read(chip, &temp, chip->chgr_base + CHGR_IBAT_MAX, 1);
+ if (rc) {
+ pr_err("failed read ibat_max rc=%d\n", rc);
+ return rc;
+ }
+
+ *chg_current = ((temp & QPNP_CHG_I_MASK) * QPNP_CHG_I_STEP_MA);
+
+ return 0;
+}
+
#define QPNP_CHG_TCHG_MASK 0x7F
+#define QPNP_CHG_TCHG_EN_MASK 0x80
#define QPNP_CHG_TCHG_MIN 4
#define QPNP_CHG_TCHG_MAX 512
#define QPNP_CHG_TCHG_STEP 4
static int qpnp_chg_tchg_max_set(struct qpnp_chg_chip *chip, int minutes)
{
u8 temp;
+ int rc;
if (minutes < QPNP_CHG_TCHG_MIN || minutes > QPNP_CHG_TCHG_MAX) {
pr_err("bad max minutes =%d asked to set\n", minutes);
return -EINVAL;
}
- temp = (minutes - 1)/QPNP_CHG_TCHG_STEP;
- return qpnp_chg_masked_write(chip, chip->chgr_base + CHGR_TCHG_MAX,
+ rc = qpnp_chg_masked_write(chip, chip->chgr_base + CHGR_TCHG_MAX_EN,
+ QPNP_CHG_TCHG_EN_MASK, 0, 1);
+ if (rc) {
+ pr_err("failed write tchg_max_en rc=%d\n", rc);
+ return rc;
+ }
+
+ temp = minutes / QPNP_CHG_TCHG_STEP - 1;
+
+ rc = qpnp_chg_masked_write(chip, chip->chgr_base + CHGR_TCHG_MAX,
QPNP_CHG_TCHG_MASK, temp, 1);
+ if (rc) {
+ pr_err("failed write tchg_max_en rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = qpnp_chg_masked_write(chip, chip->chgr_base + CHGR_TCHG_MAX_EN,
+ QPNP_CHG_TCHG_EN_MASK, QPNP_CHG_TCHG_EN_MASK, 1);
+ if (rc) {
+ pr_err("failed write tchg_max_en rc=%d\n", rc);
+ return rc;
+ }
+
+ return 0;
}
static int
@@ -2381,6 +2492,155 @@
chip->chgr_base + CHGR_VDD_SAFE, 1);
}
+#define IBAT_TRIM_TGT_MA 500
+#define IBAT_TRIM_OFFSET_MASK 0x7F
+#define IBAT_TRIM_GOOD_BIT BIT(7)
+#define IBAT_TRIM_LOW_LIM 20
+#define IBAT_TRIM_HIGH_LIM 114
+#define IBAT_TRIM_MEAN 64
+
+static void
+qpnp_chg_trim_ibat(struct qpnp_chg_chip *chip, u8 ibat_trim)
+{
+ int ibat_now_ma, ibat_diff_ma, rc;
+ struct qpnp_iadc_result i_result;
+ enum qpnp_iadc_channels iadc_channel;
+
+ iadc_channel = chip->use_external_rsense ?
+ EXTERNAL_RSENSE : INTERNAL_RSENSE;
+ rc = qpnp_iadc_read(chip->iadc_dev, iadc_channel, &i_result);
+ if (rc) {
+ pr_err("Unable to read bat rc=%d\n", rc);
+ return;
+ }
+
+ ibat_now_ma = i_result.result_ua / 1000;
+
+ if (qpnp_chg_is_ibat_loop_active(chip)) {
+ ibat_diff_ma = ibat_now_ma - IBAT_TRIM_TGT_MA;
+
+ if (abs(ibat_diff_ma) > 50) {
+ ibat_trim += (ibat_diff_ma / 20);
+ ibat_trim &= IBAT_TRIM_OFFSET_MASK;
+ /* reject new ibat_trim if it is outside limits */
+ if (!is_within_range(ibat_trim, IBAT_TRIM_LOW_LIM,
+ IBAT_TRIM_HIGH_LIM))
+ return;
+ }
+ ibat_trim |= IBAT_TRIM_GOOD_BIT;
+ rc = qpnp_chg_write(chip, &ibat_trim,
+ chip->buck_base + BUCK_CTRL_TRIM3, 1);
+ if (rc)
+ pr_err("failed to set IBAT_TRIM rc=%d\n", rc);
+
+ pr_debug("ibat_now=%dmA, itgt=%dmA, ibat_diff=%dmA, ibat_trim=%x\n",
+ ibat_now_ma, IBAT_TRIM_TGT_MA,
+ ibat_diff_ma, ibat_trim);
+ } else {
+ pr_debug("ibat loop not active - cannot calibrate ibat\n");
+ }
+}
+
+static int
+qpnp_chg_input_current_settled(struct qpnp_chg_chip *chip)
+{
+ int rc, ibat_max_ma;
+ u8 reg, chgr_sts, ibat_trim, i;
+
+ chip->aicl_settled = true;
+
+ /*
+ * Perform the ibat calibration.
+ * This is for devices which have a IBAT_TRIM error
+ * which can show IBAT_MAX out of spec.
+ */
+ if (!chip->ibat_calibration_enabled)
+ return 0;
+
+ if (chip->type != SMBB)
+ return 0;
+
+ rc = qpnp_chg_read(chip, ®,
+ chip->buck_base + BUCK_CTRL_TRIM3, 1);
+ if (rc) {
+ pr_err("failed to read BUCK_CTRL_TRIM3 rc=%d\n", rc);
+ return rc;
+ }
+ if (reg & IBAT_TRIM_GOOD_BIT) {
+ pr_debug("IBAT_TRIM_GOOD bit already set. Quitting!\n");
+ return 0;
+ }
+ ibat_trim = reg & IBAT_TRIM_OFFSET_MASK;
+
+ if (!is_within_range(ibat_trim, IBAT_TRIM_LOW_LIM,
+ IBAT_TRIM_HIGH_LIM)) {
+ pr_debug("Improper ibat_trim value=%x setting to value=%x\n",
+ ibat_trim, IBAT_TRIM_MEAN);
+ ibat_trim = IBAT_TRIM_MEAN;
+ rc = qpnp_chg_masked_write(chip,
+ chip->buck_base + BUCK_CTRL_TRIM3,
+ IBAT_TRIM_OFFSET_MASK, ibat_trim, 1);
+ if (rc) {
+ pr_err("failed to set ibat_trim to %x rc=%d\n",
+ IBAT_TRIM_MEAN, rc);
+ return rc;
+ }
+ }
+
+ rc = qpnp_chg_read(chip, &chgr_sts,
+ INT_RT_STS(chip->chgr_base), 1);
+ if (rc) {
+ pr_err("failed to read interrupt sts rc=%d\n", rc);
+ return rc;
+ }
+ if (!(chgr_sts & FAST_CHG_ON_IRQ)) {
+ pr_debug("Not in fastchg\n");
+ return rc;
+ }
+
+ /* save the ibat_max to restore it later */
+ rc = qpnp_chg_ibatmax_get(chip, &ibat_max_ma);
+ if (rc) {
+ pr_debug("failed to save ibatmax rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = qpnp_chg_ibatmax_set(chip, IBAT_TRIM_TGT_MA);
+ if (rc) {
+ pr_err("failed to set ibatmax rc=%d\n", rc);
+ return rc;
+ }
+
+ for (i = 0; i < 3; i++) {
+ /*
+ * ibat settling delay - to make sure the BMS controller
+ * has sufficient time to sample ibat for the configured
+ * ibat_max
+ */
+ msleep(20);
+ if (qpnp_chg_is_ibat_loop_active(chip))
+ qpnp_chg_trim_ibat(chip, ibat_trim);
+ else
+ pr_debug("ibat loop not active\n");
+
+ /* read the adjusted ibat_trim for further adjustments */
+ rc = qpnp_chg_read(chip, &ibat_trim,
+ chip->buck_base + BUCK_CTRL_TRIM3, 1);
+ if (rc) {
+ pr_err("failed to read BUCK_CTRL_TRIM3 rc=%d\n", rc);
+ break;
+ }
+ }
+
+ /* restore IBATMAX */
+ rc = qpnp_chg_ibatmax_set(chip, ibat_max_ma);
+ if (rc)
+ pr_err("failed to restore ibatmax rc=%d\n", rc);
+
+ return rc;
+}
+
+
#define BOOST_MIN_UV 4200000
#define BOOST_MAX_UV 5500000
#define BOOST_STEP_UV 50000
@@ -2875,10 +3135,17 @@
count = 0;
} else {
if (count == CONSECUTIVE_COUNT) {
- pr_info("End of Charging\n");
+ if (!chip->bat_is_cool && !chip->bat_is_warm) {
+ pr_info("End of Charging\n");
+ chip->chg_done = true;
+ } else {
+ pr_info("stop charging: battery is %s, vddmax = %d reached\n",
+ chip->bat_is_cool
+ ? "cool" : "warm",
+ qpnp_chg_vddmax_get(chip));
+ }
chip->delta_vddmax_mv = 0;
qpnp_chg_set_appropriate_vddmax(chip);
- chip->chg_done = true;
qpnp_chg_charge_en(chip, 0);
/* sleep for a second before enabling */
msleep(2000);
@@ -3352,6 +3619,10 @@
case POWER_SUPPLY_PROP_WARM_TEMP:
rc = qpnp_chg_configure_jeita(chip, psp, val->intval);
break;
+ case POWER_SUPPLY_PROP_CAPACITY:
+ chip->fake_battery_soc = val->intval;
+ power_supply_changed(&chip->batt_psy);
+ break;
case POWER_SUPPLY_PROP_CHARGING_ENABLED:
chip->charging_disabled = !(val->intval);
if (chip->charging_disabled) {
@@ -3370,11 +3641,15 @@
qpnp_batt_system_temp_level_set(chip, val->intval);
break;
case POWER_SUPPLY_PROP_INPUT_CURRENT_MAX:
- qpnp_chg_iusbmax_set(chip, val->intval / 1000);
+ if (qpnp_chg_is_usb_chg_plugged_in(chip))
+ qpnp_chg_iusbmax_set(chip, val->intval / 1000);
break;
case POWER_SUPPLY_PROP_INPUT_CURRENT_TRIM:
qpnp_chg_iusb_trim_set(chip, val->intval);
break;
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED:
+ qpnp_chg_input_current_settled(chip);
+ break;
case POWER_SUPPLY_PROP_VOLTAGE_MIN:
qpnp_chg_vinmin_set(chip, val->intval / 1000);
break;
@@ -4096,6 +4371,11 @@
return rc;
}
+ /* Get the use-external-rsense property */
+ chip->use_external_rsense = of_property_read_bool(
+ chip->spmi->dev.of_node,
+ "qcom,use-external-rsense");
+
/* Get the btc-disabled property */
chip->btc_disabled = of_property_read_bool(chip->spmi->dev.of_node,
"qcom,btc-disabled");
@@ -4124,17 +4404,25 @@
if (chip->use_default_batt_values)
chip->charging_disabled = true;
+ chip->power_stage_workaround_enable =
+ of_property_read_bool(chip->spmi->dev.of_node,
+ "qcom,power-stage-reduced");
+
+ chip->ibat_calibration_enabled =
+ of_property_read_bool(chip->spmi->dev.of_node,
+ "qcom,ibat-calibration-enabled");
+
of_get_property(chip->spmi->dev.of_node, "qcom,thermal-mitigation",
&(chip->thermal_levels));
if (chip->thermal_levels > sizeof(int)) {
- chip->thermal_mitigation = kzalloc(
+ chip->thermal_mitigation = devm_kzalloc(chip->dev,
chip->thermal_levels,
GFP_KERNEL);
if (chip->thermal_mitigation == NULL) {
pr_err("thermal mitigation kzalloc() failed.\n");
- return rc;
+ return -ENOMEM;
}
chip->thermal_levels /= sizeof(int);
@@ -4159,13 +4447,15 @@
struct spmi_resource *spmi_resource;
int rc = 0;
- chip = kzalloc(sizeof *chip, GFP_KERNEL);
+ chip = devm_kzalloc(&spmi->dev,
+ sizeof(struct qpnp_chg_chip), GFP_KERNEL);
if (chip == NULL) {
pr_err("kzalloc() failed.\n");
return -ENOMEM;
}
chip->prev_usb_max_ma = -EINVAL;
+ chip->fake_battery_soc = -EINVAL;
chip->dev = &(spmi->dev);
chip->spmi = spmi;
@@ -4191,7 +4481,7 @@
/* Get all device tree properties */
rc = qpnp_charger_read_dt_props(chip);
if (rc)
- goto fail_chg_enable;
+ return rc;
/*
* Check if bat_if is set in DT and make sure VADC is present
@@ -4231,6 +4521,17 @@
goto fail_chg_enable;
}
+ if (subtype == SMBB_BAT_IF_SUBTYPE) {
+ chip->iadc_dev = qpnp_get_iadc(chip->dev,
+ "chg");
+ if (IS_ERR(chip->iadc_dev)) {
+ rc = PTR_ERR(chip->iadc_dev);
+ if (rc != -EPROBE_DEFER)
+ pr_err("iadc property missing\n");
+ goto fail_chg_enable;
+ }
+ }
+
rc = qpnp_chg_load_battery_data(chip);
if (rc)
goto fail_chg_enable;
@@ -4473,6 +4774,7 @@
goto unregister_dc_psy;
}
+ qpnp_chg_usb_chg_gone_irq_handler(chip->chg_gone.irq, chip);
qpnp_chg_usb_usbin_valid_irq_handler(chip->usbin_valid.irq, chip);
qpnp_chg_dc_dcin_valid_irq_handler(chip->dcin_valid.irq, chip);
power_supply_set_present(chip->usb_psy,
@@ -4503,9 +4805,6 @@
fail_chg_enable:
regulator_unregister(chip->otg_vreg.rdev);
regulator_unregister(chip->boost_vreg.rdev);
- kfree(chip->thermal_mitigation);
- kfree(chip);
- dev_set_drvdata(&spmi->dev, NULL);
return rc;
}
@@ -4518,15 +4817,27 @@
qpnp_adc_tm_disable_chan_meas(chip->adc_tm_dev,
&chip->adc_param);
}
- cancel_work_sync(&chip->adc_measure_work);
+
+ cancel_delayed_work_sync(&chip->aicl_check_work);
+ power_supply_unregister(&chip->dc_psy);
+ cancel_work_sync(&chip->soc_check_work);
+ cancel_delayed_work_sync(&chip->usbin_health_check);
+ cancel_delayed_work_sync(&chip->arb_stop_work);
cancel_delayed_work_sync(&chip->eoc_work);
+ cancel_work_sync(&chip->adc_disable_work);
+ cancel_work_sync(&chip->adc_measure_work);
+ power_supply_unregister(&chip->batt_psy);
+ cancel_work_sync(&chip->batfet_lcl_work);
+ cancel_work_sync(&chip->insertion_ocv_work);
+ cancel_work_sync(&chip->reduce_power_stage_work);
+ alarm_cancel(&chip->reduce_power_stage_alarm);
+
+ mutex_destroy(&chip->batfet_vreg_lock);
+ mutex_destroy(&chip->jeita_configure_lock);
regulator_unregister(chip->otg_vreg.rdev);
regulator_unregister(chip->boost_vreg.rdev);
- dev_set_drvdata(&spmi->dev, NULL);
- kfree(chip);
-
return 0;
}
diff --git a/drivers/rtc/alarm.c b/drivers/rtc/alarm.c
index 7d59e28..51e176f 100644
--- a/drivers/rtc/alarm.c
+++ b/drivers/rtc/alarm.c
@@ -553,8 +553,8 @@
return;
disable_alarm:
- rtc_alarm_irq_enable(alarm_rtc_dev, 0);
spin_unlock_irqrestore(&alarm_slock, flags);
+ rtc_alarm_irq_enable(alarm_rtc_dev, 0);
}
static struct rtc_task alarm_rtc_task = {
diff --git a/drivers/sensors/Kconfig b/drivers/sensors/Kconfig
new file mode 100644
index 0000000..2d81924
--- /dev/null
+++ b/drivers/sensors/Kconfig
@@ -0,0 +1,5 @@
+config SENSORS
+ bool "Sensors Class Support"
+ help
+ This option enables the sensor sysfs class in /sys/class/sensors.
+ You'll need this to do anything useful with sensorss. If unsure, say N.
diff --git a/drivers/sensors/Makefile b/drivers/sensors/Makefile
new file mode 100644
index 0000000..3a2a848
--- /dev/null
+++ b/drivers/sensors/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_SENSORS) += sensors_class.o
diff --git a/drivers/sensors/sensors_class.c b/drivers/sensors/sensors_class.c
new file mode 100644
index 0000000..bbf168c
--- /dev/null
+++ b/drivers/sensors/sensors_class.c
@@ -0,0 +1,249 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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/kernel.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+#include <linux/rwsem.h>
+#include <linux/sensors.h>
+
+static struct class *sensors_class;
+
+DECLARE_RWSEM(sensors_list_lock);
+LIST_HEAD(sensors_list);
+
+static ssize_t sensors_name_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct sensors_classdev *sensors_cdev = dev_get_drvdata(dev);
+ return snprintf(buf, PAGE_SIZE, "%s\n", sensors_cdev->name);
+}
+
+static ssize_t sensors_vendor_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct sensors_classdev *sensors_cdev = dev_get_drvdata(dev);
+ return snprintf(buf, PAGE_SIZE, "%s\n", sensors_cdev->vendor);
+}
+
+static ssize_t sensors_version_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct sensors_classdev *sensors_cdev = dev_get_drvdata(dev);
+ return snprintf(buf, PAGE_SIZE, "%d\n", sensors_cdev->version);
+}
+
+static ssize_t sensors_handle_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct sensors_classdev *sensors_cdev = dev_get_drvdata(dev);
+ return snprintf(buf, PAGE_SIZE, "%d\n", sensors_cdev->handle);
+}
+
+static ssize_t sensors_type_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct sensors_classdev *sensors_cdev = dev_get_drvdata(dev);
+ return snprintf(buf, PAGE_SIZE, "%d\n", sensors_cdev->type);
+}
+
+static ssize_t sensors_max_range_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct sensors_classdev *sensors_cdev = dev_get_drvdata(dev);
+ return snprintf(buf, PAGE_SIZE, "%s\n", sensors_cdev->max_range);
+}
+
+static ssize_t sensors_resolution_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct sensors_classdev *sensors_cdev = dev_get_drvdata(dev);
+ return snprintf(buf, PAGE_SIZE, "%s\n", sensors_cdev->resolution);
+}
+
+static ssize_t sensors_power_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct sensors_classdev *sensors_cdev = dev_get_drvdata(dev);
+ return snprintf(buf, PAGE_SIZE, "%s\n", sensors_cdev->sensor_power);
+}
+
+static ssize_t sensors_min_delay_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct sensors_classdev *sensors_cdev = dev_get_drvdata(dev);
+ return snprintf(buf, PAGE_SIZE, "%d\n", sensors_cdev->min_delay);
+}
+
+static ssize_t sensors_fifo_event_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct sensors_classdev *sensors_cdev = dev_get_drvdata(dev);
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ sensors_cdev->fifo_reserved_event_count);
+}
+
+static ssize_t sensors_fifo_max_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct sensors_classdev *sensors_cdev = dev_get_drvdata(dev);
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ sensors_cdev->fifo_max_event_count);
+}
+
+static ssize_t sensors_enable_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct sensors_classdev *sensors_cdev = dev_get_drvdata(dev);
+ ssize_t ret = -EINVAL;
+ unsigned long data = 0;
+
+ ret = kstrtoul(buf, 10, &data);
+ if (ret)
+ return ret;
+ if (data > 1) {
+ dev_err(dev, "Invalid value of input, input=%ld\n", data);
+ return -EINVAL;
+ }
+
+ if (sensors_cdev->sensors_enable == NULL) {
+ dev_err(dev, "Invalid sensor class enable handle\n");
+ return -EINVAL;
+ }
+ ret = sensors_cdev->sensors_enable(sensors_cdev, data);
+ if (ret)
+ return ret;
+
+ sensors_cdev->enabled = data;
+ return size;
+}
+
+
+static ssize_t sensors_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct sensors_classdev *sensors_cdev = dev_get_drvdata(dev);
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ sensors_cdev->enabled);
+}
+
+static ssize_t sensors_delay_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct sensors_classdev *sensors_cdev = dev_get_drvdata(dev);
+ ssize_t ret = -EINVAL;
+ unsigned long data = 0;
+
+ ret = kstrtoul(buf, 10, &data);
+ if (ret)
+ return ret;
+ /* The data unit is millisecond, the min_delay unit is microseconds. */
+ if ((data * 1000) < sensors_cdev->min_delay) {
+ dev_err(dev, "Invalid value of delay, delay=%ld\n", data);
+ return -EINVAL;
+ }
+ if (sensors_cdev->sensors_poll_delay == NULL) {
+ dev_err(dev, "Invalid sensor class delay handle\n");
+ return -EINVAL;
+ }
+ ret = sensors_cdev->sensors_poll_delay(sensors_cdev, data);
+ if (ret)
+ return ret;
+
+ sensors_cdev->delay_msec = data;
+ return size;
+}
+
+static ssize_t sensors_delay_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct sensors_classdev *sensors_cdev = dev_get_drvdata(dev);
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ sensors_cdev->delay_msec);
+}
+
+
+static struct device_attribute sensors_class_attrs[] = {
+ __ATTR(name, 0444, sensors_name_show, NULL),
+ __ATTR(vendor, 0444, sensors_vendor_show, NULL),
+ __ATTR(version, 0444, sensors_version_show, NULL),
+ __ATTR(handle, 0444, sensors_handle_show, NULL),
+ __ATTR(type, 0444, sensors_type_show, NULL),
+ __ATTR(max_range, 0444, sensors_max_range_show, NULL),
+ __ATTR(resolution, 0444, sensors_resolution_show, NULL),
+ __ATTR(sensor_power, 0444, sensors_power_show, NULL),
+ __ATTR(min_delay, 0444, sensors_min_delay_show, NULL),
+ __ATTR(fifo_reserved_event_count, 0444, sensors_fifo_event_show, NULL),
+ __ATTR(fifo_max_event_count, 0444, sensors_fifo_max_show, NULL),
+ __ATTR(enable, 0664, sensors_enable_show, sensors_enable_store),
+ __ATTR(poll_delay, 0664, sensors_delay_show, sensors_delay_store),
+ __ATTR_NULL,
+};
+
+/**
+ * sensors_classdev_register - register a new object of sensors_classdev class.
+ * @parent: The device to register.
+ * @sensors_cdev: the sensors_classdev structure for this device.
+*/
+int sensors_classdev_register(struct device *parent,
+ struct sensors_classdev *sensors_cdev)
+{
+ sensors_cdev->dev = device_create(sensors_class, parent, 0,
+ sensors_cdev, "%s", sensors_cdev->name);
+ if (IS_ERR(sensors_cdev->dev))
+ return PTR_ERR(sensors_cdev->dev);
+
+ down_write(&sensors_list_lock);
+ list_add_tail(&sensors_cdev->node, &sensors_list);
+ up_write(&sensors_list_lock);
+
+ pr_debug("Registered sensors device: %s\n",
+ sensors_cdev->name);
+ return 0;
+}
+EXPORT_SYMBOL(sensors_classdev_register);
+
+/**
+ * sensors_classdev_unregister - unregister a object of sensors class.
+ * @sensors_cdev: the sensor device to unregister
+ * Unregister a previously registered via sensors_classdev_register object.
+*/
+void sensors_classdev_unregister(struct sensors_classdev *sensors_cdev)
+{
+ device_unregister(sensors_cdev->dev);
+ down_write(&sensors_list_lock);
+ list_del(&sensors_cdev->node);
+ up_write(&sensors_list_lock);
+}
+EXPORT_SYMBOL(sensors_classdev_unregister);
+
+static int __init sensors_init(void)
+{
+ sensors_class = class_create(THIS_MODULE, "sensors");
+ if (IS_ERR(sensors_class))
+ return PTR_ERR(sensors_class);
+ sensors_class->dev_attrs = sensors_class_attrs;
+ return 0;
+}
+
+static void __exit sensors_exit(void)
+{
+ class_destroy(sensors_class);
+}
+
+subsys_initcall(sensors_init);
+module_exit(sensors_exit);
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index 0c9959c..adca457 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -973,6 +973,7 @@
struct slim_controller *ctrl = &dev->ctrl;
struct slim_device *sbdev;
int i;
+ slim_framer_booted(ctrl);
mutex_lock(&ctrl->m_ctrl);
list_for_each_entry(sbdev, &ctrl->devs, dev_list) {
int ret = 0;
@@ -1065,7 +1066,7 @@
}
dev = kzalloc(sizeof(struct msm_slim_ctrl), GFP_KERNEL);
- if (IS_ERR(dev)) {
+ if (IS_ERR_OR_NULL(dev)) {
dev_err(&pdev->dev, "no memory for MSM slimbus controller\n");
return PTR_ERR(dev);
}
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index b074289..f6594c8 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -650,6 +650,36 @@
EXPORT_SYMBOL(slim_report_absent);
/*
+ * slim_framer_booted: This function is called by controller after the active
+ * framer has booted (using Bus Reset sequence, or after it has shutdown and has
+ * come back up). Components, devices on the bus may be in undefined state,
+ * and this function triggers their drivers to do the needful
+ * to bring them back in Reset state so that they can acquire sync, report
+ * present and be operational again.
+ */
+void slim_framer_booted(struct slim_controller *ctrl)
+{
+ struct slim_device *sbdev;
+ struct list_head *pos, *next;
+ if (!ctrl)
+ return;
+ mutex_lock(&ctrl->m_ctrl);
+ list_for_each_safe(pos, next, &ctrl->devs) {
+ struct slim_driver *sbdrv;
+ sbdev = list_entry(pos, struct slim_device, dev_list);
+ mutex_unlock(&ctrl->m_ctrl);
+ if (sbdev && sbdev->dev.driver) {
+ sbdrv = to_slim_driver(sbdev->dev.driver);
+ if (sbdrv->reset_device)
+ sbdrv->reset_device(sbdev);
+ }
+ mutex_lock(&ctrl->m_ctrl);
+ }
+ mutex_unlock(&ctrl->m_ctrl);
+}
+EXPORT_SYMBOL(slim_framer_booted);
+
+/*
* slim_msg_response: Deliver Message response received from a device to the
* framework.
* @ctrl: Controller handle
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
index bc328e0..e3284d5 100644
--- a/drivers/spmi/spmi-pmic-arb.c
+++ b/drivers/spmi/spmi-pmic-arb.c
@@ -223,7 +223,9 @@
if (opc < SPMI_CMD_RESET || opc > SPMI_CMD_WAKEUP)
return -EINVAL;
- cmd = ((opc | 0x40) << 27) | ((sid & 0xf) << 20);
+ opc -= SPMI_CMD_RESET - PMIC_ARB_OP_RESET;
+
+ cmd = (opc << 27) | ((sid & 0xf) << 20);
spin_lock_irqsave(&pmic_arb->lock, flags);
pmic_arb_write(pmic_arb, PMIC_ARB_CMD(pmic_arb->channel), cmd);
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index 4251968..1ad0054 100644
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -40,6 +40,7 @@
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/swap.h>
+#include <linux/fs.h>
#ifdef CONFIG_HIGHMEM
#define _ZONE ZONE_HIGHMEM
@@ -246,8 +247,14 @@
}
other_free = global_page_state(NR_FREE_PAGES);
- other_file = global_page_state(NR_FILE_PAGES) -
- global_page_state(NR_SHMEM);
+
+ if (global_page_state(NR_SHMEM) + total_swapcache_pages <
+ global_page_state(NR_FILE_PAGES))
+ other_file = global_page_state(NR_FILE_PAGES) -
+ global_page_state(NR_SHMEM) -
+ total_swapcache_pages;
+ else
+ other_file = 0;
tune_lmk_param(&other_free, &other_file, sc);
diff --git a/drivers/staging/zram/Kconfig b/drivers/staging/zram/Kconfig
index 9d11a4c..983314c 100644
--- a/drivers/staging/zram/Kconfig
+++ b/drivers/staging/zram/Kconfig
@@ -1,9 +1,6 @@
config ZRAM
tristate "Compressed RAM block device support"
- # X86 dependency is because zsmalloc uses non-portable pte/tlb
- # functions
- depends on BLOCK && SYSFS && X86
- select ZSMALLOC
+ depends on BLOCK && SYSFS && ZSMALLOC
select LZO_COMPRESS
select LZO_DECOMPRESS
default n
@@ -17,7 +14,7 @@
disks and maybe many more.
See zram.txt for more information.
- Project home: http://compcache.googlecode.com/
+ Project home: <https://compcache.googlecode.com/>
config ZRAM_DEBUG
bool "Compressed RAM block device debug support"
diff --git a/drivers/staging/zram/Makefile b/drivers/staging/zram/Makefile
index 7f4a301..cb0f9ce 100644
--- a/drivers/staging/zram/Makefile
+++ b/drivers/staging/zram/Makefile
@@ -1,3 +1,3 @@
-zram-y := zram_drv.o zram_sysfs.o
+zram-y := zram_drv.o
obj-$(CONFIG_ZRAM) += zram.o
diff --git a/drivers/staging/zram/zram.txt b/drivers/staging/zram/zram.txt
index 5f75d29..765d790 100644
--- a/drivers/staging/zram/zram.txt
+++ b/drivers/staging/zram/zram.txt
@@ -23,17 +23,17 @@
This creates 4 devices: /dev/zram{0,1,2,3}
(num_devices parameter is optional. Default: 1)
-2) Set Disksize (Optional):
- Set disk size by writing the value to sysfs node 'disksize'
- (in bytes). If disksize is not given, default value of 25%
- of RAM is used.
+2) Set Disksize
+ Set disk size by writing the value to sysfs node 'disksize'.
+ The value can be either in bytes or you can use mem suffixes.
+ Examples:
+ # Initialize /dev/zram0 with 50MB disksize
+ echo $((50*1024*1024)) > /sys/block/zram0/disksize
- # Initialize /dev/zram0 with 50MB disksize
- echo $((50*1024*1024)) > /sys/block/zram0/disksize
-
- NOTE: disksize cannot be changed if the disk contains any
- data. So, for such a disk, you need to issue 'reset' (see below)
- before you can change its disksize.
+ # Using mem suffixes
+ echo 256K > /sys/block/zram0/disksize
+ echo 512M > /sys/block/zram0/disksize
+ echo 1G > /sys/block/zram0/disksize
3) Activate:
mkswap /dev/zram0
@@ -65,8 +65,9 @@
echo 1 > /sys/block/zram0/reset
echo 1 > /sys/block/zram1/reset
- (This frees all the memory allocated for the given device).
-
+ This frees all the memory allocated for the given device and
+ resets the disksize to zero. You must set the disksize again
+ before reusing the device.
Please report any problems at:
- Mailing list: linux-mm-cc at laptop dot org
diff --git a/drivers/staging/zram/zram_drv.c b/drivers/staging/zram/zram_drv.c
index 685d612..83fa657 100644
--- a/drivers/staging/zram/zram_drv.c
+++ b/drivers/staging/zram/zram_drv.c
@@ -32,61 +32,229 @@
#include <linux/lzo.h>
#include <linux/string.h>
#include <linux/vmalloc.h>
+#include <linux/ratelimit.h>
#include "zram_drv.h"
/* Globals */
static int zram_major;
-struct zram *zram_devices;
+static struct zram *zram_devices;
+
+/*
+ * We don't need to see memory allocation errors more than once every 1
+ * second to know that a problem is occurring.
+ */
+#define ALLOC_ERROR_LOG_RATE_MS 1000
/* Module params (documentation at end) */
-static unsigned int num_devices;
+static unsigned int num_devices = 1;
-static void zram_stat_inc(u32 *v)
+static inline struct zram *dev_to_zram(struct device *dev)
{
- *v = *v + 1;
+ return (struct zram *)dev_to_disk(dev)->private_data;
}
-static void zram_stat_dec(u32 *v)
+static ssize_t disksize_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- *v = *v - 1;
+ struct zram *zram = dev_to_zram(dev);
+
+ return sprintf(buf, "%llu\n", zram->disksize);
}
-static void zram_stat64_add(struct zram *zram, u64 *v, u64 inc)
+static ssize_t initstate_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- spin_lock(&zram->stat64_lock);
- *v = *v + inc;
- spin_unlock(&zram->stat64_lock);
+ struct zram *zram = dev_to_zram(dev);
+
+ return sprintf(buf, "%u\n", zram->init_done);
}
-static void zram_stat64_sub(struct zram *zram, u64 *v, u64 dec)
+static ssize_t num_reads_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- spin_lock(&zram->stat64_lock);
- *v = *v - dec;
- spin_unlock(&zram->stat64_lock);
+ struct zram *zram = dev_to_zram(dev);
+
+ return sprintf(buf, "%llu\n",
+ (u64)atomic64_read(&zram->stats.num_reads));
}
-static void zram_stat64_inc(struct zram *zram, u64 *v)
+static ssize_t num_writes_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- zram_stat64_add(zram, v, 1);
+ struct zram *zram = dev_to_zram(dev);
+
+ return sprintf(buf, "%llu\n",
+ (u64)atomic64_read(&zram->stats.num_writes));
}
-static int zram_test_flag(struct zram *zram, u32 index,
+static ssize_t invalid_io_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct zram *zram = dev_to_zram(dev);
+
+ return sprintf(buf, "%llu\n",
+ (u64)atomic64_read(&zram->stats.invalid_io));
+}
+
+static ssize_t notify_free_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct zram *zram = dev_to_zram(dev);
+
+ return sprintf(buf, "%llu\n",
+ (u64)atomic64_read(&zram->stats.notify_free));
+}
+
+static ssize_t zero_pages_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct zram *zram = dev_to_zram(dev);
+
+ return sprintf(buf, "%u\n", zram->stats.pages_zero);
+}
+
+static ssize_t orig_data_size_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct zram *zram = dev_to_zram(dev);
+
+ return sprintf(buf, "%llu\n",
+ (u64)(zram->stats.pages_stored) << PAGE_SHIFT);
+}
+
+static ssize_t compr_data_size_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct zram *zram = dev_to_zram(dev);
+
+ return sprintf(buf, "%llu\n",
+ (u64)atomic64_read(&zram->stats.compr_size));
+}
+
+static ssize_t mem_used_total_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ u64 val = 0;
+ struct zram *zram = dev_to_zram(dev);
+ struct zram_meta *meta = zram->meta;
+
+ down_read(&zram->init_lock);
+ if (zram->init_done)
+ val = zs_get_total_size_bytes(meta->mem_pool);
+ up_read(&zram->init_lock);
+
+ return sprintf(buf, "%llu\n", val);
+}
+
+static int zram_test_flag(struct zram_meta *meta, u32 index,
enum zram_pageflags flag)
{
- return zram->table[index].flags & BIT(flag);
+ return meta->table[index].flags & BIT(flag);
}
-static void zram_set_flag(struct zram *zram, u32 index,
+static void zram_set_flag(struct zram_meta *meta, u32 index,
enum zram_pageflags flag)
{
- zram->table[index].flags |= BIT(flag);
+ meta->table[index].flags |= BIT(flag);
}
-static void zram_clear_flag(struct zram *zram, u32 index,
+static void zram_clear_flag(struct zram_meta *meta, u32 index,
enum zram_pageflags flag)
{
- zram->table[index].flags &= ~BIT(flag);
+ meta->table[index].flags &= ~BIT(flag);
+}
+
+static inline int is_partial_io(struct bio_vec *bvec)
+{
+ return bvec->bv_len != PAGE_SIZE;
+}
+
+/*
+ * Check if request is within bounds and aligned on zram logical blocks.
+ */
+static inline int valid_io_request(struct zram *zram, struct bio *bio)
+{
+ u64 start, end, bound;
+
+ /* unaligned request */
+ if (unlikely(bio->bi_sector & (ZRAM_SECTOR_PER_LOGICAL_BLOCK - 1)))
+ return 0;
+ if (unlikely(bio->bi_size & (ZRAM_LOGICAL_BLOCK_SIZE - 1)))
+ return 0;
+
+ start = bio->bi_sector;
+ end = start + (bio->bi_size >> SECTOR_SHIFT);
+ bound = zram->disksize >> SECTOR_SHIFT;
+ /* out of range range */
+ if (unlikely(start >= bound || end > bound || start > end))
+ return 0;
+
+ /* I/O request is valid */
+ return 1;
+}
+
+static void zram_meta_free(struct zram_meta *meta)
+{
+ zs_destroy_pool(meta->mem_pool);
+ kfree(meta->compress_workmem);
+ free_pages((unsigned long)meta->compress_buffer, 1);
+ vfree(meta->table);
+ kfree(meta);
+}
+
+static struct zram_meta *zram_meta_alloc(u64 disksize)
+{
+ size_t num_pages;
+ struct zram_meta *meta = kmalloc(sizeof(*meta), GFP_KERNEL);
+ if (!meta)
+ goto out;
+
+ meta->compress_workmem = kzalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
+ if (!meta->compress_workmem)
+ goto free_meta;
+
+ meta->compress_buffer =
+ (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 1);
+ if (!meta->compress_buffer) {
+ pr_err("Error allocating compressor buffer space\n");
+ goto free_workmem;
+ }
+
+ num_pages = disksize >> PAGE_SHIFT;
+ meta->table = vzalloc(num_pages * sizeof(*meta->table));
+ if (!meta->table) {
+ pr_err("Error allocating zram address table\n");
+ goto free_buffer;
+ }
+
+ meta->mem_pool = zs_create_pool(GFP_NOIO | __GFP_HIGHMEM |
+ __GFP_NOWARN);
+ if (!meta->mem_pool) {
+ pr_err("Error creating memory pool\n");
+ goto free_table;
+ }
+
+ return meta;
+
+free_table:
+ vfree(meta->table);
+free_buffer:
+ free_pages((unsigned long)meta->compress_buffer, 1);
+free_workmem:
+ kfree(meta->compress_workmem);
+free_meta:
+ kfree(meta);
+ meta = NULL;
+out:
+ return meta;
+}
+
+static void update_position(u32 *index, int *offset, struct bio_vec *bvec)
+{
+ if (*offset + bvec->bv_len >= PAGE_SIZE)
+ (*index)++;
+ *offset = (*offset + bvec->bv_len) % PAGE_SIZE;
}
static int page_zero_filled(void *ptr)
@@ -104,352 +272,272 @@
return 1;
}
-static void zram_set_disksize(struct zram *zram, size_t totalram_bytes)
-{
- if (!zram->disksize) {
- pr_info(
- "disk size not provided. You can use disksize_kb module "
- "param to specify size.\nUsing default: (%u%% of RAM).\n",
- default_disksize_perc_ram
- );
- zram->disksize = default_disksize_perc_ram *
- (totalram_bytes / 100);
- }
-
- if (zram->disksize > 2 * (totalram_bytes)) {
- pr_info(
- "There is little point creating a zram of greater than "
- "twice the size of memory since we expect a 2:1 compression "
- "ratio. Note that zram uses about 0.1%% of the size of "
- "the disk when not in use so a huge zram is "
- "wasteful.\n"
- "\tMemory Size: %zu kB\n"
- "\tSize you selected: %llu kB\n"
- "Continuing anyway ...\n",
- totalram_bytes >> 10, zram->disksize
- );
- }
-
- zram->disksize &= PAGE_MASK;
-}
-
-static void zram_free_page(struct zram *zram, size_t index)
-{
- void *handle = zram->table[index].handle;
-
- if (unlikely(!handle)) {
- /*
- * No memory is allocated for zero filled pages.
- * Simply clear zero page flag.
- */
- if (zram_test_flag(zram, index, ZRAM_ZERO)) {
- zram_clear_flag(zram, index, ZRAM_ZERO);
- zram_stat_dec(&zram->stats.pages_zero);
- }
- return;
- }
-
- if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED))) {
- __free_page(handle);
- zram_clear_flag(zram, index, ZRAM_UNCOMPRESSED);
- zram_stat_dec(&zram->stats.pages_expand);
- goto out;
- }
-
- zs_free(zram->mem_pool, handle);
-
- if (zram->table[index].size <= PAGE_SIZE / 2)
- zram_stat_dec(&zram->stats.good_compress);
-
-out:
- zram_stat64_sub(zram, &zram->stats.compr_size,
- zram->table[index].size);
- zram_stat_dec(&zram->stats.pages_stored);
-
- zram->table[index].handle = NULL;
- zram->table[index].size = 0;
-}
-
static void handle_zero_page(struct bio_vec *bvec)
{
struct page *page = bvec->bv_page;
void *user_mem;
user_mem = kmap_atomic(page);
- memset(user_mem + bvec->bv_offset, 0, bvec->bv_len);
+ if (is_partial_io(bvec))
+ memset(user_mem + bvec->bv_offset, 0, bvec->bv_len);
+ else
+ clear_page(user_mem);
kunmap_atomic(user_mem);
flush_dcache_page(page);
}
-static void handle_uncompressed_page(struct zram *zram, struct bio_vec *bvec,
- u32 index, int offset)
+static void zram_free_page(struct zram *zram, size_t index)
{
- struct page *page = bvec->bv_page;
- unsigned char *user_mem, *cmem;
+ struct zram_meta *meta = zram->meta;
+ unsigned long handle = meta->table[index].handle;
+ u16 size = meta->table[index].size;
- user_mem = kmap_atomic(page);
- cmem = kmap_atomic(zram->table[index].handle);
+ if (unlikely(!handle)) {
+ /*
+ * No memory is allocated for zero filled pages.
+ * Simply clear zero page flag.
+ */
+ if (zram_test_flag(meta, index, ZRAM_ZERO)) {
+ zram_clear_flag(meta, index, ZRAM_ZERO);
+ zram->stats.pages_zero--;
+ }
+ return;
+ }
- memcpy(user_mem + bvec->bv_offset, cmem + offset, bvec->bv_len);
- kunmap_atomic(cmem);
- kunmap_atomic(user_mem);
+ if (unlikely(size > max_zpage_size))
+ zram->stats.bad_compress--;
- flush_dcache_page(page);
+ zs_free(meta->mem_pool, handle);
+
+ if (size <= PAGE_SIZE / 2)
+ zram->stats.good_compress--;
+
+ atomic64_sub(meta->table[index].size, &zram->stats.compr_size);
+ zram->stats.pages_stored--;
+
+ meta->table[index].handle = 0;
+ meta->table[index].size = 0;
}
-static inline int is_partial_io(struct bio_vec *bvec)
+static int zram_decompress_page(struct zram *zram, char *mem, u32 index)
{
- return bvec->bv_len != PAGE_SIZE;
+ int ret = LZO_E_OK;
+ size_t clen = PAGE_SIZE;
+ unsigned char *cmem;
+ struct zram_meta *meta = zram->meta;
+ unsigned long handle = meta->table[index].handle;
+
+ if (!handle || zram_test_flag(meta, index, ZRAM_ZERO)) {
+ clear_page(mem);
+ return 0;
+ }
+
+ cmem = zs_map_object(meta->mem_pool, handle, ZS_MM_RO);
+ if (meta->table[index].size == PAGE_SIZE)
+ copy_page(mem, cmem);
+ else
+ ret = lzo1x_decompress_safe(cmem, meta->table[index].size,
+ mem, &clen);
+ zs_unmap_object(meta->mem_pool, handle);
+
+ /* Should NEVER happen. Return bio error if it does. */
+ if (unlikely(ret != LZO_E_OK)) {
+ pr_err("Decompression failed! err=%d, page=%u\n", ret, index);
+ atomic64_inc(&zram->stats.failed_reads);
+ return ret;
+ }
+
+ return 0;
}
static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec,
u32 index, int offset, struct bio *bio)
{
int ret;
- size_t clen;
struct page *page;
- struct zobj_header *zheader;
- unsigned char *user_mem, *cmem, *uncmem = NULL;
-
+ unsigned char *user_mem, *uncmem = NULL;
+ struct zram_meta *meta = zram->meta;
page = bvec->bv_page;
- if (zram_test_flag(zram, index, ZRAM_ZERO)) {
+ if (unlikely(!meta->table[index].handle) ||
+ zram_test_flag(meta, index, ZRAM_ZERO)) {
handle_zero_page(bvec);
return 0;
}
- /* Requested page is not present in compressed area */
- if (unlikely(!zram->table[index].handle)) {
- pr_debug("Read before write: sector=%lu, size=%u",
- (ulong)(bio->bi_sector), bio->bi_size);
- handle_zero_page(bvec);
- return 0;
- }
-
- /* Page is stored uncompressed since it's incompressible */
- if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED))) {
- handle_uncompressed_page(zram, bvec, index, offset);
- return 0;
- }
-
- if (is_partial_io(bvec)) {
+ if (is_partial_io(bvec))
/* Use a temporary buffer to decompress the page */
- uncmem = kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (!uncmem) {
- pr_info("Error allocating temp memory!\n");
- return -ENOMEM;
- }
- }
+ uncmem = kmalloc(PAGE_SIZE, GFP_NOIO);
user_mem = kmap_atomic(page);
if (!is_partial_io(bvec))
uncmem = user_mem;
- clen = PAGE_SIZE;
- cmem = zs_map_object(zram->mem_pool, zram->table[index].handle);
-
- ret = lzo1x_decompress_safe(cmem + sizeof(*zheader),
- zram->table[index].size,
- uncmem, &clen);
-
- if (is_partial_io(bvec)) {
- memcpy(user_mem + bvec->bv_offset, uncmem + offset,
- bvec->bv_len);
- kfree(uncmem);
+ if (!uncmem) {
+ pr_info("Unable to allocate temp memory\n");
+ ret = -ENOMEM;
+ goto out_cleanup;
}
- zs_unmap_object(zram->mem_pool, zram->table[index].handle);
- kunmap_atomic(user_mem);
-
+ ret = zram_decompress_page(zram, uncmem, index);
/* Should NEVER happen. Return bio error if it does. */
- if (unlikely(ret != LZO_E_OK)) {
- pr_err("Decompression failed! err=%d, page=%u\n", ret, index);
- zram_stat64_inc(zram, &zram->stats.failed_reads);
- return ret;
- }
+ if (unlikely(ret != LZO_E_OK))
+ goto out_cleanup;
+
+ if (is_partial_io(bvec))
+ memcpy(user_mem + bvec->bv_offset, uncmem + offset,
+ bvec->bv_len);
flush_dcache_page(page);
-
- return 0;
-}
-
-static int zram_read_before_write(struct zram *zram, char *mem, u32 index)
-{
- int ret;
- size_t clen = PAGE_SIZE;
- struct zobj_header *zheader;
- unsigned char *cmem;
-
- if (zram_test_flag(zram, index, ZRAM_ZERO) ||
- !zram->table[index].handle) {
- memset(mem, 0, PAGE_SIZE);
- return 0;
- }
-
- cmem = zs_map_object(zram->mem_pool, zram->table[index].handle);
-
- /* Page is stored uncompressed since it's incompressible */
- if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED))) {
- memcpy(mem, cmem, PAGE_SIZE);
- kunmap_atomic(cmem);
- return 0;
- }
-
- ret = lzo1x_decompress_safe(cmem + sizeof(*zheader),
- zram->table[index].size,
- mem, &clen);
- zs_unmap_object(zram->mem_pool, zram->table[index].handle);
-
- /* Should NEVER happen. Return bio error if it does. */
- if (unlikely(ret != LZO_E_OK)) {
- pr_err("Decompression failed! err=%d, page=%u\n", ret, index);
- zram_stat64_inc(zram, &zram->stats.failed_reads);
- return ret;
- }
-
- return 0;
+ ret = 0;
+out_cleanup:
+ kunmap_atomic(user_mem);
+ if (is_partial_io(bvec))
+ kfree(uncmem);
+ return ret;
}
static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
int offset)
{
- int ret;
- u32 store_offset;
+ int ret = 0;
size_t clen;
- void *handle;
- struct zobj_header *zheader;
- struct page *page, *page_store;
+ unsigned long handle;
+ struct page *page;
unsigned char *user_mem, *cmem, *src, *uncmem = NULL;
+ struct zram_meta *meta = zram->meta;
+ static unsigned long zram_rs_time;
page = bvec->bv_page;
- src = zram->compress_buffer;
+ src = meta->compress_buffer;
if (is_partial_io(bvec)) {
/*
* This is a partial IO. We need to read the full page
* before to write the changes.
*/
- uncmem = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ uncmem = kmalloc(PAGE_SIZE, GFP_NOIO);
if (!uncmem) {
- pr_info("Error allocating temp memory!\n");
ret = -ENOMEM;
goto out;
}
- ret = zram_read_before_write(zram, uncmem, index);
- if (ret) {
- kfree(uncmem);
+ ret = zram_decompress_page(zram, uncmem, index);
+ if (ret)
goto out;
- }
}
- /*
- * System overwrites unused sectors. Free memory associated
- * with this sector now.
- */
- if (zram->table[index].handle ||
- zram_test_flag(zram, index, ZRAM_ZERO))
- zram_free_page(zram, index);
-
user_mem = kmap_atomic(page);
- if (is_partial_io(bvec))
+ if (is_partial_io(bvec)) {
memcpy(uncmem + offset, user_mem + bvec->bv_offset,
bvec->bv_len);
- else
+ kunmap_atomic(user_mem);
+ user_mem = NULL;
+ } else {
uncmem = user_mem;
+ }
if (page_zero_filled(uncmem)) {
kunmap_atomic(user_mem);
- if (is_partial_io(bvec))
- kfree(uncmem);
- zram_stat_inc(&zram->stats.pages_zero);
- zram_set_flag(zram, index, ZRAM_ZERO);
+ /* Free memory associated with this sector now. */
+ zram_free_page(zram, index);
+
+ zram->stats.pages_zero++;
+ zram_set_flag(meta, index, ZRAM_ZERO);
ret = 0;
goto out;
}
- ret = lzo1x_1_compress(uncmem, PAGE_SIZE, src, &clen,
- zram->compress_workmem);
+ /*
+ * zram_slot_free_notify could miss free so that let's
+ * double check.
+ */
+ if (unlikely(meta->table[index].handle ||
+ zram_test_flag(meta, index, ZRAM_ZERO)))
+ zram_free_page(zram, index);
- kunmap_atomic(user_mem);
- if (is_partial_io(bvec))
- kfree(uncmem);
+ ret = lzo1x_1_compress(uncmem, PAGE_SIZE, src, &clen,
+ meta->compress_workmem);
+
+ if (!is_partial_io(bvec)) {
+ kunmap_atomic(user_mem);
+ user_mem = NULL;
+ uncmem = NULL;
+ }
if (unlikely(ret != LZO_E_OK)) {
pr_err("Compression failed! err=%d\n", ret);
goto out;
}
- /*
- * Page is incompressible. Store it as-is (uncompressed)
- * since we do not want to return too many disk write
- * errors which has side effect of hanging the system.
- */
if (unlikely(clen > max_zpage_size)) {
+ zram->stats.bad_compress++;
clen = PAGE_SIZE;
- page_store = alloc_page(GFP_NOIO | __GFP_HIGHMEM);
- if (unlikely(!page_store)) {
- pr_info("Error allocating memory for "
- "incompressible page: %u\n", index);
- ret = -ENOMEM;
- goto out;
- }
-
- store_offset = 0;
- zram_set_flag(zram, index, ZRAM_UNCOMPRESSED);
- zram_stat_inc(&zram->stats.pages_expand);
- handle = page_store;
- src = kmap_atomic(page);
- cmem = kmap_atomic(page_store);
- goto memstore;
+ src = NULL;
+ if (is_partial_io(bvec))
+ src = uncmem;
}
- handle = zs_malloc(zram->mem_pool, clen + sizeof(*zheader));
+ handle = zs_malloc(meta->mem_pool, clen);
if (!handle) {
- pr_info("Error allocating memory for compressed "
- "page: %u, size=%zu\n", index, clen);
+ if (printk_timed_ratelimit(&zram_rs_time,
+ ALLOC_ERROR_LOG_RATE_MS))
+ pr_info("Error allocating memory for compressed page: %u, size=%zu\n",
+ index, clen);
ret = -ENOMEM;
goto out;
}
- cmem = zs_map_object(zram->mem_pool, handle);
+ cmem = zs_map_object(meta->mem_pool, handle, ZS_MM_WO);
-memstore:
-#if 0
- /* Back-reference needed for memory defragmentation */
- if (!zram_test_flag(zram, index, ZRAM_UNCOMPRESSED)) {
- zheader = (struct zobj_header *)cmem;
- zheader->table_idx = index;
- cmem += sizeof(*zheader);
- }
-#endif
-
- memcpy(cmem, src, clen);
-
- if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED))) {
- kunmap_atomic(cmem);
+ if ((clen == PAGE_SIZE) && !is_partial_io(bvec)) {
+ src = kmap_atomic(page);
+ copy_page(cmem, src);
kunmap_atomic(src);
} else {
- zs_unmap_object(zram->mem_pool, handle);
+ memcpy(cmem, src, clen);
}
- zram->table[index].handle = handle;
- zram->table[index].size = clen;
+ zs_unmap_object(meta->mem_pool, handle);
+
+ /*
+ * Free memory associated with this sector
+ * before overwriting unused sectors.
+ */
+ zram_free_page(zram, index);
+
+ meta->table[index].handle = handle;
+ meta->table[index].size = clen;
/* Update stats */
- zram_stat64_add(zram, &zram->stats.compr_size, clen);
- zram_stat_inc(&zram->stats.pages_stored);
+ atomic64_add(clen, &zram->stats.compr_size);
+ zram->stats.pages_stored++;
if (clen <= PAGE_SIZE / 2)
- zram_stat_inc(&zram->stats.good_compress);
-
- return 0;
+ zram->stats.good_compress++;
out:
+ if (is_partial_io(bvec))
+ kfree(uncmem);
+
if (ret)
- zram_stat64_inc(zram, &zram->stats.failed_writes);
+ atomic64_inc(&zram->stats.failed_writes);
return ret;
}
+static void handle_pending_slot_free(struct zram *zram)
+{
+ struct zram_slot_free *free_rq;
+
+ spin_lock(&zram->slot_free_lock);
+ while (zram->slot_free_rq) {
+ free_rq = zram->slot_free_rq;
+ zram->slot_free_rq = free_rq->next;
+ zram_free_page(zram, free_rq->index);
+ kfree(free_rq);
+ }
+ spin_unlock(&zram->slot_free_lock);
+}
+
static int zram_bvec_rw(struct zram *zram, struct bio_vec *bvec, u32 index,
int offset, struct bio *bio, int rw)
{
@@ -457,10 +545,12 @@
if (rw == READ) {
down_read(&zram->lock);
+ handle_pending_slot_free(zram);
ret = zram_bvec_read(zram, bvec, index, offset, bio);
up_read(&zram->lock);
} else {
down_write(&zram->lock);
+ handle_pending_slot_free(zram);
ret = zram_bvec_write(zram, bvec, index, offset);
up_write(&zram->lock);
}
@@ -468,11 +558,124 @@
return ret;
}
-static void update_position(u32 *index, int *offset, struct bio_vec *bvec)
+static void zram_reset_device(struct zram *zram, bool reset_capacity)
{
- if (*offset + bvec->bv_len >= PAGE_SIZE)
- (*index)++;
- *offset = (*offset + bvec->bv_len) % PAGE_SIZE;
+ size_t index;
+ struct zram_meta *meta;
+
+ flush_work(&zram->free_work);
+
+ down_write(&zram->init_lock);
+ if (!zram->init_done) {
+ up_write(&zram->init_lock);
+ return;
+ }
+
+ meta = zram->meta;
+ zram->init_done = 0;
+
+ /* Free all pages that are still in this zram device */
+ for (index = 0; index < zram->disksize >> PAGE_SHIFT; index++) {
+ unsigned long handle = meta->table[index].handle;
+ if (!handle)
+ continue;
+
+ zs_free(meta->mem_pool, handle);
+ }
+
+ zram_meta_free(zram->meta);
+ zram->meta = NULL;
+ /* Reset stats */
+ memset(&zram->stats, 0, sizeof(zram->stats));
+
+ zram->disksize = 0;
+ if (reset_capacity)
+ set_capacity(zram->disk, 0);
+ up_write(&zram->init_lock);
+}
+
+static void zram_init_device(struct zram *zram, struct zram_meta *meta)
+{
+ if (zram->disksize > 2 * (totalram_pages << PAGE_SHIFT)) {
+ pr_info(
+ "There is little point creating a zram of greater than "
+ "twice the size of memory since we expect a 2:1 compression "
+ "ratio. Note that zram uses about 0.1%% of the size of "
+ "the disk when not in use so a huge zram is "
+ "wasteful.\n"
+ "\tMemory Size: %lu kB\n"
+ "\tSize you selected: %llu kB\n"
+ "Continuing anyway ...\n",
+ (totalram_pages << PAGE_SHIFT) >> 10, zram->disksize >> 10
+ );
+ }
+
+ /* zram devices sort of resembles non-rotational disks */
+ queue_flag_set_unlocked(QUEUE_FLAG_NONROT, zram->disk->queue);
+
+ zram->meta = meta;
+ zram->init_done = 1;
+
+ pr_debug("Initialization done!\n");
+}
+
+static ssize_t disksize_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ u64 disksize;
+ struct zram_meta *meta;
+ struct zram *zram = dev_to_zram(dev);
+
+ disksize = memparse(buf, NULL);
+ if (!disksize)
+ return -EINVAL;
+
+ disksize = PAGE_ALIGN(disksize);
+ meta = zram_meta_alloc(disksize);
+ down_write(&zram->init_lock);
+ if (zram->init_done) {
+ up_write(&zram->init_lock);
+ zram_meta_free(meta);
+ pr_info("Cannot change disksize for initialized device\n");
+ return -EBUSY;
+ }
+
+ zram->disksize = disksize;
+ set_capacity(zram->disk, zram->disksize >> SECTOR_SHIFT);
+ zram_init_device(zram, meta);
+ up_write(&zram->init_lock);
+
+ return len;
+}
+
+static ssize_t reset_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ int ret;
+ unsigned short do_reset;
+ struct zram *zram;
+ struct block_device *bdev;
+
+ zram = dev_to_zram(dev);
+ bdev = bdget_disk(zram->disk, 0);
+
+ /* Do not reset an active device! */
+ if (bdev->bd_holders)
+ return -EBUSY;
+
+ ret = kstrtou16(buf, 10, &do_reset);
+ if (ret)
+ return ret;
+
+ if (!do_reset)
+ return -EINVAL;
+
+ /* Make sure all pending I/O is finished */
+ if (bdev)
+ fsync_bdev(bdev);
+
+ zram_reset_device(zram, true);
+ return len;
}
static void __zram_make_request(struct zram *zram, struct bio *bio, int rw)
@@ -483,10 +686,10 @@
switch (rw) {
case READ:
- zram_stat64_inc(zram, &zram->stats.num_reads);
+ atomic64_inc(&zram->stats.num_reads);
break;
case WRITE:
- zram_stat64_inc(zram, &zram->stats.num_writes);
+ atomic64_inc(&zram->stats.num_writes);
break;
}
@@ -531,39 +734,19 @@
}
/*
- * Check if request is within bounds and aligned on zram logical blocks.
- */
-static inline int valid_io_request(struct zram *zram, struct bio *bio)
-{
- if (unlikely(
- (bio->bi_sector >= (zram->disksize >> SECTOR_SHIFT)) ||
- (bio->bi_sector & (ZRAM_SECTOR_PER_LOGICAL_BLOCK - 1)) ||
- (bio->bi_size & (ZRAM_LOGICAL_BLOCK_SIZE - 1)))) {
-
- return 0;
- }
-
- /* I/O request is valid */
- return 1;
-}
-
-/*
* Handler function for all zram I/O requests.
*/
static void zram_make_request(struct request_queue *queue, struct bio *bio)
{
struct zram *zram = queue->queuedata;
- if (unlikely(!zram->init_done) && zram_init_device(zram))
- goto error;
-
down_read(&zram->init_lock);
if (unlikely(!zram->init_done))
- goto error_unlock;
+ goto error;
if (!valid_io_request(zram, bio)) {
- zram_stat64_inc(zram, &zram->stats.invalid_io);
- goto error_unlock;
+ atomic64_inc(&zram->stats.invalid_io);
+ goto error;
}
__zram_make_request(zram, bio, bio_data_dir(bio));
@@ -571,129 +754,45 @@
return;
-error_unlock:
- up_read(&zram->init_lock);
error:
+ up_read(&zram->init_lock);
bio_io_error(bio);
}
-void __zram_reset_device(struct zram *zram)
+static void zram_slot_free(struct work_struct *work)
{
- size_t index;
+ struct zram *zram;
- zram->init_done = 0;
-
- /* Free various per-device buffers */
- kfree(zram->compress_workmem);
- free_pages((unsigned long)zram->compress_buffer, 1);
-
- zram->compress_workmem = NULL;
- zram->compress_buffer = NULL;
-
- /* Free all pages that are still in this zram device */
- for (index = 0; index < zram->disksize >> PAGE_SHIFT; index++) {
- void *handle = zram->table[index].handle;
- if (!handle)
- continue;
-
- if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED)))
- __free_page(handle);
- else
- zs_free(zram->mem_pool, handle);
- }
-
- vfree(zram->table);
- zram->table = NULL;
-
- zs_destroy_pool(zram->mem_pool);
- zram->mem_pool = NULL;
-
- /* Reset stats */
- memset(&zram->stats, 0, sizeof(zram->stats));
-
- zram->disksize = 0;
+ zram = container_of(work, struct zram, free_work);
+ down_write(&zram->lock);
+ handle_pending_slot_free(zram);
+ up_write(&zram->lock);
}
-void zram_reset_device(struct zram *zram)
+static void add_slot_free(struct zram *zram, struct zram_slot_free *free_rq)
{
- down_write(&zram->init_lock);
- __zram_reset_device(zram);
- up_write(&zram->init_lock);
-}
-
-int zram_init_device(struct zram *zram)
-{
- int ret;
- size_t num_pages;
-
- down_write(&zram->init_lock);
-
- if (zram->init_done) {
- up_write(&zram->init_lock);
- return 0;
- }
-
- zram_set_disksize(zram, totalram_pages << PAGE_SHIFT);
-
- zram->compress_workmem = kzalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
- if (!zram->compress_workmem) {
- pr_err("Error allocating compressor working memory!\n");
- ret = -ENOMEM;
- goto fail_no_table;
- }
-
- zram->compress_buffer =
- (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 1);
- if (!zram->compress_buffer) {
- pr_err("Error allocating compressor buffer space\n");
- ret = -ENOMEM;
- goto fail_no_table;
- }
-
- num_pages = zram->disksize >> PAGE_SHIFT;
- zram->table = vzalloc(num_pages * sizeof(*zram->table));
- if (!zram->table) {
- pr_err("Error allocating zram address table\n");
- ret = -ENOMEM;
- goto fail_no_table;
- }
-
- set_capacity(zram->disk, zram->disksize >> SECTOR_SHIFT);
-
- /* zram devices sort of resembles non-rotational disks */
- queue_flag_set_unlocked(QUEUE_FLAG_NONROT, zram->disk->queue);
-
- zram->mem_pool = zs_create_pool("zram", GFP_NOIO | __GFP_HIGHMEM);
- if (!zram->mem_pool) {
- pr_err("Error creating memory pool\n");
- ret = -ENOMEM;
- goto fail;
- }
-
- zram->init_done = 1;
- up_write(&zram->init_lock);
-
- pr_debug("Initialization done!\n");
- return 0;
-
-fail_no_table:
- /* To prevent accessing table entries during cleanup */
- zram->disksize = 0;
-fail:
- __zram_reset_device(zram);
- up_write(&zram->init_lock);
- pr_err("Initialization failed: err=%d\n", ret);
- return ret;
+ spin_lock(&zram->slot_free_lock);
+ free_rq->next = zram->slot_free_rq;
+ zram->slot_free_rq = free_rq;
+ spin_unlock(&zram->slot_free_lock);
}
static void zram_slot_free_notify(struct block_device *bdev,
unsigned long index)
{
struct zram *zram;
+ struct zram_slot_free *free_rq;
zram = bdev->bd_disk->private_data;
- zram_free_page(zram, index);
- zram_stat64_inc(zram, &zram->stats.notify_free);
+ atomic64_inc(&zram->stats.notify_free);
+
+ free_rq = kmalloc(sizeof(struct zram_slot_free), GFP_ATOMIC);
+ if (!free_rq)
+ return;
+
+ free_rq->index = index;
+ add_slot_free(zram, free_rq);
+ schedule_work(&zram->free_work);
}
static const struct block_device_operations zram_devops = {
@@ -701,19 +800,53 @@
.owner = THIS_MODULE
};
+static DEVICE_ATTR(disksize, S_IRUGO | S_IWUSR,
+ disksize_show, disksize_store);
+static DEVICE_ATTR(initstate, S_IRUGO, initstate_show, NULL);
+static DEVICE_ATTR(reset, S_IWUSR, NULL, reset_store);
+static DEVICE_ATTR(num_reads, S_IRUGO, num_reads_show, NULL);
+static DEVICE_ATTR(num_writes, S_IRUGO, num_writes_show, NULL);
+static DEVICE_ATTR(invalid_io, S_IRUGO, invalid_io_show, NULL);
+static DEVICE_ATTR(notify_free, S_IRUGO, notify_free_show, NULL);
+static DEVICE_ATTR(zero_pages, S_IRUGO, zero_pages_show, NULL);
+static DEVICE_ATTR(orig_data_size, S_IRUGO, orig_data_size_show, NULL);
+static DEVICE_ATTR(compr_data_size, S_IRUGO, compr_data_size_show, NULL);
+static DEVICE_ATTR(mem_used_total, S_IRUGO, mem_used_total_show, NULL);
+
+static struct attribute *zram_disk_attrs[] = {
+ &dev_attr_disksize.attr,
+ &dev_attr_initstate.attr,
+ &dev_attr_reset.attr,
+ &dev_attr_num_reads.attr,
+ &dev_attr_num_writes.attr,
+ &dev_attr_invalid_io.attr,
+ &dev_attr_notify_free.attr,
+ &dev_attr_zero_pages.attr,
+ &dev_attr_orig_data_size.attr,
+ &dev_attr_compr_data_size.attr,
+ &dev_attr_mem_used_total.attr,
+ NULL,
+};
+
+static struct attribute_group zram_disk_attr_group = {
+ .attrs = zram_disk_attrs,
+};
+
static int create_device(struct zram *zram, int device_id)
{
- int ret = 0;
+ int ret = -ENOMEM;
init_rwsem(&zram->lock);
init_rwsem(&zram->init_lock);
- spin_lock_init(&zram->stat64_lock);
+
+ INIT_WORK(&zram->free_work, zram_slot_free);
+ spin_lock_init(&zram->slot_free_lock);
+ zram->slot_free_rq = NULL;
zram->queue = blk_alloc_queue(GFP_KERNEL);
if (!zram->queue) {
pr_err("Error allocating disk queue for device %d\n",
device_id);
- ret = -ENOMEM;
goto out;
}
@@ -723,11 +856,9 @@
/* gendisk structure */
zram->disk = alloc_disk(1);
if (!zram->disk) {
- blk_cleanup_queue(zram->queue);
- pr_warning("Error allocating disk structure for device %d\n",
+ pr_warn("Error allocating disk structure for device %d\n",
device_id);
- ret = -ENOMEM;
- goto out;
+ goto out_free_queue;
}
zram->disk->major = zram_major;
@@ -755,12 +886,18 @@
ret = sysfs_create_group(&disk_to_dev(zram->disk)->kobj,
&zram_disk_attr_group);
if (ret < 0) {
- pr_warning("Error creating sysfs group");
- goto out;
+ pr_warn("Error creating sysfs group");
+ goto out_free_disk;
}
zram->init_done = 0;
+ return 0;
+out_free_disk:
+ del_gendisk(zram->disk);
+ put_disk(zram->disk);
+out_free_queue:
+ blk_cleanup_queue(zram->queue);
out:
return ret;
}
@@ -779,17 +916,12 @@
blk_cleanup_queue(zram->queue);
}
-unsigned int zram_get_num_devices(void)
-{
- return num_devices;
-}
-
static int __init zram_init(void)
{
int ret, dev_id;
if (num_devices > max_num_devices) {
- pr_warning("Invalid value for num_devices: %u\n",
+ pr_warn("Invalid value for num_devices: %u\n",
num_devices);
ret = -EINVAL;
goto out;
@@ -797,18 +929,12 @@
zram_major = register_blkdev(0, "zram");
if (zram_major <= 0) {
- pr_warning("Unable to get major number\n");
+ pr_warn("Unable to get major number\n");
ret = -EBUSY;
goto out;
}
- if (!num_devices) {
- pr_info("num_devices not specified. Using default: 1\n");
- num_devices = 1;
- }
-
/* Allocate the device array and initialize each one */
- pr_info("Creating %u devices ...\n", num_devices);
zram_devices = kzalloc(num_devices * sizeof(struct zram), GFP_KERNEL);
if (!zram_devices) {
ret = -ENOMEM;
@@ -821,6 +947,8 @@
goto free_devices;
}
+ pr_info("Created %u device(s) ...\n", num_devices);
+
return 0;
free_devices:
@@ -842,8 +970,11 @@
zram = &zram_devices[i];
destroy_device(zram);
- if (zram->init_done)
- zram_reset_device(zram);
+ /*
+ * Shouldn't access zram->disk after destroy_device
+ * because destroy_device already released zram->disk.
+ */
+ zram_reset_device(zram, false);
}
unregister_blkdev(zram_major, "zram");
@@ -852,12 +983,13 @@
pr_debug("Cleanup done!\n");
}
-module_param(num_devices, uint, 0);
-MODULE_PARM_DESC(num_devices, "Number of zram devices");
-
module_init(zram_init);
module_exit(zram_exit);
+module_param(num_devices, uint, 0);
+MODULE_PARM_DESC(num_devices, "Number of zram devices");
+
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Nitin Gupta <ngupta@vflare.org>");
MODULE_DESCRIPTION("Compressed RAM Block Device");
+MODULE_ALIAS("devname:zram");
diff --git a/drivers/staging/zram/zram_drv.h b/drivers/staging/zram/zram_drv.h
index fbe8ac9..508a19f 100644
--- a/drivers/staging/zram/zram_drv.h
+++ b/drivers/staging/zram/zram_drv.h
@@ -26,33 +26,18 @@
*/
static const unsigned max_num_devices = 32;
-/*
- * Stored at beginning of each compressed object.
- *
- * It stores back-reference to table entry which points to this
- * object. This is required to support memory defragmentation.
- */
-struct zobj_header {
-#if 0
- u32 table_idx;
-#endif
-};
-
/*-- Configurable parameters */
-/* Default zram disk size: 25% of total RAM */
-static const unsigned default_disksize_perc_ram = 25;
-
/*
* Pages that compress to size greater than this are stored
* uncompressed in memory.
*/
-static const size_t max_zpage_size = PAGE_SIZE / 4 * 3;
+static const size_t max_zpage_size = PAGE_SIZE / 10 * 9;
/*
* NOTE: max_zpage_size must be less than or equal to:
- * ZS_MAX_ALLOC_SIZE - sizeof(struct zobj_header)
- * otherwise, xv_malloc() would always return failure.
+ * ZS_MAX_ALLOC_SIZE. Otherwise, zs_malloc() would
+ * always return failure.
*/
/*-- End of configurable params */
@@ -68,9 +53,6 @@
/* Flags for zram pages (table[page_no].flags) */
enum zram_pageflags {
- /* Page is stored uncompressed */
- ZRAM_UNCOMPRESSED,
-
/* Page consists entirely of zeros */
ZRAM_ZERO,
@@ -81,34 +63,51 @@
/* Allocated for each disk page */
struct table {
- void *handle;
+ unsigned long handle;
u16 size; /* object size (excluding header) */
u8 count; /* object ref count (not yet used) */
u8 flags;
-} __attribute__((aligned(4)));
+} __aligned(4);
+/*
+ * All 64bit fields should only be manipulated by 64bit atomic accessors.
+ * All modifications to 32bit counter should be protected by zram->lock.
+ */
struct zram_stats {
- u64 compr_size; /* compressed size of pages stored */
- u64 num_reads; /* failed + successful */
- u64 num_writes; /* --do-- */
- u64 failed_reads; /* should NEVER! happen */
- u64 failed_writes; /* can happen when memory is too low */
- u64 invalid_io; /* non-page-aligned I/O requests */
- u64 notify_free; /* no. of swap slot free notifications */
+ atomic64_t compr_size; /* compressed size of pages stored */
+ atomic64_t num_reads; /* failed + successful */
+ atomic64_t num_writes; /* --do-- */
+ atomic64_t failed_reads; /* should NEVER! happen */
+ atomic64_t failed_writes; /* can happen when memory is too low */
+ atomic64_t invalid_io; /* non-page-aligned I/O requests */
+ atomic64_t notify_free; /* no. of swap slot free notifications */
u32 pages_zero; /* no. of zero filled pages */
u32 pages_stored; /* no. of pages currently stored */
u32 good_compress; /* % of pages with compression ratio<=50% */
- u32 pages_expand; /* % of incompressible pages */
+ u32 bad_compress; /* % of pages with compression ratio>=75% */
};
-struct zram {
- struct zs_pool *mem_pool;
+struct zram_meta {
void *compress_workmem;
void *compress_buffer;
struct table *table;
- spinlock_t stat64_lock; /* protect 64-bit stats */
- struct rw_semaphore lock; /* protect compression buffers and table
- * against concurrent read and writes */
+ struct zs_pool *mem_pool;
+};
+
+struct zram_slot_free {
+ unsigned long index;
+ struct zram_slot_free *next;
+};
+
+struct zram {
+ struct zram_meta *meta;
+ struct rw_semaphore lock; /* protect compression buffers, table,
+ * 32bit stat counters against concurrent
+ * notifications, reads and writes */
+
+ struct work_struct free_work; /* handle pending free request */
+ struct zram_slot_free *slot_free_rq; /* list head of free request */
+
struct request_queue *queue;
struct gendisk *disk;
int init_done;
@@ -119,17 +118,8 @@
* we can store in a disk.
*/
u64 disksize; /* bytes */
+ spinlock_t slot_free_lock;
struct zram_stats stats;
};
-
-extern struct zram *zram_devices;
-unsigned int zram_get_num_devices(void);
-#ifdef CONFIG_SYSFS
-extern struct attribute_group zram_disk_attr_group;
-#endif
-
-extern int zram_init_device(struct zram *zram);
-extern void __zram_reset_device(struct zram *zram);
-
#endif
diff --git a/drivers/staging/zram/zram_sysfs.c b/drivers/staging/zram/zram_sysfs.c
deleted file mode 100644
index a7f3771..0000000
--- a/drivers/staging/zram/zram_sysfs.c
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Compressed RAM block device
- *
- * Copyright (C) 2008, 2009, 2010 Nitin Gupta
- *
- * This code is released using a dual license strategy: BSD/GPL
- * You can choose the licence that better fits your requirements.
- *
- * Released under the terms of 3-clause BSD License
- * Released under the terms of GNU General Public License Version 2.0
- *
- * Project home: http://compcache.googlecode.com/
- */
-
-#include <linux/device.h>
-#include <linux/genhd.h>
-#include <linux/mm.h>
-
-#include "zram_drv.h"
-
-static u64 zram_stat64_read(struct zram *zram, u64 *v)
-{
- u64 val;
-
- spin_lock(&zram->stat64_lock);
- val = *v;
- spin_unlock(&zram->stat64_lock);
-
- return val;
-}
-
-static struct zram *dev_to_zram(struct device *dev)
-{
- int i;
- struct zram *zram = NULL;
-
- for (i = 0; i < zram_get_num_devices(); i++) {
- zram = &zram_devices[i];
- if (disk_to_dev(zram->disk) == dev)
- break;
- }
-
- return zram;
-}
-
-static ssize_t disksize_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct zram *zram = dev_to_zram(dev);
-
- return sprintf(buf, "%llu\n", zram->disksize);
-}
-
-static ssize_t disksize_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t len)
-{
- int ret;
- u64 disksize;
- struct zram *zram = dev_to_zram(dev);
-
- ret = kstrtoull(buf, 10, &disksize);
- if (ret)
- return ret;
-
- down_write(&zram->init_lock);
- if (zram->init_done) {
- up_write(&zram->init_lock);
- pr_info("Cannot change disksize for initialized device\n");
- return -EBUSY;
- }
-
- zram->disksize = PAGE_ALIGN(disksize);
- set_capacity(zram->disk, zram->disksize >> SECTOR_SHIFT);
- up_write(&zram->init_lock);
-
- return len;
-}
-
-static ssize_t initstate_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct zram *zram = dev_to_zram(dev);
-
- return sprintf(buf, "%u\n", zram->init_done);
-}
-
-static ssize_t reset_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t len)
-{
- int ret;
- unsigned short do_reset;
- struct zram *zram;
- struct block_device *bdev;
-
- zram = dev_to_zram(dev);
- bdev = bdget_disk(zram->disk, 0);
-
- /* Do not reset an active device! */
- if (bdev->bd_holders)
- return -EBUSY;
-
- ret = kstrtou16(buf, 10, &do_reset);
- if (ret)
- return ret;
-
- if (!do_reset)
- return -EINVAL;
-
- /* Make sure all pending I/O is finished */
- if (bdev)
- fsync_bdev(bdev);
-
- down_write(&zram->init_lock);
- if (zram->init_done)
- __zram_reset_device(zram);
- up_write(&zram->init_lock);
-
- return len;
-}
-
-static ssize_t num_reads_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct zram *zram = dev_to_zram(dev);
-
- return sprintf(buf, "%llu\n",
- zram_stat64_read(zram, &zram->stats.num_reads));
-}
-
-static ssize_t num_writes_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct zram *zram = dev_to_zram(dev);
-
- return sprintf(buf, "%llu\n",
- zram_stat64_read(zram, &zram->stats.num_writes));
-}
-
-static ssize_t invalid_io_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct zram *zram = dev_to_zram(dev);
-
- return sprintf(buf, "%llu\n",
- zram_stat64_read(zram, &zram->stats.invalid_io));
-}
-
-static ssize_t notify_free_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct zram *zram = dev_to_zram(dev);
-
- return sprintf(buf, "%llu\n",
- zram_stat64_read(zram, &zram->stats.notify_free));
-}
-
-static ssize_t zero_pages_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct zram *zram = dev_to_zram(dev);
-
- return sprintf(buf, "%u\n", zram->stats.pages_zero);
-}
-
-static ssize_t orig_data_size_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct zram *zram = dev_to_zram(dev);
-
- return sprintf(buf, "%llu\n",
- (u64)(zram->stats.pages_stored) << PAGE_SHIFT);
-}
-
-static ssize_t compr_data_size_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct zram *zram = dev_to_zram(dev);
-
- return sprintf(buf, "%llu\n",
- zram_stat64_read(zram, &zram->stats.compr_size));
-}
-
-static ssize_t mem_used_total_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- u64 val = 0;
- struct zram *zram = dev_to_zram(dev);
-
- if (zram->init_done) {
- val = zs_get_total_size_bytes(zram->mem_pool) +
- ((u64)(zram->stats.pages_expand) << PAGE_SHIFT);
- }
-
- return sprintf(buf, "%llu\n", val);
-}
-
-static DEVICE_ATTR(disksize, S_IRUGO | S_IWUSR,
- disksize_show, disksize_store);
-static DEVICE_ATTR(initstate, S_IRUGO, initstate_show, NULL);
-static DEVICE_ATTR(reset, S_IWUSR, NULL, reset_store);
-static DEVICE_ATTR(num_reads, S_IRUGO, num_reads_show, NULL);
-static DEVICE_ATTR(num_writes, S_IRUGO, num_writes_show, NULL);
-static DEVICE_ATTR(invalid_io, S_IRUGO, invalid_io_show, NULL);
-static DEVICE_ATTR(notify_free, S_IRUGO, notify_free_show, NULL);
-static DEVICE_ATTR(zero_pages, S_IRUGO, zero_pages_show, NULL);
-static DEVICE_ATTR(orig_data_size, S_IRUGO, orig_data_size_show, NULL);
-static DEVICE_ATTR(compr_data_size, S_IRUGO, compr_data_size_show, NULL);
-static DEVICE_ATTR(mem_used_total, S_IRUGO, mem_used_total_show, NULL);
-
-static struct attribute *zram_disk_attrs[] = {
- &dev_attr_disksize.attr,
- &dev_attr_initstate.attr,
- &dev_attr_reset.attr,
- &dev_attr_num_reads.attr,
- &dev_attr_num_writes.attr,
- &dev_attr_invalid_io.attr,
- &dev_attr_notify_free.attr,
- &dev_attr_zero_pages.attr,
- &dev_attr_orig_data_size.attr,
- &dev_attr_compr_data_size.attr,
- &dev_attr_mem_used_total.attr,
- NULL,
-};
-
-struct attribute_group zram_disk_attr_group = {
- .attrs = zram_disk_attrs,
-};
diff --git a/drivers/staging/zsmalloc/Kconfig b/drivers/staging/zsmalloc/Kconfig
index a5ab720..7fab032 100644
--- a/drivers/staging/zsmalloc/Kconfig
+++ b/drivers/staging/zsmalloc/Kconfig
@@ -1,9 +1,5 @@
config ZSMALLOC
- tristate "Memory allocator for compressed pages"
- # X86 dependency is because of the use of __flush_tlb_one and set_pte
- # in zsmalloc-main.c.
- # TODO: convert these to portable functions
- depends on X86
+ bool "Memory allocator for compressed pages"
default n
help
zsmalloc is a slab-based memory allocator designed to store
diff --git a/drivers/staging/zsmalloc/zsmalloc-main.c b/drivers/staging/zsmalloc/zsmalloc-main.c
index 917461c..41a6803 100644
--- a/drivers/staging/zsmalloc/zsmalloc-main.c
+++ b/drivers/staging/zsmalloc/zsmalloc-main.c
@@ -10,6 +10,54 @@
* Released under the terms of GNU General Public License Version 2.0
*/
+
+/*
+ * This allocator is designed for use with zcache and zram. Thus, the
+ * allocator is supposed to work well under low memory conditions. In
+ * particular, it never attempts higher order page allocation which is
+ * very likely to fail under memory pressure. On the other hand, if we
+ * just use single (0-order) pages, it would suffer from very high
+ * fragmentation -- any object of size PAGE_SIZE/2 or larger would occupy
+ * an entire page. This was one of the major issues with its predecessor
+ * (xvmalloc).
+ *
+ * To overcome these issues, zsmalloc allocates a bunch of 0-order pages
+ * and links them together using various 'struct page' fields. These linked
+ * pages act as a single higher-order page i.e. an object can span 0-order
+ * page boundaries. The code refers to these linked pages as a single entity
+ * called zspage.
+ *
+ * Following is how we use various fields and flags of underlying
+ * struct page(s) to form a zspage.
+ *
+ * Usage of struct page fields:
+ * page->first_page: points to the first component (0-order) page
+ * page->index (union with page->freelist): offset of the first object
+ * starting in this page. For the first page, this is
+ * always 0, so we use this field (aka freelist) to point
+ * to the first free object in zspage.
+ * page->lru: links together all component pages (except the first page)
+ * of a zspage
+ *
+ * For _first_ page only:
+ *
+ * page->private (union with page->first_page): refers to the
+ * component page after the first page
+ * page->freelist: points to the first free object in zspage.
+ * Free objects are linked together using in-place
+ * metadata.
+ * page->objects: maximum number of objects we can store in this
+ * zspage (class->zspage_order * PAGE_SIZE / class->size)
+ * page->lru: links together first pages of various zspages.
+ * Basically forming list of zspages in a fullness group.
+ * page->mapping: class index and fullness group of the zspage
+ *
+ * Usage of struct page flags:
+ * PG_private: identifies the first component page
+ * PG_private2: identifies the last component page
+ *
+ */
+
#ifdef CONFIG_ZSMALLOC_DEBUG
#define DEBUG
#endif
@@ -27,9 +75,139 @@
#include <linux/cpumask.h>
#include <linux/cpu.h>
#include <linux/vmalloc.h>
+#include <linux/hardirq.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
#include "zsmalloc.h"
-#include "zsmalloc_int.h"
+
+/*
+ * This must be power of 2 and greater than of equal to sizeof(link_free).
+ * These two conditions ensure that any 'struct link_free' itself doesn't
+ * span more than 1 page which avoids complex case of mapping 2 pages simply
+ * to restore link_free pointer values.
+ */
+#define ZS_ALIGN 8
+
+/*
+ * A single 'zspage' is composed of up to 2^N discontiguous 0-order (single)
+ * pages. ZS_MAX_ZSPAGE_ORDER defines upper limit on N.
+ */
+#define ZS_MAX_ZSPAGE_ORDER 2
+#define ZS_MAX_PAGES_PER_ZSPAGE (_AC(1, UL) << ZS_MAX_ZSPAGE_ORDER)
+
+/*
+ * Object location (<PFN>, <obj_idx>) is encoded as
+ * as single (void *) handle value.
+ *
+ * Note that object index <obj_idx> is relative to system
+ * page <PFN> it is stored in, so for each sub-page belonging
+ * to a zspage, obj_idx starts with 0.
+ *
+ * This is made more complicated by various memory models and PAE.
+ */
+
+#ifndef MAX_PHYSMEM_BITS
+#ifdef CONFIG_HIGHMEM64G
+#define MAX_PHYSMEM_BITS 36
+#else /* !CONFIG_HIGHMEM64G */
+/*
+ * If this definition of MAX_PHYSMEM_BITS is used, OBJ_INDEX_BITS will just
+ * be PAGE_SHIFT
+ */
+#define MAX_PHYSMEM_BITS BITS_PER_LONG
+#endif
+#endif
+#define _PFN_BITS (MAX_PHYSMEM_BITS - PAGE_SHIFT)
+#define OBJ_INDEX_BITS (BITS_PER_LONG - _PFN_BITS)
+#define OBJ_INDEX_MASK ((_AC(1, UL) << OBJ_INDEX_BITS) - 1)
+
+#define MAX(a, b) ((a) >= (b) ? (a) : (b))
+/* ZS_MIN_ALLOC_SIZE must be multiple of ZS_ALIGN */
+#define ZS_MIN_ALLOC_SIZE \
+ MAX(32, (ZS_MAX_PAGES_PER_ZSPAGE << PAGE_SHIFT >> OBJ_INDEX_BITS))
+#define ZS_MAX_ALLOC_SIZE PAGE_SIZE
+
+/*
+ * On systems with 4K page size, this gives 254 size classes! There is a
+ * trader-off here:
+ * - Large number of size classes is potentially wasteful as free page are
+ * spread across these classes
+ * - Small number of size classes causes large internal fragmentation
+ * - Probably its better to use specific size classes (empirically
+ * determined). NOTE: all those class sizes must be set as multiple of
+ * ZS_ALIGN to make sure link_free itself never has to span 2 pages.
+ *
+ * ZS_MIN_ALLOC_SIZE and ZS_SIZE_CLASS_DELTA must be multiple of ZS_ALIGN
+ * (reason above)
+ */
+#define ZS_SIZE_CLASS_DELTA (PAGE_SIZE >> 8)
+#define ZS_SIZE_CLASSES ((ZS_MAX_ALLOC_SIZE - ZS_MIN_ALLOC_SIZE) / \
+ ZS_SIZE_CLASS_DELTA + 1)
+
+/*
+ * We do not maintain any list for completely empty or full pages
+ */
+enum fullness_group {
+ ZS_ALMOST_FULL,
+ ZS_ALMOST_EMPTY,
+ _ZS_NR_FULLNESS_GROUPS,
+
+ ZS_EMPTY,
+ ZS_FULL
+};
+
+/*
+ * We assign a page to ZS_ALMOST_EMPTY fullness group when:
+ * n <= N / f, where
+ * n = number of allocated objects
+ * N = total number of objects zspage can store
+ * f = 1/fullness_threshold_frac
+ *
+ * Similarly, we assign zspage to:
+ * ZS_ALMOST_FULL when n > N / f
+ * ZS_EMPTY when n == 0
+ * ZS_FULL when n == N
+ *
+ * (see: fix_fullness_group())
+ */
+static const int fullness_threshold_frac = 4;
+
+struct size_class {
+ /*
+ * Size of objects stored in this class. Must be multiple
+ * of ZS_ALIGN.
+ */
+ int size;
+ unsigned int index;
+
+ /* Number of PAGE_SIZE sized pages to combine to form a 'zspage' */
+ int pages_per_zspage;
+
+ spinlock_t lock;
+
+ /* stats */
+ u64 pages_allocated;
+
+ struct page *fullness_list[_ZS_NR_FULLNESS_GROUPS];
+};
+
+/*
+ * Placed within free objects to form a singly linked list.
+ * For every zspage, first_page->freelist gives head of this list.
+ *
+ * This must be power of 2 and less than or equal to ZS_ALIGN
+ */
+struct link_free {
+ /* Handle of next free chunk (encodes <PFN, obj_idx>) */
+ void *next;
+};
+
+struct zs_pool {
+ struct size_class size_class[ZS_SIZE_CLASSES];
+
+ gfp_t flags; /* allocation flags used when growing pool */
+};
/*
* A zspage's class index and fullness group
@@ -40,17 +218,39 @@
#define CLASS_IDX_MASK ((1 << CLASS_IDX_BITS) - 1)
#define FULLNESS_MASK ((1 << FULLNESS_BITS) - 1)
+/*
+ * By default, zsmalloc uses a copy-based object mapping method to access
+ * allocations that span two pages. However, if a particular architecture
+ * performs VM mapping faster than copying, then it should be added here
+ * so that USE_PGTABLE_MAPPING is defined. This causes zsmalloc to use
+ * page table mapping rather than copying for object mapping.
+ */
+#if defined(CONFIG_ARM) && !defined(MODULE)
+#define USE_PGTABLE_MAPPING
+#endif
+
+struct mapping_area {
+#ifdef USE_PGTABLE_MAPPING
+ struct vm_struct *vm; /* vm area for mapping object that span pages */
+#else
+ char *vm_buf; /* copy buffer for objects that span pages */
+#endif
+ char *vm_addr; /* address of kmap_atomic()'ed pages */
+ enum zs_mapmode vm_mm; /* mapping mode */
+};
+
+
/* per-cpu VM mapping areas for zspage accesses that cross page boundaries */
static DEFINE_PER_CPU(struct mapping_area, zs_map_area);
static int is_first_page(struct page *page)
{
- return test_bit(PG_private, &page->flags);
+ return PagePrivate(page);
}
static int is_last_page(struct page *page)
{
- return test_bit(PG_private_2, &page->flags);
+ return PagePrivate2(page);
}
static void get_zspage_mapping(struct page *page, unsigned int *class_idx,
@@ -180,7 +380,7 @@
* link together 3 PAGE_SIZE sized pages to form a zspage
* since then we can perfectly fit in 8 such objects.
*/
-static int get_zspage_order(int class_size)
+static int get_pages_per_zspage(int class_size)
{
int i, max_usedpc = 0;
/* zspage order which gives maximum used size per KB */
@@ -223,14 +423,19 @@
if (is_last_page(page))
next = NULL;
else if (is_first_page(page))
- next = (struct page *)page->private;
+ next = (struct page *)page_private(page);
else
next = list_entry(page->lru.next, struct page, lru);
return next;
}
-/* Encode <page, obj_idx> as a single handle value */
+/*
+ * Encode <page, obj_idx> as a single handle value.
+ * On hardware platforms with physical memory starting at 0x0 the pfn
+ * could be 0 so we ensure that the handle will never be 0 by adjusting the
+ * encoded obj_idx value before encoding.
+ */
static void *obj_location_to_handle(struct page *page, unsigned long obj_idx)
{
unsigned long handle;
@@ -241,19 +446,21 @@
}
handle = page_to_pfn(page) << OBJ_INDEX_BITS;
- handle |= (obj_idx & OBJ_INDEX_MASK);
+ handle |= ((obj_idx + 1) & OBJ_INDEX_MASK);
return (void *)handle;
}
-/* Decode <page, obj_idx> pair from the given object handle */
-static void obj_handle_to_location(void *handle, struct page **page,
+/*
+ * Decode <page, obj_idx> pair from the given object handle. We adjust the
+ * decoded obj_idx back to its original value since it was adjusted in
+ * obj_location_to_handle().
+ */
+static void obj_handle_to_location(unsigned long handle, struct page **page,
unsigned long *obj_idx)
{
- unsigned long hval = (unsigned long)handle;
-
- *page = pfn_to_page(hval >> OBJ_INDEX_BITS);
- *obj_idx = hval & OBJ_INDEX_MASK;
+ *page = pfn_to_page(handle >> OBJ_INDEX_BITS);
+ *obj_idx = (handle & OBJ_INDEX_MASK) - 1;
}
static unsigned long obj_idx_to_offset(struct page *page,
@@ -354,7 +561,7 @@
static struct page *alloc_zspage(struct size_class *class, gfp_t flags)
{
int i, error;
- struct page *first_page = NULL;
+ struct page *first_page = NULL, *uninitialized_var(prev_page);
/*
* Allocate individual pages and link them together as:
@@ -368,8 +575,8 @@
* identify the last page.
*/
error = -ENOMEM;
- for (i = 0; i < class->zspage_order; i++) {
- struct page *page, *prev_page;
+ for (i = 0; i < class->pages_per_zspage; i++) {
+ struct page *page;
page = alloc_page(flags);
if (!page)
@@ -377,20 +584,19 @@
INIT_LIST_HEAD(&page->lru);
if (i == 0) { /* first page */
- set_bit(PG_private, &page->flags);
+ SetPagePrivate(page);
set_page_private(page, 0);
first_page = page;
first_page->inuse = 0;
}
if (i == 1)
- first_page->private = (unsigned long)page;
+ set_page_private(first_page, (unsigned long)page);
if (i >= 1)
page->first_page = first_page;
if (i >= 2)
list_add(&page->lru, &prev_page->lru);
- if (i == class->zspage_order - 1) /* last page */
- set_bit(PG_private_2, &page->flags);
-
+ if (i == class->pages_per_zspage - 1) /* last page */
+ SetPagePrivate2(page);
prev_page = page;
}
@@ -398,7 +604,7 @@
first_page->freelist = obj_location_to_handle(first_page, 0);
/* Maximum number of objects we can store in this zspage */
- first_page->objects = class->zspage_order * PAGE_SIZE / class->size;
+ first_page->objects = class->pages_per_zspage * PAGE_SIZE / class->size;
error = 0; /* Success */
@@ -425,34 +631,141 @@
return page;
}
+#ifdef USE_PGTABLE_MAPPING
+static inline int __zs_cpu_up(struct mapping_area *area)
+{
+ /*
+ * Make sure we don't leak memory if a cpu UP notification
+ * and zs_init() race and both call zs_cpu_up() on the same cpu
+ */
+ if (area->vm)
+ return 0;
+ area->vm = alloc_vm_area(PAGE_SIZE * 2, NULL);
+ if (!area->vm)
+ return -ENOMEM;
+ return 0;
+}
-/*
- * If this becomes a separate module, register zs_init() with
- * module_init(), zs_exit with module_exit(), and remove zs_initialized
-*/
-static int zs_initialized;
+static inline void __zs_cpu_down(struct mapping_area *area)
+{
+ if (area->vm)
+ free_vm_area(area->vm);
+ area->vm = NULL;
+}
+
+static inline void *__zs_map_object(struct mapping_area *area,
+ struct page *pages[2], int off, int size)
+{
+ BUG_ON(map_vm_area(area->vm, PAGE_KERNEL, &pages));
+ area->vm_addr = area->vm->addr;
+ return area->vm_addr + off;
+}
+
+static inline void __zs_unmap_object(struct mapping_area *area,
+ struct page *pages[2], int off, int size)
+{
+ unsigned long addr = (unsigned long)area->vm_addr;
+
+ unmap_kernel_range(addr, PAGE_SIZE * 2);
+}
+
+#else /* USE_PGTABLE_MAPPING */
+
+static inline int __zs_cpu_up(struct mapping_area *area)
+{
+ /*
+ * Make sure we don't leak memory if a cpu UP notification
+ * and zs_init() race and both call zs_cpu_up() on the same cpu
+ */
+ if (area->vm_buf)
+ return 0;
+ area->vm_buf = (char *)__get_free_page(GFP_KERNEL);
+ if (!area->vm_buf)
+ return -ENOMEM;
+ return 0;
+}
+
+static inline void __zs_cpu_down(struct mapping_area *area)
+{
+ if (area->vm_buf)
+ free_page((unsigned long)area->vm_buf);
+ area->vm_buf = NULL;
+}
+
+static void *__zs_map_object(struct mapping_area *area,
+ struct page *pages[2], int off, int size)
+{
+ int sizes[2];
+ void *addr;
+ char *buf = area->vm_buf;
+
+ /* disable page faults to match kmap_atomic() return conditions */
+ pagefault_disable();
+
+ /* no read fastpath */
+ if (area->vm_mm == ZS_MM_WO)
+ goto out;
+
+ sizes[0] = PAGE_SIZE - off;
+ sizes[1] = size - sizes[0];
+
+ /* copy object to per-cpu buffer */
+ addr = kmap_atomic(pages[0]);
+ memcpy(buf, addr + off, sizes[0]);
+ kunmap_atomic(addr);
+ addr = kmap_atomic(pages[1]);
+ memcpy(buf + sizes[0], addr, sizes[1]);
+ kunmap_atomic(addr);
+out:
+ return area->vm_buf;
+}
+
+static void __zs_unmap_object(struct mapping_area *area,
+ struct page *pages[2], int off, int size)
+{
+ int sizes[2];
+ void *addr;
+ char *buf = area->vm_buf;
+
+ /* no write fastpath */
+ if (area->vm_mm == ZS_MM_RO)
+ goto out;
+
+ sizes[0] = PAGE_SIZE - off;
+ sizes[1] = size - sizes[0];
+
+ /* copy per-cpu buffer to object */
+ addr = kmap_atomic(pages[0]);
+ memcpy(addr + off, buf, sizes[0]);
+ kunmap_atomic(addr);
+ addr = kmap_atomic(pages[1]);
+ memcpy(addr, buf + sizes[0], sizes[1]);
+ kunmap_atomic(addr);
+
+out:
+ /* enable page faults to match kunmap_atomic() return conditions */
+ pagefault_enable();
+}
+
+#endif /* USE_PGTABLE_MAPPING */
static int zs_cpu_notifier(struct notifier_block *nb, unsigned long action,
void *pcpu)
{
- int cpu = (long)pcpu;
+ int ret, cpu = (long)pcpu;
struct mapping_area *area;
switch (action) {
case CPU_UP_PREPARE:
area = &per_cpu(zs_map_area, cpu);
- if (area->vm)
- break;
- area->vm = alloc_vm_area(2 * PAGE_SIZE, area->vm_ptes);
- if (!area->vm)
- return notifier_from_errno(-ENOMEM);
+ ret = __zs_cpu_up(area);
+ if (ret)
+ return notifier_from_errno(ret);
break;
case CPU_DEAD:
case CPU_UP_CANCELED:
area = &per_cpu(zs_map_area, cpu);
- if (area->vm)
- free_vm_area(area->vm);
- area->vm = NULL;
+ __zs_cpu_down(area);
break;
}
@@ -488,14 +801,21 @@
return notifier_to_errno(ret);
}
-struct zs_pool *zs_create_pool(const char *name, gfp_t flags)
+/**
+ * zs_create_pool - Creates an allocation pool to work from.
+ * @flags: allocation flags used to allocate pool metadata
+ *
+ * This function must be called before anything when using
+ * the zsmalloc allocator.
+ *
+ * On success, a pointer to the newly created pool is returned,
+ * otherwise NULL.
+ */
+struct zs_pool *zs_create_pool(gfp_t flags)
{
- int i, error, ovhd_size;
+ int i, ovhd_size;
struct zs_pool *pool;
- if (!name)
- return NULL;
-
ovhd_size = roundup(sizeof(*pool), PAGE_SIZE);
pool = kzalloc(ovhd_size, GFP_KERNEL);
if (!pool)
@@ -513,31 +833,11 @@
class->size = size;
class->index = i;
spin_lock_init(&class->lock);
- class->zspage_order = get_zspage_order(size);
+ class->pages_per_zspage = get_pages_per_zspage(size);
}
- /*
- * If this becomes a separate module, register zs_init with
- * module_init, and remove this block
- */
- if (!zs_initialized) {
- error = zs_init();
- if (error)
- goto cleanup;
- zs_initialized = 1;
- }
-
pool->flags = flags;
- pool->name = name;
-
- error = 0; /* Success */
-
-cleanup:
- if (error) {
- zs_destroy_pool(pool);
- pool = NULL;
- }
return pool;
}
@@ -553,8 +853,7 @@
for (fg = 0; fg < _ZS_NR_FULLNESS_GROUPS; fg++) {
if (class->fullness_list[fg]) {
- pr_info("Freeing non-empty class with size "
- "%db, fullness group %d\n",
+ pr_info("Freeing non-empty class with size %db, fullness group %d\n",
class->size, fg);
}
}
@@ -567,18 +866,14 @@
* zs_malloc - Allocate block of given size from pool.
* @pool: pool to allocate from
* @size: size of block to allocate
- * @page: page no. that holds the object
- * @offset: location of object within page
*
- * On success, <page, offset> identifies block allocated
- * and 0 is returned. On failure, <page, offset> is set to
- * 0 and -ENOMEM is returned.
- *
+ * On success, handle to the allocated object is returned,
+ * otherwise 0.
* Allocation requests with size > ZS_MAX_ALLOC_SIZE will fail.
*/
-void *zs_malloc(struct zs_pool *pool, size_t size)
+unsigned long zs_malloc(struct zs_pool *pool, size_t size)
{
- void *obj;
+ unsigned long obj;
struct link_free *link;
int class_idx;
struct size_class *class;
@@ -587,7 +882,7 @@
unsigned long m_objidx, m_offset;
if (unlikely(!size || size > ZS_MAX_ALLOC_SIZE))
- return NULL;
+ return 0;
class_idx = get_size_class_index(size);
class = &pool->size_class[class_idx];
@@ -600,14 +895,14 @@
spin_unlock(&class->lock);
first_page = alloc_zspage(class, pool->flags);
if (unlikely(!first_page))
- return NULL;
+ return 0;
set_zspage_mapping(first_page, class->index, ZS_EMPTY);
spin_lock(&class->lock);
- class->pages_allocated += class->zspage_order;
+ class->pages_allocated += class->pages_per_zspage;
}
- obj = first_page->freelist;
+ obj = (unsigned long)first_page->freelist;
obj_handle_to_location(obj, &m_page, &m_objidx);
m_offset = obj_idx_to_offset(m_page, m_objidx, class->size);
@@ -626,7 +921,7 @@
}
EXPORT_SYMBOL_GPL(zs_malloc);
-void zs_free(struct zs_pool *pool, void *obj)
+void zs_free(struct zs_pool *pool, unsigned long obj)
{
struct link_free *link;
struct page *first_page, *f_page;
@@ -653,13 +948,13 @@
+ f_offset);
link->next = first_page->freelist;
kunmap_atomic(link);
- first_page->freelist = obj;
+ first_page->freelist = (void *)obj;
first_page->inuse--;
fullness = fix_fullness_group(pool, first_page);
if (fullness == ZS_EMPTY)
- class->pages_allocated -= class->zspage_order;
+ class->pages_allocated -= class->pages_per_zspage;
spin_unlock(&class->lock);
@@ -668,7 +963,22 @@
}
EXPORT_SYMBOL_GPL(zs_free);
-void *zs_map_object(struct zs_pool *pool, void *handle)
+/**
+ * zs_map_object - get address of allocated object from handle.
+ * @pool: pool from which the object was allocated
+ * @handle: handle returned from zs_malloc
+ *
+ * Before using an object allocated from zs_malloc, it must be mapped using
+ * this function. When done with the object, it must be unmapped using
+ * zs_unmap_object.
+ *
+ * Only one object can be mapped per cpu at a time. There is no protection
+ * against nested mappings.
+ *
+ * This function returns with preemption and page faults disabled.
+ */
+void *zs_map_object(struct zs_pool *pool, unsigned long handle,
+ enum zs_mapmode mm)
{
struct page *page;
unsigned long obj_idx, off;
@@ -677,38 +987,40 @@
enum fullness_group fg;
struct size_class *class;
struct mapping_area *area;
+ struct page *pages[2];
BUG_ON(!handle);
+ /*
+ * Because we use per-cpu mapping areas shared among the
+ * pools/users, we can't allow mapping in interrupt context
+ * because it can corrupt another users mappings.
+ */
+ BUG_ON(in_interrupt());
+
obj_handle_to_location(handle, &page, &obj_idx);
get_zspage_mapping(get_first_page(page), &class_idx, &fg);
class = &pool->size_class[class_idx];
off = obj_idx_to_offset(page, obj_idx, class->size);
area = &get_cpu_var(zs_map_area);
+ area->vm_mm = mm;
if (off + class->size <= PAGE_SIZE) {
/* this object is contained entirely within a page */
area->vm_addr = kmap_atomic(page);
- } else {
- /* this object spans two pages */
- struct page *nextp;
-
- nextp = get_next_page(page);
- BUG_ON(!nextp);
-
-
- set_pte(area->vm_ptes[0], mk_pte(page, PAGE_KERNEL));
- set_pte(area->vm_ptes[1], mk_pte(nextp, PAGE_KERNEL));
-
- /* We pre-allocated VM area so mapping can never fail */
- area->vm_addr = area->vm->addr;
+ return area->vm_addr + off;
}
- return area->vm_addr + off;
+ /* this object spans two pages */
+ pages[0] = page;
+ pages[1] = get_next_page(page);
+ BUG_ON(!pages[1]);
+
+ return __zs_map_object(area, pages, off, class->size);
}
EXPORT_SYMBOL_GPL(zs_map_object);
-void zs_unmap_object(struct zs_pool *pool, void *handle)
+void zs_unmap_object(struct zs_pool *pool, unsigned long handle)
{
struct page *page;
unsigned long obj_idx, off;
@@ -726,13 +1038,16 @@
off = obj_idx_to_offset(page, obj_idx, class->size);
area = &__get_cpu_var(zs_map_area);
- if (off + class->size <= PAGE_SIZE) {
+ if (off + class->size <= PAGE_SIZE)
kunmap_atomic(area->vm_addr);
- } else {
- set_pte(area->vm_ptes[0], __pte(0));
- set_pte(area->vm_ptes[1], __pte(0));
- __flush_tlb_one((unsigned long)area->vm_addr);
- __flush_tlb_one((unsigned long)area->vm_addr + PAGE_SIZE);
+ else {
+ struct page *pages[2];
+
+ pages[0] = page;
+ pages[1] = get_next_page(page);
+ BUG_ON(!pages[1]);
+
+ __zs_unmap_object(area, pages, off, class->size);
}
put_cpu_var(zs_map_area);
}
@@ -749,3 +1064,9 @@
return npages << PAGE_SHIFT;
}
EXPORT_SYMBOL_GPL(zs_get_total_size_bytes);
+
+module_init(zs_init);
+module_exit(zs_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Nitin Gupta <ngupta@vflare.org>");
diff --git a/drivers/staging/zsmalloc/zsmalloc.h b/drivers/staging/zsmalloc/zsmalloc.h
index 949384e..fbe6bec 100644
--- a/drivers/staging/zsmalloc/zsmalloc.h
+++ b/drivers/staging/zsmalloc/zsmalloc.h
@@ -15,16 +15,28 @@
#include <linux/types.h>
+/*
+ * zsmalloc mapping modes
+ *
+ * NOTE: These only make a difference when a mapped object spans pages
+ */
+enum zs_mapmode {
+ ZS_MM_RW, /* normal read-write mapping */
+ ZS_MM_RO, /* read-only (no copy-out at unmap time) */
+ ZS_MM_WO /* write-only (no copy-in at map time) */
+};
+
struct zs_pool;
-struct zs_pool *zs_create_pool(const char *name, gfp_t flags);
+struct zs_pool *zs_create_pool(gfp_t flags);
void zs_destroy_pool(struct zs_pool *pool);
-void *zs_malloc(struct zs_pool *pool, size_t size);
-void zs_free(struct zs_pool *pool, void *obj);
+unsigned long zs_malloc(struct zs_pool *pool, size_t size);
+void zs_free(struct zs_pool *pool, unsigned long obj);
-void *zs_map_object(struct zs_pool *pool, void *handle);
-void zs_unmap_object(struct zs_pool *pool, void *handle);
+void *zs_map_object(struct zs_pool *pool, unsigned long handle,
+ enum zs_mapmode mm);
+void zs_unmap_object(struct zs_pool *pool, unsigned long handle);
u64 zs_get_total_size_bytes(struct zs_pool *pool);
diff --git a/drivers/staging/zsmalloc/zsmalloc_int.h b/drivers/staging/zsmalloc/zsmalloc_int.h
deleted file mode 100644
index 92eefc6..0000000
--- a/drivers/staging/zsmalloc/zsmalloc_int.h
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * zsmalloc memory allocator
- *
- * Copyright (C) 2011 Nitin Gupta
- *
- * This code is released using a dual license strategy: BSD/GPL
- * You can choose the license that better fits your requirements.
- *
- * Released under the terms of 3-clause BSD License
- * Released under the terms of GNU General Public License Version 2.0
- */
-
-#ifndef _ZS_MALLOC_INT_H_
-#define _ZS_MALLOC_INT_H_
-
-#include <linux/kernel.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-
-/*
- * This must be power of 2 and greater than of equal to sizeof(link_free).
- * These two conditions ensure that any 'struct link_free' itself doesn't
- * span more than 1 page which avoids complex case of mapping 2 pages simply
- * to restore link_free pointer values.
- */
-#define ZS_ALIGN 8
-
-/*
- * A single 'zspage' is composed of up to 2^N discontiguous 0-order (single)
- * pages. ZS_MAX_ZSPAGE_ORDER defines upper limit on N.
- */
-#define ZS_MAX_ZSPAGE_ORDER 2
-#define ZS_MAX_PAGES_PER_ZSPAGE (_AC(1, UL) << ZS_MAX_ZSPAGE_ORDER)
-
-/*
- * Object location (<PFN>, <obj_idx>) is encoded as
- * as single (void *) handle value.
- *
- * Note that object index <obj_idx> is relative to system
- * page <PFN> it is stored in, so for each sub-page belonging
- * to a zspage, obj_idx starts with 0.
- *
- * This is made more complicated by various memory models and PAE.
- */
-
-#ifndef MAX_PHYSMEM_BITS
-#ifdef CONFIG_HIGHMEM64G
-#define MAX_PHYSMEM_BITS 36
-#else /* !CONFIG_HIGHMEM64G */
-/*
- * If this definition of MAX_PHYSMEM_BITS is used, OBJ_INDEX_BITS will just
- * be PAGE_SHIFT
- */
-#define MAX_PHYSMEM_BITS BITS_PER_LONG
-#endif
-#endif
-#define _PFN_BITS (MAX_PHYSMEM_BITS - PAGE_SHIFT)
-#define OBJ_INDEX_BITS (BITS_PER_LONG - _PFN_BITS)
-#define OBJ_INDEX_MASK ((_AC(1, UL) << OBJ_INDEX_BITS) - 1)
-
-#define MAX(a, b) ((a) >= (b) ? (a) : (b))
-/* ZS_MIN_ALLOC_SIZE must be multiple of ZS_ALIGN */
-#define ZS_MIN_ALLOC_SIZE \
- MAX(32, (ZS_MAX_PAGES_PER_ZSPAGE << PAGE_SHIFT >> OBJ_INDEX_BITS))
-#define ZS_MAX_ALLOC_SIZE PAGE_SIZE
-
-/*
- * On systems with 4K page size, this gives 254 size classes! There is a
- * trader-off here:
- * - Large number of size classes is potentially wasteful as free page are
- * spread across these classes
- * - Small number of size classes causes large internal fragmentation
- * - Probably its better to use specific size classes (empirically
- * determined). NOTE: all those class sizes must be set as multiple of
- * ZS_ALIGN to make sure link_free itself never has to span 2 pages.
- *
- * ZS_MIN_ALLOC_SIZE and ZS_SIZE_CLASS_DELTA must be multiple of ZS_ALIGN
- * (reason above)
- */
-#define ZS_SIZE_CLASS_DELTA 16
-#define ZS_SIZE_CLASSES ((ZS_MAX_ALLOC_SIZE - ZS_MIN_ALLOC_SIZE) / \
- ZS_SIZE_CLASS_DELTA + 1)
-
-/*
- * We do not maintain any list for completely empty or full pages
- */
-enum fullness_group {
- ZS_ALMOST_FULL,
- ZS_ALMOST_EMPTY,
- _ZS_NR_FULLNESS_GROUPS,
-
- ZS_EMPTY,
- ZS_FULL
-};
-
-/*
- * We assign a page to ZS_ALMOST_EMPTY fullness group when:
- * n <= N / f, where
- * n = number of allocated objects
- * N = total number of objects zspage can store
- * f = 1/fullness_threshold_frac
- *
- * Similarly, we assign zspage to:
- * ZS_ALMOST_FULL when n > N / f
- * ZS_EMPTY when n == 0
- * ZS_FULL when n == N
- *
- * (see: fix_fullness_group())
- */
-static const int fullness_threshold_frac = 4;
-
-struct mapping_area {
- struct vm_struct *vm;
- pte_t *vm_ptes[2];
- char *vm_addr;
-};
-
-struct size_class {
- /*
- * Size of objects stored in this class. Must be multiple
- * of ZS_ALIGN.
- */
- int size;
- unsigned int index;
-
- /* Number of PAGE_SIZE sized pages to combine to form a 'zspage' */
- int zspage_order;
-
- spinlock_t lock;
-
- /* stats */
- u64 pages_allocated;
-
- struct page *fullness_list[_ZS_NR_FULLNESS_GROUPS];
-};
-
-/*
- * Placed within free objects to form a singly linked list.
- * For every zspage, first_page->freelist gives head of this list.
- *
- * This must be power of 2 and less than or equal to ZS_ALIGN
- */
-struct link_free {
- /* Handle of next free chunk (encodes <PFN, obj_idx>) */
- void *next;
-};
-
-struct zs_pool {
- struct size_class size_class[ZS_SIZE_CLASSES];
-
- gfp_t flags; /* allocation flags used when growing pool */
- const char *name;
-};
-
-#endif
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 01dce2d..0d17026 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -7,7 +7,7 @@
obj-$(CONFIG_THERMAL_TSENS) += msm_tsens.o
obj-$(CONFIG_THERMAL_TSENS8960) += msm8960_tsens.o
obj-$(CONFIG_THERMAL_PM8XXX) += pm8xxx-tm.o
-obj-$(CONFIG_THERMAL_MONITOR) += msm_thermal.o
+obj-$(CONFIG_THERMAL_MONITOR) += msm_thermal.o msm_thermal-dev.o
obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o
obj-$(CONFIG_THERMAL_TSENS8974) += msm8974-tsens.o
obj-$(CONFIG_THERMAL_QPNP) += qpnp-temp-alarm.o
diff --git a/drivers/thermal/msm_thermal-dev.c b/drivers/thermal/msm_thermal-dev.c
new file mode 100644
index 0000000..c34dd27
--- /dev/null
+++ b/drivers/thermal/msm_thermal-dev.c
@@ -0,0 +1,224 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/msm_thermal_ioctl.h>
+#include <linux/msm_thermal.h>
+#include <linux/uaccess.h>
+#include <linux/cdev.h>
+#include <linux/semaphore.h>
+#include <linux/module.h>
+
+struct msm_thermal_ioctl_dev {
+ struct semaphore sem;
+ struct cdev char_dev;
+};
+
+static int msm_thermal_major;
+static struct class *thermal_class;
+static struct msm_thermal_ioctl_dev *msm_thermal_dev;
+
+static int msm_thermal_ioctl_open(struct inode *node, struct file *filep)
+{
+ int ret = 0;
+ struct msm_thermal_ioctl_dev *dev;
+
+ dev = container_of(node->i_cdev, struct msm_thermal_ioctl_dev,
+ char_dev);
+ filep->private_data = dev;
+
+ return ret;
+}
+
+static int msm_thermal_ioctl_release(struct inode *node, struct file *filep)
+{
+ pr_debug("%s: IOCTL: release\n", KBUILD_MODNAME);
+ return 0;
+}
+
+static long validate_and_copy(unsigned int *cmd, unsigned long *arg,
+ struct msm_thermal_ioctl *query)
+{
+ long ret = 0, err_val = 0;
+
+ if ((_IOC_TYPE(*cmd) != MSM_THERMAL_MAGIC_NUM) ||
+ (_IOC_NR(*cmd) >= MSM_CMD_MAX_NR)) {
+ ret = -ENOTTY;
+ goto validate_exit;
+ }
+
+ if (_IOC_DIR(*cmd) & _IOC_READ) {
+ err_val = !access_ok(VERIFY_WRITE, (void __user *)*arg,
+ _IOC_SIZE(*cmd));
+ } else if (_IOC_DIR(*cmd) & _IOC_WRITE) {
+ err_val = !access_ok(VERIFY_READ, (void __user *)*arg,
+ _IOC_SIZE(*cmd));
+ }
+ if (err_val) {
+ ret = -EFAULT;
+ goto validate_exit;
+ }
+
+ if (copy_from_user(query, (void __user *)(*arg),
+ sizeof(struct msm_thermal_ioctl))) {
+ ret = -EACCES;
+ goto validate_exit;
+ }
+
+ if (query->size != sizeof(struct msm_thermal_ioctl)) {
+ pr_err("%s: Invalid input argument size\n", __func__);
+ ret = -EINVAL;
+ goto validate_exit;
+ }
+
+ switch (*cmd) {
+ case MSM_THERMAL_SET_CPU_MAX_FREQUENCY:
+ case MSM_THERMAL_SET_CPU_MIN_FREQUENCY:
+ if (query->cpu_freq.cpu_num >= num_possible_cpus()) {
+ pr_err("%s: Invalid CPU number: %u\n", __func__,
+ query->cpu_freq.cpu_num);
+ ret = -EINVAL;
+ goto validate_exit;
+ }
+ break;
+ default:
+ ret = -ENOTTY;
+ goto validate_exit;
+ break;
+ }
+
+validate_exit:
+ return ret;
+}
+
+static long msm_thermal_ioctl_process(struct file *filep, unsigned int cmd,
+ unsigned long arg)
+{
+ long ret = 0;
+ struct msm_thermal_ioctl query;
+
+ pr_debug("%s: IOCTL: processing cmd:%u\n", KBUILD_MODNAME, cmd);
+
+ ret = validate_and_copy(&cmd, &arg, &query);
+ if (ret)
+ goto process_exit;
+
+ switch (cmd) {
+ case MSM_THERMAL_SET_CPU_MAX_FREQUENCY:
+ ret = msm_thermal_set_frequency(query.cpu_freq.cpu_num,
+ query.cpu_freq.freq_req, true);
+ break;
+ case MSM_THERMAL_SET_CPU_MIN_FREQUENCY:
+ ret = msm_thermal_set_frequency(query.cpu_freq.cpu_num,
+ query.cpu_freq.freq_req, false);
+ break;
+ default:
+ ret = -ENOTTY;
+ goto process_exit;
+ }
+process_exit:
+ return ret;
+}
+
+static const struct file_operations msm_thermal_fops = {
+ .owner = THIS_MODULE,
+ .open = msm_thermal_ioctl_open,
+ .unlocked_ioctl = msm_thermal_ioctl_process,
+ .release = msm_thermal_ioctl_release,
+};
+
+int msm_thermal_ioctl_init()
+{
+ int ret = 0;
+ dev_t thermal_dev;
+ struct device *therm_device;
+
+ ret = alloc_chrdev_region(&thermal_dev, 0, 1,
+ MSM_THERMAL_IOCTL_NAME);
+ if (ret < 0) {
+ pr_err("%s: Error in allocating char device region. Err:%d\n",
+ KBUILD_MODNAME, ret);
+ goto ioctl_init_exit;
+ }
+
+ msm_thermal_major = MAJOR(thermal_dev);
+
+ thermal_class = class_create(THIS_MODULE, "msm_thermal");
+ if (IS_ERR(thermal_class)) {
+ pr_err("%s: Error in creating class\n",
+ KBUILD_MODNAME);
+ ret = PTR_ERR(thermal_class);
+ goto ioctl_class_fail;
+ }
+
+ therm_device = device_create(thermal_class, NULL, thermal_dev, NULL,
+ MSM_THERMAL_IOCTL_NAME);
+ if (IS_ERR(therm_device)) {
+ pr_err("%s: Error in creating character device\n",
+ KBUILD_MODNAME);
+ ret = PTR_ERR(therm_device);
+ goto ioctl_dev_fail;
+ }
+ msm_thermal_dev = kmalloc(sizeof(struct msm_thermal_ioctl_dev),
+ GFP_KERNEL);
+ if (!msm_thermal_dev) {
+ pr_err("%s: Error allocating memory\n",
+ KBUILD_MODNAME);
+ ret = -ENOMEM;
+ goto ioctl_clean_all;
+ }
+
+ memset(msm_thermal_dev, 0, sizeof(struct msm_thermal_ioctl_dev));
+ sema_init(&msm_thermal_dev->sem, 1);
+ cdev_init(&msm_thermal_dev->char_dev, &msm_thermal_fops);
+ ret = cdev_add(&msm_thermal_dev->char_dev, thermal_dev, 1);
+ if (ret < 0) {
+ pr_err("%s: Error in adding character device\n",
+ KBUILD_MODNAME);
+ goto ioctl_clean_all;
+ }
+
+ return ret;
+
+ioctl_clean_all:
+ device_destroy(thermal_class, thermal_dev);
+ioctl_dev_fail:
+ class_destroy(thermal_class);
+ioctl_class_fail:
+ unregister_chrdev_region(thermal_dev, 1);
+ioctl_init_exit:
+ return ret;
+}
+
+void msm_thermal_ioctl_cleanup()
+{
+ dev_t thermal_dev = MKDEV(msm_thermal_major, 0);
+
+ if (!msm_thermal_dev) {
+ pr_err("%s: Thermal IOCTL cleanup already done\n",
+ KBUILD_MODNAME);
+ return;
+ }
+
+ device_destroy(thermal_class, thermal_dev);
+ class_destroy(thermal_class);
+ cdev_del(&msm_thermal_dev->char_dev);
+ unregister_chrdev_region(thermal_dev, 1);
+ kfree(msm_thermal_dev);
+ msm_thermal_dev = NULL;
+ thermal_class = NULL;
+}
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index 00df613..c366086 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -32,15 +32,16 @@
#include <linux/types.h>
#include <linux/android_alarm.h>
#include <linux/thermal.h>
-#include <mach/cpufreq.h>
#include <mach/rpm-regulator.h>
#include <mach/rpm-regulator-smd.h>
#include <linux/regulator/consumer.h>
+#include <linux/msm_thermal_ioctl.h>
+#define MAX_CURRENT_UA 1000000
#define MAX_RAILS 5
+#define MAX_THRESHOLD 2
static struct msm_thermal_data msm_thermal_info;
-static uint32_t limited_max_freq = MSM_CPUFREQ_NO_LIMIT;
static struct delayed_work check_temp_work;
static bool core_control_enabled;
static uint32_t cpus_offlined;
@@ -51,11 +52,14 @@
static struct kobject *cc_kobj;
static struct work_struct timer_work;
static struct task_struct *hotplug_task;
+static struct task_struct *freq_mitigation_task;
static struct completion hotplug_notify_complete;
+static struct completion freq_mitigation_complete;
static int enabled;
static int rails_cnt;
static int psm_rails_cnt;
+static int ocr_rail_cnt;
static int limit_idx;
static int limit_idx_low;
static int limit_idx_high;
@@ -69,16 +73,39 @@
static bool psm_enabled;
static bool psm_nodes_called;
static bool psm_probed;
+static bool hotplug_enabled;
+static bool freq_mitigation_enabled;
+static bool ocr_enabled;
+static bool ocr_nodes_called;
+static bool ocr_probed;
static int *tsens_id_map;
static DEFINE_MUTEX(vdd_rstr_mutex);
static DEFINE_MUTEX(psm_mutex);
+static DEFINE_MUTEX(ocr_mutex);
+static uint32_t min_freq_limit;
+
+enum thermal_threshold {
+ HOTPLUG_THRESHOLD_HIGH,
+ HOTPLUG_THRESHOLD_LOW,
+ FREQ_THRESHOLD_HIGH,
+ FREQ_THRESHOLD_LOW,
+ THRESHOLD_MAX_NR,
+};
struct cpu_info {
uint32_t cpu;
+ const char *sensor_type;
+ uint32_t sensor_id;
bool offline;
bool user_offline;
- const char *sensor_type;
- struct sensor_threshold thresh[2];
+ bool hotplug_thresh_clear;
+ struct sensor_threshold threshold[THRESHOLD_MAX_NR];
+ bool max_freq;
+ uint32_t user_max_freq;
+ uint32_t user_min_freq;
+ uint32_t limited_max_freq;
+ uint32_t limited_min_freq;
+ bool freq_thresh_clear;
};
struct rail {
@@ -100,10 +127,12 @@
uint8_t mode;
struct kobj_attribute mode_attr;
struct rpm_regulator *reg;
+ struct regulator *phase_reg;
struct attribute_group attr_gp;
};
static struct psm_rail *psm_rails;
+static struct psm_rail *ocr_rails;
static struct rail *rails;
static struct cpu_info cpus[NR_CPUS];
@@ -119,6 +148,12 @@
PMIC_PWM_MODE = RPM_REGULATOR_MODE_HPM,
};
+enum ocr_request {
+ OPTIMUM_CURRENT_MIN,
+ OPTIMUM_CURRENT_MAX,
+ OPTIMUM_CURRENT_NR,
+};
+
#define VDD_RES_RO_ATTRIB(_rail, ko_attr, j, _name) \
ko_attr.attr.name = __stringify(_name); \
ko_attr.attr.mode = 444; \
@@ -144,6 +179,14 @@
#define VDD_RSTR_REG_LEVEL_FROM_ATTRIBS(attr) \
(container_of(attr, struct rail, level_attr));
+#define OCR_RW_ATTRIB(_rail, ko_attr, j, _name) \
+ ko_attr.attr.name = __stringify(_name); \
+ ko_attr.attr.mode = 644; \
+ ko_attr.show = ocr_reg_##_name##_show; \
+ ko_attr.store = ocr_reg_##_name##_store; \
+ sysfs_attr_init(&ko_attr.attr); \
+ _rail.attr_gp.attrs[j] = &ko_attr.attr;
+
#define PSM_RW_ATTRIB(_rail, ko_attr, j, _name) \
ko_attr.attr.name = __stringify(_name); \
ko_attr.attr.mode = 644; \
@@ -154,6 +197,34 @@
#define PSM_REG_MODE_FROM_ATTRIBS(attr) \
(container_of(attr, struct psm_rail, mode_attr));
+
+static int msm_thermal_cpufreq_callback(struct notifier_block *nfb,
+ unsigned long event, void *data)
+{
+ struct cpufreq_policy *policy = data;
+ uint32_t max_freq_req = cpus[policy->cpu].limited_max_freq;
+ uint32_t min_freq_req = cpus[policy->cpu].limited_min_freq;
+
+ switch (event) {
+ case CPUFREQ_INCOMPATIBLE:
+ pr_debug("%s: mitigating cpu %d to freq max: %u min: %u\n",
+ KBUILD_MODNAME, policy->cpu, max_freq_req, min_freq_req);
+
+ cpufreq_verify_within_limits(policy, min_freq_req,
+ max_freq_req);
+
+ if (max_freq_req < min_freq_req)
+ pr_err("Invalid frequency request Max:%u Min:%u\n",
+ max_freq_req, min_freq_req);
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block msm_thermal_cpufreq_notifier = {
+ .notifier_call = msm_thermal_cpufreq_callback,
+};
+
/* If freq table exists, then we can send freq request */
static int check_freq_table(void)
{
@@ -170,40 +241,39 @@
return ret;
}
+static void update_cpu_freq(int cpu)
+{
+ if (cpu_online(cpu)) {
+ if (cpufreq_update_policy(cpu))
+ pr_err("Unable to update policy for cpu:%d\n", cpu);
+ }
+}
+
static int update_cpu_min_freq_all(uint32_t min)
{
- int cpu = 0;
+ uint32_t cpu = 0;
int ret = 0;
- struct cpufreq_policy *policy = NULL;
if (!freq_table_get) {
ret = check_freq_table();
if (ret) {
- pr_err("%s:Fail to get freq table\n", __func__);
+ pr_err("%s:Fail to get freq table\n", KBUILD_MODNAME);
return ret;
}
}
/* If min is larger than allowed max */
- if (min != MSM_CPUFREQ_NO_LIMIT &&
- min > table[limit_idx_high].frequency)
- min = table[limit_idx_high].frequency;
+ min = min(min, table[limit_idx_high].frequency);
- for_each_possible_cpu(cpu) {
- ret = msm_cpufreq_set_freq_limits(cpu, min, limited_max_freq);
- if (ret) {
- pr_err("%s:Fail to set limits for cpu%d\n",
- __func__, cpu);
- return ret;
+ if (freq_mitigation_task) {
+ min_freq_limit = min;
+ complete(&freq_mitigation_complete);
+ } else {
+ get_online_cpus();
+ for_each_possible_cpu(cpu) {
+ cpus[cpu].limited_min_freq = min;
+ update_cpu_freq(cpu);
}
-
- if (cpu_online(cpu)) {
- policy = cpufreq_cpu_get(cpu);
- if (!policy)
- continue;
- cpufreq_driver_target(policy, policy->cur,
- CPUFREQ_RELATION_L);
- cpufreq_cpu_put(policy);
- }
+ put_online_cpus();
}
return ret;
@@ -434,6 +504,92 @@
return count;
}
+static int request_optimum_current(struct psm_rail *rail, enum ocr_request req)
+{
+ int ret = 0;
+
+ if ((!rail) || (req >= OPTIMUM_CURRENT_NR) ||
+ (req < 0)) {
+ pr_err("%s:%s Invalid input\n", KBUILD_MODNAME, __func__);
+ ret = -EINVAL;
+ goto request_ocr_exit;
+ }
+
+ ret = regulator_set_optimum_mode(rail->phase_reg,
+ (req == OPTIMUM_CURRENT_MAX) ? MAX_CURRENT_UA : 0);
+ if (ret < 0) {
+ pr_err("%s: Optimum current request failed\n", KBUILD_MODNAME);
+ goto request_ocr_exit;
+ }
+ ret = 0; /*regulator_set_optimum_mode returns the mode on success*/
+ pr_debug("%s: Requested optimum current mode: %d\n",
+ KBUILD_MODNAME, req);
+
+request_ocr_exit:
+ return ret;
+}
+
+static int ocr_set_mode_all(enum ocr_request req)
+{
+ int ret = 0, i;
+
+ for (i = 0; i < ocr_rail_cnt; i++) {
+ if (ocr_rails[i].mode == req)
+ continue;
+ ret = request_optimum_current(&ocr_rails[i], req);
+ if (ret)
+ goto ocr_set_mode_exit;
+ ocr_rails[i].mode = req;
+ }
+
+ocr_set_mode_exit:
+ return ret;
+}
+
+static int ocr_reg_mode_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct psm_rail *reg = PSM_REG_MODE_FROM_ATTRIBS(attr);
+ return snprintf(buf, PAGE_SIZE, "%d\n", reg->mode);
+}
+
+static ssize_t ocr_reg_mode_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ int ret = 0;
+ int val = 0;
+ struct psm_rail *reg = PSM_REG_MODE_FROM_ATTRIBS(attr);
+
+ if (!ocr_enabled)
+ return count;
+
+ mutex_lock(&ocr_mutex);
+ ret = kstrtoint(buf, 10, &val);
+ if (ret) {
+ pr_err("%s: Invalid input %s for mode\n",
+ KBUILD_MODNAME, buf);
+ goto done_ocr_store;
+ }
+
+ if ((val != OPTIMUM_CURRENT_MAX) &&
+ (val != OPTIMUM_CURRENT_MIN)) {
+ pr_err("%s: Invalid value %d for mode\n",
+ KBUILD_MODNAME, val);
+ goto done_ocr_store;
+ }
+
+ if (val != reg->mode) {
+ ret = request_optimum_current(reg, val);
+ if (ret)
+ goto done_ocr_store;
+ reg->mode = val;
+ }
+
+done_ocr_store:
+ mutex_unlock(&ocr_mutex);
+ return count;
+}
+
static int psm_reg_mode_show(
struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
@@ -595,31 +751,73 @@
return ret;
}
-static int update_cpu_max_freq(int cpu, uint32_t max_freq)
+static int set_and_activate_threshold(uint32_t sensor_id,
+ struct sensor_threshold *threshold)
{
int ret = 0;
- ret = msm_cpufreq_set_freq_limits(cpu, MSM_CPUFREQ_NO_LIMIT, max_freq);
- if (ret)
- return ret;
-
- limited_max_freq = max_freq;
- if (max_freq != MSM_CPUFREQ_NO_LIMIT)
- pr_info("%s: Limiting cpu%d max frequency to %d\n",
- KBUILD_MODNAME, cpu, max_freq);
- else
- pr_info("%s: Max frequency reset for cpu%d\n",
- KBUILD_MODNAME, cpu);
-
- if (cpu_online(cpu)) {
- struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
- if (!policy)
- return ret;
- ret = cpufreq_driver_target(policy, policy->cur,
- CPUFREQ_RELATION_H);
- cpufreq_cpu_put(policy);
+ ret = sensor_set_trip(sensor_id, threshold);
+ if (ret != 0) {
+ pr_err("%s: Error in setting trip %d\n",
+ KBUILD_MODNAME, threshold->trip);
+ goto set_done;
}
+ ret = sensor_activate_trip(sensor_id, threshold, true);
+ if (ret != 0) {
+ pr_err("%s: Error in enabling trip %d\n",
+ KBUILD_MODNAME, threshold->trip);
+ goto set_done;
+ }
+
+set_done:
+ return ret;
+}
+
+static int set_threshold(uint32_t sensor_id,
+ struct sensor_threshold *threshold)
+{
+ struct tsens_device tsens_dev;
+ int i = 0, ret = 0;
+ long temp;
+
+ if ((!threshold) || check_sensor_id(sensor_id)) {
+ pr_err("%s: Invalid input\n", KBUILD_MODNAME);
+ ret = -EINVAL;
+ goto set_threshold_exit;
+ }
+
+ tsens_dev.sensor_num = sensor_id;
+ ret = tsens_get_temp(&tsens_dev, &temp);
+ if (ret) {
+ pr_err("%s: Unable to read TSENS sensor %d\n",
+ KBUILD_MODNAME, tsens_dev.sensor_num);
+ goto set_threshold_exit;
+ }
+ while (i < MAX_THRESHOLD) {
+ switch (threshold[i].trip) {
+ case THERMAL_TRIP_CONFIGURABLE_HI:
+ if (threshold[i].temp >= temp) {
+ ret = set_and_activate_threshold(sensor_id,
+ &threshold[i]);
+ if (ret)
+ goto set_threshold_exit;
+ }
+ break;
+ case THERMAL_TRIP_CONFIGURABLE_LOW:
+ if (threshold[i].temp <= temp) {
+ ret = set_and_activate_threshold(sensor_id,
+ &threshold[i]);
+ if (ret)
+ goto set_threshold_exit;
+ }
+ break;
+ default:
+ break;
+ }
+ i++;
+ }
+set_threshold_exit:
return ret;
}
@@ -676,7 +874,7 @@
/* Call with core_control_mutex locked */
static int __ref update_offline_cores(int val)
{
- int cpu = 0;
+ uint32_t cpu = 0;
int ret = 0;
if (!core_control_enabled)
@@ -700,8 +898,7 @@
static __ref int do_hotplug(void *data)
{
int ret = 0;
- int cpu = 0;
- uint32_t mask = 0;
+ uint32_t cpu = 0, mask = 0;
if (!core_control_enabled)
return -EINVAL;
@@ -713,6 +910,13 @@
mutex_lock(&core_control_mutex);
for_each_possible_cpu(cpu) {
+ if (hotplug_enabled &&
+ cpus[cpu].hotplug_thresh_clear) {
+ set_threshold(cpus[cpu].sensor_id,
+ &cpus[cpu].threshold[HOTPLUG_THRESHOLD_HIGH]);
+
+ cpus[cpu].hotplug_thresh_clear = false;
+ }
if (cpus[cpu].offline || cpus[cpu].user_offline)
mask |= BIT(cpu);
}
@@ -736,6 +940,63 @@
}
#endif
+static int do_ocr(void)
+{
+ struct tsens_device tsens_dev;
+ long temp = 0;
+ int ret = 0;
+ int i = 0, j = 0;
+ int auto_cnt = 0;
+
+ if (!ocr_enabled)
+ return ret;
+
+ mutex_lock(&ocr_mutex);
+ for (i = 0; i < max_tsens_num; i++) {
+ tsens_dev.sensor_num = tsens_id_map[i];
+ ret = tsens_get_temp(&tsens_dev, &temp);
+ if (ret) {
+ pr_debug("%s: Unable to read TSENS sensor %d\n",
+ __func__, tsens_dev.sensor_num);
+ auto_cnt++;
+ continue;
+ }
+
+ if (temp > msm_thermal_info.ocr_temp_degC) {
+ if (ocr_rails[0].init != OPTIMUM_CURRENT_NR)
+ for (j = 0; j < ocr_rail_cnt; j++)
+ ocr_rails[j].init = OPTIMUM_CURRENT_NR;
+ ret = ocr_set_mode_all(OPTIMUM_CURRENT_MAX);
+ if (ret)
+ pr_err("Error setting max optimum current\n");
+ goto do_ocr_exit;
+ } else if (temp <= (msm_thermal_info.ocr_temp_degC -
+ msm_thermal_info.ocr_temp_hyst_degC))
+ auto_cnt++;
+ }
+
+ if (auto_cnt == max_tsens_num ||
+ ocr_rails[0].init != OPTIMUM_CURRENT_NR) {
+ /* 'init' not equal to OPTIMUM_CURRENT_NR means this is the
+ ** first polling iteration after device probe. During first
+ ** iteration, if temperature is less than the set point, clear
+ ** the max current request made and reset the 'init'.
+ */
+ if (ocr_rails[0].init != OPTIMUM_CURRENT_NR)
+ for (j = 0; j < ocr_rail_cnt; j++)
+ ocr_rails[j].init = OPTIMUM_CURRENT_NR;
+ ret = ocr_set_mode_all(OPTIMUM_CURRENT_MIN);
+ if (ret) {
+ pr_err("Error setting min optimum current\n");
+ goto do_ocr_exit;
+ }
+ }
+
+do_ocr_exit:
+ mutex_unlock(&ocr_mutex);
+ return ret;
+}
+
static int do_vdd_restriction(void)
{
struct tsens_device tsens_dev;
@@ -835,15 +1096,14 @@
static void __ref do_freq_control(long temp)
{
- int ret = 0;
- int cpu = 0;
- uint32_t max_freq = limited_max_freq;
+ uint32_t cpu = 0;
+ uint32_t max_freq = cpus[cpu].limited_max_freq;
if (temp >= msm_thermal_info.limit_temp_degC) {
if (limit_idx == limit_idx_low)
return;
- limit_idx -= msm_thermal_info.freq_step;
+ limit_idx -= msm_thermal_info.bootup_freq_step;
if (limit_idx < limit_idx_low)
limit_idx = limit_idx_low;
max_freq = table[limit_idx].frequency;
@@ -852,28 +1112,26 @@
if (limit_idx == limit_idx_high)
return;
- limit_idx += msm_thermal_info.freq_step;
+ limit_idx += msm_thermal_info.bootup_freq_step;
if (limit_idx >= limit_idx_high) {
limit_idx = limit_idx_high;
- max_freq = MSM_CPUFREQ_NO_LIMIT;
+ max_freq = UINT_MAX;
} else
max_freq = table[limit_idx].frequency;
}
- if (max_freq == limited_max_freq)
+ if (max_freq == cpus[cpu].limited_max_freq)
return;
/* Update new limits */
+ get_online_cpus();
for_each_possible_cpu(cpu) {
- if (!(msm_thermal_info.freq_control_mask & BIT(cpu)))
+ if (!(msm_thermal_info.bootup_freq_control_mask & BIT(cpu)))
continue;
- ret = update_cpu_max_freq(cpu, max_freq);
- if (ret)
- pr_debug(
- "%s: Unable to limit cpu%d max freq to %d\n",
- KBUILD_MODNAME, cpu, max_freq);
+ cpus[cpu].limited_max_freq = max_freq;
+ update_cpu_freq(cpu);
}
-
+ put_online_cpus();
}
static void __ref check_temp(struct work_struct *work)
@@ -902,6 +1160,7 @@
do_core_control(temp);
do_vdd_restriction();
do_psm();
+ do_ocr();
do_freq_control(temp);
reschedule:
@@ -913,7 +1172,7 @@
static int __ref msm_thermal_cpu_callback(struct notifier_block *nfb,
unsigned long action, void *hcpu)
{
- unsigned int cpu = (unsigned long)hcpu;
+ uint32_t cpu = (uint32_t)hcpu;
if (action == CPU_UP_PREPARE || action == CPU_UP_PREPARE_FROZEN) {
if (core_control_enabled &&
@@ -988,10 +1247,12 @@
default:
break;
}
- if (hotplug_task)
+ if (hotplug_task) {
+ cpu_node->hotplug_thresh_clear = true;
complete(&hotplug_notify_complete);
- else
+ } else {
pr_err("%s: Hotplug task is not initialized\n", KBUILD_MODNAME);
+ }
return 0;
}
/* Adjust cpus offlined bit based on temperature reading. */
@@ -999,17 +1260,20 @@
{
struct tsens_device tsens_dev;
long temp = 0;
- int cpu = 0;
+ uint32_t cpu = 0;
+
+ if (!hotplug_enabled)
+ return 0;
mutex_lock(&core_control_mutex);
for_each_possible_cpu(cpu) {
if (!(msm_thermal_info.core_control_mask & BIT(cpus[cpu].cpu)))
continue;
- tsens_dev.sensor_num = sensor_get_id(\
- (char *)cpus[cpu].sensor_type);
+ tsens_dev.sensor_num = cpus[cpu].sensor_id;
if (tsens_get_temp(&tsens_dev, &temp)) {
pr_err("%s: Unable to read TSENS sensor %d\n",
KBUILD_MODNAME, tsens_dev.sensor_num);
+ mutex_unlock(&core_control_mutex);
return -EINVAL;
}
@@ -1033,31 +1297,34 @@
static void hotplug_init(void)
{
- int cpu = 0;
+ uint32_t cpu = 0;
+ struct sensor_threshold *hi_thresh = NULL, *low_thresh = NULL;
if (hotplug_task)
return;
+ if (!hotplug_enabled)
+ goto init_kthread;
+
for_each_possible_cpu(cpu) {
+ cpus[cpu].sensor_id =
+ sensor_get_id((char *)cpus[cpu].sensor_type);
if (!(msm_thermal_info.core_control_mask & BIT(cpus[cpu].cpu)))
continue;
- cpus[cpu].cpu = (uint32_t)cpu;
- cpus[cpu].thresh[0].temp = msm_thermal_info.hotplug_temp_degC;
- cpus[cpu].thresh[0].trip = THERMAL_TRIP_CONFIGURABLE_HI;
- cpus[cpu].thresh[0].notify = hotplug_notify;
- cpus[cpu].thresh[0].data = (void *)&cpus[cpu];
- sensor_set_trip(sensor_get_id((char *)cpus[cpu].sensor_type),
- &cpus[cpu].thresh[0]);
- cpus[cpu].thresh[1].temp = msm_thermal_info.hotplug_temp_degC -
+ hi_thresh = &cpus[cpu].threshold[HOTPLUG_THRESHOLD_HIGH];
+ low_thresh = &cpus[cpu].threshold[HOTPLUG_THRESHOLD_LOW];
+ hi_thresh->temp = msm_thermal_info.hotplug_temp_degC;
+ hi_thresh->trip = THERMAL_TRIP_CONFIGURABLE_HI;
+ low_thresh->temp = msm_thermal_info.hotplug_temp_degC -
msm_thermal_info.hotplug_temp_hysteresis_degC;
- cpus[cpu].thresh[1].trip = THERMAL_TRIP_CONFIGURABLE_LOW;
- cpus[cpu].thresh[1].notify = hotplug_notify;
- cpus[cpu].thresh[1].data = (void *)&cpus[cpu];
- sensor_set_trip(sensor_get_id((char *)cpus[cpu].sensor_type),
- &cpus[cpu].thresh[1]);
+ low_thresh->trip = THERMAL_TRIP_CONFIGURABLE_LOW;
+ hi_thresh->notify = low_thresh->notify = hotplug_notify;
+ hi_thresh->data = low_thresh->data = (void *)&cpus[cpu];
+ set_threshold(cpus[cpu].sensor_id, hi_thresh);
}
+init_kthread:
init_completion(&hotplug_notify_complete);
hotplug_task = kthread_run(do_hotplug, NULL, "msm_thermal:hotplug");
if (IS_ERR(hotplug_task)) {
@@ -1073,6 +1340,167 @@
kthread_stop(hotplug_task);
}
+static __ref int do_freq_mitigation(void *data)
+{
+ int ret = 0;
+ uint32_t cpu = 0, max_freq_req = 0, min_freq_req = 0;
+
+ while (!kthread_should_stop()) {
+ wait_for_completion(&freq_mitigation_complete);
+ INIT_COMPLETION(freq_mitigation_complete);
+
+ get_online_cpus();
+ for_each_possible_cpu(cpu) {
+ max_freq_req = (cpus[cpu].max_freq) ?
+ msm_thermal_info.freq_limit :
+ UINT_MAX;
+ max_freq_req = min(max_freq_req,
+ cpus[cpu].user_max_freq);
+
+ min_freq_req = max(min_freq_limit,
+ cpus[cpu].user_min_freq);
+
+ if ((max_freq_req == cpus[cpu].limited_max_freq)
+ && (min_freq_req ==
+ cpus[cpu].limited_min_freq))
+ goto reset_threshold;
+
+ cpus[cpu].limited_max_freq = max_freq_req;
+ cpus[cpu].limited_min_freq = min_freq_req;
+ update_cpu_freq(cpu);
+reset_threshold:
+ if (freq_mitigation_enabled &&
+ cpus[cpu].freq_thresh_clear) {
+ set_threshold(cpus[cpu].sensor_id,
+ &cpus[cpu].threshold[FREQ_THRESHOLD_HIGH]);
+
+ cpus[cpu].freq_thresh_clear = false;
+ }
+ }
+ put_online_cpus();
+ }
+ return ret;
+}
+
+static int freq_mitigation_notify(enum thermal_trip_type type,
+ int temp, void *data)
+{
+ struct cpu_info *cpu_node = (struct cpu_info *) data;
+
+ pr_debug("%s: %s reached temp threshold: %d\n", KBUILD_MODNAME,
+ cpu_node->sensor_type, temp);
+
+ if (!(msm_thermal_info.freq_mitig_control_mask &
+ BIT(cpu_node->cpu)))
+ return 0;
+
+ switch (type) {
+ case THERMAL_TRIP_CONFIGURABLE_HI:
+ if (!cpu_node->max_freq) {
+ pr_info("%s: Mitigating cpu %d frequency to %d\n",
+ KBUILD_MODNAME, cpu_node->cpu,
+ msm_thermal_info.freq_limit);
+
+ cpu_node->max_freq = true;
+ }
+ break;
+ case THERMAL_TRIP_CONFIGURABLE_LOW:
+ if (cpu_node->max_freq) {
+ pr_info("%s: Removing frequency mitigation for cpu%d\n",
+ KBUILD_MODNAME, cpu_node->cpu);
+
+ cpu_node->max_freq = false;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (freq_mitigation_task) {
+ cpu_node->freq_thresh_clear = true;
+ complete(&freq_mitigation_complete);
+ } else {
+ pr_err("%s: Frequency mitigation task is not initialized\n",
+ KBUILD_MODNAME);
+ }
+
+ return 0;
+}
+
+static void freq_mitigation_init(void)
+{
+ uint32_t cpu = 0;
+ struct sensor_threshold *hi_thresh = NULL, *low_thresh = NULL;
+
+ if (freq_mitigation_task)
+ return;
+ if (!freq_mitigation_enabled)
+ goto init_freq_thread;
+
+ for_each_possible_cpu(cpu) {
+ if (!(msm_thermal_info.freq_mitig_control_mask & BIT(cpu)))
+ continue;
+ hi_thresh = &cpus[cpu].threshold[FREQ_THRESHOLD_HIGH];
+ low_thresh = &cpus[cpu].threshold[FREQ_THRESHOLD_LOW];
+
+ hi_thresh->temp = msm_thermal_info.freq_mitig_temp_degc;
+ hi_thresh->trip = THERMAL_TRIP_CONFIGURABLE_HI;
+ low_thresh->temp = msm_thermal_info.freq_mitig_temp_degc -
+ msm_thermal_info.freq_mitig_temp_hysteresis_degc;
+ low_thresh->trip = THERMAL_TRIP_CONFIGURABLE_LOW;
+ hi_thresh->notify = low_thresh->notify =
+ freq_mitigation_notify;
+ hi_thresh->data = low_thresh->data = (void *)&cpus[cpu];
+
+ set_threshold(cpus[cpu].sensor_id, hi_thresh);
+ }
+init_freq_thread:
+ init_completion(&freq_mitigation_complete);
+ freq_mitigation_task = kthread_run(do_freq_mitigation, NULL,
+ "msm_thermal:freq_mitig");
+
+ if (IS_ERR(freq_mitigation_task)) {
+ pr_err("%s: Failed to create frequency mitigation thread\n",
+ KBUILD_MODNAME);
+ return;
+ }
+}
+
+int msm_thermal_set_frequency(uint32_t cpu, uint32_t freq, bool is_max)
+{
+ int ret = 0;
+
+ if (cpu >= num_possible_cpus()) {
+ pr_err("%s: Invalid input\n", KBUILD_MODNAME);
+ ret = -EINVAL;
+ goto set_freq_exit;
+ }
+
+ if (is_max) {
+ if (cpus[cpu].user_max_freq == freq)
+ goto set_freq_exit;
+
+ cpus[cpu].user_max_freq = freq;
+ } else {
+ if (cpus[cpu].user_min_freq == freq)
+ goto set_freq_exit;
+
+ cpus[cpu].user_min_freq = freq;
+ }
+
+ if (freq_mitigation_task) {
+ complete(&freq_mitigation_complete);
+ } else {
+ pr_err("%s: Frequency mitigation task is not initialized\n",
+ KBUILD_MODNAME);
+ ret = -ESRCH;
+ goto set_freq_exit;
+ }
+
+set_freq_exit:
+ return ret;
+}
+
/*
* We will reset the cpu frequencies limits here. The core online/offline
* status will be carried over to the process stopping the msm_thermal, as
@@ -1080,18 +1508,22 @@
*/
static void __ref disable_msm_thermal(void)
{
- int cpu = 0;
+ uint32_t cpu = 0;
/* make sure check_temp is no longer running */
cancel_delayed_work(&check_temp_work);
flush_scheduled_work();
- if (limited_max_freq == MSM_CPUFREQ_NO_LIMIT)
- return;
-
+ get_online_cpus();
for_each_possible_cpu(cpu) {
- update_cpu_max_freq(cpu, MSM_CPUFREQ_NO_LIMIT);
+ if (cpus[cpu].limited_max_freq == UINT_MAX &&
+ cpus[cpu].limited_min_freq == 0)
+ continue;
+ cpus[cpu].limited_max_freq = UINT_MAX;
+ cpus[cpu].limited_min_freq = 0;
+ update_cpu_freq(cpu);
}
+ put_online_cpus();
}
static int __ref set_enabled(const char *val, const struct kernel_param *kp)
@@ -1102,9 +1534,10 @@
if (!enabled) {
disable_msm_thermal();
hotplug_init();
+ freq_mitigation_init();
} else
pr_info("%s: no action for enabled = %d\n",
- KBUILD_MODNAME, enabled);
+ KBUILD_MODNAME, enabled);
pr_info("%s: enabled = %d\n", KBUILD_MODNAME, enabled);
@@ -1169,7 +1602,7 @@
{
int ret = 0;
uint32_t val = 0;
- int cpu;
+ uint32_t cpu;
mutex_lock(&core_control_mutex);
ret = kstrtouint(buf, 10, &val);
@@ -1334,6 +1767,7 @@
int __devinit msm_thermal_init(struct msm_thermal_data *pdata)
{
int ret = 0;
+ uint32_t cpu;
BUG_ON(!pdata);
tsens_get_max_sensor_num(&max_tsens_num);
@@ -1345,7 +1779,15 @@
return -EINVAL;
enabled = 1;
-
+ for_each_possible_cpu(cpu) {
+ cpus[cpu].limited_max_freq = UINT_MAX;
+ cpus[cpu].limited_min_freq = 0;
+ }
+ ret = cpufreq_register_notifier(&msm_thermal_cpufreq_notifier,
+ CPUFREQ_POLICY_NOTIFIER);
+ if (ret)
+ pr_err("%s: cannot register cpufreq notifier\n",
+ KBUILD_MODNAME);
INIT_DELAYED_WORK(&check_temp_work, check_temp);
schedule_delayed_work(&check_temp_work, 0);
@@ -1355,6 +1797,42 @@
return ret;
}
+static int ocr_reg_init(struct platform_device *pdev)
+{
+ int ret = 0;
+ int i, j;
+
+ for (i = 0; i < ocr_rail_cnt; i++) {
+ /* Check if vdd_restriction has already initialized any
+ * regualtor handle. If so use the same handle.*/
+ for (j = 0; j < rails_cnt; j++) {
+ if (!strcmp(ocr_rails[i].name, rails[j].name)) {
+ if (rails[j].reg == NULL)
+ break;
+ ocr_rails[i].phase_reg = rails[j].reg;
+ goto reg_init;
+ }
+
+ }
+ ocr_rails[i].phase_reg = devm_regulator_get(&pdev->dev,
+ ocr_rails[i].name);
+ if (IS_ERR_OR_NULL(ocr_rails[i].phase_reg)) {
+ ret = PTR_ERR(ocr_rails[i].phase_reg);
+ if (ret != -EPROBE_DEFER) {
+ pr_err("%s, could not get regulator: %s\n",
+ __func__, ocr_rails[i].name);
+ ocr_rails[i].phase_reg = NULL;
+ ocr_rails[i].mode = 0;
+ ocr_rails[i].init = 0;
+ }
+ return ret;
+ }
+reg_init:
+ ocr_rails[i].mode = OPTIMUM_CURRENT_MIN;
+ }
+ return ret;
+}
+
static int vdd_restriction_reg_init(struct platform_device *pdev)
{
int ret = 0;
@@ -1524,6 +2002,80 @@
return rc;
}
+static int msm_thermal_add_ocr_nodes(void)
+{
+ struct kobject *module_kobj = NULL;
+ struct kobject *ocr_kobj = NULL;
+ struct kobject *ocr_reg_kobj[MAX_RAILS] = {0};
+ int rc = 0;
+ int i = 0;
+
+ if (!ocr_probed) {
+ ocr_nodes_called = true;
+ return rc;
+ }
+
+ if (ocr_probed && ocr_rail_cnt == 0)
+ return rc;
+
+ module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
+ if (!module_kobj) {
+ pr_err("%s: cannot find kobject for module %s\n",
+ __func__, KBUILD_MODNAME);
+ rc = -ENOENT;
+ goto ocr_node_exit;
+ }
+
+ ocr_kobj = kobject_create_and_add("opt_curr_req", module_kobj);
+ if (!ocr_kobj) {
+ pr_err("%s: cannot create ocr kobject\n", KBUILD_MODNAME);
+ rc = -ENOMEM;
+ goto ocr_node_exit;
+ }
+
+ for (i = 0; i < ocr_rail_cnt; i++) {
+ ocr_reg_kobj[i] = kobject_create_and_add(ocr_rails[i].name,
+ ocr_kobj);
+ if (!ocr_reg_kobj[i]) {
+ pr_err("%s: cannot create for kobject for %s\n",
+ KBUILD_MODNAME, ocr_rails[i].name);
+ rc = -ENOMEM;
+ goto ocr_node_exit;
+ }
+ ocr_rails[i].attr_gp.attrs = kzalloc( \
+ sizeof(struct attribute *) * 2, GFP_KERNEL);
+ if (!ocr_rails[i].attr_gp.attrs) {
+ rc = -ENOMEM;
+ goto ocr_node_exit;
+ }
+
+ OCR_RW_ATTRIB(ocr_rails[i], ocr_rails[i].mode_attr, 0, mode);
+ ocr_rails[i].attr_gp.attrs[1] = NULL;
+
+ rc = sysfs_create_group(ocr_reg_kobj[i], &ocr_rails[i].attr_gp);
+ if (rc) {
+ pr_err("%s: cannot create attribute group for %s\n",
+ KBUILD_MODNAME, ocr_rails[i].name);
+ goto ocr_node_exit;
+ }
+ }
+
+ocr_node_exit:
+ if (rc) {
+ for (i = 0; i < ocr_rail_cnt; i++) {
+ if (ocr_reg_kobj[i])
+ kobject_del(ocr_reg_kobj[i]);
+ if (ocr_rails[i].attr_gp.attrs) {
+ kfree(ocr_rails[i].attr_gp.attrs);
+ ocr_rails[i].attr_gp.attrs = NULL;
+ }
+ }
+ if (ocr_kobj)
+ kobject_del(ocr_kobj);
+ }
+ return rc;
+}
+
static int msm_thermal_add_psm_nodes(void)
{
struct kobject *module_kobj = NULL;
@@ -1659,7 +2211,7 @@
key = "qcom,freq-req";
rails[i].freq_req = of_property_read_bool(child_node, key);
if (rails[i].freq_req)
- rails[i].min_level = MSM_CPUFREQ_NO_LIMIT;
+ rails[i].min_level = 0;
else {
key = "qcom,min-level";
ret = of_property_read_u32(child_node, key,
@@ -1696,6 +2248,83 @@
return ret;
}
+static int probe_ocr(struct device_node *node, struct msm_thermal_data *data,
+ struct platform_device *pdev)
+{
+ int ret = 0;
+ int j = 0;
+ char *key = NULL;
+
+ if (ocr_probed) {
+ pr_info("%s: Nodes already probed\n",
+ __func__);
+ goto read_ocr_exit;
+ }
+ ocr_rails = NULL;
+
+ key = "qti,pmic-opt-curr-temp";
+ ret = of_property_read_u32(node, key, &data->ocr_temp_degC);
+ if (ret)
+ goto read_ocr_fail;
+
+ key = "qti,pmic-opt-curr-temp-hysteresis";
+ ret = of_property_read_u32(node, key, &data->ocr_temp_hyst_degC);
+ if (ret)
+ goto read_ocr_fail;
+
+ key = "qti,pmic-opt-curr-regs";
+ ocr_rail_cnt = of_property_count_strings(node, key);
+ ocr_rails = kzalloc(sizeof(struct psm_rail) * ocr_rail_cnt,
+ GFP_KERNEL);
+ if (!ocr_rails) {
+ pr_err("%s: Fail to allocate memory for ocr rails\n", __func__);
+ ocr_rail_cnt = 0;
+ return -ENOMEM;
+ }
+
+ for (j = 0; j < ocr_rail_cnt; j++) {
+ ret = of_property_read_string_index(node, key, j,
+ &ocr_rails[j].name);
+ if (ret)
+ goto read_ocr_fail;
+ ocr_rails[j].phase_reg = NULL;
+ ocr_rails[j].init = OPTIMUM_CURRENT_MAX;
+ }
+
+ if (ocr_rail_cnt) {
+ ret = ocr_reg_init(pdev);
+ if (ret) {
+ pr_info("%s:Failed to get regulators. KTM continues.\n",
+ __func__);
+ goto read_ocr_fail;
+ }
+ ocr_enabled = true;
+ ocr_nodes_called = false;
+ /*
+ * Vote for max optimum current by default until we have made
+ * our first temp reading
+ */
+ if (ocr_set_mode_all(OPTIMUM_CURRENT_MAX))
+ pr_err("Set max optimum current failed\n");
+ }
+
+read_ocr_fail:
+ ocr_probed = true;
+ if (ret) {
+ dev_info(&pdev->dev,
+ "%s:Failed reading node=%s, key=%s. KTM continues\n",
+ __func__, node->full_name, key);
+ if (ocr_rails)
+ kfree(ocr_rails);
+ ocr_rails = NULL;
+ ocr_rail_cnt = 0;
+ }
+ if (ret == -EPROBE_DEFER)
+ ocr_probed = false;
+read_ocr_exit:
+ return ret;
+}
+
static int probe_psm(struct device_node *node, struct msm_thermal_data *data,
struct platform_device *pdev)
{
@@ -1760,9 +2389,14 @@
struct platform_device *pdev)
{
char *key = NULL;
- int cpu_cnt = 0;
+ uint32_t cpu_cnt = 0;
int ret = 0;
- int cpu = 0;
+ uint32_t cpu = 0;
+
+ if (num_possible_cpus() > 1) {
+ core_control_enabled = 1;
+ hotplug_enabled = 1;
+ }
key = "qcom,core-limit-temp";
ret = of_property_read_u32(node, key, &data->core_limit_temp_degC);
@@ -1782,34 +2416,33 @@
key = "qcom,hotplug-temp";
ret = of_property_read_u32(node, key, &data->hotplug_temp_degC);
if (ret)
- goto read_node_fail;
+ goto hotplug_node_fail;
key = "qcom,hotplug-temp-hysteresis";
ret = of_property_read_u32(node, key,
&data->hotplug_temp_hysteresis_degC);
if (ret)
- goto read_node_fail;
+ goto hotplug_node_fail;
key = "qcom,cpu-sensors";
cpu_cnt = of_property_count_strings(node, key);
if (cpu_cnt != num_possible_cpus()) {
pr_err("%s: Wrong number of cpu\n", KBUILD_MODNAME);
- goto read_node_fail;
+ ret = -EINVAL;
+ goto hotplug_node_fail;
}
for_each_possible_cpu(cpu) {
cpus[cpu].cpu = cpu;
cpus[cpu].offline = 0;
cpus[cpu].user_offline = 0;
+ cpus[cpu].hotplug_thresh_clear = false;
ret = of_property_read_string_index(node, key, cpu,
&cpus[cpu].sensor_type);
if (ret)
- goto read_node_fail;
+ goto hotplug_node_fail;
}
- if (num_possible_cpus() > 1)
- core_control_enabled = 1;
-
read_node_fail:
if (ret) {
dev_info(&pdev->dev,
@@ -1819,6 +2452,65 @@
}
return ret;
+
+hotplug_node_fail:
+ if (ret) {
+ dev_info(&pdev->dev,
+ "%s:Failed reading node=%s, key=%s. KTM continues\n",
+ KBUILD_MODNAME, node->full_name, key);
+ hotplug_enabled = 0;
+ }
+
+ return ret;
+}
+
+static int probe_freq_mitigation(struct device_node *node,
+ struct msm_thermal_data *data,
+ struct platform_device *pdev)
+{
+ char *key = NULL;
+ int ret = 0;
+ uint32_t cpu;
+
+ key = "qcom,freq-mitigation-temp";
+ ret = of_property_read_u32(node, key, &data->freq_mitig_temp_degc);
+ if (ret)
+ goto PROBE_FREQ_EXIT;
+
+ key = "qcom,freq-mitigation-temp-hysteresis";
+ ret = of_property_read_u32(node, key,
+ &data->freq_mitig_temp_hysteresis_degc);
+ if (ret)
+ goto PROBE_FREQ_EXIT;
+
+ key = "qcom,freq-mitigation-value";
+ ret = of_property_read_u32(node, key, &data->freq_limit);
+ if (ret)
+ goto PROBE_FREQ_EXIT;
+
+ key = "qcom,freq-mitigation-control-mask";
+ ret = of_property_read_u32(node, key, &data->freq_mitig_control_mask);
+ if (ret)
+ goto PROBE_FREQ_EXIT;
+
+ freq_mitigation_enabled = 1;
+ for_each_possible_cpu(cpu) {
+ cpus[cpu].max_freq = false;
+ cpus[cpu].user_max_freq = UINT_MAX;
+ cpus[cpu].user_min_freq = 0;
+ cpus[cpu].limited_max_freq = UINT_MAX;
+ cpus[cpu].limited_min_freq = 0;
+ cpus[cpu].freq_thresh_clear = false;
+ }
+
+PROBE_FREQ_EXIT:
+ if (ret) {
+ dev_info(&pdev->dev,
+ "%s:Failed reading node=%s, key=%s. KTM continues\n",
+ __func__, node->full_name, key);
+ freq_mitigation_enabled = 0;
+ }
+ return ret;
}
static int __devinit msm_thermal_dev_probe(struct platform_device *pdev)
@@ -1851,18 +2543,23 @@
goto fail;
key = "qcom,freq-step";
- ret = of_property_read_u32(node, key, &data.freq_step);
+ ret = of_property_read_u32(node, key, &data.bootup_freq_step);
if (ret)
goto fail;
key = "qcom,freq-control-mask";
- ret = of_property_read_u32(node, key, &data.freq_control_mask);
+ ret = of_property_read_u32(node, key, &data.bootup_freq_control_mask);
ret = probe_cc(node, &data, pdev);
+
+ ret = probe_freq_mitigation(node, &data, pdev);
/*
* Probe optional properties below. Call probe_psm before
* probe_vdd_rstr because rpm_regulator_get has to be called
* before devm_regulator_get
+ * probe_ocr should be called after probe_vdd_rstr to reuse the
+ * regualtor handle. calling devm_regulator_get more than once
+ * will fail.
*/
ret = probe_psm(node, &data, pdev);
if (ret == -EPROBE_DEFER)
@@ -1870,6 +2567,9 @@
ret = probe_vdd_rstr(node, &data, pdev);
if (ret == -EPROBE_DEFER)
goto fail;
+ ret = probe_ocr(node, &data, pdev);
+ if (ret == -EPROBE_DEFER)
+ goto fail;
/*
* In case sysfs add nodes get called before probe function.
@@ -1883,6 +2583,11 @@
msm_thermal_add_vdd_rstr_nodes();
vdd_rstr_nodes_called = false;
}
+ if (ocr_nodes_called) {
+ msm_thermal_add_ocr_nodes();
+ ocr_nodes_called = false;
+ }
+ msm_thermal_ioctl_init();
ret = msm_thermal_init(&data);
return ret;
@@ -1894,6 +2599,11 @@
return ret;
}
+static int msm_thermal_dev_exit(struct platform_device *inp_dev)
+{
+ msm_thermal_ioctl_cleanup();
+ return 0;
+}
static struct of_device_id msm_thermal_match_table[] = {
{.compatible = "qcom,msm-thermal"},
@@ -1907,6 +2617,7 @@
.owner = THIS_MODULE,
.of_match_table = msm_thermal_match_table,
},
+ .remove = msm_thermal_dev_exit,
};
int __init msm_thermal_device_init(void)
@@ -1920,6 +2631,7 @@
msm_thermal_add_cc_nodes();
msm_thermal_add_psm_nodes();
msm_thermal_add_vdd_rstr_nodes();
+ msm_thermal_add_ocr_nodes();
alarm_init(&thermal_rtc, ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
thermal_rtc_callback);
INIT_WORK(&timer_work, timer_work_fn);
diff --git a/drivers/thermal/qpnp-adc-tm.c b/drivers/thermal/qpnp-adc-tm.c
index cf1801b..efb87a9 100644
--- a/drivers/thermal/qpnp-adc-tm.c
+++ b/drivers/thermal/qpnp-adc-tm.c
@@ -1339,7 +1339,7 @@
{
u8 status_low = 0, status_high = 0, qpnp_adc_tm_meas_en = 0;
u8 adc_tm_low_enable = 0, adc_tm_high_enable = 0;
- u8 sensor_mask = 0;
+ u8 sensor_mask = 0, adc_tm_low_thr_set = 0, adc_tm_high_thr_set = 0;
int rc = 0, sensor_notify_num = 0, i = 0, sensor_num = 0;
uint32_t btm_chan_num = 0;
struct qpnp_adc_thr_client_info *client_info = NULL;
@@ -1368,6 +1368,20 @@
goto fail;
}
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_LOW_THR_INT_EN,
+ &adc_tm_low_thr_set);
+ if (rc) {
+ pr_err("adc-tm-tm read low thr failed with %d\n", rc);
+ goto fail;
+ }
+
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_HIGH_THR_INT_EN,
+ &adc_tm_high_thr_set);
+ if (rc) {
+ pr_err("adc-tm-tm read high thr failed with %d\n", rc);
+ goto fail;
+ }
+
/* Check which interrupt threshold is lower and measure against the
* enabled channel */
rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
@@ -1378,7 +1392,9 @@
}
adc_tm_low_enable = qpnp_adc_tm_meas_en & status_low;
+ adc_tm_low_enable &= adc_tm_low_thr_set;
adc_tm_high_enable = qpnp_adc_tm_meas_en & status_high;
+ adc_tm_high_enable &= adc_tm_high_thr_set;
if (adc_tm_high_enable) {
sensor_notify_num = adc_tm_high_enable;
@@ -1886,7 +1902,7 @@
pr_debug("thermal node%x\n", btm_channel_num);
chip->sensor[sen_idx].mode = THERMAL_DEVICE_DISABLED;
chip->sensor[sen_idx].thermal_node = true;
- snprintf(name, sizeof(name),
+ snprintf(name, sizeof(name), "%s",
chip->adc->adc_channels[sen_idx].name);
chip->sensor[sen_idx].meas_interval =
QPNP_ADC_TM_MEAS_INTERVAL;
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index 8d9da6b..739696d 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -89,30 +89,21 @@
}
EXPORT_SYMBOL(sensor_get_id);
-static long get_min(struct sensor_info *sensor, long temp)
+static int __update_sensor_thresholds(struct sensor_info *sensor)
{
- long min = LONG_MIN;
- struct sensor_threshold *pos, *var;
-
- list_for_each_entry_safe(pos, var, &sensor->threshold_list, list) {
- if (pos->trip == THERMAL_TRIP_CONFIGURABLE_LOW)
- if (pos->temp < temp && pos->temp > min)
- min = pos->temp;
- }
-
- return min;
-}
-
-static void __update_sensor_thresholds(struct sensor_info *sensor)
-{
- long min = LONG_MIN;
- long max = LONG_MAX;
- long max_of_min = LONG_MIN;
- long min_of_max = LONG_MAX;
+ long max_of_low_thresh = LONG_MIN;
+ long min_of_high_thresh = LONG_MAX;
struct sensor_threshold *pos, *var;
enum thermal_trip_type type;
- int i;
- long curr_temp;
+ int i, ret = 0;
+
+ if (!sensor->tz->ops->set_trip_temp ||
+ !sensor->tz->ops->activate_trip_type ||
+ !sensor->tz->ops->get_trip_type ||
+ !sensor->tz->ops->get_trip_temp) {
+ ret = -ENODEV;
+ goto update_done;
+ }
for (i = 0; ((sensor->max_idx == -1) || (sensor->min_idx == -1)) &&
(sensor->tz->ops->get_trip_type) && (i < sensor->tz->trips);
@@ -128,60 +119,85 @@
THERMAL_TRIP_CONFIGURABLE_HI, &sensor->threshold_max);
}
- sensor->tz->ops->get_temp(sensor->tz, &curr_temp);
list_for_each_entry_safe(pos, var, &sensor->threshold_list, list) {
+ if (!pos->active)
+ continue;
if (pos->trip == THERMAL_TRIP_CONFIGURABLE_LOW) {
- if (pos->temp > max_of_min)
- max_of_min = pos->temp;
- if (pos->temp < curr_temp && pos->temp > min)
- min = pos->temp;
+ if (pos->temp > max_of_low_thresh)
+ max_of_low_thresh = pos->temp;
}
if (pos->trip == THERMAL_TRIP_CONFIGURABLE_HI) {
- if (pos->temp < min_of_max)
- min_of_max = pos->temp;
- if (pos->temp > curr_temp && pos->temp < max)
- max = pos->temp;
+ if (pos->temp < min_of_high_thresh)
+ min_of_high_thresh = pos->temp;
}
}
- pr_debug("sensor %d: min of max: %ld max of min: %ld\n",
- sensor->sensor_id, max_of_min, min_of_max);
+ pr_debug("sensor %d: Thresholds: max of low: %ld min of high: %ld\n",
+ sensor->sensor_id, max_of_low_thresh,
+ min_of_high_thresh);
- /* If we haven't found a max and min bounding the curr_temp,
- * use the min of max and max of min instead.
- */
- if (max == LONG_MAX)
- max = min_of_max;
- if (min == LONG_MIN) {
- min = get_min(sensor, max);
- if (min == LONG_MIN)
- min = max_of_min;
+ if ((min_of_high_thresh != sensor->threshold_max) &&
+ (min_of_high_thresh != LONG_MAX)) {
+ ret = sensor->tz->ops->set_trip_temp(sensor->tz,
+ sensor->max_idx, min_of_high_thresh);
+ if (ret) {
+ pr_err("sensor %d: Unable to set high threshold %d",
+ sensor->sensor_id, ret);
+ goto update_done;
+ }
+ sensor->threshold_max = min_of_high_thresh;
+ }
+ ret = sensor->tz->ops->activate_trip_type(sensor->tz,
+ sensor->max_idx,
+ (min_of_high_thresh == LONG_MAX) ?
+ THERMAL_TRIP_ACTIVATION_DISABLED :
+ THERMAL_TRIP_ACTIVATION_ENABLED);
+ if (ret) {
+ pr_err("sensor %d: Unable to activate high threshold %d",
+ sensor->sensor_id, ret);
+ goto update_done;
}
- if (sensor->tz->ops->set_trip_temp) {
- if (max != sensor->threshold_max) {
- sensor->tz->ops->set_trip_temp(sensor->tz,
- sensor->max_idx, max);
- sensor->threshold_max = max;
+ if ((max_of_low_thresh != sensor->threshold_min) &&
+ (max_of_low_thresh != LONG_MIN)) {
+ ret = sensor->tz->ops->set_trip_temp(sensor->tz,
+ sensor->min_idx, max_of_low_thresh);
+ if (ret) {
+ pr_err("sensor %d: Unable to set low threshold %d",
+ sensor->sensor_id, ret);
+ goto update_done;
}
- if (min != sensor->threshold_min) {
- sensor->tz->ops->set_trip_temp(sensor->tz,
- sensor->min_idx, min);
- sensor->threshold_min = min;
- }
+ sensor->threshold_min = max_of_low_thresh;
+ }
+ ret = sensor->tz->ops->activate_trip_type(sensor->tz,
+ sensor->min_idx,
+ (max_of_low_thresh == LONG_MIN) ?
+ THERMAL_TRIP_ACTIVATION_DISABLED :
+ THERMAL_TRIP_ACTIVATION_ENABLED);
+ if (ret) {
+ pr_err("sensor %d: Unable to activate low threshold %d",
+ sensor->sensor_id, ret);
+ goto update_done;
}
- pr_debug("sensor %d: curr_temp: %ld min: %ld max: %ld\n",
- sensor->sensor_id, curr_temp,
+ pr_debug("sensor %d: low: %ld high: %ld\n",
+ sensor->sensor_id,
sensor->threshold_min, sensor->threshold_max);
+
+update_done:
+ return ret;
}
static void sensor_update_work(struct work_struct *work)
{
struct sensor_info *sensor = container_of(work, struct sensor_info,
work);
+ int ret = 0;
mutex_lock(&sensor->lock);
- __update_sensor_thresholds(sensor);
+ ret = __update_sensor_thresholds(sensor);
+ if (ret)
+ pr_err("sensor %d: Error %d setting threshold\n",
+ sensor->sensor_id, ret);
mutex_unlock(&sensor->lock);
}
@@ -202,7 +218,7 @@
return 0;
list_for_each_entry_safe(pos, var, &tz->sensor.threshold_list, list) {
- if (pos->trip != trip)
+ if ((pos->trip != trip) || (!pos->active))
continue;
if (((trip == THERMAL_TRIP_CONFIGURABLE_LOW) &&
(pos->temp <= tz->sensor.threshold_min) &&
@@ -210,6 +226,7 @@
((trip == THERMAL_TRIP_CONFIGURABLE_HI) &&
(pos->temp >= tz->sensor.threshold_max) &&
(pos->temp <= temp))) {
+ pos->active = 0;
pos->notify(trip, temp, pos->data);
}
}
@@ -220,6 +237,29 @@
}
EXPORT_SYMBOL(thermal_sensor_trip);
+int sensor_activate_trip(uint32_t sensor_id,
+ struct sensor_threshold *threshold, bool enable)
+{
+ struct sensor_info *sensor = get_sensor(sensor_id);
+ int ret = 0;
+
+ if (!sensor || !threshold) {
+ pr_err("Sensor %d: uninitialized data\n",
+ sensor_id);
+ ret = -ENODEV;
+ goto activate_trip_exit;
+ }
+
+ mutex_lock(&sensor->lock);
+ threshold->active = (enable) ? 1 : 0;
+ ret = __update_sensor_thresholds(sensor);
+ mutex_unlock(&sensor->lock);
+
+activate_trip_exit:
+ return ret;
+}
+EXPORT_SYMBOL(sensor_activate_trip);
+
int sensor_set_trip(uint32_t sensor_id, struct sensor_threshold *threshold)
{
struct sensor_threshold *pos, *var;
@@ -241,8 +281,7 @@
INIT_LIST_HEAD(&threshold->list);
list_add(&threshold->list, &sensor->threshold_list);
}
-
- __update_sensor_thresholds(sensor);
+ threshold->active = 0; /* Do not allow active threshold right away */
mutex_unlock(&sensor->lock);
return 0;
@@ -254,6 +293,7 @@
{
struct sensor_threshold *pos, *var;
struct sensor_info *sensor = get_sensor(sensor_id);
+ int ret = 0;
if (!sensor)
return -ENODEV;
@@ -261,15 +301,16 @@
mutex_lock(&sensor->lock);
list_for_each_entry_safe(pos, var, &sensor->threshold_list, list) {
if (pos == threshold) {
+ pos->active = 0;
list_del(&pos->list);
break;
}
}
- __update_sensor_thresholds(sensor);
+ ret = __update_sensor_thresholds(sensor);
mutex_unlock(&sensor->lock);
- return 0;
+ return ret;
}
EXPORT_SYMBOL(sensor_cancel_trip);
@@ -283,36 +324,36 @@
return 0;
}
+static void get_trip_threshold(struct thermal_zone_device *tz, int trip,
+ struct sensor_threshold **threshold)
+{
+ enum thermal_trip_type type;
+
+ tz->ops->get_trip_type(tz, trip, &type);
+
+ if (type == THERMAL_TRIP_CONFIGURABLE_HI)
+ *threshold = &tz->tz_threshold[0];
+ else if (type == THERMAL_TRIP_CONFIGURABLE_LOW)
+ *threshold = &tz->tz_threshold[1];
+ else
+ *threshold = NULL;
+}
+
int sensor_set_trip_temp(struct thermal_zone_device *tz,
int trip, long temp)
{
int ret = 0;
- enum thermal_trip_type type;
+ struct sensor_threshold *threshold = NULL;
if (!tz->ops->get_trip_type)
return -EPERM;
- tz->ops->get_trip_type(tz, trip, &type);
- switch (type) {
- case THERMAL_TRIP_CONFIGURABLE_HI:
- tz->tz_threshold[0].temp = temp;
- tz->tz_threshold[0].trip = THERMAL_TRIP_CONFIGURABLE_HI;
- tz->tz_threshold[0].notify = tz_notify_trip;
- tz->tz_threshold[0].data = tz;
- ret = sensor_set_trip(tz->sensor.sensor_id,
- &tz->tz_threshold[0]);
- break;
- case THERMAL_TRIP_CONFIGURABLE_LOW:
- tz->tz_threshold[1].temp = temp;
- tz->tz_threshold[1].trip = THERMAL_TRIP_CONFIGURABLE_LOW;
- tz->tz_threshold[1].notify = tz_notify_trip;
- tz->tz_threshold[1].data = tz;
- ret = sensor_set_trip(tz->sensor.sensor_id,
- &tz->tz_threshold[1]);
- break;
- default:
+ get_trip_threshold(tz, trip, &threshold);
+ if (threshold) {
+ threshold->temp = temp;
+ ret = sensor_set_trip(tz->sensor.sensor_id, threshold);
+ } else {
ret = tz->ops->set_trip_temp(tz, trip, temp);
- break;
}
return ret;
@@ -333,10 +374,12 @@
INIT_LIST_HEAD(&sensor->threshold_list);
INIT_LIST_HEAD(&tz->tz_threshold[0].list);
INIT_LIST_HEAD(&tz->tz_threshold[1].list);
- tz->tz_threshold[0].notify = NULL;
- tz->tz_threshold[0].data = NULL;
- tz->tz_threshold[1].notify = NULL;
- tz->tz_threshold[1].data = NULL;
+ tz->tz_threshold[0].notify = tz_notify_trip;
+ tz->tz_threshold[0].data = tz;
+ tz->tz_threshold[0].trip = THERMAL_TRIP_CONFIGURABLE_HI;
+ tz->tz_threshold[1].notify = tz_notify_trip;
+ tz->tz_threshold[1].data = tz;
+ tz->tz_threshold[1].trip = THERMAL_TRIP_CONFIGURABLE_LOW;
list_add(&sensor->sensor_list, &sensor_info_list);
INIT_WORK(&sensor->work, sensor_update_work);
@@ -489,23 +532,40 @@
const char *buf, size_t count)
{
struct thermal_zone_device *tz = to_thermal_zone(dev);
- int trip, result;
+ int trip, result = 0;
+ bool activate;
+ struct sensor_threshold *threshold = NULL;
- if (!tz->ops->activate_trip_type)
- return -EPERM;
+ if (!tz->ops->get_trip_type ||
+ !tz->ops->activate_trip_type) {
+ result = -EPERM;
+ goto trip_activate_exit;
+ }
- if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
- return -EINVAL;
-
- if (!strncmp(buf, "enabled", sizeof("enabled")))
- result = tz->ops->activate_trip_type(tz, trip,
- THERMAL_TRIP_ACTIVATION_ENABLED);
- else if (!strncmp(buf, "disabled", sizeof("disabled")))
- result = tz->ops->activate_trip_type(tz, trip,
- THERMAL_TRIP_ACTIVATION_DISABLED);
- else
+ if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip)) {
result = -EINVAL;
+ goto trip_activate_exit;
+ }
+ if (!strcmp(buf, "enabled")) {
+ activate = true;
+ } else if (!strcmp(buf, "disabled")) {
+ activate = false;
+ } else {
+ result = -EINVAL;
+ goto trip_activate_exit;
+ }
+
+ get_trip_threshold(tz, trip, &threshold);
+ if (threshold)
+ result = sensor_activate_trip(tz->sensor.sensor_id,
+ threshold, activate);
+ else
+ result = tz->ops->activate_trip_type(tz, trip,
+ activate ? THERMAL_TRIP_ACTIVATION_ENABLED :
+ THERMAL_TRIP_ACTIVATION_DISABLED);
+
+trip_activate_exit:
if (result)
return result;
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index a243a05..ecfacc0 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -67,14 +67,65 @@
#include <mach/sps.h>
#include <mach/msm_serial_hs.h>
#include <mach/msm_bus.h>
-
+#include <mach/msm_ipc_logging.h>
#include "msm_serial_hs_hwreg.h"
#define UART_SPS_CONS_PERIPHERAL 0
#define UART_SPS_PROD_PERIPHERAL 1
-static int hs_serial_debug_mask = 1;
+static void *ipc_msm_hs_log_ctxt;
+#define IPC_MSM_HS_LOG_PAGES 5
+
+/* If the debug_mask gets set to FATAL_LEV,
+ * a fatal error has happened and further IPC logging
+ * is disabled so that this problem can be detected
+ */
+enum {
+ FATAL_LEV = 0U,
+ ERR_LEV = 1U,
+ WARN_LEV = 2U,
+ INFO_LEV = 3U,
+ DBG_LEV = 4U,
+};
+
+/* Default IPC log level INFO */
+static int hs_serial_debug_mask = INFO_LEV;
module_param_named(debug_mask, hs_serial_debug_mask,
int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+#define MSM_HS_DBG(x...) do { \
+ if (hs_serial_debug_mask >= DBG_LEV) { \
+ pr_debug(x); \
+ if (ipc_msm_hs_log_ctxt) \
+ ipc_log_string(ipc_msm_hs_log_ctxt, x); \
+ } \
+} while (0)
+
+#define MSM_HS_INFO(x...) do { \
+ if (hs_serial_debug_mask >= INFO_LEV) {\
+ pr_info(x); \
+ if (ipc_msm_hs_log_ctxt) \
+ ipc_log_string(ipc_msm_hs_log_ctxt, x); \
+ } \
+} while (0)
+
+/* warnings and errors show up on console always */
+#define MSM_HS_WARN(x...) do { \
+ pr_warn(x); \
+ if (ipc_msm_hs_log_ctxt && hs_serial_debug_mask >= WARN_LEV) \
+ ipc_log_string(ipc_msm_hs_log_ctxt, x); \
+} while (0)
+
+/* ERROR condition in the driver sets the hs_serial_debug_mask
+ * to ERR_FATAL level, so that this message can be seen
+ * in IPC logging. Further errors continue to log on the console
+ */
+#define MSM_HS_ERR(x...) do { \
+ pr_err(x); \
+ if (ipc_msm_hs_log_ctxt && hs_serial_debug_mask >= ERR_LEV) { \
+ ipc_log_string(ipc_msm_hs_log_ctxt, x); \
+ hs_serial_debug_mask = FATAL_LEV; \
+ } \
+} while (0)
/*
* There are 3 different kind of UART Core available on MSM.
* High Speed UART (i.e. Legacy HSUART), GSBI based HSUART
@@ -155,7 +206,6 @@
struct tasklet_struct tlet;
struct msm_hs_sps_ep_conn_data prod;
};
-
enum buffer_states {
NONE_PENDING = 0x0,
FIFO_OVERRUN = 0x1,
@@ -219,6 +269,7 @@
struct msm_bus_scale_pdata *bus_scale_table;
bool rx_discard_flush_issued;
int rx_count_callback;
+ bool rx_bam_inprogress;
unsigned int *reg_ptr;
};
@@ -316,19 +367,19 @@
switch (cmd) {
case MSM_ENABLE_UART_CLOCK: {
- pr_debug("%s():ENABLE UART CLOCK: cmd=%d\n", __func__, cmd);
+ MSM_HS_DBG("%s():ENABLE UART CLOCK: cmd=%d\n", __func__, cmd);
msm_hs_request_clock_on(&msm_uport->uport);
break;
}
case MSM_DISABLE_UART_CLOCK: {
- pr_debug("%s():DISABLE UART CLOCK: cmd=%d\n", __func__, cmd);
+ MSM_HS_DBG("%s():DISABLE UART CLOCK: cmd=%d\n", __func__, cmd);
msm_hs_request_clock_off(&msm_uport->uport);
break;
}
case MSM_GET_UART_CLOCK_STATUS: {
/* Return value 0 - UART CLOCK is OFF
* Return value 1 - UART CLOCK is ON */
- pr_debug("%s():GET UART CLOCK STATUS: cmd=%d\n", __func__, cmd);
+ MSM_HS_DBG("%s():GET UART CLOCK STATUS: cmd=%d\n", __func__, cmd);
spin_lock_irqsave(&msm_uport->uport.lock, flags);
clk_state = msm_uport->clk_state;
spin_unlock_irqrestore(&msm_uport->uport.lock, flags);
@@ -338,7 +389,7 @@
break;
}
default: {
- pr_debug("%s():Unknown cmd specified: cmd=%d\n", __func__, cmd);
+ MSM_HS_DBG("%s():Unknown cmd specified: cmd=%d\n", __func__, cmd);
ret = -ENOIOCTLCMD;
break;
}
@@ -470,11 +521,11 @@
int ret;
if (is_blsp_uart(msm_uport) && msm_uport->bus_perf_client) {
- pr_debug("Bus voting:%d\n", vote);
+ MSM_HS_DBG("Bus voting:%d\n", vote);
ret = msm_bus_scale_client_update_request(
msm_uport->bus_perf_client, vote);
if (ret)
- pr_err("%s(): Failed for Bus voting: %d\n",
+ MSM_HS_ERR("%s(): Failed for Bus voting: %d\n",
__func__, vote);
}
}
@@ -500,6 +551,37 @@
writel_relaxed(value, uport->membase + offset);
}
+static void hex_dump_ipc(char *prefix, char *string, int size)
+{
+ char linebuf[512];
+
+ hex_dump_to_buffer(string, size, 16, 1, linebuf, sizeof(linebuf), 1);
+ MSM_HS_DBG("%s : %s", prefix, linebuf);
+}
+
+/*
+ * This API read and provides UART Core registers information.
+*/
+static void dump_uart_hs_registers(struct msm_hs_port *msm_uport)
+{
+ msm_hs_clock_vote(msm_uport);
+ MSM_HS_DBG("============= UART Registers ================\n");
+ MSM_HS_DBG("UART_DM_MR1:%x\n", msm_hs_read(&(msm_uport->uport),
+ UART_DM_MR1));
+ MSM_HS_DBG("UART_DM_MR2:%x\n", msm_hs_read(&(msm_uport->uport),
+ UART_DM_MR2));
+ MSM_HS_DBG("UART_DM_IPR:%x\n", msm_hs_read(&(msm_uport->uport),
+ UART_DM_IPR));
+ MSM_HS_DBG("UART_DM_RFWR:%x\n", msm_hs_read(&(msm_uport->uport),
+ UART_DM_RFWR));
+ MSM_HS_DBG("UART_DM_SR:%x\n", msm_hs_read(&(msm_uport->uport),
+ UART_DM_SR));
+ MSM_HS_DBG("UART_DM_IMR: %x\n", msm_hs_read(&(msm_uport->uport),
+ UART_DM_IMR));
+ MSM_HS_DBG("=============================================\n");
+ msm_hs_clock_unvote(msm_uport);
+}
+
static void msm_hs_release_port(struct uart_port *port)
{
struct msm_hs_port *msm_uport = UARTDM_TO_MSM(port);
@@ -626,7 +708,7 @@
&loopback_enable_fops);
if (IS_ERR_OR_NULL(msm_uport->loopback_dir))
- pr_err("%s(): Cannot create loopback.%d debug entry",
+ MSM_HS_ERR("%s(): Cannot create loopback.%d debug entry",
__func__, id);
}
@@ -637,7 +719,7 @@
struct device *dev;
if (pdev->id < 0 || pdev->id >= UARTDM_NR) {
- printk(KERN_ERR "Invalid plaform device ID = %d\n", pdev->id);
+ MSM_HS_ERR(KERN_ERR "Invalid plaform device ID = %d\n", pdev->id);
return -EINVAL;
}
@@ -691,13 +773,13 @@
/* Set up the MREG/NREG/DREG/MNDREG */
ret = clk_set_rate(msm_uport->clk, uport->uartclk);
if (ret) {
- printk(KERN_WARNING "Error setting clock rate on UART\n");
+ MSM_HS_WARN("Error setting clock rate on UART\n");
return ret;
}
ret = msm_hs_clock_vote(msm_uport);
if (ret) {
- printk(KERN_ERR "Error could not turn on UART clk\n");
+ MSM_HS_ERR("Error could not turn on UART clk\n");
return ret;
}
@@ -728,14 +810,14 @@
/* Establish connection between peripheral and memory endpoint */
ret = sps_connect(sps_pipe_handle, sps_config);
if (ret) {
- pr_err("msm_serial_hs: sps_connect() failed for tx!!\n"
+ MSM_HS_ERR("msm_serial_hs: sps_connect() failed for tx!!\n"
"pipe_handle=0x%x ret=%d", (u32)sps_pipe_handle, ret);
return ret;
}
/* Register callback event for EOT (End of transfer) event. */
ret = sps_register_event(sps_pipe_handle, sps_event);
if (ret) {
- pr_err("msm_serial_hs: sps_connect() failed for tx!!\n"
+ MSM_HS_ERR("msm_serial_hs: sps_connect() failed for tx!!\n"
"pipe_handle=0x%x ret=%d", (u32)sps_pipe_handle, ret);
goto reg_event_err;
}
@@ -769,14 +851,14 @@
/* Establish connection between peripheral and memory endpoint */
ret = sps_connect(sps_pipe_handle, sps_config);
if (ret) {
- pr_err("msm_serial_hs: sps_connect() failed for rx!!\n"
+ MSM_HS_ERR("msm_serial_hs: sps_connect() failed for rx!!\n"
"pipe_handle=0x%x ret=%d", (u32)sps_pipe_handle, ret);
return ret;
}
/* Register callback event for DESC_DONE event. */
ret = sps_register_event(sps_pipe_handle, sps_event);
if (ret) {
- pr_err("msm_serial_hs: sps_connect() failed for rx!!\n"
+ MSM_HS_ERR("msm_serial_hs: sps_connect() failed for rx!!\n"
"pipe_handle=0x%x ret=%d", (u32)sps_pipe_handle, ret);
goto reg_event_err;
}
@@ -909,7 +991,7 @@
}
if (clk_set_rate(msm_uport->clk, uport->uartclk)) {
- printk(KERN_WARNING "Error setting clock rate on UART\n");
+ MSM_HS_WARN("Error setting clock rate on UART\n");
WARN_ON(1);
}
@@ -998,6 +1080,17 @@
mutex_lock(&msm_uport->clk_mutex);
msm_hs_write(uport, UART_DM_IMR, 0);
+ MSM_HS_DBG("Entering %s\n", __func__);
+ dump_uart_hs_registers(msm_uport);
+
+ /* Clear the Rx Ready Ctl bit - This ensures that
+ * flow control lines stop the other side from sending
+ * data while we change the parameters
+ */
+ data = msm_hs_read(uport, UART_DM_MR1);
+ data &= ~UARTDM_MR1_RX_RDY_CTL_BMSK;
+ msm_hs_write(uport, UART_DM_MR1, data);
+
/*
* Disable Rx channel of UARTDM
* DMA Rx Stall happens if enqueue and flush of Rx command happens
@@ -1071,18 +1164,6 @@
/* write parity/bits per char/stop bit configuration */
msm_hs_write(uport, UART_DM_MR2, data);
- /* Configure HW flow control */
- data = msm_hs_read(uport, UART_DM_MR1);
-
- data &= ~(UARTDM_MR1_CTS_CTL_BMSK | UARTDM_MR1_RX_RDY_CTL_BMSK);
-
- if (c_cflag & CRTSCTS) {
- data |= UARTDM_MR1_CTS_CTL_BMSK;
- data |= UARTDM_MR1_RX_RDY_CTL_BMSK;
- }
-
- msm_hs_write(uport, UART_DM_MR1, data);
-
uport->ignore_status_mask = termios->c_iflag & INPCK;
uport->ignore_status_mask |= termios->c_iflag & IGNPAR;
uport->ignore_status_mask |= termios->c_iflag & IGNBRK;
@@ -1106,9 +1187,13 @@
*/
mb();
if (is_blsp_uart(msm_uport)) {
+ if (msm_uport->rx_bam_inprogress)
+ ret = wait_event_timeout(msm_uport->rx.wait,
+ msm_uport->rx_bam_inprogress == false,
+ RX_FLUSH_COMPLETE_TIMEOUT);
ret = sps_disconnect(sps_pipe_handle);
if (ret)
- pr_err("%s(): sps_disconnect failed\n",
+ MSM_HS_ERR("%s(): sps_disconnect failed\n",
__func__);
msm_hs_spsconnect_rx(uport);
msm_serial_hs_rx_tlet((unsigned long) &rx->tlet);
@@ -1116,20 +1201,36 @@
msm_uport->rx_discard_flush_issued = true;
/* do discard flush */
msm_dmov_flush(msm_uport->dma_rx_channel, 0);
- pr_debug("%s(): wainting for flush completion.\n",
+ MSM_HS_DBG("%s(): wainting for flush completion.\n",
__func__);
ret = wait_event_timeout(msm_uport->rx.wait,
msm_uport->rx_discard_flush_issued == false,
RX_FLUSH_COMPLETE_TIMEOUT);
if (!ret)
- pr_err("%s(): Discard flush pending.\n",
+ MSM_HS_ERR("%s(): Discard flush pending.\n",
__func__);
}
}
+ /* Configure HW flow control
+ * UART Core would see status of CTS line when it is sending data
+ * to remote uart to confirm that it can receive or not.
+ * UART Core would trigger RFR if it is not having any space with
+ * RX FIFO.
+ */
+ data = msm_hs_read(uport, UART_DM_MR1);
+ data &= ~(UARTDM_MR1_CTS_CTL_BMSK | UARTDM_MR1_RX_RDY_CTL_BMSK);
+ if (c_cflag & CRTSCTS) {
+ data |= UARTDM_MR1_CTS_CTL_BMSK;
+ data |= UARTDM_MR1_RX_RDY_CTL_BMSK;
+ }
+ msm_hs_write(uport, UART_DM_MR1, data);
+
msm_hs_write(uport, UART_DM_IMR, msm_uport->imr_reg);
mb();
mutex_unlock(&msm_uport->clk_mutex);
+ MSM_HS_DBG("Exit %s\n", __func__);
+ dump_uart_hs_registers(msm_uport);
}
/*
@@ -1143,7 +1244,7 @@
struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
msm_hs_clock_vote(msm_uport);
- data = msm_hs_read(uport, UARTDM_SR_ADDR);
+ data = msm_hs_read(uport, UART_DM_SR);
msm_hs_clock_unvote(msm_uport);
if (data & UARTDM_SR_TXEMT_BMSK)
@@ -1176,7 +1277,7 @@
ret = sps_disconnect(sps_pipe_handle);
if (ret)
- pr_err("%s(): sps_disconnect failed\n", __func__);
+ MSM_HS_ERR("%s(): sps_disconnect failed\n", __func__);
wake_lock_timeout(&msm_uport->rx.wake_lock, HZ / 2);
msm_uport->rx.flush = FLUSH_SHUTDOWN;
@@ -1254,7 +1355,8 @@
if (tx_count > left)
tx_count = left;
-
+ MSM_HS_DBG("%s(): [UART_TX]<%d>\n", __func__, tx_count);
+ hex_dump_ipc("HSUART write: ", &tx_buf->buf[tx_buf->tail], tx_count);
src_addr = tx->dma_base + tx_buf->tail;
/* Mask the src_addr to align on a cache
* and add those bytes to tx_count */
@@ -1302,7 +1404,10 @@
sizeof(u32), DMA_TO_DEVICE);
msm_dmov_enqueue_cmd(msm_uport->dma_tx_channel, &tx->xfer);
+
}
+ MSM_HS_DBG("%s:Enqueue Tx Cmd\n", __func__);
+ dump_uart_hs_registers(msm_uport);
}
/* Start to receive the next chunk of data */
@@ -1317,7 +1422,7 @@
msm_uport->rx.buffer_pending = 0;
if (buffer_pending && hs_serial_debug_mask)
- printk(KERN_ERR "Error: rx started in buffer state = %x",
+ MSM_HS_ERR("Error: rx started in buffer state = %x",
buffer_pending);
msm_hs_write(uport, UART_DM_CR, RESET_STALE_INT);
@@ -1358,14 +1463,19 @@
msm_uport->rx.flush = FLUSH_NONE;
if (is_blsp_uart(msm_uport)) {
+ msm_uport->rx_bam_inprogress = true;
sps_pipe_handle = rx->prod.pipe_handle;
/* Queue transfer request to SPS */
sps_transfer_one(sps_pipe_handle, rx->rbuffer,
UARTDM_RX_BUF_SIZE, msm_uport, flags);
+ msm_uport->rx_bam_inprogress = false;
+ wake_up(&msm_uport->rx.wait);
} else {
msm_dmov_enqueue_cmd(msm_uport->dma_rx_channel,
&msm_uport->rx.xfer);
}
+ MSM_HS_DBG("%s:Enqueue Rx Cmd\n", __func__);
+ dump_uart_hs_registers(msm_uport);
}
static void flip_insert_work(struct work_struct *work)
@@ -1380,7 +1490,7 @@
spin_lock_irqsave(&msm_uport->uport.lock, flags);
if (msm_uport->rx.buffer_pending == NONE_PENDING) {
if (hs_serial_debug_mask)
- printk(KERN_ERR "Error: No buffer pending in %s",
+ MSM_HS_ERR("Error: No buffer pending in %s",
__func__);
return;
}
@@ -1412,11 +1522,7 @@
else
if ((msm_uport->clk_state == MSM_HS_CLK_ON) &&
(msm_uport->rx.flush <= FLUSH_IGNORE)) {
- if (hs_serial_debug_mask)
- printk(KERN_WARNING
- "msm_serial_hs: "
- "Pending buffers cleared. "
- "Restarting\n");
+ MSM_HS_WARN("Pending buffers cleared,restarting\n");
msm_hs_start_rx_locked(&msm_uport->uport);
}
spin_unlock_irqrestore(&msm_uport->uport.lock, flags);
@@ -1453,6 +1559,9 @@
if (!is_blsp_uart(msm_uport))
msm_hs_write(uport, UART_DM_CR, STALE_EVENT_DISABLE);
+ MSM_HS_DBG("In %s\n", __func__);
+ dump_uart_hs_registers(msm_uport);
+
/* overflow is not connect to data in a FIFO */
if (unlikely((status & UARTDM_SR_OVERRUN_BMSK) &&
(uport->read_status_mask & CREAD))) {
@@ -1469,7 +1578,7 @@
if (unlikely(status & UARTDM_SR_PAR_FRAME_BMSK)) {
/* Can not tell difference between parity & frame error */
if (hs_serial_debug_mask)
- printk(KERN_WARNING "msm_serial_hs: parity error\n");
+ MSM_HS_WARN("msm_serial_hs: parity error\n");
uport->icount.parity++;
error_f = 1;
if (!(uport->ignore_status_mask & IGNPAR)) {
@@ -1481,7 +1590,7 @@
if (unlikely(status & UARTDM_SR_RX_BREAK_BMSK)) {
if (hs_serial_debug_mask)
- printk(KERN_WARNING "msm_serial_hs: Rx break\n");
+ MSM_HS_WARN("msm_serial_hs: Rx break\n");
uport->icount.brk++;
error_f = 1;
if (!(uport->ignore_status_mask & IGNBRK)) {
@@ -1516,36 +1625,40 @@
rmb();
}
+ MSM_HS_DBG("%s():[UART_RX]<%d>\n", __func__, rx_count);
+ hex_dump_ipc("HSUART Read: ", msm_uport->rx.buffer, rx_count);
if (0 != (uport->read_status_mask & CREAD)) {
retval = tty_insert_flip_string(tty, msm_uport->rx.buffer,
rx_count);
if (retval != rx_count) {
+ MSM_HS_DBG("%s(): retval %d rx_count %d", __func__,
+ retval, rx_count);
msm_uport->rx.buffer_pending |= CHARS_NORMAL |
retval << 5 | (rx_count - retval) << 16;
}
}
+ MSM_HS_DBG("%s() read rx buffer complete", __func__);
/* order the read of rx.buffer and the start of next rx xfer */
wmb();
if (!msm_uport->rx.buffer_pending) {
if (is_blsp_uart(msm_uport)) {
msm_uport->rx.flush = FLUSH_NONE;
+ msm_uport->rx_bam_inprogress = true;
sps_pipe_handle = rx->prod.pipe_handle;
/* Queue transfer request to SPS */
sps_transfer_one(sps_pipe_handle, rx->rbuffer,
UARTDM_RX_BUF_SIZE, msm_uport, sps_flags);
+ msm_uport->rx_bam_inprogress = false;
+ wake_up(&msm_uport->rx.wait);
} else {
msm_hs_start_rx_locked(uport);
}
}
out:
if (msm_uport->rx.buffer_pending) {
- if (hs_serial_debug_mask)
- printk(KERN_WARNING
- "msm_serial_hs: "
- "tty buffer exhausted. "
- "Stalling\n");
+ MSM_HS_WARN("tty buffer exhausted.Stalling\n");
schedule_delayed_work(&msm_uport->rx.flip_insert_work
, msecs_to_jiffies(RETRY_TIMEOUT));
}
@@ -1586,7 +1699,7 @@
((struct sps_event_notify *)notify)->user;
msm_uport->notify = *notify;
- pr_debug("%s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
+ MSM_HS_DBG("%s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
__func__, notify->event_id,
notify->data.transfer.iovec.addr,
notify->data.transfer.iovec.size,
@@ -1639,6 +1752,8 @@
mb();
spin_unlock_irqrestore(&(msm_uport->uport.lock), flags);
+ MSM_HS_DBG("In %s()\n", __func__);
+ dump_uart_hs_registers(msm_uport);
}
/**
@@ -1661,7 +1776,7 @@
uport = &(msm_uport->uport);
msm_uport->notify = *notify;
- pr_debug("%s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
+ MSM_HS_DBG("%s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
__func__, notify->event_id,
notify->data.transfer.iovec.addr,
notify->data.transfer.iovec.size,
@@ -1693,7 +1808,7 @@
msm_uport = container_of(cmd_ptr, struct msm_hs_port, rx.xfer);
uport = &(msm_uport->uport);
- pr_debug("%s(): called result:%x\n", __func__, result);
+ MSM_HS_DBG("%s(): called result:%x\n", __func__, result);
if (!(result & DMOV_RSLT_ERROR)) {
if (result & DMOV_RSLT_FLUSH) {
if (msm_uport->rx_discard_flush_issued) {
@@ -1915,13 +2030,13 @@
spin_unlock_irqrestore(&uport->lock, flags);
if (msm_uport->rx_discard_flush_issued) {
- pr_debug("%s(): wainting for flush completion.\n",
+ MSM_HS_DBG("%s(): wainting for flush completion.\n",
__func__);
ret = wait_event_timeout(msm_uport->rx.wait,
msm_uport->rx_discard_flush_issued == false,
RX_FLUSH_COMPLETE_TIMEOUT);
if (!ret)
- pr_err("%s(): Flush complete pending.\n",
+ MSM_HS_ERR("%s(): Flush complete pending.\n",
__func__);
}
@@ -1985,10 +2100,13 @@
spin_lock_irqsave(&uport->lock, flags);
isr_status = msm_hs_read(uport, UART_DM_MISR);
+ MSM_HS_DBG("%s:UART_DM_MISR %lx", __func__, isr_status);
+ dump_uart_hs_registers(msm_uport);
/* Uart RX starting */
if (isr_status & UARTDM_ISR_RXLEV_BMSK) {
wake_lock(&rx->wake_lock); /* hold wakelock while rx dma */
+ MSM_HS_DBG("%s:UARTDM_ISR_RXLEV_BMSK\n", __func__);
msm_uport->imr_reg &= ~UARTDM_ISR_RXLEV_BMSK;
msm_hs_write(uport, UART_DM_IMR, msm_uport->imr_reg);
/* Complete device write for IMR. Hence mb() requires. */
@@ -2003,6 +2121,7 @@
* mb() requires here.
*/
mb();
+ MSM_HS_DBG("%s:Stal Interrupt\n", __func__);
if (msm_uport->clk_req_off_state ==
CLK_REQ_OFF_RXSTALE_ISSUED)
@@ -2016,6 +2135,7 @@
}
/* tx ready interrupt */
if (isr_status & UARTDM_ISR_TX_READY_BMSK) {
+ MSM_HS_DBG("%s: ISR_TX_READY Interrupt\n", __func__);
/* Clear TX Ready */
msm_hs_write(uport, UART_DM_CR, CLEAR_TX_READY);
@@ -2094,7 +2214,7 @@
msm_uport->clk_state = MSM_HS_CLK_REQUEST_OFF;
msm_uport->clk_req_off_state = CLK_REQ_OFF_START;
msm_uport->imr_reg |= UARTDM_ISR_TXLEV_BMSK;
- msm_hs_write(uport, UARTDM_IMR, msm_uport->imr_reg);
+ msm_hs_write(uport, UART_DM_IMR, msm_uport->imr_reg);
/*
* Complete device write before retuning back.
* Hence mb() requires here.
@@ -2232,7 +2352,7 @@
if (gpio_is_valid(pdata->uart_rfr_gpio))
gpio_free(pdata->uart_rfr_gpio);
} else {
- pr_err("Error:Pdata is NULL.\n");
+ MSM_HS_ERR("Error:Pdata is NULL.\n");
}
}
@@ -2252,7 +2372,7 @@
ret = gpio_request(pdata->uart_tx_gpio,
"UART_TX_GPIO");
if (unlikely(ret)) {
- pr_err("gpio request failed for:%d\n",
+ MSM_HS_ERR("gpio request failed for:%d\n",
pdata->uart_tx_gpio);
goto exit_uart_config;
}
@@ -2262,7 +2382,7 @@
ret = gpio_request(pdata->uart_rx_gpio,
"UART_RX_GPIO");
if (unlikely(ret)) {
- pr_err("gpio request failed for:%d\n",
+ MSM_HS_ERR("gpio request failed for:%d\n",
pdata->uart_rx_gpio);
goto uart_tx_unconfig;
}
@@ -2272,7 +2392,7 @@
ret = gpio_request(pdata->uart_cts_gpio,
"UART_CTS_GPIO");
if (unlikely(ret)) {
- pr_err("gpio request failed for:%d\n",
+ MSM_HS_ERR("gpio request failed for:%d\n",
pdata->uart_cts_gpio);
goto uart_rx_unconfig;
}
@@ -2282,13 +2402,13 @@
ret = gpio_request(pdata->uart_rfr_gpio,
"UART_RFR_GPIO");
if (unlikely(ret)) {
- pr_err("gpio request failed for:%d\n",
+ MSM_HS_ERR("gpio request failed for:%d\n",
pdata->uart_rfr_gpio);
goto uart_cts_unconfig;
}
}
} else {
- pr_err("Pdata is NULL.\n");
+ MSM_HS_ERR("Pdata is NULL.\n");
ret = -EINVAL;
}
return ret;
@@ -2334,7 +2454,7 @@
/* turn on uart clk */
ret = msm_hs_init_clk(uport);
if (unlikely(ret)) {
- pr_err("Turning ON uartclk error\n");
+ MSM_HS_ERR("Turning ON uartclk error\n");
wake_unlock(&msm_uport->dma_wake_lock);
return ret;
}
@@ -2342,7 +2462,7 @@
if (is_blsp_uart(msm_uport)) {
ret = msm_hs_config_uart_gpios(uport);
if (ret) {
- pr_err("Uart GPIO request failed\n");
+ MSM_HS_ERR("Uart GPIO request failed\n");
goto deinit_uart_clk;
}
} else {
@@ -2356,14 +2476,14 @@
/* SPS connect for TX */
ret = msm_hs_spsconnect_tx(uport);
if (ret) {
- pr_err("msm_serial_hs: SPS connect failed for TX");
+ MSM_HS_ERR("msm_serial_hs: SPS connect failed for TX");
goto unconfig_uart_gpios;
}
/* SPS connect for RX */
ret = msm_hs_spsconnect_rx(uport);
if (ret) {
- pr_err("msm_serial_hs: SPS connect failed for RX");
+ MSM_HS_ERR("msm_serial_hs: SPS connect failed for RX");
goto sps_disconnect_tx;
}
}
@@ -2441,7 +2561,7 @@
if (use_low_power_wakeup(msm_uport)) {
ret = irq_set_irq_wake(msm_uport->wakeup.irq, 1);
if (unlikely(ret)) {
- pr_err("%s():Err setting wakeup irq\n", __func__);
+ MSM_HS_ERR("%s():Err setting wakeup irq\n", __func__);
goto sps_disconnect_rx;
}
}
@@ -2449,7 +2569,7 @@
ret = request_irq(uport->irq, msm_hs_isr, IRQF_TRIGGER_HIGH,
"msm_hs_uart", msm_uport);
if (unlikely(ret)) {
- pr_err("%s():Error getting uart irq\n", __func__);
+ MSM_HS_ERR("%s():Error getting uart irq\n", __func__);
goto free_wake_irq;
}
if (use_low_power_wakeup(msm_uport)) {
@@ -2460,7 +2580,7 @@
"msm_hs_wakeup", msm_uport);
if (unlikely(ret)) {
- pr_err("%s():Err getting uart wakeup_irq\n", __func__);
+ MSM_HS_ERR("%s():Err getting uart wakeup_irq\n", __func__);
goto free_uart_irq;
}
disable_irq(msm_uport->wakeup.irq);
@@ -2523,14 +2643,14 @@
rx->pool = dma_pool_create("rx_buffer_pool", uport->dev,
UARTDM_RX_BUF_SIZE, 16, 0);
if (!rx->pool) {
- pr_err("%s(): cannot allocate rx_buffer_pool", __func__);
+ MSM_HS_ERR("%s(): cannot allocate rx_buffer_pool", __func__);
ret = -ENOMEM;
goto exit_tasket_init;
}
rx->buffer = dma_pool_alloc(rx->pool, GFP_KERNEL, &rx->rbuffer);
if (!rx->buffer) {
- pr_err("%s(): cannot allocate rx->buffer", __func__);
+ MSM_HS_ERR("%s(): cannot allocate rx->buffer", __func__);
ret = -ENOMEM;
goto free_pool;
}
@@ -2569,14 +2689,15 @@
/* Allocate the command pointer. Needs to be 64 bit aligned */
rx->command_ptr = kmalloc(sizeof(dmov_box), GFP_KERNEL | __GFP_DMA);
if (!rx->command_ptr) {
- pr_err("%s(): cannot allocate rx->command_ptr", __func__);
+ MSM_HS_ERR("%s(): cannot allocate rx->command_ptr", __func__);
ret = -ENOMEM;
goto free_tx_command_ptr_ptr;
}
rx->command_ptr_ptr = kmalloc(sizeof(u32), GFP_KERNEL | __GFP_DMA);
if (!rx->command_ptr_ptr) {
- pr_err("%s(): cannot allocate rx->command_ptr_ptr", __func__);
+ MSM_HS_ERR("%s(): cannot allocate rx->command_ptr_ptr",
+ __func__);
ret = -ENOMEM;
goto free_rx_command_ptr;
}
@@ -2644,7 +2765,7 @@
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
- pr_err("unable to allocate memory for platform data\n");
+ MSM_HS_ERR("unable to allocate memory for platform data\n");
return ERR_PTR(-ENOMEM);
}
@@ -2652,25 +2773,25 @@
pdata->uart_tx_gpio = of_get_named_gpio(node,
"qcom,tx-gpio", 0);
if (pdata->uart_tx_gpio < 0)
- pr_debug("uart_tx_gpio is not available\n");
+ MSM_HS_DBG("uart_tx_gpio is not available\n");
/* UART RX GPIO */
pdata->uart_rx_gpio = of_get_named_gpio(node,
"qcom,rx-gpio", 0);
if (pdata->uart_rx_gpio < 0)
- pr_debug("uart_rx_gpio is not available\n");
+ MSM_HS_DBG("uart_rx_gpio is not available\n");
/* UART CTS GPIO */
pdata->uart_cts_gpio = of_get_named_gpio(node,
"qcom,cts-gpio", 0);
if (pdata->uart_cts_gpio < 0)
- pr_debug("uart_cts_gpio is not available\n");
+ MSM_HS_DBG("uart_cts_gpio is not available\n");
/* UART RFR GPIO */
pdata->uart_rfr_gpio = of_get_named_gpio(node,
"qcom,rfr-gpio", 0);
if (pdata->uart_rfr_gpio < 0)
- pr_debug("uart_rfr_gpio is not available\n");
+ MSM_HS_DBG("uart_rfr_gpio is not available\n");
pdata->inject_rx_on_wakeup = of_property_read_bool(node,
"qcom,inject-rx-on-wakeup");
@@ -2679,7 +2800,7 @@
ret = of_property_read_u32(node, "qcom,rx-char-to-inject",
&rx_to_inject);
if (ret < 0) {
- pr_err("Error: Rx_char_to_inject not specified.\n");
+ MSM_HS_ERR("Error: Rx_char_to_inject not specified.\n");
return ERR_PTR(ret);
}
pdata->rx_to_inject = (char)rx_to_inject;
@@ -2688,30 +2809,30 @@
ret = of_property_read_u32(node, "qcom,bam-tx-ep-pipe-index",
&pdata->bam_tx_ep_pipe_index);
if (ret < 0) {
- pr_err("Error: Getting UART BAM TX EP Pipe Index.\n");
+ MSM_HS_ERR("Error: Getting UART BAM TX EP Pipe Index.\n");
return ERR_PTR(ret);
}
if (!(pdata->bam_tx_ep_pipe_index >= BAM_PIPE_MIN &&
pdata->bam_tx_ep_pipe_index <= BAM_PIPE_MAX)) {
- pr_err("Error: Invalid UART BAM TX EP Pipe Index.\n");
+ MSM_HS_ERR("Error: Invalid UART BAM TX EP Pipe Index.\n");
return ERR_PTR(-EINVAL);
}
ret = of_property_read_u32(node, "qcom,bam-rx-ep-pipe-index",
&pdata->bam_rx_ep_pipe_index);
if (ret < 0) {
- pr_err("Error: Getting UART BAM RX EP Pipe Index.\n");
+ MSM_HS_ERR("Error: Getting UART BAM RX EP Pipe Index.\n");
return ERR_PTR(ret);
}
if (!(pdata->bam_rx_ep_pipe_index >= BAM_PIPE_MIN &&
pdata->bam_rx_ep_pipe_index <= BAM_PIPE_MAX)) {
- pr_err("Error: Invalid UART BAM RX EP Pipe Index.\n");
+ MSM_HS_ERR("Error: Invalid UART BAM RX EP Pipe Index.\n");
return ERR_PTR(-EINVAL);
}
- pr_debug("tx_ep_pipe_index:%d rx_ep_pipe_index:%d\n"
+ MSM_HS_DBG("tx_ep_pipe_index:%d rx_ep_pipe_index:%d\n"
"tx_gpio:%d rx_gpio:%d rfr_gpio:%d cts_gpio:%d",
pdata->bam_tx_ep_pipe_index, pdata->bam_rx_ep_pipe_index,
pdata->uart_tx_gpio, pdata->uart_rx_gpio, pdata->uart_cts_gpio,
@@ -2767,7 +2888,7 @@
/* Allocate endpoint context */
sps_pipe_handle = sps_alloc_endpoint();
if (!sps_pipe_handle) {
- pr_err("msm_serial_hs: sps_alloc_endpoint() failed!!\n"
+ MSM_HS_ERR("msm_serial_hs: sps_alloc_endpoint() failed!!\n"
"is_producer=%d", is_producer);
rc = -ENOMEM;
goto out;
@@ -2776,7 +2897,7 @@
/* Get default connection configuration for an endpoint */
rc = sps_get_config(sps_pipe_handle, sps_config);
if (rc) {
- pr_err("msm_serial_hs: sps_get_config() failed!!\n"
+ MSM_HS_ERR("msm_serial_hs: sps_get_config() failed!!\n"
"pipe_handle=0x%x rc=%d", (u32)sps_pipe_handle, rc);
goto get_config_err;
}
@@ -2812,7 +2933,7 @@
GFP_KERNEL);
if (!sps_config->desc.base) {
rc = -ENOMEM;
- pr_err("msm_serial_hs: dma_alloc_coherent() failed!!\n");
+ MSM_HS_ERR("msm_serial_hs: dma_alloc_coherent() failed!!\n");
goto get_config_err;
}
memset(sps_config->desc.base, 0x00, sps_config->desc.size);
@@ -2831,10 +2952,10 @@
/* Now save the sps pipe handle */
ep->pipe_handle = sps_pipe_handle;
- pr_debug("msm_serial_hs: success !! %s: pipe_handle=0x%x\n"
- "desc_fifo.phys_base=0x%x\n",
+ MSM_HS_DBG("msm_serial_hs: success !! %s: pipe_handle=0x%x\n"
+ "desc_fifo.phys_base=0x%llx\n",
is_producer ? "READ" : "WRITE",
- (u32)sps_pipe_handle, sps_config->desc.phys_base);
+ (u32) sps_pipe_handle, (u64) sps_config->desc.phys_base);
return 0;
get_config_err:
@@ -2875,18 +2996,18 @@
bam.irq = (u32)msm_uport->bam_irq;
bam.manage = SPS_BAM_MGR_DEVICE_REMOTE;
- pr_debug("msm_serial_hs: bam physical base=0x%x\n",
+ MSM_HS_DBG("msm_serial_hs: bam physical base=0x%x\n",
(u32)bam.phys_addr);
- pr_debug("msm_serial_hs: bam virtual base=0x%x\n",
+ MSM_HS_DBG("msm_serial_hs: bam virtual base=0x%x\n",
(u32)bam.virt_addr);
/* Register UART Peripheral BAM device to SPS driver */
rc = sps_register_bam_device(&bam, &bam_handle);
if (rc) {
- pr_err("msm_serial_hs: BAM device register failed\n");
+ MSM_HS_ERR("msm_serial_hs: BAM device register failed\n");
return rc;
}
- pr_info("msm_serial_hs: BAM device registered. bam_handle=0x%x",
+ MSM_HS_INFO("msm_serial_hs: BAM device registered. bam_handle=0x%x",
msm_uport->bam_handle);
}
msm_uport->bam_handle = bam_handle;
@@ -2894,14 +3015,14 @@
rc = msm_hs_sps_init_ep_conn(msm_uport, &msm_uport->rx.prod,
UART_SPS_PROD_PERIPHERAL);
if (rc) {
- pr_err("%s: Failed to Init Producer BAM-pipe", __func__);
+ MSM_HS_ERR("%s: Failed to Init Producer BAM-pipe", __func__);
goto deregister_bam;
}
rc = msm_hs_sps_init_ep_conn(msm_uport, &msm_uport->tx.cons,
UART_SPS_CONS_PERIPHERAL);
if (rc) {
- pr_err("%s: Failed to Init Consumer BAM-pipe", __func__);
+ MSM_HS_ERR("%s: Failed to Init Consumer BAM-pipe", __func__);
goto deinit_ep_conn_prod;
}
return 0;
@@ -2953,7 +3074,7 @@
if (deviceid[alias_num] == 0) {
pdev->id = alias_num;
} else {
- pr_err("alias_num=%d already used\n",
+ MSM_HS_ERR("alias_num=%d already used\n",
alias_num);
return -EINVAL;
}
@@ -2966,7 +3087,7 @@
}
if (pdev->id < 0 || pdev->id >= UARTDM_NR) {
- pr_err("Invalid plaform device ID = %d\n", pdev->id);
+ MSM_HS_ERR("Invalid plaform device ID = %d\n", pdev->id);
return -EINVAL;
}
@@ -2994,39 +3115,39 @@
wakeup_irqres = platform_get_irq_byname(pdev, "wakeup_irq");
if (!core_resource) {
- pr_err("Invalid core HSUART Resources.\n");
+ MSM_HS_ERR("Invalid core HSUART Resources.\n");
return -ENXIO;
}
if (!bam_resource) {
- pr_err("Invalid BAM HSUART Resources.\n");
+ MSM_HS_ERR("Invalid BAM HSUART Resources.\n");
return -ENXIO;
}
if (!core_irqres) {
- pr_err("Invalid core irqres Resources.\n");
+ MSM_HS_ERR("Invalid core irqres Resources.\n");
return -ENXIO;
}
if (!bam_irqres) {
- pr_err("Invalid bam irqres Resources.\n");
+ MSM_HS_ERR("Invalid bam irqres Resources.\n");
return -ENXIO;
}
if (!wakeup_irqres)
- pr_debug("Wakeup irq not specified.\n");
+ MSM_HS_DBG("Wakeup irq not specified.\n");
uport->mapbase = core_resource->start;
uport->membase = ioremap(uport->mapbase,
resource_size(core_resource));
if (unlikely(!uport->membase)) {
- pr_err("UART Resource ioremap Failed.\n");
+ MSM_HS_ERR("UART Resource ioremap Failed.\n");
return -ENOMEM;
}
msm_uport->bam_mem = bam_resource->start;
msm_uport->bam_base = ioremap(msm_uport->bam_mem,
resource_size(bam_resource));
if (unlikely(!msm_uport->bam_base)) {
- pr_err("UART BAM Resource ioremap Failed.\n");
+ MSM_HS_ERR("UART BAM Resource ioremap Failed.\n");
iounmap(uport->membase);
return -ENOMEM;
}
@@ -3037,13 +3158,13 @@
msm_uport->bus_scale_table = msm_bus_cl_get_pdata(pdev);
if (!msm_uport->bus_scale_table) {
- pr_err("BLSP UART: Bus scaling is disabled.\n");
+ MSM_HS_ERR("BLSP UART: Bus scaling is disabled.\n");
} else {
msm_uport->bus_perf_client =
msm_bus_scale_register_client
(msm_uport->bus_scale_table);
if (IS_ERR(&msm_uport->bus_perf_client)) {
- pr_err("%s(): Bus client register failed.\n",
+ MSM_HS_ERR("%s(): Bus client register failed.\n",
__func__);
ret = -EINVAL;
goto unmap_memory;
@@ -3062,7 +3183,7 @@
uport->irq = platform_get_irq(pdev, 0);
if (unlikely((int)uport->irq < 0)) {
- pr_err("UART IRQ Failed.\n");
+ MSM_HS_ERR("UART IRQ Failed.\n");
iounmap(uport->membase);
return -ENXIO;
}
@@ -3135,14 +3256,14 @@
ret = clk_set_rate(msm_uport->clk, uport->uartclk);
if (ret) {
- printk(KERN_WARNING "Error setting clock rate on UART\n");
+ MSM_HS_WARN("Error setting clock rate on UART\n");
goto put_clk;
}
msm_uport->hsuart_wq = alloc_workqueue("k_hsuart",
WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
if (!msm_uport->hsuart_wq) {
- pr_err("%s(): Unable to create workqueue hsuart_wq\n",
+ MSM_HS_ERR("%s(): Unable to create workqueue hsuart_wq\n",
__func__);
ret = -ENOMEM;
goto put_clk;
@@ -3161,7 +3282,7 @@
if (is_blsp_uart(msm_uport)) {
ret = msm_hs_sps_init(msm_uport);
if (unlikely(ret)) {
- pr_err("SPS Initialization failed ! err=%d", ret);
+ MSM_HS_ERR("SPS Initialization failed ! err=%d", ret);
goto destroy_mutex;
}
}
@@ -3234,28 +3355,33 @@
int ret;
int i;
+ ipc_msm_hs_log_ctxt = ipc_log_context_create(IPC_MSM_HS_LOG_PAGES,
+ "msm_serial_hs");
+ if (!ipc_msm_hs_log_ctxt)
+ MSM_HS_WARN("%s: error creating logging context", __func__);
+
/* Init all UARTS as non-configured */
for (i = 0; i < UARTDM_NR; i++)
q_uart_port[i].uport.type = PORT_UNKNOWN;
ret = uart_register_driver(&msm_hs_driver);
if (unlikely(ret)) {
- printk(KERN_ERR "%s failed to load\n", __FUNCTION__);
+ MSM_HS_WARN("%s failed to load\n", __func__);
return ret;
}
debug_base = debugfs_create_dir("msm_serial_hs", NULL);
if (IS_ERR_OR_NULL(debug_base))
- pr_info("msm_serial_hs: Cannot create debugfs dir\n");
+ MSM_HS_INFO("msm_serial_hs: Cannot create debugfs dir\n");
ret = platform_driver_register(&msm_serial_hs_platform_driver);
if (ret) {
- printk(KERN_ERR "%s failed to load\n", __FUNCTION__);
+ MSM_HS_ERR("%s failed to load\n", __FUNCTION__);
debugfs_remove_recursive(debug_base);
uart_unregister_driver(&msm_hs_driver);
return ret;
}
- printk(KERN_INFO "msm_serial_hs module loaded\n");
+ MSM_HS_INFO("msm_serial_hs module loaded\n");
return ret;
}
@@ -3298,12 +3424,12 @@
ret = wait_event_timeout(msm_uport->tx.wait,
msm_uport->tx.flush == FLUSH_SHUTDOWN, 100);
if (!ret)
- pr_err("%s():HSUART TX Stalls.\n", __func__);
+ MSM_HS_ERR("%s():HSUART TX Stalls.\n", __func__);
} else {
/* BAM Disconnect for TX */
ret = sps_disconnect(sps_pipe_handle);
if (ret)
- pr_err("%s(): sps_disconnect failed\n",
+ MSM_HS_ERR("%s(): sps_disconnect failed\n",
__func__);
}
}
@@ -3358,7 +3484,7 @@
static void __exit msm_serial_hs_exit(void)
{
- printk(KERN_INFO "msm_serial_hs module removed\n");
+ MSM_HS_INFO("msm_serial_hs module removed\n");
debugfs_remove_recursive(debug_base);
platform_driver_unregister(&msm_serial_hs_platform_driver);
uart_unregister_driver(&msm_hs_driver);
diff --git a/drivers/tty/serial/msm_serial_hs_lite.c b/drivers/tty/serial/msm_serial_hs_lite.c
index a4a4f28..0ff8ad7 100644
--- a/drivers/tty/serial/msm_serial_hs_lite.c
+++ b/drivers/tty/serial/msm_serial_hs_lite.c
@@ -523,6 +523,10 @@
{
struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port);
+ if (port->suspended) {
+ pr_err("%s: System is in Suspend state\n", __func__);
+ return;
+ }
msm_hsl_port->imr |= UARTDM_ISR_TXLEV_BMSK;
msm_hsl_write(port, msm_hsl_port->imr,
regmap[msm_hsl_port->ver_id][UARTDM_IMR]);
diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig
index 6f3ea9b..ad66113 100644
--- a/drivers/uio/Kconfig
+++ b/drivers/uio/Kconfig
@@ -111,4 +111,11 @@
To compile this driver as a module, choose M here: the module
will be called uio_pruss.
+config UIO_MSM_SHAREDMEM
+ bool "MSM shared memory driver"
+ default n
+ help
+ Provides the clients with their respective alloted shared memory
+ addresses which are used as transport buffer.
+
endif
diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile
index d4dd9a5..c4d177a 100644
--- a/drivers/uio/Makefile
+++ b/drivers/uio/Makefile
@@ -7,3 +7,4 @@
obj-$(CONFIG_UIO_PCI_GENERIC) += uio_pci_generic.o
obj-$(CONFIG_UIO_NETX) += uio_netx.o
obj-$(CONFIG_UIO_PRUSS) += uio_pruss.o
+obj-$(CONFIG_UIO_MSM_SHAREDMEM) += msm_sharedmem.o
diff --git a/drivers/uio/msm_sharedmem.c b/drivers/uio/msm_sharedmem.c
new file mode 100644
index 0000000..438f002
--- /dev/null
+++ b/drivers/uio/msm_sharedmem.c
@@ -0,0 +1,87 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/uio_driver.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+
+#define DRIVER_NAME "msm_sharedmem"
+
+static int msm_sharedmem_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct uio_info *info = NULL;
+ struct resource *clnt_res = NULL;
+
+ /* Get the addresses from platform-data */
+ if (!pdev->dev.of_node) {
+ pr_err("Node not found\n");
+ ret = -ENODEV;
+ goto out;
+ }
+ clnt_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!clnt_res) {
+ pr_err("resource not found\n");
+ return -ENODEV;
+ }
+
+ info = devm_kzalloc(&pdev->dev, sizeof(struct uio_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ info->name = clnt_res->name;
+ info->version = "1.0";
+ info->mem[0].addr = clnt_res->start;
+ info->mem[0].size = resource_size(clnt_res);
+ info->mem[0].memtype = UIO_MEM_PHYS;
+
+ /* Setup device */
+ ret = uio_register_device(&pdev->dev, info);
+ if (ret)
+ goto out;
+
+ dev_set_drvdata(&pdev->dev, info);
+ pr_debug("Device created for client '%s'\n", clnt_res->name);
+out:
+ return ret;
+}
+
+static int msm_sharedmem_remove(struct platform_device *pdev)
+{
+ struct uio_info *info = dev_get_drvdata(&pdev->dev);
+
+ uio_unregister_device(info);
+
+ return 0;
+}
+
+static struct of_device_id msm_sharedmem_of_match[] = {
+ {.compatible = "qcom,sharedmem-uio",},
+ {},
+};
+MODULE_DEVICE_TABLE(of, msm_sharedmem_of_match);
+
+static struct platform_driver msm_sharedmem_driver = {
+ .probe = msm_sharedmem_probe,
+ .remove = msm_sharedmem_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = msm_sharedmem_of_match,
+ },
+};
+
+module_platform_driver(msm_sharedmem_driver);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/class/Kconfig b/drivers/usb/class/Kconfig
index 2519e32..f7321e5 100644
--- a/drivers/usb/class/Kconfig
+++ b/drivers/usb/class/Kconfig
@@ -50,3 +50,15 @@
To compile this driver as a module, choose M here: the
module will be called usbtmc.
+
+config USB_CCID_BRIDGE
+ tristate "USB Smart Card Class (CCID) support"
+ help
+ Say Y here if you want to connect a USB Smart Card device that
+ follows the USB.org specification for Integrated Circuit(s) Cards
+ Interface Devices to your computer's USB port. This module
+ provides a character device interface to exchange the messages.
+ Ioctls facilitate control transfers and interrupt transfers.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ccid_bridge.
diff --git a/drivers/usb/class/Makefile b/drivers/usb/class/Makefile
index 32e8527..c2ee6f3 100644
--- a/drivers/usb/class/Makefile
+++ b/drivers/usb/class/Makefile
@@ -7,3 +7,4 @@
obj-$(CONFIG_USB_PRINTER) += usblp.o
obj-$(CONFIG_USB_WDM) += cdc-wdm.o
obj-$(CONFIG_USB_TMC) += usbtmc.o
+obj-$(CONFIG_USB_CCID_BRIDGE) += ccid_bridge.o
diff --git a/drivers/usb/class/ccid_bridge.c b/drivers/usb/class/ccid_bridge.c
new file mode 100644
index 0000000..a3e100a
--- /dev/null
+++ b/drivers/usb/class/ccid_bridge.c
@@ -0,0 +1,885 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt "\n", __func__
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+#include <linux/wait.h>
+#include <linux/cdev.h>
+
+#include <linux/usb/ccid_bridge.h>
+
+#define CCID_CLASS_DECRIPTOR_TYPE 0x21
+#define CCID_NOTIFY_SLOT_CHANGE 0x50
+#define CCID_NOTIFY_HARDWARE_ERROR 0x51
+#define CCID_ABORT_REQ 0x1
+#define CCID_GET_CLK_FREQ_REQ 0x2
+#define CCID_GET_DATA_RATES 0x3
+
+#define CCID_BRIDGE_MSG_SZ 512
+#define CCID_BRIDGE_OPEN_TIMEOUT 500 /* msec */
+#define CCID_CONTROL_TIMEOUT 500 /* msec */
+#define CCID_BRIDGE_MSG_TIMEOUT 500 /* msec */
+
+struct ccid_bridge {
+ struct usb_device *udev;
+ struct usb_interface *intf;
+ unsigned int in_pipe;
+ unsigned int out_pipe;
+ unsigned int int_pipe;
+ struct urb *inturb;
+ struct urb *readurb;
+ struct urb *writeurb;
+
+ bool opened;
+ bool events_supported;
+ bool is_suspended;
+ struct mutex open_mutex;
+ struct mutex write_mutex;
+ struct mutex read_mutex;
+ struct mutex event_mutex;
+ int write_result;
+ int read_result;
+ int event_result;
+ wait_queue_head_t open_wq;
+ wait_queue_head_t write_wq;
+ wait_queue_head_t read_wq;
+ wait_queue_head_t event_wq;
+ struct usb_ccid_event cur_event;
+ void *intbuf;
+
+ dev_t chrdev;
+ struct cdev cdev;
+ struct class *class;
+ struct device *device;
+};
+
+static struct ccid_bridge *__ccid_bridge_dev;
+
+static void ccid_bridge_out_cb(struct urb *urb)
+{
+ struct ccid_bridge *ccid = urb->context;
+
+ if (urb->dev->state == USB_STATE_NOTATTACHED)
+ ccid->write_result = -ENODEV;
+ else
+ ccid->write_result = urb->status ? : urb->actual_length;
+
+ pr_debug("write result = %d", ccid->write_result);
+ wake_up(&ccid->write_wq);
+}
+
+static void ccid_bridge_in_cb(struct urb *urb)
+{
+ struct ccid_bridge *ccid = urb->context;
+
+ if (urb->dev->state == USB_STATE_NOTATTACHED)
+ ccid->read_result = -ENODEV;
+ else
+ ccid->read_result = urb->status ? : urb->actual_length;
+
+ pr_debug("read result = %d", ccid->read_result);
+ wake_up(&ccid->read_wq);
+}
+
+static void ccid_bridge_int_cb(struct urb *urb)
+{
+ struct ccid_bridge *ccid = urb->context;
+ u8 *msg_type;
+ bool wakeup = true;
+
+ if (urb->dev->state == USB_STATE_NOTATTACHED || (urb->status &&
+ urb->status != -ENOENT)) {
+ ccid->event_result = -ENODEV;
+ wakeup = true;
+ goto out;
+ }
+
+ /*
+ * Don't wakeup the event ioctl process during suspend.
+ * The suspend state is not visible to user space.
+ * we wake up the process after resume to send RESUME
+ * event if the device supports remote wakeup.
+ */
+ if (urb->status == -ENOENT && !urb->actual_length) {
+ ccid->event_result = -ENOENT;
+ wakeup = false;
+ goto out;
+ }
+
+ ccid->event_result = 0;
+ msg_type = urb->transfer_buffer;
+ switch (*msg_type) {
+ case CCID_NOTIFY_SLOT_CHANGE:
+ pr_debug("NOTIFY_SLOT_CHANGE event arrived");
+ ccid->cur_event.event = USB_CCID_NOTIFY_SLOT_CHANGE_EVENT;
+ ccid->cur_event.u.notify.slot_icc_state = *(++msg_type);
+ break;
+ case CCID_NOTIFY_HARDWARE_ERROR:
+ pr_debug("NOTIFY_HARDWARE_ERROR event arrived");
+ ccid->cur_event.event = USB_CCID_HARDWARE_ERROR_EVENT;
+ ccid->cur_event.u.error.slot = *(++msg_type);
+ ccid->cur_event.u.error.seq = *(++msg_type);
+ ccid->cur_event.u.error.error_code = *(++msg_type);
+ break;
+ default:
+ pr_err("UNKNOWN event arrived\n");
+ ccid->event_result = -EINVAL;
+ }
+
+out:
+ pr_debug("returning %d", ccid->event_result);
+ if (wakeup)
+ wake_up(&ccid->event_wq);
+}
+
+static int ccid_bridge_submit_inturb(struct ccid_bridge *ccid)
+{
+ int ret = 0;
+
+ /*
+ * Don't resume the bus to submit an interrupt URB.
+ * We submit the URB in resume path. This is important.
+ * Because the device will be in suspend state during
+ * multiple system suspend/resume cycles. The user space
+ * process comes here during system resume after it is
+ * unfrozen.
+ */
+ if (!ccid->int_pipe || ccid->is_suspended)
+ goto out;
+
+ ret = usb_autopm_get_interface(ccid->intf);
+ if (ret < 0) {
+ pr_debug("fail to get autopm with %d\n", ret);
+ goto out;
+ }
+ ret = usb_submit_urb(ccid->inturb, GFP_KERNEL);
+ if (ret < 0)
+ pr_err("fail to submit int urb with %d\n", ret);
+ usb_autopm_put_interface(ccid->intf);
+
+out:
+ pr_debug("returning %d", ret);
+ return ret;
+}
+
+static int ccid_bridge_get_event(struct ccid_bridge *ccid)
+{
+ int ret = 0;
+
+ /*
+ * The first event returned after the device resume
+ * will be RESUME event. This event is set by
+ * the resume.
+ */
+ if (ccid->cur_event.event)
+ goto out;
+
+ ccid->event_result = -EINPROGRESS;
+
+ ret = ccid_bridge_submit_inturb(ccid);
+ if (ret < 0)
+ goto out;
+
+ /*
+ * Wait for the notification on interrupt endpoint
+ * or remote wakeup event from the resume. The
+ * int urb completion handler and resume callback
+ * take care of setting the current event.
+ */
+ mutex_unlock(&ccid->event_mutex);
+ ret = wait_event_interruptible(ccid->event_wq,
+ (ccid->event_result != -EINPROGRESS));
+ mutex_lock(&ccid->event_mutex);
+
+ if (ret == -ERESTARTSYS) /* interrupted */
+ usb_kill_urb(ccid->inturb);
+ else
+ ret = ccid->event_result;
+out:
+ pr_debug("returning %d", ret);
+ return ret;
+}
+
+static int ccid_bridge_open(struct inode *ip, struct file *fp)
+{
+ struct ccid_bridge *ccid = container_of(ip->i_cdev,
+ struct ccid_bridge, cdev);
+ int ret;
+
+ pr_debug("called");
+
+ mutex_lock(&ccid->open_mutex);
+ if (ccid->opened) {
+ ret = -EBUSY;
+ goto out;
+ }
+ mutex_unlock(&ccid->open_mutex);
+
+ ret = wait_event_interruptible_timeout(ccid->open_wq,
+ ccid->intf != NULL, msecs_to_jiffies(
+ CCID_BRIDGE_OPEN_TIMEOUT));
+
+ mutex_lock(&ccid->open_mutex);
+
+ if (ret != -ERESTARTSYS && ccid->intf) {
+ fp->private_data = ccid;
+ ccid->opened = true;
+ ret = 0;
+ } else if (!ret) { /* timed out */
+ ret = -ENODEV;
+ }
+out:
+ mutex_unlock(&ccid->open_mutex);
+ pr_debug("returning %d", ret);
+ return ret;
+}
+
+static ssize_t ccid_bridge_write(struct file *fp, const char __user *ubuf,
+ size_t count, loff_t *pos)
+{
+ struct ccid_bridge *ccid = fp->private_data;
+ int ret;
+ char *kbuf;
+
+ pr_debug("called with %d", count);
+
+ if (!ccid->intf) {
+ pr_debug("intf is not active");
+ return -ENODEV;
+ }
+
+ mutex_lock(&ccid->write_mutex);
+
+ if (!count || count > CCID_BRIDGE_MSG_SZ) {
+ pr_err("invalid count");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ kbuf = kmalloc(count, GFP_KERNEL);
+ if (!kbuf) {
+ pr_err("fail to allocate memory");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = copy_from_user(kbuf, ubuf, count);
+ if (ret) {
+ pr_err("fail to copy user buf");
+ ret = -EFAULT;
+ goto free_kbuf;
+ }
+
+ ret = usb_autopm_get_interface(ccid->intf);
+ if (ret) {
+ pr_err("fail to get autopm with %d", ret);
+ goto free_kbuf;
+ }
+
+ ccid->write_result = 0;
+
+ usb_fill_bulk_urb(ccid->writeurb, ccid->udev, ccid->out_pipe,
+ kbuf, count, ccid_bridge_out_cb, ccid);
+ ret = usb_submit_urb(ccid->writeurb, GFP_KERNEL);
+ if (ret < 0) {
+ pr_err("urb submit fail with %d", ret);
+ goto put_pm;
+ }
+
+ ret = wait_event_interruptible_timeout(ccid->write_wq,
+ ccid->write_result != 0,
+ msecs_to_jiffies(CCID_BRIDGE_MSG_TIMEOUT));
+ if (!ret || ret == -ERESTARTSYS) { /* timedout or interrupted */
+ usb_kill_urb(ccid->writeurb);
+ if (!ret)
+ ret = -ETIMEDOUT;
+ } else {
+ ret = ccid->write_result;
+ }
+
+ pr_debug("returning %d", ret);
+
+put_pm:
+ if (ret != -ENODEV)
+ usb_autopm_put_interface(ccid->intf);
+free_kbuf:
+ kfree(kbuf);
+out:
+ mutex_unlock(&ccid->write_mutex);
+ return ret;
+
+}
+
+static ssize_t ccid_bridge_read(struct file *fp, char __user *ubuf,
+ size_t count, loff_t *pos)
+{
+ struct ccid_bridge *ccid = fp->private_data;
+ int ret;
+ char *kbuf;
+
+ pr_debug("called with %d", count);
+ if (!ccid->intf) {
+ pr_debug("intf is not active");
+ return -ENODEV;
+ }
+
+ mutex_lock(&ccid->read_mutex);
+
+ if (!count || count > CCID_BRIDGE_MSG_SZ) {
+ pr_err("invalid count");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ kbuf = kmalloc(count, GFP_KERNEL);
+ if (!kbuf) {
+ pr_err("fail to allocate memory");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = usb_autopm_get_interface(ccid->intf);
+ if (ret) {
+ pr_err("fail to get autopm with %d", ret);
+ goto free_kbuf;
+ }
+
+ ccid->read_result = 0;
+
+ usb_fill_bulk_urb(ccid->readurb, ccid->udev, ccid->in_pipe,
+ kbuf, count, ccid_bridge_in_cb, ccid);
+ ret = usb_submit_urb(ccid->readurb, GFP_KERNEL);
+ if (ret < 0) {
+ pr_err("urb submit fail with %d", ret);
+ if (ret != -ENODEV)
+ usb_autopm_put_interface(ccid->intf);
+ goto free_kbuf;
+ }
+
+
+ ret = wait_event_interruptible_timeout(ccid->read_wq,
+ ccid->read_result != 0,
+ msecs_to_jiffies(CCID_BRIDGE_MSG_TIMEOUT));
+ if (!ret || ret == -ERESTARTSYS) { /* timedout or interrupted */
+ usb_kill_urb(ccid->readurb);
+ if (!ret)
+ ret = -ETIMEDOUT;
+ } else {
+ ret = ccid->read_result;
+ }
+
+
+ if (ret > 0) {
+ if (copy_to_user(ubuf, kbuf, ret))
+ ret = -EFAULT;
+ }
+
+ usb_autopm_put_interface(ccid->intf);
+ pr_debug("returning %d", ret);
+
+free_kbuf:
+ kfree(kbuf);
+out:
+ mutex_unlock(&ccid->read_mutex);
+ return ret;
+}
+
+static long
+ccid_bridge_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
+{
+ struct ccid_bridge *ccid = fp->private_data;
+ char *buf;
+ struct usb_ccid_data data;
+ struct usb_ccid_abort abort;
+ struct usb_descriptor_header *header;
+ int ret;
+ struct usb_device *udev = ccid->udev;
+ __u8 intf = ccid->intf->cur_altsetting->desc.bInterfaceNumber;
+ __u8 breq = 0;
+
+ if (!ccid->intf) {
+ pr_debug("intf is not active");
+ return -ENODEV;
+ }
+
+ mutex_lock(&ccid->event_mutex);
+ switch (cmd) {
+ case USB_CCID_GET_CLASS_DESC:
+ pr_debug("GET_CLASS_DESC ioctl called");
+ ret = copy_from_user(&data, (void __user *)arg, sizeof(data));
+ if (ret) {
+ ret = -EFAULT;
+ break;
+ }
+ ret = __usb_get_extra_descriptor(udev->rawdescriptors[0],
+ le16_to_cpu(udev->config[0].desc.wTotalLength),
+ CCID_CLASS_DECRIPTOR_TYPE, (void **) &buf);
+ if (ret) {
+ ret = -ENOENT;
+ break;
+ }
+ header = (struct usb_descriptor_header *) buf;
+ if (data.length != header->bLength) {
+ ret = -EINVAL;
+ break;
+ }
+ ret = copy_to_user((void __user *)data.data, buf, data.length);
+ if (ret)
+ ret = -EFAULT;
+ break;
+ case USB_CCID_GET_CLOCK_FREQUENCIES:
+ pr_debug("GET_CLOCK_FREQUENCIES ioctl called");
+ breq = CCID_GET_CLK_FREQ_REQ;
+ /* fall through */
+ case USB_CCID_GET_DATA_RATES:
+ if (!breq) {
+ pr_debug("GET_DATA_RATES ioctl called");
+ breq = CCID_GET_DATA_RATES;
+ }
+ ret = copy_from_user(&data, (void __user *)arg, sizeof(data));
+ if (ret) {
+ ret = -EFAULT;
+ break;
+ }
+ buf = kmalloc(data.length, GFP_KERNEL);
+ if (!buf) {
+ ret = -ENOMEM;
+ break;
+ }
+ ret = usb_autopm_get_interface(ccid->intf);
+ if (ret < 0) {
+ pr_debug("fail to get autopm with %d", ret);
+ break;
+ }
+ ret = usb_control_msg(ccid->udev,
+ usb_rcvctrlpipe(ccid->udev, 0),
+ breq, (USB_DIR_IN | USB_TYPE_CLASS |
+ USB_RECIP_INTERFACE), 0, intf, buf,
+ data.length, CCID_CONTROL_TIMEOUT);
+ usb_autopm_put_interface(ccid->intf);
+ if (ret == data.length) {
+ ret = copy_to_user((void __user *)data.data, buf,
+ data.length);
+ if (ret)
+ ret = -EFAULT;
+ } else {
+ if (ret > 0)
+ ret = -EPIPE;
+ }
+ kfree(buf);
+ break;
+ case USB_CCID_ABORT:
+ pr_debug("ABORT ioctl called");
+ breq = CCID_ABORT_REQ;
+ ret = copy_from_user(&abort, (void __user *)arg, sizeof(abort));
+ if (ret) {
+ ret = -EFAULT;
+ break;
+ }
+ ret = usb_autopm_get_interface(ccid->intf);
+ if (ret < 0) {
+ pr_debug("fail to get autopm with %d", ret);
+ break;
+ }
+ ret = usb_control_msg(ccid->udev,
+ usb_sndctrlpipe(ccid->udev, 0),
+ breq, (USB_DIR_OUT | USB_TYPE_CLASS |
+ USB_RECIP_INTERFACE),
+ (abort.seq << 8) | abort.slot, intf, NULL,
+ 0, CCID_CONTROL_TIMEOUT);
+ if (ret < 0)
+ pr_err("abort request failed with err %d\n", ret);
+ usb_autopm_put_interface(ccid->intf);
+ break;
+ case USB_CCID_GET_EVENT:
+ pr_debug("GET_EVENT ioctl called");
+ if (!ccid->events_supported) {
+ ret = -ENOENT;
+ break;
+ }
+ ret = ccid_bridge_get_event(ccid);
+ if (ret == 0) {
+ ret = copy_to_user((void __user *)arg, &ccid->cur_event,
+ sizeof(ccid->cur_event));
+ if (ret)
+ ret = -EFAULT;
+ }
+ ccid->cur_event.event = 0;
+ break;
+ default:
+ pr_err("UNKNOWN ioctl called");
+ ret = -EINVAL;
+ break;
+ }
+
+ mutex_unlock(&ccid->event_mutex);
+ pr_debug("returning %d", ret);
+ return ret;
+}
+
+static int ccid_bridge_release(struct inode *ip, struct file *fp)
+{
+ struct ccid_bridge *ccid = fp->private_data;
+
+ pr_debug("called");
+
+ usb_kill_urb(ccid->writeurb);
+ usb_kill_urb(ccid->readurb);
+ if (ccid->int_pipe)
+ usb_kill_urb(ccid->inturb);
+
+ ccid->event_result = -EIO;
+ wake_up(&ccid->event_wq);
+
+ mutex_lock(&ccid->open_mutex);
+ ccid->opened = false;
+ mutex_unlock(&ccid->open_mutex);
+ return 0;
+}
+
+static const struct file_operations ccid_bridge_fops = {
+ .owner = THIS_MODULE,
+ .open = ccid_bridge_open,
+ .write = ccid_bridge_write,
+ .read = ccid_bridge_read,
+ .unlocked_ioctl = ccid_bridge_ioctl,
+ .release = ccid_bridge_release,
+};
+
+static int ccid_bridge_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct ccid_bridge *ccid = usb_get_intfdata(intf);
+ int ret = 0;
+
+ pr_debug("called");
+
+ if (!ccid->opened)
+ goto out;
+
+ mutex_lock(&ccid->event_mutex);
+ if (ccid->int_pipe) {
+ usb_kill_urb(ccid->inturb);
+ if (ccid->event_result != -ENOENT) {
+ ret = -EBUSY;
+ goto rel_mutex;
+ }
+ }
+
+ ccid->is_suspended = true;
+rel_mutex:
+ mutex_unlock(&ccid->event_mutex);
+out:
+ pr_debug("returning %d", ret);
+ return ret;
+}
+
+static int ccid_bridge_resume(struct usb_interface *intf)
+{
+ struct ccid_bridge *ccid = usb_get_intfdata(intf);
+ int ret;
+
+ pr_debug("called");
+
+ if (!ccid->opened)
+ goto out;
+
+ mutex_lock(&ccid->event_mutex);
+
+ ccid->is_suspended = false;
+
+ if (device_can_wakeup(&ccid->udev->dev)) {
+ ccid->event_result = 0;
+ ccid->cur_event.event = USB_CCID_RESUME_EVENT;
+ wake_up(&ccid->event_wq);
+ } else if (ccid->int_pipe) {
+ ccid->event_result = -EINPROGRESS;
+ ret = usb_submit_urb(ccid->inturb, GFP_KERNEL);
+ if (ret < 0)
+ pr_debug("fail to submit inturb with %d\n", ret);
+ }
+
+ mutex_unlock(&ccid->event_mutex);
+out:
+ return 0;
+}
+
+static int
+ccid_bridge_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+ struct ccid_bridge *ccid = __ccid_bridge_dev;
+ struct usb_host_interface *intf_desc;
+ struct usb_endpoint_descriptor *ep_desc;
+ struct usb_host_endpoint *ep;
+ __u8 epin_addr = 0, epout_addr = 0, epint_addr = 0;
+ int i, ret;
+
+ intf_desc = intf->cur_altsetting;
+
+ if (intf_desc->desc.bNumEndpoints > 3)
+ return -ENODEV;
+
+ for (i = 0; i < intf_desc->desc.bNumEndpoints; i++) {
+ ep_desc = &intf_desc->endpoint[i].desc;
+
+ if (usb_endpoint_is_bulk_in(ep_desc))
+ epin_addr = ep_desc->bEndpointAddress;
+ else if (usb_endpoint_is_bulk_out(ep_desc))
+ epout_addr = ep_desc->bEndpointAddress;
+ else if (usb_endpoint_is_int_in(ep_desc))
+ epint_addr = ep_desc->bEndpointAddress;
+ else
+ return -ENODEV;
+ }
+
+ if (!epin_addr || !epout_addr)
+ return -ENODEV;
+
+ ccid->udev = usb_get_dev(interface_to_usbdev(intf));
+ ccid->in_pipe = usb_rcvbulkpipe(ccid->udev, epin_addr);
+ ccid->out_pipe = usb_sndbulkpipe(ccid->udev, epout_addr);
+ if (epint_addr)
+ ccid->int_pipe = usb_rcvbulkpipe(ccid->udev, epint_addr);
+
+ ccid->writeurb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!ccid->writeurb) {
+ pr_err("fail to allocate write urb");
+ ret = -ENOMEM;
+ goto put_udev;
+ }
+ ccid->readurb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!ccid->readurb) {
+ pr_err("fail to allocate read urb");
+ ret = -ENOMEM;
+ goto free_writeurb;
+ }
+
+ if (ccid->int_pipe) {
+ pr_debug("interrupt endpoint is present");
+ ep = usb_pipe_endpoint(ccid->udev, ccid->int_pipe);
+ ccid->inturb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!ccid->inturb) {
+ pr_err("fail to allocate int urb");
+ ret = -ENOMEM;
+ goto free_readurb;
+ }
+ ccid->intbuf = kmalloc(usb_endpoint_maxp(&ep->desc),
+ GFP_KERNEL);
+ if (!ccid->intbuf) {
+ pr_err("fail to allocated int buf");
+ ret = -ENOMEM;
+ goto free_inturb;
+ }
+ usb_fill_int_urb(ccid->inturb, ccid->udev,
+ usb_rcvintpipe(ccid->udev, epint_addr),
+ ccid->intbuf, usb_endpoint_maxp(&ep->desc),
+ ccid_bridge_int_cb, ccid,
+ ep->desc.bInterval);
+ }
+
+ if (ccid->int_pipe || device_can_wakeup(&ccid->udev->dev)) {
+ pr_debug("event support is present");
+ ccid->events_supported = true;
+ }
+
+ usb_set_intfdata(intf, ccid);
+
+ mutex_lock(&ccid->open_mutex);
+ ccid->intf = intf;
+ wake_up(&ccid->open_wq);
+ mutex_unlock(&ccid->open_mutex);
+
+ pr_info("success");
+ return 0;
+
+free_inturb:
+ if (ccid->int_pipe)
+ usb_free_urb(ccid->inturb);
+free_readurb:
+ usb_free_urb(ccid->readurb);
+free_writeurb:
+ usb_free_urb(ccid->writeurb);
+put_udev:
+ usb_put_dev(ccid->udev);
+ return ret;
+}
+
+static void ccid_bridge_disconnect(struct usb_interface *intf)
+{
+ struct ccid_bridge *ccid = usb_get_intfdata(intf);
+
+ pr_debug("called");
+
+ usb_kill_urb(ccid->writeurb);
+ usb_kill_urb(ccid->readurb);
+ if (ccid->int_pipe)
+ usb_kill_urb(ccid->inturb);
+
+ ccid->event_result = -ENODEV;
+ wake_up(&ccid->event_wq);
+
+ /*
+ * This would synchronize any ongoing read/write/ioctl.
+ * After acquiring the mutex, we can safely set
+ * intf to NULL.
+ */
+ mutex_lock(&ccid->open_mutex);
+ mutex_lock(&ccid->write_mutex);
+ mutex_lock(&ccid->read_mutex);
+ mutex_lock(&ccid->event_mutex);
+
+ usb_free_urb(ccid->writeurb);
+ usb_free_urb(ccid->readurb);
+ if (ccid->int_pipe) {
+ usb_free_urb(ccid->inturb);
+ kfree(ccid->intbuf);
+ ccid->int_pipe = 0;
+ }
+
+ ccid->intf = NULL;
+
+ mutex_unlock(&ccid->event_mutex);
+ mutex_unlock(&ccid->read_mutex);
+ mutex_unlock(&ccid->write_mutex);
+ mutex_unlock(&ccid->open_mutex);
+
+}
+
+static const struct usb_device_id ccid_bridge_ids[] = {
+ { USB_INTERFACE_INFO(USB_CLASS_CSCID, 0, 0) },
+
+ {} /* terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, ccid_bridge_ids);
+
+static struct usb_driver ccid_bridge_driver = {
+ .name = "ccid_bridge",
+ .probe = ccid_bridge_probe,
+ .disconnect = ccid_bridge_disconnect,
+ .suspend = ccid_bridge_suspend,
+ .resume = ccid_bridge_resume,
+ .id_table = ccid_bridge_ids,
+ .supports_autosuspend = 1,
+};
+
+static int __init ccid_bridge_init(void)
+{
+ int ret;
+ struct ccid_bridge *ccid;
+
+ ccid = kzalloc(sizeof(*ccid), GFP_KERNEL);
+ if (!ccid) {
+ pr_err("Fail to allocate ccid");
+ ret = -ENOMEM;
+ goto out;
+ }
+ __ccid_bridge_dev = ccid;
+
+ mutex_init(&ccid->open_mutex);
+ mutex_init(&ccid->write_mutex);
+ mutex_init(&ccid->read_mutex);
+ mutex_init(&ccid->event_mutex);
+
+ init_waitqueue_head(&ccid->open_wq);
+ init_waitqueue_head(&ccid->write_wq);
+ init_waitqueue_head(&ccid->read_wq);
+ init_waitqueue_head(&ccid->event_wq);
+
+ ret = usb_register(&ccid_bridge_driver);
+ if (ret < 0) {
+ pr_err("Fail to register ccid usb driver with %d", ret);
+ goto free_ccid;
+ }
+
+ ret = alloc_chrdev_region(&ccid->chrdev, 0, 1, "ccid_bridge");
+ if (ret < 0) {
+ pr_err("Fail to allocate ccid char dev region with %d", ret);
+ goto unreg_driver;
+ }
+ ccid->class = class_create(THIS_MODULE, "ccid_bridge");
+ if (IS_ERR(ccid->class)) {
+ ret = PTR_ERR(ccid->class);
+ pr_err("Fail to create ccid class with %d", ret);
+ goto unreg_chrdev;
+ }
+ cdev_init(&ccid->cdev, &ccid_bridge_fops);
+ ccid->cdev.owner = THIS_MODULE;
+
+ ret = cdev_add(&ccid->cdev, ccid->chrdev, 1);
+ if (ret < 0) {
+ pr_err("Fail to add ccid cdev with %d", ret);
+ goto destroy_class;
+ }
+ ccid->device = device_create(ccid->class,
+ NULL, ccid->chrdev, NULL,
+ "ccid_bridge");
+ if (IS_ERR(ccid->device)) {
+ ret = PTR_ERR(ccid->device);
+ pr_err("Fail to create ccid device with %d", ret);
+ goto del_cdev;
+ }
+
+ pr_info("success");
+
+ return 0;
+
+del_cdev:
+ cdev_del(&ccid->cdev);
+destroy_class:
+ class_destroy(ccid->class);
+unreg_chrdev:
+ unregister_chrdev_region(ccid->chrdev, 1);
+unreg_driver:
+ usb_deregister(&ccid_bridge_driver);
+free_ccid:
+ mutex_destroy(&ccid->open_mutex);
+ mutex_destroy(&ccid->write_mutex);
+ mutex_destroy(&ccid->read_mutex);
+ mutex_destroy(&ccid->event_mutex);
+ kfree(ccid);
+ __ccid_bridge_dev = NULL;
+out:
+ return ret;
+}
+
+static void __exit ccid_bridge_exit(void)
+{
+ struct ccid_bridge *ccid = __ccid_bridge_dev;
+
+ pr_debug("called");
+ device_destroy(ccid->class, ccid->chrdev);
+ cdev_del(&ccid->cdev);
+ class_destroy(ccid->class);
+ unregister_chrdev_region(ccid->chrdev, 1);
+
+ usb_deregister(&ccid_bridge_driver);
+
+ mutex_destroy(&ccid->open_mutex);
+ mutex_destroy(&ccid->write_mutex);
+ mutex_destroy(&ccid->read_mutex);
+ mutex_destroy(&ccid->event_mutex);
+
+ kfree(ccid);
+ __ccid_bridge_dev = NULL;
+}
+
+module_init(ccid_bridge_init);
+module_exit(ccid_bridge_exit);
+
+MODULE_DESCRIPTION("USB CCID bridge driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index d97d548..827ac9d 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -3159,7 +3159,8 @@
for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) {
if (USE_NEW_SCHEME(retry_counter) &&
!(hcd->driver->flags & HCD_USB3) &&
- !(hcd->driver->flags & HCD_OLD_ENUM)) {
+ !((hcd->driver->flags & HCD_RT_OLD_ENUM) &&
+ !hdev->parent)) {
struct usb_device_descriptor *buf;
int r = 0;
@@ -3261,7 +3262,8 @@
msleep(10);
if (USE_NEW_SCHEME(retry_counter) &&
!(hcd->driver->flags & HCD_USB3) &&
- !(hcd->driver->flags & HCD_OLD_ENUM))
+ !((hcd->driver->flags & HCD_RT_OLD_ENUM) &&
+ !hdev->parent))
break;
}
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 1be2550..4e84b94 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -631,6 +631,7 @@
u8 epnum;
struct dwc3_trb *trb;
+ struct dwc3_trb *ztrb;
dma_addr_t trb_dma;
unsigned direction:1;
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 554cce8..97592c4 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -2288,8 +2288,12 @@
if (mdwc->otg_xceiv && !mdwc->ext_inuse &&
(mdwc->ext_xceiv.otg_capability || !init)) {
mdwc->ext_xceiv.bsv = val->intval;
+ /*
+ * set debouncing delay to 120msec. Otherwise battery
+ * charging CDP complaince test fails if delay > 120ms.
+ */
queue_delayed_work(system_nrt_wq,
- &mdwc->resume_work, 20);
+ &mdwc->resume_work, 12);
if (!init)
init = true;
diff --git a/drivers/usb/dwc3/dwc3_otg.c b/drivers/usb/dwc3/dwc3_otg.c
index 9599936..cacd635 100644
--- a/drivers/usb/dwc3/dwc3_otg.c
+++ b/drivers/usb/dwc3/dwc3_otg.c
@@ -93,6 +93,19 @@
return 0;
}
+static void dwc3_otg_set_hsphy_auto_suspend(struct dwc3_otg *dotg, bool susp)
+{
+ struct dwc3 *dwc = dotg->dwc;
+ u32 reg;
+
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+ if (susp)
+ reg |= DWC3_GUSB2PHYCFG_SUSPHY;
+ else
+ reg &= ~(DWC3_GUSB2PHYCFG_SUSPHY);
+ dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+}
+
/**
* dwc3_otg_set_host_power - Enable port power control for host operation
*
@@ -194,6 +207,7 @@
* remove_hcd, But we may not use standard set_host method
* anymore.
*/
+ dwc3_otg_set_hsphy_auto_suspend(dotg, true);
dwc3_otg_set_host_regs(dotg);
/*
* FIXME If micro A cable is disconnected during system suspend,
@@ -242,6 +256,7 @@
ext_xceiv->ext_block_reset)
ext_xceiv->ext_block_reset(ext_xceiv, true);
+ dwc3_otg_set_hsphy_auto_suspend(dotg, false);
dwc3_otg_set_peripheral_regs(dotg);
/* re-init core and OTG registers as block reset clears these */
@@ -309,12 +324,14 @@
ext_xceiv->ext_block_reset)
ext_xceiv->ext_block_reset(ext_xceiv, false);
+ dwc3_otg_set_hsphy_auto_suspend(dotg, true);
dwc3_otg_set_peripheral_regs(dotg);
usb_gadget_vbus_connect(otg->gadget);
} else {
dev_dbg(otg->phy->dev, "%s: turn off gadget %s\n",
__func__, otg->gadget->name);
usb_gadget_vbus_disconnect(otg->gadget);
+ dwc3_otg_set_hsphy_auto_suspend(dotg, false);
}
return 0;
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 38c4b86..7439c45 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -294,6 +294,15 @@
if (((dep->busy_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
usb_endpoint_xfer_isoc(dep->endpoint.desc))
dep->busy_slot++;
+
+ if (req->request.zero && req->ztrb) {
+ dep->busy_slot++;
+ req->ztrb = NULL;
+ if (((dep->busy_slot & DWC3_TRB_MASK) ==
+ DWC3_TRB_NUM - 1) &&
+ usb_endpoint_xfer_isoc(dep->endpoint.desc))
+ dep->busy_slot++;
+ }
}
list_del(&req->list);
req->trb = NULL;
@@ -864,6 +873,7 @@
req->trb_dma = dwc3_trb_dma_offset(dep, trb);
}
+update_trb:
trb->size = DWC3_TRB_SIZE_LENGTH(length);
trb->bpl = lower_32_bits(dma);
trb->bph = upper_32_bits(dma);
@@ -898,15 +908,31 @@
} else {
if (chain)
trb->ctrl |= DWC3_TRB_CTRL_CHN;
-
- if (last)
- trb->ctrl |= DWC3_TRB_CTRL_LST;
}
if (usb_endpoint_xfer_bulk(dep->endpoint.desc) && dep->stream_capable)
trb->ctrl |= DWC3_TRB_CTRL_SID_SOFN(req->request.stream_id);
trb->ctrl |= DWC3_TRB_CTRL_HWO;
+
+ if (req->request.zero && length &&
+ (length % usb_endpoint_maxp(dep->endpoint.desc) == 0)) {
+ trb = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
+ dep->free_slot++;
+
+ /* Skip the LINK-TRB on ISOC */
+ if (((dep->free_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
+ usb_endpoint_xfer_isoc(dep->endpoint.desc))
+ dep->free_slot++;
+
+ req->ztrb = trb;
+ length = 0;
+
+ goto update_trb;
+ }
+
+ if (!usb_endpoint_xfer_isoc(dep->endpoint.desc) && last)
+ trb->ctrl |= DWC3_TRB_CTRL_LST;
}
/*
@@ -1007,12 +1033,25 @@
}
dbg_queue(dep->number, &req->request, 0);
} else {
+ struct dwc3_request *req1;
+ int maxpkt_size = usb_endpoint_maxp(dep->endpoint.desc);
+
dma = req->request.dma;
length = req->request.length;
trbs_left--;
- if (!trbs_left)
+ if (req->request.zero && length &&
+ (length % maxpkt_size == 0))
+ trbs_left--;
+
+ if (!trbs_left) {
last_one = 1;
+ } else if (dep->direction && (trbs_left <= 1)) {
+ req1 = next_request(&req->list);
+ if (req1->request.zero && req1->request.length
+ && (req1->request.length % maxpkt_size == 0))
+ last_one = 1;
+ }
/* Is this the last request? */
if (list_is_last(&req->list, &dep->request_list))
@@ -2052,6 +2091,8 @@
s_pkt = 1;
}
+ if (req->ztrb)
+ trb = req->ztrb;
/*
* We assume here we will always receive the entire data block
* which we should receive. Meaning, if we program RX to
@@ -2623,13 +2664,10 @@
}
}
- /*
- * Notify suspend only to gadget driver, but not resume. Resume is
- * notified as part of wakeup event in dwc3_gadget_wakeup_interrupt().
- */
if (next == DWC3_LINK_STATE_U0) {
if (dwc->link_state == DWC3_LINK_STATE_U3) {
dbg_event(0xFF, "RESUME", 0);
+ dwc->gadget_driver->resume(&dwc->gadget);
}
} else if (next == DWC3_LINK_STATE_U3) {
dbg_event(0xFF, "SUSPEND", 0);
@@ -2920,7 +2958,11 @@
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
- dwc3_gadget_usb2_phy_suspend(dwc, true);
+ /*
+ * Clear autosuspend bit in dwc3 register for USB2. It will be
+ * enabled before setting run/stop bit.
+ */
+ dwc3_gadget_usb2_phy_suspend(dwc, false);
dwc3_gadget_usb3_phy_suspend(dwc, true);
}
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 6765078..877b944 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -1770,7 +1770,7 @@
struct fsg_common *common;
int err;
int i;
- const char *name[2];
+ const char *name[3];
config = kzalloc(sizeof(struct mass_storage_function_config),
GFP_KERNEL);
@@ -2181,6 +2181,22 @@
}
}
+static inline void check_streaming_func(struct usb_gadget *gadget,
+ struct android_usb_platform_data *pdata,
+ char *name)
+{
+ int i;
+
+ for (i = 0; i < pdata->streaming_func_count; i++) {
+ if (!strcmp(name,
+ pdata->streaming_func[i])) {
+ pr_debug("set streaming_enabled to true\n");
+ gadget->streaming_enabled = true;
+ break;
+ }
+ }
+}
+
static int android_enable_function(struct android_dev *dev,
struct android_configuration *conf,
char *name)
@@ -2188,6 +2204,9 @@
struct android_usb_function **functions = dev->functions;
struct android_usb_function *f;
struct android_usb_function_holder *f_holder;
+ struct android_usb_platform_data *pdata = dev->pdata;
+ struct usb_gadget *gadget = dev->cdev->gadget;
+
while ((f = *functions++)) {
if (!strcmp(name, f->name)) {
if (f->android_dev && f->android_dev != dev)
@@ -2205,6 +2224,13 @@
f_holder->f = f;
list_add_tail(&f_holder->enabled_list,
&conf->enabled_functions);
+ pr_debug("func:%s is enabled.\n", f->name);
+ /*
+ * compare enable function with streaming func
+ * list and based on the same request streaming.
+ */
+ check_streaming_func(gadget, pdata, f->name);
+
return 0;
}
}
@@ -2577,6 +2603,10 @@
{
struct android_dev *dev = cdev_to_android_dev(c->cdev);
+ if (c->cdev->gadget->streaming_enabled) {
+ c->cdev->gadget->streaming_enabled = false;
+ pr_debug("setting streaming_enabled to false.\n");
+ }
android_unbind_enabled_functions(dev, c);
}
@@ -2745,8 +2775,10 @@
unsigned long flags;
spin_lock_irqsave(&cdev->lock, flags);
- dev->suspended = 1;
- schedule_work(&dev->work);
+ if (!dev->suspended) {
+ dev->suspended = 1;
+ schedule_work(&dev->work);
+ }
spin_unlock_irqrestore(&cdev->lock, flags);
composite_suspend(gadget);
@@ -2759,8 +2791,10 @@
unsigned long flags;
spin_lock_irqsave(&cdev->lock, flags);
- dev->suspended = 0;
- schedule_work(&dev->work);
+ if (dev->suspended) {
+ dev->suspended = 0;
+ schedule_work(&dev->work);
+ }
spin_unlock_irqrestore(&cdev->lock, flags);
composite_resume(gadget);
@@ -2895,7 +2929,7 @@
struct android_usb_platform_data *pdata;
struct android_dev *android_dev;
struct resource *res;
- int ret = 0;
+ int ret = 0, i, len = 0;
if (pdev->dev.of_node) {
dev_dbg(&pdev->dev, "device tree enabled\n");
@@ -2912,6 +2946,33 @@
"qcom,android-usb-cdrom");
pdata->internal_ums = of_property_read_bool(pdev->dev.of_node,
"qcom,android-usb-internal-ums");
+ len = of_property_count_strings(pdev->dev.of_node,
+ "qcom,streaming-func");
+ if (len > MAX_STREAMING_FUNCS) {
+ pr_err("Invalid number of functions used.\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < len; i++) {
+ const char *name = NULL;
+
+ of_property_read_string_index(pdev->dev.of_node,
+ "qcom,streaming-func", i, &name);
+ if (!name)
+ continue;
+
+ if (sizeof(name) > FUNC_NAME_LEN) {
+ pr_err("Function name is bigger than allowed.\n");
+ continue;
+ }
+
+ strlcpy(pdata->streaming_func[i], name,
+ sizeof(pdata->streaming_func[i]));
+ pr_debug("name of streaming function:%s\n",
+ pdata->streaming_func[i]);
+ }
+
+ pdata->streaming_func_count = len;
} else {
pdata = pdev->dev.platform_data;
}
diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c
index a9c073b..f1e4220 100644
--- a/drivers/usb/gadget/ci13xxx_msm.c
+++ b/drivers/usb/gadget/ci13xxx_msm.c
@@ -271,6 +271,10 @@
1 << (pdata->log2_itc-1);
is_l1_supported = pdata->l1_supported;
+ /* Set ahb2ahb bypass flag if it is requested. */
+ if (pdata->enable_ahb2ahb_bypass)
+ ci13xxx_msm_udc_driver.flags |=
+ CI13XXX_ENABLE_AHB2AHB_BYPASS;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 3f8d924..6a92684 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -70,10 +70,6 @@
#include <mach/usb_trace.h>
#include "ci13xxx_udc.h"
-/* Turns on streaming. overrides CI13XXX_DISABLE_STREAMING */
-static unsigned int streaming;
-module_param(streaming, uint, S_IRUGO | S_IWUSR);
-
/******************************************************************************
* DEFINE
*****************************************************************************/
@@ -392,20 +388,32 @@
static int hw_device_state(u32 dma)
{
struct ci13xxx *udc = _udc;
+ struct usb_gadget *gadget = &udc->gadget;
if (dma) {
- if (streaming || !(udc->udc_driver->flags &
- CI13XXX_DISABLE_STREAMING))
+ if (gadget->streaming_enabled || !(udc->udc_driver->flags &
+ CI13XXX_DISABLE_STREAMING)) {
hw_cwrite(CAP_USBMODE, USBMODE_SDIS, 0);
- else
+ pr_debug("%s(): streaming mode is enabled. USBMODE:%x\n",
+ __func__, hw_cread(CAP_USBMODE, ~0));
+ } else {
hw_cwrite(CAP_USBMODE, USBMODE_SDIS, USBMODE_SDIS);
-
+ pr_debug("%s(): streaming mode is disabled. USBMODE:%x\n",
+ __func__, hw_cread(CAP_USBMODE, ~0));
+ }
hw_cwrite(CAP_ENDPTLISTADDR, ~0, dma);
if (udc->udc_driver->notify_event)
udc->udc_driver->notify_event(udc,
CI13XXX_CONTROLLER_CONNECT_EVENT);
+ /* Set BIT(31) to enable AHB2AHB Bypass functionality */
+ if (udc->udc_driver->flags & CI13XXX_ENABLE_AHB2AHB_BYPASS) {
+ hw_awrite(ABS_AHBMODE, AHB2AHB_BYPASS, AHB2AHB_BYPASS);
+ pr_debug("%s(): ByPass Mode is enabled. AHBMODE:%x\n",
+ __func__, hw_aread(ABS_AHBMODE, ~0));
+ }
+
/* interrupt, error, port change, reset, sleep/suspend */
hw_cwrite(CAP_USBINTR, ~0,
USBi_UI|USBi_UEI|USBi_PCI|USBi_URI|USBi_SLI);
@@ -413,6 +421,12 @@
} else {
hw_cwrite(CAP_USBCMD, USBCMD_RS, 0);
hw_cwrite(CAP_USBINTR, ~0, 0);
+ /* Clear BIT(31) to disable AHB2AHB Bypass functionality */
+ if (udc->udc_driver->flags & CI13XXX_ENABLE_AHB2AHB_BYPASS) {
+ hw_awrite(ABS_AHBMODE, AHB2AHB_BYPASS, 0);
+ pr_debug("%s(): ByPass Mode is disabled. AHBMODE:%x\n",
+ __func__, hw_aread(ABS_AHBMODE, ~0));
+ }
}
return 0;
}
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
index f90ea86..47fe138 100644
--- a/drivers/usb/gadget/ci13xxx_udc.h
+++ b/drivers/usb/gadget/ci13xxx_udc.h
@@ -136,6 +136,7 @@
#define CI13XXX_DISABLE_STREAMING BIT(3)
#define CI13XXX_ZERO_ITC BIT(4)
#define CI13XXX_IS_OTG BIT(5)
+#define CI13XXX_ENABLE_AHB2AHB_BYPASS BIT(6)
#define CI13XXX_CONTROLLER_RESET_EVENT 0
#define CI13XXX_CONTROLLER_CONNECT_EVENT 1
@@ -197,6 +198,9 @@
/* TESTMODE */
#define TESTMODE_FORCE BIT(0)
+/* AHB_MODE */
+#define AHB2AHB_BYPASS BIT(31)
+
/* USBCMD */
#define USBCMD_RS BIT(0)
#define USBCMD_RST BIT(1)
diff --git a/drivers/usb/gadget/f_mtp.c b/drivers/usb/gadget/f_mtp.c
index 6d7dd3d..88ebd80 100644
--- a/drivers/usb/gadget/f_mtp.c
+++ b/drivers/usb/gadget/f_mtp.c
@@ -899,7 +899,10 @@
dev->rx_done || dev->state != STATE_BUSY);
if (dev->state == STATE_CANCELED
|| dev->state == STATE_OFFLINE) {
- r = -ECANCELED;
+ if (dev->state == STATE_OFFLINE)
+ r = -EIO;
+ else
+ r = -ECANCELED;
if (!dev->rx_done)
usb_ep_dequeue(dev->ep_out, read_req);
break;
diff --git a/drivers/usb/gadget/f_qdss.c b/drivers/usb/gadget/f_qdss.c
index f649248..7e474f3 100644
--- a/drivers/usb/gadget/f_qdss.c
+++ b/drivers/usb/gadget/f_qdss.c
@@ -18,6 +18,7 @@
#include <linux/usb/usb_qdss.h>
#include <linux/usb/msm_hsusb.h>
+#include "gadget_chips.h"
#include "f_qdss.h"
#include "u_qdss.c"
@@ -395,7 +396,9 @@
goto fail;
}
}
- dwc3_tx_fifo_resize_request(qdss->data, true);
+
+ if (gadget_is_dwc3(gadget))
+ dwc3_tx_fifo_resize_request(qdss->data, true);
return 0;
fail:
@@ -408,12 +411,15 @@
static void qdss_unbind(struct usb_configuration *c, struct usb_function *f)
{
struct f_qdss *qdss = func_to_qdss(f);
+ struct usb_gadget *gadget = c->cdev->gadget;
pr_debug("qdss_unbind\n");
- dwc3_tx_fifo_resize_request(qdss->data, false);
+ if (gadget_is_dwc3(gadget))
+ dwc3_tx_fifo_resize_request(qdss->data, false);
+
clear_eps(f);
- clear_desc(c->cdev->gadget, f);
+ clear_desc(gadget, f);
}
static void qdss_eps_disable(struct usb_function *f)
@@ -605,7 +611,7 @@
spin_lock_irqsave(&d_lock, flags);
list_for_each_entry(ch, &usb_qdss_ch_list, list) {
- if (!strncmp(name, ch->name, sizeof(ch->name))) {
+ if (!strcmp(name, ch->name)) {
found = 1;
break;
}
@@ -767,7 +773,7 @@
spin_lock_irqsave(&d_lock, flags);
/* Check if we already have a channel with this name */
list_for_each_entry(ch, &usb_qdss_ch_list, list) {
- if (!strncmp(name, ch->name, sizeof(ch->name))) {
+ if (!strcmp(name, ch->name)) {
found = 1;
break;
}
@@ -824,7 +830,8 @@
ch->app_conn = 0;
spin_unlock_irqrestore(&d_lock, flags);
- msm_dwc3_restart_usb_session(gadget);
+ if (gadget_is_dwc3(gadget))
+ msm_dwc3_restart_usb_session(gadget);
}
EXPORT_SYMBOL(usb_qdss_close);
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
index 7903764..aee7b58 100644
--- a/drivers/usb/gadget/f_rndis.c
+++ b/drivers/usb/gadget/f_rndis.c
@@ -379,13 +379,35 @@
struct sk_buff *skb)
{
struct sk_buff *skb2;
+ struct rndis_packet_msg_type *header = NULL;
+ struct f_rndis *rndis = func_to_rndis(&port->func);
- skb2 = skb_realloc_headroom(skb, sizeof(struct rndis_packet_msg_type));
- if (skb2)
- rndis_add_hdr(skb2);
+ if (rndis->port.multi_pkt_xfer) {
+ if (port->header) {
+ header = port->header;
+ memset(header, 0, sizeof(*header));
+ header->MessageType = cpu_to_le32(REMOTE_NDIS_PACKET_MSG);
+ header->MessageLength = cpu_to_le32(skb->len +
+ sizeof(*header));
+ header->DataOffset = cpu_to_le32(36);
+ header->DataLength = cpu_to_le32(skb->len);
+ pr_debug("MessageLength:%d DataLength:%d\n",
+ header->MessageLength,
+ header->DataLength);
+ return skb;
+ } else {
+ pr_err("RNDIS header is NULL.\n");
+ return NULL;
+ }
+ } else {
+ skb2 = skb_realloc_headroom(skb,
+ sizeof(struct rndis_packet_msg_type));
+ if (skb2)
+ rndis_add_hdr(skb2);
- dev_kfree_skb_any(skb);
- return skb2;
+ dev_kfree_skb_any(skb);
+ return skb2;
+ }
}
static void rndis_response_available(void *_rndis)
diff --git a/drivers/usb/gadget/f_uac1.c b/drivers/usb/gadget/f_uac1.c
index e8c9667..883c5fa 100644
--- a/drivers/usb/gadget/f_uac1.c
+++ b/drivers/usb/gadget/f_uac1.c
@@ -1,7 +1,7 @@
/*
* f_audio.c -- USB Audio class function driver
*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
* Copyright (C) 2008 Bryan Wu <cooloney@kernel.org>
* Copyright (C) 2008 Analog Devices, Inc
*
@@ -438,8 +438,8 @@
{
if (audio_buf) {
kfree(audio_buf->buf);
- kfree(audio_buf);
audio_buf->buf = NULL;
+ kfree(audio_buf);
audio_buf = NULL;
}
}
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index 9e789c5..734619f 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -197,6 +197,7 @@
}
static void rx_complete(struct usb_ep *ep, struct usb_request *req);
+static void tx_complete(struct usb_ep *ep, struct usb_request *req);
static int
rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
@@ -256,7 +257,6 @@
req->buf = skb->data;
req->length = size;
- req->complete = rx_complete;
req->context = skb;
retval = usb_ep_queue(out, req, gfp_flags);
@@ -349,6 +349,7 @@
{
unsigned i;
struct usb_request *req;
+ bool usb_in;
if (!n)
return -ENOMEM;
@@ -359,10 +360,22 @@
if (i-- == 0)
goto extra;
}
+
+ if (ep->desc->bEndpointAddress & USB_DIR_IN)
+ usb_in = true;
+ else
+ usb_in = false;
+
while (i--) {
req = usb_ep_alloc_request(ep, GFP_ATOMIC);
if (!req)
return list_empty(list) ? -ENOMEM : 0;
+ /* update completion handler */
+ if (usb_in)
+ req->complete = tx_complete;
+ else
+ req->complete = rx_complete;
+
list_add(&req->list, list);
}
return 0;
@@ -479,7 +492,7 @@
static void tx_complete(struct usb_ep *ep, struct usb_request *req)
{
- struct sk_buff *skb = req->context;
+ struct sk_buff *skb;
struct eth_dev *dev;
struct net_device *net;
struct usb_request *new_req;
@@ -553,7 +566,6 @@
}
new_req->length = length;
- new_req->complete = tx_complete;
retval = usb_ep_queue(in, new_req, GFP_ATOMIC);
switch (retval) {
default:
@@ -585,6 +597,7 @@
spin_unlock(&dev->req_lock);
}
} else {
+ skb = req->context;
spin_unlock(&dev->req_lock);
dev_kfree_skb_any(skb);
}
@@ -613,7 +626,7 @@
list_for_each(act, &dev->tx_reqs) {
req = container_of(act, struct usb_request, list);
if (!req->buf)
- req->buf = kmalloc(dev->tx_req_bufsize,
+ req->buf = kzalloc(dev->tx_req_bufsize,
GFP_ATOMIC);
if (!req->buf)
goto free_buf;
@@ -626,6 +639,7 @@
list_for_each(act, &dev->tx_reqs) {
req = container_of(act, struct usb_request, list);
kfree(req->buf);
+ req->buf = NULL;
}
return -ENOMEM;
}
@@ -710,28 +724,37 @@
* or the hardware can't use skb buffers.
* or there's not enough space for extra headers we need
*/
+ spin_lock_irqsave(&dev->lock, flags);
if (dev->wrap) {
- unsigned long flags;
-
- spin_lock_irqsave(&dev->lock, flags);
if (dev->port_usb)
skb = dev->wrap(dev->port_usb, skb);
- spin_unlock_irqrestore(&dev->lock, flags);
- if (!skb)
+ if (!skb) {
+ spin_unlock_irqrestore(&dev->lock, flags);
goto drop;
+ }
}
- spin_lock_irqsave(&dev->req_lock, flags);
- dev->tx_skb_hold_count++;
- spin_unlock_irqrestore(&dev->req_lock, flags);
-
if (multi_pkt_xfer) {
+
+ pr_debug("req->length:%d header_len:%u\n"
+ "skb->len:%d skb->data_len:%d\n",
+ req->length, dev->header_len,
+ skb->len, skb->data_len);
+ /* Add RNDIS Header */
+ memcpy(req->buf + req->length, dev->port_usb->header,
+ dev->header_len);
+ /* Increment req length by header size */
+ req->length += dev->header_len;
+ spin_unlock_irqrestore(&dev->lock, flags);
+ /* Copy received IP data from SKB */
memcpy(req->buf + req->length, skb->data, skb->len);
- req->length = req->length + skb->len;
+ /* Increment req length by skb data length */
+ req->length += skb->len;
length = req->length;
dev_kfree_skb_any(skb);
spin_lock_irqsave(&dev->req_lock, flags);
+ dev->tx_skb_hold_count++;
if (dev->tx_skb_hold_count < dev->dl_max_pkts_per_xfer) {
if (dev->no_tx_req_used > TX_REQ_THRESHOLD) {
list_add(&req->list, &dev->tx_reqs);
@@ -741,19 +764,15 @@
}
dev->no_tx_req_used++;
- spin_unlock_irqrestore(&dev->req_lock, flags);
-
- spin_lock_irqsave(&dev->lock, flags);
dev->tx_skb_hold_count = 0;
- spin_unlock_irqrestore(&dev->lock, flags);
+ spin_unlock_irqrestore(&dev->req_lock, flags);
} else {
+ spin_unlock_irqrestore(&dev->lock, flags);
length = skb->len;
req->buf = skb->data;
req->context = skb;
}
- req->complete = tx_complete;
-
/* NCM requires no zlp if transfer is dwNtbInMaxSize */
if (dev->port_usb->is_fixed &&
length == dev->port_usb->fixed_in_len &&
@@ -806,7 +825,7 @@
spin_lock_irqsave(&dev->req_lock, flags);
if (list_empty(&dev->tx_reqs))
netif_start_queue(net);
- list_add(&req->list, &dev->tx_reqs);
+ list_add_tail(&req->list, &dev->tx_reqs);
spin_unlock_irqrestore(&dev->req_lock, flags);
}
success:
@@ -1085,6 +1104,14 @@
if (!dev)
return ERR_PTR(-EINVAL);
+ link->header = kzalloc(sizeof(struct rndis_packet_msg_type),
+ GFP_ATOMIC);
+ if (!link->header) {
+ pr_err("RNDIS header memory allocation failed.\n");
+ result = -ENOMEM;
+ goto fail;
+ }
+
link->in_ep->driver_data = dev;
result = usb_ep_enable(link->in_ep);
if (result != 0) {
@@ -1105,6 +1132,7 @@
result = alloc_requests(dev, link, qlen(dev->gadget));
if (result == 0) {
+
dev->zlp = link->is_zlp_ok;
DBG(dev, "qlen %d\n", qlen(dev->gadget));
@@ -1139,10 +1167,15 @@
fail1:
(void) usb_ep_disable(link->in_ep);
}
-fail0:
+
/* caller is responsible for cleanup on error */
- if (result < 0)
+ if (result < 0) {
+fail0:
+ kfree(link->header);
+fail:
return ERR_PTR(result);
+ }
+
return dev->net;
}
@@ -1184,11 +1217,16 @@
list_del(&req->list);
spin_unlock(&dev->req_lock);
- if (link->multi_pkt_xfer)
+ if (link->multi_pkt_xfer) {
kfree(req->buf);
+ req->buf = NULL;
+ }
usb_ep_free_request(link->in_ep, req);
spin_lock(&dev->req_lock);
}
+ /* Free rndis header buffer memory */
+ kfree(link->header);
+ link->header = NULL;
spin_unlock(&dev->req_lock);
link->in_ep->driver_data = NULL;
link->in_ep->desc = NULL;
diff --git a/drivers/usb/gadget/u_ether.h b/drivers/usb/gadget/u_ether.h
index 05984d8..2c5da77 100644
--- a/drivers/usb/gadget/u_ether.h
+++ b/drivers/usb/gadget/u_ether.h
@@ -66,6 +66,8 @@
/* called on network open/close */
void (*open)(struct gether *);
void (*close)(struct gether *);
+ struct rndis_packet_msg_type *header;
+
};
#define DEFAULT_FILTER (USB_CDC_PACKET_TYPE_BROADCAST \
diff --git a/drivers/usb/gadget/u_qdss.c b/drivers/usb/gadget/u_qdss.c
index e241e29..23d4d06 100644
--- a/drivers/usb/gadget/u_qdss.c
+++ b/drivers/usb/gadget/u_qdss.c
@@ -14,6 +14,7 @@
#include <linux/device.h>
#include <linux/usb/msm_hsusb.h>
#include <mach/usb_bam.h>
+#include "gadget_chips.h"
struct usb_qdss_bam_connect_info {
u32 usb_bam_pipe_idx;
@@ -88,8 +89,11 @@
&bam_info.usb_bam_pipe_idx, &bam_info.peer_pipe_idx,
NULL, bam_info.data_fifo);
- msm_data_fifo_config(data_ep, bam_info.data_fifo->phys_base,
- bam_info.data_fifo->size, bam_info.usb_bam_pipe_idx);
+ if (gadget_is_dwc3(gadget))
+ msm_data_fifo_config(data_ep,
+ bam_info.data_fifo->phys_base,
+ bam_info.data_fifo->size,
+ bam_info.usb_bam_pipe_idx);
} else {
kfree(bam_info.data_fifo);
res = usb_bam_disconnect_pipe(idx);
diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c
index 299f620c..95b6fbc7 100644
--- a/drivers/usb/gadget/u_serial.c
+++ b/drivers/usb/gadget/u_serial.c
@@ -689,18 +689,20 @@
}
static int gs_alloc_requests(struct usb_ep *ep, struct list_head *head,
- int num, int size, void (*fn)(struct usb_ep *, struct usb_request *),
+ int queue_size, int req_size,
+ void (*fn)(struct usb_ep *, struct usb_request *),
int *allocated)
{
int i;
struct usb_request *req;
+ int n = allocated ? queue_size - *allocated : queue_size;
/* Pre-allocate up to QUEUE_SIZE transfers, but if we can't
* do quite that many this time, don't fail ... we just won't
* be as speedy as we might otherwise be.
*/
- for (i = 0; i < num; i++) {
- req = gs_alloc_req(ep, size, GFP_ATOMIC);
+ for (i = 0; i < n; i++) {
+ req = gs_alloc_req(ep, req_size, GFP_ATOMIC);
if (!req)
return list_empty(head) ? -ENOMEM : 0;
req->complete = fn;
@@ -941,22 +943,6 @@
port->port_num, tty, file);
wake_up_interruptible(&port->close_wait);
-
- /*
- * Freeing the previously queued requests as they are
- * allocated again as a part of gs_open()
- */
- if (port->port_usb) {
- spin_unlock_irq(&port->port_lock);
- usb_ep_fifo_flush(gser->out);
- usb_ep_fifo_flush(gser->in);
- spin_lock_irq(&port->port_lock);
- gs_free_requests(gser->out, &port->read_queue, NULL);
- gs_free_requests(gser->out, &port->read_pool, NULL);
- gs_free_requests(gser->in, &port->write_pool, NULL);
- }
- port->read_allocated = port->read_started =
- port->write_allocated = port->write_started = 0;
exit:
spin_unlock_irq(&port->port_lock);
}
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 5d58f16..a89ac06 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -1,6 +1,6 @@
/* ehci-msm-hsic.c - HSUSB Host Controller Driver Implementation
*
- * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
*
* Partly derived from ehci-fsl.c and ehci-hcd.c
* Copyright (c) 2000-2004 by David Brownell
@@ -1486,7 +1486,7 @@
* generic hardware linkage
*/
.irq = msm_hsic_irq,
- .flags = HCD_USB2 | HCD_MEMORY | HCD_OLD_ENUM,
+ .flags = HCD_USB2 | HCD_MEMORY | HCD_RT_OLD_ENUM,
.reset = ehci_hsic_reset,
.start = ehci_run,
@@ -1947,7 +1947,6 @@
if (pdev->dev.of_node) {
dev_dbg(&pdev->dev, "device tree enabled\n");
pdev->dev.platform_data = msm_hsic_dt_to_pdata(pdev);
- dev_set_name(&pdev->dev, ehci_msm_hsic_driver.driver.name);
} else {
/* explicitly pass wakeup_irq flag for !DT */
wakeup_irq_flags = IRQF_TRIGGER_HIGH;
@@ -2264,6 +2263,9 @@
iounmap(hcd->regs);
usb_put_hcd(hcd);
+ if (pdev->dev.of_node)
+ pdev->dev.platform_data = NULL;
+
return 0;
}
diff --git a/drivers/usb/host/ehci-msm2.c b/drivers/usb/host/ehci-msm2.c
index dd04f49..7ae0a54 100644
--- a/drivers/usb/host/ehci-msm2.c
+++ b/drivers/usb/host/ehci-msm2.c
@@ -1063,7 +1063,7 @@
memset(kbuf, 0, 10);
- if (copy_from_user(kbuf, buf, count > 10 ? 10 : count))
+ if (copy_from_user(kbuf, buf, min_t(size_t, sizeof(kbuf) - 1, count)))
return -EFAULT;
if (sscanf(kbuf, "%x", &data) != 1)
@@ -1088,7 +1088,7 @@
memset(kbuf, 0, 10);
- if (copy_from_user(kbuf, buf, count > 10 ? 10 : count))
+ if (copy_from_user(kbuf, buf, min_t(size_t, sizeof(kbuf) - 1, count)))
return -EFAULT;
if (sscanf(kbuf, "%x", &temp) != 1)
diff --git a/drivers/usb/misc/diag_bridge.c b/drivers/usb/misc/diag_bridge.c
index 22e2a25..ccd48ca 100644
--- a/drivers/usb/misc/diag_bridge.c
+++ b/drivers/usb/misc/diag_bridge.c
@@ -464,12 +464,7 @@
pr_err("unable to allocate dev");
return -ENOMEM;
}
- dev->pdev = platform_device_alloc("diag_bridge", devid);
- if (!dev->pdev) {
- pr_err("unable to allocate platform device");
- kfree(dev);
- return -ENOMEM;
- }
+
__dev[devid] = dev;
dev->id = devid;
@@ -498,7 +493,13 @@
usb_set_intfdata(ifc, dev);
diag_bridge_debugfs_init();
- platform_device_add(dev->pdev);
+ dev->pdev = platform_device_register_simple("diag_bridge", devid,
+ NULL, 0);
+ if (IS_ERR(dev->pdev)) {
+ pr_err("unable to allocate platform device");
+ ret = PTR_ERR(dev->pdev);
+ goto error;
+ }
dev_dbg(&dev->ifc->dev, "%s: complete\n", __func__);
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 276bbb0..8287ad7 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -470,6 +470,20 @@
int ret;
struct msm_otg_platform_data *pdata = motg->pdata;
+ /*
+ * AHB2AHB Bypass mode shouldn't be enable before doing
+ * async clock reset. If it is enable, disable the same.
+ */
+ val = readl_relaxed(USB_AHBMODE);
+ if (val & AHB2AHB_BYPASS) {
+ pr_err("%s(): AHB2AHB_BYPASS SET: AHBMODE:%x\n",
+ __func__, val);
+ val &= ~AHB2AHB_BYPASS_BIT_MASK;
+ writel_relaxed(val | AHB2AHB_BYPASS_CLEAR, USB_AHBMODE);
+ pr_err("%s(): AHBMODE: %x\n", __func__,
+ readl_relaxed(USB_AHBMODE));
+ }
+
ret = msm_otg_link_clk_reset(motg, 1);
if (ret)
return ret;
@@ -615,6 +629,10 @@
pm8xxx_usb_id_pullup(1);
}
+ if (motg->caps & ALLOW_VDD_MIN_WITH_RETENTION_DISABLED)
+ writel_relaxed(readl_relaxed(USB_OTGSC) & ~(OTGSC_IDPU),
+ USB_OTGSC);
+
return 0;
}
@@ -875,6 +893,7 @@
u32 phy_ctrl_val = 0, cmd_val;
unsigned ret;
u32 portsc, config2;
+ u32 func_ctrl;
if (atomic_read(&motg->in_lpm))
return 0;
@@ -942,6 +961,15 @@
ulpi_write(phy, 0x08, 0x09);
}
+ if (motg->caps & ALLOW_VDD_MIN_WITH_RETENTION_DISABLED) {
+ /* put the controller in non-driving mode */
+ func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
+ func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
+ func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
+ ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
+ ulpi_write(phy, ULPI_IFC_CTRL_AUTORESUME,
+ ULPI_CLR(ULPI_IFC_CTRL));
+ }
/* Set the PHCD bit, only if it is not set by the controller.
* PHY may take some time or even fail to enter into low power
@@ -1007,8 +1035,13 @@
}
if (host_bus_suspend)
phy_ctrl_val |= PHY_CLAMP_DPDMSE_EN;
- writel_relaxed(phy_ctrl_val & ~PHY_RETEN, USB_PHY_CTRL);
- motg->lpm_flags |= PHY_RETENTIONED;
+
+ if (!(motg->caps & ALLOW_VDD_MIN_WITH_RETENTION_DISABLED)) {
+ writel_relaxed(phy_ctrl_val & ~PHY_RETEN, USB_PHY_CTRL);
+ motg->lpm_flags |= PHY_RETENTIONED;
+ } else {
+ writel_relaxed(phy_ctrl_val, USB_PHY_CTRL);
+ }
}
/* Ensure that above operation is completed before turning off clocks */
@@ -1049,7 +1082,8 @@
motg->lpm_flags |= PHY_REGULATORS_LPM;
}
- if (motg->lpm_flags & PHY_RETENTIONED) {
+ if (motg->lpm_flags & PHY_RETENTIONED ||
+ (motg->caps & ALLOW_VDD_MIN_WITH_RETENTION_DISABLED)) {
msm_hsusb_config_vddcx(0);
msm_hsusb_mhl_switch_enable(motg, 0);
}
@@ -1102,6 +1136,7 @@
unsigned temp;
u32 phy_ctrl_val = 0;
unsigned ret;
+ u32 func_ctrl;
if (!atomic_read(&motg->in_lpm))
return 0;
@@ -1145,7 +1180,8 @@
motg->lpm_flags &= ~PHY_REGULATORS_LPM;
}
- if (motg->lpm_flags & PHY_RETENTIONED) {
+ if (motg->lpm_flags & PHY_RETENTIONED ||
+ (motg->caps & ALLOW_VDD_MIN_WITH_RETENTION_DISABLED)) {
msm_hsusb_mhl_switch_enable(motg, 1);
msm_hsusb_config_vddcx(1);
phy_ctrl_val = readl_relaxed(USB_PHY_CTRL);
@@ -1191,6 +1227,14 @@
}
skip_phy_resume:
+ if (motg->caps & ALLOW_VDD_MIN_WITH_RETENTION_DISABLED) {
+ /* put the controller in normal mode */
+ func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
+ func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
+ func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
+ ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
+ }
+
if (device_may_wakeup(phy->dev)) {
if (motg->async_irq)
disable_irq_wake(motg->async_irq);
@@ -1275,7 +1319,8 @@
else if (motg->chg_type == USB_CDP_CHARGER)
charger_type = POWER_SUPPLY_TYPE_USB_CDP;
else if (motg->chg_type == USB_DCP_CHARGER ||
- motg->chg_type == USB_PROPRIETARY_CHARGER)
+ motg->chg_type == USB_PROPRIETARY_CHARGER ||
+ motg->chg_type == USB_FLOATED_CHARGER)
charger_type = POWER_SUPPLY_TYPE_USB_DCP;
else if ((motg->chg_type == USB_ACA_DOCK_CHARGER ||
motg->chg_type == USB_ACA_A_CHARGER ||
@@ -3834,6 +3879,8 @@
ci_pdata.log2_itc = otg_pdata->log2_itc;
ci_pdata.usb_core_id = 0;
ci_pdata.l1_supported = otg_pdata->l1_supported;
+ ci_pdata.enable_ahb2ahb_bypass =
+ otg_pdata->enable_ahb2ahb_bypass;
retval = platform_device_add_data(pdev, &ci_pdata,
sizeof(ci_pdata));
if (retval)
@@ -4164,6 +4211,10 @@
pdata->l1_supported = of_property_read_bool(node,
"qcom,hsusb-l1-supported");
+ pdata->enable_ahb2ahb_bypass = of_property_read_bool(node,
+ "qcom,ahb-async-bridge-bypass");
+ pdata->disable_retention_with_vdd_min = of_property_read_bool(node,
+ "qcom,disable-retention-with-vdd-min");
return pdata;
}
@@ -4549,6 +4600,9 @@
if (motg->pdata->enable_lpm_on_dev_suspend)
motg->caps |= ALLOW_LPM_ON_DEV_SUSPEND;
+ if (motg->pdata->disable_retention_with_vdd_min)
+ motg->caps |= ALLOW_VDD_MIN_WITH_RETENTION_DISABLED;
+
wake_lock(&motg->wlock);
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
diff --git a/drivers/video/fbcmap.c b/drivers/video/fbcmap.c
index 5c3960d..f26570d 100644
--- a/drivers/video/fbcmap.c
+++ b/drivers/video/fbcmap.c
@@ -166,6 +166,9 @@
int tooff = 0, fromoff = 0;
int size;
+ if (!to || !from)
+ return -EINVAL;
+
if (to->start > from->start)
fromoff = to->start - from->start;
else
@@ -177,9 +180,12 @@
return -EINVAL;
size *= sizeof(u16);
- memcpy(to->red+tooff, from->red+fromoff, size);
- memcpy(to->green+tooff, from->green+fromoff, size);
- memcpy(to->blue+tooff, from->blue+fromoff, size);
+ if (from->red && to->red)
+ memcpy(to->red+tooff, from->red+fromoff, size);
+ if (from->green && to->green)
+ memcpy(to->green+tooff, from->green+fromoff, size);
+ if (from->blue && to->blue)
+ memcpy(to->blue+tooff, from->blue+fromoff, size);
if (from->transp && to->transp)
memcpy(to->transp+tooff, from->transp+fromoff, size);
return 0;
@@ -190,23 +196,31 @@
int tooff = 0, fromoff = 0;
int size;
+ if (!to || !from)
+ return -EINVAL;
+
if (to->start > from->start)
fromoff = to->start - from->start;
else
tooff = from->start - to->start;
+ if ((to->len <= tooff) || (from->len <= fromoff))
+ return -EINVAL;
+
size = to->len - tooff;
+
if (size > (int) (from->len - fromoff))
size = from->len - fromoff;
- if (size <= 0)
- return -EINVAL;
size *= sizeof(u16);
- if (copy_to_user(to->red+tooff, from->red+fromoff, size))
- return -EFAULT;
- if (copy_to_user(to->green+tooff, from->green+fromoff, size))
- return -EFAULT;
- if (copy_to_user(to->blue+tooff, from->blue+fromoff, size))
- return -EFAULT;
+ if (from->red && to->red)
+ if (copy_to_user(to->red+tooff, from->red+fromoff, size))
+ return -EFAULT;
+ if (from->green && to->green)
+ if (copy_to_user(to->green+tooff, from->green+fromoff, size))
+ return -EFAULT;
+ if (from->blue && to->blue)
+ if (copy_to_user(to->blue+tooff, from->blue+fromoff, size))
+ return -EFAULT;
if (from->transp && to->transp)
if (copy_to_user(to->transp+tooff, from->transp+fromoff, size))
return -EFAULT;
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index d6a664a..6b84107 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -1113,6 +1113,10 @@
if (copy_from_user(&cmap, argp, sizeof(cmap)))
return -EFAULT;
ret = fb_set_user_cmap(&cmap, info);
+ if (ret) {
+ if (info)
+ fb_dealloc_cmap(&info->cmap);
+ }
break;
case FBIOGETCMAP:
if (copy_from_user(&cmap, argp, sizeof(cmap)))
diff --git a/drivers/video/msm/mdss/Kconfig b/drivers/video/msm/mdss/Kconfig
index 7682a49..01edf92 100644
--- a/drivers/video/msm/mdss/Kconfig
+++ b/drivers/video/msm/mdss/Kconfig
@@ -20,3 +20,18 @@
Support the HDMI to MHL conversion.
MHL (Mobile High-Definition Link) technology
uses USB connector to output HDMI content
+
+config FB_MSM_MDSS_DSI_CTRL_STATUS
+ tristate "DSI controller status check feature"
+ ---help---
+ Check DSI controller status periodically (default period is 5
+ seconds) by sending Bus-Turn-Around (BTA) command. If DSI controller
+ fails to acknowledge the BTA command, it sends PANEL_ALIVE=0 status
+ to HAL layer to reset the controller.
+
+config FB_MSM_MDSS_MDP3
+ depends on FB_MSM_MDSS
+ bool "MDP3 display controller"
+ ---help---
+ The MDP3 provides support for an older version display controller
+ included in latest display sub-system, known as MDSS.
diff --git a/drivers/video/msm/mdss/Makefile b/drivers/video/msm/mdss/Makefile
index ba14d67..fd03b63 100644
--- a/drivers/video/msm/mdss/Makefile
+++ b/drivers/video/msm/mdss/Makefile
@@ -1,6 +1,6 @@
mdss-mdp3-objs = mdp3.o mdp3_dma.o mdp3_ctrl.o
mdss-mdp3-objs += mdp3_ppp.o mdp3_ppp_hwio.o mdp3_ppp_data.o
-obj-$(CONFIG_FB_MSM_MDSS) += mdss-mdp3.o
+obj-$(CONFIG_FB_MSM_MDSS_MDP3) += mdss-mdp3.o
mdss-mdp-objs := mdss_mdp.o mdss_mdp_ctl.o mdss_mdp_pipe.o mdss_mdp_util.o
mdss-mdp-objs += mdss_mdp_pp.o
@@ -17,9 +17,9 @@
endif
dsi-v2-objs = dsi_v2.o dsi_host_v2.o dsi_io_v2.o
-obj-$(CONFIG_FB_MSM_MDSS) += dsi-v2.o
+obj-$(CONFIG_FB_MSM_MDSS_MDP3) += dsi-v2.o
-mdss-dsi-objs := mdss_dsi.o mdss_dsi_host.o
+mdss-dsi-objs := mdss_dsi.o mdss_dsi_host.o mdss_dsi_cmd.o
mdss-dsi-objs += mdss_dsi_panel.o
mdss-dsi-objs += msm_mdss_io_8974.o
obj-$(CONFIG_FB_MSM_MDSS) += mdss-dsi.o
@@ -41,3 +41,9 @@
obj-$(CONFIG_FB_MSM_QPIC_ILI_QVGA_PANEL) += qpic_panel_ili_qvga.o
obj-$(CONFIG_FB_MSM_MDSS) += mdss_fb.o
+
+ifeq ($(CONFIG_FB_MSM_MDSS_MDP3),y)
+obj-$(CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS) += dsi_status_v2.o
+else
+obj-$(CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS) += mdss_dsi_status.o
+endif
diff --git a/drivers/video/msm/mdss/dsi_host_v2.c b/drivers/video/msm/mdss/dsi_host_v2.c
index e416a55..53b6fc6 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.c
+++ b/drivers/video/msm/mdss/dsi_host_v2.c
@@ -31,21 +31,24 @@
#define DSI_POLL_TIMEOUT_US 16000
#define DSI_ESC_CLK_RATE 19200000
#define DSI_DMA_CMD_TIMEOUT_MS 200
+#define VSYNC_PERIOD 17
+#define DSI_MAX_PKT_SIZE 10
+#define DSI_SHORT_PKT_DATA_SIZE 2
+#define DSI_MAX_BYTES_TO_READ 16
struct dsi_host_v2_private {
- struct completion dma_comp;
- int irq_enabled;
- spinlock_t irq_lock;
-
int irq_no;
unsigned char *dsi_base;
size_t dsi_reg_size;
struct device dis_dev;
+ int clk_count;
+ int dsi_on;
void (*debug_enable_clk)(int on);
};
static struct dsi_host_v2_private *dsi_host_private;
+static int msm_dsi_clk_ctrl(struct mdss_panel_data *pdata, int enable);
int msm_dsi_init(void)
{
@@ -58,8 +61,6 @@
}
}
- init_completion(&dsi_host_private->dma_comp);
- spin_lock_init(&dsi_host_private->irq_lock);
return 0;
}
@@ -77,7 +78,10 @@
if (status) {
MIPI_OUTP(ctrl_base + DSI_ACK_ERR_STATUS, status);
- pr_debug("%s: status=%x\n", __func__, status);
+
+ /* Writing of an extra 0 needed to clear error bits */
+ MIPI_OUTP(ctrl_base + DSI_ACK_ERR_STATUS, 0);
+ pr_err("%s: status=%x\n", __func__, status);
}
}
@@ -88,7 +92,7 @@
status = MIPI_INP(ctrl_base + DSI_TIMEOUT_STATUS);
if (status & 0x0111) {
MIPI_OUTP(ctrl_base + DSI_TIMEOUT_STATUS, status);
- pr_debug("%s: status=%x\n", __func__, status);
+ pr_err("%s: status=%x\n", __func__, status);
}
}
@@ -100,7 +104,7 @@
if (status & 0x011111) {
MIPI_OUTP(ctrl_base + DSI_DLN0_PHY_ERR, status);
- pr_debug("%s: status=%x\n", __func__, status);
+ pr_err("%s: status=%x\n", __func__, status);
}
}
@@ -112,7 +116,7 @@
if (status & 0x44444489) {
MIPI_OUTP(ctrl_base + DSI_FIFO_STATUS, status);
- pr_debug("%s: status=%x\n", __func__, status);
+ pr_err("%s: status=%x\n", __func__, status);
}
}
@@ -124,7 +128,7 @@
if (status & 0x80000000) {
MIPI_OUTP(ctrl_base + DSI_STATUS, status);
- pr_debug("%s: status=%x\n", __func__, status);
+ pr_err("%s: status=%x\n", __func__, status);
}
}
@@ -137,61 +141,104 @@
msm_dsi_dln0_phy_err(ctrl_base);
}
-void msm_dsi_enable_irq(void)
+static void msm_dsi_set_irq_mask(struct mdss_dsi_ctrl_pdata *ctrl, u32 mask)
+{
+ u32 intr_ctrl;
+ intr_ctrl = MIPI_INP(dsi_host_private->dsi_base + DSI_INT_CTRL);
+ intr_ctrl |= mask;
+ MIPI_OUTP(dsi_host_private->dsi_base + DSI_INT_CTRL, intr_ctrl);
+}
+
+static void msm_dsi_clear_irq_mask(struct mdss_dsi_ctrl_pdata *ctrl, u32 mask)
+{
+ u32 intr_ctrl;
+ intr_ctrl = MIPI_INP(dsi_host_private->dsi_base + DSI_INT_CTRL);
+ intr_ctrl &= ~mask;
+ MIPI_OUTP(dsi_host_private->dsi_base + DSI_INT_CTRL, intr_ctrl);
+}
+
+static void msm_dsi_set_irq(struct mdss_dsi_ctrl_pdata *ctrl, u32 mask)
{
unsigned long flags;
- spin_lock_irqsave(&dsi_host_private->irq_lock, flags);
- dsi_host_private->irq_enabled++;
- if (dsi_host_private->irq_enabled == 1)
+ spin_lock_irqsave(&ctrl->irq_lock, flags);
+ if (ctrl->dsi_irq_mask & mask) {
+ spin_unlock_irqrestore(&ctrl->irq_lock, flags);
+ return;
+ }
+ if (ctrl->dsi_irq_mask == 0) {
enable_irq(dsi_host_private->irq_no);
+ pr_debug("%s: IRQ Enable, mask=%x term=%x\n", __func__,
+ (int)ctrl->dsi_irq_mask, (int)mask);
+ }
- spin_unlock_irqrestore(&dsi_host_private->irq_lock, flags);
+ msm_dsi_set_irq_mask(ctrl, mask);
+ ctrl->dsi_irq_mask |= mask;
+ spin_unlock_irqrestore(&ctrl->irq_lock, flags);
}
-void msm_dsi_disable_irq(void)
+static void msm_dsi_clear_irq(struct mdss_dsi_ctrl_pdata *ctrl, u32 mask)
{
unsigned long flags;
- spin_lock_irqsave(&dsi_host_private->irq_lock, flags);
- dsi_host_private->irq_enabled--;
- if (dsi_host_private->irq_enabled == 0)
+ spin_lock_irqsave(&ctrl->irq_lock, flags);
+ if (!(ctrl->dsi_irq_mask & mask)) {
+ spin_unlock_irqrestore(&ctrl->irq_lock, flags);
+ return;
+ }
+ ctrl->dsi_irq_mask &= ~mask;
+ if (ctrl->dsi_irq_mask == 0) {
disable_irq(dsi_host_private->irq_no);
-
- spin_unlock_irqrestore(&dsi_host_private->irq_lock, flags);
+ pr_debug("%s: IRQ Disable, mask=%x term=%x\n", __func__,
+ (int)ctrl->dsi_irq_mask, (int)mask);
+ }
+ msm_dsi_clear_irq_mask(ctrl, mask);
+ spin_unlock_irqrestore(&ctrl->irq_lock, flags);
}
-void msm_dsi_disable_irq_nosync(void)
-{
- spin_lock(&dsi_host_private->irq_lock);
- dsi_host_private->irq_enabled--;
- if (dsi_host_private->irq_enabled == 0)
- disable_irq_nosync(dsi_host_private->irq_no);
- spin_unlock(&dsi_host_private->irq_lock);
-}
-
-irqreturn_t msm_dsi_isr(int irq, void *ptr)
+irqreturn_t msm_dsi_isr_handler(int irq, void *ptr)
{
u32 isr;
+ struct mdss_dsi_ctrl_pdata *ctrl =
+ (struct mdss_dsi_ctrl_pdata *)ptr;
+
isr = MIPI_INP(dsi_host_private->dsi_base + DSI_INT_CTRL);
MIPI_OUTP(dsi_host_private->dsi_base + DSI_INT_CTRL, isr);
- if (isr & DSI_INTR_ERROR)
+ pr_debug("%s: isr=%x", __func__, isr);
+
+ if (isr & DSI_INTR_ERROR) {
+ pr_err("%s: isr=%x %x", __func__, isr, (int)DSI_INTR_ERROR);
msm_dsi_error(dsi_host_private->dsi_base);
+ }
+
+ spin_lock(&ctrl->mdp_lock);
+
+ if (isr & DSI_INTR_VIDEO_DONE)
+ complete(&ctrl->video_comp);
if (isr & DSI_INTR_CMD_DMA_DONE)
- complete(&dsi_host_private->dma_comp);
+ complete(&ctrl->dma_comp);
+
+ spin_unlock(&ctrl->mdp_lock);
+
+ if (isr & DSI_INTR_BTA_DONE)
+ complete(&ctrl->bta_comp);
+
+ if (isr & DSI_INTR_CMD_MDP_DONE)
+ complete(&ctrl->mdp_comp);
return IRQ_HANDLED;
}
-int msm_dsi_irq_init(struct device *dev, int irq_no)
+int msm_dsi_irq_init(struct device *dev, int irq_no,
+ struct mdss_dsi_ctrl_pdata *ctrl)
{
int ret;
- ret = devm_request_irq(dev, irq_no, msm_dsi_isr,
- IRQF_DISABLED, "DSI", NULL);
+ ret = devm_request_irq(dev, irq_no, msm_dsi_isr_handler,
+ IRQF_DISABLED, "DSI", ctrl);
if (ret) {
pr_err("msm_dsi_irq_init request_irq() failed!\n");
return ret;
@@ -201,9 +248,119 @@
return 0;
}
+static void msm_dsi_get_cmd_engine(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ unsigned char *ctrl_base = dsi_host_private->dsi_base;
+ u32 dsi_ctrl;
+
+ if (ctrl->panel_mode == DSI_VIDEO_MODE) {
+ dsi_ctrl = MIPI_INP(ctrl_base + DSI_CTRL);
+ MIPI_OUTP(ctrl_base + DSI_CTRL, dsi_ctrl | 0x04);
+ }
+}
+
+static void msm_dsi_release_cmd_engine(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ unsigned char *ctrl_base = dsi_host_private->dsi_base;
+ u32 dsi_ctrl;
+ if (ctrl->panel_mode == DSI_VIDEO_MODE) {
+ dsi_ctrl = MIPI_INP(ctrl_base + DSI_CTRL);
+ dsi_ctrl &= ~0x04;
+ MIPI_OUTP(ctrl_base + DSI_CTRL, dsi_ctrl);
+ }
+}
+
+static int msm_dsi_wait4mdp_done(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ int rc;
+ unsigned long flag;
+
+ spin_lock_irqsave(&ctrl->mdp_lock, flag);
+ INIT_COMPLETION(ctrl->mdp_comp);
+ msm_dsi_set_irq(ctrl, DSI_INTR_CMD_MDP_DONE_MASK);
+ spin_unlock_irqrestore(&ctrl->mdp_lock, flag);
+
+ rc = wait_for_completion_timeout(&ctrl->mdp_comp,
+ msecs_to_jiffies(VSYNC_PERIOD * 4));
+
+ if (rc == 0) {
+ pr_err("DSI wait 4 mdp done time out\n");
+ rc = -ETIME;
+ } else if (!IS_ERR_VALUE(rc)) {
+ rc = 0;
+ }
+
+ msm_dsi_clear_irq(ctrl, DSI_INTR_CMD_MDP_DONE_MASK);
+
+ return rc;
+}
+
+void msm_dsi_cmd_mdp_busy(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ int rc;
+ u32 dsi_status;
+ unsigned char *ctrl_base = dsi_host_private->dsi_base;
+
+ if (ctrl->panel_mode == DSI_VIDEO_MODE)
+ return;
+
+ dsi_status = MIPI_INP(ctrl_base + DSI_STATUS);
+ if (dsi_status & 0x04) {
+ pr_debug("dsi command engine is busy\n");
+ rc = msm_dsi_wait4mdp_done(ctrl);
+ if (rc)
+ pr_err("Timed out waiting for mdp done");
+ }
+}
+
+static int msm_dsi_wait4video_done(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ int rc;
+ unsigned long flag;
+
+ spin_lock_irqsave(&ctrl->mdp_lock, flag);
+ INIT_COMPLETION(ctrl->video_comp);
+ msm_dsi_set_irq(ctrl, DSI_INTR_VIDEO_DONE_MASK);
+ spin_unlock_irqrestore(&ctrl->mdp_lock, flag);
+
+ rc = wait_for_completion_timeout(&ctrl->video_comp,
+ msecs_to_jiffies(VSYNC_PERIOD * 4));
+
+ if (rc == 0) {
+ pr_err("DSI wait 4 video done time out\n");
+ rc = -ETIME;
+ } else if (!IS_ERR_VALUE(rc)) {
+ rc = 0;
+ }
+
+ msm_dsi_clear_irq(ctrl, DSI_INTR_VIDEO_DONE_MASK);
+
+ return rc;
+}
+
+static int msm_dsi_wait4video_eng_busy(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ int rc = 0;
+ u32 dsi_status;
+ unsigned char *ctrl_base = dsi_host_private->dsi_base;
+
+ if (ctrl->panel_mode == DSI_CMD_MODE)
+ return rc;
+
+ dsi_status = MIPI_INP(ctrl_base + DSI_STATUS);
+ if (dsi_status & 0x08) {
+ pr_debug("dsi command in video mode wait for active region\n");
+ rc = msm_dsi_wait4video_done(ctrl);
+ /* delay 4-5 ms to skip BLLP */
+ if (!rc)
+ usleep_range(4000, 5000);
+ }
+ return rc;
+}
+
void msm_dsi_host_init(struct mipi_panel_info *pinfo)
{
- u32 dsi_ctrl, intr_ctrl, data;
+ u32 dsi_ctrl, data;
unsigned char *ctrl_base = dsi_host_private->dsi_base;
pr_debug("msm_dsi_host_init\n");
@@ -262,8 +419,6 @@
pr_err("%s: Unknown DSI mode=%d\n", __func__, pinfo->mode);
dsi_ctrl = BIT(8) | BIT(2); /* clock enable & cmd mode */
- intr_ctrl = 0;
- intr_ctrl = (DSI_INTR_CMD_DMA_DONE_MASK | DSI_INTR_CMD_MDP_DONE_MASK);
if (pinfo->crc_check)
dsi_ctrl |= BIT(24);
@@ -312,9 +467,6 @@
/* DSI_ERR_INT_MASK0 */
MIPI_OUTP(ctrl_base + DSI_ERR_INT_MASK0, 0x13ff3fe0);
- intr_ctrl |= DSI_INTR_ERROR_MASK;
- MIPI_OUTP(ctrl_base + DSI_INT_CTRL, intr_ctrl);
-
/* turn esc, byte, dsi, pclk, sclk, hclk on */
MIPI_OUTP(ctrl_base + DSI_CLK_CTRL, 0x23f);
@@ -404,7 +556,7 @@
void msm_dsi_op_mode_config(int mode, struct mdss_panel_data *pdata)
{
- u32 dsi_ctrl, intr_ctrl;
+ u32 dsi_ctrl;
unsigned char *ctrl_base = dsi_host_private->dsi_base;
pr_debug("msm_dsi_op_mode_config\n");
@@ -415,46 +567,24 @@
dsi_ctrl &= ~0x06;
- if (mode == DSI_VIDEO_MODE) {
+ if (mode == DSI_VIDEO_MODE)
dsi_ctrl |= 0x02;
- intr_ctrl = DSI_INTR_CMD_DMA_DONE_MASK;
- } else { /* command mode */
+ else
dsi_ctrl |= 0x04;
- intr_ctrl = DSI_INTR_CMD_DMA_DONE_MASK | DSI_INTR_ERROR_MASK |
- DSI_INTR_CMD_MDP_DONE_MASK;
- }
+ pr_debug("%s: dsi_ctrl=%x\n", __func__, dsi_ctrl);
- pr_debug("%s: dsi_ctrl=%x intr=%x\n", __func__, dsi_ctrl, intr_ctrl);
-
- MIPI_OUTP(ctrl_base + DSI_INT_CTRL, intr_ctrl);
MIPI_OUTP(ctrl_base + DSI_CTRL, dsi_ctrl);
wmb();
}
-int msm_dsi_cmd_reg_tx(u32 data)
-{
- unsigned char *ctrl_base = dsi_host_private->dsi_base;
-
- MIPI_OUTP(ctrl_base + DSI_TRIG_CTRL, 0x04);/* sw trigger */
- MIPI_OUTP(ctrl_base + DSI_CTRL, 0x135);
- wmb();
-
- MIPI_OUTP(ctrl_base + DSI_COMMAND_MODE_DMA_CTRL, data);
- wmb();
- MIPI_OUTP(ctrl_base + DSI_CMD_MODE_DMA_SW_TRIGGER, 0x01);
- wmb();
-
- udelay(300); /*per spec*/
-
- return 0;
-}
-
-int msm_dsi_cmd_dma_tx(struct dsi_buf *tp)
+int msm_dsi_cmd_dma_tx(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct dsi_buf *tp)
{
int len, rc;
unsigned long size, addr;
unsigned char *ctrl_base = dsi_host_private->dsi_base;
+ unsigned long flag;
len = ALIGN(tp->len, 4);
size = ALIGN(tp->len, SZ_4K);
@@ -468,7 +598,12 @@
addr = tp->dmap;
- INIT_COMPLETION(dsi_host_private->dma_comp);
+ msm_dsi_get_cmd_engine(ctrl);
+
+ spin_lock_irqsave(&ctrl->mdp_lock, flag);
+ INIT_COMPLETION(ctrl->dma_comp);
+ msm_dsi_set_irq(ctrl, DSI_INTR_CMD_DMA_DONE_MASK);
+ spin_unlock_irqrestore(&ctrl->mdp_lock, flag);
MIPI_OUTP(ctrl_base + DSI_DMA_CMD_OFFSET, addr);
MIPI_OUTP(ctrl_base + DSI_DMA_CMD_LENGTH, len);
@@ -477,7 +612,7 @@
MIPI_OUTP(ctrl_base + DSI_CMD_MODE_DMA_SW_TRIGGER, 0x01);
wmb();
- rc = wait_for_completion_timeout(&dsi_host_private->dma_comp,
+ rc = wait_for_completion_timeout(&ctrl->dma_comp,
msecs_to_jiffies(DSI_DMA_CMD_TIMEOUT_MS));
if (rc == 0) {
pr_err("DSI command transaction time out\n");
@@ -489,10 +624,16 @@
dma_unmap_single(&dsi_host_private->dis_dev, tp->dmap, size,
DMA_TO_DEVICE);
tp->dmap = 0;
+
+ msm_dsi_clear_irq(ctrl, DSI_INTR_CMD_DMA_DONE_MASK);
+
+ msm_dsi_release_cmd_engine(ctrl);
+
return rc;
}
-int msm_dsi_cmd_dma_rx(struct dsi_buf *rp, int rlen)
+int msm_dsi_cmd_dma_rx(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct dsi_buf *rp, int rlen)
{
u32 *lp, data;
int i, off, cnt;
@@ -518,202 +659,321 @@
rp->len += sizeof(*lp);
}
- return 0;
+ return rlen;
}
-int msm_dsi_cmds_tx(struct mdss_panel_data *pdata,
- struct dsi_buf *tp, struct dsi_cmd_desc *cmds, int cnt)
+static int msm_dsi_cmds_tx(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct dsi_cmd_desc *cmds, int cnt)
{
+ struct dsi_buf *tp;
struct dsi_cmd_desc *cm;
- u32 dsi_ctrl, ctrl;
- int i, video_mode, rc = 0;
- unsigned char *ctrl_base = dsi_host_private->dsi_base;
+ struct dsi_ctrl_hdr *dchdr;
+ int len;
+ int rc = 0;
- /* turn on cmd mode
- * for video mode, do not send cmds more than
- * one pixel line, since it only transmit it
- * during BLLP.
- */
- dsi_ctrl = MIPI_INP(ctrl_base + DSI_CTRL);
- video_mode = dsi_ctrl & 0x02; /* VIDEO_MODE_EN */
- if (video_mode) {
- ctrl = dsi_ctrl | 0x04; /* CMD_MODE_EN */
- MIPI_OUTP(ctrl_base + DSI_CTRL, ctrl);
- }
- msm_dsi_enable_irq();
-
+ tp = &ctrl->tx_buf;
+ mdss_dsi_buf_init(tp);
cm = cmds;
- for (i = 0; i < cnt; i++) {
- dsi_buf_init(tp);
- dsi_cmd_dma_add(tp, cm);
- rc = msm_dsi_cmd_dma_tx(tp);
- if (IS_ERR_VALUE(rc)) {
- pr_err("%s: failed to call cmd_dma_tx\n", __func__);
- break;
+ len = 0;
+ while (cnt--) {
+ dchdr = &cm->dchdr;
+ mdss_dsi_buf_reserve(tp, len);
+ len = mdss_dsi_cmd_dma_add(tp, cm);
+ if (!len) {
+ pr_err("%s: failed to add cmd = 0x%x\n",
+ __func__, cm->payload[0]);
+ rc = -EINVAL;
+ goto dsi_cmds_tx_err;
}
- if (cm->dchdr.wait)
- msleep(cm->dchdr.wait);
+
+ if (dchdr->last) {
+ tp->data = tp->start; /* begin of buf */
+ rc = msm_dsi_wait4video_eng_busy(ctrl);
+ if (rc) {
+ pr_err("%s: wait4video_eng failed\n", __func__);
+ goto dsi_cmds_tx_err;
+
+ }
+
+ rc = msm_dsi_cmd_dma_tx(ctrl, tp);
+ if (IS_ERR_VALUE(len)) {
+ pr_err("%s: failed to call cmd_dma_tx for cmd = 0x%x\n",
+ __func__, cmds->payload[0]);
+ goto dsi_cmds_tx_err;
+ }
+
+ if (dchdr->wait)
+ usleep(dchdr->wait * 1000);
+
+ mdss_dsi_buf_init(tp);
+ len = 0;
+ }
cm++;
}
- msm_dsi_disable_irq();
-
- if (video_mode)
- MIPI_OUTP(ctrl_base + DSI_CTRL, dsi_ctrl);
+dsi_cmds_tx_err:
return rc;
}
-/* MDSS_DSI_MRPS, Maximum Return Packet Size */
-static char max_pktsize[2] = {0x00, 0x00}; /* LSB tx first, 10 bytes */
-
-static struct dsi_cmd_desc pkt_size_cmd[] = {
- {{DTYPE_MAX_PKTSIZE, 1, 0, 0, 0,
- sizeof(max_pktsize)}, max_pktsize}
-};
-
-/*
- * DSI panel reply with MAX_RETURN_PACKET_SIZE bytes of data
- * plus DCS header, ECC and CRC for DCS long read response
- * mdss_dsi_controller only have 4x32 bits register ( 16 bytes) to
- * hold data per transaction.
- * MDSS_DSI_LEN equal to 8
- * len should be either 4 or 8
- * any return data more than MDSS_DSI_LEN need to be break down
- * to multiple transactions.
- *
- * ov_mutex need to be acquired before call this function.
- */
-int msm_dsi_cmds_rx(struct mdss_panel_data *pdata,
- struct dsi_buf *tp, struct dsi_buf *rp,
- struct dsi_cmd_desc *cmds, int rlen)
+static int msm_dsi_parse_rx_response(struct dsi_buf *rp)
{
- int cnt, len, diff, pkt_size, rc = 0;
- char cmd;
- unsigned char *ctrl_base = dsi_host_private->dsi_base;
- u32 dsi_ctrl, data;
- int video_mode;
-
- /* turn on cmd mode for video mode */
- dsi_ctrl = MIPI_INP(ctrl_base + DSI_CTRL);
- video_mode = dsi_ctrl & 0x02; /* VIDEO_MODE_EN */
- if (video_mode) {
- data = dsi_ctrl | 0x04; /* CMD_MODE_EN */
- MIPI_OUTP(ctrl_base + DSI_CTRL, data);
- }
-
- if (pdata->panel_info.mipi.no_max_pkt_size)
- rlen = ALIGN(rlen, 4); /* Only support rlen = 4*n */
-
- len = rlen;
- diff = 0;
-
- if (len <= 2) {
- cnt = 4; /* short read */
- } else {
- if (len > MDSS_DSI_LEN)
- len = MDSS_DSI_LEN; /* 8 bytes at most */
-
- len = ALIGN(len, 4); /* len 4 bytes align */
- diff = len - rlen;
- /*
- * add extra 2 bytes to len to have overall
- * packet size is multipe by 4. This also make
- * sure 4 bytes dcs headerlocates within a
- * 32 bits register after shift in.
- * after all, len should be either 6 or 10.
- */
- len += 2;
- cnt = len + 6; /* 4 bytes header + 2 bytes crc */
- }
-
- msm_dsi_enable_irq();
-
- if (!pdata->panel_info.mipi.no_max_pkt_size) {
- /* packet size need to be set at every read */
- pkt_size = len;
- max_pktsize[0] = pkt_size;
- dsi_buf_init(tp);
- dsi_cmd_dma_add(tp, pkt_size_cmd);
- rc = msm_dsi_cmd_dma_tx(tp);
- if (IS_ERR_VALUE(rc)) {
- msm_dsi_disable_irq();
- pr_err("%s: dma_tx failed\n", __func__);
- rp->len = 0;
- goto end;
- }
- pr_debug("%s: Max packet size sent\n", __func__);
- }
-
- dsi_buf_init(tp);
- dsi_cmd_dma_add(tp, cmds);
-
- /* transmit read comamnd to client */
- msm_dsi_cmd_dma_tx(tp);
- if (IS_ERR_VALUE(rc)) {
- msm_dsi_disable_irq();
- pr_err("%s: dma_tx failed\n", __func__);
- rp->len = 0;
- goto end;
- }
- /*
- * once cmd_dma_done interrupt received,
- * return data from client is ready and stored
- * at RDBK_DATA register already
- */
- dsi_buf_init(rp);
- if (pdata->panel_info.mipi.no_max_pkt_size) {
- /*
- * expect rlen = n * 4
- * short alignement for start addr
- */
- rp->data += 2;
- }
-
- msm_dsi_cmd_dma_rx(rp, cnt);
-
- msm_dsi_disable_irq();
-
- if (pdata->panel_info.mipi.no_max_pkt_size) {
- /*
- * remove extra 2 bytes from previous
- * rx transaction at shift register
- * which was inserted during copy
- * shift registers to rx buffer
- * rx payload start from long alignment addr
- */
- rp->data += 2;
- }
+ int rc = 0;
+ unsigned char cmd;
cmd = rp->data[0];
switch (cmd) {
case DTYPE_ACK_ERR_RESP:
pr_debug("%s: rx ACK_ERR_PACLAGE\n", __func__);
+ rc = -EINVAL;
break;
case DTYPE_GEN_READ1_RESP:
case DTYPE_DCS_READ1_RESP:
- dsi_short_read1_resp(rp);
+ mdss_dsi_short_read1_resp(rp);
break;
case DTYPE_GEN_READ2_RESP:
case DTYPE_DCS_READ2_RESP:
- dsi_short_read2_resp(rp);
+ mdss_dsi_short_read2_resp(rp);
break;
case DTYPE_GEN_LREAD_RESP:
case DTYPE_DCS_LREAD_RESP:
- dsi_long_read_resp(rp);
- rp->len -= 2; /* extra 2 bytes added */
- rp->len -= diff; /* align bytes */
+ mdss_dsi_long_read_resp(rp);
break;
default:
- pr_debug("%s: Unknown cmd received\n", __func__);
+ rc = -EINVAL;
+ pr_warn("%s: Unknown cmd received\n", __func__);
break;
}
- if (video_mode)
- MIPI_OUTP(ctrl_base + DSI_CTRL,
- dsi_ctrl); /* restore */
-end:
- return rp->len;
+ return rc;
+}
+
+/* MIPI_DSI_MRPS, Maximum Return Packet Size */
+static char max_pktsize[2] = {0x00, 0x00}; /* LSB tx first, 10 bytes */
+
+static struct dsi_cmd_desc pkt_size_cmd = {
+ {DTYPE_MAX_PKTSIZE, 1, 0, 0, 0, sizeof(max_pktsize)},
+ max_pktsize,
+};
+
+static int msm_dsi_set_max_packet_size(struct mdss_dsi_ctrl_pdata *ctrl,
+ int size)
+{
+ struct dsi_buf *tp;
+ int rc;
+
+ tp = &ctrl->tx_buf;
+ mdss_dsi_buf_init(tp);
+ max_pktsize[0] = size;
+
+ rc = mdss_dsi_cmd_dma_add(tp, &pkt_size_cmd);
+ if (!rc) {
+ pr_err("%s: failed to add max_pkt_size\n", __func__);
+ return -EINVAL;
+ }
+
+ rc = msm_dsi_wait4video_eng_busy(ctrl);
+ if (rc) {
+ pr_err("%s: failed to wait4video_eng\n", __func__);
+ return rc;
+ }
+
+ rc = msm_dsi_cmd_dma_tx(ctrl, tp);
+ if (IS_ERR_VALUE(rc)) {
+ pr_err("%s: failed to tx max_pkt_size\n", __func__);
+ return rc;
+ }
+ pr_debug("%s: max_pkt_size=%d sent\n", __func__, size);
+ return rc;
+}
+
+/* read data length is less than or equal to 10 bytes*/
+static int msm_dsi_cmds_rx_1(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct dsi_cmd_desc *cmds, int rlen)
+{
+ int rc;
+ struct dsi_buf *tp, *rp;
+
+ tp = &ctrl->tx_buf;
+ rp = &ctrl->rx_buf;
+ mdss_dsi_buf_init(rp);
+ mdss_dsi_buf_init(tp);
+
+ rc = mdss_dsi_cmd_dma_add(tp, cmds);
+ if (!rc) {
+ pr_err("%s: dsi_cmd_dma_add failed\n", __func__);
+ rc = -EINVAL;
+ goto dsi_cmds_rx_1_error;
+ }
+
+ rc = msm_dsi_wait4video_eng_busy(ctrl);
+ if (rc) {
+ pr_err("%s: wait4video_eng failed\n", __func__);
+ goto dsi_cmds_rx_1_error;
+ }
+
+ rc = msm_dsi_cmd_dma_tx(ctrl, tp);
+ if (IS_ERR_VALUE(rc)) {
+ pr_err("%s: msm_dsi_cmd_dma_tx failed\n", __func__);
+ goto dsi_cmds_rx_1_error;
+ }
+
+ if (rlen <= DSI_SHORT_PKT_DATA_SIZE) {
+ msm_dsi_cmd_dma_rx(ctrl, rp, rlen);
+ } else {
+ msm_dsi_cmd_dma_rx(ctrl, rp, rlen + DSI_HOST_HDR_SIZE);
+ rp->len = rlen + DSI_HOST_HDR_SIZE;
+ }
+ rc = msm_dsi_parse_rx_response(rp);
+
+dsi_cmds_rx_1_error:
+ if (rc)
+ rp->len = 0;
+
+ return rc;
+}
+
+/* read data length is more than 10 bytes, which requires multiple DSI read*/
+static int msm_dsi_cmds_rx_2(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct dsi_cmd_desc *cmds, int rlen)
+{
+ int rc;
+ struct dsi_buf *tp, *rp;
+ int pkt_size, data_bytes, total;
+
+ tp = &ctrl->tx_buf;
+ rp = &ctrl->rx_buf;
+ mdss_dsi_buf_init(rp);
+ pkt_size = DSI_MAX_PKT_SIZE;
+ data_bytes = MDSS_DSI_LEN;
+ total = 0;
+
+ while (true) {
+ rc = msm_dsi_set_max_packet_size(ctrl, pkt_size);
+ if (rc)
+ break;
+
+ mdss_dsi_buf_init(tp);
+ rc = mdss_dsi_cmd_dma_add(tp, cmds);
+ if (!rc) {
+ pr_err("%s: dsi_cmd_dma_add failed\n", __func__);
+ rc = -EINVAL;
+ break;
+ }
+ rc = msm_dsi_wait4video_eng_busy(ctrl);
+ if (rc) {
+ pr_err("%s: wait4video_eng failed\n", __func__);
+ break;
+ }
+
+ rc = msm_dsi_cmd_dma_tx(ctrl, tp);
+ if (IS_ERR_VALUE(rc)) {
+ pr_err("%s: msm_dsi_cmd_dma_tx failed\n", __func__);
+ break;
+ }
+
+ msm_dsi_cmd_dma_rx(ctrl, rp, DSI_MAX_BYTES_TO_READ);
+
+ rp->data += DSI_MAX_BYTES_TO_READ - DSI_HOST_HDR_SIZE;
+ total += data_bytes;
+ if (total >= rlen)
+ break;
+
+ data_bytes = DSI_MAX_BYTES_TO_READ - DSI_HOST_HDR_SIZE;
+ pkt_size += data_bytes;
+ }
+
+ if (!rc) {
+ rp->data = rp->start;
+ rp->len = rlen + DSI_HOST_HDR_SIZE;
+ rc = msm_dsi_parse_rx_response(rp);
+ }
+
+ if (rc)
+ rp->len = 0;
+
+ return rc;
+}
+
+int msm_dsi_cmds_rx(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct dsi_cmd_desc *cmds, int rlen)
+{
+ int rc;
+ if (rlen <= DSI_MAX_PKT_SIZE)
+ rc = msm_dsi_cmds_rx_1(ctrl, cmds, rlen);
+ else
+ rc = msm_dsi_cmds_rx_2(ctrl, cmds, rlen);
+
+ return rc;
+}
+
+void msm_dsi_cmdlist_tx(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct dcs_cmd_req *req)
+{
+ int ret;
+
+ ret = msm_dsi_cmds_tx(ctrl, req->cmds, req->cmds_cnt);
+
+ if (req->cb)
+ req->cb(ret);
+}
+
+void msm_dsi_cmdlist_rx(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct dcs_cmd_req *req)
+{
+ struct dsi_buf *rp;
+ int len = 0;
+
+ if (req->rbuf) {
+ rp = &ctrl->rx_buf;
+ len = msm_dsi_cmds_rx(ctrl, req->cmds, req->rlen);
+ memcpy(req->rbuf, rp->data, rp->len);
+ } else {
+ pr_err("%s: No rx buffer provided\n", __func__);
+ }
+
+ if (req->cb)
+ req->cb(len);
+}
+int msm_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp)
+{
+ struct dcs_cmd_req *req;
+ int dsi_on;
+ int ret = -EINVAL;
+
+ mutex_lock(&ctrl->mutex);
+ dsi_on = dsi_host_private->dsi_on;
+ mutex_unlock(&ctrl->mutex);
+ if (!dsi_on) {
+ pr_err("try to send DSI commands while dsi is off\n");
+ return ret;
+ }
+
+ mutex_lock(&ctrl->cmd_mutex);
+ req = mdss_dsi_cmdlist_get(ctrl);
+
+ if (!req) {
+ mutex_unlock(&ctrl->cmd_mutex);
+ return ret;
+ }
+
+ msm_dsi_clk_ctrl(&ctrl->panel_data, 1);
+
+ if (0 == (req->flags & CMD_REQ_LP_MODE))
+ dsi_set_tx_power_mode(0);
+
+ if (req->flags & CMD_REQ_RX)
+ msm_dsi_cmdlist_rx(ctrl, req);
+ else
+ msm_dsi_cmdlist_tx(ctrl, req);
+
+ if (0 == (req->flags & CMD_REQ_LP_MODE))
+ dsi_set_tx_power_mode(1);
+
+ msm_dsi_clk_ctrl(&ctrl->panel_data, 0);
+
+ mutex_unlock(&ctrl->cmd_mutex);
+ return 0;
}
static int msm_dsi_cal_clk_rate(struct mdss_panel_data *pdata,
@@ -785,11 +1045,14 @@
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
panel_data);
+ mutex_lock(&ctrl_pdata->mutex);
+
ret = msm_dss_enable_vreg(
ctrl_pdata->power_data.vreg_config,
ctrl_pdata->power_data.num_vreg, 1);
if (ret) {
pr_err("%s: DSI power on failed\n", __func__);
+ mutex_unlock(&ctrl_pdata->mutex);
return ret;
}
@@ -876,6 +1139,11 @@
msm_dsi_op_mode_config(mipi->mode, pdata);
+ msm_dsi_set_irq(ctrl_pdata, DSI_INTR_ERROR_MASK);
+ dsi_host_private->clk_count = 1;
+ dsi_host_private->dsi_on = 1;
+ mutex_unlock(&ctrl_pdata->mutex);
+
return ret;
}
@@ -894,6 +1162,8 @@
panel_data);
pr_debug("msm_dsi_off\n");
+ mutex_lock(&ctrl_pdata->mutex);
+ msm_dsi_clear_irq(ctrl_pdata, ctrl_pdata->dsi_irq_mask);
msm_dsi_controller_cfg(0);
msm_dsi_clk_set_rate(DSI_ESC_CLK_RATE, 0, 0, 0);
msm_dsi_clk_disable();
@@ -906,8 +1176,11 @@
ctrl_pdata->power_data.num_vreg, 0);
if (ret) {
pr_err("%s: Panel power off failed\n", __func__);
- return ret;
}
+ dsi_host_private->clk_count = 0;
+ dsi_host_private->dsi_on = 0;
+
+ mutex_unlock(&ctrl_pdata->mutex);
return ret;
}
@@ -931,20 +1204,58 @@
panel_data);
pinfo = &pdata->panel_info;
+ mutex_lock(&ctrl_pdata->mutex);
ret = msm_dss_enable_vreg(
ctrl_pdata->power_data.vreg_config,
ctrl_pdata->power_data.num_vreg, 1);
if (ret) {
pr_err("%s: DSI power on failed\n", __func__);
+ mutex_unlock(&ctrl_pdata->mutex);
return ret;
}
msm_dsi_ahb_ctrl(1);
msm_dsi_prepare_clocks();
msm_dsi_clk_enable();
+ msm_dsi_set_irq(ctrl_pdata, DSI_INTR_ERROR_MASK);
+ dsi_host_private->clk_count = 1;
+ dsi_host_private->dsi_on = 1;
+ mutex_unlock(&ctrl_pdata->mutex);
return 0;
}
+int msm_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+{
+ int ret = 0;
+
+ if (ctrl_pdata == NULL) {
+ pr_err("%s: Invalid input data\n", __func__);
+ return 0;
+ }
+
+ mutex_lock(&ctrl_pdata->cmd_mutex);
+ msm_dsi_clk_ctrl(&ctrl_pdata->panel_data, 1);
+ msm_dsi_cmd_mdp_busy(ctrl_pdata);
+ msm_dsi_set_irq(ctrl_pdata, DSI_INTR_BTA_DONE_MASK);
+ INIT_COMPLETION(ctrl_pdata->bta_comp);
+
+ /* BTA trigger */
+ MIPI_OUTP(dsi_host_private->dsi_base + DSI_CMD_MODE_BTA_SW_TRIGGER,
+ 0x01);
+ wmb();
+ ret = wait_for_completion_killable_timeout(&ctrl_pdata->bta_comp,
+ HZ/10);
+ msm_dsi_clear_irq(ctrl_pdata, DSI_INTR_BTA_DONE_MASK);
+ msm_dsi_clk_ctrl(&ctrl_pdata->panel_data, 0);
+ mutex_unlock(&ctrl_pdata->cmd_mutex);
+
+ if (ret <= 0)
+ pr_err("%s: DSI BTA error: %i\n", __func__, __LINE__);
+
+ pr_debug("%s: BTA done with ret: %d\n", __func__, ret);
+ return ret;
+}
+
static void msm_dsi_debug_enable_clock(int on)
{
if (dsi_host_private->debug_enable_clk)
@@ -1000,6 +1311,21 @@
return rc;
}
+static struct device_node *dsi_pref_prim_panel(
+ struct platform_device *pdev)
+{
+ struct device_node *dsi_pan_node = NULL;
+
+ pr_debug("%s:%d: Select primary panel from dt\n",
+ __func__, __LINE__);
+ dsi_pan_node = of_parse_phandle(pdev->dev.of_node,
+ "qcom,dsi-pref-prim-pan", 0);
+ if (!dsi_pan_node)
+ pr_err("%s:can't find panel phandle\n", __func__);
+
+ return dsi_pan_node;
+}
+
/**
* dsi_find_panel_of_node(): find device node of dsi panel
* @pdev: platform_device of the dsi ctrl node
@@ -1029,14 +1355,7 @@
/* no panel cfg chg, parse dt */
pr_debug("%s:%d: no cmd line cfg present\n",
__func__, __LINE__);
- dsi_pan_node = of_parse_phandle(
- pdev->dev.of_node,
- "qcom,dsi-pref-prim-pan", 0);
- if (!dsi_pan_node) {
- pr_err("%s:can't find panel phandle\n",
- __func__);
- return NULL;
- }
+ dsi_pan_node = dsi_pref_prim_panel(pdev);
} else {
if (panel_cfg[0] != '0') {
pr_err("%s:%d:ctrl id=[%d] not supported\n",
@@ -1064,12 +1383,64 @@
if (!dsi_pan_node) {
pr_err("%s: invalid pan node\n",
__func__);
- return NULL;
+ dsi_pan_node = dsi_pref_prim_panel(pdev);
}
}
return dsi_pan_node;
}
+static int msm_dsi_clk_ctrl(struct mdss_panel_data *pdata, int enable)
+{
+ u32 bitclk_rate = 0, byteclk_rate = 0, pclk_rate = 0, dsiclk_rate = 0;
+ struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+
+ pr_debug("%s:\n", __func__);
+
+ ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+ panel_data);
+
+ mutex_lock(&ctrl_pdata->mutex);
+
+ if (enable) {
+ dsi_host_private->clk_count++;
+ if (dsi_host_private->clk_count == 1) {
+ msm_dsi_ahb_ctrl(1);
+ msm_dsi_cal_clk_rate(pdata, &bitclk_rate, &dsiclk_rate,
+ &byteclk_rate, &pclk_rate);
+ msm_dsi_clk_set_rate(DSI_ESC_CLK_RATE, dsiclk_rate,
+ byteclk_rate, pclk_rate);
+ msm_dsi_clk_enable();
+ }
+ } else {
+ dsi_host_private->clk_count--;
+ if (dsi_host_private->clk_count == 0) {
+ msm_dsi_clk_set_rate(DSI_ESC_CLK_RATE, 0, 0, 0);
+ msm_dsi_clk_disable();
+ msm_dsi_ahb_ctrl(0);
+ }
+ }
+ mutex_unlock(&ctrl_pdata->mutex);
+ return 0;
+}
+
+void msm_dsi_ctrl_init(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ init_completion(&ctrl->dma_comp);
+ init_completion(&ctrl->mdp_comp);
+ init_completion(&ctrl->bta_comp);
+ init_completion(&ctrl->video_comp);
+ spin_lock_init(&ctrl->irq_lock);
+ spin_lock_init(&ctrl->mdp_lock);
+ mutex_init(&ctrl->mutex);
+ mutex_init(&ctrl->cmd_mutex);
+ complete(&ctrl->mdp_comp);
+ dsi_buf_alloc(&ctrl->tx_buf, SZ_4K);
+ dsi_buf_alloc(&ctrl->rx_buf, SZ_4K);
+ ctrl->cmdlist_commit = msm_dsi_cmdlist_commit;
+ ctrl->panel_mode = ctrl->panel_data.panel_info.mipi.mode;
+ ctrl->check_status = msm_dsi_bta_status_check;
+}
+
static int __devinit msm_dsi_probe(struct platform_device *pdev)
{
struct dsi_interface intf;
@@ -1130,7 +1501,8 @@
rc = -ENODEV;
goto error_irq_resource;
} else {
- rc = msm_dsi_irq_init(&pdev->dev, mdss_dsi_mres->start);
+ rc = msm_dsi_irq_init(&pdev->dev, mdss_dsi_mres->start,
+ ctrl_pdata);
if (rc) {
dev_err(&pdev->dev, "%s: failed to init irq, rc=%d\n",
__func__, rc);
@@ -1188,15 +1560,16 @@
intf.on = msm_dsi_on;
intf.off = msm_dsi_off;
intf.cont_on = msm_dsi_cont_on;
+ intf.clk_ctrl = msm_dsi_clk_ctrl;
intf.op_mode_config = msm_dsi_op_mode_config;
- intf.tx = msm_dsi_cmds_tx;
- intf.rx = msm_dsi_cmds_rx;
intf.index = 0;
intf.private = NULL;
dsi_register_interface(&intf);
msm_dsi_debug_init();
+ msm_dsi_ctrl_init(ctrl_pdata);
+
rc = dsi_panel_device_register_v2(pdev, ctrl_pdata);
if (rc) {
pr_err("%s: dsi panel dev reg failed\n", __func__);
@@ -1211,7 +1584,7 @@
error_pan_node:
of_node_put(dsi_pan_node);
error_platform_pop:
- msm_dsi_disable_irq();
+ msm_dsi_clear_irq(ctrl_pdata, ctrl_pdata->dsi_irq_mask);
error_irq_resource:
if (dsi_host_private->dsi_base) {
iounmap(dsi_host_private->dsi_base);
@@ -1233,7 +1606,7 @@
return -ENODEV;
}
- msm_dsi_disable_irq();
+ msm_dsi_clear_irq(ctrl_pdata, ctrl_pdata->dsi_irq_mask);
msm_dsi_io_deinit(pdev, &(ctrl_pdata->power_data));
dsi_ctrl_config_deinit(pdev, ctrl_pdata);
iounmap(dsi_host_private->dsi_base);
diff --git a/drivers/video/msm/mdss/dsi_host_v2.h b/drivers/video/msm/mdss/dsi_host_v2.h
index cec9774..b297452 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.h
+++ b/drivers/video/msm/mdss/dsi_host_v2.h
@@ -17,6 +17,8 @@
#define DSI_INTR_ERROR_MASK BIT(25)
#define DSI_INTR_ERROR BIT(24)
+#define DSI_INTR_BTA_DONE_MASK BIT(21)
+#define DSI_INTR_BTA_DONE BIT(20)
#define DSI_INTR_VIDEO_DONE_MASK BIT(17)
#define DSI_INTR_VIDEO_DONE BIT(16)
#define DSI_INTR_CMD_MDP_DONE_MASK BIT(9)
@@ -24,6 +26,8 @@
#define DSI_INTR_CMD_DMA_DONE_MASK BIT(1)
#define DSI_INTR_CMD_DMA_DONE BIT(0)
+#define DSI_BTA_TERM BIT(1)
+
#define DSI_CTRL 0x0000
#define DSI_STATUS 0x0004
#define DSI_FIFO_STATUS 0x0008
diff --git a/drivers/video/msm/mdss/dsi_status_v2.c b/drivers/video/msm/mdss/dsi_status_v2.c
new file mode 100644
index 0000000..d62ddf3
--- /dev/null
+++ b/drivers/video/msm/mdss/dsi_status_v2.c
@@ -0,0 +1,188 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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/kernel.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <linux/notifier.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/iopoll.h>
+#include <linux/kobject.h>
+#include <linux/string.h>
+#include <linux/sysfs.h>
+
+#include "mdss_fb.h"
+#include "mdss_dsi.h"
+#include "mdss_panel.h"
+#include "mdp3_ctrl.h"
+
+#define STATUS_CHECK_INTERVAL 5000
+
+/**
+ * dsi_status_data - Stores all the data necessary for this module
+ * @fb_notif: Used to egister for the fb events
+ * @live_status: Delayed worker structure, used to associate the
+ * delayed worker function
+ * @mfd: Used to store the msm_fb_data_type received when the notifier
+ * call back happens
+ * @root: Stores the dir created by debuugfs
+ * @debugfs_reset_panel: The debugfs variable used to inject errors
+ */
+
+struct dsi_status_data {
+ struct notifier_block fb_notifier;
+ struct delayed_work check_status;
+ struct msm_fb_data_type *mfd;
+ uint32_t check_interval;
+};
+struct dsi_status_data *pstatus_data;
+static uint32_t interval = STATUS_CHECK_INTERVAL;
+
+void check_dsi_ctrl_status(struct work_struct *work)
+{
+ struct dsi_status_data *pdsi_status = NULL;
+ struct mdss_panel_data *pdata = NULL;
+ struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+ struct mdp3_session_data *mdp3_session = NULL;
+ int ret = 0;
+
+ pdsi_status = container_of(to_delayed_work(work),
+ struct dsi_status_data, check_status);
+ if (!pdsi_status) {
+ pr_err("%s: DSI status data not available\n", __func__);
+ return;
+ }
+
+ pdata = dev_get_platdata(&pdsi_status->mfd->pdev->dev);
+ if (!pdata) {
+ pr_err("%s: Panel data not available\n", __func__);
+ return;
+ }
+ ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+ panel_data);
+ if (!ctrl_pdata || !ctrl_pdata->check_status) {
+ pr_err("%s: DSI ctrl or status_check callback not avilable\n",
+ __func__);
+ return;
+ }
+ mdp3_session = pdsi_status->mfd->mdp.private1;
+ mutex_lock(&mdp3_session->lock);
+
+ ret = ctrl_pdata->check_status(ctrl_pdata);
+
+ mutex_unlock(&mdp3_session->lock);
+
+ if ((pdsi_status->mfd->panel_power_on)) {
+ if (ret > 0) {
+ schedule_delayed_work(&pdsi_status->check_status,
+ msecs_to_jiffies(pdsi_status->check_interval));
+ } else {
+ char *envp[2] = {"PANEL_ALIVE=0", NULL};
+ pdata->panel_info.panel_dead = true;
+ ret = kobject_uevent_env(
+ &pdsi_status->mfd->fbi->dev->kobj,
+ KOBJ_CHANGE, envp);
+ pr_err("%s: Panel has gone bad, sending uevent - %s\n",
+ __func__, envp[0]);
+ }
+ }
+}
+
+/**
+ * fb_notifier_callback() - Call back function for the fb_register_client()
+ * notifying events
+ * @self : notifier block
+ * @event : The event that was triggered
+ * @data : Of type struct fb_event
+ *
+ * - This function listens for FB_BLANK_UNBLANK and FB_BLANK_POWERDOWN events
+ * - Based on the event the delayed work is either scheduled again after
+ * PANEL_STATUS_CHECK_INTERVAL or cancelled
+ */
+static int fb_event_callback(struct notifier_block *self,
+ unsigned long event, void *data)
+{
+ struct fb_event *evdata = (struct fb_event *)data;
+ struct dsi_status_data *pdata = container_of(self,
+ struct dsi_status_data, fb_notifier);
+ pdata->mfd = (struct msm_fb_data_type *)evdata->info->par;
+
+ if (event == FB_EVENT_BLANK && evdata) {
+ int *blank = evdata->data;
+ switch (*blank) {
+ case FB_BLANK_UNBLANK:
+ schedule_delayed_work(&pdata->check_status,
+ msecs_to_jiffies(STATUS_CHECK_INTERVAL));
+ break;
+ case FB_BLANK_POWERDOWN:
+ cancel_delayed_work(&pdata->check_status);
+ break;
+ }
+ }
+ return 0;
+}
+
+int __init mdss_dsi_status_init(void)
+{
+ int rc;
+
+ pstatus_data = kzalloc(sizeof(struct dsi_status_data), GFP_KERNEL);
+ if (!pstatus_data) {
+ pr_err("%s: can't alloc mem\n", __func__);
+ rc = -ENOMEM;
+ return rc;
+ }
+
+ memset(pstatus_data, 0, sizeof(struct dsi_status_data));
+
+ pstatus_data->fb_notifier.notifier_call = fb_event_callback;
+
+ rc = fb_register_client(&pstatus_data->fb_notifier);
+ if (rc < 0) {
+ pr_err("%s: fb_register_client failed, returned with rc=%d\n",
+ __func__, rc);
+ kfree(pstatus_data);
+ return -EPERM;
+ }
+
+ pstatus_data->check_interval = interval;
+ pr_info("%s: DSI status check interval:%d\n", __func__, interval);
+
+ INIT_DELAYED_WORK(&pstatus_data->check_status, check_dsi_ctrl_status);
+
+ pr_debug("%s: DSI ctrl status thread initialized\n", __func__);
+
+ return rc;
+}
+
+void __exit mdss_dsi_status_exit(void)
+{
+ fb_unregister_client(&pstatus_data->fb_notifier);
+ cancel_delayed_work_sync(&pstatus_data->check_status);
+ kfree(pstatus_data);
+ pr_debug("%s: DSI ctrl status thread removed\n", __func__);
+}
+
+module_param(interval, uint, 0);
+MODULE_PARM_DESC(interval,
+ "Duration in milliseconds to send BTA command for checking"
+ "DSI status periodically");
+
+module_init(mdss_dsi_status_init);
+module_exit(mdss_dsi_status_exit);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/msm/mdss/dsi_v2.c b/drivers/video/msm/mdss/dsi_v2.c
index 65cca0e..ccde545 100644
--- a/drivers/video/msm/mdss/dsi_v2.c
+++ b/drivers/video/msm/mdss/dsi_v2.c
@@ -21,7 +21,6 @@
#include "dsi_v2.h"
static struct dsi_interface dsi_intf;
-static struct dsi_buf dsi_panel_tx_buf;
static int dsi_off(struct mdss_panel_data *pdata)
{
@@ -67,21 +66,13 @@
if (enable) {
dsi_ctrl_gpio_request(ctrl_pdata);
mdss_dsi_panel_reset(pdata, 1);
-
- rc = dsi_cmds_tx_v2(pdata, &dsi_panel_tx_buf,
- ctrl_pdata->on_cmds.cmds,
- ctrl_pdata->on_cmds.cmd_cnt);
-
+ rc = ctrl_pdata->on(pdata);
if (rc)
pr_err("dsi_panel_handler panel on failed %d\n", rc);
} else {
if (dsi_intf.op_mode_config)
dsi_intf.op_mode_config(DSI_CMD_MODE, pdata);
-
- dsi_cmds_tx_v2(pdata, &dsi_panel_tx_buf,
- ctrl_pdata->off_cmds.cmds,
- ctrl_pdata->off_cmds.cmd_cnt);
-
+ rc = ctrl_pdata->off(pdata);
mdss_dsi_panel_reset(pdata, 0);
dsi_ctrl_gpio_free(ctrl_pdata);
}
@@ -104,6 +95,18 @@
return rc;
}
+static int dsi_clk_ctrl(struct mdss_panel_data *pdata, int enable)
+{
+ int rc = 0;
+
+ pr_debug("%s:\n", __func__);
+
+ if (dsi_intf.clk_ctrl)
+ rc = dsi_intf.clk_ctrl(pdata, enable);
+
+ return rc;
+}
+
static int dsi_event_handler(struct mdss_panel_data *pdata,
int event, void *arg)
{
@@ -130,6 +133,9 @@
case MDSS_EVENT_CONT_SPLASH_BEGIN:
rc = dsi_splash_on(pdata);
break;
+ case MDSS_EVENT_PANEL_CLK_CTRL:
+ rc = dsi_clk_ctrl(pdata, (int)arg);
+ break;
default:
pr_debug("%s: unhandled event=%d\n", __func__, event);
break;
@@ -557,19 +563,12 @@
ctrl_pdata->panel_data.event_handler = dsi_event_handler;
- rc = dsi_buf_alloc(&dsi_panel_tx_buf,
- ALIGN(DSI_BUF_SIZE,
- SZ_4K));
- if (rc)
- return rc;
-
/*
* register in mdp driver
*/
rc = mdss_register_panel(dev, &(ctrl_pdata->panel_data));
if (rc) {
dev_err(&dev->dev, "unable to register MIPI DSI panel\n");
- kfree(dsi_panel_tx_buf.start);
return rc;
}
@@ -582,72 +581,6 @@
dsi_intf = *intf;
}
-int dsi_cmds_tx_v2(struct mdss_panel_data *pdata,
- struct dsi_buf *tp, struct dsi_cmd_desc *cmds,
- int cnt)
-{
- int rc = 0;
-
- if (!dsi_intf.tx)
- return -EINVAL;
-
- rc = dsi_intf.tx(pdata, tp, cmds, cnt);
- return rc;
-}
-
-int dsi_cmds_rx_v2(struct mdss_panel_data *pdata,
- struct dsi_buf *tp, struct dsi_buf *rp,
- struct dsi_cmd_desc *cmds, int rlen)
-{
- int rc = 0;
-
- if (pdata == NULL) {
- pr_err("%s: Invalid input data\n", __func__);
- return -EINVAL;
- }
-
- if (!dsi_intf.rx)
- return -EINVAL;
-
- rc = dsi_intf.rx(pdata, tp, rp, cmds, rlen);
- return rc;
-}
-
-static char *dsi_buf_reserve(struct dsi_buf *dp, int len)
-{
- dp->data += len;
- return dp->data;
-}
-
-
-static char *dsi_buf_push(struct dsi_buf *dp, int len)
-{
- dp->data -= len;
- dp->len += len;
- return dp->data;
-}
-
-static char *dsi_buf_reserve_hdr(struct dsi_buf *dp, int hlen)
-{
- dp->hdr = (u32 *)dp->data;
- return dsi_buf_reserve(dp, hlen);
-}
-
-char *dsi_buf_init(struct dsi_buf *dp)
-{
- int off;
-
- dp->data = dp->start;
- off = (int)dp->data;
- /* 8 byte align */
- off &= 0x07;
- if (off)
- off = 8 - off;
- dp->data += off;
- dp->len = 0;
- return dp->data;
-}
-
int dsi_buf_alloc(struct dsi_buf *dp, int size)
{
dp->start = kmalloc(size, GFP_KERNEL);
@@ -669,507 +602,3 @@
return 0;
}
-/*
- * mipi dsi generic long write
- */
-static int dsi_generic_lwrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
-{
- char *bp;
- u32 *hp;
- int i, len;
- struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
-
- bp = dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
-
- /* fill up payload */
- if (cm->payload) {
- len = dchdr->dlen;
- len += 3;
- len &= ~0x03; /* multipled by 4 */
- for (i = 0; i < dchdr->dlen; i++)
- *bp++ = cm->payload[i];
-
- /* append 0xff to the end */
- for (; i < len; i++)
- *bp++ = 0xff;
-
- dp->len += len;
- }
-
- /* fill up header */
- hp = dp->hdr;
- *hp = 0;
- *hp = DSI_HDR_WC(dchdr->dlen);
- *hp |= DSI_HDR_VC(dchdr->vc);
- *hp |= DSI_HDR_LONG_PKT;
- *hp |= DSI_HDR_DTYPE(DTYPE_GEN_LWRITE);
- if (dchdr->last)
- *hp |= DSI_HDR_LAST;
-
- dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
-
- return dp->len;
-}
-
-/*
- * mipi dsi generic short write with 0, 1 2 parameters
- */
-static int dsi_generic_swrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
-{
- u32 *hp;
- int len;
- struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
-
- if (dchdr->dlen && cm->payload == 0) {
- pr_err("%s: NO payload error\n", __func__);
- return 0;
- }
-
- dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
- hp = dp->hdr;
- *hp = 0;
- *hp |= DSI_HDR_VC(dchdr->vc);
- if (dchdr->last)
- *hp |= DSI_HDR_LAST;
-
- len = (dchdr->dlen > 2) ? 2 : dchdr->dlen;
-
- if (len == 1) {
- *hp |= DSI_HDR_DTYPE(DTYPE_GEN_WRITE1);
- *hp |= DSI_HDR_DATA1(cm->payload[0]);
- *hp |= DSI_HDR_DATA2(0);
- } else if (len == 2) {
- *hp |= DSI_HDR_DTYPE(DTYPE_GEN_WRITE2);
- *hp |= DSI_HDR_DATA1(cm->payload[0]);
- *hp |= DSI_HDR_DATA2(cm->payload[1]);
- } else {
- *hp |= DSI_HDR_DTYPE(DTYPE_GEN_WRITE);
- *hp |= DSI_HDR_DATA1(0);
- *hp |= DSI_HDR_DATA2(0);
- }
-
- dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
-
- return dp->len;
-}
-
-/*
- * mipi dsi gerneric read with 0, 1 2 parameters
- */
-static int dsi_generic_read(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
-{
- u32 *hp;
- int len;
- struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
-
- if (dchdr->dlen && cm->payload == 0) {
- pr_err("%s: NO payload error\n", __func__);
- return 0;
- }
-
- dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
- hp = dp->hdr;
- *hp = 0;
- *hp |= DSI_HDR_VC(dchdr->vc);
- *hp |= DSI_HDR_BTA;
- if (dchdr->last)
- *hp |= DSI_HDR_LAST;
-
- len = (dchdr->dlen > 2) ? 2 : dchdr->dlen;
-
- if (len == 1) {
- *hp |= DSI_HDR_DTYPE(DTYPE_GEN_READ1);
- *hp |= DSI_HDR_DATA1(cm->payload[0]);
- *hp |= DSI_HDR_DATA2(0);
- } else if (len == 2) {
- *hp |= DSI_HDR_DTYPE(DTYPE_GEN_READ2);
- *hp |= DSI_HDR_DATA1(cm->payload[0]);
- *hp |= DSI_HDR_DATA2(cm->payload[1]);
- } else {
- *hp |= DSI_HDR_DTYPE(DTYPE_GEN_READ);
- *hp |= DSI_HDR_DATA1(0);
- *hp |= DSI_HDR_DATA2(0);
- }
-
- dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
- return dp->len;
-}
-
-/*
- * mipi dsi dcs long write
- */
-static int dsi_dcs_lwrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
-{
- char *bp;
- u32 *hp;
- int i, len;
- struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
-
- bp = dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
-
- /*
- * fill up payload
- * dcs command byte (first byte) followed by payload
- */
- if (cm->payload) {
- len = dchdr->dlen;
- len += 3;
- len &= ~0x03; /* multipled by 4 */
- for (i = 0; i < dchdr->dlen; i++)
- *bp++ = cm->payload[i];
-
- /* append 0xff to the end */
- for (; i < len; i++)
- *bp++ = 0xff;
-
- dp->len += len;
- }
-
- /* fill up header */
- hp = dp->hdr;
- *hp = 0;
- *hp = DSI_HDR_WC(dchdr->dlen);
- *hp |= DSI_HDR_VC(dchdr->vc);
- *hp |= DSI_HDR_LONG_PKT;
- *hp |= DSI_HDR_DTYPE(DTYPE_DCS_LWRITE);
- if (dchdr->last)
- *hp |= DSI_HDR_LAST;
-
- dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
-
- return dp->len;
-}
-
-/*
- * mipi dsi dcs short write with 0 parameters
- */
-static int dsi_dcs_swrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
-{
- u32 *hp;
- int len;
- struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
-
- if (cm->payload == 0) {
- pr_err("%s: NO payload error\n", __func__);
- return -EINVAL;
- }
-
- dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
- hp = dp->hdr;
- *hp = 0;
- *hp |= DSI_HDR_VC(dchdr->vc);
- if (dchdr->ack)
- *hp |= DSI_HDR_BTA;
- if (dchdr->last)
- *hp |= DSI_HDR_LAST;
-
- len = (dchdr->dlen > 1) ? 1 : dchdr->dlen;
-
- *hp |= DSI_HDR_DTYPE(DTYPE_DCS_WRITE);
- *hp |= DSI_HDR_DATA1(cm->payload[0]); /* dcs command byte */
- *hp |= DSI_HDR_DATA2(0);
-
- dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
- return dp->len;
-}
-
-/*
- * mipi dsi dcs short write with 1 parameters
- */
-static int dsi_dcs_swrite1(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
-{
- u32 *hp;
- struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
-
- if (dchdr->dlen < 2 || cm->payload == 0) {
- pr_err("%s: NO payload error\n", __func__);
- return -EINVAL;
- }
-
- dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
- hp = dp->hdr;
- *hp = 0;
- *hp |= DSI_HDR_VC(dchdr->vc);
- if (dchdr->ack)
- *hp |= DSI_HDR_BTA;
- if (dchdr->last)
- *hp |= DSI_HDR_LAST;
-
- *hp |= DSI_HDR_DTYPE(DTYPE_DCS_WRITE1);
- *hp |= DSI_HDR_DATA1(cm->payload[0]); /* dcs comamnd byte */
- *hp |= DSI_HDR_DATA2(cm->payload[1]); /* parameter */
-
- dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
-
- return dp->len;
-}
-
-/*
- * mipi dsi dcs read with 0 parameters
- */
-static int dsi_dcs_read(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
-{
- u32 *hp;
- struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
-
- if (cm->payload == 0) {
- pr_err("%s: NO payload error\n", __func__);
- return -EINVAL;
- }
-
- dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
- hp = dp->hdr;
- *hp = 0;
- *hp |= DSI_HDR_VC(dchdr->vc);
- *hp |= DSI_HDR_BTA;
- *hp |= DSI_HDR_DTYPE(DTYPE_DCS_READ);
- if (dchdr->last)
- *hp |= DSI_HDR_LAST;
-
- *hp |= DSI_HDR_DATA1(cm->payload[0]); /* dcs command byte */
- *hp |= DSI_HDR_DATA2(0);
-
- dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
-
- return dp->len; /* 4 bytes */
-}
-
-static int dsi_cm_on(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
-{
- u32 *hp;
- struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
-
- dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
- hp = dp->hdr;
- *hp = 0;
- *hp |= DSI_HDR_VC(dchdr->vc);
- *hp |= DSI_HDR_DTYPE(DTYPE_CM_ON);
- if (dchdr->last)
- *hp |= DSI_HDR_LAST;
-
- dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
-
- return dp->len; /* 4 bytes */
-}
-
-static int dsi_cm_off(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
-{
- u32 *hp;
- struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
-
- dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
- hp = dp->hdr;
- *hp = 0;
- *hp |= DSI_HDR_VC(dchdr->vc);
- *hp |= DSI_HDR_DTYPE(DTYPE_CM_OFF);
- if (dchdr->last)
- *hp |= DSI_HDR_LAST;
-
- dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
-
- return dp->len; /* 4 bytes */
-}
-
-static int dsi_peripheral_on(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
-{
- u32 *hp;
- struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
-
- dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
- hp = dp->hdr;
- *hp = 0;
- *hp |= DSI_HDR_VC(dchdr->vc);
- *hp |= DSI_HDR_DTYPE(DTYPE_PERIPHERAL_ON);
- if (dchdr->last)
- *hp |= DSI_HDR_LAST;
-
- dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
-
- return dp->len; /* 4 bytes */
-}
-
-static int dsi_peripheral_off(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
-{
- u32 *hp;
- struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
-
- dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
- hp = dp->hdr;
- *hp = 0;
- *hp |= DSI_HDR_VC(dchdr->vc);
- *hp |= DSI_HDR_DTYPE(DTYPE_PERIPHERAL_OFF);
- if (dchdr->last)
- *hp |= DSI_HDR_LAST;
-
- dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
-
- return dp->len; /* 4 bytes */
-}
-
-static int dsi_set_max_pktsize(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
-{
- u32 *hp;
- struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
-
- if (cm->payload == 0) {
- pr_err("%s: NO payload error\n", __func__);
- return 0;
- }
-
- dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
- hp = dp->hdr;
- *hp = 0;
- *hp |= DSI_HDR_VC(dchdr->vc);
- *hp |= DSI_HDR_DTYPE(DTYPE_MAX_PKTSIZE);
- if (dchdr->last)
- *hp |= DSI_HDR_LAST;
-
- *hp |= DSI_HDR_DATA1(cm->payload[0]);
- *hp |= DSI_HDR_DATA2(cm->payload[1]);
-
- dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
-
- return dp->len; /* 4 bytes */
-}
-
-static int dsi_null_pkt(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
-{
- u32 *hp;
- struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
-
- dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
- hp = dp->hdr;
- *hp = 0;
- *hp = DSI_HDR_WC(dchdr->dlen);
- *hp |= DSI_HDR_LONG_PKT;
- *hp |= DSI_HDR_VC(dchdr->vc);
- *hp |= DSI_HDR_DTYPE(DTYPE_NULL_PKT);
- if (dchdr->last)
- *hp |= DSI_HDR_LAST;
-
- dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
-
- return dp->len; /* 4 bytes */
-}
-
-static int dsi_blank_pkt(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
-{
- u32 *hp;
- struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
-
- dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
- hp = dp->hdr;
- *hp = 0;
- *hp = DSI_HDR_WC(dchdr->dlen);
- *hp |= DSI_HDR_LONG_PKT;
- *hp |= DSI_HDR_VC(dchdr->vc);
- *hp |= DSI_HDR_DTYPE(DTYPE_BLANK_PKT);
- if (dchdr->last)
- *hp |= DSI_HDR_LAST;
-
- dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
-
- return dp->len; /* 4 bytes */
-}
-
-/*
- * prepare cmd buffer to be txed
- */
-int dsi_cmd_dma_add(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
-{
- int len = 0;
- struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
-
- switch (dchdr->dtype) {
- case DTYPE_GEN_WRITE:
- case DTYPE_GEN_WRITE1:
- case DTYPE_GEN_WRITE2:
- len = dsi_generic_swrite(dp, cm);
- break;
- case DTYPE_GEN_LWRITE:
- len = dsi_generic_lwrite(dp, cm);
- break;
- case DTYPE_GEN_READ:
- case DTYPE_GEN_READ1:
- case DTYPE_GEN_READ2:
- len = dsi_generic_read(dp, cm);
- break;
- case DTYPE_DCS_LWRITE:
- len = dsi_dcs_lwrite(dp, cm);
- break;
- case DTYPE_DCS_WRITE:
- len = dsi_dcs_swrite(dp, cm);
- break;
- case DTYPE_DCS_WRITE1:
- len = dsi_dcs_swrite1(dp, cm);
- break;
- case DTYPE_DCS_READ:
- len = dsi_dcs_read(dp, cm);
- break;
- case DTYPE_MAX_PKTSIZE:
- len = dsi_set_max_pktsize(dp, cm);
- break;
- case DTYPE_NULL_PKT:
- len = dsi_null_pkt(dp, cm);
- break;
- case DTYPE_BLANK_PKT:
- len = dsi_blank_pkt(dp, cm);
- break;
- case DTYPE_CM_ON:
- len = dsi_cm_on(dp, cm);
- break;
- case DTYPE_CM_OFF:
- len = dsi_cm_off(dp, cm);
- break;
- case DTYPE_PERIPHERAL_ON:
- len = dsi_peripheral_on(dp, cm);
- break;
- case DTYPE_PERIPHERAL_OFF:
- len = dsi_peripheral_off(dp, cm);
- break;
- default:
- pr_debug("%s: dtype=%x NOT supported\n",
- __func__, dchdr->dtype);
- break;
-
- }
-
- return len;
-}
-
-/*
- * mdss_dsi_short_read1_resp: 1 parameter
- */
-int dsi_short_read1_resp(struct dsi_buf *rp)
-{
- /* strip out dcs type */
- rp->data++;
- rp->len = 1;
- return rp->len;
-}
-
-/*
- * mdss_dsi_short_read2_resp: 2 parameter
- */
-int dsi_short_read2_resp(struct dsi_buf *rp)
-{
- /* strip out dcs type */
- rp->data++;
- rp->len = 2;
- return rp->len;
-}
-
-int dsi_long_read_resp(struct dsi_buf *rp)
-{
- short len;
-
- len = rp->data[2];
- len <<= 8;
- len |= rp->data[1];
- /* strip out dcs header */
- rp->data += 4;
- rp->len -= 4;
- /* strip out 2 bytes of checksum */
- rp->len -= 2;
- return len;
-}
diff --git a/drivers/video/msm/mdss/dsi_v2.h b/drivers/video/msm/mdss/dsi_v2.h
index e15f640..b8c91da 100644
--- a/drivers/video/msm/mdss/dsi_v2.h
+++ b/drivers/video/msm/mdss/dsi_v2.h
@@ -27,12 +27,8 @@
int (*on)(struct mdss_panel_data *pdata);
int (*off)(struct mdss_panel_data *pdata);
int (*cont_on)(struct mdss_panel_data *pdata);
+ int (*clk_ctrl)(struct mdss_panel_data *pdata, int enable);
void (*op_mode_config)(int mode, struct mdss_panel_data *pdata);
- int (*tx)(struct mdss_panel_data *pdata,
- struct dsi_buf *tp, struct dsi_cmd_desc *cmds, int cnt);
- int (*rx)(struct mdss_panel_data *pdata,
- struct dsi_buf *tp, struct dsi_buf *rp,
- struct dsi_cmd_desc *cmds, int len);
int index;
void *private;
};
@@ -42,26 +38,8 @@
void dsi_register_interface(struct dsi_interface *intf);
-int dsi_cmds_rx_v2(struct mdss_panel_data *pdata,
- struct dsi_buf *tp, struct dsi_buf *rp,
- struct dsi_cmd_desc *cmds, int len);
-
-int dsi_cmds_tx_v2(struct mdss_panel_data *pdata,
- struct dsi_buf *tp, struct dsi_cmd_desc *cmds,
- int cnt);
-
-char *dsi_buf_init(struct dsi_buf *dp);
-
int dsi_buf_alloc(struct dsi_buf *dp, int size);
-int dsi_cmd_dma_add(struct dsi_buf *dp, struct dsi_cmd_desc *cm);
-
-int dsi_short_read1_resp(struct dsi_buf *rp);
-
-int dsi_short_read2_resp(struct dsi_buf *rp);
-
-int dsi_long_read_resp(struct dsi_buf *rp);
-
void dsi_set_tx_power_mode(int mode);
void dsi_ctrl_config_deinit(struct platform_device *pdev,
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index 638fcb3..02bd7e9 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -38,7 +38,7 @@
#include <linux/major.h>
#include <linux/bootmem.h>
#include <linux/memblock.h>
-
+#include <linux/iopoll.h>
#include <mach/board.h>
#include <mach/clk.h>
#include <mach/hardware.h>
@@ -55,6 +55,10 @@
#include "mdp3_ppp.h"
#include "mdss_debug.h"
+#define MISR_POLL_SLEEP 2000
+#define MISR_POLL_TIMEOUT 32000
+#define MDP3_REG_CAPTURED_DSI_PCLK_MASK 1
+
#define MDP_CORE_HW_VERSION 0x03040310
struct mdp3_hw_resource *mdp3_res;
@@ -182,16 +186,17 @@
int i = 0;
struct mdp3_hw_resource *mdata = (struct mdp3_hw_resource *)ptr;
u32 mdp_interrupt = 0;
+ u32 mdp_status = 0;
spin_lock(&mdata->irq_lock);
- if (!mdata->irq_mask) {
+ if (!mdata->irq_mask)
pr_err("spurious interrupt\n");
- spin_unlock(&mdata->irq_lock);
- return IRQ_HANDLED;
- }
- mdp_interrupt = MDP3_REG_READ(MDP3_REG_INTR_STATUS);
- MDP3_REG_WRITE(MDP3_REG_INTR_CLEAR, mdp_interrupt);
+ clk_enable(mdp3_res->clocks[MDP3_CLK_AHB]);
+ clk_enable(mdp3_res->clocks[MDP3_CLK_CORE]);
+
+ mdp_status = MDP3_REG_READ(MDP3_REG_INTR_STATUS);
+ mdp_interrupt = mdp_status;
pr_debug("mdp3_irq_handler irq=%d\n", mdp_interrupt);
mdp_interrupt &= mdata->irq_mask;
@@ -202,6 +207,11 @@
mdp_interrupt = mdp_interrupt >> 1;
i++;
}
+ MDP3_REG_WRITE(MDP3_REG_INTR_CLEAR, mdp_status);
+
+ clk_disable(mdp3_res->clocks[MDP3_CLK_AHB]);
+ clk_disable(mdp3_res->clocks[MDP3_CLK_CORE]);
+
spin_unlock(&mdata->irq_lock);
return IRQ_HANDLED;
@@ -281,8 +291,6 @@
spin_lock_irqsave(&mdp3_res->irq_lock, flag);
memset(mdp3_res->irq_ref_count, 0, sizeof(u32) * MDP3_MAX_INTR);
mdp3_res->irq_mask = 0;
- MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, 0);
- MDP3_REG_WRITE(MDP3_REG_INTR_CLEAR, 0xfffffff);
disable_irq_nosync(mdp3_res->irq);
spin_unlock_irqrestore(&mdp3_res->irq_lock, flag);
}
@@ -415,10 +423,10 @@
count = mdp3_res->clock_ref_count[clk_idx];
if (count == 1 && enable) {
pr_debug("clk=%d en=%d\n", clk_idx, enable);
- ret = clk_prepare_enable(clk);
+ ret = clk_enable(clk);
} else if (count == 0) {
pr_debug("clk=%d disable\n", clk_idx);
- clk_disable_unprepare(clk);
+ clk_disable(clk);
ret = 0;
} else if (count < 0) {
pr_err("clk=%d count=%d\n", clk_idx, count);
@@ -554,7 +562,7 @@
clk_put(mdp3_res->clocks[MDP3_CLK_DSI]);
}
-int mdp3_clk_enable(int enable)
+int mdp3_clk_enable(int enable, int dsi_clk)
{
int rc;
@@ -564,7 +572,79 @@
rc = mdp3_clk_update(MDP3_CLK_AHB, enable);
rc |= mdp3_clk_update(MDP3_CLK_CORE, enable);
rc |= mdp3_clk_update(MDP3_CLK_VSYNC, enable);
- rc |= mdp3_clk_update(MDP3_CLK_DSI, enable);
+ if (dsi_clk)
+ rc |= mdp3_clk_update(MDP3_CLK_DSI, enable);
+ mutex_unlock(&mdp3_res->res_mutex);
+ return rc;
+}
+
+int mdp3_clk_prepare(void)
+{
+ int rc = 0;
+
+ mutex_lock(&mdp3_res->res_mutex);
+ mdp3_res->clk_prepare_count++;
+ if (mdp3_res->clk_prepare_count == 1) {
+ rc = clk_prepare(mdp3_res->clocks[MDP3_CLK_AHB]);
+ if (rc < 0)
+ goto error0;
+ rc = clk_prepare(mdp3_res->clocks[MDP3_CLK_CORE]);
+ if (rc < 0)
+ goto error1;
+ rc = clk_prepare(mdp3_res->clocks[MDP3_CLK_VSYNC]);
+ if (rc < 0)
+ goto error2;
+ rc = clk_prepare(mdp3_res->clocks[MDP3_CLK_DSI]);
+ if (rc < 0)
+ goto error3;
+ }
+ mutex_unlock(&mdp3_res->res_mutex);
+ return rc;
+
+error3:
+ clk_unprepare(mdp3_res->clocks[MDP3_CLK_VSYNC]);
+error2:
+ clk_unprepare(mdp3_res->clocks[MDP3_CLK_CORE]);
+error1:
+ clk_unprepare(mdp3_res->clocks[MDP3_CLK_AHB]);
+error0:
+ mdp3_res->clk_prepare_count--;
+ mutex_unlock(&mdp3_res->res_mutex);
+ return rc;
+}
+
+void mdp3_clk_unprepare(void)
+{
+ mutex_lock(&mdp3_res->res_mutex);
+ mdp3_res->clk_prepare_count--;
+ if (mdp3_res->clk_prepare_count == 0) {
+ clk_unprepare(mdp3_res->clocks[MDP3_CLK_AHB]);
+ clk_unprepare(mdp3_res->clocks[MDP3_CLK_CORE]);
+ clk_unprepare(mdp3_res->clocks[MDP3_CLK_VSYNC]);
+ clk_unprepare(mdp3_res->clocks[MDP3_CLK_DSI]);
+ } else if (mdp3_res->clk_prepare_count < 0) {
+ pr_err("mdp3 clk unprepare mismatch\n");
+ }
+ mutex_unlock(&mdp3_res->res_mutex);
+}
+
+int mdp3_get_mdp_dsi_clk(void)
+{
+ int rc;
+
+ mutex_lock(&mdp3_res->res_mutex);
+ clk_prepare(mdp3_res->clocks[MDP3_CLK_DSI]);
+ rc = mdp3_clk_update(MDP3_CLK_DSI, 1);
+ mutex_unlock(&mdp3_res->res_mutex);
+ return rc;
+}
+
+int mdp3_put_mdp_dsi_clk(void)
+{
+ int rc;
+ mutex_lock(&mdp3_res->res_mutex);
+ rc = mdp3_clk_update(MDP3_CLK_DSI, 0);
+ clk_unprepare(mdp3_res->clocks[MDP3_CLK_DSI]);
mutex_unlock(&mdp3_res->res_mutex);
return rc;
}
@@ -871,7 +951,7 @@
{
char *t = NULL;
char pan_intf_str[MDSS_MAX_PANEL_LEN];
- int rc, i;
+ int rc, i, panel_len;
char pan_name[MDSS_MAX_PANEL_LEN];
if (!pan_cfg)
@@ -908,6 +988,14 @@
strlcpy(&pan_cfg->arg_cfg[0], t, sizeof(pan_cfg->arg_cfg));
pr_debug("%s:%d: t=[%s] panel name=[%s]\n", __func__, __LINE__,
t, pan_cfg->arg_cfg);
+
+ panel_len = strlen(pan_cfg->arg_cfg);
+ if (!panel_len) {
+ pr_err("%s: Panel name is invalid\n", __func__);
+ pan_cfg->pan_intf = MDSS_PANEL_INTF_INVALID;
+ return -EINVAL;
+ }
+
rc = mdp3_get_pan_intf(pan_intf_str);
pan_cfg->pan_intf = (rc < 0) ? MDSS_PANEL_INTF_INVALID : rc;
return 0;
@@ -991,10 +1079,10 @@
of_node_put(chosen_node);
rc = mdp3_get_pan_cfg(pan_cfg);
- if (!rc)
+ if (!rc) {
pan_cfg->init_done = true;
-
- return rc;
+ return rc;
+ }
get_dt_pan:
rc = mdp3_parse_dt_pan_intf(pdev);
@@ -1012,6 +1100,7 @@
static int mdp3_parse_dt(struct platform_device *pdev)
{
struct resource *res;
+ struct property *prop = NULL;
int rc;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mdp_phys");
@@ -1046,9 +1135,44 @@
return rc;
}
+ prop = of_find_property(pdev->dev.of_node, "batfet-supply", NULL);
+ mdp3_res->batfet_required = prop ? true : false;
+
return 0;
}
+void mdp3_batfet_ctrl(int enable)
+{
+ int rc;
+ if (!mdp3_res->batfet_required)
+ return;
+
+ if (!mdp3_res->batfet) {
+ if (enable) {
+ mdp3_res->batfet =
+ devm_regulator_get(&mdp3_res->pdev->dev,
+ "batfet");
+ if (IS_ERR_OR_NULL(mdp3_res->batfet)) {
+ pr_debug("unable to get batfet reg. rc=%d\n",
+ PTR_RET(mdp3_res->batfet));
+ mdp3_res->batfet = NULL;
+ return;
+ }
+ } else {
+ pr_debug("Batfet regulator disable w/o enable\n");
+ return;
+ }
+ }
+
+ if (enable)
+ rc = regulator_enable(mdp3_res->batfet);
+ else
+ rc = regulator_disable(mdp3_res->batfet);
+
+ if (rc < 0)
+ pr_err("%s: reg enable/disable failed", __func__);
+}
+
static void mdp3_iommu_heap_unmap_iommu(struct mdp3_iommu_meta *meta)
{
unsigned int domain_num;
@@ -1329,7 +1453,9 @@
ret = 0;
} else {
ret = PTR_ERR(iommu_meta);
- goto out_unlock;
+ mutex_unlock(&mdp3_res->iommu_lock);
+ pr_err("%s: meta_create failed err=%d", __func__, ret);
+ return ret;
}
} else {
if (iommu_meta->flags != iommu_flags) {
@@ -1512,8 +1638,17 @@
static int mdp3_init(struct msm_fb_data_type *mfd)
{
int rc;
+
rc = mdp3_ctrl_init(mfd);
- rc |= mdp3_ppp_res_init(mfd);
+ if (rc) {
+ pr_err("mdp3 ctl init fail\n");
+ return rc;
+ }
+
+ rc = mdp3_ppp_res_init(mfd);
+ if (rc)
+ pr_err("mdp3 ppp res init fail\n");
+
return rc;
}
@@ -1671,6 +1806,11 @@
return mdp3_res->domains[MDP3_DMA_IOMMU_DOMAIN].domain_idx;
}
+int mdp3_get_cont_spash_en(void)
+{
+ return mdp3_res->cont_splash_en;
+}
+
int mdp3_continuous_splash_copy(struct mdss_panel_data *pdata)
{
unsigned long splash_phys, phys;
@@ -1726,7 +1866,7 @@
rc = (status == 0x080000);
}
- mdp3_res->splash_mem_addr = MDP3_REG_READ(MDP3_REG_DMA_S_IBUF_ADDR);
+ mdp3_res->splash_mem_addr = MDP3_REG_READ(MDP3_REG_DMA_P_IBUF_ADDR);
mdp3_clk_update(MDP3_CLK_AHB, 0);
mdp3_clk_update(MDP3_CLK_CORE, 0);
@@ -1740,9 +1880,19 @@
pr_debug("mdp3__continuous_splash_on\n");
- rc = mdp3_clk_enable(1);
+ mdp3_clk_set_rate(MDP3_CLK_VSYNC, MDP_VSYNC_CLK_RATE,
+ MDP3_CLIENT_DMA_P);
+
+ rc = mdp3_clk_prepare();
+ if (rc) {
+ pr_err("fail to prepare clk\n");
+ return rc;
+ }
+
+ rc = mdp3_clk_enable(1, 1);
if (rc) {
pr_err("fail to enable clk\n");
+ mdp3_clk_unprepare();
return rc;
}
@@ -1776,11 +1926,16 @@
mdp3_res->intf[MDP3_DMA_OUTPUT_SEL_DSI_VIDEO].active = 1;
else
mdp3_res->intf[MDP3_DMA_OUTPUT_SEL_DSI_CMD].active = 1;
+
+ mdp3_batfet_ctrl(true);
+ mdp3_res->cont_splash_en = 1;
return 0;
splash_on_err:
- if (mdp3_clk_enable(0))
+ if (mdp3_clk_enable(0, 1))
pr_err("%s: Unable to disable mdp3 clocks\n", __func__);
+
+ mdp3_clk_unprepare();
return rc;
}
@@ -1813,10 +1968,13 @@
static void mdp3_debug_enable_clock(int on)
{
- if (on)
- mdp3_clk_enable(1);
- else
- mdp3_clk_enable(0);
+ if (on) {
+ mdp3_clk_prepare();
+ mdp3_clk_enable(1, 0);
+ } else {
+ mdp3_clk_enable(0, 0);
+ mdp3_clk_unprepare();
+ }
}
static int mdp3_debug_init(struct platform_device *pdev)
@@ -1859,6 +2017,151 @@
mdp3_res->underrun_cnt);
}
+static ssize_t mdp3_show_capabilities(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ size_t len = PAGE_SIZE;
+ int cnt = 0;
+
+#define SPRINT(fmt, ...) \
+ (cnt += scnprintf(buf + cnt, len - cnt, fmt, ##__VA_ARGS__))
+
+ SPRINT("mdp_version=3\n");
+ SPRINT("hw_rev=%d\n", 304);
+ SPRINT("dma_pipes=%d\n", 1);
+ SPRINT("\n");
+
+ return cnt;
+}
+
+static DEVICE_ATTR(caps, S_IRUGO, mdp3_show_capabilities, NULL);
+
+static struct attribute *mdp3_fs_attrs[] = {
+ &dev_attr_caps.attr,
+ NULL
+};
+
+static struct attribute_group mdp3_fs_attr_group = {
+ .attrs = mdp3_fs_attrs
+};
+
+static int mdp3_register_sysfs(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ int rc;
+
+ rc = sysfs_create_group(&dev->kobj, &mdp3_fs_attr_group);
+
+ return rc;
+}
+
+int mdp3_create_sysfs_link(struct device *dev)
+{
+ int rc;
+ rc = sysfs_create_link_nowarn(&dev->kobj,
+ &mdp3_res->pdev->dev.kobj, "mdp");
+
+ return rc;
+}
+
+int mdp3_misr_get(struct mdp_misr *misr_resp)
+{
+ int result = 0, ret = -1;
+ int crc = 0;
+ pr_debug("%s CRC Capture on DSI\n", __func__);
+ switch (misr_resp->block_id) {
+ case DISPLAY_MISR_DSI0:
+ MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_EN, 0);
+ /* Sleep for one vsync after DSI video engine is disabled */
+ msleep(20);
+ /* Enable DSI_VIDEO_0 MISR Block */
+ MDP3_REG_WRITE(MDP3_REG_MODE_DSI_PCLK, 0x20);
+ /* Reset MISR Block */
+ MDP3_REG_WRITE(MDP3_REG_MISR_RESET_DSI_PCLK, 1);
+ /* Clear MISR capture done bit */
+ MDP3_REG_WRITE(MDP3_REG_CAPTURED_DSI_PCLK, 0);
+ /* Enable MDP DSI interface */
+ MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_EN, 1);
+ ret = readl_poll_timeout(mdp3_res->mdp_base +
+ MDP3_REG_CAPTURED_DSI_PCLK, result,
+ result & MDP3_REG_CAPTURED_DSI_PCLK_MASK,
+ MISR_POLL_SLEEP, MISR_POLL_TIMEOUT);
+ MDP3_REG_WRITE(MDP3_REG_MODE_DSI_PCLK, 0);
+ if (ret == 0) {
+ /* Disable DSI MISR interface */
+ MDP3_REG_WRITE(MDP3_REG_MODE_DSI_PCLK, 0x0);
+ crc = MDP3_REG_READ(MDP3_REG_MISR_CAPT_VAL_DSI_PCLK);
+ pr_debug("CRC Val %d\n", crc);
+ } else {
+ pr_err("CRC Read Timed Out\n");
+ }
+ break;
+
+ case DISPLAY_MISR_DSI_CMD:
+ /* Select DSI PCLK Domain */
+ MDP3_REG_WRITE(MDP3_REG_SEL_CLK_OR_HCLK_TEST_BUS, 0x004);
+ /* Select Block id DSI_CMD */
+ MDP3_REG_WRITE(MDP3_REG_MODE_DSI_PCLK, 0x10);
+ /* Reset MISR Block */
+ MDP3_REG_WRITE(MDP3_REG_MISR_RESET_DSI_PCLK, 1);
+ /* Drive Data on Test Bus */
+ MDP3_REG_WRITE(MDP3_REG_EXPORT_MISR_DSI_PCLK, 0);
+ /* Kikk off DMA_P */
+ MDP3_REG_WRITE(MDP3_REG_DMA_P_START, 0x11);
+ /* Wait for DMA_P Done */
+ ret = readl_poll_timeout(mdp3_res->mdp_base +
+ MDP3_REG_INTR_STATUS, result,
+ result & MDP3_INTR_DMA_P_DONE_BIT,
+ MISR_POLL_SLEEP, MISR_POLL_TIMEOUT);
+ if (ret == 0) {
+ crc = MDP3_REG_READ(MDP3_REG_MISR_CURR_VAL_DSI_PCLK);
+ pr_debug("CRC Val %d\n", crc);
+ } else {
+ pr_err("CRC Read Timed Out\n");
+ }
+ break;
+
+ default:
+ pr_err("%s CRC Capture not supported\n", __func__);
+ ret = -EINVAL;
+ break;
+ }
+
+ misr_resp->crc_value[0] = crc;
+ pr_debug("%s, CRC Capture on DSI Param Block = 0x%x, CRC 0x%x\n",
+ __func__, misr_resp->block_id, misr_resp->crc_value[0]);
+ return ret;
+}
+
+int mdp3_misr_set(struct mdp_misr *misr_req)
+{
+ int ret = 0;
+ pr_debug("%s Parameters Block = %d Cframe Count = %d CRC = %d\n",
+ __func__, misr_req->block_id, misr_req->frame_count,
+ misr_req->crc_value[0]);
+
+ switch (misr_req->block_id) {
+ case DISPLAY_MISR_DSI0:
+ pr_debug("In the case DISPLAY_MISR_DSI0\n");
+ MDP3_REG_WRITE(MDP3_REG_SEL_CLK_OR_HCLK_TEST_BUS, 1);
+ MDP3_REG_WRITE(MDP3_REG_MODE_DSI_PCLK, 0x20);
+ MDP3_REG_WRITE(MDP3_REG_MISR_RESET_DSI_PCLK, 0x1);
+ break;
+
+ case DISPLAY_MISR_DSI_CMD:
+ pr_debug("In the case DISPLAY_MISR_DSI_CMD\n");
+ MDP3_REG_WRITE(MDP3_REG_SEL_CLK_OR_HCLK_TEST_BUS, 1);
+ MDP3_REG_WRITE(MDP3_REG_MODE_DSI_PCLK, 0x10);
+ MDP3_REG_WRITE(MDP3_REG_MISR_RESET_DSI_PCLK, 0x1);
+ break;
+
+ default:
+ pr_err("%s CRC Capture not supported\n", __func__);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
static int mdp3_probe(struct platform_device *pdev)
{
@@ -1918,6 +2221,10 @@
goto probe_done;
}
+ rc = mdp3_register_sysfs(pdev);
+ if (rc)
+ pr_err("unable to register mdp sysfs nodes\n");
+
rc = mdss_fb_register_mdp_instance(&mdp3_interface);
if (rc)
pr_err("unable to register mdp instance\n");
@@ -1973,11 +2280,13 @@
static int mdp3_suspend_sub(struct mdp3_hw_resource *mdata)
{
+ mdp3_batfet_ctrl(false);
return 0;
}
static int mdp3_resume_sub(struct mdp3_hw_resource *mdata)
{
+ mdp3_batfet_ctrl(true);
return 0;
}
diff --git a/drivers/video/msm/mdss/mdp3.h b/drivers/video/msm/mdss/mdp3.h
index 4480c20..f1f0455 100644
--- a/drivers/video/msm/mdss/mdp3.h
+++ b/drivers/video/msm/mdss/mdp3.h
@@ -25,6 +25,9 @@
#include "mdp3_dma.h"
#include "mdss_fb.h"
+#define MDP_VSYNC_CLK_RATE 19200000
+#define KOFF_TIMEOUT msecs_to_jiffies(84)
+
enum {
MDP3_CLK_AHB,
MDP3_CLK_CORE,
@@ -152,6 +155,12 @@
struct mdss_panel_cfg pan_cfg;
u32 splash_mem_addr;
u32 splash_mem_size;
+
+ int clk_prepare_count;
+ int cont_splash_en;
+
+ bool batfet_required;
+ struct regulator *batfet;
};
struct mdp3_img_data {
@@ -175,7 +184,9 @@
void mdp3_irq_register(void);
void mdp3_irq_deregister(void);
int mdp3_clk_set_rate(int clk_type, unsigned long clk_rate, int client);
-int mdp3_clk_enable(int enable);
+int mdp3_clk_enable(int enable, int dsi_clk);
+int mdp3_clk_prepare(void);
+void mdp3_clk_unprepare(void);
int mdp3_bus_scale_set_quota(int client, u64 ab_quota, u64 ib_quota);
int mdp3_put_img(struct mdp3_img_data *data, int client);
int mdp3_get_img(struct msmfb_data *img, struct mdp3_img_data *data,
@@ -186,6 +197,14 @@
void mdp3_free(void);
int mdp3_parse_dt_splash(struct msm_fb_data_type *mfd);
void mdp3_release_splash_memory(void);
+int mdp3_create_sysfs_link(struct device *dev);
+int mdp3_get_cont_spash_en(void);
+int mdp3_get_mdp_dsi_clk(void);
+int mdp3_put_mdp_dsi_clk(void);
+void mdp3_batfet_ctrl(int enable);
+
+int mdp3_misr_set(struct mdp_misr *misr_req);
+int mdp3_misr_get(struct mdp_misr *misr_resp);
#define MDP3_REG_WRITE(addr, val) writel_relaxed(val, mdp3_res->mdp_base + addr)
#define MDP3_REG_READ(addr) readl_relaxed(mdp3_res->mdp_base + addr)
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index e92e178..b204493 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -26,12 +26,18 @@
#include "mdp3_ppp.h"
#define MDP_CORE_CLK_RATE 100000000
-#define MDP_VSYNC_CLK_RATE 19200000
+#define VSYNC_EXPIRE_TICK 4
-static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd);
+static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd,
+ struct mdp_overlay *req,
+ int image_size,
+ int *pipe_ndx);
static int mdp3_overlay_unset(struct msm_fb_data_type *mfd, int ndx);
static int mdp3_histogram_stop(struct mdp3_session_data *session,
u32 block);
+static int mdp3_ctrl_clk_enable(struct msm_fb_data_type *mfd, int enable);
+static int mdp3_ctrl_vsync_enable(struct msm_fb_data_type *mfd, int enable);
+static int mdp3_ctrl_get_intf_type(struct msm_fb_data_type *mfd);
static void mdp3_bufq_init(struct mdp3_buffer_queue *bufq)
{
@@ -88,6 +94,59 @@
return bufq->count;
}
+void mdp3_ctrl_notifier_register(struct mdp3_session_data *ses,
+ struct notifier_block *notifier)
+{
+ blocking_notifier_chain_register(&ses->notifier_head, notifier);
+}
+
+void mdp3_ctrl_notifier_unregister(struct mdp3_session_data *ses,
+ struct notifier_block *notifier)
+{
+ blocking_notifier_chain_unregister(&ses->notifier_head, notifier);
+}
+
+int mdp3_ctrl_notify(struct mdp3_session_data *ses, int event)
+{
+ return blocking_notifier_call_chain(&ses->notifier_head, event, ses);
+}
+
+static void mdp3_dispatch_dma_done(struct work_struct *work)
+{
+ struct mdp3_session_data *session;
+
+ pr_debug("%s\n", __func__);
+ session = container_of(work, struct mdp3_session_data,
+ dma_done_work);
+ if (!session)
+ return;
+
+ mdp3_ctrl_notify(session, MDP_NOTIFY_FRAME_DONE);
+}
+
+static void mdp3_dispatch_clk_off(struct work_struct *work)
+{
+ struct mdp3_session_data *session;
+
+ pr_debug("%s\n", __func__);
+ session = container_of(work, struct mdp3_session_data,
+ clk_off_work);
+ if (!session)
+ return;
+
+ mutex_lock(&session->lock);
+ if (session->vsync_enabled ||
+ atomic_read(&session->vsync_countdown) != 0) {
+ mutex_unlock(&session->lock);
+ pr_debug("Ignoring clk shut down\n");
+ return;
+ }
+
+ mdp3_ctrl_vsync_enable(session->mfd, 0);
+ mdp3_ctrl_clk_enable(session->mfd, 0);
+ mutex_unlock(&session->lock);
+}
+
void vsync_notify_handler(void *arg)
{
struct mdp3_session_data *session = (struct mdp3_session_data *)arg;
@@ -95,11 +154,33 @@
sysfs_notify_dirent(session->vsync_event_sd);
}
+void dma_done_notify_handler(void *arg)
+{
+ struct mdp3_session_data *session = (struct mdp3_session_data *)arg;
+ schedule_work(&session->dma_done_work);
+}
+
+void vsync_count_down(void *arg)
+{
+ struct mdp3_session_data *session = (struct mdp3_session_data *)arg;
+ /* We are counting down to turn off clocks */
+ atomic_dec(&session->vsync_countdown);
+ if (atomic_read(&session->vsync_countdown) == 0)
+ schedule_work(&session->clk_off_work);
+}
+
+void mdp3_ctrl_reset_countdown(struct mdp3_session_data *session,
+ struct msm_fb_data_type *mfd)
+{
+ if (mdp3_ctrl_get_intf_type(mfd) == MDP3_DMA_OUTPUT_SEL_DSI_CMD)
+ atomic_set(&session->vsync_countdown, VSYNC_EXPIRE_TICK);
+}
+
static int mdp3_ctrl_vsync_enable(struct msm_fb_data_type *mfd, int enable)
{
struct mdp3_session_data *mdp3_session;
- struct mdp3_vsync_notification vsync_client;
- struct mdp3_vsync_notification *arg = NULL;
+ struct mdp3_notification vsync_client;
+ struct mdp3_notification *arg = NULL;
pr_debug("mdp3_ctrl_vsync_enable =%d\n", enable);
mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
@@ -115,24 +196,46 @@
vsync_client.handler = vsync_notify_handler;
vsync_client.arg = mdp3_session;
arg = &vsync_client;
+ } else if (atomic_read(&mdp3_session->vsync_countdown)) {
+ /*
+ * Now that vsync is no longer needed we will
+ * shutdown dsi clocks as soon as cnt down == 0
+ * for cmd mode panels
+ */
+ vsync_client.handler = vsync_count_down;
+ vsync_client.arg = mdp3_session;
+ arg = &vsync_client;
+ enable = 1;
}
- mutex_lock(&mdp3_session->lock);
+ mdp3_clk_enable(1, 0);
mdp3_session->dma->vsync_enable(mdp3_session->dma, arg);
- if (enable && mdp3_session->status == 1 && !mdp3_session->intf->active)
+ mdp3_clk_enable(0, 0);
+
+ /*
+ * Need to fake vsync whenever dsi interface is not
+ * active or when dsi clocks are currently off
+ */
+ if (enable && mdp3_session->status == 1
+ && (mdp3_session->vsync_before_commit ||
+ !mdp3_session->intf->active)) {
mod_timer(&mdp3_session->vsync_timer,
jiffies + msecs_to_jiffies(mdp3_session->vsync_period));
- else if (!enable)
+ } else if (enable && !mdp3_session->clk_on) {
+ mdp3_ctrl_reset_countdown(mdp3_session, mfd);
+ mdp3_ctrl_clk_enable(mfd, 1);
+ } else if (!enable) {
del_timer(&mdp3_session->vsync_timer);
+ }
- mutex_unlock(&mdp3_session->lock);
return 0;
}
void mdp3_vsync_timer_func(unsigned long arg)
{
struct mdp3_session_data *session = (struct mdp3_session_data *)arg;
- if (session->status == 1 && !session->intf->active) {
+ if (session->status == 1 && (session->vsync_before_commit ||
+ !session->intf->active)) {
pr_debug("mdp3_vsync_timer_func trigger\n");
vsync_notify_handler(session);
mod_timer(&session->vsync_timer,
@@ -209,6 +312,33 @@
.attrs = vsync_fs_attrs,
};
+static int mdp3_ctrl_clk_enable(struct msm_fb_data_type *mfd, int enable)
+{
+ struct mdp3_session_data *session;
+ struct mdss_panel_data *panel;
+ int rc = 0;
+
+ pr_debug("mdp3_ctrl_clk_enable %d\n", enable);
+
+ session = mfd->mdp.private1;
+ panel = session->panel;
+
+ if (!panel->event_handler)
+ return 0;
+
+ if ((enable && session->clk_on == 0) ||
+ (!enable && session->clk_on == 1)) {
+ rc = panel->event_handler(panel,
+ MDSS_EVENT_PANEL_CLK_CTRL, (void *)enable);
+ rc |= mdp3_clk_enable(enable, 1);
+ } else {
+ pr_debug("enable = %d, clk_on=%d\n", enable, session->clk_on);
+ }
+
+ session->clk_on = enable;
+ return rc;
+}
+
static int mdp3_ctrl_res_req_bus(struct msm_fb_data_type *mfd, int status)
{
int rc = 0;
@@ -236,12 +366,24 @@
mdp3_clk_set_rate(MDP3_CLK_VSYNC, MDP_VSYNC_CLK_RATE,
MDP3_CLIENT_DMA_P);
- rc = mdp3_clk_enable(true);
- if (rc)
+ rc = mdp3_clk_prepare();
+ if (rc) {
+ pr_err("mdp3 clk prepare fail\n");
return rc;
+ }
+ rc = mdp3_clk_enable(1, 1);
+ if (rc) {
+ pr_err("mdp3 clk enable fail\n");
+ mdp3_clk_unprepare();
+ return rc;
+ }
} else {
- rc = mdp3_clk_enable(false);
+ rc = mdp3_clk_enable(0, 1);
+ if (rc)
+ pr_err("mdp3 clk disable fail\n");
+ else
+ mdp3_clk_unprepare();
}
return rc;
}
@@ -265,10 +407,10 @@
return type;
}
-static int mdp3_ctrl_get_source_format(struct msm_fb_data_type *mfd)
+static int mdp3_ctrl_get_source_format(u32 imgType)
{
int format;
- switch (mfd->fb_imgType) {
+ switch (imgType) {
case MDP_RGB_565:
format = MDP3_DMA_IBUF_FORMAT_RGB565;
break;
@@ -363,6 +505,7 @@
int frame_rate = mfd->panel_info->mipi.frame_rate;
int vbp, vfp, vspw;
int vtotal, vporch;
+ struct mdp3_notification dma_done_callback;
vbp = panel_info->lcdc.v_back_porch;
vfp = panel_info->lcdc.v_front_porch;
@@ -373,7 +516,7 @@
fix = &fbi->fix;
var = &fbi->var;
- sourceConfig.format = mdp3_ctrl_get_source_format(mfd);
+ sourceConfig.format = mdp3_ctrl_get_source_format(mfd->fb_imgType);
sourceConfig.width = panel_info->xres;
sourceConfig.height = panel_info->yres;
sourceConfig.x = 0;
@@ -398,6 +541,13 @@
rc = dma->dma_config(dma, &sourceConfig, &outputConfig);
else
rc = -EINVAL;
+
+ if (outputConfig.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
+ dma_done_callback.handler = dma_done_notify_handler;
+ dma_done_callback.arg = mfd->mdp.private1;
+ dma->dma_done_notifier(dma, &dma_done_callback);
+ }
+
return rc;
}
@@ -425,6 +575,10 @@
goto on_error;
}
+ mdp3_batfet_ctrl(true);
+ mdp3_ctrl_notifier_register(mdp3_session,
+ &mdp3_session->mfd->mdp_sync_pt_data.notifier);
+
rc = mdp3_iommu_enable(MDP3_CLIENT_DMA_P);
if (rc) {
pr_err("fail to attach MDP DMA SMMU\n");
@@ -473,6 +627,7 @@
goto on_error;
}
+ mdp3_session->clk_on = 1;
pr_debug("mdp3_ctrl_on dma start\n");
if (mfd->fbi->screen_base) {
rc = mdp3_session->dma->start(mdp3_session->dma,
@@ -514,31 +669,36 @@
goto off_error;
}
+ mdp3_ctrl_clk_enable(mfd, 1);
+
mdp3_histogram_stop(mdp3_session, MDP_BLOCK_DMA_P);
rc = mdp3_session->dma->stop(mdp3_session->dma, mdp3_session->intf);
if (rc)
pr_debug("fail to stop the MDP3 dma\n");
+
if (panel->event_handler)
rc = panel->event_handler(panel, MDSS_EVENT_PANEL_OFF, NULL);
if (rc)
pr_err("fail to turn off the panel\n");
-
-
mdp3_irq_deregister();
pr_debug("mdp3_ctrl_off stop clock\n");
- rc = mdp3_ctrl_res_req_clk(mfd, 0);
- if (rc)
- pr_err("mdp clock resource release failed\n");
+ if (mdp3_session->clk_on) {
+ rc = mdp3_clk_enable(0, 1);
+ if (rc)
+ pr_err("mdp clock resource release failed\n");
- pr_debug("mdp3_ctrl_off stop dsi controller\n");
- if (panel->event_handler)
- rc = panel->event_handler(panel, MDSS_EVENT_BLANK, NULL);
- if (rc)
- pr_err("fail to turn off the panel\n");
+ pr_debug("mdp3_ctrl_off stop dsi controller\n");
+ if (panel->event_handler)
+ rc = panel->event_handler(panel,
+ MDSS_EVENT_BLANK, NULL);
+ if (rc)
+ pr_err("fail to turn off the panel\n");
+ }
+ mdp3_clk_unprepare();
pr_debug("mdp3_ctrl_off release bus\n");
rc = mdp3_ctrl_res_req_bus(mfd, 0);
@@ -549,6 +709,12 @@
if (rc)
pr_err("fail to dettach MDP DMA SMMU\n");
+ mdp3_ctrl_notifier_unregister(mdp3_session,
+ &mdp3_session->mfd->mdp_sync_pt_data.notifier);
+ mdp3_batfet_ctrl(false);
+ mdp3_session->vsync_enabled = 0;
+ atomic_set(&mdp3_session->vsync_countdown, 0);
+ mdp3_session->clk_on = 0;
off_error:
mdp3_session->status = 0;
mdp3_bufq_deinit(&mdp3_session->bufq_out);
@@ -564,7 +730,7 @@
struct mdp3_session_data *mdp3_session;
struct mdp3_dma *mdp3_dma;
struct mdss_panel_data *panel;
- struct mdp3_vsync_notification vsync_client;
+ struct mdp3_notification vsync_client;
pr_debug("mdp3_ctrl_reset_cmd\n");
mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
@@ -614,7 +780,7 @@
struct mdp3_session_data *mdp3_session;
struct mdp3_dma *mdp3_dma;
struct mdss_panel_data *panel;
- struct mdp3_vsync_notification vsync_client;
+ struct mdp3_notification vsync_client;
pr_debug("mdp3_ctrl_reset\n");
mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
@@ -647,7 +813,7 @@
if (rc)
pr_err("fail to turn off panel\n");
- rc = mdp3_ctrl_res_req_clk(mfd, 0);
+ rc = mdp3_put_mdp_dsi_clk();
if (rc) {
pr_err("fail to release mdp clocks\n");
goto reset_error;
@@ -677,7 +843,7 @@
goto reset_error;
}
- rc = mdp3_ctrl_res_req_clk(mfd, 1);
+ rc = mdp3_get_mdp_dsi_clk();
if (rc) {
pr_err("fail to turn on mdp clks\n");
goto reset_error;
@@ -722,6 +888,15 @@
{
int rc = 0;
struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
+ struct mdp3_dma *dma = mdp3_session->dma;
+ struct fb_fix_screeninfo *fix;
+ struct fb_info *fbi = mfd->fbi;
+ int stride;
+ int format;
+
+ fix = &fbi->fix;
+ stride = req->src.width * ppp_bpp(req->src.format);
+ format = mdp3_ctrl_get_source_format(req->src.format);
mutex_lock(&mdp3_session->lock);
@@ -730,6 +905,18 @@
mdp3_session->overlay = *req;
if (req->id == MSMFB_NEW_REQUEST) {
+ if (dma->source_config.stride != stride ||
+ dma->source_config.width != req->src.width ||
+ dma->source_config.height != req->src.height ||
+ dma->source_config.format != format) {
+ dma->source_config.width = req->src.width;
+ dma->source_config.height = req->src.height,
+ dma->source_config.format = format;
+ dma->source_config.stride = stride;
+ mdp3_clk_enable(1, 0);
+ mdp3_session->dma->dma_config_source(dma);
+ mdp3_clk_enable(0, 0);
+ }
mdp3_session->overlay.id = 1;
req->id = 1;
}
@@ -743,10 +930,24 @@
{
int rc = 0;
struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
+ struct fb_info *fbi = mfd->fbi;
+ struct fb_fix_screeninfo *fix;
+ struct mdss_panel_info *panel_info = mfd->panel_info;
+ int format;
+ fix = &fbi->fix;
+ format = mdp3_ctrl_get_source_format(mfd->fb_imgType);
mutex_lock(&mdp3_session->lock);
if (mdp3_session->overlay.id == ndx && ndx == 1) {
+ struct mdp3_dma *dma = mdp3_session->dma;
+ dma->source_config.width = panel_info->xres,
+ dma->source_config.height = panel_info->yres,
+ dma->source_config.format = format;
+ dma->source_config.stride = fix->line_length;
+ mdp3_clk_enable(1, 0);
+ mdp3_session->dma->dma_config_source(dma);
+ mdp3_clk_enable(0, 0);
mdp3_session->overlay.id = MSMFB_NEW_REQUEST;
mdp3_bufq_deinit(&mdp3_session->bufq_in);
} else {
@@ -840,15 +1041,31 @@
return -EPERM;
}
+ mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_BEGIN);
data = mdp3_bufq_pop(&mdp3_session->bufq_in);
if (data) {
- mdp3_session->dma->update(mdp3_session->dma,
+ mdp3_ctrl_reset_countdown(mdp3_session, mfd);
+ mdp3_ctrl_clk_enable(mfd, 1);
+ rc = mdp3_session->dma->update(mdp3_session->dma,
(void *)data->addr,
mdp3_session->intf);
+ /* This is for the previous frame */
+ if (rc < 0) {
+ mdp3_ctrl_notify(mdp3_session,
+ MDP_NOTIFY_FRAME_TIMEOUT);
+ } else {
+ if (mdp3_ctrl_get_intf_type(mfd) ==
+ MDP3_DMA_OUTPUT_SEL_DSI_VIDEO) {
+ mdp3_ctrl_notify(mdp3_session,
+ MDP_NOTIFY_FRAME_DONE);
+ }
+ }
+
+ mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_FLUSHED);
mdp3_bufq_push(&mdp3_session->bufq_out, data);
}
- if (mdp3_bufq_count(&mdp3_session->bufq_out) > 2) {
+ if (mdp3_bufq_count(&mdp3_session->bufq_out) > 1) {
data = mdp3_bufq_pop(&mdp3_session->bufq_out);
mdp3_put_img(data, MDP3_CLIENT_DMA_P);
}
@@ -858,6 +1075,8 @@
msleep(1000 / panel_info->mipi.frame_rate);
mdp3_session->first_commit = false;
}
+
+ mdp3_session->vsync_before_commit = 0;
if (reset_done && (panel && panel->set_backlight))
panel->set_backlight(panel, panel->panel_info.bl_max);
@@ -865,16 +1084,20 @@
mdss_fb_update_notify_update(mfd);
- return rc;
+ return 0;
}
-static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd)
+static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd,
+ struct mdp_overlay *req,
+ int image_size,
+ int *pipe_ndx)
{
struct fb_info *fbi;
struct mdp3_session_data *mdp3_session;
u32 offset;
int bpp;
struct mdss_panel_info *panel_info = mfd->panel_info;
+ int rc;
pr_debug("mdp3_ctrl_pan_display\n");
if (!mfd || !mfd->mdp.private1)
@@ -910,12 +1133,29 @@
}
if (mfd->fbi->screen_base) {
- mdp3_session->dma->update(mdp3_session->dma,
- (void *)mfd->iova + offset,
+ mdp3_ctrl_reset_countdown(mdp3_session, mfd);
+ mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_BEGIN);
+ mdp3_ctrl_clk_enable(mfd, 1);
+ rc = mdp3_session->dma->update(mdp3_session->dma,
+ (void *)(mfd->iova + offset),
mdp3_session->intf);
+ /* This is for the previous frame */
+ if (rc < 0) {
+ mdp3_ctrl_notify(mdp3_session,
+ MDP_NOTIFY_FRAME_TIMEOUT);
+ } else {
+ if (mdp3_ctrl_get_intf_type(mfd) ==
+ MDP3_DMA_OUTPUT_SEL_DSI_VIDEO) {
+ mdp3_ctrl_notify(mdp3_session,
+ MDP_NOTIFY_FRAME_DONE);
+ }
+ }
+ mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_FLUSHED);
} else {
pr_debug("mdp3_ctrl_pan_display no memory, stop interface");
+ mdp3_clk_enable(1, 0);
mdp3_session->dma->stop(mdp3_session->dma, mdp3_session->intf);
+ mdp3_clk_enable(0, 0);
}
if (mdp3_session->first_commit) {
@@ -924,10 +1164,28 @@
mdp3_session->first_commit = false;
}
+ mdp3_session->vsync_before_commit = 0;
+
pan_error:
mutex_unlock(&mdp3_session->lock);
}
+static int mdp3_set_metadata(struct msm_fb_data_type *mfd,
+ struct msmfb_metadata *metadata_ptr)
+{
+ int ret = 0;
+ switch (metadata_ptr->op) {
+ case metadata_op_crc:
+ ret = mdp3_misr_set(&metadata_ptr->data.misr_request);
+ break;
+ default:
+ pr_warn("Unsupported request to MDP SET META IOCTL.\n");
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
static int mdp3_get_metadata(struct msm_fb_data_type *mfd,
struct msmfb_metadata *metadata)
{
@@ -943,8 +1201,11 @@
metadata->data.caps.vig_pipes = 0;
metadata->data.caps.dma_pipes = 1;
break;
+ case metadata_op_crc:
+ ret = mdp3_misr_get(&metadata->data.misr_request);
+ break;
default:
- pr_warn("Unsupported request to MDP META IOCTL.\n");
+ pr_warn("Unsupported request to MDP GET META IOCTL.\n");
ret = -EINVAL;
break;
}
@@ -1031,10 +1292,11 @@
if (session->histo_status) {
pr_err("mdp3_histogram_start already started\n");
- ret = -EBUSY;
- goto histogram_start_err;
+ mutex_unlock(&session->histo_lock);
+ return -EBUSY;
}
+ mdp3_clk_enable(1, 0);
ret = session->dma->histo_op(session->dma, MDP3_DMA_HISTO_OP_RESET);
if (ret) {
pr_err("mdp3_histogram_start reset error\n");
@@ -1060,6 +1322,7 @@
session->histo_status = 1;
histogram_start_err:
+ mdp3_clk_enable(0, 0);
mutex_unlock(&session->histo_lock);
return ret;
}
@@ -1082,7 +1345,9 @@
goto histogram_stop_err;
}
+ mdp3_clk_enable(1, 0);
ret = session->dma->histo_op(session->dma, MDP3_DMA_HISTO_OP_CANCEL);
+ mdp3_clk_enable(0, 0);
if (ret)
pr_err("mdp3_histogram_stop error\n");
@@ -1099,11 +1364,17 @@
int ret;
struct mdp3_dma_histogram_data *mdp3_histo;
+ pr_debug("%s\n", __func__);
if (!session->dma->get_histo) {
pr_err("mdp3_histogram_collect not supported\n");
return -EINVAL;
}
+ if (!session->clk_on) {
+ pr_debug("mdp/dsi clock off currently\n");
+ return -EPERM;
+ }
+
mutex_lock(&session->histo_lock);
if (!session->histo_status) {
@@ -1114,7 +1385,9 @@
mutex_unlock(&session->histo_lock);
+ mdp3_clk_enable(1, 0);
ret = session->dma->get_histo(session->dma);
+ mdp3_clk_enable(0, 0);
if (ret) {
pr_debug("mdp3_histogram_collect error = %d\n", ret);
return ret;
@@ -1196,7 +1469,9 @@
ccs.post_lv = data->csc_data.csc_post_lv;
mutex_lock(&session->lock);
+ mdp3_clk_enable(1, 0);
ret = session->dma->config_ccs(session->dma, &config, &ccs);
+ mdp3_clk_enable(0, 0);
mutex_unlock(&session->lock);
return ret;
}
@@ -1338,8 +1613,10 @@
return -EPERM;
}
+ mdp3_clk_enable(1, 0);
rc = mdp3_session->dma->config_lut(mdp3_session->dma, &lut_config,
&lut);
+ mdp3_clk_enable(0, 0);
if (rc)
pr_err("mdp3_ctrl_lut_update failed\n");
@@ -1355,7 +1632,7 @@
int rc = -EINVAL;
struct mdp3_session_data *mdp3_session;
struct msmfb_metadata metadata;
- struct mdp_overlay req;
+ struct mdp_overlay *req = NULL;
struct msmfb_overlay_data ov_data;
int val;
@@ -1363,7 +1640,10 @@
if (!mdp3_session)
return -ENODEV;
- if (!mdp3_session->status && cmd != MSMFB_METADATA_GET) {
+ req = &mdp3_session->req_overlay;
+
+ if (!mdp3_session->status && cmd != MSMFB_METADATA_GET &&
+ cmd != MSMFB_HISTOGRAM_STOP) {
pr_err("mdp3_ctrl_ioctl_handler, display off!\n");
return -EPERM;
}
@@ -1381,7 +1661,10 @@
case MSMFB_VSYNC_CTRL:
case MSMFB_OVERLAY_VSYNC_CTRL:
if (!copy_from_user(&val, argp, sizeof(val))) {
+ mutex_lock(&mdp3_session->lock);
+ mdp3_session->vsync_enabled = val;
rc = mdp3_ctrl_vsync_enable(mfd, val);
+ mutex_unlock(&mdp3_session->lock);
} else {
pr_err("MSMFB_OVERLAY_VSYNC_CTRL failed\n");
rc = -EFAULT;
@@ -1395,30 +1678,38 @@
break;
case MSMFB_METADATA_GET:
rc = copy_from_user(&metadata, argp, sizeof(metadata));
- if (rc)
- return rc;
- rc = mdp3_get_metadata(mfd, &metadata);
+ if (!rc)
+ rc = mdp3_get_metadata(mfd, &metadata);
if (!rc)
rc = copy_to_user(argp, &metadata, sizeof(metadata));
+ if (rc)
+ pr_err("mdp3_get_metadata failed (%d)\n", rc);
+ break;
+ case MSMFB_METADATA_SET:
+ rc = copy_from_user(&metadata, argp, sizeof(metadata));
+ if (!rc)
+ rc = mdp3_set_metadata(mfd, &metadata);
+ if (rc)
+ pr_err("mdp3_set_metadata failed (%d)\n", rc);
break;
case MSMFB_OVERLAY_GET:
- rc = copy_from_user(&req, argp, sizeof(req));
+ rc = copy_from_user(req, argp, sizeof(*req));
if (!rc) {
- rc = mdp3_overlay_get(mfd, &req);
+ rc = mdp3_overlay_get(mfd, req);
if (!IS_ERR_VALUE(rc))
- rc = copy_to_user(argp, &req, sizeof(req));
+ rc = copy_to_user(argp, req, sizeof(*req));
}
if (rc)
pr_err("OVERLAY_GET failed (%d)\n", rc);
break;
case MSMFB_OVERLAY_SET:
- rc = copy_from_user(&req, argp, sizeof(req));
+ rc = copy_from_user(req, argp, sizeof(*req));
if (!rc) {
- rc = mdp3_overlay_set(mfd, &req);
+ rc = mdp3_overlay_set(mfd, req);
if (!IS_ERR_VALUE(rc))
- rc = copy_to_user(argp, &req, sizeof(req));
+ rc = copy_to_user(argp, req, sizeof(*req));
}
if (rc)
pr_err("OVERLAY_SET failed (%d)\n", rc);
@@ -1470,6 +1761,9 @@
}
memset(mdp3_session, 0, sizeof(struct mdp3_session_data));
mutex_init(&mdp3_session->lock);
+ INIT_WORK(&mdp3_session->clk_off_work, mdp3_dispatch_clk_off);
+ INIT_WORK(&mdp3_session->dma_done_work, mdp3_dispatch_dma_done);
+ atomic_set(&mdp3_session->vsync_countdown, 0);
mutex_init(&mdp3_session->histo_lock);
mdp3_session->dma = mdp3_get_dma_pipe(MDP3_DMA_CAP_ALL);
if (!mdp3_session->dma) {
@@ -1504,6 +1798,7 @@
mdp3_bufq_init(&mdp3_session->bufq_out);
mdp3_session->histo_status = 0;
mdp3_session->lut_sel = 0;
+ BLOCKING_INIT_NOTIFIER_HEAD(&mdp3_session->notifier_head);
init_timer(&mdp3_session->vsync_timer);
mdp3_session->vsync_timer.function = mdp3_vsync_timer_func;
@@ -1525,14 +1820,25 @@
goto init_done;
}
+ rc = mdp3_create_sysfs_link(dev);
+ if (rc)
+ pr_warn("problem creating link to mdp sysfs\n");
+
kobject_uevent(&dev->kobj, KOBJ_ADD);
pr_debug("vsync kobject_uevent(KOBJ_ADD)\n");
+ if (mdp3_get_cont_spash_en()) {
+ mdp3_session->clk_on = 1;
+ mdp3_ctrl_notifier_register(mdp3_session,
+ &mdp3_session->mfd->mdp_sync_pt_data.notifier);
+ }
+
if (splash_mismatch) {
pr_err("splash memory mismatch, stop splash\n");
mdp3_ctrl_off(mfd);
}
+ mdp3_session->vsync_before_commit = true;
init_done:
if (IS_ERR_VALUE(rc))
kfree(mdp3_session);
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.h b/drivers/video/msm/mdss/mdp3_ctrl.h
index 7c4f6ac..cfad1d3 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.h
+++ b/drivers/video/msm/mdss/mdp3_ctrl.h
@@ -45,13 +45,22 @@
int vsync_period;
struct sysfs_dirent *vsync_event_sd;
struct mdp_overlay overlay;
+ struct mdp_overlay req_overlay;
struct mdp3_buffer_queue bufq_in;
struct mdp3_buffer_queue bufq_out;
+ struct work_struct clk_off_work;
+ struct work_struct dma_done_work;
int histo_status;
struct mutex histo_lock;
int lut_sel;
int cc_vect_sel;
+ bool vsync_before_commit;
bool first_commit;
+ int clk_on;
+ struct blocking_notifier_head notifier_head;
+
+ int vsync_enabled;
+ atomic_t vsync_countdown; /* Used to count down */
};
int mdp3_ctrl_init(struct msm_fb_data_type *mfd);
diff --git a/drivers/video/msm/mdss/mdp3_dma.c b/drivers/video/msm/mdss/mdp3_dma.c
index 89f3e27..36d5cf1 100644
--- a/drivers/video/msm/mdss/mdp3_dma.c
+++ b/drivers/video/msm/mdss/mdp3_dma.c
@@ -27,26 +27,38 @@
static void mdp3_vsync_intr_handler(int type, void *arg)
{
struct mdp3_dma *dma = (struct mdp3_dma *)arg;
- struct mdp3_vsync_notification vsync_client;
+ struct mdp3_notification vsync_client;
+ unsigned int wait_for_next_vs;
pr_debug("mdp3_vsync_intr_handler\n");
spin_lock(&dma->dma_lock);
vsync_client = dma->vsync_client;
- complete(&dma->vsync_comp);
+ wait_for_next_vs = !dma->vsync_status;
+ dma->vsync_status = 0;
+ if (wait_for_next_vs)
+ complete(&dma->vsync_comp);
spin_unlock(&dma->dma_lock);
- if (vsync_client.handler)
+ if (vsync_client.handler) {
vsync_client.handler(vsync_client.arg);
- else
- mdp3_irq_disable_nosync(type);
+ } else {
+ if (wait_for_next_vs)
+ mdp3_irq_disable_nosync(type);
+ }
}
static void mdp3_dma_done_intr_handler(int type, void *arg)
{
struct mdp3_dma *dma = (struct mdp3_dma *)arg;
+ struct mdp3_notification dma_client;
pr_debug("mdp3_dma_done_intr_handler\n");
+ spin_lock(&dma->dma_lock);
+ dma_client = dma->dma_notifier_client;
complete(&dma->dma_comp);
+ spin_unlock(&dma->dma_lock);
mdp3_irq_disable_nosync(type);
+ if (dma_client.handler)
+ dma_client.handler(dma_client.arg);
}
static void mdp3_hist_done_intr_handler(int type, void *arg)
@@ -189,7 +201,7 @@
}
static void mdp3_dma_vsync_enable(struct mdp3_dma *dma,
- struct mdp3_vsync_notification *vsync_client)
+ struct mdp3_notification *vsync_client)
{
unsigned long flag;
int updated = 0;
@@ -220,6 +232,21 @@
}
}
+static void mdp3_dma_done_notifier(struct mdp3_dma *dma,
+ struct mdp3_notification *dma_client)
+{
+ unsigned long flag;
+
+ spin_lock_irqsave(&dma->dma_lock, flag);
+ if (dma_client) {
+ dma->dma_notifier_client = *dma_client;
+ } else {
+ dma->dma_notifier_client.handler = NULL;
+ dma->dma_notifier_client.arg = NULL;
+ }
+ spin_unlock_irqrestore(&dma->dma_lock, flag);
+}
+
static void mdp3_dma_clk_auto_gating(struct mdp3_dma *dma, int enable)
{
u32 cgc;
@@ -304,6 +331,22 @@
return 0;
}
+static void mdp3_dmap_config_source(struct mdp3_dma *dma)
+{
+ struct mdp3_dma_source *source_config = &dma->source_config;
+ u32 dma_p_cfg_reg, dma_p_size;
+
+ dma_p_cfg_reg = MDP3_REG_READ(MDP3_REG_DMA_P_CONFIG);
+ dma_p_cfg_reg &= ~MDP3_DMA_IBUF_FORMAT_MASK;
+ dma_p_cfg_reg |= source_config->format << 25;
+
+ dma_p_size = source_config->width | (source_config->height << 16);
+
+ MDP3_REG_WRITE(MDP3_REG_DMA_P_CONFIG, dma_p_cfg_reg);
+ MDP3_REG_WRITE(MDP3_REG_DMA_P_SIZE, dma_p_size);
+ MDP3_REG_WRITE(MDP3_REG_DMA_P_IBUF_Y_STRIDE, source_config->stride);
+}
+
static int mdp3_dmas_config(struct mdp3_dma *dma,
struct mdp3_dma_source *source_config,
struct mdp3_dma_output_config *output_config)
@@ -339,6 +382,22 @@
return 0;
}
+static void mdp3_dmas_config_source(struct mdp3_dma *dma)
+{
+ struct mdp3_dma_source *source_config = &dma->source_config;
+ u32 dma_s_cfg_reg, dma_s_size;
+
+ dma_s_cfg_reg = MDP3_REG_READ(MDP3_REG_DMA_S_CONFIG);
+ dma_s_cfg_reg &= ~MDP3_DMA_IBUF_FORMAT_MASK;
+ dma_s_cfg_reg |= source_config->format << 25;
+
+ dma_s_size = source_config->width | (source_config->height << 16);
+
+ MDP3_REG_WRITE(MDP3_REG_DMA_S_CONFIG, dma_s_cfg_reg);
+ MDP3_REG_WRITE(MDP3_REG_DMA_S_SIZE, dma_s_size);
+ MDP3_REG_WRITE(MDP3_REG_DMA_S_IBUF_Y_STRIDE, source_config->stride);
+}
+
static int mdp3_dmap_cursor_config(struct mdp3_dma *dma,
struct mdp3_dma_cursor *cursor)
{
@@ -529,13 +588,20 @@
{
unsigned long flag;
int cb_type = MDP3_DMA_CALLBACK_TYPE_VSYNC;
+ int rc = 0;
pr_debug("mdp3_dmap_update\n");
if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
cb_type = MDP3_DMA_CALLBACK_TYPE_DMA_DONE;
- if (intf->active)
- wait_for_completion_killable(&dma->dma_comp);
+ if (intf->active) {
+ rc = wait_for_completion_timeout(&dma->dma_comp,
+ KOFF_TIMEOUT);
+ if (rc <= 0) {
+ WARN(1, "cmd kickoff timed out (%d)\n", rc);
+ rc = -1;
+ }
+ }
}
spin_lock_irqsave(&dma->dma_lock, flag);
MDP3_REG_WRITE(MDP3_REG_DMA_P_IBUF_ADDR, (u32)buf);
@@ -550,16 +616,22 @@
intf->start(intf);
}
- wmb();
+ mb();
+ dma->vsync_status = MDP3_REG_READ(MDP3_REG_INTR_STATUS) &
+ (1 << MDP3_INTR_LCDC_START_OF_FRAME);
init_completion(&dma->vsync_comp);
spin_unlock_irqrestore(&dma->dma_lock, flag);
mdp3_dma_callback_enable(dma, cb_type);
pr_debug("mdp3_dmap_update wait for vsync_comp in\n");
- if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO)
- wait_for_completion_killable(&dma->vsync_comp);
+ if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO) {
+ rc = wait_for_completion_timeout(&dma->vsync_comp,
+ KOFF_TIMEOUT);
+ if (rc <= 0)
+ rc = -1;
+ }
pr_debug("mdp3_dmap_update wait for vsync_comp out\n");
- return 0;
+ return rc;
}
static int mdp3_dmas_update(struct mdp3_dma *dma, void *buf,
@@ -828,6 +900,9 @@
MDP3_DMA_CALLBACK_TYPE_DMA_DONE);
mdp3_irq_disable(MDP3_INTR_LCDC_UNDERFLOW);
+ MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, 0);
+ MDP3_REG_WRITE(MDP3_REG_INTR_CLEAR, 0xfffffff);
+
init_completion(&dma->dma_comp);
dma->vsync_client.handler = NULL;
return ret;
@@ -841,6 +916,7 @@
switch (dma->dma_sel) {
case MDP3_DMA_P:
dma->dma_config = mdp3_dmap_config;
+ dma->dma_config_source = mdp3_dmap_config_source;
dma->config_cursor = mdp3_dmap_cursor_config;
dma->config_ccs = mdp3_dmap_ccs_config;
dma->config_histo = mdp3_dmap_histo_config;
@@ -850,11 +926,13 @@
dma->get_histo = mdp3_dmap_histo_get;
dma->histo_op = mdp3_dmap_histo_op;
dma->vsync_enable = mdp3_dma_vsync_enable;
+ dma->dma_done_notifier = mdp3_dma_done_notifier;
dma->start = mdp3_dma_start;
dma->stop = mdp3_dma_stop;
break;
case MDP3_DMA_S:
dma->dma_config = mdp3_dmas_config;
+ dma->dma_config_source = mdp3_dmas_config_source;
dma->config_cursor = NULL;
dma->config_ccs = NULL;
dma->config_histo = NULL;
diff --git a/drivers/video/msm/mdss/mdp3_dma.h b/drivers/video/msm/mdss/mdp3_dma.h
index 6983e55..207168f 100644
--- a/drivers/video/msm/mdss/mdp3_dma.h
+++ b/drivers/video/msm/mdss/mdp3_dma.h
@@ -14,6 +14,7 @@
#ifndef MDP3_DMA_H
#define MDP3_DMA_H
+#include <linux/notifier.h>
#include <linux/sched.h>
#define MDP_HISTOGRAM_BL_SCALE_MAX 1024
@@ -227,7 +228,7 @@
u32 extra[2];
};
-struct mdp3_vsync_notification {
+struct mdp3_notification {
void (*handler)(void *arg);
void *arg;
};
@@ -245,7 +246,8 @@
struct completion vsync_comp;
struct completion dma_comp;
struct completion histo_comp;
- struct mdp3_vsync_notification vsync_client;
+ struct mdp3_notification vsync_client;
+ struct mdp3_notification dma_notifier_client;
struct mdp3_dma_output_config output_config;
struct mdp3_dma_source source_config;
@@ -256,11 +258,14 @@
struct mdp3_dma_histogram_config histogram_config;
int histo_state;
struct mdp3_dma_histogram_data histo_data;
+ unsigned int vsync_status;
int (*dma_config)(struct mdp3_dma *dma,
struct mdp3_dma_source *source_config,
struct mdp3_dma_output_config *output_config);
+ void (*dma_config_source)(struct mdp3_dma *dma);
+
int (*start)(struct mdp3_dma *dma, struct mdp3_intf *intf);
int (*stop)(struct mdp3_dma *dma, struct mdp3_intf *intf);
@@ -288,7 +293,10 @@
int (*histo_op)(struct mdp3_dma *dma, u32 op);
void (*vsync_enable)(struct mdp3_dma *dma,
- struct mdp3_vsync_notification *vsync_client);
+ struct mdp3_notification *vsync_client);
+
+ void (*dma_done_notifier)(struct mdp3_dma *dma,
+ struct mdp3_notification *dma_client);
};
struct mdp3_video_intf_cfg {
diff --git a/drivers/video/msm/mdss/mdp3_hwio.h b/drivers/video/msm/mdss/mdp3_hwio.h
index 90ee357..5205b42 100644
--- a/drivers/video/msm/mdss/mdp3_hwio.h
+++ b/drivers/video/msm/mdss/mdp3_hwio.h
@@ -55,6 +55,7 @@
#define MDP3_REG_HW_VERSION 0x0070
#define MDP3_REG_SW_RESET 0x0074
+#define MDP3_REG_SEL_CLK_OR_HCLK_TEST_BUS 0x007C
/*EBI*/
#define MDP3_REG_EBI2_LCD0 0x003c
@@ -117,6 +118,49 @@
#define MDP3_REG_DMA_S_IBUF_Y_STRIDE 0xA000C
#define MDP3_REG_DMA_S_OUT_XY 0xA0010
+/*DMA MASK*/
+#define MDP3_DMA_IBUF_FORMAT_MASK 0x06000000
+
+/*MISR*/
+#define MDP3_REG_MODE_CLK 0x000D0000
+#define MDP3_REG_MISR_RESET_CLK 0x000D0004
+#define MDP3_REG_EXPORT_MISR_CLK 0x000D0008
+#define MDP3_REG_MISR_CURR_VAL_CLK 0x000D000C
+#define MDP3_REG_MODE_HCLK 0x000D0100
+#define MDP3_REG_MISR_RESET_HCLK 0x000D0104
+#define MDP3_REG_EXPORT_MISR_HCLK 0x000D0108
+#define MDP3_REG_MISR_CURR_VAL_HCLK 0x000D010C
+#define MDP3_REG_MODE_DCLK 0x000D0200
+#define MDP3_REG_MISR_RESET_DCLK 0x000D0204
+#define MDP3_REG_EXPORT_MISR_DCLK 0x000D0208
+#define MDP3_REG_MISR_CURR_VAL_DCLK 0x000D020C
+#define MDP3_REG_CAPTURED_DCLK 0x000D0210
+#define MDP3_REG_MISR_CAPT_VAL_DCLK 0x000D0214
+#define MDP3_REG_MODE_TVCLK 0x000D0300
+#define MDP3_REG_MISR_RESET_TVCLK 0x000D0304
+#define MDP3_REG_EXPORT_MISR_TVCLK 0x000D0308
+#define MDP3_REG_MISR_CURR_VAL_TVCLK 0x000D030C
+#define MDP3_REG_CAPTURED_TVCLK 0x000D0310
+#define MDP3_REG_MISR_CAPT_VAL_TVCLK 0x000D0314
+
+/* Select DSI operation type(CMD/VIDEO) */
+#define MDP3_REG_MODE_DSI_PCLK 0x000D0400
+#define MDP3_REG_MODE_DSI_PCLK_BLOCK_DSI_CMD 0x10
+#define MDP3_REG_MODE_DSI_PCLK_BLOCK_DSI_VIDEO1 0x20
+#define MDP3_REG_MODE_DSI_PCLK_BLOCK_DSI_VIDEO2 0x30
+/* RESET DSI MISR STATE */
+#define MDP3_REG_MISR_RESET_DSI_PCLK 0x000D0404
+
+/* For reading MISR State(1) and driving data on test bus(0) */
+#define MDP3_REG_EXPORT_MISR_DSI_PCLK 0x000D0408
+/* Read MISR signature */
+#define MDP3_REG_MISR_CURR_VAL_DSI_PCLK 0x000D040C
+
+/* MISR status Bit0 (1) Capture Done */
+#define MDP3_REG_CAPTURED_DSI_PCLK 0x000D0410
+#define MDP3_REG_MISR_CAPT_VAL_DSI_PCLK 0x000D0414
+#define MDP3_REG_MISR_TESTBUS_CAPT_VAL 0x000D0600
+
/*interface*/
#define MDP3_REG_LCDC_EN 0xE0000
#define MDP3_REG_LCDC_HSYNC_CTL 0xE0004
@@ -221,6 +265,9 @@
#define MDP3_PPP_BG_UNPACK_PATTERN1 0x101D8
#define MDP3_PPP_BG_UNPACK_PATTERN2 0x101DC
+#define MDP3_TFETCH_SOLID_FILL 0x20004
+#define MDP3_TFETCH_FILL_COLOR 0x20040
+
#define MDP3_PPP_BLEND_PARAM 0x1014C
#define MDP3_PPP_BLEND_BG_ALPHA_SEL 0x70010
diff --git a/drivers/video/msm/mdss/mdp3_ppp.c b/drivers/video/msm/mdss/mdp3_ppp.c
index d16cb3f..71cbbe4 100644
--- a/drivers/video/msm/mdss/mdp3_ppp.c
+++ b/drivers/video/msm/mdss/mdp3_ppp.c
@@ -36,6 +36,8 @@
#define MDP_PPP_MAX_BPP 4
#define MDP_PPP_DYNAMIC_FACTOR 3
#define MDP_PPP_MAX_READ_WRITE 3
+#define ENABLE_SOLID_FILL 0x2
+#define DISABLE_SOLID_FILL 0x0
static const bool valid_fmt[MDP_IMGTYPE_LIMIT] = {
[MDP_RGB_565] = true,
@@ -281,7 +283,7 @@
spin_unlock_irqrestore(&ppp_stat->ppp_lock, flag);
if (wait) {
- ret = wait_for_completion_interruptible_timeout(
+ ret = wait_for_completion_timeout(
&ppp_stat->ppp_comp, 5 * HZ);
if (!ret)
pr_err("%s: Timed out waiting for the MDP.\n",
@@ -370,14 +372,14 @@
ib = (ab * 3) / 2;
}
mdp3_clk_set_rate(MDP3_CLK_CORE, rate, MDP3_CLIENT_PPP);
- rc = mdp3_clk_enable(on_off);
+ rc = mdp3_clk_enable(on_off, 0);
if (rc < 0) {
pr_err("%s: mdp3_clk_enable failed\n", __func__);
return rc;
}
rc = mdp3_bus_scale_set_quota(MDP3_CLIENT_PPP, ab, ib);
if (rc < 0) {
- mdp3_clk_enable(!on_off);
+ mdp3_clk_enable(!on_off, 0);
pr_err("%s: scale_set_quota failed\n", __func__);
return rc;
}
@@ -390,15 +392,67 @@
/* Wait for the pipe to clear */
do { } while (mdp3_ppp_pipe_wait() <= 0);
config_ppp_op_mode(blit_op);
+ if (blit_op->solid_fill) {
+ MDP3_REG_WRITE(0x10138, 0x10000000);
+ MDP3_REG_WRITE(0x1014c, 0xffffffff);
+ MDP3_REG_WRITE(0x101b8, 0);
+ MDP3_REG_WRITE(0x101bc, 0);
+ MDP3_REG_WRITE(0x1013c, 0);
+ MDP3_REG_WRITE(0x10140, 0);
+ MDP3_REG_WRITE(0x10144, 0);
+ MDP3_REG_WRITE(0x10148, 0);
+ MDP3_REG_WRITE(MDP3_TFETCH_FILL_COLOR,
+ blit_op->solid_fill_color);
+ MDP3_REG_WRITE(MDP3_TFETCH_SOLID_FILL,
+ ENABLE_SOLID_FILL);
+ } else {
+ MDP3_REG_WRITE(MDP3_TFETCH_SOLID_FILL,
+ DISABLE_SOLID_FILL);
+ }
mdp3_ppp_kickoff();
}
-static void mdp3_ppp_process_req(struct ppp_blit_op *blit_op,
+static int solid_fill_workaround(struct mdp_blit_req *req,
+ struct ppp_blit_op *blit_op)
+{
+ /* Make width 2 when there is a solid fill of width 1, and make
+ sure width does not become zero while trying to avoid odd width */
+ if (blit_op->dst.roi.width == 1) {
+ if (req->dst_rect.x + 2 > req->dst.width) {
+ pr_err("%s: Unable to handle solid fill of width 1",
+ __func__);
+ return -EINVAL;
+ }
+ blit_op->dst.roi.width = 2;
+ }
+ if (blit_op->src.roi.width == 1) {
+ if (req->src_rect.x + 2 > req->src.width) {
+ pr_err("%s: Unable to handle solid fill of width 1",
+ __func__);
+ return -EINVAL;
+ }
+ blit_op->src.roi.width = 2;
+ }
+
+ /* Avoid odd width, as it could hang ppp during solid fill */
+ blit_op->dst.roi.width = (blit_op->dst.roi.width / 2) * 2;
+ blit_op->src.roi.width = (blit_op->src.roi.width / 2) * 2;
+
+ /* Avoid RGBA format, as it could hang ppp during solid fill */
+ if (blit_op->src.color_fmt == MDP_RGBA_8888)
+ blit_op->src.color_fmt = MDP_RGBX_8888;
+ if (blit_op->dst.color_fmt == MDP_RGBA_8888)
+ blit_op->dst.color_fmt = MDP_RGBX_8888;
+ return 0;
+}
+
+static int mdp3_ppp_process_req(struct ppp_blit_op *blit_op,
struct mdp_blit_req *req, struct mdp3_img_data *src_data,
struct mdp3_img_data *dst_data)
{
unsigned long srcp0_start, srcp0_len, dst_start, dst_len;
uint32_t dst_width, dst_height;
+ int ret = 0;
srcp0_start = (unsigned long) src_data->addr;
srcp0_len = (unsigned long) src_data->len;
@@ -489,6 +543,21 @@
if (req->flags & MDP_BLUR)
blit_op->mdp_op |= MDPOP_ASCALE | MDPOP_BLUR;
+
+ if (req->flags & MDP_SOLID_FILL) {
+ ret = solid_fill_workaround(req, blit_op);
+ if (ret)
+ return ret;
+
+ blit_op->solid_fill_color = (req->const_color.g & 0xFF)|
+ (req->const_color.r & 0xFF) << 8 |
+ (req->const_color.b & 0xFF) << 16 |
+ (req->const_color.alpha & 0xFF) << 24;
+ blit_op->solid_fill = true;
+ } else {
+ blit_op->solid_fill = false;
+ }
+ return ret;
}
static void mdp3_ppp_tile_workaround(struct ppp_blit_op *blit_op,
@@ -587,6 +656,7 @@
struct mdp3_img_data *dst_data)
{
struct ppp_blit_op blit_op;
+ int ret = 0;
memset(&blit_op, 0, sizeof(blit_op));
@@ -600,7 +670,11 @@
return -EINVAL;
}
- mdp3_ppp_process_req(&blit_op, req, src_data, dst_data);
+ ret = mdp3_ppp_process_req(&blit_op, req, src_data, dst_data);
+ if (ret) {
+ pr_err("%s: Failed to process the blit request", __func__);
+ return ret;
+ }
if (((blit_op.mdp_op & (MDPOP_TRANSP | MDPOP_ALPHAB)) ||
(req->src.format == MDP_ARGB_8888) ||
@@ -791,9 +865,10 @@
}
is_bpp_4 = (ret == 4) ? 1 : 0;
- if ((is_bpp_4 && (remainder == 6 || remainder == 14)))
+ if ((is_bpp_4 && (remainder == 6 || remainder == 14)) &&
+ !(req->flags & MDP_SOLID_FILL))
ret = mdp3_ppp_blit_workaround(mfd, req, remainder,
- src_data, dst_data);
+ src_data, dst_data);
else
ret = mdp3_ppp_blit(mfd, req, src_data, dst_data);
return ret;
@@ -1024,7 +1099,7 @@
while (req_q->count >= MDP3_PPP_MAX_LIST_REQ) {
ppp_stat->wait_for_pop = true;
mutex_unlock(&ppp_stat->req_mutex);
- rc = wait_for_completion_interruptible_timeout(
+ rc = wait_for_completion_timeout(
&ppp_stat->pop_q_comp, 5 * HZ);
if (rc == 0) {
/* This will only occur if there is serious problem */
diff --git a/drivers/video/msm/mdss/mdp3_ppp.h b/drivers/video/msm/mdss/mdp3_ppp.h
index b4252ca..9753e94 100644
--- a/drivers/video/msm/mdss/mdp3_ppp.h
+++ b/drivers/video/msm/mdss/mdp3_ppp.h
@@ -332,6 +332,8 @@
struct ppp_img_desc bg;
struct ppp_blend blend;
uint32_t mdp_op; /* Operations */
+ uint32_t solid_fill_color;
+ bool solid_fill;
};
struct ppp_edge_rep {
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index 61c4acd..ce4005e 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -66,6 +66,19 @@
void (*debug_enable_clock)(int on);
};
+#define MDSS_IRQ_SUSPEND -1
+#define MDSS_IRQ_RESUME 1
+#define MDSS_IRQ_REQ 0
+
+struct mdss_intr {
+ /* requested intr */
+ u32 req;
+ /* currently enabled intr */
+ u32 curr;
+ int state;
+ spinlock_t lock;
+};
+
struct mdss_data_type {
u32 mdp_rev;
struct clk *mdp_clk[MDSS_MAX_CLK];
@@ -107,6 +120,9 @@
u32 rot_block_size;
+ u32 max_bw_low;
+ u32 max_bw_high;
+
struct mdss_hw_settings *hw_settings;
struct mdss_mdp_pipe *vig_pipes;
@@ -130,10 +146,14 @@
u32 nintf;
u32 pp_bus_hdl;
+ struct mdss_mdp_ad *ad_off;
struct mdss_ad_info *ad_cfgs;
u32 nad_cfgs;
+ u32 nmax_concurrent_ad_hw;
struct workqueue_struct *ad_calc_wq;
+ struct mdss_intr hist_intr;
+
struct ion_client *iclient;
int iommu_attached;
struct mdss_iommu_map_type *iommu_map;
diff --git a/drivers/video/msm/mdss/mdss_debug.c b/drivers/video/msm/mdss/mdss_debug.c
index f933c8e..0d0240f 100644
--- a/drivers/video/msm/mdss/mdss_debug.c
+++ b/drivers/video/msm/mdss/mdss_debug.c
@@ -23,12 +23,13 @@
#include "mdss.h"
#include "mdss_mdp.h"
+#include "mdss_mdp_hwio.h"
#include "mdss_debug.h"
#define DEFAULT_BASE_REG_CNT 0x100
#define GROUP_BYTES 4
#define ROW_BYTES 16
-
+#define MAX_VSYNC_COUNT 0xFFFFFFF
struct mdss_debug_data {
struct dentry *root;
struct list_head base_list;
@@ -409,28 +410,63 @@
return 0;
}
+int vsync_count;
static struct mdss_mdp_misr_map {
u32 ctrl_reg;
u32 value_reg;
u32 crc_op_mode;
u32 crc_index;
- u32 crc_value[MISR_CRC_BATCH_SIZE];
+ bool use_ping;
+ bool is_ping_full;
+ bool is_pong_full;
+ struct mutex crc_lock;
+ u32 crc_ping[MISR_CRC_BATCH_SIZE];
+ u32 crc_pong[MISR_CRC_BATCH_SIZE];
} mdss_mdp_misr_table[DISPLAY_MISR_MAX] = {
[DISPLAY_MISR_DSI0] = {
.ctrl_reg = MDSS_MDP_LP_MISR_CTRL_DSI0,
.value_reg = MDSS_MDP_LP_MISR_SIGN_DSI0,
+ .crc_op_mode = 0,
+ .crc_index = 0,
+ .use_ping = true,
+ .is_ping_full = false,
+ .is_pong_full = false,
},
[DISPLAY_MISR_DSI1] = {
.ctrl_reg = MDSS_MDP_LP_MISR_CTRL_DSI1,
.value_reg = MDSS_MDP_LP_MISR_SIGN_DSI1,
+ .crc_op_mode = 0,
+ .crc_index = 0,
+ .use_ping = true,
+ .is_ping_full = false,
+ .is_pong_full = false,
},
[DISPLAY_MISR_EDP] = {
.ctrl_reg = MDSS_MDP_LP_MISR_CTRL_EDP,
.value_reg = MDSS_MDP_LP_MISR_SIGN_EDP,
+ .crc_op_mode = 0,
+ .crc_index = 0,
+ .use_ping = true,
+ .is_ping_full = false,
+ .is_pong_full = false,
},
[DISPLAY_MISR_HDMI] = {
.ctrl_reg = MDSS_MDP_LP_MISR_CTRL_HDMI,
.value_reg = MDSS_MDP_LP_MISR_SIGN_HDMI,
+ .crc_op_mode = 0,
+ .crc_index = 0,
+ .use_ping = true,
+ .is_ping_full = false,
+ .is_pong_full = false,
+ },
+ [DISPLAY_MISR_MDP] = {
+ .ctrl_reg = MDSS_MDP_LP_MISR_CTRL_MDP,
+ .value_reg = MDSS_MDP_LP_MISR_SIGN_MDP,
+ .crc_op_mode = 0,
+ .crc_index = 0,
+ .use_ping = true,
+ .is_ping_full = false,
+ .is_pong_full = false,
},
};
@@ -438,7 +474,7 @@
{
struct mdss_mdp_misr_map *map;
- if (block_id > DISPLAY_MISR_LCDC) {
+ if (block_id > DISPLAY_MISR_MDP) {
pr_err("MISR Block id (%d) out of range\n", block_id);
return NULL;
}
@@ -452,23 +488,51 @@
return map;
}
-int mdss_misr_crc_set(struct mdss_data_type *mdata, struct mdp_misr *req)
+int mdss_misr_set(struct mdss_data_type *mdata,
+ struct mdp_misr *req,
+ struct mdss_mdp_ctl *ctl)
{
struct mdss_mdp_misr_map *map;
- u32 config = 0;
-
+ struct mdss_mdp_mixer *mixer;
+ u32 config = 0, val = 0;
+ u32 mixer_num = 0;
+ bool is_valid_wb_mixer = true;
map = mdss_misr_get_map(req->block_id);
if (!map) {
pr_err("Invalid MISR Block=%d\n", req->block_id);
return -EINVAL;
}
-
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ if (req->block_id == DISPLAY_MISR_MDP) {
+ mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_DEFAULT);
+ mixer_num = mixer->num;
+ pr_debug("SET MDP MISR BLK to MDSS_MDP_LP_MISR_SEL_LMIX%d_GC\n",
+ req->block_id);
+ switch (mixer_num) {
+ case MDSS_MDP_INTF_LAYERMIXER0:
+ pr_debug("Use Layer Mixer 0 for WB CRC\n");
+ val = MDSS_MDP_LP_MISR_SEL_LMIX0_GC;
+ break;
+ case MDSS_MDP_INTF_LAYERMIXER1:
+ pr_debug("Use Layer Mixer 1 for WB CRC\n");
+ val = MDSS_MDP_LP_MISR_SEL_LMIX1_GC;
+ break;
+ case MDSS_MDP_INTF_LAYERMIXER2:
+ pr_debug("Use Layer Mixer 2 for WB CRC\n");
+ val = MDSS_MDP_LP_MISR_SEL_LMIX2_GC;
+ break;
+ default:
+ pr_err("Invalid Layer Mixer %d selected for WB CRC\n",
+ mixer_num);
+ is_valid_wb_mixer = false;
+ break;
+ }
+ if (is_valid_wb_mixer)
+ writel_relaxed(val,
+ mdata->mdp_base + MDSS_MDP_LP_MISR_SEL);
+ }
+ vsync_count = 0;
map->crc_op_mode = req->crc_op_mode;
- memset(map->crc_value, 0, sizeof(map->crc_value));
-
- pr_debug("MISR Config (BlockId %d) (Frame Count = %d)\n",
- req->block_id, req->frame_count);
-
config = (MDSS_MDP_LP_MISR_CTRL_FRAME_COUNT_MASK & req->frame_count) |
(MDSS_MDP_LP_MISR_CTRL_ENABLE);
@@ -476,24 +540,32 @@
mdata->mdp_base + map->ctrl_reg);
/* ensure clear is done */
wmb();
- if (MISR_OP_BM == map->crc_op_mode) {
- writel_relaxed(MISR_CRC_BATCH_CFG,
- mdata->mdp_base + map->ctrl_reg);
- } else {
- writel_relaxed(config,
- mdata->mdp_base + map->ctrl_reg);
- config = readl_relaxed(mdata->mdp_base + map->ctrl_reg);
- pr_debug("MISR_CTRL = 0x%x", config);
+ memset(map->crc_ping, 0, sizeof(map->crc_ping));
+ memset(map->crc_pong, 0, sizeof(map->crc_pong));
+ map->crc_index = 0;
+ map->use_ping = true;
+ map->is_ping_full = false;
+ map->is_pong_full = false;
+
+ if (MISR_OP_BM != map->crc_op_mode) {
+
+ writel_relaxed(config,
+ mdata->mdp_base + map->ctrl_reg);
+ pr_debug("MISR_CTRL = 0x%x",
+ readl_relaxed(mdata->mdp_base + map->ctrl_reg));
}
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
return 0;
}
-int mdss_misr_crc_get(struct mdss_data_type *mdata, struct mdp_misr *resp)
+int mdss_misr_get(struct mdss_data_type *mdata,
+ struct mdp_misr *resp,
+ struct mdss_mdp_ctl *ctl)
{
struct mdss_mdp_misr_map *map;
u32 status;
- int ret = 0;
+ int ret = -1;
int i;
map = mdss_misr_get_map(resp->block_id);
@@ -501,35 +573,60 @@
pr_err("Invalid MISR Block=%d\n", resp->block_id);
return -EINVAL;
}
-
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
switch (map->crc_op_mode) {
case MISR_OP_SFM:
case MISR_OP_MFM:
ret = readl_poll_timeout(mdata->mdp_base + map->ctrl_reg,
status, status & MDSS_MDP_LP_MISR_CTRL_STATUS,
MISR_POLL_SLEEP, MISR_POLL_TIMEOUT);
-
- pr_debug("Status of Get MISR_CTRL = 0x%x", status);
if (ret == 0) {
- resp->crc_value[0] =
- readl_relaxed(mdata->mdp_base + map->value_reg);
+ resp->crc_value[0] = readl_relaxed(mdata->mdp_base +
+ map->value_reg);
pr_debug("CRC %d=0x%x\n", resp->block_id,
- resp->crc_value[0]);
+ resp->crc_value[0]);
+ writel_relaxed(0, mdata->mdp_base + map->ctrl_reg);
} else {
- pr_warn("MISR %d busy with status 0x%x\n",
- resp->block_id, status);
+ mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_START, 1);
+ ret = readl_poll_timeout(mdata->mdp_base +
+ map->ctrl_reg, status,
+ status & MDSS_MDP_LP_MISR_CTRL_STATUS,
+ MISR_POLL_SLEEP, MISR_POLL_TIMEOUT);
+ if (ret == 0) {
+ resp->crc_value[0] =
+ readl_relaxed(mdata->mdp_base +
+ map->value_reg);
+ }
+ writel_relaxed(0, mdata->mdp_base + map->ctrl_reg);
}
break;
case MISR_OP_BM:
- for (i = 0; i < MISR_CRC_BATCH_SIZE; i++)
- resp->crc_value[i] = map->crc_value[i];
- map->crc_index = 0;
+ if (map->is_ping_full) {
+ for (i = 0; i < MISR_CRC_BATCH_SIZE; i++)
+ resp->crc_value[i] = map->crc_ping[i];
+ memset(map->crc_ping, 0, sizeof(map->crc_ping));
+ map->is_ping_full = false;
+ ret = 0;
+ } else if (map->is_pong_full) {
+ for (i = 0; i < MISR_CRC_BATCH_SIZE; i++)
+ resp->crc_value[i] = map->crc_pong[i];
+ memset(map->crc_pong, 0, sizeof(map->crc_pong));
+ map->is_pong_full = false;
+ ret = 0;
+ } else {
+ pr_debug("mdss_mdp_misr_crc_get PING BUF %s\n",
+ map->is_ping_full ? "FULL" : "EMPTRY");
+ pr_debug("mdss_mdp_misr_crc_get PONG BUF %s\n",
+ map->is_pong_full ? "FULL" : "EMPTRY");
+ }
+ resp->crc_op_mode = map->crc_op_mode;
break;
default:
ret = -ENOSYS;
break;
}
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
return ret;
}
@@ -537,22 +634,71 @@
void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id)
{
struct mdss_mdp_misr_map *map;
- u32 status, config;
+ u32 status = 0;
+ u32 crc = 0x0BAD0BAD;
+ bool crc_stored = false;
map = mdss_misr_get_map(block_id);
if (!map || (map->crc_op_mode != MISR_OP_BM))
return;
- config = MISR_CRC_BATCH_CFG;
-
status = readl_relaxed(mdata->mdp_base + map->ctrl_reg);
- if (status & MDSS_MDP_LP_MISR_CTRL_STATUS) {
- map->crc_value[map->crc_index] =
- readl_relaxed(mdata->mdp_base + map->value_reg);
- map->crc_index++;
- if (map->crc_index == MISR_CRC_BATCH_SIZE)
- map->crc_index = 0;
- config |= MDSS_MDP_LP_MISR_CTRL_STATUS_CLEAR;
+ if (MDSS_MDP_LP_MISR_CTRL_STATUS & status) {
+ crc = readl_relaxed(mdata->mdp_base + map->value_reg);
+ if (map->use_ping) {
+ if (map->is_ping_full) {
+ pr_err("PING Buffer FULL\n");
+ } else {
+ map->crc_ping[map->crc_index] = crc;
+ crc_stored = true;
+ }
+ } else {
+ if (map->is_pong_full) {
+ pr_err("PONG Buffer FULL\n");
+ } else {
+ map->crc_pong[map->crc_index] = crc;
+ crc_stored = true;
+ }
+ }
+
+ if (crc_stored) {
+ map->crc_index = (map->crc_index + 1);
+ if (map->crc_index == MISR_CRC_BATCH_SIZE) {
+ map->crc_index = 0;
+ if (true == map->use_ping) {
+ map->is_ping_full = true;
+ map->use_ping = false;
+ } else {
+ map->is_pong_full = true;
+ map->use_ping = true;
+ }
+ pr_debug("USE BUFF %s\n", map->use_ping ?
+ "PING" : "PONG");
+ pr_debug("mdss_misr_crc_collect PING BUF %s\n",
+ map->is_ping_full ? "FULL" : "EMPTRY");
+ pr_debug("mdss_misr_crc_collect PONG BUF %s\n",
+ map->is_pong_full ? "FULL" : "EMPTRY");
+ }
+ } else {
+ pr_err("CRC(%d) Not saved\n", crc);
+ }
+
+ writel_relaxed(MDSS_MDP_LP_MISR_CTRL_STATUS_CLEAR,
+ mdata->mdp_base + map->ctrl_reg);
+ writel_relaxed(MISR_CRC_BATCH_CFG,
+ mdata->mdp_base + map->ctrl_reg);
+ } else if (0 == status) {
+ writel_relaxed(MISR_CRC_BATCH_CFG,
+ mdata->mdp_base + map->ctrl_reg);
+ pr_debug("$$ Batch CRC Start $$\n");
}
- writel_relaxed(config, mdata->mdp_base + map->ctrl_reg);
+ pr_debug("$$ Vsync Count = %d, CRC=0x%x Indx = %d$$\n",
+ vsync_count, crc, map->crc_index);
+
+ if (MAX_VSYNC_COUNT == vsync_count) {
+ pr_err("RESET vsync_count(%d)\n", vsync_count);
+ vsync_count = 0;
+ } else {
+ vsync_count += 1;
+ }
}
diff --git a/drivers/video/msm/mdss/mdss_debug.h b/drivers/video/msm/mdss/mdss_debug.h
index 29eb16c..984caab 100644
--- a/drivers/video/msm/mdss/mdss_debug.h
+++ b/drivers/video/msm/mdss/mdss_debug.h
@@ -16,30 +16,35 @@
#include "mdss.h"
-#define MISR_POLL_SLEEP 2000
-#define MISR_POLL_TIMEOUT 32000
-#define MISR_CRC_BATCH_SIZE 32
-#define MISR_CRC_BATCH_CFG 0x101
+#define MISR_POLL_SLEEP 2000
+#define MISR_POLL_TIMEOUT 32000
+#define MISR_CRC_BATCH_CFG 0x101
#ifdef CONFIG_DEBUG_FS
int mdss_debugfs_init(struct mdss_data_type *mdata);
int mdss_debugfs_remove(struct mdss_data_type *mdata);
int mdss_debug_register_base(const char *name, void __iomem *base,
size_t max_offset);
-int mdss_misr_crc_set(struct mdss_data_type *mdata, struct mdp_misr *req);
-int mdss_misr_crc_get(struct mdss_data_type *mdata, struct mdp_misr *resp);
+int mdss_misr_set(struct mdss_data_type *mdata, struct mdp_misr *req,
+ struct mdss_mdp_ctl *ctl);
+int mdss_misr_get(struct mdss_data_type *mdata, struct mdp_misr *resp,
+ struct mdss_mdp_ctl *ctl);
void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id);
#else
static inline int mdss_debugfs_init(struct mdss_data_type *mdata) { return 0; }
static inline int mdss_debugfs_remove(struct mdss_data_type *mdata)
{ return 0; }
static inline int mdss_debug_register_base(const char *name, void __iomem *base,
- size_t max_offset) { return 0; }
-static inline int mdss_misr_crc_set(struct mdss_data_type *mdata,
- struct mdp_misr *reg) { return 0; }
-static inline int mdss_misr_crc_get(struct mdss_data_type *mdata,
- struct mdp_misr *resp) { return 0; }
+ size_t max_offset) { return 0; }
+static inline int mdss_misr_set(struct mdss_data_type *mdata,
+ struct mdp_misr *req,
+ struct mdss_mdp_ctl *ctl)
+{ return 0; }
+static inline int mdss_misr_get(struct mdss_data_type *mdata,
+ struct mdp_misr *resp,
+ struct mdss_mdp_ctl *ctl)
+{ return 0; }
static inline void mdss_misr_crc_collect(struct mdss_data_type *mdata,
- int block_id) { }
+ int block_id) { }
#endif
#endif /* MDSS_DEBUG_H */
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index 865775a..54c8a06 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -377,19 +377,24 @@
pinfo = &pdata->panel_info;
- ret = mdss_dsi_panel_power_on(pdata, 1);
+ ret = msm_dss_enable_vreg(ctrl_pdata->power_data.vreg_config,
+ ctrl_pdata->power_data.num_vreg, 1);
if (ret) {
- pr_err("%s: Panel power on failed\n", __func__);
+ pr_err("%s:Failed to enable vregs. rc=%d\n", __func__, ret);
return ret;
}
pdata->panel_info.panel_power_on = 1;
+ if (!pdata->panel_info.mipi.lp11_init)
+ mdss_dsi_panel_reset(pdata, 1);
+
ret = mdss_dsi_enable_bus_clocks(ctrl_pdata);
if (ret) {
pr_err("%s: failed to enable bus clocks. rc=%d\n", __func__,
ret);
mdss_dsi_panel_power_on(pdata, 0);
+ pdata->panel_info.panel_power_on = 0;
return ret;
}
@@ -470,6 +475,16 @@
mdss_dsi_sw_reset(pdata);
mdss_dsi_host_init(mipi, pdata);
+ /*
+ * Issue hardware reset line after enabling the DSI clocks and data
+ * data lanes for LP11 init
+ */
+ if (pdata->panel_info.mipi.lp11_init)
+ mdss_dsi_panel_reset(pdata, 1);
+
+ if (pdata->panel_info.mipi.init_delay)
+ usleep(pdata->panel_info.mipi.init_delay);
+
if (mipi->force_clk_lane_hs) {
u32 tmp;
@@ -778,6 +793,21 @@
return rc;
}
+static struct device_node *mdss_dsi_pref_prim_panel(
+ struct platform_device *pdev)
+{
+ struct device_node *dsi_pan_node = NULL;
+
+ pr_debug("%s:%d: Select primary panel from dt\n",
+ __func__, __LINE__);
+ dsi_pan_node = of_parse_phandle(pdev->dev.of_node,
+ "qcom,dsi-pref-prim-pan", 0);
+ if (!dsi_pan_node)
+ pr_err("%s:can't find panel phandle\n", __func__);
+
+ return dsi_pan_node;
+}
+
/**
* mdss_dsi_find_panel_of_node(): find device node of dsi panel
* @pdev: platform_device of the dsi ctrl node
@@ -805,14 +835,7 @@
/* no panel cfg chg, parse dt */
pr_debug("%s:%d: no cmd line cfg present\n",
__func__, __LINE__);
- dsi_pan_node = of_parse_phandle(
- pdev->dev.of_node,
- "qcom,dsi-pref-prim-pan", 0);
- if (!dsi_pan_node) {
- pr_err("%s:can't find panel phandle\n",
- __func__);
- return NULL;
- }
+ dsi_pan_node = mdss_dsi_pref_prim_panel(pdev);
} else {
if (panel_cfg[0] == '0') {
pr_debug("%s:%d: DSI ctrl 1\n", __func__, __LINE__);
@@ -845,11 +868,12 @@
dsi_pan_node = of_find_node_by_name(mdss_node,
panel_name);
if (!dsi_pan_node) {
- pr_err("%s: invalid pan node\n",
+ pr_err("%s: invalid pan node, selecting prim panel\n",
__func__);
- return NULL;
+ dsi_pan_node = mdss_dsi_pref_prim_panel(pdev);
}
}
+
return dsi_pan_node;
}
@@ -1216,7 +1240,8 @@
}
}
- if (gpio_is_valid(ctrl_pdata->disp_te_gpio)) {
+ if (gpio_is_valid(ctrl_pdata->disp_te_gpio) &&
+ pinfo->type == MIPI_CMD_PANEL) {
rc = gpio_request(ctrl_pdata->disp_te_gpio, "disp_te");
if (rc) {
pr_err("request TE gpio failed, rc=%d\n",
@@ -1304,6 +1329,7 @@
}
ctrl_pdata->panel_data.event_handler = mdss_dsi_event_handler;
+ ctrl_pdata->check_status = mdss_dsi_bta_status_check;
if (ctrl_pdata->bklt_ctrl == BL_PWM)
mdss_dsi_panel_pwm_cfg(ctrl_pdata);
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index 13dad06..b89a935 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -19,6 +19,7 @@
#include "mdss_panel.h"
#include "mdss_io_util.h"
+#include "mdss_dsi_cmd.h"
#define MMSS_SERDES_BASE_PHY 0x04f01000 /* mmss (De)Serializer CFG */
@@ -89,6 +90,17 @@
DSI_HS_MODE,
};
+enum dsi_lane_map_type {
+ DSI_LANE_MAP_0123,
+ DSI_LANE_MAP_3012,
+ DSI_LANE_MAP_2301,
+ DSI_LANE_MAP_1230,
+ DSI_LANE_MAP_0321,
+ DSI_LANE_MAP_1032,
+ DSI_LANE_MAP_2103,
+ DSI_LANE_MAP_3210,
+};
+
#define CTRL_STATE_UNKNOWN 0x00
#define CTRL_STATE_PANEL_INIT BIT(0)
#define CTRL_STATE_MDP_ACTIVE BIT(1)
@@ -118,6 +130,8 @@
#define DSI_INTR_ERROR_MASK BIT(25)
#define DSI_INTR_ERROR BIT(24)
+#define DSI_INTR_BTA_DONE_MASK BIT(21)
+#define DSI_INTR_BTA_DONE BIT(20)
#define DSI_INTR_VIDEO_DONE_MASK BIT(17)
#define DSI_INTR_VIDEO_DONE BIT(16)
#define DSI_INTR_CMD_MDP_DONE_MASK BIT(9)
@@ -133,6 +147,7 @@
#define DSI_VIDEO_TERM BIT(16)
#define DSI_MDP_TERM BIT(8)
+#define DSI_BTA_TERM BIT(1)
#define DSI_CMD_TERM BIT(0)
extern struct device dsi_dev;
@@ -180,81 +195,6 @@
u32 pre_div_func;
};
-#define DSI_HOST_HDR_SIZE 4
-#define DSI_HDR_LAST BIT(31)
-#define DSI_HDR_LONG_PKT BIT(30)
-#define DSI_HDR_BTA BIT(29)
-#define DSI_HDR_VC(vc) (((vc) & 0x03) << 22)
-#define DSI_HDR_DTYPE(dtype) (((dtype) & 0x03f) << 16)
-#define DSI_HDR_DATA2(data) (((data) & 0x0ff) << 8)
-#define DSI_HDR_DATA1(data) ((data) & 0x0ff)
-#define DSI_HDR_WC(wc) ((wc) & 0x0ffff)
-
-#define MDSS_DSI_MRPS 0x04 /* Maximum Return Packet Size */
-
-#define MDSS_DSI_LEN 8 /* 4 x 4 - 6 - 2, bytes dcs header+crc-align */
-
-struct dsi_buf {
- u32 *hdr; /* dsi host header */
- char *start; /* buffer start addr */
- char *end; /* buffer end addr */
- int size; /* size of buffer */
- char *data; /* buffer */
- int len; /* data length */
- dma_addr_t dmap; /* mapped dma addr */
-};
-
-/* dcs read/write */
-#define DTYPE_DCS_WRITE 0x05 /* short write, 0 parameter */
-#define DTYPE_DCS_WRITE1 0x15 /* short write, 1 parameter */
-#define DTYPE_DCS_READ 0x06 /* read */
-#define DTYPE_DCS_LWRITE 0x39 /* long write */
-
-/* generic read/write */
-#define DTYPE_GEN_WRITE 0x03 /* short write, 0 parameter */
-#define DTYPE_GEN_WRITE1 0x13 /* short write, 1 parameter */
-#define DTYPE_GEN_WRITE2 0x23 /* short write, 2 parameter */
-#define DTYPE_GEN_LWRITE 0x29 /* long write */
-#define DTYPE_GEN_READ 0x04 /* long read, 0 parameter */
-#define DTYPE_GEN_READ1 0x14 /* long read, 1 parameter */
-#define DTYPE_GEN_READ2 0x24 /* long read, 2 parameter */
-
-#define DTYPE_TEAR_ON 0x35 /* set tear on */
-#define DTYPE_MAX_PKTSIZE 0x37 /* set max packet size */
-#define DTYPE_NULL_PKT 0x09 /* null packet, no data */
-#define DTYPE_BLANK_PKT 0x19 /* blankiing packet, no data */
-
-#define DTYPE_CM_ON 0x02 /* color mode off */
-#define DTYPE_CM_OFF 0x12 /* color mode on */
-#define DTYPE_PERIPHERAL_OFF 0x22
-#define DTYPE_PERIPHERAL_ON 0x32
-
-/*
- * dcs response
- */
-#define DTYPE_ACK_ERR_RESP 0x02
-#define DTYPE_EOT_RESP 0x08 /* end of tx */
-#define DTYPE_GEN_READ1_RESP 0x11 /* 1 parameter, short */
-#define DTYPE_GEN_READ2_RESP 0x12 /* 2 parameter, short */
-#define DTYPE_GEN_LREAD_RESP 0x1a
-#define DTYPE_DCS_LREAD_RESP 0x1c
-#define DTYPE_DCS_READ1_RESP 0x21 /* 1 parameter, short */
-#define DTYPE_DCS_READ2_RESP 0x22 /* 2 parameter, short */
-
-
-struct dsi_ctrl_hdr {
- char dtype; /* data type */
- char last; /* last in chain */
- char vc; /* virtual chan */
- char ack; /* ask ACK from peripheral */
- char wait; /* ms */
- short dlen; /* 16 bits */
-} __packed;
-
-struct dsi_cmd_desc {
- struct dsi_ctrl_hdr dchdr;
- char *payload;
-};
struct dsi_panel_cmds {
char *buf;
@@ -264,29 +204,6 @@
int link_state;
};
-#define CMD_REQ_MAX 4
-
-#define CMD_REQ_RX 0x0001
-#define CMD_REQ_COMMIT 0x0002
-#define CMD_CLK_CTRL 0x0004
-#define CMD_REQ_NO_MAX_PKT_SIZE 0x0008
-
-struct dcs_cmd_req {
- struct dsi_cmd_desc *cmds;
- int cmds_cnt;
- u32 flags;
- int rlen; /* rx length */
- char *rbuf; /* rx buf */
- void (*cb)(int data);
-};
-
-struct dcs_cmd_list {
- int put;
- int get;
- int tot;
- struct dcs_cmd_req list[CMD_REQ_MAX];
-};
-
struct dsi_kickoff_action {
struct list_head act_entry;
void (*action) (void *);
@@ -315,6 +232,8 @@
int (*on) (struct mdss_panel_data *pdata);
int (*off) (struct mdss_panel_data *pdata);
int (*partial_update_fnc) (struct mdss_panel_data *pdata);
+ int (*check_status) (struct mdss_dsi_ctrl_pdata *pdata);
+ int (*cmdlist_commit)(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
struct mdss_panel_data panel_data;
unsigned char *ctrl_base;
int reg_size;
@@ -360,6 +279,7 @@
struct completion dma_comp;
struct completion mdp_comp;
struct completion video_comp;
+ struct completion bta_comp;
spinlock_t irq_lock;
spinlock_t mdp_lock;
int mdp_busy;
@@ -373,11 +293,6 @@
int dsi_panel_device_register(struct device_node *pan_node,
struct mdss_dsi_ctrl_pdata *ctrl_pdata);
-char *mdss_dsi_buf_reserve_hdr(struct dsi_buf *dp, int hlen);
-char *mdss_dsi_buf_init(struct dsi_buf *dp);
-void mdss_dsi_init(void);
-int mdss_dsi_buf_alloc(struct dsi_buf *, int size);
-int mdss_dsi_cmd_dma_add(struct dsi_buf *dp, struct dsi_cmd_desc *cm);
int mdss_dsi_cmds_tx(struct mdss_dsi_ctrl_pdata *ctrl,
struct dsi_cmd_desc *cmds, int cnt);
@@ -386,8 +301,6 @@
void mdss_dsi_host_init(struct mipi_panel_info *pinfo,
struct mdss_panel_data *pdata);
-void mdss_dsi_set_tear_on(struct mdss_dsi_ctrl_pdata *ctrl);
-void mdss_dsi_set_tear_off(struct mdss_dsi_ctrl_pdata *ctrl);
void mdss_dsi_op_mode_config(int mode,
struct mdss_panel_data *pdata);
void mdss_dsi_cmd_mode_ctrl(int enable);
@@ -417,17 +330,16 @@
void mdss_dsi_phy_enable(struct mdss_dsi_ctrl_pdata *ctrl, int on);
void mdss_dsi_phy_init(struct mdss_panel_data *pdata);
void mdss_dsi_phy_sw_reset(unsigned char *ctrl_base);
-void mdss_dsi_cmd_test_pattern(struct mdss_panel_data *pdata);
+void mdss_dsi_cmd_test_pattern(struct mdss_dsi_ctrl_pdata *ctrl);
+void mdss_dsi_video_test_pattern(struct mdss_dsi_ctrl_pdata *ctrl);
void mdss_dsi_panel_pwm_cfg(struct mdss_dsi_ctrl_pdata *ctrl);
void mdss_dsi_ctrl_init(struct mdss_dsi_ctrl_pdata *ctrl);
void mdss_dsi_cmd_mdp_busy(struct mdss_dsi_ctrl_pdata *ctrl);
void mdss_dsi_wait4video_done(struct mdss_dsi_ctrl_pdata *ctrl);
-void mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
-int mdss_dsi_cmdlist_put(struct mdss_dsi_ctrl_pdata *ctrl,
- struct dcs_cmd_req *cmdreq);
-struct dcs_cmd_req *mdss_dsi_cmdlist_get(struct mdss_dsi_ctrl_pdata *ctrl);
+int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
void mdss_dsi_cmdlist_kickoff(int intf);
+int mdss_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl);
int mdss_dsi_panel_init(struct device_node *node,
struct mdss_dsi_ctrl_pdata *ctrl_pdata,
diff --git a/drivers/video/msm/mdss/mdss_dsi_cmd.c b/drivers/video/msm/mdss/mdss_dsi_cmd.c
new file mode 100644
index 0000000..8fc1115c0
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_dsi_cmd.c
@@ -0,0 +1,688 @@
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/iopoll.h>
+#include <linux/kthread.h>
+
+#include <mach/iommu_domains.h>
+
+#include "mdss_dsi_cmd.h"
+#include "mdss_dsi.h"
+
+/*
+ * mipi dsi buf mechanism
+ */
+char *mdss_dsi_buf_reserve(struct dsi_buf *dp, int len)
+{
+ dp->data += len;
+ return dp->data;
+}
+
+char *mdss_dsi_buf_unreserve(struct dsi_buf *dp, int len)
+{
+ dp->data -= len;
+ return dp->data;
+}
+
+char *mdss_dsi_buf_push(struct dsi_buf *dp, int len)
+{
+ dp->data -= len;
+ dp->len += len;
+ return dp->data;
+}
+
+char *mdss_dsi_buf_reserve_hdr(struct dsi_buf *dp, int hlen)
+{
+ dp->hdr = (u32 *)dp->data;
+ return mdss_dsi_buf_reserve(dp, hlen);
+}
+
+char *mdss_dsi_buf_init(struct dsi_buf *dp)
+{
+ int off;
+
+ dp->data = dp->start;
+ off = (int)dp->data;
+ /* 8 byte align */
+ off &= 0x07;
+ if (off)
+ off = 8 - off;
+ dp->data += off;
+ dp->len = 0;
+ return dp->data;
+}
+
+int mdss_dsi_buf_alloc(struct dsi_buf *dp, int size)
+{
+
+ dp->start = dma_alloc_writecombine(NULL, size, &dp->dmap, GFP_KERNEL);
+ if (dp->start == NULL) {
+ pr_err("%s:%u\n", __func__, __LINE__);
+ return -ENOMEM;
+ }
+
+ dp->end = dp->start + size;
+ dp->size = size;
+
+ if ((int)dp->start & 0x07)
+ pr_err("%s: buf NOT 8 bytes aligned\n", __func__);
+
+ dp->data = dp->start;
+ dp->len = 0;
+ return size;
+}
+
+/*
+ * mipi dsi generic long write
+ */
+static int mdss_dsi_generic_lwrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+ struct dsi_ctrl_hdr *dchdr;
+ char *bp;
+ u32 *hp;
+ int i, len = 0;
+
+ dchdr = &cm->dchdr;
+ bp = mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+
+ /* fill up payload */
+ if (cm->payload) {
+ len = dchdr->dlen;
+ len += 3;
+ len &= ~0x03; /* multipled by 4 */
+ for (i = 0; i < dchdr->dlen; i++)
+ *bp++ = cm->payload[i];
+
+ /* append 0xff to the end */
+ for (; i < len; i++)
+ *bp++ = 0xff;
+
+ dp->len += len;
+ }
+
+ /* fill up header */
+ hp = dp->hdr;
+ *hp = 0;
+ *hp = DSI_HDR_WC(dchdr->dlen);
+ *hp |= DSI_HDR_VC(dchdr->vc);
+ *hp |= DSI_HDR_LONG_PKT;
+ *hp |= DSI_HDR_DTYPE(DTYPE_GEN_LWRITE);
+ if (dchdr->last)
+ *hp |= DSI_HDR_LAST;
+
+ mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+ len += DSI_HOST_HDR_SIZE;
+
+ return len;
+}
+
+/*
+ * mipi dsi generic short write with 0, 1 2 parameters
+ */
+static int mdss_dsi_generic_swrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+ struct dsi_ctrl_hdr *dchdr;
+ u32 *hp;
+ int len;
+
+ dchdr = &cm->dchdr;
+ if (dchdr->dlen && cm->payload == 0) {
+ pr_err("%s: NO payload error\n", __func__);
+ return 0;
+ }
+
+ mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+ hp = dp->hdr;
+ *hp = 0;
+ *hp |= DSI_HDR_VC(dchdr->vc);
+ if (dchdr->last)
+ *hp |= DSI_HDR_LAST;
+
+
+ len = (dchdr->dlen > 2) ? 2 : dchdr->dlen;
+
+ if (len == 1) {
+ *hp |= DSI_HDR_DTYPE(DTYPE_GEN_WRITE1);
+ *hp |= DSI_HDR_DATA1(cm->payload[0]);
+ *hp |= DSI_HDR_DATA2(0);
+ } else if (len == 2) {
+ *hp |= DSI_HDR_DTYPE(DTYPE_GEN_WRITE2);
+ *hp |= DSI_HDR_DATA1(cm->payload[0]);
+ *hp |= DSI_HDR_DATA2(cm->payload[1]);
+ } else {
+ *hp |= DSI_HDR_DTYPE(DTYPE_GEN_WRITE);
+ *hp |= DSI_HDR_DATA1(0);
+ *hp |= DSI_HDR_DATA2(0);
+ }
+
+ mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+ return DSI_HOST_HDR_SIZE; /* 4 bytes */
+}
+
+/*
+ * mipi dsi gerneric read with 0, 1 2 parameters
+ */
+static int mdss_dsi_generic_read(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+ struct dsi_ctrl_hdr *dchdr;
+ u32 *hp;
+ int len;
+
+ dchdr = &cm->dchdr;
+ if (dchdr->dlen && cm->payload == 0) {
+ pr_err("%s: NO payload error\n", __func__);
+ return 0;
+ }
+
+ mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+ hp = dp->hdr;
+ *hp = 0;
+ *hp |= DSI_HDR_VC(dchdr->vc);
+ *hp |= DSI_HDR_BTA;
+ if (dchdr->last)
+ *hp |= DSI_HDR_LAST;
+
+ len = (dchdr->dlen > 2) ? 2 : dchdr->dlen;
+
+ if (len == 1) {
+ *hp |= DSI_HDR_DTYPE(DTYPE_GEN_READ1);
+ *hp |= DSI_HDR_DATA1(cm->payload[0]);
+ *hp |= DSI_HDR_DATA2(0);
+ } else if (len == 2) {
+ *hp |= DSI_HDR_DTYPE(DTYPE_GEN_READ2);
+ *hp |= DSI_HDR_DATA1(cm->payload[0]);
+ *hp |= DSI_HDR_DATA2(cm->payload[1]);
+ } else {
+ *hp |= DSI_HDR_DTYPE(DTYPE_GEN_READ);
+ *hp |= DSI_HDR_DATA1(0);
+ *hp |= DSI_HDR_DATA2(0);
+ }
+
+ mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+ return DSI_HOST_HDR_SIZE; /* 4 bytes */
+}
+
+/*
+ * mipi dsi dcs long write
+ */
+static int mdss_dsi_dcs_lwrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+ struct dsi_ctrl_hdr *dchdr;
+ char *bp;
+ u32 *hp;
+ int i, len = 0;
+
+ dchdr = &cm->dchdr;
+ bp = mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+
+ /*
+ * fill up payload
+ * dcs command byte (first byte) followed by payload
+ */
+ if (cm->payload) {
+ len = dchdr->dlen;
+ len += 3;
+ len &= ~0x03; /* multipled by 4 */
+ for (i = 0; i < dchdr->dlen; i++)
+ *bp++ = cm->payload[i];
+
+ /* append 0xff to the end */
+ for (; i < len; i++)
+ *bp++ = 0xff;
+
+ dp->len += len;
+ }
+
+ /* fill up header */
+ hp = dp->hdr;
+ *hp = 0;
+ *hp = DSI_HDR_WC(dchdr->dlen);
+ *hp |= DSI_HDR_VC(dchdr->vc);
+ *hp |= DSI_HDR_LONG_PKT;
+ *hp |= DSI_HDR_DTYPE(DTYPE_DCS_LWRITE);
+ if (dchdr->last)
+ *hp |= DSI_HDR_LAST;
+
+ mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+
+ len += DSI_HOST_HDR_SIZE;
+ return len;
+}
+
+/*
+ * mipi dsi dcs short write with 0 parameters
+ */
+static int mdss_dsi_dcs_swrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+ struct dsi_ctrl_hdr *dchdr;
+ u32 *hp;
+ int len;
+
+ dchdr = &cm->dchdr;
+ if (cm->payload == 0) {
+ pr_err("%s: NO payload error\n", __func__);
+ return -EINVAL;
+ }
+
+ mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+ hp = dp->hdr;
+ *hp = 0;
+ *hp |= DSI_HDR_VC(dchdr->vc);
+ if (dchdr->ack) /* ask ACK trigger msg from peripeheral */
+ *hp |= DSI_HDR_BTA;
+ if (dchdr->last)
+ *hp |= DSI_HDR_LAST;
+
+ len = (dchdr->dlen > 1) ? 1 : dchdr->dlen;
+
+ *hp |= DSI_HDR_DTYPE(DTYPE_DCS_WRITE);
+ *hp |= DSI_HDR_DATA1(cm->payload[0]); /* dcs command byte */
+ *hp |= DSI_HDR_DATA2(0);
+
+ mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+ return DSI_HOST_HDR_SIZE; /* 4 bytes */
+}
+
+/*
+ * mipi dsi dcs short write with 1 parameters
+ */
+static int mdss_dsi_dcs_swrite1(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+ struct dsi_ctrl_hdr *dchdr;
+ u32 *hp;
+
+ dchdr = &cm->dchdr;
+ if (dchdr->dlen < 2 || cm->payload == 0) {
+ pr_err("%s: NO payload error\n", __func__);
+ return -EINVAL;
+ }
+
+ mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+ hp = dp->hdr;
+ *hp = 0;
+ *hp |= DSI_HDR_VC(dchdr->vc);
+ if (dchdr->ack) /* ask ACK trigger msg from peripeheral */
+ *hp |= DSI_HDR_BTA;
+ if (dchdr->last)
+ *hp |= DSI_HDR_LAST;
+
+ *hp |= DSI_HDR_DTYPE(DTYPE_DCS_WRITE1);
+ *hp |= DSI_HDR_DATA1(cm->payload[0]); /* dcs comamnd byte */
+ *hp |= DSI_HDR_DATA2(cm->payload[1]); /* parameter */
+
+ mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+ return DSI_HOST_HDR_SIZE; /* 4 bytes */
+}
+/*
+ * mipi dsi dcs read with 0 parameters
+ */
+
+static int mdss_dsi_dcs_read(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+ struct dsi_ctrl_hdr *dchdr;
+ u32 *hp;
+
+ dchdr = &cm->dchdr;
+ if (cm->payload == 0) {
+ pr_err("%s: NO payload error\n", __func__);
+ return -EINVAL;
+ }
+
+ mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+ hp = dp->hdr;
+ *hp = 0;
+ *hp |= DSI_HDR_VC(dchdr->vc);
+ *hp |= DSI_HDR_BTA;
+ *hp |= DSI_HDR_DTYPE(DTYPE_DCS_READ);
+ if (dchdr->last)
+ *hp |= DSI_HDR_LAST;
+
+ *hp |= DSI_HDR_DATA1(cm->payload[0]); /* dcs command byte */
+ *hp |= DSI_HDR_DATA2(0);
+
+ mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+ return DSI_HOST_HDR_SIZE; /* 4 bytes */
+}
+
+static int mdss_dsi_cm_on(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+ struct dsi_ctrl_hdr *dchdr;
+ u32 *hp;
+
+ dchdr = &cm->dchdr;
+ mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+ hp = dp->hdr;
+ *hp = 0;
+ *hp |= DSI_HDR_VC(dchdr->vc);
+ *hp |= DSI_HDR_DTYPE(DTYPE_CM_ON);
+ if (dchdr->last)
+ *hp |= DSI_HDR_LAST;
+
+ mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+ return DSI_HOST_HDR_SIZE; /* 4 bytes */
+}
+
+static int mdss_dsi_cm_off(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+ struct dsi_ctrl_hdr *dchdr;
+ u32 *hp;
+
+ dchdr = &cm->dchdr;
+ mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+ hp = dp->hdr;
+ *hp = 0;
+ *hp |= DSI_HDR_VC(dchdr->vc);
+ *hp |= DSI_HDR_DTYPE(DTYPE_CM_OFF);
+ if (dchdr->last)
+ *hp |= DSI_HDR_LAST;
+
+ mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+ return DSI_HOST_HDR_SIZE; /* 4 bytes */
+}
+
+static int mdss_dsi_peripheral_on(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+ struct dsi_ctrl_hdr *dchdr;
+ u32 *hp;
+
+ dchdr = &cm->dchdr;
+ mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+ hp = dp->hdr;
+ *hp = 0;
+ *hp |= DSI_HDR_VC(dchdr->vc);
+ *hp |= DSI_HDR_DTYPE(DTYPE_PERIPHERAL_ON);
+ if (dchdr->last)
+ *hp |= DSI_HDR_LAST;
+
+ mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+ return DSI_HOST_HDR_SIZE; /* 4 bytes */
+}
+
+static int mdss_dsi_peripheral_off(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+ struct dsi_ctrl_hdr *dchdr;
+ u32 *hp;
+
+ dchdr = &cm->dchdr;
+ mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+ hp = dp->hdr;
+ *hp = 0;
+ *hp |= DSI_HDR_VC(dchdr->vc);
+ *hp |= DSI_HDR_DTYPE(DTYPE_PERIPHERAL_OFF);
+ if (dchdr->last)
+ *hp |= DSI_HDR_LAST;
+
+ mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+ return DSI_HOST_HDR_SIZE; /* 4 bytes */
+}
+
+static int mdss_dsi_set_max_pktsize(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+ struct dsi_ctrl_hdr *dchdr;
+ u32 *hp;
+
+ dchdr = &cm->dchdr;
+ if (cm->payload == 0) {
+ pr_err("%s: NO payload error\n", __func__);
+ return 0;
+ }
+
+ mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+ hp = dp->hdr;
+ *hp = 0;
+ *hp |= DSI_HDR_VC(dchdr->vc);
+ *hp |= DSI_HDR_DTYPE(DTYPE_MAX_PKTSIZE);
+ if (dchdr->last)
+ *hp |= DSI_HDR_LAST;
+
+ *hp |= DSI_HDR_DATA1(cm->payload[0]);
+ *hp |= DSI_HDR_DATA2(cm->payload[1]);
+
+ mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+ return DSI_HOST_HDR_SIZE; /* 4 bytes */
+}
+
+static int mdss_dsi_null_pkt(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+ struct dsi_ctrl_hdr *dchdr;
+ u32 *hp;
+
+ dchdr = &cm->dchdr;
+ mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+ hp = dp->hdr;
+ *hp = 0;
+ *hp = DSI_HDR_WC(dchdr->dlen);
+ *hp |= DSI_HDR_LONG_PKT;
+ *hp |= DSI_HDR_VC(dchdr->vc);
+ *hp |= DSI_HDR_DTYPE(DTYPE_NULL_PKT);
+ if (dchdr->last)
+ *hp |= DSI_HDR_LAST;
+
+ mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+ return DSI_HOST_HDR_SIZE; /* 4 bytes */
+}
+
+static int mdss_dsi_blank_pkt(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+ struct dsi_ctrl_hdr *dchdr;
+ u32 *hp;
+
+ dchdr = &cm->dchdr;
+ mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+ hp = dp->hdr;
+ *hp = 0;
+ *hp = DSI_HDR_WC(dchdr->dlen);
+ *hp |= DSI_HDR_LONG_PKT;
+ *hp |= DSI_HDR_VC(dchdr->vc);
+ *hp |= DSI_HDR_DTYPE(DTYPE_BLANK_PKT);
+ if (dchdr->last)
+ *hp |= DSI_HDR_LAST;
+
+ mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+ return DSI_HOST_HDR_SIZE; /* 4 bytes */
+}
+
+/*
+ * prepare cmd buffer to be txed
+ */
+int mdss_dsi_cmd_dma_add(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+ struct dsi_ctrl_hdr *dchdr;
+ int len = 0;
+
+ dchdr = &cm->dchdr;
+
+ switch (dchdr->dtype) {
+ case DTYPE_GEN_WRITE:
+ case DTYPE_GEN_WRITE1:
+ case DTYPE_GEN_WRITE2:
+ len = mdss_dsi_generic_swrite(dp, cm);
+ break;
+ case DTYPE_GEN_LWRITE:
+ len = mdss_dsi_generic_lwrite(dp, cm);
+ break;
+ case DTYPE_GEN_READ:
+ case DTYPE_GEN_READ1:
+ case DTYPE_GEN_READ2:
+ len = mdss_dsi_generic_read(dp, cm);
+ break;
+ case DTYPE_DCS_LWRITE:
+ len = mdss_dsi_dcs_lwrite(dp, cm);
+ break;
+ case DTYPE_DCS_WRITE:
+ len = mdss_dsi_dcs_swrite(dp, cm);
+ break;
+ case DTYPE_DCS_WRITE1:
+ len = mdss_dsi_dcs_swrite1(dp, cm);
+ break;
+ case DTYPE_DCS_READ:
+ len = mdss_dsi_dcs_read(dp, cm);
+ break;
+ case DTYPE_MAX_PKTSIZE:
+ len = mdss_dsi_set_max_pktsize(dp, cm);
+ break;
+ case DTYPE_NULL_PKT:
+ len = mdss_dsi_null_pkt(dp, cm);
+ break;
+ case DTYPE_BLANK_PKT:
+ len = mdss_dsi_blank_pkt(dp, cm);
+ break;
+ case DTYPE_CM_ON:
+ len = mdss_dsi_cm_on(dp, cm);
+ break;
+ case DTYPE_CM_OFF:
+ len = mdss_dsi_cm_off(dp, cm);
+ break;
+ case DTYPE_PERIPHERAL_ON:
+ len = mdss_dsi_peripheral_on(dp, cm);
+ break;
+ case DTYPE_PERIPHERAL_OFF:
+ len = mdss_dsi_peripheral_off(dp, cm);
+ break;
+ default:
+ pr_debug("%s: dtype=%x NOT supported\n",
+ __func__, dchdr->dtype);
+ break;
+
+ }
+
+ return len;
+}
+
+/*
+ * mdss_dsi_short_read1_resp: 1 parameter
+ */
+int mdss_dsi_short_read1_resp(struct dsi_buf *rp)
+{
+ /* strip out dcs type */
+ rp->data++;
+ rp->len = 1;
+ return rp->len;
+}
+
+/*
+ * mdss_dsi_short_read2_resp: 2 parameter
+ */
+int mdss_dsi_short_read2_resp(struct dsi_buf *rp)
+{
+ /* strip out dcs type */
+ rp->data++;
+ rp->len = 2;
+ return rp->len;
+}
+
+int mdss_dsi_long_read_resp(struct dsi_buf *rp)
+{
+ /* strip out dcs header */
+ rp->data += 4;
+ rp->len -= 4;
+ return rp->len;
+}
+
+static char set_tear_on[2] = {0x35, 0x00};
+static struct dsi_cmd_desc dsi_tear_on_cmd = {
+ {DTYPE_DCS_WRITE1, 1, 0, 0, 0, sizeof(set_tear_on)}, set_tear_on};
+
+static char set_tear_off[2] = {0x34, 0x00};
+static struct dsi_cmd_desc dsi_tear_off_cmd = {
+ {DTYPE_DCS_WRITE, 1, 0, 0, 0, sizeof(set_tear_off)}, set_tear_off};
+
+void mdss_dsi_set_tear_on(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ struct dcs_cmd_req cmdreq;
+
+ cmdreq.cmds = &dsi_tear_on_cmd;
+ cmdreq.cmds_cnt = 1;
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+
+ mdss_dsi_cmdlist_put(ctrl, &cmdreq);
+}
+
+void mdss_dsi_set_tear_off(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ struct dcs_cmd_req cmdreq;
+
+ cmdreq.cmds = &dsi_tear_off_cmd;
+ cmdreq.cmds_cnt = 1;
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+
+ mdss_dsi_cmdlist_put(ctrl, &cmdreq);
+}
+
+/*
+ * mdss_dsi_cmd_get: ctrl->cmd_mutex acquired by caller
+ */
+struct dcs_cmd_req *mdss_dsi_cmdlist_get(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ struct dcs_cmd_list *clist;
+ struct dcs_cmd_req *req = NULL;
+
+ clist = &ctrl->cmdlist;
+ if (clist->get != clist->put) {
+ req = &clist->list[clist->get];
+ clist->get++;
+ clist->get %= CMD_REQ_MAX;
+ clist->tot--;
+ pr_debug("%s: tot=%d put=%d get=%d\n", __func__,
+ clist->tot, clist->put, clist->get);
+ }
+ return req;
+}
+
+int mdss_dsi_cmdlist_put(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct dcs_cmd_req *cmdreq)
+{
+ struct dcs_cmd_req *req;
+ struct dcs_cmd_list *clist;
+ int ret = -EINVAL;
+
+ mutex_lock(&ctrl->cmd_mutex);
+ clist = &ctrl->cmdlist;
+ req = &clist->list[clist->put];
+ *req = *cmdreq;
+ clist->put++;
+ clist->put %= CMD_REQ_MAX;
+ clist->tot++;
+ if (clist->put == clist->get) {
+ /* drop the oldest one */
+ pr_debug("%s: DROP, tot=%d put=%d get=%d\n", __func__,
+ clist->tot, clist->put, clist->get);
+ clist->get++;
+ clist->get %= CMD_REQ_MAX;
+ clist->tot--;
+ }
+ mutex_unlock(&ctrl->cmd_mutex);
+
+ pr_debug("%s: tot=%d put=%d get=%d\n", __func__,
+ clist->tot, clist->put, clist->get);
+
+ if (req->flags & CMD_REQ_COMMIT) {
+ if (!ctrl->cmdlist_commit)
+ pr_err("cmdlist_commit not implemented!\n");
+ else
+ ret = ctrl->cmdlist_commit(ctrl, 0);
+ }
+ return ret;
+}
+
diff --git a/drivers/video/msm/mdss/mdss_dsi_cmd.h b/drivers/video/msm/mdss/mdss_dsi_cmd.h
new file mode 100644
index 0000000..f806e78
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_dsi_cmd.h
@@ -0,0 +1,134 @@
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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 MDSS_DSI_CMD_H
+#define MDSS_DSI_CMD_H
+
+#include "mdss.h"
+
+struct mdss_dsi_ctrl_pdata;
+
+#define DSI_HOST_HDR_SIZE 4
+#define DSI_HDR_LAST BIT(31)
+#define DSI_HDR_LONG_PKT BIT(30)
+#define DSI_HDR_BTA BIT(29)
+#define DSI_HDR_VC(vc) (((vc) & 0x03) << 22)
+#define DSI_HDR_DTYPE(dtype) (((dtype) & 0x03f) << 16)
+#define DSI_HDR_DATA2(data) (((data) & 0x0ff) << 8)
+#define DSI_HDR_DATA1(data) ((data) & 0x0ff)
+#define DSI_HDR_WC(wc) ((wc) & 0x0ffff)
+
+#define MDSS_DSI_MRPS 0x04 /* Maximum Return Packet Size */
+
+#define MDSS_DSI_LEN 8 /* 4 x 4 - 6 - 2, bytes dcs header+crc-align */
+
+struct dsi_buf {
+ u32 *hdr; /* dsi host header */
+ char *start; /* buffer start addr */
+ char *end; /* buffer end addr */
+ int size; /* size of buffer */
+ char *data; /* buffer */
+ int len; /* data length */
+ dma_addr_t dmap; /* mapped dma addr */
+};
+
+/* dcs read/write */
+#define DTYPE_DCS_WRITE 0x05 /* short write, 0 parameter */
+#define DTYPE_DCS_WRITE1 0x15 /* short write, 1 parameter */
+#define DTYPE_DCS_READ 0x06 /* read */
+#define DTYPE_DCS_LWRITE 0x39 /* long write */
+
+/* generic read/write */
+#define DTYPE_GEN_WRITE 0x03 /* short write, 0 parameter */
+#define DTYPE_GEN_WRITE1 0x13 /* short write, 1 parameter */
+#define DTYPE_GEN_WRITE2 0x23 /* short write, 2 parameter */
+#define DTYPE_GEN_LWRITE 0x29 /* long write */
+#define DTYPE_GEN_READ 0x04 /* long read, 0 parameter */
+#define DTYPE_GEN_READ1 0x14 /* long read, 1 parameter */
+#define DTYPE_GEN_READ2 0x24 /* long read, 2 parameter */
+
+#define DTYPE_TEAR_ON 0x35 /* set tear on */
+#define DTYPE_MAX_PKTSIZE 0x37 /* set max packet size */
+#define DTYPE_NULL_PKT 0x09 /* null packet, no data */
+#define DTYPE_BLANK_PKT 0x19 /* blankiing packet, no data */
+
+#define DTYPE_CM_ON 0x02 /* color mode off */
+#define DTYPE_CM_OFF 0x12 /* color mode on */
+#define DTYPE_PERIPHERAL_OFF 0x22
+#define DTYPE_PERIPHERAL_ON 0x32
+
+/*
+ * dcs response
+ */
+#define DTYPE_ACK_ERR_RESP 0x02
+#define DTYPE_EOT_RESP 0x08 /* end of tx */
+#define DTYPE_GEN_READ1_RESP 0x11 /* 1 parameter, short */
+#define DTYPE_GEN_READ2_RESP 0x12 /* 2 parameter, short */
+#define DTYPE_GEN_LREAD_RESP 0x1a
+#define DTYPE_DCS_LREAD_RESP 0x1c
+#define DTYPE_DCS_READ1_RESP 0x21 /* 1 parameter, short */
+#define DTYPE_DCS_READ2_RESP 0x22 /* 2 parameter, short */
+
+struct dsi_ctrl_hdr {
+ char dtype; /* data type */
+ char last; /* last in chain */
+ char vc; /* virtual chan */
+ char ack; /* ask ACK from peripheral */
+ char wait; /* ms */
+ short dlen; /* 16 bits */
+} __packed;
+
+struct dsi_cmd_desc {
+ struct dsi_ctrl_hdr dchdr;
+ char *payload;
+};
+
+#define CMD_REQ_MAX 4
+#define CMD_REQ_RX 0x0001
+#define CMD_REQ_COMMIT 0x0002
+#define CMD_CLK_CTRL 0x0004
+#define CMD_REQ_NO_MAX_PKT_SIZE 0x0008
+#define CMD_REQ_LP_MODE 0x0010
+
+struct dcs_cmd_req {
+ struct dsi_cmd_desc *cmds;
+ int cmds_cnt;
+ u32 flags;
+ int rlen; /* rx length */
+ char *rbuf; /* rx buf */
+ void (*cb)(int data);
+};
+
+struct dcs_cmd_list {
+ int put;
+ int get;
+ int tot;
+ struct dcs_cmd_req list[CMD_REQ_MAX];
+};
+
+char *mdss_dsi_buf_reserve(struct dsi_buf *dp, int len);
+char *mdss_dsi_buf_unreserve(struct dsi_buf *dp, int len);
+char *mdss_dsi_buf_push(struct dsi_buf *dp, int len);
+char *mdss_dsi_buf_reserve_hdr(struct dsi_buf *dp, int hlen);
+char *mdss_dsi_buf_init(struct dsi_buf *dp);
+int mdss_dsi_buf_alloc(struct dsi_buf *dp, int size);
+int mdss_dsi_cmd_dma_add(struct dsi_buf *dp, struct dsi_cmd_desc *cm);
+int mdss_dsi_short_read1_resp(struct dsi_buf *rp);
+int mdss_dsi_short_read2_resp(struct dsi_buf *rp);
+int mdss_dsi_long_read_resp(struct dsi_buf *rp);
+void mdss_dsi_set_tear_on(struct mdss_dsi_ctrl_pdata *ctrl);
+void mdss_dsi_set_tear_off(struct mdss_dsi_ctrl_pdata *ctrl);
+struct dcs_cmd_req *mdss_dsi_cmdlist_get(struct mdss_dsi_ctrl_pdata *ctrl);
+int mdss_dsi_cmdlist_put(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct dcs_cmd_req *cmdreq);
+#endif
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index bb2818b..bd156fc 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -49,6 +49,8 @@
#define DSI_EVENT_Q_MAX 4
+#define DSI_BTA_EVENT_TIMEOUT (HZ / 10)
+
/* event */
struct dsi_event_q {
struct mdss_dsi_ctrl_pdata *ctrl;
@@ -98,12 +100,14 @@
init_completion(&ctrl->dma_comp);
init_completion(&ctrl->mdp_comp);
init_completion(&ctrl->video_comp);
+ init_completion(&ctrl->bta_comp);
spin_lock_init(&ctrl->irq_lock);
spin_lock_init(&ctrl->mdp_lock);
mutex_init(&ctrl->mutex);
mutex_init(&ctrl->cmd_mutex);
mdss_dsi_buf_alloc(&ctrl->tx_buf, SZ_4K);
mdss_dsi_buf_alloc(&ctrl->rx_buf, SZ_4K);
+ ctrl->cmdlist_commit = mdss_dsi_cmdlist_commit;
if (dsi_event.inited == 0) {
@@ -196,598 +200,34 @@
spin_unlock(&ctrl->irq_lock);
}
-/*
- * mipi dsi buf mechanism
- */
-char *mdss_dsi_buf_reserve(struct dsi_buf *dp, int len)
+void mdss_dsi_video_test_pattern(struct mdss_dsi_ctrl_pdata *ctrl)
{
- dp->data += len;
- return dp->data;
-}
-
-char *mdss_dsi_buf_unreserve(struct dsi_buf *dp, int len)
-{
- dp->data -= len;
- return dp->data;
-}
-
-char *mdss_dsi_buf_push(struct dsi_buf *dp, int len)
-{
- dp->data -= len;
- dp->len += len;
- return dp->data;
-}
-
-char *mdss_dsi_buf_reserve_hdr(struct dsi_buf *dp, int hlen)
-{
- dp->hdr = (u32 *)dp->data;
- return mdss_dsi_buf_reserve(dp, hlen);
-}
-
-char *mdss_dsi_buf_init(struct dsi_buf *dp)
-{
- int off;
-
- dp->data = dp->start;
- off = (int)dp->data;
- /* 8 byte align */
- off &= 0x07;
- if (off)
- off = 8 - off;
- dp->data += off;
- dp->len = 0;
- return dp->data;
-}
-
-int mdss_dsi_buf_alloc(struct dsi_buf *dp, int size)
-{
-
- dp->start = dma_alloc_writecombine(NULL, size, &dp->dmap, GFP_KERNEL);
- if (dp->start == NULL) {
- pr_err("%s:%u\n", __func__, __LINE__);
- return -ENOMEM;
- }
-
- dp->end = dp->start + size;
- dp->size = size;
-
- if ((int)dp->start & 0x07)
- pr_err("%s: buf NOT 8 bytes aligned\n", __func__);
-
- dp->data = dp->start;
- dp->len = 0;
- return size;
-}
-
-/*
- * mipi dsi generic long write
- */
-static int mdss_dsi_generic_lwrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
-{
- struct dsi_ctrl_hdr *dchdr;
- char *bp;
- u32 *hp;
- int i, len = 0;
-
- dchdr = &cm->dchdr;
- bp = mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
-
- /* fill up payload */
- if (cm->payload) {
- len = dchdr->dlen;
- len += 3;
- len &= ~0x03; /* multipled by 4 */
- for (i = 0; i < dchdr->dlen; i++)
- *bp++ = cm->payload[i];
-
- /* append 0xff to the end */
- for (; i < len; i++)
- *bp++ = 0xff;
-
- dp->len += len;
- }
-
- /* fill up header */
- hp = dp->hdr;
- *hp = 0;
- *hp = DSI_HDR_WC(dchdr->dlen);
- *hp |= DSI_HDR_VC(dchdr->vc);
- *hp |= DSI_HDR_LONG_PKT;
- *hp |= DSI_HDR_DTYPE(DTYPE_GEN_LWRITE);
- if (dchdr->last)
- *hp |= DSI_HDR_LAST;
-
- mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
- len += DSI_HOST_HDR_SIZE;
-
- return len;
-}
-
-/*
- * mipi dsi generic short write with 0, 1 2 parameters
- */
-static int mdss_dsi_generic_swrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
-{
- struct dsi_ctrl_hdr *dchdr;
- u32 *hp;
- int len;
-
- dchdr = &cm->dchdr;
- if (dchdr->dlen && cm->payload == 0) {
- pr_err("%s: NO payload error\n", __func__);
- return 0;
- }
-
- mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
- hp = dp->hdr;
- *hp = 0;
- *hp |= DSI_HDR_VC(dchdr->vc);
- if (dchdr->last)
- *hp |= DSI_HDR_LAST;
-
-
- len = (dchdr->dlen > 2) ? 2 : dchdr->dlen;
-
- if (len == 1) {
- *hp |= DSI_HDR_DTYPE(DTYPE_GEN_WRITE1);
- *hp |= DSI_HDR_DATA1(cm->payload[0]);
- *hp |= DSI_HDR_DATA2(0);
- } else if (len == 2) {
- *hp |= DSI_HDR_DTYPE(DTYPE_GEN_WRITE2);
- *hp |= DSI_HDR_DATA1(cm->payload[0]);
- *hp |= DSI_HDR_DATA2(cm->payload[1]);
- } else {
- *hp |= DSI_HDR_DTYPE(DTYPE_GEN_WRITE);
- *hp |= DSI_HDR_DATA1(0);
- *hp |= DSI_HDR_DATA2(0);
- }
-
- mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
- return DSI_HOST_HDR_SIZE; /* 4 bytes */
-}
-
-/*
- * mipi dsi gerneric read with 0, 1 2 parameters
- */
-static int mdss_dsi_generic_read(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
-{
- struct dsi_ctrl_hdr *dchdr;
- u32 *hp;
- int len;
-
- dchdr = &cm->dchdr;
- if (dchdr->dlen && cm->payload == 0) {
- pr_err("%s: NO payload error\n", __func__);
- return 0;
- }
-
- mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
- hp = dp->hdr;
- *hp = 0;
- *hp |= DSI_HDR_VC(dchdr->vc);
- *hp |= DSI_HDR_BTA;
- if (dchdr->last)
- *hp |= DSI_HDR_LAST;
-
- len = (dchdr->dlen > 2) ? 2 : dchdr->dlen;
-
- if (len == 1) {
- *hp |= DSI_HDR_DTYPE(DTYPE_GEN_READ1);
- *hp |= DSI_HDR_DATA1(cm->payload[0]);
- *hp |= DSI_HDR_DATA2(0);
- } else if (len == 2) {
- *hp |= DSI_HDR_DTYPE(DTYPE_GEN_READ2);
- *hp |= DSI_HDR_DATA1(cm->payload[0]);
- *hp |= DSI_HDR_DATA2(cm->payload[1]);
- } else {
- *hp |= DSI_HDR_DTYPE(DTYPE_GEN_READ);
- *hp |= DSI_HDR_DATA1(0);
- *hp |= DSI_HDR_DATA2(0);
- }
-
- mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
- return DSI_HOST_HDR_SIZE; /* 4 bytes */
-}
-
-/*
- * mipi dsi dcs long write
- */
-static int mdss_dsi_dcs_lwrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
-{
- struct dsi_ctrl_hdr *dchdr;
- char *bp;
- u32 *hp;
- int i, len = 0;
-
- dchdr = &cm->dchdr;
- bp = mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
-
- /*
- * fill up payload
- * dcs command byte (first byte) followed by payload
- */
- if (cm->payload) {
- len = dchdr->dlen;
- len += 3;
- len &= ~0x03; /* multipled by 4 */
- for (i = 0; i < dchdr->dlen; i++)
- *bp++ = cm->payload[i];
-
- /* append 0xff to the end */
- for (; i < len; i++)
- *bp++ = 0xff;
-
- dp->len += len;
- }
-
- /* fill up header */
- hp = dp->hdr;
- *hp = 0;
- *hp = DSI_HDR_WC(dchdr->dlen);
- *hp |= DSI_HDR_VC(dchdr->vc);
- *hp |= DSI_HDR_LONG_PKT;
- *hp |= DSI_HDR_DTYPE(DTYPE_DCS_LWRITE);
- if (dchdr->last)
- *hp |= DSI_HDR_LAST;
-
- mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
-
- len += DSI_HOST_HDR_SIZE;
- return len;
-}
-
-/*
- * mipi dsi dcs short write with 0 parameters
- */
-static int mdss_dsi_dcs_swrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
-{
- struct dsi_ctrl_hdr *dchdr;
- u32 *hp;
- int len;
-
- dchdr = &cm->dchdr;
- if (cm->payload == 0) {
- pr_err("%s: NO payload error\n", __func__);
- return -EINVAL;
- }
-
- mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
- hp = dp->hdr;
- *hp = 0;
- *hp |= DSI_HDR_VC(dchdr->vc);
- if (dchdr->ack) /* ask ACK trigger msg from peripeheral */
- *hp |= DSI_HDR_BTA;
- if (dchdr->last)
- *hp |= DSI_HDR_LAST;
-
- len = (dchdr->dlen > 1) ? 1 : dchdr->dlen;
-
- *hp |= DSI_HDR_DTYPE(DTYPE_DCS_WRITE);
- *hp |= DSI_HDR_DATA1(cm->payload[0]); /* dcs command byte */
- *hp |= DSI_HDR_DATA2(0);
-
- mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
- return DSI_HOST_HDR_SIZE; /* 4 bytes */
-}
-
-/*
- * mipi dsi dcs short write with 1 parameters
- */
-static int mdss_dsi_dcs_swrite1(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
-{
- struct dsi_ctrl_hdr *dchdr;
- u32 *hp;
-
- dchdr = &cm->dchdr;
- if (dchdr->dlen < 2 || cm->payload == 0) {
- pr_err("%s: NO payload error\n", __func__);
- return -EINVAL;
- }
-
- mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
- hp = dp->hdr;
- *hp = 0;
- *hp |= DSI_HDR_VC(dchdr->vc);
- if (dchdr->ack) /* ask ACK trigger msg from peripeheral */
- *hp |= DSI_HDR_BTA;
- if (dchdr->last)
- *hp |= DSI_HDR_LAST;
-
- *hp |= DSI_HDR_DTYPE(DTYPE_DCS_WRITE1);
- *hp |= DSI_HDR_DATA1(cm->payload[0]); /* dcs comamnd byte */
- *hp |= DSI_HDR_DATA2(cm->payload[1]); /* parameter */
-
- mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
- return DSI_HOST_HDR_SIZE; /* 4 bytes */
-}
-/*
- * mipi dsi dcs read with 0 parameters
- */
-
-static int mdss_dsi_dcs_read(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
-{
- struct dsi_ctrl_hdr *dchdr;
- u32 *hp;
-
- dchdr = &cm->dchdr;
- if (cm->payload == 0) {
- pr_err("%s: NO payload error\n", __func__);
- return -EINVAL;
- }
-
- mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
- hp = dp->hdr;
- *hp = 0;
- *hp |= DSI_HDR_VC(dchdr->vc);
- *hp |= DSI_HDR_BTA;
- *hp |= DSI_HDR_DTYPE(DTYPE_DCS_READ);
- if (dchdr->last)
- *hp |= DSI_HDR_LAST;
-
- *hp |= DSI_HDR_DATA1(cm->payload[0]); /* dcs command byte */
- *hp |= DSI_HDR_DATA2(0);
-
- mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
- return DSI_HOST_HDR_SIZE; /* 4 bytes */
-}
-
-static int mdss_dsi_cm_on(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
-{
- struct dsi_ctrl_hdr *dchdr;
- u32 *hp;
-
- dchdr = &cm->dchdr;
- mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
- hp = dp->hdr;
- *hp = 0;
- *hp |= DSI_HDR_VC(dchdr->vc);
- *hp |= DSI_HDR_DTYPE(DTYPE_CM_ON);
- if (dchdr->last)
- *hp |= DSI_HDR_LAST;
-
- mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
- return DSI_HOST_HDR_SIZE; /* 4 bytes */
-}
-
-static int mdss_dsi_cm_off(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
-{
- struct dsi_ctrl_hdr *dchdr;
- u32 *hp;
-
- dchdr = &cm->dchdr;
- mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
- hp = dp->hdr;
- *hp = 0;
- *hp |= DSI_HDR_VC(dchdr->vc);
- *hp |= DSI_HDR_DTYPE(DTYPE_CM_OFF);
- if (dchdr->last)
- *hp |= DSI_HDR_LAST;
-
- mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
- return DSI_HOST_HDR_SIZE; /* 4 bytes */
-}
-
-static int mdss_dsi_peripheral_on(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
-{
- struct dsi_ctrl_hdr *dchdr;
- u32 *hp;
-
- dchdr = &cm->dchdr;
- mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
- hp = dp->hdr;
- *hp = 0;
- *hp |= DSI_HDR_VC(dchdr->vc);
- *hp |= DSI_HDR_DTYPE(DTYPE_PERIPHERAL_ON);
- if (dchdr->last)
- *hp |= DSI_HDR_LAST;
-
- mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
- return DSI_HOST_HDR_SIZE; /* 4 bytes */
-}
-
-static int mdss_dsi_peripheral_off(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
-{
- struct dsi_ctrl_hdr *dchdr;
- u32 *hp;
-
- dchdr = &cm->dchdr;
- mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
- hp = dp->hdr;
- *hp = 0;
- *hp |= DSI_HDR_VC(dchdr->vc);
- *hp |= DSI_HDR_DTYPE(DTYPE_PERIPHERAL_OFF);
- if (dchdr->last)
- *hp |= DSI_HDR_LAST;
-
- mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
- return DSI_HOST_HDR_SIZE; /* 4 bytes */
-}
-
-static int mdss_dsi_set_max_pktsize(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
-{
- struct dsi_ctrl_hdr *dchdr;
- u32 *hp;
-
- dchdr = &cm->dchdr;
- if (cm->payload == 0) {
- pr_err("%s: NO payload error\n", __func__);
- return 0;
- }
-
- mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
- hp = dp->hdr;
- *hp = 0;
- *hp |= DSI_HDR_VC(dchdr->vc);
- *hp |= DSI_HDR_DTYPE(DTYPE_MAX_PKTSIZE);
- if (dchdr->last)
- *hp |= DSI_HDR_LAST;
-
- *hp |= DSI_HDR_DATA1(cm->payload[0]);
- *hp |= DSI_HDR_DATA2(cm->payload[1]);
-
- mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
- return DSI_HOST_HDR_SIZE; /* 4 bytes */
-}
-
-static int mdss_dsi_null_pkt(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
-{
- struct dsi_ctrl_hdr *dchdr;
- u32 *hp;
-
- dchdr = &cm->dchdr;
- mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
- hp = dp->hdr;
- *hp = 0;
- *hp = DSI_HDR_WC(dchdr->dlen);
- *hp |= DSI_HDR_LONG_PKT;
- *hp |= DSI_HDR_VC(dchdr->vc);
- *hp |= DSI_HDR_DTYPE(DTYPE_NULL_PKT);
- if (dchdr->last)
- *hp |= DSI_HDR_LAST;
-
- mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
- return DSI_HOST_HDR_SIZE; /* 4 bytes */
-}
-
-static int mdss_dsi_blank_pkt(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
-{
- struct dsi_ctrl_hdr *dchdr;
- u32 *hp;
-
- dchdr = &cm->dchdr;
- mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
- hp = dp->hdr;
- *hp = 0;
- *hp = DSI_HDR_WC(dchdr->dlen);
- *hp |= DSI_HDR_LONG_PKT;
- *hp |= DSI_HDR_VC(dchdr->vc);
- *hp |= DSI_HDR_DTYPE(DTYPE_BLANK_PKT);
- if (dchdr->last)
- *hp |= DSI_HDR_LAST;
-
- mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
- return DSI_HOST_HDR_SIZE; /* 4 bytes */
-}
-
-/*
- * prepare cmd buffer to be txed
- */
-int mdss_dsi_cmd_dma_add(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
-{
- struct dsi_ctrl_hdr *dchdr;
- int len = 0;
-
- dchdr = &cm->dchdr;
-
- switch (dchdr->dtype) {
- case DTYPE_GEN_WRITE:
- case DTYPE_GEN_WRITE1:
- case DTYPE_GEN_WRITE2:
- len = mdss_dsi_generic_swrite(dp, cm);
- break;
- case DTYPE_GEN_LWRITE:
- len = mdss_dsi_generic_lwrite(dp, cm);
- break;
- case DTYPE_GEN_READ:
- case DTYPE_GEN_READ1:
- case DTYPE_GEN_READ2:
- len = mdss_dsi_generic_read(dp, cm);
- break;
- case DTYPE_DCS_LWRITE:
- len = mdss_dsi_dcs_lwrite(dp, cm);
- break;
- case DTYPE_DCS_WRITE:
- len = mdss_dsi_dcs_swrite(dp, cm);
- break;
- case DTYPE_DCS_WRITE1:
- len = mdss_dsi_dcs_swrite1(dp, cm);
- break;
- case DTYPE_DCS_READ:
- len = mdss_dsi_dcs_read(dp, cm);
- break;
- case DTYPE_MAX_PKTSIZE:
- len = mdss_dsi_set_max_pktsize(dp, cm);
- break;
- case DTYPE_NULL_PKT:
- len = mdss_dsi_null_pkt(dp, cm);
- break;
- case DTYPE_BLANK_PKT:
- len = mdss_dsi_blank_pkt(dp, cm);
- break;
- case DTYPE_CM_ON:
- len = mdss_dsi_cm_on(dp, cm);
- break;
- case DTYPE_CM_OFF:
- len = mdss_dsi_cm_off(dp, cm);
- break;
- case DTYPE_PERIPHERAL_ON:
- len = mdss_dsi_peripheral_on(dp, cm);
- break;
- case DTYPE_PERIPHERAL_OFF:
- len = mdss_dsi_peripheral_off(dp, cm);
- break;
- default:
- pr_debug("%s: dtype=%x NOT supported\n",
- __func__, dchdr->dtype);
- break;
-
- }
-
- return len;
-}
-
-/*
- * mdss_dsi_short_read1_resp: 1 parameter
- */
-static int mdss_dsi_short_read1_resp(struct dsi_buf *rp)
-{
- /* strip out dcs type */
- rp->data++;
- rp->len = 1;
- return rp->len;
-}
-
-/*
- * mdss_dsi_short_read2_resp: 2 parameter
- */
-static int mdss_dsi_short_read2_resp(struct dsi_buf *rp)
-{
- /* strip out dcs type */
- rp->data++;
- rp->len = 2;
- return rp->len;
-}
-
-static int mdss_dsi_long_read_resp(struct dsi_buf *rp)
-{
- /* strip out dcs header */
- rp->data += 4;
- rp->len -= 4;
- return rp->len;
-}
-
-void mdss_dsi_cmd_test_pattern(struct mdss_panel_data *pdata)
-{
- struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
int i;
- if (pdata == NULL) {
- pr_err("%s: Invalid input data\n", __func__);
- return;
- }
-
- ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
- panel_data);
-
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x015c, 0x201);
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x016c, 0xff0000); /* red */
+ MIPI_OUTP((ctrl->ctrl_base) + 0x015c, 0x021);
+ MIPI_OUTP((ctrl->ctrl_base) + 0x0164, 0xff0000); /* red */
i = 0;
while (i++ < 50) {
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0184, 0x1);
+ MIPI_OUTP((ctrl->ctrl_base) + 0x0180, 0x1);
/* Add sleep to get ~50 fps frame rate*/
msleep(20);
}
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x015c, 0x0);
+ MIPI_OUTP((ctrl->ctrl_base) + 0x015c, 0x0);
+}
+
+void mdss_dsi_cmd_test_pattern(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ int i;
+
+ MIPI_OUTP((ctrl->ctrl_base) + 0x015c, 0x201);
+ MIPI_OUTP((ctrl->ctrl_base) + 0x016c, 0xff0000); /* red */
+ i = 0;
+ while (i++ < 50) {
+ MIPI_OUTP((ctrl->ctrl_base) + 0x0184, 0x1);
+ /* Add sleep to get ~50 fps frame rate*/
+ msleep(20);
+ }
+ MIPI_OUTP((ctrl->ctrl_base) + 0x015c, 0x0);
}
void mdss_dsi_host_init(struct mipi_panel_info *pinfo,
@@ -1107,14 +547,14 @@
if (mode == DSI_VIDEO_MODE) {
dsi_ctrl |= 0x03;
- intr_ctrl = DSI_INTR_CMD_DMA_DONE_MASK;
+ intr_ctrl = DSI_INTR_CMD_DMA_DONE_MASK | DSI_INTR_BTA_DONE_MASK;
} else { /* command mode */
dsi_ctrl |= 0x05;
if (pdata->panel_info.type == MIPI_VIDEO_PANEL)
dsi_ctrl |= 0x02;
intr_ctrl = DSI_INTR_CMD_DMA_DONE_MASK | DSI_INTR_ERROR_MASK |
- DSI_INTR_CMD_MDP_DONE_MASK;
+ DSI_INTR_CMD_MDP_DONE_MASK | DSI_INTR_BTA_DONE_MASK;
}
if (ctrl_pdata->shared_pdata.broadcast_enable)
@@ -1160,38 +600,43 @@
pr_debug("%s: BTA done, status = %d\n", __func__, status);
}
-static char set_tear_on[2] = {0x35, 0x00};
-static struct dsi_cmd_desc dsi_tear_on_cmd = {
- {DTYPE_DCS_WRITE1, 1, 0, 0, 0, sizeof(set_tear_on)}, set_tear_on};
-
-static char set_tear_off[2] = {0x34, 0x00};
-static struct dsi_cmd_desc dsi_tear_off_cmd = {
- {DTYPE_DCS_WRITE, 1, 0, 0, 0, sizeof(set_tear_off)}, set_tear_off};
-
-void mdss_dsi_set_tear_on(struct mdss_dsi_ctrl_pdata *ctrl)
+int mdss_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
- struct dcs_cmd_req cmdreq;
+ int ret = 0;
+ unsigned long flag;
- cmdreq.cmds = &dsi_tear_on_cmd;
- cmdreq.cmds_cnt = 1;
- cmdreq.flags = CMD_REQ_COMMIT;
- cmdreq.rlen = 0;
- cmdreq.cb = NULL;
+ if (ctrl_pdata == NULL) {
+ pr_err("%s: Invalid input data\n", __func__);
- mdss_dsi_cmdlist_put(ctrl, &cmdreq);
-}
+ /*
+ * This should not return error otherwise
+ * BTA status thread will treat it as dead panel scenario
+ * and request for blank/unblank
+ */
+ return 0;
+ }
-void mdss_dsi_set_tear_off(struct mdss_dsi_ctrl_pdata *ctrl)
-{
- struct dcs_cmd_req cmdreq;
+ pr_debug("%s: Checking BTA status\n", __func__);
- cmdreq.cmds = &dsi_tear_off_cmd;
- cmdreq.cmds_cnt = 1;
- cmdreq.flags = CMD_REQ_COMMIT;
- cmdreq.rlen = 0;
- cmdreq.cb = NULL;
+ mdss_dsi_clk_ctrl(ctrl_pdata, 1);
+ spin_lock_irqsave(&ctrl_pdata->mdp_lock, flag);
+ INIT_COMPLETION(ctrl_pdata->bta_comp);
+ mdss_dsi_enable_irq(ctrl_pdata, DSI_BTA_TERM);
+ spin_unlock_irqrestore(&ctrl_pdata->mdp_lock, flag);
+ MIPI_OUTP(ctrl_pdata->ctrl_base + 0x098, 0x01); /* trigger */
+ wmb();
- mdss_dsi_cmdlist_put(ctrl, &cmdreq);
+ ret = wait_for_completion_killable_timeout(&ctrl_pdata->bta_comp,
+ DSI_BTA_EVENT_TIMEOUT);
+ if (ret <= 0) {
+ mdss_dsi_disable_irq(ctrl_pdata, DSI_BTA_TERM);
+ pr_err("%s: DSI BTA error: %i\n", __func__, ret);
+ }
+
+ mdss_dsi_clk_ctrl(ctrl_pdata, 0);
+ pr_debug("%s: BTA done with ret: %d\n", __func__, ret);
+
+ return ret;
}
int mdss_dsi_cmd_reg_tx(u32 data,
@@ -1708,45 +1153,63 @@
/* wait until DMA finishes the current job */
pr_debug("%s: pending pid=%d\n",
__func__, current->pid);
- wait_for_completion(&ctrl->mdp_comp);
+ if (!wait_for_completion_timeout(&ctrl->mdp_comp,
+ msecs_to_jiffies(DMA_TX_TIMEOUT)))
+ pr_err("%s: timeout error\n", __func__);
}
pr_debug("%s: done pid=%d\n",
__func__, current->pid);
}
-void mdss_dsi_cmdlist_tx(struct mdss_dsi_ctrl_pdata *ctrl,
+int mdss_dsi_cmdlist_tx(struct mdss_dsi_ctrl_pdata *ctrl,
struct dcs_cmd_req *req)
{
- int ret;
+ int ret, ret_val = -EINVAL;
ret = mdss_dsi_cmds_tx(ctrl, req->cmds, req->cmds_cnt);
+ if (!IS_ERR_VALUE(ret))
+ ret_val = 0;
+
if (req->cb)
req->cb(ret);
+ return ret_val;
}
-void mdss_dsi_cmdlist_rx(struct mdss_dsi_ctrl_pdata *ctrl,
+int mdss_dsi_cmdlist_rx(struct mdss_dsi_ctrl_pdata *ctrl,
struct dcs_cmd_req *req)
{
struct dsi_buf *rp;
- int len = 0;
+ int len = 0, ret = -EINVAL;
if (req->rbuf) {
rp = &ctrl->rx_buf;
len = mdss_dsi_cmds_rx(ctrl, req->cmds, req->rlen);
memcpy(req->rbuf, rp->data, rp->len);
+ /*
+ * For dual DSI cases, early return of controller - 0
+ * is valid. Hence, for those cases the return value
+ * is zero even though we don't send any commands.
+ *
+ */
+ if ((ctrl->shared_pdata.broadcast_enable &&
+ ctrl->ndx == DSI_CTRL_0) || (len != 0))
+ ret = 0;
} else {
pr_err("%s: No rx buffer provided\n", __func__);
}
if (req->cb)
req->cb(len);
+
+ return ret;
}
-void mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp)
+int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp)
{
struct dcs_cmd_req *req;
+ int ret = -EINVAL;
mutex_lock(&ctrl->cmd_mutex);
req = mdss_dsi_cmdlist_get(ctrl);
@@ -1771,9 +1234,9 @@
mdss_dsi_clk_ctrl(ctrl, 1);
if (req->flags & CMD_REQ_RX)
- mdss_dsi_cmdlist_rx(ctrl, req);
+ ret = mdss_dsi_cmdlist_rx(ctrl, req);
else
- mdss_dsi_cmdlist_tx(ctrl, req);
+ ret = mdss_dsi_cmdlist_tx(ctrl, req);
mdss_dsi_clk_ctrl(ctrl, 0);
mdss_bus_bandwidth_ctrl(0);
@@ -1784,63 +1247,9 @@
mdss_dsi_cmd_mdp_start(ctrl);
mutex_unlock(&ctrl->cmd_mutex);
-}
-
-/*
- * mdss_dsi_cmd_get: ctrl->cmd_mutex acquired by caller
- */
-struct dcs_cmd_req *mdss_dsi_cmdlist_get(struct mdss_dsi_ctrl_pdata *ctrl)
-{
- struct dcs_cmd_list *clist;
- struct dcs_cmd_req *req = NULL;
-
- clist = &ctrl->cmdlist;
- if (clist->get != clist->put) {
- req = &clist->list[clist->get];
- clist->get++;
- clist->get %= CMD_REQ_MAX;
- clist->tot--;
- pr_debug("%s: tot=%d put=%d get=%d\n", __func__,
- clist->tot, clist->put, clist->get);
- }
- return req;
-}
-
-int mdss_dsi_cmdlist_put(struct mdss_dsi_ctrl_pdata *ctrl,
- struct dcs_cmd_req *cmdreq)
-{
- struct dcs_cmd_req *req;
- struct dcs_cmd_list *clist;
- int ret = 0;
-
- mutex_lock(&ctrl->cmd_mutex);
- clist = &ctrl->cmdlist;
- req = &clist->list[clist->put];
- *req = *cmdreq;
- clist->put++;
- clist->put %= CMD_REQ_MAX;
- clist->tot++;
- if (clist->put == clist->get) {
- /* drop the oldest one */
- pr_debug("%s: DROP, tot=%d put=%d get=%d\n", __func__,
- clist->tot, clist->put, clist->get);
- clist->get++;
- clist->get %= CMD_REQ_MAX;
- clist->tot--;
- }
- mutex_unlock(&ctrl->cmd_mutex);
-
- ret++;
- pr_debug("%s: tot=%d put=%d get=%d\n", __func__,
- clist->tot, clist->put, clist->get);
-
- if (req->flags & CMD_REQ_COMMIT)
- mdss_dsi_cmdlist_commit(ctrl, 0);
-
return ret;
}
-
static void dsi_send_events(struct mdss_dsi_ctrl_pdata *ctrl, u32 events)
{
struct dsi_event_q *evq;
@@ -1928,6 +1337,8 @@
if (status) {
MIPI_OUTP(base + 0x0068, status);
+ /* Writing of an extra 0 needed to clear error bits */
+ MIPI_OUTP(base + 0x0068, 0);
pr_err("%s: status=%x\n", __func__, status);
}
}
@@ -2078,5 +1489,12 @@
spin_unlock(&ctrl->mdp_lock);
}
+ if (isr & DSI_INTR_BTA_DONE) {
+ spin_lock(&ctrl->mdp_lock);
+ mdss_dsi_disable_irq_nosync(ctrl, DSI_BTA_TERM);
+ complete(&ctrl->bta_comp);
+ spin_unlock(&ctrl->mdp_lock);
+ }
+
return IRQ_HANDLED;
}
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index 9932186..60e2cf9 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -19,7 +19,7 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/leds.h>
-#include <linux/pwm.h>
+#include <linux/qpnp/pwm.h>
#include <linux/err.h>
#include "mdss_dsi.h"
@@ -30,29 +30,10 @@
void mdss_dsi_panel_pwm_cfg(struct mdss_dsi_ctrl_pdata *ctrl)
{
- int ret;
-
- if (!gpio_is_valid(ctrl->pwm_pmic_gpio)) {
- pr_err("%s: pwm_pmic_gpio=%d Invalid\n", __func__,
- ctrl->pwm_pmic_gpio);
- ctrl->pwm_pmic_gpio = -1;
- return;
- }
-
- ret = gpio_request(ctrl->pwm_pmic_gpio, "disp_pwm");
- if (ret) {
- pr_err("%s: pwm_pmic_gpio=%d request failed\n", __func__,
- ctrl->pwm_pmic_gpio);
- ctrl->pwm_pmic_gpio = -1;
- return;
- }
-
ctrl->pwm_bl = pwm_request(ctrl->pwm_lpg_chan, "lcd-bklt");
if (ctrl->pwm_bl == NULL || IS_ERR(ctrl->pwm_bl)) {
- pr_err("%s: lpg_chan=%d pwm request failed", __func__,
- ctrl->pwm_lpg_chan);
- gpio_free(ctrl->pwm_pmic_gpio);
- ctrl->pwm_pmic_gpio = -1;
+ pr_err("%s: Error: lpg_chan=%d pwm request failed",
+ __func__, ctrl->pwm_lpg_chan);
}
}
@@ -88,9 +69,9 @@
ctrl->pwm_enabled = 0;
}
- ret = pwm_config(ctrl->pwm_bl, duty, ctrl->pwm_period);
+ ret = pwm_config_us(ctrl->pwm_bl, duty, ctrl->pwm_period);
if (ret) {
- pr_err("%s: pwm_config() failed err=%d.\n", __func__, ret);
+ pr_err("%s: pwm_config_us() failed err=%d.\n", __func__, ret);
return;
}
@@ -137,6 +118,11 @@
cmdreq.cmds = pcmds->cmds;
cmdreq.cmds_cnt = pcmds->cmd_cnt;
cmdreq.flags = CMD_REQ_COMMIT;
+
+ /*Panel ON/Off commands should be sent in DSI Low Power Mode*/
+ if (pcmds->link_state == DSI_LP_MODE)
+ cmdreq.flags |= CMD_REQ_LP_MODE;
+
cmdreq.rlen = 0;
cmdreq.cb = NULL;
@@ -293,6 +279,15 @@
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
panel_data);
+ /*
+ * Some backlight controllers specify a minimum duty cycle
+ * for the backlight brightness. If the brightness is less
+ * than it, the controller can malfunction.
+ */
+
+ if ((bl_level < pdata->panel_info.bl_min) && (bl_level != 0))
+ bl_level = pdata->panel_info.bl_min;
+
switch (ctrl_pdata->bklt_ctrl) {
case BL_WLED:
led_trigger_event(bl_led_trigger, bl_level);
@@ -357,6 +352,49 @@
return 0;
}
+static void mdss_dsi_parse_lane_swap(struct device_node *np, char *dlane_swap)
+{
+ const char *data;
+
+ *dlane_swap = DSI_LANE_MAP_0123;
+ data = of_get_property(np, "qcom,mdss-dsi-lane-map", NULL);
+ if (data) {
+ if (!strcmp(data, "lane_map_3012"))
+ *dlane_swap = DSI_LANE_MAP_3012;
+ else if (!strcmp(data, "lane_map_2301"))
+ *dlane_swap = DSI_LANE_MAP_2301;
+ else if (!strcmp(data, "lane_map_1230"))
+ *dlane_swap = DSI_LANE_MAP_1230;
+ else if (!strcmp(data, "lane_map_0321"))
+ *dlane_swap = DSI_LANE_MAP_0321;
+ else if (!strcmp(data, "lane_map_1032"))
+ *dlane_swap = DSI_LANE_MAP_1032;
+ else if (!strcmp(data, "lane_map_2103"))
+ *dlane_swap = DSI_LANE_MAP_2103;
+ else if (!strcmp(data, "lane_map_3210"))
+ *dlane_swap = DSI_LANE_MAP_3210;
+ }
+}
+
+static void mdss_dsi_parse_trigger(struct device_node *np, char *trigger,
+ char *trigger_key)
+{
+ const char *data;
+
+ *trigger = DSI_CMD_TRIGGER_SW;
+ data = of_get_property(np, trigger_key, NULL);
+ if (data) {
+ if (!strcmp(data, "none"))
+ *trigger = DSI_CMD_TRIGGER_NONE;
+ else if (!strcmp(data, "trigger_te"))
+ *trigger = DSI_CMD_TRIGGER_TE;
+ else if (!strcmp(data, "trigger_sw_seof"))
+ *trigger = DSI_CMD_TRIGGER_SW_SEOF;
+ else if (!strcmp(data, "trigger_sw_te"))
+ *trigger = DSI_CMD_TRIGGER_SW_TE;
+ }
+}
+
static int mdss_dsi_parse_dcs_cmds(struct device_node *np,
struct dsi_panel_cmds *pcmds, char *cmd_key, char *link_key)
@@ -389,7 +427,7 @@
if (dchdr->dlen > len) {
pr_err("%s: dtsi cmd=%x error, len=%d",
__func__, dchdr->dtype, dchdr->dlen);
- return -ENOMEM;
+ goto exit_free;
}
bp += sizeof(*dchdr);
len -= sizeof(*dchdr);
@@ -401,14 +439,13 @@
if (len != 0) {
pr_err("%s: dcs_cmd=%x len=%d error!",
__func__, buf[0], blen);
- kfree(buf);
- return -ENOMEM;
+ goto exit_free;
}
pcmds->cmds = kzalloc(cnt * sizeof(struct dsi_cmd_desc),
GFP_KERNEL);
if (!pcmds->cmds)
- return -ENOMEM;
+ goto exit_free;
pcmds->cmd_cnt = cnt;
pcmds->buf = buf;
@@ -427,7 +464,7 @@
}
data = of_get_property(np, link_key, NULL);
- if (!strncmp(data, "dsi_hs_mode", 11))
+ if (data && !strcmp(data, "dsi_hs_mode"))
pcmds->link_state = DSI_HS_MODE;
else
pcmds->link_state = DSI_LP_MODE;
@@ -436,6 +473,10 @@
pcmds->buf[0], pcmds->blen, pcmds->cmd_cnt, pcmds->link_state);
return 0;
+
+exit_free:
+ kfree(buf);
+ return -ENOMEM;
}
@@ -643,8 +684,10 @@
data = of_get_property(np, "qcom,mdss-dsi-panel-type", NULL);
if (data && !strncmp(data, "dsi_cmd_mode", 12))
pinfo->mipi.mode = DSI_CMD_MODE;
- rc = of_property_read_u32(np, "qcom,mdss-dsi-pixel-packing", &tmp);
- tmp = (!rc ? tmp : 0);
+ tmp = 0;
+ data = of_get_property(np, "qcom,mdss-dsi-pixel-packing", NULL);
+ if (data && !strcmp(data, "loose"))
+ tmp = 1;
rc = mdss_panel_dt_get_dst_fmt(pinfo->bpp,
pinfo->mipi.mode, tmp,
&(pinfo->mipi.dst_format));
@@ -657,19 +700,24 @@
pdest = of_get_property(np,
"qcom,mdss-dsi-panel-destination", NULL);
- if (strlen(pdest) != 9) {
- pr_err("%s: Unknown pdest specified\n", __func__);
+ if (pdest) {
+ if (strlen(pdest) != 9) {
+ pr_err("%s: Unknown pdest specified\n", __func__);
+ return -EINVAL;
+ }
+ if (!strcmp(pdest, "display_1"))
+ pinfo->pdest = DISPLAY_1;
+ else if (!strcmp(pdest, "display_2"))
+ pinfo->pdest = DISPLAY_2;
+ else {
+ pr_debug("%s: pdest not specified. Set Default\n",
+ __func__);
+ pinfo->pdest = DISPLAY_1;
+ }
+ } else {
+ pr_err("%s: pdest not specified\n", __func__);
return -EINVAL;
}
- if (!strncmp(pdest, "display_1", 9))
- pinfo->pdest = DISPLAY_1;
- else if (!strncmp(pdest, "display_2", 9))
- pinfo->pdest = DISPLAY_2;
- else {
- pr_debug("%s: pdest not specified. Set Default\n",
- __func__);
- pinfo->pdest = DISPLAY_1;
- }
rc = of_property_read_u32(np, "qcom,mdss-dsi-h-front-porch", &tmp);
pinfo->lcdc.h_front_porch = (!rc ? tmp : 6);
rc = of_property_read_u32(np, "qcom,mdss-dsi-h-back-porch", &tmp);
@@ -724,6 +772,8 @@
ctrl_pdata->bklt_ctrl = BL_DCS_CMD;
}
}
+ rc = of_property_read_u32(np, "qcom,mdss-brightness-max-level", &tmp);
+ pinfo->brightness_max = (!rc ? tmp : MDSS_MAX_BL_BRIGHTNESS);
rc = of_property_read_u32(np, "qcom,mdss-dsi-bl-min-level", &tmp);
pinfo->bl_min = (!rc ? tmp : 0);
rc = of_property_read_u32(np, "qcom,mdss-dsi-bl-max-level", &tmp);
@@ -752,10 +802,14 @@
"qcom,mdss-dsi-bllp-power-mode");
pinfo->mipi.eof_bllp_power_stop = of_property_read_bool(
np, "qcom,mdss-dsi-bllp-eof-power-mode");
- rc = of_property_read_u32(np,
- "qcom,mdss-dsi-traffic-mode", &tmp);
- pinfo->mipi.traffic_mode =
- (!rc ? tmp : DSI_NON_BURST_SYNCH_PULSE);
+ pinfo->mipi.traffic_mode = DSI_NON_BURST_SYNCH_PULSE;
+ data = of_get_property(np, "qcom,mdss-dsi-traffic-mode", NULL);
+ if (data) {
+ if (!strcmp(data, "non_burst_sync_event"))
+ pinfo->mipi.traffic_mode = DSI_NON_BURST_SYNCH_EVENT;
+ else if (!strcmp(data, "burst_mode"))
+ pinfo->mipi.traffic_mode = DSI_BURST_MODE;
+ }
rc = of_property_read_u32(np,
"qcom,mdss-dsi-te-dcs-command", &tmp);
pinfo->mipi.insert_dcs_cmd =
@@ -774,8 +828,20 @@
(!rc ? tmp : 1);
rc = of_property_read_u32(np, "qcom,mdss-dsi-virtual-channel-id", &tmp);
pinfo->mipi.vc = (!rc ? tmp : 0);
- rc = of_property_read_u32(np, "qcom,mdss-dsi-color-order", &tmp);
- pinfo->mipi.rgb_swap = (!rc ? tmp : DSI_RGB_SWAP_RGB);
+ pinfo->mipi.rgb_swap = DSI_RGB_SWAP_RGB;
+ data = of_get_property(np, "mdss-dsi-color-order", NULL);
+ if (data) {
+ if (!strcmp(data, "rgb_swap_rbg"))
+ pinfo->mipi.rgb_swap = DSI_RGB_SWAP_RBG;
+ else if (!strcmp(data, "rgb_swap_bgr"))
+ pinfo->mipi.rgb_swap = DSI_RGB_SWAP_BGR;
+ else if (!strcmp(data, "rgb_swap_brg"))
+ pinfo->mipi.rgb_swap = DSI_RGB_SWAP_BRG;
+ else if (!strcmp(data, "rgb_swap_grb"))
+ pinfo->mipi.rgb_swap = DSI_RGB_SWAP_GRB;
+ else if (!strcmp(data, "rgb_swap_gbr"))
+ pinfo->mipi.rgb_swap = DSI_RGB_SWAP_GBR;
+ }
pinfo->mipi.data_lane0 = of_property_read_bool(np,
"qcom,mdss-dsi-lane-0-state");
pinfo->mipi.data_lane1 = of_property_read_bool(np,
@@ -785,9 +851,6 @@
pinfo->mipi.data_lane3 = of_property_read_bool(np,
"qcom,mdss-dsi-lane-3-state");
- rc = of_property_read_u32(np, "qcom,mdss-dsi-lane-map", &tmp);
- pinfo->mipi.dlane_swap = (!rc ? tmp : 0);
-
rc = of_property_read_u32(np, "qcom,mdss-dsi-t-clk-pre", &tmp);
pinfo->mipi.t_clk_pre = (!rc ? tmp : 0x24);
rc = of_property_read_u32(np, "qcom,mdss-dsi-t-clk-post", &tmp);
@@ -796,26 +859,7 @@
rc = of_property_read_u32(np, "qcom,mdss-dsi-stream", &tmp);
pinfo->mipi.stream = (!rc ? tmp : 0);
- rc = of_property_read_u32(np, "qcom,mdss-dsi-mdp-trigger", &tmp);
- pinfo->mipi.mdp_trigger =
- (!rc ? tmp : DSI_CMD_TRIGGER_SW);
- if (pinfo->mipi.mdp_trigger > 6) {
- pr_err("%s:%d, Invalid mdp trigger. Forcing to sw trigger",
- __func__, __LINE__);
- pinfo->mipi.mdp_trigger =
- DSI_CMD_TRIGGER_SW;
- }
-
- rc = of_property_read_u32(np, "qcom,mdss-dsi-dma-trigger", &tmp);
- pinfo->mipi.dma_trigger =
- (!rc ? tmp : DSI_CMD_TRIGGER_SW);
- if (pinfo->mipi.dma_trigger > 6) {
- pr_err("%s:%d, Invalid dma trigger. Forcing to sw trigger",
- __func__, __LINE__);
- pinfo->mipi.dma_trigger =
- DSI_CMD_TRIGGER_SW;
- }
- data = of_get_property(np, "qcom,mdss-dsi-panel-mode-gpio-state", &tmp);
+ data = of_get_property(np, "qcom,mdss-dsi-panel-mode-gpio-state", NULL);
if (data) {
if (!strcmp(data, "high"))
pinfo->mode_gpio_state = MODE_GPIO_HIGH;
@@ -825,9 +869,9 @@
pinfo->mode_gpio_state = MODE_GPIO_NOT_VALID;
}
- rc = of_property_read_u32(np, "qcom,mdss-dsi-panel-frame-rate", &tmp);
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-panel-framerate", &tmp);
pinfo->mipi.frame_rate = (!rc ? tmp : 60);
- rc = of_property_read_u32(np, "qcom,mdss-dsi-panel-clock-rate", &tmp);
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-panel-clockrate", &tmp);
pinfo->clk_rate = (!rc ? tmp : 0);
data = of_get_property(np, "qcom,mdss-dsi-panel-timings", &len);
if ((!data) || (len != 12)) {
@@ -838,8 +882,21 @@
for (i = 0; i < len; i++)
pinfo->mipi.dsi_phy_db.timing[i] = data[i];
+ pinfo->mipi.lp11_init = of_property_read_bool(np,
+ "qcom,mdss-dsi-lp11-init");
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-init-delay-us", &tmp);
+ pinfo->mipi.init_delay = (!rc ? tmp : 0);
+
mdss_dsi_parse_fbc_params(np, pinfo);
+ mdss_dsi_parse_trigger(np, &(pinfo->mipi.mdp_trigger),
+ "qcom,mdss-dsi-mdp-trigger");
+
+ mdss_dsi_parse_trigger(np, &(pinfo->mipi.dma_trigger),
+ "qcom,mdss-dsi-dma-trigger");
+
+ mdss_dsi_parse_lane_swap(np, &(pinfo->mipi.dlane_swap));
+
mdss_dsi_parse_reset_seq(np, pinfo->rst_seq, &(pinfo->rst_seq_len),
"qcom,mdss-dsi-reset-sequence");
diff --git a/drivers/video/msm/mdss/mdss_dsi_status.c b/drivers/video/msm/mdss/mdss_dsi_status.c
new file mode 100644
index 0000000..f0c4f4c
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_dsi_status.c
@@ -0,0 +1,208 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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/kernel.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <linux/notifier.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/iopoll.h>
+#include <linux/kobject.h>
+#include <linux/string.h>
+#include <linux/sysfs.h>
+
+#include "mdss_fb.h"
+#include "mdss_dsi.h"
+#include "mdss_panel.h"
+#include "mdss_mdp.h"
+
+#define STATUS_CHECK_INTERVAL 5000
+
+struct dsi_status_data {
+ struct notifier_block fb_notifier;
+ struct delayed_work check_status;
+ struct msm_fb_data_type *mfd;
+ uint32_t check_interval;
+};
+struct dsi_status_data *pstatus_data;
+static uint32_t interval = STATUS_CHECK_INTERVAL;
+
+/*
+ * check_dsi_ctrl_status() - Check DSI controller status periodically.
+ * @work : dsi controller status data
+ *
+ * This function calls check_status API on DSI controller to send the BTA
+ * command. If DSI controller fails to acknowledge the BTA command, it sends
+ * the PANEL_ALIVE=0 status to HAL layer.
+ */
+static void check_dsi_ctrl_status(struct work_struct *work)
+{
+ struct dsi_status_data *pdsi_status = NULL;
+ struct mdss_panel_data *pdata = NULL;
+ struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+ struct mdss_overlay_private *mdp5_data = NULL;
+ struct mdss_mdp_ctl *ctl = NULL;
+ int ret = 0;
+
+ pdsi_status = container_of(to_delayed_work(work),
+ struct dsi_status_data, check_status);
+ if (!pdsi_status) {
+ pr_err("%s: DSI status data not available\n", __func__);
+ return;
+ }
+
+ pdata = dev_get_platdata(&pdsi_status->mfd->pdev->dev);
+ if (!pdata) {
+ pr_err("%s: Panel data not available\n", __func__);
+ return;
+ }
+
+ ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+ panel_data);
+ if (!ctrl_pdata || !ctrl_pdata->check_status) {
+ pr_err("%s: DSI ctrl or status_check callback not available\n",
+ __func__);
+ return;
+ }
+
+ mdp5_data = mfd_to_mdp5_data(pdsi_status->mfd);
+ ctl = mfd_to_ctl(pdsi_status->mfd);
+
+ if (ctl->shared_lock)
+ mutex_lock(ctl->shared_lock);
+ mutex_lock(&mdp5_data->ov_lock);
+
+ /*
+ * For the command mode panels, we return pan display
+ * IOCTL on vsync interrupt. So, after vsync interrupt comes
+ * and when DMA_P is in progress, if the panel stops responding
+ * and if we trigger BTA before DMA_P finishes, then the DSI
+ * FIFO will not be cleared since the DSI data bus control
+ * doesn't come back to the host after BTA. This may cause the
+ * display reset not to be proper. Hence, wait for DMA_P done
+ * for command mode panels before triggering BTA.
+ */
+ if (ctl->wait_pingpong)
+ ctl->wait_pingpong(ctl, NULL);
+
+ pr_debug("%s: DSI ctrl wait for ping pong done\n", __func__);
+
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ ret = ctrl_pdata->check_status(ctrl_pdata);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+ mutex_unlock(&mdp5_data->ov_lock);
+ if (ctl->shared_lock)
+ mutex_unlock(ctl->shared_lock);
+
+ if ((pdsi_status->mfd->panel_power_on)) {
+ if (ret > 0) {
+ schedule_delayed_work(&pdsi_status->check_status,
+ msecs_to_jiffies(pdsi_status->check_interval));
+ } else {
+ char *envp[2] = {"PANEL_ALIVE=0", NULL};
+ pdata->panel_info.panel_dead = true;
+ ret = kobject_uevent_env(
+ &pdsi_status->mfd->fbi->dev->kobj,
+ KOBJ_CHANGE, envp);
+ pr_err("%s: Panel has gone bad, sending uevent - %s\n",
+ __func__, envp[0]);
+ }
+ }
+}
+
+/*
+ * fb_event_callback() - Call back function for the fb_register_client()
+ * notifying events
+ * @self : notifier block
+ * @event : The event that was triggered
+ * @data : Of type struct fb_event
+ *
+ * This function listens for FB_BLANK_UNBLANK and FB_BLANK_POWERDOWN events
+ * from frame buffer. DSI status check work is either scheduled again after
+ * PANEL_STATUS_CHECK_INTERVAL or cancelled based on the event.
+ */
+static int fb_event_callback(struct notifier_block *self,
+ unsigned long event, void *data)
+{
+ struct fb_event *evdata = data;
+ struct dsi_status_data *pdata = container_of(self,
+ struct dsi_status_data, fb_notifier);
+ pdata->mfd = evdata->info->par;
+
+ if (event == FB_EVENT_BLANK && evdata) {
+ int *blank = evdata->data;
+ switch (*blank) {
+ case FB_BLANK_UNBLANK:
+ schedule_delayed_work(&pdata->check_status,
+ msecs_to_jiffies(pdata->check_interval));
+ break;
+ case FB_BLANK_POWERDOWN:
+ cancel_delayed_work(&pdata->check_status);
+ break;
+ }
+ }
+ return 0;
+}
+
+int __init mdss_dsi_status_init(void)
+{
+ int rc = 0;
+
+ pstatus_data = kzalloc(sizeof(struct dsi_status_data), GFP_KERNEL);
+ if (!pstatus_data) {
+ pr_err("%s: can't allocate memory\n", __func__);
+ return -ENOMEM;
+ }
+
+ pstatus_data->fb_notifier.notifier_call = fb_event_callback;
+
+ rc = fb_register_client(&pstatus_data->fb_notifier);
+ if (rc < 0) {
+ pr_err("%s: fb_register_client failed, returned with rc=%d\n",
+ __func__, rc);
+ kfree(pstatus_data);
+ return -EPERM;
+ }
+
+ pstatus_data->check_interval = interval;
+ pr_info("%s: DSI status check interval:%d\n", __func__, interval);
+
+ INIT_DELAYED_WORK(&pstatus_data->check_status, check_dsi_ctrl_status);
+
+ pr_debug("%s: DSI ctrl status work queue initialized\n", __func__);
+
+ return rc;
+}
+
+void __exit mdss_dsi_status_exit(void)
+{
+ fb_unregister_client(&pstatus_data->fb_notifier);
+ cancel_delayed_work_sync(&pstatus_data->check_status);
+ kfree(pstatus_data);
+ pr_debug("%s: DSI ctrl status work queue removed\n", __func__);
+}
+
+module_param(interval, uint, 0);
+MODULE_PARM_DESC(interval,
+ "Duration in milliseconds to send BTA command for checking"
+ "DSI status periodically");
+
+module_init(mdss_dsi_status_init);
+module_exit(mdss_dsi_status_exit);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/msm/mdss/mdss_edp.c b/drivers/video/msm/mdss/mdss_edp.c
index 042491d..95c746e 100644
--- a/drivers/video/msm/mdss/mdss_edp.c
+++ b/drivers/video/msm/mdss/mdss_edp.c
@@ -23,7 +23,7 @@
#include <linux/gpio.h>
#include <linux/err.h>
#include <linux/regulator/consumer.h>
-#include <linux/pwm.h>
+#include <linux/qpnp/pwm.h>
#include <linux/clk.h>
#include <linux/spinlock_types.h>
#include <linux/kthread.h>
@@ -210,11 +210,11 @@
if (bl_level > bl_max)
bl_level = bl_max;
- ret = pwm_config(edp_drv->bl_pwm,
+ ret = pwm_config_us(edp_drv->bl_pwm,
bl_level * edp_drv->pwm_period / bl_max,
edp_drv->pwm_period);
if (ret) {
- pr_err("%s: pwm_config() failed err=%d.\n", __func__,
+ pr_err("%s: pwm_config_us() failed err=%d.\n", __func__,
ret);
return;
}
@@ -228,38 +228,273 @@
}
}
-void mdss_edp_config_sync(unsigned char *base)
+int mdss_edp_mainlink_ready(struct mdss_edp_drv_pdata *ep, u32 which)
+{
+ u32 data;
+ int cnt = 10;
+
+ while (--cnt) {
+ data = edp_read(ep->base + 0x84); /* EDP_MAINLINK_READY */
+ if (data & which) {
+ pr_debug("%s: which=%x ready\n", __func__, which);
+ return 1;
+ }
+ usleep(1000);
+ }
+ pr_err("%s: which=%x NOT ready\n", __func__, which);
+
+ return 0;
+}
+
+void mdss_edp_mainlink_reset(struct mdss_edp_drv_pdata *ep)
+{
+ edp_write(ep->base + 0x04, 0x02); /* EDP_MAINLINK_CTRL */
+ usleep(1000);
+ edp_write(ep->base + 0x04, 0); /* EDP_MAINLINK_CTRL */
+}
+
+void mdss_edp_mainlink_ctrl(struct mdss_edp_drv_pdata *ep, int enable)
+{
+ u32 data;
+
+ data = edp_read(ep->base + 0x04);
+ data &= ~BIT(0);
+
+ if (enable)
+ data |= 0x1;
+
+ edp_write(ep->base + 0x04, data);
+}
+
+void mdss_edp_state_ctrl(struct mdss_edp_drv_pdata *ep, u32 state)
+{
+ edp_write(ep->base + EDP_STATE_CTRL, state);
+}
+
+void mdss_edp_aux_reset(struct mdss_edp_drv_pdata *ep)
+{
+ /* reset AUX */
+ edp_write(ep->base + 0x300, BIT(1)); /* EDP_AUX_CTRL */
+ usleep(1000);
+ edp_write(ep->base + 0x300, 0); /* EDP_AUX_CTRL */
+}
+
+void mdss_edp_aux_ctrl(struct mdss_edp_drv_pdata *ep, int enable)
+{
+ u32 data;
+
+ data = edp_read(ep->base + 0x300);
+ if (enable)
+ data |= 0x01;
+ else
+ data |= ~0x01;
+ edp_write(ep->base + 0x300, data); /* EDP_AUX_CTRL */
+}
+
+void mdss_edp_phy_pll_reset(struct mdss_edp_drv_pdata *ep)
+{
+ /* EDP_PHY_CTRL */
+ edp_write(ep->base + 0x74, 0x005); /* bit 0, 2 */
+ usleep(1000);
+ edp_write(ep->base + 0x74, 0x000); /* EDP_PHY_CTRL */
+}
+
+int mdss_edp_phy_pll_ready(struct mdss_edp_drv_pdata *ep)
+{
+ int cnt;
+ u32 status = 0;
+
+ cnt = 100;
+ while (--cnt) {
+ status = edp_read(ep->base + 0x6c0);
+ if (status & 0x01)
+ break;
+ usleep(100);
+ }
+
+ pr_debug("%s: PLL cnt=%d status=%x\n", __func__, cnt, (int)status);
+
+ if (cnt <= 0) {
+ pr_err("%s: PLL NOT ready\n", __func__);
+ return 0;
+ } else
+ return 1;
+}
+
+int mdss_edp_phy_ready(struct mdss_edp_drv_pdata *ep)
+{
+ u32 status;
+
+ status = edp_read(ep->base + 0x598);
+ status &= 0x01;
+
+ return status;
+}
+
+void mdss_edp_phy_power_ctrl(struct mdss_edp_drv_pdata *ep, int enable)
+{
+ if (enable) {
+ /* EDP_PHY_EDPPHY_GLB_PD_CTL */
+ edp_write(ep->base + 0x52c, 0x3f);
+ /* EDP_PHY_EDPPHY_GLB_CFG */
+ edp_write(ep->base + 0x528, 0x1);
+ /* EDP_PHY_PLL_UNIPHY_PLL_GLB_CFG */
+ edp_write(ep->base + 0x620, 0xf);
+ } else {
+ /* EDP_PHY_EDPPHY_GLB_PD_CTL */
+ edp_write(ep->base + 0x52c, 0xc0);
+ }
+}
+
+void mdss_edp_lane_power_ctrl(struct mdss_edp_drv_pdata *ep, int up)
+{
+ int i, off, max_lane;
+ u32 data;
+
+ max_lane = ep->lane_cnt;
+
+ if (up)
+ data = 0; /* power up */
+ else
+ data = 0x7; /* power down */
+
+ /* EDP_PHY_EDPPHY_LNn_PD_CTL */
+ for (i = 0; i < max_lane; i++) {
+ off = 0x40 * i;
+ edp_write(ep->base + 0x404 + off , data);
+ }
+
+ /* power down un used lane */
+ data = 0x7; /* power down */
+ for (i = max_lane; i < EDP_MAX_LANE; i++) {
+ off = 0x40 * i;
+ edp_write(ep->base + 0x404 + off , data);
+ }
+}
+
+void mdss_edp_clock_synchrous(struct mdss_edp_drv_pdata *ep, int sync)
+{
+ u32 data;
+
+ /* EDP_MISC1_MISC0 */
+ data = edp_read(ep->base + 0x02c);
+
+ if (sync)
+ data |= 0x01;
+ else
+ data &= ~0x01;
+
+ /* EDP_MISC1_MISC0 */
+ edp_write(ep->base + 0x2c, data);
+}
+
+/* voltage mode and pre emphasis cfg */
+void mdss_edp_phy_vm_pe_init(struct mdss_edp_drv_pdata *ep)
+{
+ /* EDP_PHY_EDPPHY_GLB_VM_CFG0 */
+ edp_write(ep->base + 0x510, 0x3); /* vm only */
+ /* EDP_PHY_EDPPHY_GLB_VM_CFG1 */
+ edp_write(ep->base + 0x514, 0x64);
+ /* EDP_PHY_EDPPHY_GLB_MISC9 */
+ edp_write(ep->base + 0x518, 0x6c);
+}
+
+void mdss_edp_config_ctrl(struct mdss_edp_drv_pdata *ep)
+{
+ struct dpcd_cap *cap;
+ struct display_timing_desc *dp;
+ u32 data = 0;
+
+ dp = &ep->edid.timing[0];
+
+ cap = &ep->dpcd;
+
+ data = ep->lane_cnt - 1;
+ data <<= 4;
+
+ if (cap->enhanced_frame)
+ data |= 0x40;
+
+ if (ep->edid.color_depth == 8) {
+ /* 0 == 6 bits, 1 == 8 bits */
+ data |= 0x100; /* bit 8 */
+ }
+
+ if (!dp->interlaced) /* progressive */
+ data |= 0x04;
+
+ data |= 0x03; /* sycn clock & static Mvid */
+
+ edp_write(ep->base + 0xc, data); /* EDP_CONFIGURATION_CTRL */
+}
+
+static void mdss_edp_sw_mvid_nvid(struct mdss_edp_drv_pdata *ep)
+{
+ edp_write(ep->base + 0x14, 0x13b); /* EDP_SOFTWARE_MVID */
+ edp_write(ep->base + 0x18, 0x266); /* EDP_SOFTWARE_NVID */
+}
+
+static void mdss_edp_timing_cfg(struct mdss_edp_drv_pdata *ep)
+{
+ struct mdss_panel_info *pinfo;
+ u32 total_ver, total_hor;
+ u32 data;
+
+ pinfo = &ep->panel_data.panel_info;
+
+ pr_debug("%s: width=%d hporch= %d %d %d\n", __func__,
+ pinfo->xres, pinfo->lcdc.h_back_porch,
+ pinfo->lcdc.h_front_porch, pinfo->lcdc.h_pulse_width);
+
+ pr_debug("%s: height=%d vporch= %d %d %d\n", __func__,
+ pinfo->yres, pinfo->lcdc.v_back_porch,
+ pinfo->lcdc.v_front_porch, pinfo->lcdc.v_pulse_width);
+
+ total_hor = pinfo->xres + pinfo->lcdc.h_back_porch +
+ pinfo->lcdc.h_front_porch + pinfo->lcdc.h_pulse_width;
+
+ total_ver = pinfo->yres + pinfo->lcdc.v_back_porch +
+ pinfo->lcdc.v_front_porch + pinfo->lcdc.v_pulse_width;
+
+ data = total_ver;
+ data <<= 16;
+ data |= total_hor;
+ edp_write(ep->base + 0x1c, data); /* EDP_TOTAL_HOR_VER */
+
+ data = (pinfo->lcdc.v_back_porch + pinfo->lcdc.v_pulse_width);
+ data <<= 16;
+ data |= (pinfo->lcdc.h_back_porch + pinfo->lcdc.h_pulse_width);
+ edp_write(ep->base + 0x20, data); /* EDP_START_HOR_VER_FROM_SYNC */
+
+ data = pinfo->lcdc.v_pulse_width;
+ data <<= 16;
+ data |= pinfo->lcdc.h_pulse_width;
+ edp_write(ep->base + 0x24, data); /* EDP_HSYNC_VSYNC_WIDTH_POLARITY */
+
+ data = pinfo->yres;
+ data <<= 16;
+ data |= pinfo->xres;
+ edp_write(ep->base + 0x28, data); /* EDP_ACTIVE_HOR_VER */
+}
+
+int mdss_edp_wait4train(struct mdss_edp_drv_pdata *edp_drv)
{
int ret = 0;
- ret = edp_read(base + 0xc); /* EDP_CONFIGURATION_CTRL */
- ret &= ~0x733;
- ret |= (0x55 & 0x733);
- edp_write(base + 0xc, ret);
- edp_write(base + 0xc, 0x55); /* EDP_CONFIGURATION_CTRL */
-}
+ if (edp_drv->cont_splash)
+ return ret;
-static void mdss_edp_config_sw_div(unsigned char *base)
-{
- edp_write(base + 0x14, 0x13b); /* EDP_SOFTWARE_MVID */
- edp_write(base + 0x18, 0x266); /* EDP_SOFTWARE_NVID */
-}
+ ret = wait_for_completion_timeout(&edp_drv->video_comp, 30);
+ if (ret <= 0) {
+ pr_err("%s: Link Train timedout\n", __func__);
+ ret = -EINVAL;
+ } else {
+ ret = 0;
+ }
-static void mdss_edp_config_static_mdiv(unsigned char *base)
-{
- int ret = 0;
+ pr_debug("%s:\n", __func__);
- ret = edp_read(base + 0xc); /* EDP_CONFIGURATION_CTRL */
- edp_write(base + 0xc, ret | 0x2); /* EDP_CONFIGURATION_CTRL */
- edp_write(base + 0xc, 0x57); /* EDP_CONFIGURATION_CTRL */
-}
-
-static void mdss_edp_enable(unsigned char *base, int enable)
-{
- edp_write(base + 0x8, 0x0); /* EDP_STATE_CTRL */
- edp_write(base + 0x8, 0x40); /* EDP_STATE_CTRL */
- edp_write(base + 0x94, enable); /* EDP_TIMING_ENGINE_EN */
- edp_write(base + 0x4, enable); /* EDP_MAINLINK_CTRL */
+ return ret;
}
static void mdss_edp_irq_enable(struct mdss_edp_drv_pdata *edp_drv);
@@ -278,73 +513,53 @@
edp_drv = container_of(pdata, struct mdss_edp_drv_pdata,
panel_data);
- pr_debug("%s:+\n", __func__);
- if (edp_drv->train_start == 0)
- edp_drv->train_start++;
+ pr_debug("%s:+, cont_splash=%d\n", __func__, edp_drv->cont_splash);
- mdss_edp_phy_pll_reset(edp_drv->base);
- mdss_edp_aux_reset(edp_drv->base);
- mdss_edp_mainlink_reset(edp_drv->base);
-
- ret = mdss_edp_prepare_clocks(edp_drv);
- if (ret)
- return ret;
- mdss_edp_phy_powerup(edp_drv->base, 1);
-
- mdss_edp_pll_configure(edp_drv->base, edp_drv->edid.timing[0].pclk);
- mdss_edp_phy_pll_ready(edp_drv->base);
-
- ret = mdss_edp_clk_enable(edp_drv);
- if (ret) {
- mdss_edp_unprepare_clocks(edp_drv);
- return ret;
- }
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
- mdss_edp_aux_ctrl(edp_drv->base, 1);
+ if (!edp_drv->cont_splash) { /* vote for clocks */
+ mdss_edp_phy_pll_reset(edp_drv);
+ mdss_edp_aux_reset(edp_drv);
+ mdss_edp_mainlink_reset(edp_drv);
+ mdss_edp_aux_ctrl(edp_drv, 1);
- mdss_edp_lane_power_ctrl(edp_drv->base,
- edp_drv->dpcd.max_lane_count, 1);
- mdss_edp_enable_mainlink(edp_drv->base, 1);
- mdss_edp_config_clk(edp_drv->base, edp_drv->mmss_cc_base);
+ ret = mdss_edp_prepare_clocks(edp_drv);
+ if (ret)
+ return ret;
- mdss_edp_clock_synchrous(edp_drv->base, 1);
- mdss_edp_phy_vm_pe_init(edp_drv->base);
- mdss_edp_config_sync(edp_drv->base);
- mdss_edp_config_sw_div(edp_drv->base);
- mdss_edp_config_static_mdiv(edp_drv->base);
- gpio_set_value(edp_drv->gpio_panel_en, 1);
+ mdss_edp_phy_power_ctrl(edp_drv, 1);
+
+ ret = mdss_edp_clk_enable(edp_drv);
+ if (ret) {
+ mdss_edp_unprepare_clocks(edp_drv);
+ return ret;
+ }
+
+ mdss_edp_phy_pll_ready(edp_drv);
+
+ mdss_edp_lane_power_ctrl(edp_drv, 1);
+
+ mdss_edp_clock_synchrous(edp_drv, 1);
+ mdss_edp_phy_vm_pe_init(edp_drv);
+ mdss_edp_config_ctrl(edp_drv);
+ mdss_edp_sw_mvid_nvid(edp_drv);
+ mdss_edp_timing_cfg(edp_drv);
+
+ gpio_set_value(edp_drv->gpio_panel_en, 1);
+
+ INIT_COMPLETION(edp_drv->idle_comp);
+ mdss_edp_mainlink_ctrl(edp_drv, 1);
+ } else {
+ mdss_edp_aux_ctrl(edp_drv, 1);
+ }
+
mdss_edp_irq_enable(edp_drv);
+ mdss_edp_wait4train(edp_drv);
+
+ edp_drv->cont_splash = 0;
+
pr_debug("%s:-\n", __func__);
- return 0;
-}
-
-int mdss_edp_wait4train(struct mdss_panel_data *pdata)
-{
- struct mdss_edp_drv_pdata *edp_drv = NULL;
- int ret = 0;
-
- if (!pdata) {
- pr_err("%s: Invalid input data\n", __func__);
- return -EINVAL;
- }
-
- edp_drv = container_of(pdata, struct mdss_edp_drv_pdata,
- panel_data);
-
- ret = wait_for_completion_timeout(&edp_drv->train_comp, 100);
- if (ret <= 0) {
- pr_err("%s: Link Train timedout\n", __func__);
- ret = -EINVAL;
- } else {
- ret = 0;
- }
-
- mdss_edp_enable(edp_drv->base, 1);
-
- pr_debug("%s:\n", __func__);
-
return ret;
}
@@ -359,28 +574,44 @@
pr_err("%s: Invalid input data\n", __func__);
return -EINVAL;
}
- pr_debug("%s:+\n", __func__);
+ pr_debug("%s:+, cont_splash=%d\n", __func__, edp_drv->cont_splash);
+
+
+ INIT_COMPLETION(edp_drv->idle_comp);
+ mdss_edp_state_ctrl(edp_drv, ST_PUSH_IDLE);
+
+ ret = wait_for_completion_timeout(&edp_drv->idle_comp,
+ msecs_to_jiffies(100));
+ if (ret == 0)
+ pr_err("%s: idle pattern timedout\n", __func__);
+
+ mdss_edp_state_ctrl(edp_drv, 0);
+
+ mdss_edp_sink_power_state(edp_drv, SINK_POWER_OFF);
mdss_edp_irq_disable(edp_drv);
gpio_set_value(edp_drv->gpio_panel_en, 0);
+
if (edp_drv->bl_pwm != NULL)
pwm_disable(edp_drv->bl_pwm);
- mdss_edp_enable(edp_drv->base, 0);
- mdss_edp_unconfig_clk(edp_drv->base, edp_drv->mmss_cc_base);
- mdss_edp_enable_mainlink(edp_drv->base, 0);
- mdss_edp_lane_power_ctrl(edp_drv->base,
- edp_drv->dpcd.max_lane_count, 0);
+ mdss_edp_mainlink_reset(edp_drv);
+ mdss_edp_mainlink_ctrl(edp_drv, 0);
+
+ mdss_edp_lane_power_ctrl(edp_drv, 0);
+ mdss_edp_phy_power_ctrl(edp_drv, 0);
+
mdss_edp_clk_disable(edp_drv);
- mdss_edp_phy_powerup(edp_drv->base, 0);
mdss_edp_unprepare_clocks(edp_drv);
+
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
- mdss_edp_aux_ctrl(edp_drv->base, 0);
+ mdss_edp_aux_ctrl(edp_drv, 0);
- pr_debug("%s:-\n", __func__);
- return ret;
+ pr_debug("%s-: state_ctrl=%x\n", __func__,
+ edp_read(edp_drv->base + 0x8));
+ return 0;
}
static int mdss_edp_event_handler(struct mdss_panel_data *pdata,
@@ -393,9 +624,6 @@
case MDSS_EVENT_UNBLANK:
rc = mdss_edp_on(pdata);
break;
- case MDSS_EVENT_PANEL_ON:
- rc = mdss_edp_wait4train(pdata);
- break;
case MDSS_EVENT_PANEL_OFF:
rc = mdss_edp_off(pdata);
break;
@@ -469,14 +697,22 @@
static int mdss_edp_device_register(struct mdss_edp_drv_pdata *edp_drv)
{
int ret;
+ u32 tmp;
mdss_edp_edid2pinfo(edp_drv);
edp_drv->panel_data.panel_info.bl_min = 1;
edp_drv->panel_data.panel_info.bl_max = 255;
+ ret = of_property_read_u32(edp_drv->pdev->dev.of_node,
+ "qcom,mdss-brightness-max-level", &tmp);
+ edp_drv->panel_data.panel_info.brightness_max =
+ (!ret ? tmp : MDSS_MAX_BL_BRIGHTNESS);
edp_drv->panel_data.event_handler = mdss_edp_event_handler;
edp_drv->panel_data.set_backlight = mdss_edp_set_backlight;
+ edp_drv->panel_data.panel_info.cont_splash_enabled =
+ edp_drv->cont_splash;
+
ret = mdss_register_panel(edp_drv->pdev, &edp_drv->panel_data);
if (ret) {
dev_err(&(edp_drv->pdev->dev), "unable to register eDP\n");
@@ -539,10 +775,25 @@
return 0;
}
-static void mdss_edp_video_ready(struct mdss_edp_drv_pdata *edp_drv)
+static void mdss_edp_video_ready(struct mdss_edp_drv_pdata *ep)
{
pr_debug("%s: edp_video_ready\n", __func__);
+ complete(&ep->video_comp);
+}
+static void mdss_edp_idle_patterns_sent(struct mdss_edp_drv_pdata *ep)
+{
+ pr_debug("%s: idle_patterns_sent\n", __func__);
+ complete(&ep->idle_comp);
+}
+
+static void mdss_edp_do_link_train(struct mdss_edp_drv_pdata *ep)
+{
+ if (ep->cont_splash)
+ return;
+
+ INIT_COMPLETION(ep->train_comp);
+ mdss_edp_link_train(ep);
}
static int edp_event_thread(void *data)
@@ -579,13 +830,14 @@
if (todo & EV_DPCD_STATUS_READ)
mdss_edp_dpcd_status_read(ep);
- if (todo & EV_LINK_TRAIN) {
- INIT_COMPLETION(ep->train_comp);
- mdss_edp_link_train(ep);
- }
+ if (todo & EV_LINK_TRAIN)
+ mdss_edp_do_link_train(ep);
if (todo & EV_VIDEO_READY)
mdss_edp_video_ready(ep);
+
+ if (todo & EV_IDLE_PATTERNS_SENT)
+ mdss_edp_idle_patterns_sent(ep);
}
return 0;
@@ -607,11 +859,12 @@
u32 isr1, isr2, mask1, mask2;
u32 ack;
+ spin_lock(&ep->lock);
isr1 = edp_read(base + 0x308);
isr2 = edp_read(base + 0x30c);
- mask1 = isr1 & EDP_INTR_MASK1;
- mask2 = isr2 & EDP_INTR_MASK2;
+ mask1 = isr1 & ep->mask1;
+ mask2 = isr2 & ep->mask2;
isr1 &= ~mask1; /* remove masks bit */
isr2 &= ~mask2;
@@ -628,16 +881,19 @@
ack <<= 1; /* ack bits */
ack |= mask2;
edp_write(base + 0x30c, ack);
+ spin_unlock(&ep->lock);
if (isr1 & EDP_INTR_HPD) {
isr1 &= ~EDP_INTR_HPD; /* clear */
- if (ep->train_start)
- edp_send_events(ep, EV_LINK_TRAIN);
+ edp_send_events(ep, EV_LINK_TRAIN);
}
if (isr2 & EDP_INTR_READY_FOR_VIDEO)
edp_send_events(ep, EV_VIDEO_READY);
+ if (isr2 & EDP_INTR_IDLE_PATTERNs_SENT)
+ edp_send_events(ep, EV_IDLE_PATTERNS_SENT);
+
if (isr1 && ep->aux_cmd_busy) {
/* clear EDP_AUX_TRANS_CTRL */
edp_write(base + 0x318, 0);
@@ -661,16 +917,24 @@
static void mdss_edp_irq_enable(struct mdss_edp_drv_pdata *edp_drv)
{
- edp_write(edp_drv->base + 0x308, EDP_INTR_MASK1);
- edp_write(edp_drv->base + 0x30c, EDP_INTR_MASK2);
+ unsigned long flags;
+
+ spin_lock_irqsave(&edp_drv->lock, flags);
+ edp_write(edp_drv->base + 0x308, edp_drv->mask1);
+ edp_write(edp_drv->base + 0x30c, edp_drv->mask2);
+ spin_unlock_irqrestore(&edp_drv->lock, flags);
mdss_enable_irq(&mdss_edp_hw);
}
static void mdss_edp_irq_disable(struct mdss_edp_drv_pdata *edp_drv)
{
+ unsigned long flags;
+
+ spin_lock_irqsave(&edp_drv->lock, flags);
edp_write(edp_drv->base + 0x308, 0x0);
edp_write(edp_drv->base + 0x30c, 0x0);
+ spin_unlock_irqrestore(&edp_drv->lock, flags);
mdss_disable_irq(&mdss_edp_hw);
}
@@ -679,7 +943,6 @@
{
int ret = 0;
-
edp_drv->gpio_panel_hpd = of_get_named_gpio_flags(
edp_drv->pdev->dev.of_node, "gpio-panel-hpd", 0,
&edp_drv->hpd_flags);
@@ -769,7 +1032,11 @@
edp_drv->pdev = pdev;
edp_drv->pdev->id = 1;
edp_drv->clk_on = 0;
- edp_drv->train_start = 0; /* no link train yet */
+ edp_drv->aux_rate = 19200000;
+ edp_drv->mask1 = EDP_INTR_MASK1;
+ edp_drv->mask2 = EDP_INTR_MASK2;
+ mutex_init(&edp_drv->emutex);
+ spin_lock_init(&edp_drv->lock);
ret = mdss_edp_get_base_address(edp_drv);
if (ret)
@@ -801,34 +1068,55 @@
mdss_edp_event_setup(edp_drv);
+ edp_drv->cont_splash = of_property_read_bool(pdev->dev.of_node,
+ "qcom,cont-splash-enabled");
+
+ pr_debug("%s:cont_splash=%d\n", __func__, edp_drv->cont_splash);
+
/* need mdss clock to receive irq */
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ if (!edp_drv->cont_splash)
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
/* only need aux and ahb clock for aux channel */
mdss_edp_prepare_aux_clocks(edp_drv);
mdss_edp_aux_clk_enable(edp_drv);
- mdss_edp_phy_pll_reset(edp_drv->base);
- mdss_edp_aux_reset(edp_drv->base);
- mdss_edp_mainlink_reset(edp_drv->base);
- mdss_edp_phy_powerup(edp_drv->base, 1);
- mdss_edp_aux_ctrl(edp_drv->base, 1);
+
+ if (!edp_drv->cont_splash) {
+ mdss_edp_phy_pll_reset(edp_drv);
+ mdss_edp_aux_reset(edp_drv);
+ mdss_edp_mainlink_reset(edp_drv);
+ mdss_edp_phy_power_ctrl(edp_drv, 1);
+ mdss_edp_aux_ctrl(edp_drv, 1);
+ }
mdss_edp_irq_enable(edp_drv);
mdss_edp_edid_read(edp_drv, 0);
mdss_edp_dpcd_cap_read(edp_drv);
+ mdss_edp_fill_link_cfg(edp_drv);
mdss_edp_irq_disable(edp_drv);
- mdss_edp_aux_ctrl(edp_drv->base, 0);
+ if (!edp_drv->cont_splash) {
+ mdss_edp_aux_ctrl(edp_drv, 0);
+ mdss_edp_phy_power_ctrl(edp_drv, 0);
+ }
+
mdss_edp_aux_clk_disable(edp_drv);
- mdss_edp_phy_powerup(edp_drv->base, 0);
mdss_edp_unprepare_aux_clocks(edp_drv);
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ if (!edp_drv->cont_splash)
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+ if (edp_drv->cont_splash) { /* vote for clocks */
+ mdss_edp_prepare_clocks(edp_drv);
+ mdss_edp_clk_enable(edp_drv);
+ }
mdss_edp_device_register(edp_drv);
+ pr_info("%s: done\n", __func__);
+
return 0;
diff --git a/drivers/video/msm/mdss/mdss_edp.h b/drivers/video/msm/mdss/mdss_edp.h
index 33b899f..0c0200d 100644
--- a/drivers/video/msm/mdss/mdss_edp.h
+++ b/drivers/video/msm/mdss/mdss_edp.h
@@ -57,6 +57,8 @@
#define EDP_INTR_ACK_SHIFT 1
#define EDP_INTR_MASK_SHIFT 2
+#define EDP_MAX_LANE 4
+
/* isr */
#define EDP_INTR_HPD BIT(0)
#define EDP_INTR_AUX_I2C_DONE BIT(3)
@@ -137,8 +139,27 @@
#define EV_DPCD_CAP_READ BIT(2)
#define EV_DPCD_STATUS_READ BIT(3)
#define EV_LINK_TRAIN BIT(4)
+#define EV_IDLE_PATTERNS_SENT BIT(30)
#define EV_VIDEO_READY BIT(31)
+/* edp state ctrl */
+#define ST_TRAIN_PATTERN_1 BIT(0)
+#define ST_TRAIN_PATTERN_2 BIT(1)
+#define ST_TRAIN_PATTERN_3 BIT(2)
+#define ST_SYMBOL_ERR_RATE_MEASUREMENT BIT(3)
+#define ST_PRBS7 BIT(4)
+#define ST_CUSTOM_80_BIT_PATTERN BIT(5)
+#define ST_SEND_VIDEO BIT(6)
+#define ST_PUSH_IDLE BIT(7)
+
+/* sink power state */
+#define SINK_POWER_ON 1
+#define SINK_POWER_OFF 2
+
+#define EDP_LINK_RATE_162 6 /* 1.62G = 270M * 6 */
+#define EDP_LINK_RATE_270 10 /* 2.70G = 270M * 10 */
+#define EDP_LINK_RATE_MAX EDP_LINK_RATE_270
+
struct dpcd_cap {
char major;
char minor;
@@ -238,16 +259,31 @@
int (*off) (struct mdss_panel_data *pdata);
struct platform_device *pdev;
+ struct mutex emutex;
+ int clk_cnt;
+ int cont_splash;
+
/* edp specific */
unsigned char *base;
int base_size;
unsigned char *mmss_cc_base;
+ u32 mask1;
+ u32 mask2;
struct mdss_panel_data panel_data;
+ int edp_on_cnt;
+ int edp_off_cnt;
+
+ u32 pixel_rate;
+ u32 aux_rate;
+ char link_rate; /* X 27000000 for real rate */
+ char lane_cnt;
+ char train_link_rate; /* X 27000000 for real rate */
+ char train_lane_cnt;
+
struct edp_edid edid;
struct dpcd_cap dpcd;
- int train_start;
/* regulators */
struct regulator *vdda_vreg;
@@ -275,6 +311,8 @@
/* aux */
struct completion aux_comp;
struct completion train_comp;
+ struct completion idle_comp;
+ struct completion video_comp;
struct mutex aux_mutex;
u32 aux_cmd_busy;
u32 aux_cmd_i2c;
@@ -286,8 +324,6 @@
char txbuf[256];
char rxbuf[256];
struct dpcd_link_status link_status;
- char link_rate;
- char lane_cnt;
char v_level;
char p_level;
/* transfer unit */
@@ -303,12 +339,9 @@
u32 event_gndx;
u32 event_todo_list[HPD_EVENT_MAX];
spinlock_t event_lock;
+ spinlock_t lock;
};
-void mdss_edp_phy_sw_reset(unsigned char *base);
-void mdss_edp_pll_configure(unsigned char *base, int rate);
-void mdss_edp_enable_mainlink(unsigned char *base, int enable);
-void mdss_edp_phy_powerup(unsigned char *base, int enable);
int mdss_edp_aux_clk_enable(struct mdss_edp_drv_pdata *edp_drv);
void mdss_edp_aux_clk_disable(struct mdss_edp_drv_pdata *edp_drv);
int mdss_edp_clk_enable(struct mdss_edp_drv_pdata *edp_drv);
@@ -319,29 +352,22 @@
void mdss_edp_unprepare_aux_clocks(struct mdss_edp_drv_pdata *edp_drv);
int mdss_edp_prepare_clocks(struct mdss_edp_drv_pdata *edp_drv);
void mdss_edp_unprepare_clocks(struct mdss_edp_drv_pdata *edp_drv);
-void mdss_edp_config_clk(unsigned char *base, unsigned char *mmss_cc_base);
-void mdss_edp_unconfig_clk(unsigned char *base,
- unsigned char *mmss_cc_base);
void mdss_edp_dpcd_cap_read(struct mdss_edp_drv_pdata *edp);
-void mdss_edp_dpcd_status_read(struct mdss_edp_drv_pdata *edp);
+int mdss_edp_dpcd_status_read(struct mdss_edp_drv_pdata *edp);
void mdss_edp_edid_read(struct mdss_edp_drv_pdata *edp, int block);
int mdss_edp_link_train(struct mdss_edp_drv_pdata *edp);
void edp_aux_i2c_handler(struct mdss_edp_drv_pdata *edp, u32 isr);
void edp_aux_native_handler(struct mdss_edp_drv_pdata *edp, u32 isr);
void mdss_edp_aux_init(struct mdss_edp_drv_pdata *ep);
-void mdss_edp_enable_aux(unsigned char *edp_base, int enable);
-void mdss_edp_timing_engine_ctrl(unsigned char *edp_base, int enable);
-void mdss_edp_mainlink_ctrl(unsigned char *edp_base, int enable);
-void mdss_edp_mainlink_reset(unsigned char *edp_base);
-void mdss_edp_aux_reset(unsigned char *edp_base);
-void mdss_edp_aux_ctrl(unsigned char *edp_base, int enable);
-void mdss_edp_phy_pll_reset(unsigned char *edp_base);
-int mdss_edp_phy_pll_ready(unsigned char *edp_base);
-int mdss_edp_phy_ready(unsigned char *edp_base);
-void mdss_edp_lane_power_ctrl(unsigned char *edp_base, int max_lane, int up);
-void mdss_edp_phy_vm_pe_init(unsigned char *edp_base);
-void mdss_edp_clock_synchrous(unsigned char *edp_base, int sync);
+void mdss_edp_fill_link_cfg(struct mdss_edp_drv_pdata *ep);
+void mdss_edp_sink_power_down(struct mdss_edp_drv_pdata *ep);
+void mdss_edp_state_ctrl(struct mdss_edp_drv_pdata *ep, u32 state);
+int mdss_edp_sink_power_state(struct mdss_edp_drv_pdata *ep, char state);
+void mdss_edp_lane_power_ctrl(struct mdss_edp_drv_pdata *ep, int up);
+void mdss_edp_config_ctrl(struct mdss_edp_drv_pdata *ep);
+
+void mdss_edp_clk_debug(unsigned char *edp_base, unsigned char *mmss_cc_base);
#endif /* MDSS_EDP_H */
diff --git a/drivers/video/msm/mdss/mdss_edp_aux.c b/drivers/video/msm/mdss/mdss_edp_aux.c
index 6d8e2c2..bbcee19 100644
--- a/drivers/video/msm/mdss/mdss_edp_aux.c
+++ b/drivers/video/msm/mdss/mdss_edp_aux.c
@@ -368,7 +368,6 @@
char *bp;
int i;
char csum = 0;
- int ret = 0;
bp = buf;
if (len < 128) {
@@ -389,7 +388,7 @@
return -EINVAL;
}
- return ret;
+ return 0;
}
@@ -411,7 +410,7 @@
edid->id_name[2] = 'A' + data - 1;
edid->id_name[3] = 0;
- pr_debug("%s: edid manufacturer = %s", __func__, edid->id_name);
+ pr_debug("%s: edid manufacturer = %s\n", __func__, edid->id_name);
}
void edp_extract_edid_product(struct edp_edid *edid, char *buf)
@@ -427,21 +426,21 @@
data <<= 8;
edid->id_product |= data;
- pr_debug("%s: edid product = 0x%x", __func__, edid->id_product);
+ pr_debug("%s: edid product = 0x%x\n", __func__, edid->id_product);
};
void edp_extract_edid_version(struct edp_edid *edid, char *buf)
{
edid->version = buf[0x12];
edid->revision = buf[0x13];
- pr_debug("%s: edid version = %d.%d", __func__, edid->version,
+ pr_debug("%s: edid version = %d.%d\n", __func__, edid->version,
edid->revision);
};
void edp_extract_edid_ext_block_cnt(struct edp_edid *edid, char *buf)
{
edid->ext_block_cnt = buf[0x7e];
- pr_debug("%s: edid extension = %d", __func__,
+ pr_debug("%s: edid extension = %d\n", __func__,
edid->ext_block_cnt);
};
@@ -461,7 +460,7 @@
pr_debug("%s: Digital Video intf=%d color_depth=%d\n",
__func__, edid->video_intf, edid->color_depth);
} else {
- pr_err("%s: Error, Analog video interface", __func__);
+ pr_err("%s: Error, Analog video interface\n", __func__);
}
};
@@ -485,7 +484,7 @@
}
}
- pr_debug("%s: edid dpm=%d color_format=%d", __func__,
+ pr_debug("%s: edid dpm=%d color_format=%d\n", __func__,
edid->dpm, edid->color_format);
};
@@ -567,6 +566,7 @@
dp->h_border = *bp++; /* byte 0x45 */
dp->v_border = *bp++; /* byte 0x46 */
+ /* progressive or interlaved */
dp->interlaced = *bp & 0x80; /* byte 0x47 */
dp->stereo = *bp & 0x60;
@@ -642,12 +642,13 @@
pr_debug("%s: ret=%d\n", __func__, ret);
if (ret >= 0)
break;
- pr_debug("%s: failed in write\n", __func__);
msleep(100);
}
- if (cnt == 0)
+ if (cnt <= 0) {
+ pr_err("%s: aux chan NOT ready\n", __func__);
return 0;
+ }
return 1;
}
@@ -718,14 +719,15 @@
data = *bp++; /* byte 1 */
/* 162, 270 and 540 MB, symbol rate, NOT bit rate */
- cap->max_link_rate = data * 27;
+ cap->max_link_rate = data;
if (--rlen <= 0)
return;
pr_debug("%s: link_rate=%d\n", __func__, cap->max_link_rate);
data = *bp++; /* byte 2 */
if (data & BIT(7))
- cap->flags |= DPCD_ENHANCED_FRAME;
+ cap->enhanced_frame++;
+
if (data & 0x40)
cap->flags |= DPCD_TPS3;
data &= 0x0f;
@@ -789,7 +791,9 @@
pr_debug("%s: scrambler_reset=%d\n", __func__,
cap->scrambler_reset);
- cap->enhanced_frame = data & BIT(1);
+ if (data & BIT(1))
+ cap->enhanced_frame++;
+
pr_debug("%s: enhanced_framing=%d\n", __func__,
cap->enhanced_frame);
if (--rlen <= 0)
@@ -804,7 +808,7 @@
cap->training_read_interval);
}
-static void edp_link_status_read(struct mdss_edp_drv_pdata *ep, int len)
+static int edp_link_status_read(struct mdss_edp_drv_pdata *ep, int len)
{
char *bp;
char data;
@@ -815,9 +819,9 @@
pr_debug("%s: len=%d", __func__, len);
/* skip byte 0x200 and 0x201 */
rlen = edp_aux_read_buf(ep, 0x202, len, 0);
- if (rlen <= 0) {
+ if (rlen < len) {
pr_err("%s: edp aux read failed\n", __func__);
- return;
+ return 0;
}
rp = &ep->rxp;
bp = rp->data;
@@ -825,26 +829,18 @@
data = *bp++; /* byte 0x202 */
sp->lane_01_status = data; /* lane 0, 1 */
- if (--rlen <= 0)
- return;
data = *bp++; /* byte 0x203 */
sp->lane_23_status = data; /* lane 2, 3 */
- if (--rlen <= 0)
- return;
data = *bp++; /* byte 0x204 */
sp->interlane_align_done = (data & BIT(0));
sp->downstream_port_status_changed = (data & BIT(6));
sp->link_status_updated = (data & BIT(7));
- if (--rlen <= 0)
- return;
data = *bp++; /* byte 0x205 */
sp->port_0_in_sync = (data & BIT(0));
sp->port_1_in_sync = (data & BIT(1));
- if (--rlen <= 0)
- return;
data = *bp++; /* byte 0x206 */
sp->req_voltage_swing[0] = data & 0x03;
@@ -854,8 +850,6 @@
sp->req_voltage_swing[1] = data & 0x03;
data >>= 2;
sp->req_pre_emphasis[1] = data & 0x03;
- if (--rlen <= 0)
- return;
data = *bp++; /* byte 0x207 */
sp->req_voltage_swing[2] = data & 0x03;
@@ -865,16 +859,23 @@
sp->req_voltage_swing[3] = data & 0x03;
data >>= 2;
sp->req_pre_emphasis[3] = data & 0x03;
+
+ return len;
}
static int edp_cap_lane_rate_set(struct mdss_edp_drv_pdata *ep)
{
char buf[4];
int len = 0;
+ struct dpcd_cap *cap;
+
+ cap = &ep->dpcd;
pr_debug("%s: bw=%x lane=%d\n", __func__, ep->link_rate, ep->lane_cnt);
buf[0] = ep->link_rate;
buf[1] = ep->lane_cnt;
+ if (cap->enhanced_frame)
+ buf[1] |= 0x80;
len = edp_aux_write_buf(ep, 0x100, buf, 2, 0);
return len;
@@ -901,13 +902,6 @@
return edp_aux_write_buf(ep, 0x103, buf, 4, 0);
}
-static int edp_powerstate_write(struct mdss_edp_drv_pdata *ep,
- char powerstate)
-{
- pr_debug("%s: state=%d\n", __func__, powerstate);
- return edp_aux_write_buf(ep, 0x600, &powerstate, 1, 0);
-}
-
static int edp_train_pattern_set_write(struct mdss_edp_drv_pdata *ep,
int pattern)
{
@@ -923,8 +917,6 @@
u32 mask;
u32 data;
- pr_debug("%s:\n", __func__);
-
if (ep->lane_cnt == 1) {
mask = 0x01; /* lane 0 */
data = ep->link_status.lane_01_status;
@@ -953,8 +945,10 @@
pr_debug("%s:\n", __func__);
- if (!ep->link_status.interlane_align_done) /* not align */
+ if (!ep->link_status.interlane_align_done) { /* not align */
+ pr_err("%s: interlane align failed\n", __func__);
return 0;
+ }
if (ep->lane_cnt == 1) {
mask = 0x7;
@@ -1154,8 +1148,47 @@
return ret;
}
-static int edp_link_rate_shift(struct mdss_edp_drv_pdata *ep)
+static int edp_link_rate_down_shift(struct mdss_edp_drv_pdata *ep)
{
+ u32 prate, lrate;
+ int rate, lane, max_lane;
+ int changed = 0;
+
+ rate = ep->link_rate;
+ lane = ep->lane_cnt;
+ max_lane = ep->dpcd.max_lane_count;
+
+ prate = ep->pixel_rate;
+ prate /= 1000; /* avoid using 64 biits */
+ prate *= ep->bpp;
+ prate /= 8; /* byte */
+
+ if (rate > EDP_LINK_RATE_162 && rate <= EDP_LINK_RATE_MAX) {
+ rate -= 4; /* reduce rate */
+ changed++;
+ }
+
+ if (changed) {
+ if (lane >= 1 && lane < max_lane)
+ lane <<= 1; /* increase lane */
+
+ lrate = 270000000; /* 270M */
+ lrate /= 1000; /* avoid using 64 bits */
+ lrate *= rate;
+ lrate /= 10; /* byte, 10 bits --> 8 bits */
+ lrate *= lane;
+
+ pr_debug("%s: new lrate=%u prate=%u rate=%d lane=%d p=%d b=%d\n",
+ __func__, lrate, prate, rate, lane, ep->pixel_rate, ep->bpp);
+
+ if (lrate > prate) {
+ ep->link_rate = rate;
+ ep->lane_cnt = lane;
+ pr_debug("%s: new rate=%d %d\n", __func__, rate, lane);
+ return 0;
+ }
+ }
+
/* add calculation later */
return -EINVAL;
}
@@ -1180,23 +1213,23 @@
return ret;
}
- /* start with max rate and lane */
- ep->lane_cnt = ep->dpcd.max_lane_count;
- ep->link_rate = ep->dpcd.max_link_rate;
edp_write(ep->base + EDP_MAINLINK_CTRL, 0x1);
+ mdss_edp_sink_power_state(ep, SINK_POWER_ON);
+
train_start:
ep->v_level = 0; /* start from default level */
ep->p_level = 0;
edp_cap_lane_rate_set(ep);
+ mdss_edp_config_ctrl(ep);
+ mdss_edp_lane_power_ctrl(ep, 1);
edp_clear_training_pattern(ep);
usleep(ep->dpcd.training_read_interval);
- edp_powerstate_write(ep, 1);
ret = edp_start_link_train_1(ep);
if (ret < 0) {
- if (edp_link_rate_shift(ep) == 0) {
+ if (edp_link_rate_down_shift(ep) == 0) {
goto train_start;
} else {
pr_err("%s: Training 1 failed", __func__);
@@ -1210,7 +1243,7 @@
edp_clear_training_pattern(ep);
ret = edp_start_link_train_2(ep);
if (ret < 0) {
- if (edp_link_rate_shift(ep) == 0) {
+ if (edp_link_rate_down_shift(ep) == 0) {
goto train_start;
} else {
pr_err("%s: Training 2 failed", __func__);
@@ -1221,6 +1254,7 @@
pr_debug("%s: Training 2 completed successfully", __func__);
+ mdss_edp_state_ctrl(ep, ST_SEND_VIDEO);
clear:
edp_clear_training_pattern(ep);
@@ -1233,9 +1267,33 @@
edp_sink_capability_read(ep, 16);
}
-void mdss_edp_dpcd_status_read(struct mdss_edp_drv_pdata *ep)
+int mdss_edp_dpcd_status_read(struct mdss_edp_drv_pdata *ep)
{
- edp_link_status_read(ep, 6);
+ struct dpcd_link_status *sp;
+ int ret = 0; /* not sync */
+
+ ret = edp_link_status_read(ep, 6);
+
+ if (ret) {
+ sp = &ep->link_status;
+ ret = sp->port_0_in_sync; /* 1 == sync */
+ }
+
+ return ret;
+}
+
+void mdss_edp_fill_link_cfg(struct mdss_edp_drv_pdata *ep)
+{
+ struct display_timing_desc *dp;
+
+ dp = &ep->edid.timing[0];
+ ep->pixel_rate = dp->pclk;
+ ep->lane_cnt = ep->dpcd.max_lane_count;
+ ep->link_rate = ep->dpcd.max_link_rate;
+
+ pr_debug("%s: pclk=%d rate=%d lane=%d\n", __func__,
+ ep->pixel_rate, ep->link_rate, ep->lane_cnt);
+
}
void mdss_edp_edid_read(struct mdss_edp_drv_pdata *ep, int block)
@@ -1243,6 +1301,15 @@
edp_sink_edid_read(ep, block);
}
+int mdss_edp_sink_power_state(struct mdss_edp_drv_pdata *ep, char state)
+{
+ int ret;
+
+ ret = edp_aux_write_buf(ep, 0x600, &state, 1, 0);
+ pr_debug("%s: state=%d ret=%d\n", __func__, state, ret);
+ return ret;
+}
+
int mdss_edp_link_train(struct mdss_edp_drv_pdata *ep)
{
return edp_aux_link_train(ep);
@@ -1253,7 +1320,10 @@
mutex_init(&ep->aux_mutex);
init_completion(&ep->aux_comp);
init_completion(&ep->train_comp);
+ init_completion(&ep->idle_comp);
+ init_completion(&ep->video_comp);
complete(&ep->train_comp); /* make non block at first time */
+ complete(&ep->video_comp); /* make non block at first time */
edp_buf_init(&ep->txp, ep->txbuf, sizeof(ep->txbuf));
edp_buf_init(&ep->rxp, ep->rxbuf, sizeof(ep->rxbuf));
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 105dd1a..08cdcef 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -92,14 +92,16 @@
unsigned long val, void *data);
static int __mdss_fb_display_thread(void *data);
-static void mdss_fb_pan_idle(struct msm_fb_data_type *mfd);
+static int mdss_fb_pan_idle(struct msm_fb_data_type *mfd);
static int mdss_fb_send_panel_event(struct msm_fb_data_type *mfd,
int event, void *arg);
void mdss_fb_no_update_notify_timer_cb(unsigned long data)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data;
- if (!mfd)
+ if (!mfd) {
pr_err("%s mfd NULL\n", __func__);
+ return;
+ }
mfd->no_update.value = NOTIFY_TYPE_NO_UPDATE;
complete(&mfd->no_update.comp);
}
@@ -107,9 +109,10 @@
static int mdss_fb_notify_update(struct msm_fb_data_type *mfd,
unsigned long *argp)
{
- int ret, notify, to_user;
+ int ret;
+ unsigned long notify = 0x0, to_user = 0x0;
- ret = copy_from_user(¬ify, argp, sizeof(int));
+ ret = copy_from_user(¬ify, argp, sizeof(unsigned long));
if (ret) {
pr_err("%s:ioctl failed\n", __func__);
return ret;
@@ -120,18 +123,22 @@
if (notify == NOTIFY_UPDATE_START) {
INIT_COMPLETION(mfd->update.comp);
- ret = wait_for_completion_interruptible_timeout(
+ ret = wait_for_completion_timeout(
&mfd->update.comp, 4 * HZ);
- to_user = mfd->update.value;
+ to_user = (unsigned int)mfd->update.value;
+ if (mfd->update.type == NOTIFY_TYPE_SUSPEND) {
+ to_user = (unsigned int)mfd->update.type;
+ ret = 1;
+ }
} else if (notify == NOTIFY_UPDATE_STOP) {
INIT_COMPLETION(mfd->no_update.comp);
- ret = wait_for_completion_interruptible_timeout(
+ ret = wait_for_completion_timeout(
&mfd->no_update.comp, 4 * HZ);
- to_user = mfd->no_update.value;
+ to_user = (unsigned int)mfd->no_update.value;
} else {
if (mfd->panel_power_on) {
INIT_COMPLETION(mfd->power_off_comp);
- ret = wait_for_completion_interruptible_timeout(
+ ret = wait_for_completion_timeout(
&mfd->power_off_comp, 1 * HZ);
}
}
@@ -139,7 +146,48 @@
if (ret == 0)
ret = -ETIMEDOUT;
else if (ret > 0)
- ret = copy_to_user(argp, &to_user, sizeof(int));
+ ret = copy_to_user(argp, &to_user, sizeof(unsigned long));
+ return ret;
+}
+
+static int mdss_fb_splash_thread(void *data)
+{
+ struct msm_fb_data_type *mfd = data;
+ int ret = -EINVAL;
+ struct fb_info *fbi = NULL;
+ int ov_index[2];
+
+ if (!mfd || !mfd->fbi || !mfd->mdp.splash_fnc) {
+ pr_err("Invalid input parameter\n");
+ goto end;
+ }
+
+ fbi = mfd->fbi;
+
+ ret = mdss_fb_open(fbi, current->tgid);
+ if (ret) {
+ pr_err("fb_open failed\n");
+ goto end;
+ }
+
+ mfd->bl_updated = true;
+ mdss_fb_set_backlight(mfd, mfd->panel_info->bl_max >> 1);
+
+ ret = mfd->mdp.splash_fnc(mfd, ov_index, MDP_CREATE_SPLASH_OV);
+ if (ret) {
+ pr_err("Splash image failed\n");
+ goto splash_err;
+ }
+
+ do {
+ schedule_timeout_interruptible(SPLASH_THREAD_WAIT_TIMEOUT * HZ);
+ } while (!kthread_should_stop());
+
+ mfd->mdp.splash_fnc(mfd, ov_index, MDP_REMOVE_SPLASH_OV);
+
+splash_err:
+ mdss_fb_release(fbi, current->tgid);
+end:
return ret;
}
@@ -151,13 +199,13 @@
struct msm_fb_data_type *mfd = dev_get_drvdata(led_cdev->dev->parent);
int bl_lvl;
- if (value > MDSS_MAX_BL_BRIGHTNESS)
- value = MDSS_MAX_BL_BRIGHTNESS;
+ if (value > mfd->panel_info->brightness_max)
+ value = mfd->panel_info->brightness_max;
/* This maps android backlight level 0 to 255 into
driver backlight level 0 to bl_max with rounding */
MDSS_BRIGHT_TO_BL(bl_lvl, value, mfd->panel_info->bl_max,
- MDSS_MAX_BL_BRIGHTNESS);
+ mfd->panel_info->brightness_max);
if (!bl_lvl && value)
bl_lvl = 1;
@@ -294,6 +342,7 @@
{
struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
+ mfd->shutdown_pending = true;
lock_fb_info(mfd->fbi);
mdss_fb_release_all(mfd->fbi, true);
unlock_fb_info(mfd->fbi);
@@ -370,6 +419,9 @@
/* android supports only one lcd-backlight/lcd for now */
if (!lcd_backlight_registered) {
+
+ backlight_led.brightness = mfd->panel_info->brightness_max;
+ backlight_led.max_brightness = mfd->panel_info->brightness_max;
if (led_classdev_register(&pdev->dev, &backlight_led))
pr_err("led_classdev_register failed\n");
else
@@ -399,6 +451,16 @@
else
mfd->mdp_sync_pt_data.threshold = 2;
+ if (mfd->index == 0) {
+ mfd->splash_thread = kthread_run(mdss_fb_splash_thread, mfd,
+ "mdss_fb_splash");
+ if (IS_ERR(mfd->splash_thread)) {
+ pr_err("unable to start splash thread %d\n",
+ mfd->index);
+ mfd->splash_thread = NULL;
+ }
+ }
+
return rc;
}
@@ -616,11 +678,11 @@
* scaling fraction (x/1024)
*/
temp = (temp * mfd->bl_scale) / 1024;
- }
- /*if less than minimum level, use min level*/
- else if ((temp < mfd->bl_min_lvl) && (0 != temp))
- temp = mfd->bl_min_lvl;
+ /*if less than minimum level, use min level*/
+ if (temp < mfd->bl_min_lvl)
+ temp = mfd->bl_min_lvl;
+ }
pr_debug("output = %d", temp);
(*bl_lvl) = temp;
@@ -635,11 +697,8 @@
if (((!mfd->panel_power_on && mfd->dcm_state != DCM_ENTER)
|| !mfd->bl_updated) && !IS_CALIB_MODE_BL(mfd)) {
- if (bkl_lvl < mfd->bl_min_lvl)
- mfd->unset_bl_level = mfd->bl_min_lvl;
- else
- mfd->unset_bl_level = bkl_lvl;
- return;
+ mfd->unset_bl_level = bkl_lvl;
+ return;
} else {
mfd->unset_bl_level = 0;
}
@@ -708,8 +767,10 @@
case FB_BLANK_UNBLANK:
if (!mfd->panel_power_on && mfd->mdp.on_fnc) {
ret = mfd->mdp.on_fnc(mfd);
- if (ret == 0)
+ if (ret == 0) {
mfd->panel_power_on = true;
+ mfd->panel_info->panel_dead = false;
+ }
mutex_lock(&mfd->update.lock);
mfd->update.type = NOTIFY_TYPE_UPDATE;
mutex_unlock(&mfd->update.lock);
@@ -777,13 +838,18 @@
u32 len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ int ret = 0;
if (!start) {
pr_warn("No framebuffer memory is allocated.\n");
return -ENOMEM;
}
- mdss_fb_pan_idle(mfd);
+ ret = mdss_fb_pan_idle(mfd);
+ if (ret) {
+ pr_err("Shutdown pending. Aborting operation\n");
+ return ret;
+ }
/* Set VM flags. */
start &= PAGE_MASK;
@@ -1118,8 +1184,6 @@
mfd->index, fbi->var.xres, fbi->var.yres,
fbi->fix.smem_len);
- kthread_run(__mdss_fb_display_thread, mfd, "mdss_fb%d", mfd->index);
-
return 0;
}
@@ -1130,6 +1194,11 @@
int result;
int pid = current->tgid;
+ if (mfd->shutdown_pending) {
+ pr_err("Shutdown pending. Aborting operation\n");
+ return -EPERM;
+ }
+
list_for_each_entry(pinfo, &mfd->proc_list, list) {
if (pinfo->pid == pid)
break;
@@ -1149,23 +1218,55 @@
result = pm_runtime_get_sync(info->dev);
- if (result < 0)
+ if (result < 0) {
pr_err("pm_runtime: fail to wake up\n");
+ goto pm_error;
+ }
if (!mfd->ref_cnt) {
+ mfd->disp_thread = kthread_run(__mdss_fb_display_thread, mfd,
+ "mdss_fb%d", mfd->index);
+ if (IS_ERR(mfd->disp_thread)) {
+ pr_err("unable to start display thread %d\n",
+ mfd->index);
+ result = PTR_ERR(mfd->disp_thread);
+ mfd->disp_thread = NULL;
+ goto thread_error;
+ }
+
result = mdss_fb_blank_sub(FB_BLANK_UNBLANK, info,
mfd->op_enable);
if (result) {
- pm_runtime_put(info->dev);
pr_err("can't turn on fb%d! rc=%d\n", mfd->index,
result);
- return result;
+ goto blank_error;
}
}
pinfo->ref_cnt++;
mfd->ref_cnt++;
+
+ /* Stop the splash thread once userspace open the fb node */
+ if (mfd->splash_thread && mfd->ref_cnt > 1) {
+ kthread_stop(mfd->splash_thread);
+ mfd->splash_thread = NULL;
+ }
+
return 0;
+
+blank_error:
+ kthread_stop(mfd->disp_thread);
+ mfd->disp_thread = NULL;
+
+thread_error:
+ if (pinfo && !pinfo->ref_cnt) {
+ list_del(&pinfo->list);
+ kfree(pinfo);
+ }
+ pm_runtime_put(info->dev);
+
+pm_error:
+ return result;
}
static int mdss_fb_release_all(struct fb_info *info, bool release_all)
@@ -1174,9 +1275,12 @@
struct mdss_fb_proc_info *pinfo = NULL, *temp_pinfo = NULL;
int ret = 0;
int pid = current->tgid;
+ bool unknown_pid = true, release_needed = false;
+ struct task_struct *task = current->group_leader;
if (!mfd->ref_cnt) {
- pr_info("try to close unopened fb %d!\n", mfd->index);
+ pr_info("try to close unopened fb %d! from %s\n", mfd->index,
+ task->comm);
return -EINVAL;
}
@@ -1188,12 +1292,15 @@
if (!release_all && (pinfo->pid != pid))
continue;
- pr_debug("found process entry pid=%d ref=%d\n", pinfo->pid,
- pinfo->ref_cnt);
+ unknown_pid = false;
+
+ pr_debug("found process %s pid=%d mfd->ref=%d pinfo->ref=%d\n",
+ task->comm, mfd->ref_cnt, pinfo->pid, pinfo->ref_cnt);
do {
if (mfd->ref_cnt < pinfo->ref_cnt)
- pr_warn("WARN:mfd->ref_cnt < pinfo->ref_cnt\n");
+ pr_warn("WARN:mfd->ref=%d < pinfo->ref=%d\n",
+ mfd->ref_cnt, pinfo->ref_cnt);
else
mfd->ref_cnt--;
@@ -1201,24 +1308,57 @@
pm_runtime_put(info->dev);
} while (release_all && pinfo->ref_cnt);
+ if (release_all && mfd->disp_thread) {
+ kthread_stop(mfd->disp_thread);
+ mfd->disp_thread = NULL;
+ }
+
if (pinfo->ref_cnt == 0) {
- if (mfd->mdp.release_fnc) {
- ret = mfd->mdp.release_fnc(mfd);
- if (ret)
- pr_err("error releasing fb%d pid=%d\n",
- mfd->index, pinfo->pid);
- }
list_del(&pinfo->list);
kfree(pinfo);
+ release_needed = !release_all;
+ }
+
+ if (!release_all)
+ break;
+ }
+
+ if (release_needed) {
+ pr_debug("known process %s pid=%d mfd->ref=%d\n",
+ task->comm, pid, mfd->ref_cnt);
+
+ if (mfd->mdp.release_fnc) {
+ ret = mfd->mdp.release_fnc(mfd, false);
+ if (ret)
+ pr_err("error releasing fb%d pid=%d\n",
+ mfd->index, pid);
+ }
+ } else if (unknown_pid || release_all) {
+ pr_warn("unknown process %s pid=%d mfd->ref=%d\n",
+ task->comm, pid, mfd->ref_cnt);
+
+ if (mfd->ref_cnt)
+ mfd->ref_cnt--;
+
+ if (mfd->mdp.release_fnc) {
+ ret = mfd->mdp.release_fnc(mfd, true);
+ if (ret)
+ pr_err("error fb%d release process %s pid=%d\n",
+ mfd->index, task->comm, pid);
}
}
if (!mfd->ref_cnt) {
+ if (mfd->disp_thread) {
+ kthread_stop(mfd->disp_thread);
+ mfd->disp_thread = NULL;
+ }
+
ret = mdss_fb_blank_sub(FB_BLANK_POWERDOWN, info,
mfd->op_enable);
if (ret) {
- pr_err("can't turn off fb%d! rc=%d\n",
- mfd->index, ret);
+ pr_err("can't turn off fb%d! rc=%d process %s pid=%d\n",
+ mfd->index, ret, task->comm, pid);
return ret;
}
}
@@ -1390,21 +1530,28 @@
* hardware configuration. After this function returns it is safe to perform
* software updates for next frame.
*/
-static void mdss_fb_pan_idle(struct msm_fb_data_type *mfd)
+static int mdss_fb_pan_idle(struct msm_fb_data_type *mfd)
{
- int ret;
+ int ret = 0;
ret = wait_event_timeout(mfd->idle_wait_q,
- !atomic_read(&mfd->commits_pending),
+ (!atomic_read(&mfd->commits_pending) ||
+ mfd->shutdown_pending),
msecs_to_jiffies(WAIT_DISP_OP_TIMEOUT));
if (!ret) {
pr_err("wait for idle timeout %d pending=%d\n",
ret, atomic_read(&mfd->commits_pending));
mdss_fb_signal_timeline(&mfd->mdp_sync_pt_data);
+ } else if (mfd->shutdown_pending) {
+ pr_debug("Shutdown signalled\n");
+ return -EPERM;
}
+
+ return 0;
}
+
static int mdss_fb_pan_display_ex(struct fb_info *info,
struct mdp_display_commit *disp_commit)
{
@@ -1413,7 +1560,7 @@
u32 wait_for_finish = disp_commit->wait_for_finish;
int ret = 0;
- if ((!mfd->op_enable) || (!mfd->panel_power_on))
+ if (!mfd || (!mfd->op_enable) || (!mfd->panel_power_on))
return -EPERM;
if (var->xoffset > (info->var.xres_virtual - info->var.xres))
@@ -1422,7 +1569,11 @@
if (var->yoffset > (info->var.yres_virtual - info->var.yres))
return -EINVAL;
- mdss_fb_pan_idle(mfd);
+ ret = mdss_fb_pan_idle(mfd);
+ if (ret) {
+ pr_err("Shutdown pending. Aborting operation\n");
+ return ret;
+ }
mutex_lock(&mfd->mdp_sync_pt_data.sync_mutex);
if (info->fix.xpanstep)
@@ -1478,7 +1629,7 @@
(var->yoffset / info->fix.ypanstep) * info->fix.ypanstep;
if (mfd->mdp.dma_fnc)
- mfd->mdp.dma_fnc(mfd);
+ mfd->mdp.dma_fnc(mfd, NULL, 0, NULL);
else
pr_warn("dma function not set for panel type=%d\n",
mfd->panel.type);
@@ -1554,14 +1705,20 @@
while (1) {
wait_event(mfd->commit_wait_q,
- atomic_read(&mfd->commits_pending));
+ (atomic_read(&mfd->commits_pending) ||
+ kthread_should_stop()));
+
+ if (kthread_should_stop())
+ break;
ret = __mdss_fb_perform_commit(mfd);
-
atomic_dec(&mfd->commits_pending);
wake_up_all(&mfd->idle_wait_q);
}
+ atomic_set(&mfd->commits_pending, 0);
+ wake_up_all(&mfd->idle_wait_q);
+
return ret;
}
@@ -1684,8 +1841,14 @@
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
struct fb_var_screeninfo *var = &info->var;
int old_imgType;
+ int ret = 0;
- mdss_fb_pan_idle(mfd);
+ ret = mdss_fb_pan_idle(mfd);
+ if (ret) {
+ pr_err("Shutdown pending. Aborting operation\n");
+ return ret;
+ }
+
old_imgType = mfd->fb_imgType;
switch (var->bits_per_pixel) {
case 16:
@@ -1732,16 +1895,16 @@
mfd->panel_reconfig = false;
}
- return 0;
+ return ret;
}
int mdss_fb_dcm(struct msm_fb_data_type *mfd, int req_state)
{
- int ret = -EINVAL;
+ int ret = 0;
if (req_state == mfd->dcm_state) {
- pr_warn("Already in correct DCM state");
- ret = 0;
+ pr_warn("Already in correct DCM/DTM state");
+ return ret;
}
switch (req_state) {
@@ -1757,11 +1920,12 @@
break;
case DCM_ENTER:
if (mfd->dcm_state == DCM_UNBLANK) {
- /* Keep unblank path available for only
- DCM operation */
+ /*
+ * Keep unblank path available for only
+ * DCM operation
+ */
mfd->panel_power_on = false;
mfd->dcm_state = DCM_ENTER;
- ret = 0;
}
break;
case DCM_EXIT:
@@ -1769,7 +1933,6 @@
/* Release the unblank path for exit */
mfd->panel_power_on = true;
mfd->dcm_state = DCM_EXIT;
- ret = 0;
}
break;
case DCM_BLANK:
@@ -1783,7 +1946,16 @@
}
}
break;
+ case DTM_ENTER:
+ if (mfd->dcm_state == DCM_UNINIT)
+ mfd->dcm_state = DTM_ENTER;
+ break;
+ case DTM_EXIT:
+ if (mfd->dcm_state == DTM_ENTER)
+ mfd->dcm_state = DCM_UNINIT;
+ break;
}
+
return ret;
}
@@ -1972,8 +2144,16 @@
return -EINVAL;
mfd = (struct msm_fb_data_type *)info->par;
mdss_fb_power_setting_idle(mfd);
- if ((cmd != MSMFB_VSYNC_CTRL) && (cmd != MSMFB_OVERLAY_VSYNC_CTRL))
- mdss_fb_pan_idle(mfd);
+ if ((cmd != MSMFB_VSYNC_CTRL) && (cmd != MSMFB_OVERLAY_VSYNC_CTRL) &&
+ (cmd != MSMFB_ASYNC_BLIT) && (cmd != MSMFB_BLIT) &&
+ (cmd != MSMFB_NOTIFY_UPDATE)) {
+ ret = mdss_fb_pan_idle(mfd);
+ if (ret) {
+ pr_debug("Shutdown pending. Aborting operation %x\n",
+ cmd);
+ return ret;
+ }
+ }
switch (cmd) {
case MSMFB_CURSOR:
@@ -2080,6 +2260,7 @@
struct platform_device *fb_pdev, *mdss_pdev;
struct device_node *node;
int rc = 0;
+ bool master_panel = true;
if (!pdev || !pdev->dev.of_node) {
pr_err("Invalid device node\n");
@@ -2107,6 +2288,8 @@
fb_pdev = of_find_device_by_node(node);
if (fb_pdev) {
rc = mdss_fb_register_extra_panel(fb_pdev, pdata);
+ if (rc == 0)
+ master_panel = false;
} else {
pr_info("adding framebuffer device %s\n", dev_name(&pdev->dev));
fb_pdev = of_platform_device_create(node, NULL,
@@ -2114,7 +2297,7 @@
fb_pdev->dev.platform_data = pdata;
}
- if (mdp_instance->panel_register_done)
+ if (master_panel && mdp_instance->panel_register_done)
mdp_instance->panel_register_done(pdata);
mdss_notfound:
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index 8213dbe..e796fc6 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -33,6 +33,8 @@
#define WAIT_DISP_OP_TIMEOUT ((WAIT_FENCE_FIRST_TIMEOUT + \
WAIT_FENCE_FINAL_TIMEOUT) * MDP_MAX_FENCE_FD)
+#define SPLASH_THREAD_WAIT_TIMEOUT 3
+
#ifndef MAX
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#endif
@@ -67,6 +69,11 @@
MDP_NOTIFY_FRAME_TIMEOUT,
};
+enum mdp_splash_event {
+ MDP_CREATE_SPLASH_OV = 0,
+ MDP_REMOVE_SPLASH_OV,
+};
+
struct disp_info_type_suspend {
int op_enable;
int panel_power_on;
@@ -106,11 +113,12 @@
int (*on_fnc)(struct msm_fb_data_type *mfd);
int (*off_fnc)(struct msm_fb_data_type *mfd);
/* called to release resources associated to the process */
- int (*release_fnc)(struct msm_fb_data_type *mfd);
+ int (*release_fnc)(struct msm_fb_data_type *mfd, bool release_all);
int (*kickoff_fnc)(struct msm_fb_data_type *mfd,
struct mdp_display_commit *data);
int (*ioctl_handler)(struct msm_fb_data_type *mfd, u32 cmd, void *arg);
- void (*dma_fnc)(struct msm_fb_data_type *mfd);
+ void (*dma_fnc)(struct msm_fb_data_type *mfd, struct mdp_overlay *req,
+ int image_len, int *pipe_ndx);
int (*cursor_update)(struct msm_fb_data_type *mfd,
struct fb_cursor *cursor);
int (*lut_update)(struct msm_fb_data_type *mfd, struct fb_cmap *cmap);
@@ -119,6 +127,7 @@
int (*update_ad_input)(struct msm_fb_data_type *mfd);
int (*panel_register_done)(struct mdss_panel_data *pdata);
u32 (*fb_stride)(u32 fb_index, u32 xres, int bpp);
+ int (*splash_fnc) (struct msm_fb_data_type *mfd, int *index, int req);
struct msm_sync_pt_data *(*get_sync_fnc)(struct msm_fb_data_type *mfd,
const struct mdp_buf_sync *buf_sync);
void *private1;
@@ -195,9 +204,13 @@
struct msm_sync_pt_data mdp_sync_pt_data;
/* for non-blocking */
+ struct task_struct *disp_thread;
atomic_t commits_pending;
wait_queue_head_t commit_wait_q;
wait_queue_head_t idle_wait_q;
+ bool shutdown_pending;
+
+ struct task_struct *splash_thread;
struct msm_fb_backup_type msm_fb_backup;
struct completion power_set_comp;
diff --git a/drivers/video/msm/mdss/mdss_hdmi_cec.c b/drivers/video/msm/mdss/mdss_hdmi_cec.c
index 410f2b3..9d85070 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_cec.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_cec.c
@@ -366,7 +366,7 @@
DSS_REG_W(io, HDMI_CEC_CTRL, BIT(0) | BIT(1) |
((msg->frame_size & 0x1F) << 4) | BIT(9));
- if (!wait_for_completion_interruptible_timeout(
+ if (!wait_for_completion_timeout(
&cec_ctrl->cec_msg_wr_done, HZ)) {
DEV_ERR("%s: timedout", __func__);
hdmi_cec_dump_msg(cec_ctrl, msg);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_edid.c b/drivers/video/msm/mdss/mdss_hdmi_edid.c
index cf0c287..a45876b 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_edid.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_edid.c
@@ -16,6 +16,13 @@
#include "mdss_hdmi_edid.h"
#define DBC_START_OFFSET 4
+
+/*
+ * As per CEA-861-E specification 7.5.2, there can be
+ * upto 31 bytes following any tag (data block type).
+ */
+#define MAX_DATA_BLOCK_SIZE 31
+
#define HDMI_VSDB_3D_EVF_DATA_OFFSET(vsd) \
(!((vsd)[8] & BIT(7)) ? 9 : (!((vsd)[8] & BIT(6)) ? 11 : 13))
@@ -32,6 +39,17 @@
/* Support for first 5 EDID blocks */
#define MAX_EDID_BLOCK_SIZE (0x80 * 5)
+enum data_block_types {
+ RESERVED,
+ AUDIO_DATA_BLOCK,
+ VIDEO_DATA_BLOCK,
+ VENDOR_SPECIFIC_DATA_BLOCK,
+ SPEAKER_ALLOCATION_DATA_BLOCK,
+ VESA_DTC_DATA_BLOCK,
+ RESERVED2,
+ USE_EXTENDED_TAG
+};
+
struct hdmi_edid_sink_data {
u32 disp_mode_list[HDMI_VFRMT_MAX];
u32 disp_3d_mode_list[HDMI_VFRMT_MAX];
@@ -524,7 +542,8 @@
}
/* A Tage code of 7 identifies extended data blocks */
- etag = hdmi_edid_find_block(in_buf, start_offset, 7, &len);
+ etag = hdmi_edid_find_block(in_buf, start_offset, USE_EXTENDED_TAG,
+ &len);
while (etag != NULL) {
/* The extended data block should at least be 2 bytes long */
@@ -570,7 +589,8 @@
/* There could be more that one extended data block */
start_offset = etag - in_buf + len + 1;
- etag = hdmi_edid_find_block(in_buf, start_offset, 7, &len);
+ etag = hdmi_edid_find_block(in_buf, start_offset,
+ USE_EXTENDED_TAG, &len);
}
} /* hdmi_edid_extract_extended_data_blocks */
@@ -585,11 +605,12 @@
return;
}
- vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 3, &len);
+ vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET,
+ VENDOR_SPECIFIC_DATA_BLOCK, &len);
edid_ctrl->present_3d = 0;
- if (vsd == NULL || len < 9) {
- DEV_DBG("%s: blk-id 3 not found or not long enough\n",
+ if (vsd == NULL || len == 0 || len > MAX_DATA_BLOCK_SIZE) {
+ DEV_DBG("%s: No/Invalid vendor Specific Data Block\n",
__func__);
return;
}
@@ -616,9 +637,13 @@
return;
}
- adb = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 1, &len);
- if ((adb == NULL) || (len > MAX_AUDIO_DATA_BLOCK_SIZE))
+ adb = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, AUDIO_DATA_BLOCK,
+ &len);
+ if ((adb == NULL) || (len > MAX_AUDIO_DATA_BLOCK_SIZE)) {
+ DEV_DBG("%s: No/Invalid Audio Data Block\n",
+ __func__);
return;
+ }
memcpy(edid_ctrl->audio_data_block, adb + 1, len);
edid_ctrl->adb_size = len;
@@ -644,9 +669,13 @@
return;
}
- sadb = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 4, &len);
- if ((sadb == NULL) || (len != MAX_SPKR_ALLOC_DATA_BLOCK_SIZE))
+ sadb = hdmi_edid_find_block(in_buf, DBC_START_OFFSET,
+ SPEAKER_ALLOCATION_DATA_BLOCK, &len);
+ if ((sadb == NULL) || (len != MAX_SPKR_ALLOC_DATA_BLOCK_SIZE)) {
+ DEV_DBG("%s: No/Invalid Speaker Allocation Data Block\n",
+ __func__);
return;
+ }
memcpy(edid_ctrl->spkr_alloc_data_block, sadb + 1, len);
edid_ctrl->sadb_size = len;
@@ -673,9 +702,11 @@
return;
}
- vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 3, &len);
+ vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET,
+ VENDOR_SPECIFIC_DATA_BLOCK, &len);
- if (vsd == NULL || len < 12 || !(vsd[8] & BIT(7))) {
+ if (vsd == NULL || len == 0 || len > MAX_DATA_BLOCK_SIZE ||
+ !(vsd[8] & BIT(7))) {
edid_ctrl->video_latency = (u16)-1;
edid_ctrl->audio_latency = (u16)-1;
DEV_DBG("%s: EDID: No audio/video latency present\n", __func__);
@@ -699,9 +730,14 @@
return 0;
}
- vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 3, &len);
- if (vsd == NULL || len < 8)
+ vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET,
+ VENDOR_SPECIFIC_DATA_BLOCK, &len);
+
+ if (vsd == NULL || len == 0 || len > MAX_DATA_BLOCK_SIZE) {
+ DEV_DBG("%s: No/Invalid Vendor Specific Data Block\n",
+ __func__);
return 0;
+ }
DEV_DBG("%s: EDID: VSD PhyAddr=%04x, MaxTMDS=%dMHz\n", __func__,
((u32)vsd[4] << 8) + (u32)vsd[5], (u32)vsd[7] * 5);
@@ -898,11 +934,14 @@
u16 structure_all, structure_mask;
const u8 *vsd = num_of_cea_blocks ?
hdmi_edid_find_block(data_buf+0x80, DBC_START_OFFSET,
- 3, &len) : NULL;
+ VENDOR_SPECIFIC_DATA_BLOCK, &len) : NULL;
int i;
- if (!vsd)
+ if (vsd == NULL || len == 0 || len > MAX_DATA_BLOCK_SIZE) {
+ DEV_DBG("%s: No/Invalid Vendor Specific Data Block\n",
+ __func__);
return -ENXIO;
+ }
offset = HDMI_VSDB_3D_EVF_DATA_OFFSET(vsd);
if (offset >= len - 1)
@@ -1044,10 +1083,11 @@
return;
}
- vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 3, &db_len);
+ vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET,
+ VENDOR_SPECIFIC_DATA_BLOCK, &db_len);
- if (vsd == NULL || db_len < 9) {
- DEV_DBG("%s: blk-id 3 not found or not long enough\n",
+ if (vsd == NULL || db_len == 0 || db_len > MAX_DATA_BLOCK_SIZE) {
+ DEV_DBG("%s: No/Invalid Vendor Specific Data Block\n",
__func__);
return;
}
@@ -1097,8 +1137,14 @@
edid_blk0 = &data_buf[0x0];
edid_blk1 = &data_buf[0x80];
svd = num_of_cea_blocks ?
- hdmi_edid_find_block(data_buf+0x80, DBC_START_OFFSET, 2,
- &len) : NULL;
+ hdmi_edid_find_block(data_buf+0x80, DBC_START_OFFSET,
+ VIDEO_DATA_BLOCK, &len) : NULL;
+
+ if (svd == NULL || len == 0 || len > MAX_DATA_BLOCK_SIZE) {
+ DEV_DBG("%s: No/Invalid Video Data Block\n",
+ __func__);
+ return;
+ }
sink_data = &edid_ctrl->sink_data;
diff --git a/drivers/video/msm/mdss/mdss_hdmi_hdcp.c b/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
index 80b27ed..e56e9fa 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
@@ -31,6 +31,8 @@
#define HDCP_KEYS_STATE_PROD_AKSV 6
#define HDCP_KEYS_STATE_RESERVED 7
+#define HDCP_INT_CLR (BIT(1) | BIT(5) | BIT(7) | BIT(9) | BIT(13))
+
struct hdmi_hdcp_ctrl {
u32 auth_retries;
u32 tp_msgid;
@@ -289,6 +291,10 @@
}
DEV_DBG("%s: %s: BCAPS=%02x\n", __func__, HDCP_STATE_NAME, bcaps);
+ /* receiver (0), repeater (1) */
+ hdcp_ctrl->current_tp.ds_type =
+ (bcaps & BIT(6)) >> 6 ? DS_REPEATER : DS_RECEIVER;
+
/*
* HDCP setup prior to enabling HDCP_CTRL.
* Setup seed values for random number An.
@@ -514,7 +520,7 @@
/* Write R0' to HDCP registers and check to see if it is a match */
INIT_COMPLETION(hdcp_ctrl->r0_checked);
DSS_REG_W(io, HDMI_HDCP_RCVPORT_DATA2_0, (((u32)buf[1]) << 8) | buf[0]);
- timeout_count = wait_for_completion_interruptible_timeout(
+ timeout_count = wait_for_completion_timeout(
&hdcp_ctrl->r0_checked, HZ*2);
link0_status = DSS_REG_R(io, HDMI_HDCP_LINK0_STATUS);
is_match = link0_status & BIT(12);
@@ -644,40 +650,12 @@
memset(ksv_fifo, 0,
sizeof(hdcp_ctrl->current_tp.ksv_list));
- /* Read BCAPS at offset 0x40 */
- memset(&ddc_data, 0, sizeof(ddc_data));
- ddc_data.dev_addr = 0x74;
- ddc_data.offset = 0x40;
- ddc_data.data_buf = &bcaps;
- ddc_data.data_len = 1;
- ddc_data.request_len = 1;
- ddc_data.retry = 5;
- ddc_data.what = "Bcaps";
- ddc_data.no_align = false;
- rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl, &ddc_data);
- if (rc) {
- DEV_ERR("%s: %s: BCAPS read failed\n", __func__,
- HDCP_STATE_NAME);
- goto error;
- }
- DEV_DBG("%s: %s: BCAPS=%02x (%s)\n", __func__, HDCP_STATE_NAME, bcaps,
- (bcaps & BIT(6)) ? "repeater" : "no repeater");
-
- /* receiver (0), repeater (1) */
- hdcp_ctrl->current_tp.ds_type =
- (bcaps & BIT(6)) >> 6 ? DS_REPEATER : DS_RECEIVER;
-
- /* if REPEATER (Bit 6), perform Part2 Authentication */
- if (!(bcaps & BIT(6))) {
- DEV_INFO("%s: %s: auth part II skipped, no repeater\n",
- __func__, HDCP_STATE_NAME);
- return 0;
- }
-
- /* Wait until READY bit is set in BCAPS */
+ /*
+ * Wait until READY bit is set in BCAPS, as per HDCP specifications
+ * maximum permitted time to check for READY bit is five seconds.
+ */
timeout_count = 50;
- while (!(bcaps & BIT(5)) && timeout_count) {
- msleep(100);
+ do {
timeout_count--;
/* Read BCAPS at offset 0x40 */
memset(&ddc_data, 0, sizeof(ddc_data));
@@ -695,7 +673,8 @@
HDCP_STATE_NAME);
goto error;
}
- }
+ msleep(100);
+ } while (!(bcaps & BIT(5)) && timeout_count);
/* Read BSTATUS at offset 0x41 */
memset(&ddc_data, 0, sizeof(ddc_data));
@@ -976,11 +955,15 @@
goto error;
}
- rc = hdmi_hdcp_authentication_part2(hdcp_ctrl);
- if (rc) {
- DEV_DBG("%s: %s: HDCP Auth Part II failed\n", __func__,
- HDCP_STATE_NAME);
- goto error;
+ if (hdcp_ctrl->current_tp.ds_type == DS_REPEATER) {
+ rc = hdmi_hdcp_authentication_part2(hdcp_ctrl);
+ if (rc) {
+ DEV_DBG("%s: %s: HDCP Auth Part II failed\n", __func__,
+ HDCP_STATE_NAME);
+ goto error;
+ }
+ } else {
+ DEV_INFO("%s: Downstream device is not a repeater\n", __func__);
}
/* Disabling software DDC before going into part3 to make sure
* there is no Arbitration between software and hardware for DDC */
@@ -1158,16 +1141,15 @@
}
/*
- * Need to set the state to inactive here so that any ongoing
- * reauth works will know that the HDCP session has been turned off
+ * Disable HDCP interrupts.
+ * Also, need to set the state to inactive here so that any ongoing
+ * reauth works will know that the HDCP session has been turned off.
*/
mutex_lock(hdcp_ctrl->init_data.mutex);
+ DSS_REG_W(io, HDMI_HDCP_INT_CTRL, 0);
hdcp_ctrl->hdcp_state = HDCP_STATE_INACTIVE;
mutex_unlock(hdcp_ctrl->init_data.mutex);
- /* Disable HDCP interrupts */
- DSS_REG_W(io, HDMI_HDCP_INT_CTRL, 0);
-
/*
* Cancel any pending auth/reauth attempts.
* If one is ongoing, this will wait for it to finish.
@@ -1212,7 +1194,7 @@
if (HDCP_STATE_INACTIVE == hdcp_ctrl->hdcp_state) {
DEV_ERR("%s: HDCP inactive. Just clear int and return.\n",
__func__);
- DSS_REG_W(io, HDMI_HDCP_INT_CTRL, hdcp_int_val);
+ DSS_REG_W(io, HDMI_HDCP_INT_CTRL, HDCP_INT_CLR);
return 0;
}
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index 0cd0543..a29fb751 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -63,10 +63,31 @@
/* Supported HDMI Audio channels */
#define MSM_HDMI_AUDIO_CHANNEL_2 2
+#define MSM_HDMI_AUDIO_CHANNEL_3 3
#define MSM_HDMI_AUDIO_CHANNEL_4 4
+#define MSM_HDMI_AUDIO_CHANNEL_5 5
#define MSM_HDMI_AUDIO_CHANNEL_6 6
+#define MSM_HDMI_AUDIO_CHANNEL_7 7
#define MSM_HDMI_AUDIO_CHANNEL_8 8
+#define NUM_MODES_AVI 20
+
+/* AVI Infoframe data byte 3, bit 7 (msb) represents ITC bit */
+#define SET_ITC_BIT(byte) (byte = (byte | BIT(7)))
+#define CLR_ITC_BIT(byte) (byte = (byte & ~BIT(7)))
+
+/*
+ * CN represents IT content type, if ITC bit in infoframe data byte 3
+ * is set, CN bits will represent content type as below:
+ * 0b00 Graphics
+ * 0b01 Photo
+ * 0b10 Cinema
+ * 0b11 Game
+*/
+#define CONFIG_CN_BITS(bits, byte) \
+ (byte = (byte & ~(BIT(4) | BIT(5))) |\
+ ((bits & (BIT(0) | BIT(1))) << 4))
+
enum msm_hdmi_supported_audio_sample_rates {
AUDIO_SAMPLE_RATE_32KHZ,
AUDIO_SAMPLE_RATE_44_1KHZ,
@@ -134,12 +155,6 @@
}
} /* hdmi_pm_name */
-static DEFINE_MUTEX(avi_iframe_lut_lock);
-#define NUM_MODES_AVI 20
-#define SET_ITC_BIT(byte) (byte | 0x80)
-#define CLR_ITC_BIT(byte) (byte & 0x7F)
-#define CONFIG_CN_BITS(bits, byte) ((byte & ~(0x03 << 4)) | (bits << 4))
-
static u8 hdmi_tx_avi_iframe_lut[][NUM_MODES_AVI] = {
{0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
@@ -207,55 +222,6 @@
{20480, 247500} } },
};
-/* To statically config ITC bit from sysfs attribute */
-static int hdmi_tx_config_itc_bit(int itc)
-{
- int ret = 0, loop = NUM_MODES_AVI;
-
- if (mutex_lock_interruptible(&avi_iframe_lut_lock)) {
- ret = -ERESTARTSYS;
- goto signal_intr;
- }
-
- do {
- --loop;
- if (itc == 0)
- hdmi_tx_avi_iframe_lut[2][loop] =
- CLR_ITC_BIT(hdmi_tx_avi_iframe_lut[2][loop]);
- if (itc == 1)
- hdmi_tx_avi_iframe_lut[2][loop] =
- SET_ITC_BIT(hdmi_tx_avi_iframe_lut[2][loop]);
- } while (loop);
-
- mutex_unlock(&avi_iframe_lut_lock);
-
-signal_intr:
- return ret;
-}
-
-/* To configure CN0_1 bits from sysfs attribute */
-static int hdmi_tx_config_cn_bits(int cns)
-{
- int ret = 0, loop = NUM_MODES_AVI;
-
- if (mutex_lock_interruptible(&avi_iframe_lut_lock)) {
- ret = -ERESTARTSYS;
- goto signal_intr;
- }
-
- do {
- --loop;
- hdmi_tx_avi_iframe_lut[4][loop] =
- CONFIG_CN_BITS(cns, hdmi_tx_avi_iframe_lut[4][loop]);
- } while (loop);
-
- mutex_unlock(&avi_iframe_lut_lock);
-
-signal_intr:
- return ret;
-}
-
-
static bool hdmi_tx_is_cea_format(int mode)
{
bool cea_fmt;
@@ -679,53 +645,80 @@
struct device_attribute *attr, const char *buf, size_t count)
{
ssize_t ret = strnlen(buf, PAGE_SIZE);
- int err = 0;
- int itc = 0, rc = 0;
+ u8 *avi_byte3 = hdmi_tx_avi_iframe_lut[2];
+ struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+ int loop = 0, itc = 0, rc = 0;
+
+ hdmi_ctrl = hdmi_tx_get_drvdata_from_sysfs_dev(dev);
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
rc = kstrtoint(buf, 10, &itc);
if (rc) {
- DEV_ERR("%s: kstrtoint failed. rc=%d\n", __func__, rc);
+ DEV_ERR("%s: kstrtoint failed. rc =%d\n", __func__, rc);
return rc;
}
- if (itc == 0 || itc == 1) {
- if (hdmi_tx_config_itc_bit(itc))
- ret = err;
- else
- DEV_DBG("%s: '%d is configured'!\n", __func__, itc);
- } else {
- DEV_ERR("%s: unknown ITC '%d', should be either 0 or 1\n",
- __func__, itc);
+ if (itc < 0 || itc > 1) {
+ DEV_ERR("%s: Invalid ITC %d\n", __func__, itc);
+ return ret;
}
+ if (mutex_lock_interruptible(&hdmi_ctrl->lut_lock))
+ return -ERESTARTSYS;
+
+ for (loop = 0; loop < NUM_MODES_AVI; loop++) {
+ if (itc)
+ SET_ITC_BIT(avi_byte3[loop]);
+ else
+ CLR_ITC_BIT(avi_byte3[loop]);
+ }
+
+ mutex_unlock(&hdmi_ctrl->lut_lock);
+
return ret;
} /* hdmi_tx_sysfs_wta_avi_itc */
-static ssize_t hdmi_tx_sysfs_wta_avi_cn0_1(struct device *dev,
+static ssize_t hdmi_tx_sysfs_wta_avi_cn_bits(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
ssize_t ret = strnlen(buf, PAGE_SIZE);
- int err = 0;
- int cns = 0, rc = 0;
+ u8 *avi_byte5 = hdmi_tx_avi_iframe_lut[4];
+ struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+ int loop = 0, cn_bits = 0, rc = 0;
- rc = kstrtoint(buf, 10, &cns);
+ hdmi_ctrl = hdmi_tx_get_drvdata_from_sysfs_dev(dev);
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ rc = kstrtoint(buf, 10, &cn_bits);
if (rc) {
DEV_ERR("%s: kstrtoint failed. rc=%d\n", __func__, rc);
return rc;
}
- if (cns == 0 || cns == 1 || cns == 2 || cns == 3) {
- if (hdmi_tx_config_cn_bits(cns))
- ret = err;
- else
- DEV_DBG("%s: '%d is configured'!\n", __func__, cns);
- } else {
- DEV_ERR("%s: unknown CN '%d' should be either 0 or 1, 2 ,3\n",
- __func__, cns);
+ /* As per CEA-861-E, CN is a positive number and can be max 3 */
+ if (cn_bits < 0 || cn_bits > 3) {
+ DEV_ERR("%s: Invalid CN %d\n", __func__, cn_bits);
+ return ret;
}
+ if (mutex_lock_interruptible(&hdmi_ctrl->lut_lock))
+ return -ERESTARTSYS;
+
+ for (loop = 0; loop < NUM_MODES_AVI; loop++)
+ CONFIG_CN_BITS(cn_bits, avi_byte5[loop]);
+
+ mutex_unlock(&hdmi_ctrl->lut_lock);
+
return ret;
-} /* hdmi_tx_sysfs_wta_avi_cn0_1 */
+} /* hdmi_tx_sysfs_wta_cn_bits */
static DEVICE_ATTR(connected, S_IRUGO, hdmi_tx_sysfs_rda_connected, NULL);
static DEVICE_ATTR(hpd, S_IRUGO | S_IWUSR, hdmi_tx_sysfs_rda_hpd,
@@ -736,7 +729,7 @@
hdmi_tx_sysfs_rda_product_description,
hdmi_tx_sysfs_wta_product_description);
static DEVICE_ATTR(avi_itc, S_IWUSR, NULL, hdmi_tx_sysfs_wta_avi_itc);
-static DEVICE_ATTR(avi_cn0_1, S_IWUSR, NULL, hdmi_tx_sysfs_wta_avi_cn0_1);
+static DEVICE_ATTR(avi_cn0_1, S_IWUSR, NULL, hdmi_tx_sysfs_wta_avi_cn_bits);
static struct attribute *hdmi_tx_fs_attrs[] = {
&dev_attr_connected.attr,
@@ -1718,8 +1711,6 @@
} else {
msm_dss_enable_clk(power_data->clk_config,
power_data->num_clk, 0);
- msm_dss_clk_set_rate(power_data->clk_config,
- power_data->num_clk);
msm_dss_enable_gpio(power_data->gpio_config,
power_data->num_gpio, 0);
msm_dss_enable_vreg(power_data->vreg_config,
@@ -2051,12 +2042,15 @@
switch (num_of_channels) {
case MSM_HDMI_AUDIO_CHANNEL_2:
break;
+ case MSM_HDMI_AUDIO_CHANNEL_3:
case MSM_HDMI_AUDIO_CHANNEL_4:
channel_count = 3;
break;
+ case MSM_HDMI_AUDIO_CHANNEL_5:
case MSM_HDMI_AUDIO_CHANNEL_6:
channel_count = 5;
break;
+ case MSM_HDMI_AUDIO_CHANNEL_7:
case MSM_HDMI_AUDIO_CHANNEL_8:
channel_count = 7;
break;
@@ -2473,12 +2467,6 @@
hdmi_tx_powerdown_phy(hdmi_ctrl);
- /*
- * this is needed to avoid pll lock failure due to
- * clk framework's rate caching.
- */
- hdmi_ctrl->pdata.power_data[HDMI_TX_CORE_PM].clk_config[0].rate = 0;
-
hdmi_cec_deconfig(hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC]);
hdmi_tx_core_off(hdmi_ctrl);
@@ -2493,6 +2481,10 @@
mutex_unlock(&hdmi_ctrl->mutex);
DEV_INFO("%s: HDMI Core: OFF\n", __func__);
+
+ if (hdmi_ctrl->hdmi_tx_hpd_done)
+ hdmi_ctrl->hdmi_tx_hpd_done(
+ hdmi_ctrl->downstream_data);
} /* hdmi_tx_power_off_work */
static int hdmi_tx_power_off(struct mdss_panel_data *panel_data)
@@ -2544,7 +2536,7 @@
flush_work_sync(&hdmi_ctrl->power_off_work);
if (hdmi_ctrl->pdata.primary) {
- timeout = wait_for_completion_interruptible_timeout(
+ timeout = wait_for_completion_timeout(
&hdmi_ctrl->hpd_done, HZ);
if (!timeout) {
DEV_ERR("%s: cable connection hasn't happened yet\n",
@@ -2595,6 +2587,9 @@
hdmi_tx_hpd_polarity_setup(hdmi_ctrl, HPD_DISCONNECT_POLARITY);
+ if (hdmi_ctrl->hdmi_tx_hpd_done)
+ hdmi_ctrl->hdmi_tx_hpd_done(hdmi_ctrl->downstream_data);
+
return 0;
} /* hdmi_tx_power_on */
@@ -2839,6 +2834,7 @@
switch_dev_unregister(&hdmi_ctrl->sdev);
if (hdmi_ctrl->workq)
destroy_workqueue(hdmi_ctrl->workq);
+ mutex_destroy(&hdmi_ctrl->lut_lock);
mutex_destroy(&hdmi_ctrl->mutex);
hdmi_tx_hw.ptr = NULL;
@@ -2867,6 +2863,7 @@
hdmi_setup_video_mode_lut();
mutex_init(&hdmi_ctrl->mutex);
+ mutex_init(&hdmi_ctrl->lut_lock);
hdmi_ctrl->workq = create_workqueue("hdmi_tx_workq");
if (!hdmi_ctrl->workq) {
DEV_ERR("%s: hdmi_tx_workq creation failed.\n", __func__);
@@ -2915,6 +2912,7 @@
fail_create_workq:
if (hdmi_ctrl->workq)
destroy_workqueue(hdmi_ctrl->workq);
+ mutex_destroy(&hdmi_ctrl->lut_lock);
mutex_destroy(&hdmi_ctrl->mutex);
fail_no_hdmi:
return rc;
@@ -3005,7 +3003,7 @@
u32 timeout;
hdmi_ctrl->panel_suspend = false;
- timeout = wait_for_completion_interruptible_timeout(
+ timeout = wait_for_completion_timeout(
&hdmi_ctrl->hpd_done, HZ/10);
if (!timeout & !hdmi_ctrl->hpd_state) {
DEV_INFO("%s: cable removed during suspend\n",
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.h b/drivers/video/msm/mdss/mdss_hdmi_tx.h
index 5f2a23e..0787dee 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.h
@@ -54,6 +54,7 @@
struct hdmi_audio audio_data;
struct mutex mutex;
+ struct mutex lut_lock;
struct kobject *kobj;
struct switch_dev sdev;
struct switch_dev audio_sdev;
@@ -86,6 +87,9 @@
struct hdmi_tx_ddc_ctrl ddc_ctrl;
+ void (*hdmi_tx_hpd_done) (void *data);
+ void *downstream_data;
+
void *feature_data[HDMI_TX_FEAT_MAX];
};
diff --git a/drivers/video/msm/mdss/mdss_hdmi_util.c b/drivers/video/msm/mdss/mdss_hdmi_util.c
index 711ec68..de422a4 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_util.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_util.c
@@ -296,7 +296,7 @@
INIT_COMPLETION(ddc_ctrl->ddc_sw_done);
DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_CTRL, BIT(0) | BIT(20));
- time_out_count = wait_for_completion_interruptible_timeout(
+ time_out_count = wait_for_completion_timeout(
&ddc_ctrl->ddc_sw_done, HZ/2);
DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_INT_CTRL, BIT(1));
if (!time_out_count) {
@@ -547,7 +547,7 @@
INIT_COMPLETION(ddc_ctrl->ddc_sw_done);
DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_CTRL, BIT(0) | BIT(21));
- time_out_count = wait_for_completion_interruptible_timeout(
+ time_out_count = wait_for_completion_timeout(
&ddc_ctrl->ddc_sw_done, HZ/2);
reg_val = DSS_REG_R(ddc_ctrl->io, HDMI_DDC_INT_CTRL);
@@ -721,7 +721,7 @@
INIT_COMPLETION(ddc_ctrl->ddc_sw_done);
DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_CTRL, BIT(0) | BIT(20));
- time_out_count = wait_for_completion_interruptible_timeout(
+ time_out_count = wait_for_completion_timeout(
&ddc_ctrl->ddc_sw_done, HZ/2);
reg_val = DSS_REG_R(ddc_ctrl->io, HDMI_DDC_INT_CTRL);
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index bac01fc..131744c 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -546,6 +546,8 @@
if (clk) {
pr_debug("clk=%d en=%d\n", clk_idx, enable);
if (enable) {
+ if (clk_idx == MDSS_CLK_MDP_VSYNC)
+ clk_set_rate(clk, 19200000);
ret = clk_prepare_enable(clk);
} else {
clk_disable_unprepare(clk);
@@ -646,6 +648,7 @@
if (!enable) {
msm_bus_scale_client_update_request(
mdata->bus_hdl, 0);
+ mdss_iommu_dettach(mdata);
pm_runtime_put(&mdata->pdev->dev);
} else {
pm_runtime_get_sync(&mdata->pdev->dev);
@@ -994,6 +997,9 @@
/* swap */
writel_relaxed(1, offset + 16);
}
+
+ mdata->nmax_concurrent_ad_hw = (mdata->mdp_rev <= MDSS_MDP_HW_REV_102) ?
+ 1 : 2;
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
pr_debug("MDP hw init done\n");
@@ -1018,6 +1024,11 @@
if (rc)
return rc;
+ mdata->hist_intr.req = 0;
+ mdata->hist_intr.curr = 0;
+ mdata->hist_intr.state = 0;
+ spin_lock_init(&mdata->hist_intr.lock);
+
mdata->iclient = msm_ion_client_create(-1, mdata->pdev->name);
if (IS_ERR_OR_NULL(mdata->iclient)) {
pr_err("msm_ion_client_create() return error (%p)\n",
@@ -1057,15 +1068,20 @@
#define SPRINT(fmt, ...) \
(cnt += scnprintf(buf + cnt, len - cnt, fmt, ##__VA_ARGS__))
- SPRINT("mdp_version=5 hw_rev=%d\n", mdata->mdp_rev);
+ SPRINT("mdp_version=5\n");
+ SPRINT("hw_rev=%d\n", mdata->mdp_rev);
SPRINT("rgb_pipes=%d\n", mdata->nrgb_pipes);
SPRINT("vig_pipes=%d\n", mdata->nvig_pipes);
SPRINT("dma_pipes=%d\n", mdata->ndma_pipes);
SPRINT("smp_count=%d\n", mdata->smp_mb_cnt);
SPRINT("smp_size=%d\n", mdata->smp_mb_size);
- SPRINT("max downscale ratio=%d\n", MAX_DOWNSCALE_RATIO);
- SPRINT("max upscale ratio=%d\n", MAX_UPSCALE_RATIO);
- SPRINT("features:");
+ SPRINT("max_downscale_ratio=%d\n", MAX_DOWNSCALE_RATIO);
+ SPRINT("max_upscale_ratio=%d\n", MAX_UPSCALE_RATIO);
+ if (mdata->max_bw_low)
+ SPRINT("max_bandwidth_low=%u\n", mdata->max_bw_low);
+ if (mdata->max_bw_high)
+ SPRINT("max_bandwidth_high=%u\n", mdata->max_bw_high);
+ SPRINT("features=");
if (mdata->has_bwc)
SPRINT(" bwc");
if (mdata->has_decimation)
@@ -1302,7 +1318,7 @@
{
char *t = NULL;
char pan_intf_str[MDSS_MAX_PANEL_LEN];
- int rc, i;
+ int rc, i, panel_len;
char pan_name[MDSS_MAX_PANEL_LEN];
if (!pan_cfg)
@@ -1339,6 +1355,14 @@
strlcpy(&pan_cfg->arg_cfg[0], t, sizeof(pan_cfg->arg_cfg));
pr_debug("%s:%d: t=[%s] panel name=[%s]\n", __func__, __LINE__,
t, pan_cfg->arg_cfg);
+
+ panel_len = strlen(pan_cfg->arg_cfg);
+ if (!panel_len) {
+ pr_err("%s: Panel name is invalid\n", __func__);
+ pan_cfg->pan_intf = MDSS_PANEL_INTF_INVALID;
+ return -EINVAL;
+ }
+
rc = mdss_mdp_get_pan_intf(pan_intf_str);
pan_cfg->pan_intf = (rc < 0) ? MDSS_PANEL_INTF_INVALID : rc;
return 0;
@@ -1443,10 +1467,10 @@
of_node_put(chosen_node);
rc = mdss_mdp_get_pan_cfg(pan_cfg);
- if (!rc)
+ if (!rc) {
pan_cfg->init_done = true;
-
- return rc;
+ return rc;
+ }
get_dt_pan:
rc = mdss_mdp_parse_dt_pan_intf(pdev);
@@ -1962,6 +1986,16 @@
prop = of_find_property(pdev->dev.of_node, "batfet-supply", NULL);
mdata->batfet_required = prop ? true : false;
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,max-bandwidth-low-kbps", &mdata->max_bw_low);
+ if (rc)
+ pr_debug("max bandwidth (low) property not specified\n");
+
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,max-bandwidth-high-kbps", &mdata->max_bw_high);
+ if (rc)
+ pr_debug("max bandwidth (high) property not specified\n");
+
return 0;
}
@@ -1977,9 +2011,11 @@
mdata->ad_cfgs = NULL;
return 0;
}
+
if (mdata->nad_cfgs > mdata->nmixers_intf)
return -EINVAL;
+
mdata->has_wb_ad = of_property_read_bool(pdev->dev.of_node,
"qcom,mdss-has-wb-ad");
@@ -2082,7 +2118,7 @@
int rc;
if (!mdss_res || !mdss_res->pan_cfg.init_done)
- rc = -EPROBE_DEFER;
+ return -EPROBE_DEFER;
if (mdss_res->pan_cfg.lk_cfg)
rc = 1;
else
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 5442d9d..8918df8 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -37,7 +37,6 @@
#define MAX_IMG_HEIGHT 0x3FFF
#define MAX_DST_W MAX_MIXER_WIDTH
#define MAX_DST_H MAX_MIXER_HEIGHT
-#define MAX_PLANES 4
#define MAX_DOWNSCALE_RATIO 4
#define MAX_UPSCALE_RATIO 20
#define MAX_DECIMATION 4
@@ -52,6 +51,11 @@
/* wait for at most 2 vsync for lowest refresh rate (24hz) */
#define KOFF_TIMEOUT msecs_to_jiffies(84)
+#define OVERFETCH_DISABLE_TOP BIT(0)
+#define OVERFETCH_DISABLE_BOTTOM BIT(1)
+#define OVERFETCH_DISABLE_LEFT BIT(2)
+#define OVERFETCH_DISABLE_RIGHT BIT(3)
+
#ifdef MDSS_MDP_DEBUG_REG
static inline void mdss_mdp_reg_write(u32 addr, u32 val)
{
@@ -113,6 +117,12 @@
MDSS_MDP_MAX_CSC
};
+struct splash_pipe_cfg {
+ int width;
+ int height;
+ int mixer;
+};
+
struct mdss_mdp_ctl;
typedef void (*mdp_vsync_handler_t)(struct mdss_mdp_ctl *, ktime_t);
@@ -264,17 +274,23 @@
u32 hist_cnt_sent;
u32 hist_cnt_time;
u32 frame_cnt;
- u32 is_kick_ready;
struct completion comp;
u32 data[HIST_V_SIZE];
struct mutex hist_mutex;
spinlock_t hist_lock;
};
-struct mdss_ad_info {
+struct mdss_mdp_ad {
char __iomem *base;
u8 num;
+};
+
+struct mdss_ad_info {
+ u8 num;
+ u8 calc_hw_num;
+ u32 ops;
u32 sts;
+ u32 reg_sts;
u32 state;
u32 ad_data;
u32 ad_data_mode;
@@ -288,6 +304,7 @@
struct completion comp;
u32 last_str;
u32 last_bl;
+ u32 bl_data;
u32 calc_itr;
uint32_t bl_bright_shift;
uint32_t bl_lin[AD_BL_LIN_LEN];
@@ -341,9 +358,6 @@
u8 vert_deci;
struct mdss_mdp_img_rect src;
struct mdss_mdp_img_rect dst;
- u32 phase_step_x;
- u32 phase_step_y;
-
struct mdss_mdp_format_params *src_fmt;
struct mdss_mdp_plane_sizes src_planes;
@@ -353,6 +367,8 @@
u8 blend_op;
u8 overfetch_disable;
u32 transp;
+ u32 bg_color;
+ u8 has_buf;
struct msm_fb_data_type *mfd;
struct mdss_mdp_mixer *mixer;
@@ -370,11 +386,13 @@
struct mdp_overlay_pp_params pp_cfg;
struct mdss_pipe_pp_res pp_res;
+ struct mdp_scale_data scale;
+ u8 chroma_sample_h;
+ u8 chroma_sample_v;
};
struct mdss_mdp_writeback_arg {
struct mdss_mdp_data *data;
- void (*callback_fnc) (void *arg);
void *priv_data;
};
@@ -448,6 +466,8 @@
irqreturn_t mdss_mdp_isr(int irq, void *ptr);
int mdss_iommu_attach(struct mdss_data_type *mdata);
+int mdss_iommu_dettach(struct mdss_data_type *mdata);
+int mdss_mdp_scan_cont_splash(void);
void mdss_mdp_irq_clear(struct mdss_data_type *mdata,
u32 intr_type, u32 intf_num);
int mdss_mdp_irq_enable(u32 intr_type, u32 intf_num);
@@ -496,7 +516,7 @@
int mdss_mdp_ctl_split_display_setup(struct mdss_mdp_ctl *ctl,
struct mdss_panel_data *pdata);
int mdss_mdp_ctl_destroy(struct mdss_mdp_ctl *ctl);
-int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl);
+int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl, bool handoff);
int mdss_mdp_ctl_stop(struct mdss_mdp_ctl *ctl);
int mdss_mdp_ctl_intf_event(struct mdss_mdp_ctl *ctl, int event, void *arg);
int mdss_mdp_perf_calc_pipe(struct mdss_mdp_pipe *pipe,
@@ -509,6 +529,8 @@
int mdss_mdp_mixer_handoff(struct mdss_mdp_ctl *ctl, u32 num,
struct mdss_mdp_pipe *pipe);
+int mdss_mdp_scan_pipes(void);
+
struct mdss_mdp_mixer *mdss_mdp_wb_mixer_alloc(int rotator);
int mdss_mdp_wb_mixer_destroy(struct mdss_mdp_mixer *mixer);
struct mdss_mdp_mixer *mdss_mdp_mixer_get(struct mdss_mdp_ctl *ctl, int mux);
@@ -541,6 +563,7 @@
int mdss_hw_init(struct mdss_data_type *mdata);
int mdss_mdp_pa_config(struct mdp_pa_cfg_data *config, u32 *copyback);
+int mdss_mdp_pa_v2_config(struct mdp_pa_v2_cfg_data *config, u32 *copyback);
int mdss_mdp_pcc_config(struct mdp_pcc_cfg_data *cfg_ptr, u32 *copyback);
int mdss_mdp_igc_lut_config(struct mdp_igc_lut_data *config, u32 *copyback,
u32 copy_from_kernel);
@@ -549,8 +572,10 @@
int mdss_mdp_dither_config(struct mdp_dither_cfg_data *config, u32 *copyback);
int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config, u32 *copyback);
-int mdss_mdp_histogram_start(struct mdp_histogram_start_req *req);
-int mdss_mdp_histogram_stop(u32 block);
+int mdss_mdp_hist_intr_req(struct mdss_intr *intr, u32 bits, bool en);
+int mdss_mdp_hist_intr_setup(struct mdss_intr *intr, int state);
+int mdss_mdp_hist_start(struct mdp_histogram_start_req *req);
+int mdss_mdp_hist_stop(u32 block);
int mdss_mdp_hist_collect(struct mdp_histogram_data *hist);
void mdss_mdp_hist_intr_done(u32 isr);
@@ -558,7 +583,7 @@
struct mdss_ad_init_cfg *init_cfg);
int mdss_mdp_ad_input(struct msm_fb_data_type *mfd,
struct mdss_ad_input *input, int wait);
-int mdss_mdp_ad_addr_setup(struct mdss_data_type *mdata, u32 *ad_off);
+int mdss_mdp_ad_addr_setup(struct mdss_data_type *mdata, u32 *ad_offsets);
int mdss_mdp_calib_mode(struct msm_fb_data_type *mfd,
struct mdss_calib_cfg *cfg);
@@ -633,6 +658,7 @@
int mdss_mdp_wb_set_secure(struct msm_fb_data_type *mfd, int enable);
int mdss_mdp_wb_get_secure(struct msm_fb_data_type *mfd, uint8_t *enable);
+int mdss_mdp_pipe_program_pixel_extn(struct mdss_mdp_pipe *pipe);
#define mfd_to_mdp5_data(mfd) (mfd->mdp.private1)
#define mfd_to_mdata(mfd) (((struct mdss_overlay_private *)\
(mfd->mdp.private1))->mdata)
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 82937e3..d57e4fb 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -28,7 +28,7 @@
#define MDSS_MDP_BUS_FUDGE_FACTOR_IB(val) (((val) / 2) * 3)
#define MDSS_MDP_BUS_FUDGE_FACTOR_HIGH_IB(val) (val << 1)
#define MDSS_MDP_BUS_FUDGE_FACTOR_AB(val) (val << 1)
-#define MDSS_MDP_BUS_FLOOR_BW (3200000000ULL >> MDSS_MDP_BUS_FACTOR_SHIFT)
+#define MDSS_MDP_BUS_FLOOR_BW (1600000000ULL >> MDSS_MDP_BUS_FACTOR_SHIFT)
/* 1.25 clock fudge factor */
#define MDSS_MDP_CLK_FUDGE_FACTOR(val) (((val) * 5) / 4)
@@ -615,6 +615,7 @@
{
switch (ctl->panel_data->panel_info.type) {
case MIPI_VIDEO_PANEL:
+ case EDP_PANEL:
return mdss_mdp_video_reconfigure_splash_done(ctl, handoff);
case MIPI_CMD_PANEL:
return mdss_mdp_cmd_reconfigure_splash_done(ctl, handoff);
@@ -974,6 +975,8 @@
mixer->width = sctl->width;
mixer->height = sctl->height;
+ mixer->roi = (struct mdss_mdp_img_rect)
+ {0, 0, mixer->width, mixer->height};
sctl->mixer_left = mixer;
return mdss_mdp_set_split_ctl(ctl, sctl);
@@ -1059,26 +1062,34 @@
return rc;
}
-static int mdss_mdp_ctl_start_sub(struct mdss_mdp_ctl *ctl)
+static int mdss_mdp_ctl_start_sub(struct mdss_mdp_ctl *ctl, bool handoff)
{
struct mdss_mdp_mixer *mixer;
u32 outsize, temp;
int ret = 0;
int i, nmixers;
- if (ctl->start_fnc)
- ret = ctl->start_fnc(ctl);
- else
- pr_warn("no start function for ctl=%d type=%d\n", ctl->num,
- ctl->panel_data->panel_info.type);
-
- if (ret) {
- pr_err("unable to start intf\n");
- return ret;
- }
-
pr_debug("ctl_num=%d\n", ctl->num);
+ /*
+ * Need start_fnc in 2 cases:
+ * (1) handoff
+ * (2) continuous splash finished.
+ */
+ if (handoff || !ctl->panel_data->panel_info.cont_splash_enabled) {
+ if (ctl->start_fnc)
+ ret = ctl->start_fnc(ctl);
+ else
+ pr_warn("no start function for ctl=%d type=%d\n",
+ ctl->num,
+ ctl->panel_data->panel_info.type);
+
+ if (ret) {
+ pr_err("unable to start intf\n");
+ return ret;
+ }
+ }
+
if (!ctl->panel_data->panel_info.cont_splash_enabled) {
nmixers = MDSS_MDP_INTF_MAX_LAYERMIXER +
MDSS_MDP_WB_MAX_LAYERMIXER;
@@ -1105,9 +1116,10 @@
return ret;
}
-int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl)
+int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl, bool handoff)
{
struct mdss_mdp_ctl *sctl;
+ struct mdss_data_type *mdata = mdss_mdp_get_mdata();
int ret = 0;
if (ctl->power_on) {
@@ -1119,12 +1131,17 @@
if (ret)
return ret;
-
sctl = mdss_mdp_get_split_ctl(ctl);
mutex_lock(&ctl->lock);
- ctl->power_on = true;
+ /*
+ * keep power_on false during handoff to avoid unexpected
+ * operations to overlay.
+ */
+ if (!handoff)
+ ctl->power_on = true;
+
ctl->bus_ab_quota = 0;
ctl->bus_ib_quota = 0;
ctl->clk_rate = 0;
@@ -1137,10 +1154,10 @@
goto error;
}
- ret = mdss_mdp_ctl_start_sub(ctl);
+ ret = mdss_mdp_ctl_start_sub(ctl, handoff);
if (ret == 0) {
if (sctl) { /* split display is available */
- ret = mdss_mdp_ctl_start_sub(sctl);
+ ret = mdss_mdp_ctl_start_sub(sctl, handoff);
if (!ret)
mdss_mdp_ctl_split_display_enable(1, ctl, sctl);
} else if (ctl->mixer_right) {
@@ -1155,6 +1172,7 @@
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_PACK_3D, 0);
}
}
+ mdss_mdp_hist_intr_setup(&mdata->hist_intr, MDSS_IRQ_RESUME);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
error:
@@ -1167,6 +1185,7 @@
{
struct mdss_mdp_ctl *sctl;
int ret = 0;
+ struct mdss_data_type *mdata = mdss_mdp_get_mdata();
u32 off;
if (!ctl->power_on) {
@@ -1182,6 +1201,8 @@
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ mdss_mdp_hist_intr_setup(&mdata->hist_intr, MDSS_IRQ_SUSPEND);
+
if (ctl->stop_fnc)
ret = ctl->stop_fnc(ctl);
else
@@ -1560,9 +1581,17 @@
struct mdss_mdp_mixer *mdss_mdp_mixer_get(struct mdss_mdp_ctl *ctl, int mux)
{
struct mdss_mdp_mixer *mixer = NULL;
- struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(ctl->mfd);
- if (!ctl)
+ struct mdss_overlay_private *mdp5_data = NULL;
+ if (!ctl || !ctl->mfd) {
+ pr_err("ctl not initialized\n");
return NULL;
+ }
+
+ mdp5_data = mfd_to_mdp5_data(ctl->mfd);
+ if (!mdp5_data) {
+ pr_err("ctl not initialized\n");
+ return NULL;
+ }
switch (mux) {
case MDSS_MDP_MIXER_MUX_DEFAULT:
@@ -1774,6 +1803,11 @@
{
int ret;
+ if (!ctl) {
+ pr_err("invalid ctl\n");
+ return -ENODEV;
+ }
+
ret = mutex_lock_interruptible(&ctl->lock);
if (ret)
return ret;
@@ -1879,8 +1913,10 @@
if (ctl->wait_pingpong)
ctl->wait_pingpong(ctl, NULL);
- /* postprocessing setup, including dspp */
- mdss_mdp_pp_setup_locked(ctl);
+ if (ctl->mfd && ctl->mfd->dcm_state != DTM_ENTER)
+ /* postprocessing setup, including dspp */
+ mdss_mdp_pp_setup_locked(ctl);
+
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, ctl->flush_bits);
if (sctl) {
mdss_mdp_ctl_write(sctl, MDSS_MDP_REG_CTL_FLUSH,
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index c8af903..5d3e841 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -107,7 +107,9 @@
MDSS_MDP_MAX_CTL
};
-#define MDSS_MDP_REG_CTL_OFFSET(ctl) (0x00600 + ((ctl) * 0x100))
+#define MDSS_MDP_CTL_ADDRESS_OFFSET 0x100
+#define MDSS_MDP_REG_CTL_OFFSET(ctl) (0x00600 + ((ctl) * \
+ MDSS_MDP_CTL_ADDRESS_OFFSET))
#define MDSS_MDP_REG_CTL_LAYER(lm) ((lm) * 0x004)
#define MDSS_MDP_REG_CTL_TOP 0x014
@@ -158,7 +160,10 @@
MDSS_MDP_CHROMA_420
};
-#define MDSS_MDP_REG_SSPP_OFFSET(pipe) (0x01200 + ((pipe) * 0x400))
+
+#define MDSS_MDP_SSPP_ADDRESS_OFFSET 0x400
+#define MDSS_MDP_REG_SSPP_OFFSET(pipe) (0x01200 + ((pipe) * \
+ MDSS_MDP_SSPP_ADDRESS_OFFSET))
#define MDSS_MDP_REG_SSPP_SRC_SIZE 0x000
#define MDSS_MDP_REG_SSPP_SRC_IMG_SIZE 0x004
@@ -174,6 +179,7 @@
#define MDSS_MDP_REG_SSPP_STILE_FRAME_SIZE 0x02C
#define MDSS_MDP_REG_SSPP_SRC_FORMAT 0x030
#define MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN 0x034
+#define MDSS_MDP_REG_SSPP_SRC_CONSTANT_COLOR 0x03C
#define MDSS_MDP_REG_SSPP_REQPRIO_FIFO_WM_0 0x050
#define MDSS_MDP_REG_SSPP_REQPRIO_FIFO_WM_1 0x054
#define MDSS_MDP_REG_SSPP_REQPRIO_FIFO_WM_2 0x058
@@ -201,6 +207,9 @@
#define MDSS_MDP_REG_SSPP_CURRENT_SRC2_ADDR 0x0AC
#define MDSS_MDP_REG_SSPP_CURRENT_SRC3_ADDR 0x0B0
#define MDSS_MDP_REG_SSPP_DECIMATION_CONFIG 0x0B4
+#define MDSS_MDP_REG_SSPP_SW_PIX_EXT_C0_LR 0x100
+#define MDSS_MDP_REG_SSPP_SW_PIX_EXT_C0_TB 0x104
+#define MDSS_MDP_REG_SSPP_SW_PIX_EXT_C0_REQ_PIXELS 0x108
#define MDSS_MDP_REG_VIG_OP_MODE 0x200
#define MDSS_MDP_REG_VIG_QSEED2_CONFIG 0x204
@@ -213,8 +222,20 @@
#define MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEX 0x228
#define MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEY 0x22C
#define MDSS_MDP_REG_VIG_QSEED2_SHARP 0x230
+#define MDSS_MDP_REG_VIG_MEM_COL_BASE 0x288
#define MDSS_MDP_REG_VIG_PA_BASE 0x310
+#define MDSS_MDP_VIG_OP_PA_SAT_ZERO_EXP_EN BIT(2)
+#define MDSS_MDP_VIG_OP_PA_MEM_PROTECT_EN BIT(3)
+#define MDSS_MDP_VIG_OP_PA_EN BIT(4)
+#define MDSS_MDP_VIG_OP_PA_MEM_COL_SKIN_MASK BIT(5)
+#define MDSS_MDP_VIG_OP_PA_MEM_COL_FOL_MASK BIT(6)
+#define MDSS_MDP_VIG_OP_PA_MEM_COL_SKY_MASK BIT(7)
+#define MDSS_MDP_VIG_OP_PA_HUE_MASK BIT(25)
+#define MDSS_MDP_VIG_OP_PA_SAT_MASK BIT(26)
+#define MDSS_MDP_VIG_OP_PA_VAL_MASK BIT(27)
+#define MDSS_MDP_VIG_OP_PA_CONT_MASK BIT(28)
+
#define MDSS_MDP_REG_SCALE_CONFIG 0x204
#define MDSS_MDP_REG_SCALE_PHASE_STEP_X 0x210
#define MDSS_MDP_REG_SCALE_PHASE_STEP_Y 0x214
@@ -264,8 +285,9 @@
MDSS_MDP_MAX_STAGE
};
-#define MDSS_MDP_REG_LM_OFFSET(lm) (0x03200 + ((lm) * 0x400))
-
+#define MDSS_MDP_LM_ADDRESS_OFFSET 0x400
+#define MDSS_MDP_REG_LM_OFFSET(lm) (0x03200 + ((lm) * \
+ MDSS_MDP_LM_ADDRESS_OFFSET))
#define MDSS_MDP_REG_LM_OP_MODE 0x000
#define MDSS_MDP_REG_LM_OUT_SIZE 0x004
#define MDSS_MDP_REG_LM_BORDER_COLOR_0 0x008
@@ -356,6 +378,8 @@
#define MDSS_MDP_REG_WB_CSC_BASE 0x260
#define MDSS_MDP_REG_WB_DST_ADDR_SW_STATUS 0x2B0
+#define MDSS_MDP_MAX_AD_AL 65535
+#define MDSS_MDP_MAX_AD_STR 255
#define MDSS_MDP_REG_AD_BYPASS 0x000
#define MDSS_MDP_REG_AD_CTRL_0 0x004
@@ -391,6 +415,11 @@
#define MDSS_MDP_REG_AD_STR_OUT 0x14C
#define MDSS_MDP_REG_AD_BL_OUT 0x154
#define MDSS_MDP_REG_AD_CALC_DONE 0x158
+#define MDSS_MDP_REG_AD_FRAME_END 0x15C
+#define MDSS_MDP_REG_AD_PROCS_END 0x160
+#define MDSS_MDP_REG_AD_FRAME_START 0x164
+#define MDSS_MDP_REG_AD_PROCS_START 0x168
+#define MDSS_MDP_REG_AD_TILE_CTRL 0x16C
enum mdss_mdp_dspp_index {
MDSS_MDP_DSPP0,
@@ -400,16 +429,41 @@
MDSS_MDP_MAX_DSPP
};
-#define MDSS_MDP_REG_DSPP_OFFSET(pipe) (0x4600 + ((pipe) * 0x400))
+#define MDSS_MDP_DSPP_ADDRESS_OFFSET 0x400
+#define MDSS_MDP_REG_DSPP_OFFSET(pipe) (0x4600 + ((pipe) * \
+ MDSS_MDP_DSPP_ADDRESS_OFFSET))
#define MDSS_MDP_REG_DSPP_OP_MODE 0x000
#define MDSS_MDP_REG_DSPP_PCC_BASE 0x030
#define MDSS_MDP_REG_DSPP_DITHER_DEPTH 0x150
#define MDSS_MDP_REG_DSPP_HIST_CTL_BASE 0x210
#define MDSS_MDP_REG_DSPP_HIST_LUT_BASE 0x230
#define MDSS_MDP_REG_DSPP_PA_BASE 0x238
+#define MDSS_MDP_REG_DSPP_SIX_ZONE_BASE 0x248
#define MDSS_MDP_REG_DSPP_GAMUT_BASE 0x2DC
#define MDSS_MDP_REG_DSPP_GC_BASE 0x2B0
+#define MDSS_MDP_DSPP_OP_IGC_LUT_EN BIT(0)
+#define MDSS_MDP_DSPP_OP_PA_SAT_ZERO_EXP_EN BIT(1)
+#define MDSS_MDP_DSPP_OP_PA_MEM_PROTECT_EN BIT(2)
+#define MDSS_MDP_DSPP_OP_PCC_EN BIT(4)
+#define MDSS_MDP_DSPP_OP_PA_MEM_COL_SKIN_MASK BIT(5)
+#define MDSS_MDP_DSPP_OP_PA_MEM_COL_FOL_MASK BIT(6)
+#define MDSS_MDP_DSPP_OP_PA_MEM_COL_SKY_MASK BIT(7)
+#define MDSS_MDP_DSPP_OP_DST_DITHER_EN BIT(8)
+#define MDSS_MDP_DSPP_OP_HIST_EN BIT(16)
+#define MDSS_MDP_DSPP_OP_HIST_LUTV_EN BIT(19)
+#define MDSS_MDP_DSPP_OP_PA_EN BIT(20)
+#define MDSS_MDP_DSPP_OP_ARGC_LUT_EN BIT(22)
+#define MDSS_MDP_DSPP_OP_GAMUT_EN BIT(23)
+#define MDSS_MDP_DSPP_OP_GAMUT_PCC_ORDER BIT(24)
+#define MDSS_MDP_DSPP_OP_PA_HUE_MASK BIT(25)
+#define MDSS_MDP_DSPP_OP_PA_SAT_MASK BIT(26)
+#define MDSS_MDP_DSPP_OP_PA_VAL_MASK BIT(27)
+#define MDSS_MDP_DSPP_OP_PA_CONT_MASK BIT(28)
+#define MDSS_MDP_DSPP_OP_PA_SIX_ZONE_HUE_MASK BIT(29)
+#define MDSS_MDP_DSPP_OP_PA_SIX_ZONE_SAT_MASK BIT(30)
+#define MDSS_MDP_DSPP_OP_PA_SIX_ZONE_VAL_MASK BIT(31)
+
enum mdss_mpd_intf_index {
MDSS_MDP_NO_INTF,
MDSS_MDP_INTF0,
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
index 6056f21..c4a0645 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
@@ -196,12 +196,14 @@
static inline void mdss_mdp_cmd_clk_on(struct mdss_mdp_cmd_ctx *ctx)
{
unsigned long flags;
+ struct mdss_data_type *mdata = mdss_mdp_get_mdata();
mutex_lock(&ctx->clk_mtx);
if (!ctx->clk_enabled) {
ctx->clk_enabled = 1;
mdss_mdp_ctl_intf_event
(ctx->ctl, MDSS_EVENT_PANEL_CLK_CTRL, (void *)1);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ mdss_mdp_hist_intr_setup(&mdata->hist_intr, MDSS_IRQ_RESUME);
}
spin_lock_irqsave(&ctx->clk_lock, flags);
if (!ctx->rdptr_enabled)
@@ -214,6 +216,7 @@
static inline void mdss_mdp_cmd_clk_off(struct mdss_mdp_cmd_ctx *ctx)
{
unsigned long flags;
+ struct mdss_data_type *mdata = mdss_mdp_get_mdata();
int set_clk_off = 0;
mutex_lock(&ctx->clk_mtx);
@@ -224,6 +227,7 @@
if (ctx->clk_enabled && set_clk_off) {
ctx->clk_enabled = 0;
+ mdss_mdp_hist_intr_setup(&mdata->hist_intr, MDSS_IRQ_SUSPEND);
mdss_mdp_ctl_intf_event
(ctx->ctl, MDSS_EVENT_PANEL_CLK_CTRL, (void *)0);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
@@ -510,14 +514,14 @@
mdss_mdp_cmd_set_partial_roi(ctl);
+ mdss_mdp_cmd_clk_on(ctx);
+
/*
* tx dcs command if had any
*/
mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_DSI_CMDLIST_KOFF,
(void *)&ctx->recovery);
- mdss_mdp_cmd_clk_on(ctx);
-
INIT_COMPLETION(ctx->pp_comp);
mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num);
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_START, 1);
@@ -532,6 +536,7 @@
int mdss_mdp_cmd_stop(struct mdss_mdp_ctl *ctl)
{
struct mdss_mdp_cmd_ctx *ctx;
+ struct mdss_panel_info *pinfo;
unsigned long flags;
struct mdss_mdp_vsync_handler *tmp, *handle;
int need_wait = 0;
@@ -555,9 +560,23 @@
if (need_wait)
if (wait_for_completion_timeout(&ctx->stop_comp, STOP_TIMEOUT)
- <= 0)
+ <= 0) {
WARN(1, "stop cmd time out\n");
+ if (IS_ERR_OR_NULL(ctl->panel_data)) {
+ pr_err("no panel data\n");
+ } else {
+ pinfo = &ctl->panel_data->panel_info;
+
+ if (pinfo->panel_dead) {
+ mdss_mdp_irq_disable
+ (MDSS_MDP_IRQ_PING_PONG_RD_PTR,
+ ctx->pp_num);
+ ctx->rdptr_enabled = 0;
+ }
+ }
+ }
+
if (cancel_work_sync(&ctx->clk_work))
pr_debug("no pending clk work\n");
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index 7c79ceb..f8c59d7 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -62,6 +62,7 @@
atomic_t vsync_ref;
spinlock_t vsync_lock;
+ struct mutex vsync_mtx;
struct list_head vsync_handlers;
};
@@ -216,19 +217,23 @@
{
struct mdss_mdp_video_ctx *ctx = ctl->priv_data;
+ mutex_lock(&ctx->vsync_mtx);
if (atomic_inc_return(&ctx->vsync_ref) == 1)
mdss_mdp_irq_enable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
else if (clear)
mdss_mdp_irq_clear(ctl->mdata, MDSS_MDP_IRQ_INTF_VSYNC,
ctl->intf_num);
+ mutex_unlock(&ctx->vsync_mtx);
}
static inline void video_vsync_irq_disable(struct mdss_mdp_ctl *ctl)
{
struct mdss_mdp_video_ctx *ctx = ctl->priv_data;
+ mutex_lock(&ctx->vsync_mtx);
if (atomic_dec_return(&ctx->vsync_ref) == 0)
mdss_mdp_irq_disable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
+ mutex_unlock(&ctx->vsync_mtx);
}
static int mdss_mdp_video_add_vsync_handler(struct mdss_mdp_ctl *ctl,
@@ -294,6 +299,7 @@
struct mdss_mdp_video_ctx *ctx;
struct mdss_mdp_vsync_handler *tmp, *handle;
int rc;
+ u32 frame_rate = 0;
pr_debug("stop ctl=%d\n", ctl->num);
@@ -313,6 +319,14 @@
WARN(rc, "intf %d blank error (%d)\n", ctl->intf_num, rc);
mdp_video_write(ctx, MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 0);
+ /* wait for at least one VSYNC on HDMI intf for proper TG OFF */
+ if (MDSS_INTF_HDMI == ctx->intf_type) {
+ frame_rate = mdss_panel_get_framerate
+ (&(ctl->panel_data->panel_info));
+ if (!(frame_rate >= 24 && frame_rate <= 240))
+ frame_rate = 24;
+ msleep((1000/frame_rate) + 1);
+ }
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
ctx->timegen_en = false;
@@ -429,10 +443,9 @@
} else {
rc = 0;
}
-
- mdss_mdp_ctl_notify(ctl,
- rc ? MDP_NOTIFY_FRAME_TIMEOUT : MDP_NOTIFY_FRAME_DONE);
}
+ mdss_mdp_ctl_notify(ctl,
+ rc ? MDP_NOTIFY_FRAME_TIMEOUT : MDP_NOTIFY_FRAME_DONE);
if (ctx->wait_pending) {
ctx->wait_pending = 0;
@@ -676,6 +689,7 @@
ctx->intf_type = ctl->intf_type;
init_completion(&ctx->vsync_comp);
spin_lock_init(&ctx->vsync_lock);
+ mutex_init(&ctx->vsync_mtx);
atomic_set(&ctx->vsync_ref, 0);
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num,
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
index 3929501..ff55c57 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
@@ -46,8 +46,6 @@
struct mdss_mdp_plane_sizes dst_planes;
- void (*callback_fnc) (void *arg);
- void *callback_arg;
spinlock_t wb_lock;
struct list_head vsync_handlers;
};
@@ -365,6 +363,8 @@
mdss_mdp_set_intr_callback(ctx->intr_type, ctx->intf_num,
NULL, NULL);
+ complete_all(&ctx->wb_comp);
+
ctl->priv_data = NULL;
ctx->ref_cnt--;
}
@@ -389,9 +389,6 @@
mdss_mdp_irq_disable_nosync(ctx->intr_type, ctx->intf_num);
- if (ctx->callback_fnc)
- ctx->callback_fnc(ctx->callback_arg);
-
spin_lock(&ctx->wb_lock);
list_for_each_entry(tmp, &ctx->vsync_handlers, list) {
tmp->vsync_handler(ctl, vsync_time);
@@ -467,9 +464,6 @@
mdss_mdp_set_intr_callback(ctx->intr_type, ctx->intf_num,
mdss_mdp_writeback_intr_done, ctl);
- ctx->callback_fnc = wb_args->callback_fnc;
- ctx->callback_arg = wb_args->priv_data;
-
flush_bits = BIT(16); /* WB */
mdp_wb_write(ctx, MDSS_MDP_REG_WB_DST_ADDR_SW_STATUS, ctl->is_secure);
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, flush_bits);
@@ -529,6 +523,8 @@
int mdss_mdp_writeback_display_commit(struct mdss_mdp_ctl *ctl, void *arg)
{
+ int ret = 0;
+
if (ctl->shared_lock && !mutex_is_locked(ctl->shared_lock)) {
pr_err("shared mutex is not locked before commit on ctl=%d\n",
ctl->num);
@@ -542,5 +538,10 @@
ctl->mixer_right->params_changed++;
}
- return mdss_mdp_display_commit(ctl, arg);
+ ret = mdss_mdp_display_commit(ctl, arg);
+
+ if (!IS_ERR_VALUE(ret))
+ mdss_mdp_display_wait4comp(ctl);
+
+ return ret;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index c296edb..572af1c 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -34,6 +34,8 @@
#include "mdss_mdp.h"
#include "mdss_mdp_rotator.h"
+#include "splash.h"
+
#define VSYNC_PERIOD 16
#define BORDERFILL_NDX 0x0BF000BF
#define CHECK_BOUNDS(offset, size, max_size) \
@@ -44,6 +46,8 @@
#define MEM_PROTECT_SD_CTRL 0xF
+#define INVALID_PIPE_INDEX 0xFFFF
+
struct sd_ctrl_req {
unsigned int enable;
} __attribute__ ((__packed__));
@@ -282,7 +286,12 @@
int rc;
src = pipe->src.w >> pipe->horz_deci;
- rc = mdss_mdp_calc_phase_step(src, pipe->dst.w, &pipe->phase_step_x);
+
+ if (pipe->scale.enable_pxl_ext)
+ return 0;
+ memset(&pipe->scale, 0, sizeof(struct mdp_scale_data));
+ rc = mdss_mdp_calc_phase_step(src, pipe->dst.w,
+ &pipe->scale.phase_step_x[0]);
if (rc) {
pr_err("Horizontal scaling calculation failed=%d! %d->%d\n",
rc, src, pipe->dst.w);
@@ -290,16 +299,43 @@
}
src = pipe->src.h >> pipe->vert_deci;
- rc = mdss_mdp_calc_phase_step(src, pipe->dst.h, &pipe->phase_step_y);
+ rc = mdss_mdp_calc_phase_step(src, pipe->dst.h,
+ &pipe->scale.phase_step_y[0]);
if (rc) {
pr_err("Vertical scaling calculation failed=%d! %d->%d\n",
rc, src, pipe->dst.h);
return rc;
}
-
+ pipe->scale.init_phase_x[0] = (pipe->scale.phase_step_x[0] -
+ (1 << PHASE_STEP_SHIFT)) / 2;
+ pipe->scale.init_phase_y[0] = (pipe->scale.phase_step_y[0] -
+ (1 << PHASE_STEP_SHIFT)) / 2;
return 0;
}
+static inline void __mdss_mdp_overlay_set_chroma_sample(
+ struct mdss_mdp_pipe *pipe)
+{
+ pipe->chroma_sample_v = pipe->chroma_sample_h = 0;
+
+ switch (pipe->src_fmt->chroma_sample) {
+ case MDSS_MDP_CHROMA_H1V2:
+ pipe->chroma_sample_v = 1;
+ break;
+ case MDSS_MDP_CHROMA_H2V1:
+ pipe->chroma_sample_h = 1;
+ break;
+ case MDSS_MDP_CHROMA_420:
+ pipe->chroma_sample_v = 1;
+ pipe->chroma_sample_h = 1;
+ break;
+ }
+ if (pipe->horz_deci)
+ pipe->chroma_sample_h = 0;
+ if (pipe->vert_deci)
+ pipe->chroma_sample_v = 0;
+}
+
static int mdss_mdp_overlay_pipe_setup(struct msm_fb_data_type *mfd,
struct mdp_overlay *req,
struct mdss_mdp_pipe **ppipe)
@@ -442,7 +478,10 @@
pipe->dst.h = req->dst_rect.h;
pipe->horz_deci = req->horz_deci;
pipe->vert_deci = req->vert_deci;
+
+ memcpy(&pipe->scale, &req->scale, sizeof(struct mdp_scale_data));
pipe->src_fmt = fmt;
+ __mdss_mdp_overlay_set_chroma_sample(pipe);
pipe->mixer_stage = req->z_order;
pipe->is_fg = req->is_fg;
@@ -458,8 +497,18 @@
pr_debug("Unintended blend_op %d on layer with no alpha plane\n",
pipe->blend_op);
- pipe->overfetch_disable = fmt->is_yuv &&
- !(pipe->flags & MDP_SOURCE_ROTATED_90);
+ if (fmt->is_yuv && !(pipe->flags & MDP_SOURCE_ROTATED_90) &&
+ !pipe->scale.enable_pxl_ext) {
+ pipe->overfetch_disable = OVERFETCH_DISABLE_BOTTOM;
+
+ if (!(pipe->flags & MDSS_MDP_DUAL_PIPE) ||
+ (pipe->flags & MDSS_MDP_RIGHT_MIXER))
+ pipe->overfetch_disable |= OVERFETCH_DISABLE_RIGHT;
+ pr_debug("overfetch flags=%x\n", pipe->overfetch_disable);
+ } else {
+ pipe->overfetch_disable = 0;
+ }
+ pipe->bg_color = req->bg_color;
req->id = pipe->ndx;
pipe->req_data = *req;
@@ -495,11 +544,10 @@
pipe->pp_cfg.hist_cfg.frame_cnt;
hist.bit_mask = pipe->pp_cfg.hist_cfg.bit_mask;
hist.num_bins = pipe->pp_cfg.hist_cfg.num_bins;
- mdss_mdp_histogram_start(&hist);
+ mdss_mdp_hist_start(&hist);
} else if (pipe->pp_cfg.hist_cfg.ops &
MDP_PP_OPS_DISABLE) {
- mdss_mdp_histogram_stop(
- pipe->pp_cfg.hist_cfg.block);
+ mdss_mdp_hist_stop(pipe->pp_cfg.hist_cfg.block);
}
}
len = pipe->pp_cfg.hist_lut_cfg.len;
@@ -516,12 +564,16 @@
}
}
- if (pipe->flags & MDP_DEINTERLACE) {
+ if ((pipe->flags & MDP_DEINTERLACE) && !pipe->scale.enable_pxl_ext) {
if (pipe->flags & MDP_SOURCE_ROTATED_90) {
+ pipe->src.x = DIV_ROUND_UP(pipe->src.x, 2);
+ pipe->src.x &= ~1;
pipe->src.w /= 2;
pipe->img_width /= 2;
} else {
pipe->src.h /= 2;
+ pipe->src.y = DIV_ROUND_UP(pipe->src.y, 2);
+ pipe->src.y &= ~1;
}
}
@@ -539,6 +591,12 @@
!mdp5_data->mdata->has_wfd_blk)
mdss_mdp_smp_release(pipe);
+ /*
+ * Clear previous SMP reservations and reserve according to the
+ * latest configuration
+ */
+ mdss_mdp_smp_unreserve(pipe);
+
ret = mdss_mdp_smp_reserve(pipe);
if (ret) {
pr_debug("mdss_mdp_smp_reserve failed. ret=%d\n", ret);
@@ -546,6 +604,7 @@
}
pipe->params_changed++;
+ pipe->has_buf = 0;
req->vert_deci = pipe->vert_deci;
@@ -776,6 +835,9 @@
if (ctl->power_on) {
if (!mdp5_data->mdata->batfet)
mdss_mdp_batfet_ctrl(mdp5_data->mdata, true);
+ if (!is_mdss_iommu_attached() &&
+ !mfd->panel_info->cont_splash_enabled)
+ mdss_iommu_attach(mdp5_data->mdata);
return 0;
}
@@ -801,7 +863,7 @@
mdss_hw_init(mdss_res);
}
- rc = mdss_mdp_ctl_start(ctl);
+ rc = mdss_mdp_ctl_start(ctl, false);
if (rc == 0) {
atomic_inc(&ov_active_panels);
@@ -894,6 +956,9 @@
int ret = 0;
int sd_in_pipe = 0;
+ if (!is_mdss_iommu_attached() && !mfd->panel_info->cont_splash_enabled)
+ mdss_iommu_attach(mdp5_data->mdata);
+
if (ctl->shared_lock)
mutex_lock(ctl->shared_lock);
@@ -977,8 +1042,9 @@
} else if (pipe->front_buf.num_planes) {
buf = &pipe->front_buf;
} else {
- pr_warn("pipe queue w/o buffer\n");
- continue;
+ pr_debug("no buf detected pnum=%d use solid fill\n",
+ pipe->num);
+ buf = NULL;
}
ret = mdss_mdp_pipe_queue_data(pipe, buf);
@@ -1103,11 +1169,13 @@
/**
* mdss_mdp_overlay_release_all() - release any overlays associated with fb dev
* @mfd: Msm frame buffer structure associated with fb device
+ * @release_all: ignore pid and release all the pipes
*
* Release any resources allocated by calling process, this can be called
* on fb_release to release any overlays/rotator sessions left open.
*/
-static int __mdss_mdp_overlay_release_all(struct msm_fb_data_type *mfd)
+static int __mdss_mdp_overlay_release_all(struct msm_fb_data_type *mfd,
+ bool release_all)
{
struct mdss_mdp_pipe *pipe;
struct mdss_mdp_rotator_session *rot, *tmp;
@@ -1121,7 +1189,7 @@
mutex_lock(&mdp5_data->ov_lock);
mutex_lock(&mfd->lock);
list_for_each_entry(pipe, &mdp5_data->pipes_used, used_list) {
- if (!mfd->ref_cnt || (pipe->pid == pid)) {
+ if (release_all || (pipe->pid == pid)) {
unset_ndx |= pipe->ndx;
cnt++;
}
@@ -1133,6 +1201,9 @@
cnt++;
}
+ pr_debug("release_all=%d mfd->ref_cnt=%d unset_ndx=0x%x cnt=%d\n",
+ release_all, mfd->ref_cnt, unset_ndx, cnt);
+
mutex_unlock(&mfd->lock);
if (unset_ndx) {
@@ -1201,6 +1272,7 @@
if (IS_ERR_VALUE(ret)) {
pr_err("src_data pmem error\n");
}
+ pipe->has_buf = 1;
mdss_mdp_pipe_unmap(pipe);
return ret;
@@ -1307,18 +1379,18 @@
static int mdss_mdp_overlay_get_fb_pipe(struct msm_fb_data_type *mfd,
struct mdss_mdp_pipe **ppipe,
- int mixer_mux)
+ int mixer_mux,
+ struct mdp_overlay *req_ov)
{
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
struct mdss_mdp_pipe *pipe;
+ int ret;
pipe = mdss_mdp_mixer_stage_pipe(mdp5_data->ctl, mixer_mux,
MDSS_MDP_STAGE_BASE);
+
if (pipe == NULL) {
- struct mdp_overlay req;
- struct fb_info *fbi = mfd->fbi;
struct mdss_mdp_mixer *mixer;
- int ret, bpp;
mixer = mdss_mdp_mixer_get(mdp5_data->ctl,
MDSS_MDP_MIXER_MUX_LEFT);
@@ -1327,49 +1399,73 @@
return -ENODEV;
}
- memset(&req, 0, sizeof(req));
+ if (req_ov == NULL) {
+ struct mdp_overlay req;
+ struct fb_info *fbi = mfd->fbi;
+ int bpp;
- bpp = fbi->var.bits_per_pixel / 8;
- req.id = MSMFB_NEW_REQUEST;
- req.src.format = mfd->fb_imgType;
- req.src.height = fbi->var.yres;
- req.src.width = fbi->fix.line_length / bpp;
- if (mixer_mux == MDSS_MDP_MIXER_MUX_RIGHT) {
- if (req.src.width <= mixer->width) {
- pr_warn("right fb pipe not needed\n");
- return -EINVAL;
+ memset(&req, 0, sizeof(req));
+
+ bpp = fbi->var.bits_per_pixel / 8;
+ req.id = MSMFB_NEW_REQUEST;
+ req.src.format = mfd->fb_imgType;
+ req.src.height = fbi->var.yres;
+ req.src.width = fbi->fix.line_length / bpp;
+ if (mixer_mux == MDSS_MDP_MIXER_MUX_RIGHT) {
+ if (req.src.width <= mixer->width) {
+ pr_warn("right fb pipe not needed\n");
+ return -EINVAL;
+ }
+
+ req.flags |= MDSS_MDP_RIGHT_MIXER;
+ req.src_rect.x = mixer->width;
+ req.src_rect.w = fbi->var.xres - mixer->width;
+ } else {
+ req.src_rect.x = 0;
+ req.src_rect.w = MIN(fbi->var.xres,
+ mixer->width);
}
- req.flags |= MDSS_MDP_RIGHT_MIXER;
- req.src_rect.x = mixer->width;
- req.src_rect.w = fbi->var.xres - mixer->width;
+ req.src_rect.y = 0;
+ req.src_rect.h = req.src.height;
+ req.dst_rect.x = 0;
+ req.dst_rect.y = 0;
+ req.dst_rect.w = req.src_rect.w;
+ req.dst_rect.h = req.src_rect.h;
+ req.z_order = MDSS_MDP_STAGE_BASE;
+
+ pr_debug("allocating base pipe mux=%d\n", mixer_mux);
+
+ ret = mdss_mdp_overlay_pipe_setup(mfd, &req, &pipe);
+ if (ret)
+ return ret;
} else {
- req.src_rect.x = 0;
- req.src_rect.w = MIN(fbi->var.xres, mixer->width);
+ if (mixer_mux == MDSS_MDP_MIXER_MUX_RIGHT) {
+ req_ov->id = MSMFB_NEW_REQUEST;
+ req_ov->flags |= MDSS_MDP_RIGHT_MIXER;
+ req_ov->src_rect.w = MIN(mixer->width,
+ req_ov->src_rect.w >> 1);
+ req_ov->dst_rect.w = req_ov->src_rect.w;
+ req_ov->src_rect.x = req_ov->src_rect.w;
+ req_ov->dst_rect.x = 0;
+ }
+
+ ret = mdss_mdp_overlay_pipe_setup(mfd, req_ov, &pipe);
+ if (ret)
+ return ret;
}
-
- req.src_rect.y = 0;
- req.src_rect.h = req.src.height;
- req.dst_rect.x = 0;
- req.dst_rect.y = 0;
- req.dst_rect.w = req.src_rect.w;
- req.dst_rect.h = req.src_rect.h;
- req.z_order = MDSS_MDP_STAGE_BASE;
-
- pr_debug("allocating base pipe mux=%d\n", mixer_mux);
-
- ret = mdss_mdp_overlay_pipe_setup(mfd, &req, &pipe);
- if (ret)
- return ret;
-
- pr_debug("ctl=%d pnum=%d\n", mdp5_data->ctl->num, pipe->num);
}
+ pr_debug("ctl=%d pnum=%d\n", mdp5_data->ctl->num, pipe->num);
+
*ppipe = pipe;
return 0;
}
-static void mdss_mdp_overlay_pan_display(struct msm_fb_data_type *mfd)
+static void mdss_mdp_overlay_pan_display(struct msm_fb_data_type *mfd,
+ struct mdp_overlay *req,
+ int image_size,
+ int *pipe_ndx)
{
struct mdss_mdp_data *buf;
struct mdss_mdp_pipe *pipe;
@@ -1417,8 +1513,8 @@
goto pan_display_error;
}
-
- ret = mdss_mdp_overlay_get_fb_pipe(mfd, &pipe, MDSS_MDP_MIXER_MUX_LEFT);
+ ret = mdss_mdp_overlay_get_fb_pipe(mfd, &pipe,
+ MDSS_MDP_MIXER_MUX_LEFT, req);
if (ret) {
pr_err("unable to allocate base pipe\n");
goto pan_display_error;
@@ -1428,12 +1524,14 @@
pr_err("unable to map base pipe\n");
goto pan_display_error;
}
+ if (pipe_ndx)
+ pipe_ndx[0] = pipe->ndx;
buf = &pipe->back_buf;
if (is_mdss_iommu_attached()) {
if (!mfd->iova) {
pr_err("mfd iova is zero\n");
- goto pan_display_error;
+ goto attach_err;
}
buf->p[0].addr = mfd->iova;
} else {
@@ -1441,22 +1539,30 @@
}
buf->p[0].addr += offset;
- buf->p[0].len = fbi->fix.smem_len - offset;
+ if (image_size)
+ buf->p[0].len = image_size;
+ else
+ buf->p[0].len = fbi->fix.smem_len - offset;
buf->num_planes = 1;
+ pipe->has_buf = 1;
mdss_mdp_pipe_unmap(pipe);
if (fbi->var.xres > MAX_MIXER_WIDTH || mfd->split_display) {
ret = mdss_mdp_overlay_get_fb_pipe(mfd, &pipe,
- MDSS_MDP_MIXER_MUX_RIGHT);
+ MDSS_MDP_MIXER_MUX_RIGHT, req);
if (ret) {
pr_err("unable to allocate right base pipe\n");
- goto pan_display_error;
+ goto attach_err;
}
if (mdss_mdp_pipe_map(pipe)) {
pr_err("unable to map right base pipe\n");
- goto pan_display_error;
+ goto attach_err;
}
+ if (pipe_ndx)
+ pipe_ndx[1] = pipe->ndx;
+
pipe->back_buf = *buf;
+ pipe->has_buf = 1;
mdss_mdp_pipe_unmap(pipe);
}
mutex_unlock(&mdp5_data->ov_lock);
@@ -1467,6 +1573,12 @@
return;
+attach_err:
+ mutex_unlock(&mdp5_data->ov_lock);
+ mdss_mdp_overlay_unset(mfd, pipe->ndx);
+ if (pipe_ndx)
+ pipe_ndx[0] = INVALID_PIPE_INDEX;
+ return;
pan_display_error:
mutex_unlock(&mdp5_data->ov_lock);
}
@@ -1475,15 +1587,26 @@
static void mdss_mdp_overlay_handle_vsync(struct mdss_mdp_ctl *ctl,
ktime_t t)
{
- struct msm_fb_data_type *mfd = ctl->mfd;
- struct mdss_overlay_private *mdp5_data;
+ struct msm_fb_data_type *mfd = NULL;
+ struct mdss_overlay_private *mdp5_data = NULL;
+ if (!ctl) {
+ pr_err("ctl is NULL\n");
+ return;
+ }
+
+ mfd = ctl->mfd;
if (!mfd || !mfd->mdp.private1) {
pr_warn("Invalid handle for vsync\n");
return;
}
mdp5_data = mfd_to_mdp5_data(mfd);
+ if (!mdp5_data) {
+ pr_err("mdp5_data is NULL\n");
+ return;
+ }
+
pr_debug("vsync on fb%d play_cnt=%d\n", mfd->index, ctl->play_cnt);
mdp5_data->vsync_time = t;
@@ -1499,8 +1622,8 @@
return -ENODEV;
if (!ctl->add_vsync_handler || !ctl->remove_vsync_handler)
return -EOPNOTSUPP;
-
- if (!ctl->power_on) {
+ if (!ctl->panel_data->panel_info.cont_splash_enabled
+ && !ctl->power_on) {
pr_debug("fb%d vsync pending first update en=%d\n",
mfd->index, en);
return -EPERM;
@@ -1617,7 +1740,9 @@
u64 vsync_ticks;
int ret;
- if (!mdp5_data->ctl || !mdp5_data->ctl->power_on)
+ if (!mdp5_data->ctl ||
+ (!mdp5_data->ctl->panel_data->panel_info.cont_splash_enabled
+ && !mdp5_data->ctl->power_on))
return -EAGAIN;
vsync_ticks = ktime_to_ns(mdp5_data->vsync_time);
@@ -1881,6 +2006,11 @@
©back);
break;
+ case mdp_op_pa_v2_cfg:
+ ret = mdss_mdp_pa_v2_config(&mdp_pp.data.pa_v2_cfg_data,
+ ©back);
+ break;
+
case mdp_op_pcc_cfg:
ret = mdss_mdp_pcc_config(&mdp_pp.data.pcc_cfg_data,
©back);
@@ -1987,7 +2117,7 @@
if (ret)
return ret;
- ret = mdss_mdp_histogram_start(&hist_req);
+ ret = mdss_mdp_hist_start(&hist_req);
break;
case MSMFB_HISTOGRAM_STOP:
@@ -1995,7 +2125,7 @@
if (ret)
return ret;
- ret = mdss_mdp_histogram_stop(block);
+ ret = mdss_mdp_hist_stop(block);
if (ret)
return ret;
@@ -2031,7 +2161,10 @@
struct msmfb_metadata *metadata)
{
struct mdss_data_type *mdata = mfd_to_mdata(mfd);
+ struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
int ret = 0;
+ if (!ctl)
+ return -EPERM;
switch (metadata->op) {
case metadata_op_vic:
if (mfd->panel_info)
@@ -2043,7 +2176,7 @@
case metadata_op_crc:
if (!mfd->panel_power_on)
return -EPERM;
- ret = mdss_misr_crc_set(mdata, &metadata->data.misr_request);
+ ret = mdss_misr_set(mdata, &metadata->data.misr_request, ctl);
break;
case metadata_op_wb_format:
ret = mdss_mdp_wb_set_format(mfd,
@@ -2079,7 +2212,10 @@
struct msmfb_metadata *metadata)
{
struct mdss_data_type *mdata = mfd_to_mdata(mfd);
+ struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
int ret = 0;
+ if (!ctl)
+ return -EPERM;
switch (metadata->op) {
case metadata_op_frame_rate:
metadata->data.panel_frame_rate =
@@ -2091,7 +2227,7 @@
case metadata_op_crc:
if (!mfd->panel_power_on)
return -EPERM;
- ret = mdss_misr_crc_get(mdata, &metadata->data.misr_request);
+ ret = mdss_misr_get(mdata, &metadata->data.misr_request, ctl);
break;
case metadata_op_wb_format:
ret = mdss_mdp_wb_get_format(mfd, &metadata->data.mixer_cfg);
@@ -2111,7 +2247,7 @@
u32 cmd, void __user *argp)
{
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
- struct mdp_overlay req;
+ struct mdp_overlay *req = NULL;
int val, ret = -ENOSYS;
struct msmfb_metadata metadata;
@@ -2127,12 +2263,15 @@
break;
case MSMFB_OVERLAY_GET:
- ret = copy_from_user(&req, argp, sizeof(req));
+ req = kmalloc(sizeof(struct mdp_overlay), GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
+ ret = copy_from_user(req, argp, sizeof(*req));
if (!ret) {
- ret = mdss_mdp_overlay_get(mfd, &req);
+ ret = mdss_mdp_overlay_get(mfd, req);
if (!IS_ERR_VALUE(ret))
- ret = copy_to_user(argp, &req, sizeof(req));
+ ret = copy_to_user(argp, req, sizeof(*req));
}
if (ret)
@@ -2140,12 +2279,15 @@
break;
case MSMFB_OVERLAY_SET:
- ret = copy_from_user(&req, argp, sizeof(req));
+ req = kmalloc(sizeof(struct mdp_overlay), GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
+ ret = copy_from_user(req, argp, sizeof(*req));
if (!ret) {
- ret = mdss_mdp_overlay_set(mfd, &req);
+ ret = mdss_mdp_overlay_set(mfd, req);
if (!IS_ERR_VALUE(ret))
- ret = copy_to_user(argp, &req, sizeof(req));
+ ret = copy_to_user(argp, req, sizeof(*req));
}
if (ret)
pr_debug("OVERLAY_SET failed (%d)\n", ret);
@@ -2230,6 +2372,7 @@
break;
}
+ kfree(req);
return ret;
}
@@ -2436,9 +2579,15 @@
mdp5_data->ctl = ctl;
}
- rc = mdss_mdp_ctl_setup(ctl);
- if (rc)
+ /*
+ * vsync interrupt needs on during continuous splash, this is
+ * to initialize necessary ctl members here.
+ */
+ rc = mdss_mdp_ctl_start(ctl, true);
+ if (rc) {
+ pr_err("Failed to initialize ctl\n");
goto error;
+ }
ctl->clk_rate = mdss_mdp_get_clk_rate(MDSS_CLK_MDP_SRC);
pr_debug("Set the ctl clock rate to %d Hz\n", ctl->clk_rate);
@@ -2497,6 +2646,63 @@
return rc;
}
+static int mdss_mdp_overlay_splash_image(struct msm_fb_data_type *mfd,
+ int *pipe_ndx, int splash_event)
+{
+ struct mdp_overlay req;
+ int rc = 0;
+ struct fb_info *fbi = NULL;
+ int image_len = 0;
+
+ if (!mfd || !mfd->fbi || !mfd->fbi->screen_base || !pipe_ndx) {
+ pr_err("Invalid input parameter\n");
+ return -EINVAL;
+ }
+
+ fbi = mfd->fbi;
+ image_len = SPLASH_IMAGE_WIDTH * SPLASH_IMAGE_HEIGHT * SPLASH_IMAGE_BPP;
+
+ if (SPLASH_IMAGE_WIDTH > fbi->var.xres ||
+ SPLASH_IMAGE_HEIGHT > fbi->var.yres ||
+ SPLASH_IMAGE_BPP > fbi->var.bits_per_pixel / 8 ||
+ image_len > fbi->fix.smem_len) {
+ pr_err("Invalid splash parameter configuration\n");
+ return -EINVAL;
+ }
+
+ if (splash_event == MDP_CREATE_SPLASH_OV) {
+ pipe_ndx[0] = INVALID_PIPE_INDEX;
+ pipe_ndx[1] = INVALID_PIPE_INDEX;
+
+ memset(&req, 0, sizeof(struct mdp_overlay));
+ req.src.width = req.dst_rect.w = req.src_rect.w =
+ SPLASH_IMAGE_WIDTH;
+ req.src.height = req.dst_rect.h = req.src_rect.h =
+ SPLASH_IMAGE_HEIGHT;
+ req.src.format = SPLASH_IMAGE_FORMAT;
+ req.id = MSMFB_NEW_REQUEST;
+ req.z_order = MDSS_MDP_STAGE_0;
+ req.is_fg = 1;
+ req.alpha = 0xff;
+ req.transp_mask = MDP_TRANSP_NOP;
+ req.dst_rect.x =
+ (fbi->var.xres >> 1) - (SPLASH_IMAGE_WIDTH >> 1);
+ req.dst_rect.y =
+ (fbi->var.yres >> 1) - (SPLASH_IMAGE_HEIGHT >> 1);
+
+ memcpy(fbi->screen_base, splash_bgr888_image, image_len);
+ mdss_mdp_overlay_pan_display(mfd, &req, image_len, pipe_ndx);
+
+ } else if (splash_event == MDP_REMOVE_SPLASH_OV) {
+ if (pipe_ndx[0] != INVALID_PIPE_INDEX)
+ mdss_mdp_overlay_unset(mfd, pipe_ndx[0]);
+ if (pipe_ndx[1] != INVALID_PIPE_INDEX)
+ mdss_mdp_overlay_unset(mfd, pipe_ndx[1]);
+ }
+
+ return rc;
+}
+
int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd)
{
struct device *dev = mfd->fbi->dev;
@@ -2514,6 +2720,7 @@
mdp5_interface->panel_register_done = mdss_panel_register_done;
mdp5_interface->kickoff_fnc = mdss_mdp_overlay_kickoff;
mdp5_interface->get_sync_fnc = mdss_mdp_rotator_sync_pt_get;
+ mdp5_interface->splash_fnc = mdss_mdp_overlay_splash_image;
mdp5_data = kmalloc(sizeof(struct mdss_overlay_private), GFP_KERNEL);
if (!mdp5_data) {
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index 779f74c..0abd4d5 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -166,7 +166,7 @@
struct mdss_mdp_plane_sizes ps;
int i;
int rc = 0, rot_mode = 0;
- u32 nlines;
+ u32 nlines, format;
u16 width;
width = pipe->src.w >> pipe->horz_deci;
@@ -179,8 +179,25 @@
pr_debug("BWC SMP strides ystride0=%x ystride1=%x\n",
ps.ystride[0], ps.ystride[1]);
} else {
- rc = mdss_mdp_get_plane_sizes(pipe->src_fmt->format,
- width, pipe->src.h, &ps, 0);
+ format = pipe->src_fmt->format;
+ /*
+ * when decimation block is present, all chroma planes
+ * are fetched on a single SMP plane for chroma pixels
+ */
+ if (mdata->has_decimation) {
+ switch (pipe->src_fmt->chroma_sample) {
+ case MDSS_MDP_CHROMA_H2V1:
+ format = MDP_Y_CRCB_H2V1;
+ break;
+ case MDSS_MDP_CHROMA_420:
+ format = MDP_Y_CBCR_H2V2;
+ break;
+ default:
+ break;
+ }
+ }
+ rc = mdss_mdp_get_plane_sizes(format, width, pipe->src.h,
+ &ps, 0);
if (rc)
return rc;
@@ -191,15 +208,6 @@
max(pipe->mixer->width, width);
} else if (mdata->has_decimation) {
/*
- * when decimation block is used, all chroma planes
- * are fetched on a single SMP plane for chroma pixels
- */
- if (ps.num_planes == 3) {
- ps.num_planes = 2;
- ps.ystride[1] += ps.ystride[2];
- }
-
- /*
* To avoid quailty loss, MDP does one less decimation
* on chroma components if they are subsampled.
* Account for this to have enough SMPs for latency
@@ -581,6 +589,8 @@
mdss_mdp_smp_free(pipe);
pipe->flags = 0;
pipe->bwc_mode = 0;
+ memset(&pipe->scale, 0, sizeof(struct mdp_scale_data));
+
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
return 0;
@@ -728,24 +738,43 @@
dst = pipe->dst;
src = pipe->src;
- mdss_mdp_crop_rect(&src, &dst, &sci);
+ if (pipe->mixer->type == MDSS_MDP_MIXER_TYPE_INTF)
+ mdss_mdp_crop_rect(&src, &dst, &sci);
src_size = (src.h << 16) | src.w;
src_xy = (src.y << 16) | src.x;
dst_size = (dst.h << 16) | dst.w;
dst_xy = (dst.y << 16) | dst.x;
- img_size = (height << 16) | width;
-
ystride0 = (pipe->src_planes.ystride[0]) |
(pipe->src_planes.ystride[1] << 16);
ystride1 = (pipe->src_planes.ystride[2]) |
(pipe->src_planes.ystride[3] << 16);
- if (pipe->overfetch_disable) {
- img_size = src_size;
- src_xy = 0;
+ /*
+ * Software overfetch is used when scalar pixel extension is
+ * not enabled
+ */
+ if (pipe->overfetch_disable && !pipe->scale.enable_pxl_ext) {
+ if (pipe->overfetch_disable & OVERFETCH_DISABLE_BOTTOM) {
+ height = pipe->src.h;
+ if (!(pipe->overfetch_disable & OVERFETCH_DISABLE_TOP))
+ height += pipe->src.y;
+ }
+ if (pipe->overfetch_disable & OVERFETCH_DISABLE_RIGHT) {
+ width = pipe->src.w;
+ if (!(pipe->overfetch_disable & OVERFETCH_DISABLE_LEFT))
+ width += pipe->src.x;
+ }
+ if (pipe->overfetch_disable & OVERFETCH_DISABLE_LEFT)
+ src_xy &= ~0xFFFF;
+ if (pipe->overfetch_disable & OVERFETCH_DISABLE_TOP)
+ src_xy &= ~(0xFFFF << 16);
+
+ pr_debug("overfetch w=%d/%d h=%d/%d src_xy=0x%08x\n", width,
+ pipe->img_width, height, pipe->img_height, src_xy);
}
+ img_size = (height << 16) | width;
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_IMG_SIZE, img_size);
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_SIZE, src_size);
@@ -812,6 +841,9 @@
mdss_mdp_pipe_sspp_setup(pipe, &opmode);
+ if (pipe->scale.enable_pxl_ext)
+ opmode |= (1 << 31);
+
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_FORMAT, src_format);
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN, unpack);
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_OP_MODE, opmode);
@@ -843,33 +875,42 @@
}
static int mdss_mdp_src_addr_setup(struct mdss_mdp_pipe *pipe,
- struct mdss_mdp_data *data)
+ struct mdss_mdp_data *src_data)
{
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+ struct mdss_mdp_data data = *src_data;
int ret = 0;
pr_debug("pnum=%d\n", pipe->num);
- data->bwc_enabled = pipe->bwc_mode;
+ data.bwc_enabled = pipe->bwc_mode;
- ret = mdss_mdp_data_check(data, &pipe->src_planes);
+ ret = mdss_mdp_data_check(&data, &pipe->src_planes);
if (ret)
return ret;
- if (pipe->overfetch_disable)
- mdss_mdp_data_calc_offset(data, pipe->src.x, pipe->src.y,
+ if (pipe->overfetch_disable && !pipe->scale.enable_pxl_ext) {
+ u32 x = 0, y = 0;
+
+ if (pipe->overfetch_disable & OVERFETCH_DISABLE_LEFT)
+ x = pipe->src.x;
+ if (pipe->overfetch_disable & OVERFETCH_DISABLE_TOP)
+ y = pipe->src.y;
+
+ mdss_mdp_data_calc_offset(&data, x, y,
&pipe->src_planes, pipe->src_fmt);
+ }
/* planar format expects YCbCr, swap chroma planes if YCrCb */
if (mdata->mdp_rev < MDSS_MDP_HW_REV_102 &&
(pipe->src_fmt->fetch_planes == MDSS_MDP_PLANE_PLANAR)
&& (pipe->src_fmt->element[0] == C1_B_Cb))
- swap(data->p[1].addr, data->p[2].addr);
+ swap(data.p[1].addr, data.p[2].addr);
- mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC0_ADDR, data->p[0].addr);
- mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC1_ADDR, data->p[1].addr);
- mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC2_ADDR, data->p[2].addr);
- mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC3_ADDR, data->p[3].addr);
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC0_ADDR, data.p[0].addr);
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC1_ADDR, data.p[1].addr);
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC2_ADDR, data.p[2].addr);
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC3_ADDR, data.p[3].addr);
return 0;
}
@@ -891,6 +932,8 @@
secure = (pipe->flags & MDP_SECURE_OVERLAY_SESSION ? 0xF : 0x0);
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_FORMAT, format);
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_CONSTANT_COLOR,
+ pipe->bg_color);
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_ADDR_SW_STATUS, secure);
return 0;
@@ -900,8 +943,9 @@
struct mdss_mdp_data *src_data)
{
int ret = 0;
- u32 params_changed, opmode;
struct mdss_mdp_ctl *ctl;
+ u32 params_changed;
+ u32 opmode = 0;
if (!pipe) {
pr_err("pipe not setup properly for queue\n");
@@ -928,7 +972,8 @@
(pipe->mixer->type == MDSS_MDP_MIXER_TYPE_WRITEBACK)
&& (ctl->mdata->mixer_switched)) ||
ctl->roi_changed;
- if (src_data == NULL) {
+ if (src_data == NULL || !pipe->has_buf) {
+ pipe->params_changed = 0;
mdss_mdp_pipe_solidfill_setup(pipe);
goto update_nobuf;
}
@@ -982,3 +1027,53 @@
{
return (pipe == pipe->mixer->stage_pipe[pipe->mixer_stage]);
}
+
+static inline void __mdss_mdp_pipe_program_pixel_extn_helper(
+ struct mdss_mdp_pipe *pipe, u32 plane, u32 off)
+{
+ u32 src_h = pipe->src.h >> pipe->vert_deci;
+ u32 mask = 0xFF;
+
+ /*
+ * CB CR plane required pxls need to be accounted
+ * for chroma decimation.
+ */
+ if (plane == 1)
+ src_h >>= pipe->chroma_sample_v;
+ writel_relaxed(((pipe->scale.right_ftch[plane] & mask) << 24)|
+ ((pipe->scale.right_rpt[plane] & mask) << 16)|
+ ((pipe->scale.left_ftch[plane] & mask) << 8)|
+ (pipe->scale.left_rpt[plane] & mask), pipe->base +
+ MDSS_MDP_REG_SSPP_SW_PIX_EXT_C0_LR + off);
+ writel_relaxed(((pipe->scale.btm_ftch[plane] & mask) << 24)|
+ ((pipe->scale.btm_rpt[plane] & mask) << 16)|
+ ((pipe->scale.top_ftch[plane] & mask) << 8)|
+ (pipe->scale.top_rpt[plane] & mask), pipe->base +
+ MDSS_MDP_REG_SSPP_SW_PIX_EXT_C0_TB + off);
+ mask = 0xFFFF;
+ writel_relaxed((((src_h + pipe->scale.num_ext_pxls_top[plane] +
+ pipe->scale.num_ext_pxls_btm[plane]) & mask) << 16) |
+ ((pipe->scale.roi_w[plane] +
+ pipe->scale.num_ext_pxls_left[plane] +
+ pipe->scale.num_ext_pxls_right[plane]) & mask), pipe->base +
+ MDSS_MDP_REG_SSPP_SW_PIX_EXT_C0_REQ_PIXELS + off);
+}
+
+/**
+ * mdss_mdp_pipe_program_pixel_extn - Program the source pipe's
+ * sw pixel extension
+ * @pipe: Source pipe struct containing pixel extn values
+ *
+ * Function programs the pixel extn values calculated during
+ * scale setup.
+ */
+int mdss_mdp_pipe_program_pixel_extn(struct mdss_mdp_pipe *pipe)
+{
+ /* Y plane pixel extn */
+ __mdss_mdp_pipe_program_pixel_extn_helper(pipe, 0, 0);
+ /* CB CR plane pixel extn */
+ __mdss_mdp_pipe_program_pixel_extn_helper(pipe, 1, 16);
+ /* Alpha plane pixel extn */
+ __mdss_mdp_pipe_program_pixel_extn_helper(pipe, 3, 32);
+ return 0;
+}
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index b31f6c1..87f0779 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -173,6 +173,15 @@
GAMUT_T2_SIZE + GAMUT_T3_SIZE + GAMUT_T4_SIZE + \
GAMUT_T5_SIZE + GAMUT_T6_SIZE + GAMUT_T7_SIZE)
+#define MDSS_MDP_PA_SIZE 0xC
+#define MDSS_MDP_SIX_ZONE_SIZE 0xC
+#define MDSS_MDP_MEM_COL_SIZE 0x3C
+#define MDSS_MDP_GC_SIZE 0x28
+#define MDSS_MDP_PCC_SIZE 0xB8
+#define MDSS_MDP_GAMUT_SIZE 0x5C
+#define MDSS_MDP_IGC_DSPP_COLORS 0x3
+#define TOTAL_BLEND_STAGES 0x4
+
#define PP_FLAGS_DIRTY_PA 0x1
#define PP_FLAGS_DIRTY_PCC 0x2
#define PP_FLAGS_DIRTY_IGC 0x4
@@ -184,9 +193,31 @@
#define PP_FLAGS_DIRTY_PGC 0x100
#define PP_FLAGS_DIRTY_SHARP 0x200
+#define PP_SSPP 0
+#define PP_DSPP 1
+
#define PP_STS_ENABLE 0x1
#define PP_STS_GAMUT_FIRST 0x2
+#define PP_STS_PA_HUE_MASK 0x2
+#define PP_STS_PA_SAT_MASK 0x4
+#define PP_STS_PA_VAL_MASK 0x8
+#define PP_STS_PA_CONT_MASK 0x10
+#define PP_STS_PA_MEM_PROTECT_EN 0x20
+#define PP_STS_PA_MEM_COL_SKIN_MASK 0x40
+#define PP_STS_PA_MEM_COL_FOL_MASK 0x80
+#define PP_STS_PA_MEM_COL_SKY_MASK 0x100
+#define PP_STS_PA_SIX_ZONE_HUE_MASK 0x200
+#define PP_STS_PA_SIX_ZONE_SAT_MASK 0x400
+#define PP_STS_PA_SIX_ZONE_VAL_MASK 0x800
+#define PP_STS_PA_SAT_ZERO_EXP_EN 0x1000
+
+#define PP_AD_BAD_HW_NUM 255
+
+#define MDSS_SIDE_NONE 0
+#define MDSS_SIDE_LEFT 1
+#define MDSS_SIDE_RIGHT 2
+
#define PP_AD_STATE_INIT 0x2
#define PP_AD_STATE_CFG 0x4
#define PP_AD_STATE_DATA 0x8
@@ -205,6 +236,7 @@
#define PP_AD_STS_DIRTY_CFG 0x4
#define PP_AD_STS_DIRTY_DATA 0x8
#define PP_AD_STS_DIRTY_VSYNC 0x10
+#define PP_AD_STS_DIRTY_ENABLE 0x20
#define PP_AD_STS_IS_DIRTY(sts) (((sts) & PP_AD_STS_DIRTY_INIT) ||\
((sts) & PP_AD_STS_DIRTY_CFG))
@@ -262,6 +294,9 @@
gc_lut_b[MDSS_BLOCK_DISP_NUM][GC_LUT_SEGMENTS];
u32 enhist_lut[MDSS_BLOCK_DISP_NUM][ENHIST_LUT_ENTRIES];
struct mdp_pa_cfg pa_disp_cfg[MDSS_BLOCK_DISP_NUM];
+ struct mdp_pa_v2_data pa_v2_disp_cfg[MDSS_BLOCK_DISP_NUM];
+ u32 six_zone_lut_curve_p0[MDSS_BLOCK_DISP_NUM][MDP_SIX_ZONE_LUT_SIZE];
+ u32 six_zone_lut_curve_p1[MDSS_BLOCK_DISP_NUM][MDP_SIX_ZONE_LUT_SIZE];
struct mdp_pcc_cfg_data pcc_disp_cfg[MDSS_BLOCK_DISP_NUM];
struct mdp_igc_lut_data igc_disp_cfg[MDSS_BLOCK_DISP_NUM];
struct mdp_pgc_lut_data argc_disp_cfg[MDSS_BLOCK_DISP_NUM];
@@ -271,59 +306,98 @@
struct mdp_gamut_cfg_data gamut_disp_cfg[MDSS_BLOCK_DISP_NUM];
uint16_t gamut_tbl[MDSS_BLOCK_DISP_NUM][GAMUT_TOTAL_TABLE_SIZE];
u32 hist_data[MDSS_BLOCK_DISP_NUM][HIST_V_SIZE];
- /* physical info */
struct pp_sts_type pp_disp_sts[MDSS_BLOCK_DISP_NUM];
+ /* physical info */
struct pp_hist_col_info dspp_hist[MDSS_MDP_MAX_DSPP];
};
static DEFINE_MUTEX(mdss_pp_mutex);
static struct mdss_pp_res_type *mdss_pp_res;
-static void pp_hist_read(char __iomem *v_base,
+static u32 pp_hist_read(char __iomem *v_addr,
struct pp_hist_col_info *hist_info);
static int pp_histogram_setup(u32 *op, u32 block, struct mdss_mdp_mixer *mix);
static int pp_histogram_disable(struct pp_hist_col_info *hist_info,
u32 done_bit, char __iomem *ctl_base);
-static void pp_update_pcc_regs(u32 offset,
+static void pp_update_pcc_regs(char __iomem *addr,
struct mdp_pcc_cfg_data *cfg_ptr);
static void pp_update_igc_lut(struct mdp_igc_lut_data *cfg,
- u32 offset, u32 blk_idx);
-static void pp_update_gc_one_lut(u32 offset,
+ char __iomem *addr, u32 blk_idx);
+static void pp_update_gc_one_lut(char __iomem *addr,
struct mdp_ar_gc_lut_data *lut_data,
uint8_t num_stages);
-static void pp_update_argc_lut(u32 offset,
+static void pp_update_argc_lut(char __iomem *addr,
struct mdp_pgc_lut_data *config);
static void pp_update_hist_lut(char __iomem *base,
struct mdp_hist_lut_data *cfg);
static int pp_gm_has_invalid_lut_size(struct mdp_gamut_cfg_data *config);
static void pp_gamut_config(struct mdp_gamut_cfg_data *gamut_cfg,
- u32 base, struct pp_sts_type *pp_sts);
-static void pp_pa_config(unsigned long flags, u32 base,
+ char __iomem *base, struct pp_sts_type *pp_sts);
+static void pp_pa_config(unsigned long flags, char __iomem *addr,
struct pp_sts_type *pp_sts,
struct mdp_pa_cfg *pa_config);
-static void pp_pcc_config(unsigned long flags, u32 base,
+static void pp_pa_v2_config(unsigned long flags, char __iomem *addr,
+ struct pp_sts_type *pp_sts,
+ struct mdp_pa_v2_data *pa_v2_config,
+ int mdp_location);
+static void pp_pcc_config(unsigned long flags, char __iomem *addr,
struct pp_sts_type *pp_sts,
struct mdp_pcc_cfg_data *pcc_config);
-static void pp_igc_config(unsigned long flags, u32 base,
+static void pp_igc_config(unsigned long flags, char __iomem *addr,
struct pp_sts_type *pp_sts,
struct mdp_igc_lut_data *igc_config,
u32 pipe_num);
-static void pp_enhist_config(unsigned long flags, char __iomem *base,
+static void pp_enhist_config(unsigned long flags, char __iomem *addr,
struct pp_sts_type *pp_sts,
struct mdp_hist_lut_data *enhist_cfg);
-static void pp_sharp_config(char __iomem *offset,
+static void pp_dither_config(char __iomem *addr,
+ struct pp_sts_type *pp_sts,
+ struct mdp_dither_cfg_data *dither_cfg);
+static void pp_dspp_opmode_config(struct mdss_mdp_ctl *ctl, u32 num,
+ struct pp_sts_type *pp_sts, int mdp_rev,
+ u32 *opmode);
+static void pp_sharp_config(char __iomem *addr,
struct pp_sts_type *pp_sts,
struct mdp_sharp_cfg *sharp_config);
+static void pp_update_pa_v2_vig_opmode(struct pp_sts_type *pp_sts,
+ u32 *opmode);
+static int pp_copy_pa_six_zone_lut(struct mdp_pa_v2_cfg_data *pa_v2_config,
+ u32 disp_num);
+static void pp_update_pa_v2_global_adj_regs(char __iomem *addr,
+ struct mdp_pa_v2_data *pa_config);
+static void pp_update_pa_v2_mem_col(char __iomem *addr,
+ struct mdp_pa_v2_data *pa_v2_config);
+static void pp_update_pa_v2_mem_col_regs(char __iomem *addr,
+ struct mdp_pa_mem_col_cfg *cfg);
+static void pp_update_pa_v2_six_zone_regs(char __iomem *addr,
+ struct mdp_pa_v2_data *pa_v2_config);
+static void pp_update_pa_v2_sts(struct pp_sts_type *pp_sts,
+ struct mdp_pa_v2_data *pa_v2_config);
+static int pp_read_pa_v2_regs(char __iomem *addr,
+ struct mdp_pa_v2_data *pa_v2_config,
+ u32 disp_num);
+static void pp_read_pa_mem_col_regs(char __iomem *addr,
+ struct mdp_pa_mem_col_cfg *mem_col_cfg);
static int mdss_ad_init_checks(struct msm_fb_data_type *mfd);
static int mdss_mdp_get_ad(struct msm_fb_data_type *mfd,
struct mdss_ad_info **ad);
static int pp_update_ad_input(struct msm_fb_data_type *mfd);
static void pp_ad_vsync_handler(struct mdss_mdp_ctl *ctl, ktime_t t);
-static void pp_ad_cfg_write(struct mdss_ad_info *ad);
-static void pp_ad_init_write(struct mdss_ad_info *ad);
-static void pp_ad_input_write(struct mdss_ad_info *ad, u32 bl_lvl);
+static void pp_ad_cfg_write(struct mdss_mdp_ad *ad_hw,
+ struct mdss_ad_info *ad);
+static void pp_ad_init_write(struct mdss_mdp_ad *ad_hw,
+ struct mdss_ad_info *ad, struct mdss_mdp_ctl *ctl);
+static void pp_ad_input_write(struct mdss_mdp_ad *ad_hw,
+ struct mdss_ad_info *ad);
+static int pp_ad_setup_hw_nums(struct msm_fb_data_type *mfd,
+ struct mdss_ad_info *ad);
+static void pp_ad_bypass_config(struct mdss_ad_info *ad,
+ struct mdss_mdp_ctl *ctl, u32 num, u32 *opmode);
static int mdss_mdp_ad_setup(struct msm_fb_data_type *mfd);
-static void pp_ad_cfg_lut(char __iomem *offset, u32 *data);
+static void pp_ad_cfg_lut(char __iomem *addr, u32 *data);
+static int pp_num_to_side(struct mdss_mdp_ctl *ctl, u32 num);
+static inline bool pp_sts_is_enabled(u32 sts, int side);
+static inline void pp_sts_set_split_bits(u32 *sts, u32 bits);
static u32 last_sts, last_state;
@@ -331,7 +405,7 @@
struct mdp_csc_cfg *data)
{
int i, ret = 0;
- char __iomem *base, *off;
+ char __iomem *base, *addr;
u32 val = 0;
struct mdss_data_type *mdata;
struct mdss_mdp_pipe *pipe;
@@ -374,33 +448,33 @@
return ret;
}
- off = base + CSC_MV_OFF;
+ addr = base + CSC_MV_OFF;
for (i = 0; i < 9; i++) {
if (i & 0x1) {
val |= data->csc_mv[i] << 16;
- writel_relaxed(val, off);
- off += sizeof(u32 *);
+ writel_relaxed(val, addr);
+ addr += sizeof(u32 *);
} else {
val = data->csc_mv[i];
}
}
- writel_relaxed(val, off); /* COEFF_33 */
+ writel_relaxed(val, addr); /* COEFF_33 */
- off = base + CSC_BV_OFF;
+ addr = base + CSC_BV_OFF;
for (i = 0; i < 3; i++) {
- writel_relaxed(data->csc_pre_bv[i], off);
- writel_relaxed(data->csc_post_bv[i], off + CSC_POST_OFF);
- off += sizeof(u32 *);
+ writel_relaxed(data->csc_pre_bv[i], addr);
+ writel_relaxed(data->csc_post_bv[i], addr + CSC_POST_OFF);
+ addr += sizeof(u32 *);
}
- off = base + CSC_LV_OFF;
+ addr = base + CSC_LV_OFF;
for (i = 0; i < 6; i += 2) {
val = (data->csc_pre_lv[i] << 8) | data->csc_pre_lv[i+1];
- writel_relaxed(val, off);
+ writel_relaxed(val, addr);
val = (data->csc_post_lv[i] << 8) | data->csc_post_lv[i+1];
- writel_relaxed(val, off + CSC_POST_OFF);
- off += sizeof(u32 *);
+ writel_relaxed(val, addr + CSC_POST_OFF);
+ addr += sizeof(u32 *);
}
return ret;
@@ -423,29 +497,29 @@
}
static void pp_gamut_config(struct mdp_gamut_cfg_data *gamut_cfg,
- u32 base, struct pp_sts_type *pp_sts)
+ char __iomem *base, struct pp_sts_type *pp_sts)
{
- u32 offset;
+ char __iomem *addr;
int i, j;
if (gamut_cfg->flags & MDP_PP_OPS_WRITE) {
- offset = base + MDSS_MDP_REG_DSPP_GAMUT_BASE;
+ addr = base + MDSS_MDP_REG_DSPP_GAMUT_BASE;
for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
for (j = 0; j < gamut_cfg->tbl_size[i]; j++)
- MDSS_MDP_REG_WRITE(offset,
- (u32)gamut_cfg->r_tbl[i][j]);
- offset += 4;
+ writel_relaxed((u32)gamut_cfg->r_tbl[i][j],
+ addr);
+ addr += 4;
}
for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
for (j = 0; j < gamut_cfg->tbl_size[i]; j++)
- MDSS_MDP_REG_WRITE(offset,
- (u32)gamut_cfg->g_tbl[i][j]);
- offset += 4;
+ writel_relaxed((u32)gamut_cfg->g_tbl[i][j],
+ addr);
+ addr += 4;
}
for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
for (j = 0; j < gamut_cfg->tbl_size[i]; j++)
- MDSS_MDP_REG_WRITE(offset,
- (u32)gamut_cfg->b_tbl[i][j]);
- offset += 4;
+ writel_relaxed((u32)gamut_cfg->b_tbl[i][j],
+ addr);
+ addr += 4;
}
if (gamut_cfg->gamut_first)
pp_sts->gamut_sts |= PP_STS_GAMUT_FIRST;
@@ -455,21 +529,22 @@
pp_sts->gamut_sts &= ~PP_STS_ENABLE;
else if (gamut_cfg->flags & MDP_PP_OPS_ENABLE)
pp_sts->gamut_sts |= PP_STS_ENABLE;
+ pp_sts_set_split_bits(&pp_sts->gamut_sts, gamut_cfg->flags);
}
-static void pp_pa_config(unsigned long flags, u32 base,
+static void pp_pa_config(unsigned long flags, char __iomem *addr,
struct pp_sts_type *pp_sts,
struct mdp_pa_cfg *pa_config)
{
if (flags & PP_FLAGS_DIRTY_PA) {
if (pa_config->flags & MDP_PP_OPS_WRITE) {
- MDSS_MDP_REG_WRITE(base, pa_config->hue_adj);
- base += 4;
- MDSS_MDP_REG_WRITE(base, pa_config->sat_adj);
- base += 4;
- MDSS_MDP_REG_WRITE(base, pa_config->val_adj);
- base += 4;
- MDSS_MDP_REG_WRITE(base, pa_config->cont_adj);
+ writel_relaxed(pa_config->hue_adj, addr);
+ addr += 4;
+ writel_relaxed(pa_config->sat_adj, addr);
+ addr += 4;
+ writel_relaxed(pa_config->val_adj, addr);
+ addr += 4;
+ writel_relaxed(pa_config->cont_adj, addr);
}
if (pa_config->flags & MDP_PP_OPS_DISABLE)
pp_sts->pa_sts &= ~PP_STS_ENABLE;
@@ -478,22 +553,171 @@
}
}
-static void pp_pcc_config(unsigned long flags, u32 base,
+static void pp_pa_v2_config(unsigned long flags, char __iomem *addr,
+ struct pp_sts_type *pp_sts,
+ struct mdp_pa_v2_data *pa_v2_config,
+ int mdp_location)
+{
+ if ((flags & PP_FLAGS_DIRTY_PA) &&
+ (pa_v2_config->flags & MDP_PP_OPS_WRITE)) {
+ pp_update_pa_v2_global_adj_regs(addr,
+ pa_v2_config);
+ /* Update PA DSPP Regs */
+ if (mdp_location == PP_DSPP) {
+ addr += 0x10;
+ pp_update_pa_v2_six_zone_regs(addr, pa_v2_config);
+ addr += 0xC;
+ pp_update_pa_v2_mem_col(addr, pa_v2_config);
+ } else if (mdp_location == PP_SSPP) { /* Update PA SSPP Regs */
+ addr -= MDSS_MDP_REG_VIG_PA_BASE;
+ addr += MDSS_MDP_REG_VIG_MEM_COL_BASE;
+ pp_update_pa_v2_mem_col(addr, pa_v2_config);
+ }
+ pp_update_pa_v2_sts(pp_sts, pa_v2_config);
+ }
+}
+
+static void pp_update_pa_v2_global_adj_regs(char __iomem *addr,
+ struct mdp_pa_v2_data *pa_v2_config)
+{
+ if (pa_v2_config->flags & MDP_PP_PA_HUE_ENABLE)
+ writel_relaxed(pa_v2_config->global_hue_adj, addr);
+ addr += 4;
+ if (pa_v2_config->flags & MDP_PP_PA_SAT_ENABLE)
+ /* Sat Global Adjust reg includes Sat Threshold */
+ writel_relaxed(pa_v2_config->global_sat_adj, addr);
+ addr += 4;
+ if (pa_v2_config->flags & MDP_PP_PA_VAL_ENABLE)
+ writel_relaxed(pa_v2_config->global_val_adj, addr);
+ addr += 4;
+ if (pa_v2_config->flags & MDP_PP_PA_CONT_ENABLE)
+ writel_relaxed(pa_v2_config->global_cont_adj, addr);
+}
+
+static void pp_update_pa_v2_mem_col(char __iomem *addr,
+ struct mdp_pa_v2_data *pa_v2_config)
+{
+ /* Update skin zone memory color registers */
+ if (pa_v2_config->flags & MDP_PP_PA_SKIN_ENABLE)
+ pp_update_pa_v2_mem_col_regs(addr, &pa_v2_config->skin_cfg);
+ addr += 0x14;
+ /* Update sky zone memory color registers */
+ if (pa_v2_config->flags & MDP_PP_PA_SKY_ENABLE)
+ pp_update_pa_v2_mem_col_regs(addr, &pa_v2_config->sky_cfg);
+ addr += 0x14;
+ /* Update foliage zone memory color registers */
+ if (pa_v2_config->flags & MDP_PP_PA_FOL_ENABLE)
+ pp_update_pa_v2_mem_col_regs(addr, &pa_v2_config->fol_cfg);
+}
+
+static void pp_update_pa_v2_mem_col_regs(char __iomem *addr,
+ struct mdp_pa_mem_col_cfg *cfg)
+{
+ pr_debug("ADDR: 0x%x, P0: 0x%x\n", (u32)addr, cfg->color_adjust_p0);
+ writel_relaxed(cfg->color_adjust_p0, addr);
+ addr += 4;
+ pr_debug("ADDR: 0x%x, P1: 0x%x\n", (u32)addr, cfg->color_adjust_p1);
+ writel_relaxed(cfg->color_adjust_p1, addr);
+ addr += 4;
+ pr_debug("ADDR: 0x%x, HUE REGION: 0x%x\n", (u32)addr, cfg->hue_region);
+ writel_relaxed(cfg->hue_region, addr);
+ addr += 4;
+ pr_debug("ADDR: 0x%x, SAT REGION: 0x%x\n", (u32)addr, cfg->sat_region);
+ writel_relaxed(cfg->sat_region, addr);
+ addr += 4;
+ pr_debug("ADDR: 0x%x, VAL REGION: 0x%x\n", (u32)addr, cfg->val_region);
+ writel_relaxed(cfg->val_region, addr);
+}
+
+static void pp_update_pa_v2_six_zone_regs(char __iomem *addr,
+ struct mdp_pa_v2_data *pa_v2_config)
+{
+ int i;
+ u32 data;
+ /* Update six zone memory color registers */
+ if (pa_v2_config->flags & MDP_PP_PA_SIX_ZONE_ENABLE) {
+ addr += 4;
+ writel_relaxed(pa_v2_config->six_zone_curve_p1[0], addr);
+ addr -= 4;
+ /* Index Update to trigger auto-incrementing LUT accesses */
+ data = (1 << 26);
+ writel_relaxed((pa_v2_config->six_zone_curve_p0[0] & 0xFFF) |
+ data, addr);
+
+ /* Remove Index Update */
+ for (i = 1; i < MDP_SIX_ZONE_LUT_SIZE; i++) {
+ addr += 4;
+ writel_relaxed(pa_v2_config->six_zone_curve_p1[i],
+ addr);
+ addr -= 4;
+ writel_relaxed(pa_v2_config->six_zone_curve_p0[i] &
+ 0xFFF, addr);
+ }
+ addr += 8;
+ writel_relaxed(pa_v2_config->six_zone_thresh, addr);
+ }
+}
+
+static void pp_update_pa_v2_sts(struct pp_sts_type *pp_sts,
+ struct mdp_pa_v2_data *pa_v2_config)
+{
+ pp_sts->pa_sts = 0;
+ /* PA STS update */
+ if (pa_v2_config->flags & MDP_PP_OPS_ENABLE)
+ pp_sts->pa_sts |= PP_STS_ENABLE;
+ else
+ pp_sts->pa_sts &= ~PP_STS_ENABLE;
+
+ /* Global HSV STS update */
+ if (pa_v2_config->flags & MDP_PP_PA_HUE_MASK)
+ pp_sts->pa_sts |= PP_STS_PA_HUE_MASK;
+ if (pa_v2_config->flags & MDP_PP_PA_SAT_MASK)
+ pp_sts->pa_sts |= PP_STS_PA_SAT_MASK;
+ if (pa_v2_config->flags & MDP_PP_PA_VAL_MASK)
+ pp_sts->pa_sts |= PP_STS_PA_VAL_MASK;
+ if (pa_v2_config->flags & MDP_PP_PA_CONT_MASK)
+ pp_sts->pa_sts |= PP_STS_PA_CONT_MASK;
+ if (pa_v2_config->flags & MDP_PP_PA_MEM_PROTECT_EN)
+ pp_sts->pa_sts |= PP_STS_PA_MEM_PROTECT_EN;
+ if (pa_v2_config->flags & MDP_PP_PA_SAT_ZERO_EXP_EN)
+ pp_sts->pa_sts |= PP_STS_PA_SAT_ZERO_EXP_EN;
+
+ /* Memory Color STS update */
+ if (pa_v2_config->flags & MDP_PP_PA_MEM_COL_SKIN_MASK)
+ pp_sts->pa_sts |= PP_STS_PA_MEM_COL_SKIN_MASK;
+ if (pa_v2_config->flags & MDP_PP_PA_MEM_COL_SKY_MASK)
+ pp_sts->pa_sts |= PP_STS_PA_MEM_COL_SKY_MASK;
+ if (pa_v2_config->flags & MDP_PP_PA_MEM_COL_FOL_MASK)
+ pp_sts->pa_sts |= PP_STS_PA_MEM_COL_FOL_MASK;
+
+ /* Six Zone STS update */
+ if (pa_v2_config->flags & MDP_PP_PA_SIX_ZONE_HUE_MASK)
+ pp_sts->pa_sts |= PP_STS_PA_SIX_ZONE_HUE_MASK;
+ if (pa_v2_config->flags & MDP_PP_PA_SIX_ZONE_SAT_MASK)
+ pp_sts->pa_sts |= PP_STS_PA_SIX_ZONE_SAT_MASK;
+ if (pa_v2_config->flags & MDP_PP_PA_SIX_ZONE_VAL_MASK)
+ pp_sts->pa_sts |= PP_STS_PA_SIX_ZONE_VAL_MASK;
+
+ pp_sts_set_split_bits(&pp_sts->pa_sts, pa_v2_config->flags);
+}
+
+static void pp_pcc_config(unsigned long flags, char __iomem *addr,
struct pp_sts_type *pp_sts,
struct mdp_pcc_cfg_data *pcc_config)
{
if (flags & PP_FLAGS_DIRTY_PCC) {
if (pcc_config->ops & MDP_PP_OPS_WRITE)
- pp_update_pcc_regs(base, pcc_config);
+ pp_update_pcc_regs(addr, pcc_config);
if (pcc_config->ops & MDP_PP_OPS_DISABLE)
pp_sts->pcc_sts &= ~PP_STS_ENABLE;
else if (pcc_config->ops & MDP_PP_OPS_ENABLE)
pp_sts->pcc_sts |= PP_STS_ENABLE;
+ pp_sts_set_split_bits(&pp_sts->pcc_sts, pcc_config->ops);
}
}
-static void pp_igc_config(unsigned long flags, u32 base,
+static void pp_igc_config(unsigned long flags, char __iomem *addr,
struct pp_sts_type *pp_sts,
struct mdp_igc_lut_data *igc_config,
u32 pipe_num)
@@ -501,7 +725,7 @@
u32 tbl_idx;
if (flags & PP_FLAGS_DIRTY_IGC) {
if (igc_config->ops & MDP_PP_OPS_WRITE)
- pp_update_igc_lut(igc_config, base, pipe_num);
+ pp_update_igc_lut(igc_config, addr, pipe_num);
if (igc_config->ops & MDP_PP_IGC_FLAG_ROM0) {
pp_sts->pcc_sts |= PP_STS_ENABLE;
@@ -517,16 +741,17 @@
pp_sts->igc_sts &= ~PP_STS_ENABLE;
else if (igc_config->ops & MDP_PP_OPS_ENABLE)
pp_sts->igc_sts |= PP_STS_ENABLE;
+ pp_sts_set_split_bits(&pp_sts->igc_sts, igc_config->ops);
}
}
-static void pp_enhist_config(unsigned long flags, char __iomem *base,
+static void pp_enhist_config(unsigned long flags, char __iomem *addr,
struct pp_sts_type *pp_sts,
struct mdp_hist_lut_data *enhist_cfg)
{
if (flags & PP_FLAGS_DIRTY_ENHIST) {
if (enhist_cfg->ops & MDP_PP_OPS_WRITE)
- pp_update_hist_lut(base, enhist_cfg);
+ pp_update_hist_lut(addr, enhist_cfg);
if (enhist_cfg->ops & MDP_PP_OPS_DISABLE)
pp_sts->enhist_sts &= ~PP_STS_ENABLE;
@@ -536,18 +761,18 @@
}
/*the below function doesn't do error checking on the input params*/
-static void pp_sharp_config(char __iomem *base,
+static void pp_sharp_config(char __iomem *addr,
struct pp_sts_type *pp_sts,
struct mdp_sharp_cfg *sharp_config)
{
if (sharp_config->flags & MDP_PP_OPS_WRITE) {
- writel_relaxed(sharp_config->strength, base);
- base += 4;
- writel_relaxed(sharp_config->edge_thr, base);
- base += 4;
- writel_relaxed(sharp_config->smooth_thr, base);
- base += 4;
- writel_relaxed(sharp_config->noise_thr, base);
+ writel_relaxed(sharp_config->strength, addr);
+ addr += 4;
+ writel_relaxed(sharp_config->edge_thr, addr);
+ addr += 4;
+ writel_relaxed(sharp_config->smooth_thr, addr);
+ addr += 4;
+ writel_relaxed(sharp_config->noise_thr, addr);
}
if (sharp_config->flags & MDP_PP_OPS_DISABLE)
pp_sts->sharp_sts &= ~PP_STS_ENABLE;
@@ -558,12 +783,14 @@
static int pp_vig_pipe_setup(struct mdss_mdp_pipe *pipe, u32 *op)
{
- u32 opmode = 0, base = 0;
+ u32 opmode = 0;
unsigned long flags = 0;
char __iomem *offset;
+ struct mdss_data_type *mdata;
pr_debug("pnum=%x\n", pipe->num);
+ mdata = mdss_mdp_get_mdata();
if ((pipe->flags & MDP_OVERLAY_PP_CFG_EN) &&
(pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_CSC_CFG)) {
opmode |= !!(pipe->pp_cfg.csc_cfg.flags &
@@ -597,15 +824,30 @@
pp_histogram_setup(&opmode, MDSS_PP_SSPP_CFG | pipe->num, pipe->mixer);
if (pipe->flags & MDP_OVERLAY_PP_CFG_EN) {
- if (pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_PA_CFG) {
+ if ((pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_PA_CFG) &&
+ (mdata->mdp_rev < MDSS_MDP_HW_REV_103)) {
flags = PP_FLAGS_DIRTY_PA;
- base = MDSS_MDP_REG_SSPP_OFFSET(pipe->num) +
- MDSS_MDP_REG_VIG_PA_BASE;
- pp_pa_config(flags, base, &pipe->pp_res.pp_sts,
- &pipe->pp_cfg.pa_cfg);
+ pp_pa_config(flags,
+ pipe->base + MDSS_MDP_REG_VIG_PA_BASE,
+ &pipe->pp_res.pp_sts,
+ &pipe->pp_cfg.pa_cfg);
if (pipe->pp_res.pp_sts.pa_sts & PP_STS_ENABLE)
- opmode |= (1 << 4); /* PA_EN */
+ opmode |= MDSS_MDP_VIG_OP_PA_EN;
+ }
+ if ((pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_PA_V2_CFG) &&
+ (mdata->mdp_rev >= MDSS_MDP_HW_REV_103)) {
+ flags = PP_FLAGS_DIRTY_PA;
+ pp_pa_v2_config(flags,
+ pipe->base + MDSS_MDP_REG_VIG_PA_BASE,
+ &pipe->pp_res.pp_sts,
+ &pipe->pp_cfg.pa_v2_cfg,
+ PP_SSPP);
+ pp_update_pa_v2_vig_opmode(&pipe->pp_res.pp_sts,
+ &opmode);
+
+ if (pipe->pp_res.pp_sts.pa_sts & PP_STS_ENABLE)
+ opmode |= MDSS_MDP_VIG_OP_PA_EN;
}
if (pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_HIST_LUT_CFG) {
@@ -629,20 +871,46 @@
}
}
- *op = opmode;
+ *op |= opmode;
return 0;
}
+static void pp_update_pa_v2_vig_opmode(struct pp_sts_type *pp_sts,
+ u32 *opmode)
+{
+ if (pp_sts->pa_sts & PP_STS_PA_HUE_MASK)
+ *opmode |= MDSS_MDP_VIG_OP_PA_HUE_MASK;
+ if (pp_sts->pa_sts & PP_STS_PA_SAT_MASK)
+ *opmode |= MDSS_MDP_VIG_OP_PA_SAT_MASK;
+ if (pp_sts->pa_sts & PP_STS_PA_VAL_MASK)
+ *opmode |= MDSS_MDP_VIG_OP_PA_VAL_MASK;
+ if (pp_sts->pa_sts & PP_STS_PA_CONT_MASK)
+ *opmode |= MDSS_MDP_VIG_OP_PA_CONT_MASK;
+ if (pp_sts->pa_sts & PP_STS_PA_MEM_PROTECT_EN)
+ *opmode |= MDSS_MDP_VIG_OP_PA_MEM_PROTECT_EN;
+ if (pp_sts->pa_sts & PP_STS_PA_SAT_ZERO_EXP_EN)
+ *opmode |= MDSS_MDP_VIG_OP_PA_SAT_ZERO_EXP_EN;
+ if (pp_sts->pa_sts & PP_STS_PA_MEM_COL_SKIN_MASK)
+ *opmode |= MDSS_MDP_VIG_OP_PA_MEM_COL_SKIN_MASK;
+ if (pp_sts->pa_sts & PP_STS_PA_MEM_COL_SKY_MASK)
+ *opmode |= MDSS_MDP_VIG_OP_PA_MEM_COL_SKY_MASK;
+ if (pp_sts->pa_sts & PP_STS_PA_MEM_COL_FOL_MASK)
+ *opmode |= MDSS_MDP_VIG_OP_PA_MEM_COL_FOL_MASK;
+}
+
static int mdss_mdp_scale_setup(struct mdss_mdp_pipe *pipe)
{
u32 scale_config = 0;
- u32 phasex_step = 0, phasey_step = 0;
+ int init_phasex = 0, init_phasey = 0;
+ int phasex_step = 0, phasey_step = 0;
u32 chroma_sample;
u32 filter_mode;
struct mdss_data_type *mdata;
u32 src_w, src_h;
+ pr_debug("pipe=%d, change pxl ext=%d\n", pipe->num,
+ pipe->scale.enable_pxl_ext);
mdata = mdss_mdp_get_mdata();
if (mdata->mdp_rev >= MDSS_MDP_HW_REV_102 && pipe->src_fmt->is_yuv)
filter_mode = MDSS_MDP_SCALE_FILTER_CA;
@@ -689,7 +957,8 @@
if ((src_h != pipe->dst.h) ||
(pipe->pp_res.pp_sts.sharp_sts & PP_STS_ENABLE) ||
(chroma_sample == MDSS_MDP_CHROMA_420) ||
- (chroma_sample == MDSS_MDP_CHROMA_H1V2)) {
+ (chroma_sample == MDSS_MDP_CHROMA_H1V2) ||
+ pipe->scale.enable_pxl_ext) {
pr_debug("scale y - src_h=%d dst_h=%d\n", src_h, pipe->dst.h);
if ((src_h / MAX_DOWNSCALE_RATIO) > pipe->dst.h) {
@@ -699,7 +968,8 @@
}
scale_config |= MDSS_MDP_SCALEY_EN;
- phasey_step = pipe->phase_step_y;
+ phasey_step = pipe->scale.phase_step_y[0];
+ init_phasey = pipe->scale.init_phase_y[0];
if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG) {
u32 chroma_shift = 0;
@@ -708,11 +978,11 @@
(chroma_sample == MDSS_MDP_CHROMA_H1V2)))
chroma_shift = 1; /* 2x upsample chroma */
- if (src_h <= pipe->dst.h) {
+ if (src_h <= pipe->dst.h)
scale_config |= /* G/Y, A */
(filter_mode << 10) |
(MDSS_MDP_SCALE_FILTER_BIL << 18);
- } else
+ else
scale_config |= /* G/Y, A */
(MDSS_MDP_SCALE_FILTER_PCMN << 10) |
(MDSS_MDP_SCALE_FILTER_PCMN << 18);
@@ -724,6 +994,8 @@
scale_config |= /* CrCb */
(MDSS_MDP_SCALE_FILTER_PCMN << 14);
+ writel_relaxed(init_phasey, pipe->base +
+ MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEY);
writel_relaxed(phasey_step >> chroma_shift, pipe->base +
MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPY);
} else {
@@ -741,7 +1013,8 @@
if ((src_w != pipe->dst.w) ||
(pipe->pp_res.pp_sts.sharp_sts & PP_STS_ENABLE) ||
(chroma_sample == MDSS_MDP_CHROMA_420) ||
- (chroma_sample == MDSS_MDP_CHROMA_H2V1)) {
+ (chroma_sample == MDSS_MDP_CHROMA_H2V1) ||
+ pipe->scale.enable_pxl_ext) {
pr_debug("scale x - src_w=%d dst_w=%d\n", src_w, pipe->dst.w);
if ((src_w / MAX_DOWNSCALE_RATIO) > pipe->dst.w) {
@@ -751,7 +1024,8 @@
}
scale_config |= MDSS_MDP_SCALEX_EN;
- phasex_step = pipe->phase_step_x;
+ init_phasex = pipe->scale.init_phase_x[0];
+ phasex_step = pipe->scale.phase_step_x[0];
if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG) {
u32 chroma_shift = 0;
@@ -761,11 +1035,11 @@
(chroma_sample == MDSS_MDP_CHROMA_H2V1)))
chroma_shift = 1; /* 2x upsample chroma */
- if (src_w <= pipe->dst.w) {
+ if (src_w <= pipe->dst.w)
scale_config |= /* G/Y, A */
(filter_mode << 8) |
(MDSS_MDP_SCALE_FILTER_BIL << 16);
- } else
+ else
scale_config |= /* G/Y, A */
(MDSS_MDP_SCALE_FILTER_PCMN << 8) |
(MDSS_MDP_SCALE_FILTER_PCMN << 16);
@@ -777,6 +1051,8 @@
scale_config |= /* CrCb */
(MDSS_MDP_SCALE_FILTER_PCMN << 12);
+ writel_relaxed(init_phasex, pipe->base +
+ MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEX);
writel_relaxed(phasex_step >> chroma_shift, pipe->base +
MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPX);
} else {
@@ -791,12 +1067,49 @@
}
}
+ if (pipe->scale.enable_pxl_ext &&
+ pipe->type == MDSS_MDP_PIPE_TYPE_VIG) {
+
+ /*program x,y initial phase and phase step*/
+ writel_relaxed(pipe->scale.init_phase_x[0],
+ pipe->base + MDSS_MDP_REG_VIG_QSEED2_C03_INIT_PHASEX);
+ writel_relaxed(pipe->scale.phase_step_x[0],
+ pipe->base + MDSS_MDP_REG_VIG_QSEED2_C03_PHASESTEPX);
+ writel_relaxed(pipe->scale.init_phase_x[1],
+ pipe->base + MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEX);
+ writel_relaxed(pipe->scale.phase_step_x[1],
+ pipe->base + MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPX);
+
+ writel_relaxed(pipe->scale.init_phase_y[0],
+ pipe->base + MDSS_MDP_REG_VIG_QSEED2_C03_INIT_PHASEY);
+ writel_relaxed(pipe->scale.phase_step_y[0],
+ pipe->base + MDSS_MDP_REG_VIG_QSEED2_C03_PHASESTEPY);
+ writel_relaxed(pipe->scale.init_phase_y[1],
+ pipe->base + MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEY);
+ writel_relaxed(pipe->scale.phase_step_y[1],
+ pipe->base + MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPY);
+
+ /*program pixel extn values for the SSPP*/
+ mdss_mdp_pipe_program_pixel_extn(pipe);
+ } else if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG) {
+ writel_relaxed(phasex_step, pipe->base +
+ MDSS_MDP_REG_SCALE_PHASE_STEP_X);
+ writel_relaxed(phasey_step, pipe->base +
+ MDSS_MDP_REG_SCALE_PHASE_STEP_Y);
+ writel_relaxed(init_phasex, pipe->base +
+ MDSS_MDP_REG_SCALE_INIT_PHASE_X);
+ writel_relaxed(init_phasey, pipe->base +
+ MDSS_MDP_REG_SCALE_INIT_PHASE_Y);
+ } else {
+ writel_relaxed(phasex_step, pipe->base +
+ MDSS_MDP_REG_SCALE_PHASE_STEP_X);
+ writel_relaxed(phasey_step, pipe->base +
+ MDSS_MDP_REG_SCALE_PHASE_STEP_Y);
+ }
+
writel_relaxed(scale_config, pipe->base +
MDSS_MDP_REG_SCALE_CONFIG);
- writel_relaxed(phasex_step, pipe->base +
- MDSS_MDP_REG_SCALE_PHASE_STEP_X);
- writel_relaxed(phasey_step, pipe->base +
- MDSS_MDP_REG_SCALE_PHASE_STEP_Y);
+
return 0;
}
@@ -837,8 +1150,9 @@
{
int ret = 0;
unsigned long flags = 0;
- u32 pipe_base;
+ char __iomem *pipe_base;
u32 pipe_num;
+ struct mdss_data_type *mdata = mdss_mdp_get_mdata();
if (pipe == NULL)
return -EINVAL;
@@ -850,15 +1164,15 @@
*/
switch (pipe->type) {
case MDSS_MDP_PIPE_TYPE_VIG:
- pipe_base = MDSS_MDP_REG_IGC_VIG_BASE;
+ pipe_base = mdata->mdp_base + MDSS_MDP_REG_IGC_VIG_BASE;
pipe_num = pipe->num - MDSS_MDP_SSPP_VIG0;
break;
case MDSS_MDP_PIPE_TYPE_RGB:
- pipe_base = MDSS_MDP_REG_IGC_RGB_BASE;
+ pipe_base = mdata->mdp_base + MDSS_MDP_REG_IGC_RGB_BASE;
pipe_num = pipe->num - MDSS_MDP_SSPP_RGB0;
break;
case MDSS_MDP_PIPE_TYPE_DMA:
- pipe_base = MDSS_MDP_REG_IGC_DMA_BASE;
+ pipe_base = mdata->mdp_base + MDSS_MDP_REG_IGC_DMA_BASE;
pipe_num = pipe->num - MDSS_MDP_SSPP_DMA0;
break;
default:
@@ -880,10 +1194,11 @@
static int pp_mixer_setup(u32 disp_num,
struct mdss_mdp_mixer *mixer)
{
- u32 flags, offset, dspp_num, opmode = 0;
+ u32 flags, dspp_num, opmode = 0;
struct mdp_pgc_lut_data *pgc_config;
struct pp_sts_type *pp_sts;
struct mdss_mdp_ctl *ctl;
+ char __iomem *addr;
dspp_num = mixer->num;
if (!mixer || !mixer->ctl)
@@ -904,9 +1219,9 @@
if (flags & PP_FLAGS_DIRTY_ARGC) {
pgc_config = &mdss_pp_res->argc_disp_cfg[disp_num];
if (pgc_config->flags & MDP_PP_OPS_WRITE) {
- offset = MDSS_MDP_REG_LM_OFFSET(disp_num) +
+ addr = mixer->base +
MDSS_MDP_REG_LM_GC_LUT_BASE;
- pp_update_argc_lut(offset, pgc_config);
+ pp_update_argc_lut(addr, pgc_config);
}
if (pgc_config->flags & MDP_PP_OPS_DISABLE)
pp_sts->argc_sts &= ~PP_STS_ENABLE;
@@ -917,15 +1232,28 @@
/* update LM opmode if LM needs flush */
if ((pp_sts->argc_sts & PP_STS_ENABLE) &&
(ctl->flush_bits & (BIT(6) << dspp_num))) {
- offset = MDSS_MDP_REG_LM_OFFSET(dspp_num) +
- MDSS_MDP_REG_LM_OP_MODE;
- opmode = MDSS_MDP_REG_READ(offset);
+ addr = mixer->base + MDSS_MDP_REG_LM_OP_MODE;
+ opmode = readl_relaxed(addr);
opmode |= (1 << 0); /* GC_LUT_EN */
- MDSS_MDP_REG_WRITE(offset, opmode);
+ writel_relaxed(opmode, addr);
}
return 0;
}
+static char __iomem *mdss_mdp_get_mixer_addr_off(u32 dspp_num)
+{
+ struct mdss_data_type *mdata;
+ struct mdss_mdp_mixer *mixer;
+
+ mdata = mdss_mdp_get_mdata();
+ if (mdata->nmixers_intf <= dspp_num) {
+ pr_err("Invalid dspp_num=%d", dspp_num);
+ return ERR_PTR(-EINVAL);
+ }
+ mixer = mdata->mixer_intf + dspp_num;
+ return mixer->base;
+}
+
static char __iomem *mdss_mdp_get_dspp_addr_off(u32 dspp_num)
{
struct mdss_data_type *mdata;
@@ -981,10 +1309,7 @@
mutex_lock(&hist_info->hist_mutex);
spin_lock_irqsave(&hist_info->hist_lock, flag);
col_state = hist_info->col_state;
- if (hist_info->is_kick_ready &&
- ((col_state == HIST_IDLE) ||
- ((false == hist_info->read_request) &&
- col_state == HIST_READY))) {
+ if (col_state == HIST_IDLE) {
/* Kick off collection */
writel_relaxed(1, base + kick_base);
hist_info->col_state = HIST_START;
@@ -997,16 +1322,105 @@
return ret;
}
+static void pp_dither_config(char __iomem *addr,
+ struct pp_sts_type *pp_sts,
+ struct mdp_dither_cfg_data *dither_cfg)
+{
+ u32 data;
+ int i;
+
+ if (dither_cfg->flags & MDP_PP_OPS_WRITE) {
+ data = dither_depth_map[dither_cfg->g_y_depth];
+ data |= dither_depth_map[dither_cfg->b_cb_depth] << 2;
+ data |= dither_depth_map[dither_cfg->r_cr_depth] << 4;
+ writel_relaxed(data, addr);
+ addr += 0x14;
+ for (i = 0; i < 16; i += 4) {
+ data = dither_matrix[i] |
+ (dither_matrix[i + 1] << 4) |
+ (dither_matrix[i + 2] << 8) |
+ (dither_matrix[i + 3] << 12);
+ writel_relaxed(data, addr);
+ addr += 4;
+ }
+ }
+ if (dither_cfg->flags & MDP_PP_OPS_DISABLE)
+ pp_sts->dither_sts &= ~PP_STS_ENABLE;
+ else if (dither_cfg->flags & MDP_PP_OPS_ENABLE)
+ pp_sts->dither_sts |= PP_STS_ENABLE;
+ pp_sts_set_split_bits(&pp_sts->dither_sts, dither_cfg->flags);
+}
+
+static void pp_dspp_opmode_config(struct mdss_mdp_ctl *ctl, u32 num,
+ struct pp_sts_type *pp_sts, int mdp_rev,
+ u32 *opmode)
+{
+ int side;
+ side = pp_num_to_side(ctl, num);
+
+ if (side < 0)
+ return;
+
+ if (pp_sts_is_enabled(pp_sts->pa_sts, side))
+ *opmode |= MDSS_MDP_DSPP_OP_PA_EN; /* PA_EN */
+ if (mdp_rev >= MDSS_MDP_HW_REV_103) {
+ if (pp_sts->pa_sts & PP_STS_PA_HUE_MASK)
+ *opmode |= MDSS_MDP_DSPP_OP_PA_HUE_MASK;
+ if (pp_sts->pa_sts & PP_STS_PA_SAT_MASK)
+ *opmode |= MDSS_MDP_DSPP_OP_PA_SAT_MASK;
+ if (pp_sts->pa_sts & PP_STS_PA_VAL_MASK)
+ *opmode |= MDSS_MDP_DSPP_OP_PA_VAL_MASK;
+ if (pp_sts->pa_sts & PP_STS_PA_CONT_MASK)
+ *opmode |= MDSS_MDP_DSPP_OP_PA_CONT_MASK;
+ if (pp_sts->pa_sts & PP_STS_PA_MEM_PROTECT_EN)
+ *opmode |= MDSS_MDP_DSPP_OP_PA_MEM_PROTECT_EN;
+ if (pp_sts->pa_sts & PP_STS_PA_SAT_ZERO_EXP_EN)
+ *opmode |= MDSS_MDP_DSPP_OP_PA_SAT_ZERO_EXP_EN;
+ if (pp_sts->pa_sts & PP_STS_PA_MEM_COL_SKIN_MASK)
+ *opmode |= MDSS_MDP_DSPP_OP_PA_MEM_COL_SKIN_MASK;
+ if (pp_sts->pa_sts & PP_STS_PA_MEM_COL_FOL_MASK)
+ *opmode |= MDSS_MDP_DSPP_OP_PA_MEM_COL_FOL_MASK;
+ if (pp_sts->pa_sts & PP_STS_PA_MEM_COL_SKY_MASK)
+ *opmode |= MDSS_MDP_DSPP_OP_PA_MEM_COL_SKY_MASK;
+ if (pp_sts->pa_sts & PP_STS_PA_SIX_ZONE_HUE_MASK)
+ *opmode |= MDSS_MDP_DSPP_OP_PA_SIX_ZONE_HUE_MASK;
+ if (pp_sts->pa_sts & PP_STS_PA_SIX_ZONE_SAT_MASK)
+ *opmode |= MDSS_MDP_DSPP_OP_PA_SIX_ZONE_SAT_MASK;
+ if (pp_sts->pa_sts & PP_STS_PA_SIX_ZONE_VAL_MASK)
+ *opmode |= MDSS_MDP_DSPP_OP_PA_SIX_ZONE_VAL_MASK;
+ }
+ if (pp_sts_is_enabled(pp_sts->pcc_sts, side))
+ *opmode |= MDSS_MDP_DSPP_OP_PCC_EN; /* PCC_EN */
+
+ if (pp_sts_is_enabled(pp_sts->igc_sts, side)) {
+ *opmode |= MDSS_MDP_DSPP_OP_IGC_LUT_EN | /* IGC_LUT_EN */
+ (pp_sts->igc_tbl_idx << 1);
+ }
+ if (pp_sts->enhist_sts & PP_STS_ENABLE) {
+ *opmode |= MDSS_MDP_DSPP_OP_HIST_LUTV_EN | /* HIST_LUT_EN */
+ MDSS_MDP_DSPP_OP_PA_EN; /* PA_EN */
+ }
+ if (pp_sts_is_enabled(pp_sts->dither_sts, side))
+ *opmode |= MDSS_MDP_DSPP_OP_DST_DITHER_EN; /* DITHER_EN */
+ if (pp_sts_is_enabled(pp_sts->gamut_sts, side)) {
+ *opmode |= MDSS_MDP_DSPP_OP_GAMUT_EN; /* GAMUT_EN */
+ if (pp_sts->gamut_sts & PP_STS_GAMUT_FIRST)
+ *opmode |= MDSS_MDP_DSPP_OP_GAMUT_PCC_ORDER;
+ }
+ if (pp_sts_is_enabled(pp_sts->pgc_sts, side))
+ *opmode |= MDSS_MDP_DSPP_OP_ARGC_LUT_EN;
+}
+
static int pp_dspp_setup(u32 disp_num, struct mdss_mdp_mixer *mixer)
{
- u32 flags, base, offset, dspp_num, opmode = 0;
- struct mdp_dither_cfg_data *dither_cfg;
+ u32 ad_flags, flags, dspp_num, opmode = 0, ad_bypass;
struct mdp_pgc_lut_data *pgc_config;
struct pp_sts_type *pp_sts;
- u32 data;
- char __iomem *basel;
- int i, ret = 0;
+ char __iomem *base, *addr;
+ int ret = 0;
struct mdss_data_type *mdata;
+ struct mdss_ad_info *ad = NULL;
+ struct mdss_mdp_ad *ad_hw = NULL;
struct mdss_mdp_ctl *ctl;
u32 mixer_cnt;
u32 mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
@@ -1020,8 +1434,7 @@
if ((mixer->type != MDSS_MDP_MIXER_TYPE_INTF) ||
(dspp_num >= MDSS_MDP_MAX_DSPP))
return -EINVAL;
- base = MDSS_MDP_REG_DSPP_OFFSET(dspp_num);
- basel = mdss_mdp_get_dspp_addr_off(dspp_num);
+ base = mdss_mdp_get_dspp_addr_off(dspp_num);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
@@ -1035,107 +1448,92 @@
flags = 0;
mixer_cnt = mdss_mdp_get_ctl_mixers(disp_num, mixer_id);
- if (dspp_num < mdata->nad_cfgs && (mixer_cnt != 2)) {
- ret = mdss_mdp_ad_setup(ctl->mfd);
- if (ret < 0)
- pr_warn("ad_setup(dspp%d) returns %d", dspp_num, ret);
+ if (dspp_num < mdata->nad_cfgs && disp_num < mdata->nad_cfgs &&
+ (mixer_cnt <= mdata->nmax_concurrent_ad_hw)) {
+ ad = &mdata->ad_cfgs[disp_num];
+ ad_flags = ad->reg_sts;
+ ad_hw = &mdata->ad_off[dspp_num];
+ } else {
+ ad_flags = 0;
}
+
/* call calibration specific processing here */
if (ctl->mfd->calib_mode)
goto flush_exit;
/* nothing to update */
- if ((!flags) && (!(opmode)) && (ret <= 0))
+ if ((!flags) && (!(opmode)) && (!ad_flags))
goto dspp_exit;
- ret = 0;
pp_sts = &mdss_pp_res->pp_disp_sts[disp_num];
- pp_pa_config(flags, base + MDSS_MDP_REG_DSPP_PA_BASE, pp_sts,
- &mdss_pp_res->pa_disp_cfg[disp_num]);
+ if (mdata->mdp_rev >= MDSS_MDP_HW_REV_103) {
+ pp_pa_v2_config(flags, base + MDSS_MDP_REG_DSPP_PA_BASE, pp_sts,
+ &mdss_pp_res->pa_v2_disp_cfg[disp_num],
+ PP_DSPP);
+ } else
+ pp_pa_config(flags, base + MDSS_MDP_REG_DSPP_PA_BASE, pp_sts,
+ &mdss_pp_res->pa_disp_cfg[disp_num]);
pp_pcc_config(flags, base + MDSS_MDP_REG_DSPP_PCC_BASE, pp_sts,
&mdss_pp_res->pcc_disp_cfg[disp_num]);
- pp_igc_config(flags, MDSS_MDP_REG_IGC_DSPP_BASE, pp_sts,
- &mdss_pp_res->igc_disp_cfg[disp_num], dspp_num);
+ pp_igc_config(flags, mdata->mdp_base + MDSS_MDP_REG_IGC_DSPP_BASE,
+ pp_sts, &mdss_pp_res->igc_disp_cfg[disp_num],
+ dspp_num);
- pp_enhist_config(flags, basel + MDSS_MDP_REG_DSPP_HIST_LUT_BASE,
+ pp_enhist_config(flags, base + MDSS_MDP_REG_DSPP_HIST_LUT_BASE,
pp_sts, &mdss_pp_res->enhist_disp_cfg[disp_num]);
- if (pp_sts->pa_sts & PP_STS_ENABLE)
- opmode |= (1 << 20); /* PA_EN */
-
- if (pp_sts->pcc_sts & PP_STS_ENABLE)
- opmode |= (1 << 4); /* PCC_EN */
-
- if (pp_sts->igc_sts & PP_STS_ENABLE) {
- opmode |= (1 << 0) | /* IGC_LUT_EN */
- (pp_sts->igc_tbl_idx << 1);
- }
-
- if (pp_sts->enhist_sts & PP_STS_ENABLE) {
- opmode |= (1 << 19) | /* HIST_LUT_EN */
- (1 << 20); /* PA_EN */
- if (!(pp_sts->pa_sts & PP_STS_ENABLE)) {
- /* Program default value */
- offset = base + MDSS_MDP_REG_DSPP_PA_BASE;
- MDSS_MDP_REG_WRITE(offset, 0);
- MDSS_MDP_REG_WRITE(offset + 4, 0);
- MDSS_MDP_REG_WRITE(offset + 8, 0);
- MDSS_MDP_REG_WRITE(offset + 12, 0);
- }
+ if (pp_sts->enhist_sts & PP_STS_ENABLE &&
+ !(pp_sts->pa_sts & PP_STS_ENABLE)) {
+ /* Program default value */
+ addr = base + MDSS_MDP_REG_DSPP_PA_BASE;
+ writel_relaxed(0, addr);
+ writel_relaxed(0, addr + 4);
+ writel_relaxed(0, addr + 8);
+ writel_relaxed(0, addr + 12);
}
if (flags & PP_FLAGS_DIRTY_DITHER) {
- dither_cfg = &mdss_pp_res->dither_disp_cfg[disp_num];
- if (dither_cfg->flags & MDP_PP_OPS_WRITE) {
- offset = base + MDSS_MDP_REG_DSPP_DITHER_DEPTH;
- MDSS_MDP_REG_WRITE(offset,
- dither_depth_map[dither_cfg->g_y_depth] |
- (dither_depth_map[dither_cfg->b_cb_depth] << 2) |
- (dither_depth_map[dither_cfg->r_cr_depth] << 4));
- offset += 0x14;
- for (i = 0; i << 16; i += 4) {
- data = dither_matrix[i] |
- (dither_matrix[i + 1] << 4) |
- (dither_matrix[i + 2] << 8) |
- (dither_matrix[i + 3] << 12);
- MDSS_MDP_REG_WRITE(offset, data);
- offset += 4;
- }
- }
- if (dither_cfg->flags & MDP_PP_OPS_DISABLE)
- pp_sts->dither_sts &= ~PP_STS_ENABLE;
- else if (dither_cfg->flags & MDP_PP_OPS_ENABLE)
- pp_sts->dither_sts |= PP_STS_ENABLE;
+ addr = base + MDSS_MDP_REG_DSPP_DITHER_DEPTH;
+ pp_dither_config(addr, pp_sts,
+ &mdss_pp_res->dither_disp_cfg[disp_num]);
}
- if (pp_sts->dither_sts & PP_STS_ENABLE)
- opmode |= (1 << 8); /* DITHER_EN */
if (flags & PP_FLAGS_DIRTY_GAMUT)
pp_gamut_config(&mdss_pp_res->gamut_disp_cfg[disp_num], base,
pp_sts);
- if (pp_sts->gamut_sts & PP_STS_ENABLE) {
- opmode |= (1 << 23); /* GAMUT_EN */
- if (pp_sts->gamut_sts & PP_STS_GAMUT_FIRST)
- opmode |= (1 << 24); /* GAMUT_ORDER */
- }
if (flags & PP_FLAGS_DIRTY_PGC) {
pgc_config = &mdss_pp_res->pgc_disp_cfg[disp_num];
if (pgc_config->flags & MDP_PP_OPS_WRITE) {
- offset = base + MDSS_MDP_REG_DSPP_GC_BASE;
- pp_update_argc_lut(offset, pgc_config);
+ addr = base + MDSS_MDP_REG_DSPP_GC_BASE;
+ pp_update_argc_lut(addr, pgc_config);
}
if (pgc_config->flags & MDP_PP_OPS_DISABLE)
pp_sts->pgc_sts &= ~PP_STS_ENABLE;
else if (pgc_config->flags & MDP_PP_OPS_ENABLE)
pp_sts->pgc_sts |= PP_STS_ENABLE;
+ pp_sts_set_split_bits(&pp_sts->pgc_sts, pgc_config->flags);
}
- if (pp_sts->pgc_sts & PP_STS_ENABLE)
- opmode |= (1 << 22);
+
+ pp_dspp_opmode_config(ctl, dspp_num, pp_sts, mdata->mdp_rev, &opmode);
flush_exit:
- writel_relaxed(opmode, basel + MDSS_MDP_REG_DSPP_OP_MODE);
+ if (ad_hw) {
+ mutex_lock(&ad->lock);
+ ad_flags = ad->reg_sts;
+ if (ad_flags & PP_AD_STS_DIRTY_DATA)
+ pp_ad_input_write(ad_hw, ad);
+ if (ad_flags & PP_AD_STS_DIRTY_INIT)
+ pp_ad_init_write(ad_hw, ad, ctl);
+ if (ad_flags & PP_AD_STS_DIRTY_CFG)
+ pp_ad_cfg_write(ad_hw, ad);
+ pp_ad_bypass_config(ad, ctl, ad_hw->num, &ad_bypass);
+ writel_relaxed(ad_bypass, ad_hw->base);
+ mutex_unlock(&ad->lock);
+ }
+
+ writel_relaxed(opmode, base + MDSS_MDP_REG_DSPP_OP_MODE);
ctl->flush_bits |= BIT(13 + dspp_num);
wmb();
dspp_exit:
@@ -1166,13 +1564,39 @@
/* call only when holding and mfd->lock */
int mdss_mdp_pp_setup_locked(struct mdss_mdp_ctl *ctl)
{
+ struct mdss_data_type *mdata = ctl->mdata;
+ int ret = 0;
+ u32 mixer_cnt;
+ u32 mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
u32 disp_num;
+ int i;
+ bool valid_mixers = true;
if ((!ctl->mfd) || (!mdss_pp_res))
return -EINVAL;
/* treat fb_num the same as block logical id*/
disp_num = ctl->mfd->index;
+ mixer_cnt = mdss_mdp_get_ctl_mixers(disp_num, mixer_id);
+ if (!mixer_cnt) {
+ valid_mixers = false;
+ ret = -EINVAL;
+ pr_warn("Configuring post processing without mixers, err = %d",
+ ret);
+ goto exit;
+ }
+ if (mdata->nad_cfgs == 0)
+ valid_mixers = false;
+ for (i = 0; i < mixer_cnt && valid_mixers; i++) {
+ if (mixer_id[i] > mdata->nad_cfgs)
+ valid_mixers = false;
+ }
+ if (valid_mixers && (mixer_cnt <= mdata->nmax_concurrent_ad_hw)) {
+ ret = mdss_mdp_ad_setup(ctl->mfd);
+ if (ret < 0)
+ pr_warn("ad_setup(disp%d) returns %d", disp_num, ret);
+ }
+
mutex_lock(&mdss_pp_mutex);
if (ctl->mixer_left) {
pp_mixer_setup(disp_num, ctl->mixer_left);
@@ -1183,11 +1607,14 @@
pp_dspp_setup(disp_num, ctl->mixer_right);
}
/* clear dirty flag */
- if (disp_num < MDSS_BLOCK_DISP_NUM)
+ if (disp_num < MDSS_BLOCK_DISP_NUM) {
mdss_pp_res->pp_disp_flags[disp_num] = 0;
+ if (disp_num < mdata->nad_cfgs)
+ mdata->ad_cfgs[disp_num].reg_sts = 0;
+ }
mutex_unlock(&mdss_pp_mutex);
-
- return 0;
+exit:
+ return ret;
}
/*
@@ -1210,17 +1637,19 @@
ad = &mdata->ad_cfgs[dspp_num];
if (PP_AD_STATE_CFG & ad->state)
- pp_ad_cfg_write(ad);
+ pp_ad_cfg_write(&mdata->ad_off[dspp_num], ad);
if (PP_AD_STATE_INIT & ad->state)
- pp_ad_init_write(ad);
- if ((PP_AD_STATE_DATA & ad->state) && (ad->sts & PP_STS_ENABLE)) {
+ pp_ad_init_write(&mdata->ad_off[dspp_num], ad, ctl);
+ if ((PP_AD_STATE_DATA & ad->state) &&
+ (ad->sts & PP_STS_ENABLE)) {
bl = ad->bl_mfd->bl_level;
ad->last_bl = bl;
if (ad->state & PP_AD_STATE_BL_LIN) {
bl = ad->bl_lin[bl >> ad->bl_bright_shift];
bl = bl << ad->bl_bright_shift;
}
- pp_ad_input_write(ad, bl);
+ ad->bl_data = bl;
+ pp_ad_input_write(&mdata->ad_off[dspp_num], ad);
}
if ((PP_AD_STATE_VSYNC & ad->state) && ad->calc_itr)
ctl->add_vsync_handler(ctl, &ad->handle);
@@ -1230,10 +1659,17 @@
if (pp_sts.pa_sts & PP_STS_ENABLE) {
flags |= PP_FLAGS_DIRTY_PA;
- if (!(mdss_pp_res->pa_disp_cfg[disp_num].flags
- & MDP_PP_OPS_DISABLE))
- mdss_pp_res->pa_disp_cfg[disp_num].flags |=
- MDP_PP_OPS_WRITE;
+ if (mdata->mdp_rev >= MDSS_MDP_HW_REV_103) {
+ if (!(mdss_pp_res->pa_v2_disp_cfg[disp_num].flags
+ & MDP_PP_OPS_DISABLE))
+ mdss_pp_res->pa_v2_disp_cfg[disp_num].flags |=
+ MDP_PP_OPS_WRITE;
+ } else {
+ if (!(mdss_pp_res->pa_disp_cfg[disp_num].flags
+ & MDP_PP_OPS_DISABLE))
+ mdss_pp_res->pa_disp_cfg[disp_num].flags |=
+ MDP_PP_OPS_WRITE;
+ }
}
if (pp_sts.pcc_sts & PP_STS_ENABLE) {
flags |= PP_FLAGS_DIRTY_PCC;
@@ -1303,11 +1739,13 @@
if (mdss_pp_res == NULL) {
pr_err("%s mdss_pp_res allocation failed!", __func__);
ret = -ENOMEM;
- }
-
- for (i = 0; i < MDSS_MDP_MAX_DSPP; i++) {
- mutex_init(&mdss_pp_res->dspp_hist[i].hist_mutex);
- spin_lock_init(&mdss_pp_res->dspp_hist[i].hist_lock);
+ } else {
+ for (i = 0; i < MDSS_MDP_MAX_DSPP; i++) {
+ mutex_init(
+ &mdss_pp_res->dspp_hist[i].hist_mutex);
+ spin_lock_init(
+ &mdss_pp_res->dspp_hist[i].hist_lock);
+ }
}
}
if (mdata) {
@@ -1376,10 +1814,15 @@
u32 *copyback)
{
int ret = 0;
- u32 pa_offset, disp_num, dspp_num = 0;
+ u32 disp_num, dspp_num = 0;
+ struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+ char __iomem *pa_addr;
+
+ if (mdata->mdp_rev >= MDSS_MDP_HW_REV_103)
+ return -EINVAL;
if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
- (config->block >= MDP_BLOCK_MAX))
+ (config->block >= MDP_BLOCK_MAX))
return -EINVAL;
mutex_lock(&mdss_pp_mutex);
@@ -1388,20 +1831,20 @@
if (config->pa_data.flags & MDP_PP_OPS_READ) {
ret = pp_get_dspp_num(disp_num, &dspp_num);
if (ret) {
- pr_err("%s, no dspp connects to disp %d",
- __func__, disp_num);
+ pr_err("no dspp connects to disp %d",
+ disp_num);
goto pa_config_exit;
}
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
- pa_offset = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) +
- MDSS_MDP_REG_DSPP_PA_BASE;
- config->pa_data.hue_adj = MDSS_MDP_REG_READ(pa_offset);
- pa_offset += 4;
- config->pa_data.sat_adj = MDSS_MDP_REG_READ(pa_offset);
- pa_offset += 4;
- config->pa_data.val_adj = MDSS_MDP_REG_READ(pa_offset);
- pa_offset += 4;
- config->pa_data.cont_adj = MDSS_MDP_REG_READ(pa_offset);
+ pa_addr = mdss_mdp_get_dspp_addr_off(dspp_num) +
+ MDSS_MDP_REG_DSPP_PA_BASE;
+ config->pa_data.hue_adj = readl_relaxed(pa_addr);
+ pa_addr += 4;
+ config->pa_data.sat_adj = readl_relaxed(pa_addr);
+ pa_addr += 4;
+ config->pa_data.val_adj = readl_relaxed(pa_addr);
+ pa_addr += 4;
+ config->pa_data.cont_adj = readl_relaxed(pa_addr);
*copyback = 1;
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
} else {
@@ -1414,142 +1857,321 @@
return ret;
}
-static void pp_read_pcc_regs(u32 offset,
- struct mdp_pcc_cfg_data *cfg_ptr)
+int mdss_mdp_pa_v2_config(struct mdp_pa_v2_cfg_data *config,
+ u32 *copyback)
{
- cfg_ptr->r.c = MDSS_MDP_REG_READ(offset);
- cfg_ptr->g.c = MDSS_MDP_REG_READ(offset + 4);
- cfg_ptr->b.c = MDSS_MDP_REG_READ(offset + 8);
- offset += 0x10;
+ int ret = 0;
+ u32 disp_num, dspp_num = 0;
+ char __iomem *pa_addr;
+ struct mdss_data_type *mdata = mdss_mdp_get_mdata();
- cfg_ptr->r.r = MDSS_MDP_REG_READ(offset);
- cfg_ptr->g.r = MDSS_MDP_REG_READ(offset + 4);
- cfg_ptr->b.r = MDSS_MDP_REG_READ(offset + 8);
- offset += 0x10;
+ if (mdata->mdp_rev < MDSS_MDP_HW_REV_103)
+ return -EINVAL;
- cfg_ptr->r.g = MDSS_MDP_REG_READ(offset);
- cfg_ptr->g.g = MDSS_MDP_REG_READ(offset + 4);
- cfg_ptr->b.g = MDSS_MDP_REG_READ(offset + 8);
- offset += 0x10;
+ if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
+ (config->block >= MDP_BLOCK_MAX))
+ return -EINVAL;
- cfg_ptr->r.b = MDSS_MDP_REG_READ(offset);
- cfg_ptr->g.b = MDSS_MDP_REG_READ(offset + 4);
- cfg_ptr->b.b = MDSS_MDP_REG_READ(offset + 8);
- offset += 0x10;
+ if ((config->pa_v2_data.flags & MDSS_PP_SPLIT_MASK) ==
+ MDSS_PP_SPLIT_MASK) {
+ pr_warn("Can't set both split bits\n");
+ return -EINVAL;
+ }
- cfg_ptr->r.rr = MDSS_MDP_REG_READ(offset);
- cfg_ptr->g.rr = MDSS_MDP_REG_READ(offset + 4);
- cfg_ptr->b.rr = MDSS_MDP_REG_READ(offset + 8);
- offset += 0x10;
+ mutex_lock(&mdss_pp_mutex);
+ disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
- cfg_ptr->r.rg = MDSS_MDP_REG_READ(offset);
- cfg_ptr->g.rg = MDSS_MDP_REG_READ(offset + 4);
- cfg_ptr->b.rg = MDSS_MDP_REG_READ(offset + 8);
- offset += 0x10;
+ if (config->pa_v2_data.flags & MDP_PP_OPS_READ) {
+ ret = pp_get_dspp_num(disp_num, &dspp_num);
+ if (ret) {
+ pr_err("no dspp connects to disp %d",
+ disp_num);
+ goto pa_config_exit;
+ }
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ pa_addr = mdss_mdp_get_dspp_addr_off(dspp_num);
+ if (IS_ERR(pa_addr)) {
+ ret = PTR_ERR(pa_addr);
+ goto pa_config_exit;
+ } else
+ pa_addr += MDSS_MDP_REG_DSPP_PA_BASE;
+ ret = pp_read_pa_v2_regs(pa_addr,
+ &config->pa_v2_data,
+ disp_num);
+ if (ret)
+ goto pa_config_exit;
+ *copyback = 1;
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ } else {
+ if (config->pa_v2_data.flags & MDP_PP_PA_SIX_ZONE_ENABLE) {
+ ret = pp_copy_pa_six_zone_lut(config, disp_num);
+ if (ret)
+ goto pa_config_exit;
+ }
+ mdss_pp_res->pa_v2_disp_cfg[disp_num] =
+ config->pa_v2_data;
+ mdss_pp_res->pa_v2_disp_cfg[disp_num].six_zone_curve_p0 =
+ &mdss_pp_res->six_zone_lut_curve_p0[disp_num][0];
+ mdss_pp_res->pa_v2_disp_cfg[disp_num].six_zone_curve_p1 =
+ &mdss_pp_res->six_zone_lut_curve_p1[disp_num][0];
+ mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_PA;
+ }
- cfg_ptr->r.rb = MDSS_MDP_REG_READ(offset);
- cfg_ptr->g.rb = MDSS_MDP_REG_READ(offset + 4);
- cfg_ptr->b.rb = MDSS_MDP_REG_READ(offset + 8);
- offset += 0x10;
-
- cfg_ptr->r.gg = MDSS_MDP_REG_READ(offset);
- cfg_ptr->g.gg = MDSS_MDP_REG_READ(offset + 4);
- cfg_ptr->b.gg = MDSS_MDP_REG_READ(offset + 8);
- offset += 0x10;
-
- cfg_ptr->r.gb = MDSS_MDP_REG_READ(offset);
- cfg_ptr->g.gb = MDSS_MDP_REG_READ(offset + 4);
- cfg_ptr->b.gb = MDSS_MDP_REG_READ(offset + 8);
- offset += 0x10;
-
- cfg_ptr->r.bb = MDSS_MDP_REG_READ(offset);
- cfg_ptr->g.bb = MDSS_MDP_REG_READ(offset + 4);
- cfg_ptr->b.bb = MDSS_MDP_REG_READ(offset + 8);
- offset += 0x10;
-
- cfg_ptr->r.rgb_0 = MDSS_MDP_REG_READ(offset);
- cfg_ptr->g.rgb_0 = MDSS_MDP_REG_READ(offset + 4);
- cfg_ptr->b.rgb_0 = MDSS_MDP_REG_READ(offset + 8);
- offset += 0x10;
-
- cfg_ptr->r.rgb_1 = MDSS_MDP_REG_READ(offset);
- cfg_ptr->g.rgb_1 = MDSS_MDP_REG_READ(offset + 4);
- cfg_ptr->b.rgb_1 = MDSS_MDP_REG_READ(offset + 8);
+pa_config_exit:
+ mutex_unlock(&mdss_pp_mutex);
+ return ret;
}
-static void pp_update_pcc_regs(u32 offset,
+
+static int pp_read_pa_v2_regs(char __iomem *addr,
+ struct mdp_pa_v2_data *pa_v2_config,
+ u32 disp_num)
+{
+ int i;
+ u32 data;
+
+ if (pa_v2_config->flags & MDP_PP_PA_HUE_ENABLE)
+ pa_v2_config->global_hue_adj = readl_relaxed(addr);
+ addr += 4;
+ if (pa_v2_config->flags & MDP_PP_PA_SAT_ENABLE)
+ pa_v2_config->global_sat_adj = readl_relaxed(addr);
+ addr += 4;
+ if (pa_v2_config->flags & MDP_PP_PA_VAL_ENABLE)
+ pa_v2_config->global_val_adj = readl_relaxed(addr);
+ addr += 4;
+ if (pa_v2_config->flags & MDP_PP_PA_CONT_ENABLE)
+ pa_v2_config->global_cont_adj = readl_relaxed(addr);
+ addr += 4;
+
+ /* Six zone LUT and thresh data */
+ if (pa_v2_config->flags & MDP_PP_PA_SIX_ZONE_ENABLE) {
+ if (pa_v2_config->six_zone_len != MDP_SIX_ZONE_LUT_SIZE)
+ return -EINVAL;
+
+ data = (3 << 25);
+ writel_relaxed(data, addr);
+
+ for (i = 0; i < MDP_SIX_ZONE_LUT_SIZE; i++) {
+ addr += 4;
+ mdss_pp_res->six_zone_lut_curve_p1[disp_num][i] =
+ readl_relaxed(addr);
+ addr -= 4;
+ mdss_pp_res->six_zone_lut_curve_p0[disp_num][i] =
+ readl_relaxed(addr) & 0xFFF;
+ }
+
+ if (copy_to_user(pa_v2_config->six_zone_curve_p0,
+ &mdss_pp_res->six_zone_lut_curve_p0[disp_num][0],
+ pa_v2_config->six_zone_len * sizeof(u32))) {
+ return -EFAULT;
+ }
+
+ if (copy_to_user(pa_v2_config->six_zone_curve_p1,
+ &mdss_pp_res->six_zone_lut_curve_p1[disp_num][0],
+ pa_v2_config->six_zone_len * sizeof(u32))) {
+ return -EFAULT;
+ }
+
+ addr += 8;
+ pa_v2_config->six_zone_thresh = readl_relaxed(addr);
+ addr += 4;
+ } else {
+ addr += 12;
+ }
+
+ /* Skin memory color config registers */
+ if (pa_v2_config->flags & MDP_PP_PA_SKIN_ENABLE)
+ pp_read_pa_mem_col_regs(addr, &pa_v2_config->skin_cfg);
+
+ addr += 0x14;
+ /* Sky memory color config registers */
+ if (pa_v2_config->flags & MDP_PP_PA_SKY_ENABLE)
+ pp_read_pa_mem_col_regs(addr, &pa_v2_config->sky_cfg);
+
+ addr += 0x14;
+ /* Foliage memory color config registers */
+ if (pa_v2_config->flags & MDP_PP_PA_FOL_ENABLE)
+ pp_read_pa_mem_col_regs(addr, &pa_v2_config->fol_cfg);
+
+ return 0;
+}
+
+static void pp_read_pa_mem_col_regs(char __iomem *addr,
+ struct mdp_pa_mem_col_cfg *mem_col_cfg)
+{
+ mem_col_cfg->color_adjust_p0 = readl_relaxed(addr);
+ addr += 4;
+ mem_col_cfg->color_adjust_p1 = readl_relaxed(addr);
+ addr += 4;
+ mem_col_cfg->hue_region = readl_relaxed(addr);
+ addr += 4;
+ mem_col_cfg->sat_region = readl_relaxed(addr);
+ addr += 4;
+ mem_col_cfg->val_region = readl_relaxed(addr);
+}
+
+static int pp_copy_pa_six_zone_lut(struct mdp_pa_v2_cfg_data *pa_v2_config,
+ u32 disp_num)
+{
+ if (pa_v2_config->pa_v2_data.six_zone_len != MDP_SIX_ZONE_LUT_SIZE)
+ return -EINVAL;
+
+ if (copy_from_user(&mdss_pp_res->six_zone_lut_curve_p0[disp_num][0],
+ pa_v2_config->pa_v2_data.six_zone_curve_p0,
+ pa_v2_config->pa_v2_data.six_zone_len * sizeof(u32))) {
+ return -EFAULT;
+ }
+ if (copy_from_user(&mdss_pp_res->six_zone_lut_curve_p1[disp_num][0],
+ pa_v2_config->pa_v2_data.six_zone_curve_p1,
+ pa_v2_config->pa_v2_data.six_zone_len * sizeof(u32))) {
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static void pp_read_pcc_regs(char __iomem *addr,
struct mdp_pcc_cfg_data *cfg_ptr)
{
- MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.c);
- MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.c);
- MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.c);
- offset += 0x10;
+ cfg_ptr->r.c = readl_relaxed(addr);
+ cfg_ptr->g.c = readl_relaxed(addr + 4);
+ cfg_ptr->b.c = readl_relaxed(addr + 8);
+ addr += 0x10;
- MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.r);
- MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.r);
- MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.r);
- offset += 0x10;
+ cfg_ptr->r.r = readl_relaxed(addr);
+ cfg_ptr->g.r = readl_relaxed(addr + 4);
+ cfg_ptr->b.r = readl_relaxed(addr + 8);
+ addr += 0x10;
- MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.g);
- MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.g);
- MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.g);
- offset += 0x10;
+ cfg_ptr->r.g = readl_relaxed(addr);
+ cfg_ptr->g.g = readl_relaxed(addr + 4);
+ cfg_ptr->b.g = readl_relaxed(addr + 8);
+ addr += 0x10;
- MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.b);
- MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.b);
- MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.b);
- offset += 0x10;
+ cfg_ptr->r.b = readl_relaxed(addr);
+ cfg_ptr->g.b = readl_relaxed(addr + 4);
+ cfg_ptr->b.b = readl_relaxed(addr + 8);
+ addr += 0x10;
- MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.rr);
- MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.rr);
- MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.rr);
- offset += 0x10;
+ cfg_ptr->r.rr = readl_relaxed(addr);
+ cfg_ptr->g.rr = readl_relaxed(addr + 4);
+ cfg_ptr->b.rr = readl_relaxed(addr + 8);
+ addr += 0x10;
- MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.rg);
- MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.rg);
- MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.rg);
- offset += 0x10;
+ cfg_ptr->r.rg = readl_relaxed(addr);
+ cfg_ptr->g.rg = readl_relaxed(addr + 4);
+ cfg_ptr->b.rg = readl_relaxed(addr + 8);
+ addr += 0x10;
- MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.rb);
- MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.rb);
- MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.rb);
- offset += 0x10;
+ cfg_ptr->r.rb = readl_relaxed(addr);
+ cfg_ptr->g.rb = readl_relaxed(addr + 4);
+ cfg_ptr->b.rb = readl_relaxed(addr + 8);
+ addr += 0x10;
- MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.gg);
- MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.gg);
- MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.gg);
- offset += 0x10;
+ cfg_ptr->r.gg = readl_relaxed(addr);
+ cfg_ptr->g.gg = readl_relaxed(addr + 4);
+ cfg_ptr->b.gg = readl_relaxed(addr + 8);
+ addr += 0x10;
- MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.gb);
- MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.gb);
- MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.gb);
- offset += 0x10;
+ cfg_ptr->r.gb = readl_relaxed(addr);
+ cfg_ptr->g.gb = readl_relaxed(addr + 4);
+ cfg_ptr->b.gb = readl_relaxed(addr + 8);
+ addr += 0x10;
- MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.bb);
- MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.bb);
- MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.bb);
- offset += 0x10;
+ cfg_ptr->r.bb = readl_relaxed(addr);
+ cfg_ptr->g.bb = readl_relaxed(addr + 4);
+ cfg_ptr->b.bb = readl_relaxed(addr + 8);
+ addr += 0x10;
- MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.rgb_0);
- MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.rgb_0);
- MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.rgb_0);
- offset += 0x10;
+ cfg_ptr->r.rgb_0 = readl_relaxed(addr);
+ cfg_ptr->g.rgb_0 = readl_relaxed(addr + 4);
+ cfg_ptr->b.rgb_0 = readl_relaxed(addr + 8);
+ addr += 0x10;
- MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.rgb_1);
- MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.rgb_1);
- MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.rgb_1);
+ cfg_ptr->r.rgb_1 = readl_relaxed(addr);
+ cfg_ptr->g.rgb_1 = readl_relaxed(addr + 4);
+ cfg_ptr->b.rgb_1 = readl_relaxed(addr + 8);
+}
+
+static void pp_update_pcc_regs(char __iomem *addr,
+ struct mdp_pcc_cfg_data *cfg_ptr)
+{
+ writel_relaxed(cfg_ptr->r.c, addr);
+ writel_relaxed(cfg_ptr->g.c, addr + 4);
+ writel_relaxed(cfg_ptr->b.c, addr + 8);
+ addr += 0x10;
+
+ writel_relaxed(cfg_ptr->r.r, addr);
+ writel_relaxed(cfg_ptr->g.r, addr + 4);
+ writel_relaxed(cfg_ptr->b.r, addr + 8);
+ addr += 0x10;
+
+ writel_relaxed(cfg_ptr->r.g, addr);
+ writel_relaxed(cfg_ptr->g.g, addr + 4);
+ writel_relaxed(cfg_ptr->b.g, addr + 8);
+ addr += 0x10;
+
+ writel_relaxed(cfg_ptr->r.b, addr);
+ writel_relaxed(cfg_ptr->g.b, addr + 4);
+ writel_relaxed(cfg_ptr->b.b, addr + 8);
+ addr += 0x10;
+
+ writel_relaxed(cfg_ptr->r.rr, addr);
+ writel_relaxed(cfg_ptr->g.rr, addr + 4);
+ writel_relaxed(cfg_ptr->b.rr, addr + 8);
+ addr += 0x10;
+
+ writel_relaxed(cfg_ptr->r.rg, addr);
+ writel_relaxed(cfg_ptr->g.rg, addr + 4);
+ writel_relaxed(cfg_ptr->b.rg, addr + 8);
+ addr += 0x10;
+
+ writel_relaxed(cfg_ptr->r.rb, addr);
+ writel_relaxed(cfg_ptr->g.rb, addr + 4);
+ writel_relaxed(cfg_ptr->b.rb, addr + 8);
+ addr += 0x10;
+
+ writel_relaxed(cfg_ptr->r.gg, addr);
+ writel_relaxed(cfg_ptr->g.gg, addr + 4);
+ writel_relaxed(cfg_ptr->b.gg, addr + 8);
+ addr += 0x10;
+
+ writel_relaxed(cfg_ptr->r.gb, addr);
+ writel_relaxed(cfg_ptr->g.gb, addr + 4);
+ writel_relaxed(cfg_ptr->b.gb, addr + 8);
+ addr += 0x10;
+
+ writel_relaxed(cfg_ptr->r.bb, addr);
+ writel_relaxed(cfg_ptr->g.bb, addr + 4);
+ writel_relaxed(cfg_ptr->b.bb, addr + 8);
+ addr += 0x10;
+
+ writel_relaxed(cfg_ptr->r.rgb_0, addr);
+ writel_relaxed(cfg_ptr->g.rgb_0, addr + 4);
+ writel_relaxed(cfg_ptr->b.rgb_0, addr + 8);
+ addr += 0x10;
+
+ writel_relaxed(cfg_ptr->r.rgb_1, addr);
+ writel_relaxed(cfg_ptr->g.rgb_1, addr + 4);
+ writel_relaxed(cfg_ptr->b.rgb_1, addr + 8);
}
int mdss_mdp_pcc_config(struct mdp_pcc_cfg_data *config,
u32 *copyback)
{
int ret = 0;
- u32 base, disp_num, dspp_num = 0;
+ u32 disp_num, dspp_num = 0;
+ char __iomem *addr;
if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
(config->block >= MDP_BLOCK_MAX))
return -EINVAL;
+ if ((config->ops & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
+ pr_warn("Can't set both split bits\n");
+ return -EINVAL;
+ }
+
mutex_lock(&mdss_pp_mutex);
disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
@@ -1563,9 +2185,9 @@
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
- base = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) +
+ addr = mdss_mdp_get_dspp_addr_off(dspp_num) +
MDSS_MDP_REG_DSPP_PCC_BASE;
- pp_read_pcc_regs(base, config);
+ pp_read_pcc_regs(addr, config);
*copyback = 1;
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
} else {
@@ -1579,57 +2201,57 @@
}
static void pp_read_igc_lut(struct mdp_igc_lut_data *cfg,
- u32 offset, u32 blk_idx)
+ char __iomem *addr, u32 blk_idx)
{
int i;
u32 data;
/* INDEX_UPDATE & VALUE_UPDATEN */
data = (3 << 24) | (((~(1 << blk_idx)) & 0x7) << 28);
- MDSS_MDP_REG_WRITE(offset, data);
+ writel_relaxed(data, addr);
for (i = 0; i < cfg->len; i++)
- cfg->c0_c1_data[i] = MDSS_MDP_REG_READ(offset) & 0xFFF;
+ cfg->c0_c1_data[i] = readl_relaxed(addr) & 0xFFF;
- offset += 0x4;
- MDSS_MDP_REG_WRITE(offset, data);
+ addr += 0x4;
+ writel_relaxed(data, addr);
for (i = 0; i < cfg->len; i++)
- cfg->c0_c1_data[i] |= (MDSS_MDP_REG_READ(offset) & 0xFFF) << 16;
+ cfg->c0_c1_data[i] |= (readl_relaxed(addr) & 0xFFF) << 16;
- offset += 0x4;
- MDSS_MDP_REG_WRITE(offset, data);
+ addr += 0x4;
+ writel_relaxed(data, addr);
for (i = 0; i < cfg->len; i++)
- cfg->c2_data[i] = MDSS_MDP_REG_READ(offset) & 0xFFF;
+ cfg->c2_data[i] = readl_relaxed(addr) & 0xFFF;
}
static void pp_update_igc_lut(struct mdp_igc_lut_data *cfg,
- u32 offset, u32 blk_idx)
+ char __iomem *addr, u32 blk_idx)
{
int i;
u32 data;
/* INDEX_UPDATE */
data = (1 << 25) | (((~(1 << blk_idx)) & 0x7) << 28);
- MDSS_MDP_REG_WRITE(offset, (cfg->c0_c1_data[0] & 0xFFF) | data);
+ writel_relaxed((cfg->c0_c1_data[0] & 0xFFF) | data, addr);
/* disable index update */
data &= ~(1 << 25);
for (i = 1; i < cfg->len; i++)
- MDSS_MDP_REG_WRITE(offset, (cfg->c0_c1_data[i] & 0xFFF) | data);
+ writel_relaxed((cfg->c0_c1_data[i] & 0xFFF) | data, addr);
- offset += 0x4;
+ addr += 0x4;
data |= (1 << 25);
- MDSS_MDP_REG_WRITE(offset, ((cfg->c0_c1_data[0] >> 16) & 0xFFF) | data);
+ writel_relaxed(((cfg->c0_c1_data[0] >> 16) & 0xFFF) | data, addr);
data &= ~(1 << 25);
for (i = 1; i < cfg->len; i++)
- MDSS_MDP_REG_WRITE(offset,
- ((cfg->c0_c1_data[i] >> 16) & 0xFFF) | data);
+ writel_relaxed(((cfg->c0_c1_data[i] >> 16) & 0xFFF) | data,
+ addr);
- offset += 0x4;
+ addr += 0x4;
data |= (1 << 25);
- MDSS_MDP_REG_WRITE(offset, (cfg->c2_data[0] & 0xFFF) | data);
+ writel_relaxed((cfg->c2_data[0] & 0xFFF) | data, addr);
data &= ~(1 << 25);
for (i = 1; i < cfg->len; i++)
- MDSS_MDP_REG_WRITE(offset, (cfg->c2_data[i] & 0xFFF) | data);
+ writel_relaxed((cfg->c2_data[i] & 0xFFF) | data, addr);
}
int mdss_mdp_limited_lut_igc_config(struct mdss_mdp_ctl *ctl)
@@ -1657,8 +2279,10 @@
u32 *copyback, u32 copy_from_kernel)
{
int ret = 0;
- u32 tbl_idx, igc_offset, disp_num, dspp_num = 0;
+ u32 tbl_idx, disp_num, dspp_num = 0;
struct mdp_igc_lut_data local_cfg;
+ char __iomem *igc_addr;
+ struct mdss_data_type *mdata = mdss_mdp_get_mdata();
if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
(config->block >= MDP_BLOCK_MAX))
@@ -1667,6 +2291,11 @@
if (config->len != IGC_LUT_ENTRIES)
return -EINVAL;
+ if ((config->ops & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
+ pr_warn("Can't set both split bits\n");
+ return -EINVAL;
+ }
+
mutex_lock(&mdss_pp_mutex);
disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
@@ -1684,13 +2313,14 @@
tbl_idx = 2;
else
tbl_idx = 0;
- igc_offset = MDSS_MDP_REG_IGC_DSPP_BASE + (0x10 * tbl_idx);
+ igc_addr = mdata->mdp_base + MDSS_MDP_REG_IGC_DSPP_BASE +
+ (0x10 * tbl_idx);
local_cfg = *config;
local_cfg.c0_c1_data =
&mdss_pp_res->igc_lut_c0c1[disp_num][0];
local_cfg.c2_data =
&mdss_pp_res->igc_lut_c2[disp_num][0];
- pp_read_igc_lut(&local_cfg, igc_offset, dspp_num);
+ pp_read_igc_lut(&local_cfg, igc_addr, dspp_num);
if (copy_to_user(config->c0_c1_data, local_cfg.c2_data,
config->len * sizeof(u32))) {
ret = -EFAULT;
@@ -1738,144 +2368,151 @@
mutex_unlock(&mdss_pp_mutex);
return ret;
}
-static void pp_update_gc_one_lut(u32 offset,
+static void pp_update_gc_one_lut(char __iomem *addr,
struct mdp_ar_gc_lut_data *lut_data,
uint8_t num_stages)
{
int i, start_idx, idx;
- start_idx = (MDSS_MDP_REG_READ(offset) >> 16) & 0xF;
+ start_idx = (readl_relaxed(addr) >> 16) & 0xF;
for (i = start_idx; i < GC_LUT_SEGMENTS; i++) {
idx = min((uint8_t)i, (uint8_t)(num_stages-1));
- MDSS_MDP_REG_WRITE(offset, lut_data[idx].x_start);
+ writel_relaxed(lut_data[idx].x_start, addr);
}
for (i = 0; i < start_idx; i++) {
idx = min((uint8_t)i, (uint8_t)(num_stages-1));
- MDSS_MDP_REG_WRITE(offset, lut_data[idx].x_start);
+ writel_relaxed(lut_data[idx].x_start, addr);
}
- offset += 4;
- start_idx = (MDSS_MDP_REG_READ(offset) >> 16) & 0xF;
+ addr += 4;
+ start_idx = (readl_relaxed(addr) >> 16) & 0xF;
for (i = start_idx; i < GC_LUT_SEGMENTS; i++) {
idx = min((uint8_t)i, (uint8_t)(num_stages-1));
- MDSS_MDP_REG_WRITE(offset, lut_data[idx].slope);
+ writel_relaxed(lut_data[idx].slope, addr);
}
for (i = 0; i < start_idx; i++) {
idx = min((uint8_t)i, (uint8_t)(num_stages-1));
- MDSS_MDP_REG_WRITE(offset, lut_data[idx].slope);
+ writel_relaxed(lut_data[idx].slope, addr);
}
- offset += 4;
- start_idx = (MDSS_MDP_REG_READ(offset) >> 16) & 0xF;
+ addr += 4;
+ start_idx = (readl_relaxed(addr) >> 16) & 0xF;
for (i = start_idx; i < GC_LUT_SEGMENTS; i++) {
idx = min((uint8_t)i, (uint8_t)(num_stages-1));
- MDSS_MDP_REG_WRITE(offset, lut_data[idx].offset);
+ writel_relaxed(lut_data[idx].offset, addr);
}
for (i = 0; i < start_idx; i++) {
idx = min((uint8_t)i, (uint8_t)(num_stages-1));
- MDSS_MDP_REG_WRITE(offset, lut_data[idx].offset);
+ writel_relaxed(lut_data[idx].offset, addr);
}
}
-static void pp_update_argc_lut(u32 offset, struct mdp_pgc_lut_data *config)
+static void pp_update_argc_lut(char __iomem *addr,
+ struct mdp_pgc_lut_data *config)
{
- pp_update_gc_one_lut(offset, config->r_data, config->num_r_stages);
- offset += 0x10;
- pp_update_gc_one_lut(offset, config->g_data, config->num_g_stages);
- offset += 0x10;
- pp_update_gc_one_lut(offset, config->b_data, config->num_b_stages);
+ pp_update_gc_one_lut(addr, config->r_data, config->num_r_stages);
+ addr += 0x10;
+ pp_update_gc_one_lut(addr, config->g_data, config->num_g_stages);
+ addr += 0x10;
+ pp_update_gc_one_lut(addr, config->b_data, config->num_b_stages);
}
-static void pp_read_gc_one_lut(u32 offset,
+static void pp_read_gc_one_lut(char __iomem *addr,
struct mdp_ar_gc_lut_data *gc_data)
{
int i, start_idx, data;
- data = MDSS_MDP_REG_READ(offset);
+ data = readl_relaxed(addr);
start_idx = (data >> 16) & 0xF;
gc_data[start_idx].x_start = data & 0xFFF;
for (i = start_idx + 1; i < GC_LUT_SEGMENTS; i++) {
- data = MDSS_MDP_REG_READ(offset);
+ data = readl_relaxed(addr);
gc_data[i].x_start = data & 0xFFF;
}
for (i = 0; i < start_idx; i++) {
- data = MDSS_MDP_REG_READ(offset);
+ data = readl_relaxed(addr);
gc_data[i].x_start = data & 0xFFF;
}
- offset += 4;
- data = MDSS_MDP_REG_READ(offset);
+ addr += 4;
+ data = readl_relaxed(addr);
start_idx = (data >> 16) & 0xF;
gc_data[start_idx].slope = data & 0x7FFF;
for (i = start_idx + 1; i < GC_LUT_SEGMENTS; i++) {
- data = MDSS_MDP_REG_READ(offset);
+ data = readl_relaxed(addr);
gc_data[i].slope = data & 0x7FFF;
}
for (i = 0; i < start_idx; i++) {
- data = MDSS_MDP_REG_READ(offset);
+ data = readl_relaxed(addr);
gc_data[i].slope = data & 0x7FFF;
}
- offset += 4;
- data = MDSS_MDP_REG_READ(offset);
+ addr += 4;
+ data = readl_relaxed(addr);
start_idx = (data >> 16) & 0xF;
gc_data[start_idx].offset = data & 0x7FFF;
for (i = start_idx + 1; i < GC_LUT_SEGMENTS; i++) {
- data = MDSS_MDP_REG_READ(offset);
+ data = readl_relaxed(addr);
gc_data[i].offset = data & 0x7FFF;
}
for (i = 0; i < start_idx; i++) {
- data = MDSS_MDP_REG_READ(offset);
+ data = readl_relaxed(addr);
gc_data[i].offset = data & 0x7FFF;
}
}
-static int pp_read_argc_lut(struct mdp_pgc_lut_data *config, u32 offset)
+static int pp_read_argc_lut(struct mdp_pgc_lut_data *config, char __iomem *addr)
{
int ret = 0;
- pp_read_gc_one_lut(offset, config->r_data);
- offset += 0x10;
- pp_read_gc_one_lut(offset, config->g_data);
- offset += 0x10;
- pp_read_gc_one_lut(offset, config->b_data);
+ pp_read_gc_one_lut(addr, config->r_data);
+ addr += 0x10;
+ pp_read_gc_one_lut(addr, config->g_data);
+ addr += 0x10;
+ pp_read_gc_one_lut(addr, config->b_data);
return ret;
}
/* Note: Assumes that its inputs have been checked by calling function */
-static void pp_update_hist_lut(char __iomem *offset,
+static void pp_update_hist_lut(char __iomem *addr,
struct mdp_hist_lut_data *cfg)
{
int i;
for (i = 0; i < ENHIST_LUT_ENTRIES; i++)
- writel_relaxed(cfg->data[i], offset);
+ writel_relaxed(cfg->data[i], addr);
/* swap */
if (PP_LOCAT(cfg->block) == MDSS_PP_DSPP_CFG)
- writel_relaxed(1, offset + 4);
+ writel_relaxed(1, addr + 4);
else
- writel_relaxed(1, offset + 16);
+ writel_relaxed(1, addr + 16);
}
int mdss_mdp_argc_config(struct mdp_pgc_lut_data *config,
u32 *copyback)
{
int ret = 0;
- u32 argc_offset = 0, disp_num, dspp_num = 0;
+ u32 disp_num, dspp_num = 0;
struct mdp_pgc_lut_data local_cfg;
struct mdp_pgc_lut_data *pgc_ptr;
u32 tbl_size, r_size, g_size, b_size;
+ char __iomem *argc_addr = 0;
if ((PP_BLOCK(config->block) < MDP_LOGICAL_BLOCK_DISP_0) ||
(PP_BLOCK(config->block) >= MDP_BLOCK_MAX))
return -EINVAL;
+ if ((config->flags & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
+ pr_warn("Can't set both split bits\n");
+ return -EINVAL;
+ }
+
mutex_lock(&mdss_pp_mutex);
disp_num = PP_BLOCK(config->block) - MDP_LOGICAL_BLOCK_DISP_0;
switch (PP_LOCAT(config->block)) {
case MDSS_PP_LM_CFG:
- argc_offset = MDSS_MDP_REG_LM_OFFSET(dspp_num) +
+ argc_addr = mdss_mdp_get_mixer_addr_off(dspp_num) +
MDSS_MDP_REG_LM_GC_LUT_BASE;
pgc_ptr = &mdss_pp_res->argc_disp_cfg[disp_num];
mdss_pp_res->pp_disp_flags[disp_num] |=
PP_FLAGS_DIRTY_ARGC;
break;
case MDSS_PP_DSPP_CFG:
- argc_offset = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) +
+ argc_addr = mdss_mdp_get_dspp_addr_off(dspp_num) +
MDSS_MDP_REG_DSPP_GC_BASE;
pgc_ptr = &mdss_pp_res->pgc_disp_cfg[disp_num];
mdss_pp_res->pp_disp_flags[disp_num] |=
@@ -1903,7 +2540,7 @@
&mdss_pp_res->gc_lut_g[disp_num][0];
local_cfg.b_data =
&mdss_pp_res->gc_lut_b[disp_num][0];
- pp_read_argc_lut(&local_cfg, argc_offset);
+ pp_read_argc_lut(&local_cfg, argc_addr);
if (copy_to_user(config->r_data,
&mdss_pp_res->gc_lut_r[disp_num][0], tbl_size)) {
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
@@ -1974,7 +2611,8 @@
u32 *copyback)
{
int i, ret = 0;
- u32 hist_offset, disp_num, dspp_num = 0;
+ u32 disp_num, dspp_num = 0;
+ char __iomem *hist_addr;
if ((PP_BLOCK(config->block) < MDP_LOGICAL_BLOCK_DISP_0) ||
(PP_BLOCK(config->block) >= MDP_BLOCK_MAX))
@@ -1992,11 +2630,11 @@
}
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
- hist_offset = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) +
+ hist_addr = mdss_mdp_get_dspp_addr_off(dspp_num) +
MDSS_MDP_REG_DSPP_HIST_LUT_BASE;
for (i = 0; i < ENHIST_LUT_ENTRIES; i++)
mdss_pp_res->enhist_lut[disp_num][i] =
- MDSS_MDP_REG_READ(hist_offset);
+ readl_relaxed(hist_addr);
if (copy_to_user(config->data,
&mdss_pp_res->enhist_lut[disp_num][0],
ENHIST_LUT_ENTRIES * sizeof(u32))) {
@@ -2033,6 +2671,11 @@
if (config->flags & MDP_PP_OPS_READ)
return -ENOTSUPP;
+ if ((config->flags & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
+ pr_warn("Can't set both split bits\n");
+ return -EINVAL;
+ }
+
mutex_lock(&mdss_pp_mutex);
disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
mdss_pp_res->dither_disp_cfg[disp_num] = *config;
@@ -2067,13 +2710,13 @@
u32 *copyback)
{
int i, j, ret = 0;
- u32 offset, disp_num, dspp_num = 0;
+ u32 disp_num, dspp_num = 0;
uint16_t *tbl_off;
struct mdp_gamut_cfg_data local_cfg;
uint16_t *r_tbl[MDP_GAMUT_TABLE_NUM];
uint16_t *g_tbl[MDP_GAMUT_TABLE_NUM];
uint16_t *b_tbl[MDP_GAMUT_TABLE_NUM];
-
+ char __iomem *addr;
if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
(config->block >= MDP_BLOCK_MAX))
@@ -2082,6 +2725,11 @@
if (pp_gm_has_invalid_lut_size(config))
return -EINVAL;
+ if ((config->flags & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
+ pr_warn("Can't set both split bits\n");
+ return -EINVAL;
+ }
+
mutex_lock(&mdss_pp_mutex);
disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
@@ -2094,7 +2742,7 @@
}
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
- offset = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) +
+ addr = mdss_mdp_get_dspp_addr_off(dspp_num) +
MDSS_MDP_REG_DSPP_GAMUT_BASE;
for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
r_tbl[i] = kzalloc(
@@ -2106,8 +2754,8 @@
}
for (j = 0; j < config->tbl_size[i]; j++)
r_tbl[i][j] =
- (u16)MDSS_MDP_REG_READ(offset);
- offset += 4;
+ (u16)readl_relaxed(addr);
+ addr += 4;
ret = copy_to_user(config->r_tbl[i], r_tbl[i],
sizeof(uint16_t) * config->tbl_size[i]);
kfree(r_tbl[i]);
@@ -2127,8 +2775,8 @@
}
for (j = 0; j < config->tbl_size[i]; j++)
g_tbl[i][j] =
- (u16)MDSS_MDP_REG_READ(offset);
- offset += 4;
+ (u16)readl_relaxed(addr);
+ addr += 4;
ret = copy_to_user(config->g_tbl[i], g_tbl[i],
sizeof(uint16_t) * config->tbl_size[i]);
kfree(g_tbl[i]);
@@ -2148,8 +2796,8 @@
}
for (j = 0; j < config->tbl_size[i]; j++)
b_tbl[i][j] =
- (u16)MDSS_MDP_REG_READ(offset);
- offset += 4;
+ (u16)readl_relaxed(addr);
+ addr += 4;
ret = copy_to_user(config->b_tbl[i], b_tbl[i],
sizeof(uint16_t) * config->tbl_size[i]);
kfree(b_tbl[i]);
@@ -2198,19 +2846,27 @@
mutex_unlock(&mdss_pp_mutex);
return ret;
}
-static void pp_hist_read(char __iomem *v_base,
+
+static u32 pp_hist_read(char __iomem *v_addr,
struct pp_hist_col_info *hist_info)
{
int i, i_start;
+ u32 sum = 0;
u32 data;
- data = readl_relaxed(v_base);
+ data = readl_relaxed(v_addr);
i_start = data >> 24;
hist_info->data[i_start] = data & 0xFFFFFF;
- for (i = i_start + 1; i < HIST_V_SIZE; i++)
- hist_info->data[i] = readl_relaxed(v_base) & 0xFFFFFF;
- for (i = 0; i < i_start - 1; i++)
- hist_info->data[i] = readl_relaxed(v_base) & 0xFFFFFF;
+ sum += hist_info->data[i_start];
+ for (i = i_start + 1; i < HIST_V_SIZE; i++) {
+ hist_info->data[i] = readl_relaxed(v_addr) & 0xFFFFFF;
+ sum += hist_info->data[i];
+ }
+ for (i = 0; i < i_start; i++) {
+ hist_info->data[i] = readl_relaxed(v_addr) & 0xFFFFFF;
+ sum += hist_info->data[i];
+ }
hist_info->hist_cnt_read++;
+ return sum;
}
/* Assumes that relevant clocks are enabled */
@@ -2220,6 +2876,8 @@
{
unsigned long flag;
int ret = 0;
+ struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+
mutex_lock(&hist_info->hist_mutex);
/* check if it is idle */
if (hist_info->col_en) {
@@ -2234,12 +2892,11 @@
hist_info->hist_cnt_sent = 0;
hist_info->hist_cnt_time = 0;
spin_lock_irqsave(&hist_info->hist_lock, flag);
- hist_info->read_request = false;
+ hist_info->read_request = 0;
hist_info->col_state = HIST_RESET;
hist_info->col_en = true;
spin_unlock_irqrestore(&hist_info->hist_lock, flag);
- hist_info->is_kick_ready = true;
- mdss_mdp_hist_irq_enable(3 << shift_bit);
+ mdss_mdp_hist_intr_req(&mdata->hist_intr, 3 << shift_bit, true);
writel_relaxed(req->frame_cnt, ctl_base + 8);
/* Kick out reset start */
writel_relaxed(1, ctl_base + 4);
@@ -2248,7 +2905,8 @@
return ret;
}
-int mdss_mdp_histogram_start(struct mdp_histogram_start_req *req)
+#define MDSS_MAX_HIST_BIN_SIZE 16777215
+int mdss_mdp_hist_start(struct mdp_histogram_start_req *req)
{
u32 done_shift_bit;
char __iomem *ctl_base;
@@ -2256,9 +2914,13 @@
int i, ret = 0;
u32 disp_num, dspp_num = 0;
u32 mixer_cnt, mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
+ u32 frame_size;
struct mdss_mdp_pipe *pipe;
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+ if (!mdss_is_ready())
+ return -EPROBE_DEFER;
+
if ((PP_BLOCK(req->block) < MDP_LOGICAL_BLOCK_DISP_0) ||
(PP_BLOCK(req->block) >= MDP_BLOCK_MAX))
return -EINVAL;
@@ -2278,6 +2940,16 @@
ret = -EPERM;
goto hist_exit;
}
+
+ frame_size = (mdata->ctl_off[mixer_id[0]].width *
+ mdata->ctl_off[mixer_id[0]].height);
+ if (!frame_size ||
+ ((MDSS_MAX_HIST_BIN_SIZE / frame_size) < req->frame_cnt)) {
+ pr_err("%s, too many frames for given display size, %d",
+ __func__, req->frame_cnt);
+ ret = -EINVAL;
+ goto hist_exit;
+ }
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
if (PP_LOCAT(req->block) == MDSS_PP_SSPP_CFG) {
@@ -2285,7 +2957,7 @@
if (!i) {
ret = -EINVAL;
pr_warn("Must pass pipe arguments, %d", i);
- goto hist_exit;
+ goto hist_stop_clk;
}
for (i = 0; i < MDSS_PP_ARG_NUM; i++) {
@@ -2295,10 +2967,9 @@
if (IS_ERR_OR_NULL(pipe))
continue;
if (!pipe || pipe->num > MDSS_MDP_SSPP_VIG2) {
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
ret = -EINVAL;
pr_warn("Invalid Hist pipe (%d)", i);
- goto hist_exit;
+ goto hist_stop_clk;
}
done_shift_bit = (pipe->num * 4);
hist_info = &pipe->pp_res.hist;
@@ -2321,8 +2992,8 @@
PP_FLAGS_DIRTY_HIST_COL;
}
}
+hist_stop_clk:
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
-
hist_exit:
return ret;
}
@@ -2332,6 +3003,8 @@
{
int ret = 0;
unsigned long flag;
+ struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+
mutex_lock(&hist_info->hist_mutex);
if (hist_info->col_en == false) {
pr_debug("Histogram already disabled (%d)", (u32) ctl_base);
@@ -2343,8 +3016,7 @@
hist_info->col_en = false;
hist_info->col_state = HIST_UNKNOWN;
spin_unlock_irqrestore(&hist_info->hist_lock, flag);
- hist_info->is_kick_ready = false;
- mdss_mdp_hist_irq_disable(done_bit);
+ mdss_mdp_hist_intr_req(&mdata->hist_intr, done_bit, false);
writel_relaxed(BIT(1), ctl_base);/* cancel */
ret = 0;
exit:
@@ -2352,7 +3024,7 @@
return ret;
}
-int mdss_mdp_histogram_stop(u32 block)
+int mdss_mdp_hist_stop(u32 block)
{
int i, ret = 0;
char __iomem *ctl_base;
@@ -2429,12 +3101,156 @@
return ret;
}
+/**
+ * mdss_mdp_hist_intr_req() - Request changes the histogram interupts
+ * @intr: structure containting state of interrupt register
+ * @bits: the bits on interrupt register that should be changed
+ * @en: true if bits should be set, false if bits should be cleared
+ *
+ * Adds or removes the bits from the interrupt request.
+ *
+ * Does not store reference count for each bit. I.e. a bit with multiple
+ * enable requests can be disabled with a single disable request.
+ *
+ * Return: 0 if uneventful, errno on invalid input
+ */
+int mdss_mdp_hist_intr_req(struct mdss_intr *intr, u32 bits, bool en)
+{
+ unsigned long flag;
+ int ret = 0;
+ if (!intr) {
+ pr_err("NULL addr passed, %p", intr);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&intr->lock, flag);
+ if (en)
+ intr->req |= bits;
+ else
+ intr->req &= ~bits;
+ spin_unlock_irqrestore(&intr->lock, flag);
+
+ mdss_mdp_hist_intr_setup(intr, MDSS_IRQ_REQ);
+
+ return ret;
+}
+
+
+#define MDSS_INTR_STATE_ACTIVE 1
+#define MDSS_INTR_STATE_NULL 0
+#define MDSS_INTR_STATE_SUSPEND -1
+
+/**
+ * mdss_mdp_hist_intr_setup() - Manage intr and clk depending on requests.
+ * @intr: structure containting state of intr reg
+ * @state: MDSS_IRQ_SUSPEND if suspend is needed,
+ * MDSS_IRQ_RESUME if resume is needed,
+ * MDSS_IRQ_REQ if neither (i.e. requesting an interrupt)
+ *
+ * This function acts as a gatekeeper for the interrupt, making sure that the
+ * MDP clocks are enabled while the interrupts are enabled to prevent
+ * unclocked accesses.
+ *
+ * To reduce code repetition, 4 state transitions have been encoded here. Each
+ * transition updates the interrupt's state structure (mdss_intr) to reflect
+ * the which bits have been requested (intr->req), are currently enabled
+ * (intr->curr), as well as defines which interrupt bits need to be enabled or
+ * disabled ('en' and 'dis' respectively). The 4th state is not explicity
+ * coded in the if/else chain, but is for MDSS_IRQ_REQ's when the interrupt
+ * is in suspend, in which case, the only change required (intr->req being
+ * updated) has already occured in the calling function.
+ *
+ * To control the clock, which can't be requested while holding the spinlock,
+ * the inital state is compared with the exit state to detect when the
+ * interrupt needs a clock.
+ *
+ * The clock requests surrounding the majority of this function serve to
+ * enable the register writes to change the interrupt register, as well as to
+ * prevent a race condition that could keep the clocks on (due to mdp_clk_cnt
+ * never being decremented below 0) when a enable/disable occurs but the
+ * disable requests the clocks disabled before the enable is able to request
+ * the clocks enabled.
+ *
+ * Return: 0 if uneventful, errno on repeated action or invalid input
+ */
+int mdss_mdp_hist_intr_setup(struct mdss_intr *intr, int type)
+{
+ unsigned long flag;
+ int ret = 0, req_clk = 0;
+ u32 en = 0, dis = 0;
+ u32 diff, init_curr;
+ int init_state;
+ if (!intr) {
+ WARN(1, "NULL intr pointer");
+ return -EINVAL;
+ }
+
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ spin_lock_irqsave(&intr->lock, flag);
+
+ init_state = intr->state;
+ init_curr = intr->curr;
+
+ if (type == MDSS_IRQ_RESUME) {
+ /* resume intrs */
+ if (intr->state == MDSS_INTR_STATE_ACTIVE) {
+ ret = -EPERM;
+ goto exit;
+ }
+ en = intr->req;
+ dis = 0;
+ intr->curr = intr->req;
+ intr->state = intr->curr ?
+ MDSS_INTR_STATE_ACTIVE : MDSS_INTR_STATE_NULL;
+ } else if (type == MDSS_IRQ_SUSPEND) {
+ /* suspend intrs */
+ if (intr->state == MDSS_INTR_STATE_SUSPEND) {
+ ret = -EPERM;
+ goto exit;
+ }
+ en = 0;
+ dis = intr->curr;
+ intr->curr = 0;
+ intr->state = MDSS_INTR_STATE_SUSPEND;
+ } else if (intr->state != MDSS_IRQ_SUSPEND) {
+ /* Not resuming/suspending or in suspend state */
+ diff = intr->req ^ intr->curr;
+ en = diff & ~intr->curr;
+ dis = diff & ~intr->req;
+ intr->curr = intr->req;
+ intr->state = intr->curr ?
+ MDSS_INTR_STATE_ACTIVE : MDSS_INTR_STATE_NULL;
+ }
+
+ if (en)
+ mdss_mdp_hist_irq_enable(en);
+ if (dis)
+ mdss_mdp_hist_irq_disable(dis);
+
+ if ((init_state != MDSS_INTR_STATE_ACTIVE) &&
+ (intr->state == MDSS_INTR_STATE_ACTIVE))
+ req_clk = 1;
+ else if ((init_state == MDSS_INTR_STATE_ACTIVE) &&
+ (intr->state != MDSS_INTR_STATE_ACTIVE))
+ req_clk = -1;
+
+exit:
+ spin_unlock_irqrestore(&intr->lock, flag);
+ if (req_clk < 0)
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ else if (req_clk > 0)
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ return ret;
+}
+
static int pp_hist_collect(struct mdp_histogram_data *hist,
struct pp_hist_col_info *hist_info,
- char __iomem *ctl_base)
+ char __iomem *ctl_base, u32 expect_sum)
{
int wait_ret, ret = 0;
- u32 timeout;
+ u32 timeout, sum;
char __iomem *v_base;
unsigned long flag;
struct mdss_pipe_pp_res *res;
@@ -2449,7 +3265,6 @@
spin_lock_irqsave(&hist_info->hist_lock, flag);
/* wait for hist done if cache has no data */
if (hist_info->col_state != HIST_READY) {
- hist_info->read_request = true;
spin_unlock_irqrestore(&hist_info->hist_lock, flag);
timeout = HIST_WAIT_TIMEOUT(hist_info->frame_cnt);
mutex_unlock(&hist_info->hist_mutex);
@@ -2489,9 +3304,11 @@
}
if (hist_info->col_state != HIST_READY) {
ret = -ENODATA;
+ spin_lock_irqsave(&hist_info->hist_lock, flag);
+ hist_info->col_state = HIST_READY;
+ spin_unlock_irqrestore(&hist_info->hist_lock, flag);
pr_debug("%s: state is not ready: %d",
__func__, hist_info->col_state);
- goto hist_collect_exit;
}
} else {
spin_unlock_irqrestore(&hist_info->hist_lock, flag);
@@ -2501,10 +3318,11 @@
spin_unlock_irqrestore(&hist_info->hist_lock, flag);
v_base = ctl_base + 0x1C;
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
- pp_hist_read(v_base, hist_info);
+ sum = pp_hist_read(v_base, hist_info);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
spin_lock_irqsave(&hist_info->hist_lock, flag);
- hist_info->read_request = false;
+ if (expect_sum && sum != expect_sum)
+ ret = -ENODATA;
hist_info->col_state = HIST_IDLE;
}
spin_unlock_irqrestore(&hist_info->hist_lock, flag);
@@ -2515,8 +3333,9 @@
int mdss_mdp_hist_collect(struct mdp_histogram_data *hist)
{
- int i, j, off, ret = 0;
+ int i, j, off, ret = 0, temp_ret = 0;
struct pp_hist_col_info *hist_info;
+ struct pp_hist_col_info *hists[MDSS_MDP_INTF_MAX_LAYERMIXER];
u32 dspp_num, disp_num;
char __iomem *ctl_base;
u32 hist_cnt, mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
@@ -2524,8 +3343,10 @@
u32 *hist_data_addr;
u32 pipe_cnt = 0;
u32 pipe_num = MDSS_MDP_SSPP_VIG0;
+ u32 exp_sum = 0;
struct mdss_mdp_pipe *pipe;
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+ unsigned long flag;
if ((PP_BLOCK(hist->block) < MDP_LOGICAL_BLOCK_DISP_0) ||
(PP_BLOCK(hist->block) >= MDP_BLOCK_MAX))
@@ -2546,17 +3367,41 @@
ret = -EPERM;
goto hist_collect_exit;
}
+
if (PP_LOCAT(hist->block) == MDSS_PP_DSPP_CFG) {
- hist_info = &mdss_pp_res->dspp_hist[disp_num];
for (i = 0; i < hist_cnt; i++) {
dspp_num = mixer_id[i];
- hist_info = &mdss_pp_res->dspp_hist[dspp_num];
+ hists[i] = &mdss_pp_res->dspp_hist[dspp_num];
+ }
+ for (i = 0; i < hist_cnt; i++) {
+ spin_lock_irqsave(&hists[i]->hist_lock, flag);
+ /* mark that collect is ready to handle completions */
+ hists[i]->read_request = 1;
+ spin_unlock_irqrestore(&hists[i]->hist_lock, flag);
+ }
+ for (i = 0; i < hist_cnt; i++) {
+ dspp_num = mixer_id[i];
ctl_base = mdss_mdp_get_dspp_addr_off(dspp_num) +
MDSS_MDP_REG_DSPP_HIST_CTL_BASE;
- ret = pp_hist_collect(hist, hist_info, ctl_base);
+ exp_sum = (mdata->mixer_intf[dspp_num].width *
+ mdata->mixer_intf[dspp_num].height);
if (ret)
- goto hist_collect_exit;
+ temp_ret = ret;
+ ret = pp_hist_collect(hist, hists[i], ctl_base,
+ exp_sum);
}
+ for (i = 0; i < hist_cnt; i++) {
+ /* reset read requests and re-intialize completions */
+ spin_lock_irqsave(&hists[i]->hist_lock, flag);
+ hists[i]->read_request = 0;
+ INIT_COMPLETION(hists[i]->comp);
+ spin_unlock_irqrestore(&hists[i]->hist_lock, flag);
+ }
+ if (ret || temp_ret) {
+ ret = ret ? ret : temp_ret;
+ goto hist_collect_exit;
+ }
+
if (hist->bin_cnt != HIST_V_SIZE) {
pr_err("User not expecting size %d output",
HIST_V_SIZE);
@@ -2572,19 +3417,19 @@
}
memset(hist_concat, 0, HIST_V_SIZE * sizeof(u32));
for (i = 0; i < hist_cnt; i++) {
- dspp_num = mixer_id[i];
- hist_info = &mdss_pp_res->dspp_hist[dspp_num];
- mutex_lock(&hist_info->hist_mutex);
+ mutex_lock(&hists[i]->hist_mutex);
for (j = 0; j < HIST_V_SIZE; j++)
- hist_concat[j] += hist_info->data[j];
- mutex_unlock(&hist_info->hist_mutex);
+ hist_concat[j] += hists[i]->data[j];
+ mutex_unlock(&hists[i]->hist_mutex);
}
hist_data_addr = hist_concat;
} else {
- hist_data_addr = hist_info->data;
+ hist_data_addr = hists[0]->data;
}
- hist_info = &mdss_pp_res->dspp_hist[disp_num];
- hist_info->hist_cnt_sent++;
+
+ for (i = 0; i < hist_cnt; i++)
+ hists[i]->hist_cnt_sent++;
+
} else if (PP_LOCAT(hist->block) == MDSS_PP_SSPP_CFG) {
hist_cnt = MDSS_PP_ARG_MASK & hist->block;
@@ -2620,13 +3465,50 @@
continue;
}
hist_info = &pipe->pp_res.hist;
+ spin_lock_irqsave(&hist_info->hist_lock, flag);
+ hist_info->read_request = 1;
+ spin_unlock_irqrestore(&hist_info->hist_lock, flag);
+ }
+ for (i = pipe_num; i < MDSS_PP_ARG_NUM; i++) {
+ if (!PP_ARG(i, hist->block))
+ continue;
+ pipe_cnt++;
+ pipe = mdss_mdp_pipe_get(mdata, BIT(i));
+ if (IS_ERR_OR_NULL(pipe) ||
+ pipe->num > MDSS_MDP_SSPP_VIG2) {
+ pr_warn("Invalid Hist pipe (%d)", i);
+ continue;
+ }
+ hist_info = &pipe->pp_res.hist;
ctl_base = pipe->base +
MDSS_MDP_REG_VIG_HIST_CTL_BASE;
- ret = pp_hist_collect(hist, hist_info, ctl_base);
- mdss_mdp_pipe_unmap(pipe);
if (ret)
- goto hist_collect_exit;
+ temp_ret = ret;
+ ret = pp_hist_collect(hist, hist_info, ctl_base,
+ exp_sum);
+ mdss_mdp_pipe_unmap(pipe);
}
+ for (i = pipe_num; i < MDSS_PP_ARG_NUM; i++) {
+ if (!PP_ARG(i, hist->block))
+ continue;
+ pipe_cnt++;
+ pipe = mdss_mdp_pipe_get(mdata, BIT(i));
+ if (IS_ERR_OR_NULL(pipe) ||
+ pipe->num > MDSS_MDP_SSPP_VIG2) {
+ pr_warn("Invalid Hist pipe (%d)", i);
+ continue;
+ }
+ hist_info = &pipe->pp_res.hist;
+ spin_lock_irqsave(&hist_info->hist_lock, flag);
+ hist_info->read_request = 0;
+ INIT_COMPLETION(hist_info->comp);
+ spin_unlock_irqrestore(&hist_info->hist_lock, flag);
+ }
+ if (ret || temp_ret) {
+ ret = ret ? ret : temp_ret;
+ goto hist_collect_exit;
+ }
+
if (pipe_cnt != 0 &&
(hist->bin_cnt != (HIST_V_SIZE * pipe_cnt))) {
pr_err("User not expecting size %d output",
@@ -2724,8 +3606,10 @@
spin_lock(&hist_info->hist_lock);
hist_info->col_state = HIST_READY;
spin_unlock(&hist_info->hist_lock);
- if (hist_info->read_request)
+ if (hist_info->read_request == 1) {
complete(&hist_info->comp);
+ hist_info->read_request++;
+ }
}
/* Histogram Reset Done Interrupt */
if ((isr_blk & 0x2) &&
@@ -2753,7 +3637,53 @@
return out;
}
-#define MDSS_AD_MAX_MIXERS 1
+static int pp_num_to_side(struct mdss_mdp_ctl *ctl, u32 num)
+{
+ u32 mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
+ u32 mixer_num;
+
+ if (!ctl || !ctl->mfd)
+ return -EINVAL;
+ mixer_num = mdss_mdp_get_ctl_mixers(ctl->mfd->index, mixer_id);
+ if (mixer_num < 2)
+ return MDSS_SIDE_NONE;
+ else if (mixer_id[1] == num)
+ return MDSS_SIDE_RIGHT;
+ else if (mixer_id[0] == num)
+ return MDSS_SIDE_LEFT;
+ else
+ pr_err("invalid, not on any side");
+ return -EINVAL;
+}
+
+static inline void pp_sts_set_split_bits(u32 *sts, u32 bits)
+{
+ u32 tmp = *sts;
+ tmp &= ~MDSS_PP_SPLIT_MASK;
+ tmp |= bits & MDSS_PP_SPLIT_MASK;
+ *sts = tmp;
+}
+
+static inline bool pp_sts_is_enabled(u32 sts, int side)
+{
+ bool ret = false;
+ /*
+ * If there are no sides, or if there are no split mode bits set, the
+ * side can't be disabled via split mode.
+ *
+ * Otherwise, if the side being checked opposes the split mode
+ * configuration, the side is disabled.
+ */
+ if ((side == MDSS_SIDE_NONE) || !(sts & MDSS_PP_SPLIT_MASK))
+ ret = true;
+ else if ((sts & MDSS_PP_SPLIT_RIGHT_ONLY) && (side == MDSS_SIDE_RIGHT))
+ ret = true;
+ else if ((sts & MDSS_PP_SPLIT_LEFT_ONLY) && (side == MDSS_SIDE_LEFT))
+ ret = true;
+
+ return ret && (sts & PP_STS_ENABLE);
+}
+
static int mdss_ad_init_checks(struct msm_fb_data_type *mfd)
{
u32 mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
@@ -2779,8 +3709,9 @@
pr_debug("no mixers connected, %d", mixer_num);
return -EHOSTDOWN;
}
- if (mixer_num > MDSS_AD_MAX_MIXERS) {
- pr_debug("too many mixers, not supported, %d", mixer_num);
+ if (mixer_num > mdata->nmax_concurrent_ad_hw) {
+ pr_debug("too many mixers, not supported, %d > %d", mixer_num,
+ mdata->nmax_concurrent_ad_hw);
return ret;
}
@@ -2846,10 +3777,9 @@
struct mdss_ad_init_cfg *init_cfg)
{
struct mdss_ad_info *ad;
- struct mdss_mdp_ctl *ctl;
struct msm_fb_data_type *bl_mfd;
int lin_ret = -1, inv_ret = -1, ret = 0;
- u32 ratio_temp, shift = 0;
+ u32 ratio_temp, shift = 0, last_ops;
ret = mdss_mdp_get_ad(mfd, &ad);
if (ret)
@@ -2862,6 +3792,11 @@
bl_mfd = mfd;
}
+ if ((init_cfg->ops & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
+ pr_warn("Can't set both split bits\n");
+ return -EINVAL;
+ }
+
mutex_lock(&ad->lock);
if (init_cfg->ops & MDP_PP_AD_INIT) {
memcpy(&ad->init, &init_cfg->params.init,
@@ -2869,10 +3804,12 @@
if (init_cfg->params.init.bl_lin_len == AD_BL_LIN_LEN) {
lin_ret = copy_from_user(&ad->bl_lin,
init_cfg->params.init.bl_lin,
- AD_BL_LIN_LEN * sizeof(uint32_t));
+ init_cfg->params.init.bl_lin_len *
+ sizeof(uint32_t));
inv_ret = copy_from_user(&ad->bl_lin_inv,
init_cfg->params.init.bl_lin_inv,
- AD_BL_LIN_LEN * sizeof(uint32_t));
+ init_cfg->params.init.bl_lin_len *
+ sizeof(uint32_t));
if (lin_ret || inv_ret)
ret = -ENOMEM;
ratio_temp = mfd->panel_info->bl_max / AD_BL_LIN_LEN;
@@ -2881,13 +3818,14 @@
shift++;
}
ad->bl_bright_shift = shift;
- } else if (init_cfg->params.init.bl_lin_len) {
+ } else {
ret = -EINVAL;
}
- if (!lin_ret && !inv_ret)
+ if (ret) {
+ ad->state &= ~PP_AD_STATE_BL_LIN;
+ goto ad_config_exit;
+ } else
ad->state |= PP_AD_STATE_BL_LIN;
- else
- ad->state &= !PP_AD_STATE_BL_LIN;
ad->sts |= PP_AD_STS_DIRTY_INIT;
} else if (init_cfg->ops & MDP_PP_AD_CFG) {
@@ -2901,6 +3839,22 @@
ad->sts |= PP_AD_STS_DIRTY_CFG;
}
+ last_ops = ad->ops & MDSS_PP_SPLIT_MASK;
+ ad->ops = init_cfg->ops & MDSS_PP_SPLIT_MASK;
+ /*
+ * if there is a change in the split mode config, the init values
+ * need to be re-written to hardware (if they have already been
+ * written or if there is data pending to be written). Check for
+ * pending data (DIRTY_INIT) is not checked here since it will not
+ * affect the outcome of this conditional (i.e. if init hasn't
+ * already been written (*_STATE_INIT is set), this conditional will
+ * only evaluate to true (and set the DIRTY bit) if the DIRTY bit has
+ * already been set).
+ */
+ if ((last_ops ^ ad->ops) && (ad->state & PP_AD_STATE_INIT))
+ ad->sts |= PP_AD_STS_DIRTY_INIT;
+
+
if (!ret && (init_cfg->ops & MDP_PP_OPS_DISABLE)) {
ad->sts &= ~PP_STS_ENABLE;
mutex_unlock(&ad->lock);
@@ -2913,8 +3867,8 @@
ad->mfd = mfd;
ad->bl_mfd = bl_mfd;
}
+ad_config_exit:
mutex_unlock(&ad->lock);
- ctl = mfd_to_ctl(mfd);
return ret;
}
@@ -2944,6 +3898,11 @@
ret = -EINVAL;
goto error;
}
+ if (input->in.amb_light > MDSS_MDP_MAX_AD_AL) {
+ pr_warn("invalid input ambient light");
+ ret = -EINVAL;
+ goto error;
+ }
ad->ad_data_mode = MDSS_AD_INPUT_AMBIENT;
pr_debug("ambient = %d", input->in.amb_light);
ad->ad_data = input->in.amb_light;
@@ -2958,6 +3917,11 @@
ret = -EINVAL;
goto error;
}
+ if (input->in.strength > MDSS_MDP_MAX_AD_STR) {
+ pr_warn("invalid input strength");
+ ret = -EINVAL;
+ goto error;
+ }
ad->ad_data_mode = MDSS_AD_INPUT_STRENGTH;
pr_debug("strength = %d", input->in.strength);
ad->ad_data = input->in.strength;
@@ -2976,7 +3940,7 @@
mutex_unlock(&ad->lock);
mutex_lock(&mfd->bl_lock);
MDSS_BRIGHT_TO_BL(bl, bl, mfd->panel_info->bl_max,
- MDSS_MAX_BL_BRIGHTNESS);
+ mfd->panel_info->brightness_max);
mdss_fb_set_backlight(mfd, bl);
mutex_unlock(&mfd->bl_lock);
mutex_lock(&ad->lock);
@@ -2998,7 +3962,7 @@
mutex_unlock(&ad->lock);
}
if (wait) {
- ret = wait_for_completion_interruptible_timeout(
+ ret = wait_for_completion_timeout(
&ad->comp, HIST_WAIT_TIMEOUT(1));
if (ret == 0)
ret = -ETIMEDOUT;
@@ -3009,23 +3973,26 @@
return ret;
}
-static void pp_ad_input_write(struct mdss_ad_info *ad, u32 bl_lvl)
+static void pp_ad_input_write(struct mdss_mdp_ad *ad_hw,
+ struct mdss_ad_info *ad)
{
- char __iomem *base = ad->base;
+ char __iomem *base;
+
+ base = ad_hw->base;
switch (ad->cfg.mode) {
case MDSS_AD_MODE_AUTO_BL:
writel_relaxed(ad->ad_data, base + MDSS_MDP_REG_AD_AL);
break;
case MDSS_AD_MODE_AUTO_STR:
- writel_relaxed(bl_lvl, base + MDSS_MDP_REG_AD_BL);
+ writel_relaxed(ad->bl_data, base + MDSS_MDP_REG_AD_BL);
writel_relaxed(ad->ad_data, base + MDSS_MDP_REG_AD_AL);
break;
case MDSS_AD_MODE_TARG_STR:
- writel_relaxed(bl_lvl, base + MDSS_MDP_REG_AD_BL);
+ writel_relaxed(ad->bl_data, base + MDSS_MDP_REG_AD_BL);
writel_relaxed(ad->ad_data, base + MDSS_MDP_REG_AD_TARG_STR);
break;
case MDSS_AD_MODE_MAN_STR:
- writel_relaxed(bl_lvl, base + MDSS_MDP_REG_AD_BL);
+ writel_relaxed(ad->bl_data, base + MDSS_MDP_REG_AD_BL);
writel_relaxed(ad->ad_data, base + MDSS_MDP_REG_AD_STR_MAN);
break;
default:
@@ -3034,10 +4001,29 @@
}
}
-static void pp_ad_init_write(struct mdss_ad_info *ad)
+#define MDSS_AD_MERGED_WIDTH 4
+static void pp_ad_init_write(struct mdss_mdp_ad *ad_hw, struct mdss_ad_info *ad,
+ struct mdss_mdp_ctl *ctl)
{
+ struct mdss_data_type *mdata = ctl->mdata;
u32 temp;
- char __iomem *base = ad->base;
+ u32 frame_start, frame_end, procs_start, procs_end, tile_ctrl;
+ u32 num;
+ int side;
+ char __iomem *base;
+ bool is_calc, is_dual_pipe, split_mode;
+ u32 mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
+ u32 mixer_num;
+ mixer_num = mdss_mdp_get_ctl_mixers(ctl->mfd->index, mixer_id);
+ if (mixer_num > 1)
+ is_dual_pipe = true;
+ else
+ is_dual_pipe = false;
+
+ base = ad_hw->base;
+ is_calc = ad->calc_hw_num == ad_hw->num;
+ split_mode = !!(ad->ops & MDSS_PP_SPLIT_MASK);
+
writel_relaxed(ad->init.i_control[0] & 0x1F,
base + MDSS_MDP_REG_AD_CON_CTRL_0);
writel_relaxed(ad->init.i_control[1] << 8,
@@ -3062,7 +4048,10 @@
writel_relaxed(ad->init.format, base + MDSS_MDP_REG_AD_CTRL_0);
writel_relaxed(ad->init.auto_size, base + MDSS_MDP_REG_AD_CTRL_1);
- temp = ad->init.frame_w << 16;
+ if (split_mode)
+ temp = mdata->mixer_intf[ad_hw->num].width << 16;
+ else
+ temp = ad->init.frame_w << 16;
temp |= ad->init.frame_h & 0xFFFF;
writel_relaxed(temp, base + MDSS_MDP_REG_AD_FRAME_SIZE);
@@ -3072,13 +4061,64 @@
pp_ad_cfg_lut(base + MDSS_MDP_REG_AD_LUT_FI, ad->init.asym_lut);
pp_ad_cfg_lut(base + MDSS_MDP_REG_AD_LUT_CC, ad->init.color_corr_lut);
+
+ if (mdata->mdp_rev >= MDSS_MDP_HW_REV_103) {
+ if (is_dual_pipe && !split_mode) {
+ num = ad_hw->num;
+ side = pp_num_to_side(ctl, num);
+ tile_ctrl = 0x5;
+ if ((ad->calc_hw_num + 1) == num)
+ tile_ctrl |= 0x10;
+
+ if (side <= MDSS_SIDE_NONE) {
+ WARN(1, "error finding sides, %d", side);
+ frame_start = 0;
+ procs_start = frame_start;
+ frame_end = 0;
+ procs_end = frame_end;
+ } else if (side == MDSS_SIDE_LEFT) {
+ frame_start = 0;
+ procs_start = 0;
+ frame_end = mdata->mixer_intf[num].width +
+ MDSS_AD_MERGED_WIDTH;
+ procs_end = mdata->mixer_intf[num].width;
+ } else {
+ procs_start = ad->init.frame_w -
+ (mdata->mixer_intf[num].width);
+ procs_end = ad->init.frame_w;
+ frame_start = procs_start -
+ MDSS_AD_MERGED_WIDTH;
+ frame_end = procs_end;
+ }
+ procs_end -= 1;
+ frame_end -= 1;
+ } else {
+ frame_start = 0x0;
+ frame_end = 0xFFFF;
+ procs_start = 0x0;
+ procs_end = 0xFFFF;
+ if (split_mode)
+ tile_ctrl = 0x0;
+ else
+ tile_ctrl = 0x1;
+ }
+
+
+ writel_relaxed(frame_start, base + MDSS_MDP_REG_AD_FRAME_START);
+ writel_relaxed(frame_end, base + MDSS_MDP_REG_AD_FRAME_END);
+ writel_relaxed(procs_start, base + MDSS_MDP_REG_AD_PROCS_START);
+ writel_relaxed(procs_end, base + MDSS_MDP_REG_AD_PROCS_END);
+ writel_relaxed(tile_ctrl, base + MDSS_MDP_REG_AD_TILE_CTRL);
+ }
}
#define MDSS_PP_AD_DEF_CALIB 0x6E
-static void pp_ad_cfg_write(struct mdss_ad_info *ad)
+static void pp_ad_cfg_write(struct mdss_mdp_ad *ad_hw, struct mdss_ad_info *ad)
{
- char __iomem *base = ad->base;
+ char __iomem *base;
u32 temp, temp_calib = MDSS_PP_AD_DEF_CALIB;
+
+ base = ad_hw->base;
switch (ad->cfg.mode) {
case MDSS_AD_MODE_AUTO_BL:
temp = ad->cfg.backlight_max << 16;
@@ -3127,29 +4167,64 @@
}
#define MDSS_PP_AD_BYPASS_DEF 0x101
+static void pp_ad_bypass_config(struct mdss_ad_info *ad,
+ struct mdss_mdp_ctl *ctl, u32 num, u32 *opmode)
+{
+ int side = pp_num_to_side(ctl, num);
+
+ if (pp_sts_is_enabled(ad->reg_sts | (ad->ops & MDSS_PP_SPLIT_MASK),
+ side)) {
+ *opmode = 0;
+ } else {
+ *opmode = MDSS_PP_AD_BYPASS_DEF;
+ }
+}
+
+static int pp_ad_setup_hw_nums(struct msm_fb_data_type *mfd,
+ struct mdss_ad_info *ad)
+{
+ u32 mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
+ u32 mixer_num;
+
+ mixer_num = mdss_mdp_get_ctl_mixers(mfd->index, mixer_id);
+ if (!mixer_num)
+ return -EINVAL;
+
+ /* default to left mixer */
+ ad->calc_hw_num = mixer_id[0];
+ if ((mixer_num > 1) && (ad->ops & MDSS_PP_SPLIT_RIGHT_ONLY))
+ ad->calc_hw_num = mixer_id[1];
+ return 0;
+}
+
static int mdss_mdp_ad_setup(struct msm_fb_data_type *mfd)
{
int ret = 0;
struct mdss_ad_info *ad;
struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
struct msm_fb_data_type *bl_mfd;
- char __iomem *base;
- u32 temp;
+ struct mdss_data_type *mdata;
u32 bypass = MDSS_PP_AD_BYPASS_DEF, bl;
ret = mdss_mdp_get_ad(mfd, &ad);
- if (ret)
- return ret;
+ if (ret) {
+ ret = -EINVAL;
+ pr_debug("failed to get ad_info, err = %d", ret);
+ goto exit;
+ }
if (mfd->panel_info->type == WRITEBACK_PANEL) {
bl_mfd = mdss_get_mfd_from_index(0);
- if (!bl_mfd)
- return ret;
+ if (!bl_mfd) {
+ ret = -EINVAL;
+ pr_warn("failed to get primary FB bl handle, err = %d",
+ ret);
+ goto exit;
+ }
} else {
bl_mfd = mfd;
}
-
- base = ad->base;
+ mdata = mfd_to_mdata(mfd);
mutex_lock(&ad->lock);
if (ad->sts != last_sts || ad->state != last_state) {
@@ -3179,17 +4254,17 @@
bl = ad->bl_lin[bl >> ad->bl_bright_shift];
bl = bl << ad->bl_bright_shift;
}
- mutex_unlock(&bl_mfd->bl_lock);
+ ad->bl_data = bl;
}
- mutex_unlock(&mfd->bl_lock);
- pp_ad_input_write(ad, bl);
+ mutex_unlock(&bl_mfd->bl_lock);
+ ad->reg_sts |= PP_AD_STS_DIRTY_DATA;
}
if (ad->sts & PP_AD_STS_DIRTY_CFG) {
ad->sts &= ~PP_AD_STS_DIRTY_CFG;
ad->state |= PP_AD_STATE_CFG;
- pp_ad_cfg_write(ad);
+ ad->reg_sts |= PP_AD_STS_DIRTY_CFG;
if (!MDSS_AD_MODE_DATA_MATCH(ad->cfg.mode, ad->ad_data_mode)) {
ad->sts &= ~PP_AD_STS_DIRTY_DATA;
@@ -3199,8 +4274,13 @@
}
if (ad->sts & PP_AD_STS_DIRTY_INIT) {
ad->sts &= ~PP_AD_STS_DIRTY_INIT;
- ad->state |= PP_AD_STATE_INIT;
- pp_ad_init_write(ad);
+ if (pp_ad_setup_hw_nums(mfd, ad)) {
+ pr_warn("failed to setup ad master");
+ ad->calc_hw_num = PP_AD_BAD_HW_NUM;
+ } else {
+ ad->state |= PP_AD_STATE_INIT;
+ ad->reg_sts |= PP_AD_STS_DIRTY_INIT;
+ }
}
/* update ad screen size if it has changed since last configuration */
@@ -3213,14 +4293,12 @@
ctl->height);
ad->init.frame_w = ctl->width;
ad->init.frame_h = ctl->height;
- temp = ad->init.frame_w << 16;
- temp |= ad->init.frame_h & 0xFFFF;
- writel_relaxed(temp, base + MDSS_MDP_REG_AD_FRAME_SIZE);
+ ad->reg_sts |= PP_AD_STS_DIRTY_INIT;
}
if ((ad->sts & PP_STS_ENABLE) && PP_AD_STATE_IS_READY(ad->state)) {
bypass = 0;
- ret = 1;
+ ad->reg_sts |= PP_AD_STS_DIRTY_ENABLE;
ad->state |= PP_AD_STATE_RUN;
mutex_lock(&bl_mfd->bl_lock);
if (bl_mfd != mfd)
@@ -3231,7 +4309,7 @@
} else {
if (ad->state & PP_AD_STATE_RUN) {
- ret = 1;
+ ad->reg_sts = PP_AD_STS_DIRTY_ENABLE;
/* Clear state and regs when going to off state*/
ad->sts = 0;
ad->sts |= PP_AD_STS_DIRTY_VSYNC;
@@ -3244,6 +4322,7 @@
ad->ad_data_mode = 0;
ad->last_bl = 0;
ad->calc_itr = 0;
+ ad->calc_hw_num = PP_AD_BAD_HW_NUM;
memset(&ad->bl_lin, 0, sizeof(uint32_t) *
AD_BL_LIN_LEN);
memset(&ad->bl_lin_inv, 0, sizeof(uint32_t) *
@@ -3258,7 +4337,10 @@
}
ad->state &= ~PP_AD_STATE_RUN;
}
- writel_relaxed(bypass, base);
+ if (!bypass)
+ ad->reg_sts |= PP_STS_ENABLE;
+ else
+ ad->reg_sts &= ~PP_STS_ENABLE;
if (PP_AD_STS_DIRTY_VSYNC & ad->sts) {
pr_debug("dirty vsync, calc_itr = %d", ad->calc_itr);
@@ -3281,6 +4363,7 @@
ad->state);
}
mutex_unlock(&ad->lock);
+exit:
return ret;
}
@@ -3290,6 +4373,8 @@
struct mdss_ad_info *ad;
struct mdss_mdp_ctl *ctl;
struct msm_fb_data_type *mfd, *bl_mfd;
+ struct mdss_data_type *mdata;
+ char __iomem *base;
u32 bl, calc_done = 0;
ad = container_of(work, struct mdss_ad_info, calc_work);
@@ -3301,34 +4386,43 @@
mfd = ad->mfd;
bl_mfd = ad->bl_mfd;
ctl = mfd_to_ctl(ad->mfd);
+ mdata = mfd_to_mdata(ad->mfd);
+
+ if (!mdata || ad->calc_hw_num > mdata->nad_cfgs) {
+ mutex_unlock(&ad->lock);
+ return;
+ }
+
+
+ base = mdata->ad_off[ad->calc_hw_num].base;
if ((ad->cfg.mode == MDSS_AD_MODE_AUTO_STR) && (ad->last_bl == 0)) {
mutex_unlock(&ad->lock);
return;
}
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
if (PP_AD_STATE_RUN & ad->state) {
/* Kick off calculation */
ad->calc_itr--;
- writel_relaxed(1, ad->base + MDSS_MDP_REG_AD_START_CALC);
+ writel_relaxed(1, base + MDSS_MDP_REG_AD_START_CALC);
}
if (ad->state & PP_AD_STATE_RUN) {
do {
- calc_done = readl_relaxed(ad->base +
+ calc_done = readl_relaxed(base +
MDSS_MDP_REG_AD_CALC_DONE);
if (!calc_done)
usleep(MDSS_PP_AD_SLEEP);
} while (!calc_done && (ad->state & PP_AD_STATE_RUN));
if (calc_done) {
- ad->last_str = 0xFF & readl_relaxed(ad->base +
+ ad->last_str = 0xFF & readl_relaxed(base +
MDSS_MDP_REG_AD_STR_OUT);
if (MDSS_AD_RUNNING_AUTO_BL(ad)) {
- bl = 0xFFFF & readl_relaxed(ad->base +
+ bl = 0xFFFF & readl_relaxed(base +
MDSS_MDP_REG_AD_BL_OUT);
if (ad->state & PP_AD_STATE_BL_LIN) {
bl = bl >> ad->bl_bright_shift;
- bl = min_t(u32, bl,
- MDSS_MAX_BL_BRIGHTNESS);
+ bl = min_t(u32, bl, (AD_BL_LIN_LEN-1));
bl = ad->bl_lin_inv[bl];
bl = bl << ad->bl_bright_shift;
}
@@ -3346,6 +4440,7 @@
ad->last_str = 0xFFFFFFFF;
}
}
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
complete(&ad->comp);
if (!ad->calc_itr) {
@@ -3362,7 +4457,7 @@
}
#define PP_AD_LUT_LEN 33
-static void pp_ad_cfg_lut(char __iomem *offset, u32 *data)
+static void pp_ad_cfg_lut(char __iomem *addr, u32 *data)
{
int i;
u32 temp;
@@ -3370,30 +4465,43 @@
for (i = 0; i < PP_AD_LUT_LEN - 1; i += 2) {
temp = data[i+1] << 16;
temp |= (data[i] & 0xFFFF);
- writel_relaxed(temp, offset + (i*2));
+ writel_relaxed(temp, addr + (i*2));
}
writel_relaxed(data[PP_AD_LUT_LEN - 1] << 16,
- offset + ((PP_AD_LUT_LEN - 1) * 2));
+ addr + ((PP_AD_LUT_LEN - 1) * 2));
}
-int mdss_mdp_ad_addr_setup(struct mdss_data_type *mdata, u32 *ad_off)
+int mdss_mdp_ad_addr_setup(struct mdss_data_type *mdata, u32 *ad_offsets)
{
u32 i;
int rc = 0;
- mdata->ad_cfgs = devm_kzalloc(&mdata->pdev->dev,
- sizeof(struct mdss_ad_info) * mdata->nad_cfgs,
+ mdata->ad_off = devm_kzalloc(&mdata->pdev->dev,
+ sizeof(struct mdss_mdp_ad) * mdata->nad_cfgs,
GFP_KERNEL);
+ if (!mdata->ad_off) {
+ pr_err("unable to setup assertive display hw:devm_kzalloc fail\n");
+ return -ENOMEM;
+ }
+
+ mdata->ad_cfgs = devm_kzalloc(&mdata->pdev->dev,
+ sizeof(struct mdss_ad_info) * mdata->nad_cfgs,
+ GFP_KERNEL);
+
if (!mdata->ad_cfgs) {
pr_err("unable to setup assertive display:devm_kzalloc fail\n");
+ devm_kfree(&mdata->pdev->dev, mdata->ad_off);
return -ENOMEM;
}
mdata->ad_calc_wq = create_singlethread_workqueue("ad_calc_wq");
for (i = 0; i < mdata->nad_cfgs; i++) {
- mdata->ad_cfgs[i].base = mdata->mdp_base + ad_off[i];
+ mdata->ad_off[i].base = mdata->mdp_base + ad_offsets[i];
+ mdata->ad_off[i].num = i;
mdata->ad_cfgs[i].num = i;
+ mdata->ad_cfgs[i].ops = 0;
+ mdata->ad_cfgs[i].reg_sts = 0;
mdata->ad_cfgs[i].calc_itr = 0;
mdata->ad_cfgs[i].last_str = 0xFFFFFFFF;
mdata->ad_cfgs[i].last_bl = 0;
@@ -3405,71 +4513,298 @@
return rc;
}
-static int is_valid_calib_addr(void *addr)
+static int is_valid_calib_ctrl_addr(char __iomem *ptr)
+{
+ char __iomem *base;
+ int ret = 0, counter = 0;
+ int stage = 0;
+ struct mdss_mdp_ctl *ctl;
+
+ /* Controller */
+ for (counter = 0; counter < mdss_res->nctl; counter++) {
+ ctl = mdss_res->ctl_off + counter;
+ base = ctl->base;
+
+ if (ptr == base + MDSS_MDP_REG_CTL_TOP) {
+ ret = MDP_PP_OPS_READ;
+ break;
+ } else if (ptr == base + MDSS_MDP_REG_CTL_FLUSH) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ }
+
+ for (stage = 0; stage < mdss_res->nmixers_intf; stage++)
+ if (ptr == base + MDSS_MDP_REG_CTL_LAYER(stage)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ goto End;
+ }
+ }
+
+End:
+ return ret;
+}
+
+static int is_valid_calib_dspp_addr(char __iomem *ptr)
+{
+ char __iomem *base;
+ int ret = 0, counter = 0;
+ struct mdss_mdp_mixer *mixer;
+
+ for (counter = 0; counter < mdss_res->nmixers_intf; counter++) {
+ mixer = mdss_res->mixer_intf + counter;
+ base = mixer->dspp_base;
+
+ if (ptr == base) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ /* PA range */
+ } else if ((ptr >= base + MDSS_MDP_REG_DSPP_PA_BASE) &&
+ (ptr <= base + MDSS_MDP_REG_DSPP_PA_BASE +
+ MDSS_MDP_PA_SIZE)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ /* PCC range */
+ } else if ((ptr >= base + MDSS_MDP_REG_DSPP_PCC_BASE) &&
+ (ptr <= base + MDSS_MDP_REG_DSPP_PCC_BASE +
+ MDSS_MDP_PCC_SIZE)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ /* Gamut range */
+ } else if ((ptr >= base + MDSS_MDP_REG_DSPP_GAMUT_BASE) &&
+ (ptr <= base + MDSS_MDP_REG_DSPP_GAMUT_BASE +
+ MDSS_MDP_GAMUT_SIZE)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ /* GC range */
+ } else if ((ptr >= base + MDSS_MDP_REG_DSPP_GC_BASE) &&
+ (ptr <= base + MDSS_MDP_REG_DSPP_GC_BASE +
+ MDSS_MDP_GC_SIZE)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ /* Dither enable/disable */
+ } else if ((ptr == base + MDSS_MDP_REG_DSPP_DITHER_DEPTH)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ /* Six zone and mem color */
+ } else if (mdss_res->mdp_rev >= MDSS_MDP_HW_REV_103 &&
+ (ptr >= base + MDSS_MDP_REG_DSPP_SIX_ZONE_BASE) &&
+ (ptr <= base + MDSS_MDP_REG_DSPP_SIX_ZONE_BASE +
+ MDSS_MDP_SIX_ZONE_SIZE +
+ MDSS_MDP_MEM_COL_SIZE)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int is_valid_calib_vig_addr(char __iomem *ptr)
+{
+ char __iomem *base;
+ int ret = 0, counter = 0;
+ struct mdss_mdp_pipe *pipe;
+
+ for (counter = 0; counter < mdss_res->nvig_pipes; counter++) {
+ pipe = mdss_res->vig_pipes + counter;
+ base = pipe->base;
+
+ if (ptr == base + MDSS_MDP_REG_VIG_OP_MODE) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ } else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_FORMAT) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ } else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_CONSTANT_COLOR) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ } else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ } else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_OP_MODE) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ } else if ((ptr == base + MDSS_MDP_REG_VIG_QSEED2_SHARP)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ /* PA range */
+ } else if ((ptr >= base + MDSS_MDP_REG_VIG_PA_BASE) &&
+ (ptr <= base + MDSS_MDP_REG_VIG_PA_BASE +
+ MDSS_MDP_PA_SIZE)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ /* Mem color range */
+ } else if (mdss_res->mdp_rev >= MDSS_MDP_HW_REV_103 &&
+ (ptr >= base + MDSS_MDP_REG_VIG_MEM_COL_BASE) &&
+ (ptr <= base + MDSS_MDP_REG_VIG_MEM_COL_BASE +
+ MDSS_MDP_MEM_COL_SIZE)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ /* IGC range */
+ } else if ((ptr >= base + MDSS_MDP_REG_IGC_VIG_BASE) &&
+ (ptr <= base + MDSS_MDP_REG_IGC_VIG_BASE +
+ MDSS_MDP_GC_SIZE)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int is_valid_calib_rgb_addr(char __iomem *ptr)
+{
+ char __iomem *base;
+ int ret = 0, counter = 0;
+ struct mdss_mdp_pipe *pipe;
+
+ for (counter = 0; counter < mdss_res->nrgb_pipes; counter++) {
+ pipe = mdss_res->rgb_pipes + counter;
+ base = pipe->base;
+
+ if (ptr == base + MDSS_MDP_REG_SSPP_SRC_FORMAT) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ } else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_CONSTANT_COLOR) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ } else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ } else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_OP_MODE) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ /* IGC range */
+ } else if ((ptr >= base + MDSS_MDP_REG_IGC_RGB_BASE) &&
+ (ptr <= base + MDSS_MDP_REG_IGC_RGB_BASE +
+ MDSS_MDP_GC_SIZE)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int is_valid_calib_dma_addr(char __iomem *ptr)
+{
+ char __iomem *base;
+ int ret = 0, counter = 0;
+ struct mdss_mdp_pipe *pipe;
+
+ for (counter = 0; counter < mdss_res->ndma_pipes; counter++) {
+ pipe = mdss_res->dma_pipes + counter;
+ base = pipe->base;
+
+ if (ptr == base + MDSS_MDP_REG_SSPP_SRC_FORMAT) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ } else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_CONSTANT_COLOR) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ } else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ } else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_OP_MODE) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ /* IGC range */
+ } else if ((ptr >= base + MDSS_MDP_REG_IGC_DMA_BASE) &&
+ (ptr <= base + MDSS_MDP_REG_IGC_DMA_BASE +
+ MDSS_MDP_GC_SIZE)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int is_valid_calib_mixer_addr(char __iomem *ptr)
+{
+ char __iomem *base;
+ int ret = 0, counter = 0;
+ int stage = 0;
+ struct mdss_mdp_mixer *mixer;
+
+ for (counter = 0; counter < mdss_res->nmixers_intf; counter++) {
+ mixer = mdss_res->mixer_intf + counter;
+ base = mixer->base;
+
+ if (ptr == base + MDSS_MDP_REG_LM_OP_MODE) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ /* GC range */
+ } else if ((ptr >= base + MDSS_MDP_REG_LM_GC_LUT_BASE) &&
+ (ptr <= base + MDSS_MDP_REG_LM_GC_LUT_BASE +
+ MDSS_MDP_GC_SIZE)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ }
+
+ for (stage = 0; stage < TOTAL_BLEND_STAGES; stage++)
+ if (ptr == base + MDSS_MDP_REG_LM_BLEND_OFFSET(stage) +
+ MDSS_MDP_REG_LM_BLEND_OP) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ goto End;
+ } else if (ptr == base +
+ MDSS_MDP_REG_LM_BLEND_OFFSET(stage) +
+ MDSS_MDP_REG_LM_BLEND_FG_ALPHA) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ goto End;
+ } else if (ptr == base +
+ MDSS_MDP_REG_LM_BLEND_OFFSET(stage) +
+ MDSS_MDP_REG_LM_BLEND_BG_ALPHA) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ goto End;
+ }
+ }
+
+End:
+ return ret;
+}
+
+static int is_valid_calib_addr(void *addr, u32 operation)
{
int ret = 0;
- unsigned int ptr;
- ptr = (unsigned int) addr;
- /* if request is outside the MDP reg-map or is not aligned 4 */
- if (ptr > 0x5138 || ptr % 0x4)
- goto end;
- if (ptr >= 0x100 && ptr <= 0x5138) {
- /* if ptr is in dspp range */
- if (ptr >= 0x4600 && ptr <= 0x5138) {
- /* if ptr is in dspp0 range*/
- if (ptr >= 0x4600 && ptr <= 0x4938)
- ptr -= 0x4600;
- /* if ptr is in dspp1 range */
- else if (ptr >= 0x4a00 && ptr <= 0x4d38)
- ptr -= 0x4a00;
- /* if ptr is in dspp2 range */
- else if (ptr >= 0x4e00 && ptr <= 0x5138)
- ptr -= 0x4e00;
- /* if ptr is in pcc plane rgb coeff.range */
- if (ptr >= 0x30 && ptr <= 0xe8)
- ret = 1;
- /* if ptr is in ARLUT red range */
- else if (ptr >= 0x2b0 && ptr <= 0x2b8)
- ret = 1;
- /* if ptr is in PA range */
- else if (ptr >= 0x238 && ptr <= 0x244)
- ret = 1;
- /* if ptr is in ARLUT green range */
- else if (ptr >= 0x2c0 && ptr <= 0x2c8)
- ret = 1;
- /* if ptr is in ARLUT blue range or
- gamut map table range */
- else if (ptr >= 0x2d0 && ptr <= 0x338)
- ret = 1;
- /* if ptr is dspp0,dspp1,dspp2 op mode
- register */
- else if (ptr == 0)
- ret = 1;
- } else if (ptr >= 0x600 && ptr <= 0x608)
- ret = 1;
- else if (ptr >= 0x400 && ptr <= 0x408)
- ret = 1;
- else if ((ptr == 0x1830) || (ptr == 0x1c30) ||
- (ptr == 0x1430) || (ptr == 0x1e38))
- ret = 1;
- else if ((ptr == 0x1e3c) || (ptr == 0x1e30))
- ret = 1;
- else if (ptr >= 0x3220 && ptr <= 0x3228)
- ret = 1;
- else if (ptr == 0x3200 || ptr == 0x100)
- ret = 1;
- else if (ptr == 0x104 || ptr == 0x614 || ptr == 0x714 ||
- ptr == 0x814 || ptr == 0x914 || ptr == 0xa14)
- ret = 1;
- else if (ptr == 0x618 || ptr == 0x718 || ptr == 0x818 ||
- ptr == 0x918 || ptr == 0xa18)
- ret = 1;
- else if (ptr == 0x2234 || ptr == 0x1e34 || ptr == 0x2634)
- ret = 1;
- } else if (ptr == 0x0)
- ret = 1;
-end:
- return ret;
+ char __iomem *ptr = addr;
+ char __iomem *mixer_base = mdss_res->mixer_intf->base;
+ char __iomem *rgb_base = mdss_res->rgb_pipes->base;
+ char __iomem *dma_base = mdss_res->dma_pipes->base;
+ char __iomem *vig_base = mdss_res->vig_pipes->base;
+ char __iomem *ctl_base = mdss_res->ctl_off->base;
+ char __iomem *dspp_base = mdss_res->mixer_intf->dspp_base;
+
+ if ((unsigned int)addr % 4) {
+ ret = 0;
+ } else if (ptr == (mdss_res->mdp_base + MDSS_MDP_REG_HW_VERSION) ||
+ ptr == (mdss_res->mdp_base + MDSS_MDP_REG_DISP_INTF_SEL)) {
+ ret = MDP_PP_OPS_READ;
+ } else if (ptr >= (mdss_res->mdp_base + MDSS_MDP_REG_IGC_DSPP_BASE) &&
+ ptr < (mdss_res->mdp_base + MDSS_MDP_REG_IGC_DSPP_BASE +
+ MDSS_MDP_IGC_DSPP_COLORS)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ } else if (ptr >= dspp_base && ptr < (dspp_base +
+ (mdss_res->nmixers_intf * MDSS_MDP_DSPP_ADDRESS_OFFSET))) {
+ ret = is_valid_calib_dspp_addr(ptr);
+ } else if (ptr >= ctl_base && ptr < (ctl_base + (mdss_res->nctl
+ * MDSS_MDP_CTL_ADDRESS_OFFSET))) {
+ ret = is_valid_calib_ctrl_addr(ptr);
+ } else if (ptr >= vig_base && ptr < (vig_base + (mdss_res->nvig_pipes
+ * MDSS_MDP_SSPP_ADDRESS_OFFSET))) {
+ ret = is_valid_calib_vig_addr(ptr);
+ } else if (ptr >= rgb_base && ptr < (rgb_base + (mdss_res->nrgb_pipes
+ * MDSS_MDP_SSPP_ADDRESS_OFFSET))) {
+ ret = is_valid_calib_rgb_addr(ptr);
+ } else if (ptr >= dma_base && ptr < (dma_base + (mdss_res->ndma_pipes
+ * MDSS_MDP_SSPP_ADDRESS_OFFSET))) {
+ ret = is_valid_calib_dma_addr(ptr);
+ } else if (ptr >= mixer_base && ptr < (mixer_base +
+ (mdss_res->nmixers_intf * MDSS_MDP_LM_ADDRESS_OFFSET))) {
+ ret = is_valid_calib_mixer_addr(ptr);
+ }
+
+ return ret & operation;
}
int mdss_mdp_calib_config(struct mdp_calib_config_data *cfg, u32 *copyback)
@@ -3477,11 +4812,12 @@
int ret = -1;
void *ptr = (void *) cfg->addr;
- if (is_valid_calib_addr(ptr))
+ ptr = (void *)(((unsigned int) ptr) + (mdss_res->mdp_base));
+ if (is_valid_calib_addr(ptr, cfg->ops))
ret = 0;
else
return ret;
- ptr = (void *)(((unsigned int) ptr) + (mdss_res->mdp_base));
+
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
if (cfg->ops & MDP_PP_OPS_READ) {
@@ -3516,65 +4852,50 @@
int i = 0;
if (!cfg) {
- pr_err("Invalid buffer pointer");
+ pr_err("Invalid buffer pointer\n");
return ret;
}
if (cfg->size == 0) {
- pr_err("Invalid buffer size");
+ pr_err("Invalid buffer size\n");
return ret;
}
counter = cfg->size / (sizeof(uint32_t) * 2);
buff_org = buff = kzalloc(cfg->size, GFP_KERNEL);
if (buff == NULL) {
- pr_err("Allocation failed");
+ pr_err("Config buffer allocation failed\n");
return ret;
}
if (copy_from_user(buff, cfg->buffer, cfg->size)) {
kfree(buff);
- pr_err("Copy failed");
+ pr_err("config buffer copy failed\n");
return ret;
}
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
- if (cfg->ops & MDP_PP_OPS_READ) {
- for (i = 0 ; i < counter ; i++) {
- if (is_valid_calib_addr((void *) *buff)) {
- ret = 0;
- } else {
- ret = -1;
- pr_err("Address validation failed");
- break;
- }
+ for (i = 0; i < counter; i++) {
+ ptr = (void *) (((unsigned int) *buff) + mdss_res->mdp_base);
- ptr = (void *)(((unsigned int) *buff) +
- (mdss_res->mdp_base));
- buff++;
+ if (!is_valid_calib_addr(ptr, cfg->ops)) {
+ ret = -1;
+ pr_err("Address validation failed or access not permitted\n");
+ break;
+ }
+
+ buff++;
+ if (cfg->ops & MDP_PP_OPS_READ)
*buff = readl_relaxed(ptr);
- buff++;
- }
- if (!ret)
- ret = copy_to_user(cfg->buffer, buff_org, cfg->size);
- *copyback = 1;
- } else if (cfg->ops & MDP_PP_OPS_WRITE) {
- for (i = 0 ; i < counter ; i++) {
- if (is_valid_calib_addr((void *) *buff)) {
- ret = 0;
- } else {
- ret = -1;
- pr_err("Address validation failed");
- break;
- }
-
- ptr = (void *)(((unsigned int) *buff) +
- (mdss_res->mdp_base));
- buff++;
+ else if (cfg->ops & MDP_PP_OPS_WRITE)
writel_relaxed(*buff, ptr);
- buff++;
- }
+ buff++;
+ }
+
+ if (ret & MDP_PP_OPS_READ) {
+ ret = copy_to_user(cfg->buffer, buff_org, cfg->size);
+ *copyback = 1;
}
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.c b/drivers/video/msm/mdss/mdss_mdp_rotator.c
index 1d172f3..883a728 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.c
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.c
@@ -137,7 +137,6 @@
{
int ret;
struct mdss_mdp_writeback_arg wb_args = {
- .callback_fnc = NULL,
.data = dst_data,
.priv_data = rot,
};
@@ -203,7 +202,7 @@
struct mdss_mdp_data *dst_data)
{
struct mdss_mdp_pipe *rot_pipe = NULL;
- struct mdss_mdp_ctl *ctl;
+ struct mdss_mdp_ctl *orig_ctl, *rot_ctl;
int ret;
if (!rot || !rot->ref_cnt)
@@ -219,20 +218,20 @@
pr_debug("queue rotator pnum=%d\n", rot_pipe->num);
- ctl = rot_pipe->mixer->ctl;
- if (ctl->shared_lock)
- mutex_lock(ctl->shared_lock);
+ orig_ctl = rot_pipe->mixer->ctl;
+ if (orig_ctl->shared_lock)
+ mutex_lock(orig_ctl->shared_lock);
- ctl = mdss_mdp_ctl_mixer_switch(ctl,
+ rot_ctl = mdss_mdp_ctl_mixer_switch(orig_ctl,
MDSS_MDP_WB_CTL_TYPE_BLOCK);
- if (!ctl) {
+ if (!rot_ctl) {
ret = -EINVAL;
goto error;
} else {
- rot->pipe->mixer = ctl->mixer_left;
+ rot->pipe->mixer = rot_ctl->mixer_left;
}
- if (rot->params_changed || ctl->mdata->mixer_switched) {
+ if (rot->params_changed || rot_ctl->mdata->mixer_switched) {
rot->params_changed = 0;
rot_pipe->flags = rot->flags;
rot_pipe->src_fmt = mdss_mdp_get_format_params(rot->format);
@@ -258,12 +257,12 @@
goto error;
}
- ret = mdss_mdp_rotator_kickoff(ctl, rot, dst_data);
+ ret = mdss_mdp_rotator_kickoff(rot_ctl, rot, dst_data);
return ret;
error:
- if (ctl->shared_lock)
- mutex_unlock(ctl->shared_lock);
+ if (orig_ctl->shared_lock)
+ mutex_unlock(orig_ctl->shared_lock);
return ret;
}
@@ -438,6 +437,7 @@
rot->flags |= MDP_DEINTERLACE;
rot->src_rect.h /= 2;
rot->src_rect.y = DIV_ROUND_UP(rot->src_rect.y, 2);
+ rot->src_rect.y &= ~1;
}
rot->dst = rot->src_rect;
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index 1170d1e..c3e1916 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -200,14 +200,20 @@
mdss_misr_crc_collect(mdata, DISPLAY_MISR_HDMI);
}
- if (isr & MDSS_MDP_INTR_WB_0_DONE)
+ if (isr & MDSS_MDP_INTR_WB_0_DONE) {
mdss_mdp_intr_done(MDP_INTR_WB_0);
+ mdss_misr_crc_collect(mdata, DISPLAY_MISR_MDP);
+ }
- if (isr & MDSS_MDP_INTR_WB_1_DONE)
+ if (isr & MDSS_MDP_INTR_WB_1_DONE) {
mdss_mdp_intr_done(MDP_INTR_WB_1);
+ mdss_misr_crc_collect(mdata, DISPLAY_MISR_MDP);
+ }
- if (isr & MDSS_MDP_INTR_WB_2_DONE)
+ if (isr & MDSS_MDP_INTR_WB_2_DONE) {
mdss_mdp_intr_done(MDP_INTR_WB_2);
+ mdss_misr_crc_collect(mdata, DISPLAY_MISR_MDP);
+ }
mdp_isr_done:
hist_isr = MDSS_MDP_REG_READ(MDSS_MDP_REG_HIST_INTR_STATUS);
@@ -592,7 +598,7 @@
return -EINVAL;
unit = 1 << PHASE_STEP_SHIFT;
- *out_phase = mult_frac(src, unit, dst);
+ *out_phase = mult_frac(unit, src, dst);
/* check if overflow is possible */
if (src > dst) {
diff --git a/drivers/video/msm/mdss/mdss_mdp_wb.c b/drivers/video/msm/mdss/mdss_mdp_wb.c
index c0e49c8..5789341 100644
--- a/drivers/video/msm/mdss/mdss_mdp_wb.c
+++ b/drivers/video/msm/mdss/mdss_mdp_wb.c
@@ -164,6 +164,16 @@
return -EINVAL;
}
+ if (!ctl || !ctl->mdata) {
+ pr_err("%s : ctl is NULL", __func__);
+ return -EINVAL;
+ }
+
+ if (!wb) {
+ pr_err("unable to start, writeback is not initialized\n");
+ return -ENODEV;
+ }
+
ctl->is_secure = enable;
wb->is_secure = enable;
@@ -508,23 +518,13 @@
return ret;
}
-static void mdss_mdp_wb_callback(void *arg)
-{
- if (arg)
- complete((struct completion *) arg);
-}
-
int mdss_mdp_wb_kickoff(struct msm_fb_data_type *mfd)
{
struct mdss_mdp_wb *wb = mfd_to_wb(mfd);
struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
struct mdss_mdp_wb_data *node = NULL;
int ret = 0;
- DECLARE_COMPLETION_ONSTACK(comp);
- struct mdss_mdp_writeback_arg wb_args = {
- .callback_fnc = mdss_mdp_wb_callback,
- .priv_data = &comp,
- };
+ struct mdss_mdp_writeback_arg wb_args;
if (!ctl->power_on)
return 0;
@@ -566,12 +566,6 @@
goto kickoff_fail;
}
- ret = wait_for_completion_timeout(&comp, KOFF_TIMEOUT);
- if (ret == 0)
- WARN(1, "wfd kick off time out=%d ctl=%d", ret, ctl->num);
- else
- ret = 0;
-
if (wb && node) {
mutex_lock(&wb->lock);
list_add_tail(&node->active_entry, &wb->busy_queue);
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index 75fc095..a42ff1e 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -222,6 +222,9 @@
char vsync_enable;
char hw_vsync_mode;
+
+ char lp11_init;
+ u32 init_delay;
};
enum dynamic_fps_update {
@@ -269,6 +272,7 @@
u32 type;
u32 wait_cycle;
u32 pdest;
+ u32 brightness_max;
u32 bl_max;
u32 bl_min;
u32 fb_num;
@@ -299,6 +303,8 @@
struct ion_handle *splash_ihdl;
u32 panel_power_on;
+ uint32_t panel_dead;
+
struct lcd_panel_info lcdc;
struct fbc_panel_info fbc;
struct mipi_panel_info mipi;
diff --git a/drivers/video/msm/mdss/mdss_qpic.c b/drivers/video/msm/mdss/mdss_qpic.c
index fa6bd3d..54b837a 100644
--- a/drivers/video/msm/mdss/mdss_qpic.c
+++ b/drivers/video/msm/mdss/mdss_qpic.c
@@ -368,7 +368,7 @@
phys_addr += block_len;
len -= block_len;
}
- ret = wait_for_completion_interruptible_timeout(
+ ret = wait_for_completion_timeout(
&qpic_res->qpic_endpt.completion,
msecs_to_jiffies(100 * 4));
if (ret <= 0)
diff --git a/drivers/video/msm/mdss/mhl_sii8334.c b/drivers/video/msm/mdss/mhl_sii8334.c
index a759e86..1f728e0 100644
--- a/drivers/video/msm/mdss/mhl_sii8334.c
+++ b/drivers/video/msm/mdss/mhl_sii8334.c
@@ -364,7 +364,7 @@
* after toggling reset line and enabling disc
* tx can take a while to generate intr
*/
- timeout = wait_for_completion_interruptible_timeout
+ timeout = wait_for_completion_timeout
(&mhl_ctrl->rgnd_done, HZ * 3);
if (!timeout) {
/*
@@ -1274,7 +1274,7 @@
INIT_COMPLETION(mhl_ctrl->msc_cmd_done);
MHL_SII_REG_NAME_WR(REG_CBUS_PRI_START, start_bit);
- timeout = wait_for_completion_interruptible_timeout
+ timeout = wait_for_completion_timeout
(&mhl_ctrl->msc_cmd_done, msecs_to_jiffies(T_ABORT_NEXT));
if (!timeout) {
pr_err("%s: cbus_command_send timed out!\n", __func__);
@@ -1463,7 +1463,7 @@
static struct regulator *reg_8941_l02;
static struct regulator *reg_8941_smps3a;
static struct regulator *reg_8941_vdda;
- int rc;
+ int rc = -EINVAL;
pr_debug("%s\n", __func__);
if (!reg_8941_l24) {
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index 62704a9..a63275b 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -665,215 +665,6 @@
}
-void mdss_edp_timing_engine_ctrl(unsigned char *edp_base, int enable)
-{
- /* should eb last reg to program */
- edp_write(edp_base + 0x94, enable); /* EDP_TIMING_ENGINE_EN */
-}
-
-void mdss_edp_mainlink_ctrl(unsigned char *edp_base, int enable)
-{
- edp_write(edp_base + 0x04, enable); /* EDP_MAINLINK_CTRL */
-}
-
-void mdss_edp_mainlink_reset(unsigned char *edp_base)
-{
- edp_write(edp_base + 0x04, 0x02); /* EDP_MAINLINK_CTRL */
- usleep(1000);
- edp_write(edp_base + 0x04, 0); /* EDP_MAINLINK_CTRL */
-}
-
-void mdss_edp_aux_reset(unsigned char *edp_base)
-{
- /*reset AUX */
- edp_write(edp_base + 0x300, BIT(1)); /* EDP_AUX_CTRL */
- usleep(1000);
- edp_write(edp_base + 0x300, 0); /* EDP_AUX_CTRL */
-}
-
-void mdss_edp_aux_ctrl(unsigned char *edp_base, int enable)
-{
- u32 data;
-
- data = edp_read(edp_base + 0x300);
- if (enable)
- data |= 0x01;
- else
- data |= ~0x01;
- edp_write(edp_base + 0x300, data); /* EDP_AUX_CTRL */
-}
-
-void mdss_edp_phy_pll_reset(unsigned char *edp_base)
-{
- /* EDP_PHY_CTRL */
- edp_write(edp_base + 0x74, 0x005); /* bit 0, 2 */
- usleep(1000);
- edp_write(edp_base + 0x74, 0x000); /* EDP_PHY_CTRL */
-}
-
-int mdss_edp_phy_pll_ready(unsigned char *edp_base)
-{
- int cnt;
- u32 status;
-
- cnt = 10;
- while (cnt--) {
- status = edp_read(edp_base + 0x6c0);
- if (status & 0x01)
- break;
- usleep(100);
- }
-
- if (cnt == 0) {
- pr_err("%s: PLL NOT ready\n", __func__);
- return 0;
- } else
- return 1;
-}
-
-int mdss_edp_phy_ready(unsigned char *edp_base)
-{
- u32 status;
-
- status = edp_read(edp_base + 0x598);
- status &= 0x01;
-
- return status;
-}
-
-void mdss_edp_phy_powerup(unsigned char *edp_base, int enable)
-{
- if (enable) {
- /* EDP_PHY_EDPPHY_GLB_PD_CTL */
- edp_write(edp_base + 0x52c, 0x3f);
- /* EDP_PHY_EDPPHY_GLB_CFG */
- edp_write(edp_base + 0x528, 0x1);
- /* EDP_PHY_PLL_UNIPHY_PLL_GLB_CFG */
- edp_write(edp_base + 0x620, 0xf);
- } else {
- /* EDP_PHY_EDPPHY_GLB_PD_CTL */
- edp_write(edp_base + 0x52c, 0xc0);
- }
-}
-
-void mdss_edp_pll_configure(unsigned char *edp_base, int rate)
-{
- if (rate == 810000000) {
- edp_write(edp_base + 0x60c, 0x18);
- edp_write(edp_base + 0x664, 0x5);
- edp_write(edp_base + 0x600, 0x0);
- edp_write(edp_base + 0x638, 0x36);
- edp_write(edp_base + 0x63c, 0x69);
- edp_write(edp_base + 0x640, 0xff);
- edp_write(edp_base + 0x644, 0x2f);
- edp_write(edp_base + 0x648, 0x0);
- edp_write(edp_base + 0x66c, 0x0a);
- edp_write(edp_base + 0x674, 0x01);
- edp_write(edp_base + 0x684, 0x5a);
- edp_write(edp_base + 0x688, 0x0);
- edp_write(edp_base + 0x68c, 0x60);
- edp_write(edp_base + 0x690, 0x0);
- edp_write(edp_base + 0x694, 0x2a);
- edp_write(edp_base + 0x698, 0x3);
- edp_write(edp_base + 0x65c, 0x10);
- edp_write(edp_base + 0x660, 0x1a);
- edp_write(edp_base + 0x604, 0x0);
- edp_write(edp_base + 0x624, 0x0);
- edp_write(edp_base + 0x628, 0x0);
-
- edp_write(edp_base + 0x620, 0x1);
- edp_write(edp_base + 0x620, 0x5);
- edp_write(edp_base + 0x620, 0x7);
- edp_write(edp_base + 0x620, 0xf);
-
- } else if (rate == 138530000) {
- edp_write(edp_base + 0x664, 0x5); /* UNIPHY_PLL_LKDET_CFG2 */
- edp_write(edp_base + 0x600, 0x1); /* UNIPHY_PLL_REFCLK_CFG */
- edp_write(edp_base + 0x638, 0x36); /* UNIPHY_PLL_SDM_CFG0 */
- edp_write(edp_base + 0x63c, 0x62); /* UNIPHY_PLL_SDM_CFG1 */
- edp_write(edp_base + 0x640, 0x0); /* UNIPHY_PLL_SDM_CFG2 */
- edp_write(edp_base + 0x644, 0x28); /* UNIPHY_PLL_SDM_CFG3 */
- edp_write(edp_base + 0x648, 0x0); /* UNIPHY_PLL_SDM_CFG4 */
- edp_write(edp_base + 0x64c, 0x80); /* UNIPHY_PLL_SSC_CFG0 */
- edp_write(edp_base + 0x650, 0x0); /* UNIPHY_PLL_SSC_CFG1 */
- edp_write(edp_base + 0x654, 0x0); /* UNIPHY_PLL_SSC_CFG2 */
- edp_write(edp_base + 0x658, 0x0); /* UNIPHY_PLL_SSC_CFG3 */
- edp_write(edp_base + 0x66c, 0xa); /* UNIPHY_PLL_CAL_CFG0 */
- edp_write(edp_base + 0x674, 0x1); /* UNIPHY_PLL_CAL_CFG2 */
- edp_write(edp_base + 0x684, 0x5a); /* UNIPHY_PLL_CAL_CFG6 */
- edp_write(edp_base + 0x688, 0x0); /* UNIPHY_PLL_CAL_CFG7 */
- edp_write(edp_base + 0x68c, 0x60); /* UNIPHY_PLL_CAL_CFG8 */
- edp_write(edp_base + 0x690, 0x0); /* UNIPHY_PLL_CAL_CFG9 */
- edp_write(edp_base + 0x694, 0x46); /* UNIPHY_PLL_CAL_CFG10 */
- edp_write(edp_base + 0x698, 0x5); /* UNIPHY_PLL_CAL_CFG11 */
- edp_write(edp_base + 0x65c, 0x10); /* UNIPHY_PLL_LKDET_CFG0 */
- edp_write(edp_base + 0x660, 0x1a); /* UNIPHY_PLL_LKDET_CFG1 */
- edp_write(edp_base + 0x604, 0x0); /* UNIPHY_PLL_POSTDIV1_CFG */
- edp_write(edp_base + 0x624, 0x0); /* UNIPHY_PLL_POSTDIV2_CFG */
- edp_write(edp_base + 0x628, 0x0); /* UNIPHY_PLL_POSTDIV3_CFG */
-
- edp_write(edp_base + 0x620, 0x1); /* UNIPHY_PLL_GLB_CFG */
- edp_write(edp_base + 0x620, 0x5); /* UNIPHY_PLL_GLB_CFG */
- edp_write(edp_base + 0x620, 0x7); /* UNIPHY_PLL_GLB_CFG */
- edp_write(edp_base + 0x620, 0xf); /* UNIPHY_PLL_GLB_CFG */
- } else {
- pr_err("%s: rate=%d is NOT supported\n", __func__, rate);
- }
-}
-
-void mdss_edp_enable_aux(unsigned char *edp_base, int enable)
-{
- if (!enable) {
- edp_write(edp_base + 0x300, 0); /* EDP_AUX_CTRL */
- return;
- }
-
- /*reset AUX */
- edp_write(edp_base + 0x300, BIT(1)); /* EDP_AUX_CTRL */
- edp_write(edp_base + 0x300, 0); /* EDP_AUX_CTRL */
-
- /* Enable AUX */
- edp_write(edp_base + 0x300, BIT(0)); /* EDP_AUX_CTRL */
-
- edp_write(edp_base + 0x550, 0x2c); /* AUX_CFG0 */
- edp_write(edp_base + 0x308, 0xffffffff); /* INTR_STATUS */
- edp_write(edp_base + 0x568, 0xff); /* INTR_MASK */
-}
-
-void mdss_edp_enable_mainlink(unsigned char *edp_base, int enable)
-{
- u32 data;
-
- data = edp_read(edp_base + 0x004);
- data &= ~BIT(0);
-
- if (enable) {
- data |= 0x1;
- edp_write(edp_base + 0x004, data);
- edp_write(edp_base + 0x004, 0x1);
- } else {
- data |= 0x0;
- edp_write(edp_base + 0x004, data);
- }
-}
-
-void mdss_edp_lane_power_ctrl(unsigned char *edp_base, int max_lane, int up)
-{
- int i, off;
- u32 data;
-
- if (up)
- data = 0; /* power up */
- else
- data = 0x7; /* power down */
-
- /* EDP_PHY_EDPPHY_LNn_PD_CTL */
- for (i = 0; i < max_lane; i++) {
- off = 0x40 * i;
- edp_write(edp_base + 0x404 + off , data);
- }
-}
-
void mdss_edp_clk_deinit(struct mdss_edp_drv_pdata *edp_drv)
{
if (edp_drv->aux_clk)
@@ -968,18 +759,18 @@
return 0;
}
- if (clk_set_rate(edp_drv->aux_clk, 19200000) < 0)
+ if (clk_set_rate(edp_drv->link_clk, edp_drv->link_rate * 27000000) < 0)
+ pr_err("%s: link_clk - clk_set_rate failed\n",
+ __func__);
+
+ if (clk_set_rate(edp_drv->aux_clk, edp_drv->aux_rate) < 0)
pr_err("%s: aux_clk - clk_set_rate failed\n",
__func__);
- if (clk_set_rate(edp_drv->pixel_clk, 138500000) < 0)
+ if (clk_set_rate(edp_drv->pixel_clk, edp_drv->pixel_rate) < 0)
pr_err("%s: pixel_clk - clk_set_rate failed\n",
__func__);
- if (clk_set_rate(edp_drv->link_clk, 270000000) < 0)
- pr_err("%s: link_clk - clk_set_rate failed\n",
- __func__);
-
ret = clk_enable(edp_drv->aux_clk);
if (ret) {
pr_err("%s: Failed to enable aux clk\n", __func__);
@@ -1034,20 +825,20 @@
{
int ret;
- ret = clk_prepare(edp_drv->aux_clk);
- if (ret) {
- pr_err("%s: Failed to prepare aux clk\n", __func__);
- goto c2;
- }
ret = clk_prepare(edp_drv->ahb_clk);
if (ret) {
pr_err("%s: Failed to prepare ahb clk\n", __func__);
goto c1;
}
+ ret = clk_prepare(edp_drv->aux_clk);
+ if (ret) {
+ pr_err("%s: Failed to prepare aux clk\n", __func__);
+ goto c2;
+ }
return 0;
c1:
- clk_unprepare(edp_drv->aux_clk);
+ clk_unprepare(edp_drv->ahb_clk);
c2:
return ret;
@@ -1063,19 +854,20 @@
{
int ret;
+ /* ahb clock should be first one to enable */
+ ret = clk_prepare(edp_drv->ahb_clk);
+ if (ret) {
+ pr_err("%s: Failed to prepare ahb clk\n", __func__);
+ goto c4;
+ }
ret = clk_prepare(edp_drv->aux_clk);
if (ret) {
pr_err("%s: Failed to prepare aux clk\n", __func__);
- goto c4;
+ goto c3;
}
ret = clk_prepare(edp_drv->pixel_clk);
if (ret) {
pr_err("%s: Failed to prepare pixel clk\n", __func__);
- goto c3;
- }
- ret = clk_prepare(edp_drv->ahb_clk);
- if (ret) {
- pr_err("%s: Failed to prepare ahb clk\n", __func__);
goto c2;
}
ret = clk_prepare(edp_drv->link_clk);
@@ -1086,11 +878,11 @@
return 0;
c1:
- clk_unprepare(edp_drv->ahb_clk);
-c2:
clk_unprepare(edp_drv->pixel_clk);
-c3:
+c2:
clk_unprepare(edp_drv->aux_clk);
+c3:
+ clk_unprepare(edp_drv->ahb_clk);
c4:
return ret;
}
@@ -1099,81 +891,27 @@
{
clk_unprepare(edp_drv->aux_clk);
clk_unprepare(edp_drv->pixel_clk);
- clk_unprepare(edp_drv->ahb_clk);
clk_unprepare(edp_drv->link_clk);
+ /* ahb clock should be last one to disable */
+ clk_unprepare(edp_drv->ahb_clk);
}
-void mdss_edp_enable_pixel_clk(unsigned char *edp_base,
- unsigned char *mmss_cc_base, int enable)
+void mdss_edp_clk_debug(unsigned char *edp_base, unsigned char *mmss_cc_base)
{
- if (!enable) {
- edp_write(mmss_cc_base + 0x032c, 0); /* CBCR */
- return;
- }
+ u32 da4, da0, d32c;
+ u32 dc4, dc0, d330;
- edp_write(edp_base + 0x624, 0x1); /* PostDiv2 */
+ /* pixel clk */
+ da0 = edp_read(mmss_cc_base + 0x0a0);
+ da4 = edp_read(mmss_cc_base + 0x0a4);
+ d32c = edp_read(mmss_cc_base + 0x32c);
- /* Configuring MND for Pixel */
- edp_write(mmss_cc_base + 0x00a8, 0x3f); /* M value */
- edp_write(mmss_cc_base + 0x00ac, 0xb); /* N value */
- edp_write(mmss_cc_base + 0x00b0, 0x0); /* D value */
+ /* main link clk */
+ dc0 = edp_read(mmss_cc_base + 0x0c0);
+ dc4 = edp_read(mmss_cc_base + 0x0c4);
+ d330 = edp_read(mmss_cc_base + 0x330);
- /* CFG RCGR */
- edp_write(mmss_cc_base + 0x00a4, (5 << 8) | (2 << 12));
- edp_write(mmss_cc_base + 0x00a0, 3); /* CMD RCGR */
+ pr_err("%s: da0=%x da4=%x d32c=%x dc0=%x dc4=%x d330=%x\n", __func__,
+ (int)da0, (int)da4, (int)d32c, (int)dc0, (int)dc4, (int)d330);
- edp_write(mmss_cc_base + 0x032c, 1); /* CBCR */
-}
-
-void mdss_edp_enable_link_clk(unsigned char *mmss_cc_base, int enable)
-{
- if (!enable) {
- edp_write(mmss_cc_base + 0x0330, 0); /* CBCR */
- return;
- }
-
- edp_write(mmss_cc_base + 0x00c4, (4 << 8)); /* CFG RCGR */
- edp_write(mmss_cc_base + 0x00c0, 3); /* CMD RCGR */
-
- edp_write(mmss_cc_base + 0x0330, 1); /* CBCR */
-}
-
-void mdss_edp_config_clk(unsigned char *edp_base, unsigned char *mmss_cc_base)
-{
- mdss_edp_enable_link_clk(mmss_cc_base, 1);
- mdss_edp_enable_pixel_clk(edp_base, mmss_cc_base, 1);
-}
-
-void mdss_edp_unconfig_clk(unsigned char *edp_base,
- unsigned char *mmss_cc_base)
-{
- mdss_edp_enable_link_clk(mmss_cc_base, 0);
- mdss_edp_enable_pixel_clk(edp_base, mmss_cc_base, 0);
-}
-
-void mdss_edp_clock_synchrous(unsigned char *edp_base, int sync)
-{
- u32 data;
-
- /* EDP_MISC1_MISC0 */
- data = edp_read(edp_base + 0x02c);
-
- if (sync)
- data |= 0x01;
- else
- data &= ~0x01;
-
- /* EDP_MISC1_MISC0 */
- edp_write(edp_base + 0x2c, data);
-}
-
-/* voltage mode and pre emphasis cfg */
-void mdss_edp_phy_vm_pe_init(unsigned char *edp_base)
-{
- /* EDP_PHY_EDPPHY_GLB_VM_CFG0 */
- edp_write(edp_base + 0x510, 0x3); /* vm only */
- /* EDP_PHY_EDPPHY_GLB_VM_CFG1 */
- edp_write(edp_base + 0x514, 0x64);
- /* EDP_PHY_EDPPHY_GLB_MISC9 */
- edp_write(edp_base + 0x518, 0x6c);
}
diff --git a/drivers/video/msm/mdss/splash.h b/drivers/video/msm/mdss/splash.h
new file mode 100644
index 0000000..dc8a473
--- /dev/null
+++ b/drivers/video/msm/mdss/splash.h
@@ -0,0 +1,5279 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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 __SPLASH_H_
+#define __SPLASH_H_
+
+#define SPLASH_IMAGE_WIDTH 113
+#define SPLASH_IMAGE_HEIGHT 124
+#define SPLASH_IMAGE_FORMAT MDP_BGR_888
+#define SPLASH_IMAGE_BPP 3
+
+char splash_bgr888_image[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10,
+ 0x29, 0x19, 0x31, 0x31,
+ 0x29, 0x31, 0x31, 0x29, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+ 0x08, 0x10, 0x31, 0x31,
+ 0x29, 0x4a, 0x52, 0x4a, 0x6b, 0x5a, 0x73, 0x4a, 0x52, 0x4a, 0x10, 0x29,
+ 0x19, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x08,
+ 0x10, 0x31, 0x31, 0x29, 0x6b, 0x5a, 0x73, 0x6b, 0x7b, 0x73, 0x6b, 0x5a,
+ 0x4a, 0x31, 0x31, 0x29,
+ 0x3a, 0x10, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08,
+ 0x08, 0x10, 0x10, 0x21, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x08, 0x10, 0x31, 0x31, 0x29, 0x6b, 0x5a, 0x4a, 0x6b, 0x5a,
+ 0x73, 0x3a, 0x31, 0x4a,
+ 0x31, 0x31, 0x29, 0x10, 0x29, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x31, 0x31, 0x29, 0x3a, 0x31,
+ 0x4a, 0x31, 0x31, 0x29,
+ 0x10, 0x29, 0x19, 0x08, 0x08, 0x10, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x10, 0x21, 0x00,
+ 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x08, 0x08,
+ 0x10, 0x08, 0x08, 0x10,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00,
+ 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x08,
+ 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x21,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08,
+ 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x21, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x08, 0x10, 0x00,
+ 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x21, 0x00, 0x08, 0x08, 0x10,
+ 0x08, 0x08, 0x10, 0x10,
+ 0x29, 0x19, 0x10, 0x29, 0x19, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x08,
+ 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x08, 0x10,
+ 0x4a, 0x52, 0x4a, 0x08,
+ 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x08, 0x10,
+ 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x08, 0x10, 0x31, 0x31, 0x29, 0x08,
+ 0x08, 0x10, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x29, 0x19, 0x4a, 0x52, 0x4a, 0x3a, 0x31, 0x4a,
+ 0x08, 0x00, 0x00, 0x08,
+ 0x08, 0x10, 0x4a, 0x52, 0x4a, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+ 0x08, 0x10, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x4a,
+ 0x52, 0x4a, 0x9c, 0xa5, 0x94, 0x9c, 0x7b, 0x94, 0x08, 0x08, 0x10, 0x08,
+ 0x08, 0x10, 0x10, 0x29,
+ 0x19, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08,
+ 0x10, 0x10, 0x21, 0x00,
+ 0x08, 0x08, 0x10, 0x6b, 0x7b, 0x73, 0x9c, 0x7b, 0x94, 0x9c, 0xa5, 0x94,
+ 0xce, 0xad, 0xad, 0xa5,
+ 0xb5, 0xb5, 0x31, 0x31, 0x29, 0x08, 0x08, 0x10, 0x10, 0x29, 0x19, 0x08,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x4a,
+ 0x52, 0x4a, 0xa5, 0x9c, 0xad, 0xce, 0xad, 0xad, 0xce, 0xde, 0xce, 0x9c,
+ 0x7b, 0x94, 0x10, 0x29,
+ 0x19, 0x3a, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x08, 0x10, 0x9c, 0x7b, 0x94, 0x9c, 0xa5, 0x94, 0xa5, 0xb5, 0xb5,
+ 0xa5, 0xb5, 0xb5, 0xce,
+ 0xde, 0xce, 0xc5, 0xad, 0xd6, 0x9c, 0xa5, 0x94, 0x3a, 0x10, 0x21, 0x00,
+ 0x00, 0x00, 0x08, 0x08,
+ 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08,
+ 0x08, 0x10, 0x9c, 0x7b, 0x94, 0xce, 0xad, 0xad, 0xce, 0xe6, 0xef, 0xce,
+ 0xe6, 0xef, 0xe6, 0xde,
+ 0xde, 0xa5, 0x9c, 0xad, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x6b, 0x5a, 0x73, 0xce, 0xde, 0xce, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xde, 0xce, 0x6b,
+ 0x7b, 0x73, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x21, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x29, 0x19, 0xef, 0xf7, 0xe6, 0xef, 0xf7, 0xff, 0x9c,
+ 0xa5, 0x94, 0xce, 0xde,
+ 0xce, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x21, 0x00, 0xce, 0xde, 0xce, 0xff, 0xf7, 0xff,
+ 0xff, 0xf7, 0xff, 0x9c,
+ 0xa5, 0x94, 0x00, 0x00, 0x00, 0x31, 0x31, 0x29, 0xef, 0xf7, 0xe6, 0xff,
+ 0xf7, 0xff, 0xef, 0xde,
+ 0xef, 0x08, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x08, 0x00, 0x00, 0x4a, 0x52, 0x4a, 0xff, 0xf7, 0xff, 0x10,
+ 0x29, 0x19, 0x08, 0x08,
+ 0x10, 0x4a, 0x52, 0x4a, 0xce, 0xad, 0xad, 0xff, 0xff, 0xff, 0x4a, 0x52,
+ 0x4a, 0x08, 0x08, 0x10,
+ 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x08, 0x08, 0x10, 0xce, 0xad, 0xad,
+ 0xef, 0xf7, 0xff, 0xce,
+ 0xde, 0xce, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x9c, 0x7b, 0x94, 0x31,
+ 0x31, 0x29, 0xef, 0xf7,
+ 0xe6, 0xff, 0xff, 0xff, 0x4a, 0x52, 0x4a, 0x00, 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6b, 0x5a, 0x73, 0xef,
+ 0xf7, 0xe6, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00, 0x6b, 0x7b, 0x73, 0x08, 0x08, 0x10, 0xff, 0xff,
+ 0xff, 0x6b, 0x7b, 0x73,
+ 0x08, 0x08, 0x10, 0x31, 0x31, 0x29, 0x4a, 0x52, 0x4a, 0x08, 0x08, 0x10,
+ 0xce, 0xde, 0xce, 0xff,
+ 0xff, 0xff, 0x10, 0x29, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31,
+ 0x31, 0x29, 0x4a, 0x52,
+ 0x4a, 0xa5, 0xb5, 0xb5, 0xff, 0xff, 0xff, 0x9c, 0x7b, 0x94, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x4a,
+ 0x52, 0x4a, 0xe6, 0xde,
+ 0xde, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x31, 0x31, 0x29, 0x08, 0x08,
+ 0x10, 0xff, 0xff, 0xff,
+ 0x4a, 0x52, 0x4a, 0x08, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00,
+ 0x08, 0x08, 0x10, 0x9c,
+ 0x7b, 0x94, 0xff, 0xff, 0xff, 0x3a, 0x10, 0x21, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x08,
+ 0x10, 0x08, 0x08, 0x10, 0x6b, 0x5a, 0x73, 0xff, 0xff, 0xff, 0xa5, 0xb5,
+ 0xb5, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x4a, 0x52,
+ 0x4a, 0xef, 0xf7, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0xe6, 0xde, 0xde, 0x08, 0x31, 0x5a, 0x10, 0x7b, 0x9c, 0x10, 0x7b, 0x9c,
+ 0x10, 0x7b, 0x9c, 0x10,
+ 0x52, 0x7b, 0x31, 0x31, 0x29, 0xef, 0xf7, 0xff, 0x08, 0x08, 0x10, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0xa5, 0x94, 0xff, 0xff,
+ 0xff, 0xa5, 0x9c, 0xad,
+ 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x21, 0x00, 0x08,
+ 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x08, 0x08, 0x10, 0xff, 0xf7, 0xff, 0x4a, 0x52, 0x4a, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x31, 0x5a, 0x00, 0x84, 0xbd, 0x08, 0xad, 0xd6, 0x00, 0xbd, 0xef,
+ 0x00, 0xbd, 0xef, 0x00,
+ 0x9c, 0xd6, 0x08, 0xa5, 0xad, 0x08, 0xad, 0xd6, 0x10, 0xce, 0xce, 0x6b,
+ 0x7b, 0x9c, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0xf7,
+ 0xff, 0xff, 0xff, 0xff,
+ 0x6b, 0x5a, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0xce, 0xde, 0xce, 0xff, 0xf7,
+ 0xff, 0x10, 0x29, 0x19,
+ 0x10, 0x5a, 0x9c, 0x00, 0x9c, 0xd6, 0x19, 0x94, 0xce, 0x00, 0xbd, 0xf7,
+ 0x10, 0xc5, 0xef, 0x08,
+ 0xad, 0xd6, 0x08, 0xad, 0xd6, 0x08, 0xad, 0xd6, 0x08, 0xad, 0xd6, 0x10,
+ 0xc5, 0xef, 0x00, 0xbd,
+ 0xef, 0x08, 0xa5, 0xad, 0x08, 0x31, 0x5a, 0x10, 0x29, 0x19, 0xff, 0xf7,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xe6, 0xde, 0xde, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08,
+ 0x08, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6b, 0x5a,
+ 0x73, 0xef, 0xf7, 0xe6,
+ 0x19, 0x7b, 0xbd, 0x19, 0x7b, 0xbd, 0x08, 0xad, 0xd6, 0x00, 0xbd, 0xef,
+ 0x10, 0xc5, 0xef, 0x00,
+ 0xbd, 0xef, 0x10, 0xc5, 0xef, 0x10, 0xc5, 0xef, 0x3a, 0xde, 0xef, 0x19,
+ 0xbd, 0xf7, 0x3a, 0xde,
+ 0xef, 0x3a, 0xde, 0xef, 0x10, 0xc5, 0xef, 0x10, 0xc5, 0xef, 0x08, 0xad,
+ 0xd6, 0x19, 0x94, 0xce,
+ 0xa5, 0xb5, 0xb5, 0x4a, 0x5a, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x08, 0x10,
+ 0x10, 0x7b, 0x9c, 0x00, 0x84, 0xbd, 0x08, 0xad, 0xd6, 0x08, 0xad, 0xd6,
+ 0x08, 0xad, 0xef, 0x10,
+ 0xc5, 0xef, 0x08, 0xad, 0xd6, 0x10, 0xc5, 0xef, 0x10, 0xe6, 0xef, 0x19,
+ 0xbd, 0xf7, 0x3a, 0xde,
+ 0xef, 0x3a, 0xde, 0xef, 0x10, 0xc5, 0xef, 0x10, 0xe6, 0xef, 0x10, 0xe6,
+ 0xef, 0x10, 0xc5, 0xef,
+ 0x10, 0xe6, 0xef, 0x19, 0xbd, 0xf7, 0x08, 0xad, 0xd6, 0x08, 0x31, 0x3a,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x08, 0x10,
+ 0x10, 0x7b, 0x9c, 0x00, 0x84, 0xbd, 0x19, 0x94, 0xce, 0x00, 0x9c, 0xd6,
+ 0x10, 0xc5, 0xef, 0x08,
+ 0xad, 0xef, 0x10, 0xc5, 0xef, 0x10, 0xc5, 0xef, 0x10, 0xc5, 0xef, 0x10,
+ 0xc5, 0xef, 0x6b, 0xe6,
+ 0xef, 0x3a, 0xde, 0xef, 0x10, 0xe6, 0xef, 0x10, 0xe6, 0xef, 0x10, 0xc5,
+ 0xef, 0x10, 0xe6, 0xef,
+ 0x10, 0xc5, 0xef, 0x10, 0xe6, 0xef, 0x10, 0xc5, 0xef, 0x19, 0xbd, 0xf7,
+ 0x19, 0x7b, 0xbd, 0x00,
+ 0x00, 0x00, 0x10, 0x21, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x31, 0x5a, 0x00, 0x84, 0xbd, 0x00, 0x84, 0xbd, 0x00, 0x9c, 0xd6,
+ 0x08, 0xad, 0xef, 0x08,
+ 0xad, 0xef, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xef, 0x10, 0xc5, 0xef, 0x10,
+ 0xc5, 0xef, 0x10, 0xe6,
+ 0xef, 0x3a, 0xde, 0xef, 0x19, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x10, 0xe6,
+ 0xef, 0x10, 0xc5, 0xef,
+ 0x10, 0xe6, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0x84, 0xbd, 0x10, 0x7b, 0x9c,
+ 0x00, 0xbd, 0xef, 0x10,
+ 0x73, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+ 0x08, 0x10, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x52, 0x7b, 0x19, 0x7b, 0xbd, 0x00, 0x9c, 0xd6,
+ 0x19, 0x94, 0xce, 0x08,
+ 0xad, 0xef, 0x08, 0xad, 0xef, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xd6, 0x10,
+ 0xe6, 0xef, 0x19, 0xbd,
+ 0xf7, 0x6b, 0xe6, 0xef, 0x19, 0xbd, 0xf7, 0x10, 0xe6, 0xef, 0x10, 0xe6,
+ 0xef, 0x10, 0xe6, 0xef,
+ 0x10, 0xc5, 0xef, 0x00, 0x9c, 0xd6, 0x00, 0x84, 0xbd, 0x00, 0x9c, 0xd6,
+ 0x19, 0x94, 0xce, 0x00,
+ 0x9c, 0xd6, 0x10, 0x52, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x08, 0x31, 0x5a,
+ 0x08, 0xa5, 0xad, 0x08,
+ 0xad, 0xef, 0x00, 0xbd, 0xef, 0x10, 0xc5, 0xef, 0x10, 0xc5, 0xef, 0x10,
+ 0xc5, 0xef, 0x10, 0xc5,
+ 0xef, 0x10, 0xe6, 0xef, 0x19, 0xbd, 0xf7, 0x10, 0xe6, 0xef, 0x10, 0xc5,
+ 0xef, 0x10, 0xc5, 0xef,
+ 0x19, 0xbd, 0xf7, 0x10, 0x7b, 0x9c, 0x00, 0x84, 0xbd, 0x19, 0x94, 0xce,
+ 0x08, 0xad, 0xd6, 0x00,
+ 0x9c, 0xd6, 0x19, 0x94, 0xce, 0x08, 0x31, 0x3a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x08,
+ 0x10, 0x31, 0x31, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08,
+ 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x31, 0x3a, 0x10,
+ 0x52, 0x7b, 0x10, 0x7b, 0x9c, 0x08, 0xad, 0xef, 0x08, 0xad, 0xef, 0x10,
+ 0xc5, 0xef, 0x10, 0xc5,
+ 0xef, 0x3a, 0xde, 0xef, 0x10, 0xe6, 0xef, 0x10, 0xc5, 0xef, 0x10, 0xe6,
+ 0xef, 0x08, 0xad, 0xd6,
+ 0x10, 0x5a, 0x9c, 0x10, 0x5a, 0x9c, 0x00, 0x9c, 0xd6, 0x19, 0x94, 0xce,
+ 0x00, 0x9c, 0xd6, 0x00,
+ 0x9c, 0xd6, 0x19, 0x7b, 0xbd, 0x19, 0x7b, 0xbd, 0x08, 0x08, 0x10, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x08, 0x10, 0x9c, 0x7b, 0x73, 0x6b, 0x5a, 0x73, 0x10, 0x29,
+ 0x19, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08,
+ 0x08, 0x10, 0x73, 0xa5, 0xad, 0x10, 0x52, 0x7b, 0x10, 0x52, 0x7b, 0x00,
+ 0x84, 0xbd, 0x08, 0xa5,
+ 0xad, 0x08, 0xad, 0xd6, 0x19, 0x94, 0xce, 0x00, 0x84, 0xbd, 0x10, 0x73,
+ 0x7b, 0x10, 0x5a, 0x9c,
+ 0x00, 0x84, 0xbd, 0x00, 0x9c, 0xd6, 0x00, 0x9c, 0xd6, 0x00, 0x9c, 0xd6,
+ 0x00, 0x9c, 0xd6, 0x00,
+ 0x84, 0xbd, 0x3a, 0xa5, 0xce, 0xce, 0xad, 0xad, 0xce, 0xde, 0xce, 0x6b,
+ 0x5a, 0x73, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x52, 0x4a, 0x6b, 0x7b,
+ 0x9c, 0x9c, 0x7b, 0x73,
+ 0x31, 0x31, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x31, 0x31, 0x29, 0xc5, 0xad, 0xd6, 0x52, 0xa5, 0xa5, 0x10,
+ 0x5a, 0x9c, 0x10, 0x7b,
+ 0x9c, 0x19, 0x94, 0xce, 0x08, 0xad, 0xd6, 0x08, 0xad, 0xd6, 0x19, 0x94,
+ 0xce, 0x00, 0x9c, 0xd6,
+ 0x00, 0x9c, 0xd6, 0x00, 0x84, 0xbd, 0x00, 0x84, 0xbd, 0x19, 0x94, 0xce,
+ 0x00, 0x84, 0xbd, 0x19,
+ 0x7b, 0xbd, 0xce, 0xad, 0xad, 0xce, 0xde, 0xce, 0xce, 0xde, 0xce, 0xa5,
+ 0xb5, 0xb5, 0xa5, 0xb5,
+ 0xb5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x21,
+ 0x00, 0x6b, 0x7b, 0x73,
+ 0x9c, 0x7b, 0x94, 0x6b, 0x7b, 0x73, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x08, 0x10, 0x4a, 0x52, 0x4a, 0xa5, 0xd6, 0xad, 0xc5,
+ 0xad, 0xd6, 0x4a, 0x7b,
+ 0x9c, 0x10, 0x5a, 0x9c, 0x00, 0x84, 0xbd, 0x00, 0x9c, 0xd6, 0x00, 0x84,
+ 0xbd, 0x00, 0x9c, 0xd6,
+ 0x19, 0x94, 0xce, 0x00, 0x84, 0xbd, 0x19, 0x94, 0xce, 0x00, 0x84, 0xbd,
+ 0x19, 0x7b, 0xbd, 0x73,
+ 0xa5, 0xad, 0xa5, 0xb5, 0xb5, 0xc5, 0xad, 0xd6, 0xa5, 0xb5, 0xb5, 0xe6,
+ 0xde, 0xde, 0xce, 0xde,
+ 0xce, 0xce, 0xad, 0xad, 0x10, 0x29, 0x19, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x4a, 0x52, 0x4a, 0x6b, 0x7b, 0x73, 0x31, 0x31, 0x29, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x31, 0x4a, 0xce,
+ 0xad, 0xad, 0xce, 0xde,
+ 0xce, 0xa5, 0xb5, 0xb5, 0x73, 0xa5, 0xad, 0x10, 0x73, 0x7b, 0x10, 0x5a,
+ 0x9c, 0x10, 0x7b, 0x9c,
+ 0x10, 0x5a, 0xbd, 0x10, 0x7b, 0x9c, 0x10, 0x5a, 0x9c, 0x10, 0x5a, 0x9c,
+ 0x19, 0x7b, 0xbd, 0xa5,
+ 0xb5, 0xb5, 0xa5, 0xb5, 0xb5, 0xc5, 0xad, 0xd6, 0xa5, 0xd6, 0xad, 0xef,
+ 0xde, 0xef, 0xef, 0xf7,
+ 0xe6, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xa5, 0x9c, 0xad, 0x08, 0x08,
+ 0x10, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x4a,
+ 0x52, 0x4a, 0xe6, 0xde,
+ 0xde, 0xc5, 0xad, 0xd6, 0xa5, 0xb5, 0xb5, 0xce, 0xad, 0xad, 0x9c, 0xad,
+ 0xce, 0x52, 0xa5, 0xa5,
+ 0x10, 0x5a, 0x9c, 0x10, 0x7b, 0x9c, 0x10, 0x5a, 0x9c, 0x52, 0xa5, 0xa5,
+ 0x73, 0xa5, 0xad, 0xc5,
+ 0xad, 0xd6, 0xa5, 0xb5, 0xb5, 0xce, 0xde, 0xce, 0xce, 0xde, 0xce, 0xef,
+ 0xde, 0xef, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xef, 0xf7, 0xff, 0xef, 0xf7,
+ 0xe6, 0x08, 0x08, 0x10,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xef, 0xf7,
+ 0xe6, 0xef, 0xf7, 0xe6, 0xce, 0xde, 0xce, 0xce, 0xde, 0xce, 0xa5, 0xb5,
+ 0xb5, 0xce, 0xde, 0xce,
+ 0xce, 0xad, 0xad, 0xce, 0xde, 0xce, 0xa5, 0xb5, 0xb5, 0xce, 0xde, 0xce,
+ 0xce, 0xad, 0xad, 0xc5,
+ 0xad, 0xd6, 0xa5, 0xd6, 0xad, 0xce, 0xad, 0xad, 0xce, 0xde, 0xce, 0xe6,
+ 0xde, 0xde, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xa5, 0xb5, 0xb5, 0x08, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x08, 0x08,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x10, 0x21, 0x00, 0x00,
+ 0x00, 0x00, 0x9c, 0xa5,
+ 0x94, 0xff, 0xf7, 0xff, 0xff, 0xf7, 0xff, 0xef, 0xf7, 0xe6, 0xc5, 0xad,
+ 0xd6, 0xa5, 0xb5, 0xb5,
+ 0xce, 0xad, 0xad, 0xc5, 0xad, 0xd6, 0xa5, 0xb5, 0xb5, 0xce, 0xad, 0xad,
+ 0xc5, 0xad, 0xd6, 0xa5,
+ 0xd6, 0xad, 0xc5, 0xad, 0xd6, 0xce, 0xde, 0xce, 0xef, 0xde, 0xef, 0xef,
+ 0xf7, 0xe6, 0xff, 0xf7,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x31, 0x31, 0x29, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x08, 0x08, 0x10, 0x08,
+ 0x08, 0x10, 0x10, 0x29,
+ 0x19, 0xef, 0xde, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xe6,
+ 0xc5, 0xad, 0xd6, 0xa5, 0xd6, 0xad, 0xa5, 0xb5, 0xb5, 0xce, 0xde, 0xce,
+ 0xa5, 0xb5, 0xb5, 0xce,
+ 0xde, 0xce, 0xce, 0xad, 0xad, 0xce, 0xde, 0xce, 0xef, 0xf7, 0xe6, 0xef,
+ 0xf7, 0xff, 0xff, 0xf7,
+ 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe6, 0xde, 0xde,
+ 0x08, 0x08, 0x10, 0x08,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x21,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0xe6, 0xde, 0xde, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xe6, 0xe6, 0xde, 0xde, 0xce, 0xad, 0xad, 0xc5, 0xad, 0xd6,
+ 0xa5, 0xb5, 0xb5, 0xce,
+ 0xad, 0xad, 0xce, 0xde, 0xce, 0xce, 0xe6, 0xef, 0xff, 0xf7, 0xff, 0xff,
+ 0xf7, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xe6,
+ 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff,
+ 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x08, 0x08,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x4a, 0x52, 0x4a, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xef, 0xf7, 0xe6,
+ 0xe6, 0xde, 0xde, 0xef,
+ 0xf7, 0xe6, 0xce, 0xe6, 0xef, 0xff, 0xf7, 0xff, 0xff, 0xf7, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xa5, 0x9c, 0xad, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xe6, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xe6, 0xde, 0xde, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x4a, 0x52, 0x4a, 0xef, 0xf7, 0xe6, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x08,
+ 0x08, 0x10, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00, 0x08, 0x08, 0x10, 0xce, 0xde, 0xce, 0xef, 0xde,
+ 0xef, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xef,
+ 0xf7, 0xff, 0x31, 0x31,
+ 0x29, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0xce, 0xad,
+ 0xad, 0xef, 0xf7, 0xe6,
+ 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff,
+ 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xef,
+ 0xf7, 0xe6, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff,
+ 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xef, 0xf7, 0xe6, 0xef,
+ 0xde, 0xef, 0xef, 0xf7,
+ 0xe6, 0x9c, 0xa5, 0x94, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x21, 0x00,
+ 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x31,
+ 0x29, 0xa5, 0xb5, 0xb5,
+ 0xce, 0xde, 0xce, 0xef, 0xf7, 0xe6, 0xef, 0xf7, 0xff, 0xff, 0xf7, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xef, 0xf7, 0xe6, 0xef, 0xde, 0xef, 0xef,
+ 0xf7, 0xe6, 0xe6, 0xde,
+ 0xde, 0xce, 0xe6, 0xef, 0xff, 0xf7, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xf7,
+ 0xff, 0xef, 0xf7, 0xe6,
+ 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xef, 0xf7, 0xff, 0xef, 0xf7, 0xe6,
+ 0xef, 0xf7, 0xe6, 0xef,
+ 0xde, 0xef, 0xce, 0xe6, 0xef, 0xe6, 0xde, 0xde, 0xe6, 0xde, 0xde, 0xce,
+ 0xde, 0xce, 0xce, 0xde,
+ 0xce, 0xe6, 0xde, 0xde, 0xce, 0xad, 0xad, 0x08, 0x08, 0x10, 0x00, 0x00,
+ 0x00, 0x10, 0x21, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x08, 0x10, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08,
+ 0x10, 0x6b, 0x5a, 0x4a,
+ 0x73, 0xa5, 0xad, 0xce, 0xad, 0xad, 0xc5, 0xad, 0xd6, 0xe6, 0xde, 0xde,
+ 0xe6, 0xde, 0xde, 0xff,
+ 0xf7, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xef,
+ 0xde, 0xef, 0xce, 0xde,
+ 0xce, 0xef, 0xde, 0xef, 0xef, 0xf7, 0xe6, 0xef, 0xf7, 0xe6, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xde, 0xef,
+ 0xce, 0xde, 0xce, 0xc5,
+ 0xad, 0xd6, 0xce, 0xde, 0xce, 0xce, 0xad, 0xad, 0xce, 0xde, 0xce, 0xa5,
+ 0xb5, 0xb5, 0xc5, 0xad,
+ 0xd6, 0xa5, 0xb5, 0xb5, 0xc5, 0xad, 0xd6, 0xef, 0xf7, 0xff, 0x4a, 0x52,
+ 0x4a, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00,
+ 0x00, 0x10, 0x29, 0x19,
+ 0x6b, 0x5a, 0x73, 0xce, 0xad, 0xad, 0xce, 0xde, 0xce, 0xce, 0xde, 0xce,
+ 0xef, 0xf7, 0xe6, 0xef,
+ 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xef, 0xf7,
+ 0xff, 0xef, 0xde, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xf7, 0xff, 0xef, 0xf7, 0xe6, 0xe6, 0xde, 0xde, 0xce, 0xde, 0xce, 0xc5,
+ 0xad, 0xd6, 0xce, 0xde,
+ 0xce, 0xce, 0xad, 0xad, 0xce, 0xde, 0xce, 0xa5, 0xb5, 0xb5, 0xce, 0xde,
+ 0xce, 0xff, 0xf7, 0xff,
+ 0x31, 0x31, 0x29, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x4a, 0x52, 0x4a,
+ 0x31, 0x31, 0x29, 0x08,
+ 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00,
+ 0x08, 0x08, 0x10, 0xa5, 0x9c, 0xad, 0xce, 0xde, 0xce, 0xce, 0xe6, 0xef,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xff, 0xff, 0xf7,
+ 0xff, 0xef, 0xf7, 0xe6, 0xef, 0xf7, 0xe6, 0xef, 0xf7, 0xff, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xce, 0xe6, 0xef, 0xe6, 0xde, 0xde, 0xce, 0xde, 0xce, 0xc5, 0xad,
+ 0xd6, 0xce, 0xad, 0xad,
+ 0xe6, 0xde, 0xde, 0xff, 0xf7, 0xff, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08,
+ 0x08, 0x10, 0x31, 0x31, 0x29, 0x3a, 0x10, 0x21, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x31, 0x31,
+ 0x29, 0x00, 0x00, 0x00,
+ 0x10, 0x21, 0x00, 0x6b, 0x5a, 0x73, 0xce, 0xde, 0xce, 0xff, 0xf7, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+ 0xe6, 0xce, 0xde, 0xce,
+ 0xce, 0xde, 0xce, 0x9c, 0xad, 0xce, 0xef, 0xf7, 0xe6, 0xa5, 0x9c, 0xad,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x3a, 0x31, 0x4a, 0x10,
+ 0x29, 0x19, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x52,
+ 0x4a, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0xe6, 0xde, 0xde, 0xef, 0xf7, 0xe6,
+ 0xff, 0xf7, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xef, 0xf7,
+ 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xe6, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xf7, 0xff, 0xef,
+ 0xf7, 0xff, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+ 0xe6, 0xff, 0xf7, 0xff,
+ 0xef, 0xf7, 0xff, 0xef, 0xde, 0xef, 0xce, 0xe6, 0xad, 0xc5, 0xad, 0xd6,
+ 0xff, 0xff, 0xff, 0x10,
+ 0x29, 0x19, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x31, 0x31,
+ 0x29, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x10, 0x21, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x29,
+ 0x19, 0x08, 0x08, 0x10,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6b, 0x5a, 0x73, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xef, 0xf7,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xde, 0xef,
+ 0xce, 0xde, 0xce, 0xce,
+ 0xde, 0xce, 0xce, 0xad, 0xad, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x21, 0x00, 0x08, 0x08,
+ 0x10, 0x08, 0x08, 0x10, 0x4a, 0x52, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x4a, 0x52, 0x4a,
+ 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0xf7, 0xe6,
+ 0xef, 0xf7, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6,
+ 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xe6, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6,
+ 0xff, 0xff, 0xff, 0xef,
+ 0xde, 0xef, 0xce, 0xde, 0xce, 0xef, 0xf7, 0xff, 0x08, 0x08, 0x10, 0x00,
+ 0x00, 0x00, 0x3a, 0x10,
+ 0x21, 0x31, 0x31, 0x29, 0x31, 0x31, 0x29, 0x08, 0x08, 0x10, 0x10, 0x29,
+ 0x19, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x29, 0x19,
+ 0x3a, 0x10, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x7b, 0x94,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xef, 0xf7,
+ 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xf7, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0x4a,
+ 0x52, 0x4a, 0x00, 0x00,
+ 0x00, 0x10, 0x29, 0x19, 0x4a, 0x52, 0x4a, 0x31, 0x31, 0x29, 0x08, 0x08,
+ 0x10, 0x3a, 0x31, 0x4a,
+ 0x08, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00,
+ 0x4a, 0x52, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10,
+ 0xef, 0xf7, 0xe6, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xff, 0xff,
+ 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff,
+ 0xff, 0xff, 0xef, 0xf7,
+ 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xf7, 0xff,
+ 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xce, 0xde,
+ 0xce, 0x3a, 0x10, 0x21, 0x10, 0x29, 0x19, 0x3a, 0x31, 0x4a, 0x3a, 0x10,
+ 0x21, 0x10, 0x21, 0x00,
+ 0x08, 0x08, 0x10, 0x31, 0x31, 0x29, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x08, 0x10, 0x3a, 0x10, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x7b, 0x94, 0xef,
+ 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xe6, 0xde, 0xde, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x4a, 0x52, 0x4a, 0x08, 0x08, 0x10,
+ 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x4a, 0x52, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x08, 0x10, 0xef,
+ 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xe6, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xe6, 0xef, 0xef, 0xf7, 0xe6,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xff, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xff, 0xff,
+ 0xf7, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0x3a, 0x10, 0x21, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x31, 0x29,
+ 0x08, 0x08, 0x10, 0x08,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x31, 0x31, 0x29, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x4a,
+ 0x52, 0x4a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xe6, 0xde, 0xde,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x4a, 0x52,
+ 0x4a, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x08, 0x10, 0x31,
+ 0x31, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x31, 0x29, 0x08, 0x08, 0x10,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xe6, 0xde, 0xde, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xef, 0xf7,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6,
+ 0xe6, 0xde, 0xde, 0xef,
+ 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xf7,
+ 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xe6,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xff, 0xef,
+ 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xf7, 0xff, 0xef, 0xf7,
+ 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+ 0xff, 0x9c, 0x7b, 0x94,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x08,
+ 0x08, 0x10, 0x10, 0x29, 0x19, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x52, 0x4a,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x29, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7,
+ 0xe6, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xe6, 0xce,
+ 0xe6, 0xef, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xef, 0xf7, 0xe6, 0xff,
+ 0xff, 0xff, 0xef, 0xf7,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xe6, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff,
+ 0xff, 0xff, 0xef, 0xf7,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xa5, 0xb5, 0xb5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+ 0x08, 0x08, 0x10, 0x00,
+ 0x00, 0x00, 0x08, 0x08, 0x10, 0x3a, 0x10, 0x21, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x31, 0x31, 0x29, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x52, 0x4a, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xf7, 0xff,
+ 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xf7, 0xff, 0xef,
+ 0xf7, 0xe6, 0xe6, 0xde, 0xde, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xf7,
+ 0xff, 0xef, 0xf7, 0xe6,
+ 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xe6,
+ 0xff, 0xff, 0xff, 0xce, 0xde, 0xce, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x00, 0x00, 0x10, 0x29, 0x19, 0x08, 0x08, 0x10, 0x00,
+ 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+ 0x08, 0x08, 0x10, 0x31,
+ 0x31, 0x29, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0xce, 0xad, 0xad, 0xef,
+ 0xf7, 0xff, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xff, 0xff,
+ 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xef, 0xde, 0xef, 0xef, 0xf7, 0xe6, 0xff,
+ 0xff, 0xff, 0xef, 0xf7,
+ 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff,
+ 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10, 0x29, 0x19, 0x08,
+ 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10,
+ 0x21, 0x00, 0x3a, 0x31, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xce,
+ 0xe6, 0xef, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xe6,
+ 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff,
+ 0xff, 0xf7, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xf7, 0xff, 0xce, 0xe6, 0xef, 0xe6, 0xde, 0xde, 0xef,
+ 0xf7, 0xff, 0xef, 0xf7,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xe6,
+ 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff,
+ 0xff, 0xff, 0xef, 0xf7,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xff,
+ 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x3a,
+ 0x31, 0x4a, 0x08, 0x08,
+ 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x08, 0x10, 0x4a, 0x52, 0x4a, 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0xef, 0xf7,
+ 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xe6,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xe6, 0xde, 0xde, 0xe6,
+ 0xde, 0xde, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xff, 0xff,
+ 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xf7, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xe6, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x4a, 0x52,
+ 0x4a, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x10, 0x21, 0x4a, 0x52, 0x4a, 0x00,
+ 0x00, 0x00, 0x08, 0x08,
+ 0x10, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce,
+ 0xe6, 0xef, 0xe6, 0xde,
+ 0xde, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xff,
+ 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff,
+ 0xff, 0xf7, 0xff, 0xff,
+ 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x10, 0x29, 0x19, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x3a, 0x31, 0x4a, 0x6b,
+ 0x7b, 0x73, 0x08, 0x00,
+ 0x00, 0x10, 0x29, 0x19, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff,
+ 0xff, 0xff, 0xe6, 0xde,
+ 0xde, 0xef, 0xf7, 0xe6, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xe6,
+ 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xef, 0xf7, 0xe6,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xef, 0xf7, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x29, 0x19, 0x08, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00,
+ 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10,
+ 0x29, 0x19, 0x6b, 0x5a,
+ 0x73, 0x08, 0x00, 0x00, 0x10, 0x29, 0x19, 0xff, 0xf7, 0xff, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xe6,
+ 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xe6, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xe6, 0xde, 0xde, 0xe6, 0xde, 0xde, 0xff, 0xff, 0xff, 0xef, 0xf7,
+ 0xe6, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xff, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x08, 0x10, 0x31, 0x31, 0x29, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x31, 0x31, 0x29, 0x08, 0x00, 0x00, 0x31, 0x31, 0x29, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xf7,
+ 0xff, 0xef, 0xf7, 0xff, 0xe6, 0xde, 0xde, 0xef, 0xf7, 0xe6, 0xef, 0xf7,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff,
+ 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xe6, 0xde, 0xde, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x10, 0x29, 0x19, 0x08, 0x08,
+ 0x10, 0x08, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x31, 0x4a, 0x31, 0x31,
+ 0x29, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xe6, 0xff,
+ 0xff, 0xff, 0xff, 0xf7, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe6, 0xde, 0xde, 0xce, 0xe6,
+ 0xef, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff,
+ 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff,
+ 0xff, 0xff, 0xef, 0xf7,
+ 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xef, 0xf7, 0xff, 0xff, 0xf7,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff,
+ 0xff, 0xf7, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa5,
+ 0xb5, 0xb5, 0x00, 0x00,
+ 0x00, 0x10, 0x21, 0x00, 0x3a, 0x31, 0x4a, 0x10, 0x29, 0x19, 0x3a, 0x08,
+ 0x00, 0x08, 0x08, 0x10,
+ 0x08, 0x08, 0x10, 0x31, 0x31, 0x29, 0x31, 0x31, 0x29, 0x10, 0x29, 0x19,
+ 0x08, 0x08, 0x10, 0x00,
+ 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x10,
+ 0x7b, 0x9c, 0x10, 0xc5,
+ 0xef, 0x10, 0xc5, 0xef, 0x10, 0x7b, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x4a, 0x52, 0x4a,
+ 0xef, 0xf7, 0xe6, 0xff, 0xf7, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xe6, 0xff, 0xf7,
+ 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe6, 0xde,
+ 0xde, 0xef, 0xf7, 0xe6,
+ 0xff, 0xf7, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xf7, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0x6b, 0x5a,
+ 0x4a, 0x08, 0x08, 0x10, 0x08, 0x08, 0x10, 0x08, 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x08, 0x08, 0x10,
+ 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00,
+ 0x3a, 0x10, 0x21, 0x6b,
+ 0x5a, 0x73, 0x10, 0x29, 0x19, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19,
+ 0x94, 0xce, 0x08, 0xad,
+ 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x08, 0xad,
+ 0xd6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x4a, 0x5a, 0x73, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+ 0xff, 0xe6, 0xde, 0xde,
+ 0xef, 0xde, 0xef, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xff, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xe6, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xe6, 0xef, 0xce,
+ 0xe6, 0xef, 0xce, 0xe6,
+ 0xef, 0x08, 0x10, 0x42, 0x10, 0x29, 0x19, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x31, 0x31, 0x29, 0x4a, 0x52, 0x4a, 0x08, 0x08, 0x10, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19,
+ 0x7b, 0xbd, 0x00, 0x9c,
+ 0xd6, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd,
+ 0xf7, 0x19, 0xbd, 0xf7,
+ 0x00, 0x9c, 0xd6, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x4a, 0x52, 0x4a,
+ 0xef, 0xde, 0xef, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xef, 0xf7,
+ 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+ 0xe6, 0xff, 0xff, 0xff,
+ 0xe6, 0xde, 0xde, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xe6, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xef, 0xf7, 0xff, 0xef, 0xf7, 0xff, 0x08, 0xad, 0xd6, 0x19,
+ 0xbd, 0xf7, 0x00, 0xbd,
+ 0xef, 0x10, 0xc5, 0xef, 0x10, 0xc5, 0xef, 0x08, 0x08, 0x10, 0x08, 0x08,
+ 0x10, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x08, 0x10, 0x31, 0x31, 0x29, 0x10, 0x29, 0x19, 0x3a,
+ 0x10, 0x21, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x84,
+ 0xbd, 0x08, 0xad, 0xd6, 0x08, 0xad, 0xef, 0x08, 0xad, 0xef, 0x10, 0xc5,
+ 0xef, 0x00, 0xbd, 0xf7,
+ 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x19, 0x7b, 0xbd, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x31,
+ 0x31, 0x29, 0xe6, 0xde, 0xde, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff,
+ 0xff, 0xff, 0xef, 0xf7,
+ 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xce, 0xe6, 0xef, 0xef, 0xf7, 0xe6, 0xef, 0xf7, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xe6,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xe6, 0xef, 0x08,
+ 0xad, 0xef, 0x00, 0xbd,
+ 0xf7, 0x10, 0xe6, 0xef, 0x10, 0xc5, 0xef, 0x10, 0xe6, 0xef, 0x08, 0x08,
+ 0x10, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x08, 0x00, 0x00, 0x10, 0x29, 0x19, 0x10, 0x29, 0x19, 0x00,
+ 0x00, 0x00, 0x00, 0x84,
+ 0xbd, 0x10, 0xe6, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x19, 0x7b,
+ 0xbd, 0x00, 0x9c, 0xd6, 0x08, 0xad, 0xef, 0x10, 0xc5, 0xef, 0x19, 0xbd,
+ 0xf7, 0x00, 0xbd, 0xf7,
+ 0x08, 0xad, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x10, 0xc5, 0xef,
+ 0x10, 0x5a, 0x9c, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x29, 0x19, 0xce, 0xde, 0xce, 0xff,
+ 0xf7, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+ 0xe6, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe6, 0xde, 0xde, 0xef, 0xde, 0xef,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xef, 0xf7,
+ 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xce,
+ 0xe6, 0xef, 0x00, 0x9c,
+ 0xd6, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x08, 0xad,
+ 0xd6, 0x08, 0x08, 0x10,
+ 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x08, 0x10, 0x00,
+ 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x08, 0x10, 0x08, 0x00, 0x00, 0x08,
+ 0x08, 0x10, 0x08, 0x31,
+ 0x3a, 0x10, 0xc5, 0xef, 0x10, 0xc5, 0xef, 0x10, 0xc5, 0xef, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x84,
+ 0xbd, 0x19, 0x94, 0xce, 0x08, 0xad, 0xef, 0x08, 0xad, 0xef, 0x08, 0xad,
+ 0xef, 0x00, 0xbd, 0xef,
+ 0x19, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7,
+ 0x10, 0xc5, 0xef, 0x00,
+ 0xbd, 0xef, 0x08, 0x31, 0x3a, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x9c, 0xa5,
+ 0x94, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xe6, 0xef,
+ 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xff,
+ 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xce, 0xe6,
+ 0xef, 0x08, 0xad, 0xd6, 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd,
+ 0xef, 0x19, 0x94, 0xce,
+ 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x19, 0x94, 0xce, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xef, 0x10, 0xc5,
+ 0xef, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x84, 0xbd, 0x00,
+ 0x84, 0xbd, 0x19, 0x94, 0xce, 0x08, 0xad, 0xef, 0x00, 0x84, 0xbd, 0x19,
+ 0x94, 0xce, 0x00, 0x84,
+ 0xbd, 0x08, 0xad, 0xd6, 0x00, 0x9c, 0xd6, 0x08, 0xad, 0xef, 0x10, 0xc5,
+ 0xef, 0x19, 0xbd, 0xf7,
+ 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7,
+ 0x00, 0xbd, 0xf7, 0x00,
+ 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xd6, 0x08, 0x08, 0x10, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x4a, 0x52, 0x4a, 0xff, 0xf7, 0xff, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xe6,
+ 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xef, 0xf7,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xe6,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xff, 0xff,
+ 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xe6, 0xef, 0xde,
+ 0xef, 0x9c, 0xde, 0xd6, 0x08, 0xad, 0xef, 0x08, 0xad, 0xef, 0x10, 0xc5,
+ 0xef, 0x08, 0xad, 0xef,
+ 0x00, 0x84, 0xbd, 0x08, 0x31, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x21, 0x00, 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x10, 0x5a, 0x9c, 0x08, 0xad, 0xd6, 0x00, 0xbd, 0xef, 0x10, 0xc5,
+ 0xef, 0x10, 0xc5, 0xef,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x19,
+ 0x94, 0xce, 0x08, 0xad, 0xef, 0x08, 0xad, 0xd6, 0x08, 0xad, 0xef, 0x08,
+ 0xad, 0xef, 0x08, 0xad,
+ 0xef, 0x08, 0xad, 0xef, 0x08, 0xad, 0xef, 0x08, 0xad, 0xef, 0x10, 0xc5,
+ 0xef, 0x00, 0xbd, 0xf7,
+ 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7,
+ 0x10, 0xc5, 0xef, 0x00,
+ 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x19,
+ 0x7b, 0xbd, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x31,
+ 0x29, 0xce, 0xe6, 0xef,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff,
+ 0xff, 0xff, 0xef, 0xf7,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff,
+ 0xff, 0xff, 0xce, 0xe6,
+ 0xef, 0xce, 0xad, 0xad, 0x9c, 0xad, 0xce, 0x19, 0x94, 0xce, 0x08, 0xad,
+ 0xef, 0x00, 0xbd, 0xef,
+ 0x19, 0x94, 0xce, 0x00, 0x9c, 0xd6, 0x10, 0x5a, 0x9c, 0x08, 0x08, 0x10,
+ 0x00, 0x00, 0x00, 0x08,
+ 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00,
+ 0x00, 0x00, 0x08, 0x08,
+ 0x10, 0x10, 0x73, 0x7b, 0x00, 0x9c, 0xd6, 0x00, 0xbd, 0xef, 0x10, 0xc5,
+ 0xef, 0x08, 0xad, 0xef,
+ 0x00, 0xbd, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x84, 0xbd, 0x00, 0x9c, 0xd6, 0x08, 0xad, 0xef, 0x10, 0xc5, 0xef, 0x08,
+ 0xad, 0xef, 0x10, 0xc5,
+ 0xef, 0x08, 0xad, 0xef, 0x10, 0xc5, 0xef, 0x19, 0xbd, 0xf7, 0x19, 0xbd,
+ 0xf7, 0x19, 0xbd, 0xf7,
+ 0x00, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7,
+ 0x19, 0xbd, 0xf7, 0x00,
+ 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef, 0x19, 0xbd, 0xf7, 0x00,
+ 0xbd, 0xef, 0x10, 0xce,
+ 0xce, 0x08, 0x31, 0x3a, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x08, 0x10, 0xce, 0xde, 0xce, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xf7, 0xff, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xff,
+ 0xff, 0xf7, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff,
+ 0xff, 0xff, 0xef, 0xf7,
+ 0xe6, 0xc5, 0xad, 0xd6, 0xce, 0xde, 0xce, 0x9c, 0xad, 0xce, 0x08, 0xad,
+ 0xd6, 0x08, 0xad, 0xef,
+ 0x08, 0xad, 0xef, 0x08, 0xad, 0xef, 0x00, 0x9c, 0xd6, 0x19, 0x7b, 0xbd,
+ 0x10, 0x7b, 0x9c, 0x08,
+ 0x31, 0x5a, 0x08, 0x31, 0x3a, 0x08, 0x08, 0x10, 0x08, 0x31, 0x3a, 0x08,
+ 0x31, 0x3a, 0x10, 0x5a,
+ 0x9c, 0x00, 0x84, 0xbd, 0x00, 0x9c, 0xd6, 0x19, 0x94, 0xce, 0x00, 0xbd,
+ 0xef, 0x08, 0xad, 0xef,
+ 0x10, 0xc5, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x19, 0x7b, 0xbd, 0x19, 0x94, 0xce, 0x08, 0xad, 0xef, 0x08,
+ 0xad, 0xef, 0x00, 0xbd,
+ 0xef, 0x19, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x10, 0xc5,
+ 0xef, 0x00, 0xbd, 0xf7,
+ 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x00, 0xbd, 0xf7,
+ 0x19, 0xbd, 0xf7, 0x00,
+ 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00,
+ 0xbd, 0xf7, 0x10, 0xc5,
+ 0xef, 0x00, 0xbd, 0xf7, 0x19, 0x94, 0xce, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x7b, 0x94,
+ 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff,
+ 0xff, 0xff, 0xef, 0xf7,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xf7, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xf7, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xa5, 0xb5, 0xb5, 0xce, 0xde, 0xce, 0x9c, 0xad,
+ 0xce, 0x19, 0x94, 0xce,
+ 0x08, 0xad, 0xd6, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xd6, 0x00, 0x9c, 0xd6,
+ 0x00, 0x9c, 0xd6, 0x00,
+ 0x84, 0xbd, 0x00, 0x84, 0xbd, 0x00, 0x84, 0xbd, 0x00, 0x84, 0xbd, 0x19,
+ 0x7b, 0xbd, 0x00, 0x84,
+ 0xbd, 0x00, 0x84, 0xbd, 0x00, 0x84, 0xbd, 0x08, 0xad, 0xef, 0x08, 0xad,
+ 0xef, 0x10, 0xc5, 0xef,
+ 0x19, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x00, 0xbd, 0xef, 0x08, 0xad, 0xef,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0xbd, 0x08, 0xad, 0xd6, 0x08,
+ 0xad, 0xef, 0x10, 0xc5,
+ 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x19, 0xbd,
+ 0xf7, 0x00, 0xbd, 0xf7,
+ 0x19, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7,
+ 0x00, 0xbd, 0xef, 0x19,
+ 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef, 0x00,
+ 0xbd, 0xf7, 0x19, 0xbd,
+ 0xf7, 0x00, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xef, 0x10, 0x52,
+ 0x7b, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x6b,
+ 0x7b, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xef, 0xf7,
+ 0xe6, 0xef, 0xf7, 0xff,
+ 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff,
+ 0xff, 0xff, 0xef, 0xf7,
+ 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xce, 0xad, 0xad, 0xce, 0xde,
+ 0xce, 0xa5, 0xb5, 0xb5,
+ 0x00, 0x9c, 0xd6, 0x08, 0xad, 0xef, 0x08, 0xad, 0xef, 0x08, 0xad, 0xef,
+ 0x19, 0x94, 0xce, 0x00,
+ 0x9c, 0xd6, 0x19, 0x94, 0xce, 0x00, 0x84, 0xbd, 0x19, 0x94, 0xce, 0x00,
+ 0x84, 0xbd, 0x00, 0x84,
+ 0xbd, 0x00, 0x84, 0xbd, 0x19, 0x94, 0xce, 0x08, 0xad, 0xef, 0x08, 0xad,
+ 0xef, 0x19, 0xbd, 0xf7,
+ 0x00, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x10, 0xc5, 0xef,
+ 0x10, 0xc5, 0xef, 0x19,
+ 0x94, 0xce, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x7b, 0xbd, 0x19,
+ 0x94, 0xce, 0x08, 0xad,
+ 0xef, 0x08, 0xad, 0xef, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x19, 0xbd,
+ 0xf7, 0x00, 0xbd, 0xf7,
+ 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x00, 0xbd, 0xf7, 0x10, 0xc5, 0xef,
+ 0x00, 0xbd, 0xf7, 0x08,
+ 0xad, 0xef, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00,
+ 0xbd, 0xf7, 0x19, 0xbd,
+ 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x10, 0xc5,
+ 0xef, 0x08, 0xad, 0xd6,
+ 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xce, 0xde, 0xce, 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xe6, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xef, 0xf7, 0xff, 0xce, 0xde,
+ 0xce, 0xc5, 0xad, 0xd6,
+ 0xa5, 0xb5, 0xb5, 0x19, 0x94, 0xce, 0x00, 0x9c, 0xd6, 0x08, 0xad, 0xd6,
+ 0x08, 0xad, 0xef, 0x08,
+ 0xad, 0xef, 0x08, 0xad, 0xef, 0x00, 0x9c, 0xd6, 0x00, 0x9c, 0xd6, 0x00,
+ 0x9c, 0xd6, 0x00, 0x9c,
+ 0xd6, 0x19, 0x94, 0xce, 0x08, 0xad, 0xef, 0x08, 0xad, 0xd6, 0x08, 0xad,
+ 0xef, 0x19, 0xbd, 0xf7,
+ 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xf7,
+ 0x10, 0xc5, 0xef, 0x08,
+ 0xad, 0xef, 0x08, 0xad, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x84, 0xbd, 0x00, 0x9c,
+ 0xd6, 0x08, 0xad, 0xd6, 0x08, 0xad, 0xef, 0x19, 0xbd, 0xf7, 0x19, 0xbd,
+ 0xf7, 0x00, 0xbd, 0xef,
+ 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x19, 0xbd, 0xf7,
+ 0x00, 0xbd, 0xf7, 0x19,
+ 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x10,
+ 0xc5, 0xef, 0x00, 0xbd,
+ 0xf7, 0x10, 0xc5, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x00, 0xbd,
+ 0xf7, 0x19, 0xbd, 0xf7,
+ 0x00, 0xbd, 0xef, 0x19, 0x7b, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6b, 0x5a, 0x73, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xe6, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+ 0xe6, 0xce, 0xde, 0xce,
+ 0xa5, 0xb5, 0xb5, 0x9c, 0xad, 0xce, 0x00, 0x84, 0xbd, 0x00, 0x9c, 0xd6,
+ 0x08, 0xad, 0xef, 0x10,
+ 0xc5, 0xef, 0x08, 0xad, 0xef, 0x08, 0xad, 0xd6, 0x08, 0xad, 0xef, 0x19,
+ 0x94, 0xce, 0x08, 0xad,
+ 0xef, 0x19, 0x94, 0xce, 0x08, 0xad, 0xef, 0x08, 0xad, 0xd6, 0x08, 0xad,
+ 0xef, 0x00, 0xbd, 0xef,
+ 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x08, 0xad, 0xef,
+ 0x19, 0xbd, 0xf7, 0x00,
+ 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef, 0x08, 0xad, 0xd6, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x7b, 0xe6, 0x08, 0xad, 0xd6, 0x08, 0xad, 0xef, 0x00, 0xbd,
+ 0xef, 0x00, 0xbd, 0xf7,
+ 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7,
+ 0x00, 0xbd, 0xf7, 0x08,
+ 0xad, 0xef, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x08,
+ 0xad, 0xef, 0x00, 0xbd,
+ 0xf7, 0x19, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x10, 0xc5, 0xef, 0x00, 0xbd,
+ 0xf7, 0x19, 0xbd, 0xf7,
+ 0x10, 0xc5, 0xef, 0x10, 0xe6, 0xef, 0x00, 0xbd, 0xef, 0x08, 0x31, 0x3a,
+ 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a,
+ 0x52, 0x4a, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xe6, 0xff,
+ 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xf7, 0xff,
+ 0xe6, 0xde, 0xde, 0xc5, 0xad, 0xd6, 0x29, 0x5a, 0x4a, 0x00, 0x84, 0xbd,
+ 0x19, 0x94, 0xce, 0x08,
+ 0xad, 0xd6, 0x08, 0xad, 0xef, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef, 0x00,
+ 0xbd, 0xef, 0x08, 0xad,
+ 0xef, 0x08, 0xad, 0xef, 0x08, 0xad, 0xd6, 0x08, 0xad, 0xef, 0x08, 0xad,
+ 0xef, 0x08, 0xad, 0xef,
+ 0x19, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7,
+ 0x00, 0xbd, 0xf7, 0x00,
+ 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x19,
+ 0xbd, 0xf7, 0x00, 0xbd,
+ 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x19, 0x94, 0xce, 0x08, 0xad, 0xd6, 0x08, 0xad,
+ 0xef, 0x19, 0xbd, 0xf7,
+ 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7,
+ 0x10, 0xc5, 0xef, 0x19,
+ 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x10,
+ 0xc5, 0xef, 0x19, 0xbd,
+ 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd,
+ 0xf7, 0x00, 0xbd, 0xf7,
+ 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef, 0x00, 0xbd, 0xf7, 0x10, 0xc5, 0xef,
+ 0x08, 0xad, 0xd6, 0x08,
+ 0x08, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x9c, 0xa5,
+ 0x94, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xf7,
+ 0xff, 0xef, 0xf7, 0xe6,
+ 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xf7, 0xff, 0xef, 0xf7, 0xe6,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xef, 0xf7,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+ 0xe6, 0xff, 0xf7, 0xff,
+ 0xef, 0xf7, 0xff, 0xce, 0xde, 0xce, 0x4a, 0x52, 0x4a, 0x08, 0x31, 0x5a,
+ 0x00, 0x84, 0xbd, 0x00,
+ 0x9c, 0xd6, 0x08, 0xad, 0xef, 0x08, 0xad, 0xef, 0x19, 0xbd, 0xf7, 0x10,
+ 0xc5, 0xef, 0x08, 0xad,
+ 0xef, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef, 0x00, 0xbd, 0xef, 0x10, 0xc5,
+ 0xef, 0x08, 0xad, 0xef,
+ 0x00, 0xbd, 0xef, 0x10, 0xc5, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7,
+ 0x19, 0xbd, 0xf7, 0x00,
+ 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x00,
+ 0xbd, 0xef, 0x00, 0xbd,
+ 0xf7, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef, 0x08, 0xad, 0xef, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0xd6, 0x19, 0x94,
+ 0xce, 0x19, 0xbd, 0xf7,
+ 0x00, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7,
+ 0x08, 0xad, 0xef, 0x19,
+ 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x10,
+ 0xc5, 0xef, 0x00, 0xbd,
+ 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19, 0xbd,
+ 0xf7, 0x00, 0xbd, 0xf7,
+ 0x08, 0xad, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7,
+ 0x10, 0xc5, 0xef, 0x10,
+ 0xc5, 0xef, 0x10, 0x5a, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x9c, 0x7b,
+ 0x94, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xff, 0xff, 0xf7, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xe6, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x4a, 0x52, 0x4a, 0x08, 0x00, 0x00,
+ 0x08, 0x31, 0x5a, 0x00,
+ 0x84, 0xbd, 0x19, 0x94, 0xce, 0x08, 0xad, 0xef, 0x10, 0xc5, 0xef, 0x08,
+ 0xad, 0xef, 0x19, 0xbd,
+ 0xf7, 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x00, 0xbd,
+ 0xf7, 0x19, 0xbd, 0xf7,
+ 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x10, 0xc5, 0xef,
+ 0x00, 0xbd, 0xf7, 0x19,
+ 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x19,
+ 0xbd, 0xf7, 0x00, 0xbd,
+ 0xf7, 0x19, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19, 0xbd,
+ 0xf7, 0x19, 0xbd, 0xf7,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x94,
+ 0xce, 0x00, 0x9c, 0xd6,
+ 0x08, 0xad, 0xef, 0x10, 0xc5, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xef,
+ 0x19, 0xbd, 0xf7, 0x00,
+ 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19,
+ 0xbd, 0xf7, 0x00, 0xbd,
+ 0xf7, 0x19, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef, 0x00, 0xbd,
+ 0xf7, 0x19, 0xbd, 0xf7,
+ 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x10, 0xc5, 0xef,
+ 0x08, 0xad, 0xef, 0x00,
+ 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xd6, 0x10, 0x73, 0x7b, 0xe6,
+ 0xde, 0xde, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0x31, 0x31, 0x29, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10,
+ 0x52, 0x7b, 0x00, 0x84, 0xbd, 0x08, 0xad, 0xd6, 0x08, 0xad, 0xef, 0x08,
+ 0xad, 0xef, 0x00, 0xbd,
+ 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x08, 0xad,
+ 0xef, 0x19, 0xbd, 0xf7,
+ 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7,
+ 0x00, 0xbd, 0xf7, 0x19,
+ 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19,
+ 0xbd, 0xf7, 0x00, 0xbd,
+ 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x00, 0xbd, 0xf7, 0x19, 0xbd,
+ 0xf7, 0x00, 0xbd, 0xf7,
+ 0x00, 0xbd, 0xef, 0x08, 0xad, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x84, 0xbd,
+ 0x00, 0x9c, 0xd6, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x08, 0xad, 0xef,
+ 0x19, 0xbd, 0xf7, 0x00,
+ 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x19,
+ 0xbd, 0xf7, 0x00, 0xbd,
+ 0xf7, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd,
+ 0xf7, 0x19, 0xbd, 0xf7,
+ 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7,
+ 0x00, 0xbd, 0xf7, 0x19,
+ 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xd6, 0x10, 0xc5, 0xef, 0x19,
+ 0x94, 0xce, 0x9c, 0xad,
+ 0xce, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xe6, 0xff,
+ 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xe6, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xf7, 0xff, 0xef, 0xde, 0xef, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x52, 0x7b, 0x00, 0x84, 0xbd, 0x19, 0x94, 0xce, 0x08,
+ 0xad, 0xef, 0x08, 0xad,
+ 0xef, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x10, 0xc5,
+ 0xef, 0x00, 0xbd, 0xf7,
+ 0x00, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x10, 0xc5, 0xef,
+ 0x00, 0xbd, 0xf7, 0x10,
+ 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x08,
+ 0xad, 0xef, 0x10, 0xc5,
+ 0xef, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x10, 0xc5,
+ 0xef, 0x00, 0xbd, 0xf7,
+ 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef, 0x08, 0xad, 0xef, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x84, 0xbd,
+ 0x00, 0x84, 0xbd, 0x08, 0xad, 0xef, 0x08, 0xad, 0xef, 0x19, 0xbd, 0xf7,
+ 0x00, 0xbd, 0xf7, 0x00,
+ 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x19,
+ 0xbd, 0xf7, 0x00, 0xbd,
+ 0xef, 0x19, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd,
+ 0xf7, 0x10, 0xc5, 0xef,
+ 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x10, 0xc5, 0xef,
+ 0x00, 0xbd, 0xf7, 0x10,
+ 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x10,
+ 0xc5, 0xef, 0x08, 0xad,
+ 0xd6, 0x10, 0x7b, 0x9c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xff,
+ 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff,
+ 0xff, 0xef, 0xf7, 0xff,
+ 0xff, 0xff, 0xff, 0x9c, 0xa5, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x08, 0x08, 0x10, 0x10, 0x52, 0x7b, 0x00, 0x84, 0xbd, 0x08,
+ 0xad, 0xd6, 0x00, 0xbd,
+ 0xef, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd,
+ 0xf7, 0x19, 0xbd, 0xf7,
+ 0x00, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef, 0x19, 0xbd, 0xf7,
+ 0x08, 0xad, 0xef, 0x19,
+ 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x19,
+ 0xbd, 0xf7, 0x00, 0xbd,
+ 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd,
+ 0xf7, 0x19, 0xbd, 0xf7,
+ 0x08, 0xad, 0xef, 0x08, 0xad, 0xef, 0x19, 0x94, 0xce, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x84, 0xbd, 0x19, 0x94, 0xce, 0x08, 0xad, 0xef, 0x08, 0xad, 0xef,
+ 0x00, 0xbd, 0xef, 0x19,
+ 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19,
+ 0xbd, 0xf7, 0x00, 0xbd,
+ 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd,
+ 0xf7, 0x10, 0xc5, 0xef,
+ 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7,
+ 0x08, 0xad, 0xef, 0x00,
+ 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x10, 0xc5, 0xef, 0x00,
+ 0xbd, 0xef, 0x10, 0xc5,
+ 0xef, 0x08, 0xad, 0xd6, 0x00, 0x84, 0xbd, 0x10, 0x52, 0x7b, 0xef, 0xf7,
+ 0xe6, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xef, 0xf7,
+ 0xff, 0xff, 0xf7, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xf7, 0xff,
+ 0xce, 0xde, 0xce, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x52, 0x7b, 0x00,
+ 0x84, 0xbd, 0x19, 0x94,
+ 0xce, 0x08, 0xad, 0xef, 0x08, 0xad, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd,
+ 0xf7, 0x19, 0xbd, 0xf7,
+ 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7,
+ 0x19, 0xbd, 0xf7, 0x00,
+ 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x19,
+ 0xbd, 0xf7, 0x00, 0xbd,
+ 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd,
+ 0xef, 0x19, 0xbd, 0xf7,
+ 0x08, 0xad, 0xef, 0x08, 0xad, 0xd6, 0x00, 0x9c, 0xd6, 0x19, 0x7b, 0xbd,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x84, 0xbd, 0x19, 0x94, 0xce, 0x00, 0xbd, 0xf7,
+ 0x19, 0xbd, 0xf7, 0x19,
+ 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19,
+ 0xbd, 0xf7, 0x00, 0xbd,
+ 0xef, 0x00, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x10, 0xc5,
+ 0xef, 0x08, 0xad, 0xef,
+ 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef,
+ 0x00, 0xbd, 0xf7, 0x19,
+ 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00,
+ 0xbd, 0xf7, 0x19, 0xbd,
+ 0xf7, 0x00, 0xbd, 0xef, 0x08, 0xad, 0xd6, 0x08, 0xad, 0xd6, 0x10, 0x52,
+ 0x7b, 0x3a, 0x31, 0x4a,
+ 0xef, 0xf7, 0xe6, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6,
+ 0xff, 0xff, 0xff, 0xef,
+ 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xce, 0xde, 0xce,
+ 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x08, 0x08, 0x10, 0x10,
+ 0x52, 0x7b, 0x00, 0x84,
+ 0xbd, 0x00, 0x9c, 0xd6, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef, 0x00, 0xbd,
+ 0xf7, 0x10, 0xc5, 0xef,
+ 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x00, 0xbd, 0xf7,
+ 0x19, 0xbd, 0xf7, 0x00,
+ 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x00,
+ 0xbd, 0xf7, 0x00, 0xbd,
+ 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd,
+ 0xef, 0x08, 0xad, 0xef,
+ 0x08, 0xad, 0xef, 0x19, 0x94, 0xce, 0x19, 0x94, 0xce, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x19, 0x7b, 0xbd, 0x00, 0x84, 0xbd, 0x08, 0xad, 0xef,
+ 0x10, 0xc5, 0xef, 0x00,
+ 0xbd, 0xef, 0x08, 0xad, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19,
+ 0xbd, 0xf7, 0x00, 0xbd,
+ 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x08, 0xad,
+ 0xef, 0x19, 0xbd, 0xf7,
+ 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7,
+ 0x00, 0xbd, 0xf7, 0x19,
+ 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x10,
+ 0xc5, 0xef, 0x00, 0xbd,
+ 0xf7, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef, 0x08, 0xad, 0xd6, 0x00, 0x9c,
+ 0xd6, 0x10, 0x7b, 0x9c,
+ 0x08, 0x31, 0x5a, 0x00, 0x00, 0x00, 0x4a, 0x5a, 0x73, 0xce, 0xde, 0xce,
+ 0xef, 0xf7, 0xe6, 0xff,
+ 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xef, 0xf7,
+ 0xe6, 0xef, 0xf7, 0xff, 0xef, 0xf7, 0xe6, 0xa5, 0xb5, 0xb5, 0x6b, 0x5a,
+ 0x73, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+ 0x31, 0x3a, 0x10, 0x52,
+ 0x7b, 0x19, 0x7b, 0xbd, 0x00, 0x9c, 0xd6, 0x08, 0xad, 0xef, 0x10, 0xc5,
+ 0xef, 0x19, 0xbd, 0xf7,
+ 0x08, 0xad, 0xef, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7,
+ 0x08, 0xad, 0xef, 0x10,
+ 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19,
+ 0xbd, 0xf7, 0x00, 0xbd,
+ 0xef, 0x19, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x10, 0xc5, 0xef, 0x08, 0xad,
+ 0xef, 0x08, 0xad, 0xef,
+ 0x19, 0x94, 0xce, 0x00, 0x9c, 0xd6, 0x19, 0x7b, 0xbd, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0xbd, 0x00, 0x9c, 0xd6,
+ 0x19, 0x94, 0xce, 0x08,
+ 0xad, 0xef, 0x08, 0xad, 0xef, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef, 0x00,
+ 0xbd, 0xf7, 0x10, 0xc5,
+ 0xef, 0x08, 0xad, 0xef, 0x00, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x00, 0xbd,
+ 0xf7, 0x19, 0xbd, 0xf7,
+ 0x00, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef,
+ 0x00, 0xbd, 0xf7, 0x19,
+ 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x19,
+ 0xbd, 0xf7, 0x08, 0xad,
+ 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x08, 0xad,
+ 0xd6, 0x19, 0x94, 0xce,
+ 0x00, 0x84, 0xbd, 0x10, 0x52, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x08, 0x10, 0x10, 0x29, 0x19, 0x31, 0x31, 0x29, 0x31,
+ 0x31, 0x29, 0x08, 0x08,
+ 0x10, 0x08, 0x08, 0x10, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x31,
+ 0x3a, 0x10, 0x52, 0x7b, 0x00, 0x84, 0xbd, 0x00, 0x9c, 0xd6, 0x08, 0xad,
+ 0xef, 0x10, 0xc5, 0xef,
+ 0x08, 0xad, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7,
+ 0x00, 0xbd, 0xf7, 0x19,
+ 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19,
+ 0xbd, 0xf7, 0x08, 0xad,
+ 0xef, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef, 0x10, 0xc5, 0xef, 0x08, 0xad,
+ 0xef, 0x00, 0x84, 0xbd,
+ 0x19, 0x94, 0xce, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0xbd,
+ 0x19, 0x94, 0xce, 0x00,
+ 0x9c, 0xd6, 0x00, 0x9c, 0xd6, 0x08, 0xad, 0xef, 0x08, 0xad, 0xd6, 0x08,
+ 0xad, 0xef, 0x08, 0xad,
+ 0xef, 0x08, 0xad, 0xef, 0x08, 0xad, 0xef, 0x19, 0xbd, 0xf7, 0x08, 0xad,
+ 0xef, 0x08, 0xad, 0xef,
+ 0x19, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7,
+ 0x00, 0xbd, 0xf7, 0x19,
+ 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19,
+ 0xbd, 0xf7, 0x00, 0xbd,
+ 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x08, 0xad,
+ 0xef, 0x08, 0xad, 0xef,
+ 0x00, 0x9c, 0xd6, 0x10, 0x5a, 0x9c, 0x10, 0x52, 0x7b, 0x08, 0x31, 0x3a,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x08, 0x10, 0x08, 0x00, 0x00, 0x08,
+ 0x08, 0x10, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x31, 0x5a, 0x10, 0x5a, 0x9c, 0x00, 0x84, 0xbd, 0x19, 0x94,
+ 0xce, 0x08, 0xad, 0xef,
+ 0x08, 0xad, 0xef, 0x00, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7,
+ 0x00, 0xbd, 0xf7, 0x10,
+ 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x10,
+ 0xc5, 0xef, 0x00, 0xbd,
+ 0xef, 0x08, 0xad, 0xef, 0x08, 0xad, 0xef, 0x19, 0x94, 0xce, 0x00, 0x9c,
+ 0xd6, 0x00, 0x84, 0xbd,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x7b, 0x9c, 0x00,
+ 0x84, 0xbd, 0x00, 0x84, 0xbd, 0x19, 0x94, 0xce, 0x00, 0x84, 0xbd, 0x19,
+ 0x94, 0xce, 0x00, 0x9c,
+ 0xd6, 0x19, 0x94, 0xce, 0x00, 0x9c, 0xd6, 0x08, 0xad, 0xd6, 0x08, 0xad,
+ 0xef, 0x08, 0xad, 0xd6,
+ 0x08, 0xad, 0xef, 0x08, 0xad, 0xef, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef,
+ 0x10, 0xc5, 0xef, 0x08,
+ 0xad, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19,
+ 0xbd, 0xf7, 0x00, 0xbd,
+ 0xef, 0x10, 0xc5, 0xef, 0x19, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x00, 0xbd,
+ 0xf7, 0x08, 0xad, 0xd6,
+ 0x19, 0x94, 0xce, 0x00, 0x84, 0xbd, 0x10, 0x7b, 0x9c, 0x10, 0x52, 0x7b,
+ 0x08, 0x31, 0x5a, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00,
+ 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x31, 0x3a, 0x10, 0x52, 0x7b, 0x00, 0x84,
+ 0xbd, 0x00, 0x84, 0xbd,
+ 0x08, 0xad, 0xd6, 0x08, 0xad, 0xef, 0x19, 0xbd, 0xf7, 0x10, 0xc5, 0xef,
+ 0x00, 0xbd, 0xf7, 0x10,
+ 0xc5, 0xef, 0x08, 0xad, 0xef, 0x19, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x00,
+ 0xbd, 0xf7, 0x08, 0xad,
+ 0xef, 0x19, 0x94, 0xce, 0x08, 0xad, 0xd6, 0x00, 0x9c, 0xd6, 0x00, 0x9c,
+ 0xd6, 0x10, 0x5a, 0x9c,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x5a, 0x9c, 0x10, 0x5a, 0x9c, 0x10,
+ 0x5a, 0x9c, 0x00, 0x84,
+ 0xbd, 0x19, 0x7b, 0xbd, 0x00, 0x84, 0xbd, 0x00, 0x84, 0xbd, 0x19, 0x94,
+ 0xce, 0x00, 0x84, 0xbd,
+ 0x19, 0x94, 0xce, 0x00, 0x9c, 0xd6, 0x19, 0x94, 0xce, 0x08, 0xad, 0xef,
+ 0x19, 0x94, 0xce, 0x08,
+ 0xad, 0xef, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef, 0x00, 0xbd, 0xef, 0x19,
+ 0xbd, 0xf7, 0x00, 0xbd,
+ 0xef, 0x19, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x00, 0xbd, 0xf7, 0x10, 0xc5,
+ 0xef, 0x08, 0xad, 0xef,
+ 0x08, 0xad, 0xef, 0x00, 0x84, 0xbd, 0x00, 0x84, 0xbd, 0x10, 0x5a, 0x9c,
+ 0x10, 0x52, 0x7b, 0x08,
+ 0x31, 0x3a, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x31, 0x5a, 0x10, 0x52,
+ 0x7b, 0x00, 0x84, 0xbd,
+ 0x00, 0x84, 0xbd, 0x19, 0x94, 0xce, 0x08, 0xad, 0xd6, 0x08, 0xad, 0xef,
+ 0x19, 0xbd, 0xf7, 0x08,
+ 0xad, 0xef, 0x08, 0xad, 0xef, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef, 0x00,
+ 0xbd, 0xef, 0x08, 0xad,
+ 0xef, 0x19, 0x94, 0xce, 0x08, 0xad, 0xef, 0x00, 0x84, 0xbd, 0x00, 0x84,
+ 0xbd, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x73, 0x7b, 0x10, 0x5a, 0x9c, 0x10, 0x7b,
+ 0x9c, 0x10, 0x5a, 0xbd,
+ 0x00, 0x84, 0xbd, 0x10, 0x7b, 0x9c, 0x00, 0x84, 0xbd, 0x00, 0x84, 0xbd,
+ 0x00, 0x84, 0xbd, 0x00,
+ 0x84, 0xbd, 0x00, 0x84, 0xbd, 0x19, 0x94, 0xce, 0x00, 0x9c, 0xd6, 0x08,
+ 0xad, 0xef, 0x08, 0xad,
+ 0xef, 0x08, 0xad, 0xef, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef, 0x08, 0xad,
+ 0xef, 0x08, 0xad, 0xef,
+ 0x08, 0xad, 0xd6, 0x19, 0x94, 0xce, 0x00, 0x84, 0xbd, 0x10, 0x5a, 0x9c,
+ 0x10, 0x52, 0x7b, 0x10,
+ 0x52, 0x7b, 0x08, 0x31, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x21, 0x00, 0x08,
+ 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x31,
+ 0x3a, 0x10, 0x52, 0x7b,
+ 0x10, 0x5a, 0x9c, 0x00, 0x84, 0xbd, 0x00, 0x84, 0xbd, 0x08, 0xad, 0xef,
+ 0x08, 0xad, 0xd6, 0x08,
+ 0xad, 0xef, 0x08, 0xad, 0xef, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef, 0x08,
+ 0xad, 0xef, 0x19, 0x94,
+ 0xce, 0x00, 0x9c, 0xd6, 0x00, 0x84, 0xbd, 0x19, 0x7b, 0xbd, 0x10, 0x5a,
+ 0x9c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x5a, 0x9c, 0x10, 0x52, 0x7b, 0x10, 0x5a, 0x9c,
+ 0x10, 0x5a, 0x9c, 0x10,
+ 0x5a, 0x9c, 0x10, 0x5a, 0x9c, 0x10, 0x7b, 0x9c, 0x00, 0x84, 0xbd, 0x00,
+ 0x84, 0xbd, 0x19, 0x94,
+ 0xce, 0x00, 0x9c, 0xd6, 0x19, 0x94, 0xce, 0x00, 0x9c, 0xd6, 0x08, 0xad,
+ 0xef, 0x08, 0xad, 0xd6,
+ 0x19, 0x94, 0xce, 0x00, 0x84, 0xbd, 0x00, 0x84, 0xbd, 0x10, 0x5a, 0x9c,
+ 0x10, 0x52, 0x7b, 0x10,
+ 0x52, 0x7b, 0x08, 0x31, 0x5a, 0x08, 0x08, 0x10, 0x08, 0x08, 0x10, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x31, 0x3a,
+ 0x08, 0x31, 0x5a, 0x10, 0x5a, 0x9c, 0x10, 0x5a, 0x9c, 0x19, 0x7b, 0xbd,
+ 0x00, 0x84, 0xbd, 0x00,
+ 0x9c, 0xd6, 0x08, 0xad, 0xd6, 0x19, 0x94, 0xce, 0x00, 0x9c, 0xd6, 0x19,
+ 0x94, 0xce, 0x00, 0x9c,
+ 0xd6, 0x00, 0x84, 0xbd, 0x00, 0x84, 0xbd, 0x00, 0x84, 0xbd, 0x10, 0x5a,
+ 0x9c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x52, 0x7b, 0x10, 0x52, 0x7b, 0x10, 0x5a, 0x9c, 0x10,
+ 0x5a, 0x9c, 0x10, 0x5a,
+ 0x9c, 0x10, 0x5a, 0x9c, 0x10, 0x7b, 0x9c, 0x00, 0x84, 0xbd, 0x19, 0x7b,
+ 0xbd, 0x00, 0x84, 0xbd,
+ 0x19, 0x7b, 0xbd, 0x00, 0x84, 0xbd, 0x00, 0x84, 0xbd, 0x10, 0x5a, 0x9c,
+ 0x10, 0x52, 0x7b, 0x10,
+ 0x52, 0x7b, 0x08, 0x31, 0x5a, 0x08, 0x31, 0x5a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x31, 0x5a, 0x10, 0x5a, 0x9c, 0x10, 0x7b, 0x9c,
+ 0x00, 0x84, 0xbd, 0x00,
+ 0x84, 0xbd, 0x19, 0x7b, 0xbd, 0x00, 0x84, 0xbd, 0x00, 0x84, 0xbd, 0x00,
+ 0x84, 0xbd, 0x00, 0x84,
+ 0xbd, 0x19, 0x7b, 0xbd, 0x10, 0x7b, 0x9c, 0x10, 0x5a, 0x9c, 0x10, 0x52,
+ 0x7b, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x31, 0x5a, 0x10, 0x52, 0x7b, 0x10, 0x52, 0x7b, 0x10, 0x5a,
+ 0x9c, 0x10, 0x73, 0x7b,
+ 0x10, 0x5a, 0x9c, 0x10, 0x5a, 0x9c, 0x10, 0x5a, 0x9c, 0x10, 0x52, 0x7b,
+ 0x10, 0x52, 0x7b, 0x10,
+ 0x52, 0x7b, 0x08, 0x31, 0x5a, 0x08, 0x31, 0x3a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x31, 0x5a, 0x08, 0x31, 0x5a,
+ 0x10, 0x52, 0x7b, 0x10,
+ 0x5a, 0x9c, 0x10, 0x5a, 0x9c, 0x10, 0x7b, 0x9c, 0x10, 0x5a, 0x9c, 0x00,
+ 0x84, 0xbd, 0x00, 0x84,
+ 0xbd, 0x10, 0x7b, 0x9c, 0x10, 0x5a, 0x9c, 0x10, 0x5a, 0x9c, 0x08, 0x31,
+ 0x5a, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x31,
+ 0x5a, 0x10, 0x52, 0x7b,
+ 0x08, 0x31, 0x5a, 0x10, 0x52, 0x7b, 0x10, 0x52, 0x7b, 0x08, 0x31, 0x5a,
+ 0x10, 0x52, 0x7b, 0x08,
+ 0x31, 0x5a, 0x08, 0x31, 0x5a, 0x08, 0x31, 0x3a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x31, 0x5a, 0x08,
+ 0x31, 0x5a, 0x10, 0x52, 0x7b, 0x10, 0x5a, 0x9c, 0x10, 0x5a, 0x9c, 0x10,
+ 0x5a, 0x9c, 0x10, 0x5a,
+ 0x9c, 0x10, 0x5a, 0x9c, 0x10, 0x52, 0x7b, 0x10, 0x52, 0x7b, 0x08, 0x31,
+ 0x5a, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x31, 0x5a, 0x08, 0x31, 0x5a,
+ 0x08, 0x31, 0x5a, 0x08,
+ 0x31, 0x5a, 0x08, 0x31, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x31, 0x3a, 0x08, 0x31, 0x5a, 0x08,
+ 0x31, 0x5a, 0x10, 0x52,
+ 0x7b, 0x08, 0x31, 0x5a, 0x08, 0x31, 0x5a, 0x08, 0x31, 0x3a, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+};
+
+#endif
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
index 4bbd07a..8da837b 100644
--- a/fs/ext4/balloc.c
+++ b/fs/ext4/balloc.c
@@ -90,8 +90,8 @@
* unusual file system layouts.
*/
if (ext4_block_in_group(sb, ext4_block_bitmap(sb, gdp), block_group)) {
- block_cluster = EXT4_B2C(sbi, (start -
- ext4_block_bitmap(sb, gdp)));
+ block_cluster = EXT4_B2C(sbi,
+ ext4_block_bitmap(sb, gdp) - start);
if (block_cluster < num_clusters)
block_cluster = -1;
else if (block_cluster == num_clusters) {
@@ -102,7 +102,7 @@
if (ext4_block_in_group(sb, ext4_inode_bitmap(sb, gdp), block_group)) {
inode_cluster = EXT4_B2C(sbi,
- start - ext4_inode_bitmap(sb, gdp));
+ ext4_inode_bitmap(sb, gdp) - start);
if (inode_cluster < num_clusters)
inode_cluster = -1;
else if (inode_cluster == num_clusters) {
@@ -114,7 +114,7 @@
itbl_blk = ext4_inode_table(sb, gdp);
for (i = 0; i < sbi->s_itb_per_group; i++) {
if (ext4_block_in_group(sb, itbl_blk + i, block_group)) {
- c = EXT4_B2C(sbi, start - itbl_blk + i);
+ c = EXT4_B2C(sbi, itbl_blk + i - start);
if ((c < num_clusters) || (c == inode_cluster) ||
(c == block_cluster) || (c == itbl_cluster))
continue;
diff --git a/fs/ext4/ext4_jbd2.c b/fs/ext4/ext4_jbd2.c
index aca1790..d0b8f98 100644
--- a/fs/ext4/ext4_jbd2.c
+++ b/fs/ext4/ext4_jbd2.c
@@ -109,10 +109,10 @@
if (ext4_handle_valid(handle)) {
err = jbd2_journal_dirty_metadata(handle, bh);
- if (err) {
- /* Errors can only happen if there is a bug */
- handle->h_err = err;
- __ext4_journal_stop(where, line, handle);
+ /* Errors can only happen if there is a bug */
+ if (WARN_ON_ONCE(err)) {
+ ext4_journal_abort_handle(where, line, __func__, bh,
+ handle, err);
}
} else {
if (inode)
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index e1fb1d5..48609bc 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -4105,6 +4105,7 @@
ext4_commit_super(sb, 1);
jbd2_journal_clear_err(journal);
+ jbd2_journal_update_sb_errno(journal);
}
}
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index e88748e..6c27436 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -1267,6 +1267,8 @@
s_min_extra_isize) {
tried_min_extra_isize++;
new_extra_isize = s_min_extra_isize;
+ kfree(is); is = NULL;
+ kfree(bs); bs = NULL;
goto retry;
}
error = -1;
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index 1afb701..9956ac6 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -1340,7 +1340,7 @@
* Update a journal's errno. Write updated superblock to disk waiting for IO
* to complete.
*/
-static void jbd2_journal_update_sb_errno(journal_t *journal)
+void jbd2_journal_update_sb_errno(journal_t *journal)
{
journal_superblock_t *sb = journal->j_superblock;
@@ -1352,6 +1352,7 @@
jbd2_write_superblock(journal, WRITE_SYNC);
}
+EXPORT_SYMBOL(jbd2_journal_update_sb_errno);
/*
* Read the superblock for a given journal, performing initial
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
old mode 100644
new mode 100755
index f66a034..4640d3b
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -99,7 +99,6 @@
header-y += connector.h
header-y += const.h
header-y += cramfs_fs.h
-header-y += csdio.h
header-y += cuda.h
header-y += cyclades.h
header-y += cycx_cfm.h
@@ -325,6 +324,7 @@
header-y += ptrace.h
header-y += qnx4_fs.h
header-y += qnxtypes.h
+header-y += qrng.h
header-y += quota.h
header-y += radeonfb.h
header-y += random.h
@@ -453,3 +453,4 @@
header-y += msm_audio_amrwbplus.h
header-y += avtimer.h
header-y += msm_ipa.h
+header-y += msm_thermal_ioctl.h
diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h
index 81e803e..20b8446 100644
--- a/include/linux/clockchips.h
+++ b/include/linux/clockchips.h
@@ -55,6 +55,11 @@
#define CLOCK_EVT_FEAT_C3STOP 0x000008
#define CLOCK_EVT_FEAT_DUMMY 0x000010
+/*
+ * Core shall set the interrupt affinity dynamically in broadcast mode
+ */
+#define CLOCK_EVT_FEAT_DYNIRQ 0x000020
+
/**
* struct clock_event_device - clock event device descriptor
* @event_handler: Assigned by the framework to be called by the low
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index 5ab7183..6b76dfd7 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -147,7 +147,9 @@
extern void cpuidle_unregister_driver(struct cpuidle_driver *drv);
extern int cpuidle_register_device(struct cpuidle_device *dev);
extern void cpuidle_unregister_device(struct cpuidle_device *dev);
-
+extern int cpuidle_register(struct cpuidle_driver *drv,
+ const struct cpumask *const coupled_cpus);
+extern void cpuidle_unregister(struct cpuidle_driver *drv);
extern void cpuidle_pause_and_lock(void);
extern void cpuidle_resume_and_unlock(void);
extern int cpuidle_enable_device(struct cpuidle_device *dev);
@@ -168,7 +170,10 @@
static inline int cpuidle_register_device(struct cpuidle_device *dev)
{return -ENODEV; }
static inline void cpuidle_unregister_device(struct cpuidle_device *dev) { }
-
+static inline int cpuidle_register(struct cpuidle_driver *drv,
+ const struct cpumask *const coupled_cpus)
+{return -ENODEV; }
+static inline void cpuidle_unregister(struct cpuidle_driver *drv) { }
static inline void cpuidle_pause_and_lock(void) { }
static inline void cpuidle_resume_and_unlock(void) { }
static inline int cpuidle_enable_device(struct cpuidle_device *dev)
diff --git a/include/linux/csdio.h b/include/linux/csdio.h
deleted file mode 100644
index 260c49d..0000000
--- a/include/linux/csdio.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef CSDIO_H
-#define CSDIO_H
-
-#include <linux/ioctl.h>
-
-#define CSDIO_IOC_MAGIC 'm'
-
-#define CSDIO_IOC_ENABLE_HIGHSPEED_MODE _IO(CSDIO_IOC_MAGIC, 0)
-#define CSDIO_IOC_SET_DATA_TRANSFER_CLOCKS _IO(CSDIO_IOC_MAGIC, 1)
-#define CSDIO_IOC_SET_OP_CODE _IO(CSDIO_IOC_MAGIC, 2)
-#define CSDIO_IOC_FUNCTION_SET_BLOCK_SIZE _IO(CSDIO_IOC_MAGIC, 3)
-#define CSDIO_IOC_SET_BLOCK_MODE _IO(CSDIO_IOC_MAGIC, 4)
-#define CSDIO_IOC_CONNECT_ISR _IO(CSDIO_IOC_MAGIC, 5)
-#define CSDIO_IOC_DISCONNECT_ISR _IO(CSDIO_IOC_MAGIC, 6)
-#define CSDIO_IOC_CMD52 _IO(CSDIO_IOC_MAGIC, 7)
-#define CSDIO_IOC_CMD53 _IO(CSDIO_IOC_MAGIC, 8)
-#define CSDIO_IOC_ENABLE_ISR _IO(CSDIO_IOC_MAGIC, 9)
-#define CSDIO_IOC_DISABLE_ISR _IO(CSDIO_IOC_MAGIC, 10)
-#define CSDIO_IOC_SET_VDD _IO(CSDIO_IOC_MAGIC, 11)
-#define CSDIO_IOC_GET_VDD _IO(CSDIO_IOC_MAGIC, 12)
-
-#define CSDIO_IOC_MAXNR 12
-
-struct csdio_cmd53_ctrl_t {
- uint32_t m_block_mode; /* data tran. byte(0)/block(1) mode */
- uint32_t m_op_code; /* address auto increment flag */
- uint32_t m_address;
-} __attribute__ ((packed));
-
-struct csdio_cmd52_ctrl_t {
- uint32_t m_write;
- uint32_t m_address;
- uint32_t m_data;
- uint32_t m_ret;
-} __attribute__ ((packed));
-
-#endif
diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
index 9c74fbb..d00847a 100644
--- a/include/linux/devfreq.h
+++ b/include/linux/devfreq.h
@@ -52,6 +52,9 @@
*/
#define DEVFREQ_FLAG_LEAST_UPPER_BOUND 0x1
+#define DEVFREQ_FLAG_FAST_HINT 0x2
+#define DEVFREQ_FLAG_SLOW_HINT 0x4
+
/**
* struct devfreq_governor_data - mapping to per device governor data
* @name: The name of the governor.
@@ -132,7 +135,8 @@
struct list_head node;
const char name[DEVFREQ_NAME_LEN];
- int (*get_target_freq)(struct devfreq *this, unsigned long *freq);
+ int (*get_target_freq)(struct devfreq *this, unsigned long *freq,
+ u32 *flag);
int (*event_handler)(struct devfreq *devfreq,
unsigned int event, void *data);
};
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index 0739ece..d525e84 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -726,25 +726,27 @@
};
/* LOG CODES */
+static const uint32_t log_code_last_tbl[] = {
+ 0x0, /* EQUIP ID 0 */
+ 0x182F, /* EQUIP ID 1 */
+ 0x0, /* EQUIP ID 2 */
+ 0x0, /* EQUIP ID 3 */
+ 0x4910, /* EQUIP ID 4 */
+ 0x5420, /* EQUIP ID 5 */
+ 0x0, /* EQUIP ID 6 */
+ 0x74FF, /* EQUIP ID 7 */
+ 0x0, /* EQUIP ID 8 */
+ 0x0, /* EQUIP ID 9 */
+ 0xA38A, /* EQUIP ID 10 */
+ 0xB201, /* EQUIP ID 11 */
+ 0x0, /* EQUIP ID 12 */
+ 0x0, /* EQUIP ID 13 */
+ 0x0, /* EQUIP ID 14 */
+ 0x0, /* EQUIP ID 15 */
+};
-#define LOG_0 0x0
-#define LOG_1 0x1808
-#define LOG_2 0x0
-#define LOG_3 0x0
-#define LOG_4 0x4910
-#define LOG_5 0x5420
-#define LOG_6 0x0
-#define LOG_7 0x74FF
-#define LOG_8 0x0
-#define LOG_9 0x0
-#define LOG_10 0xA38A
-#define LOG_11 0xB201
-#define LOG_12 0x0
-#define LOG_13 0x0
-#define LOG_14 0x0
-#define LOG_15 0x0
-
-#define LOG_GET_ITEM_NUM(xx_code) (xx_code & 0x0FFF)
-#define LOG_GET_EQUIP_ID(xx_code) ((xx_code & 0xF000) >> 12)
+#define LOG_GET_ITEM_NUM(xx_code) (xx_code & 0x0FFF)
+#define LOG_GET_EQUIP_ID(xx_code) ((xx_code & 0xF000) >> 12)
+#define LOG_ITEMS_TO_SIZE(num_items) ((num_items+7)/8)
#endif
diff --git a/include/linux/dma-contiguous.h b/include/linux/dma-contiguous.h
index 8a1b3a1..78e57cd 100644
--- a/include/linux/dma-contiguous.h
+++ b/include/linux/dma-contiguous.h
@@ -65,6 +65,9 @@
*/
#define MAX_CMA_AREAS (1 + CONFIG_CMA_AREAS)
+
+phys_addr_t cma_get_base(struct device *dev);
+
extern struct cma *dma_contiguous_def_area;
void dma_contiguous_reserve(phys_addr_t addr_limit);
@@ -129,6 +132,12 @@
return false;
}
+
+static inline phys_addr_t cma_get_base(struct device *dev)
+{
+ return 0;
+}
+
#endif
#endif
diff --git a/include/linux/input.h b/include/linux/input.h
index d4cdb02..558178b 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -167,6 +167,7 @@
#define INPUT_PROP_DIRECT 0x01 /* direct input devices */
#define INPUT_PROP_BUTTONPAD 0x02 /* has button(s) under pad */
#define INPUT_PROP_SEMI_MT 0x03 /* touch rectangle only */
+#define INPUT_PROP_NO_DUMMY_RELEASE 0x04 /* no dummy event */
#define INPUT_PROP_MAX 0x1f
#define INPUT_PROP_CNT (INPUT_PROP_MAX + 1)
diff --git a/include/linux/ion.h b/include/linux/ion.h
index 4983316..7131da3 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -22,6 +22,8 @@
#include <linux/types.h>
struct ion_handle;
+typedef struct ion_handle *ion_user_handle_t;
+
/**
* enum ion_heap_types - list of all possible types of heaps
* @ION_HEAP_TYPE_SYSTEM: memory allocated via vmalloc
@@ -58,6 +60,14 @@
#define ION_FLAG_CACHED_NEEDS_SYNC 2 /* mappings of this buffer will created
at mmap time, if this is set
caches must be managed manually */
+#define ION_FLAG_FREED_FROM_SHRINKER 4 /* Skip any possible
+ heap-specific caching
+ mechanism (e.g. page
+ pools). Guarantees that any
+ buffer storage that came
+ from the system allocator
+ will be returned to the
+ system allocator. */
#ifdef __KERNEL__
#include <linux/err.h>
@@ -342,7 +352,7 @@
size_t align;
unsigned int heap_mask;
unsigned int flags;
- struct ion_handle *handle;
+ ion_user_handle_t handle;
};
/**
@@ -356,7 +366,7 @@
* provides the file descriptor and the kernel returns the handle.
*/
struct ion_fd_data {
- struct ion_handle *handle;
+ ion_user_handle_t handle;
int fd;
};
@@ -365,7 +375,7 @@
* @handle: a handle
*/
struct ion_handle_data {
- struct ion_handle *handle;
+ ion_user_handle_t handle;
};
/**
diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
index 912c30a..2ed66ef 100644
--- a/include/linux/jbd2.h
+++ b/include/linux/jbd2.h
@@ -1091,6 +1091,7 @@
extern int jbd2_journal_recover (journal_t *journal);
extern int jbd2_journal_wipe (journal_t *, int);
extern int jbd2_journal_skip_recovery (journal_t *);
+extern void jbd2_journal_update_sb_errno(journal_t *);
extern void jbd2_journal_update_sb_log_tail (journal_t *, tid_t,
unsigned long, int);
extern void __jbd2_journal_abort_hard (journal_t *);
diff --git a/include/linux/kref.h b/include/linux/kref.h
index aa5acc26..6f515f2 100644
--- a/include/linux/kref.h
+++ b/include/linux/kref.h
@@ -18,6 +18,7 @@
#include <linux/bug.h>
#include <linux/atomic.h>
#include <linux/kernel.h>
+#include <linux/mutex.h>
struct kref {
atomic_t refcount;
@@ -94,6 +95,23 @@
return kref_sub(kref, 1, release);
}
+static inline int kref_put_mutex(struct kref *kref,
+ void (*release)(struct kref *kref),
+ struct mutex *lock)
+{
+ WARN_ON(release == NULL);
+ if (unlikely(!atomic_add_unless(&kref->refcount, -1, 1))) {
+ mutex_lock(lock);
+ if (unlikely(!atomic_dec_and_test(&kref->refcount))) {
+ mutex_unlock(lock);
+ return 0;
+ }
+ release(kref);
+ return 1;
+ }
+ return 0;
+}
+
/**
* kref_get_unless_zero - Increment refcount for object unless it is zero.
diff --git a/include/linux/mm.h b/include/linux/mm.h
index a5fa304..2218ac4 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -806,6 +806,17 @@
return (void *)((unsigned long)page->mapping & ~PAGE_MAPPING_FLAGS);
}
+extern struct address_space *__page_file_mapping(struct page *);
+
+static inline
+struct address_space *page_file_mapping(struct page *page)
+{
+ if (unlikely(PageSwapCache(page)))
+ return __page_file_mapping(page);
+
+ return page->mapping;
+}
+
static inline int PageAnon(struct page *page)
{
return ((unsigned long)page->mapping & PAGE_MAPPING_ANON) != 0;
@@ -822,6 +833,20 @@
return page->index;
}
+extern pgoff_t __page_file_index(struct page *page);
+
+/*
+ * Return the file index of the page. Regular pagecache pages use ->index
+ * whereas swapcache pages use swp_offset(->private)
+ */
+static inline pgoff_t page_file_index(struct page *page)
+{
+ if (unlikely(PageSwapCache(page)))
+ return __page_file_index(page);
+
+ return page->index;
+}
+
/*
* Return true if this page is mapped into pagetables.
*/
diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h
index 227fd3e..9a584c0 100644
--- a/include/linux/mm_inline.h
+++ b/include/linux/mm_inline.h
@@ -2,6 +2,7 @@
#define LINUX_MM_INLINE_H
#include <linux/huge_mm.h>
+#include <linux/swap.h>
/**
* page_is_file_cache - should the page be on a file LRU or anon LRU?
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index d0ad3e4..1740576 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -219,6 +219,7 @@
MMC_BLK_NEW_REQUEST,
MMC_BLK_URGENT,
MMC_BLK_URGENT_DONE,
+ MMC_BLK_NO_REQ_TO_STOP,
};
struct mmc_wr_pack_stats {
@@ -351,6 +352,9 @@
#define MMC_QUIRK_INAND_DATA_TIMEOUT (1<<8) /* For incorrect data timeout */
/* To avoid eMMC device getting broken permanently due to HPI feature */
#define MMC_QUIRK_BROKEN_HPI (1 << 11)
+ /* Skip data-timeout advertised by card */
+#define MMC_QUIRK_BROKEN_DATA_TIMEOUT (1<<12)
+
unsigned int erase_size; /* erase size in sectors */
unsigned int erase_shift; /* if erase unit is power 2 */
@@ -391,7 +395,7 @@
unsigned int idle_timeout;
struct notifier_block reboot_notify;
bool issue_long_pon;
- u8 cached_ext_csd;
+ u8 *cached_ext_csd;
};
/*
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index e1dbd21..bff056d 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -300,6 +300,7 @@
#define MMC_CAP2_HS400_1_8V (1 << 21) /* can support */
#define MMC_CAP2_HS400_1_2V (1 << 22) /* can support */
+#define MMC_CAP2_CORE_PM (1 << 23) /* use PM framework */
#define MMC_CAP2_HS400 (MMC_CAP2_HS400_1_8V | \
MMC_CAP2_HS400_1_2V)
mmc_pm_flag_t pm_caps; /* supported pm features */
@@ -572,4 +573,9 @@
return host->caps2 & MMC_CAP2_CORE_RUNTIME_PM;
}
+static inline int mmc_use_core_pm(struct mmc_host *host)
+{
+ return host->caps2 & MMC_CAP2_CORE_PM;
+}
+
#endif /* LINUX_MMC_HOST_H */
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 7539e03..381fff5 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -375,7 +375,6 @@
* free areas of different sizes
*/
spinlock_t lock;
- int all_unreclaimable; /* All pages pinned */
#if defined CONFIG_COMPACTION || defined CONFIG_CMA
/* Set to true when the PG_migrate_skip bits should be cleared */
bool compact_blockskip_flush;
diff --git a/include/linux/msm_adreno_devfreq.h b/include/linux/msm_adreno_devfreq.h
new file mode 100644
index 0000000..53d7085
--- /dev/null
+++ b/include/linux/msm_adreno_devfreq.h
@@ -0,0 +1,47 @@
+#ifndef MSM_ADRENO_DEVFREQ_H
+#define MSM_ADRENO_DEVFREQ_H
+
+#include <linux/notifier.h>
+
+#define ADRENO_DEVFREQ_NOTIFY_SUBMIT 1
+#define ADRENO_DEVFREQ_NOTIFY_RETIRE 2
+#define ADRENO_DEVFREQ_NOTIFY_IDLE 3
+
+struct device;
+
+int kgsl_devfreq_add_notifier(struct device *, struct notifier_block *);
+
+int kgsl_devfreq_del_notifier(struct device *, struct notifier_block *);
+
+/* same as KGSL_MAX_PWRLEVELS */
+#define MSM_ADRENO_MAX_PWRLEVELS 10
+
+struct xstats {
+ u64 ram_time;
+ u64 ram_wait;
+ int mod;
+};
+
+struct devfreq_msm_adreno_tz_data {
+ struct notifier_block nb;
+ struct {
+ s64 total_time;
+ s64 busy_time;
+ } bin;
+ struct {
+ u64 total_time;
+ u64 ram_time;
+ u64 gpu_time;
+ u32 num;
+ u32 max;
+ u32 up[MSM_ADRENO_MAX_PWRLEVELS];
+ u32 down[MSM_ADRENO_MAX_PWRLEVELS];
+ u32 p_up[MSM_ADRENO_MAX_PWRLEVELS];
+ u32 p_down[MSM_ADRENO_MAX_PWRLEVELS];
+ unsigned int *index;
+ uint64_t *ib;
+ } bus;
+ unsigned int device_id;
+};
+
+#endif
diff --git a/include/linux/msm_audio_acdb.h b/include/linux/msm_audio_acdb.h
index 853899e..8912dc9 100644
--- a/include/linux/msm_audio_acdb.h
+++ b/include/linux/msm_audio_acdb.h
@@ -126,6 +126,8 @@
(AUDIO_MAX_ACDB_IOCTL+9), unsigned)
#define AUDIO_SET_RTAC_CVP_CAL _IOWR(AUDIO_IOCTL_MAGIC, \
(AUDIO_MAX_ACDB_IOCTL+10), unsigned)
+#define AUDIO_GET_RTAC_ADM_INFO_V2 _IOWR(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_ACDB_IOCTL+11), unsigned)
#define AUDIO_MAX_RTAC_IOCTL (AUDIO_MAX_ACDB_IOCTL+20)
diff --git a/include/linux/msm_ion.h b/include/linux/msm_ion.h
index 16a1000..0127edc 100644
--- a/include/linux/msm_ion.h
+++ b/include/linux/msm_ion.h
@@ -5,11 +5,14 @@
enum msm_ion_heap_types {
ION_HEAP_TYPE_MSM_START = ION_HEAP_TYPE_CUSTOM + 1,
- ION_HEAP_TYPE_IOMMU = ION_HEAP_TYPE_MSM_START,
- ION_HEAP_TYPE_DMA,
+ ION_HEAP_TYPE_DMA = ION_HEAP_TYPE_MSM_START,
ION_HEAP_TYPE_CP,
ION_HEAP_TYPE_SECURE_DMA,
ION_HEAP_TYPE_REMOVED,
+ /*
+ * if you add a heap type here you should also add it to
+ * heap_types_info[] in msm_ion.c
+ */
};
/**
@@ -31,17 +34,23 @@
ION_ADSP_HEAP_ID = 22,
ION_PIL1_HEAP_ID = 23, /* Currently used for other PIL images */
ION_SF_HEAP_ID = 24,
- ION_IOMMU_HEAP_ID = 25,
+ ION_SYSTEM_HEAP_ID = 25,
ION_PIL2_HEAP_ID = 26, /* Currently used for modem firmware images */
ION_QSECOM_HEAP_ID = 27,
ION_AUDIO_HEAP_ID = 28,
ION_MM_FIRMWARE_HEAP_ID = 29,
- ION_SYSTEM_HEAP_ID = 30,
ION_HEAP_ID_RESERVED = 31 /** Bit reserved for ION_FLAG_SECURE flag */
};
+/*
+ * The IOMMU heap is deprecated! Here are some aliases for backwards
+ * compatibility:
+ */
+#define ION_IOMMU_HEAP_ID ION_SYSTEM_HEAP_ID
+#define ION_HEAP_TYPE_IOMMU ION_HEAP_TYPE_SYSTEM
+
enum ion_fixed_position {
NOT_FIXED,
FIXED_LOW,
@@ -90,7 +99,8 @@
#define ION_HEAP(bit) (1 << (bit))
#define ION_ADSP_HEAP_NAME "adsp"
-#define ION_VMALLOC_HEAP_NAME "vmalloc"
+#define ION_SYSTEM_HEAP_NAME "system"
+#define ION_VMALLOC_HEAP_NAME ION_SYSTEM_HEAP_NAME
#define ION_KMALLOC_HEAP_NAME "kmalloc"
#define ION_AUDIO_HEAP_NAME "audio"
#define ION_SF_HEAP_NAME "sf"
@@ -187,6 +197,14 @@
enum ion_memory_types memory_type;
};
+/*
+ * struct ion_cma_pdata - extra data for CMA regions
+ * @default_prefetch_size - default size to use for prefetching
+ */
+struct ion_cma_pdata {
+ unsigned long default_prefetch_size;
+};
+
#ifdef CONFIG_ION
/**
* msm_ion_client_create - allocate a client using the ion_device specified in
@@ -494,6 +512,11 @@
unsigned int length;
};
+struct ion_prefetch_data {
+ int heap_id;
+ unsigned long len;
+};
+
#define ION_IOC_MSM_MAGIC 'M'
/**
@@ -518,4 +541,10 @@
#define ION_IOC_CLEAN_INV_CACHES _IOWR(ION_IOC_MSM_MAGIC, 2, \
struct ion_flush_data)
+#define ION_IOC_PREFETCH _IOWR(ION_IOC_MSM_MAGIC, 3, \
+ struct ion_prefetch_data)
+
+#define ION_IOC_DRAIN _IOWR(ION_IOC_MSM_MAGIC, 4, \
+ struct ion_prefetch_data)
+
#endif
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index cd80920..121a00c 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -156,6 +156,7 @@
#define MDSS_MDP_ROT_ONLY 0x80
#define MDSS_MDP_RIGHT_MIXER 0x100
+#define MDSS_MDP_DUAL_PIPE 0x200
/* mdp_blit_req flag values */
#define MDP_ROT_NOP 0
@@ -168,6 +169,7 @@
#define MDP_BLUR 0x10
#define MDP_BLEND_FG_PREMULT 0x20000
#define MDP_IS_FG 0x40000
+#define MDP_SOLID_FILL 0x0000100
#define MDP_DEINTERLACE 0x80000000
#define MDP_SHARPENING 0x40000000
#define MDP_NO_DMA_BARRIER_START 0x20000000
@@ -253,11 +255,19 @@
#define MDP_BLIT_REQ_VERSION 2
+struct color {
+ uint32_t r;
+ uint32_t g;
+ uint32_t b;
+ uint32_t alpha;
+};
+
struct mdp_blit_req {
struct mdp_img src;
struct mdp_img dst;
struct mdp_rect src_rect;
struct mdp_rect dst_rect;
+ struct color const_color;
uint32_t alpha;
uint32_t transp_mask;
uint32_t flags;
@@ -310,6 +320,27 @@
#define MDP_PP_IGC_FLAG_ROM0 0x10
#define MDP_PP_IGC_FLAG_ROM1 0x20
+#define MDP_PP_PA_HUE_ENABLE 0x10
+#define MDP_PP_PA_SAT_ENABLE 0x20
+#define MDP_PP_PA_VAL_ENABLE 0x40
+#define MDP_PP_PA_CONT_ENABLE 0x80
+#define MDP_PP_PA_SIX_ZONE_ENABLE 0x100
+#define MDP_PP_PA_SKIN_ENABLE 0x200
+#define MDP_PP_PA_SKY_ENABLE 0x400
+#define MDP_PP_PA_FOL_ENABLE 0x800
+#define MDP_PP_PA_HUE_MASK 0x1000
+#define MDP_PP_PA_SAT_MASK 0x2000
+#define MDP_PP_PA_VAL_MASK 0x4000
+#define MDP_PP_PA_CONT_MASK 0x8000
+#define MDP_PP_PA_SIX_ZONE_HUE_MASK 0x10000
+#define MDP_PP_PA_SIX_ZONE_SAT_MASK 0x20000
+#define MDP_PP_PA_SIX_ZONE_VAL_MASK 0x40000
+#define MDP_PP_PA_MEM_COL_SKIN_MASK 0x80000
+#define MDP_PP_PA_MEM_COL_SKY_MASK 0x100000
+#define MDP_PP_PA_MEM_COL_FOL_MASK 0x200000
+#define MDP_PP_PA_MEM_PROTECT_EN 0x400000
+#define MDP_PP_PA_SAT_ZERO_EXP_EN 0x800000
+
#define MDSS_PP_DSPP_CFG 0x000
#define MDSS_PP_SSPP_CFG 0x100
#define MDSS_PP_LM_CFG 0x200
@@ -354,6 +385,7 @@
#define MDP_OVERLAY_PP_SHARP_CFG 0x10
#define MDP_OVERLAY_PP_HIST_CFG 0x20
#define MDP_OVERLAY_PP_HIST_LUT_CFG 0x40
+#define MDP_OVERLAY_PP_PA_V2_CFG 0x80
#define MDP_CSC_FLAG_ENABLE 0x1
#define MDP_CSC_FLAG_YUV_IN 0x2
@@ -382,6 +414,32 @@
uint32_t cont_adj;
};
+struct mdp_pa_mem_col_cfg {
+ uint32_t color_adjust_p0;
+ uint32_t color_adjust_p1;
+ uint32_t hue_region;
+ uint32_t sat_region;
+ uint32_t val_region;
+};
+
+#define MDP_SIX_ZONE_LUT_SIZE 384
+
+struct mdp_pa_v2_data {
+ /* Mask bits for PA features */
+ uint32_t flags;
+ uint32_t global_hue_adj;
+ uint32_t global_sat_adj;
+ uint32_t global_val_adj;
+ uint32_t global_cont_adj;
+ struct mdp_pa_mem_col_cfg skin_cfg;
+ struct mdp_pa_mem_col_cfg sky_cfg;
+ struct mdp_pa_mem_col_cfg fol_cfg;
+ uint32_t six_zone_len;
+ uint32_t six_zone_thresh;
+ uint32_t *six_zone_curve_p0;
+ uint32_t *six_zone_curve_p1;
+};
+
struct mdp_igc_lut_data {
uint32_t block;
uint32_t len, ops;
@@ -409,6 +467,7 @@
struct mdp_csc_cfg csc_cfg;
struct mdp_qseed_cfg qseed_cfg[2];
struct mdp_pa_cfg pa_cfg;
+ struct mdp_pa_v2_data pa_v2_cfg;
struct mdp_igc_lut_data igc_cfg;
struct mdp_sharp_cfg sharp_cfg;
struct mdp_histogram_cfg hist_cfg;
@@ -442,6 +501,77 @@
BLEND_OP_MAX,
};
+#define MAX_PLANES 4
+struct mdp_scale_data {
+ uint8_t enable_pxl_ext;
+
+ int init_phase_x[MAX_PLANES];
+ int phase_step_x[MAX_PLANES];
+ int init_phase_y[MAX_PLANES];
+ int phase_step_y[MAX_PLANES];
+
+ int num_ext_pxls_left[MAX_PLANES];
+ int num_ext_pxls_right[MAX_PLANES];
+ int num_ext_pxls_top[MAX_PLANES];
+ int num_ext_pxls_btm[MAX_PLANES];
+
+ int left_ftch[MAX_PLANES];
+ int left_rpt[MAX_PLANES];
+ int right_ftch[MAX_PLANES];
+ int right_rpt[MAX_PLANES];
+
+ int top_rpt[MAX_PLANES];
+ int btm_rpt[MAX_PLANES];
+ int top_ftch[MAX_PLANES];
+ int btm_ftch[MAX_PLANES];
+
+ uint32_t roi_w[MAX_PLANES];
+};
+
+/**
+ * struct mdp_overlay - overlay surface structure
+ * @src: Source image information (width, height, format).
+ * @src_rect: Source crop rectangle, portion of image that will be fetched.
+ * This should always be within boundaries of source image.
+ * @dst_rect: Destination rectangle, the position and size of image on screen.
+ * This should always be within panel boundaries.
+ * @z_order: Blending stage to occupy in display, if multiple layers are
+ * present, highest z_order usually means the top most visible
+ * layer. The range acceptable is from 0-3 to support blending
+ * up to 4 layers.
+ * @is_fg: This flag is used to disable blending of any layers with z_order
+ * less than this overlay. It means that any layers with z_order
+ * less than this layer will not be blended and will be replaced
+ * by the background border color.
+ * @alpha: Used to set plane opacity. The range can be from 0-255, where
+ * 0 means completely transparent and 255 means fully opaque.
+ * @transp_mask: Color used as color key for transparency. Any pixel in fetched
+ * image matching this color will be transparent when blending.
+ * The color should be in same format as the source image format.
+ * @flags: This is used to customize operation of overlay. See MDP flags
+ * for more information.
+ * @user_data: DEPRECATED* Used to store user application specific information.
+ * @bg_color: Solid color used to fill the overlay surface when no source
+ * buffer is provided.
+ * @horz_deci: Horizontal decimation value, this indicates the amount of pixels
+ * dropped for each pixel that is fetched from a line. The value
+ * given should be power of two of decimation amount.
+ * 0: no decimation
+ * 1: decimate by 2 (drop 1 pixel for each pixel fetched)
+ * 2: decimate by 4 (drop 3 pixels for each pixel fetched)
+ * 3: decimate by 8 (drop 7 pixels for each pixel fetched)
+ * 4: decimate by 16 (drop 15 pixels for each pixel fetched)
+ * @vert_deci: Vertical decimation value, this indicates the amount of lines
+ * dropped for each line that is fetched from overlay. The value
+ * given should be power of two of decimation amount.
+ * 0: no decimation
+ * 1: decimation by 2 (drop 1 line for each line fetched)
+ * 2: decimation by 4 (drop 3 lines for each line fetched)
+ * 3: decimation by 8 (drop 7 lines for each line fetched)
+ * 4: decimation by 16 (drop 15 lines for each line fetched)
+ * @overlay_pp_cfg: Overlay post processing configuration, for more information
+ * see struct mdp_overlay_pp_params.
+ */
struct mdp_overlay {
struct msmfb_img src;
struct mdp_rect src_rect;
@@ -453,10 +583,12 @@
uint32_t transp_mask;
uint32_t flags;
uint32_t id;
- uint32_t user_data[7];
+ uint32_t user_data[6];
+ uint32_t bg_color;
uint8_t horz_deci;
uint8_t vert_deci;
struct mdp_overlay_pp_params overlay_pp_cfg;
+ struct mdp_scale_data scale;
};
struct msmfb_overlay_3d {
@@ -482,19 +614,21 @@
uint32_t *b;
};
+#define MISR_CRC_BATCH_SIZE 32
enum {
- DISPLAY_MISR_EDP,
+ DISPLAY_MISR_EDP = 0,
DISPLAY_MISR_DSI0,
DISPLAY_MISR_DSI1,
DISPLAY_MISR_HDMI,
DISPLAY_MISR_LCDC,
+ DISPLAY_MISR_MDP,
DISPLAY_MISR_ATV,
DISPLAY_MISR_DSI_CMD,
DISPLAY_MISR_MAX
};
enum {
- MISR_OP_NONE,
+ MISR_OP_NONE = 0,
MISR_OP_SFM,
MISR_OP_MFM,
MISR_OP_BM,
@@ -505,7 +639,7 @@
uint32_t block_id;
uint32_t frame_count;
uint32_t crc_op_mode;
- uint32_t crc_value[32];
+ uint32_t crc_value[MISR_CRC_BATCH_SIZE];
};
/*
@@ -621,6 +755,11 @@
struct mdp_pa_cfg pa_data;
};
+struct mdp_pa_v2_cfg_data {
+ uint32_t block;
+ struct mdp_pa_v2_data pa_v2_data;
+};
+
struct mdp_dither_cfg_data {
uint32_t block;
uint32_t flags;
@@ -662,10 +801,16 @@
DCM_ENTER,
DCM_EXIT,
DCM_BLANK,
+ DTM_ENTER,
+ DTM_EXIT,
};
+#define MDSS_PP_SPLIT_LEFT_ONLY 0x10000000
+#define MDSS_PP_SPLIT_RIGHT_ONLY 0x20000000
+#define MDSS_PP_SPLIT_MASK 0x30000000
+
#define MDSS_MAX_BL_BRIGHTNESS 255
-#define AD_BL_LIN_LEN (MDSS_MAX_BL_BRIGHTNESS + 1)
+#define AD_BL_LIN_LEN 256
#define MDSS_AD_MODE_AUTO_BL 0x0
#define MDSS_AD_MODE_AUTO_STR 0x1
@@ -749,6 +894,7 @@
mdp_op_qseed_cfg,
mdp_bl_scale_cfg,
mdp_op_pa_cfg,
+ mdp_op_pa_v2_cfg,
mdp_op_dither_cfg,
mdp_op_gamut_cfg,
mdp_op_calib_cfg,
@@ -780,6 +926,7 @@
struct mdp_qseed_cfg_data qseed_cfg_data;
struct mdp_bl_scale_data bl_scale_data;
struct mdp_pa_cfg_data pa_cfg_data;
+ struct mdp_pa_v2_cfg_data pa_v2_cfg_data;
struct mdp_dither_cfg_data dither_cfg_data;
struct mdp_gamut_cfg_data gamut_cfg_data;
struct mdp_calib_config_data calib_cfg;
diff --git a/include/linux/msm_thermal.h b/include/linux/msm_thermal.h
index 2ca9900..25b5363 100644
--- a/include/linux/msm_thermal.h
+++ b/include/linux/msm_thermal.h
@@ -19,22 +19,30 @@
uint32_t poll_ms;
int32_t limit_temp_degC;
int32_t temp_hysteresis_degC;
- uint32_t freq_step;
- uint32_t freq_control_mask;
+ uint32_t bootup_freq_step;
+ uint32_t bootup_freq_control_mask;
int32_t core_limit_temp_degC;
int32_t core_temp_hysteresis_degC;
int32_t hotplug_temp_degC;
int32_t hotplug_temp_hysteresis_degC;
uint32_t core_control_mask;
+ uint32_t freq_mitig_temp_degc;
+ uint32_t freq_mitig_temp_hysteresis_degc;
+ uint32_t freq_mitig_control_mask;
+ uint32_t freq_limit;
int32_t vdd_rstr_temp_degC;
int32_t vdd_rstr_temp_hyst_degC;
int32_t psm_temp_degC;
int32_t psm_temp_hyst_degC;
+ int32_t ocr_temp_degC;
+ int32_t ocr_temp_hyst_degC;
};
#ifdef CONFIG_THERMAL_MONITOR
extern int msm_thermal_init(struct msm_thermal_data *pdata);
extern int msm_thermal_device_init(void);
+extern int msm_thermal_set_frequency(uint32_t cpu, uint32_t freq,
+ bool is_max);
#else
static inline int msm_thermal_init(struct msm_thermal_data *pdata)
{
@@ -44,6 +52,11 @@
{
return -ENOSYS;
}
+static inline int msm_thermal_set_frequency(uint32_t cpu, uint32_t freq,
+ bool is_max)
+{
+ return -ENOSYS;
+}
#endif
#endif /*__MSM_THERMAL_H*/
diff --git a/include/linux/msm_thermal_ioctl.h b/include/linux/msm_thermal_ioctl.h
new file mode 100644
index 0000000..7b36493
--- /dev/null
+++ b/include/linux/msm_thermal_ioctl.h
@@ -0,0 +1,41 @@
+#ifndef _MSM_THERMAL_IOCTL_H
+#define _MSM_THERMAL_IOCTL_H
+
+#include <linux/ioctl.h>
+
+#define MSM_THERMAL_IOCTL_NAME "msm_thermal_query"
+
+struct __attribute__((__packed__)) cpu_freq_arg {
+ uint32_t cpu_num;
+ uint32_t freq_req;
+};
+
+struct __attribute__((__packed__)) msm_thermal_ioctl {
+ uint32_t size;
+ union {
+ struct cpu_freq_arg cpu_freq;
+ };
+};
+
+enum {
+ /*Set CPU Frequency*/
+ MSM_SET_CPU_MAX_FREQ = 0x00,
+ MSM_SET_CPU_MIN_FREQ = 0x01,
+
+ MSM_CMD_MAX_NR,
+};
+
+#define MSM_THERMAL_MAGIC_NUM 0xCA /*Unique magic number*/
+
+#define MSM_THERMAL_SET_CPU_MAX_FREQUENCY _IOW(MSM_THERMAL_MAGIC_NUM,\
+ MSM_SET_CPU_MAX_FREQ, struct msm_thermal_ioctl)
+
+#define MSM_THERMAL_SET_CPU_MIN_FREQUENCY _IOW(MSM_THERMAL_MAGIC_NUM,\
+ MSM_SET_CPU_MIN_FREQ, struct msm_thermal_ioctl)
+
+#ifdef __KERNEL__
+extern int msm_thermal_ioctl_init(void);
+extern void msm_thermal_ioctl_cleanup(void);
+#endif
+
+#endif
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index 0844dc3..696ca39 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -295,6 +295,11 @@
return ((loff_t)page->index) << PAGE_CACHE_SHIFT;
}
+static inline loff_t page_file_offset(struct page *page)
+{
+ return ((loff_t)page_file_index(page)) << PAGE_CACHE_SHIFT;
+}
+
extern pgoff_t linear_hugepage_index(struct vm_area_struct *vma,
unsigned long address);
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 22b004e..0065203 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -105,6 +105,7 @@
POWER_SUPPLY_PROP_CURRENT_MAX,
POWER_SUPPLY_PROP_INPUT_CURRENT_MAX,
POWER_SUPPLY_PROP_INPUT_CURRENT_TRIM,
+ POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED,
POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_CURRENT_AVG,
POWER_SUPPLY_PROP_POWER_NOW,
diff --git a/include/linux/qpnp/power-on.h b/include/linux/qpnp/power-on.h
index 772bf62..ae4e731 100644
--- a/include/linux/qpnp/power-on.h
+++ b/include/linux/qpnp/power-on.h
@@ -52,6 +52,7 @@
int qpnp_pon_system_pwr_off(enum pon_power_off_type type);
int qpnp_pon_is_warm_reset(void);
int qpnp_pon_trigger_config(enum pon_trigger_source pon_src, bool enable);
+int qpnp_pon_wd_config(bool enable);
#else
static int qpnp_pon_system_pwr_off(enum pon_power_off_type type)
{
@@ -63,6 +64,10 @@
{
return -ENODEV;
}
+int qpnp_pon_wd_config(bool enable)
+{
+ return -ENODEV;
+}
#endif
#endif
diff --git a/include/linux/qpnp/pwm.h b/include/linux/qpnp/pwm.h
index bf7908b..50fb2e5 100644
--- a/include/linux/qpnp/pwm.h
+++ b/include/linux/qpnp/pwm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -146,6 +146,12 @@
int pwm_lut_config(struct pwm_device *pwm, int period_us,
int duty_pct[], struct lut_params lut_params);
+/*
+ * support microsecond level configuration
+ */
+int pwm_config_us(struct pwm_device *pwm,
+ int duty_us, int period_us);
+
/* Standard APIs supported */
/*
* pwm_request - request a PWM device
@@ -161,8 +167,8 @@
/*
* pwm_config - change a PWM device configuration
* @pwm: the PWM device
- * @period_us: period in microsecond
- * @duty_us: duty cycle in microsecond
+ * @period_ns: period in nanosecond
+ * @duty_ns: duty cycle in nanosecond
*/
/*
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index 6e711c2..e6dcc3b 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -220,6 +220,8 @@
* btm parameters.
* %SCALE_QRD_SKUAA_BATT_THERM: Conversion to temperature(decidegC) based on
* btm parametersi for SKUAA.
+ * %SCALE_QRD_SKUG_BATT_THERM: Conversion to temperature(decidegC) based on
+ * btm parametersi for SKUG.
* %SCALE_NONE: Do not use this scaling type.
*/
enum qpnp_adc_scale_fn_type {
@@ -231,6 +233,7 @@
SCALE_THERM_150K_PULLUP,
SCALE_QRD_BATT_THERM,
SCALE_QRD_SKUAA_BATT_THERM,
+ SCALE_QRD_SKUG_BATT_THERM = 9,
SCALE_NONE,
};
@@ -1135,6 +1138,23 @@
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt);
/**
+ * qpnp_adc_scale_qrd_skug_batt_therm() - Scales the pre-calibrated digital output
+ * of an ADC to the ADC reference and compensates for the
+ * gain and offset. Returns the temperature in decidegC.
+ * @dev: Structure device for qpnp vadc
+ * @adc_code: pre-calibrated digital ouput of the ADC.
+ * @adc_prop: adc properties of the pm8xxx adc such as bit resolution,
+ * reference voltage.
+ * @chan_prop: individual channel properties to compensate the i/p scaling,
+ * slope and offset.
+ * @chan_rslt: physical result to be stored.
+ */
+int32_t qpnp_adc_scale_qrd_skug_batt_therm(struct qpnp_vadc_chip *dev,
+ int32_t adc_code,
+ const struct qpnp_adc_properties *adc_prop,
+ const struct qpnp_vadc_chan_properties *chan_prop,
+ struct qpnp_vadc_result *chan_rslt);
+/**
* qpnp_adc_scale_batt_id() - Scales the pre-calibrated digital output
* of an ADC to the ADC reference and compensates for the
* gain and offset.
@@ -1388,6 +1408,12 @@
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt)
{ return -ENXIO; }
+static inline int32_t qpnp_adc_scale_qrd_skug_batt_therm(
+ struct qpnp_vadc_chip *vadc, int32_t adc_code,
+ const struct qpnp_adc_properties *adc_prop,
+ const struct qpnp_vadc_chan_properties *chan_prop,
+ struct qpnp_vadc_result *chan_rslt)
+{ return -ENXIO; }
static inline int32_t qpnp_adc_scale_batt_id(struct qpnp_vadc_chip *vadc,
int32_t adc_code,
const struct qpnp_adc_properties *adc_prop,
diff --git a/include/linux/qrng.h b/include/linux/qrng.h
new file mode 100644
index 0000000..35708e3
--- /dev/null
+++ b/include/linux/qrng.h
@@ -0,0 +1,12 @@
+#ifndef __QRNG_H_
+#define __QRNG_H_
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define QRNG_IOC_MAGIC 0x100
+
+#define QRNG_IOCTL_RESET_BUS_BANDWIDTH\
+ _IO(QRNG_IOC_MAGIC, 1)
+
+#endif /* __QRNG_H_ */
diff --git a/include/linux/qseecom.h b/include/linux/qseecom.h
index 6d2db8f3..a45c34c 100644
--- a/include/linux/qseecom.h
+++ b/include/linux/qseecom.h
@@ -163,6 +163,13 @@
QSEOS_UNPROTECT_PROTECTED_BUFFER,
};
+enum qseecom_bandwidth_request_mode {
+ INACTIVE = 0,
+ LOW,
+ MEDIUM,
+ HIGH,
+};
+
/*
* struct qseecom_send_modfd_resp - for send command ioctl request
* @req_len - command buffer length
@@ -177,7 +184,6 @@
enum qseecom_buffer_protection protection_mode; /* in */
};
-
#define QSEECOM_IOC_MAGIC 0x97
@@ -246,4 +252,8 @@
#define QSEECOM_IOCTL_UNPROTECT_BUF \
_IOWR(QSEECOM_IOC_MAGIC, 22, int)
+
+#define QSEECOM_IOCTL_SET_BUS_SCALING_REQ \
+ _IOWR(QSEECOM_IOC_MAGIC, 23, int)
+
#endif /* __QSEECOM_H_ */
diff --git a/include/linux/regulator/cpr-regulator.h b/include/linux/regulator/cpr-regulator.h
index 6387913..3b23d17 100644
--- a/include/linux/regulator/cpr-regulator.h
+++ b/include/linux/regulator/cpr-regulator.h
@@ -22,20 +22,51 @@
#define CPR_PVS_EFUSE_BINS_MAX (1 << CPR_PVS_EFUSE_BITS_MAX)
/**
+ * enum cpr_fuse_corner_enum - CPR fuse corner enum values
+ * %CPR_FUSE_CORNER_SVS: Lowest voltage for APC
+ * %CPR_FUSE_CORNER_NORMAL: Normal mode voltage
+ * %CPR_FUSE_CORNER_TURBO: Turbo mode voltage
+ * %CPR_FUSE_CORNER_SUPER_TURBO: Super Turbo mode voltage
+ *
+ */
+enum cpr_fuse_corner_enum {
+ CPR_FUSE_CORNER_SVS = 1,
+ CPR_FUSE_CORNER_NORMAL,
+ CPR_FUSE_CORNER_TURBO,
+ CPR_FUSE_CORNER_MAX,
+};
+
+/**
* enum cpr_corner_enum - CPR corner enum values
- * %CPR_CORNER_SVS: Lowest voltage for APC
- * %CPR_CORNER_NORMAL: Normal mode voltage
- * %CPR_CORNER_TURBO: Turbo mode voltage
- * %CPR_CORNER_SUPER_TURBO: Super Turbo mode voltage
+ * %CPR_CORNER_1: Lowest voltage for APC
+ * %CPR_CORNER_2: Second lowest voltage for APC
+ * %CPR_CORNER_3: Third lowest voltage for APC
+ * %CPR_CORNER_4: Forth lowest voltage for APC
+ * %CPR_CORNER_5: Fifth lowest voltage for APC
+ * %CPR_CORNER_6: Sixth lowest voltage for APC
+ * %CPR_CORNER_7: Seventh lowest voltage for APC
+ * %CPR_CORNER_8: Eighth lowest voltage for APC
+ * %CPR_CORNER_9: Ninth lowest voltage for APC
+ * %CPR_CORNER_10: Tenth lowest voltage for APC
+ * %CPR_CORNER_11: Eleventh lowest voltage for APC
+ * %CPR_CORNER_12: Twelfth lowest voltage for APC
*
* These should be used in regulator_set_voltage() for CPR
* regulator as if they had units of uV.
*/
enum cpr_corner_enum {
- CPR_CORNER_SVS = 1,
- CPR_CORNER_NORMAL,
- CPR_CORNER_TURBO,
- CPR_CORNER_MAX,
+ CPR_CORNER_1 = 1,
+ CPR_CORNER_2,
+ CPR_CORNER_3,
+ CPR_CORNER_4,
+ CPR_CORNER_5,
+ CPR_CORNER_6,
+ CPR_CORNER_7,
+ CPR_CORNER_8,
+ CPR_CORNER_9,
+ CPR_CORNER_10,
+ CPR_CORNER_11,
+ CPR_CORNER_12,
};
/**
diff --git a/include/linux/sensors.h b/include/linux/sensors.h
new file mode 100644
index 0000000..96d2aa6
--- /dev/null
+++ b/include/linux/sensors.h
@@ -0,0 +1,105 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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_SENSORS_H_INCLUDED
+#define __LINUX_SENSORS_H_INCLUDED
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/rwsem.h>
+
+#define SENSORS_ACCELERATION_HANDLE 0
+#define SENSORS_MAGNETIC_FIELD_HANDLE 1
+#define SENSORS_ORIENTATION_HANDLE 2
+#define SENSORS_LIGHT_HANDLE 3
+#define SENSORS_PROXIMITY_HANDLE 4
+#define SENSORS_GYROSCOPE_HANDLE 5
+#define SENSORS_PRESSURE_HANDLE 6
+
+#define SENSOR_TYPE_ACCELEROMETER 1
+#define SENSOR_TYPE_GEOMAGNETIC_FIELD 2
+#define SENSOR_TYPE_MAGNETIC_FIELD SENSOR_TYPE_GEOMAGNETIC_FIELD
+#define SENSOR_TYPE_ORIENTATION 3
+#define SENSOR_TYPE_GYROSCOPE 4
+#define SENSOR_TYPE_LIGHT 5
+#define SENSOR_TYPE_PRESSURE 6
+#define SENSOR_TYPE_TEMPERATURE 7
+#define SENSOR_TYPE_PROXIMITY 8
+#define SENSOR_TYPE_GRAVITY 9
+#define SENSOR_TYPE_LINEAR_ACCELERATION 10
+#define SENSOR_TYPE_ROTATION_VECTOR 11
+#define SENSOR_TYPE_RELATIVE_HUMIDITY 12
+#define SENSOR_TYPE_AMBIENT_TEMPERATURE 13
+#define SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED 14
+#define SENSOR_TYPE_GAME_ROTATION_VECTOR 15
+#define SENSOR_TYPE_GYROSCOPE_UNCALIBRATED 16
+#define SENSOR_TYPE_SIGNIFICANT_MOTION 17
+#define SENSOR_TYPE_STEP_DETECTOR 18
+#define SENSOR_TYPE_STEP_COUNTER 19
+#define SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR 20
+
+/**
+ * struct sensors_classdev - hold the sensor general parameters and APIs
+ * @dev: The device to register.
+ * @node: The list for the all the sensor drivers.
+ * @name: Name of this sensor.
+ * @vendor: The vendor of the hardware part.
+ * @handle: The handle that identifies this sensors.
+ * @type: The sensor type.
+ * @max_range: The maximum range of this sensor's value in SI units.
+ * @resolution: The smallest difference between two values reported by
+ * this sensor.
+ * @sensor_power: The rough estimate of this sensor's power consumption
+ * in mA.
+ * @min_delay: This value depends on the trigger mode:
+ * continuous: minimum period allowed in microseconds
+ * on-change : 0
+ * one-shot :-1
+ * special : 0, unless otherwise noted
+ * @fifo_reserved_event_count: The number of events reserved for this sensor
+ * in the batch mode FIFO.
+ * @fifo_max_event_count: The maximum number of events of this sensor
+ * that could be batched.
+ * @enabled: Store the sensor driver enable status.
+ * @delay_msec: Store the sensor driver delay value. The data unit is
+ * millisecond.
+ * @sensors_enable: The handle for enable and disable sensor.
+ * @sensors_poll_delay: The handle for set the sensor polling delay time.
+ */
+struct sensors_classdev {
+ struct device *dev;
+ struct list_head node;
+ const char *name;
+ const char *vendor;
+ int version;
+ int handle;
+ int type;
+ const char *max_range;
+ const char *resolution;
+ const char *sensor_power;
+ int min_delay;
+ int fifo_reserved_event_count;
+ int fifo_max_event_count;
+ unsigned int enabled;
+ unsigned int delay_msec;
+ /* enable and disable the sensor handle*/
+ int (*sensors_enable)(struct sensors_classdev *sensors_cdev,
+ unsigned int enabled);
+ int (*sensors_poll_delay)(struct sensors_classdev *sensors_cdev,
+ unsigned int delay_msec);
+};
+
+extern int sensors_classdev_register(struct device *parent,
+ struct sensors_classdev *sensors_cdev);
+extern void sensors_classdev_unregister(struct sensors_classdev *sensors_cdev);
+
+#endif /* __LINUX_SENSORS_H_INCLUDED */
diff --git a/include/linux/slimbus/slimbus.h b/include/linux/slimbus/slimbus.h
index cba4394..67f4d8c 100644
--- a/include/linux/slimbus/slimbus.h
+++ b/include/linux/slimbus/slimbus.h
@@ -586,6 +586,9 @@
* @device_down: This callback is called when device reports absent, or the
* bus goes down. Device will report present when bus is up and
* device_up callback will be called again when that happens
+ * @reset_device: This callback is called after framer is booted.
+ * Driver should do the needful to reset the device,
+ * so that device acquires sync and be operational.
* @driver: Slimbus device drivers should initialize name and owner field of
* this structure
* @id_table: List of slimbus devices supported by this driver
@@ -600,6 +603,8 @@
int (*device_up)(struct slim_device *sldev);
int (*device_down)
(struct slim_device *sldev);
+ int (*reset_device)
+ (struct slim_device *sldev);
struct device_driver driver;
const struct slim_device_id *id_table;
@@ -1036,6 +1041,16 @@
void slim_report_absent(struct slim_device *sbdev);
/*
+ * slim_framer_booted: This function is called by controller after the active
+ * framer has booted (using Bus Reset sequence, or after it has shutdown and has
+ * come back up). Components, devices on the bus may be in undefined state,
+ * and this function triggers their drivers to do the needful
+ * to bring them back in Reset state so that they can acquire sync, report
+ * present and be operational again.
+ */
+void slim_framer_booted(struct slim_controller *ctrl);
+
+/*
* slim_msg_response: Deliver Message response received from a device to the
* framework.
* @ctrl: Controller handle
@@ -1077,7 +1092,7 @@
extern int slim_register_board_info(struct slim_boardinfo const *info,
unsigned n);
#else
-int slim_register_board_info(struct slim_boardinfo const *info,
+static inline int slim_register_board_info(struct slim_boardinfo const *info,
unsigned n)
{
return 0;
diff --git a/include/linux/swap.h b/include/linux/swap.h
index d5bd6ee..c1fcf34 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -197,6 +197,18 @@
struct block_device *bdev; /* swap device or bdev of swap file */
struct file *swap_file; /* seldom referenced */
unsigned int old_block_size; /* seldom referenced */
+ spinlock_t lock; /*
+ * protect map scan related fields like
+ * swap_map, lowest_bit, highest_bit,
+ * inuse_pages, cluster_next,
+ * cluster_nr, lowest_alloc and
+ * highest_alloc. other fields are only
+ * changed at swapon/swapoff, so are
+ * protected by swap_lock. changing
+ * flags need hold this lock and
+ * swap_lock. If both locks need hold,
+ * hold swap_lock first.
+ */
};
struct swap_list_t {
@@ -204,9 +216,6 @@
int next; /* swapfile to be used next */
};
-/* Swap 50% full? Release swapcache more aggressively.. */
-#define vm_swap_full() (nr_swap_pages*2 < total_swap_pages)
-
/* linux/mm/page_alloc.c */
extern unsigned long totalram_pages;
extern unsigned long totalreserve_pages;
@@ -335,8 +344,20 @@
struct vm_area_struct *vma, unsigned long addr);
/* linux/mm/swapfile.c */
-extern long nr_swap_pages;
+extern atomic_long_t nr_swap_pages;
extern long total_swap_pages;
+
+/* Swap 50% full? Release swapcache more aggressively.. */
+static inline bool vm_swap_full(void)
+{
+ return atomic_long_read(&nr_swap_pages) * 2 < total_swap_pages;
+}
+
+static inline long get_nr_swap_pages(void)
+{
+ return atomic_long_read(&nr_swap_pages);
+}
+
extern void si_swapinfo(struct sysinfo *);
extern swp_entry_t get_swap_page(void);
extern swp_entry_t get_swap_page_of_type(int);
@@ -351,6 +372,8 @@
extern unsigned int count_swap_pages(int, int);
extern sector_t map_swap_page(struct page *, struct block_device **);
extern sector_t swapdev_block(int, pgoff_t);
+extern int page_swapcount(struct page *);
+extern struct swap_info_struct *page_swap_info(struct page *);
extern int reuse_swap_page(struct page *);
extern int try_to_free_swap(struct page *);
struct backing_dev_info;
@@ -368,9 +391,10 @@
#else /* CONFIG_SWAP */
-#define nr_swap_pages 0L
+#define get_nr_swap_pages() 0L
#define total_swap_pages 0L
#define total_swapcache_pages 0UL
+#define vm_swap_full() 0
#define si_swapinfo(val) \
do { (val)->freeswap = (val)->totalswap = 0; } while (0)
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index ed6d41b..faf98fe 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -102,6 +102,7 @@
enum thermal_trip_type trip;
int (*notify)(enum thermal_trip_type type, int temp, void *data);
void *data;
+ uint8_t active;
struct list_head list;
};
@@ -189,6 +190,8 @@
int sensor_get_id(char *name);
int sensor_set_trip(uint32_t sensor_id, struct sensor_threshold *threshold);
int sensor_cancel_trip(uint32_t sensor_id, struct sensor_threshold *threshold);
+int sensor_activate_trip(uint32_t sensor_id, struct sensor_threshold *threshold,
+ bool enable);
int thermal_sensor_trip(struct thermal_zone_device *tz,
enum thermal_trip_type trip, long temp);
diff --git a/include/linux/tick.h b/include/linux/tick.h
index 494a314..dc15221 100644
--- a/include/linux/tick.h
+++ b/include/linux/tick.h
@@ -8,6 +8,7 @@
#include <linux/clockchips.h>
#include <linux/irqflags.h>
+#include <linux/hrtimer.h>
#ifdef CONFIG_GENERIC_CLOCKEVENTS
diff --git a/include/linux/tspp.h b/include/linux/tspp.h
index c790c28..ddddbfb 100644
--- a/include/linux/tspp.h
+++ b/include/linux/tspp.h
@@ -34,7 +34,7 @@
int pid;
int mask;
enum tspp_mode mode;
- int priority; /* 0 - 15 */
+ unsigned int priority; /* 0 - 15 */
int decrypt;
enum tspp_source source;
};
diff --git a/include/linux/usb/Kbuild b/include/linux/usb/Kbuild
index 087d163..fe4d6da 100644
--- a/include/linux/usb/Kbuild
+++ b/include/linux/usb/Kbuild
@@ -1,4 +1,5 @@
header-y += audio.h
+header-y += ccid_bridge.h
header-y += cdc.h
header-y += ch9.h
header-y += ch11.h
diff --git a/include/linux/usb/android.h b/include/linux/usb/android.h
index e17e978..8d5e51b 100644
--- a/include/linux/usb/android.h
+++ b/include/linux/usb/android.h
@@ -19,12 +19,16 @@
#include <linux/usb/composite.h>
+#define MAX_STREAMING_FUNCS 3
+#define FUNC_NAME_LEN 10
struct android_usb_platform_data {
int (*update_pid_and_serial_num)(uint32_t, const char *);
u32 swfi_latency;
u8 usb_core_id;
bool cdrom;
bool internal_ums;
+ char streaming_func[MAX_STREAMING_FUNCS][FUNC_NAME_LEN];
+ int streaming_func_count;
};
#ifndef CONFIG_TARGET_CORE
diff --git a/include/linux/usb/ccid_bridge.h b/include/linux/usb/ccid_bridge.h
new file mode 100644
index 0000000..1d1b895
--- /dev/null
+++ b/include/linux/usb/ccid_bridge.h
@@ -0,0 +1,64 @@
+#ifndef __UAPI_USB_CCID_BRIDGE_H
+#define __UAPI_USB_CCID_BRIDGE_H
+
+#include <linux/ioctl.h>
+
+/**
+ * struct usb_ccid_data - Used to receive the CCID class descriptor,
+ * clock rates and data rates supported by the device.
+ * @length: The length of the buffer.
+ * @data: The buffer as it is returned by the device for GET_DESCRIPTOR,
+ * GET_CLOCK_FREQUENCIES and GET_DATA_RATES requests.
+ */
+struct usb_ccid_data {
+ uint8_t length;
+ void *data;
+};
+
+/**
+ * struct usb_ccid_abort - Used to abort an already sent command.
+ * @seq: The sequence number of the command.
+ * @slot: The slot of the IC, on which the command is sent.
+ */
+struct usb_ccid_abort {
+ uint8_t seq;
+ uint8_t slot;
+};
+
+#define USB_CCID_NOTIFY_SLOT_CHANGE_EVENT 1
+#define USB_CCID_HARDWARE_ERROR_EVENT 2
+#define USB_CCID_RESUME_EVENT 3
+/**
+ * struct usb_ccid_event - Used to receive notify slot change or hardware
+ * error event.
+ * @notify: If the event is USB_CCID_NOTIFY_SLOT_CHANGE_EVENT, slot_icc_state
+ * has the information about the current slots state.
+ * @error: If the event is USB_CCID_HARDWARE_ERROR_EVENT, error has
+ * information about the hardware error condition.
+ */
+struct usb_ccid_event {
+ uint8_t event;
+ union {
+ struct {
+ uint8_t slot_icc_state;
+ } notify;
+
+ struct {
+ uint8_t slot;
+ uint8_t seq;
+ uint8_t error_code;
+ } error;
+ } u;
+};
+
+#define USB_CCID_GET_CLASS_DESC _IOWR('C', 0, struct usb_ccid_data)
+
+#define USB_CCID_GET_CLOCK_FREQUENCIES _IOWR('C', 1, struct usb_ccid_data)
+
+#define USB_CCID_GET_DATA_RATES _IOWR('C', 2, struct usb_ccid_data)
+
+#define USB_CCID_ABORT _IOW('C', 3, struct usb_ccid_abort)
+
+#define USB_CCID_GET_EVENT _IOR('C', 4, struct usb_ccid_event)
+
+#endif /* __UAPI_USB_CCID_BRIDGE_H */
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index fea832e..3844f41 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -508,6 +508,7 @@
* @dev: Driver model state for this abstract device.
* @usb_core_id: Identifies the usb core controlled by this usb_gadget.
* Used in case of more then one core operates concurrently.
+ * @streaming_enabled: Enable streaming mode with usb core.
*
* Gadgets have a mostly-portable "gadget driver" implementing device
* functions, handling all usb configurations and interfaces. Gadget
@@ -546,6 +547,7 @@
struct device dev;
u8 usb_core_id;
bool l1_supported;
+ bool streaming_enabled;
};
static inline void set_gadget_data(struct usb_gadget *gadget, void *data)
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 4fb20f6..f9dec0b 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -212,7 +212,8 @@
#define HCD_MEMORY 0x0001 /* HC regs use memory (else I/O) */
#define HCD_LOCAL_MEM 0x0002 /* HC needs local memory */
#define HCD_SHARED 0x0004 /* Two (or more) usb_hcds share HW */
-#define HCD_OLD_ENUM 0x0008 /* HC supports short enumeration */
+#define HCD_RT_OLD_ENUM 0x0008 /* HC supports short enumeration
+ on root port */
#define HCD_USB11 0x0010 /* USB 1.1 */
#define HCD_USB2 0x0020 /* USB 2.0 */
#define HCD_USB3 0x0040 /* USB 3.0 */
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 07f9b90..045a58b 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -229,7 +229,11 @@
* between 1 to 7.
* @l1_supported: enable link power management support.
* @dpdm_pulldown_added: Indicates whether pull down resistors are
- connected on data lines or not.
+ * connected on data lines or not.
+ * @enable_ahb2ahb_bypass: Indicates whether enable AHB2AHB BYPASS
+ * mode with controller in device mode.
+ * @disable_retention_with_vdd_min: Indicates whether to enable allowing
+ * VDD min without putting PHY into retention
*/
struct msm_otg_platform_data {
int *phy_init_seq;
@@ -258,6 +262,8 @@
int log2_itc;
bool l1_supported;
bool dpdm_pulldown_added;
+ bool enable_ahb2ahb_bypass;
+ bool disable_retention_with_vdd_min;
};
/* phy related flags */
@@ -424,6 +430,11 @@
* voltage regulator(VDDCX) during host mode.
*/
#define ALLOW_HOST_PHY_RETENTION BIT(4)
+ /*
+ * Allow VDD minimization without putting PHY into retention
+ * for fixing PHY current leakage issue when LDOs are turned off.
+ */
+#define ALLOW_VDD_MIN_WITH_RETENTION_DISABLED BIT(5)
unsigned long lpm_flags;
#define PHY_PWR_COLLAPSED BIT(0)
#define PHY_RETENTIONED BIT(1)
@@ -462,6 +473,7 @@
int log2_itc;
void *prv_data;
bool l1_supported;
+ bool enable_ahb2ahb_bypass;
};
/**
diff --git a/include/linux/usb/msm_hsusb_hw.h b/include/linux/usb/msm_hsusb_hw.h
index 58ab4eb..2a5ebd4 100644
--- a/include/linux/usb/msm_hsusb_hw.h
+++ b/include/linux/usb/msm_hsusb_hw.h
@@ -49,6 +49,10 @@
#define L1_CONFIG_PHY_LPM BIT(10)
#define L1_CONFIG_PLL BIT(11)
+#define AHB2AHB_BYPASS BIT(31)
+#define AHB2AHB_BYPASS_BIT_MASK BIT(31)
+#define AHB2AHB_BYPASS_CLEAR (0 << 31)
+
#define PORTSC_PHCD (1 << 23) /* phy suspend mode */
#define PORTSC_PTS_MASK (3 << 30)
#define PORTSC_PTS_ULPI (3 << 30)
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 560accb..51ca67d 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1904,6 +1904,11 @@
V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_SECONDARY = 1,
};
+#define V4L2_CID_MPEG_VIDC_VIDEO_VP8_MIN_QP (V4L2_CID_MPEG_MSM_VIDC_BASE + 36)
+#define V4L2_CID_MPEG_VIDC_VIDEO_VP8_MAX_QP (V4L2_CID_MPEG_MSM_VIDC_BASE + 37)
+#define V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 38)
+
/* Camera class control IDs */
#define V4L2_CID_CAMERA_CLASS_BASE (V4L2_CTRL_CLASS_CAMERA | 0x900)
#define V4L2_CID_CAMERA_CLASS (V4L2_CTRL_CLASS_CAMERA | 1)
diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
index 7675a5c..500421f 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -136,6 +136,12 @@
extern __init void vm_area_add_early(struct vm_struct *vm);
extern __init void vm_area_register_early(struct vm_struct *vm, size_t align);
extern __init int vm_area_check_early(struct vm_struct *vm);
+#ifdef CONFIG_ENABLE_VMALLOC_SAVING
+extern void mark_vmalloc_reserved_area(void *addr, unsigned long size);
+#else
+static inline void mark_vmalloc_reserved_area(void *addr, unsigned long size)
+{ };
+#endif
#ifdef CONFIG_SMP
# ifdef CONFIG_MMU
diff --git a/include/linux/vmstat.h b/include/linux/vmstat.h
index 1d10474..2d59889 100644
--- a/include/linux/vmstat.h
+++ b/include/linux/vmstat.h
@@ -140,7 +140,6 @@
}
extern unsigned long global_reclaimable_pages(void);
-extern unsigned long zone_reclaimable_pages(struct zone *zone);
#ifdef CONFIG_NUMA
/*
diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h
index 39357e0..9241b93 100644
--- a/include/linux/wcnss_wlan.h
+++ b/include/linux/wcnss_wlan.h
@@ -86,7 +86,11 @@
{
}
#endif
-
+int wcnss_set_wlan_unsafe_channel(
+ u16 *unsafe_ch_list, u16 ch_count);
+int wcnss_get_wlan_unsafe_channel(
+ u16 *unsafe_ch_list, u16 buffer_size,
+ u16 *ch_count);
#define wcnss_wlan_get_drvdata(dev) dev_get_drvdata(dev)
#define wcnss_wlan_set_drvdata(dev, data) dev_set_drvdata((dev), (data))
/* WLAN driver uses these names */
diff --git a/include/media/msm_cam_sensor.h b/include/media/msm_cam_sensor.h
index cccf851..38d3aab 100644
--- a/include/media/msm_cam_sensor.h
+++ b/include/media/msm_cam_sensor.h
@@ -482,6 +482,7 @@
int8_t sign_dir;
int16_t dest_step_pos;
int32_t num_steps;
+ uint16_t curr_lens_pos;
struct damping_params_t *ringing_params;
};
@@ -571,6 +572,8 @@
struct msm_camera_led_cfg_t {
enum msm_camera_led_config_t cfgtype;
+ uint32_t torch_current;
+ uint32_t flash_current[2];
};
#define VIDIOC_MSM_SENSOR_CFG \
diff --git a/include/media/msm_jpeg.h b/include/media/msm_jpeg.h
index 56829f1..99f0de0 100644
--- a/include/media/msm_jpeg.h
+++ b/include/media/msm_jpeg.h
@@ -55,6 +55,9 @@
#define MSM_JPEG_IOCTL_TEST_DUMP_REGION \
_IOW(MSM_JPEG_IOCTL_MAGIC, 15, unsigned long)
+#define MSM_JPEG_IOCTL_SET_CLK_RATE \
+ _IOW(MSM_JPEG_IOCTL_MAGIC, 16, unsigned long)
+
#define MSM_JPEG_MODE_REALTIME_ENCODE 0
#define MSM_JPEG_MODE_OFFLINE_ENCODE 1
#define MSM_JPEG_MODE_REALTIME_ROTATION 2
diff --git a/include/media/msm_vidc.h b/include/media/msm_vidc.h
index 868be9f..bc85ebb 100644
--- a/include/media/msm_vidc.h
+++ b/include/media/msm_vidc.h
@@ -18,6 +18,41 @@
MSM_VIDC_MAX_DEVICES,
};
+/* NOTE: if you change this enum you MUST update the
+ * "buffer-type-tz-usage-table" for any affected target
+ * in arch/arm/boot/dts/<arch>.dtsi
+ */
+enum hal_buffer {
+ HAL_BUFFER_INPUT = 0x1,
+ HAL_BUFFER_OUTPUT = 0x2,
+ HAL_BUFFER_OUTPUT2 = 0x4,
+ HAL_BUFFER_EXTRADATA_INPUT = 0x8,
+ HAL_BUFFER_EXTRADATA_OUTPUT = 0x10,
+ HAL_BUFFER_EXTRADATA_OUTPUT2 = 0x20,
+ HAL_BUFFER_INTERNAL_SCRATCH = 0x40,
+ HAL_BUFFER_INTERNAL_SCRATCH_1 = 0x80,
+ HAL_BUFFER_INTERNAL_SCRATCH_2 = 0x100,
+ HAL_BUFFER_INTERNAL_PERSIST = 0x200,
+ HAL_BUFFER_INTERNAL_PERSIST_1 = 0x400,
+ HAL_BUFFER_INTERNAL_CMD_QUEUE = 0x800,
+};
+
+struct msm_smem {
+ int mem_type;
+ size_t size;
+ void *kvaddr;
+ unsigned long device_addr;
+ u32 flags;
+ void *smem_priv;
+ enum hal_buffer buffer_type;
+};
+
+enum smem_cache_ops {
+ SMEM_CACHE_CLEAN,
+ SMEM_CACHE_INVALIDATE,
+ SMEM_CACHE_CLEAN_INVALIDATE,
+};
+
void *msm_vidc_open(int core_id, int session_type);
int msm_vidc_close(void *instance);
int msm_vidc_querycap(void *instance, struct v4l2_capability *cap);
@@ -47,6 +82,18 @@
int msm_vidc_wait(void *instance);
int msm_vidc_s_parm(void *instance, struct v4l2_streamparm *a);
int msm_vidc_enum_framesizes(void *instance, struct v4l2_frmsizeenum *fsize);
+struct msm_smem *msm_vidc_smem_alloc(void *instance,
+ size_t size, u32 align, u32 flags,
+ enum hal_buffer buffer_type, int map_kernel);
+void msm_vidc_smem_free(void *instance, struct msm_smem *mem);
+int msm_vidc_smem_cache_operations(void *instance,
+ struct msm_smem *mem, enum smem_cache_ops);
+struct msm_smem *msm_vidc_smem_user_to_kernel(void *instance,
+ int fd, u32 offset, enum hal_buffer buffer_type);
+int msm_vidc_smem_get_domain_partition(void *instance,
+ u32 flags, enum hal_buffer buffer_type,
+ int *domain_num, int *partition_num);
+void *msm_vidc_smem_get_client(void *instance);
#endif
struct msm_vidc_interlace_payload {
unsigned int format;
@@ -93,6 +140,27 @@
unsigned int num_panscan_windows;
struct msm_vidc_panscan_window wnd[1];
};
+struct msm_vidc_s3d_frame_packing_payload {
+ unsigned int fpa_id;
+ unsigned int cancel_flag;
+ unsigned int fpa_type;
+ unsigned int quin_cunx_flag;
+ unsigned int content_interprtation_type;
+ unsigned int spatial_flipping_flag;
+ unsigned int frame0_flipped_flag;
+ unsigned int field_views_flag;
+ unsigned int current_frame_is_frame0_flag;
+ unsigned int frame0_self_contained_flag;
+ unsigned int frame1_self_contained_flag;
+ unsigned int frame0_graid_pos_x;
+ unsigned int frame0_graid_pos_y;
+ unsigned int frame1_graid_pos_x;
+ unsigned int frame1_graid_pos_y;
+ unsigned int fpa_reserved_byte;
+ unsigned int fpa_repetition_period;
+ unsigned int fpa_extension_flag;
+};
+
enum msm_vidc_extradata_type {
EXTRADATA_NONE = 0x00000000,
EXTRADATA_MB_QUANTIZATION = 0x00000001,
diff --git a/include/media/msmb_generic_buf_mgr.h b/include/media/msmb_generic_buf_mgr.h
index efcb425..237380f 100644
--- a/include/media/msmb_generic_buf_mgr.h
+++ b/include/media/msmb_generic_buf_mgr.h
@@ -20,4 +20,10 @@
#define VIDIOC_MSM_BUF_MNGR_BUF_DONE \
_IOWR('V', BASE_VIDIOC_PRIVATE + 35, struct msm_buf_mngr_info)
+#define VIDIOC_MSM_BUF_MNGR_INIT \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 36, struct msm_buf_mngr_info)
+
+#define VIDIOC_MSM_BUF_MNGR_DEINIT \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 37, struct msm_buf_mngr_info)
+
#endif
diff --git a/include/media/msmb_isp.h b/include/media/msmb_isp.h
index 7b0ad14..3ba0abe 100644
--- a/include/media/msmb_isp.h
+++ b/include/media/msmb_isp.h
@@ -152,6 +152,7 @@
enum msm_vfe_axi_stream_cmd {
STOP_STREAM,
START_STREAM,
+ STOP_IMMEDIATELY,
};
struct msm_vfe_axi_stream_cfg_cmd {
@@ -227,6 +228,7 @@
VFE_READ_DMI_32BIT,
VFE_READ_DMI_64BIT,
GET_SOC_HW_VER,
+ GET_MAX_CLK_RATE,
};
struct msm_vfe_cfg_cmd2 {
diff --git a/include/media/msmb_pproc.h b/include/media/msmb_pproc.h
index de42c38..ed4ffa2 100644
--- a/include/media/msmb_pproc.h
+++ b/include/media/msmb_pproc.h
@@ -90,6 +90,7 @@
uint32_t offset;
uint8_t native_buff;
uint8_t processed_divert;
+ uint32_t identity;
};
struct msm_cpp_stream_buff_info_t {
diff --git a/include/media/radio-iris.h b/include/media/radio-iris.h
index d28a8c0..a69f3f1 100644
--- a/include/media/radio-iris.h
+++ b/include/media/radio-iris.h
@@ -32,6 +32,50 @@
#include <linux/mutex.h>
#include <linux/atomic.h>
#include "radio-iris-commands.h"
+const unsigned char MIN_TX_TONE_VAL = 0x00;
+const unsigned char MAX_TX_TONE_VAL = 0x07;
+const unsigned char MIN_HARD_MUTE_VAL = 0x00;
+const unsigned char MAX_HARD_MUTE_VAL = 0x03;
+const unsigned char MIN_SRCH_MODE = 0x00;
+const unsigned char MAX_SRCH_MODE = 0x01;
+const unsigned char MIN_SCAN_DWELL = 0x00;
+const unsigned char MAX_SCAN_DWELL = 0x0F;
+const unsigned char MIN_SIG_TH = 0x00;
+const unsigned char MAX_SIG_TH = 0x03;
+const unsigned char MIN_PTY = 0X00;
+const unsigned char MAX_PTY = 0x1F;
+const unsigned short MIN_PI = 0x0000;
+const unsigned short MAX_PI = 0xFFFF;
+const unsigned char MIN_SRCH_STATIONS_CNT = 0x00;
+const unsigned char MAX_SRCH_STATIONS_CNT = 0x14;
+const unsigned char MIN_CHAN_SPACING = 0x00;
+const unsigned char MAX_CHAN_SPACING = 0x02;
+const unsigned char MIN_EMPHASIS = 0x00;
+const unsigned char MAX_EMPHASIS = 0x01;
+const unsigned char MIN_RDS_STD = 0x00;
+const unsigned char MAX_RDS_STD = 0x02;
+const unsigned char MIN_ANTENNA_VAL = 0x00;
+const unsigned char MAX_ANTENNA_VAL = 0x01;
+const unsigned char MIN_TX_PS_REPEAT_CNT = 0x01;
+const unsigned char MAX_TX_PS_REPEAT_CNT = 0x0F;
+const unsigned char MIN_SOFT_MUTE = 0x00;
+const unsigned char MAX_SOFT_MUTE = 0x01;
+const unsigned char MIN_PEEK_ACCESS_LEN = 0x01;
+const unsigned char MAX_PEEK_ACCESS_LEN = 0xF9;
+const unsigned char MIN_RESET_CNTR = 0x00;
+const unsigned char MAX_RESET_CNTR = 0x01;
+const unsigned char MIN_HLSI = 0x00;
+const unsigned char MAX_HLSI = 0x02;
+const unsigned char MIN_NOTCH_FILTER = 0x00;
+const unsigned char MAX_NOTCH_FILTER = 0x02;
+const unsigned char MIN_INTF_DET_OUT_LW_TH = 0x00;
+const unsigned char MAX_INTF_DET_OUT_LW_TH = 0xFF;
+const unsigned char MIN_INTF_DET_OUT_HG_TH = 0x00;
+const unsigned char MAX_INTF_DET_OUT_HG_TH = 0xFF;
+const signed char MIN_SINR_TH = -128;
+const signed char MAX_SINR_TH = 127;
+const unsigned char MIN_SINR_SAMPLES = 0x01;
+const unsigned char MAX_SINR_SAMPLES = 0xFF;
/* ---- HCI Packet structures ---- */
#define RADIO_HCI_COMMAND_HDR_SIZE sizeof(struct radio_hci_command_hdr)
@@ -630,6 +674,7 @@
FM_TURNING_OFF,
FM_RECV_TURNING_ON,
FM_TRANS_TURNING_ON,
+ FM_MAX_NO_STATES,
};
enum emphasis_type {
@@ -828,4 +873,209 @@
int hci_fm_do_calibration(__u8 *arg, struct radio_hci_dev *hdev);
int hci_fm_do_calibration(__u8 *arg, struct radio_hci_dev *hdev);
+static inline int is_valid_tone(int tone)
+{
+ if ((tone >= MIN_TX_TONE_VAL) &&
+ (tone <= MAX_TX_TONE_VAL))
+ return 1;
+ else
+ return 0;
+}
+
+static inline int is_valid_hard_mute(int hard_mute)
+{
+ if ((hard_mute >= MIN_HARD_MUTE_VAL) &&
+ (hard_mute <= MAX_HARD_MUTE_VAL))
+ return 1;
+ else
+ return 0;
+}
+
+static inline int is_valid_srch_mode(int srch_mode)
+{
+ if ((srch_mode >= MIN_SRCH_MODE) &&
+ (srch_mode <= MAX_SRCH_MODE))
+ return 1;
+ else
+ return 0;
+}
+
+static inline int is_valid_scan_dwell_prd(int scan_dwell_prd)
+{
+ if ((scan_dwell_prd >= MIN_SCAN_DWELL) &&
+ (scan_dwell_prd <= MAX_SCAN_DWELL))
+ return 1;
+ else
+ return 0;
+}
+
+static inline int is_valid_sig_th(int sig_th)
+{
+ if ((sig_th >= MIN_SIG_TH) &&
+ (sig_th <= MAX_SIG_TH))
+ return 1;
+ else
+ return 0;
+}
+
+static inline int is_valid_pty(int pty)
+{
+ if ((pty >= MIN_PTY) &&
+ (pty <= MAX_PTY))
+ return 1;
+ else
+ return 0;
+}
+
+static inline int is_valid_pi(int pi)
+{
+ if ((pi >= MIN_PI) &&
+ (pi <= MAX_PI))
+ return 1;
+ else
+ return 0;
+}
+
+static inline int is_valid_srch_station_cnt(int cnt)
+{
+ if ((cnt >= MIN_SRCH_STATIONS_CNT) &&
+ (cnt <= MAX_SRCH_STATIONS_CNT))
+ return 1;
+ else
+ return 0;
+}
+
+static inline int is_valid_chan_spacing(int spacing)
+{
+ if ((spacing >= MIN_CHAN_SPACING) &&
+ (spacing <= MAX_CHAN_SPACING))
+ return 1;
+ else
+ return 0;
+}
+
+static inline int is_valid_emphasis(int emphasis)
+{
+ if ((emphasis >= MIN_EMPHASIS) &&
+ (emphasis <= MAX_EMPHASIS))
+ return 1;
+ else
+ return 0;
+}
+
+static inline int is_valid_rds_std(int rds_std)
+{
+ if ((rds_std >= MIN_RDS_STD) &&
+ (rds_std <= MAX_RDS_STD))
+ return 1;
+ else
+ return 0;
+}
+
+static inline int is_valid_antenna(int antenna_type)
+{
+ if ((antenna_type >= MIN_ANTENNA_VAL) &&
+ (antenna_type <= MAX_ANTENNA_VAL))
+ return 1;
+ else
+ return 0;
+}
+
+static inline int is_valid_ps_repeat_cnt(int cnt)
+{
+ if ((cnt >= MIN_TX_PS_REPEAT_CNT) &&
+ (cnt <= MAX_TX_PS_REPEAT_CNT))
+ return 1;
+ else
+ return 0;
+}
+
+static inline int is_valid_soft_mute(int soft_mute)
+{
+ if ((soft_mute >= MIN_SOFT_MUTE) &&
+ (soft_mute <= MAX_SOFT_MUTE))
+ return 1;
+ else
+ return 0;
+}
+
+static inline int is_valid_peek_len(int len)
+{
+ if ((len >= MIN_PEEK_ACCESS_LEN) &&
+ (len <= MAX_PEEK_ACCESS_LEN))
+ return 1;
+ else
+ return 0;
+}
+
+static inline int is_valid_reset_cntr(int cntr)
+{
+ if ((cntr >= MIN_RESET_CNTR) &&
+ (cntr <= MAX_RESET_CNTR))
+ return 1;
+ else
+ return 0;
+}
+
+static inline int is_valid_hlsi(int hlsi)
+{
+ if ((hlsi >= MIN_HLSI) &&
+ (hlsi <= MAX_HLSI))
+ return 1;
+ else
+ return 0;
+}
+
+static inline int is_valid_notch_filter(int filter)
+{
+ if ((filter >= MIN_NOTCH_FILTER) &&
+ (filter <= MAX_NOTCH_FILTER))
+ return 1;
+ else
+ return 0;
+}
+
+static inline int is_valid_intf_det_low_th(int th)
+{
+ if ((th >= MIN_INTF_DET_OUT_LW_TH) &&
+ (th <= MAX_INTF_DET_OUT_LW_TH))
+ return 1;
+ else
+ return 0;
+}
+
+static inline int is_valid_intf_det_hgh_th(int th)
+{
+ if ((th >= MIN_INTF_DET_OUT_HG_TH) &&
+ (th <= MAX_INTF_DET_OUT_HG_TH))
+ return 1;
+ else
+ return 0;
+}
+
+static inline int is_valid_sinr_th(int th)
+{
+ if ((th >= MIN_SINR_TH) &&
+ (th <= MAX_SINR_TH))
+ return 1;
+ else
+ return 0;
+}
+
+static inline int is_valid_sinr_samples(int samples_cnt)
+{
+ if ((samples_cnt >= MIN_SINR_SAMPLES) &&
+ (samples_cnt <= MAX_SINR_SAMPLES))
+ return 1;
+ else
+ return 0;
+}
+
+static inline int is_valid_fm_state(int state)
+{
+ if ((state >= 0) && (state < FM_MAX_NO_STATES))
+ return 1;
+ else
+ return 0;
+}
#endif /* __RADIO_HCI_CORE_H */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 4ecadd8..7932ba1 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1801,22 +1801,28 @@
* enum wiphy_flags - wiphy capability flags
*
* @WIPHY_FLAG_CUSTOM_REGULATORY: tells us the driver for this device
- * has its own custom regulatory domain and cannot identify the
- * ISO / IEC 3166 alpha2 it belongs to. When this is enabled
- * we will disregard the first regulatory hint (when the
- * initiator is %REGDOM_SET_BY_CORE).
- * @WIPHY_FLAG_STRICT_REGULATORY: tells us the driver for this device will
- * ignore regulatory domain settings until it gets its own regulatory
- * domain via its regulatory_hint() unless the regulatory hint is
- * from a country IE. After its gets its own regulatory domain it will
- * only allow further regulatory domain settings to further enhance
- * compliance. For example if channel 13 and 14 are disabled by this
- * regulatory domain no user regulatory domain can enable these channels
- * at a later time. This can be used for devices which do not have
- * calibration information guaranteed for frequencies or settings
- * outside of its regulatory domain. If used in combination with
- * WIPHY_FLAG_CUSTOM_REGULATORY the inspected country IE power settings
- * will be followed.
+ * has its own custom regulatory domain and cannot identify the
+ * ISO / IEC 3166 alpha2 it belongs to. When this is enabled
+ * we will disregard the first regulatory hint (when the
+ * initiator is %REGDOM_SET_BY_CORE). wiphys can set the custom
+ * regulatory domain using wiphy_apply_custom_regulatory()
+ * prior to wiphy registration.
+ * @WIPHY_FLAG_STRICT_REGULATORY: tells us that the wiphy for this device
+ * has regulatory domain that it wishes to be considered as the
+ * superset for regulatory rules. After this device gets its regulatory
+ * domain programmed further regulatory hints shall only be considered
+ * for this device to enhance regulatory compliance, forcing the
+ * device to only possibly use subsets of the original regulatory
+ * rules. For example if channel 13 and 14 are disabled by this
+ * device's regulatory domain no user specified regulatory hint which
+ * has these channels enabled would enable them for this wiphy,
+ * the device's original regulatory domain will be trusted as the
+ * base. You can program the superset of regulatory rules for this
+ * wiphy with regulatory_hint() for cards programmed with an
+ * ISO3166-alpha2 country code. wiphys that use regulatory_hint()
+ * will have their wiphy->regd programmed once the regulatory
+ * domain is set, and all other regulatory hints will be ignored
+ * until their own regulatory domain gets programmed.
* @WIPHY_FLAG_DISABLE_BEACON_HINTS: enable this if your driver needs to ensure
* that passive scan flags and beaconing flags may not be lifted by
* cfg80211 due to regulatory beacon hints. For more information on beacon
@@ -1884,6 +1890,34 @@
};
/**
+ * enum nl80211_country_ie_pref - country IE processing preferences
+ *
+ * enumerates the different preferences a 802.11 card can advertize
+ * for parsing the country IEs. As per the current implementation
+ * country IEs are only used derive the apha2, the information
+ * for power settings that comes with the country IE is ignored
+ * and we use the power settings from regdb.
+ *
+ * @NL80211_COUNTRY_IE_FOLLOW_CORE - This is the default behaviour.
+ * It allows the core to update channel flags according to the
+ * ISO3166-alpha2 in the country IE. The applied power is -
+ * MIN(power specified by custom domain, power obtained from regdb)
+ * @NL80211_COUNTRY_IE_FOLLOW_POWER - for devices that have a
+ * preference that even though they may have programmed their own
+ * custom power setting prior to wiphy registration, they want
+ * to ensure their channel power settings are updated for this
+ * connection with the power settings derived from alpha2 of the
+ * country IE.
+ * @NL80211_COUNTRY_IE_IGNORE_CORE - for devices that have a preference to
+ * to ignore all country IE information processed by the core.
+ */
+enum nl80211_country_ie_pref {
+ NL80211_COUNTRY_IE_FOLLOW_CORE,
+ NL80211_COUNTRY_IE_FOLLOW_POWER,
+ NL80211_COUNTRY_IE_IGNORE_CORE,
+};
+
+/**
* struct ieee80211_iface_limit - limit on certain interface types
* @max: maximum number of interfaces of these types
* @types: interface types (bits)
@@ -2100,6 +2134,8 @@
*
* @max_acl_mac_addrs: Maximum number of MAC addresses that the device
* supports for ACL.
+ * @country_ie_pref: country IE processing preferences specified
+ * by enum nl80211_country_ie_pref
*/
struct wiphy {
/* assign these fields before you register the wiphy */
@@ -2164,6 +2200,8 @@
*/
u32 probe_resp_offload;
+ u8 country_ie_pref;
+
/* If multiple wiphys are registered and you're handed e.g.
* a regular netdev with assigned ieee80211_ptr, you won't
* know whether it points to a wiphy your driver has registered
@@ -2691,6 +2729,30 @@
extern int regulatory_hint(struct wiphy *wiphy, const char *alpha2);
/**
+ * regulatory_hint_user - hint to the wireless core a regulatory domain
+ * which the driver has received from an application
+ * @alpha2: the ISO/IEC 3166 alpha2 the driver claims its regulatory domain
+ * should be in. If @rd is set this should be NULL. Note that if you
+ * set this to NULL you should still set rd->alpha2 to some accepted
+ * alpha2.
+ *
+ * Wireless drivers can use this function to hint to the wireless core
+ * the current regulatory domain as specified by trusted applications,
+ * it is the driver's responsibilty to estbalish which applications it
+ * trusts.
+ *
+ * The wiphy should be registered to cfg80211 prior to this call.
+ * For cfg80211 drivers this means you must first use wiphy_register(),
+ * for mac80211 drivers you must first use ieee80211_register_hw().
+ *
+ * Drivers should check the return value, its possible you can get
+ * an -ENOMEM or an -EINVAL.
+ *
+ * Return: 0 on success. -ENOMEM, -EINVAL.
+ */
+extern int regulatory_hint_user(const char *alpha2);
+
+/**
* wiphy_apply_custom_regulatory - apply a custom driver regulatory domain
* @wiphy: the wireless device we want to process the regulatory domain on
* @regd: the custom regulatory domain to use for this wiphy
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index bbda72e..2c969cd 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -3676,6 +3676,7 @@
} __packed;
#define ASM_SESSION_CMD_PAUSE 0x00010BD3
+#define ASM_SESSION_CMD_SUSPEND 0x00010DEC
#define ASM_SESSION_CMD_GET_SESSIONTIME_V3 0x00010D9D
#define ASM_SESSION_CMD_REGISTER_FOR_RX_UNDERFLOW_EVENTS 0x00010BD5
@@ -4698,6 +4699,25 @@
} __packed;
+
+/*
+ Indicates the number of samples per channel to be removed from the
+ beginning of the stream.
+*/
+#define ASM_DATA_CMD_REMOVE_INITIAL_SILENCE 0x00010D67
+/*
+ Indicates the number of samples per channel to be removed from
+ the end of the stream.
+*/
+#define ASM_DATA_CMD_REMOVE_TRAILING_SILENCE 0x00010D68
+struct asm_data_cmd_remove_silence {
+ struct apr_hdr hdr;
+ u32 num_samples_to_remove;
+ /**< Number of samples per channel to be removed.
+
+ @values 0 to (2@sscr{32}-1) */
+} __packed;
+
#define ASM_STREAM_CMD_OPEN_READ_COMPRESSED 0x00010D95
struct asm_stream_cmd_open_read_compressed {
@@ -6259,6 +6279,206 @@
#define VOICE_CMD_GET_PARAM 0x0001133E
#define VOICE_EVT_GET_PARAM_ACK 0x00011008
+
+/** ID of the Bass Boost module.
+ This module supports the following parameter IDs:
+ - #AUDPROC_PARAM_ID_BASS_BOOST_ENABLE
+ - #AUDPROC_PARAM_ID_BASS_BOOST_MODE
+ - #AUDPROC_PARAM_ID_BASS_BOOST_STRENGTH
+*/
+#define AUDPROC_MODULE_ID_BASS_BOOST 0x000108A1
+/** ID of the Bass Boost enable parameter used by
+ AUDPROC_MODULE_ID_BASS_BOOST.
+*/
+#define AUDPROC_PARAM_ID_BASS_BOOST_ENABLE 0x000108A2
+/** ID of the Bass Boost mode parameter used by
+ AUDPROC_MODULE_ID_BASS_BOOST.
+*/
+#define AUDPROC_PARAM_ID_BASS_BOOST_MODE 0x000108A3
+/** ID of the Bass Boost strength parameter used by
+ AUDPROC_MODULE_ID_BASS_BOOST.
+*/
+#define AUDPROC_PARAM_ID_BASS_BOOST_STRENGTH 0x000108A4
+
+/** ID of the Virtualizer module. This module supports the
+ following parameter IDs:
+ - #AUDPROC_PARAM_ID_VIRTUALIZER_ENABLE
+ - #AUDPROC_PARAM_ID_VIRTUALIZER_STRENGTH
+ - #AUDPROC_PARAM_ID_VIRTUALIZER_OUT_TYPE
+ - #AUDPROC_PARAM_ID_VIRTUALIZER_GAIN_ADJUST
+*/
+#define AUDPROC_MODULE_ID_VIRTUALIZER 0x000108A5
+/** ID of the Virtualizer enable parameter used by
+ AUDPROC_MODULE_ID_VIRTUALIZER.
+*/
+#define AUDPROC_PARAM_ID_VIRTUALIZER_ENABLE 0x000108A6
+/** ID of the Virtualizer strength parameter used by
+ AUDPROC_MODULE_ID_VIRTUALIZER.
+*/
+#define AUDPROC_PARAM_ID_VIRTUALIZER_STRENGTH 0x000108A7
+/** ID of the Virtualizer out type parameter used by
+ AUDPROC_MODULE_ID_VIRTUALIZER.
+*/
+#define AUDPROC_PARAM_ID_VIRTUALIZER_OUT_TYPE 0x000108A8
+/** ID of the Virtualizer out type parameter used by
+ AUDPROC_MODULE_ID_VIRTUALIZER.
+*/
+#define AUDPROC_PARAM_ID_VIRTUALIZER_GAIN_ADJUST 0x000108A9
+
+/** ID of the Reverb module. This module supports the following
+ parameter IDs:
+ - #AUDPROC_PARAM_ID_REVERB_ENABLE
+ - #AUDPROC_PARAM_ID_REVERB_MODE
+ - #AUDPROC_PARAM_ID_REVERB_PRESET
+ - #AUDPROC_PARAM_ID_REVERB_WET_MIX
+ - #AUDPROC_PARAM_ID_REVERB_GAIN_ADJUST
+ - #AUDPROC_PARAM_ID_REVERB_ROOM_LEVEL
+ - #AUDPROC_PARAM_ID_REVERB_ROOM_HF_LEVEL
+ - #AUDPROC_PARAM_ID_REVERB_DECAY_TIME
+ - #AUDPROC_PARAM_ID_REVERB_DECAY_HF_RATIO
+ - #AUDPROC_PARAM_ID_REVERB_REFLECTIONS_LEVEL
+ - #AUDPROC_PARAM_ID_REVERB_REFLECTIONS_DELAY
+ - #AUDPROC_PARAM_ID_REVERB_LEVEL
+ - #AUDPROC_PARAM_ID_REVERB_DELAY
+ - #AUDPROC_PARAM_ID_REVERB_DIFFUSION
+ - #AUDPROC_PARAM_ID_REVERB_DENSITY
+*/
+#define AUDPROC_MODULE_ID_REVERB 0x000108AA
+/** ID of the Reverb enable parameter used by
+ AUDPROC_MODULE_ID_REVERB.
+*/
+#define AUDPROC_PARAM_ID_REVERB_ENABLE 0x000108AB
+/** ID of the Reverb mode parameter used by
+ AUDPROC_MODULE_ID_REVERB.
+*/
+#define AUDPROC_PARAM_ID_REVERB_MODE 0x000108AC
+/** ID of the Reverb preset parameter used by
+ AUDPROC_MODULE_ID_REVERB.
+*/
+#define AUDPROC_PARAM_ID_REVERB_PRESET 0x000108AD
+/** ID of the Reverb wet mix parameter used by
+ AUDPROC_MODULE_ID_REVERB.
+*/
+#define AUDPROC_PARAM_ID_REVERB_WET_MIX 0x000108AE
+/** ID of the Reverb gain adjust parameter used by
+ AUDPROC_MODULE_ID_REVERB.
+*/
+#define AUDPROC_PARAM_ID_REVERB_GAIN_ADJUST 0x000108AF
+/** ID of the Reverb room level parameter used by
+ AUDPROC_MODULE_ID_REVERB.
+*/
+#define AUDPROC_PARAM_ID_REVERB_ROOM_LEVEL 0x000108B0
+/** ID of the Reverb room hf level parameter used by
+ AUDPROC_MODULE_ID_REVERB.
+*/
+#define AUDPROC_PARAM_ID_REVERB_ROOM_HF_LEVEL 0x000108B1
+/** ID of the Reverb decay time parameter used by
+ AUDPROC_MODULE_ID_REVERB.
+*/
+#define AUDPROC_PARAM_ID_REVERB_DECAY_TIME 0x000108B2
+/** ID of the Reverb decay hf ratio parameter used by
+ AUDPROC_MODULE_ID_REVERB.
+*/
+#define AUDPROC_PARAM_ID_REVERB_DECAY_HF_RATIO 0x000108B3
+/** ID of the Reverb reflections level parameter used by
+ AUDPROC_MODULE_ID_REVERB.
+*/
+#define AUDPROC_PARAM_ID_REVERB_REFLECTIONS_LEVEL 0x000108B4
+/** ID of the Reverb reflections delay parameter used by
+ AUDPROC_MODULE_ID_REVERB.
+*/
+#define AUDPROC_PARAM_ID_REVERB_REFLECTIONS_DELAY 0x000108B5
+/** ID of the Reverb level parameter used by
+ AUDPROC_MODULE_ID_REVERB.
+*/
+#define AUDPROC_PARAM_ID_REVERB_LEVEL 0x000108B6
+/** ID of the Reverb delay parameter used by
+ AUDPROC_MODULE_ID_REVERB.
+*/
+#define AUDPROC_PARAM_ID_REVERB_DELAY 0x000108B7
+/** ID of the Reverb diffusion parameter used by
+ AUDPROC_MODULE_ID_REVERB.
+*/
+#define AUDPROC_PARAM_ID_REVERB_DIFFUSION 0x000108B8
+/** ID of the Reverb density parameter used by
+ AUDPROC_MODULE_ID_REVERB.
+*/
+#define AUDPROC_PARAM_ID_REVERB_DENSITY 0x000108B9
+
+/** ID of the Popless Equalizer module. This module supports the
+ following parameter IDs:
+ - #AUDPROC_PARAM_ID_EQ_ENABLE
+ - #AUDPROC_PARAM_ID_EQ_CONFIG
+ - #AUDPROC_PARAM_ID_EQ_NUM_BANDS
+ - #AUDPROC_PARAM_ID_EQ_BAND_LEVELS
+ - #AUDPROC_PARAM_ID_EQ_BAND_LEVEL_RANGE
+ - #AUDPROC_PARAM_ID_EQ_BAND_FREQS
+ - #AUDPROC_PARAM_ID_EQ_SINGLE_BAND_FREQ_RANGE
+ - #AUDPROC_PARAM_ID_EQ_SINGLE_BAND_FREQ
+ - #AUDPROC_PARAM_ID_EQ_BAND_INDEX
+ - #AUDPROC_PARAM_ID_EQ_PRESET_ID
+ - #AUDPROC_PARAM_ID_EQ_NUM_PRESETS
+ - #AUDPROC_PARAM_ID_EQ_GET_PRESET_NAME
+*/
+#define AUDPROC_MODULE_ID_POPLESS_EQUALIZER 0x000108BA
+/** ID of the Popless Equalizer enable parameter used by
+ AUDPROC_MODULE_ID_POPLESS_EQUALIZER.
+*/
+#define AUDPROC_PARAM_ID_EQ_ENABLE 0x000108BB
+/** ID of the Popless Equalizer config parameter used by
+ AUDPROC_MODULE_ID_POPLESS_EQUALIZER.
+*/
+#define AUDPROC_PARAM_ID_EQ_CONFIG 0x000108BC
+/** ID of the Popless Equalizer number of bands parameter used
+ by AUDPROC_MODULE_ID_POPLESS_EQUALIZER. This param ID is
+ used for get param only.
+*/
+#define AUDPROC_PARAM_ID_EQ_NUM_BANDS 0x000108BD
+/** ID of the Popless Equalizer band levels parameter used by
+ AUDPROC_MODULE_ID_POPLESS_EQUALIZER. This param ID is
+ used for get param only.
+*/
+#define AUDPROC_PARAM_ID_EQ_BAND_LEVELS 0x000108BE
+/** ID of the Popless Equalizer band level range parameter used
+ by AUDPROC_MODULE_ID_POPLESS_EQUALIZER. This param ID is
+ used for get param only.
+*/
+#define AUDPROC_PARAM_ID_EQ_BAND_LEVEL_RANGE 0x000108BF
+/** ID of the Popless Equalizer band frequencies parameter used
+ by AUDPROC_MODULE_ID_POPLESS_EQUALIZER. This param ID is
+ used for get param only.
+*/
+#define AUDPROC_PARAM_ID_EQ_BAND_FREQS 0x000108C0
+/** ID of the Popless Equalizer single band frequency range
+ parameter used by AUDPROC_MODULE_ID_POPLESS_EQUALIZER.
+ This param ID is used for get param only.
+*/
+#define AUDPROC_PARAM_ID_EQ_SINGLE_BAND_FREQ_RANGE 0x000108C1
+/** ID of the Popless Equalizer single band frequency parameter
+ used by AUDPROC_MODULE_ID_POPLESS_EQUALIZER. This param ID
+ is used for set param only.
+*/
+#define AUDPROC_PARAM_ID_EQ_SINGLE_BAND_FREQ 0x000108C2
+/** ID of the Popless Equalizer band index parameter used by
+ AUDPROC_MODULE_ID_POPLESS_EQUALIZER.
+*/
+#define AUDPROC_PARAM_ID_EQ_BAND_INDEX 0x000108C3
+/** ID of the Popless Equalizer preset id parameter used by
+ AUDPROC_MODULE_ID_POPLESS_EQUALIZER. This param ID is used
+ for get param only.
+*/
+#define AUDPROC_PARAM_ID_EQ_PRESET_ID 0x000108C4
+/** ID of the Popless Equalizer number of presets parameter used
+ by AUDPROC_MODULE_ID_POPLESS_EQUALIZER. This param ID is used
+ for get param only.
+*/
+#define AUDPROC_PARAM_ID_EQ_NUM_PRESETS 0x000108C5
+/** ID of the Popless Equalizer preset name parameter used by
+ AUDPROC_MODULE_ID_POPLESS_EQUALIZER. This param ID is used
+ for get param only.
+*/
+#define AUDPROC_PARAM_ID_EQ_PRESET_NAME 0x000108C6
+
/* Set Q6 topologies */
#define ASM_CMD_ADD_TOPOLOGIES 0x00010DBE
#define ADM_CMD_ADD_TOPOLOGIES 0x00010335
@@ -6952,5 +7172,7 @@
#define US_POINT_EPOS_FORMAT_V2 0x0001272D
#define US_RAW_FORMAT_V2 0x0001272C
#define US_PROX_FORMAT_V2 0x0001272E
+#define US_RAW_SYNC_FORMAT 0x0001272F
+#define US_GES_SYNC_FORMAT 0x00012730
#endif /*_APR_AUDIO_V2_H_ */
diff --git a/include/sound/audio_effects.h b/include/sound/audio_effects.h
new file mode 100644
index 0000000..3444477
--- /dev/null
+++ b/include/sound/audio_effects.h
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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 _AUDIO_EFFECTS_H
+#define _AUDIO_EFFECTS_H
+
+/** AUDIO EFFECTS **/
+
+
+/* CONFIG GET/SET */
+#define CONFIG_CACHE 0
+#define CONFIG_SET 1
+#define CONFIG_GET 2
+
+/* CONFIG HEADER */
+/*
+
+ MODULE_ID,
+ DEVICE,
+ NUM_COMMANDS,
+ COMMAND_ID_1,
+ CONFIG_CACHE/SET/GET,
+ OFFSET_1,
+ LENGTH_1,
+ VALUES_1,
+ ...,
+ ...,
+ COMMAND_ID_2,
+ CONFIG_CACHE/SET/GET,
+ OFFSET_2,
+ LENGTH_2,
+ VALUES_2,
+ ...,
+ ...,
+ COMMAND_ID_3,
+ ...
+*/
+
+
+/* CONFIG PARAM IDs */
+#define VIRTUALIZER_MODULE 0x00001000
+#define VIRTUALIZER_ENABLE 0x00001001
+#define VIRTUALIZER_STRENGTH 0x00001002
+#define VIRTUALIZER_OUT_TYPE 0x00001003
+#define VIRTUALIZER_GAIN_ADJUST 0x00001004
+#define VIRTUALIZER_ENABLE_PARAM_LEN 1
+#define VIRTUALIZER_STRENGTH_PARAM_LEN 1
+#define VIRTUALIZER_OUT_TYPE_PARAM_LEN 1
+#define VIRTUALIZER_GAIN_ADJUST_PARAM_LEN 1
+
+#define REVERB_MODULE 0x00002000
+#define REVERB_ENABLE 0x00002001
+#define REVERB_MODE 0x00002002
+#define REVERB_PRESET 0x00002003
+#define REVERB_WET_MIX 0x00002004
+#define REVERB_GAIN_ADJUST 0x00002005
+#define REVERB_ROOM_LEVEL 0x00002006
+#define REVERB_ROOM_HF_LEVEL 0x00002007
+#define REVERB_DECAY_TIME 0x00002008
+#define REVERB_DECAY_HF_RATIO 0x00002009
+#define REVERB_REFLECTIONS_LEVEL 0x0000200a
+#define REVERB_REFLECTIONS_DELAY 0x0000200b
+#define REVERB_LEVEL 0x0000200c
+#define REVERB_DELAY 0x0000200d
+#define REVERB_DIFFUSION 0x0000200e
+#define REVERB_DENSITY 0x0000200f
+#define REVERB_ENABLE_PARAM_LEN 1
+#define REVERB_MODE_PARAM_LEN 1
+#define REVERB_PRESET_PARAM_LEN 1
+#define REVERB_WET_MIX_PARAM_LEN 1
+#define REVERB_GAIN_ADJUST_PARAM_LEN 1
+#define REVERB_ROOM_LEVEL_PARAM_LEN 1
+#define REVERB_ROOM_HF_LEVEL_PARAM_LEN 1
+#define REVERB_DECAY_TIME_PARAM_LEN 1
+#define REVERB_DECAY_HF_RATIO_PARAM_LEN 1
+#define REVERB_REFLECTIONS_LEVEL_PARAM_LEN 1
+#define REVERB_REFLECTIONS_DELAY_PARAM_LEN 1
+#define REVERB_LEVEL_PARAM_LEN 1
+#define REVERB_DELAY_PARAM_LEN 1
+#define REVERB_DIFFUSION_PARAM_LEN 1
+#define REVERB_DENSITY_PARAM_LEN 1
+
+#define BASS_BOOST_MODULE 0x00003000
+#define BASS_BOOST_ENABLE 0x00003001
+#define BASS_BOOST_MODE 0x00003002
+#define BASS_BOOST_STRENGTH 0x00003003
+#define BASS_BOOST_ENABLE_PARAM_LEN 1
+#define BASS_BOOST_MODE_PARAM_LEN 1
+#define BASS_BOOST_STRENGTH_PARAM_LEN 1
+
+#define EQ_MODULE 0x00004000
+#define EQ_ENABLE 0x00004001
+#define EQ_CONFIG 0x00004002
+#define EQ_NUM_BANDS 0x00004003
+#define EQ_BAND_LEVELS 0x00004004
+#define EQ_BAND_LEVEL_RANGE 0x00004005
+#define EQ_BAND_FREQS 0x00004006
+#define EQ_SINGLE_BAND_FREQ_RANGE 0x00004007
+#define EQ_SINGLE_BAND_FREQ 0x00004008
+#define EQ_BAND_INDEX 0x00004009
+#define EQ_PRESET_ID 0x0000400a
+#define EQ_NUM_PRESETS 0x0000400b
+#define EQ_PRESET_NAME 0x0000400c
+#define EQ_ENABLE_PARAM_LEN 1
+#define EQ_CONFIG_PARAM_LEN 3
+#define EQ_CONFIG_PER_BAND_PARAM_LEN 5
+#define EQ_NUM_BANDS_PARAM_LEN 1
+#define EQ_BAND_LEVELS_PARAM_LEN 13
+#define EQ_BAND_LEVEL_RANGE_PARAM_LEN 2
+#define EQ_BAND_FREQS_PARAM_LEN 13
+#define EQ_SINGLE_BAND_FREQ_RANGE_PARAM_LEN 2
+#define EQ_SINGLE_BAND_FREQ_PARAM_LEN 1
+#define EQ_BAND_INDEX_PARAM_LEN 1
+#define EQ_PRESET_ID_PARAM_LEN 1
+#define EQ_NUM_PRESETS_PARAM_LEN 1
+#define EQ_PRESET_NAME_PARAM_LEN 32
+
+#define EQ_TYPE_NONE 0
+#define EQ_BASS_BOOST 1
+#define EQ_BASS_CUT 2
+#define EQ_TREBLE_BOOST 3
+#define EQ_TREBLE_CUT 4
+#define EQ_BAND_BOOST 5
+#define EQ_BAND_CUT 6
+
+
+
+#define COMMAND_PAYLOAD_LEN 3
+#define COMMAND_PAYLOAD_SZ (COMMAND_PAYLOAD_LEN * sizeof(uint32_t))
+#define MAX_INBAND_PARAM_SZ 4096
+#define Q27_UNITY (1 << 27)
+#define Q8_UNITY (1 << 8)
+#define CUSTOM_OPENSL_PRESET 18
+
+#define VIRTUALIZER_ENABLE_PARAM_SZ \
+ (VIRTUALIZER_ENABLE_PARAM_LEN*sizeof(uint32_t))
+#define VIRTUALIZER_STRENGTH_PARAM_SZ \
+ (VIRTUALIZER_STRENGTH_PARAM_LEN*sizeof(uint32_t))
+#define VIRTUALIZER_OUT_TYPE_PARAM_SZ \
+ (VIRTUALIZER_OUT_TYPE_PARAM_LEN*sizeof(uint32_t))
+#define VIRTUALIZER_GAIN_ADJUST_PARAM_SZ \
+ (VIRTUALIZER_GAIN_ADJUST_PARAM_LEN*sizeof(uint32_t))
+struct virtualizer_params {
+ uint32_t device;
+ uint32_t enable_flag;
+ uint32_t strength;
+ uint32_t out_type;
+ int32_t gain_adjust;
+};
+
+#define NUM_OSL_REVERB_PRESETS_SUPPORTED 6
+#define REVERB_ENABLE_PARAM_SZ \
+ (REVERB_ENABLE_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_MODE_PARAM_SZ \
+ (REVERB_MODE_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_PRESET_PARAM_SZ \
+ (REVERB_PRESET_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_WET_MIX_PARAM_SZ \
+ (REVERB_WET_MIX_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_GAIN_ADJUST_PARAM_SZ \
+ (REVERB_GAIN_ADJUST_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_ROOM_LEVEL_PARAM_SZ \
+ (REVERB_ROOM_LEVEL_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_ROOM_HF_LEVEL_PARAM_SZ \
+ (REVERB_ROOM_HF_LEVEL_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_DECAY_TIME_PARAM_SZ \
+ (REVERB_DECAY_TIME_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_DECAY_HF_RATIO_PARAM_SZ \
+ (REVERB_DECAY_HF_RATIO_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_REFLECTIONS_LEVEL_PARAM_SZ \
+ (REVERB_REFLECTIONS_LEVEL_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_REFLECTIONS_DELAY_PARAM_SZ \
+ (REVERB_REFLECTIONS_DELAY_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_LEVEL_PARAM_SZ \
+ (REVERB_LEVEL_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_DELAY_PARAM_SZ \
+ (REVERB_DELAY_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_DIFFUSION_PARAM_SZ \
+ (REVERB_DIFFUSION_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_DENSITY_PARAM_SZ \
+ (REVERB_DENSITY_PARAM_LEN*sizeof(uint32_t))
+struct reverb_params {
+ uint32_t device;
+ uint32_t enable_flag;
+ uint32_t mode;
+ uint32_t preset;
+ uint32_t wet_mix;
+ int32_t gain_adjust;
+ int32_t room_level;
+ int32_t room_hf_level;
+ uint32_t decay_time;
+ uint32_t decay_hf_ratio;
+ int32_t reflections_level;
+ uint32_t reflections_delay;
+ int32_t level;
+ uint32_t delay;
+ uint32_t diffusion;
+ uint32_t density;
+};
+
+#define BASS_BOOST_ENABLE_PARAM_SZ \
+ (BASS_BOOST_ENABLE_PARAM_LEN*sizeof(uint32_t))
+#define BASS_BOOST_MODE_PARAM_SZ \
+ (BASS_BOOST_MODE_PARAM_LEN*sizeof(uint32_t))
+#define BASS_BOOST_STRENGTH_PARAM_SZ \
+ (BASS_BOOST_STRENGTH_PARAM_LEN*sizeof(uint32_t))
+struct bass_boost_params {
+ uint32_t device;
+ uint32_t enable_flag;
+ uint32_t mode;
+ uint32_t strength;
+};
+
+
+#define MAX_EQ_BANDS 12
+#define MAX_OSL_EQ_BANDS 5
+#define EQ_ENABLE_PARAM_SZ \
+ (EQ_ENABLE_PARAM_LEN*sizeof(uint32_t))
+#define EQ_CONFIG_PARAM_SZ \
+ (EQ_CONFIG_PARAM_LEN*sizeof(uint32_t))
+#define EQ_CONFIG_PER_BAND_PARAM_SZ \
+ (EQ_CONFIG_PER_BAND_PARAM_LEN*sizeof(uint32_t))
+#define EQ_CONFIG_PARAM_MAX_LEN (EQ_CONFIG_PARAM_LEN+\
+ MAX_EQ_BANDS*EQ_CONFIG_PER_BAND_PARAM_LEN)
+#define EQ_CONFIG_PARAM_MAX_SZ \
+ (EQ_CONFIG_PARAM_MAX_LEN*sizeof(uint32_t))
+#define EQ_NUM_BANDS_PARAM_SZ \
+ (EQ_NUM_BANDS_PARAM_LEN*sizeof(uint32_t))
+#define EQ_BAND_LEVELS_PARAM_SZ \
+ (EQ_BAND_LEVELS_PARAM_LEN*sizeof(uint32_t))
+#define EQ_BAND_LEVEL_RANGE_PARAM_SZ \
+ (EQ_BAND_LEVEL_RANGE_PARAM_LEN*sizeof(uint32_t))
+#define EQ_BAND_FREQS_PARAM_SZ \
+ (EQ_BAND_FREQS_PARAM_LEN*sizeof(uint32_t))
+#define EQ_SINGLE_BAND_FREQ_RANGE_PARAM_SZ \
+ (EQ_SINGLE_BAND_FREQ_RANGE_PARAM_LEN*sizeof(uint32_t))
+#define EQ_SINGLE_BAND_FREQ_PARAM_SZ \
+ (EQ_SINGLE_BAND_FREQ_PARAM_LEN*sizeof(uint32_t))
+#define EQ_BAND_INDEX_PARAM_SZ \
+ (EQ_BAND_INDEX_PARAM_LEN*sizeof(uint32_t))
+#define EQ_PRESET_ID_PARAM_SZ \
+ (EQ_PRESET_ID_PARAM_LEN*sizeof(uint32_t))
+#define EQ_NUM_PRESETS_PARAM_SZ \
+ (EQ_NUM_PRESETS_PARAM_LEN*sizeof(uint8_t))
+struct eq_config_t {
+ int32_t eq_pregain;
+ int32_t preset_id;
+ uint32_t num_bands;
+};
+struct eq_per_band_config_t {
+ int32_t band_idx;
+ uint32_t filter_type;
+ uint32_t freq_millihertz;
+ int32_t gain_millibels;
+ uint32_t quality_factor;
+};
+struct eq_per_band_freq_range_t {
+ uint32_t band_index;
+ uint32_t min_freq_millihertz;
+ uint32_t max_freq_millihertz;
+};
+
+struct eq_params {
+ uint32_t device;
+ uint32_t enable_flag;
+ struct eq_config_t config;
+ struct eq_per_band_config_t per_band_cfg[MAX_EQ_BANDS];
+ struct eq_per_band_freq_range_t per_band_freq_range[MAX_EQ_BANDS];
+ uint32_t band_index;
+ uint32_t freq_millihertz;
+};
+
+#endif /*_MSM_AUDIO_EFFECTS_H*/
diff --git a/include/sound/q6adm-v2.h b/include/sound/q6adm-v2.h
index 6f121b3..5941f71 100644
--- a/include/sound/q6adm-v2.h
+++ b/include/sound/q6adm-v2.h
@@ -31,7 +31,7 @@
int srs_trumedia_open(int port_id, int srs_tech_id, void *srs_params);
int adm_open(int port, int path, int rate, int mode, int topology,
- bool perf_mode, uint16_t bits_per_sample);
+ int perf_mode, uint16_t bits_per_sample);
int adm_get_params(int port_id, uint32_t module_id, uint32_t param_id,
uint32_t params_length, char *params);
@@ -40,7 +40,7 @@
uint32_t params_length);
int adm_multi_ch_copp_open(int port, int path, int rate, int mode,
- int topology, bool perf_mode, uint16_t bits_per_sample);
+ int topology, int perf_mode, uint16_t bits_per_sample);
int adm_unmap_cal_blocks(void);
@@ -53,10 +53,10 @@
int adm_memory_unmap_regions(int port_id);
-int adm_close(int port, bool perf_mode);
+int adm_close(int port, int perf_mode);
int adm_matrix_map(int session_id, int path, int num_copps,
- unsigned int *port_id, int copp_id, bool perf_mode);
+ unsigned int *port_id, int copp_id, int perf_mode);
int adm_connect_afe_port(int mode, int session_id, int port_id);
@@ -64,6 +64,8 @@
int adm_get_copp_id(int port_id);
+int adm_get_lowlatency_copp_id(int port_id);
+
void adm_set_multi_ch_map(char *channel_map);
void adm_get_multi_ch_map(char *channel_map);
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index 3cc476f..a78c333 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -54,6 +54,7 @@
#define CMD_EOS 0x0003
#define CMD_CLOSE 0x0004
#define CMD_OUT_FLUSH 0x0005
+#define CMD_SUSPEND 0x0006
/* bit 0:1 represents priority of stream */
#define STREAM_PRIORITY_NORMAL 0x0000
@@ -66,6 +67,8 @@
/* Enable Sample_Rate/Channel_Mode notification event from Decoder */
#define SR_CM_NOTIFY_ENABLE 0x0004
+#define TUN_WRITE_IO_MODE 0x0008 /* tunnel read write mode */
+#define TUN_READ_IO_MODE 0x0004 /* tunnel read write mode */
#define SYNC_IO_MODE 0x0001
#define ASYNC_IO_MODE 0x0002
#define COMPRESSED_IO 0x0040
@@ -80,6 +83,9 @@
#define SESSION_MAX 0x08
#define ASM_CONTROL_SESSION 0x0F
+#define ASM_SHIFT_GAPLESS_MODE_FLAG 31
+#define ASM_SHIFT_LAST_BUFFER_FLAG 30
+
/* payload structure bytes */
#define READDONE_IDX_STATUS 0
#define READDONE_IDX_BUFADD_LSW 1
@@ -130,6 +136,7 @@
uint32_t msw_ts;
uint32_t flags;
uint32_t metadata_len;
+ uint32_t last_buffer;
};
struct audio_aio_read_param {
@@ -162,12 +169,14 @@
uint64_t time_stamp;
struct apr_svc *apr;
struct apr_svc *mmap_apr;
+ struct apr_svc *apr2;
struct mutex cmd_lock;
/* idx:1 out port, 0: in port*/
struct audio_port_data port[2];
wait_queue_head_t cmd_wait;
wait_queue_head_t time_wait;
- bool perf_mode;
+ int perf_mode;
+ int stream_id;
/* audio cache operations fptr*/
int (*fptr_cache_ops)(struct audio_buffer *abuff, int cache_op);
};
@@ -203,10 +212,17 @@
int q6asm_open_write_v2(struct audio_client *ac, uint32_t format,
uint16_t bits_per_sample);
+int q6asm_stream_open_write_v2(struct audio_client *ac, uint32_t format,
+ uint16_t bits_per_sample, int32_t stream_id,
+ bool is_gapless_mode);
+
int q6asm_open_read_write(struct audio_client *ac,
uint32_t rd_format,
uint32_t wr_format);
+int q6asm_open_loopback_v2(struct audio_client *ac,
+ uint16_t bits_per_sample);
+
int q6asm_write(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
uint32_t lsw_ts, uint32_t flags);
int q6asm_write_nolock(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
@@ -239,12 +255,22 @@
int q6asm_run_nowait(struct audio_client *ac, uint32_t flags,
uint32_t msw_ts, uint32_t lsw_ts);
+int q6asm_stream_run_nowait(struct audio_client *ac, uint32_t flags,
+ uint32_t msw_ts, uint32_t lsw_ts, uint32_t stream_id);
+
int q6asm_reg_tx_overflow(struct audio_client *ac, uint16_t enable);
+int q6asm_reg_rx_underflow(struct audio_client *ac, uint16_t enable);
+
int q6asm_cmd(struct audio_client *ac, int cmd);
+int q6asm_stream_cmd(struct audio_client *ac, int cmd, uint32_t stream_id);
+
int q6asm_cmd_nowait(struct audio_client *ac, int cmd);
+int q6asm_stream_cmd_nowait(struct audio_client *ac, int cmd,
+ uint32_t stream_id);
+
void *q6asm_is_cpu_buf_avail(int dir, struct audio_client *ac,
uint32_t *size, uint32_t *idx);
@@ -316,6 +342,9 @@
int q6asm_media_format_block_aac(struct audio_client *ac,
struct asm_aac_cfg *cfg);
+int q6asm_stream_media_format_block_aac(struct audio_client *ac,
+ struct asm_aac_cfg *cfg, int stream_id);
+
int q6asm_media_format_block_multi_aac(struct audio_client *ac,
struct asm_aac_cfg *cfg);
@@ -353,6 +382,9 @@
int q6asm_get_session_time(struct audio_client *ac, uint64_t *tstamp);
+int q6asm_send_audio_effects_params(struct audio_client *ac, char *params,
+ uint32_t params_length);
+
/* Client can set the IO mode to either AIO/SIO mode */
int q6asm_set_io_mode(struct audio_client *ac, uint32_t mode);
@@ -363,4 +395,8 @@
*/
int q6asm_media_format_block(struct audio_client *ac, uint32_t format);
+/* Send the meta data to remove initial and trailing silence */
+int q6asm_send_meta_data(struct audio_client *ac, uint32_t initial_samples,
+ uint32_t trailing_samples);
+
#endif /* __Q6_ASM_H__ */
diff --git a/include/sound/q6audio-v2.h b/include/sound/q6audio-v2.h
index fd6a490..8ac835c 100644
--- a/include/sound/q6audio-v2.h
+++ b/include/sound/q6audio-v2.h
@@ -15,6 +15,13 @@
#include <mach/qdsp6v2/apr.h>
+enum {
+ LEGACY_PCM_MODE = 0,
+ LOW_LATENCY_PCM_MODE,
+ ULTRA_LOW_LATENCY_PCM_MODE,
+};
+
+
int q6audio_get_port_index(u16 port_id);
int q6audio_convert_virtual_to_portid(u16 port_id);
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index fed2e0a..4a606af 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -442,6 +442,11 @@
snd_soc_dapm_siggen, /* signal generator */
};
+enum snd_soc_dapm_subclass {
+ SND_SOC_DAPM_CLASS_INIT = 0,
+ SND_SOC_DAPM_CLASS_PCM = 1,
+};
+
/*
* DAPM audio route definition.
*
diff --git a/include/sound/soc.h b/include/sound/soc.h
index ecfba67..278ada3 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -563,6 +563,7 @@
#endif
struct snd_soc_jack {
+ struct mutex mutex;
struct snd_jack *jack;
struct snd_soc_codec *codec;
struct list_head pins;
diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h
index 41f8607..c549831 100644
--- a/include/trace/events/sched.h
+++ b/include/trace/events/sched.h
@@ -242,6 +242,56 @@
__entry->status ? "online" : "offline", __entry->error)
);
+/*
+ * Tracepoint for load balancing:
+ */
+#if NR_CPUS > 32
+#error "Unsupported NR_CPUS for lb tracepoint."
+#endif
+TRACE_EVENT(sched_load_balance,
+
+ TP_PROTO(int cpu, enum cpu_idle_type idle, int balance,
+ unsigned long group_mask, int busiest_nr_running,
+ unsigned long imbalance, unsigned int env_flags, int ld_moved,
+ unsigned int balance_interval),
+
+ TP_ARGS(cpu, idle, balance, group_mask, busiest_nr_running,
+ imbalance, env_flags, ld_moved, balance_interval),
+
+ TP_STRUCT__entry(
+ __field( int, cpu)
+ __field( enum cpu_idle_type, idle)
+ __field( int, balance)
+ __field( unsigned long, group_mask)
+ __field( int, busiest_nr_running)
+ __field( unsigned long, imbalance)
+ __field( unsigned int, env_flags)
+ __field( int, ld_moved)
+ __field( unsigned int, balance_interval)
+ ),
+
+ TP_fast_assign(
+ __entry->cpu = cpu;
+ __entry->idle = idle;
+ __entry->balance = balance;
+ __entry->group_mask = group_mask;
+ __entry->busiest_nr_running = busiest_nr_running;
+ __entry->imbalance = imbalance;
+ __entry->env_flags = env_flags;
+ __entry->ld_moved = ld_moved;
+ __entry->balance_interval = balance_interval;
+ ),
+
+ TP_printk("cpu=%d state=%s balance=%d group=%#lx busy_nr=%d imbalance=%ld flags=%#x ld_moved=%d bal_int=%d",
+ __entry->cpu,
+ __entry->idle == CPU_IDLE ? "idle" :
+ (__entry->idle == CPU_NEWLY_IDLE ? "newly_idle" : "busy"),
+ __entry->balance,
+ __entry->group_mask, __entry->busiest_nr_running,
+ __entry->imbalance, __entry->env_flags, __entry->ld_moved,
+ __entry->balance_interval)
+);
+
DECLARE_EVENT_CLASS(sched_process_template,
TP_PROTO(struct task_struct *p),
diff --git a/kernel/cpu.c b/kernel/cpu.c
index d5ab2e6..2db91f9 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -77,6 +77,10 @@
if (cpu_hotplug.active_writer == current)
return;
mutex_lock(&cpu_hotplug.lock);
+
+ if (WARN_ON(!cpu_hotplug.refcount))
+ cpu_hotplug.refcount++; /* try to fix things up */
+
if (!--cpu_hotplug.refcount && unlikely(cpu_hotplug.active_writer))
wake_up_process(cpu_hotplug.active_writer);
mutex_unlock(&cpu_hotplug.lock);
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 627dab1..954a8c4 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -621,7 +621,19 @@
static inline bool got_nohz_idle_kick(void)
{
int cpu = smp_processor_id();
- return idle_cpu(cpu) && test_bit(NOHZ_BALANCE_KICK, nohz_flags(cpu));
+
+ if (!test_bit(NOHZ_BALANCE_KICK, nohz_flags(cpu)))
+ return false;
+
+ if (idle_cpu(cpu) && !need_resched())
+ return true;
+
+ /*
+ * We can't run Idle Load Balance on this CPU for this time so we
+ * cancel it and clear NOHZ_BALANCE_KICK
+ */
+ clear_bit(NOHZ_BALANCE_KICK, nohz_flags(cpu));
+ return false;
}
#else /* CONFIG_NO_HZ */
@@ -1519,7 +1531,7 @@
/*
* Check if someone kicked us for doing the nohz idle load balance.
*/
- if (unlikely(got_nohz_idle_kick() && !need_resched())) {
+ if (unlikely(got_nohz_idle_kick())) {
this_rq()->idle_balance = 1;
raise_softirq_irqoff(SCHED_SOFTIRQ);
}
@@ -4919,7 +4931,7 @@
touch_all_softlockup_watchdogs();
-#ifdef CONFIG_SCHED_DEBUG
+#ifdef CONFIG_SYSRQ_SCHED_DEBUG
sysrq_sched_debug_show();
#endif
rcu_read_unlock();
diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c
index 09acaa1..c00829e 100644
--- a/kernel/sched/debug.c
+++ b/kernel/sched/debug.c
@@ -374,10 +374,12 @@
return 0;
}
+#ifdef CONFIG_SYSRQ_SCHED_DEBUG
void sysrq_sched_debug_show(void)
{
sched_debug_show(NULL, NULL);
}
+#endif
static int sched_debug_open(struct inode *inode, struct file *filp)
{
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 2e98983..08497b0 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -4422,7 +4422,7 @@
int ld_moved, active_balance = 0;
struct sched_group *group;
unsigned long imbalance;
- struct rq *busiest;
+ struct rq *busiest = NULL;
unsigned long flags;
struct cpumask *cpus = __get_cpu_var(load_balance_tmpmask);
@@ -4591,6 +4591,10 @@
ld_moved = 0;
out:
+ trace_sched_load_balance(this_cpu, idle, *balance,
+ group ? group->cpumask[0] : 0,
+ busiest ? busiest->nr_running : 0, imbalance,
+ env.flags, ld_moved, sd->balance_interval);
return ld_moved;
}
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 55f6d9c..c0288a6 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -872,7 +872,9 @@
#endif
+#ifdef CONFIG_SYSRQ_SCHED_DEBUG
extern void sysrq_sched_debug_show(void);
+#endif
extern void sched_init_granularity(void);
extern void update_max_interval(void);
extern void update_group_power(struct sched_domain *sd, int cpu);
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index d16a59ec..c35fe53 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -102,6 +102,7 @@
extern unsigned int core_pipe_limit;
extern int pid_max;
extern int min_free_kbytes;
+extern int extra_free_kbytes;
extern int min_free_order_shift;
extern int pid_max_min, pid_max_max;
extern int sysctl_drop_caches;
@@ -1228,6 +1229,14 @@
.extra1 = &zero,
},
{
+ .procname = "extra_free_kbytes",
+ .data = &extra_free_kbytes,
+ .maxlen = sizeof(extra_free_kbytes),
+ .mode = 0644,
+ .proc_handler = min_free_kbytes_sysctl_handler,
+ .extra1 = &zero,
+ },
+ {
.procname = "min_free_order_shift",
.data = &min_free_order_shift,
.maxlen = sizeof(min_free_order_shift),
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c
index f113755..d6d0d41 100644
--- a/kernel/time/tick-broadcast.c
+++ b/kernel/time/tick-broadcast.c
@@ -370,14 +370,34 @@
return to_cpumask(tick_broadcast_oneshot_mask);
}
-static int tick_broadcast_set_event(ktime_t expires, int force)
+/*
+ * Set broadcast interrupt affinity
+ */
+static void tick_broadcast_set_affinity(struct clock_event_device *bc,
+ const struct cpumask *cpumask)
{
- struct clock_event_device *bc = tick_broadcast_device.evtdev;
+ if (!(bc->features & CLOCK_EVT_FEAT_DYNIRQ))
+ return;
+
+ if (cpumask_equal(bc->cpumask, cpumask))
+ return;
+
+ bc->cpumask = cpumask;
+ irq_set_affinity(bc->irq, bc->cpumask);
+}
+
+static int tick_broadcast_set_event(struct clock_event_device *bc, int cpu,
+ ktime_t expires, int force)
+{
+ int ret;
if (bc->mode != CLOCK_EVT_MODE_ONESHOT)
clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT);
- return clockevents_program_event(bc, expires, force);
+ ret = clockevents_program_event(bc, expires, force);
+ if (!ret)
+ tick_broadcast_set_affinity(bc, cpumask_of(cpu));
+ return ret;
}
int tick_resume_broadcast_oneshot(struct clock_event_device *bc)
@@ -406,7 +426,7 @@
{
struct tick_device *td;
ktime_t now, next_event;
- int cpu;
+ int cpu, next_cpu = 0;
raw_spin_lock(&tick_broadcast_lock);
again:
@@ -417,10 +437,12 @@
/* Find all expired events */
for_each_cpu(cpu, tick_get_broadcast_oneshot_mask()) {
td = &per_cpu(tick_cpu_device, cpu);
- if (td->evtdev->next_event.tv64 <= now.tv64)
+ if (td->evtdev->next_event.tv64 <= now.tv64) {
cpumask_set_cpu(cpu, to_cpumask(tmpmask));
- else if (td->evtdev->next_event.tv64 < next_event.tv64)
+ } else if (td->evtdev->next_event.tv64 < next_event.tv64) {
next_event.tv64 = td->evtdev->next_event.tv64;
+ next_cpu = cpu;
+ }
}
/*
@@ -443,7 +465,7 @@
* Rearm the broadcast device. If event expired,
* repeat the above
*/
- if (tick_broadcast_set_event(next_event, 0))
+ if (tick_broadcast_set_event(dev, next_cpu, next_event, 0))
goto again;
}
raw_spin_unlock(&tick_broadcast_lock);
@@ -486,7 +508,7 @@
cpumask_set_cpu(cpu, tick_get_broadcast_oneshot_mask());
clockevents_set_mode(dev, CLOCK_EVT_MODE_SHUTDOWN);
if (dev->next_event.tv64 < bc->next_event.tv64)
- tick_broadcast_set_event(dev->next_event, 1);
+ tick_broadcast_set_event(bc, cpu, dev->next_event, 1);
}
} else {
if (cpumask_test_cpu(cpu, tick_get_broadcast_oneshot_mask())) {
@@ -555,7 +577,7 @@
clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT);
tick_broadcast_init_next_event(to_cpumask(tmpmask),
tick_next_period);
- tick_broadcast_set_event(tick_next_period, 1);
+ tick_broadcast_set_event(bc, cpu, tick_next_period, 1);
} else
bc->next_event.tv64 = KTIME_MAX;
} else {
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index b9060a1..5160a45 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -291,6 +291,15 @@
that can help debug the scheduler. The runtime overhead of this
option is minimal.
+config SYSRQ_SCHED_DEBUG
+ bool "Print scheduling debugging info from sysrq-trigger"
+ depends on SCHED_DEBUG
+ default y
+ help
+ If you say Y here, the "show-task-states(T)" and
+ "show-blocked-tasks(W)" sysrq-triggers will print additional
+ scheduling statistics.
+
config SCHEDSTATS
bool "Collect scheduler statistics"
depends on DEBUG_KERNEL && PROC_FS
diff --git a/lib/idr.c b/lib/idr.c
index 4046e29..e90d2d0 100644
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -625,7 +625,14 @@
return p;
}
- id += 1 << n;
+ /*
+ * Proceed to the next layer at the current level. Unlike
+ * idr_for_each(), @id isn't guaranteed to be aligned to
+ * layer boundary at this point and adding 1 << n may
+ * incorrectly skip IDs. Make sure we jump to the
+ * beginning of the next layer using round_up().
+ */
+ id = round_up(id + 1, 1 << n);
while (n < fls(id)) {
n += IDR_BITS;
p = *--paa;
diff --git a/lib/spinlock_debug.c b/lib/spinlock_debug.c
index 6d22836..955a47b 100644
--- a/lib/spinlock_debug.c
+++ b/lib/spinlock_debug.c
@@ -108,7 +108,7 @@
static void __spin_lock_debug(raw_spinlock_t *lock)
{
u64 i;
- u64 loops = (loops_per_jiffy * HZ) >> 1;
+ u64 loops = (loops_per_jiffy * HZ);
for (i = 0; i < loops; i++) {
if (arch_spin_trylock(&lock->raw_lock))
diff --git a/mm/internal.h b/mm/internal.h
index 3439ef4..f5369cc 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -90,6 +90,8 @@
*/
extern int isolate_lru_page(struct page *page);
extern void putback_lru_page(struct page *page);
+extern unsigned long zone_reclaimable_pages(struct zone *zone);
+extern bool zone_reclaimable(struct zone *zone);
/*
* in mm/page_alloc.c
diff --git a/mm/mmap.c b/mm/mmap.c
index 848ef52..9932edb 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -133,7 +133,7 @@
*/
free -= global_page_state(NR_SHMEM);
- free += nr_swap_pages;
+ free += get_nr_swap_pages();
/*
* Any slabs which are created with the
diff --git a/mm/nommu.c b/mm/nommu.c
index bb8f4f0..6bb7042 100644
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -1928,7 +1928,7 @@
*/
free -= global_page_state(NR_SHMEM);
- free += nr_swap_pages;
+ free += get_nr_swap_pages();
/*
* Any slabs which are created with the
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index 26adea8..a5e8dc2 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -34,8 +34,11 @@
#include <linux/syscalls.h>
#include <linux/buffer_head.h> /* __set_page_dirty_buffers */
#include <linux/pagevec.h>
+#include <linux/mm_inline.h>
#include <trace/events/writeback.h>
+#include "internal.h"
+
/*
* Sleep at most 200ms at a time in balance_dirty_pages().
*/
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 46ccd2f..d4c0534 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -57,6 +57,7 @@
#include <linux/ftrace_event.h>
#include <linux/memcontrol.h>
#include <linux/prefetch.h>
+#include <linux/mm_inline.h>
#include <linux/migrate.h>
#include <linux/page-debug-flags.h>
@@ -198,9 +199,21 @@
"Movable",
};
+/*
+ * Try to keep at least this much lowmem free. Do not allow normal
+ * allocations below this point, only high priority ones. Automatically
+ * tuned according to the amount of memory in the system.
+ */
int min_free_kbytes = 1024;
int min_free_order_shift = 1;
+/*
+ * Extra memory for the system to try freeing. Used to temporarily
+ * free memory, to make space for new workloads. Anyone can allocate
+ * down to the min watermarks controlled by min_free_kbytes above.
+ */
+int extra_free_kbytes = 0;
+
static unsigned long __meminitdata nr_kernel_pages;
static unsigned long __meminitdata nr_all_pages;
static unsigned long __meminitdata dma_reserve;
@@ -647,7 +660,6 @@
int mt = 0;
spin_lock(&zone->lock);
- zone->all_unreclaimable = 0;
zone->pages_scanned = 0;
while (to_free) {
@@ -693,7 +705,6 @@
int migratetype)
{
spin_lock(&zone->lock);
- zone->all_unreclaimable = 0;
zone->pages_scanned = 0;
__free_one_page(page, zone, order, migratetype);
@@ -1452,10 +1463,11 @@
zone = page_zone(page);
mt = get_pageblock_migratetype(page);
- if (mt != MIGRATE_ISOLATE && !is_migrate_cma(mt)) {
+ if (mt != MIGRATE_ISOLATE) {
/* Obey watermarks as if the page was being allocated */
watermark = low_wmark_pages(zone) + (1 << order);
- if (!zone_watermark_ok(zone, 0, watermark, 0, 0))
+ if (!is_migrate_cma(mt) &&
+ !zone_watermark_ok(zone, 0, watermark, 0, 0))
return 0;
__mod_zone_freepage_state(zone, -(1UL << order), mt);
@@ -2997,7 +3009,7 @@
K(zone_page_state(zone, NR_FREE_CMA_PAGES)),
K(zone_page_state(zone, NR_WRITEBACK_TEMP)),
zone->pages_scanned,
- (zone->all_unreclaimable ? "yes" : "no")
+ (!zone_reclaimable(zone) ? "yes" : "no")
);
printk("lowmem_reserve[]:");
for (i = 0; i < MAX_NR_ZONES; i++)
@@ -5178,6 +5190,7 @@
static void __setup_per_zone_wmarks(void)
{
unsigned long pages_min = min_free_kbytes >> (PAGE_SHIFT - 10);
+ unsigned long pages_low = extra_free_kbytes >> (PAGE_SHIFT - 10);
unsigned long lowmem_pages = 0;
struct zone *zone;
unsigned long flags;
@@ -5189,11 +5202,14 @@
}
for_each_zone(zone) {
- u64 tmp;
+ u64 min, low;
spin_lock_irqsave(&zone->lock, flags);
- tmp = (u64)pages_min * zone->present_pages;
- do_div(tmp, lowmem_pages);
+ min = (u64)pages_min * zone->present_pages;
+ do_div(min, lowmem_pages);
+ low = (u64)pages_low * zone->present_pages;
+ do_div(low, vm_total_pages);
+
if (is_highmem(zone)) {
/*
* __GFP_HIGH and PF_MEMALLOC allocations usually don't
@@ -5217,11 +5233,13 @@
* If it's a lowmem zone, reserve a number of pages
* proportionate to the zone's size.
*/
- zone->watermark[WMARK_MIN] = tmp;
+ zone->watermark[WMARK_MIN] = min;
}
- zone->watermark[WMARK_LOW] = min_wmark_pages(zone) + (tmp >> 2);
- zone->watermark[WMARK_HIGH] = min_wmark_pages(zone) + (tmp >> 1);
+ zone->watermark[WMARK_LOW] = min_wmark_pages(zone) +
+ low + (min >> 2);
+ zone->watermark[WMARK_HIGH] = min_wmark_pages(zone) +
+ low + (min >> 1);
setup_zone_migrate_reserve(zone);
spin_unlock_irqrestore(&zone->lock, flags);
@@ -5334,7 +5352,7 @@
/*
* min_free_kbytes_sysctl_handler - just a wrapper around proc_dointvec() so
* that we can call two helper functions whenever min_free_kbytes
- * changes.
+ * or extra_free_kbytes changes.
*/
int min_free_kbytes_sysctl_handler(ctl_table *table, int write,
void __user *buffer, size_t *length, loff_t *ppos)
diff --git a/mm/page_io.c b/mm/page_io.c
index dc76b4d..1499e1c 100644
--- a/mm/page_io.c
+++ b/mm/page_io.c
@@ -1,3 +1,4 @@
+
/*
* linux/mm/page_io.c
*
@@ -18,8 +19,16 @@
#include <linux/bio.h>
#include <linux/swapops.h>
#include <linux/writeback.h>
+#include <linux/blkdev.h>
+#include <linux/ratelimit.h>
#include <asm/pgtable.h>
+/*
+ * We don't need to see swap errors more than once every 1 second to know
+ * that a problem is occurring.
+ */
+#define SWAP_ERROR_LOG_RATE_MS 1000
+
static struct bio *get_swap_bio(gfp_t gfp_flags,
struct page *page, bio_end_io_t end_io)
{
@@ -44,6 +53,7 @@
{
const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
struct page *page = bio->bi_io_vec[0].bv_page;
+ static unsigned long swap_error_rs_time;
if (!uptodate) {
SetPageError(page);
@@ -56,7 +66,9 @@
* Also clear PG_reclaim to avoid rotate_reclaimable_page()
*/
set_page_dirty(page);
- printk(KERN_ALERT "Write-error on swap-device (%u:%u:%Lu)\n",
+ if (printk_timed_ratelimit(&swap_error_rs_time,
+ SWAP_ERROR_LOG_RATE_MS))
+ printk(KERN_ALERT "Write-error on swap-device (%u:%u:%Lu)\n",
imajor(bio->bi_bdev->bd_inode),
iminor(bio->bi_bdev->bd_inode),
(unsigned long long)bio->bi_sector);
@@ -78,9 +90,54 @@
imajor(bio->bi_bdev->bd_inode),
iminor(bio->bi_bdev->bd_inode),
(unsigned long long)bio->bi_sector);
- } else {
- SetPageUptodate(page);
+ goto out;
}
+
+ SetPageUptodate(page);
+
+ /*
+ * There is no guarantee that the page is in swap cache - the software
+ * suspend code (at least) uses end_swap_bio_read() against a non-
+ * swapcache page. So we must check PG_swapcache before proceeding with
+ * this optimization.
+ */
+ if (likely(PageSwapCache(page))) {
+ struct swap_info_struct *sis;
+
+ sis = page_swap_info(page);
+ if (sis->flags & SWP_BLKDEV) {
+ /*
+ * The swap subsystem performs lazy swap slot freeing,
+ * expecting that the page will be swapped out again.
+ * So we can avoid an unnecessary write if the page
+ * isn't redirtied.
+ * This is good for real swap storage because we can
+ * reduce unnecessary I/O and enhance wear-leveling
+ * if an SSD is used as the as swap device.
+ * But if in-memory swap device (eg zram) is used,
+ * this causes a duplicated copy between uncompressed
+ * data in VM-owned memory and compressed data in
+ * zram-owned memory. So let's free zram-owned memory
+ * and make the VM-owned decompressed page *dirty*,
+ * so the page should be swapped out somewhere again if
+ * we again wish to reclaim it.
+ */
+ struct gendisk *disk = sis->bdev->bd_disk;
+ if (disk->fops->swap_slot_free_notify) {
+ swp_entry_t entry;
+ unsigned long offset;
+
+ entry.val = page_private(page);
+ offset = swp_offset(entry);
+
+ SetPageDirty(page);
+ disk->fops->swap_slot_free_notify(sis->bdev,
+ offset);
+ }
+ }
+ }
+
+out:
unlock_page(page);
bio_put(bio);
}
diff --git a/mm/swap_state.c b/mm/swap_state.c
index 4c5ff7f..eb6a79c 100644
--- a/mm/swap_state.c
+++ b/mm/swap_state.c
@@ -58,7 +58,8 @@
printk("Swap cache stats: add %lu, delete %lu, find %lu/%lu\n",
swap_cache_info.add_total, swap_cache_info.del_total,
swap_cache_info.find_success, swap_cache_info.find_total);
- printk("Free swap = %ldkB\n", nr_swap_pages << (PAGE_SHIFT - 10));
+ printk("Free swap = %ldkB\n",
+ get_nr_swap_pages() << (PAGE_SHIFT - 10));
printk("Total swap = %lukB\n", total_swap_pages << (PAGE_SHIFT - 10));
}
diff --git a/mm/swapfile.c b/mm/swapfile.c
index fafc26d..9ae4c8d 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -31,6 +31,7 @@
#include <linux/memcontrol.h>
#include <linux/poll.h>
#include <linux/oom.h>
+#include <linux/export.h>
#include <asm/pgtable.h>
#include <asm/tlbflush.h>
@@ -44,9 +45,11 @@
static DEFINE_SPINLOCK(swap_lock);
static unsigned int nr_swapfiles;
-long nr_swap_pages;
+atomic_long_t nr_swap_pages;
+/* protected with swap_lock. reading in vm_swap_full() doesn't need lock */
long total_swap_pages;
static int least_priority;
+static atomic_t highest_priority_index = ATOMIC_INIT(-1);
static const char Bad_file[] = "Bad swap file entry ";
static const char Unused_file[] = "Unused swap file entry ";
@@ -220,7 +223,7 @@
si->lowest_alloc = si->max;
si->highest_alloc = 0;
}
- spin_unlock(&swap_lock);
+ spin_unlock(&si->lock);
/*
* If seek is expensive, start searching for new cluster from
@@ -239,7 +242,7 @@
if (si->swap_map[offset])
last_in_cluster = offset + SWAPFILE_CLUSTER;
else if (offset == last_in_cluster) {
- spin_lock(&swap_lock);
+ spin_lock(&si->lock);
offset -= SWAPFILE_CLUSTER - 1;
si->cluster_next = offset;
si->cluster_nr = SWAPFILE_CLUSTER - 1;
@@ -260,7 +263,7 @@
if (si->swap_map[offset])
last_in_cluster = offset + SWAPFILE_CLUSTER;
else if (offset == last_in_cluster) {
- spin_lock(&swap_lock);
+ spin_lock(&si->lock);
offset -= SWAPFILE_CLUSTER - 1;
si->cluster_next = offset;
si->cluster_nr = SWAPFILE_CLUSTER - 1;
@@ -274,7 +277,7 @@
}
offset = scan_base;
- spin_lock(&swap_lock);
+ spin_lock(&si->lock);
si->cluster_nr = SWAPFILE_CLUSTER - 1;
si->lowest_alloc = 0;
}
@@ -290,9 +293,9 @@
/* reuse swap entry of cache-only swap if not busy. */
if (vm_swap_full() && si->swap_map[offset] == SWAP_HAS_CACHE) {
int swap_was_freed;
- spin_unlock(&swap_lock);
+ spin_unlock(&si->lock);
swap_was_freed = __try_to_reclaim_swap(si, offset);
- spin_lock(&swap_lock);
+ spin_lock(&si->lock);
/* entry was freed successfully, try to use this again */
if (swap_was_freed)
goto checks;
@@ -332,13 +335,13 @@
si->lowest_alloc <= last_in_cluster)
last_in_cluster = si->lowest_alloc - 1;
si->flags |= SWP_DISCARDING;
- spin_unlock(&swap_lock);
+ spin_unlock(&si->lock);
if (offset < last_in_cluster)
discard_swap_cluster(si, offset,
last_in_cluster - offset + 1);
- spin_lock(&swap_lock);
+ spin_lock(&si->lock);
si->lowest_alloc = 0;
si->flags &= ~SWP_DISCARDING;
@@ -352,10 +355,10 @@
* could defer that delay until swap_writepage,
* but it's easier to keep this self-contained.
*/
- spin_unlock(&swap_lock);
+ spin_unlock(&si->lock);
wait_on_bit(&si->flags, ilog2(SWP_DISCARDING),
wait_for_discard, TASK_UNINTERRUPTIBLE);
- spin_lock(&swap_lock);
+ spin_lock(&si->lock);
} else {
/*
* Note pages allocated by racing tasks while
@@ -371,14 +374,14 @@
return offset;
scan:
- spin_unlock(&swap_lock);
+ spin_unlock(&si->lock);
while (++offset <= si->highest_bit) {
if (!si->swap_map[offset]) {
- spin_lock(&swap_lock);
+ spin_lock(&si->lock);
goto checks;
}
if (vm_swap_full() && si->swap_map[offset] == SWAP_HAS_CACHE) {
- spin_lock(&swap_lock);
+ spin_lock(&si->lock);
goto checks;
}
if (unlikely(--latency_ration < 0)) {
@@ -389,11 +392,11 @@
offset = si->lowest_bit;
while (++offset < scan_base) {
if (!si->swap_map[offset]) {
- spin_lock(&swap_lock);
+ spin_lock(&si->lock);
goto checks;
}
if (vm_swap_full() && si->swap_map[offset] == SWAP_HAS_CACHE) {
- spin_lock(&swap_lock);
+ spin_lock(&si->lock);
goto checks;
}
if (unlikely(--latency_ration < 0)) {
@@ -401,7 +404,7 @@
latency_ration = LATENCY_LIMIT;
}
}
- spin_lock(&swap_lock);
+ spin_lock(&si->lock);
no_page:
si->flags -= SWP_SCANNING;
@@ -414,13 +417,34 @@
pgoff_t offset;
int type, next;
int wrapped = 0;
+ int hp_index;
spin_lock(&swap_lock);
- if (nr_swap_pages <= 0)
+ if (atomic_long_read(&nr_swap_pages) <= 0)
goto noswap;
- nr_swap_pages--;
+ atomic_long_dec(&nr_swap_pages);
for (type = swap_list.next; type >= 0 && wrapped < 2; type = next) {
+ hp_index = atomic_xchg(&highest_priority_index, -1);
+ /*
+ * highest_priority_index records current highest priority swap
+ * type which just frees swap entries. If its priority is
+ * higher than that of swap_list.next swap type, we use it. It
+ * isn't protected by swap_lock, so it can be an invalid value
+ * if the corresponding swap type is swapoff. We double check
+ * the flags here. It's even possible the swap type is swapoff
+ * and swapon again and its priority is changed. In such rare
+ * case, low prority swap type might be used, but eventually
+ * high priority swap will be used after several rounds of
+ * swap.
+ */
+ if (hp_index != -1 && hp_index != type &&
+ swap_info[type]->prio < swap_info[hp_index]->prio &&
+ (swap_info[hp_index]->flags & SWP_WRITEOK)) {
+ type = hp_index;
+ swap_list.next = type;
+ }
+
si = swap_info[type];
next = si->next;
if (next < 0 ||
@@ -429,22 +453,29 @@
wrapped++;
}
- if (!si->highest_bit)
+ spin_lock(&si->lock);
+ if (!si->highest_bit) {
+ spin_unlock(&si->lock);
continue;
- if (!(si->flags & SWP_WRITEOK))
+ }
+ if (!(si->flags & SWP_WRITEOK)) {
+ spin_unlock(&si->lock);
continue;
+ }
swap_list.next = next;
+
+ spin_unlock(&swap_lock);
/* This is called for allocating swap entry for cache */
offset = scan_swap_map(si, SWAP_HAS_CACHE);
- if (offset) {
- spin_unlock(&swap_lock);
+ spin_unlock(&si->lock);
+ if (offset)
return swp_entry(type, offset);
- }
+ spin_lock(&swap_lock);
next = swap_list.next;
}
- nr_swap_pages++;
+ atomic_long_inc(&nr_swap_pages);
noswap:
spin_unlock(&swap_lock);
return (swp_entry_t) {0};
@@ -456,19 +487,19 @@
struct swap_info_struct *si;
pgoff_t offset;
- spin_lock(&swap_lock);
si = swap_info[type];
+ spin_lock(&si->lock);
if (si && (si->flags & SWP_WRITEOK)) {
- nr_swap_pages--;
+ atomic_long_dec(&nr_swap_pages);
/* This is called for allocating swap entry, not cache */
offset = scan_swap_map(si, 1);
if (offset) {
- spin_unlock(&swap_lock);
+ spin_unlock(&si->lock);
return swp_entry(type, offset);
}
- nr_swap_pages++;
+ atomic_long_inc(&nr_swap_pages);
}
- spin_unlock(&swap_lock);
+ spin_unlock(&si->lock);
return (swp_entry_t) {0};
}
@@ -490,7 +521,7 @@
goto bad_offset;
if (!p->swap_map[offset])
goto bad_free;
- spin_lock(&swap_lock);
+ spin_lock(&p->lock);
return p;
bad_free:
@@ -508,6 +539,27 @@
return NULL;
}
+/*
+ * This swap type frees swap entry, check if it is the highest priority swap
+ * type which just frees swap entry. get_swap_page() uses
+ * highest_priority_index to search highest priority swap type. The
+ * swap_info_struct.lock can't protect us if there are multiple swap types
+ * active, so we use atomic_cmpxchg.
+ */
+static void set_highest_priority_index(int type)
+{
+ int old_hp_index, new_hp_index;
+
+ do {
+ old_hp_index = atomic_read(&highest_priority_index);
+ if (old_hp_index != -1 &&
+ swap_info[old_hp_index]->prio >= swap_info[type]->prio)
+ break;
+ new_hp_index = type;
+ } while (atomic_cmpxchg(&highest_priority_index,
+ old_hp_index, new_hp_index) != old_hp_index);
+}
+
static unsigned char swap_entry_free(struct swap_info_struct *p,
swp_entry_t entry, unsigned char usage)
{
@@ -551,10 +603,8 @@
p->lowest_bit = offset;
if (offset > p->highest_bit)
p->highest_bit = offset;
- if (swap_list.next >= 0 &&
- p->prio > swap_info[swap_list.next]->prio)
- swap_list.next = p->type;
- nr_swap_pages++;
+ set_highest_priority_index(p->type);
+ atomic_long_inc(&nr_swap_pages);
p->inuse_pages--;
if ((p->flags & SWP_BLKDEV) &&
disk->fops->swap_slot_free_notify)
@@ -575,7 +625,7 @@
p = swap_info_get(entry);
if (p) {
swap_entry_free(p, entry, 1);
- spin_unlock(&swap_lock);
+ spin_unlock(&p->lock);
}
}
@@ -592,7 +642,7 @@
count = swap_entry_free(p, entry, SWAP_HAS_CACHE);
if (page)
mem_cgroup_uncharge_swapcache(page, entry, count != 0);
- spin_unlock(&swap_lock);
+ spin_unlock(&p->lock);
}
}
@@ -601,7 +651,7 @@
* This does not give an exact answer when swap count is continued,
* but does include the high COUNT_CONTINUED flag to allow for that.
*/
-static inline int page_swapcount(struct page *page)
+int page_swapcount(struct page *page)
{
int count = 0;
struct swap_info_struct *p;
@@ -611,7 +661,7 @@
p = swap_info_get(entry);
if (p) {
count = swap_count(p->swap_map[swp_offset(entry)]);
- spin_unlock(&swap_lock);
+ spin_unlock(&p->lock);
}
return count;
}
@@ -699,7 +749,7 @@
page = NULL;
}
}
- spin_unlock(&swap_lock);
+ spin_unlock(&p->lock);
}
if (page) {
/*
@@ -828,11 +878,13 @@
if ((unsigned int)type < nr_swapfiles) {
struct swap_info_struct *sis = swap_info[type];
+ spin_lock(&sis->lock);
if (sis->flags & SWP_WRITEOK) {
n = sis->pages;
if (free)
n -= sis->inuse_pages;
}
+ spin_unlock(&sis->lock);
}
spin_unlock(&swap_lock);
return n;
@@ -1528,7 +1580,7 @@
p->prio = --least_priority;
p->swap_map = swap_map;
p->flags |= SWP_WRITEOK;
- nr_swap_pages += p->pages;
+ atomic_long_add(p->pages, &nr_swap_pages);
total_swap_pages += p->pages;
/* insert swap space into swap_list: */
@@ -1605,14 +1657,16 @@
/* just pick something that's safe... */
swap_list.next = swap_list.head;
}
+ spin_lock(&p->lock);
if (p->prio < 0) {
for (i = p->next; i >= 0; i = swap_info[i]->next)
swap_info[i]->prio = p->prio--;
least_priority++;
}
- nr_swap_pages -= p->pages;
+ atomic_long_sub(p->pages, &nr_swap_pages);
total_swap_pages -= p->pages;
p->flags &= ~SWP_WRITEOK;
+ spin_unlock(&p->lock);
spin_unlock(&swap_lock);
oom_score_adj = test_set_oom_score_adj(OOM_SCORE_ADJ_MAX);
@@ -1637,14 +1691,17 @@
mutex_lock(&swapon_mutex);
spin_lock(&swap_lock);
+ spin_lock(&p->lock);
drain_mmlist();
/* wait for anyone still in scan_swap_map */
p->highest_bit = 0; /* cuts scans short */
while (p->flags >= SWP_SCANNING) {
+ spin_unlock(&p->lock);
spin_unlock(&swap_lock);
schedule_timeout_uninterruptible(1);
spin_lock(&swap_lock);
+ spin_lock(&p->lock);
}
swap_file = p->swap_file;
@@ -1653,6 +1710,7 @@
swap_map = p->swap_map;
p->swap_map = NULL;
p->flags = 0;
+ spin_unlock(&p->lock);
spin_unlock(&swap_lock);
mutex_unlock(&swapon_mutex);
vfree(swap_map);
@@ -1856,6 +1914,7 @@
p->flags = SWP_USED;
p->next = -1;
spin_unlock(&swap_lock);
+ spin_lock_init(&p->lock);
return p;
}
@@ -2177,7 +2236,7 @@
if ((si->flags & SWP_USED) && !(si->flags & SWP_WRITEOK))
nr_to_be_unused += si->inuse_pages;
}
- val->freeswap = nr_swap_pages + nr_to_be_unused;
+ val->freeswap = atomic_long_read(&nr_swap_pages) + nr_to_be_unused;
val->totalswap = total_swap_pages + nr_to_be_unused;
spin_unlock(&swap_lock);
}
@@ -2210,7 +2269,7 @@
p = swap_info[type];
offset = swp_offset(entry);
- spin_lock(&swap_lock);
+ spin_lock(&p->lock);
if (unlikely(offset >= p->max))
goto unlock_out;
@@ -2245,7 +2304,7 @@
p->swap_map[offset] = count | has_cache;
unlock_out:
- spin_unlock(&swap_lock);
+ spin_unlock(&p->lock);
out:
return err;
@@ -2292,6 +2351,31 @@
return __swap_duplicate(entry, SWAP_HAS_CACHE);
}
+struct swap_info_struct *page_swap_info(struct page *page)
+{
+ swp_entry_t swap = { .val = page_private(page) };
+ BUG_ON(!PageSwapCache(page));
+ return swap_info[swp_type(swap)];
+}
+
+/*
+ * out-of-line __page_file_ methods to avoid include hell.
+ */
+struct address_space *__page_file_mapping(struct page *page)
+{
+ VM_BUG_ON(!PageSwapCache(page));
+ return page_swap_info(page)->swap_file->f_mapping;
+}
+EXPORT_SYMBOL_GPL(__page_file_mapping);
+
+pgoff_t __page_file_index(struct page *page)
+{
+ swp_entry_t swap = { .val = page_private(page) };
+ VM_BUG_ON(!PageSwapCache(page));
+ return swp_offset(swap);
+}
+EXPORT_SYMBOL_GPL(__page_file_index);
+
/*
* add_swap_count_continuation - called when a swap count is duplicated
* beyond SWAP_MAP_MAX, it allocates a new page and links that to the entry's
@@ -2345,7 +2429,7 @@
}
if (!page) {
- spin_unlock(&swap_lock);
+ spin_unlock(&si->lock);
return -ENOMEM;
}
@@ -2393,7 +2477,7 @@
list_add_tail(&page->lru, &head->lru);
page = NULL; /* now it's attached, don't free it */
out:
- spin_unlock(&swap_lock);
+ spin_unlock(&si->lock);
outer:
if (page)
__free_page(page);
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index e174693..2e074aa 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -184,36 +184,6 @@
return ret;
}
-#ifdef ENABLE_VMALLOC_SAVING
-int is_vmalloc_addr(const void *x)
-{
- struct rb_node *n;
- struct vmap_area *va;
- int ret = 0;
-
- spin_lock(&vmap_area_lock);
-
- for (n = rb_first(vmap_area_root); n; rb_next(n)) {
- va = rb_entry(n, struct vmap_area, rb_node);
- if (x >= va->va_start && x < va->va_end) {
- ret = 1;
- break;
- }
- }
-
- spin_unlock(&vmap_area_lock);
- return ret;
-}
-#else
-int is_vmalloc_addr(const void *x)
-{
- unsigned long addr = (unsigned long)x;
-
- return addr >= VMALLOC_START && addr < VMALLOC_END;
-}
-#endif
-EXPORT_SYMBOL(is_vmalloc_addr);
-
int is_vmalloc_or_module_addr(const void *x)
{
/*
@@ -302,6 +272,47 @@
static unsigned long vmap_area_pcpu_hole;
+#ifdef CONFIG_ENABLE_VMALLOC_SAVING
+#define POSSIBLE_VMALLOC_START PAGE_OFFSET
+
+#define VMALLOC_BITMAP_SIZE ((VMALLOC_END - PAGE_OFFSET) >> \
+ PAGE_SHIFT)
+#define VMALLOC_TO_BIT(addr) ((addr - PAGE_OFFSET) >> PAGE_SHIFT)
+#define BIT_TO_VMALLOC(i) (PAGE_OFFSET + i * PAGE_SIZE)
+
+DECLARE_BITMAP(possible_areas, VMALLOC_BITMAP_SIZE);
+
+void mark_vmalloc_reserved_area(void *x, unsigned long size)
+{
+ unsigned long addr = (unsigned long)x;
+
+ bitmap_set(possible_areas, VMALLOC_TO_BIT(addr), size >> PAGE_SHIFT);
+}
+
+int is_vmalloc_addr(const void *x)
+{
+ unsigned long addr = (unsigned long)x;
+
+ if (addr < POSSIBLE_VMALLOC_START || addr >= VMALLOC_END)
+ return 0;
+
+ if (test_bit(VMALLOC_TO_BIT(addr), possible_areas))
+ return 0;
+
+ return 1;
+}
+#else
+int is_vmalloc_addr(const void *x)
+{
+ unsigned long addr = (unsigned long)x;
+
+ return addr >= VMALLOC_START && addr < VMALLOC_END;
+}
+#endif
+EXPORT_SYMBOL(is_vmalloc_addr);
+
+
+
static struct vmap_area *__find_vmap_area(unsigned long addr)
{
struct rb_node *n = vmap_area_root.rb_node;
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 1438de9..d0e40e5 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -158,8 +158,28 @@
return &mz->zone->reclaim_stat;
}
+unsigned long zone_reclaimable_pages(struct zone *zone)
+{
+ int nr;
+
+ nr = zone_page_state(zone, NR_ACTIVE_FILE) +
+ zone_page_state(zone, NR_INACTIVE_FILE);
+
+ if (get_nr_swap_pages() > 0)
+ nr += zone_page_state(zone, NR_ACTIVE_ANON) +
+ zone_page_state(zone, NR_INACTIVE_ANON);
+
+ return nr;
+}
+
+bool zone_reclaimable(struct zone *zone)
+{
+ return zone->pages_scanned < zone_reclaimable_pages(zone) * 6;
+}
+
static unsigned long zone_nr_lru_pages(struct mem_cgroup_zone *mz,
enum lru_list lru)
+
{
if (!mem_cgroup_disabled())
return mem_cgroup_zone_nr_lru_pages(mz->mem_cgroup,
@@ -454,6 +474,8 @@
if (!PageWriteback(page)) {
/* synchronous write or broken a_ops? */
ClearPageReclaim(page);
+ if (PageError(page))
+ return PAGE_ACTIVATE;
}
trace_mm_vmscan_writepage(page, trace_reclaim_flags(page));
inc_zone_page_state(page, NR_VMSCAN_WRITE);
@@ -1648,13 +1670,13 @@
* latencies, so it's better to scan a minimum amount there as
* well.
*/
- if (current_is_kswapd() && mz->zone->all_unreclaimable)
+ if (current_is_kswapd() && !zone_reclaimable(mz->zone))
force_scan = true;
if (!global_reclaim(sc))
force_scan = true;
/* If we have no swap space, do not bother scanning anon pages. */
- if (!sc->may_swap || (nr_swap_pages <= 0)) {
+ if (!sc->may_swap || (get_nr_swap_pages() <= 0)) {
noswap = 1;
fraction[0] = 0;
fraction[1] = 1;
@@ -1798,7 +1820,7 @@
*/
pages_for_compaction = (2UL << sc->order);
inactive_lru_pages = zone_nr_lru_pages(mz, LRU_INACTIVE_FILE);
- if (nr_swap_pages > 0)
+ if (get_nr_swap_pages() > 0)
inactive_lru_pages += zone_nr_lru_pages(mz, LRU_INACTIVE_ANON);
if (sc->nr_reclaimed < pages_for_compaction &&
inactive_lru_pages > pages_for_compaction)
@@ -1995,8 +2017,8 @@
if (global_reclaim(sc)) {
if (!cpuset_zone_allowed_hardwall(zone, GFP_KERNEL))
continue;
- if (zone->all_unreclaimable &&
- sc->priority != DEF_PRIORITY)
+ if (sc->priority != DEF_PRIORITY &&
+ !zone_reclaimable(zone))
continue; /* Let kswapd poll it */
if (COMPACTION_BUILD) {
/*
@@ -2034,11 +2056,6 @@
return aborted_reclaim;
}
-static bool zone_reclaimable(struct zone *zone)
-{
- return zone->pages_scanned < zone_reclaimable_pages(zone) * 6;
-}
-
/* All zones in zonelist are unreclaimable? */
static bool all_unreclaimable(struct zonelist *zonelist,
struct scan_control *sc)
@@ -2052,7 +2069,7 @@
continue;
if (!cpuset_zone_allowed_hardwall(zone, GFP_KERNEL))
continue;
- if (!zone->all_unreclaimable)
+ if (zone_reclaimable(zone))
return false;
}
@@ -2377,7 +2394,7 @@
* they must be considered balanced here as well if kswapd
* is to sleep
*/
- if (zone->all_unreclaimable) {
+ if (!zone_reclaimable(zone)) {
balanced += zone->present_pages;
continue;
}
@@ -2470,8 +2487,8 @@
if (!populated_zone(zone))
continue;
- if (zone->all_unreclaimable &&
- sc.priority != DEF_PRIORITY)
+ if (sc.priority != DEF_PRIORITY &&
+ !zone_reclaimable(zone))
continue;
/*
@@ -2525,8 +2542,8 @@
if (!populated_zone(zone))
continue;
- if (zone->all_unreclaimable &&
- sc.priority != DEF_PRIORITY)
+ if (sc.priority != DEF_PRIORITY &&
+ !zone_reclaimable(zone))
continue;
sc.nr_scanned = 0;
@@ -2576,8 +2593,6 @@
sc.nr_reclaimed += reclaim_state->reclaimed_slab;
total_scanned += sc.nr_scanned;
- if (nr_slab == 0 && !zone_reclaimable(zone))
- zone->all_unreclaimable = 1;
}
/*
@@ -2589,7 +2604,7 @@
total_scanned > sc.nr_reclaimed + sc.nr_reclaimed / 2)
sc.may_writepage = 1;
- if (zone->all_unreclaimable) {
+ if (!zone_reclaimable(zone)) {
if (end_zone && end_zone == i)
end_zone--;
continue;
@@ -2912,27 +2927,13 @@
nr = global_page_state(NR_ACTIVE_FILE) +
global_page_state(NR_INACTIVE_FILE);
- if (nr_swap_pages > 0)
+ if (get_nr_swap_pages() > 0)
nr += global_page_state(NR_ACTIVE_ANON) +
global_page_state(NR_INACTIVE_ANON);
return nr;
}
-unsigned long zone_reclaimable_pages(struct zone *zone)
-{
- int nr;
-
- nr = zone_page_state(zone, NR_ACTIVE_FILE) +
- zone_page_state(zone, NR_INACTIVE_FILE);
-
- if (nr_swap_pages > 0)
- nr += zone_page_state(zone, NR_ACTIVE_ANON) +
- zone_page_state(zone, NR_INACTIVE_ANON);
-
- return nr;
-}
-
#ifdef CONFIG_HIBERNATION
/*
* Try to free `nr_to_reclaim' of memory, system-wide, and return the number of
@@ -3227,7 +3228,7 @@
zone_page_state(zone, NR_SLAB_RECLAIMABLE) <= zone->min_slab_pages)
return ZONE_RECLAIM_FULL;
- if (zone->all_unreclaimable)
+ if (!zone_reclaimable(zone))
return ZONE_RECLAIM_FULL;
/*
diff --git a/mm/vmstat.c b/mm/vmstat.c
index 959a558..9559032 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -19,6 +19,9 @@
#include <linux/math64.h>
#include <linux/writeback.h>
#include <linux/compaction.h>
+#include <linux/mm_inline.h>
+
+#include "internal.h"
#ifdef CONFIG_VM_EVENT_COUNTERS
DEFINE_PER_CPU(struct vm_event_state, vm_event_states) = {{0}};
@@ -1027,7 +1030,7 @@
"\n all_unreclaimable: %u"
"\n start_pfn: %lu"
"\n inactive_ratio: %u",
- zone->all_unreclaimable,
+ !zone_reclaimable(zone),
zone->zone_start_pfn,
zone->inactive_ratio);
seq_putc(m, '\n');
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 9962c88..6c78c0c 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1457,7 +1457,7 @@
head = p; id++;
}
- sprintf(hdev->name, "hci%d", id);
+ snprintf(hdev->name, sizeof(hdev->name), "hci%d", id);
hdev->id = id;
list_add(&hdev->list, head);
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index e598400..04cfc69 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -191,7 +191,7 @@
size = SKB_DATA_ALIGN(size);
size += SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
data = kmalloc_node_track_caller(size, gfp_mask, node);
- if (!data)
+ if (unlikely(ZERO_OR_NULL_PTR(data)))
goto nodata;
/* kmalloc(size) might give us more room than requested.
* Put skb_shared_info exactly at the end of allocated zone,
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index fd7a3f6..cfaaf13 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -271,6 +271,11 @@
local_bh_disable();
addend = xt_write_recseq_begin();
private = table->private;
+ /*
+ * Ensure we load private-> members after we've fetched the base
+ * pointer.
+ */
+ smp_read_barrier_depends();
table_base = private->entries[smp_processor_id()];
e = get_entry(table_base, private->hook_entry[hook]);
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 24e556e..ed1468a 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -327,6 +327,11 @@
addend = xt_write_recseq_begin();
private = table->private;
cpu = smp_processor_id();
+ /*
+ * Ensure we load private-> members after we've fetched the base
+ * pointer.
+ */
+ smp_read_barrier_depends();
table_base = private->entries[cpu];
jumpstack = (struct ipt_entry **)private->jumpstack[cpu];
stackptr = per_cpu_ptr(private->stackptr, cpu);
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index b2b0e99..74a286c 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -485,14 +485,12 @@
!tp->urg_data ||
before(tp->urg_seq, tp->copied_seq) ||
!before(tp->urg_seq, tp->rcv_nxt)) {
- struct sk_buff *skb;
answ = tp->rcv_nxt - tp->copied_seq;
- /* Subtract 1, if FIN is in queue. */
- skb = skb_peek_tail(&sk->sk_receive_queue);
- if (answ && skb)
- answ -= tcp_hdr(skb)->fin;
+ /* Subtract 1, if FIN was received */
+ if (answ && sock_flag(sk, SOCK_DONE))
+ answ--;
} else
answ = tp->urg_seq - tp->copied_seq;
release_sock(sk);
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index e641f8f..c30a20c 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -349,6 +349,11 @@
local_bh_disable();
addend = xt_write_recseq_begin();
private = table->private;
+ /*
+ * Ensure we load private-> members after we've fetched the base
+ * pointer.
+ */
+ smp_read_barrier_depends();
cpu = smp_processor_id();
table_base = private->entries[cpu];
jumpstack = (struct ip6t_entry **)private->jumpstack[cpu];
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index 8d987c3..5888e00 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -832,8 +832,13 @@
return NULL;
}
- table->private = newinfo;
newinfo->initial_entries = private->initial_entries;
+ /*
+ * Ensure contents of newinfo are visible before assigning to
+ * private.
+ */
+ smp_wmb();
+ table->private = newinfo;
/*
* Even though table entries have now been swapped, other CPU's
diff --git a/net/wireless/db.txt b/net/wireless/db.txt
index c5861b8..b1efe57 100644
--- a/net/wireless/db.txt
+++ b/net/wireless/db.txt
@@ -6,24 +6,34 @@
# Channel 14. Only JP enables this and for 802.11b only
(2474 - 2494 @ 20), (3, 20), PASSIVE-SCAN, NO-IBSS, NO-OFDM
# Channel 36 - 48
- (5170 - 5250 @ 40), (3, 20), PASSIVE-SCAN, NO-IBSS
+ (5170 - 5250 @ 80), (3, 20), PASSIVE-SCAN, NO-IBSS
# NB: 5260 MHz - 5700 MHz requies DFS
# Channel 149 - 165
- (5735 - 5835 @ 40), (3, 20), PASSIVE-SCAN, NO-IBSS
+ (5735 - 5835 @ 80), (3, 20), PASSIVE-SCAN, NO-IBSS
+ # IEEE 802.11ad (60GHz), channels 1..3
+ (57240 - 63720 @ 2160), (N/A, 0)
country AD:
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country AE:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (3, 17)
+ (5250 - 5330 @ 80), (3, 24), DFS
+ (5490 - 5710 @ 80), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
country AL:
- (2402 - 2482 @ 20), (N/A, 20)
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5150 - 5250 @ 80), (N/A, 20)
+ (5250 - 5350 @ 80), (N/A, 20), DFS
+ (5470 - 5725 @ 80), (N/A, 27), DFS
country AM:
(2402 - 2482 @ 40), (N/A, 20)
@@ -32,30 +42,38 @@
country AN:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
country AR:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (3, 17)
- (5250 - 5330 @ 40), (3, 20), DFS
- (5490 - 5710 @ 40), (3, 20), DFS
- (5735 - 5835 @ 40), (3, 30)
+ (5170 - 5250 @ 80), (3, 17)
+ (5250 - 5330 @ 80), (3, 24), DFS
+ (5490 - 5710 @ 80), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
+
+country AS:
+ (2402 - 2472 @ 40), (N/A, 30)
+ (5150 - 5250 @ 80), (6, 17)
+ (5250 - 5350 @ 80), (6, 24), DFS
+ (5470 - 5725 @ 80), (6, 24), DFS
+ (5725 - 5850 @ 80), (6, 30)
country AT: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country AU:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (3, 23)
- (5250 - 5330 @ 40), (3, 23), DFS
- (5735 - 5835 @ 40), (3, 30)
+ (5170 - 5250 @ 80), (3, 17)
+ (5250 - 5330 @ 80), (3, 24), DFS
+ (5490 - 5710 @ 80), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
country AW:
(2402 - 2482 @ 40), (N/A, 20)
@@ -65,39 +83,40 @@
country AZ:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 18)
- (5250 - 5330 @ 40), (N/A, 18), DFS
+ (5170 - 5250 @ 80), (N/A, 18)
+ (5250 - 5330 @ 80), (N/A, 18), DFS
country BA: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country BB:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (3, 23)
- (5250 - 5330 @ 40), (3, 23), DFS
- (5735 - 5835 @ 40), (3, 30)
+ (5170 - 5250 @ 80), (3, 23)
+ (5250 - 5330 @ 80), (3, 23), DFS
+ (5735 - 5835 @ 80), (3, 30)
country BD:
(2402 - 2482 @ 40), (N/A, 20)
+ (5725 - 5850 @ 80), (N/A, 30)
country BE: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country BG: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 23)
- (5250 - 5290 @ 40), (N/A, 23), DFS
- (5490 - 5710 @ 40), (N/A, 30), DFS
+ (5170 - 5250 @ 80), (N/A, 23)
+ (5250 - 5290 @ 80), (N/A, 23), DFS
+ (5490 - 5710 @ 80), (N/A, 30), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
@@ -112,57 +131,74 @@
(5170 - 5250 @ 40), (N/A, 18)
(5250 - 5330 @ 40), (N/A, 18), DFS
+country BM:
+ (2402 - 2472 @ 40), (N/A, 30)
+ (5150 - 5250 @ 80), (6, 17)
+ (5250 - 5350 @ 80), (6, 24), DFS
+ (5470 - 5725 @ 80), (6, 24), DFS
+ (5725 - 5850 @ 80), (6, 30)
+
country BN:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5735 - 5835 @ 40), (N/A, 30)
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5735 - 5835 @ 80), (N/A, 30)
country BO:
(2402 - 2482 @ 40), (N/A, 30)
- (5735 - 5835 @ 40), (N/A, 30)
+ (5735 - 5835 @ 80), (N/A, 30)
country BR:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (3, 17)
- (5250 - 5330 @ 40), (3, 20), DFS
- (5490 - 5710 @ 40), (3, 20), DFS
- (5735 - 5835 @ 40), (3, 30)
+ (5170 - 5250 @ 80), (3, 17)
+ (5250 - 5330 @ 80), (3, 24), DFS
+ (5490 - 5710 @ 80), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
+
+country BS:
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5150 - 5250 @ 80), (6, 17)
+ (5250 - 5350 @ 80), (6, 24), DFS
+ (5470 - 5725 @ 80), (6, 24), DFS
+ (5725 - 5850 @ 80), (6, 30)
country BY:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
country BZ:
(2402 - 2482 @ 40), (N/A, 30)
- (5735 - 5835 @ 40), (N/A, 30)
+ (5735 - 5835 @ 80), (N/A, 30)
country CA:
- (2402 - 2472 @ 40), (3, 27)
- (5170 - 5250 @ 40), (3, 17)
- (5250 - 5330 @ 40), (3, 20), DFS
- (5490 - 5710 @ 40), (3, 20), DFS
- (5735 - 5835 @ 40), (3, 30)
+ (2402 - 2472 @ 40), (N/A, 27)
+ (5170 - 5250 @ 80), (3, 17)
+ (5250 - 5330 @ 80), (3, 24), DFS
+ (5490 - 5710 @ 80), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
country CH: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country CL:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5735 - 5835 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5735 - 5835 @ 80), (N/A, 20)
country CN:
(2402 - 2482 @ 40), (N/A, 20)
- (5735 - 5835 @ 40), (N/A, 30)
+ (5150 - 5250 @ 80), (6, 23)
+ (5250 - 5350 @ 80), (6, 23), DFS
+ (5725 - 5850 @ 80), (6, 30)
+ (5735 - 5835 @ 80), (N/A, 30)
# 60 gHz band channels 1,4: 28dBm, channels 2,3: 44dBm
# ref: http://www.miit.gov.cn/n11293472/n11505629/n11506593/n11960250/n11960606/n11960700/n12330791.files/n12330790.pdf
(57240 - 59400 @ 2160), (N/A, 28)
@@ -170,28 +206,24 @@
(63720 - 65880 @ 2160), (N/A, 28)
country CO:
- (2402 - 2472 @ 40), (3, 27)
- (5170 - 5250 @ 40), (3, 17)
- (5250 - 5330 @ 40), (3, 23), DFS
- (5735 - 5835 @ 40), (3, 30)
+ (2402 - 2472 @ 40), (N/A, 27)
+ (5170 - 5250 @ 80), (3, 17)
+ (5250 - 5330 @ 80), (3, 24), DFS
+ (5490 - 5710 @ 80), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
country CR:
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 20), (3, 17)
- (5250 - 5330 @ 20), (3, 23), DFS
+ (5250 - 5330 @ 20), (3, 24), DFS
+ (5490 - 5710 @ 20), (3, 24), DFS
(5735 - 5835 @ 20), (3, 30)
-country CS:
- (2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
-
country CY: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
@@ -201,9 +233,9 @@
# implemented.
country CZ: DFS-ETSI
(2400 - 2483.5 @ 40), (N/A, 100 mW)
- (5150 - 5250 @ 40), (N/A, 200 mW), NO-OUTDOOR
- (5250 - 5350 @ 40), (N/A, 100 mW), NO-OUTDOOR, DFS
- (5470 - 5725 @ 40), (N/A, 500 mW), DFS
+ (5150 - 5250 @ 80), (N/A, 200 mW), NO-OUTDOOR
+ (5250 - 5350 @ 80), (N/A, 100 mW), NO-OUTDOOR, DFS
+ (5470 - 5725 @ 80), (N/A, 500 mW), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
@@ -223,27 +255,27 @@
# entries 279004 and 280006
(2400 - 2483.5 @ 40), (N/A, 100 mW)
# entry 303005
- (5150 - 5250 @ 40), (N/A, 100 mW), NO-OUTDOOR
+ (5150 - 5250 @ 80), (N/A, 100 mW), NO-OUTDOOR
# entries 304002 and 305002
- (5250 - 5350 @ 40), (N/A, 100 mW), NO-OUTDOOR, DFS
+ (5250 - 5350 @ 80), (N/A, 100 mW), NO-OUTDOOR, DFS
# entries 308002, 309001 and 310003
- (5470 - 5725 @ 40), (N/A, 500 mW), DFS
+ (5470 - 5725 @ 80), (N/A, 500 mW), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country DK: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country DO:
- (2402 - 2472 @ 40), (3, 27)
- (5170 - 5250 @ 40), (3, 17)
- (5250 - 5330 @ 40), (3, 23), DFS
- (5735 - 5835 @ 40), (3, 30)
+ (2402 - 2472 @ 40), (N/A, 27)
+ (5170 - 5250 @ 80), (3, 17)
+ (5250 - 5330 @ 80), (3, 23), DFS
+ (5735 - 5835 @ 80), (3, 30)
country DZ:
(2402 - 2482 @ 40), (N/A, 20)
@@ -251,14 +283,15 @@
country EC:
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 20), (3, 17)
- (5250 - 5330 @ 20), (3, 23), DFS
+ (5250 - 5330 @ 20), (3, 24), DFS
+ (5490 - 5710 @ 20), (3, 24), DFS
(5735 - 5835 @ 20), (3, 30)
country EE: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
@@ -269,55 +302,67 @@
country ES: DFS-ETSI
(2400 - 2483.5 @ 40), (N/A, 100 mW)
- (5150 - 5250 @ 40), (N/A, 100 mW), NO-OUTDOOR
- (5250 - 5350 @ 40), (N/A, 100 mW), NO-OUTDOOR, DFS
- (5470 - 5725 @ 40), (N/A, 500 mW), DFS
+ (5150 - 5250 @ 80), (N/A, 100 mW), NO-OUTDOOR
+ (5250 - 5350 @ 80), (N/A, 100 mW), NO-OUTDOOR, DFS
+ (5470 - 5725 @ 80), (N/A, 500 mW), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country FI: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country FR: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+country GF:
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5150 - 5250 @ 80), (N/A, 20)
+ (5250 - 5350 @ 80), (N/A, 20), DFS
+ (5470 - 5725 @ 80), (N/A, 20), DFS
+
country GE:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 18)
- (5250 - 5330 @ 40), (N/A, 18), DFS
+ (5170 - 5250 @ 80), (N/A, 18)
+ (5250 - 5330 @ 80), (N/A, 18), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country GB: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country GD:
- (2402 - 2472 @ 40), (3, 27)
- (5170 - 5250 @ 40), (3, 17)
- (5250 - 5330 @ 40), (3, 20), DFS
- (5490 - 5710 @ 40), (3, 20), DFS
- (5735 - 5835 @ 40), (3, 30)
+ (2402 - 2472 @ 40), (3, 30)
+ (5170 - 5250 @ 80), (6, 17)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5710 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
+
+country GP:
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5150 - 5250 @ 80), (N/A, 20)
+ (5250 - 5350 @ 80), (N/A, 20), DFS
+ (5470 - 5725 @ 80), (N/A, 27), DFS
country GR: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
@@ -328,156 +373,165 @@
(5490 - 5710 @ 20), (N/A, 27), DFS
country GT:
- (2402 - 2472 @ 40), (3, 27)
- (5170 - 5250 @ 40), (3, 17)
- (5250 - 5330 @ 40), (3, 23), DFS
- (5735 - 5835 @ 40), (3, 30)
+ (2402 - 2472 @ 40), (3, 30)
+ (5170 - 5250 @ 80), (6, 17)
+ (5250 - 5330 @ 80), (6, 23), DFS
+ (5735 - 5835 @ 80), (6, 30)
country GU:
- (2402 - 2472 @ 40), (3, 27)
- (5170 - 5250 @ 20), (3, 17)
- (5250 - 5330 @ 20), (3, 23), DFS
- (5735 - 5835 @ 20), (3, 30)
+ (2402 - 2472 @ 40), (3, 30)
+ (5170 - 5250 @ 20), (6, 17)
+ (5250 - 5330 @ 20), (6, 24), DFS
+ (5490 - 5710 @ 20), (6, 24), DFS
+ (5735 - 5835 @ 20), (6, 30)
country HN:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (3, 17)
- (5250 - 5330 @ 40), (3, 20), DFS
- (5490 - 5710 @ 40), (3, 20), DFS
- (5735 - 5835 @ 40), (3, 30)
+ (5170 - 5250 @ 80), (6, 17)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5710 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
country HK:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (3, 17)
- (5250 - 5330 @ 40), (3, 20), DFS
- (5490 - 5710 @ 40), (3, 20), DFS
- (5735 - 5835 @ 40), (3, 30)
+ (5170 - 5250 @ 80), (6, 17)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5710 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
country HR: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country HT:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
country HU: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country ID:
+ # ref: http://www.postel.go.id/content/ID/regulasi/standardisasi/kepdir/bwa%205,8%20ghz.pdf
(2402 - 2482 @ 40), (N/A, 20)
+ (5735 - 5815 @ 20), (N/A, 23)
country IE: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country IL:
(2402 - 2482 @ 40), (N/A, 20)
- (5150 - 5250 @ 40), (N/A, 200 mW), NO-OUTDOOR
- (5250 - 5350 @ 40), (N/A, 200 mW), NO-OUTDOOR, DFS
+ (5150 - 5250 @ 80), (N/A, 200 mW), NO-OUTDOOR
+ (5250 - 5350 @ 80), (N/A, 200 mW), NO-OUTDOOR, DFS
country IN:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5735 - 5835 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5735 - 5835 @ 80), (N/A, 20)
country IS: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country IR:
(2402 - 2482 @ 40), (N/A, 20)
- (5735 - 5835 @ 40), (N/A, 30)
+ (5735 - 5835 @ 80), (N/A, 30)
country IT: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country JM:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (3, 17)
- (5250 - 5330 @ 40), (3, 20), DFS
- (5490 - 5710 @ 40), (3, 20), DFS
- (5735 - 5835 @ 40), (3, 30)
+ (5170 - 5250 @ 80), (6, 17)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5710 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
country JP:
(2402 - 2482 @ 40), (N/A, 20)
(2474 - 2494 @ 20), (N/A, 20), NO-OFDM
(4910 - 4990 @ 40), (N/A, 23)
(5030 - 5090 @ 40), (N/A, 23)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 23), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 160), (N/A, 23), DFS
country JO:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 18)
+ (5150 - 5250 @ 80), (N/A, 23)
+ (5725 - 5850 @ 80), (N/A, 23)
country KE:
(2402 - 2482 @ 40), (N/A, 20)
- (5735 - 5835 @ 40), (N/A, 30)
+ (5150 - 5250 @ 80), (N/A, 23)
+ (5470 - 5570 @ 80), (N/A, 30), DFS
+ (5725 - 5775 @ 80), (N/A, 23)
country KH:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
country KP:
- (2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5330 @ 40), (3, 20)
- (5160 - 5250 @ 40), (3, 20), DFS
- (5490 - 5630 @ 40), (3, 30), DFS
- (5735 - 5815 @ 40), (3, 30)
+ (2402 - 2482 @ 20), (N/A, 20)
+ (5170 - 5330 @ 20), (6, 20)
+ (5160 - 5250 @ 20), (6, 20), DFS
+ (5490 - 5630 @ 20), (6, 30), DFS
+ (5735 - 5815 @ 20), (6, 30)
country KR:
(2402 - 2482 @ 20), (N/A, 20)
- (5170 - 5250 @ 20), (3, 20)
- (5250 - 5330 @ 20), (3, 20), DFS
- (5490 - 5630 @ 20), (3, 30), DFS
- (5735 - 5815 @ 20), (3, 30)
+ (5150 - 5250 @ 80), (6, 20)
+ (5250 - 5350 @ 80), (6, 20), DFS
+ (5470 - 5725 @ 80), (6, 30), DFS
+ (5725 - 5825 @ 80), (6, 30)
country KW:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
country KZ:
(2402 - 2482 @ 40), (N/A, 20)
country LB:
(2402 - 2482 @ 40), (N/A, 20)
- (5735 - 5835 @ 40), (N/A, 30)
+ (5150 - 5250 @ 80), (6, 17)
+ (5250 - 5350 @ 80), (6, 24), DFS
+ (5470 - 5725 @ 80), (6, 24), DFS
+ (5725 - 5850 @ 80), (6, 30)
country LI: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
country LK:
(2402 - 2482 @ 40), (N/A, 20)
@@ -488,35 +542,38 @@
country LT: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country LU: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country LV: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country MC: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 18)
- (5250 - 5330 @ 40), (N/A, 18), DFS
+ (5150 - 5250 @ 80), (N/A, 20)
+ (5250 - 5350 @ 80), (N/A, 20), DFS
+ (5470 - 5725 @ 80), (N/A, 27), DFS
country MA:
(2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5735 - 5835 @ 80), (N/A, 20), DFS
country MO:
(2402 - 2482 @ 40), (N/A, 20)
@@ -524,6 +581,13 @@
(5250 - 5330 @ 40), (3, 23), DFS
(5735 - 5835 @ 40), (3, 30)
+country MP:
+ (2402 - 2472 @ 40), (N/A, 30)
+ (5150 - 5250 @ 80), (6, 17)
+ (5250 - 5350 @ 80), (6, 24), DFS
+ (5470 - 5725 @ 80), (6, 24), DFS
+ (5725 - 5850 @ 80), (6, 30)
+
country MK: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 40), (N/A, 20)
@@ -532,6 +596,13 @@
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+country MN:
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5150 - 5250 @ 80), (6, 17)
+ (5250 - 5350 @ 80), (6, 24), DFS
+ (5470 - 5725 @ 80), (6, 24), DFS
+ (5725 - 5850 @ 80), (6, 30)
+
country MT: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 40), (N/A, 20)
@@ -540,105 +611,167 @@
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+country MQ: DFS-ETSI
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5150 - 5250 @ 80), (N/A, 20)
+ (5250 - 5350 @ 80), (N/A, 20), DFS
+ (5470 - 5725 @ 80), (N/A, 27), DFS
+
+country MU:
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5150 - 5250 @ 80), (6, 17)
+ (5250 - 5350 @ 80), (6, 24), DFS
+ (5470 - 5725 @ 80), (6, 24), DFS
+ (5725 - 5850 @ 80), (6, 30)
+
country MY:
(2402 - 2482 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 30), DFS
- (5735 - 5835 @ 40), (N/A, 30)
+ (5170 - 5250 @ 80), (N/A, 17)
+ (5250 - 5330 @ 80), (N/A, 23), DFS
+ (5735 - 5835 @ 80), (N/A, 30)
country MX:
(2402 - 2472 @ 40), (3, 27)
- (5170 - 5250 @ 40), (3, 17)
- (5250 - 5330 @ 40), (3, 23), DFS
- (5735 - 5835 @ 40), (3, 30)
+ (5170 - 5250 @ 80), (3, 17)
+ (5250 - 5330 @ 80), (3, 24), DFS
+ (5490 - 5710 @ 80), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
+
+country MW:
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5150 - 5250 @ 80), (N/A, 20)
+ (5250 - 5350 @ 80), (N/A, 20), DFS
+ (5470 - 5725 @ 80), (N/A, 27), DFS
+
+country NG:
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5250 - 5350 @ 80), (N/A, 30), DFS
+ (5725 - 5850 @ 80), (N/A, 30)
+
+country NI:
+ (2402 - 2472 @ 40), (N/A, 30)
+ (5150 - 5250 @ 80), (6, 17)
+ (5250 - 5350 @ 80), (6, 24), DFS
+ (5470 - 5725 @ 80), (6, 24), DFS
+ (5725 - 5850 @ 80), (6, 30)
country NL: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20), NO-OUTDOOR
- (5250 - 5330 @ 40), (N/A, 20), NO-OUTDOOR, DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20), NO-OUTDOOR
+ (5250 - 5330 @ 80), (N/A, 20), NO-OUTDOOR, DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country NO: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country NP:
(2402 - 2482 @ 40), (N/A, 20)
- (5735 - 5835 @ 40), (N/A, 30)
+ (5150 - 5250 @ 80), (N/A, 20)
+ (5250 - 5350 @ 80), (N/A, 20), DFS
+ (5725 - 5850 @ 80), (N/A, 20)
country NZ:
(2402 - 2482 @ 40), (N/A, 30)
- (5170 - 5250 @ 20), (3, 23)
- (5250 - 5330 @ 20), (3, 23), DFS
- (5735 - 5835 @ 20), (3, 30)
+ (5170 - 5250 @ 80), (6, 17)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5710 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
country OM:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (3, 17)
- (5250 - 5330 @ 40), (3, 20), DFS
- (5490 - 5710 @ 40), (3, 20), DFS
- (5735 - 5835 @ 40), (3, 30)
+ (5150 - 5250 @ 80), (N/A, 20)
+ (5250 - 5350 @ 80), (N/A, 20), DFS
+ (5470 - 5725 @ 80), (N/A, 27), DFS
country PA:
- (2402 - 2472 @ 40), (3, 27)
- (5170 - 5250 @ 40), (3, 17)
- (5250 - 5330 @ 40), (3, 23), DFS
- (5735 - 5835 @ 40), (3, 30)
+ (2402 - 2472 @ 40), (N/A, 30)
+ (5170 - 5250 @ 80), (6, 17)
+ (5250 - 5330 @ 80), (6, 23), DFS
+ (5735 - 5835 @ 80), (6, 30)
country PE:
(2402 - 2482 @ 40), (N/A, 20)
- (5735 - 5835 @ 40), (N/A, 30)
+ (5170 - 5250 @ 80), (6, 20)
+ (5250 - 5330 @ 80), (6, 20), DFS
+ (5490 - 5710 @ 80), (6, 27), DFS
+ (5735 - 5835 @ 80), (6, 30)
+
+country PF:
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5150 - 5250 @ 80), (N/A, 20)
+ (5250 - 5350 @ 80), (N/A, 20), DFS
+ (5470 - 5725 @ 80), (N/A, 27), DFS
country PG:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (3, 17)
- (5250 - 5330 @ 40), (3, 23), DFS
- (5735 - 5835 @ 40), (3, 30)
+ (5150 - 5250 @ 80), (6, 17)
+ (5250 - 5350 @ 80), (6, 24), DFS
+ (5470 - 5725 @ 80), (6, 24), DFS
+ (5725 - 5850 @ 80), (6, 30)
country PH:
(2402 - 2482 @ 40), (N/A, 20)
- (5735 - 5835 @ 40), (N/A, 30)
+ (5170 - 5250 @ 80), (6, 17)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5710 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
country PK:
(2402 - 2482 @ 40), (N/A, 20)
- (5735 - 5835 @ 40), (N/A, 30)
+ (5735 - 5835 @ 80), (N/A, 30)
country PL: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country PT: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country PR:
- (2402 - 2472 @ 40), (3, 27)
- (5170 - 5250 @ 40), (3, 17)
- (5250 - 5330 @ 40), (3, 23), DFS
- (5735 - 5835 @ 40), (3, 30)
+ (2402 - 2472 @ 40), (3, 30)
+ (5170 - 5250 @ 80), (6, 17)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5710 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
+
+country PY:
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5150 - 5250 @ 80), (6, 17)
+ (5250 - 5350 @ 80), (6, 24), DFS
+ (5470 - 5725 @ 80), (6, 24), DFS
+ (5725 - 5850 @ 80), (6, 30)
country QA:
(2402 - 2482 @ 40), (N/A, 20)
- (5735 - 5835 @ 40), (N/A, 30)
+ (5735 - 5835 @ 80), (N/A, 30)
+
+country RE:
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5150 - 5250 @ 80), (N/A, 20)
+ (5250 - 5350 @ 80), (N/A, 20), DFS
+ (5470 - 5725 @ 80), (N/A, 27), DFS
country RO: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
@@ -647,52 +780,61 @@
# http://www.ratel.rs/upload/documents/Plan_namene/Plan_namene-sl_glasnik.pdf
country RS:
(2400 - 2483.5 @ 40), (N/A, 100 mW)
- (5150 - 5350 @ 40), (N/A, 200 mW), NO-OUTDOOR
- (5470 - 5725 @ 20), (3, 1000 mW), DFS
+ (5150 - 5250 @ 80), (N/A, 200 mW), NO-OUTDOOR
+ (5250 - 5350 @ 80), (N/A, 200 mW), DFS
+ (5470 - 5725 @ 80), (3, 1000 mW), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country RU:
(2402 - 2482 @ 40), (N/A, 20)
- (5735 - 5835 @ 20), (N/A, 30)
+ (5150 - 5250 @ 40), (N/A, 20)
+ (5250 - 5350 @ 40), (N/A, 20), DFS
+ (5650 - 5725 @ 40), (N/A, 30), DFS
+ (5725 - 5825 @ 40), (N/A, 30)
country RW:
(2402 - 2482 @ 40), (N/A, 20)
- (5735 - 5835 @ 40), (N/A, 30)
+ (5150 - 5250 @ 80), (6, 17)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5470 - 5725 @ 80), (6, 24), DFS
+ (5725 - 5835 @ 80), (6, 30)
country SA:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 20), (3, 23)
- (5250 - 5330 @ 20), (3, 23), DFS
- (5735 - 5835 @ 20), (3, 30)
+ (5170 - 5250 @ 80), (3, 17)
+ (5250 - 5330 @ 80), (3, 24), DFS
+ (5490 - 5710 @ 80), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
country SE: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country SG:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5735 - 5835 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (6, 17)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5710 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
country SI: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country SK: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
@@ -707,15 +849,16 @@
country TW:
(2402 - 2472 @ 40), (3, 27)
- (5270 - 5330 @ 40), (3, 17), DFS
- (5735 - 5815 @ 40), (3, 30)
+ (5270 - 5330 @ 80), (6, 17), DFS
+ (5490 - 5710 @ 80), (6, 30), DFS
+ (5735 - 5815 @ 80), (6, 30)
country TH:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (3, 17)
- (5250 - 5330 @ 40), (3, 20), DFS
- (5490 - 5710 @ 40), (3, 20), DFS
- (5735 - 5835 @ 40), (3, 30)
+ (5170 - 5250 @ 80), (3, 17)
+ (5250 - 5330 @ 80), (3, 24), DFS
+ (5490 - 5710 @ 80), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
country TT:
(2402 - 2482 @ 40), (N/A, 20)
@@ -731,8 +874,9 @@
country TR: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 20), (N/A, 20)
- (5250 - 5330 @ 20), (N/A, 20), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
@@ -745,22 +889,42 @@
# disputable definitions there.
country UA:
(2400 - 2483.5 @ 40), (N/A, 20), NO-OUTDOOR
- (5150 - 5350 @ 40), (N/A, 20), NO-OUTDOOR
+ (5150 - 5250 @ 40), (N/A, 20), NO-OUTDOOR
+ (5250 - 5350 @ 40), (N/A, 20), NO-OUTDOOR, DFS
+ (5470 - 5670 @ 40), (N/A, 20), DFS
+ (5725 - 5850 @ 40), (N/A, 20)
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+country UG:
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5150 - 5250 @ 80), (6, 20)
+ (5250 - 5350 @ 80), (6, 20), DFS
+ (5470 - 5725 @ 80), (6, 20), DFS
+ (5725 - 5825 @ 80), (6, 20)
+
country US: DFS-FCC
(2402 - 2472 @ 40), (3, 27)
- (5170 - 5250 @ 40), (3, 17)
- (5250 - 5330 @ 40), (3, 20), DFS
- (5490 - 5600 @ 40), (3, 20), DFS
- (5650 - 5710 @ 40), (3, 20), DFS
- (5735 - 5835 @ 40), (3, 30)
+ (5170 - 5250 @ 80), (3, 17)
+ (5250 - 5330 @ 80), (3, 24), DFS
+ (5490 - 5600 @ 80), (3, 24), DFS
+ (5650 - 5710 @ 40), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
# 60g band
# reference: http://cfr.regstoday.com/47cfr15.aspx#47_CFR_15p255
# channels 1,2,3, EIRP=40dBm(43dBm peak)
(57240 - 63720 @ 2160), (N/A, 40)
+# Public Safety FCCA, FCC4
+# 27dBm [4.9GHz 1/4 rate], 30dBm [1/2 rate], 33dBm [full rate], and 5GHz same as FCC1
+# db.txt cannot express the limitation on 5G so disable all 5G channels for FCC4
+country PS:
+ (2402 - 2472 @ 40), (N/A, 30)
+ #(4940 - 4990 @ 40), (6, 27)
+ #(5150 - 5250 @ 80), (6, 30)
+ #(5250 - 5350 @ 80), (6, 30), DFS
+ #(5725 - 5850 @ 80), (6, 33)
+
country UY:
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 40), (3, 17)
@@ -777,23 +941,44 @@
country VE:
(2402 - 2482 @ 40), (N/A, 20)
- (5735 - 5815 @ 40), (N/A, 23)
+ (5150 - 5250 @ 80), (6, 17)
+ (5250 - 5350 @ 80), (6, 23), DFS
+ (5725 - 5850 @ 80), (6, 30)
+
country VN:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
+ (5170 - 5250 @ 80), (3, 17)
+ (5250 - 5330 @ 80), (3, 24), DFS
+ (5490 - 5710 @ 80), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
+
+country VI:
+ (2402 - 2472 @ 40), (N/A, 30)
+ (5150 - 5250 @ 80), (6, 17)
+ (5250 - 5350 @ 80), (6, 24), DFS
+ (5470 - 5725 @ 80), (6, 24), DFS
+ (5725 - 5850 @ 80), (6, 30)
country YE:
(2402 - 2482 @ 40), (N/A, 20)
+country YT: DFS-ETSI
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5150 - 5250 @ 80), (N/A, 20)
+ (5250 - 5350 @ 80), (N/A, 20), DFS
+ (5470 - 5725 @ 80), (N/A, 27), DFS
+
country ZA:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (3, 17)
- (5250 - 5330 @ 40), (3, 20), DFS
- (5490 - 5710 @ 40), (3, 20), DFS
- (5735 - 5835 @ 40), (3, 30)
+ (5170 - 5250 @ 80), (3, 17)
+ (5250 - 5330 @ 80), (3, 24), DFS
+ (5490 - 5710 @ 80), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
country ZW:
(2402 - 2482 @ 40), (N/A, 20)
+ (5150 - 5250 @ 80), (N/A, 20)
+ (5250 - 5350 @ 80), (N/A, 20), DFS
+ (5470 - 5725 @ 80), (N/A, 27), DFS
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index b96094c..b094741 100755
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -848,8 +848,18 @@
r == -ERANGE)
return;
- REG_DBG_PRINT("Disabling freq %d MHz\n", chan->center_freq);
- chan->flags = IEEE80211_CHAN_DISABLED;
+ if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
+ request_wiphy && request_wiphy == wiphy &&
+ request_wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) {
+ REG_DBG_PRINT("Disabling freq %d MHz for good\n",
+ chan->center_freq);
+ chan->orig_flags |= IEEE80211_CHAN_DISABLED;
+ chan->flags = chan->orig_flags;
+ } else {
+ REG_DBG_PRINT("Disabling freq %d MHz\n",
+ chan->center_freq);
+ chan->flags |= IEEE80211_CHAN_DISABLED;
+ }
return;
}
@@ -883,7 +893,19 @@
chan->max_antenna_gain = min(chan->orig_mag,
(int) MBI_TO_DBI(power_rule->max_antenna_gain));
chan->max_reg_power = (int) MBM_TO_DBM(power_rule->max_eirp);
- chan->max_power = min(chan->max_power, chan->max_reg_power);
+ if (chan->orig_mpwr) {
+ /*
+ * Devices that use NL80211_COUNTRY_IE_FOLLOW_POWER will always
+ * follow the passed country IE power settings.
+ */
+ if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE &&
+ wiphy->country_ie_pref & NL80211_COUNTRY_IE_FOLLOW_POWER)
+ chan->max_power = chan->max_reg_power;
+ else
+ chan->max_power = min(chan->orig_mpwr,
+ chan->max_reg_power);
+ } else
+ chan->max_power = chan->max_reg_power;
}
static void handle_band(struct wiphy *wiphy,
@@ -1218,7 +1240,8 @@
"wide channel\n",
chan->center_freq,
KHZ_TO_MHZ(desired_bw_khz));
- chan->flags = IEEE80211_CHAN_DISABLED;
+ chan->orig_flags |= IEEE80211_CHAN_DISABLED;
+ chan->flags = chan->orig_flags;
return;
}
@@ -1295,6 +1318,8 @@
case NL80211_REGDOM_SET_BY_CORE:
return 0;
case NL80211_REGDOM_SET_BY_COUNTRY_IE:
+ if (wiphy->country_ie_pref & NL80211_COUNTRY_IE_IGNORE_CORE)
+ return -EALREADY;
last_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
@@ -1485,8 +1510,8 @@
if (wiphy_idx_valid(reg_request->wiphy_idx))
wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx);
- if (reg_initiator == NL80211_REGDOM_SET_BY_DRIVER &&
- !wiphy) {
+ if ((reg_initiator == NL80211_REGDOM_SET_BY_DRIVER ||
+ reg_initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) && !wiphy) {
kfree(reg_request);
return;
}
@@ -1648,6 +1673,7 @@
return 0;
}
+EXPORT_SYMBOL(regulatory_hint_user);
/* Driver hints */
int regulatory_hint(struct wiphy *wiphy, const char *alpha2)
@@ -2117,7 +2143,7 @@
* checking if the alpha2 changes if CRDA was already called
*/
if (!regdom_changes(rd->alpha2))
- return -EINVAL;
+ return -EALREADY;
}
/*
@@ -2242,6 +2268,9 @@
/* Note that this doesn't update the wiphys, this is done below */
r = __set_regdom(rd);
if (r) {
+ if (r == -EALREADY)
+ reg_set_request_processed();
+
kfree(rd);
mutex_unlock(®_mutex);
return r;
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
index e2aaaf5..017880c 100644
--- a/net/wireless/reg.h
+++ b/net/wireless/reg.h
@@ -22,8 +22,6 @@
bool reg_is_valid_request(const char *alpha2);
bool reg_supported_dfs_region(u8 dfs_region);
-int regulatory_hint_user(const char *alpha2);
-
int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env);
void reg_device_remove(struct wiphy *wiphy);
diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
index 487ac6f..9a11f9f 100644
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -55,6 +55,7 @@
static unsigned int table_size, table_cnt;
static int all_symbols = 0;
static char symbol_prefix_char = '\0';
+static unsigned long long kernel_start_addr = 0;
int token_profit[0x10000];
@@ -65,7 +66,10 @@
static void usage(void)
{
- fprintf(stderr, "Usage: kallsyms [--all-symbols] [--symbol-prefix=<prefix char>] < in.map > out.S\n");
+ fprintf(stderr, "Usage: kallsyms [--all-symbols] "
+ "[--symbol-prefix=<prefix char>] "
+ "[--page-offset=<CONFIG_PAGE_OFFSET>] "
+ "< in.map > out.S\n");
exit(1);
}
@@ -194,6 +198,9 @@
int i;
int offset = 1;
+ if (s->addr < kernel_start_addr)
+ return 0;
+
/* skip prefix char */
if (symbol_prefix_char && *(s->sym + 1) == symbol_prefix_char)
offset++;
@@ -646,6 +653,9 @@
if ((*p == '"' && *(p+2) == '"') || (*p == '\'' && *(p+2) == '\''))
p++;
symbol_prefix_char = *p;
+ } else if (strncmp(argv[i], "--page-offset=", 14) == 0) {
+ const char *p = &argv[i][14];
+ kernel_start_addr = strtoull(p, NULL, 16);
} else
usage();
}
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c
index 8daa015..f8e9d7a 100644
--- a/sound/core/compress_offload.c
+++ b/sound/core/compress_offload.c
@@ -612,9 +612,10 @@
static inline int
snd_compr_tstamp(struct snd_compr_stream *stream, unsigned long arg)
{
- struct snd_compr_tstamp tstamp = {0};
+ struct snd_compr_tstamp tstamp;
int ret;
+ memset(&tstamp, 0, sizeof(tstamp));
ret = snd_compr_update_tstamp(stream, &tstamp);
if (ret == 0)
ret = copy_to_user((struct snd_compr_tstamp __user *)arg,
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index 6785fe1..bbebc5d 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -50,6 +50,8 @@
#define BITS_PER_REG 8
#define MSM8X10_WCD_TX_PORT_NUMBER 4
+#define DAPM_MICBIAS_EXTERNAL_STANDALONE "MIC BIAS External Standalone"
+
#define MSM8X10_WCD_I2S_MASTER_MODE_MASK 0x08
#define MSM8X10_DINO_CODEC_BASE_ADDR 0xFE043000
#define MSM8X10_DINO_CODEC_REG_SIZE 0x200
@@ -1396,7 +1398,10 @@
switch (decimator) {
case 1:
case 2:
- adc_dmic_sel = 0x0;
+ if ((dec_mux == 3) || (dec_mux == 4))
+ adc_dmic_sel = 0x1;
+ else
+ adc_dmic_sel = 0x0;
break;
default:
dev_err(codec->dev, "%s: Invalid Decimator = %u\n",
@@ -1632,6 +1637,8 @@
/* Always pull up TxFe for TX2 to Micbias */
snd_soc_update_bits(codec, micb_int_reg, 0x04, 0x04);
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_1_CTL,
+ 0x80, 0x80);
break;
case SND_SOC_DAPM_POST_PMU:
usleep_range(20000, 20100);
@@ -1639,6 +1646,8 @@
wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_on);
break;
case SND_SOC_DAPM_POST_PMD:
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_1_CTL,
+ 0x80, 0x00);
/* Let MBHC module know so micbias switch to be off */
wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_off);
@@ -2297,7 +2306,8 @@
SND_SOC_DAPM_OUTPUT("EAR"),
SND_SOC_DAPM_PGA_E("EAR PA", MSM8X10_WCD_A_RX_EAR_EN, 4, 0, NULL, 0,
- msm8x10_wcd_codec_enable_ear_pa, SND_SOC_DAPM_POST_PMU),
+ msm8x10_wcd_codec_enable_ear_pa,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MIXER("DAC1", MSM8X10_WCD_A_RX_EAR_EN, 6, 0, dac1_switch,
ARRAY_SIZE(dac1_switch)),
@@ -2455,6 +2465,11 @@
MSM8X10_WCD_A_MICB_1_CTL, 7, 0,
msm8x10_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E(DAPM_MICBIAS_EXTERNAL_STANDALONE,
+ MSM8X10_WCD_A_MICB_1_CTL,
+ 7, 0, msm8x10_wcd_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_ADC_E("ADC1", NULL, MSM8X10_WCD_A_TX_1_EN, 7, 0,
msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
@@ -2582,6 +2597,8 @@
*/
{MSM8X10_WCD_A_RX_HPH_OCP_CTL, 0xE1, 0x61},
{MSM8X10_WCD_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
+ {MSM8X10_WCD_A_RX_HPH_L_TEST, 0x01, 0x01},
+ {MSM8X10_WCD_A_RX_HPH_R_TEST, 0x01, 0x01},
/* Initialize gain registers to use register gain */
{MSM8X10_WCD_A_RX_HPH_L_GAIN, 0x20, 0x20},
@@ -2704,6 +2721,30 @@
return ret;
}
+static int msm8x10_wcd_enable_mbhc_micbias(struct snd_soc_codec *codec,
+ bool enable)
+{
+ int rc;
+
+ if (enable)
+ rc = snd_soc_dapm_force_enable_pin(&codec->dapm,
+ DAPM_MICBIAS_EXTERNAL_STANDALONE);
+ else
+ rc = snd_soc_dapm_disable_pin(&codec->dapm,
+ DAPM_MICBIAS_EXTERNAL_STANDALONE);
+ snd_soc_dapm_sync(&codec->dapm);
+
+ snd_soc_update_bits(codec, WCD9XXX_A_MICB_1_CTL,
+ 0x80, enable ? 0x80 : 0x00);
+ if (rc)
+ pr_debug("%s: Failed to force %s micbias", __func__,
+ enable ? "enable" : "disable");
+ else
+ pr_debug("%s: Trying force %s micbias", __func__,
+ enable ? "enable" : "disable");
+ return rc;
+}
+
static void msm8x10_wcd_micb_internal(struct snd_soc_codec *codec, bool on)
{
snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_1_INT_RBIAS,
@@ -3007,10 +3048,21 @@
return NULL;
}
+static int msm8x10_wcd_device_down(struct snd_soc_codec *codec)
+{
+ dev_dbg(codec->dev, "%s: device down!\n", __func__);
+
+ snd_soc_card_change_online_state(codec->card, 0);
+ return 0;
+}
static int msm8x10_wcd_device_up(struct snd_soc_codec *codec)
{
- pr_debug("%s: device up!\n", __func__);
+ dev_dbg(codec->dev, "%s: device up!\n", __func__);
+
+ snd_soc_card_change_online_state(codec->card, 1);
+ /* delay is required to make sure sound card state updated */
+ usleep_range(5000, 5100);
mutex_lock(&codec->mutex);
@@ -3029,7 +3081,9 @@
bool timedout;
unsigned long timeout;
- if (value == SUBSYS_AFTER_POWERUP) {
+ if (value == SUBSYS_BEFORE_SHUTDOWN)
+ msm8x10_wcd_device_down(registered_codec);
+ else if (value == SUBSYS_AFTER_POWERUP) {
pr_debug("%s: ADSP is about to power up. bring up codec\n",
__func__);
@@ -3173,7 +3227,8 @@
ret = wcd9xxx_mbhc_init(&msm8x10_wcd_priv->mbhc,
&msm8x10_wcd_priv->resmgr,
- codec, NULL, &mbhc_cb, &cdc_intr_ids,
+ codec, msm8x10_wcd_enable_mbhc_micbias,
+ &mbhc_cb, &cdc_intr_ids,
HELICON_MCLK_CLK_9P6MHZ, true);
if (ret) {
dev_err(msm8x10_wcd->dev, "%s: Failed to initialize mbhc\n",
diff --git a/sound/soc/codecs/msm_hdmi_codec_rx.c b/sound/soc/codecs/msm_hdmi_codec_rx.c
index e5d5c32..73c9547e 100644
--- a/sound/soc/codecs/msm_hdmi_codec_rx.c
+++ b/sound/soc/codecs/msm_hdmi_codec_rx.c
@@ -21,6 +21,8 @@
#define MSM_HDMI_PCM_RATES SNDRV_PCM_RATE_48000
+static int msm_hdmi_audio_codec_return_value;
+
struct msm_hdmi_audio_codec_rx_data {
struct platform_device *hdmi_core_pdev;
struct msm_hdmi_audio_codec_ops hdmi_ops;
@@ -54,8 +56,8 @@
int rc;
codec_data = snd_soc_codec_get_drvdata(codec);
- rc = codec_data->hdmi_ops.get_audio_edid_blk(codec_data->hdmi_core_pdev,
- &edid_blk);
+ rc = codec_data->hdmi_ops.get_audio_edid_blk(
+ codec_data->hdmi_core_pdev, &edid_blk);
if (!IS_ERR_VALUE(rc)) {
memcpy(ucontrol->value.bytes.data, edid_blk.audio_data_blk,
@@ -80,6 +82,24 @@
},
};
+static int msm_hdmi_audio_codec_rx_dai_startup(
+ struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct msm_hdmi_audio_codec_rx_data *codec_data =
+ dev_get_drvdata(dai->codec->dev);
+
+ msm_hdmi_audio_codec_return_value =
+ codec_data->hdmi_ops.hdmi_cable_status(
+ codec_data->hdmi_core_pdev, 1);
+ if (IS_ERR_VALUE(msm_hdmi_audio_codec_return_value)) {
+ dev_err(dai->dev,
+ "%s() HDMI core is not ready\n", __func__);
+ }
+
+ return msm_hdmi_audio_codec_return_value;
+}
+
static int msm_hdmi_audio_codec_rx_dai_hw_params(
struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
@@ -89,17 +109,37 @@
u32 level_shift = 0; /* 0dB */
bool down_mix = 0;
u32 num_channels = params_channels(params);
+ int rc = 0;
struct msm_hdmi_audio_codec_rx_data *codec_data =
dev_get_drvdata(dai->codec->dev);
+ /*refer to HDMI spec CEA-861-E: Table 28 Audio InfoFrame Data Byte 4*/
+ if (IS_ERR_VALUE(msm_hdmi_audio_codec_return_value)) {
+ dev_err(dai->dev,
+ "%s() HDMI core is not ready\n", __func__);
+ return msm_hdmi_audio_codec_return_value;
+ }
+
switch (num_channels) {
case 2:
channel_allocation = 0;
break;
+ case 3:
+ channel_allocation = 0x02;//default to FL/FR/FC
+ break;
+ case 4:
+ channel_allocation = 0x06;//default to FL/FR/FC/RC
+ break;
+ case 5:
+ channel_allocation = 0x0A;//default to FL/FR/FC/RR/RL
+ break;
case 6:
channel_allocation = 0x0B;
break;
+ case 7:
+ channel_allocation = 0x12;//default to FL/FR/FC/RL/RR/RRC/RLC
+ break;
case 8:
channel_allocation = 0x13;
break;
@@ -108,19 +148,47 @@
return -EINVAL;
}
- dev_dbg(dai->dev, "%s() num_ch %u samplerate %u channel_allocation = %u\n",
+ dev_dbg(dai->dev,
+ "%s() num_ch %u samplerate %u channel_allocation = %u\n",
__func__, num_channels, params_rate(params),
channel_allocation);
- codec_data->hdmi_ops.audio_info_setup(codec_data->hdmi_core_pdev,
- params_rate(params), num_channels, channel_allocation,
- level_shift, down_mix);
+ rc = codec_data->hdmi_ops.audio_info_setup(
+ codec_data->hdmi_core_pdev,
+ params_rate(params), num_channels,
+ channel_allocation, level_shift, down_mix);
+ if (IS_ERR_VALUE(rc)) {
+ dev_err(dai->dev,
+ "%s() HDMI core is not ready\n", __func__);
+ }
- return 0;
+ return rc;
+}
+
+static void msm_hdmi_audio_codec_rx_dai_shutdown(
+ struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ int rc;
+
+ struct msm_hdmi_audio_codec_rx_data *codec_data =
+ dev_get_drvdata(dai->codec->dev);
+
+ rc = codec_data->hdmi_ops.hdmi_cable_status(
+ codec_data->hdmi_core_pdev, 0);
+ if (IS_ERR_VALUE(rc)) {
+ dev_err(dai->dev,
+ "%s() HDMI core had problems releasing HDMI audio flag\n",
+ __func__);
+ }
+
+ return;
}
static struct snd_soc_dai_ops msm_hdmi_audio_codec_rx_dai_ops = {
+ .startup = msm_hdmi_audio_codec_rx_dai_startup,
.hw_params = msm_hdmi_audio_codec_rx_dai_hw_params,
+ .shutdown = msm_hdmi_audio_codec_rx_dai_shutdown
};
static int msm_hdmi_audio_codec_rx_probe(struct snd_soc_codec *codec)
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index da99254..27ea648 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -42,6 +42,8 @@
#define TAPAN_HPH_PA_SETTLE_COMP_ON 3000
#define TAPAN_HPH_PA_SETTLE_COMP_OFF 13000
+#define DAPM_MICBIAS2_EXTERNAL_STANDALONE "MIC BIAS2 External Standalone"
+
#define TAPAN_VDD_CX_OPTIMAL_UA 10000
#define TAPAN_VDD_CX_SLEEP_UA 2000
@@ -281,6 +283,8 @@
s32 dmic_1_2_clk_cnt;
s32 dmic_3_4_clk_cnt;
s32 dmic_5_6_clk_cnt;
+ s32 ldo_h_users;
+ s32 micb_2_users;
u32 anc_slot;
bool anc_func;
@@ -510,31 +514,41 @@
struct snd_ctl_elem_value *ucontrol)
{
u8 ear_pa_gain;
+ int rc = 0;
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
ear_pa_gain = snd_soc_read(codec, TAPAN_A_RX_EAR_GAIN);
-
ear_pa_gain = ear_pa_gain >> 5;
- if (ear_pa_gain == 0x00) {
- ucontrol->value.integer.value[0] = 0;
- } else if (ear_pa_gain == 0x04) {
- ucontrol->value.integer.value[0] = 1;
- } else {
+ switch (ear_pa_gain) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ ucontrol->value.integer.value[0] = ear_pa_gain;
+ break;
+ case 7:
+ ucontrol->value.integer.value[0] = (ear_pa_gain - 1);
+ break;
+ default:
+ rc = -EINVAL;
pr_err("%s: ERROR: Unsupported Ear Gain = 0x%x\n",
- __func__, ear_pa_gain);
- return -EINVAL;
+ __func__, ear_pa_gain);
+ break;
}
dev_dbg(codec->dev, "%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
- return 0;
+ return rc;
}
static int tapan_pa_gain_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u8 ear_pa_gain;
+ int rc = 0;
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
@@ -542,17 +556,24 @@
switch (ucontrol->value.integer.value[0]) {
case 0:
- ear_pa_gain = 0x00;
- break;
case 1:
- ear_pa_gain = 0x80;
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ ear_pa_gain = ucontrol->value.integer.value[0];
+ break;
+ case 6:
+ ear_pa_gain = 0x07;
break;
default:
- return -EINVAL;
+ rc = -EINVAL;
+ break;
}
-
- snd_soc_update_bits(codec, TAPAN_A_RX_EAR_GAIN, 0xE0, ear_pa_gain);
- return 0;
+ if (!rc)
+ snd_soc_update_bits(codec, TAPAN_A_RX_EAR_GAIN,
+ 0xE0, ear_pa_gain << 5);
+ return rc;
}
static int tapan_get_iir_enable_audio_mixer(
@@ -1013,9 +1034,13 @@
return 0;
}
-static const char * const tapan_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
+static const char * const tapan_ear_pa_gain_text[] = {"POS_6_DB", "POS_4P5_DB",
+ "POS_3_DB", "POS_1P5_DB",
+ "POS_0_DB", "NEG_2P5_DB",
+ "NEG_12_DB"};
static const struct soc_enum tapan_ear_pa_gain_enum[] = {
- SOC_ENUM_SINGLE_EXT(2, tapan_ear_pa_gain_text),
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tapan_ear_pa_gain_text),
+ tapan_ear_pa_gain_text),
};
static const char *const tapan_anc_func_text[] = {"OFF", "ON"};
@@ -1323,6 +1348,9 @@
static const struct soc_enum rx4_mix1_inp2_chain_enum =
SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX4_B1_CTL, 4, 13, rx_3_4_mix1_text);
+static const struct soc_enum rx4_mix1_inp3_chain_enum =
+ SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX4_B2_CTL, 0, 13, rx_3_4_mix1_text);
+
static const struct soc_enum rx1_mix2_inp1_chain_enum =
SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX1_B3_CTL, 0, 5, rx_mix2_text);
@@ -1418,6 +1446,9 @@
static const struct snd_kcontrol_new rx4_mix1_inp2_mux =
SOC_DAPM_ENUM("RX4 MIX1 INP2 Mux", rx4_mix1_inp2_chain_enum);
+static const struct snd_kcontrol_new rx4_mix1_inp3_mux =
+ SOC_DAPM_ENUM("RX4 MIX1 INP3 Mux", rx4_mix1_inp3_chain_enum);
+
static const struct snd_kcontrol_new rx1_mix2_inp1_mux =
SOC_DAPM_ENUM("RX1 MIX2 INP1 Mux", rx1_mix2_inp1_chain_enum);
@@ -1829,6 +1860,7 @@
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
+ struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
u16 adc_reg;
u8 init_bit_shift;
@@ -1856,6 +1888,9 @@
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
+ if (w->reg == TAPAN_A_TX_3_EN)
+ wcd9xxx_resmgr_notifier_call(&tapan->resmgr,
+ WCD9XXX_EVENT_PRE_TX_3_ON);
snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
1 << init_bit_shift);
break;
@@ -1864,6 +1899,11 @@
snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (w->reg == TAPAN_A_TX_3_EN)
+ wcd9xxx_resmgr_notifier_call(&tapan->resmgr,
+ WCD9XXX_EVENT_POST_TX_3_OFF);
+ break;
}
return 0;
}
@@ -2137,38 +2177,37 @@
{
struct snd_soc_codec *codec = w->codec;
struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
- u16 micb_int_reg;
+ u16 micb_int_reg = 0, micb_ctl_reg = 0;
u8 cfilt_sel_val = 0;
char *internal1_text = "Internal1";
char *internal2_text = "Internal2";
char *internal3_text = "Internal3";
enum wcd9xxx_notify_event e_post_off, e_pre_on, e_post_on;
- dev_dbg(codec->dev, "%s %d\n", __func__, event);
- switch (w->reg) {
- case TAPAN_A_MICB_1_CTL:
+ pr_debug("%s: w->name %s event %d\n", __func__, w->name, event);
+ if (strnstr(w->name, "MIC BIAS1", sizeof("MIC BIAS1"))) {
+ micb_ctl_reg = TAPAN_A_MICB_1_CTL;
micb_int_reg = TAPAN_A_MICB_1_INT_RBIAS;
cfilt_sel_val = tapan->resmgr.pdata->micbias.bias1_cfilt_sel;
e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_1_ON;
e_post_on = WCD9XXX_EVENT_POST_MICBIAS_1_ON;
e_post_off = WCD9XXX_EVENT_POST_MICBIAS_1_OFF;
- break;
- case TAPAN_A_MICB_2_CTL:
+ } else if (strnstr(w->name, "MIC BIAS2", sizeof("MIC BIAS2"))) {
+ micb_ctl_reg = TAPAN_A_MICB_2_CTL;
micb_int_reg = TAPAN_A_MICB_2_INT_RBIAS;
cfilt_sel_val = tapan->resmgr.pdata->micbias.bias2_cfilt_sel;
e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_2_ON;
e_post_on = WCD9XXX_EVENT_POST_MICBIAS_2_ON;
e_post_off = WCD9XXX_EVENT_POST_MICBIAS_2_OFF;
- break;
- case TAPAN_A_MICB_3_CTL:
+ } else if (strnstr(w->name, "MIC BIAS3", sizeof("MIC BIAS3"))) {
+ micb_ctl_reg = TAPAN_A_MICB_3_CTL;
micb_int_reg = TAPAN_A_MICB_3_INT_RBIAS;
cfilt_sel_val = tapan->resmgr.pdata->micbias.bias3_cfilt_sel;
e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_3_ON;
e_post_on = WCD9XXX_EVENT_POST_MICBIAS_3_ON;
e_post_off = WCD9XXX_EVENT_POST_MICBIAS_3_OFF;
- break;
- default:
- pr_err("%s: Error, invalid micbias register\n", __func__);
+ } else {
+ pr_err("%s: Error, invalid micbias %s\n", __func__, w->name);
return -EINVAL;
}
@@ -2187,6 +2226,20 @@
else if (strnstr(w->name, internal3_text, 30))
snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
+ if (micb_ctl_reg == TAPAN_A_MICB_2_CTL) {
+ if (++tapan->micb_2_users == 1)
+ wcd9xxx_resmgr_add_cond_update_bits(
+ &tapan->resmgr,
+ WCD9XXX_COND_HPH_MIC,
+ micb_ctl_reg, w->shift,
+ false);
+ pr_debug("%s: micb_2_users %d\n", __func__,
+ tapan->micb_2_users);
+ } else
+ snd_soc_update_bits(codec, micb_ctl_reg, 1 << w->shift,
+ 1 << w->shift);
+
+
break;
case SND_SOC_DAPM_POST_PMU:
usleep_range(20000, 20000);
@@ -2194,6 +2247,22 @@
wcd9xxx_resmgr_notifier_call(&tapan->resmgr, e_post_on);
break;
case SND_SOC_DAPM_POST_PMD:
+ if (micb_ctl_reg == TAPAN_A_MICB_2_CTL) {
+ if (--tapan->micb_2_users == 0)
+ wcd9xxx_resmgr_rm_cond_update_bits(
+ &tapan->resmgr,
+ WCD9XXX_COND_HPH_MIC,
+ micb_ctl_reg, 7,
+ false);
+ pr_debug("%s: micb_2_users %d\n", __func__,
+ tapan->micb_2_users);
+ WARN(tapan->micb_2_users < 0,
+ "Unexpected micbias users %d\n",
+ tapan->micb_2_users);
+ } else
+ snd_soc_update_bits(codec, micb_ctl_reg, 1 << w->shift,
+ 0);
+
/* Let MBHC module know so micbias switch to be off */
wcd9xxx_resmgr_notifier_call(&tapan->resmgr, e_post_off);
@@ -2212,6 +2281,23 @@
return 0;
}
+/* called under codec_resource_lock acquisition */
+static int tapan_enable_mbhc_micbias(struct snd_soc_codec *codec, bool enable)
+{
+ int rc;
+
+ if (enable)
+ rc = snd_soc_dapm_force_enable_pin(&codec->dapm,
+ DAPM_MICBIAS2_EXTERNAL_STANDALONE);
+ else
+ rc = snd_soc_dapm_disable_pin(&codec->dapm,
+ DAPM_MICBIAS2_EXTERNAL_STANDALONE);
+ if (!rc)
+ snd_soc_dapm_sync(&codec->dapm);
+ pr_debug("%s: leave ret %d\n", __func__, rc);
+ return rc;
+}
+
static void tx_hpf_corner_freq_callback(struct work_struct *work)
{
struct delayed_work *hpf_delayed_work;
@@ -2426,16 +2512,66 @@
return 0;
}
+/* called under codec_resource_lock acquisition */
+static int __tapan_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct tapan_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+ pr_debug("%s: enter\n", __func__);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /*
+ * ldo_h_users is protected by codec->mutex, don't need
+ * additional mutex
+ */
+ if (++priv->ldo_h_users == 1) {
+ WCD9XXX_BG_CLK_LOCK(&priv->resmgr);
+ wcd9xxx_resmgr_get_bandgap(&priv->resmgr,
+ WCD9XXX_BANDGAP_AUDIO_MODE);
+ wcd9xxx_resmgr_get_clk_block(&priv->resmgr,
+ WCD9XXX_CLK_RCO);
+ snd_soc_update_bits(codec, TAPAN_A_LDO_H_MODE_1, 1 << 7,
+ 1 << 7);
+ wcd9xxx_resmgr_put_clk_block(&priv->resmgr,
+ WCD9XXX_CLK_RCO);
+ WCD9XXX_BG_CLK_UNLOCK(&priv->resmgr);
+ pr_debug("%s: ldo_h_users %d\n", __func__,
+ priv->ldo_h_users);
+ /* LDO enable requires 1ms to settle down */
+ usleep_range(1000, 1010);
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (--priv->ldo_h_users == 0) {
+ WCD9XXX_BG_CLK_LOCK(&priv->resmgr);
+ wcd9xxx_resmgr_get_clk_block(&priv->resmgr,
+ WCD9XXX_CLK_RCO);
+ snd_soc_update_bits(codec, TAPAN_A_LDO_H_MODE_1, 1 << 7,
+ 0);
+ wcd9xxx_resmgr_put_clk_block(&priv->resmgr,
+ WCD9XXX_CLK_RCO);
+ wcd9xxx_resmgr_put_bandgap(&priv->resmgr,
+ WCD9XXX_BANDGAP_AUDIO_MODE);
+ WCD9XXX_BG_CLK_UNLOCK(&priv->resmgr);
+ pr_debug("%s: ldo_h_users %d\n", __func__,
+ priv->ldo_h_users);
+ }
+ WARN(priv->ldo_h_users < 0, "Unexpected ldo_h users %d\n",
+ priv->ldo_h_users);
+ break;
+ }
+ pr_debug("%s: leave\n", __func__);
+ return 0;
+}
+
static int tapan_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- switch (event) {
- case SND_SOC_DAPM_POST_PMU:
- case SND_SOC_DAPM_POST_PMD:
- usleep_range(1000, 1000);
- break;
- }
- return 0;
+ int rc;
+ rc = __tapan_codec_enable_ldo_h(w, kcontrol, event);
+ return rc;
}
static int tapan_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
@@ -2847,7 +2983,7 @@
{"DAC1", "Switch", "CLASS_H_DSM MUX"},
{"HPHL DAC", "Switch", "CLASS_H_DSM MUX"},
- {"HPHR DAC", NULL, "RX2 CHAIN"},
+ {"HPHR DAC", NULL, "RDAC3 MUX"},
{"LINEOUT1", NULL, "LINEOUT1 PA"},
{"LINEOUT2", NULL, "LINEOUT2 PA"},
@@ -2858,11 +2994,14 @@
{"LINEOUT2 PA", NULL, "LINEOUT2_PA_MIXER"},
{"LINEOUT2_PA_MIXER", NULL, "LINEOUT2 DAC"},
- {"LINEOUT1 DAC", NULL, "RX3 MIX1"},
{"RDAC5 MUX", "DEM3_INV", "RX3 MIX1"},
{"LINEOUT2 DAC", NULL, "RDAC5 MUX"},
+ {"RDAC4 MUX", "DEM3", "RX3 MIX1"},
+ {"RDAC4 MUX", "DEM2", "RX2 CHAIN"},
+ {"LINEOUT1 DAC", NULL, "RDAC4 MUX"},
+
{"SPK PA", NULL, "SPK DAC"},
{"SPK DAC", NULL, "VDD_SPKDRV"},
@@ -2875,7 +3014,7 @@
{"LINEOUT1 DAC", NULL, "CDC_CP_VDD"},
{"LINEOUT2 DAC", NULL, "CDC_CP_VDD"},
- {"RDAC3 MUX", "DEM2", "RX2 MIX1"},
+ {"RDAC3 MUX", "DEM2", "RX2 CHAIN"},
{"RDAC3 MUX", "DEM1", "RX1 CHAIN"},
{"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
@@ -3005,14 +3144,12 @@
{"MIC BIAS2 Internal2", NULL, "LDO_H"},
{"MIC BIAS2 Internal3", NULL, "LDO_H"},
{"MIC BIAS2 External", NULL, "LDO_H"},
+ {DAPM_MICBIAS2_EXTERNAL_STANDALONE, NULL, "LDO_H Standalone"},
};
static const struct snd_soc_dapm_route wcd9302_map[] = {
{"SPK DAC", "Switch", "RX3 MIX1"},
- {"RDAC4 MUX", "DEM3", "RX3 MIX1"},
- {"RDAC4 MUX", "DEM2", "RX2 CHAIN"},
- {"LINEOUT1 DAC", NULL, "RDAC4 MUX"},
{"RDAC5 MUX", "DEM4", "RX3 MIX1"},
{"RDAC5 MUX", "DEM3_INV", "RDAC4 MUX"},
@@ -3154,13 +3291,27 @@
struct snd_soc_dai *dai)
{
struct wcd9xxx *tapan_core = dev_get_drvdata(dai->codec->dev->parent);
+ struct tapan_priv *tapan = snd_soc_codec_get_drvdata(dai->codec);
+ u32 active = 0;
+
dev_dbg(dai->codec->dev, "%s(): substream = %s stream = %d\n",
__func__, substream->name, substream->stream);
+
+ if (dai->id <= NUM_CODEC_DAIS) {
+ if (tapan->dai[dai->id].ch_mask) {
+ active = 1;
+ dev_dbg(dai->codec->dev, "%s(): Codec DAI: chmask[%d] = 0x%lx\n",
+ __func__, dai->id,
+ tapan->dai[dai->id].ch_mask);
+ }
+ }
if ((tapan_core != NULL) &&
(tapan_core->dev != NULL) &&
- (tapan_core->dev->parent != NULL)) {
+ (tapan_core->dev->parent != NULL) &&
+ (active == 0)) {
pm_runtime_mark_last_busy(tapan_core->dev->parent);
pm_runtime_put(tapan_core->dev->parent);
+ dev_dbg(dai->codec->dev, "%s: unvote requested", __func__);
}
}
@@ -3920,6 +4071,13 @@
dev_dbg(codec->dev, "%s: Disconnect RX port, ret = %d\n",
__func__, ret);
}
+ if ((core != NULL) &&
+ (core->dev != NULL) &&
+ (core->dev->parent != NULL)) {
+ pm_runtime_mark_last_busy(core->dev->parent);
+ pm_runtime_put(core->dev->parent);
+ dev_dbg(codec->dev, "%s: unvote requested", __func__);
+ }
break;
}
return ret;
@@ -3967,6 +4125,13 @@
dev_dbg(codec->dev, "%s: Disconnect RX port, ret = %d\n",
__func__, ret);
}
+ if ((core != NULL) &&
+ (core->dev != NULL) &&
+ (core->dev->parent != NULL)) {
+ pm_runtime_mark_last_busy(core->dev->parent);
+ pm_runtime_put(core->dev->parent);
+ dev_dbg(codec->dev, "%s: unvote requested", __func__);
+ }
break;
}
return ret;
@@ -4139,7 +4304,7 @@
SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
&rx4_mix1_inp2_mux),
SND_SOC_DAPM_MUX("RX4 MIX1 INP3", SND_SOC_NOPM, 0, 0,
- &rx4_mix1_inp2_mux),
+ &rx4_mix1_inp3_mux),
/* RX4 MIX2 mux inputs */
SND_SOC_DAPM_MUX("RX4 MIX2 INP1", SND_SOC_NOPM, 0, 0,
@@ -4196,13 +4361,13 @@
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TAPAN_A_MICB_3_CTL, 7, 0,
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", SND_SOC_NOPM, 7, 0,
tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", TAPAN_A_MICB_3_CTL, 7, 0,
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", SND_SOC_NOPM, 7, 0,
tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", TAPAN_A_MICB_3_CTL, 7, 0,
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", SND_SOC_NOPM, 7, 0,
tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
@@ -4425,17 +4590,27 @@
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_SUPPLY("LDO_H", TAPAN_A_LDO_H_MODE_1, 7, 0,
- tapan_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_SUPPLY("LDO_H", SND_SOC_NOPM, 7, 0,
+ tapan_codec_enable_ldo_h,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /*
+ * DAPM 'LDO_H Standalone' is to be powered by mbhc driver after
+ * acquring codec_resource lock.
+ * So call __tapan_codec_enable_ldo_h instead and avoid deadlock.
+ */
+ SND_SOC_DAPM_SUPPLY("LDO_H Standalone", SND_SOC_NOPM, 7, 0,
+ __tapan_codec_enable_ldo_h,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_INPUT("AMIC1"),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TAPAN_A_MICB_1_CTL, 7, 0,
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", SND_SOC_NOPM, 7, 0,
tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TAPAN_A_MICB_1_CTL, 7, 0,
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", SND_SOC_NOPM, 7, 0,
tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TAPAN_A_MICB_1_CTL, 7, 0,
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", SND_SOC_NOPM, 7, 0,
tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
@@ -4457,19 +4632,24 @@
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_INPUT("AMIC2"),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TAPAN_A_MICB_2_CTL, 7, 0,
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", SND_SOC_NOPM, 7, 0,
tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", TAPAN_A_MICB_2_CTL, 7, 0,
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", SND_SOC_NOPM, 7, 0,
tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", TAPAN_A_MICB_2_CTL, 7, 0,
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", SND_SOC_NOPM, 7, 0,
tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", TAPAN_A_MICB_2_CTL, 7, 0,
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", SND_SOC_NOPM, 7, 0,
tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E(DAPM_MICBIAS2_EXTERNAL_STANDALONE, SND_SOC_NOPM,
+ 7, 0, tapan_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
SND_SOC_DAPM_AIF_OUT_E("AIF1 CAP", "AIF1 Capture", 0, SND_SOC_NOPM,
AIF1_CAP, 0, tapan_codec_enable_slimtx,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
@@ -5467,7 +5647,8 @@
else
rco_clk_rate = TAPAN_MCLK_CLK_9P6MHZ;
- ret = wcd9xxx_mbhc_init(&tapan->mbhc, &tapan->resmgr, codec, NULL,
+ ret = wcd9xxx_mbhc_init(&tapan->mbhc, &tapan->resmgr, codec,
+ tapan_enable_mbhc_micbias,
&mbhc_cb, &cdc_intr_ids, rco_clk_rate,
TAPAN_CDC_ZDET_SUPPORTED);
if (ret)
@@ -5674,7 +5855,8 @@
else
rco_clk_rate = TAPAN_MCLK_CLK_9P6MHZ;
- ret = wcd9xxx_mbhc_init(&tapan->mbhc, &tapan->resmgr, codec, NULL,
+ ret = wcd9xxx_mbhc_init(&tapan->mbhc, &tapan->resmgr, codec,
+ tapan_enable_mbhc_micbias,
&mbhc_cb, &cdc_intr_ids, rco_clk_rate,
TAPAN_CDC_ZDET_SUPPORTED);
@@ -5692,6 +5874,8 @@
tapan->aux_pga_cnt = 0;
tapan->aux_l_gain = 0x1F;
tapan->aux_r_gain = 0x1F;
+ tapan->ldo_h_users = 0;
+ tapan->micb_2_users = 0;
tapan_update_reg_defaults(codec);
tapan_update_reg_mclk_rate(wcd9xxx);
tapan_codec_init_reg(codec);
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 673b634..725c51f 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -1235,49 +1235,49 @@
SOC_SINGLE_TLV("HPHR Volume", TABLA_A_RX_HPH_R_GAIN, 0, 12, 1,
line_gain),
- SOC_SINGLE_S8_TLV("RX1 Digital Volume", TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
- -84, 40, digital_gain),
- SOC_SINGLE_S8_TLV("RX2 Digital Volume", TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
- -84, 40, digital_gain),
- SOC_SINGLE_S8_TLV("RX3 Digital Volume", TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
- -84, 40, digital_gain),
- SOC_SINGLE_S8_TLV("RX4 Digital Volume", TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
- -84, 40, digital_gain),
- SOC_SINGLE_S8_TLV("RX5 Digital Volume", TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
- -84, 40, digital_gain),
- SOC_SINGLE_S8_TLV("RX6 Digital Volume", TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
- -84, 40, digital_gain),
- SOC_SINGLE_S8_TLV("RX7 Digital Volume", TABLA_A_CDC_RX7_VOL_CTL_B2_CTL,
- -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("RX1 Digital Volume", TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("RX2 Digital Volume", TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("RX3 Digital Volume", TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("RX4 Digital Volume", TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("RX5 Digital Volume", TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("RX6 Digital Volume", TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("RX7 Digital Volume", TABLA_A_CDC_RX7_VOL_CTL_B2_CTL,
+ 0, -84, 40, digital_gain),
- SOC_SINGLE_S8_TLV("DEC1 Volume", TABLA_A_CDC_TX1_VOL_CTL_GAIN, -84, 40,
- digital_gain),
- SOC_SINGLE_S8_TLV("DEC2 Volume", TABLA_A_CDC_TX2_VOL_CTL_GAIN, -84, 40,
- digital_gain),
- SOC_SINGLE_S8_TLV("DEC3 Volume", TABLA_A_CDC_TX3_VOL_CTL_GAIN, -84, 40,
- digital_gain),
- SOC_SINGLE_S8_TLV("DEC4 Volume", TABLA_A_CDC_TX4_VOL_CTL_GAIN, -84, 40,
- digital_gain),
- SOC_SINGLE_S8_TLV("DEC5 Volume", TABLA_A_CDC_TX5_VOL_CTL_GAIN, -84, 40,
- digital_gain),
- SOC_SINGLE_S8_TLV("DEC6 Volume", TABLA_A_CDC_TX6_VOL_CTL_GAIN, -84, 40,
- digital_gain),
- SOC_SINGLE_S8_TLV("DEC7 Volume", TABLA_A_CDC_TX7_VOL_CTL_GAIN, -84, 40,
- digital_gain),
- SOC_SINGLE_S8_TLV("DEC8 Volume", TABLA_A_CDC_TX8_VOL_CTL_GAIN, -84, 40,
- digital_gain),
- SOC_SINGLE_S8_TLV("DEC9 Volume", TABLA_A_CDC_TX9_VOL_CTL_GAIN, -84, 40,
- digital_gain),
- SOC_SINGLE_S8_TLV("DEC10 Volume", TABLA_A_CDC_TX10_VOL_CTL_GAIN, -84,
+ SOC_SINGLE_SX_TLV("DEC1 Volume", TABLA_A_CDC_TX1_VOL_CTL_GAIN, 0, -84,
40, digital_gain),
- SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", TABLA_A_CDC_IIR1_GAIN_B1_CTL, -84,
+ SOC_SINGLE_SX_TLV("DEC2 Volume", TABLA_A_CDC_TX2_VOL_CTL_GAIN, 0, -84,
40, digital_gain),
- SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", TABLA_A_CDC_IIR1_GAIN_B2_CTL, -84,
+ SOC_SINGLE_SX_TLV("DEC3 Volume", TABLA_A_CDC_TX3_VOL_CTL_GAIN, 0, -84,
40, digital_gain),
- SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", TABLA_A_CDC_IIR1_GAIN_B3_CTL, -84,
+ SOC_SINGLE_SX_TLV("DEC4 Volume", TABLA_A_CDC_TX4_VOL_CTL_GAIN, 0, -84,
40, digital_gain),
- SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", TABLA_A_CDC_IIR1_GAIN_B4_CTL, -84,
+ SOC_SINGLE_SX_TLV("DEC5 Volume", TABLA_A_CDC_TX5_VOL_CTL_GAIN, 0, -84,
40, digital_gain),
+ SOC_SINGLE_SX_TLV("DEC6 Volume", TABLA_A_CDC_TX6_VOL_CTL_GAIN, 0, -84,
+ 40, digital_gain),
+ SOC_SINGLE_SX_TLV("DEC7 Volume", TABLA_A_CDC_TX7_VOL_CTL_GAIN, 0, -84,
+ 40, digital_gain),
+ SOC_SINGLE_SX_TLV("DEC8 Volume", TABLA_A_CDC_TX8_VOL_CTL_GAIN, 0, -84,
+ 40, digital_gain),
+ SOC_SINGLE_SX_TLV("DEC9 Volume", TABLA_A_CDC_TX9_VOL_CTL_GAIN, 0, -84,
+ 40, digital_gain),
+ SOC_SINGLE_SX_TLV("DEC10 Volume", TABLA_A_CDC_TX10_VOL_CTL_GAIN, 0,
+ -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("IIR1 INP1 Volume", TABLA_A_CDC_IIR1_GAIN_B1_CTL, 0,
+ -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("IIR1 INP2 Volume", TABLA_A_CDC_IIR1_GAIN_B2_CTL, 0,
+ -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("IIR1 INP3 Volume", TABLA_A_CDC_IIR1_GAIN_B3_CTL, 0,
+ -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("IIR1 INP4 Volume", TABLA_A_CDC_IIR1_GAIN_B4_CTL, 0,
+ -84, 40, digital_gain),
SOC_SINGLE_TLV("ADC1 Volume", TABLA_A_TX_1_2_EN, 5, 3, 0, analog_gain),
SOC_SINGLE_TLV("ADC2 Volume", TABLA_A_TX_1_2_EN, 1, 3, 0, analog_gain),
SOC_SINGLE_TLV("ADC3 Volume", TABLA_A_TX_3_4_EN, 5, 3, 0, analog_gain),
@@ -2155,7 +2155,7 @@
goto err;
}
rtn:
- snd_soc_dapm_mux_update_power(widget, kcontrol, 1, widget->value, e);
+ snd_soc_dapm_mux_update_power(widget, kcontrol, widget->value, e);
mutex_unlock(&codec->mutex);
return 0;
err:
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 9cad1e5..f874c43 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -260,6 +260,8 @@
#define TAIKO_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
+#define TAIKO_SLIM_PGD_PORT_INT_TX_EN0 (TAIKO_SLIM_PGD_PORT_INT_EN0 + 2)
+
enum {
AIF1_PB = 0,
AIF1_CAP,
@@ -3402,6 +3404,7 @@
TAIKO_A_TX_7_MBHC_EN, 0x80, 00);
ret |= taiko_codec_enable_anc(w, kcontrol, event);
}
+ break;
case SND_SOC_DAPM_POST_PMD:
ret = taiko_hph_pa_event(w, kcontrol, event);
break;
@@ -4884,6 +4887,46 @@
return ret;
}
+static void taiko_codec_enable_int_port(struct wcd9xxx_codec_dai_data *dai,
+ struct snd_soc_codec *codec)
+{
+ struct wcd9xxx_ch *ch;
+ int port_num = 0;
+ unsigned short reg = 0;
+ u8 val = 0;
+ if (!dai || !codec) {
+ pr_err("%s: Invalid params\n", __func__);
+ return;
+ }
+ list_for_each_entry(ch, &dai->wcd9xxx_ch_list, list) {
+ if (ch->port >= TAIKO_RX_PORT_START_NUMBER) {
+ port_num = ch->port - TAIKO_RX_PORT_START_NUMBER;
+ reg = TAIKO_SLIM_PGD_PORT_INT_EN0 + (port_num / 8);
+ val = wcd9xxx_interface_reg_read(codec->control_data,
+ reg);
+ if (!(val & (1 << (port_num % 8)))) {
+ val |= (1 << (port_num % 8));
+ wcd9xxx_interface_reg_write(
+ codec->control_data, reg, val);
+ val = wcd9xxx_interface_reg_read(
+ codec->control_data, reg);
+ }
+ } else {
+ port_num = ch->port;
+ reg = TAIKO_SLIM_PGD_PORT_INT_TX_EN0 + (port_num / 8);
+ val = wcd9xxx_interface_reg_read(codec->control_data,
+ reg);
+ if (!(val & (1 << (port_num % 8)))) {
+ val |= (1 << (port_num % 8));
+ wcd9xxx_interface_reg_write(codec->control_data,
+ reg, val);
+ val = wcd9xxx_interface_reg_read(
+ codec->control_data, reg);
+ }
+ }
+ }
+}
+
static int taiko_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event)
@@ -4910,6 +4953,7 @@
switch (event) {
case SND_SOC_DAPM_POST_PMU:
+ taiko_codec_enable_int_port(dai, codec);
(void) taiko_codec_enable_slim_chmask(dai, true);
ret = wcd9xxx_cfg_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
dai->rate, dai->bit_width,
@@ -4974,12 +5018,7 @@
/*Enable spkr VI clocks*/
snd_soc_update_bits(codec,
TAIKO_A_CDC_CLK_TX_CLK_EN_B2_CTL, 0xC, 0xC);
- /*Enable Voltage Decimator*/
- snd_soc_update_bits(codec,
- TAIKO_A_CDC_CONN_TX_SB_B9_CTL, 0x1F, 0x12);
- /*Enable Current Decimator*/
- snd_soc_update_bits(codec,
- TAIKO_A_CDC_CONN_TX_SB_B10_CTL, 0x1F, 0x13);
+ taiko_codec_enable_int_port(dai, codec);
(void) taiko_codec_enable_slim_chmask(dai, true);
ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
dai->rate, dai->bit_width,
@@ -4991,13 +5030,6 @@
if (ret)
pr_err("%s error in close_slim_sch_tx %d\n",
__func__, ret);
- /*Disable Voltage decimator*/
- snd_soc_update_bits(codec,
- TAIKO_A_CDC_CONN_TX_SB_B9_CTL, 0x1F, 0x0);
- /*Disable Current decimator*/
- snd_soc_update_bits(codec,
- TAIKO_A_CDC_CONN_TX_SB_B10_CTL, 0x1F, 0x0);
- /*Disable spkr VI clocks*/
snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_TX_CLK_EN_B2_CTL,
0xC, 0x0);
/*Disable V&I sensing*/
@@ -5034,6 +5066,7 @@
dai = &taiko_p->dai[w->shift];
switch (event) {
case SND_SOC_DAPM_POST_PMU:
+ taiko_codec_enable_int_port(dai, codec);
(void) taiko_codec_enable_slim_chmask(dai, true);
ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
dai->rate, dai->bit_width,
@@ -5642,8 +5675,9 @@
unsigned long status = 0;
int i, j, port_id, k;
u32 bit;
- u8 val;
+ u8 val, int_val = 0;
bool tx, cleared;
+ unsigned short reg = 0;
for (i = TAIKO_SLIM_PGD_PORT_INT_STATUS_RX_0, j = 0;
i <= TAIKO_SLIM_PGD_PORT_INT_STATUS_TX_1; i++, j++) {
@@ -5658,12 +5692,28 @@
TAIKO_SLIM_PGD_PORT_INT_RX_SOURCE0 + j);
if (val & TAIKO_SLIM_IRQ_OVERFLOW)
pr_err_ratelimited(
- "%s: overflow error on %s port %d, value %x\n",
- __func__, (tx ? "TX" : "RX"), port_id, val);
+ "%s: overflow error on %s port %d, value %x\n",
+ __func__, (tx ? "TX" : "RX"), port_id, val);
if (val & TAIKO_SLIM_IRQ_UNDERFLOW)
pr_err_ratelimited(
- "%s: underflow error on %s port %d, value %x\n",
- __func__, (tx ? "TX" : "RX"), port_id, val);
+ "%s: underflow error on %s port %d, value %x\n",
+ __func__, (tx ? "TX" : "RX"), port_id, val);
+ if ((val & TAIKO_SLIM_IRQ_OVERFLOW) ||
+ (val & TAIKO_SLIM_IRQ_UNDERFLOW)) {
+ if (!tx)
+ reg = TAIKO_SLIM_PGD_PORT_INT_EN0 +
+ (port_id / 8);
+ else
+ reg = TAIKO_SLIM_PGD_PORT_INT_TX_EN0 +
+ (port_id / 8);
+ int_val = wcd9xxx_interface_reg_read(
+ codec->control_data, reg);
+ if (int_val & (1 << (port_id % 8))) {
+ int_val = int_val ^ (1 << (port_id % 8));
+ wcd9xxx_interface_reg_write(codec->control_data,
+ reg, int_val);
+ }
+ }
if (val & TAIKO_SLIM_IRQ_PORT_CLOSED) {
/*
* INT SOURCE register starts from RX to TX
@@ -5988,6 +6038,10 @@
/* Set HPH Path to low power mode */
TAIKO_REG_VAL(TAIKO_A_RX_HPH_BIAS_PA, 0x55),
+
+ /* BUCK default */
+ TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_4, 0x51),
+ TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_1, 0x5B),
};
static const struct wcd9xxx_reg_mask_val taiko_1_0_reg_defaults[] = {
@@ -5996,13 +6050,9 @@
* Taiko 2.0 will have appropriate defaults for these registers.
*/
- /* BUCK default */
- TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_4, 0x50),
-
/* Required defaults for class H operation */
TAIKO_REG_VAL(TAIKO_A_RX_HPH_CHOP_CTL, 0xF4),
TAIKO_REG_VAL(TAIKO_A_BIAS_CURR_CTL_2, 0x08),
- TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_1, 0x5B),
TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_3, 0x60),
/* Choose max non-overlap time for NCP */
@@ -6053,7 +6103,7 @@
TAIKO_REG_VAL(TAIKO_A_CDC_TX_5_6_ADC_IB, 0x44),
TAIKO_REG_VAL(WCD9XXX_A_BUCK_MODE_3, 0xCE),
TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_VCL_1, 0x8),
- TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_4, 0x51),
+ TAIKO_REG_VAL(TAIKO_A_BUCK_CTRL_CCL_4, 0x51),
TAIKO_REG_VAL(TAIKO_A_NCP_DTEST, 0x10),
TAIKO_REG_VAL(TAIKO_A_RX_HPH_CHOP_CTL, 0xA4),
TAIKO_REG_VAL(TAIKO_A_RX_HPH_OCP_CTL, 0x69),
@@ -6094,6 +6144,7 @@
TAIKO_REG_VAL(TAIKO_A_CDC_SPKR_CLIPDET_B1_CTL, 0x0),
TAIKO_REG_VAL(TAIKO_A_CDC_COMP0_B4_CTL, 0x37),
TAIKO_REG_VAL(TAIKO_A_CDC_COMP0_B5_CTL, 0x7f),
+ TAIKO_REG_VAL(TAIKO_A_CDC_COMP0_B5_CTL, 0x7f),
};
static void taiko_update_reg_defaults(struct snd_soc_codec *codec)
diff --git a/sound/soc/codecs/wcd9xxx-common.c b/sound/soc/codecs/wcd9xxx-common.c
index 05f2191..b104a6b 100644
--- a/sound/soc/codecs/wcd9xxx-common.c
+++ b/sound/soc/codecs/wcd9xxx-common.c
@@ -22,12 +22,11 @@
#define CLSH_COMPUTE_HPH_L 0x02
#define CLSH_COMPUTE_HPH_R 0x03
+#define BUCK_VREF_0P494V 0x3F
#define BUCK_VREF_2V 0xFF
+#define BUCK_VREF_0P494V 0x3F
#define BUCK_VREF_1P8V 0xE6
-#define NCP_FCLK_LEVEL_8 0x08
-#define NCP_FCLK_LEVEL_5 0x05
-
#define BUCK_SETTLE_TIME_US 50
#define NCP_SETTLE_TIME_US 50
@@ -414,12 +413,16 @@
{32164, 22},
};
-static inline void wcd9xxx_enable_clsh_block(
- struct snd_soc_codec *codec,
- bool on)
+static inline void
+wcd9xxx_enable_clsh_block(struct snd_soc_codec *codec,
+ struct wcd9xxx_clsh_cdc_data *clsh_d, bool enable)
{
- snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_B1_CTL,
- 0x01, on ? 0x01 : 0x00);
+ if ((enable && ++clsh_d->clsh_users == 1) ||
+ (!enable && --clsh_d->clsh_users == 0))
+ snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_B1_CTL,
+ 0x01, enable ? 0x01 : 0x00);
+ dev_dbg(codec->dev, "%s: clsh_users %d, enable %d", __func__,
+ clsh_d->clsh_users, enable);
}
static inline void wcd9xxx_enable_anc_delay(
@@ -430,64 +433,56 @@
0x02, on ? 0x02 : 0x00);
}
-static inline void wcd9xxx_enable_ncp(
- struct snd_soc_codec *codec,
- bool on)
+static inline void
+wcd9xxx_enable_buck(struct snd_soc_codec *codec,
+ struct wcd9xxx_clsh_cdc_data *clsh_d, bool enable)
{
- snd_soc_update_bits(codec, WCD9XXX_A_NCP_EN,
- 0x01, on ? 0x01 : 0x00);
+ if ((enable && ++clsh_d->buck_users == 1) ||
+ (!enable && --clsh_d->buck_users == 0))
+ snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_1,
+ 0x80, enable ? 0x80 : 0x00);
+ dev_dbg(codec->dev, "%s: buck_users %d, enable %d", __func__,
+ clsh_d->buck_users, enable);
}
-static inline void wcd9xxx_enable_buck(
- struct snd_soc_codec *codec,
- bool on)
-{
- snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_1,
- 0x80, on ? 0x80 : 0x00);
-}
+static void (*clsh_state_fp[NUM_CLSH_STATES])(struct snd_soc_codec *,
+ struct wcd9xxx_clsh_cdc_data *,
+ u8 req_state, bool req_type);
-static int cdc_lo_count;
-
-static void (*clsh_state_fp[NUM_CLSH_STATES])
- (struct snd_soc_codec *,
- struct wcd9xxx_clsh_cdc_data *,
- u8 req_state, bool req_type);
-
-static const char *state_to_str(u8 state)
-{
- if (state == WCD9XXX_CLSH_STATE_IDLE)
- return "STATE_IDLE";
- else if (state == WCD9XXX_CLSH_STATE_EAR)
- return "STATE_EAR";
- else if (state == WCD9XXX_CLSH_STATE_HPHL)
- return "STATE_HPH_L";
- else if (state == WCD9XXX_CLSH_STATE_HPHR)
- return "STATE_HPH_R";
- else if (state == (WCD9XXX_CLSH_STATE_HPHL
- | WCD9XXX_CLSH_STATE_HPHR))
- return "STATE_HPH_L_R";
- else if (state == WCD9XXX_CLSH_STATE_LO)
- return "STATE_LO";
-
- return "UNKNOWN_STATE";
-}
-
-static void wcd9xxx_cfg_clsh_buck(
- struct snd_soc_codec *codec)
+static const char *state_to_str(u8 state, char *buf, size_t buflen)
{
int i;
- const struct wcd9xxx_reg_mask_val reg_set[] = {
- {WCD9XXX_A_BUCK_CTRL_CCL_4, 0x0B, 0x00},
- {WCD9XXX_A_BUCK_CTRL_CCL_1, 0xF0, 0x50},
- {WCD9XXX_A_BUCK_CTRL_CCL_3, 0x03, 0x00},
- {WCD9XXX_A_BUCK_CTRL_CCL_3, 0x0B, 0x00},
+ int cnt = 0;
+ /*
+ * This array of strings should match with enum wcd9xxx_clsh_state_bit.
+ */
+ const char *states[] = {
+ "STATE_EAR",
+ "STATE_HPH_L",
+ "STATE_HPH_R",
+ "STATE_LO",
};
- for (i = 0; i < ARRAY_SIZE(reg_set); i++)
- snd_soc_update_bits(codec, reg_set[i].reg, reg_set[i].mask,
- reg_set[i].val);
+ if (state == WCD9XXX_CLSH_STATE_IDLE) {
+ snprintf(buf, buflen, "[STATE_IDLE]");
+ goto done;
+ }
- dev_dbg(codec->dev, "%s: Programmed buck parameters", __func__);
+ buf[0] = '\0';
+ for (i = 0; i < ARRAY_SIZE(states); i++) {
+ if (!(state & (1 << i)))
+ continue;
+ cnt = snprintf(buf, buflen - cnt - 1, "%s%s%s", buf,
+ buf[0] == '\0' ? "[" : "|",
+ states[i]);
+ }
+ if (cnt > 0)
+ strlcat(buf + cnt, "]", buflen);
+
+done:
+ if (buf[0] == '\0')
+ snprintf(buf, buflen, "[STATE_UNKNOWN]");
+ return buf;
}
static void wcd9xxx_cfg_clsh_param_common(
@@ -515,26 +510,25 @@
__func__);
}
-static void wcd9xxx_chargepump_request(
- struct snd_soc_codec *codec, bool on)
+static void wcd9xxx_chargepump_request(struct snd_soc_codec *codec, bool on)
{
static int cp_count;
if (on && (++cp_count == 1)) {
snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL,
- 0x01, 0x01);
+ 0x01, 0x01);
dev_dbg(codec->dev, "%s: Charge Pump enabled, count = %d\n",
- __func__, cp_count);
- }
-
- else if (!on) {
+ __func__, cp_count);
+ } else if (!on) {
if (--cp_count < 0) {
- dev_dbg(codec->dev, "%s: Unbalanced disable for charge pump\n",
+ dev_dbg(codec->dev,
+ "%s: Unbalanced disable for charge pump\n",
+ __func__);
+ if (snd_soc_read(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL) &
+ 0x01) {
+ dev_dbg(codec->dev,
+ "%s: Actual chargepump is ON\n",
__func__);
- if (snd_soc_read(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL)
- & 0x01) {
- dev_dbg(codec->dev, "%s: Actual chargepump is ON\n",
- __func__);
}
cp_count = 0;
WARN_ON(1);
@@ -542,9 +536,10 @@
if (cp_count == 0) {
snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL,
- 0x01, 0x00);
- dev_dbg(codec->dev, "%s: Charge pump disabled, count = %d\n",
- __func__, cp_count);
+ 0x01, 0x00);
+ dev_dbg(codec->dev,
+ "%s: Charge pump disabled, count = %d\n",
+ __func__, cp_count);
}
}
}
@@ -617,7 +612,6 @@
}
}
-
int wcd9xxx_soc_update_bits_push(struct snd_soc_codec *codec,
struct list_head *list,
uint16_t reg, uint8_t mask,
@@ -657,18 +651,15 @@
}
EXPORT_SYMBOL(wcd9xxx_restore_registers);
-static void wcd9xxx_enable_buck_mode(struct snd_soc_codec *codec,
- u8 buck_vref)
+static void wcd9xxx_set_buck_mode(struct snd_soc_codec *codec, u8 buck_vref)
{
int i;
const struct wcd9xxx_reg_mask_val reg_set[] = {
- {WCD9XXX_A_BUCK_MODE_5, 0x02, 0x03},
+ {WCD9XXX_A_BUCK_MODE_5, 0x02, 0x02},
{WCD9XXX_A_BUCK_MODE_4, 0xFF, buck_vref},
{WCD9XXX_A_BUCK_MODE_1, 0x04, 0x04},
- {WCD9XXX_A_BUCK_MODE_1, 0x08, 0x00},
{WCD9XXX_A_BUCK_MODE_3, 0x04, 0x00},
{WCD9XXX_A_BUCK_MODE_3, 0x08, 0x00},
- {WCD9XXX_A_BUCK_MODE_1, 0x80, 0x80},
};
for (i = 0; i < ARRAY_SIZE(reg_set); i++)
@@ -704,25 +695,51 @@
}
-static void wcd9xxx_set_fclk_enable_ncp(struct snd_soc_codec *codec,
- u8 fclk_level)
+static void wcd9xxx_set_fclk_get_ncp(struct snd_soc_codec *codec,
+ struct wcd9xxx_clsh_cdc_data *clsh_d,
+ enum ncp_fclk_level fclk_level)
{
- int i;
- const struct wcd9xxx_reg_mask_val reg_set[] = {
- {WCD9XXX_A_NCP_STATIC, 0x20, 0x20},
- {WCD9XXX_A_NCP_EN, 0x01, 0x01},
- };
- snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
- 0x010, 0x00);
- snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
- 0x0F, fclk_level);
- for (i = 0; i < ARRAY_SIZE(reg_set); i++)
- snd_soc_update_bits(codec, reg_set[i].reg,
- reg_set[i].mask, reg_set[i].val);
+ clsh_d->ncp_users[fclk_level]++;
- usleep_range(NCP_SETTLE_TIME_US, NCP_SETTLE_TIME_US);
+ pr_debug("%s: enter ncp type %d users fclk8 %d, fclk5 %d\n", __func__,
+ fclk_level, clsh_d->ncp_users[NCP_FCLK_LEVEL_8],
+ clsh_d->ncp_users[NCP_FCLK_LEVEL_5]);
- dev_dbg(codec->dev, "%s: set ncp done\n", __func__);
+ snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC, 0x10, 0x00);
+ /* fclk level 8 dominates level 5 */
+ if (clsh_d->ncp_users[NCP_FCLK_LEVEL_8] > 0)
+ snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC, 0x0F, 0x08);
+ else if (clsh_d->ncp_users[NCP_FCLK_LEVEL_5] > 0)
+ snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC, 0x0F, 0x05);
+ else
+ WARN_ONCE(1, "Unexpected users %d,%d\n",
+ clsh_d->ncp_users[NCP_FCLK_LEVEL_8],
+ clsh_d->ncp_users[NCP_FCLK_LEVEL_5]);
+ snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC, 0x20, 0x20);
+
+ /* enable NCP and wait until settles down */
+ if (snd_soc_update_bits(codec, WCD9XXX_A_NCP_EN, 0x01, 0x01))
+ usleep_range(NCP_SETTLE_TIME_US, NCP_SETTLE_TIME_US);
+ pr_debug("%s: leave\n", __func__);
+}
+
+static void wcd9xxx_set_fclk_put_ncp(struct snd_soc_codec *codec,
+ struct wcd9xxx_clsh_cdc_data *clsh_d,
+ enum ncp_fclk_level fclk_level)
+{
+ clsh_d->ncp_users[fclk_level]--;
+
+ pr_debug("%s: enter ncp type %d users fclk8 %d, fclk5 %d\n", __func__,
+ fclk_level, clsh_d->ncp_users[NCP_FCLK_LEVEL_8],
+ clsh_d->ncp_users[NCP_FCLK_LEVEL_5]);
+
+ if (clsh_d->ncp_users[NCP_FCLK_LEVEL_8] == 0 &&
+ clsh_d->ncp_users[NCP_FCLK_LEVEL_5] == 0)
+ snd_soc_update_bits(codec, WCD9XXX_A_NCP_EN, 0x01, 0x00);
+ else if (clsh_d->ncp_users[NCP_FCLK_LEVEL_8] == 0)
+ /* if dominating level 8 has gone, switch to 5 */
+ snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC, 0x0F, 0x05);
+ pr_debug("%s: leave\n", __func__);
}
static void wcd9xxx_cfg_clsh_param_ear(struct snd_soc_codec *codec)
@@ -790,72 +807,30 @@
__func__);
}
-static void wcd9xxx_clsh_turnoff_postpa
- (struct snd_soc_codec *codec)
-{
-
- int i;
-
- const struct wcd9xxx_reg_mask_val reg_set[] = {
- {WCD9XXX_A_NCP_EN, 0x01, 0x00},
- {WCD9XXX_A_BUCK_MODE_1, 0x80, 0x00},
- {WCD9XXX_A_CDC_CLSH_B1_CTL, 0x10, 0x00},
- };
-
- wcd9xxx_chargepump_request(codec, false);
-
- for (i = 0; i < ARRAY_SIZE(reg_set); i++)
- snd_soc_update_bits(codec, reg_set[i].reg,
- reg_set[i].mask, reg_set[i].val);
-
- wcd9xxx_enable_clsh_block(codec, false);
-
- dev_dbg(codec->dev, "%s: Done\n", __func__);
-}
-
-static void wcd9xxx_clsh_state_idle(struct snd_soc_codec *codec,
- struct wcd9xxx_clsh_cdc_data *clsh_d,
- u8 req_state, bool is_enable)
-{
- if (is_enable) {
- dev_dbg(codec->dev, "%s: wrong transition, cannot enable IDLE state\n",
- __func__);
- } else {
- if (req_state == WCD9XXX_CLSH_STATE_EAR) {
- wcd9xxx_clsh_turnoff_postpa(codec);
- } else if (req_state == WCD9XXX_CLSH_STATE_HPHL) {
- wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L,
- false);
- wcd9xxx_clsh_turnoff_postpa(codec);
- } else if (req_state == WCD9XXX_CLSH_STATE_HPHR) {
- wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R,
- false);
- wcd9xxx_clsh_turnoff_postpa(codec);
- } else if (req_state == WCD9XXX_CLSH_STATE_LO) {
- wcd9xxx_enable_ncp(codec, false);
- wcd9xxx_enable_buck(codec, false);
- }
- }
-}
-
static void wcd9xxx_clsh_state_ear(struct snd_soc_codec *codec,
struct wcd9xxx_clsh_cdc_data *clsh_d,
u8 req_state, bool is_enable)
{
+ pr_debug("%s: enter %s\n", __func__, is_enable ? "enable" : "disable");
if (is_enable) {
- wcd9xxx_cfg_clsh_buck(codec);
wcd9xxx_cfg_clsh_param_common(codec);
wcd9xxx_cfg_clsh_param_ear(codec);
- wcd9xxx_enable_clsh_block(codec, true);
+ wcd9xxx_enable_clsh_block(codec, clsh_d, true);
wcd9xxx_chargepump_request(codec, true);
wcd9xxx_enable_anc_delay(codec, true);
wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_EAR, true);
- wcd9xxx_enable_buck_mode(codec, BUCK_VREF_2V);
- wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_8);
+ wcd9xxx_set_buck_mode(codec, BUCK_VREF_2V);
+ wcd9xxx_enable_buck(codec, clsh_d, true);
+ wcd9xxx_set_fclk_get_ncp(codec, clsh_d, NCP_FCLK_LEVEL_8);
dev_dbg(codec->dev, "%s: Enabled ear mode class h\n", __func__);
} else {
dev_dbg(codec->dev, "%s: stub fallback to ear\n", __func__);
+ wcd9xxx_set_fclk_put_ncp(codec, clsh_d, NCP_FCLK_LEVEL_8);
+ wcd9xxx_enable_buck(codec, clsh_d, false);
+ wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_EAR, true);
+ wcd9xxx_chargepump_request(codec, false);
+ wcd9xxx_enable_clsh_block(codec, clsh_d, false);
}
}
@@ -863,26 +838,26 @@
struct wcd9xxx_clsh_cdc_data *clsh_d,
u8 req_state, bool is_enable)
{
+ pr_debug("%s: enter %s\n", __func__, is_enable ? "enable" : "disable");
+
if (is_enable) {
- wcd9xxx_cfg_clsh_buck(codec);
wcd9xxx_cfg_clsh_param_common(codec);
wcd9xxx_cfg_clsh_param_hph(codec);
- wcd9xxx_enable_clsh_block(codec, true);
+ wcd9xxx_enable_clsh_block(codec, clsh_d, true);
wcd9xxx_chargepump_request(codec, true);
wcd9xxx_enable_anc_delay(codec, true);
wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L, true);
- wcd9xxx_enable_buck_mode(codec, BUCK_VREF_2V);
- wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_8);
+ wcd9xxx_set_buck_mode(codec, BUCK_VREF_0P494V);
+ wcd9xxx_enable_buck(codec, clsh_d, true);
+ wcd9xxx_set_fclk_get_ncp(codec, clsh_d, NCP_FCLK_LEVEL_8);
dev_dbg(codec->dev, "%s: Done\n", __func__);
} else {
- if (req_state == WCD9XXX_CLSH_STATE_HPHR) {
- wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R,
- false);
- } else {
- dev_dbg(codec->dev, "%s: stub fallback to hph_l\n",
- __func__);
- }
+ wcd9xxx_set_fclk_put_ncp(codec, clsh_d, NCP_FCLK_LEVEL_8);
+ wcd9xxx_enable_buck(codec, clsh_d, false);
+ wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L, false);
+ wcd9xxx_chargepump_request(codec, false);
+ wcd9xxx_enable_clsh_block(codec, clsh_d, false);
}
}
@@ -890,27 +865,26 @@
struct wcd9xxx_clsh_cdc_data *clsh_d,
u8 req_state, bool is_enable)
{
- if (is_enable) {
+ pr_debug("%s: enter %s\n", __func__, is_enable ? "enable" : "disable");
- wcd9xxx_cfg_clsh_buck(codec);
+ if (is_enable) {
wcd9xxx_cfg_clsh_param_common(codec);
wcd9xxx_cfg_clsh_param_hph(codec);
- wcd9xxx_enable_clsh_block(codec, true);
+ wcd9xxx_enable_clsh_block(codec, clsh_d, true);
wcd9xxx_chargepump_request(codec, true);
wcd9xxx_enable_anc_delay(codec, true);
wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R, true);
- wcd9xxx_enable_buck_mode(codec, BUCK_VREF_2V);
- wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_8);
+ wcd9xxx_set_buck_mode(codec, BUCK_VREF_0P494V);
+ wcd9xxx_enable_buck(codec, clsh_d, true);
+ wcd9xxx_set_fclk_get_ncp(codec, clsh_d, NCP_FCLK_LEVEL_8);
dev_dbg(codec->dev, "%s: Done\n", __func__);
} else {
- if (req_state == WCD9XXX_CLSH_STATE_HPHL) {
- wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L,
- false);
- } else {
- dev_dbg(codec->dev, "%s: stub fallback to hph_r\n",
- __func__);
- }
+ wcd9xxx_set_fclk_put_ncp(codec, clsh_d, NCP_FCLK_LEVEL_8);
+ wcd9xxx_enable_buck(codec, clsh_d, false);
+ wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R, false);
+ wcd9xxx_chargepump_request(codec, false);
+ wcd9xxx_enable_clsh_block(codec, clsh_d, false);
}
}
@@ -918,9 +892,11 @@
struct wcd9xxx_clsh_cdc_data *clsh_d,
u8 req_state, bool is_enable)
{
+ pr_debug("%s: enter %s\n", __func__, is_enable ? "enable" : "disable");
+
if (is_enable) {
wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L, true);
- wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R, true);
+ wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R, true);
} else {
dev_dbg(codec->dev, "%s: stub fallback to hph_st\n", __func__);
}
@@ -930,38 +906,36 @@
struct wcd9xxx_clsh_cdc_data *clsh_d,
u8 req_state, bool is_enable)
{
- if (is_enable) {
- if (++cdc_lo_count > 1)
- return;
+ pr_debug("%s: enter %s, buck_mv %d\n", __func__,
+ is_enable ? "enable" : "disable", clsh_d->buck_mv);
- wcd9xxx_enable_buck_mode(codec, BUCK_VREF_1P8V);
- wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_5);
+ if (is_enable) {
+ wcd9xxx_set_buck_mode(codec, BUCK_VREF_1P8V);
+ wcd9xxx_enable_buck(codec, clsh_d, true);
+ wcd9xxx_set_fclk_get_ncp(codec, clsh_d, NCP_FCLK_LEVEL_5);
if (clsh_d->buck_mv == WCD9XXX_CDC_BUCK_MV_1P8) {
- wcd9xxx_enable_buck(codec, false);
+ wcd9xxx_enable_buck(codec, clsh_d, false);
snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
- 0x20, 0x01);
- wcd9xxx_enable_ncp(codec, true);
+ 1 << 4, 1 << 4);
/* NCP settle time recommended by codec specification */
usleep_range(NCP_SETTLE_TIME_US,
- NCP_SETTLE_TIME_US + 10);
-
+ NCP_SETTLE_TIME_US + 10);
} else {
- snd_soc_update_bits(codec, WCD9XXX_A_NCP_EN,
- 0x40, 0x00);
- wcd9xxx_enable_ncp(codec, true);
/* NCP settle time recommended by codec specification */
usleep_range(NCP_SETTLE_TIME_US,
- NCP_SETTLE_TIME_US + 10);
+ NCP_SETTLE_TIME_US + 10);
snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_5,
- 0x01, 0x01);
+ 0x01, (0x01 & 0x03));
snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_5,
- 0xFB, (0x02 << 2));
+ 0xFC, (0xFC & 0xB));
}
- snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_1,
- 0x04, 0x00);
+ snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_1, 0x04, 0x00);
} else {
dev_dbg(codec->dev, "%s: stub fallback to lineout\n", __func__);
+ wcd9xxx_set_fclk_put_ncp(codec, clsh_d, NCP_FCLK_LEVEL_5);
+ if (clsh_d->buck_mv != WCD9XXX_CDC_BUCK_MV_1P8)
+ wcd9xxx_enable_buck(codec, clsh_d, false);
}
}
@@ -969,9 +943,12 @@
struct wcd9xxx_clsh_cdc_data *clsh_d,
u8 req_state, bool is_enable)
{
- dev_dbg(codec->dev, "%s Wrong request for class H state machine requested to %s %s"
- , __func__, is_enable ? "enable" : "disable",
- state_to_str(req_state));
+ char msg[128];
+
+ dev_dbg(codec->dev,
+ "%s Wrong request for class H state machine requested to %s %s",
+ __func__, is_enable ? "enable" : "disable",
+ state_to_str(req_state, msg, sizeof(msg)));
WARN_ON(1);
}
@@ -980,51 +957,45 @@
u8 req_state, bool req_type, u8 clsh_event)
{
u8 old_state, new_state;
+ char msg0[128], msg1[128];
switch (clsh_event) {
-
case WCD9XXX_CLSH_EVENT_PRE_DAC:
-
/* PRE_DAC event should be used only for Enable */
BUG_ON(req_type != WCD9XXX_CLSH_REQ_ENABLE);
old_state = cdc_clsh_d->state;
new_state = old_state | req_state;
- (*clsh_state_fp[new_state]) (codec, cdc_clsh_d,
- req_state, req_type);
+ (*clsh_state_fp[req_state]) (codec, cdc_clsh_d, req_state,
+ req_type);
cdc_clsh_d->state = new_state;
dev_dbg(codec->dev, "%s: ClassH state transition from %s to %s\n",
- __func__, state_to_str(old_state),
- state_to_str(cdc_clsh_d->state));
+ __func__, state_to_str(old_state, msg0, sizeof(msg0)),
+ state_to_str(cdc_clsh_d->state, msg1, sizeof(msg1)));
break;
-
case WCD9XXX_CLSH_EVENT_POST_PA:
-
if (req_type == WCD9XXX_CLSH_REQ_DISABLE) {
- if (req_state == WCD9XXX_CLSH_STATE_LO
- && --cdc_lo_count > 0)
- break;
-
old_state = cdc_clsh_d->state;
new_state = old_state & (~req_state);
if (new_state < NUM_CLSH_STATES) {
- (*clsh_state_fp[new_state]) (codec, cdc_clsh_d,
- req_state, req_type);
+ (*clsh_state_fp[req_state]) (codec, cdc_clsh_d,
+ req_state,
+ req_type);
cdc_clsh_d->state = new_state;
dev_dbg(codec->dev, "%s: ClassH state transition from %s to %s\n",
- __func__, state_to_str(old_state),
- state_to_str(cdc_clsh_d->state));
+ __func__, state_to_str(old_state, msg0,
+ sizeof(msg0)),
+ state_to_str(cdc_clsh_d->state, msg1,
+ sizeof(msg1)));
} else {
dev_dbg(codec->dev, "%s: wrong new state = %x\n",
__func__, new_state);
}
-
-
- } else if (req_state != WCD9XXX_CLSH_STATE_LO) {
+ } else if (!(cdc_clsh_d->state & WCD9XXX_CLSH_STATE_LO)) {
wcd9xxx_clsh_enable_post_pa(codec, cdc_clsh_d);
}
@@ -1044,7 +1015,6 @@
for (i = 0; i < NUM_CLSH_STATES; i++)
clsh_state_fp[i] = wcd9xxx_clsh_state_err;
- clsh_state_fp[WCD9XXX_CLSH_STATE_IDLE] = wcd9xxx_clsh_state_idle;
clsh_state_fp[WCD9XXX_CLSH_STATE_EAR] = wcd9xxx_clsh_state_ear;
clsh_state_fp[WCD9XXX_CLSH_STATE_HPHL] =
wcd9xxx_clsh_state_hph_l;
diff --git a/sound/soc/codecs/wcd9xxx-common.h b/sound/soc/codecs/wcd9xxx-common.h
index 0239c86..324f6e9 100644
--- a/sound/soc/codecs/wcd9xxx-common.h
+++ b/sound/soc/codecs/wcd9xxx-common.h
@@ -63,11 +63,20 @@
u8 val;
};
+enum ncp_fclk_level {
+ NCP_FCLK_LEVEL_8,
+ NCP_FCLK_LEVEL_5,
+ NCP_FCLK_LEVEL_MAX,
+};
+
/* Class H data that the codec driver will maintain */
struct wcd9xxx_clsh_cdc_data {
u8 state;
int buck_mv;
bool is_dynamic_vdd_cp;
+ int clsh_users;
+ int buck_users;
+ int ncp_users[NCP_FCLK_LEVEL_MAX];
struct wcd9xxx_resmgr *resmgr;
};
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index 8d6c4bc..9e97f5f 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -90,7 +90,7 @@
#define WCD9XXX_HPHL_STATUS_READY_WAIT_US 1000
#define WCD9XXX_MUX_SWITCH_READY_WAIT_MS 50
-#define WCD9XXX_MEAS_DELTA_MAX_MV 50
+#define WCD9XXX_MEAS_DELTA_MAX_MV 120
#define WCD9XXX_MEAS_INVALD_RANGE_LOW_MV 20
#define WCD9XXX_MEAS_INVALD_RANGE_HIGH_MV 80
@@ -98,7 +98,7 @@
* Invalid voltage range for the detection
* of plug type with current source
*/
-#define WCD9XXX_CS_MEAS_INVALD_RANGE_LOW_MV 110
+#define WCD9XXX_CS_MEAS_INVALD_RANGE_LOW_MV 160
#define WCD9XXX_CS_MEAS_INVALD_RANGE_HIGH_MV 265
/*
@@ -121,14 +121,14 @@
#define WCD9XXX_V_CS_HS_MAX 500
#define WCD9XXX_V_CS_NO_MIC 5
#define WCD9XXX_MB_MEAS_DELTA_MAX_MV 80
-#define WCD9XXX_CS_MEAS_DELTA_MAX_MV 10
+#define WCD9XXX_CS_MEAS_DELTA_MAX_MV 12
static int impedance_detect_en;
module_param(impedance_detect_en, int,
S_IRUGO | S_IWUSR | S_IWGRP);
MODULE_PARM_DESC(impedance_detect_en, "enable/disable impedance detect");
-static bool detect_use_vddio_switch = true;
+static bool detect_use_vddio_switch;
struct wcd9xxx_mbhc_detect {
u16 dce;
@@ -213,7 +213,6 @@
/* called under codec_resource_lock acquisition */
static void wcd9xxx_start_hs_polling(struct wcd9xxx_mbhc *mbhc)
{
- s16 v_brh, v_b1_hu;
struct snd_soc_codec *codec = mbhc->codec;
int mbhc_state = mbhc->mbhc_state;
@@ -222,6 +221,19 @@
pr_debug("Polling is not active, do not start polling\n");
return;
}
+
+ /*
+ * setup internal micbias if codec uses internal micbias for
+ * headset detection
+ */
+ if (mbhc->mbhc_cfg->use_int_rbias) {
+ if (mbhc->mbhc_cb && mbhc->mbhc_cb->setup_int_rbias)
+ mbhc->mbhc_cb->setup_int_rbias(codec, true);
+ else
+ pr_err("%s: internal bias requested but codec did not provide callback\n",
+ __func__);
+ }
+
snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1, 0x04);
if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mux_bias_block)
mbhc->mbhc_cb->enable_mux_bias_block(codec);
@@ -241,17 +253,6 @@
/* set to max */
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL, 0x7F);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL, 0xFF);
-
- v_brh = wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_BR_H);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
- (v_brh >> 8) & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
- v_brh & 0xFF);
- v_b1_hu = wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_HU);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
- v_b1_hu & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
- (v_b1_hu >> 8) & 0xFF);
}
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x1);
@@ -312,22 +313,32 @@
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B2_CTL,
(d->v_ins_hu[MBHC_V_IDX_VDDIO] >> 8) &
0xFF);
- /* Threshods for button press */
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
- d->v_b1_hu[MBHC_V_IDX_VDDIO] & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
- (d->v_b1_hu[MBHC_V_IDX_VDDIO] >> 8) &
- 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL,
- d->v_b1_h[MBHC_V_IDX_VDDIO] & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
- (d->v_b1_h[MBHC_V_IDX_VDDIO] >> 8) &
- 0xFF);
- /* Threshods for button release */
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
- d->v_brh[MBHC_V_IDX_VDDIO] & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
- (d->v_brh[MBHC_V_IDX_VDDIO] >> 8) & 0xFF);
+
+ if (mbhc->mbhc_state != MBHC_STATE_POTENTIAL_RECOVERY) {
+ /* Threshods for button press */
+ snd_soc_write(codec,
+ WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
+ d->v_b1_hu[MBHC_V_IDX_VDDIO] & 0xFF);
+ snd_soc_write(codec,
+ WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
+ (d->v_b1_hu[MBHC_V_IDX_VDDIO] >> 8) &
+ 0xFF);
+ snd_soc_write(codec,
+ WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL,
+ d->v_b1_h[MBHC_V_IDX_VDDIO] & 0xFF);
+ snd_soc_write(codec,
+ WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
+ (d->v_b1_h[MBHC_V_IDX_VDDIO] >> 8) &
+ 0xFF);
+ /* Threshods for button release */
+ snd_soc_write(codec,
+ WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
+ d->v_brh[MBHC_V_IDX_VDDIO] & 0xFF);
+ snd_soc_write(codec,
+ WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
+ (d->v_brh[MBHC_V_IDX_VDDIO] >> 8) &
+ 0xFF);
+ }
pr_debug("%s: Programmed MBHC thresholds to VDDIO\n",
__func__);
}
@@ -363,22 +374,31 @@
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B2_CTL,
(d->v_ins_hu[MBHC_V_IDX_CFILT] >> 8) &
0xFF);
- /* Revert threshods for button press */
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
- d->v_b1_hu[MBHC_V_IDX_CFILT] & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
- (d->v_b1_hu[MBHC_V_IDX_CFILT] >> 8) &
- 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL,
- d->v_b1_h[MBHC_V_IDX_CFILT] & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
- (d->v_b1_h[MBHC_V_IDX_CFILT] >> 8) &
- 0xFF);
- /* Revert threshods for button release */
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
- d->v_brh[MBHC_V_IDX_CFILT] & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
- (d->v_brh[MBHC_V_IDX_CFILT] >> 8) & 0xFF);
+ if (mbhc->mbhc_state != MBHC_STATE_POTENTIAL_RECOVERY) {
+ /* Revert threshods for button press */
+ snd_soc_write(codec,
+ WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
+ d->v_b1_hu[MBHC_V_IDX_CFILT] & 0xFF);
+ snd_soc_write(codec,
+ WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
+ (d->v_b1_hu[MBHC_V_IDX_CFILT] >> 8) &
+ 0xFF);
+ snd_soc_write(codec,
+ WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL,
+ d->v_b1_h[MBHC_V_IDX_CFILT] & 0xFF);
+ snd_soc_write(codec,
+ WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
+ (d->v_b1_h[MBHC_V_IDX_CFILT] >> 8) &
+ 0xFF);
+ /* Revert threshods for button release */
+ snd_soc_write(codec,
+ WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
+ d->v_brh[MBHC_V_IDX_CFILT] & 0xFF);
+ snd_soc_write(codec,
+ WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
+ (d->v_brh[MBHC_V_IDX_CFILT] >> 8) &
+ 0xFF);
+ }
pr_debug("%s: Programmed MBHC thresholds to MICBIAS\n",
__func__);
}
@@ -476,19 +496,25 @@
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B1_CTL, v_ins_hu & 0xFF);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B2_CTL,
(v_ins_hu >> 8) & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL, v_b1_hu & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
- (v_b1_hu >> 8) & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL, v_b1_h & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
- (v_b1_h >> 8) & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL, v_brh & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
- (v_brh >> 8) & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B11_CTL,
- mbhc->mbhc_data.v_brl & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B12_CTL,
- (mbhc->mbhc_data.v_brl >> 8) & 0xFF);
+
+ if (mbhc->mbhc_state != MBHC_STATE_POTENTIAL_RECOVERY) {
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL, v_b1_hu &
+ 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
+ (v_b1_hu >> 8) & 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL, v_b1_h &
+ 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
+ (v_b1_h >> 8) & 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL, v_brh &
+ 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
+ (v_brh >> 8) & 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B11_CTL,
+ mbhc->mbhc_data.v_brl & 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B12_CTL,
+ (mbhc->mbhc_data.v_brl >> 8) & 0xFF);
+ }
}
static void wcd9xxx_codec_switch_cfilt_mode(struct wcd9xxx_mbhc *mbhc,
@@ -828,7 +854,8 @@
mbhc->zl = mbhc->zr = 0;
wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
0, WCD9XXX_JACK_MASK);
- mbhc->hph_status = 0;
+ mbhc->hph_status &= ~(SND_JACK_HEADSET |
+ SND_JACK_LINEOUT);
}
/* Report insertion */
mbhc->hph_status |= jack_type;
@@ -959,7 +986,9 @@
if (noreldetection)
wcd9xxx_turn_onoff_rel_detection(codec, false);
- snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x2, 0x0);
+ if (mbhc->mbhc_cfg->do_recalibration)
+ snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x2,
+ 0x0);
/* Turn on the override */
if (!override_bypass)
snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
@@ -969,8 +998,9 @@
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x4);
snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8,
0x0);
- snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x2,
- 0x2);
+ if (mbhc->mbhc_cfg->do_recalibration)
+ snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL,
+ 0x2, 0x2);
usleep_range(mbhc->mbhc_data.t_sta_dce,
mbhc->mbhc_data.t_sta_dce);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x4);
@@ -982,8 +1012,9 @@
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x2);
snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8,
0x0);
- snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x2,
- 0x2);
+ if (mbhc->mbhc_cfg->do_recalibration)
+ snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL,
+ 0x2, 0x2);
usleep_range(mbhc->mbhc_data.t_sta_dce,
mbhc->mbhc_data.t_sta_dce);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x2);
@@ -1094,8 +1125,8 @@
if (mbhc->mbhc_cb && mbhc->mbhc_cb->setup_int_rbias)
mbhc->mbhc_cb->setup_int_rbias(codec, true);
else
- pr_err("%s: internal bias is requested but codec did not provide callback\n",
- __func__);
+ pr_err("%s: internal bias requested but codec did not provide callback\n",
+ __func__);
}
snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1, 0x05, 0x01);
@@ -1127,48 +1158,59 @@
snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x2, 0x2);
snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
+ if (!mbhc->mbhc_cfg->do_recalibration) {
+ if (!is_cs_enable)
+ wcd9xxx_calibrate_hs_polling(mbhc);
+ }
+
/* don't flip override */
bias_value = __wcd9xxx_codec_sta_dce(mbhc, 1, true, true);
snd_soc_write(codec, mbhc->mbhc_bias_regs.cfilt_ctl, cfilt_mode);
snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x13, 0x00);
- /* recalibrate dce_z and sta_z */
- reg = snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B1_CTL);
- change = snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x78,
- btn_det->mbhc_nsc << 3);
- wcd9xxx_get_z(mbhc, &dce_z, &sta_z);
- if (change)
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, reg);
- if (dce_z && sta_z) {
- pr_debug("%s: sta_z 0x%x -> 0x%x, dce_z 0x%x -> 0x%x\n",
- __func__,
- mbhc->mbhc_data.sta_z, sta_z & 0xffff,
- mbhc->mbhc_data.dce_z, dce_z & 0xffff);
- mbhc->mbhc_data.dce_z = dce_z;
- mbhc->mbhc_data.sta_z = sta_z;
- wcd9xxx_mbhc_calc_thres(mbhc);
- wcd9xxx_calibrate_hs_polling(mbhc);
- } else {
- pr_warn("%s: failed get new dce_z/sta_z 0x%x/0x%x\n", __func__,
- dce_z, sta_z);
- }
-
- if (is_cs_enable) {
- /* recalibrate dce_nsc_cs_z */
- reg = snd_soc_read(mbhc->codec, WCD9XXX_A_CDC_MBHC_B1_CTL);
- snd_soc_update_bits(mbhc->codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
- 0x78, WCD9XXX_MBHC_NSC_CS << 3);
- wcd9xxx_get_z(mbhc, &dce_z, NULL);
- snd_soc_write(mbhc->codec, WCD9XXX_A_CDC_MBHC_B1_CTL, reg);
- if (dce_z) {
- pr_debug("%s: dce_nsc_cs_z 0x%x -> 0x%x\n", __func__,
- mbhc->mbhc_data.dce_nsc_cs_z, dce_z & 0xffff);
- mbhc->mbhc_data.dce_nsc_cs_z = dce_z;
+ if (mbhc->mbhc_cfg->do_recalibration) {
+ /* recalibrate dce_z and sta_z */
+ reg = snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B1_CTL);
+ change = snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
+ 0x78, btn_det->mbhc_nsc << 3);
+ wcd9xxx_get_z(mbhc, &dce_z, &sta_z);
+ if (change)
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, reg);
+ if (dce_z && sta_z) {
+ pr_debug("%s: sta_z 0x%x -> 0x%x, dce_z 0x%x -> 0x%x\n",
+ __func__,
+ mbhc->mbhc_data.sta_z, sta_z & 0xffff,
+ mbhc->mbhc_data.dce_z, dce_z & 0xffff);
+ mbhc->mbhc_data.dce_z = dce_z;
+ mbhc->mbhc_data.sta_z = sta_z;
+ wcd9xxx_mbhc_calc_thres(mbhc);
+ wcd9xxx_calibrate_hs_polling(mbhc);
} else {
- pr_debug("%s: failed get new dce_nsc_cs_z\n", __func__);
+ pr_warn("%s: failed get new dce_z/sta_z 0x%x/0x%x\n",
+ __func__, dce_z, sta_z);
+ }
+
+ if (is_cs_enable) {
+ /* recalibrate dce_nsc_cs_z */
+ reg = snd_soc_read(mbhc->codec,
+ WCD9XXX_A_CDC_MBHC_B1_CTL);
+ snd_soc_update_bits(mbhc->codec,
+ WCD9XXX_A_CDC_MBHC_B1_CTL,
+ 0x78, WCD9XXX_MBHC_NSC_CS << 3);
+ wcd9xxx_get_z(mbhc, &dce_z, NULL);
+ snd_soc_write(mbhc->codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
+ reg);
+ if (dce_z) {
+ pr_debug("%s: dce_nsc_cs_z 0x%x -> 0x%x\n",
+ __func__, mbhc->mbhc_data.dce_nsc_cs_z,
+ dce_z & 0xffff);
+ mbhc->mbhc_data.dce_nsc_cs_z = dce_z;
+ } else {
+ pr_debug("%s: failed get new dce_nsc_cs_z\n",
+ __func__);
+ }
}
}
-
return bias_value;
}
@@ -1289,6 +1331,7 @@
const struct wcd9xxx_mbhc_plug_type_cfg *plug_type =
WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
s16 hs_max, no_mic, dce_z;
+ int highhph_cnt = 0;
pr_debug("%s: enter\n", __func__);
pr_debug("%s: event_state 0x%lx\n", __func__, event_state);
@@ -1309,13 +1352,13 @@
vdce = __wcd9xxx_codec_sta_dce_v(mbhc, true, d->dce,
dce_z, (u32)mb_mv);
-
d->_vdces = vdce;
if (d->_vdces < no_mic)
d->_type = PLUG_TYPE_HEADPHONE;
- else if (d->_vdces >= hs_max)
+ else if (d->_vdces >= hs_max) {
d->_type = PLUG_TYPE_HIGH_HPH;
- else
+ highhph_cnt++;
+ } else
d->_type = PLUG_TYPE_HEADSET;
pr_debug("%s: DCE #%d, %04x, V %04d(%04d), HPHL %d TYPE %d\n",
@@ -1342,15 +1385,8 @@
}
}
- if (event_state & (1 << MBHC_EVENT_PA_HPHL)) {
- pr_debug("%s: HPHL PA was ON\n", __func__);
- } else if (ch != sz && ch > 0) {
- pr_debug("%s: Invalid, inconsistent HPHL\n", __func__);
- type = PLUG_TYPE_INVALID;
- goto exit;
- }
-
- delta_thr = highhph ? WCD9XXX_MB_MEAS_DELTA_MAX_MV :
+ delta_thr = ((highhph_cnt == sz) || highhph) ?
+ WCD9XXX_MB_MEAS_DELTA_MAX_MV :
WCD9XXX_CS_MEAS_DELTA_MAX_MV;
for (i = 0, d = dt; i < sz; i++, d++) {
@@ -1400,6 +1436,30 @@
}
}
+ if (type == PLUG_TYPE_HEADSET && dgnd && !dgnd->mic_bias) {
+ /* if plug type is Headphone report as GND_MIC_SWAP */
+ if (dgnd->_type == PLUG_TYPE_HEADPHONE) {
+ pr_debug("%s: GND_MIC_SWAP\n", __func__);
+ type = PLUG_TYPE_GND_MIC_SWAP;
+ /*
+ * if type is GND_MIC_SWAP we should not check
+ * HPHL status hence goto exit
+ */
+ goto exit;
+ } else if (dgnd->_type != PLUG_TYPE_HEADSET && !dmicbias) {
+ pr_debug("%s: Invalid, inconsistent types\n", __func__);
+ type = PLUG_TYPE_INVALID;
+ }
+ }
+
+ if (event_state & (1 << MBHC_EVENT_PA_HPHL)) {
+ pr_debug("%s: HPHL PA was ON\n", __func__);
+ } else if (ch != sz && ch > 0) {
+ pr_debug("%s: Invalid, inconsistent HPHL..\n", __func__);
+ type = PLUG_TYPE_INVALID;
+ goto exit;
+ }
+
if (!(event_state & (1UL << MBHC_EVENT_PA_HPHL))) {
if (((type == PLUG_TYPE_HEADSET ||
type == PLUG_TYPE_HEADPHONE) && ch != sz)) {
@@ -1408,17 +1468,12 @@
type = PLUG_TYPE_INVALID;
}
}
- if (type == PLUG_TYPE_HEADSET && dgnd && !dgnd->mic_bias) {
- if ((dgnd->_vdces + WCD9XXX_CS_GM_SWAP_THRES_MIN_MV <
- minv) &&
- (dgnd->_vdces + WCD9XXX_CS_GM_SWAP_THRES_MAX_MV >
- maxv))
- type = PLUG_TYPE_GND_MIC_SWAP;
- else if (dgnd->_type != PLUG_TYPE_HEADSET && !dmicbias) {
- pr_debug("%s: Invalid, inconsistent types\n", __func__);
- type = PLUG_TYPE_INVALID;
- }
- }
+
+ if (type == PLUG_TYPE_HEADSET &&
+ (mbhc->mbhc_cfg->micbias_enable_flags &
+ (1 << MBHC_MICBIAS_ENABLE_REGULAR_HEADSET)))
+ mbhc->micbias_enable = true;
+
exit:
pr_debug("%s: Plug type %d detected\n", __func__, type);
return type;
@@ -1735,6 +1790,7 @@
/* GND and MIC swap detection requires at least 2 rounds of DCE */
BUG_ON(NUM_DCE_PLUG_INS_DETECT < 2);
+ detect_use_vddio_switch = mbhc->mbhc_cfg->use_vddio_meas;
/*
* There are chances vddio switch is on and cfilt voltage is adjusted
@@ -2032,8 +2088,11 @@
pr_debug("%s: enter\n", __func__);
WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
- current_source_enable = ((mbhc->mbhc_cfg->cs_enable_flags &
- (1 << MBHC_CS_ENABLE_INSERTION)) != 0);
+
+ current_source_enable = (((mbhc->mbhc_cfg->cs_enable_flags &
+ (1 << MBHC_CS_ENABLE_INSERTION)) != 0) &&
+ (!(snd_soc_read(mbhc->codec,
+ mbhc->mbhc_bias_regs.ctl_reg) & 0x80)));
if (current_source_enable) {
wcd9xxx_turn_onoff_current_source(mbhc, true, false);
@@ -2158,9 +2217,10 @@
unsigned long retry = 0, timeout;
bool cs_enable;
- cs_enable = ((mbhc->mbhc_cfg->cs_enable_flags &
- (1 << MBHC_CS_ENABLE_REMOVAL)) != 0);
-
+ cs_enable = (((mbhc->mbhc_cfg->cs_enable_flags &
+ (1 << MBHC_CS_ENABLE_REMOVAL)) != 0) &&
+ (!(snd_soc_read(mbhc->codec,
+ mbhc->mbhc_bias_regs.ctl_reg) & 0x80)));
if (cs_enable)
wcd9xxx_turn_onoff_current_source(mbhc, true, false);
@@ -2672,8 +2732,11 @@
mbhc = container_of(work, struct wcd9xxx_mbhc, correct_plug_swch);
codec = mbhc->codec;
- current_source_enable = ((mbhc->mbhc_cfg->cs_enable_flags &
- (1 << MBHC_CS_ENABLE_POLLING)) != 0);
+
+ current_source_enable = (((mbhc->mbhc_cfg->cs_enable_flags &
+ (1 << MBHC_CS_ENABLE_POLLING)) != 0) &&
+ (!(snd_soc_read(codec,
+ mbhc->mbhc_bias_regs.ctl_reg) & 0x80)));
wcd9xxx_onoff_ext_mclk(mbhc, true);
@@ -2842,6 +2905,10 @@
if (wcd9xxx_cancel_btn_work(mbhc))
pr_debug("%s: button press is canceled\n", __func__);
+ /* cancel detect plug */
+ wcd9xxx_cancel_hs_detect_plug(mbhc,
+ &mbhc->correct_plug_swch);
+
insert = !wcd9xxx_swch_level_remove(mbhc);
pr_debug("%s: Current plug type %d, insert %d\n", __func__,
mbhc->current_plug, insert);
@@ -2849,9 +2916,6 @@
mbhc->lpi_enabled = false;
wmb();
- /* cancel detect plug */
- wcd9xxx_cancel_hs_detect_plug(mbhc,
- &mbhc->correct_plug_swch);
if ((mbhc->current_plug != PLUG_TYPE_NONE) &&
!(snd_soc_read(codec, WCD9XXX_A_MBHC_INSERT_DETECT) &
(1 << 1)))
@@ -2866,10 +2930,6 @@
mbhc->lpi_enabled = false;
wmb();
- /* cancel detect plug */
- wcd9xxx_cancel_hs_detect_plug(mbhc,
- &mbhc->correct_plug_swch);
-
if (mbhc->current_plug == PLUG_TYPE_HEADPHONE) {
wcd9xxx_report_plug(mbhc, 0, SND_JACK_HEADPHONE);
is_removed = true;
@@ -3111,15 +3171,22 @@
mv = ceilmv + btn_det->v_btn_press_delta_cic;
pr_debug("%s: reprogram vb1hu/vbrh to %dmv\n", __func__, mv);
- /* update LSB first so mbhc hardware block doesn't see too low value */
- v_b1_hu = wcd9xxx_codec_v_sta_dce(mbhc, STA, mv, false);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL, v_b1_hu & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
- (v_b1_hu >> 8) & 0xFF);
- v_brh = wcd9xxx_codec_v_sta_dce(mbhc, DCE, mv, false);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL, v_brh & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
- (v_brh >> 8) & 0xFF);
+ if (mbhc->mbhc_state != MBHC_STATE_POTENTIAL_RECOVERY) {
+ /*
+ * update LSB first so mbhc hardware block
+ * doesn't see too low value.
+ */
+ v_b1_hu = wcd9xxx_codec_v_sta_dce(mbhc, STA, mv, false);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL, v_b1_hu &
+ 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
+ (v_b1_hu >> 8) & 0xFF);
+ v_brh = wcd9xxx_codec_v_sta_dce(mbhc, DCE, mv, false);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL, v_brh &
+ 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
+ (v_brh >> 8) & 0xFF);
+ }
return 0;
}
@@ -3171,6 +3238,19 @@
goto done;
}
+ /*
+ * setup internal micbias if codec uses internal micbias for
+ * headset detection
+ */
+ if (mbhc->mbhc_cfg->use_int_rbias) {
+ if (mbhc->mbhc_cb && mbhc->mbhc_cb->setup_int_rbias)
+ mbhc->mbhc_cb->setup_int_rbias(codec, true);
+ else
+ pr_err("%s: internal bias requested but codec did not provide callback\n",
+ __func__);
+ }
+
+
/* Measure scaled HW DCE */
vddio = (mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
mbhc->mbhc_micbias_switched);
@@ -3192,7 +3272,9 @@
__func__);
if (mbhc->update_z) {
wcd9xxx_update_z(mbhc);
- mbhc->update_z = false;
+ dce_z = mbhc->mbhc_data.dce_z;
+ sta_z = mbhc->mbhc_data.sta_z;
+ mbhc->update_z = true;
}
stamv = __wcd9xxx_codec_sta_dce_v(mbhc, 0, sta, sta_z,
mbhc->mbhc_data.micb_mv);
@@ -3218,7 +3300,9 @@
if (mbhc->update_z) {
wcd9xxx_update_z(mbhc);
- mbhc->update_z = false;
+ dce_z = mbhc->mbhc_data.dce_z;
+ sta_z = mbhc->mbhc_data.sta_z;
+ mbhc->update_z = true;
}
stamv = __wcd9xxx_codec_sta_dce_v(mbhc, 0, sta, sta_z,
@@ -3692,6 +3776,7 @@
gain = wcd9xxx_mbhc_cal_btn_det_mp(btn_det, MBHC_BTN_DET_GAIN);
snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B2_CTL, 0x78,
gain[idx] << 3);
+ snd_soc_update_bits(codec, WCD9XXX_A_MICB_2_MBHC, 0x04, 0x04);
pr_debug("%s: leave\n", __func__);
}
@@ -3991,11 +4076,12 @@
* headset detection
*/
if (mbhc->mbhc_cfg->use_int_rbias) {
- if (mbhc->mbhc_cb && mbhc->mbhc_cb->setup_int_rbias)
+ if (mbhc->mbhc_cb && mbhc->mbhc_cb->setup_int_rbias) {
mbhc->mbhc_cb->setup_int_rbias(codec, true);
- else
- pr_info("%s: internal bias is requested but codec did not provide callback\n",
+ } else {
+ pr_info("%s: internal bias requested but codec did not provide callback\n",
__func__);
+ }
}
/*
@@ -4189,6 +4275,14 @@
if (!mbhc->polling_active)
wcd9xxx_enable_mbhc_txfe(mbhc, false);
}
+ if (mbhc->micbias_enable && mbhc->polling_active &&
+ !(snd_soc_read(mbhc->codec, mbhc->mbhc_bias_regs.ctl_reg)
+ & 0x80)) {
+ pr_debug("%s:Micbias turned off by recording, set up again",
+ __func__);
+ snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg,
+ 0x80, 0x80);
+ }
break;
/* PA usage change */
case WCD9XXX_EVENT_PRE_HPHL_PA_ON:
@@ -4208,7 +4302,8 @@
if (mbhc->hph_status & SND_JACK_OC_HPHL)
hphlocp_off_report(mbhc, SND_JACK_OC_HPHL);
if (!(mbhc->event_state &
- (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR)))
+ (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR |
+ 1 << MBHC_EVENT_PRE_TX_3_ON)))
wcd9xxx_switch_micbias(mbhc, 0);
break;
case WCD9XXX_EVENT_POST_HPHR_PA_OFF:
@@ -4219,7 +4314,8 @@
if (mbhc->hph_status & SND_JACK_OC_HPHR)
hphrocp_off_report(mbhc, SND_JACK_OC_HPHL);
if (!(mbhc->event_state &
- (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR)))
+ (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR |
+ 1 << MBHC_EVENT_PRE_TX_3_ON)))
wcd9xxx_switch_micbias(mbhc, 0);
break;
/* Clock usage change */
@@ -4301,6 +4397,28 @@
case WCD9XXX_EVENT_POST_BG_MBHC_ON:
/* Not used for now */
break;
+ case WCD9XXX_EVENT_PRE_TX_3_ON:
+ /*
+ * if polling is ON, mbhc micbias not enabled
+ * switch micbias source to VDDIO
+ */
+ set_bit(MBHC_EVENT_PRE_TX_3_ON, &mbhc->event_state);
+ if (!(snd_soc_read(codec, mbhc->mbhc_bias_regs.ctl_reg)
+ & 0x80) &&
+ mbhc->polling_active && !mbhc->mbhc_micbias_switched)
+ wcd9xxx_switch_micbias(mbhc, 1);
+ break;
+ case WCD9XXX_EVENT_POST_TX_3_OFF:
+ /*
+ * Switch back to micbias if HPH PA or TX3 path
+ * is disabled
+ */
+ clear_bit(MBHC_EVENT_PRE_TX_3_ON, &mbhc->event_state);
+ if (mbhc->polling_active && mbhc->mbhc_micbias_switched &&
+ !(mbhc->event_state & (1 << MBHC_EVENT_PA_HPHL |
+ 1 << MBHC_EVENT_PA_HPHR)))
+ wcd9xxx_switch_micbias(mbhc, 0);
+ break;
default:
WARN(1, "Unknown event %d\n", event);
ret = -EINVAL;
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.h b/sound/soc/codecs/wcd9xxx-mbhc.h
index 9d0afe9..98f73fc 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.h
+++ b/sound/soc/codecs/wcd9xxx-mbhc.h
@@ -123,6 +123,8 @@
enum wcd9xxx_mbhc_event_state {
MBHC_EVENT_PA_HPHL,
MBHC_EVENT_PA_HPHR,
+ MBHC_EVENT_PRE_TX_3_ON,
+ MBHC_EVENT_POST_TX_3_OFF,
};
struct wcd9xxx_mbhc_general_cfg {
@@ -228,6 +230,8 @@
bool (*swap_gnd_mic) (struct snd_soc_codec *);
unsigned long cs_enable_flags;
bool use_int_rbias;
+ bool do_recalibration;
+ bool use_vddio_meas;
};
struct wcd9xxx_cfilt_mode {
@@ -336,7 +340,6 @@
u32 rco_clk_rate;
bool update_z;
-
/* Holds codec specific interrupt mapping */
const struct wcd9xxx_mbhc_intr *intr_ids;
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.c b/sound/soc/codecs/wcd9xxx-resmgr.c
index 5d74469..e56b182 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.c
+++ b/sound/soc/codecs/wcd9xxx-resmgr.c
@@ -92,6 +92,9 @@
"WCD9XXX_EVENT_POST_RESUME",
+ "WCD9XXX_EVENT_PRE_TX_3_ON",
+ "WCD9XXX_EVENT_POST_TX_3_OFF",
+
"WCD9XXX_EVENT_LAST",
};
@@ -561,8 +564,15 @@
if (--resmgr->clk_rco_users == 0 &&
resmgr->clk_type == WCD9XXX_CLK_RCO) {
wcd9xxx_disable_clock_block(resmgr);
- snd_soc_update_bits(resmgr->codec,
- WCD9XXX_A_RC_OSC_FREQ, 0x80, 0x00);
+ /* if RCO is enabled, switch from it */
+ if (snd_soc_read(resmgr->codec, WCD9XXX_A_RC_OSC_FREQ)
+ & 0x80) {
+ if (resmgr->codec_type !=
+ WCD9XXX_CDC_TYPE_HELICON)
+ snd_soc_write(resmgr->codec,
+ WCD9XXX_A_CLK_BUFF_EN2, 0x02);
+ wcd9xxx_resmgr_enable_config_mode(resmgr, 0);
+ }
resmgr->clk_type = WCD9XXX_CLK_OFF;
}
break;
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.h b/sound/soc/codecs/wcd9xxx-resmgr.h
index 603bd1e..9f383b6 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.h
+++ b/sound/soc/codecs/wcd9xxx-resmgr.h
@@ -105,6 +105,9 @@
WCD9XXX_EVENT_POST_RESUME,
+ WCD9XXX_EVENT_PRE_TX_3_ON,
+ WCD9XXX_EVENT_POST_TX_3_OFF,
+
WCD9XXX_EVENT_LAST,
};
diff --git a/sound/soc/msm/apq8074.c b/sound/soc/msm/apq8074.c
index 3a055e2..5b12b9c 100644
--- a/sound/soc/msm/apq8074.c
+++ b/sound/soc/msm/apq8074.c
@@ -19,18 +19,22 @@
#include <linux/mfd/pm8xxx/pm8921.h>
#include <linux/qpnp/clkdiv.h>
#include <linux/regulator/consumer.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/pcm.h>
#include <sound/jack.h>
#include <sound/q6afe-v2.h>
-#include <asm/mach-types.h>
-#include <mach/socinfo.h>
#include <sound/pcm_params.h>
+#include <asm/mach-types.h>
+#include <mach/subsystem_notif.h>
+#include <mach/socinfo.h>
+
#include "qdsp6v2/msm-pcm-routing-v2.h"
+#include "qdsp6v2/q6core.h"
+#include "../codecs/wcd9xxx-common.h"
#include "../codecs/wcd9320.h"
-#include <linux/io.h>
#define DRV_NAME "apq8074-asoc-taiko"
@@ -82,6 +86,10 @@
#define NUM_OF_AUXPCM_GPIOS 4
+static void *adsp_state_notifier;
+
+#define ADSP_STATE_READY_TIMEOUT_MS 3000
+
static inline int param_is_mask(int p)
{
return ((p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
@@ -1230,6 +1238,101 @@
return true;
}
+static int msm_afe_set_config(struct snd_soc_codec *codec)
+{
+ int rc;
+ void *config_data;
+
+ pr_debug("%s: enter\n", __func__);
+ config_data = taiko_get_afe_config(codec, AFE_CDC_REGISTERS_CONFIG);
+ rc = afe_set_config(AFE_CDC_REGISTERS_CONFIG, config_data, 0);
+ if (rc) {
+ pr_err("%s: Failed to set codec registers config %d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ config_data = taiko_get_afe_config(codec, AFE_SLIMBUS_SLAVE_CONFIG);
+ rc = afe_set_config(AFE_SLIMBUS_SLAVE_CONFIG, config_data, 0);
+ if (rc) {
+ pr_err("%s: Failed to set slimbus slave config %d\n", __func__,
+ rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+static void msm_afe_clear_config(void)
+{
+ afe_clear_config(AFE_CDC_REGISTERS_CONFIG);
+ afe_clear_config(AFE_SLIMBUS_SLAVE_CONFIG);
+}
+
+static int msm8974_adsp_state_callback(struct notifier_block *nb,
+ unsigned long value, void *priv)
+{
+ if (value == SUBSYS_BEFORE_SHUTDOWN) {
+ pr_debug("%s: ADSP is about to shutdown. Clearing AFE config\n",
+ __func__);
+ msm_afe_clear_config();
+ } else if (value == SUBSYS_AFTER_POWERUP) {
+ pr_debug("%s: ADSP is up\n", __func__);
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block adsp_state_notifier_block = {
+ .notifier_call = msm8974_adsp_state_callback,
+ .priority = -INT_MAX,
+};
+
+static int msm8974_taiko_codec_up(struct snd_soc_codec *codec)
+{
+ int err;
+ unsigned long timeout;
+ int adsp_ready = 0;
+
+ timeout = jiffies +
+ msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS);
+
+ do {
+ if (!q6core_is_adsp_ready()) {
+ pr_err("%s: ADSP Audio isn't ready\n", __func__);
+ } else {
+ pr_debug("%s: ADSP Audio is ready\n", __func__);
+ adsp_ready = 1;
+ break;
+ }
+ } while (time_after(timeout, jiffies));
+
+ if (!adsp_ready) {
+ pr_err("%s: timed out waiting for ADSP Audio\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ err = msm_afe_set_config(codec);
+ if (err)
+ pr_err("%s: Failed to set AFE config. err %d\n",
+ __func__, err);
+ return err;
+}
+
+static int apq8074_taiko_event_cb(struct snd_soc_codec *codec,
+ enum wcd9xxx_codec_event codec_event)
+{
+ switch (codec_event) {
+ case WCD9XXX_CODEC_EVENT_CODEC_UP:
+ return msm8974_taiko_codec_up(codec);
+ break;
+ default:
+ pr_err("%s: UnSupported codec event %d\n",
+ __func__, codec_event);
+ return -EINVAL;
+ }
+}
+
static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
{
int err;
@@ -1291,19 +1394,9 @@
tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
- config_data = taiko_get_afe_config(codec, AFE_CDC_REGISTERS_CONFIG);
- err = afe_set_config(AFE_CDC_REGISTERS_CONFIG, config_data, 0);
+ err = msm_afe_set_config(codec);
if (err) {
- pr_err("%s: Failed to set codec registers config %d\n",
- __func__, err);
- goto out;
- }
-
- config_data = taiko_get_afe_config(codec, AFE_SLIMBUS_SLAVE_CONFIG);
- err = afe_set_config(AFE_SLIMBUS_SLAVE_CONFIG, config_data, 0);
- if (err) {
- pr_err("%s: Failed to set slimbus slave config %d\n", __func__,
- err);
+ pr_err("%s: Failed to set AFE config %d\n", __func__, err);
goto out;
}
@@ -1340,12 +1433,23 @@
err = taiko_hs_detect(codec, &mbhc_cfg);
if (err)
goto out;
- else
- return err;
} else {
err = -ENOMEM;
goto out;
}
+ adsp_state_notifier =
+ subsys_notif_register_notifier("adsp",
+ &adsp_state_notifier_block);
+ if (!adsp_state_notifier) {
+ pr_err("%s: Failed to register adsp state notifier\n",
+ __func__);
+ err = -EFAULT;
+ taiko_hs_detect_exit(codec);
+ goto out;
+ }
+
+ taiko_event_register(apq8074_taiko_event_cb, rtd->codec);
+ return 0;
out:
clk_put(codec_clk);
return err;
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index d235a69..6f94d99 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -281,6 +281,17 @@
.rate_min = 8000,
.rate_max = 192000,
},
+ .capture = {
+ .stream_name = "MultiMedia8 Capture",
+ .aif_name = "MM_UL8",
+ .rates = (SNDRV_PCM_RATE_8000_48000|
+ SNDRV_PCM_RATE_KNOT),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
.ops = &msm_fe_Multimedia_dai_ops,
.name = "MultiMedia8",
},
@@ -411,6 +422,30 @@
},
{
.playback = {
+ .stream_name = "INT_HFP_BT Hostless Playback",
+ .aif_name = "INTHFP_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 16000,
+ },
+ .capture = {
+ .stream_name = "INT_HFP_BT Hostless Capture",
+ .aif_name = "INTHFP_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 16000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "INT_HFP_BT_HOSTLESS",
+ },
+ {
+ .playback = {
.stream_name = "AFE-PROXY Playback",
.aif_name = "PCM_RX",
.rates = (SNDRV_PCM_RATE_8000 |
diff --git a/sound/soc/msm/msm-pcm-host-voice.c b/sound/soc/msm/msm-pcm-host-voice.c
index 2eafc1d..1b68bcf 100644
--- a/sound/soc/msm/msm-pcm-host-voice.c
+++ b/sound/soc/msm/msm-pcm-host-voice.c
@@ -989,7 +989,7 @@
spin_unlock_irqrestore(&dai_data->dsp_lock, dsp_flags);
ret = copy_to_user(buf,
&buf_node->frame.voc_pkt,
- count);
+ buf_node->frame.len);
if (ret) {
pr_err("%s: Copy to user retuned %d\n",
__func__, ret);
diff --git a/sound/soc/msm/msm8226.c b/sound/soc/msm/msm8226.c
index c25a460..b4ae0a4 100644
--- a/sound/soc/msm/msm8226.c
+++ b/sound/soc/msm/msm8226.c
@@ -94,6 +94,8 @@
.cs_enable_flags = (1 << MBHC_CS_ENABLE_POLLING |
1 << MBHC_CS_ENABLE_INSERTION |
1 << MBHC_CS_ENABLE_REMOVAL),
+ .do_recalibration = true,
+ .use_vddio_meas = true,
};
struct msm_auxpcm_gpio {
@@ -1418,6 +1420,21 @@
.codec_name = "snd-soc-dummy",
.be_id = MSM_FRONTEND_DAI_LSM1,
},
+ {
+ .name = "MSM8226 Compr8",
+ .stream_name = "COMPR8",
+ .cpu_dai_name = "MultiMedia8",
+ .platform_name = "msm-compr-dsp",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA8,
+ },
/* Backend BT/FM DAI Links */
{
.name = LPASS_BE_INT_BT_SCO_RX,
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 01b7956..4c3a72e 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -58,16 +58,9 @@
#define LO_2_SPK_AMP 0x4
#define LO_4_SPK_AMP 0x8
-#define LPAIF_OFFSET 0xFE000000
-#define LPAIF_PRI_MODE_MUXSEL (LPAIF_OFFSET + 0x2B000)
-#define LPAIF_SEC_MODE_MUXSEL (LPAIF_OFFSET + 0x2C000)
-#define LPAIF_TER_MODE_MUXSEL (LPAIF_OFFSET + 0x2D000)
-#define LPAIF_QUAD_MODE_MUXSEL (LPAIF_OFFSET + 0x2E000)
-
#define I2S_PCM_SEL 1
#define I2S_PCM_SEL_OFFSET 1
-
#define WCD9XXX_MBHC_DEF_BUTTONS 8
#define WCD9XXX_MBHC_DEF_RLOADS 5
#define TAIKO_EXT_CLK_RATE 9600000
@@ -136,6 +129,8 @@
.cs_enable_flags = (1 << MBHC_CS_ENABLE_POLLING |
1 << MBHC_CS_ENABLE_INSERTION |
1 << MBHC_CS_ENABLE_REMOVAL),
+ .do_recalibration = true,
+ .use_vddio_meas = true,
};
struct msm_auxpcm_gpio {
@@ -146,6 +141,7 @@
struct msm_auxpcm_ctrl {
struct msm_auxpcm_gpio *pin_data;
u32 cnt;
+ void __iomem *mux;
};
struct msm8974_asoc_mach_data {
@@ -173,9 +169,6 @@
{"SEC_AUXPCM_DOUT", "qcom,sec-auxpcm-gpio-dout"},
};
-void *lpaif_pri_muxsel_virt_addr;
-void *lpaif_sec_muxsel_virt_addr;
-
struct msm8974_liquid_dock_dev {
int dock_plug_gpio;
int dock_plug_irq;
@@ -1192,12 +1185,14 @@
goto err;
}
if (atomic_inc_return(&prim_auxpcm_rsc_ref) == 1) {
- if (lpaif_pri_muxsel_virt_addr != NULL)
+ if (auxpcm_ctrl->mux != NULL) {
iowrite32(I2S_PCM_SEL << I2S_PCM_SEL_OFFSET,
- lpaif_pri_muxsel_virt_addr);
- else
- pr_err("%s lpaif_pri_muxsel_virt_addr is NULL\n",
- __func__);
+ auxpcm_ctrl->mux);
+ } else {
+ pr_err("%s: Pri AUXPCM MUX addr is NULL\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
ret = msm_aux_pcm_get_gpios(auxpcm_ctrl);
}
if (ret < 0) {
@@ -1247,12 +1242,14 @@
goto err;
}
if (atomic_inc_return(&sec_auxpcm_rsc_ref) == 1) {
- if (lpaif_sec_muxsel_virt_addr != NULL)
+ if (auxpcm_ctrl->mux != NULL) {
iowrite32(I2S_PCM_SEL << I2S_PCM_SEL_OFFSET,
- lpaif_sec_muxsel_virt_addr);
- else
- pr_err("%s lpaif_sec_muxsel_virt_addr is NULL\n",
- __func__);
+ auxpcm_ctrl->mux);
+ } else {
+ pr_err("%s Sec AUXPCM MUX addr is NULL\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
ret = msm_aux_pcm_get_gpios(auxpcm_ctrl);
}
if (ret < 0) {
@@ -2163,7 +2160,7 @@
.name = "MSM8974 Compr4",
.stream_name = "COMPR4",
.cpu_dai_name = "MultiMedia8",
- .platform_name = "msm-compress-dsp",
+ .platform_name = "msm-compr-dsp",
.dynamic = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
@@ -2206,6 +2203,53 @@
.codec_name = "snd-soc-dummy",
},
{
+ .name = "Voice2",
+ .stream_name = "Voice2",
+ .cpu_dai_name = "Voice2",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_VOICE2,
+ },
+ {
+ .name = "INT_HFP_BT Hostless",
+ .stream_name = "INT_HFP_BT Hostless",
+ .cpu_dai_name = "INT_HFP_BT_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {
+ .name = "MSM8974 HFP TX",
+ .stream_name = "MultiMedia6",
+ .cpu_dai_name = "MultiMedia6",
+ .platform_name = "msm-pcm-loopback",
+ .dynamic = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA6,
+ },
+ {
.name = LPASS_BE_SLIMBUS_4_TX,
.stream_name = "Slimbus4 Capture",
.cpu_dai_name = "msm-dai-q6-dev.16393",
@@ -2667,6 +2711,8 @@
int ret;
const char *auxpcm_pri_gpio_set = NULL;
const char *prop_name_ult_lo_gpio = "qcom,ext-ult-lo-amp-gpio";
+ struct resource *pri_muxsel;
+ struct resource *sec_muxsel;
if (!pdev->dev.of_node) {
dev_err(&pdev->dev, "No platform supplied from device tree\n");
@@ -2794,7 +2840,6 @@
}
}
-
pdata->us_euro_gpio = of_get_named_gpio(pdev->dev.of_node,
"qcom,us-euro-gpios", 0);
if (pdata->us_euro_gpio < 0) {
@@ -2821,28 +2866,49 @@
goto err1;
}
if (!strcmp(auxpcm_pri_gpio_set, "prim-gpio-prim")) {
- lpaif_pri_muxsel_virt_addr = ioremap(LPAIF_PRI_MODE_MUXSEL, 4);
+ pri_muxsel = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "lpaif_pri_mode_muxsel");
} else if (!strcmp(auxpcm_pri_gpio_set, "prim-gpio-tert")) {
- lpaif_pri_muxsel_virt_addr = ioremap(LPAIF_TER_MODE_MUXSEL, 4);
+ pri_muxsel = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "lpaif_tert_mode_muxsel");
} else {
dev_err(&pdev->dev, "Invalid value %s for AUXPCM GPIO set\n",
auxpcm_pri_gpio_set);
ret = -EINVAL;
goto err1;
}
- if (lpaif_pri_muxsel_virt_addr == NULL) {
- pr_err("%s Pri muxsel virt addr is null\n", __func__);
- ret = -EINVAL;
- goto err1;
+ if (!pri_muxsel) {
+ dev_err(&pdev->dev, "MUX addr invalid for primary AUXPCM\n");
+ ret = -ENODEV;
+ goto err1;
+ } else {
+ pdata->pri_auxpcm_ctrl->mux = ioremap(pri_muxsel->start,
+ resource_size(pri_muxsel));
+ if (pdata->pri_auxpcm_ctrl->mux == NULL) {
+ pr_err("%s Pri muxsel virt addr is null\n", __func__);
+ ret = -EINVAL;
+ goto err1;
+ }
}
- lpaif_sec_muxsel_virt_addr = ioremap(LPAIF_SEC_MODE_MUXSEL, 4);
- if (lpaif_sec_muxsel_virt_addr == NULL) {
+
+ sec_muxsel = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "lpaif_sec_mode_muxsel");
+ if (!sec_muxsel) {
+ dev_err(&pdev->dev, "MUX addr invalid for secondary AUXPCM\n");
+ ret = -ENODEV;
+ goto err2;
+ }
+ pdata->sec_auxpcm_ctrl->mux = ioremap(sec_muxsel->start,
+ resource_size(sec_muxsel));
+ if (pdata->sec_auxpcm_ctrl->mux == NULL) {
pr_err("%s Sec muxsel virt addr is null\n", __func__);
ret = -EINVAL;
- goto err1;
+ goto err2;
}
return 0;
+err2:
+ iounmap(pdata->pri_auxpcm_ctrl->mux);
err1:
if (ext_ult_lo_amp_gpio >= 0)
gpio_free(ext_ult_lo_amp_gpio);
@@ -2896,8 +2962,8 @@
msm8974_liquid_dock_dev = NULL;
}
- iounmap(lpaif_pri_muxsel_virt_addr);
- iounmap(lpaif_sec_muxsel_virt_addr);
+ iounmap(pdata->pri_auxpcm_ctrl->mux);
+ iounmap(pdata->sec_auxpcm_ctrl->mux);
snd_soc_unregister_card(card);
return 0;
diff --git a/sound/soc/msm/msm8x10.c b/sound/soc/msm/msm8x10.c
index d9af6f3..caf81fc 100644
--- a/sound/soc/msm/msm8x10.c
+++ b/sound/soc/msm/msm8x10.c
@@ -99,9 +99,13 @@
.insert_detect = true,
.swap_gnd_mic = NULL,
.use_int_rbias = false,
+ .micbias_enable_flags = 1 << MBHC_MICBIAS_ENABLE_THRESHOLD_HEADSET |
+ 1 << MBHC_MICBIAS_ENABLE_REGULAR_HEADSET,
.cs_enable_flags = (1 << MBHC_CS_ENABLE_POLLING |
1 << MBHC_CS_ENABLE_INSERTION |
1 << MBHC_CS_ENABLE_REMOVAL),
+ .do_recalibration = false,
+ .use_vddio_meas = false,
};
/*
@@ -161,6 +165,8 @@
SND_SOC_DAPM_MIC("Handset Mic", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_MIC("Secondary Mic", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic1", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic2", NULL),
};
static int msm8x10_ext_spk_power_amp_init(void)
{
@@ -603,21 +609,21 @@
btn_high = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg,
MBHC_BTN_DET_V_BTN_HIGH);
btn_low[0] = -50;
- btn_high[0] = 10;
- btn_low[1] = 11;
- btn_high[1] = 52;
- btn_low[2] = 53;
- btn_high[2] = 94;
- btn_low[3] = 95;
- btn_high[3] = 133;
- btn_low[4] = 134;
- btn_high[4] = 171;
- btn_low[5] = 172;
- btn_high[5] = 208;
- btn_low[6] = 209;
- btn_high[6] = 244;
- btn_low[7] = 245;
- btn_high[7] = 330;
+ btn_high[0] = 20;
+ btn_low[1] = 21;
+ btn_high[1] = 61;
+ btn_low[2] = 62;
+ btn_high[2] = 104;
+ btn_low[3] = 105;
+ btn_high[3] = 148;
+ btn_low[4] = 149;
+ btn_high[4] = 189;
+ btn_low[5] = 190;
+ btn_high[5] = 228;
+ btn_low[6] = 229;
+ btn_high[6] = 269;
+ btn_low[7] = 270;
+ btn_high[7] = 500;
n_ready = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg, MBHC_BTN_DET_N_READY);
n_ready[0] = 80;
n_ready[1] = 68;
diff --git a/sound/soc/msm/qdsp6v2/Makefile b/sound/soc/msm/qdsp6v2/Makefile
index 15128c9..f0f5db6 100644
--- a/sound/soc/msm/qdsp6v2/Makefile
+++ b/sound/soc/msm/qdsp6v2/Makefile
@@ -1,8 +1,10 @@
snd-soc-qdsp6v2-objs += msm-dai-q6-v2.o msm-pcm-q6-v2.o msm-pcm-routing-v2.o \
- msm-compress-q6-v2.o msm-multi-ch-pcm-q6-v2.o \
- msm-pcm-lpa-v2.o msm-pcm-afe-v2.o msm-pcm-voip-v2.o \
+ msm-compress-q6-v2.o msm-compr-q6-v2.o \
+ msm-multi-ch-pcm-q6-v2.o msm-pcm-lpa-v2.o \
+ msm-pcm-afe-v2.o msm-pcm-voip-v2.o \
msm-pcm-voice-v2.o msm-dai-q6-hdmi-v2.o \
- msm-lsm-client.o
+ msm-lsm-client.o msm-audio-effects-q6-v2.o \
+ msm-pcm-loopback-v2.o
obj-$(CONFIG_SND_SOC_QDSP6V2) += snd-soc-qdsp6v2.o msm-pcm-dtmf-v2.o \
msm-dai-stub-v2.o
obj-$(CONFIG_DOLBY_DAP) += msm-dolby-dap-config.o
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.c b/sound/soc/msm/qdsp6v2/audio_acdb.c
index 01422cf..4e04bef 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.c
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.c
@@ -38,64 +38,60 @@
#define MAX_HW_DELAY_ENTRIES 25
-struct sidetone_atomic_cal {
- atomic_t enable;
- atomic_t gain;
-};
-
-
struct acdb_data {
+ uint32_t usage_count;
+
struct mutex acdb_mutex;
/* ANC Cal */
- struct acdb_atomic_cal_block anc_cal;
+ struct acdb_cal_block anc_cal;
/* AANC Cal */
- struct acdb_atomic_cal_block aanc_cal;
+ struct acdb_cal_block aanc_cal;
/* LSM Cal */
- struct acdb_atomic_cal_block lsm_cal;
+ struct acdb_cal_block lsm_cal;
/* AudProc Cal */
- atomic_t asm_topology;
- atomic_t adm_topology[MAX_AUDPROC_TYPES];
- struct acdb_atomic_cal_block audproc_cal[MAX_AUDPROC_TYPES];
- struct acdb_atomic_cal_block audstrm_cal[MAX_AUDPROC_TYPES];
- struct acdb_atomic_cal_block audvol_cal[MAX_AUDPROC_TYPES];
+ uint32_t asm_topology;
+ uint32_t adm_topology[MAX_AUDPROC_TYPES];
+ struct acdb_cal_block audproc_cal[MAX_AUDPROC_TYPES];
+ struct acdb_cal_block audstrm_cal[MAX_AUDPROC_TYPES];
+ struct acdb_cal_block audvol_cal[MAX_AUDPROC_TYPES];
/* VocProc Cal */
- atomic_t voice_rx_topology;
- atomic_t voice_tx_topology;
- struct acdb_atomic_cal_block vocproc_cal;
- struct acdb_atomic_cal_block vocstrm_cal;
- struct acdb_atomic_cal_block vocvol_cal;
+ uint32_t voice_rx_topology;
+ uint32_t voice_tx_topology;
+ struct acdb_cal_block vocproc_cal;
+ struct acdb_cal_block vocstrm_cal;
+ struct acdb_cal_block vocvol_cal;
/* Voice Column data */
- struct acdb_atomic_cal_block vocproc_col_cal[MAX_VOCPROC_TYPES];
+ struct acdb_cal_block vocproc_col_cal[MAX_VOCPROC_TYPES];
uint32_t *col_data[MAX_VOCPROC_TYPES];
/* VocProc dev cfg cal*/
- struct acdb_atomic_cal_block vocproc_dev_cal;
+ struct acdb_cal_block vocproc_dev_cal;
/* Custom topology */
- struct acdb_atomic_cal_block adm_custom_topology;
- struct acdb_atomic_cal_block asm_custom_topology;
- atomic_t valid_adm_custom_top;
- atomic_t valid_asm_custom_top;
+ struct acdb_cal_block adm_custom_topology;
+ struct acdb_cal_block asm_custom_topology;
+ uint32_t valid_adm_custom_top;
+ uint32_t valid_asm_custom_top;
/* AFE cal */
- struct acdb_atomic_cal_block afe_cal[MAX_AUDPROC_TYPES];
+ struct acdb_cal_block afe_cal[MAX_AUDPROC_TYPES];
/* Sidetone Cal */
- struct sidetone_atomic_cal sidetone_cal;
+ struct sidetone_cal sidetone_cal;
/* Allocation information */
struct ion_client *ion_client;
struct ion_handle *ion_handle;
- atomic_t map_handle;
- atomic64_t paddr;
- atomic64_t kvaddr;
- atomic64_t mem_len;
+ uint32_t map_handle;
+ uint64_t paddr;
+ uint64_t kvaddr;
+ uint64_t mem_len;
/* Speaker protection */
struct msm_spk_prot_cfg spk_prot_cfg;
@@ -106,62 +102,63 @@
};
static struct acdb_data acdb_data;
-static atomic_t usage_count;
uint32_t get_voice_rx_topology(void)
{
- return atomic_read(&acdb_data.voice_rx_topology);
+ return acdb_data.voice_rx_topology;
}
void store_voice_rx_topology(uint32_t topology)
{
- atomic_set(&acdb_data.voice_rx_topology, topology);
+ acdb_data.voice_rx_topology = topology;
}
uint32_t get_voice_tx_topology(void)
{
- return atomic_read(&acdb_data.voice_tx_topology);
+ return acdb_data.voice_tx_topology;
}
void store_voice_tx_topology(uint32_t topology)
{
- atomic_set(&acdb_data.voice_tx_topology, topology);
+ acdb_data.voice_tx_topology = topology;
}
uint32_t get_adm_rx_topology(void)
{
- return atomic_read(&acdb_data.adm_topology[RX_CAL]);
+ return acdb_data.adm_topology[RX_CAL];
}
void store_adm_rx_topology(uint32_t topology)
{
- atomic_set(&acdb_data.adm_topology[RX_CAL], topology);
+ acdb_data.adm_topology[RX_CAL] = topology;
}
uint32_t get_adm_tx_topology(void)
{
- return atomic_read(&acdb_data.adm_topology[TX_CAL]);
+ return acdb_data.adm_topology[TX_CAL];
}
void store_adm_tx_topology(uint32_t topology)
{
- atomic_set(&acdb_data.adm_topology[TX_CAL], topology);
+ acdb_data.adm_topology[TX_CAL] = topology;
}
uint32_t get_asm_topology(void)
{
- return atomic_read(&acdb_data.asm_topology);
+ return acdb_data.asm_topology;
}
void store_asm_topology(uint32_t topology)
{
- atomic_set(&acdb_data.asm_topology, topology);
+ acdb_data.asm_topology = topology;
}
void reset_custom_topology_flags(void)
{
- atomic_set(&acdb_data.valid_adm_custom_top, 1);
- atomic_set(&acdb_data.valid_asm_custom_top, 1);
+ mutex_lock(&acdb_data.acdb_mutex);
+ acdb_data.valid_adm_custom_top = 1;
+ acdb_data.valid_asm_custom_top = 1;
+ mutex_unlock(&acdb_data.acdb_mutex);
}
int get_adm_custom_topology(struct acdb_cal_block *cal_block)
@@ -175,19 +172,19 @@
goto done;
}
+ mutex_lock(&acdb_data.acdb_mutex);
/* Only return allow one access after memory registered */
- if (atomic_read(&acdb_data.valid_adm_custom_top) == 0) {
+ if (acdb_data.valid_adm_custom_top == 0) {
cal_block->cal_size = 0;
- goto done;
+ goto unlock;
}
- atomic_set(&acdb_data.valid_adm_custom_top, 0);
+ acdb_data.valid_adm_custom_top = 0;
- cal_block->cal_size =
- atomic_read(&acdb_data.adm_custom_topology.cal_size);
- cal_block->cal_paddr =
- atomic_read(&acdb_data.adm_custom_topology.cal_paddr);
- cal_block->cal_kvaddr =
- atomic_read(&acdb_data.adm_custom_topology.cal_kvaddr);
+ cal_block->cal_size = acdb_data.adm_custom_topology.cal_size;
+ cal_block->cal_paddr = acdb_data.adm_custom_topology.cal_paddr;
+ cal_block->cal_kvaddr = acdb_data.adm_custom_topology.cal_kvaddr;
+unlock:
+ mutex_unlock(&acdb_data.acdb_mutex);
done:
return result;
}
@@ -197,21 +194,18 @@
int result = 0;
pr_debug("%s,\n", __func__);
- if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
- pr_err("%s: offset %d is > mem_len %ld\n",
- __func__, cal_block->cal_offset,
- (long)atomic64_read(&acdb_data.mem_len));
+ if (cal_block->cal_offset > acdb_data.mem_len) {
+ pr_err("%s: offset %d is > mem_len %llu\n",
+ __func__, cal_block->cal_offset, acdb_data.mem_len);
result = -EINVAL;
goto done;
}
- atomic_set(&acdb_data.adm_custom_topology.cal_size,
- cal_block->cal_size);
- atomic_set(&acdb_data.adm_custom_topology.cal_paddr,
- cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
- atomic_set(&acdb_data.adm_custom_topology.cal_kvaddr,
- cal_block->cal_offset +
- atomic64_read(&acdb_data.kvaddr));
+ acdb_data.adm_custom_topology.cal_size = cal_block->cal_size;
+ acdb_data.adm_custom_topology.cal_paddr =
+ cal_block->cal_offset + acdb_data.paddr;
+ acdb_data.adm_custom_topology.cal_kvaddr =
+ cal_block->cal_offset + acdb_data.kvaddr;
done:
return result;
}
@@ -227,19 +221,19 @@
goto done;
}
+ mutex_lock(&acdb_data.acdb_mutex);
/* Only return allow one access after memory registered */
- if (atomic_read(&acdb_data.valid_asm_custom_top) == 0) {
+ if (acdb_data.valid_asm_custom_top == 0) {
cal_block->cal_size = 0;
- goto done;
+ goto unlock;
}
- atomic_set(&acdb_data.valid_asm_custom_top, 0);
+ acdb_data.valid_asm_custom_top = 0;
- cal_block->cal_size =
- atomic_read(&acdb_data.asm_custom_topology.cal_size);
- cal_block->cal_paddr =
- atomic_read(&acdb_data.asm_custom_topology.cal_paddr);
- cal_block->cal_kvaddr =
- atomic_read(&acdb_data.asm_custom_topology.cal_kvaddr);
+ cal_block->cal_size = acdb_data.asm_custom_topology.cal_size;
+ cal_block->cal_paddr = acdb_data.asm_custom_topology.cal_paddr;
+ cal_block->cal_kvaddr = acdb_data.asm_custom_topology.cal_kvaddr;
+unlock:
+ mutex_unlock(&acdb_data.acdb_mutex);
done:
return result;
}
@@ -249,21 +243,18 @@
int result = 0;
pr_debug("%s,\n", __func__);
- if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
- pr_err("%s: offset %d is > mem_len %ld\n",
- __func__, cal_block->cal_offset,
- (long)atomic64_read(&acdb_data.mem_len));
+ if (cal_block->cal_offset > acdb_data.mem_len) {
+ pr_err("%s: offset %d is > mem_len %llu\n",
+ __func__, cal_block->cal_offset, acdb_data.mem_len);
result = -EINVAL;
goto done;
}
- atomic_set(&acdb_data.asm_custom_topology.cal_size,
- cal_block->cal_size);
- atomic_set(&acdb_data.asm_custom_topology.cal_paddr,
- cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
- atomic_set(&acdb_data.asm_custom_topology.cal_kvaddr,
- cal_block->cal_offset +
- atomic64_read(&acdb_data.kvaddr));
+ acdb_data.asm_custom_topology.cal_size = cal_block->cal_size;
+ acdb_data.asm_custom_topology.cal_paddr =
+ cal_block->cal_offset + acdb_data.paddr;
+ acdb_data.asm_custom_topology.cal_kvaddr =
+ cal_block->cal_offset + acdb_data.kvaddr;
done:
return result;
}
@@ -280,10 +271,8 @@
}
cal_block->cal_size = ACDB_TOTAL_VOICE_ALLOCATION;
- cal_block->cal_paddr =
- atomic_read(&acdb_data.vocproc_cal.cal_paddr);
- cal_block->cal_kvaddr =
- atomic_read(&acdb_data.vocproc_cal.cal_kvaddr);
+ cal_block->cal_paddr = acdb_data.vocproc_cal.cal_paddr;
+ cal_block->cal_kvaddr = acdb_data.vocproc_cal.cal_kvaddr;
done:
return result;
}
@@ -299,12 +288,9 @@
goto done;
}
- cal_block->cal_size =
- atomic_read(&acdb_data.aanc_cal.cal_size);
- cal_block->cal_paddr =
- atomic_read(&acdb_data.aanc_cal.cal_paddr);
- cal_block->cal_kvaddr =
- atomic_read(&acdb_data.aanc_cal.cal_kvaddr);
+ cal_block->cal_size = acdb_data.aanc_cal.cal_size;
+ cal_block->cal_paddr = acdb_data.aanc_cal.cal_paddr;
+ cal_block->cal_kvaddr = acdb_data.aanc_cal.cal_kvaddr;
done:
return result;
}
@@ -314,20 +300,18 @@
int result = 0;
pr_debug("%s,\n", __func__);
- if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
- pr_err("%s: offset %d is > mem_len %ld\n",
- __func__, cal_block->cal_offset,
- (long)atomic64_read(&acdb_data.mem_len));
+ if (cal_block->cal_offset > acdb_data.mem_len) {
+ pr_err("%s: offset %d is > mem_len %llu\n",
+ __func__, cal_block->cal_offset, acdb_data.mem_len);
result = -EINVAL;
goto done;
}
- atomic_set(&acdb_data.aanc_cal.cal_size,
- cal_block->cal_size);
- atomic_set(&acdb_data.aanc_cal.cal_paddr,
- cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
- atomic_set(&acdb_data.aanc_cal.cal_kvaddr,
- cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
+ acdb_data.aanc_cal.cal_size = cal_block->cal_size;
+ acdb_data.aanc_cal.cal_paddr =
+ cal_block->cal_offset + acdb_data.paddr;
+ acdb_data.aanc_cal.cal_kvaddr =
+ cal_block->cal_offset + acdb_data.kvaddr;
done:
return result;
}
@@ -343,12 +327,9 @@
goto done;
}
- cal_block->cal_size =
- atomic_read(&acdb_data.lsm_cal.cal_size);
- cal_block->cal_paddr =
- atomic_read(&acdb_data.lsm_cal.cal_paddr);
- cal_block->cal_kvaddr =
- atomic_read(&acdb_data.lsm_cal.cal_kvaddr);
+ cal_block->cal_size = acdb_data.lsm_cal.cal_size;
+ cal_block->cal_paddr = acdb_data.lsm_cal.cal_paddr;
+ cal_block->cal_kvaddr = acdb_data.lsm_cal.cal_kvaddr;
done:
return result;
}
@@ -358,20 +339,18 @@
int result = 0;
pr_debug("%s,\n", __func__);
- if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
- pr_err("%s: offset %d is > mem_len %ld\n",
- __func__, cal_block->cal_offset,
- (long)atomic64_read(&acdb_data.mem_len));
+ if (cal_block->cal_offset > acdb_data.mem_len) {
+ pr_err("%s: offset %d is > mem_len %llu\n",
+ __func__, cal_block->cal_offset, acdb_data.mem_len);
result = -EINVAL;
goto done;
}
- atomic_set(&acdb_data.lsm_cal.cal_size,
- cal_block->cal_size);
- atomic_set(&acdb_data.lsm_cal.cal_paddr,
- cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
- atomic_set(&acdb_data.lsm_cal.cal_kvaddr,
- cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
+ acdb_data.lsm_cal.cal_size = cal_block->cal_size;
+ acdb_data.lsm_cal.cal_paddr =
+ cal_block->cal_offset + acdb_data.paddr;
+ acdb_data.lsm_cal.cal_kvaddr =
+ cal_block->cal_offset + acdb_data.kvaddr;
done:
return result;
}
@@ -426,9 +405,9 @@
done:
mutex_unlock(&acdb_data.acdb_mutex);
-ret:
pr_debug("ACDB=> %s: Path = %d samplerate = %u usec = %u status %d\n",
__func__, path, entry->sample_rate, entry->delay_usec, result);
+ret:
return result;
}
@@ -470,7 +449,6 @@
pr_debug("ACDB=> %s : Path = %d num_entries = %d\n",
__func__, path, delay.num_entries);
- mutex_lock(&acdb_data.acdb_mutex);
if (path == RX_CAL)
delay_dest = &acdb_data.hw_delay_rx;
else if (path == TX_CAL)
@@ -487,7 +465,6 @@
__func__, result, path);
result = -EFAULT;
}
- mutex_unlock(&acdb_data.acdb_mutex);
done:
return result;
}
@@ -503,12 +480,9 @@
goto done;
}
- cal_block->cal_size =
- atomic_read(&acdb_data.anc_cal.cal_size);
- cal_block->cal_paddr =
- atomic_read(&acdb_data.anc_cal.cal_paddr);
- cal_block->cal_kvaddr =
- atomic_read(&acdb_data.anc_cal.cal_kvaddr);
+ cal_block->cal_size = acdb_data.anc_cal.cal_size;
+ cal_block->cal_paddr = acdb_data.anc_cal.cal_paddr;
+ cal_block->cal_kvaddr = acdb_data.anc_cal.cal_kvaddr;
done:
return result;
}
@@ -518,20 +492,18 @@
int result = 0;
pr_debug("%s,\n", __func__);
- if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
- pr_err("%s: offset %d is > mem_len %ld\n",
- __func__, cal_block->cal_offset,
- (long)atomic64_read(&acdb_data.mem_len));
+ if (cal_block->cal_offset > acdb_data.mem_len) {
+ pr_err("%s: offset %d is > mem_len %llu\n",
+ __func__, cal_block->cal_offset, acdb_data.mem_len);
result = -EINVAL;
goto done;
}
- atomic_set(&acdb_data.anc_cal.cal_size,
- cal_block->cal_size);
- atomic_set(&acdb_data.anc_cal.cal_paddr,
- cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
- atomic_set(&acdb_data.anc_cal.cal_kvaddr,
- cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
+ acdb_data.anc_cal.cal_size = cal_block->cal_size;
+ acdb_data.anc_cal.cal_paddr =
+ cal_block->cal_offset + acdb_data.paddr;
+ acdb_data.anc_cal.cal_kvaddr =
+ cal_block->cal_offset + acdb_data.kvaddr;
done:
return result;
}
@@ -541,10 +513,9 @@
int result = 0;
pr_debug("%s, path = %d\n", __func__, path);
- if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
- pr_err("%s: offset %d is > mem_len %ld\n",
- __func__, cal_block->cal_offset,
- (long)atomic64_read(&acdb_data.mem_len));
+ if (cal_block->cal_offset > acdb_data.mem_len) {
+ pr_err("%s: offset %d is > mem_len %llu\n",
+ __func__, cal_block->cal_offset, acdb_data.mem_len);
result = -EINVAL;
goto done;
}
@@ -555,12 +526,11 @@
goto done;
}
- atomic_set(&acdb_data.afe_cal[path].cal_size,
- cal_block->cal_size);
- atomic_set(&acdb_data.afe_cal[path].cal_paddr,
- cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
- atomic_set(&acdb_data.afe_cal[path].cal_kvaddr,
- cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
+ acdb_data.afe_cal[path].cal_size = cal_block->cal_size;
+ acdb_data.afe_cal[path].cal_paddr =
+ cal_block->cal_offset + acdb_data.paddr;
+ acdb_data.afe_cal[path].cal_kvaddr =
+ cal_block->cal_offset + acdb_data.kvaddr;
done:
return result;
}
@@ -582,12 +552,9 @@
goto done;
}
- cal_block->cal_size =
- atomic_read(&acdb_data.afe_cal[path].cal_size);
- cal_block->cal_paddr =
- atomic_read(&acdb_data.afe_cal[path].cal_paddr);
- cal_block->cal_kvaddr =
- atomic_read(&acdb_data.afe_cal[path].cal_kvaddr);
+ cal_block->cal_size = acdb_data.afe_cal[path].cal_size;
+ cal_block->cal_paddr = acdb_data.afe_cal[path].cal_paddr;
+ cal_block->cal_kvaddr = acdb_data.afe_cal[path].cal_kvaddr;
done:
return result;
}
@@ -597,10 +564,9 @@
int result = 0;
pr_debug("%s, path = %d\n", __func__, path);
- if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
- pr_err("%s: offset %d is > mem_len %ld\n",
- __func__, cal_block->cal_offset,
- (long)atomic64_read(&acdb_data.mem_len));
+ if (cal_block->cal_offset > acdb_data.mem_len) {
+ pr_err("%s: offset %d is > mem_len %llu\n",
+ __func__, cal_block->cal_offset, acdb_data.mem_len);
result = -EINVAL;
goto done;
}
@@ -611,12 +577,11 @@
goto done;
}
- atomic_set(&acdb_data.audproc_cal[path].cal_size,
- cal_block->cal_size);
- atomic_set(&acdb_data.audproc_cal[path].cal_paddr,
- cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
- atomic_set(&acdb_data.audproc_cal[path].cal_kvaddr,
- cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
+ acdb_data.audproc_cal[path].cal_size = cal_block->cal_size;
+ acdb_data.audproc_cal[path].cal_paddr =
+ cal_block->cal_offset + acdb_data.paddr;
+ acdb_data.audproc_cal[path].cal_kvaddr =
+ cal_block->cal_offset + acdb_data.kvaddr;
done:
return result;
}
@@ -638,12 +603,9 @@
goto done;
}
- cal_block->cal_size =
- atomic_read(&acdb_data.audproc_cal[path].cal_size);
- cal_block->cal_paddr =
- atomic_read(&acdb_data.audproc_cal[path].cal_paddr);
- cal_block->cal_kvaddr =
- atomic_read(&acdb_data.audproc_cal[path].cal_kvaddr);
+ cal_block->cal_size = acdb_data.audproc_cal[path].cal_size;
+ cal_block->cal_paddr = acdb_data.audproc_cal[path].cal_paddr;
+ cal_block->cal_kvaddr = acdb_data.audproc_cal[path].cal_kvaddr;
done:
return result;
}
@@ -653,10 +615,9 @@
int result = 0;
pr_debug("%s, path = %d\n", __func__, path);
- if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
- pr_err("%s: offset %d is > mem_len %ld\n",
- __func__, cal_block->cal_offset,
- (long)atomic64_read(&acdb_data.mem_len));
+ if (cal_block->cal_offset > acdb_data.mem_len) {
+ pr_err("%s: offset %d is > mem_len %llu\n",
+ __func__, cal_block->cal_offset, acdb_data.mem_len);
result = -EINVAL;
goto done;
}
@@ -667,12 +628,11 @@
goto done;
}
- atomic_set(&acdb_data.audstrm_cal[path].cal_size,
- cal_block->cal_size);
- atomic_set(&acdb_data.audstrm_cal[path].cal_paddr,
- cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
- atomic_set(&acdb_data.audstrm_cal[path].cal_kvaddr,
- cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
+ acdb_data.audstrm_cal[path].cal_size = cal_block->cal_size;
+ acdb_data.audstrm_cal[path].cal_paddr =
+ cal_block->cal_offset + acdb_data.paddr;
+ acdb_data.audstrm_cal[path].cal_kvaddr =
+ cal_block->cal_offset + acdb_data.kvaddr;
done:
return result;
}
@@ -694,12 +654,9 @@
goto done;
}
- cal_block->cal_size =
- atomic_read(&acdb_data.audstrm_cal[path].cal_size);
- cal_block->cal_paddr =
- atomic_read(&acdb_data.audstrm_cal[path].cal_paddr);
- cal_block->cal_kvaddr =
- atomic_read(&acdb_data.audstrm_cal[path].cal_kvaddr);
+ cal_block->cal_size = acdb_data.audstrm_cal[path].cal_size;
+ cal_block->cal_paddr = acdb_data.audstrm_cal[path].cal_paddr;
+ cal_block->cal_kvaddr = acdb_data.audstrm_cal[path].cal_kvaddr;
done:
return result;
}
@@ -709,10 +666,9 @@
int result = 0;
pr_debug("%s, path = %d\n", __func__, path);
- if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
- pr_err("%s: offset %d is > mem_len %ld\n",
- __func__, cal_block->cal_offset,
- (long)atomic64_read(&acdb_data.mem_len));
+ if (cal_block->cal_offset > acdb_data.mem_len) {
+ pr_err("%s: offset %d is > mem_len %llu\n",
+ __func__, cal_block->cal_offset, acdb_data.mem_len);
result = -EINVAL;
goto done;
}
@@ -723,12 +679,11 @@
goto done;
}
- atomic_set(&acdb_data.audvol_cal[path].cal_size,
- cal_block->cal_size);
- atomic_set(&acdb_data.audvol_cal[path].cal_paddr,
- cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
- atomic_set(&acdb_data.audvol_cal[path].cal_kvaddr,
- cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
+ acdb_data.audvol_cal[path].cal_size = cal_block->cal_size;
+ acdb_data.audvol_cal[path].cal_paddr =
+ cal_block->cal_offset + acdb_data.paddr;
+ acdb_data.audvol_cal[path].cal_kvaddr =
+ cal_block->cal_offset + acdb_data.kvaddr;
done:
return result;
}
@@ -750,12 +705,9 @@
goto done;
}
- cal_block->cal_size =
- atomic_read(&acdb_data.audvol_cal[path].cal_size);
- cal_block->cal_paddr =
- atomic_read(&acdb_data.audvol_cal[path].cal_paddr);
- cal_block->cal_kvaddr =
- atomic_read(&acdb_data.audvol_cal[path].cal_kvaddr);
+ cal_block->cal_size = acdb_data.audvol_cal[path].cal_size;
+ cal_block->cal_paddr = acdb_data.audvol_cal[path].cal_paddr;
+ cal_block->cal_kvaddr = acdb_data.audvol_cal[path].cal_kvaddr;
done:
return result;
}
@@ -766,22 +718,30 @@
int result = 0;
pr_debug("%s,\n", __func__);
+ if (cal_block == NULL) {
+ pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+ result = -EINVAL;
+ goto done;
+ }
if (cal_size > MAX_COL_SIZE) {
- pr_err("%s: col size is to big %d\n", __func__,
- cal_size);
+ pr_err("%s: col size is to big %d\n", __func__, cal_size);
+ result = -EINVAL;
+ goto done;
+ }
+ if (acdb_data.col_data[vocproc_type] == NULL) {
+ pr_err("%s: vocproc_type %d data not allocated!\n",
+ __func__, vocproc_type);
result = -EINVAL;
goto done;
}
if (copy_from_user(acdb_data.col_data[vocproc_type],
(void *)((uint8_t *)cal_block + sizeof(cal_size)),
cal_size)) {
- pr_err("%s: fail to copy col size %d\n",
- __func__, cal_size);
+ pr_err("%s: fail to copy col size %d\n", __func__, cal_size);
result = -EINVAL;
goto done;
}
- atomic_set(&acdb_data.vocproc_col_cal[vocproc_type].cal_size,
- cal_size);
+ acdb_data.vocproc_col_cal[vocproc_type].cal_size = cal_size;
done:
return result;
}
@@ -797,13 +757,19 @@
result = -EINVAL;
goto done;
}
+ if (acdb_data.col_data[vocproc_type] == NULL) {
+ pr_err("%s: vocproc_type %d data not allocated!\n",
+ __func__, vocproc_type);
+ result = -EINVAL;
+ goto done;
+ }
- cal_block->cal_size = atomic_read(&acdb_data.
- vocproc_col_cal[vocproc_type].cal_size);
- cal_block->cal_paddr = atomic_read(&acdb_data.
- vocproc_col_cal[vocproc_type].cal_paddr);
- cal_block->cal_kvaddr = atomic_read(&acdb_data.
- vocproc_col_cal[vocproc_type].cal_kvaddr);
+ cal_block->cal_size = acdb_data.
+ vocproc_col_cal[vocproc_type].cal_size;
+ cal_block->cal_paddr = acdb_data.
+ vocproc_col_cal[vocproc_type].cal_paddr;
+ cal_block->cal_kvaddr = acdb_data.
+ vocproc_col_cal[vocproc_type].cal_kvaddr;
done:
return result;
}
@@ -815,24 +781,19 @@
if (cal_block->cal_offset >
- atomic64_read(&acdb_data.mem_len)) {
- pr_err("%s: offset %d is > mem_len %ld\n",
- __func__, cal_block->cal_offset,
- (long)atomic64_read(&acdb_data.mem_len));
- atomic_set(&acdb_data.vocproc_dev_cal.cal_size, 0);
+ acdb_data.mem_len) {
+ pr_err("%s: offset %d is > mem_len %llu\n",
+ __func__, cal_block->cal_offset, acdb_data.mem_len);
+ acdb_data.vocproc_dev_cal.cal_size = 0;
result = -EINVAL;
goto done;
}
- atomic_set(&acdb_data.vocproc_dev_cal.cal_size,
- cal_block->cal_size);
- atomic_set(&acdb_data.vocproc_dev_cal.cal_paddr,
- cal_block->cal_offset +
- atomic64_read(&acdb_data.paddr));
- atomic_set(&acdb_data.vocproc_dev_cal.cal_kvaddr,
- cal_block->cal_offset +
- atomic64_read(&acdb_data.kvaddr));
-
+ acdb_data.vocproc_dev_cal.cal_size = cal_block->cal_size;
+ acdb_data.vocproc_dev_cal.cal_paddr =
+ cal_block->cal_offset + acdb_data.paddr;
+ acdb_data.vocproc_dev_cal.cal_kvaddr =
+ cal_block->cal_offset + acdb_data.kvaddr;
done:
return result;
}
@@ -848,12 +809,9 @@
goto done;
}
- cal_block->cal_size =
- atomic_read(&acdb_data.vocproc_dev_cal.cal_size);
- cal_block->cal_paddr =
- atomic_read(&acdb_data.vocproc_dev_cal.cal_paddr);
- cal_block->cal_kvaddr =
- atomic_read(&acdb_data.vocproc_dev_cal.cal_kvaddr);
+ cal_block->cal_size = acdb_data.vocproc_dev_cal.cal_size;
+ cal_block->cal_paddr = acdb_data.vocproc_dev_cal.cal_paddr;
+ cal_block->cal_kvaddr = acdb_data.vocproc_dev_cal.cal_kvaddr;
done:
return result;
}
@@ -866,24 +824,19 @@
pr_debug("%s,\n", __func__);
if (cal_block->cal_offset >
- atomic64_read(&acdb_data.mem_len)) {
- pr_err("%s: offset %d is > mem_len %ld\n",
- __func__, cal_block->cal_offset,
- (long)atomic64_read(&acdb_data.mem_len));
- atomic_set(&acdb_data.vocproc_cal.cal_size, 0);
+ acdb_data.mem_len) {
+ pr_err("%s: offset %d is > mem_len %llu\n",
+ __func__, cal_block->cal_offset, acdb_data.mem_len);
+ acdb_data.vocproc_cal.cal_size = 0;
result = -EINVAL;
goto done;
}
- atomic_set(&acdb_data.vocproc_cal.cal_size,
- cal_block->cal_size);
- atomic_set(&acdb_data.vocproc_cal.cal_paddr,
- cal_block->cal_offset +
- atomic64_read(&acdb_data.paddr));
- atomic_set(&acdb_data.vocproc_cal.cal_kvaddr,
- cal_block->cal_offset +
- atomic64_read(&acdb_data.kvaddr));
-
+ acdb_data.vocproc_cal.cal_size = cal_block->cal_size;
+ acdb_data.vocproc_cal.cal_paddr =
+ cal_block->cal_offset + acdb_data.paddr;
+ acdb_data.vocproc_cal.cal_kvaddr =
+ cal_block->cal_offset + acdb_data.kvaddr;
done:
return result;
}
@@ -899,12 +852,9 @@
goto done;
}
- cal_block->cal_size =
- atomic_read(&acdb_data.vocproc_cal.cal_size);
- cal_block->cal_paddr =
- atomic_read(&acdb_data.vocproc_cal.cal_paddr);
- cal_block->cal_kvaddr =
- atomic_read(&acdb_data.vocproc_cal.cal_kvaddr);
+ cal_block->cal_size = acdb_data.vocproc_cal.cal_size;
+ cal_block->cal_paddr = acdb_data.vocproc_cal.cal_paddr;
+ cal_block->cal_kvaddr = acdb_data.vocproc_cal.cal_kvaddr;
done:
return result;
}
@@ -915,24 +865,19 @@
pr_debug("%s,\n", __func__);
if (cal_block->cal_offset >
- atomic64_read(&acdb_data.mem_len)) {
- pr_err("%s: offset %d is > mem_len %ld\n",
- __func__, cal_block->cal_offset,
- (long)atomic64_read(&acdb_data.mem_len));
- atomic_set(&acdb_data.vocstrm_cal.cal_size, 0);
+ acdb_data.mem_len) {
+ pr_err("%s: offset %d is > mem_len %llu\n",
+ __func__, cal_block->cal_offset, acdb_data.mem_len);
+ acdb_data.vocstrm_cal.cal_size = 0;
result = -EINVAL;
goto done;
}
- atomic_set(&acdb_data.vocstrm_cal.cal_size,
- cal_block->cal_size);
- atomic_set(&acdb_data.vocstrm_cal.cal_paddr,
- cal_block->cal_offset +
- atomic64_read(&acdb_data.paddr));
- atomic_set(&acdb_data.vocstrm_cal.cal_kvaddr,
- cal_block->cal_offset +
- atomic64_read(&acdb_data.kvaddr));
-
+ acdb_data.vocstrm_cal.cal_size = cal_block->cal_size;
+ acdb_data.vocstrm_cal.cal_paddr =
+ cal_block->cal_offset + acdb_data.paddr;
+ acdb_data.vocstrm_cal.cal_kvaddr =
+ cal_block->cal_offset + acdb_data.kvaddr;
done:
return result;
}
@@ -948,12 +893,9 @@
goto done;
}
- cal_block->cal_size =
- atomic_read(&acdb_data.vocstrm_cal.cal_size);
- cal_block->cal_paddr =
- atomic_read(&acdb_data.vocstrm_cal.cal_paddr);
- cal_block->cal_kvaddr =
- atomic_read(&acdb_data.vocstrm_cal.cal_kvaddr);
+ cal_block->cal_size = acdb_data.vocstrm_cal.cal_size;
+ cal_block->cal_paddr = acdb_data.vocstrm_cal.cal_paddr;
+ cal_block->cal_kvaddr = acdb_data.vocstrm_cal.cal_kvaddr;
done:
return result;
}
@@ -963,25 +905,19 @@
int result = 0;
pr_debug("%s,\n", __func__);
- if (cal_block->cal_offset >
- atomic64_read(&acdb_data.mem_len)) {
- pr_err("%s: offset %d is > mem_len %ld\n",
- __func__, cal_block->cal_offset,
- (long)atomic64_read(&acdb_data.mem_len));
- atomic_set(&acdb_data.vocvol_cal.cal_size, 0);
+ if (cal_block->cal_offset > acdb_data.mem_len) {
+ pr_err("%s: offset %d is > mem_len %llu\n",
+ __func__, cal_block->cal_offset, acdb_data.mem_len);
+ acdb_data.vocvol_cal.cal_size = 0;
result = -EINVAL;
goto done;
}
- atomic_set(&acdb_data.vocvol_cal.cal_size,
- cal_block->cal_size);
- atomic_set(&acdb_data.vocvol_cal.cal_paddr,
- cal_block->cal_offset +
- atomic64_read(&acdb_data.paddr));
- atomic_set(&acdb_data.vocvol_cal.cal_kvaddr,
- cal_block->cal_offset +
- atomic64_read(&acdb_data.kvaddr));
-
+ acdb_data.vocvol_cal.cal_size = cal_block->cal_size;
+ acdb_data.vocvol_cal.cal_paddr =
+ cal_block->cal_offset + acdb_data.paddr;
+ acdb_data.vocvol_cal.cal_kvaddr =
+ cal_block->cal_offset + acdb_data.kvaddr;
done:
return result;
}
@@ -997,12 +933,9 @@
goto done;
}
- cal_block->cal_size =
- atomic_read(&acdb_data.vocvol_cal.cal_size);
- cal_block->cal_paddr =
- atomic_read(&acdb_data.vocvol_cal.cal_paddr);
- cal_block->cal_kvaddr =
- atomic_read(&acdb_data.vocvol_cal.cal_kvaddr);
+ cal_block->cal_size = acdb_data.vocvol_cal.cal_size;
+ cal_block->cal_paddr = acdb_data.vocvol_cal.cal_paddr;
+ cal_block->cal_kvaddr = acdb_data.vocvol_cal.cal_kvaddr;
done:
return result;
}
@@ -1011,8 +944,8 @@
{
pr_debug("%s,\n", __func__);
- atomic_set(&acdb_data.sidetone_cal.enable, cal_data->enable);
- atomic_set(&acdb_data.sidetone_cal.gain, cal_data->gain);
+ acdb_data.sidetone_cal.enable = cal_data->enable;
+ acdb_data.sidetone_cal.gain = cal_data->gain;
}
int get_sidetone_cal(struct sidetone_cal *cal_data)
@@ -1026,8 +959,10 @@
goto done;
}
- cal_data->enable = atomic_read(&acdb_data.sidetone_cal.enable);
- cal_data->gain = atomic_read(&acdb_data.sidetone_cal.gain);
+ mutex_lock(&acdb_data.acdb_mutex);
+ cal_data->enable = acdb_data.sidetone_cal.enable;
+ cal_data->gain = acdb_data.sidetone_cal.gain;
+ mutex_unlock(&acdb_data.acdb_mutex);
done:
return result;
}
@@ -1111,20 +1046,32 @@
s32 result = 0;
pr_debug("%s\n", __func__);
- if (atomic64_read(&acdb_data.mem_len)) {
+ mutex_lock(&acdb_data.acdb_mutex);
+ if (acdb_data.mem_len)
pr_debug("%s: ACDB opened but memory allocated, using existing allocation!\n",
__func__);
- }
- atomic_set(&acdb_data.valid_adm_custom_top, 1);
- atomic_set(&acdb_data.valid_asm_custom_top, 1);
- atomic_inc(&usage_count);
+ acdb_data.valid_adm_custom_top = 1;
+ acdb_data.valid_asm_custom_top = 1;
+ acdb_data.usage_count++;
+ mutex_unlock(&acdb_data.acdb_mutex);
return result;
}
-static void allocate_hw_delay_entries(void)
+static void deallocate_hw_delay_entries(void)
{
+ kfree(acdb_data.hw_delay_rx.delay_info);
+ kfree(acdb_data.hw_delay_tx.delay_info);
+
+ acdb_data.hw_delay_rx.delay_info = NULL;
+ acdb_data.hw_delay_tx.delay_info = NULL;
+}
+
+static int allocate_hw_delay_entries(void)
+{
+ int result = 0;
+
/* Allocate memory for hw delay entries */
acdb_data.hw_delay_rx.num_entries = 0;
acdb_data.hw_delay_tx.num_entries = 0;
@@ -1135,6 +1082,8 @@
if (acdb_data.hw_delay_rx.delay_info == NULL) {
pr_err("%s : Failed to allocate av sync delay entries rx\n",
__func__);
+ result = -ENOMEM;
+ goto done;
}
acdb_data.hw_delay_tx.delay_info =
kmalloc(sizeof(struct hw_delay_entry)*
@@ -1143,7 +1092,44 @@
if (acdb_data.hw_delay_tx.delay_info == NULL) {
pr_err("%s : Failed to allocate av sync delay entries tx\n",
__func__);
+ deallocate_hw_delay_entries();
+ result = -ENOMEM;
+ goto done;
}
+done:
+ return result;
+}
+
+static void deallocate_col_data(void)
+{
+ int i;
+
+ for (i = 0; i < MAX_VOCPROC_TYPES; i++) {
+ kfree(acdb_data.col_data[i]);
+ acdb_data.col_data[i] = NULL;
+ }
+}
+
+static int allocate_col_data(void)
+{
+ int result = 0;
+ int i;
+
+ for (i = 0; i < MAX_VOCPROC_TYPES; i++) {
+ acdb_data.col_data[i] = kmalloc(MAX_COL_SIZE, GFP_KERNEL);
+ if (acdb_data.col_data[i] == NULL) {
+ pr_err("%s: kmalloc column data failed, type = %d\n",
+ __func__, i);
+ deallocate_col_data();
+ result = -ENOMEM;
+ goto done;
+ }
+ acdb_data.vocproc_col_cal[i].cal_kvaddr =
+ (uint32_t)acdb_data.col_data[i];
+ }
+
+done:
+ return result;
}
static int unmap_cal_tables(void)
@@ -1192,81 +1178,81 @@
static int deregister_memory(void)
{
int result = 0;
- int i;
pr_debug("%s\n", __func__);
- mutex_lock(&acdb_data.acdb_mutex);
- kfree(acdb_data.hw_delay_tx.delay_info);
- kfree(acdb_data.hw_delay_rx.delay_info);
+ if (acdb_data.mem_len == 0)
+ goto done;
- if (atomic64_read(&acdb_data.mem_len)) {
- /* unmap all cal data */
- result = unmap_cal_tables();
- if (result < 0)
- pr_err("%s: unmap_cal_tables failed, err = %d\n",
- __func__, result);
+ pr_debug("Remove existing memory\n");
+ acdb_data.mem_len = 0;
- atomic64_set(&acdb_data.mem_len, 0);
+ /* unmap all cal data */
+ result = unmap_cal_tables();
+ if (result < 0)
+ pr_err("%s: unmap_cal_tables failed, err = %d\n",
+ __func__, result);
- for (i = 0; i < MAX_VOCPROC_TYPES; i++) {
- kfree(acdb_data.col_data[i]);
- acdb_data.col_data[i] = NULL;
- }
- msm_audio_ion_free(acdb_data.ion_client, acdb_data.ion_handle);
- acdb_data.ion_client = NULL;
- acdb_data.ion_handle = NULL;
- mutex_unlock(&acdb_data.acdb_mutex);
- }
- mutex_unlock(&acdb_data.acdb_mutex);
- return 0;
+ msm_audio_ion_free(acdb_data.ion_client, acdb_data.ion_handle);
+ acdb_data.ion_client = NULL;
+ acdb_data.ion_handle = NULL;
+
+ deallocate_col_data();
+ deallocate_hw_delay_entries();
+done:
+ return result;
}
static int register_memory(void)
{
int result;
- int i;
ion_phys_addr_t paddr;
void *kvptr;
unsigned long kvaddr;
unsigned long mem_len;
pr_debug("%s\n", __func__);
- mutex_lock(&acdb_data.acdb_mutex);
- allocate_hw_delay_entries();
- for (i = 0; i < MAX_VOCPROC_TYPES; i++) {
- acdb_data.col_data[i] = kmalloc(MAX_COL_SIZE, GFP_KERNEL);
- atomic_set(&acdb_data.vocproc_col_cal[i].cal_kvaddr,
- (uint32_t)acdb_data.col_data[i]);
+ result = allocate_col_data();
+ if (result) {
+ pr_err("%s: allocate_col_data failed, rc = %d\n",
+ __func__, result);
+ goto err_done;
+ }
+
+ result = allocate_hw_delay_entries();
+ if (result) {
+ pr_err("%s: allocate_hw_delay_entries failed, rc = %d\n",
+ __func__, result);
+ goto err_col;
}
result = msm_audio_ion_import("audio_acdb_client",
&acdb_data.ion_client,
&acdb_data.ion_handle,
- atomic_read(&acdb_data.map_handle),
+ acdb_data.map_handle,
NULL, 0,
&paddr, (size_t *)&mem_len, &kvptr);
if (result) {
pr_err("%s: audio ION alloc failed, rc = %d\n",
__func__, result);
- result = PTR_ERR(acdb_data.ion_client);
- goto err_ion_handle;
+ goto err_hw_delay;
}
- kvaddr = (unsigned long)kvptr;
- atomic64_set(&acdb_data.paddr, paddr);
- atomic64_set(&acdb_data.kvaddr, kvaddr);
- atomic64_set(&acdb_data.mem_len, mem_len);
- mutex_unlock(&acdb_data.acdb_mutex);
- pr_debug("%s done! paddr = 0x%lx, kvaddr = 0x%lx, len = x%lx\n",
- __func__,
- (long)atomic64_read(&acdb_data.paddr),
- (long)atomic64_read(&acdb_data.kvaddr),
- (long)atomic64_read(&acdb_data.mem_len));
+ kvaddr = (unsigned long)kvptr;
+ acdb_data.paddr = paddr;
+ acdb_data.kvaddr = kvaddr;
+ acdb_data.mem_len = mem_len;
+
+ pr_debug("%s done! paddr = 0x%llx, kvaddr = 0x%llx, len = 0x%llx\n",
+ __func__, acdb_data.paddr, acdb_data.kvaddr,
+ acdb_data.mem_len);
return result;
-err_ion_handle:
- atomic64_set(&acdb_data.mem_len, 0);
- mutex_unlock(&acdb_data.acdb_mutex);
+err_hw_delay:
+ deallocate_hw_delay_entries();
+err_col:
+ deallocate_col_data();
+err_done:
+ acdb_data.mem_len = 0;
return result;
}
static long acdb_ioctl(struct file *f,
@@ -1281,26 +1267,26 @@
struct msm_spk_prot_status acdb_spk_status;
pr_debug("%s\n", __func__);
+ mutex_lock(&acdb_data.acdb_mutex);
switch (cmd) {
case AUDIO_REGISTER_PMEM:
pr_debug("AUDIO_REGISTER_PMEM\n");
- if (atomic_read(&acdb_data.mem_len)) {
- deregister_memory();
- pr_debug("Remove the existing memory\n");
- }
+ result = deregister_memory();
+ if (result < 0)
+ pr_err("%s: deregister_memory failed returned %d!\n",
+ __func__, result);
if (copy_from_user(&map_fd, (void *)arg, sizeof(map_fd))) {
pr_err("%s: fail to copy memory handle!\n", __func__);
result = -EFAULT;
} else {
- atomic_set(&acdb_data.map_handle, map_fd);
+ acdb_data.map_handle = map_fd;
result = register_memory();
}
goto done;
-
case AUDIO_DEREGISTER_PMEM:
pr_debug("AUDIO_DEREGISTER_PMEM\n");
- deregister_memory();
+ result = deregister_memory();
goto done;
case AUDIO_SET_VOICE_RX_TOPOLOGY:
if (copy_from_user(&topology, (void *)arg,
@@ -1343,16 +1329,13 @@
store_asm_topology(topology);
goto done;
case AUDIO_SET_SPEAKER_PROT:
- mutex_lock(&acdb_data.acdb_mutex);
if (copy_from_user(&acdb_data.spk_prot_cfg, (void *)arg,
sizeof(acdb_data.spk_prot_cfg))) {
pr_err("%s fail to copy spk_prot_cfg\n", __func__);
result = -EFAULT;
}
- mutex_unlock(&acdb_data.acdb_mutex);
goto done;
case AUDIO_GET_SPEAKER_PROT:
- mutex_lock(&acdb_data.acdb_mutex);
/*Indicates calibration was succesfull*/
if (acdb_data.spk_prot_cfg.mode == MSM_SPKR_PROT_CALIBRATED) {
prot_status.r0 = acdb_data.spk_prot_cfg.r0;
@@ -1379,7 +1362,6 @@
sizeof(prot_status))) {
pr_err("%s: Failed to update prot_status\n", __func__);
}
- mutex_unlock(&acdb_data.acdb_mutex);
goto done;
case AUDIO_REGISTER_VOCPROC_VOL_TABLE:
result = register_vocvol_table();
@@ -1502,23 +1484,25 @@
}
done:
+ mutex_unlock(&acdb_data.acdb_mutex);
return result;
}
static int acdb_mmap(struct file *file, struct vm_area_struct *vma)
{
int result = 0;
- uint32_t size = vma->vm_end - vma->vm_start;
+ size_t size = vma->vm_end - vma->vm_start;
pr_debug("%s\n", __func__);
- if (atomic64_read(&acdb_data.mem_len)) {
- if (size <= atomic64_read(&acdb_data.mem_len)) {
+ mutex_lock(&acdb_data.acdb_mutex);
+ if (acdb_data.mem_len) {
+ if (size <= acdb_data.mem_len) {
vma->vm_page_prot = pgprot_noncached(
vma->vm_page_prot);
result = remap_pfn_range(vma,
vma->vm_start,
- atomic64_read(&acdb_data.paddr) >> PAGE_SHIFT,
+ acdb_data.paddr >> PAGE_SHIFT,
size,
vma->vm_page_prot);
} else {
@@ -1529,25 +1513,29 @@
pr_err("%s: memory is not allocated, yet!\n", __func__);
result = -ENODEV;
}
+ mutex_unlock(&acdb_data.acdb_mutex);
return result;
}
static int acdb_release(struct inode *inode, struct file *f)
{
- s32 result = 0;
+ int result = 0;
+ pr_debug("%s\n", __func__);
- atomic_dec(&usage_count);
- atomic_read(&usage_count);
+ mutex_lock(&acdb_data.acdb_mutex);
+ acdb_data.usage_count--;
- pr_debug("%s: ref count %d!\n", __func__,
- atomic_read(&usage_count));
+ pr_debug("%s: ref count %d!\n", __func__, acdb_data.usage_count);
- if (atomic_read(&usage_count) >= 1)
+ if (acdb_data.usage_count > 0) {
result = -EBUSY;
- else
- result = deregister_memory();
+ goto done;
+ }
+ result = deregister_memory();
+done:
+ mutex_unlock(&acdb_data.acdb_mutex);
return result;
}
@@ -1571,9 +1559,9 @@
/*Speaker protection disabled*/
acdb_data.spk_prot_cfg.mode = MSM_SPKR_PROT_DISABLED;
mutex_init(&acdb_data.acdb_mutex);
- atomic_set(&usage_count, 0);
- atomic_set(&acdb_data.valid_adm_custom_top, 1);
- atomic_set(&acdb_data.valid_asm_custom_top, 1);
+ acdb_data.usage_count = 0;
+ acdb_data.valid_adm_custom_top = 1;
+ acdb_data.valid_asm_custom_top = 1;
return misc_register(&acdb_misc);
}
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.h b/sound/soc/msm/qdsp6v2/audio_acdb.h
index e2ca395..45a83f6 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.h
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.h
@@ -35,12 +35,6 @@
uint32_t cal_paddr;
};
-struct acdb_atomic_cal_block {
- atomic_t cal_size;
- atomic_t cal_kvaddr;
- atomic_t cal_paddr;
-};
-
struct hw_delay_entry {
uint32_t sample_rate;
uint32_t delay_usec;
diff --git a/sound/soc/msm/qdsp6v2/audio_ocmem.c b/sound/soc/msm/qdsp6v2/audio_ocmem.c
index 93b3597..4a25606 100644
--- a/sound/soc/msm/qdsp6v2/audio_ocmem.c
+++ b/sound/soc/msm/qdsp6v2/audio_ocmem.c
@@ -879,6 +879,15 @@
pr_debug("%s\n", __func__);
+ audio_ocmem_lcl.audio_hdl = ocmem_notifier_register(OCMEM_LP_AUDIO,
+ &audio_ocmem_client_nb);
+ if (PTR_RET(audio_ocmem_lcl.audio_hdl) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ else if (!audio_ocmem_lcl.audio_hdl) {
+ pr_err("%s: Failed to get ocmem handle %d\n", __func__,
+ OCMEM_LP_AUDIO);
+ return -ENODEV;
+ }
subsys_notif_register_notifier("adsp", &anb);
audio_ocmem_lcl.ocmem_dump_addr =
@@ -944,12 +953,6 @@
ret = -EFAULT;
goto destroy_voice_wq;
}
- audio_ocmem_lcl.audio_hdl = ocmem_notifier_register(OCMEM_LP_AUDIO,
- &audio_ocmem_client_nb);
- if (audio_ocmem_lcl.audio_hdl == NULL) {
- pr_err("%s: Failed to get ocmem handle %d\n", __func__,
- OCMEM_LP_AUDIO);
- }
audio_ocmem_lcl.lp_memseg_ptr = NULL;
return 0;
destroy_voice_wq:
diff --git a/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.c
new file mode 100644
index 0000000..5e4d9d3
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.c
@@ -0,0 +1,721 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+#include <sound/apr_audio-v2.h>
+#include <sound/q6asm-v2.h>
+#include <sound/compress_params.h>
+#include "msm-audio-effects-q6-v2.h"
+
+int msm_audio_effects_virtualizer_handler(struct audio_client *ac,
+ struct virtualizer_params *virtualizer,
+ long *values)
+{
+ int devices = *values++;
+ int num_commands = *values++;
+ char *params;
+ int *updt_params, i, prev_enable_flag;
+ uint32_t params_length = (MAX_INBAND_PARAM_SZ);
+ int rc = 0;
+
+ pr_debug("%s\n", __func__);
+ if (!ac) {
+ pr_err("%s: cannot set audio effects\n", __func__);
+ return -EINVAL;
+ }
+ params = kzalloc(params_length, GFP_KERNEL);
+ if (!params) {
+ pr_err("%s, params memory alloc failed\n", __func__);
+ return -ENOMEM;
+ }
+ pr_debug("%s: device: %d\n", __func__, devices);
+ updt_params = (int *)params;
+ params_length = 0;
+ for (i = 0; i < num_commands; i++) {
+ uint32_t command_id = *values++;
+ uint32_t command_config_state = *values++;
+ uint32_t index_offset = *values++;
+ uint32_t length = *values++;
+ switch (command_id) {
+ case VIRTUALIZER_ENABLE:
+ pr_debug("%s: VIRTUALIZER_ENABLE\n", __func__);
+ if (length != 1 || index_offset != 0) {
+ pr_err("no valid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ prev_enable_flag = virtualizer->enable_flag;
+ virtualizer->enable_flag = *values++;
+ if (prev_enable_flag != virtualizer->enable_flag) {
+ *updt_params++ = AUDPROC_MODULE_ID_VIRTUALIZER;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_VIRTUALIZER_ENABLE;
+ *updt_params++ = VIRTUALIZER_ENABLE_PARAM_SZ;
+ *updt_params++ = virtualizer->enable_flag;
+ params_length += COMMAND_PAYLOAD_SZ +
+ VIRTUALIZER_ENABLE_PARAM_SZ;
+ }
+ break;
+ case VIRTUALIZER_STRENGTH:
+ pr_debug("%s: VIRTUALIZER_STRENGTH\n", __func__);
+ if (length != 1 || index_offset != 0) {
+ pr_err("no valid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ virtualizer->strength = *values++;
+ if (command_config_state == CONFIG_SET) {
+ *updt_params++ = AUDPROC_MODULE_ID_VIRTUALIZER;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_VIRTUALIZER_STRENGTH;
+ *updt_params++ = VIRTUALIZER_STRENGTH_PARAM_SZ;
+ *updt_params++ = virtualizer->strength;
+ params_length += COMMAND_PAYLOAD_SZ +
+ VIRTUALIZER_STRENGTH_PARAM_SZ;
+ }
+ break;
+ case VIRTUALIZER_OUT_TYPE:
+ pr_debug("%s: VIRTUALIZER_OUT_TYPE\n", __func__);
+ if (length != 1 || index_offset != 0) {
+ pr_err("no valid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ virtualizer->out_type = *values++;
+ if (command_config_state == CONFIG_SET) {
+ *updt_params++ = AUDPROC_MODULE_ID_VIRTUALIZER;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_VIRTUALIZER_OUT_TYPE;
+ *updt_params++ = VIRTUALIZER_OUT_TYPE_PARAM_SZ;
+ *updt_params++ = virtualizer->out_type;
+ params_length += COMMAND_PAYLOAD_SZ +
+ VIRTUALIZER_OUT_TYPE_PARAM_SZ;
+ }
+ break;
+ case VIRTUALIZER_GAIN_ADJUST:
+ pr_debug("%s: VIRTUALIZER_GAIN_ADJUST\n", __func__);
+ if (length != 1 || index_offset != 0) {
+ pr_err("no valid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ virtualizer->gain_adjust = *values++;
+ if (command_config_state == CONFIG_SET) {
+ *updt_params++ = AUDPROC_MODULE_ID_VIRTUALIZER;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_VIRTUALIZER_GAIN_ADJUST;
+ *updt_params++ =
+ VIRTUALIZER_GAIN_ADJUST_PARAM_SZ;
+ *updt_params++ = virtualizer->gain_adjust;
+ params_length += COMMAND_PAYLOAD_SZ +
+ VIRTUALIZER_GAIN_ADJUST_PARAM_SZ;
+ }
+ break;
+ default:
+ pr_err("%s: Invalid command to set config\n", __func__);
+ break;
+ }
+ }
+ if (params_length)
+ q6asm_send_audio_effects_params(ac, params,
+ params_length);
+invalid_config:
+ kfree(params);
+ return rc;
+}
+
+int msm_audio_effects_reverb_handler(struct audio_client *ac,
+ struct reverb_params *reverb,
+ long *values)
+{
+ int devices = *values++;
+ int num_commands = *values++;
+ char *params;
+ int *updt_params, i, prev_enable_flag;
+ uint32_t params_length = (MAX_INBAND_PARAM_SZ);
+ int rc = 0;
+
+ pr_debug("%s\n", __func__);
+ if (!ac) {
+ pr_err("%s: cannot set audio effects\n", __func__);
+ return -EINVAL;
+ }
+ params = kzalloc(params_length, GFP_KERNEL);
+ if (!params) {
+ pr_err("%s, params memory alloc failed\n", __func__);
+ return -ENOMEM;
+ }
+ pr_debug("%s: device: %d\n", __func__, devices);
+ updt_params = (int *)params;
+ params_length = 0;
+ for (i = 0; i < num_commands; i++) {
+ uint32_t command_id = *values++;
+ uint32_t command_config_state = *values++;
+ uint32_t index_offset = *values++;
+ uint32_t length = *values++;
+ switch (command_id) {
+ case REVERB_ENABLE:
+ pr_debug("%s: REVERB_ENABLE\n", __func__);
+ if (length != 1 || index_offset != 0) {
+ pr_err("no valid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ prev_enable_flag = reverb->enable_flag;
+ reverb->enable_flag = *values++;
+ if (prev_enable_flag != reverb->enable_flag) {
+ *updt_params++ = AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ = AUDPROC_PARAM_ID_REVERB_ENABLE;
+ *updt_params++ = REVERB_ENABLE_PARAM_SZ;
+ *updt_params++ = reverb->enable_flag;
+ params_length += COMMAND_PAYLOAD_SZ +
+ REVERB_ENABLE_PARAM_SZ;
+ }
+ break;
+ case REVERB_MODE:
+ pr_debug("%s: REVERB_MODE\n", __func__);
+ if (length != 1 || index_offset != 0) {
+ pr_err("no valid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ reverb->mode = *values++;
+ if (command_config_state == CONFIG_SET) {
+ *updt_params++ = AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ = AUDPROC_PARAM_ID_REVERB_MODE;
+ *updt_params++ = REVERB_MODE_PARAM_SZ;
+ *updt_params++ = reverb->mode;
+ params_length += COMMAND_PAYLOAD_SZ +
+ REVERB_MODE_PARAM_SZ;
+ }
+ break;
+ case REVERB_PRESET:
+ pr_debug("%s: REVERB_PRESET\n", __func__);
+ if (length != 1 || index_offset != 0) {
+ pr_err("no valid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ reverb->preset = *values++;
+ if (command_config_state == CONFIG_SET) {
+ *updt_params++ = AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ = AUDPROC_PARAM_ID_REVERB_PRESET;
+ *updt_params++ = REVERB_PRESET_PARAM_SZ;
+ *updt_params++ = reverb->preset;
+ params_length += COMMAND_PAYLOAD_SZ +
+ REVERB_PRESET_PARAM_SZ;
+ }
+ break;
+ case REVERB_WET_MIX:
+ pr_debug("%s: REVERB_WET_MIX\n", __func__);
+ if (length != 1 || index_offset != 0) {
+ pr_err("no valid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ reverb->wet_mix = *values++;
+ if (command_config_state == CONFIG_SET) {
+ *updt_params++ = AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_WET_MIX;
+ *updt_params++ = REVERB_WET_MIX_PARAM_SZ;
+ *updt_params++ = reverb->wet_mix;
+ params_length += COMMAND_PAYLOAD_SZ +
+ REVERB_WET_MIX_PARAM_SZ;
+ }
+ break;
+ case REVERB_GAIN_ADJUST:
+ pr_debug("%s: REVERB_GAIN_ADJUST\n", __func__);
+ if (length != 1 || index_offset != 0) {
+ pr_err("no valid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ reverb->gain_adjust = *values++;
+ if (command_config_state == CONFIG_SET) {
+ *updt_params++ = AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_GAIN_ADJUST;
+ *updt_params++ = REVERB_GAIN_ADJUST_PARAM_SZ;
+ *updt_params++ = reverb->gain_adjust;
+ params_length += COMMAND_PAYLOAD_SZ +
+ REVERB_GAIN_ADJUST_PARAM_SZ;
+ }
+ break;
+ case REVERB_ROOM_LEVEL:
+ pr_debug("%s: REVERB_ROOM_LEVEL\n", __func__);
+ if (length != 1 || index_offset != 0) {
+ pr_err("no valid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ reverb->room_level = *values++;
+ if (command_config_state == CONFIG_SET) {
+ *updt_params++ = AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_ROOM_LEVEL;
+ *updt_params++ = REVERB_ROOM_LEVEL_PARAM_SZ;
+ *updt_params++ = reverb->room_level;
+ params_length += COMMAND_PAYLOAD_SZ +
+ REVERB_ROOM_LEVEL_PARAM_SZ;
+ }
+ break;
+ case REVERB_ROOM_HF_LEVEL:
+ pr_debug("%s: REVERB_ROOM_HF_LEVEL\n", __func__);
+ if (length != 1 || index_offset != 0) {
+ pr_err("no valid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ reverb->room_hf_level = *values++;
+ if (command_config_state == CONFIG_SET) {
+ *updt_params++ = AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_ROOM_HF_LEVEL;
+ *updt_params++ = REVERB_ROOM_HF_LEVEL_PARAM_SZ;
+ *updt_params++ = reverb->room_hf_level;
+ params_length += COMMAND_PAYLOAD_SZ +
+ REVERB_ROOM_HF_LEVEL_PARAM_SZ;
+ }
+ break;
+ case REVERB_DECAY_TIME:
+ pr_debug("%s: REVERB_DECAY_TIME\n", __func__);
+ if (length != 1 || index_offset != 0) {
+ pr_err("no valid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ reverb->decay_time = *values++;
+ if (command_config_state == CONFIG_SET) {
+ *updt_params++ = AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_DECAY_TIME;
+ *updt_params++ = REVERB_DECAY_TIME_PARAM_SZ;
+ *updt_params++ = reverb->decay_time;
+ params_length += COMMAND_PAYLOAD_SZ +
+ REVERB_DECAY_TIME_PARAM_SZ;
+ }
+ break;
+ case REVERB_DECAY_HF_RATIO:
+ pr_debug("%s: REVERB_DECAY_HF_RATIO\n", __func__);
+ if (length != 1 || index_offset != 0) {
+ pr_err("no valid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ reverb->decay_hf_ratio = *values++;
+ if (command_config_state == CONFIG_SET) {
+ *updt_params++ = AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_DECAY_HF_RATIO;
+ *updt_params++ = REVERB_DECAY_HF_RATIO_PARAM_SZ;
+ *updt_params++ = reverb->decay_hf_ratio;
+ params_length += COMMAND_PAYLOAD_SZ +
+ REVERB_DECAY_HF_RATIO_PARAM_SZ;
+ }
+ break;
+ case REVERB_REFLECTIONS_LEVEL:
+ pr_debug("%s: REVERB_REFLECTIONS_LEVEL\n", __func__);
+ if (length != 1 || index_offset != 0) {
+ pr_err("no valid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ reverb->reflections_level = *values++;
+ if (command_config_state == CONFIG_SET) {
+ *updt_params++ = AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_REFLECTIONS_LEVEL;
+ *updt_params++ =
+ REVERB_REFLECTIONS_LEVEL_PARAM_SZ;
+ *updt_params++ = reverb->reflections_level;
+ params_length += COMMAND_PAYLOAD_SZ +
+ REVERB_REFLECTIONS_LEVEL_PARAM_SZ;
+ }
+ break;
+ case REVERB_REFLECTIONS_DELAY:
+ pr_debug("%s: REVERB_REFLECTIONS_DELAY\n", __func__);
+ if (length != 1 || index_offset != 0) {
+ pr_err("no valid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ reverb->reflections_delay = *values++;
+ if (command_config_state == CONFIG_SET) {
+ *updt_params++ = AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_REFLECTIONS_DELAY;
+ *updt_params++ =
+ REVERB_REFLECTIONS_DELAY_PARAM_SZ;
+ *updt_params++ = reverb->reflections_delay;
+ params_length += COMMAND_PAYLOAD_SZ +
+ REVERB_REFLECTIONS_DELAY_PARAM_SZ;
+ }
+ break;
+ case REVERB_LEVEL:
+ pr_debug("%s: REVERB_LEVEL\n", __func__);
+ if (length != 1 || index_offset != 0) {
+ pr_err("no valid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ reverb->level = *values++;
+ if (command_config_state == CONFIG_SET) {
+ *updt_params++ = AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ = AUDPROC_PARAM_ID_REVERB_LEVEL;
+ *updt_params++ = REVERB_LEVEL_PARAM_SZ;
+ *updt_params++ = reverb->level;
+ params_length += COMMAND_PAYLOAD_SZ +
+ REVERB_LEVEL_PARAM_SZ;
+ }
+ break;
+ case REVERB_DELAY:
+ pr_debug("%s: REVERB_DELAY\n", __func__);
+ if (length != 1 || index_offset != 0) {
+ pr_err("no valid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ reverb->delay = *values++;
+ if (command_config_state == CONFIG_SET) {
+ *updt_params++ = AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ = AUDPROC_PARAM_ID_REVERB_DELAY;
+ *updt_params++ = REVERB_DELAY_PARAM_SZ;
+ *updt_params++ = reverb->delay;
+ params_length += COMMAND_PAYLOAD_SZ +
+ REVERB_DELAY_PARAM_SZ;
+ }
+ break;
+ case REVERB_DIFFUSION:
+ pr_debug("%s: REVERB_DIFFUSION\n", __func__);
+ if (length != 1 || index_offset != 0) {
+ pr_err("no valid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ reverb->diffusion = *values++;
+ if (command_config_state == CONFIG_SET) {
+ *updt_params++ = AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_DIFFUSION;
+ *updt_params++ = REVERB_DIFFUSION_PARAM_SZ;
+ *updt_params++ = reverb->diffusion;
+ params_length += COMMAND_PAYLOAD_SZ +
+ REVERB_DIFFUSION_PARAM_SZ;
+ }
+ break;
+ case REVERB_DENSITY:
+ pr_debug("%s: REVERB_DENSITY\n", __func__);
+ if (length != 1 || index_offset != 0) {
+ pr_err("no valid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ reverb->density = *values++;
+ if (command_config_state == CONFIG_SET) {
+ *updt_params++ = AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_DENSITY;
+ *updt_params++ = REVERB_DENSITY_PARAM_SZ;
+ *updt_params++ = reverb->density;
+ params_length += COMMAND_PAYLOAD_SZ +
+ REVERB_DENSITY_PARAM_SZ;
+ }
+ break;
+ default:
+ pr_err("%s: Invalid command to set config\n", __func__);
+ break;
+ }
+ }
+ if (params_length)
+ q6asm_send_audio_effects_params(ac, params,
+ params_length);
+invalid_config:
+ kfree(params);
+ return rc;
+}
+
+int msm_audio_effects_bass_boost_handler(struct audio_client *ac,
+ struct bass_boost_params *bass_boost,
+ long *values)
+{
+ int devices = *values++;
+ int num_commands = *values++;
+ char *params;
+ int *updt_params, i, prev_enable_flag;
+ uint32_t params_length = (MAX_INBAND_PARAM_SZ);
+ int rc = 0;
+
+ pr_debug("%s\n", __func__);
+ if (!ac) {
+ pr_err("%s: cannot set audio effects\n", __func__);
+ return -EINVAL;
+ }
+ params = kzalloc(params_length, GFP_KERNEL);
+ if (!params) {
+ pr_err("%s, params memory alloc failed\n", __func__);
+ return -ENOMEM;
+ }
+ pr_debug("%s: device: %d\n", __func__, devices);
+ updt_params = (int *)params;
+ params_length = 0;
+ for (i = 0; i < num_commands; i++) {
+ uint32_t command_id = *values++;
+ uint32_t command_config_state = *values++;
+ uint32_t index_offset = *values++;
+ uint32_t length = *values++;
+ switch (command_id) {
+ case BASS_BOOST_ENABLE:
+ pr_debug("%s: BASS_BOOST_ENABLE\n", __func__);
+ if (length != 1 || index_offset != 0) {
+ pr_err("no valid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ prev_enable_flag = bass_boost->enable_flag;
+ bass_boost->enable_flag = *values++;
+ if (prev_enable_flag != bass_boost->enable_flag) {
+ *updt_params++ = AUDPROC_MODULE_ID_BASS_BOOST;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_BASS_BOOST_ENABLE;
+ *updt_params++ = BASS_BOOST_ENABLE_PARAM_SZ;
+ *updt_params++ = bass_boost->enable_flag;
+ params_length += COMMAND_PAYLOAD_SZ +
+ BASS_BOOST_ENABLE_PARAM_SZ;
+ }
+ break;
+ case BASS_BOOST_MODE:
+ pr_debug("%s: BASS_BOOST_MODE\n", __func__);
+ if (length != 1 || index_offset != 0) {
+ pr_err("no valid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ bass_boost->mode = *values++;
+ if (command_config_state == CONFIG_SET) {
+ *updt_params++ = AUDPROC_MODULE_ID_BASS_BOOST;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_BASS_BOOST_MODE;
+ *updt_params++ = BASS_BOOST_MODE_PARAM_SZ;
+ *updt_params++ = bass_boost->mode;
+ params_length += COMMAND_PAYLOAD_SZ +
+ BASS_BOOST_MODE_PARAM_SZ;
+ }
+ break;
+ case BASS_BOOST_STRENGTH:
+ pr_debug("%s: BASS_BOOST_STRENGTH\n", __func__);
+ if (length != 1 || index_offset != 0) {
+ pr_err("no valid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ bass_boost->strength = *values++;
+ if (command_config_state == CONFIG_SET) {
+ *updt_params++ = AUDPROC_MODULE_ID_BASS_BOOST;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_BASS_BOOST_STRENGTH;
+ *updt_params++ = BASS_BOOST_STRENGTH_PARAM_SZ;
+ *updt_params++ = bass_boost->strength;
+ params_length += COMMAND_PAYLOAD_SZ +
+ BASS_BOOST_STRENGTH_PARAM_SZ;
+ }
+ break;
+ default:
+ pr_err("%s: Invalid command to set config\n", __func__);
+ break;
+ }
+ }
+ if (params_length)
+ q6asm_send_audio_effects_params(ac, params,
+ params_length);
+invalid_config:
+ kfree(params);
+ return rc;
+}
+
+int msm_audio_effects_popless_eq_handler(struct audio_client *ac,
+ struct eq_params *eq,
+ long *values)
+{
+ int devices = *values++;
+ int num_commands = *values++;
+ char *params;
+ int *updt_params, i, prev_enable_flag;
+ uint32_t params_length = (MAX_INBAND_PARAM_SZ);
+ int rc = 0;
+
+ pr_debug("%s\n", __func__);
+ if (!ac) {
+ pr_err("%s: cannot set audio effects\n", __func__);
+ return -EINVAL;
+ }
+ params = kzalloc(params_length, GFP_KERNEL);
+ if (!params) {
+ pr_err("%s, params memory alloc failed\n", __func__);
+ return -ENOMEM;
+ }
+ pr_debug("%s: device: %d\n", __func__, devices);
+ updt_params = (int *)params;
+ params_length = 0;
+ for (i = 0; i < num_commands; i++) {
+ uint32_t command_id = *values++;
+ uint32_t command_config_state = *values++;
+ uint32_t index_offset = *values++;
+ uint32_t length = *values++;
+ int idx, j;
+ switch (command_id) {
+ case EQ_ENABLE:
+ pr_debug("%s: EQ_ENABLE\n", __func__);
+ if (length != 1 || index_offset != 0) {
+ pr_err("no valid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ prev_enable_flag = eq->enable_flag;
+ eq->enable_flag = *values++;
+ pr_debug("%s: prev_enable_flag : %d, eq.enable_flag : %d",
+ __func__, prev_enable_flag, eq->enable_flag);
+ if (prev_enable_flag != eq->enable_flag) {
+ *updt_params++ =
+ AUDPROC_MODULE_ID_POPLESS_EQUALIZER;
+ *updt_params++ = AUDPROC_PARAM_ID_EQ_ENABLE;
+ *updt_params++ = EQ_ENABLE_PARAM_SZ;
+ *updt_params++ = eq->enable_flag;
+ params_length += COMMAND_PAYLOAD_SZ +
+ EQ_ENABLE_PARAM_SZ;
+ }
+ break;
+ case EQ_CONFIG:
+ pr_debug("%s: EQ_CONFIG\n", __func__);
+ if (length < EQ_CONFIG_PARAM_LEN || index_offset != 0) {
+ pr_err("no valid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ for (idx = 0; idx < MAX_EQ_BANDS; idx++)
+ eq->per_band_cfg[idx].band_idx = -1;
+ eq->config.eq_pregain = *values++;
+ eq->config.preset_id = *values++;
+ eq->config.num_bands = *values++;
+ if (eq->config.num_bands > MAX_EQ_BANDS) {
+ pr_err("invalid num of bands\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ if (eq->config.num_bands &&
+ (((length - EQ_CONFIG_PARAM_LEN)/
+ EQ_CONFIG_PER_BAND_PARAM_LEN)
+ != eq->config.num_bands)) {
+ pr_err("invalid length to set config per band\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ for (j = 0; j < eq->config.num_bands; j++) {
+ idx = *values++;
+ eq->per_band_cfg[idx].band_idx = idx;
+ eq->per_band_cfg[idx].filter_type = *values++;
+ eq->per_band_cfg[idx].freq_millihertz =
+ *values++;
+ eq->per_band_cfg[idx].gain_millibels =
+ *values++;
+ eq->per_band_cfg[idx].quality_factor =
+ *values++;
+ }
+ if (command_config_state == CONFIG_SET) {
+ int config_param_length = EQ_CONFIG_PARAM_SZ +
+ (EQ_CONFIG_PER_BAND_PARAM_SZ*
+ eq->config.num_bands);
+ *updt_params++ =
+ AUDPROC_MODULE_ID_POPLESS_EQUALIZER;
+ *updt_params++ = AUDPROC_PARAM_ID_EQ_CONFIG;
+ *updt_params++ = config_param_length;
+ *updt_params++ = eq->config.eq_pregain;
+ *updt_params++ = eq->config.preset_id;
+ *updt_params++ = eq->config.num_bands;
+ for (idx = 0; idx < MAX_EQ_BANDS; idx++) {
+ if (eq->per_band_cfg[idx].band_idx < 0)
+ continue;
+ *updt_params++ =
+ eq->per_band_cfg[idx].filter_type;
+ *updt_params++ =
+ eq->per_band_cfg[idx].freq_millihertz;
+ *updt_params++ =
+ eq->per_band_cfg[idx].gain_millibels;
+ *updt_params++ =
+ eq->per_band_cfg[idx].quality_factor;
+ *updt_params++ =
+ eq->per_band_cfg[idx].band_idx;
+ }
+ params_length += COMMAND_PAYLOAD_SZ +
+ config_param_length;
+ }
+ break;
+ case EQ_BAND_INDEX:
+ pr_debug("%s: EQ_BAND_INDEX\n", __func__);
+ if (length != 1 || index_offset != 0) {
+ pr_err("no valid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ idx = *values++;
+ if (idx > MAX_EQ_BANDS) {
+ pr_err("invalid band index\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ eq->band_index = idx;
+ if (command_config_state == CONFIG_SET) {
+ *updt_params++ =
+ AUDPROC_MODULE_ID_POPLESS_EQUALIZER;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_EQ_BAND_INDEX;
+ *updt_params++ = EQ_BAND_INDEX_PARAM_SZ;
+ *updt_params++ = eq->band_index;
+ params_length += COMMAND_PAYLOAD_SZ +
+ EQ_BAND_INDEX_PARAM_SZ;
+ }
+ break;
+ case EQ_SINGLE_BAND_FREQ:
+ pr_debug("%s: EQ_SINGLE_BAND_FREQ\n", __func__);
+ if (length != 1 || index_offset != 0) {
+ pr_err("no valid params\n");
+ rc = -EINVAL;
+ goto invalid_config;
+ }
+ if (eq->band_index > MAX_EQ_BANDS) {
+ pr_err("invalid band index to set frequency\n");
+ break;
+ }
+ eq->freq_millihertz = *values++;
+ if (command_config_state == CONFIG_SET) {
+ *updt_params++ =
+ AUDPROC_MODULE_ID_POPLESS_EQUALIZER;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_EQ_SINGLE_BAND_FREQ;
+ *updt_params++ = EQ_SINGLE_BAND_FREQ_PARAM_SZ;
+ *updt_params++ = eq->freq_millihertz;
+ params_length += COMMAND_PAYLOAD_SZ +
+ EQ_SINGLE_BAND_FREQ_PARAM_SZ;
+ }
+ break;
+ default:
+ pr_err("%s: Invalid command to set config\n", __func__);
+ break;
+ }
+ }
+ if (params_length)
+ q6asm_send_audio_effects_params(ac, params,
+ params_length);
+invalid_config:
+ kfree(params);
+ return rc;
+}
diff --git a/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.h b/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.h
new file mode 100644
index 0000000..3d2e6d4
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MSM_AUDIO_EFFECTS_H
+#define _MSM_AUDIO_EFFECTS_H
+
+#include <sound/audio_effects.h>
+
+int msm_audio_effects_reverb_handler(struct audio_client *ac,
+ struct reverb_params *reverb,
+ long *values);
+
+int msm_audio_effects_bass_boost_handler(struct audio_client *ac,
+ struct bass_boost_params *bass_boost,
+ long *values);
+int msm_audio_effects_virtualizer_handler(struct audio_client *ac,
+ struct virtualizer_params *virtualizer,
+ long *values);
+
+int msm_audio_effects_popless_eq_handler(struct audio_client *ac,
+ struct eq_params *eq,
+ long *values);
+#endif /*_MSM_AUDIO_EFFECTS_H*/
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
index fb362a1..bb325d8 100755
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -52,6 +52,9 @@
#define COMPRESSED_LR_VOL_MAX_STEPS 0x20002000
#define MAX_AC3_PARAM_SIZE (18*2*sizeof(int))
+#define AMR_WB_BAND_MODE 8
+#define AMR_WB_DTX_MODE 0
+
const DECLARE_TLV_DB_LINEAR(compr_rx_vol_gain, 0,
COMPRESSED_LR_VOL_MAX_STEPS);
@@ -108,12 +111,30 @@
8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
};
+/* Add supported codecs for compress capture path */
+static uint32_t supported_compr_capture_codecs[] = {
+ SND_AUDIOCODEC_AMRWB
+};
+
static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
.count = ARRAY_SIZE(supported_sample_rates),
.list = supported_sample_rates,
.mask = 0,
};
+static bool msm_compr_capture_codecs(uint32_t req_codec)
+{
+ int i;
+ pr_debug("%s req_codec:%d\n", __func__, req_codec);
+ if (req_codec == 0)
+ return false;
+ for (i = 0; i < ARRAY_SIZE(supported_compr_capture_codecs); i++) {
+ if (req_codec == supported_compr_capture_codecs[i])
+ return true;
+ }
+ return false;
+}
+
static void compr_event_handler(uint32_t opcode,
uint32_t token, uint32_t *payload, void *priv)
{
@@ -428,6 +449,11 @@
prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
prtd->pcm_irq_pos = 0;
+ if (!msm_compr_capture_codecs(codec->id)) {
+ /*request codec invalid or not supported,
+ use default compress format*/
+ codec->id = SND_AUDIOCODEC_AMRWB;
+ }
/* rate and channels are sent to audio driver */
prtd->samp_rate = runtime->rate;
prtd->channel_mode = runtime->channels;
@@ -441,8 +467,12 @@
pr_debug("SND_AUDIOCODEC_AMRWB\n");
ret = q6asm_enc_cfg_blk_amrwb(prtd->audio_client,
MAX_NUM_FRAMES_PER_BUFFER,
- codec->options.generic.reserved[0] /*bitrate 0-8*/,
- codec->options.generic.reserved[1] /*dtx mode 0/1*/);
+ /* use fixed band mode and dtx mode
+ * band mode - 23.85 kbps
+ */
+ AMR_WB_BAND_MODE,
+ /* dtx mode - disable */
+ AMR_WB_DTX_MODE);
if (ret < 0)
pr_err("%s: CMD Format block" \
"failed: %d\n", __func__, ret);
@@ -500,6 +530,13 @@
prtd->pcm_irq_pos = 0;
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ if (!msm_compr_capture_codecs(
+ compr->info.codec_param.codec.id)) {
+ /*request codec invalid or not supported,
+ use default compress format*/
+ compr->info.codec_param.codec.id =
+ SND_AUDIOCODEC_AMRWB;
+ }
switch (compr->info.codec_param.codec.id) {
case SND_AUDIOCODEC_AMRWB:
break;
@@ -834,6 +871,13 @@
pr_err("%s: Send SoftVolume Param failed ret=%d\n",
__func__, ret);
} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ if (!msm_compr_capture_codecs(
+ compr->info.codec_param.codec.id)) {
+ /*request codec invalid or not supported,
+ use default compress format*/
+ compr->info.codec_param.codec.id =
+ SND_AUDIOCODEC_AMRWB;
+ }
switch (compr->info.codec_param.codec.id) {
case SND_AUDIOCODEC_AMRWB:
pr_debug("q6asm_open_read(FORMAT_AMRWB)\n");
@@ -987,7 +1031,7 @@
struct snd_dec_ddp *ddp =
&compr->info.codec_param.codec.options.ddp;
uint32_t params_length = ddp->params_length*sizeof(int);
- if(params_length > MAX_AC3_PARAM_SIZE) {
+ if (params_length > MAX_AC3_PARAM_SIZE) {
/*MAX is 36*sizeof(int) this should not happen*/
pr_err("params_length(%d) is greater than %d",
params_length, MAX_AC3_PARAM_SIZE);
@@ -1024,7 +1068,7 @@
struct snd_dec_ddp *ddp =
&compr->info.codec_param.codec.options.ddp;
uint32_t params_length = ddp->params_length*sizeof(int);
- if(params_length > MAX_AC3_PARAM_SIZE) {
+ if (params_length > MAX_AC3_PARAM_SIZE) {
/*MAX is 36*sizeof(int) this should not happen*/
pr_err("params_length(%d) is greater than %d",
params_length, MAX_AC3_PARAM_SIZE);
diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
index da36f7f..5f512ae 100644
--- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -43,6 +43,13 @@
#include "msm-pcm-routing-v2.h"
#include "audio_ocmem.h"
+#include "msm-audio-effects-q6-v2.h"
+
+#define DSP_PP_BUFFERING_IN_MSEC 25
+#define PARTIAL_DRAIN_ACK_EARLY_BY_MSEC 150
+#define MP3_OUTPUT_FRAME_SZ 1152
+#define AAC_OUTPUT_FRAME_SZ 1024
+#define DSP_NUM_OUTPUT_FRAME_BUFFERED 2
/* Default values used if user space does not set */
#define COMPR_PLAYBACK_MIN_FRAGMENT_SIZE (8 * 1024)
@@ -54,10 +61,21 @@
const DECLARE_TLV_DB_LINEAR(msm_compr_vol_gain, 0,
COMPRESSED_LR_VOL_MAX_STEPS);
+struct msm_compr_gapless_state {
+ bool set_next_stream_id;
+ int32_t stream_opened[2];
+ uint32_t initial_samples_drop;
+ uint32_t trailing_samples_drop;
+ uint32_t gapless_transition;
+ bool use_dsp_gapless_mode;
+};
+
struct msm_compr_pdata {
atomic_t audio_ocmem_req;
struct snd_compr_stream *cstream[MSM_FRONTEND_DAI_MAX];
uint32_t volume[MSM_FRONTEND_DAI_MAX][2]; /* For both L & R */
+ struct msm_compr_audio_effects *audio_effects[MSM_FRONTEND_DAI_MAX];
+ bool use_dsp_gapless_mode;
};
struct msm_compr_audio {
@@ -75,6 +93,9 @@
uint32_t byte_offset;
uint32_t copied_total;
uint32_t bytes_received;
+ int32_t first_buffer;
+ int32_t last_buffer;
+ int32_t partial_drain_delay;
uint16_t session_id;
@@ -85,18 +106,31 @@
uint32_t cmd_interrupt;
uint32_t drain_ready;
+ struct msm_compr_gapless_state gapless_state;
+
atomic_t start;
atomic_t eos;
atomic_t drain;
atomic_t xrun;
+ atomic_t close;
+ atomic_t wait_on_close;
+ atomic_t error;
wait_queue_head_t eos_wait;
wait_queue_head_t drain_wait;
wait_queue_head_t flush_wait;
+ wait_queue_head_t close_wait;
spinlock_t lock;
};
+struct msm_compr_audio_effects {
+ struct bass_boost_params bass_boost;
+ struct virtualizer_params virtualizer;
+ struct reverb_params reverb;
+ struct eq_params equalizer;
+};
+
static int msm_compr_set_volume(struct snd_compr_stream *cstream,
uint32_t volume_l, uint32_t volume_r)
{
@@ -143,6 +177,11 @@
pr_debug("%s: bytes_received = %d copied_total = %d\n",
__func__, prtd->bytes_received, prtd->copied_total);
+ if (prtd->first_buffer && prtd->gapless_state.use_dsp_gapless_mode)
+ q6asm_send_meta_data(prtd->audio_client,
+ prtd->gapless_state.initial_samples_drop,
+ prtd->gapless_state.trailing_samples_drop);
+
buffer_length = prtd->codec_param.buffer.fragment_size;
bytes_available = prtd->bytes_received - prtd->copied_total;
if (bytes_available < prtd->codec_param.buffer.fragment_size)
@@ -153,7 +192,10 @@
pr_debug("wrap around situation, send partial data %d now", buffer_length);
}
- param.paddr = prtd->buffer_paddr + prtd->byte_offset;
+ if (buffer_length)
+ param.paddr = prtd->buffer_paddr + prtd->byte_offset;
+ else
+ param.paddr = prtd->buffer_paddr;
WARN(param.paddr % 32 != 0, "param.paddr %lx not multiple of 32", param.paddr);
param.len = buffer_length;
@@ -162,11 +204,16 @@
param.flags = NO_TIMESTAMP;
param.uid = buffer_length;
param.metadata_len = 0;
+ param.last_buffer = prtd->last_buffer;
pr_debug("%s: sending %d bytes to DSP byte_offset = %d\n",
__func__, buffer_length, prtd->byte_offset);
- if (q6asm_async_write(prtd->audio_client, ¶m) < 0)
+ if (q6asm_async_write(prtd->audio_client, ¶m) < 0) {
pr_err("%s:q6asm_async_write failed\n", __func__);
+ } else {
+ if (prtd->first_buffer)
+ prtd->first_buffer = 0;
+ }
return 0;
}
@@ -176,9 +223,10 @@
{
struct msm_compr_audio *prtd = priv;
struct snd_compr_stream *cstream = prtd->cstream;
+ struct audio_client *ac = prtd->audio_client;
uint32_t chan_mode = 0;
uint32_t sample_rate = 0;
- int bytes_available;
+ int bytes_available, stream_id;
pr_debug("%s opcode =%08x\n", __func__, opcode);
switch (opcode) {
@@ -217,12 +265,19 @@
pr_debug("WRITE_DONE Insufficient data to send. break out\n");
atomic_set(&prtd->xrun, 1);
+ if (prtd->last_buffer)
+ prtd->last_buffer = 0;
if (atomic_read(&prtd->drain)) {
- pr_debug("wake up on drain");
+ pr_debug("wake up on drain\n");
prtd->drain_ready = 1;
wake_up(&prtd->drain_wait);
atomic_set(&prtd->drain, 0);
}
+ } else if ((bytes_available == cstream->runtime->fragment_size)
+ && atomic_read(&prtd->drain)) {
+ prtd->last_buffer = 1;
+ msm_compr_send_buffer(prtd);
+ prtd->last_buffer = 0;
} else
msm_compr_send_buffer(prtd);
@@ -230,12 +285,24 @@
break;
case ASM_DATA_EVENT_RENDERED_EOS:
pr_debug("ASM_DATA_CMDRSP_EOS\n");
- if (atomic_read(&prtd->eos)) {
+ spin_lock(&prtd->lock);
+ if (atomic_read(&prtd->eos) &&
+ !prtd->gapless_state.set_next_stream_id) {
pr_debug("ASM_DATA_CMDRSP_EOS wake up\n");
prtd->cmd_ack = 1;
wake_up(&prtd->eos_wait);
- atomic_set(&prtd->eos, 0);
}
+ atomic_set(&prtd->eos, 0);
+ stream_id = ac->stream_id^1; /*prev stream */
+ if (prtd->gapless_state.set_next_stream_id &&
+ prtd->gapless_state.stream_opened[stream_id]) {
+ q6asm_stream_cmd_nowait(prtd->audio_client,
+ CMD_CLOSE, stream_id);
+ atomic_set(&prtd->close, 1);
+ prtd->gapless_state.stream_opened[stream_id] = 0;
+ prtd->gapless_state.set_next_stream_id = false;
+ }
+ spin_unlock(&prtd->lock);
break;
case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
case ASM_DATA_EVENT_ENC_SR_CM_CHANGE_NOTIFY: {
@@ -271,6 +338,21 @@
prtd->cmd_ack = 1;
wake_up(&prtd->flush_wait);
break;
+ case ASM_DATA_CMD_REMOVE_INITIAL_SILENCE:
+ pr_debug("ASM_DATA_CMD_REMOVE_INITIAL_SILENCE\n");
+ break;
+ case ASM_DATA_CMD_REMOVE_TRAILING_SILENCE:
+ pr_debug("ASM_DATA_CMD_REMOVE_TRAILING_SILENCE\n");
+ break;
+ case ASM_STREAM_CMD_CLOSE:
+ pr_debug("ASM_DATA_CMD_CLOSE\n");
+ if (atomic_read(&prtd->close) &&
+ atomic_read(&prtd->wait_on_close)) {
+ prtd->cmd_ack = 1;
+ wake_up(&prtd->close_wait);
+ }
+ atomic_set(&prtd->close, 0);
+ break;
default:
break;
}
@@ -279,6 +361,14 @@
case ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3:
pr_debug("ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3\n");
break;
+ case RESET_EVENTS:
+ pr_err("Received reset events CB, move to error state");
+ spin_lock(&prtd->lock);
+ snd_compr_fragment_elapsed(cstream);
+ prtd->copied_total = prtd->bytes_received;
+ atomic_set(&prtd->error, 1);
+ spin_unlock(&prtd->lock);
+ break;
default:
pr_debug("Not Supported Event opcode[0x%x]\n", opcode);
break;
@@ -297,12 +387,15 @@
COMPR_PLAYBACK_MIN_NUM_FRAGMENTS;
prtd->compr_cap.max_fragments =
COMPR_PLAYBACK_MAX_NUM_FRAGMENTS;
- prtd->compr_cap.num_codecs = 2;
+ prtd->compr_cap.num_codecs = 4;
prtd->compr_cap.codecs[0] = SND_AUDIOCODEC_MP3;
prtd->compr_cap.codecs[1] = SND_AUDIOCODEC_AAC;
+ prtd->compr_cap.codecs[2] = SND_AUDIOCODEC_AC3;
+ prtd->compr_cap.codecs[3] = SND_AUDIOCODEC_EAC3;
}
-static int msm_compr_send_media_format_block(struct snd_compr_stream *cstream)
+static int msm_compr_send_media_format_block(struct snd_compr_stream *cstream,
+ int stream_id)
{
struct snd_compr_runtime *runtime = cstream->runtime;
struct msm_compr_audio *prtd = runtime->private_data;
@@ -319,11 +412,15 @@
aac_cfg.format = 0x03;
aac_cfg.ch_cfg = prtd->num_channels;
aac_cfg.sample_rate = prtd->sample_rate;
- ret = q6asm_media_format_block_aac(prtd->audio_client,
- &aac_cfg);
+ ret = q6asm_stream_media_format_block_aac(prtd->audio_client,
+ &aac_cfg, stream_id);
if (ret < 0)
pr_err("%s: CMD Format block failed\n", __func__);
break;
+ case FORMAT_AC3:
+ break;
+ case FORMAT_EAC3:
+ break;
default:
pr_debug("%s, unsupported format, skip", __func__);
break;
@@ -338,6 +435,7 @@
struct snd_soc_pcm_runtime *soc_prtd = cstream->private_data;
uint16_t bits_per_sample = 16;
int dir = IN, ret = 0;
+ struct audio_client *ac = prtd->audio_client;
struct asm_softpause_params softpause = {
.enable = SOFT_PAUSE_ENABLE,
.period = SOFT_PAUSE_PERIOD,
@@ -351,16 +449,19 @@
};
pr_debug("%s\n", __func__);
- ret = q6asm_open_write_v2(prtd->audio_client,
- prtd->codec, bits_per_sample);
+ ret = q6asm_stream_open_write_v2(ac,
+ prtd->codec, bits_per_sample,
+ ac->stream_id,
+ prtd->gapless_state.use_dsp_gapless_mode);
if (ret < 0) {
pr_err("%s: Session out open failed\n", __func__);
return -ENOMEM;
}
+ prtd->gapless_state.stream_opened[ac->stream_id] = 1;
pr_debug("%s be_id %d\n", __func__, soc_prtd->dai_link->be_id);
msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
- prtd->audio_client->perf_mode,
+ ac->perf_mode,
prtd->session_id,
SNDRV_PCM_STREAM_PLAYBACK);
@@ -368,19 +469,17 @@
if (ret < 0)
pr_err("%s : Set Volume failed : %d", __func__, ret);
- ret = q6asm_set_softpause(prtd->audio_client,
- &softpause);
+ ret = q6asm_set_softpause(ac, &softpause);
if (ret < 0)
pr_err("%s: Send SoftPause Param failed ret=%d\n",
__func__, ret);
- ret = q6asm_set_softvolume(prtd->audio_client, &softvol);
+ ret = q6asm_set_softvolume(ac, &softvol);
if (ret < 0)
pr_err("%s: Send SoftVolume Param failed ret=%d\n",
__func__, ret);
- ret = q6asm_set_io_mode(prtd->audio_client,
- (COMPRESSED_IO | ASYNC_IO_MODE));
+ ret = q6asm_set_io_mode(ac, (COMPRESSED_IO | ASYNC_IO_MODE));
if (ret < 0) {
pr_err("%s: Set IO mode failed\n", __func__);
return -EINVAL;
@@ -391,8 +490,7 @@
pr_debug("allocate %d buffers each of size %d\n",
runtime->fragments,
runtime->fragment_size);
- ret = q6asm_audio_client_buf_alloc_contiguous(dir,
- prtd->audio_client,
+ ret = q6asm_audio_client_buf_alloc_contiguous(dir, ac,
runtime->fragment_size,
runtime->fragments);
if (ret < 0) {
@@ -404,15 +502,13 @@
prtd->copied_total = 0;
prtd->app_pointer = 0;
prtd->bytes_received = 0;
- prtd->buffer = prtd->audio_client->port[dir].buf[0].data;
- prtd->buffer_paddr = prtd->audio_client->port[dir].buf[0].phys;
+ prtd->buffer = ac->port[dir].buf[0].data;
+ prtd->buffer_paddr = ac->port[dir].buf[0].phys;
prtd->buffer_size = runtime->fragments * runtime->fragment_size;
- ret = msm_compr_send_media_format_block(cstream);
-
- if (ret < 0) {
+ ret = msm_compr_send_media_format_block(cstream, ac->stream_id);
+ if (ret < 0)
pr_err("%s, failed to send media format block\n", __func__);
- }
return ret;
}
@@ -434,10 +530,18 @@
prtd->cstream = cstream;
pdata->cstream[rtd->dai_link->be_id] = cstream;
+ pdata->audio_effects[rtd->dai_link->be_id] =
+ kzalloc(sizeof(struct msm_compr_audio_effects), GFP_KERNEL);
+ if (!pdata->audio_effects[rtd->dai_link->be_id]) {
+ pr_err("%s: Could not allocate memory for effects\n", __func__);
+ kfree(prtd);
+ return -ENOMEM;
+ }
prtd->audio_client = q6asm_audio_client_alloc(
(app_cb)compr_event_handler, prtd);
if (!prtd->audio_client) {
- pr_err("%s: Could not allocate memory\n", __func__);
+ pr_err("%s: Could not allocate memory for client\n", __func__);
+ kfree(pdata->audio_effects[rtd->dai_link->be_id]);
kfree(prtd);
return -ENOMEM;
}
@@ -452,6 +556,17 @@
prtd->sample_rate = 44100;
prtd->num_channels = 2;
prtd->drain_ready = 0;
+ prtd->last_buffer = 0;
+ prtd->first_buffer = 1;
+ prtd->partial_drain_delay = 0;
+ memset(&prtd->gapless_state, 0, sizeof(struct msm_compr_gapless_state));
+ /*
+ * Update the use_dsp_gapless_mode from gapless struture with the value
+ * part of platform data.
+ */
+ prtd->gapless_state.use_dsp_gapless_mode = pdata->use_dsp_gapless_mode;
+
+ pr_debug("%s: gapless mode %d", __func__, pdata->use_dsp_gapless_mode);
spin_lock_init(&prtd->lock);
@@ -459,10 +574,14 @@
atomic_set(&prtd->start, 0);
atomic_set(&prtd->drain, 0);
atomic_set(&prtd->xrun, 0);
+ atomic_set(&prtd->close, 0);
+ atomic_set(&prtd->wait_on_close, 0);
+ atomic_set(&prtd->error, 0);
init_waitqueue_head(&prtd->eos_wait);
init_waitqueue_head(&prtd->drain_wait);
init_waitqueue_head(&prtd->flush_wait);
+ init_waitqueue_head(&prtd->close_wait);
runtime->private_data = prtd;
populate_codec_list(prtd);
@@ -488,7 +607,9 @@
struct snd_soc_pcm_runtime *soc_prtd = cstream->private_data;
struct msm_compr_pdata *pdata =
snd_soc_platform_get_drvdata(soc_prtd->platform);
- int dir = IN, ret = 0;
+ struct audio_client *ac = prtd->audio_client;
+ int dir = IN, ret = 0, stream_id;
+ unsigned long flags;
pr_debug("%s\n", __func__);
pdata->cstream[soc_prtd->dai_link->be_id] = NULL;
@@ -511,14 +632,36 @@
if (!ret)
pr_err("%s: CMD_EOS failed\n", __func__);
}
+ if (atomic_read(&prtd->close)) {
+ prtd->cmd_ack = 0;
+ atomic_set(&prtd->wait_on_close, 1);
+ ret = wait_event_timeout(prtd->close_wait,
+ prtd->cmd_ack, 5 * HZ);
+ if (!ret)
+ pr_err("%s: CMD_CLOSE failed\n", __func__);
+ }
- q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+ spin_lock_irqsave(&prtd->lock, flags);
+ stream_id = ac->stream_id;
+ if (prtd->gapless_state.stream_opened[stream_id^1]) {
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ q6asm_stream_cmd(ac, CMD_CLOSE, stream_id^1);
+ spin_lock_irqsave(&prtd->lock, flags);
+ }
+ if (prtd->gapless_state.stream_opened[stream_id]) {
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ q6asm_stream_cmd(ac, CMD_CLOSE, stream_id);
+ spin_lock_irqsave(&prtd->lock, flags);
+ }
+ spin_unlock_irqrestore(&prtd->lock, flags);
- q6asm_audio_client_buf_free_contiguous(dir,
- prtd->audio_client);
+ /* client buf alloc was with stream id 0, so free with the same */
+ ac->stream_id = 0;
+ q6asm_audio_client_buf_free_contiguous(dir, ac);
- q6asm_audio_client_free(prtd->audio_client);
+ q6asm_audio_client_free(ac);
+ kfree(pdata->audio_effects[soc_prtd->dai_link->be_id]);
kfree(prtd);
return 0;
@@ -530,7 +673,7 @@
{
struct snd_compr_runtime *runtime = cstream->runtime;
struct msm_compr_audio *prtd = runtime->private_data;
- int ret = 0;
+ int ret = 0, frame_sz = 0, delay_time_ms = 0;
pr_debug("%s\n", __func__);
@@ -570,12 +713,24 @@
case SND_AUDIOCODEC_MP3: {
pr_debug("SND_AUDIOCODEC_MP3\n");
prtd->codec = FORMAT_MP3;
+ frame_sz = MP3_OUTPUT_FRAME_SZ;
break;
}
case SND_AUDIOCODEC_AAC: {
pr_debug("SND_AUDIOCODEC_AAC\n");
prtd->codec = FORMAT_MPEG4_AAC;
+ frame_sz = AAC_OUTPUT_FRAME_SZ;
+ break;
+ }
+
+ case SND_AUDIOCODEC_AC3: {
+ prtd->codec = FORMAT_AC3;
+ break;
+ }
+
+ case SND_AUDIOCODEC_EAC3: {
+ prtd->codec = FORMAT_EAC3;
break;
}
@@ -584,11 +739,40 @@
return -EINVAL;
}
+ delay_time_ms = ((DSP_NUM_OUTPUT_FRAME_BUFFERED * frame_sz * 1000) /
+ prtd->sample_rate) + DSP_PP_BUFFERING_IN_MSEC;
+ delay_time_ms = delay_time_ms > PARTIAL_DRAIN_ACK_EARLY_BY_MSEC ?
+ delay_time_ms - PARTIAL_DRAIN_ACK_EARLY_BY_MSEC : 0;
+ prtd->partial_drain_delay = delay_time_ms;
+
ret = msm_compr_configure_dsp(cstream);
return ret;
}
+static int msm_compr_drain_buffer(struct msm_compr_audio *prtd,
+ unsigned long *flags)
+{
+ int rc = 0;
+
+ atomic_set(&prtd->drain, 1);
+ prtd->drain_ready = 0;
+ spin_unlock_irqrestore(&prtd->lock, *flags);
+ pr_debug("%s: wait for buffer to be drained\n", __func__);
+ rc = wait_event_interruptible(prtd->drain_wait,
+ prtd->drain_ready ||
+ prtd->cmd_interrupt ||
+ atomic_read(&prtd->xrun));
+ pr_debug("%s: out of buffer drain wait\n", __func__);
+ spin_lock_irqsave(&prtd->lock, *flags);
+ if (prtd->cmd_interrupt) {
+ pr_debug("%s: buffer drain interrupted by flush)\n", __func__);
+ rc = -EINTR;
+ prtd->cmd_interrupt = 0;
+ }
+ return rc;
+}
+
static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd)
{
struct snd_compr_runtime *runtime = cstream->runtime;
@@ -597,15 +781,25 @@
struct msm_compr_pdata *pdata =
snd_soc_platform_get_drvdata(rtd->platform);
uint32_t *volume = pdata->volume[rtd->dai_link->be_id];
+ struct audio_client *ac = prtd->audio_client;
int rc = 0;
int bytes_to_write;
unsigned long flags;
+ int stream_id;
if (cstream->direction != SND_COMPRESS_PLAYBACK) {
pr_err("%s: Unsupported stream type\n", __func__);
return -EINVAL;
}
+ spin_lock_irqsave(&prtd->lock, flags);
+ if (atomic_read(&prtd->error)) {
+ pr_err("%s Got RESET EVENTS notification, return immediately", __func__);
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ return 0;
+ }
+ spin_unlock_irqrestore(&prtd->lock, flags);
+
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
pr_debug("%s: SNDRV_PCM_TRIGGER_START\n", __func__);
@@ -618,37 +812,48 @@
__func__, rc);
break;
case SNDRV_PCM_TRIGGER_STOP:
- pr_debug("%s: SNDRV_PCM_TRIGGER_STOP\n", __func__);
spin_lock_irqsave(&prtd->lock, flags);
-
+ pr_debug("%s: SNDRV_PCM_TRIGGER_STOP transition %d\n", __func__,
+ prtd->gapless_state.gapless_transition);
+ stream_id = ac->stream_id;
atomic_set(&prtd->start, 0);
if (atomic_read(&prtd->eos)) {
- pr_debug("%s: interrupt drain and eos wait queues", __func__);
+ pr_debug("%s: interrupt eos wait queues", __func__);
prtd->cmd_interrupt = 1;
- prtd->drain_ready = 1;
- wake_up(&prtd->drain_wait);
wake_up(&prtd->eos_wait);
atomic_set(&prtd->eos, 0);
}
-
- pr_debug("issue CMD_FLUSH \n");
- prtd->cmd_ack = 0;
- spin_unlock_irqrestore(&prtd->lock, flags);
- rc = q6asm_cmd(prtd->audio_client, CMD_FLUSH);
- if (rc < 0) {
- pr_err("%s: flush cmd failed rc=%d\n",
- __func__, rc);
- return rc;
+ if (atomic_read(&prtd->drain)) {
+ pr_debug("%s: interrupt drain wait queues", __func__);
+ prtd->cmd_interrupt = 1;
+ prtd->drain_ready = 1;
+ wake_up(&prtd->drain_wait);
+ atomic_set(&prtd->drain, 0);
}
- rc = wait_event_timeout(prtd->flush_wait,
+ prtd->last_buffer = 0;
+ pr_debug("issue CMD_FLUSH\n");
+ prtd->cmd_ack = 0;
+ if (!prtd->gapless_state.gapless_transition) {
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ rc = q6asm_stream_cmd(
+ prtd->audio_client, CMD_FLUSH, stream_id);
+ if (rc < 0) {
+ pr_err("%s: flush cmd failed rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+ rc = wait_event_timeout(prtd->flush_wait,
prtd->cmd_ack, 1 * HZ);
- if (!rc) {
- rc = -ETIMEDOUT;
- pr_err("Flush cmd timeout\n");
- } else
- rc = 0; /* prtd->cmd_status == OK? 0 : -EPERM */
-
- spin_lock_irqsave(&prtd->lock, flags);
+ if (!rc) {
+ rc = -ETIMEDOUT;
+ pr_err("Flush cmd timeout\n");
+ } else {
+ rc = 0; /* prtd->cmd_status == OK? 0 : -EPERM*/
+ }
+ spin_lock_irqsave(&prtd->lock, flags);
+ } else {
+ prtd->first_buffer = 0;
+ }
/* FIXME. only reset if flush was successful */
prtd->byte_offset = 0;
prtd->copied_total = 0;
@@ -658,17 +863,27 @@
spin_unlock_irqrestore(&prtd->lock, flags);
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- pr_debug("SNDRV_PCM_TRIGGER_PAUSE_PUSH\n");
- q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
- atomic_set(&prtd->start, 0);
+ pr_debug("SNDRV_PCM_TRIGGER_PAUSE_PUSH transition %d\n",
+ prtd->gapless_state.gapless_transition);
+ if (!prtd->gapless_state.gapless_transition) {
+ q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
+ atomic_set(&prtd->start, 0);
+ }
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- pr_debug("SNDRV_PCM_TRIGGER_PAUSE_RELEASE\n");
- atomic_set(&prtd->start, 1);
- q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
+ pr_debug("SNDRV_PCM_TRIGGER_PAUSE_RELEASE transition %d\n",
+ prtd->gapless_state.gapless_transition);
+ if (!prtd->gapless_state.gapless_transition) {
+ atomic_set(&prtd->start, 1);
+ q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
+ }
break;
case SND_COMPR_TRIGGER_PARTIAL_DRAIN:
pr_debug("%s: SND_COMPR_TRIGGER_PARTIAL_DRAIN\n", __func__);
+ if (!prtd->gapless_state.use_dsp_gapless_mode) {
+ pr_debug("%s: set partial drain as drain\n", __func__);
+ cmd = SND_COMPR_TRIGGER_DRAIN;
+ }
case SND_COMPR_TRIGGER_DRAIN:
pr_debug("%s: SNDRV_COMPRESS_DRAIN\n", __func__);
/* Make sure all the data is sent to DSP before sending EOS */
@@ -681,15 +896,15 @@
spin_unlock_irqrestore(&prtd->lock, flags);
break;
}
- atomic_set(&prtd->eos, 1);
-
if (prtd->bytes_received > prtd->copied_total) {
- atomic_set(&prtd->drain, 1);
- prtd->drain_ready = 0;
- spin_unlock_irqrestore(&prtd->lock, flags);
pr_debug("%s: wait till all the data is sent to dsp\n",
__func__);
-
+ rc = msm_compr_drain_buffer(prtd, &flags);
+ if (rc || !atomic_read(&prtd->start)) {
+ rc = -EINTR;
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ break;
+ }
/*
* FIXME: Bug.
* Write(32767)
@@ -698,47 +913,108 @@
* sol1 : if (prtd->copied_total) then wait?
* sol2 : prtd->cmd_interrupt || prtd->drain_ready || atomic_read(xrun)
*/
- rc = wait_event_interruptible(prtd->drain_wait,
- prtd->cmd_interrupt || prtd->drain_ready ||
- atomic_read(&prtd->xrun));
+ bytes_to_write = prtd->bytes_received - prtd->copied_total;
+ WARN(bytes_to_write > runtime->fragment_size,
+ "last write %d cannot be > than fragment_size",
+ bytes_to_write);
- spin_lock_irqsave(&prtd->lock, flags);
- if (!prtd->cmd_interrupt) {
- bytes_to_write = prtd->bytes_received - prtd->copied_total;
- WARN(bytes_to_write > runtime->fragment_size,
- "last write %d cannot be > than fragment_size",
- bytes_to_write);
-
- if (bytes_to_write > 0) {
- pr_debug("%s: send %d partial bytes at the end",
- __func__, bytes_to_write);
- atomic_set(&prtd->xrun, 0);
- msm_compr_send_buffer(prtd);
- }
+ if (bytes_to_write > 0) {
+ pr_debug("%s: send %d partial bytes at the end",
+ __func__, bytes_to_write);
+ atomic_set(&prtd->xrun, 0);
+ prtd->last_buffer = 1;
+ msm_compr_send_buffer(prtd);
}
}
- if (!atomic_read(&prtd->start) || prtd->cmd_interrupt) {
- pr_debug("%s: stream is not started (interrupted by flush?)\n", __func__);
- rc = -EINTR;
- prtd->cmd_interrupt = 0;
+ if ((cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN) &&
+ (prtd->gapless_state.set_next_stream_id)) {
+ /* wait for the last buffer to be returned */
+
+ if (prtd->last_buffer) {
+ pr_debug("%s: last buffer drain\n", __func__);
+ rc = msm_compr_drain_buffer(prtd, &flags);
+ if (rc) {
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ break;
+ }
+ }
+
+ /* send EOS */
+ prtd->cmd_ack = 0;
+ q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
+ pr_info("PARTIAL DRAIN, do not wait for EOS ack\n");
+
+ /* send a zero length buffer */
+ atomic_set(&prtd->xrun, 0);
+ msm_compr_send_buffer(prtd);
+
+ /* wait for the zero length buffer to be returned */
+ pr_debug("%s: zero length buffer drain\n", __func__);
+ rc = msm_compr_drain_buffer(prtd, &flags);
+ if (rc) {
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ break;
+ }
+
+ /* sleep for additional duration partial drain */
+ atomic_set(&prtd->drain, 1);
+ prtd->drain_ready = 0;
+ pr_debug("%s, additional sleep: %d\n", __func__,
+ prtd->partial_drain_delay);
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ rc = wait_event_timeout(prtd->drain_wait,
+ prtd->drain_ready || prtd->cmd_interrupt,
+ msecs_to_jiffies(prtd->partial_drain_delay));
+ pr_debug("%s: out of additional wait for low sample rate\n",
+ __func__);
+ spin_lock_irqsave(&prtd->lock, flags);
+ if (prtd->cmd_interrupt) {
+ pr_debug("%s: additional wait interrupted by flush)\n",
+ __func__);
+ rc = -EINTR;
+ prtd->cmd_interrupt = 0;
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ break;
+ }
+
+ /* move to next stream and reset vars */
+ pr_debug("%s: Moving to next stream in gapless\n", __func__);
+ ac->stream_id ^= 1;
+ prtd->byte_offset = 0;
+ prtd->app_pointer = 0;
+ prtd->first_buffer = 1;
+ prtd->last_buffer = 0;
+ prtd->gapless_state.gapless_transition = 1;
+ /*
+ Don't reset these as these vars map to
+ total_bytes_transferred and total_bytes_available
+ directly, only total_bytes_transferred will be updated
+ in the next avail() ioctl
+ prtd->copied_total = 0;
+ prtd->bytes_received = 0;
+ */
+ atomic_set(&prtd->drain, 0);
+ atomic_set(&prtd->xrun, 1);
+ pr_debug("%s: issue CMD_RUN", __func__);
+ q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
spin_unlock_irqrestore(&prtd->lock, flags);
break;
}
-
+ /*
+ moving to next stream failed, so reset the gapless state
+ set next stream id for the same session so that the same
+ stream can be used for gapless playback
+ */
+ prtd->gapless_state.set_next_stream_id = false;
pr_debug("%s: CMD_EOS\n", __func__);
prtd->cmd_ack = 0;
+ atomic_set(&prtd->eos, 1);
q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
spin_unlock_irqrestore(&prtd->lock, flags);
-/*
- if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN) {
- pr_err("PARTIAL DRAIN, do not wait for EOS ack");
- break;
- }
-*/
/* Wait indefinitely for DRAIN. Flush can also signal this*/
rc = wait_event_interruptible(prtd->eos_wait,
@@ -753,7 +1029,11 @@
rc = -EINTR;
/*FIXME : what if a flush comes while PC is here */
- if (rc == 0 && (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN)) {
+ if (rc == 0) {
+ /*
+ * Failed to open second stream in DSP for gapless
+ * so prepare the current stream in session for gapless playback
+ */
spin_lock_irqsave(&prtd->lock, flags);
pr_debug("%s: issue CMD_PAUSE ", __func__);
q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
@@ -765,27 +1045,60 @@
prtd->cmd_ack, 1 * HZ / 4);
spin_lock_irqsave(&prtd->lock, flags);
+ /*
+ Don't reset these as these vars map to
+ total_bytes_transferred and total_bytes_available
+ directly, only total_bytes_transferred will be updated
+ in the next avail() ioctl
+ prtd->copied_total = 0;
+ prtd->bytes_received = 0;
+ */
prtd->byte_offset = 0;
prtd->app_pointer = 0;
- /* Don't reset these as these vars map
- to total_bytes_transferred and total_bytes_available directly,
- only total_bytes_transferred will be updated in the next avail()
- ioctl
- prtd->copied_total = 0;
- prtd->bytes_received = 0;
- */
+ prtd->first_buffer = 1;
+ prtd->last_buffer = 0;
atomic_set(&prtd->drain, 0);
atomic_set(&prtd->xrun, 1);
- pr_debug("%s: issue CMD_RESUME", __func__);
q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
spin_unlock_irqrestore(&prtd->lock, flags);
}
- pr_debug("%s: out of drain", __func__);
-
prtd->cmd_interrupt = 0;
break;
case SND_COMPR_TRIGGER_NEXT_TRACK:
+ if (!prtd->gapless_state.use_dsp_gapless_mode) {
+ pr_debug("%s: ignore trigger next track\n", __func__);
+ rc = 0;
+ break;
+ }
pr_debug("%s: SND_COMPR_TRIGGER_NEXT_TRACK\n", __func__);
+ spin_lock_irqsave(&prtd->lock, flags);
+ rc = 0;
+ stream_id = ac->stream_id^1; /*next stream in gapless*/
+ if (prtd->gapless_state.stream_opened[stream_id]) {
+ pr_debug("next session is already in opened state\n");
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ break;
+ }
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ rc = q6asm_stream_open_write_v2(prtd->audio_client,
+ prtd->codec, 16,
+ stream_id,
+ prtd->gapless_state.use_dsp_gapless_mode);
+ if (rc < 0) {
+ pr_err("%s: Session out open failed for gapless\n",
+ __func__);
+ break;
+ }
+ rc = msm_compr_send_media_format_block(cstream, stream_id);
+ if (rc < 0) {
+ pr_err("%s, failed to send media format block\n",
+ __func__);
+ break;
+ }
+ spin_lock_irqsave(&prtd->lock, flags);
+ prtd->gapless_state.stream_opened[stream_id] = 1;
+ prtd->gapless_state.set_next_stream_id = true;
+ spin_unlock_irqrestore(&prtd->lock, flags);
break;
}
@@ -799,7 +1112,7 @@
struct msm_compr_audio *prtd = runtime->private_data;
struct snd_compr_tstamp tstamp;
uint64_t timestamp = 0;
- int rc = 0;
+ int rc = 0, first_buffer;
unsigned long flags;
pr_debug("%s\n", __func__);
@@ -809,13 +1122,23 @@
tstamp.sampling_rate = prtd->sample_rate;
tstamp.byte_offset = prtd->byte_offset;
tstamp.copied_total = prtd->copied_total;
+ first_buffer = prtd->first_buffer;
+
+ if (atomic_read(&prtd->error)) {
+ pr_err("%s Got RESET EVENTS notification, return error", __func__);
+ tstamp.pcm_io_frames = 0;
+ memcpy(arg, &tstamp, sizeof(struct snd_compr_tstamp));
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ return -EINVAL;
+ }
+
spin_unlock_irqrestore(&prtd->lock, flags);
/*
Query timestamp from DSP if some data is with it.
This prevents timeouts.
*/
- if (prtd->copied_total) {
+ if (!first_buffer) {
rc = q6asm_get_session_time(prtd->audio_client, ×tamp);
if (rc < 0) {
pr_err("%s: Get Session Time return value =%lld\n",
@@ -897,6 +1220,14 @@
return 0;
}
+ spin_lock_irqsave(&prtd->lock, flags);
+ if (atomic_read(&prtd->error)) {
+ pr_err("%s Got RESET EVENTS notification", __func__);
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ return -EINVAL;
+ }
+ spin_unlock_irqrestore(&prtd->lock, flags);
+
dstn = prtd->buffer + prtd->app_pointer;
if (count < prtd->buffer_size - prtd->app_pointer) {
if (copy_from_user(dstn, buf, count))
@@ -916,7 +1247,8 @@
* since the available bytes fits fragment_size, copy the data right away
*/
spin_lock_irqsave(&prtd->lock, flags);
-
+ if (prtd->gapless_state.gapless_transition)
+ prtd->gapless_state.gapless_transition = 0;
prtd->bytes_received += count;
if (atomic_read(&prtd->start)) {
if (atomic_read(&prtd->xrun)) {
@@ -979,6 +1311,10 @@
(SND_AUDIOSTREAMFORMAT_MP4ADTS |
SND_AUDIOSTREAMFORMAT_RAW);
break;
+ case SND_AUDIOCODEC_AC3:
+ break;
+ case SND_AUDIOCODEC_EAC3:
+ break;
default:
pr_err("%s: Unsupported audio codec %d\n",
__func__, codec->codec);
@@ -991,65 +1327,148 @@
static int msm_compr_set_metadata(struct snd_compr_stream *cstream,
struct snd_compr_metadata *metadata)
{
+ struct msm_compr_audio *prtd;
+ struct audio_client *ac;
pr_debug("%s\n", __func__);
if (!metadata || !cstream)
return -EINVAL;
+ prtd = cstream->runtime->private_data;
+ if (!prtd && !prtd->audio_client)
+ return -EINVAL;
+ ac = prtd->audio_client;
if (metadata->key == SNDRV_COMPRESS_ENCODER_PADDING) {
pr_debug("%s, got encoder padding %u", __func__, metadata->value[0]);
+ prtd->gapless_state.trailing_samples_drop = metadata->value[0];
} else if (metadata->key == SNDRV_COMPRESS_ENCODER_DELAY) {
pr_debug("%s, got encoder delay %u", __func__, metadata->value[0]);
+ prtd->gapless_state.initial_samples_drop = metadata->value[0];
}
return 0;
}
static int msm_compr_volume_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+ struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
+ unsigned long fe_id = kcontrol->private_value;
struct msm_compr_pdata *pdata = (struct msm_compr_pdata *)
snd_soc_platform_get_drvdata(platform);
- struct snd_compr_stream *cstream = pdata->cstream[mc->reg];
- uint32_t *volume = pdata->volume[mc->reg];
+ struct snd_compr_stream *cstream = NULL;
+ uint32_t *volume = NULL;
+
+ if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+ pr_err("%s Received out of bounds fe_id %lu\n",
+ __func__, fe_id);
+ return -EINVAL;
+ }
+
+ cstream = pdata->cstream[fe_id];
+ volume = pdata->volume[fe_id];
volume[0] = ucontrol->value.integer.value[0];
volume[1] = ucontrol->value.integer.value[1];
- pr_debug("%s: mc->reg %d left_vol %d right_vol %d\n",
- __func__, mc->reg, volume[0], volume[1]);
+ pr_debug("%s: fe_id %lu left_vol %d right_vol %d\n",
+ __func__, fe_id, volume[0], volume[1]);
if (cstream)
msm_compr_set_volume(cstream, volume[0], volume[1]);
return 0;
}
static int msm_compr_volume_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+ struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
+ unsigned long fe_id = kcontrol->private_value;
+
struct msm_compr_pdata *pdata =
snd_soc_platform_get_drvdata(platform);
- uint32_t *volume = pdata->volume[mc->reg];
- pr_debug("%s: mc->reg %d\n", __func__, mc->reg);
+ uint32_t *volume = NULL;
+
+ if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+ pr_err("%s Received out of bound fe_id %lu\n", __func__, fe_id);
+ return -EINVAL;
+ }
+
+ volume = pdata->volume[fe_id];
+ pr_debug("%s: fe_id %lu\n", __func__, fe_id);
ucontrol->value.integer.value[0] = volume[0];
ucontrol->value.integer.value[1] = volume[1];
return 0;
}
-/* System Pin has no volume control */
-static const struct snd_kcontrol_new msm_compr_volume_controls[] = {
- SOC_DOUBLE_EXT_TLV("Compress Playback Volume",
- MSM_FRONTEND_DAI_MULTIMEDIA4,
- 0, 8, COMPRESSED_LR_VOL_MAX_STEPS, 0,
- msm_compr_volume_get,
- msm_compr_volume_put,
- msm_compr_vol_gain),
-};
+static int msm_compr_audio_effects_config_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
+ unsigned long fe_id = kcontrol->private_value;
+ struct msm_compr_pdata *pdata = (struct msm_compr_pdata *)
+ snd_soc_platform_get_drvdata(platform);
+ struct msm_compr_audio_effects *audio_effects = NULL;
+ struct snd_compr_stream *cstream = NULL;
+ struct msm_compr_audio *prtd = NULL;
+ long *values = &(ucontrol->value.integer.value[0]);
+ int effects_module;
+
+ pr_debug("%s\n", __func__);
+ if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+ pr_err("%s Received out of bounds fe_id %lu\n",
+ __func__, fe_id);
+ return -EINVAL;
+ }
+ cstream = pdata->cstream[fe_id];
+ audio_effects = pdata->audio_effects[fe_id];
+ if (!cstream || !audio_effects) {
+ pr_err("%s: stream or effects inactive\n", __func__);
+ return -EINVAL;
+ }
+ prtd = cstream->runtime->private_data;
+ if (!prtd) {
+ pr_err("%s: cannot set audio effects\n", __func__);
+ return -EINVAL;
+ }
+ effects_module = *values++;
+ switch (effects_module) {
+ case VIRTUALIZER_MODULE:
+ pr_debug("%s: VIRTUALIZER_MODULE\n", __func__);
+ msm_audio_effects_virtualizer_handler(prtd->audio_client,
+ &(audio_effects->virtualizer),
+ values);
+ break;
+ case REVERB_MODULE:
+ pr_debug("%s: REVERB_MODULE\n", __func__);
+ msm_audio_effects_reverb_handler(prtd->audio_client,
+ &(audio_effects->reverb),
+ values);
+ break;
+ case BASS_BOOST_MODULE:
+ pr_debug("%s: BASS_BOOST_MODULE\n", __func__);
+ msm_audio_effects_bass_boost_handler(prtd->audio_client,
+ &(audio_effects->bass_boost),
+ values);
+ break;
+ case EQ_MODULE:
+ pr_debug("%s: EQ_MODULE\n", __func__);
+ msm_audio_effects_popless_eq_handler(prtd->audio_client,
+ &(audio_effects->equalizer),
+ values);
+ break;
+ default:
+ pr_err("%s Invalid effects config module\n", __func__);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int msm_compr_audio_effects_config_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ /* dummy function */
+ return 0;
+}
static int msm_compr_probe(struct snd_soc_platform *platform)
{
@@ -1069,9 +1488,177 @@
for (i = 0; i < MSM_FRONTEND_DAI_MAX; i++) {
pdata->volume[i][0] = COMPRESSED_LR_VOL_MAX_STEPS;
pdata->volume[i][1] = COMPRESSED_LR_VOL_MAX_STEPS;
+ pdata->audio_effects[i] = NULL;
pdata->cstream[i] = NULL;
}
+ /*
+ * use_dsp_gapless_mode part of platform data(pdata) is updated from HAL
+ * through a mixer control before compress driver is opened. The mixer
+ * control is used to decide if dsp gapless mode needs to be enabled.
+ * Gapless is disabled by default.
+ */
+ pdata->use_dsp_gapless_mode = false;
+ return 0;
+}
+
+static int msm_compr_volume_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = COMPRESSED_LR_VOL_MAX_STEPS;
+ return 0;
+}
+
+static int msm_compr_audio_effects_config_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 128;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 0xFFFFFFFF;
+ return 0;
+}
+
+static int msm_compr_add_volume_control(struct snd_soc_pcm_runtime *rtd)
+{
+ const char *mixer_ctl_name = "Compress Playback";
+ const char *deviceNo = "NN";
+ const char *suffix = "Volume";
+ char *mixer_str = NULL;
+ int ctl_len;
+ struct snd_kcontrol_new fe_volume_control[1] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "?",
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+ SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = msm_compr_volume_info,
+ .tlv.p = msm_compr_vol_gain,
+ .get = msm_compr_volume_get,
+ .put = msm_compr_volume_put,
+ .private_value = 0,
+ }
+ };
+
+ if (!rtd) {
+ pr_err("%s NULL rtd\n", __func__);
+ return 0;
+ }
+ pr_debug("%s: added new compr FE with name %s, id %d, cpu dai %s, device no %d\n",
+ __func__, rtd->dai_link->name, rtd->dai_link->be_id,
+ rtd->dai_link->cpu_dai_name, rtd->pcm->device);
+ ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1 +
+ strlen(suffix) + 1;
+ mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+ if (!mixer_str) {
+ pr_err("failed to allocate mixer ctrl str of len %d", ctl_len);
+ return 0;
+ }
+ snprintf(mixer_str, ctl_len, "%s %d %s", mixer_ctl_name,
+ rtd->pcm->device, suffix);
+ fe_volume_control[0].name = mixer_str;
+ fe_volume_control[0].private_value = rtd->dai_link->be_id;
+ pr_debug("Registering new mixer ctl %s", mixer_str);
+ snd_soc_add_platform_controls(rtd->platform, fe_volume_control,
+ ARRAY_SIZE(fe_volume_control));
+ kfree(mixer_str);
+ return 0;
+}
+
+static int msm_compr_add_audio_effects_control(struct snd_soc_pcm_runtime *rtd)
+{
+ const char *mixer_ctl_name = "Audio Effects Config";
+ const char *deviceNo = "NN";
+ char *mixer_str = NULL;
+ int ctl_len;
+ struct snd_kcontrol_new fe_audio_effects_config_control[1] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "?",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = msm_compr_audio_effects_config_info,
+ .get = msm_compr_audio_effects_config_get,
+ .put = msm_compr_audio_effects_config_put,
+ .private_value = 0,
+ }
+ };
+
+
+ if (!rtd) {
+ pr_err("%s NULL rtd\n", __func__);
+ return 0;
+ }
+
+ pr_debug("%s: added new compr FE with name %s, id %d, cpu dai %s, device no %d\n",
+ __func__, rtd->dai_link->name, rtd->dai_link->be_id,
+ rtd->dai_link->cpu_dai_name, rtd->pcm->device);
+
+ ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
+ mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+
+ if (!mixer_str) {
+ pr_err("failed to allocate mixer ctrl str of len %d", ctl_len);
+ return 0;
+ }
+
+ snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
+
+ fe_audio_effects_config_control[0].name = mixer_str;
+ fe_audio_effects_config_control[0].private_value = rtd->dai_link->be_id;
+ pr_debug("Registering new mixer ctl %s\n", mixer_str);
+ snd_soc_add_platform_controls(rtd->platform,
+ fe_audio_effects_config_control,
+ ARRAY_SIZE(fe_audio_effects_config_control));
+ kfree(mixer_str);
+ return 0;
+}
+
+static int msm_compr_gapless_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
+ struct msm_compr_pdata *pdata = (struct msm_compr_pdata *)
+ snd_soc_platform_get_drvdata(platform);
+ pdata->use_dsp_gapless_mode = ucontrol->value.integer.value[0];
+ pr_debug("%s: value: %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+
+ return 0;
+}
+
+static int msm_compr_gapless_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
+ struct msm_compr_pdata *pdata =
+ snd_soc_platform_get_drvdata(platform);
+ pr_debug("%s:gapless mode %d\n", __func__, pdata->use_dsp_gapless_mode);
+ ucontrol->value.integer.value[0] = pdata->use_dsp_gapless_mode;
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new msm_compr_gapless_controls[] = {
+ SOC_SINGLE_EXT("Compress Gapless Playback",
+ 0, 0, 1, 0,
+ msm_compr_gapless_get,
+ msm_compr_gapless_put),
+};
+
+static int msm_compr_new(struct snd_soc_pcm_runtime *rtd)
+{
+ int rc;
+
+ rc = msm_compr_add_volume_control(rtd);
+ if (rc)
+ pr_err("%s: Could not add Compr Volume Control\n", __func__);
+ rc = msm_compr_add_audio_effects_control(rtd);
+ if (rc)
+ pr_err("%s: Could not add Compr Audio Effects Control\n",
+ __func__);
return 0;
}
@@ -1091,8 +1678,10 @@
static struct snd_soc_platform_driver msm_soc_platform = {
.probe = msm_compr_probe,
.compr_ops = &msm_compr_ops,
- .controls = msm_compr_volume_controls,
- .num_controls = ARRAY_SIZE(msm_compr_volume_controls),
+ .pcm_new = msm_compr_new,
+ .controls = msm_compr_gapless_controls,
+ .num_controls = ARRAY_SIZE(msm_compr_gapless_controls),
+
};
static __devinit int msm_compr_dev_probe(struct platform_device *pdev)
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c
index 0cf044c..9de15d9 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c
@@ -129,13 +129,26 @@
break;
}
+ /*refer to HDMI spec CEA-861-E: Table 28 Audio InfoFrame Data Byte 4*/
switch (dai_data->channels) {
case 2:
dai_data->port_config.hdmi_multi_ch.channel_allocation = 0;
break;
+ case 3:
+ dai_data->port_config.hdmi_multi_ch.channel_allocation = 0x02;
+ break;
+ case 4:
+ dai_data->port_config.hdmi_multi_ch.channel_allocation = 0x06;
+ break;
+ case 5:
+ dai_data->port_config.hdmi_multi_ch.channel_allocation = 0x0A;
+ break;
case 6:
dai_data->port_config.hdmi_multi_ch.channel_allocation = 0x0B;
break;
+ case 7:
+ dai_data->port_config.hdmi_multi_ch.channel_allocation = 0x12;
+ break;
case 8:
dai_data->port_config.hdmi_multi_ch.channel_allocation = 0x13;
break;
diff --git a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
index 307d63e..63ac5d3 100644
--- a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
+++ b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
@@ -179,13 +179,13 @@
DOLBY_ENDDEP_PARAM_VMB_OFFSET},
{-320, -320, 144}
},
- {REMOTE_SUBMIX, 2, DOLBY_ENDP_EXT_SPEAKERS,
+ {REMOTE_SUBMIX, 2, DOLBY_ENDP_HDMI,
{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
DOLBY_ENDDEP_PARAM_VMB_LENGTH},
{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
DOLBY_ENDDEP_PARAM_VMB_OFFSET},
- {-320, -320, 144}
+ {-496, -496, 0}
},
{ANC_HEADSET, 2, DOLBY_ENDP_HEADPHONES,
{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
@@ -211,13 +211,13 @@
DOLBY_ENDDEP_PARAM_VMB_OFFSET},
{-320, -320, 144}
},
- {FM, 2, DOLBY_ENDP_EXT_SPEAKERS,
+ {FM, 2, DOLBY_ENDP_HDMI,
{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
DOLBY_ENDDEP_PARAM_VMB_LENGTH},
{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
DOLBY_ENDDEP_PARAM_VMB_OFFSET},
- {-320, -320, 144}
+ {-496, -496, 0}
},
{FM_TX, 2, DOLBY_ENDP_EXT_SPEAKERS,
{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
diff --git a/sound/soc/msm/qdsp6v2/msm-lsm-client.c b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
index 3f57078..ff82299 100644
--- a/sound/soc/msm/qdsp6v2/msm-lsm-client.c
+++ b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
@@ -170,6 +170,9 @@
*/
rc = -EFAULT;
} else {
+ if (!access_ok(VERIFY_READ, user,
+ sizeof(struct snd_lsm_event_status)))
+ rc = -EFAULT;
if (user->payload_size <
event_status->payload_size) {
pr_debug("%s: provided %dbytes isn't enough, needs %dbytes\n",
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c
new file mode 100644
index 0000000..57fc268
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c
@@ -0,0 +1,441 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 and
+* only version 2 as published by the Free Software Foundation.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT 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/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <sound/apr_audio-v2.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/q6asm-v2.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <sound/tlv.h>
+#include <asm/dma.h>
+
+#include "msm-pcm-routing-v2.h"
+
+#define LOOPBACK_VOL_MAX_STEPS 0x2000
+
+static const DECLARE_TLV_DB_LINEAR(loopback_rx_vol_gain, 0,
+ LOOPBACK_VOL_MAX_STEPS);
+
+struct msm_pcm_loopback {
+ struct snd_pcm_substream *playback_substream;
+ struct snd_pcm_substream *capture_substream;
+
+ int instance;
+
+ struct mutex lock;
+
+ uint32_t samp_rate;
+ uint32_t channel_mode;
+
+ int playback_start;
+ int capture_start;
+ int session_id;
+ struct audio_client *audio_client;
+ int volume;
+};
+
+static void stop_pcm(struct msm_pcm_loopback *pcm);
+
+static const struct snd_pcm_hardware dummy_pcm_hardware = {
+ .formats = 0xffffffff,
+ .channels_min = 1,
+ .channels_max = UINT_MAX,
+
+ /* Random values to keep userspace happy when checking constraints */
+ .info = SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER,
+ .buffer_bytes_max = 128*1024,
+ .period_bytes_min = 1024,
+ .period_bytes_max = 1024*2,
+ .periods_min = 2,
+ .periods_max = 128,
+};
+
+static void msm_pcm_route_event_handler(enum msm_pcm_routing_event event,
+ void *priv_data)
+{
+ struct msm_pcm_loopback *pcm = priv_data;
+
+ BUG_ON(!pcm);
+
+ pr_debug("%s: event %x\n", __func__, event);
+
+ switch (event) {
+ case MSM_PCM_RT_EVT_DEVSWITCH:
+ q6asm_cmd(pcm->audio_client, CMD_PAUSE);
+ q6asm_cmd(pcm->audio_client, CMD_FLUSH);
+ q6asm_run(pcm->audio_client, 0, 0, 0);
+ default:
+ break;
+ }
+}
+
+static void msm_pcm_loopback_event_handler(uint32_t opcode, uint32_t token,
+ uint32_t *payload, void *priv)
+{
+ pr_debug("%s\n", __func__);
+ switch (opcode) {
+ case APR_BASIC_RSP_RESULT: {
+ switch (payload[0]) {
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ default:
+ pr_err("Not Supported Event opcode[0x%x]\n", opcode);
+ break;
+ }
+}
+
+static int pcm_loopback_set_volume(struct msm_pcm_loopback *prtd, int volume)
+{
+ int rc = -EINVAL;
+
+ pr_debug("%s Setting volume 0x%x\n", __func__, volume);
+
+ if (prtd && prtd->audio_client) {
+ rc = q6asm_set_volume(prtd->audio_client, volume);
+ if (rc < 0) {
+ pr_err("%s: Send Volume command failed rc = %d\n",
+ __func__, rc);
+ return rc;
+ }
+ prtd->volume = volume;
+ }
+ return rc;
+}
+
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+ struct msm_pcm_loopback *pcm;
+ int ret = 0;
+ uint16_t bits_per_sample = 16;
+ struct msm_pcm_routing_evt event;
+
+ pcm = dev_get_drvdata(rtd->platform->dev);
+ mutex_lock(&pcm->lock);
+
+ snd_soc_set_runtime_hwparams(substream, &dummy_pcm_hardware);
+ pcm->volume = 0x2000;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ pcm->playback_substream = substream;
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ pcm->capture_substream = substream;
+
+ pcm->instance++;
+ dev_dbg(rtd->platform->dev, "%s: pcm out open: %d,%d\n", __func__,
+ pcm->instance, substream->stream);
+ if (pcm->instance == 2) {
+ struct snd_soc_pcm_runtime *soc_pcm_rx =
+ pcm->playback_substream->private_data;
+ struct snd_soc_pcm_runtime *soc_pcm_tx =
+ pcm->capture_substream->private_data;
+ if (pcm->audio_client != NULL)
+ stop_pcm(pcm);
+
+ pcm->audio_client = q6asm_audio_client_alloc(
+ (app_cb)msm_pcm_loopback_event_handler, pcm);
+ if (!pcm->audio_client) {
+ dev_err(rtd->platform->dev,
+ "%s: Could not allocate memory\n", __func__);
+ mutex_unlock(&pcm->lock);
+ return -ENOMEM;
+ }
+ pcm->session_id = pcm->audio_client->session;
+ pcm->audio_client->perf_mode = false;
+ ret = q6asm_open_loopback_v2(pcm->audio_client,
+ bits_per_sample);
+ if (ret < 0) {
+ dev_err(rtd->platform->dev,
+ "%s: pcm out open failed\n", __func__);
+ q6asm_audio_client_free(pcm->audio_client);
+ mutex_unlock(&pcm->lock);
+ return -ENOMEM;
+ }
+ event.event_func = msm_pcm_route_event_handler;
+ event.priv_data = (void *) pcm;
+ msm_pcm_routing_reg_phy_stream(soc_pcm_tx->dai_link->be_id,
+ pcm->audio_client->perf_mode,
+ pcm->session_id, pcm->capture_substream->stream);
+ msm_pcm_routing_reg_phy_stream_v2(soc_pcm_rx->dai_link->be_id,
+ pcm->audio_client->perf_mode,
+ pcm->session_id, pcm->playback_substream->stream,
+ event);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ pcm->playback_substream = substream;
+ ret = pcm_loopback_set_volume(pcm, pcm->volume);
+ if (ret < 0)
+ dev_err(rtd->platform->dev,
+ "Error %d setting volume", ret);
+ }
+ }
+ dev_info(rtd->platform->dev, "%s: Instance = %d, Stream ID = %s\n",
+ __func__ , pcm->instance, substream->pcm->id);
+ runtime->private_data = pcm;
+
+ mutex_unlock(&pcm->lock);
+
+ return 0;
+}
+
+static void stop_pcm(struct msm_pcm_loopback *pcm)
+{
+ struct snd_soc_pcm_runtime *soc_pcm_rx =
+ pcm->playback_substream->private_data;
+ struct snd_soc_pcm_runtime *soc_pcm_tx =
+ pcm->capture_substream->private_data;
+
+ if (pcm->audio_client == NULL)
+ return;
+ q6asm_cmd(pcm->audio_client, CMD_CLOSE);
+
+ msm_pcm_routing_dereg_phy_stream(soc_pcm_rx->dai_link->be_id,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ msm_pcm_routing_dereg_phy_stream(soc_pcm_tx->dai_link->be_id,
+ SNDRV_PCM_STREAM_CAPTURE);
+ q6asm_audio_client_free(pcm->audio_client);
+ pcm->audio_client = NULL;
+}
+
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_pcm_loopback *pcm = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+ int ret = 0;
+
+ mutex_lock(&pcm->lock);
+
+ dev_dbg(rtd->platform->dev, "%s: end pcm call:%d\n",
+ __func__, substream->stream);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ pcm->playback_start = 0;
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ pcm->capture_start = 0;
+
+ pcm->instance--;
+ if (!pcm->playback_start || !pcm->capture_start) {
+ dev_dbg(rtd->platform->dev, "%s: end pcm call\n", __func__);
+ stop_pcm(pcm);
+ }
+
+ mutex_unlock(&pcm->lock);
+ return ret;
+}
+
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_pcm_loopback *pcm = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+
+ mutex_lock(&pcm->lock);
+
+ dev_dbg(rtd->platform->dev, "%s: ASM loopback stream:%d\n",
+ __func__, substream->stream);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (!pcm->playback_start)
+ pcm->playback_start = 1;
+ } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ if (!pcm->capture_start)
+ pcm->capture_start = 1;
+ }
+ mutex_unlock(&pcm->lock);
+
+ return ret;
+}
+
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_pcm_loopback *pcm = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ dev_dbg(rtd->platform->dev,
+ "%s: playback_start:%d,capture_start:%d\n", __func__,
+ pcm->playback_start, pcm->capture_start);
+ if (pcm->playback_start && pcm->capture_start)
+ q6asm_run_nowait(pcm->audio_client, 0, 0, 0);
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_STOP:
+ dev_dbg(rtd->platform->dev,
+ "%s:Pause/Stop - playback_start:%d,capture_start:%d\n",
+ __func__, pcm->playback_start, pcm->capture_start);
+ if (pcm->playback_start && pcm->capture_start)
+ q6asm_cmd_nowait(pcm->audio_client, CMD_PAUSE);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+
+ dev_dbg(rtd->platform->dev, "%s: ASM loopback\n", __func__);
+
+ return snd_pcm_lib_alloc_vmalloc_buffer(substream,
+ params_buffer_bytes(params));
+}
+
+static int msm_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ return snd_pcm_lib_free_vmalloc_buffer(substream);
+}
+
+static struct snd_pcm_ops msm_pcm_ops = {
+ .open = msm_pcm_open,
+ .hw_params = msm_pcm_hw_params,
+ .hw_free = msm_pcm_hw_free,
+ .close = msm_pcm_close,
+ .prepare = msm_pcm_prepare,
+ .trigger = msm_pcm_trigger,
+};
+
+static int msm_pcm_volume_ctl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int rc = 0;
+ struct snd_pcm_volume *vol = kcontrol->private_data;
+ struct snd_pcm_substream *substream = vol->pcm->streams[0].substream;
+ struct msm_pcm_loopback *prtd = substream->runtime->private_data;
+ int volume = ucontrol->value.integer.value[0];
+
+ rc = pcm_loopback_set_volume(prtd, volume);
+ return rc;
+}
+
+static int msm_pcm_add_controls(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_pcm *pcm = rtd->pcm->streams[0].pcm;
+ struct snd_pcm_volume *volume_info;
+ struct snd_kcontrol *kctl;
+ int ret = 0;
+
+ dev_dbg(rtd->dev, "%s, Volume cntrl add\n", __func__);
+ ret = snd_pcm_add_volume_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ NULL, 1,
+ rtd->dai_link->be_id,
+ &volume_info);
+ if (ret < 0)
+ return ret;
+ kctl = volume_info->kctl;
+ kctl->put = msm_pcm_volume_ctl_put;
+ kctl->tlv.p = loopback_rx_vol_gain;
+ return 0;
+}
+
+static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_card *card = rtd->card->snd_card;
+ int ret = 0;
+
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+ ret = msm_pcm_add_controls(rtd);
+ if (ret)
+ dev_err(rtd->dev, "%s, kctl add failed\n", __func__);
+ return ret;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+ .ops = &msm_pcm_ops,
+ .pcm_new = msm_asoc_pcm_new,
+};
+
+static __devinit int msm_pcm_probe(struct platform_device *pdev)
+{
+ struct msm_pcm_loopback *pcm;
+
+ dev_set_name(&pdev->dev, "%s", "msm-pcm-loopback");
+ dev_dbg(&pdev->dev, "%s: dev name %s\n",
+ __func__, dev_name(&pdev->dev));
+
+ pcm = kzalloc(sizeof(struct msm_pcm_loopback), GFP_KERNEL);
+ if (!pcm) {
+ dev_err(&pdev->dev, "%s Failed to allocate memory for pcm\n",
+ __func__);
+ return -ENOMEM;
+ } else {
+ mutex_init(&pcm->lock);
+ dev_set_drvdata(&pdev->dev, pcm);
+ }
+ return snd_soc_register_platform(&pdev->dev,
+ &msm_soc_platform);
+}
+
+static int msm_pcm_remove(struct platform_device *pdev)
+{
+ struct msm_pcm_loopback *pcm;
+
+ pcm = dev_get_drvdata(&pdev->dev);
+ mutex_destroy(&pcm->lock);
+ kfree(pcm);
+
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static const struct of_device_id msm_pcm_loopback_dt_match[] = {
+ {.compatible = "qti,msm-pcm-loopback"},
+ {}
+};
+
+static struct platform_driver msm_pcm_driver = {
+ .driver = {
+ .name = "msm-pcm-loopback",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_pcm_loopback_dt_match,
+ },
+ .probe = msm_pcm_probe,
+ .remove = __devexit_p(msm_pcm_remove),
+};
+
+static int __init msm_soc_platform_init(void)
+{
+ return platform_driver_register(&msm_pcm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+ platform_driver_unregister(&msm_pcm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("PCM loopback platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index dc41948..32eaebf 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -25,6 +25,7 @@
#include <sound/pcm.h>
#include <sound/initval.h>
#include <sound/control.h>
+#include <sound/q6audio-v2.h>
#include <asm/dma.h>
#include <linux/dma-mapping.h>
#include <linux/msm_audio_ion.h>
@@ -109,6 +110,25 @@
.mask = 0,
};
+static void msm_pcm_route_event_handler(enum msm_pcm_routing_event event,
+ void *priv_data)
+{
+ struct msm_audio *prtd = priv_data;
+
+ BUG_ON(!prtd);
+
+ pr_debug("%s: event %x\n", __func__, event);
+
+ switch (event) {
+ case MSM_PCM_RT_EVT_BUF_RECFG:
+ q6asm_cmd(prtd->audio_client, CMD_PAUSE);
+ q6asm_cmd(prtd->audio_client, CMD_FLUSH);
+ q6asm_run(prtd->audio_client, 0, 0, 0);
+ default:
+ break;
+ }
+}
+
static void event_handler(uint32_t opcode,
uint32_t token, uint32_t *payload, void *priv)
{
@@ -151,18 +171,32 @@
pr_debug("token = 0x%08x\n", token);
in_frame_info[token][0] = payload[4];
in_frame_info[token][1] = payload[5];
- prtd->pcm_irq_pos += in_frame_info[token][0];
- pr_debug("pcm_irq_pos=%d\n", prtd->pcm_irq_pos);
- if (atomic_read(&prtd->start))
- snd_pcm_period_elapsed(substream);
- if (atomic_read(&prtd->in_count) <= prtd->periods)
- atomic_inc(&prtd->in_count);
- wake_up(&the_locks.read_wait);
- if (prtd->mmap_flag
- && q6asm_is_cpu_buf_avail_nolock(OUT,
+ /* assume data size = 0 during flushing */
+ if (in_frame_info[token][0]) {
+ prtd->pcm_irq_pos += in_frame_info[token][0];
+ pr_debug("pcm_irq_pos=%d\n", prtd->pcm_irq_pos);
+ if (atomic_read(&prtd->start))
+ snd_pcm_period_elapsed(substream);
+ if (atomic_read(&prtd->in_count) <= prtd->periods)
+ atomic_inc(&prtd->in_count);
+ wake_up(&the_locks.read_wait);
+ if (prtd->mmap_flag &&
+ q6asm_is_cpu_buf_avail_nolock(OUT,
prtd->audio_client,
&size, &idx))
- q6asm_read_nolock(prtd->audio_client);
+ q6asm_read_nolock(prtd->audio_client);
+ } else {
+ pr_debug("%s: reclaim flushed buf in_count %x\n",
+ __func__, atomic_read(&prtd->in_count));
+ prtd->pcm_irq_pos += prtd->pcm_count;
+ atomic_inc(&prtd->in_count);
+ if (atomic_read(&prtd->in_count) == prtd->periods) {
+ pr_info("%s: reclaimed all bufs\n", __func__);
+ if (atomic_read(&prtd->start))
+ snd_pcm_period_elapsed(substream);
+ wake_up(&the_locks.read_wait);
+ }
+ }
break;
}
case APR_BASIC_RSP_RESULT: {
@@ -681,6 +715,7 @@
int dir, ret;
struct msm_plat_data *pdata;
uint16_t bits_per_sample = 16;
+ struct msm_pcm_routing_evt event;
pdata = (struct msm_plat_data *)
dev_get_drvdata(soc_prtd->platform->dev);
@@ -737,9 +772,12 @@
pr_debug("%s: session ID %d\n",
__func__, prtd->audio_client->session);
prtd->session_id = prtd->audio_client->session;
- msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+ event.event_func = msm_pcm_route_event_handler;
+ event.priv_data = (void *) prtd;
+ msm_pcm_routing_reg_phy_stream_v2(soc_prtd->dai_link->be_id,
prtd->audio_client->perf_mode,
- prtd->session_id, substream->stream);
+ prtd->session_id, substream->stream,
+ event);
}
ret = q6asm_audio_client_buf_alloc_contiguous(dir,
@@ -880,11 +918,12 @@
int rc;
int id;
struct msm_plat_data *pdata;
+ const char *latency_level;
rc = of_property_read_u32(pdev->dev.of_node,
- "qcom,msm-pcm-dsp-id", &id);
+ "qti,msm-pcm-dsp-id", &id);
if (rc) {
- dev_err(&pdev->dev, "%s: qcom,msm-pcm-dsp-id missing in DT node\n",
+ dev_err(&pdev->dev, "%s: qti,msm-pcm-dsp-id missing in DT node\n",
__func__);
return rc;
}
@@ -896,10 +935,17 @@
}
if (of_property_read_bool(pdev->dev.of_node,
- "qcom,msm-pcm-low-latency"))
- pdata->perf_mode = 1;
- else
- pdata->perf_mode = 0;
+ "qti,msm-pcm-low-latency")) {
+
+ pdata->perf_mode = LOW_LATENCY_PCM_MODE;
+ rc = of_property_read_string(pdev->dev.of_node,
+ "qti,latency-level", &latency_level);
+ if (!rc) {
+ if (!strcmp(latency_level, "ultra"))
+ pdata->perf_mode = ULTRA_LOW_LATENCY_PCM_MODE;
+ }
+ } else
+ pdata->perf_mode = LEGACY_PCM_MODE;
dev_set_drvdata(&pdev->dev, pdata);
@@ -921,7 +967,7 @@
return 0;
}
static const struct of_device_id msm_pcm_dt_match[] = {
- {.compatible = "qcom,msm-pcm-dsp"},
+ {.compatible = "qti,msm-pcm-dsp"},
{}
};
MODULE_DEVICE_TABLE(of, msm_pcm_dt_match);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 1b4fae9..91c0744 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -50,10 +50,21 @@
unsigned int format;
};
+struct msm_pcm_routing_fdai_data {
+ u16 be_srate; /* track prior backend sample rate for flushing purpose */
+ int strm_id; /* ASM stream ID */
+ struct msm_pcm_routing_evt event_info;
+};
+
#define INVALID_SESSION -1
#define SESSION_TYPE_RX 0
#define SESSION_TYPE_TX 1
+#define EC_PORT_ID_PRIMARY_MI2S_TX 1
+#define EC_PORT_ID_SECONDARY_MI2S_TX 2
+#define EC_PORT_ID_TERTIARY_MI2S_TX 3
+#define EC_PORT_ID_QUATERNARY_MI2S_TX 4
+
static struct mutex routing_lock;
static int fm_switch_enable;
@@ -63,6 +74,7 @@
static int slim0_rx_aanc_fb_port;
static int msm_route_ec_ref_rx = 3; /* NONE */
static uint32_t voc_session_id = ALL_SESSION_VSID;
+static int msm_route_ext_ec_ref = AFE_PORT_INVALID;
enum {
MADNONE,
@@ -244,31 +256,41 @@
/* Track ASM playback & capture sessions of DAI */
-static int fe_dai_map[MSM_FRONTEND_DAI_MM_SIZE][2] = {
+static struct msm_pcm_routing_fdai_data
+ fe_dai_map[MSM_FRONTEND_DAI_MM_SIZE][2] = {
/* MULTIMEDIA1 */
- {INVALID_SESSION, INVALID_SESSION},
+ {{0, INVALID_SESSION, {NULL, NULL} },
+ {0, INVALID_SESSION, {NULL, NULL} } },
/* MULTIMEDIA2 */
- {INVALID_SESSION, INVALID_SESSION},
+ {{0, INVALID_SESSION, {NULL, NULL} },
+ {0, INVALID_SESSION, {NULL, NULL} } },
/* MULTIMEDIA3 */
- {INVALID_SESSION, INVALID_SESSION},
+ {{0, INVALID_SESSION, {NULL, NULL} },
+ {0, INVALID_SESSION, {NULL, NULL} } },
/* MULTIMEDIA4 */
- {INVALID_SESSION, INVALID_SESSION},
+ {{0, INVALID_SESSION, {NULL, NULL} },
+ {0, INVALID_SESSION, {NULL, NULL} } },
/* MULTIMEDIA5 */
- {INVALID_SESSION, INVALID_SESSION},
+ {{0, INVALID_SESSION, {NULL, NULL} },
+ {0, INVALID_SESSION, {NULL, NULL} } },
/* MULTIMEDIA6 */
- {INVALID_SESSION, INVALID_SESSION},
- /* MULTIMEDIA7 */
- {INVALID_SESSION, INVALID_SESSION},
+ {{0, INVALID_SESSION, {NULL, NULL} },
+ {0, INVALID_SESSION, {NULL, NULL} } },
+ /* MULTIMEDIA7*/
+ {{0, INVALID_SESSION, {NULL, NULL} },
+ {0, INVALID_SESSION, {NULL, NULL} } },
/* MULTIMEDIA8 */
- {INVALID_SESSION, INVALID_SESSION},
+ {{0, INVALID_SESSION, {NULL, NULL} },
+ {0, INVALID_SESSION, {NULL, NULL} } },
/* MULTIMEDIA9 */
- {INVALID_SESSION, INVALID_SESSION},
+ {{0, INVALID_SESSION, {NULL, NULL} },
+ {0, INVALID_SESSION, {NULL, NULL} } },
};
/* Track performance mode of all front-end multimedia sessions.
* Performance mode is only valid when session is valid.
*/
-static bool fe_dai_perf_mode[MSM_FRONTEND_DAI_MM_SIZE][2];
+static int fe_dai_perf_mode[MSM_FRONTEND_DAI_MM_SIZE][2];
static uint8_t is_be_dai_extproc(int be_dai)
{
@@ -281,7 +303,7 @@
}
static void msm_pcm_routing_build_matrix(int fedai_id, int dspst_id,
- int path_type, bool perf_mode)
+ int path_type, int perf_mode)
{
int i, port_type;
struct route_payload payload;
@@ -328,7 +350,7 @@
mutex_lock(&routing_lock);
- fe_dai_map[fedai_id][session_type] = dspst_id;
+ fe_dai_map[fedai_id][session_type].strm_id = dspst_id;
for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
if (!is_be_dai_extproc(i) &&
(afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
@@ -343,7 +365,7 @@
mutex_unlock(&routing_lock);
}
-void msm_pcm_routing_reg_phy_stream(int fedai_id, bool perf_mode,
+void msm_pcm_routing_reg_phy_stream(int fedai_id, int perf_mode,
int dspst_id, int stream_type)
{
int i, session_type, path_type, port_type, port_id, topology;
@@ -370,7 +392,7 @@
mutex_lock(&routing_lock);
payload.num_copps = 0; /* only RX needs to use payload */
- fe_dai_map[fedai_id][session_type] = dspst_id;
+ fe_dai_map[fedai_id][session_type].strm_id = dspst_id;
fe_dai_perf_mode[fedai_id][session_type] = perf_mode;
/* re-enable EQ if active */
@@ -415,7 +437,7 @@
port_id = srs_port_id = msm_bedais[i].port_id;
srs_send_params(srs_port_id, 1, 0);
if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
- (!perf_mode))
+ (perf_mode == LEGACY_PCM_MODE))
if (dolby_dap_init(port_id,
msm_bedais[i].channel) < 0)
pr_err("%s: Err init dolby dap\n",
@@ -429,6 +451,19 @@
mutex_unlock(&routing_lock);
}
+void msm_pcm_routing_reg_phy_stream_v2(int fedai_id, bool perf_mode,
+ int dspst_id, int stream_type,
+ struct msm_pcm_routing_evt event_info)
+{
+ msm_pcm_routing_reg_phy_stream(fedai_id, perf_mode, dspst_id,
+ stream_type);
+
+ if (stream_type == SNDRV_PCM_STREAM_PLAYBACK)
+ fe_dai_map[fedai_id][SESSION_TYPE_RX].event_info = event_info;
+ else
+ fe_dai_map[fedai_id][SESSION_TYPE_TX].event_info = event_info;
+}
+
void msm_pcm_routing_dereg_phy_stream(int fedai_id, int stream_type)
{
int i, port_type, session_type, path_type, topology;
@@ -459,13 +494,14 @@
adm_close(msm_bedais[i].port_id,
fe_dai_perf_mode[fedai_id][session_type]);
if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
- (fe_dai_perf_mode[fedai_id][session_type] == false))
+ (fe_dai_perf_mode[fedai_id][session_type] ==
+ LEGACY_PCM_MODE))
dolby_dap_deinit(msm_bedais[i].port_id);
}
}
- fe_dai_map[fedai_id][session_type] = INVALID_SESSION;
-
+ fe_dai_map[fedai_id][session_type].strm_id = INVALID_SESSION;
+ fe_dai_map[fedai_id][session_type].be_srate = 0;
mutex_unlock(&routing_lock);
}
@@ -491,6 +527,7 @@
int session_type, path_type, port_id, topology;
u32 channels;
uint16_t bits_per_sample = 16;
+ struct msm_pcm_routing_fdai_data *fdai;
pr_debug("%s: reg %x val %x set %x\n", __func__, reg, val, set);
@@ -517,10 +554,23 @@
(msm_bedais[reg].port_id == VOICE2_PLAYBACK_TX)))
voc_start_playback(set, msm_bedais[reg].port_id);
set_bit(val, &msm_bedais[reg].fe_sessions);
- if (msm_bedais[reg].active && fe_dai_map[val][session_type] !=
+ fdai = &fe_dai_map[val][session_type];
+ if (msm_bedais[reg].active && fdai->strm_id !=
INVALID_SESSION) {
channels = msm_bedais[reg].channel;
+ if (session_type == SESSION_TYPE_TX &&
+ fdai->be_srate &&
+ (fdai->be_srate != msm_bedais[reg].sample_rate)) {
+ pr_debug("%s: flush strm %d diff BE rates\n",
+ __func__, fdai->strm_id);
+
+ if (fdai->event_info.event_func)
+ fdai->event_info.event_func(
+ MSM_PCM_RT_EVT_BUF_RECFG,
+ fdai->event_info.priv_data);
+ fdai->be_srate = 0; /* might not need it */
+ }
if (msm_bedais[reg].format == SNDRV_PCM_FORMAT_S24_LE)
bits_per_sample = 24;
@@ -543,13 +593,20 @@
msm_bedais[reg].sample_rate, channels,
topology, false, bits_per_sample);
+ if (session_type == SESSION_TYPE_RX &&
+ fdai->event_info.event_func)
+ fdai->event_info.event_func(
+ MSM_PCM_RT_EVT_DEVSWITCH,
+ fdai->event_info.priv_data);
+
msm_pcm_routing_build_matrix(val,
- fe_dai_map[val][session_type], path_type,
+ fdai->strm_id, path_type,
fe_dai_perf_mode[val][session_type]);
port_id = srs_port_id = msm_bedais[reg].port_id;
srs_send_params(srs_port_id, 1, 0);
if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
- (fe_dai_perf_mode[val][session_type] == false))
+ (fe_dai_perf_mode[val][session_type] ==
+ LEGACY_PCM_MODE))
if (dolby_dap_init(port_id, channels) < 0)
pr_err("%s: Err init dolby dap\n",
__func__);
@@ -560,15 +617,17 @@
(msm_bedais[reg].port_id == VOICE2_PLAYBACK_TX)))
voc_start_playback(set, msm_bedais[reg].port_id);
clear_bit(val, &msm_bedais[reg].fe_sessions);
- if (msm_bedais[reg].active && fe_dai_map[val][session_type] !=
+ fdai = &fe_dai_map[val][session_type];
+ if (msm_bedais[reg].active && fdai->strm_id !=
INVALID_SESSION) {
adm_close(msm_bedais[reg].port_id,
fe_dai_perf_mode[val][session_type]);
if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
- (fe_dai_perf_mode[val][session_type] == false))
+ (fe_dai_perf_mode[val][session_type] ==
+ LEGACY_PCM_MODE))
dolby_dap_deinit(msm_bedais[reg].port_id);
msm_pcm_routing_build_matrix(val,
- fe_dai_map[val][session_type], path_type,
+ fdai->strm_id, path_type,
fe_dai_perf_mode[val][session_type]);
}
}
@@ -1197,12 +1256,12 @@
static void msm_send_eq_values(int eq_idx)
{
int result;
- struct audio_client *ac =
- q6asm_get_audio_client(fe_dai_map[eq_idx][SESSION_TYPE_RX]);
+ struct audio_client *ac = q6asm_get_audio_client(
+ fe_dai_map[eq_idx][SESSION_TYPE_RX].strm_id);
if (ac == NULL) {
pr_err("%s: Could not get audio client for session: %d\n",
- __func__, fe_dai_map[eq_idx][SESSION_TYPE_RX]);
+ __func__, fe_dai_map[eq_idx][SESSION_TYPE_RX].strm_id);
goto done;
}
@@ -1369,6 +1428,76 @@
msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put),
};
+static int msm_routing_ext_ec_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: ext_ec_ref_rx = %x\n", __func__, msm_route_ext_ec_ref);
+
+ mutex_lock(&routing_lock);
+ ucontrol->value.integer.value[0] = msm_route_ext_ec_ref;
+ mutex_unlock(&routing_lock);
+ return 0;
+}
+
+static int msm_routing_ext_ec_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ int mux = ucontrol->value.enumerated.item[0];
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ int ret = 0;
+ bool state = false;
+
+ pr_debug("%s: msm_route_ec_ref_rx = %d value = %ld\n",
+ __func__, msm_route_ext_ec_ref,
+ ucontrol->value.integer.value[0]);
+
+ mutex_lock(&routing_lock);
+ switch (ucontrol->value.integer.value[0]) {
+ case EC_PORT_ID_PRIMARY_MI2S_TX:
+ msm_route_ext_ec_ref = AFE_PORT_ID_PRIMARY_MI2S_TX;
+ state = true;
+ break;
+ case EC_PORT_ID_SECONDARY_MI2S_TX:
+ msm_route_ext_ec_ref = AFE_PORT_ID_SECONDARY_MI2S_TX;
+ state = true;
+ break;
+ case EC_PORT_ID_TERTIARY_MI2S_TX:
+ msm_route_ext_ec_ref = AFE_PORT_ID_TERTIARY_MI2S_TX;
+ state = true;
+ break;
+ case EC_PORT_ID_QUATERNARY_MI2S_TX:
+ msm_route_ext_ec_ref = AFE_PORT_ID_QUATERNARY_MI2S_TX;
+ state = true;
+ break;
+ default:
+ msm_route_ext_ec_ref = AFE_PORT_INVALID;
+ break;
+ }
+ if (voc_set_ext_ec_ref(msm_route_ext_ec_ref, state)) {
+ mutex_unlock(&routing_lock);
+ snd_soc_dapm_mux_update_power(widget, kcontrol, 1, mux, e);
+ } else {
+ ret = -EINVAL;
+ mutex_unlock(&routing_lock);
+ }
+ return ret;
+}
+
+static const char * const ext_ec_ref_rx[] = {"NONE", "PRI_MI2S_TX",
+ "SEC_MI2S_TX", "TERT_MI2S_TX",
+ "QUAT_MI2S_TX"};
+
+static const struct soc_enum msm_route_ext_ec_ref_rx_enum[] = {
+ SOC_ENUM_SINGLE_EXT(5, ext_ec_ref_rx),
+};
+
+static const struct snd_kcontrol_new voc_ext_ec_mux =
+ SOC_DAPM_ENUM_EXT("VOC_EXT_EC MUX Mux", msm_route_ext_ec_ref_rx_enum[0],
+ msm_routing_ext_ec_get, msm_routing_ext_ec_put);
+
+
static const struct snd_kcontrol_new pri_i2s_rx_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_PRI_I2S_RX ,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
@@ -1933,6 +2062,40 @@
msm_routing_put_audio_mixer),
};
+static const struct snd_kcontrol_new mmul8_mixer_controls[] = {
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+
+static const struct snd_kcontrol_new mmul6_mixer_controls[] = {
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = {
SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_PRI_I2S_RX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
@@ -2938,6 +3101,8 @@
SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL4", "MultiMedia4 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL5", "MultiMedia5 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MM_UL8", "MultiMedia8 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MM_UL6", "MultiMedia6 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL9", "MultiMedia9 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("CS-VOICE_DL1", "CS-VOICE Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0),
@@ -2966,6 +3131,10 @@
0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("INTFM_UL_HL", "INT_FM_HOSTLESS Capture",
0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("INTHFP_DL_HL", "INT_HFP_BT_HOSTLESS Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("INTHFP_UL_HL", "INT_HFP_BT_HOSTLESS Capture",
+ 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("HDMI_DL_HL", "HDMI_HOSTLESS Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("SEC_I2S_DL_HL", "SEC_I2S_RX_HOSTLESS Playback",
0, 0, 0, 0),
@@ -3114,6 +3283,10 @@
mmul4_mixer_controls, ARRAY_SIZE(mmul4_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia5 Mixer", SND_SOC_NOPM, 0, 0,
mmul5_mixer_controls, ARRAY_SIZE(mmul5_mixer_controls)),
+ SND_SOC_DAPM_MIXER("MultiMedia8 Mixer", SND_SOC_NOPM, 0, 0,
+ mmul8_mixer_controls, ARRAY_SIZE(mmul8_mixer_controls)),
+ SND_SOC_DAPM_MIXER("MultiMedia6 Mixer", SND_SOC_NOPM, 0, 0,
+ mmul6_mixer_controls, ARRAY_SIZE(mmul6_mixer_controls)),
SND_SOC_DAPM_MIXER("AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
auxpcm_rx_mixer_controls, ARRAY_SIZE(auxpcm_rx_mixer_controls)),
SND_SOC_DAPM_MIXER("SEC_AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
@@ -3235,6 +3408,8 @@
SND_SOC_DAPM_MUX("SLIM0_RX_VI_FB_LCH_MUX", SND_SOC_NOPM, 0, 0,
&slim0_rx_vi_fb_lch_mux),
+ SND_SOC_DAPM_MUX("VOC_EXT_EC MUX", SND_SOC_NOPM, 0, 0,
+ &voc_ext_ec_mux),
};
@@ -3300,11 +3475,15 @@
{"MultiMedia1 Mixer", "VOC_REC_UL", "INCALL_RECORD_TX"},
{"MultiMedia4 Mixer", "VOC_REC_UL", "INCALL_RECORD_TX"},
+ {"MultiMedia8 Mixer", "VOC_REC_UL", "INCALL_RECORD_TX"},
{"MultiMedia1 Mixer", "VOC_REC_DL", "INCALL_RECORD_RX"},
{"MultiMedia4 Mixer", "VOC_REC_DL", "INCALL_RECORD_RX"},
+ {"MultiMedia8 Mixer", "VOC_REC_DL", "INCALL_RECORD_RX"},
{"MultiMedia1 Mixer", "SLIM_4_TX", "SLIMBUS_4_TX"},
{"MultiMedia4 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+ {"MultiMedia8 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia4 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"MultiMedia8 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
{"MultiMedia5 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
@@ -3322,6 +3501,9 @@
{"QUAT_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"QUAT_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"QUAT_MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"QUAT_MI2S_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"QUAT_MI2S_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"QUAT_MI2S_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
{"QUAT_MI2S_RX", NULL, "QUAT_MI2S_RX Audio Mixer"},
{"TERT_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -3361,6 +3543,7 @@
{"MultiMedia2 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia1 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
{"MultiMedia1 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"MultiMedia6 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
@@ -3371,6 +3554,7 @@
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia6", "MM_UL6"},
{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX Audio Mixer"},
{"INTERNAL_FM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -3398,18 +3582,24 @@
{"MultiMedia1 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"MultiMedia4 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"MultiMedia5 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"MultiMedia8 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"MultiMedia1 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"MultiMedia4 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"MultiMedia5 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"MultiMedia8 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"MultiMedia6 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"MultiMedia1 Mixer", "AFE_PCM_TX", "PCM_TX"},
{"MultiMedia4 Mixer", "AFE_PCM_TX", "PCM_TX"},
{"MultiMedia5 Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"MultiMedia8 Mixer", "AFE_PCM_TX", "PCM_TX"},
{"MM_UL1", NULL, "MultiMedia1 Mixer"},
{"MultiMedia2 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"MM_UL2", NULL, "MultiMedia2 Mixer"},
{"MM_UL4", NULL, "MultiMedia4 Mixer"},
{"MM_UL5", NULL, "MultiMedia5 Mixer"},
+ {"MM_UL8", NULL, "MultiMedia8 Mixer"},
+ {"MM_UL6", NULL, "MultiMedia6 Mixer"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
@@ -3524,6 +3714,12 @@
{"MI2S_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
{"MI2S_RX", NULL, "MI2S_RX_Voice Mixer"},
+ {"VOC_EXT_EC MUX", "PRI_MI2S_TX" , "PRI_MI2S_TX"},
+ {"VOC_EXT_EC MUX", "SEC_MI2S_TX" , "SEC_MI2S_TX"},
+ {"VOC_EXT_EC MUX", "TERT_MI2S_TX" , "TERT_MI2S_TX"},
+ {"VOC_EXT_EC MUX", "QUAT_MI2S_TX" , "QUAT_MI2S_TX"},
+ {"CS-VOICE_UL1", NULL, "VOC_EXT_EC MUX"},
+
{"Voice_Tx Mixer", "PRI_TX_Voice", "PRI_I2S_TX"},
{"Voice_Tx Mixer", "PRI_MI2S_TX_Voice", "PRI_MI2S_TX"},
{"Voice_Tx Mixer", "MI2S_TX_Voice", "MI2S_TX"},
@@ -3593,6 +3789,8 @@
{"INT_FM_RX", NULL, "INTFM_DL_HL"},
{"INTFM_UL_HL", NULL, "INT_FM_TX"},
+ {"INTHFP_UL_HL", NULL, "INT_BT_SCO_TX"},
+ {"INT_BT_SCO_RX", NULL, "MM_DL6"},
{"AUX_PCM_RX", NULL, "AUXPCM_DL_HL"},
{"AUXPCM_UL_HL", NULL, "AUX_PCM_TX"},
{"MI2S_RX", NULL, "MI2S_DL_HL"},
@@ -3758,12 +3956,15 @@
mutex_lock(&routing_lock);
topology = get_topology(path_type);
for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MM_SIZE) {
- if (fe_dai_map[i][session_type] != INVALID_SESSION) {
+ if (fe_dai_map[i][session_type].strm_id != INVALID_SESSION) {
+ fe_dai_map[i][session_type].be_srate =
+ bedai->sample_rate;
adm_close(bedai->port_id,
fe_dai_perf_mode[i][session_type]);
srs_port_id = -1;
if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
- (fe_dai_perf_mode[i][session_type] == false))
+ (fe_dai_perf_mode[i][session_type] ==
+ LEGACY_PCM_MODE))
dolby_dap_deinit(bedai->port_id);
}
}
@@ -3785,6 +3986,7 @@
u32 channels;
bool playback, capture;
uint16_t bits_per_sample = 16;
+ struct msm_pcm_routing_fdai_data *fdai;
if (be_id >= MSM_BACKEND_DAI_MAX) {
pr_err("%s: unexpected be_id %d\n", __func__, be_id);
@@ -3816,8 +4018,21 @@
capture = substream->stream == SNDRV_PCM_STREAM_CAPTURE;
for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MM_SIZE) {
- if (fe_dai_map[i][session_type] != INVALID_SESSION) {
+ fdai = &fe_dai_map[i][session_type];
+ if (fdai->strm_id != INVALID_SESSION) {
+ if (session_type == SESSION_TYPE_TX &&
+ fdai->be_srate &&
+ (fdai->be_srate != bedai->sample_rate)) {
+ pr_debug("%s: flush strm %d diff BE rates\n",
+ __func__,
+ fdai->strm_id);
+ if (fdai->event_info.event_func)
+ fdai->event_info.event_func(
+ MSM_PCM_RT_EVT_BUF_RECFG,
+ fdai->event_info.priv_data);
+ fdai->be_srate = 0; /* might not need it */
+ }
channels = bedai->channel;
if (bedai->format == SNDRV_PCM_FORMAT_S24_LE)
bits_per_sample = 24;
@@ -3844,12 +4059,13 @@
}
msm_pcm_routing_build_matrix(i,
- fe_dai_map[i][session_type], path_type,
+ fdai->strm_id, path_type,
fe_dai_perf_mode[i][session_type]);
port_id = srs_port_id = bedai->port_id;
srs_send_params(srs_port_id, 1, 0);
if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
- (fe_dai_perf_mode[i][session_type] == false))
+ (fe_dai_perf_mode[i][session_type] ==
+ LEGACY_PCM_MODE))
if (dolby_dap_init(port_id, channels) < 0)
pr_err("%s: Err init dolby dap\n",
__func__);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
index 10be150..54f5e4a 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
@@ -133,15 +133,30 @@
MSM_BACKEND_DAI_MAX,
};
+enum msm_pcm_routing_event {
+ MSM_PCM_RT_EVT_BUF_RECFG,
+ MSM_PCM_RT_EVT_DEVSWITCH,
+ MSM_PCM_RT_EVT_MAX,
+};
+
/* dai_id: front-end ID,
* dspst_id: DSP audio stream ID
* stream_type: playback or capture
*/
-void msm_pcm_routing_reg_phy_stream(int fedai_id, bool perf_mode, int dspst_id,
+void msm_pcm_routing_reg_phy_stream(int fedai_id, int perf_mode, int dspst_id,
int stream_type);
void msm_pcm_routing_reg_psthr_stream(int fedai_id, int dspst_id,
int stream_type);
+struct msm_pcm_routing_evt {
+ void (*event_func)(enum msm_pcm_routing_event, void *);
+ void *priv_data;
+};
+
+void msm_pcm_routing_reg_phy_stream_v2(int fedai_id, bool perf_mode,
+ int dspst_id, int stream_type,
+ struct msm_pcm_routing_evt event_info);
+
void msm_pcm_routing_dereg_phy_stream(int fedai_id, int stream_type);
int msm_routing_check_backend_enabled(int fedai_id);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
index af25454..97c7b5d 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
@@ -48,6 +48,9 @@
#define MODE_PCM 0xC
#define MODE_4GV_NW 0xE
+#define VOIP_MODE_MAX MODE_4GV_NW
+#define VOIP_RATE_MAX 23850
+
enum format {
FORMAT_S16_LE = 2,
FORMAT_SPECIAL = 31,
@@ -153,10 +156,14 @@
uint32_t rate,
uint32_t *rate_type);
static int voip_config_vocoder(struct snd_pcm_substream *substream);
-static int msm_voip_mode_rate_config_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol);
-static int msm_voip_mode_rate_config_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol);
+static int msm_voip_mode_config_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+static int msm_voip_mode_config_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+static int msm_voip_rate_config_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+static int msm_voip_rate_config_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
static int msm_voip_evrc_min_max_rate_config_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
static int msm_voip_evrc_min_max_rate_config_get(struct snd_kcontrol *kcontrol,
@@ -267,11 +274,12 @@
SOC_SINGLE_MULTI_EXT("Voip Rx Gain", SND_SOC_NOPM, 0,
MAX_RAMP_DURATION,
0, 2, NULL, msm_voip_gain_put),
- SOC_SINGLE_MULTI_EXT("Voip Mode Rate Config", SND_SOC_NOPM, 0, 23850,
- 0, 2, msm_voip_mode_rate_config_get,
- msm_voip_mode_rate_config_put),
+ SOC_SINGLE_EXT("Voip Mode Config", SND_SOC_NOPM, 0, VOIP_MODE_MAX, 0,
+ msm_voip_mode_config_get, msm_voip_mode_config_put),
+ SOC_SINGLE_EXT("Voip Rate Config", SND_SOC_NOPM, 0, VOIP_RATE_MAX, 0,
+ msm_voip_rate_config_get, msm_voip_rate_config_put),
SOC_SINGLE_MULTI_EXT("Voip Evrc Min Max Rate Config", SND_SOC_NOPM,
- 0, 4, 0, 2, msm_voip_evrc_min_max_rate_config_get,
+ 0, VOC_1_RATE, 0, 2, msm_voip_evrc_min_max_rate_config_get,
msm_voip_evrc_min_max_rate_config_put),
SOC_SINGLE_EXT("Voip Dtx Mode", SND_SOC_NOPM, 0, 1, 0,
msm_voip_dtx_mode_get, msm_voip_dtx_mode_put),
@@ -439,6 +447,8 @@
list_add_tail(&buf_node->list, &prtd->free_in_queue);
}
}
+ pr_debug("%s: frame.pktlen=%d\n", __func__, buf_node->frame.pktlen);
+
prtd->pcm_playback_irq_pos += prtd->pcm_count;
spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
snd_pcm_period_elapsed(prtd->playback_substream);
@@ -800,26 +810,20 @@
uint32_t evrc_min_rate_type = 0;
uint32_t evrc_max_rate_type = 0;
- if ((runtime->format != FORMAT_SPECIAL) &&
- ((prtd->mode == MODE_AMR) || (prtd->mode == MODE_AMR_WB) ||
+ pr_debug("%s(): mode=%d, playback sample rate=%d, capture sample rate=%d\n",
+ __func__, prtd->mode, prtd->play_samp_rate, prtd->cap_samp_rate);
+
+ if ((runtime->format != FORMAT_S16_LE) && ((prtd->mode == MODE_PCM) ||
+ (prtd->mode == MODE_AMR) || (prtd->mode == MODE_AMR_WB) ||
(prtd->mode == MODE_IS127) || (prtd->mode == MODE_4GV_NB) ||
(prtd->mode == MODE_4GV_WB) || (prtd->mode == MODE_4GV_NW))) {
- pr_err("%s(): mode:%d and format:%u are not mached\n",
+ pr_err("%s(): mode:%d and format:%u are not matched\n",
__func__, prtd->mode, (uint32_t)runtime->format);
ret = -EINVAL;
goto done;
}
- if ((runtime->format != FORMAT_S16_LE) &&
- (prtd->mode == MODE_PCM)) {
- pr_err("%s(): mode:%d and format:%u are not mached\n",
- __func__, prtd->mode, (uint32_t)runtime->format);
-
- ret = -EINVAL;
- goto done;
- }
-
ret = voip_get_media_type(prtd->mode,
prtd->play_samp_rate,
&media_type);
@@ -1057,29 +1061,52 @@
return 0;
}
-static int msm_voip_mode_rate_config_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int msm_voip_mode_config_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
mutex_lock(&voip_info.lock);
ucontrol->value.integer.value[0] = voip_info.mode;
- ucontrol->value.integer.value[1] = voip_info.rate;
mutex_unlock(&voip_info.lock);
return 0;
}
-static int msm_voip_mode_rate_config_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int msm_voip_mode_config_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
mutex_lock(&voip_info.lock);
voip_info.mode = ucontrol->value.integer.value[0];
- voip_info.rate = ucontrol->value.integer.value[1];
- pr_debug("%s: mode=%d,rate=%d\n", __func__, voip_info.mode,
- voip_info.rate);
+ pr_debug("%s: mode=%d\n", __func__, voip_info.mode);
+
+ mutex_unlock(&voip_info.lock);
+
+ return 0;
+}
+
+static int msm_voip_rate_config_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ mutex_lock(&voip_info.lock);
+
+ ucontrol->value.integer.value[0] = voip_info.rate;
+
+ mutex_unlock(&voip_info.lock);
+
+ return 0;
+}
+
+static int msm_voip_rate_config_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ mutex_lock(&voip_info.lock);
+
+ voip_info.rate = ucontrol->value.integer.value[0];
+
+ pr_debug("%s: rate=%d\n", __func__, voip_info.rate);
mutex_unlock(&voip_info.lock);
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index 3ee6f6e..54b1263 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -702,7 +702,8 @@
return;
}
-static int send_adm_cal_block(int port_id, struct acdb_cal_block *aud_cal)
+static int send_adm_cal_block(int port_id, struct acdb_cal_block *aud_cal,
+ int perf_mode)
{
s32 result = 0;
struct adm_cmd_set_pp_params_v5 adm_params;
@@ -731,7 +732,14 @@
adm_params.hdr.src_port = port_id;
adm_params.hdr.dest_svc = APR_SVC_ADM;
adm_params.hdr.dest_domain = APR_DOMAIN_ADSP;
- adm_params.hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+
+ if (perf_mode == LEGACY_PCM_MODE)
+ adm_params.hdr.dest_port =
+ atomic_read(&this_adm.copp_id[index]);
+ else
+ adm_params.hdr.dest_port =
+ atomic_read(&this_adm.copp_low_latency_id[index]);
+
adm_params.hdr.token = port_id;
adm_params.hdr.opcode = ADM_CMD_SET_PP_PARAMS_V5;
adm_params.payload_addr_lsw = aud_cal->cal_paddr;
@@ -767,7 +775,7 @@
return result;
}
-static void send_adm_cal(int port_id, int path)
+static void send_adm_cal(int port_id, int path, int perf_mode)
{
int result = 0;
s32 acdb_path;
@@ -808,7 +816,7 @@
}
}
- if (!send_adm_cal_block(port_id, &aud_cal))
+ if (!send_adm_cal_block(port_id, &aud_cal, perf_mode))
pr_debug("%s: Audproc cal sent for port id: %#x, path %d\n",
__func__, port_id, acdb_path);
else
@@ -842,7 +850,7 @@
}
}
- if (!send_adm_cal_block(port_id, &aud_cal))
+ if (!send_adm_cal_block(port_id, &aud_cal, perf_mode))
pr_debug("%s: Audvol cal sent for port id: %#x, path %d\n",
__func__, port_id, acdb_path);
else
@@ -1048,7 +1056,7 @@
}
int adm_open(int port_id, int path, int rate, int channel_mode, int topology,
- bool perf_mode, uint16_t bits_per_sample)
+ int perf_mode, uint16_t bits_per_sample)
{
struct adm_cmd_device_open_v5 open;
int ret = 0;
@@ -1079,7 +1087,7 @@
rtac_set_adm_handle(this_adm.apr);
}
- if (!perf_mode) {
+ if (perf_mode == LEGACY_PCM_MODE) {
atomic_set(&this_adm.copp_perf_mode[index], 0);
send_adm_custom_topology(port_id);
} else {
@@ -1087,8 +1095,9 @@
}
/* Create a COPP if port id are not enabled */
- if ((!perf_mode && (atomic_read(&this_adm.copp_cnt[index]) == 0)) ||
- (perf_mode &&
+ if ((perf_mode == LEGACY_PCM_MODE &&
+ (atomic_read(&this_adm.copp_cnt[index]) == 0)) ||
+ (perf_mode != LEGACY_PCM_MODE &&
(atomic_read(&this_adm.copp_low_latency_cnt[index]) == 0))) {
pr_debug("%s:opening ADM: perf_mode: %d\n", __func__,
perf_mode);
@@ -1103,12 +1112,12 @@
open.hdr.dest_port = tmp_port;
open.hdr.token = port_id;
open.hdr.opcode = ADM_CMD_DEVICE_OPEN_V5;
- open.flags = 0x00;
- if (perf_mode) {
- open.flags |= ADM_ULTRA_LOW_LATENCY_DEVICE_SESSION;
- } else {
- open.flags |= ADM_LEGACY_DEVICE_SESSION;
- }
+ if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE)
+ open.flags = ADM_ULTRA_LOW_LATENCY_DEVICE_SESSION;
+ else if (perf_mode == LOW_LATENCY_PCM_MODE)
+ open.flags = ADM_LOW_LATENCY_DEVICE_SESSION;
+ else
+ open.flags = ADM_LEGACY_DEVICE_SESSION;
open.mode_of_operation = path;
open.endpoint_id_1 = tmp_port;
@@ -1125,7 +1134,7 @@
(open.topology_id == VPM_TX_DM_FLUENCE_COPP_TOPOLOGY))
rate = 16000;
- if (perf_mode) {
+ if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE) {
open.topology_id = NULL_COPP_TOPOLOGY;
rate = ULL_SUPPORTED_SAMPLE_RATE;
if(channel_mode > ULL_MAX_SUPPORTED_CHANNEL)
@@ -1133,7 +1142,8 @@
}
open.dev_num_channel = channel_mode & 0x00FF;
open.bit_width = bits_per_sample;
- WARN_ON(perf_mode && (rate != 48000));
+ WARN_ON(perf_mode == ULTRA_LOW_LATENCY_PCM_MODE &&
+ (rate != 48000));
open.sample_rate = rate;
memset(open.dev_channel_mapping, 0, 8);
@@ -1160,10 +1170,10 @@
} else if (channel_mode == 6) {
open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
- open.dev_channel_mapping[2] = PCM_CHANNEL_FC;
- open.dev_channel_mapping[3] = PCM_CHANNEL_LFE;
- open.dev_channel_mapping[4] = PCM_CHANNEL_LB;
- open.dev_channel_mapping[5] = PCM_CHANNEL_RB;
+ open.dev_channel_mapping[2] = PCM_CHANNEL_LFE;
+ open.dev_channel_mapping[3] = PCM_CHANNEL_FC;
+ open.dev_channel_mapping[4] = PCM_CHANNEL_LS;
+ open.dev_channel_mapping[5] = PCM_CHANNEL_RS;
} else if (channel_mode == 8) {
open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
@@ -1171,8 +1181,8 @@
open.dev_channel_mapping[3] = PCM_CHANNEL_FC;
open.dev_channel_mapping[4] = PCM_CHANNEL_LB;
open.dev_channel_mapping[5] = PCM_CHANNEL_RB;
- open.dev_channel_mapping[6] = PCM_CHANNEL_RLC;
- open.dev_channel_mapping[7] = PCM_CHANNEL_RRC;
+ open.dev_channel_mapping[6] = PCM_CHANNEL_FLC;
+ open.dev_channel_mapping[7] = PCM_CHANNEL_FRC;
} else {
pr_err("%s invalid num_chan %d\n", __func__,
channel_mode);
@@ -1208,7 +1218,8 @@
goto fail_cmd;
}
}
- if (perf_mode) {
+ if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE ||
+ perf_mode == LOW_LATENCY_PCM_MODE) {
atomic_inc(&this_adm.copp_low_latency_cnt[index]);
pr_debug("%s: index: %d coppid: %d", __func__, index,
atomic_read(&this_adm.copp_low_latency_id[index]));
@@ -1225,7 +1236,7 @@
}
int adm_multi_ch_copp_open(int port_id, int path, int rate, int channel_mode,
- int topology, bool perf_mode, uint16_t bits_per_sample)
+ int topology, int perf_mode, uint16_t bits_per_sample)
{
int ret = 0;
@@ -1236,7 +1247,7 @@
}
int adm_matrix_map(int session_id, int path, int num_copps,
- unsigned int *port_id, int copp_id, bool perf_mode)
+ unsigned int *port_id, int copp_id, int perf_mode)
{
struct adm_cmd_matrix_map_routings_v5 *route;
struct adm_session_map_node_v5 *node;
@@ -1275,7 +1286,8 @@
route->hdr.src_port = copp_id;
route->hdr.dest_svc = APR_SVC_ADM;
route->hdr.dest_domain = APR_DOMAIN_ADSP;
- if (perf_mode) {
+ if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE ||
+ perf_mode == LOW_LATENCY_PCM_MODE) {
route->hdr.dest_port =
atomic_read(&this_adm.copp_low_latency_id[index]);
} else {
@@ -1313,7 +1325,8 @@
if (tmp >= 0 && tmp < AFE_MAX_PORTS) {
- if (perf_mode)
+ if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE ||
+ perf_mode == LOW_LATENCY_PCM_MODE)
copps_list[i] =
atomic_read(&this_adm.copp_low_latency_id[tmp]);
else
@@ -1323,8 +1336,7 @@
else
continue;
pr_debug("%s: port_id[%#x]: %d, index: %d act coppid[0x%x]\n",
- __func__, i, port_id[i], tmp,
- atomic_read(&this_adm.copp_id[tmp]));
+ __func__, i, port_id[i], tmp, copps_list[i]);
}
atomic_set(&this_adm.copp_stat[index], 0);
@@ -1344,25 +1356,31 @@
ret = -EINVAL;
goto fail_cmd;
}
- if (!perf_mode) {
+
+ if (perf_mode != ULTRA_LOW_LATENCY_PCM_MODE) {
for (i = 0; i < num_copps; i++)
- send_adm_cal(port_id[i], path);
+ send_adm_cal(port_id[i], path, perf_mode);
for (i = 0; i < num_copps; i++) {
- int tmp;
+ int tmp, copp_id;
tmp = afe_get_port_index(port_id[i]);
if (tmp >= 0 && tmp < AFE_MAX_PORTS) {
+ if (perf_mode == LEGACY_PCM_MODE)
+ copp_id = atomic_read(
+ &this_adm.copp_id[tmp]);
+ else
+ copp_id = atomic_read(
+ &this_adm.copp_low_latency_id[tmp]);
rtac_add_adm_device(port_id[i],
- atomic_read(&this_adm.copp_id[tmp]),
- path, session_id);
- pr_debug("%s, copp_id: %d\n", __func__,
- atomic_read(&this_adm.copp_id[tmp]));
- } else {
+ copp_id, path, session_id);
+ pr_debug("%s, copp_id: %d\n",
+ __func__, copp_id);
+ } else
pr_debug("%s: Invalid port index %d",
- __func__, tmp);
- }
+ __func__, tmp);
}
}
+
fail_cmd:
kfree(matrix_map);
return ret;
@@ -1514,8 +1532,26 @@
return ret;
}
+#ifdef CONFIG_RTAC
int adm_get_copp_id(int port_index)
{
+ int copp_id;
+ pr_debug("%s\n", __func__);
+
+ if (port_index < 0) {
+ pr_err("%s: invalid port_id = %d\n", __func__, port_index);
+ return -EINVAL;
+ }
+
+ copp_id = atomic_read(&this_adm.copp_id[port_index]);
+ if (copp_id == RESET_COPP_ID)
+ copp_id = atomic_read(
+ &this_adm.copp_low_latency_id[port_index]);
+ return copp_id;
+}
+
+int adm_get_lowlatency_copp_id(int port_index)
+{
pr_debug("%s\n", __func__);
if (port_index < 0) {
@@ -1523,8 +1559,19 @@
return -EINVAL;
}
- return atomic_read(&this_adm.copp_id[port_index]);
+ return atomic_read(&this_adm.copp_low_latency_id[port_index]);
}
+#else
+int adm_get_copp_id(int port_index)
+{
+ return -EINVAL;
+}
+
+int adm_get_lowlatency_copp_id(int port_index)
+{
+ return -EINVAL;
+}
+#endif /* #ifdef CONFIG_RTAC */
void adm_ec_ref_rx_id(int port_id)
{
@@ -1532,12 +1579,13 @@
pr_debug("%s ec_ref_rx:%d", __func__, this_adm.ec_ref_rx);
}
-int adm_close(int port_id, bool perf_mode)
+int adm_close(int port_id, int perf_mode)
{
struct apr_hdr close;
int ret = 0;
int index = 0;
+ int copp_id = RESET_COPP_ID;
port_id = q6audio_convert_virtual_to_portid(port_id);
@@ -1548,7 +1596,8 @@
pr_debug("%s port_id=%#x index %d perf_mode: %d\n", __func__, port_id,
index, perf_mode);
- if (perf_mode) {
+ if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE ||
+ perf_mode == LOW_LATENCY_PCM_MODE) {
if (!(atomic_read(&this_adm.copp_low_latency_cnt[index]))) {
pr_err("%s: copp count for port[%#x]is 0\n", __func__,
port_id);
@@ -1563,8 +1612,9 @@
}
atomic_dec(&this_adm.copp_cnt[index]);
}
- if ((!perf_mode && !(atomic_read(&this_adm.copp_cnt[index]))) ||
- (perf_mode &&
+ if ((perf_mode == LEGACY_PCM_MODE &&
+ !(atomic_read(&this_adm.copp_cnt[index]))) ||
+ ((perf_mode != LEGACY_PCM_MODE) &&
!(atomic_read(&this_adm.copp_low_latency_cnt[index])))) {
pr_debug("%s:Closing ADM: perf_mode: %d\n", __func__,
@@ -1577,7 +1627,8 @@
close.src_port = port_id;
close.dest_svc = APR_SVC_ADM;
close.dest_domain = APR_DOMAIN_ADSP;
- if (perf_mode)
+ if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE ||
+ perf_mode == LOW_LATENCY_PCM_MODE)
close.dest_port =
atomic_read(&this_adm.copp_low_latency_id[index]);
else
@@ -1587,18 +1638,23 @@
atomic_set(&this_adm.copp_stat[index], 0);
- if (perf_mode) {
+ if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE ||
+ perf_mode == LOW_LATENCY_PCM_MODE) {
+ copp_id = atomic_read(
+ &this_adm.copp_low_latency_id[index]);
pr_debug("%s:coppid %d portid=%#x index=%d coppcnt=%d\n",
- __func__,
- atomic_read(&this_adm.copp_low_latency_id[index]),
- port_id, index,
- atomic_read(&this_adm.copp_low_latency_cnt[index]));
+ __func__,
+ copp_id,
+ port_id, index,
+ atomic_read(
+ &this_adm.copp_low_latency_cnt[index]));
atomic_set(&this_adm.copp_low_latency_id[index],
RESET_COPP_ID);
} else {
+ copp_id = atomic_read(&this_adm.copp_id[index]);
pr_debug("%s:coppid %d portid=%#x index=%d coppcnt=%d\n",
__func__,
- atomic_read(&this_adm.copp_id[index]),
+ copp_id,
port_id, index,
atomic_read(&this_adm.copp_cnt[index]));
atomic_set(&this_adm.copp_id[index],
@@ -1623,9 +1679,9 @@
}
}
- if (!perf_mode) {
+ if (perf_mode != ULTRA_LOW_LATENCY_PCM_MODE) {
pr_debug("%s: remove adm device from rtac\n", __func__);
- rtac_remove_adm_device(port_id);
+ rtac_remove_adm_device(port_id, copp_id);
}
fail_cmd:
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 09ecd75..acb8e70 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -2879,7 +2879,14 @@
uint16_t port_index;
if (this_afe.apr == NULL) {
- pr_err("AFE is already closed\n");
+ pr_err("%s: AFE is already closed\n", __func__);
+ if ((port_id == RT_PROXY_DAI_001_RX) ||
+ (port_id == RT_PROXY_DAI_002_TX))
+ pcm_afe_instance[port_id & 0x1] = 0;
+ if ((port_id == RT_PROXY_DAI_002_RX) ||
+ (port_id == RT_PROXY_DAI_001_TX))
+ proxy_afe_instance[port_id & 0x1] = 0;
+ afe_close_done[port_id & 0x1] = true;
ret = -EINVAL;
goto fail_cmd;
}
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 3785a3e..24f5f3b 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -39,6 +39,7 @@
#include <sound/apr_audio-v2.h>
#include <sound/q6asm-v2.h>
+#include <sound/q6audio-v2.h>
#include "audio_acdb.h"
@@ -62,10 +63,13 @@
uint32_t buf_addr_lsw;
uint32_t mmap_hdl;
};
-static int32_t q6asm_mmapcallback(struct apr_client_data *data, void *priv);
+static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv);
static int32_t q6asm_callback(struct apr_client_data *data, void *priv);
static void q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
uint32_t pkt_size, uint32_t cmd_flg);
+static void q6asm_add_hdr_custom_topology(struct audio_client *ac,
+ struct apr_hdr *hdr,
+ uint32_t pkt_size, uint32_t cmd_flg);
static void q6asm_add_hdr_async(struct audio_client *ac, struct apr_hdr *hdr,
uint32_t pkt_size, uint32_t cmd_flg);
static int q6asm_memory_map_regions(struct audio_client *ac, int dir,
@@ -351,7 +355,7 @@
session[ac->session] = 0;
mutex_unlock(&session_lock);
ac->session = 0;
- ac->perf_mode = 0;
+ ac->perf_mode = LEGACY_PCM_MODE;
ac->fptr_cache_ops = NULL;
return;
}
@@ -364,7 +368,6 @@
struct list_head *ptr, *next;
int result;
int size = 4096;
-
get_asm_custom_topology(&cal_block);
if (cal_block.cal_size == 0) {
pr_debug("%s: no cal to send addr= 0x%x\n",
@@ -422,8 +425,9 @@
}
}
- q6asm_add_hdr(ac, &asm_top.hdr, APR_PKT_SIZE(APR_HDR_SIZE,
- sizeof(asm_top)), TRUE);
+ q6asm_add_hdr_custom_topology(ac, &asm_top.hdr,
+ APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(asm_top)), TRUE);
asm_top.hdr.opcode = ASM_CMD_ADD_TOPOLOGIES;
asm_top.payload_addr_lsw = cal_block.cal_paddr;
@@ -445,7 +449,7 @@
result = wait_event_timeout(ac->cmd_wait,
(atomic_read(&ac->cmd_state) == 0), 5*HZ);
if (!result) {
- pr_err("%s: Set topologies failed payload = 0x%x\n",
+ pr_err("%s: Set topologies failed after timedout payload = 0x%x\n",
__func__, cal_block.cal_paddr);
goto done;
}
@@ -731,6 +735,8 @@
}
}
+ apr_deregister(ac->apr2);
+ ac->apr2 = NULL;
apr_deregister(ac->apr);
ac->apr = NULL;
ac->mmap_apr = NULL;
@@ -775,7 +781,7 @@
if ((atomic_read(&this_mmap.ref_cnt) == 0) ||
(this_mmap.apr == NULL)) {
this_mmap.apr = apr_register("ADSP", "ASM", \
- (apr_fn)q6asm_mmapcallback,\
+ (apr_fn)q6asm_srvc_callback,\
0x0FFFFFFFF, &this_mmap);
if (this_mmap.apr == NULL) {
pr_debug("%s Unable to register APR ASM common port\n",
@@ -805,7 +811,7 @@
ac->cb = cb;
ac->priv = priv;
ac->io_mode = SYNC_IO_MODE;
- ac->perf_mode = false;
+ ac->perf_mode = LEGACY_PCM_MODE;
ac->fptr_cache_ops = NULL;
ac->apr = apr_register("ADSP", "ASM", \
(apr_fn)q6asm_callback,\
@@ -816,6 +822,15 @@
pr_err("%s Registration with APR failed\n", __func__);
goto fail;
}
+ ac->apr2 = apr_register("ADSP", "ASM", \
+ (apr_fn)q6asm_callback,\
+ ((ac->session) << 8 | 0x0002),\
+ ac);
+
+ if (ac->apr2 == NULL) {
+ pr_err("%s Registration with APR-2 failed\n", __func__);
+ goto fail;
+ }
rtac_set_asm_handle(n, ac->apr);
pr_debug("%s Registering the common port with APR\n", __func__);
@@ -865,7 +880,6 @@
pr_err("%s: session not active: %d\n", __func__, session_id);
goto err;
}
-
return session[session_id];
err:
return NULL;
@@ -1038,7 +1052,7 @@
return -EINVAL;
}
-static int32_t q6asm_mmapcallback(struct apr_client_data *data, void *priv)
+static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv)
{
uint32_t sid = 0;
uint32_t dir = 0;
@@ -1085,6 +1099,7 @@
switch (payload[0]) {
case ASM_CMD_SHARED_MEM_MAP_REGIONS:
case ASM_CMD_SHARED_MEM_UNMAP_REGIONS:
+ case ASM_CMD_ADD_TOPOLOGIES:
if (payload[1] != 0) {
pr_err("%s: cmd = 0x%x returned error = 0x%x sid:%d\n",
__func__, payload[0], payload[1], sid);
@@ -1210,7 +1225,8 @@
data->token, data->payload_size, data->src_port,
data->dest_port);
if ((data->opcode != ASM_DATA_EVENT_RENDERED_EOS) &&
- (data->opcode != ASM_DATA_EVENT_EOS))
+ (data->opcode != ASM_DATA_EVENT_EOS) &&
+ (data->opcode != ASM_SESSION_EVENT_RX_UNDERFLOW))
pr_debug("%s:Payload = [0x%x] status[0x%x]\n",
__func__, payload[0], payload[1]);
if (data->opcode == APR_BASIC_RSP_RESULT) {
@@ -1225,6 +1241,7 @@
data->payload_size))
break;
case ASM_SESSION_CMD_PAUSE:
+ case ASM_SESSION_CMD_SUSPEND:
case ASM_DATA_CMD_EOS:
case ASM_STREAM_CMD_CLOSE:
case ASM_STREAM_CMD_FLUSH:
@@ -1240,9 +1257,13 @@
case ASM_STREAM_CMD_OPEN_READ_V3:
case ASM_STREAM_CMD_OPEN_WRITE_V3:
case ASM_STREAM_CMD_OPEN_READWRITE_V2:
+ case ASM_STREAM_CMD_OPEN_LOOPBACK_V2:
case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
case ASM_CMD_ADD_TOPOLOGIES:
+ case ASM_DATA_CMD_REMOVE_INITIAL_SILENCE:
+ case ASM_DATA_CMD_REMOVE_TRAILING_SILENCE:
+ case ASM_SESSION_CMD_REGISTER_FOR_RX_UNDERFLOW_EVENTS:
pr_debug("%s:Payload = [0x%x]stat[0x%x]\n",
__func__, payload[0], payload[1]);
if (atomic_read(&ac->cmd_state) && wakeup_flag) {
@@ -1366,7 +1387,10 @@
__func__, data->opcode);
break;
case ASM_SESSION_EVENTX_OVERFLOW:
- pr_err("ASM_SESSION_EVENTX_OVERFLOW\n");
+ pr_debug("ASM_SESSION_EVENTX_OVERFLOW\n");
+ break;
+ case ASM_SESSION_EVENT_RX_UNDERFLOW:
+ pr_debug("ASM_SESSION_EVENT_RX_UNDERFLOW\n");
break;
case ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3:
pr_debug("%s: ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3, payload[0] = %d, payload[1] = %d, payload[2] = %d\n",
@@ -1518,9 +1542,94 @@
return ret;
}
+static void __q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
+ uint32_t pkt_size, uint32_t cmd_flg, uint32_t stream_id)
+{
+ pr_debug("%s:pkt_size=%d cmd_flg=%d session=%d stream_id=%d\n",
+ __func__, pkt_size, cmd_flg, ac->session, stream_id);
+ if (ac->apr == NULL) {
+ pr_err("%s: ac->apr is NULL", __func__);
+ return;
+ }
+
+ mutex_lock(&ac->cmd_lock);
+ hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, \
+ APR_HDR_LEN(sizeof(struct apr_hdr)),\
+ APR_PKT_VER);
+ hdr->src_svc = ((struct apr_svc *)ac->apr)->id;
+ hdr->src_domain = APR_DOMAIN_APPS;
+ hdr->dest_svc = APR_SVC_ASM;
+ hdr->dest_domain = APR_DOMAIN_ADSP;
+ hdr->src_port = ((ac->session << 8) & 0xFF00) | (stream_id+1);
+ hdr->dest_port = ((ac->session << 8) & 0xFF00) | (stream_id+1);
+ if (cmd_flg) {
+ hdr->token = ac->session;
+ atomic_set(&ac->cmd_state, 1);
+ }
+ hdr->pkt_size = pkt_size;
+ mutex_unlock(&ac->cmd_lock);
+ return;
+}
+
static void q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
uint32_t pkt_size, uint32_t cmd_flg)
{
+ __q6asm_add_hdr(ac, hdr, pkt_size, cmd_flg, ac->stream_id);
+ return;
+}
+
+static void q6asm_stream_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
+ uint32_t pkt_size, uint32_t cmd_flg, int32_t stream_id)
+{
+ __q6asm_add_hdr(ac, hdr, pkt_size, cmd_flg, stream_id);
+ return;
+}
+
+static void __q6asm_add_hdr_async(struct audio_client *ac, struct apr_hdr *hdr,
+ uint32_t pkt_size, uint32_t cmd_flg, uint32_t stream_id)
+{
+ pr_debug("%s pkt_size = %d, cmd_flg = %d, session = %d stream_id=%d\n",
+ __func__, pkt_size, cmd_flg, ac->session, stream_id);
+ hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, \
+ APR_HDR_LEN(sizeof(struct apr_hdr)),\
+ APR_PKT_VER);
+ if (ac->apr == NULL) {
+ pr_err("%s: ac->apr is NULL", __func__);
+ return;
+ }
+ hdr->src_svc = ((struct apr_svc *)ac->apr)->id;
+ hdr->src_domain = APR_DOMAIN_APPS;
+ hdr->dest_svc = APR_SVC_ASM;
+ hdr->dest_domain = APR_DOMAIN_ADSP;
+ hdr->src_port = ((ac->session << 8) & 0xFF00) | (stream_id+1);
+ hdr->dest_port = ((ac->session << 8) & 0xFF00) | (stream_id+1);
+ if (cmd_flg) {
+ hdr->token = ac->session;
+ atomic_set(&ac->cmd_state, 1);
+ }
+ hdr->pkt_size = pkt_size;
+ return;
+}
+
+static void q6asm_add_hdr_async(struct audio_client *ac, struct apr_hdr *hdr,
+ uint32_t pkt_size, uint32_t cmd_flg)
+{
+ __q6asm_add_hdr_async(ac, hdr, pkt_size, cmd_flg, ac->stream_id);
+ return;
+}
+
+static void q6asm_stream_add_hdr_async(struct audio_client *ac,
+ struct apr_hdr *hdr, uint32_t pkt_size,
+ uint32_t cmd_flg, int32_t stream_id)
+{
+ __q6asm_add_hdr_async(ac, hdr, pkt_size, cmd_flg, stream_id);
+ return;
+}
+
+static void q6asm_add_hdr_custom_topology(struct audio_client *ac,
+ struct apr_hdr *hdr,
+ uint32_t pkt_size, uint32_t cmd_flg)
+{
pr_debug("%s:pkt_size=%d cmd_flg=%d session=%d\n", __func__, pkt_size,
cmd_flg, ac->session);
if (ac->apr == NULL) {
@@ -1537,9 +1646,9 @@
hdr->dest_svc = APR_SVC_ASM;
hdr->dest_domain = APR_DOMAIN_ADSP;
hdr->src_port = ((ac->session << 8) & 0xFF00) | 0x01;
- hdr->dest_port = ((ac->session << 8) & 0xFF00) | 0x01;
+ hdr->dest_port = 0;
if (cmd_flg) {
- hdr->token = ac->session;
+ hdr->token = ((ac->session << 8) | 0x0001) ;
atomic_set(&ac->cmd_state, 1);
}
hdr->pkt_size = pkt_size;
@@ -1547,32 +1656,6 @@
return;
}
-static void q6asm_add_hdr_async(struct audio_client *ac, struct apr_hdr *hdr,
- uint32_t pkt_size, uint32_t cmd_flg)
-{
- pr_debug("pkt_size = %d, cmd_flg = %d, session = %d\n",
- pkt_size, cmd_flg, ac->session);
- hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, \
- APR_HDR_LEN(sizeof(struct apr_hdr)),\
- APR_PKT_VER);
- if (ac->apr == NULL) {
- pr_err("%s: ac->apr is NULL", __func__);
- return;
- }
- hdr->src_svc = ((struct apr_svc *)ac->apr)->id;
- hdr->src_domain = APR_DOMAIN_APPS;
- hdr->dest_svc = APR_SVC_ASM;
- hdr->dest_domain = APR_DOMAIN_ADSP;
- hdr->src_port = ((ac->session << 8) & 0xFF00) | 0x01;
- hdr->dest_port = ((ac->session << 8) & 0xFF00) | 0x01;
- if (cmd_flg) {
- hdr->token = ac->session;
- atomic_set(&ac->cmd_state, 1);
- }
- hdr->pkt_size = pkt_size;
- return;
-}
-
static void q6asm_add_mmaphdr(struct audio_client *ac, struct apr_hdr *hdr,
u32 pkt_size, u32 cmd_flg, u32 token)
{
@@ -1613,7 +1696,7 @@
open.bits_per_sample = bits_per_sample;
open.mode_flags = 0x0;
- if (ac->perf_mode) {
+ if (ac->perf_mode == LOW_LATENCY_PCM_MODE) {
open.mode_flags |= ASM_LOW_LATENCY_STREAM_SESSION <<
ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ;
} else {
@@ -1663,6 +1746,7 @@
rc);
goto fail_cmd;
}
+ ac->io_mode |= TUN_READ_IO_MODE;
return 0;
fail_cmd:
return -EINVAL;
@@ -1681,7 +1765,8 @@
}
static int __q6asm_open_write(struct audio_client *ac, uint32_t format,
- uint16_t bits_per_sample)
+ uint16_t bits_per_sample, uint32_t stream_id,
+ bool is_gapless_mode)
{
int rc = 0x00;
struct asm_stream_cmd_open_write_v3 open;
@@ -1693,14 +1778,19 @@
pr_debug("%s: session[%d] wr_format[0x%x]", __func__, ac->session,
format);
- q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+ q6asm_stream_add_hdr(ac, &open.hdr, sizeof(open), TRUE, stream_id);
open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V3;
open.mode_flags = 0x00;
- if (ac->perf_mode)
+ if (ac->perf_mode == ULTRA_LOW_LATENCY_PCM_MODE)
open.mode_flags |= ASM_ULTRA_LOW_LATENCY_STREAM_SESSION;
- else
+ else if (ac->perf_mode == LOW_LATENCY_PCM_MODE)
+ open.mode_flags |= ASM_LOW_LATENCY_STREAM_SESSION;
+ else {
open.mode_flags |= ASM_LEGACY_STREAM_SESSION;
+ if (is_gapless_mode)
+ open.mode_flags |= 1 << ASM_SHIFT_GAPLESS_MODE_FLAG;
+ }
/* source endpoint : matrix */
open.sink_endpointype = ASM_END_POINT_DEVICE_MATRIX;
@@ -1752,6 +1842,7 @@
rc);
goto fail_cmd;
}
+ ac->io_mode |= TUN_WRITE_IO_MODE;
return 0;
fail_cmd:
return -EINVAL;
@@ -1759,13 +1850,23 @@
int q6asm_open_write(struct audio_client *ac, uint32_t format)
{
- return __q6asm_open_write(ac, format, 16);
+ return __q6asm_open_write(ac, format, 16, ac->stream_id,
+ false /*gapless*/);
}
int q6asm_open_write_v2(struct audio_client *ac, uint32_t format,
uint16_t bits_per_sample)
{
- return __q6asm_open_write(ac, format, bits_per_sample);
+ return __q6asm_open_write(ac, format, bits_per_sample,
+ ac->stream_id, false /*gapless*/);
+}
+
+int q6asm_stream_open_write_v2(struct audio_client *ac, uint32_t format,
+ uint16_t bits_per_sample, int32_t stream_id,
+ bool is_gapless_mode)
+{
+ return __q6asm_open_write(ac, format, bits_per_sample,
+ stream_id, is_gapless_mode);
}
int q6asm_open_read_write(struct audio_client *ac,
@@ -1776,7 +1877,7 @@
struct asm_stream_cmd_open_readwrite_v2 open;
if ((ac == NULL) || (ac->apr == NULL)) {
- pr_err("APR handle NULL\n");
+ pr_err("%s: APR handle NULL\n", __func__);
return -EINVAL;
}
pr_debug("%s: session[%d]", __func__, ac->session);
@@ -1882,13 +1983,56 @@
return -EINVAL;
}
+int q6asm_open_loopback_v2(struct audio_client *ac, uint16_t bits_per_sample)
+{
+ int rc = 0x00;
+ struct asm_stream_cmd_open_loopback_v2 open;
+
+ if ((ac == NULL) || (ac->apr == NULL)) {
+ pr_err("%s APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ pr_debug("%s: session[%d]", __func__, ac->session);
+
+ q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+ open.hdr.opcode = ASM_STREAM_CMD_OPEN_LOOPBACK_V2;
+
+ open.mode_flags = 0;
+ open.src_endpointype = 0;
+ open.sink_endpointype = 0;
+ /* source endpoint : matrix */
+ open.postprocopo_id = get_asm_topology();
+ if (open.postprocopo_id == 0)
+ open.postprocopo_id = DEFAULT_POPP_TOPOLOGY;
+ open.bits_per_sample = bits_per_sample;
+ open.reserved = 0;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+ if (rc < 0) {
+ pr_err("%s open failed op[0x%x]rc[%d]\n", __func__,
+ open.hdr.opcode, rc);
+ goto fail_cmd;
+ }
+
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s timeout. waited for open_loopback rc[%d]\n",
+ __func__, rc);
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
int q6asm_run(struct audio_client *ac, uint32_t flags,
uint32_t msw_ts, uint32_t lsw_ts)
{
struct asm_session_cmd_run_v2 run;
int rc;
if (!ac || ac->apr == NULL) {
- pr_err("APR handle NULL\n");
+ pr_err("%s: APR handle NULL\n", __func__);
return -EINVAL;
}
pr_debug("%s session[%d]", __func__, ac->session);
@@ -1919,8 +2063,8 @@
return -EINVAL;
}
-int q6asm_run_nowait(struct audio_client *ac, uint32_t flags,
- uint32_t msw_ts, uint32_t lsw_ts)
+static int __q6asm_run_nowait(struct audio_client *ac, uint32_t flags,
+ uint32_t msw_ts, uint32_t lsw_ts, uint32_t stream_id)
{
struct asm_session_cmd_run_v2 run;
int rc;
@@ -1929,7 +2073,7 @@
return -EINVAL;
}
pr_debug("session[%d]", ac->session);
- q6asm_add_hdr_async(ac, &run.hdr, sizeof(run), TRUE);
+ q6asm_stream_add_hdr_async(ac, &run.hdr, sizeof(run), TRUE, stream_id);
run.hdr.opcode = ASM_SESSION_CMD_RUN_V2;
run.flags = flags;
@@ -1947,6 +2091,17 @@
return 0;
}
+int q6asm_run_nowait(struct audio_client *ac, uint32_t flags,
+ uint32_t msw_ts, uint32_t lsw_ts)
+{
+ return __q6asm_run_nowait(ac, flags, msw_ts, lsw_ts, ac->stream_id);
+}
+
+int q6asm_stream_run_nowait(struct audio_client *ac, uint32_t flags,
+ uint32_t msw_ts, uint32_t lsw_ts, uint32_t stream_id)
+{
+ return __q6asm_run_nowait(ac, flags, msw_ts, lsw_ts, stream_id);
+}
int q6asm_enc_cfg_blk_aac(struct audio_client *ac,
uint32_t frames_per_buf,
@@ -2170,21 +2325,21 @@
lchannel_mapping[3] = PCM_CHANNEL_LB;
lchannel_mapping[4] = PCM_CHANNEL_RB;
} else if (channels == 6) {
- lchannel_mapping[0] = PCM_CHANNEL_FC;
- lchannel_mapping[1] = PCM_CHANNEL_FL;
- lchannel_mapping[2] = PCM_CHANNEL_FR;
- lchannel_mapping[3] = PCM_CHANNEL_LB;
- lchannel_mapping[4] = PCM_CHANNEL_RB;
- lchannel_mapping[5] = PCM_CHANNEL_LFE;
+ lchannel_mapping[0] = PCM_CHANNEL_FL;
+ lchannel_mapping[1] = PCM_CHANNEL_FR;
+ lchannel_mapping[2] = PCM_CHANNEL_FC;
+ lchannel_mapping[3] = PCM_CHANNEL_LFE;
+ lchannel_mapping[4] = PCM_CHANNEL_LS;
+ lchannel_mapping[5] = PCM_CHANNEL_RS;
} else if (channels == 8) {
lchannel_mapping[0] = PCM_CHANNEL_FL;
lchannel_mapping[1] = PCM_CHANNEL_FR;
- lchannel_mapping[2] = PCM_CHANNEL_LFE;
- lchannel_mapping[3] = PCM_CHANNEL_FC;
+ lchannel_mapping[2] = PCM_CHANNEL_FC;
+ lchannel_mapping[3] = PCM_CHANNEL_LFE;
lchannel_mapping[4] = PCM_CHANNEL_LB;
lchannel_mapping[5] = PCM_CHANNEL_RB;
- lchannel_mapping[6] = PCM_CHANNEL_RLC;
- lchannel_mapping[7] = PCM_CHANNEL_RRC;
+ lchannel_mapping[6] = PCM_CHANNEL_FLC;
+ lchannel_mapping[7] = PCM_CHANNEL_FRC;
} else {
pr_err("%s: ERROR.unsupported num_ch = %u\n",
__func__, channels);
@@ -2439,12 +2594,6 @@
}
-int q6asm_media_format_block_aac(struct audio_client *ac,
- struct asm_aac_cfg *cfg)
-{
- return q6asm_media_format_block_multi_aac(ac, cfg);
-}
-
static int __q6asm_media_format_block_pcm(struct audio_client *ac,
uint32_t rate, uint32_t channels,
uint16_t bits_per_sample)
@@ -2575,8 +2724,8 @@
bits_per_sample);
}
-int q6asm_media_format_block_multi_aac(struct audio_client *ac,
- struct asm_aac_cfg *cfg)
+static int __q6asm_media_format_block_multi_aac(struct audio_client *ac,
+ struct asm_aac_cfg *cfg, int stream_id)
{
struct asm_aac_fmt_blk_v2 fmt;
int rc = 0;
@@ -2584,7 +2733,7 @@
pr_debug("%s:session[%d]rate[%d]ch[%d]\n", __func__, ac->session,
cfg->sample_rate, cfg->ch_cfg);
- q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+ q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
@@ -2618,6 +2767,24 @@
return -EINVAL;
}
+int q6asm_media_format_block_multi_aac(struct audio_client *ac,
+ struct asm_aac_cfg *cfg)
+{
+ return __q6asm_media_format_block_multi_aac(ac, cfg, ac->stream_id);
+}
+
+int q6asm_media_format_block_aac(struct audio_client *ac,
+ struct asm_aac_cfg *cfg)
+{
+ return __q6asm_media_format_block_multi_aac(ac, cfg, ac->stream_id);
+}
+
+int q6asm_stream_media_format_block_aac(struct audio_client *ac,
+ struct asm_aac_cfg *cfg, int stream_id)
+{
+ return __q6asm_media_format_block_multi_aac(ac, cfg, stream_id);
+}
+
int q6asm_media_format_block_wma(struct audio_client *ac,
void *cfg)
{
@@ -2793,7 +2960,7 @@
int cmd_size = 0;
if (!ac || ac->mmap_apr == NULL) {
- pr_err("APR handle NULL\n");
+ pr_err("%s: APR handle NULL\n", __func__);
return -EINVAL;
}
pr_debug("%s: Session[%d]\n", __func__, ac->session);
@@ -2870,7 +3037,7 @@
int rc = 0;
if (!ac || this_mmap.apr == NULL) {
- pr_err("APR handle NULL\n");
+ pr_err("%s: APR handle NULL\n", __func__);
return -EINVAL;
}
pr_debug("%s: Session[%d]\n", __func__, ac->session);
@@ -2940,7 +3107,7 @@
uint32_t bufsz_t;
if (!ac || ac->mmap_apr == NULL) {
- pr_err("APR handle NULL\n");
+ pr_err("%s: APR handle NULL\n", __func__);
return -EINVAL;
}
pr_debug("%s: Session[%d]\n", __func__, ac->session);
@@ -3049,7 +3216,7 @@
int cmd_size = 0;
if (!ac || ac->mmap_apr == NULL) {
- pr_err("APR handle NULL\n");
+ pr_err("%s: APR handle NULL\n", __func__);
return -EINVAL;
}
pr_debug("%s: Session[%d]\n", __func__, ac->session);
@@ -3435,7 +3602,7 @@
struct audio_port_data *port;
int rc;
if (!ac || ac->apr == NULL) {
- pr_err("APR handle NULL\n");
+ pr_err("%s: APR handle NULL\n", __func__);
return -EINVAL;
}
if (ac->io_mode & SYNC_IO_MODE) {
@@ -3498,7 +3665,7 @@
struct audio_port_data *port;
int rc;
if (!ac || ac->apr == NULL) {
- pr_err("APR handle NULL\n");
+ pr_err("%s: APR handle NULL\n", __func__);
return -EINVAL;
}
if (ac->io_mode & SYNC_IO_MODE) {
@@ -3602,7 +3769,7 @@
write.flags = (0x00000000 | (param->flags & 0x800000FF));
else
write.flags = (0x80000000 | param->flags);
-
+ write.flags |= param->last_buffer << ASM_SHIFT_LAST_BUFFER_FLAG;
write.seq_id = param->uid;
list_for_each_safe(ptr, next, &ac->port[IN].mem_map_handle) {
buf_node = list_entry(ptr, struct asm_buffer_node,
@@ -3695,7 +3862,7 @@
int dsp_buf = 0;
if (!ac || ac->apr == NULL) {
- pr_err("APR handle NULL\n");
+ pr_err("%s: APR handle NULL\n", __func__);
return -EINVAL;
}
pr_debug("%s: session[%d] len=%d", __func__, ac->session, len);
@@ -3763,7 +3930,7 @@
int dsp_buf = 0;
if (!ac || ac->apr == NULL) {
- pr_err("APR handle NULL\n");
+ pr_err("%s: APR handle NULL\n", __func__);
return -EINVAL;
}
pr_debug("%s: session[%d] len=%d", __func__, ac->session, len);
@@ -3822,7 +3989,7 @@
int rc;
if (!ac || ac->apr == NULL || tstamp == NULL) {
- pr_err("APR handle NULL or tstamp NULL\n");
+ pr_err("%s: APR handle NULL or tstamp NULL\n", __func__);
return -EINVAL;
}
q6asm_add_hdr(ac, &hdr, sizeof(hdr), TRUE);
@@ -3852,7 +4019,59 @@
return -EINVAL;
}
-int q6asm_cmd(struct audio_client *ac, int cmd)
+int q6asm_send_audio_effects_params(struct audio_client *ac, char *params,
+ uint32_t params_length)
+{
+ char *asm_params = NULL;
+ struct apr_hdr hdr;
+ struct asm_stream_cmd_set_pp_params_v2 payload_params;
+ int sz, rc;
+
+ pr_debug("%s\n", __func__);
+ if (!ac || ac->apr == NULL || params == NULL) {
+ pr_err("APR handle NULL or params NULL\n");
+ return -EINVAL;
+ }
+ sz = sizeof(struct apr_hdr) +
+ sizeof(struct asm_stream_cmd_set_pp_params_v2) +
+ params_length;
+ asm_params = kzalloc(sz, GFP_KERNEL);
+ if (!asm_params) {
+ pr_err("%s, adm params memory alloc failed", __func__);
+ return -ENOMEM;
+ }
+ q6asm_add_hdr_async(ac, &hdr, (sizeof(struct apr_hdr) +
+ sizeof(struct asm_stream_cmd_set_pp_params_v2) +
+ params_length), TRUE);
+ hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
+ payload_params.data_payload_addr_lsw = 0;
+ payload_params.data_payload_addr_msw = 0;
+ payload_params.mem_map_handle = 0;
+ payload_params.data_payload_size = params_length;
+ memcpy(((u8 *)asm_params), &hdr, sizeof(struct apr_hdr));
+ memcpy(((u8 *)asm_params + sizeof(struct apr_hdr)), &payload_params,
+ sizeof(struct asm_stream_cmd_set_pp_params_v2));
+ memcpy(((u8 *)asm_params + sizeof(struct apr_hdr) +
+ sizeof(struct asm_stream_cmd_set_pp_params_v2)),
+ params, params_length);
+ rc = apr_send_pkt(ac->apr, (uint32_t *) asm_params);
+ if (rc < 0) {
+ pr_err("%s: audio effects set-params send failed\n", __func__);
+ goto fail_send_param;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 1*HZ);
+ if (!rc) {
+ pr_err("%s: timeout, audio effects set-params\n", __func__);
+ goto fail_send_param;
+ }
+ rc = 0;
+fail_send_param:
+ kfree(asm_params);
+ return rc;
+}
+
+static int __q6asm_cmd(struct audio_client *ac, int cmd, uint32_t stream_id)
{
struct apr_hdr hdr;
int rc;
@@ -3860,16 +4079,21 @@
int cnt = 0;
if (!ac || ac->apr == NULL) {
- pr_err("APR handle NULL\n");
+ pr_err("%s: APR handle NULL\n", __func__);
return -EINVAL;
}
- q6asm_add_hdr(ac, &hdr, sizeof(hdr), TRUE);
+ q6asm_stream_add_hdr(ac, &hdr, sizeof(hdr), TRUE, stream_id);
switch (cmd) {
case CMD_PAUSE:
pr_debug("%s:CMD_PAUSE\n", __func__);
hdr.opcode = ASM_SESSION_CMD_PAUSE;
state = &ac->cmd_state;
break;
+ case CMD_SUSPEND:
+ pr_debug("%s:CMD_SUSPEND\n", __func__);
+ hdr.opcode = ASM_SESSION_CMD_SUSPEND;
+ state = &ac->cmd_state;
+ break;
case CMD_FLUSH:
pr_debug("%s:CMD_FLUSH\n", __func__);
hdr.opcode = ASM_STREAM_CMD_FLUSH;
@@ -3936,7 +4160,18 @@
return -EINVAL;
}
-int q6asm_cmd_nowait(struct audio_client *ac, int cmd)
+int q6asm_cmd(struct audio_client *ac, int cmd)
+{
+ return __q6asm_cmd(ac, cmd, ac->stream_id);
+}
+
+int q6asm_stream_cmd(struct audio_client *ac, int cmd, uint32_t stream_id)
+{
+ return __q6asm_cmd(ac, cmd, stream_id);
+}
+
+static int __q6asm_cmd_nowait(struct audio_client *ac, int cmd,
+ uint32_t stream_id)
{
struct apr_hdr hdr;
int rc;
@@ -3945,7 +4180,7 @@
pr_err("%s:APR handle NULL\n", __func__);
return -EINVAL;
}
- q6asm_add_hdr_async(ac, &hdr, sizeof(hdr), TRUE);
+ q6asm_stream_add_hdr_async(ac, &hdr, sizeof(hdr), TRUE, stream_id);
switch (cmd) {
case CMD_PAUSE:
pr_debug("%s:CMD_PAUSE\n", __func__);
@@ -3955,6 +4190,10 @@
pr_debug("%s:CMD_EOS\n", __func__);
hdr.opcode = ASM_DATA_CMD_EOS;
break;
+ case CMD_CLOSE:
+ pr_debug("%s:CMD_CLOSE\n", __func__);
+ hdr.opcode = ASM_STREAM_CMD_CLOSE;
+ break;
default:
pr_err("%s:Invalid format[%d]\n", __func__, cmd);
goto fail_cmd;
@@ -3975,13 +4214,63 @@
return -EINVAL;
}
+int q6asm_cmd_nowait(struct audio_client *ac, int cmd)
+{
+ pr_debug("%s: stream_id: %d\n", __func__, ac->stream_id);
+ return __q6asm_cmd_nowait(ac, cmd, ac->stream_id);
+}
+
+int q6asm_stream_cmd_nowait(struct audio_client *ac, int cmd,
+ uint32_t stream_id)
+{
+ pr_debug("%s: stream_id: %d\n", __func__, stream_id);
+ return __q6asm_cmd_nowait(ac, cmd, stream_id);
+}
+
+int q6asm_send_meta_data(struct audio_client *ac, uint32_t initial_samples,
+ uint32_t trailing_samples)
+{
+ struct asm_data_cmd_remove_silence silence;
+ int rc = 0;
+ if (!ac || ac->apr == NULL) {
+ pr_err("APR handle NULL\n");
+ return -EINVAL;
+ }
+ pr_debug("%s session[%d]", __func__, ac->session);
+ q6asm_add_hdr_async(ac, &silence.hdr, sizeof(silence), FALSE);
+
+ silence.hdr.opcode = ASM_DATA_CMD_REMOVE_INITIAL_SILENCE;
+ silence.num_samples_to_remove = initial_samples;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &silence);
+ if (rc < 0) {
+ pr_err("Commmand silence failed[%d]", rc);
+ goto fail_cmd;
+ }
+
+ silence.hdr.opcode = ASM_DATA_CMD_REMOVE_TRAILING_SILENCE;
+ silence.num_samples_to_remove = trailing_samples;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &silence);
+ if (rc < 0) {
+ pr_err("Commmand silence failed[%d]", rc);
+ goto fail_cmd;
+ }
+
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
static void q6asm_reset_buf_state(struct audio_client *ac)
{
int cnt = 0;
int loopcnt = 0;
+ int used;
struct audio_port_data *port = NULL;
if (ac->io_mode & SYNC_IO_MODE) {
+ used = (ac->io_mode & TUN_WRITE_IO_MODE ? 1 : 0);
mutex_lock(&ac->cmd_lock);
for (loopcnt = 0; loopcnt <= OUT; loopcnt++) {
port = &ac->port[loopcnt];
@@ -3991,7 +4280,7 @@
while (cnt >= 0) {
if (!port->buf)
continue;
- port->buf[cnt].used = 1;
+ port->buf[cnt].used = used;
cnt--;
}
}
@@ -4005,7 +4294,7 @@
int rc;
if (!ac || ac->apr == NULL) {
- pr_err("APR handle NULL\n");
+ pr_err("%s: APR handle NULL\n", __func__);
return -EINVAL;
}
pr_debug("%s:session[%d]enable[%d]\n", __func__,
@@ -4034,6 +4323,35 @@
return -EINVAL;
}
+int q6asm_reg_rx_underflow(struct audio_client *ac, uint16_t enable)
+{
+ struct asm_session_cmd_rgstr_rx_underflow rx_underflow;
+ int rc;
+
+ if (!ac || ac->apr == NULL) {
+ pr_err("APR handle NULL\n");
+ return -EINVAL;
+ }
+ pr_debug("%s:session[%d]enable[%d]\n", __func__,
+ ac->session, enable);
+ q6asm_add_hdr_async(ac, &rx_underflow.hdr, sizeof(rx_underflow), FALSE);
+
+ rx_underflow.hdr.opcode = \
+ ASM_SESSION_CMD_REGISTER_FOR_RX_UNDERFLOW_EVENTS;
+ /* tx overflow event: enable */
+ rx_underflow.enable_flag = enable;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &rx_underflow);
+ if (rc < 0) {
+ pr_err("tx overflow op[0x%x]rc[%d]\n", \
+ rx_underflow.hdr.opcode, rc);
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
int q6asm_get_apr_service_id(int session_id)
{
pr_debug("%s\n", __func__);
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index 673ecff..c4395c2 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -350,6 +350,11 @@
NULL : &common.voice[idx]);
}
+static bool is_voice_session(u32 session_id)
+{
+ return (session_id == common.voice[VOC_PATH_PASSIVE].session_id);
+}
+
static bool is_voip_session(u32 session_id)
{
return (session_id == common.voice[VOC_PATH_FULL].session_id);
@@ -1861,10 +1866,18 @@
cvp_setdev_cmd.cvp_set_device_v2.tx_port_id = v->dev_tx.port_id;
cvp_setdev_cmd.cvp_set_device_v2.rx_port_id = v->dev_rx.port_id;
- cvp_setdev_cmd.cvp_set_device_v2.vocproc_mode =
+
+ if (common.ec_ref_ext) {
+ cvp_setdev_cmd.cvp_set_device_v2.vocproc_mode =
+ VSS_IVOCPROC_VOCPROC_MODE_EC_EXT_MIXING;
+ cvp_setdev_cmd.cvp_set_device_v2.ec_ref_port_id =
+ common.ec_port_id;
+ } else {
+ cvp_setdev_cmd.cvp_set_device_v2.vocproc_mode =
VSS_IVOCPROC_VOCPROC_MODE_EC_INT_MIXING;
- cvp_setdev_cmd.cvp_set_device_v2.ec_ref_port_id =
+ cvp_setdev_cmd.cvp_set_device_v2.ec_ref_port_id =
VSS_IVOCPROC_PORT_ID_NONE;
+ }
pr_debug("topology=%d , tx_port_id=%d, rx_port_id=%d\n",
cvp_setdev_cmd.cvp_set_device_v2.tx_topology_id,
cvp_setdev_cmd.cvp_set_device_v2.tx_port_id,
@@ -3026,10 +3039,17 @@
cvp_session_cmd.cvp_session.rx_port_id = v->dev_rx.port_id;
cvp_session_cmd.cvp_session.profile_id =
VSS_ICOMMON_CAL_NETWORK_ID_NONE;
- cvp_session_cmd.cvp_session.vocproc_mode =
+ if (common.ec_ref_ext) {
+ cvp_session_cmd.cvp_session.vocproc_mode =
+ VSS_IVOCPROC_VOCPROC_MODE_EC_EXT_MIXING;
+ cvp_session_cmd.cvp_session.ec_ref_port_id =
+ common.ec_port_id;
+ } else {
+ cvp_session_cmd.cvp_session.vocproc_mode =
VSS_IVOCPROC_VOCPROC_MODE_EC_INT_MIXING;
- cvp_session_cmd.cvp_session.ec_ref_port_id =
+ cvp_session_cmd.cvp_session.ec_ref_port_id =
VSS_IVOCPROC_PORT_ID_NONE;
+ }
pr_debug("tx_topology: %d tx_port_id=%d, rx_port_id=%d, mode: 0x%x\n",
cvp_session_cmd.cvp_session.tx_topology_id,
@@ -4257,8 +4277,10 @@
v = voice_get_session(voc_get_session_id(VOICE_SESSION_NAME));
else if (port_id == VOICE2_PLAYBACK_TX)
v = voice_get_session(voc_get_session_id(VOICE2_SESSION_NAME));
+ else
+ pr_err("%s: Invalid port_id 0x%x", __func__, port_id);
- if (v != NULL) {
+ while (v != NULL) {
mutex_lock(&v->lock);
v->music_info.port_id = port_id;
v->music_info.play_enable = set;
@@ -4278,8 +4300,17 @@
}
mutex_unlock(&v->lock);
- } else {
- pr_err("%s: Invalid port_id 0x%x", __func__, port_id);
+
+ /* Voice and VoLTE call use the same pseudo port and hence
+ * use the same mixer control. So enable incall delivery
+ * for VoLTE as well with Voice.
+ */
+ if (is_voice_session(v->session_id)) {
+ v = voice_get_session(voc_get_session_id(
+ VOLTE_SESSION_NAME));
+ } else {
+ break;
+ }
}
return ret;
@@ -4313,7 +4344,8 @@
v->voc_state = VOC_CHANGE;
}
-
+ if (common.ec_ref_ext)
+ voc_set_ext_ec_ref(AFE_PORT_INVALID, false);
fail: mutex_unlock(&v->lock);
return ret;
@@ -4756,6 +4788,8 @@
ret = -EINVAL;
}
+ if (common.ec_ref_ext)
+ voc_set_ext_ec_ref(AFE_PORT_INVALID, false);
mutex_unlock(&v->lock);
return ret;
@@ -4973,6 +5007,28 @@
return ret;
}
+int voc_set_ext_ec_ref(uint16_t port_id, bool state)
+{
+ int ret = 0;
+
+ mutex_lock(&common.common_lock);
+ if (state == true) {
+ if (port_id == AFE_PORT_INVALID) {
+ pr_err("%s: Invalid port id", __func__);
+ ret = -EINVAL;
+ goto exit;
+ }
+ common.ec_port_id = port_id;
+ common.ec_ref_ext = true;
+ } else {
+ common.ec_ref_ext = false;
+ common.ec_port_id = port_id;
+ }
+exit:
+ mutex_unlock(&common.common_lock);
+ return ret;
+}
+
void voc_register_mvs_cb(ul_cb_fn ul_cb,
dl_cb_fn dl_cb,
void *private_data)
@@ -5807,7 +5863,7 @@
common.default_vol_step_val = 0;
common.default_vol_ramp_duration_ms = DEFAULT_VOLUME_RAMP_DURATION;
common.default_mute_ramp_duration_ms = DEFAULT_MUTE_RAMP_DURATION;
-
+ common.ec_ref_ext = false;
/* Initialize MVS info. */
common.mvs_info.network_type = VSS_NETWORK_ID_DEFAULT;
diff --git a/sound/soc/msm/qdsp6v2/q6voice.h b/sound/soc/msm/qdsp6v2/q6voice.h
index 39f0986..5c0cf21 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.h
+++ b/sound/soc/msm/qdsp6v2/q6voice.h
@@ -1328,6 +1328,8 @@
uint32_t default_vol_step_val;
uint32_t default_vol_ramp_duration_ms;
uint32_t default_mute_ramp_duration_ms;
+ bool ec_ref_ext;
+ uint16_t ec_port_id;
/* APR to MVM in the Q6 */
void *apr_q6_mvm;
@@ -1462,5 +1464,6 @@
int voc_start_playback(uint32_t set, uint16_t port_id);
int voc_start_record(uint32_t port_id, uint32_t set, uint32_t session_id);
int voice_get_idx_for_session(u32 session_id);
+int voc_set_ext_ec_ref(uint16_t port_id, bool state);
#endif
diff --git a/sound/soc/msm/qdsp6v2/rtac.c b/sound/soc/msm/qdsp6v2/rtac.c
index ee21112..701dfef 100644
--- a/sound/soc/msm/qdsp6v2/rtac.c
+++ b/sound/soc/msm/qdsp6v2/rtac.c
@@ -100,6 +100,28 @@
struct rtac_adm_data device[RTAC_MAX_ACTIVE_DEVICES];
};
static struct rtac_adm rtac_adm_data;
+
+
+/* ADM V2 data */
+struct rtac_popp_data {
+ uint32_t popp;
+ uint32_t popp_topology;
+};
+
+struct rtac_adm_data_v2 {
+ uint32_t topology_id;
+ uint32_t afe_port;
+ uint32_t copp;
+ uint32_t num_of_popp;
+ struct rtac_popp_data popp[RTAC_MAX_ACTIVE_POPP];
+};
+
+struct rtac_adm_v2 {
+ uint32_t num_of_dev;
+ struct rtac_adm_data_v2 device[RTAC_MAX_ACTIVE_DEVICES];
+};
+
+static struct rtac_adm_v2 rtac_adm_data_v2;
static u32 *rtac_adm_buffer;
@@ -356,6 +378,147 @@
return result;
}
+
+/* ADM Info V2 */
+static void add_popp_v2(u32 dev_idx, u32 port_id, u32 popp_id)
+{
+ u32 i = 0;
+
+ for (; i < rtac_adm_data_v2.device[dev_idx].num_of_popp; i++)
+ if (rtac_adm_data_v2.device[dev_idx].popp[i].popp == popp_id)
+ goto done;
+
+ if (rtac_adm_data_v2.device[dev_idx].num_of_popp ==
+ RTAC_MAX_ACTIVE_POPP) {
+ pr_err("%s, Max POPP!\n", __func__);
+ goto done;
+ }
+ rtac_adm_data_v2.device[dev_idx].popp[
+ rtac_adm_data_v2.device[dev_idx].num_of_popp].popp = popp_id;
+ rtac_adm_data_v2.device[dev_idx].popp[
+ rtac_adm_data_v2.device[dev_idx].num_of_popp++].popp_topology =
+ get_asm_topology();
+done:
+ return;
+}
+
+static void rtac_add_adm_device_v2(u32 port_id, u32 copp_id, u32 path_id,
+ u32 popp_id)
+{
+ u32 i = 0;
+ pr_debug("%s: port_id = %d, popp_id = %d\n", __func__, port_id,
+ popp_id);
+
+ if (rtac_adm_data_v2.num_of_dev == RTAC_MAX_ACTIVE_DEVICES) {
+ pr_err("%s, Can't add anymore RTAC devices!\n", __func__);
+ goto done;
+ }
+
+ /* Check if device already added */
+ if (rtac_adm_data_v2.num_of_dev != 0) {
+ for (; i < rtac_adm_data_v2.num_of_dev; i++) {
+ if (rtac_adm_data_v2.device[i].afe_port == port_id) {
+ add_popp_v2(i, port_id, popp_id);
+ goto done;
+ }
+ if (rtac_adm_data_v2.device[i].num_of_popp ==
+ RTAC_MAX_ACTIVE_POPP) {
+ pr_err("%s, Max POPP!\n", __func__);
+ goto done;
+ }
+ }
+ }
+
+ /* Add device */
+ rtac_adm_data_v2.num_of_dev++;
+
+ if (path_id == ADM_PATH_PLAYBACK)
+ rtac_adm_data_v2.device[i].topology_id =
+ get_adm_rx_topology();
+ else
+ rtac_adm_data_v2.device[i].topology_id =
+ get_adm_tx_topology();
+ rtac_adm_data_v2.device[i].afe_port = port_id;
+ rtac_adm_data_v2.device[i].copp = copp_id;
+ rtac_adm_data_v2.device[i].popp[
+ rtac_adm_data_v2.device[i].num_of_popp].popp = popp_id;
+ rtac_adm_data_v2.device[i].popp[
+ rtac_adm_data_v2.device[i].num_of_popp++].popp_topology =
+ get_asm_topology();
+done:
+ return;
+}
+
+static void shift_adm_devices_v2(u32 dev_idx)
+{
+ for (; dev_idx < rtac_adm_data_v2.num_of_dev; dev_idx++) {
+ memcpy(&rtac_adm_data_v2.device[dev_idx],
+ &rtac_adm_data_v2.device[dev_idx + 1],
+ sizeof(rtac_adm_data_v2.device[dev_idx]));
+ memset(&rtac_adm_data_v2.device[dev_idx + 1], 0,
+ sizeof(rtac_adm_data_v2.device[dev_idx]));
+ }
+}
+
+static void shift_popp_v2(u32 copp_idx, u32 popp_idx)
+{
+ for (; popp_idx < rtac_adm_data_v2.device[copp_idx].num_of_popp;
+ popp_idx++) {
+ memcpy(&rtac_adm_data_v2.device[copp_idx].popp[popp_idx].popp,
+ &rtac_adm_data_v2.device[copp_idx].popp[popp_idx + 1].
+ popp, sizeof(uint32_t));
+ memcpy(&rtac_adm_data_v2.device[copp_idx].popp[popp_idx].
+ popp_topology,
+ &rtac_adm_data_v2.device[copp_idx].popp[popp_idx + 1].
+ popp_topology,
+ sizeof(uint32_t));
+ memset(&rtac_adm_data_v2.device[copp_idx].popp[popp_idx + 1].
+ popp, 0, sizeof(uint32_t));
+ memset(&rtac_adm_data_v2.device[copp_idx].popp[popp_idx + 1].
+ popp_topology, 0, sizeof(uint32_t));
+ }
+}
+
+static void rtac_remove_adm_device_v2(u32 port_id)
+{
+ s32 i;
+ pr_debug("%s: port_id = %d\n", __func__, port_id);
+
+ /* look for device */
+ for (i = 0; i < rtac_adm_data_v2.num_of_dev; i++) {
+ if (rtac_adm_data_v2.device[i].afe_port == port_id) {
+ memset(&rtac_adm_data_v2.device[i], 0,
+ sizeof(rtac_adm_data_v2.device[i]));
+ rtac_adm_data_v2.num_of_dev--;
+
+ if (rtac_adm_data_v2.num_of_dev >= 1) {
+ shift_adm_devices_v2(i);
+ break;
+ }
+ }
+ }
+ return;
+}
+
+static void rtac_remove_popp_from_adm_devices_v2(u32 popp_id)
+{
+ s32 i, j;
+ pr_debug("%s: popp_id = %d\n", __func__, popp_id);
+
+ for (i = 0; i < rtac_adm_data_v2.num_of_dev; i++) {
+ for (j = 0; j < rtac_adm_data_v2.device[i].num_of_popp; j++) {
+ if (rtac_adm_data_v2.device[i].popp[j].popp ==
+ popp_id) {
+ rtac_adm_data_v2.device[i].popp[j].popp = 0;
+ rtac_adm_data_v2.device[i].popp[j].
+ popp_topology = 0;
+ rtac_adm_data_v2.device[i].num_of_popp--;
+ shift_popp_v2(i, j);
+ }
+ }
+ }
+}
+
/* ADM Info */
void add_popp(u32 dev_idx, u32 port_id, u32 popp_id)
{
@@ -383,6 +546,8 @@
popp_id);
mutex_lock(&rtac_adm_mutex);
+ rtac_add_adm_device_v2(port_id, copp_id, path_id, popp_id);
+
if (rtac_adm_data.num_of_dev == RTAC_MAX_ACTIVE_DEVICES) {
pr_err("%s, Can't add anymore RTAC devices!\n", __func__);
goto done;
@@ -391,7 +556,8 @@
/* Check if device already added */
if (rtac_adm_data.num_of_dev != 0) {
for (; i < rtac_adm_data.num_of_dev; i++) {
- if (rtac_adm_data.device[i].afe_port == port_id) {
+ if (rtac_adm_data.device[i].afe_port == port_id &&
+ rtac_adm_data.device[i].copp == copp_id) {
add_popp(i, port_id, popp_id);
goto done;
}
@@ -440,19 +606,22 @@
&rtac_adm_data.device[copp_idx].popp[popp_idx + 1],
sizeof(uint32_t));
memset(&rtac_adm_data.device[copp_idx].popp[popp_idx + 1], 0,
- sizeof(uint32_t));
+ sizeof(uint32_t));
}
}
-void rtac_remove_adm_device(u32 port_id)
+void rtac_remove_adm_device(u32 port_id, u32 copp_id)
{
s32 i;
pr_debug("%s: port_id = %d\n", __func__, port_id);
mutex_lock(&rtac_adm_mutex);
+ rtac_remove_adm_device_v2(port_id);
+
/* look for device */
for (i = 0; i < rtac_adm_data.num_of_dev; i++) {
- if (rtac_adm_data.device[i].afe_port == port_id) {
+ if (rtac_adm_data.device[i].afe_port == port_id &&
+ rtac_adm_data.device[i].copp == copp_id) {
memset(&rtac_adm_data.device[i], 0,
sizeof(rtac_adm_data.device[i]));
rtac_adm_data.num_of_dev--;
@@ -474,6 +643,7 @@
pr_debug("%s: popp_id = %d\n", __func__, popp_id);
mutex_lock(&rtac_adm_mutex);
+ rtac_remove_popp_from_adm_devices_v2(popp_id);
for (i = 0; i < rtac_adm_data.num_of_dev; i++) {
for (j = 0; j < rtac_adm_data.device[i].num_of_popp; j++) {
@@ -702,6 +872,8 @@
for (port_index = 0; port_index < AFE_MAX_PORTS; port_index++) {
if (adm_get_copp_id(port_index) == copp_id)
break;
+ if (adm_get_lowlatency_copp_id(port_index) == copp_id)
+ break;
}
if (port_index >= AFE_MAX_PORTS) {
pr_err("%s: Could not find port index for copp = %d\n",
@@ -1269,6 +1441,13 @@
else
result = sizeof(rtac_adm_data);
break;
+ case AUDIO_GET_RTAC_ADM_INFO_V2:
+ if (copy_to_user((void *)arg, &rtac_adm_data_v2,
+ sizeof(rtac_adm_data_v2)))
+ pr_err("%s: Could not copy to userspace!\n", __func__);
+ else
+ result = sizeof(rtac_adm_data_v2);
+ break;
case AUDIO_GET_RTAC_VOICE_INFO:
if (copy_to_user((void *)arg, &rtac_voice_data,
sizeof(rtac_voice_data)))
@@ -1339,6 +1518,7 @@
/* ADM */
memset(&rtac_adm_data, 0, sizeof(rtac_adm_data));
+ memset(&rtac_adm_data_v2, 0, sizeof(rtac_adm_data_v2));
rtac_adm_apr_data.apr_handle = NULL;
atomic_set(&rtac_adm_apr_data.cmd_state, 0);
init_waitqueue_head(&rtac_adm_apr_data.cmd_wait);
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index 58b8399..b9af9b6 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -756,6 +756,14 @@
rtd->compr = compr;
compr->private_data = rtd;
+ if (platform->driver->pcm_new) {
+ ret = platform->driver->pcm_new(rtd);
+ if (ret < 0) {
+ pr_err("asoc: compress pcm constructor failed\n");
+ goto compr_err;
+ }
+ }
+
printk(KERN_INFO "compress asoc: %s <-> %s mapping ok\n", codec_dai->name,
cpu_dai->name);
return ret;
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 2cb3576..021d731 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -3240,7 +3240,7 @@
mutex_init(&card->mutex);
mutex_init(&card->dpcm_mutex);
mutex_init(&card->dapm_power_mutex);
-
+ mutex_init(&card->dapm_mutex);
ret = snd_soc_instantiate_card(card);
if (ret != 0) {
soc_cleanup_card_debugfs(card);
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 99047178..63bbbdd 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -1866,7 +1866,7 @@
#endif
/* test and update the power status of a mux widget */
-int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
+static int soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
struct snd_kcontrol *kcontrol, int change,
int mux, struct soc_enum *e)
{
@@ -1915,10 +1915,22 @@
return 0;
}
+
+int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
+ struct snd_kcontrol *kcontrol, int change,
+ int mux, struct soc_enum *e)
+{
+ struct snd_soc_card *card = widget->dapm->card;
+ int ret;
+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
+ ret = soc_dapm_mux_update_power(widget, kcontrol, change, mux, e);
+ mutex_unlock(&card->dapm_mutex);
+ return ret;
+}
EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);
/* test and update the power status of a mixer or switch widget */
-int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
+static int soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
struct snd_kcontrol *kcontrol, int connect)
{
struct snd_soc_dapm_path *path;
@@ -1952,6 +1964,17 @@
return 0;
}
+
+int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
+ struct snd_kcontrol *kcontrol, int connect)
+{
+ struct snd_soc_card *card = widget->dapm->card;
+ int ret;
+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
+ ret = soc_dapm_mixer_update_power(widget, kcontrol, connect);
+ mutex_unlock(&card->dapm_mutex);
+ return ret;
+}
EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power);
/* show dapm widget status in sys fs */
@@ -2108,6 +2131,8 @@
*/
int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
{
+ int ret;
+
/*
* Suppress early reports (eg, jacks syncing their state) to avoid
* silly DAPM runs during card startup.
@@ -2115,7 +2140,10 @@
if (!dapm->card || !dapm->card->instantiated)
return 0;
- return dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
+ mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
+ ret = dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
+ mutex_unlock(&dapm->card->dapm_mutex);
+ return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
@@ -2279,6 +2307,7 @@
{
int i, ret;
+ mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
for (i = 0; i < num; i++) {
ret = snd_soc_dapm_add_route(dapm, route);
if (ret < 0) {
@@ -2288,6 +2317,7 @@
}
route++;
}
+ mutex_unlock(&dapm->card->dapm_mutex);
return 0;
}
@@ -2360,12 +2390,14 @@
int i, err;
int ret = 0;
+ mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
for (i = 0; i < num; i++) {
err = snd_soc_dapm_weak_route(dapm, route);
if (err)
ret = err;
route++;
}
+ mutex_unlock(&dapm->card->dapm_mutex);
return ret;
}
@@ -2384,6 +2416,8 @@
struct snd_soc_dapm_widget *w;
unsigned int val;
+ mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
+
list_for_each_entry(w, &dapm->card->widgets, list)
{
if (w->new)
@@ -2393,8 +2427,10 @@
w->kcontrols = kzalloc(w->num_kcontrols *
sizeof(struct snd_kcontrol *),
GFP_KERNEL);
- if (!w->kcontrols)
+ if (!w->kcontrols) {
+ mutex_unlock(&dapm->card->dapm_mutex);
return -ENOMEM;
+ }
}
switch(w->id) {
@@ -2434,6 +2470,7 @@
}
dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
+ mutex_unlock(&dapm->card->dapm_mutex);
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
@@ -2493,6 +2530,7 @@
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
struct snd_soc_codec *codec = widget->codec;
+ struct snd_soc_card *card = codec->card;
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
unsigned int reg = mc->reg;
@@ -2519,7 +2557,7 @@
/* old connection must be powered down */
connect = invert ? 1 : 0;
- mutex_lock(&codec->mutex);
+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
change = snd_soc_test_bits(widget->codec, reg, mask, val);
if (change) {
@@ -2535,13 +2573,13 @@
update.val = val;
widget->dapm->update = &update;
- snd_soc_dapm_mixer_update_power(widget, kcontrol, connect);
+ soc_dapm_mixer_update_power(widget, kcontrol, connect);
widget->dapm->update = NULL;
}
}
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&card->dapm_mutex);
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
@@ -2590,6 +2628,7 @@
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
struct snd_soc_codec *codec = widget->codec;
+ struct snd_soc_card *card = codec->card;
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int val, mux, change;
unsigned int mask, bitmask;
@@ -2610,7 +2649,7 @@
mask |= (bitmask - 1) << e->shift_r;
}
- mutex_lock(&codec->mutex);
+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
if (change) {
@@ -2626,13 +2665,13 @@
update.val = val;
widget->dapm->update = &update;
- snd_soc_dapm_mux_update_power(widget, kcontrol, change, mux, e);
+ soc_dapm_mux_update_power(widget, kcontrol, change, mux, e);
widget->dapm->update = NULL;
}
}
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&card->dapm_mutex);
return change;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
@@ -2669,6 +2708,7 @@
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
struct snd_soc_codec *codec = widget->codec;
+ struct snd_soc_card *card = codec->card;
struct soc_enum *e =
(struct soc_enum *)kcontrol->private_value;
int change;
@@ -2678,7 +2718,7 @@
if (ucontrol->value.enumerated.item[0] >= e->max)
return -EINVAL;
- mutex_lock(&codec->mutex);
+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
change = widget->value != ucontrol->value.enumerated.item[0];
if (change) {
@@ -2687,12 +2727,12 @@
widget->value = ucontrol->value.enumerated.item[0];
- snd_soc_dapm_mux_update_power(widget, kcontrol, change,
+ soc_dapm_mux_update_power(widget, kcontrol, change,
widget->value, e);
}
}
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&card->dapm_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt);
@@ -2757,6 +2797,7 @@
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
struct snd_soc_codec *codec = widget->codec;
+ struct snd_soc_card *card = codec->card;
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int val, mux, change;
unsigned int mask;
@@ -2775,7 +2816,7 @@
mask |= e->mask << e->shift_r;
}
- mutex_lock(&codec->mutex);
+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
if (change) {
@@ -2791,13 +2832,13 @@
update.val = val;
widget->dapm->update = &update;
- snd_soc_dapm_mux_update_power(widget, kcontrol, change, mux, e);
+ soc_dapm_mux_update_power(widget, kcontrol, change, mux, e);
widget->dapm->update = NULL;
}
}
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&card->dapm_mutex);
return change;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double);
@@ -2831,15 +2872,15 @@
int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
const char *pin = (const char *)kcontrol->private_value;
- mutex_lock(&codec->mutex);
+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
ucontrol->value.integer.value[0] =
- snd_soc_dapm_get_pin_status(&codec->dapm, pin);
+ snd_soc_dapm_get_pin_status(&card->dapm, pin);
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&card->dapm_mutex);
return 0;
}
@@ -2854,20 +2895,19 @@
int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
const char *pin = (const char *)kcontrol->private_value;
- mutex_lock(&codec->mutex);
+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
if (ucontrol->value.integer.value[0])
- snd_soc_dapm_enable_pin(&codec->dapm, pin);
+ snd_soc_dapm_enable_pin(&card->dapm, pin);
else
- snd_soc_dapm_disable_pin(&codec->dapm, pin);
+ snd_soc_dapm_disable_pin(&card->dapm, pin);
- snd_soc_dapm_sync(&codec->dapm);
+ mutex_unlock(&card->dapm_mutex);
- mutex_unlock(&codec->mutex);
-
+ snd_soc_dapm_sync(&card->dapm);
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch);
@@ -2975,6 +3015,7 @@
{
int i, ret;
+ mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
for (i = 0; i < num; i++) {
ret = snd_soc_dapm_new_control(dapm, widget);
if (ret < 0) {
@@ -2985,6 +3026,7 @@
}
widget++;
}
+ mutex_unlock(&dapm->card->dapm_mutex);
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
@@ -3099,7 +3141,6 @@
mutex_lock(&codec->mutex);
soc_dapm_stream_event(&codec->dapm, stream, event);
mutex_unlock(&codec->mutex);
-
return 0;
}
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
index 9eb96e5..60a401a 100644
--- a/sound/soc/soc-jack.c
+++ b/sound/soc/soc-jack.c
@@ -36,6 +36,7 @@
int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type,
struct snd_soc_jack *jack)
{
+ mutex_init(&jack->mutex);
jack->codec = codec;
INIT_LIST_HEAD(&jack->pins);
INIT_LIST_HEAD(&jack->jack_zones);
@@ -75,7 +76,7 @@
codec = jack->codec;
dapm = &codec->dapm;
- mutex_lock(&codec->mutex);
+ mutex_lock(&jack->mutex);
oldstatus = jack->status;
@@ -109,7 +110,7 @@
snd_jack_report(jack->jack, jack->status);
out:
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&jack->mutex);
}
EXPORT_SYMBOL_GPL(snd_soc_jack_report);
diff --git a/sound/usb/card.c b/sound/usb/card.c
index f453dbd..d419e2f 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -205,11 +205,24 @@
struct usb_device *dev = chip->dev;
struct usb_host_interface *host_iface;
struct usb_interface_descriptor *altsd;
+ struct usb_interface *usb_iface;
void *control_header;
int i, protocol;
+ usb_iface = usb_ifnum_to_if(dev, ctrlif);
+ if (!usb_iface) {
+ snd_printk(KERN_ERR "%d:%u : does not exist\n",
+ dev->devnum, ctrlif);
+ return -EINVAL;
+ }
+
/* find audiocontrol interface */
- host_iface = &usb_ifnum_to_if(dev, ctrlif)->altsetting[0];
+ host_iface = &usb_iface->altsetting[0];
+ if (!host_iface) {
+ snd_printk(KERN_ERR "Audio Control interface is not available.");
+ return -EINVAL;
+ }
+
control_header = snd_usb_find_csint_desc(host_iface->extra,
host_iface->extralen,
NULL, UAC_HEADER);
@@ -248,8 +261,7 @@
case UAC_VERSION_2: {
struct usb_interface_assoc_descriptor *assoc =
- usb_ifnum_to_if(dev, ctrlif)->intf_assoc;
-
+ usb_iface->intf_assoc;
if (!assoc) {
snd_printk(KERN_ERR "Audio class v2 interfaces need an interface association\n");
return -EINVAL;
@@ -723,6 +735,11 @@
}
usbaudiosdev = kzalloc(sizeof(*usbaudiosdev), GFP_KERNEL);
+ if (!usbaudiosdev) {
+ pr_err("Usb audio device memory allocation failed.\n");
+ return -ENOMEM;
+ }
+
usbaudiosdev->name = "usb_audio";
err = switch_dev_register(usbaudiosdev);