Merge "ion: iommu: Add support for 2MB chunk allocation in IOMMU"
diff --git a/Documentation/arm/msm/msm_ipc_logging.txt b/Documentation/arm/msm/msm_ipc_logging.txt
new file mode 100644
index 0000000..cb330b0
--- /dev/null
+++ b/Documentation/arm/msm/msm_ipc_logging.txt
@@ -0,0 +1,323 @@
+Introduction
+============
+
+This module will be used to log the events by any module/driver which
+enables Inter Processor Communication (IPC). Some of the IPC drivers such
+as Message Routers, Multiplexers etc. which act as a passive pipe need
+some mechanism to log their events. Since all such IPC drivers handle a
+large amount of traffic/events, using kernel logs renders kernel logs
+unusable by other drivers and also degrades the performance of IPC
+drivers. This new module will help in logging such high frequency IPC
+driver events while keeping the standard kernel logging mechanism
+intact.
+
+Hardware description
+====================
+
+This module does not drive any hardware resource and will only use the
+kernel memory-space to log the events.
+
+Software description
+====================
+
+Design Goals
+------------
+This module is designed to
+ * support logging for drivers handling large amount of
+ traffic/events
+ * define & differentiate events/logs from different drivers
+ * support both id-based and stream-based logging
+ * support extracting the logs from both live target & memory dump
+
+IPC Log Context
+----------------
+
+This module will support logging by multiple drivers. To differentiate
+between the multiple drivers that are using this logging mechanism, each
+driver will be assigned a unique context by this module. Associated with
+each context is the logging space, dynamically allocated from the kernel
+memory-space, specific to that context so that the events logged using that
+context will not interfere with other contexts.
+
+Event Logging
+--------------
+
+Every event will be logged as a <Type: Size: Value> combination. Type
+field identifies the type of the event that is logged. Size field represents
+the size of the log information. Value field represents the actual
+information being logged. This approach will support both id-based logging
+and stream-based logging. This approach will also support logging sub-events
+of an event. This module will provide helper routines to encode/decode the
+logs to/from this format.
+
+Encode Context
+---------------
+
+Encode context is a temporary storage space that will be used by the client
+drivers to log the events in <Type: Size: Value> format. The client drivers
+will perform an encode start operation to initialize the encode context
+data structure. Then the client drivers will log their events into the
+encode context. Upon completion of event logging, the client drivers will
+perform an encode end operation to finalize the encode context data
+structure to be logged. Then this updated encode context data structure
+will be written into the client driver's IPC Log Context. The maximum
+event log size will be defined as 256 bytes.
+
+Log Space
+----------
+
+Each context will have an associated log space, which is dynamically
+allocated from the kernel memory-space. The log space is organized as a
+list of kernel memory pages. Each page contains header information which
+is used to differentiate the log kernel page from the other kernel pages.
+
+ 0 ---------------------------------
+ | magic_no = 0x52784425 |
+ ---------------------------------
+ | nmagic_no = 0xAD87BBDA |
+ ---------------------------------
+ | log_id |
+ ---------------------------------
+ | page_num |
+ ---------------------------------
+ | read_offset | write_offset |
+ ---------------------------------
+ | next/prev page |
+ ---------------------------------
+ | |
+ | Data |
+ | . |
+ | . |
+ | . |
+ | |
+ --------------------------------- PAGE_SIZE - 1
+
+This approach will support extracting the logs either from the memory dumps
+or from the live targets using DEBUGFS.
+
+Design
+======
+
+Alternate solutions discussed include using kernel & SMEM logs which are
+limited in size and hence using them render them unusable by other drivers.
+Also kernel logging into serial console is slowing down the performance of
+the drivers by multiple times and sometimes lead to APPs watchdog bite.
+
+Power Management
+================
+
+Not-Applicable
+
+SMP/multi-core
+==============
+
+This module uses spinlocks & mutexes to handle multi-core safety.
+
+Security
+========
+
+Not-Applicable
+
+Performance
+===========
+
+This logging mechanism, based on experimental data, is not expected to
+cause a significant performance degradation. Under worst case, it can
+cause 1 - 2 percent degradation in the throughput of the IPC Drivers.
+
+Interface
+=========
+
+Exported Data Structures
+------------------------
+struct encode_context {
+ struct tsv_header hdr;
+ char buff[MAX_MSG_SIZE];
+ int offset;
+};
+
+struct decode_context {
+ int output_format;
+ char *buff;
+ int size;
+};
+
+Kernel-Space Interface APIs
+----------------------------
+/*
+ * ipc_log_context_create: Create a ipc log context
+ *
+ * @max_num_pages: Number of pages of logging space required (max. 10)
+ * @mod_name : Name of the directory entry under DEBUGFS
+ *
+ * returns reference to context on success, NULL on failure
+ */
+void * ipc_log_context_create(int max_num_pages,
+ const char *mod_name);
+
+/*
+ * msg_encode_start: Start encoding a log message
+ *
+ * @ectxt: Temporary storage to hold the encoded message
+ * @type: Root event type defined by the module which is logging
+ */
+void msg_encode_start(struct encode_context *ectxt, uint32_t type);
+
+/*
+ * msg_encode_end: Complete the message encode process
+ *
+ * @ectxt: Temporary storage which holds the encoded message
+ */
+void msg_encode_end(struct encode_context *ectxt);
+
+/*
+ * tsv_timestamp_write: Writes the current timestamp count
+ *
+ * @ectxt: Context initialized by calling msg_encode_start()
+ *
+ * Returns 0 on success, -ve error code on failure
+ */
+int tsv_timestamp_write(struct encode_context *ectxt);
+
+/*
+ * tsv_pointer_write: Writes a data pointer
+ *
+ * @ectxt: Context initialized by calling msg_encode_start()
+ * @pointer: Pointer value to write
+ *
+ * Returns 0 on success, -ve error code on failure
+ */
+int tsv_pointer_write(struct encode_context *ectxt, void *pointer);
+
+/*
+ * tsv_int32_write: Writes a 32-bit integer value
+ *
+ * @ectxt: Context initialized by calling msg_encode_start()
+ * @n: Integer to write
+ *
+ * Returns 0 on success, -ve error code on failure
+ */
+int tsv_int32_write(struct encode_context *ectxt, int32_t n);
+
+/*
+ * tsv_byte_array_write: Writes a byte array
+ *
+ * @ectxt: Context initialized by calling msg_encode_start()
+ * @data: Location of data
+ * @data_size: Size of data to be written
+ *
+ * Returns 0 on success, -ve error code on failure
+ */
+int tsv_byte_array_write(struct encode_context *ectxt,
+ void *data, int data_size);
+
+/*
+ * ipc_log_write: Write the encoded message into the log space
+ *
+ * @ctxt: IPC log context where the message has to be logged into
+ * @ectxt: Temporary storage containing the encoded message
+ */
+void ipc_log_write(unsigned long ctxt, struct encode_context *ectxt);
+
+/*
+ * ipc_log_string: Helper function to log a string
+ *
+ * @dlctxt: IPC Log Context created using ipc_log_context_create()
+ * @fmt: Data specified using format specifiers
+ */
+int ipc_log_string(unsigned long dlctxt, const char *fmt, ...);
+
+/*
+ * tsv_timestamp_read: Reads a timestamp
+ *
+ * @ectxt: Context retrieved by reading from log space
+ * @dctxt: Temporary storage to hold the decoded message
+ * @format: Output format while dumping through DEBUGFS
+ */
+void tsv_timestamp_read(struct encode_context *ectxt,
+ struct decode_context *dctxt, const char *format);
+
+/*
+ * tsv_pointer_read: Reads a data pointer
+ *
+ * @ectxt: Context retrieved by reading from log space
+ * @dctxt: Temporary storage to hold the decoded message
+ * @format: Output format while dumping through DEBUGFS
+ */
+void tsv_pointer_read(struct encode_context *ectxt,
+ struct decode_context *dctxt, const char *format);
+
+/*
+ * tsv_int32_read: Reads a 32-bit integer value
+ *
+ * @ectxt: Context retrieved by reading from log space
+ * @dctxt: Temporary storage to hold the decoded message
+ * @format: Output format while dumping through DEBUGFS
+ */
+void tsv_int32_read(struct encode_context *ectxt,
+ struct decode_context *dctxt, const char *format);
+
+/*
+ * tsv_byte_array_read: Reads a byte array/string
+ *
+ * @ectxt: Context retrieved by reading from log space
+ * @dctxt: Temporary storage to hold the decoded message
+ * @format: Output format while dumping through DEBUGFS
+ */
+void tsv_byte_array_read(struct encode_context *ectxt,
+ struct decode_context *dctxt, const char *format);
+
+/*
+ * add_deserialization_func: Register a deserialization function to
+ * to unpack the subevents of a main event
+ *
+ * @ctxt: IPC log context to which the deserialization function has
+ * to be registered
+ * @type: Main/Root event, defined by the module which is logging, to
+ * which this deserialization function has to be registered.
+ * @dfune: Deserialization function to be registered
+ *
+ * return 0 on success, -ve value on FAILURE
+ */
+int add_deserialization_func(unsigned long ctxt, int type,
+ void (*dfunc)(struct encode_context *,
+ struct decode_context *));
+
+Driver parameters
+=================
+
+Not-Applicable
+
+Config options
+==============
+
+Not-Applicable
+
+Dependencies
+============
+
+This module will partially depend on CONFIG_DEBUGFS, in order to dump the
+logs through debugfs. If CONFIG_DEBUGFS is disabled, the above mentioned
+helper functions will perform no operation and return appropriate error
+code if the return value is non void. Under such circumstances the logs can
+only be extracted through the memory dump.
+
+User space utilities
+====================
+
+DEBUGFS
+
+Other
+=====
+
+Not-Applicable
+
+Known issues
+============
+
+None
+
+To do
+=====
+
+None
diff --git a/Documentation/devicetree/bindings/arm/msm/board-id.txt b/Documentation/devicetree/bindings/arm/msm/board-id.txt
new file mode 100644
index 0000000..c29a2d2
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/board-id.txt
@@ -0,0 +1,18 @@
+* BOARD-ID
+
+The qcom,board-id entry specifies the MSM platform and subtype revision.
+It can optionally be an array of these to indicate multiple hardware that use
+the same device tree. It is expected that the bootloader will use this
+information at boot-up to decide which device tree to use when given multiple
+device trees, some of which may not be compatible with the actual hardware. It
+is the bootloader's responsibility to pass the correct device tree to the kernel.
+
+Format:
+
+It is expected that the qcom,board-id entry be at the top level of the device
+tree structure. The format of the entry is:
+
+ qcom,board-id = <platform_id, subtype_id> [, <p2, s2> ...]
+
+Example:
+ qcom,board-id = <15 0>;
diff --git a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
index 04310ec..b489f7a 100644
--- a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
+++ b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
@@ -13,21 +13,17 @@
Required properties:
- compatible: Must be "qcom,cpr-regulator"
- reg: Register addresses for RBCPR, RBCPR clock
- select, PVS eFuse and CPR eFuse
+ select, PVS and CPR eFuse address
- reg-names: Register names. Must be "rbcpr", "rbcpr_clk",
- "pvs_efuse" and "cpr_efuse"
+ "efuse_addr"
- regulator-name: A string used to describe the regulator
- interrupts: Interrupt line from RBCPR to interrupt controller.
- regulator-min-microvolt: Minimum corner value as min constraint, which
should be 1 for SVS corner
- regulator-max-microvolt: Maximum corner value as max constraint, which
should be 4 for SUPER_TURBO or 3 for TURBO
-- qcom,num-efuse-bits: The number of bits used in efuse memory to
- represent total number of PVS bins. It should
- not exceed a maximum of 5 for total number of
- 32 bins.
- qcom,pvs-bin-process: A list of integers whose length is equal to 2 to
- the power of qcom,num-efuse-bits. The location or
+ the power of qcom,pvs-fuse[num-of-bits]. The location or
0-based index of an element in the list corresponds
to the bin number. The value of each integer
corresponds to the PVS process speed of the APC
@@ -54,7 +50,7 @@
- qcom,cpr-timer-cons-down: Consecutive number of timer interval (qcom,cpr-timer-delay)
occurred before issuing DOWN interrupt.
- qcom,cpr-irq-line: Internal interrupt route signal of RBCPR, one of 0, 1 or 2.
-- qcom,cpr-step-quotient: Number of CPR quotient (RO count) per vdd-apc-supply step
+- qcom,cpr-step-quotient: Number of CPR quotient (Ring Oscillator(RO) count) per vdd-apc-supply step
to issue error_steps.
- qcom,cpr-up-threshold: The threshold for CPR to issue interrupt when
error_steps is greater than it when stepping up.
@@ -64,6 +60,62 @@
- 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
+ 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:
+ [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
+ 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:
+ [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.
+ 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
+ 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:
+ [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
+ 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
+- 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.
+ It should have index and value like this:
+ [0] => bit position of the LSB bit for SVS target quotient
+ [1] => bit position of the LSB bit for NOMINAL target quotient
+ [2] => bit position of the LSB bit for TURBO target quotient
+- qcom,cpr-fuse-ro-sel: Array of bit positions in fuse for RO select of all corners.
+ It should have index and value like this:
+ [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-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
+ [1] => bit position of the LSB bit for redundant NOMINAL target quotient
+ [2] => bit position of the LSB bit for redundant TURBO target quotient
+- qcom,cpr-fuse-redun-ro-sel: Array of bit positions in eFuse for redundant RO select.
+ It should have index and value like this:
+ [0] => bit position of the LSB bit for redundant SVS RO select bits
+ [1] => bit position of the LSB bit for redundant NOMINAL RO select bits
+ [2] => bit position of the LSB bit for redundant TURBO RO select bits
+
Optional properties:
- vdd-mx-supply: Regulator to supply memory power as dependency
@@ -78,6 +130,10 @@
2 => equal to slow speed corner ceiling
3 => equal to qcom,vdd-mx-vmax
This is required when vdd-mx-supply is present.
+- qcom,cpr-fuse-redun-bp-cpr-disable: Redundant bit position of the bit to indicate if CPR should be disable
+- qcom,cpr-fuse-redun-bp-scheme: Redundant bit position of the bit to indicate if it's a global/local scheme
+ This property is required if cpr-fuse-redun-bp-cpr-disable
+ is present, and vise versa.
- qcom,cpr-enable: Present: CPR enabled by default.
Not Present: CPR disable by default.
@@ -86,13 +142,17 @@
apc_vreg_corner: regulator@f9018000 {
status = "okay";
compatible = "qcom,cpr-regulator";
- reg = <0xf9018000 0x1000>, <0xfc4b80b0 8>, <0xfc4bc450 16>;
- reg-names = "rbcpr", "pvs_efuse", "cpr_efuse";
+ reg = <0xf9018000 0x1000>, <0xfc4b8000 0x1000>;
+ reg-names = "rbcpr", "efuse_addr";
interrupts = <0 15 0>;
regulator-name = "apc_corner";
regulator-min-microvolt = <1>;
regulator-max-microvolt = <3>;
- qcom,num-efuse-bits = <5>;
+
+ qcom,pvs-fuse = <22 6 5>;
+ qcom,pvs-fuse-redun-sel = <22 24 3 2>;
+ qcom,pvs-fuse-redun = <22 27 5>;
+
qcom,pvs-bin-process = <0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 2
2 2 2 2 3 3 3 3 3 3 3 3 0 0 0 0>;
qcom,pvs-corner-ceiling-slow = <1050000 1160000 1275000>;
@@ -115,5 +175,15 @@
qcom,cpr-idle-clocks = <5>;
qcom,cpr-gcnt-time = <1>;
qcom,cpr-apc-volt-step = <5000>;
+
+ qcom,cpr-fuse-row = <138>;
+ 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-target-quot = <24 12 0>;
+ qcom,cpr-fuse-redun-ro-sel = <46 36 39>;
};
diff --git a/Documentation/devicetree/bindings/arm/msm/jtag-fuse.txt b/Documentation/devicetree/bindings/arm/msm/jtag-fuse.txt
new file mode 100644
index 0000000..617d2ba
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/jtag-fuse.txt
@@ -0,0 +1,18 @@
+* JTAG-FUSE
+
+The jtag-fuse entry specifies the memory mapped addresses for the fuse
+registers. The jtag-fuse driver uses these to provide api(s) that can be used
+by jtag save and restore driver(s) to query whether the Hardware they manage
+is functionally disabled or not and take corresponding steps.
+
+Required Properties:
+compatible: component name used for driver matching, should be "qcom,jtag-fuse"
+reg: physical base address and length of the register set
+reg-names: should be "fuse-base"
+
+Example:
+ jtag_fuse: jtagfuse@fc4be024 {
+ compatible = "qcom,jtag-fuse";
+ reg = <0xfc4be024 0x8>;
+ reg-names = "fuse-base";
+ };
diff --git a/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
index 195a98d..f57d928 100644
--- a/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
+++ b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
@@ -3,10 +3,8 @@
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 a combination of low power modes of different resources -
-L2, XO, Vdd Dig and Vdd Mem. The combination is captured in the device tree as
-lpm-level. The units for voltage are dependent on the PMIC used on the target
-and are in uV.
+the system can do several low power modes. The combination is captured in the
+device tree as lpm-level.
The required nodes for lpm-levels are:
@@ -20,20 +18,11 @@
"retention" - Retention
"pc_suspend" - Suspended Power Collapse
"pc_no_xo_shutdown" - Power Collapse with no XO shutdown
-- qcom,xo: The state of XO clock. Values are "xo_on" and "xo_off"
- qcom,l2: The state of L2 cache. Values are:
"l2_cache_pc" - L2 cache in power collapse
"l2_cache_retenetion" - L2 cache in retention
"l2_cache_gdhs" - L2 cache in GDHS
"l2_cache_active" - L2 cache in active mode
-- qcom,vdd-mem-upper-bound: The upper bound value of mem voltage in uV
-- qcom,vdd-mem-lower-bound: The lower bound value of mem voltage in uV
-- qcom,vdd-dig-upper-bound: The upper bound value of dig voltage in uV
- or an RBCPR (Rapid Bridge Core Power Reduction)
- corner voltage.
-- qcom,vdd-dig-lower-bound: The lower bound value of dig voltage in uV
- or an RBCPR (Rapid Bridge Core Power Reduction)
- corner voltage.
- 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
@@ -42,29 +31,18 @@
in mWatts.uSec
- qcom,time-overhead: The time spent in entering and exiting this level in uS
-Optional properties
-- qcom,irqs-detectable: The field indicates whether the IRQs are detectable by
- the GIC controller when entering a low power mode.
-- qcom,gpio-detectable: The field indicates whether the GPIOs can be detected
- by the GPIO interrupt controller during a given low
- power mode.
-- qcom,use-qtimer: Indicates whether the target uses the synchronized QTimer.
+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.
Example:
qcom,lpm-levels {
- qcom,use-qtimer;
+ qcom,no-l2-saw;
qcom,lpm-level@0 {
reg = <0>;
qcom,mode = "wfi";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_active";
- qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
- qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
- qcom,vdd-dig-upper-bound = <5>; /* MAX */
- qcom,vdd-dig-lower-bound = <3>; /* ACTIVE */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
qcom,latency-us = <100>;
qcom,ss-power = <650>;
qcom,energy-overhead = <801>;
diff --git a/Documentation/devicetree/bindings/arm/msm/lpm-resources.txt b/Documentation/devicetree/bindings/arm/msm/lpm-resources.txt
deleted file mode 100644
index 7b5fda3..0000000
--- a/Documentation/devicetree/bindings/arm/msm/lpm-resources.txt
+++ /dev/null
@@ -1,47 +0,0 @@
-* Low Power Management Resources
-
-The application processor in the MSM can enter several different low power
-states depending on the sleep time and on the required system resources. The
-MSM cannot enter a given low power state if that state involves turning off
-some shared resources which are required by some components of the
-system.The lpm-resources device tree node represents the shared resources
-that need to be monitored for usage requirement to check if a given low power
-state can be entered.Each resource is identified by a combination of the name,
-id,type and key which is also used by the RPM to identify a shared resource.
-The name and resource-type are required nodes; the type, id and key are
-optional nodes which are needed if the resource type is RPM shared resource
-(MSM_LPM_RPM_RS_TYPE).
-
-The nodes for lpm-resources are:
-
-Required Nodes:
-
-- compatible: "qcom,lpm-resources"
-- reg: The numeric level id
-- qcom,name: The name of the low power resource represented
- as a string.
-- qcom,init-value: Initialization value of the LPM resource represented as
- decimal value for vdd-dig and vdd-mem resources and
- as string for pxo and l2 resources.
-
-
-Optional Nodes:
-
-- qcom,type: The type of resource used like smps or pxo
- represented as a hex value.
-- qcom,id: The id representing a device within a resource type.
-- qcom,key: The key is the specific attribute of the resource being
- monitored represented as a hex value.
-- qcom,local-resource-type: The property exists only for locally managed
- resource and is represented as a bool.
-
-Example:
- qcom,lpm-resources@0 {
- reg = <0x0>;
- qcom,name = "vdd-dig";
- qcom,type = <0x62706d73>; /* "smpb" */
- qcom,id = <0x02>;
- qcom,key = <0x6e726f63>; /* "corn" */
- qcom,init-value= <5>; /* Active Corner*/
- };
-
diff --git a/Documentation/devicetree/bindings/arm/msm/memory-reserve.txt b/Documentation/devicetree/bindings/arm/msm/memory-reserve.txt
index 6dac1b7..bf5e544 100644
--- a/Documentation/devicetree/bindings/arm/msm/memory-reserve.txt
+++ b/Documentation/devicetree/bindings/arm/msm/memory-reserve.txt
@@ -26,12 +26,13 @@
add the appropriate binding:
Required parameters:
-- qcom,memblock-remove: base and size of block to be removed
+- qcom,memblock-remove: array of the base and size of blocks to be removed
qcom,a-driver {
compatible = "qcom,a-driver";
- /* Remove 4MB at 0x200000*/
- qcom,memblock-remove = <0x200000 0x400000>;
+ /* Remove 4MB at 0x200000 and 2MB at 0x800000*/
+ qcom,memblock-remove = <0x200000 0x400000
+ 0x800000 0x200000>;
};
In order to ensure memory is only reserved when a driver is actually enabled,
diff --git a/Documentation/devicetree/bindings/arm/msm/msm-id.txt b/Documentation/devicetree/bindings/arm/msm/msm-id.txt
index b8c71d76..b2da59f 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm-id.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm-id.txt
@@ -10,9 +10,16 @@
Format:
It is expected that the qcom,msm-id entry be at the top level of the device
-tree structure. The format of the entry is:
+tree structure. The format can take one of the two forms below:
qcom,msm-id = <chipset_id, platform_id, rev_id> [, <c2, p2, r2> ...]
+ qcom,msm-id = <chipset_id, rev_id> [, <c2, r2> ...]
+
+If the second format is used one must also define the board-id.
Example:
qcom,msm-id = <126 15 0>;
+
+ qcom,board-id= <15 2>;
+ qcom,msm-id = <126 0>;
+
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
index 6ef2b77..d07eba6 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
@@ -85,19 +85,19 @@
qcom,core-control-mask = <7>;
qcom,pmic-sw-mode-temp = <90>;
qcom,pmic-sw-mode-temp-hysteresis = <80>;
- qcom,pmic-sw-mode-regs = "vdd_dig";
+ qcom,pmic-sw-mode-regs = "vdd-dig";
qcom,vdd-restriction-temp = <5>;
qcom,vdd-restriction-temp-hysteresis = <10>;
- vdd_dig-supply=<&pm8841_s2_floor_corner>
+ vdd-dig-supply=<&pm8841_s2_floor_corner>
qcom,vdd-dig-rstr{
- qcom,vdd-rstr-reg = "vdd_dig";
+ qcom,vdd-rstr-reg = "vdd-dig";
qcom,levels = <5 7 7>; /* Nominal, Super Turbo, Super Turbo */
qcom,min-level = <1>; /* No Request */
};
qcom,vdd-apps-rstr{
- qcom,vdd-rstr-reg = "vdd_apps";
+ qcom,vdd-rstr-reg = "vdd-apps";
qcom,levels = <1881600 1958400 2265600>;
qcom,freq-req;
};
diff --git a/Documentation/devicetree/bindings/batterydata/batterydata.txt b/Documentation/devicetree/bindings/batterydata/batterydata.txt
new file mode 100644
index 0000000..985fb4c
--- /dev/null
+++ b/Documentation/devicetree/bindings/batterydata/batterydata.txt
@@ -0,0 +1,163 @@
+Battery Profile Data
+
+Battery Data is a collection of battery profile data made available to
+the QPNP Charger and BMS drivers via device tree.
+
+qcom,battery-data node required properties:
+- qcom,rpull-up-kohm : The vadc pullup resistor's resistance value in kOhms.
+- qcom,vref-batt-therm-uv : The vadc voltage used to make readings.
+ For Qualcomm VADCs this should be 1800000uV.
+
+qcom,battery-data can also include any number of children nodes. These children
+nodes will be treated as battery profile data nodes.
+
+Profile data node required properties:
+- qcom,fcc-mah : Full charge count of the battery in milliamp-hours
+- qcom,default-rbatt-mohm : The nominal battery resistance value
+- qcom,rbatt-capacitive-mohm : The capacitive resistance of the battery.
+- qcom,flat-ocv-threshold-uv : The threshold under which the battery can be
+ considered to be in the flat portion of the discharge
+ curve.
+- qcom,max-voltage-uv : The maximum rated voltage of the battery
+- qcom,v-cutoff-uv : The cutoff voltage of the battery at which the device
+ should shutdown gracefully.
+- qcom,chg-term-ua : The termination charging current of the battery.
+- qcom,batt-id-kohm : The battery id resistance of the battery.
+
+Profile data node required subnodes:
+- qcom,fcc-temp-lut : An 1-dimensional lookup table node that encodes
+ temperature to fcc lookup. The units for this lookup
+ table should be degrees celsius to milliamp-hours.
+- qcom,pc-temp-ocv-lut : A 2-dimensional lookup table node that encodes
+ temperature and percent charge to open circuit voltage
+ lookup. The units for this lookup table should be
+ degrees celsius and percent to millivolts.
+- qcom,rbatt-sf-lut : A 2-dimentional lookup table node that encodes
+ temperature and percent charge to battery internal
+ resistance lookup. The units for this lookup table
+ should be degrees celsius and percent to milliohms.
+
+Lookup table required properties:
+- qcom,lut-col-legend : An array that encodes the legend of the lookup table's
+ columns. The length of this array will determine the
+ lookup table's width.
+- qcom,lut-data : An array that encodes the lookup table's data. The size of this
+ array should be equal to the size of qcom,lut-col-legend
+ multiplied by 1 if it's a 1-dimensional table, or
+ the size of qcom,lut-row-legend if it's a 2-dimensional
+ table. The data should be in a flattened row-major
+ representation.
+
+Lookup table optional properties:
+- qcom,lut-row-legend : An array that encodes the legend of the lookup table's rows.
+ If this property exists, then it is assumed that the
+ lookup table is a 2-dimensional table.
+
+Example:
+
+In msm8974-mtp.dtsi:
+
+mtp_batterydata: qcom,battery-data {
+ qcom,rpull-up-kohm = <100>;
+ qcom,vref-batt-therm-uv = <1800000>;
+
+ /include/ "batterydata-palladium.dtsi"
+ /include/ "batterydata-mtp-3000mah.dtsi"
+};
+
+&pm8941_bms {
+ qcom,battery-data = <&mtp_batterydata>;
+};
+
+In batterydata-palladium.dtsi:
+
+qcom,palladium-batterydata {
+ qcom,fcc-mah = <1500>;
+ qcom,default-rbatt-mohm = <236>;
+ qcom,rbatt-capacitive-mohm = <50>;
+ qcom,flat-ocv-threshold-uv = <3800000>;
+ qcom,max-voltage-uv = <4200000>;
+ qcom,v-cutoff-uv = <3400000>;
+ qcom,chg-term-ua = <100000>;
+ qcom,batt-id-kohm = <75>;
+
+ qcom,fcc-temp-lut {
+ qcom,lut-col-legend = <(-20) 0 25 40 65>;
+ qcom,lut-data = <1492 1492 1493 1483 1502>;
+ };
+
+ qcom,pc-temp-ocv-lut {
+ qcom,lut-col-legend = <(-20) 0 25 40 65>;
+ 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 = <4173 4167 4163 4156 4154>,
+ <4104 4107 4108 4102 4104>,
+ <4057 4072 4069 4061 4060>,
+ <3973 4009 4019 4016 4020>,
+ <3932 3959 3981 3982 3983>,
+ <3899 3928 3954 3950 3950>,
+ <3868 3895 3925 3921 3920>,
+ <3837 3866 3898 3894 3892>,
+ <3812 3841 3853 3856 3862>,
+ <3794 3818 3825 3823 3822>,
+ <3780 3799 3804 3804 3803>,
+ <3768 3787 3790 3788 3788>,
+ <3757 3779 3778 3775 3776>,
+ <3747 3772 3771 3766 3765>,
+ <3736 3763 3766 3760 3746>,
+ <3725 3749 3756 3747 3729>,
+ <3714 3718 3734 3724 3706>,
+ <3701 3703 3696 3689 3668>,
+ <3675 3695 3682 3675 3662>,
+ <3670 3691 3680 3673 3661>,
+ <3661 3686 3679 3672 3656>,
+ <3649 3680 3676 3669 3641>,
+ <3633 3669 3667 3655 3606>,
+ <3610 3647 3640 3620 3560>,
+ <3580 3607 3596 3572 3501>,
+ <3533 3548 3537 3512 3425>,
+ <3457 3468 3459 3429 3324>,
+ <3328 3348 3340 3297 3172>,
+ <3000 3000 3000 3000 3000>;
+ };
+
+ qcom,rbatt-sf-lut {
+ qcom,lut-col-legend = <(-20) 0 25 40 65>;
+ 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 = <357 187 100 91 91>,
+ <400 208 105 94 94>,
+ <390 204 106 95 96>,
+ <391 201 108 98 98>,
+ <391 202 110 98 100>,
+ <390 200 110 99 102>,
+ <389 200 110 99 102>,
+ <393 202 101 93 100>,
+ <407 205 99 89 94>,
+ <428 208 100 91 96>,
+ <455 212 102 92 98>,
+ <495 220 104 93 101>,
+ <561 232 107 95 102>,
+ <634 245 112 98 98>,
+ <714 258 114 98 98>,
+ <791 266 114 97 100>,
+ <871 289 108 95 97>,
+ <973 340 124 108 105>,
+ <489 241 109 96 99>,
+ <511 246 110 96 99>,
+ <534 252 111 95 98>,
+ <579 263 112 96 96>,
+ <636 276 111 95 97>,
+ <730 294 109 96 99>,
+ <868 328 112 98 104>,
+ <1089 374 119 101 115>,
+ <1559 457 128 105 213>,
+ <12886 1026 637 422 3269>,
+ <170899 127211 98968 88907 77102>;
+ };
+};
+
diff --git a/Documentation/devicetree/bindings/coresight/coresight.txt b/Documentation/devicetree/bindings/coresight/coresight.txt
index 8d1d46d..7f7ee25 100644
--- a/Documentation/devicetree/bindings/coresight/coresight.txt
+++ b/Documentation/devicetree/bindings/coresight/coresight.txt
@@ -21,6 +21,7 @@
"qcom,coresight-csr" for coresight csr device,
"arm,coresight-cti" for coresight cti devices,
"qcom,coresight-hwevent" for coresight hardware event devices
+ "arm,coresight-fuse" for coresight fuse device,
- reg : physical base address and length of the register set(s) of the component
- reg-names : names corresponding to each reg property value. The reg-names that
need to be used with corresponding compatible string for a coresight device
@@ -68,6 +69,10 @@
"<ss-mux>" - physical base address of hardware event mux
control registers where <ss-mux> is subsystem mux it
represents
+ - for coresight fuse device:
+ compatible : should be "arm,coresight-fuse"
+ reg-names : should be:
+ "fuse-base" - physical base address of fuse registers
- coresight-id : unique integer identifier for the component
- coresight-name : unique descriptive name of the component
- coresight-nr-inports : number of input ports on the component
@@ -113,6 +118,12 @@
- qcom,setb-gpios-pull : active pull configuration for set B gpios
- qcom,setb-gpios-dir : active direction for set B gpios
- qcom,hwevent-clks : list of clocks required by hardware event driver
+- qcom,byte-cntr-absent : specifies if the byte counter feature is absent on
+ the device. Only relevant in case of tmc-etr device.
+- interrupts : <a b c> where a is 0 or 1 depending on if the interrupt is
+ spi/ppi, b is the interrupt number and c is the mask,
+- interrupt-names : a list of strings that map in order to the list of
+ interrupts specified in the 'interrupts' property.
Examples:
@@ -123,6 +134,11 @@
<0xfc37c000 0x3000>;
reg-names = "tmc-base", "bam-base";
+ interrupts = <0 166 0>;
+ interrupt-names = "byte-cntr-irq";
+
+ qcom,byte-cntr-absent;
+
coresight-id = <0>;
coresight-name = "coresight-tmc-etr";
coresight-nr-inports = <1>;
@@ -236,3 +252,13 @@
qcom,hwevent-clks = "core_mmss_clk";
};
+
+ fuse: fuse@fc4be024 {
+ compatible = "arm,coresight-fuse";
+ reg = <0xfc4be024 0x8>;
+ reg-names = "fuse-base";
+
+ coresight-id = <30>;
+ coresight-name = "coresight-fuse";
+ coresight-nr-inports = <0>;
+ };
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt
index ce4972a..4cec0cd 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt
@@ -12,21 +12,41 @@
- vdda-supply: Phandle for vreg regulator device node.
- qcom,mdss-fb-map: pHandle that specifies the framebuffer to which the
interface is mapped.
+- qcom,platform-regulator-settings: An array of length 7 that specifies the PHY
+ regulator settings.
+- qcom,platform-strength-ctrl: An array of length 2 that specifies the PHY
+ strengthCtrl settings.
+- qcom,platform-bist-ctrl: An array of length 6 that specifies the PHY
+ BIST ctrl settings.
+- qcom,platform-lane-config: An array of length 45 that specifies the PHY
+ lane configuration settings.
Optional properties:
- label: A string used to describe the controller used.
-- qcom,supply-names: A list of strings that lists the names of the
- regulator supplies.
-- qcom,supply-min-voltage-level: A list that specifies minimum voltage level
- of supply(ies) mentioned above. This list maps
- in the order of the supply names listed above.
-- qcom,supply-max-voltage-level: A list that specifies maximum voltage level of
- supply(ies) mentioned above. This list maps in
- the order of the supply names listed above.
-- qcom,supply-peak-current: A list that specifies the peak current that will
- be drawn from the supply(ies) mentioned above. This
- list maps in the order of the supply names listed above.
+- qcom,platform-supply-entry<1..n>: A node that lists the elements of the supply. There
+ can be more than one instance of this binding,
+ in which case the entry would be appended with
+ the supply entry index.
+ e.g. qcom,platform-supply-entry1
+ -- qcom,supply-name: name of the supply (vdd/vdda/vddio)
+ -- qcom,supply-min-voltage: minimum voltage level (uV)
+ -- qcom,supply-max-voltage: maximum voltage level (uV)
+ -- qcom,supply-enable-load: load drawn (uA) from enabled supply
+ -- qcom,supply-disable-load: load drawn (uA) from disabled supply
+ -- qcom,supply-pre-on-sleep: time to sleep (ms) before turning on
+ -- qcom,supply-post-on-sleep: time to sleep (ms) after turning on
+ -- qcom,supply-pre-off-sleep: time to sleep (ms) before turning off
+ -- qcom,supply-post-off-sleep: time to sleep (ms) after turning off
+- qcom,platform-enable-gpio: Specifies the panel lcd/display enable gpio.
+- qcom,platform-reset-gpio: Specifies the panel reset gpio.
+- qcom,platform-te-gpio: Specifies the gpio used for TE.
+- qcom,platform-reset-sequence: An array that lists the
+ sequence of reset gpio values and sleeps
+ Each command will have the format defined
+ as below:
+ --> Reset GPIO value
+ --> Sleep value (in ms)
Example:
mdss_dsi0: qcom,mdss_dsi@fd922800 {
@@ -37,9 +57,50 @@
vdd-supply = <&pm8226_l15>;
vddio-supply = <&pm8226_l8>;
vdda-supply = <&pm8226_l4>;
- qcom,supply-names = "vdd", "vddio", "vdda";
- qcom,supply-min-voltage-level = <2800000 1800000 1200000>;
- qcom,supply-max-voltage-level = <2800000 1800000 1200000>;
- qcom,supply-peak-current = <150000 100000 100000>;
+ qcom,platform-strength-ctrl = [ff 06];
+ qcom,platform-bist-ctrl = [00 00 b1 ff 00 00];
+ qcom,platform-regulator-settings = [07 09 03 00 20 00 01];
+ qcom,platform-lane-config = [00 00 00 00 00 00 00 01 97
+ 00 00 00 00 05 00 00 01 97
+ 00 00 00 00 0a 00 00 01 97
+ 00 00 00 00 0f 00 00 01 97
+ 00 c0 00 00 00 00 00 01 bb];
qcom,mdss-fb-map = <&mdss_fb0>;
+ qcom,platform-reset-gpio = <&msmgpio 25 1>;
+ qcom,platform-te-gpio = <&msmgpio 24 0>;
+ qcom,platform-enable-gpio = <&msmgpio 58 1>;
+ qcom,platform-reset-sequence = <1 25 0 20 1 10>;
+ qcom,platform-supply-entry1 {
+ qcom,supply-name = "vdd";
+ qcom,supply-min-voltage = <2800000>;
+ qcom,supply-max-voltage = <2800000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ qcom,supply-pre-on-sleep = <0>;
+ qcom,supply-post-on-sleep = <20>;
+ qcom,supply-pre-off-sleep = <0>;
+ qcom,supply-post-off-sleep = <20>;
+ };
+ qcom,platform-supply-entry2 {
+ qcom,supply-name = "vddio";
+ qcom,supply-min-voltage = <1800000>;
+ qcom,supply-max-voltage = <1800000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ qcom,supply-pre-on-sleep = <0>;
+ qcom,supply-post-on-sleep = <30>;
+ qcom,supply-pre-off-sleep = <0>;
+ qcom,supply-post-off-sleep = <30>;
+ };
+ qcom,platform-supply-entry3 {
+ qcom,supply-name = "vdda";
+ qcom,supply-min-voltage = <1200000>;
+ qcom,supply-max-voltage = <1200000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ qcom,supply-pre-on-sleep = <0>;
+ qcom,supply-post-on-sleep = <20>;
+ qcom,supply-pre-off-sleep = <0>;
+ qcom,supply-post-off-sleep = <30>;
+ };
};
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index 8c87eac..44134f8 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -12,140 +12,173 @@
the panel driver. By default this property will be
set to "disable". Will be set to "ok/okay" status
for specific platforms.
-- qcom,dsi-ctrl-phandle: Specifies the phandle for the DSI controller that
+- qcom,mdss-dsi-panel-controller: Specifies the phandle for the DSI controller that
this panel will be mapped to.
-- qcom,mdss-pan-res: A two dimensional array that specifies the panel
- resolution.
-- qcom,mdss-pan-bpp: Specifies the panel bits per pixel. Default value is 24(rgb888).
- 18 = for rgb666
+- qcom,mdss-dsi-panel-width: Specifies panel width in pixels.
+- qcom,mdss-dsi-panel-height: Specifies panel height in pixels.
+- qcom,mdss-dsi-bpp: Specifies the panel bits per pixel.
+ 3 = for rgb111
+ 8 = for rgb332
+ 12 = for rgb444
16 = for rgb565
-- qcom,mdss-pan-dest: A string that specifies the destination display for the panel.
- Default is "display_1".
+ 18 = for rgb666
+ 24 = for rgb888
+- qcom,mdss-dsi-panel-destination: A string that specifies the destination display for the panel.
"display_1" = DISPLAY_1
"display_2" = DISPLAY_2
-- qcom,panel-phy-regulatorSettings: An array of length 7 that specifies the PHY
- regulator settings for the panel.
-- qcom,panel-phy-timingSettings: An array of length 12 that specifies the PHY
+- qcom,mdss-dsi-panel-timings: An array of length 12 that specifies the PHY
timing settings for the panel.
-- qcom,panel-phy-strengthCtrl: An array of length 2 that specifies the PHY
- strengthCtrl settings for the panel.
-- qcom,panel-phy-bistCtrl: An array of length 6 that specifies the PHY
- BIST ctrl settings for the panel.
-- qcom,panel-phy-laneConfig: An array of length 45 that specifies the PHY
- lane configuration settings for the panel.
-- qcom,mdss-panel-on-cmds: An array of variable length that lists the init commands
- of the panel. Each command will have the format specified
- as below:
- --> data type of the command
- --> specifies whether this command packet is last.
- --> virtual channel
- --> Needs acknowledge from the panel or not.
- --> wait time after the command is transmitter.
- --> size of payload
- --> payload.
-- qcom,mdss-panel-off-cmds: An array of variable length that lists the panel off
- commands. Each command will have the format specified
- as below:
- --> data type of the command
- --> specifies whether this command packet is last.
- --> virtual channel
- --> Needs acknowledge from the panel or not.
- --> wait time after the command is transmitter.
- --> size of payload
- --> payload.
+- qcom,mdss-dsi-on-command: A byte stream formed by multiple dcs packets base on
+ qcom dsi controller protocol.
+ byte 0: dcs data type
+ byte 1: set to indicate this is an individual packet
+ (no chain)
+ byte 2: virtual channel number
+ byte 3: expect ack from client (dcs read command)
+ byte 4: wait number of specified ms after dcs command
+ transmitted
+ byte 5, 6: 16 bits length in network byte order
+ byte 7 and beyond: number byte of payload
+- qcom,mdss-dsi-off-command: A byte stream formed by multiple dcs packets base on
+ qcom dsi controller protocol.
+ byte 0: dcs data type
+ byte 1: set to indicate this is an individual packet
+ (no chain)
+ byte 2: virtual channel number
+ byte 3: expect ack from client (dcs read command)
+ byte 4: wait number of specified ms after dcs command
+ transmitted
+ byte 5, 6: 16 bits length in network byte order
+ byte 7 and beyond: number byte of payload
Optional properties:
-- label: A string used as a descriptive name of the panel
-- qcom,enable-gpio: Specifies the panel lcd/display enable gpio.
-- qcom,rst-gpio: Specifies the panel reset gpio.
-- qcom,te-gpio: Specifies the gpio used for TE.
-- qcom,pwm-lpg-channel: LPG channel for backlight.
-- qcom,pwm-period: PWM period in microseconds.
-- qcom,pwm-pmic-gpio: PMIC gpio binding to backlight.
-- qcom,mdss-pan-broadcast-mode: Boolean used to enable broadcast mode.
+- qcom,mdss-dsi-panel-name: A string used as a descriptive name of the panel
- qcom,cont-splash-enabled: Boolean used to enable continuous splash mode.
-- qcom,fbc-enabled: Boolean used to enable frame buffer compression mode.
-- qcom,fbc-mode-select: An array of length 7 that specifies the fbc mode supported
- by the panel. FBC enabled panels may or may not support
- the modes specified here. Each entry will
- have the format specified below:
- --> compressed bpp supported by the panel
- --> component packing
- --> enable/disable quantization error calculation
- --> Bias for CD
- --> enable/disable PAT mode
- --> enable/disable VLC mode
- --> enable/disable BFLC mode
-- qcom,fbc-budget-ctl: An array of length 3 that specifies the budget control settings
- supported by the fbc enabled panel. Each entry will have the format
- specified below:
- --> per line extra budget
- --> extra budget level
- --> per block budget
-- qcom,fbc-lossy-mode: An array of 3 that specifies the lossy mode settings
- supported by the fbc enabled panel. Each entry will
- have the format specified below:
- --> lossless mode threshold
- --> lossy mode threshold
- --> lossy RGB threshold
-- qcom,mdss-pan-porch-values: An array of size 6 that specifies the panel blanking values.
-- qcom,mdss-pan-underflow-clr: Specifies the controller settings for the panel underflow clear
- settings. Default value is 0xff.
-- qcom,mdss-pan-bl-ctrl: A string that specifies the implementation of backlight
+- qcom,mdss-dsi-panel-broadcast-mode: Boolean used to enable broadcast mode.
+- qcom,mdss-dsi-fbc-enable: Boolean used to enable frame buffer compression mode.
+- qcom,mdss-dsi-fbc-bpp: Compressed bpp supported by the panel.
+ Specified color order is used as default value.
+- qcom,mdss-dsi-fbc-packing: Component packing.
+ 0 = default value.
+- qcom,mdss-dsi-fbc-quant-error: Boolean used to enable quantization error calculation.
+- qcom,mdss-dsi-fbc-bias: Bias for CD.
+ 0 = default value.
+- qcom,mdss-dsi-fbc-pat-mode: Boolean used to enable PAT mode.
+- qcom,mdss-dsi-fbc-vlc-mode: Boolean used to enable VLC mode.
+- qcom,mdss-dsi-fbc-bflc-mode: Boolean used to enable BFLC mode.
+- qcom,mdss-dsi-fbc-h-line-budget: Per line extra budget.
+ 0 = default value.
+- qcom,mdss-dsi-fbc-budget-ctrl: Extra budget level.
+ 0 = default value.
+- qcom,mdss-dsi-fbc-block-budget: Per block budget.
+ 0 = default value.
+- qcom,mdss-dsi-fbc-lossless-threshold: Lossless mode threshold.
+ 0 = default value.
+- qcom,mdss-dsi-fbc-lossy-threshold: Lossy mode threshold.
+ 0 = default value.
+- qcom,mdss-dsi-fbc-rgb-threshold: Lossy RGB threshold.
+ 0 = default value.
+- qcom,mdss-dsi-fbc-lossy-mode-idx: Lossy mode index value.
+ 0 = default value.
+- qcom,mdss-dsi-h-back-porch: Horizontal back porch value in pixel.
+ 6 = default value.
+- qcom,mdss-dsi-h-front-porch: Horizontal front porch value in pixel.
+ 6 = default value.
+- qcom,mdss-dsi-h-pulse-width: Horizontal pulse width.
+ 2 = default value.
+- qcom,mdss-dsi-h-sync-skew: Horizontal sync skew value.
+ 0 = default value.
+- qcom,mdss-dsi-v-back-porch: Vertical back porch value in pixel.
+ 6 = default value.
+- qcom,mdss-dsi-v-front-porch: Vertical front porch value in pixel.
+ 6 = default value.
+- qcom,mdss-dsi-v-pulse-width: Vertical pulse width.
+ 2 = default value.
+- qcom,mdss-dsi-h-left-border: Horizontal left border in pixel.
+ 0 = default value
+- qcom,mdss-dsi-h-right-border: Horizontal right border in pixel.
+ 0 = default value
+- qcom,mdss-dsi-v-top-border: Vertical top border in pixel.
+ 0 = default value
+- qcom,mdss-dsi-v-bottom-border: Vertical bottom border in pixel.
+ 0 = default value
+- qcom,mdss-dsi-underflow-color: Specifies the controller settings for the
+ panel under flow color.
+ 0xff = default value.
+- qcom,mdss-dsi-border-color: Defines the border color value if border is present.
+ 0 = default value.
+- qcom,mdss-dsi-bl-pmic-control-type: A string that specifies the implementation of backlight
control for this panel.
"bl_ctrl_pwm" = Backlight controlled by PWM gpio.
"bl_ctrl_wled" = Backlight controlled by WLED.
- "bl_ctrl_dcs_cmds" = Backlight controlled by DCS commands.
-- qcom,mdss-pan-bl-levels: Specifies the backlight levels supported by the panel.
- Default range is 1 to 255.
-
-- qcom,mdss-pan-dsi-mode: Specifies the panel operating mode.
- 0 = enable video mode(default mode).
- 1 = enable command mode.
-- qcom,mdss-vsync-enable: Specifies Tear Check configuration.
- 0 = TE disable.
- 1 = TE enable.
-- qcom,mdss-hw-vsync-mode: Specifies TE type.
- 0 = software vsync.
- 1 = hardware vsync (TE gpio pin).
-- qcom,mdss-pan-te-sel: Specifies TE operating mode.
+ "bl_ctrl_dcs" = Backlight controlled by DCS commands.
+ other: Unknown backlight control. (default)
+- qcom,mdss-dsi-bl-pmic-bank-select: LPG channel for backlight.
+ Requred if blpmiccontroltype is PWM
+- qcom,mdss-dsi-bl-pmic-pwm-frequency: PWM period in microseconds.
+ Requred if blpmiccontroltype is PWM
+- qcom,mdss-dsi-pwm-gpio: PMIC gpio binding to backlight.
+ Requred if blpmiccontroltype is PWM
+- qcom,mdss-dsi-bl-min-level: Specifies the min backlight level supported by the panel.
+ 0 = default value.
+- qcom,mdss-dsi-bl-max-level: Specifies the max backlight level supported by the panel.
+ 255 = default value.
+- qcom,mdss-dsi-interleave-mode: Specifies interleave mode.
+ 0 = default value.
+- qcom,mdss-dsi-panel-type: Specifies the panel operating mode.
+ "dsi_video_mode" = enable video mode (default).
+ "dsi_cmd_mode" = enable command mode.
+- qcom,mdss-dsi-te-check-enable: Boolean to enable Tear Check configuration.
+- qcom,mdss-dsi-te-using-te-pin: Boolean to specify whether using hardware vsync.
+- qcom,mdss-dsi-te-pin-select: Specifies TE operating mode.
0 = TE through embedded dcs command
- 1 = TE through TE gpio pin.
-- qcom,mdss-pan-dsi-h-pulse-mode: Specifies the pulse mode option for the panel.
+ 1 = TE through TE gpio pin. (default)
+- qcom,mdss-dsi-te-dcs-command: Inserts the dcs command.
+ 1 = default value.
+- qcom,mdss-dsi-te-v-sync-rd-ptr-irq-line: Configures the scan line number that the dsi
+ pixel transfer will start on. Rasing this number
+ will result in delaying the start of the pixel
+ transfer.
+ 0x2c = default value.
+- qcom,mdss-dsi-te-v-sync-continue-lines: Represents the difference in number of lines
+ between estimated read pointer and write pointer
+ to allow the updating of all the lines except
+ the first line of the frame.
+ 0x3c = default value.
+- qcom,mdss-dsi-h-sync-pulse: Specifies the pulse mode option for the panel.
0 = Don't send hsa/he following vs/ve packet(default)
1 = Send hsa/he following vs/ve packet
-- qcom,mdss-pan-dsi-h-power-stop: An Array of size 3 that specifies the power mode
- during horizontal porch and sync periods of the panel.
- 0 = high speed mode(default mode).
- 1 = Low power mode for horizontal porches and sync pulse.
-- qcom,mdss-pan-dsi-bllp-power-stop: An Array of size 2 that specifies the power mode
- during blanking period and after EOF(end of frame).
- 0 = high speed mode(default mode).
- 1 = Low power mode during blanking and EOF.
-- qcom,mdss-pan-dsi-traffic-mode: Specifies the panel traffic mode.
+- qcom,mdss-dsi-hfp-power-mode: Boolean to determine DSI lane state during
+ horizontal front porch (HFP) blanking period.
+- qcom,mdss-dsi-hbp-power-mode: Boolean to determine DSI lane state during
+ horizontal back porch (HBP) blanking period.
+- qcom,mdss-dsi-hsa-power-mode: Boolean to determine DSI lane state during
+ horizontal sync active (HSA) mode.
+- qcom,mdss-dsi-bllp-eof-power-mode: Boolean to determine DSI lane state during
+ blanking low power period (BLLP) EOF mode.
+- 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.
-- qcom,mdss-pan-dsi-dst-format: Specifies the destination format.
- 0 = DSI_VIDEO_DST_FORMAT_RGB565.
- 1 = DSI_VIDEO_DST_FORMAT_RGB666.
- 2 = DSI_VIDEO_DST_FORMAT_RGB666_LOOSE.
- 3 = DSI_VIDEO_DST_FORMAT_RGB888 (Default format)
- 6 = DSI_CMD_DST_FORMAT_RGB565
- 7 = DSI_CMD_DST_FORMAT_RGB666
- 8 = DSI_CMD_DST_FORMAT_RGB888
-- qcom,mdss-pan-dsi-vc: Specifies the virtual channel identefier.
+- qcom,mdss-dsi-pixel-packing: Specifies if pixel packing is used (in case of RGB666).
+ 0 = Tight packing (default value).
+ 1 = Loose packing.
+- qcom,mdss-dsi-virtual-channel-id: Specifies the virtual channel identefier.
0 = default value.
-- qcom,mdss-pan-dsi-rgb-swap: Specifies the R, G and B channel ordering.
+- 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
-- qcom,mdss-pan-dsi-data-lanes: An array that specifies the data lanes enabled.
- <1 1 0 0> = data lanes 1 and 2 are enabled.(default).
-- qcom,mdss-pan-dsi-dlane-swap: Specifies the data lane swap configuration.
+- 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>
@@ -154,79 +187,121 @@
5 = <1 0 3 2>
6 = <2 1 0 3>
7 = <3 2 1 0>
-- qcom,mdss-pan-dsi-t-clk: An array that specifies the byte clock cycles
- before and after each mode switch.
-- qcom,mdss-pan-dsi-stream: Specifies the packet stream to be used.
+- 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.
+ 0x24 = default value.
+- qcom,mdss-dsi-stream: Specifies the packet stream to be used.
0 = stream 0 (default)
1 = stream 1
-- qcom,mdss-pan-dsi-mdp-tr: Specifies the trigger mechanism to be used for MDP path.
+- 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 mode)
+ 4 = Triggered by software (default)
6 = Software trigger and TE
-- qcom,mdss-pan-dsi-dma-tr: Specifies the trigger mechanism to be used for DMA path.
+- 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 mode)
+ 4 = Triggered by software (default)
5 = Software trigger and start/end of frame trigger.
6 = Software trigger and TE
-- qcom,mdss-pan-dsi-frame-rate: Specifies the frame rate for the panel.
+- qcom,mdss-dsi-panel-framerate: Specifies the frame rate for the panel.
60 = 60 frames per second (default)
-- qcom,on-cmds-dsi-state: A string that Specifies the ctrl state for sending ON commands.
- Supported modes are "DSI_LP_MODE" and "DSI_HS_MODE".
-- qcom,off-cmds-dsi-state: A string that Specifies the ctrl state for sending ON commands.
- Supported modes are "DSI_LP_MODE" and "DSI_HS_MODE".
+- qcom,mdss-dsi-panel-clockrate: Specifies the panel clock speed in Hz.
+ 0 = default value.
+- qcom,mdss-dsi-on-command-state: String that specifies the ctrl state for sending ON commands.
+ "dsi_lp_mode" = DSI low power mode (default)
+ "dsi_hs_mode" = DSI high speed mode
+- qcom,mdss-dsi-off-command-state: String that specifies the ctrl state for sending OFF commands.
+ "dsi_lp_mode" = DSI low power mode (default)
+ "dsi_hs_mode" = DSI high speed mode
-- qcom,panel-on-cmds: A byte stream formed by multiple dcs packets base on
- qcom dsi controller protocol.
- byte 0 : dcs data type
- byte 1 : set to indicate this is an individual packet
- (no chain).
- byte 2 : virtual channel number
- byte 3 : expect ack from client (dcs read command)
- byte 4 : wait number of specified ms after dcs command
- transmitted
- byte 5, 6: 16 bits length in network byte order
- byte 7 and beyond: number byte of payload
-
Note, if a given optional qcom,* binding is not present, then the driver will configure
the default values specified.
Example:
-/ {
+&soc {
qcom,mdss_dsi_sim_video {
compatible = "qcom,mdss-dsi-panel";
- label = "simulator video mode dsi panel";
+ qcom,mdss-dsi-panel-name = "simulator video mode dsi panel";
status = "disable";
- qcom,dsi-ctrl-phandle = <&mdss_dsi0>;
- qcom,mdss-pan-res = <640 480>;
- qcom,mdss-pan-bpp = <24>;
- qcom,mdss-pan-dest = "display_1";
- qcom,mdss-pan-porch-values = <6 2 6 6 2 6>;
- qcom,mdss-pan-underflow-clr = <0xff>;
- qcom,mdss-pan-bl-levels = <1 15>;
- qcom,mdss-pan-dsi-mode = <0>;
- qcom,mdss-pan-dsi-h-pulse-mode = <1>;
- qcom,mdss-pan-dsi-h-power-stop = <1 1 1>;
- qcom,mdss-pan-dsi-bllp-power-stop = <1 1>;
- qcom,mdss-pan-dsi-traffic-mode = <0>;
- qcom,mdss-pan-dsi-dst-format = <3>;
- qcom,mdss-pan-dsi-vc = <0>;
- qcom,mdss-pan-dsi-rgb-swap = <0>;
- qcom,mdss-pan-dsi-data-lanes = <1 1 0 0>;
- qcom,mdss-pan-dsi-t-clk = <0x24 0x03>;
- qcom,mdss-pan-dsi-stream = <0>;
- qcom,mdss-pan-dsi-mdp-tr = <0x04>;
- qcom,mdss-pan-dsi-dma-tr = <0x04>;
- qcom,mdss-pan-frame-rate = <60>;
- qcom,panel-on-cmds = [32 01 00 00 00 00 02 00 00];
- qcom,on-cmds-dsi-state = "DSI_LP_MODE";
- qcom,panel-off-cmds = [22 01 00 00 00 00 00];
- qcom,off-cmds-dsi-state = "DSI LP MODE";
- qcom,fbc-enabled;
- qcom,fbc-mode = <12 0 1 2 1 1 1>;
- qcom,fbc-budget-ctl = <675 5 91>;
- qcom,fbc-lossy-mode = <0 0xc0 0 3>;
+ qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
+ qcom,mdss-dsi-panel-height = <1280>;
+ qcom,mdss-dsi-panel-width = <720>;
+ qcom,mdss-dsi-bpp = <24>;
+ qcom,mdss-dsi-pixel-packing = <0>;
+ qcom,mdss-dsi-panel-destination = "display_1";
+ qcom,mdss-dsi-panel-broadcast-mode;
+ qcom,mdss-dsi-fbc-enable;
+ qcom,mdss-dsi-fbc-bpp = <0>;
+ qcom,mdss-dsi-fbc-packing = <0>;
+ qcom,mdss-dsi-fbc-quant-error;
+ qcom,mdss-dsi-fbc-bias = <0>;
+ qcom,mdss-dsi-fbc-pat-mode;
+ qcom,mdss-dsi-fbc-vlc-mode;
+ qcom,mdss-dsi-fbc-bflc-mode;
+ qcom,mdss-dsi-fbc-h-line-budget = <0>;
+ qcom,mdss-dsi-fbc-budget-ctrl = <0>;
+ qcom,mdss-dsi-fbc-block-budget = <0>;
+ qcom,mdss-dsi-fbc-lossless-threshold = <0>;
+ qcom,mdss-dsi-fbc-lossy-threshold = <0>;
+ qcom,mdss-dsi-fbc-rgb-threshold = <0>;
+ qcom,mdss-dsi-fbc-lossy-mode-idx = <0>;
+ qcom,mdss-dsi-h-front-porch = <140>;
+ qcom,mdss-dsi-h-back-porch = <164>;
+ qcom,mdss-dsi-h-pulse-width = <8>;
+ qcom,mdss-dsi-h-sync-skew = <0>;
+ qcom,mdss-dsi-v-back-porch = <6>;
+ qcom,mdss-dsi-v-front-porch = <1>;
+ qcom,mdss-dsi-v-pulse-width = <1>;
+ qcom,mdss-dsi-h-left-border = <0>;
+ qcom,mdss-dsi-h-right-border = <0>;
+ qcom,mdss-dsi-v-top-border = <0>;
+ qcom,mdss-dsi-v-bottom-border = <0>;
+ qcom,mdss-dsi-border-color = <0>;
+ qcom,mdss-dsi-underflow-color = <0xff>;
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = < 15>;
+ qcom,mdss-dsi-interleave-mode = <0>;
+ qcom,mdss-dsi-panel-type = "dsi_video_mode";
+ qcom,mdss-dsi-te-check-enable;
+ qcom,mdss-dsi-te-using-te-pin;
+ qcom,mdss-dsi-te-dcs-command = <1>;
+ qcom,mdss-dsi-te-v-sync-continue-lines = <0x3c>;
+ qcom,mdss-dsi-te-v-sync-rd-ptr-irq-line = <0x2c>;
+ qcom,mdss-dsi-te-pin-select = <1>;
+ qcom,mdss-dsi-h-sync-pulse = <1>;
+ qcom,mdss-dsi-hfp-power-mode;
+ qcom,mdss-dsi-hbp-power-mode;
+ qcom,mdss-dsi-hsa-power-mode;
+ qcom,mdss-dsi-bllp-eof-power-mode;
+ qcom,mdss-dsi-bllp-power-mode;
+ qcom,mdss-dsi-traffic-mode = <0>;
+ qcom,mdss-dsi-virtual-channel-id = <0>;
+ qcom,mdss-dsi-color-order = <0>;
+ 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-lane-map = <0>;
+ qcom,mdss-dsi-t-clk-post = <0x20>;
+ qcom,mdss-dsi-t-clk-pre = <0x2c>;
+ qcom,mdss-dsi-stream = <0>;
+ qcom,mdss-dsi-mdp-trigger = <0>;
+ qcom,mdss-dsi-dma-trigger = <0>;
+ qcom,mdss-dsi-panel-framerate = <60>;
+ qcom,mdss-dsi-panel-clockrate = <424000000>;
+ qcom,mdss-dsi-panel-timings = [7d 25 1d 00 37 33
+ 22 27 1e 03 04 00];
+ qcom,mdss-dsi-on-command = [32 01 00 00 00 00 02 00 00
+ 29 01 00 00 10 00 02 FF 99];
+ qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+ qcom,mdss-dsi-off-command = [22 01 00 00 00 00 00];
+ qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-pmic-bank-select = <0>;
+ qcom,mdss-dsi-bl-pmic-pwm-frequency = <0>;
+ qcom,mdss-dsi-pwm-gpio = <&pm8941_mpps 5 0>;
};
};
diff --git a/Documentation/devicetree/bindings/fb/mdss-edp.txt b/Documentation/devicetree/bindings/fb/mdss-edp.txt
index 578b07c..3d7e5a2 100644
--- a/Documentation/devicetree/bindings/fb/mdss-edp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-edp.txt
@@ -20,6 +20,7 @@
specific platforms.
- qcom,mdss-fb-map: pHandle that specifies the framebuffer to which the
interface is mapped.
+- gpio-panel-hpd : gpio pin use for edp hpd
Example:
mdss_edp: qcom,mdss_edp@fd923400 {
@@ -32,6 +33,8 @@
qcom,panel-lpg-channel = <7>; /* LPG Channel 8 */
qcom,panel-pwm-period = <53>;
status = "disable";
+ qcom,mdss-fb-map = <&mdss_fb0>;
+ gpio-panel-hpd = <&msmgpio 102 0>;
};
diff --git a/Documentation/devicetree/bindings/fb/mdss-mdp.txt b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
index 9bc949e..7ba9a88 100644
--- a/Documentation/devicetree/bindings/fb/mdss-mdp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
@@ -123,6 +123,13 @@
offsets as well (i.e. the first mixer offset
corresponds to the same pathway as the first
AD offset).
+- qcom,mdss-has-wfd-blk: Boolean property to indicate the presence of dedicated
+ writeback wfd block in MDSS as opposed to writeback
+ block that is shared between rotator and wfd.
+- qcom,mdss-smp-mb-per-pipe: Maximum number of shared memory pool blocks
+ restricted for a source surface pipe. If this
+ property is not specified, no such restriction
+ would be applied.
Optional subnodes:
Child nodes representing the frame buffer virtual devices.
@@ -133,8 +140,20 @@
- qcom,mdss-mixer-swap: A boolean property that indicates if the mixer muxes
need to be swapped based on the target panel.
By default the property is not defined.
+- qcom,mdss-fb-split: Array of splitted framebuffer size. There should
+ be only two values in this property. The values
+ correspond to the left and right size respectively.
+ MDP muxes two mixer output together before sending to
+ the panel interface and these values are used to set
+ each mixer width, so the sum of these two values
+ should be equal to the panel x-resolution.
-
+ Note that if the sum of two values is not equal to
+ x-resolution or this subnode itself is not defined
+ in device tree there are two cases: 1)split is not
+ enabled if framebuffer size is less than max mixer
+ width; 2) the defaut even split is enabled if frambuffer
+ size is greater than max mixer width.
Example:
qcom,mdss_mdp@fd900000 {
@@ -159,8 +178,10 @@
qcom,mdss-pipe-dma-fetch-id = <10 13>;
qcom,mdss-smp-data = <22 4096>;
qcom,mdss-rot-block-size = <64>;
+ qcom,mdss-smp-mb-per-pipe = <2>;
qcom,mdss-has-bwc;
qcom,mdss-has-decimation;
+ qcom,mdss-has-wfd-blk;
qcom,mdss-ctl-off = <0x00000600 0x00000700 0x00000800
0x00000900 0x0000A00>;
@@ -178,6 +199,7 @@
cell-index = <0>;
compatible = "qcom,mdss-fb";
qcom,mdss-mixer-swap;
+ qcom,mdss-fb-split = <480 240>
};
};
diff --git a/Documentation/devicetree/bindings/input/misc/bmp180.txt b/Documentation/devicetree/bindings/input/misc/bmp180.txt
new file mode 100644
index 0000000..13e0839
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/misc/bmp180.txt
@@ -0,0 +1,35 @@
+Bosch BMP18x-series altimeter driver
+
+Required properties:
+
+ - compatible : Should be "bosch,bmp180".
+ - reg : i2c slave address of the device.
+ - vdd-supply : Analog power supply needed to power device.
+ - vddio-supply : Digital IO power supply needed for IO and I2C.
+ - bosch,chip-id : Chip id for the bmp18x altimeter sensor.
+ - bosch,oversample : Sensor default oversampling value.
+ Default oversampling value to be used at startup.
+ Value range is 0-3 with rising sensitivity.
+ - bosch,period : Temperature measurement period (milliseconds).
+ Set to zero if unsure.
+
+Optional properties:
+
+ - bosch,sw-oversample : Boolean to enable software oversampling if
+ this property is defined. Only take effect when
+ default_oversampling is 3.
+
+Example:
+ i2c@f9925000 {
+ bmp180@77 {
+ status = "okay";
+ reg = <0x77>;
+ compatible = "bosch,bmp180";
+ vdd-supply = <&pm8110_l19>;
+ vddio-supply = <&pm8110_l14>;
+ bosch,chip-id = <0x55>;
+ bosch,oversample = <3>;
+ bosch,period = <1000>;
+ bosch,sw-oversample;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/input/misc/mma8x5x.txt b/Documentation/devicetree/bindings/input/misc/mma8x5x.txt
new file mode 100644
index 0000000..854939c
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/misc/mma8x5x.txt
@@ -0,0 +1,39 @@
+Freescale MMA8x5x 3-Axis Orientation/Motion Detection Sensor series
+(MMA8451/MMA8452/MMA8453/MMA8652/MMA8653)
+
+The Freescale 3-Axis Orientation/Motion Detection Sensor is
+connected to host processor via i2c.
+The sensor can be polling for acceleration data or configure to
+generates interrupts when a motion is detected.
+
+Required properties:
+
+ - compatible : should be "fsl,mma8x5x"
+ - reg : i2c slave address of the device
+ - vdd-supply : power supply needed to power up the device.
+ - vio-supply : power supply needed for device IO and to pullup i2c bus.
+ - fsl,sensors-position : select from 0 to 7 depends on how the sensor is
+ mounting on the board, this will decide how the 3-axis reading
+ of data will be translated to X/Y/Z axis of acceleration data.
+
+Optional properties:
+ Sensor can work on polling mode or interrupt mode, following interrupt
+ is required if the sensor need to work on interrupt mode.
+ - interrupt-parent : parent of interrupt.
+ - interrupts : sensor signal interrupt to indicate new data ready or
+ a motion is detected.
+ - fsl,irq-gpio : First irq gpio which is to provide interrupts to host, same
+ as "interrupts" node. It will also contain active low or active
+ high information.
+
+Example:
+ fsl@1c {
+ compatible = "fsl,mma8x5x";
+ reg = <0x1c>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <81 0x2>;
+ vdd-supply = <&pm8110_l19>;
+ vio-supply = <&pm8110_l14>;
+ fsl,sensors-position = <5>;
+ fsl,irq-gpio = <&msmgpio 0x81 0x02>;
+ };
\ No newline at end of file
diff --git a/Documentation/devicetree/bindings/input/misc/mpu3050.txt b/Documentation/devicetree/bindings/input/misc/mpu3050.txt
new file mode 100644
index 0000000..edbe147
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/misc/mpu3050.txt
@@ -0,0 +1,31 @@
+InvenSense MPU30X0-series gyrometer driver
+
+Required properties:
+
+ - compatible : Should be "invn,mpu3050".
+ - reg : i2c slave address of the device.
+ - interrupt-parent : Parent of interrupt.
+ - interrupts : Gyrometer sample interrupt to indicate new data ready.
+ - vdd-supply : Analog power supply needed to power device.
+ - vlogic-supply : Digital IO power supply needed for IO and I2C.
+ - invn,gpio-int : GPIO used for interrupt.
+ - invn,gpio-en : GPIO used for power enabling.
+ - invn,poll-interval : Initial data polling interval in milliseconds.
+
+Example:
+ i2c@f9925000 {
+ mpu3050@68 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "okay";
+ reg = <0x68>;
+ compatible = "invn,mpu3050";
+ interrupt-parent = <&msmgpio>;
+ interrupts = <84 0x2>;
+ vlogic-supply = <&pm8110_l14>;
+ vdd-supply = <&pm8110_l19>;
+ invn,gpio-int = <&msmgpio 84 0x2>;
+ invn,gpio-en = <&pm8110_gpios 2 0x2>;
+ invn,poll-interval = <200>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/input/touchscreen/atmel-mxt-ts.txt b/Documentation/devicetree/bindings/input/touchscreen/atmel-mxt-ts.txt
index 6fe88a9..4c6ae93 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/atmel-mxt-ts.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/atmel-mxt-ts.txt
@@ -35,6 +35,8 @@
needed during wakeup.
- atmel,no-force-update : flag that signifies whether force configuration
update is applicable or not
+ - atmel,no-lpm-support : flag that signifies whether low power mode is
+ supported or not on this platform
Example:
i2c@f9966000 {
diff --git a/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt b/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt
index 0f35e73..3720172 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt
@@ -20,6 +20,7 @@
- synaptics,panel-x : panel x dimension
- synaptics,panel-y : panel y dimension
- synaptics,fw-image-name : name of firmware .img file in /etc/firmware
+ - synaptics,power-down : fully power down regulators in suspend
Example:
i2c@f9927000 { /* BLSP1 QUP5 */
diff --git a/Documentation/devicetree/bindings/iommu/msm_iommu_v1.txt b/Documentation/devicetree/bindings/iommu/msm_iommu_v1.txt
index 26a119c..9d3ee39 100644
--- a/Documentation/devicetree/bindings/iommu/msm_iommu_v1.txt
+++ b/Documentation/devicetree/bindings/iommu/msm_iommu_v1.txt
@@ -54,6 +54,10 @@
qcom,iommu-bfb-regs property. If this property is present, the
qcom,iommu-bfb-regs property shall also be present, and the lengths of both
properties shall be the same.
+- qcom,iommu-lpae-bfb-regs : See description for qcom,iommu-bfb-regs. This is
+ the same property except this is for IOMMU with LPAE support.
+- qcom,iommu-lpae-bfb-data : See description for qcom,iommu-bfb-data. This is
+ the same property except this is for IOMMU with LPAE support.
Example:
diff --git a/Documentation/devicetree/bindings/leds/leds-msm-gpio-flash.txt b/Documentation/devicetree/bindings/leds/leds-msm-gpio-flash.txt
new file mode 100644
index 0000000..ddbfd5a
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/leds-msm-gpio-flash.txt
@@ -0,0 +1,30 @@
+Qualcomm GPIO Flash Leds
+
+Qualcomm GPIO flash LEDs driver is used for
+controlling flash LEDs that are connected with 2 GPIOs. The 2 GPIOs are name
+flash_en and flash now.
+
+
+The flash LEDs has torch mode and flash mode. The flash mode is used for camera.
+The torch mode is used for torch.
+
+
+Required properties for each node:
+- compatible : should be "qcom,leds-gpio-flash"
+- qcom,flash-en : the GPIO pin number of flash-en function
+- qcom,flash-now : the GPIO pin number of flash-now function
+- linux,name : name of the led that is used in led framework
+- linux,default-trigger : name of the led trigger event
+
+No other optional properties for it.
+
+Example:
+
+ flashlight {
+ compatible = "leds-gpio-flash";
+ status = "okay";
+ qcom,flash-en = <&msmgpio 18 0>;
+ qcom,flash-now = <&msmgpio 19 0>;
+ linux,name = "flashlight";
+ linux,default-trigger = "flashlight-trigger";
+ };
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp.txt b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
index ff95d43..b60760e 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
@@ -81,7 +81,9 @@
- qcom,source-sel: select power source, default 1 (enabled)
- qcom,mode-ctrl: select operation mode, default 0x60 = Mode Sink
- qcom,mode: mode the led should operate in, options "pwm", "lpg" and "manual"
+- 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.
Required properties for PWM mode only:
- qcom,pwm-channel: pwm channel the led will operate on
@@ -105,10 +107,13 @@
- qcom,mode: mode the led should operate in, options "pwm" and "lpg"
- qcom,pwm-channel: pwm channel the led will operate on
- qcom,pwm-us: time the pwm device will modulate at (us)
-- qcom,row-src-sel-val: select source for rows. One bit is used for each row.
- Specify 0 for vph_pwr and 1 for vbst for each row.
-- qcom,row-scan-val: select rows for scanning
-- qcom,row-scan-en: row scan enable
+- qcom,row-id: specify the id of the row. Supported values are 0 to 3.
+
+Optional properties for keypad backlight:
+- qcom,row-src-vbst: select source for rows. Specify for vbst and ignore it
+ for vph_pwr.
+- qcom,row-src-en: specify to enable row source
+- qcom,always-on: specify if the module has to be always on
Required properties for PWM mode only:
- qcom,pwm-us: time the pwm device will modulate at (us)
@@ -136,6 +141,8 @@
qcom,id = <6>;
qcom,source-sel = <1>;
qcom,mode-ctrl = <0x10>;
+ qcom,vin-ctrl = <0x03>;
+ qcom,min-brightness = <20>;
};
};
@@ -255,16 +262,33 @@
qcom,leds@e200 {
status = "okay";
- qcom,kpdbl {
+
+ qcom,kpdbl1 {
label = "kpdbl";
- linux,name = "button-backlight";
+ linux,name = "kpdbl-pwm-1";
qcom,mode = <0>;
qcom,pwm-channel = <8>;
qcom,pwm-us = <1000>;
qcom,id = <7>;
qcom,max-current = <20>;
- qcom,row-src-sel-val = <0x00>;
- qcom,row-scan-en = <0x01>;
- qcom,row-scan-val = <0x01>;
+ qcom,row-id = <0>;
+ qcom,row-src-en;
+ qcom,always-on;
};
+
+ qcom,kpdbl2 {
+ label = "kpdbl";
+ linux,name = "kpdbl-lut-2";
+ qcom,mode = <1>;
+ qcom,pwm-channel = <9>;
+ qcom,pwm-us = <1000>;
+ qcom,start-idx = <1>;
+ qcom,duty-pcts = [00 00 00 00 64
+ 64 00 00 00 00];
+ qcom,id = <7>;
+ qcom,max-current = <20>;
+ qcom,row-id = <1>;
+ qcom,row-src-en;
+ };
+
};
diff --git a/Documentation/devicetree/bindings/media/video/msm-cci.txt b/Documentation/devicetree/bindings/media/video/msm-cci.txt
index 583fbfa..b8156c3 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cci.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cci.txt
@@ -18,6 +18,17 @@
qcom,gpio-req-tbl-num property (in the same order)
- qcom,gpio-req-tbl-label : should contain name of gpios present in
qcom,gpio-req-tbl-num property (in the same order)
+
+Optional properties:
+- master0: qcom,cci-master0 - node should contain clock settings for
+ cci master 0 bus
+- master1: qcom,cci-master1 - node should contain clock settings for
+ cci master 1 bus
+
+[Second level nodes]
+* Qualcomm CCI clock settings
+
+Optional properties:
- qcom,hw-thigh : should contain high period of the SCL clock in terms of CCI
clock cycle
- qcom,hw-tlow : should contain high period of the SCL clock in terms of CCI
@@ -31,7 +42,6 @@
- qcom,hw-trdhld : should contain internal hold time for SDA
- qcom,hw-tsp : should contain filtering of glitches
-[Second level nodes]
* Qualcomm MSM Sensor
MSM sensor node contains properties of camera sensor
@@ -95,6 +105,11 @@
#gpio-cells specifying specific gpio (controller specific)
- qcom,gpio-reset : should contain index to gpio used by sensors reset_n
- qcom,gpio-standby : should contain index to gpio used by sensors standby_n
+- qcom,gpio-vio : should contain index to gpio used by sensors io vreg enable
+- qcom,gpio-vana : should contain index to gpio used by sensors analog vreg enable
+- qcom,gpio-vdig : should contain index to gpio used by sensors digital vreg enable
+- qcom,gpio-vaf : should contain index to gpio used by sensors af vreg enable
+- qcom,gpio-af-pwdm : should contain index to gpio used by sensors af pwdm_n
- qcom,gpio-req-tbl-num : should contain index to gpios specific to this sensor
- qcom,gpio-req-tbl-flags : should contain direction of gpios present in
qcom,gpio-req-tbl-num property (in the same order)
@@ -170,16 +185,12 @@
"CCI_I2C_CLK0",
"CCI_I2C_DATA1",
"CCI_I2C_CLK1";
- 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-scl-stretch-en = <0>;
- qcom,hw-trdhld = <6>;
- qcom,hw-tsp = <1>;
+ master0: qcom,cci-master0 {
+ status = "disabled";
+ };
+ master1: qcom,cci-master1 {
+ status = "disabled";
+ };
actuator0: qcom,actuator@18 {
cell-index = <0>;
@@ -230,3 +241,31 @@
qcom,sensor-mode = <1>;
};
};
+
+ &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-scl-stretch-en = <0>;
+ qcom,hw-trdhld = <6>;
+ qcom,hw-tsp = <1>;
+ 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-scl-stretch-en = <0>;
+ qcom,hw-trdhld = <6>;
+ qcom,hw-tsp = <1>;
+ status = "ok";
+ };
diff --git a/Documentation/devicetree/bindings/pil/pil-pronto.txt b/Documentation/devicetree/bindings/pil/pil-pronto.txt
index 85ccc5d..2cbf22c 100644
--- a/Documentation/devicetree/bindings/pil/pil-pronto.txt
+++ b/Documentation/devicetree/bindings/pil/pil-pronto.txt
@@ -13,6 +13,8 @@
- interrupts: WCNSS to Apps watchdog bite interrupt
- vdd_pronto_pll-supply: regulator to supply pronto pll.
- qcom,firmware-name: Base name of the firmware image. Ex. "wcnss"
+
+Optional properties:
- qcom,gpio-err-fatal: GPIO used by the wcnss to indicate error fatal to the Apps.
- qcom,gpio-err-ready: GPIO used by the wcnss to indicate error ready to the Apps.
- qcom,gpio-proxy-unvote: GPIO used by the wcnss to trigger proxy unvoting in
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
index a7a3f0c..d32279d 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
@@ -14,14 +14,14 @@
- interrupts: The lpass watchdog interrupt
- vdd_cx-supply: Reference to the regulator that supplies the vdd_cx domain.
- qcom,firmware-name: Base name of the firmware image. Ex. "lpass"
-- qcom,gpio-err-fatal: GPIO used by the lpass to indicate error fatal to the apps.
-- qcom,gpio-err-ready: GPIO used by the lpass to indicate apps error service is ready.
-- qcom,gpio-force-stop: GPIO used by the apps to force the lpass to shutdown.
-- qcom,gpio-proxy-unvote: GPIO used by the lpass to indicate apps clock is ready.
Optional properties:
- vdd_pll-supply: Reference to the regulator that supplies the PLL's rail.
- qcom,vdd_pll: Voltage to be set for the PLL's rail.
+- qcom,gpio-err-fatal: GPIO used by the lpass to indicate error fatal to the apps.
+- qcom,gpio-err-ready: GPIO used by the lpass to indicate apps error service is ready.
+- qcom,gpio-proxy-unvote: GPIO used by the lpass to indicate apps clock is ready.
+- qcom,gpio-force-stop: GPIO used by the apps to force the lpass to shutdown.
Example:
qcom,lpass@fe200000 {
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
index d6980ac..0a3789a 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
@@ -15,13 +15,6 @@
- vdd_cx-supply: Reference to the regulator that supplies the vdd_cx domain.
- vdd_mx-supply: Reference to the regulator that supplies the memory rail.
- qcom,firmware-name: Base name of the firmware image. Ex. "mdsp"
-- qcom,gpio-err-fatal: GPIO used by the modem to indicate error fatal to the apps.
-- qcom,gpio-err-ready: GPIO used by the modem to indicate error ready to the apps.
-- qcom,gpio-proxy-unvote: GPIO used by the modem to trigger proxy unvoting in
- the apps.
-- qcom,gpio-force-stop: GPIO used by the apps to force the modem to shutdown.
-- qcom,gpio-stop-ack: GPIO used by the modem to ack force stop or a graceful stop
- to the apps.
Optional properties:
- vdd_mss-supply: Reference to the regulator that supplies the processor.
@@ -35,6 +28,13 @@
- qcom,is-not-loadable: Boolean- Present if the image does not need to
be loaded.
- qcom,pil-self-auth: Boolean- True if authentication is required.
+- qcom,gpio-err-fatal: GPIO used by the modem to indicate error fatal to the apps.
+- qcom,gpio-err-ready: GPIO used by the modem to indicate error ready to the apps.
+- qcom,gpio-proxy-unvote: GPIO used by the modem to trigger proxy unvoting in
+ the apps.
+- qcom,gpio-force-stop: GPIO used by the apps to force the modem to shutdown.
+- qcom,gpio-stop-ack: GPIO used by the modem to ack force stop or a graceful stop
+ to the apps.
Example:
qcom,mss@fc880000 {
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
new file mode 100644
index 0000000..2d730e3
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
@@ -0,0 +1,186 @@
+== Introduction ==
+
+Hardware modules that control pin multiplexing or configuration parameters
+such as pull-up/down, tri-state, drive-strength etc are designated as pin
+controllers. Each pin controller must be represented as a node in device tree,
+just like any other hardware module.
+
+Hardware modules whose signals are affected by pin configuration are
+designated client devices. Again, each client device must be represented as a
+node in device tree, just like any other hardware module.
+
+For a client device to operate correctly, certain pin controllers must
+set up certain specific pin configurations. Some client devices need a
+single static pin configuration, e.g. set up during initialization. Others
+need to reconfigure pins at run-time, for example to tri-state pins when the
+device is inactive. Hence, each client device can define a set of named
+states. The number and names of those states is defined by the client device's
+own binding.
+
+The common pinctrl bindings defined in this file provide an infrastructure
+for client device device tree nodes to map those state names to the pin
+configuration used by those states.
+
+Note that pin controllers themselves may also be client devices of themselves.
+For example, a pin controller may set up its own "active" state when the
+driver loads. This would allow representing a board's static pin configuration
+in a single place, rather than splitting it across multiple client device
+nodes. The decision to do this or not somewhat rests with the author of
+individual board device tree files, and any requirements imposed by the
+bindings for the individual client devices in use by that board, i.e. whether
+they require certain specific named states for dynamic pin configuration.
+
+== Pinctrl client devices ==
+
+For each client device individually, every pin state is assigned an integer
+ID. These numbers start at 0, and are contiguous. For each state ID, a unique
+property exists to define the pin configuration. Each state may also be
+assigned a name. When names are used, another property exists to map from
+those names to the integer IDs.
+
+Each client device's own binding determines the set of states the must be
+defined in its device tree node, and whether to define the set of state
+IDs that must be provided, or whether to define the set of state names that
+must be provided.
+
+Required properties:
+pinctrl-0: List of phandles, each pointing at a pin configuration
+ node. These referenced pin configuration nodes must be child
+ nodes of the pin controller that they configure. Multiple
+ entries may exist in this list so that multiple pin
+ controllers may be configured, or so that a state may be built
+ from multiple nodes for a single pin controller, each
+ contributing part of the overall configuration. See the next
+ section of this document for details of the format of these
+ pin configuration nodes.
+
+ In some cases, it may be useful to define a state, but for it
+ to be empty. This may be required when a common IP block is
+ used in an SoC either without a pin controller, or where the
+ pin controller does not affect the HW module in question. If
+ the binding for that IP block requires certain pin states to
+ exist, they must still be defined, but may be left empty.
+
+Optional properties:
+pinctrl-1: List of phandles, each pointing at a pin configuration
+ node within a pin controller.
+...
+pinctrl-n: List of phandles, each pointing at a pin configuration
+ node within a pin controller.
+pinctrl-names: The list of names to assign states. List entry 0 defines the
+ name for integer state ID 0, list entry 1 for state ID 1, and
+ so on.
+
+For example:
+
+ /* For a client device requiring named states */
+ device {
+ pinctrl-names = "active", "idle";
+ pinctrl-0 = <&state_0_node_a>;
+ pinctrl-1 = <&state_1_node_a &state_1_node_b>;
+ };
+
+ /* For the same device if using state IDs */
+ device {
+ pinctrl-0 = <&state_0_node_a>;
+ pinctrl-1 = <&state_1_node_a &state_1_node_b>;
+ };
+
+ /*
+ * For an IP block whose binding supports pin configuration,
+ * but in use on an SoC that doesn't have any pin control hardware
+ */
+ device {
+ pinctrl-names = "active", "idle";
+ pinctrl-0 = <>;
+ pinctrl-1 = <>;
+ };
+
+== Pin controller devices ==
+
+Pin controller devices should contain the pin configuration nodes that client
+devices reference.
+
+For example:
+
+ pincontroller {
+ ... /* Standard DT properties for the device itself elided */
+
+ state_0_node_a {
+ ...
+ };
+ state_1_node_a {
+ ...
+ };
+ state_1_node_b {
+ ...
+ };
+ }
+
+The contents of each of those pin configuration child nodes is defined
+entirely by the binding for the individual pin controller device. There
+exists no common standard for this content.
+
+The pin configuration nodes need not be direct children of the pin controller
+device; they may be grandchildren, for example. Whether this is legal, and
+whether there is any interaction between the child and intermediate parent
+nodes, is again defined entirely by the binding for the individual pin
+controller device.
+
+== Using generic pinconfig options ==
+
+Generic pinconfig parameters can be used by defining a separate node containing
+the applicable parameters (and optional values), like:
+
+pcfg_pull_up: pcfg_pull_up {
+ bias-pull-up;
+ drive-strength = <20>;
+};
+
+This node should then be referenced in the appropriate pinctrl node as a phandle
+and parsed in the driver using the pinconf_generic_parse_dt_config function.
+
+Supported configuration parameters are:
+
+bias-disable - disable any pin bias
+bias-high-impedance - high impedance mode ("third-state", "floating")
+bias-bus-hold - latch weakly
+bias-pull-up - pull up the pin
+bias-pull-down - pull down the pin
+bias-pull-pin-default - use pin-default pull state
+drive-push-pull - drive actively high and low
+drive-open-drain - drive with open drain
+drive-open-source - drive with open source
+drive-strength - sink or source at most X mA
+input-schmitt-enable - enable schmitt-trigger mode
+input-schmitt-disable - disable schmitt-trigger mode
+input-schmitt - run in schmitt-trigger mode with hysteresis X
+input-debounce - debounce mode with debound time X
+power-source - select power source X
+slew-rate - use slew-rate X
+low-power-enable - enable low power mode
+low-power-disable - disable low power mode
+output-low - set the pin to output mode with low level
+output-high - set the pin to output mode with high level
+
+Arguments for parameters:
+
+- bias-pull-up, -down and -pin-default take as optional argument 0 to disable
+ the pull, on hardware supporting it the pull strength in Ohm. bias-disable
+ will also disable any active pull.
+
+- drive-strength takes as argument the target strength in mA.
+
+- input-schmitt takes as argument the adjustable hysteresis in a
+ driver-specific format
+
+- input-debounce takes the debounce time as argument or 0 to disable debouncing
+
+- power-source argument is the custom value describing the source to select
+
+- slew-rate takes as argument the target rate in a driver-specific format
+
+All parameters not listed here, do not take an argument.
+
+More in-depth documentation on these parameters can be found in
+<include/linux/pinctrl/pinconfig-generic.h>
diff --git a/Documentation/devicetree/bindings/power/qpnp-bms.txt b/Documentation/devicetree/bindings/power/qpnp-bms.txt
index 3cac311..0672f14 100644
--- a/Documentation/devicetree/bindings/power/qpnp-bms.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-bms.txt
@@ -13,6 +13,11 @@
to determine whether the BMS is using an internal or external
rsense to accumulate the Coulomb Counter and read current.
+Additionally, an optional subnode may be included:
+- qcom,battery-data : A phandle to a node containing the available batterydata
+ profiles. See the batterydata bindings documentation for more
+ details.
+
Parent node required properties:
- compatible : should be "qcom,qpnp-bms" for the BM driver.
- qcom,r-sense-uohm : sensor resistance in in micro-ohms.
@@ -77,6 +82,10 @@
number of the FCC measurement cycles required to
generate an FCC update. This is applicable only
if the FCC learning is enabled.
+- qcom,fcc-resolution: An integer which defines the fcc resolution used
+ for storing the FCC(mAh) in the 8-bit BMS register.
+ For example - A value of 10 indicates:
+ FCC value (in mAh) = (8-bit register value) * 10.
Parent node optional properties:
- qcom,ignore-shutdown-soc: A boolean that controls whether BMS will
@@ -138,6 +147,7 @@
qcom,high-ocv-correction-limit-uv = <50>;
qcom,hold-soc-est = <3>;
qcom,tm-temp-margin = <5000>;
+ qcom,battery-data = <&mtp_batterydata>;
qcom,bms-iadc@3800 {
reg = <0x3800 0x100>;
diff --git a/Documentation/devicetree/bindings/power/qpnp-charger.txt b/Documentation/devicetree/bindings/power/qpnp-charger.txt
index 6e125f2..e3c3555 100644
--- a/Documentation/devicetree/bindings/power/qpnp-charger.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-charger.txt
@@ -65,10 +65,21 @@
detection, "bpd_thm_id" selects both.
If the property is not set, the temperatue pin will
be used.
+- qcom,btc-disabled: If flag is set battery hot and cold monitoring is
+ disabled in hardware. This monitoring is turned on
+ by default.
+- qcom,batt-hot-percent: Specify a supported hot threshold percentage.
+ Supported thresholds: 25% and 35%. If none is specified
+ hardware defaults will be used.
+- qcom,batt-cold-percent: Specify a supported cold threshold percentage.
+ Supported thresholds: 70% and 80%. If none is specified
+ hardware defaults will be used.
- otg-parent-supply Specify a phandle to a parent supply regulator
for the OTG regulator.
- boost-parent-supply Specify a phandle to a parent supply regulator
for the boost regulator.
+- qcom,resume-soc Capacity in percent at which charging should resume
+ when a fully charged battery drops below this level.
Sub node required structure:
- A qcom,chg node must be a child of an SPMI node that has specified
@@ -182,6 +193,9 @@
qcom,warm-bat-mv = <4100>;
qcom,ibatmax-cool-ma = <350>;
qcom,vbatdet-delta-mv = <60>;
+ qcom,batt-hot-percent = <25>;
+ qcom,batt-cold-percent = <85>;
+ qcom,btc-disabled = <0>;
qcom,chgr@1000 {
reg = <0x1000 0x100>;
diff --git a/Documentation/devicetree/bindings/pwm/qpnp-pwm.txt b/Documentation/devicetree/bindings/pwm/qpnp-pwm.txt
index 83ce3f8..95be46c 100644
--- a/Documentation/devicetree/bindings/pwm/qpnp-pwm.txt
+++ b/Documentation/devicetree/bindings/pwm/qpnp-pwm.txt
@@ -11,17 +11,10 @@
Required device bindings:
- compatible: should be "qcom,qpnp-pwm"
-- reg: Offset and length of the controller's LPG channel register,
- and LPG look-up table (LUT). The LPG look-up table is a
- contiguous address space that is populated with PWM values.
- The size of PWM value is 9 bit and the size of each
- entry of the table is 8 bit. Thus, two entries are used
- to fill each PWM value. The lower entry is used for PWM
- LSB byte and higher entry is used for PWM MSB bit.
-- reg-names: Names for the above registers.
+- reg: Offset and length of the controller's LPG channel register.
+- reg-names: Name for the above register.
"qpnp-lpg-channel-base" = physical base address of the
controller's LPG channel register.
- "qpnp-lpg-lut-base" = physical base address of LPG LUT.
- qcom,channel-id: channel Id for the PWM.
Optional device bindings:
@@ -52,12 +45,20 @@
duty cycle percentages is populated. The size of the list cannot exceed
the size of the LPG look-up table.
-- qcom,period: PWM period time in microseconds.
-- qcom,duty-percents: List of entries for look-up table
-- cell-index: Index of look-up table that should be used to start
- filling up the duty-pct list. start-idx + size of list
- cannot exceed the size of look-up table.
-- label: "lpg"
+- reg: Offset and length of LPG look-up table (LUT). The LPG look-up table is a
+ contiguous address space that is populated with PWM values.
+ The size of PWM value is 9 bit and the size of each
+ entry of the table is 8 bit. Thus, two entries are used
+ to fill each PWM value. The lower entry is used for PWM
+ LSB byte and higher entry is used for PWM MSB bit.
+- reg-names: Name for the above register.
+ "qpnp-lpg-lut-base" = physical base address of LPG LUT.
+- qcom,period: PWM period time in microseconds.
+- qcom,duty-percents: List of entries for look-up table
+- cell-index: Index of look-up table that should be used to start
+ filling up the duty-pct list. start-idx + size of list
+ cannot exceed the size of look-up table.
+- label: "lpg"
Optional bindings to support LPG feature:
diff --git a/Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt b/Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt
index 6b090fa..64f2ddd 100644
--- a/Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt
+++ b/Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt
@@ -44,6 +44,17 @@
- qcom,rxreg-access: This boolean indicates that slimbus RX should use direct
register access to receive data. This flag is only needed if
BAM pipe is not available to receive data from slimbus
+ - qcom,apps-ch-pipes: This value represents BAM pipe-mask used by application
+ processor for data channels. If this property is not defined,
+ default mask of 0x3F000000 is used indicating apps can use 6
+ pipes from 24-29.
+ - qcom,ea-pc: This value represents product code (PC) field of enumeration
+ address (EA) for the Qualcomm slimbus controller hardware.
+ This value is needed if data-channels originating from apps
+ are to be used, so that application processor can query
+ logical address of the ported generic device to be used.
+ Other than PC, fields of EA are same across platforms.
+
Example:
slim@fe12f000 {
cell-index = <1>;
@@ -55,4 +66,6 @@
interrupt-names = "slimbus_irq", "slimbus_bam_irq";
qcom,min-clk-gear = <10>;
qcom,rxreg-access;
+ qcom,apps-ch-pipes = <0x60000000>;
+ qcom,ea-pc = <0x30>;
};
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 4c6569e..b618597 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -131,15 +131,9 @@
* msm-auxpcm
-[First Level Nodes]
-
Required properties:
- - compatible : "qcom,msm-auxpcm-resource"
-
- - qcom,msm-cpudai-auxpcm-clk: clock for auxpcm. The first value is
- for 8khz mode, the second is for
- 16khz
+ - compatible : "qcom,msm-auxpcm-dev"
- qcom,msm-cpudai-auxpcm-mode: mode information. The first value is
for 8khz mode, the second is for
@@ -174,16 +168,10 @@
first value is for 8khz mode, the
second is for auxpcm
-[Second Level Nodes]
-
-Required Properties:
-
- - qcom,msm-auxpcm-dev-id: This property specifies the device
- port id.
- For Rx device, the port id is 4106
- and for Tx device, the port id is 4107
-
- - compatible: "qcom,msm-auxpcm-dev"
+ - qcom,msm-auxpcm-interface: name of AUXPCM interface "primary"
+ indicates primary AUXPCM interface
+ "secondary" indicates secondary
+ AUXPCM interface
* msm-pcm-hostless
@@ -378,37 +366,17 @@
};
};
- qcom,msm-auxpcm {
- compatible = "qcom,msm-auxpcm-resource";
- qcom,msm-cpudai-auxpcm-clk = "pcm_clk";
- qcom,msm-cpudai-auxpcm-mode = <0>, <0>;
- qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
- qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
- qcom,msm-cpudai-auxpcm-quant = <2>, <2>;
- qcom,msm-cpudai-auxpcm-slot = <1>, <1>;
- qcom,msm-cpudai-auxpcm-data = <0>, <0>;
- qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
-
- qcom,msm-prim-auxpcm-rx {
- qcom,msm-auxpcm-dev-id = <4106>;
- compatible = "qcom,msm-auxpcm-dev";
- };
-
- qcom,msm-prim-auxpcm-tx {
- qcom,msm-auxpcm-dev-id = <4107>;
- compatible = "qcom,msm-auxpcm-dev";
- };
-
- qcom,msm-sec-auxpcm-rx {
- qcom,msm-auxpcm-dev-id = <4108>;
- compatible = "qcom,msm-auxpcm-dev";
- };
-
- qcom,msm-sec-auxpcm-tx {
- qcom,msm-auxpcm-dev-id = <4109>;
- compatible = "qcom,msm-auxpcm-dev";
- };
- };
+ qcom,msm-pri-auxpcm {
+ qcom,msm-cpudai-auxpcm-mode = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
+ qcom,msm-cpudai-auxpcm-quant = <2>, <2>;
+ qcom,msm-cpudai-auxpcm-slot = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-data = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
+ qcom,msm-auxpcm-interface = "primary";
+ compatible = "qcom,msm-auxpcm-dev";
+ };
qcom,msm-pcm-hostless {
compatible = "qcom,msm-pcm-hostless";
@@ -693,7 +661,9 @@
prim-gpio-tert : Primary AUXPCM shares GPIOs with Tertiary MI2S
Optional Properties:
-- qcom,us-euro-gpios : GPIO on which gnd/mic swap signal is coming.
+- qcom,cdc-us-euro-gpios : GPIO on which gnd/mic swap signal is coming.
+- qcom,cdc-lineout-spkr-gpios : GPIO which controls external PAs to enable Lineout1/2 speaker
+- qcom,cdc-vdd-spkr-gpios : GPIO which controls PA for VDD speaker
Example:
@@ -707,4 +677,6 @@
qcom,prim-auxpcm-gpio-dout = <&msmgpio 66 0>;
qcom,prim-auxpcm-gpio-set = "prim-gpio-prim";
qcom,cdc-us-euro-gpios = <&msmgpio 69 0>;
+ qcom,cdc-lineout-spkr-gpios = <&pm8226_gpios 2 0>;
+ qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 3 0>;
};
diff --git a/Documentation/devicetree/bindings/spi/spi_qsd.txt b/Documentation/devicetree/bindings/spi/spi_qsd.txt
index f16bcbc..1504dc0 100644
--- a/Documentation/devicetree/bindings/spi/spi_qsd.txt
+++ b/Documentation/devicetree/bindings/spi/spi_qsd.txt
@@ -17,9 +17,13 @@
'spi{n}' where n is the bus number.
Optional properties:
-- gpios : Specifies the gpio pins to be used for SPI CLK, MISO, MOSI in
- that order.
-- cs-gpios : Specifies the gpio pins to be used for chipselects.
+- qcom,gpio-mosi : GPIO pin number of the MOSI bus line.
+- qcom,gpio-miso : GPIO pin number of the MISO bus line.
+- qcom,gpio-clk : GPIO pin number of the CLK bus line.
+- qcom,gpio-cs0 : GPIO pin number of the chipselect0 bus line.
+- qcom,gpio-cs1 : GPIO pin number of the chipselect1 bus line.
+- qcom,gpio-cs2 : GPIO pin number of the chipselect2 bus line.
+- qcom,gpio-cs3 : GPIO pin number of the chipselect3 bus line.
- qcom,infinite-mode: When missing or set to zero, QUP uses infinite-mode. When
value is non-zero, the value is the number of words in maximum transfer
length.
@@ -77,10 +81,10 @@
spi-max-frequency = <19200000>;
#address-cells = <1>;
#size-cells = <0>;
- gpios = <&msmgpio 3 0>, /* CLK */
- <&msmgpio 1 0>, /* MISO */
- <&msmgpio 0 0>; /* MOSI */
- cs-gpios = <&msmgpio 9 0>;
+ qcom,gpio-mosi = <&msmgpio 0 0>;
+ qcom,gpio-miso = <&msmgpio 1 0>;
+ qcom,gpio-clk = <&msmgpio 3 0>;
+ qcom,gpio-cs2 = <&msmgpio 9 0>;
qcom,infinite-mode = <0>;
qcom,use-bam;
diff --git a/Documentation/devicetree/bindings/tty/serial/msm_serial_hs.txt b/Documentation/devicetree/bindings/tty/serial/msm_serial_hs.txt
index 96c9486..762d40f 100644
--- a/Documentation/devicetree/bindings/tty/serial/msm_serial_hs.txt
+++ b/Documentation/devicetree/bindings/tty/serial/msm_serial_hs.txt
@@ -12,6 +12,11 @@
- interrupt-names :
- "core_irq" to be used as uart irq
- "bam irq" to be used as bam irq
+- #interrupt-cells: Specifies the number of cells needed to encode an interrupt
+ source. The type shall be a <u32> and the value shall be 1
+- #address-cells: Specifies the number of cells needed to encode an address.
+ The type shall be <u32> and the value shall be 0
+- interrupt-parent = It is needed for interrupt mapping
- bam-tx-ep-pipe-index : BAM TX Endpoint Pipe Index for HSUART
- bam-rx-ep-pipe-index : BAM RX Endpoint Pipe Index for HSUART
@@ -35,8 +40,13 @@
reg = <0xf995d000 0x1000>,
<0xf9944000 0x5000>;
reg-names = "core_mem", "bam_mem";
- interrupts = <0 113 0>, <0 239 0>;
interrupt-names = "core_irq", "bam_irq";
+ #address-cells = <0>;
+ interrupt-parent = <&uart7>;
+ interrupts = <0 1>;
+ #interrupt-cells = <1>;
+ interrupt-map = <0 &intc 0 113 0
+ 1 &intc 0 239 0>
qcom,bam-tx-ep-pipe-index = <0>;
qcom,bam-rx-ep-pipe-index = <1>;
};
@@ -50,10 +60,10 @@
case where there is nothing connected and we want to use internal loopback mode
for uart.
- qcom, wakeup_irq : UART RX GPIO IRQ line to be configured as wakeup source.
-- qcom,inject_rx_on_wakeup : inject_rx_on_wakeup enables feature where on
+- qcom,inject-rx-on-wakeup : inject_rx_on_wakeup enables feature where on
receiving interrupt with UART RX GPIO IRQ line (i.e. above wakeup_irq property),
HSUART driver injects provided character with property rx_to_inject.
-- qcom, rx_to_inject : The character to be inserted on wakeup.
+- qcom, rx-char-to-inject : The character to be inserted on wakeup.
- Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for
below optional properties:
- qcom,msm_bus,name
@@ -80,13 +90,21 @@
reg = <0x19c40000 0x1000">,
<0xf9944000 0x5000>;
reg-names = "core_mem", "bam_mem";
- interrupts = <0 113 0>, <0 239 0>;
- interrupt-names = "core_irq", "bam_irq";
-
+ interrupt-names = "core_irq", "bam_irq", "wakeup_irq";
+ #address-cells = <0>;
+ interrupt-parent = <&uart7>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 113 0
+ 1 &intc 0 239 0
+ 2 &msmgpio 42 0>;
qcom,tx-gpio = <&msmgpio 41 0x00>;
qcom,rx-gpio = <&msmgpio 42 0x00>;
qcom,cts-gpio = <&msmgpio 43 0x00>;
qcom,rfr-gpio = <&msmgpio 44 0x00>;
+ qcom,inject-rx-on-wakeup = <1>;
+ qcom,rx-char-to-inject = <0xFD>;
qcom,bam-tx-ep-pipe-index = <0>;
qcom,bam-rx-ep-pipe-index = <1>;
diff --git a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
index e724c62..f2707f6 100644
--- a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
@@ -73,6 +73,11 @@
programs the CERR to 3 by default. When this flag is true, CERR is set to
zero and transaction errors are ignored.
+- hsic,reset-delay: If present then add the given delay time (ms) between
+ the reset and enumeration. Since some devices might take more than 100ms
+ for initialization when receiving the bus reset, add delay to avoid the
+ problem that enmueration is before device initialization done.
+
- Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for
below optional properties:
- qcom,msm_bus,name
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index ac314ea..ad1b5ad 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -81,6 +81,11 @@
interrupt threshold (ITC), when log2_itc is between 1 to 7.
- qcom,hsusb-l1-supported: If present, the device supports l1 (Link power
management).
+- qcom,no-selective-suspend: If present selective suspend is disabled on hub ports.
+- qcom,hsusb-otg-dpsehv-int: If present, indicates mpm interrupt to be configured
+ 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.
Example HSUSB OTG controller device node :
usb@f9690000 {
@@ -105,6 +110,8 @@
HSUSB_3p3-supply = <&pm8226_l20>;
qcom,vdd-voltage-level = <1 5 7>;
qcom,dp-manual-pullup;
+ qcom,hsusb-otg-dpsehv-int = <49>;
+ qcom,hsusb-otg-dmsehv-int = <58>;
qcom,msm_bus,name = "usb2";
qcom,msm_bus,num_cases = <2>;
qcom,msm_bus,active_only = <0>;
@@ -128,6 +135,9 @@
Optional properties :
- qcom,usb2-enable-hsphy2: If present, select second PHY for USB operation.
+- qcom,resume-gpio: if present then peripheral connected to usb controller
+ cannot wakeup from XO shutdown using in-band usb bus resume. Use resume
+ gpio to wakeup peripheral.
Example MSM HSUSB EHCI controller device node :
ehci: qcom,ehci-host@f9a55000 {
diff --git a/Documentation/devicetree/bindings/usb/msm-ssusb.txt b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
index 282257c..ff7b03d 100644
--- a/Documentation/devicetree/bindings/usb/msm-ssusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
@@ -47,6 +47,8 @@
bits 20-25 PARAMETER_OVERRIDE_D
- qcom,skip-charger-detection: If present then charger detection using BC1.2
is not supported and attached host should always be assumed as SDP.
+- USB3_GDSC-supply : phandle to the globally distributed switch controller
+ regulator node to the USB controller.
Sub nodes:
- Sub node for "DWC3- USB3 controller".
@@ -66,6 +68,7 @@
HSUSB_1p8-supply = <&pm8941_l6>;
HSUSB_3p3-supply = <&pm8941_l24>;
vbus_dwc3-supply = <&pm8941_mvs1>;
+ USB3_GDSC-supply = <&gdsc_usb30>;
qcom,dwc-usb3-msm-dbm-eps = <4>
qcom,vdd-voltage-level = <1 5 7>;
qcom,dwc-hsphy-init = <0x00D195A4>;
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 0ebbe63..a3a3807 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -8,6 +8,7 @@
apm Applied Micro Circuits Corporation (APM)
arm ARM Ltd.
atmel Atmel Corporation
+bosch Bosch Sensortec GmbH
cavium Cavium, Inc.
chrp Common Hardware Reference Platform
cortina Cortina Systems, Inc.
@@ -23,6 +24,7 @@
ibm International Business Machines (IBM)
idt Integrated Device Technologies, Inc.
intercontrol Inter Control Group
+invn InvenSense Inc.
linux Linux-specific binding
kionix Kionix Inc.
marvell Marvell Technology Group Ltd.
diff --git a/arch/arm/boot/dts/apq8026-xpm.dts b/arch/arm/boot/dts/apq8026-v1-cdp.dts
similarity index 79%
copy from arch/arm/boot/dts/apq8026-xpm.dts
copy to arch/arm/boot/dts/apq8026-v1-cdp.dts
index 67152af..8c6daa6 100644
--- a/arch/arm/boot/dts/apq8026-xpm.dts
+++ b/arch/arm/boot/dts/apq8026-v1-cdp.dts
@@ -12,11 +12,11 @@
/dts-v1/;
-/include/ "apq8026.dtsi"
+/include/ "apq8026-v1.dtsi"
/include/ "msm8226-cdp.dtsi"
/ {
- model = "Qualcomm APQ 8026 XPM";
- compatible = "qcom,apq8026-xpm", "qcom,apq8026", "qcom,xpm";
- qcom,msm-id = <199 14 0>;
+ model = "Qualcomm APQ 8026 CDP";
+ compatible = "qcom,apq8026-cdp", "qcom,apq8026", "qcom,cdp";
+ qcom,msm-id = <199 1 0>;
};
diff --git a/arch/arm/boot/dts/apq8026-mtp.dts b/arch/arm/boot/dts/apq8026-v1-mtp.dts
similarity index 95%
rename from arch/arm/boot/dts/apq8026-mtp.dts
rename to arch/arm/boot/dts/apq8026-v1-mtp.dts
index e14a6856..b89c676 100644
--- a/arch/arm/boot/dts/apq8026-mtp.dts
+++ b/arch/arm/boot/dts/apq8026-v1-mtp.dts
@@ -12,7 +12,7 @@
/dts-v1/;
-/include/ "apq8026.dtsi"
+/include/ "apq8026-v1.dtsi"
/include/ "msm8226-mtp.dtsi"
/ {
diff --git a/arch/arm/boot/dts/apq8026-xpm.dts b/arch/arm/boot/dts/apq8026-v1-xpm.dts
similarity index 95%
rename from arch/arm/boot/dts/apq8026-xpm.dts
rename to arch/arm/boot/dts/apq8026-v1-xpm.dts
index 67152af..8c97823 100644
--- a/arch/arm/boot/dts/apq8026-xpm.dts
+++ b/arch/arm/boot/dts/apq8026-v1-xpm.dts
@@ -12,7 +12,7 @@
/dts-v1/;
-/include/ "apq8026.dtsi"
+/include/ "apq8026-v1.dtsi"
/include/ "msm8226-cdp.dtsi"
/ {
diff --git a/arch/arm/boot/dts/apq8026.dtsi b/arch/arm/boot/dts/apq8026-v1.dtsi
similarity index 88%
rename from arch/arm/boot/dts/apq8026.dtsi
rename to arch/arm/boot/dts/apq8026-v1.dtsi
index db6576a..7fbfcb5 100644
--- a/arch/arm/boot/dts/apq8026.dtsi
+++ b/arch/arm/boot/dts/apq8026-v1.dtsi
@@ -16,9 +16,14 @@
* file.
*/
-/include/ "msm8226.dtsi"
+/include/ "msm8226-v1.dtsi"
/ {
model = "Qualcomm APQ 8026";
compatible = "qcom,apq8026";
};
+
+&tsens {
+ qcom,sensors = <4>;
+ qcom,slope = <2901 2846 3038 2955>;
+};
diff --git a/arch/arm/boot/dts/apq8026-xpm.dts b/arch/arm/boot/dts/apq8026-v2-cdp.dts
similarity index 78%
copy from arch/arm/boot/dts/apq8026-xpm.dts
copy to arch/arm/boot/dts/apq8026-v2-cdp.dts
index 67152af..74608dd 100644
--- a/arch/arm/boot/dts/apq8026-xpm.dts
+++ b/arch/arm/boot/dts/apq8026-v2-cdp.dts
@@ -12,11 +12,11 @@
/dts-v1/;
-/include/ "apq8026.dtsi"
+/include/ "apq8026-v2.dtsi"
/include/ "msm8226-cdp.dtsi"
/ {
- model = "Qualcomm APQ 8026 XPM";
- compatible = "qcom,apq8026-xpm", "qcom,apq8026", "qcom,xpm";
- qcom,msm-id = <199 14 0>;
+ model = "Qualcomm APQ 8026v2 CDP";
+ compatible = "qcom,apq8026-cdp", "qcom,apq8026", "qcom,cdp";
+ qcom,msm-id = <199 1 0x20000>;
};
diff --git a/arch/arm/boot/dts/apq8026-mtp.dts b/arch/arm/boot/dts/apq8026-v2-mtp.dts
similarity index 86%
copy from arch/arm/boot/dts/apq8026-mtp.dts
copy to arch/arm/boot/dts/apq8026-v2-mtp.dts
index e14a6856..c6b7f2a 100644
--- a/arch/arm/boot/dts/apq8026-mtp.dts
+++ b/arch/arm/boot/dts/apq8026-v2-mtp.dts
@@ -12,11 +12,11 @@
/dts-v1/;
-/include/ "apq8026.dtsi"
+/include/ "apq8026-v2.dtsi"
/include/ "msm8226-mtp.dtsi"
/ {
- model = "Qualcomm APQ 8026 MTP";
+ model = "Qualcomm APQ 8026v2 MTP";
compatible = "qcom,apq8026-mtp", "qcom,apq8026", "qcom,mtp";
- qcom,msm-id = <199 8 0>;
+ qcom,msm-id = <199 8 0x20000>;
};
diff --git a/arch/arm/boot/dts/apq8026-xpm.dts b/arch/arm/boot/dts/apq8026-v2-xpm.dts
similarity index 86%
copy from arch/arm/boot/dts/apq8026-xpm.dts
copy to arch/arm/boot/dts/apq8026-v2-xpm.dts
index 67152af..42acd98 100644
--- a/arch/arm/boot/dts/apq8026-xpm.dts
+++ b/arch/arm/boot/dts/apq8026-v2-xpm.dts
@@ -12,11 +12,11 @@
/dts-v1/;
-/include/ "apq8026.dtsi"
+/include/ "apq8026-v2.dtsi"
/include/ "msm8226-cdp.dtsi"
/ {
- model = "Qualcomm APQ 8026 XPM";
+ model = "Qualcomm APQ 8026v2 XPM";
compatible = "qcom,apq8026-xpm", "qcom,apq8026", "qcom,xpm";
- qcom,msm-id = <199 14 0>;
+ qcom,msm-id = <199 14 0x20000>;
};
diff --git a/arch/arm/boot/dts/apq8026.dtsi b/arch/arm/boot/dts/apq8026-v2.dtsi
similarity index 87%
copy from arch/arm/boot/dts/apq8026.dtsi
copy to arch/arm/boot/dts/apq8026-v2.dtsi
index db6576a..4c0d3ce 100644
--- a/arch/arm/boot/dts/apq8026.dtsi
+++ b/arch/arm/boot/dts/apq8026-v2.dtsi
@@ -16,9 +16,14 @@
* file.
*/
-/include/ "msm8226.dtsi"
+/include/ "msm8226-v2.dtsi"
/ {
model = "Qualcomm APQ 8026";
compatible = "qcom,apq8026";
};
+
+&tsens {
+ qcom,sensors = <6>;
+ qcom,slope = <2901 2846 3038 2955 2901 2846>;
+};
diff --git a/arch/arm/boot/dts/apq8074-dragonboard.dtsi b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
index 4b20e9f..53e9b3b 100644
--- a/arch/arm/boot/dts/apq8074-dragonboard.dtsi
+++ b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
@@ -14,6 +14,10 @@
/include/ "msm8974-camera-sensor-dragonboard.dtsi"
/include/ "msm8974-leds.dtsi"
+&vph_pwr_vreg {
+ status = "ok";
+};
+
&soc {
serial@f991e000 {
status = "ok";
@@ -62,6 +66,10 @@
#size-cells = <1>;
ranges;
smsc,reset-gpio = <&pm8941_gpios 8 0x00>;
+ /* Dragonboard has an always-on VBUS supply for HSIC hub,
+ * providing a dummy regulator for the hub driver
+ */
+ hub_vbus-supply = <&vph_pwr_vreg>;
hsic_host: hsic@f9a00000 {
compatible = "qcom,hsic-host";
@@ -183,10 +191,10 @@
"MIC BIAS2 External", "ANCRight Headset Mic",
"AMIC4", "MIC BIAS2 External",
"MIC BIAS2 External", "ANCLeft Headset Mic",
- "AMIC5", "MIC BIAS1 External",
- "MIC BIAS1 External", "Analog Mic6",
- "AMIC6", "MIC BIAS1 External",
- "MIC BIAS1 External", "Analog Mic7",
+ "AMIC5", "MIC BIAS4 External",
+ "MIC BIAS4 External", "Analog Mic6",
+ "AMIC6", "MIC BIAS3 External",
+ "MIC BIAS3 External", "Analog Mic7",
"DMIC1", "MIC BIAS3 External",
"MIC BIAS3 External", "Digital Mic1",
"DMIC2", "MIC BIAS3 External",
@@ -199,6 +207,15 @@
"MIC BIAS4 External", "Digital Mic5",
"DMIC6", "MIC BIAS4 External",
"MIC BIAS4 External", "Digital Mic6";
+
+
+ qcom,prim-auxpcm-gpio-clk = <&msmgpio 74 0>;
+ qcom,prim-auxpcm-gpio-sync = <&msmgpio 75 0>;
+ qcom,prim-auxpcm-gpio-din = <&msmgpio 76 0>;
+ qcom,prim-auxpcm-gpio-dout = <&msmgpio 77 0>;
+ qcom,prim-auxpcm-gpio-set = "prim-gpio-tert";
+
+ qcom,cdc-micbias2-headset-only;
};
qcom,pronto@fb21b000 {
@@ -273,6 +290,7 @@
};
&usb3 {
+ interrupts = <0>; /* remove pmic_id_irq; used by &usb_otg */
qcom,charging-disabled;
vbus_dwc3-supply = <0>;
dwc3@f9200000 {
@@ -282,8 +300,17 @@
&slim_msm {
taiko_codec {
+ qcom,cdc-micbias1-ext-cap;
qcom,cdc-micbias2-ext-cap;
qcom,cdc-micbias3-ext-cap;
+ qcom,cdc-micbias4-ext-cap;
+
+ /* If boot isn't available, vph_pwr_vreg can be used instead */
+ cdc-vdd-spkdrv-supply = <&pm8941_boost>;
+ qcom,cdc-vdd-spkdrv-voltage = <5000000 5000000>;
+ qcom,cdc-vdd-spkdrv-current = <1250000>;
+
+ qcom,cdc-on-demand-supplies = "cdc-vdd-spkdrv";
};
};
@@ -484,6 +511,7 @@
&pm8941_mpps {
mpp@a000 { /* MPP 1 */
+ status = "disabled";
};
mpp@a100 { /* MPP 2 */
@@ -524,52 +552,35 @@
};
&spi_epm {
- epm-adc@0 {
- compatible = "cy,epm-adc-cy8c5568lti-114";
- reg = <0>;
- interrupt-parent = <&msmgpio>;
- spi-max-frequency = <960000>;
- qcom,channels = <31>;
- qcom,gain = <50 50 50 50 50 100 50 50 50 50
- 50 50 50 50 100 50 50 50 50 100
- 50 50 50 100 50 50 50 1 1 1
- 1>;
- qcom,rsense = <40 10 10 25 10 1000 75 25 10 25
- 33 500 200 10 500 100 33 200 25 100
- 75 500 50 200 5 5 3 1 1 1
- 1>;
- qcom,channel-type = <0xf0000000>;
- };
+ status = "disabled";
};
-&spmi_bus {
- qcom,pm8941@1 {
- qcom,leds@d000 {
- qcom,rgb_2 {
- status = "ok";
- qcom,default-state = "on";
- qcom,turn-off-delay-ms = <1000>;
- };
+&pm8941_lsid1 {
+ qcom,leds@d000 {
+ qcom,rgb_2 {
+ status = "ok";
+ qcom,default-state = "on";
+ qcom,turn-off-delay-ms = <1000>;
};
+ };
- qcom,leds@d800 {
- status = "okay";
- qcom,wled_0 {
- label = "wled";
- linux,name = "wled:backlight";
- linux,default-trigger = "bkl-trigger";
- qcom,cs-out-en;
- qcom,op-fdbck = <1>;
- qcom,default-state = "on";
- qcom,max-current = <20>;
- qcom,ctrl-delay-us = <0>;
- qcom,boost-curr-lim = <3>;
- qcom,cp-sel = <0>;
- qcom,switch-freq = <2>;
- qcom,ovp-val = <1>;
- qcom,num-strings = <1>;
- qcom,id = <0>;
- };
+ qcom,leds@d800 {
+ status = "okay";
+ qcom,wled_0 {
+ label = "wled";
+ linux,name = "wled:backlight";
+ linux,default-trigger = "bkl-trigger";
+ qcom,cs-out-en;
+ qcom,op-fdbck = <1>;
+ qcom,default-state = "on";
+ qcom,max-current = <20>;
+ qcom,ctrl-delay-us = <0>;
+ qcom,boost-curr-lim = <3>;
+ qcom,cp-sel = <0>;
+ qcom,switch-freq = <2>;
+ qcom,ovp-val = <1>;
+ qcom,num-strings = <1>;
+ qcom,id = <0>;
};
};
};
diff --git a/arch/arm/boot/dts/apq8074-v2-cdp.dts b/arch/arm/boot/dts/apq8074-v2-cdp.dts
new file mode 100644
index 0000000..1dc0912
--- /dev/null
+++ b/arch/arm/boot/dts/apq8074-v2-cdp.dts
@@ -0,0 +1,34 @@
+/* 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.
+ */
+
+/dts-v1/;
+
+/include/ "apq8074-v2.dtsi"
+/include/ "msm8974-cdp.dtsi"
+
+/ {
+ model = "Qualcomm APQ 8074v2 CDP";
+ compatible = "qcom,apq8074-cdp", "qcom,apq8074", "qcom,cdp";
+ qcom,msm-id = <184 1 0x20000>;
+};
+
+&usb3 {
+ interrupt-parent = <&usb3>;
+ interrupts = <0 1>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0x0 0xffffffff>;
+ interrupt-map = <0x0 0 &intc 0 133 0
+ 0x0 1 &spmi_bus 0x0 0x0 0x9 0x0>;
+ interrupt-names = "hs_phy_irq", "pmic_id_irq";
+
+ qcom,misc-ref = <&pm8941_misc>;
+};
diff --git a/arch/arm/boot/dts/apq8074-v2-liquid.dts b/arch/arm/boot/dts/apq8074-v2-liquid.dts
index 4ec1cdd..a0ecb50 100644
--- a/arch/arm/boot/dts/apq8074-v2-liquid.dts
+++ b/arch/arm/boot/dts/apq8074-v2-liquid.dts
@@ -20,15 +20,3 @@
compatible = "qcom,apq8074-liquid", "qcom,apq8074", "qcom,liquid";
qcom,msm-id = <184 9 0x20000>;
};
-
-&usb3 {
- interrupt-parent = <&usb3>;
- interrupts = <0 1>;
- #interrupt-cells = <1>;
- interrupt-map-mask = <0x0 0xffffffff>;
- interrupt-map = <0x0 0 &intc 0 133 0
- 0x0 1 &spmi_bus 0x0 0x0 0x9 0x0>;
- interrupt-names = "hs_phy_irq", "pmic_id_irq";
-
- qcom,misc-ref = <&pm8941_misc>;
-};
diff --git a/arch/arm/boot/dts/apq8084-coresight.dtsi b/arch/arm/boot/dts/apq8084-coresight.dtsi
index 610d80b..1905e3b 100644
--- a/arch/arm/boot/dts/apq8084-coresight.dtsi
+++ b/arch/arm/boot/dts/apq8084-coresight.dtsi
@@ -23,6 +23,7 @@
coresight-id = <0>;
coresight-name = "coresight-tmc-etr";
coresight-nr-inports = <1>;
+ coresight-ctis = <&cti0 &cti8>;
};
replicator: replicator@fc324000 {
@@ -50,6 +51,7 @@
coresight-child-list = <&replicator>;
coresight-child-ports = <0>;
coresight-default-sink;
+ coresight-ctis = <&cti0 &cti8>;
};
funnel_merg: funnel@fc323000 {
@@ -142,4 +144,144 @@
qcom,blk-size = <3>;
};
+
+ cti0: cti@fc310000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc310000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <15>;
+ coresight-name = "coresight-cti0";
+ coresight-nr-inports = <0>;
+ };
+
+ cti1: cti@fc311000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc311000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <16>;
+ coresight-name = "coresight-cti1";
+ coresight-nr-inports = <0>;
+ };
+
+ cti2: cti@fc312000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc312000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <17>;
+ coresight-name = "coresight-cti2";
+ coresight-nr-inports = <0>;
+ };
+
+ cti3: cti@fc313000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc313000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <18>;
+ coresight-name = "coresight-cti3";
+ coresight-nr-inports = <0>;
+ };
+
+ cti4: cti@fc314000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc314000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <19>;
+ coresight-name = "coresight-cti4";
+ coresight-nr-inports = <0>;
+ };
+
+ cti5: cti@fc315000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc315000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <20>;
+ coresight-name = "coresight-cti5";
+ coresight-nr-inports = <0>;
+ };
+
+ cti6: cti@fc316000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc316000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <21>;
+ coresight-name = "coresight-cti6";
+ coresight-nr-inports = <0>;
+ };
+
+ cti7: cti@fc317000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc317000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <22>;
+ coresight-name = "coresight-cti7";
+ coresight-nr-inports = <0>;
+ };
+
+ cti8: cti@fc318000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc318000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <23>;
+ coresight-name = "coresight-cti8";
+ coresight-nr-inports = <0>;
+ };
+
+ cti_l2: cti@fc340000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc340000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <24>;
+ coresight-name = "coresight-cti-l2";
+ coresight-nr-inports = <0>;
+ };
+
+ cti_cpu0: cti@fc341000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc341000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <25>;
+ coresight-name = "coresight-cti-cpu0";
+ coresight-nr-inports = <0>;
+ };
+
+ cti_cpu1: cti@fc342000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc342000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <26>;
+ coresight-name = "coresight-cti-cpu1";
+ coresight-nr-inports = <0>;
+ };
+
+ cti_cpu2: cti@fc343000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc343000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <27>;
+ coresight-name = "coresight-cti-cpu2";
+ coresight-nr-inports = <0>;
+ };
+
+ cti_cpu3: cti@fc344000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc344000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-id = <28>;
+ coresight-name = "coresight-cti-cpu3";
+ coresight-nr-inports = <0>;
+ };
};
diff --git a/arch/arm/boot/dts/apq8084-gpu.dtsi b/arch/arm/boot/dts/apq8084-gpu.dtsi
new file mode 100644
index 0000000..8570b4f
--- /dev/null
+++ b/arch/arm/boot/dts/apq8084-gpu.dtsi
@@ -0,0 +1,95 @@
+/* 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 {
+ msm_gpu: qcom,kgsl-3d0@fdb00000 {
+ label = "kgsl-3d0";
+ compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d";
+ reg = <0xfdb00000 0x10000
+ 0xfdb20000 0x20000>;
+ reg-names = "kgsl_3d0_reg_memory" , "kgsl_3d0_shader_memory";
+ interrupts = <0 33 0>;
+ interrupt-names = "kgsl_3d0_irq";
+ qcom,id = <0>;
+
+ qcom,chipid = <0x04020000>;
+
+ qcom,initial-pwrlevel = <2>;
+
+ qcom,idle-timeout = <8>; //<HZ/12>
+ qcom,strtstp-sleepwake;
+ qcom,clk-map = <0x00000016>; //KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM_IFACE
+
+ /* Bus Scale Settings */
+ qcom,msm-bus,name = "grp3d";
+ qcom,msm-bus,num-cases = <5>;
+ qcom,msm-bus,num-paths = <2>;
+ qcom,msm-bus,vectors-KBps =
+ <26 512 0 0>, <89 604 0 0>,
+ <26 512 0 3144000>, <89 604 0 3200000>,
+ <26 512 0 4800000>, <89 604 0 4800000>,
+ <26 512 0 6400000>, <89 604 0 6400000>,
+ <26 512 0 8528000>, <89 604 0 9600000>;
+
+ /* GDSC oxili regulators */
+ vddcx-supply = <&gdsc_oxili_cx>;
+ vdd-supply = <&gdsc_oxili_gx>;
+
+ /* IOMMU Data */
+ iommu = <&kgsl_iommu>;
+
+ /* Power levels */
+ qcom,gpu-pwrlevels {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ compatible = "qcom,gpu-pwrlevels";
+
+ qcom,gpu-pwrlevel@0 {
+ reg = <0>;
+ qcom,gpu-freq = <600000000>;
+ qcom,bus-freq = <4>;
+ qcom,io-fraction = <33>;
+ };
+
+ qcom,gpu-pwrlevel@1 {
+ reg = <1>;
+ qcom,gpu-freq = <400000000>;
+ qcom,bus-freq = <3>;
+ qcom,io-fraction = <66>;
+ };
+
+ qcom,gpu-pwrlevel@2 {
+ reg = <2>;
+ qcom,gpu-freq = <300000000>;
+ qcom,bus-freq = <2>;
+ qcom,io-fraction = <100>;
+ };
+
+ qcom,gpu-pwrlevel@3 {
+ reg = <3>;
+ qcom,gpu-freq = <200000000>;
+ qcom,bus-freq = <1>;
+ qcom,io-fraction = <100>;
+ };
+
+ 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/apq8084-iommu.dtsi b/arch/arm/boot/dts/apq8084-iommu.dtsi
new file mode 100644
index 0000000..72d2748
--- /dev/null
+++ b/arch/arm/boot/dts/apq8084-iommu.dtsi
@@ -0,0 +1,477 @@
+/* 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/ "msm-iommu-v1.dtsi"
+
+&venus_iommu {
+ status = "ok";
+
+ qcom,iommu-bfb-regs = <0x204c
+ 0x2514
+ 0x2540
+ 0x256c
+ 0x20ac
+ 0x215c
+ 0x220c
+ 0x22bc
+ 0x2314
+ 0x2394
+ 0x2414
+ 0x2494
+ 0x2008
+ 0x200c
+ 0x2010
+ 0x2014
+ 0x2018
+ 0x201c>;
+
+ qcom,iommu-bfb-data = <0x7ffffff
+ 0x4
+ 0x8
+ 0x0
+ 0x13607
+ 0x4201
+ 0x14221
+ 0x0
+ 0x0
+ 0x94
+ 0x114
+ 0x0
+ 0x0
+ 0x0
+ 0x0
+ 0x0
+ 0x0
+ 0x0>;
+
+ qcom,iommu-lpae-bfb-regs = <0x204c
+ 0x2514
+ 0x2540
+ 0x256c
+ 0x20ac
+ 0x215c
+ 0x220c
+ 0x22bc
+ 0x2314
+ 0x2394
+ 0x2414
+ 0x2494
+ 0x2008
+ 0x200c
+ 0x2010
+ 0x2014
+ 0x2018
+ 0x201c>;
+
+ qcom,iommu-lpae-bfb-data = <0x7ffffff
+ 0x0
+ 0x4
+ 0x8
+ 0x13607
+ 0x0
+ 0x4201
+ 0x14221
+ 0x0
+ 0x0
+ 0x94
+ 0x114
+ 0x0
+ 0x0
+ 0x0
+ 0x0
+ 0x0
+ 0x0>;
+
+
+ venus_ns: qcom,iommu-ctx@fdc8c000 {
+ qcom,iommu-ctx-sids = <0 1 2 3 4 5 7>;
+ };
+
+ venus_sec_bitstream: qcom,iommu-ctx@fdc8d000 {
+ qcom,iommu-ctx-sids = <0x80 0x81 0x82 0x83 0x84>;
+ label = "venus_sec_bitstream";
+ };
+
+ venus_sec_pixel: qcom,iommu-ctx@fdc8f000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
+ reg = <0xfdc8f000 0x1000>;
+ interrupts = <0 42 0>;
+ qcom,iommu-ctx-sids = <0x85>;
+ label = "venus_sec_pixel";
+ qcom,secure-context;
+ };
+
+ venus_sec_non_pixel: qcom,iommu-ctx@fdc90000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
+ reg = <0xfdc90000 0x1000>;
+ interrupts = <0 42 0>;
+ qcom,iommu-ctx-sids = <0x87 0xA0>;
+ label = "venus_sec_non_pixel";
+ qcom,secure-context;
+ };
+};
+
+&jpeg_iommu {
+ status = "ok";
+
+ qcom,iommu-bfb-regs = <0x204c
+ 0x2514
+ 0x2540
+ 0x256c
+ 0x2314
+ 0x2394
+ 0x2414
+ 0x2494
+ 0x20ac
+ 0x215c
+ 0x220c
+ 0x22bc
+ 0x2008
+ 0x200c
+ 0x2010>;
+
+ qcom,iommu-bfb-data = <0x3fff
+ 0x4
+ 0x4
+ 0x0
+ 0x0
+ 0x10
+ 0x50
+ 0x0
+ 0x2000
+ 0x2804
+ 0x9614
+ 0x0
+ 0x0
+ 0x0
+ 0x0>;
+
+ qcom,iommu-lpae-bfb-regs = <0x204c
+ 0x2514
+ 0x2540
+ 0x256c
+ 0x2314
+ 0x2394
+ 0x2414
+ 0x2494
+ 0x20ac
+ 0x215c
+ 0x220c
+ 0x22bc
+ 0x2008
+ 0x200c
+ 0x2010>;
+
+ qcom,iommu-lpae-bfb-data = <0x3fff
+ 0x0
+ 0x4
+ 0x4
+ 0x0
+ 0x0
+ 0x10
+ 0x50
+ 0x2000
+ 0x964b
+ 0x2804
+ 0x9614
+ 0x0
+ 0x0
+ 0x0>;
+
+};
+
+&mdp_iommu {
+ status = "ok";
+
+ qcom,iommu-bfb-regs = <0x204c
+ 0x2514
+ 0x2540
+ 0x256c
+ 0x20ac
+ 0x215c
+ 0x220c
+ 0x22bc
+ 0x2314
+ 0x2394
+ 0x2414
+ 0x2494
+ 0x2008
+ 0x200c
+ 0x2010
+ 0x2014
+ 0x2018>;
+
+ qcom,iommu-bfb-data = <0x7fffff
+ 0x4
+ 0x10
+ 0x0
+ 0x5000
+ 0x5a1d
+ 0x1822d
+ 0x0
+ 0x0
+ 0x28
+ 0x68
+ 0x0
+ 0x0
+ 0x0
+ 0x0
+ 0x0
+ 0x0>;
+
+ qcom,iommu-lpae-bfb-regs = <0x204c
+ 0x2514
+ 0x2540
+ 0x256c
+ 0x20ac
+ 0x215c
+ 0x220c
+ 0x22bc
+ 0x2314
+ 0x2394
+ 0x2414
+ 0x2494
+ 0x2008
+ 0x200c
+ 0x2010
+ 0x2014
+ 0x2018>;
+
+ qcom,iommu-lpae-bfb-data = <0x7fffff
+ 0x0
+ 0x4
+ 0x10
+ 0x5000
+ 0x182c1
+ 0x5a1d
+ 0x1822d
+ 0x0
+ 0x0
+ 0x28
+ 0x68
+ 0x0
+ 0x0
+ 0x0
+ 0x0
+ 0x0>;
+
+};
+
+&kgsl_iommu {
+ status = "ok";
+
+ qcom,iommu-bfb-regs = <0x204c
+ 0x2514
+ 0x2540
+ 0x256c
+ 0x20ac
+ 0x215c
+ 0x220c
+ 0x22bc
+ 0x2314
+ 0x2394
+ 0x2414
+ 0x2494
+ 0x2008
+ 0x2600
+ 0x2604
+ 0x2608
+ 0x260c
+ 0x2610
+ 0x2614
+ 0x2618
+ 0x261c
+ 0x2620
+ 0x2624
+ 0x2628
+ 0x262c>;
+
+ qcom,iommu-bfb-data = <0x3
+ 0x8
+ 0x10
+ 0x0
+ 0x0
+ 0x0
+ 0x20
+ 0x0
+ 0x0
+ 0x1
+ 0x101
+ 0x0
+ 0x0
+ 0x7
+ 0x4
+ 0x8
+ 0x14
+ 0x0
+ 0x0
+ 0xc
+ 0x6c
+ 0x0
+ 0x8
+ 0x10
+ 0x0>;
+
+ qcom,iommu-lpae-bfb-regs = <0x204c
+ 0x2514
+ 0x2540
+ 0x256c
+ 0x20ac
+ 0x215c
+ 0x220c
+ 0x22bc
+ 0x2314
+ 0x2394
+ 0x2414
+ 0x2494
+ 0x2008
+ 0x2600
+ 0x2604
+ 0x2608
+ 0x260c
+ 0x2610
+ 0x2614
+ 0x2618
+ 0x261c
+ 0x2620
+ 0x2624
+ 0x2628
+ 0x262c>;
+
+ qcom,iommu-lpae-bfb-data = <0x3
+ 0x0
+ 0x8
+ 0x10
+ 0x0
+ 0x120
+ 0x0
+ 0x20
+ 0x0
+ 0x0
+ 0x1
+ 0x101
+ 0x0
+ 0x7
+ 0x4
+ 0x20
+ 0x8
+ 0x14
+ 0x0
+ 0x0
+ 0xc
+ 0x6c
+ 0x0
+ 0x8
+ 0x10>;
+
+};
+
+&vfe_iommu {
+ status = "ok";
+
+ qcom,iommu-bfb-regs = <0x204c
+ 0x2514
+ 0x2540
+ 0x256c
+ 0x2314
+ 0x2394
+ 0x2414
+ 0x2494
+ 0x20ac
+ 0x215c
+ 0x220c
+ 0x22bc
+ 0x2008
+ 0x200c
+ 0x2010
+ 0x2014
+ 0x2018
+ 0x201c
+ 0x2020>;
+
+ qcom,iommu-bfb-data = <0xffffffff
+ 0x4
+ 0x8
+ 0x0
+ 0x0
+ 0x20
+ 0x78
+ 0x0
+ 0x4000
+ 0x3c08
+ 0xb41e
+ 0x0
+ 0x0
+ 0x0
+ 0x0
+ 0x0
+ 0x0
+ 0x0
+ 0x0>;
+
+ qcom,iommu-lpae-bfb-regs = <0x204c
+ 0x2514
+ 0x2540
+ 0x256c
+ 0x2314
+ 0x2394
+ 0x2414
+ 0x2494
+ 0x20ac
+ 0x215c
+ 0x220c
+ 0x22bc
+ 0x2008
+ 0x200c
+ 0x2010
+ 0x2014
+ 0x2018
+ 0x201c
+ 0x2020>;
+
+ qcom,iommu-lpae-bfb-data = <0xffffffff
+ 0x0
+ 0x4
+ 0x8
+ 0x0
+ 0x0
+ 0x20
+ 0x78
+ 0x4000
+ 0xb45a
+ 0x3c08
+ 0xb41e
+ 0x0
+ 0x0
+ 0x0
+ 0x0
+ 0x0
+ 0x0
+ 0x0>;
+
+};
+
+&copss_iommu {
+ status = "ok";
+};
+
+&vpu_iommu {
+ status = "ok";
+};
+
+&lpass_qdsp_iommu {
+ status = "ok";
+};
+
+&lpass_core_iommu {
+ status = "ok";
+};
diff --git a/arch/arm/boot/dts/apq8084-mdss.dtsi b/arch/arm/boot/dts/apq8084-mdss.dtsi
new file mode 100644
index 0000000..5c5cd1b
--- /dev/null
+++ b/arch/arm/boot/dts/apq8084-mdss.dtsi
@@ -0,0 +1,80 @@
+/* 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 {
+ mdss_mdp: qcom,mdss_mdp@fd900000 {
+ compatible = "qcom,mdss_mdp";
+ reg = <0xfd900000 0x22100>,
+ <0xfd924000 0x1000>;
+ reg-names = "mdp_phys", "vbif_phys";
+ interrupts = <0 72 0>;
+ vdd-supply = <&gdsc_mdss>;
+
+ status = "disabled";
+
+ qcom,max-clk-rate = <320000000>;
+
+ qcom,mdss-pipe-vig-off = <0x00001200 0x00001600
+ 0x00001A00 0x00001E00>;
+ qcom,mdss-pipe-rgb-off = <0x00002200 0x00002600
+ 0x00002A00 0x00002E00>;
+ qcom,mdss-pipe-dma-off = <0x00003200 0x00003600>;
+
+ qcom,mdss-pipe-vig-fetch-id = <1 4 7 19>;
+ qcom,mdss-pipe-rgb-fetch-id = <16 17 18 22>;
+ qcom,mdss-pipe-dma-fetch-id = <10 13>;
+
+ qcom,mdss-smp-data = <44 8192>;
+
+ qcom,mdss-ctl-off = <0x00000600 0x00000700 0x00000800
+ 0x00000900 0x0000A00>;
+ qcom,mdss-mixer-intf-off = <0x00003A00 0x00003E00
+ 0x00004200 0x00004E00>;
+ qcom,mdss-mixer-wb-off = <0x00004600 0x00004A00>;
+ qcom,mdss-dspp-off = <0x00005200 0x00005600 0x00005A00
+ 0x00005E00>;
+ qcom,mdss-wb-off = <0x00011100 0x00011500 0x00011900
+ 0x00011D00 0x00012100>;
+ qcom,mdss-intf-off = <0x00012500 0x00012700
+ 0x00012900 0x00012b00>;
+ qcom,mdss-pingpong-off = <0x00012F00 0x00013000 0x00013100
+ 0x00013200>;
+ qcom,mdss-ad-off = <0x0013500 0x00013700 0x00013900>;
+
+ qcom,mdss-has-bwc;
+ qcom,mdss-has-decimation;
+
+ mdss_fb0: qcom,mdss_fb_primary {
+ cell-index = <0>;
+ compatible = "qcom,mdss-fb";
+ qcom,memory-reservation-type = "EBI1";
+ qcom,memory-reservation-size = <0x1000000>;
+ };
+
+ mdss_fb1: qcom,mdss_fb_external {
+ cell-index = <1>;
+ compatible = "qcom,mdss-fb";
+ };
+
+ mdss_fb2: qcom,mdss_fb_wfd {
+ cell-index = <2>;
+ compatible = "qcom,mdss-fb";
+ };
+ };
+
+ qcom,mdss_wb_panel {
+ compatible = "qcom,mdss_wb";
+ qcom,mdss_pan_res = <1920 1080>;
+ qcom,mdss_pan_bpp = <24>;
+ qcom,mdss-fb-map = <&mdss_fb2>;
+ };
+};
diff --git a/arch/arm/boot/dts/apq8084-sim.dts b/arch/arm/boot/dts/apq8084-sim.dts
index e206d4d..dccdbc4 100644
--- a/arch/arm/boot/dts/apq8084-sim.dts
+++ b/arch/arm/boot/dts/apq8084-sim.dts
@@ -171,3 +171,7 @@
&usb3 {
qcom,skip-charger-detection;
};
+
+&ufs1 {
+ status = "ok";
+};
diff --git a/arch/arm/boot/dts/apq8084.dtsi b/arch/arm/boot/dts/apq8084.dtsi
index 80b6ffa..b027f7d 100644
--- a/arch/arm/boot/dts/apq8084.dtsi
+++ b/arch/arm/boot/dts/apq8084.dtsi
@@ -19,9 +19,13 @@
soc: soc { };
};
+/include/ "msm-gdsc.dtsi"
/include/ "apq8084-ion.dtsi"
+/include/ "apq8084-iommu.dtsi"
/include/ "apq8084-smp2p.dtsi"
/include/ "apq8084-coresight.dtsi"
+/include/ "apq8084-mdss.dtsi"
+/include/ "apq8084-gpu.dtsi"
&soc {
#address-cells = <1>;
@@ -160,6 +164,37 @@
qcom,scl-gpio = <&msmgpio 11 0>;
};
+ qcom,usbbam@f9304000 {
+ compatible = "qcom,usb-bam-msm";
+ reg = <0xf9304000 0x5000>,
+ <0xf92f880c 0x4>;
+ reg-names = "ssusb", "qscratch_ram1_reg";
+ interrupts = <0 132 0>;
+ interrupt-names = "ssusb";
+ qcom,usb-bam-num-pipes = <16>;
+ qcom,usb-bam-fifo-baseaddr = <0x00000000 0xf9200000>;
+ qcom,ignore-core-reset-ack;
+ qcom,disable-clk-gating;
+
+ qcom,pipe0 {
+ label = "ssusb-qdss-in-0";
+ qcom,usb-bam-mem-type = <1>;
+ qcom,bam-type = <0>;
+ qcom,dir = <1>;
+ qcom,pipe-num = <0>;
+ qcom,peer-bam = <1>;
+ qcom,src-bam-physical-address = <0xfc37C000>;
+ qcom,src-bam-pipe-index = <0>;
+ qcom,dst-bam-physical-address = <0xf9304000>;
+ qcom,dst-bam-pipe-index = <2>;
+ qcom,data-fifo-offset = <0xf0000>;
+ qcom,data-fifo-size = <0x1800>;
+ qcom,descriptor-fifo-offset = <0xf4000>;
+ qcom,descriptor-fifo-size = <0x1400>;
+ qcom,reset-bam-on-connect;
+ };
+ };
+
usb3: qcom,ssusb@f9200000 {
compatible = "qcom,dwc-usb3-msm";
reg = <0xf9200000 0xfc000>,
@@ -194,7 +229,7 @@
tsens: tsens@fc4a8000 {
compatible = "qcom,msm-tsens";
reg = <0xfc4a8000 0x2000>,
- <0xfc4b8000 0x1000>;
+ <0xfc4bc000 0x1000>;
reg-names = "tsens_physical", "tsens_eeprom_physical";
interrupts = <0 184 0>;
qcom,sensors = <11>;
@@ -241,7 +276,7 @@
memory_hole: qcom,msm-mem-hole {
compatible = "qcom,msm-mem-hole";
- qcom,memblock-remove = <0x0dc00000 0x2000000>; /* Address and Size of Hole */
+ qcom,memblock-remove = <0x0d200000 0x02c00000>; /* Address and Size of Hole */
};
qcom,ipc-spinlock@fd484000 {
@@ -283,6 +318,88 @@
qcom,irq-no-suspend;
};
};
+
+ qcom,venus@fdce0000 {
+ compatible = "qcom,pil-venus";
+ reg = <0xfdce0000 0x4000>,
+ <0xfdc80000 0x400>;
+ reg-names = "wrapper_base", "vbif_base";
+ vdd-supply = <&gdsc_venus>;
+
+ qcom,firmware-name = "venus";
+ };
+
+ ufs1: ufshc@0xfc598000 {
+ compatible = "jedec,ufs-1.1";
+ reg = <0xfc598000 0x800>;
+ interrupts = <0 28 0>;
+ status = "disabled";
+ };
+
+ qcom,wdt@f9017000 {
+ compatible = "qcom,msm-watchdog";
+ reg = <0xf9017000 0x1000>;
+ interrupts = <0 3 0>, <0 4 0>;
+ qcom,bark-time = <11000>;
+ qcom,pet-time = <10000>;
+ qcom,ipi-ping;
+ };
+};
+
+&gdsc_venus {
+ status = "ok";
+};
+
+&gdsc_venus_core0 {
+ status = "ok";
+};
+
+&gdsc_venus_core1 {
+ status = "ok";
+};
+
+&gdsc_vpu {
+ status = "ok";
+};
+
+&gdsc_mdss {
+ status = "ok";
+};
+
+&gdsc_jpeg {
+ status = "ok";
+};
+
+&gdsc_vfe {
+ status = "ok";
+};
+
+&gdsc_oxili_gx {
+ status = "ok";
+};
+
+&gdsc_oxili_cx {
+ status = "ok";
+};
+
+&gdsc_usb_hsic {
+ status = "ok";
+};
+
+&gdsc_pcie_0{
+ status = "ok";
+};
+
+&gdsc_pcie_1{
+ status = "ok";
+};
+
+&gdsc_usb30{
+ status = "ok";
+};
+
+&gdsc_usb30_sec{
+ status = "ok";
};
/include/ "msm-pma8084.dtsi"
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 25c1851..c8d150a 100644
--- a/arch/arm/boot/dts/dsi-panel-hx8394a-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-hx8394a-720p-video.dtsi
@@ -10,98 +10,76 @@
* GNU General Public License for more details.
*/
+/*---------------------------------------------------------------------------
+ * This file is autogenerated file using gcdb parser. Please do not edit it.
+ * Update input XML file to add a new entry or update variable in this file
+ * VERSION = "1.0"
+ *---------------------------------------------------------------------------*/
&soc {
qcom,mdss_dsi_hx8394a_720p_video {
compatible = "qcom,mdss-dsi-panel";
- label = "hx8394a 720p video mode dsi panel";
status = "disable";
- qcom,dsi-ctrl-phandle = <&mdss_dsi0>;
- qcom,rst-gpio = <&msmgpio 25 0>;
- qcom,mdss-pan-res = <720 1280>;
- qcom,mdss-pan-bpp = <24>;
- qcom,mdss-pan-dest = "display_1";
- qcom,mdss-pan-porch-values = <59 60 79 10 2 7>;
- qcom,mdss-pan-underflow-clr = <0xff>;
- qcom,mdss-pan-bl-ctrl = "bl_ctrl_wled";
- qcom,mdss-pan-bl-levels = <1 4095>;
- qcom,mdss-pan-dsi-mode = <0>;
- qcom,mdss-pan-dsi-h-pulse-mode = <1>;
- qcom,mdss-pan-dsi-h-power-stop = <0 0 0>;
- qcom,mdss-pan-dsi-bllp-power-stop = <1 1>;
- qcom,mdss-pan-dsi-traffic-mode = <2>;
- qcom,mdss-pan-dsi-dst-format = <3>;
- qcom,mdss-pan-dsi-vc = <0>;
- qcom,mdss-pan-dsi-rgb-swap = <0>;
- qcom,mdss-pan-dsi-data-lanes = <1 1 1 1>; /* 4 lanes */
- qcom,mdss-pan-dsi-dlane-swap = <0>;
- qcom,mdss-pan-dsi-t-clk = <0x2d 0x1f>;
- 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,panel-phy-regulatorSettings = [07 09 03 00 /* Regualotor settings */
- 20 00 01];
- qcom,panel-phy-timingSettings = [8d 24 19 00 34 34
- 1d 26 2a 03 04 00];
- qcom,panel-phy-strengthCtrl = [ff 06];
- qcom,panel-phy-bistCtrl = [00 00 b1 ff /* BIST Ctrl settings */
- 00 00];
- qcom,panel-phy-laneConfig = [00 00 00 00 00 00 00 01 97 /* lane0 config */
- 00 00 00 00 05 00 00 01 97 /* lane1 config */
- 00 00 00 00 0a 00 00 01 97 /* lane2 config */
- 00 00 00 00 0f 00 00 01 97 /* lane3 config */
- 00 c0 00 00 00 00 00 01 bb]; /* Clk ln config */
- qcom,panel-on-cmds = [39 01 00 00 00 00 04
- b9 ff 83 94
- 39 01 00 00 00 00 05
- c7 00 10 00 10
- 39 01 00 00 00 00 02
- bc 07
- 39 01 00 00 00 00 02
- ba 13
- 39 01 00 00 00 00 10
- b1 01 00 07 83 01
- 12 0f 32 38 29 29
- 50 02 00 00
- 39 01 00 00 00 00 07
- b2 00 c8 09 05 00
- 71
- 39 01 00 00 00 00 02
- cc 05
- 05 01 00 00 00 00 02 00 00
- 39 01 00 00 00 00 35
- d5 00 00 00 00 0a
- 00 01 00 00 00 33
- 00 23 45 67 01 01
- 23 88 88 88 88 88
- 88 88 99 99 99 88
- 88 99 88 54 32 10
- 76 32 10 88 88 88
- 88 88 88 88 99 99
- 99 88 88 88 99
- 39 01 00 00 00 00 17
- b4 80 08 32 10 00
- 32 15 08 32 12 20
- 33 05 4c 05 37 05
- 3f 1e 5f 5f 06
- 39 01 00 00 00 00 02
- b6 00
- 39 01 00 00 00 00 23
- e0 01 05 07 25 35
- 3f 0b 32 04 09 0e
- 10 13 10 14 16 1b
- 01 05 07 25 35 3f
- 0b 32 04 09 0e 10
- 13 10 14 16 1b
- 05 01 00 00 00 00 02 00 00
- 39 01 00 00 00 00 04
- bf 06 00 10
- 05 01 00 00 c8 00 02 11 00
- 05 01 00 00 32 00 02 29 00];
+ qcom,mdss-dsi-panel-name = "hx8394a 720p 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";
+ qcom,mdss-dsi-panel-framerate = <60>;
+ qcom,mdss-dsi-virtual-channel-id = <0>;
+ qcom,mdss-dsi-stream = <0>;
+ qcom,mdss-dsi-panel-width = <720>;
+ qcom,mdss-dsi-panel-height = <1280>;
+ qcom,mdss-dsi-h-front-porch = <79>;
+ qcom,mdss-dsi-h-back-porch = <59>;
+ qcom,mdss-dsi-h-pulse-width = <60>;
+ qcom,mdss-dsi-h-sync-skew = <0>;
+ qcom,mdss-dsi-v-back-porch = <10>;
+ qcom,mdss-dsi-v-front-porch = <7>;
+ 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-underflow-color = <0xff>;
+ qcom,mdss-dsi-border-color = <0>;
+ qcom,mdss-dsi-on-command = [39 01 00 00 00 00 04 b9 ff 83 94
+ 39 01 00 00 00 00 05 c7 00 10 00 10
+ 39 01 00 00 00 00 02 bc 07
+ 39 01 00 00 00 00 02 ba 13
+ 39 01 00 00 00 00 10 b1 01 00 07 83 01 12 0f 32 38 29 29 50 02 00 00
+ 39 01 00 00 00 00 07 b2 00 c8 09 05 00 71
+ 39 01 00 00 00 00 02 cc 05
+ 05 01 00 00 00 00 02 00 00
+ 39 01 00 00 00 00 35 d5 00 00 00 00 0a 00 01 00 00 00 33 00 23 45 67 01 01 23 88 88 88 88 88 88 88 99 99 99 88 88 99 88 54 32 10 76 32 10 88 88 88 88 88 88 88 99 99 99 88 88 88 99
+ 39 01 00 00 00 00 17 b4 80 08 32 10 00 32 15 08 32 12 20 33 05 4c 05 37 05 3f 1e 5f 5f 06
+ 39 01 00 00 00 00 02 b6 00
+ 39 01 00 00 00 00 23 e0 01 05 07 25 35 3f 0b 32 04 09 0e 10 13 10 14 16 1b 01 05 07 25 35 3f 0b 32 04 09 0e 10 13 10 14 16 1b
+ 05 01 00 00 00 00 02 00 00
+ 39 01 00 00 00 00 04 bf 06 00 10
+ 05 01 00 00 c8 00 02 11 00
+ 05 01 00 00 32 00 02 29 00];
+ qcom,mdss-dsi-off-command = [05 01 00 00 0a 00 02 28 00
+ 05 01 00 00 96 00 02 10 00];
+ qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+ qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+ qcom,mdss-dsi-h-sync-pulse = <1>;
+ qcom,mdss-dsi-traffic-mode = <2>;
+ qcom,mdss-dsi-lane-map = <0>;
+ qcom,mdss-dsi-bllp-eof-power-mode;
+ qcom,mdss-dsi-bllp-power-mode;
+ qcom,mdss-dsi-lane-0-state;
+ qcom,mdss-dsi-lane-1-state;
+ qcom,mdss-dsi-lane-2-state;
+ qcom,mdss-dsi-lane-3-state;
+ qcom,mdss-dsi-panel-timings = [8d 24 19 00 34 34 1d 26 2a 03 04 00];
+ qcom,mdss-dsi-t-clk-post = <0x1f>;
+ 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-bl-pmic-control-type = "bl_ctrl_wled";
- qcom,on-cmds-dsi-state = "DSI_LP_MODE";
- qcom,panel-off-cmds = [05 01 00 00 0a 00 02 28 00
- 05 01 00 00 96 00 02 10 00];
- qcom,off-cmds-dsi-state = "DSI_HS_MODE";
};
};
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 2a6bbf9..d0b4da8 100644
--- a/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi
@@ -10,55 +10,40 @@
* GNU General Public License for more details.
*/
+/*---------------------------------------------------------------------------
+ * This file is autogenerated file using gcdb parser. Please do not edit it.
+ * Update input XML file to add a new entry or update variable in this file
+ * VERSION = "1.0"
+ *---------------------------------------------------------------------------*/
&soc {
qcom,mdss_dsi_nt35590_720p_cmd {
compatible = "qcom,mdss-dsi-panel";
- label = "nt35590 720p command mode dsi panel";
status = "disable";
- qcom,dsi-ctrl-phandle = <&mdss_dsi0>;
- qcom,rst-gpio = <&msmgpio 25 0>;
- qcom,te-gpio = <&msmgpio 24 0>;
- qcom,mdss-pan-res = <720 1280>;
- qcom,mdss-pan-bpp = <24>;
- qcom,mdss-pan-dest = "display_1";
- qcom,mdss-pan-porch-values = <164 8 140 1 1 6>;
- qcom,mdss-pan-underflow-clr = <0xff>;
- qcom,mdss-pan-bl-ctrl = "bl_ctrl_wled";
- qcom,mdss-pan-bl-levels = <1 4095>;
- qcom,mdss-pan-dsi-mode = <1>;
- qcom,mdss-vsync-enable = <1>;
- qcom,mdss-hw-vsync-mode = <1>;
- qcom,mdss-pan-dsi-h-pulse-mode = <1>;
- qcom,mdss-pan-dsi-h-power-stop = <0 0 0>;
- qcom,mdss-pan-dsi-bllp-power-stop = <1 1>;
- qcom,mdss-pan-dsi-traffic-mode = <2>;
- qcom,mdss-pan-dsi-dst-format = <8>;
- qcom,mdss-pan-insert-dcs-cmd = <1>;
- qcom,mdss-pan-wr-mem-continue = <0x3c>;
- qcom,mdss-pan-wr-mem-start = <0x2c>;
- qcom,mdss-pan-te-sel = <1>;
- qcom,mdss-pan-dsi-vc = <0>;
- qcom,mdss-pan-dsi-rgb-swap = <0>;
- qcom,mdss-pan-dsi-data-lanes = <1 1 1 1>; /* 4 lanes */
- qcom,mdss-pan-dsi-dlane-swap = <0>;
- qcom,mdss-pan-dsi-t-clk = <0x2c 0x20>;
- 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,panel-phy-regulatorSettings = [07 09 03 00 /* Regualotor settings */
- 20 00 01];
- qcom,panel-phy-timingSettings = [7d 25 1d 00 37 33
- 22 27 1e 03 04 00];
- qcom,panel-phy-strengthCtrl = [ff 06];
- qcom,panel-phy-bistCtrl = [00 00 b1 ff /* BIST Ctrl settings */
- 00 00];
- qcom,panel-phy-laneConfig = [00 00 00 00 00 00 00 01 97 /* lane0 config */
- 00 00 00 00 05 00 00 01 97 /* lane1 config */
- 00 00 00 00 0a 00 00 01 97 /* lane2 config */
- 00 00 00 00 0f 00 00 01 97 /* lane3 config */
- 00 c0 00 00 00 00 00 01 bb]; /* Clk ln config */
- qcom,panel-on-cmds = [29 01 00 00 00 00 02 FF EE
+ qcom,mdss-dsi-panel-name = "nt35590 720p command mode dsi panel";
+ qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
+ qcom,mdss-dsi-panel-type = "dsi_cmd_mode";
+ qcom,mdss-dsi-panel-destination = "display_1";
+ qcom,mdss-dsi-panel-framerate = <60>;
+ qcom,mdss-dsi-virtual-channel-id = <0>;
+ qcom,mdss-dsi-stream = <0>;
+ qcom,mdss-dsi-panel-width = <720>;
+ qcom,mdss-dsi-panel-height = <1280>;
+ qcom,mdss-dsi-h-front-porch = <140>;
+ qcom,mdss-dsi-h-back-porch = <164>;
+ qcom,mdss-dsi-h-pulse-width = <8>;
+ qcom,mdss-dsi-h-sync-skew = <0>;
+ qcom,mdss-dsi-v-back-porch = <1>;
+ qcom,mdss-dsi-v-front-porch = <6>;
+ qcom,mdss-dsi-v-pulse-width = <1>;
+ qcom,mdss-dsi-h-left-border = <0>;
+ qcom,mdss-dsi-h-right-border = <0>;
+ qcom,mdss-dsi-v-top-border = <0>;
+ qcom,mdss-dsi-v-bottom-border = <0>;
+ qcom,mdss-dsi-bpp = <24>;
+ qcom,mdss-dsi-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
29 01 00 00 00 00 02 26 08
29 01 00 00 00 00 02 26 00
29 01 00 00 10 00 02 FF 00
@@ -522,10 +507,32 @@
29 01 00 00 00 00 02 6A 60
29 01 00 00 00 00 02 FF 00
29 01 00 00 78 00 02 29 00];
-
- qcom,on-cmds-dsi-state = "DSI_LP_MODE";
- qcom,panel-off-cmds = [05 01 00 00 32 00 02 28 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,off-cmds-dsi-state = "DSI_HS_MODE";
+ 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-bllp-eof-power-mode;
+ qcom,mdss-dsi-bllp-power-mode;
+ qcom,mdss-dsi-lane-0-state;
+ qcom,mdss-dsi-lane-1-state;
+ qcom,mdss-dsi-lane-2-state;
+ qcom,mdss-dsi-lane-3-state;
+ qcom,mdss-dsi-te-pin-select = <1>;
+ qcom,mdss-dsi-te-v-sync-rd-ptr-irq-line = <0x2c>;
+ qcom,mdss-dsi-te-dcs-command = <1>;
+ qcom,mdss-dsi-te-check-enable;
+ qcom,mdss-dsi-te-using-te-pin;
+ qcom,mdss-dsi-panel-timings = [7d 25 1d 00 37 33 22 27 1e 03 04 00];
+ qcom,mdss-dsi-t-clk-post = <0x20>;
+ 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-bl-pmic-control-type = "bl_ctrl_wled";
+
};
};
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 7bc748d..a171a5c 100644
--- a/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
@@ -10,48 +10,40 @@
* GNU General Public License for more details.
*/
+/*---------------------------------------------------------------------------
+ * This file is autogenerated file using gcdb parser. Please do not edit it.
+ * Update input XML file to add a new entry or update variable in this file
+ * VERSION = "1.0"
+ *---------------------------------------------------------------------------*/
&soc {
qcom,mdss_dsi_nt35590_720p_video {
compatible = "qcom,mdss-dsi-panel";
- label = "nt35590 720p video mode dsi panel";
status = "disable";
- qcom,dsi-ctrl-phandle = <&mdss_dsi0>;
- qcom,rst-gpio = <&msmgpio 25 0>;
- qcom,mdss-pan-res = <720 1280>;
- qcom,mdss-pan-bpp = <24>;
- qcom,mdss-pan-dest = "display_1";
- qcom,mdss-pan-porch-values = <164 8 140 1 1 6>;
- qcom,mdss-pan-underflow-clr = <0xff>;
- qcom,mdss-pan-bl-ctrl = "bl_ctrl_wled";
- qcom,mdss-pan-bl-levels = <1 4095>;
- qcom,mdss-pan-dsi-mode = <0>;
- qcom,mdss-pan-dsi-h-pulse-mode = <1>;
- qcom,mdss-pan-dsi-h-power-stop = <0 0 0>;
- qcom,mdss-pan-dsi-bllp-power-stop = <1 1>;
- qcom,mdss-pan-dsi-traffic-mode = <2>;
- qcom,mdss-pan-dsi-dst-format = <3>;
- qcom,mdss-pan-dsi-vc = <0>;
- qcom,mdss-pan-dsi-rgb-swap = <0>;
- qcom,mdss-pan-dsi-data-lanes = <1 1 1 1>; /* 4 lanes */
- qcom,mdss-pan-dsi-dlane-swap = <0>;
- qcom,mdss-pan-dsi-t-clk = <0x2c 0x20>;
- 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,panel-phy-regulatorSettings = [07 09 03 00 /* Regualotor settings */
- 20 00 01];
- qcom,panel-phy-timingSettings = [7d 25 1d 00 37 33
- 22 27 1e 03 04 00];
- qcom,panel-phy-strengthCtrl = [ff 06];
- qcom,panel-phy-bistCtrl = [00 00 b1 ff /* BIST Ctrl settings */
- 00 00];
- qcom,panel-phy-laneConfig = [00 00 00 00 00 00 00 01 97 /* lane0 config */
- 00 00 00 00 05 00 00 01 97 /* lane1 config */
- 00 00 00 00 0a 00 00 01 97 /* lane2 config */
- 00 00 00 00 0f 00 00 01 97 /* lane3 config */
- 00 c0 00 00 00 00 00 01 bb]; /* Clk ln config */
- qcom,panel-on-cmds = [29 01 00 00 00 00 02 FF EE
+ qcom,mdss-dsi-panel-name = "nt35590 720p 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";
+ qcom,mdss-dsi-panel-framerate = <60>;
+ qcom,mdss-dsi-virtual-channel-id = <0>;
+ qcom,mdss-dsi-stream = <0>;
+ qcom,mdss-dsi-panel-width = <720>;
+ qcom,mdss-dsi-panel-height = <1280>;
+ qcom,mdss-dsi-h-front-porch = <140>;
+ qcom,mdss-dsi-h-back-porch = <164>;
+ qcom,mdss-dsi-h-pulse-width = <8>;
+ qcom,mdss-dsi-h-sync-skew = <0>;
+ qcom,mdss-dsi-v-back-porch = <1>;
+ qcom,mdss-dsi-v-front-porch = <6>;
+ qcom,mdss-dsi-v-pulse-width = <1>;
+ qcom,mdss-dsi-h-left-border = <0>;
+ qcom,mdss-dsi-h-right-border = <0>;
+ qcom,mdss-dsi-v-top-border = <0>;
+ qcom,mdss-dsi-v-bottom-border = <0>;
+ qcom,mdss-dsi-bpp = <24>;
+ qcom,mdss-dsi-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
29 01 00 00 00 00 02 26 08
29 01 00 00 00 00 02 26 00
29 01 00 00 10 00 02 FF 00
@@ -514,11 +506,29 @@
29 01 00 00 00 00 02 13 02
29 01 00 00 00 00 02 6A 60
29 01 00 00 00 00 02 FF 00
- 29 01 00 00 78 00 02 29 00];
-
- qcom,on-cmds-dsi-state = "DSI_LP_MODE";
- qcom,panel-off-cmds = [05 01 00 00 32 00 02 28 00
+ 29 01 00 00 78 00 02 29 00
+ 29 01 00 00 78 00 02 53 2C];
+ qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00
05 01 00 00 78 00 02 10 00];
- qcom,off-cmds-dsi-state = "DSI_HS_MODE";
+ 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-bllp-eof-power-mode;
+ qcom,mdss-dsi-bllp-power-mode;
+ qcom,mdss-dsi-lane-0-state;
+ qcom,mdss-dsi-lane-1-state;
+ qcom,mdss-dsi-lane-2-state;
+ qcom,mdss-dsi-lane-3-state;
+ qcom,mdss-dsi-panel-timings = [7d 25 1d 00 37 33 22 27 1e 03 04 00];
+ qcom,mdss-dsi-t-clk-post = <0x20>;
+ 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-bl-pmic-control-type = "bl_ctrl_wled";
+
};
};
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 1ecad71..998799a 100644
--- a/arch/arm/boot/dts/dsi-panel-nt35596-1080p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-nt35596-1080p-video.dtsi
@@ -10,48 +10,40 @@
* GNU General Public License for more details.
*/
+/*---------------------------------------------------------------------------
+ * This file is autogenerated file using gcdb parser. Please do not edit it.
+ * Update input XML file to add a new entry or update variable in this file
+ * VERSION = "1.0"
+ *---------------------------------------------------------------------------*/
&soc {
qcom,mdss_dsi_nt35596_1080p_video {
compatible = "qcom,mdss-dsi-panel";
- label = "nt35596 1080p video mode dsi panel";
status = "disable";
- qcom,dsi-ctrl-phandle = <&mdss_dsi0>;
- qcom,rst-gpio = <&msmgpio 25 0>;
- qcom,mdss-pan-res = <1080 1920>;
- qcom,mdss-pan-bpp = <24>;
- qcom,mdss-pan-dest = "display_1";
- qcom,mdss-pan-porch-values = <32 8 32 18 2 2>;
- qcom,mdss-pan-underflow-clr = <0xff>;
- qcom,mdss-pan-bl-ctrl = "bl_ctrl_wled";
- qcom,mdss-pan-bl-levels = <1 4095>;
- qcom,mdss-pan-dsi-mode = <0>;
- qcom,mdss-pan-dsi-h-pulse-mode = <1>;
- qcom,mdss-pan-dsi-h-power-stop = <0 0 0>;
- qcom,mdss-pan-dsi-bllp-power-stop = <1 1>;
- qcom,mdss-pan-dsi-traffic-mode = <2>;
- qcom,mdss-pan-dsi-dst-format = <3>;
- qcom,mdss-pan-dsi-vc = <0>;
- qcom,mdss-pan-dsi-rgb-swap = <0>;
- qcom,mdss-pan-dsi-data-lanes = <1 1 1 1>; /* 4 lanes */
- qcom,mdss-pan-dsi-dlane-swap = <0>;
- qcom,mdss-pan-dsi-t-clk = <0x38 0x1e>;
- 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,panel-phy-regulatorSettings = [07 09 03 00 /* Regualotor settings */
- 20 00 01];
- qcom,panel-phy-timingSettings = [f9 3d 34 00 58 4d
- 36 3f 53 03 04 00];
- qcom,panel-phy-strengthCtrl = [ff 06];
- qcom,panel-phy-bistCtrl = [00 00 b1 ff /* BIST Ctrl settings */
- 00 00];
- qcom,panel-phy-laneConfig = [00 00 00 00 00 00 00 01 97 /* lane0 config */
- 00 00 00 00 05 00 00 01 97 /* lane1 config */
- 00 00 00 00 0a 00 00 01 97 /* lane2 config */
- 00 00 00 00 0f 00 00 01 97 /* lane3 config */
- 00 c0 00 00 00 00 00 01 bb]; /* Clk ln config */
- qcom,panel-on-cmds = [29 01 00 00 00 00 02 FF EE
+ qcom,mdss-dsi-panel-name = "nt35596 1080p 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";
+ qcom,mdss-dsi-panel-framerate = <60>;
+ qcom,mdss-dsi-virtual-channel-id = <0>;
+ qcom,mdss-dsi-stream = <0>;
+ qcom,mdss-dsi-panel-width = <1080>;
+ qcom,mdss-dsi-panel-height = <1920>;
+ qcom,mdss-dsi-h-front-porch = <32>;
+ qcom,mdss-dsi-h-back-porch = <32>;
+ qcom,mdss-dsi-h-pulse-width = <8>;
+ qcom,mdss-dsi-h-sync-skew = <0>;
+ qcom,mdss-dsi-v-back-porch = <18>;
+ qcom,mdss-dsi-v-front-porch = <2>;
+ 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-underflow-color = <0xff>;
+ qcom,mdss-dsi-border-color = <0>;
+ qcom,mdss-dsi-on-command = [29 01 00 00 00 00 02 FF EE
29 01 00 00 00 00 02 FB 01
29 01 00 00 00 00 02 1F 45
29 01 00 00 00 00 02 24 4F
@@ -571,10 +563,27 @@
29 01 00 00 00 00 02 FF 00
29 01 00 00 00 00 02 35 00
29 01 00 00 78 00 02 29 00];
-
- qcom,on-cmds-dsi-state = "DSI_LP_MODE";
- qcom,panel-off-cmds = [05 01 00 00 32 00 02 28 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,off-cmds-dsi-state = "DSI_HS_MODE";
+ 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-bllp-eof-power-mode;
+ qcom,mdss-dsi-bllp-power-mode;
+ qcom,mdss-dsi-lane-0-state;
+ qcom,mdss-dsi-lane-1-state;
+ qcom,mdss-dsi-lane-2-state;
+ qcom,mdss-dsi-lane-3-state;
+ qcom,mdss-dsi-panel-timings = [f9 3d 34 00 58 4d 36 3f 53 03 04 00];
+ qcom,mdss-dsi-t-clk-post = <0x1e>;
+ 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-bl-pmic-control-type = "bl_ctrl_wled";
+
};
};
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 45d396c..7fe0f7f 100644
--- a/arch/arm/boot/dts/dsi-panel-sharp-qhd-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-sharp-qhd-video.dtsi
@@ -10,58 +10,65 @@
* GNU General Public License for more details.
*/
+/*---------------------------------------------------------------------------
+ * This file is autogenerated file using gcdb parser. Please do not edit it.
+ * Update input XML file to add a new entry or update variable in this file
+ * VERSION = "1.0"
+ *---------------------------------------------------------------------------*/
&soc {
qcom,mdss_dsi_sharp_qhd_video {
compatible = "qcom,mdss-dsi-panel";
- label = "sharp QHD LS043T1LE01 video mode dsi panel";
status = "disable";
- qcom,dsi-ctrl-phandle = <&mdss_dsi0>;
- qcom,enable-gpio = <&msmgpio 58 0>;
- qcom,rst-gpio = <&pm8941_gpios 19 0>;
- qcom,mdss-pan-res = <540 960>;
- qcom,mdss-pan-bpp = <24>;
- qcom,mdss-pan-dest = "display_1";
- qcom,mdss-pan-porch-values = <80 32 48 15 10 3>; /* HBP, HPW, HFP, VBP, VPW, VFP */
- qcom,mdss-pan-underflow-clr = <0xff>;
- qcom,mdss-pan-bl-ctrl = "bl_ctrl_wled";
- qcom,mdss-pan-bl-levels = <1 4095>;
- qcom,mdss-pan-dsi-mode = <0>;
- qcom,mdss-pan-dsi-h-pulse-mode = <1>;
- qcom,mdss-pan-dsi-h-power-stop = <0 0 0>;
- qcom,mdss-pan-dsi-bllp-power-stop = <1 1>;
- qcom,mdss-pan-dsi-traffic-mode = <0>;
- qcom,mdss-pan-dsi-dst-format = <3>;
- qcom,mdss-pan-dsi-vc = <0>;
- qcom,mdss-pan-dsi-rgb-swap = <2>;
- qcom,mdss-pan-dsi-data-lanes = <1 1 0 0>;
- qcom,mdss-pan-dsi-dlane-swap = <0>;
- qcom,mdss-pan-dsi-t-clk = <0x1c 0x04>;
- qcom,mdss-pan-dsi-stream = <0>;
- qcom,mdss-pan-dsi-mdp-tr = <0x04>;
- qcom,mdss-pan-dsi-dma-tr = <0x04>;
- qcom,mdss-pan-frame-rate = <60>;
- qcom,panel-phy-regulatorSettings = [07 09 03 00 /* Regulator settings */
- 20 00 01];
- qcom,panel-phy-timingSettings = [46 1d 20 00 39 3a
- 21 21 32 03 04 00];
- qcom,panel-phy-strengthCtrl = [ff 06];
- qcom,panel-phy-bistCtrl = [00 00 b1 ff /* BIST Ctrl settings */
- 00 00];
- qcom,panel-phy-laneConfig = [00 00 00 00 00 00 00 01 97 /* lane0 config */
- 00 00 00 00 05 00 00 01 97 /* lane1 config */
- 00 00 00 00 0a 00 00 01 97 /* lane2 config */
- 00 00 00 00 0f 00 00 01 97 /* lane3 config */
- 00 c0 00 00 00 00 00 01 bb]; /* Clk ln config */
- qcom,panel-on-cmds = [05 01 00 00 32 00 02 01 00 /* sw reset */
- 05 01 00 00 0a 00 02 11 00 /* exit sleep */
- 15 01 00 00 0a 00 02 53 2c /* backlight on */
- 15 01 00 00 0a 00 02 51 ff /* brightness max */
- 05 01 00 00 0a 00 02 29 00 /* display on */
- 15 01 00 00 0a 00 02 ae 03 /* set num of lanes */
- 15 01 00 00 0a 00 02 3a 77 /* rgb_888 */];
- qcom,on-cmds-dsi-state = "DSI_LP_MODE";
- qcom,panel-off-cmds = [05 01 00 00 0a 00 02 28 00 /* display off */
- 05 01 00 00 78 00 02 10 00 /* enter sleep */];
- qcom,off-cmds-dsi-state = "DSI_HS_MODE";
+ qcom,mdss-dsi-panel-name = "sharp QHD LS043T1LE01 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";
+ qcom,mdss-dsi-panel-framerate = <60>;
+ qcom,mdss-dsi-virtual-channel-id = <0>;
+ 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 = <80>;
+ qcom,mdss-dsi-h-pulse-width = <32>;
+ qcom,mdss-dsi-h-sync-skew = <0>;
+ qcom,mdss-dsi-v-back-porch = <15>;
+ qcom,mdss-dsi-v-front-porch = <3>;
+ qcom,mdss-dsi-v-pulse-width = <10>;
+ 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 = <2>;
+ 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
+ 05 01 00 00 0a 00 02 11 00
+ 15 01 00 00 0a 00 02 53 2c
+ 15 01 00 00 0a 00 02 51 ff
+ 05 01 00 00 0a 00 02 29 00
+ 15 01 00 00 0a 00 02 ae 03
+ 15 01 00 00 0a 00 02 3a 77];
+ qcom,mdss-dsi-off-command = [05 01 00 00 0a 00 02 28 00
+ 05 01 00 00 78 00 02 10 00];
+ qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+ qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+ qcom,mdss-dsi-h-sync-pulse = <1>;
+ qcom,mdss-dsi-traffic-mode = <0>;
+ qcom,mdss-dsi-lane-map = <0>;
+ 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 = [46 1d 20 00 39 3a 21 21 32 03 04 00];
+ qcom,mdss-dsi-t-clk-post = <0x04>;
+ 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-bl-pmic-control-type = "bl_ctrl_wled";
+
};
};
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 5c37cf8..a824d45 100644
--- a/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
@@ -10,115 +10,88 @@
* GNU General Public License for more details.
*/
+/*---------------------------------------------------------------------------
+ * This file is autogenerated file using gcdb parser. Please do not edit it.
+ * Update input XML file to add a new entry or update variable in this file
+ * VERSION = "1.0"
+ *---------------------------------------------------------------------------*/
&soc {
-
qcom,mdss_dsi_toshiba_720p_video {
compatible = "qcom,mdss-dsi-panel";
- label = "toshiba 720p video mode dsi panel";
status = "disable";
- qcom,dsi-ctrl-phandle = <&mdss_dsi0>;
- qcom,enable-gpio = <&msmgpio 58 0>;
- qcom,rst-gpio = <&pm8941_gpios 19 0>;
- qcom,mdss-pan-res = <720 1280>;
- qcom,mdss-pan-bpp = <24>;
- qcom,mdss-pan-dest = "display_1";
- qcom,mdss-pan-porch-values = <32 12 144 3 4 9>;
- qcom,mdss-pan-underflow-clr = <0xff>;
- qcom,mdss-pan-bl-ctrl = "bl_ctrl_wled";
- qcom,mdss-pan-bl-levels = <1 4095>;
- qcom,mdss-pan-dsi-mode = <0>;
- qcom,mdss-pan-dsi-h-pulse-mode = <0>;
- qcom,mdss-pan-dsi-h-power-stop = <0 0 0>;
- qcom,mdss-pan-dsi-bllp-power-stop = <1 1>;
- qcom,mdss-pan-dsi-traffic-mode = <1>;
- qcom,mdss-pan-dsi-dst-format = <3>;
- qcom,mdss-pan-dsi-vc = <0>;
- qcom,mdss-pan-dsi-rgb-swap = <0>;
- qcom,mdss-pan-dsi-data-lanes = <1 1 1 1>;
- qcom,mdss-pan-dsi-dlane-swap = <0>;
- qcom,mdss-pan-dsi-t-clk = <0x1b 0x04>;
- 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,panel-phy-regulatorSettings = [07 09 03 00 /* Regualotor settings */
- 20 00 01];
- qcom,panel-phy-timingSettings = [b0 23 1b 00 94 93
- 1e 25 15 03 04 00];
- qcom,panel-phy-strengthCtrl = [ff 06];
- qcom,panel-phy-bistCtrl = [00 00 b1 ff /* BIST Ctrl settings */
- 00 00];
- qcom,panel-phy-laneConfig = [00 00 00 00 00 00 00 01 97 /* lane0 config */
- 00 00 00 00 05 00 00 01 97 /* lane1 config */
- 00 00 00 00 0a 00 00 01 97 /* lane2 config */
- 00 00 00 00 0f 00 00 01 97 /* lane3 config */
- 00 c0 00 00 00 00 00 01 bb]; /* Clk ln config */
+ qcom,mdss-dsi-panel-name = "toshiba 720p 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";
+ qcom,mdss-dsi-panel-framerate = <60>;
+ qcom,mdss-dsi-virtual-channel-id = <0>;
+ qcom,mdss-dsi-stream = <0>;
+ qcom,mdss-dsi-panel-width = <720>;
+ qcom,mdss-dsi-panel-height = <1280>;
+ qcom,mdss-dsi-h-front-porch = <144>;
+ qcom,mdss-dsi-h-back-porch = <32>;
+ qcom,mdss-dsi-h-pulse-width = <12>;
+ qcom,mdss-dsi-h-sync-skew = <0>;
+ qcom,mdss-dsi-v-back-porch = <3>;
+ qcom,mdss-dsi-v-front-porch = <9>;
+ qcom,mdss-dsi-v-pulse-width = <4>;
+ 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-underflow-color = <0xff>;
+ qcom,mdss-dsi-border-color = <0>;
+ qcom,mdss-dsi-on-command = [23 01 00 00 0a 00 02 b0 00
+ 23 01 00 00 0a 00 02 b2 00
+ 23 01 00 00 0a 00 02 b3 0c
+ 23 01 00 00 0a 00 02 b4 02
+ 29 01 00 00 00 00 06 c0 40 02 7f c8 08
+ 29 01 00 00 00 00 10 c1 00 a8 00 00 00 00 00 9d 08 27 00 00 00 00 00
+ 29 01 00 00 00 00 06 c2 00 00 09 00 00
+ 23 01 00 00 0a 00 02 c3 04
+ 29 01 00 00 00 00 04 c4 4d 83 00
+ 29 01 00 00 00 00 0b c6 12 00 08 71 00 00 00 80 00 04
+ 23 01 00 00 0a 00 02 c7 22
+ 29 01 00 00 00 00 05 c8 4c 0c 0c 0c
+ 29 01 00 00 00 00 0e c9 00 40 00 16 32 2e 3a 43 3e 3c 45 79 3f
+ 29 01 00 00 00 00 0e ca 00 46 1a 23 21 1c 25 31 2d 49 5f 7f 3f
+ 29 01 00 00 00 00 0e cb 00 4c 20 3a 42 40 47 4b 42 3e 46 7e 3f
+ 29 01 00 00 00 00 0e cc 00 41 19 21 1d 14 18 1f 1d 25 3f 73 3f
+ 29 01 00 00 00 00 0e cd 23 79 5a 5f 57 4c 51 51 45 3f 4b 7f 3f
+ 29 01 00 00 00 00 0e ce 00 40 14 20 1a 0e 0e 13 08 00 05 46 1c
+ 29 01 00 00 00 00 04 d0 6a 64 01
+ 29 01 00 00 00 00 03 d1 77 d4
+ 23 01 00 00 0a 00 02 d3 33
+ 29 01 00 00 00 00 03 d5 0f 0f
+ 29 01 00 00 00 00 07 d8 34 64 23 25 62 32
+ 29 01 00 00 00 00 0c de 10 7b 11 0a 00 00 00 00 00 00 00
+ 29 01 00 00 00 00 09 fd 04 55 53 00 70 ff 10 73
+ 23 01 00 00 0a 00 02 e2 00
+ 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_hs_mode";
+ qcom,mdss-dsi-h-sync-pulse = <0>;
+ qcom,mdss-dsi-traffic-mode = <1>;
+ qcom,mdss-dsi-lane-map = <0>;
+ qcom,mdss-dsi-bllp-eof-power-mode;
+ qcom,mdss-dsi-bllp-power-mode;
+ qcom,mdss-dsi-lane-0-state;
+ qcom,mdss-dsi-lane-1-state;
+ qcom,mdss-dsi-lane-2-state;
+ qcom,mdss-dsi-lane-3-state;
+ qcom,mdss-dsi-panel-timings = [b0 23 1b 00 94 93 1e 25 15 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-max-level = <4095>;
+ qcom,mdss-dsi-dma-trigger = <0x04>;
+ qcom,mdss-dsi-mdp-trigger = <0x0>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
- qcom,panel-on-cmds = [23 01 00 00 0a 00 02 b0 00
- 23 01 00 00 0a 00 02 b2 00
- 23 01 00 00 0a 00 02 b3 0c
- 23 01 00 00 0a 00 02 b4 02
- 29 01 00 00 00 00 06
- c0 40 02 7f c8 08
- 29 01 00 00 00 00 10
- c1 00 a8 00 00 00
- 00 00 9d 08 27 00
- 00 00 00 00
- 29 01 00 00 00 00 06
- c2 00 00 09 00 00
- 23 01 00 00 0a 00 02 c3 04
- 29 01 00 00 00 00 04
- c4 4d 83 00
- 29 01 00 00 00 00 0b
- c6 12 00 08 71 00
- 00 00 80 00 04
- 23 01 00 00 0a 00 02 c7 22
- 29 01 00 00 00 00 05
- c8 4c 0c 0c 0c
- 29 01 00 00 00 00 0e
- c9 00 40 00 16 32
- 2e 3a 43 3e 3c 45
- 79 3f
- 29 01 00 00 00 00 0e
- ca 00 46 1a 23 21
- 1c 25 31 2d 49 5f
- 7f 3f
- 29 01 00 00 00 00 0e
- cb 00 4c 20 3a 42
- 40 47 4b 42 3e 46
- 7e 3f
- 29 01 00 00 00 00 0e
- cc 00 41 19 21 1d
- 14 18 1f 1d 25 3f
- 73 3f
- 29 01 00 00 00 00 0e
- cd 23 79 5a 5f 57
- 4c 51 51 45 3f 4b
- 7f 3f
- 29 01 00 00 00 00 0e
- ce 00 40 14 20 1a
- 0e 0e 13 08 00 05
- 46 1c
- 29 01 00 00 00 00 04
- d0 6a 64 01
- 29 01 00 00 00 00 03 d1 77 d4
- 23 01 00 00 0a 00 02 d3 33
- 29 01 00 00 00 00 03 d5 0f 0f
- 29 01 00 00 00 00 07
- d8 34 64 23 25 62
- 32
- 29 01 00 00 00 00 0c
- de 10 7b 11 0a 00
- 00 00 00 00 00 00
- 29 01 00 00 00 00 09
- fd 04 55 53 00 70
- ff 10 73
- 23 01 00 00 0a 00 02 e2 00
- 05 01 00 00 78 00 02 11 00
- 05 01 00 00 32 00 02 29 00];
- qcom,on-cmds-dsi-state = "DSI_LP_MODE";
- qcom,panel-off-cmds = [05 01 00 00 32 00 02 28 00
- 05 01 00 00 78 00 02 10 00];
- qcom,off-cmds-dsi-state = "DSI_HS_MODE";
};
};
diff --git a/arch/arm/boot/dts/dsi-v2-panel-hx8379a-wvga-video.dtsi b/arch/arm/boot/dts/dsi-v2-panel-hx8379a-wvga-video.dtsi
index b9ed050..befc29c 100644
--- a/arch/arm/boot/dts/dsi-v2-panel-hx8379a-wvga-video.dtsi
+++ b/arch/arm/boot/dts/dsi-v2-panel-hx8379a-wvga-video.dtsi
@@ -40,7 +40,7 @@
qcom,mdss-pan-dsi-mdp-tr = <0x0>;/*todo*/
qcom,mdss-pan-dsi-dma-tr = <0x04>;
qcom,mdss-pan-dsi-frame-rate = <60>;
- qcom,panel-phy-regulatorSettings =[09 08 05 00 20 03];
+ qcom,panel-phy-regulatorSettings =[02 08 05 00 20 03];
qcom,panel-phy-timingSettings = [5D 12 0C 00 33 39
10 16 15 03 04 00];
qcom,panel-phy-strengthCtrl = [ff 06];
diff --git a/arch/arm/boot/dts/dsi-v2-panel-otm8018b-fwvga-video.dtsi b/arch/arm/boot/dts/dsi-v2-panel-otm8018b-fwvga-video.dtsi
new file mode 100644
index 0000000..c2c64da
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-v2-panel-otm8018b-fwvga-video.dtsi
@@ -0,0 +1,261 @@
+/* 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,dsi_v2_otm8018b_fwvga_video {
+ compatible = "qcom,dsi-panel-v2";
+ label = "OTM8018B FWVGA video mode dsi panel";
+ qcom,dsi-ctrl-phandle = <&mdss_dsi0>;
+ qcom,rst-gpio = <&msmgpio 41 0>;
+ vdda-supply = <&pm8110_l19>;
+ vddio-supply=<&pm8110_l14>;
+ qcom,mdss-pan-res = <480 854>;
+ qcom,mdss-pan-bpp = <24>;
+ qcom,mdss-pan-dest = "display_1";
+ qcom,mdss-pan-porch-values = <54 8 80 16 2 12>;
+ qcom,mdss-pan-underflow-clr = <0xff>;
+ qcom,mdss-pan-bl-levels = <1 255>;
+ qcom,mdss-pan-bl-ctrl = "bl_ctrl_wled";
+ qcom,mdss-pan-dsi-mode = <0>;
+ qcom,mdss-pan-dsi-h-pulse-mode = <0>;
+ qcom,mdss-pan-dsi-h-power-stop = <0 0 0>;
+ qcom,mdss-pan-dsi-bllp-power-stop = <1 1>;
+ qcom,mdss-pan-dsi-traffic-mode = <1>;
+ qcom,mdss-pan-dsi-dst-format = <3>;
+ qcom,mdss-pan-dsi-vc = <0>;
+ qcom,mdss-pan-dsi-rgb-swap = <0>;
+ qcom,mdss-pan-dsi-data-lanes = <1 1 0 0>;
+ qcom,mdss-pan-dsi-dlane-swap = <1>;
+ qcom,mdss-pan-dsi-t-clk = <0x1b 0x04>;
+ qcom,mdss-pan-dsi-stream = <0>;
+ qcom,mdss-pan-dsi-mdp-tr = <0x0>;/*todo*/
+ qcom,mdss-pan-dsi-dma-tr = <0x04>;
+ qcom,mdss-pan-dsi-frame-rate = <60>;
+ qcom,panel-phy-regulatorSettings =[02 08 05 00 20 03];
+ qcom,panel-phy-timingSettings = [8B 1F 14 00 45 4A
+ 19 23 23 03 04 00];
+ qcom,panel-phy-strengthCtrl = [ff 06];
+ qcom,panel-phy-bistCtrl = [03 03 00 00 0f 00];
+ qcom,panel-phy-laneConfig =
+ [80 45 00 00 01 66 /*lane0**/
+ 80 45 00 00 01 66 /*lane1*/
+ 80 45 00 00 01 66 /*lane2*/
+ 80 45 00 00 01 66 /*lane3*/
+ 40 67 00 00 01 88]; /*Clk*/
+
+ qcom,on-cmds-dsi-state = "DSI_LP_MODE";
+ qcom,panel-on-cmds = [
+ 29 01 00 00 00 02
+ 00 00
+ 29 01 00 00 00 04
+ ff 80 09 01
+ 29 01 00 00 00 02
+ 00 80
+ 29 01 00 00 00 03
+ ff 80 09
+ 29 01 00 00 00 02
+ 00 80
+ 29 01 00 00 00 02
+ d6 48
+ 29 01 00 00 00 02
+ 00 03
+ 29 01 00 00 00 02
+ ff 01
+ 29 01 00 00 00 02
+ 00 B4
+ 29 01 00 00 00 02
+ C0 10
+ 29 01 00 00 00 02
+ 00 82
+ 29 01 00 00 00 02
+ C5 A3
+ 29 01 00 00 00 02
+ 00 90
+ 29 01 00 00 00 03
+ C5 96 87
+ 29 01 00 00 00 02
+ 00 00
+ 29 01 00 00 00 03
+ D8 74 72
+ 29 01 00 00 00 02
+ 00 00
+ 29 01 00 00 00 02
+ D9 56
+ 29 01 00 00 00 02
+ 00 00
+ 29 01 00 00 00 11
+ E1 00 06 0A
+ 07 03 16 08
+ 0A 04 06 07
+ 08 0F 23 22
+ 05
+ 29 01 00 00 00 02
+ 00 00
+ 29 01 00 00 00 11
+ E2 00 06 0A
+ 07 03 16 08
+ 0A 04 06 07
+ 08 0F 23 22
+ 05
+ 29 01 00 00 00 02
+ 00 81
+ 29 01 00 00 00 02
+ C1 77
+ 29 01 00 00 00 02
+ 00 A0
+ 29 01 00 00 00 02
+ C1 EA
+ 29 01 00 00 00 02
+ 00 A1
+ 29 01 00 00 00 02
+ C1 08
+ 29 01 00 00 00 02
+ 00 89
+ 29 01 00 00 00 02
+ C4 08
+ 29 01 00 00 00 02
+ 00 81
+ 29 01 00 00 00 02
+ C4 83
+ 29 01 00 00 00 02
+ 00 92
+ 29 01 00 00 00 02
+ C5 01
+ 29 01 00 00 00 02
+ 00 B1
+ 29 01 00 00 00 02
+ C5 A9
+ 29 01 00 00 00 02
+ 00 92
+ 29 01 00 00 00 02
+ B3 45
+ 29 01 00 00 00 02
+ 00 90
+ 29 01 00 00 00 02
+ B3 02
+ 29 01 00 00 00 02
+ 00 80
+ 29 01 00 00 00 06
+ C0 00 58 00
+ 14 16
+ 29 01 00 00 00 02
+ 00 80
+ 29 01 00 00 00 02
+ C4 30
+ 29 01 00 00 00 02
+ 00 90
+ 29 01 00 00 00 07
+ C0 00 44 00
+ 00 00 03
+ 29 01 00 00 00 02
+ 00 A6
+ 29 01 00 00 00 04
+ C1 01 00 00
+ 29 01 00 00 00 02
+ 00 80
+ 29 01 00 00 00 0D
+ CE 87 03 00
+ 85 03 00 86
+ 03 00 84 03
+ 00
+ 29 01 00 00 00 02
+ 00 A0
+ 29 01 00 00 00 0f
+ CE 38 03 03
+ 58 00 00 00
+ 38 02 03 59
+ 00 00 00
+ 29 01 00 00 00 02
+ 00 B0
+ 29 01 00 00 00 0f
+ CE 38 01 03
+ 5A 00 00 00
+ 38 00 03 5B
+ 00 00 00
+ 29 01 00 00 00 02
+ 00 C0
+ 29 01 00 00 00 0f
+ CE 30 00 03
+ 5C 00 00 00
+ 30 01 03 5D
+ 00 00 00
+ 29 01 00 00 00 02
+ 00 D0
+ 29 01 00 00 00 0f
+ CE 30 02 03
+ 5E 00 00 00
+ 30 03 03 5F
+ 00 00 00
+ 29 01 00 00 00 02
+ 00 C7
+ 29 01 00 00 00 02
+ CF 00
+ 29 01 00 00 00 02
+ 00 C9
+ 29 01 00 00 00 02
+ CF 00
+ 29 01 00 00 00 02
+ 00 D0
+ 29 01 00 00 00 02
+ CF 00
+ 29 01 00 00 00 02
+ 00 C4
+ 29 01 00 00 00 07
+ CB 04 04 04
+ 04 04 04
+ 29 01 00 00 00 02
+ 00 D9
+ 29 01 00 00 00 07
+ CB 04 04 04
+ 04 04 04
+ 29 01 00 00 00 02
+ 00 84
+ 29 01 00 00 00 07
+ CC 0C 0A 10
+ 0E 03 04
+ 29 01 00 00 00 02
+ 00 9E
+ 29 01 00 00 00 02
+ CC 0B
+ 29 01 00 00 00 02
+ 00 A0
+ 29 01 00 00 00 06
+ CC 09 0F 0D
+ 01 02
+ 29 01 00 00 00 02
+ 00 B4
+ 29 01 00 00 00 07
+ CC 0D 0F 09
+ 0B 02 01
+ 29 01 00 00 00 02
+ 00 CE
+ 29 01 00 00 00 02
+ CC 0E
+ 29 01 00 00 00 02
+ 00 D0
+ 29 01 00 00 00 06
+ CC 10 0A 0C
+ 04 03
+ 29 01 00 00 00 02
+ 00 00
+ 29 01 00 00 00 04
+ ff ff ff ff
+ 05 01 00 00 78 02
+ 11 00
+ 05 01 00 00 32 02
+ 29 00
+ ];
+ qcom,panel-off-cmds = [05 01 00 00 32 02 28 00
+ 05 01 00 00 78 02 10 00];
+ qcom,off-cmds-dsi-state = "DSI_LP_MODE";
+ };
+};
diff --git a/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-cmd.dtsi b/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-cmd.dtsi
new file mode 100644
index 0000000..f57a7bd
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-cmd.dtsi
@@ -0,0 +1,124 @@
+/* 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,dsi_v2_truly_wvga_video {
+ compatible = "qcom,dsi-panel-v2";
+ label = "Truly WVGA command mode dsi panel";
+ qcom,dsi-ctrl-phandle = <&mdss_dsi0>;
+ qcom,rst-gpio = <&msmgpio 41 0>;
+ qcom,mode-selection-gpio = <&msmgpio 7 0>;
+ qcom,te-gpio = <&msmgpio 12 0>;
+ vdda-supply = <&pm8110_l19>;
+ vddio-supply=<&pm8110_l14>;
+ qcom,mdss-pan-res = <480 800>;
+ qcom,mdss-pan-bpp = <24>;
+ qcom,mdss-pan-dest = "display_1";
+ qcom,mdss-pan-porch-values = <40 8 160 10 2 12>;
+ qcom,mdss-pan-underflow-clr = <0xff>;
+ qcom,mdss-pan-bl-levels = <1 255>;
+ qcom,mdss-pan-bl-ctrl = "bl_ctrl_wled";
+ qcom,mdss-pan-dsi-mode = <1>;
+ qcom,mdss-pan-dsi-h-pulse-mode = <0>;
+ qcom,mdss-pan-dsi-h-power-stop = <0 0 0>;
+ qcom,mdss-pan-dsi-bllp-power-stop = <1 1>;
+ qcom,mdss-pan-dsi-traffic-mode = <1>;
+ qcom,mdss-pan-dsi-dst-format = <8>;
+ qcom,mdss-pan-insert-dcs-cmd = <1>;
+ qcom,mdss-pan-wr-mem-continue = <0x3c>;
+ qcom,mdss-pan-wr-mem-start = <0x2c>;
+ qcom,mdss-pan-dsi-vc = <0>;
+ qcom,mdss-pan-dsi-rgb-swap = <0>;
+ qcom,mdss-pan-dsi-data-lanes = <1 1 0 0>;
+ qcom,mdss-pan-dsi-dlane-swap = <0>;
+ qcom,mdss-pan-dsi-t-clk = <0x1b 0x04>;
+ qcom,mdss-pan-dsi-stream = <0>;
+ qcom,mdss-pan-dsi-mdp-tr = <0x02>;
+ qcom,mdss-pan-dsi-dma-tr = <0x04>;
+ qcom,mdss-pan-dsi-frame-rate = <60>;
+ qcom,panel-phy-regulatorSettings =[02 08 05 00 20 03];
+ qcom,panel-phy-timingSettings = [5D 12 0C 00 33 38
+ 10 16 1E 03 04 00];
+ qcom,panel-phy-strengthCtrl = [ff 06];
+ qcom,panel-phy-bistCtrl = [03 03 00 00 0f 00];
+ qcom,panel-phy-laneConfig =
+ [80 45 00 00 01 66 /*lane0**/
+ 80 45 00 00 01 66 /*lane1*/
+ 80 45 00 00 01 66 /*lane2*/
+ 80 45 00 00 01 66 /*lane3*/
+ 40 67 00 00 01 88]; /*Clk*/
+
+ qcom,on-cmds-dsi-state = "DSI_LP_MODE";
+ qcom,panel-on-cmds = [
+ 05 01 00 00 00 02
+ 01 00
+ 23 01 00 00 00 02
+ b0 04
+ 29 01 00 00 00 03
+ b3 02 00
+ 23 01 00 00 00 02
+ bd 00
+ 29 01 00 00 00 03
+ c0 18 66
+ 29 01 00 00 00 10
+ c1 23 31 99 21 20 00 30 28 0c 0c
+ 00 00 00 21 01
+ 29 01 00 00 00 07
+ c2 00 06 06 01 03 00
+ 29 01 00 00 00 19
+ c8 04 10 18 20 2e 46 3c 28 1f 18
+ 10 04 04 10 18 20 2e 46 3c 28 1f 18 10 04
+ 29 01 00 00 00 19
+ c9 04 10 18 20 2e 46 3c 28 1f 18
+ 10 04 04 10 18 20 2e 46 3c 28 1f 18 10 04
+ 29 01 00 00 00 19
+ ca 04 10 18 20 2e 46 3c 28 1f 18
+ 10 04 04 10 18 20 2e 46 3c 28 1f 18 10 04
+ 29 01 00 00 00 11
+ d0 29 03 ce a6 00 43 20 10 01 00
+ 01 01 00 03 01 00
+ 29 01 00 00 00 08
+ d1 18 0C 23 03 75 02 50
+ 23 01 00 00 00 02
+ d3 11
+ 29 01 00 00 00 03
+ d5 2a 2a
+ 29 01 00 00 00 03
+ de 01 51
+ 23 01 00 00 00 02
+ e6 51
+ 23 01 00 00 00 02
+ fa 03
+ 23 01 00 00 64 02
+ d6 28
+ 15 01 00 00 00 02
+ 36 41
+ 39 01 00 00 00 05
+ 2a 00 00 01 df
+ 39 01 00 00 00 05
+ 2b 00 00 03 1f
+ 15 01 00 00 00 02
+ 35 00
+ 39 01 00 00 00 03
+ 44 00 50
+ 15 01 00 00 00 02
+ 3a 77
+ 05 01 00 00 7D 02
+ 11 00
+ 05 01 00 00 14 02
+ 29 00
+ ];
+ qcom,panel-off-cmds = [05 01 00 00 32 02 28 00
+ 05 01 00 00 78 02 10 00];
+ qcom,off-cmds-dsi-state = "DSI_LP_MODE";
+ };
+};
diff --git a/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-video.dtsi b/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-video.dtsi
index 891eac3..8be8d71 100644
--- a/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-video.dtsi
+++ b/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-video.dtsi
@@ -41,7 +41,7 @@
qcom,mdss-pan-dsi-mdp-tr = <0x0>;/*todo*/
qcom,mdss-pan-dsi-dma-tr = <0x04>;
qcom,mdss-pan-dsi-frame-rate = <60>;
- qcom,panel-phy-regulatorSettings =[09 08 05 00 20 03];
+ qcom,panel-phy-regulatorSettings =[02 08 05 00 20 03];
qcom,panel-phy-timingSettings = [5D 12 0C 00 33 38
10 16 1E 03 04 00];
qcom,panel-phy-strengthCtrl = [ff 06];
@@ -69,7 +69,7 @@
c1 23 31 99 21 20 00 30 28 0c 0c
00 00 00 21 01
29 01 00 00 00 07
- c2 10 06 06 01 03 00
+ c2 00 06 06 01 03 00
29 01 00 00 00 19
c8 04 10 18 20 2e 46 3c 28 1f 18
10 04 04 10 18 20 2e 46 3c 28 1f 18 10 04
@@ -89,7 +89,7 @@
29 01 00 00 00 03
d5 2a 2a
29 01 00 00 00 03
- de 01 41
+ de 01 51
23 01 00 00 00 02
e6 51
23 01 00 00 00 02
diff --git a/arch/arm/boot/dts/mpq8092-iommu-domains.dtsi b/arch/arm/boot/dts/mpq8092-iommu-domains.dtsi
new file mode 100644
index 0000000..25fca2a
--- /dev/null
+++ b/arch/arm/boot/dts/mpq8092-iommu-domains.dtsi
@@ -0,0 +1,31 @@
+/* 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 {
+ qcom,iommu-domains {
+ compatible = "qcom,iommu-domains";
+
+ venus_domain_ns: qcom,iommu-domain1 {
+ label = "venus_ns";
+ qcom,iommu-contexts = <&venus_ns>;
+ qcom,virtual-addr-pool = <0x40000000 0x3f000000
+ 0x7f000000 0x1000000>;
+ };
+
+ venus_domain_cp: qcom,iommu-domain2 {
+ label = "venus_cp";
+ qcom,iommu-contexts = <&venus_cp>;
+ qcom,virtual-addr-pool = <0x1000000 0x3f000000>;
+ qcom,secure-domain;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/mpq8092-iommu.dtsi b/arch/arm/boot/dts/mpq8092-iommu.dtsi
index 56369dc..baec2d5 100644
--- a/arch/arm/boot/dts/mpq8092-iommu.dtsi
+++ b/arch/arm/boot/dts/mpq8092-iommu.dtsi
@@ -14,27 +14,218 @@
&jpeg_iommu {
status = "ok";
- vdd-supply = <&gdsc_jpeg>;
+
+ qcom,iommu-bfb-regs = <0x204c
+ 0x2514
+ 0x2540
+ 0x256c
+ 0x2314
+ 0x2394
+ 0x2414
+ 0x2494
+ 0x20ac
+ 0x215c
+ 0x220c
+ 0x22bc
+ 0x2008
+ 0x200c
+ 0x2010>;
+
+ qcom,iommu-bfb-data = <0x3FFF
+ 0x4
+ 0x4
+ 0x0
+ 0x0
+ 0x10
+ 0x50
+ 0x0
+ 0x2000
+ 0x2804
+ 0x9614
+ 0x0
+ 0x0
+ 0x0
+ 0x0>;
};
&mdp_iommu {
status = "ok";
- vdd-supply = <&gdsc_mdss>;
+
+ qcom,iommu-bfb-regs = <0x204c
+ 0x2514
+ 0x2540
+ 0x256c
+ 0x20ac
+ 0x215c
+ 0x220c
+ 0x22bc
+ 0x2314
+ 0x2394
+ 0x2414
+ 0x2494
+ 0x2008
+ 0x200c
+ 0x2010
+ 0x2014
+ 0x2018>;
+
+ qcom,iommu-bfb-data = <0x7FFFFF
+ 0x4
+ 0x10
+ 0x0
+ 0x5000
+ 0x5a1d
+ 0x1822d
+ 0x0
+ 0x0
+ 0x28
+ 0x68
+ 0x0
+ 0x0
+ 0x0
+ 0x0
+ 0x0
+ 0x0>;
};
&venus_iommu {
status = "ok";
- vdd-supply = <&gdsc_venus>;
+
+ qcom,iommu-bfb-regs = <0x204c
+ 0x2514
+ 0x2540
+ 0x256c
+ 0x20ac
+ 0x215c
+ 0x220c
+ 0x22bc
+ 0x2314
+ 0x2394
+ 0x2414
+ 0x2494
+ 0x2008
+ 0x200c
+ 0x2010
+ 0x2014
+ 0x2018
+ 0x201c>;
+
+ qcom,iommu-bfb-data = <0x7FFFFFF
+ 0x4
+ 0x8
+ 0x0
+ 0x13607
+ 0x4201
+ 0x14221
+ 0x0
+ 0x0
+ 0x94
+ 0x114
+ 0x0
+ 0x0
+ 0x0
+ 0x0
+ 0x0
+ 0x0
+ 0x0>;
+
+ venus_ns: qcom,iommu-ctx@fdc8c000 {
+ qcom,iommu-ctx-sids = <0 1 2 3 4 5 7>;
+ };
+
+ venus_sec_bitstream: qcom,iommu-ctx@fdc8d000 {
+ qcom,iommu-ctx-sids = <0x80 0x81 0x82 0x83 0x84>;
+ label = "venus_sec_bitstream";
+ };
+
+ venus_sec_pixel: qcom,iommu-ctx@fdc8f000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
+ reg = <0xfdc8f000 0x1000>;
+ interrupts = <0 42 0>;
+ qcom,iommu-ctx-sids = <0x85>;
+ label = "venus_sec_pixel";
+ qcom,secure-context;
+ };
+
+ venus_sec_non_pixel: qcom,iommu-ctx@fdc90000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
+ reg = <0xfdc90000 0x1000>;
+ interrupts = <0 42 0>;
+ qcom,iommu-ctx-sids = <0x87 0xA0>;
+ label = "venus_sec_non_pixel";
+ qcom,secure-context;
+ };
};
&kgsl_iommu {
status = "ok";
- qcom,needs-alt-core-clk;
- vdd-supply = <&gdsc_oxili_cx>;
- qcom,alt-vdd-supply = <&gdsc_oxili_gx>;
+
+ qcom,iommu-bfb-regs = <0x204c
+ 0x2514
+ 0x2540
+ 0x256c
+ 0x20ac
+ 0x215c
+ 0x220c
+ 0x22bc
+ 0x2314
+ 0x2394
+ 0x2414
+ 0x2494
+ 0x2008
+ 0x2600
+ 0x2604
+ 0x2608
+ 0x260c
+ 0x2610
+ 0x2614
+ 0x2618
+ 0x261c
+ 0x2620
+ 0x2624
+ 0x2628
+ 0x262c>;
+
+ qcom,iommu-bfb-data = <0x3
+ 0x8
+ 0x10
+ 0x0
+ 0x0
+ 0x0
+ 0x20
+ 0x0
+ 0x0
+ 0x1
+ 0x101
+ 0x0
+ 0x0
+ 0x7
+ 0x4
+ 0x8
+ 0x14
+ 0x0
+ 0x0
+ 0xc
+ 0x6c
+ 0x0
+ 0x8
+ 0x10
+ 0x0>;
};
-&vfe_iommu {
+&vpu_iommu {
status = "ok";
- vdd-supply = <&gdsc_vfe>;
+
+ interrupts = <0 300 0>;
+ vpu_cb_0: qcom,iommu-ctx@fdeec000 {
+ interrupts = <0 302 0>;
+ };
+
+ vpu_cb_1: qcom,iommu-ctx@fdeed000 {
+ interrupts = <0 302 0>;
+ };
+
+ vpu_cb_2: qcom,iommu-ctx@fdeee000 {
+ interrupts = <0 302 0>;
+ };
};
diff --git a/arch/arm/boot/dts/mpq8092-rumi.dtsi b/arch/arm/boot/dts/mpq8092-rumi.dtsi
index 2016998..cc345d8 100644
--- a/arch/arm/boot/dts/mpq8092-rumi.dtsi
+++ b/arch/arm/boot/dts/mpq8092-rumi.dtsi
@@ -24,13 +24,13 @@
};
qcom,sdcc@f9824000 {
- status = "disabled";
qcom,clk-rates = <400000 19200000>;
+ status = "ok";
};
qcom,sdcc@f98a4000 {
- status = "disabled";
qcom,clk-rates = <400000 19200000>;
+ status = "ok";
};
qcom,sps@f998000 {
diff --git a/arch/arm/boot/dts/mpq8092.dtsi b/arch/arm/boot/dts/mpq8092.dtsi
index 2eaa32f..2f67f3e 100644
--- a/arch/arm/boot/dts/mpq8092.dtsi
+++ b/arch/arm/boot/dts/mpq8092.dtsi
@@ -21,6 +21,7 @@
};
/include/ "mpq8092-iommu.dtsi"
+/include/ "mpq8092-iommu-domains.dtsi"
/include/ "msm-gdsc.dtsi"
/include/ "mpq8092-ion.dtsi"
@@ -140,6 +141,38 @@
reg = <0xfe805000 0x1000>; /* Address and size of IMEM */
};
+ usb@f9a55000 {
+ compatible = "qcom,hsusb-otg";
+ reg = <0xf9a55000 0x400>;
+ interrupts = <0 134 0>, <0 140 0>;
+ interrupt-names = "core_irq", "async_irq";
+
+ HSUSB_VDDCX-supply = <&pma8084_s8>;
+ HSUSB_1p8-supply = <&pma8084_l22>;
+ HSUSB_3p3-supply = <&pma8084_l24>;
+ qcom,vdd-voltage-level = <1050000 1050000>;
+
+ qcom,hsusb-otg-phy-type = <2>;
+ qcom,hsusb-otg-mode = <1>;
+ qcom,hsusb-otg-otg-control = <1>;
+ qcom,hsusb-otg-disable-reset;
+
+ qcom,msm_bus,name = "usb_otg";
+ qcom,msm_bus,num_cases = <3>;
+ qcom,msm_bus,active_only = <0>;
+ qcom,msm_bus,num_paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <87 512 0 0>,
+ <87 512 60000 960000>,
+ <87 512 6000 6000>;
+ };
+
+ android_usb@fe8050c8 {
+ compatible = "qcom,android-usb";
+ reg = <0xfe8050c8 0xc8>;
+ qcom,android-usb-swfi-latency = <1>;
+ };
+
spmi_bus: qcom,spmi@fc4c0000 {
cell-index = <0>;
compatible = "qcom,spmi-pmic-arb";
@@ -259,6 +292,10 @@
status = "ok";
};
+&gdsc_vpu {
+ status = "ok";
+};
+
&gdsc_oxili_gx {
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm-gdsc.dtsi b/arch/arm/boot/dts/msm-gdsc.dtsi
index 78234e8..495f65a 100644
--- a/arch/arm/boot/dts/msm-gdsc.dtsi
+++ b/arch/arm/boot/dts/msm-gdsc.dtsi
@@ -19,6 +19,27 @@
status = "disabled";
};
+ gdsc_venus_core0: qcom,gdsc@fd8c1040 {
+ compatible = "qcom,gdsc";
+ regulator-name = "gdsc_venus_core0";
+ reg = <0xfd8c1040 0x4>;
+ status = "disabled";
+ };
+
+ gdsc_venus_core1: qcom,gdsc@fd8c1044 {
+ compatible = "qcom,gdsc";
+ regulator-name = "gdsc_venus_core1";
+ reg = <0xfd8c1044 0x4>;
+ status = "disabled";
+ };
+
+ gdsc_vpu: qcom,gdsc@fd8c1404 {
+ compatible = "qcom,gdsc";
+ regulator-name = "gdsc_vpu";
+ reg = <0xfd8c1404 0x4>;
+ status = "disabled";
+ };
+
gdsc_mdss: qcom,gdsc@fd8c2304 {
compatible = "qcom,gdsc";
regulator-name = "gdsc_mdss";
@@ -60,4 +81,32 @@
reg = <0xfc400404 0x4>;
status = "disabled";
};
+
+ gdsc_pcie_0: qcom,gdsc@fc401ac4 {
+ compatible = "qcom,gdsc";
+ regulator-name = "gdsc_pcie_0";
+ reg = <0xfc401ac4 0x4>;
+ status = "disabled";
+ };
+
+ gdsc_pcie_1: qcom,gdsc@fc401b44 {
+ compatible = "qcom,gdsc";
+ regulator-name = "gdsc_pcie_1";
+ reg = <0xfc401b44 0x4>;
+ status = "disabled";
+ };
+
+ gdsc_usb30: qcom,gdsc@fc401e84 {
+ compatible = "qcom,gdsc";
+ regulator-name = "gdsc_usb30";
+ reg = <0xfc401e84 0x4>;
+ status = "disabled";
+ };
+
+ gdsc_usb30_sec: qcom,gdsc@fc401ec0 {
+ compatible = "qcom,gdsc";
+ regulator-name = "gdsc_usb30_sec";
+ reg = <0xfc401ec0 0x4>;
+ status = "disabled";
+ };
};
diff --git a/arch/arm/boot/dts/msm-iommu-v1.dtsi b/arch/arm/boot/dts/msm-iommu-v1.dtsi
index 4492077..ef8677d 100644
--- a/arch/arm/boot/dts/msm-iommu-v1.dtsi
+++ b/arch/arm/boot/dts/msm-iommu-v1.dtsi
@@ -408,6 +408,15 @@
qcom,iommu-ctx-sids = <1>;
label = "gfx3d_priv";
};
+
+ qcom,iommu-ctx@fdb1a000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
+ reg = <0xfdb1a000 0x1000>;
+ interrupts = <0 241 0>;
+ qcom,iommu-ctx-sids = <2>;
+ label = "gfx3d_spare";
+ };
+
};
vfe_iommu: qcom,iommu@fda44000 {
@@ -511,4 +520,540 @@
label = "cpp";
};
};
+
+ copss_iommu: qcom,iommu@f9bc4000 {
+ compatible = "qcom,msm-smmu-v1";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ reg = <0xf9bc4000 0x10000>;
+ reg-names = "iommu_base";
+ interrupts = <0 153 0>;
+ label = "copss_iommu";
+ qcom,msm-bus,name = "copss_ebi";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,active-only;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <88 512 0 0>,
+ <88 512 0 1000>;
+ status = "disabled";
+ qcom,iommu-pmu-ngroups = <1>;
+ qcom,iommu-pmu-ncounters = <8>;
+ qcom,iommu-pmu-event-classes = <0x00
+ 0x01
+ 0x08
+ 0x09
+ 0x0a
+ 0x10
+ 0x11
+ 0x12
+ 0x80
+ 0x81
+ 0x82
+ 0x83
+ 0x90
+ 0x91
+ 0x92
+ 0xb0
+ 0xb1>;
+
+ qcom,iommu-bfb-regs = <0x204c
+ 0x2514
+ 0x2540
+ 0x256c
+ 0x20ac
+ 0x215c
+ 0x220c
+ 0x22bc
+ 0x2314
+ 0x2394
+ 0x2414
+ 0x2494
+ 0x2008>;
+
+ qcom,iommu-bfb-data = <0x3
+ 0x4
+ 0x4
+ 0x0
+ 0x0
+ 0x0
+ 0x1
+ 0x0
+ 0x0
+ 0x40
+ 0x44
+ 0x0
+ 0x0>;
+
+ qcom,iommu-lpae-bfb-regs = <0x204c
+ 0x2514
+ 0x2540
+ 0x256c
+ 0x20ac
+ 0x215c
+ 0x220c
+ 0x22bc
+ 0x2314
+ 0x2394
+ 0x2414
+ 0x2494
+ 0x2008>;
+
+ qcom,iommu-lpae-bfb-data = <0x3
+ 0x0
+ 0x4
+ 0x4
+ 0x0
+ 0x5
+ 0x0
+ 0x1
+ 0x0
+ 0x0
+ 0x40
+ 0x44
+ 0x0>;
+
+
+ copss_cb_0: qcom,iommu-ctx@f9bcc000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
+ reg = <0xf9bcc000 0x1000>;
+ interrupts = <0 142 0>;
+ qcom,iommu-ctx-sids = <0>;
+ label = "copss_cb_0";
+ };
+
+ copss_cb_1: qcom,iommu-ctx@f9bcd000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
+ reg = <0xf9bcd000 0x1000>;
+ interrupts = <0 142 0>;
+ qcom,iommu-ctx-sids = <1>;
+ label = "copss_cb_1";
+ };
+
+ copss_cb_2: qcom,iommu-ctx@f9bce000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
+ reg = <0xf9bce000 0x1000>;
+ interrupts = <0 142 0>;
+ qcom,iommu-ctx-sids = <2>;
+ label = "copss_cb_2";
+ };
+
+ copss_cb_3: qcom,iommu-ctx@f9bcf000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
+ reg = <0xf9bcf000 0x1000>;
+ interrupts = <0 142 0>;
+ qcom,iommu-ctx-sids = <3>;
+ label = "copss_cb_3";
+ };
+
+ copss_cb_4: qcom,iommu-ctx@f9bd0000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
+ reg = <0xf9bd0000 0x1000>;
+ interrupts = <0 142 0>;
+ qcom,iommu-ctx-sids = <4>;
+ label = "copss_cb_4";
+ };
+
+ copss_cb_5: qcom,iommu-ctx@f9bd1000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
+ reg = <0xf9bd1000 0x1000>;
+ interrupts = <0 142 0>;
+ qcom,iommu-ctx-sids = <5>;
+ label = "copss_cb_5";
+ };
+
+ copss_cb_6: qcom,iommu-ctx@f9bd2000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
+ reg = <0xf9bd2000 0x1000>;
+ interrupts = <0 142 0>;
+ qcom,iommu-ctx-sids = <6>;
+ label = "copss_cb_6";
+ };
+
+ copss_cb_7: qcom,iommu-ctx@f9bd3000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
+ reg = <0xf9bd3000 0x1000>;
+ interrupts = <0 142 0>;
+ qcom,iommu-ctx-sids = <7>;
+ label = "copss_cb_7";
+ };
+ };
+
+ vpu_iommu: qcom,iommu@fdee4000 {
+ compatible = "qcom,msm-smmu-v1";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ reg = <0xfdee4000 0x10000>;
+ reg-names = "iommu_base";
+ interrupts = <0 147 0>;
+ label = "vpu_iommu";
+ qcom,msm-bus,name = "vpu_ebi";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,active-only;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <93 512 0 0>,
+ <93 512 0 1000>;
+ status = "disabled";
+ qcom,iommu-pmu-ngroups = <1>;
+ qcom,iommu-pmu-ncounters = <8>;
+ qcom,iommu-pmu-event-classes = <0x00
+ 0x01
+ 0x08
+ 0x09
+ 0x0a
+ 0x10
+ 0x11
+ 0x12
+ 0x80
+ 0x81
+ 0x82
+ 0x83
+ 0x90
+ 0x91
+ 0x92
+ 0xb0
+ 0xb1>;
+
+ qcom,iommu-bfb-regs = <0x204c
+ 0x2514
+ 0x2540
+ 0x256c
+ 0x2314
+ 0x2394
+ 0x2414
+ 0x2494
+ 0x20ac
+ 0x215c
+ 0x220c
+ 0x22bc
+ 0x2008
+ 0x200c
+ 0x2010
+ 0x2014>;
+
+ qcom,iommu-bfb-data = <0xffff
+ 0x4
+ 0x10
+ 0x0
+ 0x0
+ 0xf
+ 0x4b
+ 0x0
+ 0x1e00
+ 0x1e00
+ 0x5a0f
+ 0x0
+ 0x0
+ 0x0
+ 0x0
+ 0x0>;
+
+ qcom,iommu-lpae-bfb-regs = <0x204c
+ 0x2514
+ 0x2540
+ 0x256c
+ 0x2314
+ 0x2394
+ 0x2414
+ 0x2494
+ 0x20ac
+ 0x215c
+ 0x220c
+ 0x22bc
+ 0x2008
+ 0x200c
+ 0x2010
+ 0x2014>;
+
+ qcom,iommu-lpae-bfb-data = <0xffff
+ 0x0
+ 0x4
+ 0x10
+ 0x0
+ 0x0
+ 0xf
+ 0x4b
+ 0x1e00
+ 0x5a2d
+ 0x1e00
+ 0x5a0f
+ 0x0
+ 0x0
+ 0x0
+ 0x0>;
+
+
+ vpu_cb_0: qcom,iommu-ctx@fdeec000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
+ reg = <0xfdeec000 0x1000>;
+ interrupts = <0 145 0>;
+ qcom,iommu-ctx-sids = <0 1 3>;
+ label = "vpu_cb_0";
+ };
+
+ vpu_cb_1: qcom,iommu-ctx@fdeed000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
+ reg = <0xfdeed000 0x1000>;
+ interrupts = <0 145 0>;
+ qcom,iommu-ctx-sids = <8 9>;
+ label = "vpu_cb_1";
+ };
+
+ vpu_cb_2: qcom,iommu-ctx@fdeee000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
+ reg = <0xfdeee000 0x1000>;
+ interrupts = <0 145 0>;
+ qcom,iommu-ctx-sids = <5 7 15>;
+ label = "vpu_cb_2";
+ };
+ };
+
+ lpass_qdsp_iommu: qcom,iommu@fe054000 {
+ compatible = "qcom,msm-smmu-v1";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ reg = <0xfe054000 0x10000>;
+ reg-names = "iommu_base";
+ interrupts = <0 202 0>;
+ label = "lpass_qdsp_iommu";
+ qcom,msm-bus,name = "lpass_qdsp_ebi";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,active-only;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <11 512 0 0>,
+ <11 512 0 1000>;
+ status = "disabled";
+ qcom,iommu-pmu-ngroups = <1>;
+ qcom,iommu-pmu-ncounters = <8>;
+ qcom,iommu-pmu-event-classes = <0x00
+ 0x01
+ 0x08
+ 0x09
+ 0x0a
+ 0x10
+ 0x11
+ 0x12
+ 0x80
+ 0x81
+ 0x82
+ 0x83
+ 0x90
+ 0x91
+ 0x92
+ 0xb0
+ 0xb1>;
+
+ qcom,iommu-bfb-regs = <0x204c
+ 0x2514
+ 0x2540
+ 0x256c
+ 0x20ac
+ 0x215c
+ 0x220c
+ 0x22bc
+ 0x2314
+ 0x2394
+ 0x2414
+ 0x2494
+ 0x2008>;
+
+ qcom,iommu-bfb-data = <0x3
+ 0x4
+ 0x4
+ 0x0
+ 0x0
+ 0x0
+ 0x10
+ 0x0
+ 0x0
+ 0x15e
+ 0x19e
+ 0x0
+ 0x0>;
+
+ qcom,iommu-lpae-bfb-regs = <0x204c
+ 0x2514
+ 0x2540
+ 0x256c
+ 0x20ac
+ 0x215c
+ 0x220c
+ 0x22bc
+ 0x2314
+ 0x2394
+ 0x2414
+ 0x2494
+ 0x2008>;
+
+ qcom,iommu-lpae-bfb-data = <0x3
+ 0x0
+ 0x4
+ 0x4
+ 0x0
+ 0x20
+ 0x0
+ 0x10
+ 0x0
+ 0x0
+ 0x15e
+ 0x19e
+ 0x0>;
+
+
+ lpass_qdsp_cb_0: qcom,iommu-ctx@fe05c000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
+ reg = <0xfe05c000 0x1000>;
+ interrupts = <0 265 0>;
+ qcom,iommu-ctx-sids = <0>;
+ label = "lpass_qdsp_cb_0";
+ };
+
+ lpass_qdsp_cb_1: qcom,iommu-ctx@fe05d000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
+ reg = <0xfe05d000 0x1000>;
+ interrupts = <0 265 0>;
+ qcom,iommu-ctx-sids = <1>;
+ label = "lpass_qdsp_cb_1";
+ };
+
+ lpass_qdsp_cb_2: qcom,iommu-ctx@fe05e000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
+ reg = <0xfe05e000 0x1000>;
+ interrupts = <0 265 0>;
+ qcom,iommu-ctx-sids = <2>;
+ label = "lpass_qdsp_cb_2";
+ };
+
+ lpass_qdsp_cb_3: qcom,iommu-ctx@fe05f000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
+ reg = <0xfe05f000 0x1000>;
+ interrupts = <0 265 0>;
+ qcom,iommu-ctx-sids = <3>;
+ label = "lpass_qdsp_cb_3";
+ };
+ };
+
+ lpass_core_iommu: qcom,iommu@fe064000 {
+ compatible = "qcom,msm-smmu-v1";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ reg = <0xfe064000 0x10000>;
+ reg-names = "iommu_base";
+ interrupts = <0 166 0>;
+ label = "lpass_core_iommu";
+ qcom,msm-bus,name = "lpass_core_ebi";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,active-only;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <52 512 0 0>,
+ <52 512 0 1000>;
+ status = "disabled";
+ qcom,iommu-pmu-ngroups = <1>;
+ qcom,iommu-pmu-ncounters = <8>;
+ qcom,iommu-pmu-event-classes = <0x00
+ 0x01
+ 0x08
+ 0x09
+ 0x0a
+ 0x10
+ 0x11
+ 0x12
+ 0x80
+ 0x81
+ 0x82
+ 0x83
+ 0x90
+ 0x91
+ 0x92
+ 0xb0
+ 0xb1>;
+
+ qcom,iommu-bfb-regs = <0x204c
+ 0x2514
+ 0x2540
+ 0x256c
+ 0x20ac
+ 0x215c
+ 0x220c
+ 0x22bc
+ 0x2314
+ 0x2394
+ 0x2414
+ 0x2494
+ 0x2008>;
+
+ qcom,iommu-bfb-data = <0x3
+ 0x4
+ 0x4
+ 0x0
+ 0x0
+ 0x0
+ 0x4
+ 0x0
+ 0x0
+ 0x40
+ 0x50
+ 0x0
+ 0x0>;
+
+ qcom,iommu-lpae-bfb-regs = <0x204c
+ 0x2514
+ 0x2540
+ 0x256c
+ 0x20ac
+ 0x215c
+ 0x220c
+ 0x22bc
+ 0x2314
+ 0x2394
+ 0x2414
+ 0x2494
+ 0x2008>;
+
+ qcom,iommu-lpae-bfb-data = <0x3
+ 0x0
+ 0x4
+ 0x4
+ 0x0
+ 0xc
+ 0x0
+ 0x4
+ 0x0
+ 0x0
+ 0x40
+ 0x50
+ 0x0>;
+
+
+ lpass_core_cb_0: qcom,iommu-ctx@fe06c000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
+ reg = <0xfe06c000 0x1000>;
+ interrupts = <0 267 0>;
+ qcom,iommu-ctx-sids = <0>;
+ label = "lpass_core_cb_0";
+ };
+
+ lpass_core_cb_1: qcom,iommu-ctx@fe06d000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
+ reg = <0xfe06d000 0x1000>;
+ interrupts = <0 267 0>;
+ qcom,iommu-ctx-sids = <1>;
+ label = "lpass_core_cb_1";
+ };
+
+ lpass_core_cb_2: qcom,iommu-ctx@fe06e000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
+ reg = <0xfe06e000 0x1000>;
+ interrupts = <0 267 0>;
+ qcom,iommu-ctx-sids = <2>;
+ label = "lpass_core_cb_2";
+ };
+ };
};
diff --git a/arch/arm/boot/dts/msm-pm8110-rpm-regulator.dtsi b/arch/arm/boot/dts/msm-pm8110-rpm-regulator.dtsi
index 0de72b0..f940495 100644
--- a/arch/arm/boot/dts/msm-pm8110-rpm-regulator.dtsi
+++ b/arch/arm/boot/dts/msm-pm8110-rpm-regulator.dtsi
@@ -182,7 +182,7 @@
regulator-l8 {
compatible = "qcom,rpm-regulator-smd";
regulator-name = "8110_l8";
- qcom,set = <1>;
+ qcom,set = <3>;
status = "disabled";
};
};
diff --git a/arch/arm/boot/dts/msm-pm8110.dtsi b/arch/arm/boot/dts/msm-pm8110.dtsi
index 0e446e2..4f3e461 100644
--- a/arch/arm/boot/dts/msm-pm8110.dtsi
+++ b/arch/arm/boot/dts/msm-pm8110.dtsi
@@ -62,10 +62,11 @@
qcom,vinmin-mv = <4200>;
qcom,vbatdet-mv = <4100>;
qcom,ibatmax-ma = <1500>;
- qcom,ibatterm-ma = <200>;
+ qcom,ibatterm-ma = <100>;
qcom,ibatsafe-ma = <1500>;
qcom,thermal-mitigation = <1500 700 600 325>;
qcom,vbatdet-delta-mv = <350>;
+ qcom,resume-soc = <99>;
qcom,tchg-mins = <150>;
qcom,chgr@1000 {
@@ -609,5 +610,12 @@
label = "vibrator";
status = "disabled";
};
+
+ pwm@bc00 {
+ compatible = "qcom,qpnp-pwm";
+ reg = <0xbc00 0x100>;
+ reg-names = "qpnp-lpg-channel-base";
+ qcom,channel-id = <0>;
+ };
};
};
diff --git a/arch/arm/boot/dts/msm-pm8226-rpm-regulator.dtsi b/arch/arm/boot/dts/msm-pm8226-rpm-regulator.dtsi
index ded9494..23bb4ac 100644
--- a/arch/arm/boot/dts/msm-pm8226-rpm-regulator.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226-rpm-regulator.dtsi
@@ -198,7 +198,7 @@
regulator-l8 {
compatible = "qcom,rpm-regulator-smd";
regulator-name = "8226_l8";
- qcom,set = <1>;
+ qcom,set = <3>;
status = "disabled";
};
};
@@ -427,6 +427,22 @@
};
};
+ rpm-regulator-ldoa25 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <25>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l25 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8226_l25";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
rpm-regulator-ldoa26 {
compatible = "qcom,rpm-regulator-smd-resource";
qcom,resource-name = "ldoa";
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index 2008e1e..d7c2155 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -32,10 +32,13 @@
reg = <0x800 0x100>;
interrupts = <0x0 0x8 0x0>,
<0x0 0x8 0x1>,
- <0x0 0x8 0x4>;
- interrupt-names = "kpdpwr", "resin", "resin-bark";
+ <0x0 0x8 0x4>,
+ <0x0 0x8 0x5>;
+ interrupt-names = "kpdpwr", "resin",
+ "resin-bark", "kpdpwr-resin-bark";
qcom,pon-dbc-delay = <15625>;
qcom,system-reset;
+ qcom,s3-debounce = <32>;
qcom,pon_1 {
qcom,pon-type = <0>;
@@ -52,6 +55,15 @@
qcom,s2-type = <1>;
linux,code = <114>;
};
+
+ qcom,pon_3 {
+ qcom,pon-type = <3>;
+ qcom,support-reset = <1>;
+ qcom,pull-up = <1>;
+ qcom,s1-timer = <6720>;
+ qcom,s2-timer = <2000>;
+ qcom,s2-type = <7>;
+ };
};
pm8226_chg: qcom,charger {
@@ -69,6 +81,7 @@
qcom,ibatterm-ma = <100>;
qcom,ibatsafe-ma = <1500>;
qcom,thermal-mitigation = <1500 700 600 325>;
+ qcom,resume-soc = <99>;
qcom,tchg-mins = <150>;
qcom,chgr@1000 {
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index b801da8..2460377 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -15,1383 +15,1419 @@
#size-cells = <0>;
interrupt-controller;
#interrupt-cells = <3>;
+};
- qcom,pm8941@0 {
- spmi-slave-container;
- reg = <0x0>;
- #address-cells = <1>;
- #size-cells = <1>;
+&pm8941_lsid0 {
+ spmi-slave-container;
+ #address-cells = <1>;
+ #size-cells = <1>;
- pm8941_misc: qcom,misc@900 {
- compatible = "qcom,qpnp-misc";
- reg = <0x900 0x100>;
+ pm8941_misc: qcom,misc@900 {
+ compatible = "qcom,qpnp-misc";
+ reg = <0x900 0x100>;
+ };
+
+ qcom,revid@100 {
+ compatible = "qcom,qpnp-revid";
+ reg = <0x100 0x100>;
+ };
+
+ qcom,temp-alarm@2400 {
+ compatible = "qcom,qpnp-temp-alarm";
+ reg = <0x2400 0x100>;
+ interrupts = <0x0 0x24 0x0>;
+ label = "pm8941_tz";
+ qcom,channel-num = <8>;
+ qcom,threshold-set = <0>;
+ };
+
+ qcom,power-on@800 {
+ compatible = "qcom,qpnp-power-on";
+ reg = <0x800 0x100>;
+ interrupts = <0x0 0x8 0x0>,
+ <0x0 0x8 0x1>,
+ <0x0 0x8 0x4>,
+ <0x0 0x8 0x5>;
+ interrupt-names = "kpdpwr", "resin",
+ "resin-bark", "kpdpwr-resin-bark";
+ qcom,pon-dbc-delay = <15625>;
+ qcom,system-reset;
+ qcom,s3-debounce = <32>;
+
+ qcom,pon_1 {
+ qcom,pon-type = <0>;
+ qcom,pull-up = <1>;
+ linux,code = <116>;
};
- qcom,revid@100 {
- compatible = "qcom,qpnp-revid";
- reg = <0x100 0x100>;
+ qcom,pon_2 {
+ qcom,pon-type = <1>;
+ qcom,support-reset = <1>;
+ qcom,pull-up = <1>;
+ qcom,s1-timer = <0>;
+ qcom,s2-timer = <2000>;
+ qcom,s2-type = <1>;
+ linux,code = <114>;
};
- qcom,temp-alarm@2400 {
- compatible = "qcom,qpnp-temp-alarm";
- reg = <0x2400 0x100>;
- interrupts = <0x0 0x24 0x0>;
- label = "pm8941_tz";
- qcom,channel-num = <8>;
- qcom,threshold-set = <0>;
- };
-
- qcom,power-on@800 {
- compatible = "qcom,qpnp-power-on";
- reg = <0x800 0x100>;
- interrupts = <0x0 0x8 0x0>,
- <0x0 0x8 0x1>,
- <0x0 0x8 0x4>,
- <0x0 0x8 0x5>;
- interrupt-names = "kpdpwr", "resin",
- "resin-bark", "kpdpwr-resin-bark";
- qcom,pon-dbc-delay = <15625>;
- qcom,system-reset;
- qcom,s3-debounce = <32>;
-
- qcom,pon_1 {
- qcom,pon-type = <0>;
- qcom,pull-up = <1>;
- linux,code = <116>;
- };
-
- qcom,pon_2 {
- qcom,pon-type = <1>;
- qcom,support-reset = <1>;
- qcom,pull-up = <1>;
- qcom,s1-timer = <0>;
- qcom,s2-timer = <2000>;
- qcom,s2-type = <1>;
- linux,code = <114>;
- };
-
- qcom,pon_3 {
- qcom,pon-type = <3>;
- qcom,support-reset = <1>;
- qcom,s1-timer = <6720>;
- qcom,s2-timer = <2000>;
- qcom,s2-type = <7>;
- qcom,pull-up = <1>;
- };
- };
-
- bif_ctrl: qcom,bsi@1b00 {
- compatible = "qcom,qpnp-bsi";
- reg = <0x1b00 0x100>,
- <0x1208 0x1>;
- reg-names = "bsi-base", "batt-id-status";
- label = "pm8941-bsi";
- interrupts = <0x0 0x1b 0x0>,
- <0x0 0x1b 0x1>,
- <0x0 0x1b 0x2>,
- <0x0 0x12 0x0>;
- interrupt-names = "err",
- "rx",
- "tx",
- "batt-present";
- qcom,channel-num = <0x31>;
- qcom,pullup-ohms = <100000>;
- qcom,vref-microvolts = <1800000>;
- qcom,min-clock-period = <1000>;
- qcom,max-clock-period = <160000>;
- qcom,sample-rate = <4>;
- };
-
- pm8941_coincell: qcom,coincell@2800 {
- compatible = "qcom,qpnp-coincell";
- reg = <0x2800 0x100>;
- };
-
- pm8941_bms: qcom,bms {
- spmi-dev-container;
- compatible = "qcom,qpnp-bms";
- #address-cells = <1>;
- #size-cells = <1>;
- status = "disabled";
-
- qcom,r-sense-uohm = <10000>;
- qcom,v-cutoff-uv = <3400000>;
- qcom,max-voltage-uv = <4200000>;
- qcom,r-conn-mohm = <0>;
- qcom,shutdown-soc-valid-limit = <20>;
- qcom,adjust-soc-low-threshold = <15>;
- qcom,ocv-voltage-high-threshold-uv = <3750000>;
- qcom,ocv-voltage-low-threshold-uv = <3650000>;
- qcom,low-soc-calculate-soc-threshold = <15>;
- qcom,low-soc-calculate-soc-ms = <5000>;
- qcom,calculate-soc-ms = <20000>;
- qcom,chg-term-ua = <100000>;
- qcom,batt-type = <0>;
- 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,hold-soc-est = <3>;
-
- qcom,bms-iadc@3800 {
- reg = <0x3800 0x100>;
- };
-
- qcom,bms-bms@4000 {
- reg = <0x4000 0x100>;
- interrupts = <0x0 0x40 0x0>,
- <0x0 0x40 0x1>,
- <0x0 0x40 0x2>,
- <0x0 0x40 0x3>,
- <0x0 0x40 0x4>,
- <0x0 0x40 0x5>,
- <0x0 0x40 0x6>,
- <0x0 0x40 0x7>;
-
- interrupt-names = "cc_thr",
- "ocv_for_r",
- "good_ocv",
- "charge_begin",
- "ocv_thr",
- "sw_cc_thr",
- "vsense_avg",
- "vsense_for_r";
-
- };
- };
-
- clkdiv@5b00 {
- reg = <0x5b00 0x100>;
- compatible = "qcom,qpnp-clkdiv";
- qcom,cxo-freq = <19200000>;
- };
-
- clkdiv@5c00 {
- reg = <0x5c00 0x100>;
- compatible = "qcom,qpnp-clkdiv";
- qcom,cxo-freq = <19200000>;
- };
-
- clkdiv@5d00 {
- reg = <0x5d00 0x1000>;
- compatible = "qcom,qpnp-clkdiv";
- qcom,cxo-freq = <19200000>;
- };
-
- pm8941_chg: qcom,charger {
- spmi-dev-container;
- compatible = "qcom,qpnp-charger";
- #address-cells = <1>;
- #size-cells = <1>;
- status = "disabled";
-
- qcom,vddmax-mv = <4200>;
- qcom,vddsafe-mv = <4230>;
- qcom,vinmin-mv = <4300>;
- qcom,ibatmax-ma = <1500>;
- qcom,ibatterm-ma = <100>;
- qcom,ibatsafe-ma = <1500>;
- qcom,thermal-mitigation = <1500 700 600 325>;
- qcom,cool-bat-decidegc = <100>;
- qcom,cool-bat-mv = <4100>;
- qcom,ibatmax-warm-ma = <350>;
- qcom,warm-bat-decidegc = <450>;
- qcom,warm-bat-mv = <4100>;
- qcom,ibatmax-cool-ma = <350>;
- qcom,vbatdet-delta-mv = <100>;
- qcom,tchg-mins = <150>;
-
- qcom,chgr@1000 {
- status = "disabled";
- reg = <0x1000 0x100>;
- interrupts = <0x0 0x10 0x0>,
- <0x0 0x10 0x1>,
- <0x0 0x10 0x2>,
- <0x0 0x10 0x3>,
- <0x0 0x10 0x4>,
- <0x0 0x10 0x5>,
- <0x0 0x10 0x6>,
- <0x0 0x10 0x7>;
-
- interrupt-names = "vbat-det-lo",
- "vbat-det-hi",
- "chgwdog",
- "state-change",
- "trkl-chg-on",
- "fast-chg-on",
- "chg-failed",
- "chg-done";
- };
-
- qcom,buck@1100 {
- status = "disabled";
- reg = <0x1100 0x100>;
- interrupts = <0x0 0x11 0x0>,
- <0x0 0x11 0x1>,
- <0x0 0x11 0x2>,
- <0x0 0x11 0x3>,
- <0x0 0x11 0x4>,
- <0x0 0x11 0x5>,
- <0x0 0x11 0x6>;
-
- interrupt-names = "vbat-ov",
- "vreg-ov",
- "overtemp",
- "vchg-loop",
- "ichg-loop",
- "ibat-loop",
- "vdd-loop";
- };
-
- qcom,bat-if@1200 {
- status = "disabled";
- reg = <0x1200 0x100>;
- interrupts = <0x0 0x12 0x0>,
- <0x0 0x12 0x1>,
- <0x0 0x12 0x2>,
- <0x0 0x12 0x3>,
- <0x0 0x12 0x4>;
-
- interrupt-names = "batt-pres",
- "bat-temp-ok",
- "bat-fet-on",
- "vcp-on",
- "psi";
-
- };
-
- pm8941_chg_otg: qcom,usb-chgpth@1300 {
- status = "disabled";
- reg = <0x1300 0x100>;
- interrupts = <0 0x13 0x0>,
- <0 0x13 0x1>,
- <0x0 0x13 0x2>;
-
- interrupt-names = "coarse-det-usb",
- "usbin-valid",
- "chg-gone";
- };
-
- qcom,dc-chgpth@1400 {
- status = "disabled";
- reg = <0x1400 0x100>;
- interrupts = <0x0 0x14 0x0>,
- <0x0 0x14 0x1>;
-
- interrupt-names = "coarse-det-dc",
- "dcin-valid";
- };
-
- pm8941_chg_boost: qcom,boost@1500 {
- status = "disabled";
- reg = <0x1500 0x100>;
- interrupts = <0x0 0x15 0x0>,
- <0x0 0x15 0x1>;
-
- interrupt-names = "boost-pwr-ok",
- "limit-error";
- };
-
- qcom,chg-misc@1600 {
- status = "disabled";
- reg = <0x1600 0x100>;
- };
- };
-
- pm8941_gpios: gpios {
- spmi-dev-container;
- compatible = "qcom,qpnp-pin";
- gpio-controller;
- #gpio-cells = <2>;
- #address-cells = <1>;
- #size-cells = <1>;
- label = "pm8941-gpio";
-
- gpio@c000 {
- reg = <0xc000 0x100>;
- qcom,pin-num = <1>;
- };
-
- gpio@c100 {
- reg = <0xc100 0x100>;
- qcom,pin-num = <2>;
- };
-
- gpio@c200 {
- reg = <0xc200 0x100>;
- qcom,pin-num = <3>;
- };
-
- gpio@c300 {
- reg = <0xc300 0x100>;
- qcom,pin-num = <4>;
- };
-
- gpio@c400 {
- reg = <0xc400 0x100>;
- qcom,pin-num = <5>;
- };
-
- gpio@c500 {
- reg = <0xc500 0x100>;
- qcom,pin-num = <6>;
- };
-
- gpio@c600 {
- reg = <0xc600 0x100>;
- qcom,pin-num = <7>;
- };
-
- gpio@c700 {
- reg = <0xc700 0x100>;
- qcom,pin-num = <8>;
- };
-
- gpio@c800 {
- reg = <0xc800 0x100>;
- qcom,pin-num = <9>;
- };
-
- gpio@c900 {
- reg = <0xc900 0x100>;
- qcom,pin-num = <10>;
- };
-
- gpio@ca00 {
- reg = <0xca00 0x100>;
- qcom,pin-num = <11>;
- };
-
- gpio@cb00 {
- reg = <0xcb00 0x100>;
- qcom,pin-num = <12>;
- };
-
- gpio@cc00 {
- reg = <0xcc00 0x100>;
- qcom,pin-num = <13>;
- };
-
- gpio@cd00 {
- reg = <0xcd00 0x100>;
- qcom,pin-num = <14>;
- };
-
- gpio@ce00 {
- reg = <0xce00 0x100>;
- qcom,pin-num = <15>;
- };
-
- gpio@cf00 {
- reg = <0xcf00 0x100>;
- qcom,pin-num = <16>;
- };
-
- gpio@d000 {
- reg = <0xd000 0x100>;
- qcom,pin-num = <17>;
- };
-
- gpio@d100 {
- reg = <0xd100 0x100>;
- qcom,pin-num = <18>;
- };
-
- gpio@d200 {
- reg = <0xd200 0x100>;
- qcom,pin-num = <19>;
- };
-
- gpio@d300 {
- reg = <0xd300 0x100>;
- qcom,pin-num = <20>;
- };
-
- gpio@d400 {
- reg = <0xd400 0x100>;
- qcom,pin-num = <21>;
- };
-
- gpio@d500 {
- reg = <0xd500 0x100>;
- qcom,pin-num = <22>;
- };
-
- gpio@d600 {
- reg = <0xd600 0x100>;
- qcom,pin-num = <23>;
- };
-
- gpio@d700 {
- reg = <0xd700 0x100>;
- qcom,pin-num = <24>;
- };
-
- gpio@d800 {
- reg = <0xd800 0x100>;
- qcom,pin-num = <25>;
- };
-
- gpio@d900 {
- reg = <0xd900 0x100>;
- qcom,pin-num = <26>;
- };
-
- gpio@da00 {
- reg = <0xda00 0x100>;
- qcom,pin-num = <27>;
- };
-
- gpio@db00 {
- reg = <0xdb00 0x100>;
- qcom,pin-num = <28>;
- };
-
- gpio@dc00 {
- reg = <0xdc00 0x100>;
- qcom,pin-num = <29>;
- };
-
- gpio@dd00 {
- reg = <0xdd00 0x100>;
- qcom,pin-num = <30>;
- };
-
- gpio@de00 {
- reg = <0xde00 0x100>;
- qcom,pin-num = <31>;
- };
-
- gpio@df00 {
- reg = <0xdf00 0x100>;
- qcom,pin-num = <32>;
- };
-
- gpio@e000 {
- reg = <0xe000 0x100>;
- qcom,pin-num = <33>;
- };
-
- gpio@e100 {
- reg = <0xe100 0x100>;
- qcom,pin-num = <34>;
- };
-
- gpio@e200 {
- reg = <0xe200 0x100>;
- qcom,pin-num = <35>;
- };
-
- gpio@e300 {
- reg = <0xe300 0x100>;
- qcom,pin-num = <36>;
- };
- };
-
- pm8941_mpps: mpps {
- spmi-dev-container;
- compatible = "qcom,qpnp-pin";
- gpio-controller;
- #gpio-cells = <2>;
- #address-cells = <1>;
- #size-cells = <1>;
- label = "pm8941-mpp";
-
- mpp@a000 {
- reg = <0xa000 0x100>;
- qcom,pin-num = <1>;
- };
-
- mpp@a100 {
- reg = <0xa100 0x100>;
- qcom,pin-num = <2>;
- };
-
- mpp@a200 {
- reg = <0xa200 0x100>;
- qcom,pin-num = <3>;
- };
-
- mpp@a300 {
- reg = <0xa300 0x100>;
- qcom,pin-num = <4>;
- };
-
- mpp@a400 {
- reg = <0xa400 0x100>;
- qcom,pin-num = <5>;
- };
-
- mpp@a500 {
- reg = <0xa500 0x100>;
- qcom,pin-num = <6>;
- };
-
- mpp@a600 {
- reg = <0xa600 0x100>;
- qcom,pin-num = <7>;
- };
-
- mpp@a700 {
- reg = <0xa700 0x100>;
- qcom,pin-num = <8>;
- };
- };
-
- qcom,pm8941_rtc {
- spmi-dev-container;
- compatible = "qcom,qpnp-rtc";
- #address-cells = <1>;
- #size-cells = <1>;
- qcom,qpnp-rtc-write = <0>;
- qcom,qpnp-rtc-alarm-pwrup = <0>;
-
- qcom,pm8941_rtc_rw@6000 {
- reg = <0x6000 0x100>;
- };
- qcom,pm8941_rtc_alarm@6100 {
- reg = <0x6100 0x100>;
- interrupts = <0x0 0x61 0x1>;
- };
- };
-
- vadc@3100 {
- compatible = "qcom,qpnp-vadc";
- reg = <0x3100 0x100>;
- #address-cells = <1>;
- #size-cells = <0>;
- interrupts = <0x0 0x31 0x0>;
- interrupt-names = "eoc-int-en-set";
- qcom,adc-bit-resolution = <15>;
- qcom,adc-vdd-reference = <1800>;
-
- chan@0 {
- label = "usb_in";
- reg = <0>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <4>;
- qcom,calibration-type = "absolute";
- qcom,scale-function = <0>;
- qcom,hw-settle-time = <0>;
- qcom,fast-avg-setup = <0>;
- };
-
- chan@1 {
- label = "dc_in";
- reg = <1>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <4>;
- qcom,calibration-type = "absolute";
- qcom,scale-function = <0>;
- qcom,hw-settle-time = <0>;
- qcom,fast-avg-setup = <0>;
- };
-
- chan@2 {
- label = "vchg_sns";
- reg = <2>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <3>;
- qcom,calibration-type = "absolute";
- qcom,scale-function = <0>;
- qcom,hw-settle-time = <0>;
- qcom,fast-avg-setup = <0>;
- };
-
- chan@3 {
- label = "spare1_div3";
- reg = <3>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <1>;
- qcom,calibration-type = "absolute";
- qcom,scale-function = <0>;
- qcom,hw-settle-time = <0>;
- qcom,fast-avg-setup = <0>;
- };
-
- chan@4 {
- label = "usb_id_mv";
- reg = <4>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <1>;
- qcom,calibration-type = "absolute";
- qcom,scale-function = <0>;
- qcom,hw-settle-time = <0>;
- qcom,fast-avg-setup = <0>;
- };
-
- chan@5 {
- label = "vcoin";
- reg = <5>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <1>;
- qcom,calibration-type = "absolute";
- qcom,scale-function = <0>;
- qcom,hw-settle-time = <0>;
- qcom,fast-avg-setup = <0>;
- };
-
- chan@6 {
- label = "vbat_sns";
- reg = <6>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <1>;
- qcom,calibration-type = "absolute";
- qcom,scale-function = <0>;
- qcom,hw-settle-time = <0>;
- qcom,fast-avg-setup = <0>;
- };
-
- chan@7 {
- label = "vph_pwr";
- reg = <7>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <1>;
- qcom,calibration-type = "absolute";
- qcom,scale-function = <0>;
- qcom,hw-settle-time = <0>;
- qcom,fast-avg-setup = <0>;
- };
-
- chan@8 {
- label = "die_temp";
- reg = <8>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "absolute";
- qcom,scale-function = <3>;
- qcom,hw-settle-time = <0>;
- qcom,fast-avg-setup = <0>;
- };
-
- chan@9 {
- label = "ref_625mv";
- reg = <9>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "absolute";
- qcom,scale-function = <0>;
- qcom,hw-settle-time = <0>;
- qcom,fast-avg-setup = <0>;
- };
-
- chan@a {
- label = "ref_1250v";
- reg = <0xa>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "absolute";
- qcom,scale-function = <0>;
- qcom,hw-settle-time = <0>;
- qcom,fast-avg-setup = <0>;
- };
-
- chan@30 {
- label = "batt_therm";
- reg = <0x30>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "ratiometric";
- qcom,scale-function = <1>;
- qcom,hw-settle-time = <2>;
- qcom,fast-avg-setup = <0>;
- };
-
- chan@31 {
- label = "batt_id";
- reg = <0x31>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "ratiometric";
- qcom,scale-function = <0>;
- qcom,hw-settle-time = <2>;
- qcom,fast-avg-setup = <0>;
- };
-
- chan@b2 {
- label = "xo_therm_pu2";
- reg = <0xb2>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "ratiometric";
- qcom,scale-function = <4>;
- qcom,hw-settle-time = <2>;
- qcom,fast-avg-setup = <0>;
- };
-
- chan@b3 {
- label = "msm_therm";
- reg = <0xb3>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "ratiometric";
- qcom,scale-function = <2>;
- qcom,hw-settle-time = <2>;
- qcom,fast-avg-setup = <0>;
- };
-
- chan@b4 {
- label = "emmc_therm";
- reg = <0xb4>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "ratiometric";
- qcom,scale-function = <2>;
- qcom,hw-settle-time = <2>;
- qcom,fast-avg-setup = <0>;
- };
-
- chan@b5 {
- label = "pa_therm0";
- reg = <0xb5>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "ratiometric";
- qcom,scale-function = <2>;
- qcom,hw-settle-time = <2>;
- qcom,fast-avg-setup = <0>;
- };
-
- chan@b7 {
- label = "pa_therm1";
- reg = <0xb7>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "ratiometric";
- qcom,scale-function = <2>;
- qcom,hw-settle-time = <2>;
- qcom,fast-avg-setup = <0>;
- };
-
- chan@b8 {
- label = "quiet_therm";
- reg = <0xb8>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "ratiometric";
- qcom,scale-function = <2>;
- qcom,hw-settle-time = <2>;
- qcom,fast-avg-setup = <0>;
- };
-
- chan@b9 {
- label = "usb_id";
- reg = <0xb9>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "ratiometric";
- qcom,scale-function = <0>;
- qcom,hw-settle-time = <2>;
- qcom,fast-avg-setup = <0>;
- };
-
- chan@39 {
- label = "usb_id_nopull";
- reg = <0x39>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "ratiometric";
- qcom,scale-function = <0>;
- qcom,hw-settle-time = <2>;
- qcom,fast-avg-setup = <0>;
- };
- };
-
- iadc@3600 {
- compatible = "qcom,qpnp-iadc";
- reg = <0x3600 0x100>;
- #address-cells = <1>;
- #size-cells = <0>;
- interrupts = <0x0 0x36 0x0>;
- interrupt-names = "eoc-int-en-set";
- qcom,adc-bit-resolution = <16>;
- qcom,adc-vdd-reference = <1800>;
-
- chan@0 {
- label = "internal_rsense";
- reg = <0>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <1>;
- qcom,calibration-type = "absolute";
- qcom,scale-function = <0>;
- qcom,hw-settle-time = <0>;
- qcom,fast-avg-setup = <0>;
- };
- };
-
- qcom,vadc@3400 {
- compatible = "qcom,qpnp-adc-tm";
- reg = <0x3400 0x100>;
- #address-cells = <1>;
- #size-cells = <0>;
- interrupts = <0x0 0x34 0x0>,
- <0x0 0x34 0x3>,
- <0x0 0x34 0x4>;
- interrupt-names = "eoc-int-en-set",
- "high-thr-en-set",
- "low-thr-en-set";
- qcom,adc-bit-resolution = <15>;
- qcom,adc-vdd-reference = <1800>;
-
- /* Channel Node */
- chan@b9 {
- label = "usb_id";
- reg = <0xb9>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "ratiometric";
- qcom,scale-function = <2>;
- qcom,hw-settle-time = <2>;
- qcom,fast-avg-setup = <3>;
- qcom,btm-channel-number = <0x48>;
- };
-
- chan@30 {
- label = "batt_therm";
- reg = <0x30>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "ratiometric";
- qcom,scale-function = <1>;
- qcom,hw-settle-time = <2>;
- qcom,fast-avg-setup = <3>;
- qcom,btm-channel-number = <0x68>;
- };
-
- chan@8 {
- label = "die_temp";
- reg = <8>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "absolute";
- qcom,scale-function = <3>;
- qcom,hw-settle-time = <0>;
- qcom,fast-avg-setup = <3>;
- qcom,btm-channel-number = <0x70>;
- };
-
- chan@6 {
- label = "vbat_sns";
- reg = <6>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <1>;
- qcom,calibration-type = "absolute";
- qcom,scale-function = <0>;
- qcom,hw-settle-time = <0>;
- qcom,fast-avg-setup = <3>;
- qcom,btm-channel-number = <0x78>;
- };
-
- chan@b5 {
- label = "pa_therm0";
- reg = <0xb5>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "ratiometric";
- qcom,scale-function = <2>;
- qcom,hw-settle-time = <2>;
- qcom,fast-avg-setup = <3>;
- qcom,btm-channel-number = <0x80>;
- qcom,thermal-node;
- };
-
- chan@b7 {
- label = "pa_therm1";
- reg = <0xb7>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "ratiometric";
- qcom,scale-function = <2>;
- qcom,hw-settle-time = <2>;
- qcom,fast-avg-setup = <3>;
- qcom,btm-channel-number = <0x88>;
- qcom,thermal-node;
- };
-
- chan@b4 {
- label = "emmc_therm";
- reg = <0xb4>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "ratiometric";
- qcom,scale-function = <2>;
- qcom,hw-settle-time = <2>;
- qcom,fast-avg-setup = <3>;
- qcom,btm-channel-number = <0x90>;
- qcom,thermal-node;
- };
-
- chan@b3 {
- label = "msm_therm";
- reg = <0xb3>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "ratiometric";
- qcom,scale-function = <2>;
- qcom,hw-settle-time = <2>;
- qcom,fast-avg-setup = <3>;
- qcom,btm-channel-number = <0x98>;
- qcom,thermal-node;
- };
+ qcom,pon_3 {
+ qcom,pon-type = <3>;
+ qcom,support-reset = <1>;
+ qcom,s1-timer = <6720>;
+ qcom,s2-timer = <2000>;
+ qcom,s2-type = <7>;
+ qcom,pull-up = <1>;
};
};
- qcom,pm8941@1 {
- spmi-slave-container;
- reg = <0x1>;
+ bif_ctrl: qcom,bsi@1b00 {
+ compatible = "qcom,qpnp-bsi";
+ reg = <0x1b00 0x100>,
+ <0x1208 0x1>;
+ reg-names = "bsi-base", "batt-id-status";
+ label = "pm8941-bsi";
+ interrupts = <0x0 0x1b 0x0>,
+ <0x0 0x1b 0x1>,
+ <0x0 0x1b 0x2>,
+ <0x0 0x12 0x0>;
+ interrupt-names = "err",
+ "rx",
+ "tx",
+ "batt-present";
+ qcom,channel-num = <0x31>;
+ qcom,pullup-ohms = <100000>;
+ qcom,vref-microvolts = <1800000>;
+ qcom,min-clock-period = <1000>;
+ qcom,max-clock-period = <160000>;
+ qcom,sample-rate = <4>;
+ };
+
+ pm8941_coincell: qcom,coincell@2800 {
+ compatible = "qcom,qpnp-coincell";
+ reg = <0x2800 0x100>;
+ };
+
+ pm8941_bms: qcom,bms {
+ spmi-dev-container;
+ compatible = "qcom,qpnp-bms";
#address-cells = <1>;
#size-cells = <1>;
+ status = "disabled";
- regulator@1400 {
- regulator-name = "8941_s1";
- spmi-dev-container;
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "qcom,qpnp-regulator";
- reg = <0x1400 0x300>;
- status = "disabled";
+ qcom,r-sense-uohm = <10000>;
+ qcom,v-cutoff-uv = <3400000>;
+ qcom,max-voltage-uv = <4200000>;
+ qcom,r-conn-mohm = <0>;
+ qcom,shutdown-soc-valid-limit = <20>;
+ qcom,adjust-soc-low-threshold = <15>;
+ qcom,ocv-voltage-high-threshold-uv = <3750000>;
+ qcom,ocv-voltage-low-threshold-uv = <3650000>;
+ qcom,low-soc-calculate-soc-threshold = <15>;
+ qcom,low-soc-calculate-soc-ms = <5000>;
+ qcom,calculate-soc-ms = <20000>;
+ qcom,chg-term-ua = <100000>;
+ qcom,batt-type = <0>;
+ 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,hold-soc-est = <3>;
- qcom,ctl@1400 {
- reg = <0x1400 0x100>;
- };
- qcom,ps@1500 {
- reg = <0x1500 0x100>;
- };
- qcom,freq@1600 {
- reg = <0x1600 0x100>;
- };
+ qcom,bms-iadc@3800 {
+ reg = <0x3800 0x100>;
};
- regulator@1700 {
- regulator-name = "8941_s2";
- spmi-dev-container;
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "qcom,qpnp-regulator";
- reg = <0x1700 0x300>;
- status = "disabled";
-
- qcom,ctl@1700 {
- reg = <0x1700 0x100>;
- };
- qcom,ps@1800 {
- reg = <0x1800 0x100>;
- };
- qcom,freq@1900 {
- reg = <0x1900 0x100>;
- };
- };
-
- regulator@1a00 {
- regulator-name = "8941_s3";
- spmi-dev-container;
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "qcom,qpnp-regulator";
- reg = <0x1a00 0x300>;
- status = "disabled";
-
- qcom,ctl@1a00 {
- reg = <0x1a00 0x100>;
- };
- qcom,ps@1b00 {
- reg = <0x1b00 0x100>;
- };
- qcom,freq@1c00 {
- reg = <0x1c00 0x100>;
- };
- };
-
- regulator@a000 {
- regulator-name = "8941_boost";
- reg = <0xa000 0x100>;
- compatible = "qcom,qpnp-regulator";
- status = "disabled";
- };
-
- regulator@4000 {
- regulator-name = "8941_l1";
+ qcom,bms-bms@4000 {
reg = <0x4000 0x100>;
- compatible = "qcom,qpnp-regulator";
+ interrupts = <0x0 0x40 0x0>,
+ <0x0 0x40 0x1>,
+ <0x0 0x40 0x2>,
+ <0x0 0x40 0x3>,
+ <0x0 0x40 0x4>,
+ <0x0 0x40 0x5>,
+ <0x0 0x40 0x6>,
+ <0x0 0x40 0x7>;
+
+ interrupt-names = "cc_thr",
+ "ocv_for_r",
+ "good_ocv",
+ "charge_begin",
+ "ocv_thr",
+ "sw_cc_thr",
+ "vsense_avg",
+ "vsense_for_r";
+ };
+ };
+
+ clkdiv@5b00 {
+ reg = <0x5b00 0x100>;
+ compatible = "qcom,qpnp-clkdiv";
+ qcom,cxo-freq = <19200000>;
+ };
+
+ clkdiv@5c00 {
+ reg = <0x5c00 0x100>;
+ compatible = "qcom,qpnp-clkdiv";
+ qcom,cxo-freq = <19200000>;
+ };
+
+ clkdiv@5d00 {
+ reg = <0x5d00 0x1000>;
+ compatible = "qcom,qpnp-clkdiv";
+ qcom,cxo-freq = <19200000>;
+ };
+
+ pm8941_chg: qcom,charger {
+ spmi-dev-container;
+ compatible = "qcom,qpnp-charger";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ status = "disabled";
+
+ qcom,vddmax-mv = <4200>;
+ qcom,vddsafe-mv = <4230>;
+ qcom,vinmin-mv = <4300>;
+ qcom,ibatmax-ma = <1500>;
+ qcom,ibatterm-ma = <100>;
+ qcom,ibatsafe-ma = <1500>;
+ qcom,thermal-mitigation = <1500 700 600 325>;
+ qcom,cool-bat-decidegc = <100>;
+ qcom,cool-bat-mv = <4100>;
+ qcom,ibatmax-warm-ma = <350>;
+ qcom,warm-bat-decidegc = <450>;
+ qcom,warm-bat-mv = <4100>;
+ qcom,ibatmax-cool-ma = <350>;
+ qcom,vbatdet-delta-mv = <100>;
+ qcom,resume-soc = <99>;
+ qcom,tchg-mins = <150>;
+
+ qcom,chgr@1000 {
status = "disabled";
+ reg = <0x1000 0x100>;
+ interrupts = <0x0 0x10 0x0>,
+ <0x0 0x10 0x1>,
+ <0x0 0x10 0x2>,
+ <0x0 0x10 0x3>,
+ <0x0 0x10 0x4>,
+ <0x0 0x10 0x5>,
+ <0x0 0x10 0x6>,
+ <0x0 0x10 0x7>;
+
+ interrupt-names = "vbat-det-lo",
+ "vbat-det-hi",
+ "chgwdog",
+ "state-change",
+ "trkl-chg-on",
+ "fast-chg-on",
+ "chg-failed",
+ "chg-done";
};
- regulator@4100 {
- regulator-name = "8941_l2";
- reg = <0x4100 0x100>;
- compatible = "qcom,qpnp-regulator";
+ qcom,buck@1100 {
status = "disabled";
+ reg = <0x1100 0x100>;
+ interrupts = <0x0 0x11 0x0>,
+ <0x0 0x11 0x1>,
+ <0x0 0x11 0x2>,
+ <0x0 0x11 0x3>,
+ <0x0 0x11 0x4>,
+ <0x0 0x11 0x5>,
+ <0x0 0x11 0x6>;
+
+ interrupt-names = "vbat-ov",
+ "vreg-ov",
+ "overtemp",
+ "vchg-loop",
+ "ichg-loop",
+ "ibat-loop",
+ "vdd-loop";
};
- regulator@4200 {
- regulator-name = "8941_l3";
- reg = <0x4200 0x100>;
- compatible = "qcom,qpnp-regulator";
+ qcom,bat-if@1200 {
status = "disabled";
+ reg = <0x1200 0x100>;
+ interrupts = <0x0 0x12 0x0>,
+ <0x0 0x12 0x1>,
+ <0x0 0x12 0x2>,
+ <0x0 0x12 0x3>,
+ <0x0 0x12 0x4>;
+
+ interrupt-names = "batt-pres",
+ "bat-temp-ok",
+ "bat-fet-on",
+ "vcp-on",
+ "psi";
+
};
- regulator@4300 {
- regulator-name = "8941_l4";
- reg = <0x4300 0x100>;
- compatible = "qcom,qpnp-regulator";
+ pm8941_chg_otg: qcom,usb-chgpth@1300 {
status = "disabled";
+ reg = <0x1300 0x100>;
+ interrupts = <0 0x13 0x0>,
+ <0 0x13 0x1>,
+ <0x0 0x13 0x2>;
+
+ interrupt-names = "coarse-det-usb",
+ "usbin-valid",
+ "chg-gone";
};
- regulator@4400 {
- regulator-name = "8941_l5";
- reg = <0x4400 0x100>;
- compatible = "qcom,qpnp-regulator";
- qcom,force-type = <0x04 0x10>;
+ qcom,dc-chgpth@1400 {
status = "disabled";
+ reg = <0x1400 0x100>;
+ interrupts = <0x0 0x14 0x0>,
+ <0x0 0x14 0x1>;
+
+ interrupt-names = "coarse-det-dc",
+ "dcin-valid";
};
- regulator@4500 {
- regulator-name = "8941_l6";
- reg = <0x4500 0x100>;
- compatible = "qcom,qpnp-regulator";
+ pm8941_chg_boost: qcom,boost@1500 {
status = "disabled";
+ reg = <0x1500 0x100>;
+ interrupts = <0x0 0x15 0x0>,
+ <0x0 0x15 0x1>;
+
+ interrupt-names = "boost-pwr-ok",
+ "limit-error";
};
- regulator@4600 {
- regulator-name = "8941_l7";
- reg = <0x4600 0x100>;
- compatible = "qcom,qpnp-regulator";
- qcom,force-type = <0x04 0x10>;
+ qcom,chg-misc@1600 {
status = "disabled";
+ reg = <0x1600 0x100>;
};
+ };
- regulator@4700 {
- regulator-name = "8941_l8";
- reg = <0x4700 0x100>;
- compatible = "qcom,qpnp-regulator";
- status = "disabled";
- };
+ pm8941_gpios: gpios {
+ spmi-dev-container;
+ compatible = "qcom,qpnp-pin";
+ gpio-controller;
+ #gpio-cells = <2>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ label = "pm8941-gpio";
- regulator@4800 {
- regulator-name = "8941_l9";
- reg = <0x4800 0x100>;
- compatible = "qcom,qpnp-regulator";
- status = "disabled";
- };
-
- regulator@4900 {
- regulator-name = "8941_l10";
- reg = <0x4900 0x100>;
- compatible = "qcom,qpnp-regulator";
- status = "disabled";
- };
-
- regulator@4a00 {
- regulator-name = "8941_l11";
- reg = <0x4a00 0x100>;
- compatible = "qcom,qpnp-regulator";
- status = "disabled";
- };
-
- regulator@4b00 {
- regulator-name = "8941_l12";
- reg = <0x4b00 0x100>;
- compatible = "qcom,qpnp-regulator";
- status = "disabled";
- };
-
- regulator@4c00 {
- regulator-name = "8941_l13";
- reg = <0x4c00 0x100>;
- compatible = "qcom,qpnp-regulator";
- status = "disabled";
- };
-
- regulator@4d00 {
- regulator-name = "8941_l14";
- reg = <0x4d00 0x100>;
- compatible = "qcom,qpnp-regulator";
- status = "disabled";
- };
-
- regulator@4e00 {
- regulator-name = "8941_l15";
- reg = <0x4e00 0x100>;
- compatible = "qcom,qpnp-regulator";
- status = "disabled";
- };
-
- regulator@4f00 {
- regulator-name = "8941_l16";
- reg = <0x4f00 0x100>;
- compatible = "qcom,qpnp-regulator";
- status = "disabled";
- };
-
- regulator@5000 {
- regulator-name = "8941_l17";
- reg = <0x5000 0x100>;
- compatible = "qcom,qpnp-regulator";
- status = "disabled";
- };
-
- regulator@5100 {
- regulator-name = "8941_l18";
- reg = <0x5100 0x100>;
- compatible = "qcom,qpnp-regulator";
- status = "disabled";
- };
-
- regulator@5200 {
- regulator-name = "8941_l19";
- reg = <0x5200 0x100>;
- compatible = "qcom,qpnp-regulator";
- status = "disabled";
- };
-
- regulator@5300 {
- regulator-name = "8941_l20";
- reg = <0x5300 0x100>;
- compatible = "qcom,qpnp-regulator";
- status = "disabled";
- };
-
- regulator@5400 {
- regulator-name = "8941_l21";
- reg = <0x5400 0x100>;
- compatible = "qcom,qpnp-regulator";
- status = "disabled";
- };
-
- regulator@5500 {
- regulator-name = "8941_l22";
- reg = <0x5500 0x100>;
- compatible = "qcom,qpnp-regulator";
- status = "disabled";
- };
-
- regulator@5600 {
- regulator-name = "8941_l23";
- reg = <0x5600 0x100>;
- compatible = "qcom,qpnp-regulator";
- status = "disabled";
- };
-
- regulator@5700 {
- regulator-name = "8941_l24";
- reg = <0x5700 0x100>;
- compatible = "qcom,qpnp-regulator";
- status = "disabled";
- };
-
- regulator@8000 {
- regulator-name = "8941_lvs1";
- reg = <0x8000 0x100>;
- compatible = "qcom,qpnp-regulator";
- status = "disabled";
- };
-
- regulator@8100 {
- regulator-name = "8941_lvs2";
- reg = <0x8100 0x100>;
- compatible = "qcom,qpnp-regulator";
- status = "disabled";
- };
-
- regulator@8200 {
- regulator-name = "8941_lvs3";
- reg = <0x8200 0x100>;
- compatible = "qcom,qpnp-regulator";
- status = "disabled";
- };
-
- regulator@8300 {
- regulator-name = "8941_mvs1";
- reg = <0x8300 0x100>;
- compatible = "qcom,qpnp-regulator";
- status = "disabled";
- };
-
- regulator@8400 {
- regulator-name = "8941_mvs2";
- reg = <0x8400 0x100>;
- compatible = "qcom,qpnp-regulator";
- status = "disabled";
- };
-
- qcom,vibrator@c000 {
- compatible = "qcom,qpnp-vibrator";
+ gpio@c000 {
reg = <0xc000 0x100>;
- label = "vibrator";
- status = "disabled";
+ qcom,pin-num = <1>;
};
- qcom,leds@d000 {
- compatible = "qcom,leds-qpnp";
+ gpio@c100 {
+ reg = <0xc100 0x100>;
+ qcom,pin-num = <2>;
+ };
+
+ gpio@c200 {
+ reg = <0xc200 0x100>;
+ qcom,pin-num = <3>;
+ };
+
+ gpio@c300 {
+ reg = <0xc300 0x100>;
+ qcom,pin-num = <4>;
+ };
+
+ gpio@c400 {
+ reg = <0xc400 0x100>;
+ qcom,pin-num = <5>;
+ };
+
+ gpio@c500 {
+ reg = <0xc500 0x100>;
+ qcom,pin-num = <6>;
+ };
+
+ gpio@c600 {
+ reg = <0xc600 0x100>;
+ qcom,pin-num = <7>;
+ };
+
+ gpio@c700 {
+ reg = <0xc700 0x100>;
+ qcom,pin-num = <8>;
+ };
+
+ gpio@c800 {
+ reg = <0xc800 0x100>;
+ qcom,pin-num = <9>;
+ };
+
+ gpio@c900 {
+ reg = <0xc900 0x100>;
+ qcom,pin-num = <10>;
+ };
+
+ gpio@ca00 {
+ reg = <0xca00 0x100>;
+ qcom,pin-num = <11>;
+ };
+
+ gpio@cb00 {
+ reg = <0xcb00 0x100>;
+ qcom,pin-num = <12>;
+ };
+
+ gpio@cc00 {
+ reg = <0xcc00 0x100>;
+ qcom,pin-num = <13>;
+ };
+
+ gpio@cd00 {
+ reg = <0xcd00 0x100>;
+ qcom,pin-num = <14>;
+ };
+
+ gpio@ce00 {
+ reg = <0xce00 0x100>;
+ qcom,pin-num = <15>;
+ };
+
+ gpio@cf00 {
+ reg = <0xcf00 0x100>;
+ qcom,pin-num = <16>;
+ };
+
+ gpio@d000 {
reg = <0xd000 0x100>;
- label = "rgb";
+ qcom,pin-num = <17>;
};
- qcom,leds@d100 {
- compatible = "qcom,leds-qpnp";
+ gpio@d100 {
reg = <0xd100 0x100>;
- label = "rgb";
+ qcom,pin-num = <18>;
};
- qcom,leds@d200 {
- compatible = "qcom,leds-qpnp";
+ gpio@d200 {
reg = <0xd200 0x100>;
- label = "rgb";
+ qcom,pin-num = <19>;
};
- qcom,leds@d300 {
- compatible = "qcom,leds-qpnp";
+ gpio@d300 {
reg = <0xd300 0x100>;
- label = "flash";
- flash_boost-supply = <&pm8941_chg_boost>;
+ qcom,pin-num = <20>;
};
- qcom,leds@d400 {
- compatible = "qcom,leds-qpnp";
+ gpio@d400 {
reg = <0xd400 0x100>;
- label = "flash";
+ qcom,pin-num = <21>;
};
- qcom,leds@d500 {
- compatible = "qcom,leds-qpnp";
+ gpio@d500 {
reg = <0xd500 0x100>;
- label = "flash";
+ qcom,pin-num = <22>;
};
- qcom,leds@d600 {
- compatible = "qcom,leds-qpnp";
+ gpio@d600 {
reg = <0xd600 0x100>;
- label = "flash";
+ qcom,pin-num = <23>;
};
- qcom,leds@d700 {
- compatible = "qcom,leds-qpnp";
+ gpio@d700 {
reg = <0xd700 0x100>;
- label = "flash";
+ qcom,pin-num = <24>;
};
- qcom,leds@d800 {
- compatible = "qcom,leds-qpnp";
+ gpio@d800 {
reg = <0xd800 0x100>;
- label = "wled";
+ qcom,pin-num = <25>;
};
- qcom,leds@d900 {
- compatible = "qcom,leds-qpnp";
+ gpio@d900 {
reg = <0xd900 0x100>;
- label = "wled";
+ qcom,pin-num = <26>;
};
- qcom,leds@da00 {
- compatible = "qcom,leds-qpnp";
+ gpio@da00 {
reg = <0xda00 0x100>;
- label = "wled";
+ qcom,pin-num = <27>;
};
- qcom,leds@db00 {
- compatible = "qcom,leds-qpnp";
+ gpio@db00 {
reg = <0xdb00 0x100>;
- label = "wled";
+ qcom,pin-num = <28>;
};
- qcom,leds@dc00 {
- compatible = "qcom,leds-qpnp";
+ gpio@dc00 {
reg = <0xdc00 0x100>;
- label = "wled";
+ qcom,pin-num = <29>;
};
- qcom,leds@dd00 {
- compatible = "qcom,leds-qpnp";
+ gpio@dd00 {
reg = <0xdd00 0x100>;
- label = "wled";
+ qcom,pin-num = <30>;
};
- qcom,leds@de00 {
- compatible = "qcom,leds-qpnp";
+ gpio@de00 {
reg = <0xde00 0x100>;
- label = "wled";
+ qcom,pin-num = <31>;
};
- qcom,leds@df00 {
- compatible = "qcom,leds-qpnp";
+ gpio@df00 {
reg = <0xdf00 0x100>;
- label = "wled";
+ qcom,pin-num = <32>;
};
- qcom,leds@e000 {
- compatible = "qcom,leds-qpnp";
+ gpio@e000 {
reg = <0xe000 0x100>;
- label = "wled";
+ qcom,pin-num = <33>;
};
- qcom,leds@e100 {
- compatible = "qcom,leds-qpnp";
+ gpio@e100 {
reg = <0xe100 0x100>;
- label = "wled";
+ qcom,pin-num = <34>;
};
- pwm@b100 {
- compatible = "qcom,qpnp-pwm";
- reg = <0xb100 0x100>,
- <0xb042 0x7e>;
- reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base";
- qcom,channel-id = <0>;
+ gpio@e200 {
+ reg = <0xe200 0x100>;
+ qcom,pin-num = <35>;
};
- pwm@b200 {
- compatible = "qcom,qpnp-pwm";
- reg = <0xb200 0x100>,
- <0xb042 0x7e>;
- reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base";
- qcom,channel-id = <1>;
+ gpio@e300 {
+ reg = <0xe300 0x100>;
+ qcom,pin-num = <36>;
+ };
+ };
+
+ pm8941_mpps: mpps {
+ spmi-dev-container;
+ compatible = "qcom,qpnp-pin";
+ gpio-controller;
+ #gpio-cells = <2>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ label = "pm8941-mpp";
+
+ mpp@a000 {
+ reg = <0xa000 0x100>;
+ qcom,pin-num = <1>;
};
- pwm@b300 {
- compatible = "qcom,qpnp-pwm";
- reg = <0xb300 0x100>,
- <0xb042 0x7e>;
- reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base";
- qcom,channel-id = <2>;
+ mpp@a100 {
+ reg = <0xa100 0x100>;
+ qcom,pin-num = <2>;
};
- pwm@b400 {
- compatible = "qcom,qpnp-pwm";
- reg = <0xb400 0x100>,
- <0xb042 0x7e>;
- reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base";
- qcom,channel-id = <3>;
+ mpp@a200 {
+ reg = <0xa200 0x100>;
+ qcom,pin-num = <3>;
};
- pwm@b500 {
- compatible = "qcom,qpnp-pwm";
- reg = <0xb500 0x100>,
- <0xb042 0x7e>;
- reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base";
- qcom,channel-id = <4>;
+ mpp@a300 {
+ reg = <0xa300 0x100>;
+ qcom,pin-num = <4>;
};
- pwm@b600 {
- compatible = "qcom,qpnp-pwm";
- reg = <0xb600 0x100>,
- <0xb042 0x7e>;
- reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base";
- qcom,channel-id = <5>;
+ mpp@a400 {
+ reg = <0xa400 0x100>;
+ qcom,pin-num = <5>;
};
- pwm@b700 {
- compatible = "qcom,qpnp-pwm";
- reg = <0xb700 0x100>,
- <0xb042 0x7e>;
- reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base";
- qcom,channel-id = <6>;
+ mpp@a500 {
+ reg = <0xa500 0x100>;
+ qcom,pin-num = <6>;
};
- pwm@b800 {
- compatible = "qcom,qpnp-pwm";
- reg = <0xb800 0x100>,
- <0xb042 0x7e>;
- reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base";
- qcom,channel-id = <7>;
+ mpp@a600 {
+ reg = <0xa600 0x100>;
+ qcom,pin-num = <7>;
};
+
+ mpp@a700 {
+ reg = <0xa700 0x100>;
+ qcom,pin-num = <8>;
+ };
+ };
+
+ qcom,pm8941_rtc {
+ spmi-dev-container;
+ compatible = "qcom,qpnp-rtc";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ qcom,qpnp-rtc-write = <0>;
+ qcom,qpnp-rtc-alarm-pwrup = <0>;
+
+ qcom,pm8941_rtc_rw@6000 {
+ reg = <0x6000 0x100>;
+ };
+ qcom,pm8941_rtc_alarm@6100 {
+ reg = <0x6100 0x100>;
+ interrupts = <0x0 0x61 0x1>;
+ };
+ };
+
+ pm8941_vadc: vadc@3100 {
+ compatible = "qcom,qpnp-vadc";
+ reg = <0x3100 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0x0 0x31 0x0>;
+ interrupt-names = "eoc-int-en-set";
+ qcom,adc-bit-resolution = <15>;
+ qcom,adc-vdd-reference = <1800>;
+
+ chan@0 {
+ label = "usb_in";
+ reg = <0>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <4>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@1 {
+ label = "dc_in";
+ reg = <1>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <4>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@2 {
+ label = "vchg_sns";
+ reg = <2>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <3>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@3 {
+ label = "spare1_div3";
+ reg = <3>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@4 {
+ label = "usb_id_mv";
+ reg = <4>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@5 {
+ label = "vcoin";
+ reg = <5>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@6 {
+ label = "vbat_sns";
+ reg = <6>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@7 {
+ label = "vph_pwr";
+ reg = <7>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@8 {
+ label = "die_temp";
+ reg = <8>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <3>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@9 {
+ label = "ref_625mv";
+ reg = <9>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@a {
+ label = "ref_1250v";
+ reg = <0xa>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@30 {
+ label = "batt_therm";
+ reg = <0x30>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <1>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@31 {
+ label = "batt_id";
+ reg = <0x31>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@b2 {
+ label = "xo_therm_pu2";
+ reg = <0xb2>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <4>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@b3 {
+ label = "msm_therm";
+ reg = <0xb3>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@b4 {
+ label = "emmc_therm";
+ reg = <0xb4>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@b5 {
+ label = "pa_therm0";
+ reg = <0xb5>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@b7 {
+ label = "pa_therm1";
+ reg = <0xb7>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@b8 {
+ label = "quiet_therm";
+ reg = <0xb8>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@b9 {
+ label = "usb_id";
+ reg = <0xb9>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@39 {
+ label = "usb_id_nopull";
+ reg = <0x39>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+ };
+
+ pm8941_iadc: iadc@3600 {
+ compatible = "qcom,qpnp-iadc";
+ reg = <0x3600 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0x0 0x36 0x0>;
+ interrupt-names = "eoc-int-en-set";
+ qcom,adc-bit-resolution = <16>;
+ qcom,adc-vdd-reference = <1800>;
+
+ chan@0 {
+ label = "internal_rsense";
+ reg = <0>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+ };
+
+ pm8941_adc_tm: qcom,vadc@3400 {
+ compatible = "qcom,qpnp-adc-tm";
+ reg = <0x3400 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0x0 0x34 0x0>,
+ <0x0 0x34 0x3>,
+ <0x0 0x34 0x4>;
+ interrupt-names = "eoc-int-en-set",
+ "high-thr-en-set",
+ "low-thr-en-set";
+ qcom,adc-bit-resolution = <15>;
+ qcom,adc-vdd-reference = <1800>;
+
+ /* Channel Node */
+ chan@b9 {
+ label = "usb_id";
+ reg = <0xb9>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <3>;
+ qcom,btm-channel-number = <0x48>;
+ };
+
+ chan@30 {
+ label = "batt_therm";
+ reg = <0x30>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <1>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <3>;
+ qcom,btm-channel-number = <0x68>;
+ };
+
+ chan@8 {
+ label = "die_temp";
+ reg = <8>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <3>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <3>;
+ qcom,btm-channel-number = <0x70>;
+ };
+
+ chan@6 {
+ label = "vbat_sns";
+ reg = <6>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <3>;
+ qcom,btm-channel-number = <0x78>;
+ };
+
+ chan@b5 {
+ label = "pa_therm0";
+ reg = <0xb5>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <3>;
+ qcom,btm-channel-number = <0x80>;
+ qcom,thermal-node;
+ };
+
+ chan@b7 {
+ label = "pa_therm1";
+ reg = <0xb7>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <3>;
+ qcom,btm-channel-number = <0x88>;
+ qcom,thermal-node;
+ };
+
+ chan@b4 {
+ label = "emmc_therm";
+ reg = <0xb4>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <3>;
+ qcom,btm-channel-number = <0x90>;
+ qcom,thermal-node;
+ };
+
+ chan@b3 {
+ label = "msm_therm";
+ reg = <0xb3>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <3>;
+ qcom,btm-channel-number = <0x98>;
+ qcom,thermal-node;
+ };
+ };
+};
+
+&pm8941_lsid1 {
+ spmi-slave-container;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ regulator@1400 {
+ regulator-name = "8941_s1";
+ spmi-dev-container;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "qcom,qpnp-regulator";
+ reg = <0x1400 0x300>;
+ status = "disabled";
+
+ qcom,ctl@1400 {
+ reg = <0x1400 0x100>;
+ };
+ qcom,ps@1500 {
+ reg = <0x1500 0x100>;
+ };
+ qcom,freq@1600 {
+ reg = <0x1600 0x100>;
+ };
+ };
+
+ regulator@1700 {
+ regulator-name = "8941_s2";
+ spmi-dev-container;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "qcom,qpnp-regulator";
+ reg = <0x1700 0x300>;
+ status = "disabled";
+
+ qcom,ctl@1700 {
+ reg = <0x1700 0x100>;
+ };
+ qcom,ps@1800 {
+ reg = <0x1800 0x100>;
+ };
+ qcom,freq@1900 {
+ reg = <0x1900 0x100>;
+ };
+ };
+
+ regulator@1a00 {
+ regulator-name = "8941_s3";
+ spmi-dev-container;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "qcom,qpnp-regulator";
+ reg = <0x1a00 0x300>;
+ status = "disabled";
+
+ qcom,ctl@1a00 {
+ reg = <0x1a00 0x100>;
+ };
+ qcom,ps@1b00 {
+ reg = <0x1b00 0x100>;
+ };
+ qcom,freq@1c00 {
+ reg = <0x1c00 0x100>;
+ };
+ };
+
+ regulator@a000 {
+ regulator-name = "8941_boost";
+ reg = <0xa000 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@4000 {
+ regulator-name = "8941_l1";
+ reg = <0x4000 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@4100 {
+ regulator-name = "8941_l2";
+ reg = <0x4100 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@4200 {
+ regulator-name = "8941_l3";
+ reg = <0x4200 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@4300 {
+ regulator-name = "8941_l4";
+ reg = <0x4300 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@4400 {
+ regulator-name = "8941_l5";
+ reg = <0x4400 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ qcom,force-type = <0x04 0x10>;
+ status = "disabled";
+ };
+
+ regulator@4500 {
+ regulator-name = "8941_l6";
+ reg = <0x4500 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@4600 {
+ regulator-name = "8941_l7";
+ reg = <0x4600 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ qcom,force-type = <0x04 0x10>;
+ status = "disabled";
+ };
+
+ regulator@4700 {
+ regulator-name = "8941_l8";
+ reg = <0x4700 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@4800 {
+ regulator-name = "8941_l9";
+ reg = <0x4800 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@4900 {
+ regulator-name = "8941_l10";
+ reg = <0x4900 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@4a00 {
+ regulator-name = "8941_l11";
+ reg = <0x4a00 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@4b00 {
+ regulator-name = "8941_l12";
+ reg = <0x4b00 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@4c00 {
+ regulator-name = "8941_l13";
+ reg = <0x4c00 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@4d00 {
+ regulator-name = "8941_l14";
+ reg = <0x4d00 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@4e00 {
+ regulator-name = "8941_l15";
+ reg = <0x4e00 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@4f00 {
+ regulator-name = "8941_l16";
+ reg = <0x4f00 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@5000 {
+ regulator-name = "8941_l17";
+ reg = <0x5000 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@5100 {
+ regulator-name = "8941_l18";
+ reg = <0x5100 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@5200 {
+ regulator-name = "8941_l19";
+ reg = <0x5200 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@5300 {
+ regulator-name = "8941_l20";
+ reg = <0x5300 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@5400 {
+ regulator-name = "8941_l21";
+ reg = <0x5400 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@5500 {
+ regulator-name = "8941_l22";
+ reg = <0x5500 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@5600 {
+ regulator-name = "8941_l23";
+ reg = <0x5600 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@5700 {
+ regulator-name = "8941_l24";
+ reg = <0x5700 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@8000 {
+ regulator-name = "8941_lvs1";
+ reg = <0x8000 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@8100 {
+ regulator-name = "8941_lvs2";
+ reg = <0x8100 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@8200 {
+ regulator-name = "8941_lvs3";
+ reg = <0x8200 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@8300 {
+ regulator-name = "8941_mvs1";
+ reg = <0x8300 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@8400 {
+ regulator-name = "8941_mvs2";
+ reg = <0x8400 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ qcom,vibrator@c000 {
+ compatible = "qcom,qpnp-vibrator";
+ reg = <0xc000 0x100>;
+ label = "vibrator";
+ status = "disabled";
+ };
+
+ qcom,leds@d000 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xd000 0x100>;
+ label = "rgb";
+ };
+
+ qcom,leds@d100 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xd100 0x100>;
+ label = "rgb";
+ };
+
+ qcom,leds@d200 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xd200 0x100>;
+ label = "rgb";
+ };
+
+ qcom,leds@d300 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xd300 0x100>;
+ label = "flash";
+ flash_boost-supply = <&pm8941_chg_boost>;
+ };
+
+ qcom,leds@d400 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xd400 0x100>;
+ label = "flash";
+ };
+
+ qcom,leds@d500 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xd500 0x100>;
+ label = "flash";
+ };
+
+ qcom,leds@d600 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xd600 0x100>;
+ label = "flash";
+ };
+
+ qcom,leds@d700 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xd700 0x100>;
+ label = "flash";
+ };
+
+ qcom,leds@d800 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xd800 0x100>;
+ label = "wled";
+ };
+
+ qcom,leds@d900 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xd900 0x100>;
+ label = "wled";
+ };
+
+ qcom,leds@da00 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xda00 0x100>;
+ label = "wled";
+ };
+
+ qcom,leds@db00 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xdb00 0x100>;
+ label = "wled";
+ };
+
+ qcom,leds@dc00 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xdc00 0x100>;
+ label = "wled";
+ };
+
+ qcom,leds@dd00 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xdd00 0x100>;
+ label = "wled";
+ };
+
+ qcom,leds@de00 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xde00 0x100>;
+ label = "wled";
+ };
+
+ qcom,leds@df00 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xdf00 0x100>;
+ label = "wled";
+ };
+
+ qcom,leds@e000 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xe000 0x100>;
+ label = "wled";
+ };
+
+ qcom,leds@e100 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xe100 0x100>;
+ label = "wled";
+ };
+
+ qcom,leds@e200 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xe200 0x100>;
+ label = "kpdbl";
+ };
+
+ pwm@b100 {
+ compatible = "qcom,qpnp-pwm";
+ reg = <0xb100 0x100>,
+ <0xb042 0x7e>;
+ reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base";
+ qcom,channel-id = <0>;
+ };
+
+ pwm@b200 {
+ compatible = "qcom,qpnp-pwm";
+ reg = <0xb200 0x100>,
+ <0xb042 0x7e>;
+ reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base";
+ qcom,channel-id = <1>;
+ };
+
+ pwm@b300 {
+ compatible = "qcom,qpnp-pwm";
+ reg = <0xb300 0x100>,
+ <0xb042 0x7e>;
+ reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base";
+ qcom,channel-id = <2>;
+ };
+
+ pwm@b400 {
+ compatible = "qcom,qpnp-pwm";
+ reg = <0xb400 0x100>,
+ <0xb042 0x7e>;
+ reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base";
+ qcom,channel-id = <3>;
+ };
+
+ pwm@b500 {
+ compatible = "qcom,qpnp-pwm";
+ reg = <0xb500 0x100>,
+ <0xb042 0x7e>;
+ reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base";
+ qcom,channel-id = <4>;
+ };
+
+ pwm@b600 {
+ compatible = "qcom,qpnp-pwm";
+ reg = <0xb600 0x100>,
+ <0xb042 0x7e>;
+ reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base";
+ qcom,channel-id = <5>;
+ };
+
+ pwm@b700 {
+ compatible = "qcom,qpnp-pwm";
+ reg = <0xb700 0x100>,
+ <0xb042 0x7e>;
+ reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base";
+ qcom,channel-id = <6>;
+ };
+
+ pwm@b800 {
+ compatible = "qcom,qpnp-pwm";
+ reg = <0xb800 0x100>,
+ <0xb042 0x7e>;
+ reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base";
+ qcom,channel-id = <7>;
+ };
+
+ pwm@e400 {
+ compatible = "qcom,qpnp-pwm";
+ reg = <0xe400 0x100>,
+ <0xe342 0x1e>;
+ reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base";
+ qcom,channel-id = <8>;
+ };
+
+ pwm@e500 {
+ compatible = "qcom,qpnp-pwm";
+ reg = <0xe500 0x100>,
+ <0xe342 0x1e>;
+ reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base";
+ qcom,channel-id = <9>;
+ };
+
+ pwm@e600 {
+ compatible = "qcom,qpnp-pwm";
+ reg = <0xe600 0x100>,
+ <0xe342 0x1e>;
+ reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base";
+ qcom,channel-id = <10>;
+ };
+
+ pwm@e700 {
+ compatible = "qcom,qpnp-pwm";
+ reg = <0xe700 0x100>,
+ <0xe342 0x1e>;
+ reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base";
+ qcom,channel-id = <11>;
};
};
diff --git a/arch/arm/boot/dts/msm-pma8084-rpm-regulator.dtsi b/arch/arm/boot/dts/msm-pma8084-rpm-regulator.dtsi
new file mode 100644
index 0000000..31796dd
--- /dev/null
+++ b/arch/arm/boot/dts/msm-pma8084-rpm-regulator.dtsi
@@ -0,0 +1,712 @@
+/* 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.
+ */
+
+&rpm_bus {
+ rpm-regulator-smpa1 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "smpa";
+ qcom,resource-id = <1>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ status = "disabled";
+
+ regulator-s1 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_s1";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-smpa2 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "smpa";
+ qcom,resource-id = <2>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ status = "disabled";
+
+ regulator-s2 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_s2";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-smpa3 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "smpa";
+ qcom,resource-id = <3>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ status = "disabled";
+
+ regulator-s3 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_s3";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-smpa4 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "smpa";
+ qcom,resource-id = <4>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ status = "disabled";
+
+ regulator-s4 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_s4";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-smpa5 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "smpa";
+ qcom,resource-id = <5>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ status = "disabled";
+
+ regulator-s5 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_s5";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-smpa6 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "smpa";
+ qcom,resource-id = <6>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ status = "disabled";
+
+ regulator-s6 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_s6";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-smpa7 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "smpa";
+ qcom,resource-id = <7>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ status = "disabled";
+
+ regulator-s7 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_s7";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-smpa8 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "smpa";
+ qcom,resource-id = <8>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ status = "disabled";
+
+ regulator-s8 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_s8";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-smpa9 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "smpa";
+ qcom,resource-id = <9>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ status = "disabled";
+
+ regulator-s9 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_s9";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-smpa10 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "smpa";
+ qcom,resource-id = <10>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ status = "disabled";
+
+ regulator-s10 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_s10";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-smpa11 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "smpa";
+ qcom,resource-id = <11>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ status = "disabled";
+
+ regulator-s11 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_s11";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-smpa12 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "smpa";
+ qcom,resource-id = <12>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ status = "disabled";
+
+ regulator-s12 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_s12";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa1 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <1>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l1 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_l1";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa2 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <2>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l2 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_l2";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa3 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <3>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l3 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_l3";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa4 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <4>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l4 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_l4";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa5 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <5>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l5 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_l5";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa6 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <6>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l6 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_l6";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa7 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <7>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l7 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_l7";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa8 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <8>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l8 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_l8";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa9 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <9>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l9 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_l9";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa10 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <10>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l10 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_l10";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa11 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <11>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l11 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_l11";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa12 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <12>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l12 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_l12";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa13 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <13>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l13 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_l13";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa14 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <14>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l14 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_l14";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa15 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <15>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l15 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_l15";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa16 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <16>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l16 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_l16";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa17 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <17>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l17 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_l17";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa18 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <18>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l18 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_l18";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa19 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <19>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l19 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_l19";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa20 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <20>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l20 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_l20";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa21 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <21>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l21 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_l21";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa22 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <22>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l22 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_l22";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa23 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <23>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l23 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_l23";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa24 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <24>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l24 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_l24";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa25 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <25>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l25 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_l25";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa26 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <26>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l26 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_l26";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa27 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <27>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l27 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_l27";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-vsa1 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "vsa";
+ qcom,resource-id = <1>;
+ qcom,regulator-type = <2>;
+ status = "disabled";
+
+ regulator-lvs1 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_lvs1";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-vsa2 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "vsa";
+ qcom,resource-id = <2>;
+ qcom,regulator-type = <2>;
+ status = "disabled";
+
+ regulator-lvs2 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_lvs2";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-vsa3 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "vsa";
+ qcom,resource-id = <3>;
+ qcom,regulator-type = <2>;
+ status = "disabled";
+
+ regulator-lvs3 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_lvs3";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-vsa4 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "vsa";
+ qcom,resource-id = <4>;
+ qcom,regulator-type = <2>;
+ status = "disabled";
+
+ regulator-lvs4 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_lvs4";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-vsa5 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "vsa";
+ qcom,resource-id = <5>;
+ qcom,regulator-type = <2>;
+ status = "disabled";
+
+ regulator-mvs1 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_mvs1";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/msm-pma8084.dtsi b/arch/arm/boot/dts/msm-pma8084.dtsi
index 42c48f8..ecbfc53 100644
--- a/arch/arm/boot/dts/msm-pma8084.dtsi
+++ b/arch/arm/boot/dts/msm-pma8084.dtsi
@@ -22,6 +22,68 @@
#address-cells = <1>;
#size-cells = <1>;
+ qcom,revid@100 {
+ compatible = "qcom,qpnp-revid";
+ reg = <0x100 0x100>;
+ };
+
+ qcom,power-on@800 {
+ compatible = "qcom,qpnp-power-on";
+ reg = <0x800 0x100>;
+ interrupts = <0x0 0x8 0x0>,
+ <0x0 0x8 0x1>,
+ <0x0 0x8 0x4>,
+ <0x0 0x8 0x5>;
+ interrupt-names = "kpdpwr", "resin",
+ "resin-bark", "kpdpwr-resin-bark";
+ qcom,pon-dbc-delay = <15625>;
+ qcom,system-reset;
+ qcom,s3-debounce = <32>;
+
+ qcom,pon_1 {
+ qcom,pon-type = <0>;
+ qcom,pull-up = <1>;
+ linux,code = <116>;
+ };
+
+ qcom,pon_2 {
+ qcom,pon-type = <1>;
+ qcom,support-reset = <1>;
+ qcom,pull-up = <1>;
+ qcom,s1-timer = <0>;
+ qcom,s2-timer = <2000>;
+ qcom,s2-type = <1>;
+ linux,code = <114>;
+ };
+
+ qcom,pon_3 {
+ qcom,pon-type = <3>;
+ qcom,support-reset = <1>;
+ qcom,s1-timer = <6720>;
+ qcom,s2-timer = <2000>;
+ qcom,s2-type = <7>;
+ qcom,pull-up = <1>;
+ };
+ };
+
+ pma8084_misc: qcom,misc@900 {
+ compatible = "qcom,qpnp-misc";
+ reg = <0x900 0x100>;
+ };
+
+ qcom,temp-alarm@2400 {
+ compatible = "qcom,qpnp-temp-alarm";
+ reg = <0x2400 0x100>;
+ interrupts = <0x0 0x24 0x0>;
+ label = "pma8084_tz";
+ qcom,threshold-set = <0>;
+ };
+
+ qcom,coincell@2800 {
+ compatible = "qcom,qpnp-coincell";
+ reg = <0x2800 0x100>;
+ };
+
pma8084_gpios: gpios {
spmi-dev-container;
compatible = "qcom,qpnp-pin";
@@ -261,6 +323,23 @@
qcom,adc-bit-resolution = <15>;
qcom,adc-vdd-reference = <1800>;
};
+
+ qcom,rtc {
+ compatible = "qcom,qpnp-rtc";
+ spmi-dev-container;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ qcom,qpnp-rtc-write = <0>;
+ qcom,qpnp-rtc-alarm-pwrup = <0>;
+
+ qcom,rtc_rw@6000 {
+ reg = <0x6000 0x100>;
+ };
+ qcom,rtc_alarm@6100 {
+ reg = <0x6100 0x100>;
+ interrupts = <0x0 0x61 0x1>;
+ };
+ };
};
qcom,pma8084@1 {
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
index 41d6b7e..d4b605b 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
@@ -105,4 +105,41 @@
qcom,cci-master = <0>;
status = "ok";
};
+
+ qcom,camera@90 {
+ compatible = "qcom,mt9m114";
+ reg = <0x90 0x0>;
+ qcom,slave-id = <0x90 0x0 0x2481>;
+ qcom,csiphy-sd-index = <1>;
+ qcom,csid-sd-index = <1>;
+ qcom,mount-angle = <90>;
+ qcom,sensor-name = "mt9m114";
+ cam_vdig-supply = <&pm8226_l5>;
+ cam_vana-supply = <&pm8226_l19>;
+ cam_vio-supply = <&pm8226_lvs1>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
+ qcom,cam-vreg-type = <0 1 0>;
+ qcom,cam-vreg-min-voltage = <1200000 0 2850000>;
+ qcom,cam-vreg-max-voltage = <1200000 0 2850000>;
+ qcom,cam-vreg-op-mode = <200000 0 80000>;
+ qcom,gpio-no-mux = <0>;
+ gpios = <&msmgpio 26 0>,
+ <&msmgpio 28 0>,
+ <&msmgpio 35 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET",
+ "CAM_STANDBY";
+ qcom,gpio-set-tbl-num = <1 1>;
+ qcom,gpio-set-tbl-flags = <0 2>;
+ qcom,gpio-set-tbl-delay = <1000 4000>;
+ qcom,csi-lane-assign = <0x4320>;
+ qcom,csi-lane-mask = <0x3>;
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <1>;
+ qcom,cci-master = <0>;
+ };
};
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
index 3935dbb..fb24a25 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
@@ -68,6 +68,57 @@
qcom,cci-master = <0>;
};
+ actuator1: qcom,actuator@18 {
+ cell-index = <4>;
+ reg = <0x18>;
+ compatible = "qcom,actuator";
+ qcom,cci-master = <0>;
+ };
+
+ qcom,camera@6c {
+ compatible = "qcom,ov12830";
+ reg = <0x6c>;
+ qcom,slave-id = <0x20 0x300a 0xc830>;
+ qcom,csiphy-sd-index = <0>;
+ qcom,csid-sd-index = <0>;
+ qcom,actuator-src = <&actuator1>;
+ qcom,led-flash-src = <&led_flash0>;
+ qcom,mount-angle = <270>;
+ qcom,sensor-name = "skuf_ov12830_p12v01c";
+ cam_vdig-supply = <&pm8226_l5>;
+ cam_vana-supply = <&pm8226_l19>;
+ cam_vio-supply = <&pm8226_lvs1>;
+ cam_vaf-supply = <&pm8226_l15>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_vaf";
+ qcom,cam-vreg-type = <0 1 0 0>;
+ qcom,cam-vreg-min-voltage = <1200000 0 2850000 2800000>;
+ qcom,cam-vreg-max-voltage = <1200000 0 2850000 2800000>;
+ qcom,cam-vreg-op-mode = <120000 0 0 80000 100000>;
+ qcom,gpio-no-mux = <0>;
+ gpios = <&msmgpio 26 0>,
+ <&msmgpio 37 0>,
+ <&msmgpio 36 0>,
+ <&msmgpio 22 0>,
+ <&msmgpio 34 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-vdig = <3>;
+ qcom,gpio-af-pwdm = <4>;
+ qcom,gpio-req-tbl-num = <0 1 2 3 4>;
+ qcom,gpio-req-tbl-flags = <1 0 0 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET1",
+ "CAM_STANDBY",
+ "CAM_VDIG",
+ "CAM_AF_PWDM";
+ qcom,csi-lane-assign = <0x4320>;
+ qcom,csi-lane-mask = <0x1f>;
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <1>;
+ qcom,cci-master = <0>;
+ };
+
qcom,camera@6d {
compatible = "qcom,ov9724";
reg = <0x6d>;
@@ -105,4 +156,45 @@
qcom,cci-master = <0>;
status = "ok";
};
+
+ qcom,camera@6a {
+ compatible = "qcom,ov5648";
+ reg = <0x6a>;
+ qcom,slave-id = <0x6c 0x300a 0x5648>;
+ qcom,csiphy-sd-index = <1>;
+ qcom,csid-sd-index = <1>;
+ qcom,mount-angle = <270>;
+ qcom,sensor-name = "skuf_ov5648_p5v23c";
+ cam_vdig-supply = <&pm8226_l5>;
+ cam_vana-supply = <&pm8226_l19>;
+ cam_vio-supply = <&pm8226_lvs1>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
+ qcom,cam-vreg-type = <0 1 0>;
+ qcom,cam-vreg-min-voltage = <1200000 0 2850000>;
+ qcom,cam-vreg-max-voltage = <1200000 0 2850000>;
+ qcom,cam-vreg-op-mode = <200000 0 80000>;
+ qcom,gpio-no-mux = <0>;
+ gpios = <&msmgpio 26 0>,
+ <&msmgpio 28 0>,
+ <&msmgpio 35 0>,
+ <&msmgpio 21 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-vdig = <3>;
+ qcom,gpio-req-tbl-num = <0 1 2 3>;
+ qcom,gpio-req-tbl-flags = <1 0 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET",
+ "CAM_STANDBY",
+ "CAM_VDIG";
+ qcom,gpio-set-tbl-num = <1 1>;
+ qcom,gpio-set-tbl-flags = <0 2>;
+ qcom,gpio-set-tbl-delay = <1000 4000>;
+ qcom,csi-lane-assign = <0x4320>;
+ qcom,csi-lane-mask = <0x3>;
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <1>;
+ qcom,cci-master = <0>;
+ status = "ok";
+ };
};
diff --git a/arch/arm/boot/dts/msm8226-camera.dtsi b/arch/arm/boot/dts/msm8226-camera.dtsi
index ec0092d..617d738 100644
--- a/arch/arm/boot/dts/msm8226-camera.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera.dtsi
@@ -125,15 +125,39 @@
qcom,gpio-tbl-flags = <1 1>;
qcom,gpio-tbl-label = "CCI_I2C_DATA0",
"CCI_I2C_CLK0";
- 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-scl-stretch-en = <0>;
- qcom,hw-trdhld = <6>;
- qcom,hw-tsp = <1>;
+ master0: qcom,cci-master0 {
+ status = "disabled";
+ };
+ master1: qcom,cci-master1 {
+ status = "disabled";
+ };
};
};
+
+&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-scl-stretch-en = <0>;
+ qcom,hw-trdhld = <6>;
+ qcom,hw-tsp = <1>;
+ 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-scl-stretch-en = <0>;
+ qcom,hw-trdhld = <6>;
+ qcom,hw-tsp = <1>;
+ status = "ok";
+};
diff --git a/arch/arm/boot/dts/msm8226-cdp.dtsi b/arch/arm/boot/dts/msm8226-cdp.dtsi
index 308a6f5..d94b41d 100644
--- a/arch/arm/boot/dts/msm8226-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8226-cdp.dtsi
@@ -20,6 +20,7 @@
qcom,mdss_dsi_nt35590_720p_video {
status = "ok";
+ qcom,cont-splash-enabled;
};
i2c@f9927000 { /* BLSP1 QUP5 */
@@ -34,6 +35,7 @@
synaptics,irq-gpio = <&msmgpio 17 0x2008>;
synaptics,button-map = <139 102 158>;
synaptics,i2c-pull-up;
+ synaptics,power-down;
};
};
@@ -74,7 +76,7 @@
compatible = "micrel,ks8851";
reg = <3>;
interrupt-parent = <&msmgpio>;
- interrupts = <0 115 0>;
+ interrupts = <115 0x8>;
spi-max-frequency = <4800000>;
rst-gpio = <&msmgpio 114 0>;
vdd-io-supply = <&pm8226_lvs1>;
@@ -113,8 +115,6 @@
&sdcc1 {
vdd-supply = <&pm8226_l17>;
- qcom,vdd-always-on;
- qcom,vdd-lpm-sup;
qcom,vdd-voltage-level = <2950000 2950000>;
qcom,vdd-current-level = <800 500000>;
@@ -139,8 +139,6 @@
&sdhc_1 {
vdd-supply = <&pm8226_l17>;
- qcom,vdd-always-on;
- qcom,vdd-lpm-sup;
qcom,vdd-voltage-level = <2950000 2950000>;
qcom,vdd-current-level = <800 500000>;
@@ -226,6 +224,16 @@
status = "ok";
};
+&sdcc3 {
+ qcom,sup-voltages = <1800 1800>;
+ status = "disabled";
+};
+
+&sdhc_3 {
+ qcom,sup-voltages = <1800 1800>;
+ status = "disabled";
+};
+
&spmi_bus {
qcom,pm8226@0 {
qcom,leds@a100 {
@@ -260,8 +268,12 @@
qcom,mode-ctrl = <0x60>;
qcom,pwm-channel = <0>;
qcom,start-idx = <1>;
- qcom,duty-pcts = [00 00 00 00 64
- 64 00 00 00 00];
+ qcom,ramp-step-ms = <120>;
+ qcom,duty-pcts = [00 00 00 00 00
+ 00 00 00 00 00
+ 50 00 00 00 00
+ 00 00 00 00 00
+ 00];
qcom,use-blink;
};
};
@@ -282,8 +294,12 @@
qcom,source-sel = <10>;
qcom,pwm-channel = <5>;
qcom,start-idx = <1>;
- qcom,duty-pcts = [00 00 00 00 64
- 64 00 00 00 00];
+ qcom,ramp-step-ms = <120>;
+ qcom,duty-pcts = [00 00 00 00 00
+ 00 00 00 00 00
+ 50 00 00 00 00
+ 00 00 00 00 00
+ 00];
qcom,use-blink;
};
};
diff --git a/arch/arm/boot/dts/msm8226-coresight.dtsi b/arch/arm/boot/dts/msm8226-coresight.dtsi
index e11c963..cbfdfc9 100644
--- a/arch/arm/boot/dts/msm8226-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8226-coresight.dtsi
@@ -16,6 +16,8 @@
reg = <0xfc322000 0x1000>,
<0xfc37c000 0x3000>;
reg-names = "tmc-base", "bam-base";
+ interrupts = <0 166 0>;
+ interrupt-names = "byte-cntr-irq";
qcom,memory-reservation-type = "EBI1";
qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
@@ -365,8 +367,9 @@
compatible = "qcom,coresight-hwevent";
reg = <0xfd828018 0x80>,
<0xf9011080 0x80>,
- <0xfd4ab160 0x80>;
- reg-names = "mmss-mux", "apcs-mux", "ppss-mux";
+ <0xfd4ab160 0x80>,
+ <0xfc401600 0x80>;
+ reg-names = "mmss-mux", "apcs-mux", "ppss-mux", "gcc-mux";
coresight-id = <29>;
coresight-name = "coresight-hwevent";
@@ -374,4 +377,14 @@
qcom,hwevent-clks = "core_mmss_clk";
};
+
+ fuse: fuse@fc4be024 {
+ compatible = "arm,coresight-fuse";
+ reg = <0xfc4be024 0x8>;
+ reg-names = "fuse-base";
+
+ coresight-id = <30>;
+ coresight-name = "coresight-fuse";
+ coresight-nr-inports = <0>;
+ };
};
diff --git a/arch/arm/boot/dts/msm8226-mdss.dtsi b/arch/arm/boot/dts/msm8226-mdss.dtsi
index f580897..5f991fb 100644
--- a/arch/arm/boot/dts/msm8226-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8226-mdss.dtsi
@@ -36,6 +36,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,vbif-settings = <0x004 0x00000001>,
<0x0D8 0x00000707>,
@@ -61,14 +62,54 @@
label = "MDSS DSI CTRL->0";
cell-index = <0>;
reg = <0xfd922800 0x600>;
+ qcom,mdss-fb-map = <&mdss_fb0>;
vdd-supply = <&pm8226_l15>;
vddio-supply = <&pm8226_l8>;
vdda-supply = <&pm8226_l4>;
- qcom,supply-names = "vdd", "vddio", "vdda";
- qcom,supply-min-voltage-level = <2800000 1800000 1200000>;
- qcom,supply-max-voltage-level = <2800000 1800000 1200000>;
- qcom,supply-peak-current = <150000 100000 100000>;
- qcom,mdss-fb-map = <&mdss_fb0>;
+ qcom,platform-reset-gpio = <&msmgpio 25 1>;
+ qcom,platform-te-gpio = <&msmgpio 24 0>;
+ qcom,platform-strength-ctrl = [ff 06];
+ qcom,platform-bist-ctrl = [00 00 b1 ff 00 00];
+ qcom,platform-regulator-settings = [07 09 03 00 20 00 01];
+ qcom,platform-lane-config = [00 00 00 00 00 00 00 01 97
+ 00 00 00 00 05 00 00 01 97
+ 00 00 00 00 0a 00 00 01 97
+ 00 00 00 00 0f 00 00 01 97
+ 00 c0 00 00 00 00 00 01 bb];
+ qcom,platform-reset-sequence = <1 20 0 1 1 20>;
+ qcom,platform-supply-entry1 {
+ qcom,supply-name = "vdd";
+ qcom,supply-min-voltage = <2800000>;
+ qcom,supply-max-voltage = <2800000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ qcom,supply-pre-on-sleep = <0>;
+ qcom,supply-post-on-sleep = <0>;
+ qcom,supply-pre-off-sleep = <0>;
+ qcom,supply-post-off-sleep = <0>;
+ };
+ qcom,platform-supply-entry2 {
+ qcom,supply-name = "vddio";
+ qcom,supply-min-voltage = <1800000>;
+ qcom,supply-max-voltage = <1800000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ qcom,supply-pre-on-sleep = <0>;
+ qcom,supply-post-on-sleep = <0>;
+ qcom,supply-pre-off-sleep = <0>;
+ qcom,supply-post-off-sleep = <0>;
+ };
+ qcom,platform-supply-entry3 {
+ qcom,supply-name = "vdda";
+ qcom,supply-min-voltage = <1200000>;
+ qcom,supply-max-voltage = <1200000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ qcom,supply-pre-on-sleep = <0>;
+ qcom,supply-post-on-sleep = <20>;
+ qcom,supply-pre-off-sleep = <0>;
+ qcom,supply-post-off-sleep = <0>;
+ };
};
qcom,mdss_wb_panel {
diff --git a/arch/arm/boot/dts/msm8226-mtp.dtsi b/arch/arm/boot/dts/msm8226-mtp.dtsi
index bd32138..825e853 100644
--- a/arch/arm/boot/dts/msm8226-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-mtp.dtsi
@@ -20,6 +20,7 @@
qcom,mdss_dsi_nt35590_720p_video {
status = "ok";
+ qcom,cont-splash-enabled;
};
i2c@f9927000 { /* BLSP1 QUP5 */
@@ -34,6 +35,7 @@
synaptics,irq-gpio = <&msmgpio 17 0x2008>;
synaptics,button-map = <139 102 158>;
synaptics,i2c-pull-up;
+ synaptics,power-down;
};
};
@@ -85,7 +87,7 @@
compatible = "micrel,ks8851";
reg = <3>;
interrupt-parent = <&msmgpio>;
- interrupts = <0 115 0>;
+ interrupts = <115 0x8>;
spi-max-frequency = <4800000>;
rst-gpio = <&msmgpio 114 0>;
vdd-io-supply = <&pm8226_lvs1>;
@@ -130,8 +132,6 @@
&sdcc1 {
vdd-supply = <&pm8226_l17>;
- qcom,vdd-always-on;
- qcom,vdd-lpm-sup;
qcom,vdd-voltage-level = <2950000 2950000>;
qcom,vdd-current-level = <800 500000>;
@@ -156,8 +156,6 @@
&sdhc_1 {
vdd-supply = <&pm8226_l17>;
- qcom,vdd-always-on;
- qcom,vdd-lpm-sup;
qcom,vdd-voltage-level = <2950000 2950000>;
qcom,vdd-current-level = <800 500000>;
@@ -274,8 +272,12 @@
qcom,mode-ctrl = <0x60>;
qcom,pwm-channel = <0>;
qcom,start-idx = <1>;
- qcom,duty-pcts = [00 00 00 00 64
- 64 00 00 00 00];
+ qcom,ramp-step-ms = <120>;
+ qcom,duty-pcts = [00 00 00 00 00
+ 00 00 00 00 00
+ 50 00 00 00 00
+ 00 00 00 00 00
+ 00];
qcom,use-blink;
};
};
@@ -296,8 +298,12 @@
qcom,source-sel = <10>;
qcom,pwm-channel = <5>;
qcom,start-idx = <1>;
- qcom,duty-pcts = [00 00 00 00 64
- 64 00 00 00 00];
+ qcom,ramp-step-ms = <120>;
+ qcom,duty-pcts = [00 00 00 00 00
+ 00 00 00 00 00
+ 50 00 00 00 00
+ 00 00 00 00 00
+ 00];
qcom,use-blink;
};
};
diff --git a/arch/arm/boot/dts/msm8226-pm.dtsi b/arch/arm/boot/dts/msm8226-pm.dtsi
index d9bd5e8..ef0a55e 100644
--- a/arch/arm/boot/dts/msm8226-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-pm.dtsi
@@ -20,12 +20,12 @@
qcom,saw2-ver-reg = <0xfd0>;
qcom,saw2-cfg = <0x00>;
qcom,saw2-spm-dly= <0x3c102800>;
- qcom,saw2-spm-ctl = <0x0>;
+ 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 07 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 07 60 3b 76 76
+ 0b 94 5b 80 10 26 30 0f];
};
qcom,spm@f9099000 {
@@ -37,12 +37,12 @@
qcom,saw2-ver-reg = <0xfd0>;
qcom,saw2-cfg = <0x00>;
qcom,saw2-spm-dly= <0x3c102800>;
- qcom,saw2-spm-ctl = <0x0>;
+ 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 07 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 07 60 3b 76 76
+ 0b 94 5b 80 10 26 30 0f];
};
qcom,spm@f90a9000 {
@@ -54,12 +54,12 @@
qcom,saw2-ver-reg = <0xfd0>;
qcom,saw2-cfg = <0x00>;
qcom,saw2-spm-dly= <0x3c102800>;
- qcom,saw2-spm-ctl = <0x0>;
+ 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 07 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 07 60 3b 76 76
+ 0b 94 5b 80 10 26 30 0f];
};
qcom,spm@f90b9000 {
@@ -71,12 +71,12 @@
qcom,saw2-ver-reg = <0xfd0>;
qcom,saw2-cfg = <0x00>;
qcom,saw2-spm-dly= <0x3c102800>;
- qcom,saw2-spm-ctl = <0x0>;
+ 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 07 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 07 60 3b 76 76
+ 0b 94 5b 80 10 26 30 0f];
};
qcom,spm@f9012000 {
@@ -95,68 +95,22 @@
qcom,vctl-port = <0x0>;
qcom,phase-port = <0x1>;
qcom,pfm-port = <0x2>;
- qcom,saw2-spm-cmd-ret = [00 03 00 7b 0f];
+ qcom,saw2-spm-cmd-ret = [00 03 00 0f];
qcom,saw2-spm-cmd-pc = [00 32 b0 10 e0 d0 6b c0 42 f0
- 11 07 01 b0 4e c0 d0 12 e0 6b 50 02 32
- 50 f0 7b 0f]; /*APCS_PMIC_OFF_L2RAM_OFF*/
- };
-
- qcom,lpm-resources {
- compatible = "qcom,lpm-resources";
- #address-cells = <1>;
- #size-cells = <0>;
-
- qcom,lpm-resources@0 {
- reg = <0x0>;
- qcom,name = "vdd-dig";
- qcom,type = <0x61706d73>; /* "smpa" */
- qcom,id = <0x01>;
- qcom,key = <0x6e726f63>; /* "corn" */
- qcom,init-value = <3>; /* SVS SOC */
- };
-
- qcom,lpm-resources@1 {
- reg = <0x1>;
- qcom,name = "vdd-mem";
- qcom,type = <0x616F646C>; /* "ldoa" */
- qcom,id = <0x03>;
- qcom,key = <0x6e726f63>; /* "corn" */
- qcom,init-value = <3>; /* SVS SOC */
- };
-
- qcom,lpm-resources@2 {
- reg = <0x2>;
- qcom,name = "pxo";
- qcom,type = <0x306b6c63>; /* "clk0" */
- qcom,id = <0x00>;
- qcom,key = <0x62616e45>; /* "Enab" */
- qcom,init-value = "xo_on";
- };
-
- qcom,lpm-resources@3 {
- reg = <0x3>;
- qcom,name = "l2";
- qcom,local-resource-type;
- qcom,init-value = "l2_cache_retention";
- };
+ 11 07 01 b0 50 4e 02 02 c0 d0 12 e0 6b 02 32
+ 50 f0 0f]; /*APCS_PMIC_OFF_L2RAM_OFF*/
};
qcom,lpm-levels {
compatible = "qcom,lpm-levels";
+ qcom,default-l2-state = "l2_cache_active";
#address-cells = <1>;
#size-cells = <0>;
qcom,lpm-level@0 {
reg = <0x0>;
qcom,mode = "wfi";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_active";
- qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
qcom,latency-us = <1>;
qcom,ss-power = <784>;
qcom,energy-overhead = <190000>;
@@ -166,14 +120,7 @@
qcom,lpm-level@1 {
reg = <0x1>;
qcom,mode = "standalone_pc";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_active";
- qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
qcom,latency-us = <3000>;
qcom,ss-power = <725>;
qcom,energy-overhead = <99500>;
@@ -183,15 +130,8 @@
qcom,lpm-level@2 {
reg = <0x2>;
qcom,mode = "pc";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_retention";
- qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
- qcom,latency-us = <8000>;
+ qcom,latency-us = <20000>;
qcom,ss-power = <138>;
qcom,energy-overhead = <1208400>;
qcom,time-overhead = <9200>;
@@ -200,64 +140,12 @@
qcom,lpm-level@3 {
reg = <0x3>;
qcom,mode = "pc";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <4>; /* NORMAL */
- qcom,vdd-mem-lower-bound = <3>; /* SVS SOC */
- qcom,vdd-dig-upper-bound = <4>; /* NORMAL */
- qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
- qcom,latency-us = <9000>;
+ qcom,latency-us = <30000>;
qcom,ss-power = <110>;
qcom,energy-overhead = <1250300>;
qcom,time-overhead = <9500>;
};
-
- qcom,lpm-level@4 {
- reg = <0x4>;
- qcom,mode = "pc";
- qcom,xo = "xo_off";
- qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,latency-us = <16300>;
- qcom,ss-power = <63>;
- qcom,energy-overhead = <2128000>;
- qcom,time-overhead = <24200>;
- };
-
- qcom,lpm-level@5 {
- reg = <0x5>;
- qcom,mode = "pc";
- qcom,xo = "xo_off";
- qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <4>; /* NORMAL */
- qcom,vdd-mem-lower-bound = <3>; /* SVS SOC */
- qcom,vdd-dig-upper-bound = <4>; /* NORMAL */
- qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
- qcom,latency-us = <24000>;
- qcom,ss-power = <10>;
- qcom,energy-overhead = <3202600>;
- qcom,time-overhead = <33000>;
- };
-
- qcom,lpm-level@6 {
- reg = <0x6>;
- qcom,mode = "pc";
- qcom,xo = "xo_off";
- qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <3>; /* SVS SOC */
- qcom,vdd-mem-lower-bound = <1>; /* RETENTION */
- qcom,vdd-dig-upper-bound = <3>; /* SVS SOC */
- qcom,vdd-dig-lower-bound = <1>; /* RETENTION */
- qcom,latency-us = <26000>;
- qcom,ss-power = <2>;
- qcom,energy-overhead = <4252000>;
- qcom,time-overhead = <38000>;
- };
};
qcom,pm-boot {
diff --git a/arch/arm/boot/dts/msm8226-qrd.dtsi b/arch/arm/boot/dts/msm8226-qrd.dtsi
index 64cbb10..55d8691 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8226-qrd.dtsi
@@ -10,16 +10,13 @@
* GNU General Public License for more details.
*/
-/include/ "dsi-panel-nt35590-720p-video.dtsi"
+/include/ "dsi-panel-nt35596-1080p-video.dtsi"
/include/ "msm8226-camera-sensor-qrd.dtsi"
&soc {
serial@f991f000 {
status = "ok";
- };
-
- qcom,mdss_dsi_nt35590_720p_video {
- status = "ok";
+ qcom,cont-splash-enabled;
};
i2c@f9927000 { /* BLSP1 QUP5 */
@@ -34,7 +31,35 @@
synaptics,irq-gpio = <&msmgpio 17 0x2008>;
synaptics,button-map = <139 102 158>;
synaptics,i2c-pull-up;
+ synaptics,power-down;
};
+ focaltech@38 {
+ compatible = "focaltech,5x06";
+ reg = <0x38>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <17 0x2>;
+ vdd-supply = <&pm8226_l19>;
+ vcc_i2c-supply = <&pm8226_lvs1>;
+ focaltech,family-id = <0x55>;
+ focaltech,reset-gpio = <&msmgpio 16 0x00>;
+ focaltech,irq-gpio = <&msmgpio 17 0x00>;
+ focaltech,display-coords = <0 0 1080 1920>;
+ focaltech,panel-coords = <0 0 1080 2000>;
+ focaltech,button-map= <139 102 158>;
+ focaltech,no-force-update;
+ focaltech,i2c-pull-up;
+ };
+ };
+
+ gen-vkeys {
+ compatible = "qcom,gen-vkeys";
+ label = "ft5x06_ts";
+ qcom,disp-maxx = <1080>;
+ qcom,disp-maxy = <1920>;
+ qcom,panel-maxx = <1080>;
+ qcom,panel-maxy = <2080>;
+ qcom,key-codes = <139 102 158>;
+ qcom,y-offset = <0>;
};
gpio_keys {
@@ -74,7 +99,7 @@
compatible = "micrel,ks8851";
reg = <3>;
interrupt-parent = <&msmgpio>;
- interrupts = <0 115 0>;
+ interrupts = <115 0x8>;
spi-max-frequency = <4800000>;
rst-gpio = <&msmgpio 114 0>;
vdd-io-supply = <&pm8226_lvs1>;
@@ -105,8 +130,6 @@
&sdcc1 {
vdd-supply = <&pm8226_l17>;
- qcom,vdd-always-on;
- qcom,vdd-lpm-sup;
qcom,vdd-voltage-level = <2950000 2950000>;
qcom,vdd-current-level = <800 500000>;
@@ -131,8 +154,6 @@
&sdhc_1 {
vdd-supply = <&pm8226_l17>;
- qcom,vdd-always-on;
- qcom,vdd-lpm-sup;
qcom,vdd-voltage-level = <2950000 2950000>;
qcom,vdd-current-level = <800 500000>;
@@ -156,7 +177,7 @@
&sdcc2 {
vdd-supply = <&pm8226_l18>;
qcom,vdd-voltage-level = <2950000 2950000>;
- qcom,vdd-current-level = <9000 800000>;
+ qcom,vdd-current-level = <9000 400000>;
vdd-io-supply = <&pm8226_l21>;
qcom,vdd-io-voltage-level = <1800000 2950000>;
@@ -172,7 +193,7 @@
qcom,xpc;
qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
- qcom,current-limit = <600>;
+ qcom,current-limit = <400>;
#address-cells = <0>;
interrupt-parent = <&sdcc2>;
@@ -191,7 +212,7 @@
&sdhc_2 {
vdd-supply = <&pm8226_l18>;
qcom,vdd-voltage-level = <2950000 2950000>;
- qcom,vdd-current-level = <9000 800000>;
+ qcom,vdd-current-level = <9000 400000>;
vdd-io-supply = <&pm8226_l21>;
qcom,vdd-io-voltage-level = <1800000 2950000>;
@@ -241,7 +262,7 @@
qcom,led_mpp_4 {
label = "mpp";
linux,name = "green";
- linux,default-trigger = "none";
+ linux,default-trigger = "battery-full";
qcom,default-state = "off";
qcom,max-current = <40>;
qcom,current-setting = <5>;
@@ -252,8 +273,12 @@
qcom,mode-ctrl = <0x60>;
qcom,pwm-channel = <0>;
qcom,start-idx = <1>;
- qcom,duty-pcts = [00 00 00 00 64
- 64 00 00 00 00];
+ qcom,ramp-step-ms = <120>;
+ qcom,duty-pcts = [00 00 00 00 00
+ 00 00 00 00 00
+ 50 00 00 00 00
+ 00 00 00 00 00
+ 00];
qcom,use-blink;
};
};
@@ -263,7 +288,7 @@
qcom,led_mpp_6 {
label = "mpp";
linux,name = "red";
- linux,default-trigger = "none";
+ linux,default-trigger = "battery-charging";
qcom,default-state = "off";
qcom,max-current = <40>;
qcom,current-setting = <5>;
@@ -274,8 +299,12 @@
qcom,source-sel = <10>;
qcom,pwm-channel = <5>;
qcom,start-idx = <1>;
- qcom,duty-pcts = [00 00 00 00 64
- 64 00 00 00 00];
+ qcom,ramp-step-ms = <120>;
+ qcom,duty-pcts = [00 00 00 00 00
+ 00 00 00 00 00
+ 50 00 00 00 00
+ 00 00 00 00 00
+ 00];
qcom,use-blink;
};
};
@@ -399,5 +428,17 @@
tapan_codec {
qcom,cdc-micbias1-ext-cap;
};
+};
+&pm8226_vadc {
+ chan@30 {
+ label = "batt_therm";
+ reg = <0x30>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <6>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
};
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index e1a0f0b..d587b77 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -30,19 +30,22 @@
apc_vreg_corner: regulator@f9018000 {
status = "okay";
compatible = "qcom,cpr-regulator";
- reg = <0xf9018000 0x1000>, <0xf9011064 4>, <0xfc4b80b0 8>,
- <0xfc4bc450 16>;
- reg-names = "rbcpr", "rbcpr_clk", "pvs_efuse", "cpr_efuse";
+ reg = <0xf9018000 0x1000>, <0xf9011064 4>, <0xfc4b8000 0x1000>;
+ reg-names = "rbcpr", "rbcpr_clk", "efuse_addr";
interrupts = <0 15 0>;
regulator-name = "apc_corner";
regulator-min-microvolt = <1>;
regulator-max-microvolt = <3>;
- qcom,num-efuse-bits = <5>;
+
+ qcom,pvs-fuse-redun-sel = <22 24 3 2>;
+ qcom,pvs-fuse = <22 6 5>;
+ qcom,pvs-fuse-redun = <22 27 5>;
+
qcom,pvs-bin-process = <0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 2
2 2 2 2 3 3 3 3 3 3 3 3 0 0 0 0>;
- qcom,pvs-corner-ceiling-slow = <1155000 1160000 1275000>;
- qcom,pvs-corner-ceiling-nom = <975000 1075000 1200000>;
- qcom,pvs-corner-ceiling-fast = <900000 1000000 1140000>;
+ qcom,pvs-corner-ceiling-slow = <1050000 1160000 1275000>;
+ qcom,pvs-corner-ceiling-nom = <1050000 1075000 1200000>;
+ qcom,pvs-corner-ceiling-fast = <1050000 1050000 1140000>;
vdd-apc-supply = <&pm8226_s2>;
vdd-mx-supply = <&pm8226_l3_ao>;
@@ -63,6 +66,16 @@
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-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-target-quot = <24 12 0>;
+ qcom,cpr-fuse-redun-ro-sel = <46 36 39>;
+
qcom,cpr-enable;
};
};
@@ -95,6 +108,15 @@
qcom,use-voltage-corner;
qcom,consumer-supplies = "vdd_sr2_dig", "";
};
+ pm8226_s1_floor_corner: regulator-s1-floor-corner {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8226_s1_floor_corner";
+ qcom,set = <3>;
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+ qcom,use-voltage-floor-corner;
+ qcom,always-send-voltage;
+ };
};
rpm-regulator-smpa3 {
@@ -110,9 +132,9 @@
rpm-regulator-smpa4 {
status = "okay";
pm8226_s4: regulator-s4 {
- regulator-min-microvolt = <2100000>;
- regulator-max-microvolt = <2100000>;
- qcom,init-voltage = <2100000>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2200000>;
+ qcom,init-voltage = <1800000>;
status = "okay";
};
};
@@ -402,6 +424,17 @@
};
};
+ rpm-regulator-ldoa25 {
+ status = "okay";
+ pm8226_l25: regulator-l25 {
+ regulator-name = "8226_l25";
+ regulator-min-microvolt = <1775000>;
+ regulator-max-microvolt = <2125000>;
+ qcom,init-voltage = <1775000>;
+ status = "okay";
+ };
+ };
+
rpm-regulator-ldoa26 {
status = "okay";
pm8226_l26: regulator-l26 {
diff --git a/arch/arm/boot/dts/msm8226-v1-qrd.dts b/arch/arm/boot/dts/msm8226-v1-qrd-dvt.dts
similarity index 71%
copy from arch/arm/boot/dts/msm8226-v1-qrd.dts
copy to arch/arm/boot/dts/msm8226-v1-qrd-dvt.dts
index d2aabac..45c26c5 100644
--- a/arch/arm/boot/dts/msm8226-v1-qrd.dts
+++ b/arch/arm/boot/dts/msm8226-v1-qrd-dvt.dts
@@ -13,13 +13,20 @@
/dts-v1/;
/include/ "msm8226-v1.dtsi"
/include/ "msm8226-qrd.dtsi"
+/include/ "dsi-panel-hx8394a-720p-video.dtsi"
/ {
model = "Qualcomm MSM 8226 QRD";
compatible = "qcom,msm8226-qrd", "qcom,msm8226", "qcom,qrd";
- qcom,msm-id = <145 11 0>,
- <158 11 0>,
- <159 11 0>,
- <198 11 0>,
- <205 11 0>;
+ qcom,msm-id = <145 0x2000b 0>,
+ <158 0x2000b 0>,
+ <159 0x2000b 0>,
+ <198 0x2000b 0>;
+};
+
+&soc {
+ qcom,mdss_dsi_hx8394a_720p_video {
+ status = "ok";
+ qcom,cont-splash-enabled;
+ };
};
diff --git a/arch/arm/boot/dts/msm8226-v1-qrd.dts b/arch/arm/boot/dts/msm8226-v1-qrd-evt.dts
similarity index 82%
rename from arch/arm/boot/dts/msm8226-v1-qrd.dts
rename to arch/arm/boot/dts/msm8226-v1-qrd-evt.dts
index d2aabac..a081308 100644
--- a/arch/arm/boot/dts/msm8226-v1-qrd.dts
+++ b/arch/arm/boot/dts/msm8226-v1-qrd-evt.dts
@@ -13,6 +13,7 @@
/dts-v1/;
/include/ "msm8226-v1.dtsi"
/include/ "msm8226-qrd.dtsi"
+/include/ "dsi-panel-nt35590-720p-video.dtsi"
/ {
model = "Qualcomm MSM 8226 QRD";
@@ -23,3 +24,10 @@
<198 11 0>,
<205 11 0>;
};
+
+&soc {
+ qcom,mdss_dsi_nt35590_720p_video {
+ status = "ok";
+ qcom,cont-splash-enabled;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts b/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts
new file mode 100644
index 0000000..936f87f
--- /dev/null
+++ b/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts
@@ -0,0 +1,115 @@
+/* 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.
+ */
+
+/dts-v1/;
+/include/ "msm8226-v1.dtsi"
+/include/ "msm8226-qrd.dtsi"
+/include/ "dsi-panel-nt35590-720p-video.dtsi"
+
+/ {
+ model = "Qualcomm MSM 8226 QRD";
+ compatible = "qcom,msm8226-qrd", "qcom,msm8226", "qcom,qrd";
+ qcom,board-id = <11 2>;
+ qcom,msm-id = <145 0>,
+ <158 0>,
+ <159 0>,
+ <198 0>;
+};
+
+&soc {
+ qcom,mdss_dsi_nt35590_720p_video {
+ status = "ok";
+ qcom,mdss-pan-bl-ctrl = "bl_ctrl_dcs";
+ };
+
+ sound {
+ qcom,model = "msm8226-tapan-skuf-snd-card";
+
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "LDO_H", "MCLK",
+ "SPK_OUT", "MCLK",
+ "SPK_OUT", "EXT_VDD_SPKR",
+ "Lineout_1 amp", "LINEOUT1",
+ "Lineout_2 amp", "LINEOUT2",
+ "AMIC1", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Handset Mic",
+ "AMIC2", "MIC BIAS2 External",
+ "MIC BIAS2 External", "Headset Mic",
+ "AMIC3", "MIC BIAS1 External",
+ "MIC BIAS1 External", "ANCRight Headset Mic",
+ "AMIC4", "MIC BIAS2 External",
+ "MIC BIAS2 External", "ANCLeft Headset Mic";
+
+ qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
+ qcom,cdc-lineout-spkr-gpios = <&pm8226_gpios 2 0>;
+ qcom,cdc-vdd-spkr-gpios;
+ qcom,cdc-us-euro-gpios;
+ };
+};
+
+&spmi_bus {
+ qcom,pm8226@0 {
+ qcom,leds@a300 {
+ status = "disabled";
+ };
+
+ qcom,leds@a500 {
+ status = "disabled";
+ };
+ };
+};
+
+&pm8226_mpps {
+ mpp@a300 { /* MPP 4 */
+ /* camera2_id */
+ qcom,mode = <4>; /* AIN input */
+ qcom,invert = <1>; /* Enable MPP */
+ qcom,ain-route = <3>; /* AMUX 8 */
+ qcom,master-en = <1>;
+ qcom,src-sel = <0>; /* Function constant */
+ };
+
+ mpp@a500 { /* MPP 6 */
+ /* camera_id */
+ qcom,mode = <4>; /* AIN input */
+ qcom,invert = <1>; /* Enable MPP */
+ qcom,ain-route = <1>; /* AMUX 6 */
+ qcom,master-en = <1>;
+ qcom,src-sel = <0>; /* Function constant */
+ };
+
+};
+
+&pm8226_vadc {
+ chan@13 {
+ label = "camera2_id";
+ reg = <0x13>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@15 {
+ label = "camera_id";
+ reg = <0x15>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8226-v1.dtsi b/arch/arm/boot/dts/msm8226-v1.dtsi
index d471bec..2833673 100644
--- a/arch/arm/boot/dts/msm8226-v1.dtsi
+++ b/arch/arm/boot/dts/msm8226-v1.dtsi
@@ -17,3 +17,38 @@
*/
/include/ "msm8226.dtsi"
+
+&tsens {
+ qcom,sensors = <4>;
+ qcom,slope = <2901 2846 3038 2955>;
+};
+
+&gdsc_venus {
+ qcom,skip-logic-collapse;
+ qcom,retain-periph;
+ qcom,retain-mem;
+};
+
+&gdsc_mdss {
+ qcom,skip-logic-collapse;
+ qcom,retain-periph;
+ qcom,retain-mem;
+};
+
+&gdsc_jpeg {
+ qcom,skip-logic-collapse;
+ qcom,retain-periph;
+ qcom,retain-mem;
+};
+
+&gdsc_vfe {
+ qcom,skip-logic-collapse;
+ qcom,retain-periph;
+ qcom,retain-mem;
+};
+
+&gdsc_oxili_cx {
+ qcom,skip-logic-collapse;
+ qcom,retain-periph;
+ qcom,retain-mem;
+};
diff --git a/arch/arm/boot/dts/msm8226-v2-qrd.dts b/arch/arm/boot/dts/msm8226-v2-qrd-dvt.dts
similarity index 67%
copy from arch/arm/boot/dts/msm8226-v2-qrd.dts
copy to arch/arm/boot/dts/msm8226-v2-qrd-dvt.dts
index ad6d154..0a3148b 100644
--- a/arch/arm/boot/dts/msm8226-v2-qrd.dts
+++ b/arch/arm/boot/dts/msm8226-v2-qrd-dvt.dts
@@ -13,14 +13,21 @@
/dts-v1/;
/include/ "msm8226-v2.dtsi"
/include/ "msm8226-qrd.dtsi"
-/include/ "msm8226-camera-sensor-cdp.dtsi"
+/include/ "dsi-panel-hx8394a-720p-video.dtsi"
/ {
model = "Qualcomm MSM 8226v2 QRD";
compatible = "qcom,msm8226-qrd", "qcom,msm8226", "qcom,qrd";
- qcom,msm-id = <145 11 0x20000>,
- <158 11 0x20000>,
- <159 11 0x20000>,
- <198 11 0x20000>,
- <205 11 0x20000>;
+ qcom,msm-id = <145 0x2000b 0x20000>,
+ <158 0x2000b 0x20000>,
+ <159 0x2000b 0x20000>,
+ <198 0x2000b 0x20000>,
+ <205 0x2000b 0x20000>;
+};
+
+&soc {
+ qcom,mdss_dsi_hx8394a_720p_video {
+ status = "ok";
+ qcom,cont-splash-enabled;
+ };
};
diff --git a/arch/arm/boot/dts/msm8226-v2-qrd.dts b/arch/arm/boot/dts/msm8226-v2-qrd-evt.dts
similarity index 83%
rename from arch/arm/boot/dts/msm8226-v2-qrd.dts
rename to arch/arm/boot/dts/msm8226-v2-qrd-evt.dts
index ad6d154..a2ad682 100644
--- a/arch/arm/boot/dts/msm8226-v2-qrd.dts
+++ b/arch/arm/boot/dts/msm8226-v2-qrd-evt.dts
@@ -14,6 +14,7 @@
/include/ "msm8226-v2.dtsi"
/include/ "msm8226-qrd.dtsi"
/include/ "msm8226-camera-sensor-cdp.dtsi"
+/include/ "dsi-panel-nt35590-720p-video.dtsi"
/ {
model = "Qualcomm MSM 8226v2 QRD";
@@ -24,3 +25,10 @@
<198 11 0x20000>,
<205 11 0x20000>;
};
+
+&soc {
+ qcom,mdss_dsi_nt35590_720p_video {
+ status = "ok";
+ qcom,cont-splash-enabled;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts b/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts
new file mode 100644
index 0000000..b34fb94
--- /dev/null
+++ b/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts
@@ -0,0 +1,116 @@
+/* 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.
+ */
+
+/dts-v1/;
+/include/ "msm8226-v2.dtsi"
+/include/ "msm8226-qrd.dtsi"
+/include/ "dsi-panel-nt35590-720p-video.dtsi"
+
+/ {
+ model = "Qualcomm MSM 8226v2 QRD";
+ compatible = "qcom,msm8226-qrd", "qcom,msm8226", "qcom,qrd";
+ qcom,board-id = <0xb 0x2>;
+ qcom,msm-id = <145 0x20000>,
+ <158 0x20000>,
+ <159 0x20000>,
+ <198 0x20000>,
+ <205 0x20000>;
+};
+
+&soc {
+ qcom,mdss_dsi_nt35590_720p_video {
+ status = "ok";
+ qcom,mdss-pan-bl-ctrl = "bl_ctrl_dcs";
+ };
+
+ sound {
+ qcom,model = "msm8226-tapan-skuf-snd-card";
+
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "LDO_H", "MCLK",
+ "SPK_OUT", "MCLK",
+ "SPK_OUT", "EXT_VDD_SPKR",
+ "Lineout_1 amp", "LINEOUT1",
+ "Lineout_2 amp", "LINEOUT2",
+ "AMIC1", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Handset Mic",
+ "AMIC2", "MIC BIAS2 External",
+ "MIC BIAS2 External", "Headset Mic",
+ "AMIC3", "MIC BIAS1 External",
+ "MIC BIAS1 External", "ANCRight Headset Mic",
+ "AMIC4", "MIC BIAS2 External",
+ "MIC BIAS2 External", "ANCLeft Headset Mic";
+
+ qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
+ qcom,cdc-lineout-spkr-gpios = <&pm8226_gpios 2 0>;
+ qcom,cdc-vdd-spkr-gpios;
+ qcom,cdc-us-euro-gpios;
+ };
+};
+
+&spmi_bus {
+ qcom,pm8226@0 {
+ qcom,leds@a300 {
+ status = "disabled";
+ };
+
+ qcom,leds@a500 {
+ status = "disabled";
+ };
+ };
+};
+
+&pm8226_mpps {
+ mpp@a300 { /* MPP 4 */
+ /* camera2_id */
+ qcom,mode = <4>; /* AIN input */
+ qcom,invert = <1>; /* Enable MPP */
+ qcom,ain-route = <3>; /* AMUX 8 */
+ qcom,master-en = <1>;
+ qcom,src-sel = <0>; /* Function constant */
+ };
+
+ mpp@a500 { /* MPP 6 */
+ /* camera_id */
+ qcom,mode = <4>; /* AIN input */
+ qcom,invert = <1>; /* Enable MPP */
+ qcom,ain-route = <1>; /* AMUX 6 */
+ qcom,master-en = <1>;
+ qcom,src-sel = <0>; /* Function constant */
+ };
+
+};
+
+&pm8226_vadc {
+ chan@13 {
+ label = "camera2_id";
+ reg = <0x13>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@15 {
+ label = "camera_id";
+ reg = <0x15>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8226-v2.dtsi b/arch/arm/boot/dts/msm8226-v2.dtsi
index 2148e1d..1dab78a 100644
--- a/arch/arm/boot/dts/msm8226-v2.dtsi
+++ b/arch/arm/boot/dts/msm8226-v2.dtsi
@@ -42,9 +42,9 @@
&apc_vreg_corner {
qcom,pvs-bin-process = <1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2
2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3>;
- qcom,pvs-corner-ceiling-slow = <1160000 1160000 1280000>;
- qcom,pvs-corner-ceiling-nom = <980000 1080000 1200000>;
- qcom,pvs-corner-ceiling-fast = <900000 1000000 1140000>;
+ qcom,pvs-corner-ceiling-slow = <1050000 1160000 1280000>;
+ qcom,pvs-corner-ceiling-nom = <1050000 1080000 1200000>;
+ qcom,pvs-corner-ceiling-fast = <1050000 1050000 1140000>;
qcom,cpr-step-quotient = <30>;
qcom,cpr-up-threshold = <0>;
qcom,cpr-down-threshold = <5>;
@@ -63,3 +63,8 @@
reg-names = "rcg_base", "pte_efuse";
};
};
+
+&tsens {
+ qcom,sensors = <6>;
+ qcom,slope = <2901 2846 3038 2955 2901 2846>;
+};
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index c151948..b836100 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -21,6 +21,7 @@
spi0 = &spi_0;
sdhc1 = &sdhc_1; /* SDC1 eMMC slot */
sdhc2 = &sdhc_2; /* SDC2 SD card slot */
+ sdhc3 = &sdhc_3; /* SDC3 SDIO slot */
};
memory {
@@ -266,11 +267,12 @@
qcom,dp-manual-pullup;
qcom,msm-bus,name = "usb";
- qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-cases = <3>;
qcom,msm-bus,num-paths = <1>;
qcom,msm-bus,vectors-KBps =
<87 512 0 0>,
- <87 512 60000 960000>;
+ <87 512 60000 960000>,
+ <87 512 6000 6000>;
};
android_usb@fe8050c8 {
@@ -308,7 +310,7 @@
qcom,cdc-reset-gpio = <&msmgpio 72 0>;
cdc-vdd-buck-supply = <&pm8226_s4>;
- qcom,cdc-vdd-buck-voltage = <2100000 2100000>;
+ qcom,cdc-vdd-buck-voltage = <1800000 2150000>;
qcom,cdc-vdd-buck-current = <650000>;
cdc-vdd-h-supply = <&pm8226_l6>;
@@ -508,15 +510,19 @@
compatible = "qcom,msm-dai-q6-dev";
qcom,msm-dai-q6-dev-id = <32773>;
};
+
+ qcom,msm-dai-q6-incall-music-2-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32770>;
+ };
};
qcom,msm-pcm-hostless {
compatible = "qcom,msm-pcm-hostless";
};
- qcom,msm-auxpcm {
- compatible = "qcom,msm-auxpcm-resource";
- qcom,msm-cpudai-auxpcm-clk = "pcm_clk";
+ qcom,msm-pri-auxpcm {
+ compatible = "qcom,msm-auxpcm-dev";
qcom,msm-cpudai-auxpcm-mode = <0>, <0>;
qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
@@ -524,16 +530,7 @@
qcom,msm-cpudai-auxpcm-slot = <1>, <1>;
qcom,msm-cpudai-auxpcm-data = <0>, <0>;
qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
-
- qcom,msm-prim-auxpcm-rx {
- qcom,msm-auxpcm-dev-id = <4106>;
- compatible = "qcom,msm-auxpcm-dev";
- };
-
- qcom,msm-prim-auxpcm-tx {
- qcom,msm-auxpcm-dev-id = <4107>;
- compatible = "qcom,msm-auxpcm-dev";
- };
+ qcom,msm-auxpcm-interface = "primary";
};
qcom,wcnss-wlan@fb000000 {
@@ -664,6 +661,21 @@
interrupt-names = "core_irq", "bam_irq";
qcom,bus-width = <8>;
+
+ qcom,msm-bus,name = "sdcc1";
+ qcom,msm-bus,num-cases = <8>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps = <78 512 0 0>, /* No vote */
+ <78 512 1600 3200>, /* 400 KB/s*/
+ <78 512 80000 160000>, /* 20 MB/s */
+ <78 512 100000 200000>, /* 25 MB/s */
+ <78 512 200000 400000>, /* 50 MB/s */
+ <78 512 400000 800000>, /* 100 MB/s */
+ <78 512 400000 800000>, /* 200 MB/s */
+ <78 512 2048000 4096000>; /* Max. bandwidth */
+ qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000
+ 100000000 200000000 4294967295>;
+
status = "disabled";
};
@@ -676,6 +688,21 @@
interrupt-names = "hc_irq", "pwr_irq";
qcom,bus-width = <8>;
+
+ qcom,msm-bus,name = "sdhc1";
+ qcom,msm-bus,num-cases = <8>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps = <78 512 0 0>, /* No vote */
+ <78 512 1600 3200>, /* 400 KB/s*/
+ <78 512 80000 160000>, /* 20 MB/s */
+ <78 512 100000 200000>, /* 25 MB/s */
+ <78 512 200000 400000>, /* 50 MB/s */
+ <78 512 400000 800000>, /* 100 MB/s */
+ <78 512 400000 800000>, /* 200 MB/s */
+ <78 512 2048000 4096000>; /* Max. bandwidth */
+ qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000
+ 100000000 200000000 4294967295>;
+
status = "disabled";
};
@@ -691,6 +718,21 @@
interrupt-names = "core_irq", "bam_irq";
qcom,bus-width = <4>;
+
+ qcom,msm-bus,name = "sdcc2";
+ qcom,msm-bus,num-cases = <8>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps = <81 512 0 0>, /* No vote */
+ <81 512 1600 3200>, /* 400 KB/s*/
+ <81 512 80000 160000>, /* 20 MB/s */
+ <81 512 100000 200000>, /* 25 MB/s */
+ <81 512 200000 400000>, /* 50 MB/s */
+ <81 512 400000 800000>, /* 100 MB/s */
+ <81 512 400000 800000>, /* 200 MB/s */
+ <81 512 2048000 4096000>; /* Max. bandwidth */
+ qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000
+ 100000000 200000000 4294967295>;
+
status = "disabled";
};
@@ -703,6 +745,110 @@
interrupt-names = "hc_irq", "pwr_irq";
qcom,bus-width = <4>;
+
+ qcom,msm-bus,name = "sdhc2";
+ qcom,msm-bus,num-cases = <8>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps = <81 512 0 0>, /* No vote */
+ <81 512 1600 3200>, /* 400 KB/s*/
+ <81 512 80000 160000>, /* 20 MB/s */
+ <81 512 100000 200000>, /* 25 MB/s */
+ <81 512 200000 400000>, /* 50 MB/s */
+ <81 512 400000 800000>, /* 100 MB/s */
+ <81 512 400000 800000>, /* 200 MB/s */
+ <81 512 2048000 4096000>; /* Max. bandwidth */
+ qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000
+ 100000000 200000000 4294967295>;
+
+ status = "disabled";
+ };
+
+ sdcc3: qcom,sdcc@f9864000 {
+ cell-index = <3>;
+ compatible = "qcom,msm-sdcc";
+ reg = <0xf9864000 0x800>,
+ <0xf9864800 0x100>,
+ <0xf9844000 0x7000>;
+ reg-names = "core_mem", "dml_mem", "bam_mem";
+
+ qcom,bus-width = <4>;
+ gpios = <&msmgpio 44 0>, /* CLK */
+ <&msmgpio 43 0>, /* CMD */
+ <&msmgpio 42 0>, /* DATA0 */
+ <&msmgpio 41 0>, /* DATA1 */
+ <&msmgpio 40 0>, /* DATA2 */
+ <&msmgpio 39 0>; /* DATA3 */
+ qcom,gpio-names = "CLK", "CMD", "DAT0", "DAT1", "DAT2", "DAT3";
+
+ qcom,clk-rates = <400000 20000000 25000000 50000000 100000000>;
+
+ qcom,msm-bus,name = "sdcc3";
+ qcom,msm-bus,num-cases = <8>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps = <79 512 0 0>, /* No vote */
+ <79 512 1600 3200>, /* 400 KB/s*/
+ <79 512 80000 160000>, /* 20 MB/s */
+ <79 512 100000 200000>, /* 25 MB/s */
+ <79 512 200000 400000>, /* 50 MB/s */
+ <79 512 400000 800000>, /* 100 MB/s */
+ <79 512 400000 800000>, /* 200 MB/s */
+ <79 512 2048000 4096000>; /* Max. bandwidth */
+ qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000
+ 100000000 200000000 4294967295>;
+
+ #address-cells = <0>;
+ interrupt-parent = <&sdcc3>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 127 0
+ 1 &intc 0 223 0
+ 2 &msmgpio 41 0x8>;
+ interrupt-names = "core_irq", "bam_irq", "sdiowakeup_irq";
+
+ status = "disabled";
+ };
+
+ sdhc_3: sdhci@f9864900 {
+ compatible = "qcom,sdhci-msm";
+ reg = <0xf9864900 0x11c>, <0xf9864000 0x800>;
+ reg-names = "hc_mem", "core_mem";
+
+ qcom,bus-width = <4>;
+ gpios = <&msmgpio 44 0>, /* CLK */
+ <&msmgpio 43 0>, /* CMD */
+ <&msmgpio 42 0>, /* DATA0 */
+ <&msmgpio 41 0>, /* DATA1 */
+ <&msmgpio 40 0>, /* DATA2 */
+ <&msmgpio 39 0>; /* DATA3 */
+ qcom,gpio-names = "CLK", "CMD", "DAT0", "DAT1", "DAT2", "DAT3";
+
+ qcom,clk-rates = <400000 20000000 25000000 50000000 100000000>;
+
+ qcom,msm-bus,name = "sdhc3";
+ qcom,msm-bus,num-cases = <8>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps = <79 512 0 0>, /* No vote */
+ <79 512 1600 3200>, /* 400 KB/s*/
+ <79 512 80000 160000>, /* 20 MB/s */
+ <79 512 100000 200000>, /* 25 MB/s */
+ <79 512 200000 400000>, /* 50 MB/s */
+ <79 512 400000 800000>, /* 100 MB/s */
+ <79 512 400000 800000>, /* 200 MB/s */
+ <79 512 2048000 4096000>; /* Max. bandwidth */
+ qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000
+ 100000000 200000000 4294967295>;
+
+ #address-cells = <0>;
+ interrupt-parent = <&sdhc_3>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 127 0
+ 1 &intc 0 224 0
+ 2 &msmgpio 41 0x8>;
+ interrupt-names = "hc_irq", "pwr_irq", "sdiowakeup_irq";
+
status = "disabled";
};
@@ -879,7 +1025,7 @@
tsens: tsens@fc4a8000 {
compatible = "qcom,msm-tsens";
reg = <0xfc4a8000 0x2000>,
- <0xfc4b8000 0x1000>;
+ <0xfc4bc000 0x1000>;
reg-names = "tsens_physical", "tsens_eeprom_physical";
interrupts = <0 184 0>;
qcom,sensors = <4>;
@@ -895,6 +1041,24 @@
qcom,temp-hysteresis = <10>;
qcom,freq-step = <2>;
qcom,freq-control-mask = <0xf>;
+ qcom,core-limit-temp = <80>;
+ qcom,core-temp-hysteresis = <10>;
+ qcom,core-control-mask = <0xe>;
+ qcom,vdd-restriction-temp = <5>;
+ qcom,vdd-restriction-temp-hysteresis = <10>;
+ vdd-dig-supply = <&pm8226_s1_floor_corner>;
+
+ qcom,vdd-dig-rstr{
+ qcom,vdd-rstr-reg = "vdd-dig";
+ qcom,levels = <5 7 7>; /* Nominal, Super Turbo, Super Turbo */
+ qcom,min-level = <1>; /* No Request */
+ };
+
+ qcom,vdd-apps-rstr{
+ qcom,vdd-rstr-reg = "vdd-apps";
+ qcom,levels = <600000 787200 998400>;
+ qcom,freq-req;
+ };
};
spi_0: spi@f9923000 { /* BLSP1 QUP1 */
@@ -949,6 +1113,12 @@
reg = <0x0fe805720 0x1000>;
};
+ jtag_fuse: jtagfuse@fc4be024 {
+ compatible = "qcom,jtag-fuse";
+ reg = <0xfc4be024 0x8>;
+ reg-names = "fuse-base";
+ };
+
jtag_mm0: jtagmm@fc33c000 {
compatible = "qcom,jtag-mm";
reg = <0xfc33c000 0x1000>,
diff --git a/arch/arm/boot/dts/msm8610-bus.dtsi b/arch/arm/boot/dts/msm8610-bus.dtsi
index d9bb6ab..cef04ef 100644
--- a/arch/arm/boot/dts/msm8610-bus.dtsi
+++ b/arch/arm/boot/dts/msm8610-bus.dtsi
@@ -934,9 +934,9 @@
qcom,qport = <0>;
qcom,ws = <10000>;
qcom,mas-hw-id = <0>;
- qcom,prio-rd = <1>;
- qcom,prio-wr = <1>;
- qcom,prio-lvl = <1>;
+ qcom,prio-rd = <0>;
+ qcom,prio-wr = <0>;
+ qcom,prio-lvl = <0>;
};
mas-mss-proc {
diff --git a/arch/arm/boot/dts/msm8610-cdp.dts b/arch/arm/boot/dts/msm8610-cdp.dts
index 6891b90..b0c0191 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dts
+++ b/arch/arm/boot/dts/msm8610-cdp.dts
@@ -42,6 +42,7 @@
atmel,display-coords = <0 0 480 800>;
atmel,i2c-pull-up;
atmel,no-force-update;
+ atmel,no-lpm-support;
atmel,cfg_1 {
atmel,family-id = <0x81>;
atmel,variant-id = <0x15>;
@@ -149,12 +150,12 @@
compatible = "qcom,msm8x10-wcd-i2c";
reg = <0x0d>;
cdc-vdda-cp-supply = <&pm8110_s4>;
- qcom,cdc-vdda-cp-voltage = <2150000 2150000>;
+ qcom,cdc-vdda-cp-voltage = <1800000 2150000>;
qcom,cdc-vdda-cp-current = <650000>;
cdc-vdda-h-supply = <&pm8110_l6>;
qcom,cdc-vdda-h-voltage = <1800000 1800000>;
- qcom,cdc-vdda-h-current = <250000>;
+ qcom,cdc-vdda-h-current = <25000>;
cdc-vdd-px-supply = <&pm8110_l6>;
qcom,cdc-vdd-px-voltage = <1800000 1800000>;
@@ -171,6 +172,13 @@
qcom,cdc-micbias-cfilt-sel = <0x0>;
qcom,cdc-micbias-cfilt-mv = <1800000>;
qcom,cdc-mclk-clk-rate = <12288000>;
+
+ qcom,cdc-static-supplies = "cdc-vdda-h",
+ "cdc-vdd-px",
+ "cdc-vdd-1p2v";
+
+ qcom,cdc-on-demand-supplies = "cdc-vdda-cp",
+ "cdc-vdd-mic-bias";
};
msm8x10_wcd_codec@77{
@@ -215,9 +223,13 @@
qcom,default-state = "on";
qcom,max-current = <40>;
qcom,id = <6>;
- qcom,source-sel = <1>;
+ qcom,source-sel = <8>;
qcom,mode-ctrl = <0x10>;
- qcom,mode = "manual";
+ qcom,pwm-channel = <0>;
+ qcom,pwm-us = <14>;
+ qcom,vin-ctrl = <0x03>;
+ qcom,mode = "pwm";
+ qcom,min-brightness = <19>;
};
};
};
@@ -235,8 +247,6 @@
&sdhc_1 {
vdd-supply = <&pm8110_l17>;
- qcom,vdd-always-on;
- qcom,vdd-lpm-sup;
qcom,vdd-voltage-level = <2900000 2900000>;
qcom,vdd-current-level = <200 400000>;
diff --git a/arch/arm/boot/dts/msm8610-coresight.dtsi b/arch/arm/boot/dts/msm8610-coresight.dtsi
index 516522e..2041bf6 100644
--- a/arch/arm/boot/dts/msm8610-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8610-coresight.dtsi
@@ -345,8 +345,9 @@
compatible = "qcom,coresight-hwevent";
reg = <0xfd820018 0x80>,
<0xf9011080 0x80>,
- <0xfd4ab160 0x80>;
- reg-names = "mmss-mux", "apcs-mux", "ppss-mux";
+ <0xfd4ab160 0x80>,
+ <0xfc401600 0x80>;
+ reg-names = "mmss-mux", "apcs-mux", "ppss-mux", "gcc-mux";
coresight-id = <27>;
coresight-name = "coresight-hwevent";
@@ -354,4 +355,14 @@
qcom,hwevent-clks = "core_mmss_clk";
};
+
+ fuse: fuse@fc4be024 {
+ compatible = "arm,coresight-fuse";
+ reg = <0xfc4be024 0x8>;
+ reg-names = "fuse-base";
+
+ coresight-id = <28>;
+ coresight-name = "coresight-fuse";
+ coresight-nr-inports = <0>;
+ };
};
diff --git a/arch/arm/boot/dts/msm8610-mtp.dts b/arch/arm/boot/dts/msm8610-mtp.dts
index ddbe3a0..221ace4 100644
--- a/arch/arm/boot/dts/msm8610-mtp.dts
+++ b/arch/arm/boot/dts/msm8610-mtp.dts
@@ -42,6 +42,7 @@
atmel,display-coords = <0 0 480 800>;
atmel,i2c-pull-up;
atmel,no-force-update;
+ atmel,no-lpm-support;
atmel,cfg_1 {
atmel,family-id = <0x81>;
atmel,variant-id = <0x15>;
@@ -90,6 +91,44 @@
};
};
+ i2c@f9925000 {
+ mpu3050@68 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "okay";
+ reg = <0x68>;
+ compatible = "invn,mpu3050";
+ interrupt-parent = <&msmgpio>;
+ interrupts = <84 0x2>;
+ vlogic-supply = <&pm8110_l14>;
+ vdd-supply = <&pm8110_l19>;
+ invn,gpio-int = <&msmgpio 84 0x2>;
+ invn,gpio-en = <&pm8110_gpios 2 0x2>;
+ invn,poll-interval = <200>;
+ };
+
+ bmp180@77 {
+ reg = <0x77>;
+ compatible = "bosch,bmp18x";
+ vdd-supply = <&pm8110_l19>;
+ vddio-supply = <&pm8110_l14>;
+ bosch,chip-id = <0x55>;
+ bosch,oversample = <3>;
+ bosch,period = <1000>;
+ };
+
+ mma8x5x@1d {
+ reg = <0x1d>;
+ compatible = "fsl,mma8x5x";
+ interrupt-parent = <&msmgpio>;
+ interrupts = <81 0x2>;
+ vdd-supply = <&pm8110_l19>;
+ vio-supply = <&pm8110_l14>;
+ fsl,irq-gpio = <&msmgpio 81 0x00>;
+ fsl,sensors-position = <5>;
+ };
+ };
+
gen-vkeys {
compatible = "qcom,gen-vkeys";
label = "atmel_mxt_ts";
@@ -149,12 +188,12 @@
compatible = "qcom,msm8x10-wcd-i2c";
reg = <0x0d>;
cdc-vdda-cp-supply = <&pm8110_s4>;
- qcom,cdc-vdda-cp-voltage = <2150000 2150000>;
+ qcom,cdc-vdda-cp-voltage = <1800000 2150000>;
qcom,cdc-vdda-cp-current = <650000>;
cdc-vdda-h-supply = <&pm8110_l6>;
qcom,cdc-vdda-h-voltage = <1800000 1800000>;
- qcom,cdc-vdda-h-current = <250000>;
+ qcom,cdc-vdda-h-current = <25000>;
cdc-vdd-px-supply = <&pm8110_l6>;
qcom,cdc-vdd-px-voltage = <1800000 1800000>;
@@ -171,6 +210,13 @@
qcom,cdc-micbias-cfilt-sel = <0x0>;
qcom,cdc-micbias-cfilt-mv = <1800000>;
qcom,cdc-mclk-clk-rate = <12288000>;
+
+ qcom,cdc-static-supplies = "cdc-vdda-h",
+ "cdc-vdd-px",
+ "cdc-vdd-1p2v";
+
+ qcom,cdc-on-demand-supplies = "cdc-vdda-cp",
+ "cdc-vdd-mic-bias";
};
msm8x10_wcd_codec@77{
@@ -215,9 +261,13 @@
qcom,default-state = "on";
qcom,max-current = <40>;
qcom,id = <6>;
- qcom,source-sel = <1>;
+ qcom,source-sel = <8>;
qcom,mode-ctrl = <0x10>;
- qcom,mode = "manual";
+ qcom,pwm-channel = <0>;
+ qcom,pwm-us = <14>;
+ qcom,vin-ctrl = <0x03>;
+ qcom,mode = "pwm";
+ qcom,min-brightness = <19>;
};
};
};
@@ -235,8 +285,6 @@
&sdhc_1 {
vdd-supply = <&pm8110_l17>;
- qcom,vdd-always-on;
- qcom,vdd-lpm-sup;
qcom,vdd-voltage-level = <2900000 2900000>;
qcom,vdd-current-level = <200 400000>;
diff --git a/arch/arm/boot/dts/msm8610-pm.dtsi b/arch/arm/boot/dts/msm8610-pm.dtsi
index c48eaf7..d31a65c 100644
--- a/arch/arm/boot/dts/msm8610-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-pm.dtsi
@@ -20,12 +20,12 @@
qcom,saw2-ver-reg = <0xfd0>;
qcom,saw2-cfg = <0x00>;
qcom,saw2-spm-dly= <0x3c102800>;
- qcom,saw2-spm-ctl = <0x0>;
+ 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 07 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 07 60 3b 76 76
+ 0b 94 5b 80 10 26 30 0f];
};
qcom,spm@f9099000 {
@@ -37,13 +37,13 @@
qcom,saw2-ver-reg = <0xfd0>;
qcom,saw2-cfg = <0x00>;
qcom,saw2-spm-dly= <0x3c102800>;
- qcom,saw2-spm-ctl = <0x0>;
+ 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 07 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 07 60 3b 76 76
+ 0b 94 5b 80 10 26 30 0f];
+ };
qcom,spm@f90a9000 {
compatible = "qcom,spm-v2";
@@ -54,7 +54,7 @@
qcom,saw2-ver-reg = <0xfd0>;
qcom,saw2-cfg = <0x00>;
qcom,saw2-spm-dly= <0x3c102800>;
- qcom,saw2-spm-ctl = <0x0>;
+ 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];
@@ -71,12 +71,12 @@
qcom,saw2-ver-reg = <0xfd0>;
qcom,saw2-cfg = <0x00>;
qcom,saw2-spm-dly= <0x3c102800>;
- qcom,saw2-spm-ctl = <0x0>;
+ 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 07 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 07 60 3b 76 76
+ 0b 94 5b 80 10 26 30 0f];
};
qcom,spm@f9012000 {
@@ -95,68 +95,22 @@
qcom,vctl-port = <0x0>;
qcom,phase-port = <0x1>;
qcom,pfm-port = <0x2>;
- qcom,saw2-spm-cmd-ret = [00 03 00 7b 0f];
+ qcom,saw2-spm-cmd-ret = [00 03 00 0f];
qcom,saw2-spm-cmd-pc = [00 32 b0 10 e0 d0 6b c0 42 f0
- 11 07 01 b0 4e c0 d0 12 e0 6b 50 02 32
- 50 f0 7b 0f]; /*APCS_PMIC_OFF_L2RAM_OFF*/
- };
-
- qcom,lpm-resources {
- compatible = "qcom,lpm-resources";
- #address-cells = <1>;
- #size-cells = <0>;
-
- qcom,lpm-resources@0 {
- reg = <0x0>;
- qcom,name = "vdd-dig";
- qcom,type = <0x61706d73>; /* "smpa" */
- qcom,id = <0x01>;
- qcom,key = <0x6e726f63>; /* "corn" */
- qcom,init-value = <3>; /* SVS SOC */
- };
-
- qcom,lpm-resources@1 {
- reg = <0x1>;
- qcom,name = "vdd-mem";
- qcom,type = <0x616F646C>; /* "ldoa" */
- qcom,id = <0x03>;
- qcom,key = <0x6e726f63>; /* "corn" */
- qcom,init-value = <3>; /* SVS SOC */
- };
-
- qcom,lpm-resources@2 {
- reg = <0x2>;
- qcom,name = "pxo";
- qcom,type = <0x306b6c63>; /* "clk0" */
- qcom,id = <0x00>;
- qcom,key = <0x62616e45>; /* "Enab" */
- qcom,init-value = "xo_on";
- };
-
- qcom,lpm-resources@3 {
- reg = <0x3>;
- qcom,name = "l2";
- qcom,local-resource-type;
- qcom,init-value = "l2_cache_retention";
- };
+ 11 07 01 b0 50 4e 02 02 c0 d0 12 e0 6b 02 32
+ 50 f0 0f]; /*APCS_PMIC_OFF_L2RAM_OFF*/
};
qcom,lpm-levels {
compatible = "qcom,lpm-levels";
+ qcom,default-l2-state = "l2_cache_active";
#address-cells = <1>;
#size-cells = <0>;
qcom,lpm-level@0 {
reg = <0x0>;
qcom,mode = "wfi";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_active";
- qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
qcom,latency-us = <1>;
qcom,ss-power = <784>;
qcom,energy-overhead = <190000>;
@@ -166,14 +120,7 @@
qcom,lpm-level@1 {
reg = <0x1>;
qcom,mode = "standalone_pc";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_active";
- qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
qcom,latency-us = <3000>;
qcom,ss-power = <725>;
qcom,energy-overhead = <99500>;
@@ -183,15 +130,8 @@
qcom,lpm-level@2 {
reg = <0x2>;
qcom,mode = "pc";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_retention";
- qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
- qcom,latency-us = <8000>;
+ qcom,latency-us = <20000>;
qcom,ss-power = <138>;
qcom,energy-overhead = <1208400>;
qcom,time-overhead = <9200>;
@@ -200,64 +140,12 @@
qcom,lpm-level@3 {
reg = <0x3>;
qcom,mode = "pc";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <4>; /* NORMAL */
- qcom,vdd-mem-lower-bound = <3>; /* SVS SOC */
- qcom,vdd-dig-upper-bound = <4>; /* NORMAL */
- qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
- qcom,latency-us = <9000>;
+ qcom,latency-us = <30000>;
qcom,ss-power = <110>;
qcom,energy-overhead = <1250300>;
qcom,time-overhead = <9500>;
};
-
- qcom,lpm-level@4 {
- reg = <0x4>;
- qcom,mode = "pc";
- qcom,xo = "xo_off";
- qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,latency-us = <16300>;
- qcom,ss-power = <63>;
- qcom,energy-overhead = <2128000>;
- qcom,time-overhead = <24200>;
- };
-
- qcom,lpm-level@5 {
- reg = <0x5>;
- qcom,mode = "pc";
- qcom,xo = "xo_off";
- qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <4>; /* NORMAL */
- qcom,vdd-mem-lower-bound = <3>; /* SVS SOC */
- qcom,vdd-dig-upper-bound = <4>; /* NORMAL */
- qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
- qcom,latency-us = <24000>;
- qcom,ss-power = <10>;
- qcom,energy-overhead = <3202600>;
- qcom,time-overhead = <33000>;
- };
-
- qcom,lpm-level@6 {
- reg = <0x6>;
- qcom,mode = "pc";
- qcom,xo = "xo_off";
- qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <3>; /* SVS SOC */
- qcom,vdd-mem-lower-bound = <1>; /* RETENTION */
- qcom,vdd-dig-upper-bound = <3>; /* SVS SOC */
- qcom,vdd-dig-lower-bound = <1>; /* RETENTION */
- qcom,latency-us = <26000>;
- qcom,ss-power = <2>;
- qcom,energy-overhead = <4252000>;
- qcom,time-overhead = <38000>;
- };
};
qcom,pm-boot {
diff --git a/arch/arm/boot/dts/msm8610-qrd-skuaa.dts b/arch/arm/boot/dts/msm8610-qrd-skuaa.dts
new file mode 100644
index 0000000..aeaf8ca
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-qrd-skuaa.dts
@@ -0,0 +1,47 @@
+/* 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.
+ */
+
+/dts-v1/;
+
+/include/ "msm8610-qrd.dtsi"
+/include/ "dsi-v2-panel-hx8379a-wvga-video.dtsi"
+/include/ "msm8610-qrd-camera-sensor.dtsi"
+
+/ {
+ model = "Qualcomm MSM 8610 QRD";
+ compatible = "qcom,msm8610-qrd", "qcom,msm8610", "qcom,qrd";
+ qcom,board-id = <11 1>, <11 0>;
+ qcom,msm-id = <147 0>, <165 0>, <161 0>, <162 0>,
+ <163 0>, <164 0>, <166 0>;
+};
+
+&soc {
+ sound {
+ qcom,model = "msm8x10-skuaa-snd-card";
+
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "INT_LDO_H", "MCLK",
+ "Lineout amp", "LINEOUT",
+ "MIC BIAS Internal1", "Handset Mic",
+ "MIC BIAS Internal2", "Headset Mic",
+ "AMIC1", "MIC BIAS Internal1",
+ "AMIC2", "MIC BIAS Internal2";
+
+ qcom,ext-spk-amp-gpio = <&msmgpio 92 0x0>;
+ };
+};
+
+&pm8110_bms {
+ status = "ok";
+ qcom,batt-type = <5>;
+};
diff --git a/arch/arm/boot/dts/msm8610-qrd-skuab.dts b/arch/arm/boot/dts/msm8610-qrd-skuab.dts
new file mode 100644
index 0000000..c435038
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-qrd-skuab.dts
@@ -0,0 +1,86 @@
+/* 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.
+ */
+
+/dts-v1/;
+
+/include/ "msm8610-qrd.dtsi"
+/include/ "dsi-v2-panel-otm8018b-fwvga-video.dtsi"
+/include/ "msm8612-qrd-camera-sensor.dtsi"
+
+/ {
+ model = "Qualcomm MSM 8610 QRD";
+ compatible = "qcom,msm8610-qrd", "qcom,msm8610", "qcom,qrd";
+ qcom,board-id = <11 3>;
+ qcom,msm-id = <147 0>, <165 0>, <161 0>, <162 0>,
+ <163 0>, <164 0>, <166 0>;
+};
+
+&soc {
+ sound {
+ qcom,model = "msm8x10-skuab-snd-card";
+
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "INT_LDO_H", "MCLK",
+ "Lineout amp", "LINEOUT",
+ "MIC BIAS Internal1", "Handset Mic",
+ "MIC BIAS Internal2", "Headset Mic",
+ "AMIC1", "MIC BIAS Internal1",
+ "AMIC2", "MIC BIAS Internal2";
+
+ qcom,ext-spk-amp-gpio = <&msmgpio 92 0x0>;
+ };
+ i2c@f9923000{
+ focaltech@38{
+ compatible = "focaltech,5x06";
+ reg = <0x38>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <1 0x2>;
+ vdd-supply = <&pm8110_l19>;
+ vcc_i2c-supply = <&pm8110_l14>;
+ focaltech,family-id = <0x06>;
+ focaltech,reset-gpio = <&msmgpio 0 0x00>;
+ focaltech,irq-gpio = <&msmgpio 1 0x00>;
+ focaltech,display-coords = <0 0 480 854>;
+ focaltech,panel-coords = <0 0 480 946>;
+ focaltech,button-map= <139 102 158>;
+ focaltech,no-force-update;
+ focaltech,i2c-pull-up;
+ };
+ };
+ gen-vkeys {
+ compatible = "qcom,gen-vkeys";
+ label = "ft5x06_ts";
+ qcom,disp-maxx = <480>;
+ qcom,disp-maxy = <854>;
+ qcom,panel-maxx = <481>;
+ qcom,panel-maxy = <946>;
+ qcom,key-codes = <139 102 158>;
+ qcom,y-offset = <0>;
+ };
+ i2c@f9925000 {
+ fsl@1c {
+ compatible = "fsl,mma8x5x";
+ reg = <0x1c>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <81 0x2>;
+ vdd-supply = <&pm8110_l19>;
+ vio-supply = <&pm8110_l14>;
+ fsl,irq-gpio = <&msmgpio 81 0x00>;
+ fsl,sensors-position = <5>;
+ };
+ };
+
+ qcom,dsi_v2_otm8018b_fwvga_video {
+ status = "ok";
+ };
+};
diff --git a/arch/arm/boot/dts/msm8610-qrd.dts b/arch/arm/boot/dts/msm8610-qrd.dtsi
similarity index 74%
rename from arch/arm/boot/dts/msm8610-qrd.dts
rename to arch/arm/boot/dts/msm8610-qrd.dtsi
index 4a2c57c..ea47d45 100644
--- a/arch/arm/boot/dts/msm8610-qrd.dts
+++ b/arch/arm/boot/dts/msm8610-qrd.dtsi
@@ -10,18 +10,23 @@
* GNU General Public License for more details.
*/
-/dts-v1/;
+/* This is a QRD reference design common file. The common device
+ * tree approach would help OEM during development of their extended
+ * device tree. Each new QRD OEM target can select its own include
+ * files and provide board specific overrides in the top level DTS
+ * file.
+ *
+ * For example:
+ * msm8xxx-qrd.dtsi: QRD reference common node
+ * msm8xxx-qrd-skuxx.dts:
+ * /include/ "msm8610-qrd.dtsi"
+ * / {
+ * List skuxx specific node which is different with QRD
+ * reference design.
+ * };
+ */
/include/ "msm8610.dtsi"
-/include/ "dsi-v2-panel-hx8379a-wvga-video.dtsi"
-/include/ "msm8610-qrd-camera-sensor.dtsi"
-
-/ {
- model = "Qualcomm MSM 8610 QRD";
- compatible = "qcom,msm8610-qrd", "qcom,msm8610", "qcom,qrd";
- qcom,msm-id = <147 11 0>, <165 11 0>, <161 11 0>, <162 11 0>,
- <163 11 0>, <164 11 0>, <166 11 0>;
-};
&soc {
i2c@f9923000{
@@ -119,51 +124,6 @@
};
};
- i2c@f9927000 {
- msm8x10_wcd_codec@0d{
- compatible = "qcom,msm8x10-wcd-i2c";
- reg = <0x0d>;
- cdc-vdda-cp-supply = <&pm8110_s4>;
- qcom,cdc-vdda-cp-voltage = <2150000 2150000>;
- qcom,cdc-vdda-cp-current = <650000>;
-
- cdc-vdda-h-supply = <&pm8110_l6>;
- qcom,cdc-vdda-h-voltage = <1800000 1800000>;
- qcom,cdc-vdda-h-current = <250000>;
-
- cdc-vdd-px-supply = <&pm8110_l6>;
- qcom,cdc-vdd-px-voltage = <1800000 1800000>;
- qcom,cdc-vdd-px-current = <10000>;
-
- cdc-vdd-1p2v-supply = <&pm8110_l4>;
- qcom,cdc-vdd-1p2v-voltage = <1200000 1200000>;
- qcom,cdc-vdd-1p2v-current = <5000>;
-
- cdc-vdd-mic-bias-supply = <&pm8110_l20>;
- qcom,cdc-vdd-mic-bias-voltage = <3075000 3075000>;
- qcom,cdc-vdd-mic-bias-current = <25000>;
-
- qcom,cdc-micbias-cfilt-sel = <0x0>;
- qcom,cdc-micbias-cfilt-mv = <1800000>;
- qcom,cdc-mclk-clk-rate = <12288000>;
- };
-
- msm8x10_wcd_codec@77{
- compatible = "qcom,msm8x10-wcd-i2c";
- reg = <0x77>;
- };
-
- msm8x10_wcd_codec@66{
- compatible = "qcom,msm8x10-wcd-i2c";
- reg = <0x66>;
- };
-
- msm8x10_wcd_codec@55{
- compatible = "qcom,msm8x10-wcd-i2c";
- reg = <0x55>;
- };
- };
-
sound {
qcom,audio-routing =
"RX_BIAS", "MCLK",
@@ -175,6 +135,58 @@
};
};
+&i2c_cdc {
+ msm8x10_wcd_codec@0d{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x0d>;
+ cdc-vdda-cp-supply = <&pm8110_s4>;
+ qcom,cdc-vdda-cp-voltage = <1800000 2150000>;
+ qcom,cdc-vdda-cp-current = <650000>;
+
+ cdc-vdda-h-supply = <&pm8110_l6>;
+ qcom,cdc-vdda-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdda-h-current = <25000>;
+
+ cdc-vdd-px-supply = <&pm8110_l6>;
+ qcom,cdc-vdd-px-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-px-current = <10000>;
+
+ cdc-vdd-1p2v-supply = <&pm8110_l4>;
+ qcom,cdc-vdd-1p2v-voltage = <1200000 1200000>;
+ qcom,cdc-vdd-1p2v-current = <5000>;
+
+ cdc-vdd-mic-bias-supply = <&pm8110_l20>;
+ qcom,cdc-vdd-mic-bias-voltage = <3075000 3075000>;
+ qcom,cdc-vdd-mic-bias-current = <25000>;
+
+ qcom,cdc-micbias-cfilt-sel = <0x0>;
+ qcom,cdc-micbias-cfilt-mv = <1800000>;
+ qcom,cdc-mclk-clk-rate = <12288000>;
+
+ qcom,cdc-static-supplies = "cdc-vdda-h",
+ "cdc-vdd-px",
+ "cdc-vdd-1p2v";
+
+ qcom,cdc-on-demand-supplies = "cdc-vdda-cp",
+ "cdc-vdd-mic-bias";
+ };
+
+ msm8x10_wcd_codec@77{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x77>;
+ };
+
+ msm8x10_wcd_codec@66{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x66>;
+ };
+
+ msm8x10_wcd_codec@55{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x55>;
+ };
+};
+
&spmi_bus {
qcom,pm8110@0 {
qcom,leds@a100 {
@@ -201,9 +213,13 @@
qcom,default-state = "on";
qcom,max-current = <40>;
qcom,id = <6>;
- qcom,source-sel = <1>;
+ qcom,source-sel = <8>;
qcom,mode-ctrl = <0x10>;
- qcom,mode = "manual";
+ qcom,pwm-channel = <0>;
+ qcom,pwm-us = <14>;
+ qcom,vin-ctrl = <0x03>;
+ qcom,mode = "pwm";
+ qcom,min-brightness = <19>;
};
};
};
@@ -221,8 +237,6 @@
&sdhc_1 {
vdd-supply = <&pm8110_l17>;
- qcom,vdd-always-on;
- qcom,vdd-lpm-sup;
qcom,vdd-voltage-level = <2900000 2900000>;
qcom,vdd-current-level = <200 400000>;
diff --git a/arch/arm/boot/dts/msm8610-regulator.dtsi b/arch/arm/boot/dts/msm8610-regulator.dtsi
index 09520c5..34cbd99 100644
--- a/arch/arm/boot/dts/msm8610-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8610-regulator.dtsi
@@ -30,19 +30,22 @@
apc_vreg_corner: regulator@f9018000 {
status = "okay";
compatible = "qcom,cpr-regulator";
- reg = <0xf9018000 0x1000>, <0xf9011064 4>, <0xfc4b80b0 8>,
- <0xfc4bc450 16>;
- reg-names = "rbcpr", "rbcpr_clk", "pvs_efuse", "cpr_efuse";
+ reg = <0xf9018000 0x1000>, <0xf9011064 4>, <0xfc4b8000 0x1000>;
+ reg-names = "rbcpr", "rbcpr_clk", "efuse_addr";
interrupts = <0 15 0>;
regulator-name = "apc_corner";
regulator-min-microvolt = <1>;
regulator-max-microvolt = <3>;
- qcom,num-efuse-bits = <5>;
- qcom,pvs-bin-process = <0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 2
- 2 2 2 2 3 3 3 3 3 3 3 3 0 0 0 0>;
- qcom,pvs-corner-ceiling-slow = <1150000 1150000 1275000>;
- qcom,pvs-corner-ceiling-nom = <975000 1075000 1200000>;
- qcom,pvs-corner-ceiling-fast = <900000 1000000 1140000>;
+
+ qcom,pvs-fuse-redun-sel = <53 25 3 2>;
+ qcom,pvs-fuse = <23 6 5>;
+ qcom,pvs-fuse-redun = <61 47 5>;
+
+ qcom,pvs-bin-process = <1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1>;
+ qcom,pvs-corner-ceiling-slow = <1050000 1150000 1275000>;
+ qcom,pvs-corner-ceiling-nom = <1050000 1075000 1200000>;
+ qcom,pvs-corner-ceiling-fast = <1050000 1050000 1140000>;
vdd-apc-supply = <&pm8110_s2>;
vdd-mx-supply = <&pm8110_l3_ao>;
@@ -51,17 +54,31 @@
qcom,cpr-ref-clk = <19200>;
qcom,cpr-timer-delay = <5000>;
- qcom,cpr-timer-cons-up = <1>;
+ qcom,cpr-timer-cons-up = <0>;
qcom,cpr-timer-cons-down = <2>;
qcom,cpr-irq-line = <0>;
qcom,cpr-step-quotient = <15>;
- qcom,cpr-up-threshold = <1>;
- qcom,cpr-down-threshold = <2>;
+ qcom,cpr-up-threshold = <0>;
+ qcom,cpr-down-threshold = <10>;
qcom,cpr-idle-clocks = <5>;
qcom,cpr-gcnt-time = <1>;
qcom,vdd-apc-step-up-limit = <1>;
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-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-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-enable;
};
};
@@ -96,6 +113,16 @@
qcom,use-voltage-corner;
qcom,consumer-supplies = "vdd_sr2_dig", "";
};
+
+ pm8110_s1_floor_corner: regulator-s1-floor-corner {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8110_s1_floor_corner";
+ qcom,set = <3>;
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+ qcom,use-voltage-floor-corner;
+ qcom,always-send-voltage;
+ };
};
rpm-regulator-smpa3 {
@@ -111,7 +138,7 @@
rpm-regulator-smpa4 {
status = "okay";
pm8110_s4: regulator-s4 {
- regulator-min-microvolt = <2150000>;
+ regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <2150000>;
qcom,init-voltage = <2150000>;
status = "okay";
@@ -172,6 +199,7 @@
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
qcom,init-voltage = <1200000>;
+ regulator-always-on;
status = "okay";
};
};
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index ad0980c..79543b1 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -215,10 +215,13 @@
reg = <0xf9a55000 0x400>;
interrupts = <0 134 0>, <0 140 0>;
interrupt-names = "core_irq", "async_irq";
- HSUSB_VDDCX-supply = <&pm8110_s1>;
+ hsusb_vdd_dig-supply = <&pm8110_s1_corner>;
HSUSB_1p8-supply = <&pm8110_l10>;
HSUSB_3p3-supply = <&pm8110_l20>;
+ qcom,vdd-voltage-level = <1 5 7>;
+ qcom,hsusb-otg-phy-init-seq =
+ <0x44 0x80 0x68 0x81 0x24 0x82 0x13 0x83 0xffffffff>;
qcom,hsusb-otg-phy-type = <2>;
qcom,hsusb-otg-mode = <1>;
qcom,hsusb-otg-otg-control = <2>;
@@ -251,8 +254,6 @@
interrupt-names = "core_irq", "bam_irq";
vdd-supply = <&pm8110_l17>;
- qcom,vdd-always-on;
- qcom,vdd-lpm-sup;
qcom,vdd-voltage-level = <2900000 2900000>;
qcom,vdd-current-level = <9000 400000>;
@@ -699,6 +700,7 @@
gpios = <&msmgpio 23 0>, <&msmgpio 24 0>, <&msmgpio 25 0>, <&msmgpio 26 0>, <&msmgpio 27 0>;
qcom,has-pronto-hw;
qcom,wlan-rx-buff-count = <256>;
+ qcom,has-autodetect-xo;
};
qcom,mss@fc880000 {
@@ -752,7 +754,7 @@
tsens: tsens@fc4a8000 {
compatible = "qcom,msm-tsens";
reg = <0xfc4a8000 0x2000>,
- <0xfc4b8000 0x1000>;
+ <0xfc4bc000 0x1000>;
reg-names = "tsens_physical", "tsens_eeprom_physical";
interrupts = <0 184 0>;
qcom,sensors = <2>;
@@ -772,6 +774,21 @@
qcom,core-limit-temp = <80>;
qcom,core-temp-hysteresis = <10>;
qcom,core-control-mask = <0xe>;
+ qcom,vdd-restriction-temp = <5>;
+ qcom,vdd-restriction-temp-hysteresis = <10>;
+ vdd-dig-supply = <&pm8110_s1_floor_corner>;
+
+ qcom,vdd-dig-rstr{
+ qcom,vdd-rstr-reg = "vdd-dig";
+ qcom,levels = <5 7 7>; /* Nominal, Super Turbo, Super Turbo */
+ qcom,min-level = <1>; /* No Request */
+ };
+
+ qcom,vdd-apps-rstr{
+ qcom,vdd-rstr-reg = "vdd-apps";
+ qcom,levels = <600000 787200 998400>;
+ qcom,freq-req;
+ };
};
qcom,ipc-spinlock@fd484000 {
@@ -822,6 +839,12 @@
qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
};
+ jtag_fuse: jtagfuse@fc4be024 {
+ compatible = "qcom,jtag-fuse";
+ reg = <0xfc4be024 0x8>;
+ reg-names = "fuse-base";
+ };
+
jtag_mm0: jtagmm@fc34c000 {
compatible = "qcom,jtag-mm";
reg = <0xfc34c000 0x1000>,
@@ -891,6 +914,11 @@
<55 512 393600 3936000>;
};
+ cpu-pmu {
+ compatible = "arm,cortex-a7-pmu";
+ qcom,irq-is-percpu;
+ interrupts = <1 7 0xf00>;
+ };
};
&gdsc_vfe {
diff --git a/arch/arm/boot/dts/msm8612-qrd-camera-sensor.dtsi b/arch/arm/boot/dts/msm8612-qrd-camera-sensor.dtsi
new file mode 100644
index 0000000..25554eb
--- /dev/null
+++ b/arch/arm/boot/dts/msm8612-qrd-camera-sensor.dtsi
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+
+&i2c {
+
+ qcom,camera@20 {
+ compatible = "shinetech,s5k4e1";
+ reg = <0x20>;
+ qcom,slave-id = <0x20 0x0000 0x4e10>;
+ qcom,csiphy-sd-index = <0>;
+ qcom,csid-sd-index = <0>;
+ qcom,mount-angle = <90>;
+ qcom,sensor-name = "SKUAB_ST_s5k4e1";
+ cam_vdig-supply = <&pm8110_l2>;
+ cam_vana-supply = <&pm8110_l19>;
+ cam_vio-supply = <&pm8110_l14>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
+ qcom,cam-vreg-type = <0 0 0>;
+ qcom,cam-vreg-min-voltage = <1200000 1800000 2850000>;
+ qcom,cam-vreg-max-voltage = <1200000 1800000 2850000>;
+ qcom,cam-vreg-op-mode = <200000 8000 80000>;
+ qcom,gpio-no-mux = <0>;
+ gpios = <&msmgpio 13 0>,
+ <&msmgpio 21 0>,
+ <&msmgpio 20 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET1",
+ "CAM_STANDBY";
+ qcom,csi-lane-assign = <0xe4>;
+ qcom,csi-lane-mask = <0x3>;
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <1>;
+ qcom,sensor-type = <0>;
+ qcom,cci-master = <0>;
+ };
+ qcom,camera@78 {
+ compatible = "shinetech,gc0339";
+ reg = <0x78>;
+ qcom,slave-id = <0x42 0x00 0xc8>;
+ qcom,csiphy-sd-index = <1>;
+ qcom,csid-sd-index = <1>;
+ qcom,mount-angle = <90>;
+ qcom,sensor-name = "skuab_shinetech_gc0339";
+ cam_vdig-supply = <&pm8110_l14>;
+ cam_vana-supply = <&pm8110_l19>;
+ cam_vio-supply = <&pm8110_l14>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
+ qcom,cam-vreg-type = <0 1 0>;
+ qcom,cam-vreg-min-voltage = <1800000 1800000 2850000>;
+ qcom,cam-vreg-max-voltage = <1800000 1800000 2850000>;
+ qcom,cam-vreg-op-mode = <200000 0 80000>;
+ qcom,gpio-no-mux = <0>;
+ gpios = <&msmgpio 14 0>,
+ <&msmgpio 15 0>,
+ <&msmgpio 85 0>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET",
+ "CAM_STANDBY";
+ qcom,gpio-set-tbl-num = <1 1>;
+ qcom,gpio-set-tbl-flags = <0 2>;
+ qcom,gpio-set-tbl-delay = <1000 4000>;
+ qcom,csi-lane-assign = <0xe4>;
+ qcom,csi-lane-mask = <0x3>;
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <1>;
+ qcom,cci-master = <0>;
+ status = "ok";
+ };
+};
diff --git a/arch/arm/boot/dts/msm8926.dtsi b/arch/arm/boot/dts/msm8926.dtsi
index d15459c..f46b714 100644
--- a/arch/arm/boot/dts/msm8926.dtsi
+++ b/arch/arm/boot/dts/msm8926.dtsi
@@ -73,3 +73,8 @@
qcom,cpr-down-threshold = <5>;
qcom,cpr-apc-volt-step = <10000>;
};
+
+&tsens {
+ qcom,sensors = <6>;
+ qcom,slope = <2901 2846 3038 2955 2901 2846>;
+};
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-dragonboard.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-dragonboard.dtsi
index b9f2125..2f8e558 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-dragonboard.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-dragonboard.dtsi
@@ -50,12 +50,15 @@
qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
qcom,gpio-no-mux = <0>;
gpios = <&msmgpio 15 0>,
- <&msmgpio 90 0>;
+ <&msmgpio 90 0>,
+ <&msmgpio 89 0>;
qcom,gpio-reset = <1>;
- qcom,gpio-req-tbl-num = <0 1>;
- qcom,gpio-req-tbl-flags = <1 0>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
qcom,gpio-req-tbl-label = "CAMIF_MCLK",
- "CAM_RESET1";
+ "CAM_RESET1",
+ "CAM_STANDBY";
qcom,gpio-set-tbl-num = <1 1>;
qcom,gpio-set-tbl-flags = <0 2>;
qcom,gpio-set-tbl-delay = <1000 30000>;
@@ -90,12 +93,15 @@
qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
qcom,gpio-no-mux = <0>;
gpios = <&msmgpio 15 0>,
- <&msmgpio 90 0>;
+ <&msmgpio 90 0>,
+ <&msmgpio 89 0>;
qcom,gpio-reset = <1>;
- qcom,gpio-req-tbl-num = <0 1>;
- qcom,gpio-req-tbl-flags = <1 0>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
qcom,gpio-req-tbl-label = "CAMIF_MCLK",
- "CAM_RESET1";
+ "CAM_RESET1",
+ "CAM_STANDBY";
qcom,gpio-set-tbl-num = <1 1>;
qcom,gpio-set-tbl-flags = <0 2>;
qcom,gpio-set-tbl-delay = <1000 30000>;
diff --git a/arch/arm/boot/dts/msm8974-camera.dtsi b/arch/arm/boot/dts/msm8974-camera.dtsi
index 456b079..4be2b38 100644
--- a/arch/arm/boot/dts/msm8974-camera.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera.dtsi
@@ -196,18 +196,42 @@
qcom,gpio-tbl-num = <0 1 2 3>;
qcom,gpio-tbl-flags = <1 1 1 1>;
qcom,gpio-tbl-label = "CCI_I2C_DATA0",
- "CCI_I2C_CLK0",
- "CCI_I2C_DATA1",
- "CCI_I2C_CLK1";
- 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-scl-stretch-en = <0>;
- qcom,hw-trdhld = <6>;
- qcom,hw-tsp = <1>;
+ "CCI_I2C_CLK0",
+ "CCI_I2C_DATA1",
+ "CCI_I2C_CLK1";
+ master0: qcom,cci-master0 {
+ status = "disabled";
+ };
+ master1: qcom,cci-master1 {
+ status = "disabled";
+ };
};
};
+
+&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-scl-stretch-en = <0>;
+ qcom,hw-trdhld = <6>;
+ qcom,hw-tsp = <1>;
+ 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-scl-stretch-en = <0>;
+ qcom,hw-trdhld = <6>;
+ qcom,hw-tsp = <1>;
+ status = "ok";
+};
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index 2a60df4..e66ea25 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -15,6 +15,12 @@
/include/ "msm8974-leds.dtsi"
/include/ "msm8974-camera-sensor-cdp.dtsi"
+/ {
+ aliases {
+ serial0 = &blsp1_uart1;
+ };
+};
+
&soc {
serial@f991e000 {
status = "ok";
@@ -48,6 +54,7 @@
atmel,i2c-pull-up;
atmel,no-force-update;
atmel,cfg_1 {
+ atmel,fw-name = "atmel_8974_fluid_v1_0_AA.hex";
atmel,family-id = <0x82>;
atmel,variant-id = <0x19>;
atmel,version = <0x10>;
@@ -251,63 +258,61 @@
};
};
-&spmi_bus {
- qcom,pm8941@1 {
- qcom,leds@d800 {
- status = "okay";
- qcom,wled_0 {
- label = "wled";
- linux,name = "wled:backlight";
- linux,default-trigger = "bkl-trigger";
- qcom,cs-out-en;
- qcom,op-fdbck = <1>;
- qcom,default-state = "on";
- qcom,max-current = <25>;
- qcom,ctrl-delay-us = <0>;
- qcom,boost-curr-lim = <3>;
- qcom,cp-sel = <0>;
- qcom,switch-freq = <2>;
- qcom,ovp-val = <2>;
- qcom,num-strings = <1>;
- qcom,id = <0>;
- };
+&pm8941_lsid1 {
+ qcom,leds@d800 {
+ status = "okay";
+ qcom,wled_0 {
+ label = "wled";
+ linux,name = "wled:backlight";
+ linux,default-trigger = "bkl-trigger";
+ qcom,cs-out-en;
+ qcom,op-fdbck = <1>;
+ qcom,default-state = "on";
+ qcom,max-current = <25>;
+ qcom,ctrl-delay-us = <0>;
+ qcom,boost-curr-lim = <3>;
+ qcom,cp-sel = <0>;
+ qcom,switch-freq = <2>;
+ qcom,ovp-val = <2>;
+ qcom,num-strings = <1>;
+ qcom,id = <0>;
};
+ };
- qcom,leds@d900 {
- status = "disabled";
- };
+ qcom,leds@d900 {
+ status = "disabled";
+ };
- qcom,leds@da00 {
- status = "disabled";
- };
+ qcom,leds@da00 {
+ status = "disabled";
+ };
- qcom,leds@db00 {
- status = "disabled";
- };
+ qcom,leds@db00 {
+ status = "disabled";
+ };
- qcom,leds@dc00 {
- status = "disabled";
- };
+ qcom,leds@dc00 {
+ status = "disabled";
+ };
- qcom,leds@dd00 {
- status = "disabled";
- };
+ qcom,leds@dd00 {
+ status = "disabled";
+ };
- qcom,leds@de00 {
- status = "disabled";
- };
+ qcom,leds@de00 {
+ status = "disabled";
+ };
- qcom,leds@df00 {
- status = "disabled";
- };
+ qcom,leds@df00 {
+ status = "disabled";
+ };
- qcom,leds@e000 {
- status = "disabled";
- };
+ qcom,leds@e000 {
+ status = "disabled";
+ };
- qcom,leds@e100 {
- status = "disabled";
- };
+ qcom,leds@e100 {
+ status = "disabled";
};
};
@@ -406,6 +411,8 @@
qcom,rx-gpio = <&msmgpio 42 0x00>;
qcom,cts-gpio = <&msmgpio 43 0x00>;
qcom,rfr-gpio = <&msmgpio 44 0x00>;
+ qcom,inject-rx-on-wakeup = <1>;
+ qcom,rx-char-to-inject = <0xFD>;
};
&usb3 {
diff --git a/arch/arm/boot/dts/msm8974-clock.dtsi b/arch/arm/boot/dts/msm8974-clock.dtsi
index bed5d70..8d90771 100644
--- a/arch/arm/boot/dts/msm8974-clock.dtsi
+++ b/arch/arm/boot/dts/msm8974-clock.dtsi
@@ -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
@@ -10,18 +10,14 @@
* GNU General Public License for more details.
*/
-&spmi_bus {
+&pm8941_lsid0 {
+ pm8941_clkdiv1: clkdiv@5b00 {
+ qcom,cxo-div = <2>;
+ };
- qcom,pm8941@0 {
+ pm8941_clkdiv2: clkdiv@5c00 {
+ };
- pm8941_clkdiv1: clkdiv@5b00 {
- qcom,cxo-div = <2>;
- };
-
- pm8941_clkdiv2: clkdiv@5c00 {
- };
-
- pm8941_clkdiv3: clkdiv@5d00 {
- };
+ pm8941_clkdiv3: clkdiv@5d00 {
};
};
diff --git a/arch/arm/boot/dts/msm8974-coresight.dtsi b/arch/arm/boot/dts/msm8974-coresight.dtsi
index 9fee2e5..9fd0cd9 100644
--- a/arch/arm/boot/dts/msm8974-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8974-coresight.dtsi
@@ -16,6 +16,8 @@
reg = <0xfc322000 0x1000>,
<0xfc37c000 0x3000>;
reg-names = "tmc-base", "bam-base";
+ interrupts = <0 166 0>;
+ interrupt-names = "byte-cntr-irq";
qcom,memory-reservation-type = "EBI1";
qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
@@ -379,4 +381,14 @@
qcom,hwevent-clks = "core_mmss_clk";
};
+
+ fuse: fuse@fc4be024 {
+ compatible = "arm,coresight-fuse";
+ reg = <0xfc4be024 0x8>;
+ reg-names = "fuse-base";
+
+ coresight-id = <30>;
+ coresight-name = "coresight-fuse";
+ coresight-nr-inports = <0>;
+ };
};
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index 3d2308d..7f714e8 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -14,6 +14,12 @@
/include/ "msm8974-camera-sensor-fluid.dtsi"
/include/ "msm8974-leds.dtsi"
+/ {
+ aliases {
+ serial0 = &blsp1_uart1;
+ };
+};
+
&soc {
serial@f991e000 {
status = "ok";
@@ -43,6 +49,7 @@
atmel,i2c-pull-up;
atmel,no-force-update;
atmel,cfg_1 {
+ atmel,fw-name = "atmel_8974_fluid_v1_0_AA.hex";
atmel,family-id = <0x82>;
atmel,variant-id = <0x19>;
atmel,version = <0x10>;
@@ -250,63 +257,61 @@
};
};
-&spmi_bus {
- qcom,pm8941@1 {
- qcom,leds@d800 {
- status = "okay";
- qcom,wled_0 {
- label = "wled";
- linux,name = "wled:backlight";
- linux,default-trigger = "bkl-trigger";
- qcom,cs-out-en;
- qcom,op-fdbck = <1>;
- qcom,default-state = "on";
- qcom,max-current = <25>;
- qcom,ctrl-delay-us = <0>;
- qcom,boost-curr-lim = <3>;
- qcom,cp-sel = <0>;
- qcom,switch-freq = <2>;
- qcom,ovp-val = <2>;
- qcom,num-strings = <1>;
- qcom,id = <0>;
- };
+&pm8941_lsid1 {
+ qcom,leds@d800 {
+ status = "okay";
+ qcom,wled_0 {
+ label = "wled";
+ linux,name = "wled:backlight";
+ linux,default-trigger = "bkl-trigger";
+ qcom,cs-out-en;
+ qcom,op-fdbck = <1>;
+ qcom,default-state = "on";
+ qcom,max-current = <25>;
+ qcom,ctrl-delay-us = <0>;
+ qcom,boost-curr-lim = <3>;
+ qcom,cp-sel = <0>;
+ qcom,switch-freq = <2>;
+ qcom,ovp-val = <2>;
+ qcom,num-strings = <1>;
+ qcom,id = <0>;
};
+ };
- qcom,leds@d900 {
- status = "disabled";
- };
+ qcom,leds@d900 {
+ status = "disabled";
+ };
- qcom,leds@da00 {
- status = "disabled";
- };
+ qcom,leds@da00 {
+ status = "disabled";
+ };
- qcom,leds@db00 {
- status = "disabled";
- };
+ qcom,leds@db00 {
+ status = "disabled";
+ };
- qcom,leds@dc00 {
- status = "disabled";
- };
+ qcom,leds@dc00 {
+ status = "disabled";
+ };
- qcom,leds@dd00 {
- status = "disabled";
- };
+ qcom,leds@dd00 {
+ status = "disabled";
+ };
- qcom,leds@de00 {
- status = "disabled";
- };
+ qcom,leds@de00 {
+ status = "disabled";
+ };
- qcom,leds@df00 {
- status = "disabled";
- };
+ qcom,leds@df00 {
+ status = "disabled";
+ };
- qcom,leds@e000 {
- status = "disabled";
- };
+ qcom,leds@e000 {
+ status = "disabled";
+ };
- qcom,leds@e100 {
- status = "disabled";
- };
+ qcom,leds@e100 {
+ status = "disabled";
};
};
@@ -407,6 +412,7 @@
qcom,min-fcc-learning-soc = <20>;
qcom,min-fcc-ocv-pc = <30>;
qcom,min-fcc-learning-samples = <5>;
+ qcom,fcc-resolution = <10>;
status = "ok";
};
@@ -658,14 +664,14 @@
interrupt-parent = <&msmgpio>;
spi-max-frequency = <960000>;
qcom,channels = <31>;
- qcom,gain = <100 100 100 50 100 100 1 100 1 50
- 1 100 1 100 50 50 50 50 50 50
- 100 50 100 50 50 50 50 50 50 50
- 50>;
- qcom,rsense = <2 2 2 200 20 2 1 2 1 30
- 1 10 1 30 50 30 500 30 100 30
- 100 500 20 200 1000 20 1000 1000 70 200
- 50>;
- qcom,channel-type = <0x1540>;
+ qcom,gain = <100 100 100 100 100 100 100 100 100 100
+ 100 100 100 100 100 100 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1
+ 1>;
+ qcom,rsense = <10 10 10 10 100 200 500 10 10 10
+ 200 200 10 500 10 10 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1
+ 1>;
+ qcom,channel-type = <0xf0000000>;
};
};
diff --git a/arch/arm/boot/dts/msm8974-leds.dtsi b/arch/arm/boot/dts/msm8974-leds.dtsi
index 5e91f45..06abbd8 100644
--- a/arch/arm/boot/dts/msm8974-leds.dtsi
+++ b/arch/arm/boot/dts/msm8974-leds.dtsi
@@ -11,119 +11,172 @@
* GNU General Public License for more details.
*/
-&spmi_bus {
- qcom,pm8941@1 {
- qcom,leds@d000 {
- status = "okay";
- qcom,rgb_0 {
- label = "rgb";
- linux,name = "led:rgb_red";
- qcom,mode = "pwm";
- qcom,pwm-channel = <6>;
- qcom,pwm-us = <1000>;
- qcom,max-current = <12>;
- qcom,default-state = "off";
- qcom,id = <3>;
- linux,default-trigger =
- "battery-charging";
- };
-
- qcom,rgb_1 {
- label = "rgb";
- linux,name = "led:rgb_green";
- qcom,mode = "pwm";
- qcom,pwm-channel = <5>;
- qcom,pwm-us = <1000>;
- qcom,max-current = <12>;
- qcom,default-state = "off";
- qcom,id = <4>;
- linux,default-trigger = "battery-full";
- };
-
- qcom,rgb_2 {
- label = "rgb";
- linux,name = "led:rgb_blue";
- qcom,mode = "pwm";
- qcom,pwm-channel = <4>;
- qcom,pwm-us = <1000>;
- qcom,max-current = <12>;
- qcom,id = <5>;
- status = "disabled";
- };
+&pm8941_lsid1 {
+ qcom,leds@d000 {
+ status = "okay";
+ qcom,rgb_0 {
+ label = "rgb";
+ linux,name = "led:rgb_red";
+ qcom,mode = "pwm";
+ qcom,pwm-channel = <6>;
+ qcom,pwm-us = <1000>;
+ qcom,max-current = <12>;
+ qcom,default-state = "off";
+ qcom,id = <3>;
+ linux,default-trigger =
+ "battery-charging";
};
- qcom,leds@d100 {
- status = "disabled";
+ qcom,rgb_1 {
+ label = "rgb";
+ linux,name = "led:rgb_green";
+ qcom,mode = "pwm";
+ qcom,pwm-channel = <5>;
+ qcom,pwm-us = <1000>;
+ qcom,max-current = <12>;
+ qcom,default-state = "off";
+ qcom,id = <4>;
+ linux,default-trigger = "battery-full";
};
- qcom,leds@d200 {
- status = "disabled";
- };
-
- qcom,leds@d300 {
- status = "okay";
- pm8941_flash0: qcom,flash_0 {
- 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;
- label = "flash";
- linux,default-trigger =
- "flash0_trigger";
- qcom,id = <1>;
- linux,name = "led:flash_0";
- qcom,current = <625>;
- };
-
- pm8941_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>;
- };
-
- pm8941_torch: qcom,flash_torch {
- qcom,max-current = <200>;
- qcom,default-state = "off";
- qcom,headroom = <0>;
- qcom,startup-dly = <1>;
- linux,default-trigger =
- "torch_trigger";
- label = "flash";
- qcom,id = <2>;
- linux,name = "led:flash_torch";
- qcom,current = <200>;
- qcom,torch-enable;
- };
- };
-
- qcom,leds@d400 {
- status = "disabled";
- };
-
- qcom,leds@d500 {
- status = "disabled";
- };
-
- qcom,leds@d600 {
- status = "disabled";
- };
-
- qcom,leds@d700 {
+ qcom,rgb_2 {
+ label = "rgb";
+ linux,name = "led:rgb_blue";
+ qcom,mode = "pwm";
+ qcom,pwm-channel = <4>;
+ qcom,pwm-us = <1000>;
+ qcom,max-current = <12>;
+ qcom,id = <5>;
status = "disabled";
};
};
-};
+ qcom,leds@d100 {
+ status = "disabled";
+ };
+
+ qcom,leds@d200 {
+ status = "disabled";
+ };
+
+ qcom,leds@d300 {
+ status = "okay";
+ pm8941_flash0: qcom,flash_0 {
+ 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;
+ label = "flash";
+ linux,default-trigger =
+ "flash0_trigger";
+ qcom,id = <1>;
+ linux,name = "led:flash_0";
+ qcom,current = <625>;
+ };
+
+ pm8941_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>;
+ };
+
+ pm8941_torch: qcom,flash_torch {
+ qcom,max-current = <200>;
+ qcom,default-state = "off";
+ qcom,headroom = <0>;
+ qcom,startup-dly = <1>;
+ linux,default-trigger =
+ "torch_trigger";
+ label = "flash";
+ qcom,id = <2>;
+ linux,name = "led:flash_torch";
+ qcom,current = <200>;
+ qcom,torch-enable;
+ };
+ };
+
+ qcom,leds@d400 {
+ status = "disabled";
+ };
+
+ qcom,leds@d500 {
+ status = "disabled";
+ };
+
+ qcom,leds@d600 {
+ status = "disabled";
+ };
+
+ qcom,leds@d700 {
+ status = "disabled";
+ };
+
+ qcom,leds@e200 {
+ status = "okay";
+
+ qcom,kpdbl1 {
+ label = "kpdbl";
+ linux,name = "kpdbl-pwm-1";
+ qcom,mode = "pwm";
+ qcom,pwm-channel = <8>;
+ qcom,pwm-us = <1000>;
+ qcom,id = <7>;
+ qcom,max-current = <20>;
+ qcom,row-id = <0>;
+ qcom,row-src-en;
+ qcom,always-on;
+ };
+
+ qcom,kpdbl2 {
+ label = "kpdbl";
+ linux,name = "kpdbl-lut-2";
+ qcom,mode = "lpg";
+ qcom,pwm-channel = <9>;
+ qcom,pwm-us = <1000>;
+ qcom,start-idx = <1>;
+ qcom,duty-pcts = [00 00 00 00 64
+ 64 00 00 00 00];
+ qcom,id = <7>;
+ qcom,max-current = <20>;
+ qcom,row-id = <1>;
+ qcom,row-src-en;
+ };
+
+ qcom,kpdbl3 {
+ label = "kpdbl";
+ linux,name = "kpdbl-pwm-3";
+ qcom,mode = "pwm";
+ qcom,pwm-channel = <10>;
+ qcom,pwm-us = <1000>;
+ qcom,id = <7>;
+ qcom,max-current = <20>;
+ qcom,row-id = <2>;
+ qcom,row-src-en;
+ };
+
+ qcom,kpdbl4 {
+ label = "kpdbl";
+ linux,name = "kpdbl-pwm-4";
+ qcom,mode = "pwm";
+ qcom,pwm-channel = <11>;
+ qcom,pwm-us = <1000>;
+ qcom,id = <7>;
+ qcom,max-current = <20>;
+ qcom,row-id = <3>;
+ qcom,row-src-en;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index 2dc52b6..51cb226 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -13,6 +13,12 @@
/include/ "msm8974-leds.dtsi"
/include/ "msm8974-camera-sensor-liquid.dtsi"
+/ {
+ aliases {
+ serial0 = &blsp1_uart1;
+ };
+};
+
&soc {
serial@f991e000 {
status = "ok";
@@ -770,26 +776,24 @@
interrupt-parent = <&msmgpio>;
spi-max-frequency = <960000>;
qcom,channels = <31>;
- qcom,gain = <50 50 50 50 50 100 50 50 50 50
- 50 50 50 50 100 50 50 50 50 100
+ qcom,gain = <50 50 50 50 50 100 50 100 50 50
+ 100 50 50 50 50 50 50 50 50 50
50 50 50 100 50 50 50 1 1 1
1>;
- qcom,rsense = <40 10 10 25 10 1000 75 25 10 25
- 33 500 200 10 500 100 33 200 25 100
- 75 500 50 200 5 5 3 1 1 1
- 1>;
+ qcom,rsense = <50 100 500 10 25 1000 40 200 200 5
+ 500 500 75 10 5 25 33 75 25 200
+ 10 25 33 100 10 10 3 1000 1000 1000
+ 1000>;
qcom,channel-type = <0xf0000000>;
};
};
-&spmi_bus {
- qcom,pm8941@1 {
- qcom,leds@d000 {
- qcom,rgb_2 {
- status = "ok";
- qcom,default-state = "on";
- qcom,turn-off-delay-ms = <1000>;
- };
+&pm8941_lsid1 {
+ qcom,leds@d000 {
+ qcom,rgb_2 {
+ status = "ok";
+ qcom,default-state = "on";
+ qcom,turn-off-delay-ms = <1000>;
};
};
};
@@ -813,7 +817,7 @@
};
qcom,dc-chgpth@1400 {
- status = "ok";
+ status = "disabled";
};
qcom,boost@1500 {
diff --git a/arch/arm/boot/dts/msm8974-mdss.dtsi b/arch/arm/boot/dts/msm8974-mdss.dtsi
index 6b8d600..f8a8fa6 100644
--- a/arch/arm/boot/dts/msm8974-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8974-mdss.dtsi
@@ -41,6 +41,7 @@
qcom,mdss-intf-off = <0x00021100 0x00021300
0x00021500 0x00021700>;
+ qcom,mdss-has-wfd-blk;
qcom,vbif-settings = <0x0004 0x00000001>,
<0x00D8 0x00000707>,
<0x00F0 0x00000030>,
@@ -85,6 +86,50 @@
vddio-supply = <&pm8941_l12>;
vdda-supply = <&pm8941_l2>;
qcom,mdss-fb-map = <&mdss_fb0>;
+ qcom,platform-reset-gpio = <&pm8941_gpios 19 1>;
+ qcom,platform-enable-gpio = <&msmgpio 58 1>;
+ qcom,platform-reset-sequence = <1 20 0 200 1 20 2>;
+ qcom,platform-strength-ctrl = [ff 06];
+ qcom,platform-bist-ctrl = [00 00 b1 ff 00 00];
+ qcom,platform-regulator-settings = [07 09 03 00 20 00 01];
+ qcom,platform-lane-config = [00 00 00 00 00 00 00 01 97
+ 00 00 00 00 05 00 00 01 97
+ 00 00 00 00 0a 00 00 01 97
+ 00 00 00 00 0f 00 00 01 97
+ 00 c0 00 00 00 00 00 01 bb];
+ qcom,platform-supply-entry1 {
+ qcom,supply-name = "vdd";
+ qcom,supply-min-voltage = <3000000>;
+ qcom,supply-max-voltage = <3000000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ qcom,supply-pre-on-sleep = <0>;
+ qcom,supply-post-on-sleep = <20>;
+ qcom,supply-pre-off-sleep = <0>;
+ qcom,supply-post-off-sleep = <0>;
+ };
+ qcom,platform-supply-entry2 {
+ qcom,supply-name = "vddio";
+ qcom,supply-min-voltage = <1800000>;
+ qcom,supply-max-voltage = <1800000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ qcom,supply-pre-on-sleep = <0>;
+ qcom,supply-post-on-sleep = <20>;
+ qcom,supply-pre-off-sleep = <0>;
+ qcom,supply-post-off-sleep = <0>;
+ };
+ qcom,platform-supply-entry3 {
+ qcom,supply-name = "vdda";
+ qcom,supply-min-voltage = <1200000>;
+ qcom,supply-max-voltage = <1200000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ qcom,supply-pre-on-sleep = <0>;
+ qcom,supply-post-on-sleep = <0>;
+ qcom,supply-pre-off-sleep = <0>;
+ qcom,supply-post-off-sleep = <0>;
+ };
};
mdss_dsi1: qcom,mdss_dsi@fd922e00 {
@@ -144,5 +189,6 @@
qcom,panel-pwm-period = <53>;
status = "disable";
qcom,mdss-fb-map = <&mdss_fb0>;
+ gpio-panel-hpd = <&msmgpio 102 0>;
};
};
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index 28111fa..4ee56ad 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -14,6 +14,12 @@
/include/ "msm8974-camera-sensor-mtp.dtsi"
/include/ "msm8974-leds.dtsi"
+/ {
+ aliases {
+ serial0 = &blsp1_uart1;
+ };
+};
+
&soc {
serial@f991e000 {
status = "ok";
@@ -43,6 +49,7 @@
atmel,i2c-pull-up;
atmel,no-force-update;
atmel,cfg_1 {
+ atmel,fw-name = "atmel_8974_fluid_v1_0_AA.hex";
atmel,family-id = <0x82>;
atmel,variant-id = <0x19>;
atmel,version = <0x10>;
@@ -191,63 +198,61 @@
};
};
-&spmi_bus {
- qcom,pm8941@1 {
- qcom,leds@d800 {
- status = "okay";
- qcom,wled_0 {
- label = "wled";
- linux,name = "wled:backlight";
- linux,default-trigger = "bkl-trigger";
- qcom,cs-out-en;
- qcom,op-fdbck = <1>;
- qcom,default-state = "on";
- qcom,max-current = <25>;
- qcom,ctrl-delay-us = <0>;
- qcom,boost-curr-lim = <3>;
- qcom,cp-sel = <0>;
- qcom,switch-freq = <2>;
- qcom,ovp-val = <2>;
- qcom,num-strings = <1>;
- qcom,id = <0>;
- };
+&pm8941_lsid1 {
+ qcom,leds@d800 {
+ status = "okay";
+ qcom,wled_0 {
+ label = "wled";
+ linux,name = "wled:backlight";
+ linux,default-trigger = "bkl-trigger";
+ qcom,cs-out-en;
+ qcom,op-fdbck = <1>;
+ qcom,default-state = "on";
+ qcom,max-current = <25>;
+ qcom,ctrl-delay-us = <0>;
+ qcom,boost-curr-lim = <3>;
+ qcom,cp-sel = <0>;
+ qcom,switch-freq = <2>;
+ qcom,ovp-val = <2>;
+ qcom,num-strings = <1>;
+ qcom,id = <0>;
};
+ };
- qcom,leds@d900 {
- status = "disabled";
- };
+ qcom,leds@d900 {
+ status = "disabled";
+ };
- qcom,leds@da00 {
- status = "disabled";
- };
+ qcom,leds@da00 {
+ status = "disabled";
+ };
- qcom,leds@db00 {
- status = "disabled";
- };
+ qcom,leds@db00 {
+ status = "disabled";
+ };
- qcom,leds@dc00 {
- status = "disabled";
- };
+ qcom,leds@dc00 {
+ status = "disabled";
+ };
- qcom,leds@dd00 {
- status = "disabled";
- };
+ qcom,leds@dd00 {
+ status = "disabled";
+ };
- qcom,leds@de00 {
- status = "disabled";
- };
+ qcom,leds@de00 {
+ status = "disabled";
+ };
- qcom,leds@df00 {
- status = "disabled";
- };
+ qcom,leds@df00 {
+ status = "disabled";
+ };
- qcom,leds@e000 {
- status = "disabled";
- };
+ qcom,leds@e000 {
+ status = "disabled";
+ };
- qcom,leds@e100 {
- status = "disabled";
- };
+ qcom,leds@e100 {
+ status = "disabled";
};
};
@@ -356,6 +361,7 @@
qcom,min-fcc-learning-soc = <20>;
qcom,min-fcc-ocv-pc = <30>;
qcom,min-fcc-learning-samples = <5>;
+ qcom,fcc-resolution = <10>;
status = "ok";
};
@@ -666,21 +672,6 @@
};
};
-&pm8841_mpps {
-
- mpp@a000 { /* MPP 1 */
- };
-
- mpp@a100 { /* MPP 2 */
- };
-
- mpp@a200 { /* MPP 3 */
- };
-
- mpp@a300 { /* MPP 4 */
- };
-};
-
&slim_msm {
taiko_codec {
qcom,cdc-micbias1-ext-cap;
diff --git a/arch/arm/boot/dts/msm8974-regulator.dtsi b/arch/arm/boot/dts/msm8974-regulator.dtsi
index d9d5aaa..eae9032 100644
--- a/arch/arm/boot/dts/msm8974-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974-regulator.dtsi
@@ -13,48 +13,44 @@
/* QPNP controlled regulators: */
-&spmi_bus {
+&pm8941_lsid1 {
+ pm8941_boost: regulator@a000 {
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ qcom,enable-time = <500>;
+ status = "okay";
+ };
- qcom,pm8941@1 {
+ pm8941_mvs1: regulator@8300 {
+ parent-supply = <&pm8941_chg_otg>;
+ qcom,enable-time = <1000>;
+ qcom,pull-down-enable = <1>;
+ interrupts = <0x1 0x83 0x2>;
+ interrupt-names = "ocp";
+ qcom,ocp-enable = <1>;
+ qcom,ocp-max-retries = <10>;
+ qcom,ocp-retry-delay = <30>;
+ qcom,soft-start-enable = <1>;
+ qcom,vs-soft-start-strength = <0>;
+ qcom,hpm-enable = <1>;
+ qcom,auto-mode-enable = <0>;
+ status = "okay";
+ };
- pm8941_boost: regulator@a000 {
- regulator-min-microvolt = <5000000>;
- regulator-max-microvolt = <5000000>;
- qcom,enable-time = <500>;
- status = "okay";
- };
-
- pm8941_mvs1: regulator@8300 {
- parent-supply = <&pm8941_chg_otg>;
- qcom,enable-time = <1000>;
- qcom,pull-down-enable = <1>;
- interrupts = <0x1 0x83 0x2>;
- interrupt-names = "ocp";
- qcom,ocp-enable = <1>;
- qcom,ocp-max-retries = <10>;
- qcom,ocp-retry-delay = <30>;
- qcom,soft-start-enable = <1>;
- qcom,vs-soft-start-strength = <0>;
- qcom,hpm-enable = <1>;
- qcom,auto-mode-enable = <0>;
- status = "okay";
- };
-
- pm8941_mvs2: regulator@8400 {
- parent-supply = <&pm8941_boost>;
- qcom,enable-time = <1000>;
- qcom,pull-down-enable = <1>;
- interrupts = <0x1 0x84 0x2>;
- interrupt-names = "ocp";
- qcom,ocp-enable = <1>;
- qcom,ocp-max-retries = <10>;
- qcom,ocp-retry-delay = <30>;
- qcom,soft-start-enable = <1>;
- qcom,vs-soft-start-strength = <0>;
- qcom,hpm-enable = <1>;
- qcom,auto-mode-enable = <0>;
- status = "okay";
- };
+ pm8941_mvs2: regulator@8400 {
+ parent-supply = <&pm8941_boost>;
+ qcom,enable-time = <1000>;
+ qcom,pull-down-enable = <1>;
+ interrupts = <0x1 0x84 0x2>;
+ interrupt-names = "ocp";
+ qcom,ocp-enable = <1>;
+ qcom,ocp-max-retries = <10>;
+ qcom,ocp-retry-delay = <30>;
+ qcom,soft-start-enable = <1>;
+ qcom,vs-soft-start-strength = <0>;
+ qcom,hpm-enable = <1>;
+ qcom,auto-mode-enable = <0>;
+ status = "okay";
};
};
diff --git a/arch/arm/boot/dts/msm8974-v1-pm.dtsi b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
index 288a703..7362b64 100644
--- a/arch/arm/boot/dts/msm8974-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
@@ -129,64 +129,16 @@
50 02 32 50 0f];
};
- qcom,lpm-resources {
- compatible = "qcom,lpm-resources";
- #address-cells = <1>;
- #size-cells = <0>;
-
- qcom,lpm-resources@0 {
- reg = <0x0>;
- qcom,name = "vdd-dig";
- qcom,type = <0x62706d73>; /* "smpb" */
- qcom,id = <0x02>;
- qcom,key = <0x6e726f63>; /* "corn" */
- qcom,init-value = <6>; /* Super Turbo */
- };
-
- qcom,lpm-resources@1 {
- reg = <0x1>;
- qcom,name = "vdd-mem";
- qcom,type = <0x62706d73>; /* "smpb" */
- qcom,id = <0x01>;
- qcom,key = <0x7675>; /* "uv" */
- qcom,init-value = <1050000>; /* Super Turbo */
- };
-
- qcom,lpm-resources@2 {
- reg = <0x2>;
- qcom,name = "pxo";
- qcom,type = <0x306b6c63>; /* "clk0" */
- qcom,id = <0x00>;
- qcom,key = <0x62616e45>; /* "Enab" */
- qcom,init-value = "xo_on";
- };
-
- qcom,lpm-resources@3 {
- reg = <0x3>;
- qcom,name = "l2";
- qcom,local-resource-type;
- qcom,init-value = "l2_cache_retention";
- };
- };
-
qcom,lpm-levels {
compatible = "qcom,lpm-levels";
+ qcom,default-l2-state = "l2_cache_retention";
#address-cells = <1>;
#size-cells = <0>;
- qcom,use-qtimer;
-
qcom,lpm-level@0 {
reg = <0x0>;
qcom,mode = "wfi";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_active";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
qcom,latency-us = <1>;
qcom,ss-power = <784>;
qcom,energy-overhead = <190000>;
@@ -196,14 +148,7 @@
qcom,lpm-level@1 {
reg = <0x1>;
qcom,mode = "retention";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_active";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
qcom,latency-us = <75>;
qcom,ss-power = <735>;
qcom,energy-overhead = <77341>;
@@ -214,14 +159,7 @@
qcom,lpm-level@2 {
reg = <0x2>;
qcom,mode = "standalone_pc";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_active";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
qcom,latency-us = <95>;
qcom,ss-power = <725>;
qcom,energy-overhead = <99500>;
@@ -231,15 +169,8 @@
qcom,lpm-level@3 {
reg = <0x3>;
qcom,mode = "pc";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_gdhs";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
- qcom,latency-us = <2000>;
+ qcom,latency-us = <20000>;
qcom,ss-power = <138>;
qcom,energy-overhead = <1208400>;
qcom,time-overhead = <3200>;
@@ -248,79 +179,12 @@
qcom,lpm-level@4 {
reg = <0x4>;
qcom,mode = "pc";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* SVS SOC */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
- qcom,latency-us = <3000>;
+ qcom,latency-us = <30000>;
qcom,ss-power = <110>;
qcom,energy-overhead = <1250300>;
qcom,time-overhead = <3500>;
};
-
- qcom,lpm-level@5 {
- reg = <0x5>;
- qcom,mode = "pc";
- qcom,xo = "xo_off";
- qcom,l2 = "l2_cache_gdhs";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,latency-us = <3000>;
- qcom,ss-power = <68>;
- qcom,energy-overhead = <1350200>;
- qcom,time-overhead = <4000>;
- };
-
- qcom,lpm-level@6 {
- reg = <0x6>;
- qcom,mode = "pc";
- qcom,xo = "xo_off";
- qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,latency-us = <10300>;
- qcom,ss-power = <63>;
- qcom,energy-overhead = <2128000>;
- qcom,time-overhead = <18200>;
- };
-
- qcom,lpm-level@7 {
- reg = <0x7>;
- qcom,mode= "pc";
- qcom,xo = "xo_off";
- qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <950000>; /* NORMAL */
- qcom,vdd-mem-lower-bound = <950000>; /* SVS SOC */
- qcom,vdd-dig-upper-bound = <4>; /* NORMAL */
- qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
- qcom,latency-us = <18000>;
- qcom,ss-power = <10>;
- qcom,energy-overhead = <3202600>;
- qcom,time-overhead = <27000>;
- };
-
- qcom,lpm-level@8 {
- reg = <0x8>;
- qcom,mode= "pc";
- qcom,xo = "xo_off";
- qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <950000>; /* SVS SOC */
- qcom,vdd-mem-lower-bound = <675000>; /* RETENTION */
- qcom,vdd-dig-upper-bound = <3>; /* SVS SOC */
- qcom,vdd-dig-lower-bound = <1>; /* RETENTION */
- qcom,latency-us = <20000>;
- qcom,ss-power = <2>;
- qcom,energy-overhead = <4252000>;
- qcom,time-overhead = <32000>;
- };
};
qcom,pm-boot {
diff --git a/arch/arm/boot/dts/msm8974-v1.dtsi b/arch/arm/boot/dts/msm8974-v1.dtsi
index caec2dc..7b801da 100644
--- a/arch/arm/boot/dts/msm8974-v1.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1.dtsi
@@ -17,6 +17,21 @@
*/
/include/ "msm8974.dtsi"
+
+/include/ "msm-pm8x41-rpm-regulator.dtsi"
+/include/ "msm-pm8841.dtsi"
+&spmi_bus {
+ pm8941_lsid0: qcom,pm8941@0 {
+ reg = <0x0>;
+ };
+ pm8941_lsid1: qcom,pm8941@1 {
+ reg = <0x1>;
+ };
+};
+/include/ "msm-pm8941.dtsi"
+/include/ "msm8974-regulator.dtsi"
+/include/ "msm8974-clock.dtsi"
+
/include/ "msm8974-v1-iommu.dtsi"
/include/ "msm8974-v1-iommu-domains.dtsi"
/include/ "msm8974-v1-pm.dtsi"
@@ -50,6 +65,7 @@
/* CoreSight */
&tmc_etr {
qcom,reset-flush-race;
+ qcom,byte-cntr-absent;
};
&stm {
diff --git a/arch/arm/boot/dts/msm8974-v2-cdp.dts b/arch/arm/boot/dts/msm8974-v2-cdp.dts
index 85d478b..f4014aa 100644
--- a/arch/arm/boot/dts/msm8974-v2-cdp.dts
+++ b/arch/arm/boot/dts/msm8974-v2-cdp.dts
@@ -22,15 +22,3 @@
<185 1 0x20000>,
<186 1 0x20000>;
};
-
-&usb3 {
- interrupt-parent = <&usb3>;
- interrupts = <0 1>;
- #interrupt-cells = <1>;
- interrupt-map-mask = <0x0 0xffffffff>;
- interrupt-map = <0x0 0 &intc 0 133 0
- 0x0 1 &spmi_bus 0x0 0x0 0x9 0x0>;
- interrupt-names = "hs_phy_irq", "pmic_id_irq";
-
- qcom,misc-ref = <&pm8941_misc>;
-};
diff --git a/arch/arm/boot/dts/msm8974-v2-fluid.dts b/arch/arm/boot/dts/msm8974-v2-fluid.dts
index d83d130..9c9e3c0 100644
--- a/arch/arm/boot/dts/msm8974-v2-fluid.dts
+++ b/arch/arm/boot/dts/msm8974-v2-fluid.dts
@@ -22,15 +22,3 @@
<185 3 0x20000>,
<186 3 0x20000>;
};
-
-&usb3 {
- interrupt-parent = <&usb3>;
- interrupts = <0 1>;
- #interrupt-cells = <1>;
- interrupt-map-mask = <0x0 0xffffffff>;
- interrupt-map = <0x0 0 &intc 0 133 0
- 0x0 1 &spmi_bus 0x0 0x0 0x9 0x0>;
- interrupt-names = "hs_phy_irq", "pmic_id_irq";
-
- qcom,misc-ref = <&pm8941_misc>;
-};
diff --git a/arch/arm/boot/dts/msm8974-v2-iommu.dtsi b/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
index 03f7e80..5efa17d 100644
--- a/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
@@ -42,14 +42,14 @@
0x2034
0x2038>;
- qcom,iommu-bfb-data = <0xFFFFFFFF
- 0xFFFFFFFF
- 0x00000004
- 0x00000008
- 0x00000000
- 0x00013205
- 0x00004000
- 0x00014020
+ qcom,iommu-bfb-data = <0xffffffff
+ 0xffffffff
+ 0x4
+ 0x8
+ 0x0
+ 0x13205
+ 0x4000
+ 0x14020
0x0
0x94
0x114
@@ -116,8 +116,8 @@
0x2010
0x2014>;
- qcom,iommu-bfb-data = <0x3FFF
- 0x00000000
+ qcom,iommu-bfb-data = <0xffff
+ 0x0
0x4
0x4
0x0
@@ -125,8 +125,8 @@
0x10
0x50
0x0
- 0x00002804
- 0x00009614
+ 0x2804
+ 0x9614
0x0
0x0
0x0
@@ -157,14 +157,14 @@
0x201c
0x2020>;
- qcom,iommu-bfb-data = <0xFFFFF
- 0x00000000
- 0x00000004
- 0x00000010
- 0x00000000
- 0x00006800
- 0x00006221
- 0x00016231
+ qcom,iommu-bfb-data = <0xffffffff
+ 0x0
+ 0x4
+ 0x10
+ 0x0
+ 0x6800
+ 0x6221
+ 0x16231
0x0
0x34
0x74
@@ -197,14 +197,14 @@
0x2414
0x2008>;
- qcom,iommu-bfb-data = <0x00000003
+ qcom,iommu-bfb-data = <0x3
0x0
- 0x00000004
- 0x00000010
- 0x00000000
- 0x00000000
- 0x00000000
- 0x00000020
+ 0x4
+ 0x10
+ 0x0
+ 0x0
+ 0x0
+ 0x20
0x0
0x1
0x81
@@ -236,7 +236,7 @@
0x2020>;
qcom,iommu-bfb-data = <0xffffffff
- 0x00000000
+ 0x0
0x4
0x8
0x0
@@ -244,8 +244,8 @@
0x20
0x78
0x0
- 0x00003c08
- 0x0000b41e
+ 0x3c08
+ 0xb41e
0x0
0x0
0x0
diff --git a/arch/arm/boot/dts/msm8974-v2-liquid.dts b/arch/arm/boot/dts/msm8974-v2-liquid.dts
index 53983dc..ddae6fe 100644
--- a/arch/arm/boot/dts/msm8974-v2-liquid.dts
+++ b/arch/arm/boot/dts/msm8974-v2-liquid.dts
@@ -22,15 +22,3 @@
<185 9 0x20000>,
<186 9 0x20000>;
};
-
-&usb3 {
- interrupt-parent = <&usb3>;
- interrupts = <0 1>;
- #interrupt-cells = <1>;
- interrupt-map-mask = <0x0 0xffffffff>;
- interrupt-map = <0x0 0 &intc 0 133 0
- 0x0 1 &spmi_bus 0x0 0x0 0x9 0x0>;
- interrupt-names = "hs_phy_irq", "pmic_id_irq";
-
- qcom,misc-ref = <&pm8941_misc>;
-};
diff --git a/arch/arm/boot/dts/msm8974-v2-mtp.dts b/arch/arm/boot/dts/msm8974-v2-mtp.dts
index 792a78c..021b626 100644
--- a/arch/arm/boot/dts/msm8974-v2-mtp.dts
+++ b/arch/arm/boot/dts/msm8974-v2-mtp.dts
@@ -23,18 +23,6 @@
<186 8 0x20000>;
};
-&usb3 {
- interrupt-parent = <&usb3>;
- interrupts = <0 1>;
- #interrupt-cells = <1>;
- interrupt-map-mask = <0x0 0xffffffff>;
- interrupt-map = <0x0 0 &intc 0 133 0
- 0x0 1 &spmi_bus 0x0 0x0 0x9 0x0>;
- interrupt-names = "hs_phy_irq", "pmic_id_irq";
-
- qcom,misc-ref = <&pm8941_misc>;
-};
-
&pm8941_chg {
qcom,bpd-detection = "bpd_thm";
};
diff --git a/arch/arm/boot/dts/msm8974-v2-pm.dtsi b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
index 686cdd8..1235c6e 100644
--- a/arch/arm/boot/dts/msm8974-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
@@ -125,64 +125,16 @@
50 02 32 50 0f];
};
- qcom,lpm-resources {
- compatible = "qcom,lpm-resources";
- #address-cells = <1>;
- #size-cells = <0>;
-
- qcom,lpm-resources@0 {
- reg = <0x0>;
- qcom,name = "vdd-dig";
- qcom,type = <0x62706d73>; /* "smpb" */
- qcom,id = <0x02>;
- qcom,key = <0x6e726f63>; /* "corn" */
- qcom,init-value = <6>; /* Super Turbo */
- };
-
- qcom,lpm-resources@1 {
- reg = <0x1>;
- qcom,name = "vdd-mem";
- qcom,type = <0x62706d73>; /* "smpb" */
- qcom,id = <0x01>;
- qcom,key = <0x7675>; /* "uv" */
- qcom,init-value = <1050000>; /* Super Turbo */
- };
-
- qcom,lpm-resources@2 {
- reg = <0x2>;
- qcom,name = "pxo";
- qcom,type = <0x306b6c63>; /* "clk0" */
- qcom,id = <0x00>;
- qcom,key = <0x62616e45>; /* "Enab" */
- qcom,init-value = "xo_on";
- };
-
- qcom,lpm-resources@3 {
- reg = <0x3>;
- qcom,name = "l2";
- qcom,local-resource-type;
- qcom,init-value = "l2_cache_retention";
- };
- };
-
qcom,lpm-levels {
compatible = "qcom,lpm-levels";
+ qcom,default-l2-state = "l2_cache_retention";
#address-cells = <1>;
#size-cells = <0>;
- qcom,use-qtimer;
-
qcom,lpm-level@0 {
reg = <0x0>;
qcom,mode = "wfi";
- qcom,xo = "xo_on";
- qcom,l2 = "l2_cache_active";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
+ qcom,l2 = "l2_cache_retention";
qcom,latency-us = <1>;
qcom,ss-power = <715>;
qcom,energy-overhead = <17700>;
@@ -192,14 +144,7 @@
qcom,lpm-level@1 {
reg = <0x1>;
qcom,mode = "retention";
- qcom,xo = "xo_on";
- qcom,l2 = "l2_cache_active";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
+ qcom,l2 = "l2_cache_retention";
qcom,latency-us = <35>;
qcom,ss-power = <542>;
qcom,energy-overhead = <34920>;
@@ -210,14 +155,7 @@
qcom,lpm-level@2 {
reg = <0x2>;
qcom,mode = "standalone_pc";
- qcom,xo = "xo_on";
- qcom,l2 = "l2_cache_active";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
+ qcom,l2 = "l2_cache_retention";
qcom,latency-us = <300>;
qcom,ss-power = <476>;
qcom,energy-overhead = <225300>;
@@ -226,81 +164,33 @@
qcom,lpm-level@3 {
reg = <0x3>;
- qcom,mode = "pc";
- qcom,xo = "xo_on";
+ qcom,mode = "standalone_pc";
qcom,l2 = "l2_cache_gdhs";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
- qcom,latency-us = <2817>;
- qcom,ss-power = <163>;
- qcom,energy-overhead = <1577736>;
- qcom,time-overhead = <5067>;
+ 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,xo = "xo_on";
- qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* SVS SOC */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
- qcom,irqs-detectable;
+ qcom,l2 = "l2_cache_gdhs";
qcom,gpio-detectable;
- qcom,latency-us = <3922>;
- qcom,ss-power = <83>;
- qcom,energy-overhead = <2274420>;
- qcom,time-overhead = <6605>;
+ 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,xo = "xo_off";
qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,latency-us = <4922>;
- qcom,ss-power = <68>;
- qcom,energy-overhead = <2568180>;
- qcom,time-overhead = <8812>;
- };
-
- qcom,lpm-level@6 {
- reg = <0x6>;
- qcom,mode= "pc";
- qcom,xo = "xo_off";
- qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <950000>; /* NORMAL */
- qcom,vdd-mem-lower-bound = <950000>; /* SVS SOC */
- qcom,vdd-dig-upper-bound = <4>; /* NORMAL */
- qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
- qcom,latency-us = <5890>;
- qcom,ss-power = <60>;
- qcom,energy-overhead = <2675900>;
- qcom,time-overhead = <10140>;
- };
-
- qcom,lpm-level@7 {
- reg = <0x7>;
- qcom,mode= "pc";
- qcom,xo = "xo_off";
- qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <950000>; /* SVS SOC */
- qcom,vdd-mem-lower-bound = <675000>; /* RETENTION */
- qcom,vdd-dig-upper-bound = <3>; /* SVS SOC */
- qcom,vdd-dig-lower-bound = <1>; /* RETENTION */
- qcom,latency-us = <8500>;
- qcom,ss-power = <18>;
- qcom,energy-overhead = <3286600>;
- qcom,time-overhead = <15760>;
+ qcom,latency-us = <30000>;
+ qcom,ss-power = <83>;
+ qcom,energy-overhead = <2274420>;
+ qcom,time-overhead = <6605>;
};
};
diff --git a/arch/arm/boot/dts/apq8026-xpm.dts b/arch/arm/boot/dts/msm8974-v2.2-cdp.dts
similarity index 69%
copy from arch/arm/boot/dts/apq8026-xpm.dts
copy to arch/arm/boot/dts/msm8974-v2.2-cdp.dts
index 67152af..c1f4a8b 100644
--- a/arch/arm/boot/dts/apq8026-xpm.dts
+++ b/arch/arm/boot/dts/msm8974-v2.2-cdp.dts
@@ -10,13 +10,15 @@
* GNU General Public License for more details.
*/
-
/dts-v1/;
-/include/ "apq8026.dtsi"
-/include/ "msm8226-cdp.dtsi"
+
+/include/ "msm8974-v2.2.dtsi"
+/include/ "msm8974-cdp.dtsi"
/ {
- model = "Qualcomm APQ 8026 XPM";
- compatible = "qcom,apq8026-xpm", "qcom,apq8026", "qcom,xpm";
- qcom,msm-id = <199 14 0>;
+ model = "Qualcomm MSM 8974v2.2 CDP";
+ compatible = "qcom,msm8974-cdp", "qcom,msm8974", "qcom,cdp";
+ qcom,msm-id = <126 1 0x20002>,
+ <185 1 0x20002>,
+ <186 1 0x20002>;
};
diff --git a/arch/arm/boot/dts/apq8026-xpm.dts b/arch/arm/boot/dts/msm8974-v2.2-fluid.dts
similarity index 68%
copy from arch/arm/boot/dts/apq8026-xpm.dts
copy to arch/arm/boot/dts/msm8974-v2.2-fluid.dts
index 67152af..207db37 100644
--- a/arch/arm/boot/dts/apq8026-xpm.dts
+++ b/arch/arm/boot/dts/msm8974-v2.2-fluid.dts
@@ -10,13 +10,15 @@
* GNU General Public License for more details.
*/
-
/dts-v1/;
-/include/ "apq8026.dtsi"
-/include/ "msm8226-cdp.dtsi"
+
+/include/ "msm8974-v2.2.dtsi"
+/include/ "msm8974-fluid.dtsi"
/ {
- model = "Qualcomm APQ 8026 XPM";
- compatible = "qcom,apq8026-xpm", "qcom,apq8026", "qcom,xpm";
- qcom,msm-id = <199 14 0>;
+ model = "Qualcomm MSM 8974v2.2 FLUID";
+ compatible = "qcom,msm8974-fluid", "qcom,msm8974", "qcom,fluid";
+ qcom,msm-id = <126 3 0x20002>,
+ <185 3 0x20002>,
+ <186 3 0x20002>;
};
diff --git a/arch/arm/boot/dts/apq8026-xpm.dts b/arch/arm/boot/dts/msm8974-v2.2-liquid.dts
similarity index 68%
copy from arch/arm/boot/dts/apq8026-xpm.dts
copy to arch/arm/boot/dts/msm8974-v2.2-liquid.dts
index 67152af..36e6e9c 100644
--- a/arch/arm/boot/dts/apq8026-xpm.dts
+++ b/arch/arm/boot/dts/msm8974-v2.2-liquid.dts
@@ -10,13 +10,15 @@
* GNU General Public License for more details.
*/
-
/dts-v1/;
-/include/ "apq8026.dtsi"
-/include/ "msm8226-cdp.dtsi"
+
+/include/ "msm8974-v2.2.dtsi"
+/include/ "msm8974-liquid.dtsi"
/ {
- model = "Qualcomm APQ 8026 XPM";
- compatible = "qcom,apq8026-xpm", "qcom,apq8026", "qcom,xpm";
- qcom,msm-id = <199 14 0>;
+ model = "Qualcomm MSM 8974v2.2 LIQUID";
+ compatible = "qcom,msm8974-liquid", "qcom,msm8974", "qcom,liquid";
+ qcom,msm-id = <126 9 0x20002>,
+ <185 9 0x20002>,
+ <186 9 0x20002>;
};
diff --git a/arch/arm/boot/dts/apq8026-xpm.dts b/arch/arm/boot/dts/msm8974-v2.2-mtp.dts
similarity index 65%
copy from arch/arm/boot/dts/apq8026-xpm.dts
copy to arch/arm/boot/dts/msm8974-v2.2-mtp.dts
index 67152af..0593f6e 100644
--- a/arch/arm/boot/dts/apq8026-xpm.dts
+++ b/arch/arm/boot/dts/msm8974-v2.2-mtp.dts
@@ -10,13 +10,19 @@
* GNU General Public License for more details.
*/
-
/dts-v1/;
-/include/ "apq8026.dtsi"
-/include/ "msm8226-cdp.dtsi"
+
+/include/ "msm8974-v2.2.dtsi"
+/include/ "msm8974-mtp.dtsi"
/ {
- model = "Qualcomm APQ 8026 XPM";
- compatible = "qcom,apq8026-xpm", "qcom,apq8026", "qcom,xpm";
- qcom,msm-id = <199 14 0>;
+ model = "Qualcomm MSM 8974v2.2 MTP";
+ compatible = "qcom,msm8974-mtp", "qcom,msm8974", "qcom,mtp";
+ qcom,msm-id = <126 8 0x20002>,
+ <185 8 0x20002>,
+ <186 8 0x20002>;
+};
+
+&pm8941_chg {
+ qcom,bpd-detection = "bpd_thm";
};
diff --git a/arch/arm/boot/dts/msm8974-v2.2.dtsi b/arch/arm/boot/dts/msm8974-v2.2.dtsi
new file mode 100644
index 0000000..09455b1
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-v2.2.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.
+ */
+
+/*
+ * As a general rule, only version-specific property overrides should be placed
+ * inside this file. However, device definitions should be placed inside the
+ * msm8974.dtsi file.
+ */
+
+/include/ "msm8974-v2.dtsi"
+
+/* GPU overrides */
+&msm_gpu {
+ /* Updated chip ID */
+ qcom,chipid = <0x03030001>;
+
+ qcom,initial-pwrlevel = <4>;
+
+ /* Updated bus bandwidth requirements */
+ qcom,msm-bus,vectors-KBps =
+ /* Off */
+ <26 512 0 0>, <89 604 0 0>,
+ /* 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>;
+
+ qcom,gpu-pwrlevels {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ compatible = "qcom,gpu-pwrlevels";
+
+ qcom,gpu-pwrlevel@0 {
+ reg = <0>;
+ qcom,gpu-freq = <450000000>;
+ qcom,bus-freq = <5>;
+ qcom,io-fraction = <33>;
+ };
+
+ qcom,gpu-pwrlevel@1 {
+ reg = <1>;
+ qcom,gpu-freq = <389000000>;
+ qcom,bus-freq = <4>;
+ qcom,io-fraction = <33>;
+ };
+
+ qcom,gpu-pwrlevel@2 {
+ reg = <2>;
+ qcom,gpu-freq = <389000000>;
+ qcom,bus-freq = <3>;
+ 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-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 0240039..0b3b60f 100644
--- a/arch/arm/boot/dts/msm8974-v2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.dtsi
@@ -17,6 +17,21 @@
*/
/include/ "msm8974.dtsi"
+
+/include/ "msm-pm8x41-rpm-regulator.dtsi"
+/include/ "msm-pm8841.dtsi"
+&spmi_bus {
+ pm8941_lsid0: qcom,pm8941@0 {
+ reg = <0x0>;
+ };
+ pm8941_lsid1: qcom,pm8941@1 {
+ reg = <0x1>;
+ };
+};
+/include/ "msm-pm8941.dtsi"
+/include/ "msm8974-regulator.dtsi"
+/include/ "msm8974-clock.dtsi"
+
/include/ "msm8974-v2-iommu.dtsi"
/include/ "msm8974-v2-iommu-domains.dtsi"
/include/ "msm8974-v2-pm.dtsi"
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 068f581..59e8dac 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -227,7 +227,7 @@
status = "disabled";
};
- serial@f991e000 {
+ blsp1_uart1: serial@f991e000 {
compatible = "qcom,msm-lsuart-v14";
reg = <0xf991e000 0x1000>;
interrupts = <0 108 0>;
@@ -258,6 +258,8 @@
qcom,hsusb-otg-mode = <1>;
qcom,hsusb-otg-otg-control = <1>;
qcom,hsusb-otg-disable-reset;
+ qcom,hsusb-otg-mpm-dpsehv-int = <49>;
+ qcom,hsusb-otg-mpm-dmsehv-int = <58>;
qcom,msm-bus,name = "usb2";
qcom,msm-bus,num-cases = <2>;
@@ -585,11 +587,11 @@
spi-max-frequency = <19200000>;
#address-cells = <1>;
#size-cells = <0>;
- gpios = <&msmgpio 56 0>, /* CLK */
- <&msmgpio 54 0>, /* MISO */
- <&msmgpio 53 0>; /* MOSI */
- cs-gpios = <&msmgpio 55 0>;
qcom,master-id = <84>;
+ qcom,gpio-mosi = <&msmgpio 53 0>;
+ qcom,gpio-miso = <&msmgpio 54 0>;
+ qcom,gpio-clk = <&msmgpio 56 0>;
+ qcom,gpio-cs0 = <&msmgpio 55 0>;
};
tspp: msm_tspp@f99d8000 {
@@ -648,6 +650,8 @@
reg-names = "slimbus_physical", "slimbus_bam_physical";
interrupts = <0 163 0 0 164 0>;
interrupt-names = "slimbus_irq", "slimbus_bam_irq";
+ qcom,apps-ch-pipes = <0x60000000>;
+ qcom,ea-pc = <0x30>;
taiko_codec {
compatible = "qcom,taiko-slim-pgd";
@@ -819,11 +823,11 @@
spi-max-frequency = <19200000>;
#address-cells = <1>;
#size-cells = <0>;
- gpios = <&msmgpio 3 0>, /* CLK */
- <&msmgpio 1 0>, /* MISO */
- <&msmgpio 0 0>; /* MOSI */
- cs-gpios = <&msmgpio 9 0>;
qcom,master-id = <86>;
+ qcom,gpio-mosi = <&msmgpio 0 0>;
+ qcom,gpio-miso = <&msmgpio 1 0>;
+ qcom,gpio-clk = <&msmgpio 3 0>;
+ qcom,gpio-cs2 = <&msmgpio 9 0>;
};
qcom,acpuclk@f9000000 {
@@ -854,8 +858,15 @@
#address-cells = <1>;
#size-cells = <1>;
ranges;
- interrupts = <0 133 0>;
- interrupt-names = "hs_phy_irq";
+
+ interrupt-parent = <&usb3>;
+ interrupts = <0 1>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0x0 0xffffffff>;
+ interrupt-map = <0x0 0 &intc 0 133 0
+ 0x0 1 &spmi_bus 0x0 0x0 0x9 0x0>;
+ interrupt-names = "hs_phy_irq", "pmic_id_irq";
+
ssusb_vdd_dig-supply = <&pm8841_s2_corner>;
SSUSB_1p8-supply = <&pm8941_l6>;
hsusb_vdd_dig-supply = <&pm8841_s2_corner>;
@@ -865,6 +876,7 @@
qcom,dwc-usb3-msm-dbm-eps = <4>;
qcom,vdd-voltage-level = <1 5 7>;
qcom,dwc-hsphy-init = <0x00D191A4>;
+ qcom,misc-ref = <&pm8941_misc>;
qcom,msm-bus,name = "usb3";
qcom,msm-bus,num-cases = <2>;
@@ -1092,9 +1104,8 @@
};
};
- qcom,msm-auxpcm {
- compatible = "qcom,msm-auxpcm-resource";
- qcom,msm-cpudai-auxpcm-clk = "pcm_clk";
+ qcom,msm-pri-auxpcm {
+ compatible = "qcom,msm-auxpcm-dev";
qcom,msm-cpudai-auxpcm-mode = <0>, <0>;
qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
@@ -1102,26 +1113,19 @@
qcom,msm-cpudai-auxpcm-slot = <1>, <1>;
qcom,msm-cpudai-auxpcm-data = <0>, <0>;
qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
+ qcom,msm-auxpcm-interface = "primary";
+ };
- qcom,msm-prim-auxpcm-rx {
- qcom,msm-auxpcm-dev-id = <4106>;
- compatible = "qcom,msm-auxpcm-dev";
- };
-
- qcom,msm-prim-auxpcm-tx {
- qcom,msm-auxpcm-dev-id = <4107>;
- compatible = "qcom,msm-auxpcm-dev";
- };
-
- qcom,msm-sec-auxpcm-rx {
- qcom,msm-auxpcm-dev-id = <4108>;
- compatible = "qcom,msm-auxpcm-dev";
- };
-
- qcom,msm-sec-auxpcm-tx {
- qcom,msm-auxpcm-dev-id = <4109>;
- compatible = "qcom,msm-auxpcm-dev";
- };
+ qcom,msm-sec-auxpcm {
+ compatible = "qcom,msm-auxpcm-dev";
+ qcom,msm-cpudai-auxpcm-mode = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
+ qcom,msm-cpudai-auxpcm-quant = <2>, <2>;
+ qcom,msm-cpudai-auxpcm-slot = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-data = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
+ qcom,msm-auxpcm-interface = "secondary";
};
qcom,msm-dai-mi2s {
@@ -1282,9 +1286,9 @@
<1 618 0 800>;
};
- qseecom: qcom,qseecom@7f00000 {
+ qseecom: qcom,qseecom@7b00000 {
compatible = "qcom,qseecom";
- reg = <0x7f00000 0x500000>;
+ reg = <0x7b00000 0x500000>;
reg-names = "secapp-region";
qcom,disk-encrypt-pipe-pair = <2>;
qcom,hlos-ce-hw-instance = <1>;
@@ -1360,7 +1364,7 @@
tsens: tsens@fc4a8000 {
compatible = "qcom,msm-tsens";
reg = <0xfc4a8000 0x2000>,
- <0xfc4b8000 0x1000>;
+ <0xfc4bc000 0x1000>;
reg-names = "tsens_physical", "tsens_eeprom_physical";
interrupts = <0 184 0>;
qcom,sensors = <11>;
@@ -1369,6 +1373,12 @@
qcom,calib-mode = "fuse_map1";
};
+ jtag_fuse: jtagfuse@fc4be024 {
+ compatible = "qcom,jtag-fuse";
+ reg = <0xfc4be024 0x8>;
+ reg-names = "fuse-base";
+ };
+
qcom,msm-rtb {
compatible = "qcom,msm-rtb";
qcom,memory-reservation-type = "EBI1";
@@ -1477,24 +1487,24 @@
qcom,vdd-restriction-temp-hysteresis = <10>;
qcom,pmic-sw-mode-temp = <85>;
qcom,pmic-sw-mode-temp-hysteresis = <75>;
- qcom,pmic-sw-mode-regs = "vdd_dig";
- vdd_dig-supply = <&pm8841_s2_floor_corner>;
- vdd_gfx-supply = <&pm8841_s4_floor_corner>;
+ qcom,pmic-sw-mode-regs = "vdd-dig";
+ vdd-dig-supply = <&pm8841_s2_floor_corner>;
+ vdd-gfx-supply = <&pm8841_s4_floor_corner>;
qcom,vdd-dig-rstr{
- qcom,vdd-rstr-reg = "vdd_dig";
+ qcom,vdd-rstr-reg = "vdd-dig";
qcom,levels = <5 7 7>; /* Nominal, Super Turbo, Super Turbo */
qcom,min-level = <1>; /* No Request */
};
qcom,vdd-gfx-rstr{
- qcom,vdd-rstr-reg = "vdd_gfx";
+ qcom,vdd-rstr-reg = "vdd-gfx";
qcom,levels = <5 7 7>; /* Nominal, Super Turbo, Super Turbo */
qcom,min-level = <1>; /* No Request */
};
qcom,vdd-apps-rstr{
- qcom,vdd-rstr-reg = "vdd_apps";
+ qcom,vdd-rstr-reg = "vdd-apps";
qcom,levels = <1881600 1958400 2265600>;
qcom,freq-req;
};
@@ -1509,7 +1519,7 @@
memory_hole: qcom,msm-mem-hole {
compatible = "qcom,msm-mem-hole";
- qcom,memblock-remove = <0x7f00000 0x8000000>; /* Address and Size of Hole */
+ qcom,memblock-remove = <0x7b00000 0x8400000>; /* Address and Size of Hole */
};
uart7: uart@f995d000 { /*BLSP #2, UART #7 */
@@ -1518,8 +1528,15 @@
reg = <0xf995d000 0x1000>,
<0xf9944000 0x19000>;
reg-names = "core_mem", "bam_mem";
- interrupts = <0 113 0>, <0 239 0>;
- interrupt-names = "core_irq", "bam_irq";
+ interrupt-names = "core_irq", "bam_irq", "wakeup_irq";
+ #address-cells = <0>;
+ interrupt-parent = <&uart7>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 113 0
+ 1 &intc 0 239 0
+ 2 &msmgpio 42 0>;
qcom,bam-tx-ep-pipe-index = <0>;
qcom,bam-rx-ep-pipe-index = <1>;
@@ -1673,9 +1690,3 @@
&gdsc_usb_hsic {
status = "ok";
};
-
-/include/ "msm-pm8x41-rpm-regulator.dtsi"
-/include/ "msm-pm8841.dtsi"
-/include/ "msm-pm8941.dtsi"
-/include/ "msm8974-regulator.dtsi"
-/include/ "msm8974-clock.dtsi"
diff --git a/arch/arm/boot/dts/msm8974pro-ab-mtp.dts b/arch/arm/boot/dts/msm8974pro-ab-mtp.dts
index 002baf7..d1566ae 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-mtp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ab-mtp.dts
@@ -26,3 +26,7 @@
<217 8 0x10000>,
<218 8 0x10000>;
};
+
+&sdhc_1 {
+ qcom,clk-rates = <400000 20000000 25000000 50000000 100000000>;
+};
diff --git a/arch/arm/boot/dts/msm8974pro-ab.dtsi b/arch/arm/boot/dts/msm8974pro-ab.dtsi
index 9240514..88687bd 100644
--- a/arch/arm/boot/dts/msm8974pro-ab.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-ab.dtsi
@@ -17,3 +17,25 @@
*/
/include/ "msm8974pro.dtsi"
+
+/include/ "msm-pm8x41-rpm-regulator.dtsi"
+/include/ "msm-pm8841.dtsi"
+&spmi_bus {
+ pm8941_lsid0: qcom,pm8941@0 {
+ reg = <0x0>;
+ };
+ pm8941_lsid1: qcom,pm8941@1 {
+ reg = <0x1>;
+ };
+};
+/include/ "msm-pm8941.dtsi"
+/include/ "msm8974-regulator.dtsi"
+/include/ "msm8974-clock.dtsi"
+
+&krait_pdn {
+ qcom,use-phase-switching;
+};
+
+&tspp {
+ vdd_cx-supply = <&pm8841_s2_corner>;
+};
diff --git a/arch/arm/boot/dts/msm8974pro-ac-mtp.dts b/arch/arm/boot/dts/msm8974pro-ac-mtp.dts
index c5042b7..b8df576 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-mtp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ac-mtp.dts
@@ -12,8 +12,8 @@
/dts-v1/;
-/include/ "msm8974pro-ac.dtsi"
-/include/ "msm8974-mtp.dtsi"
+/include/ "msm8974pro-ac-pm8941.dtsi"
+/include/ "msm8974pro-ac-mtp.dtsi"
/ {
model = "Qualcomm MSM 8974Pro-AC MTP";
@@ -23,3 +23,7 @@
<213 8 0x10000>,
<216 8 0x10000>;
};
+
+&sdhc_1 {
+ qcom,clk-rates = <400000 20000000 25000000 50000000 100000000>;
+};
diff --git a/arch/arm/boot/dts/msm8974pro-ac-mtp.dtsi b/arch/arm/boot/dts/msm8974pro-ac-mtp.dtsi
new file mode 100644
index 0000000..250afd2
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974pro-ac-mtp.dtsi
@@ -0,0 +1,302 @@
+/* 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/ "msm8974-mtp.dtsi"
+
+&cci {
+ qcom,camera@6e {
+ qcom,vdd-cx-supply = <&pma8084_s2>;
+ cam_vdig-supply = <&pma8084_l3>;
+ cam_vana-supply = <&pma8084_l17>;
+ cam_vio-supply = <&pma8084_lvs4>;
+ cam_vaf-supply = <&pma8084_l23>;
+ };
+
+ qcom,camera@20 {
+ qcom,vdd-cx-supply = <&pma8084_s2>;
+ cam_vdig-supply = <&pma8084_l3>;
+ cam_vana-supply = <&pma8084_l17>;
+ cam_vio-supply = <&pma8084_lvs4>;
+ cam_vaf-supply = <&pma8084_l23>;
+ };
+
+ qcom,camera@6c {
+ qcom,vdd-cx-supply = <&pma8084_s2>;
+ cam_vdig-supply = <&pma8084_l3>;
+ cam_vana-supply = <&pma8084_l17>;
+ cam_vio-supply = <&pma8084_lvs4>;
+ };
+
+ qcom,camera@90 {
+ qcom,vdd-cx-supply = <&pma8084_s2>;
+ cam_vdig-supply = <&pma8084_l3>;
+ cam_vana-supply = <&pma8084_l17>;
+ cam_vio-supply = <&pma8084_lvs4>;
+ };
+};
+
+&soc {
+ i2c@f9924000 {
+ atmel_mxt_ts@4a {
+ vdd_ana-supply = <&pma8084_l18>;
+ vcc_i2c-supply = <&pma8084_lvs1>;
+ };
+ };
+
+ i2c@f9967000 {
+ isa1200@48 {
+ vcc_i2c-supply = <&pma8084_s4>;
+ };
+ };
+
+ qcom,ssusb@f9200000 {
+ vbus_dwc3-supply = <&pm8941_mvs1>;
+ };
+
+ qcom,mdss_dsi_toshiba_720p_video {
+ qcom,rst-gpio = <&pma8084_gpios 20 0>;
+ };
+
+ gpio_keys {
+ camera_snapshot {
+ gpios = <&pma8084_gpios 3 0x1>;
+ };
+
+ camera_focus {
+ gpios = <&pma8084_gpios 4 0x1>;
+ };
+
+ vol_up {
+ gpios = <&pma8084_gpios 5 0x1>;
+ };
+ };
+
+ spi@f9923000 {
+ ethernet-switch@2 {
+ rst-gpio = <&pma8084_mpps 6 0>;
+ };
+ };
+};
+
+&sdhc_1 {
+ vdd-supply = <&pma8084_l20>;
+ vdd-io-supply = <&pma8084_s4>;
+};
+
+&sdhc_2 {
+ vdd-supply = <&pma8084_l21>;
+ vdd-io-supply = <&pma8084_l13>;
+};
+
+&pma8084_gpios {
+ gpio@c000 { /* GPIO 1 */
+ /* Unused */
+ qcom,mode = <0>; /* Digital input */
+ qcom,pull = <0>; /* Pull up 30 uA */
+ qcom,master-en = <1>;
+ };
+
+ gpio@c100 { /* GPIO 2 */
+ /* Unused */
+ qcom,mode = <0>; /* Digital input */
+ qcom,pull = <0>; /* Pull up 30 uA */
+ qcom,master-en = <1>;
+ };
+
+ gpio@c200 { /* GPIO 3 */
+ /* Snapshot button */
+ qcom,mode = <0>; /* Digital input */
+ qcom,pull = <0>; /* Pull up 30 uA */
+ qcom,vin-sel = <2>; /* PMA8084 S4 = 1.8 V */
+ qcom,src-sel = <0>; /* Constant */
+ qcom,master-en = <1>;
+ };
+
+ gpio@c300 { /* GPIO 4 */
+ /* Focus button */
+ qcom,mode = <0>; /* Digital input */
+ qcom,pull = <0>; /* Pull up 30 uA */
+ qcom,vin-sel = <2>; /* PMA8084 S4 = 1.8 V */
+ qcom,src-sel = <0>; /* Constant */
+ qcom,master-en = <1>;
+ };
+
+ gpio@c400 { /* GPIO 5 */
+ /* Volume up button */
+ qcom,mode = <0>; /* Digital input */
+ qcom,pull = <0>; /* Pull up 30 uA */
+ qcom,vin-sel = <2>; /* PMA8084 S4 = 1.8 V */
+ qcom,src-sel = <0>; /* Constant */
+ qcom,master-en = <1>;
+ };
+
+ gpio@c500 { /* GPIO 6 */
+ /* Flash LED now */
+ qcom,mode = <0>; /* Digital input */
+ qcom,pull = <4>; /* Pull down */
+ qcom,master-en = <1>;
+ };
+
+ gpio@c600 { /* GPIO 7 */
+ /* GRFC_12 */
+ };
+
+ gpio@c700 { /* GPIO 8 */
+ /* Unused */
+ qcom,mode = <0>; /* Digital input */
+ qcom,pull = <0>; /* Pull up 30 uA */
+ qcom,master-en = <1>;
+ };
+
+ gpio@c800 { /* GPIO 9 */
+ /* Unused */
+ qcom,mode = <1>; /* Digital output */
+ qcom,out-strength = <1>; /* Low */
+ qcom,src-sel = <2>; /* Function 1 */
+ qcom,master-en = <1>;
+ };
+
+ gpio@c900 { /* GPIO 10 */
+ /* NFC clock request */
+ qcom,mode = <0>; /* Digital input */
+ qcom,pull = <4>; /* Pull down */
+ qcom,master-en = <1>;
+ };
+
+ gpio@ca00 { /* GPIO 11 */
+ /* Unused */
+ qcom,mode = <1>; /* Digital output */
+ qcom,out-strength = <1>; /* Low */
+ qcom,src-sel = <2>; /* Function 1 */
+ qcom,master-en = <1>;
+ };
+
+ gpio@cb00 { /* GPIO 12 */
+ /* Unused */
+ qcom,mode = <1>; /* Digital output */
+ qcom,out-strength = <1>; /* Low */
+ qcom,src-sel = <2>; /* Function 1 */
+ qcom,master-en = <1>;
+ };
+
+ gpio@cc00 { /* GPIO 13 */
+ /* TS_CHGR_IN */
+ qcom,mode = <0>; /* Digital input */
+ qcom,pull = <4>; /* Pull down */
+ qcom,master-en = <1>;
+ };
+
+ gpio@cd00 { /* GPIO 14 */
+ /* Unused */
+ qcom,mode = <1>; /* Digital output */
+ qcom,out-strength = <1>; /* Low */
+ qcom,src-sel = <2>; /* Function 1 */
+ qcom,master-en = <1>;
+ };
+
+ gpio@ce00 { /* GPIO 15 */
+ /* Codec clock */
+ qcom,mode = <1>; /* Digital output */
+ qcom,output-type = <0>; /* CMOS */
+ qcom,vin-sel = <2>; /* PMA8084 S4 = 1.8 V */
+ qcom,out-strength = <1>; /* Low */
+ qcom,src-sel = <2>; /* Function 1 - DIVCLK1 */
+ qcom,master-en = <1>;
+ };
+
+ gpio@cf00 { /* GPIO 16 */
+ /* Haptics clock */
+ qcom,mode = <1>; /* Digital output */
+ qcom,output-type = <0>; /* CMOS */
+ qcom,vin-sel = <2>; /* PMA8084 S4 = 1.8 V */
+ qcom,out-strength = <3>; /* High */
+ qcom,src-sel = <3>; /* Function 2 - SLEEPCLK3 */
+ qcom,master-en = <1>;
+ };
+
+ gpio@d000 { /* GPIO 17 */
+ /* QPA clock */
+ };
+
+ gpio@d100 { /* GPIO 18 */
+ /* Unused */
+ };
+
+ gpio@d200 { /* GPIO 19 */
+ /* BOOST_BYP */
+ };
+
+ gpio@d300 { /* GPIO 20 */
+ /* Display enable */
+ qcom,mode = <1>; /* Digital output */
+ qcom,output-type = <0>; /* CMOS */
+ qcom,vin-sel = <2>; /* PMA8084 S4 = 1.8 V */
+ qcom,out-strength = <1>; /* Low */
+ qcom,src-sel = <0>; /* Constant */
+ qcom,master-en = <1>;
+ };
+
+ gpio@d400 { /* GPIO 21 */
+ /* BATT_GONE */
+ };
+
+ gpio@d500 { /* GPIO 22 */
+ /* BATT_REM_ALARM */
+ };
+};
+
+&pma8084_mpps {
+ mpp@a000 { /* MPP 1 */
+ /* SDC_UIM_VBIAS */
+ status = "disabled";
+ };
+
+ mpp@a100 { /* MPP 2 */
+ /* PM8941_PON_1 */
+ };
+
+ mpp@a200 { /* MPP 3 */
+ /* VREF_DAC */
+ };
+
+ mpp@a300 { /* MPP 4 */
+ /* Unused */
+ };
+
+ mpp@a400 { /* MPP 5 */
+ /* Unused */
+ };
+
+ mpp@a500 { /* MPP 6 */
+ /* SPI ethernet enable */
+ qcom,mode = <1>; /* Digital output */
+ qcom,output-type = <0>; /* CMOS */
+ qcom,vin-sel = <2>; /* PMA8084 S4 = 1.8V > 1.6V */
+ qcom,src-sel = <0>; /* Constant */
+ qcom,out-strength = <1>; /* Low */
+ qcom,master-en = <1>;
+ };
+
+ mpp@a600 { /* MPP 7 */
+ /* NFC disable */
+ qcom,mode = <1>; /* Digital output */
+ qcom,out-strength = <1>; /* Low */
+ qcom,master-en = <1>;
+ };
+
+ mpp@a700 { /* MPP 8 */
+ /* Unused */
+ qcom,mode = <1>; /* Digital output */
+ qcom,out-strength = <1>; /* Low */
+ qcom,master-en = <1>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974pro-ac-pm8941.dtsi b/arch/arm/boot/dts/msm8974pro-ac-pm8941.dtsi
new file mode 100644
index 0000000..4d10ded
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974pro-ac-pm8941.dtsi
@@ -0,0 +1,250 @@
+/* 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/ "msm8974pro-ac.dtsi"
+&spmi_bus {
+ pm8941_lsid0: qcom,pm8941@2 {
+ reg = <0x2>;
+ };
+ pm8941_lsid1: qcom,pm8941@3 {
+ reg = <0x3>;
+ };
+};
+/include/ "msm-pm8941.dtsi"
+
+&pma8084_vadc {
+ status = "disabled";
+};
+
+&pma8084_adc_tm {
+ status = "disabled";
+};
+
+&pm8941_lsid0 {
+ qcom,power-on@800 {
+ status = "disabled";
+ };
+
+ clkdiv@5b00 {
+ status = "disabled";
+ };
+
+ clkdiv@5c00 {
+ status = "disabled";
+ };
+
+ clkdiv@5d00 {
+ status = "disabled";
+ };
+
+ qcom,pm8941_rtc {
+ status = "disabled";
+ };
+
+ gpios {
+ status = "disabled";
+ };
+
+ mpps {
+ status = "disabled";
+ };
+};
+
+&pm8941_lsid1 {
+ pm8941_boost: regulator@a000 {
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ qcom,enable-time = <500>;
+ status = "okay";
+ };
+
+ pm8941_mvs1: regulator@8300 {
+ parent-supply = <&pm8941_chg_otg>;
+ qcom,enable-time = <1000>;
+ qcom,pull-down-enable = <1>;
+ interrupts = <0x3 0x83 0x2>;
+ interrupt-names = "ocp";
+ qcom,ocp-enable = <1>;
+ qcom,ocp-max-retries = <10>;
+ qcom,ocp-retry-delay = <30>;
+ qcom,soft-start-enable = <1>;
+ qcom,vs-soft-start-strength = <0>;
+ qcom,hpm-enable = <1>;
+ qcom,auto-mode-enable = <0>;
+ status = "okay";
+ };
+};
+
+&pma8084_mvs1 {
+ parent-supply = <&pm8941_boost>;
+};
+
+&pm8941_chg {
+ otg-parent-supply = <&pm8941_boost>;
+};
+
+&pm8941_chg_boost {
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-name = "8941_smbb_boost";
+};
+
+&pm8941_chg_otg {
+ regulator-name = "8941_smbb_otg";
+};
+
+/* Correct PM8941 local slave ID 0 to use global SID 4 for all interrupts. */
+&pm8941_lsid0 {
+ qcom,temp-alarm@2400 {
+ interrupts = <0x2 0x24 0x0>;
+ };
+
+ qcom,power-on@800 {
+ interrupts = <0x2 0x8 0x0>,
+ <0x2 0x8 0x1>,
+ <0x2 0x8 0x4>,
+ <0x2 0x8 0x5>;
+ interrupt-names = "kpdpwr", "resin",
+ "resin-bark", "kpdpwr-resin-bark";
+ };
+
+ qcom,bsi@1b00 {
+ interrupts = <0x2 0x1b 0x0>,
+ <0x2 0x1b 0x1>,
+ <0x2 0x1b 0x2>,
+ <0x2 0x12 0x0>;
+ interrupt-names = "err",
+ "rx",
+ "tx",
+ "batt-present";
+ };
+
+ qcom,bms {
+ qcom,bms-bms@4000 {
+ interrupts = <0x2 0x40 0x0>,
+ <0x2 0x40 0x1>,
+ <0x2 0x40 0x2>,
+ <0x2 0x40 0x3>,
+ <0x2 0x40 0x4>,
+ <0x2 0x40 0x5>,
+ <0x2 0x40 0x6>,
+ <0x2 0x40 0x7>;
+ interrupt-names = "cc_thr",
+ "ocv_for_r",
+ "good_ocv",
+ "charge_begin",
+ "ocv_thr",
+ "sw_cc_thr",
+ "vsense_avg",
+ "vsense_for_r";
+ };
+ };
+
+ qcom,charger {
+ qcom,chgr@1000 {
+ interrupts = <0x2 0x10 0x0>,
+ <0x2 0x10 0x1>,
+ <0x2 0x10 0x2>,
+ <0x2 0x10 0x3>,
+ <0x2 0x10 0x4>,
+ <0x2 0x10 0x5>,
+ <0x2 0x10 0x6>,
+ <0x2 0x10 0x7>;
+ interrupt-names = "vbat-det-lo",
+ "vbat-det-hi",
+ "chgwdog",
+ "state-change",
+ "trkl-chg-on",
+ "fast-chg-on",
+ "chg-failed",
+ "chg-done";
+ };
+
+ qcom,buck@1100 {
+ interrupts = <0x2 0x11 0x0>,
+ <0x2 0x11 0x1>,
+ <0x2 0x11 0x2>,
+ <0x2 0x11 0x3>,
+ <0x2 0x11 0x4>,
+ <0x2 0x11 0x5>,
+ <0x2 0x11 0x6>;
+ interrupt-names = "vbat-ov",
+ "vreg-ov",
+ "overtemp",
+ "vchg-loop",
+ "ichg-loop",
+ "ibat-loop",
+ "vdd-loop";
+ };
+
+ qcom,bat-if@1200 {
+ interrupts = <0x2 0x12 0x0>,
+ <0x2 0x12 0x1>,
+ <0x2 0x12 0x2>,
+ <0x2 0x12 0x3>,
+ <0x2 0x12 0x4>;
+ interrupt-names = "batt-pres",
+ "bat-temp-ok",
+ "bat-fet-on",
+ "vcp-on",
+ "psi";
+ };
+
+ qcom,usb-chgpth@1300 {
+ interrupts = <0x2 0x13 0x0>,
+ <0x2 0x13 0x1>,
+ <0x2 0x13 0x2>;
+ interrupt-names = "coarse-det-usb",
+ "usbin-valid",
+ "chg-gone";
+ };
+
+ qcom,dc-chgpth@1400 {
+ interrupts = <0x2 0x14 0x0>,
+ <0x2 0x14 0x1>;
+ interrupt-names = "coarse-det-dc",
+ "dcin-valid";
+ };
+
+ qcom,boost@1500 {
+ interrupts = <0x2 0x15 0x0>,
+ <0x2 0x15 0x1>;
+ interrupt-names = "boost-pwr-ok",
+ "limit-error";
+ };
+ };
+
+ qcom,pm8941_rtc {
+ qcom,pm8941_rtc_alarm@6100 {
+ interrupts = <0x2 0x61 0x1>;
+ };
+ };
+
+ vadc@3100 {
+ interrupts = <0x2 0x31 0x0>;
+ interrupt-names = "eoc-int-en-set";
+ };
+
+ iadc@3600 {
+ interrupts = <0x2 0x36 0x0>;
+ interrupt-names = "eoc-int-en-set";
+ };
+
+ qcom,vadc@3400 {
+ interrupts = <0x2 0x34 0x0>,
+ <0x2 0x34 0x3>,
+ <0x2 0x34 0x4>;
+ interrupt-names = "eoc-int-en-set",
+ "high-thr-en-set",
+ "low-thr-en-set";
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974pro-ac-regulator.dtsi b/arch/arm/boot/dts/msm8974pro-ac-regulator.dtsi
new file mode 100644
index 0000000..9d7f316
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974pro-ac-regulator.dtsi
@@ -0,0 +1,566 @@
+/* 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.
+ */
+
+
+/* QPNP controlled regulators: */
+
+&spmi_bus {
+ qcom,pma8084@1 {
+ pma8084_mvs1: regulator@8400 {
+ qcom,enable-time = <1000>;
+ qcom,pull-down-enable = <1>;
+ interrupts = <0x1 0x84 0x2>;
+ interrupt-names = "ocp";
+ qcom,ocp-enable = <1>;
+ qcom,ocp-max-retries = <10>;
+ qcom,ocp-retry-delay = <30>;
+ qcom,soft-start-enable = <1>;
+ qcom,vs-soft-start-strength = <0>;
+ qcom,hpm-enable = <1>;
+ qcom,auto-mode-enable = <0>;
+ status = "okay";
+ };
+ };
+};
+
+/* RPM controlled regulators: */
+
+&rpm_bus {
+ rpm-regulator-smpa1 {
+ status = "okay";
+ pma8084_s1: regulator-s1 {
+ regulator-min-microvolt = <675000>;
+ regulator-max-microvolt = <1050000>;
+ status = "okay";
+ };
+ pma8084_s1_ao: regulator-s1-ao {
+ regulator-name = "8084_s1_ao";
+ qcom,set = <1>;
+ regulator-min-microvolt = <675000>;
+ regulator-max-microvolt = <1050000>;
+ status = "okay";
+ compatible = "qcom,rpm-regulator-smd";
+ };
+ pma8084_s1_so: regulator-s1-so {
+ regulator-name = "8084_s1_so";
+ qcom,set = <2>;
+ regulator-min-microvolt = <675000>;
+ regulator-max-microvolt = <1050000>;
+ qcom,init-voltage = <675000>;
+ status = "okay";
+ compatible = "qcom,rpm-regulator-smd";
+ };
+ };
+
+ rpm-regulator-smpa2 {
+ status = "okay";
+ pma8084_s2: regulator-s2 {
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1050000>;
+ status = "okay";
+ };
+ pma8084_s2_corner: regulator-s2-corner {
+ regulator-name = "8084_s2_corner";
+ qcom,set = <3>;
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+ qcom,use-voltage-corner;
+ compatible = "qcom,rpm-regulator-smd";
+ qcom,consumer-supplies = "vdd_dig", "";
+ };
+ pma8084_s2_corner_ao: regulator-s2-corner-ao {
+ regulator-name = "8084_s2_corner_ao";
+ qcom,set = <1>;
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+ qcom,use-voltage-corner;
+ compatible = "qcom,rpm-regulator-smd";
+ };
+ pma8084_s2_floor_corner: regulator-s2-floor-corner {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_s2_floor_corner";
+ qcom,set = <3>;
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+ qcom,use-voltage-floor-corner;
+ qcom,always-send-voltage;
+ };
+ };
+
+
+ rpm-regulator-smpa3 {
+ status = "okay";
+ pma8084_s3: regulator-s3 {
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ qcom,init-voltage = <1300000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-smpa4 {
+ status = "okay";
+ pma8084_s4: regulator-s4 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-smpa5 {
+ status = "okay";
+ pma8084_s5: regulator-s5 {
+ regulator-min-microvolt = <2150000>;
+ regulator-max-microvolt = <2150000>;
+ qcom,init-voltage = <2150000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-smpa6 {
+ status = "okay";
+ pma8084_s6: regulator-s6 {
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1050000>;
+ qcom,init-voltage = <1050000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-smpa7 {
+ status = "okay";
+ pma8084_s7: regulator-s7 {
+ regulator-min-microvolt = <815000>;
+ regulator-max-microvolt = <900000>;
+ status = "okay";
+ };
+ pma8084_s7_corner: regulator-s7-corner {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_s7_corner";
+ qcom,set = <3>;
+ qcom,use-voltage-corner;
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+ qcom,init-voltage-corner = <3>; /* SVS SOC */
+ };
+ pma8084_s7_floor_corner: regulator-s7-floor-corner {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_s7_floor_corner";
+ qcom,set = <3>;
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+ qcom,use-voltage-floor-corner;
+ qcom,always-send-voltage;
+ };
+ };
+
+ rpm-regulator-ldoa1 {
+ status = "okay";
+ pma8084_l1: regulator-l1 {
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ qcom,init-voltage = <1225000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa2 {
+ status = "okay";
+ pma8084_l2: regulator-l2 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ qcom,init-voltage = <1200000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa3 {
+ status = "okay";
+ pma8084_l3: regulator-l3 {
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ qcom,init-voltage = <1225000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa4 {
+ status = "okay";
+ pma8084_l4: regulator-l4 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1225000>;
+ qcom,init-voltage = <1225000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa5 {
+ status = "okay";
+ pma8084_l5: regulator-l5 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa6 {
+ status = "okay";
+ pma8084_l6: regulator-l6 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa7 {
+ status = "okay";
+ pma8084_l7: regulator-l7 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa8 {
+ status = "okay";
+ pma8084_l8: regulator-l8 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa9 {
+ status = "okay";
+ pma8084_l9: regulator-l9 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ qcom,init-voltage = <2950000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa10 {
+ status = "okay";
+ pma8084_l10: regulator-l10 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ qcom,init-voltage = <2950000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa11 {
+ status = "okay";
+ pma8084_l11: regulator-l11 {
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ qcom,init-voltage = <1300000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa12 {
+ status = "okay";
+ pma8084_l12: regulator-l12 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ status = "okay";
+ };
+ pma8084_l12_ao: regulator-l12-ao {
+ regulator-name = "8084_l12_ao";
+ qcom,set = <1>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ status = "okay";
+ compatible = "qcom,rpm-regulator-smd";
+ };
+ };
+
+ rpm-regulator-ldoa13 {
+ status = "okay";
+ pma8084_l13: regulator-l13 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ qcom,init-voltage = <2950000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa14 {
+ status = "okay";
+ pma8084_l14: regulator-l14 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa15 {
+ status = "okay";
+ pma8084_l15: regulator-l15 {
+ regulator-min-microvolt = <2050000>;
+ regulator-max-microvolt = <2050000>;
+ qcom,init-voltage = <2050000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa16 {
+ status = "okay";
+ pma8084_l16: regulator-l16 {
+ regulator-min-microvolt = <2700000>;
+ regulator-max-microvolt = <2700000>;
+ qcom,init-voltage = <2700000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa17 {
+ status = "okay";
+ pma8084_l17: regulator-l17 {
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ qcom,init-voltage = <2850000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa18 {
+ status = "okay";
+ pma8084_l18: regulator-l18 {
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ qcom,init-voltage = <2850000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa19 {
+ status = "okay";
+ pma8084_l19: regulator-l19 {
+ regulator-min-microvolt = <2900000>;
+ regulator-max-microvolt = <3300000>;
+ qcom,init-voltage = <2900000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa20 {
+ status = "okay";
+ pma8084_l20: regulator-l20 {
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ qcom,init-voltage = <2950000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa21 {
+ status = "okay";
+ pma8084_l21: regulator-l21 {
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ qcom,init-voltage = <2950000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa22 {
+ status = "okay";
+ pma8084_l22: regulator-l22 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ qcom,init-voltage = <3000000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa23 {
+ status = "okay";
+ pma8084_l23: regulator-l23 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ qcom,init-voltage = <3000000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa24 {
+ status = "okay";
+ pma8084_l24: regulator-l24 {
+ regulator-min-microvolt = <3075000>;
+ regulator-max-microvolt = <3075000>;
+ qcom,init-voltage = <3075000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa25 {
+ status = "okay";
+ pma8084_l25: regulator-l25 {
+ regulator-min-microvolt = <2100000>;
+ regulator-max-microvolt = <2100000>;
+ qcom,init-voltage = <2100000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa26 {
+ status = "okay";
+ pma8084_l26: regulator-l26 {
+ regulator-min-microvolt = <2050000>;
+ regulator-max-microvolt = <2050000>;
+ qcom,init-voltage = <2050000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa27 {
+ status = "okay";
+ pma8084_l27: regulator-l27 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1225000>;
+ qcom,init-voltage = <1200000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-vsa1 {
+ status = "okay";
+ pma8084_lvs1: regulator-lvs1 {
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-vsa2 {
+ status = "okay";
+ pma8084_lvs2: regulator-lvs2 {
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-vsa3 {
+ status = "okay";
+ pma8084_lvs3: regulator-lvs3 {
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-vsa4 {
+ status = "okay";
+ pma8084_lvs4: regulator-lvs4 {
+ status = "okay";
+ };
+ };
+};
+
+&soc {
+ krait_pdn: krait-pdn@f9011000 {
+ reg = <0xf9011000 0x1000>,
+ <0xfc4b80b0 8>;
+ reg-names = "apcs_gcc", "phase-scaling-efuse";
+ compatible = "qcom,krait-pdn";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ qcom,pfm-threshold = <73>;
+
+ krait0_vreg: regulator@f9088000 {
+ compatible = "qcom,krait-regulator";
+ regulator-name = "krait0";
+ reg = <0xf9088000 0x1000>, /* APCS_ALIAS0_KPSS_ACS */
+ <0xf908a800 0x1000>; /* APCS_ALIAS0_KPSS_MDD */
+ reg-names = "acs", "mdd";
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1100000>;
+ qcom,headroom-voltage = <150000>;
+ qcom,retention-voltage = <675000>;
+ qcom,ldo-default-voltage = <750000>;
+ qcom,ldo-threshold-voltage = <850000>;
+ qcom,ldo-delta-voltage = <50000>;
+ qcom,cpu-num = <0>;
+ };
+
+ krait1_vreg: regulator@f9098000 {
+ compatible = "qcom,krait-regulator";
+ regulator-name = "krait1";
+ reg = <0xf9098000 0x1000>, /* APCS_ALIAS1_KPSS_ACS */
+ <0xf909a800 0x1000>; /* APCS_ALIAS1_KPSS_MDD */
+ reg-names = "acs", "mdd";
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1100000>;
+ qcom,headroom-voltage = <150000>;
+ qcom,retention-voltage = <675000>;
+ qcom,ldo-default-voltage = <750000>;
+ qcom,ldo-threshold-voltage = <850000>;
+ qcom,ldo-delta-voltage = <50000>;
+ qcom,cpu-num = <1>;
+ };
+
+ krait2_vreg: regulator@f90a8000 {
+ compatible = "qcom,krait-regulator";
+ regulator-name = "krait2";
+ reg = <0xf90a8000 0x1000>, /* APCS_ALIAS2_KPSS_ACS */
+ <0xf90aa800 0x1000>; /* APCS_ALIAS2_KPSS_MDD */
+ reg-names = "acs", "mdd";
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1100000>;
+ qcom,headroom-voltage = <150000>;
+ qcom,retention-voltage = <675000>;
+ qcom,ldo-default-voltage = <750000>;
+ qcom,ldo-threshold-voltage = <850000>;
+ qcom,ldo-delta-voltage = <50000>;
+ qcom,cpu-num = <2>;
+ };
+
+ krait3_vreg: regulator@f90b8000 {
+ compatible = "qcom,krait-regulator";
+ regulator-name = "krait3";
+ reg = <0xf90b8000 0x1000>, /* APCS_ALIAS3_KPSS_ACS */
+ <0xf90ba800 0x1000>; /* APCS_ALIAS3_KPSS_MDD */
+ reg-names = "acs", "mdd";
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1100000>;
+ qcom,headroom-voltage = <150000>;
+ qcom,retention-voltage = <675000>;
+ qcom,ldo-default-voltage = <750000>;
+ qcom,ldo-threshold-voltage = <850000>;
+ qcom,ldo-delta-voltage = <50000>;
+ qcom,cpu-num = <3>;
+ };
+ };
+
+ /* SPI expects a regulator device, but no hardware is present. */
+ spi_eth_vreg: spi_eth_phy_vreg {
+ compatible = "regulator-fixed";
+ regulator-name = "ethernet_phy";
+ regulator-always-on;
+ };
+
+ /*
+ * vph_pwr_vreg represents the unregulated battery voltage supply
+ * VPH_PWR that is present whenever the device is powered on.
+ */
+ vph_pwr_vreg: vph_pwr_vreg {
+ compatible = "regulator-fixed";
+ status = "disabled";
+ regulator-name = "vph_pwr";
+ regulator-always-on;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974pro-ac.dtsi b/arch/arm/boot/dts/msm8974pro-ac.dtsi
index 9240514..032c256 100644
--- a/arch/arm/boot/dts/msm8974pro-ac.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-ac.dtsi
@@ -17,3 +17,174 @@
*/
/include/ "msm8974pro.dtsi"
+
+/include/ "msm-pma8084-rpm-regulator.dtsi"
+/include/ "msm-pma8084.dtsi"
+/include/ "msm8974pro-ac-regulator.dtsi"
+
+/*
+ * Override PM8841 and PM8941 resources with proper PMA8084 resources for
+ * MSM8974Pro AC.
+ */
+
+&soc {
+ qcom,csid@fda08000 {
+ qcom,mipi-csi-vdd-supply = <&pma8084_l12>;
+ };
+
+ qcom,csid@fda08400 {
+ qcom,mipi-csi-vdd-supply = <&pma8084_l12>;
+ };
+
+ qcom,csid@fda08800 {
+ qcom,mipi-csi-vdd-supply = <&pma8084_l12>;
+ };
+
+ qcom,csid@fda08C00 {
+ qcom,mipi-csi-vdd-supply = <&pma8084_l12>;
+ };
+
+ tpiu@fc318000 {
+ vdd-supply = <&pma8084_l21>;
+ };
+
+ qcom,mdss_dsi@fd922800 {
+ vdd-supply = <&pma8084_l22>;
+ vddio-supply = <&pma8084_l12>;
+ vdda-supply = <&pma8084_l2>;
+ };
+
+ qcom,mdss_dsi@fd922e00 {
+ vdd-supply = <&pma8084_l22>;
+ vddio-supply = <&pma8084_l12>;
+ vdda-supply = <&pma8084_l2>;
+ };
+
+ qcom,hdmi_tx@fd922100 {
+ hpd-5v-supply = <&pma8084_mvs1>;
+ core-vdda-supply = <&pma8084_l12>;
+ core-vcc-supply = <&pma8084_s4>;
+ };
+
+ qcom,mdss_edp@fd923400 {
+ vdda-supply = <&pma8084_l12>;
+ };
+
+ usb@f9a55000 {
+ HSUSB_VDDCX-supply = <&pma8084_s2_corner>;
+ HSUSB_1p8-supply = <&pma8084_l6>;
+ HSUSB_3p3-supply = <&pma8084_l24>;
+ };
+
+ qcom,sdcc@f9824000 {
+ vdd-supply = <&pma8084_l20>;
+ vdd-io-supply = <&pma8084_s4>;
+ };
+
+ qcom,sdcc@f98a4000 {
+ vdd-supply = <&pma8084_l21>;
+ vdd-io-supply = <&pma8084_l13>;
+ };
+
+ slim@fe12f000 {
+ taiko_codec {
+ cdc-vdd-buck-supply = <&pma8084_s5>;
+ cdc-vdd-tx-h-supply = <&pma8084_s4>;
+ cdc-vdd-rx-h-supply = <&pma8084_s4>;
+ cdc-vddpx-1-supply = <&pma8084_s4>;
+ cdc-vdd-a-1p2v-supply = <&pma8084_l1>;
+ cdc-vddcx-1-supply = <&pma8084_l1>;
+ cdc-vddcx-2-supply = <&pma8084_l1>;
+ };
+ };
+
+ 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,ssusb@f9200000 {
+ ssusb_vdd_dig-supply = <&pma8084_s2_corner>;
+ SSUSB_1p8-supply = <&pma8084_l6>;
+ hsusb_vdd_dig-supply = <&pma8084_s2_corner>;
+ HSUSB_1p8-supply = <&pma8084_l6>;
+ HSUSB_3p3-supply = <&pma8084_l24>;
+ };
+
+ qcom,ehci-host@f9a55000 {
+ HSUSB_VDDCX-supply = <&pma8084_s2>;
+ HSUSB_1p8-supply = <&pma8084_l6>;
+ HSUSB_3p3-supply = <&pma8084_l24>;
+ };
+
+ qcom,gdsc@fd8c4024 {
+ parent-supply = <&pma8084_s7_corner>;
+ };
+
+ qcom,lpass@fe200000 {
+ vdd_cx-supply = <&pma8084_s2_corner>;
+ };
+
+ qcom,mss@fc880000 {
+ vdd_mss-supply = <&pma8084_s6>;
+ vdd_cx-supply = <&pma8084_s2_corner>;
+ vdd_mx-supply = <&pma8084_s1>;
+ vdd_pll-supply = <&pma8084_l12>;
+ };
+
+ qcom,pronto@fb21b000 {
+ vdd_pronto_pll-supply = <&pma8084_l12>;
+ };
+
+ qcom,wcnss-wlan@fb000000 {
+ qcom,pronto-vddmx-supply = <&pma8084_s1>;
+ qcom,pronto-vddcx-supply = <&pma8084_s2>;
+ qcom,pronto-vddpx-supply = <&pma8084_s4>;
+ qcom,iris-vddxo-supply = <&pma8084_l6>;
+ qcom,iris-vddrfa-supply = <&pma8084_l11>;
+ qcom,iris-vddpa-supply = <&pma8084_l19>;
+ qcom,iris-vdddig-supply = <&pma8084_s4>;
+ };
+
+ qcom,msm-thermal {
+ vdd-dig-supply = <&pma8084_s2_floor_corner>;
+ vdd-gfx-supply = <&pma8084_s7_floor_corner>;
+ };
+
+ qcom,lpm-resources {
+ qcom,lpm-resources@0 {
+ qcom,name = "vdd-dig";
+ qcom,type = <0x61706d73>; /* "smpa" */
+ qcom,id = <2>;
+ };
+
+ qcom,lpm-resources@1 {
+ qcom,name = "vdd-mem";
+ qcom,type = <0x61706d73>; /* "smpa" */
+ qcom,id = <1>;
+ };
+ };
+
+ sound {
+ qcom,cdc-mclk-gpios = <&pma8084_gpios 15 0>;
+ };
+};
+
+&krait_pdn {
+ qcom,use-phase-switching;
+};
+
+&tspp {
+ vdd_cx-supply = <&pma8084_s2_corner>;
+};
diff --git a/arch/arm/boot/dts/msm8974pro.dtsi b/arch/arm/boot/dts/msm8974pro.dtsi
index 96e78ac..b80eb0f 100644
--- a/arch/arm/boot/dts/msm8974pro.dtsi
+++ b/arch/arm/boot/dts/msm8974pro.dtsi
@@ -37,7 +37,7 @@
/* GPU overrides */
&msm_gpu {
/* Updated chip ID */
- qcom,chipid = <0x03030001>;
+ qcom,chipid = <0x03030002>;
/* Updated bus bandwidth requirements */
qcom,msm-bus,vectors-KBps =
@@ -53,6 +53,55 @@
<26 512 0 7464000>, <89 604 0 5120000>,
/* Turbo */
<26 512 0 7464000>, <89 604 0 6400000>;
+
+ qcom,gpu-pwrlevels {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ compatible = "qcom,gpu-pwrlevels";
+
+ qcom,gpu-pwrlevel@0 {
+ reg = <0>;
+ qcom,gpu-freq = <550000000>;
+ qcom,bus-freq = <5>;
+ qcom,io-fraction = <33>;
+ };
+
+ qcom,gpu-pwrlevel@1 {
+ reg = <1>;
+ qcom,gpu-freq = <320000000>;
+ qcom,bus-freq = <4>;
+ 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-freq = <27000000>;
+ qcom,bus-freq = <0>;
+ qcom,io-fraction = <0>;
+ };
+ };
};
&mdss_mdp {
@@ -128,11 +177,3 @@
<0x42 0x2>,
<0x120 0x3>;
};
-
-&krait_pdn {
- qcom,use-phase-switching;
-};
-
-&tspp {
- vdd_cx-supply = <&pm8841_s2_corner>;
-};
diff --git a/arch/arm/boot/dts/msm9625-coresight.dtsi b/arch/arm/boot/dts/msm9625-coresight.dtsi
index bde734e..4a903b7 100644
--- a/arch/arm/boot/dts/msm9625-coresight.dtsi
+++ b/arch/arm/boot/dts/msm9625-coresight.dtsi
@@ -16,6 +16,8 @@
reg = <0xfc322000 0x1000>,
<0xfc37c000 0x3000>;
reg-names = "tmc-base", "bam-base";
+ interrupts = <0 166 0>;
+ interrupt-names = "byte-cntr-irq";
qcom,memory-reservation-type = "EBI1";
qcom,memory-reservation-size = <0x20000>; /* 128K EBI1 buffer */
@@ -249,11 +251,22 @@
hwevent: hwevent@f9011038 {
compatible = "qcom,coresight-hwevent";
reg = <0xf9011038 0x8>,
- <0xfd4ab160 0x80>;
- reg-names = "apcs-mux", "ppss-mux";
+ <0xfd4ab160 0x80>,
+ <0xfc401600 0x80>;
+ reg-names = "apcs-mux", "ppss-mux", "gcc-mux";
coresight-id = <20>;
coresight-name = "coresight-hwevent";
coresight-nr-inports = <0>;
};
+
+ fuse: fuse@fc4be024 {
+ compatible = "arm,coresight-fuse";
+ reg = <0xfc4be024 0x8>;
+ reg-names = "fuse-base";
+
+ coresight-id = <21>;
+ coresight-name = "coresight-fuse";
+ coresight-nr-inports = <0>;
+ };
};
diff --git a/arch/arm/boot/dts/msm9625-pm.dtsi b/arch/arm/boot/dts/msm9625-pm.dtsi
index 8eb1119..7989f2b 100644
--- a/arch/arm/boot/dts/msm9625-pm.dtsi
+++ b/arch/arm/boot/dts/msm9625-pm.dtsi
@@ -28,57 +28,16 @@
3e 0f];
};
- qcom,lpm-resources {
- compatible = "qcom,lpm-resources";
- #address-cells = <1>;
- #size-cells = <0>;
-
- qcom,lpm-resources@0 {
- reg = <0x0>;
- qcom,name = "vdd-dig";
- qcom,type = <0x616F646C>; /* "ldoa" */
- qcom,id = <0x0A>;
- qcom,key = <0x6e726f63>; /* "corn" */
- qcom,init-value = <5>; /* Super Turbo */
- };
-
- qcom,lpm-resources@1 {
- reg = <0x1>;
- qcom,name = "vdd-mem";
- qcom,type = <0x616F646C>; /* "ldoa" */
- qcom,id = <0x0C>;
- qcom,key = <0x7675>; /* "uv" */
- qcom,init-value = <1050000>; /* Super Turbo */
- };
-
- qcom,lpm-resources@2 {
- reg = <0x2>;
- qcom,name = "pxo";
- qcom,type = <0x306b6c63>; /* "clk0" */
- qcom,id = <0x00>;
- qcom,key = <0x62616e45>; /* "Enab" */
- qcom,init-value = "xo_on";
- };
- };
-
qcom,lpm-levels {
compatible = "qcom,lpm-levels";
+ qcom,no-l2-saw;
#address-cells = <1>;
#size-cells = <0>;
- qcom,use-qtimer;
-
qcom,lpm-level@0 {
reg = <0x0>;
qcom,mode = "wfi";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_active";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
qcom,latency-us = <100>;
qcom,ss-power = <8000>;
qcom,energy-overhead = <100000>;
@@ -88,14 +47,7 @@
qcom,lpm-level@1 {
reg = <0x1>;
qcom,mode = "standalone_pc";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_active";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
qcom,latency-us = <2000>;
qcom,ss-power = <5000>;
qcom,energy-overhead = <60100000>;
@@ -105,15 +57,8 @@
qcom,lpm-level@2 {
reg = <0x2>;
qcom,mode = "pc";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_gdhs";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
- qcom,latency-us = <3500>;
+ qcom,latency-us = <20000>;
qcom,ss-power = <5000>;
qcom,energy-overhead = <60350000>;
qcom,time-overhead = <6300>;
@@ -122,66 +67,12 @@
qcom,lpm-level@3 {
reg = <0x3>;
qcom,mode = "pc";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* SVS SOC */
- qcom,vdd-dig-upper-bound = <4>; /* NORMAL */
- qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
- qcom,latency-us = <4500>;
+ qcom,latency-us = <30000>;
qcom,ss-power = <5000>;
qcom,energy-overhead = <60350000>;
qcom,time-overhead = <7300>;
};
-
- qcom,lpm-level@4 {
- reg = <0x4>;
- qcom,mode = "pc";
- qcom,xo = "xo_off";
- qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom,latency-us = <6800>;
- qcom,ss-power = <2000>;
- qcom,energy-overhead = <71850000>;
- qcom,time-overhead = <13300>;
- };
-
- qcom,lpm-level@5 {
- reg = <0x5>;
- qcom,mode = "pc";
- qcom,xo = "xo_off";
- qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* SVS SOC */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
- qcom,irqs-detectable;
- qcom,latency-us = <8000>;
- qcom,ss-power = <1800>;
- qcom,energy-overhead = <71950000>;
- qcom,time-overhead = <15300>;
- };
-
- qcom,lpm-level@6 {
- reg = <0x6>;
- qcom,mode = "pc";
- qcom,xo = "xo_off";
- qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <950000>; /* SVS SOC */
- qcom,vdd-mem-lower-bound = <675000>; /* RETENTION */
- qcom,vdd-dig-upper-bound = <3>; /* SVS SOC */
- qcom,vdd-dig-lower-bound = <1>; /* RETENTION */
- qcom,latency-us = <9800>;
- qcom,ss-power = <0>;
- qcom,energy-overhead = <76350000>;
- qcom,time-overhead = <28300>;
- };
};
qcom,pm-boot {
@@ -271,8 +162,9 @@
<37 71>;
};
- qcom,pm-8x60 {
+ qcom,pm-8x60@fe805664 {
compatible = "qcom,pm-8x60";
+ reg = <0xfe805664 0x40>;
qcom,pc-mode = "tz_l2_ext";
qcom,use-sync-timer;
};
@@ -294,4 +186,10 @@
reg-names = "phys_addr_base";
qcom,sleep-stats-version = <2>;
};
+
+ qcom,rpm-rbcpr-stats@fc000000 {
+ compatible = "qcom,rpmrbcpr-stats";
+ reg = <0xfc000000 0x1a0000>;
+ qcom,start-offset = <0x190010>;
+ };
};
diff --git a/arch/arm/boot/dts/msm9625-regulator.dtsi b/arch/arm/boot/dts/msm9625-regulator.dtsi
index ee48b7f..eb56d1c 100644
--- a/arch/arm/boot/dts/msm9625-regulator.dtsi
+++ b/arch/arm/boot/dts/msm9625-regulator.dtsi
@@ -194,6 +194,15 @@
qcom,use-voltage-corner;
status = "okay";
};
+ pm8019_l10_floor_corner: regulator-l10-floor-corner {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8019_l10_floor_corner";
+ qcom,set = <3>;
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+ qcom,use-voltage-floor-corner;
+ qcom,always-send-voltage;
+ };
};
rpm-regulator-ldoa11 {
diff --git a/arch/arm/boot/dts/msm9625-v1.dtsi b/arch/arm/boot/dts/msm9625-v1.dtsi
index b238ba5..daf774b 100644
--- a/arch/arm/boot/dts/msm9625-v1.dtsi
+++ b/arch/arm/boot/dts/msm9625-v1.dtsi
@@ -48,6 +48,7 @@
/* CoreSight */
&tmc_etr {
qcom,reset-flush-race;
+ qcom,byte-cntr-absent;
};
&stm {
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index dda32ce..59d7ba0 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -173,7 +173,7 @@
qcom,msm-bus,vectors-KBps =
<87 512 0 0>,
<87 512 40000 640000>;
- qcom,hsusb-log2-itc = <5>;
+ qcom,hsusb-log2-itc = <4>;
};
hsic_host: hsic@f9a15000 {
@@ -511,7 +511,7 @@
tsens@fc4a8000 {
compatible = "qcom,msm-tsens";
reg = <0xfc4a8000 0x2000>,
- <0xfc4b8000 0x1000>;
+ <0xfc4bc000 0x1000>;
reg-names = "tsens_physical", "tsens_eeprom_physical";
interrupts = <0 184 0>;
qcom,sensors = <5>;
@@ -529,10 +529,10 @@
qcom,freq-control-mask = <0x0>;
qcom,vdd-restriction-temp = <5>;
qcom,vdd-restriction-temp-hysteresis = <10>;
- vdd_dig-supply = <&pm8019_l10_corner>;
+ vdd-dig-supply = <&pm8019_l10_floor_corner>;
qcom,vdd-dig-rstr{
- qcom,vdd-rstr-reg = "vdd_dig";
+ qcom,vdd-rstr-reg = "vdd-dig";
qcom,levels = <5 7 7>; /* Nominal, Super Turbo, Super Turbo */
qcom,min-level = <1>; /* No Request */
};
@@ -749,9 +749,8 @@
compatible = "qcom,msm-stub-codec";
};
- qcom,msm-auxpcm {
- compatible = "qcom,msm-auxpcm-resource";
- qcom,msm-cpudai-auxpcm-clk = "pcm_clk";
+ qcom,msm-pri-auxpcm {
+ compatible = "qcom,msm-auxpcm-dev";
qcom,msm-cpudai-auxpcm-mode = <0>, <0>;
qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
@@ -759,16 +758,7 @@
qcom,msm-cpudai-auxpcm-slot = <1>, <1>;
qcom,msm-cpudai-auxpcm-data = <0>, <0>;
qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
-
- qcom,msm-auxpcm-rx {
- qcom,msm-auxpcm-dev-id = <4106>;
- compatible = "qcom,msm-auxpcm-dev";
- };
-
- qcom,msm-auxpcm-tx {
- qcom,msm-auxpcm-dev-id = <4107>;
- compatible = "qcom,msm-auxpcm-dev";
- };
+ qcom,msm-auxpcm-interface = "primary";
};
qcom,msm-dai-mi2s {
@@ -869,6 +859,12 @@
qcom,bam-pipe-pair = <2>;
};
+ jtag_fuse: jtagfuse@fc4be024 {
+ compatible = "qcom,jtag-fuse";
+ reg = <0xfc4be024 0x8>;
+ reg-names = "fuse-base";
+ };
+
jtag_mm: jtagmm@fc332000 {
compatible = "qcom,jtag-mm";
reg = <0xfc332000 0x1000>,
diff --git a/arch/arm/boot/dts/msmkrypton-smp2p.dtsi b/arch/arm/boot/dts/msmkrypton-smp2p.dtsi
new file mode 100644
index 0000000..fcd2880
--- /dev/null
+++ b/arch/arm/boot/dts/msmkrypton-smp2p.dtsi
@@ -0,0 +1,122 @@
+/* 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 {
+ qcom,smp2p-modem {
+ compatible = "qcom,smp2p";
+ reg = <0xf9011008 0x4>;
+ qcom,remote-pid = <1>;
+ qcom,irq-bitmask = <0x4000>;
+ interrupts = <0 27 1>;
+ };
+
+ qcom,smp2p-adsp {
+ compatible = "qcom,smp2p";
+ reg = <0xf9011008 0x4>;
+ qcom,remote-pid = <2>;
+ qcom,irq-bitmask = <0x400>;
+ interrupts = <0 158 1>;
+ };
+
+ smp2pgpio_smp2p_7_in: qcom,smp2pgpio-smp2p-7-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <7>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_7_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_7_in";
+ gpios = <&smp2pgpio_smp2p_7_in 0 0>;
+ };
+
+ smp2pgpio_smp2p_7_out: qcom,smp2pgpio-smp2p-7-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <7>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_7_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_7_out";
+ gpios = <&smp2pgpio_smp2p_7_out 0 0>;
+ };
+
+ smp2pgpio_smp2p_1_in: qcom,smp2pgpio-smp2p-1-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <1>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_1_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_1_in";
+ gpios = <&smp2pgpio_smp2p_1_in 0 0>;
+ };
+
+ smp2pgpio_smp2p_1_out: qcom,smp2pgpio-smp2p-1-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_1_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_1_out";
+ gpios = <&smp2pgpio_smp2p_1_out 0 0>;
+ };
+
+ smp2pgpio_smp2p_2_in: qcom,smp2pgpio-smp2p-2-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <2>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_2_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_2_in";
+ gpios = <&smp2pgpio_smp2p_2_in 0 0>;
+ };
+
+ smp2pgpio_smp2p_2_out: qcom,smp2pgpio-smp2p-2-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <2>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_2_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_2_out";
+ gpios = <&smp2pgpio_smp2p_2_out 0 0>;
+ };
+
+};
diff --git a/arch/arm/boot/dts/msmkrypton.dtsi b/arch/arm/boot/dts/msmkrypton.dtsi
index ba6377c..cdaf964 100644
--- a/arch/arm/boot/dts/msmkrypton.dtsi
+++ b/arch/arm/boot/dts/msmkrypton.dtsi
@@ -20,6 +20,8 @@
soc: soc { };
};
+/include/ "msmkrypton-smp2p.dtsi"
+
&soc {
#address-cells = <1>;
#size-cells = <1>;
@@ -50,6 +52,11 @@
reg = <0xfe807800 0x1000>; /* Address and size of IMEM */
};
+ qcom,msm-mem-hole {
+ compatible = "qcom,msm-mem-hole";
+ qcom,memblock-remove = <0x02000000 0x06000000>; /* Address and Size of Hole */
+ };
+
timer@f9020000 {
#address-cells = <1>;
#size-cells = <1>;
@@ -123,6 +130,15 @@
status = "disabled";
};
+ qcom,sps@f9980000 {
+ compatible = "qcom,msm_sps";
+ reg = <0xf9984000 0x15000>,
+ <0xf9999000 0xb000>,
+ <0xfe803000 0xd000>,
+ <0xfe805000 0x1000>;
+ interrupts = <0 94 0>;
+ };
+
spi_6: spi@f9928000 { /* BLSP1 QUP6 */
cell-index = <0>;
compatible = "qcom,spi-qup-v2";
@@ -137,4 +153,68 @@
<&msmgpio 20 0>; /* MOSI */
cs-gpios = <&msmgpio 22 0>;
};
+
+ qcom,ipc-spinlock@fd484000 {
+ compatible = "qcom,ipc-spinlock-sfpb";
+ reg = <0xfd484000 0x400>;
+ qcom,num-locks = <8>;
+ };
+
+ qcom,smem@2200000 {
+ compatible = "qcom,smem";
+ reg = <0x2200000 0x100000>,
+ <0xf9011000 0x1000>,
+ <0xfc428000 0x4000>;
+ reg-names = "smem", "irq-reg-base", "aux-mem1";
+
+ qcom,smd-modem {
+ compatible = "qcom,smd";
+ qcom,smd-edge = <0>;
+ qcom,smd-irq-offset = <0x8>;
+ qcom,smd-irq-bitmask = <0x1000>;
+ qcom,pil-string = "modem";
+ interrupts = <0 25 1>;
+ };
+
+ qcom,smsm-modem {
+ compatible = "qcom,smsm";
+ qcom,smsm-edge = <0>;
+ qcom,smsm-irq-offset = <0x8>;
+ qcom,smsm-irq-bitmask = <0x2000>;
+ interrupts = <0 26 1>;
+ };
+
+ qcom,smd-adsp {
+ compatible = "qcom,smd";
+ qcom,smd-edge = <1>;
+ qcom,smd-irq-offset = <0x8>;
+ qcom,smd-irq-bitmask = <0x100>;
+ qcom,pil-string = "adsp";
+ interrupts = <0 156 1>;
+ };
+
+ qcom,smsm-adsp {
+ compatible = "qcom,smsm";
+ qcom,smsm-edge = <1>;
+ qcom,smsm-irq-offset = <0x8>;
+ qcom,smsm-irq-bitmask = <0x200>;
+ interrupts = <0 157 1>;
+ };
+
+ qcom,smd-rpm {
+ compatible = "qcom,smd";
+ qcom,smd-edge = <15>;
+ qcom,smd-irq-offset = <0x8>;
+ qcom,smd-irq-bitmask = <0x1>;
+ interrupts = <0 168 1>;
+ qcom,irq-no-suspend;
+ };
+ };
+
+ rpm_bus: qcom,rpm-smd {
+ compatible = "qcom,rpm-smd";
+ rpm-channel-name = "rpm_requests";
+ rpm-channel-type = <15>; /* SMD_APPS_RPM */
+ rpm-standalone = <1>;
+ };
};
diff --git a/arch/arm/boot/dts/msmsamarium-sim.dts b/arch/arm/boot/dts/msmsamarium-sim.dts
index 4acffae..d23bd89 100644
--- a/arch/arm/boot/dts/msmsamarium-sim.dts
+++ b/arch/arm/boot/dts/msmsamarium-sim.dts
@@ -53,3 +53,7 @@
status = "ok";
};
+
+&usb_otg {
+ status = "ok";
+};
diff --git a/arch/arm/boot/dts/msmsamarium-smp2p.dtsi b/arch/arm/boot/dts/msmsamarium-smp2p.dtsi
new file mode 100644
index 0000000..3d8441b
--- /dev/null
+++ b/arch/arm/boot/dts/msmsamarium-smp2p.dtsi
@@ -0,0 +1,160 @@
+/* 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 {
+ qcom,smp2p-modem {
+ compatible = "qcom,smp2p";
+ reg = <0xf9011008 0x4>;
+ qcom,remote-pid = <1>;
+ qcom,irq-bitmask = <0x4000>;
+ interrupts = <0 27 1>;
+ };
+
+ qcom,smp2p-adsp {
+ compatible = "qcom,smp2p";
+ reg = <0xf9011008 0x4>;
+ qcom,remote-pid = <2>;
+ qcom,irq-bitmask = <0x400>;
+ interrupts = <0 158 1>;
+ };
+
+ qcom,smp2p-wcnss {
+ compatible = "qcom,smp2p";
+ reg = <0xf9011008 0x4>;
+ qcom,remote-pid = <4>;
+ qcom,irq-bitmask = <0x40000>;
+ interrupts = <0 143 1>;
+ };
+
+ smp2pgpio_smp2p_7_in: qcom,smp2pgpio-smp2p-7-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <7>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_7_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_7_in";
+ gpios = <&smp2pgpio_smp2p_7_in 0 0>;
+ };
+
+ smp2pgpio_smp2p_7_out: qcom,smp2pgpio-smp2p-7-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <7>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_7_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_7_out";
+ gpios = <&smp2pgpio_smp2p_7_out 0 0>;
+ };
+
+ smp2pgpio_smp2p_1_in: qcom,smp2pgpio-smp2p-1-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <1>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_1_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_1_in";
+ gpios = <&smp2pgpio_smp2p_1_in 0 0>;
+ };
+
+ smp2pgpio_smp2p_1_out: qcom,smp2pgpio-smp2p-1-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_1_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_1_out";
+ gpios = <&smp2pgpio_smp2p_1_out 0 0>;
+ };
+
+ smp2pgpio_smp2p_2_in: qcom,smp2pgpio-smp2p-2-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <2>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_2_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_2_in";
+ gpios = <&smp2pgpio_smp2p_2_in 0 0>;
+ };
+
+ smp2pgpio_smp2p_2_out: qcom,smp2pgpio-smp2p-2-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <2>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_2_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_2_out";
+ gpios = <&smp2pgpio_smp2p_2_out 0 0>;
+ };
+
+ smp2pgpio_smp2p_4_in: qcom,smp2pgpio-smp2p-4-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <4>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_4_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_4_in";
+ gpios = <&smp2pgpio_smp2p_4_in 0 0>;
+ };
+
+ smp2pgpio_smp2p_4_out: qcom,smp2pgpio-smp2p-4-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_4_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_4_out";
+ gpios = <&smp2pgpio_smp2p_4_out 0 0>;
+ };
+};
diff --git a/arch/arm/boot/dts/msmsamarium.dtsi b/arch/arm/boot/dts/msmsamarium.dtsi
index a9cca0b..251bef2 100644
--- a/arch/arm/boot/dts/msmsamarium.dtsi
+++ b/arch/arm/boot/dts/msmsamarium.dtsi
@@ -20,6 +20,7 @@
};
/include/ "msmsamarium-ion.dtsi"
+/include/ "msmsamarium-smp2p.dtsi"
&soc {
#address-cells = <1>;
@@ -101,4 +102,136 @@
compatible = "qcom,msm-mem-hole";
qcom,memblock-remove = <0x07f00000 0x8000000>; /* Address and size of hole */
};
+
+ qcom,ipc-spinlock@fd484000 {
+ compatible = "qcom,ipc-spinlock-sfpb";
+ reg = <0xfd484000 0x400>;
+ qcom,num-locks = <8>;
+ };
+
+ qcom,smem@fa00000 {
+ compatible = "qcom,smem";
+ reg = <0xfa00000 0x200000>,
+ <0xf9011000 0x1000>,
+ <0xfc428000 0x4000>;
+ reg-names = "smem", "irq-reg-base", "aux-mem1";
+
+ qcom,smd-modem {
+ compatible = "qcom,smd";
+ qcom,smd-edge = <0>;
+ qcom,smd-irq-offset = <0x8>;
+ qcom,smd-irq-bitmask = <0x1000>;
+ qcom,pil-string = "modem";
+ interrupts = <0 25 1>;
+ };
+
+ qcom,smsm-modem {
+ compatible = "qcom,smsm";
+ qcom,smsm-edge = <0>;
+ qcom,smsm-irq-offset = <0x8>;
+ qcom,smsm-irq-bitmask = <0x2000>;
+ interrupts = <0 26 1>;
+ };
+
+ qcom,smd-adsp {
+ compatible = "qcom,smd";
+ qcom,smd-edge = <1>;
+ qcom,smd-irq-offset = <0x8>;
+ qcom,smd-irq-bitmask = <0x100>;
+ qcom,pil-string = "adsp";
+ interrupts = <0 156 1>;
+ };
+
+ qcom,smsm-adsp {
+ compatible = "qcom,smsm";
+ qcom,smsm-edge = <1>;
+ qcom,smsm-irq-offset = <0x8>;
+ qcom,smsm-irq-bitmask = <0x200>;
+ interrupts = <0 157 1>;
+ };
+
+ qcom,smd-wcnss {
+ compatible = "qcom,smd";
+ qcom,smd-edge = <6>;
+ qcom,smd-irq-offset = <0x8>;
+ qcom,smd-irq-bitmask = <0x20000>;
+ qcom,pil-string = "wcnss";
+ interrupts = <0 142 1>;
+ };
+
+ qcom,smsm-wcnss {
+ compatible = "qcom,smsm";
+ qcom,smsm-edge = <6>;
+ qcom,smsm-irq-offset = <0x8>;
+ qcom,smsm-irq-bitmask = <0x80000>;
+ interrupts = <0 144 1>;
+ };
+
+ qcom,smd-rpm {
+ compatible = "qcom,smd";
+ qcom,smd-edge = <15>;
+ qcom,smd-irq-offset = <0x8>;
+ qcom,smd-irq-bitmask = <0x1>;
+ interrupts = <0 168 1>;
+ qcom,irq-no-suspend;
+ };
+ };
+
+ android_usb@fe8050c8 {
+ compatible = "qcom,android-usb";
+ reg = <0xfe8050c8 0xc8>;
+ qcom,android-usb-swfi-latency = <1>;
+ };
+
+ usb_otg: usb@f9a55000 {
+ compatible = "qcom,hsusb-otg";
+ status = "disabled";
+
+ reg = <0xf9a55000 0x400>;
+ interrupts = <0 134 0>, <0 140 0>;
+ interrupt-names = "core_irq", "async_irq";
+ HSUSB_VDDCX-supply = "";
+ HSUSB_1p8-supply = "";
+ HSUSB_3p3-supply = "";
+ qcom,vdd-voltage-level = <1 5 7>;
+
+ qcom,hsusb-otg-phy-type = <2>;
+ qcom,hsusb-otg-phy-init-seq =
+ <0x44 0x80 0x68 0x81 0x24 0x82 0x13 0x83 0xffffffff>;
+ qcom,hsusb-otg-mode = <1>;
+ qcom,hsusb-otg-otg-control = <1>;
+ qcom,hsusb-otg-disable-reset;
+
+ qcom,msm-bus,name = "usb2";
+ qcom,msm-bus,num-cases = <3>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <87 512 0 0>,
+ <87 512 60000 960000>,
+ <87 512 6000 6000>;
+ };
+
+ qcom,bam_dmux@fc834000 {
+ compatible = "qcom,bam_dmux";
+ reg = <0xfc834000 0x7000>;
+ interrupts = <0 29 1>;
+ qcom,rx-ring-size = <64>;
+ };
+
+ spmi_bus: qcom,spmi@fc4c0000 {
+ compatible = "qcom,spmi-pmic-arb";
+ reg = <0xfc4cf000 0x1000>,
+ <0Xfc4cb000 0x1000>,
+ <0Xfc4ca000 0x1000>;
+ reg-names = "core", "intr", "cnfg";
+ interrupts = <0 190 0>;
+ qcom,pmic-arb-channel = <0>;
+ qcom,pmic-arb-ee = <0>;
+ #interrupt-cells = <3>;
+ interrupt-controller;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cell-index = <0>;
+ qcom,not-wakeup; /* Needed until MPM is fully configured. */
+ };
};
diff --git a/arch/arm/common/cpaccess.c b/arch/arm/common/cpaccess.c
index 3572e5a..cca0b39 100644
--- a/arch/arm/common/cpaccess.c
+++ b/arch/arm/common/cpaccess.c
@@ -385,6 +385,12 @@
}
sema_init(&cp_sem, 1);
+
+ /*
+ * Make the target instruction writeable when built as a module
+ */
+ set_memory_rw((unsigned long)&cpaccess_dummy_inst & PAGE_MASK, 1);
+
return 0;
exit1:
diff --git a/arch/arm/configs/apq8084_defconfig b/arch/arm/configs/apq8084_defconfig
index 2965607..fef6543 100644
--- a/arch/arm/configs/apq8084_defconfig
+++ b/arch/arm/configs/apq8084_defconfig
@@ -52,6 +52,8 @@
CONFIG_MSM_RPM_REGULATOR_SMD=y
CONFIG_MSM_SUBSYSTEM_RESTART=y
CONFIG_MSM_SYSMON_COMM=y
+CONFIG_MSM_PIL=y
+CONFIG_MSM_PIL_VENUS=y
CONFIG_MSM_DIRECT_SCLK_ACCESS=y
CONFIG_MSM_WATCHDOG_V2=y
CONFIG_MSM_MEMORY_DUMP=y
@@ -404,3 +406,4 @@
CONFIG_CORESIGHT_FUNNEL=y
CONFIG_CORESIGHT_REPLICATOR=y
CONFIG_CORESIGHT_STM=y
+CONFIG_USB_BAM=y
diff --git a/arch/arm/configs/mpq8092_defconfig b/arch/arm/configs/mpq8092_defconfig
index 5d05596..0ee406a 100644
--- a/arch/arm/configs/mpq8092_defconfig
+++ b/arch/arm/configs/mpq8092_defconfig
@@ -239,6 +239,7 @@
CONFIG_INPUT_UINPUT=y
CONFIG_SERIAL_MSM_HSL=y
CONFIG_SERIAL_MSM_HSL_CONSOLE=y
+CONFIG_DIAG_CHAR=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_MSM=y
CONFIG_I2C=y
@@ -274,6 +275,7 @@
CONFIG_ION_MSM=y
CONFIG_MSM_KGSL=y
CONFIG_FB=y
+CONFIG_FB_VIRTUAL=y
CONFIG_FB_MSM=y
# CONFIG_FB_MSM_BACKLIGHT is not set
CONFIG_FB_MSM_MDSS=y
@@ -284,6 +286,7 @@
# CONFIG_LCD_CLASS_DEVICE is not set
CONFIG_BACKLIGHT_CLASS_DEVICE=y
# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_SOUND=y
CONFIG_USB=y
CONFIG_USB_SUSPEND=y
CONFIG_USB_EHCI_HCD=y
@@ -303,6 +306,11 @@
CONFIG_USB_STORAGE_KARMA=y
CONFIG_USB_STORAGE_CYPRESS_ATACB=y
CONFIG_USB_STORAGE_ENE_UB6250=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_DEBUG_FS=y
+CONFIG_USB_CI13XXX_MSM=y
+CONFIG_USB_G_ANDROID=y
CONFIG_MMC=y
CONFIG_MMC_PERF_PROFILING=y
CONFIG_MMC_UNSAFE_RESUME=y
@@ -334,6 +342,7 @@
CONFIG_QPNP_CLKDIV=y
CONFIG_MSM_IOMMU_V1=y
CONFIG_IOMMU_PGTABLES_L2=y
+CONFIG_IOMMU_NON_SECURE=y
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT3_FS=y
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
index 4a5c9a7..31d133a 100644
--- a/arch/arm/configs/msm8226-perf_defconfig
+++ b/arch/arm/configs/msm8226-perf_defconfig
@@ -27,6 +27,7 @@
CONFIG_EMBEDDED=y
CONFIG_PROFILING=y
CONFIG_OPROFILE=m
+CONFIG_KPROBES=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
@@ -55,6 +56,7 @@
CONFIG_MSM_PIL_VENUS=y
CONFIG_MSM_PIL_PRONTO=y
CONFIG_MSM_TZ_LOG=y
+CONFIG_MSM_SMCMOD=y
CONFIG_MSM_DIRECT_SCLK_ACCESS=y
CONFIG_MSM_WATCHDOG_V2=y
CONFIG_MSM_MEMORY_DUMP=y
@@ -79,6 +81,7 @@
CONFIG_AEABI=y
CONFIG_HIGHMEM=y
CONFIG_COMPACTION=y
+CONFIG_CP_ACCESS=y
CONFIG_USE_OF=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
@@ -220,6 +223,7 @@
CONFIG_DM_CRYPT=y
CONFIG_NETDEVICES=y
CONFIG_DUMMY=y
+CONFIG_KS8851=y
# CONFIG_MSM_RMNET is not set
CONFIG_MSM_RMNET_BAM=y
CONFIG_PPP=y
@@ -242,6 +246,8 @@
CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV=y
CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
+CONFIG_TOUCHSCREEN_FT5X06=y
+CONFIG_TOUCHSCREEN_GEN_VKEYS=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_UINPUT=y
CONFIG_INPUT_GPIO=m
@@ -283,7 +289,9 @@
CONFIG_VIDEO_V4L2_SUBDEV_API=y
# CONFIG_MSM_CAMERA is not set
CONFIG_OV8825=y
+CONFIG_OV12830=y
CONFIG_MSM_CAMERA_SENSOR=y
+CONFIG_MSM_EEPROM=y
CONFIG_MSM_CPP=y
CONFIG_MSM_CCI=y
CONFIG_MSM_CSI30_HEADER=y
@@ -292,6 +300,8 @@
CONFIG_MSM_ISPIF=y
CONFIG_MSMB_CAMERA=y
CONFIG_OV9724=y
+CONFIG_MT9M114=y
+CONFIG_OV5648=y
CONFIG_MSMB_JPEG=y
CONFIG_MSM_VIDC_V4L2=y
CONFIG_MSM_WFD=y
@@ -398,20 +408,8 @@
CONFIG_MAGIC_SYSRQ=y
CONFIG_SCHEDSTATS=y
CONFIG_TIMER_STATS=y
-CONFIG_DEBUG_KMEMLEAK=y
-CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
-CONFIG_DEBUG_SPINLOCK=y
-CONFIG_DEBUG_MUTEXES=y
-CONFIG_DEBUG_ATOMIC_SLEEP=y
-CONFIG_DEBUG_STACK_USAGE=y
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_MEMORY_INIT=y
-CONFIG_DEBUG_LIST=y
-CONFIG_FAULT_INJECTION=y
-CONFIG_FAIL_PAGE_ALLOC=y
-CONFIG_FAULT_INJECTION_DEBUG_FS=y
-CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
-CONFIG_DEBUG_PAGEALLOC=y
CONFIG_ENABLE_DEFAULT_TRACERS=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_USER=y
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index 02d4873..24ac0d8 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -27,6 +27,7 @@
CONFIG_EMBEDDED=y
CONFIG_PROFILING=y
CONFIG_OPROFILE=m
+CONFIG_KPROBES=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
@@ -55,6 +56,7 @@
CONFIG_MSM_PIL_VENUS=y
CONFIG_MSM_PIL_PRONTO=y
CONFIG_MSM_TZ_LOG=y
+CONFIG_MSM_SMCMOD=y
CONFIG_MSM_DIRECT_SCLK_ACCESS=y
CONFIG_MSM_WATCHDOG_V2=y
CONFIG_MSM_MEMORY_DUMP=y
@@ -70,6 +72,7 @@
CONFIG_MSM_RTB_SEPARATE_CPUS=y
CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
CONFIG_MSM_BOOT_STATS=y
+CONFIG_MSM_XPU_ERR_FATAL=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_SMP=y
@@ -79,6 +82,7 @@
CONFIG_AEABI=y
CONFIG_HIGHMEM=y
CONFIG_COMPACTION=y
+CONFIG_CP_ACCESS=y
CONFIG_USE_OF=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
@@ -221,6 +225,7 @@
CONFIG_NETDEVICES=y
CONFIG_DUMMY=y
CONFIG_TUN=y
+CONFIG_KS8851=y
# CONFIG_MSM_RMNET is not set
CONFIG_MSM_RMNET_BAM=y
CONFIG_PPP=y
@@ -243,6 +248,8 @@
CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV=y
CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
+CONFIG_TOUCHSCREEN_FT5X06=y
+CONFIG_TOUCHSCREEN_GEN_VKEYS=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_UINPUT=y
CONFIG_INPUT_GPIO=m
@@ -286,7 +293,9 @@
CONFIG_VIDEO_V4L2_SUBDEV_API=y
# CONFIG_MSM_CAMERA is not set
CONFIG_OV8825=y
+CONFIG_OV12830=y
CONFIG_MSM_CAMERA_SENSOR=y
+CONFIG_MSM_EEPROM=y
CONFIG_MSM_CPP=y
CONFIG_MSM_CCI=y
CONFIG_MSM_CSI30_HEADER=y
@@ -295,6 +304,8 @@
CONFIG_MSM_ISPIF=y
CONFIG_MSMB_CAMERA=y
CONFIG_OV9724=y
+CONFIG_MT9M114=y
+CONFIG_OV5648=y
CONFIG_MSMB_JPEG=y
CONFIG_MSM_VIDC_V4L2=y
CONFIG_MSM_WFD=y
@@ -409,6 +420,7 @@
CONFIG_QPNP_REVID=y
CONFIG_MSM_IOMMU_V1=y
CONFIG_CORESIGHT=y
+CONFIG_CORESIGHT_FUSE=y
CONFIG_CORESIGHT_TMC=y
CONFIG_CORESIGHT_TPIU=y
CONFIG_CORESIGHT_FUNNEL=y
@@ -448,6 +460,7 @@
CONFIG_DEBUG_PAGEALLOC=y
CONFIG_ENABLE_DEFAULT_TRACERS=y
CONFIG_DYNAMIC_DEBUG=y
+CONFIG_PANIC_ON_DATA_CORRUPTION=y
CONFIG_DEBUG_USER=y
CONFIG_DEBUG_LL=y
CONFIG_EARLY_PRINTK=y
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index 010bc10..0db08db 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -28,6 +28,7 @@
# CONFIG_SLUB_DEBUG is not set
CONFIG_PROFILING=y
CONFIG_OPROFILE=m
+CONFIG_KPROBES=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
@@ -37,7 +38,6 @@
CONFIG_IOSCHED_TEST=y
CONFIG_ARCH_MSM=y
CONFIG_ARCH_MSM8610=y
-CONFIG_ARCH_MSM8226=y
# CONFIG_MSM_STACKED_MEMORY is not set
CONFIG_CPU_HAS_L2_PMU=y
# CONFIG_MSM_FIQ_SUPPORT is not set
@@ -82,6 +82,7 @@
CONFIG_AEABI=y
CONFIG_HIGHMEM=y
CONFIG_COMPACTION=y
+CONFIG_CP_ACCESS=y
CONFIG_USE_OF=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
@@ -241,6 +242,9 @@
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_QUP=y
+CONFIG_INPUT_MPU3050=y
+CONFIG_BMP18X=y
+CONFIG_BMP18X_I2C=y
CONFIG_MSM_BUSPM_DEV=m
CONFIG_SPI=y
CONFIG_SPI_QUP=y
@@ -274,6 +278,8 @@
CONFIG_OV8825=y
CONFIG_s5k4e1=y
CONFIG_HI256=y
+CONFIG_OV12830=y
+CONFIG_OV5648=y
CONFIG_MSM_CAMERA_SENSOR=y
# CONFIG_MSM_CPP is not set
CONFIG_MSM_CCI=y
@@ -310,7 +316,6 @@
CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_SOC=y
-CONFIG_SND_SOC_MSM8226=y
CONFIG_SND_SOC_MSM8X10=y
CONFIG_UHID=y
CONFIG_HID_APPLE=y
@@ -385,3 +390,4 @@
CONFIG_INPUT_KXTJ9=y
CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
CONFIG_SENSORS_STK3X1X=y
+CONFIG_SENSORS_MMA8X5X=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 7225ec5..cfd346e 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -26,6 +26,7 @@
CONFIG_EMBEDDED=y
CONFIG_PROFILING=y
CONFIG_OPROFILE=m
+CONFIG_KPROBES=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
@@ -35,7 +36,6 @@
CONFIG_IOSCHED_TEST=y
CONFIG_ARCH_MSM=y
CONFIG_ARCH_MSM8610=y
-CONFIG_ARCH_MSM8226=y
# CONFIG_MSM_STACKED_MEMORY is not set
CONFIG_CPU_HAS_L2_PMU=y
# CONFIG_MSM_FIQ_SUPPORT is not set
@@ -71,6 +71,7 @@
CONFIG_MSM_RTB_SEPARATE_CPUS=y
CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
CONFIG_MSM_BOOT_STATS=y
+CONFIG_MSM_XPU_ERR_FATAL=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_SMP=y
@@ -80,6 +81,7 @@
CONFIG_AEABI=y
CONFIG_HIGHMEM=y
CONFIG_COMPACTION=y
+CONFIG_CP_ACCESS=y
CONFIG_USE_OF=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
@@ -239,6 +241,9 @@
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_QUP=y
+CONFIG_INPUT_MPU3050=y
+CONFIG_BMP18X=y
+CONFIG_BMP18X_I2C=y
CONFIG_MSM_BUSPM_DEV=m
CONFIG_SPI=y
CONFIG_SPI_QUP=y
@@ -272,6 +277,7 @@
CONFIG_OV8825=y
CONFIG_s5k4e1=y
CONFIG_HI256=y
+CONFIG_OV12830=y
CONFIG_MSM_CAMERA_SENSOR=y
CONFIG_MSM_CCI=y
CONFIG_MSM_CSIPHY=y
@@ -283,6 +289,7 @@
CONFIG_OV9724=y
CONFIG_SP1628=y
CONFIG_GC0339=y
+CONFIG_OV5648=y
CONFIG_MSMB_JPEG=y
CONFIG_MSM_VIDC_V4L2=y
CONFIG_MSM_WFD=y
@@ -328,7 +335,6 @@
CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_SOC=y
-CONFIG_SND_SOC_MSM8226=y
CONFIG_SND_SOC_MSM8X10=y
CONFIG_UHID=y
CONFIG_HID_APPLE=y
@@ -376,6 +382,7 @@
CONFIG_QPNP_REVID=y
CONFIG_MSM_IOMMU_V0=y
CONFIG_CORESIGHT=y
+CONFIG_CORESIGHT_FUSE=y
CONFIG_CORESIGHT_TMC=y
CONFIG_CORESIGHT_TPIU=y
CONFIG_CORESIGHT_FUNNEL=y
@@ -415,6 +422,7 @@
CONFIG_DEBUG_PAGEALLOC=y
CONFIG_ENABLE_DEFAULT_TRACERS=y
CONFIG_DYNAMIC_DEBUG=y
+CONFIG_PANIC_ON_DATA_CORRUPTION=y
CONFIG_DEBUG_USER=y
CONFIG_DEBUG_SET_MODULE_RONX=y
CONFIG_KEYS=y
@@ -428,3 +436,4 @@
CONFIG_INPUT_KXTJ9=y
CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
CONFIG_SENSORS_STK3X1X=y
+CONFIG_SENSORS_MMA8X5X=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index cdf4263..f2f6558 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -81,7 +81,6 @@
CONFIG_MSM_L1_ERR_LOG=y
CONFIG_MSM_L2_ERP_2BIT_PANIC=y
CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
-CONFIG_MSM_UARTDM_Core_v14=y
CONFIG_MSM_BOOT_STATS=y
CONFIG_STRICT_MEMORY_RWX=y
CONFIG_NO_HZ=y
@@ -398,8 +397,6 @@
CONFIG_USB_STORAGE_CYPRESS_ATACB=y
CONFIG_USB_STORAGE_ENE_UB6250=y
CONFIG_USB_EHSET_TEST_FIXTURE=y
-CONFIG_USB_QCOM_DIAG_BRIDGE=y
-CONFIG_USB_QCOM_KS_BRIDGE=y
CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_DEBUG_FILES=y
CONFIG_USB_CI13XXX_MSM=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 19d428b..71742a5 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -86,7 +86,6 @@
CONFIG_MSM_CACHE_DUMP=y
CONFIG_MSM_CACHE_DUMP_ON_PANIC=y
CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
-CONFIG_MSM_UARTDM_Core_v14=y
CONFIG_MSM_BOOT_STATS=y
CONFIG_MSM_XPU_ERR_FATAL=y
CONFIG_STRICT_MEMORY_RWX=y
@@ -404,8 +403,6 @@
CONFIG_USB_STORAGE_CYPRESS_ATACB=y
CONFIG_USB_STORAGE_ENE_UB6250=y
CONFIG_USB_EHSET_TEST_FIXTURE=y
-CONFIG_USB_QCOM_DIAG_BRIDGE=y
-CONFIG_USB_QCOM_KS_BRIDGE=y
CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_DEBUG_FILES=y
CONFIG_USB_CI13XXX_MSM=y
@@ -456,6 +453,7 @@
CONFIG_MOBICORE_SUPPORT=m
CONFIG_MOBICORE_API=m
CONFIG_CORESIGHT=y
+CONFIG_CORESIGHT_FUSE=y
CONFIG_CORESIGHT_TMC=y
CONFIG_CORESIGHT_TPIU=y
CONFIG_CORESIGHT_FUNNEL=y
@@ -500,6 +498,7 @@
CONFIG_DEBUG_PAGEALLOC=y
CONFIG_CPU_FREQ_SWITCH_PROFILER=y
CONFIG_DYNAMIC_DEBUG=y
+CONFIG_PANIC_ON_DATA_CORRUPTION=y
CONFIG_DEBUG_USER=y
CONFIG_DEBUG_LL=y
CONFIG_EARLY_PRINTK=y
diff --git a/arch/arm/configs/msm9625-perf_defconfig b/arch/arm/configs/msm9625-perf_defconfig
index d02f5da..9a5aaf0 100644
--- a/arch/arm/configs/msm9625-perf_defconfig
+++ b/arch/arm/configs/msm9625-perf_defconfig
@@ -115,6 +115,7 @@
CONFIG_NETFILTER_XT_MATCH_ESP=y
CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
CONFIG_IP_SET=y
CONFIG_NF_CONNTRACK_IPV4=y
@@ -317,3 +318,4 @@
CONFIG_CRYPTO_DEV_QCEDEV=m
CONFIG_CRC_CCITT=y
CONFIG_LIBCRC32C=y
+CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index 64c8535..3f34690 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -119,6 +119,7 @@
CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
CONFIG_NETFILTER_XT_MATCH_LIMIT=y
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
CONFIG_IP_SET=y
CONFIG_NF_CONNTRACK_IPV4=y
@@ -286,6 +287,7 @@
CONFIG_QPNP_POWER_ON=y
CONFIG_IPA=y
CONFIG_CORESIGHT=y
+CONFIG_CORESIGHT_FUSE=y
CONFIG_CORESIGHT_TMC=y
CONFIG_CORESIGHT_TPIU=y
CONFIG_CORESIGHT_FUNNEL=y
@@ -327,3 +329,4 @@
CONFIG_CRYPTO_DEFLATE=y
CONFIG_CRC_CCITT=y
CONFIG_LIBCRC32C=y
+CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
diff --git a/arch/arm/configs/msmkrypton_defconfig b/arch/arm/configs/msmkrypton_defconfig
index f073d2b..b04acb5 100644
--- a/arch/arm/configs/msmkrypton_defconfig
+++ b/arch/arm/configs/msmkrypton_defconfig
@@ -38,7 +38,12 @@
# CONFIG_MSM_PROC_COMM is not set
CONFIG_MSM_SMD=y
CONFIG_MSM_SMD_PKG4=y
+CONFIG_MSM_SMP2P=y
+CONFIG_MSM_SMP2P_TEST=y
CONFIG_MSM_IPC_LOGGING=y
+CONFIG_MSM_IPC_ROUTER=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_QMI_INTERFACE=y
CONFIG_MSM_WATCHDOG_V2=y
CONFIG_MSM_UARTDM_Core_v14=y
CONFIG_NO_HZ=y
@@ -104,6 +109,9 @@
CONFIG_SPI_SPIDEV=m
CONFIG_DEBUG_GPIO=y
CONFIG_GPIO_SYSFS=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_BAMDMA=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
CONFIG_MMC=y
CONFIG_MMC_PERF_PROFILING=y
CONFIG_MMC_UNSAFE_RESUME=y
diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h
index 03fb936..5c8b3bf4 100644
--- a/arch/arm/include/asm/assembler.h
+++ b/arch/arm/include/asm/assembler.h
@@ -320,4 +320,12 @@
.size \name , . - \name
.endm
+ .macro check_uaccess, addr:req, size:req, limit:req, tmp:req, bad:req
+#ifndef CONFIG_CPU_USE_DOMAINS
+ adds \tmp, \addr, #\size - 1
+ sbcccs \tmp, \tmp, \limit
+ bcs \bad
+#endif
+ .endm
+
#endif /* __ASM_ASSEMBLER_H__ */
diff --git a/arch/arm/include/asm/smcmod.h b/arch/arm/include/asm/smcmod.h
index 06918c4..6225c1e 100644
--- a/arch/arm/include/asm/smcmod.h
+++ b/arch/arm/include/asm/smcmod.h
@@ -108,6 +108,45 @@
uint32_t return_val; /* out */
} __packed;
+/**
+ * struct smcmod_decrypt_req - used to decrypt image fragments.
+ * @service_id - requested service.
+ * @command_id - requested command.
+ * @operation - specifies metadata parsing or image fragment decrypting.
+ * @request - describes request parameters depending on operation.
+ * @response - this is the response of the request.
+ */
+struct smcmod_decrypt_req {
+ uint32_t service_id;
+ uint32_t command_id;
+#define SMCMOD_DECRYPT_REQ_OP_METADATA 1
+#define SMCMOD_DECRYPT_REQ_OP_IMG_FRAG 2
+ uint32_t operation;
+ union {
+ struct {
+ uint32_t len;
+ uint32_t ion_fd;
+ } metadata;
+ struct {
+ uint32_t ctx_id;
+ uint32_t last_frag;
+ uint32_t frag_len;
+ uint32_t ion_fd;
+ uint32_t offset;
+ } img_frag;
+ } request;
+ union {
+ struct {
+ uint32_t status;
+ uint32_t ctx_id;
+ uint32_t end_offset;
+ } metadata;
+ struct {
+ uint32_t status;
+ } img_frag;
+ } response;
+};
+
#define SMCMOD_IOC_MAGIC 0x97
/* Number chosen to avoid any conflicts */
@@ -120,4 +159,7 @@
#define SMCMOD_IOCTL_SEND_MSG_DIGEST_CMD \
_IOWR(SMCMOD_IOC_MAGIC, 35, struct smcmod_msg_digest_req)
#define SMCMOD_IOCTL_GET_VERSION _IOWR(SMCMOD_IOC_MAGIC, 36, uint32_t)
+#define SMCMOD_IOCTL_SEND_DECRYPT_CMD \
+ _IOWR(SMCMOD_IOC_MAGIC, 37, struct smcmod_decrypt_req)
+
#endif /* __SMCMOD_H_ */
diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h
index 71f6536..0a070e9 100644
--- a/arch/arm/include/asm/uaccess.h
+++ b/arch/arm/include/asm/uaccess.h
@@ -101,28 +101,39 @@
extern int __get_user_2(void *);
extern int __get_user_4(void *);
-#define __get_user_x(__r2,__p,__e,__s,__i...) \
+#define __GUP_CLOBBER_1 "lr", "cc"
+#ifdef CONFIG_CPU_USE_DOMAINS
+#define __GUP_CLOBBER_2 "ip", "lr", "cc"
+#else
+#define __GUP_CLOBBER_2 "lr", "cc"
+#endif
+#define __GUP_CLOBBER_4 "lr", "cc"
+
+#define __get_user_x(__r2,__p,__e,__l,__s) \
__asm__ __volatile__ ( \
__asmeq("%0", "r0") __asmeq("%1", "r2") \
+ __asmeq("%3", "r1") \
"bl __get_user_" #__s \
: "=&r" (__e), "=r" (__r2) \
- : "0" (__p) \
- : __i, "cc")
+ : "0" (__p), "r" (__l) \
+ : __GUP_CLOBBER_##__s)
#define get_user(x,p) \
({ \
+ unsigned long __limit = current_thread_info()->addr_limit - 1; \
register const typeof(*(p)) __user *__p asm("r0") = (p);\
register unsigned long __r2 asm("r2"); \
+ register unsigned long __l asm("r1") = __limit; \
register int __e asm("r0"); \
switch (sizeof(*(__p))) { \
case 1: \
- __get_user_x(__r2, __p, __e, 1, "lr"); \
- break; \
+ __get_user_x(__r2, __p, __e, __l, 1); \
+ break; \
case 2: \
- __get_user_x(__r2, __p, __e, 2, "r3", "lr"); \
+ __get_user_x(__r2, __p, __e, __l, 2); \
break; \
case 4: \
- __get_user_x(__r2, __p, __e, 4, "lr"); \
+ __get_user_x(__r2, __p, __e, __l, 4); \
break; \
default: __e = __get_user_bad(); break; \
} \
@@ -135,31 +146,34 @@
extern int __put_user_4(void *, unsigned int);
extern int __put_user_8(void *, unsigned long long);
-#define __put_user_x(__r2,__p,__e,__s) \
+#define __put_user_x(__r2,__p,__e,__l,__s) \
__asm__ __volatile__ ( \
__asmeq("%0", "r0") __asmeq("%2", "r2") \
+ __asmeq("%3", "r1") \
"bl __put_user_" #__s \
: "=&r" (__e) \
- : "0" (__p), "r" (__r2) \
+ : "0" (__p), "r" (__r2), "r" (__l) \
: "ip", "lr", "cc")
#define put_user(x,p) \
({ \
+ unsigned long __limit = current_thread_info()->addr_limit - 1; \
register const typeof(*(p)) __r2 asm("r2") = (x); \
register const typeof(*(p)) __user *__p asm("r0") = (p);\
+ register unsigned long __l asm("r1") = __limit; \
register int __e asm("r0"); \
switch (sizeof(*(__p))) { \
case 1: \
- __put_user_x(__r2, __p, __e, 1); \
+ __put_user_x(__r2, __p, __e, __l, 1); \
break; \
case 2: \
- __put_user_x(__r2, __p, __e, 2); \
+ __put_user_x(__r2, __p, __e, __l, 2); \
break; \
case 4: \
- __put_user_x(__r2, __p, __e, 4); \
+ __put_user_x(__r2, __p, __e, __l, 4); \
break; \
case 8: \
- __put_user_x(__r2, __p, __e, 8); \
+ __put_user_x(__r2, __p, __e, __l, 8); \
break; \
default: __e = __put_user_bad(); break; \
} \
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 6e94b32..0241da1 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -902,11 +902,13 @@
static int perf_cpu_pm_notifier(struct notifier_block *self, unsigned long cmd,
void *v)
{
+ struct pmu *pmu;
switch (cmd) {
case CPU_PM_ENTER:
if (cpu_has_active_perf((int)v)) {
armpmu_update_counters();
- perf_pmu_disable(&cpu_pmu->pmu);
+ pmu = &cpu_pmu->pmu;
+ pmu->pmu_disable(pmu);
}
break;
@@ -919,7 +921,8 @@
*/
__get_cpu_var(from_idle) = 1;
cpu_pmu->reset(NULL);
- perf_pmu_enable(&cpu_pmu->pmu);
+ pmu = &cpu_pmu->pmu;
+ pmu->pmu_enable(pmu);
}
break;
}
diff --git a/arch/arm/lib/getuser.S b/arch/arm/lib/getuser.S
index 11093a7..9b06bb4 100644
--- a/arch/arm/lib/getuser.S
+++ b/arch/arm/lib/getuser.S
@@ -16,8 +16,9 @@
* __get_user_X
*
* Inputs: r0 contains the address
+ * r1 contains the address limit, which must be preserved
* Outputs: r0 is the error code
- * r2, r3 contains the zero-extended value
+ * r2 contains the zero-extended value
* lr corrupted
*
* No other registers must be altered. (see <asm/uaccess.h>
@@ -27,33 +28,39 @@
* Note also that it is intended that __get_user_bad is not global.
*/
#include <linux/linkage.h>
+#include <asm/assembler.h>
#include <asm/errno.h>
#include <asm/domain.h>
ENTRY(__get_user_1)
+ check_uaccess r0, 1, r1, r2, __get_user_bad
1: TUSER(ldrb) r2, [r0]
mov r0, #0
mov pc, lr
ENDPROC(__get_user_1)
ENTRY(__get_user_2)
-#ifdef CONFIG_THUMB2_KERNEL
-2: TUSER(ldrb) r2, [r0]
-3: TUSER(ldrb) r3, [r0, #1]
+ check_uaccess r0, 2, r1, r2, __get_user_bad
+#ifdef CONFIG_CPU_USE_DOMAINS
+rb .req ip
+2: ldrbt r2, [r0], #1
+3: ldrbt rb, [r0], #0
#else
-2: TUSER(ldrb) r2, [r0], #1
-3: TUSER(ldrb) r3, [r0]
+rb .req r0
+2: ldrb r2, [r0]
+3: ldrb rb, [r0, #1]
#endif
#ifndef __ARMEB__
- orr r2, r2, r3, lsl #8
+ orr r2, r2, rb, lsl #8
#else
- orr r2, r3, r2, lsl #8
+ orr r2, rb, r2, lsl #8
#endif
mov r0, #0
mov pc, lr
ENDPROC(__get_user_2)
ENTRY(__get_user_4)
+ check_uaccess r0, 4, r1, r2, __get_user_bad
4: TUSER(ldr) r2, [r0]
mov r0, #0
mov pc, lr
diff --git a/arch/arm/lib/putuser.S b/arch/arm/lib/putuser.S
index 7db2599..3d73dcb 100644
--- a/arch/arm/lib/putuser.S
+++ b/arch/arm/lib/putuser.S
@@ -16,6 +16,7 @@
* __put_user_X
*
* Inputs: r0 contains the address
+ * r1 contains the address limit, which must be preserved
* r2, r3 contains the value
* Outputs: r0 is the error code
* lr corrupted
@@ -27,16 +28,19 @@
* Note also that it is intended that __put_user_bad is not global.
*/
#include <linux/linkage.h>
+#include <asm/assembler.h>
#include <asm/errno.h>
#include <asm/domain.h>
ENTRY(__put_user_1)
+ check_uaccess r0, 1, r1, ip, __put_user_bad
1: TUSER(strb) r2, [r0]
mov r0, #0
mov pc, lr
ENDPROC(__put_user_1)
ENTRY(__put_user_2)
+ check_uaccess r0, 2, r1, ip, __put_user_bad
mov ip, r2, lsr #8
#ifdef CONFIG_THUMB2_KERNEL
#ifndef __ARMEB__
@@ -60,12 +64,14 @@
ENDPROC(__put_user_2)
ENTRY(__put_user_4)
+ check_uaccess r0, 4, r1, ip, __put_user_bad
4: TUSER(str) r2, [r0]
mov r0, #0
mov pc, lr
ENDPROC(__put_user_4)
ENTRY(__put_user_8)
+ check_uaccess r0, 8, r1, ip, __put_user_bad
#ifdef CONFIG_THUMB2_KERNEL
5: TUSER(str) r2, [r0]
6: TUSER(str) r3, [r0, #4]
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index e0f9e8a..b80949c 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -282,7 +282,6 @@
select QMI_ENCDEC
select DONT_MAP_HOLE_AFTER_MEMBANK0
select MSM_ULTRASOUND_B
- select MSM_LPM_TEST
select MSM_RPM_LOG
select ARCH_WANT_KMAP_ATOMIC_FLUSH
@@ -307,6 +306,10 @@
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
config ARCH_MPQ8092
bool "MPQ8092"
@@ -429,6 +432,8 @@
select GPIO_MSM_V3
select MAY_HAVE_SPARSE_IRQ
select SPARSE_IRQ
+ select MEMORY_HOLE_CARVEOUT
+ select QMI_ENCDEC
config ARCH_MSM8610
bool "MSM8610"
@@ -528,6 +533,7 @@
select ARM_HAS_SG_CHAIN
select MSM_RUN_QUEUE_STATS
select ARCH_WANT_KMAP_ATOMIC_FLUSH
+ select QMI_ENCDEC
endmenu
choice
@@ -2171,12 +2177,12 @@
config MSM_SMCMOD
tristate "Secure Monitor Call (SMC) Module"
default n
- depends on (ARCH_FSM9XXX && ION && ION_MSM && MSM_SCM)
+ depends on (ION && ION_MSM && MSM_SCM)
help
Enable support for smcmod driver. This driver provides a mechanism
to execute the Secure Monitor Call (SMC) to switch from non-secure
- to secure execution in the fsm9xxx targets. This module utilizes Ion
- for buffer management.
+ to secure execution in the fsm9xxx and msm8x26 targets. This module
+ utilizes Ion for buffer management.
config MSM_SUBSYSTEM_RESTART
bool "MSM Subsystem Restart"
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 300b2da..8c42b8d 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -62,8 +62,8 @@
obj-$(CONFIG_MSM_AVS_HW) += avs.o
obj-$(CONFIG_CPU_V6) += idle-v6.o
obj-$(CONFIG_CPU_V7) += idle-v7.o
-obj-$(CONFIG_MSM_JTAG) += jtag.o
-obj-$(CONFIG_MSM_JTAG_MM) += jtag-mm.o
+obj-$(CONFIG_MSM_JTAG) += jtag-fuse.o jtag.o
+obj-$(CONFIG_MSM_JTAG_MM) += jtag-fuse.o jtag-mm.o
msm-etm-objs := etm.o
obj-$(CONFIG_MSM_ETM) += msm-etm.o
@@ -295,6 +295,7 @@
obj-$(CONFIG_ARCH_MSM8226) += gdsc.o
obj-$(CONFIG_ARCH_MSM8610) += gdsc.o
obj-$(CONFIG_ARCH_MPQ8092) += gdsc.o
+obj-$(CONFIG_ARCH_APQ8084) += gdsc.o
obj-$(CONFIG_ARCH_MSM8974) += krait-regulator.o
obj-$(CONFIG_ARCH_MSMKRYPTON) += board-krypton.o board-krypton-gpiomux.o
obj-$(CONFIG_ARCH_MSMSAMARIUM) += board-samarium.o board-samarium-gpiomux.o
@@ -308,6 +309,7 @@
obj-$(CONFIG_ARCH_MSM8226) += acpuclock-8226.o acpuclock-cortex.o
obj-$(CONFIG_ARCH_MSM8610) += board-8610.o board-8610-gpiomux.o
obj-$(CONFIG_ARCH_MSM8610) += clock-local2.o clock-pll.o clock-8610.o clock-rpm.o clock-voter.o
+obj-$(CONFIG_ARCH_MSM8610) += acpuclock-8226.o acpuclock-cortex.o
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
@@ -329,7 +331,7 @@
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 lpm_resources.o
+obj-$(CONFIG_MSM_RPM_SMD) += rpm-smd.o lpm_levels.o
obj-$(CONFIG_MSM_MPM_OF) += mpm-of.o
obj-$(CONFIG_MSM_MPM) += mpm.o
obj-$(CONFIG_MSM_RPM_STATS_LOG) += rpm_stats.o rpm_master_stat.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index 3469c66..3505afe 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -57,6 +57,7 @@
dtb-$(CONFIG_ARCH_MSM8974) += msm8974-v2-fluid.dtb
dtb-$(CONFIG_ARCH_MSM8974) += msm8974-v2-liquid.dtb
dtb-$(CONFIG_ARCH_MSM8974) += msm8974-v2-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += apq8074-v2-cdp.dtb
dtb-$(CONFIG_ARCH_MSM8974) += apq8074-v2-liquid.dtb
dtb-$(CONFIG_ARCH_MSM8974) += apq8074-v2-dragonboard.dtb
@@ -86,15 +87,23 @@
dtb-$(CONFIG_ARCH_MSM8226) += msm8226-sim.dtb
dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v1-cdp.dtb
dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v1-mtp.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v1-qrd.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.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) += apq8026-xpm.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += apq8026-mtp.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
# FSM9XXX
zreladdr-$(CONFIG_ARCH_FSM9XXX) := 0x10008000
@@ -113,6 +122,8 @@
zreladdr-$(CONFIG_ARCH_MSM8610) := 0x00008000
dtb-$(CONFIG_ARCH_MSM8610) += msm8610-rumi.dtb
dtb-$(CONFIG_ARCH_MSM8610) += msm8610-sim.dtb
+ dtb-$(CONFIG_ARCH_MSM8610) += msm8610-qrd-skuaa.dtb
+ dtb-$(CONFIG_ARCH_MSM8610) += msm8610-qrd-skuab.dtb
# MSMSAMARIUM
zreladdr-$(CONFIG_ARCH_MSMSAMARIUM) := 0x00008000
diff --git a/arch/arm/mach-msm/acpuclock-8974.c b/arch/arm/mach-msm/acpuclock-8974.c
index 98ed2d8..6d848d2 100644
--- a/arch/arm/mach-msm/acpuclock-8974.c
+++ b/arch/arm/mach-msm/acpuclock-8974.c
@@ -270,7 +270,7 @@
[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, 6 },
+ [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, 7 },
@@ -899,7 +899,7 @@
{ 0, { 0 } }
};
-static struct acpu_level acpu_freq_tbl_v3_pvs0[] __initdata = {
+static struct acpu_level acpu_freq_tbl_pro_pvs0[] __initdata = {
{ 1, { 300000, PLL_0, 0, 0 }, L2(0), 800000, 999 },
{ 0, { 345600, HFPLL, 2, 36 }, L2(1), 800000, 999 },
{ 1, { 422400, HFPLL, 2, 44 }, L2(2), 800000, 999 },
@@ -971,17 +971,48 @@
[2][5] = { acpu_freq_tbl_2p2g_pvs5, sizeof(acpu_freq_tbl_2p2g_pvs5) },
[2][6] = { acpu_freq_tbl_2p2g_pvs6, sizeof(acpu_freq_tbl_2p2g_pvs6) },
[2][7] = { acpu_freq_tbl_2p2g_pvs6, sizeof(acpu_freq_tbl_2p2g_pvs6) },
+};
- /* 8974v3 Bringup */
- [3][0] = { acpu_freq_tbl_v3_pvs0, sizeof(acpu_freq_tbl_v3_pvs0) },
- [3][1] = { acpu_freq_tbl_v3_pvs0, sizeof(acpu_freq_tbl_v3_pvs0) },
- [3][2] = { acpu_freq_tbl_v3_pvs0, sizeof(acpu_freq_tbl_v3_pvs0) },
- [3][3] = { acpu_freq_tbl_v3_pvs0, sizeof(acpu_freq_tbl_v3_pvs0) },
- [3][4] = { acpu_freq_tbl_v3_pvs0, sizeof(acpu_freq_tbl_v3_pvs0) },
- [3][5] = { acpu_freq_tbl_v3_pvs0, sizeof(acpu_freq_tbl_v3_pvs0) },
- [3][6] = { acpu_freq_tbl_v3_pvs0, sizeof(acpu_freq_tbl_v3_pvs0) },
- [3][7] = { acpu_freq_tbl_v3_pvs0, sizeof(acpu_freq_tbl_v3_pvs0) },
+static struct pvs_table pvs_pro[NUM_SPEED_BINS][NUM_PVS] __initdata = {
+ /* Not used by 8974Pro */
+ [0][0] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+ [0][1] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+ [0][2] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+ [0][3] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+ [0][4] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+ [0][5] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+ [0][6] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+ [0][7] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+ /* 8974Pro AB Bringup */
+ [1][0] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+ [1][1] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+ [1][2] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+ [1][3] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+ [1][4] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+ [1][5] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+ [1][6] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+ [1][7] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+
+ /* Not used by 8974Pro */
+ [2][0] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+ [2][1] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+ [2][2] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+ [2][3] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+ [2][4] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+ [2][5] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+ [2][6] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+ [2][7] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+
+ /* 8974Pro Bringup */
+ [3][0] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+ [3][1] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+ [3][2] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+ [3][3] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+ [3][4] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+ [3][5] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+ [3][6] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+ [3][7] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
};
static struct msm_bus_scale_pdata bus_scale_data __initdata = {
@@ -1004,6 +1035,11 @@
.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 = {
@@ -1023,9 +1059,13 @@
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) {
+ 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;
@@ -1043,6 +1083,9 @@
apply_v1_l2_workaround();
}
+ if (cpu_is_msm8974pro())
+ apply_pro_bringup_workaround();
+
return acpuclk_krait_init(&pdev->dev, &acpuclk_8974_params);
}
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index b5a7552..21a940d 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -232,6 +232,7 @@
/* A2 power collaspe */
#define UL_TIMEOUT_DELAY 1000 /* in ms */
#define ENABLE_DISCONNECT_ACK 0x1
+#define SHUTDOWN_TIMEOUT_MS 500
static void toggle_apps_ack(void);
static void reconnect_to_bam(void);
static void disconnect_to_bam(void);
@@ -272,6 +273,7 @@
static int power_management_only_mode;
static int in_ssr;
static int ssr_skipped_disconnect;
+static struct completion shutdown_completion;
struct outside_notify_func {
void (*notify)(void *, int, unsigned long);
@@ -1066,6 +1068,7 @@
goto fail;
}
polling_mode = 0;
+ complete_all(&shutdown_completion);
release_wakelock();
/* handle any rx packets before interrupt was enabled */
@@ -1266,6 +1269,7 @@
" not disabled\n", __func__, ret);
break;
}
+ INIT_COMPLETION(shutdown_completion);
grab_wakelock();
polling_mode = 1;
/*
@@ -1745,6 +1749,14 @@
struct list_head *node;
struct rx_pkt_info *info;
unsigned long flags;
+ unsigned long time_remaining;
+
+ time_remaining = wait_for_completion_timeout(&shutdown_completion,
+ msecs_to_jiffies(SHUTDOWN_TIMEOUT_MS));
+ if (time_remaining == 0) {
+ pr_err("%s: shutdown completion timed out\n", __func__);
+ ssrestart_check();
+ }
bam_connection_is_active = 0;
@@ -2365,6 +2377,8 @@
init_completion(&ul_wakeup_ack_completion);
init_completion(&bam_connection_completion);
init_completion(&dfab_unvote_completion);
+ 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");
diff --git a/arch/arm/mach-msm/batterydata-lib.c b/arch/arm/mach-msm/batterydata-lib.c
index 2be591c..42a59d1 100644
--- a/arch/arm/mach-msm/batterydata-lib.c
+++ b/arch/arm/mach-msm/batterydata-lib.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
@@ -13,7 +13,7 @@
#define pr_fmt(fmt) "%s: " fmt, __func__
#include <linux/module.h>
-#include <linux/mfd/pm8xxx/batterydata-lib.h>
+#include <linux/batterydata-lib.h>
int linear_interpolate(int y0, int x0, int y1, int x1, int x)
{
diff --git a/arch/arm/mach-msm/bms-batterydata-desay.c b/arch/arm/mach-msm/bms-batterydata-desay.c
index e2b62be..1e168cd 100644
--- a/arch/arm/mach-msm/bms-batterydata-desay.c
+++ b/arch/arm/mach-msm/bms-batterydata-desay.c
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-#include <linux/mfd/pm8xxx/batterydata-lib.h>
+#include <linux/batterydata-lib.h>
static struct single_row_lut desay_5200_fcc_temp = {
.x = {-20, 0, 25, 40},
diff --git a/arch/arm/mach-msm/bms-batterydata-oem.c b/arch/arm/mach-msm/bms-batterydata-oem.c
index e4c42d7..634b4dd 100644
--- a/arch/arm/mach-msm/bms-batterydata-oem.c
+++ b/arch/arm/mach-msm/bms-batterydata-oem.c
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-#include <linux/mfd/pm8xxx/batterydata-lib.h>
+#include <linux/batterydata-lib.h>
static struct single_row_lut fcc_temp = {
.x = {-20, 0, 25, 40, 65},
diff --git a/arch/arm/mach-msm/bms-batterydata-qrd-4v2-1300mah.c b/arch/arm/mach-msm/bms-batterydata-qrd-4v2-1300mah.c
index a2c6391..7e4b2fd 100644
--- a/arch/arm/mach-msm/bms-batterydata-qrd-4v2-1300mah.c
+++ b/arch/arm/mach-msm/bms-batterydata-qrd-4v2-1300mah.c
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-#include <linux/mfd/pm8xxx/batterydata-lib.h>
+#include <linux/batterydata-lib.h>
static struct single_row_lut fcc_temp = {
.x = {-20, 0, 25, 40, 60},
diff --git a/arch/arm/mach-msm/bms-batterydata-qrd-4v35-2000mah.c b/arch/arm/mach-msm/bms-batterydata-qrd-4v35-2000mah.c
index 8adf8ca..46c1bbe 100644
--- a/arch/arm/mach-msm/bms-batterydata-qrd-4v35-2000mah.c
+++ b/arch/arm/mach-msm/bms-batterydata-qrd-4v35-2000mah.c
@@ -9,7 +9,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-#include <linux/mfd/pm8xxx/batterydata-lib.h>
+#include <linux/batterydata-lib.h>
static struct single_row_lut fcc_temp = {
.x = {-20, 0, 25, 40, 60},
diff --git a/arch/arm/mach-msm/bms-batterydata.c b/arch/arm/mach-msm/bms-batterydata.c
index dc98c57..75bf5a1 100644
--- a/arch/arm/mach-msm/bms-batterydata.c
+++ b/arch/arm/mach-msm/bms-batterydata.c
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-#include <linux/mfd/pm8xxx/batterydata-lib.h>
+#include <linux/batterydata-lib.h>
static struct single_row_lut fcc_temp = {
.x = {-20, 0, 25, 40, 65},
diff --git a/arch/arm/mach-msm/board-8064-storage.c b/arch/arm/mach-msm/board-8064-storage.c
index dd6c9ec..094765f 100644
--- a/arch/arm/mach-msm/board-8064-storage.c
+++ b/arch/arm/mach-msm/board-8064-storage.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, 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
@@ -21,6 +21,7 @@
#include <mach/msm_bus_board.h>
#include <mach/board.h>
#include <mach/gpiomux.h>
+#include <mach/socinfo.h>
#include "devices.h"
#include "board-8064.h"
#include "board-storage-common-a.h"
@@ -238,6 +239,10 @@
400000, 24000000, 48000000, 96000000
};
+static unsigned int sdc1_sup_clk_rates_all[] = {
+ 400000, 24000000, 48000000, 96000000, 192000000
+};
+
static struct mmc_platform_data sdc1_data = {
.ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29,
#ifdef CONFIG_MMC_MSM_SDC1_8_BIT_SUPPORT
@@ -331,8 +336,16 @@
void __init apq8064_init_mmc(void)
{
- if (apq8064_sdc1_pdata)
+ if (apq8064_sdc1_pdata) {
+ /* 8064 v2 supports upto 200MHz clock on SDC1 slot */
+ if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 2) {
+ apq8064_sdc1_pdata->sup_clk_table =
+ sdc1_sup_clk_rates_all;
+ apq8064_sdc1_pdata->sup_clk_cnt =
+ ARRAY_SIZE(sdc1_sup_clk_rates_all);
+ }
apq8064_add_sdcc(1, apq8064_sdc1_pdata);
+ }
if (apq8064_sdc2_pdata)
apq8064_add_sdcc(2, apq8064_sdc2_pdata);
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index f5a9070..362f34d 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -71,7 +71,6 @@
#include <mach/msm_serial_hs.h>
#include <sound/cs8427.h>
#include <media/gpio-ir-recv.h>
-#include <linux/fmem.h>
#include <mach/msm_pcie.h>
#include <mach/restart.h>
#include <mach/msm_iomap.h>
@@ -165,9 +164,6 @@
};
#endif
-struct fmem_platform_data apq8064_fmem_pdata = {
-};
-
static struct memtype_reserve apq8064_reserve_table[] __initdata = {
[MEMTYPE_SMI] = {
},
@@ -191,36 +187,28 @@
return MEMTYPE_EBI1;
}
-#define FMEM_ENABLED 0
-
#ifdef CONFIG_ION_MSM
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
static struct ion_cp_heap_pdata cp_mm_apq8064_ion_pdata = {
.permission_type = IPT_TYPE_MM_CARVEOUT,
.align = PAGE_SIZE,
- .reusable = FMEM_ENABLED,
- .mem_is_fmem = FMEM_ENABLED,
.fixed_position = FIXED_MIDDLE,
};
static struct ion_cp_heap_pdata cp_mfc_apq8064_ion_pdata = {
.permission_type = IPT_TYPE_MFC_SHAREDMEM,
.align = PAGE_SIZE,
- .reusable = 0,
- .mem_is_fmem = FMEM_ENABLED,
.fixed_position = FIXED_HIGH,
};
static struct ion_co_heap_pdata co_apq8064_ion_pdata = {
.adjacent_mem_id = INVALID_HEAP_ID,
.align = PAGE_SIZE,
- .mem_is_fmem = 0,
};
static struct ion_co_heap_pdata fw_co_apq8064_ion_pdata = {
.adjacent_mem_id = ION_CP_MM_HEAP_ID,
.align = SZ_128K,
- .mem_is_fmem = FMEM_ENABLED,
.fixed_position = FIXED_LOW,
};
#endif
@@ -342,12 +330,6 @@
};
#endif
-static struct platform_device apq8064_fmem_device = {
- .name = "fmem",
- .id = 1,
- .dev = { .platform_data = &apq8064_fmem_pdata },
-};
-
static void __init reserve_mem_for_ion(enum ion_memory_types mem_type,
unsigned long size)
{
@@ -373,15 +355,10 @@
}
/**
- * Reserve memory for ION and calculate amount of reusable memory for fmem.
- * We only reserve memory for heaps that are not reusable. However, we only
- * support one reusable heap at the moment so we ignore the reusable flag for
- * other than the first heap with reusable flag set. Also handle special case
+ * Reserve memory for ION. Also handle special case
* for video heaps (MM,FW, and MFC). Video requires heaps MM and MFC to be
* at a higher address than FW in addition to not more than 256MB away from the
- * base address of the firmware. This means that if MM is reusable the other
- * two heaps must be allocated in the same region as FW. This is handled by the
- * mem_is_fmem flag in the platform data. In addition the MM heap must be
+ * base address of the firmware. In addition the MM heap must be
* adjacent to the FW heap for content protection purposes.
*/
static void __init reserve_ion_memory(void)
@@ -2502,7 +2479,6 @@
&apq8064_device_hsusb_host,
&android_usb_device,
&msm_device_wcnss_wlan,
- &apq8064_fmem_device,
#ifdef CONFIG_ION_MSM
&apq8064_ion_dev,
#endif
@@ -2619,7 +2595,6 @@
&android_usb_device,
&msm_device_wcnss_wlan,
&msm_device_iris_fm,
- &apq8064_fmem_device,
#ifdef CONFIG_ION_MSM
&apq8064_ion_dev,
#endif
diff --git a/arch/arm/mach-msm/board-8084.c b/arch/arm/mach-msm/board-8084.c
index 2a6bbb7..8f35a29 100644
--- a/arch/arm/mach-msm/board-8084.c
+++ b/arch/arm/mach-msm/board-8084.c
@@ -29,6 +29,8 @@
#include <mach/socinfo.h>
#include <mach/clk-provider.h>
#include <mach/msm_smem.h>
+#include <mach/rpm-smd.h>
+#include "spm.h"
#include "board-dt.h"
#include "clock.h"
#include "devices.h"
@@ -88,6 +90,8 @@
msm_smem_init();
msm_init_modem_notifier_list();
msm_smd_init();
+ msm_rpm_driver_init();
+ msm_spm_device_init();
msm_clock_init(&msm8084_clock_init_data);
tsens_tm_init_driver();
}
diff --git a/arch/arm/mach-msm/board-8092.c b/arch/arm/mach-msm/board-8092.c
index 56826c7..500731c 100644
--- a/arch/arm/mach-msm/board-8092.c
+++ b/arch/arm/mach-msm/board-8092.c
@@ -73,6 +73,8 @@
}
static struct of_dev_auxdata mpq8092_auxdata_lookup[] __initdata = {
+ OF_DEV_AUXDATA("qcom,hsusb-otg", 0xF9A55000, \
+ "msm_otg", NULL),
OF_DEV_AUXDATA("qcom,msm-lsuart-v14", 0xF991F000, \
"msm_serial_hsl.0", NULL),
OF_DEV_AUXDATA("qcom,msm-lsuart-v14", 0xF9922000, \
diff --git a/arch/arm/mach-msm/board-8226-gpiomux.c b/arch/arm/mach-msm/board-8226-gpiomux.c
index a32031d..78a73c4 100644
--- a/arch/arm/mach-msm/board-8226-gpiomux.c
+++ b/arch/arm/mach-msm/board-8226-gpiomux.c
@@ -85,12 +85,6 @@
.pull = GPIOMUX_PULL_DOWN,
};
-static struct gpiomux_setting gpio_spi_cs_eth_config = {
- .func = GPIOMUX_FUNC_4,
- .drv = GPIOMUX_DRV_6MA,
- .pull = GPIOMUX_PULL_DOWN,
-};
-
static struct gpiomux_setting wcnss_5wire_suspend_cfg = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_2MA,
@@ -205,12 +199,6 @@
[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
},
},
- {
- .gpio = 22, /* BLSP1 QUP1 SPI_CS_ETH */
- .settings = {
- [GPIOMUX_SUSPENDED] = &gpio_spi_cs_eth_config,
- },
- },
{ /* NFC */
.gpio = 10, /* BLSP1 QUP3 I2C_DAT */
.settings = {
@@ -394,6 +382,20 @@
},
},
{
+ .gpio = 22, /* CAM1_VDD */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[3],
+ [GPIOMUX_SUSPENDED] = &cam_settings[4],
+ },
+ },
+ {
+ .gpio = 34, /* CAM1 VCM_PWDN */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[3],
+ [GPIOMUX_SUSPENDED] = &cam_settings[4],
+ },
+ },
+ {
.gpio = 35, /* CAM2_STANDBY_N */
.settings = {
[GPIOMUX_ACTIVE] = &cam_settings[3],
@@ -468,6 +470,91 @@
},
};
+#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
+static struct gpiomux_setting sdc3_clk_actv_cfg = {
+ .func = GPIOMUX_FUNC_2,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting sdc3_cmd_data_0_3_actv_cfg = {
+ .func = GPIOMUX_FUNC_2,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting sdc3_suspend_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting sdc3_data_1_suspend_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct msm_gpiomux_config msm8226_sdc3_configs[] __initdata = {
+ {
+ /* DAT3 */
+ .gpio = 39,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &sdc3_cmd_data_0_3_actv_cfg,
+ [GPIOMUX_SUSPENDED] = &sdc3_suspend_cfg,
+ },
+ },
+ {
+ /* DAT2 */
+ .gpio = 40,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &sdc3_cmd_data_0_3_actv_cfg,
+ [GPIOMUX_SUSPENDED] = &sdc3_suspend_cfg,
+ },
+ },
+ {
+ /* DAT1 */
+ .gpio = 41,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &sdc3_cmd_data_0_3_actv_cfg,
+ [GPIOMUX_SUSPENDED] = &sdc3_data_1_suspend_cfg,
+ },
+ },
+ {
+ /* DAT0 */
+ .gpio = 42,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &sdc3_cmd_data_0_3_actv_cfg,
+ [GPIOMUX_SUSPENDED] = &sdc3_suspend_cfg,
+ },
+ },
+ {
+ /* CMD */
+ .gpio = 43,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &sdc3_cmd_data_0_3_actv_cfg,
+ [GPIOMUX_SUSPENDED] = &sdc3_suspend_cfg,
+ },
+ },
+ {
+ /* CLK */
+ .gpio = 44,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &sdc3_clk_actv_cfg,
+ [GPIOMUX_SUSPENDED] = &sdc3_suspend_cfg,
+ },
+ },
+};
+
+static void msm_gpiomux_sdc3_install(void)
+{
+ msm_gpiomux_install(msm8226_sdc3_configs,
+ ARRAY_SIZE(msm8226_sdc3_configs));
+}
+#else
+static void msm_gpiomux_sdc3_install(void) {}
+#endif /* CONFIG_MMC_MSM_SDC3_SUPPORT */
+
void __init msm8226_init_gpiomux(void)
{
int rc;
@@ -500,4 +587,6 @@
if (of_board_is_cdp() || of_board_is_mtp() || of_board_is_xpm())
msm_gpiomux_install(usb_otg_sw_configs,
ARRAY_SIZE(usb_otg_sw_configs));
+
+ msm_gpiomux_sdc3_install();
}
diff --git a/arch/arm/mach-msm/board-8226.c b/arch/arm/mach-msm/board-8226.c
index 5ad6175..aff2d75 100644
--- a/arch/arm/mach-msm/board-8226.c
+++ b/arch/arm/mach-msm/board-8226.c
@@ -51,7 +51,6 @@
#include "platsmp.h"
#include "spm.h"
#include "pm.h"
-#include "lpm_resources.h"
#include "modem_notifier.h"
static struct memtype_reserve msm8226_reserve_table[] __initdata = {
@@ -75,10 +74,14 @@
"msm_sdcc.1", NULL),
OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF98A4000, \
"msm_sdcc.2", NULL),
+ OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF9864000, \
+ "msm_sdcc.3", NULL),
OF_DEV_AUXDATA("qcom,sdhci-msm", 0xF9824900, \
"msm_sdcc.1", NULL),
OF_DEV_AUXDATA("qcom,sdhci-msm", 0xF98A4900, \
"msm_sdcc.2", NULL),
+ OF_DEV_AUXDATA("qcom,sdhci-msm", 0xF9864900, \
+ "msm_sdcc.3", NULL),
{}
};
@@ -112,7 +115,6 @@
msm_init_modem_notifier_list();
msm_smd_init();
msm_rpm_driver_init();
- msm_lpmrs_module_init();
msm_spm_device_init();
msm_pm_sleep_status_init();
rpm_regulator_smd_driver_init();
diff --git a/arch/arm/mach-msm/board-8610-gpiomux.c b/arch/arm/mach-msm/board-8610-gpiomux.c
index b261ce4..01f1468 100644
--- a/arch/arm/mach-msm/board-8610-gpiomux.c
+++ b/arch/arm/mach-msm/board-8610-gpiomux.c
@@ -16,6 +16,7 @@
#include <mach/board.h>
#include <mach/gpio.h>
#include <mach/gpiomux.h>
+#include <mach/socinfo.h>
static struct gpiomux_setting gpio_spi_config = {
.func = GPIOMUX_FUNC_1,
@@ -59,6 +60,30 @@
.pull = GPIOMUX_PULL_DOWN,
};
+static struct gpiomux_setting focaltech_int_act_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting focaltech_int_sus_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting focaltech_reset_act_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting focaltech_reset_sus_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
static struct gpiomux_setting wcnss_5wire_suspend_cfg = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_2MA,
@@ -110,6 +135,31 @@
.pull = GPIOMUX_PULL_NONE,
};
+/* define gpio used as interrupt input */
+static struct gpiomux_setting gpio_int_act_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_UP,
+ .dir = GPIOMUX_IN,
+};
+
+static struct gpiomux_setting gpio_int_sus_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_UP,
+ .dir = GPIOMUX_IN,
+};
+
+static struct msm_gpiomux_config msm_gpio_int_configs[] __initdata = {
+ {
+ .gpio = 84,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &gpio_int_act_cfg,
+ [GPIOMUX_SUSPENDED] = &gpio_int_sus_cfg,
+ },
+ },
+};
+
static struct msm_gpiomux_config msm_lcd_configs[] __initdata = {
{
.gpio = 41,
@@ -214,6 +264,48 @@
},
};
+static struct msm_gpiomux_config msm_focaltech_configs[] __initdata = {
+ {
+ .gpio = 0, /* TOUCH RESET */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &focaltech_reset_act_cfg,
+ [GPIOMUX_SUSPENDED] = &focaltech_reset_sus_cfg,
+ },
+ },
+ {
+ .gpio = 1, /* TOUCH INT */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &focaltech_int_act_cfg,
+ [GPIOMUX_SUSPENDED] = &focaltech_int_sus_cfg,
+ },
+ },
+ {
+ .gpio = 86, /* BLSP1 QUP4 SPI_DATA_MOSI */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ },
+ },
+ {
+ .gpio = 87, /* BLSP1 QUP4 SPI_DATA_MISO */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ },
+ },
+ {
+ .gpio = 89, /* BLSP1 QUP4 SPI_CLK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ },
+ },
+ {
+ .gpio = 88, /* BLSP1 QUP4 SPI_CS */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ },
+ },
+};
+
+
static struct msm_gpiomux_config wcnss_5wire_interface[] = {
{
.gpio = 23,
@@ -430,13 +522,21 @@
}
msm_gpiomux_install(msm_blsp_configs, ARRAY_SIZE(msm_blsp_configs));
- msm_gpiomux_install(msm_atmel_configs,
+ if (of_board_is_qrd()) {
+ msm_gpiomux_install(msm_focaltech_configs,
+ ARRAY_SIZE(msm_focaltech_configs));
+ } else {
+ msm_gpiomux_install(msm_atmel_configs,
ARRAY_SIZE(msm_atmel_configs));
+ }
msm_gpiomux_install(wcnss_5wire_interface,
ARRAY_SIZE(wcnss_5wire_interface));
- msm_gpiomux_install(msm_lcd_configs, ARRAY_SIZE(msm_lcd_configs));
+ msm_gpiomux_install_nowrite(msm_lcd_configs,
+ ARRAY_SIZE(msm_lcd_configs));
msm_gpiomux_install(msm_keypad_configs,
ARRAY_SIZE(msm_keypad_configs));
msm_gpiomux_install(sd_card_det, ARRAY_SIZE(sd_card_det));
msm_gpiomux_install(msm_sensor_configs, ARRAY_SIZE(msm_sensor_configs));
+ msm_gpiomux_install(msm_gpio_int_configs,
+ ARRAY_SIZE(msm_gpio_int_configs));
}
diff --git a/arch/arm/mach-msm/board-8610.c b/arch/arm/mach-msm/board-8610.c
index c6c9d14..d175bb4 100644
--- a/arch/arm/mach-msm/board-8610.c
+++ b/arch/arm/mach-msm/board-8610.c
@@ -52,7 +52,6 @@
#include "platsmp.h"
#include "spm.h"
#include "pm.h"
-#include "lpm_resources.h"
#include "modem_notifier.h"
static struct memtype_reserve msm8610_reserve_table[] __initdata = {
@@ -107,7 +106,6 @@
msm_init_modem_notifier_list();
msm_smd_init();
msm_rpm_driver_init();
- msm_lpmrs_module_init();
msm_spm_device_init();
msm_pm_sleep_status_init();
rpm_regulator_smd_driver_init();
diff --git a/arch/arm/mach-msm/board-8930-gpiomux.c b/arch/arm/mach-msm/board-8930-gpiomux.c
index 4298d96..62e8122 100644
--- a/arch/arm/mach-msm/board-8930-gpiomux.c
+++ b/arch/arm/mach-msm/board-8930-gpiomux.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, 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
@@ -726,6 +726,96 @@
}
};
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+static struct gpiomux_setting sdcc2_clk_actv_cfg = {
+ .func = GPIOMUX_FUNC_2,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting sdcc2_cmd_data_0_3_actv_cfg = {
+ .func = GPIOMUX_FUNC_2,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting sdcc2_suspend_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting sdcc2_data_1_suspend_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+/**
+ * DAT_0 to DAT_3 lines (gpio 89 - 92) are shared with ethernet
+ * CMD line (gpio 97) is shared with USB
+ * CLK line (gpio 98) is shared with battery alarm in
+ */
+static struct msm_gpiomux_config msm8960_sdcc2_configs[] __initdata = {
+ {
+ /* DATA_3 */
+ .gpio = 92,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &sdcc2_cmd_data_0_3_actv_cfg,
+ [GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
+ },
+ },
+ {
+ /* DATA_2 */
+ .gpio = 91,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &sdcc2_cmd_data_0_3_actv_cfg,
+ [GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
+ },
+ },
+ {
+ /* DATA_1 */
+ .gpio = 90,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &sdcc2_cmd_data_0_3_actv_cfg,
+ [GPIOMUX_SUSPENDED] = &sdcc2_data_1_suspend_cfg,
+ },
+ },
+ {
+ /* DATA_0 */
+ .gpio = 89,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &sdcc2_cmd_data_0_3_actv_cfg,
+ [GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
+ },
+ },
+ {
+ /* CMD */
+ .gpio = 97,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &sdcc2_cmd_data_0_3_actv_cfg,
+ [GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
+ },
+ },
+ {
+ /* CLK */
+ .gpio = 98,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &sdcc2_clk_actv_cfg,
+ [GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
+ },
+ },
+};
+
+static void msm_gpiomux_sdc2_install(void)
+{
+ msm_gpiomux_install(msm8960_sdcc2_configs,
+ ARRAY_SIZE(msm8960_sdcc2_configs));
+}
+#else
+static void msm_gpiomux_sdc2_install(void) {}
+#endif /* CONFIG_MMC_MSM_SDC2_SUPPORT */
+
int __init msm8930_init_gpiomux(void)
{
int rc = msm_gpiomux_init(NR_GPIO_IRQS);
@@ -802,5 +892,7 @@
msm_gpiomux_install(msm_sitar_config, ARRAY_SIZE(msm_sitar_config));
+ msm_gpiomux_sdc2_install();
+
return 0;
}
diff --git a/arch/arm/mach-msm/board-8930-regulator-pm8038.c b/arch/arm/mach-msm/board-8930-regulator-pm8038.c
index 8ed93ea..8e04003 100644
--- a/arch/arm/mach-msm/board-8930-regulator-pm8038.c
+++ b/arch/arm/mach-msm/board-8930-regulator-pm8038.c
@@ -99,6 +99,7 @@
REGULATOR_SUPPLY("mhl_iovcc18", "0-0039"),
REGULATOR_SUPPLY("vdd-io", "spi0.0"),
REGULATOR_SUPPLY("vdd-phy", "spi0.0"),
+ REGULATOR_SUPPLY("sdc_vdd", "msm_sdcc.2"),
};
VREG_CONSUMERS(L12) = {
REGULATOR_SUPPLY("8038_l12", NULL),
diff --git a/arch/arm/mach-msm/board-8930-regulator-pm8917.c b/arch/arm/mach-msm/board-8930-regulator-pm8917.c
index cdc419f..e63fbdd 100644
--- a/arch/arm/mach-msm/board-8930-regulator-pm8917.c
+++ b/arch/arm/mach-msm/board-8930-regulator-pm8917.c
@@ -81,6 +81,7 @@
REGULATOR_SUPPLY("cam_vana", "4-006c"),
REGULATOR_SUPPLY("cam_vana", "4-0048"),
REGULATOR_SUPPLY("cam_vana", "4-0020"),
+ REGULATOR_SUPPLY("sdc_vdd", "msm_sdcc.2"),
};
VREG_CONSUMERS(L12) = {
REGULATOR_SUPPLY("8917_l12", NULL),
diff --git a/arch/arm/mach-msm/board-8930-storage.c b/arch/arm/mach-msm/board-8930-storage.c
index d045040..fec87ae 100644
--- a/arch/arm/mach-msm/board-8930-storage.c
+++ b/arch/arm/mach-msm/board-8930-storage.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, 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
@@ -49,6 +49,13 @@
.lpm_uA = 9000,
.hpm_uA = 200000, /* 200mA */
},
+ /* SDCC2 : SDIO slot connected */
+ [SDCC2] = {
+ .name = "sdc_vdd",
+ .high_vol_level = 1800000,
+ .low_vol_level = 1800000,
+ .hpm_uA = 200000, /* 200mA */
+ },
/* SDCC3 : External card slot connected */
[SDCC3] = {
.name = "sdc_vdd",
@@ -94,7 +101,7 @@
* during sleep.
*/
.lpm_uA = 2000,
- }
+ },
};
static struct msm_mmc_slot_reg_data mmc_slot_vreg_data[MAX_SDCC_CONTROLLER] = {
@@ -103,6 +110,10 @@
.vdd_data = &mmc_vdd_reg_data[SDCC1],
.vdd_io_data = &mmc_vdd_io_reg_data[SDCC1],
},
+ /* SDCC2 : SDIO card slot connected */
+ [SDCC2] = {
+ .vdd_data = &mmc_vdd_reg_data[SDCC2],
+ },
/* SDCC3 : External card slot connected */
[SDCC3] = {
.vdd_data = &mmc_vdd_reg_data[SDCC3],
@@ -170,6 +181,15 @@
{TLMM_PULL_SDC3_DATA, GPIO_CFG_PULL_UP}
};
+static struct msm_mmc_gpio sdc2_gpio[] = {
+ {92, "sdc2_dat_3"},
+ {91, "sdc2_dat_2"},
+ {90, "sdc2_dat_1"},
+ {89, "sdc2_dat_0"},
+ {97, "sdc2_cmd"},
+ {98, "sdc2_clk"}
+};
+
static struct msm_mmc_pad_pull_data mmc_pad_pull_data[MAX_SDCC_CONTROLLER] = {
[SDCC1] = {
.on = sdc1_pad_pull_on_cfg,
@@ -207,10 +227,21 @@
},
};
+static struct msm_mmc_gpio_data mmc_gpio_data[MAX_SDCC_CONTROLLER] = {
+ [SDCC2] = {
+ .gpio = sdc2_gpio,
+ .size = ARRAY_SIZE(sdc2_gpio),
+ },
+};
+
static struct msm_mmc_pin_data mmc_slot_pin_data[MAX_SDCC_CONTROLLER] = {
[SDCC1] = {
.pad_data = &mmc_pad_data[SDCC1],
},
+ [SDCC2] = {
+ .is_gpio = true,
+ .gpio_data = &mmc_gpio_data[SDCC2],
+ },
[SDCC3] = {
.pad_data = &mmc_pad_data[SDCC3],
},
@@ -248,6 +279,23 @@
};
#endif
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+static unsigned int sdc2_sup_clk_rates[] = {
+ 400000, 24000000, 48000000
+};
+
+static struct mmc_platform_data msm8960_sdc2_data = {
+ .ocr_mask = MMC_VDD_165_195 | MMC_VDD_27_28 | MMC_VDD_28_29,
+ .mmc_bus_width = MMC_CAP_4_BIT_DATA,
+ .sup_clk_table = sdc2_sup_clk_rates,
+ .sup_clk_cnt = ARRAY_SIZE(sdc2_sup_clk_rates),
+ .vreg_data = &mmc_slot_vreg_data[SDCC2],
+ .pin_data = &mmc_slot_pin_data[SDCC2],
+ .sdiowakeup_irq = MSM_GPIO_TO_INT(90),
+ .msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
+};
+#endif
+
#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
static struct mmc_platform_data msm8960_sdc3_data = {
.ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29,
@@ -300,6 +348,10 @@
/* SDC1 : eMMC card connected */
msm_add_sdcc(1, &msm8960_sdc1_data);
#endif
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+ /* SDC2: SDIO slot for WLAN */
+ msm_add_sdcc(2, &msm8960_sdc2_data);
+#endif
#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
/*
* All 8930 platform boards using the 1.2 SoC have been reworked so that
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index e097faf..d79464a 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -79,7 +79,6 @@
#include <mach/ion.h>
#include <mach/mdm2.h>
#include <mach/msm_rtb.h>
-#include <linux/fmem.h>
#include <mach/msm_cache_dump.h>
#include <mach/kgsl.h>
@@ -183,9 +182,6 @@
early_param("msm_contig_mem_size", msm_contig_mem_size_setup);
#endif
-struct fmem_platform_data msm8930_fmem_pdata = {
-};
-
#define DSP_RAM_BASE_8960 0x8da00000
#define DSP_RAM_SIZE_8960 0x1800000
static int dspcrashd_pdata_8960 = 0xDEADDEAD;
@@ -230,35 +226,28 @@
return MEMTYPE_EBI1;
}
-#define FMEM_ENABLED 0
#ifdef CONFIG_ION_MSM
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
static struct ion_cp_heap_pdata cp_mm_msm8930_ion_pdata = {
.permission_type = IPT_TYPE_MM_CARVEOUT,
.align = PAGE_SIZE,
- .reusable = FMEM_ENABLED,
- .mem_is_fmem = FMEM_ENABLED,
.fixed_position = FIXED_MIDDLE,
};
static struct ion_cp_heap_pdata cp_mfc_msm8930_ion_pdata = {
.permission_type = IPT_TYPE_MFC_SHAREDMEM,
.align = PAGE_SIZE,
- .reusable = 0,
- .mem_is_fmem = FMEM_ENABLED,
.fixed_position = FIXED_HIGH,
};
static struct ion_co_heap_pdata co_msm8930_ion_pdata = {
.adjacent_mem_id = INVALID_HEAP_ID,
.align = PAGE_SIZE,
- .mem_is_fmem = 0,
};
static struct ion_co_heap_pdata fw_co_msm8930_ion_pdata = {
.adjacent_mem_id = ION_CP_MM_HEAP_ID,
.align = SZ_128K,
- .mem_is_fmem = FMEM_ENABLED,
.fixed_position = FIXED_LOW,
};
#endif
@@ -382,12 +371,6 @@
};
#endif
-struct platform_device msm8930_fmem_device = {
- .name = "fmem",
- .id = 1,
- .dev = { .platform_data = &msm8930_fmem_pdata },
-};
-
static void __init reserve_mem_for_ion(enum ion_memory_types mem_type,
unsigned long size)
{
@@ -413,15 +396,10 @@
}
/**
- * Reserve memory for ION and calculate amount of reusable memory for fmem.
- * We only reserve memory for heaps that are not reusable. However, we only
- * support one reusable heap at the moment so we ignore the reusable flag for
- * other than the first heap with reusable flag set. Also handle special case
+ * Reserve memory for ION. Also handle special case
* for video heaps (MM,FW, and MFC). Video requires heaps MM and MFC to be
* at a higher address than FW in addition to not more than 256MB away from the
- * base address of the firmware. This means that if MM is reusable the other
- * two heaps must be allocated in the same region as FW. This is handled by the
- * mem_is_fmem flag in the platform data. In addition the MM heap must be
+ * base address of the firmware. In addition the MM heap must be
* adjacent to the FW heap for content protection purposes.
*/
static void __init reserve_ion_memory(void)
@@ -2274,7 +2252,6 @@
#ifdef CONFIG_MSM_FAKE_BATTERY
&fish_battery_device,
#endif
- &msm8930_fmem_device,
&msm_device_bam_dmux,
&msm_fm_platform_init,
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index b45e690..37567ed 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -86,7 +86,6 @@
#include <mach/iommu_domains.h>
#include <mach/kgsl.h>
-#include <linux/fmem.h>
#include "timer.h"
#include "devices.h"
@@ -194,9 +193,6 @@
early_param("msm_contig_mem_size", msm_contig_mem_size_setup);
#endif
-struct fmem_platform_data msm8960_fmem_pdata = {
-};
-
#define DSP_RAM_BASE_8960 0x8da00000
#define DSP_RAM_SIZE_8960 0x1800000
static int dspcrashd_pdata_8960 = 0xDEADDEAD;
@@ -247,8 +243,6 @@
static struct ion_cp_heap_pdata cp_mm_msm8960_ion_pdata = {
.permission_type = IPT_TYPE_MM_CARVEOUT,
.align = SZ_64K,
- .reusable = FMEM_ENABLED,
- .mem_is_fmem = FMEM_ENABLED,
.fixed_position = FIXED_MIDDLE,
.iommu_map_all = 1,
.iommu_2x_map_domain = VIDEO_DOMAIN,
@@ -257,21 +251,17 @@
static struct ion_cp_heap_pdata cp_mfc_msm8960_ion_pdata = {
.permission_type = IPT_TYPE_MFC_SHAREDMEM,
.align = PAGE_SIZE,
- .reusable = 0,
- .mem_is_fmem = FMEM_ENABLED,
.fixed_position = FIXED_HIGH,
};
static struct ion_co_heap_pdata co_msm8960_ion_pdata = {
.adjacent_mem_id = INVALID_HEAP_ID,
.align = PAGE_SIZE,
- .mem_is_fmem = 0,
};
static struct ion_co_heap_pdata fw_co_msm8960_ion_pdata = {
.adjacent_mem_id = ION_CP_MM_HEAP_ID,
.align = SZ_128K,
- .mem_is_fmem = FMEM_ENABLED,
.fixed_position = FIXED_LOW,
};
#endif
@@ -394,12 +384,6 @@
};
#endif
-struct platform_device msm8960_fmem_device = {
- .name = "fmem",
- .id = 1,
- .dev = { .platform_data = &msm8960_fmem_pdata },
-};
-
static void __init adjust_mem_for_liquid(void)
{
unsigned int i;
@@ -450,15 +434,10 @@
}
/**
- * Reserve memory for ION and calculate amount of reusable memory for fmem.
- * We only reserve memory for heaps that are not reusable. However, we only
- * support one reusable heap at the moment so we ignore the reusable flag for
- * other than the first heap with reusable flag set. Also handle special case
+ * Reserve memory for ION. Also handle special case
* for video heaps (MM,FW, and MFC). Video requires heaps MM and MFC to be
* at a higher address than FW in addition to not more than 256MB away from the
- * base address of the firmware. This means that if MM is reusable the other
- * two heaps must be allocated in the same region as FW. This is handled by the
- * mem_is_fmem flag in the platform data. In addition the MM heap must be
+ * base address of the firmware. In addition the MM heap must be
* adjacent to the FW heap for content protection purposes.
*/
static void __init reserve_ion_memory(void)
@@ -2729,7 +2708,6 @@
#ifdef CONFIG_BATTERY_BCL
&battery_bcl_device,
#endif
- &msm8960_fmem_device,
&msm_device_bam_dmux,
&msm_fm_platform_init,
#if defined(CONFIG_TSIF) || defined(CONFIG_TSIF_MODULE)
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index c8a88d7..6165c32 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -177,7 +177,15 @@
static struct gpiomux_setting gpio_epm_config = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_2MA,
- .pull = GPIOMUX_PULL_DOWN,
+ .pull = GPIOMUX_PULL_NONE,
+ .dir = GPIOMUX_OUT_HIGH,
+};
+
+static struct gpiomux_setting gpio_epm_marker_config = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+ .dir = GPIOMUX_OUT_HIGH,
};
static struct gpiomux_setting wcnss_5wire_suspend_cfg = {
@@ -519,6 +527,27 @@
},
};
+static struct msm_gpiomux_config msm_epm_configs[] __initdata = {
+ {
+ .gpio = 81, /* EPM enable */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_epm_config,
+ },
+ },
+ {
+ .gpio = 85, /* EPM MARKER2 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_epm_marker_config,
+ },
+ },
+ {
+ .gpio = 96, /* EPM MARKER1 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_epm_marker_config,
+ },
+ },
+};
+
static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
{
@@ -616,12 +645,6 @@
[GPIOMUX_SUSPENDED] = &gpio_suspend_config[0],
},
},
- {
- .gpio = 81, /* EPM enable */
- .settings = {
- [GPIOMUX_SUSPENDED] = &gpio_epm_config,
- },
- },
};
static struct msm_gpiomux_config msm8974_slimbus_config[] __initdata = {
@@ -822,6 +845,135 @@
},
};
+static struct msm_gpiomux_config msm_sensor_configs_dragonboard[] __initdata = {
+ {
+ .gpio = 15, /* CAM_MCLK0 */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[0],
+ [GPIOMUX_SUSPENDED] = &cam_settings[1],
+ },
+ },
+ {
+ .gpio = 16, /* CAM_MCLK1 */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[0],
+ [GPIOMUX_SUSPENDED] = &cam_settings[1],
+ },
+ },
+ {
+ .gpio = 17, /* CAM_MCLK2 */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[0],
+ [GPIOMUX_SUSPENDED] = &cam_settings[1],
+ },
+ },
+ {
+ .gpio = 18, /* WEBCAM1_RESET_N / CAM_MCLK3 */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[3],
+ [GPIOMUX_SUSPENDED] = &cam_settings[4],
+ },
+ },
+ {
+ .gpio = 19, /* CCI_I2C_SDA0 */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[0],
+ [GPIOMUX_SUSPENDED] = &gpio_suspend_config[0],
+ },
+ },
+ {
+ .gpio = 20, /* CCI_I2C_SCL0 */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[0],
+ [GPIOMUX_SUSPENDED] = &gpio_suspend_config[0],
+ },
+ },
+ {
+ .gpio = 21, /* CCI_I2C_SDA1 */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[0],
+ [GPIOMUX_SUSPENDED] = &gpio_suspend_config[0],
+ },
+ },
+ {
+ .gpio = 22, /* CCI_I2C_SCL1 */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[0],
+ [GPIOMUX_SUSPENDED] = &gpio_suspend_config[0],
+ },
+ },
+ {
+ .gpio = 23, /* FLASH_LED_EN */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[0],
+ [GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
+ },
+ },
+ {
+ .gpio = 24, /* FLASH_LED_NOW */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[0],
+ [GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
+ },
+ },
+ {
+ .gpio = 25, /* WEBCAM2_RESET_N */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[3],
+ [GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
+ },
+ },
+ {
+ .gpio = 26, /* CAM_IRQ */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[0],
+ [GPIOMUX_SUSPENDED] = &cam_settings[1],
+ },
+ },
+ {
+ .gpio = 27, /* OIS_SYNC */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[0],
+ [GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
+ },
+ },
+ {
+ .gpio = 28, /* WEBCAM1_STANDBY */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[3],
+ [GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
+ },
+ },
+ {
+ .gpio = 89, /* CAM1_STANDBY_N */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[3],
+ [GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
+ },
+ },
+ {
+ .gpio = 90, /* CAM1_RST_N */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[3],
+ [GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
+ },
+ },
+ {
+ .gpio = 91, /* CAM2_STANDBY_N */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[3],
+ [GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
+ },
+ },
+ {
+ .gpio = 94, /* CAM2_RST_N */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[3],
+ [GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
+ },
+ },
+};
+
static struct gpiomux_setting auxpcm_act_cfg = {
.func = GPIOMUX_FUNC_1,
.drv = GPIOMUX_DRV_8MA,
@@ -1195,7 +1347,9 @@
}
#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
- msm_gpiomux_install(msm_eth_configs, ARRAY_SIZE(msm_eth_configs));
+ if (!(of_board_is_dragonboard() && machine_is_apq8074()))
+ msm_gpiomux_install(msm_eth_configs, \
+ ARRAY_SIZE(msm_eth_configs));
#endif
msm_gpiomux_install(msm_blsp_configs, ARRAY_SIZE(msm_blsp_configs));
msm_gpiomux_install(msm_blsp2_uart7_configs,
@@ -1212,7 +1366,12 @@
msm_gpiomux_install(hap_lvl_shft_config,
ARRAY_SIZE(hap_lvl_shft_config));
- msm_gpiomux_install(msm_sensor_configs, ARRAY_SIZE(msm_sensor_configs));
+ if (of_board_is_dragonboard() && machine_is_apq8074())
+ msm_gpiomux_install(msm_sensor_configs_dragonboard, \
+ ARRAY_SIZE(msm_sensor_configs_dragonboard));
+ else
+ msm_gpiomux_install(msm_sensor_configs, \
+ ARRAY_SIZE(msm_sensor_configs));
msm_gpiomux_install(&sd_card_det, 1);
@@ -1220,7 +1379,8 @@
of_board_is_dragonboard()))
msm_gpiomux_sdc3_install();
- msm_gpiomux_sdc4_install();
+ if (!(of_board_is_dragonboard() && machine_is_apq8074()))
+ msm_gpiomux_sdc4_install();
msm_gpiomux_install(msm_taiko_config, ARRAY_SIZE(msm_taiko_config));
@@ -1233,15 +1393,21 @@
msm_gpiomux_install(msm_mhl_configs,
ARRAY_SIZE(msm_mhl_configs));
- if (of_board_is_liquid())
+ if (of_board_is_liquid() ||
+ (of_board_is_dragonboard() && machine_is_apq8074()))
msm_gpiomux_install(msm8974_pri_ter_auxpcm_configs,
ARRAY_SIZE(msm8974_pri_ter_auxpcm_configs));
else
msm_gpiomux_install(msm8974_pri_pri_auxpcm_configs,
ARRAY_SIZE(msm8974_pri_pri_auxpcm_configs));
- msm_gpiomux_install(msm8974_sec_auxpcm_configs,
+ if (of_board_is_cdp())
+ msm_gpiomux_install(msm8974_sec_auxpcm_configs,
ARRAY_SIZE(msm8974_sec_auxpcm_configs));
+ else if (of_board_is_liquid() || of_board_is_fluid() ||
+ of_board_is_mtp())
+ msm_gpiomux_install(msm_epm_configs,
+ ARRAY_SIZE(msm_epm_configs));
msm_gpiomux_install_nowrite(msm_lcd_configs,
ARRAY_SIZE(msm_lcd_configs));
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index 68af757..80a957f 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -45,8 +45,8 @@
#include "clock.h"
#include "devices.h"
#include "spm.h"
+#include "pm.h"
#include "modem_notifier.h"
-#include "lpm_resources.h"
#include "platsmp.h"
@@ -96,7 +96,6 @@
msm_init_modem_notifier_list();
msm_smd_init();
msm_rpm_driver_init();
- msm_lpmrs_module_init();
msm_pm_sleep_status_init();
rpm_regulator_smd_driver_init();
msm_spm_device_init();
diff --git a/arch/arm/mach-msm/board-9625.c b/arch/arm/mach-msm/board-9625.c
index fad2efc..058789a 100644
--- a/arch/arm/mach-msm/board-9625.c
+++ b/arch/arm/mach-msm/board-9625.c
@@ -42,7 +42,6 @@
#include <mach/msm_smem.h>
#include "clock.h"
#include "modem_notifier.h"
-#include "lpm_resources.h"
#include "spm.h"
#define MSM_KERNEL_EBI_SIZE 0x51000
@@ -117,6 +116,10 @@
"usb_bam", NULL),
OF_DEV_AUXDATA("qcom,hsic-host", 0xF9A15000, \
"msm_hsic_host", NULL),
+ OF_DEV_AUXDATA("qcom,sdhci-msm", 0xF98A4900, \
+ "msm_sdcc.2", NULL),
+ OF_DEV_AUXDATA("qcom,sdhci-msm", 0xF9864900, \
+ "msm_sdcc.3", NULL),
{}
};
@@ -236,7 +239,6 @@
msm_init_modem_notifier_list();
msm_smd_init();
msm_rpm_driver_init();
- msm_lpmrs_module_init();
rpm_regulator_smd_driver_init();
msm_spm_device_init();
msm_clock_init(&msm9625_clock_init_data);
diff --git a/arch/arm/mach-msm/board-krypton.c b/arch/arm/mach-msm/board-krypton.c
index 0d06b83..8ceccf4 100644
--- a/arch/arm/mach-msm/board-krypton.c
+++ b/arch/arm/mach-msm/board-krypton.c
@@ -24,12 +24,31 @@
#include <mach/msm_iomap.h>
#include <mach/msm_memtypes.h>
#include <mach/msm_smd.h>
+#include <mach/rpm-smd.h>
#include <mach/restart.h>
#include <mach/socinfo.h>
#include <mach/clk-provider.h>
+#include <mach/msm_smem.h>
#include "board-dt.h"
#include "clock.h"
#include "devices.h"
+#include "modem_notifier.h"
+
+static struct memtype_reserve msmkrypton_reserve_table[] __initdata = {
+ [MEMTYPE_EBI1] = {
+ .flags = MEMTYPE_FLAGS_1M_ALIGN,
+ },
+};
+
+static int msmkrypton_paddr_to_memtype(unsigned int paddr)
+{
+ return MEMTYPE_EBI1;
+}
+
+static struct reserve_info msmkrypton_reserve_info __initdata = {
+ .memtype_reserve_table = msmkrypton_reserve_table,
+ .paddr_to_memtype = msmkrypton_paddr_to_memtype,
+};
static struct of_dev_auxdata msmkrypton_auxdata_lookup[] __initdata = {
{}
@@ -43,10 +62,18 @@
*/
void __init msmkrypton_add_drivers(void)
{
+ msm_smem_init();
+ msm_init_modem_notifier_list();
msm_smd_init();
+ msm_rpm_driver_init();
msm_clock_init(&msmkrypton_clock_init_data);
}
+static void __init msmkrypton_early_memory(void)
+{
+ reserve_info = &msmkrypton_reserve_info;
+ of_scan_flat_dt(dt_scan_for_memory_hole, msmkrypton_reserve_table);
+}
static void __init msmkrypton_map_io(void)
{
msm_map_msmkrypton_io();
@@ -74,5 +101,6 @@
.handle_irq = gic_handle_irq,
.timer = &msm_dt_timer,
.dt_compat = msmkrypton_dt_match,
+ .init_very_early = msmkrypton_early_memory,
.restart = msm_restart,
MACHINE_END
diff --git a/arch/arm/mach-msm/board-samarium.c b/arch/arm/mach-msm/board-samarium.c
index cfdc074..6133983 100644
--- a/arch/arm/mach-msm/board-samarium.c
+++ b/arch/arm/mach-msm/board-samarium.c
@@ -27,10 +27,12 @@
#include <mach/socinfo.h>
#include <mach/clk-provider.h>
#include <mach/msm_smem.h>
+#include <mach/msm_smd.h>
#include "board-dt.h"
#include "clock.h"
#include "devices.h"
#include "platsmp.h"
+#include "modem_notifier.h"
static struct clk_lookup msm_clocks_dummy[] = {
CLK_DUMMY("core_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
@@ -39,6 +41,11 @@
CLK_DUMMY("iface_clk", SDC1_P_CLK, "msm_sdcc.1", OFF),
CLK_DUMMY("core_clk", SDC2_CLK, "msm_sdcc.2", OFF),
CLK_DUMMY("iface_clk", SDC2_P_CLK, "msm_sdcc.2", OFF),
+ CLK_DUMMY("core_clk", USB_HS_SYSTEM_CLK, "msm_otg", OFF),
+ CLK_DUMMY("iface_clk", USB_HS_AHB_CLK, "msm_otg", OFF),
+ CLK_DUMMY("xo", CXO_OTG_CLK, "msm_otg", OFF),
+ CLK_DUMMY("dfab_clk", DFAB_CLK, "msm_sps", OFF),
+ CLK_DUMMY("dma_bam_pclk", DMA_BAM_P_CLK, "msm_sps", OFF),
};
static struct clock_init_data msm_dummy_clock_init_data __initdata = {
@@ -51,6 +58,8 @@
"msm_sdcc.1", NULL),
OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF98A4000, \
"msm_sdcc.2", NULL),
+ OF_DEV_AUXDATA("qcom,hsusb-otg", 0xF9A55000, \
+ "msm_otg", NULL),
{},
};
@@ -97,6 +106,8 @@
void __init msmsamarium_add_drivers(void)
{
msm_smem_init();
+ msm_init_modem_notifier_list();
+ msm_smd_init();
msm_clock_init(&msm_dummy_clock_init_data);
}
diff --git a/arch/arm/mach-msm/cache_erp.c b/arch/arm/mach-msm/cache_erp.c
index f52bc28..97b8448 100644
--- a/arch/arm/mach-msm/cache_erp.c
+++ b/arch/arm/mach-msm/cache_erp.c
@@ -17,6 +17,7 @@
#include <linux/errno.h>
#include <linux/proc_fs.h>
#include <linux/cpu.h>
+#include <linux/seq_file.h>
#include <linux/io.h>
#include <mach/msm-krait-l2-accessors.h>
#include <mach/msm_iomap.h>
@@ -159,25 +160,23 @@
return cesynr;
}
-static int proc_read_status(char *page, char **start, off_t off, int count,
- int *eof, void *data)
+static int cache_erp_show(struct seq_file *m, void *v)
{
struct msm_l1_err_stats *l1_stats;
- char *p = page;
- int len, cpu, ret, bytes_left = PAGE_SIZE;
+ int cpu;
for_each_present_cpu(cpu) {
l1_stats = &per_cpu(msm_l1_erp_stats, cpu);
- ret = snprintf(p, bytes_left,
- "CPU %d:\n" \
- "\tD-cache tag parity errors:\t%u\n" \
- "\tD-cache data parity errors:\t%u\n" \
- "\tI-cache tag parity errors:\t%u\n" \
- "\tI-cache data parity errors:\t%u\n" \
- "\tD-cache timing errors:\t\t%u\n" \
- "\tI-cache timing errors:\t\t%u\n" \
- "\tTLB multi-hit errors:\t\t%u\n\n", \
+ seq_printf(m,
+ "CPU %d:\n"
+ "\tD-cache tag parity errors:\t%u\n"
+ "\tD-cache data parity errors:\t%u\n"
+ "\tI-cache tag parity errors:\t%u\n"
+ "\tI-cache data parity errors:\t%u\n"
+ "\tD-cache timing errors:\t\t%u\n"
+ "\tI-cache timing errors:\t\t%u\n"
+ "\tTLB multi-hit errors:\t\t%u\n\n",
cpu,
l1_stats->dctpe,
l1_stats->dcdpe,
@@ -186,18 +185,16 @@
l1_stats->dcte,
l1_stats->icte,
l1_stats->tlbmh);
- p += ret;
- bytes_left -= ret;
}
- p += snprintf(p, bytes_left,
- "L2 master port decode errors:\t\t%u\n" \
- "L2 master port slave errors:\t\t%u\n" \
- "L2 tag soft errors, single-bit:\t\t%u\n" \
- "L2 tag soft errors, double-bit:\t\t%u\n" \
- "L2 data soft errors, single-bit:\t%u\n" \
- "L2 data soft errors, double-bit:\t%u\n" \
- "L2 modified soft errors:\t\t%u\n" \
+ seq_printf(m,
+ "L2 master port decode errors:\t\t%u\n"
+ "L2 master port slave errors:\t\t%u\n"
+ "L2 tag soft errors, single-bit:\t\t%u\n"
+ "L2 tag soft errors, double-bit:\t\t%u\n"
+ "L2 data soft errors, single-bit:\t%u\n"
+ "L2 data soft errors, double-bit:\t%u\n"
+ "L2 modified soft errors:\t\t%u\n"
"L2 master port LDREX NOK errors:\t%u\n",
msm_l2_erp_stats.mpdcd,
msm_l2_erp_stats.mpslv,
@@ -208,16 +205,21 @@
msm_l2_erp_stats.mse,
msm_l2_erp_stats.mplxrexnok);
- len = (p - page) - off;
- if (len < 0)
- len = 0;
-
- *eof = (len <= count) ? 1 : 0;
- *start = page + off;
-
- return len;
+ return 0;
}
+static int cache_erp_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, cache_erp_show, NULL);
+}
+
+static const struct file_operations cache_erp_fops = {
+ .open = cache_erp_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
static int msm_erp_dump_regions(void)
{
int i = 0;
@@ -235,26 +237,30 @@
}
#ifdef CONFIG_MSM_L1_ERR_LOG
-static int proc_read_log(char *page, char **start, off_t off, int count,
- int *eof, void *data)
+static int cache_erp_log_show(struct seq_file *m, void *v)
{
- char *p = page;
- int len, log_value;
+ int log_value;
+
log_value = __raw_readl(MSM_IMEM_BASE + ERP_LOG_MAGIC_ADDR) ==
ERP_LOG_MAGIC ? 1 : 0;
- p += snprintf(p, PAGE_SIZE, "%d\n", log_value);
+ seq_printf(m, "%d\n", log_value);
- len = (p - page) - off;
- if (len < 0)
- len = 0;
-
- *eof = (len <= count) ? 1 : 0;
- *start = page + off;
-
- return len;
+ return 0;
}
+static int cache_erp_log_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, cache_erp_log_show, NULL);
+}
+
+static const struct file_operations cache_erp_log_fops = {
+ .open = cache_erp_log_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
static void log_cpu_event(void)
{
__raw_writel(ERP_LOG_MAGIC, MSM_IMEM_BASE + ERP_LOG_MAGIC_ADDR);
@@ -263,11 +269,10 @@
static int procfs_event_log_init(void)
{
- procfs_log_entry = create_proc_entry("cpu/msm_erp_log", S_IRUGO, NULL);
-
+ procfs_log_entry = proc_create("cpu/msm_erp_log", S_IRUGO, NULL,
+ &cache_erp_log_fops);
if (!procfs_log_entry)
return -ENODEV;
- procfs_log_entry->read_proc = proc_read_log;
return 0;
}
@@ -561,7 +566,8 @@
goto fail_l1;
}
- procfs_entry = create_proc_entry("cpu/msm_cache_erp", S_IRUGO, NULL);
+ procfs_entry = proc_create("cpu/msm_cache_erp", S_IRUGO, NULL,
+ &cache_erp_fops);
if (!procfs_entry) {
pr_err("Failed to create procfs node for cache error reporting\n");
@@ -580,8 +586,6 @@
smp_call_function_single(cpu, enable_erp_irq_callback, NULL, 1);
put_online_cpus();
- procfs_entry->read_proc = proc_read_status;
-
ret = procfs_event_log_init();
if (ret)
pr_err("Failed to create procfs node for ERP log access\n");
diff --git a/arch/arm/mach-msm/clock-8084.c b/arch/arm/mach-msm/clock-8084.c
index 940e24b..4e47064 100644
--- a/arch/arm/mach-msm/clock-8084.c
+++ b/arch/arm/mach-msm/clock-8084.c
@@ -137,7 +137,8 @@
CLK_DUMMY("", gcc_lpass_mport_axi_clk.c, "", OFF),
CLK_DUMMY("", gcc_lpass_q6_axi_clk.c, "", OFF),
CLK_DUMMY("", gcc_lpass_sway_clk.c, "", OFF),
- CLK_DUMMY("", gcc_mmss_bimc_gfx_clk.c, "", OFF),
+ CLK_DUMMY("mem_iface_clk", gcc_mmss_bimc_gfx_clk.c,
+ "fdb00000.qcom,kgsl-3d0", OFF),
CLK_DUMMY("", gcc_mmss_vpu_maple_sys_noc_axi_clk.c, "", OFF),
CLK_DUMMY("", gcc_ocmem_noc_cfg_ahb_clk.c, "", OFF),
CLK_DUMMY("", gcc_msg_ram_ahb_clk.c, "", OFF),
@@ -167,7 +168,8 @@
CLK_DUMMY("", gcc_sdcc4_inactivity_timers_clk.c, "", OFF),
CLK_DUMMY("", gcc_spss_ahb_clk.c, "", OFF),
CLK_DUMMY("", gcc_sys_noc_ufs_axi_clk.c, "", OFF),
- CLK_DUMMY("", gcc_sys_noc_usb3_axi_clk.c, "", OFF),
+ CLK_DUMMY("mem_iface_clk", gcc_sys_noc_usb3_axi_clk.c,
+ "f9304000.qcom,usbbam", OFF),
CLK_DUMMY("", gcc_sys_noc_usb3_sec_axi_clk.c, "", OFF),
CLK_DUMMY("", gcc_tsif_ahb_clk.c, "", OFF),
CLK_DUMMY("", gcc_tsif_inactivity_timers_clk.c, "", OFF),
@@ -182,7 +184,8 @@
CLK_DUMMY("", gcc_ufs_tx_symbol_1_clk.c, "", OFF),
CLK_DUMMY("", gcc_usb2a_phy_sleep_clk.c, "", OFF),
CLK_DUMMY("", gcc_usb2b_phy_sleep_clk.c, "", OFF),
- CLK_DUMMY("", gcc_usb30_master_clk.c, "", OFF),
+ CLK_DUMMY("mem_clk", gcc_usb30_master_clk.c, "f9304000.qcom,usbbam",
+ OFF),
CLK_DUMMY("", gcc_usb30_mock_utmi_clk.c, "", OFF),
CLK_DUMMY("", gcc_usb30_sleep_clk.c, "", OFF),
CLK_DUMMY("", gcc_usb30_sec_master_clk.c, "", OFF),
@@ -307,23 +310,28 @@
CLK_DUMMY("", camss_vfe_vfe1_clk.c, "", OFF),
CLK_DUMMY("", camss_vfe_vfe_ahb_clk.c, "", OFF),
CLK_DUMMY("", camss_vfe_vfe_axi_clk.c, "", OFF),
- CLK_DUMMY("", mdss_ahb_clk.c, "", OFF),
- CLK_DUMMY("", mdss_axi_clk.c, "", OFF),
- CLK_DUMMY("", mdss_byte0_clk.c, "", OFF),
- CLK_DUMMY("", mdss_byte1_clk.c, "", OFF),
+ CLK_DUMMY("iface_clk", mdss_ahb_clk.c, "fd900000.qcom,mdss_mdp", OFF),
+ CLK_DUMMY("bus_clk", mdss_axi_clk.c, "fd900000.qcom,mdss_mdp", OFF),
+ CLK_DUMMY("core_clk_src", mdp_clk_src.c, "fd900000.qcom,mdss_mdp", OFF),
CLK_DUMMY("", mdss_edpaux_clk.c, "", OFF),
CLK_DUMMY("", mdss_edplink_clk.c, "", OFF),
CLK_DUMMY("", mdss_edppixel_clk.c, "", OFF),
- CLK_DUMMY("", mdss_esc0_clk.c, "", OFF),
- CLK_DUMMY("", mdss_esc1_clk.c, "", OFF),
+ CLK_DUMMY("byte_clk", mdss_byte0_clk.c, "fd922800.qcom,mdss_dsi", OFF),
+ CLK_DUMMY("byte_clk", mdss_byte1_clk.c, "fd922e00.qcom,mdss_dsi", OFF),
+ CLK_DUMMY("core_clk", mdss_esc0_clk.c, "fd922800.qcom,mdss_dsi", OFF),
+ CLK_DUMMY("core_clk", mdss_esc1_clk.c, "fd922e00.qcom,mdss_dsi", OFF),
+ CLK_DUMMY("iface_clk", mdss_ahb_clk.c, "fd922800.qcom,mdss_dsi", OFF),
+ CLK_DUMMY("iface_clk", mdss_ahb_clk.c, "fd922e00.qcom,mdss_dsi", OFF),
+ CLK_DUMMY("bus_clk", mdss_axi_clk.c, "fd922800.qcom,mdss_dsi", OFF),
+ CLK_DUMMY("bus_clk", mdss_axi_clk.c, "fd922e00.qcom,mdss_dsi", OFF),
+ CLK_DUMMY("pixel_clk", mdss_pclk0_clk.c, "fd922800.qcom,mdss_dsi", OFF),
+ CLK_DUMMY("pixel_clk", mdss_pclk1_clk.c, "fd922e00.qcom,mdss_dsi", OFF),
CLK_DUMMY("", mdss_extpclk_clk.c, "", OFF),
CLK_DUMMY("", mdss_hdmi_ahb_clk.c, "", OFF),
CLK_DUMMY("", mdss_hdmi_clk.c, "", OFF),
- CLK_DUMMY("", mdss_mdp_clk.c, "", OFF),
- CLK_DUMMY("", mdss_mdp_lut_clk.c, "", OFF),
- CLK_DUMMY("", mdss_pclk0_clk.c, "", OFF),
- CLK_DUMMY("", mdss_pclk1_clk.c, "", OFF),
- CLK_DUMMY("", mdss_vsync_clk.c, "", OFF),
+ CLK_DUMMY("core_clk", mdss_mdp_clk.c, "fd900000.qcom,mdss_mdp", OFF),
+ CLK_DUMMY("lut_clk", mdss_mdp_lut_clk.c, "fd900000.qcom,mdss_mdp", OFF),
+ CLK_DUMMY("vsync_clk", mdss_vsync_clk.c, "fd900000.qcom,mdss_mdp", OFF),
CLK_DUMMY("", mmss_misc_ahb_clk.c, "", OFF),
CLK_DUMMY("", mmss_mmssnoc_ahb_clk.c, "", OFF),
CLK_DUMMY("", mmss_mmssnoc_axi_clk.c, "", OFF),
@@ -332,15 +340,23 @@
CLK_DUMMY("iface_clk", ocmemcx_ocmemnoc_clk.c,
"fdd00000.qcom,ocmem", OFF),
CLK_DUMMY("", oxili_ocmemgx_clk.c, "", OFF),
- CLK_DUMMY("", oxili_gfx3d_clk.c, "", OFF),
+ CLK_DUMMY("core_clk", oxili_gfx3d_clk.c,
+ "fdb00000.qcom,kgsl-3d0", OFF),
CLK_DUMMY("", oxili_rbbmtimer_clk.c, "", OFF),
- CLK_DUMMY("", oxilicx_ahb_clk.c, "", OFF),
+ CLK_DUMMY("iface_clk", oxilicx_ahb_clk.c,
+ "fdb00000.qcom,kgsl-3d0", OFF),
CLK_DUMMY("", venus0_ahb_clk.c, "", OFF),
CLK_DUMMY("", venus0_axi_clk.c, "", OFF),
CLK_DUMMY("", venus0_core0_vcodec_clk.c, "", OFF),
CLK_DUMMY("", venus0_core1_vcodec_clk.c, "", OFF),
CLK_DUMMY("", venus0_ocmemnoc_clk.c, "", OFF),
CLK_DUMMY("", venus0_vcodec0_clk.c, "", OFF),
+ CLK_DUMMY("iface_clk", venus0_ahb_clk.c, "fdce0000.qcom,venus", OFF),
+ CLK_DUMMY("bus_clk", venus0_axi_clk.c, "fdce0000.qcom,venus", OFF),
+ CLK_DUMMY("mem_clk", venus0_ocmemnoc_clk.c,
+ "fdce0000.qcom,venus", OFF),
+ CLK_DUMMY("core_clk", venus0_vcodec0_clk.c,
+ "fdce0000.qcom,venus", OFF),
CLK_DUMMY("", vpu_ahb_clk.c, "", OFF),
CLK_DUMMY("", vpu_axi_clk.c, "", OFF),
CLK_DUMMY("", vpu_bus_clk.c, "", OFF),
@@ -378,8 +394,23 @@
CLK_DUMMY("core_clk", qdss_clk.c, "fc321000.funnel", OFF),
CLK_DUMMY("core_clk", qdss_clk.c, "fc322000.funnel", OFF),
CLK_DUMMY("core_clk", qdss_clk.c, "fc345000.funnel", OFF),
+ CLK_DUMMY("core_clk", qdss_clk.c, "fc355000.funnel", OFF),
CLK_DUMMY("core_clk", qdss_clk.c, "fc36c000.funnel", OFF),
CLK_DUMMY("core_clk", qdss_clk.c, "fc302000.stm", OFF),
+ CLK_DUMMY("core_clk", qdss_clk.c, "fc310000.cti", OFF),
+ CLK_DUMMY("core_clk", qdss_clk.c, "fc311000.cti", OFF),
+ CLK_DUMMY("core_clk", qdss_clk.c, "fc312000.cti", OFF),
+ CLK_DUMMY("core_clk", qdss_clk.c, "fc313000.cti", OFF),
+ CLK_DUMMY("core_clk", qdss_clk.c, "fc314000.cti", OFF),
+ CLK_DUMMY("core_clk", qdss_clk.c, "fc315000.cti", OFF),
+ CLK_DUMMY("core_clk", qdss_clk.c, "fc316000.cti", OFF),
+ CLK_DUMMY("core_clk", qdss_clk.c, "fc317000.cti", OFF),
+ CLK_DUMMY("core_clk", qdss_clk.c, "fc318000.cti", OFF),
+ CLK_DUMMY("core_clk", qdss_clk.c, "fc340000.cti", OFF),
+ CLK_DUMMY("core_clk", qdss_clk.c, "fc341000.cti", OFF),
+ CLK_DUMMY("core_clk", qdss_clk.c, "fc342000.cti", OFF),
+ CLK_DUMMY("core_clk", qdss_clk.c, "fc343000.cti", OFF),
+ CLK_DUMMY("core_clk", qdss_clk.c, "fc344000.cti", OFF),
CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc326000.tmc", OFF),
CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc324000.replicator", OFF),
@@ -388,8 +419,23 @@
CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc321000.funnel", OFF),
CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc322000.funnel", OFF),
CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc345000.funnel", OFF),
+ CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc355000.funnel", OFF),
CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc36c000.funnel", OFF),
CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc302000.stm", OFF),
+ CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc310000.cti", OFF),
+ CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc311000.cti", OFF),
+ CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc312000.cti", OFF),
+ CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc313000.cti", OFF),
+ CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc314000.cti", OFF),
+ CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc315000.cti", OFF),
+ CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc316000.cti", OFF),
+ CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc317000.cti", OFF),
+ CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc318000.cti", OFF),
+ CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc340000.cti", OFF),
+ CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc341000.cti", OFF),
+ CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc342000.cti", OFF),
+ CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc343000.cti", OFF),
+ CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc344000.cti", OFF),
};
struct clock_init_data msm8084_clock_init_data __initdata = {
diff --git a/arch/arm/mach-msm/clock-8092.c b/arch/arm/mach-msm/clock-8092.c
index 9de97ea..ec7a4b0 100644
--- a/arch/arm/mach-msm/clock-8092.c
+++ b/arch/arm/mach-msm/clock-8092.c
@@ -44,6 +44,8 @@
CLK_DUMMY("iface_clk", SDC1_P_CLK, "msm_sdcc.1", OFF),
CLK_DUMMY("core_clk", SDC2_CLK, "msm_sdcc.2", OFF),
CLK_DUMMY("iface_clk", SDC2_P_CLK, "msm_sdcc.2", OFF),
+ CLK_DUMMY("dfab_clk", DFAB_CLK, "msm_sps", OFF),
+ CLK_DUMMY("dma_bam_pclk", DMA_BAM_P_CLK, "msm_sps", OFF),
CLK_DUMMY("", usb30_master_clk_src.c, "", OFF),
CLK_DUMMY("", tsif_ref_clk_src.c, "", OFF),
CLK_DUMMY("", ce1_clk_src.c, "", OFF),
@@ -290,6 +292,18 @@
CLK_DUMMY("", vpu_sleep_clk.c, "", OFF),
CLK_DUMMY("", vpu_vdp_clk.c, "", OFF),
CLK_DUMMY("", vpu_vdp_xin_clk.c, "", OFF),
+ CLK_DUMMY("iface_clk", NULL, "fda64000.qcom,iommu", OFF),
+ CLK_DUMMY("core_clk", NULL, "fda64000.qcom,iommu", OFF),
+ CLK_DUMMY("alt_core_clk", NULL, "fda64000.qcom,iommu", OFF),
+ CLK_DUMMY("iface_clk", NULL, "fd928000.qcom,iommu", OFF),
+ CLK_DUMMY("core_clk", NULL, "fd928000.qcom,iommu", oFF),
+ CLK_DUMMY("core_clk", NULL, "fdb10000.qcom,iommu", OFF),
+ CLK_DUMMY("iface_clk", NULL, "fdb10000.qcom,iommu", OFF),
+ CLK_DUMMY("iface_clk", NULL, "fdc84000.qcom,iommu", OFF),
+ CLK_DUMMY("alt_core_clk", NULL, "fdc84000.qcom,iommu", OFF),
+ CLK_DUMMY("core_clk", NULL, "fdc84000.qcom,iommu", OFF),
+ CLK_DUMMY("iface_clk", NULL, "fdee4000.qcom,iommu", OFF),
+ CLK_DUMMY("core_clk", NULL, "fdee4000.qcom,iommu", OFF),
/* BCSS broadcast */
CLK_DUMMY("", bcc_dem_core_b_clk_src.c, "", OFF),
CLK_DUMMY("", adc_01_clk_src.c, "", OFF),
@@ -319,6 +333,11 @@
CLK_DUMMY("", nidaq_out_clk.c, "", OFF),
CLK_DUMMY("", gcc_bcss_axi_clk.c, "", OFF),
CLK_DUMMY("", bcc_lnb_core_clk.c, "", OFF),
+
+ /* USB */
+ CLK_DUMMY("core_clk", NULL, "msm_otg", OFF),
+ CLK_DUMMY("iface_clk", NULL, "msm_otg", OFF),
+ CLK_DUMMY("xo", NULL, "msm_otg", OFF),
};
struct clock_init_data mpq8092_clock_init_data __initdata = {
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index d48fa4a..0cd5d55 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -265,6 +265,7 @@
#define MMPLL1_PLL_STATUS (0x005C)
#define MMSS_PLL_VOTE_APCS (0x0100)
#define VCODEC0_CMD_RCGR (0x1000)
+#define VENUS0_BCR (0x1020)
#define VENUS0_VCODEC0_CBCR (0x1028)
#define VENUS0_AHB_CBCR (0x1030)
#define VENUS0_AXI_CBCR (0x1034)
@@ -274,6 +275,7 @@
#define BYTE0_CMD_RCGR (0x2120)
#define ESC0_CMD_RCGR (0x2160)
#define MDSS_AHB_CBCR (0x2308)
+#define MDSS_BCR (0x2300)
#define MDSS_AXI_CBCR (0x2310)
#define MDSS_PCLK0_CBCR (0x2314)
#define MDSS_MDP_CBCR (0x231C)
@@ -312,18 +314,22 @@
#define CAMSS_TOP_AHB_CBCR (0x3484)
#define CAMSS_MICRO_AHB_CBCR (0x3494)
#define JPEG0_CMD_RCGR (0x3500)
+#define CAMSS_JPEG_BCR (0x35A0)
#define CAMSS_JPEG_JPEG0_CBCR (0x35A8)
#define CAMSS_JPEG_JPEG_AHB_CBCR (0x35B4)
#define CAMSS_JPEG_JPEG_AXI_CBCR (0x35B8)
#define VFE0_CMD_RCGR (0x3600)
#define CPP_CMD_RCGR (0x3640)
+#define CAMSS_VFE_BCR (0x36A0)
#define CAMSS_VFE_VFE0_CBCR (0x36A8)
#define CAMSS_VFE_CPP_CBCR (0x36B0)
#define CAMSS_VFE_CPP_AHB_CBCR (0x36B4)
#define CAMSS_VFE_VFE_AHB_CBCR (0x36B8)
#define CAMSS_VFE_VFE_AXI_CBCR (0x36BC)
+#define CAMSS_CSI_VFE0_BCR (0x3700)
#define CAMSS_CSI_VFE0_CBCR (0x3704)
#define OXILI_GFX3D_CBCR (0x4028)
+#define OXILICX_BCR (0x4030)
#define OXILICX_AXI_CBCR (0x4038)
#define OXILICX_AHB_CBCR (0x403C)
#define MMPLL2_PLL_MODE (0x4100)
@@ -2255,6 +2261,7 @@
static struct branch_clk camss_csi_vfe0_clk = {
.cbcr_reg = CAMSS_CSI_VFE0_CBCR,
+ .bcr_reg = CAMSS_CSI_VFE0_BCR,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -2302,6 +2309,7 @@
static struct branch_clk camss_jpeg_jpeg0_clk = {
.cbcr_reg = CAMSS_JPEG_JPEG0_CBCR,
+ .bcr_reg = CAMSS_JPEG_BCR,
.has_sibling = 0,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -2430,6 +2438,7 @@
static struct branch_clk camss_vfe_vfe0_clk = {
.cbcr_reg = CAMSS_VFE_VFE0_CBCR,
+ .bcr_reg = CAMSS_VFE_BCR,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -2512,6 +2521,7 @@
static struct branch_clk mdss_mdp_clk = {
.cbcr_reg = MDSS_MDP_CBCR,
+ .bcr_reg = MDSS_BCR,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -2608,6 +2618,7 @@
static struct branch_clk oxili_gfx3d_clk = {
.cbcr_reg = OXILI_GFX3D_CBCR,
+ .bcr_reg = OXILICX_BCR,
.has_sibling = 0,
.max_div = 0,
.base = &virt_bases[MMSS_BASE],
@@ -2667,6 +2678,7 @@
static struct branch_clk venus0_vcodec0_clk = {
.cbcr_reg = VENUS0_VCODEC0_CBCR,
+ .bcr_reg = VENUS0_BCR,
.has_sibling = 0,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -3376,11 +3388,19 @@
/* MM sensor clocks */
CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6f.qcom,camera"),
- CLK_LOOKUP("cam_src_clk", mclk1_clk_src.c, "90.qcom,camera"),
+ CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "90.qcom,camera"),
CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6d.qcom,camera"),
+ CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6a.qcom,camera"),
+ CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6c.qcom,camera"),
CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6f.qcom,camera"),
- CLK_LOOKUP("cam_clk", camss_mclk1_clk.c, "90.qcom,camera"),
+ CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "90.qcom,camera"),
CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6d.qcom,camera"),
+ CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6a.qcom,camera"),
+ CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6c.qcom,camera"),
+
+ /* eeprom clocks */
+ CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6c.qcom,eeprom"),
+ CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6c.qcom,eeprom"),
/* CCI clocks */
CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 1e91d5b..0677525 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -1547,7 +1547,7 @@
F_END
};
-static CLK_SDC(sdc1_clk, 1, 6, 52000000, 104000000);
+static CLK_SDC(sdc1_clk, 1, 6, 52000000, 208000000);
static CLK_SDC(sdc2_clk, 2, 5, 52000000, 104000000);
static CLK_SDC(sdc3_clk, 3, 4, 104000000, 208000000);
static CLK_SDC(sdc4_clk, 4, 3, 33000000, 67000000);
@@ -3047,7 +3047,7 @@
return branch_reset(&to_pix_rdi_clk(c)->b, action);
}
-static int pix_rdi_clk_list_rate(struct clk *c, unsigned n)
+static long pix_rdi_clk_list_rate(struct clk *c, unsigned n)
{
if (pix_rdi_mux_map[n])
return n;
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index bd5a12e..a8cb46e 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -336,6 +336,8 @@
#define USB_HS_AHB_CBCR 0x0488
#define SDCC1_APPS_CBCR 0x04C4
#define SDCC1_AHB_CBCR 0x04C8
+#define SDCC1_CDCCAL_SLEEP_CBCR 0x04E4
+#define SDCC1_CDCCAL_FF_CBCR 0x04E8
#define SDCC2_APPS_CBCR 0x0504
#define SDCC2_AHB_CBCR 0x0508
#define SDCC3_APPS_CBCR 0x0544
@@ -810,7 +812,6 @@
static DEFINE_CLK_VOTER(snoc_msmbus_clk, &snoc_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(cnoc_msmbus_clk, &cnoc_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(pnoc_msmbus_a_clk, &pnoc_a_clk.c, LONG_MAX);
-static DEFINE_CLK_VOTER(pnoc_pm_clk, &pnoc_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(snoc_msmbus_a_clk, &snoc_a_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(cnoc_msmbus_a_clk, &cnoc_a_clk.c, LONG_MAX);
@@ -822,6 +823,7 @@
static DEFINE_CLK_VOTER(ocmemgx_msmbus_a_clk, &ocmemgx_a_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(ocmemgx_core_clk, &ocmemgx_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pnoc_keepalive_a_clk, &pnoc_a_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(pnoc_sps_clk, &pnoc_clk.c, 0);
static DEFINE_CLK_BRANCH_VOTER(cxo_otg_clk, &cxo_clk_src.c);
@@ -1399,7 +1401,7 @@
F_END
};
-static struct clk_freq_tbl ftbl_gcc_ce1_v3_clk[] = {
+static struct clk_freq_tbl ftbl_gcc_ce1_pro_clk[] = {
F( 50000000, gpll0, 12, 0, 0),
F( 75000000, gpll0, 8, 0, 0),
F(100000000, gpll0, 6, 0, 0),
@@ -1427,7 +1429,7 @@
F_END
};
-static struct clk_freq_tbl ftbl_gcc_ce2_v3_clk[] = {
+static struct clk_freq_tbl ftbl_gcc_ce2_pro_clk[] = {
F( 50000000, gpll0, 12, 0, 0),
F( 75000000, gpll0, 8, 0, 0),
F(100000000, gpll0, 6, 0, 0),
@@ -2315,6 +2317,28 @@
},
};
+static struct branch_clk gcc_sdcc1_cdccal_ff_clk = {
+ .cbcr_reg = SDCC1_CDCCAL_FF_CBCR,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .parent = &cxo_clk_src.c,
+ .dbg_name = "gcc_sdcc1_cdccal_ff_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_sdcc1_cdccal_ff_clk.c),
+ },
+};
+
+static struct branch_clk gcc_sdcc1_cdccal_sleep_clk = {
+ .cbcr_reg = SDCC1_CDCCAL_SLEEP_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_sdcc1_cdccal_sleep_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_sdcc1_cdccal_sleep_clk.c),
+ },
+};
+
static struct branch_clk gcc_sdcc2_ahb_clk = {
.cbcr_reg = SDCC2_AHB_CBCR,
.has_sibling = 1,
@@ -2921,12 +2945,12 @@
F_END
};
-static struct clk_freq_tbl ftbl_camss_mclk0_3_v3_clk[] = {
+static struct clk_freq_tbl ftbl_camss_mclk0_3_pro_clk[] = {
F_MM( 4800000, cxo, 4, 0, 0),
F_MM( 6000000, gpll0, 10, 1, 10),
F_MM( 8000000, gpll0, 15, 1, 5),
F_MM( 9600000, cxo, 2, 0, 0),
- F_MM(16000000, gpll0, 10, 1, 5),
+ F_MM(16000000, gpll0, 12.5, 1, 3),
F_MM(19200000, cxo, 1, 0, 0),
F_MM(24000000, gpll0, 5, 1, 5),
F_MM(32000000, mmpll0, 5, 1, 5),
@@ -3682,6 +3706,7 @@
static struct branch_clk camss_csi_vfe0_clk = {
.cbcr_reg = CAMSS_CSI_VFE0_CBCR,
+ .bcr_reg = CAMSS_CSI_VFE0_BCR,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -3694,6 +3719,7 @@
static struct branch_clk camss_csi_vfe1_clk = {
.cbcr_reg = CAMSS_CSI_VFE1_CBCR,
+ .bcr_reg = CAMSS_CSI_VFE1_BCR,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -3741,6 +3767,7 @@
static struct branch_clk camss_jpeg_jpeg0_clk = {
.cbcr_reg = CAMSS_JPEG_JPEG0_CBCR,
+ .bcr_reg = CAMSS_JPEG_BCR,
.has_sibling = 0,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -3941,6 +3968,7 @@
static struct branch_clk camss_vfe_vfe0_clk = {
.cbcr_reg = CAMSS_VFE_VFE0_CBCR,
+ .bcr_reg = CAMSS_VFE_BCR,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -4142,6 +4170,7 @@
static struct branch_clk mdss_mdp_clk = {
.cbcr_reg = MDSS_MDP_CBCR,
+ .bcr_reg = MDSS_BCR,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -4335,6 +4364,7 @@
static struct branch_clk oxili_gfx3d_clk = {
.cbcr_reg = OXILI_GFX3D_CBCR,
+ .bcr_reg = OXILI_BCR,
.base = &virt_bases[MMSS_BASE],
.c = {
.parent = &oxili_gfx3d_clk_src.c,
@@ -4432,6 +4462,8 @@
{&gcc_usb30_master_clk.c, GCC_BASE, 0x0050},
{&gcc_blsp2_qup3_i2c_apps_clk.c, GCC_BASE, 0x00b4},
{&gcc_usb_hsic_system_clk.c, GCC_BASE, 0x0059},
+ {&gcc_sdcc1_cdccal_sleep_clk.c, GCC_BASE, 0x006a},
+ {&gcc_sdcc1_cdccal_ff_clk.c, GCC_BASE, 0x006b},
{&gcc_blsp2_uart3_apps_clk.c, GCC_BASE, 0x00b5},
{&gcc_usb_hsic_io_cal_clk.c, GCC_BASE, 0x005b},
{&gcc_ce2_axi_clk.c, GCC_BASE, 0x0141},
@@ -4654,7 +4686,8 @@
clk->multiplier = 4;
clk_sel = 0x16A;
- if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 1) {
+ if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 1 &&
+ cpu_is_msm8974()) {
if (measure_mux[i].debug_mux == M_L2)
regval = BIT(7)|BIT(0);
else
@@ -4845,6 +4878,8 @@
static struct clk_lookup msm_clocks_8974ac_only[] __initdata = {
CLK_LOOKUP("gpll4", gpll4_clk_src.c, ""),
+ CLK_LOOKUP("sleep_clk", gcc_sdcc1_cdccal_sleep_clk.c, "msm_sdcc.1"),
+ CLK_LOOKUP("cal_clk", gcc_sdcc1_cdccal_ff_clk.c, "msm_sdcc.1"),
};
static struct clk_lookup msm_clocks_8974_common[] __initdata = {
@@ -5262,6 +5297,7 @@
CLK_LOOKUP("core_clk", gcc_prng_ahb_clk.c, "msm_rng"),
CLK_LOOKUP("dfab_clk", pnoc_sps_clk.c, "msm_sps"),
+ CLK_LOOKUP("bus_clk", pnoc_keepalive_a_clk.c, ""),
CLK_LOOKUP("bus_clk", snoc_clk.c, ""),
CLK_LOOKUP("bus_clk", pnoc_clk.c, ""),
@@ -5279,7 +5315,6 @@
CLK_LOOKUP("bus_clk", snoc_msmbus_clk.c, "msm_sys_noc"),
CLK_LOOKUP("bus_a_clk", snoc_msmbus_a_clk.c, "msm_sys_noc"),
CLK_LOOKUP("bus_clk", pnoc_msmbus_clk.c, "msm_periph_noc"),
- CLK_LOOKUP("bus_clk", pnoc_pm_clk.c, "pm_8x60"),
CLK_LOOKUP("bus_a_clk", pnoc_msmbus_a_clk.c, "msm_periph_noc"),
CLK_LOOKUP("mem_clk", bimc_msmbus_clk.c, "msm_bimc"),
CLK_LOOKUP("mem_a_clk", bimc_msmbus_a_clk.c, "msm_bimc"),
@@ -5484,15 +5519,21 @@
.mn_ena_mask = BIT(24),
.main_output_val = BIT(0),
.main_output_mask = BIT(0),
+ .aux_output_val = BIT(1),
+ .aux_output_mask = BIT(1),
};
+#define cpu_is_msm8974pro() (cpu_is_msm8974pro_aa() || cpu_is_msm8974pro_ab() \
+ || cpu_is_msm8974pro_ac())
+
static void __init reg_init(void)
{
u32 regval;
configure_sr_hpm_lp_pll(&mmpll0_config, &mmpll0_regs, 1);
- if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 2) {
+ if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 2
+ || cpu_is_msm8974pro()) {
configure_sr_hpm_lp_pll(&mmpll1_v2_config, &mmpll1_regs, 1);
configure_sr_hpm_lp_pll(&mmpll3_v2_config, &mmpll3_regs, 0);
} else {
@@ -5509,7 +5550,8 @@
* V2 requires additional votes to allow the LPASS and MMSS
* controllers to use GPLL0.
*/
- if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 2) {
+ if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 2
+ || cpu_is_msm8974pro()) {
regval = readl_relaxed(
GCC_REG_BASE(APCS_CLOCK_BRANCH_ENA_VOTE));
writel_relaxed(regval | BIT(26) | BIT(25),
@@ -5519,7 +5561,8 @@
static void __init msm8974_clock_post_init(void)
{
- if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 2) {
+ if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 2
+ || cpu_is_msm8974pro()) {
clk_set_rate(&axi_clk_src.c, 291750000);
clk_set_rate(&ocmemnoc_clk_src.c, 291750000);
} else {
@@ -5535,6 +5578,12 @@
clk_prepare_enable(&mmssnoc_ahb_a_clk.c);
/*
+ * Hold an active set vote for the PNOC AHB source. Sleep set vote is 0.
+ */
+ clk_set_rate(&pnoc_keepalive_a_clk.c, 19200000);
+ clk_prepare_enable(&pnoc_keepalive_a_clk.c);
+
+ /*
* Hold an active set vote for CXO; this is because CXO is expected
* to remain on whenever CPUs aren't power collapsed.
*/
@@ -5627,35 +5676,44 @@
qup_i2c_clks[i][0]->parent = qup_i2c_clks[i][1];
}
-/* v2 to v3 clock changes */
-static void __init msm8974_v3_clock_override(void)
+/* v2 to pro clock changes */
+static void __init msm8974_pro_clock_override(void)
{
ce1_clk_src.c.fmax[VDD_DIG_LOW] = 75000000;
ce1_clk_src.c.fmax[VDD_DIG_NOMINAL] = 150000000;
- ce1_clk_src.freq_tbl = ftbl_gcc_ce1_v3_clk;
+ ce1_clk_src.freq_tbl = ftbl_gcc_ce1_pro_clk;
ce2_clk_src.c.fmax[VDD_DIG_LOW] = 75000000;
ce2_clk_src.c.fmax[VDD_DIG_NOMINAL] = 150000000;
- ce2_clk_src.freq_tbl = ftbl_gcc_ce2_v3_clk;
+ ce2_clk_src.freq_tbl = ftbl_gcc_ce2_pro_clk;
- sdcc1_apps_clk_src.c.fmax[VDD_DIG_LOW] = 200000000;
- sdcc1_apps_clk_src.c.fmax[VDD_DIG_NOMINAL] = 400000000;
+ if (cpu_is_msm8974pro_ac()) {
+ sdcc1_apps_clk_src.c.fmax[VDD_DIG_LOW] = 200000000;
+ sdcc1_apps_clk_src.c.fmax[VDD_DIG_NOMINAL] = 400000000;
+ }
vfe0_clk_src.c.fmax[VDD_DIG_LOW] = 150000000;
vfe0_clk_src.c.fmax[VDD_DIG_NOMINAL] = 320000000;
- vfe0_clk_src.c.fmax[VDD_DIG_HIGH] = 465000000;
vfe1_clk_src.c.fmax[VDD_DIG_LOW] = 150000000;
vfe1_clk_src.c.fmax[VDD_DIG_NOMINAL] = 320000000;
- vfe1_clk_src.c.fmax[VDD_DIG_HIGH] = 465000000;
cpp_clk_src.c.fmax[VDD_DIG_LOW] = 150000000;
cpp_clk_src.c.fmax[VDD_DIG_NOMINAL] = 320000000;
- cpp_clk_src.c.fmax[VDD_DIG_HIGH] = 465000000;
+
+ if (cpu_is_msm8974pro_ab() || cpu_is_msm8974pro_ac()) {
+ vfe0_clk_src.c.fmax[VDD_DIG_HIGH] = 465000000;
+ vfe1_clk_src.c.fmax[VDD_DIG_HIGH] = 465000000;
+ cpp_clk_src.c.fmax[VDD_DIG_HIGH] = 465000000;
+ } else if (cpu_is_msm8974pro_aa()) {
+ vfe0_clk_src.c.fmax[VDD_DIG_HIGH] = 320000000;
+ vfe1_clk_src.c.fmax[VDD_DIG_HIGH] = 320000000;
+ cpp_clk_src.c.fmax[VDD_DIG_HIGH] = 320000000;
+ }
mdp_clk_src.c.fmax[VDD_DIG_NOMINAL] = 266670000;
- mclk0_clk_src.freq_tbl = ftbl_camss_mclk0_3_v3_clk;
- mclk1_clk_src.freq_tbl = ftbl_camss_mclk0_3_v3_clk;
- mclk2_clk_src.freq_tbl = ftbl_camss_mclk0_3_v3_clk;
- mclk3_clk_src.freq_tbl = ftbl_camss_mclk0_3_v3_clk;
+ mclk0_clk_src.freq_tbl = ftbl_camss_mclk0_3_pro_clk;
+ mclk1_clk_src.freq_tbl = ftbl_camss_mclk0_3_pro_clk;
+ mclk2_clk_src.freq_tbl = ftbl_camss_mclk0_3_pro_clk;
+ mclk3_clk_src.freq_tbl = ftbl_camss_mclk0_3_pro_clk;
mclk0_clk_src.set_rate = set_rate_mnd;
mclk1_clk_src.set_rate = set_rate_mnd;
mclk2_clk_src.set_rate = set_rate_mnd;
@@ -5699,10 +5757,11 @@
msm8974_clock_init_data.size -= ARRAY_SIZE(msm_clocks_8974ac_only);
/* version specific changes */
- if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 2)
+ if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 2
+ || cpu_is_msm8974pro())
msm8974_v2_clock_override();
- if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 3) {
- msm8974_v3_clock_override();
+ if (cpu_is_msm8974pro()) {
+ msm8974_pro_clock_override();
memcpy(msm_clocks_8974 + ARRAY_SIZE(msm_clocks_8974_common),
msm_clocks_8974ac_only, sizeof(msm_clocks_8974ac_only));
msm8974_clock_init_data.size +=
diff --git a/arch/arm/mach-msm/clock-debug.c b/arch/arm/mach-msm/clock-debug.c
index 8ec87d1..35917c3 100644
--- a/arch/arm/mach-msm/clock-debug.c
+++ b/arch/arm/mach-msm/clock-debug.c
@@ -161,25 +161,62 @@
DEFINE_SIMPLE_ATTRIBUTE(clock_hwcg_fops, clock_debug_hwcg_get,
NULL, "%llu\n");
+static void clock_print_fmax_by_level(struct seq_file *m, int level)
+{
+ struct clk *clock = m->private;
+ struct clk_vdd_class *vdd_class = clock->vdd_class;
+ int off, i, vdd_level, nregs = vdd_class->num_regulators;
+
+ vdd_level = find_vdd_level(clock, clock->rate);
+
+ seq_printf(m, "%2s%10lu", vdd_level == level ? "[" : "",
+ clock->fmax[level]);
+ for (i = 0; i < nregs; i++) {
+ off = nregs*level + i;
+ if (vdd_class->vdd_uv)
+ seq_printf(m, "%10u", vdd_class->vdd_uv[off]);
+ if (vdd_class->vdd_ua)
+ seq_printf(m, "%10u", vdd_class->vdd_ua[off]);
+ }
+
+ if (vdd_level == level)
+ seq_puts(m, "]");
+ seq_puts(m, "\n");
+}
+
static int fmax_rates_show(struct seq_file *m, void *unused)
{
struct clk *clock = m->private;
- int level = 0;
+ struct clk_vdd_class *vdd_class = clock->vdd_class;
+ int level = 0, i, nregs = vdd_class->num_regulators;
+ char reg_name[10];
int vdd_level = find_vdd_level(clock, clock->rate);
if (vdd_level < 0) {
seq_printf(m, "could not find_vdd_level for %s, %ld\n",
- clock->dbg_name, clock->rate);
+ clock->dbg_name, clock->rate);
return 0;
}
- for (level = 0; level < clock->num_fmax; level++) {
- if (vdd_level == level)
- seq_printf(m, "[%lu] ", clock->fmax[level]);
- else
- seq_printf(m, "%lu ", clock->fmax[level]);
+
+ seq_printf(m, "%12s", "");
+ for (i = 0; i < nregs; i++) {
+ snprintf(reg_name, ARRAY_SIZE(reg_name), "reg %d", i);
+ seq_printf(m, "%10s", reg_name);
+ if (vdd_class->vdd_ua)
+ seq_printf(m, "%10s", "");
+ }
+
+ seq_printf(m, "\n%12s", "freq");
+ for (i = 0; i < nregs; i++) {
+ seq_printf(m, "%10s", "uV");
+ if (vdd_class->vdd_ua)
+ seq_printf(m, "%10s", "uA");
}
seq_printf(m, "\n");
+ for (level = 0; level < clock->num_fmax; level++)
+ clock_print_fmax_by_level(m, level);
+
return 0;
}
@@ -195,14 +232,92 @@
.release = seq_release,
};
+#define clock_debug_output(m, c, fmt, ...) \
+do { \
+ if (m) \
+ seq_printf(m, fmt, ##__VA_ARGS__); \
+ else if (c) \
+ pr_cont(fmt, ##__VA_ARGS__); \
+ else \
+ pr_info(fmt, ##__VA_ARGS__); \
+} while (0)
+
+static int clock_debug_print_clock(struct clk *c, struct seq_file *m)
+{
+ char *start = "";
+
+ if (!c || !c->prepare_count)
+ return 0;
+
+ clock_debug_output(m, 0, "\t");
+ do {
+ if (c->vdd_class)
+ clock_debug_output(m, 1, "%s%s:%u:%u [%ld, %lu]", start,
+ c->dbg_name, c->prepare_count, c->count,
+ c->rate, c->vdd_class->cur_level);
+ else
+ clock_debug_output(m, 1, "%s%s:%u:%u [%ld]", start,
+ c->dbg_name, c->prepare_count, c->count,
+ c->rate);
+ start = " -> ";
+ } while ((c = clk_get_parent(c)));
+
+ clock_debug_output(m, 1, "\n");
+
+ return 1;
+}
+
+/**
+ * clock_debug_print_enabled_clocks() - Print names of enabled clocks
+ *
+ */
+static void clock_debug_print_enabled_clocks(struct seq_file *m)
+{
+ struct clk_table *table;
+ unsigned long flags;
+ int i, cnt = 0;
+
+ clock_debug_output(m, 0, "Enabled clocks:\n");
+ spin_lock_irqsave(&clk_list_lock, flags);
+ list_for_each_entry(table, &clk_list, node) {
+ for (i = 0; i < table->num_clocks; i++)
+ cnt += clock_debug_print_clock(table->clocks[i].clk, m);
+ }
+ spin_unlock_irqrestore(&clk_list_lock, flags);
+
+ if (cnt)
+ clock_debug_output(m, 0, "Enabled clock count: %d\n", cnt);
+ else
+ clock_debug_output(m, 0, "No clocks enabled.\n");
+}
+
+static int enabled_clocks_show(struct seq_file *m, void *unused)
+{
+ clock_debug_print_enabled_clocks(m);
+ return 0;
+}
+
+static int enabled_clocks_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, enabled_clocks_show, inode->i_private);
+}
+
+static const struct file_operations enabled_clocks_fops = {
+ .open = enabled_clocks_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
static int list_rates_show(struct seq_file *m, void *unused)
{
struct clk *clock = m->private;
- int rate, level, fmax = 0, i = 0;
+ int level, i = 0;
+ unsigned long rate, fmax = 0;
/* Find max frequency supported within voltage constraints. */
if (!clock->vdd_class) {
- fmax = INT_MAX;
+ fmax = ULONG_MAX;
} else {
for (level = 0; level < clock->num_fmax; level++)
if (clock->fmax[level])
@@ -213,9 +328,9 @@
* List supported frequencies <= fmax. Higher frequencies may appear in
* the frequency table, but are not valid and should not be listed.
*/
- while ((rate = clock->ops->list_rate(clock, i++)) >= 0) {
+ while (!IS_ERR_VALUE(rate = clock->ops->list_rate(clock, i++))) {
if (rate <= fmax)
- seq_printf(m, "%u\n", rate);
+ seq_printf(m, "%lu\n", rate);
}
return 0;
@@ -377,6 +492,10 @@
return -ENOMEM;
}
+ if (!debugfs_create_file("enabled_clocks", S_IRUGO, debugfs_base, NULL,
+ &enabled_clocks_fops))
+ return -ENOMEM;
+
measure = clk_get_sys("debug", "measure");
if (IS_ERR(measure))
measure = NULL;
@@ -423,55 +542,13 @@
return ret;
}
-static int clock_debug_print_clock(struct clk *c)
-{
- char *start = "";
-
- if (!c || !c->prepare_count)
- return 0;
-
- pr_info("\t");
- do {
- if (c->vdd_class)
- pr_cont("%s%s:%u:%u [%ld, %lu]", start, c->dbg_name,
- c->prepare_count, c->count, c->rate,
- c->vdd_class->cur_level);
- else
- pr_cont("%s%s:%u:%u [%ld]", start, c->dbg_name,
- c->prepare_count, c->count, c->rate);
- start = " -> ";
- } while ((c = clk_get_parent(c)));
-
- pr_cont("\n");
-
- return 1;
-}
-
-/**
- * clock_debug_print_enabled() - Print names of enabled clocks for suspend debug
- *
+/*
* Print the names of enabled clocks and their parents if debug_suspend is set
*/
void clock_debug_print_enabled(void)
{
- struct clk_table *table;
- unsigned long flags;
- int i, cnt = 0;
-
if (likely(!debug_suspend))
return;
- pr_info("Enabled clocks:\n");
- spin_lock_irqsave(&clk_list_lock, flags);
- list_for_each_entry(table, &clk_list, node) {
- for (i = 0; i < table->num_clocks; i++)
- cnt += clock_debug_print_clock(table->clocks[i].clk);
- }
- spin_unlock_irqrestore(&clk_list_lock, flags);
-
- if (cnt)
- pr_info("Enabled clock count: %d\n", cnt);
- else
- pr_info("No clocks enabled.\n");
-
+ clock_debug_print_enabled_clocks(NULL);
}
diff --git a/arch/arm/mach-msm/clock-dsi-8610.c b/arch/arm/mach-msm/clock-dsi-8610.c
index 44b332e..73196fe 100644
--- a/arch/arm/mach-msm/clock-dsi-8610.c
+++ b/arch/arm/mach-msm/clock-dsi-8610.c
@@ -192,7 +192,7 @@
status = readl_relaxed(dsi_base + DSI_DSIPHY_PLL_CTRL_0);
if (!status & DSI_PLL_RDY_BIT) {
pr_err("DSI PLL not ready\n");
- clk_disable(dsi_ahb_clk);
+ clk_disable_unprepare(dsi_ahb_clk);
return HANDOFF_DISABLED_CLK;
}
@@ -370,35 +370,19 @@
return HANDOFF_ENABLED_CLK;
}
-int dsi_prepare(struct clk *clk)
-{
- return clk_prepare(dsi_ahb_clk);
-}
-
-void dsi_unprepare(struct clk *clk)
-{
- clk_unprepare(dsi_ahb_clk);
-}
-
struct clk_ops clk_ops_dsi_dsiclk = {
- .prepare = dsi_prepare,
- .unprepare = dsi_unprepare,
.set_rate = dsi_dsiclk_set_rate,
.round_rate = dsi_dsiclk_round_rate,
.handoff = dsi_dsiclk_handoff,
};
struct clk_ops clk_ops_dsi_byteclk = {
- .prepare = dsi_prepare,
- .unprepare = dsi_unprepare,
.set_rate = dsi_byteclk_set_rate,
.round_rate = dsi_byteclk_round_rate,
.handoff = dsi_byteclk_handoff,
};
struct clk_ops clk_ops_dsi_vco = {
- .prepare = dsi_prepare,
- .unprepare = dsi_unprepare,
.enable = dsi_pll_vco_enable,
.disable = dsi_pll_vco_disable,
.set_rate = dsi_pll_vco_set_rate,
diff --git a/arch/arm/mach-msm/clock-dummy.c b/arch/arm/mach-msm/clock-dummy.c
index 883a5c2..139c756 100644
--- a/arch/arm/mach-msm/clock-dummy.c
+++ b/arch/arm/mach-msm/clock-dummy.c
@@ -1,4 +1,4 @@
-/* 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
@@ -19,6 +19,7 @@
static int dummy_clk_set_rate(struct clk *clk, unsigned long rate)
{
+ clk->rate = rate;
return 0;
}
@@ -34,7 +35,7 @@
static unsigned long dummy_clk_get_rate(struct clk *clk)
{
- return 0;
+ return clk->rate;
}
static long dummy_clk_round_rate(struct clk *clk, unsigned long rate)
@@ -42,7 +43,7 @@
return rate;
}
-static struct clk_ops clk_ops_dummy = {
+struct clk_ops clk_ops_dummy = {
.reset = dummy_clk_reset,
.set_rate = dummy_clk_set_rate,
.set_max_rate = dummy_clk_set_max_rate,
diff --git a/arch/arm/mach-msm/clock-generic.c b/arch/arm/mach-msm/clock-generic.c
index e66764f..b0d32a0 100644
--- a/arch/arm/mach-msm/clock-generic.c
+++ b/arch/arm/mach-msm/clock-generic.c
@@ -93,6 +93,7 @@
struct clk *new_parent = NULL;
int rc = 0, i;
unsigned long new_par_curr_rate;
+ unsigned long flags;
for (i = 0; i < mux->num_parents; i++) {
if (clk_round_rate(mux->parents[i].src, rate) == rate) {
@@ -108,8 +109,16 @@
* same and the parent might temporarily turn off while switching
* rates.
*/
- if (mux->safe_sel >= 0)
+ if (mux->safe_sel >= 0) {
+ /*
+ * Some mux implementations might switch to/from a low power
+ * parent as part of their disable/enable ops. Grab the
+ * enable lock to avoid racing with these implementations.
+ */
+ spin_lock_irqsave(&c->lock, flags);
rc = mux->ops->set_mux_sel(mux, mux->safe_sel);
+ spin_unlock_irqrestore(&c->lock, flags);
+ }
if (rc)
return rc;
@@ -266,6 +275,12 @@
if (rrate != rate)
return -EINVAL;
+ /*
+ * 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. __div_round_rate() ensures div ==
+ * d->div if !d->ops.
+ */
if (div > d->div)
rc = d->ops->set_div(d, div);
if (rc)
@@ -299,7 +314,7 @@
static int div_enable(struct clk *c)
{
struct div_clk *d = to_div_clk(c);
- if (d->ops->enable)
+ if (d->ops && d->ops->enable)
return d->ops->enable(d);
return 0;
}
@@ -307,7 +322,7 @@
static void div_disable(struct clk *c)
{
struct div_clk *d = to_div_clk(c);
- if (d->ops->disable)
+ if (d->ops && d->ops->disable)
return d->ops->disable(d);
}
@@ -315,7 +330,7 @@
{
struct div_clk *d = to_div_clk(c);
- if (d->ops->get_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;
@@ -389,8 +404,13 @@
if (div == d->div)
return 0;
- if (d->ops->set_div)
- rc = d->ops->set_div(d, div);
+ /*
+ * 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.
+ */
+ rc = d->ops->set_div(d, div);
if (rc)
return rc;
diff --git a/arch/arm/mach-msm/clock-krypton.c b/arch/arm/mach-msm/clock-krypton.c
index aaee003..0b615cc 100644
--- a/arch/arm/mach-msm/clock-krypton.c
+++ b/arch/arm/mach-msm/clock-krypton.c
@@ -46,6 +46,8 @@
CLK_DUMMY("mem_clk", bimc_msmbus_clk.c, "msm_bimc", OFF),
CLK_DUMMY("mem_a_clk", bimc_msmbus_a_clk.c, "msm_bimc", OFF),
CLK_DUMMY("mem_clk", bimc_acpu_a_clk.c, "", OFF),
+ CLK_DUMMY("dfab_clk", DFAB_CLK, "msm_sps", OFF),
+ CLK_DUMMY("dma_bam_pclk", DMA_BAM_P_CLK, "msm_sps", OFF),
CLK_DUMMY("clktype", gcc_imem_axi_clk , "drivername", OFF),
CLK_DUMMY("clktype", gcc_imem_cfg_ahb_clk , "drivername", OFF),
diff --git a/arch/arm/mach-msm/clock-local.c b/arch/arm/mach-msm/clock-local.c
index 0b8240c..18ea514 100644
--- a/arch/arm/mach-msm/clock-local.c
+++ b/arch/arm/mach-msm/clock-local.c
@@ -579,7 +579,7 @@
}
/* Return the nth supported frequency for a given clock. */
-static int rcg_clk_list_rate(struct clk *c, unsigned n)
+static long rcg_clk_list_rate(struct clk *c, unsigned n)
{
struct rcg_clk *rcg = to_rcg_clk(c);
@@ -944,7 +944,7 @@
return rate > to_cdiv_clk(c)->max_div ? -EPERM : rate;
}
-static int cdiv_clk_list_rate(struct clk *c, unsigned n)
+static long cdiv_clk_list_rate(struct clk *c, unsigned n)
{
return n > to_cdiv_clk(c)->max_div ? -ENXIO : n;
}
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index fd790e2..b7852fe 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -210,7 +210,7 @@
}
/* Return the nth supported frequency for a given clock. */
-static int rcg_clk_list_rate(struct clk *c, unsigned n)
+static long rcg_clk_list_rate(struct clk *c, unsigned n)
{
struct rcg_clk *rcg = to_rcg_clk(c);
@@ -459,7 +459,7 @@
return clk_get_rate(c->parent);
}
-static int branch_clk_list_rate(struct clk *c, unsigned n)
+static long branch_clk_list_rate(struct clk *c, unsigned n)
{
int level, fmax = 0, rate;
struct branch_clk *branch = to_branch_clk(c);
@@ -934,7 +934,7 @@
return ERR_PTR(-EPERM);
}
-static int cam_mux_clk_list_rate(struct clk *c, unsigned n)
+static long cam_mux_clk_list_rate(struct clk *c, unsigned n)
{
struct cam_mux_clk *mux = to_cam_mux_clk(c);
int i;
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index 6877b4d9..47332a4 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -854,6 +854,17 @@
return div;
}
+static void dsi_pll_toggle_lock_detect(void)
+{
+ 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,
+ 0x04);
+ udelay(1);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG2,
+ 0x05);
+}
+
static int dsi_pll_lock_status(void)
{
u32 status;
@@ -875,6 +886,12 @@
return pll_locked;
}
+static inline int dsi_pll_toggle_lock_detect_and_check_status(void)
+{
+ dsi_pll_toggle_lock_detect();
+ return dsi_pll_lock_status();
+}
+
static void dsi_pll_software_reset(void)
{
/*
@@ -906,7 +923,7 @@
DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
udelay(1000);
- pll_locked = dsi_pll_lock_status();
+ pll_locked = dsi_pll_toggle_lock_detect_and_check_status();
for (i = 0; (i < 4) && !pll_locked; i++) {
DSS_REG_W(mdss_dsi_base,
DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x07);
@@ -917,7 +934,7 @@
DSS_REG_W(mdss_dsi_base,
DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
udelay(1000);
- pll_locked = dsi_pll_lock_status();
+ pll_locked = dsi_pll_toggle_lock_detect_and_check_status();
}
if (pll_locked)
@@ -953,7 +970,7 @@
DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
udelay(1000);
- pll_locked = dsi_pll_lock_status();
+ pll_locked = dsi_pll_toggle_lock_detect_and_check_status();
pr_debug("%s: PLL status = %s\n", __func__,
pll_locked ? "Locked" : "Unlocked");
@@ -982,7 +999,7 @@
DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
udelay(1000);
- pll_locked = dsi_pll_lock_status();
+ pll_locked = dsi_pll_toggle_lock_detect_and_check_status();
pr_debug("%s: PLL status = %s\n", __func__,
pll_locked ? "Locked" : "Unlocked");
@@ -1007,7 +1024,7 @@
DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
udelay(1000);
- pll_locked = dsi_pll_lock_status();
+ pll_locked = dsi_pll_toggle_lock_detect_and_check_status();
pr_debug("%s: PLL status = %s\n", __func__,
pll_locked ? "Locked" : "Unlocked");
@@ -1034,7 +1051,7 @@
DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
udelay(1000);
- pll_locked = dsi_pll_lock_status();
+ pll_locked = dsi_pll_toggle_lock_detect_and_check_status();
pr_debug("%s: PLL status = %s\n", __func__,
pll_locked ? "Locked" : "Unlocked");
@@ -1118,7 +1135,7 @@
return rc;
}
-static int vco_enable(struct clk *c)
+static int dsi_pll_enable(struct clk *c)
{
int i, rc = 0;
struct dsi_pll_vco_clk *vco = to_vco_clk(c);
@@ -1146,7 +1163,7 @@
return rc;
}
-static void vco_disable(struct clk *c)
+static void dsi_pll_disable(struct clk *c)
{
int rc = 0;
@@ -1367,19 +1384,32 @@
static int vco_prepare(struct clk *c)
{
- return vco_set_rate(c, vco_cached_rate);
+ int rc = 0;
+
+ if (vco_cached_rate != 0) {
+ rc = vco_set_rate(c, vco_cached_rate);
+ if (rc) {
+ pr_err("%s: vco_set_rate failed. rc=%d\n",
+ __func__, rc);
+ goto error;
+ }
+ }
+
+ rc = dsi_pll_enable(c);
+
+error:
+ return rc;
}
static void vco_unprepare(struct clk *c)
{
vco_cached_rate = c->rate;
+ dsi_pll_disable(c);
}
/* Op structures */
static struct clk_ops clk_ops_dsi_vco = {
- .enable = vco_enable,
- .disable = vco_disable,
.set_rate = vco_set_rate,
.round_rate = vco_round_rate,
.handoff = vco_handoff,
diff --git a/arch/arm/mach-msm/clock-pll.c b/arch/arm/mach-msm/clock-pll.c
index 908107e..a251784 100644
--- a/arch/arm/mach-msm/clock-pll.c
+++ b/arch/arm/mach-msm/clock-pll.c
@@ -57,6 +57,18 @@
#define ENABLE_WAIT_MAX_LOOPS 200
#define PLL_LOCKED_BIT BIT(16)
+static int fixed_pll_clk_set_rate(struct clk *c, unsigned long rate)
+{
+ if (rate != c->rate)
+ return -EINVAL;
+ return 0;
+}
+
+static long fixed_pll_clk_round_rate(struct clk *c, unsigned long rate)
+{
+ return c->rate;
+}
+
static int pll_vote_clk_enable(struct clk *c)
{
u32 ena, count;
@@ -119,6 +131,8 @@
.enable = pll_vote_clk_enable,
.disable = pll_vote_clk_disable,
.is_enabled = pll_vote_clk_is_enabled,
+ .round_rate = fixed_pll_clk_round_rate,
+ .set_rate = fixed_pll_clk_set_rate,
.handoff = pll_vote_clk_handoff,
};
@@ -574,6 +588,8 @@
struct clk_ops clk_ops_pll = {
.enable = pll_clk_enable,
.disable = pll_clk_disable,
+ .round_rate = fixed_pll_clk_round_rate,
+ .set_rate = fixed_pll_clk_set_rate,
.handoff = pll_clk_handoff,
.is_enabled = pll_clk_is_enabled,
};
@@ -625,6 +641,8 @@
struct clk_ops clk_ops_pll_acpu_vote = {
.enable = pll_acpu_vote_clk_enable,
.disable = pll_acpu_vote_clk_disable,
+ .round_rate = fixed_pll_clk_round_rate,
+ .set_rate = fixed_pll_clk_set_rate,
.is_enabled = pll_vote_clk_is_enabled,
.handoff = pll_acpu_vote_clk_handoff,
};
@@ -676,6 +694,12 @@
regval |= config->main_output_val;
}
+ /* Enable the aux output */
+ if (config->aux_output_mask) {
+ regval &= ~config->aux_output_mask;
+ regval |= config->aux_output_val;
+ }
+
/* Set pre-divider and post-divider values */
regval &= ~config->pre_div_mask;
regval |= config->pre_div_val;
diff --git a/arch/arm/mach-msm/clock-pll.h b/arch/arm/mach-msm/clock-pll.h
index c4addb2..58c00b9 100644
--- a/arch/arm/mach-msm/clock-pll.h
+++ b/arch/arm/mach-msm/clock-pll.h
@@ -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
@@ -184,6 +184,8 @@
u32 mn_ena_mask;
u32 main_output_val;
u32 main_output_mask;
+ u32 aux_output_val;
+ u32 aux_output_mask;
};
struct pll_config_regs {
diff --git a/arch/arm/mach-msm/clock-rpm.c b/arch/arm/mach-msm/clock-rpm.c
index 8356207..1d7a5e2 100644
--- a/arch/arm/mach-msm/clock-rpm.c
+++ b/arch/arm/mach-msm/clock-rpm.c
@@ -42,7 +42,7 @@
int rc;
struct msm_rpm_iv_pair iv = { .id = r->rpm_status_id, };
rc = msm_rpm_get_status(&iv, 1);
- return (rc < 0) ? rc : iv.value * r->factor;
+ return (rc < 0) ? rc : iv.value * 1000;
}
static int clk_rpmrs_handoff(struct rpm_clk *r)
@@ -54,7 +54,7 @@
return rc;
if (!r->branch)
- r->c.rate = iv.value * r->factor;
+ r->c.rate = iv.value * 1000;
return 0;
}
@@ -122,7 +122,7 @@
unsigned long *active_khz, unsigned long *sleep_khz)
{
/* Convert the rate (hz) to khz */
- *active_khz = DIV_ROUND_UP(rate, r->factor);
+ *active_khz = DIV_ROUND_UP(rate, 1000);
/*
* Active-only clocks don't care what the rate is during sleep. So,
diff --git a/arch/arm/mach-msm/clock-rpm.h b/arch/arm/mach-msm/clock-rpm.h
index b20c3d6..d283861 100644
--- a/arch/arm/mach-msm/clock-rpm.h
+++ b/arch/arm/mach-msm/clock-rpm.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
@@ -39,9 +39,7 @@
const bool active_only;
bool enabled;
bool branch; /* true: RPM only accepts 1 for ON and 0 for OFF */
- unsigned factor;
struct clk_rpmrs_data *rpmrs_data;
-
struct rpm_clk *peer;
struct clk c;
};
@@ -69,7 +67,6 @@
.rpm_status_id = (stat_id), \
.rpm_key = (key), \
.peer = &active, \
- .factor = 1000, \
.rpmrs_data = (rpmrsdata),\
.c = { \
.ops = &clk_ops_rpm, \
@@ -85,7 +82,6 @@
.rpm_key = (key), \
.peer = &name, \
.active_only = true, \
- .factor = 1000, \
.rpmrs_data = (rpmrsdata),\
.c = { \
.ops = &clk_ops_rpm, \
@@ -104,7 +100,6 @@
.rpm_status_id = (stat_id), \
.rpm_key = (key), \
.peer = &active, \
- .factor = 1000, \
.branch = true, \
.rpmrs_data = (rpmrsdata),\
.c = { \
@@ -121,7 +116,6 @@
.rpm_key = (key), \
.peer = &name, \
.active_only = true, \
- .factor = 1000, \
.branch = true, \
.rpmrs_data = (rpmrsdata),\
.c = { \
@@ -132,46 +126,13 @@
}, \
};
-#define __DEFINE_CLK_RPM_QDSS(name, active, type, r_id, stat_id, \
- key, rpmrsdata) \
- static struct rpm_clk active; \
- static struct rpm_clk name = { \
- .rpm_res_type = (type), \
- .rpm_clk_id = (r_id), \
- .rpm_status_id = (stat_id), \
- .rpm_key = (key), \
- .peer = &active, \
- .factor = 1, \
- .rpmrs_data = (rpmrsdata),\
- .c = { \
- .ops = &clk_ops_rpm, \
- .dbg_name = #name, \
- CLK_INIT(name.c), \
- }, \
- }; \
- static struct rpm_clk active = { \
- .rpm_res_type = (type), \
- .rpm_clk_id = (r_id), \
- .rpm_status_id = (stat_id), \
- .rpm_key = (key), \
- .peer = &name, \
- .active_only = true, \
- .factor = 1, \
- .rpmrs_data = (rpmrsdata),\
- .c = { \
- .ops = &clk_ops_rpm, \
- .dbg_name = #active, \
- CLK_INIT(active.c), \
- }, \
- };
-
#define DEFINE_CLK_RPM(name, active, r_id, dep) \
__DEFINE_CLK_RPM(name, active, 0, MSM_RPM_ID_##r_id##_CLK, \
MSM_RPM_STATUS_ID_##r_id##_CLK, dep, 0, &clk_rpmrs_data)
#define DEFINE_CLK_RPM_QDSS(name, active) \
- __DEFINE_CLK_RPM_QDSS(name, active, 0, MSM_RPM_ID_QDSS_CLK, \
- MSM_RPM_STATUS_ID_QDSS_CLK, 0, &clk_rpmrs_data)
+ __DEFINE_CLK_RPM(name, active, 0, MSM_RPM_ID_QDSS_CLK, \
+ MSM_RPM_STATUS_ID_QDSS_CLK, 0, 0, &clk_rpmrs_data)
#define DEFINE_CLK_RPM_BRANCH(name, active, r_id, r) \
__DEFINE_CLK_RPM_BRANCH(name, active, 0, MSM_RPM_ID_##r_id##_CLK, \
@@ -186,8 +147,8 @@
RPM_SMD_KEY_ENABLE, &clk_rpmrs_data_smd)
#define DEFINE_CLK_RPM_SMD_QDSS(name, active, type, r_id) \
- __DEFINE_CLK_RPM_QDSS(name, active, type, r_id, \
- 0, RPM_SMD_KEY_STATE, &clk_rpmrs_data_smd)
+ __DEFINE_CLK_RPM(name, active, type, r_id, \
+ 0, 0, RPM_SMD_KEY_STATE, &clk_rpmrs_data_smd)
/*
* The RPM XO buffer clock management code aggregates votes for pin-control mode
* and software mode separately. Software-enable has higher priority over pin-
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index 3c43223..527d73d 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -485,11 +485,16 @@
start_rate = clk->rate;
+ if (clk->ops->pre_set_rate)
+ rc = clk->ops->pre_set_rate(clk, rate);
+ if (rc)
+ goto out;
+
/* Enforce vdd requirements for target frequency. */
if (clk->prepare_count) {
rc = vote_rate_vdd(clk, rate);
if (rc)
- goto out;
+ goto err_vote_vdd;
}
rc = clk->ops->set_rate(clk, rate);
@@ -501,6 +506,9 @@
if (clk->prepare_count)
unvote_rate_vdd(clk, start_rate);
+ if (clk->ops->post_set_rate)
+ clk->ops->post_set_rate(clk, start_rate);
+
out:
mutex_unlock(&clk->prepare_lock);
return rc;
@@ -508,6 +516,10 @@
err_set_rate:
if (clk->prepare_count)
unvote_rate_vdd(clk, rate);
+err_vote_vdd:
+ /* clk->rate is still the old rate. So, pass the new rate instead. */
+ if (clk->ops->post_set_rate)
+ clk->ops->post_set_rate(clk, rate);
goto out;
}
EXPORT_SYMBOL(clk_set_rate);
diff --git a/arch/arm/mach-msm/cpr-regulator.c b/arch/arm/mach-msm/cpr-regulator.c
index 5550282..60a62ec 100644
--- a/arch/arm/mach-msm/cpr-regulator.c
+++ b/arch/arm/mach-msm/cpr-regulator.c
@@ -125,21 +125,9 @@
#define CPR_FUSE_RO_SEL_BITS 3
#define CPR_FUSE_RO_SEL_BITS_MASK ((1<<CPR_FUSE_RO_SEL_BITS)-1)
-#define CPR_FUSE_TARGET_QUOT_TURBO_SHIFT 0
-#define CPR_FUSE_TARGET_QUOT_NOMINAL_SHIFT 12
-#define CPR_FUSE_TARGET_QUOT_SVS_SHIFT 24
+#define CPR_FUSE_MIN_QUOT_DIFF 100
-#define CPR_FUSE_DISABLE_CPR_SHIFT 36
-#define CPR_FUSE_LOCAL_APPROACH_SHIFT 37
-#define CPR_FUSE_REDUNDANT_SHIFT 57
-
-/* PVS eFuse parameters */
-#define PVS_FUSE_REDUNDANT_SHIFT 24
-#define PVS_FUSE_REDUNDANT_BITS 3
-#define PVS_FUSE_REDUNDANT_MASK ((1<<PVS_FUSE_REDUNDANT_BITS)-1)
-
-#define PVS_FUSE_BINS_SHIFT 6
-#define PVS_FUSE_BINS_REDUNDANT_SHIFT 27
+#define BYTES_PER_FUSE_ROW 8
enum voltage_change_dir {
NO_CHANGE,
@@ -154,9 +142,11 @@
int corner;
int ceiling_max;
+ /* eFuse parameters */
+ phys_addr_t efuse_addr;
+ void __iomem *efuse_base;
+
/* Process voltage parameters */
- phys_addr_t pvs_efuse;
- u32 num_efuse_bits;
u32 pvs_bin_process[CPR_PVS_EFUSE_BINS_MAX];
u32 pvs_corner_v[NUM_APC_PVS][CPR_CORNER_MAX];
/* Process voltage variables */
@@ -173,12 +163,9 @@
int vdd_mx_vmin;
/* CPR parameters */
- phys_addr_t cpr_fuse_addr;
u64 cpr_fuse_bits;
- u64 cpr_fuse_bits_2;
bool cpr_fuse_disable;
bool cpr_fuse_local;
- bool cpr_fuse_redundancy;
int cpr_fuse_target_quot[CPR_CORNER_MAX];
int cpr_fuse_ro_sel[CPR_CORNER_MAX];
int gcnt;
@@ -215,16 +202,26 @@
u32 vdd_apc_step_down_limit;
};
-static int cpr_debug_enable;
+#define CPR_DEBUG_MASK_IRQ BIT(0)
+#define CPR_DEBUG_MASK_API BIT(1)
+
+static int cpr_debug_enable = CPR_DEBUG_MASK_IRQ;
static int cpr_enable;
static struct cpr_regulator *the_cpr;
module_param_named(debug_enable, cpr_debug_enable, int, S_IRUGO | S_IWUSR);
#define cpr_debug(message, ...) \
do { \
- if (cpr_debug_enable) \
+ if (cpr_debug_enable & CPR_DEBUG_MASK_API) \
pr_info(message, ##__VA_ARGS__); \
} while (0)
+#define cpr_debug_irq(message, ...) \
+ do { \
+ if (cpr_debug_enable & CPR_DEBUG_MASK_IRQ) \
+ pr_info(message, ##__VA_ARGS__); \
+ else \
+ pr_debug(message, ##__VA_ARGS__); \
+ } while (0)
static bool cpr_is_allowed(struct cpr_regulator *cpr_vreg)
{
@@ -282,11 +279,12 @@
cpr_masked_write(cpr_vreg, REG_RBCPR_CTL, mask, value);
}
-static void cpr_ctl_enable(struct cpr_regulator *cpr_vreg)
+static void cpr_ctl_enable(struct cpr_regulator *cpr_vreg, int corner)
{
u32 val;
- if (cpr_is_allowed(cpr_vreg))
+ if (cpr_is_allowed(cpr_vreg) &&
+ (cpr_vreg->ceiling_volt[corner] > cpr_vreg->floor_volt[corner]))
val = RBCPR_CTL_LOOP_EN;
else
val = 0;
@@ -384,7 +382,7 @@
cpr_ctl_disable(the_cpr);
cpr_irq_clr(the_cpr);
cpr_corner_restore(the_cpr, the_cpr->corner);
- cpr_ctl_enable(the_cpr);
+ cpr_ctl_enable(the_cpr, the_cpr->corner);
} else {
cpr_ctl_disable(the_cpr);
cpr_irq_set(the_cpr, 0);
@@ -500,16 +498,16 @@
& RBCPR_RESULT0_ERROR_STEPS_MASK;
last_volt = cpr_vreg->last_volt[corner];
- cpr_debug("last_volt[corner:%d] = %d uV\n", corner, last_volt);
+ cpr_debug_irq("last_volt[corner:%d] = %d uV\n", corner, last_volt);
if (dir == UP) {
- cpr_debug("Up: cpr status = 0x%08x (error_steps=%d)\n",
- reg_val, error_steps);
+ 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("[corn:%d] @ ceiling: %d >= %d: NACK\n",
- corner, 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]);
cpr_irq_clr_nack(cpr_vreg);
/* Maximize the UP threshold */
@@ -521,17 +519,18 @@
}
if (error_steps > cpr_vreg->vdd_apc_step_up_limit) {
- cpr_debug("%d is over up-limit(%d): Clamp\n",
- error_steps,
- cpr_vreg->vdd_apc_step_up_limit);
+ cpr_debug_irq("%d is over up-limit(%d): Clamp\n",
+ error_steps,
+ cpr_vreg->vdd_apc_step_up_limit);
error_steps = cpr_vreg->vdd_apc_step_up_limit;
}
/* Calculate new voltage */
new_volt = last_volt + (error_steps * cpr_vreg->step_volt);
if (new_volt > cpr_vreg->ceiling_volt[corner]) {
- cpr_debug("new_volt(%d) >= ceiling_volt(%d): Clamp\n",
- new_volt, cpr_vreg->ceiling_volt[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];
}
@@ -557,15 +556,16 @@
/* Ack */
cpr_irq_clr_ack(cpr_vreg);
- cpr_debug("UP: -> new_volt = %d uV\n", new_volt);
+ cpr_debug_irq("UP: -> new_volt[corner:%d] = %d uV\n",
+ corner, new_volt);
} else if (dir == DOWN) {
- cpr_debug("Down: cpr status = 0x%08x (error_steps=%d)\n",
- reg_val, error_steps);
+ 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("[corn:%d] @ floor: %d <= %d: NACK\n",
- corner, 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]);
cpr_irq_clr_nack(cpr_vreg);
/* Maximize the DOWN threshold */
@@ -586,17 +586,18 @@
}
if (error_steps > cpr_vreg->vdd_apc_step_down_limit) {
- cpr_debug("%d is over down-limit(%d): Clamp\n",
- error_steps,
- cpr_vreg->vdd_apc_step_down_limit);
+ cpr_debug_irq("%d is over down-limit(%d): Clamp\n",
+ error_steps,
+ cpr_vreg->vdd_apc_step_down_limit);
error_steps = cpr_vreg->vdd_apc_step_down_limit;
}
/* Calculte new voltage */
new_volt = last_volt - (error_steps * cpr_vreg->step_volt);
if (new_volt < cpr_vreg->floor_volt[corner]) {
- cpr_debug("new_volt(%d) < floor_volt(%d): Clamp\n",
- new_volt, cpr_vreg->floor_volt[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];
}
@@ -616,7 +617,8 @@
/* Ack */
cpr_irq_clr_ack(cpr_vreg);
- cpr_debug("DOWN: -> new_volt = %d uV\n", new_volt);
+ cpr_debug_irq("DOWN: -> new_volt[corner:%d] = %d uV\n",
+ corner, new_volt);
}
}
@@ -628,7 +630,7 @@
mutex_lock(&cpr_vreg->cpr_mutex);
reg_val = cpr_read(cpr_vreg, REG_RBIF_IRQ_STATUS);
- cpr_debug("IRQ_STATUS = 0x%02X\n", reg_val);
+ cpr_debug_irq("IRQ_STATUS = 0x%02X\n", reg_val);
if (!cpr_is_allowed(cpr_vreg)) {
reg_val = cpr_read(cpr_vreg, REG_RBCPR_CTL);
@@ -647,7 +649,7 @@
cpr_irq_clr_nack(cpr_vreg);
} else if (reg_val & CPR_INT_MID) {
/* RBCPR_CTL_SW_AUTO_CONT_ACK_EN is enabled */
- cpr_debug("IRQ occured for Mid Flag\n");
+ cpr_debug_irq("IRQ occured for Mid Flag\n");
} else {
pr_err("IRQ occured for unknown flag (0x%08x)\n", reg_val);
}
@@ -693,7 +695,7 @@
if (cpr_is_allowed(cpr_vreg) && cpr_vreg->corner) {
cpr_irq_clr(cpr_vreg);
cpr_corner_switch(cpr_vreg, cpr_vreg->corner);
- cpr_ctl_enable(cpr_vreg);
+ cpr_ctl_enable(cpr_vreg, cpr_vreg->corner);
}
mutex_unlock(&cpr_vreg->cpr_mutex);
@@ -759,7 +761,7 @@
if (cpr_is_allowed(cpr_vreg) && cpr_vreg->vreg_enabled) {
cpr_irq_clr(cpr_vreg);
cpr_corner_switch(cpr_vreg, corner);
- cpr_ctl_enable(cpr_vreg);
+ cpr_ctl_enable(cpr_vreg, corner);
}
cpr_vreg->corner = corner;
@@ -808,7 +810,7 @@
cpr_irq_clr(cpr_vreg);
enable_irq(cpr_vreg->cpr_irq);
- cpr_ctl_enable(cpr_vreg);
+ cpr_ctl_enable(cpr_vreg, cpr_vreg->corner);
return 0;
}
@@ -838,7 +840,7 @@
#define cpr_regulator_resume NULL
#endif
-static int cpr_config(struct cpr_regulator *cpr_vreg)
+static int __devinit cpr_config(struct cpr_regulator *cpr_vreg)
{
int i;
u32 val, gcnt, reg;
@@ -928,47 +930,80 @@
return 0;
}
-static int __init cpr_pvs_init(struct cpr_regulator *cpr_vreg)
+static int __devinit cpr_is_fuse_redundant(struct cpr_regulator *cpr_vreg,
+ u32 redun_sel[4])
{
- void __iomem *efuse_base;
- u32 efuse_bits, redundant, shift, mask;
- int i, process;
+ u32 fuse_bits;
+ int redundant;
- efuse_base = ioremap(cpr_vreg->pvs_efuse, 4);
- if (!efuse_base) {
- pr_err("Unable to map pvs_efuse 0x%08x\n",
- cpr_vreg->pvs_efuse);
- return -EINVAL;
+ fuse_bits = readl_relaxed(cpr_vreg->efuse_base
+ + redun_sel[0] * BYTES_PER_FUSE_ROW);
+ fuse_bits = (fuse_bits >> redun_sel[1]) & ((1 << redun_sel[2]) - 1);
+ if (fuse_bits == redun_sel[3])
+ redundant = 1;
+ else
+ redundant = 0;
+
+ pr_info("[row:%d] = 0x%x @%d:%d = %d?: redundant=%d\n",
+ redun_sel[0], fuse_bits,
+ redun_sel[1], redun_sel[2], redun_sel[3], redundant);
+ return redundant;
+}
+
+static int __devinit cpr_pvs_init(struct platform_device *pdev,
+ struct cpr_regulator *cpr_vreg)
+{
+ struct device_node *of_node = pdev->dev.of_node;
+ u32 efuse_bits;
+ int rc, process;
+ u32 pvs_fuse[3], pvs_fuse_redun_sel[4];
+ bool redundant;
+ size_t pvs_bins;
+
+ rc = of_property_read_u32_array(of_node, "qcom,pvs-fuse-redun-sel",
+ pvs_fuse_redun_sel, 4);
+ if (rc < 0) {
+ pr_err("pvs-fuse-redun-sel missing: rc=%d\n", rc);
+ return rc;
}
- efuse_bits = readl_relaxed(efuse_base);
+ redundant = cpr_is_fuse_redundant(cpr_vreg, pvs_fuse_redun_sel);
+
+ if (redundant) {
+ rc = of_property_read_u32_array(of_node, "qcom,pvs-fuse-redun",
+ pvs_fuse, 3);
+ 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);
+ if (rc < 0) {
+ pr_err("pvs-fuse missing: rc=%d\n", rc);
+ return rc;
+ }
+ }
/* Construct PVS process # from the efuse bits */
- redundant = (efuse_bits >> PVS_FUSE_REDUNDANT_SHIFT)
- & PVS_FUSE_REDUNDANT_MASK;
- if (redundant == 2)
- shift = PVS_FUSE_BINS_REDUNDANT_SHIFT;
- else
- shift = PVS_FUSE_BINS_SHIFT;
- mask = (1 << cpr_vreg->num_efuse_bits) - 1;
- cpr_vreg->pvs_bin = (efuse_bits >> shift) & mask;
+ efuse_bits = readl_relaxed(cpr_vreg->efuse_base +
+ pvs_fuse[0] * BYTES_PER_FUSE_ROW);
+ cpr_vreg->pvs_bin = (efuse_bits >> pvs_fuse[1]) &
+ ((1 << pvs_fuse[2]) - 1);
- /* 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];
-
- iounmap(efuse_base);
+ pvs_bins = 1 << pvs_fuse[2];
+ rc = of_property_read_u32_array(of_node, "qcom,pvs-bin-process",
+ cpr_vreg->pvs_bin_process,
+ pvs_bins);
+ if (rc < 0) {
+ pr_err("pvs-bin-process missing: rc=%d\n", rc);
+ return rc;
+ }
process = cpr_vreg->pvs_bin_process[cpr_vreg->pvs_bin];
- pr_info("[0x%08X] = 0x%08X, n_bits=%d, bin=%d (%d) [redundant=%d]\n",
- cpr_vreg->pvs_efuse, efuse_bits, cpr_vreg->num_efuse_bits,
- cpr_vreg->pvs_bin, process, redundant);
- 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]);
- }
+ pr_info("[row:%d] = 0x%08X, n_bits=%d, bin=%d (%d)\n",
+ pvs_fuse[0], efuse_bits, pvs_fuse[2],
+ cpr_vreg->pvs_bin, process);
if (process == APC_PVS_NO || process >= NUM_APC_PVS) {
pr_err("Bin=%d (%d) is out of spec. Assume SLOW.\n",
@@ -994,7 +1029,7 @@
} \
} while (0)
-static int __init cpr_apc_init(struct platform_device *pdev,
+static int __devinit cpr_apc_init(struct platform_device *pdev,
struct cpr_regulator *cpr_vreg)
{
struct device_node *of_node = pdev->dev.of_node;
@@ -1055,90 +1090,156 @@
}
}
-static int __init cpr_init_cpr_efuse(struct cpr_regulator *cpr_vreg)
+static int __devinit cpr_init_cpr_efuse(struct platform_device *pdev,
+ struct cpr_regulator *cpr_vreg)
{
- void __iomem *efuse_base;
+ struct device_node *of_node = pdev->dev.of_node;
+ int i, rc = 0;
+ bool redundant;
+ u32 cpr_fuse_redun_sel[4];
+ char *targ_quot_str, *ro_sel_str;
+ u32 cpr_fuse_row;
+ u32 bp_cpr_disable, bp_scheme;
+ int bp_target_quot[CPR_CORNER_MAX];
+ int bp_ro_sel[CPR_CORNER_MAX];
u32 ro_sel, val;
- u64 fuse_bits;
- int ro_sel_shift[CPR_CORNER_MAX];
+ u64 fuse_bits, fuse_bits_2;
- efuse_base = ioremap(cpr_vreg->cpr_fuse_addr, 16);
- if (!efuse_base) {
- pr_err("Unable to map cpr_fuse_addr 0x%08x\n",
- cpr_vreg->cpr_fuse_addr);
- return -EINVAL;
+ rc = of_property_read_u32_array(of_node, "qcom,cpr-fuse-redun-sel",
+ cpr_fuse_redun_sel, 4);
+ if (rc < 0) {
+ pr_err("cpr-fuse-redun-sel missing: rc=%d\n", rc);
+ return rc;
}
- cpr_vreg->cpr_fuse_bits = readll_relaxed(efuse_base);
- cpr_vreg->cpr_fuse_bits_2 = readll_relaxed(efuse_base + 8);
+ redundant = cpr_is_fuse_redundant(cpr_vreg, cpr_fuse_redun_sel);
- iounmap(efuse_base);
+ if (redundant) {
+ CPR_PROP_READ_U32(of_node, "cpr-fuse-redun-row",
+ &cpr_fuse_row, rc);
+ 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);
+ targ_quot_str = "qcom,cpr-fuse-target-quot";
+ ro_sel_str = "qcom,cpr-fuse-ro-sel";
+ }
+ if (rc)
+ return rc;
+
+ rc = of_property_read_u32_array(of_node,
+ targ_quot_str,
+ &bp_target_quot[CPR_CORNER_SVS],
+ CPR_CORNER_MAX - CPR_CORNER_SVS);
+ if (rc < 0) {
+ pr_err("missing %s: rc=%d\n", targ_quot_str, rc);
+ return rc;
+ }
+
+ rc = of_property_read_u32_array(of_node,
+ ro_sel_str,
+ &bp_ro_sel[CPR_CORNER_SVS],
+ CPR_CORNER_MAX - CPR_CORNER_SVS);
+ if (rc < 0) {
+ pr_err("missing %s: rc=%d\n", ro_sel_str, rc);
+ return rc;
+ }
/* Read the control bits of eFuse */
- cpr_vreg->cpr_fuse_disable = (cpr_vreg->cpr_fuse_bits >>
- CPR_FUSE_DISABLE_CPR_SHIFT) & 0x01;
- cpr_vreg->cpr_fuse_local = (cpr_vreg->cpr_fuse_bits >>
- CPR_FUSE_LOCAL_APPROACH_SHIFT) & 0x01;
- cpr_vreg->cpr_fuse_redundancy = (cpr_vreg->cpr_fuse_bits >>
- CPR_FUSE_REDUNDANT_SHIFT) & 0x01;
+ fuse_bits = readll_relaxed(cpr_vreg->efuse_base
+ + cpr_fuse_row * BYTES_PER_FUSE_ROW);
+ pr_info("[row:%d] = 0x%llx\n", cpr_fuse_row, fuse_bits);
- pr_info("[0x%08X] = 0x%llx\n", cpr_vreg->cpr_fuse_addr,
- cpr_vreg->cpr_fuse_bits);
- pr_info("disable = %d, local = %d, redundancy = %d\n",
- cpr_vreg->cpr_fuse_disable,
- cpr_vreg->cpr_fuse_local,
- cpr_vreg->cpr_fuse_redundancy);
- pr_info("[0x%08X] = 0x%llx\n", cpr_vreg->cpr_fuse_addr + 8,
- cpr_vreg->cpr_fuse_bits_2);
+ if (redundant) {
+ if (of_property_read_bool(of_node,
+ "qcom,cpr-fuse-redun-bp-cpr-disable")) {
+ CPR_PROP_READ_U32(of_node,
+ "cpr-fuse-redun-bp-cpr-disable",
+ &bp_cpr_disable, rc);
+ CPR_PROP_READ_U32(of_node,
+ "cpr-fuse-redun-bp-scheme",
+ &bp_scheme, rc);
+ if (rc)
+ return rc;
+ fuse_bits_2 = fuse_bits;
+ } else {
+ u32 temp_row;
- if (cpr_vreg->cpr_fuse_redundancy == 0) {
- fuse_bits = cpr_vreg->cpr_fuse_bits;
- ro_sel_shift[CPR_CORNER_SVS] = 54;
- ro_sel_shift[CPR_CORNER_NORMAL] = 38;
- ro_sel_shift[CPR_CORNER_TURBO] = 41;
+ /* 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);
+ if (rc)
+ return rc;
+ fuse_bits_2 = readll_relaxed(cpr_vreg->efuse_base
+ + temp_row * BYTES_PER_FUSE_ROW);
+ pr_info("[original row:%d] = 0x%llx\n",
+ temp_row, fuse_bits_2);
+ }
} else {
- fuse_bits = cpr_vreg->cpr_fuse_bits_2;
- ro_sel_shift[CPR_CORNER_SVS] = 46;
- ro_sel_shift[CPR_CORNER_NORMAL] = 36;
- ro_sel_shift[CPR_CORNER_TURBO] = 39;
+ 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);
+ if (rc)
+ return rc;
+ fuse_bits_2 = fuse_bits;
}
- /* SVS */
- ro_sel = (fuse_bits >> ro_sel_shift[CPR_CORNER_SVS])
- & CPR_FUSE_RO_SEL_BITS_MASK;
- val = (fuse_bits >> CPR_FUSE_TARGET_QUOT_SVS_SHIFT)
- & CPR_FUSE_TARGET_QUOT_BITS_MASK;
- cpr_vreg->cpr_fuse_target_quot[CPR_CORNER_SVS] = val;
- cpr_vreg->cpr_fuse_ro_sel[CPR_CORNER_SVS] = ro_sel;
- pr_info("SVS: ro_sel = %d, target quot = 0x%04x\n", ro_sel, val);
+ cpr_vreg->cpr_fuse_disable = (fuse_bits_2 >> bp_cpr_disable) & 0x01;
+ cpr_vreg->cpr_fuse_local = (fuse_bits_2 >> bp_scheme) & 0x01;
- /* Nominal */
- ro_sel = (fuse_bits >> ro_sel_shift[CPR_CORNER_NORMAL])
- & CPR_FUSE_RO_SEL_BITS_MASK;
- val = (fuse_bits >> CPR_FUSE_TARGET_QUOT_NOMINAL_SHIFT)
- & CPR_FUSE_TARGET_QUOT_BITS_MASK;
- cpr_vreg->cpr_fuse_target_quot[CPR_CORNER_NORMAL] = val;
- cpr_vreg->cpr_fuse_ro_sel[CPR_CORNER_NORMAL] = ro_sel;
- pr_info("Nominal: ro_sel = %d, target quot = 0x%04x\n", ro_sel, val);
+ pr_info("disable = %d, local = %d\n",
+ cpr_vreg->cpr_fuse_disable, cpr_vreg->cpr_fuse_local);
- /* Turbo */
- ro_sel = (fuse_bits >> ro_sel_shift[CPR_CORNER_TURBO])
+ for (i = CPR_CORNER_SVS; i < CPR_CORNER_MAX; i++) {
+ ro_sel = (fuse_bits >> bp_ro_sel[i])
& CPR_FUSE_RO_SEL_BITS_MASK;
- val = (fuse_bits >> CPR_FUSE_TARGET_QUOT_TURBO_SHIFT)
+ val = (fuse_bits >> bp_target_quot[i])
& CPR_FUSE_TARGET_QUOT_BITS_MASK;
- cpr_vreg->cpr_fuse_target_quot[CPR_CORNER_TURBO] = val;
- cpr_vreg->cpr_fuse_ro_sel[CPR_CORNER_TURBO] = ro_sel;
- pr_info("Turbo: ro_sel = %d, target quot = 0x%04x\n", ro_sel, val);
+ 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);
+ }
+ cpr_vreg->cpr_fuse_bits = fuse_bits;
if (!cpr_vreg->cpr_fuse_bits) {
cpr_vreg->cpr_fuse_disable = 1;
pr_err("cpr_fuse_bits = 0: set cpr_fuse_disable = 1\n");
+ } else {
+ /* Check if the target quotients are too close together */
+ 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])
+ <= CPR_FUSE_MIN_QUOT_DIFF)
+ valid_fuse = false;
+ else if ((quot[CPR_CORNER_NORMAL] -
+ quot[CPR_CORNER_SVS])
+ <= CPR_FUSE_MIN_QUOT_DIFF)
+ valid_fuse = false;
+ } else {
+ valid_fuse = false;
+ }
+
+ if (!valid_fuse) {
+ cpr_vreg->cpr_fuse_disable = 1;
+ pr_err("invalid quotient values\n");
+ }
}
return 0;
}
-static int __init cpr_init_cpr_voltages(struct cpr_regulator *cpr_vreg)
+static int __devinit cpr_init_cpr_voltages(struct cpr_regulator *cpr_vreg)
{
int i;
@@ -1155,7 +1256,7 @@
return 0;
}
-static int __init cpr_init_cpr_parameters(struct platform_device *pdev,
+static int __devinit cpr_init_cpr_parameters(struct platform_device *pdev,
struct cpr_regulator *cpr_vreg)
{
struct device_node *of_node = pdev->dev.of_node;
@@ -1223,20 +1324,12 @@
return rc;
}
-static int __init cpr_init_cpr(struct platform_device *pdev,
+static int __devinit cpr_init_cpr(struct platform_device *pdev,
struct cpr_regulator *cpr_vreg)
{
struct resource *res;
int rc = 0;
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- "cpr_efuse");
- if (!res || !res->start) {
- pr_err("cpr_efuse missing: res=%p\n", res);
- return -EINVAL;
- }
- cpr_vreg->cpr_fuse_addr = res->start;
-
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rbcpr_clk");
if (!res || !res->start) {
pr_err("missing rbcpr_clk address: res=%p\n", res);
@@ -1244,7 +1337,7 @@
}
cpr_vreg->rbcpr_clk_addr = res->start;
- rc = cpr_init_cpr_efuse(cpr_vreg);
+ rc = cpr_init_cpr_efuse(pdev, cpr_vreg);
if (rc)
return rc;
@@ -1287,44 +1380,41 @@
return 0;
}
-static int __init cpr_pvs_parse_dt(struct platform_device *pdev,
- struct cpr_regulator *cpr_vreg)
+static int __devinit cpr_efuse_init(struct platform_device *pdev,
+ struct cpr_regulator *cpr_vreg)
+{
+ struct resource *res;
+ int len;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "efuse_addr");
+ if (!res || !res->start) {
+ pr_err("efuse_addr missing: res=%p\n", res);
+ return -EINVAL;
+ }
+ cpr_vreg->efuse_addr = res->start;
+ len = res->end - res->start + 1;
+
+ pr_info("efuse_addr = 0x%x (len=0x%x)\n", res->start, len);
+
+ cpr_vreg->efuse_base = ioremap(cpr_vreg->efuse_addr, len);
+ if (!cpr_vreg->efuse_base) {
+ pr_err("Unable to map efuse_addr 0x%08x\n",
+ cpr_vreg->efuse_addr);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void cpr_efuse_free(struct cpr_regulator *cpr_vreg)
+{
+ iounmap(cpr_vreg->efuse_base);
+}
+
+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;
- struct resource *res;
- int rc;
- size_t pvs_bins;
-
- /* Parse process voltage parameters */
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pvs_efuse");
- if (!res || !res->start) {
- pr_err("pvs_efuse missing: res=%p\n", res);
- return -EINVAL;
- }
- cpr_vreg->pvs_efuse = res->start;
-
- rc = of_property_read_u32(of_node, "qcom,num-efuse-bits",
- &cpr_vreg->num_efuse_bits);
- if (rc < 0) {
- pr_err("num-efuse-bits missing: rc=%d\n", rc);
- return rc;
- }
-
- if (cpr_vreg->num_efuse_bits == 0 ||
- cpr_vreg->num_efuse_bits > CPR_PVS_EFUSE_BITS_MAX) {
- pr_err("invalid num-efuse-bits : %d\n",
- cpr_vreg->num_efuse_bits);
- return -EINVAL;
- }
-
- pvs_bins = 1 << cpr_vreg->num_efuse_bits;
- rc = of_property_read_u32_array(of_node, "qcom,pvs-bin-process",
- cpr_vreg->pvs_bin_process,
- pvs_bins);
- if (rc < 0) {
- pr_err("pvs-bin-process missing: rc=%d\n", rc);
- return rc;
- }
+ int rc, i;
rc = of_property_read_u32_array(of_node,
"qcom,pvs-corner-ceiling-slow",
@@ -1353,6 +1443,17 @@
return rc;
}
+ /* 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];
+
+ 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]);
+ }
+
return 0;
}
@@ -1386,31 +1487,39 @@
return -ENOMEM;
}
- rc = cpr_pvs_parse_dt(pdev, cpr_vreg);
+ rc = cpr_efuse_init(pdev, cpr_vreg);
if (rc) {
- pr_err("Wrong DT parameter specified: rc=%d\n", rc);
+ pr_err("Wrong eFuse address specified: rc=%d\n", rc);
return rc;
}
- rc = cpr_pvs_init(cpr_vreg);
+ rc = cpr_voltage_plan_init(pdev, cpr_vreg);
+ if (rc) {
+ pr_err("Wrong DT parameter specified: rc=%d\n", rc);
+ goto err_out;
+ }
+
+ rc = cpr_pvs_init(pdev, cpr_vreg);
if (rc) {
pr_err("Initialize PVS wrong: rc=%d\n", rc);
- return rc;
+ goto err_out;
}
rc = cpr_apc_init(pdev, cpr_vreg);
if (rc) {
if (rc != -EPROBE_DEFER)
pr_err("Initialize APC wrong: rc=%d\n", rc);
- return rc;
+ goto err_out;
}
rc = cpr_init_cpr(pdev, cpr_vreg);
if (rc) {
pr_err("Initialize CPR failed: rc=%d\n", rc);
- return rc;
+ goto err_out;
}
+ cpr_efuse_free(cpr_vreg);
+
mutex_init(&cpr_vreg->cpr_mutex);
rdesc = &cpr_vreg->rdesc;
@@ -1433,6 +1542,10 @@
the_cpr = cpr_vreg;
return 0;
+
+err_out:
+ cpr_efuse_free(cpr_vreg);
+ return rc;
}
static int __devexit cpr_regulator_remove(struct platform_device *pdev)
diff --git a/arch/arm/mach-msm/cpufreq.c b/arch/arm/mach-msm/cpufreq.c
index 2e70c83..e02df3e 100644
--- a/arch/arm/mach-msm/cpufreq.c
+++ b/arch/arm/mach-msm/cpufreq.c
@@ -128,15 +128,6 @@
struct cpufreq_frequency_table *table;
struct cpufreq_work_struct *cpu_work = NULL;
- cpumask_var_t mask;
-
- if (!cpu_active(policy->cpu)) {
- pr_info("cpufreq: cpu %d is not active.\n", policy->cpu);
- return -ENODEV;
- }
-
- if (!alloc_cpumask_var(&mask, GFP_KERNEL))
- return -ENOMEM;
mutex_lock(&per_cpu(cpufreq_suspend, policy->cpu).suspend_mutex);
@@ -164,22 +155,14 @@
cpu_work->frequency = table[index].frequency;
cpu_work->status = -ENODEV;
- cpumask_clear(mask);
- cpumask_set_cpu(policy->cpu, mask);
- if (cpumask_equal(mask, ¤t->cpus_allowed)) {
- ret = set_cpu_freq(cpu_work->policy, cpu_work->frequency);
- goto done;
- } else {
- cancel_work_sync(&cpu_work->work);
- INIT_COMPLETION(cpu_work->complete);
- queue_work_on(policy->cpu, msm_cpufreq_wq, &cpu_work->work);
- wait_for_completion(&cpu_work->complete);
- }
+ cancel_work_sync(&cpu_work->work);
+ INIT_COMPLETION(cpu_work->complete);
+ queue_work_on(policy->cpu, msm_cpufreq_wq, &cpu_work->work);
+ wait_for_completion(&cpu_work->complete);
ret = cpu_work->status;
done:
- free_cpumask_var(mask);
mutex_unlock(&per_cpu(cpufreq_suspend, policy->cpu).suspend_mutex);
return ret;
}
@@ -402,8 +385,7 @@
per_cpu(cpufreq_suspend, cpu).device_suspended = 0;
}
- msm_cpufreq_wq = alloc_workqueue("msm-cpufreq",
- WQ_MEM_RECLAIM | WQ_HIGHPRI, 1);
+ 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/idle-v7.S b/arch/arm/mach-msm/idle-v7.S
index 5d25134..f8a32b4 100644
--- a/arch/arm/mach-msm/idle-v7.S
+++ b/arch/arm/mach-msm/idle-v7.S
@@ -25,6 +25,7 @@
#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)
@@ -99,7 +100,7 @@
#ifdef CONFIG_MSM_SCM
ldr r0, =SCM_SVC_BOOT
ldr r1, =SCM_CMD_TERMINATE_PC
- mov r2, #0
+ ldr r2, =SCM_CMD_CORE_HOTPLUGGED
bl scm_call_atomic1
#else
mrc p15, 0, r3, c1, c0, 0 /* read current CR */
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 7b26bd6..6370bd4 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -183,7 +183,7 @@
};
struct msm_camera_gpio_num_info {
- uint16_t gpio_num[2];
+ uint16_t gpio_num[7];
};
struct msm_camera_gpio_conf {
diff --git a/arch/arm/mach-msm/include/mach/camera2.h b/arch/arm/mach-msm/include/mach/camera2.h
index 3e7e5fd..887c594 100644
--- a/arch/arm/mach-msm/include/mach/camera2.h
+++ b/arch/arm/mach-msm/include/mach/camera2.h
@@ -40,6 +40,7 @@
enum cci_i2c_master_t {
MASTER_0,
MASTER_1,
+ MASTER_MAX,
};
struct msm_camera_slave_info {
diff --git a/arch/arm/mach-msm/include/mach/clk-provider.h b/arch/arm/mach-msm/include/mach/clk-provider.h
index 27c6df4..75dc240 100644
--- a/arch/arm/mach-msm/include/mach/clk-provider.h
+++ b/arch/arm/mach-msm/include/mach/clk-provider.h
@@ -108,11 +108,13 @@
int (*in_hwcg_mode)(struct clk *clk);
enum handoff (*handoff)(struct clk *clk);
int (*reset)(struct clk *clk, enum clk_reset_action action);
+ int (*pre_set_rate)(struct clk *clk, unsigned long new_rate);
int (*set_rate)(struct clk *clk, unsigned long rate);
+ void (*post_set_rate)(struct clk *clk, unsigned long old_rate);
int (*set_max_rate)(struct clk *clk, unsigned long rate);
int (*set_flags)(struct clk *clk, unsigned flags);
unsigned long (*get_rate)(struct clk *clk);
- int (*list_rate)(struct clk *clk, unsigned n);
+ long (*list_rate)(struct clk *clk, unsigned n);
int (*is_enabled)(struct clk *clk);
long (*round_rate)(struct clk *clk, unsigned long rate);
int (*set_parent)(struct clk *clk, struct clk *parent);
@@ -166,6 +168,7 @@
int msm_clock_register(struct clk_lookup *table, size_t size);
extern struct clk dummy_clk;
+extern struct clk_ops clk_ops_dummy;
#define CLK_DUMMY(clk_name, clk_id, clk_dev, flags) { \
.con_id = clk_name, \
@@ -173,6 +176,16 @@
.clk = &dummy_clk, \
}
+#define DEFINE_CLK_DUMMY(name, _rate) \
+ static struct fixed_clk name = { \
+ .c = { \
+ .dbg_name = #name, \
+ .rate = _rate, \
+ .ops = &clk_ops_dummy, \
+ CLK_INIT(name.c), \
+ }, \
+ };
+
#define CLK_LOOKUP(con, c, dev) { .con_id = con, .clk = &c, .dev_id = dev }
#endif
diff --git a/arch/arm/mach-msm/include/mach/clock-generic.h b/arch/arm/mach-msm/include/mach/clock-generic.h
index 0f689f1..f6feda0 100644
--- a/arch/arm/mach-msm/include/mach/clock-generic.h
+++ b/arch/arm/mach-msm/include/mach/clock-generic.h
@@ -72,8 +72,6 @@
struct clk_div_ops {
int (*set_div)(struct div_clk *clk, int div);
int (*get_div)(struct div_clk *clk);
-
- /* Optional */
bool (*is_enabled)(struct div_clk *clk);
int (*enable)(struct div_clk *clk);
void (*disable)(struct div_clk *clk);
@@ -84,6 +82,7 @@
unsigned int min_div;
unsigned int max_div;
unsigned long rate_margin;
+ /* Optional */
struct clk_div_ops *ops;
/* Fields not used by helper function. */
diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
index 541ca44..7cfbd93 100644
--- a/arch/arm/mach-msm/include/mach/iommu.h
+++ b/arch/arm/mach-msm/include/mach/iommu.h
@@ -197,8 +197,10 @@
DUMP_REG_FSR,
DUMP_REG_FSYNR0,
DUMP_REG_FSYNR1,
- DUMP_REG_TTBR0,
- DUMP_REG_TTBR1,
+ DUMP_REG_TTBR0_0,
+ DUMP_REG_TTBR0_1,
+ DUMP_REG_TTBR1_0,
+ DUMP_REG_TTBR1_1,
DUMP_REG_SCTLR,
DUMP_REG_ACTLR,
DUMP_REG_PRRR,
@@ -216,6 +218,7 @@
unsigned long key;
const char *name;
int offset;
+ int must_be_present;
};
extern struct dump_regs_tbl dump_regs_tbl[MAX_DUMP_REGS];
@@ -324,30 +327,43 @@
static inline int msm_soc_version_supports_iommu_v0(void)
{
+ static int soc_supports_v0 = -1;
#ifdef CONFIG_OF
struct device_node *node;
+#endif
+ if (soc_supports_v0 != -1)
+ return soc_supports_v0;
+
+#ifdef CONFIG_OF
node = of_find_compatible_node(NULL, NULL, "qcom,msm-smmu-v1");
if (node) {
+ soc_supports_v0 = 0;
of_node_put(node);
return 0;
}
node = of_find_compatible_node(NULL, NULL, "qcom,msm-smmu-v0");
if (node) {
+ soc_supports_v0 = 1;
of_node_put(node);
return 1;
}
#endif
if (cpu_is_msm8960() &&
- SOCINFO_VERSION_MAJOR(socinfo_get_version()) < 2)
+ SOCINFO_VERSION_MAJOR(socinfo_get_version()) < 2) {
+ soc_supports_v0 = 0;
return 0;
+ }
if (cpu_is_msm8x60() &&
(SOCINFO_VERSION_MAJOR(socinfo_get_version()) != 2 ||
SOCINFO_VERSION_MINOR(socinfo_get_version()) < 1)) {
+ soc_supports_v0 = 0;
return 0;
}
+
+ soc_supports_v0 = 1;
return 1;
}
#endif
diff --git a/arch/arm/mach-msm/include/mach/ipa.h b/arch/arm/mach-msm/include/mach/ipa.h
index b6acef2..f79afee 100644
--- a/arch/arm/mach-msm/include/mach/ipa.h
+++ b/arch/arm/mach-msm/include/mach/ipa.h
@@ -670,6 +670,7 @@
int teth_bridge_set_aggr_params(struct teth_aggr_params *aggr_params);
void ipa_bam_reg_dump(void);
+bool ipa_emb_ul_pipes_empty(void);
#else /* CONFIG_IPA */
@@ -1113,6 +1114,11 @@
return;
}
+static inline bool ipa_emb_ul_pipes_empty(void)
+{
+ return false;
+}
+
#endif /* CONFIG_IPA*/
#endif /* _IPA_H_ */
diff --git a/arch/arm/mach-msm/include/mach/jtag.h b/arch/arm/mach-msm/include/mach/jtag.h
index 2131be6..ae006be 100644
--- a/arch/arm/mach-msm/include/mach/jtag.h
+++ b/arch/arm/mach-msm/include/mach/jtag.h
@@ -16,9 +16,11 @@
#if defined(CONFIG_MSM_JTAG) || defined(CONFIG_MSM_JTAG_MM)
extern void msm_jtag_save_state(void);
extern void msm_jtag_restore_state(void);
+extern bool msm_jtag_fuse_apps_access_disabled(void);
#else
static inline void msm_jtag_save_state(void) {}
static inline void msm_jtag_restore_state(void) {}
+static inline bool msm_jtag_fuse_apps_access_disabled(void) { return false; }
#endif
#endif
diff --git a/arch/arm/mach-msm/include/mach/mpm.h b/arch/arm/mach-msm/include/mach/mpm.h
index b92c039..e76a6a9 100644
--- a/arch/arm/mach-msm/include/mach/mpm.h
+++ b/arch/arm/mach-msm/include/mach/mpm.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
@@ -163,4 +163,23 @@
static inline void msm_mpm_exit_sleep(bool from_idle) {}
static inline void __init of_mpm_init(struct device_node *node) {}
#endif
+#ifdef CONFIG_MSM_MPM_OF
+/** msm_mpm_suspend_prepare() - Called at prepare_late() op during suspend
+ *
+ *
+ * When called the MPM driver checks if the wakeup interrupts can be monitored
+ * by MPM hardware and program them accordingly. If wake up interrupts cannot
+ * be monitored then it disallows system low power modes.
+ */
+void msm_mpm_suspend_prepare(void);
+/** msm_mpm_suspend_wake - Called during wake() op in suspend.
+ *
+ * When called MPM drivers sets the vote for system low power modes depending
+ * on the active interrupts.
+ */
+void msm_mpm_suspend_wake(void);
+#else
+static inline void msm_mpm_suspend_prepare(void){}
+static inline void msm_mpm_suspend_wake(void) {}
+#endif
#endif /* __ARCH_ARM_MACH_MSM_MPM_H */
diff --git a/arch/arm/mach-msm/include/mach/msm_hdmi_audio_codec.h b/arch/arm/mach-msm/include/mach/msm_hdmi_audio_codec.h
index 95f33d5..ff3da11 100644
--- a/arch/arm/mach-msm/include/mach/msm_hdmi_audio_codec.h
+++ b/arch/arm/mach-msm/include/mach/msm_hdmi_audio_codec.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
@@ -25,7 +25,8 @@
struct msm_hdmi_audio_codec_ops {
int (*audio_info_setup)(struct platform_device *pdev,
- u32 num_of_channels, u32 channel_allocation, u32 level_shift,
+ u32 sample_rate, u32 num_of_channels,
+ u32 channel_allocation, u32 level_shift,
bool down_mix);
int (*get_audio_edid_blk) (struct platform_device *pdev,
struct msm_hdmi_audio_edid_blk *blk);
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-krypton.h b/arch/arm/mach-msm/include/mach/msm_iomap-krypton.h
index a8b9da5..1861b48 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-krypton.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-krypton.h
@@ -23,7 +23,7 @@
*
*/
-#define MSMKRYPTON_SHARED_RAM_PHYS 0x00000000
+#define MSMKRYPTON_SHARED_RAM_PHYS 0x02200000
#define MSMKRYPTON_TLMM_PHYS 0xFD510000
#define MSMKRYPTON_TLMM_SIZE SZ_16K
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h
index 7b73333..67cf442 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap.h
@@ -115,7 +115,8 @@
#if defined(CONFIG_ARCH_MSM9615) || defined(CONFIG_ARCH_MSM7X27) \
|| defined(CONFIG_ARCH_MSM7X30) || defined(CONFIG_ARCH_MSM9625) \
- || defined(CONFIG_ARCH_MSM8610) || defined(CONFIG_ARCH_MSM8226)
+ || defined(CONFIG_ARCH_MSM8610) || defined(CONFIG_ARCH_MSM8226) \
+ || defined(CONFIG_ARCH_MSMKRYPTON)
#define MSM_SHARED_RAM_SIZE SZ_1M
#else
#define MSM_SHARED_RAM_SIZE SZ_2M
diff --git a/arch/arm/mach-msm/include/mach/msm_ipc_logging.h b/arch/arm/mach-msm/include/mach/msm_ipc_logging.h
index 0a91719..b3bf07c 100644
--- a/arch/arm/mach-msm/include/mach/msm_ipc_logging.h
+++ b/arch/arm/mach-msm/include/mach/msm_ipc_logging.h
@@ -115,6 +115,20 @@
*/
int ipc_log_string(void *ilctxt, const char *fmt, ...) __printf(2, 3);
+/**
+ * ipc_log_extract - Reads and deserializes log
+ *
+ * @ilctxt: logging context
+ * @buff: buffer to receive the data
+ * @size: size of the buffer
+ * @returns: 0 if no data read; >0 number of bytes read; < 0 error
+ *
+ * If no data is available to be read, then the ilctxt::read_avail
+ * completion is reinitialized. This allows clients to block
+ * until new log data is save.
+ */
+int ipc_log_extract(void *ilctxt, char *buff, int size);
+
/*
* Print a string to decode context.
* @dctxt Decode context
@@ -220,6 +234,9 @@
static inline int ipc_log_string(void *ilctxt, const char *fmt, ...)
{ return -EINVAL; }
+static inline int ipc_log_extract(void *ilctxt, char *buff, int size)
+{ return -EINVAL; }
+
#define IPC_SPRINTF_DECODE(dctxt, args...) do { } while (0)
static inline void tsv_timestamp_read(struct encode_context *ectxt,
diff --git a/arch/arm/mach-msm/include/mach/msm_memtypes.h b/arch/arm/mach-msm/include/mach/msm_memtypes.h
index 5c8f525..95c4fe3 100644
--- a/arch/arm/mach-msm/include/mach/msm_memtypes.h
+++ b/arch/arm/mach-msm/include/mach/msm_memtypes.h
@@ -79,5 +79,4 @@
int __init dt_scan_for_memory_hole(unsigned long node, const char *uname,
int depth, void *data);
void adjust_meminfo(unsigned long start, unsigned long size);
-unsigned long __init reserve_memory_for_fmem(unsigned long, unsigned long);
#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_smd.h b/arch/arm/mach-msm/include/mach/msm_smd.h
index 62fada1..2653ae4 100644
--- a/arch/arm/mach-msm/include/mach/msm_smd.h
+++ b/arch/arm/mach-msm/include/mach/msm_smd.h
@@ -46,6 +46,7 @@
SMD_MODEM = SMEM_MODEM,
SMD_Q6 = SMEM_Q6,
SMD_DSPS = SMEM_DSPS,
+ SMD_TZ = SMEM_DSPS,
SMD_WCNSS = SMEM_WCNSS,
SMD_MODEM_Q6_FW = SMEM_MODEM_Q6_FW,
SMD_RPM = SMEM_RPM,
@@ -72,6 +73,7 @@
SMD_MODEM_RPM,
SMD_QDSP_RPM,
SMD_WCNSS_RPM,
+ SMD_TZ_RPM,
SMD_NUM_TYPE,
SMD_LOOPBACK_TYPE = 100,
diff --git a/arch/arm/mach-msm/include/mach/msm_tspp.h b/arch/arm/mach-msm/include/mach/msm_tspp.h
index ddc99f3..2c40d83 100644
--- a/arch/arm/mach-msm/include/mach/msm_tspp.h
+++ b/arch/arm/mach-msm/include/mach/msm_tspp.h
@@ -25,7 +25,7 @@
struct tspp_data_descriptor {
void *virt_base; /* logical address of the actual data */
- u32 phys_base; /* physical address of the actual data */
+ phys_addr_t phys_base; /* physical address of the actual data */
u32 size; /* size of buffer in bytes */
int id; /* unique identifier */
void *user; /* user-defined data */
@@ -33,9 +33,9 @@
typedef void (tspp_notifier)(int channel_id, void *user);
typedef void* (tspp_allocator)(int channel_id, u32 size,
- u32 *phys_base, void *user);
+ phys_addr_t *phys_base, void *user);
typedef void (tspp_memfree)(int channel_id, u32 size,
- void *virt_base, u32 phys_base, void *user);
+ void *virt_base, phys_addr_t phys_base, void *user);
/* Kernel API functions */
int tspp_open_stream(u32 dev, u32 channel_id,
diff --git a/arch/arm/mach-msm/include/mach/ocmem_priv.h b/arch/arm/mach-msm/include/mach/ocmem_priv.h
index 6f83c53..32d58d4 100644
--- a/arch/arm/mach-msm/include/mach/ocmem_priv.h
+++ b/arch/arm/mach-msm/include/mach/ocmem_priv.h
@@ -174,8 +174,8 @@
/* Request Power State */
unsigned power_state;
struct ocmem_eviction_data *edata;
- /* Request that triggered eviction */
- struct ocmem_req *e_handle;
+ /* Eviction data of the request being evicted */
+ struct ocmem_eviction_data *eviction_info;
};
struct ocmem_handle {
diff --git a/arch/arm/mach-msm/include/mach/smem_log.h b/arch/arm/mach-msm/include/mach/smem_log.h
index 992ab05..a429bc3 100644
--- a/arch/arm/mach-msm/include/mach/smem_log.h
+++ b/arch/arm/mach-msm/include/mach/smem_log.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2009, 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2009, 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
@@ -51,6 +51,9 @@
#define SMEM_LOG_DCVS_EVENT_BASE 0x00070000
#define SMEM_LOG_SLEEP_EVENT_BASE 0x00080000
#define SMEM_LOG_RPC_ROUTER_EVENT_BASE 0x00090000
+#define SMEM_LOG_IPC_ROUTER_EVENT_BASE 0x000D0000
+#define SMEM_LOG_QMI_CCI_EVENT_BASE 0x000E0000
+#define SMEM_LOG_QMI_CSI_EVENT_BASE 0x000F0000
#if defined(CONFIG_MSM_N_WAY_SMSM)
#define DEM_SMSM_ISR (SMEM_LOG_DEM_EVENT_BASE + 0x1)
#define DEM_STATE_CHANGE (SMEM_LOG_DEM_EVENT_BASE + 0x2)
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index 52102e3..830992c 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -32,6 +32,7 @@
#define SOCINFO_VERSION_MINOR(ver) (ver & 0x0000ffff)
#ifdef CONFIG_OF
+#define of_board_is_cdp() of_machine_is_compatible("qcom,cdp")
#define of_board_is_sim() of_machine_is_compatible("qcom,sim")
#define of_board_is_rumi() of_machine_is_compatible("qcom,rumi")
#define of_board_is_fluid() of_machine_is_compatible("qcom,fluid")
diff --git a/arch/arm/mach-msm/include/mach/sps.h b/arch/arm/mach-msm/include/mach/sps.h
index 3332701..6cd4a2e 100644
--- a/arch/arm/mach-msm/include/mach/sps.h
+++ b/arch/arm/mach-msm/include/mach/sps.h
@@ -17,6 +17,34 @@
#include <linux/types.h> /* u32 */
+#ifdef CONFIG_ARM_LPAE
+
+/* Returns upper 4bits of 36bits physical address */
+#define SPS_GET_UPPER_ADDR(addr) ((addr & 0xF00000000ULL) >> 32)
+
+/* Returns 36bits physical address from 32bit address &
+ * flags word */
+#define DESC_FULL_ADDR(flags, addr) (((flags & 0xF) << 32) | addr)
+
+/* Returns flags word with flags and 4bit upper address
+ * from flags and 36bit physical address */
+#define DESC_FLAG_WORD(flags, addr) (((addr & 0xF00000000ULL) >> 32) | flags)
+
+#else
+
+#define SPS_GET_UPPER_ADDR(addr) (0)
+#define DESC_FULL_ADDR(flags, addr) (addr)
+#define DESC_FLAG_WORD(flags, addr) (flags)
+
+#endif
+
+/* Returns upper 4bits of 36bits physical address from
+ * flags word */
+#define DESC_UPPER_ADDR(flags) ((flags & 0xF))
+
+/* Returns lower 32bits of 36bits physical address */
+#define SPS_GET_LOWER_ADDR(addr) ((u32)(addr & 0xFFFFFFFF))
+
/* SPS device handle indicating use of system memory */
#define SPS_DEV_HANDLE_MEM ((u32)0x7ffffffful)
@@ -56,8 +84,8 @@
#define SPS_IOVEC_FLAG_LOCK 0x0400 /* pipe lock */
#define SPS_IOVEC_FLAG_UNLOCK 0x0200 /* pipe unlock */
#define SPS_IOVEC_FLAG_IMME 0x0100 /* immediate command descriptor */
-#define SPS_IOVEC_FLAG_NO_SUBMIT 0x0002 /* Do not submit descriptor to HW */
-#define SPS_IOVEC_FLAG_DEFAULT 0x0001 /* Use driver default */
+#define SPS_IOVEC_FLAG_NO_SUBMIT 0x0020 /* Do not submit descriptor to HW */
+#define SPS_IOVEC_FLAG_DEFAULT 0x0010 /* Use driver default */
/* Maximum descriptor/iovec size */
#define SPS_IOVEC_MAX_SIZE (32 * 1024 - 1) /* 32K-1 bytes due to HW limit */
@@ -79,6 +107,9 @@
#define SPS_BAM_NO_EXT_P_RST (1UL << 4)
/* Don't enable local clock gating */
#define SPS_BAM_NO_LOCAL_CLK_GATING (1UL << 5)
+/* Don't enable writeback cancel*/
+#define SPS_BAM_CANCEL_WB (1UL << 6)
+
/* BAM device management flags */
@@ -137,6 +168,8 @@
SPS_O_OUT_OF_DESC = 0x00000008,/* Out of descriptors */
SPS_O_ERROR = 0x00000010, /* Error */
SPS_O_EOT = 0x00000020, /* End-of-transfer */
+ SPS_O_RST_ERROR = 0x00000040, /* Pipe reset unsucessful error */
+ SPS_O_HRESP_ERROR = 0x00000080,/* Errorneous Hresponse by AHB MASTER */
/* Options to enable hardware features */
SPS_O_STREAMING = 0x00010000, /* Enable streaming mode (no EOT) */
@@ -200,6 +233,8 @@
SPS_EVENT_FLOWOFF, /* Graceful halt (idle) */
SPS_EVENT_INACTIVE, /* Inactivity timeout */
SPS_EVENT_ERROR, /* Error */
+ SPS_EVENT_RST_ERROR, /* Pipe Reset unsuccessful */
+ SPS_EVENT_HRESP_ERROR, /* Errorneous Hresponse by AHB Master*/
SPS_EVENT_MAX,
};
@@ -429,7 +464,7 @@
*/
struct sps_mem_buffer {
void *base;
- u32 phys_base;
+ phys_addr_t phys_base;
u32 size;
u32 min_size;
};
@@ -646,7 +681,7 @@
*
*/
struct sps_transfer {
- u32 iovec_phys;
+ phys_addr_t iovec_phys;
struct sps_iovec *iovec;
u32 iovec_count;
void *user;
@@ -938,7 +973,7 @@
* @return 0 on success, negative value on error
*
*/
-int sps_transfer_one(struct sps_pipe *h, u32 addr, u32 size,
+int sps_transfer_one(struct sps_pipe *h, phys_addr_t addr, u32 size,
void *user, u32 flags);
/**
@@ -1335,8 +1370,8 @@
return -EPERM;
}
-static inline int sps_transfer_one(struct sps_pipe *h, u32 addr, u32 size,
- void *user, u32 flags)
+static inline int sps_transfer_one(struct sps_pipe *h, phys_addr_t addr,
+ u32 size, void *user, u32 flags)
{
return -EPERM;
}
diff --git a/arch/arm/mach-msm/include/mach/subsystem_restart.h b/arch/arm/mach-msm/include/mach/subsystem_restart.h
index 962429e..c232cc9 100644
--- a/arch/arm/mach-msm/include/mach/subsystem_restart.h
+++ b/arch/arm/mach-msm/include/mach/subsystem_restart.h
@@ -15,6 +15,7 @@
#define __SUBSYS_RESTART_H
#include <linux/spinlock.h>
+#include <linux/interrupt.h>
#define SUBSYS_NAME_MAX_LENGTH 40
@@ -57,8 +58,15 @@
int (*powerup)(const struct subsys_desc *desc);
void (*crash_shutdown)(const struct subsys_desc *desc);
int (*ramdump)(int, const struct subsys_desc *desc);
- unsigned int err_ready_irq;
+ irqreturn_t (*err_fatal_handler) (int irq, void *dev_id);
+ irqreturn_t (*stop_ack_handler) (int irq, void *dev_id);
+ irqreturn_t (*wdog_bite_handler) (int irq, void *dev_id);
int is_not_loadable;
+ unsigned int err_fatal_irq;
+ unsigned int err_ready_irq;
+ unsigned int stop_ack_irq;
+ unsigned int wdog_bite_irq;
+ int force_stop_gpio;
};
#if defined(CONFIG_MSM_SUBSYSTEM_RESTART)
diff --git a/arch/arm/mach-msm/ipc_logging.c b/arch/arm/mach-msm/ipc_logging.c
index 43214cc..bad861d 100644
--- a/arch/arm/mach-msm/ipc_logging.c
+++ b/arch/arm/mach-msm/ipc_logging.c
@@ -34,6 +34,8 @@
static LIST_HEAD(ipc_log_context_list);
DEFINE_RWLOCK(ipc_log_context_list_lock);
static atomic_t next_log_id = ATOMIC_INIT(0);
+static void *get_deserialization_func(struct ipc_log_context *ilctxt,
+ int type);
static struct ipc_log_page *get_first_page(struct ipc_log_context *ilctxt)
{
@@ -339,6 +341,59 @@
ipc_log_write(ilctxt, &ectxt);
return 0;
}
+EXPORT_SYMBOL(ipc_log_string);
+
+/**
+ * ipc_log_extract - Reads and deserializes log
+ *
+ * @ctxt: logging context
+ * @buff: buffer to receive the data
+ * @size: size of the buffer
+ * @returns: 0 if no data read; >0 number of bytes read; < 0 error
+ *
+ * If no data is available to be read, then the ilctxt::read_avail
+ * completion is reinitialized. This allows clients to block
+ * until new log data is save.
+ */
+int ipc_log_extract(void *ctxt, char *buff, int size)
+{
+ struct encode_context ectxt;
+ struct decode_context dctxt;
+ void (*deserialize_func)(struct encode_context *ectxt,
+ struct decode_context *dctxt);
+ struct ipc_log_context *ilctxt = (struct ipc_log_context *)ctxt;
+ unsigned long flags;
+
+ if (size < MAX_MSG_DECODED_SIZE)
+ return -EINVAL;
+
+ dctxt.output_format = OUTPUT_DEBUGFS;
+ dctxt.buff = buff;
+ dctxt.size = size;
+ read_lock_irqsave(&ipc_log_context_list_lock, flags);
+ spin_lock(&ilctxt->ipc_log_context_lock);
+ while (dctxt.size >= MAX_MSG_DECODED_SIZE &&
+ !is_ilctxt_empty(ilctxt)) {
+ msg_read(ilctxt, &ectxt);
+ deserialize_func = get_deserialization_func(ilctxt,
+ ectxt.hdr.type);
+ spin_unlock(&ilctxt->ipc_log_context_lock);
+ read_unlock_irqrestore(&ipc_log_context_list_lock, flags);
+ if (deserialize_func)
+ deserialize_func(&ectxt, &dctxt);
+ else
+ pr_err("%s: unknown message 0x%x\n",
+ __func__, ectxt.hdr.type);
+ read_lock_irqsave(&ipc_log_context_list_lock, flags);
+ spin_lock(&ilctxt->ipc_log_context_lock);
+ }
+ if ((size - dctxt.size) == 0)
+ init_completion(&ilctxt->read_avail);
+ spin_unlock(&ilctxt->ipc_log_context_lock);
+ read_unlock_irqrestore(&ipc_log_context_list_lock, flags);
+ return size - dctxt.size;
+}
+EXPORT_SYMBOL(ipc_log_extract);
/*
* Helper funtion used to read data from a message context.
@@ -482,6 +537,21 @@
}
EXPORT_SYMBOL(add_deserialization_func);
+static void *get_deserialization_func(struct ipc_log_context *ilctxt,
+ int type)
+{
+ struct dfunc_info *df_info = NULL;
+
+ if (!ilctxt)
+ return NULL;
+
+ list_for_each_entry(df_info, &ilctxt->dfunc_info_list, list) {
+ if (df_info->type == type)
+ return df_info->dfunc;
+ }
+ return NULL;
+}
+
void *ipc_log_context_create(int max_num_pages,
const char *mod_name)
{
diff --git a/arch/arm/mach-msm/ipc_logging.h b/arch/arm/mach-msm/ipc_logging.h
index 36b4171..ddf194b 100644
--- a/arch/arm/mach-msm/ipc_logging.h
+++ b/arch/arm/mach-msm/ipc_logging.h
@@ -13,6 +13,8 @@
#ifndef _IPC_LOGGING_H
#define _IPC_LOGGING_H
+#include <mach/msm_ipc_logging.h>
+
struct ipc_log_page_header {
uint32_t magic;
uint32_t nmagic; /* inverse of magic number */
@@ -64,6 +66,7 @@
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#define IS_MSG_TYPE(x) (((x) > TSV_TYPE_MSG_START) && \
((x) < TSV_TYPE_MSG_END))
+#define MAX_MSG_DECODED_SIZE (MAX_MSG_SIZE*4)
extern rwlock_t ipc_log_context_list_lock;
diff --git a/arch/arm/mach-msm/ipc_logging_debug.c b/arch/arm/mach-msm/ipc_logging_debug.c
index 246fb99..8a5957c 100644
--- a/arch/arm/mach-msm/ipc_logging_debug.c
+++ b/arch/arm/mach-msm/ipc_logging_debug.c
@@ -33,58 +33,6 @@
static DEFINE_MUTEX(ipc_log_debugfs_init_lock);
static struct dentry *root_dent;
-#define MAX_MSG_DECODED_SIZE (MAX_MSG_SIZE*4)
-
-static void *get_deserialization_func(struct ipc_log_context *ilctxt,
- int type)
-{
- struct dfunc_info *df_info = NULL;
-
- if (!ilctxt)
- return NULL;
-
- list_for_each_entry(df_info, &ilctxt->dfunc_info_list, list) {
- if (df_info->type == type)
- return df_info->dfunc;
- }
- return NULL;
-}
-
-static int deserialize_log(struct ipc_log_context *ilctxt,
- char *buff, int size)
-{
- struct encode_context ectxt;
- struct decode_context dctxt;
- void (*deserialize_func)(struct encode_context *ectxt,
- struct decode_context *dctxt);
- unsigned long flags;
-
- dctxt.output_format = OUTPUT_DEBUGFS;
- dctxt.buff = buff;
- dctxt.size = size;
- read_lock_irqsave(&ipc_log_context_list_lock, flags);
- spin_lock(&ilctxt->ipc_log_context_lock);
- while (dctxt.size >= MAX_MSG_DECODED_SIZE &&
- !is_ilctxt_empty(ilctxt)) {
- msg_read(ilctxt, &ectxt);
- deserialize_func = get_deserialization_func(ilctxt,
- ectxt.hdr.type);
- spin_unlock(&ilctxt->ipc_log_context_lock);
- read_unlock_irqrestore(&ipc_log_context_list_lock, flags);
- if (deserialize_func)
- deserialize_func(&ectxt, &dctxt);
- else
- pr_err("%s: unknown message 0x%x\n",
- __func__, ectxt.hdr.type);
- read_lock_irqsave(&ipc_log_context_list_lock, flags);
- spin_lock(&ilctxt->ipc_log_context_lock);
- }
- if ((size - dctxt.size) == 0)
- init_completion(&ilctxt->read_avail);
- spin_unlock(&ilctxt->ipc_log_context_lock);
- read_unlock_irqrestore(&ipc_log_context_list_lock, flags);
- return size - dctxt.size;
-}
static int debug_log(struct ipc_log_context *ilctxt,
char *buff, int size, int cont)
@@ -97,7 +45,7 @@
return -ENOMEM;
}
do {
- i = deserialize_log(ilctxt, buff, size - 1);
+ i = ipc_log_extract(ilctxt, buff, size - 1);
if (cont && i == 0) {
wait_for_completion_interruptible(&ilctxt->read_avail);
if (signal_pending(current))
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 32589f1..c0cca1d 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -95,9 +95,9 @@
#define NTFY(x...) do { } while (0)
#endif
-#define IPC_ROUTER_LOG_EVENT_ERROR 0x10
-#define IPC_ROUTER_LOG_EVENT_TX 0x11
-#define IPC_ROUTER_LOG_EVENT_RX 0x12
+#define IPC_ROUTER_LOG_EVENT_ERROR 0x00
+#define IPC_ROUTER_LOG_EVENT_TX 0x01
+#define IPC_ROUTER_LOG_EVENT_RX 0x02
static LIST_HEAD(control_ports);
static DECLARE_RWSEM(control_ports_lock_lha5);
@@ -1798,7 +1798,7 @@
#if defined(DEBUG)
if (msm_ipc_router_debug_mask & SMEM_LOG) {
smem_log_event((SMEM_LOG_PROC_ID_APPS |
- SMEM_LOG_RPC_ROUTER_EVENT_BASE |
+ SMEM_LOG_IPC_ROUTER_EVENT_BASE |
IPC_ROUTER_LOG_EVENT_RX),
(hdr->src_node_id << 24) |
(hdr->src_port_id & 0xffffff),
@@ -2117,7 +2117,7 @@
#if defined(DEBUG)
if (msm_ipc_router_debug_mask & SMEM_LOG) {
smem_log_event((SMEM_LOG_PROC_ID_APPS |
- SMEM_LOG_RPC_ROUTER_EVENT_BASE |
+ SMEM_LOG_IPC_ROUTER_EVENT_BASE |
IPC_ROUTER_LOG_EVENT_TX),
(hdr->src_node_id << 24) |
(hdr->src_port_id & 0xffffff),
@@ -2228,6 +2228,7 @@
pr_err("%s: msm_ipc_router_send_to failed - ret: %d\n",
__func__, ret);
msm_ipc_router_free_skb(out_skb_head);
+ return ret;
}
return 0;
}
@@ -2265,6 +2266,48 @@
}
/**
+ * msm_ipc_router_rx_data_wait() - Wait for new message destined to a local port.
+ * @port_ptr: Pointer to the local port
+ * @timeout: < 0 timeout indicates infinite wait till a message arrives.
+ * > 0 timeout indicates the wait time.
+ * 0 indicates that we do not wait.
+ * @return: 0 if there are pending messages to read,
+ * standard Linux error code otherwise.
+ *
+ * Checks for the availability of messages that are destined to a local port.
+ * If no messages are present then waits as per @timeout.
+ */
+int msm_ipc_router_rx_data_wait(struct msm_ipc_port *port_ptr, long timeout)
+{
+ int ret = 0;
+
+ mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
+ while (list_empty(&port_ptr->port_rx_q)) {
+ mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
+ if (timeout < 0) {
+ ret = wait_event_interruptible(
+ port_ptr->port_rx_wait_q,
+ !list_empty(&port_ptr->port_rx_q));
+ if (ret)
+ return ret;
+ } else if (timeout > 0) {
+ timeout = wait_event_interruptible_timeout(
+ port_ptr->port_rx_wait_q,
+ !list_empty(&port_ptr->port_rx_q),
+ timeout);
+ if (timeout < 0)
+ return -EFAULT;
+ }
+ if (timeout == 0)
+ return -ENOMSG;
+ mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
+ }
+ mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
+
+ return ret;
+}
+
+/**
* msm_ipc_router_recv_from() - Recieve messages destined to a local port.
* @port_ptr: Pointer to the local port
* @data : Pointer to the socket buffer head
@@ -2273,7 +2316,7 @@
* > 0 timeout indicates the wait time.
* 0 indicates that we do not wait.
* @return: = Number of bytes read(On successful read operation).
- * = 0 (If there are no pending messages and timeout is 0).
+ * = -ENOMSG (If there are no pending messages and timeout is 0).
* = -EINVAL (If either of the arguments, port_ptr or data is invalid)
* = -EFAULT (If there are no pending messages when timeout is > 0
* and the wait_event_interruptible_timeout has returned value > 0)
@@ -2302,28 +2345,10 @@
}
*data = NULL;
- mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
- while (list_empty(&port_ptr->port_rx_q)) {
- mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
- if (timeout < 0) {
- ret = wait_event_interruptible(
- port_ptr->port_rx_wait_q,
- !list_empty(&port_ptr->port_rx_q));
- if (ret)
- return ret;
- } else if (timeout > 0) {
- timeout = wait_event_interruptible_timeout(
- port_ptr->port_rx_wait_q,
- !list_empty(&port_ptr->port_rx_q),
- timeout);
- if (timeout < 0)
- return -EFAULT;
- }
- if (timeout == 0)
- return 0;
- mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
- }
- mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
+
+ ret = msm_ipc_router_rx_data_wait(port_ptr, timeout);
+ if (ret)
+ return ret;
ret = msm_ipc_router_read(port_ptr, data, 0);
if (ret <= 0 || !(*data))
@@ -2357,12 +2382,10 @@
ret = msm_ipc_router_recv_from(port_ptr, &in_skb_head, src, 0);
- if (ret == 0)
- return -ENOMSG;
-
if (ret < 0) {
- pr_err("%s: msm_ipc_router_recv_from failed - ret: %d\n",
- __func__, ret);
+ if (ret != -ENOMSG)
+ pr_err("%s: msm_ipc_router_recv_from failed - ret: %d\n",
+ __func__, ret);
return ret;
}
diff --git a/arch/arm/mach-msm/ipc_router.h b/arch/arm/mach-msm/ipc_router.h
index 55aeade..7bfc52b 100644
--- a/arch/arm/mach-msm/ipc_router.h
+++ b/arch/arm/mach-msm/ipc_router.h
@@ -160,6 +160,8 @@
void msm_ipc_sync_default_sec_rule(void *rule);
+int msm_ipc_router_rx_data_wait(struct msm_ipc_port *port_ptr, long timeout);
+
#if defined CONFIG_MSM_IPC_ROUTER_SMD_XPRT
extern void *msm_ipc_load_default_node(void);
diff --git a/arch/arm/mach-msm/ipc_socket.c b/arch/arm/mach-msm/ipc_socket.c
index 515dc92..ea27c71 100644
--- a/arch/arm/mach-msm/ipc_socket.c
+++ b/arch/arm/mach-msm/ipc_socket.c
@@ -411,33 +411,14 @@
lock_sock(sk);
timeout = sk->sk_rcvtimeo;
- mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
- while (list_empty(&port_ptr->port_rx_q)) {
- mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
- release_sock(sk);
- if (timeout < 0) {
- ret = wait_event_interruptible(
- port_ptr->port_rx_wait_q,
- !list_empty(&port_ptr->port_rx_q));
- if (ret)
- return ret;
- } else if (timeout > 0) {
- timeout = wait_event_interruptible_timeout(
- port_ptr->port_rx_wait_q,
- !list_empty(&port_ptr->port_rx_q),
- timeout);
- if (timeout < 0)
- return -EFAULT;
- }
- if (timeout == 0) {
+ ret = msm_ipc_router_rx_data_wait(port_ptr, timeout);
+ if (ret) {
+ release_sock(sk);
+ if (ret == -ENOMSG)
m->msg_namelen = 0;
- return 0;
- }
- lock_sock(sk);
- mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
+ return ret;
}
- mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
ret = msm_ipc_router_read(port_ptr, &msg, buf_len);
if (ret <= 0 || !msg) {
diff --git a/arch/arm/mach-msm/jtag-fuse.c b/arch/arm/mach-msm/jtag-fuse.c
new file mode 100644
index 0000000..ccefc41
--- /dev/null
+++ b/arch/arm/mach-msm/jtag-fuse.c
@@ -0,0 +1,140 @@
+/* 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/module.h>
+#include <linux/export.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <mach/jtag.h>
+
+#define fuse_writel(drvdata, val, off) __raw_writel((val), drvdata->base + off)
+#define fuse_readl(drvdata, off) __raw_readl(drvdata->base + off)
+
+#define OEM_CONFIG0 (0x000)
+#define OEM_CONFIG1 (0x004)
+
+#define ALL_DEBUG_DISABLE BIT(21)
+#define APPS_DBGEN_DISABLE BIT(0)
+#define APPS_NIDEN_DISABLE BIT(1)
+#define APPS_SPIDEN_DISABLE BIT(2)
+#define APPS_SPNIDEN_DISABLE BIT(3)
+#define DAP_DEVICEEN_DISABLE BIT(8)
+
+struct fuse_drvdata {
+ void __iomem *base;
+ struct device *dev;
+};
+
+static struct fuse_drvdata *fusedrvdata;
+
+bool msm_jtag_fuse_apps_access_disabled(void)
+{
+ struct fuse_drvdata *drvdata = fusedrvdata;
+ uint32_t config0, config1;
+ bool ret;
+
+ if (!drvdata)
+ return false;
+
+ config0 = fuse_readl(drvdata, OEM_CONFIG0);
+ config1 = fuse_readl(drvdata, OEM_CONFIG1);
+
+ dev_dbg(drvdata->dev, "apps config0: %lx\n", (unsigned long)config0);
+ dev_dbg(drvdata->dev, "apps config1: %lx\n", (unsigned long)config1);
+
+ if (config0 & ALL_DEBUG_DISABLE)
+ ret = true;
+ else if (config1 & APPS_DBGEN_DISABLE)
+ ret = true;
+ else if (config1 & APPS_NIDEN_DISABLE)
+ ret = true;
+ else if (config1 & APPS_SPIDEN_DISABLE)
+ ret = true;
+ else if (config1 & APPS_SPNIDEN_DISABLE)
+ ret = true;
+ else if (config1 & DAP_DEVICEEN_DISABLE)
+ ret = true;
+ else
+ ret = false;
+
+ if (ret)
+ dev_dbg(drvdata->dev, "apps fuse disabled\n");
+
+ return ret;
+}
+EXPORT_SYMBOL(msm_jtag_fuse_apps_access_disabled);
+
+static int __devinit jtag_fuse_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct fuse_drvdata *drvdata;
+ struct resource *res;
+
+ drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+ /* Store the driver data pointer for use in exported functions */
+ fusedrvdata = drvdata;
+ drvdata->dev = &pdev->dev;
+ platform_set_drvdata(pdev, drvdata);
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fuse-base");
+ if (!res)
+ return -ENODEV;
+
+ drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
+ if (!drvdata->base)
+ return -ENOMEM;
+
+ dev_info(dev, "JTag Fuse initialized\n");
+ return 0;
+}
+
+static int __devexit jtag_fuse_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static struct of_device_id jtag_fuse_match[] = {
+ {.compatible = "qcom,jtag-fuse"},
+ {}
+};
+
+static struct platform_driver jtag_fuse_driver = {
+ .probe = jtag_fuse_probe,
+ .remove = __devexit_p(jtag_fuse_remove),
+ .driver = {
+ .name = "msm-jtag-fuse",
+ .owner = THIS_MODULE,
+ .of_match_table = jtag_fuse_match,
+ },
+};
+
+static int __init jtag_fuse_init(void)
+{
+ return platform_driver_register(&jtag_fuse_driver);
+}
+arch_initcall(jtag_fuse_init);
+
+static void __exit jtag_fuse_exit(void)
+{
+ platform_driver_unregister(&jtag_fuse_driver);
+}
+module_exit(jtag_fuse_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("JTag Fuse driver");
diff --git a/arch/arm/mach-msm/jtag-mm.c b/arch/arm/mach-msm/jtag-mm.c
index 8a67614..55c5a7e 100644
--- a/arch/arm/mach-msm/jtag-mm.c
+++ b/arch/arm/mach-msm/jtag-mm.c
@@ -787,6 +787,9 @@
static uint32_t count;
struct device *dev = &pdev->dev;
+ if (msm_jtag_fuse_apps_access_disabled())
+ return -EPERM;
+
cpu = count;
count++;
diff --git a/arch/arm/mach-msm/jtag.c b/arch/arm/mach-msm/jtag.c
index 24e1c41..840449c 100644
--- a/arch/arm/mach-msm/jtag.c
+++ b/arch/arm/mach-msm/jtag.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
@@ -1105,6 +1105,9 @@
int ret;
uint32_t dbgdidr;
+ if (msm_jtag_fuse_apps_access_disabled())
+ return -EPERM;
+
/* This will run on core0 so use it to populate parameters */
/* Populate dbg_ctx data */
@@ -1146,6 +1149,9 @@
uint32_t etmidr;
uint32_t etmccr;
+ if (msm_jtag_fuse_apps_access_disabled())
+ return -EPERM;
+
/* Vote for ETM power/clock enable */
etm_clk_enable();
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index b30cba4..9c5f197 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -781,13 +781,13 @@
return rc;
}
-#define SLEW_RATE 2994
+#define SLEW_RATE 2395
static int krait_voltage_increase(struct krait_power_vreg *from,
int vmax)
{
struct pmic_gang_vreg *pvreg = from->pvreg;
int rc = 0;
- int settling_us;
+ int settling_us = DIV_ROUND_UP(vmax - pvreg->pmic_vmax_uV, SLEW_RATE);
/*
* since krait voltage is increasing set the gang voltage
@@ -800,12 +800,10 @@
return rc;
}
-
/* complete the above writes before the delay */
mb();
/* delay until the voltage is settled when it is raised */
- settling_us = DIV_ROUND_UP(vmax - pvreg->pmic_vmax_uV, SLEW_RATE);
udelay(settling_us);
rc = configure_ldo_or_hs_all(from, vmax);
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
index aa33f2c..4d7c3d4 100644
--- a/arch/arm/mach-msm/lpm_levels.c
+++ b/arch/arm/mach-msm/lpm_levels.c
@@ -16,19 +16,60 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/cpu.h>
#include <linux/of.h>
#include <mach/mpm.h>
-#include "lpm_resources.h"
#include "pm.h"
#include "rpm-notifier.h"
-
+#include "spm.h"
+#include "idle.h"
enum {
MSM_LPM_LVL_DBG_SUSPEND_LIMITS = BIT(0),
MSM_LPM_LVL_DBG_IDLE_LIMITS = BIT(1),
};
-#define MAX_STR_LEN 30
+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;
+ uint32_t latency_us;
+ uint32_t steady_state_power;
+ uint32_t energy_overhead;
+ uint32_t time_overhead_us;
+};
+
+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,
+ unsigned long action, void *hcpu);
+
+static struct notifier_block __refdata msm_lpm_cpu_nblk = {
+ .notifier_call = msm_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(
+ struct kobject *kobj, struct kobj_attribute *attr, char *buf);
+static ssize_t msm_lpm_levels_attr_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count);
static int msm_lpm_lvl_dbg_msk;
@@ -39,9 +80,54 @@
static struct msm_rpmrs_level *msm_lpm_levels;
static int msm_lpm_level_count;
-static DEFINE_PER_CPU(uint32_t , msm_lpm_sleep_time);
-static DEFINE_PER_CPU(int , lpm_permitted_level);
-static DEFINE_PER_CPU(struct atomic_notifier_head, lpm_notify_head);
+static struct kobj_attribute lpm_l2_kattr = __ATTR(l2, S_IRUGO|S_IWUSR,\
+ msm_lpm_levels_attr_show, msm_lpm_levels_attr_store);
+
+static struct attribute *lpm_levels_attr[] = {
+ &lpm_l2_kattr.attr,
+ NULL,
+};
+
+static struct attribute_group lpm_levels_attr_grp = {
+ .attrs = lpm_levels_attr,
+};
+
+/* SYSFS */
+static ssize_t msm_lpm_levels_attr_show(
+ struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+ struct kernel_param kp;
+ int rc;
+
+ kp.arg = &sysfs_dbg_l2_mode;
+
+ rc = param_get_uint(buf, &kp);
+
+ if (rc > 0) {
+ strlcat(buf, "\n", PAGE_SIZE);
+ rc++;
+ }
+
+ return rc;
+}
+
+static ssize_t msm_lpm_levels_attr_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ struct kernel_param kp;
+ unsigned int temp;
+ int rc;
+
+ kp.arg = &temp;
+ rc = param_set_uint(buf, &kp);
+ if (rc)
+ return rc;
+
+ sysfs_dbg_l2_mode = temp;
+ msm_lpm_level_update();
+
+ return count;
+}
static int msm_pm_get_sleep_mode_value(struct device_node *node,
const char *key, uint32_t *sleep_mode_val)
@@ -74,8 +160,7 @@
if (!ret) {
ret = -EINVAL;
for (i = 0; i < ARRAY_SIZE(pm_sm_lookup); i++) {
- if (!strncmp(mode_name, pm_sm_lookup[i].mode_name,
- MAX_STR_LEN)) {
+ if (!strcmp(mode_name, pm_sm_lookup[i].mode_name)) {
*sleep_mode_val = pm_sm_lookup[i].modes;
ret = 0;
break;
@@ -85,16 +170,61 @@
return ret;
}
+static int msm_lpm_set_l2_mode(int sleep_mode)
+{
+ int lpm = sleep_mode;
+ int rc = 0;
+
+ if (no_l2_saw)
+ goto bail_set_l2_mode;
+
+ msm_pm_set_l2_flush_flag(MSM_SCM_L2_ON);
+
+ switch (sleep_mode) {
+ case MSM_SPM_L2_MODE_POWER_COLLAPSE:
+ msm_pm_set_l2_flush_flag(MSM_SCM_L2_OFF);
+ break;
+ case MSM_SPM_L2_MODE_GDHS:
+ msm_pm_set_l2_flush_flag(MSM_SCM_L2_GDHS);
+ break;
+ case MSM_SPM_L2_MODE_RETENTION:
+ case MSM_SPM_L2_MODE_DISABLED:
+ break;
+ default:
+ lpm = MSM_SPM_L2_MODE_DISABLED;
+ break;
+ }
+
+ rc = msm_spm_l2_set_low_power_mode(lpm, true);
+
+ if (rc) {
+ if (rc == -ENXIO)
+ WARN_ON_ONCE(1);
+ else
+ pr_err("%s: Failed to set L2 low power mode %d, ERR %d",
+ __func__, lpm, rc);
+ }
+
+bail_set_l2_mode:
+ return rc;
+}
+
static void msm_lpm_level_update(void)
{
- unsigned int lpm_level;
+ int lpm_level;
struct msm_rpmrs_level *level = NULL;
+ uint32_t max_l2_mode;
+ static DEFINE_MUTEX(lpm_lock);
+
+ mutex_lock(&lpm_lock);
+
+ 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 =
- !msm_lpm_level_beyond_limit(&level->rs_limits);
+ level->available = !(level->l2_cache > max_l2_mode);
}
+ mutex_unlock(&lpm_lock);
}
int msm_lpm_enter_sleep(uint32_t sclk_count, void *limits,
@@ -102,13 +232,7 @@
{
int ret = 0;
int debug_mask;
- struct msm_rpmrs_limits *l = (struct msm_rpmrs_limits *)limits;
- struct msm_lpm_sleep_data sleep_data;
-
- sleep_data.limits = limits;
- sleep_data.kernel_sleep = __get_cpu_var(msm_lpm_sleep_time);
- atomic_notifier_call_chain(&__get_cpu_var(lpm_notify_head),
- MSM_LPM_STATE_ENTER, &sleep_data);
+ uint32_t l2 = *(uint32_t *)limits;
if (from_idle)
debug_mask = msm_lpm_lvl_dbg_msk &
@@ -118,19 +242,20 @@
MSM_LPM_LVL_DBG_SUSPEND_LIMITS;
if (debug_mask)
- pr_info("%s(): pxo:%d l2:%d mem:0x%x(0x%x) dig:0x%x(0x%x)\n",
- __func__, l->pxo, l->l2_cache,
- l->vdd_mem_lower_bound,
- l->vdd_mem_upper_bound,
- l->vdd_dig_lower_bound,
- l->vdd_dig_upper_bound);
+ pr_info("%s(): l2:%d", __func__, l2);
- ret = msm_lpmrs_enter_sleep(sclk_count, l, from_idle, notify_rpm);
+ ret = msm_lpm_set_l2_mode(l2);
+
if (ret) {
- pr_warn("%s() LPM resources failed to enter sleep\n",
- __func__);
- goto bail;
+ if (ret == -ENXIO)
+ ret = 0;
+ else {
+ pr_warn("%s(): Failed to set L2 SPM Mode %d",
+ __func__, l2);
+ goto bail;
+ }
}
+
if (notify_rpm) {
ret = msm_rpm_enter_sleep(debug_mask);
if (ret) {
@@ -138,6 +263,8 @@
__func__, ret);
goto bail;
}
+
+ msm_mpm_enter_sleep(sclk_count, from_idle);
}
bail:
return ret;
@@ -147,12 +274,12 @@
bool notify_rpm, bool collapsed)
{
- msm_lpmrs_exit_sleep((struct msm_rpmrs_limits *)limits,
- from_idle, notify_rpm, collapsed);
- if (notify_rpm)
+ msm_lpm_set_l2_mode(default_l2_mode);
+
+ if (notify_rpm) {
+ msm_mpm_exit_sleep(from_idle);
msm_rpm_exit_sleep();
- atomic_notifier_call_chain(&__get_cpu_var(lpm_notify_head),
- MSM_LPM_STATE_EXIT, NULL);
+ }
}
void msm_lpm_show_resources(void)
@@ -161,48 +288,6 @@
return;
}
-uint32_t msm_pm_get_pxo(struct msm_rpmrs_limits *limits)
-{
- return limits->pxo;
-}
-
-uint32_t msm_pm_get_l2_cache(struct msm_rpmrs_limits *limits)
-{
- return limits->l2_cache;
-}
-
-uint32_t msm_pm_get_vdd_mem(struct msm_rpmrs_limits *limits)
-{
- return limits->vdd_mem_upper_bound;
-}
-
-uint32_t msm_pm_get_vdd_dig(struct msm_rpmrs_limits *limits)
-{
- return limits->vdd_dig_upper_bound;
-}
-
-static bool lpm_level_permitted(int cur_level_count)
-{
- if (__get_cpu_var(lpm_permitted_level) == msm_lpm_level_count + 1)
- return true;
- return (__get_cpu_var(lpm_permitted_level) == cur_level_count);
-}
-
-int msm_lpm_register_notifier(int cpu, int level_iter,
- struct notifier_block *nb, bool is_latency_measure)
-{
- per_cpu(lpm_permitted_level, cpu) = level_iter;
- return atomic_notifier_chain_register(&per_cpu(lpm_notify_head,
- cpu), nb);
-}
-
-int msm_lpm_unregister_notifier(int cpu, struct notifier_block *nb)
-{
- per_cpu(lpm_permitted_level, cpu) = msm_lpm_level_count + 1;
- return atomic_notifier_chain_unregister(&per_cpu(lpm_notify_head, cpu),
- nb);
-}
-
s32 msm_cpuidle_get_deep_idle_latency(void)
{
int i;
@@ -225,17 +310,26 @@
}
return best->latency_us - 1;
}
-static bool msm_lpm_irqs_detectable(struct msm_rpmrs_limits *limits,
- bool irqs_detectable, bool gpio_detectable)
+
+static int msm_lpm_cpu_callback(struct notifier_block *cpu_nb,
+ unsigned long action, void *hcpu)
{
- if (!limits->irqs_detectable)
- return irqs_detectable;
-
- if (!limits->gpio_detectable)
- return gpio_detectable;
-
- return true;
-
+ switch (action) {
+ case CPU_UP_PREPARE:
+ case CPU_UP_PREPARE_FROZEN:
+ allowed_l2_mode = default_l2_mode;
+ msm_lpm_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();
+ break;
+ }
+ return NOTIFY_OK;
}
static void *msm_lpm_lowest_limits(bool from_idle,
@@ -244,24 +338,15 @@
{
unsigned int cpu = smp_processor_id();
struct msm_rpmrs_level *best_level = NULL;
+ uint32_t best_level_pwr = 0;
uint32_t pwr;
int i;
- int best_level_iter = msm_lpm_level_count + 1;
- bool irqs_detect = false;
- bool gpio_detect = false;
bool modify_event_timer;
uint32_t next_wakeup_us = time_param->sleep_us;
if (!msm_lpm_levels)
return NULL;
- msm_lpm_level_update();
-
- if (sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) {
- irqs_detect = msm_mpm_irqs_detectable(from_idle);
- gpio_detect = msm_mpm_gpio_irqs_detectable(from_idle);
- }
-
for (i = 0; i < msm_lpm_level_count; i++) {
struct msm_rpmrs_level *level = &msm_lpm_levels[i];
@@ -293,11 +378,6 @@
if (next_wakeup_us <= level->time_overhead_us)
continue;
- if ((sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) &&
- !msm_lpm_irqs_detectable(&level->rs_limits,
- irqs_detect, gpio_detect))
- 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())
@@ -318,12 +398,10 @@
pwr += level->energy_overhead / next_wakeup_us;
}
- if (!best_level || best_level->rs_limits.power[cpu] >= pwr) {
+ if (!best_level || (best_level_pwr >= pwr)) {
- level->rs_limits.latency_us[cpu] = level->latency_us;
- level->rs_limits.power[cpu] = pwr;
best_level = level;
- best_level_iter = i;
+ best_level_pwr = pwr;
if (power)
*power = pwr;
if (modify_event_timer &&
@@ -336,32 +414,78 @@
time_param->modified_time_us = 0;
}
}
- if (best_level && !lpm_level_permitted(best_level_iter))
- best_level = NULL;
- else
- per_cpu(msm_lpm_sleep_time, cpu) =
- time_param->modified_time_us ?
- time_param->modified_time_us : time_param->sleep_us;
- return best_level ? &best_level->rs_limits : NULL;
+ return best_level ? &best_level->l2_cache : NULL;
}
-static struct lpm_test_platform_data lpm_test_pdata;
-
-static struct platform_device msm_lpm_test_device = {
- .name = "lpm_test",
- .id = -1,
- .dev = {
- .platform_data = &lpm_test_pdata,
- },
-};
-
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)
+{
+ int i;
+ struct lpm_lookup_table l2_mode_lookup[] = {
+ {MSM_SPM_L2_MODE_POWER_COLLAPSE, "l2_cache_pc"},
+ {MSM_SPM_L2_MODE_GDHS, "l2_cache_gdhs"},
+ {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;
+}
+
+static int __devinit msm_lpm_levels_sysfs_add(void)
+{
+ struct kobject *module_kobj = NULL;
+ struct kobject *low_power_kobj = NULL;
+ int rc = 0;
+
+ 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 resource_sysfs_add_exit;
+ }
+
+ low_power_kobj = kobject_create_and_add(
+ "enable_low_power", module_kobj);
+ if (!low_power_kobj) {
+ pr_err("%s: cannot create kobject\n", __func__);
+ rc = -ENOMEM;
+ goto resource_sysfs_add_exit;
+ }
+
+ rc = sysfs_create_group(low_power_kobj, &lpm_levels_attr_grp);
+resource_sysfs_add_exit:
+ if (rc) {
+ if (low_power_kobj) {
+ sysfs_remove_group(low_power_kobj,
+ &lpm_levels_attr_grp);
+ kobject_del(low_power_kobj);
+ }
+ }
+
+ return rc;
+}
+
static int __devinit msm_lpm_levels_probe(struct platform_device *pdev)
{
struct msm_rpmrs_level *levels = NULL;
@@ -372,7 +496,6 @@
int ret = 0;
uint32_t num_levels = 0;
int idx = 0;
- unsigned int m_cpu = 0;
for_each_child_of_node(pdev->dev.of_node, node)
num_levels++;
@@ -392,49 +515,11 @@
goto fail;
level->sleep_mode = val;
- key = "qcom,xo";
- ret = msm_lpm_get_xo_value(node, key, &val);
- if (ret)
- goto fail;
- level->rs_limits.pxo = val;
-
key = "qcom,l2";
ret = msm_lpm_get_l2_cache_value(node, key, &val);
if (ret)
goto fail;
- level->rs_limits.l2_cache = val;
-
- key = "qcom,vdd-dig-upper-bound";
- ret = of_property_read_u32(node, key, &val);
- if (ret)
- goto fail;
- level->rs_limits.vdd_dig_upper_bound = val;
-
- key = "qcom,vdd-dig-lower-bound";
- ret = of_property_read_u32(node, key, &val);
- if (ret)
- goto fail;
- level->rs_limits.vdd_dig_lower_bound = val;
-
- key = "qcom,vdd-mem-upper-bound";
- ret = of_property_read_u32(node, key, &val);
- if (ret)
- goto fail;
- level->rs_limits.vdd_mem_upper_bound = val;
-
- key = "qcom,vdd-mem-lower-bound";
- ret = of_property_read_u32(node, key, &val);
- if (ret)
- goto fail;
- level->rs_limits.vdd_mem_lower_bound = val;
-
- key = "qcom,gpio-detectable";
- level->rs_limits.gpio_detectable =
- of_property_read_bool(node, key);
-
- key = "qcom,irqs-detectable";
- level->rs_limits.irqs_detectable =
- of_property_read_bool(node, key);
+ level->l2_cache = val;
key = "qcom,latency-us";
ret = of_property_read_u32(node, key, &val);
@@ -463,22 +548,33 @@
level->available = true;
}
+ node = pdev->dev.of_node;
+ key = "qcom,no-l2-saw";
+ no_l2_saw = of_property_read_bool(node, key);
+
msm_lpm_levels = levels;
msm_lpm_level_count = idx;
- lpm_test_pdata.msm_lpm_test_levels = msm_lpm_levels;
- lpm_test_pdata.msm_lpm_test_level_count = msm_lpm_level_count;
- key = "qcom,use-qtimer";
- lpm_test_pdata.use_qtimer =
- of_property_read_bool(pdev->dev.of_node, key);
+ if (num_online_cpus() == 1)
+ allowed_l2_mode = MSM_SPM_L2_MODE_POWER_COLLAPSE;
- for_each_possible_cpu(m_cpu)
- per_cpu(lpm_permitted_level, m_cpu) =
- msm_lpm_level_count + 1;
+ /* 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;
- platform_device_register(&msm_lpm_test_device);
+ if (msm_lpm_levels_sysfs_add())
+ goto fail;
+ register_hotcpu_notifier(&msm_lpm_cpu_nblk);
+ msm_pm_set_l2_flush_flag(0);
+ } else {
+ msm_pm_set_l2_flush_flag(1);
+ default_l2_mode = MSM_SPM_L2_MODE_POWER_COLLAPSE;
+ }
+
+ msm_lpm_level_update();
msm_pm_set_sleep_ops(&msm_lpm_ops);
-
return 0;
fail:
pr_err("%s: Error in name %s key %s\n", __func__, node->full_name, key);
diff --git a/arch/arm/mach-msm/lpm_resources.c b/arch/arm/mach-msm/lpm_resources.c
deleted file mode 100644
index 1d9c539..0000000
--- a/arch/arm/mach-msm/lpm_resources.c
+++ /dev/null
@@ -1,1009 +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/kernel.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-#include <linux/of.h>
-#include <linux/cpu.h>
-#include <linux/notifier.h>
-#include <linux/hrtimer.h>
-#include <linux/tick.h>
-#include <mach/mpm.h>
-#include <mach/rpm-smd.h>
-#include <mach/trace_msm_low_power.h>
-#include "spm.h"
-#include "lpm_resources.h"
-#include "rpm-notifier.h"
-#include "idle.h"
-
-
-/*Debug Definitions*/
-enum {
- MSM_LPMRS_DEBUG_RPM = BIT(0),
- MSM_LPMRS_DEBUG_PXO = BIT(1),
- MSM_LPMRS_DEBUG_VDD_DIG = BIT(2),
- MSM_LPMRS_DEBUG_VDD_MEM = BIT(3),
- MSM_LPMRS_DEBUG_L2 = BIT(4),
- MSM_LPMRS_DEBUG_LVLS = BIT(5),
-};
-
-static int msm_lpm_debug_mask;
-module_param_named(
- debug_mask, msm_lpm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
-);
-
-static bool msm_lpm_get_rpm_notif = true;
-
-/*Macros*/
-#define MAX_RS_NAME (16)
-#define MAX_RS_SIZE (4)
-#define IS_RPM_CTL(rs) \
- (!strncmp(rs->name, "rpm_ctl", MAX_RS_NAME))
-#define MAX_STR_LEN 30
-
-static bool msm_lpm_beyond_limits_vdd_dig(struct msm_rpmrs_limits *limits);
-static void msm_lpm_aggregate_vdd_dig(struct msm_rpmrs_limits *limits);
-static void msm_lpm_flush_vdd_dig(int notify_rpm);
-static void msm_lpm_notify_vdd_dig(struct msm_rpm_notifier_data
- *rpm_notifier_cb);
-static int msm_lpm_init_value_vdd_dig(struct device_node *node,
- char *key, uint32_t *default_value);
-
-static bool msm_lpm_beyond_limits_vdd_mem(struct msm_rpmrs_limits *limits);
-static void msm_lpm_aggregate_vdd_mem(struct msm_rpmrs_limits *limits);
-static void msm_lpm_flush_vdd_mem(int notify_rpm);
-static void msm_lpm_notify_vdd_mem(struct msm_rpm_notifier_data
- *rpm_notifier_cb);
-static int msm_lpm_init_value_vdd_mem(struct device_node *node,
- char *key, uint32_t *default_value);
-
-
-static bool msm_lpm_beyond_limits_pxo(struct msm_rpmrs_limits *limits);
-static void msm_lpm_aggregate_pxo(struct msm_rpmrs_limits *limits);
-static void msm_lpm_flush_pxo(int notify_rpm);
-static void msm_lpm_notify_pxo(struct msm_rpm_notifier_data
- *rpm_notifier_cb);
-static int msm_lpm_init_value_pxo(struct device_node *node,
- char *key, uint32_t *default_value);
-
-
-static bool msm_lpm_beyond_limits_l2(struct msm_rpmrs_limits *limits);
-static void msm_lpm_flush_l2(int notify_rpm);
-static void msm_lpm_aggregate_l2(struct msm_rpmrs_limits *limits);
-static int msm_lpm_init_value_l2(struct device_node *node,
- char *key, uint32_t *default_value);
-
-static void msm_lpm_flush_rpm_ctl(int notify_rpm);
-
-static int msm_lpm_rpm_callback(struct notifier_block *rpm_nb,
- unsigned long action, void *rpm_notif);
-
-static int msm_lpm_cpu_callback(struct notifier_block *cpu_nb,
- unsigned long action, void *hcpu);
-
-static ssize_t msm_lpm_resource_attr_show(
- struct kobject *kobj, struct kobj_attribute *attr, char *buf);
-static ssize_t msm_lpm_resource_attr_store(struct kobject *kobj,
- struct kobj_attribute *attr, const char *buf, size_t count);
-
-
-#define RPMRS_ATTR(_name) \
- __ATTR(_name, S_IRUGO|S_IWUSR, \
- msm_lpm_resource_attr_show, msm_lpm_resource_attr_store)
-
-/*Data structures*/
-struct msm_lpm_rs_data {
- uint32_t type;
- uint32_t id;
- uint32_t key;
- uint32_t value;
- uint32_t default_value;
- struct msm_rpm_request *handle;
-};
-
-enum {
- MSM_LPM_RPM_RS_TYPE = 0,
- MSM_LPM_LOCAL_RS_TYPE = 1,
-};
-
-enum {
- MSM_SCM_L2_ON = 0,
- MSM_SCM_L2_OFF = 1,
- MSM_SCM_L2_GDHS = 3,
-};
-
-struct msm_lpm_resource {
- struct msm_lpm_rs_data rs_data;
- uint32_t sleep_value;
- char name[MAX_RS_NAME];
-
- uint32_t enable_low_power;
- bool valid;
-
- bool (*beyond_limits)(struct msm_rpmrs_limits *limits);
- void (*aggregate)(struct msm_rpmrs_limits *limits);
- void (*flush)(int notify_rpm);
- void (*notify)(struct msm_rpm_notifier_data *rpm_notifier_cb);
- struct kobj_attribute ko_attr;
- int (*init_value)(struct device_node *node,
- char *key, uint32_t *default_value);
-};
-
-struct lpm_lookup_table {
- uint32_t modes;
- const char *mode_name;
-};
-
-static struct msm_lpm_resource msm_lpm_l2 = {
- .name = "l2",
- .beyond_limits = msm_lpm_beyond_limits_l2,
- .aggregate = msm_lpm_aggregate_l2,
- .flush = msm_lpm_flush_l2,
- .notify = NULL,
- .valid = false,
- .ko_attr = RPMRS_ATTR(l2),
- .init_value = msm_lpm_init_value_l2,
-};
-
-static struct msm_lpm_resource msm_lpm_vdd_dig = {
- .name = "vdd-dig",
- .beyond_limits = msm_lpm_beyond_limits_vdd_dig,
- .aggregate = msm_lpm_aggregate_vdd_dig,
- .flush = msm_lpm_flush_vdd_dig,
- .notify = msm_lpm_notify_vdd_dig,
- .valid = false,
- .ko_attr = RPMRS_ATTR(vdd_dig),
- .init_value = msm_lpm_init_value_vdd_dig,
-};
-
-static struct msm_lpm_resource msm_lpm_vdd_mem = {
- .name = "vdd-mem",
- .beyond_limits = msm_lpm_beyond_limits_vdd_mem,
- .aggregate = msm_lpm_aggregate_vdd_mem,
- .flush = msm_lpm_flush_vdd_mem,
- .notify = msm_lpm_notify_vdd_mem,
- .valid = false,
- .ko_attr = RPMRS_ATTR(vdd_mem),
- .init_value = msm_lpm_init_value_vdd_mem,
-};
-
-static struct msm_lpm_resource msm_lpm_pxo = {
- .name = "pxo",
- .beyond_limits = msm_lpm_beyond_limits_pxo,
- .aggregate = msm_lpm_aggregate_pxo,
- .flush = msm_lpm_flush_pxo,
- .notify = msm_lpm_notify_pxo,
- .valid = false,
- .ko_attr = RPMRS_ATTR(pxo),
- .init_value = msm_lpm_init_value_pxo,
-};
-
-static struct msm_lpm_resource *msm_lpm_resources[] = {
- &msm_lpm_vdd_dig,
- &msm_lpm_vdd_mem,
- &msm_lpm_pxo,
- &msm_lpm_l2,
-};
-
-static struct msm_lpm_resource msm_lpm_rpm_ctl = {
- .name = "rpm_ctl",
- .beyond_limits = NULL,
- .aggregate = NULL,
- .flush = msm_lpm_flush_rpm_ctl,
- .valid = true,
- .ko_attr = RPMRS_ATTR(rpm_ctl),
-};
-
-static struct notifier_block msm_lpm_rpm_nblk = {
- .notifier_call = msm_lpm_rpm_callback,
-};
-
-static struct notifier_block __refdata msm_lpm_cpu_nblk = {
- .notifier_call = msm_lpm_cpu_callback,
-};
-
-static DEFINE_SPINLOCK(msm_lpm_sysfs_lock);
-
-/* Attribute Definitions */
-static struct attribute *msm_lpm_attributes[] = {
- &msm_lpm_vdd_dig.ko_attr.attr,
- &msm_lpm_vdd_mem.ko_attr.attr,
- &msm_lpm_pxo.ko_attr.attr,
- &msm_lpm_l2.ko_attr.attr,
- NULL,
-};
-
-static struct attribute_group msm_lpm_attribute_group = {
- .attrs = msm_lpm_attributes,
-};
-
-static struct attribute *msm_lpm_rpm_ctl_attribute[] = {
- &msm_lpm_rpm_ctl.ko_attr.attr,
- NULL,
-};
-
-static struct attribute_group msm_lpm_rpm_ctl_attr_group = {
- .attrs = msm_lpm_rpm_ctl_attribute,
-};
-
-#define GET_RS_FROM_ATTR(attr) \
- (container_of(attr, struct msm_lpm_resource, ko_attr))
-
-/* RPM */
-static struct msm_rpm_request *msm_lpm_create_rpm_request
- (uint32_t rsc_type, uint32_t rsc_id)
-{
- struct msm_rpm_request *handle = NULL;
-
- handle = msm_rpm_create_request(MSM_RPM_CTX_SLEEP_SET,
- rsc_type,
- rsc_id, 1);
- return handle;
-}
-
-static int msm_lpm_send_sleep_data(struct msm_rpm_request *handle,
- uint32_t key, uint8_t *value)
-{
- int ret = 0;
- int msg_id;
-
- if (!handle)
- return ret;
-
- ret = msm_rpm_add_kvp_data_noirq(handle, key, value, MAX_RS_SIZE);
-
- if (ret < 0) {
- pr_err("%s: Error adding kvp data key %u, size %d\n",
- __func__, key, MAX_RS_SIZE);
- return ret;
- }
-
- msg_id = msm_rpm_send_request_noirq(handle);
- if (!msg_id) {
- pr_err("%s: Error sending RPM request key %u, handle 0x%x\n",
- __func__, key, (unsigned int)handle);
- ret = -EIO;
- return ret;
- }
-
- ret = msm_rpm_wait_for_ack_noirq(msg_id);
- if (ret < 0) {
- pr_err("%s: Couldn't get ACK from RPM for Msg %d Error %d",
- __func__, msg_id, ret);
- return ret;
- }
- if (msm_lpm_debug_mask & MSM_LPMRS_DEBUG_RPM)
- pr_info("Rs key %u, value %u, size %d\n", key,
- *(unsigned int *)value, MAX_RS_SIZE);
- return ret;
-}
-
-/* RPM Notifier */
-static int msm_lpm_rpm_callback(struct notifier_block *rpm_nb,
- unsigned long action,
- void *rpm_notif)
-{
- int i;
- struct msm_lpm_resource *rs = NULL;
- struct msm_rpm_notifier_data *rpm_notifier_cb =
- (struct msm_rpm_notifier_data *)rpm_notif;
-
- if (!msm_lpm_get_rpm_notif)
- return NOTIFY_DONE;
-
- if (!(rpm_nb && rpm_notif))
- return NOTIFY_BAD;
-
- for (i = 0; i < ARRAY_SIZE(msm_lpm_resources); i++) {
- rs = msm_lpm_resources[i];
- if (rs && rs->valid && rs->notify)
- rs->notify(rpm_notifier_cb);
- }
-
- return NOTIFY_OK;
-}
-
-/* SYSFS */
-static ssize_t msm_lpm_resource_attr_show(
- struct kobject *kobj, struct kobj_attribute *attr, char *buf)
-{
- struct kernel_param kp;
- unsigned long flags;
- unsigned int temp;
- int rc;
-
- spin_lock_irqsave(&msm_lpm_sysfs_lock, flags);
- temp = GET_RS_FROM_ATTR(attr)->enable_low_power;
- spin_unlock_irqrestore(&msm_lpm_sysfs_lock, flags);
-
- kp.arg = &temp;
- rc = param_get_uint(buf, &kp);
-
- if (rc > 0) {
- strlcat(buf, "\n", PAGE_SIZE);
- rc++;
- }
-
- return rc;
-}
-
-static ssize_t msm_lpm_resource_attr_store(struct kobject *kobj,
- struct kobj_attribute *attr, const char *buf, size_t count)
-{
- struct kernel_param kp;
- unsigned long flags;
- unsigned int temp;
- int rc;
-
- kp.arg = &temp;
- rc = param_set_uint(buf, &kp);
- if (rc)
- return rc;
-
- spin_lock_irqsave(&msm_lpm_sysfs_lock, flags);
- GET_RS_FROM_ATTR(attr)->enable_low_power = temp;
-
- if (IS_RPM_CTL(GET_RS_FROM_ATTR(attr))) {
- struct msm_lpm_resource *rs = GET_RS_FROM_ATTR(attr);
- rs->flush(false);
- }
-
- spin_unlock_irqrestore(&msm_lpm_sysfs_lock, flags);
-
- return count;
-}
-
-/* lpm resource handling functions */
-/* Common */
-static void msm_lpm_notify_common(struct msm_rpm_notifier_data *cb,
- struct msm_lpm_resource *rs)
-{
- if ((cb->rsc_type == rs->rs_data.type) &&
- (cb->rsc_id == rs->rs_data.id) &&
- (cb->key == rs->rs_data.key)) {
-
- BUG_ON(cb->size > MAX_RS_SIZE);
-
- if (rs->valid) {
- if (cb->value) {
- memcpy(&rs->rs_data.value, cb->value, cb->size);
- msm_rpm_add_kvp_data_noirq(rs->rs_data.handle,
- cb->key, cb->value, cb->size);
- }
- else
- rs->rs_data.value = rs->rs_data.default_value;
-
- if (msm_lpm_debug_mask & MSM_LPMRS_DEBUG_RPM)
- pr_info("Notification received Rs %s value %u\n",
- rs->name, rs->rs_data.value);
- }
- }
-}
-
-/* L2 */
-static bool msm_lpm_beyond_limits_l2(struct msm_rpmrs_limits *limits)
-{
- uint32_t l2;
- bool ret = false;
- struct msm_lpm_resource *rs = &msm_lpm_l2;
-
- if (rs->valid) {
- uint32_t l2_buf = rs->rs_data.value;
-
- if (rs->enable_low_power == 1)
- l2 = MSM_LPM_L2_CACHE_GDHS;
- else if (rs->enable_low_power == 2)
- l2 = MSM_LPM_L2_CACHE_HSFS_OPEN;
- else
- l2 = MSM_LPM_L2_CACHE_ACTIVE ;
-
- if (l2_buf > l2)
- l2 = l2_buf;
- ret = (l2 > limits->l2_cache);
-
- if (msm_lpm_debug_mask & MSM_LPMRS_DEBUG_L2)
- pr_info("%s: l2 buf %u, l2 %u, limits %u\n",
- __func__, l2_buf, l2, limits->l2_cache);
- }
- return ret;
-}
-
-static void msm_lpm_aggregate_l2(struct msm_rpmrs_limits *limits)
-{
- struct msm_lpm_resource *rs = &msm_lpm_l2;
-
- if (rs->valid)
- rs->sleep_value = limits->l2_cache;
- trace_lpm_resources(rs->sleep_value, rs->name);
-}
-
-static void msm_lpm_set_l2_mode(int sleep_mode)
-{
- int lpm, rc;
-
- msm_pm_set_l2_flush_flag(MSM_SCM_L2_ON);
-
- switch (sleep_mode) {
- case MSM_LPM_L2_CACHE_HSFS_OPEN:
- lpm = MSM_SPM_L2_MODE_POWER_COLLAPSE;
- msm_pm_set_l2_flush_flag(MSM_SCM_L2_OFF);
- break;
- case MSM_LPM_L2_CACHE_GDHS:
- lpm = MSM_SPM_L2_MODE_GDHS;
- msm_pm_set_l2_flush_flag(MSM_SCM_L2_GDHS);
- break;
- case MSM_LPM_L2_CACHE_RETENTION:
- lpm = MSM_SPM_L2_MODE_RETENTION;
- break;
- default:
- case MSM_LPM_L2_CACHE_ACTIVE:
- lpm = MSM_SPM_L2_MODE_DISABLED;
- break;
- }
-
- rc = msm_spm_l2_set_low_power_mode(lpm, true);
-
- if (rc < 0)
- pr_err("%s: Failed to set L2 low power mode %d",
- __func__, lpm);
-
- if (msm_lpm_debug_mask & MSM_LPMRS_DEBUG_L2)
- pr_info("%s: Requesting low power mode %d\n",
- __func__, lpm);
-}
-
-static int msm_lpm_init_value_l2(struct device_node *node,
- char *key, uint32_t *default_value)
-{
- return msm_lpm_get_l2_cache_value(node, key, default_value);
-}
-
-static void msm_lpm_flush_l2(int notify_rpm)
-{
- struct msm_lpm_resource *rs = &msm_lpm_l2;
-
- msm_lpm_set_l2_mode(rs->sleep_value);
-}
-
-int msm_lpm_get_l2_cache_value(struct device_node *node,
- char *key, uint32_t *l2_val)
-{
- int i;
- struct lpm_lookup_table l2_mode_lookup[] = {
- {MSM_LPM_L2_CACHE_HSFS_OPEN, "l2_cache_pc"},
- {MSM_LPM_L2_CACHE_GDHS, "l2_cache_gdhs"},
- {MSM_LPM_L2_CACHE_RETENTION, "l2_cache_retention"},
- {MSM_LPM_L2_CACHE_ACTIVE, "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 (!strncmp(l2_str, l2_mode_lookup[i].mode_name,
- MAX_STR_LEN)) {
- *l2_val = l2_mode_lookup[i].modes;
- ret = 0;
- break;
- }
- }
- }
- return ret;
-}
-
-/* RPM CTL */
-static void msm_lpm_flush_rpm_ctl(int notify_rpm)
-{
- struct msm_lpm_resource *rs = &msm_lpm_rpm_ctl;
- msm_lpm_send_sleep_data(rs->rs_data.handle,
- rs->rs_data.key,
- (uint8_t *)&rs->sleep_value);
-}
-
-/*VDD Dig*/
-static bool msm_lpm_beyond_limits_vdd_dig(struct msm_rpmrs_limits *limits)
-{
- bool ret = true;
- struct msm_lpm_resource *rs = &msm_lpm_vdd_dig;
-
- if (rs->valid) {
- uint32_t vdd_buf = rs->rs_data.value;
- uint32_t vdd_dig = rs->enable_low_power ? rs->enable_low_power :
- rs->rs_data.default_value;
-
- if (vdd_buf > vdd_dig)
- vdd_dig = vdd_buf;
-
- ret = (vdd_dig > limits->vdd_dig_upper_bound);
-
- if (msm_lpm_debug_mask & MSM_LPMRS_DEBUG_VDD_DIG)
- pr_info("%s:buf %d vdd dig %d limits%d\n",
- __func__, vdd_buf, vdd_dig,
- limits->vdd_dig_upper_bound);
- }
- return ret;
-}
-
-static int msm_lpm_init_value_vdd_dig(struct device_node *node,
- char *key, uint32_t *default_value)
-{
- return of_property_read_u32(node, key, default_value);
-}
-
-static void msm_lpm_aggregate_vdd_dig(struct msm_rpmrs_limits *limits)
-{
- struct msm_lpm_resource *rs = &msm_lpm_vdd_dig;
-
- if (rs->valid) {
- uint32_t vdd_buf = rs->rs_data.value;
- if (limits->vdd_dig_lower_bound > vdd_buf)
- rs->sleep_value = limits->vdd_dig_lower_bound;
- else
- rs->sleep_value = vdd_buf;
- }
- trace_lpm_resources(rs->sleep_value, rs->name);
-}
-
-static void msm_lpm_flush_vdd_dig(int notify_rpm)
-{
- if (notify_rpm) {
- struct msm_lpm_resource *rs = &msm_lpm_vdd_dig;
- msm_lpm_send_sleep_data(rs->rs_data.handle,
- rs->rs_data.key,
- (uint8_t *)&rs->sleep_value);
- }
-}
-
-static void msm_lpm_notify_vdd_dig(struct msm_rpm_notifier_data
- *rpm_notifier_cb)
-{
- struct msm_lpm_resource *rs = &msm_lpm_vdd_dig;
- msm_lpm_notify_common(rpm_notifier_cb, rs);
-}
-
-/*VDD Mem*/
-static bool msm_lpm_beyond_limits_vdd_mem(struct msm_rpmrs_limits *limits)
-{
- bool ret = true;
- struct msm_lpm_resource *rs = &msm_lpm_vdd_mem;
-
- if (rs->valid) {
- uint32_t vdd_buf = rs->rs_data.value;
- uint32_t vdd_mem = rs->enable_low_power ? rs->enable_low_power :
- rs->rs_data.default_value;
-
- if (vdd_buf > vdd_mem)
- vdd_mem = vdd_buf;
-
- ret = (vdd_mem > limits->vdd_mem_upper_bound);
-
- if (msm_lpm_debug_mask & MSM_LPMRS_DEBUG_VDD_MEM)
- pr_info("%s:buf %d vdd mem %d limits%d\n",
- __func__, vdd_buf, vdd_mem,
- limits->vdd_mem_upper_bound);
- }
- return ret;
-}
-
-static void msm_lpm_aggregate_vdd_mem(struct msm_rpmrs_limits *limits)
-{
- struct msm_lpm_resource *rs = &msm_lpm_vdd_mem;
-
- if (rs->valid) {
- uint32_t vdd_buf = rs->rs_data.value;
- if (limits->vdd_mem_lower_bound > vdd_buf)
- rs->sleep_value = limits->vdd_mem_lower_bound;
- else
- rs->sleep_value = vdd_buf;
- }
- trace_lpm_resources(rs->sleep_value, rs->name);
-}
-
-static void msm_lpm_flush_vdd_mem(int notify_rpm)
-{
- if (notify_rpm) {
- struct msm_lpm_resource *rs = &msm_lpm_vdd_mem;
- msm_lpm_send_sleep_data(rs->rs_data.handle,
- rs->rs_data.key,
- (uint8_t *)&rs->sleep_value);
- }
-}
-
-static void msm_lpm_notify_vdd_mem(struct msm_rpm_notifier_data
- *rpm_notifier_cb)
-{
- struct msm_lpm_resource *rs = &msm_lpm_vdd_mem;
- msm_lpm_notify_common(rpm_notifier_cb, rs);
-}
-
-static int msm_lpm_init_value_vdd_mem(struct device_node *node,
- char *key, uint32_t *default_value)
-{
- return of_property_read_u32(node, key, default_value);
-}
-
-/*PXO*/
-static bool msm_lpm_beyond_limits_pxo(struct msm_rpmrs_limits *limits)
-{
- bool ret = true;
- struct msm_lpm_resource *rs = &msm_lpm_pxo;
-
- if (rs->valid) {
- uint32_t pxo_buf = rs->rs_data.value;
- uint32_t pxo = rs->enable_low_power ? MSM_LPM_PXO_OFF :
- rs->rs_data.default_value;
-
- if (pxo_buf > pxo)
- pxo = pxo_buf;
-
- ret = (pxo > limits->pxo);
-
- if (msm_lpm_debug_mask & MSM_LPMRS_DEBUG_PXO)
- pr_info("%s:pxo buf %d pxo %d limits pxo %d\n",
- __func__, pxo_buf, pxo, limits->pxo);
- }
- return ret;
-}
-
-static void msm_lpm_aggregate_pxo(struct msm_rpmrs_limits *limits)
-{
- struct msm_lpm_resource *rs = &msm_lpm_pxo;
-
- if (rs->valid) {
- uint32_t pxo_buf = rs->rs_data.value;
- if (limits->pxo > pxo_buf)
- rs->sleep_value = limits->pxo;
- else
- rs->sleep_value = pxo_buf;
-
- if (msm_lpm_debug_mask & MSM_LPMRS_DEBUG_PXO)
- pr_info("%s: pxo buf %d sleep value %d\n",
- __func__, pxo_buf, rs->sleep_value);
- }
- trace_lpm_resources(rs->sleep_value, rs->name);
-}
-
-static void msm_lpm_flush_pxo(int notify_rpm)
-{
- if (notify_rpm) {
- struct msm_lpm_resource *rs = &msm_lpm_pxo;
- msm_lpm_send_sleep_data(rs->rs_data.handle,
- rs->rs_data.key,
- (uint8_t *)&rs->sleep_value);
- }
-}
-
-static void msm_lpm_notify_pxo(struct msm_rpm_notifier_data
- *rpm_notifier_cb)
-{
- struct msm_lpm_resource *rs = &msm_lpm_pxo;
- msm_lpm_notify_common(rpm_notifier_cb, rs);
-}
-
-static int msm_lpm_init_value_pxo(struct device_node *node,
- char *key, uint32_t *default_value)
-{
- return msm_lpm_get_xo_value(node, key, default_value);
-}
-
-static inline bool msm_lpm_use_mpm(struct msm_rpmrs_limits *limits)
-{
- return (limits->pxo == MSM_LPM_PXO_OFF);
-}
-
-int msm_lpm_get_xo_value(struct device_node *node,
- char *key, uint32_t *xo_val)
-{
- int i;
- struct lpm_lookup_table pxo_mode_lookup[] = {
- {MSM_LPM_PXO_OFF, "xo_off"},
- {MSM_LPM_PXO_ON, "xo_on"}
- };
- const char *xo_str;
- int ret;
-
- ret = of_property_read_string(node, key, &xo_str);
- if (!ret) {
- ret = -EINVAL;
- for (i = 0; i < ARRAY_SIZE(pxo_mode_lookup); i++) {
- if (!strncmp(xo_str, pxo_mode_lookup[i].mode_name,
- MAX_STR_LEN)) {
- *xo_val = pxo_mode_lookup[i].modes;
- ret = 0;
- break;
- }
- }
- }
- return ret;
-}
-
-/* LPM levels interface */
-bool msm_lpm_level_beyond_limit(struct msm_rpmrs_limits *limits)
-{
- int i;
- struct msm_lpm_resource *rs;
- bool beyond_limit = false;
-
- for (i = 0; i < ARRAY_SIZE(msm_lpm_resources); i++) {
- rs = msm_lpm_resources[i];
- if (rs->beyond_limits && rs->beyond_limits(limits)) {
- beyond_limit = true;
- if (msm_lpm_debug_mask & MSM_LPMRS_DEBUG_LVLS)
- pr_info("%s: %s beyond limit", __func__,
- rs->name);
- break;
- }
- }
-
- return beyond_limit;
-}
-
-int msm_lpmrs_enter_sleep(uint32_t sclk_count, struct msm_rpmrs_limits *limits,
- bool from_idle, bool notify_rpm)
-{
- int ret = 0;
- int i;
- struct msm_lpm_resource *rs = NULL;
-
- for (i = 0; i < ARRAY_SIZE(msm_lpm_resources); i++) {
- rs = msm_lpm_resources[i];
- if (rs->aggregate)
- rs->aggregate(limits);
- }
-
- msm_lpm_get_rpm_notif = false;
- for (i = 0; i < ARRAY_SIZE(msm_lpm_resources); i++) {
- rs = msm_lpm_resources[i];
- if (rs->valid && rs->flush)
- rs->flush(notify_rpm);
- }
- msm_lpm_get_rpm_notif = true;
-
- if (notify_rpm)
- msm_mpm_enter_sleep(sclk_count, from_idle);
-
- return ret;
-}
-
-void msm_lpmrs_exit_sleep(struct msm_rpmrs_limits *limits,
- bool from_idle, bool notify_rpm, bool collapsed)
-{
- if (msm_lpm_use_mpm(limits))
- msm_mpm_exit_sleep(from_idle);
-
- if (msm_lpm_l2.valid)
- msm_lpm_set_l2_mode(msm_lpm_l2.rs_data.default_value);
-}
-
-static int msm_lpm_cpu_callback(struct notifier_block *cpu_nb,
- unsigned long action, void *hcpu)
-{
- struct msm_lpm_resource *rs = &msm_lpm_l2;
- switch (action) {
- case CPU_UP_PREPARE:
- case CPU_UP_PREPARE_FROZEN:
- rs->rs_data.value = rs->rs_data.default_value;
- break;
- case CPU_ONLINE_FROZEN:
- case CPU_ONLINE:
- if (num_online_cpus() > 1)
- rs->rs_data.value = rs->rs_data.default_value;
- break;
- case CPU_DEAD_FROZEN:
- case CPU_DEAD:
- if (num_online_cpus() == 1)
- rs->rs_data.value = MSM_LPM_L2_CACHE_HSFS_OPEN;
- break;
- }
- return NOTIFY_OK;
-}
-
-/* RPM CTL */
-static int __devinit msm_lpm_init_rpm_ctl(void)
-{
- struct msm_lpm_resource *rs = &msm_lpm_rpm_ctl;
-
- rs->rs_data.handle = msm_rpm_create_request(
- MSM_RPM_CTX_ACTIVE_SET,
- rs->rs_data.type,
- rs->rs_data.id, 1);
- if (!rs->rs_data.handle)
- return -EIO;
-
- rs->valid = true;
- return 0;
-}
-
-static int __devinit msm_lpm_resource_sysfs_add(void)
-{
- struct kobject *module_kobj = NULL;
- struct kobject *low_power_kobj = NULL;
- struct kobject *mode_kobj = NULL;
- int rc = 0;
-
- 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 resource_sysfs_add_exit;
- }
-
- low_power_kobj = kobject_create_and_add(
- "enable_low_power", module_kobj);
- if (!low_power_kobj) {
- pr_err("%s: cannot create kobject\n", __func__);
- rc = -ENOMEM;
- goto resource_sysfs_add_exit;
- }
-
- mode_kobj = kobject_create_and_add(
- "mode", module_kobj);
- if (!mode_kobj) {
- pr_err("%s: cannot create kobject\n", __func__);
- rc = -ENOMEM;
- goto resource_sysfs_add_exit;
- }
-
- rc = sysfs_create_group(low_power_kobj, &msm_lpm_attribute_group);
- if (rc) {
- pr_err("%s: cannot create kobject attribute group\n", __func__);
- goto resource_sysfs_add_exit;
- }
-
- rc = sysfs_create_group(mode_kobj, &msm_lpm_rpm_ctl_attr_group);
- if (rc) {
- pr_err("%s: cannot create kobject attribute group\n", __func__);
- goto resource_sysfs_add_exit;
- }
-
-resource_sysfs_add_exit:
- if (rc) {
- if (low_power_kobj)
- sysfs_remove_group(low_power_kobj,
- &msm_lpm_attribute_group);
- kobject_del(low_power_kobj);
- kobject_del(mode_kobj);
- }
-
- return rc;
-}
-
-late_initcall(msm_lpm_resource_sysfs_add);
-
-static int __devinit msm_lpmrs_probe(struct platform_device *pdev)
-{
- struct device_node *node = NULL;
- char *key = NULL;
- int ret = 0;
-
- for_each_child_of_node(pdev->dev.of_node, node) {
- struct msm_lpm_resource *rs = NULL;
- const char *val;
- int i;
- bool local_resource;
-
- key = "qcom,name";
- ret = of_property_read_string(node, key, &val);
- if (ret) {
- pr_err("Cannot read string\n");
- goto fail;
- }
-
- for (i = 0; i < ARRAY_SIZE(msm_lpm_resources); i++) {
- char *lpmrs_name = msm_lpm_resources[i]->name;
- if (!msm_lpm_resources[i]->valid &&
- !strncmp(val, lpmrs_name, strnlen(lpmrs_name,
- MAX_RS_NAME))) {
- rs = msm_lpm_resources[i];
- break;
- }
- }
-
- if (!rs) {
- pr_err("LPM resource not found\n");
- continue;
- }
-
- key = "qcom,init-value";
- ret = rs->init_value(node, key, &rs->rs_data.default_value);
- if (ret) {
- pr_err("%s():Failed to read %s\n", __func__, key);
- goto fail;
- }
-
- rs->rs_data.value = rs->rs_data.default_value;
-
- key = "qcom,local-resource-type";
- local_resource = of_property_read_bool(node, key);
-
- if (!local_resource) {
- key = "qcom,type";
- ret = of_property_read_u32(node, key,
- &rs->rs_data.type);
- if (ret) {
- pr_err("Failed to read type\n");
- goto fail;
- }
-
- key = "qcom,id";
- ret = of_property_read_u32(node, key, &rs->rs_data.id);
- if (ret) {
- pr_err("Failed to read id\n");
- goto fail;
- }
-
- key = "qcom,key";
- ret = of_property_read_u32(node, key, &rs->rs_data.key);
- if (ret) {
- pr_err("Failed to read key\n");
- goto fail;
- }
-
- rs->rs_data.handle = msm_lpm_create_rpm_request(
- rs->rs_data.type,
- rs->rs_data.id);
-
- if (!rs->rs_data.handle) {
- pr_err("%s: Failed to allocate handle for %s\n",
- __func__, rs->name);
- ret = -1;
- goto fail;
- }
- /* fall through */
- }
-
- rs->valid = true;
- }
- msm_rpm_register_notifier(&msm_lpm_rpm_nblk);
- msm_lpm_init_rpm_ctl();
-
- if (msm_lpm_l2.valid) {
- register_hotcpu_notifier(&msm_lpm_cpu_nblk);
- /* For UP mode, set the default to HSFS OPEN*/
- if (num_possible_cpus() == 1) {
- msm_lpm_l2.rs_data.default_value =
- MSM_LPM_L2_CACHE_HSFS_OPEN;
- msm_lpm_l2.rs_data.value = MSM_LPM_L2_CACHE_HSFS_OPEN;
- }
- msm_pm_set_l2_flush_flag(0);
- } else
- msm_pm_set_l2_flush_flag(1);
-
-fail:
- return ret;
-}
-
-static struct of_device_id msm_lpmrs_match_table[] = {
- {.compatible = "qcom,lpm-resources"},
- {},
-};
-
-static struct platform_driver msm_lpmrs_driver = {
- .probe = msm_lpmrs_probe,
- .driver = {
- .name = "lpm-resources",
- .owner = THIS_MODULE,
- .of_match_table = msm_lpmrs_match_table,
- },
-};
-
-int __init msm_lpmrs_module_init(void)
-{
- return platform_driver_register(&msm_lpmrs_driver);
-}
diff --git a/arch/arm/mach-msm/lpm_resources.h b/arch/arm/mach-msm/lpm_resources.h
deleted file mode 100644
index 105cfe6..0000000
--- a/arch/arm/mach-msm/lpm_resources.h
+++ /dev/null
@@ -1,235 +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.
- */
-
-#ifndef __ARCH_ARM_MACH_MSM_LPM_RESOURCES_H
-#define __ARCH_ARM_MACH_MSM_LPM_RESOURCES_H
-
-#include "pm.h"
-#include "test-lpm.h"
-
-enum {
- MSM_LPM_PXO_OFF,
- MSM_LPM_PXO_ON
-};
-
-enum {
- MSM_LPM_L2_CACHE_HSFS_OPEN,
- MSM_LPM_L2_CACHE_GDHS,
- MSM_LPM_L2_CACHE_RETENTION,
- MSM_LPM_L2_CACHE_ACTIVE,
-};
-
-struct msm_rpmrs_limits {
- uint32_t pxo;
- uint32_t l2_cache;
- uint32_t vdd_mem_upper_bound;
- uint32_t vdd_mem_lower_bound;
- uint32_t vdd_dig_upper_bound;
- uint32_t vdd_dig_lower_bound;
- bool irqs_detectable;
- bool gpio_detectable;
-
- uint32_t latency_us[NR_CPUS];
- uint32_t power[NR_CPUS];
-};
-
-struct msm_rpmrs_level {
- enum msm_pm_sleep_mode sleep_mode;
- struct msm_rpmrs_limits rs_limits;
- bool available;
- uint32_t latency_us;
- uint32_t steady_state_power;
- uint32_t energy_overhead;
- uint32_t time_overhead_us;
-};
-
-enum {
- MSM_LPM_STATE_ENTER = 0,
- MSM_LPM_STATE_EXIT = 1,
-};
-
-#define MSM_PM(field) MSM_LPM_##field
-
-/**
- * msm_pm_get_pxo() - get the limits for pxo
- * @limits: pointer to the msm_rpmrs_limits structure
- *
- * This function gets the limits to the resource pxo on
- * 8974
- */
-
-uint32_t msm_pm_get_pxo(struct msm_rpmrs_limits *limits);
-
-/**
- * msm_pm_get_l2_cache() - get the limits for l2 cache
- * @limits: pointer to the msm_rpmrs_limits structure
- *
- * This function gets the limits to the resource l2 cache
- * on 8974
- */
-
-uint32_t msm_pm_get_l2_cache(struct msm_rpmrs_limits *limits);
-
-/**
- * msm_pm_get_vdd_mem() - get the limits for pxo
- * @limits: pointer to the msm_rpmrs_limits structure
- *
- * This function gets the limits to the resource vdd mem
- * on 8974
- */
-
-uint32_t msm_pm_get_vdd_mem(struct msm_rpmrs_limits *limits);
-
-/**
- * msm_pm_get_vdd_dig() - get the limits for vdd dig
- * @limits: pointer to the msm_rpmrs_limits structure
- *
- * This function gets the limits to the resource on 8974
- */
-
-uint32_t msm_pm_get_vdd_dig(struct msm_rpmrs_limits *limits);
-
-/**
- * msm_lpm_get_xo_value() - get the enum value for xo
- * @node pointer to the device node
- * @key pxo property key
- * @xo_val xo enum value
- */
-int msm_lpm_get_xo_value(struct device_node *node,
- char *key, uint32_t *xo_val);
-
-/**
- * msm_lpm_get_l2_cache_value() - get the enum value for l2 cache
- * @node pointer to the device node
- * @key l2 cache property key
- * @l2_val l2 mode enum value
- */
-int msm_lpm_get_l2_cache_value(struct device_node *node,
- char *key, uint32_t *l2_val);
-
-/**
- * struct msm_lpm_sleep_data - abstraction to get sleep data
- * @limits: pointer to the msm_rpmrs_limits structure
- * @kernel_sleep: kernel sleep time as decided by the power calculation
- * algorithm
- *
- * This structure is an abstraction to get the limits and kernel sleep time
- * during enter sleep.
- */
-
-struct msm_lpm_sleep_data {
- struct msm_rpmrs_limits *limits;
- uint32_t kernel_sleep;
-};
-
-/**
- * msm_lpm_register_notifier() - register for notifications
- * @cpu: cpu to debug
- * @level_iter: low power level index to debug
- * @nb: notifier block to callback on notifications
- * @is_latency_measure: is it latency measure
- *
- * This function sets the permitted level to the index of the
- * level under test and registers notifier for callback.
- */
-
-int msm_lpm_register_notifier(int cpu, int level_iter,
- struct notifier_block *nb, bool is_latency_measure);
-
-/**
- * msm_lpm_unregister_notifier() - unregister from notifications
- * @cpu: cpu to debug
- * @nb: notifier block to callback on notifications
- *
- * This function sets the permitted level to a value one more than
- * available levels count which indicates that all levels are
- * permitted and it also unregisters notifier for callback.
- */
-
-int msm_lpm_unregister_notifier(int cpu, struct notifier_block *nb);
-
-#ifdef CONFIG_MSM_RPM_SMD
-
-/**
- * msm_lpm_level_beyond_limit() - Check if the resources in a low power level
- * is beyond the limits of the driver votes received for those resources.This
- * function is used by lpm_levels to eliminate any low power level that cannot
- * be entered.
- *
- * @limits: pointer to the resource limits of a low power level.
- *
- * returns true if the resource limits are beyond driver resource votes.
- * false otherwise.
- */
-bool msm_lpm_level_beyond_limit(struct msm_rpmrs_limits *limits);
-
-/**
- * msm_lpmrs_enter_sleep() - Enter sleep flushes the sleep votes of low power
- * resources to the RPM driver, also configure the MPM if needed depending
- * on the low power mode being entered. L2 low power mode is also set in
- * this function.
-
- * @sclk_count: wakeup counter for RPM.
- * @limits: pointer to the resource limits of the low power mode being entered.
- * @from_idle: bool to determine if this call being made as a part of
- * idle power collapse.
- * @notify_rpm: bool that informs if this is an RPM notified power collapse.
- *
- * returns 0 on success.
- */
-int msm_lpmrs_enter_sleep(uint32_t sclk_count, struct msm_rpmrs_limits *limits,
- bool from_idle, bool notify_rpm);
-
-/**
- * msm_lpmrs_exit_sleep() - Exit sleep, reset the MPM and L2 mode.
- * @ limits: pointer to resource limits of the most recent low power mode.
- * @from_idle: bool to determine if this call being made as a part of
- * idle power collapse.
- * @notify_rpm: bool that informs if this is an RPM notified power collapse.
- * @collapsed: bool that informs if the Krait was power collapsed.
- */
-void msm_lpmrs_exit_sleep(struct msm_rpmrs_limits *limits,
- bool from_idle, bool notify_rpm, bool collapsed);
-/**
- * msm_lpmrs_module_init() - Init function that parses the device tree to
- * get the low power resource attributes and registers with RPM driver for
- * callback notification.
- *
- * returns 0 on success.
- */
-int __init msm_lpmrs_module_init(void);
-
-#else
-static inline bool msm_lpm_level_beyond_limit(struct msm_rpmrs_limits *limits)
-{
- return true;
-}
-
-static inline int msm_lpmrs_enter_sleep(uint32_t sclk_count,
- struct msm_rpmrs_limits *limits, bool from_idle, bool notify_rpm)
-{
- return 0;
-}
-
-static inline void msm_lpmrs_exit_sleep(struct msm_rpmrs_limits *limits,
- bool from_idle, bool notify_rpm, bool collapsed)
-{
- return;
-}
-
-static inline int __init msm_lpmrs_module_init(void)
-{
- return 0;
-}
-#endif /* CONFIG_MSM_RPM_SMD */
-
-#endif
diff --git a/arch/arm/mach-msm/memory.c b/arch/arm/mach-msm/memory.c
index 7a7fb99..a974018 100644
--- a/arch/arm/mach-msm/memory.c
+++ b/arch/arm/mach-msm/memory.c
@@ -43,7 +43,6 @@
/* fixme */
#include <asm/tlbflush.h>
#include <../../mm/mm.h>
-#include <linux/fmem.h>
#if defined(CONFIG_ARCH_MSM7X27)
static void *strongly_ordered_page;
@@ -251,16 +250,6 @@
: "=r" (msm_ttbr0));
}
-int request_fmem_c_region(void *unused)
-{
- return fmem_set_state(FMEM_C_STATE);
-}
-
-int release_fmem_c_region(void *unused)
-{
- return fmem_set_state(FMEM_T_STATE);
-}
-
static char * const memtype_names[] = {
[MEMTYPE_SMI_KERNEL] = "SMI_KERNEL",
[MEMTYPE_SMI] = "SMI",
@@ -319,6 +308,8 @@
unsigned long memory_reserve_prop_length;
unsigned int memory_size;
unsigned int memory_start;
+ unsigned int num_holes = 0;
+ int i;
int ret;
memory_name_prop = of_get_flat_dt_prop(node,
@@ -369,21 +360,27 @@
mem_remove:
if (memory_remove_prop) {
- if (memory_remove_prop_length != (2*sizeof(unsigned int))) {
+ if (!memory_remove_prop_length || (memory_remove_prop_length %
+ (2 * sizeof(unsigned int)) != 0)) {
WARN(1, "Memory remove malformed\n");
goto mem_reserve;
}
- memory_start = be32_to_cpu(memory_remove_prop[0]);
- memory_size = be32_to_cpu(memory_remove_prop[1]);
+ num_holes = memory_remove_prop_length /
+ (2 * sizeof(unsigned int));
- ret = memblock_remove(memory_start, memory_size);
- if (ret)
- WARN(1, "Failed to remove memory %x-%x\n",
+ for (i = 0; i < (num_holes * 2); i += 2) {
+ memory_start = be32_to_cpu(memory_remove_prop[i]);
+ memory_size = be32_to_cpu(memory_remove_prop[i+1]);
+
+ ret = memblock_remove(memory_start, memory_size);
+ if (ret)
+ WARN(1, "Failed to remove memory %x-%x\n",
memory_start, memory_start+memory_size);
- else
- pr_info("Node %s removed memory %x-%x\n", uname,
+ else
+ pr_info("Node %s removed memory %x-%x\n", uname,
memory_start, memory_start+memory_size);
+ }
}
mem_reserve:
@@ -439,6 +436,8 @@
unsigned long memory_remove_prop_length;
unsigned long hole_start;
unsigned long hole_size;
+ unsigned int num_holes = 0;
+ int i = 0;
memory_remove_prop = of_get_flat_dt_prop(node,
"qcom,memblock-remove",
@@ -452,15 +451,21 @@
}
if (memory_remove_prop) {
- if (memory_remove_prop_length != (2*sizeof(unsigned int))) {
+ if (!memory_remove_prop_length || (memory_remove_prop_length %
+ (2 * sizeof(unsigned int)) != 0)) {
WARN(1, "Memory remove malformed\n");
goto out;
}
- hole_start = be32_to_cpu(memory_remove_prop[0]);
- hole_size = be32_to_cpu(memory_remove_prop[1]);
+ num_holes = memory_remove_prop_length /
+ (2 * sizeof(unsigned int));
- adjust_meminfo(hole_start, hole_size);
+ for (i = 0; i < (num_holes * 2); i += 2) {
+ hole_start = be32_to_cpu(memory_remove_prop[i]);
+ hole_size = be32_to_cpu(memory_remove_prop[i+1]);
+
+ adjust_meminfo(hole_start, hole_size);
+ }
}
out:
diff --git a/arch/arm/mach-msm/mpm-of.c b/arch/arm/mach-msm/mpm-of.c
index 5c654b0..a0746f9 100644
--- a/arch/arm/mach-msm/mpm-of.c
+++ b/arch/arm/mach-msm/mpm-of.c
@@ -27,10 +27,17 @@
#include <linux/of_address.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/power_supply.h>
+#include <linux/regulator/consumer.h>
+#include <linux/workqueue.h>
#include <asm/hardware/gic.h>
#include <asm/arch_timer.h>
#include <mach/gpio.h>
#include <mach/mpm.h>
+#include <mach/clk.h>
+#include <mach/rpm-regulator-smd.h>
enum {
MSM_MPM_GIC_IRQ_DOMAIN,
@@ -75,6 +82,12 @@
#define ARCH_TIMER_HZ (19200000)
static struct msm_mpm_device_data msm_mpm_dev_data;
+static struct clk *xo_clk;
+static bool xo_enabled;
+static struct workqueue_struct *msm_mpm_wq;
+static struct work_struct msm_mpm_work;
+static struct completion wake_wq;
+
enum mpm_reg_offsets {
MSM_MPM_REG_WAKEUP,
MSM_MPM_REG_ENABLE,
@@ -257,6 +270,8 @@
else
__clear_bit(d->hwirq, irq_apps);
+ if (!wakeset && (msm_mpm_initialized & MSM_MPM_DEVICE_PROBED))
+ complete(&wake_wq);
}
return 0;
@@ -543,6 +558,54 @@
}
}
}
+static void msm_mpm_sys_low_power_modes(bool allow)
+{
+ if (allow) {
+ if (xo_enabled) {
+ clk_disable_unprepare(xo_clk);
+ xo_enabled = false;
+ }
+ } else {
+ if (!xo_enabled) {
+ /* If we cannot enable XO clock then we want to flag it,
+ * than having to deal with not being able to wakeup
+ * from a non-monitorable interrupt
+ */
+ BUG_ON(clk_prepare_enable(xo_clk));
+ xo_enabled = true;
+ }
+ }
+}
+
+void msm_mpm_suspend_prepare(void)
+{
+ bool allow = msm_mpm_irqs_detectable(false) &&
+ msm_mpm_gpio_irqs_detectable(false);
+ msm_mpm_sys_low_power_modes(allow);
+}
+EXPORT_SYMBOL(msm_mpm_suspend_prepare);
+
+void msm_mpm_suspend_wake(void)
+{
+ bool allow = msm_mpm_irqs_detectable(true) &&
+ msm_mpm_gpio_irqs_detectable(true);
+ msm_mpm_sys_low_power_modes(allow);
+}
+EXPORT_SYMBOL(msm_mpm_suspend_wake);
+
+static void msm_mpm_work_fn(struct work_struct *work)
+{
+ unsigned long flags;
+ while (1) {
+ bool allow;
+ wait_for_completion(&wake_wq);
+ spin_lock_irqsave(&msm_mpm_lock, flags);
+ allow = msm_mpm_irqs_detectable(true) &&
+ msm_mpm_gpio_irqs_detectable(true);
+ spin_unlock_irqrestore(&msm_mpm_lock, flags);
+ msm_mpm_sys_low_power_modes(allow);
+ }
+}
static int __devinit msm_mpm_dev_probe(struct platform_device *pdev)
{
@@ -555,73 +618,89 @@
return 0;
}
+ xo_clk = devm_clk_get(&pdev->dev, "xo");
+
+ if (IS_ERR(xo_clk)) {
+ pr_err("%s(): Cannot get clk resource for XO\n", __func__);
+ return PTR_ERR(xo_clk);
+ }
+
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vmpm");
if (!res) {
pr_err("%s(): Missing RPM memory resource\n", __func__);
- goto fail;
+ return -EINVAL;
}
dev->mpm_request_reg_base = devm_request_and_ioremap(&pdev->dev, res);
if (!dev->mpm_request_reg_base) {
pr_err("%s(): Unable to iomap\n", __func__);
- goto fail;
+ return -EADDRNOTAVAIL;
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ipc");
if (!res) {
pr_err("%s(): Missing GCC memory resource\n", __func__);
- goto failed_irq_get;
+ return -EINVAL;
}
dev->mpm_apps_ipc_reg = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
+ if (!dev->mpm_apps_ipc_reg) {
+ pr_err("%s(): Unable to iomap IPC register\n", __func__);
+ return -EADDRNOTAVAIL;
+ }
if (of_property_read_u32(pdev->dev.of_node,
"qcom,ipc-bit-offset", &offset)) {
pr_info("%s(): Cannot read ipc bit offset\n", __func__);
- goto failed_free_irq;
+ return -EINVAL ;
}
dev->mpm_apps_ipc_val = (1 << offset);
- if (!dev->mpm_apps_ipc_reg)
- goto failed_irq_get;
-
dev->mpm_ipc_irq = platform_get_irq(pdev, 0);
if (dev->mpm_ipc_irq == -ENXIO) {
pr_info("%s(): Cannot find IRQ resource\n", __func__);
- goto failed_irq_get;
+ return -ENXIO;
}
- ret = request_irq(dev->mpm_ipc_irq, msm_mpm_irq,
+ ret = devm_request_irq(&pdev->dev, dev->mpm_ipc_irq, msm_mpm_irq,
IRQF_TRIGGER_RISING, pdev->name, msm_mpm_irq);
if (ret) {
pr_info("%s(): request_irq failed errno: %d\n", __func__, ret);
- goto failed_irq_get;
+ return ret;
}
ret = irq_set_irq_wake(dev->mpm_ipc_irq, 1);
if (ret) {
pr_err("%s: failed to set wakeup irq %u: %d\n",
__func__, dev->mpm_ipc_irq, ret);
- goto failed_irq_get;
+ return ret;
}
+
+ init_completion(&wake_wq);
+
+ INIT_WORK(&msm_mpm_work, msm_mpm_work_fn);
+ msm_mpm_wq = create_singlethread_workqueue("mpm");
+
+ if (msm_mpm_wq)
+ queue_work(msm_mpm_wq, &msm_mpm_work);
+ else {
+ pr_warn("%s(): Failed to create wq. So voting against XO off",
+ __func__);
+ /* Throw a BUG. Otherwise, its possible that system allows
+ * XO shutdown when there are non-monitored interrupts are
+ * pending and cause errors at a later point in time.
+ */
+ BUG_ON(clk_prepare_enable(xo_clk));
+ xo_enabled = true;
+ }
+
msm_mpm_initialized |= MSM_MPM_DEVICE_PROBED;
-
return 0;
-
-failed_free_irq:
- free_irq(dev->mpm_ipc_irq, msm_mpm_irq);
-failed_irq_get:
- if (dev->mpm_apps_ipc_reg)
- devm_iounmap(&pdev->dev, dev->mpm_apps_ipc_reg);
- if (dev->mpm_request_reg_base)
- devm_iounmap(&pdev->dev, dev->mpm_request_reg_base);
-fail:
- return -EINVAL;
}
static inline int __init mpm_irq_domain_linear_size(struct irq_domain *d)
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_9625.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_9625.c
index 65834eb..3a996eb 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_board_9625.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_9625.c
@@ -595,8 +595,8 @@
.ws = 10000,
.mas_hw_id = MAS_APPSS_PROC,
.prio_lvl = 0,
- .prio_rd = 2,
- .prio_wr = 2,
+ .prio_rd = 0,
+ .prio_wr = 0,
},
{
.id = MSM_BUS_MASTER_MSS_PROC,
diff --git a/arch/arm/mach-msm/msm_qmi_interface.c b/arch/arm/mach-msm/msm_qmi_interface.c
index 8d96bd8..a8fed52 100644
--- a/arch/arm/mach-msm/msm_qmi_interface.c
+++ b/arch/arm/mach-msm/msm_qmi_interface.c
@@ -439,12 +439,12 @@
/* Wait for the response */
if (!timeout_ms) {
- rc = wait_event_interruptible(txn_handle->wait_q,
- (txn_handle->resp_received ||
- handle->handle_reset ||
- (txn_handle->send_stat < 0)));
+ wait_event(txn_handle->wait_q,
+ (txn_handle->resp_received ||
+ handle->handle_reset ||
+ (txn_handle->send_stat < 0)));
} else {
- rc = wait_event_interruptible_timeout(txn_handle->wait_q,
+ rc = wait_event_timeout(txn_handle->wait_q,
(txn_handle->resp_received ||
handle->handle_reset ||
(txn_handle->send_stat < 0)),
diff --git a/arch/arm/mach-msm/msm_watchdog_v2.c b/arch/arm/mach-msm/msm_watchdog_v2.c
index 4778d5b..52e94e6 100644
--- a/arch/arm/mach-msm/msm_watchdog_v2.c
+++ b/arch/arm/mach-msm/msm_watchdog_v2.c
@@ -340,6 +340,11 @@
mb();
/* Delay to make sure bite occurs */
mdelay(1);
+ pr_err("Wdog - STS: 0x%x, CTL: 0x%x, BARK TIME: 0x%x, BITE TIME: 0x%x",
+ __raw_readl(wdog_dd->base + WDT0_STS),
+ __raw_readl(wdog_dd->base + WDT0_EN),
+ __raw_readl(wdog_dd->base + WDT0_BARK_TIME),
+ __raw_readl(wdog_dd->base + WDT0_BITE_TIME));
panic("Failed to cause a watchdog bite! - Falling back to kernel panic!");
return IRQ_HANDLED;
}
diff --git a/arch/arm/mach-msm/ocmem_sched.c b/arch/arm/mach-msm/ocmem_sched.c
index a3fd6b2..cbf7933 100644
--- a/arch/arm/mach-msm/ocmem_sched.c
+++ b/arch/arm/mach-msm/ocmem_sched.c
@@ -1192,19 +1192,23 @@
}
/* Remove the request from eviction lists */
-static void cancel_restore(struct ocmem_req *e_handle,
- struct ocmem_req *req)
+static void cancel_restore(struct ocmem_req *req)
{
- struct ocmem_eviction_data *edata = e_handle->edata;
+ struct ocmem_eviction_data *edata;
- if (!edata || !req)
+ if (!req)
+ return;
+
+ edata = req->eviction_info;
+
+ if (!edata)
return;
if (list_empty(&edata->req_list))
return;
list_del_init(&req->eviction_list);
- req->e_handle = NULL;
+ req->eviction_info = NULL;
return;
}
@@ -1499,8 +1503,8 @@
}
/* Remove the request from any restore lists */
- if (req->e_handle)
- cancel_restore(req->e_handle, req);
+ if (req->eviction_info)
+ cancel_restore(req);
/* Remove the request from any pending opreations */
if (TEST_STATE(req, R_ENQUEUED)) {
@@ -1747,12 +1751,7 @@
goto shrink_fail;
}
- if (!req->e_handle) {
- pr_err("Unable to find evicting request\n");
- goto shrink_fail;
- }
-
- edata = req->e_handle->edata;
+ edata = req->eviction_info;
if (!edata) {
pr_err("Unable to find eviction data\n");
@@ -1905,7 +1904,7 @@
&e_req->eviction_list,
&edata->req_list);
atomic_inc(&edata->pending);
- e_req->e_handle = req;
+ e_req->eviction_info = edata;
}
}
} else {
@@ -2037,7 +2036,7 @@
pr_debug("ocmem: restoring evicted request %p\n",
req);
req->edata = NULL;
- req->e_handle = NULL;
+ req->eviction_info = NULL;
req->op = SCHED_ALLOCATE;
inc_ocmem_stat(zone_of(req), NR_RESTORES);
sched_enqueue(req);
@@ -2076,8 +2075,11 @@
struct ocmem_eviction_data *edata = evictions[id];
int rc = 0;
- if (!edata)
+ if (!edata) {
+ pr_err("Client %s invoked restore without any eviction\n",
+ get_name(id));
return -EINVAL;
+ }
mutex_lock(&free_mutex);
rc = __restore_common(edata);
diff --git a/arch/arm/mach-msm/pcie.c b/arch/arm/mach-msm/pcie.c
index c09b759..7695b2d 100644
--- a/arch/arm/mach-msm/pcie.c
+++ b/arch/arm/mach-msm/pcie.c
@@ -484,22 +484,19 @@
static void msm_pcie_adjust_tlp_size(struct msm_pcie_dev_t *dev)
{
/*
- * Apply this fix only for device such as APQ8064 version 1.
* Set the Max TLP size to 2K, instead of using default of 4K
* to avoid a RAM problem in PCIE20 core of that version.
*/
- if (readl_relaxed(dev->elbi + PCIE20_ELBI_VERSION) == 0x01002107) {
- /*
- * CFG_REMOTE_RD_REQ_BRIDGE_SIZE:
- * 5=4KB/4=2KB/3=1KB/2=512B/1=256B/0=128B
- */
- writel_relaxed(4, dev->pcie20 +
- PCIE20_PLR_AXI_MSTR_RESP_COMP_CTRL0);
+ /*
+ * CFG_REMOTE_RD_REQ_BRIDGE_SIZE:
+ * 5=4KB/4=2KB/3=1KB/2=512B/1=256B/0=128B
+ */
+ writel_relaxed(4, dev->pcie20 +
+ PCIE20_PLR_AXI_MSTR_RESP_COMP_CTRL0);
- writel_relaxed(1, dev->pcie20 +
- PCIE20_PLR_AXI_MSTR_RESP_COMP_CTRL1);
- }
+ writel_relaxed(1, dev->pcie20 +
+ PCIE20_PLR_AXI_MSTR_RESP_COMP_CTRL1);
};
static int __init msm_pcie_setup(int nr, struct pci_sys_data *sys)
diff --git a/arch/arm/mach-msm/perf_debug.c b/arch/arm/mach-msm/perf_debug.c
index 70420db..28d8e42 100644
--- a/arch/arm/mach-msm/perf_debug.c
+++ b/arch/arm/mach-msm/perf_debug.c
@@ -32,6 +32,9 @@
"7 Perf: Add L1 counters to tracepoints\n"
"8 Perf: Add cortex A7 perf support\n"
"9 ARM: dts: msm: add perf-events support for msm8226\n"
+ "10 Perf: Fix counts across power collapse\n"
+ "11 ARM: dts: msm: add perf-events support for msm8x10, msm8x12\n"
+ "12 Perf: Make per-process counters configurable\n"
;
static ssize_t desc_read(struct file *fp, char __user *buf,
diff --git a/arch/arm/mach-msm/perf_trace_counters.c b/arch/arm/mach-msm/perf_trace_counters.c
index d961994..65b0d28 100644
--- a/arch/arm/mach-msm/perf_trace_counters.c
+++ b/arch/arm/mach-msm/perf_trace_counters.c
@@ -10,9 +10,13 @@
* GNU General Public License for more details.
*/
#include <asm/thread_notify.h>
+#include <linux/uaccess.h>
+#include <linux/debugfs.h>
#define CREATE_TRACE_POINTS
#include "perf_trace_counters.h"
+static unsigned int tp_pid_state;
+
static int tracectr_notifier(struct notifier_block *self, unsigned long cmd,
void *v)
{
@@ -34,9 +38,80 @@
.notifier_call = tracectr_notifier,
};
+static void enable_tp_pid(void)
+{
+ if (tp_pid_state == 0) {
+ tp_pid_state = 1;
+ thread_register_notifier(&tracectr_notifier_block);
+ }
+}
+
+static void disable_tp_pid(void)
+{
+ if (tp_pid_state == 1) {
+ tp_pid_state = 0;
+ thread_unregister_notifier(&tracectr_notifier_block);
+ }
+}
+
+static ssize_t read_enabled_perftp_file_bool(struct file *file,
+ char __user *user_buf, size_t count, loff_t *ppos)
+{
+ char buf[2];
+ buf[1] = '\n';
+ if (tp_pid_state == 0)
+ buf[0] = '0';
+ else
+ buf[0] = '1';
+ return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
+}
+
+static ssize_t write_enabled_perftp_file_bool(struct file *file,
+ const char __user *user_buf, size_t count, loff_t *ppos)
+{
+ char buf[32];
+ size_t buf_size;
+
+ buf_size = min(count, (sizeof(buf)-1));
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ switch (buf[0]) {
+ case 'y':
+ case 'Y':
+ case '1':
+ enable_tp_pid();
+ break;
+ case 'n':
+ case 'N':
+ case '0':
+ disable_tp_pid();
+ break;
+ }
+
+ return count;
+}
+
+static const struct file_operations fops_perftp = {
+ .read = read_enabled_perftp_file_bool,
+ .write = write_enabled_perftp_file_bool,
+ .llseek = default_llseek,
+};
+
int __init init_tracecounters(void)
{
- thread_register_notifier(&tracectr_notifier_block);
+ struct dentry *dir;
+ struct dentry *file;
+ unsigned int value = 1;
+
+ dir = debugfs_create_dir("perf_debug_tp", NULL);
+ if (!dir)
+ return -ENOMEM;
+ file = debugfs_create_file("enabled", 0777, dir,
+ &value, &fops_perftp);
+ if (!file) {
+ debugfs_remove(dir);
+ return -ENOMEM;
+ }
return 0;
}
late_initcall(init_tracecounters);
diff --git a/arch/arm/mach-msm/peripheral-loader.c b/arch/arm/mach-msm/peripheral-loader.c
index c572291..8a3ecb1 100644
--- a/arch/arm/mach-msm/peripheral-loader.c
+++ b/arch/arm/mach-msm/peripheral-loader.c
@@ -30,6 +30,7 @@
#include <linux/list_sort.h>
#include <linux/idr.h>
#include <linux/interrupt.h>
+#include <linux/of_gpio.h>
#include <asm/uaccess.h>
#include <asm/setup.h>
@@ -251,6 +252,7 @@
struct pil_desc *desc = dev_id;
struct pil_priv *priv = desc->priv;
+ pil_info(desc, "Power/Clock ready interrupt received\n");
if (!desc->priv->unvoted_flag) {
desc->priv->unvoted_flag = 1;
__pil_proxy_unvote(priv);
@@ -283,6 +285,12 @@
return ERR_PTR(-EPERM);
}
+ if (phdr->p_filesz > phdr->p_memsz) {
+ pil_err(desc, "Segment %d: file size (%u) is greater than mem size (%u).\n",
+ num, phdr->p_filesz, phdr->p_memsz);
+ return ERR_PTR(-EINVAL);
+ }
+
seg = kmalloc(sizeof(*seg), GFP_KERNEL);
if (!seg)
return ERR_PTR(-ENOMEM);
@@ -511,51 +519,29 @@
int ret = 0, count;
phys_addr_t paddr;
char fw_name[30];
- const struct firmware *fw = NULL;
- const u8 *data;
int num = seg->num;
if (seg->filesz) {
snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d",
desc->name, num);
- ret = request_firmware(&fw, fw_name, desc->dev);
- if (ret) {
- pil_err(desc, "Failed to locate blob %s\n", fw_name);
+ ret = request_firmware_direct(fw_name, desc->dev, seg->paddr,
+ seg->filesz);
+ if (ret < 0) {
+ pil_err(desc, "Failed to locate blob %s or blob is too big.\n",
+ fw_name);
return ret;
}
- if (fw->size != seg->filesz) {
+ if (ret != seg->filesz) {
pil_err(desc, "Blob size %u doesn't match %lu\n",
- fw->size, seg->filesz);
- ret = -EPERM;
- goto release_fw;
+ ret, seg->filesz);
+ return -EPERM;
}
- }
-
- /* Load the segment into memory */
- count = seg->filesz;
- paddr = seg->paddr;
- data = fw ? fw->data : NULL;
- while (count > 0) {
- int size;
- u8 __iomem *buf;
-
- size = min_t(size_t, IOMAP_SIZE, count);
- buf = ioremap(paddr, size);
- if (!buf) {
- pil_err(desc, "Failed to map memory\n");
- ret = -ENOMEM;
- goto release_fw;
- }
- memcpy(buf, data, size);
- iounmap(buf);
-
- count -= size;
- paddr += size;
- data += size;
+ ret = 0;
}
/* Zero out trailing memory */
+ paddr = seg->paddr + seg->filesz;
count = seg->sz - seg->filesz;
while (count > 0) {
int size;
@@ -565,8 +551,7 @@
buf = ioremap(paddr, size);
if (!buf) {
pil_err(desc, "Failed to map memory\n");
- ret = -ENOMEM;
- goto release_fw;
+ return -ENOMEM;
}
memset(buf, 0, size);
iounmap(buf);
@@ -581,11 +566,37 @@
pil_err(desc, "Blob%u failed verification\n", num);
}
-release_fw:
- release_firmware(fw);
return ret;
}
+static void pil_parse_devicetree(struct pil_desc *desc)
+{
+ int clk_ready = 0;
+
+ if (of_find_property(desc->dev->of_node,
+ "qcom,gpio-proxy-unvote",
+ NULL)) {
+ clk_ready = of_get_named_gpio(desc->dev->of_node,
+ "qcom,gpio-proxy-unvote", 0);
+
+ if (clk_ready < 0) {
+ dev_err(desc->dev,
+ "[%s]: Error getting proxy unvoting gpio\n",
+ desc->name);
+ return;
+ }
+
+ clk_ready = gpio_to_irq(clk_ready);
+ if (clk_ready < 0) {
+ dev_err(desc->dev,
+ "[%s]: Error getting proxy unvote IRQ\n",
+ desc->name);
+ return;
+ }
+ }
+ desc->proxy_unvote_irq = clk_ready;
+}
+
/* Synchronize request_firmware() with suspend */
static DECLARE_RWSEM(pil_pm_rwsem);
@@ -741,12 +752,6 @@
void __iomem *addr;
char buf[sizeof(priv->info->name)];
- /* Ignore users who don't make any sense */
- WARN(desc->ops->proxy_unvote && desc->proxy_unvote_irq == 0
- && !desc->proxy_timeout,
- "Invalid proxy unvote callback or a proxy timeout of 0"
- " was specified or no proxy unvote IRQ was specified.\n");
-
if (WARN(desc->ops->proxy_unvote && !desc->ops->proxy_vote,
"Invalid proxy voting. Ignoring\n"))
((struct pil_reset_ops *)desc->ops)->proxy_unvote = NULL;
@@ -767,11 +772,19 @@
strncpy(buf, desc->name, sizeof(buf));
__iowrite32_copy(priv->info->name, buf, sizeof(buf) / 4);
- if (desc->proxy_unvote_irq > 0) {
+ pil_parse_devicetree(desc);
+
+ /* Ignore users who don't make any sense */
+ WARN(desc->ops->proxy_unvote && desc->proxy_unvote_irq == 0
+ && !desc->proxy_timeout,
+ "Invalid proxy unvote callback or a proxy timeout of 0"
+ " was specified or no proxy unvote IRQ was specified.\n");
+
+ if (desc->proxy_unvote_irq > 0 && desc->ops->proxy_unvote) {
ret = request_threaded_irq(desc->proxy_unvote_irq,
NULL,
proxy_unvote_intr_handler,
- IRQF_TRIGGER_RISING|IRQF_SHARED,
+ IRQF_TRIGGER_RISING,
desc->name, desc);
if (ret < 0) {
dev_err(desc->dev,
diff --git a/arch/arm/mach-msm/pil-dsps.c b/arch/arm/mach-msm/pil-dsps.c
index 73b58ab..f0a5ebf 100644
--- a/arch/arm/mach-msm/pil-dsps.c
+++ b/arch/arm/mach-msm/pil-dsps.c
@@ -23,6 +23,7 @@
#include <mach/msm_smsm.h>
#include <mach/ramdump.h>
#include <mach/msm_smem.h>
+#include <mach/msm_bus_board.h>
#include "peripheral-loader.h"
#include "scm-pas.h"
@@ -317,6 +318,8 @@
goto err_subsys;
}
+ scm_pas_init(MSM_BUS_MASTER_SPS);
+
ret = smsm_state_cb_register(SMSM_DSPS_STATE, SMSM_RESET,
dsps_smsm_state_cb, drv);
if (ret)
diff --git a/arch/arm/mach-msm/pil-gss.c b/arch/arm/mach-msm/pil-gss.c
index 840c90f..b209a25 100644
--- a/arch/arm/mach-msm/pil-gss.c
+++ b/arch/arm/mach-msm/pil-gss.c
@@ -571,6 +571,8 @@
goto err_smem;
}
+ scm_pas_init(MSM_BUS_MASTER_SPS);
+
ret = devm_request_irq(&pdev->dev, drv->irq, gss_wdog_bite_irq,
IRQF_TRIGGER_RISING, "gss_a5_wdog", drv);
if (ret < 0)
diff --git a/arch/arm/mach-msm/pil-modem.c b/arch/arm/mach-msm/pil-modem.c
index 8398206..f6a853e 100644
--- a/arch/arm/mach-msm/pil-modem.c
+++ b/arch/arm/mach-msm/pil-modem.c
@@ -25,6 +25,7 @@
#include <mach/subsystem_restart.h>
#include <mach/msm_smsm.h>
#include <mach/ramdump.h>
+#include <mach/msm_bus_board.h>
#include "modem_notifier.h"
#include "peripheral-loader.h"
@@ -490,6 +491,8 @@
goto err_ramdump;
}
+ scm_pas_init(MSM_BUS_MASTER_SPS);
+
ret = devm_request_irq(&pdev->dev, drv->irq, modem_wdog_bite_irq,
IRQF_TRIGGER_RISING, "modem_watchdog", drv);
if (ret)
diff --git a/arch/arm/mach-msm/pil-msa.c b/arch/arm/mach-msm/pil-msa.c
index a8f5b0e..3a26af9 100644
--- a/arch/arm/mach-msm/pil-msa.c
+++ b/arch/arm/mach-msm/pil-msa.c
@@ -292,25 +292,6 @@
.shutdown = pil_msa_pbl_shutdown,
};
-static int pil_msa_mba_make_proxy_votes(struct pil_desc *pil)
-{
- int ret;
- struct mba_data *drv = container_of(pil, struct mba_data, desc);
-
- ret = clk_prepare_enable(drv->xo);
- if (ret) {
- dev_err(pil->dev, "Failed to enable XO\n");
- return ret;
- }
- return 0;
-}
-
-static void pil_msa_mba_remove_proxy_votes(struct pil_desc *pil)
-{
- struct mba_data *drv = container_of(pil, struct mba_data, desc);
- clk_disable_unprepare(drv->xo);
-}
-
static int pil_msa_mba_init_image(struct pil_desc *pil,
const u8 *metadata, size_t size)
{
@@ -400,8 +381,6 @@
struct pil_reset_ops pil_msa_mba_ops = {
.init_image = pil_msa_mba_init_image,
- .proxy_vote = pil_msa_mba_make_proxy_votes,
- .proxy_unvote = pil_msa_mba_remove_proxy_votes,
.verify_blob = pil_msa_mba_verify_blob,
.auth_and_reset = pil_msa_mba_auth,
};
diff --git a/arch/arm/mach-msm/pil-pronto.c b/arch/arm/mach-msm/pil-pronto.c
index 1085408..620ab5c 100644
--- a/arch/arm/mach-msm/pil-pronto.c
+++ b/arch/arm/mach-msm/pil-pronto.c
@@ -31,6 +31,7 @@
#include <mach/msm_smsm.h>
#include <mach/ramdump.h>
#include <mach/msm_smem.h>
+#include <mach/msm_bus_board.h>
#include "peripheral-loader.h"
#include "scm-pas.h"
@@ -83,9 +84,6 @@
bool restart_inprogress;
bool crash;
struct delayed_work cancel_vote_work;
- int irq;
- unsigned int err_fatal_irq;
- int force_stop_gpio;
struct ramdump_device *ramdump_dev;
};
@@ -308,7 +306,7 @@
static irqreturn_t wcnss_err_fatal_intr_handler(int irq, void *dev_id)
{
- struct pronto_data *drv = dev_id;
+ struct pronto_data *drv = subsys_to_drv(dev_id);
pr_err("Fatal error on the wcnss.\n");
@@ -326,16 +324,17 @@
static irqreturn_t wcnss_wdog_bite_irq_hdlr(int irq, void *dev_id)
{
- struct pronto_data *drv = dev_id;
+ struct pronto_data *drv = subsys_to_drv(dev_id);
drv->crash = true;
- disable_irq_nosync(drv->irq);
+ disable_irq_nosync(drv->subsys_desc.wdog_bite_irq);
if (drv->restart_inprogress) {
pr_err("Ignoring wcnss bite irq, restart in progress\n");
return IRQ_HANDLED;
}
+ wcnss_pronto_log_debug_regs();
drv->restart_inprogress = true;
restart_wcnss(drv);
@@ -379,7 +378,7 @@
return ret;
}
drv->restart_inprogress = false;
- enable_irq(drv->irq);
+ enable_irq(drv->subsys_desc.wdog_bite_irq);
schedule_delayed_work(&drv->cancel_vote_work, msecs_to_jiffies(5000));
return 0;
@@ -391,7 +390,7 @@
pr_err("wcnss crash shutdown %d\n", drv->crash);
if (!drv->crash)
- gpio_set_value(drv->force_stop_gpio, 1);
+ gpio_set_value(subsys->force_stop_gpio, 1);
}
static int wcnss_ramdump(int enable, const struct subsys_desc *subsys)
@@ -409,27 +408,14 @@
struct pronto_data *drv;
struct resource *res;
struct pil_desc *desc;
- int ret, err_fatal_gpio, irq;
+ int ret;
uint32_t regval;
- int clk_ready = of_get_named_gpio(pdev->dev.of_node,
- "qcom,gpio-proxy-unvote", 0);
- if (clk_ready < 0)
- return clk_ready;
-
- clk_ready = gpio_to_irq(clk_ready);
- if (clk_ready < 0)
- return clk_ready;
-
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
if (!drv)
return -ENOMEM;
platform_set_drvdata(pdev, drv);
- drv->irq = platform_get_irq(pdev, 0);
- if (drv->irq < 0)
- return drv->irq;
-
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pmu_base");
drv->base = devm_request_and_ioremap(&pdev->dev, res);
if (!drv->base)
@@ -451,27 +437,9 @@
if (ret)
return ret;
- err_fatal_gpio = of_get_named_gpio(pdev->dev.of_node,
- "qcom,gpio-err-fatal", 0);
- if (err_fatal_gpio < 0)
- return err_fatal_gpio;
-
- irq = gpio_to_irq(err_fatal_gpio);
- if (irq < 0)
- return irq;
-
- drv->err_fatal_irq = irq;
-
- drv->force_stop_gpio = of_get_named_gpio(pdev->dev.of_node,
- "qcom,gpio-force-stop", 0);
- if (drv->force_stop_gpio < 0)
- return drv->force_stop_gpio;
-
-
desc->dev = &pdev->dev;
desc->owner = THIS_MODULE;
desc->proxy_timeout = 10000;
- desc->proxy_unvote_irq = clk_ready;
if (pas_supported(PAS_WCNSS) > 0) {
desc->ops = &pil_pronto_ops_trusted;
@@ -503,6 +471,8 @@
if (IS_ERR(drv->cxo))
return PTR_ERR(drv->cxo);
+ scm_pas_init(MSM_BUS_MASTER_CRYPTO_CORE0);
+
ret = pil_desc_init(desc);
if (ret)
return ret;
@@ -516,17 +486,8 @@
drv->subsys_desc.crash_shutdown = crash_shutdown;
drv->subsys_desc.start = pronto_start;
drv->subsys_desc.stop = pronto_stop;
-
- ret = of_get_named_gpio(pdev->dev.of_node,
- "qcom,gpio-err-ready", 0);
- if (ret < 0)
- return ret;
-
- ret = gpio_to_irq(ret);
- if (ret < 0)
- return ret;
-
- drv->subsys_desc.err_ready_irq = ret;
+ drv->subsys_desc.err_fatal_handler = wcnss_err_fatal_intr_handler;
+ drv->subsys_desc.wdog_bite_handler = wcnss_wdog_bite_irq_hdlr;
INIT_DELAYED_WORK(&drv->cancel_vote_work, wcnss_post_bootup);
@@ -536,19 +497,6 @@
goto err_subsys;
}
- ret = devm_request_irq(&pdev->dev, drv->irq, wcnss_wdog_bite_irq_hdlr,
- IRQF_TRIGGER_HIGH, "wcnss_wdog", drv);
- if (ret < 0)
- goto err_irq;
-
- ret = devm_request_irq(&pdev->dev, drv->err_fatal_irq,
- wcnss_err_fatal_intr_handler,
- IRQF_TRIGGER_RISING, "pil-pronto", drv);
- if (ret < 0) {
- dev_err(&pdev->dev, "Unable to register SMP2P err fatal handler!\n");
- goto err_irq;
- }
-
drv->ramdump_dev = create_ramdump_device("pronto", &pdev->dev);
if (!drv->ramdump_dev) {
ret = -ENOMEM;
diff --git a/arch/arm/mach-msm/pil-q6v3.c b/arch/arm/mach-msm/pil-q6v3.c
index a369878..58d4301 100644
--- a/arch/arm/mach-msm/pil-q6v3.c
+++ b/arch/arm/mach-msm/pil-q6v3.c
@@ -24,6 +24,7 @@
#include <mach/subsystem_restart.h>
#include <mach/scm.h>
#include <mach/ramdump.h>
+#include <mach/msm_bus_board.h>
#include "peripheral-loader.h"
#include "scm-pas.h"
@@ -393,6 +394,8 @@
goto err_subsys;
}
+ scm_pas_init(MSM_BUS_MASTER_SPS);
+
ret = devm_request_irq(&pdev->dev, drv->irq, lpass_wdog_bite_irq,
IRQF_TRIGGER_RISING, "lpass_wdog", drv);
if (ret) {
diff --git a/arch/arm/mach-msm/pil-q6v4-lpass.c b/arch/arm/mach-msm/pil-q6v4-lpass.c
index 7acb599..6ec8430 100644
--- a/arch/arm/mach-msm/pil-q6v4-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v4-lpass.c
@@ -26,6 +26,7 @@
#include <mach/subsystem_notif.h>
#include <mach/ramdump.h>
#include <mach/msm_smem.h>
+#include <mach/msm_bus_board.h>
#include "smd_private.h"
#include "sysmon.h"
@@ -356,6 +357,8 @@
goto err_notif_riva;
}
+ scm_pas_init(MSM_BUS_MASTER_SPS);
+
drv->modem_notif_hdle = subsys_notif_register_notifier("modem", &mnb);
if (IS_ERR(drv->modem_notif_hdle)) {
ret = PTR_ERR(drv->modem_notif_hdle);
diff --git a/arch/arm/mach-msm/pil-q6v4-mss.c b/arch/arm/mach-msm/pil-q6v4-mss.c
index c4b6038..6ee5965 100644
--- a/arch/arm/mach-msm/pil-q6v4-mss.c
+++ b/arch/arm/mach-msm/pil-q6v4-mss.c
@@ -24,6 +24,7 @@
#include <mach/msm_smsm.h>
#include <mach/ramdump.h>
#include <mach/msm_smem.h>
+#include <mach/msm_bus_board.h>
#include "smd_private.h"
#include "peripheral-loader.h"
@@ -462,6 +463,8 @@
if (ret)
goto err_irq;
+ scm_pas_init(MSM_BUS_MASTER_SPS);
+
ret = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_RESET,
smsm_state_cb, drv);
if (ret)
diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
index 6cd6ffe..a9a6942 100644
--- a/arch/arm/mach-msm/pil-q6v5-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v5-lpass.c
@@ -30,6 +30,7 @@
#include <mach/scm.h>
#include <mach/ramdump.h>
#include <mach/msm_smem.h>
+#include <mach/msm_bus_board.h>
#include "peripheral-loader.h"
#include "pil-q6v5.h"
@@ -47,13 +48,10 @@
struct subsys_device *subsys;
struct subsys_desc subsys_desc;
void *ramdump_dev;
- int wdog_irq;
struct work_struct work;
void *wcnss_notif_hdle;
void *modem_notif_hdle;
int crash_shutdown;
- unsigned int err_fatal_irq;
- int force_stop_gpio;
};
#define subsys_to_drv(d) container_of(d, struct lpass_data, subsys_desc)
@@ -278,7 +276,7 @@
static irqreturn_t adsp_err_fatal_intr_handler (int irq, void *dev_id)
{
- struct lpass_data *drv = dev_id;
+ struct lpass_data *drv = subsys_to_drv(dev_id);
/* Ignore if we're the one that set the force stop bit in the outbound
* entry
@@ -338,7 +336,7 @@
/* The write needs to go through before the q6 is shutdown. */
mb();
pil_shutdown(&drv->q6->desc);
- disable_irq_nosync(drv->wdog_irq);
+ disable_irq_nosync(drv->subsys_desc.wdog_bite_irq);
pr_debug("ADSP is Down\n");
adsp_set_state("OFFLINE");
@@ -350,7 +348,7 @@
struct lpass_data *drv = subsys_to_lpass(subsys);
int ret = 0;
ret = pil_boot(&drv->q6->desc);
- enable_irq(drv->wdog_irq);
+ enable_irq(drv->subsys_desc.wdog_bite_irq);
pr_debug("ADSP is back online\n");
adsp_set_state("ONLINE");
@@ -372,15 +370,15 @@
struct lpass_data *drv = subsys_to_lpass(subsys);
drv->crash_shutdown = 1;
- gpio_set_value(drv->force_stop_gpio, 1);
+ gpio_set_value(subsys->force_stop_gpio, 1);
send_q6_nmi();
}
static irqreturn_t adsp_wdog_bite_irq(int irq, void *dev_id)
{
- struct lpass_data *drv = dev_id;
+ struct lpass_data *drv = subsys_to_drv(dev_id);
- disable_irq_nosync(drv->wdog_irq);
+ disable_irq_nosync(drv->subsys_desc.wdog_bite_irq);
schedule_work(&drv->work);
return IRQ_HANDLED;
@@ -405,34 +403,13 @@
struct q6v5_data *q6;
struct pil_desc *desc;
struct resource *res;
- int ret, gpio_clk_ready;
+ int ret;
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
if (!drv)
return -ENOMEM;
platform_set_drvdata(pdev, drv);
- drv->wdog_irq = platform_get_irq(pdev, 0);
- if (drv->wdog_irq < 0)
- return drv->wdog_irq;
-
- ret = gpio_to_irq(of_get_named_gpio(pdev->dev.of_node,
- "qcom,gpio-err-fatal", 0));
- if (ret < 0)
- return ret;
- drv->err_fatal_irq = ret;
-
- ret = gpio_to_irq(of_get_named_gpio(pdev->dev.of_node,
- "qcom,gpio-proxy-unvote", 0));
- if (ret < 0)
- return ret;
- gpio_clk_ready = ret;
-
- drv->force_stop_gpio = of_get_named_gpio(pdev->dev.of_node,
- "qcom,gpio-force-stop", 0);
- if (drv->force_stop_gpio < 0)
- return drv->force_stop_gpio;
-
q6 = pil_q6v5_init(pdev);
if (IS_ERR(q6))
return PTR_ERR(q6);
@@ -441,7 +418,6 @@
desc = &q6->desc;
desc->owner = THIS_MODULE;
desc->proxy_timeout = PROXY_TIMEOUT_MS;
- desc->proxy_unvote_irq = gpio_clk_ready;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "restart_reg");
q6->restart_reg = devm_request_and_ioremap(&pdev->dev, res);
@@ -472,6 +448,8 @@
dev_info(&pdev->dev, "using non-secure boot\n");
}
+ scm_pas_init(MSM_BUS_MASTER_CRYPTO_CORE0);
+
ret = pil_desc_init(desc);
if (ret)
return ret;
@@ -485,6 +463,8 @@
drv->subsys_desc.crash_shutdown = adsp_crash_shutdown;
drv->subsys_desc.start = lpass_start;
drv->subsys_desc.stop = lpass_stop;
+ drv->subsys_desc.err_fatal_handler = adsp_err_fatal_intr_handler;
+ drv->subsys_desc.wdog_bite_handler = adsp_wdog_bite_irq;
INIT_WORK(&drv->work, adsp_fatal_fn);
@@ -500,18 +480,6 @@
goto err_subsys;
}
- ret = devm_request_irq(&pdev->dev, drv->wdog_irq, adsp_wdog_bite_irq,
- IRQF_TRIGGER_RISING, dev_name(&pdev->dev), drv);
- if (ret)
- goto err_irq;
-
- ret = devm_request_irq(&pdev->dev, drv->err_fatal_irq,
- adsp_err_fatal_intr_handler,
- IRQF_TRIGGER_RISING,
- dev_name(&pdev->dev), drv);
- if (ret)
- goto err_irq;
-
drv->wcnss_notif_hdle = subsys_notif_register_notifier("wcnss", &wnb);
if (IS_ERR(drv->wcnss_notif_hdle)) {
ret = PTR_ERR(drv->wcnss_notif_hdle);
@@ -544,7 +512,6 @@
err_notif_modem:
subsys_notif_unregister_notifier(drv->wcnss_notif_hdle, &wnb);
err_notif_wcnss:
-err_irq:
subsys_unregister(drv->subsys);
err_subsys:
destroy_ramdump_device(drv->ramdump_dev);
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
index 3a21e39..c267541 100644
--- a/arch/arm/mach-msm/pil-q6v5-mss.c
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -24,8 +24,8 @@
#include <linux/of.h>
#include <linux/regulator/consumer.h>
#include <linux/interrupt.h>
-#include <linux/of_gpio.h>
#include <linux/dma-mapping.h>
+#include <linux/of_gpio.h>
#include <mach/subsystem_restart.h>
#include <mach/clk.h>
@@ -50,12 +50,8 @@
struct subsys_desc subsys_desc;
void *adsp_state_notifier;
void *ramdump_dev;
- void *smem_ramdump_dev;
bool crash_shutdown;
bool ignore_errors;
- int err_fatal_irq;
- unsigned int stop_ack_irq;
- int force_stop_gpio;
struct completion stop_ack;
};
@@ -66,9 +62,9 @@
u32 size;
char *smem_reason, reason[MAX_SSR_REASON_LEN];
- smem_reason = smem_get_entry(SMEM_SSR_REASON_MSS0, &size);
+ smem_reason = smem_get_entry_no_rlock(SMEM_SSR_REASON_MSS0, &size);
if (!smem_reason || !size) {
- pr_err("modem subsystem failure reason: (unknown, smem_get_entry failed).\n");
+ pr_err("modem subsystem failure reason: (unknown, smem_get_entry_no_rlock failed).\n");
return;
}
if (!smem_reason[0]) {
@@ -92,7 +88,7 @@
static irqreturn_t modem_err_fatal_intr_handler(int irq, void *dev_id)
{
- struct modem_data *drv = dev_id;
+ struct modem_data *drv = subsys_to_drv(dev_id);
/* Ignore if we're the one that set the force stop GPIO */
if (drv->crash_shutdown)
@@ -106,7 +102,7 @@
static irqreturn_t modem_stop_ack_intr_handler(int irq, void *dev_id)
{
- struct modem_data *drv = dev_id;
+ struct modem_data *drv = subsys_to_drv(dev_id);
pr_info("Received stop ack interrupt from modem\n");
complete(&drv->stop_ack);
return IRQ_HANDLED;
@@ -121,12 +117,12 @@
return 0;
if (!subsys_get_crash_status(drv->subsys)) {
- gpio_set_value(drv->force_stop_gpio, 1);
+ gpio_set_value(subsys->force_stop_gpio, 1);
ret = wait_for_completion_timeout(&drv->stop_ack,
msecs_to_jiffies(STOP_ACK_TIMEOUT_MS));
if (!ret)
pr_warn("Timed out on stop ack from modem.\n");
- gpio_set_value(drv->force_stop_gpio, 0);
+ gpio_set_value(subsys->force_stop_gpio, 0);
}
pil_shutdown(&drv->mba->desc);
@@ -146,7 +142,7 @@
* run concurrently with either the watchdog bite error handler or the
* SMSM callback, making it safe to unset the flag below.
*/
- init_completion(&drv->stop_ack);
+ INIT_COMPLETION(drv->stop_ack);
drv->ignore_errors = false;
ret = pil_boot(&drv->q6->desc);
if (ret)
@@ -162,15 +158,11 @@
struct modem_data *drv = subsys_to_drv(subsys);
drv->crash_shutdown = true;
if (!subsys_get_crash_status(drv->subsys)) {
- gpio_set_value(drv->force_stop_gpio, 1);
+ gpio_set_value(subsys->force_stop_gpio, 1);
mdelay(STOP_ACK_TIMEOUT_MS);
}
}
-static struct ramdump_segment smem_segments[] = {
- {0x0FA00000, 0x0FC00000 - 0x0FA00000},
-};
-
static int modem_ramdump(int enable, const struct subsys_desc *subsys)
{
struct modem_data *drv = subsys_to_drv(subsys);
@@ -184,19 +176,9 @@
return ret;
ret = pil_do_ramdump(&drv->mba->desc, drv->ramdump_dev);
- if (ret < 0) {
+ if (ret < 0)
pr_err("Unable to dump modem fw memory (rc = %d).\n", ret);
- goto out;
- }
- ret = do_elf_ramdump(drv->smem_ramdump_dev, smem_segments,
- ARRAY_SIZE(smem_segments));
- if (ret < 0) {
- pr_err("Unable to dump smem memory (rc = %d).\n", ret);
- goto out;
- }
-
-out:
pil_shutdown(&drv->q6->desc);
return ret;
}
@@ -215,9 +197,9 @@
.notifier_call = adsp_state_notifier_fn,
};
-static irqreturn_t modem_wdog_bite_irq(int irq, void *dev_id)
+static irqreturn_t modem_wdog_bite_intr_handler(int irq, void *dev_id)
{
- struct modem_data *drv = dev_id;
+ struct modem_data *drv = subsys_to_drv(dev_id);
if (drv->ignore_errors)
return IRQ_HANDLED;
pr_err("Watchdog bite received from modem software!\n");
@@ -234,7 +216,7 @@
if (desc->is_not_loadable)
return 0;
- init_completion(&drv->stop_ack);
+ INIT_COMPLETION(drv->stop_ack);
ret = pil_boot(&drv->q6->desc);
if (ret)
return ret;
@@ -258,11 +240,7 @@
static int __devinit pil_subsys_init(struct modem_data *drv,
struct platform_device *pdev)
{
- int irq, ret;
-
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
+ int ret;
drv->subsys_desc.name = "modem";
drv->subsys_desc.dev = &pdev->dev;
@@ -273,17 +251,9 @@
drv->subsys_desc.crash_shutdown = modem_crash_shutdown;
drv->subsys_desc.start = mss_start;
drv->subsys_desc.stop = mss_stop;
-
- ret = of_get_named_gpio(pdev->dev.of_node,
- "qcom,gpio-err-ready", 0);
- if (ret < 0)
- return ret;
-
- ret = gpio_to_irq(ret);
- if (ret < 0)
- return ret;
-
- drv->subsys_desc.err_ready_irq = ret;
+ drv->subsys_desc.err_fatal_handler = modem_err_fatal_intr_handler;
+ drv->subsys_desc.stop_ack_handler = modem_stop_ack_intr_handler;
+ drv->subsys_desc.wdog_bite_handler = modem_wdog_bite_intr_handler;
drv->subsys = subsys_register(&drv->subsys_desc);
if (IS_ERR(drv->subsys)) {
@@ -299,37 +269,6 @@
goto err_ramdump;
}
- drv->smem_ramdump_dev = create_ramdump_device("smem-modem", &pdev->dev);
- if (!drv->smem_ramdump_dev) {
- pr_err("%s: Unable to create an smem ramdump device.\n",
- __func__);
- ret = -ENOMEM;
- goto err_ramdump_smem;
- }
-
- ret = devm_request_irq(&pdev->dev, irq, modem_wdog_bite_irq,
- IRQF_TRIGGER_RISING, "modem_wdog", drv);
- if (ret < 0) {
- dev_err(&pdev->dev, "Unable to request watchdog IRQ.\n");
- goto err_irq;
- }
-
- ret = devm_request_irq(&pdev->dev, drv->err_fatal_irq,
- modem_err_fatal_intr_handler,
- IRQF_TRIGGER_RISING, "pil-mss", drv);
- if (ret < 0) {
- dev_err(&pdev->dev, "Unable to register SMP2P err fatal handler!\n");
- goto err_irq;
- }
-
- ret = devm_request_irq(&pdev->dev, drv->stop_ack_irq,
- modem_stop_ack_intr_handler,
- IRQF_TRIGGER_RISING, "pil-mss", drv);
- if (ret < 0) {
- dev_err(&pdev->dev, "Unable to register SMP2P stop ack handler!\n");
- goto err_irq;
- }
-
drv->adsp_state_notifier = subsys_notif_register_notifier("adsp",
&adsp_state_notifier_block);
if (IS_ERR(drv->adsp_state_notifier)) {
@@ -342,8 +281,6 @@
return 0;
err_irq:
- destroy_ramdump_device(drv->smem_ramdump_dev);
-err_ramdump_smem:
destroy_ramdump_device(drv->ramdump_dev);
err_ramdump:
subsys_unregister(drv->subsys);
@@ -361,18 +298,9 @@
struct property *prop;
int ret;
- int clk_ready = of_get_named_gpio(pdev->dev.of_node,
- "qcom,gpio-proxy-unvote", 0);
- if (clk_ready < 0)
- return clk_ready;
-
- clk_ready = gpio_to_irq(clk_ready);
- if (clk_ready < 0)
- return clk_ready;
-
mba = devm_kzalloc(&pdev->dev, sizeof(*mba), GFP_KERNEL);
- if (IS_ERR(mba))
- return PTR_ERR(mba);
+ if (!mba)
+ return -ENOMEM;
drv->mba = mba;
q6 = pil_q6v5_init(pdev);
@@ -385,7 +313,6 @@
q6_desc->ops = &pil_msa_pbl_ops;
q6_desc->owner = THIS_MODULE;
q6_desc->proxy_timeout = PROXY_TIMEOUT_MS;
- q6_desc->proxy_unvote_irq = clk_ready;
q6->self_auth = of_property_read_bool(pdev->dev.of_node,
"qcom,pil-self-auth");
@@ -454,8 +381,6 @@
mba_desc->dev = &pdev->dev;
mba_desc->ops = &pil_msa_mba_ops;
mba_desc->owner = THIS_MODULE;
- mba_desc->proxy_timeout = PROXY_TIMEOUT_MS;
- mba_desc->proxy_unvote_irq = clk_ready;
ret = pil_desc_init(mba_desc);
if (ret)
@@ -472,7 +397,7 @@
static int __devinit pil_mss_driver_probe(struct platform_device *pdev)
{
struct modem_data *drv;
- int ret, err_fatal_gpio, is_not_loadable, stop_ack_gpio;
+ int ret, is_not_loadable;
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
if (!drv)
@@ -488,32 +413,7 @@
if (ret)
return ret;
}
-
- /* Get the IRQ from the GPIO for registering inbound handler */
- err_fatal_gpio = of_get_named_gpio(pdev->dev.of_node,
- "qcom,gpio-err-fatal", 0);
- if (err_fatal_gpio < 0)
- return err_fatal_gpio;
-
- drv->err_fatal_irq = gpio_to_irq(err_fatal_gpio);
- if (drv->err_fatal_irq < 0)
- return drv->err_fatal_irq;
-
- stop_ack_gpio = of_get_named_gpio(pdev->dev.of_node,
- "qcom,gpio-stop-ack", 0);
- if (stop_ack_gpio < 0)
- return stop_ack_gpio;
-
- ret = gpio_to_irq(stop_ack_gpio);
- if (ret < 0)
- return ret;
- drv->stop_ack_irq = ret;
-
- /* Get the GPIO pin for writing the outbound bits: add more as needed */
- drv->force_stop_gpio = of_get_named_gpio(pdev->dev.of_node,
- "qcom,gpio-force-stop", 0);
- if (drv->force_stop_gpio < 0)
- return drv->force_stop_gpio;
+ init_completion(&drv->stop_ack);
return pil_subsys_init(drv, pdev);
}
@@ -525,7 +425,6 @@
subsys_notif_unregister_notifier(drv->adsp_state_notifier,
&adsp_state_notifier_block);
subsys_unregister(drv->subsys);
- destroy_ramdump_device(drv->smem_ramdump_dev);
destroy_ramdump_device(drv->ramdump_dev);
pil_desc_release(&drv->mba->desc);
pil_desc_release(&drv->q6->desc);
diff --git a/arch/arm/mach-msm/pil-riva.c b/arch/arm/mach-msm/pil-riva.c
index bf7438b..9a364b7 100644
--- a/arch/arm/mach-msm/pil-riva.c
+++ b/arch/arm/mach-msm/pil-riva.c
@@ -25,6 +25,7 @@
#include <mach/subsystem_restart.h>
#include <mach/ramdump.h>
#include <mach/msm_smem.h>
+#include <mach/msm_bus_board.h>
#include "peripheral-loader.h"
#include "scm-pas.h"
@@ -534,6 +535,8 @@
goto err_subsys;
}
+ scm_pas_init(MSM_BUS_MASTER_SPS);
+
ret = devm_request_irq(&pdev->dev, drv->irq, riva_wdog_bite_irq_hdlr,
IRQF_TRIGGER_RISING, "riva_wdog", drv);
if (ret < 0)
diff --git a/arch/arm/mach-msm/pil-tzapps.c b/arch/arm/mach-msm/pil-tzapps.c
index 1410117..d9f5700 100644
--- a/arch/arm/mach-msm/pil-tzapps.c
+++ b/arch/arm/mach-msm/pil-tzapps.c
@@ -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
@@ -16,6 +16,7 @@
#include <linux/err.h>
#include <mach/subsystem_restart.h>
+#include <mach/msm_bus_board.h>
#include "peripheral-loader.h"
#include "scm-pas.h"
@@ -97,6 +98,9 @@
pil_desc_release(desc);
return PTR_ERR(drv->subsys);
}
+
+ scm_pas_init(MSM_BUS_MASTER_SPS);
+
return 0;
}
diff --git a/arch/arm/mach-msm/pil-venus.c b/arch/arm/mach-msm/pil-venus.c
index 4e9e54b..a7ebbf7 100644
--- a/arch/arm/mach-msm/pil-venus.c
+++ b/arch/arm/mach-msm/pil-venus.c
@@ -605,6 +605,8 @@
if (!drv->ramdump_dev)
return -ENOMEM;
+ scm_pas_init(MSM_BUS_MASTER_CRYPTO_CORE0);
+
rc = pil_desc_init(desc);
if (rc)
goto err_ramdump;
diff --git a/arch/arm/mach-msm/pil-vidc.c b/arch/arm/mach-msm/pil-vidc.c
index 629907f..3dbddae 100644
--- a/arch/arm/mach-msm/pil-vidc.c
+++ b/arch/arm/mach-msm/pil-vidc.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
@@ -17,6 +17,7 @@
#include <linux/clk.h>
#include <mach/subsystem_restart.h>
+#include <mach/msm_bus_board.h>
#include "peripheral-loader.h"
#include "scm-pas.h"
@@ -122,6 +123,9 @@
pil_desc_release(desc);
return PTR_ERR(drv->subsys);
}
+
+ scm_pas_init(MSM_BUS_MASTER_SPS);
+
return 0;
}
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 146dc0b..da5e67a 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -31,7 +31,6 @@
#include <linux/of_platform.h>
#include <linux/regulator/krait-regulator.h>
#include <linux/cpu.h>
-#include <linux/clk.h>
#include <mach/msm_iomap.h>
#include <mach/socinfo.h>
#include <mach/system.h>
@@ -41,6 +40,7 @@
#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>
@@ -134,7 +134,6 @@
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 struct clk *pnoc_clk;
static int msm_pm_get_pc_mode(struct device_node *node,
const char *key, uint32_t *pc_mode_val)
@@ -1134,17 +1133,15 @@
pm_sleep_ops = *ops;
}
-int msm_suspend_prepare(void)
+static int msm_suspend_prepare(void)
{
- if (pnoc_clk != NULL)
- clk_disable_unprepare(pnoc_clk);
+ msm_mpm_suspend_prepare();
return 0;
}
-void msm_suspend_wake(void)
+static void msm_suspend_wake(void)
{
- if (pnoc_clk != NULL)
- clk_prepare_enable(pnoc_clk);
+ msm_mpm_suspend_wake();
}
static const struct platform_suspend_ops msm_pm_ops = {
@@ -1285,14 +1282,90 @@
},
};
+#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;
-static int __init msm_pm_setup_saved_state(void)
+ 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;
- pmd_t *pmd;
- unsigned long pmdval;
unsigned long exit_phys;
- dma_addr_t temp_phys;
+ unsigned long end;
+ int ret;
/* Page table for cores to come back up safely. */
pc_pgd = pgd_alloc(&init_mm);
@@ -1301,12 +1374,33 @@
exit_phys = virt_to_phys(msm_pm_collapse_exit);
- pmd = pmd_offset(pud_offset(pc_pgd + pgd_index(exit_phys),exit_phys),
- exit_phys);
- pmdval = (exit_phys & PGDIR_MASK) |
- PMD_TYPE_SECT | PMD_SECT_AP_WRITE;
- pmd[0] = __pmd(pmdval);
- pmd[1] = __pmd(pmdval + (1 << (PGDIR_SHIFT - 1)));
+ /*
+ * 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(),
@@ -1322,19 +1416,6 @@
*/
msm_saved_state_phys = (unsigned long)temp_phys;
-
- /* It is remotely possible that the code in msm_pm_collapse_exit()
- * which turns on the MMU with this mapping is in the
- * next even-numbered megabyte beyond the
- * start of msm_pm_collapse_exit().
- * Map this megabyte in as well.
- */
- pmd[2] = __pmd(pmdval + (2 << (PGDIR_SHIFT - 1)));
- flush_pmd_entry(pmd);
- 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;
}
arch_initcall(msm_pm_setup_saved_state);
@@ -1631,18 +1712,6 @@
return rc;
}
- pnoc_clk = clk_get_sys("pm_8x60", "bus_clk");
-
- if (IS_ERR(pnoc_clk))
- pnoc_clk = NULL;
- else {
- clk_set_rate(pnoc_clk, 19200000);
- rc = clk_prepare_enable(pnoc_clk);
-
- if (rc)
- pr_err("%s: PNOC clock enable failed\n", __func__);
- }
-
return platform_driver_register(&msm_pm_8x60_driver);
}
device_initcall(msm_pm_8x60_init);
diff --git a/arch/arm/mach-msm/pm-stats.c b/arch/arm/mach-msm/pm-stats.c
index 1bd9b46..ac4ed25 100644
--- a/arch/arm/mach-msm/pm-stats.c
+++ b/arch/arm/mach-msm/pm-stats.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
@@ -17,6 +17,7 @@
#include <linux/spinlock.h>
#include <linux/uaccess.h>
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include "pm.h"
@@ -83,46 +84,19 @@
}
/*
- * Helper function of snprintf where buf is auto-incremented, size is auto-
- * decremented, and there is no return value.
- *
- * NOTE: buf and size must be l-values (e.g. variables)
- */
-#define SNPRINTF(buf, size, format, ...) \
- do { \
- if (size > 0) { \
- int ret; \
- ret = snprintf(buf, size, format, ## __VA_ARGS__); \
- if (ret > size) { \
- buf += size; \
- size = 0; \
- } else { \
- buf += ret; \
- size -= ret; \
- } \
- } \
- } while (0)
-
-/*
* Write out the power management statistics.
*/
-static int msm_pm_read_proc
- (char *page, char **start, off_t off, int count, int *eof, void *data)
+
+static int msm_pm_stats_show(struct seq_file *m, void *v)
{
- unsigned int cpu = off / MSM_PM_STAT_COUNT;
- int id = off % MSM_PM_STAT_COUNT;
- char *p = page;
+ int cpu;
+ int bucket_count = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
+ int bucket_shift = CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT;
- if (count < 1024) {
- *start = (char *) 0;
- *eof = 0;
- return 0;
- }
-
- if (cpu < num_possible_cpus()) {
+ for_each_possible_cpu(cpu) {
unsigned long flags;
struct msm_pm_time_stats *stats;
- int i;
+ int i, id;
int64_t bucket_time;
int64_t s;
uint32_t ns;
@@ -130,59 +104,52 @@
spin_lock_irqsave(&msm_pm_stats_lock, flags);
stats = per_cpu(msm_pm_stats, cpu).stats;
- /* Skip the disabled ones */
- if (!stats[id].enabled) {
- *p = '\0';
- p++;
- goto again;
- }
+ for (id = 0; id < MSM_PM_STAT_COUNT; id++) {
+ /* Skip the disabled ones */
+ if (!stats[id].enabled)
+ continue;
- s = stats[id].total_time;
- ns = do_div(s, NSEC_PER_SEC);
- SNPRINTF(p, count,
- "[cpu %u] %s:\n"
- " count: %7d\n"
- " total_time: %lld.%09u\n",
- cpu, stats[id].name,
- stats[id].count,
- s, ns);
-
- bucket_time = stats[id].first_bucket_time;
- for (i = 0; i < CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1; i++) {
- s = bucket_time;
+ s = stats[id].total_time;
ns = do_div(s, NSEC_PER_SEC);
- SNPRINTF(p, count,
- " <%6lld.%09u: %7d (%lld-%lld)\n",
+ seq_printf(m,
+ "[cpu %u] %s:\n"
+ " count: %7d\n"
+ " total_time: %lld.%09u\n",
+ cpu, stats[id].name,
+ stats[id].count,
+ s, ns);
+
+ 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]);
-
- bucket_time <<= CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT;
}
- SNPRINTF(p, count, " >=%6lld.%09u: %7d (%lld-%lld)\n",
- s, ns, stats[id].bucket[i],
- stats[id].min_time[i],
- stats[id].max_time[i]);
-
-again:
- *start = (char *) 1;
- *eof = (off + 1 >= MSM_PM_STAT_COUNT * num_possible_cpus());
-
spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
}
- return p - page;
+ return 0;
}
-#undef SNPRINTF
#define MSM_PM_STATS_RESET "reset"
-
/*
* Reset the power management statistics values.
*/
-static int msm_pm_write_proc(struct file *file, const char __user *buffer,
- unsigned long count, void *data)
+static ssize_t msm_pm_write_proc(struct file *file, const char __user *buffer,
+ size_t count, loff_t *off)
{
char buf[sizeof(MSM_PM_STATS_RESET)];
int ret;
@@ -231,6 +198,19 @@
}
#undef MSM_PM_STATS_RESET
+static int msm_pm_stats_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, msm_pm_stats_show, NULL);
+}
+
+static const struct file_operations msm_pm_stats_fops = {
+ .open = msm_pm_stats_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = msm_pm_write_proc,
+};
+
void msm_pm_add_stats(enum msm_pm_time_stats_id *enable_stats, int size)
{
unsigned int cpu;
@@ -296,11 +276,6 @@
}
- d_entry = create_proc_entry("msm_pm_stats",
- S_IRUGO | S_IWUSR | S_IWGRP, NULL);
- if (d_entry) {
- d_entry->read_proc = msm_pm_read_proc;
- d_entry->write_proc = msm_pm_write_proc;
- d_entry->data = NULL;
- }
+ 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/qdsp6v2/audio_utils_aio.c b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
index 64ee880..8baac01 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
@@ -250,7 +250,11 @@
return;
spin_lock_irqsave(&audio->dsp_lock, flags);
- BUG_ON(list_empty(&audio->out_queue));
+ if (list_empty(&audio->out_queue)) {
+ pr_warning("%s: ingore unexpected event from dsp\n", __func__);
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
+ return;
+ }
used_buf = list_first_entry(&audio->out_queue,
struct audio_aio_buffer_node, list);
if (token == used_buf->token) {
diff --git a/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c b/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c
index 5303009..0c71659 100644
--- a/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c
+++ b/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c
@@ -48,6 +48,12 @@
{
int rc = 0;
+ if ((msm_audio_ion_data.smmu_enabled == true) &&
+ (msm_audio_ion_data.group == NULL)) {
+ pr_debug("%s:probe is not done, deferred\n", __func__);
+ return -EPROBE_DEFER;
+ }
+
*client = msm_audio_ion_client_create(UINT_MAX, name);
if (IS_ERR_OR_NULL((void *)(*client))) {
pr_err("%s: ION create client for AUDIO failed\n", __func__);
@@ -96,8 +102,10 @@
err_ion_handle:
ion_free(*client, *handle);
+ *handle = NULL;
err_ion_client:
msm_audio_ion_client_destroy(*client);
+ *client = NULL;
err:
return -EINVAL;
}
@@ -143,8 +151,12 @@
goto err_ion_handle;
}
- if (bufsz != 0)
- memset((void *)*vaddr, 0, bufsz);
+ *vaddr = ion_map_kernel(*client, *handle);
+ if (IS_ERR_OR_NULL((void *)*vaddr)) {
+ pr_err("%s: ION memory mapping for AUDIO failed\n", __func__);
+ goto err_ion_handle;
+ }
+ pr_debug("%s: mapped address = %p, size=%d\n", __func__, *vaddr, bufsz);
return 0;
diff --git a/arch/arm/mach-msm/restart.c b/arch/arm/mach-msm/restart.c
index d95f979..c85f7a1 100644
--- a/arch/arm/mach-msm/restart.c
+++ b/arch/arm/mach-msm/restart.c
@@ -47,6 +47,10 @@
#define RESTART_REASON_ADDR 0x65C
#define DLOAD_MODE_ADDR 0x0
+#define EMERGENCY_DLOAD_MODE_ADDR 0xFE0
+#define EMERGENCY_DLOAD_MAGIC1 0x322A4F99
+#define EMERGENCY_DLOAD_MAGIC2 0xC67E4350
+#define EMERGENCY_DLOAD_MAGIC3 0x77777777
#define SCM_IO_DISABLE_PMIC_ARBITER 1
@@ -65,13 +69,14 @@
#ifdef CONFIG_MSM_DLOAD_MODE
static int in_panic;
static void *dload_mode_addr;
+static bool dload_mode_enabled;
+static void *emergency_dload_mode_addr;
/* Download mode master kill-switch */
static int dload_set(const char *val, struct kernel_param *kp);
static int download_mode = 1;
module_param_call(download_mode, dload_set, param_get_int,
&download_mode, 0644);
-
static int panic_prep_restart(struct notifier_block *this,
unsigned long event, void *ptr)
{
@@ -90,6 +95,27 @@
__raw_writel(on ? 0xCE14091A : 0,
dload_mode_addr + sizeof(unsigned int));
mb();
+ dload_mode_enabled = on;
+ }
+}
+
+static bool get_dload_mode(void)
+{
+ return dload_mode_enabled;
+}
+
+static void enable_emergency_dload_mode(void)
+{
+ if (emergency_dload_mode_addr) {
+ __raw_writel(EMERGENCY_DLOAD_MAGIC1,
+ emergency_dload_mode_addr);
+ __raw_writel(EMERGENCY_DLOAD_MAGIC2,
+ emergency_dload_mode_addr +
+ sizeof(unsigned int));
+ __raw_writel(EMERGENCY_DLOAD_MAGIC3,
+ emergency_dload_mode_addr +
+ (2 * sizeof(unsigned int)));
+ mb();
}
}
@@ -115,6 +141,16 @@
}
#else
#define set_dload_mode(x) do {} while (0)
+
+static void enable_emergency_dload_mode(void)
+{
+ printk(KERN_ERR "dload mode is not enabled on target\n");
+}
+
+static bool get_dload_mode(void)
+{
+ return false;
+}
#endif
void msm_set_restart_mode(int mode)
@@ -130,7 +166,7 @@
set_dload_mode(0);
#endif
pm8xxx_reset_pwr_off(0);
- qpnp_pon_system_pwr_off(0);
+ qpnp_pon_system_pwr_off(PON_POWER_OFF_SHUTDOWN);
if (lower_pshold) {
if (!use_restart_v2())
@@ -211,7 +247,12 @@
#endif
pm8xxx_reset_pwr_off(1);
- qpnp_pon_system_pwr_off(1);
+
+ /* Hard reset the PMIC unless memory contents must be maintained. */
+ if (get_dload_mode() || (cmd != NULL && cmd[0] != '\0'))
+ qpnp_pon_system_pwr_off(PON_POWER_OFF_WARM_RESET);
+ else
+ qpnp_pon_system_pwr_off(PON_POWER_OFF_HARD_RESET);
if (cmd != NULL) {
if (!strncmp(cmd, "bootloader", 10)) {
@@ -222,6 +263,8 @@
unsigned long code;
code = simple_strtoul(cmd + 4, NULL, 16) & 0xff;
__raw_writel(0x6f656d00 | code, restart_reason);
+ } else if (!strncmp(cmd, "edl", 3)) {
+ enable_emergency_dload_mode();
} else {
__raw_writel(0x77665501, restart_reason);
}
@@ -289,6 +332,8 @@
#ifdef CONFIG_MSM_DLOAD_MODE
atomic_notifier_chain_register(&panic_notifier_list, &panic_blk);
dload_mode_addr = MSM_IMEM_BASE + DLOAD_MODE_ADDR;
+ emergency_dload_mode_addr = MSM_IMEM_BASE +
+ EMERGENCY_DLOAD_MODE_ADDR;
set_dload_mode(download_mode);
#endif
msm_tmr0_base = msm_timer_get_timer0_base();
diff --git a/arch/arm/mach-msm/scm-pas.c b/arch/arm/mach-msm/scm-pas.c
index b244c6f..57acdc4 100644
--- a/arch/arm/mach-msm/scm-pas.c
+++ b/arch/arm/mach-msm/scm-pas.c
@@ -255,9 +255,14 @@
}
EXPORT_SYMBOL(pas_supported);
-static int __init scm_pas_init(void)
+void scm_pas_init(enum msm_bus_fabric_master_type id)
{
int i, rate;
+ static int is_inited;
+
+ if (is_inited)
+ return;
+
for (i = 0; i < NUM_CLKS; i++) {
scm_clocks[i] = clk_get_sys("scm", scm_clock_names[i]);
if (IS_ERR(scm_clocks[i]))
@@ -268,20 +273,14 @@
rate = clk_round_rate(scm_clocks[CORE_CLK_SRC], 1);
clk_set_rate(scm_clocks[CORE_CLK_SRC], rate);
- if (soc_class_is_msm8974() || cpu_is_msm8226() || cpu_is_msm8610()) {
- scm_pas_bw_tbl[0].vectors[0].src = MSM_BUS_MASTER_CRYPTO_CORE0;
- scm_pas_bw_tbl[1].vectors[0].src = MSM_BUS_MASTER_CRYPTO_CORE0;
- } else {
- if (!IS_ERR(scm_clocks[BUS_CLK]))
- clk_set_rate(scm_clocks[BUS_CLK], 64000000);
- else
- pr_warn("unable to get bus clock\n");
- }
+ scm_pas_bw_tbl[0].vectors[0].src = id;
+ scm_pas_bw_tbl[1].vectors[0].src = id;
+
+ clk_set_rate(scm_clocks[BUS_CLK], 64000000);
scm_perf_client = msm_bus_scale_register_client(&scm_pas_bus_pdata);
if (!scm_perf_client)
pr_warn("unable to register bus client\n");
- return 0;
+ is_inited = 1;
}
-module_init(scm_pas_init);
diff --git a/arch/arm/mach-msm/scm-pas.h b/arch/arm/mach-msm/scm-pas.h
index f13757c..48bc558 100644
--- a/arch/arm/mach-msm/scm-pas.h
+++ b/arch/arm/mach-msm/scm-pas.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
@@ -9,6 +9,9 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
+
+#include <mach/msm_bus_board.h>
+
#ifndef __MSM_SCM_PAS_H
#define __MSM_SCM_PAS_H
@@ -31,6 +34,7 @@
extern int pas_auth_and_reset(enum pas_id id);
extern int pas_shutdown(enum pas_id id);
extern int pas_supported(enum pas_id id);
+extern void scm_pas_init(enum msm_bus_fabric_master_type id);
#else
static inline int pas_init_image(enum pas_id id, const u8 *metadata,
size_t size)
@@ -53,6 +57,9 @@
{
return 0;
}
+static inline void scm_pas_init(enum msm_bus_fabric_master_type id)
+{
+}
#endif
#endif
diff --git a/arch/arm/mach-msm/smcmod.c b/arch/arm/mach-msm/smcmod.c
index fc7ffd5..683fb32 100644
--- a/arch/arm/mach-msm/smcmod.c
+++ b/arch/arm/mach-msm/smcmod.c
@@ -28,8 +28,8 @@
#include <linux/printk.h>
#include <linux/msm_ion.h>
#include <asm/smcmod.h>
-#include <asm/cacheflush.h>
#include <mach/scm.h>
+#include <mach/socinfo.h>
static DEFINE_MUTEX(ioctl_lock);
@@ -93,41 +93,6 @@
uint8_t verify;
} __packed;
-static void smcmod_inv_range(unsigned long start, unsigned long end)
-{
- uint32_t cacheline_size;
- uint32_t ctr;
-
- /* get cache line size */
- asm volatile("mrc p15, 0, %0, c0, c0, 1" : "=r" (ctr));
- cacheline_size = 4 << ((ctr >> 16) & 0xf);
-
- /* invalidate the range */
- start = round_down(start, cacheline_size);
- end = round_up(end, cacheline_size);
- while (start < end) {
- asm ("mcr p15, 0, %0, c7, c6, 1" : : "r" (start)
- : "memory");
- start += cacheline_size;
- }
- mb();
- isb();
-}
-
-/*
- * FIXME:
- * scm_call will no longer flush the entire cache before calling into the secure
- * world. Until individual buffers in this driver can be flushed, flush the
- * entire cache before calling into scm_call.
- */
-int smcmod_scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, size_t cmd_len,
- void *resp_buf, size_t resp_len)
-{
- flush_cache_all();
- outer_flush_all();
- return scm_call(svc_id, cmd_id, cmd_buf, cmd_len, resp_buf, resp_len);
-}
-
static int smcmod_ion_fd_to_phys(int32_t fd, struct ion_client *ion_clientp,
struct ion_handle **ion_handlep, uint32_t *phys_addrp, size_t *sizep)
{
@@ -249,10 +214,18 @@
}
}
+ /* No need to flush the cache lines for the command buffer here,
+ * because the buffer will be flushed by scm_call.
+ */
+
/* call scm function to switch to secure world */
- reqp->return_val = smcmod_scm_call(reqp->service_id, reqp->command_id,
+ reqp->return_val = scm_call(reqp->service_id, reqp->command_id,
cmd_vaddrp, reqp->cmd_len, resp_vaddrp, reqp->resp_len);
+ /* The cache lines for the response buffer have already been
+ * invalidated by scm_call before returning.
+ */
+
buf_cleanup:
/* if the client and handle(s) are valid, free them */
if (!IS_ERR_OR_NULL(ion_clientp)) {
@@ -370,45 +343,36 @@
goto buf_cleanup;
}
+ /* Only the scm_req structure will be flushed by scm_call,
+ * so we must flush the cache for the input ion buffers here.
+ */
+ msm_ion_do_cache_op(ion_clientp, ion_key_handlep, NULL,
+ scm_req.key_size, ION_IOC_CLEAN_CACHES);
+ msm_ion_do_cache_op(ion_clientp, ion_iv_handlep, NULL,
+ scm_req.init_vector_size, ION_IOC_CLEAN_CACHES);
+
+ /* For decrypt, cipher text is input, otherwise it's plain text. */
+ if (reqp->operation)
+ msm_ion_do_cache_op(ion_clientp, ion_cipher_handlep, NULL,
+ scm_req.cipher_text_size, ION_IOC_CLEAN_CACHES);
+ else
+ msm_ion_do_cache_op(ion_clientp, ion_plain_handlep, NULL,
+ scm_req.plain_text_size, ION_IOC_CLEAN_CACHES);
+
/* call scm function to switch to secure world */
- reqp->return_val = smcmod_scm_call(SMCMOD_SVC_CRYPTO,
+ reqp->return_val = scm_call(SMCMOD_SVC_CRYPTO,
SMCMOD_CRYPTO_CMD_CIPHER, &scm_req,
sizeof(scm_req), NULL, 0);
+ /* Invalidate the output buffer, since it's not done by scm_call */
+
/* for decrypt, plain text is the output, otherwise it's cipher text */
- if (reqp->operation) {
- void *vaddrp = NULL;
-
- /* map the plain text region to get the virtual address */
- vaddrp = ion_map_kernel(ion_clientp, ion_plain_handlep);
- if (IS_ERR_OR_NULL(vaddrp)) {
- ret = -EINVAL;
- goto buf_cleanup;
- }
-
- /* invalidate the range */
- smcmod_inv_range((unsigned long)vaddrp,
- (unsigned long)(vaddrp + scm_req.plain_text_size));
-
- /* unmap the mapped area */
- ion_unmap_kernel(ion_clientp, ion_plain_handlep);
- } else {
- void *vaddrp = NULL;
-
- /* map the cipher text region to get the virtual address */
- vaddrp = ion_map_kernel(ion_clientp, ion_cipher_handlep);
- if (IS_ERR_OR_NULL(vaddrp)) {
- ret = -EINVAL;
- goto buf_cleanup;
- }
-
- /* invalidate the range */
- smcmod_inv_range((unsigned long)vaddrp,
- (unsigned long)(vaddrp + scm_req.cipher_text_size));
-
- /* unmap the mapped area */
- ion_unmap_kernel(ion_clientp, ion_cipher_handlep);
- }
+ if (reqp->operation)
+ msm_ion_do_cache_op(ion_clientp, ion_plain_handlep, NULL,
+ scm_req.plain_text_size, ION_IOC_INV_CACHES);
+ else
+ msm_ion_do_cache_op(ion_clientp, ion_cipher_handlep, NULL,
+ scm_req.cipher_text_size, ION_IOC_INV_CACHES);
buf_cleanup:
/* if the client and handles are valid, free them */
@@ -439,7 +403,6 @@
struct ion_handle *ion_input_handlep = NULL;
struct ion_handle *ion_output_handlep = NULL;
size_t size = 0;
- void *vaddrp = NULL;
if (IS_ERR_OR_NULL(reqp))
return -EINVAL;
@@ -507,34 +470,31 @@
goto buf_cleanup;
}
+ /* Only the scm_req structure will be flushed by scm_call,
+ * so we must flush the cache for the input ion buffers here.
+ */
+ msm_ion_do_cache_op(ion_clientp, ion_key_handlep, NULL,
+ scm_req.key_size, ION_IOC_CLEAN_CACHES);
+ msm_ion_do_cache_op(ion_clientp, ion_input_handlep, NULL,
+ scm_req.input_size, ION_IOC_CLEAN_CACHES);
+
/* call scm function to switch to secure world */
if (reqp->fixed_block)
- reqp->return_val = smcmod_scm_call(SMCMOD_SVC_CRYPTO,
+ reqp->return_val = scm_call(SMCMOD_SVC_CRYPTO,
SMCMOD_CRYPTO_CMD_MSG_DIGEST_FIXED,
&scm_req,
sizeof(scm_req),
NULL, 0);
else
- reqp->return_val = smcmod_scm_call(SMCMOD_SVC_CRYPTO,
+ reqp->return_val = scm_call(SMCMOD_SVC_CRYPTO,
SMCMOD_CRYPTO_CMD_MSG_DIGEST,
&scm_req,
sizeof(scm_req),
NULL, 0);
-
- /* map the output region to get the virtual address */
- vaddrp = ion_map_kernel(ion_clientp, ion_output_handlep);
- if (IS_ERR_OR_NULL(vaddrp)) {
- ret = -EINVAL;
- goto buf_cleanup;
- }
-
- /* invalidate the range */
- smcmod_inv_range((unsigned long)vaddrp,
- (unsigned long)(vaddrp + scm_req.output_size));
-
- /* unmap the mapped area */
- ion_unmap_kernel(ion_clientp, ion_output_handlep);
+ /* Invalidate the output buffer, since it's not done by scm_call */
+ msm_ion_do_cache_op(ion_clientp, ion_output_handlep, NULL,
+ scm_req.output_size, ION_IOC_INV_CACHES);
buf_cleanup:
/* if the client and handles are valid, free them */
@@ -554,6 +514,110 @@
return ret;
}
+static int smcmod_send_dec_cmd(struct smcmod_decrypt_req *reqp)
+{
+ struct ion_client *ion_clientp;
+ struct ion_handle *ion_handlep = NULL;
+ int ion_fd;
+ int ret;
+ u32 pa;
+ size_t size;
+ struct {
+ u32 args[4];
+ } req;
+ struct {
+ u32 args[3];
+ } rsp;
+
+ ion_clientp = msm_ion_client_create(UINT_MAX, "smcmod");
+ if (IS_ERR_OR_NULL(ion_clientp))
+ return PTR_ERR(ion_clientp);
+
+ switch (reqp->operation) {
+ case SMCMOD_DECRYPT_REQ_OP_METADATA: {
+ ion_fd = reqp->request.metadata.ion_fd;
+ ret = smcmod_ion_fd_to_phys(ion_fd, ion_clientp,
+ &ion_handlep, &pa, &size);
+ if (ret)
+ goto error;
+
+ req.args[0] = reqp->request.metadata.len;
+ req.args[1] = pa;
+ break;
+ }
+ case SMCMOD_DECRYPT_REQ_OP_IMG_FRAG: {
+ ion_fd = reqp->request.img_frag.ion_fd;
+ ret = smcmod_ion_fd_to_phys(ion_fd, ion_clientp,
+ &ion_handlep, &pa, &size);
+ if (ret)
+ goto error;
+
+ req.args[0] = reqp->request.img_frag.ctx_id;
+ req.args[1] = reqp->request.img_frag.last_frag;
+ req.args[2] = reqp->request.img_frag.frag_len;
+ req.args[3] = pa + reqp->request.img_frag.offset;
+ break;
+ }
+ default:
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /*
+ * scm_call does cache maintenance over request and response buffers.
+ * The userspace must flush/invalidate ion input/output buffers itself.
+ */
+
+ ret = scm_call(reqp->service_id, reqp->command_id,
+ &req, sizeof(req), &rsp, sizeof(rsp));
+ if (ret)
+ goto error;
+
+ switch (reqp->operation) {
+ case SMCMOD_DECRYPT_REQ_OP_METADATA:
+ reqp->response.metadata.status = rsp.args[0];
+ reqp->response.metadata.ctx_id = rsp.args[1];
+ reqp->response.metadata.end_offset = rsp.args[2] - pa;
+ break;
+ case SMCMOD_DECRYPT_REQ_OP_IMG_FRAG: {
+ reqp->response.img_frag.status = rsp.args[0];
+ break;
+ }
+ default:
+ break;
+ }
+
+error:
+ if (!IS_ERR_OR_NULL(ion_clientp)) {
+ if (!IS_ERR_OR_NULL(ion_handlep))
+ ion_free(ion_clientp, ion_handlep);
+ ion_client_destroy(ion_clientp);
+ }
+ return ret;
+}
+
+static int smcmod_ioctl_check(unsigned cmd)
+{
+ switch (cmd) {
+ case SMCMOD_IOCTL_SEND_REG_CMD:
+ case SMCMOD_IOCTL_SEND_BUF_CMD:
+ case SMCMOD_IOCTL_SEND_CIPHER_CMD:
+ case SMCMOD_IOCTL_SEND_MSG_DIGEST_CMD:
+ case SMCMOD_IOCTL_GET_VERSION:
+ if (!cpu_is_fsm9xxx())
+ return -EINVAL;
+ break;
+ case SMCMOD_IOCTL_SEND_DECRYPT_CMD:
+ if (!cpu_is_msm8226())
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static long smcmod_ioctl(struct file *file, unsigned cmd, unsigned long arg)
{
void __user *argp = (void __user *)arg;
@@ -572,6 +636,10 @@
*/
mutex_lock(&ioctl_lock);
+ ret = smcmod_ioctl_check(cmd);
+ if (ret)
+ goto cleanup;
+
switch (cmd) {
case SMCMOD_IOCTL_SEND_REG_CMD:
{
@@ -693,6 +761,26 @@
}
break;
+ case SMCMOD_IOCTL_SEND_DECRYPT_CMD:
+ {
+ struct smcmod_decrypt_req req;
+
+ if (copy_from_user((void *)&req, argp, sizeof(req))) {
+ ret = -EFAULT;
+ goto cleanup;
+ }
+
+ ret = smcmod_send_dec_cmd(&req);
+ if (ret < 0)
+ goto cleanup;
+
+ if (copy_to_user(argp, (void *)&req, sizeof(req))) {
+ ret = -EFAULT;
+ goto cleanup;
+ }
+ }
+ break;
+
default:
ret = -EINVAL;
}
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index c97ba68..e148868 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -724,6 +724,7 @@
[SMD_MODEM_RPM] = {SMD_MODEM, SMD_RPM},
[SMD_QDSP_RPM] = {SMD_Q6, SMD_RPM},
[SMD_WCNSS_RPM] = {SMD_WCNSS, SMD_RPM},
+ [SMD_TZ_RPM] = {SMD_TZ, SMD_RPM},
};
struct restart_notifier_block {
@@ -3382,8 +3383,9 @@
parent_pdev = to_platform_device(pdev->dev.parent);
key = "irq-reg-base";
- /* existance check verified in smem driver */
r = platform_get_resource_byname(parent_pdev, IORESOURCE_MEM, key);
+ if (!r)
+ goto missing_key;
irq_out_size = resource_size(r);
irq_out_base = ioremap_nocache(r->start, irq_out_size);
if (!irq_out_base) {
@@ -3477,8 +3479,9 @@
parent_pdev = to_platform_device(pdev->dev.parent);
key = "irq-reg-base";
- /* existance check verified in smem driver */
r = platform_get_resource_byname(parent_pdev, IORESOURCE_MEM, key);
+ if (!r)
+ goto missing_key;
irq_out_size = resource_size(r);
irq_out_base = ioremap_nocache(r->start, irq_out_size);
if (!irq_out_base) {
diff --git a/arch/arm/mach-msm/smd_pkt.c b/arch/arm/mach-msm/smd_pkt.c
index 20a6165..1c44f9a 100644
--- a/arch/arm/mach-msm/smd_pkt.c
+++ b/arch/arm/mach-msm/smd_pkt.c
@@ -41,7 +41,7 @@
#ifdef CONFIG_ARCH_FSM9XXX
#define NUM_SMD_PKT_PORTS 4
#else
-#define NUM_SMD_PKT_PORTS 28
+#define NUM_SMD_PKT_PORTS 31
#endif
#define PDRIVER_NAME_MAX_SIZE 32
@@ -711,6 +711,9 @@
"smdcntl5",
"smdcntl6",
"smdcntl7",
+ "smdcntl9",
+ "smdcntl10",
+ "smdcntl11",
"smd22",
"smdcnt_rev0",
"smdcnt_rev1",
@@ -742,6 +745,9 @@
"DATA12_CNTL",
"DATA13_CNTL",
"DATA14_CNTL",
+ "DATA15_CNTL",
+ "DATA16_CNTL",
+ "DATA17_CNTL",
"DATA22",
"DATA23_CNTL",
"DATA24_CNTL",
@@ -783,6 +789,9 @@
SMD_APPS_MODEM,
SMD_APPS_MODEM,
SMD_APPS_MODEM,
+ SMD_APPS_MODEM,
+ SMD_APPS_MODEM,
+ SMD_APPS_MODEM,
SMD_APPS_DSPS,
SMD_APPS_QDSP,
SMD_APPS_MODEM,
@@ -1028,6 +1037,13 @@
int i;
int r;
+ if (ARRAY_SIZE(smd_ch_name) != NUM_SMD_PKT_PORTS ||
+ ARRAY_SIZE(smd_ch_edge) != NUM_SMD_PKT_PORTS ||
+ ARRAY_SIZE(smd_pkt_dev_name) != NUM_SMD_PKT_PORTS) {
+ pr_err("%s: mismatch in number of ports\n", __func__);
+ BUG();
+ }
+
r = alloc_chrdev_region(&smd_pkt_number,
0,
NUM_SMD_PKT_PORTS,
diff --git a/arch/arm/mach-msm/smd_private.c b/arch/arm/mach-msm/smd_private.c
index 94192d3..a7ef87f 100644
--- a/arch/arm/mach-msm/smd_private.c
+++ b/arch/arm/mach-msm/smd_private.c
@@ -267,7 +267,8 @@
int is_word_access_ch(unsigned ch_type)
{
if (ch_type == SMD_APPS_RPM || ch_type == SMD_MODEM_RPM ||
- ch_type == SMD_QDSP_RPM || ch_type == SMD_WCNSS_RPM)
+ ch_type == SMD_QDSP_RPM || ch_type == SMD_WCNSS_RPM ||
+ ch_type == SMD_TZ_RPM)
return 1;
else
return 0;
diff --git a/arch/arm/mach-msm/smem_log.c b/arch/arm/mach-msm/smem_log.c
index 6f20e24..35a6e15 100644
--- a/arch/arm/mach-msm/smem_log.c
+++ b/arch/arm/mach-msm/smem_log.c
@@ -159,7 +159,10 @@
{ SMEM_LOG_ERROR_EVENT_BASE, "ERROR" },
{ SMEM_LOG_DCVS_EVENT_BASE, "DCVS" },
{ SMEM_LOG_SLEEP_EVENT_BASE, "SLEEP" },
- { SMEM_LOG_RPC_ROUTER_EVENT_BASE, "ROUTER" },
+ { SMEM_LOG_RPC_ROUTER_EVENT_BASE, "RPCROUTER" },
+ { SMEM_LOG_QMI_CCI_EVENT_BASE, "QCCI" },
+ { SMEM_LOG_QMI_CSI_EVENT_BASE, "QCSI" },
+ { SMEM_LOG_IPC_ROUTER_EVENT_BASE, "IPCROUTER" },
};
struct sym event_syms[] = {
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 41509f7..6cb04c7 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -71,6 +71,21 @@
};
enum {
+ PLATFORM_SUBTYPE_QRD = 0x0,
+ PLATFORM_SUBTYPE_SKUAA = 0x1,
+ PLATFORM_SUBTYPE_SKUF = 0x2,
+ PLATFORM_SUBTYPE_SKUAB = 0x3,
+ PLATFORM_SUBTYPE_QRD_INVALID,
+};
+
+const char *qrd_hw_platform_subtype[] = {
+ [PLATFORM_SUBTYPE_QRD] = "QRD",
+ [PLATFORM_SUBTYPE_SKUAA] = "SKUAA",
+ [PLATFORM_SUBTYPE_SKUF] = "SKUF",
+ [PLATFORM_SUBTYPE_SKUAB] = "SKUAB",
+};
+
+enum {
PLATFORM_SUBTYPE_UNKNOWN = 0x0,
PLATFORM_SUBTYPE_CHARM = 0x1,
PLATFORM_SUBTYPE_STRANGE = 0x2,
@@ -647,9 +662,18 @@
}
hw_subtype = socinfo_get_platform_subtype();
+ if (HW_PLATFORM_QRD == socinfo_get_platform_type()) {
+ if (hw_subtype >= PLATFORM_SUBTYPE_QRD_INVALID) {
+ pr_err("%s: Invalid hardware platform sub type for qrd found\n",
+ __func__);
+ hw_subtype = PLATFORM_SUBTYPE_QRD;
+ }
+ return snprintf(buf, PAGE_SIZE, "%-.32s\n",
+ qrd_hw_platform_subtype[hw_subtype]);
+ }
if (hw_subtype >= PLATFORM_SUBTYPE_INVALID) {
pr_err("%s: Invalid hardware platform sub type found\n",
- __func__);
+ __func__);
hw_subtype = PLATFORM_SUBTYPE_UNKNOWN;
}
return snprintf(buf, PAGE_SIZE, "%-.32s\n",
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index 7b1a4c3..01e0985 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -32,6 +32,7 @@
#include <linux/debugfs.h>
#include <linux/miscdevice.h>
#include <linux/interrupt.h>
+#include <linux/of_gpio.h>
#include <asm/current.h>
@@ -502,8 +503,10 @@
if (ret)
return ret;
- if (subsys->desc->is_not_loadable)
+ if (subsys->desc->is_not_loadable) {
+ subsys_set_state(subsys, SUBSYS_ONLINE);
return 0;
+ }
ret = wait_for_err_ready(subsys);
if (ret)
@@ -989,6 +992,129 @@
misc_deregister(&subsys_dev->misc_dev);
}
+static int __get_gpio(struct subsys_desc *desc, const char *prop,
+ int *gpio)
+{
+ struct device_node *dnode = desc->dev->of_node;
+ int ret = -ENOENT;
+
+ if (of_find_property(dnode, prop, NULL)) {
+ *gpio = of_get_named_gpio(dnode, prop, 0);
+ ret = *gpio < 0 ? *gpio : 0;
+ }
+
+ return ret;
+}
+
+static int __get_irq(struct subsys_desc *desc, const char *prop,
+ unsigned int *irq)
+{
+ int ret, gpio, irql;
+
+ ret = __get_gpio(desc, prop, &gpio);
+ if (ret)
+ return ret;
+
+ irql = gpio_to_irq(gpio);
+
+ if (irql == -ENOENT)
+ irql = -ENXIO;
+
+ if (irql < 0) {
+ pr_err("[%s]: Error getting IRQ \"%s\"\n", desc->name,
+ prop);
+ return irql;
+ } else {
+ *irq = irql;
+ }
+
+ return 0;
+}
+
+static int subsys_parse_devicetree(struct subsys_desc *desc)
+{
+ int ret;
+ struct platform_device *pdev = container_of(desc->dev,
+ struct platform_device, dev);
+
+ ret = __get_irq(desc, "qcom,gpio-err-fatal", &desc->err_fatal_irq);
+ if (ret && ret != -ENOENT)
+ return ret;
+
+ ret = __get_irq(desc, "qcom,gpio-err-ready", &desc->err_ready_irq);
+ if (ret && ret != -ENOENT)
+ return ret;
+
+ ret = __get_irq(desc, "qcom,gpio-stop-ack", &desc->stop_ack_irq);
+ if (ret && ret != -ENOENT)
+ return ret;
+
+ ret = __get_gpio(desc, "qcom,gpio-force-stop", &desc->force_stop_gpio);
+ if (ret && ret != -ENOENT)
+ return ret;
+
+ desc->wdog_bite_irq = platform_get_irq(pdev, 0);
+ if (desc->wdog_bite_irq < 0)
+ return desc->wdog_bite_irq;
+
+ return 0;
+}
+
+static int subsys_setup_irqs(struct subsys_device *subsys)
+{
+ struct subsys_desc *desc = subsys->desc;
+ int ret;
+
+ if (desc->err_fatal_irq && desc->err_fatal_handler) {
+ ret = devm_request_irq(desc->dev, desc->err_fatal_irq,
+ desc->err_fatal_handler,
+ IRQF_TRIGGER_RISING, desc->name, desc);
+ if (ret < 0) {
+ dev_err(desc->dev, "[%s]: Unable to register error fatal IRQ handler!: %d\n",
+ desc->name, ret);
+ return ret;
+ }
+ }
+
+ if (desc->stop_ack_irq && desc->stop_ack_handler) {
+ ret = devm_request_irq(desc->dev, desc->stop_ack_irq,
+ desc->stop_ack_handler,
+ IRQF_TRIGGER_RISING, desc->name, desc);
+ if (ret < 0) {
+ dev_err(desc->dev, "[%s]: Unable to register stop ack handler!: %d\n",
+ desc->name, ret);
+ return ret;
+ }
+ }
+
+ if (desc->wdog_bite_irq && desc->wdog_bite_handler) {
+ ret = devm_request_irq(desc->dev, desc->wdog_bite_irq,
+ desc->wdog_bite_handler,
+ IRQF_TRIGGER_RISING, desc->name, desc);
+ if (ret < 0) {
+ dev_err(desc->dev, "[%s]: Unable to register wdog bite handler!: %d\n",
+ desc->name, ret);
+ return ret;
+ }
+ }
+
+ if (desc->err_ready_irq) {
+ ret = devm_request_irq(desc->dev,
+ desc->err_ready_irq,
+ subsys_err_ready_intr_handler,
+ IRQF_TRIGGER_RISING,
+ "error_ready_interrupt", subsys);
+ if (ret < 0) {
+ dev_err(desc->dev,
+ "[%s]: Unable to register err ready handler\n",
+ desc->name);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
struct subsys_device *subsys_register(struct subsys_desc *desc)
{
struct subsys_device *subsys;
@@ -1006,6 +1132,9 @@
subsys->notify = subsys_notif_add_subsys(desc->name);
subsys->restart_order = update_restart_order(subsys);
+ ret = subsys_parse_devicetree(desc);
+ if (ret)
+ goto err_dtree;
snprintf(subsys->wlname, sizeof(subsys->wlname), "ssr(%s)", desc->name);
wake_lock_init(&subsys->wake_lock, WAKE_LOCK_SUSPEND, subsys->wlname);
@@ -1037,19 +1166,9 @@
goto err_register;
}
- if (subsys->desc->err_ready_irq) {
- ret = devm_request_irq(&subsys->dev,
- subsys->desc->err_ready_irq,
- subsys_err_ready_intr_handler,
- IRQF_TRIGGER_RISING,
- "error_ready_interrupt", subsys);
- if (ret < 0) {
- dev_err(&subsys->dev,
- "[%s]: Unable to register err ready handler\n",
- subsys->desc->name);
- goto err_misc_device;
- }
- }
+ ret = subsys_setup_irqs(subsys);
+ if (ret < 0)
+ goto err_misc_device;
return subsys;
@@ -1062,6 +1181,7 @@
ida_simple_remove(&subsys_ida, subsys->id);
err_ida:
wake_lock_destroy(&subsys->wake_lock);
+err_dtree:
kfree(subsys);
return ERR_PTR(ret);
}
diff --git a/arch/arm/mach-msm/test_qmi_client.c b/arch/arm/mach-msm/test_qmi_client.c
index d070e37..b701be8 100644
--- a/arch/arm/mach-msm/test_qmi_client.c
+++ b/arch/arm/mach-msm/test_qmi_client.c
@@ -61,6 +61,25 @@
/* Variable to hold the test result */
static int test_res;
+static unsigned int callback_count;
+static void test_async_resp_cb(struct qmi_handle *handle,
+ unsigned int msg_id, void *msg,
+ void *resp_cb_data, int stat)
+{
+ callback_count++;
+ if (stat == 0)
+ D("%s invoked %d time(s): [RESP_LEN] = %d, [RESP_VALID] = %d",
+ __func__, callback_count,
+ ((struct test_data_resp_msg_v01 *)msg)->data_len,
+ ((struct test_data_resp_msg_v01 *)msg)->data_valid);
+ else if (stat < 0)
+ pr_err("%s: Request Failed [MSG_ID]: %d, [ERR_ID]: %d, [Callback_count]: %d",
+ __func__, msg_id, stat, callback_count);
+
+ kfree(msg);
+ kfree(resp_cb_data);
+}
+
static int test_qmi_ping_pong_send_sync_msg(void)
{
struct test_ping_req_msg_v01 req;
@@ -138,12 +157,68 @@
return rc;
}
+static int test_qmi_data_send_async_msg(unsigned int data_len)
+{
+ struct test_data_req_msg_v01 *req;
+ struct test_data_resp_msg_v01 *resp;
+ struct msg_desc req_desc, *resp_desc;
+ int rc, i;
+
+ req = kzalloc(sizeof(struct test_data_req_msg_v01), GFP_KERNEL);
+ if (!req) {
+ pr_err("%s: Data req msg alloc failed\n", __func__);
+ return -ENOMEM;
+ }
+
+ resp = kzalloc(sizeof(struct test_data_resp_msg_v01), GFP_KERNEL);
+ if (!resp) {
+ pr_err("%s: Data resp msg alloc failed\n", __func__);
+ kfree(req);
+ return -ENOMEM;
+ }
+
+ resp_desc = kzalloc(sizeof(struct msg_desc), GFP_KERNEL);
+ if (!resp_desc) {
+ pr_err("%s: Resp_desc msg alloc failed\n", __func__);
+ kfree(req);
+ kfree(resp);
+ return -ENOMEM;
+ }
+
+ req->data_len = data_len;
+ for (i = 0; i < data_len; i = i + sizeof(int))
+ memcpy(req->data + i, (uint8_t *)&i, sizeof(int));
+ req->client_name_valid = 0;
+
+ req_desc.max_msg_len = TEST_DATA_REQ_MAX_MSG_LEN_V01;
+ req_desc.msg_id = TEST_DATA_REQ_MSG_ID_V01;
+ req_desc.ei_array = test_data_req_msg_v01_ei;
+
+ resp_desc->max_msg_len = TEST_DATA_REQ_MAX_MSG_LEN_V01;
+ resp_desc->msg_id = TEST_DATA_REQ_MSG_ID_V01;
+ resp_desc->ei_array = test_data_resp_msg_v01_ei;
+
+ rc = qmi_send_req_nowait(test_clnt, &req_desc, req, sizeof(*req),
+ resp_desc, resp, sizeof(*resp),
+ test_async_resp_cb, (void *)resp_desc);
+ if (rc < 0) {
+ pr_err("%s: send req failed\n", __func__);
+ kfree(resp);
+ kfree(resp_desc);
+ }
+ kfree(req);
+ return rc;
+}
+
static void test_clnt_recv_msg(struct work_struct *work)
{
int rc;
- rc = qmi_recv_msg(test_clnt);
- if (rc < 0)
+ do {
+ D("%s: Notified about a Receive Event", __func__);
+ } while ((rc = qmi_recv_msg(test_clnt)) == 0);
+
+ if (rc != -ENOMSG)
pr_err("%s: Error receiving message\n", __func__);
}
@@ -280,6 +355,32 @@
} while (test_clnt_reset);
}
}
+ } else if (!strncmp(cmd, "data_async", sizeof(cmd))) {
+ int i;
+ callback_count = 0;
+ for (i = 0; i < test_rep_cnt; i++) {
+ test_res = test_qmi_data_send_async_msg(test_data_sz);
+ if (test_res == -ENETRESET || test_clnt_reset) {
+ --i;
+ do {
+ msleep(50);
+ } while (test_clnt_reset);
+ } else if (test_res < 0) {
+ --i;
+ pr_err("%s: Error sending txn, aborting now",
+ __func__);
+ break;
+ }
+ }
+ while (callback_count < i) {
+ if (test_clnt_reset) {
+ pr_err("%s: Service Exited", __func__);
+ break;
+ }
+ msleep(50);
+ }
+ D("%s complete\n", __func__);
+ callback_count = 0;
} else {
test_res = -EINVAL;
}
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index e65b5ba..c2efc34 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -360,9 +360,13 @@
PTE_SET_FN(nx, pte_mknexec)
SET_MEMORY_FN(ro, pte_set_ro)
+EXPORT_SYMBOL(set_memory_ro);
SET_MEMORY_FN(rw, pte_set_rw)
+EXPORT_SYMBOL(set_memory_rw);
SET_MEMORY_FN(x, pte_set_x)
+EXPORT_SYMBOL(set_memory_x);
SET_MEMORY_FN(nx, pte_set_nx)
+EXPORT_SYMBOL(set_memory_nx);
/*
* Adjust the PMD section entries according to the CPU in use.
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index e62af21..1d12b07 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -21,6 +21,7 @@
#include <linux/uaccess.h>
#include <linux/user.h>
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <asm/cp15.h>
#include <asm/cputype.h>
@@ -656,23 +657,23 @@
}
#ifdef CONFIG_PROC_FS
-static int proc_read_status(char *page, char **start, off_t off, int count,
- int *eof, void *data)
+static int vfp_bounce_show(struct seq_file *m, void *v)
{
- char *p = page;
- int len;
-
- p += snprintf(p, PAGE_SIZE, "%llu\n", atomic64_read(&vfp_bounce_count));
-
- len = (p - page) - off;
- if (len < 0)
- len = 0;
-
- *eof = (len <= count) ? 1 : 0;
- *start = page + off;
-
- return len;
+ seq_printf(m, "%llu\n", atomic64_read(&vfp_bounce_count));
+ return 0;
}
+
+static int vfp_bounce_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, vfp_bounce_show, NULL);
+}
+
+static const struct file_operations vfp_bounce_fops = {
+ .open = vfp_bounce_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
#endif
/*
@@ -755,11 +756,9 @@
}
#ifdef CONFIG_PROC_FS
- procfs_entry = create_proc_entry("cpu/vfp_bounce", S_IRUGO, NULL);
-
- if (procfs_entry)
- procfs_entry->read_proc = proc_read_status;
- else
+ procfs_entry = proc_create("cpu/vfp_bounce", S_IRUGO, NULL,
+ &vfp_bounce_fops);
+ if (!procfs_entry)
pr_err("Failed to create procfs node for VFP bounce reporting\n");
#endif
diff --git a/block/blk-core.c b/block/blk-core.c
index 153240e..40d9b35 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -30,6 +30,7 @@
#include <linux/list_sort.h>
#include <linux/delay.h>
#include <linux/ratelimit.h>
+#include <linux/pm_runtime.h>
#define CREATE_TRACE_POINTS
#include <trace/events/block.h>
@@ -1195,6 +1196,16 @@
}
EXPORT_SYMBOL_GPL(part_round_stats);
+#ifdef CONFIG_PM_RUNTIME
+static void blk_pm_put_request(struct request *rq)
+{
+ if (rq->q->dev && !(rq->cmd_flags & REQ_PM) && !--rq->q->nr_pending)
+ pm_runtime_mark_last_busy(rq->q->dev);
+}
+#else
+static inline void blk_pm_put_request(struct request *rq) {}
+#endif
+
/*
* queue lock must be held
*/
@@ -1205,6 +1216,8 @@
if (unlikely(--req->ref_count))
return;
+ blk_pm_put_request(req);
+
elv_completed_request(q, req);
/* this is a bio leak */
@@ -1981,6 +1994,28 @@
}
}
+#ifdef CONFIG_PM_RUNTIME
+/*
+ * Don't process normal requests when queue is suspended
+ * or in the process of suspending/resuming
+ */
+static struct request *blk_pm_peek_request(struct request_queue *q,
+ struct request *rq)
+{
+ if (q->dev && (q->rpm_status == RPM_SUSPENDED ||
+ (q->rpm_status != RPM_ACTIVE && !(rq->cmd_flags & REQ_PM))))
+ return NULL;
+ else
+ return rq;
+}
+#else
+static inline struct request *blk_pm_peek_request(struct request_queue *q,
+ struct request *rq)
+{
+ return rq;
+}
+#endif
+
/**
* blk_peek_request - peek at the top of a request queue
* @q: request queue to peek at
@@ -2003,6 +2038,11 @@
int ret;
while ((rq = __elv_next_request(q)) != NULL) {
+
+ rq = blk_pm_peek_request(q, rq);
+ if (!rq)
+ break;
+
if (!(rq->cmd_flags & REQ_STARTED)) {
/*
* This is the first time the device driver
@@ -2018,10 +2058,8 @@
* not be passed by new incoming requests
*/
rq->cmd_flags |= REQ_STARTED;
- if (rq->cmd_flags & REQ_URGENT) {
- WARN_ON(q->dispatched_urgent);
+ if (rq->cmd_flags & REQ_URGENT)
q->dispatched_urgent = true;
- }
trace_block_rq_issue(q, rq);
}
@@ -2979,6 +3017,149 @@
}
EXPORT_SYMBOL(blk_finish_plug);
+#ifdef CONFIG_PM_RUNTIME
+/**
+ * blk_pm_runtime_init - Block layer runtime PM initialization routine
+ * @q: the queue of the device
+ * @dev: the device the queue belongs to
+ *
+ * Description:
+ * Initialize runtime-PM-related fields for @q and start auto suspend for
+ * @dev. Drivers that want to take advantage of request-based runtime PM
+ * should call this function after @dev has been initialized, and its
+ * request queue @q has been allocated, and runtime PM for it can not happen
+ * yet(either due to disabled/forbidden or its usage_count > 0). In most
+ * cases, driver should call this function before any I/O has taken place.
+ *
+ * This function takes care of setting up using auto suspend for the device,
+ * the autosuspend delay is set to -1 to make runtime suspend impossible
+ * until an updated value is either set by user or by driver. Drivers do
+ * not need to touch other autosuspend settings.
+ *
+ * The block layer runtime PM is request based, so only works for drivers
+ * that use request as their IO unit instead of those directly use bio's.
+ */
+void blk_pm_runtime_init(struct request_queue *q, struct device *dev)
+{
+ q->dev = dev;
+ q->rpm_status = RPM_ACTIVE;
+ pm_runtime_set_autosuspend_delay(q->dev, -1);
+ pm_runtime_use_autosuspend(q->dev);
+}
+EXPORT_SYMBOL(blk_pm_runtime_init);
+
+/**
+ * blk_pre_runtime_suspend - Pre runtime suspend check
+ * @q: the queue of the device
+ *
+ * Description:
+ * This function will check if runtime suspend is allowed for the device
+ * by examining if there are any requests pending in the queue. If there
+ * are requests pending, the device can not be runtime suspended; otherwise,
+ * the queue's status will be updated to SUSPENDING and the driver can
+ * proceed to suspend the device.
+ *
+ * For the not allowed case, we mark last busy for the device so that
+ * runtime PM core will try to autosuspend it some time later.
+ *
+ * This function should be called near the start of the device's
+ * runtime_suspend callback.
+ *
+ * Return:
+ * 0 - OK to runtime suspend the device
+ * -EBUSY - Device should not be runtime suspended
+ */
+int blk_pre_runtime_suspend(struct request_queue *q)
+{
+ int ret = 0;
+
+ spin_lock_irq(q->queue_lock);
+ if (q->nr_pending) {
+ ret = -EBUSY;
+ pm_runtime_mark_last_busy(q->dev);
+ } else {
+ q->rpm_status = RPM_SUSPENDING;
+ }
+ spin_unlock_irq(q->queue_lock);
+ return ret;
+}
+EXPORT_SYMBOL(blk_pre_runtime_suspend);
+
+/**
+ * blk_post_runtime_suspend - Post runtime suspend processing
+ * @q: the queue of the device
+ * @err: return value of the device's runtime_suspend function
+ *
+ * Description:
+ * Update the queue's runtime status according to the return value of the
+ * device's runtime suspend function and mark last busy for the device so
+ * that PM core will try to auto suspend the device at a later time.
+ *
+ * This function should be called near the end of the device's
+ * runtime_suspend callback.
+ */
+void blk_post_runtime_suspend(struct request_queue *q, int err)
+{
+ spin_lock_irq(q->queue_lock);
+ if (!err) {
+ q->rpm_status = RPM_SUSPENDED;
+ } else {
+ q->rpm_status = RPM_ACTIVE;
+ pm_runtime_mark_last_busy(q->dev);
+ }
+ spin_unlock_irq(q->queue_lock);
+}
+EXPORT_SYMBOL(blk_post_runtime_suspend);
+
+/**
+ * blk_pre_runtime_resume - Pre runtime resume processing
+ * @q: the queue of the device
+ *
+ * Description:
+ * Update the queue's runtime status to RESUMING in preparation for the
+ * runtime resume of the device.
+ *
+ * This function should be called near the start of the device's
+ * runtime_resume callback.
+ */
+void blk_pre_runtime_resume(struct request_queue *q)
+{
+ spin_lock_irq(q->queue_lock);
+ q->rpm_status = RPM_RESUMING;
+ spin_unlock_irq(q->queue_lock);
+}
+EXPORT_SYMBOL(blk_pre_runtime_resume);
+
+/**
+ * blk_post_runtime_resume - Post runtime resume processing
+ * @q: the queue of the device
+ * @err: return value of the device's runtime_resume function
+ *
+ * Description:
+ * Update the queue's runtime status according to the return value of the
+ * device's runtime_resume function. If it is successfully resumed, process
+ * the requests that are queued into the device's queue when it is resuming
+ * and then mark last busy and initiate autosuspend for it.
+ *
+ * This function should be called near the end of the device's
+ * runtime_resume callback.
+ */
+void blk_post_runtime_resume(struct request_queue *q, int err)
+{
+ spin_lock_irq(q->queue_lock);
+ if (!err) {
+ q->rpm_status = RPM_ACTIVE;
+ __blk_run_queue(q);
+ pm_runtime_mark_last_busy(q->dev);
+ pm_request_autosuspend(q->dev);
+ } else {
+ q->rpm_status = RPM_SUSPENDED;
+ }
+ spin_unlock_irq(q->queue_lock);
+}
+EXPORT_SYMBOL(blk_post_runtime_resume);
+#endif
+
int __init blk_dev_init(void)
{
BUILD_BUG_ON(__REQ_NR_BITS > 8 *
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index 32629e2..b4711cb 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -239,6 +239,9 @@
unsigned long workload_expires;
struct cfq_group *serving_group;
+ unsigned int nr_urgent_pending;
+ unsigned int nr_urgent_in_flight;
+
/*
* Each priority tree is sorted by next_request position. These
* trees are used when determining if two or more queues are
@@ -2091,6 +2094,14 @@
(RQ_CFQG(rq))->dispatched++;
elv_dispatch_sort(q, rq);
+ if (rq->cmd_flags & REQ_URGENT) {
+ if (!cfqd->nr_urgent_pending)
+ WARN_ON(1);
+ else
+ cfqd->nr_urgent_pending--;
+ cfqd->nr_urgent_in_flight++;
+ }
+
cfqd->rq_in_flight[cfq_cfqq_sync(cfqq)]++;
cfqq->nr_sectors += blk_rq_sectors(rq);
cfq_blkiocg_update_dispatch_stats(&cfqq->cfqg->blkg, blk_rq_bytes(rq),
@@ -3194,6 +3205,69 @@
}
}
+/*
+ * Called when a request (rq) is reinserted (to cfqq). Check if there's
+ * something we should do about it
+ */
+static void
+cfq_rq_requeued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
+ struct request *rq)
+{
+ struct cfq_io_cq *cic = RQ_CIC(rq);
+
+ cfqd->rq_queued++;
+ if (rq->cmd_flags & REQ_PRIO)
+ cfqq->prio_pending++;
+
+ cfqq->dispatched--;
+ (RQ_CFQG(rq))->dispatched--;
+
+ cfqd->rq_in_flight[cfq_cfqq_sync(cfqq)]--;
+
+ cfq_update_io_thinktime(cfqd, cfqq, cic);
+ cfq_update_io_seektime(cfqd, cfqq, rq);
+ cfq_update_idle_window(cfqd, cfqq, cic);
+
+ cfqq->last_request_pos = blk_rq_pos(rq) + blk_rq_sectors(rq);
+
+ if (cfqq == cfqd->active_queue) {
+ if (cfq_cfqq_wait_request(cfqq)) {
+ if (blk_rq_bytes(rq) > PAGE_CACHE_SIZE ||
+ cfqd->busy_queues > 1) {
+ cfq_del_timer(cfqd, cfqq);
+ cfq_clear_cfqq_wait_request(cfqq);
+ } else {
+ cfq_blkiocg_update_idle_time_stats(
+ &cfqq->cfqg->blkg);
+ cfq_mark_cfqq_must_dispatch(cfqq);
+ }
+ }
+ } else if (cfq_should_preempt(cfqd, cfqq, rq)) {
+ cfq_preempt_queue(cfqd, cfqq);
+ }
+}
+
+static int cfq_reinsert_request(struct request_queue *q, struct request *rq)
+{
+ struct cfq_data *cfqd = q->elevator->elevator_data;
+ struct cfq_queue *cfqq = RQ_CFQQ(rq);
+
+ if (!cfqq || cfqq->cfqd != cfqd)
+ return -EIO;
+
+ cfq_log_cfqq(cfqd, cfqq, "re-insert_request");
+ list_add(&rq->queuelist, &cfqq->fifo);
+ cfq_add_rq_rb(rq);
+
+ cfq_rq_requeued(cfqd, cfqq, rq);
+ if (rq->cmd_flags & REQ_URGENT) {
+ if (cfqd->nr_urgent_in_flight)
+ cfqd->nr_urgent_in_flight--;
+ cfqd->nr_urgent_pending++;
+ }
+ return 0;
+}
+
static void cfq_insert_request(struct request_queue *q, struct request *rq)
{
struct cfq_data *cfqd = q->elevator->elevator_data;
@@ -3208,7 +3282,45 @@
cfq_blkiocg_update_io_add_stats(&(RQ_CFQG(rq))->blkg,
&cfqd->serving_group->blkg, rq_data_dir(rq),
rq_is_sync(rq));
+
cfq_rq_enqueued(cfqd, cfqq, rq);
+
+ if (rq->cmd_flags & REQ_URGENT) {
+ WARN_ON(1);
+ blk_dump_rq_flags(rq, "");
+ rq->cmd_flags &= ~REQ_URGENT;
+ }
+
+ /* Request is considered URGENT if:
+ * 1. The queue being served is of a lower IO priority then the new
+ * request
+ * OR:
+ * 2. The workload being performed is ASYNC
+ * Only READ requests may be considered as URGENT
+ */
+ if ((cfqd->active_queue &&
+ cfqq->ioprio_class < cfqd->active_queue->ioprio_class) ||
+ (cfqd->serving_type == ASYNC_WORKLOAD &&
+ rq_data_dir(rq) == READ)) {
+ rq->cmd_flags |= REQ_URGENT;
+ cfqd->nr_urgent_pending++;
+ }
+}
+
+
+/**
+ * cfq_urgent_pending() - Return TRUE if there is an urgent
+ * request on scheduler
+ * @q: requests queue
+ */
+static bool cfq_urgent_pending(struct request_queue *q)
+{
+ struct cfq_data *cfqd = q->elevator->elevator_data;
+
+ if (cfqd->nr_urgent_pending && !cfqd->nr_urgent_in_flight)
+ return true;
+
+ return false;
}
/*
@@ -3292,6 +3404,14 @@
const int sync = rq_is_sync(rq);
unsigned long now;
+ if (rq->cmd_flags & REQ_URGENT) {
+ if (!cfqd->nr_urgent_in_flight)
+ WARN_ON(1);
+ else
+ cfqd->nr_urgent_in_flight--;
+ rq->cmd_flags &= ~REQ_URGENT;
+ }
+
now = jiffies;
cfq_log_cfqq(cfqd, cfqq, "complete rqnoidle %d",
!!(rq->cmd_flags & REQ_NOIDLE));
@@ -3859,6 +3979,8 @@
.elevator_bio_merged_fn = cfq_bio_merged,
.elevator_dispatch_fn = cfq_dispatch_requests,
.elevator_add_req_fn = cfq_insert_request,
+ .elevator_reinsert_req_fn = cfq_reinsert_request,
+ .elevator_is_urgent_fn = cfq_urgent_pending,
.elevator_activate_req_fn = cfq_activate_request,
.elevator_deactivate_req_fn = cfq_deactivate_request,
.elevator_completed_req_fn = cfq_completed_request,
diff --git a/block/elevator.c b/block/elevator.c
index 27adf7c..55f1f1e 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -34,6 +34,7 @@
#include <linux/blktrace_api.h>
#include <linux/hash.h>
#include <linux/uaccess.h>
+#include <linux/pm_runtime.h>
#include <trace/events/block.h>
@@ -568,6 +569,27 @@
e->type->ops.elevator_bio_merged_fn(q, rq, bio);
}
+#ifdef CONFIG_PM_RUNTIME
+static void blk_pm_requeue_request(struct request *rq)
+{
+ if (rq->q->dev && !(rq->cmd_flags & REQ_PM))
+ rq->q->nr_pending--;
+}
+
+static void blk_pm_add_request(struct request_queue *q, struct request *rq)
+{
+ if (q->dev && !(rq->cmd_flags & REQ_PM) && q->nr_pending++ == 0 &&
+ (q->rpm_status == RPM_SUSPENDED || q->rpm_status == RPM_SUSPENDING))
+ pm_request_resume(q->dev);
+}
+#else
+static inline void blk_pm_requeue_request(struct request *rq) {}
+static inline void blk_pm_add_request(struct request_queue *q,
+ struct request *rq)
+{
+}
+#endif
+
void elv_requeue_request(struct request_queue *q, struct request *rq)
{
/*
@@ -582,6 +604,8 @@
rq->cmd_flags &= ~REQ_STARTED;
+ blk_pm_requeue_request(rq);
+
__elv_add_request(q, rq, ELEVATOR_INSERT_REQUEUE);
}
@@ -658,6 +682,8 @@
{
trace_block_rq_insert(q, rq);
+ blk_pm_add_request(q, rq);
+
rq->q = q;
if (rq->cmd_flags & REQ_SOFTBARRIER) {
@@ -816,7 +842,6 @@
if (rq->cmd_flags & REQ_URGENT) {
q->notified_urgent = false;
- WARN_ON(!q->dispatched_urgent);
q->dispatched_urgent = false;
}
/*
diff --git a/block/row-iosched.c b/block/row-iosched.c
index 3fa3b1a..8e19c94 100644
--- a/block/row-iosched.c
+++ b/block/row-iosched.c
@@ -350,11 +350,14 @@
if (row_queues_def[rqueue->prio].idling_enabled) {
if (rd->rd_idle_data.idling_queue_idx == rqueue->prio &&
hrtimer_active(&rd->rd_idle_data.hr_timer)) {
- (void)hrtimer_cancel(&rd->rd_idle_data.hr_timer);
- row_log_rowq(rd, rqueue->prio,
- "Canceled delayed work on %d",
- rd->rd_idle_data.idling_queue_idx);
- rd->rd_idle_data.idling_queue_idx = ROWQ_MAX_PRIO;
+ if (hrtimer_try_to_cancel(
+ &rd->rd_idle_data.hr_timer) >= 0) {
+ row_log_rowq(rd, rqueue->prio,
+ "Canceled delayed work on %d",
+ rd->rd_idle_data.idling_queue_idx);
+ rd->rd_idle_data.idling_queue_idx =
+ ROWQ_MAX_PRIO;
+ }
}
diff_ms = ktime_to_ms(ktime_sub(ktime_get(),
rqueue->idle_data.last_insert_time));
@@ -583,14 +586,14 @@
for (i = 0; i < ROWQ_REG_PRIO_IDX; i++) {
if (!list_empty(&rd->row_queues[i].fifo)) {
if (hrtimer_active(&rd->rd_idle_data.hr_timer)) {
- (void)hrtimer_cancel(
- &rd->rd_idle_data.hr_timer);
- row_log_rowq(rd,
- rd->rd_idle_data.idling_queue_idx,
+ if (hrtimer_try_to_cancel(
+ &rd->rd_idle_data.hr_timer) >= 0) {
+ row_log(rd->dispatch_queue,
"Canceling delayed work on %d. RT pending",
- rd->rd_idle_data.idling_queue_idx);
- rd->rd_idle_data.idling_queue_idx =
- ROWQ_MAX_PRIO;
+ rd->rd_idle_data.idling_queue_idx);
+ rd->rd_idle_data.idling_queue_idx =
+ ROWQ_MAX_PRIO;
+ }
}
if (row_regular_req_pending(rd) &&
@@ -726,11 +729,12 @@
int ret = 0, currq, ioprio_class_to_serve, start_idx, end_idx;
if (force && hrtimer_active(&rd->rd_idle_data.hr_timer)) {
- (void)hrtimer_cancel(&rd->rd_idle_data.hr_timer);
- row_log_rowq(rd, rd->rd_idle_data.idling_queue_idx,
- "Canceled delayed work on %d - forced dispatch",
- rd->rd_idle_data.idling_queue_idx);
- rd->rd_idle_data.idling_queue_idx = ROWQ_MAX_PRIO;
+ if (hrtimer_try_to_cancel(&rd->rd_idle_data.hr_timer) >= 0) {
+ row_log(rd->dispatch_queue,
+ "Canceled delayed work on %d - forced dispatch",
+ rd->rd_idle_data.idling_queue_idx);
+ rd->rd_idle_data.idling_queue_idx = ROWQ_MAX_PRIO;
+ }
}
if (rd->pending_urgent_rq) {
diff --git a/block/test-iosched.c b/block/test-iosched.c
index b1e5492..07b36b8 100644
--- a/block/test-iosched.c
+++ b/block/test-iosched.c
@@ -101,8 +101,8 @@
goto exit;
}
- ptd->test_info.test_duration = jiffies -
- ptd->test_info.test_duration;
+ ptd->test_info.test_duration = ktime_sub(ktime_get(),
+ ptd->test_info.test_duration);
test_pr_info("%s: Test is completed, test_count=%d, reinsert_count=%d,",
__func__, ptd->test_count, ptd->reinsert_count);
@@ -774,7 +774,7 @@
goto error;
}
- ptd->test_info.test_duration = jiffies;
+ ptd->test_info.test_duration = ktime_get();
ret = run_test(ptd);
if (ret) {
test_pr_err("%s: failed to run the test\n", __func__);
@@ -784,10 +784,10 @@
test_pr_info("%s: Waiting for the test completion", __func__);
wait_event(ptd->wait_q, ptd->test_state == TEST_COMPLETED);
- t_info->test_duration = ptd->test_info.test_duration;
- t_info->test_byte_count = ptd->test_info.test_byte_count;
del_timer_sync(&ptd->timeout_timer);
+ memcpy(t_info, &ptd->test_info, sizeof(struct test_info));
+
ret = check_test_result(ptd);
if (ret) {
test_pr_err("%s: check_test_result failed\n",
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 5401814..7f159f0 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -21,6 +21,7 @@
#include <linux/firmware.h>
#include <linux/slab.h>
#include <linux/sched.h>
+#include <linux/io.h>
#define to_dev(obj) container_of(obj, struct device, kobj)
@@ -98,6 +99,8 @@
struct page **pages;
int nr_pages;
int page_array_size;
+ phys_addr_t dest_addr;
+ size_t dest_size;
struct timer_list timeout;
struct device dev;
bool nowait;
@@ -239,6 +242,10 @@
switch (loading) {
case 1:
+ if (fw_priv->dest_addr) {
+ set_bit(FW_STATUS_LOADING, &fw_priv->status);
+ break;
+ }
firmware_free_data(fw_priv->fw);
memset(fw_priv->fw, 0, sizeof(struct firmware));
/* If the pages are not owned by 'struct firmware' */
@@ -252,6 +259,11 @@
break;
case 0:
if (test_bit(FW_STATUS_LOADING, &fw_priv->status)) {
+ if (fw_priv->dest_addr) {
+ complete(&fw_priv->completion);
+ clear_bit(FW_STATUS_LOADING, &fw_priv->status);
+ break;
+ }
vunmap(fw_priv->fw->data);
fw_priv->fw->data = vmap(fw_priv->pages,
fw_priv->nr_pages,
@@ -286,6 +298,67 @@
static DEVICE_ATTR(loading, 0644, firmware_loading_show, firmware_loading_store);
+static int __firmware_data_rw(struct firmware_priv *fw_priv, char *buffer,
+ loff_t *offset, size_t count, int read)
+{
+ u8 __iomem *fw_buf;
+ int retval = count;
+
+ if ((*offset + count) > fw_priv->dest_size) {
+ pr_debug("%s: Failed size check.\n", __func__);
+ retval = -EINVAL;
+ goto out;
+ }
+
+ fw_buf = ioremap(fw_priv->dest_addr + *offset, count);
+ if (!fw_buf) {
+ pr_debug("%s: Failed ioremap.\n", __func__);
+ retval = -ENOMEM;
+ goto out;
+ }
+
+ if (read)
+ memcpy(buffer, fw_buf, count);
+ else
+ memcpy(fw_buf, buffer, count);
+
+ *offset += count;
+ iounmap(fw_buf);
+
+out:
+ return retval;
+}
+
+static ssize_t firmware_direct_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buffer, loff_t offset, size_t count)
+{
+ struct device *dev = to_dev(kobj);
+ struct firmware_priv *fw_priv = to_firmware_priv(dev);
+ struct firmware *fw;
+ ssize_t ret_count;
+
+ mutex_lock(&fw_lock);
+ fw = fw_priv->fw;
+
+ if (offset > fw->size) {
+ ret_count = 0;
+ goto out;
+ }
+ if (count > fw->size - offset)
+ count = fw->size - offset;
+
+ if (!fw || test_bit(FW_STATUS_DONE, &fw_priv->status)) {
+ ret_count = -ENODEV;
+ goto out;
+ }
+
+ ret_count = __firmware_data_rw(fw_priv, buffer, &offset, count, 1);
+out:
+ mutex_unlock(&fw_lock);
+ return ret_count;
+}
+
static ssize_t firmware_data_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buffer, loff_t offset, size_t count)
@@ -368,6 +441,35 @@
return 0;
}
+static ssize_t firmware_direct_write(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buffer, loff_t offset, size_t count)
+{
+ struct device *dev = to_dev(kobj);
+ struct firmware_priv *fw_priv = to_firmware_priv(dev);
+ struct firmware *fw;
+ ssize_t retval;
+
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+
+ mutex_lock(&fw_lock);
+ fw = fw_priv->fw;
+ if (!fw || test_bit(FW_STATUS_DONE, &fw_priv->status)) {
+ retval = -ENODEV;
+ goto out;
+ }
+
+ retval = __firmware_data_rw(fw_priv, buffer, &offset, count, 0);
+ if (retval < 0)
+ goto out;
+
+ fw->size = max_t(size_t, offset, fw->size);
+out:
+ mutex_unlock(&fw_lock);
+ return retval;
+}
+
/**
* firmware_data_write - write method for firmware
* @filp: open sysfs file
@@ -433,6 +535,13 @@
.write = firmware_data_write,
};
+static struct bin_attribute firmware_direct_attr_data = {
+ .attr = { .name = "data", .mode = 0644 },
+ .size = 0,
+ .read = firmware_direct_read,
+ .write = firmware_direct_write,
+};
+
static void firmware_class_timeout(u_long data)
{
struct firmware_priv *fw_priv = (struct firmware_priv *) data;
@@ -511,6 +620,8 @@
{
int retval = 0;
struct device *f_dev = &fw_priv->dev;
+ struct bin_attribute *fw_attr_data = fw_priv->dest_addr ?
+ &firmware_direct_attr_data : &firmware_attr_data;
dev_set_uevent_suppress(f_dev, true);
@@ -523,7 +634,7 @@
goto err_put_dev;
}
- retval = device_create_bin_file(f_dev, &firmware_attr_data);
+ retval = device_create_bin_file(f_dev, fw_attr_data);
if (retval) {
dev_err(f_dev, "%s: sysfs_create_bin_file failed\n", __func__);
goto err_del_dev;
@@ -558,7 +669,7 @@
device_remove_file(f_dev, &dev_attr_loading);
err_del_bin_attr:
- device_remove_bin_file(f_dev, &firmware_attr_data);
+ device_remove_bin_file(f_dev, fw_attr_data);
err_del_dev:
device_del(f_dev);
err_put_dev:
@@ -566,6 +677,35 @@
return retval;
}
+static int
+__request_firmware(const struct firmware **firmware_p, const char *name,
+ struct device *device, phys_addr_t dest_addr, size_t size)
+{
+ struct firmware_priv *fw_priv;
+ int ret;
+
+ fw_priv = _request_firmware_prepare(firmware_p, name, device, true,
+ false);
+ if (IS_ERR_OR_NULL(fw_priv))
+ return PTR_RET(fw_priv);
+
+ fw_priv->dest_addr = dest_addr;
+ fw_priv->dest_size = size;
+
+ ret = usermodehelper_read_trylock();
+ if (WARN_ON(ret)) {
+ dev_err(device, "firmware: %s will not be loaded\n", name);
+ } else {
+ ret = _request_firmware_load(fw_priv, true,
+ firmware_loading_timeout());
+ usermodehelper_read_unlock();
+ }
+ if (ret)
+ _request_firmware_cleanup(firmware_p);
+
+ return ret;
+}
+
/**
* request_firmware: - send firmware request and wait for it
* @firmware_p: pointer to firmware image
@@ -583,27 +723,33 @@
**/
int
request_firmware(const struct firmware **firmware_p, const char *name,
- struct device *device)
+ struct device *device)
{
- struct firmware_priv *fw_priv;
+ return __request_firmware(firmware_p, name, device, 0, 0);
+}
+
+/**
+ * request_firmware_direct: - send firmware request and wait for it
+ * @name: name of firmware file
+ * @device: device for which firmware is being loaded
+ * @dest_addr: Destination address for the firmware
+ * @dest_size:
+ *
+ * Similar to request_firmware, except takes in a buffer address and
+ * copies firmware data directly to that buffer. Returns the size of
+ * the firmware that was loaded at dest_addr.
+*/
+int request_firmware_direct(const char *name, struct device *device,
+ phys_addr_t dest_addr, size_t dest_size)
+{
+ const struct firmware *fp = NULL;
int ret;
- fw_priv = _request_firmware_prepare(firmware_p, name, device, true,
- false);
- if (IS_ERR_OR_NULL(fw_priv))
- return PTR_RET(fw_priv);
-
- ret = usermodehelper_read_trylock();
- if (WARN_ON(ret)) {
- dev_err(device, "firmware: %s will not be loaded\n", name);
- } else {
- ret = _request_firmware_load(fw_priv, true,
- firmware_loading_timeout());
- usermodehelper_read_unlock();
- }
+ ret = __request_firmware(&fp, name, device, dest_addr, dest_size);
if (ret)
- _request_firmware_cleanup(firmware_p);
-
+ return ret;
+ ret = fp->size;
+ release_firmware(fp);
return ret;
}
diff --git a/drivers/base/genlock.c b/drivers/base/genlock.c
index 0de37c9..58b0513 100644
--- a/drivers/base/genlock.c
+++ b/drivers/base/genlock.c
@@ -742,6 +742,16 @@
fd_install(ret, lock->file);
+ /*
+ * Taking a reference for lock file.
+ * This is required as now we have two file descriptor
+ * pointing to same file. If one FD is closed, lock file
+ * will be closed. Taking this reference will make sure
+ * that file doesn't get close. This refrence will go
+ * when client will call close on this FD.
+ */
+ fget(ret);
+
return ret;
}
EXPORT_SYMBOL(genlock_get_fd_handle);
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 83d94f1..a740be6 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -395,21 +395,26 @@
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 *nbufs, int *fds)
{
+ 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);
int outbufs = REMOTE_SCALARS_OUTBUFS(sc);
+ unsigned long iova, len;
list = smq_invoke_buf_start(rpra, sc);
pages = smq_phy_page_start(sc, list);
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;
@@ -418,6 +423,22 @@
if (list[i].num) {
rpra[i].buf.pv = pra[i].buf.pv;
continue;
+ } else if (me->smmu.enabled && fds && (fds[i] >= 0)) {
+ len = buf_page_size(pra[i].buf.len);
+ handles[i] = ion_import_dma_buf(me->iclient, fds[i]);
+ VERIFY(err, 0 == IS_ERR_OR_NULL(handles[i]));
+ if (err)
+ goto bail;
+ VERIFY(err, 0 == ion_map_iommu(me->iclient, handles[i],
+ me->smmu.domain_id, 0, SZ_4K, 0,
+ &iova, &len, 0, 0));
+ if (err)
+ goto bail;
+ rpra[i].buf.pv = pra[i].buf.pv;
+ list[i].num = 1;
+ pages[list[i].pgidx].addr = iova;
+ pages[list[i].pgidx].size = len;
+ continue;
}
if (rlen < pra[i].buf.len) {
struct fastrpc_buf *b;
@@ -770,15 +791,17 @@
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)
+ struct fastrpc_ioctl_invoke *invoke, remote_arg_t *pra,
+ int *fds)
{
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;
int interrupted = 0;
uint32_t sc;
- int i, nbufs = 0, err = 0;
+ int i, bufs, nbufs = 0, err = 0;
sc = invoke->sc;
obuf.handle = 0;
@@ -798,7 +821,7 @@
goto bail;
rpra = (remote_arg_t *)obuf.virt;
VERIFY(err, 0 == get_args(kernel, sc, pra, rpra, invoke->pra,
- &obuf, &abufs, &nbufs));
+ &obuf, &abufs, &nbufs, fds));
if (err)
goto bail;
}
@@ -828,8 +851,19 @@
}
context_free(ctx);
- if (me->smmu.enabled)
+ 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);
@@ -856,7 +890,7 @@
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)));
+ VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 1, &ioctl, ra, 0)));
return err;
}
@@ -874,7 +908,7 @@
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)));
+ VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 1, &ioctl, ra, 0)));
return err;
}
@@ -912,7 +946,7 @@
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)));
+ VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 1, &ioctl, ra, 0)));
mmap->vaddrout = routargs.vaddrout;
if (err)
goto bail;
@@ -941,7 +975,7 @@
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)));
+ VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 1, &ioctl, ra, 0)));
return err;
}
@@ -1107,33 +1141,49 @@
unsigned long ioctl_param)
{
struct fastrpc_apps *me = &gfa;
- struct fastrpc_ioctl_invoke invoke;
+ 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 bufs, err = 0;
+ int *fds = 0;
+ int bufs, size = 0, err = 0;
switch (ioctl_num) {
+ case FASTRPC_IOCTL_INVOKE_FD:
case FASTRPC_IOCTL_INVOKE:
- VERIFY(err, 0 == copy_from_user(&invoke, param,
- sizeof(invoke)));
+ invokefd.fds = 0;
+ size = (ioctl_num == FASTRPC_IOCTL_INVOKE) ?
+ sizeof(*invoke) : 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);
+ bufs = REMOTE_SCALARS_INBUFS(invoke->sc) +
+ REMOTE_SCALARS_OUTBUFS(invoke->sc);
if (bufs) {
- bufs = bufs * sizeof(*pra);
- VERIFY(err, 0 != (pra = kmalloc(bufs, GFP_KERNEL)));
+ 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));
+ VERIFY(err, 0 == copy_from_user(pra, invoke->pra,
+ bufs * sizeof(*pra)));
if (err)
goto bail;
- VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 0, &invoke,
- pra)));
+ 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)));
if (err)
goto bail;
break;
diff --git a/drivers/char/adsprpc_shared.h b/drivers/char/adsprpc_shared.h
index f2804ad..da70eb5 100644
--- a/drivers/char/adsprpc_shared.h
+++ b/drivers/char/adsprpc_shared.h
@@ -19,6 +19,7 @@
#define FASTRPC_IOCTL_INVOKE _IOWR('R', 1, struct fastrpc_ioctl_invoke)
#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_SMD_GUID "fastrpcsmd-apps-dsp"
#define DEVICE_NAME "adsprpc-smd"
@@ -94,6 +95,11 @@
remote_arg_t *pra; /* remote arguments list */
};
+struct fastrpc_ioctl_invoke_fd {
+ struct fastrpc_ioctl_invoke inv;
+ int *fds; /* fd list */
+};
+
struct fastrpc_ioctl_munmap {
uint32_t vaddrout; /* address to unmap */
int size; /* size */
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 5027107..a779b24 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -20,6 +20,8 @@
#include <linux/workqueue.h>
#include <linux/pm_runtime.h>
#include <linux/platform_device.h>
+#include <linux/pm_wakeup.h>
+#include <linux/spinlock.h>
#include <asm/current.h>
#ifdef CONFIG_DIAG_OVER_USB
#include <mach/usbdiag.h>
@@ -39,6 +41,12 @@
struct mutex dci_event_mask_mutex;
struct mutex dci_health_mutex;
+spinlock_t ws_lock;
+unsigned long ws_lock_flags;
+
+/* Number of milliseconds anticipated to process the DCI data */
+#define DCI_WAKEUP_TIMEOUT 1
+
#define DCI_CHK_CAPACITY(entry, new_data_len) \
((entry->data_len + new_data_len > entry->total_capacity) ? 1 : 0) \
@@ -46,7 +54,7 @@
struct diag_dci_data_info *dci_data_smd;
struct mutex dci_stat_mutex;
-void diag_dci_smd_record_info(int read_bytes)
+void diag_dci_smd_record_info(int read_bytes, uint8_t ch_type)
{
static int curr_dci_data_smd;
static unsigned long iteration;
@@ -59,13 +67,14 @@
temp_data += curr_dci_data_smd;
temp_data->iteration = iteration + 1;
temp_data->data_size = read_bytes;
+ temp_data->ch_type = ch_type;
diag_get_timestamp(temp_data->time_stamp);
curr_dci_data_smd++;
iteration++;
mutex_unlock(&dci_stat_mutex);
}
#else
-void diag_dci_smd_record_info(int read_bytes) { }
+void diag_dci_smd_record_info(int read_bytes, uint8_t ch_type) { }
#endif
/* Process the data read from the smd dci channel */
@@ -75,7 +84,7 @@
int read_bytes, dci_pkt_len, i;
uint8_t recv_pkt_cmd_code;
- diag_dci_smd_record_info(recd_bytes);
+ diag_dci_smd_record_info(recd_bytes, (uint8_t)smd_info->type);
/* Each SMD read can have multiple DCI packets */
read_bytes = 0;
while (read_bytes < recd_bytes) {
@@ -96,6 +105,11 @@
read_bytes += 5 + dci_pkt_len;
buf += 5 + dci_pkt_len; /* advance to next DCI pkt */
}
+ /* Release wakeup source when there are no more clients to
+ process DCI data */
+ if (driver->num_dci_client == 0)
+ diag_dci_try_deactivate_wakeup_source(smd_info->ch);
+
/* wake up all sleeping DCI clients which have some data */
for (i = 0; i < MAX_DCI_CLIENTS; i++) {
if (driver->dci_client_tbl[i].client &&
@@ -515,6 +529,7 @@
if (!temp) {
pr_err("diag: Invalid buffer in %s\n", __func__);
+ return -ENOMEM;
}
/* This is Pkt request/response transaction */
@@ -1100,6 +1115,9 @@
diag_smd_notify);
driver->smd_dci[index].ch_save =
driver->smd_dci[index].ch;
+ driver->dci_device = &pdev->dev;
+ driver->dci_device->power.wakeup = wakeup_source_register
+ ("DIAG_DCI_WS");
if (err)
pr_err("diag: In %s, cannot open DCI port, Id = %d, err: %d\n",
__func__, pdev->id, err);
@@ -1122,6 +1140,9 @@
diag_smd_notify);
driver->smd_dci_cmd[index].ch_save =
driver->smd_dci_cmd[index].ch;
+ driver->dci_cmd_device = &pdev->dev;
+ driver->dci_cmd_device->power.wakeup = wakeup_source_register
+ ("DIAG_DCI_CMD_WS");
if (err)
pr_err("diag: In %s, cannot open DCI port, Id = %d, err: %d\n",
__func__, pdev->id, err);
@@ -1173,10 +1194,13 @@
driver->dci_tag = 0;
driver->dci_client_id = 0;
driver->num_dci_client = 0;
+ driver->dci_device = NULL;
+ driver->dci_cmd_device = NULL;
mutex_init(&driver->dci_mutex);
mutex_init(&dci_log_mask_mutex);
mutex_init(&dci_event_mask_mutex);
mutex_init(&dci_health_mutex);
+ spin_lock_init(&ws_lock);
for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) {
success = diag_smd_constructor(&driver->smd_dci[i], i,
@@ -1239,6 +1263,10 @@
if (driver->diag_dci_wq)
destroy_workqueue(driver->diag_dci_wq);
+ mutex_destroy(&driver->dci_mutex);
+ mutex_destroy(&dci_log_mask_mutex);
+ mutex_destroy(&dci_event_mask_mutex);
+ mutex_destroy(&dci_health_mutex);
return DIAG_DCI_NO_REG;
}
@@ -1381,4 +1409,48 @@
return 0;
}
+uint8_t diag_dci_get_cumulative_real_time()
+{
+ uint8_t real_time = MODE_NONREALTIME, i;
+ for (i = 0; i < MAX_DCI_CLIENTS; i++)
+ if (driver->dci_client_tbl[i].client &&
+ driver->dci_client_tbl[i].real_time ==
+ MODE_REALTIME) {
+ real_time = 1;
+ break;
+ }
+ return real_time;
+}
+int diag_dci_set_real_time(int client_id, uint8_t real_time)
+{
+ int i = DCI_CLIENT_INDEX_INVALID;
+ i = diag_dci_find_client_index(client_id);
+
+ if (i != DCI_CLIENT_INDEX_INVALID)
+ driver->dci_client_tbl[i].real_time = real_time;
+ return i;
+}
+
+void diag_dci_try_activate_wakeup_source(smd_channel_t *channel)
+{
+ spin_lock_irqsave(&ws_lock, ws_lock_flags);
+ if (channel == driver->smd_dci[MODEM_DATA].ch) {
+ pm_wakeup_event(driver->dci_device, DCI_WAKEUP_TIMEOUT);
+ pm_stay_awake(driver->dci_device);
+ } else if (channel == driver->smd_dci_cmd[MODEM_DATA].ch) {
+ pm_wakeup_event(driver->dci_cmd_device, DCI_WAKEUP_TIMEOUT);
+ pm_stay_awake(driver->dci_cmd_device);
+ }
+ spin_unlock_irqrestore(&ws_lock, ws_lock_flags);
+}
+
+void diag_dci_try_deactivate_wakeup_source(smd_channel_t *channel)
+{
+ spin_lock_irqsave(&ws_lock, ws_lock_flags);
+ if (channel == driver->smd_dci[MODEM_DATA].ch)
+ pm_relax(driver->dci_device);
+ else if (channel == driver->smd_dci_cmd[MODEM_DATA].ch)
+ pm_relax(driver->dci_cmd_device);
+ spin_unlock_irqrestore(&ws_lock, ws_lock_flags);
+}
diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h
index 22f2cad..e2c4158 100644
--- a/drivers/char/diag/diag_dci.h
+++ b/drivers/char/diag/diag_dci.h
@@ -66,6 +66,7 @@
int received_logs;
int received_events;
struct mutex data_mutex;
+ uint8_t real_time;
};
/* This is used for DCI health stats */
@@ -100,6 +101,7 @@
unsigned long iteration;
int data_size;
char time_stamp[DIAG_TS_SIZE];
+ uint8_t ch_type;
};
extern struct diag_dci_data_info *dci_data_smd;
@@ -134,5 +136,10 @@
void create_dci_event_mask_tbl(unsigned char *tbl_buf);
int diag_dci_clear_event_mask(void);
int diag_dci_query_event_mask(uint16_t event_id);
-void diag_dci_smd_record_info(int read_bytes);
+void diag_dci_smd_record_info(int read_bytes, uint8_t ch_type);
+uint8_t diag_dci_get_cumulative_real_time(void);
+int diag_dci_set_real_time(int client_id, uint8_t real_time);
+/* Functions related to DCI wakeup sources */
+void diag_dci_try_activate_wakeup_source(smd_channel_t *channel);
+void diag_dci_try_deactivate_wakeup_source(smd_channel_t *channel);
#endif
diff --git a/drivers/char/diag/diag_debugfs.c b/drivers/char/diag/diag_debugfs.c
index 6b0931c..a24fc54 100644
--- a/drivers/char/diag/diag_debugfs.c
+++ b/drivers/char/diag/diag_debugfs.c
@@ -70,7 +70,24 @@
"Modem CMD in_busy_1: %d\n"
"Modem CMD in_busy_2: %d\n"
"DCI CMD Modem in_busy_1: %d\n"
- "logging_mode: %d\n",
+ "Modem supports STM: %d\n"
+ "LPASS supports STM: %d\n"
+ "RIVA supports STM: %d\n"
+ "Modem STM state: %d\n"
+ "LPASS STM state: %d\n"
+ "RIVA STM state: %d\n"
+ "APPS STM state: %d\n"
+ "Modem STM requested state: %d\n"
+ "LPASS STM requested state: %d\n"
+ "RIVA STM requested state: %d\n"
+ "APPS STM requested state: %d\n"
+ "supports apps hdlc encoding: %d\n"
+ "Modem hdlc encoding: %d\n"
+ "Lpass hdlc encoding: %d\n"
+ "RIVA hdlc encoding: %d\n"
+ "Modem CMD hdlc encoding: %d\n"
+ "logging_mode: %d\n"
+ "real_time_mode: %d\n",
(unsigned int)driver->smd_data[MODEM_DATA].ch,
(unsigned int)driver->smd_data[LPASS_DATA].ch,
(unsigned int)driver->smd_data[WCNSS_DATA].ch,
@@ -100,7 +117,24 @@
driver->smd_cmd[MODEM_DATA].in_busy_1,
driver->smd_cmd[MODEM_DATA].in_busy_2,
driver->smd_dci_cmd[MODEM_DATA].in_busy_1,
- driver->logging_mode);
+ driver->peripheral_supports_stm[MODEM_DATA],
+ driver->peripheral_supports_stm[LPASS_DATA],
+ driver->peripheral_supports_stm[WCNSS_DATA],
+ driver->stm_state[MODEM_DATA],
+ driver->stm_state[LPASS_DATA],
+ driver->stm_state[WCNSS_DATA],
+ driver->stm_state[APPS_DATA],
+ driver->stm_state_requested[MODEM_DATA],
+ driver->stm_state_requested[LPASS_DATA],
+ driver->stm_state_requested[WCNSS_DATA],
+ driver->stm_state_requested[APPS_DATA],
+ driver->supports_apps_hdlc_encoding,
+ driver->smd_data[MODEM_DATA].encode_hdlc,
+ driver->smd_data[LPASS_DATA].encode_hdlc,
+ driver->smd_data[WCNSS_DATA].encode_hdlc,
+ driver->smd_cmd[MODEM_DATA].encode_hdlc,
+ driver->logging_mode,
+ driver->real_time_mode);
#ifdef CONFIG_DIAG_OVER_USB
ret += scnprintf(buf+ret, DEBUG_BUF_SIZE,
@@ -137,8 +171,12 @@
if (diag_dbgfs_dci_data_index == 0) {
bytes_written =
scnprintf(buf, buf_size,
- "number of clients: %d\n",
- driver->num_dci_client);
+ "number of clients: %d\n"
+ "dci proc active: %d\n"
+ "dci real time vote: %d\n",
+ driver->num_dci_client,
+ (driver->proc_active_mask & DIAG_PROC_DCI) ? 1 : 0,
+ (driver->proc_rt_vote_mask & DIAG_PROC_DCI) ? 1 : 0);
bytes_in_buf += bytes_written;
bytes_remaining -= bytes_written;
#ifdef CONFIG_DIAG_OVER_USB
@@ -148,17 +186,39 @@
bytes_in_buf += bytes_written;
bytes_remaining -= bytes_written;
#endif
+ if (driver->dci_device) {
+ bytes_written = scnprintf(buf+bytes_in_buf,
+ bytes_remaining,
+ "dci power active, relax: %lu, %lu\n",
+ driver->dci_device->power.wakeup->active_count,
+ driver->dci_device->power.wakeup->relax_count);
+ bytes_in_buf += bytes_written;
+ bytes_remaining -= bytes_written;
+ }
+ if (driver->dci_cmd_device) {
+ bytes_written = scnprintf(buf+bytes_in_buf,
+ bytes_remaining,
+ "dci cmd power active, relax: %lu, %lu\n",
+ driver->dci_cmd_device->power.wakeup->
+ active_count,
+ driver->dci_cmd_device->power.wakeup->
+ relax_count);
+ bytes_in_buf += bytes_written;
+ bytes_remaining -= bytes_written;
+ }
}
temp_data += diag_dbgfs_dci_data_index;
for (i = diag_dbgfs_dci_data_index; i < DIAG_DCI_DEBUG_CNT; i++) {
if (temp_data->iteration != 0) {
bytes_written = scnprintf(
buf + bytes_in_buf, bytes_remaining,
- "i %-20ld\t"
- "s %-20d\t"
- "t %-20s\n",
+ "i %-10ld\t"
+ "s %-10d\t"
+ "c %-10d\t"
+ "t %-15s\n",
temp_data->iteration,
temp_data->data_size,
+ temp_data->ch_type,
temp_data->time_stamp);
bytes_in_buf += bytes_written;
bytes_remaining -= bytes_written;
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index 5aed793..c91095e 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -26,7 +26,7 @@
#define ALL_SSID -1
#define MAX_SSID_PER_RANGE 100
-#define FEATURE_MASK_LEN_BYTES 1
+#define FEATURE_MASK_LEN_BYTES 2
struct mask_info {
int equip_id;
@@ -307,7 +307,8 @@
diag_send_feature_mask_update(smd_info);
if (smd_info->notify_context == SMD_EVENT_OPEN)
- diag_send_diag_mode_update_by_smd(smd_info, MODE_REALTIME);
+ diag_send_diag_mode_update_by_smd(smd_info,
+ driver->real_time_mode);
smd_info->notify_context = 0;
}
@@ -465,7 +466,7 @@
void *buf = driver->buf_feature_mask_update;
int header_size = sizeof(struct diag_ctrl_feature_mask);
int wr_size = -ENOMEM, retry_count = 0;
- uint8_t feature_byte = 0;
+ uint8_t feature_bytes[FEATURE_MASK_LEN_BYTES] = {0, 0};
int total_len = 0;
if (!smd_info) {
@@ -486,11 +487,14 @@
driver->feature_mask->ctrl_pkt_data_len = 4 + FEATURE_MASK_LEN_BYTES;
driver->feature_mask->feature_mask_len = FEATURE_MASK_LEN_BYTES;
memcpy(buf, driver->feature_mask, header_size);
- feature_byte |= F_DIAG_INT_FEATURE_MASK;
- feature_byte |= F_DIAG_LOG_ON_DEMAND_RSP_ON_MASTER;
- feature_byte |= driver->supports_separate_cmdrsp ?
+ feature_bytes[0] |= F_DIAG_INT_FEATURE_MASK;
+ feature_bytes[0] |= F_DIAG_LOG_ON_DEMAND_RSP_ON_MASTER;
+ feature_bytes[0] |= driver->supports_separate_cmdrsp ?
F_DIAG_REQ_RSP_CHANNEL : 0;
- memcpy(buf+header_size, &feature_byte, FEATURE_MASK_LEN_BYTES);
+ feature_bytes[0] |= driver->supports_apps_hdlc_encoding ?
+ F_DIAG_HDLC_ENCODE_IN_APPS_MASK : 0;
+ feature_bytes[1] |= F_DIAG_OVER_STM;
+ memcpy(buf+header_size, &feature_bytes, FEATURE_MASK_LEN_BYTES);
total_len = header_size + FEATURE_MASK_LEN_BYTES;
while (retry_count < 3) {
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 1f45a32..cf21b82 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -27,7 +27,7 @@
/* Size of the USB buffers used for read and write*/
#define USB_MAX_OUT_BUF 4096
-#define APPS_BUF_SIZE 2000
+#define APPS_BUF_SIZE 4096
#define IN_BUF_SIZE 16384
#define MAX_IN_BUF_SIZE 32768
#define MAX_SYNC_OBJ_NAME_SIZE 32
@@ -89,6 +89,13 @@
#define DIAG_CON_LPASS (0x0004) /* Bit mask for LPASS */
#define DIAG_CON_WCNSS (0x0008) /* Bit mask for WCNSS */
+#define NUM_STM_PROCESSORS 4
+
+#define DIAG_STM_MODEM 0x01
+#define DIAG_STM_LPASS 0x02
+#define DIAG_STM_WCNSS 0x04
+#define DIAG_STM_APPS 0x08
+
/*
* The status bit masks when received in a signal handler are to be
* used in conjunction with the peripheral list bit mask to determine the
@@ -113,6 +120,14 @@
#define SMD_CMD_TYPE 3
#define SMD_DCI_CMD_TYPE 4
+#define DIAG_PROC_DCI 1
+#define DIAG_PROC_MEMORY_DEVICE 2
+
+/* Flags to vote the DCI or Memory device process up or down
+ when it becomes active or inactive */
+#define VOTE_DOWN 0
+#define VOTE_UP 1
+
#define DIAG_TS_SIZE 50
/* Maximum number of pkt reg supported at initialization*/
@@ -182,6 +197,11 @@
spinlock_t read_spinlock;
};
+struct real_time_vote_t {
+ uint16_t proc;
+ uint8_t real_time_vote;
+};
+
/* This structure is defined in USB header file */
#ifndef CONFIG_DIAG_OVER_USB
struct diag_request {
@@ -197,6 +217,7 @@
int peripheral; /* The peripheral this smd channel communicates with */
int type; /* The type of smd channel (data, control, dci) */
uint16_t peripheral_mask;
+ int encode_hdlc; /* Whether data is raw and needs to be hdlc encoded */
smd_channel_t *ch;
smd_channel_t *ch_save;
@@ -209,14 +230,21 @@
unsigned char *buf_in_1;
unsigned char *buf_in_2;
+ unsigned char *buf_in_1_raw;
+ unsigned char *buf_in_2_raw;
+
struct diag_request *write_ptr_1;
struct diag_request *write_ptr_2;
struct diag_nrt_wake_lock nrt_lock;
+ struct workqueue_struct *wq;
+
struct work_struct diag_read_smd_work;
struct work_struct diag_notify_update_smd_work;
int notify_context;
+ struct work_struct diag_general_smd_work;
+ int general_context;
/*
* Function ptr for function to call to process the data that
@@ -248,6 +276,13 @@
unsigned int buf_tbl_size;
int use_device_tree;
int supports_separate_cmdrsp;
+ int supports_apps_hdlc_encoding;
+ /* The state requested in the STM command */
+ int stm_state_requested[NUM_STM_PROCESSORS];
+ /* The current STM state */
+ int stm_state[NUM_STM_PROCESSORS];
+ /* 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 diag_dci_client_tbl *dci_client_tbl;
@@ -286,7 +321,6 @@
struct diag_ctrl_msg_mask *msg_mask;
struct diag_ctrl_feature_mask *feature_mask;
/* State for diag forwarding */
- int real_time_mode;
struct diag_smd_info smd_data[NUM_SMD_DATA_CHANNELS];
struct diag_smd_info smd_cntl[NUM_SMD_CONTROL_CHANNELS];
struct diag_smd_info smd_dci[NUM_SMD_DCI_CHANNELS];
@@ -306,6 +340,16 @@
unsigned hdlc_count;
unsigned hdlc_escape;
int in_busy_pktdata;
+ struct device *dci_device;
+ struct device *dci_cmd_device;
+ /* Variables for non real time mode */
+ int real_time_mode;
+ int real_time_update_busy;
+ uint16_t proc_active_mask;
+ uint16_t proc_rt_vote_mask;
+ struct mutex real_time_mutex;
+ struct work_struct diag_real_time_work;
+ struct workqueue_struct *diag_real_time_wq;
#ifdef CONFIG_DIAG_OVER_USB
int usb_connected;
struct usb_diag_ch *legacy_ch;
@@ -347,7 +391,6 @@
struct diag_request *write_ptr_mdm;
#endif
#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
- spinlock_t hsic_ready_spinlock;
/* common for all bridges */
struct work_struct diag_connect_work;
struct work_struct diag_disconnect_work;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 1a2f431..099dc09 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -44,6 +44,9 @@
#include "diag_masks.h"
#include "diagfwd_bridge.h"
+#include <linux/coresight-stm.h>
+#include <linux/kernel.h>
+
MODULE_DESCRIPTION("Diag Char Driver");
MODULE_LICENSE("GPL v2");
MODULE_VERSION("1.0");
@@ -270,20 +273,24 @@
DCI_CLIENT_INDEX_INVALID)
diagchar_ioctl(NULL, DIAG_IOCTL_DCI_DEINIT, 0);
/* If the exiting process is the socket process */
+ mutex_lock(&driver->diagchar_mutex);
if (driver->socket_process &&
(driver->socket_process->tgid == current->tgid)) {
driver->socket_process = NULL;
+ diag_update_proc_vote(DIAG_PROC_MEMORY_DEVICE, VOTE_DOWN);
}
if (driver->callback_process &&
(driver->callback_process->tgid == current->tgid)) {
driver->callback_process = NULL;
+ diag_update_proc_vote(DIAG_PROC_MEMORY_DEVICE, VOTE_DOWN);
}
+ mutex_unlock(&driver->diagchar_mutex);
#ifdef CONFIG_DIAG_OVER_USB
/* If the SD logging process exits, change logging to USB mode */
if (driver->logging_process_id == current->tgid) {
driver->logging_mode = USB_MODE;
- diag_send_diag_mode_update(MODE_REALTIME);
+ diag_update_proc_vote(DIAG_PROC_MEMORY_DEVICE, VOTE_DOWN);
diagfwd_connect();
#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
diag_clear_hsic_tbl();
@@ -299,9 +306,10 @@
mutex_lock(&driver->diagchar_mutex);
driver->ref_count--;
- /* On Client exit, try to destroy all 3 pools */
+ /* On Client exit, try to destroy all 4 pools */
diagmem_exit(driver, POOL_TYPE_COPY);
diagmem_exit(driver, POOL_TYPE_HDLC);
+ diagmem_exit(driver, POOL_TYPE_USER);
diagmem_exit(driver, POOL_TYPE_WRITE_STRUCT);
for (i = 0; i < driver->num_clients; i++) {
if (NULL != diagpriv_data && diagpriv_data->pid ==
@@ -535,58 +543,10 @@
return exit_stat;
}
-static void diag_update_data_ready(int index)
-{
- int clear_bit = 1;
- unsigned long hsic_lock_flags;
- unsigned long ready_lock_flags;
- int i;
-
- /*
- * Determine whether the data_ready USER_SPACE_DATA_TYPE bit
- * should be updated/cleared or not. There is a race condition that
- * can occur when in MEMORY_DEVICE_MODE with the hsic data.
- * When new hsic data arrives we prepare the data so it can
- * later be copied to userspace. We set the USER_SPACE_DATA_TYPE
- * bit in data ready at that time. We later copy the hsic data
- * to userspace and clear the USER_SPACE_DATA_TYPE bit in
- * data ready. The race condition occurs if new data arrives (bit set)
- * while we are processing the current data and sending
- * it to userspace (bit clear). The clearing of the bit can
- * overwrite the setting of the bit.
- */
-
- spin_lock_irqsave(&driver->hsic_ready_spinlock, ready_lock_flags);
- for (i = 0; i < MAX_HSIC_CH; i++) {
- if (diag_hsic[i].hsic_inited) {
- spin_lock_irqsave(&diag_hsic[i].hsic_spinlock,
- hsic_lock_flags);
- if ((diag_hsic[i].num_hsic_buf_tbl_entries > 0) &&
- diag_hsic[i].hsic_device_enabled &&
- diag_hsic[i].hsic_ch) {
- /* New data do not clear the bit */
- clear_bit = 0;
- }
- spin_unlock_irqrestore(&diag_hsic[i].hsic_spinlock,
- hsic_lock_flags);
- if (!clear_bit)
- break;
- }
- }
-
- if (clear_bit)
- driver->data_ready[index] ^= USER_SPACE_DATA_TYPE;
-
- spin_unlock_irqrestore(&driver->hsic_ready_spinlock, ready_lock_flags);
-}
#else
inline uint16_t diag_get_remote_device_mask(void) { return 0; }
inline int diag_copy_remote(char __user *buf, size_t count, int *pret,
int *pnum_data) { return 0; }
-static void diag_update_data_ready(int index)
-{
- driver->data_ready[index] ^= USER_SPACE_DATA_TYPE;
-}
#endif
int diag_command_reg(unsigned long ioarg)
@@ -796,7 +756,6 @@
int diag_switch_logging(unsigned long ioarg)
{
int temp = 0, success = -EINVAL, status = 0;
- int temp_realtime_mode = driver->real_time_mode;
int requested_mode = (int)ioarg;
switch (requested_mode) {
@@ -806,7 +765,6 @@
case UART_MODE:
case SOCKET_MODE:
case CALLBACK_MODE:
- case MEMORY_DEVICE_MODE_NRT:
break;
default:
pr_err("diag: In %s, request to switch to invalid mode: %d\n",
@@ -814,26 +772,28 @@
return -EINVAL;
}
- mutex_lock(&driver->diagchar_mutex);
- temp = driver->logging_mode;
- driver->logging_mode = requested_mode;
-
- if (driver->logging_mode == MEMORY_DEVICE_MODE_NRT) {
- diag_send_diag_mode_update(MODE_NONREALTIME);
- driver->logging_mode = MEMORY_DEVICE_MODE;
- } else {
- diag_send_diag_mode_update(MODE_REALTIME);
- }
-
- if (temp == driver->logging_mode) {
- mutex_unlock(&driver->diagchar_mutex);
- if (driver->logging_mode != MEMORY_DEVICE_MODE ||
- temp_realtime_mode)
+ if (requested_mode == driver->logging_mode) {
+ if (requested_mode != MEMORY_DEVICE_MODE ||
+ driver->real_time_mode)
pr_info_ratelimited("diag: Already in logging mode change requested, mode: %d\n",
driver->logging_mode);
return 0;
}
+ diag_update_proc_vote(DIAG_PROC_MEMORY_DEVICE, VOTE_UP);
+ if (requested_mode != MEMORY_DEVICE_MODE)
+ diag_update_real_time_vote(DIAG_PROC_MEMORY_DEVICE,
+ MODE_REALTIME);
+
+ if (!(requested_mode == MEMORY_DEVICE_MODE &&
+ driver->logging_mode == USB_MODE))
+ queue_work(driver->diag_real_time_wq,
+ &driver->diag_real_time_work);
+
+ mutex_lock(&driver->diagchar_mutex);
+ temp = driver->logging_mode;
+ driver->logging_mode = requested_mode;
+
if (driver->logging_mode == MEMORY_DEVICE_MODE) {
diag_clear_hsic_tbl();
driver->mask_check = 1;
@@ -911,12 +871,14 @@
long diagchar_ioctl(struct file *filp,
unsigned int iocmd, unsigned long ioarg)
{
- int i, result = -EINVAL, interim_size = 0, client_id = 0;
+ int i, result = -EINVAL, interim_size = 0, client_id = 0, real_time = 0;
+ int retry_count = 0, timer = 0;
uint16_t support_list = 0, interim_rsp_id, remote_dev;
struct diag_dci_client_tbl *dci_params;
struct diag_dci_health_stats stats;
struct diag_log_event_stats le_stats;
struct diagpkt_delay_params delay_params;
+ struct real_time_vote_t rt_vote;
switch (iocmd) {
case DIAG_IOCTL_COMMAND_REG:
@@ -966,6 +928,10 @@
driver->smd_dci_cmd[i].in_busy_1 = 0;
}
driver->num_dci_client++;
+ if (driver->num_dci_client == 1)
+ diag_update_proc_vote(DIAG_PROC_DCI, VOTE_UP);
+ queue_work(driver->diag_real_time_wq,
+ &driver->diag_real_time_work);
pr_debug("diag: In %s, id = %d\n",
__func__, driver->dci_client_id);
driver->dci_client_id++;
@@ -989,6 +955,7 @@
driver->dci_client_tbl[i].dropped_events = 0;
driver->dci_client_tbl[i].received_logs = 0;
driver->dci_client_tbl[i].received_events = 0;
+ driver->dci_client_tbl[i].real_time = 1;
mutex_init(&driver->dci_client_tbl[i].
data_mutex);
break;
@@ -1037,6 +1004,15 @@
mutex_destroy(&driver->dci_client_tbl[result].
data_mutex);
driver->num_dci_client--;
+ if (driver->num_dci_client == 0) {
+ diag_update_proc_vote(DIAG_PROC_DCI, VOTE_DOWN);
+ } else {
+ real_time = diag_dci_get_cumulative_real_time();
+ diag_update_real_time_vote(DIAG_PROC_DCI,
+ real_time);
+ }
+ queue_work(driver->diag_real_time_wq,
+ &driver->diag_real_time_work);
}
mutex_unlock(&driver->dci_mutex);
break;
@@ -1131,6 +1107,44 @@
else
result = 1;
break;
+ case DIAG_IOCTL_VOTE_REAL_TIME:
+ if (copy_from_user(&rt_vote, (void *)ioarg, sizeof(struct
+ real_time_vote_t)))
+ result = -EFAULT;
+ driver->real_time_update_busy++;
+ if (rt_vote.proc == DIAG_PROC_DCI) {
+ diag_dci_set_real_time(current->tgid,
+ rt_vote.real_time_vote);
+ real_time = diag_dci_get_cumulative_real_time();
+ } else {
+ real_time = rt_vote.real_time_vote;
+ }
+ diag_update_real_time_vote(rt_vote.proc, real_time);
+ queue_work(driver->diag_real_time_wq,
+ &driver->diag_real_time_work);
+ result = 0;
+ break;
+ case DIAG_IOCTL_GET_REAL_TIME:
+ if (copy_from_user(&real_time, (void *)ioarg, sizeof(int)))
+ return -EFAULT;
+ while (retry_count < 3) {
+ if (driver->real_time_update_busy > 0) {
+ retry_count++;
+ /* The value 10000 was chosen empirically as an
+ optimum value in order to give the work in
+ diag_real_time_wq to complete processing.*/
+ for (timer = 0; timer < 5; timer++)
+ usleep_range(10000, 10100);
+ } else {
+ real_time = driver->real_time_mode;
+ if (copy_to_user((void *)ioarg, &real_time,
+ sizeof(int)))
+ return -EFAULT;
+ result = 0;
+ break;
+ }
+ }
+ break;
}
return result;
}
@@ -1154,8 +1168,8 @@
return -EINVAL;
}
- wait_event_interruptible(driver->wait_q,
- driver->data_ready[index]);
+ wait_event_interruptible(driver->wait_q, driver->data_ready[index]);
+
mutex_lock(&driver->diagchar_mutex);
clear_read_wakelock = 0;
@@ -1165,6 +1179,7 @@
pr_debug("diag: process woken up\n");
/*Copy the type of data being passed*/
data_type = driver->data_ready[index] & USER_SPACE_DATA_TYPE;
+ driver->data_ready[index] ^= USER_SPACE_DATA_TYPE;
COPY_USER_SPACE_OR_EXIT(buf, data_type, 4);
/* place holder for number of data field */
ret += 4;
@@ -1300,10 +1315,9 @@
/* copy number of data fields */
COPY_USER_SPACE_OR_EXIT(buf+4, num_data, 4);
ret -= 4;
- diag_update_data_ready(index);
for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
if (driver->smd_data[i].ch)
- queue_work(driver->diag_wq,
+ queue_work(driver->smd_data[i].wq,
&(driver->smd_data[i].diag_read_smd_work));
}
#ifdef CONFIG_DIAG_SDIO_PIPE
@@ -1391,19 +1405,25 @@
driver->data_ready[index] ^= DCI_DATA_TYPE;
for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) {
driver->smd_dci[i].in_busy_1 = 0;
- if (driver->smd_dci[i].ch)
+ if (driver->smd_dci[i].ch) {
+ diag_dci_try_deactivate_wakeup_source(
+ driver->smd_dci[i].ch);
queue_work(driver->diag_dci_wq,
&(driver->smd_dci[i].diag_read_smd_work));
+ }
}
if (driver->supports_separate_cmdrsp) {
for (i = 0; i < NUM_SMD_DCI_CMD_CHANNELS; i++) {
if (!driver->separate_cmdrsp[i])
continue;
driver->smd_dci_cmd[i].in_busy_1 = 0;
- if (driver->smd_dci_cmd[i].ch)
+ if (driver->smd_dci_cmd[i].ch) {
+ diag_dci_try_deactivate_wakeup_source(
+ driver->smd_dci_cmd[i].ch);
queue_work(driver->diag_dci_wq,
&(driver->smd_dci_cmd[i].
diag_read_smd_work));
+ }
}
}
goto exit;
@@ -1422,7 +1442,8 @@
size_t count, loff_t *ppos)
{
int err, ret = 0, pkt_type, token_offset = 0;
- int remote_proc = 0, index;
+ int remote_proc = 0;
+ uint8_t index;
#ifdef DIAG_DEBUG
int length = 0, i;
#endif
@@ -1465,11 +1486,14 @@
err = copy_from_user(user_space_data, buf + 4, payload_size);
if (err) {
pr_alert("diag: copy failed for DCI data\n");
+ diagmem_free(driver, user_space_data, POOL_TYPE_USER);
+ user_space_data = NULL;
return DIAG_DCI_SEND_DATA_FAIL;
}
err = diag_process_dci_transaction(user_space_data,
payload_size);
diagmem_free(driver, user_space_data, POOL_TYPE_USER);
+ user_space_data = NULL;
return err;
}
if (pkt_type == CALLBACK_DATA_TYPE) {
@@ -1480,16 +1504,19 @@
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");
- return -EIO;
+ ret = -EIO;
+ goto fail_free_copy;
}
/* Check for proc_type */
remote_proc = diag_get_remote(*(int *)buf_copy);
@@ -1498,8 +1525,7 @@
wait_event_interruptible(driver->wait_q,
(driver->in_busy_pktdata == 0));
ret = diag_process_apps_pkt(buf_copy, payload_size);
- diagmem_free(driver, buf_copy, POOL_TYPE_COPY);
- return ret;
+ goto fail_free_copy;
}
/* The packet is for the remote processor */
token_offset = 4;
@@ -1512,20 +1538,20 @@
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);
if (!buf_hdlc) {
ret = -ENOMEM;
- goto fail_free_hdlc;
+ driver->used = 0;
+ goto fail_free_copy;
}
if (HDLC_OUT_BUF_SIZE < (2 * payload_size) + 3) {
pr_err("diag: Dropping packet, HDLC encoded packet payload size crosses buffer limit. Current payload size %d\n",
((2*payload_size) + 3));
driver->dropped_count++;
ret = -EBADMSG;
- diagmem_free(driver, buf_hdlc, POOL_TYPE_HDLC);
goto fail_free_hdlc;
}
enc.dest = buf_hdlc + driver->used;
@@ -1552,10 +1578,11 @@
if (diag_hsic[index].hsic_ch && (payload_size > 0)) {
/* wait sending mask updates
* if HSIC ch not ready */
- if (diag_hsic[index].in_busy_hsic_write)
+ while (diag_hsic[index].in_busy_hsic_write) {
wait_event_interruptible(driver->wait_q,
(diag_hsic[index].
in_busy_hsic_write != 1));
+ }
diag_hsic[index].in_busy_hsic_write = 1;
diag_hsic[index].in_busy_hsic_read_on_device =
0;
@@ -1590,13 +1617,7 @@
}
}
#endif
- diagmem_free(driver, buf_copy, POOL_TYPE_COPY);
- diagmem_free(driver, buf_hdlc, POOL_TYPE_HDLC);
- buf_copy = NULL;
- buf_hdlc = NULL;
- driver->used = 0;
- mutex_unlock(&driver->diagchar_mutex);
- return ret;
+ goto fail_free_hdlc;
}
if (pkt_type == USER_SPACE_DATA_TYPE) {
user_space_data = diagmem_alloc(driver, payload_size,
@@ -1610,6 +1631,7 @@
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 */
@@ -1628,6 +1650,7 @@
pr_alert("diag: mask request Invalid\n");
diagmem_free(driver, user_space_data,
POOL_TYPE_USER);
+ user_space_data = NULL;
return -EFAULT;
}
}
@@ -1668,10 +1691,11 @@
if (diag_hsic[index].hsic_ch) {
/* wait sending mask updates
* if HSIC ch not ready */
- if (diag_hsic[index].in_busy_hsic_write)
+ while (diag_hsic[index].in_busy_hsic_write) {
wait_event_interruptible(driver->wait_q,
(diag_hsic[index].
in_busy_hsic_write != 1));
+ }
diag_hsic[index].in_busy_hsic_write = 1;
diag_hsic[index].in_busy_hsic_read_on_device =
0;
@@ -1705,6 +1729,7 @@
err);
diagmem_free(driver, user_space_data,
POOL_TYPE_USER);
+ user_space_data = NULL;
return err;
}
}
@@ -1715,6 +1740,7 @@
diag_process_hdlc((void *)
(user_space_data + token_offset), payload_size);
diagmem_free(driver, user_space_data, POOL_TYPE_USER);
+ user_space_data = NULL;
return 0;
}
@@ -1726,9 +1752,11 @@
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;
}
@@ -1738,6 +1766,21 @@
ret = -EFAULT;
goto fail_free_copy;
}
+ if (driver->stm_state[APPS_DATA] &&
+ (pkt_type >= DATA_TYPE_EVENT && pkt_type <= DATA_TYPE_LOG)) {
+ int stm_size = 0;
+
+ stm_size = stm_log_inv_ts(OST_ENTITY_DIAG, 0, buf_copy,
+ payload_size);
+
+ if (stm_size == 0)
+ pr_debug("diag: In %s, stm_log_inv_ts returned size of 0\n",
+ __func__);
+
+ diagmem_free(driver, buf_copy, POOL_TYPE_COPY);
+ return 0;
+ }
+
#ifdef DIAG_DEBUG
printk(KERN_DEBUG "data is -->\n");
for (i = 0; i < payload_size; i++)
@@ -1757,13 +1800,13 @@
length++;
}
#endif
- mutex_lock(&driver->diagchar_mutex);
if (!buf_hdlc)
buf_hdlc = diagmem_alloc(driver, HDLC_OUT_BUF_SIZE,
POOL_TYPE_HDLC);
if (!buf_hdlc) {
ret = -ENOMEM;
- goto fail_free_hdlc;
+ driver->used = 0;
+ goto fail_free_copy;
}
if (HDLC_OUT_BUF_SIZE < (2*payload_size) + 3) {
pr_err("diag: Dropping packet, HDLC encoded packet payload size crosses buffer limit. Current payload size %d\n",
@@ -1776,7 +1819,6 @@
err = diag_device_write(buf_hdlc, APPS_DATA, NULL);
if (err) {
/*Free the buffer right away if write failed */
- diagmem_free(driver, buf_hdlc, POOL_TYPE_HDLC);
if (driver->logging_mode == USB_MODE)
diagmem_free(driver, (unsigned char *)driver->
write_ptr_svc, POOL_TYPE_WRITE_STRUCT);
@@ -1789,7 +1831,7 @@
POOL_TYPE_HDLC);
if (!buf_hdlc) {
ret = -ENOMEM;
- goto fail_free_hdlc;
+ goto fail_free_copy;
}
}
@@ -1805,7 +1847,6 @@
err = diag_device_write(buf_hdlc, APPS_DATA, NULL);
if (err) {
/*Free the buffer right away if write failed */
- diagmem_free(driver, buf_hdlc, POOL_TYPE_HDLC);
if (driver->logging_mode == USB_MODE)
diagmem_free(driver, (unsigned char *)driver->
write_ptr_svc, POOL_TYPE_WRITE_STRUCT);
@@ -1818,7 +1859,7 @@
POOL_TYPE_HDLC);
if (!buf_hdlc) {
ret = -ENOMEM;
- goto fail_free_hdlc;
+ goto fail_free_copy;
}
enc.dest = buf_hdlc + driver->used;
enc.dest_last = (void *)(buf_hdlc + driver->used +
@@ -1831,7 +1872,6 @@
err = diag_device_write(buf_hdlc, APPS_DATA, NULL);
if (err) {
/*Free the buffer right away if write failed */
- diagmem_free(driver, buf_hdlc, POOL_TYPE_HDLC);
if (driver->logging_mode == USB_MODE)
diagmem_free(driver, (unsigned char *)driver->
write_ptr_svc, POOL_TYPE_WRITE_STRUCT);
@@ -1843,6 +1883,7 @@
}
diagmem_free(driver, buf_copy, POOL_TYPE_COPY);
+ buf_copy = NULL;
mutex_unlock(&driver->diagchar_mutex);
if (!timer_in_progress) {
timer_in_progress = 1;
@@ -1851,17 +1892,36 @@
return 0;
fail_free_hdlc:
+ diagmem_free(driver, buf_hdlc, POOL_TYPE_HDLC);
buf_hdlc = NULL;
driver->used = 0;
diagmem_free(driver, buf_copy, POOL_TYPE_COPY);
+ buf_copy = NULL;
mutex_unlock(&driver->diagchar_mutex);
return ret;
fail_free_copy:
diagmem_free(driver, buf_copy, POOL_TYPE_COPY);
+ buf_copy = NULL;
+ mutex_unlock(&driver->diagchar_mutex);
return ret;
}
+static void diag_real_time_info_init(void)
+{
+ if (!driver)
+ return;
+ driver->real_time_mode = 1;
+ driver->real_time_update_busy = 0;
+ driver->proc_active_mask = 0;
+ driver->proc_rt_vote_mask |= DIAG_PROC_DCI;
+ driver->proc_rt_vote_mask |= DIAG_PROC_MEMORY_DEVICE;
+ driver->diag_real_time_wq = create_singlethread_workqueue(
+ "diag_real_time_wq");
+ INIT_WORK(&(driver->diag_real_time_work), diag_real_time_work_fn);
+ mutex_init(&driver->real_time_mutex);
+}
+
int mask_request_validate(unsigned char mask_buf[])
{
uint8_t packet_id;
@@ -2063,11 +2123,11 @@
init_waitqueue_head(&driver->wait_q);
init_waitqueue_head(&driver->smd_wait_q);
INIT_WORK(&(driver->diag_drain_work), diag_drain_work_fn);
+ diag_real_time_info_init();
diag_debugfs_init();
diag_masks_init();
diagfwd_init();
#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
- spin_lock_init(&driver->hsic_ready_spinlock);
diagfwd_bridge_init(HSIC);
diagfwd_bridge_init(HSIC_2);
/* register HSIC device */
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 6851fd8..609d6cd 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -46,19 +46,36 @@
#define MODE_CMD 41
#define RESET_ID 2
+#define STM_CMD_VERSION_OFFSET 4
+#define STM_CMD_MASK_OFFSET 5
+#define STM_CMD_DATA_OFFSET 6
+#define STM_CMD_NUM_BYTES 7
+
+#define STM_RSP_VALID_INDEX 7
+#define STM_RSP_SUPPORTED_INDEX 8
+#define STM_RSP_SMD_COMPLY_INDEX 9
+#define STM_RSP_NUM_BYTES 10
+
int diag_debug_buf_idx;
unsigned char diag_debug_buf[1024];
/* Number of entries in table of buffers */
static unsigned int buf_tbl_size = 10;
struct diag_master_table entry;
-struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
-struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
int wrap_enabled;
uint16_t wrap_count;
void encode_rsp_and_send(int buf_length)
{
+ struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
+ struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
struct diag_smd_info *data = &(driver->smd_data[MODEM_DATA]);
+
+ if (buf_length > APPS_BUF_SIZE) {
+ pr_err("diag: In %s, invalid len %d, permissible len %d\n",
+ __func__, buf_length, APPS_BUF_SIZE);
+ return;
+ }
+
send.state = DIAG_STATE_START;
send.pkt = driver->apps_rsp_buf;
send.last = (void *)(driver->apps_rsp_buf + buf_length);
@@ -227,6 +244,124 @@
}
}
}
+int diag_add_hdlc_encoding(struct diag_smd_info *smd_info, void *buf,
+ int total_recd, uint8_t *encode_buf,
+ int *encoded_length)
+{
+ struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
+ struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
+ struct data_header {
+ uint8_t control_char;
+ uint8_t version;
+ uint16_t length;
+ };
+ struct data_header *header;
+ int header_size = sizeof(struct data_header);
+ uint8_t *end_control_char;
+ uint8_t *payload;
+ uint8_t *temp_buf;
+ uint8_t *temp_encode_buf;
+ int src_pkt_len;
+ int encoded_pkt_length;
+ int max_size;
+ int total_processed = 0;
+ int bytes_remaining;
+ int success = 1;
+
+ temp_buf = buf;
+ temp_encode_buf = encode_buf;
+ bytes_remaining = *encoded_length;
+ while (total_processed < total_recd) {
+ header = (struct data_header *)temp_buf;
+ /* Perform initial error checking */
+ if (header->control_char != CONTROL_CHAR ||
+ header->version != 1) {
+ success = 0;
+ break;
+ }
+ payload = temp_buf + header_size;
+ end_control_char = payload + header->length;
+ if (*end_control_char != CONTROL_CHAR) {
+ success = 0;
+ break;
+ }
+
+ max_size = 2 * header->length + 3;
+ if (bytes_remaining < max_size) {
+ pr_err("diag: In %s, Not enough room to encode remaining data for peripheral: %d, bytes available: %d, max_size: %d\n",
+ __func__, smd_info->peripheral,
+ bytes_remaining, max_size);
+ success = 0;
+ break;
+ }
+
+ /* Prepare for encoding the data */
+ send.state = DIAG_STATE_START;
+ send.pkt = payload;
+ send.last = (void *)(payload + header->length - 1);
+ send.terminate = 1;
+
+ enc.dest = temp_encode_buf;
+ enc.dest_last = (void *)(temp_encode_buf + max_size);
+ enc.crc = 0;
+ diag_hdlc_encode(&send, &enc);
+
+ /* Prepare for next packet */
+ src_pkt_len = (header_size + header->length + 1);
+ total_processed += src_pkt_len;
+ temp_buf += src_pkt_len;
+
+ encoded_pkt_length = (uint8_t *)enc.dest - temp_encode_buf;
+ bytes_remaining -= encoded_pkt_length;
+ temp_encode_buf = enc.dest;
+ }
+
+ *encoded_length = (int)(temp_encode_buf - encode_buf);
+
+ return success;
+}
+
+static int check_bufsize_for_encoding(struct diag_smd_info *smd_info, void *buf,
+ int total_recd)
+{
+ int buf_size = IN_BUF_SIZE;
+ int max_size = 2 * total_recd + 3;
+ unsigned char *temp_buf;
+
+ if (max_size > IN_BUF_SIZE) {
+ if (max_size < MAX_IN_BUF_SIZE) {
+ pr_err("diag: In %s, SMD sending packet of %d bytes that may expand to %d bytes, peripheral: %d\n",
+ __func__, total_recd, max_size,
+ smd_info->peripheral);
+ if (buf == smd_info->buf_in_1_raw) {
+ temp_buf = krealloc(smd_info->buf_in_1,
+ max_size, GFP_KERNEL);
+ if (temp_buf) {
+ smd_info->buf_in_1 = temp_buf;
+ buf_size = max_size;
+ } else {
+ buf_size = 0;
+ }
+ } else {
+ temp_buf = krealloc(smd_info->buf_in_2,
+ max_size, GFP_KERNEL);
+ if (temp_buf) {
+ smd_info->buf_in_2 = temp_buf;
+ buf_size = max_size;
+ } else {
+ buf_size = 0;
+ }
+ }
+ } else {
+ pr_err("diag: In %s, SMD sending packet of size %d. HDCL encoding can expand to more than %d bytes, peripheral: %d. Discarding.\n",
+ __func__, max_size, MAX_IN_BUF_SIZE,
+ smd_info->peripheral);
+ buf_size = 0;
+ }
+ }
+
+ return buf_size;
+}
void process_lock_enabling(struct diag_nrt_wake_lock *lock, int real_time)
{
@@ -317,7 +452,7 @@
/* Process the data read from the smd data channel */
int diag_process_smd_read_data(struct diag_smd_info *smd_info, void *buf,
- int total_recd)
+ int total_recd)
{
struct diag_request *write_ptr_modem = NULL;
int *in_busy_ptr = 0;
@@ -335,26 +470,74 @@
return 0;
}
- if (smd_info->buf_in_1 == buf) {
- write_ptr_modem = smd_info->write_ptr_1;
- in_busy_ptr = &smd_info->in_busy_1;
- } else if (smd_info->buf_in_2 == buf) {
- write_ptr_modem = smd_info->write_ptr_2;
- in_busy_ptr = &smd_info->in_busy_2;
- } else {
- pr_err("diag: In %s, no match for in_busy_1\n", __func__);
- }
+ /* If the data is already hdlc encoded */
+ if (!smd_info->encode_hdlc) {
+ if (smd_info->buf_in_1 == buf) {
+ write_ptr_modem = smd_info->write_ptr_1;
+ in_busy_ptr = &smd_info->in_busy_1;
+ } else if (smd_info->buf_in_2 == buf) {
+ write_ptr_modem = smd_info->write_ptr_2;
+ in_busy_ptr = &smd_info->in_busy_2;
+ } else {
+ pr_err("diag: In %s, no match for in_busy_1, peripheral: %d\n",
+ __func__, smd_info->peripheral);
+ }
- if (write_ptr_modem) {
- write_ptr_modem->length = total_recd;
- *in_busy_ptr = 1;
- err = diag_device_write(buf, smd_info->peripheral,
- write_ptr_modem);
- if (err) {
- /* Free up the buffer for future use */
- *in_busy_ptr = 0;
- pr_err_ratelimited("diag: In %s, diag_device_write error: %d\n",
- __func__, err);
+ if (write_ptr_modem) {
+ write_ptr_modem->length = total_recd;
+ *in_busy_ptr = 1;
+ err = diag_device_write(buf, smd_info->peripheral,
+ write_ptr_modem);
+ if (err) {
+ /* Free up the buffer for future use */
+ *in_busy_ptr = 0;
+ pr_err_ratelimited("diag: In %s, diag_device_write error: %d\n",
+ __func__, err);
+ }
+ }
+ } else {
+ /* The data is raw and needs to be hdlc encoded */
+ if (smd_info->buf_in_1_raw == buf) {
+ write_ptr_modem = smd_info->write_ptr_1;
+ in_busy_ptr = &smd_info->in_busy_1;
+ } else if (smd_info->buf_in_2_raw == buf) {
+ write_ptr_modem = smd_info->write_ptr_2;
+ in_busy_ptr = &smd_info->in_busy_2;
+ } else {
+ pr_err("diag: In %s, no match for in_busy_1, peripheral: %d\n",
+ __func__, smd_info->peripheral);
+ }
+
+ if (write_ptr_modem) {
+ int success = 0;
+ int write_length = 0;
+ unsigned char *write_buf = NULL;
+
+ write_length = check_bufsize_for_encoding(smd_info, buf,
+ total_recd);
+ if (write_length) {
+ write_buf = (buf == smd_info->buf_in_1_raw) ?
+ smd_info->buf_in_1 : smd_info->buf_in_2;
+ success = diag_add_hdlc_encoding(smd_info, buf,
+ total_recd, write_buf,
+ &write_length);
+ if (success) {
+ write_ptr_modem->length = write_length;
+ *in_busy_ptr = 1;
+ err = diag_device_write(write_buf,
+ smd_info->peripheral,
+ write_ptr_modem);
+ if (err) {
+ /*
+ * Free up the buffer for
+ * future use
+ */
+ *in_busy_ptr = 0;
+ pr_err_ratelimited("diag: In %s, diag_device_write error: %d\n",
+ __func__, err);
+ }
+ }
+ }
}
}
@@ -374,16 +557,45 @@
return;
}
- if (!smd_info->in_busy_1)
+ /* Determine the buffer to read the data into. */
+ if (smd_info->type == SMD_DATA_TYPE) {
+ /* If the data is raw and not hdlc encoded */
+ if (smd_info->encode_hdlc) {
+ if (!smd_info->in_busy_1)
+ buf = smd_info->buf_in_1_raw;
+ else if (!smd_info->in_busy_2)
+ buf = smd_info->buf_in_2_raw;
+ } else {
+ if (!smd_info->in_busy_1)
+ buf = smd_info->buf_in_1;
+ else if (!smd_info->in_busy_2)
+ buf = smd_info->buf_in_2;
+ }
+ } else if (smd_info->type == SMD_CMD_TYPE) {
+ /* If the data is raw and not hdlc encoded */
+ if (smd_info->encode_hdlc) {
+ if (!smd_info->in_busy_1)
+ buf = smd_info->buf_in_1_raw;
+ } else {
+ if (!smd_info->in_busy_1)
+ buf = smd_info->buf_in_1;
+ }
+ } else if (!smd_info->in_busy_1) {
buf = smd_info->buf_in_1;
- else if (!smd_info->in_busy_2 &&
- (smd_info->type == SMD_DATA_TYPE))
- buf = smd_info->buf_in_2;
+ }
+
+ if (!buf && (smd_info->type == SMD_DCI_TYPE ||
+ smd_info->type == SMD_DCI_CMD_TYPE))
+ diag_dci_try_deactivate_wakeup_source(smd_info->ch);
if (smd_info->ch && buf) {
temp_buf = buf;
pkt_len = smd_cur_packet_size(smd_info->ch);
+ if (pkt_len == 0 && (smd_info->type == SMD_DCI_TYPE ||
+ smd_info->type == SMD_DCI_CMD_TYPE))
+ diag_dci_try_deactivate_wakeup_source(smd_info->ch);
+
while (pkt_len && (pkt_len != total_recd)) {
loop_count++;
r = smd_read_avail(smd_info->ch);
@@ -402,7 +614,7 @@
} else {
pr_debug("diag: In %s, return from wait_event ch closed\n",
__func__);
- return;
+ goto fail_return;
}
}
total_recd += r;
@@ -415,13 +627,13 @@
} else {
pr_err("diag: In %s, SMD sending in packets more than %d bytes\n",
__func__, MAX_IN_BUF_SIZE);
- return;
+ goto fail_return;
}
}
if (pkt_len < r) {
pr_err("diag: In %s, SMD sending incorrect pkt\n",
__func__);
- return;
+ goto fail_return;
}
if (pkt_len > r) {
pr_debug("diag: In %s, SMD sending partial pkt %d %d %d %d %d %d\n",
@@ -452,6 +664,13 @@
(driver->logging_mode == MEMORY_DEVICE_MODE)) {
chk_logging_wakeup();
}
+ return;
+
+fail_return:
+ if (smd_info->type == SMD_DCI_TYPE ||
+ smd_info->type == SMD_DCI_CMD_TYPE)
+ diag_dci_try_deactivate_wakeup_source(smd_info->ch);
+ return;
}
void diag_read_smd_work_fn(struct work_struct *work)
@@ -462,32 +681,12 @@
diag_smd_send_req(smd_info);
}
-#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
-static void diag_mem_dev_mode_ready_update(int index, int hsic_updated)
-{
- if (hsic_updated) {
- unsigned long flags;
- spin_lock_irqsave(&driver->hsic_ready_spinlock, flags);
- driver->data_ready[index] |= USER_SPACE_DATA_TYPE;
- spin_unlock_irqrestore(&driver->hsic_ready_spinlock, flags);
- } else {
- driver->data_ready[index] |= USER_SPACE_DATA_TYPE;
- }
-}
-#else
-static void diag_mem_dev_mode_ready_update(int index, int hsic_updated)
-{
- (void) hsic_updated;
- driver->data_ready[index] |= USER_SPACE_DATA_TYPE;
-}
-#endif
int diag_device_write(void *buf, int data_type, struct diag_request *write_ptr)
{
int i, err = 0, index;
index = 0;
if (driver->logging_mode == MEMORY_DEVICE_MODE) {
- int hsic_updated = 0;
if (data_type == APPS_DATA) {
for (i = 0; i < driver->buf_tbl_size; i++)
if (driver->buf_tbl[i].length == 0) {
@@ -508,7 +707,6 @@
else if (data_type == HSIC_DATA || data_type == HSIC_2_DATA) {
unsigned long flags;
int foundIndex = -1;
- hsic_updated = 1;
index = data_type - HSIC_DATA;
spin_lock_irqsave(&diag_hsic[index].hsic_spinlock,
flags);
@@ -541,8 +739,8 @@
driver->logging_process_id)
break;
if (i < driver->num_clients) {
- diag_mem_dev_mode_ready_update(i, hsic_updated);
pr_debug("diag: wake up logging process\n");
+ driver->data_ready[i] |= USER_SPACE_DATA_TYPE;
wake_up_interruptible(&driver->wait_q);
} else
return -EINVAL;
@@ -550,7 +748,7 @@
if ((data_type >= MODEM_DATA) && (data_type <= WCNSS_DATA)) {
driver->smd_data[data_type].in_busy_1 = 0;
driver->smd_data[data_type].in_busy_2 = 0;
- queue_work(driver->diag_wq,
+ queue_work(driver->smd_data[data_type].wq,
&(driver->smd_data[data_type].
diag_read_smd_work));
if (data_type == MODEM_DATA &&
@@ -763,6 +961,77 @@
}
}
+void diag_process_stm_mask(uint8_t cmd, uint8_t data_mask, int data_type,
+ uint8_t *rsp_supported, uint8_t *rsp_smd_comply)
+{
+ int status = 0;
+ if (data_type >= MODEM_DATA && data_type <= WCNSS_DATA) {
+ if (driver->peripheral_supports_stm[data_type]) {
+ status = diag_send_stm_state(
+ &driver->smd_cntl[data_type], cmd);
+ if (status == 1)
+ *rsp_smd_comply |= data_mask;
+ *rsp_supported |= data_mask;
+ } else if (driver->smd_cntl[data_type].ch) {
+ *rsp_smd_comply |= data_mask;
+ }
+ if ((*rsp_smd_comply & data_mask) &&
+ (*rsp_supported & data_mask))
+ driver->stm_state[data_type] = cmd;
+
+ driver->stm_state_requested[data_type] = cmd;
+ } else if (data_type == APPS_DATA) {
+ *rsp_supported |= data_mask;
+ *rsp_smd_comply |= data_mask;
+ driver->stm_state[data_type] = cmd;
+ driver->stm_state_requested[data_type] = cmd;
+ }
+}
+
+int diag_process_stm_cmd(unsigned char *buf)
+{
+ uint8_t version = *(buf+STM_CMD_VERSION_OFFSET);
+ uint8_t mask = *(buf+STM_CMD_MASK_OFFSET);
+ uint8_t cmd = *(buf+STM_CMD_DATA_OFFSET);
+ uint8_t rsp_supported = 0;
+ uint8_t rsp_smd_comply = 0;
+ int valid_command = 1;
+ int i;
+
+ /* Check if command is valid */
+ if ((version != 1) || (mask == 0) || (0 != (mask >> 4)) ||
+ (cmd != ENABLE_STM && cmd != DISABLE_STM)) {
+ valid_command = 0;
+ } else {
+ if (mask & DIAG_STM_MODEM)
+ diag_process_stm_mask(cmd, DIAG_STM_MODEM, MODEM_DATA,
+ &rsp_supported, &rsp_smd_comply);
+
+ if (mask & DIAG_STM_LPASS)
+ diag_process_stm_mask(cmd, DIAG_STM_LPASS, LPASS_DATA,
+ &rsp_supported, &rsp_smd_comply);
+
+ if (mask & DIAG_STM_WCNSS)
+ diag_process_stm_mask(cmd, DIAG_STM_WCNSS, WCNSS_DATA,
+ &rsp_supported, &rsp_smd_comply);
+
+ if (mask & DIAG_STM_APPS)
+ diag_process_stm_mask(cmd, DIAG_STM_APPS, APPS_DATA,
+ &rsp_supported, &rsp_smd_comply);
+ }
+
+ for (i = 0; i < STM_CMD_NUM_BYTES; i++)
+ driver->apps_rsp_buf[i] = *(buf+i);
+
+ driver->apps_rsp_buf[STM_RSP_VALID_INDEX] = valid_command;
+ driver->apps_rsp_buf[STM_RSP_SUPPORTED_INDEX] = rsp_supported;
+ driver->apps_rsp_buf[STM_RSP_SMD_COMPLY_INDEX] = rsp_smd_comply;
+
+ encode_rsp_and_send(STM_RSP_NUM_BYTES-1);
+
+ return 0;
+}
+
int diag_process_apps_pkt(unsigned char *buf, int len)
{
uint16_t subsys_cmd_code;
@@ -838,6 +1107,9 @@
*(uint32_t *)(driver->apps_rsp_buf+4) = PKT_SIZE;
encode_rsp_and_send(7);
return 0;
+ } else if ((*buf == 0x4b) && (*(buf+1) == 0x12) &&
+ (*(uint16_t *)(buf+2) == 0x020E)) {
+ return diag_process_stm_cmd(buf);
}
/* Check for Apps Only & get event mask request */
else if (!(driver->smd_data[MODEM_DATA].ch) && chk_apps_only() &&
@@ -1216,10 +1488,12 @@
{
int i;
- if (index > 490) {
- pr_err("diag: error response too huge, aborting\n");
+ /* -1 to accomodate the first byte 0x13 */
+ if (index > APPS_BUF_SIZE-1) {
+ pr_err("diag: cannot send err rsp, huge length: %d\n", index);
return;
}
+
driver->apps_rsp_buf[0] = 0x13; /* error code 13 */
for (i = 0; i < index; i++)
driver->apps_rsp_buf[i+1] = *(driver->hdlc_buf+i);
@@ -1331,7 +1605,7 @@
driver->smd_data[i].in_busy_2 = 0;
if (queue)
/* Poll SMD data channels to check for data */
- queue_work(driver->diag_wq,
+ queue_work(driver->smd_data[i].wq,
&(driver->smd_data[i].diag_read_smd_work));
}
@@ -1384,6 +1658,8 @@
/* Poll SMD CNTL channels to check for data */
diag_smd_notify(&(driver->smd_cntl[i]), SMD_EVENT_DATA);
}
+ queue_work(driver->diag_real_time_wq,
+ &driver->diag_real_time_work);
/* Poll USB channel to check for data*/
queue_work(driver->diag_wq, &(driver->diag_read_work));
@@ -1419,6 +1695,8 @@
}
}
}
+ queue_work(driver->diag_real_time_wq,
+ &driver->diag_real_time_work);
#ifdef CONFIG_DIAG_SDIO_PIPE
if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())
if (driver->mdm_ch && !IS_ERR(driver->mdm_ch))
@@ -1437,19 +1715,24 @@
for (i = 0; i < num_channels; i++) {
if (buf == (void *)data[i].buf_in_1) {
data[i].in_busy_1 = 0;
- queue_work(driver->diag_wq,
- &(data[i].diag_read_smd_work));
found_it = 1;
break;
} else if (buf == (void *)data[i].buf_in_2) {
data[i].in_busy_2 = 0;
- queue_work(driver->diag_wq,
- &(data[i].diag_read_smd_work));
found_it = 1;
break;
}
}
+ if (found_it) {
+ if (data[i].type == SMD_DATA_TYPE)
+ queue_work(data[i].wq,
+ &(data[i].diag_read_smd_work));
+ else
+ queue_work(driver->diag_wq,
+ &(data[i].diag_read_smd_work));
+ }
+
return found_it;
}
@@ -1588,6 +1871,9 @@
/* Notify the clients of the close */
diag_dci_notify_client(smd_info->peripheral_mask,
DIAG_STATUS_CLOSED);
+ } else if (smd_info->type == SMD_CNTL_TYPE) {
+ diag_cntl_stm_notify(smd_info,
+ CLEAR_PERIPHERAL_STM_STATE);
}
return;
} else if (event == SMD_EVENT_OPEN) {
@@ -1614,11 +1900,17 @@
wake_up(&driver->smd_wait_q);
if (smd_info->type == SMD_DCI_TYPE ||
- smd_info->type == SMD_DCI_CMD_TYPE)
+ smd_info->type == SMD_DCI_CMD_TYPE) {
+ if (event == SMD_EVENT_DATA)
+ diag_dci_try_activate_wakeup_source(smd_info->ch);
queue_work(driver->diag_dci_wq,
&(smd_info->diag_read_smd_work));
- else
+ } else if (smd_info->type == SMD_DATA_TYPE) {
+ queue_work(smd_info->wq,
+ &(smd_info->diag_read_smd_work));
+ } else {
queue_work(driver->diag_wq, &(smd_info->diag_read_smd_work));
+ }
}
static int diag_smd_probe(struct platform_device *pdev)
@@ -1746,8 +2038,10 @@
void diag_smd_destructor(struct diag_smd_info *smd_info)
{
- if (smd_info->type == SMD_DATA_TYPE)
+ if (smd_info->type == SMD_DATA_TYPE) {
wake_lock_destroy(&smd_info->nrt_lock.read_lock);
+ destroy_workqueue(smd_info->wq);
+ }
if (smd_info->ch)
smd_close(smd_info->ch);
@@ -1758,6 +2052,8 @@
kfree(smd_info->buf_in_2);
kfree(smd_info->write_ptr_1);
kfree(smd_info->write_ptr_2);
+ kfree(smd_info->buf_in_1_raw);
+ kfree(smd_info->buf_in_2_raw);
}
int diag_smd_constructor(struct diag_smd_info *smd_info, int peripheral,
@@ -1765,6 +2061,7 @@
{
smd_info->peripheral = peripheral;
smd_info->type = type;
+ smd_info->encode_hdlc = 0;
mutex_init(&smd_info->smd_ch_mutex);
switch (peripheral) {
@@ -1817,6 +2114,58 @@
goto err;
kmemleak_not_leak(smd_info->write_ptr_2);
}
+ if (driver->supports_apps_hdlc_encoding) {
+ /* In support of hdlc encoding */
+ if (smd_info->buf_in_1_raw == NULL) {
+ smd_info->buf_in_1_raw = kzalloc(IN_BUF_SIZE,
+ GFP_KERNEL);
+ if (smd_info->buf_in_1_raw == NULL)
+ goto err;
+ kmemleak_not_leak(smd_info->buf_in_1_raw);
+ }
+ if (smd_info->buf_in_2_raw == NULL) {
+ smd_info->buf_in_2_raw = kzalloc(IN_BUF_SIZE,
+ GFP_KERNEL);
+ if (smd_info->buf_in_2_raw == NULL)
+ goto err;
+ kmemleak_not_leak(smd_info->buf_in_2_raw);
+ }
+ }
+ }
+
+ if (smd_info->type == SMD_CMD_TYPE &&
+ driver->supports_apps_hdlc_encoding) {
+ /* In support of hdlc encoding */
+ if (smd_info->buf_in_1_raw == NULL) {
+ smd_info->buf_in_1_raw = kzalloc(IN_BUF_SIZE,
+ GFP_KERNEL);
+ if (smd_info->buf_in_1_raw == NULL)
+ goto err;
+ kmemleak_not_leak(smd_info->buf_in_1_raw);
+ }
+ }
+
+ /* The smd data type needs separate work queues for reads */
+ if (type == SMD_DATA_TYPE) {
+ switch (peripheral) {
+ case MODEM_DATA:
+ smd_info->wq = create_singlethread_workqueue(
+ "diag_modem_data_read_wq");
+ break;
+ case LPASS_DATA:
+ smd_info->wq = create_singlethread_workqueue(
+ "diag_lpass_data_read_wq");
+ break;
+ case WCNSS_DATA:
+ smd_info->wq = create_singlethread_workqueue(
+ "diag_wcnss_data_read_wq");
+ break;
+ default:
+ smd_info->wq = NULL;
+ break;
+ }
+ } else {
+ smd_info->wq = NULL;
}
INIT_WORK(&(smd_info->diag_read_smd_work), diag_read_smd_work_fn);
@@ -1829,20 +2178,27 @@
* information to the update function.
*/
smd_info->notify_context = 0;
+ smd_info->general_context = 0;
switch (type) {
case SMD_DATA_TYPE:
case SMD_CMD_TYPE:
INIT_WORK(&(smd_info->diag_notify_update_smd_work),
diag_clean_reg_fn);
+ INIT_WORK(&(smd_info->diag_general_smd_work),
+ diag_cntl_smd_work_fn);
break;
case SMD_CNTL_TYPE:
INIT_WORK(&(smd_info->diag_notify_update_smd_work),
diag_mask_update_fn);
+ INIT_WORK(&(smd_info->diag_general_smd_work),
+ diag_cntl_smd_work_fn);
break;
case SMD_DCI_TYPE:
case SMD_DCI_CMD_TYPE:
INIT_WORK(&(smd_info->diag_notify_update_smd_work),
diag_update_smd_dci_work_fn);
+ INIT_WORK(&(smd_info->diag_general_smd_work),
+ diag_cntl_smd_work_fn);
break;
default:
pr_err("diag: In %s, unknown type, type: %d\n", __func__, type);
@@ -1902,6 +2258,8 @@
kfree(smd_info->buf_in_2);
kfree(smd_info->write_ptr_1);
kfree(smd_info->write_ptr_2);
+ kfree(smd_info->buf_in_1_raw);
+ kfree(smd_info->buf_in_2_raw);
return 0;
}
@@ -1924,11 +2282,19 @@
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;
mutex_init(&driver->diag_hdlc_mutex);
mutex_init(&driver->diag_cntl_mutex);
- for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++)
+ for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) {
driver->separate_cmdrsp[i] = 0;
+ driver->peripheral_supports_stm[i] = DISABLE_STM;
+ }
+
+ for (i = 0; i < NUM_STM_PROCESSORS; i++) {
+ driver->stm_state_requested[i] = DISABLE_STM;
+ driver->stm_state[i] = DISABLE_STM;
+ }
for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
success = diag_smd_constructor(&driver->smd_data[i], i,
diff --git a/drivers/char/diag/diagfwd_bridge.c b/drivers/char/diag/diagfwd_bridge.c
index 8c07219b..143959b 100644
--- a/drivers/char/diag/diagfwd_bridge.c
+++ b/drivers/char/diag/diagfwd_bridge.c
@@ -35,7 +35,7 @@
/* diagfwd_connect_bridge is called when the USB mdm channel is connected */
int diagfwd_connect_bridge(int process_cable)
{
- int i;
+ uint8_t i;
pr_debug("diag: in %s\n", __func__);
@@ -45,7 +45,7 @@
return 0;
}
-void connect_bridge(int process_cable, int index)
+void connect_bridge(int process_cable, uint8_t index)
{
int err;
@@ -61,10 +61,18 @@
diag_bridge[index].usb_connected = 1;
}
- if (index == SMUX && driver->diag_smux_enabled) {
- driver->in_busy_smux = 0;
- diagfwd_connect_smux();
+ if (index == SMUX) {
+ if (driver->diag_smux_enabled) {
+ driver->in_busy_smux = 0;
+ diagfwd_connect_smux();
+ }
} else {
+ if (index >= MAX_HSIC_CH) {
+ pr_err("diag: Invalid hsic channel index %d in %s\n",
+ index, __func__);
+ mutex_unlock(&diag_bridge[index].bridge_mutex);
+ return;
+ }
if (diag_hsic[index].hsic_device_enabled &&
(driver->logging_mode != MEMORY_DEVICE_MODE ||
diag_hsic[index].hsic_data_requested)) {
@@ -74,7 +82,7 @@
* device is not open */
if (!diag_hsic[index].hsic_device_opened) {
hsic_diag_bridge_ops[index].ctxt =
- (void *)(index);
+ (void *)(int)(index);
err = diag_bridge_open(index,
&hsic_diag_bridge_ops[index]);
if (err) {
diff --git a/drivers/char/diag/diagfwd_bridge.h b/drivers/char/diag/diagfwd_bridge.h
index 88c96ab..ae1259b 100644
--- a/drivers/char/diag/diagfwd_bridge.h
+++ b/drivers/char/diag/diagfwd_bridge.h
@@ -21,7 +21,7 @@
#define SMUX 4
int diagfwd_connect_bridge(int);
-void connect_bridge(int, int);
+void connect_bridge(int, uint8_t);
int diagfwd_disconnect_bridge(int);
void diagfwd_bridge_init(int index);
void diagfwd_bridge_exit(void);
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index 13cbc8f..e0deef3 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -40,6 +40,80 @@
smd_info->notify_context = 0;
}
+void diag_cntl_smd_work_fn(struct work_struct *work)
+{
+ struct diag_smd_info *smd_info = container_of(work,
+ struct diag_smd_info,
+ diag_general_smd_work);
+
+ if (!smd_info || smd_info->type != SMD_CNTL_TYPE)
+ return;
+
+ if (smd_info->general_context == UPDATE_PERIPHERAL_STM_STATE) {
+ if (driver->peripheral_supports_stm[smd_info->peripheral] ==
+ ENABLE_STM) {
+ int status = 0;
+ int index = smd_info->peripheral;
+ status = diag_send_stm_state(smd_info,
+ (uint8_t)(driver->stm_state_requested[index]));
+ if (status == 1)
+ driver->stm_state[index] =
+ driver->stm_state_requested[index];
+ }
+ }
+ smd_info->general_context = 0;
+}
+
+void diag_cntl_stm_notify(struct diag_smd_info *smd_info, int action)
+{
+ if (!smd_info || smd_info->type != SMD_CNTL_TYPE)
+ return;
+
+ if (action == CLEAR_PERIPHERAL_STM_STATE)
+ driver->peripheral_supports_stm[smd_info->peripheral] =
+ DISABLE_STM;
+}
+
+static void process_stm_feature(struct diag_smd_info *smd_info,
+ uint8_t feature_mask)
+{
+ if (feature_mask & F_DIAG_OVER_STM) {
+ driver->peripheral_supports_stm[smd_info->peripheral] =
+ ENABLE_STM;
+ smd_info->general_context = UPDATE_PERIPHERAL_STM_STATE;
+ queue_work(driver->diag_cntl_wq,
+ &(smd_info->diag_general_smd_work));
+ } else {
+ driver->peripheral_supports_stm[smd_info->peripheral] =
+ DISABLE_STM;
+ }
+}
+
+static void process_hdlc_encoding_feature(struct diag_smd_info *smd_info,
+ uint8_t feature_mask)
+{
+ /*
+ * Check if apps supports hdlc encoding and the
+ * peripheral supports apps hdlc encoding
+ */
+ if (driver->supports_apps_hdlc_encoding &&
+ (feature_mask & F_DIAG_HDLC_ENCODE_IN_APPS_MASK)) {
+ driver->smd_data[smd_info->peripheral].encode_hdlc =
+ ENABLE_APPS_HDLC_ENCODING;
+ if (driver->separate_cmdrsp[smd_info->peripheral] &&
+ smd_info->peripheral < NUM_SMD_CMD_CHANNELS)
+ driver->smd_cmd[smd_info->peripheral].encode_hdlc =
+ ENABLE_APPS_HDLC_ENCODING;
+ } else {
+ driver->smd_data[smd_info->peripheral].encode_hdlc =
+ DISABLE_APPS_HDLC_ENCODING;
+ if (driver->separate_cmdrsp[smd_info->peripheral] &&
+ smd_info->peripheral < NUM_SMD_CMD_CHANNELS)
+ driver->smd_cmd[smd_info->peripheral].encode_hdlc =
+ DISABLE_APPS_HDLC_ENCODING;
+ }
+}
+
/* Process the data read from the smd control channel */
int diag_process_smd_cntl_read_data(struct diag_smd_info *smd_info, void *buf,
int total_recd)
@@ -120,8 +194,9 @@
uint8_t feature_mask = 0;
int feature_mask_len = *(int *)(buf+8);
if (feature_mask_len > 0) {
+ int periph = smd_info->peripheral;
feature_mask = *(uint8_t *)(buf+12);
- if (smd_info->peripheral == MODEM_DATA)
+ if (periph == MODEM_DATA)
driver->log_on_demand_support =
feature_mask &
F_DIAG_LOG_ON_DEMAND_RSP_ON_MASTER;
@@ -132,13 +207,22 @@
*/
if (driver->supports_separate_cmdrsp &&
(feature_mask & F_DIAG_REQ_RSP_CHANNEL))
- driver->separate_cmdrsp
- [smd_info->peripheral] =
+ driver->separate_cmdrsp[periph] =
ENABLE_SEPARATE_CMDRSP;
else
- driver->separate_cmdrsp
- [smd_info->peripheral] =
+ driver->separate_cmdrsp[periph] =
DISABLE_SEPARATE_CMDRSP;
+ /*
+ * Check if apps supports hdlc encoding and the
+ * peripheral supports apps hdlc encoding
+ */
+ process_hdlc_encoding_feature(smd_info,
+ feature_mask);
+ if (feature_mask_len > 1) {
+ feature_mask = *(uint8_t *)(buf+13);
+ process_stm_feature(smd_info,
+ feature_mask);
+ }
}
flag = 1;
} else if (type != DIAG_CTRL_MSG_REG) {
@@ -151,15 +235,85 @@
return flag;
}
-void diag_send_diag_mode_update(int real_time)
+void diag_update_proc_vote(uint16_t proc, uint8_t vote)
{
- int i;
-
- for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++)
- diag_send_diag_mode_update_by_smd(&driver->smd_cntl[i],
- real_time);
+ mutex_lock(&driver->real_time_mutex);
+ if (vote)
+ driver->proc_active_mask |= proc;
+ else {
+ driver->proc_active_mask &= ~proc;
+ driver->proc_rt_vote_mask |= proc;
+ }
+ mutex_unlock(&driver->real_time_mutex);
}
+void diag_update_real_time_vote(uint16_t proc, uint8_t real_time)
+{
+ mutex_lock(&driver->real_time_mutex);
+ if (real_time)
+ driver->proc_rt_vote_mask |= proc;
+ else
+ driver->proc_rt_vote_mask &= ~proc;
+ mutex_unlock(&driver->real_time_mutex);
+}
+
+#ifdef CONFIG_DIAG_OVER_USB
+void diag_real_time_work_fn(struct work_struct *work)
+{
+ int temp_real_time = MODE_REALTIME, i;
+
+ /* If any of the process is voting for Real time, then Diag
+ should be in real time mode irrespective of other clauses. If
+ USB is connected, check what the memory device process is
+ voting for. If it is voting for Non real time, the final mode
+ should be Non real time, real time otherwise. If USB is
+ disconncted and no process is voting for real time, the
+ resultant mode should be Non Real Time.
+ */
+ if ((driver->proc_rt_vote_mask & driver->proc_active_mask) &&
+ (driver->proc_active_mask != 0))
+ temp_real_time = MODE_REALTIME;
+ else if (driver->usb_connected)
+ if ((driver->proc_rt_vote_mask & DIAG_PROC_MEMORY_DEVICE) == 0)
+ temp_real_time = MODE_NONREALTIME;
+ else
+ temp_real_time = MODE_REALTIME;
+ else
+ temp_real_time = MODE_NONREALTIME;
+
+ if (temp_real_time != driver->real_time_mode) {
+ for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++)
+ diag_send_diag_mode_update_by_smd(&driver->smd_cntl[i],
+ temp_real_time);
+ } else {
+ pr_info("diag: did not update real time mode, already in the req mode %d",
+ temp_real_time);
+ }
+ if (driver->real_time_update_busy > 0)
+ driver->real_time_update_busy--;
+}
+#else
+void diag_real_time_work_fn(struct work_struct *work)
+{
+ int temp_real_time = MODE_REALTIME, i;
+
+ if (!(driver->proc_rt_vote_mask & driver->proc_active_mask) &&
+ (driver->proc_active_mask != 0))
+ temp_real_time = MODE_NONREALTIME;
+
+ if (temp_real_time != driver->real_time_mode) {
+ for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++)
+ diag_send_diag_mode_update_by_smd(&driver->smd_cntl[i],
+ temp_real_time);
+ } else {
+ pr_warn("diag: did not update real time mode, already in the req mode %d",
+ temp_real_time);
+ }
+ if (driver->real_time_update_busy > 0)
+ driver->real_time_update_busy--;
+}
+#endif
+
void diag_send_diag_mode_update_by_smd(struct diag_smd_info *smd_info,
int real_time)
{
@@ -228,6 +382,56 @@
mutex_unlock(&driver->diag_cntl_mutex);
}
+int diag_send_stm_state(struct diag_smd_info *smd_info,
+ uint8_t stm_control_data)
+{
+ struct diag_ctrl_msg_stm stm_msg;
+ int msg_size = sizeof(struct diag_ctrl_msg_stm);
+ int retry_count = 0;
+ int wr_size = 0;
+ int success = 0;
+
+ if (!smd_info || (smd_info->type != SMD_CNTL_TYPE) ||
+ (driver->peripheral_supports_stm[smd_info->peripheral] ==
+ DISABLE_STM)) {
+ return -EINVAL;
+ }
+
+ if (smd_info->ch) {
+ stm_msg.ctrl_pkt_id = 21;
+ stm_msg.ctrl_pkt_data_len = 5;
+ stm_msg.version = 1;
+ stm_msg.control_data = stm_control_data;
+ while (retry_count < 3) {
+ wr_size = smd_write(smd_info->ch, &stm_msg, msg_size);
+ if (wr_size == -ENOMEM) {
+ /*
+ * The smd channel is full. Delay while
+ * smd processes existing data and smd
+ * has memory become available. The delay
+ * of 10000 was determined empirically as
+ * best value to use.
+ */
+ retry_count++;
+ usleep_range(10000, 10000);
+ } else {
+ success = 1;
+ break;
+ }
+ }
+ if (wr_size != msg_size) {
+ pr_err("diag: In %s, proc %d fail STM update %d, tried %d",
+ __func__, smd_info->peripheral, wr_size,
+ msg_size);
+ success = 0;
+ }
+ } else {
+ pr_err("diag: In %s, ch invalid, STM update on proc %d\n",
+ __func__, smd_info->peripheral);
+ }
+ return success;
+}
+
static int diag_smd_cntl_probe(struct platform_device *pdev)
{
int r = 0;
@@ -343,6 +547,7 @@
diag_smd_destructor(&driver->smd_cntl[i]);
destroy_workqueue(driver->diag_cntl_wq);
+ destroy_workqueue(driver->diag_real_time_wq);
platform_driver_unregister(&msm_smd_ch1_cntl_driver);
platform_driver_unregister(&diag_smd_lite_cntl_driver);
diff --git a/drivers/char/diag/diagfwd_cntl.h b/drivers/char/diag/diagfwd_cntl.h
index 02b9757..d79195c 100644
--- a/drivers/char/diag/diagfwd_cntl.h
+++ b/drivers/char/diag/diagfwd_cntl.h
@@ -45,10 +45,24 @@
* new Data Rx and DCI Rx channels
*/
#define F_DIAG_REQ_RSP_CHANNEL 0x10
+/* Denotes we support diag over stm */
+#define F_DIAG_OVER_STM 0x02
+
+ /* Perform hdlc encoding of data coming from smd channel */
+#define F_DIAG_HDLC_ENCODE_IN_APPS_MASK 0x40
#define ENABLE_SEPARATE_CMDRSP 1
#define DISABLE_SEPARATE_CMDRSP 0
+#define ENABLE_STM 1
+#define DISABLE_STM 0
+
+#define UPDATE_PERIPHERAL_STM_STATE 1
+#define CLEAR_PERIPHERAL_STM_STATE 2
+
+#define ENABLE_APPS_HDLC_ENCODING 1
+#define DISABLE_APPS_HDLC_ENCODING 0
+
struct cmd_code_range {
uint16_t cmd_code_lo;
uint16_t cmd_code_hi;
@@ -117,15 +131,28 @@
uint32_t event_stale_timer_val;
} __packed;
+struct diag_ctrl_msg_stm {
+ uint32_t ctrl_pkt_id;
+ uint32_t ctrl_pkt_data_len;
+ uint32_t version;
+ uint8_t control_data;
+} __packed;
+
void diagfwd_cntl_init(void);
void diagfwd_cntl_exit(void);
void diag_read_smd_cntl_work_fn(struct work_struct *);
void diag_notify_ctrl_update_fn(struct work_struct *work);
void diag_clean_reg_fn(struct work_struct *work);
+void diag_cntl_smd_work_fn(struct work_struct *work);
int diag_process_smd_cntl_read_data(struct diag_smd_info *smd_info, void *buf,
int total_recd);
-void diag_send_diag_mode_update(int real_time);
void diag_send_diag_mode_update_by_smd(struct diag_smd_info *smd_info,
int real_time);
+void diag_update_proc_vote(uint16_t proc, uint8_t vote);
+void diag_update_real_time_vote(uint16_t proc, uint8_t real_time);
+void diag_real_time_work_fn(struct work_struct *work);
+int diag_send_stm_state(struct diag_smd_info *smd_info,
+ uint8_t stm_control_data);
+void diag_cntl_stm_notify(struct diag_smd_info *smd_info, int action);
#endif
diff --git a/drivers/char/diag/diagfwd_hsic.c b/drivers/char/diag/diagfwd_hsic.c
index fa46aab..d1f72a8 100644
--- a/drivers/char/diag/diagfwd_hsic.c
+++ b/drivers/char/diag/diagfwd_hsic.c
@@ -203,6 +203,7 @@
/* The write of the data to the HSIC bridge is complete */
diag_hsic[index].in_busy_hsic_write = 0;
+ wake_up_interruptible(&driver->wait_q);
if (!diag_hsic[index].hsic_ch) {
pr_err("DIAG in %s: hsic_ch == 0, ch = %d\n", __func__, index);
diff --git a/drivers/char/diag/diagmem.c b/drivers/char/diag/diagmem.c
index f22b4c2..a6ef3ca 100644
--- a/drivers/char/diag/diagmem.c
+++ b/drivers/char/diag/diagmem.c
@@ -151,8 +151,9 @@
if (diag_hsic[index].diag_hsic_pool &&
(diag_hsic[index].hsic_inited == 0)) {
if (diag_hsic[index].count_hsic_pool == 0) {
- mempool_destroy(driver->diag_hdlc_pool);
- driver->diag_hdlc_pool = NULL;
+ mempool_destroy(
+ diag_hsic[index].diag_hsic_pool);
+ diag_hsic[index].diag_hsic_pool = NULL;
} else if (pool_type == POOL_TYPE_ALL)
pr_err("Unable to destroy HDLC mempool for ch %d"
, index);
diff --git a/drivers/coresight/Kconfig b/drivers/coresight/Kconfig
index 7ec83dd..5e2acfb 100644
--- a/drivers/coresight/Kconfig
+++ b/drivers/coresight/Kconfig
@@ -24,6 +24,15 @@
config HAVE_CORESIGHT_SINK
bool
+config CORESIGHT_FUSE
+ bool "CoreSight Fuse driver"
+ help
+ This driver provides support for CoreSight Fuse state checks that
+ other CoreSight drivers can query to determine existence of
+ Hardware functionality they support. Drivers can then take necessary
+ actions like failing the probe if the Hardware they manage is
+ functionally disabled.
+
config CORESIGHT_CTI
bool "CoreSight Cross Trigger Interface driver"
help
diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile
index 2b14f86..23352a7 100644
--- a/drivers/coresight/Makefile
+++ b/drivers/coresight/Makefile
@@ -2,6 +2,7 @@
# Makefile for CoreSight drivers.
#
obj-$(CONFIG_CORESIGHT) += coresight.o
+obj-$(CONFIG_CORESIGHT_FUSE) += coresight-fuse.o
obj-$(CONFIG_CORESIGHT_CTI) += coresight-cti.o
obj-$(CONFIG_CORESIGHT_CSR) += coresight-csr.o
obj-$(CONFIG_CORESIGHT_TMC) += coresight-tmc.o
diff --git a/drivers/coresight/coresight-csr.c b/drivers/coresight/coresight-csr.c
index 8195184..6efab5b 100644
--- a/drivers/coresight/coresight-csr.c
+++ b/drivers/coresight/coresight-csr.c
@@ -65,6 +65,7 @@
#define CSR_QDSSPWRREQIGNORE (0x060)
#define CSR_QDSSSPARE (0x064)
#define CSR_IPCAT (0x068)
+#define CSR_BYTECNTVAL (0x06C)
#define BLKSIZE_256 0
#define BLKSIZE_512 1
@@ -159,6 +160,19 @@
}
EXPORT_SYMBOL(coresight_csr_hwctrl_set);
+void coresight_csr_set_byte_cntr(uint32_t count)
+{
+ struct csr_drvdata *drvdata = csrdrvdata;
+
+ CSR_UNLOCK(drvdata);
+
+ csr_writel(drvdata, count, CSR_BYTECNTVAL);
+ mb();
+
+ CSR_LOCK(drvdata);
+}
+EXPORT_SYMBOL(coresight_csr_set_byte_cntr);
+
static int __devinit csr_probe(struct platform_device *pdev)
{
int ret;
@@ -168,6 +182,9 @@
struct resource *res;
struct coresight_desc *desc;
+ if (coresight_fuse_access_disabled())
+ return -EPERM;
+
if (pdev->dev.of_node) {
pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
if (IS_ERR(pdata))
diff --git a/drivers/coresight/coresight-cti.c b/drivers/coresight/coresight-cti.c
index 6a8d412..d139583 100644
--- a/drivers/coresight/coresight-cti.c
+++ b/drivers/coresight/coresight-cti.c
@@ -107,22 +107,37 @@
return 0;
}
-static void __cti_map_trigin(struct cti_drvdata *drvdata, int trig, int ch)
+static int __cti_map_trigin(struct cti_drvdata *drvdata, int trig, int ch)
{
uint32_t ctien;
+ int ret;
+
+ if (drvdata->refcnt == 0) {
+ ret = cti_enable(drvdata);
+ if (ret)
+ return ret;
+ }
CTI_UNLOCK(drvdata);
ctien = cti_readl(drvdata, CTIINEN(trig));
+ if (ctien & (0x1 << ch))
+ goto out;
cti_writel(drvdata, (ctien | 0x1 << ch), CTIINEN(trig));
CTI_LOCK(drvdata);
+
+ drvdata->refcnt++;
+ return 0;
+out:
+ CTI_LOCK(drvdata);
+ return 0;
}
int coresight_cti_map_trigin(struct coresight_cti *cti, int trig, int ch)
{
struct cti_drvdata *drvdata;
- int ret = 0;
+ int ret;
if (IS_ERR_OR_NULL(cti))
return -EINVAL;
@@ -134,36 +149,43 @@
drvdata = to_cti_drvdata(cti);
mutex_lock(&drvdata->mutex);
- if (drvdata->refcnt == 0) {
- ret = cti_enable(drvdata);
- if (ret)
- goto err;
- }
- drvdata->refcnt++;
-
- __cti_map_trigin(drvdata, trig, ch);
-err:
+ ret = __cti_map_trigin(drvdata, trig, ch);
mutex_unlock(&drvdata->mutex);
return ret;
}
EXPORT_SYMBOL(coresight_cti_map_trigin);
-static void __cti_map_trigout(struct cti_drvdata *drvdata, int trig, int ch)
+static int __cti_map_trigout(struct cti_drvdata *drvdata, int trig, int ch)
{
uint32_t ctien;
+ int ret;
+
+ if (drvdata->refcnt == 0) {
+ ret = cti_enable(drvdata);
+ if (ret)
+ return ret;
+ }
CTI_UNLOCK(drvdata);
ctien = cti_readl(drvdata, CTIOUTEN(trig));
+ if (ctien & (0x1 << ch))
+ goto out;
cti_writel(drvdata, (ctien | 0x1 << ch), CTIOUTEN(trig));
CTI_LOCK(drvdata);
+
+ drvdata->refcnt++;
+ return 0;
+out:
+ CTI_LOCK(drvdata);
+ return 0;
}
int coresight_cti_map_trigout(struct coresight_cti *cti, int trig, int ch)
{
struct cti_drvdata *drvdata;
- int ret = 0;
+ int ret;
if (IS_ERR_OR_NULL(cti))
return -EINVAL;
@@ -175,15 +197,7 @@
drvdata = to_cti_drvdata(cti);
mutex_lock(&drvdata->mutex);
- if (drvdata->refcnt == 0) {
- ret = cti_enable(drvdata);
- if (ret)
- goto err;
- }
- drvdata->refcnt++;
-
- __cti_map_trigout(drvdata, trig, ch);
-err:
+ ret = __cti_map_trigout(drvdata, trig, ch);
mutex_unlock(&drvdata->mutex);
return ret;
}
@@ -193,9 +207,11 @@
{
CTI_UNLOCK(drvdata);
- cti_writel(drvdata, 0x1, CTICONTROL);
+ cti_writel(drvdata, 0x0, CTICONTROL);
CTI_LOCK(drvdata);
+
+ clk_disable_unprepare(drvdata->clk);
}
static void __cti_unmap_trigin(struct cti_drvdata *drvdata, int trig, int ch)
@@ -205,9 +221,19 @@
CTI_UNLOCK(drvdata);
ctien = cti_readl(drvdata, CTIINEN(trig));
+ if (!(ctien & (0x1 << ch)))
+ goto out;
cti_writel(drvdata, (ctien & ~(0x1 << ch)), CTIINEN(trig));
CTI_LOCK(drvdata);
+
+ if (drvdata->refcnt == 1)
+ cti_disable(drvdata);
+ drvdata->refcnt--;
+ return;
+out:
+ CTI_LOCK(drvdata);
+ return;
}
void coresight_cti_unmap_trigin(struct coresight_cti *cti, int trig, int ch)
@@ -224,13 +250,8 @@
mutex_lock(&drvdata->mutex);
__cti_unmap_trigin(drvdata, trig, ch);
-
- if (drvdata->refcnt == 1)
- cti_disable(drvdata);
- drvdata->refcnt--;
mutex_unlock(&drvdata->mutex);
- clk_disable_unprepare(drvdata->clk);
}
EXPORT_SYMBOL(coresight_cti_unmap_trigin);
@@ -241,9 +262,19 @@
CTI_UNLOCK(drvdata);
ctien = cti_readl(drvdata, CTIOUTEN(trig));
+ if (!(ctien & (0x1 << ch)))
+ goto out;
cti_writel(drvdata, (ctien & ~(0x1 << ch)), CTIOUTEN(trig));
CTI_LOCK(drvdata);
+
+ if (drvdata->refcnt == 1)
+ cti_disable(drvdata);
+ drvdata->refcnt--;
+ return;
+out:
+ CTI_LOCK(drvdata);
+ return;
}
void coresight_cti_unmap_trigout(struct coresight_cti *cti, int trig, int ch)
@@ -260,13 +291,7 @@
mutex_lock(&drvdata->mutex);
__cti_unmap_trigout(drvdata, trig, ch);
-
- if (drvdata->refcnt == 1)
- cti_disable(drvdata);
- drvdata->refcnt--;
mutex_unlock(&drvdata->mutex);
-
- clk_disable_unprepare(drvdata->clk);
}
EXPORT_SYMBOL(coresight_cti_unmap_trigout);
@@ -388,6 +413,9 @@
struct resource *res;
struct coresight_desc *desc;
+ if (coresight_fuse_access_disabled())
+ return -EPERM;
+
if (pdev->dev.of_node) {
pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
if (IS_ERR(pdata))
diff --git a/drivers/coresight/coresight-etb.c b/drivers/coresight/coresight-etb.c
index 31f85dc..473b4cb 100644
--- a/drivers/coresight/coresight-etb.c
+++ b/drivers/coresight/coresight-etb.c
@@ -362,6 +362,9 @@
struct resource *res;
struct coresight_desc *desc;
+ if (coresight_fuse_access_disabled())
+ return -EPERM;
+
if (pdev->dev.of_node) {
pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
if (IS_ERR(pdata))
diff --git a/drivers/coresight/coresight-etm.c b/drivers/coresight/coresight-etm.c
index de86622..52f3027 100644
--- a/drivers/coresight/coresight-etm.c
+++ b/drivers/coresight/coresight-etm.c
@@ -2113,6 +2113,10 @@
struct msm_client_dump dump;
struct coresight_desc *desc;
+ if (coresight_fuse_access_disabled() ||
+ coresight_fuse_apps_access_disabled())
+ return -EPERM;
+
if (pdev->dev.of_node) {
pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
if (IS_ERR(pdata))
diff --git a/drivers/coresight/coresight-funnel.c b/drivers/coresight/coresight-funnel.c
index 625f481..771321d 100644
--- a/drivers/coresight/coresight-funnel.c
+++ b/drivers/coresight/coresight-funnel.c
@@ -174,6 +174,9 @@
struct resource *res;
struct coresight_desc *desc;
+ if (coresight_fuse_access_disabled())
+ return -EPERM;
+
if (pdev->dev.of_node) {
pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
if (IS_ERR(pdata))
diff --git a/drivers/coresight/coresight-fuse.c b/drivers/coresight/coresight-fuse.c
new file mode 100644
index 0000000..7af5c6c8
--- /dev/null
+++ b/drivers/coresight/coresight-fuse.c
@@ -0,0 +1,202 @@
+/* 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/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_coresight.h>
+#include <linux/coresight.h>
+
+#include "coresight-priv.h"
+
+#define fuse_writel(drvdata, val, off) __raw_writel((val), drvdata->base + off)
+#define fuse_readl(drvdata, off) __raw_readl(drvdata->base + off)
+
+#define OEM_CONFIG0 (0x000)
+#define OEM_CONFIG1 (0x004)
+
+#define ALL_DEBUG_DISABLE BIT(21)
+#define APPS_DBGEN_DISABLE BIT(0)
+#define APPS_NIDEN_DISABLE BIT(1)
+#define APPS_SPIDEN_DISABLE BIT(2)
+#define APPS_SPNIDEN_DISABLE BIT(3)
+#define DAP_DBGEN_DISABLE BIT(4)
+#define DAP_NIDEN_DISABLE BIT(5)
+#define DAP_SPIDEN_DISABLE BIT(6)
+#define DAP_SPNIDEN_DISABLE BIT(7)
+#define DAP_DEVICEEN_DISABLE BIT(8)
+
+struct fuse_drvdata {
+ void __iomem *base;
+ struct device *dev;
+ struct coresight_device *csdev;
+};
+
+static struct fuse_drvdata *fusedrvdata;
+
+bool coresight_fuse_access_disabled(void)
+{
+ struct fuse_drvdata *drvdata = fusedrvdata;
+ uint32_t config0, config1;
+ bool ret;
+
+ config0 = fuse_readl(drvdata, OEM_CONFIG0);
+ config1 = fuse_readl(drvdata, OEM_CONFIG1);
+
+ dev_dbg(drvdata->dev, "config0: %lx\n", (unsigned long)config0);
+ dev_dbg(drvdata->dev, "config1: %lx\n", (unsigned long)config1);
+
+ if (config0 & ALL_DEBUG_DISABLE)
+ ret = true;
+ else if (config1 & DAP_DBGEN_DISABLE)
+ ret = true;
+ else if (config1 & DAP_NIDEN_DISABLE)
+ ret = true;
+ else if (config1 & DAP_SPIDEN_DISABLE)
+ ret = true;
+ else if (config1 & DAP_SPNIDEN_DISABLE)
+ ret = true;
+ else if (config1 & DAP_DEVICEEN_DISABLE)
+ ret = true;
+ else
+ ret = false;
+
+ if (ret)
+ dev_dbg(drvdata->dev, "coresight fuse disabled\n");
+
+ return ret;
+}
+EXPORT_SYMBOL(coresight_fuse_access_disabled);
+
+bool coresight_fuse_apps_access_disabled(void)
+{
+ struct fuse_drvdata *drvdata = fusedrvdata;
+ uint32_t config0, config1;
+ bool ret;
+
+ config0 = fuse_readl(drvdata, OEM_CONFIG0);
+ config1 = fuse_readl(drvdata, OEM_CONFIG1);
+
+ dev_dbg(drvdata->dev, "apps config0: %lx\n", (unsigned long)config0);
+ dev_dbg(drvdata->dev, "apps config1: %lx\n", (unsigned long)config1);
+
+ if (config0 & ALL_DEBUG_DISABLE)
+ ret = true;
+ else if (config1 & APPS_DBGEN_DISABLE)
+ ret = true;
+ else if (config1 & APPS_NIDEN_DISABLE)
+ ret = true;
+ else if (config1 & APPS_SPIDEN_DISABLE)
+ ret = true;
+ else if (config1 & APPS_SPNIDEN_DISABLE)
+ ret = true;
+ else if (config1 & DAP_DEVICEEN_DISABLE)
+ ret = true;
+ else
+ ret = false;
+
+ if (ret)
+ dev_dbg(drvdata->dev, "apps fuse disabled\n");
+
+ return ret;
+}
+EXPORT_SYMBOL(coresight_fuse_apps_access_disabled);
+
+static int __devinit fuse_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct coresight_platform_data *pdata;
+ struct fuse_drvdata *drvdata;
+ struct resource *res;
+ struct coresight_desc *desc;
+
+ if (pdev->dev.of_node) {
+ pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
+ if (IS_ERR(pdata))
+ return PTR_ERR(pdata);
+ pdev->dev.platform_data = pdata;
+ }
+
+ drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+ /* Store the driver data pointer for use in exported functions */
+ fusedrvdata = drvdata;
+ drvdata->dev = &pdev->dev;
+ platform_set_drvdata(pdev, drvdata);
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fuse-base");
+ if (!res)
+ return -ENODEV;
+
+ drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
+ if (!drvdata->base)
+ return -ENOMEM;
+
+ desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+ if (!desc)
+ return -ENOMEM;
+ desc->type = CORESIGHT_DEV_TYPE_NONE;
+ desc->pdata = pdev->dev.platform_data;
+ desc->dev = &pdev->dev;
+ desc->owner = THIS_MODULE;
+ drvdata->csdev = coresight_register(desc);
+ if (IS_ERR(drvdata->csdev))
+ return PTR_ERR(drvdata->csdev);
+
+ dev_info(dev, "Fuse initialized\n");
+ return 0;
+}
+
+static int __devexit fuse_remove(struct platform_device *pdev)
+{
+ struct fuse_drvdata *drvdata = platform_get_drvdata(pdev);
+
+ coresight_unregister(drvdata->csdev);
+ return 0;
+}
+
+static struct of_device_id fuse_match[] = {
+ {.compatible = "arm,coresight-fuse"},
+ {}
+};
+
+static struct platform_driver fuse_driver = {
+ .probe = fuse_probe,
+ .remove = __devexit_p(fuse_remove),
+ .driver = {
+ .name = "coresight-fuse",
+ .owner = THIS_MODULE,
+ .of_match_table = fuse_match,
+ },
+};
+
+static int __init fuse_init(void)
+{
+ return platform_driver_register(&fuse_driver);
+}
+module_init(fuse_init);
+
+static void __exit fuse_exit(void)
+{
+ platform_driver_unregister(&fuse_driver);
+}
+module_exit(fuse_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight Fuse driver");
diff --git a/drivers/coresight/coresight-hwevent.c b/drivers/coresight/coresight-hwevent.c
index 777484d..269d56e 100644
--- a/drivers/coresight/coresight-hwevent.c
+++ b/drivers/coresight/coresight-hwevent.c
@@ -211,6 +211,9 @@
int ret, i;
const char *hmux_name, *hclk_name;
+ if (coresight_fuse_access_disabled())
+ return -EPERM;
+
if (pdev->dev.of_node) {
pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
if (IS_ERR(pdata))
diff --git a/drivers/coresight/coresight-priv.h b/drivers/coresight/coresight-priv.h
index f208185..3ad1f34 100644
--- a/drivers/coresight/coresight-priv.h
+++ b/drivers/coresight/coresight-priv.h
@@ -36,17 +36,26 @@
#define BMVAL(val, lsb, msb) ((val & BM(lsb, msb)) >> lsb)
#define BVAL(val, n) ((val & BIT(n)) >> n)
+#ifdef CONFIG_CORESIGHT_FUSE
+extern bool coresight_fuse_access_disabled(void);
+extern bool coresight_fuse_apps_access_disabled(void);
+#else
+static inline bool coresight_fuse_access_disabled(void) { return false; }
+static inline bool coresight_fuse_apps_access_disabled(void) { return false; }
+#endif
#ifdef CONFIG_CORESIGHT_CSR
extern void msm_qdss_csr_enable_bam_to_usb(void);
extern void msm_qdss_csr_disable_bam_to_usb(void);
extern void msm_qdss_csr_disable_flush(void);
extern int coresight_csr_hwctrl_set(phys_addr_t addr, uint32_t val);
+extern void coresight_csr_set_byte_cntr(uint32_t);
#else
static inline void msm_qdss_csr_enable_bam_to_usb(void) {}
static inline void msm_qdss_csr_disable_bam_to_usb(void) {}
static inline void msm_qdss_csr_disable_flush(void) {}
static inline int coresight_csr_hwctrl_set(phys_addr_t addr,
uint32_t val) { return -ENOSYS; }
+static inline void coresight_csr_set_byte_cntr(uint32_t val) {}
#endif
#ifdef CONFIG_CORESIGHT_ETM
extern unsigned int etm_readl_cp14(uint32_t off);
diff --git a/drivers/coresight/coresight-replicator.c b/drivers/coresight/coresight-replicator.c
index d4afa42..9f70dc7 100644
--- a/drivers/coresight/coresight-replicator.c
+++ b/drivers/coresight/coresight-replicator.c
@@ -126,6 +126,9 @@
struct resource *res;
struct coresight_desc *desc;
+ if (coresight_fuse_access_disabled())
+ return -EPERM;
+
if (pdev->dev.of_node) {
pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
if (IS_ERR(pdata))
diff --git a/drivers/coresight/coresight-stm.c b/drivers/coresight/coresight-stm.c
index 7d4dabe..81672ea 100644
--- a/drivers/coresight/coresight-stm.c
+++ b/drivers/coresight/coresight-stm.c
@@ -450,6 +450,8 @@
static int stm_send(void *addr, const void *data, uint32_t size)
{
+ uint32_t len = size;
+
if (((unsigned long)data & 0x1) && (size >= 1)) {
stm_data_writeb(*(uint8_t *)data, addr);
data++;
@@ -479,7 +481,7 @@
size--;
}
- return size;
+ return len;
}
static int stm_trace_ost_header(unsigned long ch_addr, uint32_t options,
@@ -791,6 +793,9 @@
size_t res_size, bitmap_size;
struct coresight_desc *desc;
+ if (coresight_fuse_access_disabled())
+ return -EPERM;
+
if (pdev->dev.of_node) {
pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
if (IS_ERR(pdata))
diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c
index f39334a..c501700 100644
--- a/drivers/coresight/coresight-tmc.c
+++ b/drivers/coresight/coresight-tmc.c
@@ -30,6 +30,10 @@
#include <linux/of_coresight.h>
#include <linux/coresight.h>
#include <linux/coresight-cti.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/cdev.h>
#include <linux/usb/usb_qdss.h>
#include <mach/memory.h>
#include <mach/sps.h>
@@ -135,6 +139,8 @@
struct device *dev;
struct coresight_device *csdev;
struct miscdevice miscdev;
+ struct cdev byte_cntr_dev;
+ struct class *byte_cntr_class;
struct clk *clk;
spinlock_t spinlock;
bool reset_flush_race;
@@ -157,6 +163,19 @@
bool enable;
enum tmc_config_type config_type;
uint32_t trigger_cntr;
+ int byte_cntr_irq;
+ atomic_t byte_cntr_irq_cnt;
+ uint32_t byte_cntr_value;
+ struct mutex byte_cntr_read_lock;
+ struct mutex byte_cntr_lock;
+ uint32_t byte_cntr_block_size;
+ bool byte_cntr_overflow;
+ bool byte_cntr_present;
+ bool byte_cntr_enable;
+ uint32_t byte_cntr_overflow_cnt;
+ bool byte_cntr_read_active;
+ wait_queue_head_t wq;
+ char *byte_cntr_node;
};
static void tmc_wait_for_flush(struct tmc_drvdata *drvdata)
@@ -368,6 +387,52 @@
mutex_unlock(&drvdata->usb_lock);
}
+static uint32_t tmc_etr_get_write_ptr(struct tmc_drvdata *drvdata)
+{
+ uint32_t rwp = 0;
+
+ TMC_UNLOCK(drvdata);
+
+ rwp = tmc_readl(drvdata, TMC_RWP);
+
+ TMC_LOCK(drvdata);
+
+ return rwp;
+}
+
+static void tmc_etr_byte_cntr_start(struct tmc_drvdata *drvdata)
+{
+ if (!drvdata->byte_cntr_present)
+ return;
+
+ mutex_lock(&drvdata->byte_cntr_lock);
+ atomic_set(&drvdata->byte_cntr_irq_cnt, 0);
+ drvdata->byte_cntr_overflow = false;
+ drvdata->byte_cntr_read_active = false;
+ drvdata->byte_cntr_enable = true;
+ if (drvdata->byte_cntr_value != 0)
+ drvdata->byte_cntr_overflow_cnt = drvdata->size /
+ (drvdata->byte_cntr_value * 8);
+ else
+ drvdata->byte_cntr_overflow_cnt = 0;
+ coresight_csr_set_byte_cntr(drvdata->byte_cntr_value);
+ mutex_unlock(&drvdata->byte_cntr_lock);
+}
+
+static void tmc_etr_byte_cntr_stop(struct tmc_drvdata *drvdata)
+{
+ if (!drvdata->byte_cntr_present)
+ return;
+
+ mutex_lock(&drvdata->byte_cntr_lock);
+ coresight_csr_set_byte_cntr(0);
+ drvdata->byte_cntr_value = 0;
+ drvdata->byte_cntr_enable = false;
+ mutex_unlock(&drvdata->byte_cntr_lock);
+
+ wake_up(&drvdata->wq);
+}
+
static void __tmc_etb_enable(struct tmc_drvdata *drvdata)
{
/* Zero out the memory to help with debug */
@@ -438,10 +503,14 @@
coresight_cti_map_trigout(drvdata->cti_flush, 1, 0);
coresight_cti_map_trigin(drvdata->cti_reset, 0, 0);
} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
- if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM &&
- !drvdata->reset_flush_race) {
- coresight_cti_map_trigout(drvdata->cti_flush, 3, 0);
- coresight_cti_map_trigin(drvdata->cti_reset, 2, 0);
+ if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM) {
+ tmc_etr_byte_cntr_start(drvdata);
+ if (!drvdata->reset_flush_race) {
+ coresight_cti_map_trigout(drvdata->cti_flush,
+ 3, 0);
+ coresight_cti_map_trigin(drvdata->cti_reset,
+ 2, 0);
+ }
} else if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB) {
drvdata->usbch = usb_qdss_open("qdss", drvdata,
usb_notifier);
@@ -674,10 +743,14 @@
coresight_cti_unmap_trigin(drvdata->cti_reset, 0, 0);
coresight_cti_unmap_trigout(drvdata->cti_flush, 1, 0);
} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
- if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM &&
- !drvdata->reset_flush_race) {
- coresight_cti_unmap_trigin(drvdata->cti_reset, 2, 0);
- coresight_cti_unmap_trigout(drvdata->cti_flush, 3, 0);
+ if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM) {
+ tmc_etr_byte_cntr_stop(drvdata);
+ if (!drvdata->reset_flush_race) {
+ coresight_cti_unmap_trigin(drvdata->cti_reset,
+ 2, 0);
+ coresight_cti_unmap_trigout(drvdata->cti_flush,
+ 3, 0);
+ }
} else if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB) {
tmc_etr_bam_disable(drvdata);
usb_qdss_close(drvdata->usbch);
@@ -929,6 +1002,161 @@
.llseek = no_llseek,
};
+static int tmc_etr_byte_cntr_open(struct inode *inode, struct file *file)
+{
+ struct tmc_drvdata *drvdata = container_of(inode->i_cdev,
+ struct tmc_drvdata,
+ byte_cntr_dev);
+
+ if (drvdata->out_mode != TMC_ETR_OUT_MODE_MEM ||
+ !drvdata->byte_cntr_enable)
+ return -EPERM;
+
+ if (!mutex_trylock(&drvdata->byte_cntr_read_lock))
+ return -EPERM;
+
+ file->private_data = drvdata;
+ nonseekable_open(inode, file);
+ drvdata->byte_cntr_block_size = drvdata->byte_cntr_value * 8;
+ drvdata->byte_cntr_read_active = true;
+ dev_dbg(drvdata->dev, "%s: successfully opened\n", __func__);
+ return 0;
+}
+
+static void tmc_etr_read_bytes(struct tmc_drvdata *drvdata, loff_t *ppos,
+ size_t bytes, size_t *len)
+{
+ if (*len >= bytes) {
+ atomic_dec(&drvdata->byte_cntr_irq_cnt);
+ *len = bytes;
+ } else {
+ if (((uint32_t)*ppos % bytes) + *len > bytes)
+ *len = bytes - ((uint32_t)*ppos % bytes);
+ if ((*len + (uint32_t)*ppos) % bytes == 0)
+ atomic_dec(&drvdata->byte_cntr_irq_cnt);
+ }
+}
+
+static size_t tmc_etr_flush_bytes(struct tmc_drvdata *drvdata, loff_t *ppos,
+ size_t bytes)
+{
+ uint32_t rwp = 0;
+ size_t len = bytes;
+
+ rwp = tmc_etr_get_write_ptr(drvdata);
+ if (rwp >= (drvdata->paddr + *ppos)) {
+ if (len > (rwp - drvdata->paddr - *ppos))
+ len = rwp - drvdata->paddr - *ppos;
+ }
+ return len;
+}
+
+static ssize_t tmc_etr_byte_cntr_read(struct file *file, char __user *data,
+ size_t len, loff_t *ppos)
+{
+ struct tmc_drvdata *drvdata = file->private_data;
+ char *bufp = drvdata->vaddr + *ppos;
+ size_t bytes = drvdata->byte_cntr_block_size;
+ int ret = 0;
+
+ if (!data)
+ return -EINVAL;
+ if (drvdata->byte_cntr_overflow)
+ return -EIO;
+
+ mutex_lock(&drvdata->byte_cntr_lock);
+ /* In case the byte counter is enabled and disabled multiple times
+ * prevent unexpected data from being given to the user
+ */
+ if (!drvdata->byte_cntr_read_active)
+ goto read_err0;
+
+ if (!drvdata->byte_cntr_enable) {
+ if (!atomic_read(&drvdata->byte_cntr_irq_cnt)) {
+ /* Read the last 'block' of data which might be needed
+ * to be read partially. If already read, return 0
+ */
+ len = tmc_etr_flush_bytes(drvdata, ppos, bytes);
+ if (!len)
+ goto read_err0;
+ } else {
+ /* Keep reading until you reach the last block of data
+ */
+ tmc_etr_read_bytes(drvdata, ppos, bytes, &len);
+ }
+ } else {
+ if (!atomic_read(&drvdata->byte_cntr_irq_cnt)) {
+ mutex_unlock(&drvdata->byte_cntr_lock);
+ if (wait_event_interruptible(drvdata->wq,
+ (atomic_read(&drvdata->byte_cntr_irq_cnt) > 0) ||
+ !drvdata->byte_cntr_enable)) {
+ ret = -ERESTARTSYS;
+ goto read_err1;
+ }
+ mutex_lock(&drvdata->byte_cntr_lock);
+ if (!drvdata->byte_cntr_read_active) {
+ ret = 0;
+ goto read_err0;
+ }
+ }
+ if (drvdata->byte_cntr_overflow) {
+ ret = -EIO;
+ goto read_err0;
+ }
+ if (!drvdata->byte_cntr_enable &&
+ !atomic_read(&drvdata->byte_cntr_irq_cnt)) {
+ len = tmc_etr_flush_bytes(drvdata, ppos, bytes);
+ if (!len) {
+ ret = 0;
+ goto read_err0;
+ }
+ } else {
+ tmc_etr_read_bytes(drvdata, ppos, bytes, &len);
+ }
+ }
+ if (copy_to_user(data, bufp, len)) {
+ mutex_unlock(&drvdata->byte_cntr_lock);
+ dev_dbg(drvdata->dev, "%s: copy_to_user failed\n", __func__);
+ ret = -EFAULT;
+ goto read_err1;
+ }
+ mutex_unlock(&drvdata->byte_cntr_lock);
+
+ if (*ppos + len >= drvdata->size)
+ *ppos = 0;
+ else
+ *ppos += len;
+
+ dev_dbg(drvdata->dev, "%s: %d bytes copied, %d bytes left\n",
+ __func__, len, (int) (drvdata->size - *ppos));
+ return len;
+
+read_err0:
+ mutex_unlock(&drvdata->byte_cntr_lock);
+read_err1:
+ return ret;
+}
+
+static int tmc_etr_byte_cntr_release(struct inode *inode, struct file *file)
+{
+ struct tmc_drvdata *drvdata = file->private_data;
+
+ mutex_lock(&drvdata->byte_cntr_lock);
+ drvdata->byte_cntr_read_active = false;
+ mutex_unlock(&drvdata->byte_cntr_lock);
+ mutex_unlock(&drvdata->byte_cntr_read_lock);
+ dev_dbg(drvdata->dev, "%s: released\n", __func__);
+ return 0;
+}
+
+static const struct file_operations byte_cntr_fops = {
+ .owner = THIS_MODULE,
+ .open = tmc_etr_byte_cntr_open,
+ .read = tmc_etr_byte_cntr_read,
+ .release = tmc_etr_byte_cntr_release,
+ .llseek = no_llseek,
+};
+
static ssize_t tmc_show_trigger_cntr(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -1044,6 +1272,41 @@
static DEVICE_ATTR(out_mode, S_IRUGO | S_IWUSR, tmc_etr_show_out_mode,
tmc_etr_store_out_mode);
+static ssize_t tmc_etr_show_byte_cntr_value(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long val = drvdata->byte_cntr_value;
+
+ if (!drvdata->byte_cntr_present)
+ return -EPERM;
+
+ return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t tmc_etr_store_byte_cntr_value(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long val;
+
+ if (!drvdata->byte_cntr_present || drvdata->byte_cntr_enable)
+ return -EPERM;
+ if (sscanf(buf, "%lx", &val) != 1)
+ return -EINVAL;
+ if ((drvdata->size / 8) < val)
+ return -EINVAL;
+ if (drvdata->size % (val * 8) != 0)
+ return -EINVAL;
+
+ drvdata->byte_cntr_value = val;
+ return size;
+}
+static DEVICE_ATTR(byte_cntr_value, S_IRUGO | S_IWUSR,
+ tmc_etr_show_byte_cntr_value, tmc_etr_store_byte_cntr_value);
+
static struct attribute *tmc_attrs[] = {
&dev_attr_trigger_cntr.attr,
NULL,
@@ -1055,6 +1318,7 @@
static struct attribute *tmc_etr_attrs[] = {
&dev_attr_out_mode.attr,
+ &dev_attr_byte_cntr_value.attr,
NULL,
};
@@ -1118,6 +1382,113 @@
sps_deregister_bam_device(bamdata->handle);
}
+static irqreturn_t tmc_etr_byte_cntr_irq(int irq, void *data)
+{
+ struct tmc_drvdata *drvdata = data;
+
+ atomic_inc(&drvdata->byte_cntr_irq_cnt);
+ if (atomic_read(&drvdata->byte_cntr_irq_cnt) >
+ drvdata->byte_cntr_overflow_cnt) {
+ dev_err(drvdata->dev, "Byte counter overflow\n");
+ drvdata->byte_cntr_overflow = true;
+ }
+ wake_up(&drvdata->wq);
+ return IRQ_HANDLED;
+}
+
+static int tmc_etr_byte_cntr_dev_register(struct tmc_drvdata *drvdata)
+{
+ int ret;
+ struct device *device;
+ dev_t dev;
+
+ ret = alloc_chrdev_region(&dev, 0, 1, drvdata->byte_cntr_node);
+ if (ret)
+ goto dev_err0;
+ cdev_init(&drvdata->byte_cntr_dev, &byte_cntr_fops);
+ drvdata->byte_cntr_dev.owner = THIS_MODULE;
+ drvdata->byte_cntr_dev.ops = &byte_cntr_fops;
+ ret = cdev_add(&drvdata->byte_cntr_dev, dev, 1);
+ if (ret)
+ goto dev_err1;
+ drvdata->byte_cntr_class = class_create(THIS_MODULE,
+ drvdata->byte_cntr_node);
+ if (!drvdata->byte_cntr_class)
+ goto dev_err2;
+ device = device_create(drvdata->byte_cntr_class, NULL,
+ drvdata->byte_cntr_dev.dev, drvdata,
+ drvdata->byte_cntr_node);
+ if (IS_ERR(device)) {
+ ret = PTR_ERR(device);
+ goto dev_err3;
+ }
+ return 0;
+dev_err3:
+ class_destroy(drvdata->byte_cntr_class);
+dev_err2:
+ cdev_del(&drvdata->byte_cntr_dev);
+dev_err1:
+ unregister_chrdev_region(drvdata->byte_cntr_dev.dev, 1);
+dev_err0:
+ return ret;
+}
+
+static void tmc_etr_byte_cntr_dev_deregister(struct tmc_drvdata *drvdata)
+{
+ device_destroy(drvdata->byte_cntr_class, drvdata->byte_cntr_dev.dev);
+ class_destroy(drvdata->byte_cntr_class);
+ cdev_del(&drvdata->byte_cntr_dev);
+ unregister_chrdev_region(drvdata->byte_cntr_dev.dev, 1);
+}
+
+static int tmc_etr_byte_cntr_init(struct platform_device *pdev,
+ struct tmc_drvdata *drvdata)
+{
+ int ret = 0;
+ size_t node_size = strlen("-stream") + 1;
+ char *node_name = (char *)((struct coresight_platform_data *)
+ (pdev->dev.platform_data))->name;
+
+ if (!drvdata->byte_cntr_present) {
+ dev_info(&pdev->dev, "Byte Counter feature absent\n");
+ return 0;
+ }
+
+ drvdata->byte_cntr_irq = platform_get_irq_byname(pdev,
+ "byte-cntr-irq");
+ if (drvdata->byte_cntr_irq < 0) {
+ dev_err(&pdev->dev, "Byte-cntr-irq not specified\n");
+ return 0;
+ }
+ ret = devm_request_irq(&pdev->dev, drvdata->byte_cntr_irq,
+ tmc_etr_byte_cntr_irq,
+ IRQF_TRIGGER_RISING | IRQF_SHARED,
+ node_name, drvdata);
+ if (ret) {
+ dev_err(&pdev->dev, "Request irq failed\n");
+ return ret;
+ }
+ init_waitqueue_head(&drvdata->wq);
+ node_size += strlen(node_name);
+ drvdata->byte_cntr_node = devm_kzalloc(&pdev->dev,
+ node_size, GFP_KERNEL);
+ strlcpy(drvdata->byte_cntr_node, node_name, node_size);
+ strlcat(drvdata->byte_cntr_node, "-stream", node_size);
+ ret = tmc_etr_byte_cntr_dev_register(drvdata);
+ if (ret) {
+ dev_err(&pdev->dev, "Byte cntr node not registered\n");
+ return ret;
+ }
+ dev_info(&pdev->dev, "Byte Counter feature enabled\n");
+ return 0;
+}
+
+static void tmc_etr_byte_cntr_exit(struct tmc_drvdata *drvdata)
+{
+ if (drvdata->byte_cntr_present)
+ tmc_etr_byte_cntr_dev_deregister(drvdata);
+}
+
static int __devinit tmc_probe(struct platform_device *pdev)
{
int ret;
@@ -1134,6 +1505,9 @@
struct coresight_cti_data *ctidata;
struct coresight_desc *desc;
+ if (coresight_fuse_access_disabled())
+ return -EPERM;
+
if (pdev->dev.of_node) {
pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
if (IS_ERR(pdata))
@@ -1159,6 +1533,9 @@
spin_lock_init(&drvdata->spinlock);
mutex_init(&drvdata->read_lock);
mutex_init(&drvdata->usb_lock);
+ mutex_init(&drvdata->byte_cntr_lock);
+ mutex_init(&drvdata->byte_cntr_read_lock);
+ atomic_set(&drvdata->byte_cntr_irq_cnt, 0);
drvdata->clk = devm_clk_get(dev, "core_clk");
if (IS_ERR(drvdata->clk))
@@ -1204,10 +1581,16 @@
memset(drvdata->vaddr, 0, drvdata->size);
drvdata->buf = drvdata->vaddr;
drvdata->out_mode = TMC_ETR_OUT_MODE_MEM;
-
- ret = tmc_etr_bam_init(pdev, drvdata);
+ if (pdev->dev.of_node)
+ drvdata->byte_cntr_present = !of_property_read_bool
+ (pdev->dev.of_node,
+ "qcom,byte-cntr-absent");
+ ret = tmc_etr_byte_cntr_init(pdev, drvdata);
if (ret)
goto err0;
+ ret = tmc_etr_bam_init(pdev, drvdata);
+ if (ret)
+ goto err1;
} else {
baddr = devm_kzalloc(dev, PAGE_SIZE + drvdata->size,
GFP_KERNEL);
@@ -1274,7 +1657,7 @@
desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
if (!desc) {
ret = -ENOMEM;
- goto err1;
+ goto err2;
}
if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
desc->type = CORESIGHT_DEV_TYPE_SINK;
@@ -1287,7 +1670,7 @@
drvdata->csdev = coresight_register(desc);
if (IS_ERR(drvdata->csdev)) {
ret = PTR_ERR(drvdata->csdev);
- goto err1;
+ goto err2;
}
} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
desc->type = CORESIGHT_DEV_TYPE_SINK;
@@ -1300,7 +1683,7 @@
drvdata->csdev = coresight_register(desc);
if (IS_ERR(drvdata->csdev)) {
ret = PTR_ERR(drvdata->csdev);
- goto err1;
+ goto err2;
}
} else {
desc->type = CORESIGHT_DEV_TYPE_LINKSINK;
@@ -1314,7 +1697,7 @@
drvdata->csdev = coresight_register(desc);
if (IS_ERR(drvdata->csdev)) {
ret = PTR_ERR(drvdata->csdev);
- goto err1;
+ goto err2;
}
}
@@ -1324,14 +1707,16 @@
drvdata->miscdev.fops = &tmc_fops;
ret = misc_register(&drvdata->miscdev);
if (ret)
- goto err2;
+ goto err3;
dev_info(dev, "TMC initialized\n");
return 0;
-err2:
+err3:
coresight_unregister(drvdata->csdev);
-err1:
+err2:
tmc_etr_bam_exit(drvdata);
+err1:
+ tmc_etr_byte_cntr_exit(drvdata);
err0:
free_contiguous_memory_by_paddr(drvdata->paddr);
return ret;
@@ -1341,6 +1726,7 @@
{
struct tmc_drvdata *drvdata = platform_get_drvdata(pdev);
+ tmc_etr_byte_cntr_exit(drvdata);
misc_deregister(&drvdata->miscdev);
coresight_unregister(drvdata->csdev);
tmc_etr_bam_exit(drvdata);
diff --git a/drivers/coresight/coresight-tpiu.c b/drivers/coresight/coresight-tpiu.c
index 53df0f9..032327c 100644
--- a/drivers/coresight/coresight-tpiu.c
+++ b/drivers/coresight/coresight-tpiu.c
@@ -717,6 +717,9 @@
struct resource *res;
struct coresight_desc *desc;
+ if (coresight_fuse_access_disabled())
+ return -EPERM;
+
if (pdev->dev.of_node) {
pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
if (IS_ERR(pdata))
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 3d5614b..374170d 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -435,8 +435,12 @@
if (ret != 1) \
return -EINVAL; \
\
+ ret = cpufreq_driver->verify(&new_policy); \
+ if (ret) \
+ pr_err("cpufreq: Frequency verification failed\n"); \
+ \
+ policy->user_policy.object = new_policy.object; \
ret = __cpufreq_set_policy(policy, &new_policy); \
- policy->user_policy.object = policy->object; \
\
return ret ? ret : count; \
}
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 2fd8bef..96e759b 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -610,6 +610,9 @@
if (dbs_info->cur_policy) {
/* restart dbs timer */
dbs_timer_init(dbs_info);
+ /* Enable frequency synchronization
+ * of CPUs */
+ atomic_set(&dbs_info->sync_enabled, 1);
}
skip_this_cpu:
unlock_policy_rwsem_write(cpu);
@@ -639,15 +642,19 @@
if (dbs_info->cur_policy) {
/* cpu using ondemand, cancel dbs timer */
- mutex_lock(&dbs_info->timer_mutex);
dbs_timer_exit(dbs_info);
+ /* Disable frequency synchronization of
+ * CPUs to avoid re-queueing of work from
+ * sync_thread */
+ atomic_set(&dbs_info->sync_enabled, 0);
+ mutex_lock(&dbs_info->timer_mutex);
ondemand_powersave_bias_setspeed(
dbs_info->cur_policy,
NULL,
input);
-
mutex_unlock(&dbs_info->timer_mutex);
+
}
skip_this_cpu_bypass:
unlock_policy_rwsem_write(cpu);
@@ -1075,18 +1082,6 @@
get_online_cpus();
- /* TODO: cur_policy is currently set for all CPUs when
- * a policy is started but cleared only on the current
- * CPU when the policy is stopped. If/when this is
- * resolved, sync_enabled can be removed and
- * cur_policy can be used instead.
- */
- if (!atomic_read(&this_dbs_info->sync_enabled)) {
- atomic_set(&this_dbs_info->src_sync_cpu, -1);
- put_online_cpus();
- continue;
- }
-
src_cpu = atomic_read(&this_dbs_info->src_sync_cpu);
src_dbs_info = &per_cpu(od_cpu_dbs_info, src_cpu);
if (src_dbs_info != NULL &&
@@ -1101,6 +1096,13 @@
if (lock_policy_rwsem_write(cpu) < 0)
goto bail_acq_sema_failed;
+ if (!atomic_read(&this_dbs_info->sync_enabled)) {
+ atomic_set(&this_dbs_info->src_sync_cpu, -1);
+ put_online_cpus();
+ unlock_policy_rwsem_write(cpu);
+ continue;
+ }
+
policy = this_dbs_info->cur_policy;
if (!policy) {
/* CPU not using ondemand governor */
@@ -1238,7 +1240,8 @@
kcpustat_cpu(j).cpustat[CPUTIME_NICE];
set_cpus_allowed(j_dbs_info->sync_thread,
*cpumask_of(j));
- atomic_set(&j_dbs_info->sync_enabled, 1);
+ if (!dbs_tuners_ins.powersave_bias)
+ atomic_set(&j_dbs_info->sync_enabled, 1);
}
this_dbs_info->cpu = cpu;
this_dbs_info->rate_mult = 1;
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index eae16fa..4c05978 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -188,12 +188,7 @@
min_rev = (rev & CRYPTO_CORE_MINOR_REV_MASK) >> CRYPTO_CORE_MINOR_REV;
step_rev = (rev & CRYPTO_CORE_STEP_REV_MASK) >> CRYPTO_CORE_STEP_REV;
- if ((maj_rev != 0x05) || (min_rev > 0x02) || (step_rev > 0x02)) {
- pr_err("Unknown Qualcomm crypto device at 0x%x, rev %d.%d.%d\n",
- pce_dev->phy_iobase, maj_rev, min_rev, step_rev);
- return -EIO;
- };
- if ((min_rev > 0) && (step_rev != 0)) {
+ if (maj_rev != 0x05) {
pr_err("Unknown Qualcomm crypto device at 0x%x, rev %d.%d.%d\n",
pce_dev->phy_iobase, maj_rev, min_rev, step_rev);
return -EIO;
@@ -3725,7 +3720,7 @@
qce_dma_map_sg(pce_dev->pdev, areq->src, pce_dev->src_nents,
(areq->src == areq->dst) ? DMA_BIDIRECTIONAL :
DMA_TO_DEVICE);
- /* cipher + mac output for encryption */
+ /* cipher output for encryption */
if (areq->src != areq->dst) {
if (pce_dev->ce_sps.minor_version == 0)
/*
@@ -3806,7 +3801,7 @@
if (_qce_sps_add_data((uint32_t)pce_dev->phy_iv_in, ivsize,
&pce_dev->ce_sps.in_transfer))
goto bad;
- if (_qce_sps_add_sg_data(pce_dev, areq->src, areq->cryptlen,
+ if (_qce_sps_add_sg_data(pce_dev, areq->src, q_req->cryptlen,
&pce_dev->ce_sps.in_transfer))
goto bad;
_qce_set_flag(&pce_dev->ce_sps.in_transfer,
@@ -3818,7 +3813,7 @@
(ivsize + areq->assoclen),
&pce_dev->ce_sps.out_transfer))
goto bad;
- if (_qce_sps_add_sg_data(pce_dev, areq->dst, areq->cryptlen,
+ if (_qce_sps_add_sg_data(pce_dev, areq->dst, q_req->cryptlen,
&pce_dev->ce_sps.out_transfer))
goto bad;
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index d069f2e..0e4b309 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -1937,7 +1937,7 @@
rc = misc_register(&podev->miscdevice);
qce_hw_support(podev->qce, &podev->ce_support);
if (podev->ce_support.bam) {
- podev->platform_support.ce_shared = podev->ce_support.is_shared;
+ podev->platform_support.ce_shared = 0;
podev->platform_support.shared_ce_resource = 0;
podev->platform_support.hw_key_support =
podev->ce_support.hw_key;
diff --git a/drivers/gpio/qpnp-pin.c b/drivers/gpio/qpnp-pin.c
index 64341e9..ed001f0 100644
--- a/drivers/gpio/qpnp-pin.c
+++ b/drivers/gpio/qpnp-pin.c
@@ -589,6 +589,9 @@
}
mutex_unlock(&qpnp_pin_chips_lock);
+ if (!q_spec)
+ return -ENODEV;
+
rc = _qpnp_pin_config(q_chip, q_spec, param);
return rc;
@@ -1225,6 +1228,8 @@
if (!res) {
dev_err(&spmi->dev, "%s: node %s is missing has no base address definition\n",
__func__, d_node->of_node->full_name);
+ rc = -EINVAL;
+ goto err_probe;
}
rc = of_property_read_u32(d_node->of_node,
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 250b387..6777dae 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -1688,9 +1688,7 @@
heap->dev = dev;
down_write(&dev->lock);
- /* 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_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);
diff --git a/drivers/gpu/ion/ion_cp_heap.c b/drivers/gpu/ion/ion_cp_heap.c
index f1868a8..f2f4fad 100644
--- a/drivers/gpu/ion/ion_cp_heap.c
+++ b/drivers/gpu/ion/ion_cp_heap.c
@@ -203,8 +203,7 @@
}
/**
- * Protects memory if heap is unsecured heap. Also ensures that we are in
- * the correct FMEM state if this heap is a reusable heap.
+ * Protects memory if heap is unsecured heap.
* Must be called with heap->lock locked.
*/
static int ion_cp_protect(struct ion_heap *heap, int version, void *data)
@@ -244,8 +243,7 @@
}
/**
- * Unprotects memory if heap is secure heap. Also ensures that we are in
- * the correct FMEM state if this heap is a reusable heap.
+ * Unprotects memory if heap is secure heap.
* Must be called with heap->lock locked.
*/
static void ion_cp_unprotect(struct ion_heap *heap, int version, void *data)
diff --git a/drivers/gpu/ion/ion_iommu_heap.c b/drivers/gpu/ion/ion_iommu_heap.c
index 45a7fae..1ea3cd2 100644
--- a/drivers/gpu/ion/ion_iommu_heap.c
+++ b/drivers/gpu/ion/ion_iommu_heap.c
@@ -31,6 +31,8 @@
struct ion_iommu_heap {
struct ion_heap heap;
+ struct ion_page_pool **cached_pools;
+ struct ion_page_pool **uncached_pools;
};
/*
@@ -48,9 +50,14 @@
};
#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;
@@ -58,13 +65,25 @@
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(unsigned long size,
- unsigned int max_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;
@@ -72,21 +91,35 @@
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;
- gfp = __GFP_HIGHMEM;
-
if (orders[i]) {
- gfp |= __GFP_COMP | __GFP_NORETRY |
- __GFP_NO_KSWAPD | __GFP_NOWARN;
+ gfp = high_gfp_flags;
} else {
- gfp |= GFP_KERNEL;
+ gfp = low_gfp_flags;
}
trace_alloc_pages_iommu_start(gfp, orders[i]);
- page = alloc_pages(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]);
@@ -94,13 +127,56 @@
}
info = kmalloc(sizeof(struct page_info), GFP_KERNEL);
- info->page = page;
- info->order = orders[i];
+ 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)
+{
+ int i, j;
+ unsigned int npages_to_vmap;
+ unsigned int total_pages;
+ void *ptr = NULL;
+
+ /*
+ * 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_kernel);
+ if (ptr)
+ break;
+ else
+ npages_to_vmap >>= 1;
+ }
+ if (!ptr)
+ return -ENOMEM;
+
+ memset(ptr, 0, npages_to_vmap * PAGE_SIZE);
+ vunmap(ptr);
+ }
+
+ return 0;
+}
+
static int ion_iommu_heap_allocate(struct ion_heap *heap,
struct ion_buffer *buffer,
unsigned long size, unsigned long align,
@@ -110,13 +186,14 @@
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;
- void *ptr = NULL;
- unsigned int npages_to_vmap, total_pages, num_large_pages = 0;
+ 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;
@@ -127,8 +204,10 @@
INIT_LIST_HEAD(&pages_list);
while (size_remaining > 0) {
- info = alloc_largest_available(size_remaining,
- max_order);
+ info = alloc_largest_available(iommu_heap,
+ size_remaining,
+ max_order,
+ flags);
if (!info) {
ret = -ENOMEM;
goto err_free_data;
@@ -188,44 +267,21 @@
kfree(info);
}
- /*
- * As an optimization, we omit __GFP_ZERO from
- * alloc_page above and 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_kernel);
- if (ptr)
- break;
- else
- npages_to_vmap >>= 1;
- }
- if (!ptr) {
+
+ if (flags & ION_FLAG_POOL_FORCE_ALLOC) {
+ ret = ion_iommu_buffer_zero(data);
+ if (ret) {
pr_err("Couldn't vmap the pages for zeroing\n");
- ret = -ENOMEM;
goto err3;
}
- memset(ptr, 0, npages_to_vmap * PAGE_SIZE);
- vunmap(ptr);
- }
- if (!ION_IS_CACHED(flags))
- dma_sync_sg_for_device(NULL, table->sgl, table->nents,
+
+ if (!ION_IS_CACHED(flags))
+ dma_sync_sg_for_device(NULL, table->sgl,
+ table->nents,
DMA_BIDIRECTIONAL);
+ }
buffer->priv_virt = data;
return 0;
@@ -262,14 +318,38 @@
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;
- for_each_sg(table->sgl, sg, table->nents, i)
- __free_pages(sg_page(sg), get_order(sg_dma_len(sg)));
+ if (!(buffer->flags & ION_FLAG_POOL_FORCE_ALLOC))
+ ion_iommu_buffer_zero(data);
+
+ 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);
@@ -354,6 +434,47 @@
{
}
+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,
@@ -367,6 +488,7 @@
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)
@@ -374,8 +496,66 @@
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)
diff --git a/drivers/gpu/ion/ion_system_heap.c b/drivers/gpu/ion/ion_system_heap.c
index 2bab7c4..44bb86f 100644
--- a/drivers/gpu/ion/ion_system_heap.c
+++ b/drivers/gpu/ion/ion_system_heap.c
@@ -139,8 +139,10 @@
continue;
info = kmalloc(sizeof(struct page_info), GFP_KERNEL);
- info->page = page;
- info->order = orders[i];
+ if (info) {
+ info->page = page;
+ info->order = orders[i];
+ }
return info;
}
return NULL;
diff --git a/drivers/gpu/ion/msm/ion_iommu_map.c b/drivers/gpu/ion/msm/ion_iommu_map.c
index 0a4fe1f..3e1a7ee 100644
--- a/drivers/gpu/ion/msm/ion_iommu_map.c
+++ b/drivers/gpu/ion/msm/ion_iommu_map.c
@@ -441,6 +441,7 @@
BUG_ON(iommu_meta->size != size);
mutex_unlock(&msm_iommu_map_mutex);
+ mutex_lock(&iommu_meta->lock);
iommu_map = ion_iommu_lookup(iommu_meta, domain_num, partition_num);
if (!iommu_map) {
iommu_map = __ion_iommu_map(iommu_meta, domain_num,
@@ -451,7 +452,7 @@
ret = 0;
} else {
ret = PTR_ERR(iommu_map);
- goto out;
+ goto out_unlock;
}
} else {
if (iommu_map->flags != iommu_flags) {
@@ -459,21 +460,24 @@
__func__, handle,
iommu_map->flags, iommu_flags);
ret = -EINVAL;
- goto out;
+ goto out_unlock;
} else if (iommu_map->mapped_size != iova_length) {
pr_err("%s: handle %p is already mapped with length %x, trying to map with length %lx\n",
__func__, handle, iommu_map->mapped_size,
iova_length);
ret = -EINVAL;
- goto out;
+ goto out_unlock;
} else {
kref_get(&iommu_map->ref);
*iova = iommu_map->iova_addr;
}
}
+ mutex_unlock(&iommu_meta->lock);
*buffer_size = size;
return ret;
+out_unlock:
+ mutex_unlock(&iommu_meta->lock);
out:
ion_iommu_meta_put(iommu_meta);
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index 4e3af1c..118c39a 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -17,7 +17,6 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/memory_alloc.h>
-#include <linux/fmem.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/mm.h>
@@ -265,6 +264,9 @@
}
}
+ if (!outer_cache_op)
+ return -EINVAL;
+
outer_cache_op(buff_phys_start + offset,
buff_phys_start + offset + length);
@@ -422,22 +424,9 @@
struct ion_co_heap_pdata *co_heap_data,
struct ion_cp_heap_pdata *cp_data)
{
- if (cp_data->reusable) {
- const struct fmem_data *fmem_info = fmem_get_info();
-
- if (!fmem_info) {
- pr_err("fmem info pointer NULL!\n");
- BUG();
- }
-
- heap->base = fmem_info->phys - fmem_info->reserved_size_low;
- cp_data->virt_addr = fmem_info->virt;
- pr_info("ION heap %s using FMEM\n", shared_heap->name);
- } else {
- heap->base = msm_ion_get_base(heap->size + shared_heap->size,
- shared_heap->memory_type,
- co_heap_data->align);
- }
+ heap->base = msm_ion_get_base(heap->size + shared_heap->size,
+ shared_heap->memory_type,
+ co_heap_data->align);
if (heap->base) {
shared_heap->base = heap->base + heap->size;
cp_data->secure_base = heap->base;
@@ -463,15 +452,6 @@
struct ion_cp_heap_pdata *cp_data =
(struct ion_cp_heap_pdata *) shared_heap->extra_data;
if (cp_data->fixed_position == FIXED_MIDDLE) {
- const struct fmem_data *fmem_info =
- fmem_get_info();
-
- if (!fmem_info) {
- pr_err("fmem info pointer NULL!\n");
- BUG();
- }
-
- cp_data->virt_addr = fmem_info->virt;
if (!cp_data->secure_base) {
cp_data->secure_base = heap->base;
cp_data->secure_size =
@@ -523,17 +503,6 @@
struct ion_cp_heap_pdata *data =
(struct ion_cp_heap_pdata *)
heap->extra_data;
- if (data->reusable) {
- const struct fmem_data *fmem_info =
- fmem_get_info();
- heap->base = fmem_info->phys;
- data->virt_addr = fmem_info->virt;
- pr_info("ION heap %s using FMEM\n", heap->name);
- } else if (data->mem_is_fmem) {
- const struct fmem_data *fmem_info =
- fmem_get_info();
- heap->base = fmem_info->phys + fmem_info->size;
- }
align = data->align;
break;
}
diff --git a/drivers/gpu/msm/Makefile b/drivers/gpu/msm/Makefile
index fc66328..118e033 100644
--- a/drivers/gpu/msm/Makefile
+++ b/drivers/gpu/msm/Makefile
@@ -17,7 +17,6 @@
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_MSM_DCVS) += kgsl_pwrscale_msm.o
msm_kgsl_core-$(CONFIG_SYNC) += kgsl_sync.o
msm_adreno-y += \
@@ -34,7 +33,7 @@
adreno_a3xx_snapshot.o \
adreno.o
-msm_adreno-$(CONFIG_DEBUG_FS) += adreno_debugfs.o
+msm_adreno-$(CONFIG_DEBUG_FS) += adreno_debugfs.o adreno_profile.o
msm_z180-y += \
z180.o \
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index ed266dc..b964620 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -23,8 +23,6 @@
#include <mach/socinfo.h>
#include <mach/msm_bus_board.h>
#include <mach/msm_bus.h>
-#include <mach/msm_dcvs.h>
-#include <mach/msm_dcvs_scm.h>
#include "kgsl.h"
#include "kgsl_pwrscale.h"
@@ -109,6 +107,10 @@
.pm4_fw = NULL,
.wait_timeout = 0, /* in milliseconds, 0 means disabled */
.ib_check_level = 0,
+ .ft_policy = KGSL_FT_DEFAULT_POLICY,
+ .ft_pf_policy = KGSL_FT_PAGEFAULT_DEFAULT_POLICY,
+ .fast_hang_detect = 1,
+ .long_ib_detect = 1,
};
/* This set of registers are used for Hang detection
@@ -123,20 +125,7 @@
#define LONG_IB_DETECT_REG_INDEX_START 1
#define LONG_IB_DETECT_REG_INDEX_END 5
-unsigned int ft_detect_regs[FT_DETECT_REGS_COUNT] = {
- A3XX_RBBM_STATUS,
- REG_CP_RB_RPTR, /* LONG_IB_DETECT_REG_INDEX_START */
- REG_CP_IB1_BASE,
- REG_CP_IB1_BUFSZ,
- REG_CP_IB2_BASE,
- REG_CP_IB2_BUFSZ, /* LONG_IB_DETECT_REG_INDEX_END */
- 0,
- 0,
- 0,
- 0,
- 0,
- 0
-};
+unsigned int ft_detect_regs[FT_DETECT_REGS_COUNT];
/*
* This is the master list of all GPU cores that are supported by this
@@ -224,6 +213,8 @@
512, 0, 2, SZ_128K, 0x3FF037, 0x3FF016 },
};
+static unsigned int adreno_isidle(struct kgsl_device *device);
+
/**
* adreno_perfcounter_init: Reserve kernel performance counters
* @device: device to configure
@@ -269,7 +260,9 @@
/* countable iter */
for (j = 0; j < group->reg_count; j++) {
if (group->regs[j].countable ==
- KGSL_PERFCOUNTER_NOT_USED)
+ KGSL_PERFCOUNTER_NOT_USED ||
+ group->regs[j].countable ==
+ KGSL_PERFCOUNTER_BROKEN)
continue;
if (adreno_dev->gpudev->perfcounter_enable)
@@ -281,7 +274,7 @@
}
/**
- * adreno_perfcounter_read_group: Determine which countables are in counters
+ * adreno_perfcounter_read_group() - Determine which countables are in counters
* @adreno_dev: Adreno device to configure
* @reads: List of kgsl_perfcounter_read_groups
* @count: Length of list
@@ -358,6 +351,61 @@
}
/**
+ * adreno_perfcounter_get_groupid() - Get the performance counter ID
+ * @adreno_dev: Adreno device
+ * @name: Performance counter group name string
+ *
+ * Get the groupid based on the name and return this ID
+ */
+
+int adreno_perfcounter_get_groupid(struct adreno_device *adreno_dev,
+ const char *name)
+{
+
+ struct adreno_perfcounters *counters = adreno_dev->gpudev->perfcounters;
+ struct adreno_perfcount_group *group;
+ int i;
+
+ if (name == NULL)
+ return -EINVAL;
+
+ /* perfcounter get/put/query not allowed on a2xx */
+ if (adreno_is_a2xx(adreno_dev))
+ return -EINVAL;
+
+ for (i = 0; i < counters->group_count; ++i) {
+ group = &(counters->groups[i]);
+ if (!strcmp(group->name, name))
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+/**
+ * adreno_perfcounter_get_name() - Get the group name
+ * @adreno_dev: Adreno device
+ * @groupid: Desired performance counter groupid
+ *
+ * Get the name based on the groupid and return it
+ */
+
+const char *adreno_perfcounter_get_name(struct adreno_device *adreno_dev,
+ unsigned int groupid)
+{
+ struct adreno_perfcounters *counters = adreno_dev->gpudev->perfcounters;
+
+ /* perfcounter get/put/query not allowed on a2xx */
+ if (adreno_is_a2xx(adreno_dev))
+ return NULL;
+
+ if (groupid >= counters->group_count)
+ return NULL;
+
+ return counters->groups[groupid].name;
+}
+
+/**
* adreno_perfcounter_query_group: Determine which countables are in counters
* @adreno_dev: Adreno device to configure
* @groupid: Desired performance counter group
@@ -450,8 +498,11 @@
for (i = 0; i < group->reg_count; i++) {
if (group->regs[i].countable == countable) {
/* Countable already associated with counter */
- group->regs[i].refcount++;
- group->regs[i].flags |= flags;
+ if (flags & PERFCOUNTER_FLAG_KERNEL)
+ group->regs[i].kernelcount++;
+ else
+ group->regs[i].usercount++;
+
if (offset)
*offset = group->regs[i].offset;
return 0;
@@ -468,14 +519,20 @@
/* initialize the new counter */
group->regs[empty].countable = countable;
- group->regs[empty].refcount = 1;
+
+ /* set initial kernel and user count */
+ if (flags & PERFCOUNTER_FLAG_KERNEL) {
+ group->regs[empty].kernelcount = 1;
+ group->regs[empty].usercount = 0;
+ } else {
+ group->regs[empty].kernelcount = 0;
+ group->regs[empty].usercount = 1;
+ }
/* enable the new counter */
adreno_dev->gpudev->perfcounter_enable(adreno_dev, groupid, empty,
countable);
- group->regs[empty].flags = flags;
-
if (offset)
*offset = group->regs[empty].offset;
@@ -488,12 +545,13 @@
* @adreno_dev: Adreno device to configure
* @groupid: Desired performance counter group
* @countable: Countable desired to be freed from a counter
+ * @flags: Flag to determine if kernel or user space request
*
* Put a performance counter/countable pair that was previously received. If
* noone else is using the countable, free up the counter for others.
*/
int adreno_perfcounter_put(struct adreno_device *adreno_dev,
- unsigned int groupid, unsigned int countable)
+ unsigned int groupid, unsigned int countable, unsigned int flags)
{
struct adreno_perfcounters *counters = adreno_dev->gpudev->perfcounters;
struct adreno_perfcount_group *group;
@@ -509,24 +567,27 @@
group = &(counters->groups[groupid]);
+ /*
+ * Find if the counter/countable pair is used currently.
+ * Start cycling through registers in the bank.
+ */
for (i = 0; i < group->reg_count; i++) {
+ /* check if countable assigned is what we are looking for */
if (group->regs[i].countable == countable) {
- if (group->regs[i].refcount > 0) {
- group->regs[i].refcount--;
+ /* found pair, book keep count based on request type */
+ if (flags & PERFCOUNTER_FLAG_KERNEL &&
+ group->regs[i].kernelcount > 0)
+ group->regs[i].kernelcount--;
+ else if (group->regs[i].usercount > 0)
+ group->regs[i].usercount--;
+ else
+ break;
- /*
- * book keeping to ensure we never free a
- * perf counter used by kernel
- */
- if (group->regs[i].flags &&
- group->regs[i].refcount == 0)
- group->regs[i].refcount++;
-
- /* make available if not used */
- if (group->regs[i].refcount == 0)
- group->regs[i].countable =
- KGSL_PERFCOUNTER_NOT_USED;
- }
+ /* mark available if not used anymore */
+ if (group->regs[i].kernelcount == 0 &&
+ group->regs[i].usercount == 0)
+ group->regs[i].countable =
+ KGSL_PERFCOUNTER_NOT_USED;
return 0;
}
@@ -568,6 +629,8 @@
kgsl_mmu_unmap(pagetable, &device->memstore);
+ kgsl_mmu_unmap(pagetable, &adreno_dev->profile.shared_buffer);
+
kgsl_mmu_unmap(pagetable, &device->mmu.setstate_memory);
}
@@ -590,6 +653,11 @@
if (result)
goto unmap_memptrs_desc;
+ result = kgsl_mmu_map_global(pagetable,
+ &adreno_dev->profile.shared_buffer);
+ if (result)
+ goto unmap_profile_shared;
+
result = kgsl_mmu_map_global(pagetable, &device->mmu.setstate_memory);
if (result)
goto unmap_memstore_desc;
@@ -603,6 +671,9 @@
device->mmu.setstate_memory.size;
return result;
+unmap_profile_shared:
+ kgsl_mmu_unmap(pagetable, &adreno_dev->profile.shared_buffer);
+
unmap_memstore_desc:
kgsl_mmu_unmap(pagetable, &device->memstore);
@@ -730,6 +801,7 @@
phys_addr_t pt_val,
int num_iommu_units, uint32_t flags)
{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
phys_addr_t ttbr0_val;
unsigned int reg_pt_val;
unsigned int *cmds = cmds_orig;
@@ -759,7 +831,9 @@
* WAIT_FOR_ME
*/
cmds += adreno_wait_reg_eq(cmds,
- A3XX_CP_WFI_PEND_CTR, 1, 0xFFFFFFFF, 0xF);
+ adreno_getreg(adreno_dev,
+ ADRENO_REG_CP_WFI_PEND_CTR),
+ 1, 0xFFFFFFFF, 0xF);
/* set the iommu lock bit */
*cmds++ = cp_type3_packet(CP_REG_RMW, 3);
@@ -826,6 +900,27 @@
return cmds - cmds_orig;
}
+/**
+ * adreno_use_default_setstate() - Use CPU instead of the GPU to manage the mmu?
+ * @adreno_dev: the device
+ *
+ * In many cases it is preferable to poke the iommu or gpummu directly rather
+ * than using the GPU command stream. If we are idle or trying to go to a low
+ * power state, using the command stream will be slower and asynchronous, which
+ * needlessly complicates the power state transitions. Additionally,
+ * the hardware simulators do not support command stream MMU operations so
+ * the command stream can never be used if we are capturing CFF data.
+ *
+ */
+static bool adreno_use_default_setstate(struct adreno_device *adreno_dev)
+{
+ return (adreno_isidle(&adreno_dev->dev) ||
+ adreno_dev->drawctxt_active == NULL ||
+ KGSL_STATE_ACTIVE != adreno_dev->dev.state ||
+ atomic_read(&adreno_dev->dev.active_cnt) == 0 ||
+ adreno_dev->dev.cff_dump_enable);
+}
+
static void adreno_iommu_setstate(struct kgsl_device *device,
unsigned int context_id,
uint32_t flags)
@@ -840,22 +935,17 @@
struct adreno_context *adreno_ctx = NULL;
struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
- if (!adreno_dev->drawctxt_active ||
- KGSL_STATE_ACTIVE != device->state ||
- !atomic_read(&device->active_cnt) ||
- device->cff_dump_enable) {
+ if (adreno_use_default_setstate(adreno_dev)) {
kgsl_mmu_device_setstate(&device->mmu, flags);
return;
}
num_iommu_units = kgsl_mmu_get_num_iommu_units(&device->mmu);
- context = idr_find(&device->context_idr, context_id);
+ context = kgsl_context_get(device, context_id);
if (context == NULL)
return;
- kgsl_context_get(context);
-
- adreno_ctx = context->devctxt;
+ adreno_ctx = ADRENO_CONTEXT(context);
if (kgsl_mmu_enable_clk(&device->mmu,
KGSL_IOMMU_CONTEXT_USER))
@@ -896,9 +986,7 @@
adreno_ringbuffer_issuecmds(device, adreno_ctx, KGSL_CMD_FLAGS_PMODE,
&link[0], sizedwords);
- kgsl_mmu_disable_clk_on_ts(&device->mmu,
- rb->timestamp[KGSL_MEMSTORE_GLOBAL], true);
-
+ kgsl_mmu_disable_clk_on_ts(&device->mmu, rb->global_ts, true);
kgsl_context_put(context);
}
@@ -926,11 +1014,11 @@
* writes For CFF dump we must idle and use the registers so that it is
* easier to filter out the mmu accesses from the dump
*/
- if (!device->cff_dump_enable && adreno_dev->drawctxt_active) {
- context = idr_find(&device->context_idr, context_id);
+ if (!adreno_use_default_setstate(adreno_dev)) {
+ context = kgsl_context_get(device, context_id);
if (context == NULL)
return;
- adreno_ctx = context->devctxt;
+ adreno_ctx = ADRENO_CONTEXT(context);
if (flags & KGSL_MMUFLAGS_PTUPDATE) {
/* wait for graphics pipe to be idle */
@@ -1007,6 +1095,8 @@
adreno_ringbuffer_issuecmds(device, adreno_ctx,
KGSL_CMD_FLAGS_PMODE,
&link[0], sizedwords);
+
+ kgsl_context_put(context);
} else {
kgsl_mmu_device_setstate(&device->mmu, flags);
}
@@ -1051,9 +1141,9 @@
if (pdata->chipid != 0)
return pdata->chipid;
- adreno_regread(device, REG_RBBM_PERIPHID1, &coreid);
- adreno_regread(device, REG_RBBM_PERIPHID2, &majorid);
- adreno_regread(device, REG_RBBM_PATCH_RELEASE, &revid);
+ kgsl_regread(device, REG_RBBM_PERIPHID1, &coreid);
+ kgsl_regread(device, REG_RBBM_PERIPHID2, &majorid);
+ kgsl_regread(device, REG_RBBM_PATCH_RELEASE, &revid);
/*
* adreno 22x gpus are indicated by coreid 2,
@@ -1142,6 +1232,17 @@
adreno_dev->pfp_jt_idx = adreno_gpulist[i].pfp_jt_idx;
adreno_dev->pfp_jt_addr = adreno_gpulist[i].pfp_jt_addr;
adreno_dev->gpulist_index = i;
+ /*
+ * Initialize uninitialzed gpu registers, only needs to be done once
+ * Make all offsets that are not initialized to ADRENO_REG_UNUSED
+ */
+ for (i = 0; i < ADRENO_REG_REGISTER_MAX; i++) {
+ if (adreno_dev->gpudev->reg_offsets->offset_0 != i &&
+ !adreno_dev->gpudev->reg_offsets->offsets[i]) {
+ adreno_dev->gpudev->reg_offsets->offsets[i] =
+ ADRENO_REG_UNUSED;
+ }
+ }
}
static struct platform_device_id adreno_id_table[] = {
@@ -1243,172 +1344,6 @@
}
-static struct msm_dcvs_core_info *adreno_of_get_dcvs(struct device_node *parent)
-{
- struct device_node *node, *child;
- struct msm_dcvs_core_info *info = NULL;
- int count = 0;
- int ret = -EINVAL;
-
- node = adreno_of_find_subnode(parent, "qcom,dcvs-core-info");
- if (node == NULL)
- return ERR_PTR(-EINVAL);
-
- info = kzalloc(sizeof(*info), GFP_KERNEL);
-
- if (info == NULL) {
- KGSL_CORE_ERR("kzalloc(%d) failed\n", sizeof(*info));
- ret = -ENOMEM;
- goto err;
- }
-
- for_each_child_of_node(node, child)
- count++;
-
- info->power_param.num_freq = count;
-
- info->freq_tbl = kzalloc(info->power_param.num_freq *
- sizeof(struct msm_dcvs_freq_entry),
- GFP_KERNEL);
-
- if (info->freq_tbl == NULL) {
- KGSL_CORE_ERR("kzalloc(%d) failed\n",
- info->power_param.num_freq *
- sizeof(struct msm_dcvs_freq_entry));
- ret = -ENOMEM;
- goto err;
- }
-
- for_each_child_of_node(node, child) {
- unsigned int index;
-
- if (adreno_of_read_property(child, "reg", &index))
- goto err;
-
- if (index >= info->power_param.num_freq) {
- KGSL_CORE_ERR("DCVS freq entry %d is out of range\n",
- index);
- continue;
- }
-
- if (adreno_of_read_property(child, "qcom,freq",
- &info->freq_tbl[index].freq))
- goto err;
-
- if (adreno_of_read_property(child, "qcom,voltage",
- &info->freq_tbl[index].voltage))
- info->freq_tbl[index].voltage = 0;
-
- if (adreno_of_read_property(child, "qcom,is_trans_level",
- &info->freq_tbl[index].is_trans_level))
- info->freq_tbl[index].is_trans_level = 0;
-
- if (adreno_of_read_property(child, "qcom,active-energy-offset",
- &info->freq_tbl[index].active_energy_offset))
- info->freq_tbl[index].active_energy_offset = 0;
-
- if (adreno_of_read_property(child, "qcom,leakage-energy-offset",
- &info->freq_tbl[index].leakage_energy_offset))
- info->freq_tbl[index].leakage_energy_offset = 0;
- }
-
- if (adreno_of_read_property(node, "qcom,num-cores", &info->num_cores))
- goto err;
-
- info->sensors = kzalloc(info->num_cores *
- sizeof(int),
- GFP_KERNEL);
-
- for (count = 0; count < info->num_cores; count++) {
- if (adreno_of_read_property(node, "qcom,sensors",
- &(info->sensors[count])))
- goto err;
- }
-
- if (adreno_of_read_property(node, "qcom,core-core-type",
- &info->core_param.core_type))
- goto err;
-
- if (adreno_of_read_property(node, "qcom,algo-disable-pc-threshold",
- &info->algo_param.disable_pc_threshold))
- goto err;
- if (adreno_of_read_property(node, "qcom,algo-em-win-size-min-us",
- &info->algo_param.em_win_size_min_us))
- goto err;
- if (adreno_of_read_property(node, "qcom,algo-em-win-size-max-us",
- &info->algo_param.em_win_size_max_us))
- goto err;
- if (adreno_of_read_property(node, "qcom,algo-em-max-util-pct",
- &info->algo_param.em_max_util_pct))
- goto err;
- if (adreno_of_read_property(node, "qcom,algo-group-id",
- &info->algo_param.group_id))
- goto err;
- if (adreno_of_read_property(node, "qcom,algo-max-freq-chg-time-us",
- &info->algo_param.max_freq_chg_time_us))
- goto err;
- if (adreno_of_read_property(node, "qcom,algo-slack-mode-dynamic",
- &info->algo_param.slack_mode_dynamic))
- goto err;
- if (adreno_of_read_property(node, "qcom,algo-slack-weight-thresh-pct",
- &info->algo_param.slack_weight_thresh_pct))
- goto err;
- if (adreno_of_read_property(node, "qcom,algo-slack-time-min-us",
- &info->algo_param.slack_time_min_us))
- goto err;
- if (adreno_of_read_property(node, "qcom,algo-slack-time-max-us",
- &info->algo_param.slack_time_max_us))
- goto err;
- if (adreno_of_read_property(node, "qcom,algo-ss-win-size-min-us",
- &info->algo_param.ss_win_size_min_us))
- goto err;
- if (adreno_of_read_property(node, "qcom,algo-ss-win-size-max-us",
- &info->algo_param.ss_win_size_max_us))
- goto err;
- if (adreno_of_read_property(node, "qcom,algo-ss-util-pct",
- &info->algo_param.ss_util_pct))
- goto err;
- if (adreno_of_read_property(node, "qcom,algo-ss-no-corr-below-freq",
- &info->algo_param.ss_no_corr_below_freq))
- goto err;
-
- if (adreno_of_read_property(node, "qcom,energy-active-coeff-a",
- &info->energy_coeffs.active_coeff_a))
- goto err;
- if (adreno_of_read_property(node, "qcom,energy-active-coeff-b",
- &info->energy_coeffs.active_coeff_b))
- goto err;
- if (adreno_of_read_property(node, "qcom,energy-active-coeff-c",
- &info->energy_coeffs.active_coeff_c))
- goto err;
- if (adreno_of_read_property(node, "qcom,energy-leakage-coeff-a",
- &info->energy_coeffs.leakage_coeff_a))
- goto err;
- if (adreno_of_read_property(node, "qcom,energy-leakage-coeff-b",
- &info->energy_coeffs.leakage_coeff_b))
- goto err;
- if (adreno_of_read_property(node, "qcom,energy-leakage-coeff-c",
- &info->energy_coeffs.leakage_coeff_c))
- goto err;
- if (adreno_of_read_property(node, "qcom,energy-leakage-coeff-d",
- &info->energy_coeffs.leakage_coeff_d))
- goto err;
-
- if (adreno_of_read_property(node, "qcom,power-current-temp",
- &info->power_param.current_temp))
- goto err;
-
- return info;
-
-err:
- if (info)
- kfree(info->freq_tbl);
-
- kfree(info);
-
- return ERR_PTR(ret);
-}
-
static int adreno_of_get_iommu(struct device_node *parent,
struct kgsl_device_platform_data *pdata)
{
@@ -1545,12 +1480,8 @@
pdata->bus_scale_table = msm_bus_cl_get_pdata(pdev);
if (IS_ERR_OR_NULL(pdata->bus_scale_table)) {
ret = PTR_ERR(pdata->bus_scale_table);
- goto err;
- }
-
- pdata->core_info = adreno_of_get_dcvs(pdev->dev.of_node);
- if (IS_ERR_OR_NULL(pdata->core_info)) {
- ret = PTR_ERR(pdata->core_info);
+ if (!ret)
+ ret = -EINVAL;
goto err;
}
@@ -1566,10 +1497,6 @@
err:
if (pdata) {
- if (pdata->core_info)
- kfree(pdata->core_info->freq_tbl);
- kfree(pdata->core_info);
-
if (pdata->iommu_data)
kfree(pdata->iommu_data->iommu_ctxs);
@@ -1660,6 +1587,9 @@
goto error_close_rb;
adreno_debugfs_init(device);
+ adreno_profile_init(device);
+
+ adreno_ft_init_sysfs(device);
kgsl_pwrscale_init(device);
kgsl_pwrscale_attach_policy(device, ADRENO_DEFAULT_PWRSCALE_POLICY);
@@ -1688,6 +1618,7 @@
adreno_dev = ADRENO_DEVICE(device);
adreno_coresight_remove(pdev);
+ adreno_profile_close(device);
kgsl_pwrscale_detach_policy(device);
kgsl_pwrscale_close(device);
@@ -1701,7 +1632,7 @@
static int adreno_init(struct kgsl_device *device)
{
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+ int i;
if (KGSL_STATE_DUMP_AND_FT != device->state)
kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
@@ -1741,11 +1672,21 @@
adreno_gpulist[adreno_dev->gpulist_index].sync_lock_pfp_ver))
device->mmu.flags |= KGSL_MMU_FLAGS_IOMMU_SYNC;
- rb->timestamp[KGSL_MEMSTORE_GLOBAL] = 0;
-
- /* Assign correct RBBM status register to hang detect regs
- */
- ft_detect_regs[0] = adreno_dev->gpudev->reg_rbbm_status;
+ /* Initialize ft detection register offsets */
+ ft_detect_regs[0] = adreno_getreg(adreno_dev,
+ ADRENO_REG_RBBM_STATUS);
+ ft_detect_regs[1] = adreno_getreg(adreno_dev,
+ ADRENO_REG_CP_RB_RPTR);
+ ft_detect_regs[2] = adreno_getreg(adreno_dev,
+ ADRENO_REG_CP_IB1_BASE);
+ ft_detect_regs[3] = adreno_getreg(adreno_dev,
+ ADRENO_REG_CP_IB1_BUFSZ);
+ ft_detect_regs[4] = adreno_getreg(adreno_dev,
+ ADRENO_REG_CP_IB2_BASE);
+ ft_detect_regs[5] = adreno_getreg(adreno_dev,
+ ADRENO_REG_CP_IB2_BUFSZ);
+ for (i = 6; i < FT_DETECT_REGS_COUNT; i++)
+ ft_detect_regs[i] = 0;
adreno_perfcounter_init(device);
@@ -1760,12 +1701,17 @@
int status = -EINVAL;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
unsigned int state = device->state;
+ unsigned int regulator_left_on = 0;
kgsl_cffdump_open(device);
if (KGSL_STATE_DUMP_AND_FT != device->state)
kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
+ regulator_left_on = (regulator_is_enabled(device->pwrctrl.gpu_reg) ||
+ (device->pwrctrl.gpu_cx &&
+ regulator_is_enabled(device->pwrctrl.gpu_cx)));
+
/* Power up the device */
kgsl_pwrctrl_enable(device);
@@ -1793,6 +1739,14 @@
goto error_mmu_off;
}
+ if (regulator_left_on && adreno_dev->gpudev->soft_reset) {
+ /*
+ * Reset the GPU for A3xx. A2xx does a soft reset in
+ * the start function.
+ */
+ adreno_dev->gpudev->soft_reset(adreno_dev);
+ }
+
/* Start the GPU */
adreno_dev->gpudev->start(adreno_dev);
@@ -1832,6 +1786,9 @@
{
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ if (adreno_dev->drawctxt_active)
+ kgsl_context_put(&adreno_dev->drawctxt_active->base);
+
adreno_dev->drawctxt_active = NULL;
adreno_ringbuffer_stop(&adreno_dev->ringbuffer);
@@ -1853,59 +1810,75 @@
return 0;
}
+/*
+ * Set the reset status of all contexts to
+ * INNOCENT_CONTEXT_RESET_EXT except for the bad context
+ * since thats the guilty party, if fault tolerance failed then
+ * mark all as guilty
+ */
+
+static int _mark_context_status(int id, void *ptr, void *data)
+{
+ unsigned int ft_status = *((unsigned int *) data);
+ struct kgsl_context *context = ptr;
+ struct adreno_context *adreno_context = ADRENO_CONTEXT(context);
+
+ if (ft_status) {
+ context->reset_status =
+ KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT;
+ adreno_context->flags |= CTXT_FLAGS_GPU_HANG;
+ } else if (KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT !=
+ context->reset_status) {
+ if (adreno_context->flags & (CTXT_FLAGS_GPU_HANG |
+ CTXT_FLAGS_GPU_HANG_FT))
+ context->reset_status =
+ KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT;
+ else
+ context->reset_status =
+ KGSL_CTX_STAT_INNOCENT_CONTEXT_RESET_EXT;
+ }
+
+ return 0;
+}
+
static void adreno_mark_context_status(struct kgsl_device *device,
int ft_status)
{
- struct kgsl_context *context;
- int next = 0;
- /*
- * Set the reset status of all contexts to
- * INNOCENT_CONTEXT_RESET_EXT except for the bad context
- * since thats the guilty party, if fault tolerance failed then
- * mark all as guilty
- */
- while ((context = idr_get_next(&device->context_idr, &next))) {
- struct adreno_context *adreno_context = context->devctxt;
- if (ft_status) {
- context->reset_status =
- KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT;
- adreno_context->flags |= CTXT_FLAGS_GPU_HANG;
- } else if (KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT !=
- context->reset_status) {
- if (adreno_context->flags & (CTXT_FLAGS_GPU_HANG |
- CTXT_FLAGS_GPU_HANG_FT))
- context->reset_status =
- KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT;
- else
- context->reset_status =
- KGSL_CTX_STAT_INNOCENT_CONTEXT_RESET_EXT;
- }
- next = next + 1;
+ /* Mark the status for all the contexts in the device */
+
+ read_lock(&device->context_lock);
+ idr_for_each(&device->context_idr, _mark_context_status, &ft_status);
+ read_unlock(&device->context_lock);
+}
+
+/*
+ * For hung contexts set the current memstore value to the most recent issued
+ * timestamp - this resets the status and lets the system continue on
+ */
+
+static int _set_max_ts(int id, void *ptr, void *data)
+{
+ struct kgsl_device *device = data;
+ struct kgsl_context *context = ptr;
+ struct adreno_context *drawctxt = ADRENO_CONTEXT(context);
+
+ if (drawctxt && drawctxt->flags & CTXT_FLAGS_GPU_HANG) {
+ kgsl_sharedmem_writel(device, &device->memstore,
+ KGSL_MEMSTORE_OFFSET(context->id,
+ soptimestamp), drawctxt->timestamp);
+ kgsl_sharedmem_writel(device, &device->memstore,
+ KGSL_MEMSTORE_OFFSET(context->id,
+ eoptimestamp), drawctxt->timestamp);
}
+
+ return 0;
}
static void adreno_set_max_ts_for_bad_ctxs(struct kgsl_device *device)
{
- struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
- struct kgsl_context *context;
- struct adreno_context *temp_adreno_context;
- int next = 0;
-
- while ((context = idr_get_next(&device->context_idr, &next))) {
- temp_adreno_context = context->devctxt;
- if (temp_adreno_context->flags & CTXT_FLAGS_GPU_HANG) {
- kgsl_sharedmem_writel(device, &device->memstore,
- KGSL_MEMSTORE_OFFSET(context->id,
- soptimestamp),
- rb->timestamp[context->id]);
- kgsl_sharedmem_writel(device, &device->memstore,
- KGSL_MEMSTORE_OFFSET(context->id,
- eoptimestamp),
- rb->timestamp[context->id]);
- }
- next = next + 1;
- }
+ read_lock(&device->context_lock);
+ idr_for_each(&device->context_idr, _set_max_ts, device);
+ read_unlock(&device->context_lock);
}
static void adreno_destroy_ft_data(struct adreno_ft_data *ft_data)
@@ -2095,7 +2068,7 @@
ft_data->start_of_replay_cmds = 0xFFFFFFFF;
ft_data->replay_for_snapshot = 0xFFFFFFFF;
- adreno_regread(device, REG_CP_IB1_BASE, &ft_data->ib1);
+ adreno_readreg(adreno_dev, ADRENO_REG_CP_IB1_BASE, &ft_data->ib1);
kgsl_sharedmem_readl(&device->memstore, &ft_data->context_id,
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
@@ -2132,7 +2105,7 @@
ft_data->status = 0;
/* find the start of bad command sequence in rb */
- context = idr_find(&device->context_idr, ft_data->context_id);
+ context = kgsl_context_get(device, ft_data->context_id);
ft_data->ft_policy = adreno_dev->ft_policy;
@@ -2144,14 +2117,14 @@
ft_data->global_eop + 1, false);
if (ret) {
ft_data->ft_policy |= KGSL_FT_TEMP_DISABLE;
- return;
+ goto done;
} else {
ft_data->start_of_replay_cmds = rb_rptr;
ft_data->ft_policy &= ~KGSL_FT_TEMP_DISABLE;
}
if (context) {
- adreno_context = context->devctxt;
+ adreno_context = ADRENO_CONTEXT(context);
if (adreno_context->flags & CTXT_FLAGS_PREAMBLE) {
if (ft_data->ib1) {
ret = _find_hanging_ib_sequence(rb,
@@ -2159,14 +2132,16 @@
if (ret) {
KGSL_FT_ERR(device,
"Start not found for replay IB seq\n");
- ret = 0;
- return;
+ goto done;
}
ft_data->start_of_replay_cmds = rb_rptr;
ft_data->replay_for_snapshot = rb_rptr;
}
}
}
+
+done:
+ kgsl_context_put(context);
}
static int
@@ -2216,6 +2191,9 @@
return -EINVAL;
}
+ if (adreno_dev->drawctxt_active)
+ kgsl_context_put(&adreno_dev->drawctxt_active->base);
+
adreno_dev->drawctxt_active = NULL;
/* Stop the ringbuffer */
@@ -2278,11 +2256,9 @@
}
reset_done:
- if (context) {
- struct adreno_context *adreno_context = context->devctxt;
- kgsl_mmu_setstate(&device->mmu, adreno_context->pagetable,
- KGSL_MEMSTORE_GLOBAL);
- }
+ if (context)
+ kgsl_mmu_setstate(&device->mmu, context->pagetable,
+ KGSL_MEMSTORE_GLOBAL);
/* If iommu is used then we need to make sure that the iommu clocks
* are on since there could be commands in pipeline that touch iommu */
@@ -2386,7 +2362,8 @@
static int no_context_ft;
struct kgsl_mmu *mmu = &device->mmu;
- context = idr_find(&device->context_idr, ft_data->context_id);
+ context = kgsl_context_get(device, ft_data->context_id);
+
if (context == NULL) {
KGSL_FT_ERR(device, "Last context unknown id:%d\n",
ft_data->context_id);
@@ -2400,7 +2377,7 @@
}
} else {
no_context_ft = 0;
- adreno_context = context->devctxt;
+ adreno_context = ADRENO_CONTEXT(context);
adreno_context->flags |= CTXT_FLAGS_GPU_HANG;
/*
* set the invalid ts flag to 0 for this context since we have
@@ -2456,16 +2433,16 @@
goto play_good_cmds;
}
- /* Do not try the reply if hang is due to a pagefault */
- if (adreno_context && adreno_context->pagefault) {
+ /* Do not try to replay if hang is due to a pagefault */
+ if (context && test_bit(KGSL_CONTEXT_PAGEFAULT, &context->priv)) {
/* Resume MMU */
mmu->mmu_ops->mmu_pagefault_resume(mmu);
- if ((ft_data->context_id == adreno_context->id) &&
- (ft_data->global_eop == adreno_context->pagefault_ts)) {
+ if ((ft_data->context_id == context->id) &&
+ (ft_data->global_eop == context->pagefault_ts)) {
ft_data->ft_policy &= ~KGSL_FT_REPLAY;
KGSL_FT_ERR(device, "MMU fault skipping replay\n");
}
- adreno_context->pagefault = 0;
+ clear_bit(KGSL_CONTEXT_PAGEFAULT, &context->priv);
}
if (ft_data->ft_policy & KGSL_FT_REPLAY) {
@@ -2553,6 +2530,10 @@
adreno_context->flags = (adreno_context->flags &
~CTXT_FLAGS_GPU_HANG) | CTXT_FLAGS_GPU_HANG_FT;
}
+
+ if (last_active_ctx)
+ _kgsl_context_get(&last_active_ctx->base);
+
adreno_dev->drawctxt_active = last_active_ctx;
}
@@ -2577,17 +2558,18 @@
/* ringbuffer now has data from the last valid context id,
* so restore the active_ctx to the last valid context */
if (ft_data->last_valid_ctx_id) {
- struct kgsl_context *last_ctx =
- idr_find(&device->context_idr,
- ft_data->last_valid_ctx_id);
- if (last_ctx)
- adreno_dev->drawctxt_active = last_ctx->devctxt;
+ struct kgsl_context *last_ctx = kgsl_context_get(device,
+ ft_data->last_valid_ctx_id);
+
+ adreno_dev->drawctxt_active = ADRENO_CONTEXT(last_ctx);
}
done:
/* Turn off iommu clocks */
if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype())
kgsl_mmu_disable_clk_on_ts(&device->mmu, 0, false);
+
+ kgsl_context_put(context);
return ret;
}
@@ -2598,7 +2580,6 @@
int ret = 0;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
- unsigned int timestamp;
/*
* If GPU FT is turned off do not run FT.
@@ -2615,8 +2596,8 @@
"Bad context_id: %u, global_eop: 0x%x\n",
ft_data->ib1, ft_data->context_id, ft_data->global_eop);
- timestamp = rb->timestamp[KGSL_MEMSTORE_GLOBAL];
- KGSL_FT_INFO(device, "Last issued global timestamp: %x\n", timestamp);
+ KGSL_FT_INFO(device, "Last issued global timestamp: %x\n",
+ rb->global_ts);
/* We may need to replay commands multiple times based on whether
* multiple contexts hang the GPU */
@@ -2645,14 +2626,12 @@
/* Restore correct states after fault tolerance */
if (adreno_dev->drawctxt_active)
device->mmu.hwpagetable =
- adreno_dev->drawctxt_active->pagetable;
+ adreno_dev->drawctxt_active->base.pagetable;
else
device->mmu.hwpagetable = device->mmu.defaultpagetable;
- rb->timestamp[KGSL_MEMSTORE_GLOBAL] = timestamp;
kgsl_sharedmem_writel(device, &device->memstore,
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
- eoptimestamp),
- rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
+ eoptimestamp), rb->global_ts);
/* switch to NULL ctxt */
if (adreno_dev->drawctxt_active != NULL)
@@ -2743,6 +2722,264 @@
}
EXPORT_SYMBOL(adreno_dump_and_exec_ft);
+/**
+ * _ft_sysfs_store() - Common routine to write to FT sysfs files
+ * @buf: value to write
+ * @count: size of the value to write
+ * @sysfs_cfg: KGSL FT sysfs config to write
+ *
+ * This is a common routine to write to FT sysfs files.
+ */
+static int _ft_sysfs_store(const char *buf, size_t count, unsigned int *ptr)
+{
+ char temp[20];
+ unsigned long val;
+ int rc;
+
+ snprintf(temp, sizeof(temp), "%.*s",
+ (int)min(count, sizeof(temp) - 1), buf);
+ rc = kstrtoul(temp, 0, &val);
+ if (rc)
+ return rc;
+
+ *ptr = val;
+
+ return count;
+}
+
+/**
+ * _get_adreno_dev() - Routine to get a pointer to adreno dev
+ * @dev: device ptr
+ * @attr: Device attribute
+ * @buf: value to write
+ * @count: size of the value to write
+ */
+struct adreno_device *_get_adreno_dev(struct device *dev)
+{
+ struct kgsl_device *device = kgsl_device_from_dev(dev);
+ return device ? ADRENO_DEVICE(device) : NULL;
+}
+
+/**
+ * _ft_policy_store() - Routine to configure FT policy
+ * @dev: device ptr
+ * @attr: Device attribute
+ * @buf: value to write
+ * @count: size of the value to write
+ *
+ * FT policy can be set to any of the options below.
+ * KGSL_FT_DISABLE -> BIT(0) Set to disable FT
+ * KGSL_FT_REPLAY -> BIT(1) Set to enable replay
+ * KGSL_FT_SKIPIB -> BIT(2) Set to skip IB
+ * KGSL_FT_SKIPFRAME -> BIT(3) Set to skip frame
+ * by default set FT policy to KGSL_FT_DEFAULT_POLICY
+ */
+static int _ft_policy_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct adreno_device *adreno_dev = _get_adreno_dev(dev);
+ int ret;
+ if (adreno_dev == NULL)
+ return 0;
+
+ mutex_lock(&adreno_dev->dev.mutex);
+ ret = _ft_sysfs_store(buf, count, &adreno_dev->ft_policy);
+ mutex_unlock(&adreno_dev->dev.mutex);
+
+ return ret;
+}
+
+/**
+ * _ft_policy_show() - Routine to read FT policy
+ * @dev: device ptr
+ * @attr: Device attribute
+ * @buf: value read
+ *
+ * This is a routine to read current FT policy
+ */
+static int _ft_policy_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct adreno_device *adreno_dev = _get_adreno_dev(dev);
+ if (adreno_dev == NULL)
+ return 0;
+ return snprintf(buf, PAGE_SIZE, "0x%X\n", adreno_dev->ft_policy);
+}
+
+/**
+ * _ft_pagefault_policy_store() - Routine to configure FT
+ * pagefault policy
+ * @dev: device ptr
+ * @attr: Device attribute
+ * @buf: value to write
+ * @count: size of the value to write
+ *
+ * FT pagefault policy can be set to any of the options below.
+ * KGSL_FT_PAGEFAULT_INT_ENABLE -> BIT(0) set to enable pagefault INT
+ * KGSL_FT_PAGEFAULT_GPUHALT_ENABLE -> BIT(1) Set to enable GPU HALT on
+ * pagefaults. This stalls the GPU on a pagefault on IOMMU v1 HW.
+ * KGSL_FT_PAGEFAULT_LOG_ONE_PER_PAGE -> BIT(2) Set to log only one
+ * pagefault per page.
+ * KGSL_FT_PAGEFAULT_LOG_ONE_PER_INT -> BIT(3) Set to log only one
+ * pagefault per INT.
+ */
+static int _ft_pagefault_policy_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct adreno_device *adreno_dev = _get_adreno_dev(dev);
+ int ret;
+ if (adreno_dev == NULL)
+ return 0;
+
+ mutex_lock(&adreno_dev->dev.mutex);
+ ret = _ft_sysfs_store(buf, count, &adreno_dev->ft_pf_policy);
+ mutex_unlock(&adreno_dev->dev.mutex);
+
+ return ret;
+}
+
+/**
+ * _ft_pagefault_policy_show() - Routine to read FT pagefault
+ * policy
+ * @dev: device ptr
+ * @attr: Device attribute
+ * @buf: value read
+ *
+ * This is a routine to read current FT pagefault policy
+ */
+static int _ft_pagefault_policy_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct adreno_device *adreno_dev = _get_adreno_dev(dev);
+ if (adreno_dev == NULL)
+ return 0;
+ return snprintf(buf, PAGE_SIZE, "0x%X\n", adreno_dev->ft_pf_policy);
+}
+
+/**
+ * _ft_fast_hang_detect_store() - Routine to configure FT fast
+ * hang detect policy
+ * @dev: device ptr
+ * @attr: Device attribute
+ * @buf: value to write
+ * @count: size of the value to write
+ *
+ * 0x1 - Enable fast hang detection
+ * 0x0 - Disable fast hang detection
+ */
+static int _ft_fast_hang_detect_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct adreno_device *adreno_dev = _get_adreno_dev(dev);
+ int ret;
+ if (adreno_dev == NULL)
+ return 0;
+
+ mutex_lock(&adreno_dev->dev.mutex);
+ ret = _ft_sysfs_store(buf, count, &adreno_dev->fast_hang_detect);
+ mutex_unlock(&adreno_dev->dev.mutex);
+
+ return ret;
+
+}
+
+/**
+ * _ft_fast_hang_detect_show() - Routine to read FT fast
+ * hang detect policy
+ * @dev: device ptr
+ * @attr: Device attribute
+ * @buf: value read
+ */
+static int _ft_fast_hang_detect_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct adreno_device *adreno_dev = _get_adreno_dev(dev);
+ if (adreno_dev == NULL)
+ return 0;
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ (adreno_dev->fast_hang_detect ? 1 : 0));
+}
+
+/**
+ * _ft_long_ib_detect_store() - Routine to configure FT long IB
+ * detect policy
+ * @dev: device ptr
+ * @attr: Device attribute
+ * @buf: value to write
+ * @count: size of the value to write
+ *
+ * 0x0 - Enable long IB detection
+ * 0x1 - Disable long IB detection
+ */
+static int _ft_long_ib_detect_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct adreno_device *adreno_dev = _get_adreno_dev(dev);
+ int ret;
+ if (adreno_dev == NULL)
+ return 0;
+
+ mutex_lock(&adreno_dev->dev.mutex);
+ ret = _ft_sysfs_store(buf, count, &adreno_dev->long_ib_detect);
+ mutex_unlock(&adreno_dev->dev.mutex);
+
+ return ret;
+
+}
+
+/**
+ * _ft_long_ib_detect_show() - Routine to read FT long IB
+ * detect policy
+ * @dev: device ptr
+ * @attr: Device attribute
+ * @buf: value read
+ */
+static int _ft_long_ib_detect_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct adreno_device *adreno_dev = _get_adreno_dev(dev);
+ if (adreno_dev == NULL)
+ return 0;
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ (adreno_dev->long_ib_detect ? 1 : 0));
+}
+
+
+#define FT_DEVICE_ATTR(name) \
+ DEVICE_ATTR(name, 0644, _ ## name ## _show, _ ## name ## _store);
+
+FT_DEVICE_ATTR(ft_policy);
+FT_DEVICE_ATTR(ft_pagefault_policy);
+FT_DEVICE_ATTR(ft_fast_hang_detect);
+FT_DEVICE_ATTR(ft_long_ib_detect);
+
+
+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,
+ NULL,
+};
+
+int adreno_ft_init_sysfs(struct kgsl_device *device)
+{
+ return kgsl_create_device_sysfs_files(device->dev, ft_attr_list);
+}
+
+void adreno_ft_uninit_sysfs(struct kgsl_device *device)
+{
+ kgsl_remove_device_sysfs_files(device->dev, ft_attr_list);
+}
+
static int adreno_getproperty(struct kgsl_device *device,
enum kgsl_property_type type,
void *value,
@@ -2887,20 +3124,15 @@
{
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
- unsigned long wait;
+ unsigned long wait = jiffies;
unsigned long timeout = jiffies + msecs_to_jiffies(ADRENO_IDLE_TIMEOUT);
unsigned int rptr;
- /*
- * The first time into the loop, wait for 100 msecs and kick wptr again
- * to ensure that the hardware has updated correctly. After that, kick
- * it periodically every KGSL_TIMEOUT_PART msecs until the timeout
- * expires
- */
-
- wait = jiffies + msecs_to_jiffies(100);
-
do {
+ /*
+ * Wait is "jiffies" first time in the loop to start
+ * GPU stall detection immediately.
+ */
if (time_after(jiffies, wait)) {
/* Check to see if the core is hung */
if (adreno_ft_detect(device, regs))
@@ -2922,16 +3154,15 @@
/* Caller must hold the device mutex. */
int adreno_idle(struct kgsl_device *device)
{
- struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- unsigned int rbbm_status;
unsigned long wait_time;
unsigned long wait_time_part;
unsigned int prev_reg_val[FT_DETECT_REGS_COUNT];
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
memset(prev_reg_val, 0, sizeof(prev_reg_val));
kgsl_cffdump_regpoll(device,
- adreno_dev->gpudev->reg_rbbm_status << 2,
+ adreno_getreg(adreno_dev, ADRENO_REG_RBBM_STATUS) << 2,
0x00000000, 0x80000000);
retry:
@@ -2944,23 +3175,15 @@
wait_time_part = jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART);
while (time_before(jiffies, wait_time)) {
- adreno_regread(device, adreno_dev->gpudev->reg_rbbm_status,
- &rbbm_status);
- if (adreno_is_a2xx(adreno_dev)) {
- if (rbbm_status == 0x110)
- return 0;
- } else {
- if (!(rbbm_status & 0x80000000))
- return 0;
- }
+ if (adreno_isidle(device))
+ return 0;
- /* Dont wait for timeout, detect hang faster.
- */
+ /* Dont wait for timeout, detect hang faster. */
if (time_after(jiffies, wait_time_part)) {
- wait_time_part = jiffies +
- msecs_to_jiffies(KGSL_TIMEOUT_PART);
- if ((adreno_ft_detect(device, prev_reg_val)))
- goto err;
+ wait_time_part = jiffies +
+ msecs_to_jiffies(KGSL_TIMEOUT_PART);
+ if ((adreno_ft_detect(device, prev_reg_val)))
+ goto err;
}
}
@@ -2990,9 +3213,8 @@
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
/* Is the core idle? */
- adreno_regread(device,
- adreno_dev->gpudev->reg_rbbm_status,
- ®_rbbm_status);
+ adreno_readreg(adreno_dev, ADRENO_REG_RBBM_STATUS,
+ ®_rbbm_status);
if (adreno_is_a2xx(adreno_dev)) {
if (reg_rbbm_status == 0x110)
@@ -3010,9 +3232,8 @@
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
- WARN_ON(device->state == KGSL_STATE_INIT);
/* If the device isn't active, don't force it on. */
- if (device->state == KGSL_STATE_ACTIVE) {
+ if (kgsl_pwrctrl_isenabled(device)) {
/* Is the ring buffer is empty? */
unsigned int rptr = adreno_get_rptr(rb);
if (rptr == rb->wptr) {
@@ -3040,6 +3261,9 @@
int status = 0;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ /* process any profiling results that are available */
+ adreno_profile_process_results(device);
+
/* switch to NULL ctxt */
if (adreno_dev->drawctxt_active != NULL) {
adreno_drawctxt_switch(adreno_dev, NULL, 0);
@@ -3055,32 +3279,33 @@
phys_addr_t pt_base, unsigned int gpuaddr, unsigned int size)
{
struct kgsl_context *context;
- struct adreno_context *adreno_context = NULL;
int next = 0;
+ struct kgsl_memdesc *desc = NULL;
+ read_lock(&device->context_lock);
while (1) {
context = idr_get_next(&device->context_idr, &next);
if (context == NULL)
break;
- adreno_context = (struct adreno_context *)context->devctxt;
-
- if (kgsl_mmu_pt_equal(&device->mmu, adreno_context->pagetable,
+ if (kgsl_mmu_pt_equal(&device->mmu, context->pagetable,
pt_base)) {
- struct kgsl_memdesc *desc;
+ struct adreno_context *adreno_context;
+ adreno_context = ADRENO_CONTEXT(context);
desc = &adreno_context->gpustate;
if (kgsl_gpuaddr_in_memdesc(desc, gpuaddr, size))
- return desc;
+ break;
desc = &adreno_context->context_gmem_shadow.gmemshadow;
if (kgsl_gpuaddr_in_memdesc(desc, gpuaddr, size))
- return desc;
+ break;
}
next = next + 1;
+ desc = NULL;
}
-
- return NULL;
+ read_unlock(&device->context_lock);
+ return desc;
}
struct kgsl_memdesc *adreno_find_region(struct kgsl_device *device,
@@ -3123,6 +3348,7 @@
return memdesc ? kgsl_gpuaddr_to_vaddr(memdesc, gpuaddr) : NULL;
}
+
/**
* adreno_read - General read function to read adreno device memory
* @device - Pointer to the GPU device struct (for adreno device)
@@ -3155,7 +3381,7 @@
* @offsetwords - Word (4 Bytes) offset to the register to be read
* @value - Value read from device register
*/
-void adreno_regread(struct kgsl_device *device, unsigned int offsetwords,
+static void adreno_regread(struct kgsl_device *device, unsigned int offsetwords,
unsigned int *value)
{
adreno_read(device, device->reg_virt, offsetwords, value,
@@ -3175,7 +3401,8 @@
device->shader_mem_len);
}
-void adreno_regwrite(struct kgsl_device *device, unsigned int offsetwords,
+static void adreno_regwrite(struct kgsl_device *device,
+ unsigned int offsetwords,
unsigned int value)
{
unsigned int *reg;
@@ -3199,9 +3426,10 @@
static unsigned int _get_context_id(struct kgsl_context *k_ctxt)
{
unsigned int context_id = KGSL_MEMSTORE_GLOBAL;
+
if (k_ctxt != NULL) {
- struct adreno_context *a_ctxt = k_ctxt->devctxt;
- if (k_ctxt->id == KGSL_CONTEXT_INVALID || a_ctxt == NULL)
+ struct adreno_context *a_ctxt = ADRENO_CONTEXT(k_ctxt);
+ if (kgsl_context_detached(k_ctxt))
context_id = KGSL_CONTEXT_INVALID;
else if (a_ctxt->flags & CTXT_FLAGS_PER_CONTEXT_TS)
context_id = k_ctxt->id;
@@ -3272,7 +3500,8 @@
*/
if (context && device->state != KGSL_STATE_SLUMBER) {
- adreno_ringbuffer_issuecmds(device, context->devctxt,
+ adreno_ringbuffer_issuecmds(device,
+ ADRENO_CONTEXT(context),
KGSL_CMD_FLAGS_GET_INT, NULL, 0);
}
}
@@ -3332,6 +3561,7 @@
unsigned int curr_context_id = 0;
static struct adreno_context *curr_context;
static struct kgsl_context *context;
+ static char pid_name[TASK_COMM_LEN] = "unknown";
if (!adreno_dev->fast_hang_detect)
fast_hang_detected = 0;
@@ -3344,7 +3574,7 @@
if (is_adreno_rbbm_status_idle(device) &&
(kgsl_readtimestamp(device, NULL, KGSL_TIMESTAMP_RETIRED)
- == rb->timestamp[KGSL_MEMSTORE_GLOBAL])) {
+ == rb->global_ts)) {
/*
* On A2XX if the RPTR != WPTR and the device is idle, then
@@ -3354,9 +3584,11 @@
if (adreno_is_a2xx(adreno_dev)) {
unsigned int rptr;
- adreno_regread(device, REG_CP_RB_RPTR, &rptr);
+ adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_RPTR,
+ &rptr);
if (rptr != adreno_dev->ringbuffer.wptr)
- adreno_regwrite(device, REG_CP_RB_WPTR,
+ adreno_writereg(adreno_dev,
+ ADRENO_REG_CP_RB_WPTR,
adreno_dev->ringbuffer.wptr);
}
@@ -3379,7 +3611,7 @@
for (i = 0; i < FT_DETECT_REGS_COUNT; i++) {
if (ft_detect_regs[i] == 0)
continue;
- adreno_regread(device, ft_detect_regs[i],
+ kgsl_regread(device, ft_detect_regs[i],
&curr_reg_val[i]);
}
@@ -3393,19 +3625,28 @@
if (curr_global_ts == prev_global_ts) {
- /* Get the current context here */
- if (context == NULL) {
+ /* If we don't already have a good context, get it. */
+ if (kgsl_context_detached(context)) {
+ kgsl_context_put(context);
+ context = NULL;
+ curr_context = NULL;
+ strlcpy(pid_name, "unknown", sizeof(pid_name));
+
kgsl_sharedmem_readl(&device->memstore,
&curr_context_id,
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
current_context));
/* Make sure the memstore read has posted */
mb();
- context = idr_find(&device->context_idr,
- curr_context_id);
+
+ context = kgsl_context_get(device, curr_context_id);
if (context != NULL) {
- curr_context = context->devctxt;
+ struct task_struct *task;
+ curr_context = ADRENO_CONTEXT(context);
curr_context->ib_gpu_time_used = 0;
+ task = find_task_by_vpid(context->pid);
+ if (task)
+ get_task_comm(pid_name, task);
} else {
KGSL_DRV_ERR(device,
"Fault tolerance no context found\n");
@@ -3429,8 +3670,7 @@
KGSL_FT_ERR(device,
"Proc %s, ctxt_id %d ts %d triggered fault tolerance"
" on global ts %d\n",
- curr_context ? curr_context->pid_name : "",
- curr_context ? curr_context->id : 0,
+ pid_name, context ? context->id : 0,
(kgsl_readtimestamp(device, context,
KGSL_TIMESTAMP_RETIRED) + 1),
curr_global_ts + 1);
@@ -3442,7 +3682,7 @@
curr_context->ib_gpu_time_used += KGSL_TIMEOUT_PART;
KGSL_FT_INFO(device,
"Proc %s used GPU Time %d ms on timestamp 0x%X\n",
- curr_context->pid_name, curr_context->ib_gpu_time_used,
+ pid_name, curr_context->ib_gpu_time_used,
curr_global_ts+1);
if ((long_ib_detected) &&
@@ -3458,8 +3698,7 @@
"Proc %s, ctxt_id %d ts %d"
"used GPU for %d ms long ib "
"detected on global ts %d\n",
- curr_context->pid_name,
- curr_context->id,
+ pid_name, context->id,
(kgsl_readtimestamp(device,
context,
KGSL_TIMESTAMP_RETIRED)+1),
@@ -3478,8 +3717,10 @@
} else {
/* GPU is moving forward */
prev_global_ts = curr_global_ts;
+ kgsl_context_put(context);
context = NULL;
curr_context = NULL;
+ strlcpy(pid_name, "unknown", sizeof(pid_name));
adreno_dev->long_ib = 0;
adreno_dev->long_ib_ts = 0;
}
@@ -3502,7 +3743,7 @@
if (context_id == KGSL_CONTEXT_INVALID)
return -EINVAL;
- ts_issued = adreno_dev->ringbuffer.timestamp[context_id];
+ ts_issued = adreno_context_timestamp(context, &adreno_dev->ringbuffer);
if (timestamp_cmp(timestamp, ts_issued) <= 0)
return 0;
@@ -3537,7 +3778,8 @@
unsigned int msecs)
{
static unsigned int io_cnt;
- struct adreno_context *adreno_ctx = context ? context->devctxt : NULL;
+ struct adreno_context *adreno_ctx = context ? ADRENO_CONTEXT(context) :
+ NULL;
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
unsigned int context_id = _get_context_id(context);
unsigned int time_elapsed = 0;
@@ -3545,8 +3787,6 @@
int ts_compare = 1;
int io, ret = -ETIMEDOUT;
- /* Get out early if the context has already been destroyed */
-
if (context_id == KGSL_CONTEXT_INVALID) {
KGSL_DRV_WARN(device, "context was detached");
return -EINVAL;
@@ -3572,10 +3812,14 @@
* this gives enough time for the engine to start moving and oddly
* provides better hang detection results than just going the full
* KGSL_TIMEOUT_PART right off the bat. The exception to this rule
- * is if msecs happens to be < 100ms then just use the full timeout
+ * is if msecs happens to be < 100ms then just use 20ms or the msecs,
+ * whichever is larger because anything less than 20 is unreliable
*/
- wait = 100;
+ if (msecs == 0 || msecs >= 100)
+ wait = 100;
+ else
+ wait = (msecs > 20) ? msecs : 20;
do {
long status;
@@ -3684,9 +3928,9 @@
switch (type) {
case KGSL_TIMESTAMP_QUEUED: {
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
- timestamp = rb->timestamp[context_id];
+ timestamp = adreno_context_timestamp(context,
+ &adreno_dev->ringbuffer);
break;
}
case KGSL_TIMESTAMP_CONSUMED:
@@ -3718,7 +3962,8 @@
binbase = data;
- context = kgsl_find_context(dev_priv, binbase->drawctxt_id);
+ context = kgsl_context_get_owner(dev_priv,
+ binbase->drawctxt_id);
if (context) {
adreno_drawctxt_set_bin_base_offset(
device, context, binbase->offset);
@@ -3729,6 +3974,8 @@
"device_id=%d\n",
binbase->drawctxt_id, device->id);
}
+
+ kgsl_context_put(context);
break;
}
case IOCTL_KGSL_PERFCOUNTER_GET: {
@@ -3740,7 +3987,7 @@
case IOCTL_KGSL_PERFCOUNTER_PUT: {
struct kgsl_perfcounter_put *put = data;
result = adreno_perfcounter_put(adreno_dev, put->groupid,
- put->countable);
+ put->countable, PERFCOUNTER_FLAG_NONE);
break;
}
case IOCTL_KGSL_PERFCOUNTER_QUERY: {
@@ -3855,6 +4102,7 @@
/* Optional functions */
.setstate = adreno_setstate,
.drawctxt_create = adreno_drawctxt_create,
+ .drawctxt_detach = adreno_drawctxt_detach,
.drawctxt_destroy = adreno_drawctxt_destroy,
.setproperty = adreno_setproperty,
.postmortem_dump = adreno_dump,
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 70b07c4..72f15e7 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -16,6 +16,7 @@
#include "kgsl_device.h"
#include "adreno_drawctxt.h"
#include "adreno_ringbuffer.h"
+#include "adreno_profile.h"
#include "kgsl_iommu.h"
#include <mach/ocmem.h>
@@ -25,6 +26,9 @@
#define ADRENO_DEVICE(device) \
KGSL_CONTAINER_OF(device, struct adreno_device, dev)
+#define ADRENO_CONTEXT(device) \
+ KGSL_CONTAINER_OF(device, struct adreno_context, base)
+
#define ADRENO_CHIPID_CORE(_id) (((_id) >> 24) & 0xFF)
#define ADRENO_CHIPID_MAJOR(_id) (((_id) >> 16) & 0xFF)
#define ADRENO_CHIPID_MINOR(_id) (((_id) >> 8) & 0xFF)
@@ -35,6 +39,7 @@
#define KGSL_CMD_FLAGS_PMODE 0x00000001
#define KGSL_CMD_FLAGS_INTERNAL_ISSUE 0x00000002
#define KGSL_CMD_FLAGS_GET_INT 0x00000004
+#define KGSL_CMD_FLAGS_PROFILE 0x00000008
#define KGSL_CMD_FLAGS_EOF 0x00000100
/* Command identifiers */
@@ -45,6 +50,8 @@
#define KGSL_END_OF_IB_IDENTIFIER 0x2ABEDEAD
#define KGSL_END_OF_FRAME_IDENTIFIER 0x2E0F2E0F
#define KGSL_NOP_IB_IDENTIFIER 0x20F20F20
+#define KGSL_START_OF_PROFILE_IDENTIFIER 0x2DEFADE1
+#define KGSL_END_OF_PROFILE_IDENTIFIER 0x2DEFADE2
#ifdef CONFIG_MSM_SCM
#define ADRENO_DEFAULT_PWRSCALE_POLICY (&kgsl_pwrscale_policy_tz)
@@ -128,6 +135,7 @@
struct ocmem_buf *ocmem_hdl;
unsigned int ocmem_base;
unsigned int gpu_cycles;
+ struct adreno_profile profile;
};
#define PERFCOUNTER_FLAG_NONE 0x0
@@ -138,24 +146,27 @@
/**
* struct adreno_perfcount_register: register state
* @countable: countable the register holds
- * @refcount: number of users of the register
+ * @kernelcount: number of user space users of the register
+ * @usercount: number of kernel users of the register
* @offset: register hardware offset
*/
struct adreno_perfcount_register {
unsigned int countable;
- unsigned int refcount;
+ unsigned int kernelcount;
+ unsigned int usercount;
unsigned int offset;
- unsigned int flags;
};
/**
* struct adreno_perfcount_group: registers for a hardware group
* @regs: available registers for this group
* @reg_count: total registers for this group
+ * @name: group name for this group
*/
struct adreno_perfcount_group {
struct adreno_perfcount_register *regs;
unsigned int reg_count;
+ const char *name;
};
/**
@@ -168,14 +179,86 @@
unsigned int group_count;
};
+/**
+ * adreno_regs: List of registers that are used in kgsl driver for all
+ * 3D devices. Each device type has different offset value for the same
+ * register, so an array of register offsets are declared for every device
+ * and are indexed by the enumeration values defined in this enum
+ */
+enum adreno_regs {
+ ADRENO_REG_CP_DEBUG,
+ ADRENO_REG_CP_ME_RAM_WADDR,
+ ADRENO_REG_CP_ME_RAM_DATA,
+ ADRENO_REG_CP_PFP_UCODE_DATA,
+ ADRENO_REG_CP_PFP_UCODE_ADDR,
+ ADRENO_REG_CP_WFI_PEND_CTR,
+ ADRENO_REG_CP_RB_BASE,
+ ADRENO_REG_CP_RB_RPTR_ADDR,
+ ADRENO_REG_CP_RB_RPTR,
+ ADRENO_REG_CP_RB_WPTR,
+ ADRENO_REG_CP_PROTECT_CTRL,
+ ADRENO_REG_CP_ME_CNTL,
+ ADRENO_REG_CP_RB_CNTL,
+ ADRENO_REG_CP_IB1_BASE,
+ ADRENO_REG_CP_IB1_BUFSZ,
+ ADRENO_REG_CP_IB2_BASE,
+ ADRENO_REG_CP_IB2_BUFSZ,
+ ADRENO_REG_CP_TIMESTAMP,
+ ADRENO_REG_SCRATCH_ADDR,
+ ADRENO_REG_SCRATCH_UMSK,
+ ADRENO_REG_SCRATCH_REG2,
+ ADRENO_REG_RBBM_STATUS,
+ ADRENO_REG_RBBM_PERFCTR_CTL,
+ ADRENO_REG_RBBM_PERFCTR_LOAD_CMD0,
+ ADRENO_REG_RBBM_PERFCTR_LOAD_CMD1,
+ ADRENO_REG_RBBM_PERFCTR_LOAD_CMD2,
+ ADRENO_REG_RBBM_PERFCTR_PWR_1_LO,
+ ADRENO_REG_RBBM_INT_0_MASK,
+ ADRENO_REG_RBBM_INT_0_STATUS,
+ ADRENO_REG_RBBM_AHB_ERROR_STATUS,
+ ADRENO_REG_RBBM_PM_OVERRIDE2,
+ ADRENO_REG_VPC_VPC_DEBUG_RAM_SEL,
+ ADRENO_REG_VPC_VPC_DEBUG_RAM_READ,
+ ADRENO_REG_VSC_PIPE_DATA_ADDRESS_0,
+ ADRENO_REG_VSC_PIPE_DATA_LENGTH_7,
+ ADRENO_REG_VSC_SIZE_ADDRESS,
+ ADRENO_REG_VFD_CONTROL_0,
+ ADRENO_REG_VFD_FETCH_INSTR_0_0,
+ ADRENO_REG_VFD_FETCH_INSTR_1_F,
+ ADRENO_REG_VFD_INDEX_MAX,
+ ADRENO_REG_SP_VS_PVT_MEM_ADDR_REG,
+ ADRENO_REG_SP_FS_PVT_MEM_ADDR_REG,
+ ADRENO_REG_SP_VS_OBJ_START_REG,
+ ADRENO_REG_SP_FS_OBJ_START_REG,
+ ADRENO_REG_PA_SC_AA_CONFIG,
+ ADRENO_REG_SQ_GPR_MANAGEMENT,
+ ADRENO_REG_SQ_INST_STORE_MANAGMENT,
+ ADRENO_REG_TC_CNTL_STATUS,
+ ADRENO_REG_TP0_CHICKEN,
+ ADRENO_REG_REGISTER_MAX,
+};
+
+/**
+ * adreno_reg_offsets: Holds array of register offsets
+ * @offsets: Offset array of size defined by enum adreno_regs
+ * @offset_0: This is the index of the register in offset array whose value
+ * is 0. 0 is a valid register offset and during initialization of the
+ * offset array we need to know if an offset value is correctly defined to 0
+ */
+struct adreno_reg_offsets {
+ unsigned int *offsets;
+ enum adreno_regs offset_0;
+};
+
+#define ADRENO_REG_UNUSED 0xFFFFFFFF
+#define ADRENO_REG_DEFINE(_offset, _reg) [_offset] = _reg
+
struct adreno_gpudev {
/*
- * These registers are in a different location on A3XX, so define
- * them in the structure and use them as variables.
+ * These registers are in a different location on different devices,
+ * so define them in the structure and use them as variables.
*/
- unsigned int reg_rbbm_status;
- unsigned int reg_cp_pfp_ucode_data;
- unsigned int reg_cp_pfp_ucode_addr;
+ struct adreno_reg_offsets *reg_offsets;
/* keeps track of when we need to execute the draw workaround code */
int ctx_switches_since_last_draw;
@@ -205,6 +288,7 @@
void (*coresight_config_debug_reg) (struct kgsl_device *device,
int debug_reg, unsigned int val);
void (*soft_reset)(struct adreno_device *device);
+ void (*postmortem_dump)(struct adreno_device *adreno_dev);
};
/*
@@ -249,6 +333,11 @@
#define FT_DETECT_REGS_COUNT 12
+struct log_field {
+ bool show;
+ const char *display;
+};
+
/* Fault Tolerance policy flags */
#define KGSL_FT_OFF BIT(0)
#define KGSL_FT_REPLAY BIT(1)
@@ -259,10 +348,10 @@
#define KGSL_FT_DEFAULT_POLICY (KGSL_FT_REPLAY + KGSL_FT_SKIPIB)
/* Pagefault policy flags */
-#define KGSL_FT_PAGEFAULT_INT_ENABLE 0x00000001
-#define KGSL_FT_PAGEFAULT_GPUHALT_ENABLE 0x00000002
-#define KGSL_FT_PAGEFAULT_LOG_ONE_PER_PAGE 0x00000004
-#define KGSL_FT_PAGEFAULT_LOG_ONE_PER_INT 0x00000008
+#define KGSL_FT_PAGEFAULT_INT_ENABLE BIT(0)
+#define KGSL_FT_PAGEFAULT_GPUHALT_ENABLE BIT(1)
+#define KGSL_FT_PAGEFAULT_LOG_ONE_PER_PAGE BIT(2)
+#define KGSL_FT_PAGEFAULT_LOG_ONE_PER_INT BIT(3)
#define KGSL_FT_PAGEFAULT_DEFAULT_POLICY (KGSL_FT_PAGEFAULT_INT_ENABLE + \
KGSL_FT_PAGEFAULT_GPUHALT_ENABLE)
@@ -295,16 +384,15 @@
int adreno_coresight_init(struct platform_device *pdev);
int adreno_idle(struct kgsl_device *device);
-void adreno_regread(struct kgsl_device *device, unsigned int offsetwords,
- unsigned int *value);
-void adreno_regwrite(struct kgsl_device *device, unsigned int offsetwords,
- unsigned int value);
void adreno_shadermem_regread(struct kgsl_device *device,
unsigned int offsetwords,
unsigned int *value);
int adreno_dump(struct kgsl_device *device, int manual);
+void adreno_dump_fields(struct kgsl_device *device,
+ const char *start, const struct log_field *lines,
+ int num);
unsigned int adreno_a3xx_rbbm_clock_ctl_default(struct adreno_device
*adreno_dev);
@@ -330,12 +418,21 @@
unsigned int adreno_ft_detect(struct kgsl_device *device,
unsigned int *prev_reg_val);
+int adreno_ft_init_sysfs(struct kgsl_device *device);
+void adreno_ft_uninit_sysfs(struct kgsl_device *device);
+
+int adreno_perfcounter_get_groupid(struct adreno_device *adreno_dev,
+ const char *name);
+
+const char *adreno_perfcounter_get_name(struct adreno_device
+ *adreno_dev, unsigned int groupid);
+
int adreno_perfcounter_get(struct adreno_device *adreno_dev,
unsigned int groupid, unsigned int countable, unsigned int *offset,
unsigned int flags);
int adreno_perfcounter_put(struct adreno_device *adreno_dev,
- unsigned int groupid, unsigned int countable);
+ unsigned int groupid, unsigned int countable, unsigned int flags);
int adreno_soft_reset(struct kgsl_device *device);
@@ -424,6 +521,26 @@
}
/**
+ * adreno_context_timestamp() - Return the last queued timestamp for the context
+ * @k_ctxt: Pointer to the KGSL context to query
+ * @rb: Pointer to the ringbuffer structure for the GPU
+ *
+ * Return the last queued context for the given context. This is used to verify
+ * that incoming requests are not using an invalid (unsubmitted) timestamp
+ */
+static inline int adreno_context_timestamp(struct kgsl_context *k_ctxt,
+ struct adreno_ringbuffer *rb)
+{
+ if (k_ctxt) {
+ struct adreno_context *a_ctxt = ADRENO_CONTEXT(k_ctxt);
+
+ if (a_ctxt->flags & CTXT_FLAGS_PER_CONTEXT_TS)
+ return a_ctxt->timestamp;
+ }
+ return rb->global_ts;
+}
+
+/**
* adreno_encode_istore_size - encode istore size in CP format
* @adreno_dev - The 3D device.
*
@@ -555,4 +672,66 @@
return cmds - start;
}
+/*
+ * adreno_checkreg_off() - Checks the validity of a register enum
+ * @adreno_dev: Pointer to adreno device
+ * @offset_name: The register enum that is checked
+ */
+static inline bool adreno_checkreg_off(struct adreno_device *adreno_dev,
+ enum adreno_regs offset_name)
+{
+ if (offset_name >= ADRENO_REG_REGISTER_MAX ||
+ ADRENO_REG_UNUSED ==
+ adreno_dev->gpudev->reg_offsets->offsets[offset_name]) {
+ BUG_ON(1);
+ }
+ return true;
+}
+
+/*
+ * adreno_readreg() - Read a register by getting its offset from the
+ * offset array defined in gpudev node
+ * @adreno_dev: Pointer to the the adreno device
+ * @offset_name: The register enum that is to be read
+ * @val: Register value read is placed here
+ */
+static inline void adreno_readreg(struct adreno_device *adreno_dev,
+ enum adreno_regs offset_name, unsigned int *val)
+{
+ struct kgsl_device *device = &adreno_dev->dev;
+ if (adreno_checkreg_off(adreno_dev, offset_name))
+ kgsl_regread(device,
+ adreno_dev->gpudev->reg_offsets->offsets[offset_name],
+ val);
+}
+
+/*
+ * adreno_writereg() - Write a register by getting its offset from the
+ * offset array defined in gpudev node
+ * @adreno_dev: Pointer to the the adreno device
+ * @offset_name: The register enum that is to be written
+ * @val: Value to write
+ */
+static inline void adreno_writereg(struct adreno_device *adreno_dev,
+ enum adreno_regs offset_name, unsigned int val)
+{
+ struct kgsl_device *device = &adreno_dev->dev;
+ if (adreno_checkreg_off(adreno_dev, offset_name))
+ kgsl_regwrite(device,
+ adreno_dev->gpudev->reg_offsets->offsets[offset_name], val);
+}
+
+/*
+ * adreno_getreg() - Returns the offset value of a register from the
+ * register offset array in the gpudev node
+ * @adreno_dev: Pointer to the the adreno device
+ * @offset_name: The register enum whore offset is returned
+ */
+static inline unsigned int adreno_getreg(struct adreno_device *adreno_dev,
+ enum adreno_regs offset_name)
+{
+ if (!adreno_checkreg_off(adreno_dev, offset_name))
+ return ADRENO_REG_REGISTER_MAX;
+ return adreno_dev->gpudev->reg_offsets->offsets[offset_name];
+}
#endif /*__ADRENO_H */
diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c
index b0a1fe8..3d72c5c 100644
--- a/drivers/gpu/msm/adreno_a2xx.c
+++ b/drivers/gpu/msm/adreno_a2xx.c
@@ -1355,7 +1355,7 @@
tmp_ctx.gmem_base = adreno_dev->gmem_base;
result = kgsl_allocate(&drawctxt->context_gmem_shadow.gmemshadow,
- drawctxt->pagetable, drawctxt->context_gmem_shadow.size);
+ drawctxt->base.pagetable, drawctxt->context_gmem_shadow.size);
if (result)
return result;
@@ -1364,7 +1364,7 @@
drawctxt->flags |= CTXT_FLAGS_GMEM_SHADOW;
/* blank out gmem shadow. */
- kgsl_sharedmem_set(drawctxt->dev_priv->device,
+ kgsl_sharedmem_set(drawctxt->base.device,
&drawctxt->context_gmem_shadow.gmemshadow, 0, 0,
drawctxt->context_gmem_shadow.size);
@@ -1389,7 +1389,7 @@
kgsl_cache_range_op(&drawctxt->context_gmem_shadow.gmemshadow,
KGSL_CACHE_OP_FLUSH);
- kgsl_cffdump_syncmem(drawctxt->dev_priv,
+ kgsl_cffdump_syncmem(drawctxt->base.device,
&drawctxt->context_gmem_shadow.gmemshadow,
drawctxt->context_gmem_shadow.gmemshadow.gpuaddr,
drawctxt->context_gmem_shadow.gmemshadow.size, false);
@@ -1410,13 +1410,13 @@
*/
ret = kgsl_allocate(&drawctxt->gpustate,
- drawctxt->pagetable, _context_size(adreno_dev));
+ drawctxt->base.pagetable, _context_size(adreno_dev));
if (ret)
return ret;
- kgsl_sharedmem_set(drawctxt->dev_priv->device, &drawctxt->gpustate, 0,
- 0, _context_size(adreno_dev));
+ kgsl_sharedmem_set(drawctxt->base.device, &drawctxt->gpustate,
+ 0, 0, _context_size(adreno_dev));
tmp_ctx.cmd = tmp_ctx.start
= (unsigned int *)((char *)drawctxt->gpustate.hostptr + CMD_OFFSET);
@@ -1440,8 +1440,8 @@
kgsl_cache_range_op(&drawctxt->gpustate,
KGSL_CACHE_OP_FLUSH);
- kgsl_cffdump_syncmem(drawctxt->dev_priv, &drawctxt->gpustate,
- drawctxt->gpustate.gpuaddr,
+ kgsl_cffdump_syncmem(drawctxt->base.device,
+ &drawctxt->gpustate, drawctxt->gpustate.gpuaddr,
drawctxt->gpustate.size, false);
done:
@@ -1516,7 +1516,7 @@
"Current active context has caused gpu hang\n");
if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
- kgsl_cffdump_syncmem(context->dev_priv, &context->gpustate,
+ kgsl_cffdump_syncmem(context->base.device, &context->gpustate,
context->reg_save[1],
context->reg_save[2] << 2, true);
/* save registers and constants. */
@@ -1525,7 +1525,7 @@
context->reg_save, 3);
if (context->flags & CTXT_FLAGS_SHADER_SAVE) {
- kgsl_cffdump_syncmem(context->dev_priv,
+ kgsl_cffdump_syncmem(context->base.device,
&context->gpustate,
context->shader_save[1],
context->shader_save[2] << 2, true);
@@ -1534,7 +1534,7 @@
KGSL_CMD_FLAGS_PMODE,
context->shader_save, 3);
- kgsl_cffdump_syncmem(context->dev_priv,
+ kgsl_cffdump_syncmem(context->base.device,
&context->gpustate,
context->shader_fixup[1],
context->shader_fixup[2] << 2, true);
@@ -1552,7 +1552,7 @@
if ((context->flags & CTXT_FLAGS_GMEM_SAVE) &&
(context->flags & CTXT_FLAGS_GMEM_SHADOW)) {
- kgsl_cffdump_syncmem(context->dev_priv, &context->gpustate,
+ kgsl_cffdump_syncmem(context->base.device, &context->gpustate,
context->context_gmem_shadow.gmem_save[1],
context->context_gmem_shadow.gmem_save[2] << 2, true);
/* save gmem.
@@ -1562,7 +1562,7 @@
KGSL_CMD_FLAGS_PMODE,
context->context_gmem_shadow.gmem_save, 3);
- kgsl_cffdump_syncmem(context->dev_priv, &context->gpustate,
+ kgsl_cffdump_syncmem(context->base.device, &context->gpustate,
context->chicken_restore[1],
context->chicken_restore[2] << 2, true);
@@ -1586,9 +1586,18 @@
unsigned int cmds[5];
if (context == NULL) {
- /* No context - set the default apgetable and thats it */
+ /* No context - set the default pagetable and thats it */
+ unsigned int id;
+ /*
+ * If there isn't a current context, the kgsl_mmu_setstate
+ * will use the CPU path so we don't need to give
+ * it a valid context id.
+ */
+ id = (adreno_dev->drawctxt_active != NULL)
+ ? adreno_dev->drawctxt_active->base.id
+ : KGSL_CONTEXT_INVALID;
kgsl_mmu_setstate(&device->mmu, device->mmu.defaultpagetable,
- adreno_dev->drawctxt_active->id);
+ id);
return;
}
@@ -1597,16 +1606,17 @@
cmds[2] = cp_type3_packet(CP_MEM_WRITE, 2);
cmds[3] = device->memstore.gpuaddr +
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, current_context);
- cmds[4] = context->id;
+ cmds[4] = context->base.id;
adreno_ringbuffer_issuecmds(device, context, KGSL_CMD_FLAGS_NONE,
cmds, 5);
- kgsl_mmu_setstate(&device->mmu, context->pagetable, context->id);
+ kgsl_mmu_setstate(&device->mmu, context->base.pagetable,
+ context->base.id);
/* restore gmem.
* (note: changes shader. shader must not already be restored.)
*/
if (context->flags & CTXT_FLAGS_GMEM_RESTORE) {
- kgsl_cffdump_syncmem(context->dev_priv, &context->gpustate,
+ kgsl_cffdump_syncmem(context->base.device, &context->gpustate,
context->context_gmem_shadow.gmem_restore[1],
context->context_gmem_shadow.gmem_restore[2] << 2,
true);
@@ -1616,7 +1626,7 @@
context->context_gmem_shadow.gmem_restore, 3);
if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
- kgsl_cffdump_syncmem(context->dev_priv,
+ kgsl_cffdump_syncmem(context->base.device,
&context->gpustate,
context->chicken_restore[1],
context->chicken_restore[2] << 2, true);
@@ -1631,7 +1641,7 @@
}
if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
- kgsl_cffdump_syncmem(context->dev_priv, &context->gpustate,
+ kgsl_cffdump_syncmem(context->base.device, &context->gpustate,
context->reg_restore[1],
context->reg_restore[2] << 2, true);
@@ -1641,7 +1651,7 @@
/* restore shader instructions & partitioning. */
if (context->flags & CTXT_FLAGS_SHADER_RESTORE) {
- kgsl_cffdump_syncmem(context->dev_priv,
+ kgsl_cffdump_syncmem(context->base.device,
&context->gpustate,
context->shader_restore[1],
context->shader_restore[2] << 2, true);
@@ -1707,11 +1717,11 @@
struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
int i;
- adreno_regread(device, REG_MASTER_INT_SIGNAL, &master_status);
+ kgsl_regread(device, REG_MASTER_INT_SIGNAL, &master_status);
while (!status && (num_reads < VALID_STATUS_COUNT_MAX) &&
(master_status & MASTER_INT_SIGNAL__CP_INT_STAT)) {
- adreno_regread(device, REG_CP_INT_STATUS, &status);
- adreno_regread(device, REG_MASTER_INT_SIGNAL,
+ kgsl_regread(device, REG_CP_INT_STATUS, &status);
+ kgsl_regread(device, REG_MASTER_INT_SIGNAL,
&master_status);
num_reads++;
}
@@ -1752,7 +1762,7 @@
/* only ack bits we understand */
status &= CP_INT_MASK;
- adreno_regwrite(device, REG_CP_INT_ACK, status);
+ kgsl_regwrite(device, REG_CP_INT_ACK, status);
if (status & (CP_INT_CNTL__IB1_INT_MASK | CP_INT_CNTL__RB_INT_MASK)) {
queue_work(device->work_queue, &device->ts_expired_ws);
@@ -1767,10 +1777,10 @@
unsigned int addr = 0;
const char *source;
- adreno_regread(device, REG_RBBM_INT_STATUS, &status);
+ kgsl_regread(device, REG_RBBM_INT_STATUS, &status);
if (status & RBBM_INT_CNTL__RDERR_INT_MASK) {
- adreno_regread(device, REG_RBBM_READ_ERROR, &rderr);
+ kgsl_regread(device, REG_RBBM_READ_ERROR, &rderr);
source = (rderr & RBBM_READ_ERROR_REQUESTER)
? "host" : "cp";
/* convert to dword address */
@@ -1794,7 +1804,7 @@
}
status &= RBBM_INT_MASK;
- adreno_regwrite(device, REG_RBBM_INT_ACK, status);
+ kgsl_regwrite(device, REG_RBBM_INT_ACK, status);
}
irqreturn_t a2xx_irq_handler(struct adreno_device *adreno_dev)
@@ -1803,7 +1813,7 @@
irqreturn_t result = IRQ_NONE;
unsigned int status;
- adreno_regread(device, REG_MASTER_INT_SIGNAL, &status);
+ kgsl_regread(device, REG_MASTER_INT_SIGNAL, &status);
if (status & MASTER_INT_SIGNAL__MH_INT_STAT) {
kgsl_mh_intrcallback(device);
@@ -1828,14 +1838,14 @@
struct kgsl_device *device = &adreno_dev->dev;
if (state) {
- adreno_regwrite(device, REG_RBBM_INT_CNTL, RBBM_INT_MASK);
- adreno_regwrite(device, REG_CP_INT_CNTL, CP_INT_MASK);
- adreno_regwrite(device, MH_INTERRUPT_MASK,
+ kgsl_regwrite(device, REG_RBBM_INT_CNTL, RBBM_INT_MASK);
+ kgsl_regwrite(device, REG_CP_INT_CNTL, CP_INT_MASK);
+ kgsl_regwrite(device, MH_INTERRUPT_MASK,
kgsl_mmu_get_int_mask());
} else {
- adreno_regwrite(device, REG_RBBM_INT_CNTL, 0);
- adreno_regwrite(device, REG_CP_INT_CNTL, 0);
- adreno_regwrite(device, MH_INTERRUPT_MASK, 0);
+ kgsl_regwrite(device, REG_RBBM_INT_CNTL, 0);
+ kgsl_regwrite(device, REG_CP_INT_CNTL, 0);
+ kgsl_regwrite(device, MH_INTERRUPT_MASK, 0);
}
/* Force the writes to post before touching the IRQ line */
@@ -1847,7 +1857,7 @@
struct kgsl_device *device = &adreno_dev->dev;
unsigned int status;
- adreno_regread(device, REG_MASTER_INT_SIGNAL, &status);
+ kgsl_regread(device, REG_MASTER_INT_SIGNAL, &status);
return (status &
(MASTER_INT_SIGNAL__MH_INT_STAT |
@@ -1929,21 +1939,21 @@
unsigned int reg, val;
/* Freeze the counter */
- adreno_regwrite(device, REG_CP_PERFMON_CNTL,
+ kgsl_regwrite(device, REG_CP_PERFMON_CNTL,
REG_PERF_MODE_CNT | REG_PERF_STATE_FREEZE);
/* Get the value */
- adreno_regread(device, REG_RBBM_PERFCOUNTER1_LO, &val);
+ kgsl_regread(device, REG_RBBM_PERFCOUNTER1_LO, &val);
/* Reset the counter */
- adreno_regwrite(device, REG_CP_PERFMON_CNTL,
+ kgsl_regwrite(device, REG_CP_PERFMON_CNTL,
REG_PERF_MODE_CNT | REG_PERF_STATE_RESET);
/* Re-Enable the performance monitors */
- adreno_regread(device, REG_RBBM_PM_OVERRIDE2, ®);
- adreno_regwrite(device, REG_RBBM_PM_OVERRIDE2, (reg | 0x40));
- adreno_regwrite(device, REG_RBBM_PERFCOUNTER1_SELECT, 0x1);
- adreno_regwrite(device, REG_CP_PERFMON_CNTL,
+ kgsl_regread(device, REG_RBBM_PM_OVERRIDE2, ®);
+ kgsl_regwrite(device, REG_RBBM_PM_OVERRIDE2, (reg | 0x40));
+ kgsl_regwrite(device, REG_RBBM_PERFCOUNTER1_SELECT, 0x1);
+ kgsl_regwrite(device, REG_CP_PERFMON_CNTL,
REG_PERF_MODE_CNT | REG_PERF_STATE_ENABLE);
return val;
@@ -1969,7 +1979,7 @@
/* must be aligned to size */
rb_edram_info.f.edram_range = (adreno_dev->gmem_base >> 14);
- adreno_regwrite(device, REG_RB_EDRAM_INFO, rb_edram_info.val);
+ kgsl_regwrite(device, REG_RB_EDRAM_INFO, rb_edram_info.val);
}
static void a2xx_start(struct adreno_device *adreno_dev)
@@ -1981,8 +1991,8 @@
* before issuing a soft reset. The overrides will then be
* turned off (set to 0)
*/
- adreno_regwrite(device, REG_RBBM_PM_OVERRIDE1, 0xfffffffe);
- adreno_regwrite(device, REG_RBBM_PM_OVERRIDE2, 0xffffffff);
+ kgsl_regwrite(device, REG_RBBM_PM_OVERRIDE1, 0xfffffffe);
+ kgsl_regwrite(device, REG_RBBM_PM_OVERRIDE2, 0xffffffff);
/*
* Only reset CP block if all blocks have previously been
@@ -1990,11 +2000,11 @@
*/
if (!(device->flags & KGSL_FLAGS_SOFT_RESET) ||
!adreno_is_a22x(adreno_dev)) {
- adreno_regwrite(device, REG_RBBM_SOFT_RESET,
+ kgsl_regwrite(device, REG_RBBM_SOFT_RESET,
0xFFFFFFFF);
device->flags |= KGSL_FLAGS_SOFT_RESET;
} else {
- adreno_regwrite(device, REG_RBBM_SOFT_RESET,
+ kgsl_regwrite(device, REG_RBBM_SOFT_RESET,
0x00000001);
}
/*
@@ -2003,11 +2013,11 @@
*/
msleep(30);
- adreno_regwrite(device, REG_RBBM_SOFT_RESET, 0x00000000);
+ kgsl_regwrite(device, REG_RBBM_SOFT_RESET, 0x00000000);
if (adreno_is_a225(adreno_dev)) {
/* Enable large instruction store for A225 */
- adreno_regwrite(device, REG_SQ_FLOW_CONTROL,
+ kgsl_regwrite(device, REG_SQ_FLOW_CONTROL,
0x18000000);
}
@@ -2015,41 +2025,242 @@
/* For A20X based targets increase number of clocks
* that RBBM will wait before de-asserting Register
* Clock Active signal */
- adreno_regwrite(device, REG_RBBM_CNTL, 0x0000FFFF);
+ kgsl_regwrite(device, REG_RBBM_CNTL, 0x0000FFFF);
else
- adreno_regwrite(device, REG_RBBM_CNTL, 0x00004442);
+ kgsl_regwrite(device, REG_RBBM_CNTL, 0x00004442);
- adreno_regwrite(device, REG_SQ_VS_PROGRAM, 0x00000000);
- adreno_regwrite(device, REG_SQ_PS_PROGRAM, 0x00000000);
+ kgsl_regwrite(device, REG_SQ_VS_PROGRAM, 0x00000000);
+ kgsl_regwrite(device, REG_SQ_PS_PROGRAM, 0x00000000);
if (cpu_is_msm8960())
- adreno_regwrite(device, REG_RBBM_PM_OVERRIDE1, 0x200);
+ kgsl_regwrite(device, REG_RBBM_PM_OVERRIDE1, 0x200);
else
- adreno_regwrite(device, REG_RBBM_PM_OVERRIDE1, 0);
+ kgsl_regwrite(device, REG_RBBM_PM_OVERRIDE1, 0);
if (!adreno_is_a22x(adreno_dev))
- adreno_regwrite(device, REG_RBBM_PM_OVERRIDE2, 0);
+ kgsl_regwrite(device, REG_RBBM_PM_OVERRIDE2, 0);
else
- adreno_regwrite(device, REG_RBBM_PM_OVERRIDE2, 0x80);
+ kgsl_regwrite(device, REG_RBBM_PM_OVERRIDE2, 0x80);
- adreno_regwrite(device, REG_RBBM_DEBUG, 0x00080000);
+ kgsl_regwrite(device, REG_RBBM_DEBUG, 0x00080000);
/* Make sure interrupts are disabled */
- adreno_regwrite(device, REG_RBBM_INT_CNTL, 0);
- adreno_regwrite(device, REG_CP_INT_CNTL, 0);
- adreno_regwrite(device, REG_SQ_INT_CNTL, 0);
+ kgsl_regwrite(device, REG_RBBM_INT_CNTL, 0);
+ kgsl_regwrite(device, REG_CP_INT_CNTL, 0);
+ kgsl_regwrite(device, REG_SQ_INT_CNTL, 0);
a2xx_gmeminit(adreno_dev);
}
+static void a2xx_postmortem_dump(struct adreno_device *adreno_dev)
+{
+ unsigned int r1, r2, r3, rbbm_status;
+ unsigned int cp_stat, rb_count;
+ struct kgsl_device *device = &adreno_dev->dev;
+
+ kgsl_regread(device, REG_RBBM_STATUS, &rbbm_status);
+
+ kgsl_regread(device, REG_RBBM_PM_OVERRIDE1, &r2);
+ kgsl_regread(device, REG_RBBM_PM_OVERRIDE2, &r3);
+ KGSL_LOG_DUMP(device,
+ "RBBM: STATUS = %08X | PM_OVERRIDE1 = %08X | PM_OVERRIDE2 = %08X\n",
+ rbbm_status, r2, r3);
+
+ kgsl_regread(device, REG_RBBM_INT_CNTL, &r1);
+ kgsl_regread(device, REG_RBBM_INT_STATUS, &r2);
+ kgsl_regread(device, REG_RBBM_READ_ERROR, &r3);
+ KGSL_LOG_DUMP(device,
+ "INT_CNTL = %08X | INT_STATUS = %08X | READ_ERROR = %08X\n",
+ r1, r2, r3);
+
+ {
+ char cmdFifo[16];
+ struct log_field lines[] = {
+ {rbbm_status & 0x001F, cmdFifo},
+ {rbbm_status & BIT(5), "TC busy "},
+ {rbbm_status & BIT(8), "HIRQ pending"},
+ {rbbm_status & BIT(9), "CPRQ pending"},
+ {rbbm_status & BIT(10), "CFRQ pending"},
+ {rbbm_status & BIT(11), "PFRQ pending"},
+ {rbbm_status & BIT(12), "VGT 0DMA bsy"},
+ {rbbm_status & BIT(14), "RBBM WU busy"},
+ {rbbm_status & BIT(16), "CP NRT busy "},
+ {rbbm_status & BIT(18), "MH busy "},
+ {rbbm_status & BIT(19), "MH chncy bsy"},
+ {rbbm_status & BIT(21), "SX busy "},
+ {rbbm_status & BIT(22), "TPC busy "},
+ {rbbm_status & BIT(24), "SC CNTX busy"},
+ {rbbm_status & BIT(25), "PA busy "},
+ {rbbm_status & BIT(26), "VGT busy "},
+ {rbbm_status & BIT(27), "SQ cntx1 bsy"},
+ {rbbm_status & BIT(28), "SQ cntx0 bsy"},
+ {rbbm_status & BIT(30), "RB busy "},
+ {rbbm_status & BIT(31), "Grphs pp bsy"},
+ };
+ snprintf(cmdFifo, sizeof(cmdFifo), "CMD FIFO=%01X ",
+ rbbm_status & 0xf);
+ adreno_dump_fields(device, " STATUS=", lines,
+ ARRAY_SIZE(lines));
+ }
+
+ kgsl_regread(device, REG_CP_RB_BASE, &r1);
+ kgsl_regread(device, REG_CP_RB_CNTL, &r2);
+ rb_count = 2 << (r2 & (BIT(6)-1));
+ kgsl_regread(device, REG_CP_RB_RPTR_ADDR, &r3);
+ KGSL_LOG_DUMP(device,
+ " RPTR = %08X | WPTR = %08X | RPTR_WR = %08X"
+ "\n", r1, r2, r3);
+
+ kgsl_regread(device, REG_CP_IB1_BASE, &r1);
+ kgsl_regread(device, REG_CP_IB1_BUFSZ, &r2);
+ KGSL_LOG_DUMP(device, "CP_IB1: BASE = %08X | BUFSZ = %d\n", r1, r2);
+
+ kgsl_regread(device, REG_CP_IB2_BASE, &r1);
+ kgsl_regread(device, REG_CP_IB2_BUFSZ, &r2);
+ KGSL_LOG_DUMP(device, "CP_IB2: BASE = %08X | BUFSZ = %d\n", r1, r2);
+
+ kgsl_regread(device, REG_CP_INT_CNTL, &r1);
+ kgsl_regread(device, REG_CP_INT_STATUS, &r2);
+ KGSL_LOG_DUMP(device, "CP_INT: CNTL = %08X | STATUS = %08X\n", r1, r2);
+
+ kgsl_regread(device, REG_CP_ME_CNTL, &r1);
+ kgsl_regread(device, REG_CP_ME_STATUS, &r2);
+ kgsl_regread(device, REG_MASTER_INT_SIGNAL, &r3);
+ KGSL_LOG_DUMP(device,
+ "CP_ME: CNTL = %08X | STATUS = %08X | MSTR_INT_SGNL = "
+ "%08X\n", r1, r2, r3);
+
+ kgsl_regread(device, REG_CP_STAT, &cp_stat);
+ KGSL_LOG_DUMP(device, "CP_STAT = %08X\n", cp_stat);
+#ifndef CONFIG_MSM_KGSL_PSTMRTMDMP_CP_STAT_NO_DETAIL
+ {
+ struct log_field lns[] = {
+ {cp_stat & BIT(0), "WR_BSY 0"},
+ {cp_stat & BIT(1), "RD_RQ_BSY 1"},
+ {cp_stat & BIT(2), "RD_RTN_BSY 2"},
+ };
+ adreno_dump_fields(device, " MIU=", lns, ARRAY_SIZE(lns));
+ }
+ {
+ struct log_field lns[] = {
+ {cp_stat & BIT(5), "RING_BUSY 5"},
+ {cp_stat & BIT(6), "NDRCTS_BSY 6"},
+ {cp_stat & BIT(7), "NDRCT2_BSY 7"},
+ {cp_stat & BIT(9), "ST_BUSY 9"},
+ {cp_stat & BIT(10), "BUSY 10"},
+ };
+ adreno_dump_fields(device, " CSF=", lns, ARRAY_SIZE(lns));
+ }
+ {
+ struct log_field lns[] = {
+ {cp_stat & BIT(11), "RNG_Q_BSY 11"},
+ {cp_stat & BIT(12), "NDRCTS_Q_B12"},
+ {cp_stat & BIT(13), "NDRCT2_Q_B13"},
+ {cp_stat & BIT(16), "ST_QUEUE_B16"},
+ {cp_stat & BIT(17), "PFP_BUSY 17"},
+ };
+ adreno_dump_fields(device, " RING=", lns, ARRAY_SIZE(lns));
+ }
+ {
+ struct log_field lns[] = {
+ {cp_stat & BIT(3), "RBIU_BUSY 3"},
+ {cp_stat & BIT(4), "RCIU_BUSY 4"},
+ {cp_stat & BIT(18), "MQ_RG_BSY 18"},
+ {cp_stat & BIT(19), "MQ_NDRS_BS19"},
+ {cp_stat & BIT(20), "MQ_NDR2_BS20"},
+ {cp_stat & BIT(21), "MIU_WC_STL21"},
+ {cp_stat & BIT(22), "CP_NRT_BSY22"},
+ {cp_stat & BIT(23), "3D_BUSY 23"},
+ {cp_stat & BIT(26), "ME_BUSY 26"},
+ {cp_stat & BIT(29), "ME_WC_BSY 29"},
+ {cp_stat & BIT(30), "MIU_FF EM 30"},
+ {cp_stat & BIT(31), "CP_BUSY 31"},
+ };
+ adreno_dump_fields(device, " CP_STT=", lns, ARRAY_SIZE(lns));
+ }
+#endif
+
+ kgsl_regread(device, REG_SCRATCH_REG0, &r1);
+ KGSL_LOG_DUMP(device, "SCRATCH_REG0 = %08X\n", r1);
+
+ kgsl_regread(device, REG_COHER_SIZE_PM4, &r1);
+ kgsl_regread(device, REG_COHER_BASE_PM4, &r2);
+ kgsl_regread(device, REG_COHER_STATUS_PM4, &r3);
+ KGSL_LOG_DUMP(device,
+ "COHER: SIZE_PM4 = %08X | BASE_PM4 = %08X | STATUS_PM4"
+ " = %08X\n", r1, r2, r3);
+
+ kgsl_regread(device, MH_AXI_ERROR, &r1);
+ KGSL_LOG_DUMP(device, "MH: AXI_ERROR = %08X\n", r1);
+
+ kgsl_regread(device, MH_MMU_PAGE_FAULT, &r1);
+ kgsl_regread(device, MH_MMU_CONFIG, &r2);
+ kgsl_regread(device, MH_MMU_MPU_BASE, &r3);
+ KGSL_LOG_DUMP(device,
+ "MH_MMU: PAGE_FAULT = %08X | CONFIG = %08X | MPU_BASE ="
+ " %08X\n", r1, r2, r3);
+
+ kgsl_regread(device, MH_MMU_MPU_END, &r1);
+ kgsl_regread(device, MH_MMU_VA_RANGE, &r2);
+ r3 = kgsl_mmu_get_current_ptbase(&device->mmu);
+ KGSL_LOG_DUMP(device,
+ " MPU_END = %08X | VA_RANGE = %08X | PT_BASE ="
+ " %08X\n", r1, r2, r3);
+
+ KGSL_LOG_DUMP(device, "PAGETABLE SIZE: %08X ",
+ kgsl_mmu_get_ptsize(&device->mmu));
+
+ kgsl_regread(device, MH_MMU_TRAN_ERROR, &r1);
+ KGSL_LOG_DUMP(device, " TRAN_ERROR = %08X\n", r1);
+
+ kgsl_regread(device, MH_INTERRUPT_MASK, &r1);
+ kgsl_regread(device, MH_INTERRUPT_STATUS, &r2);
+ KGSL_LOG_DUMP(device,
+ "MH_INTERRUPT: MASK = %08X | STATUS = %08X\n", r1, r2);
+}
+
+/* Register offset defines for A2XX */
+static unsigned int a2xx_register_offsets[ADRENO_REG_REGISTER_MAX] = {
+ ADRENO_REG_DEFINE(ADRENO_REG_CP_DEBUG, REG_CP_DEBUG),
+ ADRENO_REG_DEFINE(ADRENO_REG_CP_ME_RAM_WADDR, REG_CP_ME_RAM_WADDR),
+ ADRENO_REG_DEFINE(ADRENO_REG_CP_ME_RAM_DATA, REG_CP_ME_RAM_DATA),
+ ADRENO_REG_DEFINE(ADRENO_REG_CP_PFP_UCODE_DATA, REG_CP_PFP_UCODE_DATA),
+ ADRENO_REG_DEFINE(ADRENO_REG_CP_PFP_UCODE_ADDR, REG_CP_PFP_UCODE_ADDR),
+ ADRENO_REG_DEFINE(ADRENO_REG_CP_RB_BASE, REG_CP_RB_BASE),
+ ADRENO_REG_DEFINE(ADRENO_REG_CP_RB_RPTR_ADDR, REG_CP_RB_RPTR_ADDR),
+ ADRENO_REG_DEFINE(ADRENO_REG_CP_RB_RPTR, REG_CP_RB_RPTR),
+ ADRENO_REG_DEFINE(ADRENO_REG_CP_RB_WPTR, REG_CP_RB_WPTR),
+ ADRENO_REG_DEFINE(ADRENO_REG_CP_ME_CNTL, REG_CP_ME_CNTL),
+ ADRENO_REG_DEFINE(ADRENO_REG_CP_RB_CNTL, REG_CP_RB_CNTL),
+ ADRENO_REG_DEFINE(ADRENO_REG_CP_IB1_BASE, REG_CP_IB1_BASE),
+ ADRENO_REG_DEFINE(ADRENO_REG_CP_IB1_BUFSZ, REG_CP_IB1_BUFSZ),
+ ADRENO_REG_DEFINE(ADRENO_REG_CP_IB2_BASE, REG_CP_IB2_BASE),
+ ADRENO_REG_DEFINE(ADRENO_REG_CP_IB2_BUFSZ, REG_CP_IB2_BUFSZ),
+ ADRENO_REG_DEFINE(ADRENO_REG_CP_TIMESTAMP, REG_CP_TIMESTAMP),
+ ADRENO_REG_DEFINE(ADRENO_REG_SCRATCH_ADDR, REG_SCRATCH_ADDR),
+ ADRENO_REG_DEFINE(ADRENO_REG_SCRATCH_UMSK, REG_SCRATCH_UMSK),
+ ADRENO_REG_DEFINE(ADRENO_REG_RBBM_STATUS, REG_RBBM_STATUS),
+ ADRENO_REG_DEFINE(ADRENO_REG_PA_SC_AA_CONFIG, REG_PA_SC_AA_CONFIG),
+ ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PM_OVERRIDE2, REG_RBBM_PM_OVERRIDE2),
+ ADRENO_REG_DEFINE(ADRENO_REG_SCRATCH_REG2, REG_SCRATCH_REG2),
+ ADRENO_REG_DEFINE(ADRENO_REG_SQ_GPR_MANAGEMENT, REG_SQ_GPR_MANAGEMENT),
+ ADRENO_REG_DEFINE(ADRENO_REG_SQ_INST_STORE_MANAGMENT,
+ REG_SQ_INST_STORE_MANAGMENT),
+ ADRENO_REG_DEFINE(ADRENO_REG_TC_CNTL_STATUS, REG_TC_CNTL_STATUS),
+ ADRENO_REG_DEFINE(ADRENO_REG_TP0_CHICKEN, REG_TP0_CHICKEN),
+};
+
+struct adreno_reg_offsets a2xx_reg_offsets = {
+ .offsets = a2xx_register_offsets,
+ .offset_0 = ADRENO_REG_REGISTER_MAX,
+};
+
/* Defined in adreno_a2xx_snapshot.c */
void *a2xx_snapshot(struct adreno_device *adreno_dev, void *snapshot,
int *remain, int hang);
struct adreno_gpudev adreno_a2xx_gpudev = {
- .reg_rbbm_status = REG_RBBM_STATUS,
- .reg_cp_pfp_ucode_addr = REG_CP_PFP_UCODE_ADDR,
- .reg_cp_pfp_ucode_data = REG_CP_PFP_UCODE_DATA,
+ .reg_offsets = &a2xx_reg_offsets,
.ctxt_create = a2xx_drawctxt_create,
.ctxt_save = a2xx_drawctxt_save,
@@ -2062,4 +2273,5 @@
.rb_init = a2xx_rb_init,
.busy_cycles = a2xx_busy_cycles,
.start = a2xx_start,
+ .postmortem_dump = a2xx_postmortem_dump,
};
diff --git a/drivers/gpu/msm/adreno_a2xx_snapshot.c b/drivers/gpu/msm/adreno_a2xx_snapshot.c
index 2c86f82..5134ed6 100644
--- a/drivers/gpu/msm/adreno_a2xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a2xx_snapshot.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,11 +38,11 @@
header->size = SXDEBUG_COUNT;
for (i = 0; i < SXDEBUG_COUNT; i++) {
- adreno_regwrite(device, REG_RBBM_DEBUG_CNTL, 0x1B00 | i);
- adreno_regread(device, REG_RBBM_DEBUG_OUT, &data[i]);
+ kgsl_regwrite(device, REG_RBBM_DEBUG_CNTL, 0x1B00 | i);
+ kgsl_regread(device, REG_RBBM_DEBUG_OUT, &data[i]);
}
- adreno_regwrite(device, REG_RBBM_DEBUG_CNTL, 0);
+ kgsl_regwrite(device, REG_RBBM_DEBUG_CNTL, 0);
return DEBUG_SECTION_SZ(SXDEBUG_COUNT);
}
@@ -65,11 +65,11 @@
header->size = CPDEBUG_COUNT;
for (i = 0; i < CPDEBUG_COUNT; i++) {
- adreno_regwrite(device, REG_RBBM_DEBUG_CNTL, 0x1628);
- adreno_regread(device, REG_RBBM_DEBUG_OUT, &data[i]);
+ kgsl_regwrite(device, REG_RBBM_DEBUG_CNTL, 0x1628);
+ kgsl_regread(device, REG_RBBM_DEBUG_OUT, &data[i]);
}
- adreno_regwrite(device, REG_RBBM_DEBUG_CNTL, 0);
+ kgsl_regwrite(device, REG_RBBM_DEBUG_CNTL, 0);
return DEBUG_SECTION_SZ(CPDEBUG_COUNT);
}
@@ -82,7 +82,8 @@
#define SQ_DEBUG_WRITE(_device, _reg, _data, _offset) \
do { _data[(_offset)++] = (_reg); \
- adreno_regread(_device, (_reg), &_data[(_offset)++]); } while (0)
+ kgsl_regread(_device, (_reg), &_data[(_offset)++]); \
+ } while (0)
#define SQ_DEBUG_BANK_SIZE 23
@@ -175,7 +176,7 @@
header->size = size;
for (i = 0; i < 16; i++) {
- adreno_regwrite(device, REG_SQ_DEBUG_TB_STATUS_SEL,
+ kgsl_regwrite(device, REG_SQ_DEBUG_TB_STATUS_SEL,
i | (6<<4) | (i<<7) | (1<<11) | (1<<12)
| (i<<16) | (6<<20) | (i<<23));
SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_VTX_TB_STATE_MEM,
@@ -215,11 +216,11 @@
header->size = MIUDEBUG_COUNT;
for (i = 0; i < MIUDEBUG_COUNT; i++) {
- adreno_regwrite(device, REG_RBBM_DEBUG_CNTL, 0x1600 | i);
- adreno_regread(device, REG_RBBM_DEBUG_OUT, &data[i]);
+ kgsl_regwrite(device, REG_RBBM_DEBUG_CNTL, 0x1600 | i);
+ kgsl_regread(device, REG_RBBM_DEBUG_OUT, &data[i]);
}
- adreno_regwrite(device, REG_RBBM_DEBUG_CNTL, 0);
+ kgsl_regwrite(device, REG_RBBM_DEBUG_CNTL, 0);
return DEBUG_SECTION_SZ(MIUDEBUG_COUNT);
}
@@ -297,8 +298,8 @@
* work
*/
- adreno_regread(device, REG_RBBM_PM_OVERRIDE2, &pmoverride);
- adreno_regwrite(device, REG_RBBM_PM_OVERRIDE2, 0xFF);
+ kgsl_regread(device, REG_RBBM_PM_OVERRIDE2, &pmoverride);
+ kgsl_regwrite(device, REG_RBBM_PM_OVERRIDE2, 0xFF);
/* SX debug registers */
snapshot = kgsl_snapshot_add_section(device,
@@ -376,7 +377,7 @@
/* Reset the clock gating */
- adreno_regwrite(device, REG_RBBM_PM_OVERRIDE2, pmoverride);
+ kgsl_regwrite(device, REG_RBBM_PM_OVERRIDE2, pmoverride);
return snapshot;
}
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index a757a22..d96965c 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2321,7 +2321,7 @@
tmp_ctx.gmem_base = adreno_dev->gmem_base;
result = kgsl_allocate(&drawctxt->context_gmem_shadow.gmemshadow,
- drawctxt->pagetable, drawctxt->context_gmem_shadow.size);
+ drawctxt->base.pagetable, drawctxt->context_gmem_shadow.size);
if (result)
return result;
@@ -2355,7 +2355,7 @@
*/
ret = kgsl_allocate(&drawctxt->gpustate,
- drawctxt->pagetable, CONTEXT_SIZE);
+ drawctxt->base.pagetable, CONTEXT_SIZE);
if (ret)
return ret;
@@ -2420,7 +2420,7 @@
* already be saved.)
*/
- kgsl_cffdump_syncmem(context->dev_priv,
+ kgsl_cffdump_syncmem(context->base.device,
&context->gpustate,
context->context_gmem_shadow.gmem_save[1],
context->context_gmem_shadow.gmem_save[2] << 2, true);
@@ -2441,8 +2441,17 @@
if (context == NULL) {
/* No context - set the default pagetable and thats it */
+ unsigned int id;
+ /*
+ * If there isn't a current context, the kgsl_mmu_setstate
+ * will use the CPU path so we don't need to give
+ * it a valid context id.
+ */
+ id = (adreno_dev->drawctxt_active != NULL)
+ ? adreno_dev->drawctxt_active->base.id
+ : KGSL_CONTEXT_INVALID;
kgsl_mmu_setstate(&device->mmu, device->mmu.defaultpagetable,
- adreno_dev->drawctxt_active->id);
+ id);
return;
}
@@ -2451,10 +2460,11 @@
cmds[2] = cp_type3_packet(CP_MEM_WRITE, 2);
cmds[3] = device->memstore.gpuaddr +
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, current_context);
- cmds[4] = context->id;
+ cmds[4] = context->base.id;
adreno_ringbuffer_issuecmds(device, context, KGSL_CMD_FLAGS_NONE,
cmds, 5);
- kgsl_mmu_setstate(&device->mmu, context->pagetable, context->id);
+ kgsl_mmu_setstate(&device->mmu, context->base.pagetable,
+ context->base.id);
/*
* Restore GMEM. (note: changes shader.
@@ -2462,7 +2472,7 @@
*/
if (context->flags & CTXT_FLAGS_GMEM_RESTORE) {
- kgsl_cffdump_syncmem(context->dev_priv,
+ kgsl_cffdump_syncmem(context->base.device,
&context->gpustate,
context->context_gmem_shadow.gmem_restore[1],
context->context_gmem_shadow.gmem_restore[2] << 2,
@@ -2545,7 +2555,7 @@
case A3XX_INT_RBBM_AHB_ERROR: {
unsigned int reg;
- adreno_regread(device, A3XX_RBBM_AHB_ERROR_STATUS, ®);
+ kgsl_regread(device, A3XX_RBBM_AHB_ERROR_STATUS, ®);
/*
* Return the word address of the erroring register so that it
@@ -2559,7 +2569,7 @@
(reg >> 24) & 0x3);
/* Clear the error */
- adreno_regwrite(device, A3XX_RBBM_AHB_CMD, (1 << 3));
+ kgsl_regwrite(device, A3XX_RBBM_AHB_CMD, (1 << 3));
return;
}
case A3XX_INT_RBBM_REG_TIMEOUT:
@@ -2738,21 +2748,21 @@
if (countable > 1)
return;
- adreno_regread(device, A3XX_RBBM_RBBM_CTL, &in);
+ kgsl_regread(device, A3XX_RBBM_RBBM_CTL, &in);
if (countable == 0)
out = in | RBBM_RBBM_CTL_RESET_PWR_CTR0;
else
out = in | RBBM_RBBM_CTL_RESET_PWR_CTR1;
- adreno_regwrite(device, A3XX_RBBM_RBBM_CTL, out);
+ kgsl_regwrite(device, A3XX_RBBM_RBBM_CTL, out);
if (countable == 0)
out = in | RBBM_RBBM_CTL_ENABLE_PWR_CTR0;
else
out = in | RBBM_RBBM_CTL_ENABLE_PWR_CTR1;
- adreno_regwrite(device, A3XX_RBBM_RBBM_CTL, out);
+ kgsl_regwrite(device, A3XX_RBBM_RBBM_CTL, out);
return;
}
@@ -2766,8 +2776,8 @@
if (counter > 1 || countable > 0x7f)
return;
- adreno_regread(device, A3XX_VBIF_PERF_CNT_EN, &in);
- adreno_regread(device, A3XX_VBIF_PERF_CNT_SEL, &sel);
+ kgsl_regread(device, A3XX_VBIF_PERF_CNT_EN, &in);
+ kgsl_regread(device, A3XX_VBIF_PERF_CNT_SEL, &sel);
if (counter == 0) {
bit = VBIF_PERF_CNT_0;
@@ -2780,12 +2790,12 @@
out = in | bit;
- adreno_regwrite(device, A3XX_VBIF_PERF_CNT_SEL, sel);
+ kgsl_regwrite(device, A3XX_VBIF_PERF_CNT_SEL, sel);
- adreno_regwrite(device, A3XX_VBIF_PERF_CNT_CLR, bit);
- adreno_regwrite(device, A3XX_VBIF_PERF_CNT_CLR, 0);
+ kgsl_regwrite(device, A3XX_VBIF_PERF_CNT_CLR, bit);
+ kgsl_regwrite(device, A3XX_VBIF_PERF_CNT_CLR, 0);
- adreno_regwrite(device, A3XX_VBIF_PERF_CNT_EN, out);
+ kgsl_regwrite(device, A3XX_VBIF_PERF_CNT_EN, out);
}
static void a3xx_perfcounter_enable_vbif_pwr(struct kgsl_device *device,
@@ -2796,7 +2806,7 @@
if (countable > 2)
return;
- adreno_regread(device, A3XX_VBIF_PERF_CNT_EN, &in);
+ kgsl_regread(device, A3XX_VBIF_PERF_CNT_EN, &in);
if (countable == 0)
bit = VBIF_PERF_PWR_CNT_0;
else if (countable == 1)
@@ -2806,10 +2816,10 @@
out = in | bit;
- adreno_regwrite(device, A3XX_VBIF_PERF_CNT_CLR, bit);
- adreno_regwrite(device, A3XX_VBIF_PERF_CNT_CLR, 0);
+ kgsl_regwrite(device, A3XX_VBIF_PERF_CNT_CLR, bit);
+ kgsl_regwrite(device, A3XX_VBIF_PERF_CNT_CLR, 0);
- adreno_regwrite(device, A3XX_VBIF_PERF_CNT_EN, out);
+ kgsl_regwrite(device, A3XX_VBIF_PERF_CNT_EN, out);
}
/*
@@ -2846,14 +2856,14 @@
reg = &(a3xx_perfcounter_reglist[group].regs[counter]);
/* Select the desired perfcounter */
- adreno_regwrite(device, reg->select, countable);
+ kgsl_regwrite(device, reg->select, countable);
if (reg->load_bit < 32) {
val = 1 << reg->load_bit;
- adreno_regwrite(device, A3XX_RBBM_PERFCTR_LOAD_CMD0, val);
+ kgsl_regwrite(device, A3XX_RBBM_PERFCTR_LOAD_CMD0, val);
} else {
val = 1 << (reg->load_bit - 32);
- adreno_regwrite(device, A3XX_RBBM_PERFCTR_LOAD_CMD1, val);
+ kgsl_regwrite(device, A3XX_RBBM_PERFCTR_LOAD_CMD1, val);
}
}
@@ -2875,17 +2885,17 @@
reg = &(a3xx_perfcounter_reglist[group].regs[counter]);
/* Freeze the counter */
- adreno_regread(device, A3XX_RBBM_PERFCTR_CTL, &val);
+ kgsl_regread(device, A3XX_RBBM_PERFCTR_CTL, &val);
val &= ~reg->load_bit;
- adreno_regwrite(device, A3XX_RBBM_PERFCTR_CTL, val);
+ kgsl_regwrite(device, A3XX_RBBM_PERFCTR_CTL, val);
/* Read the values */
- adreno_regread(device, offset, &lo);
- adreno_regread(device, offset + 1, &hi);
+ kgsl_regread(device, offset, &lo);
+ kgsl_regread(device, offset + 1, &hi);
/* Re-Enable the counter */
val |= reg->load_bit;
- adreno_regwrite(device, A3XX_RBBM_PERFCTR_CTL, val);
+ kgsl_regwrite(device, A3XX_RBBM_PERFCTR_CTL, val);
return (((uint64_t) hi) << 32) | lo;
}
@@ -2945,7 +2955,7 @@
unsigned int status, tmp;
int i;
- adreno_regread(&adreno_dev->dev, A3XX_RBBM_INT_0_STATUS, &status);
+ kgsl_regread(&adreno_dev->dev, A3XX_RBBM_INT_0_STATUS, &status);
for (tmp = status, i = 0; tmp && i < ARRAY_SIZE(a3xx_irq_funcs); i++) {
if (tmp & 1) {
@@ -2964,7 +2974,7 @@
trace_kgsl_a3xx_irq_status(device, status);
if (status)
- adreno_regwrite(&adreno_dev->dev, A3XX_RBBM_INT_CLEAR_CMD,
+ kgsl_regwrite(&adreno_dev->dev, A3XX_RBBM_INT_CLEAR_CMD,
status);
return ret;
}
@@ -2974,16 +2984,16 @@
struct kgsl_device *device = &adreno_dev->dev;
if (state)
- adreno_regwrite(device, A3XX_RBBM_INT_0_MASK, A3XX_INT_MASK);
+ kgsl_regwrite(device, A3XX_RBBM_INT_0_MASK, A3XX_INT_MASK);
else
- adreno_regwrite(device, A3XX_RBBM_INT_0_MASK, 0);
+ kgsl_regwrite(device, A3XX_RBBM_INT_0_MASK, 0);
}
static unsigned int a3xx_irq_pending(struct adreno_device *adreno_dev)
{
unsigned int status;
- adreno_regread(&adreno_dev->dev, A3XX_RBBM_INT_0_STATUS, &status);
+ kgsl_regread(&adreno_dev->dev, A3XX_RBBM_INT_0_STATUS, &status);
return (status & A3XX_INT_MASK) ? 1 : 0;
}
@@ -2995,7 +3005,7 @@
unsigned int ret = 0;
/* Read the value */
- adreno_regread(device, A3XX_RBBM_PERFCTR_PWR_1_LO, &val);
+ kgsl_regread(device, A3XX_RBBM_PERFCTR_PWR_1_LO, &val);
/* Return 0 for the first read */
if (adreno_dev->gpu_cycles != 0) {
@@ -3136,8 +3146,137 @@
{ adreno_is_a305b, a305b_vbif },
};
+/*
+ * Define the available perfcounter groups - these get used by
+ * adreno_perfcounter_get and adreno_perfcounter_put
+ */
+
+static struct adreno_perfcount_register a3xx_perfcounters_cp[] = {
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_CP_0_LO },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_rbbm[] = {
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_RBBM_0_LO },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_RBBM_1_LO },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_pc[] = {
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_PC_0_LO },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_PC_1_LO },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_PC_2_LO },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_PC_3_LO },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_vfd[] = {
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_VFD_0_LO },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_VFD_1_LO },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_hlsq[] = {
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_HLSQ_0_LO },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_HLSQ_1_LO },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_HLSQ_2_LO },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_HLSQ_3_LO },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_HLSQ_4_LO },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_HLSQ_5_LO },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_vpc[] = {
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_VPC_0_LO },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_VPC_1_LO },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_tse[] = {
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TSE_0_LO },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TSE_1_LO },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_ras[] = {
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_RAS_0_LO },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_RAS_1_LO },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_uche[] = {
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_UCHE_0_LO },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_UCHE_1_LO },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_UCHE_2_LO },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_UCHE_3_LO },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_UCHE_4_LO },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_UCHE_5_LO },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_tp[] = {
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TP_0_LO },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TP_1_LO },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TP_2_LO },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TP_3_LO },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TP_4_LO },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TP_5_LO },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_sp[] = {
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_0_LO },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_1_LO },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_2_LO },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_3_LO },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_4_LO },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_5_LO },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_6_LO },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_7_LO },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_rb[] = {
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_RB_0_LO },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_RB_1_LO },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_pwr[] = {
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_PWR_0_LO },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_PWR_1_LO },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_vbif[] = {
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_VBIF_PERF_CNT0_LO },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_VBIF_PERF_CNT1_LO },
+};
+static struct adreno_perfcount_register a3xx_perfcounters_vbif_pwr[] = {
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_VBIF_PERF_PWR_CNT0_LO },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_VBIF_PERF_PWR_CNT1_LO },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_VBIF_PERF_PWR_CNT2_LO },
+};
+
+#define A3XX_PERFCOUNTER_GROUP(name) { a3xx_perfcounters_##name, \
+ ARRAY_SIZE(a3xx_perfcounters_##name), __stringify(name) }
+
+static struct adreno_perfcount_group a3xx_perfcounter_groups[] = {
+ A3XX_PERFCOUNTER_GROUP(cp),
+ A3XX_PERFCOUNTER_GROUP(rbbm),
+ A3XX_PERFCOUNTER_GROUP(pc),
+ A3XX_PERFCOUNTER_GROUP(vfd),
+ A3XX_PERFCOUNTER_GROUP(hlsq),
+ A3XX_PERFCOUNTER_GROUP(vpc),
+ A3XX_PERFCOUNTER_GROUP(tse),
+ A3XX_PERFCOUNTER_GROUP(ras),
+ A3XX_PERFCOUNTER_GROUP(uche),
+ A3XX_PERFCOUNTER_GROUP(tp),
+ A3XX_PERFCOUNTER_GROUP(sp),
+ A3XX_PERFCOUNTER_GROUP(rb),
+ A3XX_PERFCOUNTER_GROUP(pwr),
+ A3XX_PERFCOUNTER_GROUP(vbif),
+ A3XX_PERFCOUNTER_GROUP(vbif_pwr),
+};
+
+static struct adreno_perfcounters a3xx_perfcounters = {
+ a3xx_perfcounter_groups,
+ ARRAY_SIZE(a3xx_perfcounter_groups),
+};
+
static void a3xx_perfcounter_init(struct adreno_device *adreno_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.
@@ -3168,6 +3307,42 @@
/* Reserve and start countable 1 in the PWR perfcounter group */
adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_PWR, 1,
NULL, PERFCOUNTER_FLAG_KERNEL);
+
+ /* Default performance counter profiling to false */
+ adreno_dev->profile.enabled = false;
+}
+
+/**
+ * a3xx_protect_init() - Initializes register protection on a3xx
+ * @device: Pointer to the device structure
+ * Performs register writes to enable protected access to sensitive
+ * registers
+ */
+static void a3xx_protect_init(struct kgsl_device *device)
+{
+ /* enable access protection to privileged registers */
+ kgsl_regwrite(device, A3XX_CP_PROTECT_CTRL, 0x00000007);
+
+ /* RBBM registers */
+ kgsl_regwrite(device, A3XX_CP_PROTECT_REG_0, 0x63000040);
+ kgsl_regwrite(device, A3XX_CP_PROTECT_REG_1, 0x62000080);
+ kgsl_regwrite(device, A3XX_CP_PROTECT_REG_2, 0x600000CC);
+ kgsl_regwrite(device, A3XX_CP_PROTECT_REG_3, 0x60000108);
+ kgsl_regwrite(device, A3XX_CP_PROTECT_REG_4, 0x64000140);
+ kgsl_regwrite(device, A3XX_CP_PROTECT_REG_5, 0x66000400);
+
+ /* CP registers */
+ kgsl_regwrite(device, A3XX_CP_PROTECT_REG_6, 0x65000700);
+ kgsl_regwrite(device, A3XX_CP_PROTECT_REG_7, 0x610007D8);
+ kgsl_regwrite(device, A3XX_CP_PROTECT_REG_8, 0x620007E0);
+ kgsl_regwrite(device, A3XX_CP_PROTECT_REG_9, 0x61001178);
+ kgsl_regwrite(device, A3XX_CP_PROTECT_REG_A, 0x64001180);
+
+ /* RB registers */
+ kgsl_regwrite(device, A3XX_CP_PROTECT_REG_B, 0x60003300);
+
+ /* VBIF registers */
+ kgsl_regwrite(device, A3XX_CP_PROTECT_REG_C, 0x6B00C000);
}
static void a3xx_start(struct adreno_device *adreno_dev)
@@ -3186,57 +3361,59 @@
BUG_ON(vbif == NULL);
while (vbif->reg != 0) {
- adreno_regwrite(device, vbif->reg, vbif->val);
+ kgsl_regwrite(device, vbif->reg, vbif->val);
vbif++;
}
/* Make all blocks contribute to the GPU BUSY perf counter */
- adreno_regwrite(device, A3XX_RBBM_GPU_BUSY_MASKED, 0xFFFFFFFF);
+ kgsl_regwrite(device, A3XX_RBBM_GPU_BUSY_MASKED, 0xFFFFFFFF);
/* Tune the hystersis counters for SP and CP idle detection */
- adreno_regwrite(device, A3XX_RBBM_SP_HYST_CNT, 0x10);
- adreno_regwrite(device, A3XX_RBBM_WAIT_IDLE_CLOCKS_CTL, 0x10);
+ kgsl_regwrite(device, A3XX_RBBM_SP_HYST_CNT, 0x10);
+ kgsl_regwrite(device, A3XX_RBBM_WAIT_IDLE_CLOCKS_CTL, 0x10);
/* Enable the RBBM error reporting bits. This lets us get
useful information on failure */
- adreno_regwrite(device, A3XX_RBBM_AHB_CTL0, 0x00000001);
+ kgsl_regwrite(device, A3XX_RBBM_AHB_CTL0, 0x00000001);
/* Enable AHB error reporting */
- adreno_regwrite(device, A3XX_RBBM_AHB_CTL1, 0xA6FFFFFF);
+ kgsl_regwrite(device, A3XX_RBBM_AHB_CTL1, 0xA6FFFFFF);
/* Turn on the power counters */
- adreno_regwrite(device, A3XX_RBBM_RBBM_CTL, 0x00030000);
+ kgsl_regwrite(device, A3XX_RBBM_RBBM_CTL, 0x00030000);
/* Turn on hang detection - this spews a lot of useful information
* into the RBBM registers on a hang */
- adreno_regwrite(device, A3XX_RBBM_INTERFACE_HANG_INT_CTL,
+ kgsl_regwrite(device, A3XX_RBBM_INTERFACE_HANG_INT_CTL,
(1 << 16) | 0xFFF);
/* Enable 64-byte cacheline size. HW Default is 32-byte (0x000000E0). */
- adreno_regwrite(device, A3XX_UCHE_CACHE_MODE_CONTROL_REG, 0x00000001);
+ kgsl_regwrite(device, A3XX_UCHE_CACHE_MODE_CONTROL_REG, 0x00000001);
/* Enable Clock gating */
- adreno_regwrite(device, A3XX_RBBM_CLOCK_CTL,
+ kgsl_regwrite(device, A3XX_RBBM_CLOCK_CTL,
adreno_a3xx_rbbm_clock_ctl_default(adreno_dev));
if (adreno_is_a330v2(adreno_dev))
- adreno_regwrite(device, A3XX_RBBM_GPR0_CTL,
+ kgsl_regwrite(device, A3XX_RBBM_GPR0_CTL,
A330v2_RBBM_GPR0_CTL_DEFAULT);
else if (adreno_is_a330(adreno_dev))
- adreno_regwrite(device, A3XX_RBBM_GPR0_CTL,
+ kgsl_regwrite(device, A3XX_RBBM_GPR0_CTL,
A330_RBBM_GPR0_CTL_DEFAULT);
/* Set the OCMEM base address for A330 */
if (adreno_is_a330(adreno_dev) ||
adreno_is_a305b(adreno_dev)) {
- adreno_regwrite(device, A3XX_RB_GMEM_BASE_ADDR,
+ kgsl_regwrite(device, A3XX_RB_GMEM_BASE_ADDR,
(unsigned int)(adreno_dev->ocmem_base >> 14));
}
+ /* Turn on protection */
+ a3xx_protect_init(device);
/* Turn on performance counters */
- adreno_regwrite(device, A3XX_RBBM_PERFCTR_CTL, 0x01);
+ kgsl_regwrite(device, A3XX_RBBM_PERFCTR_CTL, 0x01);
/* Turn on the GPU busy counter and let it run free */
@@ -3252,22 +3429,22 @@
{
mutex_lock(&device->mutex);
if (!kgsl_active_count_get(device)) {
- adreno_regwrite(device, A3XX_RBBM_DEBUG_BUS_CTL, 0x0001093F);
- adreno_regwrite(device, A3XX_RBBM_DEBUG_BUS_STB_CTL0,
+ kgsl_regwrite(device, A3XX_RBBM_DEBUG_BUS_CTL, 0x0001093F);
+ kgsl_regwrite(device, A3XX_RBBM_DEBUG_BUS_STB_CTL0,
0x00000000);
- adreno_regwrite(device, A3XX_RBBM_DEBUG_BUS_STB_CTL1,
+ kgsl_regwrite(device, A3XX_RBBM_DEBUG_BUS_STB_CTL1,
0xFFFFFFFE);
- adreno_regwrite(device, A3XX_RBBM_INT_TRACE_BUS_CTL,
+ kgsl_regwrite(device, A3XX_RBBM_INT_TRACE_BUS_CTL,
0x00201111);
- adreno_regwrite(device, A3XX_RBBM_EXT_TRACE_BUS_CTL,
+ kgsl_regwrite(device, A3XX_RBBM_EXT_TRACE_BUS_CTL,
0x89100010);
- adreno_regwrite(device, A3XX_RBBM_EXT_TRACE_STOP_CNT,
+ kgsl_regwrite(device, A3XX_RBBM_EXT_TRACE_STOP_CNT,
0x00017fff);
- adreno_regwrite(device, A3XX_RBBM_EXT_TRACE_START_CNT,
+ kgsl_regwrite(device, A3XX_RBBM_EXT_TRACE_START_CNT,
0x0001000f);
- adreno_regwrite(device, A3XX_RBBM_EXT_TRACE_PERIOD_CNT ,
+ kgsl_regwrite(device, A3XX_RBBM_EXT_TRACE_PERIOD_CNT ,
0x0001ffff);
- adreno_regwrite(device, A3XX_RBBM_EXT_TRACE_CMD,
+ kgsl_regwrite(device, A3XX_RBBM_EXT_TRACE_CMD,
0x00000001);
kgsl_active_count_put(device);
}
@@ -3284,15 +3461,15 @@
{
mutex_lock(&device->mutex);
if (!kgsl_active_count_get(device)) {
- adreno_regwrite(device, A3XX_RBBM_DEBUG_BUS_CTL, 0x0);
- adreno_regwrite(device, A3XX_RBBM_DEBUG_BUS_STB_CTL0, 0x0);
- adreno_regwrite(device, A3XX_RBBM_DEBUG_BUS_STB_CTL1, 0x0);
- adreno_regwrite(device, A3XX_RBBM_INT_TRACE_BUS_CTL, 0x0);
- adreno_regwrite(device, A3XX_RBBM_EXT_TRACE_BUS_CTL, 0x0);
- adreno_regwrite(device, A3XX_RBBM_EXT_TRACE_STOP_CNT, 0x0);
- adreno_regwrite(device, A3XX_RBBM_EXT_TRACE_START_CNT, 0x0);
- adreno_regwrite(device, A3XX_RBBM_EXT_TRACE_PERIOD_CNT , 0x0);
- adreno_regwrite(device, A3XX_RBBM_EXT_TRACE_CMD, 0x0);
+ kgsl_regwrite(device, A3XX_RBBM_DEBUG_BUS_CTL, 0x0);
+ kgsl_regwrite(device, A3XX_RBBM_DEBUG_BUS_STB_CTL0, 0x0);
+ kgsl_regwrite(device, A3XX_RBBM_DEBUG_BUS_STB_CTL1, 0x0);
+ kgsl_regwrite(device, A3XX_RBBM_INT_TRACE_BUS_CTL, 0x0);
+ kgsl_regwrite(device, A3XX_RBBM_EXT_TRACE_BUS_CTL, 0x0);
+ kgsl_regwrite(device, A3XX_RBBM_EXT_TRACE_STOP_CNT, 0x0);
+ kgsl_regwrite(device, A3XX_RBBM_EXT_TRACE_START_CNT, 0x0);
+ kgsl_regwrite(device, A3XX_RBBM_EXT_TRACE_PERIOD_CNT , 0x0);
+ kgsl_regwrite(device, A3XX_RBBM_EXT_TRACE_CMD, 0x0);
kgsl_active_count_put(device);
}
mutex_unlock(&device->mutex);
@@ -3303,7 +3480,7 @@
{
mutex_lock(&device->mutex);
if (!kgsl_active_count_get(device)) {
- adreno_regwrite(device, wordoffset, val);
+ kgsl_regwrite(device, wordoffset, val);
kgsl_active_count_put(device);
}
mutex_unlock(&device->mutex);
@@ -3346,128 +3523,6 @@
}
/*
- * Define the available perfcounter groups - these get used by
- * adreno_perfcounter_get and adreno_perfcounter_put
- */
-
-static struct adreno_perfcount_register a3xx_perfcounters_cp[] = {
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_CP_0_LO, 0 },
-};
-
-static struct adreno_perfcount_register a3xx_perfcounters_rbbm[] = {
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_RBBM_0_LO, 0 },
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_RBBM_1_LO, 0 },
-};
-
-static struct adreno_perfcount_register a3xx_perfcounters_pc[] = {
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_PC_0_LO, 0 },
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_PC_1_LO, 0 },
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_PC_2_LO, 0 },
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_PC_3_LO, 0 },
-};
-
-static struct adreno_perfcount_register a3xx_perfcounters_vfd[] = {
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_VFD_0_LO, 0 },
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_VFD_1_LO, 0 },
-};
-
-static struct adreno_perfcount_register a3xx_perfcounters_hlsq[] = {
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_HLSQ_0_LO, 0 },
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_HLSQ_1_LO, 0 },
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_HLSQ_2_LO, 0 },
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_HLSQ_3_LO, 0 },
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_HLSQ_4_LO, 0 },
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_HLSQ_5_LO, 0 },
-};
-
-static struct adreno_perfcount_register a3xx_perfcounters_vpc[] = {
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_VPC_0_LO, 0 },
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_VPC_1_LO, 0 },
-};
-
-static struct adreno_perfcount_register a3xx_perfcounters_tse[] = {
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TSE_0_LO, 0 },
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TSE_1_LO, 0 },
-};
-
-static struct adreno_perfcount_register a3xx_perfcounters_ras[] = {
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_RAS_0_LO, 0 },
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_RAS_1_LO, 0 },
-};
-
-static struct adreno_perfcount_register a3xx_perfcounters_uche[] = {
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_UCHE_0_LO, 0 },
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_UCHE_1_LO, 0 },
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_UCHE_2_LO, 0 },
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_UCHE_3_LO, 0 },
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_UCHE_4_LO, 0 },
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_UCHE_5_LO, 0 },
-};
-
-static struct adreno_perfcount_register a3xx_perfcounters_tp[] = {
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TP_0_LO, 0 },
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TP_1_LO, 0 },
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TP_2_LO, 0 },
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TP_3_LO, 0 },
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TP_4_LO, 0 },
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TP_5_LO, 0 },
-};
-
-static struct adreno_perfcount_register a3xx_perfcounters_sp[] = {
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_0_LO, 0 },
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_1_LO, 0 },
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_2_LO, 0 },
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_3_LO, 0 },
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_4_LO, 0 },
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_5_LO, 0 },
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_6_LO, 0 },
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_7_LO, 0 },
-};
-
-static struct adreno_perfcount_register a3xx_perfcounters_rb[] = {
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_RB_0_LO, 0 },
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_RB_1_LO, 0 },
-};
-
-static struct adreno_perfcount_register a3xx_perfcounters_pwr[] = {
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_PWR_0_LO, 0 },
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_PWR_1_LO, 0 },
-};
-
-static struct adreno_perfcount_register a3xx_perfcounters_vbif[] = {
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_VBIF_PERF_CNT0_LO },
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_VBIF_PERF_CNT1_LO },
-};
-static struct adreno_perfcount_register a3xx_perfcounters_vbif_pwr[] = {
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_VBIF_PERF_PWR_CNT0_LO },
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_VBIF_PERF_PWR_CNT1_LO },
- { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_VBIF_PERF_PWR_CNT2_LO },
-};
-
-static struct adreno_perfcount_group a3xx_perfcounter_groups[] = {
- { a3xx_perfcounters_cp, ARRAY_SIZE(a3xx_perfcounters_cp) },
- { a3xx_perfcounters_rbbm, ARRAY_SIZE(a3xx_perfcounters_rbbm) },
- { a3xx_perfcounters_pc, ARRAY_SIZE(a3xx_perfcounters_pc) },
- { a3xx_perfcounters_vfd, ARRAY_SIZE(a3xx_perfcounters_vfd) },
- { a3xx_perfcounters_hlsq, ARRAY_SIZE(a3xx_perfcounters_hlsq) },
- { a3xx_perfcounters_vpc, ARRAY_SIZE(a3xx_perfcounters_vpc) },
- { a3xx_perfcounters_tse, ARRAY_SIZE(a3xx_perfcounters_tse) },
- { a3xx_perfcounters_ras, ARRAY_SIZE(a3xx_perfcounters_ras) },
- { a3xx_perfcounters_uche, ARRAY_SIZE(a3xx_perfcounters_uche) },
- { a3xx_perfcounters_tp, ARRAY_SIZE(a3xx_perfcounters_tp) },
- { a3xx_perfcounters_sp, ARRAY_SIZE(a3xx_perfcounters_sp) },
- { a3xx_perfcounters_rb, ARRAY_SIZE(a3xx_perfcounters_rb) },
- { a3xx_perfcounters_pwr, ARRAY_SIZE(a3xx_perfcounters_pwr) },
- { a3xx_perfcounters_vbif, ARRAY_SIZE(a3xx_perfcounters_vbif) },
- { a3xx_perfcounters_vbif_pwr, ARRAY_SIZE(a3xx_perfcounters_vbif_pwr) },
-};
-
-static struct adreno_perfcounters a3xx_perfcounters = {
- a3xx_perfcounter_groups,
- ARRAY_SIZE(a3xx_perfcounter_groups),
-};
-
-/*
* a3xx_soft_reset() - Soft reset GPU
* @adreno_dev: Pointer to adreno device
*
@@ -3482,23 +3537,246 @@
struct kgsl_device *device = &adreno_dev->dev;
unsigned int reg;
- adreno_regwrite(device, A3XX_RBBM_SW_RESET_CMD, 1);
+ kgsl_regwrite(device, A3XX_RBBM_SW_RESET_CMD, 1);
/*
* Do a dummy read to get a brief read cycle delay for the reset to take
* effect
*/
- adreno_regread(device, A3XX_RBBM_SW_RESET_CMD, ®);
- adreno_regwrite(device, A3XX_RBBM_SW_RESET_CMD, 0);
+ kgsl_regread(device, A3XX_RBBM_SW_RESET_CMD, ®);
+ kgsl_regwrite(device, A3XX_RBBM_SW_RESET_CMD, 0);
}
/* Defined in adreno_a3xx_snapshot.c */
void *a3xx_snapshot(struct adreno_device *adreno_dev, void *snapshot,
int *remain, int hang);
+static void a3xx_postmortem_dump(struct adreno_device *adreno_dev)
+{
+ struct kgsl_device *device = &adreno_dev->dev;
+ unsigned int r1, r2, r3, rbbm_status;
+ unsigned int cp_stat, rb_count;
+
+ kgsl_regread(device, REG_RBBM_STATUS, &rbbm_status);
+ KGSL_LOG_DUMP(device, "RBBM: STATUS = %08X\n", rbbm_status);
+
+ {
+ struct log_field lines[] = {
+ {rbbm_status & BIT(0), "HI busy "},
+ {rbbm_status & BIT(1), "CP ME busy "},
+ {rbbm_status & BIT(2), "CP PFP busy "},
+ {rbbm_status & BIT(14), "CP NRT busy "},
+ {rbbm_status & BIT(15), "VBIF busy "},
+ {rbbm_status & BIT(16), "TSE busy "},
+ {rbbm_status & BIT(17), "RAS busy "},
+ {rbbm_status & BIT(18), "RB busy "},
+ {rbbm_status & BIT(19), "PC DCALL bsy"},
+ {rbbm_status & BIT(20), "PC VSD busy "},
+ {rbbm_status & BIT(21), "VFD busy "},
+ {rbbm_status & BIT(22), "VPC busy "},
+ {rbbm_status & BIT(23), "UCHE busy "},
+ {rbbm_status & BIT(24), "SP busy "},
+ {rbbm_status & BIT(25), "TPL1 busy "},
+ {rbbm_status & BIT(26), "MARB busy "},
+ {rbbm_status & BIT(27), "VSC busy "},
+ {rbbm_status & BIT(28), "ARB busy "},
+ {rbbm_status & BIT(29), "HLSQ busy "},
+ {rbbm_status & BIT(30), "GPU bsy noHC"},
+ {rbbm_status & BIT(31), "GPU busy "},
+ };
+ adreno_dump_fields(device, " STATUS=", lines,
+ ARRAY_SIZE(lines));
+ }
+
+ kgsl_regread(device, REG_CP_RB_BASE, &r1);
+ kgsl_regread(device, REG_CP_RB_CNTL, &r2);
+ rb_count = 2 << (r2 & (BIT(6) - 1));
+ kgsl_regread(device, REG_CP_RB_RPTR_ADDR, &r3);
+ KGSL_LOG_DUMP(device,
+ "CP_RB: BASE = %08X | CNTL = %08X | RPTR_ADDR = %08X"
+ "| rb_count = %08X\n", r1, r2, r3, rb_count);
+
+ kgsl_regread(device, REG_CP_RB_RPTR, &r1);
+ kgsl_regread(device, REG_CP_RB_WPTR, &r2);
+ kgsl_regread(device, REG_CP_RB_RPTR_WR, &r3);
+ KGSL_LOG_DUMP(device,
+ "CP_RB: BASE = %08X | CNTL = %08X | RPTR_ADDR = %08X"
+ "| rb_count = %08X\n", r1, r2, r3, rb_count);
+
+ kgsl_regread(device, REG_CP_RB_RPTR, &r1);
+ kgsl_regread(device, REG_CP_RB_WPTR, &r2);
+ kgsl_regread(device, REG_CP_RB_RPTR_WR, &r3);
+ KGSL_LOG_DUMP(device,
+ " RPTR = %08X | WPTR = %08X | RPTR_WR = %08X"
+ "\n", r1, r2, r3);
+
+ kgsl_regread(device, REG_CP_IB1_BASE, &r1);
+ kgsl_regread(device, REG_CP_IB1_BUFSZ, &r2);
+ KGSL_LOG_DUMP(device, "CP_IB1: BASE = %08X | BUFSZ = %d\n", r1, r2);
+
+ kgsl_regread(device, REG_CP_ME_CNTL, &r1);
+ kgsl_regread(device, REG_CP_ME_STATUS, &r2);
+ KGSL_LOG_DUMP(device, "CP_ME: CNTL = %08X | STATUS = %08X\n", r1, r2);
+
+ kgsl_regread(device, REG_CP_STAT, &cp_stat);
+ KGSL_LOG_DUMP(device, "CP_STAT = %08X\n", cp_stat);
+#ifndef CONFIG_MSM_KGSL_PSTMRTMDMP_CP_STAT_NO_DETAIL
+ {
+ struct log_field lns[] = {
+ {cp_stat & BIT(0), "WR_BSY 0"},
+ {cp_stat & BIT(1), "RD_RQ_BSY 1"},
+ {cp_stat & BIT(2), "RD_RTN_BSY 2"},
+ };
+ adreno_dump_fields(device, " MIU=", lns, ARRAY_SIZE(lns));
+ }
+ {
+ struct log_field lns[] = {
+ {cp_stat & BIT(5), "RING_BUSY 5"},
+ {cp_stat & BIT(6), "NDRCTS_BSY 6"},
+ {cp_stat & BIT(7), "NDRCT2_BSY 7"},
+ {cp_stat & BIT(9), "ST_BUSY 9"},
+ {cp_stat & BIT(10), "BUSY 10"},
+ };
+ adreno_dump_fields(device, " CSF=", lns, ARRAY_SIZE(lns));
+ }
+ {
+ struct log_field lns[] = {
+ {cp_stat & BIT(11), "RNG_Q_BSY 11"},
+ {cp_stat & BIT(12), "NDRCTS_Q_B12"},
+ {cp_stat & BIT(13), "NDRCT2_Q_B13"},
+ {cp_stat & BIT(16), "ST_QUEUE_B16"},
+ {cp_stat & BIT(17), "PFP_BUSY 17"},
+ };
+ adreno_dump_fields(device, " RING=", lns, ARRAY_SIZE(lns));
+ }
+ {
+ struct log_field lns[] = {
+ {cp_stat & BIT(3), "RBIU_BUSY 3"},
+ {cp_stat & BIT(4), "RCIU_BUSY 4"},
+ {cp_stat & BIT(8), "EVENT_BUSY 8"},
+ {cp_stat & BIT(18), "MQ_RG_BSY 18"},
+ {cp_stat & BIT(19), "MQ_NDRS_BS19"},
+ {cp_stat & BIT(20), "MQ_NDR2_BS20"},
+ {cp_stat & BIT(21), "MIU_WC_STL21"},
+ {cp_stat & BIT(22), "CP_NRT_BSY22"},
+ {cp_stat & BIT(23), "3D_BUSY 23"},
+ {cp_stat & BIT(26), "ME_BUSY 26"},
+ {cp_stat & BIT(27), "RB_FFO_BSY27"},
+ {cp_stat & BIT(28), "CF_FFO_BSY28"},
+ {cp_stat & BIT(29), "PS_FFO_BSY29"},
+ {cp_stat & BIT(30), "VS_FFO_BSY30"},
+ {cp_stat & BIT(31), "CP_BUSY 31"},
+ };
+ adreno_dump_fields(device, " CP_STT=", lns, ARRAY_SIZE(lns));
+ }
+#endif
+
+ kgsl_regread(device, A3XX_RBBM_INT_0_STATUS, &r1);
+ KGSL_LOG_DUMP(device, "MSTR_INT_SGNL = %08X\n", r1);
+ {
+ struct log_field ints[] = {
+ {r1 & BIT(0), "RBBM_GPU_IDLE 0"},
+ {r1 & BIT(1), "RBBM_AHB_ERROR 1"},
+ {r1 & BIT(2), "RBBM_REG_TIMEOUT 2"},
+ {r1 & BIT(3), "RBBM_ME_MS_TIMEOUT 3"},
+ {r1 & BIT(4), "RBBM_PFP_MS_TIMEOUT 4"},
+ {r1 & BIT(5), "RBBM_ATB_BUS_OVERFLOW 5"},
+ {r1 & BIT(6), "VFD_ERROR 6"},
+ {r1 & BIT(7), "CP_SW_INT 7"},
+ {r1 & BIT(8), "CP_T0_PACKET_IN_IB 8"},
+ {r1 & BIT(9), "CP_OPCODE_ERROR 9"},
+ {r1 & BIT(10), "CP_RESERVED_BIT_ERROR 10"},
+ {r1 & BIT(11), "CP_HW_FAULT 11"},
+ {r1 & BIT(12), "CP_DMA 12"},
+ {r1 & BIT(13), "CP_IB2_INT 13"},
+ {r1 & BIT(14), "CP_IB1_INT 14"},
+ {r1 & BIT(15), "CP_RB_INT 15"},
+ {r1 & BIT(16), "CP_REG_PROTECT_FAULT 16"},
+ {r1 & BIT(17), "CP_RB_DONE_TS 17"},
+ {r1 & BIT(18), "CP_VS_DONE_TS 18"},
+ {r1 & BIT(19), "CP_PS_DONE_TS 19"},
+ {r1 & BIT(20), "CACHE_FLUSH_TS 20"},
+ {r1 & BIT(21), "CP_AHB_ERROR_HALT 21"},
+ {r1 & BIT(24), "MISC_HANG_DETECT 24"},
+ {r1 & BIT(25), "UCHE_OOB_ACCESS 25"},
+ };
+ adreno_dump_fields(device, "INT_SGNL=", ints, ARRAY_SIZE(ints));
+ }
+}
+
+/* Register offset defines for A3XX */
+static unsigned int a3xx_register_offsets[ADRENO_REG_REGISTER_MAX] = {
+ ADRENO_REG_DEFINE(ADRENO_REG_CP_DEBUG, REG_CP_DEBUG),
+ ADRENO_REG_DEFINE(ADRENO_REG_CP_ME_RAM_WADDR, REG_CP_ME_RAM_WADDR),
+ ADRENO_REG_DEFINE(ADRENO_REG_CP_ME_RAM_DATA, REG_CP_ME_RAM_DATA),
+ ADRENO_REG_DEFINE(ADRENO_REG_CP_PFP_UCODE_DATA, A3XX_CP_PFP_UCODE_DATA),
+ ADRENO_REG_DEFINE(ADRENO_REG_CP_PFP_UCODE_ADDR, A3XX_CP_PFP_UCODE_ADDR),
+ ADRENO_REG_DEFINE(ADRENO_REG_CP_WFI_PEND_CTR, A3XX_CP_WFI_PEND_CTR),
+ ADRENO_REG_DEFINE(ADRENO_REG_CP_RB_BASE, REG_CP_RB_BASE),
+ ADRENO_REG_DEFINE(ADRENO_REG_CP_RB_RPTR_ADDR, REG_CP_RB_RPTR_ADDR),
+ ADRENO_REG_DEFINE(ADRENO_REG_CP_RB_RPTR, REG_CP_RB_RPTR),
+ ADRENO_REG_DEFINE(ADRENO_REG_CP_RB_WPTR, REG_CP_RB_WPTR),
+ ADRENO_REG_DEFINE(ADRENO_REG_CP_PROTECT_CTRL, A3XX_CP_PROTECT_CTRL),
+ ADRENO_REG_DEFINE(ADRENO_REG_CP_ME_CNTL, REG_CP_ME_CNTL),
+ ADRENO_REG_DEFINE(ADRENO_REG_CP_RB_CNTL, REG_CP_RB_CNTL),
+ ADRENO_REG_DEFINE(ADRENO_REG_CP_IB1_BASE, REG_CP_IB1_BASE),
+ ADRENO_REG_DEFINE(ADRENO_REG_CP_IB1_BUFSZ, REG_CP_IB1_BUFSZ),
+ ADRENO_REG_DEFINE(ADRENO_REG_CP_IB2_BASE, REG_CP_IB2_BASE),
+ ADRENO_REG_DEFINE(ADRENO_REG_CP_IB2_BUFSZ, REG_CP_IB2_BUFSZ),
+ ADRENO_REG_DEFINE(ADRENO_REG_CP_TIMESTAMP, REG_CP_TIMESTAMP),
+ ADRENO_REG_DEFINE(ADRENO_REG_SCRATCH_ADDR, REG_SCRATCH_ADDR),
+ ADRENO_REG_DEFINE(ADRENO_REG_SCRATCH_UMSK, REG_SCRATCH_UMSK),
+ ADRENO_REG_DEFINE(ADRENO_REG_RBBM_STATUS, A3XX_RBBM_STATUS),
+ ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_CTL, A3XX_RBBM_PERFCTR_CTL),
+ ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_LOAD_CMD0,
+ A3XX_RBBM_PERFCTR_LOAD_CMD0),
+ ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_LOAD_CMD1,
+ A3XX_RBBM_PERFCTR_LOAD_CMD1),
+ ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_PWR_1_LO,
+ A3XX_RBBM_PERFCTR_PWR_1_LO),
+ ADRENO_REG_DEFINE(ADRENO_REG_RBBM_INT_0_MASK, A3XX_RBBM_INT_0_MASK),
+ ADRENO_REG_DEFINE(ADRENO_REG_RBBM_INT_0_STATUS, A3XX_RBBM_INT_0_STATUS),
+ ADRENO_REG_DEFINE(ADRENO_REG_RBBM_AHB_ERROR_STATUS,
+ A3XX_RBBM_AHB_ERROR_STATUS),
+ ADRENO_REG_DEFINE(ADRENO_REG_VPC_VPC_DEBUG_RAM_SEL,
+ A3XX_VPC_VPC_DEBUG_RAM_SEL),
+ ADRENO_REG_DEFINE(ADRENO_REG_VPC_VPC_DEBUG_RAM_READ,
+ A3XX_VPC_VPC_DEBUG_RAM_READ),
+ ADRENO_REG_DEFINE(ADRENO_REG_VSC_PIPE_DATA_ADDRESS_0,
+ A3XX_VSC_PIPE_DATA_ADDRESS_0),
+ ADRENO_REG_DEFINE(ADRENO_REG_VSC_PIPE_DATA_LENGTH_7,
+ A3XX_VSC_PIPE_DATA_LENGTH_7),
+ ADRENO_REG_DEFINE(ADRENO_REG_VSC_SIZE_ADDRESS, A3XX_VSC_SIZE_ADDRESS),
+ ADRENO_REG_DEFINE(ADRENO_REG_VFD_CONTROL_0, A3XX_VFD_CONTROL_0),
+ ADRENO_REG_DEFINE(ADRENO_REG_VFD_FETCH_INSTR_0_0,
+ A3XX_VFD_FETCH_INSTR_0_0),
+ ADRENO_REG_DEFINE(ADRENO_REG_VFD_FETCH_INSTR_1_F,
+ A3XX_VFD_FETCH_INSTR_1_F),
+ ADRENO_REG_DEFINE(ADRENO_REG_VFD_INDEX_MAX, A3XX_VFD_INDEX_MAX),
+ ADRENO_REG_DEFINE(ADRENO_REG_SP_VS_PVT_MEM_ADDR_REG,
+ A3XX_SP_VS_PVT_MEM_ADDR_REG),
+ ADRENO_REG_DEFINE(ADRENO_REG_SP_FS_PVT_MEM_ADDR_REG,
+ A3XX_SP_FS_PVT_MEM_ADDR_REG),
+ ADRENO_REG_DEFINE(ADRENO_REG_SP_VS_OBJ_START_REG,
+ A3XX_SP_VS_OBJ_START_REG),
+ ADRENO_REG_DEFINE(ADRENO_REG_SP_FS_OBJ_START_REG,
+ A3XX_SP_FS_OBJ_START_REG),
+ ADRENO_REG_DEFINE(ADRENO_REG_PA_SC_AA_CONFIG, REG_PA_SC_AA_CONFIG),
+ ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PM_OVERRIDE2, REG_RBBM_PM_OVERRIDE2),
+ ADRENO_REG_DEFINE(ADRENO_REG_SCRATCH_REG2, REG_SCRATCH_REG2),
+ ADRENO_REG_DEFINE(ADRENO_REG_SQ_GPR_MANAGEMENT, REG_SQ_GPR_MANAGEMENT),
+ ADRENO_REG_DEFINE(ADRENO_REG_SQ_INST_STORE_MANAGMENT,
+ REG_SQ_INST_STORE_MANAGMENT),
+ ADRENO_REG_DEFINE(ADRENO_REG_TC_CNTL_STATUS, REG_TC_CNTL_STATUS),
+ ADRENO_REG_DEFINE(ADRENO_REG_TP0_CHICKEN, REG_TP0_CHICKEN),
+};
+
+struct adreno_reg_offsets a3xx_reg_offsets = {
+ .offsets = a3xx_register_offsets,
+ .offset_0 = ADRENO_REG_REGISTER_MAX,
+};
+
struct adreno_gpudev adreno_a3xx_gpudev = {
- .reg_rbbm_status = A3XX_RBBM_STATUS,
- .reg_cp_pfp_ucode_addr = A3XX_CP_PFP_UCODE_ADDR,
- .reg_cp_pfp_ucode_data = A3XX_CP_PFP_UCODE_DATA,
+ .reg_offsets = &a3xx_reg_offsets,
.perfcounters = &a3xx_perfcounters,
.ctxt_create = a3xx_drawctxt_create,
@@ -3519,4 +3797,5 @@
.coresight_disable = a3xx_coresight_disable,
.coresight_config_debug_reg = a3xx_coresight_config_debug_reg,
.soft_reset = a3xx_soft_reset,
+ .postmortem_dump = a3xx_postmortem_dump,
};
diff --git a/drivers/gpu/msm/adreno_a3xx_snapshot.c b/drivers/gpu/msm/adreno_a3xx_snapshot.c
index 58e3126..56c4305 100644
--- a/drivers/gpu/msm/adreno_a3xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a3xx_snapshot.c
@@ -35,8 +35,8 @@
unsigned int block_id, unsigned int index, unsigned int *val)
{
unsigned int block = (block_id << 8) | 1 << 16;
- adreno_regwrite(device, A3XX_RBBM_DEBUG_BUS_CTL, block | index);
- adreno_regread(device, A3XX_RBBM_DEBUG_BUS_DATA_STATUS, val);
+ kgsl_regwrite(device, A3XX_RBBM_DEBUG_BUS_CTL, block | index);
+ kgsl_regread(device, A3XX_RBBM_DEBUG_BUS_DATA_STATUS, val);
}
/**
@@ -108,9 +108,9 @@
for (bank = 0; bank < VPC_MEMORY_BANKS; bank++) {
for (addr = 0; addr < VPC_MEMORY_SIZE; addr++) {
unsigned int val = bank | (addr << 4);
- adreno_regwrite(device,
+ kgsl_regwrite(device,
A3XX_VPC_VPC_DEBUG_RAM_SEL, val);
- adreno_regread(device,
+ kgsl_regread(device,
A3XX_VPC_VPC_DEBUG_RAM_READ, &data[i++]);
}
}
@@ -134,9 +134,9 @@
header->type = SNAPSHOT_DEBUG_CP_MEQ;
header->size = CP_MEQ_SIZE;
- adreno_regwrite(device, A3XX_CP_MEQ_ADDR, 0x0);
+ kgsl_regwrite(device, A3XX_CP_MEQ_ADDR, 0x0);
for (i = 0; i < CP_MEQ_SIZE; i++)
- adreno_regread(device, A3XX_CP_MEQ_DATA, &data[i]);
+ kgsl_regread(device, A3XX_CP_MEQ_DATA, &data[i]);
return DEBUG_SECTION_SZ(CP_MEQ_SIZE);
}
@@ -164,9 +164,9 @@
* maintain always changing hardcoded constants
*/
- adreno_regwrite(device, REG_CP_ME_RAM_RADDR, 0x0);
+ kgsl_regwrite(device, REG_CP_ME_RAM_RADDR, 0x0);
for (i = 0; i < size; i++)
- adreno_regread(device, REG_CP_ME_RAM_DATA, &data[i]);
+ kgsl_regread(device, REG_CP_ME_RAM_DATA, &data[i]);
return DEBUG_SECTION_SZ(size);
}
@@ -195,7 +195,7 @@
*/
kgsl_regwrite(device, A3XX_CP_PFP_UCODE_ADDR, 0x0);
for (i = 0; i < size; i++)
- adreno_regread(device, A3XX_CP_PFP_UCODE_DATA, &data[i]);
+ kgsl_regread(device, A3XX_CP_PFP_UCODE_DATA, &data[i]);
return DEBUG_SECTION_SZ(size);
}
@@ -226,9 +226,9 @@
header->type = SNAPSHOT_DEBUG_CP_ROQ;
header->size = size;
- adreno_regwrite(device, A3XX_CP_ROQ_ADDR, 0x0);
+ kgsl_regwrite(device, A3XX_CP_ROQ_ADDR, 0x0);
for (i = 0; i < size; i++)
- adreno_regread(device, A3XX_CP_ROQ_DATA, &data[i]);
+ kgsl_regread(device, A3XX_CP_ROQ_DATA, &data[i]);
return DEBUG_SECTION_SZ(size);
}
@@ -253,12 +253,12 @@
header->type = SNAPSHOT_DEBUG_CP_MERCIU;
header->size = size;
- adreno_regwrite(device, A3XX_CP_MERCIU_ADDR, 0x0);
+ kgsl_regwrite(device, A3XX_CP_MERCIU_ADDR, 0x0);
for (i = 0; i < A330_CP_MERCIU_QUEUE_SIZE; i++) {
- adreno_regread(device, A3XX_CP_MERCIU_DATA,
+ kgsl_regread(device, A3XX_CP_MERCIU_DATA,
&data[(i * 2)]);
- adreno_regread(device, A3XX_CP_MERCIU_DATA2,
+ kgsl_regread(device, A3XX_CP_MERCIU_DATA2,
&data[(i * 2) + 1]);
}
@@ -444,7 +444,7 @@
list.count = 0;
/* Disable Clock gating temporarily for the debug bus to work */
- adreno_regwrite(device, A3XX_RBBM_CLOCK_CTL, 0x00);
+ kgsl_regwrite(device, A3XX_RBBM_CLOCK_CTL, 0x00);
/* Store relevant registers in list to snapshot */
_snapshot_a3xx_regs(regs, &list);
@@ -516,7 +516,7 @@
snapshot = a3xx_snapshot_debugbus(device, snapshot, remain);
/* Enable Clock gating */
- adreno_regwrite(device, A3XX_RBBM_CLOCK_CTL,
+ kgsl_regwrite(device, A3XX_RBBM_CLOCK_CTL,
adreno_a3xx_rbbm_clock_ctl_default(adreno_dev));
return snapshot;
diff --git a/drivers/gpu/msm/adreno_coresight.c b/drivers/gpu/msm/adreno_coresight.c
index e18568d..1b827ff 100644
--- a/drivers/gpu/msm/adreno_coresight.c
+++ b/drivers/gpu/msm/adreno_coresight.c
@@ -109,7 +109,7 @@
mutex_lock(&device->mutex);
if (!kgsl_active_count_get(device)) {
- adreno_regread(device, offset, ®val);
+ kgsl_regread(device, offset, ®val);
kgsl_active_count_put(device);
}
mutex_unlock(&device->mutex);
diff --git a/drivers/gpu/msm/adreno_debugfs.c b/drivers/gpu/msm/adreno_debugfs.c
index 90bd017..fc98d86 100644
--- a/drivers/gpu/msm/adreno_debugfs.c
+++ b/drivers/gpu/msm/adreno_debugfs.c
@@ -56,41 +56,6 @@
&adreno_dev->wait_timeout);
debugfs_create_u32("ib_check", 0644, device->d_debugfs,
&adreno_dev->ib_check_level);
- /* By Default enable fast hang detection */
- adreno_dev->fast_hang_detect = 1;
- debugfs_create_u32("fast_hang_detect", 0644, device->d_debugfs,
- &adreno_dev->fast_hang_detect);
- /*
- * FT policy can be set to any of the options below.
- * KGSL_FT_OFF -> BIT(0) Set to turn off FT
- * KGSL_FT_REPLAY -> BIT(1) Set to enable replay
- * KGSL_FT_SKIPIB -> BIT(2) Set to skip IB
- * KGSL_FT_SKIPFRAME -> BIT(3) Set to skip frame
- * KGSL_FT_DISABLE -> BIT(4) Set to disable FT for faulting context
- * by default set FT policy to KGSL_FT_DEFAULT_POLICY
- */
- adreno_dev->ft_policy = KGSL_FT_DEFAULT_POLICY;
- debugfs_create_u32("ft_policy", 0644, device->d_debugfs,
- &adreno_dev->ft_policy);
- /* By default enable long IB detection */
- adreno_dev->long_ib_detect = 1;
- debugfs_create_u32("long_ib_detect", 0644, device->d_debugfs,
- &adreno_dev->long_ib_detect);
-
- /*
- * FT pagefault policy can be set to any of the options below.
- * KGSL_FT_PAGEFAULT_INT_ENABLE -> BIT(0) set to enable pagefault INT
- * KGSL_FT_PAGEFAULT_GPUHALT_ENABLE -> BIT(1) Set to enable GPU HALT on
- * pagefaults. This stalls the GPU on a pagefault on IOMMU v1 HW.
- * KGSL_FT_PAGEFAULT_LOG_ONE_PER_PAGE -> BIT(2) Set to log only one
- * pagefault per page.
- * KGSL_FT_PAGEFAULT_LOG_ONE_PER_INT -> BIT(3) Set to log only one
- * pagefault per INT.
- */
- adreno_dev->ft_pf_policy = KGSL_FT_PAGEFAULT_DEFAULT_POLICY;
- debugfs_create_u32("ft_pagefault_policy", 0644, device->d_debugfs,
- &adreno_dev->ft_pf_policy);
-
debugfs_create_file("active_cnt", 0444, device->d_debugfs, device,
&_active_count_fops);
}
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index b32cdae..0af4c12e 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -134,34 +134,32 @@
/**
* adreno_drawctxt_create - create a new adreno draw context
- * @device - KGSL device to create the context on
- * @pagetable - Pagetable for the context
- * @context- Generic KGSL context structure
- * @flags - flags for the context (passed from user space)
+ * @dev_priv: the owner of the context
+ * @flags: flags for the context (passed from user space)
*
- * Create a new draw context for the 3D core. Return 0 on success,
- * or error code on failure.
+ * Create and return a new draw context for the 3D core.
*/
-int adreno_drawctxt_create(struct kgsl_device *device,
- struct kgsl_pagetable *pagetable,
- struct kgsl_context *context, uint32_t *flags)
+struct kgsl_context *
+adreno_drawctxt_create(struct kgsl_device_private *dev_priv,
+ uint32_t *flags)
{
struct adreno_context *drawctxt;
+ struct kgsl_device *device = dev_priv->device;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
int ret;
drawctxt = kzalloc(sizeof(struct adreno_context), GFP_KERNEL);
-
if (drawctxt == NULL)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
- drawctxt->pid = task_pid_nr(current);
- strlcpy(drawctxt->pid_name, current->comm, TASK_COMM_LEN);
- drawctxt->pagetable = pagetable;
+ ret = kgsl_context_init(dev_priv, &drawctxt->base);
+ if (ret != 0) {
+ kfree(drawctxt);
+ return ERR_PTR(ret);
+ }
+
drawctxt->bin_base_offset = 0;
- drawctxt->id = context->id;
- rb->timestamp[context->id] = 0;
+ drawctxt->timestamp = 0;
*flags &= (KGSL_CONTEXT_PREAMBLE |
KGSL_CONTEXT_NO_GMEM_ALLOC |
@@ -192,50 +190,47 @@
drawctxt->type =
(*flags & KGSL_CONTEXT_TYPE_MASK) >> KGSL_CONTEXT_TYPE_SHIFT;
- drawctxt->dev_priv = context->dev_priv;
ret = adreno_dev->gpudev->ctxt_create(adreno_dev, drawctxt);
if (ret)
goto err;
kgsl_sharedmem_writel(device, &device->memstore,
- KGSL_MEMSTORE_OFFSET(drawctxt->id, ref_wait_ts),
+ KGSL_MEMSTORE_OFFSET(drawctxt->base.id, ref_wait_ts),
KGSL_INIT_REFTIMESTAMP);
kgsl_sharedmem_writel(device, &device->memstore,
- KGSL_MEMSTORE_OFFSET(drawctxt->id, ts_cmp_enable), 0);
+ KGSL_MEMSTORE_OFFSET(drawctxt->base.id, ts_cmp_enable),
+ 0);
kgsl_sharedmem_writel(device, &device->memstore,
- KGSL_MEMSTORE_OFFSET(drawctxt->id, soptimestamp), 0);
+ KGSL_MEMSTORE_OFFSET(drawctxt->base.id, soptimestamp),
+ 0);
kgsl_sharedmem_writel(device, &device->memstore,
- KGSL_MEMSTORE_OFFSET(drawctxt->id, eoptimestamp), 0);
+ KGSL_MEMSTORE_OFFSET(drawctxt->base.id, eoptimestamp),
+ 0);
- context->devctxt = drawctxt;
- return 0;
+ return &drawctxt->base;
err:
- kfree(drawctxt);
- return ret;
+ kgsl_context_put(&drawctxt->base);
+ return ERR_PTR(ret);
}
/**
- * adreno_drawctxt_destroy - destroy a draw context
- * @device - KGSL device that owns the context
- * @context- Generic KGSL context container for the context
+ * adreno_drawctxt_detach(): detach a context from the GPU
+ * @context: Generic KGSL context container for the context
*
- * Destroy an existing context. Return 0 on success or error
- * code on failure.
*/
-
-/* destroy a drawing context */
-
-void adreno_drawctxt_destroy(struct kgsl_device *device,
- struct kgsl_context *context)
+void adreno_drawctxt_detach(struct kgsl_context *context)
{
- struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct kgsl_device *device;
+ struct adreno_device *adreno_dev;
struct adreno_context *drawctxt;
- if (context == NULL || context->devctxt == NULL)
+ if (context == NULL)
return;
- drawctxt = context->devctxt;
+ device = context->device;
+ adreno_dev = ADRENO_DEVICE(device);
+ drawctxt = ADRENO_CONTEXT(context);
/* deactivate context */
if (adreno_dev->drawctxt_active == drawctxt) {
/* no need to save GMEM or shader, the context is
@@ -254,11 +249,21 @@
if (device->state != KGSL_STATE_HUNG)
adreno_idle(device);
+ adreno_profile_process_results(device);
+
kgsl_sharedmem_free(&drawctxt->gpustate);
kgsl_sharedmem_free(&drawctxt->context_gmem_shadow.gmemshadow);
+}
+
+void adreno_drawctxt_destroy(struct kgsl_context *context)
+{
+ struct adreno_context *drawctxt;
+ if (context == NULL)
+ return;
+
+ drawctxt = ADRENO_CONTEXT(context);
kfree(drawctxt);
- context->devctxt = NULL;
}
/**
@@ -274,10 +279,12 @@
struct kgsl_context *context,
unsigned int offset)
{
- struct adreno_context *drawctxt = context->devctxt;
+ struct adreno_context *drawctxt;
- if (drawctxt)
- drawctxt->bin_base_offset = offset;
+ if (context == NULL)
+ return;
+ drawctxt = ADRENO_CONTEXT(context);
+ drawctxt->bin_base_offset = offset;
}
/**
@@ -316,12 +323,22 @@
KGSL_CTXT_INFO(device, "from %d to %d flags %d\n",
adreno_dev->drawctxt_active ?
- adreno_dev->drawctxt_active->id : 0,
- drawctxt ? drawctxt->id : 0, flags);
+ adreno_dev->drawctxt_active->base.id : 0,
+ drawctxt ? drawctxt->base.id : 0, flags);
/* Save the old context */
adreno_dev->gpudev->ctxt_save(adreno_dev, adreno_dev->drawctxt_active);
+ /* 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 = NULL;
+ }
+
+ /* Get a refcount to the new instance */
+ if (drawctxt)
+ _kgsl_context_get(&drawctxt->base);
+
/* Set the new context */
adreno_dev->gpudev->ctxt_restore(adreno_dev, drawctxt);
adreno_dev->drawctxt_active = drawctxt;
diff --git a/drivers/gpu/msm/adreno_drawctxt.h b/drivers/gpu/msm/adreno_drawctxt.h
index 2b8e600..3088099 100644
--- a/drivers/gpu/msm/adreno_drawctxt.h
+++ b/drivers/gpu/msm/adreno_drawctxt.h
@@ -13,8 +13,6 @@
#ifndef __ADRENO_DRAWCTXT_H
#define __ADRENO_DRAWCTXT_H
-#include <linux/sched.h>
-
#include "adreno_pm4types.h"
#include "a2xx_reg.h"
@@ -63,7 +61,13 @@
{ KGSL_CONTEXT_TYPE_GL, "GL" }, \
{ KGSL_CONTEXT_TYPE_CL, "CL" }, \
{ KGSL_CONTEXT_TYPE_C2D, "C2D" }, \
- { KGSL_CONTEXT_TYPE_RS, "RS" }
+ { KGSL_CONTEXT_TYPE_RS, "RS" }, \
+ { KGSL_CONTEXT_TYPE_UNKNOWN, "UNKNOWN" }
+
+struct adreno_context_type {
+ unsigned int type;
+ const char *str;
+};
struct kgsl_device;
struct adreno_device;
@@ -96,15 +100,11 @@
};
struct adreno_context {
- pid_t pid;
- char pid_name[TASK_COMM_LEN];
- unsigned int id;
+ struct kgsl_context base;
unsigned int ib_gpu_time_used;
+ unsigned int timestamp;
uint32_t flags;
- uint32_t pagefault;
- unsigned long pagefault_ts;
unsigned int type;
- struct kgsl_pagetable *pagetable;
struct kgsl_memdesc gpustate;
unsigned int reg_restore[3];
unsigned int shader_save[3];
@@ -131,16 +131,15 @@
struct kgsl_memdesc constant_load_commands[3];
struct kgsl_memdesc cond_execs[4];
struct kgsl_memdesc hlsqcontrol_restore_commands[1];
- struct kgsl_device_private *dev_priv;
};
-int adreno_drawctxt_create(struct kgsl_device *device,
- struct kgsl_pagetable *pagetable,
- struct kgsl_context *context,
+
+struct kgsl_context *adreno_drawctxt_create(struct kgsl_device_private *,
uint32_t *flags);
-void adreno_drawctxt_destroy(struct kgsl_device *device,
- struct kgsl_context *context);
+void adreno_drawctxt_detach(struct kgsl_context *context);
+
+void adreno_drawctxt_destroy(struct kgsl_context *context);
void adreno_drawctxt_switch(struct adreno_device *adreno_dev,
struct adreno_context *drawctxt,
diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c
index c7b6b5b..32dbd51 100644
--- a/drivers/gpu/msm/adreno_postmortem.c
+++ b/drivers/gpu/msm/adreno_postmortem.c
@@ -30,19 +30,19 @@
#define NUM_DWORDS_OF_RINGBUFFER_HISTORY 100
struct pm_id_name {
- uint32_t id;
+ enum adreno_regs id;
char name[9];
};
static const struct pm_id_name pm0_types[] = {
- {REG_PA_SC_AA_CONFIG, "RPASCAAC"},
- {REG_RBBM_PM_OVERRIDE2, "RRBBPMO2"},
- {REG_SCRATCH_REG2, "RSCRTRG2"},
- {REG_SQ_GPR_MANAGEMENT, "RSQGPRMN"},
- {REG_SQ_INST_STORE_MANAGMENT, "RSQINSTS"},
- {REG_TC_CNTL_STATUS, "RTCCNTLS"},
- {REG_TP0_CHICKEN, "RTP0CHCK"},
- {REG_CP_TIMESTAMP, "CP_TM_ST"},
+ {ADRENO_REG_PA_SC_AA_CONFIG, "RPASCAAC"},
+ {ADRENO_REG_RBBM_PM_OVERRIDE2, "RRBBPMO2"},
+ {ADRENO_REG_SCRATCH_REG2, "RSCRTRG2"},
+ {ADRENO_REG_SQ_GPR_MANAGEMENT, "RSQGPRMN"},
+ {ADRENO_REG_SQ_INST_STORE_MANAGMENT, "RSQINSTS"},
+ {ADRENO_REG_TC_CNTL_STATUS, "RTCCNTLS"},
+ {ADRENO_REG_TP0_CHICKEN, "RTP0CHCK"},
+ {ADRENO_REG_CP_TIMESTAMP, "CP_TM_ST"},
};
static const struct pm_id_name pm3_types[] = {
@@ -79,6 +79,8 @@
{KGSL_CMD_INTERNAL_IDENTIFIER, "CMD__INT"},
{KGSL_START_OF_IB_IDENTIFIER, "IB_START"},
{KGSL_END_OF_IB_IDENTIFIER, "IB___END"},
+ {KGSL_START_OF_PROFILE_IDENTIFIER, "PRO_STRT"},
+ {KGSL_END_OF_PROFILE_IDENTIFIER, "PRO__END"},
};
static uint32_t adreno_is_pm4_len(uint32_t word)
@@ -89,8 +91,9 @@
return (word >> 16) & 0x3FFF;
}
-static bool adreno_is_pm4_type(uint32_t word)
+static bool adreno_is_pm4_type(struct kgsl_device *device, uint32_t word)
{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
int i;
if (word == INVALID_RB_CMD)
@@ -101,7 +104,8 @@
if ((word & (3<<30)) == CP_TYPE0_PKT) {
for (i = 0; i < ARRAY_SIZE(pm0_types); ++i) {
- if ((word & 0x7FFF) == pm0_types[i].id)
+ if ((word & 0x7FFF) == adreno_getreg(adreno_dev,
+ pm0_types[i].id))
return 1;
}
return 0;
@@ -258,8 +262,8 @@
}
}
-static void adreno_dump_rb_buffer(const void *buf, size_t len,
- char *linebuf, size_t linebuflen, int *argp)
+static void adreno_dump_rb_buffer(struct kgsl_device *device, const void *buf,
+ size_t len, char *linebuf, size_t linebuflen, int *argp)
{
const u32 *ptr4 = buf;
const int ngroups = len;
@@ -274,7 +278,7 @@
lx += scnprintf(linebuf + lx, linebuflen - lx, " ");
else
nxsp = 1;
- if (!*argp && adreno_is_pm4_type(ptr4[j])) {
+ if (!*argp && adreno_is_pm4_type(device, ptr4[j])) {
lx += scnprintf(linebuf + lx, linebuflen - lx,
"%s", adreno_pm4_name(ptr4[j]));
*argp = -(adreno_is_pm4_len(ptr4[j])+1);
@@ -326,18 +330,13 @@
hex_dump_to_buffer(ptr+i, linelen*4, rowsize*4, 4,
linebuf, sizeof(linebuf), 0);
else
- adreno_dump_rb_buffer(ptr+i, linelen, linebuf,
+ adreno_dump_rb_buffer(device, ptr+i, linelen, linebuf,
sizeof(linebuf), &args);
KGSL_LOG_DUMP(device,
"RB: %4.4X:%s\n", (start+i)%size, linebuf);
}
}
-struct log_field {
- bool show;
- const char *display;
-};
-
static int adreno_dump_fields_line(struct kgsl_device *device,
const char *start, char *str, int slen,
const struct log_field **lines,
@@ -372,7 +371,7 @@
return num;
}
-static void adreno_dump_fields(struct kgsl_device *device,
+void adreno_dump_fields(struct kgsl_device *device,
const char *start, const struct log_field *lines,
int num)
{
@@ -392,329 +391,7 @@
sstr = " ";
}
}
-
-static void adreno_dump_a3xx(struct kgsl_device *device)
-{
- unsigned int r1, r2, r3, rbbm_status;
- unsigned int cp_stat, rb_count;
- struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
-
- kgsl_regread(device, adreno_dev->gpudev->reg_rbbm_status, &rbbm_status);
- KGSL_LOG_DUMP(device, "RBBM: STATUS = %08X\n", rbbm_status);
-
- {
- struct log_field lines[] = {
- {rbbm_status & BIT(0), "HI busy "},
- {rbbm_status & BIT(1), "CP ME busy "},
- {rbbm_status & BIT(2), "CP PFP busy "},
- {rbbm_status & BIT(14), "CP NRT busy "},
- {rbbm_status & BIT(15), "VBIF busy "},
- {rbbm_status & BIT(16), "TSE busy "},
- {rbbm_status & BIT(17), "RAS busy "},
- {rbbm_status & BIT(18), "RB busy "},
- {rbbm_status & BIT(19), "PC DCALL bsy"},
- {rbbm_status & BIT(20), "PC VSD busy "},
- {rbbm_status & BIT(21), "VFD busy "},
- {rbbm_status & BIT(22), "VPC busy "},
- {rbbm_status & BIT(23), "UCHE busy "},
- {rbbm_status & BIT(24), "SP busy "},
- {rbbm_status & BIT(25), "TPL1 busy "},
- {rbbm_status & BIT(26), "MARB busy "},
- {rbbm_status & BIT(27), "VSC busy "},
- {rbbm_status & BIT(28), "ARB busy "},
- {rbbm_status & BIT(29), "HLSQ busy "},
- {rbbm_status & BIT(30), "GPU bsy noHC"},
- {rbbm_status & BIT(31), "GPU busy "},
- };
- adreno_dump_fields(device, " STATUS=", lines,
- ARRAY_SIZE(lines));
- }
-
- kgsl_regread(device, REG_CP_RB_BASE, &r1);
- kgsl_regread(device, REG_CP_RB_CNTL, &r2);
- rb_count = 2 << (r2 & (BIT(6) - 1));
- kgsl_regread(device, REG_CP_RB_RPTR_ADDR, &r3);
- KGSL_LOG_DUMP(device,
- "CP_RB: BASE = %08X | CNTL = %08X | RPTR_ADDR = %08X"
- "| rb_count = %08X\n", r1, r2, r3, rb_count);
-
- kgsl_regread(device, REG_CP_RB_RPTR, &r1);
- kgsl_regread(device, REG_CP_RB_WPTR, &r2);
- kgsl_regread(device, REG_CP_RB_RPTR_WR, &r3);
- KGSL_LOG_DUMP(device,
- " RPTR = %08X | WPTR = %08X | RPTR_WR = %08X"
- "\n", r1, r2, r3);
-
- kgsl_regread(device, REG_CP_IB1_BASE, &r1);
- kgsl_regread(device, REG_CP_IB1_BUFSZ, &r2);
- KGSL_LOG_DUMP(device, "CP_IB1: BASE = %08X | BUFSZ = %d\n", r1, r2);
-
- kgsl_regread(device, REG_CP_ME_CNTL, &r1);
- kgsl_regread(device, REG_CP_ME_STATUS, &r2);
- KGSL_LOG_DUMP(device, "CP_ME: CNTL = %08X | STATUS = %08X\n", r1, r2);
-
- kgsl_regread(device, REG_CP_STAT, &cp_stat);
- KGSL_LOG_DUMP(device, "CP_STAT = %08X\n", cp_stat);
-#ifndef CONFIG_MSM_KGSL_PSTMRTMDMP_CP_STAT_NO_DETAIL
- {
- struct log_field lns[] = {
- {cp_stat & BIT(0), "WR_BSY 0"},
- {cp_stat & BIT(1), "RD_RQ_BSY 1"},
- {cp_stat & BIT(2), "RD_RTN_BSY 2"},
- };
- adreno_dump_fields(device, " MIU=", lns, ARRAY_SIZE(lns));
- }
- {
- struct log_field lns[] = {
- {cp_stat & BIT(5), "RING_BUSY 5"},
- {cp_stat & BIT(6), "NDRCTS_BSY 6"},
- {cp_stat & BIT(7), "NDRCT2_BSY 7"},
- {cp_stat & BIT(9), "ST_BUSY 9"},
- {cp_stat & BIT(10), "BUSY 10"},
- };
- adreno_dump_fields(device, " CSF=", lns, ARRAY_SIZE(lns));
- }
- {
- struct log_field lns[] = {
- {cp_stat & BIT(11), "RNG_Q_BSY 11"},
- {cp_stat & BIT(12), "NDRCTS_Q_B12"},
- {cp_stat & BIT(13), "NDRCT2_Q_B13"},
- {cp_stat & BIT(16), "ST_QUEUE_B16"},
- {cp_stat & BIT(17), "PFP_BUSY 17"},
- };
- adreno_dump_fields(device, " RING=", lns, ARRAY_SIZE(lns));
- }
- {
- struct log_field lns[] = {
- {cp_stat & BIT(3), "RBIU_BUSY 3"},
- {cp_stat & BIT(4), "RCIU_BUSY 4"},
- {cp_stat & BIT(8), "EVENT_BUSY 8"},
- {cp_stat & BIT(18), "MQ_RG_BSY 18"},
- {cp_stat & BIT(19), "MQ_NDRS_BS19"},
- {cp_stat & BIT(20), "MQ_NDR2_BS20"},
- {cp_stat & BIT(21), "MIU_WC_STL21"},
- {cp_stat & BIT(22), "CP_NRT_BSY22"},
- {cp_stat & BIT(23), "3D_BUSY 23"},
- {cp_stat & BIT(26), "ME_BUSY 26"},
- {cp_stat & BIT(27), "RB_FFO_BSY27"},
- {cp_stat & BIT(28), "CF_FFO_BSY28"},
- {cp_stat & BIT(29), "PS_FFO_BSY29"},
- {cp_stat & BIT(30), "VS_FFO_BSY30"},
- {cp_stat & BIT(31), "CP_BUSY 31"},
- };
- adreno_dump_fields(device, " CP_STT=", lns, ARRAY_SIZE(lns));
- }
-#endif
-
- kgsl_regread(device, A3XX_RBBM_INT_0_STATUS, &r1);
- KGSL_LOG_DUMP(device, "MSTR_INT_SGNL = %08X\n", r1);
- {
- struct log_field ints[] = {
- {r1 & BIT(0), "RBBM_GPU_IDLE 0"},
- {r1 & BIT(1), "RBBM_AHB_ERROR 1"},
- {r1 & BIT(2), "RBBM_REG_TIMEOUT 2"},
- {r1 & BIT(3), "RBBM_ME_MS_TIMEOUT 3"},
- {r1 & BIT(4), "RBBM_PFP_MS_TIMEOUT 4"},
- {r1 & BIT(5), "RBBM_ATB_BUS_OVERFLOW 5"},
- {r1 & BIT(6), "VFD_ERROR 6"},
- {r1 & BIT(7), "CP_SW_INT 7"},
- {r1 & BIT(8), "CP_T0_PACKET_IN_IB 8"},
- {r1 & BIT(9), "CP_OPCODE_ERROR 9"},
- {r1 & BIT(10), "CP_RESERVED_BIT_ERROR 10"},
- {r1 & BIT(11), "CP_HW_FAULT 11"},
- {r1 & BIT(12), "CP_DMA 12"},
- {r1 & BIT(13), "CP_IB2_INT 13"},
- {r1 & BIT(14), "CP_IB1_INT 14"},
- {r1 & BIT(15), "CP_RB_INT 15"},
- {r1 & BIT(16), "CP_REG_PROTECT_FAULT 16"},
- {r1 & BIT(17), "CP_RB_DONE_TS 17"},
- {r1 & BIT(18), "CP_VS_DONE_TS 18"},
- {r1 & BIT(19), "CP_PS_DONE_TS 19"},
- {r1 & BIT(20), "CACHE_FLUSH_TS 20"},
- {r1 & BIT(21), "CP_AHB_ERROR_HALT 21"},
- {r1 & BIT(24), "MISC_HANG_DETECT 24"},
- {r1 & BIT(25), "UCHE_OOB_ACCESS 25"},
- };
- adreno_dump_fields(device, "INT_SGNL=", ints, ARRAY_SIZE(ints));
- }
-}
-
-static void adreno_dump_a2xx(struct kgsl_device *device)
-{
- unsigned int r1, r2, r3, rbbm_status;
- unsigned int cp_stat, rb_count;
- struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
-
- kgsl_regread(device, adreno_dev->gpudev->reg_rbbm_status, &rbbm_status);
-
- kgsl_regread(device, REG_RBBM_PM_OVERRIDE1, &r2);
- kgsl_regread(device, REG_RBBM_PM_OVERRIDE2, &r3);
- KGSL_LOG_DUMP(device, "RBBM: STATUS = %08X | PM_OVERRIDE1 = %08X | "
- "PM_OVERRIDE2 = %08X\n", rbbm_status, r2, r3);
-
- kgsl_regread(device, REG_RBBM_INT_CNTL, &r1);
- kgsl_regread(device, REG_RBBM_INT_STATUS, &r2);
- kgsl_regread(device, REG_RBBM_READ_ERROR, &r3);
- KGSL_LOG_DUMP(device, " INT_CNTL = %08X | INT_STATUS = %08X | "
- "READ_ERROR = %08X\n", r1, r2, r3);
-
- {
- char cmdFifo[16];
- struct log_field lines[] = {
- {rbbm_status & 0x001F, cmdFifo},
- {rbbm_status & BIT(5), "TC busy "},
- {rbbm_status & BIT(8), "HIRQ pending"},
- {rbbm_status & BIT(9), "CPRQ pending"},
- {rbbm_status & BIT(10), "CFRQ pending"},
- {rbbm_status & BIT(11), "PFRQ pending"},
- {rbbm_status & BIT(12), "VGT 0DMA bsy"},
- {rbbm_status & BIT(14), "RBBM WU busy"},
- {rbbm_status & BIT(16), "CP NRT busy "},
- {rbbm_status & BIT(18), "MH busy "},
- {rbbm_status & BIT(19), "MH chncy bsy"},
- {rbbm_status & BIT(21), "SX busy "},
- {rbbm_status & BIT(22), "TPC busy "},
- {rbbm_status & BIT(24), "SC CNTX busy"},
- {rbbm_status & BIT(25), "PA busy "},
- {rbbm_status & BIT(26), "VGT busy "},
- {rbbm_status & BIT(27), "SQ cntx1 bsy"},
- {rbbm_status & BIT(28), "SQ cntx0 bsy"},
- {rbbm_status & BIT(30), "RB busy "},
- {rbbm_status & BIT(31), "Grphs pp bsy"},
- };
- snprintf(cmdFifo, sizeof(cmdFifo), "CMD FIFO=%01X ",
- rbbm_status & 0xf);
- adreno_dump_fields(device, " STATUS=", lines,
- ARRAY_SIZE(lines));
- }
-
- kgsl_regread(device, REG_CP_RB_BASE, &r1);
- kgsl_regread(device, REG_CP_RB_CNTL, &r2);
- rb_count = 2 << (r2 & (BIT(6)-1));
- kgsl_regread(device, REG_CP_RB_RPTR_ADDR, &r3);
- KGSL_LOG_DUMP(device,
- "CP_RB: BASE = %08X | CNTL = %08X | RPTR_ADDR = %08X"
- "| rb_count = %08X\n", r1, r2, r3, rb_count);
- {
- struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
- if (rb->sizedwords != rb_count)
- rb_count = rb->sizedwords;
- }
-
- kgsl_regread(device, REG_CP_RB_RPTR, &r1);
- kgsl_regread(device, REG_CP_RB_WPTR, &r2);
- kgsl_regread(device, REG_CP_RB_RPTR_WR, &r3);
- KGSL_LOG_DUMP(device,
- " RPTR = %08X | WPTR = %08X | RPTR_WR = %08X"
- "\n", r1, r2, r3);
-
- kgsl_regread(device, REG_CP_IB1_BASE, &r1);
- kgsl_regread(device, REG_CP_IB1_BUFSZ, &r2);
- KGSL_LOG_DUMP(device, "CP_IB1: BASE = %08X | BUFSZ = %d\n", r1, r2);
-
- kgsl_regread(device, REG_CP_IB2_BASE, &r1);
- kgsl_regread(device, REG_CP_IB2_BUFSZ, &r2);
- KGSL_LOG_DUMP(device, "CP_IB2: BASE = %08X | BUFSZ = %d\n", r1, r2);
-
- kgsl_regread(device, REG_CP_INT_CNTL, &r1);
- kgsl_regread(device, REG_CP_INT_STATUS, &r2);
- KGSL_LOG_DUMP(device, "CP_INT: CNTL = %08X | STATUS = %08X\n", r1, r2);
-
- kgsl_regread(device, REG_CP_ME_CNTL, &r1);
- kgsl_regread(device, REG_CP_ME_STATUS, &r2);
- kgsl_regread(device, REG_MASTER_INT_SIGNAL, &r3);
- KGSL_LOG_DUMP(device,
- "CP_ME: CNTL = %08X | STATUS = %08X | MSTR_INT_SGNL = "
- "%08X\n", r1, r2, r3);
-
- kgsl_regread(device, REG_CP_STAT, &cp_stat);
- KGSL_LOG_DUMP(device, "CP_STAT = %08X\n", cp_stat);
-#ifndef CONFIG_MSM_KGSL_PSTMRTMDMP_CP_STAT_NO_DETAIL
- {
- struct log_field lns[] = {
- {cp_stat & BIT(0), "WR_BSY 0"},
- {cp_stat & BIT(1), "RD_RQ_BSY 1"},
- {cp_stat & BIT(2), "RD_RTN_BSY 2"},
- };
- adreno_dump_fields(device, " MIU=", lns, ARRAY_SIZE(lns));
- }
- {
- struct log_field lns[] = {
- {cp_stat & BIT(5), "RING_BUSY 5"},
- {cp_stat & BIT(6), "NDRCTS_BSY 6"},
- {cp_stat & BIT(7), "NDRCT2_BSY 7"},
- {cp_stat & BIT(9), "ST_BUSY 9"},
- {cp_stat & BIT(10), "BUSY 10"},
- };
- adreno_dump_fields(device, " CSF=", lns, ARRAY_SIZE(lns));
- }
- {
- struct log_field lns[] = {
- {cp_stat & BIT(11), "RNG_Q_BSY 11"},
- {cp_stat & BIT(12), "NDRCTS_Q_B12"},
- {cp_stat & BIT(13), "NDRCT2_Q_B13"},
- {cp_stat & BIT(16), "ST_QUEUE_B16"},
- {cp_stat & BIT(17), "PFP_BUSY 17"},
- };
- adreno_dump_fields(device, " RING=", lns, ARRAY_SIZE(lns));
- }
- {
- struct log_field lns[] = {
- {cp_stat & BIT(3), "RBIU_BUSY 3"},
- {cp_stat & BIT(4), "RCIU_BUSY 4"},
- {cp_stat & BIT(18), "MQ_RG_BSY 18"},
- {cp_stat & BIT(19), "MQ_NDRS_BS19"},
- {cp_stat & BIT(20), "MQ_NDR2_BS20"},
- {cp_stat & BIT(21), "MIU_WC_STL21"},
- {cp_stat & BIT(22), "CP_NRT_BSY22"},
- {cp_stat & BIT(23), "3D_BUSY 23"},
- {cp_stat & BIT(26), "ME_BUSY 26"},
- {cp_stat & BIT(29), "ME_WC_BSY 29"},
- {cp_stat & BIT(30), "MIU_FF EM 30"},
- {cp_stat & BIT(31), "CP_BUSY 31"},
- };
- adreno_dump_fields(device, " CP_STT=", lns, ARRAY_SIZE(lns));
- }
-#endif
-
- kgsl_regread(device, REG_SCRATCH_REG0, &r1);
- KGSL_LOG_DUMP(device, "SCRATCH_REG0 = %08X\n", r1);
-
- kgsl_regread(device, REG_COHER_SIZE_PM4, &r1);
- kgsl_regread(device, REG_COHER_BASE_PM4, &r2);
- kgsl_regread(device, REG_COHER_STATUS_PM4, &r3);
- KGSL_LOG_DUMP(device,
- "COHER: SIZE_PM4 = %08X | BASE_PM4 = %08X | STATUS_PM4"
- " = %08X\n", r1, r2, r3);
-
- kgsl_regread(device, MH_AXI_ERROR, &r1);
- KGSL_LOG_DUMP(device, "MH: AXI_ERROR = %08X\n", r1);
-
- kgsl_regread(device, MH_MMU_PAGE_FAULT, &r1);
- kgsl_regread(device, MH_MMU_CONFIG, &r2);
- kgsl_regread(device, MH_MMU_MPU_BASE, &r3);
- KGSL_LOG_DUMP(device,
- "MH_MMU: PAGE_FAULT = %08X | CONFIG = %08X | MPU_BASE ="
- " %08X\n", r1, r2, r3);
-
- kgsl_regread(device, MH_MMU_MPU_END, &r1);
- kgsl_regread(device, MH_MMU_VA_RANGE, &r2);
- r3 = kgsl_mmu_get_current_ptbase(&device->mmu);
- KGSL_LOG_DUMP(device,
- " MPU_END = %08X | VA_RANGE = %08X | PT_BASE ="
- " %08X\n", r1, r2, r3);
-
- KGSL_LOG_DUMP(device, "PAGETABLE SIZE: %08X ",
- kgsl_mmu_get_ptsize(&device->mmu));
-
- kgsl_regread(device, MH_MMU_TRAN_ERROR, &r1);
- KGSL_LOG_DUMP(device, " TRAN_ERROR = %08X\n", r1);
-
- kgsl_regread(device, MH_INTERRUPT_MASK, &r1);
- kgsl_regread(device, MH_INTERRUPT_STATUS, &r2);
- KGSL_LOG_DUMP(device,
- "MH_INTERRUPT: MASK = %08X | STATUS = %08X\n", r1, r2);
-}
+EXPORT_SYMBOL(adreno_dump_fields);
int adreno_dump(struct kgsl_device *device, int manual)
{
@@ -745,26 +422,42 @@
if (device->pm_dump_enable) {
msm_clk_dump_debug_info();
- if (adreno_is_a2xx(adreno_dev))
- adreno_dump_a2xx(device);
- else if (adreno_is_a3xx(adreno_dev))
- adreno_dump_a3xx(device);
+ if (adreno_dev->gpudev->postmortem_dump)
+ adreno_dev->gpudev->postmortem_dump(adreno_dev);
}
- kgsl_regread(device, adreno_dev->gpudev->reg_rbbm_status, &rbbm_status);
+ kgsl_regread(device,
+ adreno_getreg(adreno_dev, ADRENO_REG_RBBM_STATUS),
+ &rbbm_status);
pt_base = kgsl_mmu_get_current_ptbase(&device->mmu);
cur_pt_base = pt_base;
- kgsl_regread(device, REG_CP_RB_BASE, &cp_rb_base);
- kgsl_regread(device, REG_CP_RB_CNTL, &cp_rb_ctrl);
+ kgsl_regread(device,
+ adreno_getreg(adreno_dev, ADRENO_REG_CP_RB_BASE),
+ &cp_rb_base);
+ kgsl_regread(device,
+ adreno_getreg(adreno_dev, ADRENO_REG_CP_RB_CNTL),
+ &cp_rb_ctrl);
rb_count = 2 << (cp_rb_ctrl & (BIT(6) - 1));
- kgsl_regread(device, REG_CP_RB_RPTR, &cp_rb_rptr);
- kgsl_regread(device, REG_CP_RB_WPTR, &cp_rb_wptr);
- kgsl_regread(device, REG_CP_IB1_BASE, &cp_ib1_base);
- kgsl_regread(device, REG_CP_IB1_BUFSZ, &cp_ib1_bufsz);
- kgsl_regread(device, REG_CP_IB2_BASE, &cp_ib2_base);
- kgsl_regread(device, REG_CP_IB2_BUFSZ, &cp_ib2_bufsz);
+ kgsl_regread(device,
+ adreno_getreg(adreno_dev, ADRENO_REG_CP_RB_RPTR),
+ &cp_rb_rptr);
+ kgsl_regread(device,
+ adreno_getreg(adreno_dev, ADRENO_REG_CP_RB_WPTR),
+ &cp_rb_wptr);
+ kgsl_regread(device,
+ adreno_getreg(adreno_dev, ADRENO_REG_CP_IB1_BASE),
+ &cp_ib1_base);
+ kgsl_regread(device,
+ adreno_getreg(adreno_dev, ADRENO_REG_CP_IB1_BUFSZ),
+ &cp_ib1_bufsz);
+ kgsl_regread(device,
+ adreno_getreg(adreno_dev, ADRENO_REG_CP_IB2_BASE),
+ &cp_ib2_base);
+ kgsl_regread(device,
+ adreno_getreg(adreno_dev, ADRENO_REG_CP_IB2_BUFSZ),
+ &cp_ib2_bufsz);
/* If postmortem dump is not enabled, dump minimal set and return */
if (!device->pm_dump_enable) {
@@ -782,7 +475,9 @@
(unsigned int *) &context_id,
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
current_context));
- context = idr_find(&device->context_idr, context_id);
+
+ context = kgsl_context_get(device, context_id);
+
if (context) {
ts_processed = kgsl_readtimestamp(device, context,
KGSL_TIMESTAMP_RETIRED);
@@ -791,6 +486,8 @@
} else
KGSL_LOG_DUMP(device, "BAD CTXT: %d\n", context_id);
+ kgsl_context_put(context);
+
num_item = adreno_ringbuffer_count(&adreno_dev->ringbuffer,
cp_rb_rptr);
if (num_item <= 0)
diff --git a/drivers/gpu/msm/adreno_profile.c b/drivers/gpu/msm/adreno_profile.c
new file mode 100644
index 0000000..896b6e8
--- /dev/null
+++ b/drivers/gpu/msm/adreno_profile.c
@@ -0,0 +1,1161 @@
+/* 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/fs.h>
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+#include <linux/vmalloc.h>
+#include <linux/debugfs.h>
+
+#include "adreno.h"
+#include "adreno_profile.h"
+#include "kgsl_sharedmem.h"
+#include "kgsl_cffdump.h"
+
+#define ASSIGNS_STR_FORMAT "%.8s:%u "
+
+/*
+ * Raw Data for processing later:
+ * : 3 - timestamp, count, context id
+ * [per counter] - data for each counter
+ * : 1 - Register offset
+ * : 2 - Pre IB register hi/lo value
+ * : 2 - Post IB register hi/lo value
+ * [per counter end]
+ */
+#define SIZE_DATA(cnt) (3 + (cnt) * 5)
+
+/*
+ * Pre-IB command size (in dwords):
+ * : 2 - NOP start identifier
+ * : 3 - timestamp
+ * : 3 - count
+ * : 3 - context id
+ * [loop count start] - for each counter to watch
+ * : 3 - Register offset
+ * : 3 - Register read lo
+ * : 3 - Register read high
+ * [loop end]
+ * : 2 - NOP end identifier
+ */
+#define SIZE_PREIB(cnt) (13 + (cnt) * 9)
+
+/*
+ * Post-IB command size (in dwords):
+ * : 2 - NOP start identifier
+ * [loop count start] - for each counter to watch
+ * : 3 - Register read lo
+ * : 3 - Register read high
+ * [loop end]
+ * : 2 - NOP end identifier
+ */
+#define SIZE_POSTIB(cnt) (4 + (cnt) * 6)
+
+/* Counter data + Pre size + post size = total size */
+#define SIZE_SHARED_ENTRY(cnt) (SIZE_DATA(cnt) + SIZE_PREIB(cnt) \
+ + SIZE_POSTIB(cnt))
+
+/*
+ * Space for following string :"%u %u %u %.5s %u "
+ * [count iterations]: "%.8s:%u %llu %llu%c"
+ */
+#define SIZE_PIPE_ENTRY(cnt) (50 + (cnt) * 62)
+#define SIZE_LOG_ENTRY(cnt) (5 + (cnt) * 5)
+
+static struct adreno_context_type ctxt_type_table[] = {ADRENO_DRAWCTXT_TYPES};
+
+static const char *get_api_type_str(unsigned int type)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(ctxt_type_table) - 1; i++) {
+ if (ctxt_type_table[i].type == type)
+ break;
+ }
+ return ctxt_type_table[i].str;
+}
+
+static inline void _create_ib_ref(struct kgsl_memdesc *memdesc,
+ unsigned int *cmd, unsigned int cnt, unsigned int off)
+{
+ cmd[0] = CP_HDR_INDIRECT_BUFFER_PFD;
+ cmd[1] = memdesc->gpuaddr + off;
+ cmd[2] = cnt;
+}
+
+#define IB_START(cmd) do { \
+ *cmd++ = cp_nop_packet(1); \
+ *cmd++ = KGSL_START_OF_PROFILE_IDENTIFIER; \
+ } while (0);
+
+#define IB_END(cmd) do { \
+ *cmd++ = cp_nop_packet(1); \
+ *cmd++ = KGSL_END_OF_PROFILE_IDENTIFIER; \
+ } while (0);
+
+#define IB_CMD(cmd, type, val1, val2, off) do { \
+ *cmd++ = cp_type3_packet(type, 2); \
+ *cmd++ = val1; \
+ *cmd++ = val2; \
+ off += sizeof(unsigned int); \
+ } while (0);
+
+static void _build_pre_ib_cmds(struct adreno_profile *profile,
+ unsigned int *rbcmds, unsigned int head,
+ unsigned int timestamp, unsigned int ctxt_id)
+{
+ struct adreno_profile_assigns_list *entry;
+ unsigned int *start, *ibcmds;
+ unsigned int count = profile->assignment_count;
+ unsigned int gpuaddr = profile->shared_buffer.gpuaddr;
+ unsigned int ib_offset = head + SIZE_DATA(count);
+ unsigned int data_offset = head * sizeof(unsigned int);
+
+ ibcmds = ib_offset + ((unsigned int *) profile->shared_buffer.hostptr);
+ start = ibcmds;
+
+ /* start of profile identifier */
+ IB_START(ibcmds);
+
+ /* timestamp */
+ IB_CMD(ibcmds, CP_MEM_WRITE, gpuaddr + data_offset,
+ timestamp, data_offset);
+
+ /* count: number of perf counters pairs GPU will write */
+ IB_CMD(ibcmds, CP_MEM_WRITE, gpuaddr + data_offset,
+ profile->assignment_count, data_offset);
+
+ /* context id */
+ IB_CMD(ibcmds, CP_MEM_WRITE, gpuaddr + data_offset,
+ ctxt_id, data_offset);
+
+ /* loop for each countable assigned */
+ list_for_each_entry(entry, &profile->assignments_list, list) {
+ IB_CMD(ibcmds, CP_MEM_WRITE, gpuaddr + data_offset,
+ entry->offset, data_offset);
+ IB_CMD(ibcmds, CP_REG_TO_MEM, entry->offset,
+ gpuaddr + data_offset, data_offset);
+ IB_CMD(ibcmds, CP_REG_TO_MEM, entry->offset + 1,
+ gpuaddr + data_offset, data_offset);
+
+ /* skip over post_ib counter data */
+ data_offset += sizeof(unsigned int) * 2;
+ }
+
+ /* end of profile identifier */
+ IB_END(ibcmds);
+
+ _create_ib_ref(&profile->shared_buffer, rbcmds,
+ ibcmds - start, ib_offset * sizeof(unsigned int));
+}
+
+static void _build_post_ib_cmds(struct adreno_profile *profile,
+ unsigned int *rbcmds, unsigned int head)
+{
+ struct adreno_profile_assigns_list *entry;
+ unsigned int *start, *ibcmds;
+ unsigned int count = profile->assignment_count;
+ unsigned int gpuaddr = profile->shared_buffer.gpuaddr;
+ unsigned int ib_offset = head + SIZE_DATA(count) + SIZE_PREIB(count);
+ unsigned int data_offset = head * sizeof(unsigned int);
+
+ ibcmds = ib_offset + ((unsigned int *) profile->shared_buffer.hostptr);
+ start = ibcmds;
+ /* end of profile identifier */
+ IB_END(ibcmds);
+
+ /* skip over pre_ib preamble */
+ data_offset += sizeof(unsigned int) * 3;
+
+ /* loop for each countable assigned */
+ list_for_each_entry(entry, &profile->assignments_list, list) {
+ /* skip over pre_ib counter data */
+ data_offset += sizeof(unsigned int) * 3;
+
+ IB_CMD(ibcmds, CP_REG_TO_MEM, entry->offset,
+ gpuaddr + data_offset, data_offset);
+ IB_CMD(ibcmds, CP_REG_TO_MEM, entry->offset + 1,
+ gpuaddr + data_offset, data_offset);
+ }
+
+ /* end of profile identifier */
+ IB_END(ibcmds);
+
+ _create_ib_ref(&profile->shared_buffer, rbcmds,
+ ibcmds - start, ib_offset * sizeof(unsigned int));
+}
+
+static bool shared_buf_empty(struct adreno_profile *profile)
+{
+ if (profile->shared_buffer.hostptr == NULL ||
+ profile->shared_buffer.size == 0)
+ return true;
+
+ if (profile->shared_head == profile->shared_tail)
+ return true;
+
+ return false;
+}
+
+static inline void shared_buf_inc(unsigned int max_size,
+ unsigned int *offset, size_t inc)
+{
+ *offset = (*offset + inc) % max_size;
+}
+
+static inline void log_buf_wrapcnt(unsigned int cnt, unsigned int *off)
+{
+ *off = (*off + cnt) % ADRENO_PROFILE_LOG_BUF_SIZE_DWORDS;
+}
+
+static inline void log_buf_wrapinc(unsigned int *profile_log_buffer,
+ unsigned int **ptr)
+{
+ *ptr += 1;
+ if (*ptr >= (profile_log_buffer +
+ ADRENO_PROFILE_LOG_BUF_SIZE_DWORDS))
+ *ptr -= ADRENO_PROFILE_LOG_BUF_SIZE_DWORDS;
+}
+
+static inline unsigned int log_buf_available(struct adreno_profile *profile,
+ unsigned int *head_ptr)
+{
+ unsigned int tail, head;
+
+ tail = (unsigned int) profile->log_tail -
+ (unsigned int) profile->log_buffer;
+ head = (unsigned int) head_ptr - (unsigned int) profile->log_buffer;
+ if (tail > head)
+ return (tail - head) / sizeof(unsigned int);
+ else
+ return ADRENO_PROFILE_LOG_BUF_SIZE_DWORDS - ((head - tail) /
+ sizeof(unsigned int));
+}
+
+static inline unsigned int shared_buf_available(struct adreno_profile *profile)
+{
+ if (profile->shared_tail > profile->shared_head)
+ return profile->shared_tail - profile->shared_head;
+ else
+ return profile->shared_size -
+ (profile->shared_head - profile->shared_tail);
+}
+
+static struct adreno_profile_assigns_list *_find_assignment_by_offset(
+ struct adreno_profile *profile, unsigned int offset)
+{
+ struct adreno_profile_assigns_list *entry;
+
+ list_for_each_entry(entry, &profile->assignments_list, list) {
+ if (entry->offset == offset)
+ return entry;
+ }
+
+ return NULL;
+}
+
+static bool _in_assignments_list(struct adreno_profile *profile,
+ unsigned int groupid, unsigned int countable)
+{
+ struct adreno_profile_assigns_list *entry;
+
+ list_for_each_entry(entry, &profile->assignments_list, list) {
+ if (entry->groupid == groupid && entry->countable ==
+ countable)
+ return true;
+ }
+
+ return false;
+}
+
+static bool _add_to_assignments_list(struct adreno_profile *profile,
+ const char *str, unsigned int groupid, unsigned int countable,
+ unsigned int offset)
+{
+ struct adreno_profile_assigns_list *entry;
+
+ /* first make sure we can alloc memory */
+ entry = kmalloc(sizeof(struct adreno_profile_assigns_list), GFP_KERNEL);
+ if (!entry)
+ return false;
+
+ list_add_tail(&entry->list, &profile->assignments_list);
+
+ entry->countable = countable;
+ entry->groupid = groupid;
+ entry->offset = offset;
+
+ strlcpy(entry->name, str, sizeof(entry->name));
+
+ profile->assignment_count++;
+
+ return true;
+}
+
+static void check_close_profile(struct adreno_profile *profile)
+{
+ if (profile->log_buffer == NULL)
+ return;
+
+ if (!adreno_profile_enabled(profile) && shared_buf_empty(profile)) {
+ if (profile->log_head == profile->log_tail) {
+ vfree(profile->log_buffer);
+ profile->log_buffer = NULL;
+ profile->log_head = NULL;
+ profile->log_tail = NULL;
+ }
+ }
+}
+
+static bool results_available(struct kgsl_device *device,
+ unsigned int *shared_buf_tail)
+{
+ unsigned int global_eop;
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct adreno_profile *profile = &adreno_dev->profile;
+ unsigned int off = profile->shared_tail;
+ unsigned int *shared_ptr = (unsigned int *)
+ profile->shared_buffer.hostptr;
+ unsigned int ts, cnt;
+ int ts_cmp;
+
+ /*
+ * If shared_buffer empty or Memstore EOP timestamp is less than
+ * outstanding counter buffer timestamps then no results available
+ */
+ if (shared_buf_empty(profile))
+ return false;
+
+ global_eop = kgsl_readtimestamp(device, NULL, KGSL_TIMESTAMP_RETIRED);
+ do {
+ cnt = *(shared_ptr + off + 1);
+ if (cnt == 0)
+ return false;
+
+ ts = *(shared_ptr + off);
+ ts_cmp = timestamp_cmp(ts, global_eop);
+ if (ts_cmp >= 0) {
+ *shared_buf_tail = off;
+ if (off == profile->shared_tail)
+ return false;
+ else
+ return true;
+ }
+ shared_buf_inc(profile->shared_size, &off,
+ SIZE_SHARED_ENTRY(cnt));
+ } while (off != profile->shared_head);
+
+ *shared_buf_tail = profile->shared_head;
+
+ return true;
+}
+
+static void transfer_results(struct kgsl_device *device,
+ unsigned int shared_buf_tail)
+{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct adreno_profile *profile = &adreno_dev->profile;
+ unsigned int buf_off;
+ unsigned int ts, cnt, ctxt_id, pid, tid, client_type;
+ unsigned int *ptr = (unsigned int *) profile->shared_buffer.hostptr;
+ struct kgsl_context *k_ctxt;
+ unsigned int *log_ptr, *log_base;
+ struct adreno_profile_assigns_list *assigns_list;
+ int i;
+
+ log_ptr = profile->log_head;
+ log_base = profile->log_buffer;
+ if (log_ptr == NULL)
+ return;
+
+ /*
+ * go through counter buffers and format for write into log_buffer
+ * if log buffer doesn't have space just overwrite it circularly
+ * shared_buf is guaranteed to not wrap within an entry so can use
+ * ptr increment
+ */
+ while (profile->shared_tail != shared_buf_tail) {
+ buf_off = profile->shared_tail;
+ /*
+ * format: timestamp, count, context_id
+ * count entries: pc_off, pc_start, pc_end
+ */
+ ts = *(ptr + buf_off);
+ cnt = *(ptr + buf_off + 1);
+ ctxt_id = *(ptr + buf_off + 2);
+ /*
+ * if entry overwrites the tail of log_buffer then adjust tail
+ * ptr to make room for the new entry, discarding old entry
+ */
+ while (log_buf_available(profile, log_ptr) <=
+ SIZE_LOG_ENTRY(cnt)) {
+ unsigned int size_tail, boff;
+ size_tail = SIZE_LOG_ENTRY(0xffff &
+ *(profile->log_tail));
+ boff = ((unsigned int) profile->log_tail -
+ (unsigned int) log_base) / sizeof(unsigned int);
+ log_buf_wrapcnt(size_tail, &boff);
+ profile->log_tail = log_base + boff;
+ }
+
+ /* find Adreno ctxt struct */
+ k_ctxt = idr_find(&device->context_idr, ctxt_id);
+ if (k_ctxt == NULL) {
+ shared_buf_inc(profile->shared_size,
+ &profile->shared_tail,
+ SIZE_SHARED_ENTRY(cnt));
+ continue;
+ } else {
+ struct adreno_context *adreno_ctxt =
+ ADRENO_CONTEXT(k_ctxt);
+ pid = k_ctxt->pid; /* pid */
+ tid = k_ctxt->tid; /* tid creator */
+ client_type = adreno_ctxt->type << 16;
+ }
+
+ buf_off += 3;
+ *log_ptr = client_type | cnt;
+ log_buf_wrapinc(log_base, &log_ptr);
+ *log_ptr = pid;
+ log_buf_wrapinc(log_base, &log_ptr);
+ *log_ptr = tid;
+ log_buf_wrapinc(log_base, &log_ptr);
+ *log_ptr = ctxt_id;
+ log_buf_wrapinc(log_base, &log_ptr);
+ *log_ptr = ts;
+ log_buf_wrapinc(log_base, &log_ptr);
+
+ for (i = 0; i < cnt; i++) {
+ assigns_list = _find_assignment_by_offset(
+ profile, *(ptr + buf_off++));
+ if (assigns_list == NULL) {
+ *log_ptr = (unsigned int) -1;
+ goto err;
+ } else {
+ *log_ptr = assigns_list->groupid << 16 |
+ (assigns_list->countable & 0xffff);
+ }
+ log_buf_wrapinc(log_base, &log_ptr);
+ *log_ptr = *(ptr + buf_off++); /* perf cntr start hi */
+ log_buf_wrapinc(log_base, &log_ptr);
+ *log_ptr = *(ptr + buf_off++); /* perf cntr start lo */
+ log_buf_wrapinc(log_base, &log_ptr);
+ *log_ptr = *(ptr + buf_off++); /* perf cntr end hi */
+ log_buf_wrapinc(log_base, &log_ptr);
+ *log_ptr = *(ptr + buf_off++); /* perf cntr end lo */
+ log_buf_wrapinc(log_base, &log_ptr);
+
+ }
+ shared_buf_inc(profile->shared_size,
+ &profile->shared_tail,
+ SIZE_SHARED_ENTRY(cnt));
+
+ }
+ profile->log_head = log_ptr;
+ return;
+err:
+ /* reset head/tail to same on error in hopes we work correctly later */
+ profile->log_head = profile->log_tail;
+}
+
+static int profile_enable_get(void *data, u64 *val)
+{
+ struct kgsl_device *device = data;
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
+ mutex_lock(&device->mutex);
+ *val = adreno_profile_enabled(&adreno_dev->profile);
+ mutex_unlock(&device->mutex);
+
+ return 0;
+}
+
+static int profile_enable_set(void *data, u64 val)
+{
+ struct kgsl_device *device = data;
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct adreno_profile *profile = &adreno_dev->profile;
+
+ mutex_lock(&device->mutex);
+
+ if (adreno_is_a2xx(adreno_dev)) {
+ mutex_unlock(&device->mutex);
+ return 0;
+ }
+
+ profile->enabled = val;
+
+ check_close_profile(profile);
+
+ mutex_unlock(&device->mutex);
+
+ return 0;
+}
+
+static ssize_t profile_assignments_read(struct file *filep,
+ char __user *ubuf, size_t max, loff_t *ppos)
+{
+ struct kgsl_device *device = (struct kgsl_device *) filep->private_data;
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct adreno_profile *profile = &adreno_dev->profile;
+ struct adreno_profile_assigns_list *entry;
+ int len = 0, max_size = PAGE_SIZE;
+ char *buf, *pos;
+ ssize_t size = 0;
+
+ if (adreno_is_a2xx(adreno_dev))
+ return -EINVAL;
+
+ mutex_lock(&device->mutex);
+
+ buf = kmalloc(max_size, GFP_KERNEL);
+ if (!buf) {
+ mutex_unlock(&device->mutex);
+ return -ENOMEM;
+ }
+
+ pos = buf;
+
+ /* copy all assingments from list to str */
+ list_for_each_entry(entry, &profile->assignments_list, list) {
+ len = snprintf(pos, max_size, ASSIGNS_STR_FORMAT,
+ entry->name, entry->countable);
+
+ max_size -= len;
+ pos += len;
+ }
+
+ size = simple_read_from_buffer(ubuf, max, ppos, buf,
+ strlen(buf));
+
+ kfree(buf);
+
+ mutex_unlock(&device->mutex);
+ return size;
+}
+
+static void _remove_assignment(struct adreno_device *adreno_dev,
+ unsigned int groupid, unsigned int countable)
+{
+ struct adreno_profile *profile = &adreno_dev->profile;
+ struct adreno_profile_assigns_list *entry, *tmp;
+
+ list_for_each_entry_safe(entry, tmp, &profile->assignments_list, list) {
+ if (entry->groupid == groupid &&
+ entry->countable == countable) {
+ list_del(&entry->list);
+
+ profile->assignment_count--;
+
+ kfree(entry);
+
+ /* remove from perf counter allocation */
+ adreno_perfcounter_put(adreno_dev, groupid, countable,
+ PERFCOUNTER_FLAG_KERNEL);
+ }
+ }
+}
+
+static void _add_assignment(struct adreno_device *adreno_dev,
+ unsigned int groupid, unsigned int countable)
+{
+ struct adreno_profile *profile = &adreno_dev->profile;
+ unsigned int offset;
+ const char *name = NULL;
+
+ name = adreno_perfcounter_get_name(adreno_dev, groupid);
+ if (!name)
+ return;
+
+ /* if already in assigned list skip it */
+ if (_in_assignments_list(profile, groupid, countable))
+ return;
+
+ /* add to perf counter allocation, if fail skip it */
+ if (adreno_perfcounter_get(adreno_dev, groupid,
+ countable, &offset, PERFCOUNTER_FLAG_NONE))
+ return;
+
+ /* add to assignments list, put counter back if error */
+ if (!_add_to_assignments_list(profile, name, groupid,
+ countable, offset))
+ adreno_perfcounter_put(adreno_dev, groupid,
+ countable, PERFCOUNTER_FLAG_KERNEL);
+}
+
+static char *_parse_next_assignment(struct adreno_device *adreno_dev,
+ char *str, int *groupid, int *countable, bool *remove)
+{
+ char *groupid_str, *countable_str;
+ int ret;
+
+ *groupid = -EINVAL;
+ *countable = -EINVAL;
+ *remove = false;
+
+ /* remove spaces */
+ while (*str == ' ')
+ str++;
+
+ /* check if it's a remove assignment */
+ if (*str == '-') {
+ *remove = true;
+ str++;
+ }
+
+ /* get the groupid string */
+ groupid_str = str;
+ while (*str != ':') {
+ if (*str == '\0')
+ return NULL;
+ *str = tolower(*str);
+ str++;
+ }
+ if (groupid_str == str)
+ return NULL;
+
+ *str = '\0';
+ str++;
+
+ /* get the countable string */
+ countable_str = str;
+ while (*str != ' ' && *str != '\0')
+ str++;
+ if (countable_str == str)
+ return NULL;
+
+ *str = '\0';
+ str++;
+
+ /* set results */
+ *groupid = adreno_perfcounter_get_groupid(adreno_dev,
+ groupid_str);
+ if (*groupid < 0)
+ return NULL;
+ ret = kstrtou32(countable_str, 10, countable);
+ if (ret)
+ return NULL;
+
+ return str;
+}
+
+static ssize_t profile_assignments_write(struct file *filep,
+ const char __user *user_buf, size_t len, loff_t *off)
+{
+ struct kgsl_device *device = (struct kgsl_device *) filep->private_data;
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct adreno_profile *profile = &adreno_dev->profile;
+ size_t size = 0;
+ char *buf, *pbuf;
+ bool remove_assignment = false;
+ int groupid, countable;
+
+ if (len >= PAGE_SIZE || len == 0)
+ return -EINVAL;
+
+ if (adreno_is_a2xx(adreno_dev))
+ return -ENOSPC;
+
+ mutex_lock(&device->mutex);
+
+ if (adreno_profile_enabled(profile)) {
+ size = -EINVAL;
+ goto error_unlock;
+ }
+
+ kgsl_active_count_get(device);
+
+ /*
+ * When adding/removing assignments, ensure that the GPU is done with
+ * all it's work. This helps to syncronize the work flow to the
+ * GPU and avoid racey conditions.
+ */
+ if (adreno_idle(device)) {
+ size = -EINVAL;
+ goto error_put;
+ }
+
+ /* clear all shared buffer results */
+ adreno_profile_process_results(device);
+
+ buf = kmalloc(len + 1, GFP_KERNEL);
+ if (!buf) {
+ size = -EINVAL;
+ goto error_put;
+ }
+
+ pbuf = buf;
+
+ /* clear the log buffer */
+ if (profile->log_buffer != NULL) {
+ profile->log_head = profile->log_buffer;
+ profile->log_tail = profile->log_buffer;
+ }
+
+ if (copy_from_user(buf, user_buf, len)) {
+ size = -EFAULT;
+ goto error_free;
+ }
+
+ /* for sanity and parsing, ensure it is null terminated */
+ buf[len] = '\0';
+
+ /* parse file buf and add(remove) to(from) appropriate lists */
+ while (1) {
+ pbuf = _parse_next_assignment(adreno_dev, pbuf, &groupid,
+ &countable, &remove_assignment);
+ if (pbuf == NULL)
+ break;
+
+ if (remove_assignment)
+ _remove_assignment(adreno_dev, groupid, countable);
+ else
+ _add_assignment(adreno_dev, groupid, countable);
+ }
+
+ size = len;
+
+error_free:
+ kfree(buf);
+error_put:
+ kgsl_active_count_put(device);
+error_unlock:
+ mutex_unlock(&device->mutex);
+ return size;
+}
+
+static int _pipe_print_pending(char *ubuf, size_t max)
+{
+ loff_t unused = 0;
+ char str[] = "Operation Would Block!";
+
+ return simple_read_from_buffer(ubuf, max,
+ &unused, str, strlen(str));
+}
+
+static int _pipe_print_results(struct adreno_device *adreno_dev,
+ char *ubuf, size_t max)
+{
+ struct adreno_profile *profile = &adreno_dev->profile;
+ const char *grp_name;
+ char *usr_buf = ubuf;
+ unsigned int *log_ptr = NULL;
+ int len, i;
+ int status = 0;
+ ssize_t size, total_size = 0;
+ unsigned int cnt, api_type, ctxt_id, pid, tid, ts, cnt_reg;
+ unsigned long long pc_start, pc_end;
+ const char *api_str;
+ char format_space;
+ loff_t unused = 0;
+ char pipe_hdr_buf[51]; /* 4 uint32 + 5 space + 5 API type + '\0' */
+ char pipe_cntr_buf[63]; /* 2 uint64 + 1 uint32 + 4 spaces + 8 group */
+
+ /* convert unread entries to ASCII, copy to user-space */
+ log_ptr = profile->log_tail;
+
+ do {
+ cnt = *log_ptr & 0xffff;
+ if (SIZE_PIPE_ENTRY(cnt) > max) {
+ status = 0;
+ goto err;
+ }
+ if ((max - (usr_buf - ubuf)) < SIZE_PIPE_ENTRY(cnt))
+ break;
+
+ api_type = *log_ptr >> 16;
+ api_str = get_api_type_str(api_type);
+ log_buf_wrapinc(profile->log_buffer, &log_ptr);
+ pid = *log_ptr;
+ log_buf_wrapinc(profile->log_buffer, &log_ptr);
+ tid = *log_ptr;
+ log_buf_wrapinc(profile->log_buffer, &log_ptr);
+ ctxt_id = *log_ptr;
+ log_buf_wrapinc(profile->log_buffer, &log_ptr);
+ ts = *log_ptr;
+ log_buf_wrapinc(profile->log_buffer, &log_ptr);
+ len = snprintf(pipe_hdr_buf, sizeof(pipe_hdr_buf) - 1,
+ "%u %u %u %.5s %u ",
+ pid, tid, ctxt_id, api_str, ts);
+ size = simple_read_from_buffer(usr_buf,
+ max - (usr_buf - ubuf),
+ &unused, pipe_hdr_buf, len);
+ if (size < 0) {
+ status = -EINVAL;
+ goto err;
+ }
+
+ unused = 0;
+ usr_buf += size;
+ total_size += size;
+
+ for (i = 0; i < cnt; i++) {
+ grp_name = adreno_perfcounter_get_name(
+ adreno_dev, *log_ptr >> 16);
+ if (grp_name == NULL) {
+ status = -EFAULT;
+ goto err;
+ }
+
+ if (i == cnt - 1)
+ format_space = '\n';
+ else
+ format_space = ' ';
+
+ cnt_reg = *log_ptr & 0xffff;
+ log_buf_wrapinc(profile->log_buffer, &log_ptr);
+ pc_start = *((unsigned long long *) log_ptr);
+ log_buf_wrapinc(profile->log_buffer, &log_ptr);
+ log_buf_wrapinc(profile->log_buffer, &log_ptr);
+ pc_end = *((unsigned long long *) log_ptr);
+ log_buf_wrapinc(profile->log_buffer, &log_ptr);
+ log_buf_wrapinc(profile->log_buffer, &log_ptr);
+
+ len = snprintf(pipe_cntr_buf,
+ sizeof(pipe_cntr_buf) - 1,
+ "%.8s:%u %llu %llu%c",
+ grp_name, cnt_reg, pc_start,
+ pc_end, format_space);
+
+ size = simple_read_from_buffer(usr_buf,
+ max - (usr_buf - ubuf),
+ &unused, pipe_cntr_buf, len);
+ if (size < 0) {
+ status = size;
+ goto err;
+ }
+ unused = 0;
+ usr_buf += size;
+ total_size += size;
+ }
+ } while (log_ptr != profile->log_head);
+
+ status = total_size;
+err:
+ profile->log_tail = log_ptr;
+
+ return status;
+}
+
+static int profile_pipe_print(struct file *filep, char __user *ubuf,
+ size_t max, loff_t *ppos)
+{
+ struct kgsl_device *device = (struct kgsl_device *) filep->private_data;
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct adreno_profile *profile = &adreno_dev->profile;
+ char *usr_buf = ubuf;
+ int status = 0;
+
+ if (adreno_is_a2xx(adreno_dev))
+ return 0;
+
+ /*
+ * this file not seekable since it only supports streaming, ignore
+ * ppos <> 0
+ */
+ /*
+ * format <pid> <tid> <context id> <cnt<<16 | client type> <timestamp>
+ * for each perf counter <cntr_reg_off> <start hi & lo> <end hi & low>
+ */
+
+ mutex_lock(&device->mutex);
+
+ while (1) {
+ /* process any results that are available into the log_buffer */
+ status = adreno_profile_process_results(device);
+ if (status > 0) {
+ /* if we have results, print them and exit */
+ status = _pipe_print_results(adreno_dev, usr_buf, max);
+ break;
+ }
+
+ /* there are no unread results, act accordingly */
+ if (filep->f_flags & O_NONBLOCK) {
+ if (profile->shared_tail != profile->shared_head) {
+ status = _pipe_print_pending(usr_buf, max);
+ break;
+ } else {
+ status = 0;
+ break;
+ }
+ }
+
+ mutex_unlock(&device->mutex);
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(HZ / 10);
+ mutex_lock(&device->mutex);
+
+ if (signal_pending(current)) {
+ status = 0;
+ break;
+ }
+ }
+
+ check_close_profile(profile);
+ mutex_unlock(&device->mutex);
+
+ return status;
+}
+
+static int profile_groups_print(struct seq_file *s, void *unused)
+{
+ struct kgsl_device *device = (struct kgsl_device *) s->private;
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct adreno_perfcounters *counters = adreno_dev->gpudev->perfcounters;
+ struct adreno_perfcount_group *group;
+ int i, j, used;
+
+ /* perfcounter list not allowed on a2xx */
+ if (adreno_is_a2xx(adreno_dev))
+ return -EINVAL;
+
+ mutex_lock(&device->mutex);
+
+ for (i = 0; i < counters->group_count; ++i) {
+ group = &(counters->groups[i]);
+ /* get number of counters used for this group */
+ used = 0;
+ for (j = 0; j < group->reg_count; j++) {
+ if (group->regs[j].countable !=
+ KGSL_PERFCOUNTER_NOT_USED)
+ used++;
+ }
+
+ seq_printf(s, "%s %d %d\n", group->name,
+ group->reg_count, used);
+ }
+
+ mutex_unlock(&device->mutex);
+
+ return 0;
+}
+
+static int profile_groups_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, profile_groups_print, inode->i_private);
+}
+
+static const struct file_operations profile_groups_fops = {
+ .owner = THIS_MODULE,
+ .open = profile_groups_open,
+ .read = seq_read,
+ .llseek = noop_llseek,
+ .release = single_release,
+};
+
+static const struct file_operations profile_pipe_fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .read = profile_pipe_print,
+ .llseek = noop_llseek,
+};
+
+static const struct file_operations profile_assignments_fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .read = profile_assignments_read,
+ .write = profile_assignments_write,
+ .llseek = noop_llseek,
+};
+
+DEFINE_SIMPLE_ATTRIBUTE(profile_enable_fops,
+ profile_enable_get,
+ profile_enable_set, "%llu\n");
+
+void adreno_profile_init(struct kgsl_device *device)
+{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct adreno_profile *profile = &adreno_dev->profile;
+ struct dentry *profile_dir;
+ int ret;
+
+ profile->enabled = false;
+
+ /* allocate shared_buffer, which includes pre_ib and post_ib */
+ profile->shared_size = ADRENO_PROFILE_SHARED_BUF_SIZE_DWORDS;
+ ret = kgsl_allocate_contiguous(&profile->shared_buffer,
+ profile->shared_size * sizeof(unsigned int));
+ if (ret) {
+ profile->shared_buffer.hostptr = NULL;
+ profile->shared_size = 0;
+ }
+
+ INIT_LIST_HEAD(&profile->assignments_list);
+
+ /* Create perf counter debugfs */
+ profile_dir = debugfs_create_dir("profiling", device->d_debugfs);
+ if (IS_ERR(profile_dir))
+ return;
+
+ debugfs_create_file("enable", 0644, profile_dir, device,
+ &profile_enable_fops);
+ debugfs_create_file("blocks", 0444, profile_dir, device,
+ &profile_groups_fops);
+ debugfs_create_file("pipe", 0444, profile_dir, device,
+ &profile_pipe_fops);
+ debugfs_create_file("assignments", 0644, profile_dir, device,
+ &profile_assignments_fops);
+}
+
+void adreno_profile_close(struct kgsl_device *device)
+{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct adreno_profile *profile = &adreno_dev->profile;
+ struct adreno_profile_assigns_list *entry, *tmp;
+
+ profile->enabled = false;
+ vfree(profile->log_buffer);
+ profile->log_buffer = NULL;
+ profile->log_head = NULL;
+ profile->log_tail = NULL;
+ profile->shared_head = 0;
+ profile->shared_tail = 0;
+ kgsl_sharedmem_free(&profile->shared_buffer);
+ profile->shared_buffer.hostptr = NULL;
+ profile->shared_size = 0;
+
+ profile->assignment_count = 0;
+
+ list_for_each_entry_safe(entry, tmp, &profile->assignments_list, list) {
+ list_del(&entry->list);
+ kfree(entry);
+ }
+}
+
+int adreno_profile_process_results(struct kgsl_device *device)
+{
+
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct adreno_profile *profile = &adreno_dev->profile;
+ unsigned int shared_buf_tail = profile->shared_tail;
+
+ if (!results_available(device, &shared_buf_tail)) {
+ check_close_profile(profile);
+ return 0;
+ }
+
+ /* allocate profile_log_buffer if needed */
+ if (profile->log_buffer == NULL) {
+ profile->log_buffer = vmalloc(ADRENO_PROFILE_LOG_BUF_SIZE);
+ if (profile->log_buffer == NULL)
+ return -ENOMEM;
+ profile->log_tail = profile->log_buffer;
+ profile->log_head = profile->log_buffer;
+ }
+
+ /*
+ * transfer retired results to log_buffer
+ * update shared_buffer tail ptr
+ */
+ transfer_results(device, shared_buf_tail);
+
+ /* check for any cleanup */
+ check_close_profile(profile);
+
+ return 1;
+}
+
+void adreno_profile_preib_processing(struct kgsl_device *device,
+ unsigned int context_id, unsigned int *cmd_flags,
+ unsigned int **rbptr, unsigned int *cmds_gpu)
+{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct adreno_profile *profile = &adreno_dev->profile;
+ int count = profile->assignment_count;
+ unsigned int entry_head = profile->shared_head;
+ unsigned int *shared_ptr;
+ struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+ unsigned int rbcmds[3] = { cp_nop_packet(2),
+ KGSL_NOP_IB_IDENTIFIER, KGSL_NOP_IB_IDENTIFIER };
+
+ *cmd_flags &= ~KGSL_CMD_FLAGS_PROFILE;
+
+ if (!adreno_profile_assignments_ready(profile))
+ goto done;
+
+ /*
+ * check if space available, include the post_ib in space available
+ * check so don't have to handle trying to undo the pre_ib insertion in
+ * ringbuffer in the case where only the post_ib fails enough space
+ */
+ if (SIZE_SHARED_ENTRY(count) >= shared_buf_available(profile))
+ goto done;
+
+ if (entry_head + SIZE_SHARED_ENTRY(count) > profile->shared_size) {
+ /* entry_head would wrap, start entry_head at 0 in buffer */
+ entry_head = 0;
+ profile->shared_size = profile->shared_head;
+ profile->shared_head = 0;
+ if (profile->shared_tail == profile->shared_size)
+ profile->shared_tail = 0;
+
+ /* recheck space available */
+ if (SIZE_SHARED_ENTRY(count) >= shared_buf_available(profile))
+ goto done;
+ }
+
+ /* zero out the counter area of shared_buffer entry_head */
+ shared_ptr = entry_head + ((unsigned int *)
+ profile->shared_buffer.hostptr);
+ memset(shared_ptr, 0, SIZE_SHARED_ENTRY(count) * sizeof(unsigned int));
+
+ /* reserve space for the pre ib shared buffer */
+ shared_buf_inc(profile->shared_size, &profile->shared_head,
+ SIZE_SHARED_ENTRY(count));
+
+ /* create the shared ibdesc */
+ _build_pre_ib_cmds(profile, rbcmds, entry_head,
+ rb->global_ts + 1, context_id);
+
+ /* set flag to sync with post ib commands */
+ *cmd_flags |= KGSL_CMD_FLAGS_PROFILE;
+
+done:
+ /* write the ibdesc to the ringbuffer */
+ GSL_RB_WRITE(device, (*rbptr), (*cmds_gpu), rbcmds[0]);
+ GSL_RB_WRITE(device, (*rbptr), (*cmds_gpu), rbcmds[1]);
+ GSL_RB_WRITE(device, (*rbptr), (*cmds_gpu), rbcmds[2]);
+}
+
+void adreno_profile_postib_processing(struct kgsl_device *device,
+ unsigned int *cmd_flags, unsigned int **rbptr,
+ unsigned int *cmds_gpu)
+{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct adreno_profile *profile = &adreno_dev->profile;
+ int count = profile->assignment_count;
+ unsigned int entry_head = profile->shared_head -
+ SIZE_SHARED_ENTRY(count);
+ unsigned int rbcmds[3] = { cp_nop_packet(2),
+ KGSL_NOP_IB_IDENTIFIER, KGSL_NOP_IB_IDENTIFIER };
+
+ if (!adreno_profile_assignments_ready(profile))
+ goto done;
+
+ if (!(*cmd_flags & KGSL_CMD_FLAGS_PROFILE))
+ goto done;
+
+ /* create the shared ibdesc */
+ _build_post_ib_cmds(profile, rbcmds, entry_head);
+
+done:
+ /* write the ibdesc to the ringbuffer */
+ GSL_RB_WRITE(device, (*rbptr), (*cmds_gpu), rbcmds[0]);
+ GSL_RB_WRITE(device, (*rbptr), (*cmds_gpu), rbcmds[1]);
+ GSL_RB_WRITE(device, (*rbptr), (*cmds_gpu), rbcmds[2]);
+
+ /* reset the sync flag */
+ *cmd_flags &= ~KGSL_CMD_FLAGS_PROFILE;
+}
+
diff --git a/drivers/gpu/msm/adreno_profile.h b/drivers/gpu/msm/adreno_profile.h
new file mode 100644
index 0000000..d91b09b
--- /dev/null
+++ b/drivers/gpu/msm/adreno_profile.h
@@ -0,0 +1,92 @@
+/* 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 __ADRENO_PROFILE_H
+#define __ADRENO_PROFILE_H
+#include <linux/seq_file.h>
+
+/**
+ * struct adreno_profile_assigns_list: linked list for assigned perf counters
+ * @list: linkage for nodes in list
+ * @name: group name or GPU name name
+ * @groupid: group id
+ * @countable: countable assigned to perfcounter
+ * @offset: perfcounter register address offset
+ */
+struct adreno_profile_assigns_list {
+ struct list_head list;
+ char name[25];
+ unsigned int groupid;
+ unsigned int countable;
+ unsigned int offset; /* LO offset, HI offset is +1 */
+};
+
+struct adreno_profile {
+ struct list_head assignments_list; /* list of all assignments */
+ unsigned int assignment_count; /* Number of assigned counters */
+ unsigned int *log_buffer;
+ unsigned int *log_head;
+ unsigned int *log_tail;
+ bool enabled;
+ /* counter, pre_ib, and post_ib held in one large circular buffer
+ * shared between kgsl and GPU
+ * counter entry 0
+ * pre_ib entry 0
+ * post_ib entry 0
+ * ...
+ * counter entry N
+ * pre_ib entry N
+ * post_ib entry N
+ */
+ struct kgsl_memdesc shared_buffer;
+ unsigned int shared_head;
+ unsigned int shared_tail;
+ unsigned int shared_size;
+};
+
+#define ADRENO_PROFILE_SHARED_BUF_SIZE_DWORDS (48 * 4096 / sizeof(uint))
+/* sized @ 48 pages should allow for over 50 outstanding IBs minimum, 1755 max*/
+
+#define ADRENO_PROFILE_LOG_BUF_SIZE (1024 * 920)
+/* sized for 1024 entries of fully assigned 45 cnters in log buffer, 230 pages*/
+#define ADRENO_PROFILE_LOG_BUF_SIZE_DWORDS (ADRENO_PROFILE_LOG_BUF_SIZE / \
+ sizeof(unsigned int))
+
+void adreno_profile_init(struct kgsl_device *device);
+void adreno_profile_close(struct kgsl_device *device);
+int adreno_profile_process_results(struct kgsl_device *device);
+void adreno_profile_preib_processing(struct kgsl_device *device,
+ unsigned int context_id, unsigned int *cmd_flags,
+ unsigned int **rbptr, unsigned int *cmds_gpu);
+void adreno_profile_postib_processing(struct kgsl_device *device,
+ unsigned int *cmd_flags, unsigned int **rbptr,
+ unsigned int *cmds_gpu);
+
+static inline bool adreno_profile_enabled(struct adreno_profile *profile)
+{
+ return profile->enabled;
+}
+
+static inline bool adreno_profile_has_assignments(
+ struct adreno_profile *profile)
+{
+ return list_empty(&profile->assignments_list) ? false : true;
+}
+
+static inline bool adreno_profile_assignments_ready(
+ struct adreno_profile *profile)
+{
+ return adreno_profile_enabled(profile) &&
+ adreno_profile_has_assignments(profile);
+}
+
+#endif
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 2d87263..188ef62 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -40,6 +40,7 @@
void adreno_ringbuffer_submit(struct adreno_ringbuffer *rb)
{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device);
BUG_ON(rb->wptr == 0);
/* Let the pwrscale policy know that new commands have
@@ -51,7 +52,7 @@
*/
mb();
- adreno_regwrite(rb->device, REG_CP_RB_WPTR, rb->wptr);
+ adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_WPTR, rb->wptr);
}
static int
@@ -137,7 +138,7 @@
if (context && context->flags & CTXT_FLAGS_GPU_HANG) {
KGSL_CTXT_WARN(rb->device,
"Context %p caused a gpu hang. Will not accept commands for context %d\n",
- context, context->id);
+ context, context->base.id);
return -EDEADLK;
}
wait_time = jiffies + wait_timeout;
@@ -269,11 +270,11 @@
KGSL_DRV_INFO(device, "loading pm4 ucode version: %d\n",
adreno_dev->pm4_fw_version);
- adreno_regwrite(device, REG_CP_DEBUG, CP_DEBUG_DEFAULT);
- adreno_regwrite(device, REG_CP_ME_RAM_WADDR, addr);
+ adreno_writereg(adreno_dev, ADRENO_REG_CP_DEBUG, CP_DEBUG_DEFAULT);
+ adreno_writereg(adreno_dev, ADRENO_REG_CP_ME_RAM_WADDR, addr);
for (i = start; i < adreno_dev->pm4_fw_size; i++)
- adreno_regwrite(device, REG_CP_ME_RAM_DATA,
- adreno_dev->pm4_fw[i]);
+ adreno_writereg(adreno_dev, ADRENO_REG_CP_ME_RAM_DATA,
+ adreno_dev->pm4_fw[i]);
return 0;
}
@@ -332,12 +333,11 @@
KGSL_DRV_INFO(device, "loading pfp ucode version: %d\n",
adreno_dev->pfp_fw_version);
- adreno_regwrite(device, adreno_dev->gpudev->reg_cp_pfp_ucode_addr,
+ adreno_writereg(adreno_dev, ADRENO_REG_CP_PFP_UCODE_ADDR,
addr);
for (i = start; i < adreno_dev->pfp_fw_size; i++)
- adreno_regwrite(device,
- adreno_dev->gpudev->reg_cp_pfp_ucode_data,
- adreno_dev->pfp_fw[i]);
+ adreno_writereg(adreno_dev, ADRENO_REG_CP_PFP_UCODE_DATA,
+ adreno_dev->pfp_fw[i]);
return 0;
}
@@ -367,17 +367,17 @@
(rb->sizedwords << 2));
if (adreno_is_a2xx(adreno_dev)) {
- adreno_regwrite(device, REG_CP_RB_WPTR_BASE,
+ kgsl_regwrite(device, REG_CP_RB_WPTR_BASE,
(rb->memptrs_desc.gpuaddr
+ GSL_RB_MEMPTRS_WPTRPOLL_OFFSET));
/* setup WPTR delay */
- adreno_regwrite(device, REG_CP_RB_WPTR_DELAY,
+ kgsl_regwrite(device, REG_CP_RB_WPTR_DELAY,
0 /*0x70000010 */);
}
/*setup REG_CP_RB_CNTL */
- adreno_regread(device, REG_CP_RB_CNTL, &rb_cntl);
+ adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_CNTL, &rb_cntl);
cp_rb_cntl.val = rb_cntl;
/*
@@ -401,64 +401,40 @@
/* mem RPTR writebacks */
cp_rb_cntl.f.rb_no_update = GSL_RB_CNTL_NO_UPDATE;
- adreno_regwrite(device, REG_CP_RB_CNTL, cp_rb_cntl.val);
+ adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_CNTL, cp_rb_cntl.val);
- adreno_regwrite(device, REG_CP_RB_BASE, rb->buffer_desc.gpuaddr);
+ adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_BASE,
+ rb->buffer_desc.gpuaddr);
- adreno_regwrite(device, REG_CP_RB_RPTR_ADDR,
- rb->memptrs_desc.gpuaddr +
- GSL_RB_MEMPTRS_RPTR_OFFSET);
-
- if (adreno_is_a3xx(adreno_dev)) {
- /* enable access protection to privileged registers */
- adreno_regwrite(device, A3XX_CP_PROTECT_CTRL, 0x00000007);
-
- /* RBBM registers */
- adreno_regwrite(device, A3XX_CP_PROTECT_REG_0, 0x63000040);
- adreno_regwrite(device, A3XX_CP_PROTECT_REG_1, 0x62000080);
- adreno_regwrite(device, A3XX_CP_PROTECT_REG_2, 0x600000CC);
- adreno_regwrite(device, A3XX_CP_PROTECT_REG_3, 0x60000108);
- adreno_regwrite(device, A3XX_CP_PROTECT_REG_4, 0x64000140);
- adreno_regwrite(device, A3XX_CP_PROTECT_REG_5, 0x66000400);
-
- /* CP registers */
- adreno_regwrite(device, A3XX_CP_PROTECT_REG_6, 0x65000700);
- adreno_regwrite(device, A3XX_CP_PROTECT_REG_7, 0x610007D8);
- adreno_regwrite(device, A3XX_CP_PROTECT_REG_8, 0x620007E0);
- adreno_regwrite(device, A3XX_CP_PROTECT_REG_9, 0x61001178);
- adreno_regwrite(device, A3XX_CP_PROTECT_REG_A, 0x64001180);
-
- /* RB registers */
- adreno_regwrite(device, A3XX_CP_PROTECT_REG_B, 0x60003300);
-
- /* VBIF registers */
- adreno_regwrite(device, A3XX_CP_PROTECT_REG_C, 0x6B00C000);
- }
+ 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 */
- adreno_regwrite(device, REG_CP_INT_ACK, 0xFFFFFFFF);
+ kgsl_regwrite(device, REG_CP_INT_ACK, 0xFFFFFFFF);
}
/* setup scratch/timestamp */
- adreno_regwrite(device, REG_SCRATCH_ADDR, device->memstore.gpuaddr +
- KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
- soptimestamp));
+ adreno_writereg(adreno_dev, ADRENO_REG_SCRATCH_ADDR,
+ device->memstore.gpuaddr +
+ KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+ soptimestamp));
- adreno_regwrite(device, REG_SCRATCH_UMSK,
+ adreno_writereg(adreno_dev, ADRENO_REG_SCRATCH_UMSK,
GSL_RB_MEMPTRS_SCRATCH_MASK);
/* CP ROQ queue sizes (bytes) - RB:16, ST:16, IB1:32, IB2:64 */
if (adreno_is_a305(adreno_dev) || adreno_is_a305c(adreno_dev) ||
adreno_is_a320(adreno_dev))
- adreno_regwrite(device, REG_CP_QUEUE_THRESHOLDS, 0x000E0602);
+ kgsl_regwrite(device, REG_CP_QUEUE_THRESHOLDS, 0x000E0602);
else if (adreno_is_a330(adreno_dev) || adreno_is_a305b(adreno_dev))
- adreno_regwrite(device, REG_CP_QUEUE_THRESHOLDS, 0x003E2008);
+ kgsl_regwrite(device, REG_CP_QUEUE_THRESHOLDS, 0x003E2008);
rb->wptr = 0;
/* clear ME_HALT to start micro engine */
- adreno_regwrite(device, REG_CP_ME_CNTL, 0);
+ adreno_writereg(adreno_dev, ADRENO_REG_CP_ME_CNTL, 0);
/* ME init is GPU specific, so jump into the sub-function */
status = adreno_dev->gpudev->rb_init(adreno_dev, rb);
@@ -529,7 +505,7 @@
if (rb->flags & KGSL_FLAGS_STARTED) {
if (adreno_is_a200(adreno_dev))
- adreno_regwrite(rb->device, REG_CP_ME_CNTL, 0x10000000);
+ kgsl_regwrite(rb->device, REG_CP_ME_CNTL, 0x10000000);
rb->flags &= ~KGSL_FLAGS_STARTED;
}
@@ -573,6 +549,8 @@
/* overlay structure on memptrs memory */
rb->memptrs = (struct kgsl_rbmemptrs *) rb->memptrs_desc.hostptr;
+ rb->global_ts = 0;
+
return 0;
}
@@ -592,11 +570,11 @@
memset(rb, 0, sizeof(struct adreno_ringbuffer));
}
-static uint32_t
+static int
adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb,
struct adreno_context *context,
unsigned int flags, unsigned int *cmds,
- int sizedwords, uint32_t timestamp)
+ int sizedwords)
{
struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device);
unsigned int *ringcmds;
@@ -605,6 +583,20 @@
unsigned int rcmd_gpu;
unsigned int context_id = KGSL_MEMSTORE_GLOBAL;
unsigned int gpuaddr = rb->device->memstore.gpuaddr;
+ unsigned int timestamp;
+ bool profile_ready;
+
+ /*
+ * If in stream ib profiling is enabled and there are counters
+ * assigned, then space needs to be reserved for profiling. This
+ * space in the ringbuffer is always consumed (might be filled with
+ * NOPs in error case. profile_ready needs to be consistent through
+ * the _addcmds call since it is allocating additional ringbuffer
+ * command space.
+ */
+ profile_ready = !adreno_is_a2xx(adreno_dev) &&
+ adreno_profile_assignments_ready(&adreno_dev->profile) &&
+ !(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE);
/*
* if the context was not created with per context timestamp
@@ -614,20 +606,7 @@
*/
if ((context && (context->flags & CTXT_FLAGS_PER_CONTEXT_TS)) &&
!(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE))
- context_id = context->id;
-
- if ((context && (context->flags & CTXT_FLAGS_USER_GENERATED_TS)) &&
- !(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE)) {
- if (timestamp_cmp(rb->timestamp[context_id],
- timestamp) >= 0) {
- KGSL_DRV_ERR(rb->device,
- "Invalid user generated ts <%d:0x%x>, "
- "less than last issued ts <%d:0x%x>\n",
- context_id, timestamp, context_id,
- rb->timestamp[context_id]);
- return -ERANGE;
- }
- }
+ context_id = context->base.id;
/* reserve space to temporarily turn off protected mode
* error checking if needed
@@ -666,14 +645,12 @@
if (flags & KGSL_CMD_FLAGS_EOF)
total_sizedwords += 2;
+ if (profile_ready)
+ total_sizedwords += 6; /* space for pre_ib and post_ib */
+
ringcmds = adreno_ringbuffer_allocspace(rb, context, total_sizedwords);
- if (!ringcmds) {
- /*
- * We could not allocate space in ringbuffer, just return the
- * last timestamp
- */
- return rb->timestamp[context_id];
- }
+ if (!ringcmds)
+ return -ENOSPC;
rcmd_gpu = rb->buffer_desc.gpuaddr
+ sizeof(uint)*(rb->wptr-total_sizedwords);
@@ -687,26 +664,25 @@
KGSL_CMD_INTERNAL_IDENTIFIER);
}
- /* always increment the global timestamp. once. */
- rb->timestamp[KGSL_MEMSTORE_GLOBAL]++;
+ /* Add any IB required for profiling if it is enabled */
+ if (profile_ready)
+ adreno_profile_preib_processing(rb->device, context->base.id,
+ &flags, &ringcmds, &rcmd_gpu);
- /*
- * If global timestamp then we are not using per context ts for
- * this submission
- */
- if (context_id != KGSL_MEMSTORE_GLOBAL) {
- if (context->flags & CTXT_FLAGS_USER_GENERATED_TS)
- rb->timestamp[context_id] = timestamp;
- else
- rb->timestamp[context_id]++;
- }
- timestamp = rb->timestamp[context_id];
+ /* always increment the global timestamp. once. */
+ rb->global_ts++;
+
+ if (KGSL_MEMSTORE_GLOBAL != context_id)
+ timestamp = context->timestamp;
+ else
+ timestamp = rb->global_ts;
/* scratchpad ts for fault tolerance */
GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
- cp_type0_packet(REG_CP_TIMESTAMP, 1));
+ cp_type0_packet(adreno_getreg(adreno_dev,
+ ADRENO_REG_CP_TIMESTAMP), 1));
GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
- rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
+ rb->global_ts);
/* start-of-pipeline timestamp */
GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
@@ -759,6 +735,12 @@
GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, 0x00);
}
+ /* Add any postIB required for profiling if it is enabled and has
+ assigned counters */
+ if (profile_ready)
+ adreno_profile_postib_processing(rb->device, &flags,
+ &ringcmds, &rcmd_gpu);
+
/*
* end-of-pipeline timestamp. If per context timestamps is not
* enabled, then context_id will be KGSL_MEMSTORE_GLOBAL so all
@@ -778,7 +760,7 @@
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
eoptimestamp)));
GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
- rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
+ rb->global_ts);
}
if (adreno_is_a20x(adreno_dev)) {
@@ -854,7 +836,7 @@
adreno_ringbuffer_submit(rb);
- return timestamp;
+ return 0;
}
unsigned int
@@ -874,7 +856,7 @@
flags |= KGSL_CMD_FLAGS_INTERNAL_ISSUE;
return adreno_ringbuffer_addcmds(rb, drawctxt, flags, cmds,
- sizedwords, 0);
+ sizedwords);
}
static bool _parse_ibs(struct kgsl_device_private *dev_priv, uint gpuaddr,
@@ -1094,16 +1076,16 @@
ret = -EINVAL;
goto done;
}
- drawctxt = context->devctxt;
+ drawctxt = ADRENO_CONTEXT(context);
if (drawctxt->flags & CTXT_FLAGS_GPU_HANG) {
- KGSL_CTXT_ERR(device, "proc %s failed fault tolerance"
- " will not accept commands for context %d\n",
- drawctxt->pid_name, drawctxt->id);
ret = -EDEADLK;
goto done;
}
+ /* process any profiling results that are available into the log_buf */
+ adreno_profile_process_results(device);
+
/*When preamble is enabled, the preamble buffer with state restoration
commands are stored in the first node of the IB chain. We can skip that
if a context switch hasn't occured */
@@ -1113,10 +1095,6 @@
start_index = 1;
if (drawctxt->flags & CTXT_FLAGS_SKIP_EOF) {
- KGSL_CTXT_ERR(device,
- "proc %s triggered fault tolerance"
- " skipping commands for context till EOF %d\n",
- drawctxt->pid_name, drawctxt->id);
if (flags & KGSL_CMD_FLAGS_EOF)
drawctxt->flags &= ~CTXT_FLAGS_SKIP_EOF;
if (start_index)
@@ -1169,10 +1147,30 @@
adreno_drawctxt_switch(adreno_dev, drawctxt, flags);
- *timestamp = adreno_ringbuffer_addcmds(&adreno_dev->ringbuffer,
+ if (drawctxt->flags & CTXT_FLAGS_USER_GENERATED_TS) {
+ if (timestamp_cmp(drawctxt->timestamp, *timestamp) >= 0) {
+ KGSL_DRV_ERR(device,
+ "Invalid user generated ts <%d:0x%x>, "
+ "less than last issued ts <%d:0x%x>\n",
+ context->id, *timestamp, context->id,
+ drawctxt->timestamp);
+ return -ERANGE;
+ }
+ drawctxt->timestamp = *timestamp;
+ } else
+ drawctxt->timestamp++;
+
+ ret = adreno_ringbuffer_addcmds(&adreno_dev->ringbuffer,
drawctxt,
(flags & KGSL_CMD_FLAGS_EOF),
- &link[0], (cmds - link), *timestamp);
+ &link[0], (cmds - link));
+ if (ret)
+ goto done;
+
+ if (drawctxt->flags & CTXT_FLAGS_PER_CONTEXT_TS)
+ *timestamp = drawctxt->timestamp;
+ else
+ *timestamp = adreno_dev->ringbuffer.global_ts;
#ifdef CONFIG_MSM_KGSL_CFF_DUMP
/*
@@ -1276,11 +1274,13 @@
if (0xFFFFFFFF == ft_data->start_of_replay_cmds)
return;
- k_ctxt = idr_find(&device->context_idr, ft_data->context_id);
+ k_ctxt = kgsl_context_get(device, ft_data->context_id);
+
if (k_ctxt) {
- a_ctxt = k_ctxt->devctxt;
+ a_ctxt = ADRENO_CONTEXT(k_ctxt);
if (a_ctxt->flags & CTXT_FLAGS_PREAMBLE)
_turn_preamble_on_for_ib_seq(rb, rb_rptr);
+ kgsl_context_put(k_ctxt);
}
k_ctxt = NULL;
@@ -1311,9 +1311,10 @@
/* if context switches to a context that did not cause
* hang then start saving the rb contents as those
* commands can be executed */
- k_ctxt = idr_find(&rb->device->context_idr, val2);
+ k_ctxt = kgsl_context_get(rb->device, val2);
+
if (k_ctxt) {
- a_ctxt = k_ctxt->devctxt;
+ a_ctxt = ADRENO_CONTEXT(k_ctxt);
/* If we are changing to a good context and were not
* copying commands then copy over commands to the good
@@ -1349,6 +1350,7 @@
copy_rb_contents = 0;
}
}
+ kgsl_context_put(k_ctxt);
}
if (copy_rb_contents)
@@ -1373,12 +1375,13 @@
int i;
unsigned int *ringcmds;
unsigned int rcmd_gpu;
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device);
if (!num_rb_contents)
return;
if (num_rb_contents > (rb->buffer_desc.size - rb->wptr)) {
- adreno_regwrite(rb->device, REG_CP_RB_RPTR, 0);
+ adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_RPTR, 0);
BUG_ON(num_rb_contents > rb->buffer_desc.size);
}
ringcmds = (unsigned int *)rb->buffer_desc.hostptr + rb->wptr;
diff --git a/drivers/gpu/msm/adreno_ringbuffer.h b/drivers/gpu/msm/adreno_ringbuffer.h
index e9fb050..9634e32 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.h
+++ b/drivers/gpu/msm/adreno_ringbuffer.h
@@ -55,7 +55,7 @@
unsigned int wptr; /* write pointer offset in dwords from baseaddr */
- unsigned int timestamp[KGSL_MEMSTORE_MAX];
+ unsigned int global_ts;
};
diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c
index d6ce298..b7c2237 100644
--- a/drivers/gpu/msm/adreno_snapshot.c
+++ b/drivers/gpu/msm/adreno_snapshot.c
@@ -467,6 +467,7 @@
static void ib_parse_type0(struct kgsl_device *device, unsigned int *ptr,
phys_addr_t ptbase)
{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
int size = type0_pkt_size(*ptr);
int offset = type0_pkt_offset(*ptr);
int i;
@@ -475,9 +476,12 @@
/* Visiblity stream buffer */
- if (offset >= A3XX_VSC_PIPE_DATA_ADDRESS_0 &&
- offset <= A3XX_VSC_PIPE_DATA_LENGTH_7) {
- int index = offset - A3XX_VSC_PIPE_DATA_ADDRESS_0;
+ if (offset >= adreno_getreg(adreno_dev,
+ ADRENO_REG_VSC_PIPE_DATA_ADDRESS_0) &&
+ offset <= adreno_getreg(adreno_dev,
+ ADRENO_REG_VSC_PIPE_DATA_LENGTH_7)) {
+ int index = offset - adreno_getreg(adreno_dev,
+ ADRENO_REG_VSC_PIPE_DATA_ADDRESS_0);
/* Each bank of address and length registers are
* interleaved with an empty register:
@@ -495,9 +499,13 @@
vsc_pipe[index / 3].base = ptr[i + 1];
else if ((index % 3) == 1)
vsc_pipe[index / 3].size = ptr[i + 1];
- } else if ((offset >= A3XX_VFD_FETCH_INSTR_0_0) &&
- (offset <= A3XX_VFD_FETCH_INSTR_1_F)) {
- int index = offset - A3XX_VFD_FETCH_INSTR_0_0;
+ } else if ((offset >= adreno_getreg(adreno_dev,
+ ADRENO_REG_VFD_FETCH_INSTR_0_0)) &&
+ (offset <= adreno_getreg(adreno_dev,
+ ADRENO_REG_VFD_FETCH_INSTR_1_F))) {
+ int index = offset -
+ adreno_getreg(adreno_dev,
+ ADRENO_REG_VFD_FETCH_INSTR_0_0);
/*
* FETCH_INSTR_0_X and FETCH_INSTR_1_X banks are
@@ -516,29 +524,30 @@
* buffer sizes
*/
- switch (offset) {
- case A3XX_VFD_CONTROL_0:
+ if (offset ==
+ adreno_getreg(adreno_dev,
+ ADRENO_REG_VFD_CONTROL_0))
vfd_control_0 = ptr[i + 1];
- break;
- case A3XX_VFD_INDEX_MAX:
+ else if (offset ==
+ adreno_getreg(adreno_dev,
+ ADRENO_REG_VFD_INDEX_MAX))
vfd_index_max = ptr[i + 1];
- break;
- case A3XX_VSC_SIZE_ADDRESS:
+ else if (offset ==
+ adreno_getreg(adreno_dev,
+ ADRENO_REG_VSC_SIZE_ADDRESS))
vsc_size_address = ptr[i + 1];
- break;
- case A3XX_SP_VS_PVT_MEM_ADDR_REG:
+ else if (offset == adreno_getreg(adreno_dev,
+ ADRENO_REG_SP_VS_PVT_MEM_ADDR_REG))
sp_vs_pvt_mem_addr = ptr[i + 1];
- break;
- case A3XX_SP_FS_PVT_MEM_ADDR_REG:
+ else if (offset == adreno_getreg(adreno_dev,
+ ADRENO_REG_SP_FS_PVT_MEM_ADDR_REG))
sp_fs_pvt_mem_addr = ptr[i + 1];
- break;
- case A3XX_SP_VS_OBJ_START_REG:
+ else if (offset == adreno_getreg(adreno_dev,
+ ADRENO_REG_SP_VS_OBJ_START_REG))
sp_vs_obj_start_reg = ptr[i + 1];
- break;
- case A3XX_SP_FS_OBJ_START_REG:
+ else if (offset == adreno_getreg(adreno_dev,
+ ADRENO_REG_SP_FS_OBJ_START_REG))
sp_fs_obj_start_reg = ptr[i + 1];
- break;
- }
}
}
}
@@ -629,6 +638,7 @@
static inline int parse_ib(struct kgsl_device *device, phys_addr_t ptbase,
unsigned int gpuaddr, unsigned int dwords)
{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
unsigned int ib1base, ib2base;
int ret = 0;
@@ -638,8 +648,8 @@
* it in the dynamic list
*/
- kgsl_regread(device, REG_CP_IB1_BASE, &ib1base);
- kgsl_regread(device, REG_CP_IB2_BASE, &ib2base);
+ adreno_readreg(adreno_dev, ADRENO_REG_CP_IB1_BASE, &ib1base);
+ adreno_readreg(adreno_dev, ADRENO_REG_CP_IB2_BASE, &ib2base);
if (gpuaddr == ib1base || gpuaddr == ib2base)
push_object(device, SNAPSHOT_OBJ_TYPE_IB, ptbase,
@@ -667,10 +677,10 @@
ptbase = kgsl_mmu_get_current_ptbase(&device->mmu);
/* Get the current read pointers for the RB */
- kgsl_regread(device, REG_CP_RB_RPTR, &rptr);
+ adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_RPTR, &rptr);
/* Address of the last processed IB */
- kgsl_regread(device, REG_CP_IB1_BASE, &ibbase);
+ adreno_readreg(adreno_dev, ADRENO_REG_CP_IB1_BASE, &ibbase);
/*
* Figure out the window of ringbuffer data to dump. First we need to
@@ -998,8 +1008,8 @@
* want to be double plus sure.
*/
- kgsl_regread(device, REG_CP_IB1_BASE, &ibbase);
- kgsl_regread(device, REG_CP_IB1_BUFSZ, &ibsize);
+ adreno_readreg(adreno_dev, ADRENO_REG_CP_IB1_BASE, &ibbase);
+ adreno_readreg(adreno_dev, ADRENO_REG_CP_IB1_BUFSZ, &ibsize);
/*
* The problem is that IB size from the register is the unprocessed size
@@ -1016,8 +1026,8 @@
"Dumping %x dwords of the buffer.\n", ibsize);
}
- kgsl_regread(device, REG_CP_IB2_BASE, &ibbase);
- kgsl_regread(device, REG_CP_IB2_BUFSZ, &ibsize);
+ adreno_readreg(adreno_dev, ADRENO_REG_CP_IB2_BASE, &ibbase);
+ adreno_readreg(adreno_dev, ADRENO_REG_CP_IB2_BUFSZ, &ibsize);
/*
* Add the last parsed IB2 to the list. The IB2 should be found as we
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index e62dac9..fdd19e9 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -448,60 +448,63 @@
entry->priv = NULL;
}
-/* Allocate a new context id */
-
-static struct kgsl_context *
-kgsl_create_context(struct kgsl_device_private *dev_priv)
+/**
+ * kgsl_context_init() - helper to initialize kgsl_context members
+ * @dev_priv: the owner of the context
+ * @context: the newly created context struct, should be allocated by
+ * the device specific drawctxt_create function.
+ *
+ * This is a helper function for the device specific drawctxt_create
+ * function to initialize the common members of its context struct.
+ * If this function succeeds, reference counting is active in the context
+ * struct and the caller should kgsl_context_put() it on error.
+ * If it fails, the caller should just free the context structure
+ * it passed in.
+ */
+int kgsl_context_init(struct kgsl_device_private *dev_priv,
+ struct kgsl_context *context)
{
- struct kgsl_context *context;
- int ret, id;
-
- context = kzalloc(sizeof(*context), GFP_KERNEL);
-
- if (context == NULL) {
- KGSL_DRV_INFO(dev_priv->device, "kzalloc(%d) failed\n",
- sizeof(*context));
- return ERR_PTR(-ENOMEM);
- }
+ int ret = 0, id;
+ struct kgsl_device *device = dev_priv->device;
while (1) {
- if (idr_pre_get(&dev_priv->device->context_idr,
- GFP_KERNEL) == 0) {
- KGSL_DRV_INFO(dev_priv->device,
- "idr_pre_get: ENOMEM\n");
+ if (idr_pre_get(&device->context_idr, GFP_KERNEL) == 0) {
+ KGSL_DRV_INFO(device, "idr_pre_get: ENOMEM\n");
ret = -ENOMEM;
- goto func_end;
+ break;
}
- ret = idr_get_new_above(&dev_priv->device->context_idr,
- context, 1, &id);
+ write_lock(&device->context_lock);
+ ret = idr_get_new_above(&device->context_idr, context, 1, &id);
+ context->id = id;
+ write_unlock(&device->context_lock);
if (ret != -EAGAIN)
break;
}
if (ret)
- goto func_end;
+ goto fail;
/* MAX - 1, there is one memdesc in memstore for device info */
if (id >= KGSL_MEMSTORE_MAX) {
- KGSL_DRV_INFO(dev_priv->device, "cannot have more than %d "
+ KGSL_DRV_INFO(device, "cannot have more than %d "
"ctxts due to memstore limitation\n",
KGSL_MEMSTORE_MAX);
- idr_remove(&dev_priv->device->context_idr, id);
ret = -ENOSPC;
- goto func_end;
+ goto fail_free_id;
}
kref_init(&context->refcount);
- context->id = id;
+ context->device = dev_priv->device;
+ context->pagetable = dev_priv->process_priv->pagetable;
context->dev_priv = dev_priv;
+ context->pid = task_tgid_nr(current);
+ context->tid = task_pid_nr(current);
ret = kgsl_sync_timeline_create(context);
- if (ret) {
- idr_remove(&dev_priv->device->context_idr, id);
- goto func_end;
- }
+ if (ret)
+ goto fail_free_id;
/* Initialize the pending event list */
INIT_LIST_HEAD(&context->events);
@@ -516,15 +519,15 @@
*/
INIT_LIST_HEAD(&context->events_list);
-
-func_end:
- if (ret) {
- kfree(context);
- return ERR_PTR(ret);
- }
-
- return context;
+ return 0;
+fail_free_id:
+ write_lock(&device->context_lock);
+ idr_remove(&dev_priv->device->context_idr, id);
+ write_unlock(&device->context_lock);
+fail:
+ return ret;
}
+EXPORT_SYMBOL(kgsl_context_init);
/**
* kgsl_context_detach - Release the "master" context reference
@@ -534,31 +537,36 @@
* has requested for it to be destroyed. The context itself may
* exist a bit longer until its reference count goes to zero.
* Other code referencing the context can detect that it has been
- * detached because the context id will be set to KGSL_CONTEXT_INVALID.
+ * detached by checking the KGSL_CONTEXT_DETACHED bit in
+ * context->priv.
*/
void
kgsl_context_detach(struct kgsl_context *context)
{
- int id;
struct kgsl_device *device;
if (context == NULL)
return;
- device = context->dev_priv->device;
- trace_kgsl_context_detach(device, context);
- id = context->id;
- if (device->ftbl->drawctxt_destroy)
- device->ftbl->drawctxt_destroy(device, context);
- /*device specific drawctxt_destroy MUST clean up devctxt */
- BUG_ON(context->devctxt);
+ device = context->device;
+
+ /*
+ * Mark the context as detached to keep others from using
+ * the context before it gets fully removed, and to make sure
+ * we don't try to detach twice.
+ */
+ if (test_and_set_bit(KGSL_CONTEXT_DETACHED, &context->priv))
+ return;
+
+ trace_kgsl_context_detach(device, context);
+
+ device->ftbl->drawctxt_detach(context);
/*
* Cancel events after the device-specific context is
- * destroyed, to avoid possibly freeing memory while
+ * detached, to avoid possibly freeing memory while
* it is still in use by the GPU.
*/
- kgsl_cancel_events_ctxt(device, context);
- idr_remove(&device->context_idr, id);
- context->id = KGSL_CONTEXT_INVALID;
+ kgsl_context_cancel_events(device, context);
+
kgsl_context_put(context);
}
@@ -567,8 +575,19 @@
{
struct kgsl_context *context = container_of(kref, struct kgsl_context,
refcount);
+ struct kgsl_device *device = context->device;
+
+ trace_kgsl_context_destroy(device, context);
+
+ write_lock(&device->context_lock);
+ if (context->id != KGSL_CONTEXT_INVALID) {
+ idr_remove(&device->context_idr, context->id);
+ context->id = KGSL_CONTEXT_INVALID;
+ }
+ write_unlock(&device->context_lock);
kgsl_sync_timeline_destroy(context);
- kfree(context);
+
+ device->ftbl->drawctxt_destroy(context);
}
struct kgsl_device *kgsl_get_device(int dev_idx)
@@ -634,7 +653,7 @@
* Make sure no user process is waiting for a timestamp
* before supending.
*/
- kgsl_active_count_wait(device);
+ kgsl_active_count_wait(device, 0);
/*
* An interrupt could have snuck in and requested NAP in
@@ -690,21 +709,22 @@
KGSL_PWR_WARN(device, "resume start\n");
mutex_lock(&device->mutex);
if (device->state == KGSL_STATE_SUSPEND) {
+ kgsl_pwrctrl_set_state(device, KGSL_STATE_SLUMBER);
complete_all(&device->hwaccess_gate);
- } else {
+ } else if (device->state != KGSL_STATE_INIT) {
/*
* This is an error situation,so wait for the device
* to idle and then put the device to SLUMBER state.
* This will put the device to the right state when
* we resume.
*/
- device->ftbl->idle(device);
+ if (device->state == KGSL_STATE_ACTIVE)
+ device->ftbl->idle(device);
kgsl_pwrctrl_request_state(device, KGSL_STATE_SLUMBER);
kgsl_pwrctrl_sleep(device);
KGSL_PWR_ERR(device,
"resume invoked without a suspend\n");
}
- kgsl_pwrctrl_set_state(device, KGSL_STATE_SLUMBER);
kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
mutex_unlock(&device->mutex);
@@ -793,15 +813,15 @@
list_del(&private->list);
mutex_unlock(&kgsl_driver.process_mutex);
- if (private->kobj.ktype)
+ if (private->kobj.state_in_sysfs)
kgsl_process_uninit_sysfs(private);
if (private->debug_root)
debugfs_remove_recursive(private->debug_root);
while (1) {
- rcu_read_lock();
+ spin_lock(&private->mem_lock);
entry = idr_get_next(&private->mem_idr, &next);
- rcu_read_unlock();
+ spin_unlock(&private->mem_lock);
if (entry == NULL)
break;
kgsl_mem_entry_put(entry);
@@ -812,8 +832,8 @@
*/
next = 0;
}
- kgsl_mmu_putpagetable(private->pagetable);
idr_destroy(&private->mem_idr);
+ kgsl_mmu_putpagetable(private->pagetable);
kfree(private);
return;
@@ -907,21 +927,23 @@
pt_name = task_tgid_nr(current);
private->pagetable = kgsl_mmu_getpagetable(mmu, pt_name);
- if (private->pagetable == NULL) {
- mutex_unlock(&private->process_private_mutex);
- kgsl_put_process_private(cur_dev_priv->device,
- private);
- return NULL;
- }
+ if (private->pagetable == NULL)
+ goto error;
}
- kgsl_process_init_sysfs(private);
- kgsl_process_init_debugfs(private);
+ if (kgsl_process_init_sysfs(cur_dev_priv->device, private))
+ goto error;
+ if (kgsl_process_init_debugfs(private))
+ goto error;
done:
mutex_unlock(&private->process_private_mutex);
-
return private;
+
+error:
+ mutex_unlock(&private->process_private_mutex);
+ kgsl_put_process_private(cur_dev_priv->device, private);
+ return NULL;
}
int kgsl_close_device(struct kgsl_device *device)
@@ -929,7 +951,13 @@
int result = 0;
device->open_count--;
if (device->open_count == 0) {
+
+ /* Wait for the active count to go to 1 */
+ kgsl_active_count_wait(device, 1);
+
+ /* Fail if the wait times out */
BUG_ON(atomic_read(&device->active_cnt) > 1);
+
result = device->ftbl->stop(device);
kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
/*
@@ -960,14 +988,15 @@
kgsl_active_count_get(device);
while (1) {
+ read_lock(&device->context_lock);
context = idr_get_next(&device->context_idr, &next);
+ read_unlock(&device->context_lock);
+
if (context == NULL)
break;
- if (context->dev_priv == dev_priv) {
+ if (context->dev_priv == dev_priv)
kgsl_context_detach(context);
- context->dev_priv = NULL;
- }
next = next + 1;
}
@@ -1234,11 +1263,11 @@
{
struct kgsl_mem_entry *entry;
- rcu_read_lock();
+ spin_lock(&process->mem_lock);
entry = idr_find(&process->mem_idr, id);
if (entry)
kgsl_mem_entry_get(entry);
- rcu_read_unlock();
+ spin_unlock(&process->mem_lock);
return entry;
}
@@ -1256,10 +1285,12 @@
static inline bool kgsl_mem_entry_set_pend(struct kgsl_mem_entry *entry)
{
bool ret = false;
+
+ if (entry == NULL)
+ return false;
+
spin_lock(&entry->priv->mem_lock);
- if (entry && entry->pending_free) {
- ret = false;
- } else if (entry) {
+ if (!entry->pending_free) {
entry->pending_free = 1;
ret = true;
}
@@ -1309,7 +1340,7 @@
result = -EFAULT;
break;
}
- context = kgsl_find_context(dev_priv, id);
+ context = kgsl_context_get_owner(dev_priv, id);
if (!context) {
result = -EINVAL;
break;
@@ -1319,12 +1350,14 @@
* the out parameter
*/
if (copy_to_user(param->value, &(context->reset_status),
- sizeof(unsigned int))) {
+ sizeof(unsigned int)))
result = -EFAULT;
- break;
+ else {
+ /* Clear reset status once its been queried */
+ context->reset_status = KGSL_CTX_STAT_NO_ERROR;
}
- /* Clear reset status once its been queried */
- context->reset_status = KGSL_CTX_STAT_NO_ERROR;
+
+ kgsl_context_put(context);
break;
}
default:
@@ -1393,19 +1426,14 @@
{
struct kgsl_device_waittimestamp_ctxtid *param = data;
struct kgsl_context *context;
- int result;
+ long result = -EINVAL;
- context = kgsl_find_context(dev_priv, param->context_id);
- if (context == NULL)
- return -EINVAL;
- /*
- * A reference count is needed here, because waittimestamp may
- * block with the device mutex unlocked and userspace could
- * request for the context to be destroyed during that time.
- */
- kgsl_context_get(context);
- result = _device_waittimestamp(dev_priv, context,
+ context = kgsl_context_get_owner(dev_priv, param->context_id);
+
+ if (context)
+ result = _device_waittimestamp(dev_priv, context,
param->timestamp, param->timeout);
+
kgsl_context_put(context);
return result;
}
@@ -1419,7 +1447,7 @@
struct kgsl_ibdesc *ibdesc;
struct kgsl_context *context;
- context = kgsl_find_context(dev_priv, param->drawctxt_id);
+ context = kgsl_context_get_owner(dev_priv, param->drawctxt_id);
if (context == NULL) {
result = -EINVAL;
goto done;
@@ -1498,7 +1526,7 @@
free_ibdesc:
kfree(ibdesc);
done:
-
+ kgsl_context_put(context);
return result;
}
@@ -1531,19 +1559,24 @@
{
struct kgsl_cmdstream_readtimestamp_ctxtid *param = data;
struct kgsl_context *context;
+ long result = -EINVAL;
- context = kgsl_find_context(dev_priv, param->context_id);
- if (context == NULL)
- return -EINVAL;
+ context = kgsl_context_get_owner(dev_priv, param->context_id);
- return _cmdstream_readtimestamp(dev_priv, context,
+ if (context)
+ result = _cmdstream_readtimestamp(dev_priv, context,
param->type, ¶m->timestamp);
+
+ kgsl_context_put(context);
+ return result;
}
static void kgsl_freemem_event_cb(struct kgsl_device *device,
- void *priv, u32 id, u32 timestamp)
+ void *priv, u32 id, u32 timestamp, u32 type)
{
struct kgsl_mem_entry *entry = priv;
+
+ /* Free the memory for all event types */
trace_kgsl_mem_timestamp_free(device, entry, id, timestamp, 0);
kgsl_mem_entry_put(entry);
}
@@ -1598,13 +1631,14 @@
{
struct kgsl_cmdstream_freememontimestamp_ctxtid *param = data;
struct kgsl_context *context;
+ long result = -EINVAL;
- context = kgsl_find_context(dev_priv, param->context_id);
- if (context == NULL)
- return -EINVAL;
-
- return _cmdstream_freememontimestamp(dev_priv, param->gpuaddr,
+ context = kgsl_context_get_owner(dev_priv, param->context_id);
+ if (context)
+ result = _cmdstream_freememontimestamp(dev_priv, param->gpuaddr,
context, param->timestamp, param->type);
+ kgsl_context_put(context);
+ return result;
}
static long kgsl_ioctl_drawctxt_create(struct kgsl_device_private *dev_priv,
@@ -1613,46 +1647,34 @@
int result = 0;
struct kgsl_drawctxt_create *param = data;
struct kgsl_context *context = NULL;
+ struct kgsl_device *device = dev_priv->device;
- context = kgsl_create_context(dev_priv);
-
+ context = device->ftbl->drawctxt_create(dev_priv, ¶m->flags);
if (IS_ERR(context)) {
result = PTR_ERR(context);
goto done;
}
-
- if (dev_priv->device->ftbl->drawctxt_create) {
- result = dev_priv->device->ftbl->drawctxt_create(
- dev_priv->device, dev_priv->process_priv->pagetable,
- context, ¶m->flags);
- if (result)
- goto done;
- }
trace_kgsl_context_create(dev_priv->device, context, param->flags);
param->drawctxt_id = context->id;
done:
- if (result && !IS_ERR(context))
- kgsl_context_detach(context);
-
return result;
}
static long kgsl_ioctl_drawctxt_destroy(struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data)
{
- int result = 0;
struct kgsl_drawctxt_destroy *param = data;
struct kgsl_context *context;
+ long result = -EINVAL;
- context = kgsl_find_context(dev_priv, param->drawctxt_id);
+ context = kgsl_context_get_owner(dev_priv, param->drawctxt_id);
- if (context == NULL) {
- result = -EINVAL;
- goto done;
+ if (context) {
+ kgsl_context_detach(context);
+ result = 0;
}
- kgsl_context_detach(context);
-done:
+ kgsl_context_put(context);
return result;
}
@@ -2370,7 +2392,8 @@
entries[actual_count++] = entry;
/* If we exceed the breakeven point, flush the entire cache */
- if (op_size >= kgsl_driver.full_cache_threshold &&
+ if (kgsl_driver.full_cache_threshold != 0 &&
+ op_size >= kgsl_driver.full_cache_threshold &&
param->op == KGSL_GPUMEM_CACHE_FLUSH) {
full_flush = true;
break;
@@ -2429,6 +2452,7 @@
int result;
struct kgsl_process_private *private = dev_priv->process_priv;
struct kgsl_mem_entry *entry;
+ int align;
/*
* Mask off unknown flags from userspace. This way the caller can
@@ -2440,6 +2464,16 @@
| KGSL_MEMALIGN_MASK
| KGSL_MEMFLAGS_USE_CPU_MAP;
+ /* Cap the alignment bits to the highest number we can handle */
+
+ align = (flags & KGSL_MEMALIGN_MASK) >> KGSL_MEMALIGN_SHIFT;
+ if (align >= 32) {
+ KGSL_CORE_ERR("Alignment too big, restricting to 2^31\n");
+
+ flags &= ~KGSL_MEMALIGN_MASK;
+ flags |= (31 << KGSL_MEMALIGN_SHIFT) & KGSL_MEMALIGN_MASK;
+ }
+
entry = kgsl_mem_entry_create();
if (entry == NULL)
return -ENOMEM;
@@ -2579,7 +2613,7 @@
if (!entry)
return -EINVAL;
- kgsl_cffdump_syncmem(dev_priv, &entry->memdesc, param->gpuaddr,
+ kgsl_cffdump_syncmem(dev_priv->device, &entry->memdesc, param->gpuaddr,
param->len, true);
kgsl_mem_entry_put(entry);
@@ -2606,21 +2640,23 @@
};
/**
- * kgsl_genlock_event_cb - Event callback for a genlock timestamp event
- * @device - The KGSL device that expired the timestamp
- * @priv - private data for the event
- * @context_id - the context id that goes with the timestamp
- * @timestamp - the timestamp that triggered the event
+ * kgsl_genlock_event_cb() - Event callback for a genlock timestamp event
+ * @device: The KGSL device that expired the timestamp
+ * @priv: private data for the event
+ * @context_id: the context id that goes with the timestamp
+ * @timestamp: the timestamp that triggered the event
+ * @type: Type of event that signaled the callback
*
* Release a genlock lock following the expiration of a timestamp
*/
static void kgsl_genlock_event_cb(struct kgsl_device *device,
- void *priv, u32 context_id, u32 timestamp)
+ void *priv, u32 context_id, u32 timestamp, u32 type)
{
struct kgsl_genlock_event_priv *ev = priv;
int ret;
+ /* Signal the lock for every event type */
ret = genlock_lock(ev->handle, GENLOCK_UNLOCK, 0, 0);
if (ret)
KGSL_CORE_ERR("Error while unlocking genlock: %d\n", ret);
@@ -3418,6 +3454,8 @@
device->id, device->reg_phys, device->reg_len,
device->reg_virt);
+ rwlock_init(&device->context_lock);
+
result = kgsl_drm_init(pdev);
if (result)
goto error_pwrctrl_close;
@@ -3480,7 +3518,7 @@
/* For a manual dump, make sure that the system is idle */
if (manual) {
- kgsl_active_count_wait(device);
+ kgsl_active_count_wait(device, 0);
if (device->state == KGSL_STATE_ACTIVE)
kgsl_idle(device);
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index d05d391..8d390a9 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -218,16 +218,16 @@
void kgsl_get_memory_usage(char *str, size_t len, unsigned int memflags);
-int kgsl_add_event(struct kgsl_device *device, u32 id, u32 ts,
- void (*cb)(struct kgsl_device *, void *, u32, u32), void *priv,
- void *owner);
+void kgsl_signal_event(struct kgsl_device *device,
+ struct kgsl_context *context, unsigned int timestamp,
+ unsigned int type);
+
+void kgsl_signal_events(struct kgsl_device *device,
+ struct kgsl_context *context, unsigned int type);
void kgsl_cancel_events(struct kgsl_device *device,
void *owner);
-void kgsl_cancel_events_ctxt(struct kgsl_device *device,
- struct kgsl_context *context);
-
extern const struct dev_pm_ops kgsl_pm_ops;
int kgsl_suspend_driver(struct platform_device *pdev, pm_message_t state);
diff --git a/drivers/gpu/msm/kgsl_cffdump.c b/drivers/gpu/msm/kgsl_cffdump.c
index b07a1cad..43bcc30 100644
--- a/drivers/gpu/msm/kgsl_cffdump.c
+++ b/drivers/gpu/msm/kgsl_cffdump.c
@@ -410,29 +410,19 @@
cffdump_printline(-1, cff_opcode, op1, op2, op3, op4, op5);
}
-void kgsl_cffdump_syncmem(struct kgsl_device_private *dev_priv,
- struct kgsl_memdesc *memdesc, uint gpuaddr, uint sizebytes,
- bool clean_cache)
+void kgsl_cffdump_syncmem(struct kgsl_device *device,
+ struct kgsl_memdesc *memdesc, uint gpuaddr,
+ uint sizebytes, bool clean_cache)
{
- struct kgsl_device *device = dev_priv->device;
const void *src;
if (!device->cff_dump_enable)
return;
+ BUG_ON(memdesc == NULL);
+
total_syncmem += sizebytes;
- if (memdesc == NULL) {
- struct kgsl_mem_entry *entry;
- entry = kgsl_sharedmem_find_region(dev_priv->process_priv,
- gpuaddr, sizebytes);
- if (entry == NULL) {
- KGSL_CORE_ERR("did not find mapping "
- "for gpuaddr: 0x%08x\n", gpuaddr);
- return;
- }
- memdesc = &entry->memdesc;
- }
src = (uint *)kgsl_gpuaddr_to_vaddr(memdesc, gpuaddr);
if (memdesc->hostptr == NULL) {
KGSL_CORE_ERR(
diff --git a/drivers/gpu/msm/kgsl_cffdump.h b/drivers/gpu/msm/kgsl_cffdump.h
index 641348e..2852e0f 100644
--- a/drivers/gpu/msm/kgsl_cffdump.h
+++ b/drivers/gpu/msm/kgsl_cffdump.h
@@ -14,19 +14,21 @@
#ifndef __KGSL_CFFDUMP_H
#define __KGSL_CFFDUMP_H
-extern unsigned int kgsl_cff_dump_enable;
-
-#ifdef CONFIG_MSM_KGSL_CFF_DUMP
-
#include <linux/types.h>
-#include "kgsl_device.h"
+extern unsigned int kgsl_cff_dump_enable;
+
+static inline bool kgsl_cffdump_flags_no_memzero(void) { return true; }
+
+struct kgsl_device_private;
+
+#ifdef CONFIG_MSM_KGSL_CFF_DUMP
void kgsl_cffdump_init(void);
void kgsl_cffdump_destroy(void);
void kgsl_cffdump_open(struct kgsl_device *device);
void kgsl_cffdump_close(struct kgsl_device *device);
-void kgsl_cffdump_syncmem(struct kgsl_device_private *dev_priv,
+void kgsl_cffdump_syncmem(struct kgsl_device *,
struct kgsl_memdesc *memdesc, uint physaddr, uint sizebytes,
bool clean_cache);
void kgsl_cffdump_setmem(struct kgsl_device *device, uint addr,
@@ -42,7 +44,6 @@
unsigned int cff_opcode, unsigned int op1,
unsigned int op2, unsigned int op3,
unsigned int op4, unsigned int op5);
-static inline bool kgsl_cffdump_flags_no_memzero(void) { return true; }
void kgsl_cffdump_memory_base(struct kgsl_device *device, unsigned int base,
unsigned int range, unsigned int gmemsize);
@@ -53,20 +54,69 @@
#else
-#define kgsl_cffdump_init() (void)0
-#define kgsl_cffdump_destroy() (void)0
-#define kgsl_cffdump_open(device) (void)0
-#define kgsl_cffdump_close(device) (void)0
-#define kgsl_cffdump_syncmem(dev_priv, memdesc, addr, sizebytes, clean_cache) \
- (void) 0
-#define kgsl_cffdump_setmem(device, addr, value, sizebytes) (void)0
-#define kgsl_cffdump_regwrite(device, addr, value) (void)0
-#define kgsl_cffdump_regpoll(device, addr, value, mask) (void)0
-#define kgsl_cffdump_parse_ibs(dev_priv, memdesc, gpuaddr, \
- sizedwords, check_only) true
-#define kgsl_cffdump_flags_no_memzero() true
-#define kgsl_cffdump_memory_base(davice, base, range, gmemsize) (void)0
-#define kgsl_cffdump_hang(device) (void)0
+static inline void kgsl_cffdump_init(void)
+{
+ return;
+}
+
+static inline void kgsl_cffdump_destroy(void)
+{
+ return;
+}
+
+static inline void kgsl_cffdump_open(struct kgsl_device *device)
+{
+ return;
+}
+
+static inline void kgsl_cffdump_close(struct kgsl_device *device)
+{
+ return;
+}
+
+static inline void kgsl_cffdump_syncmem(struct kgsl_device *device,
+ struct kgsl_memdesc *memdesc, uint physaddr, uint sizebytes,
+ bool clean_cache)
+{
+ return;
+}
+
+static inline void kgsl_cffdump_setmem(struct kgsl_device *device, uint addr,
+ uint value, uint sizebytes)
+{
+ return;
+}
+
+static inline void kgsl_cffdump_regwrite(struct kgsl_device *device, uint addr,
+ uint value)
+{
+ return;
+}
+
+static inline void kgsl_cffdump_regpoll(struct kgsl_device *device, uint addr,
+ uint value, uint mask)
+{
+ return;
+}
+
+static inline bool kgsl_cffdump_parse_ibs(struct kgsl_device_private *dev_priv,
+ const struct kgsl_memdesc *memdesc, uint gpuaddr, int sizedwords,
+ bool check_only)
+{
+ return false;
+}
+
+static inline void kgsl_cffdump_memory_base(struct kgsl_device *device,
+ unsigned int base, unsigned int range, unsigned int gmemsize)
+{
+ return;
+}
+
+static inline void kgsl_cffdump_hang(struct kgsl_device *device)
+{
+ return;
+}
+
static inline void kgsl_cffdump_user_event(struct kgsl_device *device,
unsigned int cff_opcode, unsigned int op1,
unsigned int op2, unsigned int op3,
diff --git a/drivers/gpu/msm/kgsl_debugfs.c b/drivers/gpu/msm/kgsl_debugfs.c
index 9dfda32..9ab8d22 100644
--- a/drivers/gpu/msm/kgsl_debugfs.c
+++ b/drivers/gpu/msm/kgsl_debugfs.c
@@ -296,20 +296,17 @@
print_mem_entry(s, entry);
}
- spin_unlock(&private->mem_lock);
/* now print all the unbound entries */
while (1) {
- rcu_read_lock();
entry = idr_get_next(&private->mem_idr, &next);
- rcu_read_unlock();
-
if (entry == NULL)
break;
if (entry->memdesc.gpuaddr == 0)
print_mem_entry(s, entry);
next++;
}
+ spin_unlock(&private->mem_lock);
return 0;
}
@@ -326,16 +323,53 @@
.release = single_release,
};
-void
+
+/**
+ * kgsl_process_init_debugfs() - Initialize debugfs for a process
+ * @private: Pointer to process private structure created for the process
+ *
+ * @returns: 0 on success, error code otherwise
+ *
+ * kgsl_process_init_debugfs() is called at the time of creating the
+ * process struct when a process opens kgsl device for the first time.
+ * The function creates the debugfs files for the process. If debugfs is
+ * disabled in the kernel, we ignore that error and return as successful.
+ */
+int
kgsl_process_init_debugfs(struct kgsl_process_private *private)
{
unsigned char name[16];
+ int ret = 0;
+ struct dentry *dentry;
snprintf(name, sizeof(name), "%d", private->pid);
private->debug_root = debugfs_create_dir(name, proc_d_debugfs);
- debugfs_create_file("mem", 0400, private->debug_root, private,
+
+ if (!private->debug_root)
+ return -EINVAL;
+
+ /*
+ * debugfs_create_dir() and debugfs_create_file() both
+ * return -ENODEV if debugfs is disabled in the kernel.
+ * We make a distinction between these two functions
+ * failing and debugfs being disabled in the kernel.
+ * In the first case, we abort process private struct
+ * creation, in the second we continue without any changes.
+ * So if debugfs is disabled in kernel, return as
+ * success.
+ */
+ dentry = debugfs_create_file("mem", 0400, private->debug_root, private,
&process_mem_fops);
+
+ if (IS_ERR(dentry)) {
+ ret = PTR_ERR(dentry);
+
+ if (ret == -ENODEV)
+ ret = 0;
+ }
+
+ return ret;
}
void kgsl_core_debugfs_init(void)
diff --git a/drivers/gpu/msm/kgsl_debugfs.h b/drivers/gpu/msm/kgsl_debugfs.h
index ae5601f..b2f137c 100644
--- a/drivers/gpu/msm/kgsl_debugfs.h
+++ b/drivers/gpu/msm/kgsl_debugfs.h
@@ -21,7 +21,7 @@
void kgsl_core_debugfs_init(void);
void kgsl_core_debugfs_close(void);
-void kgsl_device_debugfs_init(struct kgsl_device *device);
+int kgsl_device_debugfs_init(struct kgsl_device *device);
extern struct dentry *kgsl_debugfs_dir;
static inline struct dentry *kgsl_get_debugfs_dir(void)
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 2af5ccd..09a31c9 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -15,6 +15,7 @@
#include <linux/idr.h>
#include <linux/pm_qos.h>
+#include <linux/sched.h>
#include "kgsl.h"
#include "kgsl_mmu.h"
@@ -53,6 +54,22 @@
#define KGSL_IS_PAGE_ALIGNED(addr) (!((addr) & (~PAGE_MASK)))
+/*
+ * KGSL event types - these are passed to the event callback when the event
+ * expires or is cancelled
+ */
+
+#define KGSL_EVENT_TIMESTAMP_RETIRED 0
+#define KGSL_EVENT_CANCELLED 1
+
+/*
+ * "list" of event types for ftrace symbolic magic
+ */
+
+#define KGSL_EVENT_TYPES \
+ { KGSL_EVENT_TIMESTAMP_RETIRED, "retired" }, \
+ { KGSL_EVENT_CANCELLED, "cancelled" }
+
struct kgsl_device;
struct platform_device;
struct kgsl_device_private;
@@ -103,11 +120,10 @@
calling the hook */
void (*setstate) (struct kgsl_device *device, unsigned int context_id,
uint32_t flags);
- int (*drawctxt_create) (struct kgsl_device *device,
- struct kgsl_pagetable *pagetable, struct kgsl_context *context,
- uint32_t *flags);
- void (*drawctxt_destroy) (struct kgsl_device *device,
- struct kgsl_context *context);
+ struct kgsl_context *(*drawctxt_create) (struct kgsl_device_private *,
+ uint32_t *flags);
+ void (*drawctxt_detach) (struct kgsl_context *context);
+ void (*drawctxt_destroy) (struct kgsl_context *context);
long (*ioctl) (struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data);
int (*setproperty) (struct kgsl_device *device,
@@ -127,10 +143,12 @@
int mpu_range;
};
+typedef void (*kgsl_event_func)(struct kgsl_device *, void *, u32, u32, u32);
+
struct kgsl_event {
struct kgsl_context *context;
uint32_t timestamp;
- void (*func)(struct kgsl_device *, void *, u32, u32);
+ kgsl_event_func func;
void *priv;
struct list_head list;
void *owner;
@@ -183,14 +201,15 @@
uint32_t requested_state;
atomic_t active_cnt;
- struct completion suspend_gate;
wait_queue_head_t wait_queue;
+ wait_queue_head_t active_cnt_wq;
struct workqueue_struct *work_queue;
struct device *parentdev;
struct completion ft_gate;
struct dentry *d_debugfs;
struct idr context_idr;
+ rwlock_t context_lock;
void *snapshot; /* Pointer to the snapshot memory region */
int snapshot_maxsize; /* Max size of the snapshot region */
@@ -235,7 +254,6 @@
#define KGSL_DEVICE_COMMON_INIT(_dev) \
.hwaccess_gate = COMPLETION_INITIALIZER((_dev).hwaccess_gate),\
- .suspend_gate = COMPLETION_INITIALIZER((_dev).suspend_gate),\
.ft_gate = COMPLETION_INITIALIZER((_dev).ft_gate),\
.idle_check_ws = __WORK_INITIALIZER((_dev).idle_check_ws,\
kgsl_idle_check),\
@@ -247,37 +265,54 @@
.events = LIST_HEAD_INIT((_dev).events),\
.events_pending_list = LIST_HEAD_INIT((_dev).events_pending_list), \
.wait_queue = __WAIT_QUEUE_HEAD_INITIALIZER((_dev).wait_queue),\
+ .active_cnt_wq = __WAIT_QUEUE_HEAD_INITIALIZER((_dev).active_cnt_wq),\
.mutex = __MUTEX_INITIALIZER((_dev).mutex),\
.state = KGSL_STATE_INIT,\
.ver_major = DRIVER_VERSION_MAJOR,\
.ver_minor = DRIVER_VERSION_MINOR
+/* bits for struct kgsl_context.priv */
+/* the context has been destroyed by userspace and is no longer using the gpu */
+#define KGSL_CONTEXT_DETACHED 0
+/* the context has caused a pagefault */
+#define KGSL_CONTEXT_PAGEFAULT 1
+
/**
* struct kgsl_context - Master structure for a KGSL context object
- * @refcount - kref object for reference counting the context
- * @id - integer identifier for the context
- * @dev_priv - pointer to the owning device instance
- * @devctxt - pointer to the device specific context information
- * @reset_status - status indication whether a gpu reset occured and whether
+ * @refcount: kref object for reference counting the context
+ * @id: integer identifier for the context
+ * @priv: in-kernel context flags, use KGSL_CONTEXT_* values
+ * @dev_priv: pointer to the owning device instance
+ * @reset_status: status indication whether a gpu reset occured and whether
* this context was responsible for causing it
- * @wait_on_invalid_ts - flag indicating if this context has tried to wait on a
+ * @wait_on_invalid_ts: flag indicating if this context has tried to wait on a
* bad timestamp
- * @timeline - sync timeline used to create fences that can be signaled when a
+ * @timeline: sync timeline used to create fences that can be signaled when a
* sync_pt timestamp expires
- * @events - list head of pending events for this context
- * @events_list - list node for the list of all contexts that have pending events
+ * @events: list head of pending events for this context
+ * @events_list: list node for the list of all contexts that have pending events
+ * @pid: process that owns this context.
+ * @tid: task that created this context.
+ * @pagefault: flag set if this context caused a pagefault.
+ * @pagefault_ts: global timestamp of the pagefault, if KGSL_CONTEXT_PAGEFAULT
+ * is set.
*/
struct kgsl_context {
struct kref refcount;
uint32_t id;
+ pid_t pid;
+ pid_t tid;
struct kgsl_device_private *dev_priv;
- void *devctxt;
+ unsigned long priv;
+ struct kgsl_device *device;
+ struct kgsl_pagetable *pagetable;
unsigned int reset_status;
bool wait_on_invalid_ts;
struct sync_timeline *timeline;
struct list_head events;
struct list_head events_list;
+ unsigned int pagefault_ts;
};
struct kgsl_process_private {
@@ -315,6 +350,9 @@
struct kgsl_device *kgsl_get_device(int dev_idx);
+int kgsl_add_event(struct kgsl_device *device, u32 id, u32 ts,
+ kgsl_event_func func, void *priv, void *owner);
+
static inline void kgsl_process_add_stats(struct kgsl_process_private *priv,
unsigned int type, size_t size)
{
@@ -402,17 +440,7 @@
return 0;
}
-static inline struct kgsl_context *
-kgsl_find_context(struct kgsl_device_private *dev_priv, uint32_t id)
-{
- struct kgsl_context *ctxt =
- idr_find(&dev_priv->device->context_idr, id);
- /* Make sure that the context belongs to the current instance so
- that other processes can't guess context IDs and mess things up */
-
- return (ctxt && ctxt->dev_priv == dev_priv) ? ctxt : NULL;
-}
int kgsl_check_timestamp(struct kgsl_device *device,
struct kgsl_context *context, unsigned int timestamp);
@@ -436,32 +464,137 @@
return pdev->dev.platform_data;
}
-/**
- * kgsl_context_get - Get context reference count
- * @context
- *
- * Asynchronous code that holds a pointer to a context
- * must hold a reference count on it. The kgsl device
- * mutex must be held while the context reference count
- * is changed.
- */
-static inline void
-kgsl_context_get(struct kgsl_context *context)
-{
- kref_get(&context->refcount);
-}
-
void kgsl_context_destroy(struct kref *kref);
+int kgsl_context_init(struct kgsl_device_private *, struct kgsl_context
+ *context);
+
/**
- * kgsl_context_put - Release context reference count
- * @context
+ * kgsl_context_put() - Release context reference count
+ * @context: Pointer to the KGSL context to be released
*
+ * Reduce the reference count on a KGSL context and destroy it if it is no
+ * longer needed
*/
static inline void
kgsl_context_put(struct kgsl_context *context)
{
- kref_put(&context->refcount, kgsl_context_destroy);
+ if (context)
+ kref_put(&context->refcount, kgsl_context_destroy);
}
+/**
+ * kgsl_context_detached() - check if a context is detached
+ * @context: the context
+ *
+ * Check if a context has been destroyed by userspace and is only waiting
+ * for reference counts to go away. This check is used to weed out
+ * contexts that shouldn't use the gpu so NULL is considered detached.
+ */
+static inline bool kgsl_context_detached(struct kgsl_context *context)
+{
+ return (context == NULL || test_bit(KGSL_CONTEXT_DETACHED,
+ &context->priv));
+}
+
+
+/**
+ * kgsl_context_get() - get a pointer to a KGSL context
+ * @device: Pointer to the KGSL device that owns the context
+ * @id: Context ID
+ *
+ * Find the context associated with the given ID number, increase the reference
+ * count on it and return it. The caller must make sure that this call is
+ * paired with a kgsl_context_put. This function is for internal use because it
+ * doesn't validate the ownership of the context with the calling process - use
+ * kgsl_context_get_owner for that
+ */
+static inline struct kgsl_context *kgsl_context_get(struct kgsl_device *device,
+ uint32_t id)
+{
+ struct kgsl_context *context = NULL;
+
+ read_lock(&device->context_lock);
+
+ context = idr_find(&device->context_idr, id);
+
+ /* Don't return a context that has been detached */
+ if (kgsl_context_detached(context))
+ context = NULL;
+ else
+ kref_get(&context->refcount);
+
+ read_unlock(&device->context_lock);
+
+ return context;
+}
+
+/**
+* _kgsl_context_get() - lightweight function to just increment the ref count
+* @context: Pointer to the KGSL context
+*
+* Get a reference to the specified KGSL context structure. This is a
+* lightweight way to just increase the refcount on a known context rather than
+* walking through kgsl_context_get and searching the iterator
+*/
+static inline void _kgsl_context_get(struct kgsl_context *context)
+{
+ if (context)
+ kref_get(&context->refcount);
+}
+
+/**
+ * kgsl_context_get_owner() - get a pointer to a KGSL context in a specific
+ * process
+ * @dev_priv: Pointer to the process struct
+ * @id: Context ID to return
+ *
+ * Find the context associated with the given ID number, increase the reference
+ * count on it and return it. The caller must make sure that this call is
+ * paired with a kgsl_context_put. This function validates that the context id
+ * given is owned by the dev_priv instancet that is passed in. See
+ * kgsl_context_get for the internal version that doesn't do the check
+ */
+static inline struct kgsl_context *kgsl_context_get_owner(
+ struct kgsl_device_private *dev_priv, uint32_t id)
+{
+ struct kgsl_context *context;
+
+ context = kgsl_context_get(dev_priv->device, id);
+
+ /* Verify that the context belongs to current calling process. */
+ if (context != NULL && context->pid != dev_priv->process_priv->pid) {
+ kgsl_context_put(context);
+ return NULL;
+ }
+
+ return context;
+}
+
+/**
+ * kgsl_context_cancel_events() - Cancel all events for a context
+ * @device: Pointer to the KGSL device structure for the GPU
+ * @context: Pointer to the KGSL context
+ *
+ * Signal all pending events on the context with KGSL_EVENT_CANCELLED
+ */
+static inline void kgsl_context_cancel_events(struct kgsl_device *device,
+ struct kgsl_context *context)
+{
+ kgsl_signal_events(device, context, KGSL_EVENT_CANCELLED);
+}
+
+/**
+ * kgsl_context_cancel_events_timestamp() - cancel events for a given timestamp
+ * @device: Pointer to the KGSL device that owns the context
+ * @context: Pointer to the context that owns the event or NULL for global
+ * @timestamp: Timestamp to cancel events for
+ *
+ * Cancel events pending for a specific timestamp
+ */
+static inline void kgsl_cancel_events_timestamp(struct kgsl_device *device,
+ struct kgsl_context *context, unsigned int timestamp)
+{
+ kgsl_signal_event(device, context, timestamp, KGSL_EVENT_CANCELLED);
+}
#endif /* __KGSL_DEVICE_H */
diff --git a/drivers/gpu/msm/kgsl_drm.c b/drivers/gpu/msm/kgsl_drm.c
index 1fc7467..c221c4a 100644
--- a/drivers/gpu/msm/kgsl_drm.c
+++ b/drivers/gpu/msm/kgsl_drm.c
@@ -385,6 +385,7 @@
kgsl_gem_free_memory(obj);
drm_gem_object_release(obj);
kfree(obj->driver_private);
+ kfree(obj);
}
int
diff --git a/drivers/gpu/msm/kgsl_events.c b/drivers/gpu/msm/kgsl_events.c
index a1fc5a2..e4f502a 100644
--- a/drivers/gpu/msm/kgsl_events.c
+++ b/drivers/gpu/msm/kgsl_events.c
@@ -18,6 +18,12 @@
#include "kgsl_trace.h"
+static inline struct list_head *_get_list_head(struct kgsl_device *device,
+ struct kgsl_context *context)
+{
+ return (context) ? &context->events : &device->events;
+}
+
static void _add_event_to_list(struct list_head *head, struct kgsl_event *event)
{
struct list_head *n;
@@ -36,31 +42,186 @@
list_add_tail(&event->list, head);
}
+static inline void _do_signal_event(struct kgsl_device *device,
+ struct kgsl_event *event, unsigned int timestamp,
+ unsigned int type)
+{
+ int id = event->context ? event->context->id : KGSL_MEMSTORE_GLOBAL;
+
+ trace_kgsl_fire_event(id, timestamp, type, jiffies - event->created);
+
+ if (event->func)
+ event->func(device, event->priv, id, timestamp, type);
+
+ list_del(&event->list);
+ kgsl_context_put(event->context);
+ kfree(event);
+
+ kgsl_active_count_put(device);
+}
+
+static void _retire_events(struct kgsl_device *device,
+ struct list_head *head, unsigned int timestamp)
+{
+ struct kgsl_event *event, *tmp;
+
+ list_for_each_entry_safe(event, tmp, head, list) {
+ if (timestamp_cmp(timestamp, event->timestamp) < 0)
+ break;
+
+ _do_signal_event(device, event, event->timestamp,
+ KGSL_EVENT_TIMESTAMP_RETIRED);
+ }
+}
+
+static struct kgsl_event *_find_event(struct kgsl_device *device,
+ struct list_head *head, unsigned int timestamp,
+ kgsl_event_func func, void *priv)
+{
+ struct kgsl_event *event, *tmp;
+
+ list_for_each_entry_safe(event, tmp, head, list) {
+ if (timestamp == event->timestamp && func == event->func &&
+ event->priv == priv)
+ return event;
+ }
+
+ return NULL;
+}
+
+/**
+ * _signal_event() - send a signal to a specific event in the list
+ * @device: Pointer to the KGSL device struct
+ * @head: Pointer to the event list to process
+ * @timestamp: timestamp of the event to signal
+ * @cur: timestamp value to send to the callback
+ * @type: Signal ID to send to the callback
+ *
+ * Send the specified signal to the events in the list with the specified
+ * timestamp. The timestamp 'cur' is sent to the callback so it knows
+ * when the signal was delivered
+ */
+static void _signal_event(struct kgsl_device *device,
+ struct list_head *head, unsigned int timestamp,
+ unsigned int cur, unsigned int type)
+{
+ struct kgsl_event *event, *tmp;
+
+ list_for_each_entry_safe(event, tmp, head, list) {
+ if (timestamp_cmp(timestamp, event->timestamp) == 0)
+ _do_signal_event(device, event, cur, type);
+ }
+}
+
+/**
+ * _signal_events() - send a signal to all the events in a list
+ * @device: Pointer to the KGSL device struct
+ * @head: Pointer to the event list to process
+ * @timestamp: Timestamp to pass to the events (this should be the current
+ * timestamp when the signal is sent)
+ * @type: Signal ID to send to the callback
+ *
+ * Send the specified signal to all the events in the list and destroy them
+ */
+static void _signal_events(struct kgsl_device *device,
+ struct list_head *head, uint32_t timestamp,
+ unsigned int type)
+{
+ struct kgsl_event *event, *tmp;
+
+ list_for_each_entry_safe(event, tmp, head, list)
+ _do_signal_event(device, event, timestamp, type);
+
+}
+
+/**
+ * kgsl_signal_event() - send a signal to a specific event in the context
+ * @device: Pointer to the KGSL device struct
+ * @context: Pointer to the KGSL context
+ * @timestamp: Timestamp of the event to signal
+ * @type: Signal ID to send to the callback
+ *
+ * Send the specified signal to all the events in the context with the given
+ * timestamp
+ */
+void kgsl_signal_event(struct kgsl_device *device,
+ struct kgsl_context *context, unsigned int timestamp,
+ unsigned int type)
+{
+ struct list_head *head = _get_list_head(device, context);
+ uint32_t cur;
+
+ BUG_ON(!mutex_is_locked(&device->mutex));
+
+ cur = kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_RETIRED);
+ _signal_event(device, head, timestamp, cur, type);
+
+ if (context && list_empty(&context->events))
+ list_del_init(&context->events_list);
+}
+EXPORT_SYMBOL(kgsl_signal_event);
+
+/**
+ * kgsl_signal_events() - send a signal to all events in the context
+ * @device: Pointer to the KGSL device struct
+ * @context: Pointer to the KGSL context
+ * @type: Signal ID to send to the callback function
+ *
+ * Send the specified signal to all the events in the context
+ */
+void kgsl_signal_events(struct kgsl_device *device,
+ struct kgsl_context *context, unsigned int type)
+{
+ struct list_head *head = _get_list_head(device, context);
+ uint32_t cur;
+
+ BUG_ON(!mutex_is_locked(&device->mutex));
+
+ /*
+ * Send the current timestamp to the callback so it knows when the
+ * signal occured
+ */
+
+ cur = kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_RETIRED);
+
+ _signal_events(device, head, cur, type);
+
+ /*
+ * Remove the context from the master list since we know everything on
+ * it has been removed
+ */
+
+ if (context)
+ list_del_init(&context->events_list);
+}
+EXPORT_SYMBOL(kgsl_signal_events);
+
/**
* kgsl_add_event - Add a new timstamp event for the KGSL device
* @device - KGSL device for the new event
* @id - the context ID that the event should be added to
* @ts - the timestamp to trigger the event on
- * @cb - callback function to call when the timestamp expires
+ * @func - callback function to call when the timestamp expires
* @priv - private data for the specific event type
* @owner - driver instance that owns this event
*
* @returns - 0 on success or error code on failure
*/
int kgsl_add_event(struct kgsl_device *device, u32 id, u32 ts,
- void (*cb)(struct kgsl_device *, void *, u32, u32), void *priv,
- void *owner)
+ kgsl_event_func func, void *priv, void *owner)
{
int ret;
struct kgsl_event *event;
unsigned int cur_ts;
struct kgsl_context *context = NULL;
- if (cb == NULL)
+ BUG_ON(!mutex_is_locked(&device->mutex));
+
+ if (func == NULL)
return -EINVAL;
if (id != KGSL_MEMSTORE_GLOBAL) {
- context = idr_find(&device->context_idr, id);
+ context = kgsl_context_get(device, id);
if (context == NULL)
return -EINVAL;
}
@@ -74,14 +235,18 @@
*/
if (timestamp_cmp(cur_ts, ts) >= 0) {
- trace_kgsl_fire_event(id, ts, 0);
- cb(device, priv, id, ts);
+ trace_kgsl_fire_event(id, cur_ts, ts, 0);
+
+ func(device, priv, id, ts, KGSL_EVENT_TIMESTAMP_RETIRED);
+ kgsl_context_put(context);
return 0;
}
event = kzalloc(sizeof(*event), GFP_KERNEL);
- if (event == NULL)
+ if (event == NULL) {
+ kgsl_context_put(context);
return -ENOMEM;
+ }
/*
* Increase the active count on the device to avoid going into power
@@ -89,6 +254,7 @@
*/
ret = kgsl_active_count_get_light(device);
if (ret < 0) {
+ kgsl_context_put(context);
kfree(event);
return ret;
}
@@ -96,16 +262,12 @@
event->context = context;
event->timestamp = ts;
event->priv = priv;
- event->func = cb;
+ event->func = func;
event->owner = owner;
event->created = jiffies;
trace_kgsl_register_event(id, ts);
- /* inc refcount to avoid race conditions in cleanup */
- if (context)
- kgsl_context_get(context);
-
/* Add the event to either the owning context or the global list */
if (context) {
@@ -129,131 +291,60 @@
EXPORT_SYMBOL(kgsl_add_event);
/**
- * kgsl_cancel_events_ctxt - Cancel all events for a context
- * @device - KGSL device for the events to cancel
- * @context - context whose events we want to cancel
+ * kgsl_cancel_events() - Cancel all global events owned by a process
+ * @device: Pointer to the KGSL device struct
+ * @owner: driver instance that owns the events to cancel
*
+ * Cancel all global events that match the owner pointer
*/
-void kgsl_cancel_events_ctxt(struct kgsl_device *device,
- struct kgsl_context *context)
-{
- struct kgsl_event *event, *event_tmp;
- unsigned int id, cur;
-
- cur = kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_RETIRED);
- id = context->id;
-
- /*
- * Increment the refcount to avoid freeing the context while
- * cancelling its events
- */
- kgsl_context_get(context);
-
- /* Remove ourselves from the master pending list */
- list_del_init(&context->events_list);
-
- list_for_each_entry_safe(event, event_tmp, &context->events, list) {
- /*
- * "cancel" the events by calling their callback.
- * Currently, events are used for lock and memory
- * management, so if the process is dying the right
- * thing to do is release or free.
- *
- * Send the current timestamp so the event knows how far the
- * system got before the event was canceled
- */
- list_del(&event->list);
-
- trace_kgsl_fire_event(id, cur, jiffies - event->created);
-
- if (event->func)
- event->func(device, event->priv, id, cur);
-
- kgsl_context_put(context);
- kfree(event);
-
- kgsl_active_count_put(device);
- }
- kgsl_context_put(context);
-}
-
-/**
- * kgsl_cancel_events - Cancel all generic events for a process
- * @device - KGSL device for the events to cancel
- * @owner - driver instance that owns the events to cancel
- *
- */
-void kgsl_cancel_events(struct kgsl_device *device,
- void *owner)
+void kgsl_cancel_events(struct kgsl_device *device, void *owner)
{
struct kgsl_event *event, *event_tmp;
unsigned int cur;
+ BUG_ON(!mutex_is_locked(&device->mutex));
+
cur = kgsl_readtimestamp(device, NULL, KGSL_TIMESTAMP_RETIRED);
list_for_each_entry_safe(event, event_tmp, &device->events, list) {
if (event->owner != owner)
continue;
- /*
- * "cancel" the events by calling their callback.
- * Currently, events are used for lock and memory
- * management, so if the process is dying the right
- * thing to do is release or free. Send the current timestamp so
- * the callback knows how far the GPU made it before things went
- * explosion
- */
- list_del(&event->list);
-
- trace_kgsl_fire_event(KGSL_MEMSTORE_GLOBAL, cur,
- jiffies - event->created);
-
- if (event->func)
- event->func(device, event->priv, KGSL_MEMSTORE_GLOBAL,
- cur);
-
- if (event->context)
- kgsl_context_put(event->context);
- kfree(event);
-
- kgsl_active_count_put(device);
+ _do_signal_event(device, event, cur, KGSL_EVENT_CANCELLED);
}
}
EXPORT_SYMBOL(kgsl_cancel_events);
-static void _process_event_list(struct kgsl_device *device,
- struct list_head *head, unsigned int timestamp)
+/**
+ * kgsl_cancel_event() - send a cancel signal to a specific event
+ * @device: Pointer to the KGSL device struct
+ * @context: Pointer to the KGSL context
+ * @timestamp: Timestamp of the event to cancel
+ * @func: Callback function of the event - this is used to match the actual
+ * event
+ * @priv: Private data for the callback function - this is used to match to the
+ * actual event
+ *
+ * Send the a cancel signal to a specific event that matches all the parameters
+ */
+
+void kgsl_cancel_event(struct kgsl_device *device, struct kgsl_context *context,
+ unsigned int timestamp, kgsl_event_func func,
+ void *priv)
{
- struct kgsl_event *event, *tmp;
- unsigned int id;
+ struct kgsl_event *event;
+ struct list_head *head = _get_list_head(device, context);
- list_for_each_entry_safe(event, tmp, head, list) {
- if (timestamp_cmp(timestamp, event->timestamp) < 0)
- break;
+ event = _find_event(device, head, timestamp, func, priv);
- id = event->context ? event->context->id : KGSL_MEMSTORE_GLOBAL;
+ if (event) {
+ unsigned int cur = kgsl_readtimestamp(device, context,
+ KGSL_TIMESTAMP_RETIRED);
- /*
- * Send the timestamp of the expired event, not the current
- * timestamp. This prevents the event handlers from getting
- * confused if they don't bother comparing the current timetamp
- * to the timestamp they wanted
- */
- list_del(&event->list);
-
- trace_kgsl_fire_event(id, event->timestamp,
- jiffies - event->created);
-
- if (event->func)
- event->func(device, event->priv, id, event->timestamp);
-
- if (event->context)
- kgsl_context_put(event->context);
- kfree(event);
-
- kgsl_active_count_put(device);
+ _do_signal_event(device, event, cur, KGSL_EVENT_CANCELLED);
}
}
+EXPORT_SYMBOL(kgsl_cancel_event);
static inline int _mark_next_event(struct kgsl_device *device,
struct list_head *head)
@@ -282,7 +373,7 @@
unsigned int timestamp = kgsl_readtimestamp(device, context,
KGSL_TIMESTAMP_RETIRED);
- _process_event_list(device, &context->events, timestamp);
+ _retire_events(device, &context->events, timestamp);
/*
* _mark_next event will return 1 as long as the next event
@@ -313,7 +404,7 @@
/* Process expired global events */
timestamp = kgsl_readtimestamp(device, NULL, KGSL_TIMESTAMP_RETIRED);
- _process_event_list(device, &device->events, timestamp);
+ _retire_events(device, &device->events, timestamp);
_mark_next_event(device, &device->events);
/* Now process all of the pending contexts */
@@ -324,7 +415,7 @@
* Increment the refcount to make sure that the list_del_init
* is called with a valid context's list
*/
- kgsl_context_get(context);
+ _kgsl_context_get(context);
/*
* If kgsl_timestamp_expired_context returns 0 then it no longer
* has any pending events and can be removed from the list
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 9113605..ecda5a7 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -38,6 +38,7 @@
static struct kgsl_iommu_register_list kgsl_iommuv0_reg[KGSL_IOMMU_REG_MAX] = {
{ 0, 0 }, /* GLOBAL_BASE */
+ { 0x0, 1 }, /* SCTLR */
{ 0x10, 1 }, /* TTBR0 */
{ 0x14, 1 }, /* TTBR1 */
{ 0x20, 1 }, /* FSR */
@@ -54,6 +55,7 @@
static struct kgsl_iommu_register_list kgsl_iommuv1_reg[KGSL_IOMMU_REG_MAX] = {
{ 0, 0 }, /* GLOBAL_BASE */
+ { 0x0, 1 }, /* SCTLR */
{ 0x20, 1 }, /* TTBR0 */
{ 0x28, 1 }, /* TTBR1 */
{ 0x58, 1 }, /* FSR */
@@ -61,8 +63,8 @@
{ 0x008, 1 }, /* RESUME */
{ 0, 0 }, /* TLBLKCR not in V1 */
{ 0, 0 }, /* V2PUR not in V1 */
- { 0x68, 0 }, /* FSYNR0 */
- { 0x6C, 0 }, /* FSYNR1 */
+ { 0x68, 1 }, /* FSYNR0 */
+ { 0x6C, 1 }, /* FSYNR1 */
{ 0x7F0, 1 }, /* TLBSYNC */
{ 0x7F4, 1 }, /* TLBSTATUS */
{ 0x2000, 0 } /* IMPLDEF_MICRO_MMU_CRTL */
@@ -325,8 +327,7 @@
unsigned int no_page_fault_log = 0;
unsigned int curr_context_id = 0;
unsigned int curr_global_ts = 0;
- static struct adreno_context *curr_context;
- static struct kgsl_context *context;
+ struct kgsl_context *context;
ret = get_iommu_unit(dev, &mmu, &iommu_unit);
if (ret)
@@ -396,20 +397,20 @@
kgsl_sharedmem_readl(&device->memstore, &curr_context_id,
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, current_context));
- context = idr_find(&device->context_idr, curr_context_id);
- if (context != NULL) {
- curr_context = context->devctxt;
+ context = kgsl_context_get(device, curr_context_id);
+
+ if (context != NULL) {
kgsl_sharedmem_readl(&device->memstore, &curr_global_ts,
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
eoptimestamp));
- /*
- * Store pagefault's timestamp in adreno context,
- * this information will be used in GFT
- */
- curr_context->pagefault = 1;
- curr_context->pagefault_ts = curr_global_ts;
+ /* save pagefault timestamp for GFT */
+ set_bit(KGSL_CONTEXT_PAGEFAULT, &context->priv);
+ context->pagefault_ts = curr_global_ts;
+
+ kgsl_context_put(context);
+ context = NULL;
}
trace_kgsl_mmu_pagefault(iommu_dev->kgsldev, addr,
@@ -471,7 +472,8 @@
* Return - void
*/
static void kgsl_iommu_clk_disable_event(struct kgsl_device *device, void *data,
- unsigned int id, unsigned int ts)
+ unsigned int id, unsigned int ts,
+ u32 type)
{
struct kgsl_mmu *mmu = data;
struct kgsl_iommu *iommu = mmu->priv;
@@ -804,6 +806,7 @@
struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[unit_id];
int i, j;
int found_ctx;
+ int ret = 0;
for (j = 0; j < KGSL_IOMMU_MAX_DEVS_PER_UNIT; j++) {
found_ctx = 0;
@@ -817,16 +820,21 @@
break;
if (!data->iommu_ctxs[i].iommu_ctx_name) {
KGSL_CORE_ERR("Context name invalid\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto done;
}
iommu_unit->dev[iommu_unit->dev_count].dev =
msm_iommu_get_ctx(data->iommu_ctxs[i].iommu_ctx_name);
- if (iommu_unit->dev[iommu_unit->dev_count].dev == NULL) {
- KGSL_CORE_ERR("Failed to get iommu dev handle for "
- "device %s\n", data->iommu_ctxs[i].iommu_ctx_name);
- return -EINVAL;
+ if (NULL == iommu_unit->dev[iommu_unit->dev_count].dev)
+ ret = -EINVAL;
+ if (IS_ERR(iommu_unit->dev[iommu_unit->dev_count].dev)) {
+ ret = PTR_ERR(
+ iommu_unit->dev[iommu_unit->dev_count].dev);
+ iommu_unit->dev[iommu_unit->dev_count].dev = NULL;
}
+ if (ret)
+ goto done;
iommu_unit->dev[iommu_unit->dev_count].ctx_id =
data->iommu_ctxs[i].ctx_id;
iommu_unit->dev[iommu_unit->dev_count].kgsldev = mmu->device;
@@ -838,12 +846,23 @@
iommu_unit->dev_count++;
}
- if (!j) {
- KGSL_CORE_ERR("No ctxts initialized, user ctxt absent\n ");
- return -EINVAL;
+done:
+ if (!iommu_unit->dev_count && !ret)
+ ret = -EINVAL;
+ if (ret) {
+ /*
+ * If at least the first context is initialized on v1
+ * then we can continue
+ */
+ if (!msm_soc_version_supports_iommu_v0() &&
+ iommu_unit->dev_count)
+ ret = 0;
+ else
+ KGSL_CORE_ERR(
+ "Failed to initialize iommu contexts, err: %d\n", ret);
}
- return 0;
+ return ret;
}
/*
@@ -1534,6 +1553,7 @@
KGSL_IOMMU_SET_CTX_REG(iommu, iommu_unit,
iommu_unit->dev[j].ctx_id,
V2PUR, v2pxx);
+ mb();
vaddr += PAGE_SIZE;
for (l = 0; l < iommu_unit->dev_count; l++) {
tlblkcr = KGSL_IOMMU_GET_CTX_REG(iommu,
@@ -1574,6 +1594,8 @@
int status;
struct kgsl_iommu *iommu = mmu->priv;
int i, j;
+ int sctlr_val = 0;
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(mmu->device);
if (mmu->flags & KGSL_FLAGS_STARTED)
return 0;
@@ -1625,6 +1647,25 @@
for (i = 0; i < iommu->unit_count; i++) {
struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
for (j = 0; j < iommu_unit->dev_count; j++) {
+
+ /*
+ * For IOMMU V1 do not halt IOMMU on pagefault if
+ * FT pagefault policy is set accordingly
+ */
+ if ((!msm_soc_version_supports_iommu_v0()) &&
+ (!(adreno_dev->ft_pf_policy &
+ KGSL_FT_PAGEFAULT_GPUHALT_ENABLE))) {
+ sctlr_val = KGSL_IOMMU_GET_CTX_REG(iommu,
+ iommu_unit,
+ iommu_unit->dev[j].ctx_id,
+ SCTLR);
+ sctlr_val |= (0x1 <<
+ KGSL_IOMMU_SCTLR_HUPCF_SHIFT);
+ KGSL_IOMMU_SET_CTX_REG(iommu,
+ iommu_unit,
+ iommu_unit->dev[j].ctx_id,
+ SCTLR, sctlr_val);
+ }
if (sizeof(phys_addr_t) > sizeof(unsigned long)) {
iommu_unit->dev[j].default_ttbr0 =
KGSL_IOMMU_GET_CTX_REG_LL(iommu,
diff --git a/drivers/gpu/msm/kgsl_iommu.h b/drivers/gpu/msm/kgsl_iommu.h
index 5c4b17e..7dca40e 100644
--- a/drivers/gpu/msm/kgsl_iommu.h
+++ b/drivers/gpu/msm/kgsl_iommu.h
@@ -61,8 +61,12 @@
#define KGSL_IOMMU_IMPLDEF_MICRO_MMU_CTRL_HALT BIT(2)
#define KGSL_IOMMU_IMPLDEF_MICRO_MMU_CTRL_IDLE BIT(3)
+/* SCTLR fields */
+#define KGSL_IOMMU_SCTLR_HUPCF_SHIFT 8
+
enum kgsl_iommu_reg_map {
KGSL_IOMMU_GLOBAL_BASE = 0,
+ KGSL_IOMMU_CTX_SCTLR,
KGSL_IOMMU_CTX_TTBR0,
KGSL_IOMMU_CTX_TTBR1,
KGSL_IOMMU_CTX_FSR,
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 91d462b..1a95761 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -79,6 +79,7 @@
static void kgsl_pwrctrl_clk(struct kgsl_device *device, int state,
int requested_state);
static void kgsl_pwrctrl_axi(struct kgsl_device *device, int state);
+static void kgsl_pwrctrl_pwrrail(struct kgsl_device *device, int state);
/* Update the elapsed time at a particular clock level
* if the device is active(on_time = true).Otherwise
@@ -643,6 +644,9 @@
case KGSL_PWRFLAGS_AXI_ON:
kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_ON);
break;
+ case KGSL_PWRFLAGS_POWER_ON:
+ kgsl_pwrctrl_pwrrail(device, KGSL_PWRFLAGS_ON);
+ break;
}
set_bit(flag, &device->pwrctrl.ctrl_flags);
} else {
@@ -713,6 +717,20 @@
return __force_on_store(dev, attr, buf, count, KGSL_PWRFLAGS_AXI_ON);
}
+static int kgsl_pwrctrl_force_rail_on_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return __force_on_show(dev, attr, buf, KGSL_PWRFLAGS_POWER_ON);
+}
+
+static int kgsl_pwrctrl_force_rail_on_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return __force_on_store(dev, attr, buf, count, KGSL_PWRFLAGS_POWER_ON);
+}
+
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);
@@ -749,6 +767,9 @@
DEVICE_ATTR(force_bus_on, 0644,
kgsl_pwrctrl_force_bus_on_show,
kgsl_pwrctrl_force_bus_on_store);
+DEVICE_ATTR(force_rail_on, 0644,
+ kgsl_pwrctrl_force_rail_on_show,
+ kgsl_pwrctrl_force_rail_on_store);
static const struct device_attribute *pwrctrl_attr_list[] = {
&dev_attr_gpuclk,
@@ -765,6 +786,7 @@
&dev_attr_reset_count,
&dev_attr_force_clk_on,
&dev_attr_force_bus_on,
+ &dev_attr_force_rail_on,
NULL
};
@@ -917,6 +939,9 @@
{
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+ if (test_bit(KGSL_PWRFLAGS_POWER_ON, &pwr->ctrl_flags))
+ return;
+
if (state == KGSL_PWRFLAGS_OFF) {
if (test_and_clear_bit(KGSL_PWRFLAGS_POWER_ON,
&pwr->power_flags)) {
@@ -1214,6 +1239,11 @@
}
}
+bool kgsl_pwrctrl_isenabled(struct kgsl_device *device)
+{
+ struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+ return (test_bit(KGSL_PWRFLAGS_CLK_ON, &pwr->power_flags) != 0);
+}
/**
* kgsl_pre_hwaccess - Enforce preconditions for touching registers
@@ -1230,7 +1260,7 @@
/* In order to touch a register you must hold the device mutex...*/
BUG_ON(!mutex_is_locked(&device->mutex));
/* and have the clock on! */
- BUG_ON(!test_bit(KGSL_PWRFLAGS_CLK_ON, &device->pwrctrl.power_flags));
+ BUG_ON(!kgsl_pwrctrl_isenabled(device));
}
EXPORT_SYMBOL(kgsl_pre_hwaccess);
@@ -1389,13 +1419,14 @@
(unsigned int *) &context_id,
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
current_context));
- context = idr_find(&device->context_idr, context_id);
+ context = kgsl_context_get(device, context_id);
if (context)
ts_processed = kgsl_readtimestamp(device, context,
KGSL_TIMESTAMP_RETIRED);
KGSL_PWR_INFO(device, "Wake from %s state. CTXT: %d RTRD TS: %08X\n",
kgsl_pwrstate_to_str(state),
context ? context->id : -1, ts_processed);
+ kgsl_context_put(context);
/* fall through */
case KGSL_STATE_NAP:
/* Turn on the core clocks */
@@ -1564,8 +1595,6 @@
kgsl_pwrscale_idle(device);
if (atomic_dec_and_test(&device->active_cnt)) {
- INIT_COMPLETION(device->suspend_gate);
-
if (device->state == KGSL_STATE_ACTIVE &&
device->requested_state == KGSL_STATE_NONE) {
kgsl_pwrctrl_request_state(device, KGSL_STATE_NAP);
@@ -1574,29 +1603,41 @@
mod_timer(&device->idle_timer,
jiffies + device->pwrctrl.interval_timeout);
-
- complete(&device->suspend_gate);
}
trace_kgsl_active_count(device,
(unsigned long) __builtin_return_address(0));
+
+ wake_up(&device->active_cnt_wq);
}
EXPORT_SYMBOL(kgsl_active_count_put);
+static int _check_active_count(struct kgsl_device *device, int count)
+{
+ /* Return 0 if the active count is greater than the desired value */
+ return atomic_read(&device->active_cnt) > count ? 0 : 1;
+}
+
/**
* kgsl_active_count_wait() - Wait for activity to finish.
* @device: Pointer to a KGSL device
+ * @count: Active count value to wait for
*
- * Block until all active_cnt users put() their reference.
+ * Block until the active_cnt value hits the desired value
*/
-void kgsl_active_count_wait(struct kgsl_device *device)
+int kgsl_active_count_wait(struct kgsl_device *device, int count)
{
+ int ret = 0;
+
BUG_ON(!mutex_is_locked(&device->mutex));
- if (atomic_read(&device->active_cnt) != 0) {
+ if (atomic_read(&device->active_cnt) > count) {
mutex_unlock(&device->mutex);
- wait_for_completion(&device->suspend_gate);
+ ret = wait_event_timeout(device->active_cnt_wq,
+ _check_active_count(device, count), HZ);
mutex_lock(&device->mutex);
}
+
+ return ret == 0 ? -ETIMEDOUT : 0;
}
EXPORT_SYMBOL(kgsl_active_count_wait);
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index 3bf65ee..71a0fdd 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -110,6 +110,8 @@
void kgsl_pwrctrl_uninit_sysfs(struct kgsl_device *device);
void kgsl_pwrctrl_enable(struct kgsl_device *device);
void kgsl_pwrctrl_disable(struct kgsl_device *device);
+bool kgsl_pwrctrl_isenabled(struct kgsl_device *device);
+
static inline unsigned long kgsl_get_clkrate(struct clk *clk)
{
return (clk != NULL) ? clk_get_rate(clk) : 0;
@@ -121,6 +123,6 @@
int kgsl_active_count_get(struct kgsl_device *device);
int kgsl_active_count_get_light(struct kgsl_device *device);
void kgsl_active_count_put(struct kgsl_device *device);
-void kgsl_active_count_wait(struct kgsl_device *device);
+int kgsl_active_count_wait(struct kgsl_device *device, int count);
#endif /* __KGSL_PWRCTRL_H */
diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c
index e5e23f0..47554c4 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.c
+++ b/drivers/gpu/msm/kgsl_pwrscale.c
@@ -48,9 +48,6 @@
#ifdef CONFIG_MSM_SLEEP_STATS_DEVICE
&kgsl_pwrscale_policy_idlestats,
#endif
-#ifdef CONFIG_MSM_DCVS
- &kgsl_pwrscale_policy_msm,
-#endif
NULL
};
diff --git a/drivers/gpu/msm/kgsl_pwrscale_msm.c b/drivers/gpu/msm/kgsl_pwrscale_msm.c
deleted file mode 100644
index 073e474..0000000
--- a/drivers/gpu/msm/kgsl_pwrscale_msm.c
+++ /dev/null
@@ -1,269 +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 <linux/slab.h>
-#include <mach/msm_dcvs.h>
-#include "kgsl.h"
-#include "kgsl_pwrscale.h"
-#include "kgsl_device.h"
-#include "a2xx_reg.h"
-#include "kgsl_trace.h"
-
-struct msm_priv {
- struct kgsl_device *device;
- int enabled;
- unsigned int cur_freq;
- unsigned int req_level;
- int floor_level;
- struct msm_dcvs_core_info *core_info;
- int gpu_busy;
- int dcvs_core_id;
-};
-
-/* reference to be used in idle and freq callbacks */
-static struct msm_priv *the_msm_priv;
-
-static int msm_idle_enable(int type_core_num,
- enum msm_core_control_event event)
-{
- struct msm_priv *priv = the_msm_priv;
-
- switch (event) {
- case MSM_DCVS_ENABLE_IDLE_PULSE:
- priv->enabled = true;
- break;
- case MSM_DCVS_DISABLE_IDLE_PULSE:
- priv->enabled = false;
- break;
- case MSM_DCVS_ENABLE_HIGH_LATENCY_MODES:
- case MSM_DCVS_DISABLE_HIGH_LATENCY_MODES:
- break;
- }
- return 0;
-}
-
-/* Set the requested frequency if it is within 5MHz (delta) of a
- * supported frequency.
- */
-static int msm_set_freq(int core_num, unsigned int freq)
-{
- int i, delta = 5000000;
- struct msm_priv *priv = the_msm_priv;
- struct kgsl_device *device = priv->device;
- struct kgsl_pwrctrl *pwr = &device->pwrctrl;
-
- /* msm_dcvs manager uses frequencies in kHz */
- freq *= 1000;
- for (i = 0; i < pwr->num_pwrlevels; i++)
- if (abs(pwr->pwrlevels[i].gpu_freq - freq) < delta)
- break;
- if (i == pwr->num_pwrlevels)
- return 0;
-
- mutex_lock(&device->mutex);
- priv->req_level = i;
- if (priv->req_level <= priv->floor_level) {
- kgsl_pwrctrl_pwrlevel_change(device, priv->req_level);
- priv->cur_freq = pwr->pwrlevels[pwr->active_pwrlevel].gpu_freq;
- }
- mutex_unlock(&device->mutex);
-
- /* return current frequency in kHz */
- return priv->cur_freq / 1000;
-}
-
-static int msm_set_min_freq(int core_num, unsigned int freq)
-{
- int i, delta = 5000000;
- struct msm_priv *priv = the_msm_priv;
- struct kgsl_device *device = priv->device;
- struct kgsl_pwrctrl *pwr = &device->pwrctrl;
-
- /* msm_dcvs manager uses frequencies in kHz */
- freq *= 1000;
- for (i = 0; i < pwr->num_pwrlevels; i++)
- if (abs(pwr->pwrlevels[i].gpu_freq - freq) < delta)
- break;
- if (i == pwr->num_pwrlevels)
- return 0;
-
- mutex_lock(&device->mutex);
- priv->floor_level = i;
- if (priv->floor_level <= priv->req_level)
- kgsl_pwrctrl_pwrlevel_change(device, priv->floor_level);
- else if (priv->floor_level > priv->req_level)
- kgsl_pwrctrl_pwrlevel_change(device, priv->req_level);
-
- priv->cur_freq = pwr->pwrlevels[pwr->active_pwrlevel].gpu_freq;
- mutex_unlock(&device->mutex);
-
- /* return current frequency in kHz */
- return priv->cur_freq / 1000;
-}
-
-static unsigned int msm_get_freq(int core_num)
-{
- struct msm_priv *priv = the_msm_priv;
-
- /* return current frequency in kHz */
- return priv->cur_freq / 1000;
-}
-
-static void msm_busy(struct kgsl_device *device,
- struct kgsl_pwrscale *pwrscale)
-{
- struct msm_priv *priv = pwrscale->priv;
- if (priv->enabled && !priv->gpu_busy) {
- msm_dcvs_idle(priv->dcvs_core_id, MSM_DCVS_IDLE_EXIT, 0);
- trace_kgsl_mpdcvs(device, 1);
- priv->gpu_busy = 1;
- }
- return;
-}
-
-static void msm_idle(struct kgsl_device *device,
- struct kgsl_pwrscale *pwrscale)
-{
- struct msm_priv *priv = pwrscale->priv;
-
- if (priv->enabled && priv->gpu_busy)
- if (device->ftbl->isidle(device)) {
- msm_dcvs_idle(priv->dcvs_core_id,
- MSM_DCVS_IDLE_ENTER, 0);
- trace_kgsl_mpdcvs(device, 0);
- priv->gpu_busy = 0;
- }
- return;
-}
-
-static void msm_sleep(struct kgsl_device *device,
- struct kgsl_pwrscale *pwrscale)
-{
- struct msm_priv *priv = pwrscale->priv;
-
- if (priv->enabled && priv->gpu_busy) {
- msm_dcvs_idle(priv->dcvs_core_id, MSM_DCVS_IDLE_ENTER, 0);
- trace_kgsl_mpdcvs(device, 0);
- priv->gpu_busy = 0;
- }
-
- return;
-}
-
-static void msm_set_io_fraction(struct kgsl_device *device,
- unsigned int value)
-{
- int i;
- struct kgsl_pwrctrl *pwr = &device->pwrctrl;
-
- for (i = 0; i < pwr->num_pwrlevels; i++)
- pwr->pwrlevels[i].io_fraction = value;
-
-}
-
-static void msm_restore_io_fraction(struct kgsl_device *device)
-{
- int i;
- struct kgsl_device_platform_data *pdata =
- kgsl_device_get_drvdata(device);
- struct kgsl_pwrctrl *pwr = &device->pwrctrl;
-
- for (i = 0; i < pdata->num_levels; i++)
- pwr->pwrlevels[i].io_fraction =
- pdata->pwrlevel[i].io_fraction;
-}
-
-static int msm_init(struct kgsl_device *device,
- struct kgsl_pwrscale *pwrscale)
-{
- struct msm_priv *priv;
- struct msm_dcvs_freq_entry *tbl;
- int i, ret = -EINVAL, low_level;
- struct kgsl_pwrctrl *pwr = &device->pwrctrl;
- struct platform_device *pdev =
- container_of(device->parentdev, struct platform_device, dev);
- struct kgsl_device_platform_data *pdata = pdev->dev.platform_data;
-
- if (the_msm_priv) {
- priv = pwrscale->priv = the_msm_priv;
- } else {
- priv = pwrscale->priv = kzalloc(sizeof(struct msm_priv),
- GFP_KERNEL);
- if (pwrscale->priv == NULL)
- return -ENOMEM;
-
- priv->core_info = pdata->core_info;
- tbl = priv->core_info->freq_tbl;
- priv->floor_level = pwr->num_pwrlevels - 1;
- /* Fill in frequency table from low to high, reversing order. */
- low_level = pwr->num_pwrlevels - KGSL_PWRLEVEL_LAST_OFFSET;
- for (i = 0; i <= low_level; i++)
- tbl[i].freq =
- pwr->pwrlevels[low_level - i].gpu_freq / 1000;
- priv->dcvs_core_id =
- msm_dcvs_register_core(MSM_DCVS_CORE_TYPE_GPU,
- 0,
- priv->core_info,
- msm_set_freq, msm_get_freq, msm_idle_enable,
- msm_set_min_freq,
- priv->core_info->sensors[0]);
- if (priv->dcvs_core_id < 0) {
- KGSL_PWR_ERR(device, "msm_dcvs_register_core failed");
- goto err;
- }
- the_msm_priv = priv;
- }
- priv->device = device;
- ret = msm_dcvs_freq_sink_start(priv->dcvs_core_id);
- if (ret >= 0) {
- if (device->ftbl->isidle(device)) {
- priv->gpu_busy = 0;
- msm_dcvs_idle(priv->dcvs_core_id,
- MSM_DCVS_IDLE_ENTER, 0);
- } else {
- priv->gpu_busy = 1;
- }
- msm_set_io_fraction(device, 0);
- return 0;
- }
-
- KGSL_PWR_ERR(device, "msm_dcvs_freq_sink_register failed\n");
-
-err:
- if (!the_msm_priv)
- kfree(pwrscale->priv);
- pwrscale->priv = NULL;
-
- return ret;
-}
-
-static void msm_close(struct kgsl_device *device,
- struct kgsl_pwrscale *pwrscale)
-{
- struct msm_priv *priv = pwrscale->priv;
-
- if (pwrscale->priv == NULL)
- return;
- msm_dcvs_freq_sink_stop(priv->dcvs_core_id);
- pwrscale->priv = NULL;
- msm_restore_io_fraction(device);
-}
-
-struct kgsl_pwrscale_policy kgsl_pwrscale_policy_msm = {
- .name = "msm",
- .init = msm_init,
- .idle = msm_idle,
- .busy = msm_busy,
- .sleep = msm_sleep,
- .close = msm_close,
-};
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index 2939df6..5950451 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -170,17 +170,32 @@
kobject_put(&private->kobj);
}
-void
-kgsl_process_init_sysfs(struct kgsl_process_private *private)
+/**
+ * kgsl_process_init_sysfs() - Initialize and create sysfs files for a process
+ *
+ * @device: Pointer to kgsl device struct
+ * @private: Pointer to the structure for the process
+ *
+ * @returns: 0 on success, error code otherwise
+ *
+ * kgsl_process_init_sysfs() is called at the time of creating the
+ * process struct when a process opens the kgsl device for the first time.
+ * This function creates the sysfs files for the process.
+ */
+int
+kgsl_process_init_sysfs(struct kgsl_device *device,
+ struct kgsl_process_private *private)
{
unsigned char name[16];
- int i, ret;
+ int i, ret = 0;
snprintf(name, sizeof(name), "%d", private->pid);
- if (kobject_init_and_add(&private->kobj, &ktype_mem_entry,
- kgsl_driver.prockobj, name))
- return;
+ ret = kobject_init_and_add(&private->kobj, &ktype_mem_entry,
+ kgsl_driver.prockobj, name);
+
+ if (ret)
+ return ret;
for (i = 0; i < ARRAY_SIZE(mem_stats); i++) {
/* We need to check the value of sysfs_create_file, but we
@@ -191,6 +206,7 @@
ret = sysfs_create_file(&private->kobj,
&mem_stats[i].max_attr.attr);
}
+ return ret;
}
static int kgsl_drv_memstat_show(struct device *dev,
@@ -589,13 +605,16 @@
/*
* Allocate space to store the list of pages to send to vmap.
- * This is an array of pointers so we can track 1024 pages per page of
- * allocation which means we can handle up to a 8MB buffer request with
- * two pages; well within the acceptable limits for using kmalloc.
+ * This is an array of pointers so we can track 1024 pages per page
+ * of allocation. Since allocations can be as large as the user dares,
+ * we have to use the kmalloc/vmalloc trick here to make sure we can
+ * get the memory we need.
*/
- pages = kmalloc(memdesc->sglen_alloc * sizeof(struct page *),
- GFP_KERNEL);
+ if ((memdesc->sglen_alloc * sizeof(struct page *)) > PAGE_SIZE)
+ pages = vmalloc(memdesc->sglen_alloc * sizeof(struct page *));
+ else
+ pages = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (pages == NULL) {
ret = -ENOMEM;
@@ -706,7 +725,10 @@
kgsl_driver.stats.histogram[order]++;
done:
- kfree(pages);
+ if ((memdesc->sglen_alloc * sizeof(struct page *)) > PAGE_SIZE)
+ vfree(pages);
+ else
+ kfree(pages);
if (ret)
kgsl_sharedmem_free(memdesc);
diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h
index 9f84690..3986c61 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.h
+++ b/drivers/gpu/msm/kgsl_sharedmem.h
@@ -67,7 +67,8 @@
void kgsl_cache_range_op(struct kgsl_memdesc *memdesc, int op);
-void kgsl_process_init_sysfs(struct kgsl_process_private *private);
+int kgsl_process_init_sysfs(struct kgsl_device *device,
+ struct kgsl_process_private *private);
void kgsl_process_uninit_sysfs(struct kgsl_process_private *private);
int kgsl_sharedmem_init_sysfs(void);
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index d3edbba..333089a 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -109,7 +109,7 @@
struct kgsl_device *device;
if (context)
- device = context->dev_priv->device;
+ device = context->device;
else
device = (struct kgsl_device *)data;
@@ -145,7 +145,9 @@
/* Figure out how many active contexts there are - these will
* be appended on the end of the structure */
+ read_lock(&device->context_lock);
idr_for_each(&device->context_idr, snapshot_context_count, &ctxtcount);
+ read_unlock(&device->context_lock);
/* Increment ctxcount for the global memstore */
ctxtcount++;
@@ -202,7 +204,10 @@
/* append information for the global context */
snapshot_context_info(KGSL_MEMSTORE_GLOBAL, NULL, device);
/* append information for each context */
+
+ read_lock(&device->context_lock);
idr_for_each(&device->context_idr, snapshot_context_info, NULL);
+ read_unlock(&device->context_lock);
/* Return the size of the data segment */
return size;
@@ -539,6 +544,16 @@
int remain = device->snapshot_maxsize - sizeof(*header);
void *snapshot;
struct timespec boot;
+ int ret = 0;
+
+ /*
+ * Bail if failed to get active count for GPU,
+ * try again
+ */
+ if (kgsl_active_count_get(device)) {
+ KGSL_DRV_ERR(device, "Failed to get GPU active count");
+ return -EINVAL;
+ }
/* increment the hang count (on hang) for good book keeping */
if (hang)
@@ -553,19 +568,23 @@
* of the state and never frozen.
*/
- if (hang && device->snapshot_frozen == 1)
- return 0;
+ if (hang && device->snapshot_frozen == 1) {
+ ret = 0;
+ goto done;
+ }
if (device->snapshot == NULL) {
KGSL_DRV_ERR(device,
"snapshot: No snapshot memory available\n");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto done;
}
if (remain < sizeof(*header)) {
KGSL_DRV_ERR(device,
"snapshot: Not enough memory for the header\n");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto done;
}
header->magic = SNAPSHOT_MAGIC;
@@ -601,7 +620,10 @@
__pa(device->snapshot), device->snapshot_size);
if (hang)
sysfs_notify(&device->snapshot_kobj, NULL, "timestamp");
- return 0;
+
+done:
+ kgsl_active_count_put(device);
+ return ret;
}
EXPORT_SYMBOL(kgsl_device_snapshot);
@@ -710,7 +732,10 @@
{
if (device && count > 0) {
mutex_lock(&device->mutex);
- kgsl_device_snapshot(device, 0);
+ if (!kgsl_active_count_get(device)) {
+ kgsl_device_snapshot(device, 0);
+ kgsl_active_count_put(device);
+ }
mutex_unlock(&device->mutex);
}
diff --git a/drivers/gpu/msm/kgsl_sync.c b/drivers/gpu/msm/kgsl_sync.c
index 2f67405..b7d7235 100644
--- a/drivers/gpu/msm/kgsl_sync.c
+++ b/drivers/gpu/msm/kgsl_sync.c
@@ -86,7 +86,7 @@
*/
static inline void kgsl_fence_event_cb(struct kgsl_device *device,
- void *priv, u32 context_id, u32 timestamp)
+ void *priv, u32 context_id, u32 timestamp, u32 type)
{
struct kgsl_fence_event_priv *ev = priv;
kgsl_sync_timeline_signal(ev->context->timeline, ev->timestamp);
@@ -121,16 +121,17 @@
if (len != sizeof(priv))
return -EINVAL;
- context = kgsl_find_context(owner, context_id);
- if (context == NULL)
- return -EINVAL;
-
event = kzalloc(sizeof(*event), GFP_KERNEL);
if (event == NULL)
return -ENOMEM;
+
+ context = kgsl_context_get_owner(owner, context_id);
+
+ if (context == NULL)
+ goto fail_pt;
+
event->context = context;
event->timestamp = timestamp;
- kgsl_context_get(context);
pt = kgsl_sync_pt_create(context->timeline, timestamp);
if (pt == NULL) {
@@ -161,6 +162,10 @@
goto fail_copy_fd;
}
+ /*
+ * Hold the context ref-count for the event - it will get released in
+ * the callback
+ */
ret = kgsl_add_event(device, context_id, timestamp,
kgsl_fence_event_cb, event, owner);
if (ret)
@@ -185,12 +190,16 @@
static unsigned int kgsl_sync_get_timestamp(
struct kgsl_sync_timeline *ktimeline, enum kgsl_timestamp_type type)
{
- struct kgsl_context *context = idr_find(&ktimeline->device->context_idr,
- ktimeline->context_id);
- if (context == NULL)
- return 0;
+ unsigned int ret = 0;
- return kgsl_readtimestamp(ktimeline->device, context, type);
+ struct kgsl_context *context = kgsl_context_get(ktimeline->device,
+ ktimeline->context_id);
+
+ if (context)
+ ret = kgsl_readtimestamp(ktimeline->device, context, type);
+
+ kgsl_context_put(context);
+ return ret;
}
static void kgsl_sync_timeline_value_str(struct sync_timeline *sync_timeline,
@@ -211,6 +220,15 @@
snprintf(str, size, "%u", kpt->timestamp);
}
+static void kgsl_sync_timeline_release_obj(struct sync_timeline *sync_timeline)
+{
+ /*
+ * Make sure to free the timeline only after destroy flag is set.
+ * This is to avoid further accessing to the timeline from KGSL and
+ * also to catch any unbalanced kref of timeline.
+ */
+ BUG_ON(sync_timeline && (sync_timeline->destroyed != true));
+}
static const struct sync_timeline_ops kgsl_sync_timeline_ops = {
.driver_name = "kgsl-timeline",
.dup = kgsl_sync_pt_dup,
@@ -218,6 +236,7 @@
.compare = kgsl_sync_pt_compare,
.timeline_value_str = kgsl_sync_timeline_value_str,
.pt_value_str = kgsl_sync_pt_value_str,
+ .release_obj = kgsl_sync_timeline_release_obj,
};
int kgsl_sync_timeline_create(struct kgsl_context *context)
@@ -230,7 +249,7 @@
char ktimeline_name[sizeof(context->timeline->name)] = {};
snprintf(ktimeline_name, sizeof(ktimeline_name),
"%s_%.15s(%d)-%.15s(%d)-%d",
- context->dev_priv->device->name,
+ context->device->name,
current->group_leader->comm, current->group_leader->pid,
current->comm, current->pid, context->id);
@@ -241,7 +260,7 @@
ktimeline = (struct kgsl_sync_timeline *) context->timeline;
ktimeline->last_timestamp = 0;
- ktimeline->device = context->dev_priv->device;
+ ktimeline->device = context->device;
ktimeline->context_id = context->id;
return 0;
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
index 48c7301..f16f2b4 100644
--- a/drivers/gpu/msm/kgsl_trace.h
+++ b/drivers/gpu/msm/kgsl_trace.h
@@ -70,7 +70,7 @@
),
TP_printk(
- "d_name=%s ctx=%u ib=0x%u numibs=%u timestamp=0x%x "
+ "d_name=%s ctx=%u ib=0x%u numibs=%u ts=%u "
"flags=0x%x(%s) result=%d type=%s",
__get_str(device_name),
__entry->drawctxt_id,
@@ -116,7 +116,7 @@
),
TP_printk(
- "d_name=%s context_id=%u type=%u timestamp=0x%x",
+ "d_name=%s context_id=%u type=%u ts=%u",
__get_str(device_name),
__entry->context_id,
__entry->type,
@@ -154,7 +154,7 @@
),
TP_printk(
- "d_name=%s context_id=%u curr_ts=0x%x timestamp=0x%x timeout=%u",
+ "d_name=%s ctx=%u curr_ts=%u ts=%u timeout=%u",
__get_str(device_name),
__entry->context_id,
__entry->curr_ts,
@@ -186,7 +186,7 @@
),
TP_printk(
- "d_name=%s curr_ts=0x%x result=%d",
+ "d_name=%s curr_ts=%u result=%d",
__get_str(device_name),
__entry->curr_ts,
__entry->result
@@ -209,7 +209,7 @@
),
TP_printk(
- "d_name=%s %s",
+ "d_name=%s flag=%s",
__get_str(device_name),
__entry->on ? "on" : "off"
)
@@ -262,29 +262,6 @@
)
);
-TRACE_EVENT(kgsl_mpdcvs,
-
- TP_PROTO(struct kgsl_device *device, unsigned int state),
-
- TP_ARGS(device, state),
-
- TP_STRUCT__entry(
- __string(device_name, device->name)
- __field(unsigned int, state)
- ),
-
- TP_fast_assign(
- __assign_str(device_name, device->name);
- __entry->state = state;
- ),
-
- TP_printk(
- "d_name=%s %s",
- __get_str(device_name),
- __entry->state ? "BUSY" : "IDLE"
- )
-);
-
TRACE_EVENT(kgsl_gpubusy,
TP_PROTO(struct kgsl_device *device, unsigned int busy,
unsigned int elapsed),
@@ -304,7 +281,7 @@
),
TP_printk(
- "d_name=%s busy=%d elapsed=%d",
+ "d_name=%s busy=%u elapsed=%d",
__get_str(device_name),
__entry->busy,
__entry->elapsed
@@ -327,7 +304,7 @@
),
TP_printk(
- "d_name=%s %s",
+ "d_name=%s state=%s",
__get_str(device_name),
kgsl_pwrstate_to_str(__entry->state)
)
@@ -369,7 +346,7 @@
),
TP_printk(
- "gpuaddr=0x%08x size=%d tgid=%d usage=%s id=%d flags=0x%08x",
+ "gpuaddr=0x%08x size=%u tgid=%u usage=%s id=%u flags=0x%08x",
__entry->gpuaddr, __entry->size, __entry->tgid,
__entry->usage, __entry->id, __entry->flags
)
@@ -401,7 +378,7 @@
),
TP_printk(
- "useraddr=%lx gpuaddr=0x%08x size=%d usage=%s id=%d"
+ "useraddr=0x%lx gpuaddr=0x%08x size=%u usage=%s id=%u"
" flags=0x%08x",
__entry->useraddr, __entry->gpuaddr, __entry->size,
__entry->usage, __entry->id, __entry->flags
@@ -432,7 +409,7 @@
),
TP_printk(
- "id=%d hint=0x%lx len=%ld addr=0x%lx",
+ "id=%u hint=0x%lx len=%lu addr=0x%lx",
__entry->id, __entry->hint, __entry->len, __entry->addr
)
);
@@ -465,7 +442,7 @@
),
TP_printk(
- "gpuaddr=0x%08x size=%d type=%d fd=%d tgid=%d usage=%s id=%d",
+ "gpuaddr=0x%08x size=%u type=%d fd=%d tgid=%u usage=%s id=%u",
__entry->gpuaddr, __entry->size,
__entry->type, __entry->fd, __entry->tgid,
__entry->usage, __entry->id
@@ -499,7 +476,7 @@
),
TP_printk(
- "gpuaddr=0x%08x size=%d type=%d tgid=%d usage=%s id=%d",
+ "gpuaddr=0x%08x size=%u type=%d tgid=%u usage=%s id=%u",
__entry->gpuaddr, __entry->size, __entry->type,
__entry->tgid, __entry->usage, __entry->id
)
@@ -531,7 +508,7 @@
),
TP_printk(
- "gpuaddr=0x%08x size=%d tgid=%d usage=%s id=%d op=%c%c",
+ "gpuaddr=0x%08x size=%u tgid=%u usage=%s id=%u op=%c%c",
__entry->gpuaddr, __entry->size, __entry->tgid, __entry->usage,
__entry->id,
(__entry->op & KGSL_GPUMEM_CACHE_CLEAN) ? 'c' : '.',
@@ -599,8 +576,8 @@
),
TP_printk(
- "d_name=%s gpuaddr=0x%08x size=%d type=%d usage=%s id=%d ctx=%u"
- " curr_ts=0x%x free_ts=0x%x",
+ "d_name=%s gpuaddr=0x%08x size=%u type=%d usage=%s id=%u ctx=%u"
+ " curr_ts=%u free_ts=%u",
__get_str(device_name),
__entry->gpuaddr,
__entry->size,
@@ -678,6 +655,28 @@
)
);
+TRACE_EVENT(kgsl_context_destroy,
+
+ TP_PROTO(struct kgsl_device *device, struct kgsl_context *context),
+
+ TP_ARGS(device, context),
+
+ TP_STRUCT__entry(
+ __string(device_name, device->name)
+ __field(unsigned int, id)
+ ),
+
+ TP_fast_assign(
+ __assign_str(device_name, device->name);
+ __entry->id = context->id;
+ ),
+
+ TP_printk(
+ "d_name=%s ctx=%u",
+ __get_str(device_name), __entry->id
+ )
+);
+
TRACE_EVENT(kgsl_mmu_pagefault,
TP_PROTO(struct kgsl_device *device, unsigned int page,
@@ -700,7 +699,7 @@
),
TP_printk(
- "d_name=%s page=0x%08x pt=%d op=%s",
+ "d_name=%s page=0x%08x pt=%u op=%s",
__get_str(device_name), __entry->page, __entry->pt,
__get_str(op)
)
@@ -726,7 +725,7 @@
),
TP_printk(
- "d_name=%s reg=%x value=%x",
+ "d_name=%s reg=0x%x value=0x%x",
__get_str(device_name), __entry->offset, __entry->value
)
);
@@ -743,27 +742,31 @@
__entry->timestamp = timestamp;
),
TP_printk(
- "ctx=%d ts=%d",
+ "ctx=%u ts=%u",
__entry->id, __entry->timestamp)
);
TRACE_EVENT(kgsl_fire_event,
TP_PROTO(unsigned int id, unsigned int ts,
- unsigned int age),
- TP_ARGS(id, ts, age),
+ unsigned int type, unsigned int age),
+ TP_ARGS(id, ts, type, age),
TP_STRUCT__entry(
__field(unsigned int, id)
__field(unsigned int, ts)
+ __field(unsigned int, type)
__field(unsigned int, age)
),
TP_fast_assign(
__entry->id = id;
__entry->ts = ts;
+ __entry->type = type;
__entry->age = age;
),
TP_printk(
- "ctx=%d ts=%d age=%u",
- __entry->id, __entry->ts, __entry->age)
+ "ctx=%u ts=%u type=%s age=%u",
+ __entry->id, __entry->ts,
+ __print_symbolic(__entry->type, KGSL_EVENT_TYPES),
+ __entry->age)
);
TRACE_EVENT(kgsl_active_count,
@@ -785,7 +788,7 @@
),
TP_printk(
- "d_name=%s active_cnt=%x func=%pf",
+ "d_name=%s active_cnt=%u func=%pf",
__get_str(device_name), __entry->count, (void *) __entry->ip
)
);
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index cc1819d..883417f 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -859,11 +859,30 @@
return status;
}
-static void
-z180_drawctxt_destroy(struct kgsl_device *device,
- struct kgsl_context *context)
+struct kgsl_context *
+z180_drawctxt_create(struct kgsl_device_private *dev_priv,
+ uint32_t *flags)
{
- struct z180_device *z180_dev = Z180_DEVICE(device);
+ int ret;
+ struct kgsl_context *context = kzalloc(sizeof(*context), GFP_KERNEL);
+ if (context == NULL)
+ return ERR_PTR(-ENOMEM);
+ ret = kgsl_context_init(dev_priv, context);
+ if (ret != 0) {
+ kfree(context);
+ return ERR_PTR(ret);
+ }
+ return context;
+}
+
+static void
+z180_drawctxt_detach(struct kgsl_context *context)
+{
+ struct kgsl_device *device;
+ struct z180_device *z180_dev;
+
+ device = context->device;
+ z180_dev = Z180_DEVICE(device);
z180_idle(device);
@@ -875,6 +894,12 @@
}
}
+static void
+z180_drawctxt_destroy(struct kgsl_context *context)
+{
+ kfree(context);
+}
+
static void z180_power_stats(struct kgsl_device *device,
struct kgsl_power_stats *stats)
{
@@ -941,7 +966,8 @@
.gpuid = z180_gpuid,
.irq_handler = z180_irq_handler,
/* Optional functions */
- .drawctxt_create = NULL,
+ .drawctxt_create = z180_drawctxt_create,
+ .drawctxt_detach = z180_drawctxt_detach,
.drawctxt_destroy = z180_drawctxt_destroy,
.ioctl = NULL,
.postmortem_dump = z180_dump,
diff --git a/drivers/hwmon/epm_adc.c b/drivers/hwmon/epm_adc.c
index a587ed2..f7cf2df 100644
--- a/drivers/hwmon/epm_adc.c
+++ b/drivers/hwmon/epm_adc.c
@@ -65,6 +65,8 @@
#define EPM_ADC_MILLI_VOLTS_SOURCE 4750
#define EPM_ADC_SCALE_FACTOR 64
#define GPIO_EPM_GLOBAL_ENABLE 86
+#define GPIO_EPM_MARKER1 85
+#define GPIO_EPM_MARKER2 96
#define EPM_ADC_CONVERSION_TIME_MIN 50000
#define EPM_ADC_CONVERSION_TIME_MAX 51000
/* PSoc Commands */
@@ -92,6 +94,14 @@
#define EPM_PSOC_CLEAR_BUFFER_RESPONSE_CMD 0x1e
#define EPM_PSOC_SET_VADC_REFERENCE_CMD 0x1f
#define EPM_PSOC_SET_VADC_REFERENCE_RESPONSE_CMD 0x20
+#define EPM_PSOC_PAUSE_CONVERSION 0x35
+#define EPM_PSOC_PAUSE_CONVERSION_RSP_CMD 0x36
+#define EPM_PSOC_UNPAUSE_CONVERSION 0x37
+#define EPM_PSOC_UNPAUSE_CONVERSION_RSP_CMD 0x38
+#define EPM_PSOC_GPIO_BUFFER_REQUEST_CMD 0x4f
+#define EPM_PSOC_GPIO_BUFFER_REQUEST_RESPONSE_CMD 0x50
+#define EPM_PSOC_GET_GPIO_BUFFER_CMD 0x51
+#define EPM_PSOC_GET_GPIO_BUFFER_RESPONSE_CMD 0x52
#define EPM_PSOC_GLOBAL_ENABLE 81
#define EPM_PSOC_VREF_VOLTAGE 2048
@@ -715,6 +725,130 @@
return 0;
}
+static int epm_set_marker1(struct epm_marker_level *marker_init)
+{
+ int rc = 0;
+
+ rc = gpio_request(GPIO_EPM_MARKER1, "EPM_MARKER1");
+ if (!rc) {
+ gpio_direction_output(GPIO_EPM_MARKER1, 1);
+ } else {
+ pr_err("%s: Configure MARKER1 GPIO Failed\n",
+ __func__);
+ return rc;
+ }
+
+ gpio_set_value(GPIO_EPM_MARKER1, marker_init->level);
+
+ return 0;
+}
+
+static int epm_set_marker2(struct epm_marker_level *marker_init)
+{
+ int rc = 0;
+
+ rc = gpio_request(GPIO_EPM_MARKER2, "EPM_MARKER2");
+ if (!rc) {
+ gpio_direction_output(GPIO_EPM_MARKER2, 1);
+ } else {
+ pr_err("%s: Configure MARKER2 GPIO Failed\n",
+ __func__);
+ return rc;
+ }
+
+ gpio_set_value(GPIO_EPM_MARKER2, marker_init->level);
+
+ return 0;
+}
+
+static int epm_marker1_release(void)
+{
+ gpio_free(GPIO_EPM_MARKER1);
+
+ return 0;
+}
+
+static int epm_marker2_release(void)
+{
+ gpio_free(GPIO_EPM_MARKER2);
+
+ return 0;
+}
+
+static int epm_psoc_pause_conversion(struct epm_adc_drv *epm_adc)
+{
+ struct spi_message m;
+ struct spi_transfer t;
+ char tx_buf[2], rx_buf[2];
+ int rc = 0;
+
+ spi_setup(epm_adc->epm_spi_client);
+
+ memset(&t, 0, sizeof t);
+ memset(tx_buf, 0, sizeof tx_buf);
+ memset(rx_buf, 0, sizeof tx_buf);
+ t.tx_buf = tx_buf;
+ t.rx_buf = rx_buf;
+ spi_message_init(&m);
+ spi_message_add_tail(&t, &m);
+
+ tx_buf[0] = EPM_PSOC_PAUSE_CONVERSION;
+
+ t.len = sizeof(tx_buf);
+ t.bits_per_word = EPM_ADC_ADS_SPI_BITS_PER_WORD;
+
+ rc = spi_sync(epm_adc->epm_spi_client, &m);
+ if (rc) {
+ pr_err("spi sync err with %d\n", rc);
+ return rc;
+ }
+
+ rc = spi_sync(epm_adc->epm_spi_client, &m);
+ if (rc) {
+ pr_err("spi sync err with %d\n", rc);
+ return rc;
+ }
+
+ return rx_buf[0];
+}
+
+static int epm_psoc_unpause_conversion(struct epm_adc_drv *epm_adc)
+{
+ struct spi_message m;
+ struct spi_transfer t;
+ char tx_buf[2], rx_buf[2];
+ int rc = 0;
+
+ spi_setup(epm_adc->epm_spi_client);
+
+ memset(&t, 0, sizeof t);
+ memset(tx_buf, 0, sizeof tx_buf);
+ memset(rx_buf, 0, sizeof tx_buf);
+ t.tx_buf = tx_buf;
+ t.rx_buf = rx_buf;
+ spi_message_init(&m);
+ spi_message_add_tail(&t, &m);
+
+ tx_buf[0] = EPM_PSOC_UNPAUSE_CONVERSION;
+
+ t.len = sizeof(tx_buf);
+ t.bits_per_word = EPM_ADC_ADS_SPI_BITS_PER_WORD;
+
+ rc = spi_sync(epm_adc->epm_spi_client, &m);
+ if (rc) {
+ pr_err("spi sync err with %d\n", rc);
+ return rc;
+ }
+
+ rc = spi_sync(epm_adc->epm_spi_client, &m);
+ if (rc) {
+ pr_err("spi sync err with %d\n", rc);
+ return rc;
+ }
+
+ return rx_buf[0];
+}
+
static int epm_psoc_init(struct epm_adc_drv *epm_adc,
struct epm_psoc_init_resp *init_resp)
{
@@ -1240,6 +1374,84 @@
return rc;
}
+static int epm_psoc_get_gpio_buffer_data(struct epm_adc_drv *epm_adc,
+ struct epm_get_gpio_buffer_resp *gpio_resp_pkt)
+{
+ struct spi_message m;
+ struct spi_transfer t;
+ char tx_buf[7], rx_buf[7];
+ int rc = 0;
+
+ spi_setup(epm_adc->epm_spi_client);
+
+ memset(&t, 0, sizeof t);
+ memset(tx_buf, 0, sizeof tx_buf);
+ memset(rx_buf, 0, sizeof tx_buf);
+ t.tx_buf = tx_buf;
+ t.rx_buf = rx_buf;
+ spi_message_init(&m);
+ spi_message_add_tail(&t, &m);
+
+ tx_buf[0] = EPM_PSOC_GET_GPIO_BUFFER_CMD;
+
+ t.len = sizeof(tx_buf);
+ t.bits_per_word = EPM_ADC_ADS_SPI_BITS_PER_WORD;
+
+ rc = spi_sync(epm_adc->epm_spi_client, &m);
+ if (rc)
+ return rc;
+
+ rc = spi_sync(epm_adc->epm_spi_client, &m);
+ if (rc)
+ return rc;
+
+ gpio_resp_pkt->cmd = rx_buf[0];
+ gpio_resp_pkt->status = rx_buf[1];
+ gpio_resp_pkt->bitmask_monitor_pin = rx_buf[2];
+ gpio_resp_pkt->timestamp = rx_buf[3] << 24 | rx_buf[4] << 16 |
+ rx_buf[5] << 8 | tx_buf[6];
+
+ return rc;
+}
+
+static int epm_psoc_gpio_buffer_request_configure(struct epm_adc_drv *epm_adc,
+ struct epm_gpio_buffer_request *gpio_request)
+{
+ struct spi_message m;
+ struct spi_transfer t;
+ char tx_buf[2], rx_buf[2];
+ int rc = 0;
+
+ spi_setup(epm_adc->epm_spi_client);
+
+ memset(&t, 0, sizeof t);
+ memset(tx_buf, 0, sizeof tx_buf);
+ memset(rx_buf, 0, sizeof tx_buf);
+ t.tx_buf = tx_buf;
+ t.rx_buf = rx_buf;
+ spi_message_init(&m);
+ spi_message_add_tail(&t, &m);
+
+ tx_buf[0] = EPM_PSOC_GPIO_BUFFER_REQUEST_CMD;
+ tx_buf[1] = gpio_request->bitmask_monitor_pin;
+
+ t.len = sizeof(tx_buf);
+ t.bits_per_word = EPM_ADC_ADS_SPI_BITS_PER_WORD;
+
+ rc = spi_sync(epm_adc->epm_spi_client, &m);
+ if (rc)
+ return rc;
+
+ rc = spi_sync(epm_adc->epm_spi_client, &m);
+ if (rc)
+ return rc;
+
+ gpio_request->cmd = rx_buf[0];
+ gpio_request->status = rx_buf[1];
+
+ return rc;
+}
+
static long epm_adc_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
@@ -1296,6 +1508,58 @@
return -EFAULT;
break;
}
+ case EPM_MARKER1_REQUEST:
+ {
+ struct epm_marker_level marker_init;
+ uint32_t result;
+
+ if (copy_from_user(&marker_init, (void __user *)arg,
+ sizeof(struct epm_marker_level)))
+ return -EFAULT;
+
+ result = epm_set_marker1(&marker_init);
+
+ if (copy_to_user((void __user *)arg, &result,
+ sizeof(uint32_t)))
+ return -EFAULT;
+ break;
+ }
+ case EPM_MARKER2_REQUEST:
+ {
+ struct epm_marker_level marker_init;
+ uint32_t result;
+
+ if (copy_from_user(&marker_init, (void __user *)arg,
+ sizeof(struct epm_marker_level)))
+ return -EFAULT;
+
+ result = epm_set_marker2(&marker_init);
+
+ if (copy_to_user((void __user *)arg, &result,
+ sizeof(uint32_t)))
+ return -EFAULT;
+ break;
+ }
+ case EPM_MARKER1_RELEASE:
+ {
+ uint32_t result;
+ result = epm_marker1_release();
+
+ if (copy_to_user((void __user *)arg, &result,
+ sizeof(uint32_t)))
+ return -EFAULT;
+ break;
+ }
+ case EPM_MARKER2_RELEASE:
+ {
+ uint32_t result;
+ result = epm_marker2_release();
+
+ if (copy_to_user((void __user *)arg, &result,
+ sizeof(uint32_t)))
+ return -EFAULT;
+ break;
+ }
case EPM_PSOC_ADC_INIT:
{
struct epm_psoc_init_resp psoc_init;
@@ -1312,11 +1576,29 @@
return -EINVAL;
}
+ if (!rc) {
+ rc = epm_adc_psoc_gpio_init(true);
+ if (rc) {
+ pr_err("GPIO init failed\n");
+ return -EINVAL;
+ }
+ }
+
if (copy_to_user((void __user *)arg, &psoc_init,
sizeof(struct epm_psoc_init_resp)))
return -EFAULT;
break;
}
+ case EPM_PSOC_ADC_DEINIT:
+ {
+ uint32_t result;
+ result = epm_adc_psoc_gpio_init(false);
+
+ if (copy_to_user((void __user *)arg, &result,
+ sizeof(uint32_t)))
+ return -EFAULT;
+ break;
+ }
case EPM_PSOC_ADC_CHANNEL_ENABLE:
case EPM_PSOC_ADC_CHANNEL_DISABLE:
{
@@ -1539,6 +1821,70 @@
return -EFAULT;
break;
}
+ case EPM_PSOC_GPIO_BUFFER_REQUEST:
+ {
+ struct epm_gpio_buffer_request gpio_request;
+ int rc;
+
+ if (copy_from_user(&gpio_request,
+ (void __user *)arg,
+ sizeof(struct epm_gpio_buffer_request)))
+ return -EFAULT;
+
+ rc = epm_psoc_gpio_buffer_request_configure(epm_adc,
+ &gpio_request);
+ if (rc) {
+ pr_err("PSOC buffer request failed\n");
+ return -EINVAL;
+ }
+
+ if (copy_to_user((void __user *)arg, &gpio_request,
+ sizeof(struct epm_gpio_buffer_request)))
+ return -EFAULT;
+ break;
+ }
+ case EPM_PSOC_GET_GPIO_BUFFER_DATA:
+ {
+ struct epm_get_gpio_buffer_resp gpio_resp_pkt;
+ int rc;
+
+ if (copy_from_user(&gpio_resp_pkt,
+ (void __user *)arg,
+ sizeof(struct epm_get_gpio_buffer_resp)))
+ return -EFAULT;
+
+ rc = epm_psoc_get_gpio_buffer_data(epm_adc,
+ &gpio_resp_pkt);
+ if (rc) {
+ pr_err("PSOC get buffer data failed\n");
+ return -EINVAL;
+ }
+
+ if (copy_to_user((void __user *)arg, &gpio_resp_pkt,
+ sizeof(struct epm_get_gpio_buffer_resp)))
+ return -EFAULT;
+ break;
+ }
+ case EPM_PSOC_PAUSE_CONVERSION_REQUEST:
+ {
+ uint32_t result;
+ result = epm_psoc_pause_conversion(epm_adc);
+
+ if (copy_to_user((void __user *)arg, &result,
+ sizeof(uint32_t)))
+ return -EFAULT;
+ break;
+ }
+ case EPM_PSOC_UNPAUSE_CONVERSION_REQUEST:
+ {
+ uint32_t result;
+ result = epm_psoc_unpause_conversion(epm_adc);
+
+ if (copy_to_user((void __user *)arg, &result,
+ sizeof(uint32_t)))
+ return -EFAULT;
+ break;
+ }
default:
return -EINVAL;
}
diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c
index 8e350f0..4e77ca2 100644
--- a/drivers/hwmon/qpnp-adc-common.c
+++ b/drivers/hwmon/qpnp-adc-common.c
@@ -923,8 +923,12 @@
pr_err("Invalid channel fast average setup\n");
return -EINVAL;
}
- calibration_param = of_get_property(child,
- "qcom,calibration-type", NULL);
+ rc = of_property_read_string(child, "qcom,calibration-type",
+ &calibration_param);
+ if (rc) {
+ pr_err("Invalid calibration type\n");
+ return -EINVAL;
+ }
if (!strncmp(calibration_param, "absolute", 8))
calib_type = CALIB_ABSOLUTE;
else if (!strncmp(calibration_param, "ratiometric", 11))
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
index 9570327..f0793b2 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -499,10 +499,13 @@
return 0;
}
+#define IADC_CENTER 0xC000
+#define IADC_READING_RESOLUTION_N 542535
+#define IADC_READING_RESOLUTION_D 100000
static int32_t qpnp_convert_raw_offset_voltage(void)
{
struct qpnp_iadc_drv *iadc = qpnp_iadc;
- uint32_t num = 0;
+ s64 numerator;
if ((iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw) == 0) {
pr_err("raw offset errors! raw_gain:0x%x and raw_offset:0x%x\n",
@@ -510,19 +513,23 @@
return -EINVAL;
}
- iadc->adc->calib.offset_uv = 0;
+ numerator = iadc->adc->calib.offset_raw - IADC_CENTER;
+ numerator *= IADC_READING_RESOLUTION_N;
+ iadc->adc->calib.offset_uv = div_s64(numerator,
+ IADC_READING_RESOLUTION_D);
- num = iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw;
+ numerator = iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw;
+ numerator *= IADC_READING_RESOLUTION_N;
- iadc->adc->calib.gain_uv = (num * QPNP_ADC_GAIN_NV)/
- (iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw);
+ iadc->adc->calib.gain_uv = div_s64(numerator,
+ IADC_READING_RESOLUTION_D);
pr_debug("gain_uv:%d offset_uv:%d\n",
iadc->adc->calib.gain_uv, iadc->adc->calib.offset_uv);
return 0;
}
-int32_t qpnp_iadc_calibrate_for_trim(void)
+int32_t qpnp_iadc_calibrate_for_trim(bool batfet_closed)
{
struct qpnp_iadc_drv *iadc = qpnp_iadc;
uint8_t rslt_lsb, rslt_msb;
@@ -530,6 +537,9 @@
uint16_t raw_data;
uint32_t mode_sel = 0;
+ if (!iadc || !iadc->iadc_initialized)
+ return -EPROBE_DEFER;
+
mutex_lock(&iadc->adc->adc_lock);
rc = qpnp_iadc_configure(GAIN_CALIBRATION_17P857MV,
@@ -541,11 +551,29 @@
iadc->adc->calib.gain_raw = raw_data;
- rc = qpnp_iadc_configure(OFFSET_CALIBRATION_CSP2_CSN2,
+ /*
+ * there is a features in the BMS where if the batfet is opened
+ * the BMS reads from INTERNAL_RSENSE (channel 0) actually go to
+ * OFFSET_CALIBRATION_CSP_CSN (channel 5). Hence if batfet is opened
+ * we have to calibrate based on OFFSET_CALIBRATION_CSP_CSN even for
+ * internal rsense.
+ */
+ if (!batfet_closed || iadc->external_rsense) {
+ /* external offset calculation */
+ rc = qpnp_iadc_configure(OFFSET_CALIBRATION_CSP_CSN,
&raw_data, mode_sel);
- if (rc < 0) {
- pr_err("qpnp adc result read failed with %d\n", rc);
- goto fail;
+ if (rc < 0) {
+ pr_err("qpnp adc result read failed with %d\n", rc);
+ goto fail;
+ }
+ } else {
+ /* internal offset calculation */
+ rc = qpnp_iadc_configure(OFFSET_CALIBRATION_CSP2_CSN2,
+ &raw_data, mode_sel);
+ if (rc < 0) {
+ pr_err("qpnp adc result read failed with %d\n", rc);
+ goto fail;
+ }
}
iadc->adc->calib.offset_raw = raw_data;
@@ -607,7 +635,7 @@
struct qpnp_iadc_drv *iadc = qpnp_iadc;
int rc = 0;
- rc = qpnp_iadc_calibrate_for_trim();
+ rc = qpnp_iadc_calibrate_for_trim(true);
if (rc)
pr_debug("periodic IADC calibration failed\n");
else
@@ -702,9 +730,8 @@
die_temp_offset = -die_temp_offset;
if (die_temp_offset > QPNP_IADC_DIE_TEMP_CALIB_OFFSET) {
- iadc->die_temp =
- result_pmic_therm.physical;
- rc = qpnp_iadc_calibrate_for_trim();
+ iadc->die_temp = result_pmic_therm.physical;
+ rc = qpnp_iadc_calibrate_for_trim(true);
if (rc)
pr_err("periodic IADC calibration failed\n");
}
@@ -994,7 +1021,7 @@
}
iadc->iadc_initialized = true;
- rc = qpnp_iadc_calibrate_for_trim();
+ rc = qpnp_iadc_calibrate_for_trim(true);
if (rc)
dev_err(&spmi->dev, "failed to calibrate for USR trim\n");
schedule_delayed_work(&iadc->iadc_work,
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index 309944e..53e43d1 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -866,6 +866,11 @@
amux_prescaling =
vadc->adc->adc_channels[dt_index].chan_path_prescaling;
+ if (amux_prescaling >= PATH_SCALING_NONE) {
+ rc = -EINVAL;
+ goto fail_unlock;
+ }
+
vadc->adc->amux_prop->chan_prop->offset_gain_numerator =
qpnp_vadc_amux_scaling_ratio[amux_prescaling].num;
vadc->adc->amux_prop->chan_prop->offset_gain_denominator =
@@ -1016,6 +1021,11 @@
amux_prescaling =
vadc->adc->adc_channels[dt_index].chan_path_prescaling;
+ if (amux_prescaling >= PATH_SCALING_NONE) {
+ rc = -EINVAL;
+ goto fail;
+ }
+
vadc->adc->amux_prop->chan_prop->offset_gain_numerator =
qpnp_vadc_amux_scaling_ratio[amux_prescaling].num;
vadc->adc->amux_prop->chan_prop->offset_gain_denominator =
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index b96349e..74a252f 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -1385,7 +1385,8 @@
qup_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"qup_phys_addr");
if (!qup_mem) {
- dev_err(&pdev->dev, "no qup mem resource?\n");
+ dev_err(&pdev->dev,
+ "platform_get_resource_byname(qup_phys_addr) failed\n");
ret = -ENODEV;
goto get_res_failed;
}
@@ -1655,11 +1656,22 @@
return ret;
}
+static void qup_i2c_mem_release(struct platform_device *pdev, const char *name)
+{
+ struct resource *res =
+ platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
+
+ if (res)
+ release_mem_region(res->start, resource_size(res));
+ else
+ dev_dbg(&pdev->dev,
+ "platform_get_resource_byname(%s) failed\n", name);
+}
+
static int __devexit
qup_i2c_remove(struct platform_device *pdev)
{
- struct qup_i2c_dev *dev = platform_get_drvdata(pdev);
- struct resource *qup_mem, *gsbi_mem;
+ struct qup_i2c_dev *dev = platform_get_drvdata(pdev);
/* Grab mutex to ensure ongoing transaction is over */
mutex_lock(&dev->mlock);
@@ -1693,14 +1705,11 @@
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
- if (!(dev->pdata->use_gsbi_shared_mode)) {
- gsbi_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- "gsbi_qup_i2c_addr");
- release_mem_region(gsbi_mem->start, resource_size(gsbi_mem));
- }
- qup_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- "qup_phys_addr");
- release_mem_region(qup_mem->start, resource_size(qup_mem));
+ if (!(dev->pdata->use_gsbi_shared_mode))
+ qup_i2c_mem_release(pdev, "gsbi_qup_i2c_addr");
+
+ qup_i2c_mem_release(pdev, "qup_phys_addr");
+
if (dev->dev->of_node)
kfree(dev->pdata);
kfree(dev);
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 1464dab..a052bd3 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -654,4 +654,42 @@
If you say yes here you get support for STMicroelectronics's
acceleration sensors LIS3DH.
+config BMP18X
+ tristate "BMP18X digital pressure sensor"
+ depends on (I2C ) && SYSFS
+ help
+ If you say yes here you get support for Bosch Sensortec
+ digital pressure sensors BMP085, BMP180.
+
+ To compile this driver as a module, choose M here: the
+ module will be called bmp18x-core.
+
+config BMP18X_I2C
+ tristate "support I2C bus connection"
+ depends on BMP18X && I2C
+ help
+ Say Y here if you want to support Bosch Sensortec digital pressure
+ sensor hooked to an I2C bus.
+
+ To compile this driver as a module, choose M here: the
+ module will be called bmp18x-i2c.
+
+config SENSORS_MMA8X5X
+ tristate "MMA8451/MMA8452/MMA8453/MMA8652/MMA8653 device driver"
+ depends on I2C && SYSFS
+ select INPUT_POLLDEV
+ default n
+ help
+ If you say yes here you get support for the Freescale MMA8451/
+ MMA8452/MMA8453/MMA8652/MMA8653 sensors.
+
+ To compile this driver as a module, choose M here: the
+ module will be called mma8x5x.
+
+config SENSORS_MMA_POSITION
+ int "MMA8x5x Accelerate Sensor Position Setting"
+ depends on SENSORS_MMA8X5X
+ default "0"
+ help
+ this provide the sensor position setting , value is between 0~7
endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 96c9288..4f29e05 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -61,3 +61,6 @@
obj-$(CONFIG_INPUT_PMIC8058_VIBRA_MEMLESS) += pmic8058-vib-memless.o
obj-$(CONFIG_BOSCH_BMA150) += bma150.o
obj-$(CONFIG_STM_LIS3DH) += lis3dh_acc.o
+obj-$(CONFIG_BMP18X) += bmp18x-core.o
+obj-$(CONFIG_BMP18X_I2C) += bmp18x-i2c.o
+obj-$(CONFIG_SENSORS_MMA8X5X) += mma8x5x.o
diff --git a/drivers/input/misc/bmp18x-core.c b/drivers/input/misc/bmp18x-core.c
new file mode 100644
index 0000000..4b5b710
--- /dev/null
+++ b/drivers/input/misc/bmp18x-core.c
@@ -0,0 +1,705 @@
+/* Copyright (c) 2011 Bosch Sensortec GmbH
+ Copyright (c) 2011 Unixphere
+
+ Based on:
+ BMP085 driver, bmp085.c
+ Copyright (c) 2010 Christoph Mair <christoph.mair@gmail.com>
+
+ This driver supports the bmp18x digital barometric pressure
+ and temperature sensors from Bosch Sensortec.
+
+ A pressure measurement is issued by reading from pressure0_input.
+ The return value ranges from 30000 to 110000 pascal with a resulution
+ of 1 pascal (0.01 millibar) which enables measurements from 9000m above
+ to 500m below sea level.
+
+ The temperature can be read from temp0_input. Values range from
+ -400 to 850 representing the ambient temperature in degree celsius
+ multiplied by 10.The resolution is 0.1 celsius.
+
+ Because ambient pressure is temperature dependent, a temperature
+ measurement will be executed automatically even if the user is reading
+ from pressure0_input. This happens if the last temperature measurement
+ has been executed more then one second ago.
+
+ To decrease RMS noise from pressure measurements, the bmp18x can
+ autonomously calculate the average of up to eight samples. This is
+ set up by writing to the oversampling sysfs file. Accepted values
+ are 0, 1, 2 and 3. 2^x when x is the value written to this file
+ specifies the number of samples used to calculate the ambient pressure.
+ RMS noise is specified with six pascal (without averaging) and decreases
+ down to 3 pascal when using an oversampling setting of 3.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/workqueue.h>
+#include <linux/module.h>
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+#include "bmp18x.h"
+
+#define BMP18X_CHIP_ID 0x55
+
+#define BMP18X_CALIBRATION_DATA_START 0xAA
+#define BMP18X_CALIBRATION_DATA_LENGTH 11 /* 16 bit values */
+#define BMP18X_CHIP_ID_REG 0xD0
+#define BMP18X_CTRL_REG 0xF4
+#define BMP18X_TEMP_MEASUREMENT 0x2E
+#define BMP18X_PRESSURE_MEASUREMENT 0x34
+#define BMP18X_CONVERSION_REGISTER_MSB 0xF6
+#define BMP18X_CONVERSION_REGISTER_LSB 0xF7
+#define BMP18X_CONVERSION_REGISTER_XLSB 0xF8
+#define BMP18X_TEMP_CONVERSION_TIME 5
+
+#define ABS_MIN_PRESSURE 30000
+#define ABS_MAX_PRESSURE 120000
+#define BMP_DELAY_DEFAULT 200
+
+struct bmp18x_calibration_data {
+ s16 AC1, AC2, AC3;
+ u16 AC4, AC5, AC6;
+ s16 B1, B2;
+ s16 MB, MC, MD;
+};
+
+/* Each client has this additional data */
+struct bmp18x_data {
+ struct bmp18x_data_bus data_bus;
+ struct device *dev;
+ struct mutex lock;
+ struct bmp18x_calibration_data calibration;
+ u8 oversampling_setting;
+ u8 sw_oversampling_setting;
+ u32 raw_temperature;
+ u32 raw_pressure;
+ u32 temp_measurement_period;
+ u32 last_temp_measurement;
+ s32 b6; /* calculated temperature correction coefficient */
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ struct early_suspend early_suspend;
+#endif
+ struct input_dev *input;
+ struct delayed_work work;
+ u32 delay;
+ u32 enable;
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void bmp18x_early_suspend(struct early_suspend *h);
+static void bmp18x_late_resume(struct early_suspend *h);
+#endif
+
+static s32 bmp18x_read_calibration_data(struct bmp18x_data *data)
+{
+ u16 tmp[BMP18X_CALIBRATION_DATA_LENGTH];
+ struct bmp18x_calibration_data *cali = &(data->calibration);
+ s32 status = data->data_bus.bops->read_block(data->data_bus.client,
+ BMP18X_CALIBRATION_DATA_START,
+ BMP18X_CALIBRATION_DATA_LENGTH*sizeof(u16),
+ (u8 *)tmp);
+ if (status < 0)
+ return status;
+
+ if (status != BMP18X_CALIBRATION_DATA_LENGTH*sizeof(u16))
+ return -EIO;
+
+ cali->AC1 = be16_to_cpu(tmp[0]);
+ cali->AC2 = be16_to_cpu(tmp[1]);
+ cali->AC3 = be16_to_cpu(tmp[2]);
+ cali->AC4 = be16_to_cpu(tmp[3]);
+ cali->AC5 = be16_to_cpu(tmp[4]);
+ cali->AC6 = be16_to_cpu(tmp[5]);
+ cali->B1 = be16_to_cpu(tmp[6]);
+ cali->B2 = be16_to_cpu(tmp[7]);
+ cali->MB = be16_to_cpu(tmp[8]);
+ cali->MC = be16_to_cpu(tmp[9]);
+ cali->MD = be16_to_cpu(tmp[10]);
+ return 0;
+}
+
+
+static s32 bmp18x_update_raw_temperature(struct bmp18x_data *data)
+{
+ u16 tmp;
+ s32 status;
+
+ mutex_lock(&data->lock);
+ status = data->data_bus.bops->write_byte(data->data_bus.client,
+ BMP18X_CTRL_REG, BMP18X_TEMP_MEASUREMENT);
+ if (status != 0) {
+ dev_err(data->dev,
+ "Error while requesting temperature measurement.\n");
+ goto exit;
+ }
+ msleep(BMP18X_TEMP_CONVERSION_TIME);
+
+ status = data->data_bus.bops->read_block(data->data_bus.client,
+ BMP18X_CONVERSION_REGISTER_MSB, sizeof(tmp), (u8 *)&tmp);
+ if (status < 0)
+ goto exit;
+ if (status != sizeof(tmp)) {
+ dev_err(data->dev,
+ "Error while reading temperature measurement result\n");
+ status = -EIO;
+ goto exit;
+ }
+ data->raw_temperature = be16_to_cpu(tmp);
+ data->last_temp_measurement = jiffies;
+ status = 0; /* everything ok, return 0 */
+
+exit:
+ mutex_unlock(&data->lock);
+ return status;
+}
+
+static s32 bmp18x_update_raw_pressure(struct bmp18x_data *data)
+{
+ u32 tmp = 0;
+ s32 status;
+
+ mutex_lock(&data->lock);
+ status = data->data_bus.bops->write_byte(data->data_bus.client,
+ BMP18X_CTRL_REG, BMP18X_PRESSURE_MEASUREMENT +
+ (data->oversampling_setting<<6));
+ if (status != 0) {
+ dev_err(data->dev,
+ "Error while requesting pressure measurement.\n");
+ goto exit;
+ }
+
+ /* wait for the end of conversion */
+ msleep(2+(3 << data->oversampling_setting));
+
+ /* copy data into a u32 (4 bytes), but skip the first byte. */
+ status = data->data_bus.bops->read_block(data->data_bus.client,
+ BMP18X_CONVERSION_REGISTER_MSB, 3, ((u8 *)&tmp)+1);
+ if (status < 0)
+ goto exit;
+ if (status != 3) {
+ dev_err(data->dev,
+ "Error while reading pressure measurement results\n");
+ status = -EIO;
+ goto exit;
+ }
+ data->raw_pressure = be32_to_cpu((tmp));
+ data->raw_pressure >>= (8-data->oversampling_setting);
+ status = 0; /* everything ok, return 0 */
+
+exit:
+ mutex_unlock(&data->lock);
+ return status;
+}
+
+
+/*
+ * This function starts the temperature measurement and returns the value
+ * in tenth of a degree celsius.
+ */
+static s32 bmp18x_get_temperature(struct bmp18x_data *data, int *temperature)
+{
+ struct bmp18x_calibration_data *cali = &data->calibration;
+ long x1, x2;
+ int status;
+
+ status = bmp18x_update_raw_temperature(data);
+ if (status != 0)
+ goto exit;
+
+ x1 = ((data->raw_temperature - cali->AC6) * cali->AC5) >> 15;
+ x2 = (cali->MC << 11) / (x1 + cali->MD);
+ data->b6 = x1 + x2 - 4000;
+ /* if NULL just update b6. Used for pressure only measurements */
+ if (temperature != NULL)
+ *temperature = (x1+x2+8) >> 4;
+
+exit:
+ return status;
+}
+
+/*
+ * This function starts the pressure measurement and returns the value
+ * in millibar. Since the pressure depends on the ambient temperature,
+ * a temperature measurement is executed according to the given temperature
+ * measurememt period (default is 1 sec boundary). This period could vary
+ * and needs to be adjusted accoring to the sensor environment, i.e. if big
+ * temperature variations then the temperature needs to be read out often.
+ */
+static s32 bmp18x_get_pressure(struct bmp18x_data *data, int *pressure)
+{
+ struct bmp18x_calibration_data *cali = &data->calibration;
+ s32 x1, x2, x3, b3;
+ u32 b4, b7;
+ s32 p;
+ int status;
+ int i_loop, i;
+ u32 p_tmp;
+
+ /* update the ambient temperature according to the given meas. period */
+ if (data->last_temp_measurement +
+ data->temp_measurement_period < jiffies) {
+ status = bmp18x_get_temperature(data, NULL);
+ if (status != 0)
+ goto exit;
+ }
+
+ if ((data->oversampling_setting == 3)
+ && (data->sw_oversampling_setting == 1)) {
+ i_loop = 3;
+ } else {
+ i_loop = 1;
+ }
+
+ p_tmp = 0;
+ for (i = 0; i < i_loop; i++) {
+ status = bmp18x_update_raw_pressure(data);
+ if (status != 0)
+ goto exit;
+ p_tmp += data->raw_pressure;
+ }
+
+ data->raw_pressure = (p_tmp + (i_loop >> 1)) / i_loop;
+
+ x1 = (data->b6 * data->b6) >> 12;
+ x1 *= cali->B2;
+ x1 >>= 11;
+
+ x2 = cali->AC2 * data->b6;
+ x2 >>= 11;
+
+ x3 = x1 + x2;
+
+ b3 = (((((s32)cali->AC1) * 4 + x3) << data->oversampling_setting) + 2);
+ b3 >>= 2;
+
+ x1 = (cali->AC3 * data->b6) >> 13;
+ x2 = (cali->B1 * ((data->b6 * data->b6) >> 12)) >> 16;
+ x3 = (x1 + x2 + 2) >> 2;
+ b4 = (cali->AC4 * (u32)(x3 + 32768)) >> 15;
+
+ b7 = ((u32)data->raw_pressure - b3) *
+ (50000 >> data->oversampling_setting);
+ p = ((b7 < 0x80000000) ? ((b7 << 1) / b4) : ((b7 / b4) * 2));
+
+ x1 = p >> 8;
+ x1 *= x1;
+ x1 = (x1 * 3038) >> 16;
+ x2 = (-7357 * p) >> 16;
+ p += (x1 + x2 + 3791) >> 4;
+
+ *pressure = p;
+
+exit:
+ return status;
+}
+
+/*
+ * This function sets the chip-internal oversampling. Valid values are 0..3.
+ * The chip will use 2^oversampling samples for internal averaging.
+ * This influences the measurement time and the accuracy; larger values
+ * increase both. The datasheet gives on overview on how measurement time,
+ * accuracy and noise correlate.
+ */
+static void bmp18x_set_oversampling(struct bmp18x_data *data,
+ unsigned char oversampling)
+{
+ if (oversampling > 3)
+ oversampling = 3;
+ data->oversampling_setting = oversampling;
+}
+
+/*
+ * Returns the currently selected oversampling. Range: 0..3
+ */
+static unsigned char bmp18x_get_oversampling(struct bmp18x_data *data)
+{
+ return data->oversampling_setting;
+}
+
+/* sysfs callbacks */
+static ssize_t set_oversampling(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct bmp18x_data *data = dev_get_drvdata(dev);
+ unsigned long oversampling;
+ int success = kstrtoul(buf, 10, &oversampling);
+ if (success == 0) {
+ mutex_lock(&data->lock);
+ bmp18x_set_oversampling(data, oversampling);
+ if (oversampling != 3)
+ data->sw_oversampling_setting = 0;
+ mutex_unlock(&data->lock);
+ return count;
+ }
+ return success;
+}
+
+static ssize_t show_oversampling(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct bmp18x_data *data = dev_get_drvdata(dev);
+ return snprintf(buf, PAGE_SIZE,
+ "%u\n", bmp18x_get_oversampling(data));
+}
+static DEVICE_ATTR(oversampling, S_IWUSR | S_IRUGO,
+ show_oversampling, set_oversampling);
+
+static ssize_t set_sw_oversampling(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct bmp18x_data *data = dev_get_drvdata(dev);
+ unsigned long sw_oversampling;
+ int success = kstrtoul(buf, 10, &sw_oversampling);
+ if (success == 0) {
+ mutex_lock(&data->lock);
+ data->sw_oversampling_setting = sw_oversampling ? 1 : 0;
+ mutex_unlock(&data->lock);
+ }
+ return success;
+}
+
+static ssize_t show_sw_oversampling(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct bmp18x_data *data = dev_get_drvdata(dev);
+ return snprintf(buf, PAGE_SIZE,
+ "%u\n", data->sw_oversampling_setting);
+}
+static DEVICE_ATTR(sw_oversampling, S_IWUSR | S_IRUGO,
+ show_sw_oversampling, set_sw_oversampling);
+
+static ssize_t show_delay(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct bmp18x_data *data = dev_get_drvdata(dev);
+ return snprintf(buf, PAGE_SIZE, "%u\n", data->delay);
+}
+
+static ssize_t set_delay(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ 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;
+}
+static DEVICE_ATTR(delay, S_IWUSR | S_IRUGO,
+ show_delay, set_delay);
+
+static ssize_t show_enable(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct bmp18x_data *data = dev_get_drvdata(dev);
+ return snprintf(buf, PAGE_SIZE, "%u\n", data->enable);
+}
+
+static ssize_t set_enable(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ 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;
+
+ 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 count;
+}
+static DEVICE_ATTR(enable, S_IWUSR | S_IRUGO,
+ show_enable, set_enable);
+
+static ssize_t show_temperature(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int temperature;
+ int status;
+ struct bmp18x_data *data = dev_get_drvdata(dev);
+
+ status = bmp18x_get_temperature(data, &temperature);
+ if (status != 0)
+ return status;
+ else
+ return snprintf(buf, PAGE_SIZE,
+ "%d\n", temperature);
+}
+static DEVICE_ATTR(temp0_input, S_IRUGO, show_temperature, NULL);
+
+
+static ssize_t show_pressure(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int pressure;
+ int status;
+ struct bmp18x_data *data = dev_get_drvdata(dev);
+
+ status = bmp18x_get_pressure(data, &pressure);
+ if (status != 0)
+ return status;
+ else
+ return snprintf(buf, PAGE_SIZE, "%d\n", pressure);
+}
+static DEVICE_ATTR(pressure0_input, S_IRUGO, show_pressure, NULL);
+
+
+static struct attribute *bmp18x_attributes[] = {
+ &dev_attr_temp0_input.attr,
+ &dev_attr_pressure0_input.attr,
+ &dev_attr_oversampling.attr,
+ &dev_attr_sw_oversampling.attr,
+ &dev_attr_delay.attr,
+ &dev_attr_enable.attr,
+ NULL
+};
+
+static const struct attribute_group bmp18x_attr_group = {
+ .attrs = bmp18x_attributes,
+};
+
+static void bmp18x_work_func(struct work_struct *work)
+{
+ struct bmp18x_data *client_data =
+ container_of((struct delayed_work *)work,
+ struct bmp18x_data, work);
+ unsigned long delay = msecs_to_jiffies(client_data->delay);
+ unsigned long j1 = jiffies;
+ int pressure;
+ int status;
+
+ status = bmp18x_get_pressure(client_data, &pressure);
+
+ if (status == 0) {
+ input_report_abs(client_data->input, ABS_PRESSURE, pressure);
+ input_sync(client_data->input);
+ }
+
+ schedule_delayed_work(&client_data->work, delay-(jiffies-j1));
+}
+
+static int bmp18x_input_init(struct bmp18x_data *data)
+{
+ struct input_dev *dev;
+ int err;
+
+ dev = input_allocate_device();
+ if (!dev)
+ return -ENOMEM;
+ dev->name = BMP18X_NAME;
+ dev->id.bustype = BUS_I2C;
+
+ input_set_capability(dev, EV_ABS, ABS_MISC);
+ input_set_abs_params(dev, ABS_PRESSURE,
+ ABS_MIN_PRESSURE, ABS_MAX_PRESSURE, 0, 0);
+ input_set_drvdata(dev, data);
+
+ err = input_register_device(dev);
+ if (err < 0) {
+ input_free_device(dev);
+ return err;
+ }
+ data->input = dev;
+
+ return 0;
+}
+
+static void bmp18x_input_delete(struct bmp18x_data *data)
+{
+ struct input_dev *dev = data->input;
+
+ input_unregister_device(dev);
+ input_free_device(dev);
+}
+
+static int bmp18x_init_client(struct bmp18x_data *data,
+ struct bmp18x_platform_data *pdata)
+{
+ int status = bmp18x_read_calibration_data(data);
+ if (status != 0)
+ goto exit;
+ data->last_temp_measurement = 0;
+ data->temp_measurement_period =
+ pdata ? (pdata->temp_measurement_period/1000)*HZ : 1*HZ;
+ data->oversampling_setting = pdata ? pdata->default_oversampling : 3;
+ if (data->oversampling_setting == 3)
+ data->sw_oversampling_setting
+ = pdata ? pdata->default_sw_oversampling : 0;
+ mutex_init(&data->lock);
+exit:
+ return status;
+}
+
+__devinit int bmp18x_probe(struct device *dev, struct bmp18x_data_bus *data_bus)
+{
+ struct bmp18x_data *data;
+ struct bmp18x_platform_data *pdata = dev->platform_data;
+ u8 chip_id = pdata && pdata->chip_id ? pdata->chip_id : BMP18X_CHIP_ID;
+ int err = 0;
+
+ if (pdata && pdata->init_hw) {
+ err = pdata->init_hw(data_bus);
+ if (err) {
+ printk(KERN_ERR "%s: init_hw failed!\n",
+ BMP18X_NAME);
+ goto exit;
+ }
+ }
+
+ if (data_bus->bops->read_byte(data_bus->client,
+ BMP18X_CHIP_ID_REG) != chip_id) {
+ printk(KERN_ERR "%s: chip_id failed!\n", BMP18X_NAME);
+ err = -ENODEV;
+ goto exit;
+ }
+
+ data = kzalloc(sizeof(struct bmp18x_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ dev_set_drvdata(dev, data);
+ data->data_bus = *data_bus;
+ data->dev = dev;
+
+ /* Initialize the BMP18X chip */
+ err = bmp18x_init_client(data, pdata);
+ if (err != 0)
+ goto exit_free;
+
+ /* Initialize the BMP18X input device */
+ err = bmp18x_input_init(data);
+ if (err != 0)
+ goto exit_free;
+
+ /* Register sysfs hooks */
+ err = sysfs_create_group(&data->input->dev.kobj, &bmp18x_attr_group);
+ if (err)
+ goto error_sysfs;
+ /* workqueue init */
+ INIT_DELAYED_WORK(&data->work, bmp18x_work_func);
+ data->delay = BMP_DELAY_DEFAULT;
+ data->enable = 0;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+ data->early_suspend.suspend = bmp18x_early_suspend;
+ data->early_suspend.resume = bmp18x_late_resume;
+ register_early_suspend(&data->early_suspend);
+#endif
+
+ dev_info(dev, "Succesfully initialized bmp18x!\n");
+ return 0;
+
+error_sysfs:
+ bmp18x_input_delete(data);
+exit_free:
+ kfree(data);
+exit:
+ if (pdata && pdata->deinit_hw)
+ pdata->deinit_hw(data_bus);
+ return err;
+}
+EXPORT_SYMBOL(bmp18x_probe);
+
+int bmp18x_remove(struct device *dev)
+{
+ struct bmp18x_data *data = dev_get_drvdata(dev);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ unregister_early_suspend(&data->early_suspend);
+#endif
+ sysfs_remove_group(&data->input->dev.kobj, &bmp18x_attr_group);
+ kfree(data);
+
+ return 0;
+}
+EXPORT_SYMBOL(bmp18x_remove);
+
+#ifdef CONFIG_PM
+int bmp18x_disable(struct device *dev)
+{
+ struct bmp18x_platform_data *pdata = dev->platform_data;
+ struct bmp18x_data *data = dev_get_drvdata(dev);
+ if (pdata && pdata->deinit_hw)
+ pdata->deinit_hw(&data->data_bus);
+
+ return 0;
+}
+EXPORT_SYMBOL(bmp18x_disable);
+
+int bmp18x_enable(struct device *dev)
+{
+ struct bmp18x_platform_data *pdata = dev->platform_data;
+ struct bmp18x_data *data = dev_get_drvdata(dev);
+ if (pdata && pdata->init_hw)
+ return pdata->init_hw(&data->data_bus);
+
+ return 0;
+}
+EXPORT_SYMBOL(bmp18x_enable);
+#endif
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void bmp18x_early_suspend(struct early_suspend *h)
+{
+ struct bmp18x_data *data =
+ container_of(h, struct bmp18x_data, early_suspend);
+ if (data->enable) {
+ cancel_delayed_work_sync(&data->work);
+ (void) bmp18x_disable(data->dev);
+ }
+}
+
+static void bmp18x_late_resume(struct early_suspend *h)
+{
+ struct bmp18x_data *data =
+ container_of(h, struct bmp18x_data, early_suspend);
+
+ if (data->enable) {
+ (void) bmp18x_enable(data->dev);
+ schedule_delayed_work(&data->work,
+ msecs_to_jiffies(data->delay));
+ }
+
+}
+#endif
+
+MODULE_AUTHOR("Eric Andersson <eric.andersson@unixphere.com>");
+MODULE_DESCRIPTION("BMP18X driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/bmp18x-i2c.c b/drivers/input/misc/bmp18x-i2c.c
new file mode 100644
index 0000000..abbe6e5
--- /dev/null
+++ b/drivers/input/misc/bmp18x-i2c.c
@@ -0,0 +1,275 @@
+/* Copyright (c) 2011 Bosch Sensortec GmbH
+ Copyright (c) 2011 Unixphere
+
+ Based on:
+ BMP085 driver, bmp085.c
+ Copyright (c) 2010 Christoph Mair <christoph.mair@gmail.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/regulator/consumer.h>
+#include "bmp18x.h"
+
+struct sensor_regulator {
+ struct regulator *vreg;
+ const char *name;
+ u32 min_uV;
+ u32 max_uV;
+};
+
+struct sensor_regulator bmp_vreg[] = {
+ {NULL, "vdd", 2850000, 2850000},
+ {NULL, "vddio", 1800000, 1800000},
+};
+
+
+static int bmp18x_config_regulator(struct i2c_client *client, bool on)
+{
+ int rc = 0, i;
+ int num_vreg = ARRAY_SIZE(bmp_vreg);
+
+ if (on) {
+ for (i = 0; i < num_vreg; i++) {
+ bmp_vreg[i].vreg = regulator_get(&client->dev,
+ bmp_vreg[i].name);
+ if (IS_ERR(bmp_vreg[i].vreg)) {
+ rc = PTR_ERR(bmp_vreg[i].vreg);
+ dev_err(&client->dev, "%s:regulator get failed rc=%d\n",
+ __func__, rc);
+ bmp_vreg[i].vreg = NULL;
+ goto error_vdd;
+ }
+ if (regulator_count_voltages(bmp_vreg[i].vreg) > 0) {
+ rc = regulator_set_voltage(bmp_vreg[i].vreg,
+ bmp_vreg[i].min_uV, bmp_vreg[i].max_uV);
+ if (rc) {
+ dev_err(&client->dev, "%s:set_voltage failed rc=%d\n",
+ __func__, rc);
+ regulator_put(bmp_vreg[i].vreg);
+ bmp_vreg[i].vreg = NULL;
+ goto error_vdd;
+ }
+ }
+ rc = regulator_enable(bmp_vreg[i].vreg);
+ if (rc) {
+ dev_err(&client->dev, "%s: regulator_enable failed rc =%d\n",
+ __func__, rc);
+ if (regulator_count_voltages(bmp_vreg[i].vreg)
+ > 0) {
+ regulator_set_voltage(bmp_vreg[i].vreg,
+ 0, bmp_vreg[i].max_uV);
+ }
+ regulator_put(bmp_vreg[i].vreg);
+ bmp_vreg[i].vreg = NULL;
+ goto error_vdd;
+ }
+ }
+ return rc;
+ } else {
+ i = num_vreg;
+ }
+error_vdd:
+ while (--i >= 0) {
+ if (!IS_ERR_OR_NULL(bmp_vreg[i].vreg)) {
+ if (regulator_count_voltages(
+ bmp_vreg[i].vreg) > 0) {
+ regulator_set_voltage(bmp_vreg[i].vreg, 0,
+ bmp_vreg[i].max_uV);
+ }
+ regulator_disable(bmp_vreg[i].vreg);
+ regulator_put(bmp_vreg[i].vreg);
+ bmp_vreg[i].vreg = NULL;
+ }
+ }
+ return rc;
+}
+
+static int bmp18x_init_hw(struct bmp18x_data_bus *data_bus)
+{
+ if (data_bus->client)
+ return bmp18x_config_regulator(data_bus->client, 1);
+ return 0;
+}
+
+static void bmp18x_deinit_hw(struct bmp18x_data_bus *data_bus)
+{
+ if (data_bus->client)
+ bmp18x_config_regulator(data_bus->client, 0);
+}
+
+#ifdef CONFIG_OF
+static int bmp18x_parse_dt(struct device *dev,
+ struct bmp18x_platform_data *pdata)
+{
+ int ret = 0;
+ u32 val;
+
+ ret = of_property_read_u32(dev->of_node, "bosch,chip-id", &val);
+ if (ret) {
+ dev_err(dev, "no chip_id from dt\n");
+ return ret;
+ }
+ pdata->chip_id = (u8)val;
+
+ ret = of_property_read_u32(dev->of_node, "bosch,oversample", &val);
+ if (ret) {
+ dev_err(dev, "no default_oversampling from dt\n");
+ return ret;
+ }
+ pdata->default_oversampling = (u8)val;
+
+ ret = of_property_read_u32(dev->of_node, "bosch,period",
+ &pdata->temp_measurement_period);
+ if (ret) {
+ dev_err(dev, "no temp_measurement_period from dt\n");
+ return ret;
+ }
+
+ pdata->default_sw_oversampling = of_property_read_bool(dev->of_node,
+ "bosch,sw-oversample");
+ return 0;
+}
+#else
+static int bmp18x_parse_dt(struct device *dev,
+ struct bmp18x_platform_data *pdata)
+{
+ return -EINVAL;
+}
+#endif
+
+static int bmp18x_i2c_read_block(void *client, u8 reg, int len, char *buf)
+{
+ return i2c_smbus_read_i2c_block_data(client, reg, len, buf);
+}
+
+static int bmp18x_i2c_read_byte(void *client, u8 reg)
+{
+ return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int bmp18x_i2c_write_byte(void *client, u8 reg, u8 value)
+{
+ return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static const struct bmp18x_bus_ops bmp18x_i2c_bus_ops = {
+ .read_block = bmp18x_i2c_read_block,
+ .read_byte = bmp18x_i2c_read_byte,
+ .write_byte = bmp18x_i2c_write_byte
+};
+
+static int __devinit bmp18x_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct bmp18x_data_bus data_bus = {
+ .bops = &bmp18x_i2c_bus_ops,
+ .client = client
+ };
+ struct bmp18x_platform_data *pdata;
+ int ret;
+
+ if (client->dev.of_node) {
+ pdata = devm_kzalloc(&client->dev,
+ sizeof(struct bmp18x_platform_data), GFP_KERNEL);
+ if (!pdata) {
+ dev_err(&client->dev, "Failed to allocate memory\n");
+ return -ENOMEM;
+ }
+ ret = bmp18x_parse_dt(&client->dev, pdata);
+ if (ret) {
+ dev_err(&client->dev, "Failed to parse device tree\n");
+ return ret;
+ }
+ pdata->init_hw = bmp18x_init_hw;
+ pdata->deinit_hw = bmp18x_deinit_hw;
+ client->dev.platform_data = pdata;
+ }
+ return bmp18x_probe(&client->dev, &data_bus);
+}
+
+static void bmp18x_i2c_shutdown(struct i2c_client *client)
+{
+ bmp18x_disable(&client->dev);
+}
+
+static int bmp18x_i2c_remove(struct i2c_client *client)
+{
+ return bmp18x_remove(&client->dev);
+}
+
+#ifdef CONFIG_PM
+static int bmp18x_i2c_suspend(struct device *dev)
+{
+ return bmp18x_disable(dev);
+}
+
+static int bmp18x_i2c_resume(struct device *dev)
+{
+ return bmp18x_enable(dev);
+}
+
+static const struct dev_pm_ops bmp18x_i2c_pm_ops = {
+ .suspend = bmp18x_i2c_suspend,
+ .resume = bmp18x_i2c_resume
+};
+#endif
+
+static const struct i2c_device_id bmp18x_id[] = {
+ { BMP18X_NAME, 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, bmp18x_id);
+
+static const struct of_device_id bmp18x_of_match[] = {
+ { .compatible = "bosch,bmp180", },
+ { },
+};
+
+static struct i2c_driver bmp18x_i2c_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = BMP18X_NAME,
+#ifdef CONFIG_PM
+ .pm = &bmp18x_i2c_pm_ops,
+#endif
+ .of_match_table = bmp18x_of_match,
+ },
+ .id_table = bmp18x_id,
+ .probe = bmp18x_i2c_probe,
+ .shutdown = bmp18x_i2c_shutdown,
+ .remove = __devexit_p(bmp18x_i2c_remove)
+};
+
+static int __init bmp18x_i2c_init(void)
+{
+ return i2c_add_driver(&bmp18x_i2c_driver);
+}
+
+static void __exit bmp18x_i2c_exit(void)
+{
+ i2c_del_driver(&bmp18x_i2c_driver);
+}
+
+
+MODULE_AUTHOR("Eric Andersson <eric.andersson@unixphere.com>");
+MODULE_DESCRIPTION("BMP18X I2C bus driver");
+MODULE_LICENSE("GPL");
+
+module_init(bmp18x_i2c_init);
+module_exit(bmp18x_i2c_exit);
diff --git a/drivers/input/misc/bmp18x.h b/drivers/input/misc/bmp18x.h
new file mode 100644
index 0000000..d1b1ee7
--- /dev/null
+++ b/drivers/input/misc/bmp18x.h
@@ -0,0 +1,65 @@
+/* Copyright (c) 2010 Christoph Mair <christoph.mair@gmail.com>
+ Copyright (c) 2011 Bosch Sensortec GmbH
+ Copyright (c) 2011 Unixphere AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+#ifndef _BMP18X_H
+#define _BMP18X_H
+
+#define BMP18X_NAME "bmp18x"
+
+/**
+ * struct bmp18x_platform_data - represents platform data for the bmp18x driver
+ * @chip_id: Configurable chip id for non-default chip revisions
+ * @default_oversampling: Default oversampling value to be used at startup,
+ * value range is 0-3 with rising sensitivity.
+ * @default_sw_oversampling: Default software oversampling value to be used
+ * at startup,value range is 0(Disabled) or 1(Enabled). Only take effect
+ * when default_oversampling is 3.
+ * @temp_measurement_period: Temperature measurement period (milliseconds), set
+ * to zero if unsure.
+ * @init_hw: Callback for hw specific startup
+ * @deinit_hw: Callback for hw specific shutdown
+ */
+
+struct bmp18x_bus_ops {
+ int (*read_block)(void *client, u8 reg, int len, char *buf);
+ int (*read_byte)(void *client, u8 reg);
+ int (*write_byte)(void *client, u8 reg, u8 value);
+};
+
+struct bmp18x_data_bus {
+ const struct bmp18x_bus_ops *bops;
+ void *client;
+};
+
+struct bmp18x_platform_data {
+ u8 chip_id;
+ u8 default_oversampling;
+ u8 default_sw_oversampling;
+ u32 temp_measurement_period;
+ int (*init_hw)(struct bmp18x_data_bus *);
+ void (*deinit_hw)(struct bmp18x_data_bus *);
+};
+
+int bmp18x_probe(struct device *dev, struct bmp18x_data_bus *data_bus);
+int bmp18x_remove(struct device *dev);
+#ifdef CONFIG_PM
+int bmp18x_enable(struct device *dev);
+int bmp18x_disable(struct device *dev);
+#endif
+
+#endif
diff --git a/drivers/input/misc/kxtj9.c b/drivers/input/misc/kxtj9.c
index dd2e5d8..f879d78 100644
--- a/drivers/input/misc/kxtj9.c
+++ b/drivers/input/misc/kxtj9.c
@@ -756,7 +756,10 @@
kxtj9_pdata->negate_z = of_property_read_bool(np, "kionix,negate-z");
- kxtj9_pdata->res_12bit = of_property_read_bool(np, "kionix,res-12bit");
+ if (of_property_read_bool(np, "kionix,res-12bit"))
+ kxtj9_pdata->res_ctl = RES_12BIT;
+ else
+ kxtj9_pdata->res_ctl = RES_8BIT;
return 0;
}
@@ -834,7 +837,7 @@
i2c_set_clientdata(client, tj9);
- tj9->ctrl_reg1 = tj9->pdata.res_12bit | tj9->pdata.g_range;
+ tj9->ctrl_reg1 = tj9->pdata.res_ctl | tj9->pdata.g_range;
tj9->last_poll_interval = tj9->pdata.init_interval;
if (client->irq) {
diff --git a/drivers/input/misc/mma8x5x.c b/drivers/input/misc/mma8x5x.c
new file mode 100644
index 0000000..4b78903
--- /dev/null
+++ b/drivers/input/misc/mma8x5x.c
@@ -0,0 +1,685 @@
+/*
+ * mma8x5x.c - Linux kernel modules for 3-Axis Orientation/Motion
+ * Detection Sensor MMA8451/MMA8452/MMA8453
+ *
+ * Copyright (c) 2013, 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.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/input-polldev.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of_gpio.h>
+
+#define ACCEL_INPUT_DEV_NAME "accelerometer"
+#define MMA8451_ID 0x1A
+#define MMA8452_ID 0x2A
+#define MMA8453_ID 0x3A
+#define MMA8652_ID 0x4A
+#define MMA8653_ID 0x5A
+
+
+#define POLL_INTERVAL_MIN 1
+#define POLL_INTERVAL_MAX 500
+#define POLL_INTERVAL 100 /* msecs */
+
+/* if sensor is standby ,set POLL_STOP_TIME to slow down the poll */
+#define POLL_STOP_TIME 200
+#define INPUT_FUZZ 32
+#define INPUT_FLAT 32
+#define INPUT_DATA_DIVIDER 16
+#define MODE_CHANGE_DELAY_MS 100
+
+#define MMA8X5X_STATUS_ZYXDR 0x08
+#define MMA8X5X_BUF_SIZE 7
+
+struct sensor_regulator {
+ struct regulator *vreg;
+ const char *name;
+ u32 min_uV;
+ u32 max_uV;
+};
+
+static struct sensor_regulator mma_vreg[] = {
+ {NULL, "vdd", 2850000, 2850000},
+ {NULL, "vio", 1800000, 1800000},
+};
+
+/* register enum for mma8x5x registers */
+enum {
+ MMA8X5X_STATUS = 0x00,
+ MMA8X5X_OUT_X_MSB,
+ MMA8X5X_OUT_X_LSB,
+ MMA8X5X_OUT_Y_MSB,
+ MMA8X5X_OUT_Y_LSB,
+ MMA8X5X_OUT_Z_MSB,
+ MMA8X5X_OUT_Z_LSB,
+
+ MMA8X5X_F_SETUP = 0x09,
+ MMA8X5X_TRIG_CFG,
+ MMA8X5X_SYSMOD,
+ MMA8X5X_INT_SOURCE,
+ MMA8X5X_WHO_AM_I,
+ MMA8X5X_XYZ_DATA_CFG,
+ MMA8X5X_HP_FILTER_CUTOFF,
+
+ MMA8X5X_PL_STATUS,
+ MMA8X5X_PL_CFG,
+ MMA8X5X_PL_COUNT,
+ MMA8X5X_PL_BF_ZCOMP,
+ MMA8X5X_P_L_THS_REG,
+
+ MMA8X5X_FF_MT_CFG,
+ MMA8X5X_FF_MT_SRC,
+ MMA8X5X_FF_MT_THS,
+ MMA8X5X_FF_MT_COUNT,
+
+ MMA8X5X_TRANSIENT_CFG = 0x1D,
+ MMA8X5X_TRANSIENT_SRC,
+ MMA8X5X_TRANSIENT_THS,
+ MMA8X5X_TRANSIENT_COUNT,
+
+ MMA8X5X_PULSE_CFG,
+ MMA8X5X_PULSE_SRC,
+ MMA8X5X_PULSE_THSX,
+ MMA8X5X_PULSE_THSY,
+ MMA8X5X_PULSE_THSZ,
+ MMA8X5X_PULSE_TMLT,
+ MMA8X5X_PULSE_LTCY,
+ MMA8X5X_PULSE_WIND,
+
+ MMA8X5X_ASLP_COUNT,
+ MMA8X5X_CTRL_REG1,
+ MMA8X5X_CTRL_REG2,
+ MMA8X5X_CTRL_REG3,
+ MMA8X5X_CTRL_REG4,
+ MMA8X5X_CTRL_REG5,
+
+ MMA8X5X_OFF_X,
+ MMA8X5X_OFF_Y,
+ MMA8X5X_OFF_Z,
+
+ MMA8X5X_REG_END,
+};
+
+/* The sensitivity is represented in counts/g. In 2g mode the
+sensitivity is 1024 counts/g. In 4g mode the sensitivity is 512
+counts/g and in 8g mode the sensitivity is 256 counts/g.
+ */
+enum {
+ MODE_2G = 0,
+ MODE_4G,
+ MODE_8G,
+};
+
+enum {
+ MMA_STANDBY = 0,
+ MMA_ACTIVED,
+};
+struct mma8x5x_data_axis {
+ short x;
+ short y;
+ short z;
+};
+struct mma8x5x_data {
+ struct i2c_client *client;
+ struct input_polled_dev *poll_dev;
+ struct mutex data_lock;
+ int active;
+ int position;
+ u8 chip_id;
+ int mode;
+ int int_pin;
+ u32 int_flags;
+};
+/* Addresses scanned */
+static const unsigned short normal_i2c[] = {0x1c, 0x1d, I2C_CLIENT_END};
+
+static int mma8x5x_chip_id[] = {
+ MMA8451_ID,
+ MMA8452_ID,
+ MMA8453_ID,
+ MMA8652_ID,
+ MMA8653_ID,
+};
+static char *mma8x5x_names[] = {
+ "mma8451",
+ "mma8452",
+ "mma8453",
+ "mma8652",
+ "mma8653",
+};
+static int mma8x5x_position_setting[8][3][3] = {
+ {{ 0, -1, 0}, { 1, 0, 0}, {0, 0, 1} },
+ {{-1, 0, 0}, { 0, -1, 0}, {0, 0, 1} },
+ {{ 0, 1, 0}, {-1, 0, 0}, {0, 0, 1} },
+ {{ 1, 0, 0}, { 0, 1, 0}, {0, 0, 1} },
+ {{ 0, -1, 0}, {-1, 0, 0}, {0, 0, -1} },
+ {{-1, 0, 0}, { 0, 1, 0}, {0, 0, -1} },
+ {{ 0, 1, 0}, { 1, 0, 0}, {0, 0, -1} },
+ {{ 1, 0, 0}, { 0, -1, 0}, {0, 0, -1} },
+};
+
+static int mma8x5x_config_regulator(struct i2c_client *client, bool on)
+{
+ int rc = 0, i;
+ int num_vreg = sizeof(mma_vreg)/sizeof(struct sensor_regulator);
+
+ if (on) {
+ for (i = 0; i < num_vreg; i++) {
+ mma_vreg[i].vreg = regulator_get(&client->dev,
+ mma_vreg[i].name);
+ if (IS_ERR(mma_vreg[i].vreg)) {
+ rc = PTR_ERR(mma_vreg[i].vreg);
+ dev_err(&client->dev, "%s:regulator get failed rc=%d\n",
+ __func__, rc);
+ mma_vreg[i].vreg = NULL;
+ goto error_vdd;
+ }
+ if (regulator_count_voltages(mma_vreg[i].vreg) > 0) {
+ rc = regulator_set_voltage(mma_vreg[i].vreg,
+ mma_vreg[i].min_uV, mma_vreg[i].max_uV);
+ if (rc) {
+ dev_err(&client->dev, "%s:set_voltage failed rc=%d\n",
+ __func__, rc);
+ regulator_put(mma_vreg[i].vreg);
+ mma_vreg[i].vreg = NULL;
+ goto error_vdd;
+ }
+ }
+ rc = regulator_enable(mma_vreg[i].vreg);
+ if (rc) {
+ dev_err(&client->dev, "%s: regulator_enable failed rc =%d\n",
+ __func__, rc);
+ if (regulator_count_voltages(mma_vreg[i].vreg)
+ > 0) {
+ regulator_set_voltage(mma_vreg[i].vreg,
+ 0, mma_vreg[i].max_uV);
+ }
+ regulator_put(mma_vreg[i].vreg);
+ mma_vreg[i].vreg = NULL;
+ goto error_vdd;
+ }
+ }
+ return rc;
+ } else {
+ i = num_vreg;
+ }
+error_vdd:
+ while (--i >= 0) {
+ if (!IS_ERR_OR_NULL(mma_vreg[i].vreg)) {
+ if (regulator_count_voltages(
+ mma_vreg[i].vreg) > 0) {
+ regulator_set_voltage(mma_vreg[i].vreg, 0,
+ mma_vreg[i].max_uV);
+ }
+ regulator_disable(mma_vreg[i].vreg);
+ regulator_put(mma_vreg[i].vreg);
+ mma_vreg[i].vreg = NULL;
+ }
+ }
+ return rc;
+}
+
+static int mma8x5x_data_convert(struct mma8x5x_data *pdata,
+ struct mma8x5x_data_axis *axis_data)
+{
+ short rawdata[3], data[3];
+ int i, j;
+ int position = pdata->position ;
+ if (position < 0 || position > 7)
+ position = 0;
+ rawdata[0] = axis_data->x;
+ rawdata[1] = axis_data->y;
+ rawdata[2] = axis_data->z;
+ for (i = 0; i < 3 ; i++) {
+ data[i] = 0;
+ for (j = 0; j < 3; j++)
+ data[i] += rawdata[j] *
+ mma8x5x_position_setting[position][i][j];
+ }
+ axis_data->x = data[0]/INPUT_DATA_DIVIDER;
+ axis_data->y = data[1]/INPUT_DATA_DIVIDER;
+ axis_data->z = data[2]/INPUT_DATA_DIVIDER;
+ return 0;
+}
+static int mma8x5x_check_id(int id)
+{
+ int i = 0;
+ for (i = 0; i < sizeof(mma8x5x_chip_id)/sizeof(mma8x5x_chip_id[0]);
+ i++)
+ if (id == mma8x5x_chip_id[i])
+ return 1;
+ return 0;
+}
+static char *mma8x5x_id2name(u8 id)
+{
+ return mma8x5x_names[(id >> 4)-1];
+}
+static int mma8x5x_device_init(struct i2c_client *client)
+{
+ int result;
+ struct mma8x5x_data *pdata = i2c_get_clientdata(client);
+ result = i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG1, 0);
+ if (result < 0)
+ goto out;
+
+ result = i2c_smbus_write_byte_data(client, MMA8X5X_XYZ_DATA_CFG,
+ pdata->mode);
+ if (result < 0)
+ goto out;
+ pdata->active = MMA_STANDBY;
+ msleep(MODE_CHANGE_DELAY_MS);
+ return 0;
+out:
+ dev_err(&client->dev, "error when init mma8x5x:(%d)", result);
+ return result;
+}
+static int mma8x5x_device_stop(struct i2c_client *client)
+{
+ u8 val;
+ val = i2c_smbus_read_byte_data(client, MMA8X5X_CTRL_REG1);
+ i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG1, val & 0xfe);
+ return 0;
+}
+
+static int mma8x5x_read_data(struct i2c_client *client,
+ struct mma8x5x_data_axis *data)
+{
+ u8 tmp_data[MMA8X5X_BUF_SIZE];
+ int ret;
+
+ ret = i2c_smbus_read_i2c_block_data(client,
+ MMA8X5X_OUT_X_MSB, 7, tmp_data);
+ if (ret < MMA8X5X_BUF_SIZE) {
+ dev_err(&client->dev, "i2c block read failed\n");
+ return -EIO;
+ }
+ data->x = ((tmp_data[0] << 8) & 0xff00) | tmp_data[1];
+ data->y = ((tmp_data[2] << 8) & 0xff00) | tmp_data[3];
+ data->z = ((tmp_data[4] << 8) & 0xff00) | tmp_data[5];
+ return 0;
+}
+
+static void mma8x5x_report_data(struct mma8x5x_data *pdata)
+{
+ struct input_polled_dev *poll_dev = pdata->poll_dev;
+ struct mma8x5x_data_axis data;
+ mutex_lock(&pdata->data_lock);
+ if (pdata->active == 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;
+ }
+ if (mma8x5x_read_data(pdata->client, &data) != 0)
+ goto out;
+ mma8x5x_data_convert(pdata, &data);
+ input_report_abs(poll_dev->input, ABS_X, data.x);
+ input_report_abs(poll_dev->input, ABS_Y, data.y);
+ input_report_abs(poll_dev->input, ABS_Z, data.z);
+ input_sync(poll_dev->input);
+out:
+ mutex_unlock(&pdata->data_lock);
+}
+
+static void mma8x5x_dev_poll(struct input_polled_dev *dev)
+{
+ struct mma8x5x_data *pdata = (struct mma8x5x_data *)dev->private;
+ mma8x5x_report_data(pdata);
+}
+
+static ssize_t mma8x5x_enable_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);
+ struct i2c_client *client = pdata->client;
+ u8 val;
+ int enable;
+
+ mutex_lock(&pdata->data_lock);
+ val = i2c_smbus_read_byte_data(client, MMA8X5X_CTRL_REG1);
+ if ((val & 0x01) && pdata->active == MMA_ACTIVED)
+ enable = 1;
+ else
+ enable = 0;
+ mutex_unlock(&pdata->data_lock);
+ return snprintf(buf, PAGE_SIZE, "%d\n", enable);
+}
+
+static ssize_t mma8x5x_enable_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);
+ 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 && pdata->active == MMA_STANDBY) {
+ val = i2c_smbus_read_byte_data(client, MMA8X5X_CTRL_REG1);
+ ret = i2c_smbus_write_byte_data(client,
+ MMA8X5X_CTRL_REG1, val|0x01);
+ if (!ret) {
+ pdata->active = MMA_ACTIVED;
+ dev_dbg(dev,
+ "%s:mma enable setting active.\n", __func__);
+ }
+ } else if (enable == 0 && pdata->active == MMA_ACTIVED) {
+ val = i2c_smbus_read_byte_data(client, MMA8X5X_CTRL_REG1);
+ ret = i2c_smbus_write_byte_data(client,
+ MMA8X5X_CTRL_REG1, val & 0xFE);
+ if (!ret) {
+ pdata->active = MMA_STANDBY;
+ dev_dbg(dev,
+ "%s:mma enable setting inactive.\n", __func__);
+ }
+ }
+ mutex_unlock(&pdata->data_lock);
+ return count;
+}
+static ssize_t mma8x5x_position_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);
+ int position = 0;
+ mutex_lock(&pdata->data_lock);
+ position = pdata->position ;
+ mutex_unlock(&pdata->data_lock);
+ return snprintf(buf, PAGE_SIZE, "%d\n", position);
+}
+
+static ssize_t mma8x5x_position_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 position;
+ int ret;
+ ret = kstrtoint(buf, 10, &position);
+ if (ret)
+ return ret;
+ mutex_lock(&pdata->data_lock);
+ pdata->position = position;
+ mutex_unlock(&pdata->data_lock);
+ 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 struct attribute *mma8x5x_attributes[] = {
+ &dev_attr_enable.attr,
+ &dev_attr_position.attr,
+ NULL
+};
+
+static const struct attribute_group mma8x5x_attr_group = {
+ .attrs = mma8x5x_attributes,
+};
+static int mma8x5x_detect(struct i2c_client *client,
+ struct i2c_board_info *info)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ int chip_id;
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_WORD_DATA))
+ return -ENODEV;
+ chip_id = i2c_smbus_read_byte_data(client, MMA8X5X_WHO_AM_I);
+ if (!mma8x5x_check_id(chip_id))
+ return -ENODEV;
+ dev_dbg(&client->dev, "%s,check %s i2c address 0x%x.\n",
+ __func__, mma8x5x_id2name(chip_id), client->addr);
+ strlcpy(info->type, "mma8x5x", I2C_NAME_SIZE);
+ return 0;
+}
+
+static int mma8x5x_parse_dt(struct device *dev, struct mma8x5x_data *data)
+{
+ int rc;
+ struct device_node *np = dev->of_node;
+ u32 temp_val;
+
+ data->int_pin = of_get_named_gpio_flags(np, "fsl,irq-gpio",
+ 0, &data->int_flags);
+ if (data->int_pin < 0) {
+ dev_err(dev, "Unable to read irq-gpio\n");
+ return data->int_pin;
+ }
+
+ rc = of_property_read_u32(np, "fsl,sensors-position", &temp_val);
+ if (!rc)
+ data->position = temp_val;
+ else {
+ dev_err(dev, "Unable to read sensors-position\n");
+ return rc;
+ }
+
+ return 0;
+}
+
+static int __devinit mma8x5x_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int result, chip_id;
+ struct input_dev *idev;
+ struct mma8x5x_data *pdata;
+ struct i2c_adapter *adapter;
+ struct input_polled_dev *poll_dev;
+ adapter = to_i2c_adapter(client->dev.parent);
+ /* power on the device */
+ result = mma8x5x_config_regulator(client, 1);
+ if (result)
+ goto err_power_on;
+
+ result = i2c_check_functionality(adapter,
+ I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA);
+ if (!result)
+ goto err_out;
+
+ chip_id = i2c_smbus_read_byte_data(client, MMA8X5X_WHO_AM_I);
+
+ if (!mma8x5x_check_id(chip_id)) {
+ dev_err(&client->dev,
+ "read chip ID 0x%x is not equal to 0x%x,0x%x,0x%x,0x%x,0x%x!\n",
+ chip_id, MMA8451_ID, MMA8452_ID, MMA8453_ID,
+ MMA8652_ID, MMA8653_ID);
+ result = -EINVAL;
+ goto err_out;
+ }
+ /* set the private data */
+ pdata = kzalloc(sizeof(struct mma8x5x_data), GFP_KERNEL);
+ if (!pdata) {
+ result = -ENOMEM;
+ dev_err(&client->dev, "alloc data memory error!\n");
+ goto err_out;
+ }
+
+ if (client->dev.of_node) {
+ result = mma8x5x_parse_dt(&client->dev, pdata);
+ if (result)
+ return result;
+ } else {
+ pdata->position = CONFIG_SENSORS_MMA_POSITION;
+ pdata->int_pin = -1;
+ pdata->int_flags = 0;
+ }
+
+ /* Initialize the MMA8X5X chip */
+ pdata->client = client;
+ pdata->chip_id = chip_id;
+ pdata->mode = MODE_2G;
+
+ mutex_init(&pdata->data_lock);
+ i2c_set_clientdata(client, pdata);
+ /* Initialize the MMA8X5X chip */
+ mma8x5x_device_init(client);
+ /* create the input poll device */
+ poll_dev = input_allocate_polled_device();
+ if (!poll_dev) {
+ result = -ENOMEM;
+ dev_err(&client->dev, "alloc poll device failed!\n");
+ goto err_alloc_poll_device;
+ }
+ poll_dev->poll = mma8x5x_dev_poll;
+ poll_dev->poll_interval = POLL_STOP_TIME;
+ poll_dev->poll_interval_min = POLL_INTERVAL_MIN;
+ poll_dev->poll_interval_max = POLL_INTERVAL_MAX;
+ poll_dev->private = pdata;
+ idev = poll_dev->input;
+ idev->name = ACCEL_INPUT_DEV_NAME;
+ idev->uniq = mma8x5x_id2name(pdata->chip_id);
+ idev->id.bustype = BUS_I2C;
+ idev->evbit[0] = BIT_MASK(EV_ABS);
+ input_set_abs_params(idev, ABS_X, -0x7fff, 0x7fff, 0, 0);
+ input_set_abs_params(idev, ABS_Y, -0x7fff, 0x7fff, 0, 0);
+ input_set_abs_params(idev, ABS_Z, -0x7fff, 0x7fff, 0, 0);
+ pdata->poll_dev = poll_dev;
+ result = input_register_polled_device(pdata->poll_dev);
+ if (result) {
+ dev_err(&client->dev, "register poll device failed!\n");
+ goto err_register_polled_device;
+ }
+ result = sysfs_create_group(&idev->dev.kobj, &mma8x5x_attr_group);
+ if (result) {
+ dev_err(&client->dev, "create device file failed!\n");
+ result = -EINVAL;
+ goto err_create_sysfs;
+ }
+ dev_info(&client->dev,
+ "%s:mma8x5x device driver probe successfully, position =%d\n",
+ __func__, pdata->position);
+
+ return 0;
+err_create_sysfs:
+ input_unregister_polled_device(pdata->poll_dev);
+err_register_polled_device:
+ input_free_polled_device(poll_dev);
+err_alloc_poll_device:
+ kfree(pdata);
+err_out:
+ mma8x5x_config_regulator(client, 0);
+err_power_on:
+ return result;
+}
+static int __devexit mma8x5x_remove(struct i2c_client *client)
+{
+ struct mma8x5x_data *pdata = i2c_get_clientdata(client);
+ struct input_polled_dev *poll_dev;
+ mma8x5x_device_stop(client);
+ if (pdata) {
+ poll_dev = pdata->poll_dev;
+ input_unregister_polled_device(poll_dev);
+ input_free_polled_device(poll_dev);
+ kfree(pdata);
+ }
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int mma8x5x_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct mma8x5x_data *pdata = i2c_get_clientdata(client);
+ if (pdata->active == MMA_ACTIVED)
+ mma8x5x_device_stop(client);
+ return 0;
+}
+
+static int mma8x5x_resume(struct device *dev)
+{
+ int val = 0;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct mma8x5x_data *pdata = i2c_get_clientdata(client);
+ if (pdata->active == MMA_ACTIVED) {
+ val = i2c_smbus_read_byte_data(client, MMA8X5X_CTRL_REG1);
+ i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG1, val|0x01);
+ }
+ return 0;
+
+}
+#endif
+
+static const struct i2c_device_id mma8x5x_id[] = {
+ {"mma8x5x", 0},
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, mma8x5x_id);
+
+static const struct of_device_id mma8x5x_of_match[] = {
+ { .compatible = "fsl,mma8x5x", },
+ { },
+};
+
+static SIMPLE_DEV_PM_OPS(mma8x5x_pm_ops, mma8x5x_suspend, mma8x5x_resume);
+static struct i2c_driver mma8x5x_driver = {
+ .class = I2C_CLASS_HWMON,
+ .driver = {
+ .name = "mma8x5x",
+ .owner = THIS_MODULE,
+ .pm = &mma8x5x_pm_ops,
+ .of_match_table = mma8x5x_of_match,
+ },
+ .probe = mma8x5x_probe,
+ .remove = __devexit_p(mma8x5x_remove),
+ .id_table = mma8x5x_id,
+ .detect = mma8x5x_detect,
+ .address_list = normal_i2c,
+};
+
+static int __init mma8x5x_init(void)
+{
+ /* register driver */
+ int res;
+
+ res = i2c_add_driver(&mma8x5x_driver);
+ if (res < 0) {
+ pr_info("%s:add mma8x5x i2c driver failed\n", __func__);
+ return -ENODEV;
+ }
+ return res;
+}
+
+static void __exit mma8x5x_exit(void)
+{
+ i2c_del_driver(&mma8x5x_driver);
+}
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MMA8X5X 3-Axis Orientation/Motion Detection Sensor driver");
+MODULE_LICENSE("GPL");
+
+module_init(mma8x5x_init);
+module_exit(mma8x5x_exit);
diff --git a/drivers/input/misc/mpu3050.c b/drivers/input/misc/mpu3050.c
index 6c64a57..519b7e4 100644
--- a/drivers/input/misc/mpu3050.c
+++ b/drivers/input/misc/mpu3050.c
@@ -43,8 +43,8 @@
#include <linux/gpio.h>
#include <linux/input/mpu3050.h>
#include <linux/regulator/consumer.h>
-
-#define MPU3050_CHIP_ID 0x69
+#include <linux/of_gpio.h>
+#include <mach/gpiomux.h>
#define MPU3050_AUTO_DELAY 1000
@@ -124,6 +124,8 @@
u32 use_poll;
u32 poll_interval;
u32 dlpf_index;
+ u32 enable_gpio;
+ u32 enable;
};
struct sensor_regulator {
@@ -138,6 +140,11 @@
{NULL, "vlogic", 1800000, 1800000},
};
+static const int mpu3050_chip_ids[] = {
+ 0x68,
+ 0x69,
+};
+
struct dlpf_cfg_tb {
u8 cfg; /* cfg index */
u32 lpf_bw; /* low pass filter bandwidth in Hz */
@@ -293,11 +300,42 @@
return size;
}
-static struct device_attribute attributes[] = {
+/**
+ * Set/get enable function is just needed by sensor HAL.
+ * Normally, the open function does all the initialization
+ * and power work. And close undo that open does.
+ * Just keeping the function simple.
+ */
+static ssize_t mpu3050_attr_set_enable(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct mpu3050_sensor *sensor = dev_get_drvdata(dev);
+ unsigned long val;
+
+ if (kstrtoul(buf, 10, &val))
+ return -EINVAL;
+ sensor->enable = (u32)val;
+
+ return count;
+}
+
+static ssize_t mpu3050_attr_get_enable(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mpu3050_sensor *sensor = dev_get_drvdata(dev);
+
+ return snprintf(buf, 4, "%d\n", sensor->enable);
+}
+
+static struct device_attribute attributes[] = {
__ATTR(pollrate_ms, 0664,
mpu3050_attr_get_polling_rate,
mpu3050_attr_set_polling_rate),
+ __ATTR(enable, 0644,
+ mpu3050_attr_get_enable,
+ mpu3050_attr_set_enable),
};
static int create_sysfs_interfaces(struct device *dev)
@@ -390,10 +428,12 @@
static void mpu3050_set_power_mode(struct i2c_client *client, u8 val)
{
u8 value;
+ struct mpu3050_sensor *sensor = i2c_get_clientdata(client);
if (val) {
mpu3050_config_regulator(client, 1);
udelay(10);
+ gpio_set_value(sensor->enable_gpio, 1);
}
value = i2c_smbus_read_byte_data(client, MPU3050_PWR_MGM);
@@ -404,6 +444,8 @@
if (!val) {
udelay(10);
+ gpio_set_value(sensor->enable_gpio, 0);
+ udelay(10);
mpu3050_config_regulator(client, 0);
}
}
@@ -550,6 +592,37 @@
return 0;
}
+#ifdef CONFIG_OF
+static int mpu3050_parse_dt(struct device *dev,
+ struct mpu3050_gyro_platform_data *pdata)
+{
+ int rc = 0;
+
+ rc = of_property_read_u32(dev->of_node, "invn,poll-interval",
+ &pdata->poll_interval);
+ if (rc) {
+ dev_err(dev, "Failed to read poll-interval\n");
+ return rc;
+ }
+
+ /* check gpio_int later, if it is invalid, just use poll */
+ pdata->gpio_int = of_get_named_gpio_flags(dev->of_node,
+ "invn,gpio-int", 0, NULL);
+
+ pdata->gpio_en = of_get_named_gpio_flags(dev->of_node,
+ "invn,gpio-en", 0, NULL);
+ if (!gpio_is_valid(pdata->gpio_en))
+ return -EINVAL;
+
+ return 0;
+}
+#else
+static int mpu3050_parse_dt(struct device *dev,
+ struct mpu3050_gyro_platform_data *pdata)
+{
+ return -EINVAL;
+}
+#endif
/**
* mpu3050_probe - device detection callback
@@ -566,8 +639,10 @@
{
struct mpu3050_sensor *sensor;
struct input_dev *idev;
+ struct mpu3050_gyro_platform_data *pdata;
int ret;
int error;
+ u32 i;
sensor = kzalloc(sizeof(struct mpu3050_sensor), GFP_KERNEL);
idev = input_allocate_device();
@@ -580,10 +655,29 @@
sensor->client = client;
sensor->dev = &client->dev;
sensor->idev = idev;
- sensor->platform_data = client->dev.platform_data;
i2c_set_clientdata(client, sensor);
+
+ if (client->dev.of_node) {
+ pdata = devm_kzalloc(&client->dev,
+ sizeof(struct mpu3050_gyro_platform_data), GFP_KERNEL);
+ if (!pdata) {
+ dev_err(&client->dev, "Failed to allcated memory\n");
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+ ret = mpu3050_parse_dt(&client->dev, pdata);
+ if (ret) {
+ dev_err(&client->dev, "Failed to parse device tree\n");
+ error = ret;
+ goto err_free_mem;
+ }
+ } else
+ pdata = client->dev.platform_data;
+ sensor->platform_data = pdata;
+
if (sensor->platform_data) {
u32 interval = sensor->platform_data->poll_interval;
+ sensor->enable_gpio = sensor->platform_data->gpio_en;
if ((interval < MPU3050_MIN_POLL_INTERVAL) ||
(interval > MPU3050_MAX_POLL_INTERVAL))
@@ -592,6 +686,12 @@
sensor->poll_interval = interval;
} else {
sensor->poll_interval = MPU3050_DEFAULT_POLL_INTERVAL;
+ sensor->enable_gpio = -EINVAL;
+ }
+
+ if (gpio_is_valid(sensor->enable_gpio)) {
+ ret = gpio_request(sensor->enable_gpio, "GYRO_EN_PM");
+ gpio_direction_output(sensor->enable_gpio, 1);
}
mpu3050_set_power_mode(client, 1);
@@ -604,7 +704,11 @@
goto err_free_mem;
}
- if (ret != MPU3050_CHIP_ID) {
+ for (i = 0; i < ARRAY_SIZE(mpu3050_chip_ids); i++)
+ if (ret == mpu3050_chip_ids[i])
+ break;
+
+ if (i == ARRAY_SIZE(mpu3050_chip_ids)) {
dev_err(&client->dev, "unsupported chip id\n");
error = -ENXIO;
goto err_free_mem;
@@ -617,7 +721,7 @@
idev->open = mpu3050_input_open;
idev->close = mpu3050_input_close;
- __set_bit(EV_ABS, idev->evbit);
+ input_set_capability(idev, EV_ABS, ABS_MISC);
input_set_abs_params(idev, ABS_X,
MPU3050_MIN_VALUE, MPU3050_MAX_VALUE, 0, 0);
input_set_abs_params(idev, ABS_Y,
@@ -657,6 +761,11 @@
__func__, sensor->platform_data->gpio_int);
goto err_free_gpio;
}
+ client->irq = gpio_to_irq(
+ sensor->platform_data->gpio_int);
+ } else {
+ ret = -EINVAL;
+ goto err_pm_set_suspended;
}
error = request_threaded_irq(client->irq,
@@ -677,14 +786,20 @@
goto err_free_irq;
}
- error = create_sysfs_interfaces(&client->dev);
+ error = create_sysfs_interfaces(&idev->dev);
if (error < 0) {
dev_err(&client->dev, "failed to create sysfs\n");
goto err_input_cleanup;
}
- pm_runtime_enable(&client->dev);
- pm_runtime_set_autosuspend_delay(&client->dev, MPU3050_AUTO_DELAY);
+ 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);
return 0;
@@ -722,6 +837,8 @@
free_irq(client->irq, sensor);
remove_sysfs_interfaces(&client->dev);
+ if (gpio_is_valid(sensor->enable_gpio))
+ gpio_free(sensor->enable_gpio);
input_unregister_device(sensor->idev);
kfree(sensor);
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 479b788..b725200 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -393,6 +393,9 @@
bool update_cfg;
const char *fw_name;
bool no_force_update;
+ bool lpm_support;
+ bool regs_enabled;
+
#if defined(CONFIG_SECURE_TOUCH)
atomic_t st_enabled;
atomic_t st_pending_irqs;
@@ -1993,7 +1996,7 @@
if (atomic_read(&data->st_enabled) == 0)
break;
- pm_runtime_put(&data->client->adapter->dev);
+ pm_runtime_put(data->client->adapter->dev.parent);
atomic_set(&data->st_enabled, 0);
complete(&data->st_completion);
mxt_interrupt(data->client->irq, data);
@@ -2012,8 +2015,9 @@
}
INIT_COMPLETION(data->st_completion);
INIT_COMPLETION(data->st_powerdown);
- atomic_set(&data->st_pending_irqs, 0);
atomic_set(&data->st_enabled, 1);
+ synchronize_irq(data->client->irq);
+ atomic_set(&data->st_pending_irqs, 0);
break;
default:
dev_err(&data->client->dev, "unsupported value: %lu\n", value);
@@ -2158,6 +2162,11 @@
if (on == false)
goto power_off;
+ if (data->regs_enabled) {
+ dev_dbg(&data->client->dev, "regs are already enabled\n");
+ return 0;
+ }
+
rc = reg_set_optimum_mode_check(data->vcc_ana, MXT_ACTIVE_LOAD_UA);
if (rc < 0) {
dev_err(&data->client->dev,
@@ -2206,6 +2215,8 @@
}
}
+ data->regs_enabled = true;
+
msleep(130);
return 0;
@@ -2226,6 +2237,12 @@
return rc;
power_off:
+
+ if (!data->regs_enabled) {
+ dev_dbg(&data->client->dev, "regs are already disabled\n");
+ return 0;
+ }
+
reg_set_optimum_mode_check(data->vcc_ana, 0);
regulator_disable(data->vcc_ana);
if (data->pdata->digital_pwr_regulator) {
@@ -2236,6 +2253,9 @@
reg_set_optimum_mode_check(data->vcc_i2c, 0);
regulator_disable(data->vcc_i2c);
}
+
+ data->regs_enabled = false;
+
msleep(50);
return 0;
}
@@ -2435,8 +2455,9 @@
struct input_dev *input_dev = data->input_dev;
int error;
- mutex_lock(&input_dev->mutex);
+ disable_irq(data->irq);
+ mutex_lock(&input_dev->mutex);
if (input_dev->users) {
error = mxt_stop(data);
if (error < 0) {
@@ -2444,16 +2465,24 @@
mutex_unlock(&input_dev->mutex);
return error;
}
-
}
mutex_unlock(&input_dev->mutex);
+ mxt_release_all(data);
/* put regulators in low power mode */
- error = mxt_regulator_lpm(data, true);
- if (error < 0) {
- dev_err(dev, "failed to enter low power mode\n");
- return error;
+ if (data->lpm_support) {
+ error = mxt_regulator_lpm(data, true);
+ if (error < 0) {
+ dev_err(dev, "failed to enter low power mode\n");
+ return error;
+ }
+ } else {
+ error = mxt_power_on(data, false);
+ if (error < 0) {
+ dev_err(dev, "failed to disable regulators\n");
+ return error;
+ }
}
return 0;
@@ -2466,13 +2495,25 @@
struct input_dev *input_dev = data->input_dev;
int error;
- /* put regulators in high power mode */
- error = mxt_regulator_lpm(data, false);
- if (error < 0) {
- dev_err(dev, "failed to enter high power mode\n");
- return error;
+ /* put regulators back in active power mode */
+ if (data->lpm_support) {
+ error = mxt_regulator_lpm(data, false);
+ if (error < 0) {
+ dev_err(dev, "failed to enter high power mode\n");
+ return error;
+ }
+ } else {
+ error = mxt_power_on(data, true);
+ if (error < 0) {
+ dev_err(dev, "failed to enable regulators\n");
+ return error;
+ }
+ mxt_power_on_delay(data);
}
+ mxt_write_object(data, MXT_GEN_COMMAND_T6, MXT_COMMAND_RESET, 1);
+ mxt_reset_delay(data);
+
mutex_lock(&input_dev->mutex);
if (input_dev->users) {
@@ -2495,6 +2536,8 @@
mutex_unlock(&input_dev->mutex);
+ enable_irq(data->irq);
+
return 0;
}
@@ -2672,6 +2715,9 @@
pdata->no_force_update = of_property_read_bool(np,
"atmel,no-force-update");
+ pdata->no_lpm_support = of_property_read_bool(np,
+ "atmel,no-lpm-support");
+
/* reset, irq gpio info */
pdata->reset_gpio = of_get_named_gpio_flags(np, "atmel,reset-gpio",
0, &pdata->reset_gpio_flags);
@@ -2877,6 +2923,7 @@
data->input_dev = input_dev;
data->pdata = pdata;
data->no_force_update = pdata->no_force_update;
+ data->lpm_support = !pdata->no_lpm_support;
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(EV_KEY, input_dev->evbit);
diff --git a/drivers/input/touchscreen/ft5x06_ts.c b/drivers/input/touchscreen/ft5x06_ts.c
index 8dbac64..25228a6 100644
--- a/drivers/input/touchscreen/ft5x06_ts.c
+++ b/drivers/input/touchscreen/ft5x06_ts.c
@@ -308,7 +308,7 @@
event->pressure = 0;
}
- input_mt_slot(data->input_dev, i);
+ input_mt_slot(data->input_dev, event->finger_id[i]);
input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER,
!!event->pressure);
@@ -317,10 +317,6 @@
event->x[i]);
input_report_abs(data->input_dev, ABS_MT_POSITION_Y,
event->y[i]);
- input_report_abs(data->input_dev, ABS_MT_PRESSURE,
- event->pressure);
- input_report_abs(data->input_dev, ABS_MT_TRACKING_ID,
- event->finger_id[i]);
input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR,
event->pressure);
}
@@ -493,7 +489,8 @@
static int ft5x06_ts_suspend(struct device *dev)
{
struct ft5x06_ts_data *data = dev_get_drvdata(dev);
- char txbuf[2];
+ char txbuf[2], i;
+ int err;
if (data->loading_fw) {
dev_info(dev, "Firmware loading in process...\n");
@@ -507,26 +504,72 @@
disable_irq(data->client->irq);
+ /* release all touches */
+ for (i = 0; i < CFG_MAX_TOUCH_POINTS; i++) {
+ input_mt_slot(data->input_dev, i);
+ input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER, 0);
+ }
+ input_report_key(data->input_dev, BTN_TOUCH, 0);
+ input_sync(data->input_dev);
+
if (gpio_is_valid(data->pdata->reset_gpio)) {
txbuf[0] = FT_REG_PMODE;
txbuf[1] = FT_PMODE_HIBERNATE;
ft5x06_i2c_write(data->client, txbuf, sizeof(txbuf));
}
+ if (data->pdata->power_on) {
+ err = data->pdata->power_on(false);
+ if (err) {
+ dev_err(dev, "power off failed");
+ goto pwr_off_fail;
+ }
+ } else {
+ err = ft5x06_power_on(data, false);
+ if (err) {
+ dev_err(dev, "power off failed");
+ goto pwr_off_fail;
+ }
+ }
+
data->suspended = true;
return 0;
+
+pwr_off_fail:
+ if (gpio_is_valid(data->pdata->reset_gpio)) {
+ gpio_set_value_cansleep(data->pdata->reset_gpio, 0);
+ msleep(FT_RESET_DLY);
+ gpio_set_value_cansleep(data->pdata->reset_gpio, 1);
+ }
+ enable_irq(data->client->irq);
+ return err;
}
static int ft5x06_ts_resume(struct device *dev)
{
struct ft5x06_ts_data *data = dev_get_drvdata(dev);
+ int err;
if (!data->suspended) {
dev_info(dev, "Already in awake state\n");
return 0;
}
+ if (data->pdata->power_on) {
+ err = data->pdata->power_on(true);
+ if (err) {
+ dev_err(dev, "power on failed");
+ return err;
+ }
+ } else {
+ err = ft5x06_power_on(data, true);
+ if (err) {
+ dev_err(dev, "power on failed");
+ return err;
+ }
+ }
+
if (gpio_is_valid(data->pdata->reset_gpio)) {
gpio_set_value_cansleep(data->pdata->reset_gpio, 0);
msleep(FT_RESET_DLY);
@@ -1231,7 +1274,6 @@
input_set_abs_params(input_dev, ABS_MT_POSITION_Y, pdata->y_min,
pdata->y_max, 0, 0);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, FT_PRESS, 0, 0);
- input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, FT_PRESS, 0, 0);
err = input_register_device(input_dev);
if (err) {
@@ -1306,7 +1348,7 @@
err = ft5x06_i2c_read(client, ®_addr, 1, ®_value, 1);
if (err < 0) {
dev_err(&client->dev, "version read failed");
- return err;
+ goto free_reset_gpio;
}
dev_info(&client->dev, "Device ID = 0x%x\n", reg_value);
diff --git a/drivers/input/touchscreen/synaptics_fw_update.c b/drivers/input/touchscreen/synaptics_fw_update.c
index c01ab0e..2a5fea7 100644
--- a/drivers/input/touchscreen/synaptics_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_fw_update.c
@@ -1722,7 +1722,7 @@
static struct bin_attribute dev_attr_data = {
.attr = {
.name = "data",
- .mode = (S_IRUGO | S_IWUGO),
+ .mode = (S_IRUGO | S_IWUSR | S_IWGRP),
},
.size = 0,
.read = fwu_sysfs_show_image,
@@ -1730,25 +1730,25 @@
};
static struct device_attribute attrs[] = {
- __ATTR(fw_name, S_IWUGO | S_IRUGO,
+ __ATTR(fw_name, S_IRUGO | S_IWUSR | S_IWGRP,
fwu_sysfs_fw_name_show,
fwu_sysfs_fw_name_store),
- __ATTR(force_update_fw, S_IWUGO,
+ __ATTR(force_update_fw, S_IRUGO | S_IWUSR | S_IWGRP,
synaptics_rmi4_show_error,
fwu_sysfs_force_reflash_store),
- __ATTR(update_fw, S_IWUGO,
+ __ATTR(update_fw, S_IRUGO | S_IWUSR | S_IWGRP,
synaptics_rmi4_show_error,
fwu_sysfs_do_reflash_store),
- __ATTR(writeconfig, S_IWUGO,
+ __ATTR(writeconfig, S_IRUGO | S_IWUSR | S_IWGRP,
synaptics_rmi4_show_error,
fwu_sysfs_write_config_store),
- __ATTR(readconfig, S_IWUGO,
+ __ATTR(readconfig, S_IRUGO | S_IWUSR | S_IWGRP,
synaptics_rmi4_show_error,
fwu_sysfs_read_config_store),
- __ATTR(configarea, S_IWUGO,
+ __ATTR(configarea, S_IRUGO | S_IWUSR | S_IWGRP,
synaptics_rmi4_show_error,
fwu_sysfs_config_area_store),
- __ATTR(imagesize, S_IWUGO,
+ __ATTR(imagesize, S_IRUGO | S_IWUSR | S_IWGRP,
synaptics_rmi4_show_error,
fwu_sysfs_image_size_store),
__ATTR(blocksize, S_IRUGO,
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
index 9da095a..908d0d7 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.c
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
@@ -235,11 +235,11 @@
static struct device_attribute attrs[] = {
#ifdef CONFIG_PM
- __ATTR(full_pm_cycle, (S_IRUGO | S_IWUGO),
+ __ATTR(full_pm_cycle, (S_IRUGO | S_IWUSR | S_IWGRP),
synaptics_rmi4_full_pm_cycle_show,
synaptics_rmi4_full_pm_cycle_store),
#endif
- __ATTR(reset, S_IWUGO,
+ __ATTR(reset, S_IRUGO | S_IWUSR | S_IWGRP,
synaptics_rmi4_show_error,
synaptics_rmi4_f01_reset_store),
__ATTR(productinfo, S_IRUGO,
@@ -251,13 +251,13 @@
__ATTR(flashprog, S_IRUGO,
synaptics_rmi4_f01_flashprog_show,
synaptics_rmi4_store_error),
- __ATTR(0dbutton, (S_IRUGO | S_IWUGO),
+ __ATTR(0dbutton, (S_IRUGO | S_IWUSR | S_IWGRP),
synaptics_rmi4_0dbutton_show,
synaptics_rmi4_0dbutton_store),
- __ATTR(flipx, (S_IRUGO | S_IWUGO),
+ __ATTR(flipx, (S_IRUGO | S_IWUSR | S_IWGRP),
synaptics_rmi4_flipx_show,
synaptics_rmi4_flipx_store),
- __ATTR(flipy, (S_IRUGO | S_IWUGO),
+ __ATTR(flipy, (S_IRUGO | S_IWUSR | S_IWGRP),
synaptics_rmi4_flipy_show,
synaptics_rmi4_flipy_store),
};
@@ -1056,6 +1056,8 @@
rmi4_pdata->i2c_pull_up = of_property_read_bool(np,
"synaptics,i2c-pull-up");
+ rmi4_pdata->power_down_enable = of_property_read_bool(np,
+ "synaptics,power-down");
rmi4_pdata->x_flip = of_property_read_bool(np, "synaptics,x-flip");
rmi4_pdata->y_flip = of_property_read_bool(np, "synaptics,y-flip");
@@ -2003,7 +2005,7 @@
error_reg_en_vcc_i2c:
if (rmi4_data->board->i2c_pull_up)
- reg_set_optimum_mode_check(rmi4_data->vdd, 0);
+ reg_set_optimum_mode_check(rmi4_data->vcc_i2c, 0);
error_reg_opt_i2c:
regulator_disable(rmi4_data->vdd);
error_reg_en_vdd:
@@ -2592,29 +2594,53 @@
bool on)
{
int retval;
+ int load_ua;
if (on == false)
goto regulator_hpm;
- retval = reg_set_optimum_mode_check(rmi4_data->vdd, RMI4_LPM_LOAD_UA);
+ load_ua = rmi4_data->board->power_down_enable ? 0 : RMI4_LPM_LOAD_UA;
+ retval = reg_set_optimum_mode_check(rmi4_data->vdd, load_ua);
if (retval < 0) {
dev_err(&rmi4_data->i2c_client->dev,
- "Regulator vcc_ana set_opt failed rc=%d\n",
+ "Regulator vdd_ana set_opt failed rc=%d\n",
retval);
goto fail_regulator_lpm;
}
- if (rmi4_data->board->i2c_pull_up) {
- retval = reg_set_optimum_mode_check(rmi4_data->vcc_i2c,
- RMI4_I2C_LPM_LOAD_UA);
- if (retval < 0) {
+ if (rmi4_data->board->power_down_enable) {
+ retval = regulator_disable(rmi4_data->vdd);
+ if (retval) {
dev_err(&rmi4_data->i2c_client->dev,
- "Regulator vcc_i2c set_opt failed rc=%d\n",
+ "Regulator vdd disable failed rc=%d\n",
retval);
goto fail_regulator_lpm;
}
}
+ if (rmi4_data->board->i2c_pull_up) {
+ load_ua = rmi4_data->board->power_down_enable ?
+ 0 : RMI4_I2C_LPM_LOAD_UA;
+ retval = reg_set_optimum_mode_check(rmi4_data->vcc_i2c,
+ load_ua);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "Regulator vcc_i2c set_opt failed " \
+ "rc=%d\n", retval);
+ goto fail_regulator_lpm;
+ }
+
+ if (rmi4_data->board->power_down_enable) {
+ retval = regulator_disable(rmi4_data->vcc_i2c);
+ if (retval) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "Regulator vcc_i2c disable failed " \
+ "rc=%d\n", retval);
+ goto fail_regulator_lpm;
+ }
+ }
+ }
+
return 0;
regulator_hpm:
@@ -2628,6 +2654,16 @@
goto fail_regulator_hpm;
}
+ if (rmi4_data->board->power_down_enable) {
+ retval = regulator_enable(rmi4_data->vdd);
+ if (retval) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "Regulator vdd enable failed rc=%d\n",
+ retval);
+ goto fail_regulator_hpm;
+ }
+ }
+
if (rmi4_data->board->i2c_pull_up) {
retval = reg_set_optimum_mode_check(rmi4_data->vcc_i2c,
RMI4_I2C_LOAD_UA);
@@ -2637,6 +2673,26 @@
retval);
goto fail_regulator_hpm;
}
+
+ if (rmi4_data->board->power_down_enable) {
+ retval = regulator_enable(rmi4_data->vcc_i2c);
+ if (retval) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "Regulator vcc_i2c enable failed " \
+ "rc=%d\n", retval);
+ goto fail_regulator_hpm;
+ }
+ }
+ }
+
+ if (rmi4_data->board->power_down_enable) {
+ retval = synaptics_rmi4_reset_device(rmi4_data);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to issue reset command, rc = %d\n",
+ __func__, retval);
+ return retval;
+ }
}
return 0;
diff --git a/drivers/input/touchscreen/synaptics_rmi_dev.c b/drivers/input/touchscreen/synaptics_rmi_dev.c
index c6b8a1c..c60ca23 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_IWUGO,
+ __ATTR(open, S_IRUGO | S_IWUSR | S_IWGRP,
synaptics_rmi4_show_error,
rmidev_sysfs_open_store),
- __ATTR(release, S_IWUGO,
+ __ATTR(release, S_IRUGO | S_IWUSR | S_IWGRP,
synaptics_rmi4_show_error,
rmidev_sysfs_release_store),
- __ATTR(address, S_IWUGO,
+ __ATTR(address, S_IRUGO | S_IWUSR | S_IWGRP,
synaptics_rmi4_show_error,
rmidev_sysfs_address_store),
- __ATTR(length, S_IWUGO,
+ __ATTR(length, S_IRUGO | S_IWUSR | S_IWGRP,
synaptics_rmi4_show_error,
rmidev_sysfs_length_store),
- __ATTR(data, (S_IRUGO | S_IWUGO),
+ __ATTR(data, (S_IRUGO | S_IWUSR | S_IWGRP),
rmidev_sysfs_data_show,
rmidev_sysfs_data_store),
};
diff --git a/drivers/iommu/msm_iommu-v1.c b/drivers/iommu/msm_iommu-v1.c
index 175328e..b9c4cae 100644
--- a/drivers/iommu/msm_iommu-v1.c
+++ b/drivers/iommu/msm_iommu-v1.c
@@ -843,6 +843,7 @@
void print_ctx_regs(struct msm_iommu_context_reg regs[])
{
uint32_t fsr = regs[DUMP_REG_FSR].val;
+ u64 ttbr;
pr_err("FAR = %016llx\n",
COMBINE_DUMP_REG(
@@ -865,8 +866,22 @@
pr_err("FSYNR0 = %08x FSYNR1 = %08x\n",
regs[DUMP_REG_FSYNR0].val, regs[DUMP_REG_FSYNR1].val);
- pr_err("TTBR0 = %08x TTBR1 = %08x\n",
- regs[DUMP_REG_TTBR0].val, regs[DUMP_REG_TTBR1].val);
+
+ ttbr = COMBINE_DUMP_REG(regs[DUMP_REG_TTBR0_1].val,
+ regs[DUMP_REG_TTBR0_0].val);
+ if (regs[DUMP_REG_TTBR0_1].valid)
+ pr_err("TTBR0 = %016llx\n", ttbr);
+ else
+ pr_err("TTBR0 = %016llx (32b)\n", ttbr);
+
+ ttbr = COMBINE_DUMP_REG(regs[DUMP_REG_TTBR1_1].val,
+ regs[DUMP_REG_TTBR1_0].val);
+
+ if (regs[DUMP_REG_TTBR1_1].valid)
+ pr_err("TTBR1 = %016llx\n", ttbr);
+ else
+ pr_err("TTBR1 = %016llx (32b)\n", ttbr);
+
pr_err("SCTLR = %08x ACTLR = %08x\n",
regs[DUMP_REG_SCTLR].val, regs[DUMP_REG_ACTLR].val);
pr_err("PRRR = %08x NMRR = %08x\n",
@@ -958,27 +973,30 @@
return __pa(priv->pt.fl_table);
}
-#define DUMP_REG_INIT(dump_reg, cb_reg) \
+#define DUMP_REG_INIT(dump_reg, cb_reg, mbp) \
do { \
dump_regs_tbl[dump_reg].key = cb_reg; \
dump_regs_tbl[dump_reg].name = #cb_reg; \
+ dump_regs_tbl[dump_reg].must_be_present = mbp; \
} while (0)
static void msm_iommu_build_dump_regs_table(void)
{
- DUMP_REG_INIT(DUMP_REG_FAR0, CB_FAR);
- DUMP_REG_INIT(DUMP_REG_FAR1, CB_FAR + 4);
- DUMP_REG_INIT(DUMP_REG_PAR0, CB_PAR);
- DUMP_REG_INIT(DUMP_REG_PAR1, CB_PAR + 4);
- DUMP_REG_INIT(DUMP_REG_FSR, CB_FSR);
- DUMP_REG_INIT(DUMP_REG_FSYNR0, CB_FSYNR0);
- DUMP_REG_INIT(DUMP_REG_FSYNR1, CB_FSYNR1);
- DUMP_REG_INIT(DUMP_REG_TTBR0, CB_TTBR0);
- DUMP_REG_INIT(DUMP_REG_TTBR1, CB_TTBR1);
- DUMP_REG_INIT(DUMP_REG_SCTLR, CB_SCTLR);
- DUMP_REG_INIT(DUMP_REG_ACTLR, CB_ACTLR);
- DUMP_REG_INIT(DUMP_REG_PRRR, CB_PRRR);
- DUMP_REG_INIT(DUMP_REG_NMRR, CB_NMRR);
+ DUMP_REG_INIT(DUMP_REG_FAR0, CB_FAR, 1);
+ DUMP_REG_INIT(DUMP_REG_FAR1, CB_FAR + 4, 1);
+ DUMP_REG_INIT(DUMP_REG_PAR0, CB_PAR, 1);
+ DUMP_REG_INIT(DUMP_REG_PAR1, CB_PAR + 4, 1);
+ DUMP_REG_INIT(DUMP_REG_FSR, CB_FSR, 1);
+ DUMP_REG_INIT(DUMP_REG_FSYNR0, CB_FSYNR0, 1);
+ DUMP_REG_INIT(DUMP_REG_FSYNR1, CB_FSYNR1, 1);
+ DUMP_REG_INIT(DUMP_REG_TTBR0_0, CB_TTBR0, 1);
+ DUMP_REG_INIT(DUMP_REG_TTBR0_1, CB_TTBR0 + 4, 0);
+ DUMP_REG_INIT(DUMP_REG_TTBR1_0, CB_TTBR1, 1);
+ DUMP_REG_INIT(DUMP_REG_TTBR1_1, CB_TTBR1 + 4, 0);
+ DUMP_REG_INIT(DUMP_REG_SCTLR, CB_SCTLR, 1);
+ DUMP_REG_INIT(DUMP_REG_ACTLR, CB_ACTLR, 1);
+ DUMP_REG_INIT(DUMP_REG_PRRR, CB_PRRR, 1);
+ DUMP_REG_INIT(DUMP_REG_NMRR, CB_NMRR, 1);
}
static struct iommu_ops msm_iommu_ops = {
diff --git a/drivers/iommu/msm_iommu_dev-v1.c b/drivers/iommu/msm_iommu_dev-v1.c
index 119a126..bbbe77b 100644
--- a/drivers/iommu/msm_iommu_dev-v1.c
+++ b/drivers/iommu/msm_iommu_dev-v1.c
@@ -32,6 +32,14 @@
static struct of_device_id msm_iommu_v1_ctx_match_table[];
+#ifdef CONFIG_IOMMU_LPAE
+static const char *BFB_REG_NODE_NAME = "qcom,iommu-lpae-bfb-regs";
+static const char *BFB_DATA_NODE_NAME = "qcom,iommu-lpae-bfb-data";
+#else
+static const char *BFB_REG_NODE_NAME = "qcom,iommu-bfb-regs";
+static const char *BFB_DATA_NODE_NAME = "qcom,iommu-bfb-data";
+#endif
+
static int msm_iommu_parse_bfb_settings(struct platform_device *pdev,
struct msm_iommu_drvdata *drvdata)
{
@@ -40,17 +48,17 @@
int ret;
/*
- * It is not valid for a device to have the qcom,iommu-bfb-regs
- * property but not the qcom,iommu-bfb-data property, and vice versa.
+ * It is not valid for a device to have the BFB_REG_NODE_NAME
+ * property but not the BFB_DATA_NODE_NAME property, and vice versa.
*/
- if (!of_get_property(pdev->dev.of_node, "qcom,iommu-bfb-regs", &nreg)) {
- if (of_get_property(pdev->dev.of_node, "qcom,iommu-bfb-data",
+ if (!of_get_property(pdev->dev.of_node, BFB_REG_NODE_NAME, &nreg)) {
+ if (of_get_property(pdev->dev.of_node, BFB_DATA_NODE_NAME,
&nval))
return -EINVAL;
return 0;
}
- if (!of_get_property(pdev->dev.of_node, "qcom,iommu-bfb-data", &nval))
+ if (!of_get_property(pdev->dev.of_node, BFB_DATA_NODE_NAME, &nval))
return -EINVAL;
if (nreg >= sizeof(bfb_settings->regs))
@@ -68,14 +76,14 @@
return -ENOMEM;
ret = of_property_read_u32_array(pdev->dev.of_node,
- "qcom,iommu-bfb-regs",
+ BFB_REG_NODE_NAME,
bfb_settings->regs,
nreg / sizeof(*bfb_settings->regs));
if (ret)
return ret;
ret = of_property_read_u32_array(pdev->dev.of_node,
- "qcom,iommu-bfb-data",
+ BFB_DATA_NODE_NAME,
bfb_settings->data,
nval / sizeof(*bfb_settings->data));
if (ret)
diff --git a/drivers/iommu/msm_iommu_pagetable.c b/drivers/iommu/msm_iommu_pagetable.c
index b871a5a..1e4bff8 100644
--- a/drivers/iommu/msm_iommu_pagetable.c
+++ b/drivers/iommu/msm_iommu_pagetable.c
@@ -24,6 +24,49 @@
#include <trace/events/kmem.h>
#include "msm_iommu_pagetable.h"
+#define NUM_FL_PTE 4096
+#define NUM_SL_PTE 256
+#define NUM_TEX_CLASS 8
+
+/* First-level page table bits */
+#define FL_BASE_MASK 0xFFFFFC00
+#define FL_TYPE_TABLE (1 << 0)
+#define FL_TYPE_SECT (2 << 0)
+#define FL_SUPERSECTION (1 << 18)
+#define FL_AP0 (1 << 10)
+#define FL_AP1 (1 << 11)
+#define FL_AP2 (1 << 15)
+#define FL_SHARED (1 << 16)
+#define FL_BUFFERABLE (1 << 2)
+#define FL_CACHEABLE (1 << 3)
+#define FL_TEX0 (1 << 12)
+#define FL_OFFSET(va) (((va) & 0xFFF00000) >> 20)
+#define FL_NG (1 << 17)
+
+/* Second-level page table bits */
+#define SL_BASE_MASK_LARGE 0xFFFF0000
+#define SL_BASE_MASK_SMALL 0xFFFFF000
+#define SL_TYPE_LARGE (1 << 0)
+#define SL_TYPE_SMALL (2 << 0)
+#define SL_AP0 (1 << 4)
+#define SL_AP1 (2 << 4)
+#define SL_AP2 (1 << 9)
+#define SL_SHARED (1 << 10)
+#define SL_BUFFERABLE (1 << 2)
+#define SL_CACHEABLE (1 << 3)
+#define SL_TEX0 (1 << 6)
+#define SL_OFFSET(va) (((va) & 0xFF000) >> 12)
+#define SL_NG (1 << 11)
+
+/* Memory type and cache policy attributes */
+#define MT_SO 0
+#define MT_DEV 1
+#define MT_NORMAL 2
+#define CP_NONCACHED 0
+#define CP_WB_WA 1
+#define CP_WT 2
+#define CP_WB_NWA 3
+
/* Sharability attributes of MSM IOMMU mappings */
#define MSM_IOMMU_ATTR_NON_SH 0x0
#define MSM_IOMMU_ATTR_SH 0x4
@@ -36,6 +79,13 @@
static int msm_iommu_tex_class[4];
+/* TEX Remap Registers */
+#define NMRR_ICP(nmrr, n) (((nmrr) & (3 << ((n) * 2))) >> ((n) * 2))
+#define NMRR_OCP(nmrr, n) (((nmrr) & (3 << ((n) * 2 + 16))) >> ((n) * 2 + 16))
+
+#define PRRR_NOS(prrr, n) ((prrr) & (1 << ((n) + 24)) ? 1 : 0)
+#define PRRR_MT(prrr, n) ((((prrr) & (3 << ((n) * 2))) >> ((n) * 2)))
+
static inline void clean_pte(unsigned long *start, unsigned long *end,
int redirect)
{
@@ -284,79 +334,8 @@
size_t msm_iommu_pagetable_unmap(struct msm_iommu_pt *pt, unsigned long va,
size_t len)
{
- unsigned long *fl_pte;
- unsigned long fl_offset;
- unsigned long *sl_table;
- unsigned long *sl_pte;
- unsigned long sl_offset;
- int i, ret = 0;
-
- if (len != SZ_16M && len != SZ_1M &&
- len != SZ_64K && len != SZ_4K) {
- pr_debug("Bad length: %d\n", len);
- ret = -EINVAL;
- goto fail;
- }
-
- if (!pt->fl_table) {
- pr_debug("Null page table\n");
- ret = -EINVAL;
- goto fail;
- }
-
- fl_offset = FL_OFFSET(va); /* Upper 12 bits */
- fl_pte = pt->fl_table + fl_offset; /* int pointers, 4 bytes */
-
- if (*fl_pte == 0) {
- pr_debug("First level PTE is 0\n");
- ret = -ENODEV;
- goto fail;
- }
-
- /* Unmap supersection */
- if (len == SZ_16M) {
- for (i = 0; i < 16; i++)
- *(fl_pte+i) = 0;
-
- clean_pte(fl_pte, fl_pte + 16, pt->redirect);
- }
-
- if (len == SZ_1M) {
- *fl_pte = 0;
- clean_pte(fl_pte, fl_pte + 1, pt->redirect);
- }
-
- sl_table = (unsigned long *) __va(((*fl_pte) & FL_BASE_MASK));
- sl_offset = SL_OFFSET(va);
- sl_pte = sl_table + sl_offset;
-
- if (len == SZ_64K) {
- for (i = 0; i < 16; i++)
- *(sl_pte+i) = 0;
-
- clean_pte(sl_pte, sl_pte + 16, pt->redirect);
- }
-
- if (len == SZ_4K) {
- *sl_pte = 0;
- clean_pte(sl_pte, sl_pte + 1, pt->redirect);
- }
-
- if (len == SZ_4K || len == SZ_64K) {
- int used = 0;
-
- for (i = 0; i < NUM_SL_PTE; i++)
- if (sl_table[i])
- used = 1;
- if (!used) {
- free_page((unsigned long)sl_table);
- *fl_pte = 0;
- clean_pte(fl_pte, fl_pte + 1, pt->redirect);
- }
- }
-
-fail:
- return ret;
+ msm_iommu_pagetable_unmap_range(pt, va, len);
+ return len;
}
static phys_addr_t get_phys_addr(struct scatterlist *sg)
diff --git a/drivers/iommu/msm_iommu_pagetable.h b/drivers/iommu/msm_iommu_pagetable.h
index 7513aa5..a5ea318 100644
--- a/drivers/iommu/msm_iommu_pagetable.h
+++ b/drivers/iommu/msm_iommu_pagetable.h
@@ -13,56 +13,6 @@
#ifndef __ARCH_ARM_MACH_MSM_IOMMU_PAGETABLE_H
#define __ARCH_ARM_MACH_MSM_IOMMU_PAGETABLE_H
-#define NUM_FL_PTE 4096
-#define NUM_SL_PTE 256
-#define NUM_TEX_CLASS 8
-
-/* First-level page table bits */
-#define FL_BASE_MASK 0xFFFFFC00
-#define FL_TYPE_TABLE (1 << 0)
-#define FL_TYPE_SECT (2 << 0)
-#define FL_SUPERSECTION (1 << 18)
-#define FL_AP0 (1 << 10)
-#define FL_AP1 (1 << 11)
-#define FL_AP2 (1 << 15)
-#define FL_SHARED (1 << 16)
-#define FL_BUFFERABLE (1 << 2)
-#define FL_CACHEABLE (1 << 3)
-#define FL_TEX0 (1 << 12)
-#define FL_OFFSET(va) (((va) & 0xFFF00000) >> 20)
-#define FL_NG (1 << 17)
-
-/* Second-level page table bits */
-#define SL_BASE_MASK_LARGE 0xFFFF0000
-#define SL_BASE_MASK_SMALL 0xFFFFF000
-#define SL_TYPE_LARGE (1 << 0)
-#define SL_TYPE_SMALL (2 << 0)
-#define SL_AP0 (1 << 4)
-#define SL_AP1 (2 << 4)
-#define SL_AP2 (1 << 9)
-#define SL_SHARED (1 << 10)
-#define SL_BUFFERABLE (1 << 2)
-#define SL_CACHEABLE (1 << 3)
-#define SL_TEX0 (1 << 6)
-#define SL_OFFSET(va) (((va) & 0xFF000) >> 12)
-#define SL_NG (1 << 11)
-
-/* Memory type and cache policy attributes */
-#define MT_SO 0
-#define MT_DEV 1
-#define MT_NORMAL 2
-#define CP_NONCACHED 0
-#define CP_WB_WA 1
-#define CP_WT 2
-#define CP_WB_NWA 3
-
-/* TEX Remap Registers */
-#define NMRR_ICP(nmrr, n) (((nmrr) & (3 << ((n) * 2))) >> ((n) * 2))
-#define NMRR_OCP(nmrr, n) (((nmrr) & (3 << ((n) * 2 + 16))) >> ((n) * 2 + 16))
-
-#define PRRR_NOS(prrr, n) ((prrr) & (1 << ((n) + 24)) ? 1 : 0)
-#define PRRR_MT(prrr, n) ((((prrr) & (3 << ((n) * 2))) >> ((n) * 2)))
-
#define MRC(reg, processor, op1, crn, crm, op2) \
__asm__ __volatile__ ( \
" mrc " #processor "," #op1 ", %0," #crn "," #crm "," #op2 "\n" \
@@ -71,7 +21,10 @@
#define RCP15_PRRR(reg) MRC(reg, p15, 0, c10, c2, 0)
#define RCP15_NMRR(reg) MRC(reg, p15, 0, c10, c2, 1)
-struct iommu_pt;
+#define RCP15_MAIR0(reg) MRC(reg, p15, 0, c10, c2, 0)
+#define RCP15_MAIR1(reg) MRC(reg, p15, 0, c10, c2, 1)
+
+struct msm_iommu_pt;
void msm_iommu_pagetable_init(void);
int msm_iommu_pagetable_alloc(struct msm_iommu_pt *pt);
diff --git a/drivers/iommu/msm_iommu_sec.c b/drivers/iommu/msm_iommu_sec.c
index 8d2cc8f..474efdf 100644
--- a/drivers/iommu/msm_iommu_sec.c
+++ b/drivers/iommu/msm_iommu_sec.c
@@ -172,9 +172,13 @@
for (i = 0; i < MAX_DUMP_REGS; ++i) {
if (!ctx_regs[i].valid) {
- pr_err("Register missing from dump: %s, %lx\n",
- dump_regs_tbl[i].name, dump_regs_tbl[i].key);
- ret = 1;
+ if (dump_regs_tbl[i].must_be_present) {
+ pr_err("Register missing from dump: %s, %lx\n",
+ dump_regs_tbl[i].name,
+ dump_regs_tbl[i].key);
+ ret = 1;
+ }
+ ctx_regs[i].val = 0;
}
}
@@ -462,7 +466,8 @@
* Ensure that the buffer is in RAM by the time it gets to TZ
*/
clean_caches((unsigned long) flush_va,
- map.plist.size * map.plist.list_size, virt_to_phys(flush_va));
+ sizeof(unsigned long) * map.plist.list_size,
+ virt_to_phys(flush_va));
ret = scm_call(SCM_SVC_MP, IOMMU_SECURE_MAP2, &map, sizeof(map),
&scm_ret, sizeof(scm_ret));
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index f13e55a..159c6f6 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -300,6 +300,16 @@
To compile this driver as a module, choose M here: the module will
be called leds-qpnp.
+config LEDS_MSM_GPIO_FLASH
+ tristate "Support for GPIO Flash LEDs"
+ depends on GPIO_MSM_V3
+ help
+ This driver supports the leds functionality of GPIO Flash LED. It
+ includes flash mode and torch mode.
+
+ To compile this driver as a module, choose M here: the module will
+ be called leds-gpio-flash.
+
config LEDS_WM831X_STATUS
tristate "LED support for status LEDs on WM831x PMICs"
depends on LEDS_CLASS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index c688898..f20a0d0 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -54,6 +54,7 @@
obj-$(CONFIG_LEDS_QCIBL) += leds-qci-backlight.o
obj-$(CONFIG_LEDS_MSM_PDM) += leds-msm-pdm.o
obj-$(CONFIG_LEDS_MSM_TRICOLOR) += leds-msm-tricolor.o
+obj-$(CONFIG_LEDS_MSM_GPIO_FLASH) += leds-msm-gpio-flash.o
# LED SPI Drivers
obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o
diff --git a/drivers/leds/leds-msm-gpio-flash.c b/drivers/leds/leds-msm-gpio-flash.c
new file mode 100644
index 0000000..60d4681
--- /dev/null
+++ b/drivers/leds/leds-msm-gpio-flash.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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/leds.h>
+#include <linux/platform_device.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/printk.h>
+
+#define LED_GPIO_FLASH_DRIVER_NAME "qcom,leds-gpio-flash"
+#define LED_TRIGGER_DEFAULT "none"
+
+struct led_gpio_flash_data {
+ int flash_en;
+ int flash_now;
+ int brightness;
+ struct led_classdev cdev;
+};
+
+static struct of_device_id led_gpio_flash_of_match[] = {
+ {.compatible = LED_GPIO_FLASH_DRIVER_NAME,},
+ {},
+};
+
+static void led_gpio_brightness_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ int rc = 0;
+ struct led_gpio_flash_data *flash_led =
+ container_of(led_cdev, struct led_gpio_flash_data, cdev);
+
+ int brightness = value;
+ int flash_en = 0, flash_now = 0;
+
+ if (brightness > LED_HALF) {
+ flash_en = 0;
+ flash_now = 1;
+ } else if (brightness > LED_OFF) {
+ flash_en = 1;
+ flash_now = 0;
+ } else {
+ flash_en = 0;
+ flash_now = 0;
+ }
+
+ rc = gpio_direction_output(flash_led->flash_en, flash_en);
+ if (rc) {
+ pr_err("%s: Failed to set gpio %d\n", __func__,
+ flash_led->flash_en);
+ goto err;
+ }
+ rc = gpio_direction_output(flash_led->flash_now, flash_now);
+ if (rc) {
+ pr_err("%s: Failed to set gpio %d\n", __func__,
+ flash_led->flash_now);
+ goto err;
+ }
+
+ flash_led->brightness = brightness;
+err:
+ return;
+}
+
+static enum led_brightness led_gpio_brightness_get(struct led_classdev
+ *led_cdev)
+{
+ struct led_gpio_flash_data *flash_led =
+ container_of(led_cdev, struct led_gpio_flash_data, cdev);
+ return flash_led->brightness;
+}
+
+int __devinit led_gpio_flash_probe(struct platform_device *pdev)
+{
+ int rc = 0;
+ const char *temp_str;
+ struct led_gpio_flash_data *flash_led = NULL;
+ struct device_node *node = pdev->dev.of_node;
+
+ flash_led = devm_kzalloc(&pdev->dev, sizeof(struct led_gpio_flash_data),
+ GFP_KERNEL);
+ if (flash_led == NULL) {
+ dev_err(&pdev->dev, "%s:%d Unable to allocate memory\n",
+ __func__, __LINE__);
+ return -ENOMEM;
+ }
+
+ flash_led->cdev.default_trigger = LED_TRIGGER_DEFAULT;
+ rc = of_property_read_string(node, "linux,default-trigger", &temp_str);
+ if (!rc)
+ flash_led->cdev.default_trigger = temp_str;
+
+ flash_led->flash_en = of_get_named_gpio(node, "qcom,flash-en", 0);
+
+ if (flash_led->flash_en < 0) {
+ dev_err(&pdev->dev,
+ "Looking up %s property in node %s failed. rc = %d\n",
+ "flash-en", node->full_name, flash_led->flash_en);
+ goto error;
+ } else {
+ rc = gpio_request(flash_led->flash_en, "FLASH_EN");
+ if (rc) {
+ dev_err(&pdev->dev,
+ "%s: Failed to request gpio %d,rc = %d\n",
+ __func__, flash_led->flash_en, rc);
+
+ goto error;
+ }
+ }
+
+ flash_led->flash_now = of_get_named_gpio(node, "qcom,flash-now", 0);
+ if (flash_led->flash_now < 0) {
+ dev_err(&pdev->dev,
+ "Looking up %s property in node %s failed. rc = %d\n",
+ "flash-now", node->full_name, flash_led->flash_now);
+ goto error;
+ } else {
+ rc = gpio_request(flash_led->flash_now, "FLASH_NOW");
+ if (rc) {
+ dev_err(&pdev->dev,
+ "%s: Failed to request gpio %d,rc = %d\n",
+ __func__, flash_led->flash_now, rc);
+
+ goto error;
+ }
+ }
+
+ gpio_tlmm_config(GPIO_CFG(flash_led->flash_en, 0,
+ GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
+ GPIO_CFG_2MA), GPIO_CFG_ENABLE);
+ gpio_tlmm_config(GPIO_CFG(flash_led->flash_now, 0,
+ GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
+ GPIO_CFG_2MA), GPIO_CFG_ENABLE);
+
+ rc = of_property_read_string(node, "linux,name", &flash_led->cdev.name);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: Failed to read linux name. rc = %d\n",
+ __func__, rc);
+ goto error;
+ }
+
+ platform_set_drvdata(pdev, flash_led);
+ flash_led->cdev.max_brightness = LED_FULL;
+ flash_led->cdev.brightness_set = led_gpio_brightness_set;
+ flash_led->cdev.brightness_get = led_gpio_brightness_get;
+
+ rc = led_classdev_register(&pdev->dev, &flash_led->cdev);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: Failed to register led dev. rc = %d\n",
+ __func__, rc);
+ goto error;
+ }
+ return 0;
+
+error:
+ devm_kfree(&pdev->dev, flash_led);
+ return rc;
+}
+
+int __devexit led_gpio_flash_remove(struct platform_device *pdev)
+{
+ struct led_gpio_flash_data *flash_led =
+ (struct led_gpio_flash_data *)platform_get_drvdata(pdev);
+
+ led_classdev_unregister(&flash_led->cdev);
+ devm_kfree(&pdev->dev, flash_led);
+ return 0;
+}
+
+static struct platform_driver led_gpio_flash_driver = {
+ .probe = led_gpio_flash_probe,
+ .remove = __devexit_p(led_gpio_flash_remove),
+ .driver = {
+ .name = LED_GPIO_FLASH_DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = led_gpio_flash_of_match,
+ }
+};
+
+static int __init led_gpio_flash_init(void)
+{
+ return platform_driver_register(&led_gpio_flash_driver);
+}
+
+static void __exit led_gpio_flash_exit(void)
+{
+ return platform_driver_unregister(&led_gpio_flash_driver);
+}
+
+late_initcall(led_gpio_flash_init);
+module_exit(led_gpio_flash_exit);
+
+MODULE_DESCRIPTION("QCOM GPIO LEDs driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("leds:leds-msm-gpio-flash");
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index fbcc243..3c2be38 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -170,11 +170,13 @@
#define LED_MPP_SINK_CTRL(base) (base + 0x4C)
#define LED_MPP_CURRENT_DEFAULT 5
+#define LED_MPP_VIN_CTRL_DEFAULT 0
#define LED_MPP_CURRENT_PER_SETTING 5
#define LED_MPP_SOURCE_SEL_DEFAULT LED_MPP_MODE_ENABLE
#define LED_MPP_SINK_MASK 0x07
#define LED_MPP_MODE_MASK 0x7F
+#define LED_MPP_VIN_MASK 0x03
#define LED_MPP_EN_MASK 0x80
#define LED_MPP_SRC_MASK 0x0F
#define LED_MPP_MODE_CTRL_MASK 0x70
@@ -348,6 +350,8 @@
* @current_setting - current setting, 5ma-40ma in 5ma increments
* @source_sel - source selection
* @mode_ctrl - mode control
+ * @vin_ctrl - input control
+ * @min_brightness - minimum brightness supported
* @pwm_mode - pwm mode in use
*/
struct mpp_config_data {
@@ -355,6 +359,8 @@
u8 current_setting;
u8 source_sel;
u8 mode_ctrl;
+ u8 vin_ctrl;
+ u8 min_brightness;
u8 pwm_mode;
};
@@ -397,15 +403,22 @@
/**
* kpdbl_config_data - kpdbl configuration data
* @pwm_cfg - device pwm configuration
- * @row_src_sel_val - select source, 0 for vph_pwr and 1 for vbst
- * @row_scan_en - enable row scan
- * @row_scan_val - map to enable needed rows
+ * @mode - running mode: pwm or lut
+ * @row_id - row id of the led
+ * @row_src_vbst - 0 for vph_pwr and 1 for vbst
+ * @row_src_en - enable row source
+ * @always_on - always on row
+ * @lut_params - lut parameters to be used by pwm driver
+ * @duty_cycles - duty cycles for lut
*/
struct kpdbl_config_data {
struct pwm_config_data *pwm_cfg;
- u32 row_src_sel_val;
- u32 row_scan_en;
- u32 row_scan_val;
+ u32 row_id;
+ bool row_src_vbst;
+ bool row_src_en;
+ bool always_on;
+ struct pwm_duty_cycles *duty_cycles;
+ struct lut_params lut_params;
};
/**
@@ -452,6 +465,8 @@
int turn_off_delay_ms;
};
+static int num_kpbl_leds_on;
+
static int
qpnp_led_masked_write(struct qpnp_led_data *led, u16 addr, u8 mask, u8 val)
{
@@ -576,6 +591,13 @@
int duty_us;
if (led->cdev.brightness) {
+ if (led->cdev.brightness < led->mpp_cfg->min_brightness) {
+ dev_warn(&led->spmi_dev->dev,
+ "brightness is less than supported..." \
+ "set to minimum supported\n");
+ led->cdev.brightness = led->mpp_cfg->min_brightness;
+ }
+
if (led->mpp_cfg->pwm_mode != MANUAL_MODE) {
if (!led->mpp_cfg->pwm_cfg->blinking) {
led->mpp_cfg->pwm_cfg->mode =
@@ -893,35 +915,73 @@
if (!led->kpdbl_cfg->pwm_cfg->blinking)
led->kpdbl_cfg->pwm_cfg->mode =
led->kpdbl_cfg->pwm_cfg->default_mode;
- rc = qpnp_led_masked_write(led, KPDBL_ENABLE(led->base),
- KPDBL_MODULE_EN_MASK, KPDBL_MODULE_EN);
- 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, duty_us,
- led->kpdbl_cfg->pwm_cfg->pwm_period_us);
- if (rc < 0) {
- dev_err(&led->spmi_dev->dev, "pwm config failed\n");
- return rc;
+ if (!num_kpbl_leds_on) {
+ rc = qpnp_led_masked_write(led, KPDBL_ENABLE(led->base),
+ KPDBL_MODULE_EN_MASK, KPDBL_MODULE_EN);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Enable reg write failed(%d)\n", rc);
+ return rc;
+ }
}
+
+ 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,
+ duty_us,
+ led->kpdbl_cfg->pwm_cfg->pwm_period_us);
+ if (rc < 0) {
+ dev_err(&led->spmi_dev->dev, "pwm config failed\n");
+ return rc;
+ }
+ }
+
rc = pwm_enable(led->kpdbl_cfg->pwm_cfg->pwm_dev);
if (rc < 0) {
dev_err(&led->spmi_dev->dev, "pwm enable failed\n");
return rc;
}
+
+ num_kpbl_leds_on++;
+
} else {
led->kpdbl_cfg->pwm_cfg->mode =
led->kpdbl_cfg->pwm_cfg->default_mode;
- pwm_disable(led->kpdbl_cfg->pwm_cfg->pwm_dev);
- rc = qpnp_led_masked_write(led, KPDBL_ENABLE(led->base),
- KPDBL_MODULE_EN_MASK, KPDBL_MODULE_DIS);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "Failed to write led enable reg\n");
- return rc;
+
+ if (led->kpdbl_cfg->always_on) {
+ rc = pwm_config(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,
+ "pwm config failed\n");
+ return rc;
+ }
+
+ rc = pwm_enable(led->kpdbl_cfg->pwm_cfg->pwm_dev);
+ if (rc < 0) {
+ dev_err(&led->spmi_dev->dev, "pwm enable failed\n");
+ return rc;
+ }
+ } else
+ pwm_disable(led->kpdbl_cfg->pwm_cfg->pwm_dev);
+
+ if (num_kpbl_leds_on > 0)
+ num_kpbl_leds_on--;
+
+ if (!num_kpbl_leds_on) {
+ rc = qpnp_led_masked_write(led, KPDBL_ENABLE(led->base),
+ KPDBL_MODULE_EN_MASK, KPDBL_MODULE_DIS);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Failed to write led enable reg\n");
+ return rc;
+ }
}
}
led->kpdbl_cfg->pwm_cfg->blinking = false;
+
qpnp_dump_regs(led, kpdbl_debug_regs, ARRAY_SIZE(kpdbl_debug_regs));
return 0;
@@ -987,11 +1047,14 @@
struct qpnp_led_data *led;
led = container_of(led_cdev, struct qpnp_led_data, cdev);
- if (value < LED_OFF || value > led->cdev.max_brightness) {
+ if (value < LED_OFF) {
dev_err(&led->spmi_dev->dev, "Invalid brightness value\n");
return;
}
+ if (value > led->cdev.max_brightness)
+ value = led->cdev.max_brightness;
+
led->cdev.brightness = value;
schedule_work(&led->work);
}
@@ -2000,16 +2063,31 @@
int rc;
u8 val;
- /* enable row source selct */
- rc = qpnp_led_masked_write(led, KPDBL_ROW_SRC_SEL(led->base),
- KPDBL_ROW_SRC_SEL_VAL_MASK, led->kpdbl_cfg->row_src_sel_val);
+ /* select row source - vbst or vph */
+ rc = spmi_ext_register_readl(led->spmi_dev->ctrl, led->spmi_dev->sid,
+ KPDBL_ROW_SRC_SEL(led->base), &val, 1);
if (rc) {
dev_err(&led->spmi_dev->dev,
- "Enable row src sel write failed(%d)\n", rc);
+ "Unable to read from addr=%x, rc(%d)\n",
+ KPDBL_ROW_SRC_SEL(led->base), rc);
return rc;
}
- /* row source */
+ if (led->kpdbl_cfg->row_src_vbst)
+ val |= 1 << led->kpdbl_cfg->row_id;
+ else
+ val &= ~(1 << led->kpdbl_cfg->row_id);
+
+ rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
+ KPDBL_ROW_SRC_SEL(led->base), &val, 1);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Unable to read from addr=%x, rc(%d)\n",
+ KPDBL_ROW_SRC_SEL(led->base), rc);
+ return rc;
+ }
+
+ /* row source enable */
rc = spmi_ext_register_readl(led->spmi_dev->ctrl, led->spmi_dev->sid,
KPDBL_ROW_SRC(led->base), &val, 1);
if (rc) {
@@ -2019,12 +2097,10 @@
return rc;
}
- val &= ~KPDBL_ROW_SCAN_VAL_MASK;
- val |= led->kpdbl_cfg->row_scan_val;
-
- led->kpdbl_cfg->row_scan_en <<= KPDBL_ROW_SCAN_EN_SHIFT;
- val &= ~KPDBL_ROW_SCAN_EN_MASK;
- val |= led->kpdbl_cfg->row_scan_en;
+ if (led->kpdbl_cfg->row_src_en)
+ val |= KPDBL_ROW_SCAN_EN_MASK | (1 << led->kpdbl_cfg->row_id);
+ else
+ val &= ~(1 << led->kpdbl_cfg->row_id);
rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
KPDBL_ROW_SRC(led->base), &val, 1);
@@ -2093,6 +2169,14 @@
if (val < 0)
val = 0;
+ rc = qpnp_led_masked_write(led, LED_MPP_VIN_CTRL(led->base),
+ LED_MPP_VIN_MASK, led->mpp_cfg->vin_ctrl);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Failed to write led vin control reg\n");
+ return rc;
+ }
+
rc = qpnp_led_masked_write(led, LED_MPP_SINK_CTRL(led->base),
LED_MPP_SINK_MASK, val);
if (rc) {
@@ -2544,6 +2628,7 @@
dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
return -ENOMEM;
}
+
rc = of_property_read_string(node, "qcom,mode", &mode);
if (!rc) {
led_mode = qpnp_led_get_mode(mode);
@@ -2569,23 +2654,20 @@
if (rc < 0)
return rc;
- rc = of_property_read_u32(node, "qcom,row-src-sel-val", &val);
+ rc = of_property_read_u32(node, "qcom,row-id", &val);
if (!rc)
- led->kpdbl_cfg->row_src_sel_val = val;
+ led->kpdbl_cfg->row_id = val;
else
return rc;
- rc = of_property_read_u32(node, "qcom,row-scan-val", &val);
- if (!rc)
- led->kpdbl_cfg->row_scan_val = val;
- else
- return rc;
+ led->kpdbl_cfg->row_src_vbst =
+ of_property_read_bool(node, "qcom,row-src-vbst");
- rc = of_property_read_u32(node, "qcom,row-scan-en", &val);
- if (!rc)
- led->kpdbl_cfg->row_scan_en = val;
- else
- return rc;
+ led->kpdbl_cfg->row_src_en =
+ of_property_read_bool(node, "qcom,row-src-en");
+
+ led->kpdbl_cfg->always_on =
+ of_property_read_bool(node, "qcom,always-on");
return 0;
}
@@ -2677,6 +2759,20 @@
else if (rc != -EINVAL)
return rc;
+ led->mpp_cfg->vin_ctrl = LED_MPP_VIN_CTRL_DEFAULT;
+ rc = of_property_read_u32(node, "qcom,vin-ctrl", &val);
+ if (!rc)
+ led->mpp_cfg->vin_ctrl = (u8) val;
+ else if (rc != -EINVAL)
+ return rc;
+
+ led->mpp_cfg->min_brightness = 0;
+ rc = of_property_read_u32(node, "qcom,min-brightness", &val);
+ if (!rc)
+ led->mpp_cfg->min_brightness = (u8) val;
+ else if (rc != -EINVAL)
+ return rc;
+
rc = of_property_read_string(node, "qcom,mode", &mode);
if (!rc) {
led_mode = qpnp_led_get_mode(mode);
@@ -2821,6 +2917,7 @@
goto fail_id_check;
}
} else if (strncmp(led_label, "kpdbl", sizeof("kpdbl")) == 0) {
+ num_kpbl_leds_on = 0;
rc = qpnp_get_config_kpdbl(led, temp);
if (rc < 0) {
dev_err(&led->spmi_dev->dev,
diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h
index 2c2b339..189418a 100644
--- a/drivers/media/dvb/dvb-core/demux.h
+++ b/drivers/media/dvb/dvb-core/demux.h
@@ -246,6 +246,8 @@
enum dmx_tsp_format_t tsp_format);
int (*set_secure_mode)(struct dmx_ts_feed *feed,
struct dmx_secure_mode *sec_mode);
+ int (*set_cipher_ops)(struct dmx_ts_feed *feed,
+ struct dmx_cipher_operations *cipher_ops);
int (*oob_command) (struct dmx_ts_feed *feed,
struct dmx_oob_command *cmd);
int (*ts_insertion_init)(struct dmx_ts_feed *feed);
@@ -301,6 +303,8 @@
u32 bytes_num);
int (*set_secure_mode)(struct dmx_section_feed *feed,
struct dmx_secure_mode *sec_mode);
+ int (*set_cipher_ops)(struct dmx_section_feed *feed,
+ struct dmx_cipher_operations *cipher_ops);
int (*oob_command) (struct dmx_section_feed *feed,
struct dmx_oob_command *cmd);
int (*get_scrambling_bits)(struct dmx_section_feed *feed, u8 *value);
@@ -388,6 +392,7 @@
struct dmx_frontend* frontend; /* Front-end connected to the demux */
void* priv; /* Pointer to private data of the API client */
struct data_buffer dvr_input; /* DVR input buffer */
+ int dvr_input_protected;
struct dentry *debugfs_demux_dir; /* debugfs dir */
int (*open) (struct dmx_demux* demux);
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 28e8092..a1cac54 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -566,6 +566,7 @@
int bytes_written = 0;
size_t split;
size_t tsp_size;
+ u8 *data_start;
struct dvb_ringbuffer *src = &dmxdev->dvr_input_buffer;
todo = dvr_cmd->cmd.data_feed_count;
@@ -578,15 +579,15 @@
/* wait for input */
ret = wait_event_interruptible(
src->queue,
- (dvb_ringbuffer_avail(src) >= tsp_size) || (!src->data)
- || (dmxdev->dvr_in_exit) || (src->error));
+ (dvb_ringbuffer_avail(src) >= tsp_size) ||
+ dmxdev->dvr_in_exit || src->error);
if (ret < 0)
break;
spin_lock(&dmxdev->dvr_in_lock);
- if (!src->data || dmxdev->exit || dmxdev->dvr_in_exit) {
+ if (dmxdev->exit || dmxdev->dvr_in_exit) {
spin_unlock(&dmxdev->dvr_in_lock);
ret = -ENODEV;
break;
@@ -609,12 +610,20 @@
* Lock on DVR buffer is released before calling to
* write, if DVR was released meanwhile, dvr_in_exit is
* prompted. Lock is acquired when updating the read pointer
- * again to preserve read/write pointers consistency
+ * again to preserve read/write pointers consistency.
+ *
+ * In protected input mode, DVR input buffer is not mapped
+ * to kernel memory. Underlying demux implementation
+ * should trigger HW to read from DVR input buffer
+ * based on current read offset.
*/
if (split > 0) {
+ data_start = (dmxdev->demux->dvr_input_protected) ?
+ NULL : (src->data + src->pread);
+
spin_unlock(&dmxdev->dvr_in_lock);
ret = dmxdev->demux->write(dmxdev->demux,
- src->data + src->pread,
+ data_start,
split);
if (ret < 0) {
@@ -641,9 +650,12 @@
}
}
+ data_start = (dmxdev->demux->dvr_input_protected) ?
+ NULL : (src->data + src->pread);
+
spin_unlock(&dmxdev->dvr_in_lock);
ret = dmxdev->demux->write(dmxdev->demux,
- src->data + src->pread, todo);
+ data_start, todo);
if (ret < 0) {
printk(KERN_ERR "dmxdev: dvr write error %d\n",
@@ -708,8 +720,7 @@
ret = dvb_dvr_feed_cmd(dmxdev, &dvr_cmd);
if (ret < 0) {
- printk(KERN_ERR
- "%s: DVR data feed failed, ret=%d\n",
+ dprintk("%s: DVR data feed failed, ret=%d\n",
__func__, ret);
continue;
}
@@ -825,6 +836,7 @@
dmxdev->demux->dvr_input.priv_handle = NULL;
dmxdev->demux->dvr_input.ringbuff = &dmxdev->dvr_input_buffer;
+ dmxdev->demux->dvr_input_protected = 0;
mem = vmalloc(DVR_CMDS_BUFFER_SIZE);
if (!mem) {
vfree(dmxdev->dvr_input_buffer.data);
@@ -936,7 +948,8 @@
if ((dmxdev->dvr_input_buffer_mode ==
DMX_BUFFER_MODE_EXTERNAL) &&
(dmxdev->demux->dvr_input.priv_handle)) {
- dmxdev->demux->unmap_buffer(dmxdev->demux,
+ if (!dmxdev->demux->dvr_input_protected)
+ dmxdev->demux->unmap_buffer(dmxdev->demux,
dmxdev->demux->dvr_input.priv_handle);
dmxdev->demux->dvr_input.priv_handle = NULL;
}
@@ -1130,8 +1143,8 @@
for (todo = count; todo > 0; todo -= ret) {
ret = wait_event_interruptible(src->queue,
(dvb_ringbuffer_free(src)) ||
- (!src->data) || (!cmdbuf->data) ||
- (src->error != 0) || (dmxdev->dvr_in_exit));
+ !src->data || !cmdbuf->data ||
+ (src->error != 0) || dmxdev->dvr_in_exit);
if (ret < 0)
return ret;
@@ -1314,6 +1327,7 @@
enum dmx_buffer_mode *buffer_mode;
void **buff_handle;
void *oldmem;
+ int *is_protected;
if ((mode != DMX_BUFFER_MODE_INTERNAL) &&
(mode != DMX_BUFFER_MODE_EXTERNAL))
@@ -1328,11 +1342,13 @@
lock = &dmxdev->lock;
buffer_mode = &dmxdev->dvr_buffer_mode;
buff_handle = &dmxdev->dvr_priv_buff_handle;
+ is_protected = NULL;
} else {
buf = &dmxdev->dvr_input_buffer;
lock = &dmxdev->dvr_in_lock;
buffer_mode = &dmxdev->dvr_input_buffer_mode;
buff_handle = &dmxdev->demux->dvr_input.priv_handle;
+ is_protected = &dmxdev->demux->dvr_input_protected;
}
if (mode == *buffer_mode)
@@ -1353,6 +1369,9 @@
*buff_handle = NULL;
}
+ if (is_protected)
+ *is_protected = 0;
+
/* set default internal buffer */
dvb_dvr_set_buffer_size(dmxdev, f_flags, DVR_BUFFER_SIZE);
} else if (oldmem) {
@@ -1372,31 +1391,56 @@
void **buff_handle;
void *newmem;
void *oldmem;
+ int *is_protected;
+ struct dmx_caps caps;
+
+ if (dmxdev->demux->get_caps)
+ dmxdev->demux->get_caps(dmxdev->demux, &caps);
+ else
+ caps.caps = 0;
if ((f_flags & O_ACCMODE) == O_RDONLY) {
buf = &dmxdev->dvr_buffer;
lock = &dmxdev->lock;
buffer_mode = dmxdev->dvr_buffer_mode;
buff_handle = &dmxdev->dvr_priv_buff_handle;
+ is_protected = NULL;
} else {
buf = &dmxdev->dvr_input_buffer;
lock = &dmxdev->dvr_in_lock;
buffer_mode = dmxdev->dvr_input_buffer_mode;
buff_handle = &dmxdev->demux->dvr_input.priv_handle;
+ is_protected = &dmxdev->demux->dvr_input_protected;
+ if (!(caps.caps & DMX_CAP_SECURED_INPUT_PLAYBACK) &&
+ dmx_buffer->is_protected)
+ return -EINVAL;
}
- if ((!dmx_buffer->size) ||
+ if (!dmx_buffer->size ||
(buffer_mode == DMX_BUFFER_MODE_INTERNAL))
return -EINVAL;
oldmem = *buff_handle;
- if (dmxdev->demux->map_buffer(dmxdev->demux, dmx_buffer,
- buff_handle, &newmem))
- return -ENOMEM;
+
+ /*
+ * Protected buffer is relevant only for DVR input buffer
+ * when DVR device is opened for write. In such case,
+ * buffer is mapped only if the buffer is not protected one.
+ */
+ if (!is_protected || !dmx_buffer->is_protected) {
+ if (dmxdev->demux->map_buffer(dmxdev->demux, dmx_buffer,
+ buff_handle, &newmem))
+ return -ENOMEM;
+ } else {
+ newmem = NULL;
+ *buff_handle = NULL;
+ }
spin_lock_irq(lock);
buf->data = newmem;
buf->size = dmx_buffer->size;
+ if (is_protected)
+ *is_protected = dmx_buffer->is_protected;
dvb_ringbuffer_reset(buf);
spin_unlock_irq(lock);
@@ -1717,19 +1761,20 @@
static int dvb_dmxdev_set_source(struct dmxdev_filter *dmxdevfilter,
dmx_source_t *source)
{
+ int ret = 0;
struct dmxdev *dev;
if (dmxdevfilter->state == DMXDEV_STATE_GO)
return -EBUSY;
dev = dmxdevfilter->dev;
-
- dev->source = *source;
-
if (dev->demux->set_source)
- return dev->demux->set_source(dev->demux, source);
+ ret = dev->demux->set_source(dev->demux, source);
- return 0;
+ if (!ret)
+ dev->source = *source;
+
+ return ret;
}
static int dvb_dmxdev_reuse_decoder_buf(struct dmxdev_filter *dmxdevfilter,
@@ -3105,7 +3150,10 @@
tsfeed->set_tsp_out_format(tsfeed, filter->dmx_tsp_format);
if (tsfeed->set_secure_mode)
- tsfeed->set_secure_mode(tsfeed, &feed->sec_mode);
+ tsfeed->set_secure_mode(tsfeed, &filter->sec_mode);
+
+ if (tsfeed->set_cipher_ops)
+ tsfeed->set_cipher_ops(tsfeed, &feed->cipher_ops);
if ((para->pes_type == DMX_PES_VIDEO0) ||
(para->pes_type == DMX_PES_VIDEO1) ||
@@ -3265,7 +3313,11 @@
if ((*secfeed)->set_secure_mode)
(*secfeed)->set_secure_mode(*secfeed,
- &filter->feed.sec.sec_mode);
+ &filter->sec_mode);
+
+ if ((*secfeed)->set_cipher_ops)
+ (*secfeed)->set_cipher_ops(*secfeed,
+ &filter->feed.sec.cipher_ops);
} else {
dvb_dmxdev_feed_stop(filter);
}
@@ -3434,6 +3486,8 @@
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
init_timer(&dmxdevfilter->timer);
+ dmxdevfilter->sec_mode.is_secured = 0;
+
INIT_LIST_HEAD(&dmxdevfilter->insertion_buffers);
dmxdevfilter->dmx_tsp_format = DMX_TSP_FORMAT_188;
@@ -3513,7 +3567,7 @@
return -ENOMEM;
feed->pid = pid;
- feed->sec_mode.is_secured = 0;
+ feed->cipher_ops.operations_count = 0;
feed->idx_params.enable = 0;
list_add(&feed->next, &filter->feed.ts);
@@ -3568,7 +3622,7 @@
memcpy(&dmxdevfilter->params.sec,
params, sizeof(struct dmx_sct_filter_params));
invert_mode(&dmxdevfilter->params.sec.filter);
- dmxdevfilter->feed.sec.sec_mode.is_secured = 0;
+ dmxdevfilter->feed.sec.cipher_ops.operations_count = 0;
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
if (params->flags & DMX_IMMEDIATE_START)
@@ -3582,43 +3636,78 @@
struct dmxdev_filter *filter,
struct dmx_secure_mode *sec_mode)
{
+ if (!dmxdev || !filter || !sec_mode)
+ return -EINVAL;
+
+ if (filter->state == DMXDEV_STATE_GO) {
+ printk(KERN_ERR "%s: invalid filter state\n", __func__);
+ return -EBUSY;
+ }
+
+ dprintk(KERN_DEBUG "%s: secure=%d\n", __func__, sec_mode->is_secured);
+
+ filter->sec_mode = *sec_mode;
+
+ return 0;
+}
+
+static int dvb_dmxdev_set_cipher(struct dmxdev *dmxdev,
+ struct dmxdev_filter *filter,
+ struct dmx_cipher_operations *cipher_ops)
+{
struct dmxdev_feed *feed;
struct dmxdev_feed *ts_feed = NULL;
struct dmxdev_sec_feed *sec_feed = NULL;
+ struct dmx_caps caps;
- if (NULL == dmxdev || NULL == filter || NULL == sec_mode)
+ if (!dmxdev || !dmxdev->demux->get_caps)
return -EINVAL;
+ dmxdev->demux->get_caps(dmxdev->demux, &caps);
+
+ if (!filter || !cipher_ops ||
+ (cipher_ops->operations_count > caps.num_cipher_ops) ||
+ (cipher_ops->operations_count >
+ DMX_MAX_CIPHER_OPERATIONS_COUNT))
+ return -EINVAL;
+
+ dprintk(KERN_DEBUG "%s: pid=%d, operations=%d\n", __func__,
+ cipher_ops->pid, cipher_ops->operations_count);
+
if (filter->state < DMXDEV_STATE_SET ||
filter->state > DMXDEV_STATE_GO) {
printk(KERN_ERR "%s: invalid filter state\n", __func__);
return -EPERM;
}
- dprintk(KERN_DEBUG "%s: key_id=%d, secure=%d, looking for pid=%d\n",
- __func__, sec_mode->key_ladder_id, sec_mode->is_secured,
- sec_mode->pid);
+
+ if (!filter->sec_mode.is_secured && cipher_ops->operations_count) {
+ printk(KERN_ERR "%s: secure mode must be enabled to set cipher ops\n",
+ __func__);
+ return -EPERM;
+ }
+
switch (filter->type) {
case DMXDEV_TYPE_PES:
list_for_each_entry(feed, &filter->feed.ts, next) {
- if (feed->pid == sec_mode->pid) {
+ if (feed->pid == cipher_ops->pid) {
ts_feed = feed;
- ts_feed->sec_mode = *sec_mode;
+ ts_feed->cipher_ops = *cipher_ops;
if (filter->state == DMXDEV_STATE_GO &&
- ts_feed->ts->set_secure_mode)
- ts_feed->ts->set_secure_mode(
- ts_feed->ts, sec_mode);
+ ts_feed->ts->set_cipher_ops)
+ ts_feed->ts->set_cipher_ops(
+ ts_feed->ts, cipher_ops);
break;
}
}
break;
case DMXDEV_TYPE_SEC:
- if (filter->params.sec.pid == sec_mode->pid) {
+ if (filter->params.sec.pid == cipher_ops->pid) {
sec_feed = &filter->feed.sec;
- sec_feed->sec_mode = *sec_mode;
+ sec_feed->cipher_ops = *cipher_ops;
if (filter->state == DMXDEV_STATE_GO &&
- sec_feed->feed->set_secure_mode)
- sec_feed->feed->set_secure_mode(sec_feed->feed,
- sec_mode);
+ sec_feed->feed->set_cipher_ops)
+ sec_feed->feed->set_cipher_ops(sec_feed->feed,
+ cipher_ops);
}
break;
@@ -3628,7 +3717,7 @@
if (!ts_feed && !sec_feed) {
printk(KERN_ERR "%s: pid %d is undefined for this filter\n",
- __func__, sec_mode->pid);
+ __func__, cipher_ops->pid);
return -EINVAL;
}
@@ -4029,6 +4118,15 @@
mutex_unlock(&dmxdevfilter->mutex);
break;
+ case DMX_SET_CIPHER:
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+ ret = dvb_dmxdev_set_cipher(dmxdev, dmxdevfilter, parg);
+ mutex_unlock(&dmxdevfilter->mutex);
+ break;
+
case DMX_REUSE_DECODER_BUFFER:
if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
mutex_unlock(&dmxdev->mutex);
@@ -4384,13 +4482,12 @@
buffer_status.fullness);
seq_printf(s, "error: %d, ",
buffer_status.error);
- seq_printf(s, "scramble: %d\n",
- scrambling_bits.value);
-
- } else {
- seq_printf(s, "scramble: %d\n",
- scrambling_bits.value);
}
+
+ seq_printf(s, "scramble: %d, ",
+ scrambling_bits.value);
+ seq_printf(s, "secured: %d\n",
+ filter->sec_mode.is_secured);
}
}
@@ -4425,6 +4522,7 @@
return -ENOMEM;
dmxdev->playback_mode = DMX_PB_MODE_PUSH;
+ dmxdev->demux->dvr_input_protected = 0;
mutex_init(&dmxdev->mutex);
spin_lock_init(&dmxdev->lock);
diff --git a/drivers/media/dvb/dvb-core/dmxdev.h b/drivers/media/dvb/dvb-core/dmxdev.h
index 4e306e8..6747ca7 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.h
+++ b/drivers/media/dvb/dvb-core/dmxdev.h
@@ -58,15 +58,15 @@
struct dmxdev_feed {
u16 pid;
- struct dmx_secure_mode sec_mode;
struct dmx_indexing_params idx_params;
+ struct dmx_cipher_operations cipher_ops;
struct dmx_ts_feed *ts;
struct list_head next;
};
struct dmxdev_sec_feed {
- struct dmx_secure_mode sec_mode;
struct dmx_section_feed *feed;
+ struct dmx_cipher_operations cipher_ops;
};
#define DMX_EVENT_QUEUE_SIZE 500 /* number of events */
@@ -182,6 +182,8 @@
int todo;
u8 secheader[3];
+ struct dmx_secure_mode sec_mode;
+
/* Decoder buffer(s) related */
struct dmx_decoder_buffers decoder_buffers;
};
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index bbf2470..692a04e 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -2262,19 +2262,36 @@
{
struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+
+ if (mutex_lock_interruptible(&dvbdmx->mutex))
+ return -ERESTARTSYS;
+
+ if (dvbdmxfeed->state == DMX_STATE_GO) {
+ mutex_unlock(&dvbdmx->mutex);
+ return -EBUSY;
+ }
+
+ dvbdmxfeed->secure_mode = *secure_mode;
+ mutex_unlock(&dvbdmx->mutex);
+ return 0;
+}
+
+static int dmx_ts_set_cipher_ops(struct dmx_ts_feed *feed,
+ struct dmx_cipher_operations *cipher_ops)
+{
+ struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
+ struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
int ret = 0;
- mutex_lock(&dvbdmx->mutex);
+ if (mutex_lock_interruptible(&dvbdmx->mutex))
+ return -ERESTARTSYS;
if ((dvbdmxfeed->state == DMX_STATE_GO) &&
- dvbdmxfeed->demux->set_secure_mode) {
- ret = dvbdmxfeed->demux->set_secure_mode(dvbdmxfeed,
- secure_mode);
- if (!ret)
- dvbdmxfeed->secure_mode = *secure_mode;
- } else {
- dvbdmxfeed->secure_mode = *secure_mode;
- }
+ dvbdmx->set_cipher_op)
+ ret = dvbdmx->set_cipher_op(dvbdmxfeed, cipher_ops);
+
+ if (!ret)
+ dvbdmxfeed->cipher_ops = *cipher_ops;
mutex_unlock(&dvbdmx->mutex);
return ret;
@@ -2481,6 +2498,7 @@
(*ts_feed)->data_ready_cb = dmx_ts_feed_data_ready_cb;
(*ts_feed)->notify_data_read = NULL;
(*ts_feed)->set_secure_mode = dmx_ts_set_secure_mode;
+ (*ts_feed)->set_cipher_ops = dmx_ts_set_cipher_ops;
(*ts_feed)->oob_command = dvbdmx_ts_feed_oob_cmd;
(*ts_feed)->get_scrambling_bits = dvbdmx_ts_get_scrambling_bits;
(*ts_feed)->ts_insertion_init = NULL;
@@ -2724,15 +2742,38 @@
mutex_lock(&dvbdmx->mutex);
- dvbdmxfeed->secure_mode = *secure_mode;
- if ((dvbdmxfeed->state == DMX_STATE_GO) &&
- dvbdmxfeed->demux->set_secure_mode)
- dvbdmxfeed->demux->set_secure_mode(dvbdmxfeed, secure_mode);
+ if (dvbdmxfeed->state == DMX_STATE_GO) {
+ mutex_unlock(&dvbdmx->mutex);
+ return -EBUSY;
+ }
+ dvbdmxfeed->secure_mode = *secure_mode;
mutex_unlock(&dvbdmx->mutex);
return 0;
}
+static int dmx_section_set_cipher_ops(struct dmx_section_feed *feed,
+ struct dmx_cipher_operations *cipher_ops)
+{
+ struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
+ struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+ int ret = 0;
+
+ if (mutex_lock_interruptible(&dvbdmx->mutex))
+ return -ERESTARTSYS;
+
+ if ((dvbdmxfeed->state == DMX_STATE_GO) &&
+ dvbdmx->set_cipher_op) {
+ ret = dvbdmx->set_cipher_op(dvbdmxfeed, cipher_ops);
+ }
+
+ if (!ret)
+ dvbdmxfeed->cipher_ops = *cipher_ops;
+
+ mutex_unlock(&dvbdmx->mutex);
+ return ret;
+}
+
static int dmx_section_feed_release_filter(struct dmx_section_feed *feed,
struct dmx_section_filter *filter)
{
@@ -2875,6 +2916,7 @@
(*feed)->data_ready_cb = dmx_section_feed_data_ready_cb;
(*feed)->notify_data_read = NULL;
(*feed)->set_secure_mode = dmx_section_set_secure_mode;
+ (*feed)->set_cipher_ops = dmx_section_set_cipher_ops;
(*feed)->oob_command = dvbdmx_section_feed_oob_cmd;
(*feed)->get_scrambling_bits = dvbdmx_section_get_scrambling_bits;
@@ -2939,8 +2981,10 @@
{
struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
- if ((!demux->frontend) || (demux->frontend->source != DMX_MEMORY_FE))
+ if (!demux->frontend || !buf || demux->dvr_input_protected ||
+ (demux->frontend->source != DMX_MEMORY_FE)) {
return -EINVAL;
+ }
dvb_dmx_swfilter_format(dvbdemux, buf, count, dvbdemux->tsp_format);
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h
index aeafa57..835e7b8 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.h
+++ b/drivers/media/dvb/dvb-core/dvb_demux.h
@@ -176,6 +176,7 @@
int buffer_size;
enum dmx_tsp_format_t tsp_out_format;
struct dmx_secure_mode secure_mode;
+ struct dmx_cipher_operations cipher_ops;
struct timespec timeout;
struct dvb_demux_filter *filter;
@@ -233,8 +234,8 @@
struct dmx_buffer_status *dmx_buffer_status);
int (*reuse_decoder_buffer)(struct dvb_demux_feed *feed,
int cookie);
- int (*set_secure_mode)(struct dvb_demux_feed *feed,
- struct dmx_secure_mode *secure_mode);
+ int (*set_cipher_op)(struct dvb_demux_feed *feed,
+ struct dmx_cipher_operations *cipher_ops);
u32 (*check_crc32)(struct dvb_demux_feed *feed,
const u8 *buf, size_t len);
void (*memcopy)(struct dvb_demux_feed *feed, u8 *dst,
diff --git a/drivers/media/platform/msm/camera_v2/Kconfig b/drivers/media/platform/msm/camera_v2/Kconfig
index 74ec99a..4668d02 100644
--- a/drivers/media/platform/msm/camera_v2/Kconfig
+++ b/drivers/media/platform/msm/camera_v2/Kconfig
@@ -146,6 +146,15 @@
snapshot config = 3264 * 2448 at 18 fps.
2 lanes max fps is 18, 4 lanes max fps is 24.
+config OV5648
+ bool "Sensor OV5648 (BAYER 5M)"
+ depends on MSMB_CAMERA
+ ---help---
+ OmniVision 5 MP Bayer Sensor, only use 1 mipi lane,
+ preview set to 1296*972 at 30 fps,
+ snapshot set to 2592*1944 at 12 fps,
+ This sensor driver does not support auto focus.
+
config MT9M114
bool "Sensor MT9M114 (YUV 1.26MP)"
depends on MSMB_CAMERA
@@ -191,6 +200,15 @@
and QSXGA snapshot at 15 fps.
This sensor driver does not support auto focus.
+config OV12830
+ bool "OmniVision OV12830 (BAYER 12MP)"
+ depends on MSMB_CAMERA
+ ---help---
+ OmniVision 12.8 MP Bayer Sensor with auto focus.uses
+ 4 mipi lanes, preview config = 2112 * 1500 at 30 fps,
+ snapshot config = 4224 * 3000 at 15 fps.
+ 2 lanes max fps is 18, 4 lanes max fps is 24.
+
config MSM_V4L2_VIDEO_OVERLAY_DEVICE
tristate "Qualcomm MSM V4l2 video overlay device"
---help---
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 4c5f258..07a66e6 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -22,7 +22,7 @@
#include "msm.h"
#include "msm_camera_io_util.h"
-#define VFE32_BURST_LEN 1
+#define VFE32_BURST_LEN 2
#define VFE32_UB_SIZE 1024
#define VFE32_EQUAL_SLICE_UB 204
#define VFE32_WM_BASE(idx) (0x4C + 0x18 * idx)
@@ -146,7 +146,7 @@
/* BUS_CFG */
msm_camera_io_w(0x00000001, vfe_dev->vfe_base + 0x3C);
msm_camera_io_w(0x01000025, vfe_dev->vfe_base + 0x1C);
- msm_camera_io_w_mb(0x1DFFFFFF, vfe_dev->vfe_base + 0x20);
+ msm_camera_io_w_mb(0x1CFFFFFF, vfe_dev->vfe_base + 0x20);
msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x24);
msm_camera_io_w_mb(0x1FFFFFFF, vfe_dev->vfe_base + 0x28);
}
@@ -161,8 +161,6 @@
static void msm_vfe32_process_halt_irq(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1)
{
- if (irq_status1 & BIT(24))
- complete(&vfe_dev->halt_complete);
}
static void msm_vfe32_process_camif_irq(struct vfe_device *vfe_dev,
@@ -304,7 +302,7 @@
*irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x2C);
*irq_status1 = msm_camera_io_r(vfe_dev->vfe_base + 0x30);
msm_camera_io_w(*irq_status0, vfe_dev->vfe_base + 0x24);
- msm_camera_io_w(*irq_status1, vfe_dev->vfe_base + 0x28);
+ msm_camera_io_w_mb(*irq_status1, vfe_dev->vfe_base + 0x28);
msm_camera_io_w_mb(1, vfe_dev->vfe_base + 0x18);
if (*irq_status1 & BIT(0))
@@ -750,14 +748,20 @@
static long msm_vfe32_axi_halt(struct vfe_device *vfe_dev)
{
uint32_t halt_mask;
+ uint32_t axi_busy_flag = true;
+
+ msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x1D8);
+ while (axi_busy_flag) {
+ if (msm_camera_io_r(
+ vfe_dev->vfe_base + 0x1DC) & 0x1)
+ axi_busy_flag = false;
+ }
+ msm_camera_io_w_mb(0, vfe_dev->vfe_base + 0x1D8);
halt_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x20);
- halt_mask |= BIT(24);
+ halt_mask &= 0xFEFFFFFF;
+ /* Disable AXI IRQ */
msm_camera_io_w_mb(halt_mask, vfe_dev->vfe_base + 0x20);
- init_completion(&vfe_dev->halt_complete);
- /*TD: Need to fix crashes with this*/
- /*msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x1D8);*/
- return wait_for_completion_interruptible_timeout(
- &vfe_dev->halt_complete, msecs_to_jiffies(500));
+ return 0;
}
static uint32_t msm_vfe32_get_wm_mask(
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 908d3c6..3806213 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
@@ -527,9 +527,11 @@
int i;
uint32_t *data_ptr = cfg_data +
reg_cfg_cmd->u.rw_info.cmd_data_offset/4;
- for (i = 0; i < reg_cfg_cmd->u.rw_info.len/4; i++)
+ for (i = 0; i < reg_cfg_cmd->u.rw_info.len/4; i++) {
*data_ptr++ = msm_camera_io_r(vfe_dev->vfe_base +
- reg_cfg_cmd->u.rw_info.reg_offset++);
+ reg_cfg_cmd->u.rw_info.reg_offset);
+ reg_cfg_cmd->u.rw_info.reg_offset += 4;
+ }
break;
}
}
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_core.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_core.c
index a2fc813..769e2a8 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_core.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_core.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
@@ -45,6 +45,7 @@
JPEG_DBG("%s: reset_done_ack rc %d", __func__, rc);
spin_lock_irqsave(&pgmn_dev->reset_lock, flags);
pgmn_dev->reset_done_ack = 0;
+ pgmn_dev->state = MSM_JPEG_RESET;
spin_unlock_irqrestore(&pgmn_dev->reset_lock, flags);
return 0;
@@ -196,7 +197,15 @@
jpeg_irq_status);
/*For reset and framedone IRQs, clear all bits*/
- if (jpeg_irq_status & 0x10000000) {
+ if (pgmn_dev->state == MSM_JPEG_IDLE) {
+ JPEG_DBG_HIGH("%s %d ] Error IRQ received state %d",
+ __func__, __LINE__, pgmn_dev->state);
+ JPEG_DBG_HIGH("%s %d ] Ignoring the Error", __func__,
+ __LINE__);
+ msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK,
+ JPEG_IRQ_CLEAR_ALL, pgmn_dev->base);
+ return IRQ_HANDLED;
+ } else if (jpeg_irq_status & 0x10000000) {
msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK,
JPEG_IRQ_CLEAR_ALL, pgmn_dev->base);
} else if (jpeg_irq_status & 0x1) {
@@ -239,13 +248,25 @@
/* Unexpected/unintended HW interrupt */
if (msm_jpeg_hw_irq_is_err(jpeg_irq_status)) {
- if (pgmn_dev->decode_flag)
- msm_jpeg_decode_status(pgmn_dev->base);
- msm_jpeg_core_return_buffers(pgmn_dev, jpeg_irq_status);
- data = msm_jpeg_core_err_irq(jpeg_irq_status, pgmn_dev);
- if (msm_jpeg_irq_handler)
- msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_ERR,
- context, data);
+ if (pgmn_dev->state != MSM_JPEG_EXECUTING) {
+ /*Clear all the bits and ignore the IRQ*/
+ JPEG_DBG_HIGH("%s %d ] Error IRQ received state %d",
+ __func__, __LINE__, pgmn_dev->state);
+ JPEG_DBG_HIGH("%s %d ] Ignoring the Error", __func__,
+ __LINE__);
+ msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK,
+ JPEG_IRQ_CLEAR_ALL, pgmn_dev->base);
+ return IRQ_HANDLED;
+ } else {
+ if (pgmn_dev->decode_flag)
+ msm_jpeg_decode_status(pgmn_dev->base);
+ msm_jpeg_core_return_buffers(pgmn_dev, jpeg_irq_status);
+ data = msm_jpeg_core_err_irq(jpeg_irq_status, pgmn_dev);
+ if (msm_jpeg_irq_handler) {
+ msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_ERR,
+ context, data);
+ }
+ }
}
return IRQ_HANDLED;
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 509567c..d6fa2b0 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
@@ -172,6 +172,8 @@
struct msm_jpeg_device *pgmn_dev =
(struct msm_jpeg_device *) context;
+ pgmn_dev->state = MSM_JPEG_IDLE;
+
jpeg_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!jpeg_mem) {
JPEG_PR_ERR("%s: no mem resource?\n", __func__);
@@ -271,6 +273,7 @@
pgmn_dev->jpeg_client = msm_ion_client_create(-1, "camera/jpeg");
JPEG_DBG("%s:%d] success\n", __func__, __LINE__);
+ pgmn_dev->state = MSM_JPEG_INIT;
return rc;
fail_request_irq:
@@ -345,6 +348,7 @@
iounmap(base);
release_mem_region(mem->start, resource_size(mem));
ion_client_destroy(pgmn_dev->jpeg_client);
+ pgmn_dev->state = MSM_JPEG_IDLE;
JPEG_DBG("%s:%d] success\n", __func__, __LINE__);
return result;
}
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 15b4b25..aa6f034 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
@@ -757,6 +757,7 @@
wmb();
rc = msm_jpeg_ioctl_hw_cmds(pgmn_dev, arg);
wmb();
+ pgmn_dev->state = MSM_JPEG_EXECUTING;
JPEG_DBG("%s:%d]", __func__, __LINE__);
return rc;
}
@@ -768,15 +769,21 @@
struct msm_jpeg_ctrl_cmd ctrl_cmd;
JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
- if (copy_from_user(&ctrl_cmd, arg, sizeof(ctrl_cmd))) {
- JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
- return -EFAULT;
- }
+ if (pgmn_dev->state == MSM_JPEG_INIT) {
+ if (copy_from_user(&ctrl_cmd, arg, sizeof(ctrl_cmd))) {
+ JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
pgmn_dev->op_mode = ctrl_cmd.type;
rc = msm_jpeg_core_reset(pgmn_dev, pgmn_dev->op_mode, pgmn_dev->base,
resource_size(pgmn_dev->mem));
+ } else {
+ JPEG_PR_ERR("%s:%d] JPEG not been initialized Wrong state\n",
+ __func__, __LINE__);
+ rc = -1;
+ }
return rc;
}
@@ -804,6 +811,7 @@
case MSM_JPEG_IOCTL_STOP:
rc = msm_jpeg_ioctl_hw_cmds(pgmn_dev, (void __user *) arg);
+ pgmn_dev->state = MSM_JPEG_STOPPED;
break;
case MSM_JPEG_IOCTL_START:
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.h b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.h
index be889cd..c3a57e3 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.h
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.h
@@ -26,6 +26,14 @@
#define JPEG_8974_V1 0x10000000
#define JPEG_8974_V2 0x10010000
+enum msm_jpeg_state {
+ MSM_JPEG_INIT,
+ MSM_JPEG_RESET,
+ MSM_JPEG_EXECUTING,
+ MSM_JPEG_STOPPED,
+ MSM_JPEG_IDLE
+};
+
struct msm_jpeg_q {
char const *name;
struct list_head q;
@@ -98,6 +106,7 @@
wait_queue_head_t reset_wait;
uint32_t res_size;
uint32_t jpeg_bus_client;
+ enum msm_jpeg_state state;
};
int __msm_jpeg_open(struct msm_jpeg_device *pgmn_dev);
diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c
index 27aba5c..07f3b40 100644
--- a/drivers/media/platform/msm/camera_v2/msm.c
+++ b/drivers/media/platform/msm/camera_v2/msm.c
@@ -519,6 +519,7 @@
struct msm_session *session;
unsigned int session_id;
unsigned int stream_id;
+ unsigned long spin_flags = 0;
event_data = (struct msm_v4l2_event_data *)
((struct v4l2_event *)arg)->u.data;
@@ -564,9 +565,13 @@
break;
}
+ spin_lock_irqsave(&(session->command_ack_q.lock),
+ spin_flags);
ret_cmd->event = *(struct v4l2_event *)arg;
msm_enqueue(&cmd_ack->command_q, &ret_cmd->list);
wake_up(&cmd_ack->wait);
+ spin_unlock_irqrestore(&(session->command_ack_q.lock),
+ spin_flags);
}
break;
@@ -852,16 +857,19 @@
{
unsigned long flags;
struct v4l2_subdev *subdev = NULL;
+ struct v4l2_subdev *subdev_out = NULL;
spin_lock_irqsave(&msm_v4l2_dev->lock, flags);
if (!list_empty(&msm_v4l2_dev->subdevs)) {
list_for_each_entry(subdev, &msm_v4l2_dev->subdevs, list)
- if (!strcmp(name, subdev->name))
+ if (!strcmp(name, subdev->name)) {
+ subdev_out = subdev;
break;
+ }
}
spin_unlock_irqrestore(&msm_v4l2_dev->lock, flags);
- return subdev;
+ return subdev_out;
}
static void msm_sd_notify(struct v4l2_subdev *sd,
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 d238649..a4eb274 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
@@ -34,8 +34,8 @@
#include <media/v4l2-event.h>
#include <media/v4l2-ioctl.h>
#include <media/msmb_camera.h>
-#include <media/msmb_pproc.h>
#include <media/msmb_generic_buf_mgr.h>
+#include <media/msmb_pproc.h>
#include "msm_cpp.h"
#include "msm_isp_util.h"
#include "msm_camera_io_util.h"
@@ -182,7 +182,7 @@
static unsigned long msm_cpp_get_phy_addr(struct cpp_device *cpp_dev,
struct msm_cpp_buff_queue_info_t *buff_queue_info, uint32_t buff_index,
- uint8_t native_buff)
+ uint8_t native_buff, int *fd)
{
unsigned long phy_add = 0;
struct list_head *buff_head;
@@ -196,6 +196,7 @@
list_for_each_entry_safe(buff, save, buff_head, entry) {
if (buff->map_info.buff_info.index == buff_index) {
phy_add = buff->map_info.phy_addr;
+ *fd = buff->map_info.buff_info.fd;
break;
}
}
@@ -279,7 +280,7 @@
static unsigned long msm_cpp_fetch_buffer_info(struct cpp_device *cpp_dev,
struct msm_cpp_buffer_info_t *buffer_info, uint32_t session_id,
- uint32_t stream_id)
+ uint32_t stream_id, int *fd)
{
unsigned long phy_addr = 0;
struct msm_cpp_buff_queue_info_t *buff_queue_info;
@@ -294,10 +295,11 @@
}
phy_addr = msm_cpp_get_phy_addr(cpp_dev, buff_queue_info,
- buffer_info->index, native_buff);
+ buffer_info->index, native_buff, fd);
if ((phy_addr == 0) && (native_buff)) {
phy_addr = msm_cpp_queue_buffer_info(cpp_dev, buff_queue_info,
buffer_info);
+ *fd = buffer_info->fd;
}
return phy_addr;
}
@@ -1034,7 +1036,7 @@
}
#endif
-void msm_cpp_do_timeout_work(struct work_struct *work)
+static void msm_cpp_do_timeout_work(struct work_struct *work)
{
int ret;
uint32_t i = 0;
@@ -1044,6 +1046,11 @@
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);
+ 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;
@@ -1196,6 +1203,7 @@
(struct msm_cpp_frame_info_t *)ioctl_ptr->ioctl_ptr;
int32_t status = 0;
uint8_t fw_version_1_2_x = 0;
+ int in_fd;
int i = 0;
if (!new_frame) {
@@ -1233,15 +1241,13 @@
in_phyaddr = msm_cpp_fetch_buffer_info(cpp_dev,
&new_frame->input_buffer_info,
((new_frame->identity >> 16) & 0xFFFF),
- (new_frame->identity & 0xFFFF));
+ (new_frame->identity & 0xFFFF), &in_fd);
if (!in_phyaddr) {
pr_err("error gettting input physical address\n");
rc = -EINVAL;
goto ERROR2;
}
- memset(&new_frame->output_buffer_info[0], 0,
- sizeof(struct msm_cpp_buffer_info_t));
memset(&buff_mgr_info, 0, sizeof(struct msm_buf_mngr_info));
buff_mgr_info.session_id = ((new_frame->identity >> 16) & 0xFFFF);
buff_mgr_info.stream_id = (new_frame->identity & 0xFFFF);
@@ -1256,7 +1262,8 @@
out_phyaddr0 = msm_cpp_fetch_buffer_info(cpp_dev,
&new_frame->output_buffer_info[0],
((new_frame->identity >> 16) & 0xFFFF),
- (new_frame->identity & 0xFFFF));
+ (new_frame->identity & 0xFFFF),
+ &new_frame->output_buffer_info[0].fd);
if (!out_phyaddr0) {
pr_err("error gettting output physical address\n");
rc = -EINVAL;
@@ -1286,7 +1293,8 @@
out_phyaddr1 = msm_cpp_fetch_buffer_info(cpp_dev,
&new_frame->output_buffer_info[1],
((new_frame->duplicate_identity >> 16) & 0xFFFF),
- (new_frame->duplicate_identity & 0xFFFF));
+ (new_frame->duplicate_identity & 0xFFFF),
+ &new_frame->output_buffer_info[1].fd);
if (!out_phyaddr1) {
pr_err("error gettting output physical address\n");
rc = -EINVAL;
@@ -1301,7 +1309,8 @@
(cpp_frame_msg[12] & 0x3FF);
fw_version_1_2_x = 0;
- if (cpp_dev->hw_info.cpp_hw_version == 0x10010000)
+ if ((cpp_dev->hw_info.cpp_hw_version == CPP_HW_VERSION_1_1_0) ||
+ (cpp_dev->hw_info.cpp_hw_version == CPP_HW_VERSION_1_1_1))
fw_version_1_2_x = 2;
for (i = 0; i < num_stripes; i++) {
@@ -1462,12 +1471,27 @@
return -EINVAL;
}
+ if (u_stream_buff_info->num_buffs == 0) {
+ pr_err("%s:%d: Invalid number of buffers\n", __func__,
+ __LINE__);
+ kfree(u_stream_buff_info);
+ mutex_unlock(&cpp_dev->mutex);
+ return -EINVAL;
+ }
k_stream_buff_info.num_buffs = u_stream_buff_info->num_buffs;
k_stream_buff_info.identity = u_stream_buff_info->identity;
+
+ if (k_stream_buff_info.num_buffs > MSM_CAMERA_MAX_STREAM_BUF) {
+ pr_err("%s:%d: unexpected large num buff requested\n",
+ __func__, __LINE__);
+ kfree(u_stream_buff_info);
+ mutex_unlock(&cpp_dev->mutex);
+ return -EINVAL;
+ }
k_stream_buff_info.buffer_info =
kzalloc(k_stream_buff_info.num_buffs *
sizeof(struct msm_cpp_buffer_info_t), GFP_KERNEL);
- if (!k_stream_buff_info.buffer_info) {
+ if (ZERO_OR_NULL_PTR(k_stream_buff_info.buffer_info)) {
pr_err("%s:%d: malloc error\n", __func__, __LINE__);
kfree(u_stream_buff_info);
mutex_unlock(&cpp_dev->mutex);
@@ -1552,6 +1576,33 @@
rc = 0;
break;
}
+ case VIDIOC_MSM_CPP_QUEUE_BUF: {
+ struct msm_pproc_queue_buf_info queue_buf_info;
+ rc = (copy_from_user(&queue_buf_info,
+ (void __user *)ioctl_ptr->ioctl_ptr,
+ sizeof(struct msm_pproc_queue_buf_info)) ?
+ -EFAULT : 0);
+ if (rc) {
+ ERR_COPY_FROM_USER();
+ break;
+ }
+
+ if (queue_buf_info.is_buf_dirty) {
+ rc = msm_cpp_buffer_ops(cpp_dev,
+ VIDIOC_MSM_BUF_MNGR_PUT_BUF,
+ &queue_buf_info.buff_mgr_info);
+ } else {
+ rc = msm_cpp_buffer_ops(cpp_dev,
+ VIDIOC_MSM_BUF_MNGR_BUF_DONE,
+ &queue_buf_info.buff_mgr_info);
+ }
+ if (rc < 0) {
+ pr_err("error in buf done\n");
+ rc = -EINVAL;
+ }
+
+ break;
+ }
}
mutex_unlock(&cpp_dev->mutex);
CPP_DBG("X\n");
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
index 0a70d37..796bede 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
@@ -21,6 +21,14 @@
#include <media/v4l2-subdev.h>
#include "msm_sd.h"
+/* hw version info:
+ 31:28 Major version
+ 27:16 Minor version
+ 15:0 Revision bits
+**/
+#define CPP_HW_VERSION_1_1_0 0x10010000
+#define CPP_HW_VERSION_1_1_1 0x10010001
+
#define MAX_ACTIVE_CPP_INSTANCE 8
#define MAX_CPP_PROCESSING_FRAME 2
#define MAX_CPP_V4l2_EVENTS 30
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 d53d766..d302131 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
@@ -25,8 +25,8 @@
#include <media/v4l2-ioctl.h>
#include <media/v4l2-subdev.h>
#include <media/media-entity.h>
-#include <media/msmb_pproc.h>
#include <media/msmb_generic_buf_mgr.h>
+#include <media/msmb_pproc.h>
#include "msm_vpe.h"
#include "msm_camera_io_util.h"
diff --git a/drivers/media/platform/msm/camera_v2/sensor/Makefile b/drivers/media/platform/msm/camera_v2/sensor/Makefile
index 18ac623..bd1b10b 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/Makefile
+++ b/drivers/media/platform/msm/camera_v2/sensor/Makefile
@@ -9,9 +9,11 @@
obj-$(CONFIG_IMX135) += imx135.o
obj-$(CONFIG_OV8825) += ov8825.o
obj-$(CONFIG_s5k4e1) += s5k4e1.o
+obj-$(CONFIG_OV12830) += ov12830.o
obj-$(CONFIG_OV2720) += ov2720.o
obj-$(CONFIG_OV9724) += ov9724.o
obj-$(CONFIG_HI256) += hi256.o
+obj-$(CONFIG_OV5648) += ov5648.o
obj-$(CONFIG_MT9M114) += mt9m114.o
obj-$(CONFIG_SP1628) += sp1628.o
obj-$(CONFIG_GC0339) += gc0339.o
diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
index a27ca99..4fa3085 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
@@ -46,30 +46,44 @@
static void msm_cci_set_clk_param(struct cci_device *cci_dev)
{
- struct msm_cci_clk_params_t *clk_params = &cci_dev->cci_clk_params;
+ struct msm_cci_clk_params_t *clk_params = NULL;
+ uint8_t count = 0;
- msm_camera_io_w(clk_params->hw_thigh << 16 | clk_params->hw_tlow,
- cci_dev->base + CCI_I2C_M0_SCL_CTL_ADDR);
- msm_camera_io_w(clk_params->hw_tsu_sto << 16 | clk_params->hw_tsu_sta,
- cci_dev->base + CCI_I2C_M0_SDA_CTL_0_ADDR);
- msm_camera_io_w(clk_params->hw_thd_dat << 16 | clk_params->hw_thd_sta,
- cci_dev->base + CCI_I2C_M0_SDA_CTL_1_ADDR);
- msm_camera_io_w(clk_params->hw_tbuf,
- cci_dev->base + CCI_I2C_M0_SDA_CTL_2_ADDR);
- msm_camera_io_w(clk_params->hw_scl_stretch_en << 8 |
- clk_params->hw_trdhld << 4 | clk_params->hw_tsp,
- cci_dev->base + CCI_I2C_M0_MISC_CTL_ADDR);
- msm_camera_io_w(clk_params->hw_thigh << 16 | clk_params->hw_tlow,
- cci_dev->base + CCI_I2C_M1_SCL_CTL_ADDR);
- msm_camera_io_w(clk_params->hw_tsu_sto << 16 | clk_params->hw_tsu_sta,
- cci_dev->base + CCI_I2C_M1_SDA_CTL_0_ADDR);
- msm_camera_io_w(clk_params->hw_thd_dat << 16 | clk_params->hw_thd_sta,
- cci_dev->base + CCI_I2C_M1_SDA_CTL_1_ADDR);
- msm_camera_io_w(clk_params->hw_tbuf,
- cci_dev->base + CCI_I2C_M1_SDA_CTL_2_ADDR);
- msm_camera_io_w(clk_params->hw_scl_stretch_en << 8 |
- clk_params->hw_trdhld << 4 | clk_params->hw_tsp,
- cci_dev->base + CCI_I2C_M1_MISC_CTL_ADDR);
+ for (count = 0; count < MASTER_MAX; count++) {
+ if (MASTER_0 == count) {
+ clk_params = &cci_dev->cci_clk_params[count];
+ msm_camera_io_w(clk_params->hw_thigh << 16 |
+ clk_params->hw_tlow,
+ cci_dev->base + CCI_I2C_M0_SCL_CTL_ADDR);
+ msm_camera_io_w(clk_params->hw_tsu_sto << 16 |
+ clk_params->hw_tsu_sta,
+ cci_dev->base + CCI_I2C_M0_SDA_CTL_0_ADDR);
+ msm_camera_io_w(clk_params->hw_thd_dat << 16 |
+ clk_params->hw_thd_sta,
+ cci_dev->base + CCI_I2C_M0_SDA_CTL_1_ADDR);
+ msm_camera_io_w(clk_params->hw_tbuf,
+ cci_dev->base + CCI_I2C_M0_SDA_CTL_2_ADDR);
+ msm_camera_io_w(clk_params->hw_scl_stretch_en << 8 |
+ clk_params->hw_trdhld << 4 | clk_params->hw_tsp,
+ cci_dev->base + CCI_I2C_M0_MISC_CTL_ADDR);
+ } else if (MASTER_1 == count) {
+ clk_params = &cci_dev->cci_clk_params[count];
+ msm_camera_io_w(clk_params->hw_thigh << 16 |
+ clk_params->hw_tlow,
+ cci_dev->base + CCI_I2C_M1_SCL_CTL_ADDR);
+ msm_camera_io_w(clk_params->hw_tsu_sto << 16 |
+ clk_params->hw_tsu_sta,
+ cci_dev->base + CCI_I2C_M1_SDA_CTL_0_ADDR);
+ msm_camera_io_w(clk_params->hw_thd_dat << 16 |
+ clk_params->hw_thd_sta,
+ cci_dev->base + CCI_I2C_M1_SDA_CTL_1_ADDR);
+ msm_camera_io_w(clk_params->hw_tbuf,
+ cci_dev->base + CCI_I2C_M1_SDA_CTL_2_ADDR);
+ msm_camera_io_w(clk_params->hw_scl_stretch_en << 8 |
+ clk_params->hw_trdhld << 4 | clk_params->hw_tsp,
+ cci_dev->base + CCI_I2C_M1_MISC_CTL_ADDR);
+ }
+ }
return;
}
@@ -910,58 +924,96 @@
{
int32_t rc = 0;
uint32_t val = 0;
+ uint8_t count = 0;
struct device_node *of_node = cci_dev->pdev->dev.of_node;
+ struct device_node *src_node = NULL;
- rc = of_property_read_u32(of_node, "qcom,hw-thigh", &val);
- CDBG("%s qcom,hw-thigh %d, rc %d\n", __func__, val, rc);
- if (!rc)
- cci_dev->cci_clk_params.hw_thigh = val;
+ for (count = 0; count < MASTER_MAX; count++) {
- rc = of_property_read_u32(of_node, "qcom,hw-tlow", &val);
- CDBG("%s qcom,hw-tlow %d, rc %d\n", __func__, val, rc);
- if (!rc)
- cci_dev->cci_clk_params.hw_tlow = val;
+ if (MASTER_0 == count)
+ src_node = of_find_node_by_name(of_node,
+ "qcom,cci-master0");
+ else if (MASTER_1 == count)
+ src_node = of_find_node_by_name(of_node,
+ "qcom,cci-master1");
+ else
+ return;
- rc = of_property_read_u32(of_node, "qcom,hw-tsu-sto", &val);
- CDBG("%s qcom,hw-tsu-sto %d, rc %d\n", __func__, val, rc);
- if (!rc)
- cci_dev->cci_clk_params.hw_tsu_sto = val;
+ rc = of_property_read_u32(src_node, "qcom,hw-thigh", &val);
+ CDBG("%s qcom,hw-thigh %d, rc %d\n", __func__, val, rc);
+ if (!rc)
+ cci_dev->cci_clk_params[count].hw_thigh = val;
+ else
+ cci_dev->cci_clk_params[count].hw_thigh = 78;
- rc = of_property_read_u32(of_node, "qcom,hw-tsu-sta", &val);
- CDBG("%s qcom,hw-tsu-sta %d, rc %d\n", __func__, val, rc);
- if (!rc)
- cci_dev->cci_clk_params.hw_tsu_sta = val;
+ rc = of_property_read_u32(src_node, "qcom,hw-tlow", &val);
+ CDBG("%s qcom,hw-tlow %d, rc %d\n", __func__, val, rc);
+ if (!rc)
+ cci_dev->cci_clk_params[count].hw_tlow = val;
+ else
+ cci_dev->cci_clk_params[count].hw_tlow = 114;
- rc = of_property_read_u32(of_node, "qcom,hw-thd-dat", &val);
- CDBG("%s qcom,hw-thd-dat %d, rc %d\n", __func__, val, rc);
- if (!rc)
- cci_dev->cci_clk_params.hw_thd_dat = val;
+ rc = of_property_read_u32(src_node, "qcom,hw-tsu-sto", &val);
+ CDBG("%s qcom,hw-tsu-sto %d, rc %d\n", __func__, val, rc);
+ if (!rc)
+ cci_dev->cci_clk_params[count].hw_tsu_sto = val;
+ else
+ cci_dev->cci_clk_params[count].hw_tsu_sto = 28;
- rc = of_property_read_u32(of_node, "qcom,hw-thd-sta", &val);
- CDBG("%s qcom,hwthd-sta %d, rc %d\n", __func__, val, rc);
- if (!rc)
- cci_dev->cci_clk_params.hw_thd_sta = val;
+ rc = of_property_read_u32(src_node, "qcom,hw-tsu-sta", &val);
+ CDBG("%s qcom,hw-tsu-sta %d, rc %d\n", __func__, val, rc);
+ if (!rc)
+ cci_dev->cci_clk_params[count].hw_tsu_sta = val;
+ else
+ cci_dev->cci_clk_params[count].hw_tsu_sta = 28;
- rc = of_property_read_u32(of_node, "qcom,hw-tbuf", &val);
- CDBG("%s qcom,hw-tbuf %d, rc %d\n", __func__, val, rc);
- if (!rc)
- cci_dev->cci_clk_params.hw_tbuf = val;
+ rc = of_property_read_u32(src_node, "qcom,hw-thd-dat", &val);
+ CDBG("%s qcom,hw-thd-dat %d, rc %d\n", __func__, val, rc);
+ if (!rc)
+ cci_dev->cci_clk_params[count].hw_thd_dat = val;
+ else
+ cci_dev->cci_clk_params[count].hw_thd_dat = 10;
- rc = of_property_read_u32(of_node, "qcom,hw-scl-stretch-en", &val);
- CDBG("%s qcom,hw-scl-stretch-en %d, rc %d\n", __func__, val, rc);
- if (!rc)
- cci_dev->cci_clk_params.hw_scl_stretch_en = val;
+ rc = of_property_read_u32(src_node, "qcom,hw-thd-sta", &val);
+ CDBG("%s qcom,hwthd-sta %d, rc %d\n", __func__, val, rc);
+ if (!rc)
+ cci_dev->cci_clk_params[count].hw_thd_sta = val;
+ else
+ cci_dev->cci_clk_params[count].hw_thd_sta = 77;
- rc = of_property_read_u32(of_node, "qcom,hw-trdhld", &val);
- CDBG("%s qcom,hw-trdhld %d, rc %d\n", __func__, val, rc);
- if (!rc)
- cci_dev->cci_clk_params.hw_trdhld = val;
+ rc = of_property_read_u32(src_node, "qcom,hw-tbuf", &val);
+ CDBG("%s qcom,hw-tbuf %d, rc %d\n", __func__, val, rc);
+ if (!rc)
+ cci_dev->cci_clk_params[count].hw_tbuf = val;
+ else
+ cci_dev->cci_clk_params[count].hw_tbuf = 118;
- rc = of_property_read_u32(of_node, "qcom,hw-tsp", &val);
- CDBG("%s qcom,hw-tsp %d, rc %d\n", __func__, val, rc);
- if (!rc)
- cci_dev->cci_clk_params.hw_tsp = val;
+ rc = of_property_read_u32(src_node,
+ "qcom,hw-scl-stretch-en", &val);
+ CDBG("%s qcom,hw-scl-stretch-en %d, rc %d\n",
+ __func__, val, rc);
+ if (!rc)
+ cci_dev->cci_clk_params[count].hw_scl_stretch_en = val;
+ else
+ cci_dev->cci_clk_params[count].hw_scl_stretch_en = 0;
+ rc = of_property_read_u32(src_node, "qcom,hw-trdhld", &val);
+ CDBG("%s qcom,hw-trdhld %d, rc %d\n", __func__, val, rc);
+ if (!rc)
+ cci_dev->cci_clk_params[count].hw_trdhld = val;
+ else
+ cci_dev->cci_clk_params[count].hw_trdhld = 6;
+
+ rc = of_property_read_u32(src_node, "qcom,hw-tsp", &val);
+ CDBG("%s qcom,hw-tsp %d, rc %d\n", __func__, val, rc);
+ if (!rc)
+ cci_dev->cci_clk_params[count].hw_tsp = val;
+ else
+ cci_dev->cci_clk_params[count].hw_tsp = 1;
+
+ of_node_put(src_node);
+ src_node = NULL;
+ }
return;
}
diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.h b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.h
index f9e40f1..16edaae 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.h
@@ -139,7 +139,7 @@
struct msm_camera_cci_i2c_queue_info
cci_i2c_queue_info[NUM_MASTERS][NUM_QUEUES];
struct msm_camera_cci_master_info cci_master_info[NUM_MASTERS];
- struct msm_cci_clk_params_t cci_clk_params;
+ struct msm_cci_clk_params_t cci_clk_params[MASTER_MAX];
struct gpio *cci_gpio_tbl;
uint8_t cci_gpio_tbl_size;
};
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
index 0fbe238..21b9cdc 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
@@ -400,7 +400,6 @@
struct msm_camera_csi_lane_params *csi_lane_params;
uint16_t csi_lane_mask;
csi_lane_params = (struct msm_camera_csi_lane_params *)arg;
- csi_lane_mask = csi_lane_params->csi_lane_mask;
if (!csiphy_dev || !csiphy_dev->ref_count) {
pr_err("%s csiphy dev NULL / ref_count ZERO\n", __func__);
@@ -413,19 +412,29 @@
return -EINVAL;
}
- CDBG("%s csiphy_params, lane assign %x mask = %x\n",
- __func__,
- csi_lane_params->csi_lane_assign,
- csi_lane_params->csi_lane_mask);
-
if (csiphy_dev->hw_version < CSIPHY_VERSION_V30) {
csiphy_dev->lane_mask[csiphy_dev->pdev->id] = 0;
for (i = 0; i < 4; i++)
msm_camera_io_w(0x0, csiphy_dev->base +
MIPI_CSIPHY_LNn_CFG2_ADDR + 0x40*i);
} else {
+ if (!csi_lane_params) {
+ pr_err("%s:%d failed: csi_lane_params %p\n", __func__,
+ __LINE__, csi_lane_params);
+ return -EINVAL;
+ }
+ csi_lane_mask = csi_lane_params->csi_lane_mask;
+
+ CDBG("%s csiphy_params, lane assign %x mask = %x\n",
+ __func__,
+ csi_lane_params->csi_lane_assign,
+ csi_lane_params->csi_lane_mask);
+
+ if (!csi_lane_mask)
+ csi_lane_mask = 0x1f;
+
csiphy_dev->lane_mask[csiphy_dev->pdev->id] &=
- ~(csi_lane_params->csi_lane_mask);
+ ~(csi_lane_mask);
i = 0;
while (csi_lane_mask & 0x1F) {
if (csi_lane_mask & 0x1) {
@@ -475,7 +484,6 @@
struct msm_camera_csi_lane_params *csi_lane_params;
uint16_t csi_lane_mask;
csi_lane_params = (struct msm_camera_csi_lane_params *)arg;
- csi_lane_mask = csi_lane_params->csi_lane_mask;
if (!csiphy_dev || !csiphy_dev->ref_count) {
pr_err("%s csiphy dev NULL / ref_count ZERO\n", __func__);
@@ -488,19 +496,29 @@
return -EINVAL;
}
- CDBG("%s csiphy_params, lane assign %x mask = %x\n",
- __func__,
- csi_lane_params->csi_lane_assign,
- csi_lane_params->csi_lane_mask);
-
if (csiphy_dev->hw_version < CSIPHY_VERSION_V30) {
csiphy_dev->lane_mask[csiphy_dev->pdev->id] = 0;
for (i = 0; i < 4; i++)
msm_camera_io_w(0x0, csiphy_dev->base +
MIPI_CSIPHY_LNn_CFG2_ADDR + 0x40*i);
} else {
+ if (!csi_lane_params) {
+ pr_err("%s:%d failed: csi_lane_params %p\n", __func__,
+ __LINE__, csi_lane_params);
+ return -EINVAL;
+ }
+ csi_lane_mask = csi_lane_params->csi_lane_mask;
+
+ CDBG("%s csiphy_params, lane assign %x mask = %x\n",
+ __func__,
+ csi_lane_params->csi_lane_assign,
+ csi_lane_params->csi_lane_mask);
+
+ if (!csi_lane_mask)
+ csi_lane_mask = 0x1f;
+
csiphy_dev->lane_mask[csiphy_dev->pdev->id] &=
- ~(csi_lane_params->csi_lane_mask);
+ ~(csi_lane_mask);
i = 0;
while (csi_lane_mask & 0x1F) {
if (csi_lane_mask & 0x1) {
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 e096e96..4ebcfdf 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
@@ -444,14 +444,16 @@
spi_client->spi_master->dev.of_node;
else if (e_ctrl->eeprom_device_type == MSM_CAMERA_PLATFORM_DEVICE)
of_node = e_ctrl->pdev->dev.of_node;
- rc = msm_camera_get_dt_power_setting_data(of_node,
- &power_info->power_setting, &power_info->power_setting_size);
- if (rc)
- return rc;
rc = msm_camera_get_dt_vreg_data(of_node, &power_info->cam_vreg,
&power_info->num_vreg);
- if (rc)
+ if (rc < 0)
+ return rc;
+
+ rc = msm_camera_get_dt_power_setting_data(of_node,
+ power_info->cam_vreg, power_info->num_vreg,
+ &power_info->power_setting, &power_info->power_setting_size);
+ if (rc < 0)
goto ERROR1;
power_info->gpio_conf = kzalloc(sizeof(struct msm_camera_gpio_conf),
diff --git a/drivers/media/platform/msm/camera_v2/sensor/gc0339.c b/drivers/media/platform/msm/camera_v2/sensor/gc0339.c
index 8cba04c..cc38b56 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/gc0339.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/gc0339.c
@@ -490,6 +490,11 @@
break;
}
+ if (conf_array.addr_type == MSM_CAMERA_I2C_WORD_ADDR
+ || conf_array.data_type == MSM_CAMERA_I2C_WORD_DATA
+ || !conf_array.size)
+ break;
+
reg_setting = kzalloc(conf_array.size *
(sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL);
if (!reg_setting) {
diff --git a/drivers/media/platform/msm/camera_v2/sensor/hi256.c b/drivers/media/platform/msm/camera_v2/sensor/hi256.c
index f1df703..de651df 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/hi256.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/hi256.c
@@ -1000,15 +1000,25 @@
{0x30, 0x06},
{0x31, 0x40},
{0x03, 0x20},
- {0x88, 0x05},
- {0x89, 0x7e},
- {0x8a, 0x40},
+ {0x88, 0x01},
+ {0x89, 0x5f},
+ {0x8a, 0x90},
{0x03, 0x20},
{0x10, 0x9c},
{0x03, 0x22},
{0x10, 0xe9},
};
+static struct msm_camera_i2c_reg_conf hi256_sleep_settings[] = {
+ {0x03, 0x00},
+ {0x01, 0xf1},
+ {0x03, 0x02},
+ {0x55, 0x10},
+ {0x01, 0xf1},
+ {0x01, 0xf3},
+ {0x01, 0xf1},
+};
+
static const struct i2c_device_id hi256_i2c_id[] = {
{HI256_SENSOR_NAME, (kernel_ulong_t)&hi256_s_ctrl},
@@ -1073,6 +1083,13 @@
}
+static int32_t hi256_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl)
+{
+ hi256_i2c_write_table(s_ctrl, &hi256_sleep_settings[0],
+ ARRAY_SIZE(hi256_sleep_settings));
+ return msm_sensor_power_down(s_ctrl);
+}
+
static int32_t hi256_platform_probe(struct platform_device *pdev)
{
int32_t rc;
@@ -1393,7 +1410,7 @@
static struct msm_sensor_fn_t hi256_sensor_func_tbl = {
.sensor_config = hi256_sensor_config,
.sensor_power_up = msm_sensor_power_up,
- .sensor_power_down = msm_sensor_power_down,
+ .sensor_power_down = hi256_sensor_power_down,
.sensor_match_id = hi256_sensor_match_id,
};
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c
index 80b1ccb..3792247 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c
@@ -64,7 +64,7 @@
}
int32_t msm_camera_cci_i2c_read_seq(struct msm_camera_i2c_client *client,
- uint32_t addr, uint8_t *data, uint16_t num_byte)
+ uint32_t addr, uint8_t *data, uint32_t num_byte)
{
int32_t rc = -EFAULT;
unsigned char *buf = NULL;
@@ -137,7 +137,7 @@
}
int32_t msm_camera_cci_i2c_write_seq(struct msm_camera_i2c_client *client,
- uint32_t addr, uint8_t *data, uint16_t num_byte)
+ uint32_t addr, uint8_t *data, uint32_t num_byte)
{
int32_t rc = -EFAULT;
uint8_t i = 0;
@@ -338,17 +338,11 @@
enum msm_camera_i2c_data_type data_type)
{
int32_t rc;
- int i;
S_I2C_DBG("%s: addr: 0x%x data: 0x%x dt: %d\n",
__func__, addr, data, data_type);
- for (i = 0; i < I2C_POLL_MAX_ITERATION; i++) {
- rc = msm_camera_cci_i2c_compare(client,
- addr, data, data_type);
- if (rc == 0 || rc < 0)
- break;
- usleep_range(10000, 11000);
- }
+ rc = msm_camera_cci_i2c_compare(client,
+ addr, data, data_type);
return rc;
}
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 2511651..3898bd8 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
@@ -23,12 +23,13 @@
#define CDBG(fmt, args...) do { } while (0)
#endif
-int32_t msm_camera_get_dt_power_setting_data(struct device_node *of_node,
+int msm_camera_get_dt_power_setting_data(struct device_node *of_node,
+ struct camera_vreg_t *cam_vreg, int num_vreg,
struct msm_sensor_power_setting **power_setting,
uint16_t *power_setting_size)
{
- int32_t rc = 0, i = 0;
- int32_t count = 0;
+ int rc = 0, i, j;
+ int count = 0;
const char *seq_name = NULL;
uint32_t *array = NULL;
struct msm_sensor_power_setting *ps;
@@ -43,8 +44,7 @@
if (count <= 0)
return 0;
- ps = kzalloc(sizeof(struct msm_sensor_power_setting) * count,
- GFP_KERNEL);
+ ps = kzalloc(sizeof(*ps) * count, GFP_KERNEL);
if (!ps) {
pr_err("%s failed %d\n", __func__, __LINE__);
return -ENOMEM;
@@ -77,6 +77,10 @@
ps[i].seq_type = SENSOR_I2C_MUX;
CDBG("%s:%d seq_type[%d] %d\n", __func__, __LINE__,
i, ps[i].seq_type);
+ } else {
+ CDBG("%s: unrecognized seq-type\n", __func__);
+ rc = -EILSEQ;
+ goto ERROR1;
}
}
@@ -91,24 +95,47 @@
pr_err("%s failed %d\n", __func__, __LINE__);
goto ERROR1;
}
- if (!strcmp(seq_name, "cam_vdig"))
- ps[i].seq_val = CAM_VDIG;
- else if (!strcmp(seq_name, "cam_vio"))
- ps[i].seq_val = CAM_VIO;
- else if (!strcmp(seq_name, "cam_vana"))
- ps[i].seq_val = CAM_VANA;
- else if (!strcmp(seq_name, "cam_vaf"))
- ps[i].seq_val = CAM_VAF;
- else if (!strcmp(seq_name, "sensor_gpio_reset"))
- ps[i].seq_val = SENSOR_GPIO_RESET;
- else if (!strcmp(seq_name, "sensor_gpio_standby"))
- ps[i].seq_val = SENSOR_GPIO_STANDBY;
- else if (!strcmp(seq_name, "sensor_cam_mclk"))
- ps[i].seq_val = SENSOR_CAM_MCLK;
- else if (!strcmp(seq_name, "sensor_cam_clk"))
- ps[i].seq_val = SENSOR_CAM_CLK;
- else if (!strcmp(seq_name, "none"))
- ps[i].seq_val = 0;
+ switch (ps[i].seq_type) {
+ case SENSOR_VREG:
+ for (j = 0; j < num_vreg; j++) {
+ if (!strcmp(seq_name, cam_vreg[j].reg_name))
+ break;
+ }
+ if (j < num_vreg)
+ ps[i].seq_val = j;
+ else
+ rc = -EILSEQ;
+ break;
+ case SENSOR_GPIO:
+ if (!strcmp(seq_name, "sensor_gpio_reset"))
+ ps[i].seq_val = SENSOR_GPIO_RESET;
+ else if (!strcmp(seq_name, "sensor_gpio_standby"))
+ ps[i].seq_val = SENSOR_GPIO_STANDBY;
+ else
+ rc = -EILSEQ;
+ break;
+ case SENSOR_CLK:
+ if (!strcmp(seq_name, "sensor_cam_mclk"))
+ ps[i].seq_val = SENSOR_CAM_MCLK;
+ else if (!strcmp(seq_name, "sensor_cam_clk"))
+ ps[i].seq_val = SENSOR_CAM_CLK;
+ else
+ rc = -EILSEQ;
+ break;
+ case SENSOR_I2C_MUX:
+ if (!strcmp(seq_name, "none"))
+ ps[i].seq_val = 0;
+ else
+ rc = -EILSEQ;
+ break;
+ default:
+ rc = -EILSEQ;
+ break;
+ }
+ if (rc < 0) {
+ CDBG("%s: unrecognized seq-val\n", __func__);
+ goto ERROR1;
+ }
}
array = kzalloc(sizeof(uint32_t) * count, GFP_KERNEL);
@@ -151,6 +178,7 @@
}
kfree(array);
return rc;
+
ERROR2:
kfree(array);
ERROR1:
@@ -159,11 +187,11 @@
return rc;
}
-int32_t msm_camera_get_dt_gpio_req_tbl(struct device_node *of_node,
+int msm_camera_get_dt_gpio_req_tbl(struct device_node *of_node,
struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
uint16_t gpio_array_size)
{
- int32_t rc = 0, i = 0;
+ int rc = 0, i = 0;
uint32_t count = 0;
uint32_t *val_array = NULL;
@@ -247,8 +275,7 @@
struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
uint16_t gpio_array_size)
{
- int32_t rc = 0;
- int32_t val = 0;
+ int rc = 0, val = 0;
gconf->gpio_num_info = kzalloc(sizeof(struct msm_camera_gpio_num_info),
GFP_KERNEL);
@@ -299,10 +326,10 @@
return rc;
}
-int32_t msm_camera_get_dt_vreg_data(struct device_node *of_node,
+int msm_camera_get_dt_vreg_data(struct device_node *of_node,
struct camera_vreg_t **cam_vreg, int *num_vreg)
{
- int32_t rc = 0, i = 0;
+ int rc = 0, i = 0;
uint32_t count = 0;
uint32_t *vreg_array = NULL;
struct camera_vreg_t *vreg = NULL;
@@ -313,8 +340,7 @@
if (!count)
return 0;
- vreg = kzalloc(sizeof(struct camera_vreg_t) * count,
- GFP_KERNEL);
+ vreg = kzalloc(sizeof(*vreg) * count, GFP_KERNEL);
if (!vreg) {
pr_err("%s failed %d\n", __func__, __LINE__);
return -ENOMEM;
@@ -398,7 +424,7 @@
return rc;
}
-static int32_t msm_camera_enable_i2c_mux(struct msm_camera_i2c_conf *i2c_conf)
+static int msm_camera_enable_i2c_mux(struct msm_camera_i2c_conf *i2c_conf)
{
struct v4l2_subdev *i2c_mux_sd =
dev_get_drvdata(&i2c_conf->mux_dev->dev);
@@ -409,7 +435,7 @@
return 0;
}
-static int32_t msm_camera_disable_i2c_mux(struct msm_camera_i2c_conf *i2c_conf)
+static int msm_camera_disable_i2c_mux(struct msm_camera_i2c_conf *i2c_conf)
{
struct v4l2_subdev *i2c_mux_sd =
dev_get_drvdata(&i2c_conf->mux_dev->dev);
@@ -418,11 +444,11 @@
return 0;
}
-int32_t msm_camera_power_up(struct msm_camera_power_ctrl_t *ctrl,
+int msm_camera_power_up(struct msm_camera_power_ctrl_t *ctrl,
enum msm_camera_device_type_t device_type,
struct msm_camera_i2c_client *sensor_i2c_client)
{
- int32_t rc = 0, index = 0, no_gpio = 0;
+ int rc = 0, index = 0, no_gpio = 0;
struct msm_sensor_power_setting *power_setting = NULL;
CDBG("%s:%d\n", __func__, __LINE__);
@@ -484,7 +510,7 @@
SENSOR_GPIO_MAX);
goto power_up_failed;
}
- pr_debug("%s:%d gpio set val %d\n", __func__, __LINE__,
+ CDBG("%s:%d gpio set val %d\n", __func__, __LINE__,
ctrl->gpio_conf->gpio_num_info->gpio_num
[power_setting->seq_val]);
gpio_set_value_cansleep(
@@ -584,11 +610,11 @@
return rc;
}
-int32_t msm_camera_power_down(struct msm_camera_power_ctrl_t *ctrl,
+int msm_camera_power_down(struct msm_camera_power_ctrl_t *ctrl,
enum msm_camera_device_type_t device_type,
struct msm_camera_i2c_client *sensor_i2c_client)
{
- int32_t index = 0;
+ int index = 0;
struct msm_sensor_power_setting *power_setting = NULL;
CDBG("%s:%d\n", __func__, __LINE__);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.h b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.h
index 5a35747..fee2a4c 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.h
@@ -19,6 +19,7 @@
#include "msm_camera_i2c.h"
int32_t msm_camera_get_dt_power_setting_data(struct device_node *of_node,
+ struct camera_vreg_t *cam_vreg, int num_vreg,
struct msm_sensor_power_setting **power_setting,
uint16_t *power_setting_size);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_i2c.h b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_i2c.h
index 7af04ba..389e9d9 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_i2c.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_i2c.h
@@ -35,11 +35,11 @@
int (*i2c_read) (struct msm_camera_i2c_client *, uint32_t, uint16_t *,
enum msm_camera_i2c_data_type);
int32_t (*i2c_read_seq)(struct msm_camera_i2c_client *, uint32_t,
- uint8_t *, uint16_t);
+ uint8_t *, uint32_t);
int (*i2c_write) (struct msm_camera_i2c_client *, uint32_t, uint16_t,
enum msm_camera_i2c_data_type);
int (*i2c_write_seq) (struct msm_camera_i2c_client *, uint32_t ,
- uint8_t *, uint16_t);
+ uint8_t *, uint32_t);
int32_t (*i2c_write_table)(struct msm_camera_i2c_client *,
struct msm_camera_i2c_reg_setting *);
int32_t (*i2c_write_seq_table)(struct msm_camera_i2c_client *,
@@ -62,14 +62,14 @@
enum msm_camera_i2c_data_type data_type);
int32_t msm_camera_cci_i2c_read_seq(struct msm_camera_i2c_client *client,
- uint32_t addr, uint8_t *data, uint16_t num_byte);
+ uint32_t addr, uint8_t *data, uint32_t num_byte);
int32_t msm_camera_cci_i2c_write(struct msm_camera_i2c_client *client,
uint32_t addr, uint16_t data,
enum msm_camera_i2c_data_type data_type);
int32_t msm_camera_cci_i2c_write_seq(struct msm_camera_i2c_client *client,
- uint32_t addr, uint8_t *data, uint16_t num_byte);
+ uint32_t addr, uint8_t *data, uint32_t num_byte);
int32_t msm_camera_cci_i2c_write_table(
struct msm_camera_i2c_client *client,
@@ -101,14 +101,14 @@
enum msm_camera_i2c_data_type data_type);
int32_t msm_camera_qup_i2c_read_seq(struct msm_camera_i2c_client *client,
- uint32_t addr, uint8_t *data, uint16_t num_byte);
+ uint32_t addr, uint8_t *data, uint32_t num_byte);
int32_t msm_camera_qup_i2c_write(struct msm_camera_i2c_client *client,
uint32_t addr, uint16_t data,
enum msm_camera_i2c_data_type data_type);
int32_t msm_camera_qup_i2c_write_seq(struct msm_camera_i2c_client *client,
- uint32_t addr, uint8_t *data, uint16_t num_byte);
+ uint32_t addr, uint8_t *data, uint32_t num_byte);
int32_t msm_camera_qup_i2c_write_table(struct msm_camera_i2c_client *client,
struct msm_camera_i2c_reg_setting *write_setting);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c
index ac9cdbf..60d1509 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c
@@ -107,7 +107,7 @@
}
int32_t msm_camera_qup_i2c_read_seq(struct msm_camera_i2c_client *client,
- uint32_t addr, uint8_t *data, uint16_t num_byte)
+ uint32_t addr, uint8_t *data, uint32_t num_byte)
{
int32_t rc = -EFAULT;
unsigned char buf[client->addr_type+num_byte];
@@ -188,7 +188,7 @@
}
int32_t msm_camera_qup_i2c_write_seq(struct msm_camera_i2c_client *client,
- uint32_t addr, uint8_t *data, uint16_t num_byte)
+ uint32_t addr, uint8_t *data, uint32_t num_byte)
{
int32_t rc = -EFAULT;
unsigned char buf[client->addr_type+num_byte];
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_spi.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_spi.c
index d1d5f23..75b0063 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_spi.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_spi.c
@@ -67,50 +67,86 @@
}
-static int32_t msm_camera_spi_read_helper(struct msm_camera_i2c_client *client,
- struct msm_camera_spi_inst *inst, uint32_t addr, uint8_t *data,
- uint16_t num_byte)
+/**
+ * msm_camera_spi_tx_helper() - wrapper for SPI transaction
+ * @client: io client
+ * @inst: inst of this transaction
+ * @addr: device addr following the inst
+ * @data: output byte array (could be NULL)
+ * @num_byte: size of @data
+ * @tx, rx: optional transfer buffer. It must be at least header
+ * + @num_byte long.
+ *
+ * This is the core function for SPI transaction, except for writes. It first
+ * checks address type, then allocates required memory for tx/rx buffers.
+ * It sends out <opcode><addr>, and optionally receives @num_byte of response,
+ * if @data is not NULL. This function does not check for wait conditions,
+ * and will return immediately once bus transaction finishes.
+ *
+ * This function will allocate buffers of header + @num_byte long. For
+ * large transfers, the allocation could fail. External buffer @tx, @rx
+ * should be passed in to bypass allocation. The size of buffer should be
+ * at least header + num_byte long. Since buffer is managed externally,
+ * @data will be ignored, and read results will be in @rx.
+ * @tx, @rx also can be used for repeated transfers to improve performance.
+ */
+int32_t msm_camera_spi_tx_helper(struct msm_camera_i2c_client *client,
+ struct msm_camera_spi_inst *inst, uint32_t addr, uint8_t *data,
+ uint32_t num_byte, char *tx, char *rx)
{
- int32_t rc = -EFAULT;
+ int32_t rc = -EINVAL;
struct spi_device *spi = client->spi_client->spi_master;
- char *tx, *rx;
- uint16_t len;
- int8_t retries = client->spi_client->retries;
+ char *ctx = NULL, *crx = NULL;
+ uint32_t len, hlen;
+ uint8_t retries = client->spi_client->retries;
if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR)
&& (client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
&& (client->addr_type != MSM_CAMERA_I2C_3B_ADDR))
return rc;
- len = sizeof(inst->opcode) + inst->addr_len + inst->dummy_len
- + num_byte;
+ hlen = msm_camera_spi_get_hlen(inst);
+ len = hlen + num_byte;
- tx = kmalloc(len, GFP_KERNEL | GFP_DMA);
- if (!tx)
+ if (tx)
+ ctx = tx;
+ else
+ ctx = kzalloc(len, GFP_KERNEL);
+ if (!ctx)
return -ENOMEM;
- rx = kmalloc(len, GFP_KERNEL | GFP_DMA);
- if (!rx) {
- kfree(tx);
- return -ENOMEM;
+
+ if (num_byte) {
+ if (rx)
+ crx = rx;
+ else
+ crx = kzalloc(len, GFP_KERNEL);
+ if (!crx) {
+ if (!tx)
+ kfree(ctx);
+ return -ENOMEM;
+ }
+ } else {
+ crx = NULL;
}
- memset(tx, 0, len);
- memset(rx, 0, len);
- tx[0] = inst->opcode;
- msm_camera_set_addr(addr, inst->addr_len, client->addr_type, tx + 1);
- while ((rc = msm_camera_spi_txfr(spi, tx, rx, len)) && retries) {
+ ctx[0] = inst->opcode;
+ msm_camera_set_addr(addr, inst->addr_len, client->addr_type, ctx + 1);
+ while ((rc = msm_camera_spi_txfr(spi, ctx, crx, len)) && retries) {
retries--;
msleep(client->spi_client->retry_delay);
}
- if (rc) {
+ if (rc < 0) {
SPIDBG("%s: failed %d\n", __func__, rc);
goto out;
}
- len = sizeof(inst->opcode) + inst->addr_len + inst->dummy_len;
- memcpy(data, rx + len, num_byte);
+ if (data && num_byte && !rx)
+ memcpy(data, crx + hlen, num_byte);
+
out:
- kfree(tx);
- kfree(rx);
+ if (!tx)
+ kfree(ctx);
+ if (!rx)
+ kfree(crx);
return rc;
}
@@ -118,16 +154,17 @@
uint32_t addr, uint16_t *data,
enum msm_camera_i2c_data_type data_type)
{
- int32_t rc = -EFAULT;
+ int32_t rc = -EINVAL;
uint8_t temp[2];
if ((data_type != MSM_CAMERA_I2C_BYTE_DATA)
&& (data_type != MSM_CAMERA_I2C_WORD_DATA))
return rc;
- rc = msm_camera_spi_read_helper(client,
- &client->spi_client->cmd_tbl.read, addr, &temp[0], data_type);
- if (rc)
+ rc = msm_camera_spi_tx_helper(client,
+ &client->spi_client->cmd_tbl.read, addr, &temp[0],
+ data_type, NULL, NULL);
+ if (rc < 0)
return rc;
if (data_type == MSM_CAMERA_I2C_BYTE_DATA)
@@ -140,15 +177,38 @@
}
int32_t msm_camera_spi_read_seq(struct msm_camera_i2c_client *client,
- uint32_t addr, uint8_t *data, uint16_t num_byte)
+ uint32_t addr, uint8_t *data, uint32_t num_byte)
{
- return msm_camera_spi_read_helper(client,
- &client->spi_client->cmd_tbl.read_seq, addr, data, num_byte);
+ return msm_camera_spi_tx_helper(client,
+ &client->spi_client->cmd_tbl.read_seq, addr, data, num_byte,
+ NULL, NULL);
+}
+
+/**
+ * msm_camera_spi_read_seq_l()- function for large SPI reads
+ * @client: io client
+ * @addr: device address to read
+ * @num_byte: read length
+ * @tx,rx: pre-allocated SPI buffer. Its size must be at least
+ * header + num_byte
+ *
+ * This function is used for large transactions. Instead of allocating SPI
+ * buffer each time, caller is responsible for pre-allocating memory buffers.
+ * Memory buffer must be at least header + num_byte. Header length can be
+ * obtained by msm_camera_spi_get_hlen().
+ */
+int32_t msm_camera_spi_read_seq_l(struct msm_camera_i2c_client *client,
+ uint32_t addr, uint32_t num_byte, char *tx, char *rx)
+{
+ return msm_camera_spi_tx_helper(client,
+ &client->spi_client->cmd_tbl.read_seq, addr, NULL, num_byte,
+ tx, rx);
}
int32_t msm_camera_spi_query_id(struct msm_camera_i2c_client *client,
- uint32_t addr, uint8_t *data, uint16_t num_byte)
+ uint32_t addr, uint8_t *data, uint32_t num_byte)
{
- return msm_camera_spi_read_helper(client,
- &client->spi_client->cmd_tbl.query_id, addr, data, num_byte);
+ return msm_camera_spi_tx_helper(client,
+ &client->spi_client->cmd_tbl.query_id, addr, data, num_byte,
+ NULL, NULL);
}
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_spi.h b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_spi.h
index 564e470..0aefa50 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_spi.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_spi.h
@@ -17,6 +17,12 @@
#include <media/msm_cam_sensor.h>
#include "msm_camera_i2c.h"
+/**
+ * Common SPI communication scheme
+ * tx: <opcode>[addr][wait][write buffer]
+ * rx: [read buffer]
+ * Some inst require polling busy reg until it's done
+ */
struct msm_camera_spi_inst {
uint8_t opcode; /* one-byte opcode */
uint8_t addr_len; /* addr len in bytes */
@@ -38,14 +44,23 @@
uint8_t retries; /* retry times upon failure */
};
+static __always_inline
+uint16_t msm_camera_spi_get_hlen(struct msm_camera_spi_inst *inst)
+{
+ return sizeof(inst->opcode) + inst->addr_len + inst->dummy_len;
+}
+
int32_t msm_camera_spi_read(struct msm_camera_i2c_client *client,
uint32_t addr, uint16_t *data,
enum msm_camera_i2c_data_type data_type);
int32_t msm_camera_spi_read_seq(struct msm_camera_i2c_client *client,
- uint32_t addr, uint8_t *data, uint16_t num_byte);
+ uint32_t addr, uint8_t *data, uint32_t num_byte);
+
+int32_t msm_camera_spi_read_seq_l(struct msm_camera_i2c_client *client,
+ uint32_t addr, uint32_t num_byte, char *tx, char *rx);
int32_t msm_camera_spi_query_id(struct msm_camera_i2c_client *client,
- uint32_t addr, uint8_t *data, uint16_t num_byte);
+ uint32_t addr, uint8_t *data, uint32_t num_byte);
#endif
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 7f474bb..adbfbe7 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
@@ -569,7 +569,92 @@
CDBG("%s qcom,gpio-reset %d\n", __func__,
gconf->gpio_num_info->gpio_num[SENSOR_GPIO_STANDBY]);
}
- return rc;
+
+ rc = of_property_read_u32(of_node, "qcom,gpio-vio", &val);
+ if (!rc) {
+ if (val >= gpio_array_size) {
+ pr_err("%s:%d qcom,gpio-vio invalid %d\n",
+ __func__, __LINE__, val);
+ goto ERROR;
+ }
+ gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VIO] =
+ gpio_array[val];
+ CDBG("%s qcom,gpio-vio %d\n", __func__,
+ gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VIO]);
+ } else if (rc != -EINVAL) {
+ pr_err("%s:%d read qcom,gpio-vio failed rc %d\n",
+ __func__, __LINE__, rc);
+ goto ERROR;
+ }
+
+ rc = of_property_read_u32(of_node, "qcom,gpio-vana", &val);
+ if (!rc) {
+ if (val >= gpio_array_size) {
+ pr_err("%s:%d qcom,gpio-vana invalid %d\n",
+ __func__, __LINE__, val);
+ goto ERROR;
+ }
+ gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VANA] =
+ gpio_array[val];
+ CDBG("%s qcom,gpio-vana %d\n", __func__,
+ gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VANA]);
+ } else if (rc != -EINVAL) {
+ pr_err("%s:%d read qcom,gpio-vana failed rc %d\n",
+ __func__, __LINE__, rc);
+ goto ERROR;
+ }
+
+ rc = of_property_read_u32(of_node, "qcom,gpio-vdig", &val);
+ if (!rc) {
+ if (val >= gpio_array_size) {
+ pr_err("%s:%d qcom,gpio-vdig invalid %d\n",
+ __func__, __LINE__, val);
+ goto ERROR;
+ }
+ gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VDIG] =
+ gpio_array[val];
+ CDBG("%s qcom,gpio-vdig %d\n", __func__,
+ gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VDIG]);
+ } else if (rc != -EINVAL) {
+ pr_err("%s:%d read qcom,gpio-vdig failed rc %d\n",
+ __func__, __LINE__, rc);
+ goto ERROR;
+ }
+
+ rc = of_property_read_u32(of_node, "qcom,gpio-vaf", &val);
+ if (!rc) {
+ if (val >= gpio_array_size) {
+ pr_err("%s:%d qcom,gpio-vaf invalid %d\n",
+ __func__, __LINE__, val);
+ goto ERROR;
+ }
+ gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VAF] =
+ gpio_array[val];
+ CDBG("%s qcom,gpio-vaf %d\n", __func__,
+ gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VAF]);
+ } else if (rc != -EINVAL) {
+ pr_err("%s:%d read qcom,gpio-vaf failed rc %d\n",
+ __func__, __LINE__, rc);
+ goto ERROR;
+ }
+
+ rc = of_property_read_u32(of_node, "qcom,gpio-af-pwdm", &val);
+ if (!rc) {
+ if (val >= gpio_array_size) {
+ pr_err("%s:%d qcom,gpio-af-pwdm invalid %d\n",
+ __func__, __LINE__, val);
+ goto ERROR;
+ }
+ gconf->gpio_num_info->gpio_num[SENSOR_GPIO_AF_PWDM] =
+ gpio_array[val];
+ CDBG("%s qcom,gpio-af-pwdm %d\n", __func__,
+ gconf->gpio_num_info->gpio_num[SENSOR_GPIO_AF_PWDM]);
+ } else if (rc != -EINVAL) {
+ pr_err("%s:%d read qcom,gpio-af-pwdm failed rc %d\n",
+ __func__, __LINE__, rc);
+ goto ERROR;
+ }
+ return 0;
ERROR:
kfree(gconf->gpio_num_info);
@@ -1162,6 +1247,15 @@
return;
}
+static int msm_sensor_get_af_status(struct msm_sensor_ctrl_t *s_ctrl,
+ void __user *argp)
+{
+ /* TO-DO: Need to set AF status register address and expected value
+ We need to check the AF status in the sensor register and
+ set the status in the *status variable accordingly*/
+ return 0;
+}
+
static long msm_sensor_subdev_ioctl(struct v4l2_subdev *sd,
unsigned int cmd, void *arg)
{
@@ -1174,6 +1268,8 @@
switch (cmd) {
case VIDIOC_MSM_SENSOR_CFG:
return s_ctrl->func_tbl->sensor_config(s_ctrl, argp);
+ case VIDIOC_MSM_SENSOR_GET_AF_STATUS:
+ return msm_sensor_get_af_status(s_ctrl, argp);
case VIDIOC_MSM_SENSOR_RELEASE:
msm_sensor_stop_stream(s_ctrl);
return 0;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/mt9m114.c b/drivers/media/platform/msm/camera_v2/sensor/mt9m114.c
index c1cf862..de4fcd0 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/mt9m114.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/mt9m114.c
@@ -1424,8 +1424,51 @@
break;
}
break;
- }
- default:
+ }
+ case CFG_SET_SATURATION: {
+ int32_t sat_lev;
+ if (copy_from_user(&sat_lev, (void *)cdata->cfg.setting,
+ sizeof(int32_t))) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ rc = -EFAULT;
+ break;
+ }
+ pr_debug("%s: Saturation Value is %d", __func__, sat_lev);
+ break;
+ }
+ case CFG_SET_CONTRAST: {
+ int32_t con_lev;
+ if (copy_from_user(&con_lev, (void *)cdata->cfg.setting,
+ sizeof(int32_t))) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ rc = -EFAULT;
+ break;
+ }
+ pr_debug("%s: Contrast Value is %d", __func__, con_lev);
+ break;
+ }
+ case CFG_SET_SHARPNESS: {
+ int32_t shp_lev;
+ if (copy_from_user(&shp_lev, (void *)cdata->cfg.setting,
+ sizeof(int32_t))) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ rc = -EFAULT;
+ break;
+ }
+ pr_debug("%s: Sharpness Value is %d", __func__, shp_lev);
+ break;
+ }
+ case CFG_SET_AUTOFOCUS: {
+ /* TO-DO: set the Auto Focus */
+ pr_debug("%s: Setting Auto Focus", __func__);
+ break;
+ }
+ case CFG_CANCEL_AUTOFOCUS: {
+ /* TO-DO: Cancel the Auto Focus */
+ pr_debug("%s: Cancelling Auto Focus", __func__);
+ break;
+ }
+ default:
rc = -EFAULT;
break;
}
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ov12830.c b/drivers/media/platform/msm/camera_v2/sensor/ov12830.c
new file mode 100644
index 0000000..593892e
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/ov12830.c
@@ -0,0 +1,197 @@
+/* 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 "msm_sensor.h"
+#define OV12830_SENSOR_NAME "ov12830"
+DEFINE_MSM_MUTEX(ov12830_mut);
+
+static struct msm_sensor_ctrl_t ov12830_s_ctrl;
+
+static struct msm_sensor_power_setting ov12830_power_setting[] = {
+ {
+ .seq_type = SENSOR_VREG,
+ .seq_val = CAM_VIO,
+ .config_val = 0,
+ .delay = 5,
+ },
+ {
+ .seq_type = SENSOR_VREG,
+ .seq_val = CAM_VANA,
+ .config_val = 0,
+ .delay = 5,
+ },
+ {
+ .seq_type = SENSOR_GPIO,
+ .seq_val = SENSOR_GPIO_VDIG,
+ .config_val = GPIO_OUT_LOW,
+ .delay = 40,
+ },
+ {
+ .seq_type = SENSOR_GPIO,
+ .seq_val = SENSOR_GPIO_VDIG,
+ .config_val = GPIO_OUT_HIGH,
+ .delay = 40,
+ },
+ {
+ .seq_type = SENSOR_VREG,
+ .seq_val = CAM_VAF,
+ .config_val = 0,
+ .delay = 15,
+ },
+ {
+ .seq_type = SENSOR_GPIO,
+ .seq_val = SENSOR_GPIO_STANDBY,
+ .config_val = GPIO_OUT_LOW,
+ .delay = 15,
+ },
+ {
+ .seq_type = SENSOR_GPIO,
+ .seq_val = SENSOR_GPIO_RESET,
+ .config_val = GPIO_OUT_LOW,
+ .delay = 40,
+ },
+ {
+ .seq_type = SENSOR_GPIO,
+ .seq_val = SENSOR_GPIO_AF_PWDM,
+ .config_val = GPIO_OUT_LOW,
+ .delay = 40,
+ },
+ {
+ .seq_type = SENSOR_GPIO,
+ .seq_val = SENSOR_GPIO_STANDBY,
+ .config_val = GPIO_OUT_HIGH,
+ .delay = 40,
+ },
+ {
+ .seq_type = SENSOR_GPIO,
+ .seq_val = SENSOR_GPIO_RESET,
+ .config_val = GPIO_OUT_HIGH,
+ .delay = 40,
+ },
+ {
+ .seq_type = SENSOR_GPIO,
+ .seq_val = SENSOR_GPIO_AF_PWDM,
+ .config_val = GPIO_OUT_HIGH,
+ .delay = 40,
+ },
+ {
+ .seq_type = SENSOR_CLK,
+ .seq_val = SENSOR_CAM_MCLK,
+ .config_val = 24000000,
+ .delay = 5,
+ },
+ {
+ .seq_type = SENSOR_I2C_MUX,
+ .seq_val = 0,
+ .config_val = 0,
+ .delay = 0,
+ },
+};
+
+static struct v4l2_subdev_info ov12830_subdev_info[] = {
+ {
+ .code = V4L2_MBUS_FMT_SBGGR10_1X10,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .fmt = 1,
+ .order = 0,
+ },
+};
+
+static const struct i2c_device_id ov12830_i2c_id[] = {
+ {OV12830_SENSOR_NAME,
+ (kernel_ulong_t)&ov12830_s_ctrl},
+ { }
+};
+
+static int msm_ov12830_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ return msm_sensor_i2c_probe(client, id, &ov12830_s_ctrl);
+}
+
+static struct i2c_driver ov12830_i2c_driver = {
+ .id_table = ov12830_i2c_id,
+ .probe = msm_ov12830_i2c_probe,
+ .driver = {
+ .name = OV12830_SENSOR_NAME,
+ },
+};
+
+static struct msm_camera_i2c_client ov12830_sensor_i2c_client = {
+ .addr_type = MSM_CAMERA_I2C_WORD_ADDR,
+};
+
+static const struct of_device_id ov12830_dt_match[] = {
+ {.compatible = "qcom,ov12830",
+ .data = &ov12830_s_ctrl},
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, ov12830_dt_match);
+
+static struct platform_driver ov12830_platform_driver = {
+ .driver = {
+ .name = "qcom,ov12830",
+ .owner = THIS_MODULE,
+ .of_match_table = ov12830_dt_match,
+ },
+};
+
+static int32_t ov12830_platform_probe
+ (struct platform_device *pdev)
+{
+ int32_t rc = 0;
+ const struct of_device_id *match;
+ match = of_match_device(ov12830_dt_match, &pdev->dev);
+ rc = msm_sensor_platform_probe(pdev, match->data);
+ return rc;
+}
+
+static int __init ov12830_init_module(void)
+{
+ int32_t rc = 0;
+ pr_debug("%s:%d\n", __func__, __LINE__);
+ rc = platform_driver_probe(&ov12830_platform_driver,
+ ov12830_platform_probe);
+ if (!rc)
+ return rc;
+ pr_debug("%s:%d rc %d\n", __func__, __LINE__, rc);
+ return i2c_add_driver(&ov12830_i2c_driver);
+}
+
+static void __exit ov12830_exit_module(void)
+{
+ pr_info("%s:%d\n", __func__, __LINE__);
+ if (ov12830_s_ctrl.pdev) {
+ msm_sensor_free_sensor_data(&ov12830_s_ctrl);
+ platform_driver_unregister
+ (&ov12830_platform_driver);
+ } else {
+ i2c_del_driver(&ov12830_i2c_driver);
+ }
+}
+
+static struct msm_sensor_ctrl_t ov12830_s_ctrl = {
+ .sensor_i2c_client = &ov12830_sensor_i2c_client,
+ .power_setting_array.power_setting = ov12830_power_setting,
+ .power_setting_array.size =
+ ARRAY_SIZE(ov12830_power_setting),
+ .msm_sensor_mutex = &ov12830_mut,
+ .sensor_v4l2_subdev_info = ov12830_subdev_info,
+ .sensor_v4l2_subdev_info_size =
+ ARRAY_SIZE(ov12830_subdev_info),
+};
+
+module_init(ov12830_init_module);
+module_exit(ov12830_exit_module);
+MODULE_DESCRIPTION("ov12830");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ov5648.c b/drivers/media/platform/msm/camera_v2/sensor/ov5648.c
new file mode 100644
index 0000000..7877fcb
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/ov5648.c
@@ -0,0 +1,179 @@
+/* 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 "msm_sensor.h"
+
+#define OV5648_SENSOR_NAME "ov5648"
+DEFINE_MSM_MUTEX(ov5648_mut);
+
+static struct msm_sensor_ctrl_t ov5648_s_ctrl;
+
+static struct msm_sensor_power_setting ov5648_power_setting[] = {
+ {
+ .seq_type = SENSOR_VREG,
+ .seq_val = CAM_VIO,
+ .config_val = 0,
+ .delay = 5,
+ },
+ {
+ .seq_type = SENSOR_GPIO,
+ .seq_val = SENSOR_GPIO_VDIG,
+ .config_val = GPIO_OUT_LOW,
+ .delay = 10,
+ },
+ {
+ .seq_type = SENSOR_GPIO,
+ .seq_val = SENSOR_GPIO_VDIG,
+ .config_val = GPIO_OUT_HIGH,
+ .delay = 10,
+ },
+ {
+ .seq_type = SENSOR_VREG,
+ .seq_val = CAM_VANA,
+ .config_val = 0,
+ .delay = 10,
+ },
+ {
+ .seq_type = SENSOR_GPIO,
+ .seq_val = SENSOR_GPIO_STANDBY,
+ .config_val = GPIO_OUT_LOW,
+ .delay = 30,
+ },
+ {
+ .seq_type = SENSOR_GPIO,
+ .seq_val = SENSOR_GPIO_STANDBY,
+ .config_val = GPIO_OUT_HIGH,
+ .delay = 30,
+ },
+ {
+ .seq_type = SENSOR_GPIO,
+ .seq_val = SENSOR_GPIO_RESET,
+ .config_val = GPIO_OUT_LOW,
+ .delay = 5,
+ },
+ {
+ .seq_type = SENSOR_GPIO,
+ .seq_val = SENSOR_GPIO_RESET,
+ .config_val = GPIO_OUT_HIGH,
+ .delay = 30,
+ },
+ {
+ .seq_type = SENSOR_CLK,
+ .seq_val = SENSOR_CAM_MCLK,
+ .config_val = 24000000,
+ .delay = 5,
+ },
+ {
+ .seq_type = SENSOR_I2C_MUX,
+ .seq_val = 0,
+ .config_val = 0,
+ .delay = 0,
+ },
+};
+
+static struct v4l2_subdev_info ov5648_subdev_info[] = {
+ {
+ .code = V4L2_MBUS_FMT_SBGGR10_1X10,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .fmt = 1,
+ .order = 0,
+ },
+};
+
+static const struct i2c_device_id ov5648_i2c_id[] = {
+ {OV5648_SENSOR_NAME,
+ (kernel_ulong_t)&ov5648_s_ctrl},
+ { }
+};
+
+static int32_t msm_ov5648_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ return msm_sensor_i2c_probe(client, id, &ov5648_s_ctrl);
+}
+
+static struct i2c_driver ov5648_i2c_driver = {
+ .id_table = ov5648_i2c_id,
+ .probe = msm_ov5648_i2c_probe,
+ .driver = {
+ .name = OV5648_SENSOR_NAME,
+ },
+};
+
+static struct msm_camera_i2c_client ov5648_sensor_i2c_client = {
+ .addr_type = MSM_CAMERA_I2C_WORD_ADDR,
+};
+
+static struct msm_sensor_ctrl_t ov5648_s_ctrl = {
+ .sensor_i2c_client = &ov5648_sensor_i2c_client,
+ .power_setting_array.power_setting = ov5648_power_setting,
+ .power_setting_array.size =
+ ARRAY_SIZE(ov5648_power_setting),
+ .msm_sensor_mutex = &ov5648_mut,
+ .sensor_v4l2_subdev_info = ov5648_subdev_info,
+ .sensor_v4l2_subdev_info_size =
+ ARRAY_SIZE(ov5648_subdev_info),
+};
+
+static const struct of_device_id ov5648_dt_match[] = {
+ {
+ .compatible = "qcom,ov5648",
+ .data = &ov5648_s_ctrl
+ },
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, ov5648_dt_match);
+
+static struct platform_driver ov5648_platform_driver = {
+ .driver = {
+ .name = "qcom,ov5648",
+ .owner = THIS_MODULE,
+ .of_match_table = ov5648_dt_match,
+ },
+};
+
+static int32_t ov5648_platform_probe(struct platform_device *pdev)
+{
+ int32_t rc = 0;
+ const struct of_device_id *match;
+
+ match = of_match_device(ov5648_dt_match, &pdev->dev);
+ rc = msm_sensor_platform_probe(pdev, match->data);
+ return rc;
+}
+
+static int __init ov5648_init_module(void)
+{
+ int32_t rc = 0;
+
+ rc = platform_driver_probe(&ov5648_platform_driver,
+ ov5648_platform_probe);
+ if (!rc)
+ return rc;
+ return i2c_add_driver(&ov5648_i2c_driver);
+}
+
+static void __exit ov5648_exit_module(void)
+{
+ if (ov5648_s_ctrl.pdev) {
+ msm_sensor_free_sensor_data(&ov5648_s_ctrl);
+ platform_driver_unregister(&ov5648_platform_driver);
+ } else
+ i2c_del_driver(&ov5648_i2c_driver);
+ return;
+}
+
+module_init(ov5648_init_module);
+module_exit(ov5648_exit_module);
+MODULE_DESCRIPTION("ov5648");
+MODULE_LICENSE("GPL v2");
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 85fdff6..8de8997 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
@@ -99,6 +99,14 @@
static int mpq_sdmx_debug;
module_param(mpq_sdmx_debug, int, S_IRUGO | S_IWUSR);
+/*
+ * Indicates whether the demux should search for frame boundaries
+ * and notify on video packets on frame-basis or whether to provide
+ * only video PES packet payloads as-is.
+ */
+static int video_framing = 1;
+module_param(video_framing, int, S_IRUGO | S_IWUSR);
+
/* Global data-structure for managing demux devices */
static struct
{
@@ -112,13 +120,6 @@
struct mpq_streambuffer
decoder_buffers[MPQ_ADAPTER_MAX_NUM_OF_INTERFACES];
- /*
- * Indicates whether the video decoder handles framing
- * or we are required to provide framing information
- * in the meta-data passed to the decoder.
- */
- int decoder_framing;
-
/* Indicates whether secure demux TZ application is available */
int secure_demux_app_loaded;
} mpq_dmx_info;
@@ -466,6 +467,12 @@
&mpq_demux->decoder_ts_errors);
debugfs_create_u32(
+ "decoder_cc_errors",
+ S_IRUGO | S_IWUSR | S_IWGRP,
+ mpq_demux->demux.dmx.debugfs_demux_dir,
+ &mpq_demux->decoder_cc_errors);
+
+ debugfs_create_u32(
"sdmx_process_count",
S_IRUGO | S_IWUSR | S_IWGRP,
mpq_demux->demux.dmx.debugfs_demux_dir,
@@ -616,13 +623,6 @@
mpq_dmx_info.secure_demux_app_loaded = 0;
- /*
- * TODO: the following should be set based on the decoder:
- * 0 means the decoder doesn't handle framing, so framing
- * is done by demux. 1 means the decoder handles framing.
- */
- mpq_dmx_info.decoder_framing = 0;
-
/* Allocate memory for all MPQ devices */
mpq_dmx_info.devices =
vzalloc(mpq_demux_device_num*sizeof(struct mpq_demux));
@@ -692,6 +692,7 @@
memset(feed, 0, sizeof(*feed));
feed->sdmx_filter_handle = SDMX_INVALID_FILTER_HANDLE;
feed->mpq_demux = mpq_demux;
+ feed->session_id = 0;
}
/*
@@ -1338,7 +1339,7 @@
struct mpq_streambuffer *stream_buffer;
/* get and store framing information if required */
- if (!mpq_dmx_info.decoder_framing) {
+ if (video_framing) {
mpq_dmx_get_pattern_params(
mpq_feed->dvb_demux_feed->video_codec,
feed_data->patterns, &feed_data->patterns_num);
@@ -1456,6 +1457,7 @@
mpq_demux->decoder_out_interval_sum = 0;
mpq_demux->decoder_out_interval_max = 0;
mpq_demux->decoder_ts_errors = 0;
+ mpq_demux->decoder_cc_errors = 0;
return 0;
@@ -1634,7 +1636,17 @@
__func__, ret);
goto failed_unmap_metadata_buf;
}
- metadata_buff_desc->base_addr = (void *)temp;
+
+ /*
+ * NOTE: the following casting to u32 must be done
+ * as long as TZ does not support LPAE. Once TZ supports
+ * LPAE SDMX interface needs to be updated accordingly.
+ */
+ if (temp > 0xFFFFFFFF)
+ MPQ_DVB_ERR_PRINT(
+ "%s: WARNNING - physical address %pa is larger than 32bits!\n",
+ __func__, &temp);
+ metadata_buff_desc->base_addr = (void *)(u32)temp;
dvb_ringbuffer_init(&feed->metadata_buf, metadata_buff_base,
SDMX_METADATA_BUFFER_SIZE);
@@ -2272,7 +2284,16 @@
return ret;
}
- buf_desc->base_addr = (void *)phys_addr;
+ /*
+ * NOTE: the following casting to u32 must be done
+ * as long as TZ does not support LPAE. Once TZ supports
+ * LPAE SDMX interface needs to be updated accordingly.
+ */
+ if (phys_addr > 0xFFFFFFFF)
+ MPQ_DVB_ERR_PRINT(
+ "%s: WARNNING - physical address %pa is larger than 32bits!\n",
+ __func__, &phys_addr);
+ buf_desc->base_addr = (void *)(u32)phys_addr;
buf_desc->size = rbuf->size;
return 0;
@@ -2326,6 +2347,14 @@
meta_data.info.framing.pattern_type =
feed_data->last_framing_match_type;
meta_data.info.framing.stc = feed_data->last_framing_match_stc;
+ meta_data.info.framing.continuity_error_counter =
+ feed_data->continuity_errs;
+ meta_data.info.framing.transport_error_indicator_counter =
+ feed_data->tei_errs;
+ meta_data.info.framing.ts_dropped_bytes =
+ feed_data->ts_dropped_bytes;
+ meta_data.info.framing.ts_packets_num =
+ feed_data->ts_packets_num;
mpq_streambuffer_get_buffer_handle(stream_buffer,
0, /* current write buffer handle */
@@ -2395,7 +2424,6 @@
mpq_dmx_write_pts_dts(feed_data,
&(meta_data.info.pes.pts_dts_info));
- mpq_dmx_save_pts_dts(feed_data);
meta_data.packet_type = DMX_PES_PACKET;
meta_data.info.pes.stc = feed_data->prev_stc;
@@ -2624,6 +2652,7 @@
mpq_dmx_check_continuity(feed_data,
ts_header->continuity_counter,
discontinuity_indicator);
+ mpq_demux->decoder_cc_errors += feed_data->continuity_errs;
/* Need to back-up the PTS information of the very first frame */
if (feed_data->first_pts_dts_copy) {
@@ -2768,6 +2797,15 @@
feed_data->last_framing_match_type;
meta_data.info.framing.stc =
feed_data->last_framing_match_stc;
+ meta_data.info.framing.continuity_error_counter =
+ feed_data->continuity_errs;
+ meta_data.info.framing.
+ transport_error_indicator_counter =
+ feed_data->tei_errs;
+ meta_data.info.framing.ts_dropped_bytes =
+ feed_data->ts_dropped_bytes;
+ meta_data.info.framing.ts_packets_num =
+ feed_data->ts_packets_num;
mpq_streambuffer_get_buffer_handle(
stream_buffer,
@@ -2913,7 +2951,9 @@
mpq_dmx_write_pts_dts(feed_data,
&(meta_data.info.pes.pts_dts_info));
- mpq_dmx_save_pts_dts(feed_data);
+
+ /* Mark that we detected start of new PES */
+ feed_data->first_pts_dts_copy = 1;
meta_data.packet_type = DMX_PES_PACKET;
meta_data.info.pes.stc = feed_data->prev_stc;
@@ -3018,7 +3058,7 @@
/*
* Need to back-up the PTS information
- * of the very first PES
+ * of the start of new PES
*/
if (feed_data->first_pts_dts_copy) {
mpq_dmx_save_pts_dts(feed_data);
@@ -3032,6 +3072,7 @@
mpq_dmx_check_continuity(feed_data,
ts_header->continuity_counter,
discontinuity_indicator);
+ mpq_demux->decoder_cc_errors += feed_data->continuity_errs;
if (mpq_streambuffer_data_write(
stream_buffer,
@@ -3123,7 +3164,7 @@
curr_stc *= 256; /* convert from 105.47 KHZ to 27MHz */
}
- if (mpq_dmx_info.decoder_framing)
+ if (!video_framing)
return mpq_dmx_process_video_packet_no_framing(feed, buf,
curr_stc);
else
@@ -3404,8 +3445,19 @@
sg = sg_ptr->sgl;
for (i = 0; i < sg_ptr->nents; i++) {
+ /*
+ * NOTE: the following casting to u32 must be done
+ * as long as TZ does not support LPAE. Once TZ supports
+ * LPAE SDMX interface needs to be updated accordingly.
+ */
+ if (sg_dma_address(sg) > 0xFFFFFFFF)
+ MPQ_DVB_ERR_PRINT(
+ "%s: WARNNING - physical address %pa is larger than 32bits!\n",
+ __func__, &sg_dma_address(sg));
+
buff_chunks[i].base_addr =
- (void *)sg_dma_address(sg);
+ (void *)(u32)sg_dma_address(sg);
+
if (sg->length > actual_buff_size)
chunk_size = actual_buff_size;
else
@@ -3649,16 +3701,18 @@
* If pid has a key ladder id associated, we need to
* set it to SDMX.
*/
- if (dvbdmx_feed->secure_mode.is_secured) {
+ if (dvbdmx_feed->secure_mode.is_secured &&
+ dvbdmx_feed->cipher_ops.operations_count) {
MPQ_DVB_DBG_PRINT(
- "%s: set key-ladder %d to PID %d\n",
- __func__,
- dvbdmx_feed->secure_mode.key_ladder_id,
- dvbdmx_feed->secure_mode.pid);
- ret = sdmx_set_kl_ind(
- mpq_demux->sdmx_session_handle,
- dvbdmx_feed->secure_mode.pid,
- dvbdmx_feed->secure_mode.key_ladder_id);
+ "%s: set key-ladder %d to PID %d\n",
+ __func__,
+ dvbdmx_feed->cipher_ops.operations[0].key_ladder_id,
+ dvbdmx_feed->cipher_ops.pid);
+
+ ret = sdmx_set_kl_ind(mpq_demux->sdmx_session_handle,
+ dvbdmx_feed->cipher_ops.pid,
+ dvbdmx_feed->cipher_ops.operations[0].key_ladder_id);
+
if (ret) {
MPQ_DVB_ERR_PRINT(
"%s: FAILED to set key ladder, ret=%d\n",
@@ -3776,8 +3830,10 @@
}
init_mpq_feed_end:
- if (!ret)
+ if (!ret) {
mpq_demux->num_active_feeds++;
+ mpq_feed->session_id++;
+ }
mutex_unlock(&mpq_demux->mutex);
return ret;
}
@@ -3786,14 +3842,14 @@
/**
* Note: Called only when filter is in "GO" state - after feed has been started.
*/
-int mpq_dmx_set_secure_mode(struct dvb_demux_feed *feed,
- struct dmx_secure_mode *sec_mode)
+int mpq_dmx_set_cipher_ops(struct dvb_demux_feed *feed,
+ struct dmx_cipher_operations *cipher_ops)
{
struct mpq_feed *mpq_feed;
struct mpq_demux *mpq_demux;
int ret = 0;
- if (!feed || !feed->priv || !sec_mode) {
+ if (!feed || !feed->priv || !cipher_ops) {
MPQ_DVB_ERR_PRINT(
"%s: invalid parameters\n",
__func__);
@@ -3801,37 +3857,45 @@
}
MPQ_DVB_DBG_PRINT("%s(%d, %d, %d)\n",
- __func__, sec_mode->pid,
- sec_mode->is_secured,
- sec_mode->key_ladder_id);
+ __func__, cipher_ops->pid,
+ cipher_ops->operations_count,
+ cipher_ops->operations[0].key_ladder_id);
+
+ if ((cipher_ops->operations_count > 1) ||
+ (cipher_ops->operations_count &&
+ cipher_ops->operations[0].encrypt)) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: Invalid cipher operations, count=%d, encrypt=%d\n",
+ __func__, cipher_ops->operations_count,
+ cipher_ops->operations[0].encrypt);
+ return -EINVAL;
+ }
+
+ if (!feed->secure_mode.is_secured) {
+ /*
+ * Filter is not configured as secured, setting cipher
+ * operations is not allowed.
+ */
+ MPQ_DVB_ERR_PRINT(
+ "%s: Cannot set cipher operations to non-secure filter\n",
+ __func__);
+ return -EPERM;
+ }
mpq_feed = feed->priv;
mpq_demux = mpq_feed->mpq_demux;
mutex_lock(&mpq_demux->mutex);
- if (feed->secure_mode.is_secured != sec_mode->is_secured) {
- /*
- * Switching between secure & non-secure mode is not allowed
- * while filter is running
- */
- MPQ_DVB_ERR_PRINT(
- "%s: Cannot switch between secure mode while filter is running\n",
- __func__);
- mutex_unlock(&mpq_demux->mutex);
- return -EPERM;
- }
-
/*
* Feed is running in secure mode, this secure mode request is to
* update the key ladder id
*/
- if (feed->secure_mode.pid == sec_mode->pid && sec_mode->is_secured &&
- feed->secure_mode.key_ladder_id != sec_mode->key_ladder_id &&
- mpq_demux->sdmx_session_handle != SDMX_INVALID_SESSION_HANDLE) {
+ if ((mpq_demux->sdmx_session_handle != SDMX_INVALID_SESSION_HANDLE) &&
+ cipher_ops->operations_count) {
ret = sdmx_set_kl_ind(mpq_demux->sdmx_session_handle,
- sec_mode->pid,
- sec_mode->key_ladder_id);
+ cipher_ops->pid,
+ cipher_ops->operations[0].key_ladder_id);
if (ret) {
MPQ_DVB_ERR_PRINT(
"%s: FAILED to set key ladder, ret=%d\n",
@@ -3844,7 +3908,7 @@
return ret;
}
-EXPORT_SYMBOL(mpq_dmx_set_secure_mode);
+EXPORT_SYMBOL(mpq_dmx_set_cipher_ops);
static void mpq_sdmx_prepare_filter_status(struct mpq_demux *mpq_demux,
struct sdmx_filter_status *filter_sts,
@@ -4525,19 +4589,14 @@
static void mpq_sdmx_process_results(struct mpq_demux *mpq_demux)
{
int i;
- int j;
int sdmx_filters;
struct sdmx_filter_status *sts;
struct mpq_feed *mpq_feed;
+ u8 mpq_feed_idx;
sdmx_filters = mpq_demux->sdmx_filter_count;
for (i = 0; i < sdmx_filters; i++) {
- /*
- * MPQ_TODO: review lookup optimization
- * Can have the related mpq_feed index already associated with
- * the filter status.
- */
- sts = &mpq_demux->filters_status[i];
+ sts = &mpq_demux->sdmx_filters_state.status[i];
MPQ_DVB_DBG_PRINT(
"%s: Filter: handle=%d, status=0x%x, errors=0x%x\n",
__func__, sts->filter_handle, sts->status_indicators,
@@ -4548,16 +4607,13 @@
MPQ_DVB_DBG_PRINT("%s: Data fill count=%d (write=%d)\n",
__func__, sts->data_fill_count, sts->data_write_offset);
- for (j = 0; j < MPQ_MAX_DMX_FILES; j++) {
- mpq_feed = &mpq_demux->feeds[j];
- if ((mpq_feed->dvb_demux_feed->state == DMX_STATE_GO) &&
- (sts->filter_handle ==
- mpq_feed->sdmx_filter_handle) &&
- (!mpq_feed->secondary_feed))
- break;
- }
-
- if (j == MPQ_MAX_DMX_FILES)
+ mpq_feed_idx = mpq_demux->sdmx_filters_state.mpq_feed_idx[i];
+ mpq_feed = &mpq_demux->feeds[mpq_feed_idx];
+ if ((mpq_feed->dvb_demux_feed->state != DMX_STATE_GO) ||
+ (sts->filter_handle != mpq_feed->sdmx_filter_handle) ||
+ mpq_feed->secondary_feed ||
+ (mpq_demux->sdmx_filters_state.session_id[i] !=
+ mpq_feed->session_id))
continue;
if (sts->error_indicators & SDMX_FILTER_ERR_MD_BUF_FULL)
@@ -4636,9 +4692,14 @@
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->filters_status[filter_index];
+ sts = mpq_demux->sdmx_filters_state.status +
+ filter_index;
mpq_sdmx_prepare_filter_status(mpq_demux, sts,
mpq_feed);
+ mpq_demux->sdmx_filters_state.mpq_feed_idx[filter_index]
+ = i;
+ mpq_demux->sdmx_filters_state.session_id[filter_index] =
+ mpq_feed->session_id;
filter_index++;
}
}
@@ -4662,7 +4723,8 @@
prev_fill_count = fill_count;
sdmx_res = sdmx_process(mpq_demux->sdmx_session_handle, flags, input,
&fill_count, &read_offset, &errors, &status,
- mpq_demux->sdmx_filter_count, mpq_demux->filters_status);
+ mpq_demux->sdmx_filter_count,
+ mpq_demux->sdmx_filters_state.status);
process_end_time = current_kernel_time();
bytes_read = prev_fill_count - fill_count;
@@ -4844,7 +4906,7 @@
event.status = DMX_OK_EOS;
if (!feed->secure_mode.is_secured) {
if (dvb_dmx_is_video_feed(feed)) {
- if (mpq_dmx_info.decoder_framing)
+ if (!video_framing)
mpq_dmx_decoder_pes_closure(mpq_demux,
mpq_feed);
else
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 ca7c15a..adc4261 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
@@ -322,6 +322,8 @@
* other feeds
* @metadata_buf: Ring buffer object for managing the metadata buffer
* @metadata_buf_handle: Allocation handle for the metadata buffer
+ * @session_id: Counter that is incremented every time feed is initialized
+ * through mpq_dmx_init_mpq_feed
* @sdmx_buf: Ring buffer object for intermediate output data from the sdmx
* @sdmx_buf_handle: Allocation handle for the sdmx intermediate data buffer
* @video_info: Video feed specific information
@@ -338,6 +340,7 @@
struct dvb_ringbuffer metadata_buf;
struct ion_handle *metadata_buf_handle;
+ u8 session_id;
struct dvb_ringbuffer sdmx_buf;
struct ion_handle *sdmx_buf_handle;
@@ -355,23 +358,24 @@
* @ion_client: ION demux client used to allocate memory from ION.
* @mutex: Lock used to protect against private feed data
* @feeds: mpq common feed object pool
+ * @plugin_priv: Underlying plugin's own private data
* @num_active_feeds: Number of active mpq feeds
* @num_secure_feeds: Number of secure feeds (have a sdmx filter associated)
* currently allocated.
- * @filters_status: Array holding buffers status for each secure demux filter.
* Used before each call to sdmx_process() to build up to date state.
* @sdmx_session_handle: Secure demux open session handle
* @sdmx_filter_count: Number of active secure demux filters
* @sdmx_eos: End-of-stream indication flag for current sdmx session
- * @plugin_priv: Underlying plugin's own private data
+ * @sdmx_filters_state: Array holding buffers status for each secure
+ * demux filter.
* @hw_notification_interval: Notification interval in msec,
- * exposed in debugfs.
+ * exposed in debugfs.
* @hw_notification_min_interval: Minimum notification internal in msec,
* exposed in debugfs.
* @hw_notification_count: Notification count, exposed in debugfs.
* @hw_notification_size: Notification size in bytes, exposed in debugfs.
* @hw_notification_min_size: Minimum notification size in bytes,
- * exposed in debugfs.
+ * exposed in debugfs.
* @decoder_drop_count: Accumulated number of bytes dropped due to decoder
* buffer fullness, exposed in debugfs.
* @decoder_out_count: Counter incremeneted for each video frame output by
@@ -384,6 +388,8 @@
* successive video frames output, exposed in debugfs.
* @decoder_ts_errors: Counter for number of decoder packets with TEI bit
* set, exposed in debugfs.
+ * @decoder_cc_errors: Counter for number of decoder packets with continuity
+ * counter errors, exposed in debugfs.
* @sdmx_process_count: Total number of times sdmx_process is called.
* @sdmx_process_time_sum: Total time sdmx_process takes.
* @sdmx_process_time_average: Average time sdmx_process takes.
@@ -403,14 +409,31 @@
struct ion_client *ion_client;
struct mutex mutex;
struct mpq_feed feeds[MPQ_MAX_DMX_FILES];
+ void *plugin_priv;
+
u32 num_active_feeds;
u32 num_secure_feeds;
- struct sdmx_filter_status filters_status[MPQ_MAX_DMX_FILES];
int sdmx_session_handle;
int sdmx_session_ref_count;
int sdmx_filter_count;
int sdmx_eos;
- void *plugin_priv;
+ struct {
+ /* SDMX filters status */
+ struct sdmx_filter_status status[MPQ_MAX_DMX_FILES];
+
+ /* Index of the feed respective to SDMX filter */
+ u8 mpq_feed_idx[MPQ_MAX_DMX_FILES];
+
+ /*
+ * Snapshot of session_id of the feed
+ * when SDMX process was called. This is used
+ * to identify whether the feed has been
+ * restarted when processing SDMX results.
+ * May happen when demux is stalled in playback
+ * from memory with PULL mode.
+ */
+ u8 session_id[MPQ_MAX_DMX_FILES];
+ } sdmx_filters_state;
/* debug-fs */
u32 hw_notification_interval;
@@ -424,6 +447,7 @@
u32 decoder_out_interval_average;
u32 decoder_out_interval_max;
u32 decoder_ts_errors;
+ u32 decoder_cc_errors;
u32 sdmx_process_count;
u32 sdmx_process_time_sum;
u32 sdmx_process_time_average;
@@ -633,15 +657,19 @@
void mpq_dmx_update_hw_statistics(struct mpq_demux *mpq_demux);
/**
- * mpq_dmx_set_secure_mode - Handles set secure mode command from demux device
+ * mpq_dmx_set_cipher_ops - Handles setting of cipher operations
*
- * @feed: The feed to set its secure mode
- * @sec_mode: Secure mode details (key ladder info)
+ * @feed: The feed to set its cipher operations
+ * @cipher_ops: Cipher operations to be set
+ *
+ * This common function handles only the case when working with
+ * secure-demux. When working with secure demux a single decrypt cipher
+ * operation is allowed.
*
* Return error code
-*/
-int mpq_dmx_set_secure_mode(struct dvb_demux_feed *feed,
- struct dmx_secure_mode *secure_mode);
+ */
+int mpq_dmx_set_cipher_ops(struct dvb_demux_feed *feed,
+ struct dmx_cipher_operations *cipher_ops);
/**
* mpq_dmx_convert_tts - Convert timestamp attached by HW to each TS
@@ -652,7 +680,7 @@
* @timestampIn27Mhz: Timestamp result in 27MHz
*
* Return error code
-*/
+ */
void mpq_dmx_convert_tts(struct dvb_demux_feed *feed,
const u8 timestamp[TIMESTAMP_LEN],
u64 *timestampIn27Mhz);
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tsif.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tsif.c
index ef3f57f..40445b0 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tsif.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tsif.c
@@ -561,6 +561,10 @@
caps->max_bitrate = 144;
caps->demod_input_max_bitrate = 72;
caps->memory_input_max_bitrate = 72;
+ caps->num_cipher_ops = 0;
+
+ /* TSIF reports 3 bytes STC at unit of 27MHz/256 */
+ caps->max_stc = (u64)0xFFFFFF * 256;
/* Buffer requirements */
caps->section.flags =
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
index 8e628f6..8179061 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
@@ -195,7 +195,7 @@
} mpq_dmx_tspp_info;
static void *tspp_mem_allocator(int channel_id, u32 size,
- u32 *phys_base, void *user)
+ phys_addr_t *phys_base, void *user)
{
void *virt_addr = NULL;
int i = TSPP_GET_TSIF_NUM(channel_id);
@@ -218,7 +218,7 @@
}
static void tspp_mem_free(int channel_id, u32 size,
- void *virt_base, u32 phys_base, void *user)
+ void *virt_base, phys_addr_t phys_base, void *user)
{
int i = TSPP_GET_TSIF_NUM(channel_id);
@@ -372,7 +372,18 @@
buff_start_addr_phys =
mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_phys_base;
- input.base_addr = (void *)buff_start_addr_phys;
+
+ /*
+ * NOTE: the following casting to u32 must be done
+ * as long as TZ does not support LPAE. Once TZ supports
+ * LPAE SDMX interface needs to be updated accordingly.
+ */
+ if (buff_start_addr_phys > 0xFFFFFFFF)
+ MPQ_DVB_ERR_PRINT(
+ "%s: WARNNING - physical address %pa is larger than 32bits!\n",
+ __func__, &buff_start_addr_phys);
+
+ input.base_addr = (void *)(u32)buff_start_addr_phys;
input.size = mpq_dmx_tspp_info.tsif[tsif].buffer_count *
TSPP_DESCRIPTOR_SIZE;
@@ -381,7 +392,7 @@
"%s: SDMX Processing %d descriptors: %d bytes at start address 0x%x, read offset %d\n",
__func__, aggregate_count, aggregate_len,
(unsigned int)input.base_addr,
- buff_current_addr_phys - buff_start_addr_phys);
+ (int)(buff_current_addr_phys - buff_start_addr_phys));
mpq_sdmx_process(mpq_demux, &input, aggregate_len,
buff_current_addr_phys - buff_start_addr_phys,
@@ -1627,6 +1638,10 @@
caps->max_bitrate = 192;
caps->demod_input_max_bitrate = 96;
caps->memory_input_max_bitrate = 96;
+ caps->num_cipher_ops = 1;
+
+ /* TSIF reports 3 bytes STC at unit of 27MHz/256 */
+ caps->max_stc = (u64)0xFFFFFF * 256;
/* Buffer requirements */
caps->section.flags =
@@ -1744,7 +1759,7 @@
mpq_dmx_decoder_fullness_abort;
mpq_demux->demux.decoder_buffer_status = mpq_dmx_decoder_buffer_status;
mpq_demux->demux.reuse_decoder_buffer = mpq_dmx_reuse_decoder_buffer;
- mpq_demux->demux.set_secure_mode = mpq_dmx_set_secure_mode;
+ mpq_demux->demux.set_cipher_op = mpq_dmx_set_cipher_ops;
mpq_demux->demux.oob_command = mpq_dmx_oob_command;
mpq_demux->demux.convert_ts = mpq_dmx_convert_tts;
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v2.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v2.c
index 1ab9da1..c2e37a4 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v2.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v2.c
@@ -73,7 +73,8 @@
}
caps->caps = DMX_CAP_PULL_MODE | DMX_CAP_VIDEO_INDEXING |
- DMX_CAP_VIDEO_DECODER_DATA | DMX_CAP_TS_INSERTION;
+ DMX_CAP_VIDEO_DECODER_DATA | DMX_CAP_TS_INSERTION |
+ DMX_CAP_SECURED_INPUT_PLAYBACK;
caps->num_decoders = MPQ_ADAPTER_MAX_NUM_OF_INTERFACES;
caps->num_demux_devices = CONFIG_DVB_MPQ_NUM_DMX_DEVICES;
caps->num_pid_filters = TSPP_MAX_PID_FILTER_NUM;
@@ -85,6 +86,10 @@
caps->max_bitrate = 320;
caps->demod_input_max_bitrate = 96;
caps->memory_input_max_bitrate = 80;
+ caps->num_cipher_ops = DMX_MAX_CIPHER_OPERATIONS_COUNT;
+
+ /* TSIF reports 7 bytes STC at unit of 27MHz */
+ caps->max_stc = 0x00FFFFFFFFFFFFFF;
return 0;
}
diff --git a/drivers/media/platform/msm/dvb/include/mpq_adapter.h b/drivers/media/platform/msm/dvb/include/mpq_adapter.h
index a2ade18..86f36a4 100644
--- a/drivers/media/platform/msm/dvb/include/mpq_adapter.h
+++ b/drivers/media/platform/msm/dvb/include/mpq_adapter.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
@@ -67,6 +67,24 @@
/** STC value attached to first TS packet holding the pattern */
u64 stc;
+
+ /*
+ * Number of TS packets with Transport Error Indicator (TEI)
+ * found while constructing the frame.
+ */
+ __u32 transport_error_indicator_counter;
+
+ /* Number of continuity errors found while constructing the frame */
+ __u32 continuity_error_counter;
+
+ /*
+ * Number of dropped bytes due to insufficient buffer space,
+ * since last reported frame.
+ */
+ __u32 ts_dropped_bytes;
+
+ /* Total number of TS packets holding the frame */
+ __u32 ts_packets_num;
};
struct dmx_pes_packet_info {
diff --git a/drivers/media/platform/msm/vidc/Makefile b/drivers/media/platform/msm/vidc/Makefile
index 6977165..ff6274c 100644
--- a/drivers/media/platform/msm/vidc/Makefile
+++ b/drivers/media/platform/msm/vidc/Makefile
@@ -5,6 +5,7 @@
msm_venc.o \
msm_smem.o \
msm_vidc_debug.o \
+ msm_vidc_res_parse.o \
venus_hfi.o \
hfi_response_handler.o \
hfi_packetization.o \
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index 6e8c809..d92a9c1 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -360,6 +360,25 @@
return ret;
}
+static u32 get_hfi_buf_mode(enum buffer_mode_type hal_buf_mode)
+{
+ u32 buf_mode;
+ switch (hal_buf_mode) {
+ case HAL_BUFFER_MODE_STATIC:
+ buf_mode = HFI_BUFFER_MODE_STATIC;
+ break;
+ case HAL_BUFFER_MODE_RING:
+ buf_mode = HFI_BUFFER_MODE_RING;
+ break;
+ default:
+ dprintk(VIDC_ERR, "Invalid buffer mode :0x%x\n",
+ hal_buf_mode);
+ buf_mode = 0;
+ break;
+ }
+ return buf_mode;
+}
+
int create_pkt_cmd_session_set_buffers(
struct hfi_cmd_session_set_buffers_packet *pkt,
u32 session_id,
@@ -1277,6 +1296,39 @@
pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
break;
}
+ case HAL_PARAM_BUFFER_ALLOC_MODE:
+ {
+ u32 buffer_type;
+ u32 buffer_mode;
+ struct hfi_buffer_alloc_mode *hfi;
+ struct hal_buffer_alloc_mode *alloc_info = pdata;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE;
+ hfi = (struct hfi_buffer_alloc_mode *)
+ &pkt->rg_property_data[1];
+ buffer_type = get_hfi_buffer(alloc_info->buffer_type);
+ if (buffer_type)
+ hfi->buffer_type = buffer_type;
+ else
+ return -EINVAL;
+ buffer_mode = get_hfi_buf_mode(alloc_info->buffer_mode);
+ if (buffer_mode)
+ hfi->buffer_mode = buffer_mode;
+ else
+ return -EINVAL;
+ pkt->size += sizeof(u32) + sizeof(struct hfi_buffer_alloc_mode);
+ break;
+ }
+ case HAL_PARAM_VDEC_FRAME_ASSEMBLY:
+ {
+ struct hfi_enable *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VDEC_FRAME_ASSEMBLY;
+ hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
+ hfi->enable = ((struct hfi_enable *) pdata)->enable;
+ pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+ break;
+ }
/* FOLLOWING PROPERTIES ARE NOT IMPLEMENTED IN CORE YET */
case HAL_CONFIG_BUFFER_REQUIREMENTS:
case HAL_CONFIG_PRIORITY:
@@ -1343,3 +1395,17 @@
pkt->trigger_type = get_hfi_ssr_type(type);
return 0;
}
+
+int create_pkt_cmd_sys_image_version(
+ struct hfi_cmd_sys_get_property_packet *pkt)
+{
+ if (!pkt) {
+ dprintk(VIDC_ERR, "%s invalid param :%p\n", __func__, pkt);
+ return -EINVAL;
+ }
+ pkt->size = sizeof(struct hfi_cmd_sys_get_property_packet);
+ pkt->packet_type = HFI_CMD_SYS_GET_PROPERTY;
+ pkt->num_properties = 1;
+ pkt->rg_property_data[0] = HFI_PROPERTY_SYS_IMAGE_VERSION;
+ return 0;
+}
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.h b/drivers/media/platform/msm/vidc/hfi_packetization.h
index df93906..20619c0 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.h
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.h
@@ -89,4 +89,7 @@
int create_pkt_ssr_cmd(enum hal_ssr_trigger_type type,
struct hfi_cmd_sys_test_ssr_packet *pkt);
+
+int create_pkt_cmd_sys_image_version(
+ struct hfi_cmd_sys_get_property_packet *pkt);
#endif
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index 859345f..a63ee61 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -14,6 +14,7 @@
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/interrupt.h>
+#include <mach/msm_smem.h>
#include "vidc_hfi_helper.h"
#include "vidc_hfi_io.h"
#include "msm_vidc_debug.h"
@@ -1089,6 +1090,44 @@
callback(SESSION_GET_SEQ_HDR_DONE, &data_done);
}
+void hfi_process_sys_property_info(
+ struct hfi_property_sys_image_version_info_type *pkt)
+{
+ int i = 0;
+ u32 smem_block_size = 0;
+ u8 *smem_table_ptr;
+ char version[256];
+ const u32 smem_image_index_venus = 14 * 128;
+
+ if (!pkt || !pkt->string_size) {
+ 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_INFO, "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 + 128) <= smem_block_size))
+ memcpy(smem_table_ptr + smem_image_index_venus,
+ (u8 *)pkt->str_image_version, 128);
+}
+
u32 hfi_process_msg_packet(
msm_vidc_callback callback, u32 device_id,
struct vidc_hal_msg_pkt_hdr *msg_hdr)
@@ -1121,6 +1160,11 @@
(struct hfi_msg_sys_session_init_done_packet *)
msg_hdr);
break;
+ case HFI_MSG_SYS_PROPERTY_INFO:
+ hfi_process_sys_property_info(
+ (struct hfi_property_sys_image_version_info_type *)
+ msg_hdr);
+ break;
case HFI_MSG_SYS_SESSION_END_DONE:
hfi_process_session_end_done(callback, device_id,
(struct hfi_msg_sys_session_end_done_packet *)
@@ -1186,7 +1230,7 @@
hfi_msg_sys_session_abort_done_packet*) msg_hdr);
break;
default:
- dprintk(VIDC_ERR, "UNKNOWN_MSG_TYPE : %d", msg_hdr->packet);
+ dprintk(VIDC_DBG, "UNKNOWN_MSG_TYPE : %d", msg_hdr->packet);
break;
}
return rc;
diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
index 687bd71..cf96ca2 100644
--- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
@@ -20,7 +20,6 @@
#include <linux/debugfs.h>
#include <linux/version.h>
#include <linux/slab.h>
-#include <linux/of.h>
#include <mach/board.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
@@ -31,6 +30,7 @@
#include "msm_smem.h"
#include "vidc_hfi_api.h"
#include "msm_vidc_resources.h"
+#include "msm_vidc_res_parse.h"
#define BASE_DEVICE_NUMBER 32
@@ -54,50 +54,6 @@
struct list_head registered_bufs;
};
-struct master_slave {
- int masters_ocmem[2];
- int masters_ddr[2];
- int slaves_ocmem[2];
- int slaves_ddr[2];
-};
-
-struct bus_pdata_config {
- int *masters;
- int *slaves;
- char *name;
-};
-
-static struct master_slave bus_vectors_masters_slaves = {
- .masters_ocmem = {MSM_BUS_MASTER_VIDEO_P0_OCMEM,
- MSM_BUS_MASTER_VIDEO_P1_OCMEM},
- .masters_ddr = {MSM_BUS_MASTER_VIDEO_P0, MSM_BUS_MASTER_VIDEO_P1},
- .slaves_ocmem = {MSM_BUS_SLAVE_OCMEM, MSM_BUS_SLAVE_OCMEM},
- .slaves_ddr = {MSM_BUS_SLAVE_EBI_CH0, MSM_BUS_SLAVE_EBI_CH0},
-};
-
-static struct bus_pdata_config bus_pdata_config_vector[] = {
-{
- .masters = bus_vectors_masters_slaves.masters_ocmem,
- .slaves = bus_vectors_masters_slaves.slaves_ocmem,
- .name = "qcom,enc-ocmem-ab-ib",
-},
-{
- .masters = bus_vectors_masters_slaves.masters_ocmem,
- .slaves = bus_vectors_masters_slaves.slaves_ocmem,
- .name = "qcom,dec-ocmem-ab-ib",
-},
-{
- .masters = bus_vectors_masters_slaves.masters_ddr,
- .slaves = bus_vectors_masters_slaves.slaves_ddr,
- .name = "qcom,enc-ddr-ab-ib",
-},
-{
- .masters = bus_vectors_masters_slaves.masters_ddr,
- .slaves = bus_vectors_masters_slaves.slaves_ddr,
- .name = "qcom,dec-ddr-ab-ib",
-},
-};
-
static inline struct msm_vidc_inst *get_vidc_inst(struct file *filp, void *fh)
{
return container_of(filp->private_data,
@@ -431,7 +387,6 @@
goto exit;
}
for (i = 0; i < b->length; ++i) {
- buffer_type = HAL_BUFFER_OUTPUT;
if (EXTRADATA_IDX(b->length) &&
(i == EXTRADATA_IDX(b->length)) &&
!b->m.planes[i].length) {
@@ -448,8 +403,20 @@
kfree(binfo);
goto exit;
}
- if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
- buffer_type = HAL_BUFFER_INPUT;
+
+ if (vidc_inst->session_type == MSM_VIDC_DECODER) {
+ if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ buffer_type = HAL_BUFFER_INPUT;
+ else /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */
+ buffer_type = HAL_BUFFER_OUTPUT;
+ } else {
+ /* FIXME in the future. See comment in msm_comm_get_\
+ * domain_partition. Same problem here. */
+ if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ buffer_type = HAL_BUFFER_OUTPUT;
+ else /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */
+ buffer_type = HAL_BUFFER_INPUT;
+ }
temp = get_same_fd_buffer(&v4l2_inst->registered_bufs,
b->m.planes[i].reserved[0], &plane);
@@ -736,578 +703,6 @@
{
}
-static size_t get_u32_array_num_elements(struct platform_device *pdev,
- char *name)
-{
- struct device_node *np = pdev->dev.of_node;
- int len;
- size_t num_elements = 0;
- if (!of_get_property(np, name, &len)) {
- dprintk(VIDC_ERR, "Failed to read %s from device tree\n",
- name);
- goto fail_read;
- }
-
- num_elements = len / sizeof(u32);
- if (num_elements <= 0) {
- dprintk(VIDC_ERR, "%s not specified in device tree\n",
- name);
- goto fail_read;
- }
- return num_elements / 2;
-
-fail_read:
- return 0;
-}
-
-static int read_hfi_type(struct platform_device *pdev)
-{
- struct device_node *np = pdev->dev.of_node;
- int rc = 0;
- const char *hfi_name = NULL;
-
- if (np) {
- rc = of_property_read_string(np, "qcom,hfi", &hfi_name);
- if (rc) {
- dprintk(VIDC_ERR,
- "Failed to read hfi from device tree\n");
- goto err_hfi_read;
- }
- if (!strcmp(hfi_name, "venus"))
- rc = VIDC_HFI_VENUS;
- else if (!strcmp(hfi_name, "q6"))
- rc = VIDC_HFI_Q6;
- else
- rc = -EINVAL;
- } else
- rc = VIDC_HFI_Q6;
-
-err_hfi_read:
- return rc;
-}
-
-static inline void msm_vidc_free_freq_table(
- struct msm_vidc_platform_resources *res)
-{
- kfree(res->load_freq_tbl);
- res->load_freq_tbl = NULL;
-}
-
-static inline void msm_vidc_free_reg_table(
- struct msm_vidc_platform_resources *res)
-{
- kfree(res->reg_set.reg_tbl);
- res->reg_set.reg_tbl = NULL;
-}
-
-static inline void msm_vidc_free_bus_vectors(
- struct msm_vidc_platform_resources *res)
-{
- int i, j;
- if (res->bus_pdata) {
- for (i = 0; i < ARRAY_SIZE(bus_pdata_config_vector); i++) {
- for (j = 0; j < res->bus_pdata[i].num_usecases; j++) {
- kfree(res->bus_pdata[i].usecase[j].vectors);
- res->bus_pdata[i].usecase[j].vectors = NULL;
- }
- kfree(res->bus_pdata[i].usecase);
- res->bus_pdata[i].usecase = NULL;
- }
- kfree(res->bus_pdata);
- res->bus_pdata = NULL;
- }
-}
-
-static inline void msm_vidc_free_iommu_groups(
- struct msm_vidc_platform_resources *res)
-{
- kfree(res->iommu_group_set.iommu_maps);
- res->iommu_group_set.iommu_maps = NULL;
-}
-
-static inline void msm_vidc_free_buffer_usage_table(
- struct msm_vidc_platform_resources *res)
-{
- kfree(res->buffer_usage_set.buffer_usage_tbl);
- res->buffer_usage_set.buffer_usage_tbl = NULL;
-}
-
-static int msm_vidc_load_freq_table(struct msm_vidc_platform_resources *res)
-{
- int rc = 0;
- int num_elements = 0;
- struct platform_device *pdev = res->pdev;
-
- num_elements = get_u32_array_num_elements(pdev, "qcom,load-freq-tbl");
- if (num_elements == 0) {
- dprintk(VIDC_ERR, "no elements in frequency table\n");
- return rc;
- }
-
- res->load_freq_tbl = kzalloc(num_elements * sizeof(*res->load_freq_tbl),
- GFP_KERNEL);
- if (!res->load_freq_tbl) {
- dprintk(VIDC_ERR,
- "%s Failed to alloc load_freq_tbl\n",
- __func__);
- return -ENOMEM;
- }
-
- if (of_property_read_u32_array(pdev->dev.of_node,
- "qcom,load-freq-tbl", (u32 *)res->load_freq_tbl,
- num_elements * 2)) {
- dprintk(VIDC_ERR, "Failed to read frequency table\n");
- msm_vidc_free_freq_table(res);
- return -EINVAL;
- }
-
- res->load_freq_tbl_size = num_elements;
- return rc;
-}
-
-static int msm_vidc_load_reg_table(struct msm_vidc_platform_resources *res)
-{
- struct reg_set *reg_set;
- struct platform_device *pdev = res->pdev;
- int i;
- int rc = 0;
-
- reg_set = &res->reg_set;
- reg_set->count = get_u32_array_num_elements(pdev, "qcom,reg-presets");
- if (reg_set->count == 0) {
- dprintk(VIDC_DBG, "no elements in reg set\n");
- return rc;
- }
-
- reg_set->reg_tbl = kzalloc(reg_set->count *
- sizeof(*(reg_set->reg_tbl)), GFP_KERNEL);
- if (!reg_set->reg_tbl) {
- dprintk(VIDC_ERR, "%s Failed to alloc register table\n",
- __func__);
- return -ENOMEM;
- }
-
- if (of_property_read_u32_array(pdev->dev.of_node, "qcom,reg-presets",
- (u32 *)reg_set->reg_tbl, reg_set->count * 2)) {
- dprintk(VIDC_ERR, "Failed to read register table\n");
- msm_vidc_free_reg_table(res);
- return -EINVAL;
- }
- for (i = 0; i < reg_set->count; i++) {
- dprintk(VIDC_DBG,
- "reg = %x, value = %x\n",
- reg_set->reg_tbl[i].reg,
- reg_set->reg_tbl[i].value
- );
- }
- return rc;
-}
-
-static void msm_vidc_free_bus_vector(struct msm_bus_scale_pdata *bus_pdata)
-{
- int i;
- for (i = 0; i < bus_pdata->num_usecases; i++) {
- kfree(bus_pdata->usecase[i].vectors);
- bus_pdata->usecase[i].vectors = NULL;
- }
-
- kfree(bus_pdata->usecase);
- bus_pdata->usecase = NULL;
-}
-
-static int msm_vidc_load_bus_vector(struct platform_device *pdev,
- struct msm_bus_scale_pdata *bus_pdata, u32 num_ports,
- struct bus_pdata_config *bus_pdata_config)
-{
- struct bus_values {
- u32 ab;
- u32 ib;
- };
- struct bus_values *values;
- int i, j;
- int rc = 0;
-
- values = kzalloc(sizeof(*values) * bus_pdata->num_usecases, GFP_KERNEL);
- if (!values) {
- dprintk(VIDC_ERR, "%s Failed to alloc bus_values\n", __func__);
- rc = -ENOMEM;
- goto err_mem_alloc;
- }
-
- if (of_property_read_u32_array(pdev->dev.of_node,
- bus_pdata_config->name, (u32 *)values,
- bus_pdata->num_usecases * (sizeof(*values)/sizeof(u32)))) {
- dprintk(VIDC_ERR, "%s Failed to read bus values\n", __func__);
- rc = -EINVAL;
- goto err_parse_dt;
- }
-
- bus_pdata->usecase = kzalloc(sizeof(*bus_pdata->usecase) *
- bus_pdata->num_usecases, GFP_KERNEL);
- if (!bus_pdata->usecase) {
- dprintk(VIDC_ERR,
- "%s Failed to alloc bus_pdata usecase\n", __func__);
- rc = -ENOMEM;
- goto err_parse_dt;
- }
- bus_pdata->name = bus_pdata_config->name;
- for (i = 0; i < bus_pdata->num_usecases; i++) {
- bus_pdata->usecase[i].vectors = kzalloc(
- sizeof(*bus_pdata->usecase[i].vectors) * num_ports,
- GFP_KERNEL);
- if (!bus_pdata->usecase) {
- dprintk(VIDC_ERR,
- "%s Failed to alloc bus_pdata usecase\n",
- __func__);
- break;
- }
- for (j = 0; j < num_ports; j++) {
- bus_pdata->usecase[i].vectors[j].ab = (u64)values[i].ab
- * 1000;
- bus_pdata->usecase[i].vectors[j].ib = (u64)values[i].ib
- * 1000;
- bus_pdata->usecase[i].vectors[j].src =
- bus_pdata_config->masters[j];
- bus_pdata->usecase[i].vectors[j].dst =
- bus_pdata_config->slaves[j];
- dprintk(VIDC_DBG,
- "ab = %llu, ib = %llu, src = %d, dst = %d\n",
- bus_pdata->usecase[i].vectors[j].ab,
- bus_pdata->usecase[i].vectors[j].ib,
- bus_pdata->usecase[i].vectors[j].src,
- bus_pdata->usecase[i].vectors[j].dst);
- }
- bus_pdata->usecase[i].num_paths = num_ports;
- }
- if (i < bus_pdata->num_usecases) {
- for (--i; i >= 0; i--) {
- kfree(bus_pdata->usecase[i].vectors);
- bus_pdata->usecase[i].vectors = NULL;
- }
- kfree(bus_pdata->usecase);
- bus_pdata->usecase = NULL;
- rc = -EINVAL;
- }
-err_parse_dt:
- kfree(values);
-err_mem_alloc:
- return rc;
-}
-
-static int msm_vidc_load_bus_vectors(struct msm_vidc_platform_resources *res)
-{
- u32 num_ports = 0;
- int rc = 0;
- int i;
- struct platform_device *pdev = res->pdev;
- u32 num_bus_pdata = ARRAY_SIZE(bus_pdata_config_vector);
-
- if (of_property_read_u32_array(pdev->dev.of_node, "qcom,bus-ports",
- (u32 *)&num_ports, 1) || (num_ports == 0))
- goto err_mem_alloc;
-
- res->bus_pdata = kzalloc(sizeof(*res->bus_pdata) * num_bus_pdata,
- GFP_KERNEL);
- if (!res->bus_pdata) {
- dprintk(VIDC_ERR, "Failed to alloc memory\n");
- rc = -ENOMEM;
- goto err_mem_alloc;
- }
- for (i = 0; i < num_bus_pdata; i++) {
- if (!res->has_ocmem &&
- (!strcmp(bus_pdata_config_vector[i].name,
- "qcom,enc-ocmem-ab-ib")
- || !strcmp(bus_pdata_config_vector[i].name,
- "qcom,dec-ocmem-ab-ib"))) {
- continue;
- }
- res->bus_pdata[i].num_usecases = get_u32_array_num_elements(
- pdev, bus_pdata_config_vector[i].name);
- if (res->bus_pdata[i].num_usecases == 0) {
- dprintk(VIDC_ERR, "no elements in %s\n",
- bus_pdata_config_vector[i].name);
- rc = -EINVAL;
- break;
- }
-
- rc = msm_vidc_load_bus_vector(pdev, &res->bus_pdata[i],
- num_ports, &bus_pdata_config_vector[i]);
- if (rc) {
- dprintk(VIDC_ERR,
- "Failed to load bus vector: %d\n", i);
- break;
- }
- }
- if (i < num_bus_pdata) {
- for (--i; i >= 0; i--)
- msm_vidc_free_bus_vector(&res->bus_pdata[i]);
- kfree(res->bus_pdata);
- res->bus_pdata = NULL;
- }
-err_mem_alloc:
- return rc;
-}
-
-static int msm_vidc_load_iommu_groups(struct msm_vidc_platform_resources *res)
-{
- int rc = 0;
- struct platform_device *pdev = res->pdev;
- struct device_node *ctx_node;
- struct iommu_set *iommu_group_set = &res->iommu_group_set;
- int array_size;
- int i;
- struct iommu_info *iommu_map;
- u32 *buffer_types = NULL;
-
- if (!of_get_property(pdev->dev.of_node, "qcom,iommu-groups",
- &array_size)) {
- dprintk(VIDC_DBG, "iommu_groups property not present\n");
- iommu_group_set->count = 0;
- return 0;
- }
-
- iommu_group_set->count = array_size / sizeof(u32);
- if (iommu_group_set->count == 0) {
- dprintk(VIDC_ERR, "No group present in iommu_groups\n");
- rc = -ENOENT;
- goto err_no_of_node;
- }
-
- iommu_group_set->iommu_maps = kzalloc(iommu_group_set->count *
- sizeof(*(iommu_group_set->iommu_maps)), GFP_KERNEL);
- if (!iommu_group_set->iommu_maps) {
- dprintk(VIDC_ERR, "%s Failed to alloc iommu_maps\n",
- __func__);
- rc = -ENOMEM;
- goto err_no_of_node;
- }
-
- buffer_types = kzalloc(iommu_group_set->count * sizeof(*buffer_types),
- GFP_KERNEL);
- if (!buffer_types) {
- dprintk(VIDC_ERR,
- "%s Failed to alloc iommu group buffer types\n",
- __func__);
- rc = -ENOMEM;
- goto err_load_groups;
- }
-
- rc = of_property_read_u32_array(pdev->dev.of_node,
- "qcom,iommu-group-buffer-types", buffer_types,
- iommu_group_set->count);
- if (rc) {
- dprintk(VIDC_ERR,
- "%s Failed to read iommu group buffer types\n", __func__);
- goto err_load_groups;
- }
-
- for (i = 0; i < iommu_group_set->count; i++) {
- iommu_map = &iommu_group_set->iommu_maps[i];
- ctx_node = of_parse_phandle(pdev->dev.of_node,
- "qcom,iommu-groups", i);
- if (!ctx_node) {
- dprintk(VIDC_ERR, "Unable to parse phandle : %u\n", i);
- rc = -EBADHANDLE;
- goto err_load_groups;
- }
-
- rc = of_property_read_string(ctx_node, "label",
- &(iommu_map->name));
- if (rc) {
- dprintk(VIDC_ERR, "Could not find label property\n");
- goto err_load_groups;
- }
-
- if (!of_get_property(ctx_node, "qcom,virtual-addr-pool",
- &array_size)) {
- dprintk(VIDC_ERR,
- "Could not find any addr pool for group : %s\n",
- iommu_map->name);
- rc = -EBADHANDLE;
- goto err_load_groups;
- }
-
- iommu_map->npartitions = array_size / sizeof(u32) / 2;
-
- rc = of_property_read_u32_array(ctx_node,
- "qcom,virtual-addr-pool",
- (u32 *)iommu_map->addr_range,
- iommu_map->npartitions * 2);
- if (rc) {
- dprintk(VIDC_ERR,
- "Could not read addr pool for group : %s\n",
- iommu_map->name);
- goto err_load_groups;
- }
-
- iommu_map->buffer_type = buffer_types[i];
- iommu_map->is_secure =
- of_property_read_bool(ctx_node, "qcom,secure-domain");
- }
- kfree(buffer_types);
- return 0;
-err_load_groups:
- kfree(buffer_types);
- msm_vidc_free_iommu_groups(res);
-err_no_of_node:
- return rc;
-}
-
-static int msm_vidc_load_buffer_usage_table(
- struct msm_vidc_platform_resources *res)
-{
- int rc = 0;
- struct platform_device *pdev = res->pdev;
- struct buffer_usage_set *buffer_usage_set = &res->buffer_usage_set;
-
- buffer_usage_set->count = get_u32_array_num_elements(
- pdev, "qcom,buffer-type-tz-usage-table");
- if (buffer_usage_set->count == 0) {
- dprintk(VIDC_DBG, "no elements in buffer usage set\n");
- return 0;
- }
-
- buffer_usage_set->buffer_usage_tbl = kzalloc(buffer_usage_set->count *
- sizeof(*(buffer_usage_set->buffer_usage_tbl)),
- GFP_KERNEL);
- if (!buffer_usage_set->buffer_usage_tbl) {
- dprintk(VIDC_ERR, "%s Failed to alloc buffer usage table\n",
- __func__);
- rc = -ENOMEM;
- goto err_load_buf_usage;
- }
-
- rc = of_property_read_u32_array(pdev->dev.of_node,
- "qcom,buffer-type-tz-usage-table",
- (u32 *)buffer_usage_set->buffer_usage_tbl,
- buffer_usage_set->count *
- (sizeof(*buffer_usage_set->buffer_usage_tbl)/sizeof(u32)));
- if (rc) {
- dprintk(VIDC_ERR, "Failed to read buffer usage table\n");
- goto err_load_buf_usage;
- }
-
- return 0;
-err_load_buf_usage:
- msm_vidc_free_buffer_usage_table(res);
- return rc;
-}
-
-
-static int read_platform_resources_from_dt(
- struct msm_vidc_platform_resources *res)
-{
- struct platform_device *pdev = res->pdev;
- struct resource *kres = NULL;
- int rc = 0;
-
- if (!pdev->dev.of_node) {
- dprintk(VIDC_ERR, "DT node not found\n");
- return -ENOENT;
- }
-
- res->fw_base_addr = 0x0;
-
- kres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- res->register_base = kres ? kres->start : -1;
- res->register_size = kres ? (kres->end + 1 - kres->start) : -1;
-
- kres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- res->irq = kres ? kres->start : -1;
-
- res->has_ocmem = of_property_read_bool(pdev->dev.of_node,
- "qcom,has-ocmem");
-
- rc = msm_vidc_load_freq_table(res);
- if (rc) {
- dprintk(VIDC_ERR, "Failed to load freq table: %d\n", rc);
- goto err_load_freq_table;
- }
- rc = msm_vidc_load_reg_table(res);
- if (rc) {
- dprintk(VIDC_ERR, "Failed to load reg table: %d\n", rc);
- goto err_load_reg_table;
- }
- rc = msm_vidc_load_bus_vectors(res);
- if (rc) {
- dprintk(VIDC_ERR, "Failed to load bus vectors: %d\n", rc);
- goto err_load_bus_vectors;
- }
- rc = msm_vidc_load_iommu_groups(res);
- if (rc) {
- dprintk(VIDC_ERR, "Failed to load iommu groups: %d\n", rc);
- goto err_load_iommu_groups;
- }
- rc = msm_vidc_load_buffer_usage_table(res);
- if (rc) {
- dprintk(VIDC_ERR,
- "Failed to load buffer usage table: %d\n", rc);
- goto err_load_buffer_usage_table;
- }
-
- rc = of_property_read_u32(pdev->dev.of_node, "qcom,max-hw-load",
- &res->max_load);
- if (rc) {
- dprintk(VIDC_ERR,
- "Failed to determine max load supported: %d\n", rc);
- goto err_load_buffer_usage_table;
- }
-
- return rc;
-
-err_load_buffer_usage_table:
- msm_vidc_free_iommu_groups(res);
-err_load_iommu_groups:
- msm_vidc_free_bus_vectors(res);
-err_load_bus_vectors:
- msm_vidc_free_reg_table(res);
-err_load_reg_table:
- msm_vidc_free_freq_table(res);
-err_load_freq_table:
- return rc;
-}
-
-static int read_platform_resources_from_board(
- struct msm_vidc_platform_resources *res)
-{
- struct resource *kres = NULL;
- struct platform_device *pdev = res->pdev;
- struct msm_vidc_v4l2_platform_data *pdata = pdev->dev.platform_data;
- int c = 0, rc = 0;
-
- if (!pdata) {
- dprintk(VIDC_ERR, "Platform data not found\n");
- return -ENOENT;
- }
-
- res->fw_base_addr = 0x0;
-
- kres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- res->register_base = kres ? kres->start : -1;
- res->register_size = kres ? (kres->end + 1 - kres->start) : -1;
-
- kres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- res->irq = kres ? kres->start : -1;
-
- res->load_freq_tbl = kzalloc(pdata->num_load_table *
- sizeof(*res->load_freq_tbl), GFP_KERNEL);
-
- if (!res->load_freq_tbl) {
- dprintk(VIDC_ERR, "%s Failed to alloc load_freq_tbl\n",
- __func__);
- return -ENOMEM;
- }
-
- res->load_freq_tbl_size = pdata->num_load_table;
- for (c = 0; c > pdata->num_load_table; ++c) {
- res->load_freq_tbl[c].load = pdata->load_table[c][0];
- res->load_freq_tbl[c].freq = pdata->load_table[c][1];
- }
-
- res->max_load = pdata->max_load;
- return rc;
-}
-
static int read_platform_resources(struct msm_vidc_core *core,
struct platform_device *pdev)
{
@@ -1521,11 +916,7 @@
video_unregister_device(&core->vdev[MSM_VIDC_DECODER].vdev);
v4l2_device_unregister(&core->v4l2_dev);
- msm_vidc_free_freq_table(&core->resources);
- msm_vidc_free_reg_table(&core->resources);
- msm_vidc_free_bus_vectors(&core->resources);
- msm_vidc_free_iommu_groups(&core->resources);
- msm_vidc_free_buffer_usage_table(&core->resources);
+ msm_vidc_free_platform_resources(&core->resources);
kfree(core);
return rc;
}
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 7547464..86928f2 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -68,6 +68,10 @@
"Extradata aspect ratio",
"Extradata mpeg2 seqdisp",
};
+static const char *const mpeg_vidc_video_alloc_mode_type[] = {
+ "Buffer Allocation Static",
+ "Buffer Allocation Ring Buffer",
+};
static const char *const perf_level[] = {
"Nominal",
@@ -249,6 +253,33 @@
.qmenu = perf_level,
.step = 0,
},
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE,
+ .name = "Buffer allocation mode",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_STATIC,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_RING,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_STATIC,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_VIDEO_STATIC) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_RING)
+ ),
+ .qmenu = mpeg_vidc_video_alloc_mode_type,
+ .step = 0,
+ .cluster = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_FRAME_ASSEMBLY,
+ .name = "Video frame assembly",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = V4L2_MPEG_VIDC_FRAME_ASSEMBLY_DISABLE,
+ .maximum = V4L2_MPEG_VIDC_FRAME_ASSEMBLY_ENABLE,
+ .default_value = V4L2_MPEG_VIDC_FRAME_ASSEMBLY_DISABLE,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ .cluster = 0,
+ },
};
#define NUM_CTRLS ARRAY_SIZE(msm_vdec_ctrls)
@@ -934,6 +965,8 @@
struct hal_buffer_requirements *bufreq;
int extra_idx = 0;
struct hfi_device *hdev;
+ struct hal_buffer_count_actual new_buf_count;
+ enum hal_property property_id;
if (!q || !num_buffers || !num_planes
|| !sizes || !q->drv_priv) {
dprintk(VIDC_ERR, "Invalid input, q = %p, %p, %p\n",
@@ -960,6 +993,16 @@
i, inst->capability.height.max,
inst->capability.width.max);
}
+ property_id = HAL_PARAM_BUFFER_COUNT_ACTUAL;
+ new_buf_count.buffer_type = HAL_BUFFER_INPUT;
+ new_buf_count.buffer_count_actual = *num_buffers;
+ rc = call_hfi_op(hdev, session_set_property,
+ inst->session, property_id, &new_buf_count);
+ if (rc) {
+ dprintk(VIDC_WARN,
+ "Failed to set new buffer count(%d) on FW, err: %d\n",
+ new_buf_count.buffer_count_actual, rc);
+ }
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
dprintk(VIDC_DBG, "Getting bufreqs on capture plane\n");
@@ -987,15 +1030,11 @@
}
if (*num_buffers && *num_buffers >
bufreq->buffer_count_actual) {
- struct hal_buffer_count_actual new_buf_count;
- enum hal_property property_id =
- HAL_PARAM_BUFFER_COUNT_ACTUAL;
-
+ property_id = HAL_PARAM_BUFFER_COUNT_ACTUAL;
new_buf_count.buffer_type = HAL_BUFFER_OUTPUT;
new_buf_count.buffer_count_actual = *num_buffers;
rc = call_hfi_op(hdev, session_set_property,
inst->session, property_id, &new_buf_count);
-
}
if (bufreq->buffer_count_actual > *num_buffers)
*num_buffers = bufreq->buffer_count_actual;
@@ -1258,6 +1297,7 @@
u32 property_val = 0;
void *pdata = NULL;
struct hfi_device *hdev;
+ struct hal_extradata_enable extra;
if (!inst || !inst->core || !inst->core->device) {
dprintk(VIDC_ERR, "%s invalid parameters", __func__);
@@ -1325,14 +1365,11 @@
!!(inst->flags & VIDC_SECURE));
break;
case V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA:
- {
- struct hal_extradata_enable extra;
property_id = HAL_PARAM_INDEX_EXTRADATA;
extra.index = msm_comm_get_hal_extradata_index(ctrl->val);
extra.enable = 1;
pdata = &extra;
break;
- }
case V4L2_CID_MPEG_VIDC_SET_PERF_LEVEL:
switch (ctrl->val) {
case V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL:
@@ -1349,13 +1386,29 @@
}
break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE:
+ {
+ struct hal_buffer_alloc_mode mode;
+ property_id = HAL_PARAM_BUFFER_ALLOC_MODE;
+ mode.buffer_mode = ctrl->val;
+ mode.buffer_type = HAL_BUFFER_INPUT;
+ pdata = &mode;
+ break;
+ }
+ case V4L2_CID_MPEG_VIDC_VIDEO_FRAME_ASSEMBLY:
+ {
+ property_id = HAL_PARAM_VDEC_FRAME_ASSEMBLY;
+ hal_property.enable = ctrl->val;
+ pdata = &hal_property;
+ break;
+ }
default:
break;
}
if (!rc && property_id) {
dprintk(VIDC_DBG,
- "Control: HAL property = %d, ctrl_id = 0x%x, ctrl_value = %d\n",
+ "Control: HAL property=0x%x,ctrl: id=0x%x,value=0x%x\n",
property_id, ctrl->id, ctrl->val);
rc = call_hfi_op(hdev, session_set_property, (void *)
inst->session, property_id, pdata);
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 46da496..7897068 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -1187,6 +1187,7 @@
void *pdata = NULL;
struct v4l2_ctrl *temp_ctrl = NULL;
struct hfi_device *hdev;
+ struct hal_extradata_enable extra;
if (!inst || !inst->core || !inst->core->device) {
dprintk(VIDC_ERR, "%s invalid parameters", __func__);
@@ -1728,14 +1729,11 @@
!!(inst->flags & VIDC_SECURE));
break;
case V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA:
- {
- struct hal_extradata_enable extra;
property_id = HAL_PARAM_INDEX_EXTRADATA;
extra.index = msm_comm_get_hal_extradata_index(ctrl->val);
extra.enable = 1;
pdata = &extra;
break;
- }
case V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO:
{
struct v4l2_ctrl *rc_mode;
@@ -1761,7 +1759,7 @@
case V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_ENABLED:
vui_timing_info.enable = 1;
vui_timing_info.fixed_frame_rate = cfr;
- vui_timing_info.time_scale = inst->prop.fps;
+ vui_timing_info.time_scale = NSEC_PER_SEC;
}
pdata = &vui_timing_info;
@@ -1877,7 +1875,7 @@
inst->fmts[OUTPUT_PORT] = &venc_formats[0];
inst->prop.height = DEFAULT_HEIGHT;
inst->prop.width = DEFAULT_WIDTH;
- inst->prop.fps = 30;
+ inst->prop.fps = 15;
return rc;
}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 1c43f1e..b6d031a 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -477,14 +477,14 @@
if (rc) {
dprintk(VIDC_ERR,
"Failed to initialize vb2 queue on capture port\n");
- goto fail_init;
+ goto fail_bufq_capture;
}
rc = vb2_bufq_init(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
session_type);
if (rc) {
dprintk(VIDC_ERR,
"Failed to initialize vb2 queue on capture port\n");
- goto fail_init;
+ goto fail_bufq_output;
}
rc = msm_comm_try_state(inst, MSM_VIDC_CORE_INIT);
if (rc) {
@@ -502,6 +502,14 @@
mutex_unlock(&core->lock);
return inst;
fail_init:
+ vb2_queue_release(&inst->bufq[OUTPUT_PORT].vb2_bufq);
+fail_bufq_output:
+ vb2_queue_release(&inst->bufq[CAPTURE_PORT].vb2_bufq);
+fail_bufq_capture:
+ if (session_type == MSM_VIDC_DECODER)
+ msm_vdec_ctrl_deinit(inst);
+ else if (session_type == MSM_VIDC_ENCODER)
+ msm_venc_ctrl_deinit(inst);
msm_smem_delete_client(inst->mem_client);
fail_mem_client:
kfree(inst);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 77f838c..57b98dc 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -69,6 +69,20 @@
return false;
}
+static bool is_thumbnail_session(struct msm_vidc_inst *inst)
+{
+ if (inst->session_type == MSM_VIDC_DECODER) {
+ int rc = 0;
+ struct v4l2_control ctrl = {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE
+ };
+ rc = v4l2_g_ctrl(&inst->ctrl_handler, &ctrl);
+ if (!rc && ctrl.value)
+ return true;
+ }
+ return false;
+}
+
static int msm_comm_get_load(struct msm_vidc_core *core,
enum session_type type)
{
@@ -83,7 +97,9 @@
if (inst->session_type == type &&
inst->state >= MSM_VIDC_OPEN_DONE &&
inst->state < MSM_VIDC_STOP_DONE) {
- num_mbs_per_sec += NUM_MBS_PER_SEC(inst->prop.height,
+ if (!is_thumbnail_session(inst))
+ num_mbs_per_sec += NUM_MBS_PER_SEC(
+ inst->prop.height,
inst->prop.width, inst->prop.fps);
}
mutex_unlock(&inst->lock);
@@ -728,6 +744,15 @@
vb = response->clnt_data;
inst = (struct msm_vidc_inst *)response->session_id;
if (vb) {
+ vb->v4l2_planes[0].bytesused = response->input_done.filled_len;
+ vb->v4l2_planes[0].data_offset = response->input_done.offset;
+ if (vb->v4l2_planes[0].data_offset > vb->v4l2_planes[0].length)
+ dprintk(VIDC_ERR, "Error: data_offset overflow\n");
+ if (vb->v4l2_planes[0].bytesused > vb->v4l2_planes[0].length)
+ dprintk(VIDC_ERR, "Error: buffer overflow\n");
+ if ((u8 *)vb->v4l2_planes[0].m.userptr !=
+ response->input_done.packet_buffer)
+ dprintk(VIDC_ERR, "Error: unexpected buffer address\n");
mutex_lock(&inst->bufq[OUTPUT_PORT].lock);
vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
mutex_unlock(&inst->bufq[OUTPUT_PORT].lock);
@@ -780,6 +805,8 @@
vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_DECODEONLY;
if (fill_buf_done->flags1 & HAL_BUFFERFLAG_DATACORRUPT)
vb->v4l2_buf.flags |= V4L2_QCOM_BUF_DATA_CORRUPT;
+ if (fill_buf_done->flags1 & HAL_BUFFERFLAG_DROP_FRAME)
+ vb->v4l2_buf.flags |= V4L2_QCOM_BUF_DROP_FRAME;
switch (fill_buf_done->picture_type) {
case HAL_PICTURE_IDR:
vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_IDRFRAME;
@@ -1889,10 +1916,19 @@
memset(&frame_data, 0 , sizeof(struct vidc_frame_data));
frame_data.alloc_len = vb->v4l2_planes[0].length;
frame_data.filled_len = vb->v4l2_planes[0].bytesused;
+ frame_data.offset = vb->v4l2_planes[0].data_offset;
frame_data.device_addr = vb->v4l2_planes[0].m.userptr;
frame_data.timestamp = time_usec;
frame_data.flags = 0;
frame_data.clnt_data = (u32)vb;
+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
+ (frame_data.filled_len > frame_data.alloc_len ||
+ frame_data.offset > frame_data.alloc_len)) {
+ dprintk(VIDC_ERR,
+ "Buffer will overflow, not queueing it\n");
+ rc = -EINVAL;
+ goto err_bad_input;
+ }
if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
frame_data.buffer_type = HAL_BUFFER_INPUT;
if (vb->v4l2_buf.flags & V4L2_BUF_FLAG_EOS) {
@@ -1908,11 +1944,20 @@
"Received CODECCONFIG on output cap\n");
}
if (vb->v4l2_buf.flags &
+ V4L2_QCOM_BUF_FLAG_DECODEONLY) {
+ frame_data.flags |= HAL_BUFFERFLAG_DECODEONLY;
+ dprintk(VIDC_DBG,
+ "Received DECODEONLY on output cap\n");
+ }
+ if (vb->v4l2_buf.flags &
V4L2_QCOM_BUF_TIMESTAMP_INVALID)
frame_data.timestamp = LLONG_MAX;
dprintk(VIDC_DBG,
- "Sending etb to hal: Alloc: %d :filled: %d\n",
- frame_data.alloc_len, frame_data.filled_len);
+ "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);
rc = call_hfi_op(hdev, session_etb, (void *)
inst->session, &frame_data);
if (!rc)
@@ -1965,6 +2010,7 @@
rc = -EINVAL;
}
}
+err_bad_input:
if (rc)
dprintk(VIDC_ERR, "Failed to queue buffer\n");
err_no_mem:
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
new file mode 100644
index 0000000..cb08da7
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
@@ -0,0 +1,642 @@
+/* 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/of.h>
+#include <mach/board.h>
+#include "msm_vidc_resources.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_res_parse.h"
+
+struct master_slave {
+ int masters_ocmem[2];
+ int masters_ddr[2];
+ int slaves_ocmem[2];
+ int slaves_ddr[2];
+};
+
+static struct master_slave bus_vectors_masters_slaves = {
+ .masters_ocmem = {MSM_BUS_MASTER_VIDEO_P0_OCMEM,
+ MSM_BUS_MASTER_VIDEO_P1_OCMEM},
+ .masters_ddr = {MSM_BUS_MASTER_VIDEO_P0, MSM_BUS_MASTER_VIDEO_P1},
+ .slaves_ocmem = {MSM_BUS_SLAVE_OCMEM, MSM_BUS_SLAVE_OCMEM},
+ .slaves_ddr = {MSM_BUS_SLAVE_EBI_CH0, MSM_BUS_SLAVE_EBI_CH0},
+};
+
+struct bus_pdata_config {
+ int *masters;
+ int *slaves;
+ char *name;
+};
+
+static struct bus_pdata_config bus_pdata_config_vector[] = {
+ {
+ .masters = bus_vectors_masters_slaves.masters_ocmem,
+ .slaves = bus_vectors_masters_slaves.slaves_ocmem,
+ .name = "qcom,enc-ocmem-ab-ib",
+ },
+ {
+ .masters = bus_vectors_masters_slaves.masters_ocmem,
+ .slaves = bus_vectors_masters_slaves.slaves_ocmem,
+ .name = "qcom,dec-ocmem-ab-ib",
+ },
+ {
+ .masters = bus_vectors_masters_slaves.masters_ddr,
+ .slaves = bus_vectors_masters_slaves.slaves_ddr,
+ .name = "qcom,enc-ddr-ab-ib",
+ },
+ {
+ .masters = bus_vectors_masters_slaves.masters_ddr,
+ .slaves = bus_vectors_masters_slaves.slaves_ddr,
+ .name = "qcom,dec-ddr-ab-ib",
+ },
+};
+
+static size_t get_u32_array_num_elements(struct platform_device *pdev,
+ char *name)
+{
+ struct device_node *np = pdev->dev.of_node;
+ int len;
+ size_t num_elements = 0;
+ if (!of_get_property(np, name, &len)) {
+ dprintk(VIDC_ERR, "Failed to read %s from device tree\n",
+ name);
+ goto fail_read;
+ }
+
+ num_elements = len / sizeof(u32);
+ if (num_elements <= 0) {
+ dprintk(VIDC_ERR, "%s not specified in device tree\n",
+ name);
+ goto fail_read;
+ }
+ return num_elements / 2;
+
+fail_read:
+ return 0;
+}
+
+int read_hfi_type(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ int rc = 0;
+ const char *hfi_name = NULL;
+
+ if (np) {
+ rc = of_property_read_string(np, "qcom,hfi", &hfi_name);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to read hfi from device tree\n");
+ goto err_hfi_read;
+ }
+ if (!strcmp(hfi_name, "venus"))
+ rc = VIDC_HFI_VENUS;
+ else if (!strcmp(hfi_name, "q6"))
+ rc = VIDC_HFI_Q6;
+ else
+ rc = -EINVAL;
+ } else
+ rc = VIDC_HFI_Q6;
+
+err_hfi_read:
+ return rc;
+}
+
+static inline void msm_vidc_free_freq_table(
+ struct msm_vidc_platform_resources *res)
+{
+ kfree(res->load_freq_tbl);
+ res->load_freq_tbl = NULL;
+}
+
+static inline void msm_vidc_free_reg_table(
+ struct msm_vidc_platform_resources *res)
+{
+ kfree(res->reg_set.reg_tbl);
+ res->reg_set.reg_tbl = NULL;
+}
+
+static inline void msm_vidc_free_bus_vectors(
+ struct msm_vidc_platform_resources *res)
+{
+ int i, j;
+ if (res->bus_pdata) {
+ for (i = 0; i < ARRAY_SIZE(bus_pdata_config_vector); i++) {
+ for (j = 0; j < res->bus_pdata[i].num_usecases; j++) {
+ kfree(res->bus_pdata[i].usecase[j].vectors);
+ res->bus_pdata[i].usecase[j].vectors = NULL;
+ }
+ kfree(res->bus_pdata[i].usecase);
+ res->bus_pdata[i].usecase = NULL;
+ }
+ kfree(res->bus_pdata);
+ res->bus_pdata = NULL;
+ }
+}
+
+static inline void msm_vidc_free_iommu_groups(
+ struct msm_vidc_platform_resources *res)
+{
+ kfree(res->iommu_group_set.iommu_maps);
+ res->iommu_group_set.iommu_maps = NULL;
+}
+
+static inline void msm_vidc_free_buffer_usage_table(
+ struct msm_vidc_platform_resources *res)
+{
+ kfree(res->buffer_usage_set.buffer_usage_tbl);
+ res->buffer_usage_set.buffer_usage_tbl = NULL;
+}
+
+void msm_vidc_free_platform_resources(
+ struct msm_vidc_platform_resources *res)
+{
+ msm_vidc_free_freq_table(res);
+ msm_vidc_free_reg_table(res);
+ msm_vidc_free_bus_vectors(res);
+ msm_vidc_free_iommu_groups(res);
+ msm_vidc_free_buffer_usage_table(res);
+}
+
+static void msm_vidc_free_bus_vector(struct msm_bus_scale_pdata *bus_pdata)
+{
+ int i;
+ for (i = 0; i < bus_pdata->num_usecases; i++) {
+ kfree(bus_pdata->usecase[i].vectors);
+ bus_pdata->usecase[i].vectors = NULL;
+ }
+
+ kfree(bus_pdata->usecase);
+ bus_pdata->usecase = NULL;
+}
+
+static int msm_vidc_load_reg_table(struct msm_vidc_platform_resources *res)
+{
+ struct reg_set *reg_set;
+ struct platform_device *pdev = res->pdev;
+ int i;
+ int rc = 0;
+
+ reg_set = &res->reg_set;
+ reg_set->count = get_u32_array_num_elements(pdev, "qcom,reg-presets");
+ if (reg_set->count == 0) {
+ dprintk(VIDC_DBG, "no elements in reg set\n");
+ return rc;
+ }
+
+ reg_set->reg_tbl = kzalloc(reg_set->count *
+ sizeof(*(reg_set->reg_tbl)), GFP_KERNEL);
+ if (!reg_set->reg_tbl) {
+ dprintk(VIDC_ERR, "%s Failed to alloc register table\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ if (of_property_read_u32_array(pdev->dev.of_node, "qcom,reg-presets",
+ (u32 *)reg_set->reg_tbl, reg_set->count * 2)) {
+ dprintk(VIDC_ERR, "Failed to read register table\n");
+ msm_vidc_free_reg_table(res);
+ return -EINVAL;
+ }
+ for (i = 0; i < reg_set->count; i++) {
+ dprintk(VIDC_DBG,
+ "reg = %x, value = %x\n",
+ reg_set->reg_tbl[i].reg,
+ reg_set->reg_tbl[i].value
+ );
+ }
+ return rc;
+}
+static int msm_vidc_load_freq_table(struct msm_vidc_platform_resources *res)
+{
+ int rc = 0;
+ int num_elements = 0;
+ struct platform_device *pdev = res->pdev;
+
+ num_elements = get_u32_array_num_elements(pdev, "qcom,load-freq-tbl");
+ if (num_elements == 0) {
+ dprintk(VIDC_ERR, "no elements in frequency table\n");
+ return rc;
+ }
+
+ res->load_freq_tbl = kzalloc(num_elements * sizeof(*res->load_freq_tbl),
+ GFP_KERNEL);
+ if (!res->load_freq_tbl) {
+ dprintk(VIDC_ERR,
+ "%s Failed to alloc load_freq_tbl\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ if (of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,load-freq-tbl", (u32 *)res->load_freq_tbl,
+ num_elements * 2)) {
+ dprintk(VIDC_ERR, "Failed to read frequency table\n");
+ msm_vidc_free_freq_table(res);
+ return -EINVAL;
+ }
+
+ res->load_freq_tbl_size = num_elements;
+ return rc;
+}
+
+static int msm_vidc_load_bus_vector(struct platform_device *pdev,
+ struct msm_bus_scale_pdata *bus_pdata, u32 num_ports,
+ struct bus_pdata_config *bus_pdata_config)
+{
+ struct bus_values {
+ u32 ab;
+ u32 ib;
+ };
+ struct bus_values *values;
+ int i, j;
+ int rc = 0;
+
+ values = kzalloc(sizeof(*values) * bus_pdata->num_usecases, GFP_KERNEL);
+ if (!values) {
+ dprintk(VIDC_ERR, "%s Failed to alloc bus_values\n", __func__);
+ rc = -ENOMEM;
+ goto err_mem_alloc;
+ }
+
+ if (of_property_read_u32_array(pdev->dev.of_node,
+ bus_pdata_config->name, (u32 *)values,
+ bus_pdata->num_usecases * (sizeof(*values)/sizeof(u32)))) {
+ dprintk(VIDC_ERR, "%s Failed to read bus values\n", __func__);
+ rc = -EINVAL;
+ goto err_parse_dt;
+ }
+
+ bus_pdata->usecase = kzalloc(sizeof(*bus_pdata->usecase) *
+ bus_pdata->num_usecases, GFP_KERNEL);
+ if (!bus_pdata->usecase) {
+ dprintk(VIDC_ERR,
+ "%s Failed to alloc bus_pdata usecase\n", __func__);
+ rc = -ENOMEM;
+ goto err_parse_dt;
+ }
+ bus_pdata->name = bus_pdata_config->name;
+ for (i = 0; i < bus_pdata->num_usecases; i++) {
+ bus_pdata->usecase[i].vectors = kzalloc(
+ sizeof(*bus_pdata->usecase[i].vectors) * num_ports,
+ GFP_KERNEL);
+ if (!bus_pdata->usecase) {
+ dprintk(VIDC_ERR,
+ "%s Failed to alloc bus_pdata usecase\n",
+ __func__);
+ break;
+ }
+ for (j = 0; j < num_ports; j++) {
+ bus_pdata->usecase[i].vectors[j].ab = (u64)values[i].ab
+ * 1000;
+ bus_pdata->usecase[i].vectors[j].ib = (u64)values[i].ib
+ * 1000;
+ bus_pdata->usecase[i].vectors[j].src =
+ bus_pdata_config->masters[j];
+ bus_pdata->usecase[i].vectors[j].dst =
+ bus_pdata_config->slaves[j];
+ dprintk(VIDC_DBG,
+ "ab = %llu, ib = %llu, src = %d, dst = %d\n",
+ bus_pdata->usecase[i].vectors[j].ab,
+ bus_pdata->usecase[i].vectors[j].ib,
+ bus_pdata->usecase[i].vectors[j].src,
+ bus_pdata->usecase[i].vectors[j].dst);
+ }
+ bus_pdata->usecase[i].num_paths = num_ports;
+ }
+ if (i < bus_pdata->num_usecases) {
+ for (--i; i >= 0; i--) {
+ kfree(bus_pdata->usecase[i].vectors);
+ bus_pdata->usecase[i].vectors = NULL;
+ }
+ kfree(bus_pdata->usecase);
+ bus_pdata->usecase = NULL;
+ rc = -EINVAL;
+ }
+err_parse_dt:
+ kfree(values);
+err_mem_alloc:
+ return rc;
+}
+
+static int msm_vidc_load_bus_vectors(struct msm_vidc_platform_resources *res)
+{
+ u32 num_ports = 0;
+ int rc = 0;
+ int i;
+ struct platform_device *pdev = res->pdev;
+ u32 num_bus_pdata = ARRAY_SIZE(bus_pdata_config_vector);
+
+ if (of_property_read_u32_array(pdev->dev.of_node, "qcom,bus-ports",
+ (u32 *)&num_ports, 1) || (num_ports == 0))
+ goto err_mem_alloc;
+
+ res->bus_pdata = kzalloc(sizeof(*res->bus_pdata) * num_bus_pdata,
+ GFP_KERNEL);
+ if (!res->bus_pdata) {
+ dprintk(VIDC_ERR, "Failed to alloc memory\n");
+ rc = -ENOMEM;
+ goto err_mem_alloc;
+ }
+ for (i = 0; i < num_bus_pdata; i++) {
+ if (!res->has_ocmem &&
+ (!strcmp(bus_pdata_config_vector[i].name,
+ "qcom,enc-ocmem-ab-ib")
+ || !strcmp(bus_pdata_config_vector[i].name,
+ "qcom,dec-ocmem-ab-ib"))) {
+ continue;
+ }
+ res->bus_pdata[i].num_usecases = get_u32_array_num_elements(
+ pdev, bus_pdata_config_vector[i].name);
+ if (res->bus_pdata[i].num_usecases == 0) {
+ dprintk(VIDC_ERR, "no elements in %s\n",
+ bus_pdata_config_vector[i].name);
+ rc = -EINVAL;
+ break;
+ }
+
+ rc = msm_vidc_load_bus_vector(pdev, &res->bus_pdata[i],
+ num_ports, &bus_pdata_config_vector[i]);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to load bus vector: %d\n", i);
+ break;
+ }
+ }
+ if (i < num_bus_pdata) {
+ for (--i; i >= 0; i--)
+ msm_vidc_free_bus_vector(&res->bus_pdata[i]);
+ kfree(res->bus_pdata);
+ res->bus_pdata = NULL;
+ }
+err_mem_alloc:
+ return rc;
+}
+
+static int msm_vidc_load_iommu_groups(struct msm_vidc_platform_resources *res)
+{
+ int rc = 0;
+ struct platform_device *pdev = res->pdev;
+ struct device_node *ctx_node;
+ struct iommu_set *iommu_group_set = &res->iommu_group_set;
+ int array_size;
+ int i;
+ struct iommu_info *iommu_map;
+ u32 *buffer_types = NULL;
+
+ if (!of_get_property(pdev->dev.of_node, "qcom,iommu-groups",
+ &array_size)) {
+ dprintk(VIDC_DBG, "iommu_groups property not present\n");
+ iommu_group_set->count = 0;
+ return 0;
+ }
+
+ iommu_group_set->count = array_size / sizeof(u32);
+ if (iommu_group_set->count == 0) {
+ dprintk(VIDC_ERR, "No group present in iommu_groups\n");
+ rc = -ENOENT;
+ goto err_no_of_node;
+ }
+
+ iommu_group_set->iommu_maps = kzalloc(iommu_group_set->count *
+ sizeof(*(iommu_group_set->iommu_maps)), GFP_KERNEL);
+ if (!iommu_group_set->iommu_maps) {
+ dprintk(VIDC_ERR, "%s Failed to alloc iommu_maps\n",
+ __func__);
+ rc = -ENOMEM;
+ goto err_no_of_node;
+ }
+
+ buffer_types = kzalloc(iommu_group_set->count * sizeof(*buffer_types),
+ GFP_KERNEL);
+ if (!buffer_types) {
+ dprintk(VIDC_ERR,
+ "%s Failed to alloc iommu group buffer types\n",
+ __func__);
+ rc = -ENOMEM;
+ goto err_load_groups;
+ }
+
+ rc = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,iommu-group-buffer-types", buffer_types,
+ iommu_group_set->count);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s Failed to read iommu group buffer types\n", __func__);
+ goto err_load_groups;
+ }
+
+ for (i = 0; i < iommu_group_set->count; i++) {
+ iommu_map = &iommu_group_set->iommu_maps[i];
+ ctx_node = of_parse_phandle(pdev->dev.of_node,
+ "qcom,iommu-groups", i);
+ if (!ctx_node) {
+ dprintk(VIDC_ERR, "Unable to parse phandle : %u\n", i);
+ rc = -EBADHANDLE;
+ goto err_load_groups;
+ }
+
+ rc = of_property_read_string(ctx_node, "label",
+ &(iommu_map->name));
+ if (rc) {
+ dprintk(VIDC_ERR, "Could not find label property\n");
+ goto err_load_groups;
+ }
+
+ if (!of_get_property(ctx_node, "qcom,virtual-addr-pool",
+ &array_size)) {
+ dprintk(VIDC_ERR,
+ "Could not find any addr pool for group : %s\n",
+ iommu_map->name);
+ rc = -EBADHANDLE;
+ goto err_load_groups;
+ }
+
+ iommu_map->npartitions = array_size / sizeof(u32) / 2;
+
+ rc = of_property_read_u32_array(ctx_node,
+ "qcom,virtual-addr-pool",
+ (u32 *)iommu_map->addr_range,
+ iommu_map->npartitions * 2);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Could not read addr pool for group : %s\n",
+ iommu_map->name);
+ goto err_load_groups;
+ }
+
+ iommu_map->buffer_type = buffer_types[i];
+ iommu_map->is_secure =
+ of_property_read_bool(ctx_node, "qcom,secure-domain");
+ }
+ kfree(buffer_types);
+ return 0;
+err_load_groups:
+ kfree(buffer_types);
+ msm_vidc_free_iommu_groups(res);
+err_no_of_node:
+ return rc;
+}
+
+static int msm_vidc_load_buffer_usage_table(
+ struct msm_vidc_platform_resources *res)
+{
+ int rc = 0;
+ struct platform_device *pdev = res->pdev;
+ struct buffer_usage_set *buffer_usage_set = &res->buffer_usage_set;
+
+ buffer_usage_set->count = get_u32_array_num_elements(
+ pdev, "qcom,buffer-type-tz-usage-table");
+ if (buffer_usage_set->count == 0) {
+ dprintk(VIDC_DBG, "no elements in buffer usage set\n");
+ return 0;
+ }
+
+ buffer_usage_set->buffer_usage_tbl = kzalloc(buffer_usage_set->count *
+ sizeof(*(buffer_usage_set->buffer_usage_tbl)),
+ GFP_KERNEL);
+ if (!buffer_usage_set->buffer_usage_tbl) {
+ dprintk(VIDC_ERR, "%s Failed to alloc buffer usage table\n",
+ __func__);
+ rc = -ENOMEM;
+ goto err_load_buf_usage;
+ }
+
+ rc = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,buffer-type-tz-usage-table",
+ (u32 *)buffer_usage_set->buffer_usage_tbl,
+ buffer_usage_set->count *
+ (sizeof(*buffer_usage_set->buffer_usage_tbl)/sizeof(u32)));
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to read buffer usage table\n");
+ goto err_load_buf_usage;
+ }
+
+ return 0;
+err_load_buf_usage:
+ msm_vidc_free_buffer_usage_table(res);
+ return rc;
+}
+
+int read_platform_resources_from_dt(
+ struct msm_vidc_platform_resources *res)
+{
+ struct platform_device *pdev = res->pdev;
+ struct resource *kres = NULL;
+ int rc = 0;
+
+ if (!pdev->dev.of_node) {
+ dprintk(VIDC_ERR, "DT node not found\n");
+ return -ENOENT;
+ }
+
+ res->fw_base_addr = 0x0;
+
+ kres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res->register_base = kres ? kres->start : -1;
+ res->register_size = kres ? (kres->end + 1 - kres->start) : -1;
+
+ kres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ res->irq = kres ? kres->start : -1;
+
+ res->has_ocmem = of_property_read_bool(pdev->dev.of_node,
+ "qcom,has-ocmem");
+
+ rc = msm_vidc_load_freq_table(res);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to load freq table: %d\n", rc);
+ goto err_load_freq_table;
+ }
+ rc = msm_vidc_load_reg_table(res);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to load reg table: %d\n", rc);
+ goto err_load_reg_table;
+ }
+ rc = msm_vidc_load_bus_vectors(res);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to load bus vectors: %d\n", rc);
+ goto err_load_bus_vectors;
+ }
+ rc = msm_vidc_load_iommu_groups(res);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to load iommu groups: %d\n", rc);
+ goto err_load_iommu_groups;
+ }
+ rc = msm_vidc_load_buffer_usage_table(res);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to load buffer usage table: %d\n", rc);
+ goto err_load_buffer_usage_table;
+ }
+
+ rc = of_property_read_u32(pdev->dev.of_node, "qcom,max-hw-load",
+ &res->max_load);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to determine max load supported: %d\n", rc);
+ goto err_load_buffer_usage_table;
+ }
+
+ return rc;
+
+err_load_buffer_usage_table:
+ msm_vidc_free_iommu_groups(res);
+err_load_iommu_groups:
+ msm_vidc_free_bus_vectors(res);
+err_load_bus_vectors:
+ msm_vidc_free_reg_table(res);
+err_load_reg_table:
+ msm_vidc_free_freq_table(res);
+err_load_freq_table:
+ return rc;
+}
+
+int read_platform_resources_from_board(
+ struct msm_vidc_platform_resources *res)
+{
+ struct resource *kres = NULL;
+ struct platform_device *pdev = res->pdev;
+ struct msm_vidc_v4l2_platform_data *pdata = pdev->dev.platform_data;
+ int c = 0, rc = 0;
+
+ if (!pdata) {
+ dprintk(VIDC_ERR, "Platform data not found\n");
+ return -ENOENT;
+ }
+
+ res->fw_base_addr = 0x0;
+
+ kres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res->register_base = kres ? kres->start : -1;
+ res->register_size = kres ? (kres->end + 1 - kres->start) : -1;
+
+ kres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ res->irq = kres ? kres->start : -1;
+
+ res->load_freq_tbl = kzalloc(pdata->num_load_table *
+ sizeof(*res->load_freq_tbl), GFP_KERNEL);
+
+ if (!res->load_freq_tbl) {
+ dprintk(VIDC_ERR, "%s Failed to alloc load_freq_tbl\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ res->load_freq_tbl_size = pdata->num_load_table;
+ for (c = 0; c > pdata->num_load_table; ++c) {
+ res->load_freq_tbl[c].load = pdata->load_table[c][0];
+ res->load_freq_tbl[c].freq = pdata->load_table[c][1];
+ }
+
+ res->max_load = pdata->max_load;
+ return rc;
+}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.h b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.h
new file mode 100644
index 0000000..9fe6b58
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.h
@@ -0,0 +1,30 @@
+
+/* 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 DT_PARSE
+#define DT_PARSE
+#include <linux/of.h>
+#include <mach/board.h>
+#include "msm_vidc_resources.h"
+void msm_vidc_free_platform_resources(
+ struct msm_vidc_platform_resources *res);
+
+int read_hfi_type(struct platform_device *pdev);
+
+int read_platform_resources_from_dt(
+ struct msm_vidc_platform_resources *res);
+
+int read_platform_resources_from_board(
+ struct msm_vidc_platform_resources *res);
+#endif
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 15ac493..47b88db 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -1030,6 +1030,7 @@
static int venus_hfi_core_init(void *device)
{
struct hfi_cmd_sys_init_packet pkt;
+ struct hfi_cmd_sys_get_property_packet version_pkt;
int rc = 0;
struct venus_hfi_device *dev;
@@ -1088,6 +1089,10 @@
rc = -ENOTEMPTY;
goto err_core_init;
}
+ rc = create_pkt_cmd_sys_image_version(&version_pkt);
+ if (rc || venus_hfi_iface_cmdq_write(dev, &version_pkt))
+ dprintk(VIDC_WARN, "Failed to send image version pkt to f/w");
+
return rc;
err_core_init:
disable_irq_nosync(dev->hal_data->irq);
@@ -1418,6 +1423,10 @@
break;
case HAL_SYS_DEBUG_CONFIG:
break;
+ case HAL_PARAM_BUFFER_ALLOC_MODE:
+ break;
+ case HAL_PARAM_VDEC_FRAME_ASSEMBLY:
+ break;
/*FOLLOWING PROPERTIES ARE NOT IMPLEMENTED IN CORE YET*/
case HAL_CONFIG_BUFFER_REQUIREMENTS:
case HAL_CONFIG_PRIORITY:
@@ -2852,8 +2861,8 @@
venus_hfi_disable_clks(device);
fail_enable_clks:
subsystem_put(device->resources.fw.cookie);
- device->resources.fw.cookie = NULL;
fail_load_fw:
+ device->resources.fw.cookie = NULL;
venus_hfi_iommu_detach(device);
fail_iommu_attach:
return rc;
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.h b/drivers/media/platform/msm/vidc/vidc_hfi.h
index bb72da7..874738b 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi.h
@@ -39,6 +39,8 @@
#define HFI_BUFFERFLAG_EOSEQ 0x00200000
#define HFI_BUFFERFLAG_DISCONTINUITY 0x80000000
#define HFI_BUFFERFLAG_TEI 0x40000000
+#define HFI_BUFFERFLAG_DROP_FRAME 0x20000000
+
#define HFI_ERR_SESSION_EMPTY_BUFFER_DONE_OUTPUT_PENDING \
(HFI_OX_BASE + 0x1001)
@@ -335,7 +337,6 @@
#define HFI_MSG_SYS_OX_START \
(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + HFI_MSG_START_OFFSET + 0x0000)
#define HFI_MSG_SYS_PING_ACK (HFI_MSG_SYS_OX_START + 0x2)
-#define HFI_MSG_SYS_PROPERTY_INFO (HFI_MSG_SYS_OX_START + 0x3)
#define HFI_MSG_SYS_SESSION_ABORT_DONE (HFI_MSG_SYS_OX_START + 0x4)
#define HFI_MSG_SESSION_OX_START \
@@ -408,7 +409,7 @@
u32 input_tag;
u8 *packet_buffer;
u8 *extra_data_buffer;
- u32 rgData[0];
+ u32 rgData[1];
};
struct hfi_cmd_session_empty_buffer_uncompressed_plane0_packet {
@@ -427,7 +428,7 @@
u32 input_tag;
u8 *packet_buffer;
u8 *extra_data_buffer;
- u32 rgData[0];
+ u32 rgData[1];
};
struct hfi_cmd_session_empty_buffer_uncompressed_plane1_packet {
@@ -436,7 +437,7 @@
u32 filled_len;
u32 offset;
u8 *packet_buffer2;
- u32 rgData[0];
+ u32 rgData[1];
};
struct hfi_cmd_session_empty_buffer_uncompressed_plane2_packet {
@@ -445,7 +446,7 @@
u32 filled_len;
u32 offset;
u8 *packet_buffer3;
- u32 rgData[0];
+ u32 rgData[1];
};
struct hfi_cmd_session_fill_buffer_packet {
@@ -459,7 +460,7 @@
u32 output_tag;
u8 *packet_buffer;
u8 *extra_data_buffer;
- u32 rgData[0];
+ u32 rgData[1];
};
struct hfi_cmd_session_flush_packet {
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index 389c13f..5c22552 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -44,6 +44,8 @@
#define HAL_BUFFERFLAG_READONLY 0x00000200
#define HAL_BUFFERFLAG_ENDOFSUBFRAME 0x00000400
#define HAL_BUFFERFLAG_EOSEQ 0x00200000
+#define HAL_BUFFERFLAG_DROP_FRAME 0x20000000
+
#define HAL_DEBUG_MSG_LOW 0x00000001
#define HAL_DEBUG_MSG_MEDIUM 0x00000002
@@ -172,6 +174,8 @@
HAL_PARAM_VENC_H264_VUI_TIMING_INFO,
HAL_PARAM_VENC_H264_GENERATE_AUDNAL,
HAL_PARAM_VENC_MAX_NUM_B_FRAMES,
+ HAL_PARAM_BUFFER_ALLOC_MODE,
+ HAL_PARAM_VDEC_FRAME_ASSEMBLY,
};
enum hal_domain {
@@ -860,6 +864,16 @@
HAL_UNUSED_SEQCHG = 0x10000000,
};
+enum buffer_mode_type {
+ HAL_BUFFER_MODE_STATIC = 0x00000000,
+ HAL_BUFFER_MODE_RING,
+};
+
+struct hal_buffer_alloc_mode {
+ enum hal_buffer buffer_type;
+ enum buffer_mode_type buffer_mode;
+};
+
/* HAL Response */
enum command_response {
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index 2b6d6bb..0f1e896 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -197,6 +197,10 @@
(HFI_PROPERTY_SYS_COMMON_START + 0x003)
#define HFI_PROPERTY_SYS_IDLE_INDICATOR \
(HFI_PROPERTY_SYS_COMMON_START + 0x004)
+#define HFI_PROPERTY_SYS_CODEC_POWER_PLANE_CTRL \
+ (HFI_PROPERTY_SYS_COMMON_START + 0x005)
+#define HFI_PROPERTY_SYS_IMAGE_VERSION \
+ (HFI_PROPERTY_SYS_COMMON_START + 0x006)
#define HFI_PROPERTY_PARAM_COMMON_START \
(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + 0x1000)
@@ -615,6 +619,11 @@
struct hfi_resource_ocmem_requirement rg_requirements[1];
};
+struct hfi_property_sys_image_version_info_type {
+ u32 string_size;
+ u8 str_image_version[1];
+};
+
struct hfi_venc_config_advanced {
u8 pipe2d;
u8 hw_mode;
@@ -703,6 +712,7 @@
#define HFI_MSG_SYS_SESSION_INIT_DONE (HFI_MSG_SYS_COMMON_START + 0x6)
#define HFI_MSG_SYS_SESSION_END_DONE (HFI_MSG_SYS_COMMON_START + 0x7)
#define HFI_MSG_SYS_IDLE (HFI_MSG_SYS_COMMON_START + 0x8)
+#define HFI_MSG_SYS_PROPERTY_INFO (HFI_MSG_SYS_COMMON_START + 0xA)
#define HFI_MSG_SESSION_COMMON_START \
(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + \
diff --git a/drivers/media/platform/msm/wfd/enc-venus-subdev.c b/drivers/media/platform/msm/wfd/enc-venus-subdev.c
index 8121471..9cd199b 100644
--- a/drivers/media/platform/msm/wfd/enc-venus-subdev.c
+++ b/drivers/media/platform/msm/wfd/enc-venus-subdev.c
@@ -296,24 +296,13 @@
static long set_default_properties(struct venc_inst *inst)
{
struct v4l2_control ctrl = {0};
- int rc;
/* Set the IDR period as 1. The venus core doesn't give
* the sps/pps for I-frames, only IDR. */
ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_IDR_PERIOD;
ctrl.value = 1;
- rc = msm_vidc_s_ctrl(inst->vidc_context, &ctrl);
- if (rc)
- WFD_MSG_WARN("Failed to set IDR period\n");
- /* Set the default rc mode to VBR/VFR, client can change later */
- ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL;
- ctrl.value = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_VFR;
- rc = msm_vidc_s_ctrl(inst->vidc_context, &ctrl);
- if (rc)
- WFD_MSG_WARN("Failed to set rc mode\n");
-
- return 0;
+ return msm_vidc_s_ctrl(inst->vidc_context, &ctrl);
}
static int subscribe_events(struct venc_inst *inst)
diff --git a/drivers/media/platform/msm/wfd/vsg-subdev.c b/drivers/media/platform/msm/wfd/vsg-subdev.c
index e0a46cc..0f2fbbb 100644
--- a/drivers/media/platform/msm/wfd/vsg-subdev.c
+++ b/drivers/media/platform/msm/wfd/vsg-subdev.c
@@ -424,7 +424,8 @@
struct timespec diff = timespec_sub(buf_info->time,
context->last_buffer->time);
struct timespec temp = ns_to_timespec(
- context->frame_interval);
+ context->frame_interval -
+ context->frame_interval_variance);
if (timespec_compare(&diff, &temp) >= 0)
push = true;
@@ -462,8 +463,16 @@
static long vsg_return_ip_buffer(struct v4l2_subdev *sd, void *arg)
{
struct vsg_context *context = NULL;
- struct vsg_buf_info *buf_info = NULL, *last_buffer = NULL,
- *expected_buffer = NULL;
+ struct vsg_buf_info *buf_info = NULL, *temp = NULL,
+ /* last buffer sent for encoding */
+ *last_buffer = NULL,
+ /* buffer we expected to get back, ideally ==
+ * last_buffer, but might not be if sequence is
+ * encode, encode, return */
+ *expected_buffer = NULL,
+ /* buffer that we've sent for encoding at some point */
+ *known_buffer = NULL;
+ bool is_last_buffer = false;
int rc = 0;
if (!arg || !sd) {
@@ -477,41 +486,47 @@
buf_info = (struct vsg_buf_info *)arg;
last_buffer = context->last_buffer;
+ WFD_MSG_DBG("Return frame with paddr %p\n",
+ (void *)buf_info->mdp_buf_info.paddr);
+
if (!list_empty(&context->busy_queue.node)) {
expected_buffer = list_first_entry(&context->busy_queue.node,
struct vsg_buf_info, node);
}
- WFD_MSG_DBG("Return frame with paddr %p\n",
- (void *)buf_info->mdp_buf_info.paddr);
-
- if (!expected_buffer) {
- WFD_MSG_ERR("Unexpectedly received buffer from enc with "
- "paddr %p\n", (void *)buf_info->mdp_buf_info.paddr);
- goto return_ip_buf_bad_buf;
+ list_for_each_entry(temp, &context->busy_queue.node, node) {
+ if (mdp_buf_info_equals(&temp->mdp_buf_info,
+ &buf_info->mdp_buf_info)) {
+ known_buffer = temp;
+ break;
+ }
}
- expected_buffer->flags &= ~VSG_BUF_BEING_ENCODED;
- if (mdp_buf_info_equals(&expected_buffer->mdp_buf_info,
- &buf_info->mdp_buf_info)) {
- bool is_same_buffer = context->last_buffer &&
- mdp_buf_info_equals(
- &context->last_buffer->mdp_buf_info,
- &expected_buffer->mdp_buf_info);
-
- list_del(&expected_buffer->node);
- if (!is_same_buffer &&
- !(expected_buffer->flags & VSG_NEVER_RELEASE)) {
- vsg_release_input_buffer(context, expected_buffer);
- kfree(expected_buffer);
- }
- } else {
- WFD_MSG_ERR("Returned buffer %p is not latest buffer, "
- "expected %p\n",
- (void *)buf_info->mdp_buf_info.paddr,
- (void *)expected_buffer->mdp_buf_info.paddr);
- rc = -EINVAL;
+ if (!expected_buffer || !known_buffer) {
+ WFD_MSG_ERR("Unexpectedly received buffer from enc with "
+ "paddr %p\n", (void *)buf_info->mdp_buf_info.paddr);
+ rc = -EBADHANDLE;
goto return_ip_buf_bad_buf;
+ } else if (known_buffer != expected_buffer) {
+ /* Buffers can come back out of order if encoder decides to drop
+ * a frame */
+ WFD_MSG_DBG(
+ "Got a buffer (%p) out of order. Preferred to get %p\n",
+ (void *)known_buffer->mdp_buf_info.paddr,
+ (void *)expected_buffer->mdp_buf_info.paddr);
+ }
+
+ known_buffer->flags &= ~VSG_BUF_BEING_ENCODED;
+ is_last_buffer = context->last_buffer &&
+ mdp_buf_info_equals(
+ &context->last_buffer->mdp_buf_info,
+ &known_buffer->mdp_buf_info);
+
+ list_del(&known_buffer->node);
+ if (!is_last_buffer &&
+ !(known_buffer->flags & VSG_NEVER_RELEASE)) {
+ vsg_release_input_buffer(context, known_buffer);
+ kfree(known_buffer);
}
return_ip_buf_bad_buf:
@@ -619,6 +634,61 @@
return 0;
}
+static long vsg_set_frame_interval_variance(struct v4l2_subdev *sd, void *arg)
+{
+ struct vsg_context *context = NULL;
+ int64_t variance;
+
+ if (!arg || !sd) {
+ WFD_MSG_ERR("ERROR, invalid arguments into %s\n", __func__);
+ return -EINVAL;
+ }
+
+ context = (struct vsg_context *)sd->dev_priv;
+ variance = *(int64_t *)arg;
+
+ if (variance < 0 || variance > 100) {
+ WFD_MSG_ERR("ERROR, invalid variance %lld%% into %s\n",
+ variance, __func__);
+ return -EINVAL;
+ } else if (context->mode == VSG_MODE_CFR) {
+ WFD_MSG_ERR("Setting FPS variance not supported in CFR mode\n");
+ return -ENOTSUPP;
+ }
+
+ mutex_lock(&context->mutex);
+
+ /* Convert from percentage to a value in nano seconds */
+ variance *= context->frame_interval;
+ do_div(variance, 100);
+
+ context->frame_interval_variance = variance;
+ mutex_unlock(&context->mutex);
+
+ return 0;
+}
+
+static long vsg_get_frame_interval_variance(struct v4l2_subdev *sd, void *arg)
+{
+ struct vsg_context *context = NULL;
+ int64_t variance;
+
+ if (!arg || !sd) {
+ WFD_MSG_ERR("ERROR, invalid arguments into %s\n", __func__);
+ return -EINVAL;
+ }
+
+ context = (struct vsg_context *)sd->dev_priv;
+
+ mutex_lock(&context->mutex);
+ variance = context->frame_interval_variance * 100;
+ do_div(variance, context->frame_interval);
+ *(int64_t *)arg = variance;
+ mutex_unlock(&context->mutex);
+
+ return 0;
+}
+
static long vsg_set_mode(struct v4l2_subdev *sd, void *arg)
{
struct vsg_context *context = NULL;
@@ -688,6 +758,12 @@
case VSG_SET_FRAME_INTERVAL:
rc = vsg_set_frame_interval(sd, arg);
break;
+ case VSG_SET_FRAME_INTERVAL_VARIANCE:
+ rc = vsg_set_frame_interval_variance(sd, arg);
+ break;
+ case VSG_GET_FRAME_INTERVAL_VARIANCE:
+ rc = vsg_get_frame_interval_variance(sd, arg);
+ break;
case VSG_GET_MAX_FRAME_INTERVAL:
rc = vsg_get_max_frame_interval(sd, arg);
break;
diff --git a/drivers/media/platform/msm/wfd/vsg-subdev.h b/drivers/media/platform/msm/wfd/vsg-subdev.h
index f5e4f5d..3347e5b 100644
--- a/drivers/media/platform/msm/wfd/vsg-subdev.h
+++ b/drivers/media/platform/msm/wfd/vsg-subdev.h
@@ -59,7 +59,7 @@
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;
+ int64_t frame_interval, max_frame_interval, frame_interval_variance;
struct workqueue_struct *work_queue;
struct hrtimer threshold_timer;
struct mutex mutex;
@@ -90,9 +90,11 @@
/* Time related arguments for frame interval ioctls are always in nanosecs*/
#define VSG_SET_FRAME_INTERVAL _IOW(VSG_MAGIC_IOCTL, 9, int64_t *)
#define VSG_GET_FRAME_INTERVAL _IOR(VSG_MAGIC_IOCTL, 10, int64_t *)
-#define VSG_SET_MAX_FRAME_INTERVAL _IOW(VSG_MAGIC_IOCTL, 11, int64_t *)
-#define VSG_GET_MAX_FRAME_INTERVAL _IOR(VSG_MAGIC_IOCTL, 12, int64_t *)
-#define VSG_SET_MODE _IOW(VSG_MAGIC_IOCTL, 13, enum vsg_modes *)
+#define VSG_SET_FRAME_INTERVAL_VARIANCE _IOW(VSG_MAGIC_IOCTL, 11, int64_t *)
+#define VSG_GET_FRAME_INTERVAL_VARIANCE _IOR(VSG_MAGIC_IOCTL, 12, int64_t *)
+#define VSG_SET_MAX_FRAME_INTERVAL _IOW(VSG_MAGIC_IOCTL, 13, int64_t *)
+#define VSG_GET_MAX_FRAME_INTERVAL _IOR(VSG_MAGIC_IOCTL, 14, int64_t *)
+#define VSG_SET_MODE _IOW(VSG_MAGIC_IOCTL, 15, enum vsg_modes *)
extern int vsg_init(struct v4l2_subdev *sd, u32 val);
extern long vsg_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg);
diff --git a/drivers/media/platform/msm/wfd/wfd-ioctl.c b/drivers/media/platform/msm/wfd/wfd-ioctl.c
index 30a666d..58e008d 100644
--- a/drivers/media/platform/msm/wfd/wfd-ioctl.c
+++ b/drivers/media/platform/msm/wfd/wfd-ioctl.c
@@ -715,6 +715,11 @@
if (rc)
WFD_MSG_ERR("Failed to stop MDP\n");
+ rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
+ ENCODE_FLUSH, (void *)inst->venc_inst);
+ if (rc)
+ WFD_MSG_ERR("Failed to flush encoder\n");
+
WFD_MSG_DBG("vsg stop\n");
rc = v4l2_subdev_call(&wfd_dev->vsg_sdev, core, ioctl,
VSG_STOP, NULL);
@@ -723,10 +728,6 @@
complete(&inst->stop_mdp_thread);
kthread_stop(inst->mdp_task);
- rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
- ENCODE_FLUSH, (void *)inst->venc_inst);
- if (rc)
- WFD_MSG_ERR("Failed to flush encoder\n");
WFD_MSG_DBG("enc stop\n");
rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
ENCODE_STOP, (void *)inst->venc_inst);
@@ -1123,7 +1124,9 @@
struct wfd_device *wfd_dev = video_drvdata(filp);
struct wfd_inst *inst = file_to_inst(filp);
struct v4l2_qcom_frameskip frameskip;
- int64_t frame_interval, max_frame_interval;
+ int64_t frame_interval = 0,
+ max_frame_interval = 0,
+ frame_interval_variance = 0;
void *extendedmode = NULL;
enum vsg_modes vsg_mode = VSG_MODE_VFR;
enum venc_framerate_modes venc_mode = VENC_MODE_VFR;
@@ -1176,6 +1179,7 @@
goto set_parm_fail;
max_frame_interval = (int64_t)frameskip.maxframeinterval;
+ frame_interval_variance = frameskip.fpsvariance;
vsg_mode = VSG_MODE_VFR;
venc_mode = VENC_MODE_VFR;
@@ -1205,6 +1209,16 @@
goto set_parm_fail;
}
+ if (frame_interval_variance) {
+ rc = v4l2_subdev_call(&wfd_dev->vsg_sdev, core,
+ ioctl, VSG_SET_FRAME_INTERVAL_VARIANCE,
+ &frame_interval_variance);
+ if (rc) {
+ WFD_MSG_ERR("Setting FR variance for VSG failed\n");
+ goto set_parm_fail;
+ }
+ }
+
set_parm_fail:
return rc;
}
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index d673713..b9eb8f9 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -1635,8 +1635,9 @@
if (status)
return;
- if (radio->mode != FM_CALIB)
+ if ((radio->mode != FM_CALIB) && (radio->mode != FM_OFF))
iris_q_event(radio, IRIS_EVT_RADIO_DISABLED);
+ radio->mode = FM_OFF;
radio_hci_req_complete(hdev, status);
}
@@ -2385,7 +2386,7 @@
iris_q_event(radio, IRIS_EVT_NEW_RT_RDS);
- while ((skb->data[len+RDS_OFFSET] != 0x0d) && (len < RX_RT_DATA_LENGTH))
+ while ((skb->data[len+RDS_OFFSET] != 0x0d) && (len < MAX_RT_LENGTH))
len++;
data = kmalloc(len+RDS_OFFSET, GFP_ATOMIC);
if (!data) {
@@ -2397,7 +2398,7 @@
data[1] = skb->data[RDS_PTYPE];
data[2] = skb->data[RDS_PID_LOWER];
data[3] = skb->data[RDS_PID_HIGHER];
- data[4] = 0;
+ data[4] = skb->data[RT_A_B_FLAG_OFFSET];
memcpy(data+RDS_OFFSET, &skb->data[RDS_OFFSET], len);
data[len+RDS_OFFSET] = 0x00;
@@ -2416,9 +2417,15 @@
ev.tune_freq = *((int *) &skb->data[0]);
ev.pi_code = *((__le16 *) &skb->data[PI_CODE_OFFSET]);
ev.af_size = skb->data[AF_SIZE_OFFSET];
- memcpy(&ev.af_list[0], &skb->data[AF_LIST_OFFSET], ev.af_size);
+ if (ev.af_size > AF_LIST_MAX) {
+ FMDERR("AF list size received more than available size");
+ return;
+ }
+ memcpy(&ev.af_list[0], &skb->data[AF_LIST_OFFSET],
+ ev.af_size * sizeof(int));
iris_q_event(radio, IRIS_EVT_NEW_AF_LIST);
- iris_q_evt_data(radio, (char *)&ev, sizeof(ev), IRIS_BUF_AF_LIST);
+ iris_q_evt_data(radio, (char *)&ev, (7 + ev.af_size * sizeof(int)),
+ IRIS_BUF_AF_LIST);
}
static void hci_ev_rds_lock_status(struct radio_hci_dev *hdev,
@@ -2688,7 +2695,7 @@
radio->fm_hdev);
if (retval < 0)
FMDERR("Disable Failed after calibration %d", retval);
- radio->mode = FM_OFF;
+ radio->mode = FM_TURNING_OFF;
return retval;
}
static int iris_vidioc_g_ctrl(struct file *file, void *priv,
@@ -3234,7 +3241,7 @@
" %d\n", retval);
return retval;
}
- radio->mode = FM_OFF;
+ radio->mode = FM_TURNING_OFF;
break;
case FM_TRANS:
retval = hci_cmd(HCI_FM_DISABLE_TRANS_CMD,
@@ -3245,7 +3252,7 @@
" %d\n", retval);
return retval;
}
- radio->mode = FM_OFF;
+ radio->mode = FM_TURNING_OFF;
break;
default:
retval = -EINVAL;
@@ -4036,16 +4043,18 @@
if (radio->mode == FM_OFF)
return 0;
- if (radio->mode == FM_RECV)
+ if (radio->mode == FM_RECV) {
+ radio->mode = FM_OFF;
retval = hci_cmd(HCI_FM_DISABLE_RECV_CMD,
radio->fm_hdev);
- else if (radio->mode == FM_TRANS)
+ } else if (radio->mode == FM_TRANS) {
+ radio->mode = FM_OFF;
retval = hci_cmd(HCI_FM_DISABLE_TRANS_CMD,
radio->fm_hdev);
+ }
if (retval < 0)
FMDERR("Err on disable FM %d\n", retval);
- radio->mode = FM_OFF;
return retval;
}
diff --git a/drivers/media/radio/radio-tavarua.c b/drivers/media/radio/radio-tavarua.c
index ea7032b..e0a99e2 100644
--- a/drivers/media/radio/radio-tavarua.c
+++ b/drivers/media/radio/radio-tavarua.c
@@ -1932,6 +1932,7 @@
if (bahama_present == -ENODEV)
return -ENODEV;
+ marimba_set_fm_status(radio->marimba, true);
if (bahama_present)
radio->marimba->mod_id = SLAVE_ID_BAHAMA;
else
@@ -2066,7 +2067,6 @@
radio->handle_irq = 0;
radio->marimba->mod_id = SLAVE_ID_BAHAMA;
- marimba_set_fm_status(radio->marimba, true);
return 0;
@@ -2082,6 +2082,7 @@
config_i2s_err:
radio->pdata->fm_shutdown(radio->pdata);
open_err_setup:
+ marimba_set_fm_status(radio->marimba, false);
radio->handle_irq = 1;
atomic_inc(&radio->users);
return retval;
diff --git a/drivers/mfd/pm8xxx-pwm.c b/drivers/mfd/pm8xxx-pwm.c
index eb8320f..24fd5c1 100644
--- a/drivers/mfd/pm8xxx-pwm.c
+++ b/drivers/mfd/pm8xxx-pwm.c
@@ -35,7 +35,7 @@
*/
#define PM8XXX_LPG_V0_PWM_CHANNELS 8
#define PM8XXX_LPG_V1_PWM_CHANNELS 6
-#define PM8XXX_LPG_CTL_REGS 7
+#define PM8XXX_LPG_CTL_REGS 8
/* PM8XXX PWM */
#define SSBI_REG_ADDR_PWM1_CTRL1 0x88
@@ -66,6 +66,7 @@
#define SSBI_REG_ADDR_LPG_LUT_CFG0 0x145
#define SSBI_REG_ADDR_LPG_LUT_CFG1 0x146
#define SSBI_REG_ADDR_LPG_TEST 0x147
+#define SSBI_REG_ADDR_LPG_CTL_7 0x14D
/* LPG Control 0 */
#define PM8XXX_PWM_1KHZ_COUNT_MASK 0xF0
@@ -126,6 +127,7 @@
#define PM8XXX_PWM_PAUSE_ENABLE_HIGH 0x02
#define PM8XXX_PWM_SIZE_9_BIT 0x01
+#define PM8XXX_PWM_SIZE_7_BIT 0x04
/* LPG Control 6 */
#define PM8XXX_PWM_PAUSE_COUNT_LO_MASK 0xFC
@@ -369,17 +371,22 @@
}
static void pm8xxx_pwm_calc_period(unsigned int period_us,
- struct pm8xxx_pwm_period *period)
+ struct pwm_device *pwm)
{
int n, m, clk, div;
int best_m, best_div, best_clk;
unsigned int last_err, cur_err, min_err;
unsigned int tmp_p, period_n;
+ struct pm8xxx_pwm_period *period = &pwm->period;
+
+ if (pwm->banks == PM_PWM_BANK_LO)
+ n = 7;
+ else
+ n = 6;
/* PWM Period / N */
if (period_us < ((unsigned)(-1) / NSEC_PER_USEC)) {
- period_n = (period_us * NSEC_PER_USEC) >> 6;
- n = 6;
+ period_n = (period_us * NSEC_PER_USEC) >> n;
} else {
period_n = (period_us >> 9) * NSEC_PER_USEC;
n = 9;
@@ -458,6 +465,9 @@
int rc = 0;
pwm_size = (pwm->pwm_lpg_ctl[5] & PM8XXX_PWM_SIZE_9_BIT) ? 9 : 6;
+ if (pwm->period.pwm_size == 7)
+ pwm_size = 7;
+
max_pwm_value = (1 << pwm_size) - 1;
for (i = 0; i < len; i++) {
if (raw_value)
@@ -512,9 +522,16 @@
PM8XXX_LPG_PWM_PREDIVIDE_MASK | PM8XXX_LPG_PWM_M_MASK;
pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[4], mask, val);
- val = (pwm->period.pwm_size > 6) ? PM8XXX_PWM_SIZE_9_BIT : 0;
- mask = PM8XXX_PWM_SIZE_9_BIT;
- pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[5], mask, val);
+ if (pwm->period.pwm_size == 7) {
+ val = PM8XXX_PWM_SIZE_7_BIT;
+ mask = PM8XXX_PWM_SIZE_7_BIT;
+ pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[7], mask, val);
+ } else {
+ val = (pwm->period.pwm_size > 6) ?
+ PM8XXX_PWM_SIZE_9_BIT : 0;
+ mask = PM8XXX_PWM_SIZE_9_BIT;
+ pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[5], mask, val);
+ }
} else {
val = ((pwm->period.clk + 1) << PM8XXX_PWM_CLK_SEL_SHIFT)
& PM8XXX_PWM_CLK_SEL_MASK;
@@ -639,8 +656,18 @@
{
int i, rc;
+ if (end == 7) {
+ rc = pm8xxx_writeb(pwm->chip->dev->parent,
+ SSBI_REG_ADDR_LPG_CTL_7,
+ pwm->pwm_lpg_ctl[end]);
+ if (rc) {
+ pr_err("pm8xxx_writeb(): rc=%d (PWM Ctl[7])\n", rc);
+ return rc;
+ }
+ }
+
/* Write in reverse way so 0 would be the last */
- for (i = end - 1; i >= start; i--) {
+ for (i = end - 2; i >= start; i--) {
rc = pm8xxx_writeb(pwm->chip->dev->parent,
SSBI_REG_ADDR_LPG_CTL(i),
pwm->pwm_lpg_ctl[i]);
@@ -788,7 +815,7 @@
}
if (pwm->pwm_period != period_us) {
- pm8xxx_pwm_calc_period(period_us, period);
+ pm8xxx_pwm_calc_period(period_us, pwm);
pm8xxx_pwm_save_period(pwm);
pwm->pwm_period = period_us;
}
@@ -801,7 +828,7 @@
PM8XXX_PWM_BYPASS_LUT, PM8XXX_PWM_BYPASS_LUT);
pm8xxx_pwm_bank_sel(pwm);
- rc = pm8xxx_lpg_pwm_write(pwm, 1, 6);
+ rc = pm8xxx_lpg_pwm_write(pwm, 1, 7);
} else {
rc = pm8xxx_pwm_write(pwm);
}
@@ -851,7 +878,7 @@
* PWM mode.
*/
if (pwm->chip->is_pwm_enable_sync_workaround_needed)
- rc = pm8xxx_lpg_pwm_write(pwm, 3, 4);
+ rc = pm8xxx_lpg_pwm_write(pwm, 3, 5);
} else {
pm8xxx_pwm_enable(pwm);
@@ -921,7 +948,7 @@
if (pwm_chip->is_lpg_supported) {
pm8xxx_pwm_bank_sel(pwm);
- rc = pm8xxx_lpg_pwm_write(pwm, 4, 6);
+ rc = pm8xxx_lpg_pwm_write(pwm, 4, 7);
} else {
rc = pm8xxx_pwm_write(pwm);
}
@@ -965,7 +992,7 @@
pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[1],
PM8XXX_PWM_BYPASS_LUT, PM8XXX_PWM_BYPASS_LUT);
pm8xxx_pwm_bank_sel(pwm);
- rc = pm8xxx_lpg_pwm_write(pwm, 1, 6);
+ rc = pm8xxx_lpg_pwm_write(pwm, 1, 7);
} else {
rc = pm8xxx_pwm_write(pwm);
}
@@ -996,7 +1023,6 @@
int idx_len, int pause_lo, int pause_hi, int flags)
{
struct pm8xxx_pwm_lut lut;
- struct pm8xxx_pwm_period *period;
int len;
int rc;
@@ -1032,7 +1058,6 @@
return -EINVAL;
}
- period = &pwm->period;
mutex_lock(&pwm->chip->pwm_mutex);
if (flags & PM_PWM_BANK_HI)
@@ -1052,7 +1077,7 @@
}
if (pwm->pwm_period != period_us) {
- pm8xxx_pwm_calc_period(period_us, period);
+ pm8xxx_pwm_calc_period(period_us, pwm);
pm8xxx_pwm_save_period(pwm);
pwm->pwm_period = period_us;
}
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 6ea2346..bd838fc 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -69,6 +69,8 @@
/* Check if enterprise security is activate */
#define SCM_IS_ACTIVATED_ID 0x02
+#define RPMB_SERVICE 0x2000
+
enum qseecom_clk_definitions {
CLK_DFAB = 0,
CLK_SFPB,
@@ -212,6 +214,8 @@
/* Function proto types */
static int qsee_vote_for_clock(struct qseecom_dev_handle *, int32_t);
static void qsee_disable_clock_vote(struct qseecom_dev_handle *, int32_t);
+static int __qseecom_enable_clk(enum qseecom_ce_hw_instance ce);
+static void __qseecom_disable_clk(enum qseecom_ce_hw_instance ce);
static int __qseecom_is_svc_unique(struct qseecom_dev_handle *data,
struct qseecom_register_listener_req *svc)
@@ -520,6 +524,10 @@
msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle,
ptr_svc->sb_virt, ptr_svc->sb_length,
ION_IOC_CLEAN_INV_CACHES);
+
+ if (lstnr == RPMB_SERVICE)
+ __qseecom_enable_clk(CLK_QSEE);
+
ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
(const void *)&send_data_rsp,
sizeof(send_data_rsp), resp,
@@ -527,6 +535,8 @@
if (ret) {
pr_err("scm_call() failed with err: %d (app_id = %d)\n",
ret, data->client.app_id);
+ if (lstnr == RPMB_SERVICE)
+ __qseecom_disable_clk(CLK_QSEE);
return ret;
}
if ((resp->result != QSEOS_RESULT_SUCCESS) &&
@@ -535,6 +545,9 @@
resp->result, data->client.app_id, lstnr);
ret = -EINVAL;
}
+ if (lstnr == RPMB_SERVICE)
+ __qseecom_disable_clk(CLK_QSEE);
+
}
if (rc)
return rc;
@@ -605,11 +618,12 @@
memcpy(req.app_name, load_img_req.img_name, MAX_APP_NAME_SIZE);
ret = __qseecom_check_app_exists(req);
- if (ret < 0)
+ if (ret < 0) {
+ qsee_disable_clock_vote(data, CLK_SFPB);
return ret;
- else
- app_id = ret;
+ }
+ app_id = ret;
if (app_id) {
pr_debug("App id %d (%s) already exists\n", app_id,
(char *)(req.app_name));
@@ -996,7 +1010,6 @@
return ret;
}
-
static int qseecom_send_cmd(struct qseecom_dev_handle *data, void __user *argp)
{
int ret = 0;
@@ -1017,8 +1030,29 @@
return ret;
}
-static int __qseecom_update_cmd_buf(struct qseecom_send_modfd_cmd_req *req,
- bool cleanup)
+static int qseecom_unprotect_buffer(void __user *argp)
+{
+ int ret = 0;
+ struct ion_handle *ihandle;
+ int32_t ion_fd;
+
+ ret = copy_from_user(&ion_fd, argp, sizeof(ion_fd));
+ if (ret) {
+ pr_err("copy_from_user failed");
+ return ret;
+ }
+
+ ihandle = ion_import_dma_buf(qseecom.ion_clnt, ion_fd);
+
+ ret = msm_ion_unsecure_buffer(qseecom.ion_clnt, ihandle);
+ if (ret)
+ return -EINVAL;
+ return 0;
+}
+
+static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
+ struct qseecom_dev_handle *data,
+ bool listener_svc)
{
struct ion_handle *ihandle;
char *field;
@@ -1026,76 +1060,119 @@
int i = 0;
uint32_t len = 0;
struct scatterlist *sg;
+ struct qseecom_send_modfd_cmd_req *cmd_req = NULL;
+ struct qseecom_send_modfd_listener_resp *lstnr_resp = NULL;
+ struct qseecom_registered_listener_list *this_lstnr = NULL;
+
+ if (msg == NULL) {
+ pr_err("Invalid address\n");
+ return -EINVAL;
+ }
+ if (listener_svc) {
+ lstnr_resp = (struct qseecom_send_modfd_listener_resp *)msg;
+ this_lstnr = __qseecom_find_svc(data->listener.id);
+ if (IS_ERR_OR_NULL(this_lstnr)) {
+ pr_err("Invalid listener ID\n");
+ return -ENOMEM;
+ }
+ } else {
+ cmd_req = (struct qseecom_send_modfd_cmd_req *)msg;
+ }
for (i = 0; i < MAX_ION_FD; i++) {
struct sg_table *sg_ptr = NULL;
- if (req->ifd_data[i].fd > 0) {
- /* Get the handle of the shared fd */
+ if ((!listener_svc) && (cmd_req->ifd_data[i].fd > 0)) {
ihandle = ion_import_dma_buf(qseecom.ion_clnt,
- req->ifd_data[i].fd);
+ cmd_req->ifd_data[i].fd);
if (IS_ERR_OR_NULL(ihandle)) {
pr_err("Ion client can't retrieve the handle\n");
return -ENOMEM;
}
- field = (char *) req->cmd_req_buf +
- req->ifd_data[i].cmd_buf_offset;
-
- /* Populate the cmd data structure with the phys_addr */
- sg_ptr = ion_sg_table(qseecom.ion_clnt, ihandle);
- if (sg_ptr == NULL) {
- pr_err("IOn client could not retrieve sg table\n");
- goto err;
+ field = (char *) cmd_req->cmd_req_buf +
+ cmd_req->ifd_data[i].cmd_buf_offset;
+ } else if ((listener_svc) &&
+ (lstnr_resp->ifd_data[i].fd > 0)) {
+ ihandle = ion_import_dma_buf(qseecom.ion_clnt,
+ lstnr_resp->ifd_data[i].fd);
+ if (IS_ERR_OR_NULL(ihandle)) {
+ pr_err("Ion client can't retrieve the handle\n");
+ return -ENOMEM;
}
- if (sg_ptr->nents == 0) {
- pr_err("Num of scattered entries is 0\n");
- goto err;
+ switch (lstnr_resp->protection_mode) {
+ case QSEOS_PROTECT_BUFFER:
+ ret = msm_ion_secure_buffer(qseecom.ion_clnt,
+ ihandle,
+ VIDEO_PIXEL,
+ 0);
+ break;
+ case QSEOS_UNPROTECT_PROTECTED_BUFFER:
+ ret = msm_ion_unsecure_buffer(qseecom.ion_clnt,
+ ihandle);
+ break;
+ case QSEOS_UNPROTECTED_BUFFER:
+ default:
+ break;
}
- if (sg_ptr->nents > QSEECOM_MAX_SG_ENTRY) {
- pr_err("Num of scattered entries");
- pr_err(" (%d) is greater than max supported %d\n",
- sg_ptr->nents, QSEECOM_MAX_SG_ENTRY);
- goto err;
- }
- sg = sg_ptr->sgl;
- if (sg_ptr->nents == 1) {
- uint32_t *update;
- update = (uint32_t *) field;
- if (cleanup)
- *update = 0;
- else
- *update = (uint32_t)sg_dma_address(
- sg_ptr->sgl);
- len += (uint32_t)sg->length;
- } else {
- struct qseecom_sg_entry *update;
- int j = 0;
- update = (struct qseecom_sg_entry *) field;
- for (j = 0; j < sg_ptr->nents; j++) {
- if (cleanup) {
- update->phys_addr = 0;
- update->len = 0;
- } else {
- update->phys_addr = (uint32_t)
- sg_dma_address(sg);
- update->len = sg->length;
- }
- len += sg->length;
- update++;
- sg = sg_next(sg);
- }
- }
- if (cleanup)
- msm_ion_do_cache_op(qseecom.ion_clnt,
- ihandle, NULL, len,
- ION_IOC_INV_CACHES);
- else
- msm_ion_do_cache_op(qseecom.ion_clnt,
- ihandle, NULL, len,
- ION_IOC_CLEAN_INV_CACHES);
- /* Deallocate the handle */
- if (!IS_ERR_OR_NULL(ihandle))
- ion_free(qseecom.ion_clnt, ihandle);
+ field = lstnr_resp->resp_buf_ptr +
+ lstnr_resp->ifd_data[i].cmd_buf_offset;
+ } else {
+ return ret;
}
+ /* Populate the cmd data structure with the phys_addr */
+ sg_ptr = ion_sg_table(qseecom.ion_clnt, ihandle);
+ if (sg_ptr == NULL) {
+ pr_err("IOn client could not retrieve sg table\n");
+ goto err;
+ }
+ if (sg_ptr->nents == 0) {
+ pr_err("Num of scattered entries is 0\n");
+ goto err;
+ }
+ if (sg_ptr->nents > QSEECOM_MAX_SG_ENTRY) {
+ pr_err("Num of scattered entries");
+ pr_err(" (%d) is greater than max supported %d\n",
+ sg_ptr->nents, QSEECOM_MAX_SG_ENTRY);
+ goto err;
+ }
+ sg = sg_ptr->sgl;
+ if (sg_ptr->nents == 1) {
+ uint32_t *update;
+ update = (uint32_t *) field;
+ if (cleanup)
+ *update = 0;
+ else
+ *update = (uint32_t)sg_dma_address(
+ sg_ptr->sgl);
+ len += (uint32_t)sg->length;
+ } else {
+ struct qseecom_sg_entry *update;
+ int j = 0;
+ update = (struct qseecom_sg_entry *) field;
+ for (j = 0; j < sg_ptr->nents; j++) {
+ if (cleanup) {
+ update->phys_addr = 0;
+ update->len = 0;
+ } else {
+ update->phys_addr = (uint32_t)
+ sg_dma_address(sg);
+ update->len = sg->length;
+ }
+ len += sg->length;
+ update++;
+ sg = sg_next(sg);
+ }
+ }
+ if (cleanup)
+ msm_ion_do_cache_op(qseecom.ion_clnt,
+ ihandle, NULL, len,
+ ION_IOC_INV_CACHES);
+ else
+ msm_ion_do_cache_op(qseecom.ion_clnt,
+ ihandle, NULL, len,
+ ION_IOC_CLEAN_INV_CACHES);
+ /* Deallocate the handle */
+ if (!IS_ERR_OR_NULL(ihandle))
+ ion_free(qseecom.ion_clnt, ihandle);
}
return ret;
err:
@@ -1121,13 +1198,13 @@
send_cmd_req.resp_buf = req.resp_buf;
send_cmd_req.resp_len = req.resp_len;
- ret = __qseecom_update_cmd_buf(&req, false);
+ ret = __qseecom_update_cmd_buf(&req, false, data, false);
if (ret)
return ret;
ret = __qseecom_send_cmd(data, &send_cmd_req);
if (ret)
return ret;
- ret = __qseecom_update_cmd_buf(&req, true);
+ 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",
@@ -1706,6 +1783,23 @@
return 0;
}
+
+static int qseecom_send_modfd_resp(struct qseecom_dev_handle *data,
+ void __user *argp)
+{
+ struct qseecom_send_modfd_listener_resp resp;
+
+ if (copy_from_user(&resp, argp, sizeof(resp))) {
+ pr_err("copy_from_user failed");
+ return -EINVAL;
+ }
+ __qseecom_update_cmd_buf(&resp, false, data, true);
+ qseecom.send_resp_flag = 1;
+ wake_up_interruptible(&qseecom.send_resp_wq);
+ return 0;
+}
+
+
static int qseecom_get_qseos_version(struct qseecom_dev_handle *data,
void __user *argp)
{
@@ -2008,14 +2102,15 @@
pr_err("set_cpus_allowed_ptr failed : ret %d\n",
set_cpu_ret);
ret = -EFAULT;
- goto qseecom_load_external_elf_set_cpu_err;
+ goto exit_ion_free;
}
+
/* Vote for the SFPB clock */
ret = qsee_vote_for_clock(data, CLK_SFPB);
if (ret) {
pr_err("Unable to vote for SFPB clock: ret = %d", ret);
ret = -EIO;
- goto qseecom_load_external_elf_set_cpu_err;
+ goto exit_cpu_restore;
}
msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len,
ION_IOC_CLEAN_INV_CACHES);
@@ -2027,23 +2122,32 @@
pr_err("scm_call to load failed : ret %d\n",
ret);
ret = -EFAULT;
- goto qseecom_load_external_elf_scm_err;
+ goto exit_disable_clock;
}
- if (resp.result == QSEOS_RESULT_INCOMPLETE) {
+ switch (resp.result) {
+ case QSEOS_RESULT_SUCCESS:
+ break;
+ case QSEOS_RESULT_INCOMPLETE:
+ pr_err("%s: qseos result incomplete\n", __func__);
ret = __qseecom_process_incomplete_cmd(data, &resp);
if (ret)
- pr_err("process_incomplete_cmd failed err: %d\n",
- ret);
- } else {
- if (resp.result != QSEOS_RESULT_SUCCESS) {
- pr_err("scm_call to load image failed resp.result =%d\n",
- resp.result);
- ret = -EFAULT;
- }
+ pr_err("process_incomplete_cmd failed: err: %d\n", ret);
+ break;
+ case QSEOS_RESULT_FAILURE:
+ pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n");
+ ret = -EFAULT;
+ break;
+ default:
+ pr_err("scm_call response result %d not supported\n",
+ resp.result);
+ ret = -EFAULT;
+ break;
}
-qseecom_load_external_elf_scm_err:
+exit_disable_clock:
+ qsee_disable_clock_vote(data, CLK_SFPB);
+exit_cpu_restore:
/* Restore the CPU mask */
mask = CPU_MASK_ALL;
set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
@@ -2052,12 +2156,10 @@
set_cpu_ret);
ret = -EFAULT;
}
-
-qseecom_load_external_elf_set_cpu_err:
+exit_ion_free:
/* Deallocate the handle */
if (!IS_ERR_OR_NULL(ihandle))
ion_free(qseecom.ion_clnt, ihandle);
- qsee_disable_clock_vote(data, CLK_SFPB);
return ret;
}
@@ -2768,6 +2870,26 @@
mutex_unlock(&app_access_lock);
break;
}
+ case QSEECOM_IOCTL_SEND_MODFD_RESP: {
+ /* Only one client allowed here at a time */
+ atomic_inc(&data->ioctl_count);
+ ret = qseecom_send_modfd_resp(data, argp);
+ atomic_dec(&data->ioctl_count);
+ wake_up_all(&data->abort_wq);
+ if (ret)
+ pr_err("failed qseecom_send_mod_resp: %d\n", ret);
+ break;
+ }
+ case QSEECOM_IOCTL_UNPROTECT_BUF: {
+ /* Only one client allowed here at a time */
+ atomic_inc(&data->ioctl_count);
+ ret = qseecom_unprotect_buffer(argp);
+ atomic_dec(&data->ioctl_count);
+ wake_up_all(&data->abort_wq);
+ if (ret)
+ pr_err("failed qseecom_unprotect: %d\n", ret);
+ break;
+ }
default:
return -EINVAL;
}
diff --git a/drivers/misc/tspp.c b/drivers/misc/tspp.c
index a395b7c..36bdf45 100644
--- a/drivers/misc/tspp.c
+++ b/drivers/misc/tspp.c
@@ -617,8 +617,8 @@
break;
if (iovec.addr != channel->waiting->sps.phys_base)
- pr_err("tspp: buffer mismatch 0x%08x",
- channel->waiting->sps.phys_base);
+ pr_err("tspp: buffer mismatch %pa",
+ &channel->waiting->sps.phys_base);
complete = 1;
channel->waiting->state = TSPP_BUF_STATE_DATA;
@@ -802,7 +802,7 @@
if (device->tsif_vreg) {
regulator_set_voltage(device->tsif_vreg,
- RPM_REGULATOR_CORNER_SVS_SOC,
+ RPM_REGULATOR_CORNER_NONE,
RPM_REGULATOR_CORNER_SUPER_TURBO);
}
@@ -818,7 +818,7 @@
clk_disable_unprepare(device->tsif_pclk);
if (device->tsif_vreg) {
regulator_set_voltage(device->tsif_vreg,
- RPM_REGULATOR_CORNER_SVS_SOC,
+ RPM_REGULATOR_CORNER_NONE,
RPM_REGULATOR_CORNER_SUPER_TURBO);
}
@@ -848,7 +848,7 @@
if (device->tsif_vreg) {
rc = regulator_set_voltage(device->tsif_vreg,
- RPM_REGULATOR_CORNER_SVS_SOC,
+ RPM_REGULATOR_CORNER_NONE,
RPM_REGULATOR_CORNER_SUPER_TURBO);
if (rc)
pr_err("Unable to set CX voltage.\n");
@@ -2945,7 +2945,7 @@
/* Set an initial voltage and enable the regulator */
rc = regulator_set_voltage(device->tsif_vreg,
- RPM_REGULATOR_CORNER_SVS_SOC,
+ RPM_REGULATOR_CORNER_NONE,
RPM_REGULATOR_CORNER_SUPER_TURBO);
if (rc) {
dev_err(&pdev->dev, "Unable to set CX voltage.\n");
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index d975543..da07947 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -1363,7 +1363,7 @@
pr_debug("%s: %s - SANITIZE IN PROGRESS...\n",
mmc_hostname(card->host), __func__);
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ err = mmc_switch_ignore_timeout(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_SANITIZE_START, 1,
MMC_SANITIZE_REQ_TIMEOUT);
diff --git a/drivers/mmc/card/mmc_block_test.c b/drivers/mmc/card/mmc_block_test.c
index 7a4d19e..e9ac2fc 100644
--- a/drivers/mmc/card/mmc_block_test.c
+++ b/drivers/mmc/card/mmc_block_test.c
@@ -20,7 +20,6 @@
#include <linux/mmc/host.h>
#include <linux/delay.h>
#include <linux/test-iosched.h>
-#include <linux/jiffies.h>
#include "queue.h"
#include <linux/mmc/mmc.h>
@@ -2787,7 +2786,7 @@
if (ret)
break;
- mtime = jiffies_to_msecs(mbtd->test_info.test_duration);
+ mtime = ktime_to_ms(mbtd->test_info.test_duration);
test_pr_info("%s: time is %lu msec, size is %u.%u MiB",
__func__, mtime,
@@ -2946,7 +2945,7 @@
if (ret)
break;
- mtime = jiffies_to_msecs(mbtd->test_info.test_duration);
+ mtime = ktime_to_ms(mbtd->test_info.test_duration);
byte_count = mbtd->test_info.test_byte_count;
test_pr_info("%s: time is %lu msec, size is %lu.%lu MiB",
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 04687fa..064d5ec 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -59,6 +59,9 @@
*/
#define MMC_BKOPS_MAX_TIMEOUT (30 * 1000) /* max time to wait in ms */
+/* Flushing a large amount of cached data may take a long time. */
+#define MMC_FLUSH_REQ_TIMEOUT_MS 30000 /* msec */
+
static struct workqueue_struct *workqueue;
/*
@@ -785,21 +788,13 @@
cmd = mrq->cmd;
/*
- * If host has timed out waiting for the blocking BKOPs
- * to complete, card might be still in programming state
- * so let's try to bring the card out of programming state.
+ * If host has timed out waiting for the commands which can be
+ * HPIed then let the caller handle the timeout error as it may
+ * want to send the HPI command to bring the card out of
+ * programming state.
*/
- if (cmd->bkops_busy && cmd->error == -ETIMEDOUT) {
- if (!mmc_interrupt_hpi(host->card)) {
- pr_warning("%s: %s: Interrupted blocking bkops\n",
- mmc_hostname(host), __func__);
- cmd->error = 0;
- break;
- } else {
- pr_err("%s: %s: Failed to interrupt blocking bkops\n",
- mmc_hostname(host), __func__);
- }
- }
+ if (cmd->ignore_timeout && cmd->error == -ETIMEDOUT)
+ break;
if (!cmd->error || !cmd->retries ||
mmc_card_removed(host->card))
@@ -1064,8 +1059,6 @@
}
err = mmc_send_hpi_cmd(card, &status);
- if (err)
- goto out;
prg_wait = jiffies + msecs_to_jiffies(card->ext_csd.out_of_int_time);
do {
@@ -2594,7 +2587,7 @@
if (mmc_card_sdio(card))
return 0;
- if (mmc_card_mmc(card)) {
+ if (mmc_card_mmc(card) && (card->host->caps & MMC_CAP_HW_RESET)) {
rst_n_function = card->ext_csd.rst_n_function;
if ((rst_n_function & EXT_CSD_RST_N_EN_MASK) !=
EXT_CSD_RST_N_ENABLED)
@@ -2611,9 +2604,6 @@
if (!host->bus_ops->power_restore)
return -EOPNOTSUPP;
- if (!(host->caps & MMC_CAP_HW_RESET))
- return -EOPNOTSUPP;
-
if (!card)
return -EINVAL;
@@ -2623,10 +2613,10 @@
mmc_host_clk_hold(host);
mmc_set_clock(host, host->f_init);
- if (mmc_card_sd(card))
- mmc_power_cycle(host);
- else if (host->ops->hw_reset)
+ if (mmc_card_mmc(card) && host->ops->hw_reset)
host->ops->hw_reset(host);
+ else
+ mmc_power_cycle(host);
/* If the reset has happened, then a status command will fail */
if (check) {
@@ -3336,7 +3326,7 @@
int mmc_flush_cache(struct mmc_card *card)
{
struct mmc_host *host = card->host;
- int err = 0;
+ int err = 0, rc;
if (!(host->caps2 & MMC_CAP2_CACHE_CTRL))
return err;
@@ -3344,11 +3334,20 @@
if (mmc_card_mmc(card) &&
(card->ext_csd.cache_size > 0) &&
(card->ext_csd.cache_ctrl & 1)) {
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_FLUSH_CACHE, 1, 0);
- if (err)
+ err = mmc_switch_ignore_timeout(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_FLUSH_CACHE, 1,
+ MMC_FLUSH_REQ_TIMEOUT_MS);
+ if (err == -ETIMEDOUT) {
+ pr_debug("%s: cache flush timeout\n",
+ mmc_hostname(card->host));
+ rc = mmc_interrupt_hpi(card);
+ if (rc)
+ pr_err("%s: mmc_interrupt_hpi() failed (%d)\n",
+ mmc_hostname(host), rc);
+ } else if (err) {
pr_err("%s: cache flush error %d\n",
mmc_hostname(card->host), err);
+ }
}
return err;
@@ -3364,8 +3363,8 @@
int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
{
struct mmc_card *card = host->card;
- unsigned int timeout;
- int err = 0;
+ unsigned int timeout = card->ext_csd.generic_cmd6_time;
+ int err = 0, rc;
if (!(host->caps2 & MMC_CAP2_CACHE_CTRL) ||
mmc_card_is_removable(host))
@@ -3376,16 +3375,28 @@
enable = !!enable;
if (card->ext_csd.cache_ctrl ^ enable) {
- timeout = enable ? card->ext_csd.generic_cmd6_time : 0;
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ if (!enable)
+ timeout = MMC_FLUSH_REQ_TIMEOUT_MS;
+
+ err = mmc_switch_ignore_timeout(card,
+ EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_CACHE_CTRL, enable, timeout);
- if (err)
+
+ if (err == -ETIMEDOUT && !enable) {
+ pr_debug("%s:cache disable operation timeout\n",
+ mmc_hostname(card->host));
+ rc = mmc_interrupt_hpi(card);
+ if (rc)
+ pr_err("%s: mmc_interrupt_hpi() failed (%d)\n",
+ mmc_hostname(host), rc);
+ } else if (err) {
pr_err("%s: cache %s error %d\n",
mmc_hostname(card->host),
enable ? "on" : "off",
err);
- else
+ } else {
card->ext_csd.cache_ctrl = enable;
+ }
}
}
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 9b9c1ed..90d9826 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -892,9 +892,12 @@
MMC_SEND_TUNING_BLOCK_HS200);
mmc_host_clk_release(card->host);
- if (err)
- pr_warn("%s: %s: tuning execution failed %d\n",
- mmc_hostname(card->host), __func__, err);
+ if (err) {
+ pr_warn("%s: %s: tuning execution failed %d. Restoring to previous clock %lu\n",
+ mmc_hostname(card->host), __func__, err,
+ host->clk_scaling.curr_freq);
+ mmc_set_clock(host, host->clk_scaling.curr_freq);
+ }
}
out:
mmc_release_host(host);
@@ -1576,9 +1579,7 @@
if (err)
goto out;
- if (mmc_can_poweroff_notify(host->card))
- err = mmc_poweroff_notify(host->card, EXT_CSD_POWER_OFF_SHORT);
- else if (mmc_card_can_sleep(host))
+ if (mmc_card_can_sleep(host))
err = mmc_card_sleep(host);
else if (!mmc_host_is_spi(host))
mmc_deselect_cards(host);
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 8087ea6..164c418 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -378,13 +378,13 @@
* @timeout_ms: timeout (ms) for operation performed by register write,
* timeout of zero implies maximum possible timeout
* @use_busy_signal: use the busy signal as response type
- * @bkops_busy: set this to indicate that we are starting blocking bkops
+ * @ignore_timeout: set this flag only for commands which can be HPIed
*
* Modifies the EXT_CSD register for selected card.
*/
int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
unsigned int timeout_ms, bool use_busy_signal,
- bool bkops_busy)
+ bool ignore_timeout)
{
int err;
struct mmc_command cmd = {0};
@@ -407,7 +407,7 @@
cmd.cmd_timeout_ms = timeout_ms;
- cmd.bkops_busy = bkops_busy;
+ cmd.ignore_timeout = ignore_timeout;
err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
if (err)
@@ -458,6 +458,13 @@
}
EXPORT_SYMBOL_GPL(mmc_switch);
+int mmc_switch_ignore_timeout(struct mmc_card *card, u8 set, u8 index, u8 value,
+ unsigned int timeout_ms)
+{
+ return __mmc_switch(card, set, index, value, timeout_ms, true, true);
+}
+EXPORT_SYMBOL(mmc_switch_ignore_timeout);
+
int mmc_send_status(struct mmc_card *card, u32 *status)
{
int err;
@@ -608,7 +615,7 @@
err = mmc_wait_for_cmd(card->host, &cmd, 0);
if (err) {
- pr_warn("%s: error %d interrupting operation. "
+ pr_debug("%s: error %d interrupting operation. "
"HPI command response %#x\n", mmc_hostname(card->host),
err, cmd.resp[0]);
return err;
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index ddf9a87..a4498d2 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -666,9 +666,12 @@
MMC_SEND_TUNING_BLOCK);
mmc_host_clk_release(card->host);
- if (err)
- pr_warn("%s: %s: tuning execution failed %d\n",
- mmc_hostname(card->host), __func__, err);
+ if (err) {
+ pr_warn("%s: %s: tuning execution failed %d. Restoring to previous clock %lu\n",
+ mmc_hostname(card->host), __func__, err,
+ host->clk_scaling.curr_freq);
+ mmc_set_clock(host, host->clk_scaling.curr_freq);
+ }
}
out:
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index e285bfa..89e3472 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -1656,6 +1656,13 @@
sg_miter_stop(&host->pio.sg_miter);
}
+static inline void msmsdcc_clear_pio_irq_mask(struct msmsdcc_host *host)
+{
+ writel_relaxed(readl_relaxed(host->base + MMCIMASK0) & ~MCI_IRQ_PIO,
+ host->base + MMCIMASK0);
+ mb();
+}
+
static irqreturn_t
msmsdcc_pio_irq(int irq, void *dev_id)
{
@@ -1668,7 +1675,7 @@
spin_lock(&host->lock);
- if (!atomic_read(&host->clks_on)) {
+ if (!atomic_read(&host->clks_on) || !host->curr.data) {
spin_unlock(&host->lock);
return IRQ_NONE;
}
@@ -1719,25 +1726,19 @@
msmsdcc_sg_stop(host);
local_irq_restore(flags);
+ if (!host->curr.xfer_remain) {
+ msmsdcc_clear_pio_irq_mask(host);
+ goto out_unlock;
+ }
+
if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
- (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
- host->base + MMCIMASK0);
- if (!host->curr.xfer_remain) {
- /*
- * back to back write to MASK0 register don't need
- * synchronization delay.
- */
- writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
- (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
- }
- mb();
- } else if (!host->curr.xfer_remain) {
- writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
- (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
+ ~MCI_IRQ_PIO) | MCI_RXDATAAVLBLMASK,
+ host->base + MMCIMASK0);
mb();
}
+out_unlock:
spin_unlock(&host->lock);
return IRQ_HANDLED;
@@ -1831,6 +1832,7 @@
msmsdcc_sps_exit_curr_xfer(host);
}
else if (host->curr.data) { /* Non DMA */
+ msmsdcc_clear_pio_irq_mask(host);
msmsdcc_reset_and_restore(host);
msmsdcc_stop_data(host);
msmsdcc_request_end(host, cmd->mrq);
@@ -2002,6 +2004,7 @@
/* Stop current SPS transfer */
msmsdcc_sps_exit_curr_xfer(host);
} else {
+ msmsdcc_clear_pio_irq_mask(host);
msmsdcc_reset_and_restore(host);
if (host->curr.data)
msmsdcc_stop_data(host);
@@ -4316,56 +4319,6 @@
return rc;
}
-/*
- * Work around of the unavailability of a power_reset functionality in SD cards
- * by turning the OFF & back ON the regulators supplying the SD card.
- */
-void msmsdcc_hw_reset(struct mmc_host *mmc)
-{
- struct mmc_card *card = mmc->card;
- struct msmsdcc_host *host = mmc_priv(mmc);
- int rc;
-
- /* Write-protection bits would be lost on a hardware reset in emmc */
- if (!card || !mmc_card_sd(card))
- return;
-
- pr_debug("%s: Starting h/w reset\n", mmc_hostname(host->mmc));
-
- if (host->plat->translate_vdd || host->plat->vreg_data) {
-
- /* Disable the regulators */
- if (host->plat->translate_vdd)
- rc = host->plat->translate_vdd(mmc_dev(mmc), 0);
- else if (host->plat->vreg_data)
- rc = msmsdcc_setup_vreg(host, false, false);
-
- if (rc) {
- pr_err("%s: Failed to disable voltage regulator\n",
- mmc_hostname(host->mmc));
- BUG_ON(rc);
- }
-
- /* 10ms delay for supply to reach the desired voltage level */
- usleep_range(10000, 12000);
-
- /* Enable the regulators */
- if (host->plat->translate_vdd)
- rc = host->plat->translate_vdd(mmc_dev(mmc), 1);
- else if (host->plat->vreg_data)
- rc = msmsdcc_setup_vreg(host, true, false);
-
- if (rc) {
- pr_err("%s: Failed to enable voltage regulator\n",
- mmc_hostname(host->mmc));
- BUG_ON(rc);
- }
-
- /* 10ms delay for supply to reach the desired voltage level */
- usleep_range(10000, 12000);
- }
-}
-
/**
* msmsdcc_stop_request - stops ongoing request
* @mmc: MMC host, running the request
@@ -4473,7 +4426,6 @@
.enable_sdio_irq = msmsdcc_enable_sdio_irq,
.start_signal_voltage_switch = msmsdcc_switch_io_voltage,
.execute_tuning = msmsdcc_execute_tuning,
- .hw_reset = msmsdcc_hw_reset,
.stop_request = msmsdcc_stop_request,
.get_xfer_remain = msmsdcc_get_xfer_remain,
.notify_load = msmsdcc_notify_load,
@@ -5361,7 +5313,7 @@
mrq = host->curr.mrq;
if (mrq && mrq->cmd) {
- if (!mrq->cmd->bkops_busy) {
+ if (!mrq->cmd->ignore_timeout) {
pr_info("%s: CMD%d: Request timeout\n",
mmc_hostname(host->mmc), mrq->cmd->opcode);
msmsdcc_dump_sdcc_state(host);
@@ -5380,6 +5332,7 @@
/* Stop current SPS transfer */
msmsdcc_sps_exit_curr_xfer(host);
} else {
+ msmsdcc_clear_pio_irq_mask(host);
msmsdcc_reset_and_restore(host);
msmsdcc_stop_data(host);
if (mrq->data && mrq->data->stop)
@@ -6112,6 +6065,10 @@
msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
+ /* Disable SDHCi mode if supported */
+ if (is_sdhci_supported(host))
+ writel_relaxed(0, (host->base + MCI_CORE_HC_MODE));
+
/* Apply Hard reset to SDCC to put it in power on default state */
msmsdcc_hard_reset(host);
@@ -6157,7 +6114,6 @@
mmc->caps |= plat->mmc_bus_width;
mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
- mmc->caps |= MMC_CAP_HW_RESET;
/*
* If we send the CMD23 before multi block write/read command
* then we need not to send CMD12 at the end of the transfer.
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index bcfde57..3668d75 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -197,6 +197,8 @@
#define MAX_TESTBUS 8
#define MCI_TESTBUS_ENA (1 << 3)
+#define MCI_CORE_HC_MODE 0x78
+
#define MCI_SDCC_DEBUG_REG 0x124
#define MCI_IRQENABLE \
@@ -456,6 +458,7 @@
#define MSMSDCC_SW_RST_CFG_BROKEN (1 << 11)
#define MSMSDCC_DATA_PEND_FOR_CMD53 (1 << 12)
#define MSMSDCC_TESTBUS_DEBUG (1 << 13)
+#define MSMSDCC_SDHCI_MODE_SUPPORTED (1 << 14)
#define set_hw_caps(h, val) ((h)->hw_caps |= val)
#define is_sps_mode(h) ((h)->hw_caps & MSMSDCC_SPS_BAM_SUP)
@@ -473,6 +476,7 @@
((h)->hw_caps & MSMSDCC_SW_RST_CFG_BROKEN)
#define is_data_pend_for_cmd53(h) ((h)->hw_caps & MSMSDCC_DATA_PEND_FOR_CMD53)
#define is_testbus_debug(h) ((h)->hw_caps & MSMSDCC_TESTBUS_DEBUG)
+#define is_sdhci_supported(h) ((h)->hw_caps & MSMSDCC_SDHCI_MODE_SUPPORTED)
/* Set controller capabilities based on version */
static inline void set_default_hw_caps(struct msmsdcc_host *host)
@@ -511,7 +515,8 @@
MSMSDCC_AUTO_CMD21 |
MSMSDCC_DATA_PEND_FOR_CMD53 |
MSMSDCC_TESTBUS_DEBUG |
- MSMSDCC_SW_RST_CFG_BROKEN;
+ MSMSDCC_SW_RST_CFG_BROKEN |
+ MSMSDCC_SDHCI_MODE_SUPPORTED;
}
int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave);
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 4ff8fea..3495f4d 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -89,6 +89,9 @@
#define CORE_TESTBUS_ENA (1 << 3)
#define CORE_TESTBUS_SEL2 (1 << 4)
+#define CORE_MCI_VERSION 0x050
+#define CORE_VERSION_310 0x10000011
+
/*
* Waiting until end of potential AHB access for data:
* 16 AHB cycles (160ns for 100MHz and 320ns for 50MHz) +
@@ -264,6 +267,7 @@
u32 curr_io_level;
struct completion pwr_irq_completion;
struct sdhci_msm_bus_vote msm_bus_vote;
+ struct device_attribute polling;
u32 clk_rate; /* Keeps track of current clock rate that is set */
};
@@ -593,6 +597,7 @@
int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)
{
unsigned long flags;
+ int tuning_seq_cnt = 3;
u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
const u32 *tuning_block_pattern = tuning_block_64;
int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
@@ -619,17 +624,18 @@
}
spin_unlock_irqrestore(&host->lock, flags);
- /* first of all reset the tuning block */
- rc = msm_init_cm_dll(host);
- if (rc)
- goto out;
-
data_buf = kmalloc(size, GFP_KERNEL);
if (!data_buf) {
rc = -ENOMEM;
goto out;
}
+retry:
+ /* first of all reset the tuning block */
+ rc = msm_init_cm_dll(host);
+ if (rc)
+ goto kfree;
+
phase = 0;
do {
struct mmc_command cmd = {0};
@@ -686,10 +692,12 @@
pr_debug("%s: %s: finally setting the tuning phase to %d\n",
mmc_hostname(mmc), __func__, phase);
} else {
+ if (--tuning_seq_cnt)
+ goto retry;
/* tuning failed */
pr_err("%s: %s: no tuning point found\n",
mmc_hostname(mmc), __func__);
- rc = -EAGAIN;
+ rc = -EIO;
}
kfree:
@@ -1838,6 +1846,42 @@
else
return 0;
}
+
+static ssize_t
+show_polling(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct sdhci_host *host = dev_get_drvdata(dev);
+ int poll;
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+ poll = !!(host->mmc->caps & MMC_CAP_NEEDS_POLL);
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", poll);
+}
+
+static ssize_t
+store_polling(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sdhci_host *host = dev_get_drvdata(dev);
+ int value;
+ unsigned long flags;
+
+ if (!kstrtou32(buf, 0, &value)) {
+ spin_lock_irqsave(&host->lock, flags);
+ if (value) {
+ host->mmc->caps |= MMC_CAP_NEEDS_POLL;
+ mmc_detect_change(host->mmc, 0);
+ } else {
+ host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
+ }
+ spin_unlock_irqrestore(&host->lock, flags);
+ }
+ return count;
+}
+
static ssize_t
show_sdhci_max_bus_bw(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -2129,6 +2173,12 @@
struct sdhci_msm_host *msm_host = pltfm_host->priv;
u32 value;
int ret;
+ u32 version;
+
+ version = readl_relaxed(msm_host->core_mem + CORE_MCI_VERSION);
+ /* Core version 3.1.0 doesn't need this workaround */
+ if (version == CORE_VERSION_310)
+ return;
value = readl_relaxed(msm_host->core_mem + CORE_MCI_DATA_CTRL);
value &= ~(u32)CORE_MCI_DPSM_ENABLE;
@@ -2410,7 +2460,6 @@
MMC_CAP_SET_XPC_300|
MMC_CAP_SET_XPC_330;
- msm_host->mmc->caps |= MMC_CAP_HW_RESET;
msm_host->mmc->caps2 |= msm_host->pdata->caps2;
msm_host->mmc->caps2 |= MMC_CAP2_CORE_RUNTIME_PM;
msm_host->mmc->caps2 |= MMC_CAP2_PACKED_WR;
@@ -2464,6 +2513,16 @@
if (ret)
goto remove_host;
+ if (!gpio_is_valid(msm_host->pdata->status_gpio)) {
+ msm_host->polling.show = show_polling;
+ msm_host->polling.store = store_polling;
+ sysfs_attr_init(&msm_host->polling.attr);
+ msm_host->polling.attr.name = "polling";
+ msm_host->polling.attr.mode = S_IRUGO | S_IWUSR;
+ ret = device_create_file(&pdev->dev, &msm_host->polling);
+ if (ret)
+ goto remove_max_bus_bw_file;
+ }
ret = pm_runtime_set_active(&pdev->dev);
if (ret)
pr_err("%s: %s: pm_runtime_set_active failed: err: %d\n",
@@ -2474,6 +2533,8 @@
/* Successful initialization */
goto out;
+remove_max_bus_bw_file:
+ device_remove_file(&pdev->dev, &msm_host->msm_bus_vote.max_bus_bw);
remove_host:
dead = (readl_relaxed(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
sdhci_remove_host(host, dead);
@@ -2512,6 +2573,8 @@
0xffffffff);
pr_debug("%s: %s\n", dev_name(&pdev->dev), __func__);
+ if (!gpio_is_valid(msm_host->pdata->status_gpio))
+ device_remove_file(&pdev->dev, &msm_host->polling);
device_remove_file(&pdev->dev, &msm_host->msm_bus_vote.max_bus_bw);
sdhci_remove_host(host, dead);
pm_runtime_disable(&pdev->dev);
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index ce1c536..578cc14 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -130,6 +130,33 @@
pr_info(DRIVER_NAME ": ===========================================\n");
}
+#define MAX_PM_QOS_TIMEOUT_VALUE 100000 /* 100 ms */
+static ssize_t
+show_sdhci_pm_qos_tout(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sdhci_host *host = dev_get_drvdata(dev);
+
+ return snprintf(buf, PAGE_SIZE, "%d us\n", host->pm_qos_timeout_us);
+}
+
+static ssize_t
+store_sdhci_pm_qos_tout(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sdhci_host *host = dev_get_drvdata(dev);
+ uint32_t value;
+ unsigned long flags;
+
+ if (!kstrtou32(buf, 0, &value)) {
+ spin_lock_irqsave(&host->lock, flags);
+ if (value <= MAX_PM_QOS_TIMEOUT_VALUE)
+ host->pm_qos_timeout_us = value;
+ spin_unlock_irqrestore(&host->lock, flags);
+ }
+ return count;
+}
+
/*****************************************************************************\
* *
* Low level functions *
@@ -1361,15 +1388,55 @@
{
struct sdhci_host *host = mmc_priv(mmc);
- if (host->cpu_dma_latency_us)
- pm_qos_update_request(&host->pm_qos_req_dma,
+ if (host->cpu_dma_latency_us) {
+ /*
+ * In performance mode, release QoS vote after a timeout to
+ * make sure back-to-back requests don't suffer from latencies
+ * that are involved to wake CPU from low power modes in cases
+ * where the CPU goes into low power mode as soon as QoS vote is
+ * released.
+ */
+ if (host->power_policy == SDHCI_PERFORMANCE_MODE)
+ pm_qos_update_request_timeout(&host->pm_qos_req_dma,
+ host->cpu_dma_latency_us,
+ host->pm_qos_timeout_us);
+ else
+ pm_qos_update_request(&host->pm_qos_req_dma,
PM_QOS_DEFAULT_VALUE);
+ }
+
if (host->ops->platform_bus_voting)
host->ops->platform_bus_voting(host, 0);
return 0;
}
+static inline void sdhci_update_power_policy(struct sdhci_host *host,
+ enum sdhci_power_policy policy)
+{
+ host->power_policy = policy;
+}
+
+static int sdhci_notify_load(struct mmc_host *mmc, enum mmc_load state)
+{
+ int err = 0;
+ struct sdhci_host *host = mmc_priv(mmc);
+
+ switch (state) {
+ case MMC_LOAD_HIGH:
+ sdhci_update_power_policy(host, SDHCI_PERFORMANCE_MODE);
+ break;
+ case MMC_LOAD_LOW:
+ sdhci_update_power_policy(host, SDHCI_POWER_SAVE_MODE);
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+
+ return err;
+}
+
static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
bool is_first_req)
{
@@ -1496,9 +1563,11 @@
int vdd_bit = -1;
u8 ctrl;
+ mutex_lock(&host->ios_mutex);
if (host->flags & SDHCI_DEVICE_DEAD) {
if (host->vmmc && ios->power_mode == MMC_POWER_OFF)
mmc_regulator_set_ocr(host->mmc, host->vmmc, 0);
+ mutex_unlock(&host->ios_mutex);
return;
}
@@ -1508,6 +1577,7 @@
spin_lock_irqsave(&host->lock, flags);
if (!host->clock) {
spin_unlock_irqrestore(&host->lock, flags);
+ mutex_unlock(&host->ios_mutex);
return;
}
spin_unlock_irqrestore(&host->lock, flags);
@@ -1664,6 +1734,7 @@
sdhci_set_clock(host, ios->clock);
mmiowb();
+ mutex_unlock(&host->ios_mutex);
}
static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
@@ -1932,7 +2003,7 @@
if (host->ops->execute_tuning) {
spin_unlock(&host->lock);
enable_irq(host->irq);
- host->ops->execute_tuning(host, opcode);
+ err = host->ops->execute_tuning(host, opcode);
disable_irq(host->irq);
spin_lock(&host->lock);
goto out;
@@ -2196,6 +2267,7 @@
.disable = sdhci_disable,
.stop_request = sdhci_stop_request,
.get_xfer_remain = sdhci_get_xfer_remain,
+ .notify_load = sdhci_notify_load,
};
/*****************************************************************************\
@@ -2312,9 +2384,11 @@
spin_lock_irqsave(&host->lock, flags);
if (host->mrq) {
- pr_err("%s: Timeout waiting for hardware "
- "interrupt.\n", mmc_hostname(host->mmc));
- sdhci_dumpregs(host);
+ if (!host->mrq->cmd->ignore_timeout) {
+ pr_err("%s: Timeout waiting for hardware interrupt.\n",
+ mmc_hostname(host->mmc));
+ sdhci_dumpregs(host);
+ }
if (host->data) {
pr_info("%s: bytes to transfer: %d transferred: %d\n",
@@ -2898,6 +2972,7 @@
host->mmc = mmc;
spin_lock_init(&host->lock);
+ mutex_init(&host->ios_mutex);
return host;
}
@@ -3353,9 +3428,22 @@
mmiowb();
- if (host->cpu_dma_latency_us)
+ if (host->cpu_dma_latency_us) {
+ host->pm_qos_timeout_us = 10000; /* default value */
pm_qos_add_request(&host->pm_qos_req_dma,
PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
+
+ host->pm_qos_tout.show = show_sdhci_pm_qos_tout;
+ host->pm_qos_tout.store = store_sdhci_pm_qos_tout;
+ sysfs_attr_init(&host->pm_qos_tout.attr);
+ host->pm_qos_tout.attr.name = "pm_qos_unvote_delay";
+ host->pm_qos_tout.attr.mode = S_IRUGO | S_IWUSR;
+ ret = device_create_file(mmc_dev(mmc), &host->pm_qos_tout);
+ if (ret)
+ pr_err("%s: cannot create pm_qos_unvote_delay %d\n",
+ mmc_hostname(mmc), ret);
+ }
+
mmc_add_host(mmc);
pr_info("%s: SDHCI controller on %s [%s] using %s\n",
diff --git a/drivers/mtd/devices/msm_qpic_nand.c b/drivers/mtd/devices/msm_qpic_nand.c
index efa09f6..7f02187 100644
--- a/drivers/mtd/devices/msm_qpic_nand.c
+++ b/drivers/mtd/devices/msm_qpic_nand.c
@@ -694,7 +694,7 @@
dma_addr_t dma_addr_param_info = 0;
struct onfi_param_page *onfi_param_page_ptr;
struct msm_nand_flash_onfi_data data;
- uint32_t onfi_signature;
+ uint32_t onfi_signature = 0;
/* SPS command/data descriptors */
uint32_t total_cnt = 13;
@@ -2229,7 +2229,8 @@
return err;
}
-#define BAM_APPS_PIPE_LOCK_GRP 0
+#define BAM_APPS_PIPE_LOCK_GRP0 0
+#define BAM_APPS_PIPE_LOCK_GRP1 1
/*
* This function allocates, configures, connects an end point and
* also registers event notification for an end point. It also allocates
@@ -2273,7 +2274,13 @@
}
sps_config->options = SPS_O_AUTO_ENABLE | SPS_O_DESC_DONE;
- sps_config->lock_group = BAM_APPS_PIPE_LOCK_GRP;
+
+ if (pipe_index == SPS_DATA_PROD_PIPE_INDEX ||
+ pipe_index == SPS_DATA_CONS_PIPE_INDEX)
+ sps_config->lock_group = BAM_APPS_PIPE_LOCK_GRP0;
+ else if (pipe_index == SPS_CMD_CONS_PIPE_INDEX)
+ sps_config->lock_group = BAM_APPS_PIPE_LOCK_GRP1;
+
/*
* Descriptor FIFO is a cyclic FIFO. If SPS_MAX_DESC_NUM descriptors
* are allowed to be submitted before we get any ack for any of them,
diff --git a/drivers/net/ethernet/msm/msm_rmnet_wwan.c b/drivers/net/ethernet/msm/msm_rmnet_wwan.c
index 3e4605f..b857ee3 100644
--- a/drivers/net/ethernet/msm/msm_rmnet_wwan.c
+++ b/drivers/net/ethernet/msm/msm_rmnet_wwan.c
@@ -188,9 +188,14 @@
__func__, skb);
netif_wake_queue(dev);
}
- if (a2_mux_is_ch_empty(a2_mux_lcid_by_ch_id[wwan_ptr->ch_id]))
- ipa_rm_inactivity_timer_release_resource(
- ipa_rm_resource_by_ch_id[wwan_ptr->ch_id]);
+ if (a2_mux_is_ch_empty(a2_mux_lcid_by_ch_id[wwan_ptr->ch_id])) {
+ if (ipa_emb_ul_pipes_empty())
+ ipa_rm_inactivity_timer_release_resource(
+ ipa_rm_resource_by_ch_id[wwan_ptr->ch_id]);
+ else
+ pr_err("%s: ch=%d empty but UL desc FIFOs not empty\n",
+ __func__, wwan_ptr->ch_id);
+ }
spin_unlock_irqrestore(&wwan_ptr->lock, flags);
}
diff --git a/drivers/net/usb/rmnet_usb_ctrl.c b/drivers/net/usb/rmnet_usb_ctrl.c
index 0772592..d1f3748 100644
--- a/drivers/net/usb/rmnet_usb_ctrl.c
+++ b/drivers/net/usb/rmnet_usb_ctrl.c
@@ -200,8 +200,10 @@
dev->get_encap_failure_cnt++;
usb_unanchor_urb(dev->rcvurb);
usb_autopm_put_interface(dev->intf);
- dev_err(dev->devicep,
- "%s: Error submitting Read URB %d\n", __func__, status);
+ if (status != -ENODEV)
+ dev_err(dev->devicep,
+ "%s: Error submitting Read URB %d\n",
+ __func__, status);
goto resubmit_int_urb;
}
@@ -214,7 +216,9 @@
status = usb_submit_urb(dev->inturb, GFP_KERNEL);
if (status) {
usb_unanchor_urb(dev->inturb);
- dev_err(dev->devicep, "%s: Error re-submitting Int URB %d\n",
+ if (status != -ENODEV)
+ dev_err(dev->devicep,
+ "%s: Error re-submitting Int URB %d\n",
__func__, status);
}
}
@@ -286,8 +290,10 @@
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status) {
usb_unanchor_urb(urb);
- dev_err(dev->devicep, "%s: Error re-submitting Int URB %d\n",
- __func__, status);
+ if (status != -ENODEV)
+ dev_err(dev->devicep,
+ "%s: Error re-submitting Int URB %d\n",
+ __func__, status);
}
return;
@@ -383,7 +389,9 @@
status = usb_submit_urb(dev->inturb, GFP_ATOMIC);
if (status) {
usb_unanchor_urb(dev->inturb);
- dev_err(dev->devicep, "%s: Error re-submitting Int URB %d\n",
+ if (status != -ENODEV)
+ dev_err(dev->devicep,
+ "%s: Error re-submitting Int URB %d\n",
__func__, status);
}
}
@@ -397,8 +405,9 @@
retval = usb_submit_urb(dev->inturb, GFP_KERNEL);
if (retval < 0) {
usb_unanchor_urb(dev->inturb);
- dev_err(dev->devicep, "%s Intr submit %d\n", __func__,
- retval);
+ if (retval != -ENODEV)
+ dev_err(dev->devicep,
+ "%s Intr submit %d\n", __func__, retval);
}
return retval;
@@ -527,7 +536,9 @@
dev->snd_encap_cmd_cnt++;
result = usb_submit_urb(sndurb, GFP_KERNEL);
if (result < 0) {
- dev_err(dev->devicep, "%s: Submit URB error %d\n",
+ if (result != -ENODEV)
+ dev_err(dev->devicep,
+ "%s: Submit URB error %d\n",
__func__, result);
dev->snd_encap_cmd_cnt--;
usb_autopm_put_interface(dev->intf);
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 5e22c35..657fc2f 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -115,6 +115,9 @@
#define MSM_PRONTO_SAW2_BASE 0xfb219000
#define PRONTO_SAW2_SPM_STS_OFFSET 0x0c
+#define MSM_PRONTO_PLL_BASE 0xfb21b1c0
+#define PRONTO_PLL_STATUS_OFFSET 0x1c
+
#define WCNSS_DEF_WLAN_RX_BUFF_COUNT 1024
#define WCNSS_CTRL_CHANNEL "WCNSS_CTRL"
@@ -292,6 +295,7 @@
void __iomem *pronto_a2xb_base;
void __iomem *pronto_ccpu_base;
void __iomem *pronto_saw2_base;
+ void __iomem *pronto_pll_base;
void __iomem *fiq_reg;
int ssr_boot;
int nv_downloaded;
@@ -487,6 +491,10 @@
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);
+
tst_addr = penv->pronto_a2xb_base + A2XB_TSTBUS_OFFSET;
tst_ctrl_addr = penv->pronto_a2xb_base + A2XB_TSTBUS_CTRL_OFFSET;
@@ -1699,6 +1707,15 @@
ret = -ENOMEM;
goto fail_ioremap5;
}
+ penv->pronto_pll_base = ioremap_nocache(MSM_PRONTO_PLL_BASE,
+ SZ_64);
+ if (!penv->pronto_pll_base) {
+ pr_err("%s: ioremap wcnss physical(pll) failed\n",
+ __func__);
+ ret = -ENOMEM;
+ goto fail_ioremap6;
+ }
+
}
/* trigger initialization of the WCNSS */
@@ -1715,6 +1732,9 @@
fail_pil:
if (penv->riva_ccu_base)
iounmap(penv->riva_ccu_base);
+ if (penv->pronto_pll_base)
+ iounmap(penv->pronto_pll_base);
+fail_ioremap6:
if (penv->pronto_saw2_base)
iounmap(penv->pronto_saw2_base);
fail_ioremap5:
diff --git a/drivers/nfc/nfc-nci.c b/drivers/nfc/nfc-nci.c
index 9e9a4ea..e832716 100644
--- a/drivers/nfc/nfc-nci.c
+++ b/drivers/nfc/nfc-nci.c
@@ -27,7 +27,6 @@
#include <linux/regulator/consumer.h>
#include "nfc-nci.h"
-
struct qca199x_platform_data {
unsigned int irq_gpio;
unsigned int dis_gpio;
@@ -62,6 +61,7 @@
bool irq_enabled;
spinlock_t irq_enabled_lock;
unsigned int count_irq;
+ enum nfcc_state state;
};
/*
@@ -69,6 +69,12 @@
* IOCTL NFC_KERNEL_LOGGING_MODE.
*/
static int logging_level;
+/*
+ * FTM-RAW-I2C RD/WR MODE
+ */
+static struct devicemode device_mode;
+static int ftm_raw_write_mode;
+static int ftm_werr_code;
static void qca199x_init_stat(struct qca199x_dev *qca199x_dev)
{
@@ -104,7 +110,6 @@
struct qca199x_dev *qca199x_dev = dev_id;
unsigned long flags;
-
spin_lock_irqsave(&qca199x_dev->irq_enabled_lock, flags);
qca199x_dev->count_irq++;
spin_unlock_irqrestore(&qca199x_dev->irq_enabled_lock, flags);
@@ -119,7 +124,6 @@
unsigned int mask = 0;
unsigned long flags;
-
poll_wait(filp, &qca199x_dev->read_wq, wait);
spin_lock_irqsave(&qca199x_dev->irq_enabled_lock, flags);
@@ -129,17 +133,33 @@
}
spin_unlock_irqrestore(&qca199x_dev->irq_enabled_lock, flags);
-
return mask;
}
+/*
+ * ONLY for FTM-RAW-I2C Mode
+ * Required to instigate a read, which comes from DT layer. This means we need
+ * to spoof an interrupt and send a wake up event.
+ */
+void ftm_raw_trigger_read(struct qca199x_dev *qca199x_dev)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&qca199x_dev->irq_enabled_lock, flags);
+ qca199x_dev->count_irq++;
+ spin_unlock_irqrestore(&qca199x_dev->irq_enabled_lock, flags);
+ wake_up(&qca199x_dev->read_wq);
+}
+
static ssize_t nfc_read(struct file *filp, char __user *buf,
size_t count, loff_t *offset)
{
struct qca199x_dev *qca199x_dev = filp->private_data;
- unsigned char tmp[MAX_BUFFER_SIZE];
+ unsigned char tmp[MAX_BUFFER_SIZE], rd_byte;
unsigned char len[PAYLOAD_HEADER_LENGTH];
int total, length, ret;
+ int ftm_rerr_code;
+ enum ehandler_mode dmode;
total = 0;
length = 0;
@@ -147,6 +167,36 @@
count = MAX_BUFFER_SIZE;
mutex_lock(&qca199x_dev->read_mutex);
+ dmode = device_mode.handle_flavour;
+ /* FTM-RAW-I2C RD/WR MODE - Special Case */
+ if ((dmode == UNSOLICITED_FTM_RAW_MODE) ||
+ (dmode == SOLICITED_FTM_RAW_MODE)) {
+ /* READ */
+ if ((ftm_raw_write_mode == 0) && (ftm_werr_code == 0)) {
+ ftm_rerr_code = i2c_master_recv(qca199x_dev->client,
+ &rd_byte, 1);
+ if (ftm_rerr_code == 0x1)
+ ftm_rerr_code = 0;
+ tmp[0] = (unsigned char)ftm_rerr_code;
+ tmp[1] = rd_byte;
+ total = 2;
+ ret = copy_to_user(buf, tmp, total);
+ }
+ /* WRITE */
+ else if ((ftm_raw_write_mode == 1) || (ftm_werr_code != 0)) {
+ tmp[0] = (unsigned char)ftm_werr_code;
+ total = 1;
+ ret = copy_to_user(buf, tmp, total);
+ } else {
+ /* Invalid case */
+ total = 0;
+ ret = copy_to_user(buf, tmp, total);
+ }
+ mutex_unlock(&qca199x_dev->read_mutex);
+ goto done;
+ }
+
+ /* NORMAL NCI Behaviour */
/* Read the header */
ret = i2c_master_recv(qca199x_dev->client, len, PAYLOAD_HEADER_LENGTH);
if (ret != PAYLOAD_HEADER_LENGTH)
@@ -174,7 +224,7 @@
err:
if (ret < 0)
mutex_unlock(&qca199x_dev->read_mutex);
-
+done:
return total;
}
@@ -183,7 +233,8 @@
{
struct qca199x_dev *qca199x_dev = filp->private_data;
char tmp[MAX_BUFFER_SIZE];
- int ret;
+ int ret = 0;
+ enum ehandler_mode dmode;
if (count > MAX_BUFFER_SIZE) {
dev_err(&qca199x_dev->client->dev, "out of memory\n");
@@ -195,10 +246,39 @@
return -EFAULT;
}
mutex_lock(&qca199x_dev->read_mutex);
- ret = i2c_master_send(qca199x_dev->client, tmp, count);
+ dmode = device_mode.handle_flavour;
+ /* FTM-DIRECT-I2C RD/WR MODE */
+ /* This is a special FTM-i2c mode case,where tester is not using NCI */
+ if ((dmode == UNSOLICITED_FTM_RAW_MODE) ||
+ (dmode == SOLICITED_FTM_RAW_MODE)) {
+ /* Read From Register */
+ if (count == 1) {
+ ftm_raw_write_mode = 0;
+ ret = i2c_master_send(qca199x_dev->client, tmp, count);
+ if (ret == 1)
+ ftm_werr_code = 0;
+ else
+ ftm_werr_code = ret;
+ ftm_raw_trigger_read(qca199x_dev);
+ }
+ /* Write to Register */
+ if (count == 2) {
+ ftm_raw_write_mode = 1;
+ ret = i2c_master_send(qca199x_dev->client, tmp, count);
+ if (ret == 2)
+ ftm_werr_code = 0;
+ else
+ ftm_werr_code = ret;
+ ftm_raw_trigger_read(qca199x_dev);
+ }
+ } else {
+ /* NORMAL NCI behaviour - NB :
+ We can be in FTM mode here also */
+ ret = i2c_master_send(qca199x_dev->client, tmp, count);
+ }
if (ret != count) {
dev_err(&qca199x_dev->client->dev,
- "NFC: failed to write %d\n", ret);
+ "NFC: failed to write %d\n", ret);
ret = -EIO;
}
mutex_unlock(&qca199x_dev->read_mutex);
@@ -225,7 +305,7 @@
/*
* Wake/Sleep Mode
*/
-int nfcc_wake(int level, struct nfc_info *info)
+int nfcc_wake(int level, struct file *filp)
{
int r = 0;
unsigned char raw_nci_sleep[] = {0x2F, 0x03, 0x00};
@@ -233,32 +313,32 @@
unsigned char raw_nci_wake[] = {0x10, 0x0F};
unsigned short slave_addr = 0xE;
unsigned short curr_addr;
+ struct qca199x_dev *qca199x_dev = filp->private_data;
- struct i2c_client *client = info->i2c_dev;
-
- dev_dbg(&client->dev, "nfcc_wake: %s: info: %p\n", __func__, info);
+ dev_dbg(&qca199x_dev->client->dev, "nfcc_wake: %s: info: %p\n",
+ __func__, qca199x_dev);
if (level == NFCC_SLEEP) {
- r = nfc_i2c_write(client, &raw_nci_sleep[0],
+ r = i2c_master_send(qca199x_dev->client, &raw_nci_sleep[0],
sizeof(raw_nci_sleep));
+ r = sizeof(raw_nci_sleep);
if (r != sizeof(raw_nci_sleep))
return -EMSGSIZE;
- info->state = NFCC_STATE_NORMAL_SLEEP;
+ qca199x_dev->state = NFCC_STATE_NORMAL_SLEEP;
} else {
- curr_addr = client->addr;
- client->addr = slave_addr;
- r = nfc_i2c_write(client, &raw_nci_wake[0],
+ curr_addr = qca199x_dev->client->addr;
+ qca199x_dev->client->addr = slave_addr;
+ r = nfc_i2c_write(qca199x_dev->client, &raw_nci_wake[0],
sizeof(raw_nci_wake));
/* Restore original NFCC slave I2C address */
- client->addr = curr_addr;
-
- if (r != sizeof(raw_nci_sleep))
+ qca199x_dev->client->addr = curr_addr;
+ r = sizeof(raw_nci_wake);
+ if (r != sizeof(raw_nci_wake))
return -EMSGSIZE;
-
- info->state = NFCC_STATE_NORMAL_WAKE;
+ qca199x_dev->state = NFCC_STATE_NORMAL_WAKE;
}
- msleep(20);
+
return r;
}
@@ -284,41 +364,35 @@
{
int r = 0;
struct qca199x_dev *qca199x_dev = filp->private_data;
- struct nfc_info *info = container_of(filp->private_data,
- struct nfc_info, miscdev);
-
- struct i2c_client *client = info->i2c_dev;
-
- r = gpio_request(qca199x_dev->dis_gpio, "nfc_reset_gpio");
- if (r) {
- dev_err(&client->dev, "unable to request gpio [%d]\n",
- qca199x_dev->dis_gpio);
- goto err_req;
- }
- gpio_set_value(qca199x_dev->dis_gpio, 0);
- r = gpio_direction_output(qca199x_dev->dis_gpio, 1);
- if (r) {
- dev_err(&client->dev, "unable to set direction for gpio [%d]\n",
- qca199x_dev->irq_gpio);
- goto err_req;
- }
if (arg == 0) {
gpio_set_value(qca199x_dev->dis_gpio, 0);
- msleep(20);
+ r = gpio_direction_output(qca199x_dev->dis_gpio, 1);
+ if (r) {
+ dev_err(&qca199x_dev->client->dev,
+ "unable to set direction for gpio [%d]\n",
+ qca199x_dev->dis_gpio);
+ goto err_req;
+ }
+ gpio_set_value(qca199x_dev->dis_gpio, 0);
} else if (arg == 1) {
+ gpio_set_value(qca199x_dev->dis_gpio, 0);
+ r = gpio_direction_output(qca199x_dev->dis_gpio, 1);
+ if (r) {
+ dev_err(&qca199x_dev->client->dev,
+ "unable to set direction for gpio [%d]\n",
+ qca199x_dev->dis_gpio);
+ goto err_req;
+ }
gpio_set_value(qca199x_dev->dis_gpio, 1);
- msleep(20);
} else if (arg == 2) {
msleep(20);
} else if (arg == 3) {
msleep(20);
} else if (arg == 4) {
- nfcc_wake(NFCC_WAKE, info);
- msleep(20);
+ nfcc_wake(NFCC_WAKE, filp);
} else if (arg == 5) {
- nfcc_wake(NFCC_SLEEP, info);
- msleep(20);
+ nfcc_wake(NFCC_SLEEP, filp);
} else {
r = -ENOIOCTLCMD;
}
@@ -327,6 +401,63 @@
return r;
}
+
+/*
+ * Inside nfc_ioctl_nfcc_mode
+ *
+ * @brief nfc_ioctl_nfcc_mode
+ *
+ * (arg = 0) ; NORMAL_MODE - Standard mode, unsolicited read behaviour
+ * (arg = 1) ; SOLICITED_MODE - As above but reads are solicited from User Land
+ * (arg = 2) ; UNSOLICITED_FTM_RAW MODE - NORMAL_MODE but messages from FTM and
+ * not NCI Host.
+ * (arg = 2) ; SOLICITED_FTM_RAW_MODE - As SOLICITED_MODE but messages from FTM
+ * and not NCI Host.
+ *
+ *
+ *
+ */
+int nfc_ioctl_nfcc_mode(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+
+ static unsigned short nci_addr;
+ struct qca199x_dev *qca199x_dev = filp->private_data;
+ struct qca199x_platform_data *platform_data;
+
+ platform_data = qca199x_dev->client->dev.platform_data;
+
+ if (arg == 0) {
+ device_mode.handle_flavour = UNSOLICITED_MODE;
+ qca199x_dev->client->addr = NCI_I2C_SLAVE;
+ /* enable interrupts again */
+ qca199x_enable_irq(qca199x_dev);
+ } else if (arg == 1) {
+ device_mode.handle_flavour = SOLICITED_MODE;
+ qca199x_dev->client->addr = qca199x_dev->client->addr;
+ /* enable interrupts again */
+ qca199x_enable_irq(qca199x_dev);
+ } else if (arg == 2) {
+ device_mode.handle_flavour = UNSOLICITED_FTM_RAW_MODE;
+ nci_addr = qca199x_dev->client->addr;
+ /* replace with new client slave address*/
+ qca199x_dev->client->addr = 0xE;
+ /* We also need to disable interrupts */
+ qca199x_disable_irq(qca199x_dev);
+ } else if (arg == 3) {
+ device_mode.handle_flavour = SOLICITED_FTM_RAW_MODE;
+ nci_addr = qca199x_dev->client->addr;
+ /* replace with new client slave address*/
+ qca199x_dev->client->addr = 0xE;
+ /* We also need to disable interrupts */
+ qca199x_disable_irq(qca199x_dev);
+ } else {
+ device_mode.handle_flavour = UNSOLICITED_MODE;
+ qca199x_dev->client->addr = NCI_I2C_SLAVE;
+ }
+ return retval;
+}
+
/*
* Inside nfc_ioctl_kernel_logging
*
@@ -371,6 +502,7 @@
nfc_ioctl_power_states(pfile, cmd, arg);
break;
case NFCC_MODE:
+ nfc_ioctl_nfcc_mode(pfile, cmd, arg);
break;
case NFC_KERNEL_LOGGING_MODE:
nfc_ioctl_kernel_logging(arg, pfile);
@@ -447,66 +579,75 @@
unsigned char raw_s73[] = {0x73, 0x02};
unsigned char raw_slave1_rd = {0x0};
unsigned char raw_1P8_PAD_CFG_CLK_REQ[] = {0xA5, 0x1};
- unsigned char buf[4];
+ unsigned char raw_1P8_PAD_CFG_PWR_REQ[] = {0xA7, 0x1};
+ unsigned char buf = 0;
- /* Set I2C address to enable configuration of QCA1990 */
client->addr = curr_addr;
- RAW(s73, 0x02);
+ r = i2c_master_send(client, &buf, 1);
+ buf = 0;
+ r = i2c_master_recv(client, &buf, 1);
+ if (0x10 != (0x10 & buf)) {
+ RAW(s73, 0x02);
- r = nfc_i2c_write(client, &raw_s73[0], sizeof(raw_s73));
- usleep(1000);
- RAW(1p8_CONTROL_011, XTAL_CLOCK | 0x01);
+ r = nfc_i2c_write(client, &raw_s73[0], sizeof(raw_s73));
+ usleep(1000);
+ RAW(1p8_CONTROL_011, XTAL_CLOCK | 0x01);
- r = nfc_i2c_write(client, &raw_1p8_CONTROL_011[0],
+ r = nfc_i2c_write(client, &raw_1p8_CONTROL_011[0],
sizeof(raw_1p8_CONTROL_011));
- usleep(1000);
- RAW(1P8_CONTROL_010, (0x8));
- r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
- sizeof(raw_1P8_CONTROL_010));
-
- usleep(10000); /* 10ms wait */
- RAW(1P8_CONTROL_010, (0xC));
- r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
- sizeof(raw_1P8_CONTROL_010));
- usleep(100); /* 100uS wait */
- RAW(1P8_X0_0B0, (FREQ_SEL_19));
- r = nfc_i2c_write(client, &raw_1P8_X0_0B0[0], sizeof(raw_1P8_X0_0B0));
- usleep(1000);
-
- /* PWR_EN = 1 */
- RAW(1P8_CONTROL_010, (0xd));
- r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
+ usleep(1000);
+ RAW(1P8_CONTROL_010, (0x8));
+ r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
sizeof(raw_1P8_CONTROL_010));
- usleep(20000); /* 20ms wait */
- /* LS_EN = 1 */
- RAW(1P8_CONTROL_010, 0xF);
- r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
- sizeof(raw_1P8_CONTROL_010));
- usleep(20000); /* 20ms wait */
- /* Enable the PMIC clock */
- RAW(1P8_PAD_CFG_CLK_REQ, (0x1));
- r = nfc_i2c_write(client, &raw_1P8_PAD_CFG_CLK_REQ[0],
+ usleep(10000); /* 10ms wait */
+ RAW(1P8_CONTROL_010, (0xC));
+ r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
+ sizeof(raw_1P8_CONTROL_010));
+ usleep(100); /* 100uS wait */
+ RAW(1P8_X0_0B0, (FREQ_SEL_19));
+ r = nfc_i2c_write(client, &raw_1P8_X0_0B0[0],
+ sizeof(raw_1P8_X0_0B0));
+ usleep(1000);
+
+ /* PWR_EN = 1 */
+ RAW(1P8_CONTROL_010, (0xd));
+ r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
+ sizeof(raw_1P8_CONTROL_010));
+ usleep(20000); /* 20ms wait */
+ /* LS_EN = 1 */
+ RAW(1P8_CONTROL_010, 0xF);
+ r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
+ sizeof(raw_1P8_CONTROL_010));
+ usleep(20000); /* 20ms wait */
+
+ /* Enable the PMIC clock */
+ RAW(1P8_PAD_CFG_CLK_REQ, (0x1));
+ r = nfc_i2c_write(client, &raw_1P8_PAD_CFG_CLK_REQ[0],
sizeof(raw_1P8_PAD_CFG_CLK_REQ));
- usleep(1000);
+ usleep(1000);
- RAW(slave2, 0x10);
- r = nfc_i2c_write(client, &raw_slave2[0], sizeof(raw_slave2));
- usleep(1000);
- {
- r = i2c_master_send(client, buf, 1);
- memset(buf, 0xAA, sizeof(buf));
- r = i2c_master_recv(client, buf, 1);
+ RAW(1P8_PAD_CFG_PWR_REQ, (0x1));
+ r = nfc_i2c_write(client, &raw_1P8_PAD_CFG_PWR_REQ[0],
+ sizeof(raw_1P8_PAD_CFG_PWR_REQ));
+ usleep(1000);
+
+ RAW(slave2, 0x10);
+ r = nfc_i2c_write(client, &raw_slave2[0], sizeof(raw_slave2));
+ usleep(1000);
+
+ RAW(slave1, NCI_I2C_SLAVE);
+ r = nfc_i2c_write(client, &raw_slave1[0], sizeof(raw_slave1));
+ usleep(1000);
+
+ /* QCA199x NFCC CPU should now boot... */
+ r = i2c_master_recv(client, &raw_slave1_rd, 1);
+ /* Talk on NCI slave address NCI_I2C_SLAVE 0x2C*/
+ client->addr = NCI_I2C_SLAVE;
+ r = 0;
+ } else {
+ r = 1;
}
- RAW(slave1, NCI_I2C_SLAVE);
- r = nfc_i2c_write(client, &raw_slave1[0], sizeof(raw_slave1));
- usleep(1000);
-
- /* QCA199x NFCC CPU should now boot... */
- r = i2c_master_recv(client, &raw_slave1_rd, 1);
- /* Talk on NCI slave address NCI_I2C_SLAVE 0x2C*/
- client->addr = NCI_I2C_SLAVE;
-
return r;
}
@@ -623,6 +764,9 @@
dev_err(&client->dev, "dis gpio not provided\n");
goto err_irq;
}
+ gpio_set_value(qca199x_dev->dis_gpio, 1);
+ msleep(20);
+ gpio_set_value(qca199x_dev->dis_gpio, 0);
nfc_clk = clk_get(&client->dev, "ref_clk");
@@ -640,7 +784,7 @@
r = gpio_request(platform_data->ven_gpio, "nfc_ven_gpio");
if (r) {
dev_err(&client->dev, "unable to request gpio [%d]\n",
- platform_data->irq_gpio);
+ platform_data->ven_gpio);
goto err_ven_gpio;
}
r = gpio_direction_input(platform_data->ven_gpio);
@@ -648,7 +792,7 @@
dev_err(&client->dev,
"unable to set direction for gpio [%d]\n",
- platform_data->irq_gpio);
+ platform_data->ven_gpio);
goto err_ven_gpio;
}
@@ -681,7 +825,12 @@
/* request irq. The irq is set whenever the chip has data available
* for reading. It is cleared when all data has been read.
*/
- nfcc_initialise(client, platform_data->reg);
+ device_mode.handle_flavour = UNSOLICITED_MODE;
+ r = nfcc_initialise(client, platform_data->reg);
+ if (r) {
+ dev_err(&client->dev, "nfc-nci probe: request nfcc initialise failed\n");
+ goto err_nfcc_init_failed;
+ }
qca199x_dev->irq_enabled = true;
r = request_irq(client->irq, qca199x_dev_irq_handler,
@@ -697,6 +846,7 @@
__func__);
return 0;
+err_nfcc_init_failed:
err_request_irq_failed:
misc_deregister(&qca199x_dev->qca199x_device);
err_misc_register:
diff --git a/drivers/nfc/nfc-nci.h b/drivers/nfc/nfc-nci.h
index 4398df7..c3cabc2 100644
--- a/drivers/nfc/nfc-nci.h
+++ b/drivers/nfc/nfc-nci.h
@@ -30,8 +30,10 @@
};
enum ehandler_mode {
- UNSOLICITED_READ_MODE = 0,
- SOLICITED_READ_MODE
+ UNSOLICITED_MODE = 0,
+ SOLICITED_MODE,
+ UNSOLICITED_FTM_RAW_MODE,
+ SOLICITED_FTM_RAW_MODE
};
enum ekernel_logging_mode {
@@ -43,9 +45,9 @@
LEVEL_5
};
-struct DeviceMode {
+struct devicemode {
enum ehandler_mode handle_flavour;
-} tDeviceMode;
+} tdevicemode;
#define NFC_DRIVER_NAME "nfc-nci"
#define NFC_I2C_DRIVER_NAME "NCI NFC I2C Interface",
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index acd42ae3..a3f8ec9 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -113,4 +113,9 @@
help
OpenFirmware CoreSight accessors
+config OF_BATTERYDATA
+ def_bool y
+ help
+ OpenFirmware BatteryData accessors
+
endmenu # OF
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index 61a99f2..8b52306 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -16,3 +16,4 @@
obj-$(CONFIG_OF_MTD) += of_mtd.o
obj-$(CONFIG_OF_SLIMBUS) += of_slimbus.o
obj-$(CONFIG_OF_CORESIGHT) += of_coresight.o
+obj-$(CONFIG_OF_BATTERYDATA) += of_batterydata.o
diff --git a/drivers/of/of_batterydata.c b/drivers/of/of_batterydata.c
new file mode 100644
index 0000000..c2585a7
--- /dev/null
+++ b/drivers/of/of_batterydata.c
@@ -0,0 +1,265 @@
+/* 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/of.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/batterydata-lib.h>
+
+static int of_batterydata_read_lut(const struct device_node *np,
+ int max_cols, int max_rows, int *ncols, int *nrows,
+ int *col_legend_data, int *row_legend_data,
+ int *lut_data)
+{
+ struct property *prop;
+ const __be32 *data;
+ int cols, rows, size, i, j, *out_values;
+
+ prop = of_find_property(np, "qcom,lut-col-legend", NULL);
+ if (!prop) {
+ pr_err("%s: No col legend found\n", np->name);
+ return -EINVAL;
+ } else if (!prop->value) {
+ pr_err("%s: No col legend value found, np->name\n", np->name);
+ return -ENODATA;
+ } else if (prop->length > max_cols * sizeof(int)) {
+ pr_err("%s: Too many columns\n", np->name);
+ return -EINVAL;
+ }
+
+ cols = prop->length/sizeof(int);
+ *ncols = cols;
+ data = prop->value;
+ for (i = 0; i < cols; i++)
+ *col_legend_data++ = be32_to_cpup(data++);
+
+ prop = of_find_property(np, "qcom,lut-row-legend", NULL);
+ if (!prop || row_legend_data == NULL) {
+ /* single row lut */
+ rows = 1;
+ } else if (!prop->value) {
+ pr_err("%s: No row legend value found\n", np->name);
+ return -ENODATA;
+ } else if (prop->length > max_rows * sizeof(int)) {
+ pr_err("%s: Too many rows\n", np->name);
+ return -EINVAL;
+ } else {
+ rows = prop->length/sizeof(int);
+ *nrows = rows;
+ data = prop->value;
+ for (i = 0; i < rows; i++)
+ *row_legend_data++ = be32_to_cpup(data++);
+ }
+
+ prop = of_find_property(np, "qcom,lut-data", NULL);
+ data = prop->value;
+ size = prop->length/sizeof(int);
+ if (!prop || size != cols * rows) {
+ pr_err("%s: data size mismatch, %dx%d != %d\n",
+ np->name, cols, rows, size);
+ return -EINVAL;
+ }
+ for (i = 0; i < rows; i++) {
+ out_values = lut_data + (max_cols * i);
+ for (j = 0; j < cols; j++) {
+ *out_values++ = be32_to_cpup(data++);
+ pr_debug("Value = %d\n", *(out_values-1));
+ }
+ }
+
+ return 0;
+}
+
+static int of_batterydata_read_sf_lut(struct device_node *data_node,
+ const char *name, struct sf_lut *lut)
+{
+ struct device_node *node = of_find_node_by_name(data_node, name);
+ int rc;
+
+ if (!lut) {
+ pr_debug("No lut provided, skipping\n");
+ return 0;
+ } else if (!node) {
+ pr_err("Couldn't find %s node.\n", name);
+ return -EINVAL;
+ }
+
+ rc = of_batterydata_read_lut(node, PC_CC_COLS, PC_CC_ROWS,
+ &lut->cols, &lut->rows, lut->row_entries,
+ lut->percent, *lut->sf);
+ if (rc) {
+ pr_err("Failed to read %s node.\n", name);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int of_batterydata_read_pc_temp_ocv_lut(struct device_node *data_node,
+ const char *name, struct pc_temp_ocv_lut *lut)
+{
+ struct device_node *node = of_find_node_by_name(data_node, name);
+ int rc;
+
+ if (!lut) {
+ pr_debug("No lut provided, skipping\n");
+ return 0;
+ } else if (!node) {
+ pr_err("Couldn't find %s node.\n", name);
+ return -EINVAL;
+ }
+ rc = of_batterydata_read_lut(node, PC_TEMP_COLS, PC_TEMP_ROWS,
+ &lut->cols, &lut->rows, lut->temp, lut->percent,
+ *lut->ocv);
+ if (rc) {
+ pr_err("Failed to read %s node.\n", name);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int of_batterydata_read_single_row_lut(struct device_node *data_node,
+ const char *name, struct single_row_lut *lut)
+{
+ struct device_node *node = of_find_node_by_name(data_node, name);
+ int rc;
+
+ if (!lut) {
+ pr_debug("No lut provided, skipping\n");
+ return 0;
+ } else if (!node) {
+ pr_err("Couldn't find %s node.\n", name);
+ return -EINVAL;
+ }
+
+ rc = of_batterydata_read_lut(node, MAX_SINGLE_LUT_COLS, 1,
+ &lut->cols, NULL, lut->x, NULL, lut->y);
+ if (rc) {
+ pr_err("Failed to read %s node.\n", name);
+ return rc;
+ }
+
+ return 0;
+}
+
+#define OF_PROP_READ(property, qpnp_dt_property, node, rc, optional) \
+do { \
+ rc = of_property_read_u32(node, "qcom," qpnp_dt_property, \
+ &property); \
+ \
+ if ((rc == -EINVAL) && optional) { \
+ property = -EINVAL; \
+ rc = 0; \
+ } else if (rc) { \
+ pr_err("Error reading " #qpnp_dt_property \
+ " property rc = %d\n", rc); \
+ return rc; \
+ } \
+} while (0)
+
+static int of_batterydata_load_battery_data(struct device_node *node,
+ struct bms_battery_data *batt_data)
+{
+ int rc;
+
+ rc = of_batterydata_read_single_row_lut(node, "qcom,fcc-temp-lut",
+ batt_data->fcc_temp_lut);
+ if (rc)
+ return rc;
+
+ rc = of_batterydata_read_pc_temp_ocv_lut(node,
+ "qcom,pc-temp-ocv-lut",
+ batt_data->pc_temp_ocv_lut);
+ if (rc)
+ return rc;
+
+ rc = of_batterydata_read_sf_lut(node, "qcom,rbatt-sf-lut",
+ batt_data->rbatt_sf_lut);
+ if (rc)
+ return rc;
+
+ OF_PROP_READ(batt_data->fcc, "fcc-mah", node, rc, false);
+ OF_PROP_READ(batt_data->default_rbatt_mohm,
+ "default-rbatt-mohm", node, rc, false);
+ OF_PROP_READ(batt_data->rbatt_capacitive_mohm,
+ "rbatt-capacitive-mohm", node, rc, false);
+ OF_PROP_READ(batt_data->batt_id_kohm, "batt-id-kohm", node, rc, false);
+ OF_PROP_READ(batt_data->flat_ocv_threshold_uv,
+ "flat-ocv-threshold", 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);
+ OF_PROP_READ(batt_data->iterm_ua, "chg-term-ua", node, rc, true);
+
+ return rc;
+}
+
+static int64_t of_batterydata_convert_battery_id_kohm(int batt_id_uv,
+ int rpull_up, int vadc_vdd)
+{
+ int64_t resistor_value_kohm, denom;
+
+ /* calculate the battery id resistance reported via ADC */
+ denom = div64_s64(vadc_vdd * 1000000LL, batt_id_uv) - 1000000LL;
+
+ resistor_value_kohm = div64_s64(rpull_up * 1000000LL + denom/2, denom);
+
+ pr_debug("batt id voltage = %d, resistor value = %lld\n",
+ batt_id_uv, resistor_value_kohm);
+
+ return resistor_value_kohm;
+}
+
+int of_batterydata_read_data(struct device_node *batterydata_container_node,
+ struct bms_battery_data *batt_data,
+ int batt_id_uv)
+{
+ struct device_node *node, *best_node;
+ uint32_t id_kohm;
+ int delta, best_delta, batt_id_kohm, rpull_up_kohm, vadc_vdd_uv, rc = 0;
+
+ node = batterydata_container_node;
+ OF_PROP_READ(rpull_up_kohm, "rpull-up-kohm", node, rc, false);
+ OF_PROP_READ(vadc_vdd_uv, "vref-batt-therm", node, rc, false);
+
+ batt_id_kohm = of_batterydata_convert_battery_id_kohm(batt_id_uv,
+ rpull_up_kohm, vadc_vdd_uv);
+ best_node = NULL;
+ best_delta = 0;
+
+ /*
+ * Find the battery data with a battery id resistor closest to this one
+ */
+ for_each_child_of_node(batterydata_container_node, node) {
+ rc = of_property_read_u32(node, "qcom,batt-id-kohm", &id_kohm);
+ if (rc)
+ continue;
+ delta = abs((int)id_kohm - batt_id_kohm);
+ if (delta < best_delta || !best_node) {
+ best_node = node;
+ best_delta = delta;
+ }
+ }
+
+ if (best_node == NULL) {
+ pr_err("No battery data found\n");
+ return -ENODATA;
+ }
+
+ return of_batterydata_load_battery_data(best_node, batt_data);
+}
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c
index 06c304a..180b856 100644
--- a/drivers/pinctrl/pinconf-generic.c
+++ b/drivers/pinctrl/pinconf-generic.c
@@ -20,6 +20,7 @@
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/of.h>
#include "core.h"
#include "pinconf.h"
@@ -36,11 +37,15 @@
struct pin_config_item conf_items[] = {
PCONFDUMP(PIN_CONFIG_BIAS_DISABLE, "input bias disabled", NULL),
PCONFDUMP(PIN_CONFIG_BIAS_HIGH_IMPEDANCE, "input bias high impedance", NULL),
+ PCONFDUMP(PIN_CONFIG_BIAS_BUS_HOLD, "input bias bus hold", NULL),
PCONFDUMP(PIN_CONFIG_BIAS_PULL_UP, "input bias pull up", NULL),
PCONFDUMP(PIN_CONFIG_BIAS_PULL_DOWN, "input bias pull down", NULL),
+ PCONFDUMP(PIN_CONFIG_BIAS_PULL_PIN_DEFAULT,
+ "input bias pull to pin specific state", NULL),
PCONFDUMP(PIN_CONFIG_DRIVE_PUSH_PULL, "output drive push pull", NULL),
PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_DRAIN, "output drive open drain", NULL),
PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_SOURCE, "output drive open source", NULL),
+ PCONFDUMP(PIN_CONFIG_DRIVE_STRENGTH, "output drive strength", "mA"),
PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT_ENABLE, "input schmitt enabled", NULL),
PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT, "input schmitt trigger", NULL),
PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE, "input debounce", "time units"),
@@ -121,3 +126,103 @@
}
#endif
+
+#ifdef CONFIG_OF
+struct pinconf_generic_dt_params {
+ const char * const property;
+ enum pin_config_param param;
+ u32 default_value;
+};
+
+static struct pinconf_generic_dt_params dt_params[] = {
+ { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
+ { "bias-high-impedance", PIN_CONFIG_BIAS_HIGH_IMPEDANCE, 0 },
+ { "bias-bus-hold", PIN_CONFIG_BIAS_BUS_HOLD, 0 },
+ { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
+ { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 },
+ { "bias-pull-pin-default", PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, 1 },
+ { "drive-push-pull", PIN_CONFIG_DRIVE_PUSH_PULL, 0 },
+ { "drive-open-drain", PIN_CONFIG_DRIVE_OPEN_DRAIN, 0 },
+ { "drive-open-source", PIN_CONFIG_DRIVE_OPEN_SOURCE, 0 },
+ { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 },
+ { "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 },
+ { "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 },
+ { "input-schmitt", PIN_CONFIG_INPUT_SCHMITT, 0 },
+ { "input-debounce", PIN_CONFIG_INPUT_DEBOUNCE, 0 },
+ { "power-source", PIN_CONFIG_POWER_SOURCE, 0 },
+ { "slew-rate", PIN_CONFIG_SLEW_RATE, 0 },
+ { "low-power-enable", PIN_CONFIG_LOW_POWER_MODE, 1 },
+ { "low-power-disable", PIN_CONFIG_LOW_POWER_MODE, 0 },
+ { "output-low", PIN_CONFIG_OUTPUT, 0, },
+ { "output-high", PIN_CONFIG_OUTPUT, 1, },
+};
+
+/**
+ * pinconf_generic_parse_dt_config()
+ * parse the config properties into generic pinconfig values.
+ * @np: node containing the pinconfig properties
+ * @configs: array with nconfigs entries containing the generic pinconf values
+ * @nconfigs: umber of configurations
+ */
+int pinconf_generic_parse_dt_config(struct device_node *np,
+ unsigned long **configs,
+ unsigned int *nconfigs)
+{
+ unsigned long *cfg;
+ unsigned int ncfg = 0;
+ int ret;
+ int i;
+ u32 val;
+
+ if (!np)
+ return -EINVAL;
+
+ /* allocate a temporary array big enough to hold one of each option */
+ cfg = kzalloc(sizeof(*cfg) * ARRAY_SIZE(dt_params), GFP_KERNEL);
+ if (!cfg)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(dt_params); i++) {
+ struct pinconf_generic_dt_params *par = &dt_params[i];
+ ret = of_property_read_u32(np, par->property, &val);
+
+ /* property not found */
+ if (ret == -EINVAL)
+ continue;
+
+ /* use default value, when no value is specified */
+ if (ret)
+ val = par->default_value;
+
+ pr_debug("found %s with value %u\n", par->property, val);
+ cfg[ncfg] = pinconf_to_config_packed(par->param, val);
+ ncfg++;
+ }
+
+ ret = 0;
+
+ /* no configs found at all */
+ if (ncfg == 0) {
+ *configs = NULL;
+ *nconfigs = 0;
+ goto out;
+ }
+
+ /*
+ * Now limit the number of configs to the real number of
+ * found properties.
+ */
+ *configs = kzalloc(ncfg * sizeof(unsigned long), GFP_KERNEL);
+ if (!*configs) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ memcpy(*configs, cfg, ncfg * sizeof(unsigned long));
+ *nconfigs = ncfg;
+
+out:
+ kfree(cfg);
+ return ret;
+}
+#endif
diff --git a/drivers/pinctrl/pinconf.h b/drivers/pinctrl/pinconf.h
index bfda73d..bf21525 100644
--- a/drivers/pinctrl/pinconf.h
+++ b/drivers/pinctrl/pinconf.h
@@ -115,3 +115,9 @@
}
#endif
+
+#if defined(CONFIG_GENERIC_PINCONF) && defined(CONFIG_OF)
+int pinconf_generic_parse_dt_config(struct device_node *np,
+ unsigned long **configs,
+ unsigned int *nconfigs);
+#endif
diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c
index f5d7b6e..6a16cf3 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -1667,13 +1667,6 @@
}
/* register IPA with SPS driver */
bam_props.phys_addr = resource_p->bam_mem_base;
- bam_props.virt_addr = ioremap(resource_p->bam_mem_base,
- resource_p->bam_mem_size);
- if (!bam_props.virt_addr) {
- IPAERR(":bam-base ioremap err.\n");
- result = -EFAULT;
- goto fail_bam_remap;
- }
bam_props.virt_size = resource_p->bam_mem_size;
bam_props.irq = resource_p->bam_irq;
bam_props.num_pipes = IPA_NUM_PIPES;
@@ -1685,7 +1678,7 @@
if (result) {
IPAERR(":bam register err.\n");
result = -ENODEV;
- goto fail_bam_register;
+ goto fail_init_hw;
}
if (ipa_setup_bam_cfg(resource_p)) {
@@ -2006,18 +1999,12 @@
kmem_cache_destroy(ipa_ctx->flt_rule_cache);
fail_flt_rule_cache:
sps_deregister_bam_device(ipa_ctx->bam_handle);
-fail_bam_register:
- iounmap(bam_props.virt_addr);
-fail_bam_remap:
fail_init_hw:
iounmap(ipa_ctx->mmio);
fail_remap:
kfree(ipa_ctx);
ipa_ctx = NULL;
fail_mem:
- /* gate IPA clocks */
- if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
- ipa_disable_clks();
return result;
}
@@ -2178,8 +2165,12 @@
/* Proceed to real initialization */
result = ipa_init(&ipa_res);
- if (result)
+ if (result) {
IPAERR("ipa_init failed\n");
+ /* gate IPA clocks */
+ if (ipa_res.ipa_hw_mode == IPA_HW_MODE_NORMAL)
+ ipa_disable_clks();
+ }
result = device_create_file(&pdev_p->dev,
&dev_attr_aggregation_type);
diff --git a/drivers/platform/msm/ipa/ipa_bridge.c b/drivers/platform/msm/ipa/ipa_bridge.c
index f9401f0..f626397 100644
--- a/drivers/platform/msm/ipa/ipa_bridge.c
+++ b/drivers/platform/msm/ipa/ipa_bridge.c
@@ -575,3 +575,34 @@
return 0;
}
EXPORT_SYMBOL(ipa_bridge_teardown);
+
+bool ipa_emb_ul_pipes_empty(void)
+{
+ struct sps_pipe *emb_ipa_ul =
+ ipa_ctx->sys[IPA_A5_LAN_WAN_OUT].ep->ep_hdl;
+ struct sps_pipe *emb_ipa_to_dma =
+ bridge[IPA_BRIDGE_TYPE_EMBEDDED].pipe[IPA_UL_FROM_IPA].pipe;
+ struct sps_pipe *emb_dma_to_a2 =
+ bridge[IPA_BRIDGE_TYPE_EMBEDDED].pipe[IPA_UL_TO_A2].pipe;
+ u32 emb_ipa_ul_empty;
+ u32 emb_ipa_to_dma_empty;
+ u32 emb_dma_to_a2_empty;
+
+ if (sps_is_pipe_empty(emb_ipa_ul, &emb_ipa_ul_empty)) {
+ IPAERR("emb_ip_ul pipe empty check fail\n");
+ return false;
+ }
+
+ if (sps_is_pipe_empty(emb_ipa_to_dma, &emb_ipa_to_dma_empty)) {
+ IPAERR("emb_ipa_to_dma pipe empty check fail\n");
+ return false;
+ }
+
+ if (sps_is_pipe_empty(emb_dma_to_a2, &emb_dma_to_a2_empty)) {
+ IPAERR("emb_dma_to_a2 pipe empty check fail\n");
+ return false;
+ }
+
+ return emb_ipa_ul_empty && emb_ipa_to_dma_empty && emb_dma_to_a2_empty;
+}
+EXPORT_SYMBOL(ipa_emb_ul_pipes_empty);
diff --git a/drivers/platform/msm/ipa/ipa_client.c b/drivers/platform/msm/ipa/ipa_client.c
index f20f37f..3aaec07 100644
--- a/drivers/platform/msm/ipa/ipa_client.c
+++ b/drivers/platform/msm/ipa/ipa_client.c
@@ -45,7 +45,7 @@
if (ipa_ctx->ipa_hw_type == IPA_HW_v1_1) {
ipa_write_reg(ipa_ctx->mmio,
IPA_ENDP_INIT_CTRL_n_OFST(clnt_hdl), 1);
- usleep(IPA_PKT_FLUSH_TO_US);
+ udelay(IPA_PKT_FLUSH_TO_US);
if (IPA_CLIENT_IS_CONS(ep->client) &&
ep->cfg.aggr.aggr_en == IPA_ENABLE_AGGR &&
ep->cfg.aggr.aggr_time_limit)
diff --git a/drivers/platform/msm/ipa/ipa_rm_resource.c b/drivers/platform/msm/ipa/ipa_rm_resource.c
index dba4430..986892b 100644
--- a/drivers/platform/msm/ipa/ipa_rm_resource.c
+++ b/drivers/platform/msm/ipa/ipa_rm_resource.c
@@ -787,15 +787,11 @@
&producer->resource.state_lock, flags);
consumer_result = ipa_rm_resource_consumer_release(
(struct ipa_rm_resource_cons *)consumer);
- if (consumer_result == -EINPROGRESS) {
- result = -EINPROGRESS;
- } else {
- spin_lock_irqsave(
- &producer->resource.state_lock, flags);
- producer->pending_release--;
- spin_unlock_irqrestore(
- &producer->resource.state_lock, flags);
- }
+ spin_lock_irqsave(
+ &producer->resource.state_lock, flags);
+ producer->pending_release--;
+ spin_unlock_irqrestore(
+ &producer->resource.state_lock, flags);
}
}
spin_lock_irqsave(&producer->resource.state_lock, flags);
diff --git a/drivers/platform/msm/ipa/ipa_rt.c b/drivers/platform/msm/ipa/ipa_rt.c
index 8c0adbd..8d6d5e6 100644
--- a/drivers/platform/msm/ipa/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_rt.c
@@ -74,23 +74,6 @@
rule_hdr->u.hdr.hdr_offset = 0;
}
buf += sizeof(struct ipa_rt_rule_hw_hdr);
- if ((ip == IPA_IP_v4) &&
- (entry->rule.attrib.attrib_mask & IPA_FLT_TOS)) {
- entry->rule.attrib.tos_value =
- (entry->rule.attrib.u.v4.tos << 5);
- entry->rule.attrib.tos_mask = 0xe0;
- entry->rule.attrib.attrib_mask &= ~IPA_FLT_TOS;
- entry->rule.attrib.attrib_mask |= IPA_FLT_TOS_MASKED;
- }
-
- if ((ip == IPA_IP_v6) &&
- (entry->rule.attrib.attrib_mask & IPA_FLT_TC)) {
- entry->rule.attrib.tos_value =
- (entry->rule.attrib.u.v6.tc << 5);
- entry->rule.attrib.tos_mask = 0xe0;
- entry->rule.attrib.attrib_mask &= ~IPA_FLT_TC;
- entry->rule.attrib.attrib_mask |= IPA_FLT_TOS_MASKED;
- }
if (ipa_generate_hw_rule(ip, &rule->attrib, &buf, &en_rule)) {
IPAERR("fail to generate hw rule\n");
diff --git a/drivers/platform/msm/ipa/ipa_utils.c b/drivers/platform/msm/ipa/ipa_utils.c
index e38b796..4a5fa4d 100644
--- a/drivers/platform/msm/ipa/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_utils.c
@@ -1396,12 +1396,8 @@
if (__ratelimit(&_rs)) {
ipa_inc_client_enable_clks();
pr_err("IPA BAM START\n");
- sps_get_bam_debug_info(ipa_ctx->bam_handle, 5, 1048575, 0, 0);
+ sps_get_bam_debug_info(ipa_ctx->bam_handle, 5, 479182, 0, 0);
sps_get_bam_debug_info(ipa_ctx->bam_handle, 93, 0, 0, 0);
- pr_err("BAM-DMA BAM START\n");
- sps_get_bam_debug_info(sps_dma_get_bam_handle(), 5, 1044480,
- 0, 0);
- sps_get_bam_debug_info(sps_dma_get_bam_handle(), 93, 0, 0, 0);
ipa_dec_client_disable_clks();
}
}
diff --git a/drivers/platform/msm/ipa/teth_bridge.c b/drivers/platform/msm/ipa/teth_bridge.c
index 93f2366..b3a6b17 100644
--- a/drivers/platform/msm/ipa/teth_bridge.c
+++ b/drivers/platform/msm/ipa/teth_bridge.c
@@ -373,8 +373,8 @@
/* Add a header entry for USB */
res = add_eth_hdrs(USB_ETH_HDR_NAME_IPV4,
USB_ETH_HDR_NAME_IPV6,
- teth_ctx->mac_addresses.host_pc_mac_addr,
- teth_ctx->mac_addresses.device_mac_addr);
+ teth_ctx->mac_addresses.device_mac_addr,
+ teth_ctx->mac_addresses.host_pc_mac_addr);
if (res) {
TETH_ERR("Failed adding USB Ethernet header\n");
goto bail;
@@ -384,8 +384,8 @@
/* Add a header entry for A2 */
res = add_eth_hdrs(A2_ETH_HDR_NAME_IPV4,
A2_ETH_HDR_NAME_IPV6,
- teth_ctx->mac_addresses.device_mac_addr,
- teth_ctx->mac_addresses.host_pc_mac_addr);
+ teth_ctx->mac_addresses.host_pc_mac_addr,
+ teth_ctx->mac_addresses.device_mac_addr);
if (res) {
TETH_ERR("Failed adding A2 Ethernet header\n");
goto bail;
diff --git a/drivers/platform/msm/qpnp-power-on.c b/drivers/platform/msm/qpnp-power-on.c
index 087cfa8..b4edce8 100644
--- a/drivers/platform/msm/qpnp-power-on.c
+++ b/drivers/platform/msm/qpnp-power-on.c
@@ -33,6 +33,7 @@
#define QPNP_PON_DBC_CTL(base) (base + 0x71)
/* PON/RESET sources register addresses */
+#define QPNP_PON_REASON1(base) (base + 0x8)
#define QPNP_PON_WARM_RESET_REASON1(base) (base + 0xA)
#define QPNP_PON_WARM_RESET_REASON2(base) (base + 0xB)
#define QPNP_PON_KPDPWR_S1_TIMER(base) (base + 0x40)
@@ -73,8 +74,7 @@
#define QPNP_PON_KPDPWR_RESIN_BARK_N_SET BIT(5)
#define QPNP_PON_RESET_EN BIT(7)
-#define QPNP_PON_WARM_RESET BIT(0)
-#define QPNP_PON_SHUTDOWN BIT(2)
+#define QPNP_PON_POWER_OFF_MASK 0xF
/* Ranges */
#define QPNP_PON_S1_TIMER_MAX 10256
@@ -83,6 +83,7 @@
#define QPNP_PON_S3_DBC_DELAY_MASK 0x07
#define QPNP_PON_RESET_TYPE_MAX 0xF
#define PON_S1_COUNT_MAX 0xF
+#define PON_REASON_MAX 8
#define QPNP_KEY_STATUS_DELAY msecs_to_jiffies(250)
#define QPNP_PON_REV_B 0x01
@@ -124,6 +125,17 @@
3072, 4480, 6720, 10256
};
+static const char * const qpnp_pon_reason[] = {
+ [0] = "Triggered from Hard Reset",
+ [1] = "Triggered from SMPL (sudden momentary power loss)",
+ [2] = "Triggered from RTC (RTC alarm expiry)",
+ [3] = "Triggered from DC (DC charger insertion)",
+ [4] = "Triggered from USB (USB charger insertion)",
+ [5] = "Triggered from PON1 (secondary PMIC)",
+ [6] = "Triggered from CBL (external power supply)",
+ [7] = "Triggered from KPD (power key press)",
+};
+
static int
qpnp_pon_masked_write(struct qpnp_pon *pon, u16 addr, u8 mask, u8 val)
{
@@ -150,14 +162,14 @@
/**
* qpnp_pon_system_pwr_off - Configure system-reset PMIC for shutdown or reset
- * @reset: Configures for shutdown if 0, or reset if 1.
+ * @type: Determines the type of power off to perform - shutdown, reset, etc
*
* This function will only configure a single PMIC. The other PMICs in the
* system are slaved off of it and require no explicit configuration. Once
* the system-reset PMIC is configured properly, the MSM can drop PS_HOLD to
* activate the specified configuration.
*/
-int qpnp_pon_system_pwr_off(bool reset)
+int qpnp_pon_system_pwr_off(enum pon_power_off_type type)
{
int rc;
u8 reg;
@@ -194,8 +206,7 @@
udelay(500);
rc = qpnp_pon_masked_write(pon, QPNP_PON_PS_HOLD_RST_CTL(pon->base),
- QPNP_PON_WARM_RESET | QPNP_PON_SHUTDOWN,
- reset ? QPNP_PON_WARM_RESET : QPNP_PON_SHUTDOWN);
+ QPNP_PON_POWER_OFF_MASK, type);
if (rc)
dev_err(&pon->spmi->dev,
"Unable to write to addr=%x, rc(%d)\n",
@@ -207,6 +218,8 @@
dev_err(&pon->spmi->dev,
"Unable to write to addr=%x, rc(%d)\n", rst_en_reg, rc);
+ dev_dbg(&pon->spmi->dev, "power off type = 0x%02X\n", type);
+
return rc;
}
EXPORT_SYMBOL(qpnp_pon_system_pwr_off);
@@ -966,7 +979,8 @@
struct resource *pon_resource;
struct device_node *itr = NULL;
u32 delay = 0, s3_debounce = 0;
- int rc, sys_reset;
+ int rc, sys_reset, index;
+ u8 pon_sts = 0;
pon = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_pon),
GFP_KERNEL);
@@ -1007,6 +1021,19 @@
}
pon->base = pon_resource->start;
+ /* PON reason */
+ rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
+ QPNP_PON_REASON1(pon->base), &pon_sts, 1);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "Unable to read PON_RESASON1 reg\n");
+ return rc;
+ }
+ index = ffs(pon_sts);
+ if ((index > PON_REASON_MAX) || (index < 0))
+ index = 0;
+ pr_info("PMIC@SID%d Power-on reason: %s\n", pon->spmi->sid,
+ index ? qpnp_pon_reason[index - 1] : "Unknown");
+
rc = of_property_read_u32(pon->spmi->dev.of_node,
"qcom,pon-dbc-delay", &delay);
if (rc) {
diff --git a/drivers/platform/msm/qpnp-pwm.c b/drivers/platform/msm/qpnp-pwm.c
index 4e94b90..2fdc427 100644
--- a/drivers/platform/msm/qpnp-pwm.c
+++ b/drivers/platform/msm/qpnp-pwm.c
@@ -43,21 +43,32 @@
#define QPNP_EN_PAUSE_LO_MASK 0x01
/* LPG Control for LPG_PWM_SIZE_CLK */
+#define QPNP_PWM_SIZE_SHIFT_SUB_TYPE 2
+#define QPNP_PWM_SIZE_MASK_SUB_TYPE 0x4
+#define QPNP_PWM_FREQ_CLK_SELECT_MASK_SUB_TYPE 0x03
+#define QPNP_PWM_SIZE_9_BIT_SUB_TYPE 0x01
+
+#define QPNP_SET_PWM_CLK_SUB_TYPE(val, clk, pwm_size) \
+do { \
+ val = (clk + 1) & QPNP_PWM_FREQ_CLK_SELECT_MASK_SUB_TYPE; \
+ val |= ((pwm_size > 6 ? QPNP_PWM_SIZE_9_BIT_SUB_TYPE : 0) << \
+ QPNP_PWM_SIZE_SHIFT_SUB_TYPE) & QPNP_PWM_SIZE_MASK_SUB_TYPE; \
+} while (0)
+
#define QPNP_PWM_SIZE_SHIFT 4
#define QPNP_PWM_SIZE_MASK 0x30
-#define QPNP_PWM_FREQ_CLK_SELECT_SHIFT 0
#define QPNP_PWM_FREQ_CLK_SELECT_MASK 0x03
-#define QPNP_PWM_SIZE_9_BIT 0x03
-
+#define QPNP_MIN_PWM_BIT_SIZE 6
+#define QPNP_MAX_PWM_BIT_SIZE 9
#define QPNP_SET_PWM_CLK(val, clk, pwm_size) \
do { \
val = (clk + 1) & QPNP_PWM_FREQ_CLK_SELECT_MASK; \
- val |= ((pwm_size > 6 ? QPNP_PWM_SIZE_9_BIT : 0) << \
- QPNP_PWM_SIZE_SHIFT) & QPNP_PWM_SIZE_MASK; \
+ val |= (((pwm_size - QPNP_MIN_PWM_BIT_SIZE) << \
+ QPNP_PWM_SIZE_SHIFT) & QPNP_PWM_SIZE_MASK); \
} while (0)
#define QPNP_GET_PWM_SIZE(reg) ((reg & QPNP_PWM_SIZE_MASK) \
- >> QPNP_PWM_SIZE_SHIFT)
+ >> QPNP_PWM_SIZE_SHIFT)
/* LPG Control for LPG_PWM_FREQ_PREDIV_CLK */
#define QPNP_PWM_FREQ_PRE_DIVIDE_SHIFT 5
@@ -68,7 +79,7 @@
do { \
val = (pre_div << QPNP_PWM_FREQ_PRE_DIVIDE_SHIFT) & \
QPNP_PWM_FREQ_PRE_DIVIDE_MASK; \
- val |= pre_div_exp & QPNP_PWM_FREQ_EXP_MASK; \
+ val |= (pre_div_exp & QPNP_PWM_FREQ_EXP_MASK); \
} while (0)
/* LPG Control for LPG_PWM_TYPE_CONFIG */
@@ -104,13 +115,27 @@
#define QPNP_DISABLE_PWM(value) (value &= ~QPNP_EN_PWM_OUTPUT_MASK)
+/* LPG Control for PWM_SYNC */
+#define QPNP_PWM_SYNC_VALUE 0x01
+#define QPNP_PWM_SYNC_MASK 0x01
+
/* LPG Control for RAMP_CONTROL */
#define QPNP_RAMP_START_MASK 0x01
+#define QPNP_RAMP_CONTROL_SHIFT 8
#define QPNP_ENABLE_LUT_V0(value) (value |= QPNP_RAMP_START_MASK)
#define QPNP_DISABLE_LUT_V0(value) (value &= ~QPNP_RAMP_START_MASK)
-#define QPNP_ENABLE_LUT_V1(value, id) (value |= BIT(id))
-#define QPNP_DISABLE_LUT_V1(value, id) (value &= ~BIT(id))
+#define QPNP_ENABLE_LUT_V1(value, id) \
+do { \
+ (id < 8) ? (value |= BIT(id)) : \
+ (value |= (BIT(id) >> QPNP_RAMP_CONTROL_SHIFT)); \
+} while (0)
+
+#define QPNP_DISABLE_LUT_V1(value, id) \
+do { \
+ (id < 8) ? (value &= ~BIT(id)) : \
+ (value &= (~BIT(id) >> QPNP_RAMP_CONTROL_SHIFT)); \
+} while (0)
/* LPG Control for RAMP_STEP_DURATION_LSB */
#define QPNP_RAMP_STEP_DURATION_LSB_MASK 0xFF
@@ -159,9 +184,18 @@
#define SPMI_LPG_REG_BASE_OFFSET 0x40
#define SPMI_LPG_REVISION2_OFFSET 0x1
#define SPMI_LPG_REV1_RAMP_CONTROL_OFFSET 0x86
+#define SPMI_LPG_SUB_TYPE_OFFSET 0x5
+#define SPMI_LPG_PWM_SYNC 0x7
#define SPMI_LPG_REG_ADDR(b, n) (b + SPMI_LPG_REG_BASE_OFFSET + (n))
#define SPMI_MAX_BUF_LEN 8
+#define QPNP_GPLED_LPG_CHANNEL_RANGE_START 8
+#define QPNP_GPLED_LPG_CHANNEL_RANGE_END 11
+#define qpnp_check_gpled_lpg_channel(id) \
+ (id >= QPNP_GPLED_LPG_CHANNEL_RANGE_START && \
+ id <= QPNP_GPLED_LPG_CHANNEL_RANGE_END)
+#define QPNP_PWM_LUT_NOT_SUPPORTED 0x1
+
/* LPG revisions */
enum qpnp_lpg_revision {
QPNP_LPG_REVISION_0 = 0x0,
@@ -277,6 +311,8 @@
struct qpnp_lpg_config lpg_config;
u8 qpnp_lpg_registers[QPNP_TOTAL_LPG_SPMI_REGISTERS];
enum qpnp_lpg_revision revision;
+ u8 sub_type;
+ u32 flags;
};
/* Internal functions */
@@ -374,20 +410,29 @@
* (PWM Period / N) = (Pre-divide * Clock Period) * 2^m
*/
static void qpnp_lpg_calc_period(unsigned int period_us,
- struct pwm_period_config *period)
+ struct qpnp_pwm_config *pwm_conf)
{
int n, m, clk, div;
int best_m, best_div, best_clk;
unsigned int last_err, cur_err, min_err;
unsigned int tmp_p, period_n;
+ int id = pwm_conf->channel_id;
+ struct pwm_period_config *period = &pwm_conf->period;
/* PWM Period / N */
- if (period_us < ((unsigned)(-1) / NSEC_PER_USEC)) {
- period_n = (period_us * NSEC_PER_USEC) >> 6;
+ if (qpnp_check_gpled_lpg_channel(id))
+ n = 7;
+ else
n = 6;
+
+ if (period_us < ((unsigned)(-1) / NSEC_PER_USEC)) {
+ period_n = (period_us * NSEC_PER_USEC) >> n;
} else {
- period_n = (period_us >> 9) * NSEC_PER_USEC;
- n = 9;
+ if (qpnp_check_gpled_lpg_channel(id))
+ n = 8;
+ else
+ n = 9;
+ period_n = (period_us >> n) * NSEC_PER_USEC;
}
min_err = last_err = (unsigned)(-1);
@@ -422,10 +467,22 @@
}
}
- /* Use higher resolution */
- if (best_m >= 3 && n == 6) {
- n += 3;
- best_m -= 3;
+ /* Adapt to optimal pwm size, the higher the resolution the better */
+ if (qpnp_check_gpled_lpg_channel(id)) {
+ if (n == 7 && best_m >= 1) {
+ n += 1;
+ best_m -= 1;
+ }
+ } else {
+ if (n == 6 && best_m >= 3) {
+ n += 3;
+ best_m -= 3;
+ } else {
+ if (n == 6) {
+ n += best_m;
+ best_m -= best_m;
+ }
+ }
}
period->pwm_size = n;
@@ -467,8 +524,8 @@
int offset = (lut->lo_index << 1) - 2;
pwm_size = QPNP_GET_PWM_SIZE(
- chip->qpnp_lpg_registers[QPNP_LPG_PWM_SIZE_CLK]) &
- QPNP_PWM_SIZE_9_BIT ? 9 : 6;
+ chip->qpnp_lpg_registers[QPNP_LPG_PWM_SIZE_CLK]) +
+ QPNP_MIN_PWM_BIT_SIZE;
max_pwm_value = (1 << pwm_size) - 1;
@@ -489,20 +546,30 @@
if (pwm_value > max_pwm_value)
pwm_value = max_pwm_value;
- lut->duty_pct_list[i*2] = pwm_value;
- lut->duty_pct_list[(i*2)+1] = (pwm_value >>
+ if (qpnp_check_gpled_lpg_channel(pwm->pwm_config.channel_id)) {
+ lut->duty_pct_list[i] = pwm_value;
+ } else {
+ lut->duty_pct_list[i*2] = pwm_value;
+ lut->duty_pct_list[(i*2)+1] = (pwm_value >>
QPNP_PWM_VALUE_MSB_SHIFT) & QPNP_PWM_VALUE_MSB_MASK;
+ }
}
+ /*
+ * For the Keypad Backlight Lookup Table (KPDBL_LUT),
+ * offset is lo_index.
+ */
+ if (qpnp_check_gpled_lpg_channel(pwm->pwm_config.channel_id))
+ offset = lut->lo_index;
+
/* Write with max allowable burst mode, each entry is of two bytes */
- for (i = 0; i < list_len;) {
+ for (i = 0; i < list_len; i += burst_size) {
if (i + burst_size >= list_len)
burst_size = list_len - i;
rc = spmi_ext_register_writel(chip->spmi_dev->ctrl,
chip->spmi_dev->sid,
chip->lpg_config.lut_base_addr + offset + i,
lut->duty_pct_list + i, burst_size);
- i += burst_size;
}
return rc;
@@ -514,7 +581,11 @@
struct qpnp_lpg_chip *chip = pwm->chip;
struct qpnp_pwm_config *pwm_config = &pwm->pwm_config;
- QPNP_SET_PWM_CLK(val, pwm_config->period.clk,
+ if (chip->sub_type == 0x0B)
+ QPNP_SET_PWM_CLK_SUB_TYPE(val, pwm_config->period.clk,
+ pwm_config->period.pwm_size);
+ else
+ QPNP_SET_PWM_CLK(val, pwm_config->period.clk,
pwm_config->period.pwm_size);
mask = QPNP_PWM_SIZE_MASK | QPNP_PWM_FREQ_CLK_SELECT_MASK;
@@ -542,8 +613,8 @@
int rc;
pwm_size = QPNP_GET_PWM_SIZE(
- chip->qpnp_lpg_registers[QPNP_LPG_PWM_SIZE_CLK]) &
- QPNP_PWM_SIZE_9_BIT ? 9 : 6;
+ chip->qpnp_lpg_registers[QPNP_LPG_PWM_SIZE_CLK]) +
+ QPNP_MIN_PWM_BIT_SIZE;
max_pwm_value = (1 << pwm_size) - 1;
@@ -565,10 +636,21 @@
mask = QPNP_PWM_VALUE_MSB_MASK;
- return qpnp_lpg_save_and_write(value, mask,
+ rc = qpnp_lpg_save_and_write(value, mask,
&pwm->chip->qpnp_lpg_registers[QPNP_PWM_VALUE_MSB],
SPMI_LPG_REG_ADDR(lpg_config->base_addr,
QPNP_PWM_VALUE_MSB), 1, chip);
+ if (rc)
+ return rc;
+
+ if (chip->sub_type == 0x0B) {
+ value = QPNP_PWM_SYNC_VALUE & QPNP_PWM_SYNC_MASK;
+ rc = spmi_ext_register_writel(chip->spmi_dev->ctrl,
+ chip->spmi_dev->sid,
+ SPMI_LPG_REG_ADDR(lpg_config->base_addr,
+ SPMI_LPG_PWM_SYNC), &value, 1);
+ }
+ return rc;
}
static int qpnp_lpg_configure_pattern(struct pwm_device *pwm)
@@ -910,13 +992,9 @@
addr1, 1, chip);
}
-#define QPNP_GPLED_LPG_CHANNEL_RANGE_START 8
-#define QPNP_GPLED_LPG_CHANNEL_RANGE_END 11
-
static inline int qpnp_enable_pwm_mode(struct qpnp_pwm_config *pwm_conf)
{
- if (pwm_conf->channel_id >= QPNP_GPLED_LPG_CHANNEL_RANGE_START &&
- pwm_conf->channel_id <= QPNP_GPLED_LPG_CHANNEL_RANGE_END)
+ if (qpnp_check_gpled_lpg_channel(pwm_conf->channel_id))
return QPNP_ENABLE_PWM_MODE_GPLED_CHANNEL;
return QPNP_ENABLE_PWM_MODE;
}
@@ -968,7 +1046,7 @@
period = &pwm_config->period;
if (pwm_config->pwm_period != period_us) {
- qpnp_lpg_calc_period(period_us, period);
+ qpnp_lpg_calc_period(period_us, pwm_config);
qpnp_lpg_save_period(pwm);
pwm_config->pwm_period = period_us;
}
@@ -1024,7 +1102,7 @@
period = &pwm_config->period;
if (pwm_config->pwm_period != period_us) {
- qpnp_lpg_calc_period(period_us, period);
+ qpnp_lpg_calc_period(period_us, pwm_config);
qpnp_lpg_save_period(pwm);
pwm_config->pwm_period = period_us;
}
@@ -1077,7 +1155,7 @@
static int _pwm_enable(struct pwm_device *pwm)
{
- int rc;
+ int rc = 0;
struct qpnp_lpg_chip *chip;
unsigned long flags;
@@ -1086,10 +1164,11 @@
spin_lock_irqsave(&pwm->chip->lpg_lock, flags);
if (QPNP_IS_PWM_CONFIG_SELECTED(
- chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL]))
+ chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL])) {
rc = qpnp_lpg_configure_pwm_state(pwm, QPNP_PWM_ENABLE);
- else
- rc = qpnp_lpg_configure_lut_state(pwm, QPNP_LUT_ENABLE);
+ } else if (!(chip->flags & QPNP_PWM_LUT_NOT_SUPPORTED)) {
+ rc = qpnp_lpg_configure_lut_state(pwm, QPNP_LUT_ENABLE);
+ }
spin_unlock_irqrestore(&pwm->chip->lpg_lock, flags);
@@ -1160,7 +1239,8 @@
if (pwm_config->in_use) {
qpnp_lpg_configure_pwm_state(pwm, QPNP_PWM_DISABLE);
- qpnp_lpg_configure_lut_state(pwm, QPNP_LUT_DISABLE);
+ if (!(pwm->chip->flags & QPNP_PWM_LUT_NOT_SUPPORTED))
+ qpnp_lpg_configure_lut_state(pwm, QPNP_LUT_DISABLE);
pwm_config->in_use = 0;
pwm_config->lable = NULL;
}
@@ -1249,12 +1329,13 @@
if (pwm_config->in_use) {
if (QPNP_IS_PWM_CONFIG_SELECTED(
- chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL]))
+ chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL])) {
rc = qpnp_lpg_configure_pwm_state(pwm,
QPNP_PWM_DISABLE);
- else
- rc = qpnp_lpg_configure_lut_state(pwm,
- QPNP_LUT_DISABLE);
+ } else if (!(chip->flags & QPNP_PWM_LUT_NOT_SUPPORTED)) {
+ rc = qpnp_lpg_configure_lut_state(pwm,
+ QPNP_LUT_DISABLE);
+ }
}
spin_unlock_irqrestore(&pwm->chip->lpg_lock, flags);
@@ -1435,6 +1516,11 @@
if (pwm->chip == NULL)
return -ENODEV;
+ if (pwm->chip->flags & QPNP_PWM_LUT_NOT_SUPPORTED) {
+ pr_err("LUT mode isn't supported\n");
+ return -EINVAL;
+ }
+
if (!pwm->pwm_config.in_use) {
pr_err("channel_id: %d: stale handle?\n",
pwm->pwm_config.channel_id);
@@ -1588,7 +1674,7 @@
static int qpnp_parse_dt_config(struct spmi_device *spmi,
struct qpnp_lpg_chip *chip)
{
- int rc, enable;
+ int rc, enable, lut_entry_size;
const char *lable;
struct resource *res;
struct device_node *node;
@@ -1599,6 +1685,14 @@
struct qpnp_lpg_config *lpg_config = &chip->lpg_config;
struct qpnp_lut_config *lut_config = &lpg_config->lut_config;
+ rc = of_property_read_u32(of_node, "qcom,channel-id",
+ &pwm_dev->pwm_config.channel_id);
+ if (rc) {
+ dev_err(&spmi->dev, "%s: node is missing LPG channel id\n",
+ __func__);
+ goto out;
+ }
+
res = spmi_get_resource_byname(spmi, NULL, IORESOURCE_MEM,
QPNP_LPG_CHANNEL_BASE);
if (!res) {
@@ -1612,28 +1706,27 @@
res = spmi_get_resource_byname(spmi, NULL, IORESOURCE_MEM,
QPNP_LPG_LUT_BASE);
if (!res) {
- dev_err(&spmi->dev, "%s: node is missing LUT base address\n",
- __func__);
- return -EINVAL;
- }
+ chip->flags |= QPNP_PWM_LUT_NOT_SUPPORTED;
+ } else {
+ lpg_config->lut_base_addr = res->start;
+ /* Each entry of LUT is of 2 bytes for generic LUT and of 1 byte
+ * for KPDBL/GLED LUT.
+ */
+ lpg_config->lut_size = resource_size(res) >> 1;
+ lut_entry_size = sizeof(u16);
- lpg_config->lut_base_addr = res->start;
- /* Each entry of LUT is of 2 bytes */
- lpg_config->lut_size = resource_size(res) >> 1;
+ if (qpnp_check_gpled_lpg_channel(
+ pwm_dev->pwm_config.channel_id)) {
+ lpg_config->lut_size = resource_size(res);
+ lut_entry_size = sizeof(u8);
+ }
- lut_config->duty_pct_list = kzalloc(lpg_config->lut_size *
- sizeof(u16), GFP_KERNEL);
- if (!lut_config->duty_pct_list) {
- pr_err("can not allocate duty pct list\n");
- return -ENOMEM;
- }
-
- rc = of_property_read_u32(of_node, "qcom,channel-id",
- &pwm_dev->pwm_config.channel_id);
- if (rc) {
- dev_err(&spmi->dev, "%s: node is missing LPG channel id\n",
- __func__);
- goto out;
+ lut_config->duty_pct_list = kzalloc(lpg_config->lut_size *
+ lut_entry_size, GFP_KERNEL);
+ if (!lut_config->duty_pct_list) {
+ pr_err("can not allocate duty pct list\n");
+ return -ENOMEM;
+ }
}
for_each_child_of_node(of_node, node) {
@@ -1648,7 +1741,8 @@
if (rc)
goto out;
found_pwm_subnode = 1;
- } else if (!strncmp(lable, "lpg", 3)) {
+ } else if (!strncmp(lable, "lpg", 3) &&
+ !(chip->flags & QPNP_PWM_LUT_NOT_SUPPORTED)) {
qpnp_parse_lpg_dt_config(node, of_node, chip);
if (rc)
goto out;
@@ -1722,6 +1816,11 @@
goto failed_insert;
}
+ spmi_ext_register_readl(chip->spmi_dev->ctrl,
+ chip->spmi_dev->sid,
+ chip->lpg_config.base_addr + SPMI_LPG_SUB_TYPE_OFFSET,
+ &chip->sub_type, 1);
+
rc = radix_tree_insert(&lpg_dev_tree, id, chip);
if (rc) {
diff --git a/drivers/platform/msm/sps/bam.c b/drivers/platform/msm/sps/bam.c
index 6412fc0..d6af279 100644
--- a/drivers/platform/msm/sps/bam.c
+++ b/drivers/platform/msm/sps/bam.c
@@ -53,6 +53,7 @@
#define IRQ_EN (0x1c)
#define AHB_MASTER_ERR_CTRLS (0x24)
#define AHB_MASTER_ERR_ADDR (0x28)
+#define AHB_MASTER_ERR_ADDR_MSB (0x104)
#define AHB_MASTER_ERR_DATA (0x2c)
#define TRUST_REG (0x70)
#define TEST_BUS_SEL (0x74)
@@ -61,6 +62,7 @@
#define IRQ_SRCS_EE(n) (0x800 + 128 * (n))
#define IRQ_SRCS_MSK_EE(n) (0x804 + 128 * (n))
#define IRQ_SRCS_UNMASKED_EE(n) (0x808 + 128 * (n))
+#define PIPE_ATTR_EE(n) (0x80c + 128 * (n))
#define P_CTRL(n) (0x1000 + 4096 * (n))
#define P_RST(n) (0x1004 + 4096 * (n))
@@ -74,10 +76,13 @@
#define P_CNSMR_SDBND(n) (0x1028 + 4096 * (n))
#define P_TRUST_REG(n) (0x1030 + 4096 * (n))
#define P_EVNT_DEST_ADDR(n) (0x182c + 4096 * (n))
+#define P_EVNT_DEST_ADDR_MSB(n) (0x1934 + 4096 * (n))
#define P_EVNT_REG(n) (0x1818 + 4096 * (n))
#define P_SW_OFSTS(n) (0x1800 + 4096 * (n))
#define P_DATA_FIFO_ADDR(n) (0x1824 + 4096 * (n))
+#define P_DATA_FIFO_ADDR_MSB(n) (0x1924 + 4096 * (n))
#define P_DESC_FIFO_ADDR(n) (0x181c + 4096 * (n))
+#define P_DESC_FIFO_ADDR_MSB(n) (0x1914 + 4096 * (n))
#define P_EVNT_GEN_TRSHLD(n) (0x1828 + 4096 * (n))
#define P_FIFO_SIZES(n) (0x1820 + 4096 * (n))
#define P_RETR_CNTXT(n) (0x1834 + 4096 * (n))
@@ -86,6 +91,7 @@
#define P_AU_PSM_CNTXT_1(n) (0x1804 + 4096 * (n))
#define P_PSM_CNTXT_2(n) (0x1808 + 4096 * (n))
#define P_PSM_CNTXT_3(n) (0x180c + 4096 * (n))
+#define P_PSM_CNTXT_3_MSB(n) (0x1904 + 4096 * (n))
#define P_PSM_CNTXT_4(n) (0x1810 + 4096 * (n))
#define P_PSM_CNTXT_5(n) (0x1814 + 4096 * (n))
@@ -95,6 +101,7 @@
*
*/
/* CTRL */
+#define BAM_MESS_ONLY_CANCEL_WB 0x100000
#define CACHE_MISS_ERR_RESP_EN 0x80000
#define LOCAL_CLK_GATING 0x60000
#define IBC_DISABLE 0x10000
@@ -115,7 +122,7 @@
#define BAM_SECURED 0x10000
#define BAM_USE_VMIDMT 0x8000
#define BAM_AXI_ACTIVE 0x4000
-#define BAM_CE_BUFFER_SIZE 0x2000
+#define BAM_CE_BUFFER_SIZE 0x3000
#define BAM_NUM_EES 0xf00
#define BAM_REVISION 0xff
@@ -127,6 +134,7 @@
/* NUM_PIPES */
#define BAM_NON_PIPE_GRP 0xff000000
#define BAM_PERIPH_NON_PIPE_GRP 0xff0000
+#define BAM_DATA_ADDR_BUS_WIDTH 0xC000
#define BAM_NUM_PIPES 0xff
/* TIMER */
@@ -188,6 +196,7 @@
#define BAM_TESTBUS_SEL 0x7f
/* CNFG_BITS */
+#define CNFG_BITS_AOS_OVERFLOW_PRVNT 0x80000000
#define CNFG_BITS_MULTIPLE_EVENTS_DESC_AVAIL_EN 0x40000000
#define CNFG_BITS_MULTIPLE_EVENTS_SIZE_EN 0x20000000
#define CNFG_BITS_BAM_ZLT_W_CD_SUPPORT 0x10000000
@@ -210,6 +219,10 @@
#define CNFG_BITS_BAM_FULL_PIPE 0x800
#define CNFG_BITS_BAM_PIPE_CNFG 0x4
+/* PIPE_ATTR_EEn*/
+#define BAM_ENABLED 0x80000000
+#define P_ATTR 0x7fffffff
+
/* P_ctrln */
#define P_LOCK_GROUP 0x1f0000
#define P_WRITE_NWD 0x800
@@ -234,6 +247,8 @@
#define BAM_P_EE 0x7
/* P_IRQ_STTSn */
+#define P_IRQ_STTS_P_HRESP_ERR_IRQ 0x80
+#define P_IRQ_STTS_P_PIPE_RST_ERR_IRQ 0x40
#define P_IRQ_STTS_P_TRNSFR_END_IRQ 0x20
#define P_IRQ_STTS_P_ERR_IRQ 0x10
#define P_IRQ_STTS_P_OUT_OF_DESC_IRQ 0x8
@@ -242,6 +257,8 @@
#define P_IRQ_STTS_P_PRCSD_DESC_IRQ 0x1
/* P_IRQ_CLRn */
+#define P_IRQ_CLR_P_HRESP_ERR_CLR 0x80
+#define P_IRQ_CLR_P_PIPE_RST_ERR_CLR 0x40
#define P_IRQ_CLR_P_TRNSFR_END_CLR 0x20
#define P_IRQ_CLR_P_ERR_CLR 0x10
#define P_IRQ_CLR_P_OUT_OF_DESC_CLR 0x8
@@ -250,6 +267,8 @@
#define P_IRQ_CLR_P_PRCSD_DESC_CLR 0x1
/* P_IRQ_ENn */
+#define P_IRQ_EN_P_HRESP_ERR_EN 0x80
+#define P_IRQ_EN_P_PIPE_RST_ERR_EN 0x40
#define P_IRQ_EN_P_TRNSFR_END_EN 0x20
#define P_IRQ_EN_P_ERR_EN 0x10
#define P_IRQ_EN_P_OUT_OF_DESC_EN 0x8
@@ -404,6 +423,7 @@
/* NUM_PIPES */
#define BAM_NON_PIPE_GRP 0xff000000
#define BAM_PERIPH_NON_PIPE_GRP 0xff0000
+#define BAM_DATA_ADDR_BUS_WIDTH 0xC000
#define BAM_NUM_PIPES 0xff
/* DESC_CNT_TRSHLD */
@@ -686,8 +706,16 @@
bam_write_reg_field(base, CTRL, LOCAL_CLK_GATING, 0);
else
bam_write_reg_field(base, CTRL, LOCAL_CLK_GATING, 1);
-#endif
+ if (enhd_pipe) {
+ if (options & SPS_BAM_CANCEL_WB)
+ bam_write_reg_field(base, CTRL,
+ BAM_MESS_ONLY_CANCEL_WB, 1);
+ else
+ bam_write_reg_field(base, CTRL,
+ BAM_MESS_ONLY_CANCEL_WB, 0);
+ }
+#endif
bam_write_reg(base, DESC_CNT_TRSHLD, summing_threshold);
bam_write_reg(base, CNFG_BITS, cfg_bits);
@@ -786,18 +814,43 @@
return 0;
}
+#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
+static inline u32 bam_get_pipe_attr(void *base, u32 ee, bool global)
+{
+ u32 val;
+
+ if (global)
+ val = bam_read_reg_field(base, PIPE_ATTR_EE(ee), BAM_ENABLED);
+ else
+ val = bam_read_reg_field(base, PIPE_ATTR_EE(ee), P_ATTR);
+
+ return val;
+}
+#else
+static inline u32 bam_get_pipe_attr(void *base, u32 ee, bool global)
+{
+ return 0;
+}
+#endif
+
/**
* Verify that a BAM device is enabled and gathers the hardware
* configuration.
*
*/
-int bam_check(void *base, u32 *version, u32 *num_pipes)
+int bam_check(void *base, u32 *version, u32 ee, u32 *num_pipes)
{
u32 ver = 0;
+ u32 enabled = 0;
SPS_DBG2("sps:%s:bam=0x%x(va).", __func__, (u32) base);
- if (!bam_read_reg_field(base, CTRL, BAM_EN)) {
+ if (!enhd_pipe)
+ enabled = bam_read_reg_field(base, CTRL, BAM_EN);
+ else
+ enabled = bam_get_pipe_attr(base, ee, true);
+
+ if (!enabled) {
SPS_ERR("sps:%s:bam 0x%x(va) is not enabled.\n",
__func__, (u32) base);
return -ENODEV;
@@ -843,10 +896,11 @@
* including the TEST_BUS register content under
* different TEST_BUS_SEL values.
*/
-static void bam_output_register_content(void *base)
+void bam_output_register_content(void *base, u32 ee)
{
u32 num_pipes;
u32 i;
+ u32 pipe_attr = 0;
print_bam_test_bus_reg(base, 0);
@@ -857,8 +911,18 @@
SPS_INFO("sps:bam 0x%x(va) has %d pipes.",
(u32) base, num_pipes);
- for (i = 0; i < num_pipes; i++)
- print_bam_pipe_selected_reg(base, i);
+ pipe_attr = enhd_pipe ?
+ bam_get_pipe_attr(base, ee, false) : 0x0;
+
+ if (!enhd_pipe || !pipe_attr)
+ for (i = 0; i < num_pipes; i++)
+ print_bam_pipe_selected_reg(base, i);
+ else {
+ for (i = 0; i < num_pipes; i++) {
+ if (pipe_attr & (1UL << i))
+ print_bam_pipe_selected_reg(base, i);
+ }
+ }
}
/**
@@ -878,13 +942,13 @@
SPS_ERR("sps:bam 0x%x(va);bam irq status="
"0x%x.\nsps: BAM_ERROR_IRQ\n",
(u32) base, status);
- bam_output_register_content(base);
+ bam_output_register_content(base, ee);
*cb_case = SPS_CALLBACK_BAM_ERROR_IRQ;
} else if (status & IRQ_STTS_BAM_HRESP_ERR_IRQ) {
SPS_ERR("sps:bam 0x%x(va);bam irq status="
"0x%x.\nsps: BAM_HRESP_ERR_IRQ\n",
(u32) base, status);
- bam_output_register_content(base);
+ bam_output_register_content(base, ee);
*cb_case = SPS_CALLBACK_BAM_HRESP_ERR_IRQ;
#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
} else if (status & IRQ_STTS_BAM_TIMER_IRQ) {
@@ -926,7 +990,8 @@
bam_write_reg(base, P_EVNT_GEN_TRSHLD(pipe), param->event_threshold);
- bam_write_reg(base, P_DESC_FIFO_ADDR(pipe), param->desc_base);
+ bam_write_reg(base, P_DESC_FIFO_ADDR(pipe),
+ SPS_GET_LOWER_ADDR(param->desc_base));
bam_write_reg_field(base, P_FIFO_SIZES(pipe), P_DESC_FIFO_SIZE,
param->desc_size);
@@ -934,6 +999,10 @@
param->stream_mode);
#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
+ if (SPS_LPAE)
+ bam_write_reg(base, P_DESC_FIFO_ADDR_MSB(pipe),
+ SPS_GET_UPPER_ADDR(param->desc_base));
+
bam_write_reg_field(base, P_CTRL(pipe), P_LOCK_GROUP,
param->lock_group);
@@ -946,7 +1015,7 @@
P_EVNT_REG(param->peer_pipe);
bam_write_reg(base, P_DATA_FIFO_ADDR(pipe),
- param->data_base);
+ SPS_GET_LOWER_ADDR(param->data_base));
bam_write_reg_field(base, P_FIFO_SIZES(pipe),
P_DATA_FIFO_SIZE, param->data_size);
@@ -959,6 +1028,12 @@
param->peer_pipe);
#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
+ if (SPS_LPAE) {
+ bam_write_reg(base, P_EVNT_DEST_ADDR_MSB(pipe), 0x0);
+ bam_write_reg(base, P_DATA_FIFO_ADDR_MSB(pipe),
+ SPS_GET_UPPER_ADDR(param->data_base));
+ }
+
bam_write_reg_field(base, P_CTRL(pipe), P_WRITE_NWD,
param->write_nwd);
@@ -1033,6 +1108,24 @@
u32 src_mask, u32 ee)
{
SPS_DBG2("sps:%s:bam=0x%x(va).pipe=%d.", __func__, (u32) base, pipe);
+ if (src_mask & BAM_PIPE_IRQ_RST_ERROR) {
+ if (enhd_pipe)
+ bam_write_reg_field(base, IRQ_EN,
+ IRQ_EN_BAM_ERROR_EN, 0);
+ else {
+ src_mask &= ~BAM_PIPE_IRQ_RST_ERROR;
+ SPS_DBG2("sps: SPS_O_RST_ERROR is not supported\n");
+ }
+ }
+ if (src_mask & BAM_PIPE_IRQ_HRESP_ERROR) {
+ if (enhd_pipe)
+ bam_write_reg_field(base, IRQ_EN,
+ IRQ_EN_BAM_HRESP_ERR_EN, 0);
+ else {
+ src_mask &= ~BAM_PIPE_IRQ_HRESP_ERROR;
+ SPS_DBG2("sps: SPS_O_HRESP_ERROR is not supported\n");
+ }
+ }
bam_write_reg(base, P_IRQ_EN(pipe), src_mask);
bam_write_reg_field(base, IRQ_SRCS_MSK_EE(ee), (1 << pipe), irq_en);
@@ -1294,6 +1387,7 @@
u32 bam_num_pipes;
u32 bam_pipe_num;
+ u32 bam_data_addr_bus_width;
u32 bam_desc_cnt_trshld;
u32 bam_desc_cnt_trd_val;
@@ -1304,6 +1398,7 @@
u32 bam_irq_src_ee = 0;
u32 bam_irq_msk_ee = 0;
u32 bam_irq_unmsk_ee = 0;
+ u32 bam_pipe_attr_ee = 0;
u32 bam_ahb_err_ctrl;
u32 bam_ahb_err_addr;
@@ -1313,6 +1408,7 @@
u32 bam_sw_rev = 0;
u32 bam_timer = 0;
u32 bam_timer_ctrl = 0;
+ u32 bam_ahb_err_addr_msb = 0;
if (base == NULL)
return;
@@ -1324,6 +1420,8 @@
bam_num_pipes = bam_read_reg(base, NUM_PIPES);
bam_pipe_num = bam_read_reg_field(base, NUM_PIPES, BAM_NUM_PIPES);
+ bam_data_addr_bus_width = bam_read_reg_field(base, NUM_PIPES,
+ BAM_DATA_ADDR_BUS_WIDTH);
bam_desc_cnt_trshld = bam_read_reg(base, DESC_CNT_TRSHLD);
bam_desc_cnt_trd_val = bam_read_reg_field(base, DESC_CNT_TRSHLD,
@@ -1347,6 +1445,11 @@
bam_sw_rev = bam_read_reg(base, SW_REVISION);
bam_timer = bam_read_reg(base, TIMER);
bam_timer_ctrl = bam_read_reg(base, TIMER_CTRL);
+ bam_ahb_err_addr_msb = SPS_LPAE ?
+ bam_read_reg(base, AHB_MASTER_ERR_ADDR_MSB) : 0;
+ if (ee < BAM_MAX_EES)
+ bam_pipe_attr_ee = enhd_pipe ?
+ bam_read_reg(base, PIPE_ATTR_EE(ee)) : 0x0;
#endif
@@ -1358,6 +1461,8 @@
SPS_INFO(" NUM_EES: %d\n", bam_rev_ee_num);
SPS_INFO("BAM_SW_REVISION: 0x%x\n", bam_sw_rev);
SPS_INFO("BAM_NUM_PIPES: %d\n", bam_num_pipes);
+ SPS_INFO("BAM_DATA_ADDR_BUS_WIDTH: %d\n",
+ ((bam_data_addr_bus_width == 0x0) ? 32 : 36));
SPS_INFO(" NUM_PIPES: %d\n", bam_pipe_num);
SPS_INFO("BAM_DESC_CNT_TRSHLD: 0x%x\n", bam_desc_cnt_trshld);
SPS_INFO(" DESC_CNT_TRSHLD: 0x%x (%d)\n", bam_desc_cnt_trd_val,
@@ -1371,10 +1476,12 @@
SPS_INFO("BAM_IRQ_SRCS_MSK_EE(%d): 0x%x\n", ee, bam_irq_msk_ee);
SPS_INFO("BAM_IRQ_SRCS_UNMASKED_EE(%d): 0x%x\n", ee,
bam_irq_unmsk_ee);
+ SPS_INFO("BAM_PIPE_ATTR_EE(%d): 0x%x\n", ee, bam_pipe_attr_ee);
}
SPS_INFO("BAM_AHB_MASTER_ERR_CTRLS: 0x%x\n", bam_ahb_err_ctrl);
SPS_INFO("BAM_AHB_MASTER_ERR_ADDR: 0x%x\n", bam_ahb_err_addr);
+ SPS_INFO("BAM_AHB_MASTER_ERR_ADDR_MSB: 0x%x\n", bam_ahb_err_addr_msb);
SPS_INFO("BAM_AHB_MASTER_ERR_DATA: 0x%x\n", bam_ahb_err_data);
SPS_INFO("BAM_CNFG_BITS: 0x%x\n", bam_cnfg_bits);
@@ -1421,9 +1528,12 @@
u32 p_write_pointer;
u32 p_evnt_dest;
+ u32 p_evnt_dest_msb = 0;
u32 p_desc_fifo_addr;
+ u32 p_desc_fifo_addr_msb = 0;
u32 p_desc_fifo_size;
u32 p_data_fifo_addr;
+ u32 p_data_fifo_addr_msb = 0;
u32 p_data_fifo_size;
u32 p_fifo_sizes;
@@ -1439,6 +1549,7 @@
u32 p_au_ct1;
u32 p_psm_ct2;
u32 p_psm_ct3;
+ u32 p_psm_ct3_msb = 0;
u32 p_psm_ct4;
u32 p_psm_ct5;
@@ -1520,6 +1631,15 @@
p_timer_ctrl = bam_read_reg(base, P_TIMER_CTRL(pipe));
#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
+ p_evnt_dest_msb = SPS_LPAE ?
+ bam_read_reg(base, P_EVNT_DEST_ADDR_MSB(pipe)) : 0;
+
+ p_desc_fifo_addr_msb = SPS_LPAE ?
+ bam_read_reg(base, P_DESC_FIFO_ADDR_MSB(pipe)) : 0;
+ p_data_fifo_addr_msb = SPS_LPAE ?
+ bam_read_reg(base, P_DATA_FIFO_ADDR_MSB(pipe)) : 0;
+
+ p_psm_ct3_msb = SPS_LPAE ? bam_read_reg(base, P_PSM_CNTXT_3(pipe)) : 0;
p_lock_group = bam_read_reg_field(base, P_CTRL(pipe), P_LOCK_GROUP);
p_df_ct = bam_read_reg(base, P_DF_CNTXT(pipe));
p_df_offset = bam_read_reg_field(base, P_DF_CNTXT(pipe),
@@ -1568,7 +1688,9 @@
SPS_INFO(" DF_OFFSET: 0x%x\n", p_df_offset);
SPS_INFO("BAM_P_DESC_FIFO_ADDR: 0x%x\n", p_desc_fifo_addr);
+ SPS_INFO("BAM_P_DESC_FIFO_ADDR_MSB: 0x%x\n", p_desc_fifo_addr_msb);
SPS_INFO("BAM_P_DATA_FIFO_ADDR: 0x%x\n", p_data_fifo_addr);
+ SPS_INFO("BAM_P_DATA_FIFO_ADDR_MSB: 0x%x\n", p_data_fifo_addr_msb);
SPS_INFO("BAM_P_FIFO_SIZES: 0x%x\n", p_fifo_sizes);
SPS_INFO(" DESC_FIFO_SIZE: 0x%x (%d)\n", p_desc_fifo_size,
p_desc_fifo_size);
@@ -1576,6 +1698,7 @@
p_data_fifo_size);
SPS_INFO("BAM_P_EVNT_DEST_ADDR: 0x%x\n", p_evnt_dest);
+ SPS_INFO("BAM_P_EVNT_DEST_ADDR_MSB: 0x%x\n", p_evnt_dest_msb);
SPS_INFO("BAM_P_EVNT_GEN_TRSHLD: 0x%x\n", p_evnt_trd);
SPS_INFO(" EVNT_GEN_TRSHLD: 0x%x (%d)\n", p_evnt_trd_val,
p_evnt_trd_val);
@@ -1583,6 +1706,7 @@
SPS_INFO("BAM_P_AU_PSM_CNTXT_1: 0x%x\n", p_au_ct1);
SPS_INFO("BAM_P_PSM_CNTXT_2: 0x%x\n", p_psm_ct2);
SPS_INFO("BAM_P_PSM_CNTXT_3: 0x%x\n", p_psm_ct3);
+ SPS_INFO("BAM_P_PSM_CNTXT_3_MSB: 0x%x\n", p_psm_ct3_msb);
SPS_INFO("BAM_P_PSM_CNTXT_4: 0x%x\n", p_psm_ct4);
SPS_INFO("BAM_P_PSM_CNTXT_5: 0x%x\n", p_psm_ct5);
SPS_INFO("BAM_P_TIMER: 0x%x\n", p_timer);
diff --git a/drivers/platform/msm/sps/bam.h b/drivers/platform/msm/sps/bam.h
index 2a7f05b..d34a7d3 100644
--- a/drivers/platform/msm/sps/bam.h
+++ b/drivers/platform/msm/sps/bam.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, 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
@@ -72,7 +72,7 @@
enum bam_pipe_dir dir;
enum bam_pipe_mode mode;
enum bam_write_nwd write_nwd;
- u32 desc_base; /* Physical address of descriptor FIFO */
+ phys_addr_t desc_base; /* Physical address of descriptor FIFO */
u32 desc_size; /* Size (bytes) of descriptor FIFO */
u32 lock_group; /* The lock group this pipe belongs to */
enum bam_stream_mode stream_mode;
@@ -81,7 +81,7 @@
/* The following are only valid if mode is BAM2BAM */
u32 peer_phys_addr;
u32 peer_pipe;
- u32 data_base; /* Physical address of data FIFO */
+ phys_addr_t data_base; /* Physical address of data FIFO */
u32 data_size; /* Size (bytes) of data FIFO */
};
@@ -139,12 +139,14 @@
*
* @version - return BAM hardware version
*
+ * @ee - BAM execution environment index
+ *
* @num_pipes - return number of pipes
*
* @return 0 on success, negative value on error
*
*/
-int bam_check(void *base, u32 *version, u32 *num_pipes);
+int bam_check(void *base, u32 *version, u32 ee, u32 *num_pipes);
/**
* Disable a BAM device
@@ -159,6 +161,17 @@
void bam_exit(void *base, u32 ee);
/**
+ * This function prints BAM register content
+ * including TEST_BUS and PIPE register content.
+ *
+ * @base - BAM virtual base address.
+ *
+ * @ee - BAM execution environment index
+ */
+void bam_output_register_content(void *base, u32 ee);
+
+
+/**
* Get BAM IRQ source and clear global IRQ status
*
* This function gets BAM IRQ source.
@@ -178,6 +191,7 @@
u32 bam_check_irq_source(void *base, u32 ee, u32 mask,
enum sps_callback_case *cb_case);
+
/**
* Initialize a BAM pipe
*
diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c
index 2e77114..6ccfd29 100644
--- a/drivers/platform/msm/sps/sps.c
+++ b/drivers/platform/msm/sps/sps.c
@@ -80,6 +80,7 @@
static struct sps_drv *sps;
u32 d_type;
+bool enhd_pipe;
static void sps_device_de_init(void);
@@ -1610,7 +1611,7 @@
* Perform a single DMA transfer on an SPS connection end point
*
*/
-int sps_transfer_one(struct sps_pipe *h, u32 addr, u32 size,
+int sps_transfer_one(struct sps_pipe *h, phys_addr_t addr, u32 size,
void *user, u32 flags)
{
struct sps_pipe *pipe = h;
@@ -1632,7 +1633,8 @@
return SPS_ERROR;
result = sps_bam_pipe_transfer_one(bam, pipe->pipe_index,
- addr, size, user, flags);
+ SPS_GET_LOWER_ADDR(addr), size, user,
+ DESC_FLAG_WORD(flags, addr));
sps_bam_unlock(bam);
@@ -2454,6 +2456,11 @@
} else
SPS_DBG("sps:device type is %d.", d_type);
+ enhd_pipe = of_property_read_bool((&pdev->dev)->of_node,
+ "qcom,pipe-attr-ee");
+ SPS_DBG2("sps:PIPE_ATTR_EE is %s supported.\n",
+ (enhd_pipe ? "" : "not"));
+
return 0;
}
diff --git a/drivers/platform/msm/sps/sps_bam.c b/drivers/platform/msm/sps/sps_bam.c
index 80056f5..d972e7b 100644
--- a/drivers/platform/msm/sps/sps_bam.c
+++ b/drivers/platform/msm/sps/sps_bam.c
@@ -76,7 +76,9 @@
{SPS_EVENT_INACTIVE, SPS_O_INACTIVE, BAM_PIPE_IRQ_TIMER},
{SPS_EVENT_OUT_OF_DESC, SPS_O_OUT_OF_DESC,
BAM_PIPE_IRQ_OUT_OF_DESC},
- {SPS_EVENT_ERROR, SPS_O_ERROR, BAM_PIPE_IRQ_ERROR}
+ {SPS_EVENT_ERROR, SPS_O_ERROR, BAM_PIPE_IRQ_ERROR},
+ {SPS_EVENT_RST_ERROR, SPS_O_RST_ERROR, BAM_PIPE_IRQ_RST_ERROR},
+ {SPS_EVENT_HRESP_ERROR, SPS_O_HRESP_ERROR, BAM_PIPE_IRQ_HRESP_ERROR}
};
/* Pipe event source handler */
@@ -260,7 +262,8 @@
dev->props.options);
else
/* No, so just verify that it is enabled */
- rc = bam_check(dev->base, &dev->version, &num_pipes);
+ rc = bam_check(dev->base, &dev->version,
+ dev->props.ee, &num_pipes);
if (rc) {
SPS_ERR("sps:Fail to init BAM 0x%x IRQ %d\n",
@@ -1283,14 +1286,19 @@
desc->addr = addr;
desc->size = size;
+
if ((flags & SPS_IOVEC_FLAG_DEFAULT) == 0) {
- desc->flags = flags & BAM_IOVEC_FLAG_MASK;
+ desc->flags = (flags & BAM_IOVEC_FLAG_MASK)
+ | DESC_UPPER_ADDR(flags);
} else {
if (pipe->mode == SPS_MODE_SRC)
- desc->flags = SPS_IOVEC_FLAG_INT;
+ desc->flags = SPS_IOVEC_FLAG_INT
+ | DESC_UPPER_ADDR(flags);
else
- desc->flags = SPS_IOVEC_FLAG_INT | SPS_IOVEC_FLAG_EOT;
+ desc->flags = (SPS_IOVEC_FLAG_INT | SPS_IOVEC_FLAG_EOT)
+ | DESC_UPPER_ADDR(flags);
}
+
#ifdef SPS_BAM_STATISTICS
if ((flags & SPS_IOVEC_FLAG_INT))
pipe->sys.int_flags++;
@@ -1763,6 +1771,30 @@
return;
}
+ if ((status & SPS_O_RST_ERROR) && enhd_pipe) {
+ SPS_ERR("sps:bam 0x%x ;pipe 0x%x irq status=0x%x.\n"
+ "sps: BAM_PIPE_IRQ_RST_ERROR\n",
+ BAM_ID(dev), pipe_index, status);
+ bam_output_register_content(dev->base, dev->props.ee);
+ pipe_handler_generic(dev, pipe,
+ SPS_EVENT_RST_ERROR);
+ status &= ~SPS_O_RST_ERROR;
+ if (status == 0)
+ return;
+ }
+
+ if ((status & SPS_O_HRESP_ERROR) && enhd_pipe) {
+ SPS_ERR("sps:bam 0x%x ;pipe 0x%x irq status=0x%x.\n"
+ "sps: BAM_PIPE_IRQ_HRESP_ERROR\n",
+ BAM_ID(dev), pipe_index, status);
+ bam_output_register_content(dev->base, dev->props.ee);
+ pipe_handler_generic(dev, pipe,
+ SPS_EVENT_HRESP_ERROR);
+ status &= ~SPS_O_HRESP_ERROR;
+ if (status == 0)
+ return;
+ }
+
if ((status & SPS_EVENT_ERROR))
pipe_handler_generic(dev, pipe, SPS_EVENT_ERROR);
}
diff --git a/drivers/platform/msm/sps/sps_bam.h b/drivers/platform/msm/sps/sps_bam.h
index dede487..da5dafd 100644
--- a/drivers/platform/msm/sps/sps_bam.h
+++ b/drivers/platform/msm/sps/sps_bam.h
@@ -50,6 +50,10 @@
BAM_PIPE_IRQ_ERROR = 0x00000010,
/* End-Of-Transfer */
BAM_PIPE_IRQ_EOT = 0x00000020,
+ /* Pipe RESET unsuccessful */
+ BAM_PIPE_IRQ_RST_ERROR = 0x00000040,
+ /* Errorneous Hresponse by AHB MASTER */
+ BAM_PIPE_IRQ_HRESP_ERROR = 0x00000080,
};
/* Halt Type */
diff --git a/drivers/platform/msm/sps/sps_map.c b/drivers/platform/msm/sps/sps_map.c
index d007b31..70735c3 100644
--- a/drivers/platform/msm/sps/sps_map.c
+++ b/drivers/platform/msm/sps/sps_map.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, 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
@@ -96,16 +96,16 @@
*/
desc = spsi_get_mem_ptr(map->desc_base);
if (desc == NULL) {
- SPS_ERR("sps:Cannot get virt addr for I/O buffer: 0x%x",
- map->desc_base);
+ SPS_ERR("sps:Cannot get virt addr for I/O buffer: %pa\n",
+ &map->desc_base);
return SPS_ERROR;
}
if (map->data_size > 0 && map->data_base != SPS_ADDR_INVALID) {
data = spsi_get_mem_ptr(map->data_base);
if (data == NULL) {
- SPS_ERR("sps:Can't get virt addr for I/O buffer: 0x%x",
- map->data_base);
+ SPS_ERR("sps:Can't get virt addr for I/O buffer: %pa",
+ &map->data_base);
return SPS_ERROR;
}
} else {
diff --git a/drivers/platform/msm/sps/sps_map.h b/drivers/platform/msm/sps/sps_map.h
index 7db8043..7ee4713 100644
--- a/drivers/platform/msm/sps/sps_map.h
+++ b/drivers/platform/msm/sps/sps_map.h
@@ -1,4 +1,4 @@
-/* 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
@@ -36,9 +36,9 @@
/* Resource parameters */
u32 config; /* Configuration (stream) identifier */
- u32 desc_base; /* Physical address of descriptor FIFO */
+ phys_addr_t desc_base; /* Physical address of descriptor FIFO */
u32 desc_size; /* Size (bytes) of descriptor FIFO */
- u32 data_base; /* Physical address of data FIFO */
+ phys_addr_t data_base; /* Physical address of data FIFO */
u32 data_size; /* Size (bytes) of data FIFO */
};
diff --git a/drivers/platform/msm/sps/sps_mem.c b/drivers/platform/msm/sps/sps_mem.c
index b44e3c4..faa1618 100644
--- a/drivers/platform/msm/sps/sps_mem.c
+++ b/drivers/platform/msm/sps/sps_mem.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, 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,7 +25,7 @@
#include "sps_bam.h"
#include "spsi.h"
-static u32 iomem_phys;
+static phys_addr_t iomem_phys;
static void *iomem_virt;
static u32 iomem_size;
static u32 iomem_offset;
@@ -40,7 +40,7 @@
* Translate physical to virtual address
*
*/
-void *spsi_get_mem_ptr(u32 phys_addr)
+void *spsi_get_mem_ptr(phys_addr_t phys_addr)
{
void *virt = NULL;
@@ -49,8 +49,8 @@
virt = (u8 *) iomem_virt + (phys_addr - iomem_phys);
} else {
virt = phys_to_virt(phys_addr);
- SPS_ERR("sps:spsi_get_mem_ptr.invalid phys addr=0x%x.",
- phys_addr);
+ SPS_ERR("sps:spsi_get_mem_ptr.invalid phys addr=0x%pa.",
+ &phys_addr);
}
return virt;
}
@@ -59,9 +59,9 @@
* Allocate I/O (pipe) memory
*
*/
-u32 sps_mem_alloc_io(u32 bytes)
+phys_addr_t sps_mem_alloc_io(u32 bytes)
{
- u32 phys_addr = SPS_ADDR_INVALID;
+ phys_addr_t phys_addr = SPS_ADDR_INVALID;
u32 virt_addr = 0;
virt_addr = gen_pool_alloc(pool, bytes);
@@ -74,8 +74,8 @@
return SPS_ADDR_INVALID;
}
- SPS_DBG2("sps:sps_mem_alloc_io.phys=0x%x.virt=0x%x.size=0x%x.",
- phys_addr, virt_addr, bytes);
+ SPS_DBG2("sps:sps_mem_alloc_io.phys=%pa.virt=0x%x.size=0x%x.",
+ &phys_addr, virt_addr, bytes);
return phys_addr;
}
@@ -84,15 +84,15 @@
* Free I/O memory
*
*/
-void sps_mem_free_io(u32 phys_addr, u32 bytes)
+void sps_mem_free_io(phys_addr_t phys_addr, u32 bytes)
{
u32 virt_addr = 0;
iomem_offset = phys_addr - iomem_phys;
virt_addr = (u32) iomem_virt + iomem_offset;
- SPS_DBG2("sps:sps_mem_free_io.phys=0x%x.virt=0x%x.size=0x%x.",
- phys_addr, virt_addr, bytes);
+ SPS_DBG2("sps:sps_mem_free_io.phys=%pa.virt=0x%x.size=0x%x.",
+ &phys_addr, virt_addr, bytes);
gen_pool_free(pool, virt_addr, bytes);
total_free += bytes;
@@ -102,7 +102,7 @@
* Initialize driver memory module
*
*/
-int sps_mem_init(u32 pipemem_phys_base, u32 pipemem_size)
+int sps_mem_init(phys_addr_t pipemem_phys_base, u32 pipemem_size)
{
int res;
@@ -125,8 +125,8 @@
}
iomem_offset = 0;
- SPS_DBG("sps:sps_mem_init.iomem_phys=0x%x,iomem_virt=0x%x.",
- iomem_phys, (u32) iomem_virt);
+ SPS_DBG("sps:sps_mem_init.iomem_phys=%pa,iomem_virt=0x%x.",
+ &iomem_phys, (u32) iomem_virt);
}
pool = gen_pool_create(min_alloc_order, nid);
diff --git a/drivers/platform/msm/sps/sps_rm.c b/drivers/platform/msm/sps/sps_rm.c
index 2b46203..7d7e1a6 100644
--- a/drivers/platform/msm/sps/sps_rm.c
+++ b/drivers/platform/msm/sps/sps_rm.c
@@ -499,8 +499,8 @@
map->desc.phys_base = map->alloc_desc_base;
map->desc.base = spsi_get_mem_ptr(map->desc.phys_base);
if (map->desc.base == NULL) {
- SPS_ERR("sps:Cannot get virt addr for I/O buffer:0x%x",
- map->desc.phys_base);
+ SPS_ERR("sps:Cannot get virt addr for I/O buffer:%pa",
+ &map->desc.phys_base);
goto exit_err;
}
}
@@ -516,8 +516,8 @@
map->data.phys_base = map->alloc_data_base;
map->data.base = spsi_get_mem_ptr(map->data.phys_base);
if (map->data.base == NULL) {
- SPS_ERR("sps:Cannot get virt addr for I/O buffer:0x%x",
- map->data.phys_base);
+ SPS_ERR("sps:Cannot get virt addr for I/O buffer:%pa",
+ &map->data.phys_base);
goto exit_err;
}
}
diff --git a/drivers/platform/msm/sps/spsi.h b/drivers/platform/msm/sps/spsi.h
index 8da3b40..f65fef7 100644
--- a/drivers/platform/msm/sps/spsi.h
+++ b/drivers/platform/msm/sps/spsi.h
@@ -27,6 +27,12 @@
#include "sps_map.h"
+#ifdef CONFIG_ARM_LPAE
+#define SPS_LPAE (true)
+#else
+#define SPS_LPAE (false)
+#endif
+
#define BAM_MAX_PIPES 31
#define BAM_MAX_P_LOCK_GROUP_NUM 31
@@ -43,6 +49,7 @@
#define MAX_MSG_LEN 80
extern u32 d_type;
+extern bool enhd_pipe;
#ifdef CONFIG_DEBUG_FS
extern u8 debugfs_record_enabled;
@@ -165,8 +172,9 @@
/* Dynamically allocated resouces, if required */
u32 alloc_src_pipe; /* Source pipe index */
u32 alloc_dest_pipe; /* Destination pipe index */
- u32 alloc_desc_base; /* Physical address of descriptor FIFO */
- u32 alloc_data_base; /* Physical address of data FIFO */
+ /* Physical address of descriptor FIFO */
+ phys_addr_t alloc_desc_base;
+ phys_addr_t alloc_data_base; /* Physical address of data FIFO */
};
/* Event bookkeeping descriptor struct */
@@ -218,7 +226,7 @@
* @return virtual memory pointer
*
*/
-void *spsi_get_mem_ptr(u32 phys_addr);
+void *spsi_get_mem_ptr(phys_addr_t phys_addr);
/**
* Allocate I/O (pipe) memory
@@ -229,7 +237,7 @@
*
* @return physical address of allocated memory, or SPS_ADDR_INVALID on error
*/
-u32 sps_mem_alloc_io(u32 bytes);
+phys_addr_t sps_mem_alloc_io(u32 bytes);
/**
* Free I/O (pipe) memory
@@ -240,7 +248,7 @@
*
* @bytes - number of bytes to free.
*/
-void sps_mem_free_io(u32 phys_addr, u32 bytes);
+void sps_mem_free_io(phys_addr_t phys_addr, u32 bytes);
/**
* Find matching connection mapping
@@ -324,7 +332,7 @@
* @return 0 on success, negative value on error
*
*/
-int sps_mem_init(u32 pipemem_phys_base, u32 pipemem_size);
+int sps_mem_init(phys_addr_t pipemem_phys_base, u32 pipemem_size);
/**
* De-initialize driver memory module
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index 4889a79..408681c 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -140,6 +140,7 @@
int bus_suspend;
bool disconnected;
bool in_lpm[MAX_BAMS];
+ bool pending_lpm;
int (*wake_cb)(void *);
void *wake_param;
@@ -634,15 +635,25 @@
static void usb_bam_start_lpm(bool disconnect)
{
struct usb_phy *trans = usb_get_transceiver();
+
BUG_ON(trans == NULL);
- pr_debug("%s: Going to LPM\n", __func__);
+
spin_lock(&usb_bam_ipa_handshake_info_lock);
+
info.lpm_wait_handshake[HSUSB_BAM] = false;
info.lpm_wait_pipes = 0;
+
if (disconnect)
pm_runtime_put_noidle(trans->dev);
- spin_unlock(&usb_bam_ipa_handshake_info_lock);
- pm_runtime_suspend(trans->dev);
+
+ if (info.pending_lpm) {
+ info.pending_lpm = 0;
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ pr_debug("%s: Going to LPM\n", __func__);
+ pm_runtime_suspend(trans->dev);
+ } else
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+
}
int usb_bam_connect(u8 idx, u32 *bam_pipe_idx)
@@ -1058,10 +1069,11 @@
info.connect_complete = 1;
spin_unlock(&usb_bam_ipa_handshake_info_lock);
- if (info.cur_cons_state[HSUSB_BAM] == IPA_RM_RESOURCE_GRANTED) {
- pr_debug("%s: Notify CONS_GRANTED\n", __func__);
+ if (info.cur_cons_state[cur_bam] == IPA_RM_RESOURCE_GRANTED) {
+ pr_debug("%s: Notify %s_CONS_GRANTED\n", __func__,
+ bam_enable_strings[cur_bam]);
ipa_rm_notify_completion(IPA_RM_RESOURCE_GRANTED,
- ipa_rm_resource_cons[HSUSB_BAM]);
+ ipa_rm_resource_cons[cur_bam]);
}
}
@@ -1438,6 +1450,7 @@
info.lpm_wait_handshake[HSUSB_BAM] = true;
info.connect_complete = 0;
info.disconnected = 0;
+ info.pending_lpm = 0;
info.lpm_wait_pipes = 1;
info.bus_suspend = 0;
info.cons_stopped = 0;
@@ -1493,7 +1506,7 @@
ctx.pipes_enabled_per_bam[cur_bam] += 1;
spin_unlock(&usb_bam_lock);
- if (ipa_params->dir == PEER_PERIPHERAL_TO_USB && cur_bam == HSUSB_BAM)
+ if (ipa_params->dir == PEER_PERIPHERAL_TO_USB)
notify_usb_connected(cur_bam);
if (cur_bam == HSUSB_BAM)
@@ -1998,8 +2011,18 @@
ipa_rm_notify_completion(IPA_RM_RESOURCE_RELEASED,
ipa_rm_resource_cons[cur_bam]);
}
- pr_debug("%s Ended disconnect sequence\n", __func__);
- usb_bam_start_lpm(1);
+
+ if (cur_bam == HSUSB_BAM) {
+ /*
+ * Currently we have for HSUSB BAM only one consumer
+ * pipe. Therefore ending disconnect sequence and
+ * starting hsusb lpm. This limitation will be changed
+ * in future patch.
+ */
+ pr_debug("%s Ended disconnect sequence\n", __func__);
+ usb_bam_start_lpm(1);
+ }
+
mutex_unlock(&info.suspend_resume_mutex);
return 0;
}
@@ -2138,6 +2161,7 @@
u8 i = 0;
bool reset_bam;
enum usb_bam bam;
+ u32 addr;
ctx.max_connections = 0;
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
@@ -2154,9 +2178,11 @@
}
rc = of_property_read_u32(node, "qcom,usb-bam-fifo-baseaddr",
- &pdata->usb_bam_fifo_baseaddr);
+ &addr);
if (rc)
pr_debug("%s: Invalid usb base address property\n", __func__);
+ else
+ pdata->usb_bam_fifo_baseaddr = addr;
pdata->ignore_core_reset_ack = of_property_read_bool(node,
"qcom,ignore-core-reset-ack");
@@ -2629,10 +2655,12 @@
{
spin_lock(&usb_bam_ipa_handshake_info_lock);
if (info.lpm_wait_handshake[HSUSB_BAM] || info.lpm_wait_pipes) {
+ info.pending_lpm = 1;
spin_unlock(&usb_bam_ipa_handshake_info_lock);
pr_err("%s: Scheduling LPM for later\n", __func__);
return 0;
} else {
+ info.pending_lpm = 0;
info.in_lpm[HSUSB_BAM] = true;
spin_unlock(&usb_bam_ipa_handshake_info_lock);
pr_err("%s: Going to LPM now\n", __func__);
@@ -2641,6 +2669,16 @@
}
EXPORT_SYMBOL(msm_bam_lpm_ok);
+void msm_bam_notify_lpm_resume()
+{
+ /*
+ * If core was resumed from lpm, just clear the
+ * pending indication, in case it is set.
+ */
+ info.pending_lpm = 0;
+}
+EXPORT_SYMBOL(msm_bam_notify_lpm_resume);
+
static int usb_bam_remove(struct platform_device *pdev)
{
destroy_workqueue(ctx.usb_bam_wq);
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 1fd4434..b518f1f 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -22,8 +22,8 @@
#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
#include <linux/mfd/pm8xxx/pm8921-charger.h>
#include <linux/mfd/pm8xxx/ccadc.h>
-#include <linux/mfd/pm8xxx/batterydata-lib.h>
#include <linux/mfd/pm8xxx/batt-alarm.h>
+#include <linux/batterydata-lib.h>
#include <linux/interrupt.h>
#include <linux/bitops.h>
#include <linux/debugfs.h>
@@ -2118,6 +2118,10 @@
if (the_chip->start_percent == -EINVAL)
return prev_soc;
+ /* do not scale at 100 */
+ if (new_soc == 100)
+ return new_soc;
+
chg_time_sec = DIV_ROUND_UP(the_chip->charge_time_us, USEC_PER_SEC);
catch_up_sec = DIV_ROUND_UP(the_chip->catch_up_time_us, USEC_PER_SEC);
if (catch_up_sec == 0)
@@ -2501,7 +2505,7 @@
}
/* last_soc < soc ... scale and catch up */
- if (last_soc != -EINVAL && last_soc < soc && soc != 100)
+ if (last_soc != -EINVAL && last_soc < soc)
soc = scale_soc_while_chg(chip, delta_time_us, soc, last_soc);
if (last_soc != -EINVAL) {
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index 1ad7f21..d5b2cc6 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -2616,8 +2616,7 @@
{
if (usb_target_ma)
schedule_delayed_work(&the_chip->vin_collapse_check_work,
- round_jiffies_relative(msecs_to_jiffies
- (VIN_MIN_COLLAPSE_CHECK_MS)));
+ msecs_to_jiffies(VIN_MIN_COLLAPSE_CHECK_MS));
else
handle_usb_insertion_removal(data);
return IRQ_HANDLED;
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index 11e6cc1..982c30b 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -147,7 +147,9 @@
POWER_SUPPLY_ATTR(voltage_min_design),
POWER_SUPPLY_ATTR(voltage_now),
POWER_SUPPLY_ATTR(voltage_avg),
+ POWER_SUPPLY_ATTR(input_voltage_regulation),
POWER_SUPPLY_ATTR(current_max),
+ POWER_SUPPLY_ATTR(input_current_max),
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 12aef1c..86d923d 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -25,11 +25,11 @@
#include <linux/delay.h>
#include <linux/qpnp/qpnp-adc.h>
#include <linux/qpnp/power-on.h>
-#include <linux/mfd/pm8xxx/batterydata-lib.h>
+#include <linux/of_batterydata.h>
/* BMS Register Offsets */
-#define BMS1_REVISION1 0x0
-#define BMS1_REVISION2 0x1
+#define REVISION1 0x0
+#define REVISION2 0x1
#define BMS1_STATUS1 0x8
#define BMS1_MODE_CTL 0X40
/* Coulomb counter clear registers */
@@ -64,15 +64,16 @@
/* Extra bms registers */
#define SOC_STORAGE_REG 0xB0
#define IAVG_STORAGE_REG 0xB1
-#define BMS_BATT_REMOVED_REG 0xB2
-#define BMS1_BMS_DATA_REG_3 0xB3
-#define CHARGE_INCREASE_STORAGE 0xB4
-#define FCC_BATT_TEMP_STORAGE 0xB5
-#define FCC_STORAGE_LSB 0xBC /* LSB=0xBC, MSB=0xBD */
+#define BMS_FCC_COUNT 0xB2
+#define BMS_FCC_BASE_REG 0xB3 /* FCC updates - 0xB3 to 0xB7 */
+#define BMS_CHGCYL_BASE_REG 0xB8 /* FCC chgcyl - 0xB8 to 0xBC */
+#define CHARGE_INCREASE_STORAGE 0xBD
#define CHARGE_CYCLE_STORAGE_LSB 0xBE /* LSB=0xBE, MSB=0xBF */
/* IADC Channel Select */
#define IADC1_BMS_ADC_CH_SEL_CTL 0x48
+#define IADC1_BMS_ADC_INT_RSNSN_CTL 0x49
+#define IADC1_BMS_FAST_AVG_EN 0x5B
/* Configuration for saving of shutdown soc/iavg */
#define IGNORE_SOC_TEMP_DECIDEG 50
@@ -84,8 +85,11 @@
#define IAVG_SAMPLES 16
/* FCC learning constants */
+#define MAX_FCC_CYCLES 5
#define DELTA_FCC_PERCENT 5
#define VALID_FCC_CHGCYL_RANGE 50
+#define CHGCYL_RESOLUTION 20
+#define FCC_DEFAULT_TEMP 250
#define QPNP_BMS_DEV_NAME "qcom,qpnp-bms"
@@ -116,9 +120,8 @@
int last_good_ocv_uv;
};
-struct fcc_data {
+struct fcc_sample {
int fcc_new;
- int batt_temp;
int chargecycles;
};
@@ -135,6 +138,7 @@
struct qpnp_bms_chip {
struct device *dev;
struct power_supply bms_psy;
+ bool bms_psy_registered;
struct power_supply *batt_psy;
struct spmi_device *spmi;
u16 base;
@@ -142,6 +146,10 @@
u8 revision1;
u8 revision2;
+
+ u8 iadc_bms_revision1;
+ u8 iadc_bms_revision2;
+
int battery_present;
int battery_status;
bool new_battery;
@@ -243,7 +251,8 @@
int ocv_low_threshold_uv;
unsigned long last_recalc_time;
- struct fcc_data *fcc_table;
+ struct fcc_sample *fcc_learning_samples;
+ u8 fcc_sample_count;
int enable_fcc_learning;
int min_fcc_learning_soc;
int min_fcc_ocv_pc;
@@ -258,8 +267,8 @@
int fcc_new_batt_temp;
uint16_t charge_cycles;
u8 charge_increase;
- int fcc_new_sysfs;
- int fcc_update_complete;
+ int fcc_resolution;
+ bool battery_removed;
struct bms_irq sw_cc_thr_irq;
struct bms_irq ocv_thr_irq;
};
@@ -280,48 +289,14 @@
POWER_SUPPLY_PROP_CHARGE_COUNTER,
POWER_SUPPLY_PROP_CHARGE_COUNTER_SHADOW,
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+ POWER_SUPPLY_PROP_CHARGE_FULL,
POWER_SUPPLY_PROP_CYCLE_COUNT,
};
+static int discard_backup_fcc_data(struct qpnp_bms_chip *chip);
+static void backup_charge_cycle(struct qpnp_bms_chip *chip);
+
static bool bms_reset;
-static int min_fcc_cycles = -EINVAL;
-static int last_fcc_update_count;
-static int battery_removed;
-
-static int
-bms_ro_ops_set(const char *val, const struct kernel_param *kp)
-{
- return -EINVAL;
-}
-
-static int
-bms_last_fcc_count_set(const char *val, const struct kernel_param *kp)
-{
- int rc;
-
- if (battery_removed) {
- last_fcc_update_count = 0;
- return 0;
- }
- rc = param_set_int(val, kp);
- if (rc)
- pr_err("Failed to set last_fcc_update_count rc=%d\n", rc);
-
- return rc;
-}
-
-static struct kernel_param_ops bms_ro_param_ops = {
- .set = bms_ro_ops_set,
- .get = param_get_int,
-};
-static struct kernel_param_ops bms_last_fcc_count_param_ops = {
- .set = bms_last_fcc_count_set,
- .get = param_get_int,
-};
-module_param_cb(min_fcc_cycles, &bms_ro_param_ops, &min_fcc_cycles, 0644);
-module_param_cb(battery_removed, &bms_ro_param_ops, &battery_removed, 0644);
-module_param_cb(last_fcc_update_count, &bms_last_fcc_count_param_ops,
- &last_fcc_update_count, 0644);
static int qpnp_read_wrapper(struct qpnp_bms_chip *chip, u8 *val,
u16 base, int count)
@@ -869,6 +844,19 @@
chip->last_cc_uah = INT_MIN;
chip->last_ocv_temp = batt_temp;
chip->prev_batt_terminal_uv = 0;
+ if (chip->enable_fcc_learning) {
+ chip->adjusted_fcc_temp_lut = NULL;
+ chip->fcc_new_mah = -EINVAL;
+ /* reset the charge-cycle and charge-increase registers */
+ chip->charge_increase = 0;
+ chip->charge_cycles = 0;
+ backup_charge_cycle(chip);
+ /* discard all the FCC learnt data and reset the local table */
+ discard_backup_fcc_data(chip);
+ memset(chip->fcc_learning_samples, 0,
+ chip->min_fcc_learning_samples *
+ sizeof(struct fcc_sample));
+ }
}
#define OCV_RAW_UNINITIALIZED 0xFFFF
@@ -1413,6 +1401,21 @@
return chip->fcc_mah * 1000;
}
+/* Returns the current full charge in uAh */
+static int get_prop_bms_charge_full(struct qpnp_bms_chip *chip)
+{
+ int rc;
+ struct qpnp_vadc_result result;
+
+ rc = qpnp_vadc_read(LR_MUX1_BATT_THERM, &result);
+ if (rc) {
+ pr_err("Unable to read battery temperature\n");
+ return rc;
+ }
+
+ return calculate_fcc(chip, (int)result.physical);
+}
+
static int calculate_delta_time(unsigned long *time_stamp, int *delta_time_s)
{
unsigned long now_tm_sec = 0;
@@ -1467,7 +1470,7 @@
if (params->rbatt_mohm != chip->rbatt_mohm) {
chip->rbatt_mohm = params->rbatt_mohm;
- if (chip->bms_psy.name != NULL)
+ if (chip->bms_psy_registered)
power_supply_changed(&chip->bms_psy);
}
@@ -2272,8 +2275,7 @@
}
mutex_unlock(&chip->last_soc_mutex);
- if (new_calculated_soc != previous_soc
- && chip->bms_psy.name != NULL) {
+ if (new_calculated_soc != previous_soc && chip->bms_psy_registered) {
power_supply_changed(&chip->bms_psy);
pr_debug("power supply changed\n");
} else {
@@ -2307,7 +2309,7 @@
voltage_based_soc = clamp(voltage_based_soc, 0, 100);
if (chip->prev_voltage_based_soc != voltage_based_soc
- && chip->bms_psy.name != NULL) {
+ && chip->bms_psy_registered) {
power_supply_changed(&chip->bms_psy);
pr_debug("power supply changed\n");
}
@@ -2326,12 +2328,14 @@
bms_stay_awake(&chip->soc_wake_source);
mutex_lock(&chip->vbat_monitor_mutex);
- qpnp_adc_tm_channel_measure(&chip->vbat_monitor_params);
+ if (chip->vbat_monitor_params.state_request !=
+ ADC_TM_HIGH_LOW_THR_DISABLE)
+ qpnp_adc_tm_channel_measure(&chip->vbat_monitor_params);
mutex_unlock(&chip->vbat_monitor_mutex);
if (chip->use_voltage_soc) {
soc = calculate_soc_from_voltage(chip);
} else {
- qpnp_iadc_calibrate_for_trim();
+ qpnp_iadc_calibrate_for_trim(true);
rc = qpnp_vadc_read(LR_MUX1_BATT_THERM, &result);
if (rc) {
pr_err("error reading vadc LR_MUX1_BATT_THERM = %d, rc = %d\n",
@@ -2514,7 +2518,7 @@
} else {
pr_debug("unknown voltage notification state: %d\n", state);
}
- if (chip->bms_psy.name != NULL)
+ if (chip->bms_psy_registered)
power_supply_changed(&chip->bms_psy);
}
@@ -2523,9 +2527,10 @@
int rc;
chip->vbat_monitor_params.state_request = ADC_TM_HIGH_LOW_THR_DISABLE;
- rc = qpnp_adc_tm_channel_measure(&chip->vbat_monitor_params);
+
+ rc = qpnp_adc_tm_disable_chan_meas(&chip->vbat_monitor_params);
if (rc) {
- pr_err("tm measure failed: %d\n", rc);
+ pr_err("tm disable failed: %d\n", rc);
return rc;
}
if (wake_lock_active(&chip->low_voltage_wake_lock)) {
@@ -2549,11 +2554,6 @@
return -EPROBE_DEFER;
}
- if (!is_battery_present(chip)) {
- pr_debug("no battery inserted, do not setup vbat monitoring\n");
- return 0;
- }
-
chip->vbat_monitor_params.low_thr = chip->low_voltage_threshold;
chip->vbat_monitor_params.high_thr = chip->max_voltage_uv
- VBATT_ERROR_MARGIN;
@@ -2565,10 +2565,17 @@
pr_debug("set low thr to %d and high to %d\n",
chip->vbat_monitor_params.low_thr,
chip->vbat_monitor_params.high_thr);
- rc = qpnp_adc_tm_channel_measure(&chip->vbat_monitor_params);
- if (rc) {
- pr_err("tm setup failed: %d\n", rc);
- return rc;
+
+ if (!is_battery_present(chip)) {
+ pr_debug("no battery inserted, do not enable vbat monitoring\n");
+ chip->vbat_monitor_params.state_request =
+ ADC_TM_HIGH_LOW_THR_DISABLE;
+ } else {
+ rc = qpnp_adc_tm_channel_measure(&chip->vbat_monitor_params);
+ if (rc) {
+ pr_err("tm setup failed: %d\n", rc);
+ return rc;
+ }
}
pr_debug("setup complete\n");
return 0;
@@ -2608,26 +2615,85 @@
kfree(old);
}
-
-static void backup_fcc_new(struct qpnp_bms_chip *chip)
+static int read_fcc_data_from_backup(struct qpnp_bms_chip *chip)
{
- int rc = 0;
- u8 temp = 0;
+ int rc, i;
+ u8 fcc = 0, chgcyl = 0;
- if (chip->fcc_new_mah > 0) {
- rc = qpnp_write_wrapper(chip, (u8 *)&chip->fcc_new_mah,
- chip->base + FCC_STORAGE_LSB, 2);
- if (rc)
- pr_err("Unable to backup new_fcc\n");
-
- temp = chip->fcc_new_batt_temp / 10;
- rc = qpnp_write_wrapper(chip, &temp,
- chip->base + FCC_BATT_TEMP_STORAGE, 1);
- if (rc)
- pr_err("Unable to backup fcc temp.\n");
+ for (i = 0; i < chip->min_fcc_learning_samples; i++) {
+ rc = qpnp_read_wrapper(chip, &fcc,
+ chip->base + BMS_FCC_BASE_REG + i, 1);
+ rc |= qpnp_read_wrapper(chip, &chgcyl,
+ chip->base + BMS_CHGCYL_BASE_REG + i, 1);
+ if (rc) {
+ pr_err("Unable to read FCC data\n");
+ return rc;
+ }
+ if (fcc == 0 || (fcc == 0xFF && chgcyl == 0xFF)) {
+ /* FCC invalid/not present */
+ chip->fcc_learning_samples[i].fcc_new = 0;
+ chip->fcc_learning_samples[i].chargecycles = 0;
+ } else {
+ /* valid FCC data */
+ chip->fcc_sample_count++;
+ chip->fcc_learning_samples[i].fcc_new =
+ fcc * chip->fcc_resolution;
+ chip->fcc_learning_samples[i].chargecycles =
+ chgcyl * CHGCYL_RESOLUTION;
+ }
}
+
+ return 0;
}
+static int discard_backup_fcc_data(struct qpnp_bms_chip *chip)
+{
+ int rc = 0, i;
+ u8 temp_u8 = 0;
+
+ chip->fcc_sample_count = 0;
+ for (i = 0; i < chip->min_fcc_learning_samples; i++) {
+ rc = qpnp_write_wrapper(chip, &temp_u8,
+ chip->base + BMS_FCC_BASE_REG + i, 1);
+ rc |= qpnp_write_wrapper(chip, &temp_u8,
+ chip->base + BMS_CHGCYL_BASE_REG + i, 1);
+ if (rc) {
+ pr_err("Unable to clear FCC data\n");
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+static void
+average_fcc_samples_and_readjust_fcc_table(struct qpnp_bms_chip *chip)
+{
+ int i, temp_fcc_avg = 0, temp_fcc_delta = 0, new_fcc_avg = 0;
+ struct fcc_sample *ft;
+
+ for (i = 0; i < chip->min_fcc_learning_samples; i++)
+ temp_fcc_avg += chip->fcc_learning_samples[i].fcc_new;
+
+ temp_fcc_avg /= chip->min_fcc_learning_samples;
+ temp_fcc_delta = div_u64(temp_fcc_avg * DELTA_FCC_PERCENT, 100);
+
+ /* fix the fcc if its an outlier i.e. > 5% of the average */
+ for (i = 0; i < chip->min_fcc_learning_samples; i++) {
+ ft = &chip->fcc_learning_samples[i];
+ if (abs(ft->fcc_new - temp_fcc_avg) > temp_fcc_delta)
+ new_fcc_avg += temp_fcc_avg;
+ else
+ new_fcc_avg += ft->fcc_new;
+ }
+ new_fcc_avg /= chip->min_fcc_learning_samples;
+
+ chip->fcc_new_mah = new_fcc_avg;
+ chip->fcc_new_batt_temp = FCC_DEFAULT_TEMP;
+ pr_info("FCC update: New fcc_mah=%d, fcc_batt_temp=%d\n",
+ new_fcc_avg, FCC_DEFAULT_TEMP);
+ readjust_fcc_table(chip);
+}
static void backup_charge_cycle(struct qpnp_bms_chip *chip)
{
@@ -2635,7 +2701,7 @@
if (chip->charge_increase >= 0) {
rc = qpnp_write_wrapper(chip, &chip->charge_increase,
- chip->base + CHARGE_INCREASE_STORAGE, 1);
+ chip->base + CHARGE_INCREASE_STORAGE, 1);
if (rc)
pr_err("Unable to backup charge_increase\n");
}
@@ -2648,9 +2714,31 @@
}
}
-static void restore_fcc_data(struct qpnp_bms_chip *chip)
+static bool chargecycles_in_range(struct qpnp_bms_chip *chip)
{
- int rc = 0;
+ int i, min_cycle, max_cycle, valid_range;
+
+ /* find the smallest and largest charge cycle */
+ max_cycle = min_cycle = chip->fcc_learning_samples[0].chargecycles;
+ for (i = 1; i < chip->min_fcc_learning_samples; i++) {
+ if (min_cycle > chip->fcc_learning_samples[i].chargecycles)
+ min_cycle = chip->fcc_learning_samples[i].chargecycles;
+ if (max_cycle < chip->fcc_learning_samples[i].chargecycles)
+ max_cycle = chip->fcc_learning_samples[i].chargecycles;
+ }
+
+ /* check if chargecyles are in range to continue with FCC update */
+ valid_range = DIV_ROUND_UP(VALID_FCC_CHGCYL_RANGE,
+ CHGCYL_RESOLUTION) * CHGCYL_RESOLUTION;
+ if (abs(max_cycle - min_cycle) > valid_range)
+ return false;
+
+ return true;
+}
+
+static int read_chgcycle_data_from_backup(struct qpnp_bms_chip *chip)
+{
+ int rc;
uint16_t temp_u16 = 0;
u8 temp_u8 = 0;
@@ -2664,25 +2752,18 @@
if (!rc && temp_u16 != 0xFFFF)
chip->charge_cycles = temp_u16;
- rc = qpnp_read_wrapper(chip, (u8 *)&temp_u16,
- chip->base + FCC_STORAGE_LSB, 2);
- if (!rc && temp_u16 != 0xFFFF) {
- chip->fcc_new_mah = temp_u16;
- } else {
- pr_debug("Backed-up FCC not initialized, FCC not updated\n");
- return;
- }
+ return rc;
+}
- rc = qpnp_read_wrapper(chip, &temp_u8,
- chip->base + FCC_BATT_TEMP_STORAGE, 1);
- if (!rc && temp_u8 != 0xFF) {
- chip->fcc_new_batt_temp = (s8)temp_u8 * 10;
- } else {
- pr_debug("Backed-up temp. not initialized, FCC not updated\n");
- return;
- }
- /* readjust the FCC table if fcc and temp are valid */
- readjust_fcc_table(chip);
+static void
+attempt_learning_new_fcc(struct qpnp_bms_chip *chip)
+{
+ pr_debug("Total FCC sample count=%d\n", chip->fcc_sample_count);
+
+ /* update FCC if we have the required samples */
+ if ((chip->fcc_sample_count == chip->min_fcc_learning_samples) &&
+ chargecycles_in_range(chip))
+ average_fcc_samples_and_readjust_fcc_table(chip);
}
static int calculate_real_soc(struct qpnp_bms_chip *chip,
@@ -2696,82 +2777,80 @@
return ((rc_uah - cc_uah) * 100) / fcc_uah;
}
-static void update_fcc_table_for_temp(struct qpnp_bms_chip *chip,
- int batt_temp_final)
-{
- int i, fcc_t1, fcc_t2, fcc_final;
- struct fcc_data *ft;
+#define MAX_U8_VALUE ((u8)(~0U))
- /* Interpolate all the FCC entries to the same temperature */
- for (i = 0; i < chip->min_fcc_learning_samples; i++) {
- ft = &chip->fcc_table[i];
- if (ft->batt_temp == batt_temp_final)
- continue;
- fcc_t1 = interpolate_fcc(chip->fcc_temp_lut, ft->batt_temp);
- fcc_t2 = interpolate_fcc(chip->fcc_temp_lut, batt_temp_final);
- fcc_final = (ft->fcc_new / fcc_t1) * fcc_t2;
- ft->fcc_new = fcc_final;
- ft->batt_temp = batt_temp_final;
+static int backup_new_fcc(struct qpnp_bms_chip *chip, int fcc_mah,
+ int chargecycles)
+{
+ int rc, min_cycle, i;
+ u8 fcc_new, chgcyl, pos = 0;
+ struct fcc_sample *ft;
+
+ if ((fcc_mah > (chip->fcc_resolution * MAX_U8_VALUE)) ||
+ (chargecycles > (CHGCYL_RESOLUTION * MAX_U8_VALUE))) {
+ pr_warn("FCC/Chgcyl beyond storage limit. FCC=%d, chgcyl=%d\n",
+ fcc_mah, chargecycles);
+ return -EINVAL;
}
+
+ if (chip->fcc_sample_count == chip->min_fcc_learning_samples) {
+ /* search best location - oldest entry */
+ min_cycle = chip->fcc_learning_samples[0].chargecycles;
+ for (i = 1; i < chip->min_fcc_learning_samples; i++) {
+ if (min_cycle >
+ chip->fcc_learning_samples[i].chargecycles)
+ pos = i;
+ }
+ } else {
+ /* find an empty location */
+ for (i = 0; i < chip->min_fcc_learning_samples; i++) {
+ ft = &chip->fcc_learning_samples[i];
+ if (ft->fcc_new == 0 || (ft->fcc_new == 0xFF &&
+ ft->chargecycles == 0xFF)) {
+ pos = i;
+ break;
+ }
+ }
+ chip->fcc_sample_count++;
+ }
+ chip->fcc_learning_samples[pos].fcc_new = fcc_mah;
+ chip->fcc_learning_samples[pos].chargecycles = chargecycles;
+
+ fcc_new = DIV_ROUND_UP(fcc_mah, chip->fcc_resolution);
+ rc = qpnp_write_wrapper(chip, (u8 *)&fcc_new,
+ chip->base + BMS_FCC_BASE_REG + pos, 1);
+ if (rc)
+ return rc;
+
+ chgcyl = DIV_ROUND_UP(chargecycles, CHGCYL_RESOLUTION);
+ rc = qpnp_write_wrapper(chip, (u8 *)&chgcyl,
+ chip->base + BMS_CHGCYL_BASE_REG + pos, 1);
+ if (rc)
+ return rc;
+
+ pr_debug("Backup new FCC: fcc_new=%d, chargecycle=%d, pos=%d\n",
+ fcc_new, chgcyl, pos);
+
+ return rc;
}
static void update_fcc_learning_table(struct qpnp_bms_chip *chip,
- int fcc_uah, int new_fcc_uah, int chargecycles, int batt_temp)
+ int new_fcc_uah, int chargecycles, int batt_temp)
{
- int i, count, new_fcc_avg = 0, temp_fcc_avg = 0, temp_fcc_delta = 0;
- struct fcc_data *ft;
+ int rc, fcc_default, fcc_temp;
- count = last_fcc_update_count % chip->min_fcc_learning_samples;
- ft = &chip->fcc_table[count];
- ft->fcc_new = chip->fcc_new_sysfs = new_fcc_uah;
- ft->batt_temp = batt_temp;
- ft->chargecycles = chargecycles;
- last_fcc_update_count++;
- /* update userspace */
- sysfs_notify(&chip->dev->kobj, NULL, "fcc_data");
+ /* convert the fcc at batt_temp to new fcc at FCC_DEFAULT_TEMP */
+ fcc_default = calculate_fcc(chip, FCC_DEFAULT_TEMP) / 1000;
+ fcc_temp = calculate_fcc(chip, batt_temp) / 1000;
+ new_fcc_uah = (new_fcc_uah / fcc_temp) * fcc_default;
- pr_debug("Updated fcc table. new_fcc=%d, chargecycle=%d, temp=%d fcc_update_count=%d\n",
- new_fcc_uah, chargecycles, batt_temp, last_fcc_update_count);
-
- if (last_fcc_update_count < chip->min_fcc_learning_samples) {
- pr_debug("Not enough FCC samples. Current count = %d\n",
- last_fcc_update_count);
- return; /* Not enough samples to update fcc */
+ rc = backup_new_fcc(chip, new_fcc_uah / 1000, chargecycles);
+ if (rc) {
+ pr_err("Unable to backup new FCC\n");
+ return;
}
-
- /* reject entries if they are > 50 chargecycles apart */
- for (i = 0; i < chip->min_fcc_learning_samples; i++) {
- if ((chip->fcc_table[i].chargecycles + VALID_FCC_CHGCYL_RANGE)
- < chargecycles) {
- pr_debug("Charge cycle too old (> %d cycles apart)\n",
- VALID_FCC_CHGCYL_RANGE);
- return; /* Samples old, > 50 cycles apart*/
- }
- }
- /* update the fcc table for temperature difference*/
- update_fcc_table_for_temp(chip, batt_temp);
-
- for (i = 0; i < chip->min_fcc_learning_samples; i++)
- temp_fcc_avg += chip->fcc_table[i].fcc_new;
-
- temp_fcc_avg /= chip->min_fcc_learning_samples;
- temp_fcc_delta = div_u64(temp_fcc_avg * DELTA_FCC_PERCENT, 100);
-
- /* fix the fcc if its an outlier i.e. > 5% of the average */
- for (i = 0; i < chip->min_fcc_learning_samples; i++) {
- ft = &chip->fcc_table[i];
- if (abs(ft->fcc_new - temp_fcc_avg) > temp_fcc_delta)
- ft->fcc_new = temp_fcc_avg;
- new_fcc_avg += ft->fcc_new;
- }
- new_fcc_avg /= chip->min_fcc_learning_samples;
-
- chip->fcc_new_mah = new_fcc_avg / 1000;
- chip->fcc_new_batt_temp = batt_temp;
- pr_info("FCC update: New fcc_mah=%d, fcc_batt_temp=%d\n",
- new_fcc_avg, batt_temp);
- readjust_fcc_table(chip);
- backup_fcc_new(chip);
+ /* check if FCC can be updated */
+ attempt_learning_new_fcc(chip);
}
static bool is_new_fcc_valid(int new_fcc_uah, int fcc_uah)
@@ -2825,8 +2904,8 @@
chip->start_cc_uah, chip->end_cc_uah, new_fcc_uah);
if (is_new_fcc_valid(new_fcc_uah, fcc_uah))
- update_fcc_learning_table(chip, fcc_uah,
- new_fcc_uah, chip->charge_cycles, batt_temp);
+ update_fcc_learning_table(chip, new_fcc_uah,
+ chip->charge_cycles, batt_temp);
}
}
@@ -2922,6 +3001,8 @@
}
}
+#define CALIB_WRKARND_DIG_MAJOR_MAX 0x03
+
static void battery_insertion_check(struct qpnp_bms_chip *chip)
{
bool present = is_battery_present(chip);
@@ -2985,6 +3066,9 @@
case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
val->intval = get_prop_bms_charge_full_design(chip);
break;
+ case POWER_SUPPLY_PROP_CHARGE_FULL:
+ val->intval = get_prop_bms_charge_full(chip);
+ break;
case POWER_SUPPLY_PROP_CYCLE_COUNT:
val->intval = chip->charge_cycles;
break;
@@ -2994,123 +3078,6 @@
return 0;
}
-static ssize_t fcc_data_set(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct qpnp_bms_chip *chip = dev_get_drvdata(dev);
- static int i;
- int fcc_new = 0, rc;
-
- if (chip->fcc_update_complete) {
- pr_debug("Invalid FCC update\n");
- return count;
- }
-
- i %= chip->min_fcc_learning_samples;
- rc = sscanf(buf, "%d", &fcc_new);
- if (rc != 1)
- return -EINVAL;
- chip->fcc_table[i].fcc_new = fcc_new;
- pr_debug("Rcvd: [%d] fcc_new=%d\n", i, fcc_new);
- i++;
-
- return count;
-}
-
-static ssize_t fcc_data_get(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- int count = 0;
- struct qpnp_bms_chip *chip = dev_get_drvdata(dev);
-
- count = snprintf(buf, PAGE_SIZE, "%d", chip->fcc_new_sysfs);
- pr_debug("Sent: fcc_new=%d\n", chip->fcc_new_sysfs);
- chip->fcc_update_complete = 1;
-
- return count;
-}
-
-static ssize_t fcc_temp_set(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- static int i;
- int batt_temp = 0, rc;
- struct qpnp_bms_chip *chip = dev_get_drvdata(dev);
-
- if (chip->fcc_update_complete)
- return count;
-
- i %= chip->min_fcc_learning_samples;
- rc = sscanf(buf, "%d", &batt_temp);
- if (rc != 1)
- return -EINVAL;
- chip->fcc_table[i].batt_temp = batt_temp;
- pr_debug("Rcvd: [%d] batt_temp=%d\n", i, batt_temp);
- i++;
-
- return count;
-}
-
-static ssize_t fcc_chgcyl_set(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- static int i;
- int chargecycle = 0, rc;
- struct qpnp_bms_chip *chip = dev_get_drvdata(dev);
-
- if (chip->fcc_update_complete)
- return count;
-
- i %= chip->min_fcc_learning_samples;
- rc = sscanf(buf, "%d", &chargecycle);
- if (rc != 1)
- return -EINVAL;
- chip->fcc_table[i].chargecycles = chargecycle;
- pr_debug("Rcvd: [%d] chargecycle=%d\n", i, chargecycle);
- i++;
-
- return count;
-}
-
-static ssize_t fcc_list_get(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct qpnp_bms_chip *chip = dev_get_drvdata(dev);
- struct fcc_data *ft;
- int i = 0, j, count = 0;
-
- if (last_fcc_update_count < chip->min_fcc_learning_samples)
- i = last_fcc_update_count;
- else
- i = chip->min_fcc_learning_samples;
-
- for (j = 0; j < i; j++) {
- ft = &chip->fcc_table[j];
- count += snprintf(buf + count, PAGE_SIZE - count,
- "%d %d %d\n", ft->fcc_new, ft->chargecycles,
- ft->batt_temp);
- }
-
- return count;
-}
-
-static DEVICE_ATTR(fcc_data, 0664, fcc_data_get, fcc_data_set);
-static DEVICE_ATTR(fcc_temp, 0664, NULL, fcc_temp_set);
-static DEVICE_ATTR(fcc_chgcyl, 0664, NULL, fcc_chgcyl_set);
-static DEVICE_ATTR(fcc_list, 0664, fcc_list_get, NULL);
-
-static struct attribute *fcc_attrs[] = {
- &dev_attr_fcc_data.attr,
- &dev_attr_fcc_temp.attr,
- &dev_attr_fcc_chgcyl.attr,
- &dev_attr_fcc_list.attr,
- NULL
-};
-
-static const struct attribute_group fcc_attr_group = {
- .attrs = fcc_attrs,
-};
-
#define OCV_USE_LIMIT_EN BIT(7)
static int set_ocv_voltage_thresholds(struct qpnp_bms_chip *chip,
int low_voltage_threshold,
@@ -3194,10 +3161,19 @@
}
}
- pr_debug("shutdown_soc = %d shutdown_iavg = %d shutdown_soc_invalid = %d\n",
+ /* read the SOC storage to determine if there was a battery removal */
+ rc = qpnp_read_wrapper(chip, &temp, chip->base + SOC_STORAGE_REG, 1);
+ if (!rc) {
+ if (temp == SOC_INVALID)
+ chip->battery_removed = true;
+ }
+
+
+ pr_debug("shutdown_soc = %d shutdown_iavg = %d shutdown_soc_invalid = %d, battery_removed = %d\n",
chip->shutdown_soc,
chip->shutdown_iavg_ma,
- chip->shutdown_soc_invalid);
+ chip->shutdown_soc_invalid,
+ chip->battery_removed);
}
static irqreturn_t bms_ocv_thr_irq_handler(int irq, void *_chip)
@@ -3220,11 +3196,7 @@
return IRQ_HANDLED;
}
-#define PALLADIUM_ID_MIN 0x7F40
-#define PALLADIUM_ID_MAX 0x7F5A
-#define DESAY_5200_ID_MIN 0x7F7F
-#define DESAY_5200_ID_MAX 0x802F
-static int32_t read_battery_id(struct qpnp_bms_chip *chip)
+static int64_t read_battery_id(struct qpnp_bms_chip *chip)
{
int rc;
struct qpnp_vadc_result result;
@@ -3235,16 +3207,16 @@
LR_MUX2_BAT_ID, rc);
return rc;
}
- pr_debug("batt_id phy = %lld meas = 0x%llx\n", result.physical,
- result.measurement);
- pr_debug("raw_code = 0x%x\n", result.adc_code);
- return result.adc_code;
+
+ return result.physical;
}
static int set_battery_data(struct qpnp_bms_chip *chip)
{
int64_t battery_id;
+ int rc;
struct bms_battery_data *batt_data;
+ struct device_node *node;
if (chip->batt_type == BATT_DESAY) {
batt_data = &desay_5200_data;
@@ -3264,12 +3236,30 @@
return battery_id;
}
- if (is_between(PALLADIUM_ID_MIN, PALLADIUM_ID_MAX,
- battery_id)) {
- batt_data = &palladium_1500_data;
- } else if (is_between(DESAY_5200_ID_MIN, DESAY_5200_ID_MAX,
- battery_id)) {
- batt_data = &desay_5200_data;
+ node = of_find_node_by_name(chip->spmi->dev.of_node,
+ "qcom,battery-data");
+ if (node) {
+ batt_data = kzalloc(sizeof(struct bms_battery_data),
+ GFP_KERNEL);
+ batt_data->fcc_temp_lut = kzalloc(
+ sizeof(struct single_row_lut),
+ GFP_KERNEL);
+ batt_data->pc_temp_ocv_lut = kzalloc(
+ sizeof(struct pc_temp_ocv_lut),
+ GFP_KERNEL);
+ batt_data->rbatt_sf_lut = kzalloc(
+ sizeof(struct sf_lut), GFP_KERNEL);
+
+ rc = of_batterydata_read_data(node,
+ batt_data, battery_id);
+ if (rc) {
+ pr_err("battery data load failed, using palladium 1500\n");
+ kfree(batt_data->fcc_temp_lut);
+ kfree(batt_data->pc_temp_ocv_lut);
+ kfree(batt_data->rbatt_sf_lut);
+ kfree(batt_data);
+ batt_data = &palladium_1500_data;
+ }
} else {
pr_warn("invalid battid, palladium 1500 assumed batt_id %llx\n",
battery_id);
@@ -3287,6 +3277,14 @@
chip->rbatt_capacitive_mohm = batt_data->rbatt_capacitive_mohm;
chip->flat_ocv_threshold_uv = batt_data->flat_ocv_threshold_uv;
+ /* Override battery properties if specified in the battery profile */
+ if (batt_data->max_voltage_uv >= 0)
+ chip->max_voltage_uv = batt_data->max_voltage_uv;
+ if (batt_data->cutoff_uv >= 0)
+ chip->v_cutoff_uv = batt_data->cutoff_uv;
+ if (batt_data->iterm_ua >= 0)
+ chip->chg_term_ua = batt_data->iterm_ua;
+
if (chip->pc_temp_ocv_lut == NULL) {
pr_err("temp ocv lut table is NULL\n");
return -EINVAL;
@@ -3306,6 +3304,12 @@
} \
} while (0)
+#define SPMI_PROP_READ_BOOL(chip_prop, qpnp_spmi_property) \
+do { \
+ chip->chip_prop = of_property_read_bool(chip->spmi->dev.of_node,\
+ "qcom," qpnp_spmi_property); \
+} while (0)
+
static inline int bms_read_properties(struct qpnp_bms_chip *chip)
{
int rc;
@@ -3352,8 +3356,7 @@
if (chip->adjust_soc_low_threshold >= 45)
chip->adjust_soc_low_threshold = 45;
- chip->enable_fcc_learning = of_property_read_bool(
- chip->spmi->dev.of_node, "qcom,enable-fcc-learning");
+ SPMI_PROP_READ_BOOL(enable_fcc_learning, "enable-fcc-learning");
if (chip->enable_fcc_learning) {
SPMI_PROP_READ(min_fcc_learning_soc,
"min-fcc-learning-soc", rc);
@@ -3361,12 +3364,16 @@
"min-fcc-ocv-pc", rc);
SPMI_PROP_READ(min_fcc_learning_samples,
"min-fcc-learning-samples", rc);
- chip->fcc_table = kzalloc((sizeof(struct fcc_data) *
- chip->min_fcc_learning_samples), GFP_KERNEL);
+ SPMI_PROP_READ(fcc_resolution,
+ "fcc-resolution", rc);
+ if (chip->min_fcc_learning_samples > MAX_FCC_CYCLES)
+ chip->min_fcc_learning_samples = MAX_FCC_CYCLES;
+ chip->fcc_learning_samples = devm_kzalloc(&chip->spmi->dev,
+ (sizeof(struct fcc_sample) *
+ chip->min_fcc_learning_samples), GFP_KERNEL);
pr_debug("min-fcc-soc=%d, min-fcc-pc=%d, min-fcc-cycles=%d\n",
chip->min_fcc_learning_soc, chip->min_fcc_ocv_pc,
chip->min_fcc_learning_samples);
- min_fcc_cycles = chip->min_fcc_learning_samples;
}
pr_debug("dts data: r_sense_uohm:%d, v_cutoff_uv:%d, max_v:%d\n",
@@ -3400,7 +3407,7 @@
chip->first_time_calc_uuc = 1;
}
-#define SPMI_SETUP_IRQ(irq_name) \
+#define SPMI_FIND_IRQ(chip, irq_name) \
do { \
chip->irq_name##_irq.irq = spmi_get_irq_byname(chip->spmi, \
resource, #irq_name); \
@@ -3408,6 +3415,18 @@
pr_err("Unable to get " #irq_name " irq\n"); \
return -ENXIO; \
} \
+} while (0)
+
+static int bms_find_irqs(struct qpnp_bms_chip *chip,
+ struct spmi_resource *resource)
+{
+ SPMI_FIND_IRQ(chip, sw_cc_thr);
+ SPMI_FIND_IRQ(chip, ocv_thr);
+ return 0;
+}
+
+#define SPMI_REQUEST_IRQ(chip, rc, irq_name) \
+do { \
rc = devm_request_irq(chip->dev, chip->irq_name##_irq.irq, \
bms_##irq_name##_irq_handler, \
IRQF_TRIGGER_RISING, #irq_name, chip); \
@@ -3417,14 +3436,13 @@
} \
} while (0)
-static int bms_setup_irqs(struct qpnp_bms_chip *chip,
- struct spmi_resource *resource)
+static int bms_request_irqs(struct qpnp_bms_chip *chip)
{
int rc;
- SPMI_SETUP_IRQ(sw_cc_thr);
+ SPMI_REQUEST_IRQ(chip, rc, sw_cc_thr);
enable_irq_wake(chip->sw_cc_thr_irq.irq);
- SPMI_SETUP_IRQ(ocv_thr);
+ SPMI_REQUEST_IRQ(chip, rc, ocv_thr);
enable_irq_wake(chip->ocv_thr_irq.irq);
return 0;
}
@@ -3476,9 +3494,9 @@
if (type == BMS_BMS_TYPE && subtype == BMS_BMS1_SUBTYPE) {
chip->base = resource->start;
- rc = bms_setup_irqs(chip, spmi_resource);
+ rc = bms_find_irqs(chip, spmi_resource);
if (rc) {
- pr_err("Could not register irqs\n");
+ pr_err("Could not find irqs\n");
return rc;
}
} else if (type == BMS_IADC_TYPE
@@ -3503,7 +3521,11 @@
return 0;
}
-#define ADC_CH_SEL_MASK 0x7
+#define ADC_CH_SEL_MASK 0x7
+#define ADC_INT_RSNSN_CTL_MASK 0x3
+#define ADC_INT_RSNSN_CTL_VALUE_EXT_RENSE 0x2
+#define FAST_AVG_EN_MASK 0x80
+#define FAST_AVG_EN_VALUE_EXT_RSENSE 0x80
static int read_iadc_channel_select(struct qpnp_bms_chip *chip)
{
u8 iadc_channel_select;
@@ -3571,6 +3593,34 @@
pr_debug("rds_rsense = %d nOhm, saved as %d uOhm\n",
rds_rsense_nohm, chip->r_sense_uohm);
}
+ /* prevent shorting of leads by IADC_BMS when external Rsense is used */
+ if (chip->use_external_rsense) {
+ if (chip->iadc_bms_revision2 > CALIB_WRKARND_DIG_MAJOR_MAX) {
+ rc = qpnp_masked_write_iadc(chip,
+ IADC1_BMS_ADC_INT_RSNSN_CTL,
+ ADC_INT_RSNSN_CTL_MASK,
+ ADC_INT_RSNSN_CTL_VALUE_EXT_RENSE);
+ if (rc) {
+ pr_err("Unable to set batfet config %x to %x: %d\n",
+ IADC1_BMS_ADC_INT_RSNSN_CTL,
+ ADC_INT_RSNSN_CTL_VALUE_EXT_RENSE, rc);
+ return rc;
+ }
+ } else {
+ /* In older PMICS use FAST_AVG_EN register bit 7 */
+ rc = qpnp_masked_write_iadc(chip,
+ IADC1_BMS_FAST_AVG_EN,
+ FAST_AVG_EN_MASK,
+ FAST_AVG_EN_VALUE_EXT_RSENSE);
+ if (rc) {
+ pr_err("Unable to set batfet config %x to %x: %d\n",
+ IADC1_BMS_FAST_AVG_EN,
+ FAST_AVG_EN_VALUE_EXT_RSENSE, rc);
+ return rc;
+ }
+ }
+ }
+
return 0;
}
@@ -3632,28 +3682,6 @@
return 0;
}
-static void check_battery_removal(struct qpnp_bms_chip *chip)
-{
- int rc;
- u8 temp = 0;
-
- /* check if battery was removed at PON */
- rc = qpnp_read_wrapper(chip, &temp,
- chip->base + BMS_BATT_REMOVED_REG, 1);
- if (temp == 0xFF) {
- pr_debug("New battery inserted at PON\n");
- temp = battery_removed = 1;
- rc = qpnp_write_wrapper(chip, &temp,
- chip->base + BMS_BATT_REMOVED_REG, 1);
- if (rc)
- pr_err("Unable to set BMS_BATT_REMOVED_REG\n");
- } else {
- if (rc)
- pr_err("Unable to read BMS_BATT_REMOVED_REG\n");
- battery_removed = 0;
- }
-}
-
static int __devinit qpnp_bms_probe(struct spmi_device *spmi)
{
struct qpnp_bms_chip *chip;
@@ -3681,6 +3709,12 @@
goto error_read;
}
+ mutex_init(&chip->bms_output_lock);
+ mutex_init(&chip->last_ocv_uv_mutex);
+ mutex_init(&chip->vbat_monitor_mutex);
+ mutex_init(&chip->soc_invalidation_mutex);
+ mutex_init(&chip->last_soc_mutex);
+
warm_reset = qpnp_pon_is_warm_reset();
rc = warm_reset;
if (rc < 0)
@@ -3693,20 +3727,36 @@
}
rc = qpnp_read_wrapper(chip, &chip->revision1,
- chip->base + BMS1_REVISION1, 1);
+ chip->base + REVISION1, 1);
if (rc) {
pr_err("error reading version register %d\n", rc);
goto error_read;
}
rc = qpnp_read_wrapper(chip, &chip->revision2,
- chip->base + BMS1_REVISION2, 1);
+ chip->base + REVISION2, 1);
if (rc) {
pr_err("Error reading version register %d\n", rc);
goto error_read;
}
pr_debug("BMS version: %hhu.%hhu\n", chip->revision2, chip->revision1);
+ rc = qpnp_read_wrapper(chip, &chip->iadc_bms_revision2,
+ chip->iadc_base + REVISION2, 1);
+ if (rc) {
+ pr_err("Error reading version register %d\n", rc);
+ goto error_read;
+ }
+
+ rc = qpnp_read_wrapper(chip, &chip->iadc_bms_revision1,
+ chip->iadc_base + REVISION1, 1);
+ if (rc) {
+ pr_err("Error reading version register %d\n", rc);
+ goto error_read;
+ }
+ pr_debug("IADC_BMS version: %hhu.%hhu\n",
+ chip->iadc_bms_revision2, chip->iadc_bms_revision1);
+
rc = bms_read_properties(chip);
if (rc) {
pr_err("Unable to read all bms properties, rc = %d\n", rc);
@@ -3738,12 +3788,6 @@
bms_initialize_constants(chip);
- mutex_init(&chip->bms_output_lock);
- mutex_init(&chip->last_ocv_uv_mutex);
- mutex_init(&chip->vbat_monitor_mutex);
- mutex_init(&chip->soc_invalidation_mutex);
- mutex_init(&chip->last_soc_mutex);
-
wakeup_source_init(&chip->soc_wake_source.source, "qpnp_soc_wake");
wake_lock_init(&chip->low_voltage_wake_lock, WAKE_LOCK_SUSPEND,
"qpnp_low_voltage_lock");
@@ -3756,20 +3800,26 @@
read_shutdown_soc_and_iavg(chip);
if (chip->enable_fcc_learning) {
- restore_fcc_data(chip);
- rc = sysfs_create_group(&spmi->dev.kobj, &fcc_attr_group);
- if (rc) {
- pr_err("Unable to create sysfs entries\n");
- goto error_setup;
+ if (chip->battery_removed) {
+ rc = discard_backup_fcc_data(chip);
+ if (rc)
+ pr_err("Could not discard backed-up FCC data\n");
+ } else {
+ rc = read_chgcycle_data_from_backup(chip);
+ if (rc)
+ pr_err("Unable to restore charge-cycle data\n");
+
+ rc = read_fcc_data_from_backup(chip);
+ if (rc)
+ pr_err("Unable to restore FCC-learning data\n");
+ else
+ attempt_learning_new_fcc(chip);
}
}
dev_set_drvdata(&spmi->dev, chip);
device_init_wakeup(&spmi->dev, 1);
- check_battery_removal(chip);
-
-
rc = setup_vbat_monitoring(chip);
if (rc < 0) {
pr_err("failed to set up voltage notifications: %d\n", rc);
@@ -3805,6 +3855,7 @@
goto unregister_dc;
}
+ chip->bms_psy_registered = true;
vbatt = 0;
rc = get_battery_voltage(&vbatt);
if (rc) {
@@ -3813,12 +3864,19 @@
goto unregister_dc;
}
+ rc = bms_request_irqs(chip);
+ if (rc) {
+ pr_err("error requesting bms irqs, rc = %d\n", rc);
+ goto unregister_dc;
+ }
+
pr_info("probe success: soc =%d vbatt = %d ocv = %d r_sense_uohm = %u warm_reset = %d\n",
get_prop_bms_capacity(chip), vbatt, chip->last_ocv_uv,
chip->r_sense_uohm, warm_reset);
return 0;
unregister_dc:
+ chip->bms_psy_registered = false;
power_supply_unregister(&chip->bms_psy);
error_setup:
dev_set_drvdata(&spmi->dev, NULL);
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 85bdd67..88e00ba 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -28,6 +28,7 @@
#include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/machine.h>
+#include <linux/of_batterydata.h>
/* Interrupt offsets */
#define INT_RT_STS(base) (base + 0x10)
@@ -98,6 +99,7 @@
#define BOOST_VSET 0x41
#define BOOST_ENABLE_CONTROL 0x46
#define COMP_OVR1 0xEA
+#define BAT_IF_BTC_CTRL 0x49
#define REG_OFFSET_PERP_SUBTYPE 0x05
@@ -222,6 +224,7 @@
* @dc_present: present status of dc
* @batt_present: present status of battery
* @use_default_batt_values: flag to report default battery properties
+ * @btc_disabled Flag to disable btc (disables hot and cold irqs)
* @max_voltage_mv: the max volts the batt should be charged up to
* @min_voltage_mv: min battery voltage before turning the FET on
* @max_bat_chg_current: maximum battery charge current in mA
@@ -234,6 +237,8 @@
* @safe_current: battery safety current setting
* @maxinput_usb_ma: Maximum Input current USB
* @maxinput_dc_ma: Maximum Input current DC
+ * @hot_batt_p Hot battery threshold setting
+ * @cold_batt_p Cold battery threshold setting
* @warm_bat_decidegc Warm battery temperature in degree Celsius
* @cool_bat_decidegc Cool battery temperature in degree Celsius
* @revision: PMIC revision
@@ -269,6 +274,7 @@
struct qpnp_chg_irq chg_failed;
struct qpnp_chg_irq chg_vbatdet_lo;
struct qpnp_chg_irq batt_pres;
+ struct qpnp_chg_irq vchg_loop;
bool bat_is_cool;
bool bat_is_warm;
bool chg_done;
@@ -276,6 +282,7 @@
bool dc_present;
bool batt_present;
bool charging_disabled;
+ bool btc_disabled;
bool use_default_batt_values;
bool duty_cycle_100p;
unsigned int bpd_detection;
@@ -285,14 +292,19 @@
unsigned int safe_voltage_mv;
unsigned int max_voltage_mv;
unsigned int min_voltage_mv;
+ int prev_usb_max_ma;
int set_vddmax_mv;
int delta_vddmax_mv;
unsigned int warm_bat_mv;
unsigned int cool_bat_mv;
unsigned int resume_delta_mv;
int term_current;
+ int soc_resume_limit;
+ bool resuming_charging;
unsigned int maxinput_usb_ma;
unsigned int maxinput_dc_ma;
+ unsigned int hot_batt_p;
+ unsigned int cold_batt_p;
unsigned int warm_bat_decidegc;
unsigned int cool_bat_decidegc;
unsigned int safe_current;
@@ -334,7 +346,21 @@
[BPD_TYPE_BAT_THM_BAT_ID] = "bpd_thm_id",
};
-static inline int
+enum btc_type {
+ HOT_THD_25_PCT = 25,
+ HOT_THD_35_PCT = 35,
+ COLD_THD_70_PCT = 70,
+ COLD_THD_80_PCT = 80,
+};
+
+static u8 btc_value[] = {
+ [HOT_THD_25_PCT] = 0x0,
+ [HOT_THD_35_PCT] = BIT(0),
+ [COLD_THD_70_PCT] = 0x0,
+ [COLD_THD_80_PCT] = BIT(1),
+};
+
+ static inline int
get_bpd(const char *name)
{
int i = 0;
@@ -627,6 +653,92 @@
return rc;
}
+#define QPNP_CHG_VINMIN_MIN_MV 4200
+#define QPNP_CHG_VINMIN_HIGH_MIN_MV 5600
+#define QPNP_CHG_VINMIN_HIGH_MIN_VAL 0x2B
+#define QPNP_CHG_VINMIN_MAX_MV 9600
+#define QPNP_CHG_VINMIN_STEP_MV 50
+#define QPNP_CHG_VINMIN_STEP_HIGH_MV 200
+#define QPNP_CHG_VINMIN_MASK 0x1F
+#define QPNP_CHG_VINMIN_MIN_VAL 0x10
+static int
+qpnp_chg_vinmin_set(struct qpnp_chg_chip *chip, int voltage)
+{
+ u8 temp;
+
+ if (voltage < QPNP_CHG_VINMIN_MIN_MV
+ || voltage > QPNP_CHG_VINMIN_MAX_MV) {
+ pr_err("bad mV=%d asked to set\n", voltage);
+ return -EINVAL;
+ }
+ if (voltage >= QPNP_CHG_VINMIN_HIGH_MIN_MV) {
+ temp = QPNP_CHG_VINMIN_HIGH_MIN_VAL;
+ temp += (voltage - QPNP_CHG_VINMIN_MIN_MV)
+ / QPNP_CHG_VINMIN_STEP_HIGH_MV;
+ } else {
+ temp = QPNP_CHG_VINMIN_MIN_VAL;
+ temp += (voltage - QPNP_CHG_VINMIN_MIN_MV)
+ / QPNP_CHG_VINMIN_STEP_MV;
+ }
+
+ pr_debug("voltage=%d setting %02x\n", voltage, temp);
+ return qpnp_chg_masked_write(chip,
+ chip->chgr_base + CHGR_VIN_MIN,
+ QPNP_CHG_VINMIN_MASK, temp, 1);
+}
+
+static int
+qpnp_chg_vinmin_get(struct qpnp_chg_chip *chip)
+{
+ int rc, vin_min_mv;
+ u8 vin_min;
+
+ rc = qpnp_chg_read(chip, &vin_min, chip->chgr_base + CHGR_VIN_MIN, 1);
+ if (rc) {
+ pr_err("failed to read VIN_MIN rc=%d\n", rc);
+ return 0;
+ }
+
+ if (vin_min == 0)
+ vin_min_mv = QPNP_CHG_I_MAX_MIN_100;
+ else if (vin_min > QPNP_CHG_VINMIN_HIGH_MIN_VAL)
+ vin_min_mv = QPNP_CHG_VINMIN_HIGH_MIN_MV +
+ (vin_min - QPNP_CHG_VINMIN_HIGH_MIN_VAL)
+ * QPNP_CHG_VINMIN_STEP_HIGH_MV;
+ else
+ vin_min_mv = QPNP_CHG_VINMIN_MIN_MV +
+ (vin_min - QPNP_CHG_VINMIN_MIN_VAL)
+ * QPNP_CHG_VINMIN_STEP_MV;
+ pr_debug("vin_min= 0x%02x, ma = %d\n", vin_min, vin_min_mv);
+
+ return vin_min_mv;
+}
+
+static int
+qpnp_chg_usb_iusbmax_get(struct qpnp_chg_chip *chip)
+{
+ int rc, iusbmax_ma;
+ u8 iusbmax;
+
+ rc = qpnp_chg_read(chip, &iusbmax,
+ chip->usb_chgpth_base + CHGR_I_MAX_REG, 1);
+ if (rc) {
+ pr_err("failed to read IUSB_MAX rc=%d\n", rc);
+ return 0;
+ }
+
+ if (iusbmax == 0)
+ iusbmax_ma = QPNP_CHG_I_MAX_MIN_100;
+ else if (iusbmax == 0x01)
+ iusbmax_ma = QPNP_CHG_I_MAX_MIN_150;
+ else
+ iusbmax_ma = iusbmax * QPNP_CHG_I_MAXSTEP_MA;
+
+ pr_debug("iusbmax = 0x%02x, ma = %d\n", iusbmax, iusbmax_ma);
+
+ return iusbmax_ma;
+}
+
#define USB_SUSPEND_BIT BIT(0)
static int
qpnp_chg_usb_suspend_enable(struct qpnp_chg_chip *chip, int enable)
@@ -736,6 +848,23 @@
}
static void
+qpnp_chg_set_appropriate_vbatdet(struct qpnp_chg_chip *chip)
+{
+ if (chip->bat_is_cool)
+ qpnp_chg_vbatdet_set(chip, chip->cool_bat_mv
+ - chip->resume_delta_mv);
+ else if (chip->bat_is_warm)
+ qpnp_chg_vbatdet_set(chip, chip->warm_bat_mv
+ - chip->resume_delta_mv);
+ else if (chip->resuming_charging)
+ qpnp_chg_vbatdet_set(chip, chip->max_voltage_mv
+ + chip->resume_delta_mv);
+ else
+ qpnp_chg_vbatdet_set(chip, chip->max_voltage_mv
+ - chip->resume_delta_mv);
+}
+
+static void
qpnp_arb_stop_work(struct work_struct *work)
{
struct delayed_work *dwork = to_delayed_work(work);
@@ -757,6 +886,17 @@
pr_err("request ADC error\n");
}
+static irqreturn_t
+qpnp_chg_buck_vchg_loop_irq_handler(int irq, void *_chip)
+{
+ struct qpnp_chg_chip *chip = _chip;
+
+ if (chip->bat_if_base)
+ power_supply_changed(&chip->batt_psy);
+
+ return IRQ_HANDLED;
+}
+
#define EOC_CHECK_PERIOD_MS 10000
static irqreturn_t
qpnp_chg_vbatdet_lo_irq_handler(int irq, void *_chip)
@@ -827,6 +967,7 @@
if (!usb_present) {
qpnp_chg_usb_suspend_enable(chip, 1);
chip->chg_done = false;
+ chip->prev_usb_max_ma = -EINVAL;
} else {
schedule_delayed_work(&chip->eoc_work,
msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
@@ -926,6 +1067,12 @@
qpnp_chg_chgr_chg_fastchg_irq_handler(int irq, void *_chip)
{
struct qpnp_chg_chip *chip = _chip;
+ u8 chgr_sts;
+ int rc;
+
+ rc = qpnp_chg_read(chip, &chgr_sts, INT_RT_STS(chip->chgr_base), 1);
+ if (rc)
+ pr_err("failed to read interrupt sts %d\n", rc);
pr_debug("FAST_CHG IRQ triggered\n");
chip->chg_done = false;
@@ -934,7 +1081,16 @@
power_supply_changed(chip->usb_psy);
if (chip->dc_chgpth_base)
power_supply_changed(&chip->dc_psy);
+ if (chip->resuming_charging) {
+ chip->resuming_charging = false;
+ qpnp_chg_set_appropriate_vbatdet(chip);
+ }
+
qpnp_chg_enable_irq(&chip->chg_vbatdet_lo);
+ if (chgr_sts & FAST_CHG_ON_IRQ)
+ qpnp_chg_enable_irq(&chip->vchg_loop);
+ else
+ qpnp_chg_disable_irq(&chip->vchg_loop);
return IRQ_HANDLED;
}
@@ -960,6 +1116,8 @@
switch (psp) {
case POWER_SUPPLY_PROP_CHARGING_ENABLED:
case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL:
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_MAX:
+ case POWER_SUPPLY_PROP_VOLTAGE_MIN:
return 1;
default:
break;
@@ -1065,7 +1223,11 @@
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_INPUT_CURRENT_MAX,
+ POWER_SUPPLY_PROP_VOLTAGE_MIN,
+ POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION,
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+ POWER_SUPPLY_PROP_CHARGE_FULL,
POWER_SUPPLY_PROP_TEMP,
POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL,
POWER_SUPPLY_PROP_CYCLE_COUNT,
@@ -1079,6 +1241,9 @@
"bms",
};
+static int charger_monitor;
+module_param(charger_monitor, int, 0644);
+
#define USB_WALL_THRESHOLD_MA 500
static int
qpnp_power_get_property_mains(struct power_supply *psy,
@@ -1098,7 +1263,7 @@
val->intval = qpnp_chg_is_dc_chg_plugged_in(chip);
break;
case POWER_SUPPLY_PROP_CURRENT_MAX:
- val->intval = chip->maxinput_dc_ma;
+ val->intval = chip->maxinput_dc_ma * 1000;
break;
default:
return -EINVAL;
@@ -1245,6 +1410,22 @@
return 0;
}
+static int
+get_prop_charge_full(struct qpnp_chg_chip *chip)
+{
+ union power_supply_propval ret = {0,};
+
+ if (chip->bms_psy) {
+ chip->bms_psy->get_property(chip->bms_psy,
+ POWER_SUPPLY_PROP_CHARGE_FULL, &ret);
+ return ret.intval;
+ } else {
+ pr_debug("No BMS supply registered return 0\n");
+ }
+
+ return 0;
+}
+
#define DEFAULT_CAPACITY 50
static int
get_prop_capacity(struct qpnp_chg_chip *chip)
@@ -1257,6 +1438,16 @@
if (chip->bms_psy) {
chip->bms_psy->get_property(chip->bms_psy,
POWER_SUPPLY_PROP_CAPACITY, &ret);
+ if (get_prop_batt_status(chip) == POWER_SUPPLY_STATUS_FULL
+ && !chip->resuming_charging
+ && !chip->charging_disabled
+ && chip->soc_resume_limit
+ && ret.intval <= chip->soc_resume_limit) {
+ pr_debug("resuming charging at %d%% soc\n", ret.intval);
+ chip->resuming_charging = true;
+ qpnp_chg_set_appropriate_vbatdet(chip);
+ qpnp_chg_charge_en(chip, !chip->charging_disabled);
+ }
if (ret.intval == 0) {
if (!qpnp_chg_is_usb_chg_plugged_in(chip)
&& !qpnp_chg_is_usb_chg_plugged_in(chip))
@@ -1304,6 +1495,23 @@
return ret.intval;
}
+static int get_prop_vchg_loop(struct qpnp_chg_chip *chip)
+{
+ u8 buck_sts;
+ int rc;
+
+ rc = qpnp_chg_read(chip, &buck_sts, INT_RT_STS(chip->buck_base), 1);
+
+ if (rc) {
+ pr_err("spmi read failed: addr=%03X, rc=%d\n",
+ INT_RT_STS(chip->buck_base), rc);
+ return rc;
+ }
+ pr_debug("buck usb sts 0x%x\n", buck_sts);
+
+ return (buck_sts & VCHG_LOOP_IRQ) ? 1 : 0;
+}
+
static void
qpnp_batt_external_power_changed(struct power_supply *psy)
{
@@ -1321,16 +1529,28 @@
if (qpnp_chg_is_usb_chg_plugged_in(chip)) {
chip->usb_psy->get_property(chip->usb_psy,
POWER_SUPPLY_PROP_CURRENT_MAX, &ret);
+
+ if (chip->prev_usb_max_ma == ret.intval)
+ goto skip_set_iusb_max;
+
if (ret.intval <= 2 && !chip->use_default_batt_values &&
get_prop_batt_present(chip)) {
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);
- qpnp_chg_iusbmax_set(chip, ret.intval / 1000);
+ if (((ret.intval / 1000) > USB_WALL_THRESHOLD_MA)
+ && (charger_monitor)) {
+ qpnp_chg_iusbmax_set(chip,
+ USB_WALL_THRESHOLD_MA);
+ } else {
+ qpnp_chg_iusbmax_set(chip, ret.intval / 1000);
+ }
}
+ chip->prev_usb_max_ma = ret.intval;
}
+skip_set_iusb_max:
pr_debug("end of power supply changed\n");
power_supply_changed(&chip->batt_psy);
}
@@ -1380,6 +1600,9 @@
case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
val->intval = get_prop_full_design(chip);
break;
+ case POWER_SUPPLY_PROP_CHARGE_FULL:
+ val->intval = get_prop_charge_full(chip);
+ break;
case POWER_SUPPLY_PROP_CHARGING_ENABLED:
val->intval = !(chip->charging_disabled);
break;
@@ -1389,6 +1612,15 @@
case POWER_SUPPLY_PROP_CYCLE_COUNT:
val->intval = get_prop_cycle_count(chip);
break;
+ case POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION:
+ val->intval = get_prop_vchg_loop(chip);
+ break;
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_MAX:
+ val->intval = qpnp_chg_usb_iusbmax_get(chip) * 1000;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MIN:
+ val->intval = qpnp_chg_vinmin_get(chip) * 1000;
+ break;
default:
return -EINVAL;
}
@@ -1396,36 +1628,36 @@
return 0;
}
-#define QPNP_CHG_VINMIN_MIN_MV 3400
-#define QPNP_CHG_VINMIN_HIGH_MIN_MV 5600
-#define QPNP_CHG_VINMIN_HIGH_MIN_VAL 0x2B
-#define QPNP_CHG_VINMIN_MAX_MV 9600
-#define QPNP_CHG_VINMIN_STEP_MV 50
-#define QPNP_CHG_VINMIN_STEP_HIGH_MV 200
-#define QPNP_CHG_VINMIN_MASK 0x1F
+#define BTC_CONFIG_ENABLED BIT(7)
+#define BTC_COLD BIT(1)
+#define BTC_HOT BIT(0)
static int
-qpnp_chg_vinmin_set(struct qpnp_chg_chip *chip, int voltage)
+qpnp_chg_bat_if_configure_btc(struct qpnp_chg_chip *chip)
{
- u8 temp;
+ u8 btc_cfg = 0, mask = 0;
- if (voltage < QPNP_CHG_VINMIN_MIN_MV
- || voltage > QPNP_CHG_VINMIN_MAX_MV) {
- pr_err("bad mV=%d asked to set\n", voltage);
- return -EINVAL;
- }
- if (voltage >= QPNP_CHG_VINMIN_HIGH_MIN_MV) {
- temp = QPNP_CHG_VINMIN_HIGH_MIN_VAL;
- temp += (voltage - QPNP_CHG_VINMIN_MIN_MV)
- / QPNP_CHG_VINMIN_STEP_HIGH_MV;
- } else {
- temp = (voltage - QPNP_CHG_VINMIN_MIN_MV)
- / QPNP_CHG_VINMIN_STEP_MV;
+ /* Do nothing if battery peripheral not present */
+ if (!chip->bat_if_base)
+ return 0;
+
+ if ((chip->hot_batt_p == HOT_THD_25_PCT)
+ || (chip->hot_batt_p == HOT_THD_35_PCT)) {
+ btc_cfg |= btc_value[chip->hot_batt_p];
+ mask |= BTC_HOT;
}
- pr_debug("voltage=%d setting %02x\n", voltage, temp);
+ if ((chip->cold_batt_p == COLD_THD_70_PCT) ||
+ (chip->cold_batt_p == COLD_THD_80_PCT)) {
+ btc_cfg |= btc_value[chip->cold_batt_p];
+ mask |= BTC_COLD;
+ }
+
+ if (chip->btc_disabled)
+ mask |= BTC_CONFIG_ENABLED;
+
return qpnp_chg_masked_write(chip,
- chip->chgr_base + CHGR_VIN_MIN,
- QPNP_CHG_VINMIN_MASK, temp, 1);
+ chip->bat_if_base + BAT_IF_BTC_CTRL,
+ mask, btc_cfg, 1);
}
#define QPNP_CHG_IBATSAFE_MIN_MA 100
@@ -1601,20 +1833,6 @@
}
static void
-qpnp_chg_set_appropriate_vbatdet(struct qpnp_chg_chip *chip)
-{
- if (chip->bat_is_cool)
- qpnp_chg_vbatdet_set(chip, chip->cool_bat_mv
- - chip->resume_delta_mv);
- else if (chip->bat_is_warm)
- qpnp_chg_vbatdet_set(chip, chip->warm_bat_mv
- - chip->resume_delta_mv);
- else
- qpnp_chg_vbatdet_set(chip, chip->max_voltage_mv
- - chip->resume_delta_mv);
-}
-
-static void
qpnp_chg_set_appropriate_battery_current(struct qpnp_chg_chip *chip)
{
unsigned int chg_current = chip->max_bat_chg_current;
@@ -2056,7 +2274,16 @@
chip->bat_is_cool = bat_cool;
chip->bat_is_warm = bat_warm;
- /* set appropriate voltages and currents */
+ if (bat_cool || bat_warm)
+ chip->resuming_charging = false;
+
+ /**
+ * set appropriate voltages and currents.
+ *
+ * Note that when the battery is hot or cold, the charger
+ * driver will not resume with SoC. Only vbatdet is used to
+ * determine resume of charging.
+ */
qpnp_chg_set_appropriate_vddmax(chip);
qpnp_chg_set_appropriate_battery_current(chip);
qpnp_chg_set_appropriate_vbatdet(chip);
@@ -2113,6 +2340,12 @@
case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL:
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);
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MIN:
+ qpnp_chg_vinmin_set(chip, val->intval / 1000);
+ break;
default:
return -EINVAL;
}
@@ -2251,7 +2484,8 @@
}
rc = devm_request_irq(chip->dev, chip->batt_pres.irq,
qpnp_chg_bat_if_batt_pres_irq_handler,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
+ | IRQF_SHARED | IRQF_ONESHOT,
"batt-pres", chip);
if (rc < 0) {
pr_err("Can't request %d batt-pres irq: %d\n",
@@ -2261,6 +2495,29 @@
enable_irq_wake(chip->batt_pres.irq);
break;
+ case SMBB_BUCK_SUBTYPE:
+ case SMBBP_BUCK_SUBTYPE:
+ case SMBCL_BUCK_SUBTYPE:
+ chip->vchg_loop.irq = spmi_get_irq_byname(spmi,
+ spmi_resource, "vchg-loop");
+ if (chip->vchg_loop.irq < 0) {
+ pr_err("Unable to get vchg-loop irq\n");
+ return rc;
+ }
+ rc = devm_request_irq(chip->dev, chip->vchg_loop.irq,
+ qpnp_chg_buck_vchg_loop_irq_handler,
+ IRQF_TRIGGER_RISING,
+ "vchg-loop", chip);
+ if (rc < 0) {
+ pr_err("Can't request %d vchg-loop irq: %d\n",
+ chip->vchg_loop.irq, rc);
+ return rc;
+ }
+
+ enable_irq_wake(chip->vchg_loop.irq);
+ qpnp_chg_disable_irq(&chip->vchg_loop);
+ break;
+
case SMBB_USB_CHGPTH_SUBTYPE:
case SMBBP_USB_CHGPTH_SUBTYPE:
case SMBCL_USB_CHGPTH_SUBTYPE:
@@ -2324,6 +2581,41 @@
return rc;
}
+static int
+qpnp_chg_load_battery_data(struct qpnp_chg_chip *chip)
+{
+ struct bms_battery_data batt_data;
+ struct device_node *node;
+ struct qpnp_vadc_result result;
+ int rc;
+
+ node = of_find_node_by_name(chip->spmi->dev.of_node,
+ "qcom,battery-data");
+ if (node) {
+ memset(&batt_data, 0, sizeof(struct bms_battery_data));
+ rc = qpnp_vadc_read(LR_MUX2_BAT_ID, &result);
+ if (rc) {
+ pr_err("error reading batt id channel = %d, rc = %d\n",
+ LR_MUX2_BAT_ID, rc);
+ return rc;
+ }
+
+ rc = of_batterydata_read_data(node,
+ &batt_data, result.physical);
+ if (rc) {
+ pr_err("failed to read battery data: %d\n", rc);
+ return rc;
+ }
+
+ if (batt_data.max_voltage_uv >= 0)
+ chip->max_voltage_mv = batt_data.max_voltage_uv / 1000;
+ if (batt_data.iterm_ua >= 0)
+ chip->term_current = batt_data.iterm_ua / 1000;
+ }
+
+ return 0;
+}
+
#define WDOG_EN_BIT BIT(7)
static int
qpnp_chg_hwinit(struct qpnp_chg_chip *chip, u8 subtype,
@@ -2617,6 +2909,10 @@
OF_PROP_READ(chip, warm_bat_decidegc, "warm-bat-decidegc", rc, 1);
OF_PROP_READ(chip, cool_bat_decidegc, "cool-bat-decidegc", rc, 1);
OF_PROP_READ(chip, tchg_mins, "tchg-mins", rc, 1);
+ OF_PROP_READ(chip, hot_batt_p, "batt-hot-percentage", rc, 1);
+ OF_PROP_READ(chip, cold_batt_p, "batt-cold-percentage", rc, 1);
+ OF_PROP_READ(chip, soc_resume_limit, "resume-soc", rc, 1);
+
if (rc)
return rc;
@@ -2649,6 +2945,10 @@
return rc;
}
+ /* Get the btc-disabled property */
+ chip->btc_disabled = of_property_read_bool(chip->spmi->dev.of_node,
+ "qcom,btc-disabled");
+
/* Get the charging-disabled property */
chip->charging_disabled = of_property_read_bool(chip->spmi->dev.of_node,
"qcom,charging-disabled");
@@ -2657,13 +2957,6 @@
chip->duty_cycle_100p = of_property_read_bool(
chip->spmi->dev.of_node,
"qcom,duty-cycle-100p");
- if (chip->duty_cycle_100p) {
- rc = qpnp_buck_set_100_duty_cycle_enable(chip, 1);
- if (rc) {
- pr_err("failed to enable duty cycle %d\n", rc);
- return rc;
- }
- }
/* Get the fake-batt-values property */
chip->use_default_batt_values =
@@ -2715,6 +3008,7 @@
return -ENOMEM;
}
+ chip->prev_usb_max_ma = -EINVAL;
chip->dev = &(spmi->dev);
chip->spmi = spmi;
@@ -2730,7 +3024,10 @@
if (rc)
goto fail_chg_enable;
- /* Check if bat_if is set in DT and make sure VADC is present */
+ /*
+ * Check if bat_if is set in DT and make sure VADC is present
+ * Also try loading the battery data profile if bat_if exists
+ */
spmi_for_each_container_dev(spmi_resource, spmi) {
if (!spmi_resource) {
pr_err("qpnp_chg: spmi resource absent\n");
@@ -2760,6 +3057,10 @@
rc = qpnp_vadc_is_ready();
if (rc)
goto fail_chg_enable;
+
+ rc = qpnp_chg_load_battery_data(chip);
+ if (rc)
+ goto fail_chg_enable;
}
}
@@ -2829,6 +3130,16 @@
0xFF,
0x80, 1);
+ if (chip->duty_cycle_100p) {
+ rc = qpnp_buck_set_100_duty_cycle_enable(chip,
+ 1);
+ if (rc) {
+ pr_err("failed to set duty cycle %d\n",
+ rc);
+ goto fail_chg_enable;
+ }
+ }
+
break;
case SMBB_BAT_IF_SUBTYPE:
case SMBBP_BAT_IF_SUBTYPE:
@@ -2972,6 +3283,11 @@
}
}
}
+ rc = qpnp_chg_bat_if_configure_btc(chip);
+ if (rc) {
+ pr_err("failed to configure btc %d\n", rc);
+ goto unregister_batt;
+ }
qpnp_chg_charge_en(chip, !chip->charging_disabled);
qpnp_chg_force_run_on_batt(chip, chip->charging_disabled);
@@ -3068,6 +3384,66 @@
return rc;
}
+static int
+qpnp_chg_ops_set(const char *val, const struct kernel_param *kp)
+{
+ return -EINVAL;
+}
+
+#define MAX_LEN_VADC 10
+static int
+qpnp_chg_usb_in_get(char *val, const struct kernel_param *kp)
+{
+ int rc;
+ struct qpnp_vadc_result results;
+
+ rc = qpnp_vadc_is_ready();
+ if (rc)
+ return rc;
+
+ rc = qpnp_vadc_read(USBIN, &results);
+ if (rc) {
+ pr_err("Unable to read vchg rc=%d\n", rc);
+ return 0;
+ }
+ rc = snprintf(val, MAX_LEN_VADC, "%lld\n", results.physical);
+
+ return rc;
+}
+
+static int
+qpnp_chg_vchg_get(char *val, const struct kernel_param *kp)
+{
+ int rc;
+ struct qpnp_vadc_result results;
+
+ rc = qpnp_vadc_is_ready();
+ if (rc)
+ return rc;
+
+ rc = qpnp_vadc_read(VCHG_SNS, &results);
+ if (rc) {
+ pr_err("Unable to read vchg rc=%d\n", rc);
+ return 0;
+ }
+ rc = snprintf(val, MAX_LEN_VADC, "%lld\n", results.physical);
+
+ return rc;
+}
+
+static struct kernel_param_ops usb_in_uv_param_ops = {
+ .set = qpnp_chg_ops_set,
+ .get = qpnp_chg_usb_in_get,
+};
+
+static struct kernel_param_ops vchg_uv_param_ops = {
+ .set = qpnp_chg_ops_set,
+ .get = qpnp_chg_vchg_get,
+};
+
+module_param_cb(usb_in_uv, &usb_in_uv_param_ops, NULL, 0644);
+module_param_cb(vchg_uv, &vchg_uv_param_ops, NULL, 0644);
+
static const struct dev_pm_ops qpnp_chg_pm_ops = {
.resume = qpnp_chg_resume,
.suspend = qpnp_chg_suspend,
diff --git a/drivers/regulator/qpnp-regulator.c b/drivers/regulator/qpnp-regulator.c
index c9d0500..d859651 100644
--- a/drivers/regulator/qpnp-regulator.c
+++ b/drivers/regulator/qpnp-regulator.c
@@ -1535,7 +1535,9 @@
&(pdata->init_data), vreg, spmi->dev.of_node);
if (IS_ERR(vreg->rdev)) {
rc = PTR_ERR(vreg->rdev);
- vreg_err(vreg, "regulator_register failed, rc=%d\n", rc);
+ if (rc != -EPROBE_DEFER)
+ vreg_err(vreg, "regulator_register failed, rc=%d\n",
+ rc);
goto cancel_ocp_work;
}
@@ -1547,7 +1549,7 @@
if (vreg->ocp_irq)
cancel_delayed_work_sync(&vreg->ocp_work);
bail:
- if (rc)
+ if (rc && rc != -EPROBE_DEFER)
vreg_err(vreg, "probe failed, rc=%d\n", rc);
kfree(vreg->rdesc.name);
diff --git a/drivers/rtc/qpnp-rtc.c b/drivers/rtc/qpnp-rtc.c
index e0bffb9..bfbae78 100644
--- a/drivers/rtc/qpnp-rtc.c
+++ b/drivers/rtc/qpnp-rtc.c
@@ -45,6 +45,11 @@
#define TO_SECS(arr) (arr[0] | (arr[1] << 8) | (arr[2] << 16) | \
(arr[3] << 24))
+/* Module parameter to control power-on-alarm */
+static bool poweron_alarm;
+module_param(poweron_alarm, bool, 0644);
+MODULE_PARM_DESC(poweron_alarm, "Enable/Disable power-on alarm");
+
/* rtc driver internal structure */
struct qpnp_rtc {
u8 rtc_ctrl_reg;
@@ -586,7 +591,7 @@
struct qpnp_rtc *rtc_dd = dev_get_drvdata(&spmi->dev);
bool rtc_alarm_powerup = rtc_dd->rtc_alarm_powerup;
- if (!rtc_alarm_powerup) {
+ if (!rtc_alarm_powerup && !poweron_alarm) {
spin_lock_irqsave(&rtc_dd->alarm_ctrl_lock, irq_flags);
dev_dbg(&spmi->dev, "Disabling alarm interrupts\n");
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 5dfd749..1def2dd 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -255,11 +255,10 @@
}
EXPORT_SYMBOL(scsi_execute);
-
-int scsi_execute_req(struct scsi_device *sdev, const unsigned char *cmd,
+int scsi_execute_req_flags(struct scsi_device *sdev, const unsigned char *cmd,
int data_direction, void *buffer, unsigned bufflen,
struct scsi_sense_hdr *sshdr, int timeout, int retries,
- int *resid)
+ int *resid, int flags)
{
char *sense = NULL;
int result;
@@ -270,14 +269,14 @@
return DRIVER_ERROR << 24;
}
result = scsi_execute(sdev, cmd, data_direction, buffer, bufflen,
- sense, timeout, retries, 0, resid);
+ sense, timeout, retries, flags, resid);
if (sshdr)
scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, sshdr);
kfree(sense);
return result;
}
-EXPORT_SYMBOL(scsi_execute_req);
+EXPORT_SYMBOL(scsi_execute_req_flags);
/*
* Function: scsi_init_cmd_errh()
diff --git a/drivers/scsi/scsi_pm.c b/drivers/scsi/scsi_pm.c
index c467064..ff78095 100644
--- a/drivers/scsi/scsi_pm.c
+++ b/drivers/scsi/scsi_pm.c
@@ -16,29 +16,28 @@
#include "scsi_priv.h"
-static int scsi_dev_type_suspend(struct device *dev, pm_message_t msg)
+static int scsi_dev_type_suspend(struct device *dev, int (*cb)(struct device *))
{
- struct device_driver *drv;
int err;
err = scsi_device_quiesce(to_scsi_device(dev));
if (err == 0) {
- drv = dev->driver;
- if (drv && drv->suspend)
- err = drv->suspend(dev, msg);
+ if (cb) {
+ err = cb(dev);
+ if (err)
+ scsi_device_resume(to_scsi_device(dev));
+ }
}
dev_dbg(dev, "scsi suspend: %d\n", err);
return err;
}
-static int scsi_dev_type_resume(struct device *dev)
+static int scsi_dev_type_resume(struct device *dev, int (*cb)(struct device *))
{
- struct device_driver *drv;
int err = 0;
- drv = dev->driver;
- if (drv && drv->resume)
- err = drv->resume(dev);
+ if (cb)
+ err = cb(dev);
scsi_device_resume(to_scsi_device(dev));
dev_dbg(dev, "scsi resume: %d\n", err);
return err;
@@ -46,30 +45,28 @@
#ifdef CONFIG_PM_SLEEP
-static int scsi_bus_suspend_common(struct device *dev, pm_message_t msg)
+static int
+scsi_bus_suspend_common(struct device *dev, int (*cb)(struct device *))
{
int err = 0;
if (scsi_is_sdev_device(dev)) {
/*
- * sd is the only high-level SCSI driver to implement runtime
- * PM, and sd treats runtime suspend, system suspend, and
- * system hibernate identically (but not system freeze).
+ * All the high-level SCSI drivers that implement runtime
+ * PM treat runtime suspend, system suspend, and system
+ * hibernate identically.
*/
- if (pm_runtime_suspended(dev)) {
- if (msg.event == PM_EVENT_SUSPEND ||
- msg.event == PM_EVENT_HIBERNATE)
- return 0; /* already suspended */
+ if (pm_runtime_suspended(dev))
+ return 0;
- /* wake up device so that FREEZE will succeed */
- pm_runtime_resume(dev);
- }
- err = scsi_dev_type_suspend(dev, msg);
+ err = scsi_dev_type_suspend(dev, cb);
}
+
return err;
}
-static int scsi_bus_resume_common(struct device *dev)
+static int
+scsi_bus_resume_common(struct device *dev, int (*cb)(struct device *))
{
int err = 0;
@@ -81,7 +78,7 @@
* Resume it on behalf of child.
*/
pm_runtime_get_sync(dev->parent);
- err = scsi_dev_type_resume(dev);
+ err = scsi_dev_type_resume(dev, cb);
pm_runtime_put_sync(dev->parent);
}
@@ -108,55 +105,131 @@
static int scsi_bus_suspend(struct device *dev)
{
- return scsi_bus_suspend_common(dev, PMSG_SUSPEND);
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+ return scsi_bus_suspend_common(dev, pm ? pm->suspend : NULL);
+}
+
+static int scsi_bus_resume(struct device *dev)
+{
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+ return scsi_bus_resume_common(dev, pm ? pm->resume : NULL);
}
static int scsi_bus_freeze(struct device *dev)
{
- return scsi_bus_suspend_common(dev, PMSG_FREEZE);
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+ return scsi_bus_suspend_common(dev, pm ? pm->freeze : NULL);
+}
+
+static int scsi_bus_thaw(struct device *dev)
+{
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+ return scsi_bus_resume_common(dev, pm ? pm->thaw : NULL);
}
static int scsi_bus_poweroff(struct device *dev)
{
- return scsi_bus_suspend_common(dev, PMSG_HIBERNATE);
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+ return scsi_bus_suspend_common(dev, pm ? pm->poweroff : NULL);
+}
+
+static int scsi_bus_restore(struct device *dev)
+{
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+ return scsi_bus_resume_common(dev, pm ? pm->restore : NULL);
}
#else /* CONFIG_PM_SLEEP */
-#define scsi_bus_resume_common NULL
#define scsi_bus_prepare NULL
#define scsi_bus_suspend NULL
+#define scsi_bus_resume NULL
#define scsi_bus_freeze NULL
+#define scsi_bus_thaw NULL
#define scsi_bus_poweroff NULL
+#define scsi_bus_restore NULL
#endif /* CONFIG_PM_SLEEP */
#ifdef CONFIG_PM_RUNTIME
+static int sdev_blk_runtime_suspend(struct scsi_device *sdev,
+ int (*cb)(struct device *))
+{
+ int err;
+
+ err = blk_pre_runtime_suspend(sdev->request_queue);
+ if (err)
+ return err;
+ if (cb)
+ err = cb(&sdev->sdev_gendev);
+ blk_post_runtime_suspend(sdev->request_queue, err);
+
+ return err;
+}
+
+static int sdev_runtime_suspend(struct device *dev)
+{
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+ int (*cb)(struct device *) = pm ? pm->runtime_suspend : NULL;
+ struct scsi_device *sdev = to_scsi_device(dev);
+ int err;
+
+ if (sdev->request_queue->dev)
+ return sdev_blk_runtime_suspend(sdev, cb);
+
+ err = scsi_dev_type_suspend(dev, cb);
+ if (err == -EAGAIN)
+ pm_schedule_suspend(dev, jiffies_to_msecs(
+ round_jiffies_up_relative(HZ/10)));
+ return err;
+}
+
static int scsi_runtime_suspend(struct device *dev)
{
int err = 0;
dev_dbg(dev, "scsi_runtime_suspend\n");
- if (scsi_is_sdev_device(dev)) {
- err = scsi_dev_type_suspend(dev, PMSG_AUTO_SUSPEND);
- if (err == -EAGAIN)
- pm_schedule_suspend(dev, jiffies_to_msecs(
- round_jiffies_up_relative(HZ/10)));
- }
+ if (scsi_is_sdev_device(dev))
+ err = sdev_runtime_suspend(dev);
/* Insert hooks here for targets, hosts, and transport classes */
return err;
}
+static int sdev_blk_runtime_resume(struct scsi_device *sdev,
+ int (*cb)(struct device *))
+{
+ int err = 0;
+
+ blk_pre_runtime_resume(sdev->request_queue);
+ if (cb)
+ err = cb(&sdev->sdev_gendev);
+ blk_post_runtime_resume(sdev->request_queue, err);
+
+ return err;
+}
+
+static int sdev_runtime_resume(struct device *dev)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+ int (*cb)(struct device *) = pm ? pm->runtime_resume : NULL;
+
+ if (sdev->request_queue->dev)
+ return sdev_blk_runtime_resume(sdev, cb);
+ else
+ return scsi_dev_type_resume(dev, cb);
+}
+
static int scsi_runtime_resume(struct device *dev)
{
int err = 0;
dev_dbg(dev, "scsi_runtime_resume\n");
if (scsi_is_sdev_device(dev))
- err = scsi_dev_type_resume(dev);
+ err = sdev_runtime_resume(dev);
/* Insert hooks here for targets, hosts, and transport classes */
@@ -171,10 +244,18 @@
/* Insert hooks here for targets, hosts, and transport classes */
- if (scsi_is_sdev_device(dev))
- err = pm_schedule_suspend(dev, 100);
- else
+ if (scsi_is_sdev_device(dev)) {
+ struct scsi_device *sdev = to_scsi_device(dev);
+
+ if (sdev->request_queue->dev) {
+ pm_runtime_mark_last_busy(dev);
+ err = pm_runtime_autosuspend(dev);
+ } else {
+ err = pm_runtime_suspend(dev);
+ }
+ } else {
err = pm_runtime_suspend(dev);
+ }
return err;
}
@@ -235,11 +316,11 @@
const struct dev_pm_ops scsi_bus_pm_ops = {
.prepare = scsi_bus_prepare,
.suspend = scsi_bus_suspend,
- .resume = scsi_bus_resume_common,
+ .resume = scsi_bus_resume,
.freeze = scsi_bus_freeze,
- .thaw = scsi_bus_resume_common,
+ .thaw = scsi_bus_thaw,
.poweroff = scsi_bus_poweroff,
- .restore = scsi_bus_resume_common,
+ .restore = scsi_bus_restore,
.runtime_suspend = scsi_runtime_suspend,
.runtime_resume = scsi_runtime_resume,
.runtime_idle = scsi_runtime_idle,
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 508c2bb..f454610 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -966,10 +966,6 @@
sdev = sdkp->device;
- retval = scsi_autopm_get_device(sdev);
- if (retval)
- goto error_autopm;
-
/*
* If the device is in error recovery, wait until it is done.
* If the device is offline, then disallow any access to it.
@@ -1014,8 +1010,6 @@
return 0;
error_out:
- scsi_autopm_put_device(sdev);
-error_autopm:
scsi_disk_put(sdkp);
return retval;
}
@@ -1050,7 +1044,6 @@
* XXX is followed by a "rmmod sd_mod"?
*/
- scsi_autopm_put_device(sdev);
scsi_disk_put(sdkp);
return 0;
}
@@ -1212,14 +1205,9 @@
retval = -ENODEV;
if (scsi_block_when_processing_errors(sdp)) {
- retval = scsi_autopm_get_device(sdp);
- if (retval)
- goto out;
-
sshdr = kzalloc(sizeof(*sshdr), GFP_KERNEL);
retval = scsi_test_unit_ready(sdp, SD_TIMEOUT, SD_MAX_RETRIES,
sshdr);
- scsi_autopm_put_device(sdp);
}
/* failed to execute TUR, assume media not present */
@@ -1269,8 +1257,9 @@
* Leave the rest of the command zero to indicate
* flush everything.
*/
- res = scsi_execute_req(sdp, cmd, DMA_NONE, NULL, 0, &sshdr,
- SD_FLUSH_TIMEOUT, SD_MAX_RETRIES, NULL);
+ res = scsi_execute_req_flags(sdp, cmd, DMA_NONE, NULL, 0,
+ &sshdr, SD_FLUSH_TIMEOUT,
+ SD_MAX_RETRIES, NULL, REQ_PM);
if (res == 0)
break;
}
@@ -2630,6 +2619,7 @@
sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n",
sdp->removable ? "removable " : "");
+ blk_pm_runtime_init(sdp->request_queue, dev);
scsi_autopm_put_device(sdp);
put_device(&sdkp->dev);
}
@@ -2812,8 +2802,8 @@
if (!scsi_device_online(sdp))
return -ENODEV;
- res = scsi_execute_req(sdp, cmd, DMA_NONE, NULL, 0, &sshdr,
- SD_TIMEOUT, SD_MAX_RETRIES, NULL);
+ res = scsi_execute_req_flags(sdp, cmd, DMA_NONE, NULL, 0, &sshdr,
+ SD_TIMEOUT, SD_MAX_RETRIES, NULL, REQ_PM);
if (res) {
sd_printk(KERN_WARNING, sdkp, "START_STOP FAILED\n");
sd_print_result(sdkp, res);
diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 086ff03..139bc06 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -36,20 +36,10 @@
#ifndef _UFS_H
#define _UFS_H
-#include <linux/mutex.h>
-#include <linux/types.h>
-
#define MAX_CDB_SIZE 16
-#define GENERAL_UPIU_REQUEST_SIZE 32
-#define UPIU_HEADER_DATA_SEGMENT_MAX_SIZE ((ALIGNED_UPIU_SIZE) - \
- (GENERAL_UPIU_REQUEST_SIZE))
-#define QUERY_OSF_SIZE ((GENERAL_UPIU_REQUEST_SIZE) - \
- (sizeof(struct utp_upiu_header)))
-#define UFS_QUERY_RESERVED_SCSI_CMD 0xCC
-#define UFS_QUERY_CMD_SIZE 10
#define UPIU_HEADER_DWORD(byte3, byte2, byte1, byte0)\
- cpu_to_be32((byte3 << 24) | (byte2 << 16) |\
+ ((byte3 << 24) | (byte2 << 16) |\
(byte1 << 8) | (byte0))
/*
@@ -72,7 +62,7 @@
UPIU_TRANSACTION_COMMAND = 0x01,
UPIU_TRANSACTION_DATA_OUT = 0x02,
UPIU_TRANSACTION_TASK_REQ = 0x04,
- UPIU_TRANSACTION_QUERY_REQ = 0x16,
+ UPIU_TRANSACTION_QUERY_REQ = 0x26,
};
/* UTP UPIU Transaction Codes Target to Initiator */
@@ -83,7 +73,6 @@
UPIU_TRANSACTION_TASK_RSP = 0x24,
UPIU_TRANSACTION_READY_XFER = 0x31,
UPIU_TRANSACTION_QUERY_RSP = 0x36,
- UPIU_TRANSACTION_REJECT_UPIU = 0x3F,
};
/* UPIU Read/Write flags */
@@ -101,12 +90,6 @@
UPIU_TASK_ATTR_ACA = 0x03,
};
-/* UPIU Query request function */
-enum {
- UPIU_QUERY_FUNC_STANDARD_READ_REQUEST = 0x01,
- UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST = 0x81,
-};
-
/* UTP QUERY Transaction Specific Fields OpCode */
enum {
UPIU_QUERY_OPCODE_NOP = 0x0,
@@ -120,21 +103,6 @@
UPIU_QUERY_OPCODE_TOGGLE_FLAG = 0x8,
};
-/* Query response result code */
-enum {
- QUERY_RESULT_SUCCESS = 0x00,
- QUERY_RESULT_NOT_READABLE = 0xF6,
- QUERY_RESULT_NOT_WRITEABLE = 0xF7,
- QUERY_RESULT_ALREADY_WRITTEN = 0xF8,
- QUERY_RESULT_INVALID_LENGTH = 0xF9,
- QUERY_RESULT_INVALID_VALUE = 0xFA,
- QUERY_RESULT_INVALID_SELECTOR = 0xFB,
- QUERY_RESULT_INVALID_INDEX = 0xFC,
- QUERY_RESULT_INVALID_IDN = 0xFD,
- QUERY_RESULT_INVALID_OPCODE = 0xFE,
- QUERY_RESULT_GENERAL_FAILURE = 0xFF,
-};
-
/* UTP Transfer Request Command Type (CT) */
enum {
UPIU_COMMAND_SET_TYPE_SCSI = 0x0,
@@ -142,17 +110,10 @@
UPIU_COMMAND_SET_TYPE_QUERY = 0x2,
};
-/* UTP Transfer Request Command Offset */
-#define UPIU_COMMAND_TYPE_OFFSET 28
-
-/* Offset of the response code in the UPIU header */
-#define UPIU_RSP_CODE_OFFSET 8
-
enum {
MASK_SCSI_STATUS = 0xFF,
MASK_TASK_RESPONSE = 0xFF00,
MASK_RSP_UPIU_RESULT = 0xFFFF,
- MASK_QUERY_DATA_SEG_LEN = 0xFFFF,
};
/* Task management service response */
@@ -177,59 +138,26 @@
/**
* struct utp_upiu_cmd - Command UPIU structure
+ * @header: UPIU header structure DW-0 to DW-2
* @data_transfer_len: Data Transfer Length DW-3
* @cdb: Command Descriptor Block CDB DW-4 to DW-7
*/
struct utp_upiu_cmd {
+ struct utp_upiu_header header;
u32 exp_data_transfer_len;
u8 cdb[MAX_CDB_SIZE];
};
/**
- * struct utp_upiu_query - upiu request buffer structure for
- * query request.
- * @opcode: command to perform B-0
- * @idn: a value that indicates the particular type of data B-1
- * @index: Index to further identify data B-2
- * @selector: Index to further identify data B-3
- * @reserved_osf: spec reserved field B-4,5
- * @length: number of descriptor bytes to read/write B-6,7
- * @value: Attribute value to be written DW-6
- * @reserved: spec reserved DW-7,8
- */
-struct utp_upiu_query {
- u8 opcode;
- u8 idn;
- u8 index;
- u8 selector;
- u16 reserved_osf;
- u16 length;
- u32 value;
- u32 reserved[2];
-};
-
-/**
- * struct utp_upiu_req - general upiu request structure
- * @header:UPIU header structure DW-0 to DW-2
- * @sc: fields structure for scsi command
- * @qr: fields structure for query request
- */
-struct utp_upiu_req {
- struct utp_upiu_header header;
- union {
- struct utp_upiu_cmd sc;
- struct utp_upiu_query qr;
- };
-};
-
-/**
- * struct utp_cmd_rsp - Response UPIU structure
+ * struct utp_upiu_rsp - Response UPIU structure
+ * @header: UPIU header DW-0 to DW-2
* @residual_transfer_count: Residual transfer count DW-3
* @reserved: Reserved double words DW-4 to DW-7
* @sense_data_len: Sense data length DW-8 U16
* @sense_data: Sense data field DW-8 to DW-12
*/
-struct utp_cmd_rsp {
+struct utp_upiu_rsp {
+ struct utp_upiu_header header;
u32 residual_transfer_count;
u32 reserved[4];
u16 sense_data_len;
@@ -237,20 +165,6 @@
};
/**
- * struct utp_upiu_rsp - general upiu response structure
- * @header: UPIU header structure DW-0 to DW-2
- * @sc: fields structure for scsi command
- * @qr: fields structure for query request
- */
-struct utp_upiu_rsp {
- struct utp_upiu_header header;
- union {
- struct utp_cmd_rsp sc;
- struct utp_upiu_query qr;
- };
-};
-
-/**
* struct utp_upiu_task_req - Task request UPIU structure
* @header - UPIU header structure DW0 to DW-2
* @input_param1: Input parameter 1 DW-3
@@ -280,24 +194,4 @@
u32 reserved[3];
};
-/**
- * struct ufs_query_req - parameters for building a query request
- * @query_func: UPIU header query function
- * @upiu_req: the query request data
- */
-struct ufs_query_req {
- u8 query_func;
- struct utp_upiu_query upiu_req;
-};
-
-/**
- * struct ufs_query_resp - UPIU QUERY
- * @response: device response code
- * @upiu_res: query response data
- */
-struct ufs_query_res {
- u8 response;
- struct utp_upiu_query upiu_res;
-};
-
#endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufs_test.c b/drivers/scsi/ufs/ufs_test.c
index 03c58a4..dbab808 100644
--- a/drivers/scsi/ufs/ufs_test.c
+++ b/drivers/scsi/ufs/ufs_test.c
@@ -18,13 +18,27 @@
#include <scsi/scsi_device.h>
#include <scsi/scsi_cmnd.h>
#include <../sd.h>
+#include <linux/delay.h>
#define MODULE_NAME "ufs_test"
-#define TEST_MAX_BIOS_PER_REQ 120
+#define TEST_MAX_BIOS_PER_REQ 16
#define LARGE_PRIME_1 1103515367
#define LARGE_PRIME_2 35757
-#define DEFAULT_NUM_OF_BIOS 2
+#define DEFAULT_NUM_OF_BIOS 2
+
+/* the amount of requests that will be inserted */
+#define LONG_SEQ_TEST_NUM_REQS 256
+/* request queue limitation is 128 requests, and we leave 10 spare requests */
+#define QUEUE_MAX_REQUESTS 118
+#define MB_MSEC_RATIO_APPROXIMATION ((1024 * 1024) / 1000)
+/* actual number of MiB in test multiplied by 10, for single digit precision*/
+#define BYTE_TO_MB_x_10(x) ((x * 10) / (1024 * 1024))
+/* extract integer value */
+#define LONG_TEST_SIZE_INTEGER(x) (BYTE_TO_MB_x_10(x) / 10)
+/* and calculate the MiB value fraction */
+#define LONG_TEST_SIZE_FRACTION(x) (BYTE_TO_MB_x_10(x) - \
+ (LONG_TEST_SIZE_INTEGER(x) * 10))
#define test_pr_debug(fmt, args...) pr_debug("%s: "fmt"\n", MODULE_NAME, args)
#define test_pr_info(fmt, args...) pr_info("%s: "fmt"\n", MODULE_NAME, args)
@@ -32,11 +46,16 @@
enum ufs_test_testcases {
UFS_TEST_WRITE_READ_TEST,
+
+ TEST_LONG_SEQUENTIAL_READ,
+ TEST_LONG_SEQUENTIAL_WRITE,
};
struct ufs_test_debug {
struct dentry *write_read_test; /* basic test */
struct dentry *random_test_seed; /* parameters in utils */
+ struct dentry *long_sequential_read_test;
+ struct dentry *long_sequential_write_test;
};
struct ufs_test_data {
@@ -60,6 +79,8 @@
* disabled and 2 BIOs are written.
*/
unsigned int random_test_seed;
+ /* A counter for the number of test requests completed */
+ unsigned int completed_req_count;
};
static struct ufs_test_data *utd;
@@ -77,6 +98,12 @@
case UFS_TEST_WRITE_READ_TEST:
return "UFS write read test";
break;
+ case TEST_LONG_SEQUENTIAL_READ:
+ return "UFS long sequential read test";
+ break;
+ case TEST_LONG_SEQUENTIAL_WRITE:
+ return "UFS long sequential write test";
+ break;
default:
return "Unknown test";
}
@@ -166,8 +193,9 @@
num_bios = DEFAULT_NUM_OF_BIOS;
/* Adding a write request */
- test_pr_info("%s: Adding a write requests to Q, first req_id=%d",
- __func__, td->wr_rd_next_req_id);
+ test_pr_info(
+ "%s: Adding a write request with %d bios to Q, req_id=%d"
+ , __func__, num_bios, td->wr_rd_next_req_id);
utd->write_completed = false;
ret = test_iosched_add_wr_rd_test_req(0, WRITE, start_sec,
@@ -265,21 +293,290 @@
.read = ufs_test_write_read_test_read_cb,
};
+static void long_seq_test_free_end_io_fn(struct request *rq, int err)
+{
+ struct test_request *test_rq;
+ struct test_data *ptd = test_get_test_data();
+
+ if (rq)
+ test_rq = (struct test_request *)rq->elv.priv[0];
+ else {
+ test_pr_err("%s: error: NULL request", __func__);
+ return;
+ }
+
+ BUG_ON(!test_rq);
+
+ spin_lock_irq(&ptd->lock);
+ ptd->dispatched_count--;
+ list_del_init(&test_rq->queuelist);
+ __blk_put_request(ptd->req_q, test_rq->rq);
+ spin_unlock_irq(&ptd->lock);
+
+ kfree(test_rq->bios_buffer);
+ kfree(test_rq);
+ utd->completed_req_count++;
+
+ test_pr_err("%s: request %d completed, err=%d",
+ __func__, test_rq->req_id, err);
+
+ check_test_completion();
+
+}
+
+static int run_long_seq_test(struct test_data *td)
+{
+ int ret = 0;
+ int direction;
+ static unsigned int inserted_requests;
+
+ BUG_ON(!td);
+ td->test_count = 0;
+ utd->completed_req_count = 0;
+ inserted_requests = 0;
+
+ if (td->test_info.testcase == TEST_LONG_SEQUENTIAL_READ)
+ direction = READ;
+ else
+ direction = WRITE;
+
+ test_pr_info("%s: Adding %d requests, first req_id=%d",
+ __func__, LONG_SEQ_TEST_NUM_REQS,
+ td->wr_rd_next_req_id);
+
+ do {
+ /*
+ * since our requests come from a pool containing 128
+ * requests, we don't want to exhaust this quantity,
+ * therefore we add up to QUEUE_MAX_REQUESTS (which
+ * includes a safety margin) and then call the mmc layer
+ * to fetch them
+ */
+ if (td->test_count >= QUEUE_MAX_REQUESTS) {
+ blk_run_queue(td->req_q);
+ continue;
+ }
+
+ ret = test_iosched_add_wr_rd_test_req(0, direction,
+ td->start_sector, TEST_MAX_BIOS_PER_REQ,
+ TEST_PATTERN_5A,
+ long_seq_test_free_end_io_fn);
+ if (ret) {
+ test_pr_err("%s: failed to create request" , __func__);
+ break;
+ }
+ inserted_requests++;
+ td->test_info.test_byte_count +=
+ (TEST_MAX_BIOS_PER_REQ * sizeof(unsigned int) *
+ BIO_U32_SIZE);
+
+ } while (inserted_requests < LONG_SEQ_TEST_NUM_REQS);
+
+ /* in this case the queue will not run in the above loop */
+ if (LONG_SEQ_TEST_NUM_REQS < QUEUE_MAX_REQUESTS)
+ blk_run_queue(td->req_q);
+
+ return ret;
+}
+
+
+void long_seq_test_calc_throughput(unsigned long mtime,
+ unsigned long byte_count)
+{
+ unsigned long fraction, integer;
+
+ test_pr_info("%s: time is %lu msec, size is %lu.%lu MiB",
+ __func__, mtime, LONG_TEST_SIZE_INTEGER(byte_count),
+ LONG_TEST_SIZE_FRACTION(byte_count));
+
+ /* we first multiply in order not to lose precision */
+ mtime *= MB_MSEC_RATIO_APPROXIMATION;
+ /* divide values to get a MiB/sec integer value with one
+ digit of precision
+ */
+ fraction = integer = (byte_count * 10) / mtime;
+ integer /= 10;
+ /* and calculate the MiB value fraction */
+ fraction -= integer * 10;
+
+ test_pr_info("%s: Throughput: %lu.%lu MiB/sec\n",
+ __func__, integer, fraction);
+}
+
+static ssize_t long_sequential_read_test_write(struct file *file,
+ const char __user *buf,
+ size_t count,
+ loff_t *ppos)
+{
+ int ret = 0;
+ int i = 0;
+ int number = -1;
+ unsigned long mtime, byte_count;
+
+ test_pr_info("%s: -- UFS Long Sequential Read TEST --", __func__);
+
+ sscanf(buf, "%d", &number);
+
+ if (number <= 0)
+ number = 1;
+
+ memset(&utd->test_info, 0, sizeof(struct test_info));
+
+ utd->test_info.data = utd;
+ utd->test_info.get_rq_disk_fn = ufs_test_get_rq_disk;
+ utd->test_info.run_test_fn = run_long_seq_test;
+ utd->test_info.get_test_case_str_fn = ufs_test_get_test_case_str;
+ utd->test_info.testcase = TEST_LONG_SEQUENTIAL_READ;
+
+ for (i = 0 ; i < number ; ++i) {
+ test_pr_info("%s: Cycle # %d / %d", __func__, i+1, number);
+ test_pr_info("%s: ====================", __func__);
+
+ ret = test_iosched_start_test(&utd->test_info);
+ if (ret)
+ break;
+
+ mtime = ktime_to_ms(utd->test_info.test_duration);
+ byte_count = utd->test_info.test_byte_count;
+
+ long_seq_test_calc_throughput(mtime, byte_count);
+
+ /* Allow FS requests to be dispatched */
+ msleep(1000);
+ }
+
+ return count;
+}
+
+static ssize_t long_sequential_read_test_read(struct file *file,
+ char __user *buffer,
+ size_t count,
+ loff_t *offset)
+{
+ memset((void *)buffer, 0, count);
+
+ snprintf(buffer, count,
+ "\nufs_long_sequential_read_test\n"
+ "=========\n"
+ "Description:\n"
+ "This test runs the following scenarios\n"
+ "- Long Sequential Read Test: this test measures read "
+ "throughput at the driver level by sequentially reading many "
+ "large requests.\n");
+
+ if (message_repeat == 1) {
+ message_repeat = 0;
+ return strnlen(buffer, count);
+ } else
+ return 0;
+}
+
+static bool message_repeat;
+static int test_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ message_repeat = 1;
+ return 0;
+}
+
+const struct file_operations long_sequential_read_test_ops = {
+ .open = test_open,
+ .write = long_sequential_read_test_write,
+ .read = long_sequential_read_test_read,
+};
+
+static ssize_t long_sequential_write_test_write(struct file *file,
+ const char __user *buf,
+ size_t count,
+ loff_t *ppos)
+{
+ int ret = 0;
+ int i = 0;
+ int number = -1;
+ unsigned long mtime, byte_count;
+
+ test_pr_info("%s: -- UFS Long Sequential Write TEST --", __func__);
+
+ sscanf(buf, "%d", &number);
+
+ if (number <= 0)
+ number = 1;
+
+ memset(&utd->test_info, 0, sizeof(struct test_info));
+
+ utd->test_info.data = utd;
+ utd->test_info.get_rq_disk_fn = ufs_test_get_rq_disk;
+ utd->test_info.get_test_case_str_fn = ufs_test_get_test_case_str;
+ utd->test_info.run_test_fn = run_long_seq_test;
+ utd->test_info.testcase = TEST_LONG_SEQUENTIAL_WRITE;
+
+ for (i = 0 ; i < number ; ++i) {
+ test_pr_info("%s: Cycle # %d / %d", __func__, i+1, number);
+ test_pr_info("%s: ====================", __func__);
+
+ utd->test_info.test_byte_count = 0;
+ ret = test_iosched_start_test(&utd->test_info);
+ if (ret)
+ break;
+
+ mtime = ktime_to_ms(utd->test_info.test_duration);
+ byte_count = utd->test_info.test_byte_count;
+
+ long_seq_test_calc_throughput(mtime, byte_count);
+
+ /* Allow FS requests to be dispatched */
+ msleep(1000);
+ }
+
+ return count;
+}
+
+static ssize_t long_sequential_write_test_read(struct file *file,
+ char __user *buffer,
+ size_t count,
+ loff_t *offset)
+{
+ memset((void *)buffer, 0, count);
+
+ snprintf(buffer, count,
+ "\nufs_long_sequential_write_test\n"
+ "=========\n"
+ "Description:\n"
+ "This test runs the following scenarios\n"
+ "- Long Sequential Write Test: this test measures write "
+ "throughput at the driver level by sequentially writing many "
+ "large requests\n");
+
+ if (message_repeat == 1) {
+ message_repeat = 0;
+ return strnlen(buffer, count);
+ } else
+ return 0;
+}
+
+const struct file_operations long_sequential_write_test_ops = {
+ .open = test_open,
+ .write = long_sequential_write_test_write,
+ .read = long_sequential_write_test_read,
+};
+
static void ufs_test_debugfs_cleanup(void)
{
- debugfs_remove(utd->debug.write_read_test);
+ debugfs_remove_recursive(test_iosched_get_debugfs_tests_root());
}
static int ufs_test_debugfs_init(void)
{
struct dentry *utils_root, *tests_root;
+ int ret = 0;
utils_root = test_iosched_get_debugfs_utils_root();
tests_root = test_iosched_get_debugfs_tests_root();
if (!utils_root || !tests_root) {
test_pr_err("%s: Failed to create debugfs root.", __func__);
- return -EINVAL;
+ ret = -EINVAL;
+ goto exit;
}
utd->debug.random_test_seed = debugfs_create_u32("random_test_seed",
@@ -288,21 +585,49 @@
if (!utd->debug.random_test_seed) {
test_pr_err("%s: Could not create debugfs random_test_seed.",
__func__);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto exit;
}
- utd->debug.write_read_test = debugfs_create_file("write_read_test",
+ utd->debug.write_read_test = debugfs_create_file("ufs_write_read_test",
S_IRUGO | S_IWUGO, tests_root,
NULL, &write_read_test_ops);
if (!utd->debug.write_read_test) {
- debugfs_remove(utd->debug.random_test_seed);
- test_pr_err("%s: Could not create debugfs write_read_test.",
- __func__);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto exit_err;
}
- return 0;
+ utd->debug.long_sequential_read_test = debugfs_create_file(
+ "ufs_long_sequential_read_test",
+ S_IRUGO | S_IWUGO,
+ tests_root,
+ NULL,
+ &long_sequential_read_test_ops);
+
+ if (!utd->debug.long_sequential_read_test) {
+ ret = -ENOMEM;
+ goto exit_err;
+ }
+
+ utd->debug.long_sequential_write_test = debugfs_create_file(
+ "ufs_long_sequential_write_test",
+ S_IRUGO | S_IWUGO,
+ tests_root,
+ NULL,
+ &long_sequential_write_test_ops);
+
+ if (!utd->debug.long_sequential_write_test) {
+ ret = -ENOMEM;
+ goto exit_err;
+ }
+
+ goto exit;
+
+exit_err:
+ debugfs_remove_recursive(tests_root);
+exit:
+ return ret;
}
static void ufs_test_probe(void)
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 5f21c7a..2230f14 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -33,8 +33,16 @@
* this program.
*/
+#include <linux/async.h>
+
#include "ufshcd.h"
+#define UFSHCD_ENABLE_INTRS (UTP_TRANSFER_REQ_COMPL |\
+ UTP_TASK_REQ_COMPL |\
+ UFSHCD_ERROR_MASK)
+/* UIC command timeout, unit: ms */
+#define UIC_CMD_TIMEOUT 500
+
enum {
UFSHCD_MAX_CHANNEL = 0,
UFSHCD_MAX_ID = 1,
@@ -64,6 +72,20 @@
};
/**
+ * ufshcd_get_intr_mask - Get the interrupt bit mask
+ * @hba - Pointer to adapter instance
+ *
+ * Returns interrupt bit mask per version
+ */
+static inline u32 ufshcd_get_intr_mask(struct ufs_hba *hba)
+{
+ if (hba->ufs_version == UFSHCI_VERSION_10)
+ return INTERRUPT_MASK_ALL_VER_10;
+ else
+ return INTERRUPT_MASK_ALL_VER_11;
+}
+
+/**
* ufshcd_get_ufs_version - Get the UFS version supported by the HBA
* @hba - Pointer to adapter instance
*
@@ -71,7 +93,7 @@
*/
static inline u32 ufshcd_get_ufs_version(struct ufs_hba *hba)
{
- return readl(hba->mmio_base + REG_UFS_VERSION);
+ return ufshcd_readl(hba, REG_UFS_VERSION);
}
/**
@@ -130,8 +152,7 @@
*/
static inline void ufshcd_utrl_clear(struct ufs_hba *hba, u32 pos)
{
- writel(~(1 << pos),
- (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_CLEAR));
+ ufshcd_writel(hba, ~(1 << pos), REG_UTP_TRANSFER_REQ_LIST_CLEAR);
}
/**
@@ -165,7 +186,7 @@
*/
static inline int ufshcd_get_uic_cmd_result(struct ufs_hba *hba)
{
- return readl(hba->mmio_base + REG_UIC_COMMAND_ARG_2) &
+ return ufshcd_readl(hba, REG_UIC_COMMAND_ARG_2) &
MASK_UIC_COMMAND_RESULT;
}
@@ -202,13 +223,18 @@
}
/**
- * ufshcd_get_req_rsp - returns the TR response
+ * ufshcd_is_valid_req_rsp - checks if controller TR response is valid
* @ucd_rsp_ptr: pointer to response UPIU
+ *
+ * This function checks the response UPIU for valid transaction type in
+ * response field
+ * Returns 0 on success, non-zero on failure
*/
static inline int
-ufshcd_get_req_rsp(struct utp_upiu_rsp *ucd_rsp_ptr)
+ufshcd_is_valid_req_rsp(struct utp_upiu_rsp *ucd_rsp_ptr)
{
- return be32_to_cpu(ucd_rsp_ptr->header.dword_0) >> 24;
+ return ((be32_to_cpu(ucd_rsp_ptr->header.dword_0) >> 24) ==
+ UPIU_TRANSACTION_RESPONSE) ? 0 : DID_ERROR << 16;
}
/**
@@ -238,18 +264,15 @@
{
switch (option) {
case INT_AGGR_RESET:
- writel((INT_AGGR_ENABLE |
- INT_AGGR_COUNTER_AND_TIMER_RESET),
- (hba->mmio_base +
- REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL));
+ ufshcd_writel(hba, INT_AGGR_ENABLE |
+ INT_AGGR_COUNTER_AND_TIMER_RESET,
+ REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
break;
case INT_AGGR_CONFIG:
- writel((INT_AGGR_ENABLE |
- INT_AGGR_PARAM_WRITE |
- INT_AGGR_COUNTER_THRESHOLD_VALUE |
- INT_AGGR_TIMEOUT_VALUE),
- (hba->mmio_base +
- REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL));
+ ufshcd_writel(hba, INT_AGGR_ENABLE | INT_AGGR_PARAM_WRITE |
+ INT_AGGR_COUNTER_THRESHOLD_VALUE |
+ INT_AGGR_TIMEOUT_VALUE,
+ REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
break;
}
}
@@ -262,12 +285,10 @@
*/
static void ufshcd_enable_run_stop_reg(struct ufs_hba *hba)
{
- writel(UTP_TASK_REQ_LIST_RUN_STOP_BIT,
- (hba->mmio_base +
- REG_UTP_TASK_REQ_LIST_RUN_STOP));
- writel(UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT,
- (hba->mmio_base +
- REG_UTP_TRANSFER_REQ_LIST_RUN_STOP));
+ ufshcd_writel(hba, UTP_TASK_REQ_LIST_RUN_STOP_BIT,
+ REG_UTP_TASK_REQ_LIST_RUN_STOP);
+ ufshcd_writel(hba, UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT,
+ REG_UTP_TRANSFER_REQ_LIST_RUN_STOP);
}
/**
@@ -276,7 +297,7 @@
*/
static inline void ufshcd_hba_start(struct ufs_hba *hba)
{
- writel(CONTROLLER_ENABLE , (hba->mmio_base + REG_CONTROLLER_ENABLE));
+ ufshcd_writel(hba, CONTROLLER_ENABLE, REG_CONTROLLER_ENABLE);
}
/**
@@ -287,7 +308,7 @@
*/
static inline int ufshcd_is_hba_active(struct ufs_hba *hba)
{
- return (readl(hba->mmio_base + REG_CONTROLLER_ENABLE) & 0x1) ? 0 : 1;
+ return (ufshcd_readl(hba, REG_CONTROLLER_ENABLE) & 0x1) ? 0 : 1;
}
/**
@@ -299,8 +320,7 @@
void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag)
{
__set_bit(task_tag, &hba->outstanding_reqs);
- writel((1 << task_tag),
- (hba->mmio_base + REG_UTP_TRANSFER_REQ_DOOR_BELL));
+ ufshcd_writel(hba, 1 << task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL);
}
/**
@@ -311,78 +331,20 @@
{
int len;
if (lrbp->sense_buffer) {
- len = be16_to_cpu(lrbp->ucd_rsp_ptr->sc.sense_data_len);
+ len = be16_to_cpu(lrbp->ucd_rsp_ptr->sense_data_len);
memcpy(lrbp->sense_buffer,
- lrbp->ucd_rsp_ptr->sc.sense_data,
+ lrbp->ucd_rsp_ptr->sense_data,
min_t(int, len, SCSI_SENSE_BUFFERSIZE));
}
}
/**
- * ufshcd_query_to_cpu() - formats the received buffer in to the native cpu
- * endian
- * @response: upiu query response to convert
- */
-static inline void ufshcd_query_to_cpu(struct utp_upiu_query *response)
-{
- response->length = be16_to_cpu(response->length);
- response->value = be32_to_cpu(response->value);
-}
-
-/**
- * ufshcd_query_to_be() - formats the buffer before sending in to big endian
- * @response: upiu query request to convert
- */
-static inline void ufshcd_query_to_be(struct utp_upiu_query *request)
-{
- request->length = cpu_to_be16(request->length);
- request->value = cpu_to_be32(request->value);
-}
-
-/**
- * ufshcd_copy_query_response() - Copy Query Response and descriptor
- * @lrb - pointer to local reference block
- * @query_res - pointer to the query result
- */
-static
-void ufshcd_copy_query_response(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
-{
- struct ufs_query_res *query_res = hba->query.response;
-
- /* Get the UPIU response */
- if (query_res) {
- query_res->response = ufshcd_get_rsp_upiu_result(
- lrbp->ucd_rsp_ptr) >> UPIU_RSP_CODE_OFFSET;
-
- memcpy(&query_res->upiu_res, &lrbp->ucd_rsp_ptr->qr,
- QUERY_OSF_SIZE);
- ufshcd_query_to_cpu(&query_res->upiu_res);
- }
-
- /* Get the descriptor */
- if (hba->query.descriptor && lrbp->ucd_rsp_ptr->qr.opcode ==
- UPIU_QUERY_OPCODE_READ_DESC) {
- u8 *descp = (u8 *)&lrbp->ucd_rsp_ptr +
- GENERAL_UPIU_REQUEST_SIZE;
- u16 len;
-
- /* data segment length */
- len = be32_to_cpu(lrbp->ucd_rsp_ptr->header.dword_2) &
- MASK_QUERY_DATA_SEG_LEN;
-
- memcpy(hba->query.descriptor, descp,
- min_t(u16, len, UPIU_HEADER_DATA_SEGMENT_MAX_SIZE));
- }
-}
-
-/**
* ufshcd_hba_capabilities - Read controller capabilities
* @hba: per adapter instance
*/
static inline void ufshcd_hba_capabilities(struct ufs_hba *hba)
{
- hba->capabilities =
- readl(hba->mmio_base + REG_CONTROLLER_CAPABILITIES);
+ hba->capabilities = ufshcd_readl(hba, REG_CONTROLLER_CAPABILITIES);
/* nutrs and nutmrs are 0 based values */
hba->nutrs = (hba->capabilities & MASK_TRANSFER_REQUESTS_SLOTS) + 1;
@@ -391,24 +353,119 @@
}
/**
- * ufshcd_send_uic_command - Send UIC commands to unipro layers
+ * ufshcd_ready_for_uic_cmd - Check if controller is ready
+ * to accept UIC commands
* @hba: per adapter instance
- * @uic_command: UIC command
+ * Return true on success, else false
+ */
+static inline bool ufshcd_ready_for_uic_cmd(struct ufs_hba *hba)
+{
+ if (ufshcd_readl(hba, REG_CONTROLLER_STATUS) & UIC_COMMAND_READY)
+ return true;
+ else
+ return false;
+}
+
+/**
+ * ufshcd_dispatch_uic_cmd - Dispatch UIC commands to unipro layers
+ * @hba: per adapter instance
+ * @uic_cmd: UIC command
+ *
+ * Mutex must be held.
*/
static inline void
-ufshcd_send_uic_command(struct ufs_hba *hba, struct uic_command *uic_cmnd)
+ufshcd_dispatch_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
{
+ WARN_ON(hba->active_uic_cmd);
+
+ hba->active_uic_cmd = uic_cmd;
+
/* Write Args */
- writel(uic_cmnd->argument1,
- (hba->mmio_base + REG_UIC_COMMAND_ARG_1));
- writel(uic_cmnd->argument2,
- (hba->mmio_base + REG_UIC_COMMAND_ARG_2));
- writel(uic_cmnd->argument3,
- (hba->mmio_base + REG_UIC_COMMAND_ARG_3));
+ ufshcd_writel(hba, uic_cmd->argument1, REG_UIC_COMMAND_ARG_1);
+ ufshcd_writel(hba, uic_cmd->argument2, REG_UIC_COMMAND_ARG_2);
+ ufshcd_writel(hba, uic_cmd->argument3, REG_UIC_COMMAND_ARG_3);
/* Write UIC Cmd */
- writel((uic_cmnd->command & COMMAND_OPCODE_MASK),
- (hba->mmio_base + REG_UIC_COMMAND));
+ ufshcd_writel(hba, uic_cmd->command & COMMAND_OPCODE_MASK,
+ REG_UIC_COMMAND);
+}
+
+/**
+ * ufshcd_wait_for_uic_cmd - Wait complectioin of UIC command
+ * @hba: per adapter instance
+ * @uic_command: UIC command
+ *
+ * Must be called with mutex held.
+ * Returns 0 only if success.
+ */
+static int
+ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
+{
+ int ret;
+ unsigned long flags;
+
+ if (wait_for_completion_timeout(&uic_cmd->done,
+ msecs_to_jiffies(UIC_CMD_TIMEOUT)))
+ ret = uic_cmd->argument2 & MASK_UIC_COMMAND_RESULT;
+ else
+ ret = -ETIMEDOUT;
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ hba->active_uic_cmd = NULL;
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+ return ret;
+}
+
+/**
+ * __ufshcd_send_uic_cmd - Send UIC commands and retrieve the result
+ * @hba: per adapter instance
+ * @uic_cmd: UIC command
+ *
+ * Identical to ufshcd_send_uic_cmd() expect mutex. Must be called
+ * with mutex held.
+ * Returns 0 only if success.
+ */
+static int
+__ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
+{
+ int ret;
+ unsigned long flags;
+
+ if (!ufshcd_ready_for_uic_cmd(hba)) {
+ dev_err(hba->dev,
+ "Controller not ready to accept UIC commands\n");
+ return -EIO;
+ }
+
+ init_completion(&uic_cmd->done);
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ ufshcd_dispatch_uic_cmd(hba, uic_cmd);
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+ ret = ufshcd_wait_for_uic_cmd(hba, uic_cmd);
+
+ return ret;
+}
+
+/**
+ * ufshcd_send_uic_cmd - Send UIC commands and retrieve the result
+ * @hba: per adapter instance
+ * @uic_cmd: UIC command
+ *
+ * Returns 0 only if success.
+ */
+static int
+ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
+{
+ int ret;
+
+ mutex_lock(&hba->uic_cmd_mutex);
+ ret = __ufshcd_send_uic_cmd(hba, uic_cmd);
+ mutex_unlock(&hba->uic_cmd_mutex);
+
+ return ret;
}
/**
@@ -452,177 +509,118 @@
}
/**
- * ufshcd_int_config - enable/disable interrupts
+ * ufshcd_enable_intr - enable interrupts
* @hba: per adapter instance
- * @option: interrupt option
+ * @intrs: interrupt bits
*/
-static void ufshcd_int_config(struct ufs_hba *hba, u32 option)
+static void ufshcd_enable_intr(struct ufs_hba *hba, u32 intrs)
{
- switch (option) {
- case UFSHCD_INT_ENABLE:
- writel(hba->int_enable_mask,
- (hba->mmio_base + REG_INTERRUPT_ENABLE));
- break;
- case UFSHCD_INT_DISABLE:
- if (hba->ufs_version == UFSHCI_VERSION_10)
- writel(INTERRUPT_DISABLE_MASK_10,
- (hba->mmio_base + REG_INTERRUPT_ENABLE));
- else
- writel(INTERRUPT_DISABLE_MASK_11,
- (hba->mmio_base + REG_INTERRUPT_ENABLE));
- break;
- }
-}
+ u32 set = ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
-/**
- * ufshcd_prepare_req_desc - Fills the requests header
- * descriptor according to request
- * lrbp: pointer to local reference block
- * upiu_flags: flags required in the header
- */
-static void ufshcd_prepare_req_desc(struct ufshcd_lrb *lrbp, u32 *upiu_flags)
-{
- struct utp_transfer_req_desc *req_desc = lrbp->utr_descriptor_ptr;
- enum dma_data_direction cmd_dir =
- lrbp->cmd->sc_data_direction;
- u32 data_direction;
- u32 dword_0;
-
- if (cmd_dir == DMA_FROM_DEVICE) {
- data_direction = UTP_DEVICE_TO_HOST;
- *upiu_flags = UPIU_CMD_FLAGS_READ;
- } else if (cmd_dir == DMA_TO_DEVICE) {
- data_direction = UTP_HOST_TO_DEVICE;
- *upiu_flags = UPIU_CMD_FLAGS_WRITE;
+ if (hba->ufs_version == UFSHCI_VERSION_10) {
+ u32 rw;
+ rw = set & INTERRUPT_MASK_RW_VER_10;
+ set = rw | ((set ^ intrs) & intrs);
} else {
- data_direction = UTP_NO_DATA_TRANSFER;
- *upiu_flags = UPIU_CMD_FLAGS_NONE;
+ set |= intrs;
}
- dword_0 = data_direction | (lrbp->command_type
- << UPIU_COMMAND_TYPE_OFFSET);
-
- /* Transfer request descriptor header fields */
- req_desc->header.dword_0 = cpu_to_le32(dword_0);
-
- /*
- * assigning invalid value for command status. Controller
- * updates OCS on command completion, with the command
- * status
- */
- req_desc->header.dword_2 =
- cpu_to_le32(OCS_INVALID_COMMAND_STATUS);
-}
-
-static inline bool ufshcd_is_query_req(struct ufshcd_lrb *lrbp)
-{
- return lrbp->cmd ? lrbp->cmd->cmnd[0] == UFS_QUERY_RESERVED_SCSI_CMD :
- false;
+ ufshcd_writel(hba, set, REG_INTERRUPT_ENABLE);
}
/**
- * ufshcd_prepare_utp_scsi_cmd_upiu() - fills the utp_transfer_req_desc,
- * for scsi commands
- * @lrbp - local reference block pointer
- * @upiu_flags - flags
+ * ufshcd_disable_intr - disable interrupts
+ * @hba: per adapter instance
+ * @intrs: interrupt bits
*/
-static
-void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufshcd_lrb *lrbp, u32 upiu_flags)
+static void ufshcd_disable_intr(struct ufs_hba *hba, u32 intrs)
{
- struct utp_upiu_req *ucd_req_ptr = lrbp->ucd_req_ptr;
+ u32 set = ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
- /* command descriptor fields */
- ucd_req_ptr->header.dword_0 = UPIU_HEADER_DWORD(
- UPIU_TRANSACTION_COMMAND, upiu_flags,
- lrbp->lun, lrbp->task_tag);
- ucd_req_ptr->header.dword_1 = UPIU_HEADER_DWORD(
- UPIU_COMMAND_SET_TYPE_SCSI, 0, 0, 0);
+ if (hba->ufs_version == UFSHCI_VERSION_10) {
+ u32 rw;
+ rw = (set & INTERRUPT_MASK_RW_VER_10) &
+ ~(intrs & INTERRUPT_MASK_RW_VER_10);
+ set = rw | ((set & intrs) & ~INTERRUPT_MASK_RW_VER_10);
- /* Total EHS length and Data segment length will be zero */
- ucd_req_ptr->header.dword_2 = 0;
-
- ucd_req_ptr->sc.exp_data_transfer_len =
- cpu_to_be32(lrbp->cmd->sdb.length);
-
- memcpy(ucd_req_ptr->sc.cdb, lrbp->cmd->cmnd,
- (min_t(unsigned short, lrbp->cmd->cmd_len, MAX_CDB_SIZE)));
-}
-
-/**
- * ufshcd_prepare_utp_query_req_upiu() - fills the utp_transfer_req_desc,
- * for query requsts
- * @hba: UFS hba
- * @lrbp: local reference block pointer
- * @upiu_flags: flags
- */
-static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba,
- struct ufshcd_lrb *lrbp,
- u32 upiu_flags)
-{
- struct utp_upiu_req *ucd_req_ptr = lrbp->ucd_req_ptr;
- u16 len = hba->query.request->upiu_req.length;
- u8 *descp = (u8 *)lrbp->ucd_req_ptr + GENERAL_UPIU_REQUEST_SIZE;
-
- /* Query request header */
- ucd_req_ptr->header.dword_0 = UPIU_HEADER_DWORD(
- UPIU_TRANSACTION_QUERY_REQ, upiu_flags,
- lrbp->lun, lrbp->task_tag);
- ucd_req_ptr->header.dword_1 = UPIU_HEADER_DWORD(
- 0, hba->query.request->query_func, 0, 0);
-
- /* Data segment length */
- ucd_req_ptr->header.dword_2 = UPIU_HEADER_DWORD(
- 0, 0, len >> 8, (u8)len);
-
- /* Copy the Query Request buffer as is */
- memcpy(&lrbp->ucd_req_ptr->qr, &hba->query.request->upiu_req,
- QUERY_OSF_SIZE);
- ufshcd_query_to_be(&lrbp->ucd_req_ptr->qr);
-
- /* Copy the Descriptor */
- if (hba->query.descriptor != NULL && len > 0 &&
- (hba->query.request->upiu_req.opcode ==
- UPIU_QUERY_OPCODE_WRITE_DESC)) {
- memcpy(descp, hba->query.descriptor,
- min_t(u16, len, UPIU_HEADER_DATA_SEGMENT_MAX_SIZE));
+ } else {
+ set &= ~intrs;
}
+ ufshcd_writel(hba, set, REG_INTERRUPT_ENABLE);
}
/**
* ufshcd_compose_upiu - form UFS Protocol Information Unit(UPIU)
- * @hba - UFS hba
* @lrb - pointer to local reference block
*/
-static int ufshcd_compose_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
+static void ufshcd_compose_upiu(struct ufshcd_lrb *lrbp)
{
+ struct utp_transfer_req_desc *req_desc;
+ struct utp_upiu_cmd *ucd_cmd_ptr;
+ u32 data_direction;
u32 upiu_flags;
- int ret = 0;
+
+ ucd_cmd_ptr = lrbp->ucd_cmd_ptr;
+ req_desc = lrbp->utr_descriptor_ptr;
switch (lrbp->command_type) {
case UTP_CMD_TYPE_SCSI:
+ if (lrbp->cmd->sc_data_direction == DMA_FROM_DEVICE) {
+ data_direction = UTP_DEVICE_TO_HOST;
+ upiu_flags = UPIU_CMD_FLAGS_READ;
+ } else if (lrbp->cmd->sc_data_direction == DMA_TO_DEVICE) {
+ data_direction = UTP_HOST_TO_DEVICE;
+ upiu_flags = UPIU_CMD_FLAGS_WRITE;
+ } else {
+ data_direction = UTP_NO_DATA_TRANSFER;
+ upiu_flags = UPIU_CMD_FLAGS_NONE;
+ }
+
+ /* Transfer request descriptor header fields */
+ req_desc->header.dword_0 =
+ cpu_to_le32(data_direction | UTP_SCSI_COMMAND);
+
+ /*
+ * assigning invalid value for command status. Controller
+ * updates OCS on command completion, with the command
+ * status
+ */
+ req_desc->header.dword_2 =
+ cpu_to_le32(OCS_INVALID_COMMAND_STATUS);
+
+ /* command descriptor fields */
+ ucd_cmd_ptr->header.dword_0 =
+ cpu_to_be32(UPIU_HEADER_DWORD(UPIU_TRANSACTION_COMMAND,
+ upiu_flags,
+ lrbp->lun,
+ lrbp->task_tag));
+ ucd_cmd_ptr->header.dword_1 =
+ cpu_to_be32(
+ UPIU_HEADER_DWORD(UPIU_COMMAND_SET_TYPE_SCSI,
+ 0,
+ 0,
+ 0));
+
+ /* Total EHS length and Data segment length will be zero */
+ ucd_cmd_ptr->header.dword_2 = 0;
+
+ ucd_cmd_ptr->exp_data_transfer_len =
+ cpu_to_be32(lrbp->cmd->sdb.length);
+
+ memcpy(ucd_cmd_ptr->cdb,
+ lrbp->cmd->cmnd,
+ (min_t(unsigned short,
+ lrbp->cmd->cmd_len,
+ MAX_CDB_SIZE)));
+ break;
case UTP_CMD_TYPE_DEV_MANAGE:
- ufshcd_prepare_req_desc(lrbp, &upiu_flags);
- if (lrbp->command_type == UTP_CMD_TYPE_SCSI)
- ufshcd_prepare_utp_scsi_cmd_upiu(lrbp, upiu_flags);
- else
- ufshcd_prepare_utp_query_req_upiu(hba, lrbp,
- upiu_flags);
+ /* For query function implementation */
break;
case UTP_CMD_TYPE_UFS:
/* For UFS native command implementation */
- dev_err(hba->dev, "%s: UFS native command are not supported\n",
- __func__);
- ret = -ENOTSUPP;
- break;
- default:
- ret = -ENOTSUPP;
- dev_err(hba->dev, "%s: unknown command type: 0x%x\n",
- __func__, lrbp->command_type);
break;
} /* end of switch */
-
- return ret;
}
/**
@@ -657,13 +655,10 @@
lrbp->task_tag = tag;
lrbp->lun = cmd->device->lun;
- if (ufshcd_is_query_req(lrbp))
- lrbp->command_type = UTP_CMD_TYPE_DEV_MANAGE;
- else
- lrbp->command_type = UTP_CMD_TYPE_SCSI;
+ lrbp->command_type = UTP_CMD_TYPE_SCSI;
/* form UPIU before issuing the command */
- ufshcd_compose_upiu(hba, lrbp);
+ ufshcd_compose_upiu(lrbp);
err = ufshcd_map_sg(lrbp);
if (err)
goto out;
@@ -677,109 +672,6 @@
}
/**
- * ufshcd_query_request() - Entry point for issuing query request to a
- * ufs device.
- * @hba: ufs driver context
- * @query: params for query request
- * @descriptor: buffer for sending/receiving descriptor
- * @response: pointer to a buffer that will contain the response code and
- * response upiu
- * @timeout: time limit for the command in seconds
- * @retries: number of times to try executing the command
- *
- * The query request is submitted to the same request queue as the rest of
- * the scsi commands passed to the UFS controller. In order to use this
- * queue, we need to receive a tag, same as all other commands. The tags
- * are issued from the block layer. To simulate a request from the block
- * layer, we use the same interface as the SCSI layer does when it issues
- * commands not generated by users. To distinguish a query request from
- * the SCSI commands, we use a vendor specific unused SCSI command
- * op-code. This op-code is not part of the SCSI command subset used in
- * UFS. In such way it is easy to check the command in the driver and
- * handle it appropriately.
- *
- * All necessary fields for issuing a query and receiving its response are
- * stored in the UFS hba struct. We can use this method since we know
- * there is only one active query request at all times.
- *
- * The request that will pass to the device is stored in "query" argument
- * passed to this function, while the "response" argument (which is output
- * field) will hold the query response from the device along with the
- * response code.
- */
-int ufshcd_query_request(struct ufs_hba *hba,
- struct ufs_query_req *query,
- u8 *descriptor,
- struct ufs_query_res *response,
- int timeout,
- int retries)
-{
- struct scsi_device *sdev;
- u8 cmd[UFS_QUERY_CMD_SIZE] = {0};
- int result;
- bool sdev_lookup = true;
-
- if (!hba || !query || !response) {
- pr_err("%s: NULL pointer hba = %p, query = %p response = %p\n",
- __func__, hba, query, response);
- return -EINVAL;
- }
-
- /*
- * A SCSI command structure is composed from opcode at the
- * begining and 0 at the end.
- */
- cmd[0] = UFS_QUERY_RESERVED_SCSI_CMD;
-
- /* extracting the SCSI Device */
- sdev = scsi_device_lookup(hba->host, 0, 0, 0);
- if (!sdev) {
- /**
- * There are some Query Requests that are sent during device
- * initialization, this happens before the scsi device was
- * initialized. If there is no scsi device, we generate a
- * temporary device to allow the Query Request flow.
- */
- sdev_lookup = false;
- sdev = scsi_get_host_dev(hba->host);
- }
-
- if (!sdev) {
- dev_err(hba->dev, "%s: Could not fetch scsi device\n",
- __func__);
- return -ENODEV;
- }
-
- mutex_lock(&hba->query.lock_ufs_query);
- hba->query.request = query;
- hba->query.descriptor = descriptor;
- hba->query.response = response;
-
- /* wait until request is completed */
- result = scsi_execute(sdev, cmd, DMA_NONE, NULL, 0, NULL,
- timeout, retries, 0, NULL);
- if (result) {
- dev_err(hba->dev,
- "%s: Query with opcode 0x%x, failed with result %d\n",
- __func__, query->upiu_req.opcode, result);
- result = -EIO;
- }
-
- hba->query.request = NULL;
- hba->query.descriptor = NULL;
- hba->query.response = NULL;
- mutex_unlock(&hba->query.lock_ufs_query);
-
- /* Releasing scsi device resource */
- if (sdev_lookup)
- scsi_device_put(sdev);
- else
- scsi_free_host_dev(sdev);
-
- return result;
-}
-
-/**
* ufshcd_memory_alloc - allocate memory for host memory space data structures
* @hba: per adapter instance
*
@@ -910,11 +802,11 @@
utrdlp[i].prd_table_offset =
cpu_to_le16((prdt_offset >> 2));
utrdlp[i].response_upiu_length =
- cpu_to_le16(ALIGNED_UPIU_SIZE);
+ cpu_to_le16(ALIGNED_UPIU_SIZE >> 2);
hba->lrb[i].utr_descriptor_ptr = (utrdlp + i);
- hba->lrb[i].ucd_req_ptr =
- (struct utp_upiu_req *)(cmd_descp + i);
+ hba->lrb[i].ucd_cmd_ptr =
+ (struct utp_upiu_cmd *)(cmd_descp + i);
hba->lrb[i].ucd_rsp_ptr =
(struct utp_upiu_rsp *)cmd_descp[i].response_upiu;
hba->lrb[i].ucd_prdt_ptr =
@@ -935,35 +827,16 @@
*/
static int ufshcd_dme_link_startup(struct ufs_hba *hba)
{
- struct uic_command *uic_cmd;
- unsigned long flags;
+ struct uic_command uic_cmd = {0};
+ int ret;
- /* check if controller is ready to accept UIC commands */
- if (((readl(hba->mmio_base + REG_CONTROLLER_STATUS)) &
- UIC_COMMAND_READY) == 0x0) {
+ uic_cmd.command = UIC_CMD_DME_LINK_STARTUP;
+
+ ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
+ if (ret)
dev_err(hba->dev,
- "Controller not ready"
- " to accept UIC commands\n");
- return -EIO;
- }
-
- spin_lock_irqsave(hba->host->host_lock, flags);
-
- /* form UIC command */
- uic_cmd = &hba->active_uic_cmd;
- uic_cmd->command = UIC_CMD_DME_LINK_STARTUP;
- uic_cmd->argument1 = 0;
- uic_cmd->argument2 = 0;
- uic_cmd->argument3 = 0;
-
- /* enable UIC related interrupts */
- hba->int_enable_mask |= UIC_COMMAND_COMPL;
- ufshcd_int_config(hba, UFSHCD_INT_ENABLE);
-
- /* sending UIC commands to controller */
- ufshcd_send_uic_command(hba, uic_cmd);
- spin_unlock_irqrestore(hba->host->host_lock, flags);
- return 0;
+ "dme-link-startup: error code %d\n", ret);
+ return ret;
}
/**
@@ -972,9 +845,10 @@
*
* To bring UFS host controller to operational state,
* 1. Check if device is present
- * 2. Configure run-stop-registers
- * 3. Enable required interrupts
- * 4. Configure interrupt aggregation
+ * 2. Enable required interrupts
+ * 3. Configure interrupt aggregation
+ * 4. Program UTRL and UTMRL base addres
+ * 5. Configure run-stop-registers
*
* Returns 0 on success, non-zero value on failure
*/
@@ -984,13 +858,29 @@
u32 reg;
/* check if device present */
- reg = readl((hba->mmio_base + REG_CONTROLLER_STATUS));
+ reg = ufshcd_readl(hba, REG_CONTROLLER_STATUS);
if (!ufshcd_is_device_present(reg)) {
dev_err(hba->dev, "cc: Device not present\n");
err = -ENXIO;
goto out;
}
+ /* Enable required interrupts */
+ ufshcd_enable_intr(hba, UFSHCD_ENABLE_INTRS);
+
+ /* Configure interrupt aggregation */
+ ufshcd_config_int_aggr(hba, INT_AGGR_CONFIG);
+
+ /* Configure UTRL and UTMRL base address registers */
+ ufshcd_writel(hba, lower_32_bits(hba->utrdl_dma_addr),
+ REG_UTP_TRANSFER_REQ_LIST_BASE_L);
+ ufshcd_writel(hba, upper_32_bits(hba->utrdl_dma_addr),
+ REG_UTP_TRANSFER_REQ_LIST_BASE_H);
+ ufshcd_writel(hba, lower_32_bits(hba->utmrdl_dma_addr),
+ REG_UTP_TASK_REQ_LIST_BASE_L);
+ ufshcd_writel(hba, upper_32_bits(hba->utmrdl_dma_addr),
+ REG_UTP_TASK_REQ_LIST_BASE_H);
+
/*
* UCRDY, UTMRLDY and UTRLRDY bits must be 1
* DEI, HEI bits must be 0
@@ -1004,23 +894,11 @@
goto out;
}
- /* Enable required interrupts */
- hba->int_enable_mask |= (UTP_TRANSFER_REQ_COMPL |
- UIC_ERROR |
- UTP_TASK_REQ_COMPL |
- DEVICE_FATAL_ERROR |
- CONTROLLER_FATAL_ERROR |
- SYSTEM_BUS_FATAL_ERROR);
- ufshcd_int_config(hba, UFSHCD_INT_ENABLE);
-
- /* Configure interrupt aggregation */
- ufshcd_config_int_aggr(hba, INT_AGGR_CONFIG);
-
if (hba->ufshcd_state == UFSHCD_STATE_RESET)
scsi_unblock_requests(hba->host);
hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL;
- scsi_scan_host(hba->host);
+
out:
return err;
}
@@ -1089,34 +967,28 @@
}
/**
- * ufshcd_initialize_hba - start the initialization process
+ * ufshcd_link_startup - Initialize unipro link startup
* @hba: per adapter instance
*
- * 1. Enable the controller via ufshcd_hba_enable.
- * 2. Program the Transfer Request List Address with the starting address of
- * UTRDL.
- * 3. Program the Task Management Request List Address with starting address
- * of UTMRDL.
- *
- * Returns 0 on success, non-zero value on failure.
+ * Returns 0 for success, non-zero in case of failure
*/
-static int ufshcd_initialize_hba(struct ufs_hba *hba)
+static int ufshcd_link_startup(struct ufs_hba *hba)
{
- if (ufshcd_hba_enable(hba))
- return -EIO;
+ int ret;
- /* Configure UTRL and UTMRL base address registers */
- writel(lower_32_bits(hba->utrdl_dma_addr),
- (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_BASE_L));
- writel(upper_32_bits(hba->utrdl_dma_addr),
- (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_BASE_H));
- writel(lower_32_bits(hba->utmrdl_dma_addr),
- (hba->mmio_base + REG_UTP_TASK_REQ_LIST_BASE_L));
- writel(upper_32_bits(hba->utmrdl_dma_addr),
- (hba->mmio_base + REG_UTP_TASK_REQ_LIST_BASE_H));
+ /* enable UIC related interrupts */
+ ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
- /* Initialize unipro link startup procedure */
- return ufshcd_dme_link_startup(hba);
+ ret = ufshcd_dme_link_startup(hba);
+ if (ret)
+ goto out;
+
+ ret = ufshcd_make_hba_operational(hba);
+
+out:
+ if (ret)
+ dev_err(hba->dev, "link startup failed %d\n", ret);
+ return ret;
}
/**
@@ -1156,12 +1028,19 @@
hba->outstanding_reqs = 0;
hba->outstanding_tasks = 0;
- /* start the initialization process */
- if (ufshcd_initialize_hba(hba)) {
+ /* Host controller enable */
+ if (ufshcd_hba_enable(hba)) {
dev_err(hba->dev,
"Reset: Controller initialization failed\n");
return FAILED;
}
+
+ if (ufshcd_link_startup(hba)) {
+ dev_err(hba->dev,
+ "Reset: Link start-up failed\n");
+ return FAILED;
+ }
+
return SUCCESS;
}
@@ -1337,9 +1216,7 @@
* @hba: per adapter instance
* @lrb: pointer to local reference block of completed command
*
- * Returns result of the command to notify SCSI midlayer. In
- * case of query request specific result, returns DID_OK, and
- * the error will be handled by the dispatcher.
+ * Returns result of the command to notify SCSI midlayer
*/
static inline int
ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
@@ -1353,46 +1230,27 @@
switch (ocs) {
case OCS_SUCCESS:
+
/* check if the returned transfer response is valid */
- result = ufshcd_get_req_rsp(lrbp->ucd_rsp_ptr);
-
- switch (result) {
- case UPIU_TRANSACTION_RESPONSE:
- /*
- * get the response UPIU result to extract
- * the SCSI command status
- */
- result = ufshcd_get_rsp_upiu_result(lrbp->ucd_rsp_ptr);
-
- /*
- * get the result based on SCSI status response
- * to notify the SCSI midlayer of the command status
- */
- scsi_status = result & MASK_SCSI_STATUS;
- result = ufshcd_scsi_cmd_status(lrbp, scsi_status);
- break;
- case UPIU_TRANSACTION_QUERY_RSP:
- /*
- * Return result = ok, since SCSI layer wouldn't
- * know how to handle errors from query requests.
- * The result is saved with the response so that
- * the ufs_core layer will handle it.
- */
- result = DID_OK << 16;
- ufshcd_copy_query_response(hba, lrbp);
- break;
- case UPIU_TRANSACTION_REJECT_UPIU:
- /* TODO: handle Reject UPIU Response */
- result = DID_ERROR << 16;
+ result = ufshcd_is_valid_req_rsp(lrbp->ucd_rsp_ptr);
+ if (result) {
dev_err(hba->dev,
- "Reject UPIU not fully implemented\n");
+ "Invalid response = %x\n", result);
break;
- default:
- result = DID_ERROR << 16;
- dev_err(hba->dev,
- "Unexpected request response code = %x\n",
- result);
}
+
+ /*
+ * get the response UPIU result to extract
+ * the SCSI command status
+ */
+ result = ufshcd_get_rsp_upiu_result(lrbp->ucd_rsp_ptr);
+
+ /*
+ * get the result based on SCSI status response
+ * to notify the SCSI midlayer of the command status
+ */
+ scsi_status = result & MASK_SCSI_STATUS;
+ result = ufshcd_scsi_cmd_status(lrbp, scsi_status);
break;
case OCS_ABORTED:
result |= DID_ABORT << 16;
@@ -1414,6 +1272,19 @@
}
/**
+ * ufshcd_uic_cmd_compl - handle completion of uic command
+ * @hba: per adapter instance
+ */
+static void ufshcd_uic_cmd_compl(struct ufs_hba *hba)
+{
+ if (hba->active_uic_cmd) {
+ hba->active_uic_cmd->argument2 |=
+ ufshcd_get_uic_cmd_result(hba);
+ complete(&hba->active_uic_cmd->done);
+ }
+}
+
+/**
* ufshcd_transfer_req_compl - handle SCSI and query command completion
* @hba: per adapter instance
*/
@@ -1426,8 +1297,7 @@
int index;
lrb = hba->lrb;
- tr_doorbell =
- readl(hba->mmio_base + REG_UTP_TRANSFER_REQ_DOOR_BELL);
+ tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
completed_reqs = tr_doorbell ^ hba->outstanding_reqs;
for (index = 0; index < hba->nutrs; index++) {
@@ -1454,28 +1324,6 @@
}
/**
- * ufshcd_uic_cc_handler - handle UIC command completion
- * @work: pointer to a work queue structure
- *
- * Returns 0 on success, non-zero value on failure
- */
-static void ufshcd_uic_cc_handler (struct work_struct *work)
-{
- struct ufs_hba *hba;
-
- hba = container_of(work, struct ufs_hba, uic_workq);
-
- if ((hba->active_uic_cmd.command == UIC_CMD_DME_LINK_STARTUP) &&
- !(ufshcd_get_uic_cmd_result(hba))) {
-
- if (ufshcd_make_hba_operational(hba))
- dev_err(hba->dev,
- "cc: hba not operational state\n");
- return;
- }
-}
-
-/**
* ufshcd_fatal_err_handler - handle fatal errors
* @hba: per adapter instance
*/
@@ -1501,9 +1349,7 @@
goto fatal_eh;
if (hba->errors & UIC_ERROR) {
-
- reg = readl(hba->mmio_base +
- REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER);
+ reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER);
if (reg & UIC_DATA_LINK_LAYER_ERROR_PA_INIT)
goto fatal_eh;
}
@@ -1521,7 +1367,7 @@
{
u32 tm_doorbell;
- tm_doorbell = readl(hba->mmio_base + REG_UTP_TASK_REQ_DOOR_BELL);
+ tm_doorbell = ufshcd_readl(hba, REG_UTP_TASK_REQ_DOOR_BELL);
hba->tm_condition = tm_doorbell ^ hba->outstanding_tasks;
wake_up_interruptible(&hba->ufshcd_tm_wait_queue);
}
@@ -1538,7 +1384,7 @@
ufshcd_err_handler(hba);
if (intr_status & UIC_COMMAND_COMPL)
- schedule_work(&hba->uic_workq);
+ ufshcd_uic_cmd_compl(hba);
if (intr_status & UTP_TASK_REQ_COMPL)
ufshcd_tmc_handler(hba);
@@ -1562,15 +1408,11 @@
struct ufs_hba *hba = __hba;
spin_lock(hba->host->host_lock);
- intr_status = readl(hba->mmio_base + REG_INTERRUPT_STATUS);
+ intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
if (intr_status) {
+ ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
ufshcd_sl_intr(hba, intr_status);
-
- /* If UFSHCI 1.0 then clear interrupt status register */
- if (hba->ufs_version == UFSHCI_VERSION_10)
- writel(intr_status,
- (hba->mmio_base + REG_INTERRUPT_STATUS));
retval = IRQ_HANDLED;
}
spin_unlock(hba->host->host_lock);
@@ -1621,10 +1463,10 @@
task_req_upiup =
(struct utp_upiu_task_req *) task_req_descp->task_req_upiu;
task_req_upiup->header.dword_0 =
- UPIU_HEADER_DWORD(UPIU_TRANSACTION_TASK_REQ, 0,
- lrbp->lun, lrbp->task_tag);
+ cpu_to_be32(UPIU_HEADER_DWORD(UPIU_TRANSACTION_TASK_REQ, 0,
+ lrbp->lun, lrbp->task_tag));
task_req_upiup->header.dword_1 =
- UPIU_HEADER_DWORD(0, tm_function, 0, 0);
+ cpu_to_be32(UPIU_HEADER_DWORD(0, tm_function, 0, 0));
task_req_upiup->input_param1 = lrbp->lun;
task_req_upiup->input_param1 =
@@ -1635,8 +1477,7 @@
/* send command to the controller */
__set_bit(free_slot, &hba->outstanding_tasks);
- writel((1 << free_slot),
- (hba->mmio_base + REG_UTP_TASK_REQ_DOOR_BELL));
+ ufshcd_writel(hba, 1 << free_slot, REG_UTP_TASK_REQ_DOOR_BELL);
spin_unlock_irqrestore(host->host_lock, flags);
@@ -1766,6 +1607,21 @@
return err;
}
+/**
+ * ufshcd_async_scan - asynchronous execution for link startup
+ * @data: data pointer to pass to this function
+ * @cookie: cookie data
+ */
+static void ufshcd_async_scan(void *data, async_cookie_t cookie)
+{
+ struct ufs_hba *hba = (struct ufs_hba *)data;
+ int ret;
+
+ ret = ufshcd_link_startup(hba);
+ if (!ret)
+ scsi_scan_host(hba->host);
+}
+
static struct scsi_host_template ufshcd_driver_template = {
.module = THIS_MODULE,
.name = UFSHCD,
@@ -1844,7 +1700,7 @@
void ufshcd_remove(struct ufs_hba *hba)
{
/* disable interrupts */
- ufshcd_int_config(hba, UFSHCD_INT_DISABLE);
+ ufshcd_disable_intr(hba, hba->intr_mask);
ufshcd_hba_stop(hba);
ufshcd_hba_free(hba);
@@ -1902,6 +1758,9 @@
/* Get UFS version supported by the controller */
hba->ufs_version = ufshcd_get_ufs_version(hba);
+ /* Get Interrupt bit mask per version */
+ hba->intr_mask = ufshcd_get_intr_mask(hba);
+
/* Allocate memory for host memory space */
err = ufshcd_memory_alloc(hba);
if (err) {
@@ -1924,11 +1783,10 @@
init_waitqueue_head(&hba->ufshcd_tm_wait_queue);
/* Initialize work queues */
- INIT_WORK(&hba->uic_workq, ufshcd_uic_cc_handler);
INIT_WORK(&hba->feh_workq, ufshcd_fatal_err_handler);
- /* Initialize mutex for query requests */
- mutex_init(&hba->query.lock_ufs_query);
+ /* Initialize UIC command mutex */
+ mutex_init(&hba->uic_cmd_mutex);
/* IRQ registration */
err = request_irq(irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba);
@@ -1950,14 +1808,17 @@
goto out_free_irq;
}
- /* Initialization routine */
- err = ufshcd_initialize_hba(hba);
+ /* Host controller enable */
+ err = ufshcd_hba_enable(hba);
if (err) {
- dev_err(hba->dev, "Initialization failed\n");
+ dev_err(hba->dev, "Host controller enable failed\n");
goto out_remove_scsi_host;
}
+
*hba_handle = hba;
+ async_schedule(ufshcd_async_scan, hba);
+
return 0;
out_remove_scsi_host:
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 336980b..49590ee 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -51,6 +51,7 @@
#include <linux/bitops.h>
#include <linux/pm_runtime.h>
#include <linux/clk.h>
+#include <linux/completion.h>
#include <asm/irq.h>
#include <asm/byteorder.h>
@@ -60,7 +61,6 @@
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_dbg.h>
#include <scsi/scsi_eh.h>
-#include <scsi/scsi_device.h>
#include "ufs.h"
#include "ufshci.h"
@@ -76,6 +76,7 @@
* @argument3: UIC command argument 3
* @cmd_active: Indicate if UIC command is outstanding
* @result: UIC command result
+ * @done: UIC command completion
*/
struct uic_command {
u32 command;
@@ -84,12 +85,13 @@
u32 argument3;
int cmd_active;
int result;
+ struct completion done;
};
/**
* struct ufshcd_lrb - local reference block
* @utr_descriptor_ptr: UTRD address of the command
- * @ucd_req_ptr: UCD address of the command
+ * @ucd_cmd_ptr: UCD address of the command
* @ucd_rsp_ptr: Response UPIU address for this command
* @ucd_prdt_ptr: PRDT address of the command
* @cmd: pointer to SCSI command
@@ -102,7 +104,7 @@
*/
struct ufshcd_lrb {
struct utp_transfer_req_desc *utr_descriptor_ptr;
- struct utp_upiu_req *ucd_req_ptr;
+ struct utp_upiu_cmd *ucd_cmd_ptr;
struct utp_upiu_rsp *ucd_rsp_ptr;
struct ufshcd_sg_entry *ucd_prdt_ptr;
@@ -116,19 +118,6 @@
unsigned int lun;
};
-/**
- * struct ufs_query - keeps the query request information
- * @request: request upiu and function
- * @descriptor: buffer for sending/receiving descriptor
- * @response: response upiu and response
- * @mutex: lock to allow one query at a time
- */
-struct ufs_query {
- struct ufs_query_req *request;
- u8 *descriptor;
- struct ufs_query_res *response;
- struct mutex lock_ufs_query;
-};
/**
* struct ufs_hba - per adapter private structure
@@ -150,14 +139,13 @@
* @ufs_version: UFS Version to which controller complies
* @irq: Irq number of the controller
* @active_uic_cmd: handle of active UIC command
+ * @uic_cmd_mutex: mutex for uic command
* @ufshcd_tm_wait_queue: wait queue for task management
* @tm_condition: condition variable for task management
* @ufshcd_state: UFSHCD states
- * @int_enable_mask: Interrupt Mask Bits
- * @uic_workq: Work queue for UIC completion handling
+ * @intr_mask: Interrupt Mask Bits
* @feh_workq: Work queue for fatal controller error handling
* @errors: HBA errors
- * @query: query request information
*/
struct ufs_hba {
void __iomem *mmio_base;
@@ -186,24 +174,27 @@
u32 ufs_version;
unsigned int irq;
- struct uic_command active_uic_cmd;
+ struct uic_command *active_uic_cmd;
+ struct mutex uic_cmd_mutex;
+
wait_queue_head_t ufshcd_tm_wait_queue;
unsigned long tm_condition;
u32 ufshcd_state;
- u32 int_enable_mask;
+ u32 intr_mask;
/* Work Queues */
- struct work_struct uic_workq;
struct work_struct feh_workq;
/* HBA Errors */
u32 errors;
-
- /* Query Request */
- struct ufs_query query;
};
+#define ufshcd_writel(hba, val, reg) \
+ writel((val), (hba)->mmio_base + (reg))
+#define ufshcd_readl(hba, reg) \
+ readl((hba)->mmio_base + (reg))
+
int ufshcd_init(struct device *, struct ufs_hba ** , void __iomem * ,
unsigned int);
void ufshcd_remove(struct ufs_hba *);
@@ -214,7 +205,7 @@
*/
static inline void ufshcd_hba_stop(struct ufs_hba *hba)
{
- writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE));
+ ufshcd_writel(hba, CONTROLLER_DISABLE, REG_CONTROLLER_ENABLE);
}
#endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index 4a86247..d5c5f14 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -39,7 +39,7 @@
enum {
TASK_REQ_UPIU_SIZE_DWORDS = 8,
TASK_RSP_UPIU_SIZE_DWORDS = 8,
- ALIGNED_UPIU_SIZE = 512,
+ ALIGNED_UPIU_SIZE = 128,
};
/* UFSHCI Registers */
@@ -232,10 +232,11 @@
/* Interrupt disable masks */
enum {
/* Interrupt disable mask for UFSHCI v1.0 */
- INTERRUPT_DISABLE_MASK_10 = 0xFFFF,
+ INTERRUPT_MASK_ALL_VER_10 = 0x30FFF,
+ INTERRUPT_MASK_RW_VER_10 = 0x30000,
/* Interrupt disable mask for UFSHCI v1.1 */
- INTERRUPT_DISABLE_MASK_11 = 0x0,
+ INTERRUPT_MASK_ALL_VER_11 = 0x31FFF,
};
/*
diff --git a/drivers/slimbus/slim-msm-ctrl.c b/drivers/slimbus/slim-msm-ctrl.c
index 97d47db..6e7a815 100644
--- a/drivers/slimbus/slim-msm-ctrl.c
+++ b/drivers/slimbus/slim-msm-ctrl.c
@@ -30,12 +30,6 @@
#define MSM_SLIM_NAME "msm_slim_ctrl"
#define SLIM_ROOT_FREQ 24576000
-#define QC_MFGID_LSB 0x2
-#define QC_MFGID_MSB 0x17
-#define QC_CHIPID_SL 0x10
-#define QC_DEVID_SAT1 0x3
-#define QC_DEVID_SAT2 0x4
-#define QC_DEVID_PGD 0x5
#define QC_MSM_DEVS 5
/* Manager registers */
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index 509c1e8..2f19863 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -306,8 +306,26 @@
txn->mc = SLIM_USR_MC_CONNECT_SINK;
else if (txn->mc == SLIM_MSG_MC_DISCONNECT_PORT)
txn->mc = SLIM_USR_MC_DISCONNECT_PORT;
- if (txn->la == SLIM_LA_MGR)
+ if (txn->la == SLIM_LA_MGR) {
+ if (dev->pgdla == SLIM_LA_MGR) {
+ u8 ea[] = {0, QC_DEVID_PGD, 0, 0, QC_MFGID_MSB,
+ QC_MFGID_LSB};
+ ea[2] = (u8)(dev->pdata.eapc & 0xFF);
+ ea[3] = (u8)((dev->pdata.eapc & 0xFF00) >> 8);
+ mutex_unlock(&dev->tx_lock);
+ ret = dev->ctrl.get_laddr(&dev->ctrl, ea, 6,
+ &dev->pgdla);
+ pr_debug("SLIM PGD LA:0x%x, ret:%d", dev->pgdla,
+ ret);
+ if (ret) {
+ pr_err("Incorrect SLIM-PGD EAPC:0x%x",
+ dev->pdata.eapc);
+ return ret;
+ }
+ mutex_lock(&dev->tx_lock);
+ }
txn->la = dev->pgdla;
+ }
wbuf[i++] = txn->la;
la = SLIM_LA_MGR;
wbuf[i++] = txn->wbuf[0];
@@ -380,6 +398,8 @@
dev_err(dev->dev, "pipe-port connect err:%d", dev->err);
goto ngd_xfer_err;
}
+ /* Add port-base to port number if this is manager side port */
+ puc[1] += dev->port_b;
}
dev->err = 0;
dev->wr_comp = &tx_sent;
@@ -1070,9 +1090,18 @@
}
rxreg_access = of_property_read_bool(pdev->dev.of_node,
"qcom,rxreg-access");
+ of_property_read_u32(pdev->dev.of_node, "qcom,apps-ch-pipes",
+ &dev->pdata.apps_pipes);
+ of_property_read_u32(pdev->dev.of_node, "qcom,ea-pc",
+ &dev->pdata.eapc);
} else {
dev->ctrl.nr = pdev->id;
}
+ /*
+ * Keep PGD's logical address as manager's. Query it when first data
+ * channel request comes in
+ */
+ dev->pgdla = SLIM_LA_MGR;
dev->ctrl.nchans = MSM_SLIM_NCHANS;
dev->ctrl.nports = MSM_SLIM_NPORTS;
dev->framer.rootfreq = SLIM_ROOT_FREQ >> 3;
diff --git a/drivers/slimbus/slim-msm.c b/drivers/slimbus/slim-msm.c
index a63ee76..37bc883 100644
--- a/drivers/slimbus/slim-msm.c
+++ b/drivers/slimbus/slim-msm.c
@@ -788,6 +788,10 @@
bam_props.options = SPS_O_DESC_DONE | SPS_O_ERROR |
SPS_O_ACK_TRANSFERS | SPS_O_AUTO_ENABLE;
+ /* override apps channel pipes if specified in platform-data or DT */
+ if (dev->pdata.apps_pipes)
+ sec_props.ees[dev->ee].pipe_mask = dev->pdata.apps_pipes;
+
/* First 7 bits are for message Qs */
for (i = 7; i < 32; i++) {
/* Check what pipes are owned by Apps. */
diff --git a/drivers/slimbus/slim-msm.h b/drivers/slimbus/slim-msm.h
index 896e196..b5c41ed 100644
--- a/drivers/slimbus/slim-msm.h
+++ b/drivers/slimbus/slim-msm.h
@@ -50,6 +50,13 @@
#define MSM_SLIM_NPORTS 24
#define MSM_SLIM_NCHANS 32
+#define QC_MFGID_LSB 0x2
+#define QC_MFGID_MSB 0x17
+#define QC_CHIPID_SL 0x10
+#define QC_DEVID_SAT1 0x3
+#define QC_DEVID_SAT2 0x4
+#define QC_DEVID_PGD 0x5
+
#define SLIM_MSG_ASM_FIRST_WORD(l, mt, mc, dt, ad) \
((l) | ((mt) << 5) | ((mc) << 8) | ((dt) << 15) | ((ad) << 16))
@@ -198,6 +205,11 @@
struct work_struct ssr_up;
};
+struct msm_slim_pdata {
+ u32 apps_pipes;
+ u32 eapc;
+};
+
struct msm_slim_ctrl {
struct slim_controller ctrl;
struct slim_framer framer;
@@ -240,6 +252,7 @@
u32 ver;
struct work_struct slave_notify;
struct msm_slim_qmi qmi;
+ struct msm_slim_pdata pdata;
};
struct msm_sat_chan {
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index 53aa475..b389187 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -720,6 +720,73 @@
}
}
+static int msm_spi_bam_pipe_disconnect(struct msm_spi *dd,
+ struct msm_spi_bam_pipe *pipe)
+{
+ int ret = sps_disconnect(pipe->handle);
+ if (ret) {
+ dev_dbg(dd->dev, "%s disconnect bam %s pipe failed\n",
+ __func__, pipe->name);
+ return ret;
+ }
+ return 0;
+}
+
+static int msm_spi_bam_pipe_connect(struct msm_spi *dd,
+ struct msm_spi_bam_pipe *pipe, struct sps_connect *config)
+{
+ int ret;
+ struct sps_register_event event = {
+ .mode = SPS_TRIGGER_WAIT,
+ .options = SPS_O_EOT,
+ .xfer_done = &dd->transfer_complete,
+ };
+
+ ret = sps_connect(pipe->handle, config);
+ if (ret) {
+ dev_err(dd->dev, "%s: sps_connect(%s:0x%p):%d",
+ __func__, pipe->name, pipe->handle, ret);
+ return ret;
+ }
+
+ ret = sps_register_event(pipe->handle, &event);
+ if (ret) {
+ dev_err(dd->dev, "%s sps_register_event(hndl:0x%p %s):%d",
+ __func__, pipe->handle, pipe->name, ret);
+ msm_spi_bam_pipe_disconnect(dd, pipe);
+ return ret;
+ }
+
+ pipe->teardown_required = true;
+ return 0;
+}
+
+
+static void msm_spi_bam_pipe_flush(struct msm_spi *dd,
+ enum msm_spi_pipe_direction pipe_dir)
+{
+ struct msm_spi_bam_pipe *pipe = (pipe_dir == SPI_BAM_CONSUMER_PIPE) ?
+ (&dd->bam.prod) : (&dd->bam.cons);
+ struct sps_connect config = pipe->config;
+ int ret;
+
+ ret = msm_spi_bam_pipe_disconnect(dd, pipe);
+ if (ret)
+ return;
+
+ ret = msm_spi_bam_pipe_connect(dd, pipe, &config);
+ if (ret)
+ return;
+}
+
+static void msm_spi_bam_flush(struct msm_spi *dd)
+{
+ dev_dbg(dd->dev, "%s flushing bam for recovery\n" , __func__);
+
+ msm_spi_bam_pipe_flush(dd, SPI_BAM_CONSUMER_PIPE);
+ msm_spi_bam_pipe_flush(dd, SPI_BAM_PRODUCER_PIPE);
+}
+
/**
* msm_spi_bam_begin_transfer: transfer dd->tx_bytes_remaining bytes
* using BAM.
@@ -1359,9 +1426,10 @@
dma_coherent_post_ops();
memcpy(dd->read_buf + offset, dd->rx_padding,
dd->rx_unaligned_len);
- memcpy(dd->cur_transfer->rx_buf,
- dd->read_buf + prev_xfr->len,
- dd->cur_transfer->len);
+ if (dd->cur_transfer->rx_buf)
+ memcpy(dd->cur_transfer->rx_buf,
+ dd->read_buf + prev_xfr->len,
+ dd->cur_transfer->len);
}
}
kfree(dd->temp_buf);
@@ -1681,6 +1749,8 @@
msm_dmov_flush(dd->tx_dma_chan, 1);
msm_dmov_flush(dd->rx_dma_chan, 1);
}
+ if (dd->mode == SPI_BAM_MODE)
+ msm_spi_bam_flush(dd);
break;
}
} while (msm_spi_dm_send_next(dd));
@@ -2312,7 +2382,7 @@
if (!pipe->teardown_required)
return;
- sps_disconnect(pipe->handle);
+ msm_spi_bam_pipe_disconnect(dd, pipe);
dma_free_coherent(dd->dev, pipe->config.desc.size,
pipe->config.desc.base, pipe->config.desc.phys_base);
sps_free_endpoint(pipe->handle);
@@ -2325,13 +2395,13 @@
{
int rc = 0;
struct sps_pipe *pipe_handle;
- struct sps_register_event event = {0};
struct msm_spi_bam_pipe *pipe = (pipe_dir == SPI_BAM_CONSUMER_PIPE) ?
(&dd->bam.prod) : (&dd->bam.cons);
struct sps_connect *pipe_conf = &pipe->config;
+ pipe->name = (pipe_dir == SPI_BAM_CONSUMER_PIPE) ? "cons" : "prod";
pipe->handle = 0;
- pipe_handle = sps_alloc_endpoint();
+ pipe_handle = sps_alloc_endpoint();
if (!pipe_handle) {
dev_err(dd->dev, "%s: Failed to allocate BAM endpoint\n"
, __func__);
@@ -2373,32 +2443,16 @@
rc = -ENOMEM;
goto config_err;
}
-
+ /* zero descriptor FIFO for convenient debugging of first descs */
memset(pipe_conf->desc.base, 0x00, pipe_conf->desc.size);
- rc = sps_connect(pipe_handle, pipe_conf);
- if (rc) {
- dev_err(dd->dev, "%s: Failed to connect BAM pipe", __func__);
- goto connect_err;
- }
-
- event.mode = SPS_TRIGGER_WAIT;
- event.options = SPS_O_EOT;
- event.xfer_done = &dd->transfer_complete;
- event.user = (void *)dd;
- rc = sps_register_event(pipe_handle, &event);
- if (rc) {
- dev_err(dd->dev, "%s: Failed to register BAM EOT event",
- __func__);
- goto register_err;
- }
-
pipe->handle = pipe_handle;
- pipe->teardown_required = true;
+ rc = msm_spi_bam_pipe_connect(dd, pipe, pipe_conf);
+ if (rc)
+ goto connect_err;
+
return 0;
-register_err:
- sps_disconnect(pipe_handle);
connect_err:
dma_free_coherent(dd->dev, pipe_conf->desc.size,
pipe_conf->desc.base, pipe_conf->desc.phys_base);
@@ -2665,7 +2719,7 @@
pdata->use_bam = false;
}
- if (pdata->bam_producer_pipe_index) {
+ if (!pdata->bam_producer_pipe_index) {
dev_warn(&pdev->dev,
"missing qcom,bam-producer-pipe-index entry in device-tree\n");
pdata->use_bam = false;
@@ -3068,7 +3122,7 @@
msm_spi_disable_irqs(dd);
clk_disable_unprepare(dd->clk);
clk_disable_unprepare(dd->pclk);
- if (!dd->pdata->active_only)
+ if (dd->pdata && !dd->pdata->active_only)
msm_spi_clk_path_unvote(dd);
/* Free the spi clk, miso, mosi, cs gpio */
diff --git a/drivers/spi/spi_qsd.h b/drivers/spi/spi_qsd.h
index 90d7481..2a67a61 100644
--- a/drivers/spi/spi_qsd.h
+++ b/drivers/spi/spi_qsd.h
@@ -277,6 +277,7 @@
};
struct msm_spi_bam_pipe {
+ const char *name;
struct sps_pipe *handle;
struct sps_connect config;
bool teardown_required;
diff --git a/drivers/spmi/qpnp-int.c b/drivers/spmi/qpnp-int.c
index 082c9ff..eedb1e5 100644
--- a/drivers/spmi/qpnp-int.c
+++ b/drivers/spmi/qpnp-int.c
@@ -578,11 +578,14 @@
unsigned long hwirq, busno;
int irq;
+ if (!spec || !spmi_ctrl)
+ return -EINVAL;
+
pr_debug("spec slave = %u per = %u irq = %u\n",
spec->slave, spec->per, spec->irq);
busno = spmi_ctrl->nr;
- if (!spec || !spmi_ctrl || busno >= QPNPINT_MAX_BUSSES)
+ if (busno >= QPNPINT_MAX_BUSSES)
return -EINVAL;
hwirq = qpnpint_encode_hwirq(spec);
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index bcec934..97d412d 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -84,8 +84,6 @@
source "drivers/staging/zcache/Kconfig"
-source "drivers/staging/qcache/Kconfig"
-
source "drivers/staging/zsmalloc/Kconfig"
source "drivers/staging/wlags49_h2/Kconfig"
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index c31f2ec..ffe7d44 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -34,7 +34,6 @@
obj-$(CONFIG_IIO) += iio/
obj-$(CONFIG_ZRAM) += zram/
obj-$(CONFIG_ZCACHE) += zcache/
-obj-$(CONFIG_QCACHE) += qcache/
obj-$(CONFIG_ZSMALLOC) += zsmalloc/
obj-$(CONFIG_WLAGS49_H2) += wlags49_h2/
obj-$(CONFIG_WLAGS49_H25) += wlags49_h25/
diff --git a/drivers/staging/qcache/Kconfig b/drivers/staging/qcache/Kconfig
deleted file mode 100644
index 389341c..0000000
--- a/drivers/staging/qcache/Kconfig
+++ /dev/null
@@ -1,8 +0,0 @@
-config QCACHE
- tristate "Dynamic compression of clean pagecache pages"
- depends on CLEANCACHE
- select LZO_COMPRESS
- select LZO_DECOMPRESS
- default n
- help
- Qcache is the backend for fmem
diff --git a/drivers/staging/qcache/Makefile b/drivers/staging/qcache/Makefile
deleted file mode 100644
index 4fdf05c..0000000
--- a/drivers/staging/qcache/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-qcache-y := qcache-main.o tmem.o fmem.o
-
-obj-$(CONFIG_QCACHE) += qcache.o
diff --git a/drivers/staging/qcache/fmem.c b/drivers/staging/qcache/fmem.c
deleted file mode 100644
index 0609f4a..0000000
--- a/drivers/staging/qcache/fmem.c
+++ /dev/null
@@ -1,344 +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/export.h>
-#include <linux/fmem.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#ifdef CONFIG_MEMORY_HOTPLUG
-#include <linux/memory.h>
-#include <linux/memory_hotplug.h>
-#endif
-#include "tmem.h"
-#include <asm/mach/map.h>
-
-struct fmem_data fmem_data;
-enum fmem_state fmem_state;
-static spinlock_t fmem_state_lock;
-
-#ifdef CONFIG_MEMORY_HOTPLUG
-static unsigned int section_powered_off[NR_MEM_SECTIONS];
-static unsigned int fmem_section_start, fmem_section_end;
-#endif
-
-void *fmem_map_virtual_area(int cacheability)
-{
- unsigned long addr;
- const struct mem_type *type;
- int ret;
-
- addr = (unsigned long) fmem_data.area->addr;
- type = get_mem_type(cacheability);
- ret = ioremap_pages(addr, fmem_data.phys, fmem_data.size, type);
- if (ret)
- return ERR_PTR(ret);
-
- fmem_data.virt = fmem_data.area->addr;
-
- return fmem_data.virt;
-}
-
-void fmem_unmap_virtual_area(void)
-{
- unmap_kernel_range((unsigned long)fmem_data.virt, fmem_data.size);
- fmem_data.virt = NULL;
-}
-
-static int fmem_probe(struct platform_device *pdev)
-{
- struct fmem_platform_data *pdata = pdev->dev.platform_data;
-
- if (!pdata->phys)
- pdata->phys = allocate_contiguous_ebi_nomap(pdata->size,
- pdata->align);
-
-#ifdef CONFIG_MEMORY_HOTPLUG
- fmem_section_start = pdata->phys >> PA_SECTION_SHIFT;
- fmem_section_end = (pdata->phys - 1 + pdata->size) >> PA_SECTION_SHIFT;
-#endif
- fmem_data.phys = pdata->phys + pdata->reserved_size_low;
- fmem_data.size = pdata->size - pdata->reserved_size_low -
- pdata->reserved_size_high;
- fmem_data.reserved_size_low = pdata->reserved_size_low;
- fmem_data.reserved_size_high = pdata->reserved_size_high;
-
- if (!fmem_data.size)
- return -ENODEV;
-
- fmem_data.area = get_vm_area(fmem_data.size, VM_IOREMAP);
- if (!fmem_data.area)
- return -ENOMEM;
-
- if (!fmem_map_virtual_area(MT_DEVICE_CACHED)) {
- remove_vm_area(fmem_data.area->addr);
- return -ENOMEM;
- }
- pr_info("fmem phys %lx virt %p size %lx\n",
- fmem_data.phys, fmem_data.virt, fmem_data.size);
-
- spin_lock_init(&fmem_state_lock);
-
- return 0;
-}
-
-static int fmem_remove(struct platform_device *pdev)
-{
- return 0;
-}
-
-static struct platform_driver fmem_driver = {
- .probe = fmem_probe,
- .remove = fmem_remove,
- .driver = { .name = "fmem" }
-};
-
-#ifdef CONFIG_SYSFS
-static ssize_t fmem_state_show(struct kobject *kobj,
- struct kobj_attribute *attr,
- char *buf)
-{
- if (fmem_state == FMEM_T_STATE)
- return snprintf(buf, 3, "t\n");
- else if (fmem_state == FMEM_C_STATE)
- return snprintf(buf, 3, "c\n");
-#ifdef CONFIG_MEMORY_HOTPLUG
- else if (fmem_state == FMEM_O_STATE)
- return snprintf(buf, 3, "o\n");
-#endif
- else if (fmem_state == FMEM_UNINITIALIZED)
- return snprintf(buf, 15, "uninitialized\n");
- return snprintf(buf, 3, "?\n");
-}
-
-static ssize_t fmem_state_store(struct kobject *kobj,
- struct kobj_attribute *attr,
- const char *buf, size_t count)
-{
- int ret = -EINVAL;
-
- if (!strncmp(buf, "t", 1))
- ret = fmem_set_state(FMEM_T_STATE);
- else if (!strncmp(buf, "c", 1))
- ret = fmem_set_state(FMEM_C_STATE);
-#ifdef CONFIG_MEMORY_HOTPLUG
- else if (!strncmp(buf, "o", 1))
- ret = fmem_set_state(FMEM_O_STATE);
-#endif
- if (ret)
- return ret;
- return 1;
-}
-
-static struct kobj_attribute fmem_state_attr = {
- .attr = { .name = "state", .mode = 0644 },
- .show = fmem_state_show,
- .store = fmem_state_store,
-};
-
-static struct attribute *fmem_attrs[] = {
- &fmem_state_attr.attr,
- NULL,
-};
-
-static struct attribute_group fmem_attr_group = {
- .attrs = fmem_attrs,
- .name = "fmem",
-};
-
-static int fmem_create_sysfs(void)
-{
- int ret = 0;
-
- ret = sysfs_create_group(mm_kobj, &fmem_attr_group);
- if (ret)
- pr_err("fmem: can't create sysfs\n");
- return ret;
-}
-
-#endif
-
-#ifdef CONFIG_MEMORY_HOTPLUG
-bool fmem_is_disjoint(unsigned long start_pfn, unsigned long nr_pages)
-{
- unsigned long fmem_start_pfn, fmem_end_pfn;
- unsigned long unstable_end_pfn;
- unsigned long highest_start_pfn, lowest_end_pfn;
-
- fmem_start_pfn = (fmem_data.phys - fmem_data.reserved_size_low)
- >> PAGE_SHIFT;
- fmem_end_pfn = (fmem_data.phys + fmem_data.size +
- fmem_data.reserved_size_high - 1) >> PAGE_SHIFT;
- unstable_end_pfn = start_pfn + nr_pages - 1;
-
- highest_start_pfn = max(fmem_start_pfn, start_pfn);
- lowest_end_pfn = min(fmem_end_pfn, unstable_end_pfn);
-
- return lowest_end_pfn < highest_start_pfn;
-}
-
-static int fmem_mem_going_offline_callback(void *arg)
-{
- struct memory_notify *marg = arg;
-
- if (fmem_is_disjoint(marg->start_pfn, marg->nr_pages))
- return 0;
- return fmem_set_state(FMEM_O_STATE);
-}
-
-static void fmem_mem_online_callback(void *arg)
-{
- struct memory_notify *marg = arg;
- int i;
-
- section_powered_off[marg->start_pfn >> PFN_SECTION_SHIFT] = 0;
-
- if (fmem_state != FMEM_O_STATE)
- return;
-
- for (i = fmem_section_start; i <= fmem_section_end; i++) {
- if (section_powered_off[i])
- return;
- }
-
- fmem_set_state(FMEM_T_STATE);
-}
-
-static void fmem_mem_offline_callback(void *arg)
-{
- struct memory_notify *marg = arg;
-
- section_powered_off[marg->start_pfn >> PFN_SECTION_SHIFT] = 1;
-}
-
-static int fmem_memory_callback(struct notifier_block *self,
- unsigned long action, void *arg)
-{
- int ret = 0;
-
- if (fmem_state == FMEM_UNINITIALIZED)
- return NOTIFY_OK;
-
- switch (action) {
- case MEM_ONLINE:
- fmem_mem_online_callback(arg);
- break;
- case MEM_GOING_OFFLINE:
- ret = fmem_mem_going_offline_callback(arg);
- break;
- case MEM_OFFLINE:
- fmem_mem_offline_callback(arg);
- break;
- case MEM_GOING_ONLINE:
- case MEM_CANCEL_ONLINE:
- case MEM_CANCEL_OFFLINE:
- break;
- }
- if (ret)
- ret = notifier_from_errno(ret);
- else
- ret = NOTIFY_OK;
- return ret;
-}
-#endif
-
-static int __init fmem_init(void)
-{
-#ifdef CONFIG_MEMORY_HOTPLUG
- hotplug_memory_notifier(fmem_memory_callback, 0);
-#endif
- return platform_driver_register(&fmem_driver);
-}
-
-static void __exit fmem_exit(void)
-{
- platform_driver_unregister(&fmem_driver);
-}
-
-struct fmem_data *fmem_get_info(void)
-{
- return &fmem_data;
-}
-EXPORT_SYMBOL(fmem_get_info);
-
-void lock_fmem_state(void)
-{
- spin_lock(&fmem_state_lock);
-}
-
-void unlock_fmem_state(void)
-{
- spin_unlock(&fmem_state_lock);
-}
-
-int fmem_set_state(enum fmem_state new_state)
-{
- int ret = 0;
- int create_sysfs = 0;
-
- lock_fmem_state();
- if (fmem_state == new_state)
- goto out;
-
- if (fmem_state == FMEM_UNINITIALIZED) {
- if (new_state == FMEM_T_STATE) {
- tmem_enable();
- create_sysfs = 1;
- goto out_set;
- } else {
- ret = -EINVAL;
- goto out;
- }
- }
-
-#ifdef CONFIG_MEMORY_HOTPLUG
- if (fmem_state == FMEM_C_STATE && new_state == FMEM_O_STATE) {
- ret = -EAGAIN;
- goto out;
- }
-
- if (fmem_state == FMEM_O_STATE && new_state == FMEM_C_STATE) {
- pr_warn("attempting to use powered off memory as fmem\n");
- ret = -EAGAIN;
- goto out;
- }
-#endif
-
- if (new_state == FMEM_T_STATE) {
- void *v;
- v = fmem_map_virtual_area(MT_DEVICE_CACHED);
- if (IS_ERR_OR_NULL(v)) {
- ret = PTR_ERR(v);
- goto out;
- }
- tmem_enable();
- } else {
- tmem_disable();
- fmem_unmap_virtual_area();
- }
-
-out_set:
- fmem_state = new_state;
-out:
- unlock_fmem_state();
-#ifdef CONFIG_SYSFS
- if (create_sysfs)
- fmem_create_sysfs();
-#endif
- return ret;
-}
-EXPORT_SYMBOL(fmem_set_state);
-
-arch_initcall(fmem_init);
-module_exit(fmem_exit);
diff --git a/drivers/staging/qcache/qcache-main.c b/drivers/staging/qcache/qcache-main.c
deleted file mode 100644
index f416cfc..0000000
--- a/drivers/staging/qcache/qcache-main.c
+++ /dev/null
@@ -1,1358 +0,0 @@
-/*
- * Copyright (c) 2010,2011, Dan Magenheimer, Oracle Corp.
- * Copyright (c) 2010,2011, Nitin Gupta
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
- *
- * Qcache provides an in-kernel "host implementation" for transcendent memory
- * and, thus indirectly, for cleancache and frontswap. Qcache includes a
- * page-accessible memory [1] interface, utilizing lzo1x compression:
- * 1) "compression buddies" ("zbud") is used for ephemeral pages
- * Zbud allows pairs (and potentially,
- * in the future, more than a pair of) compressed pages to be closely linked
- * so that reclaiming can be done via the kernel's physical-page-oriented
- * "shrinker" interface.
- *
- * [1] For a definition of page-accessible memory (aka PAM), see:
- * http://marc.info/?l=linux-mm&m=127811271605009
- */
-
-#include <linux/module.h>
-#include <linux/cpu.h>
-#include <linux/highmem.h>
-#include <linux/list.h>
-#include <linux/lzo.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-#include <linux/atomic.h>
-#include <linux/math64.h>
-#include <linux/bitmap.h>
-#include <linux/fmem.h>
-#include "tmem.h"
-
-#if !defined(CONFIG_CLEANCACHE)
-#error "qcache is useless without CONFIG_CLEANCACHE"
-#endif
-#include <linux/cleancache.h>
-
-#define ZCACHE_GFP_MASK \
- (__GFP_FS | __GFP_NORETRY | __GFP_NOWARN | __GFP_NOMEMALLOC)
-
-#define MAX_POOLS_PER_CLIENT 16
-
-#define MAX_CLIENTS 16
-#define LOCAL_CLIENT ((uint16_t)-1)
-
-MODULE_LICENSE("GPL");
-
-struct zcache_client {
- struct tmem_pool *tmem_pools[MAX_POOLS_PER_CLIENT];
- struct xv_pool *xvpool;
- bool allocated;
- atomic_t refcount;
-};
-
-struct qcache_info {
- void *addr;
- unsigned long *bitmap;
- spinlock_t lock;
- unsigned pages;
-};
-static struct qcache_info qcache_info;
-static unsigned long zcache_qc_allocated;
-static unsigned long zcache_qc_freed;
-static unsigned long zcache_qc_used;
-static unsigned long zcache_qc_max_used;
-
-static struct zcache_client zcache_host;
-static struct zcache_client zcache_clients[MAX_CLIENTS];
-
-static inline uint16_t get_client_id_from_client(struct zcache_client *cli)
-{
- BUG_ON(cli == NULL);
- if (cli == &zcache_host)
- return LOCAL_CLIENT;
- return cli - &zcache_clients[0];
-}
-
-static inline bool is_local_client(struct zcache_client *cli)
-{
- return cli == &zcache_host;
-}
-
-/**********
- * Compression buddies ("zbud") provides for packing two (or, possibly
- * in the future, more) compressed ephemeral pages into a single "raw"
- * (physical) page and tracking them with data structures so that
- * the raw pages can be easily reclaimed.
- *
- * A zbud page ("zbpg") is an aligned page containing a list_head,
- * a lock, and two "zbud headers". The remainder of the physical
- * page is divided up into aligned 64-byte "chunks" which contain
- * the compressed data for zero, one, or two zbuds. Each zbpg
- * resides on: (1) an "unused list" if it has no zbuds; (2) a
- * "buddied" list if it is fully populated with two zbuds; or
- * (3) one of PAGE_SIZE/64 "unbuddied" lists indexed by how many chunks
- * the one unbuddied zbud uses. The data inside a zbpg cannot be
- * read or written unless the zbpg's lock is held.
- */
-
-#define ZBH_SENTINEL 0x43214321
-#define ZBPG_SENTINEL 0xdeadbeef
-
-#define ZBUD_MAX_BUDS 2
-
-struct zbud_hdr {
- uint16_t client_id;
- uint16_t pool_id;
- struct tmem_oid oid;
- uint32_t index;
- uint16_t size; /* compressed size in bytes, zero means unused */
- DECL_SENTINEL
-};
-
-struct zbud_page {
- struct list_head bud_list;
- spinlock_t lock;
- struct zbud_hdr buddy[ZBUD_MAX_BUDS];
- DECL_SENTINEL
- /* followed by NUM_CHUNK aligned CHUNK_SIZE-byte chunks */
-};
-
-#define CHUNK_SHIFT 6
-#define CHUNK_SIZE (1 << CHUNK_SHIFT)
-#define CHUNK_MASK (~(CHUNK_SIZE-1))
-#define NCHUNKS (((PAGE_SIZE - sizeof(struct zbud_page)) & \
- CHUNK_MASK) >> CHUNK_SHIFT)
-#define MAX_CHUNK (NCHUNKS-1)
-
-static struct {
- struct list_head list;
- unsigned count;
-} zbud_unbuddied[NCHUNKS];
-/* list N contains pages with N chunks USED and NCHUNKS-N unused */
-/* element 0 is never used but optimizing that isn't worth it */
-static unsigned long zbud_cumul_chunk_counts[NCHUNKS];
-
-struct list_head zbud_buddied_list;
-static unsigned long zcache_zbud_buddied_count;
-
-/* protects the buddied list and all unbuddied lists */
-static DEFINE_SPINLOCK(zbud_budlists_spinlock);
-
-static atomic_t zcache_zbud_curr_raw_pages;
-static atomic_t zcache_zbud_curr_zpages;
-static unsigned long zcache_zbud_curr_zbytes;
-static unsigned long zcache_zbud_cumul_zpages;
-static unsigned long zcache_zbud_cumul_zbytes;
-static unsigned long zcache_compress_poor;
-static unsigned long zcache_mean_compress_poor;
-
-/* forward references */
-static void *zcache_get_free_page(void);
-
-static void *qcache_alloc(void)
-{
- void *addr;
- unsigned long flags;
- int offset;
- struct qcache_info *qc = &qcache_info;
-
- spin_lock_irqsave(&qc->lock, flags);
- offset = bitmap_find_free_region(qc->bitmap, qc->pages, 0);
-
- if (offset < 0) {
- spin_unlock_irqrestore(&qc->lock, flags);
- return NULL;
- }
-
- zcache_qc_allocated++;
- zcache_qc_used++;
- zcache_qc_max_used = max(zcache_qc_max_used, zcache_qc_used);
- spin_unlock_irqrestore(&qc->lock, flags);
-
- addr = qc->addr + offset * PAGE_SIZE;
-
- return addr;
-}
-
-static void qcache_free(void *addr)
-{
- unsigned long flags;
- int offset;
- struct qcache_info *qc = &qcache_info;
-
- offset = (addr - qc->addr) / PAGE_SIZE;
-
- spin_lock_irqsave(&qc->lock, flags);
- bitmap_release_region(qc->bitmap, offset, 0);
-
- zcache_qc_freed++;
- zcache_qc_used--;
- spin_unlock_irqrestore(&qc->lock, flags);
-}
-
-/*
- * zbud helper functions
- */
-
-static inline unsigned zbud_max_buddy_size(void)
-{
- return MAX_CHUNK << CHUNK_SHIFT;
-}
-
-static inline unsigned zbud_size_to_chunks(unsigned size)
-{
- BUG_ON(size == 0 || size > zbud_max_buddy_size());
- return (size + CHUNK_SIZE - 1) >> CHUNK_SHIFT;
-}
-
-static inline int zbud_budnum(struct zbud_hdr *zh)
-{
- unsigned offset = (unsigned long)zh & (PAGE_SIZE - 1);
- struct zbud_page *zbpg = NULL;
- unsigned budnum = -1U;
- int i;
-
- for (i = 0; i < ZBUD_MAX_BUDS; i++)
- if (offset == offsetof(typeof(*zbpg), buddy[i])) {
- budnum = i;
- break;
- }
- BUG_ON(budnum == -1U);
- return budnum;
-}
-
-static char *zbud_data(struct zbud_hdr *zh, unsigned size)
-{
- struct zbud_page *zbpg;
- char *p;
- unsigned budnum;
-
- ASSERT_SENTINEL(zh, ZBH);
- budnum = zbud_budnum(zh);
- BUG_ON(size == 0 || size > zbud_max_buddy_size());
- zbpg = container_of(zh, struct zbud_page, buddy[budnum]);
- p = (char *)zbpg;
- if (budnum == 0)
- p += ((sizeof(struct zbud_page) + CHUNK_SIZE - 1) &
- CHUNK_MASK);
- else if (budnum == 1)
- p += PAGE_SIZE - ((size + CHUNK_SIZE - 1) & CHUNK_MASK);
- return p;
-}
-
-/*
- * zbud raw page management
- */
-
-static struct zbud_page *zbud_alloc_raw_page(void)
-{
- struct zbud_page *zbpg = NULL;
- struct zbud_hdr *zh0, *zh1;
-
- zbpg = zcache_get_free_page();
- if (likely(zbpg != NULL)) {
- INIT_LIST_HEAD(&zbpg->bud_list);
- zh0 = &zbpg->buddy[0]; zh1 = &zbpg->buddy[1];
- spin_lock_init(&zbpg->lock);
- atomic_inc(&zcache_zbud_curr_raw_pages);
- INIT_LIST_HEAD(&zbpg->bud_list);
- SET_SENTINEL(zbpg, ZBPG);
- zh0->size = 0; zh1->size = 0;
- tmem_oid_set_invalid(&zh0->oid);
- tmem_oid_set_invalid(&zh1->oid);
- }
- return zbpg;
-}
-
-static void zbud_free_raw_page(struct zbud_page *zbpg)
-{
- struct zbud_hdr *zh0 = &zbpg->buddy[0], *zh1 = &zbpg->buddy[1];
-
- ASSERT_SENTINEL(zbpg, ZBPG);
- BUG_ON(!list_empty(&zbpg->bud_list));
- BUG_ON(zh0->size != 0 || tmem_oid_valid(&zh0->oid));
- BUG_ON(zh1->size != 0 || tmem_oid_valid(&zh1->oid));
- INVERT_SENTINEL(zbpg, ZBPG);
- spin_unlock(&zbpg->lock);
- qcache_free(zbpg);
-}
-
-/*
- * core zbud handling routines
- */
-
-static unsigned zbud_free(struct zbud_hdr *zh)
-{
- unsigned size;
-
- ASSERT_SENTINEL(zh, ZBH);
- BUG_ON(!tmem_oid_valid(&zh->oid));
- size = zh->size;
- BUG_ON(zh->size == 0 || zh->size > zbud_max_buddy_size());
- zh->size = 0;
- tmem_oid_set_invalid(&zh->oid);
- INVERT_SENTINEL(zh, ZBH);
- zcache_zbud_curr_zbytes -= size;
- atomic_dec(&zcache_zbud_curr_zpages);
- return size;
-}
-
-static void zbud_free_and_delist(struct zbud_hdr *zh)
-{
- unsigned chunks;
- struct zbud_hdr *zh_other;
- unsigned budnum = zbud_budnum(zh), size;
- struct zbud_page *zbpg =
- container_of(zh, struct zbud_page, buddy[budnum]);
-
- spin_lock(&zbpg->lock);
- if (list_empty(&zbpg->bud_list)) {
- spin_unlock(&zbpg->lock);
- return;
- }
- size = zbud_free(zh);
- zh_other = &zbpg->buddy[(budnum == 0) ? 1 : 0];
- if (zh_other->size == 0) { /* was unbuddied: unlist and free */
- chunks = zbud_size_to_chunks(size) ;
- spin_lock(&zbud_budlists_spinlock);
- BUG_ON(list_empty(&zbud_unbuddied[chunks].list));
- list_del_init(&zbpg->bud_list);
- zbud_unbuddied[chunks].count--;
- spin_unlock(&zbud_budlists_spinlock);
- zbud_free_raw_page(zbpg);
- } else { /* was buddied: move remaining buddy to unbuddied list */
- chunks = zbud_size_to_chunks(zh_other->size) ;
- spin_lock(&zbud_budlists_spinlock);
- list_del_init(&zbpg->bud_list);
- zcache_zbud_buddied_count--;
- list_add_tail(&zbpg->bud_list, &zbud_unbuddied[chunks].list);
- zbud_unbuddied[chunks].count++;
- spin_unlock(&zbud_budlists_spinlock);
- spin_unlock(&zbpg->lock);
- }
-}
-
-static struct zbud_hdr *zbud_create(uint16_t client_id, uint16_t pool_id,
- struct tmem_oid *oid,
- uint32_t index, struct page *page,
- void *cdata, unsigned size)
-{
- struct zbud_hdr *zh0, *zh1, *zh = NULL;
- struct zbud_page *zbpg = NULL, *ztmp;
- unsigned nchunks;
- char *to;
- int i, found_good_buddy = 0;
-
- nchunks = zbud_size_to_chunks(size) ;
- for (i = MAX_CHUNK - nchunks + 1; i > 0; i--) {
- spin_lock(&zbud_budlists_spinlock);
- if (!list_empty(&zbud_unbuddied[i].list)) {
- list_for_each_entry_safe(zbpg, ztmp,
- &zbud_unbuddied[i].list, bud_list) {
- if (spin_trylock(&zbpg->lock)) {
- found_good_buddy = i;
- goto found_unbuddied;
- }
- }
- }
- spin_unlock(&zbud_budlists_spinlock);
- }
- /* didn't find a good buddy, try allocating a new page */
- zbpg = zbud_alloc_raw_page();
- if (unlikely(zbpg == NULL))
- goto out;
- /* ok, have a page, now compress the data before taking locks */
- spin_lock(&zbpg->lock);
- spin_lock(&zbud_budlists_spinlock);
- list_add_tail(&zbpg->bud_list, &zbud_unbuddied[nchunks].list);
- zbud_unbuddied[nchunks].count++;
- zh = &zbpg->buddy[0];
- goto init_zh;
-
-found_unbuddied:
- zh0 = &zbpg->buddy[0]; zh1 = &zbpg->buddy[1];
- BUG_ON(!((zh0->size == 0) ^ (zh1->size == 0)));
- if (zh0->size != 0) { /* buddy0 in use, buddy1 is vacant */
- ASSERT_SENTINEL(zh0, ZBH);
- zh = zh1;
- } else if (zh1->size != 0) { /* buddy1 in use, buddy0 is vacant */
- ASSERT_SENTINEL(zh1, ZBH);
- zh = zh0;
- } else
- BUG();
- list_del_init(&zbpg->bud_list);
- zbud_unbuddied[found_good_buddy].count--;
- list_add_tail(&zbpg->bud_list, &zbud_buddied_list);
- zcache_zbud_buddied_count++;
-
-init_zh:
- SET_SENTINEL(zh, ZBH);
- zh->size = size;
- zh->index = index;
- zh->oid = *oid;
- zh->pool_id = pool_id;
- zh->client_id = client_id;
- /* can wait to copy the data until the list locks are dropped */
- spin_unlock(&zbud_budlists_spinlock);
-
- to = zbud_data(zh, size);
- memcpy(to, cdata, size);
- spin_unlock(&zbpg->lock);
- zbud_cumul_chunk_counts[nchunks]++;
- atomic_inc(&zcache_zbud_curr_zpages);
- zcache_zbud_cumul_zpages++;
- zcache_zbud_curr_zbytes += size;
- zcache_zbud_cumul_zbytes += size;
-out:
- return zh;
-}
-
-static int zbud_decompress(struct page *page, struct zbud_hdr *zh)
-{
- struct zbud_page *zbpg;
- unsigned budnum = zbud_budnum(zh);
- size_t out_len = PAGE_SIZE;
- char *to_va, *from_va;
- unsigned size;
- int ret = 0;
-
- zbpg = container_of(zh, struct zbud_page, buddy[budnum]);
- spin_lock(&zbpg->lock);
- if (list_empty(&zbpg->bud_list)) {
- ret = -EINVAL;
- goto out;
- }
- ASSERT_SENTINEL(zh, ZBH);
- BUG_ON(zh->size == 0 || zh->size > zbud_max_buddy_size());
- to_va = kmap_atomic(page);
- size = zh->size;
- from_va = zbud_data(zh, size);
- ret = lzo1x_decompress_safe(from_va, size, to_va, &out_len);
- BUG_ON(ret != LZO_E_OK);
- BUG_ON(out_len != PAGE_SIZE);
- kunmap_atomic(to_va);
-out:
- spin_unlock(&zbpg->lock);
- return ret;
-}
-
-static struct tmem_pool *zcache_get_pool_by_id(uint16_t cli_id,
- uint16_t poolid);
-static void zcache_put_pool(struct tmem_pool *pool);
-
-static void zbud_init(void)
-{
- int i;
-
- INIT_LIST_HEAD(&zbud_buddied_list);
- zcache_zbud_buddied_count = 0;
- for (i = 0; i < NCHUNKS; i++) {
- INIT_LIST_HEAD(&zbud_unbuddied[i].list);
- zbud_unbuddied[i].count = 0;
- }
-}
-
-#ifdef CONFIG_SYSFS
-/*
- * These sysfs routines show a nice distribution of how many zbpg's are
- * currently (and have ever been placed) in each unbuddied list. It's fun
- * to watch but can probably go away before final merge.
- */
-static int zbud_show_unbuddied_list_counts(char *buf)
-{
- int i;
- char *p = buf;
-
- for (i = 0; i < NCHUNKS; i++)
- p += sprintf(p, "%u ", zbud_unbuddied[i].count);
- return p - buf;
-}
-
-static int zbud_show_cumul_chunk_counts(char *buf)
-{
- unsigned long i, chunks = 0, total_chunks = 0, sum_total_chunks = 0;
- unsigned long total_chunks_lte_21 = 0, total_chunks_lte_32 = 0;
- unsigned long total_chunks_lte_42 = 0;
- char *p = buf;
-
- for (i = 0; i < NCHUNKS; i++) {
- p += sprintf(p, "%lu ", zbud_cumul_chunk_counts[i]);
- chunks += zbud_cumul_chunk_counts[i];
- total_chunks += zbud_cumul_chunk_counts[i];
- sum_total_chunks += i * zbud_cumul_chunk_counts[i];
- if (i == 21)
- total_chunks_lte_21 = total_chunks;
- if (i == 32)
- total_chunks_lte_32 = total_chunks;
- if (i == 42)
- total_chunks_lte_42 = total_chunks;
- }
- p += sprintf(p, "<=21:%lu <=32:%lu <=42:%lu, mean:%lu\n",
- total_chunks_lte_21, total_chunks_lte_32, total_chunks_lte_42,
- chunks == 0 ? 0 : sum_total_chunks / chunks);
- return p - buf;
-}
-#endif
-
-/*
- * zcache core code starts here
- */
-
-/* useful stats not collected by cleancache or frontswap */
-static unsigned long zcache_flush_total;
-static unsigned long zcache_flush_found;
-static unsigned long zcache_flobj_total;
-static unsigned long zcache_flobj_found;
-static unsigned long zcache_failed_eph_puts;
-
-/*
- * Tmem operations assume the poolid implies the invoking client.
- * Zcache only has one client (the kernel itself): LOCAL_CLIENT.
- * RAMster has each client numbered by cluster node, and a KVM version
- * of zcache would have one client per guest and each client might
- * have a poolid==N.
- */
-static struct tmem_pool *zcache_get_pool_by_id(uint16_t cli_id, uint16_t poolid)
-{
- struct tmem_pool *pool = NULL;
- struct zcache_client *cli = NULL;
-
- if (cli_id == LOCAL_CLIENT)
- cli = &zcache_host;
- else {
- if (cli_id >= MAX_CLIENTS)
- goto out;
- cli = &zcache_clients[cli_id];
- if (cli == NULL)
- goto out;
- atomic_inc(&cli->refcount);
- }
- if (poolid < MAX_POOLS_PER_CLIENT) {
- pool = cli->tmem_pools[poolid];
- if (pool != NULL)
- atomic_inc(&pool->refcount);
- }
-out:
- return pool;
-}
-
-static void zcache_put_pool(struct tmem_pool *pool)
-{
- struct zcache_client *cli = NULL;
-
- if (pool == NULL)
- BUG();
- cli = pool->client;
- atomic_dec(&pool->refcount);
- atomic_dec(&cli->refcount);
-}
-
-int zcache_new_client(uint16_t cli_id)
-{
- struct zcache_client *cli = NULL;
- int ret = -1;
-
- if (cli_id == LOCAL_CLIENT)
- cli = &zcache_host;
- else if ((unsigned int)cli_id < MAX_CLIENTS)
- cli = &zcache_clients[cli_id];
- if (cli == NULL)
- goto out;
- if (cli->allocated)
- goto out;
- cli->allocated = 1;
- ret = 0;
-out:
- return ret;
-}
-
-/* counters for debugging */
-static unsigned long zcache_failed_get_free_pages;
-static unsigned long zcache_failed_alloc;
-static unsigned long zcache_put_to_flush;
-static unsigned long zcache_aborted_preload;
-static unsigned long zcache_aborted_shrink;
-
-/*
- * Ensure that memory allocation requests in zcache don't result
- * in direct reclaim requests via the shrinker, which would cause
- * an infinite loop. Maybe a GFP flag would be better?
- */
-static DEFINE_SPINLOCK(zcache_direct_reclaim_lock);
-
-/*
- * for now, used named slabs so can easily track usage; later can
- * either just use kmalloc, or perhaps add a slab-like allocator
- * to more carefully manage total memory utilization
- */
-static struct kmem_cache *zcache_objnode_cache;
-static struct kmem_cache *zcache_obj_cache;
-static atomic_t zcache_curr_obj_count = ATOMIC_INIT(0);
-static unsigned long zcache_curr_obj_count_max;
-static atomic_t zcache_curr_objnode_count = ATOMIC_INIT(0);
-static unsigned long zcache_curr_objnode_count_max;
-
-/*
- * to avoid memory allocation recursion (e.g. due to direct reclaim), we
- * preload all necessary data structures so the hostops callbacks never
- * actually do a malloc
- */
-struct zcache_preload {
- void *page;
- struct tmem_obj *obj;
- int nr;
- struct tmem_objnode *objnodes[OBJNODE_TREE_MAX_PATH];
-};
-static DEFINE_PER_CPU(struct zcache_preload, zcache_preloads) = { 0, };
-
-static int zcache_do_preload(struct tmem_pool *pool)
-{
- struct zcache_preload *kp;
- struct tmem_objnode *objnode;
- struct tmem_obj *obj;
- void *page;
- int ret = -ENOMEM;
-
- if (unlikely(zcache_objnode_cache == NULL))
- goto out;
- if (unlikely(zcache_obj_cache == NULL))
- goto out;
- if (!spin_trylock(&zcache_direct_reclaim_lock)) {
- zcache_aborted_preload++;
- goto out;
- }
- preempt_disable();
- kp = &__get_cpu_var(zcache_preloads);
- while (kp->nr < ARRAY_SIZE(kp->objnodes)) {
- preempt_enable_no_resched();
- objnode = kmem_cache_alloc(zcache_objnode_cache,
- ZCACHE_GFP_MASK);
- if (unlikely(objnode == NULL)) {
- zcache_failed_alloc++;
- goto unlock_out;
- }
- preempt_disable();
- kp = &__get_cpu_var(zcache_preloads);
- if (kp->nr < ARRAY_SIZE(kp->objnodes))
- kp->objnodes[kp->nr++] = objnode;
- else
- kmem_cache_free(zcache_objnode_cache, objnode);
- }
- preempt_enable_no_resched();
- obj = kmem_cache_alloc(zcache_obj_cache, ZCACHE_GFP_MASK);
- if (unlikely(obj == NULL)) {
- zcache_failed_alloc++;
- goto unlock_out;
- }
- page = qcache_alloc();
- if (unlikely(page == NULL)) {
- zcache_failed_get_free_pages++;
- kmem_cache_free(zcache_obj_cache, obj);
- goto unlock_out;
- }
- preempt_disable();
- kp = &__get_cpu_var(zcache_preloads);
- if (kp->obj == NULL)
- kp->obj = obj;
- else
- kmem_cache_free(zcache_obj_cache, obj);
- if (kp->page == NULL)
- kp->page = page;
- else
- qcache_free(page);
- ret = 0;
-unlock_out:
- spin_unlock(&zcache_direct_reclaim_lock);
-out:
- return ret;
-}
-
-static void *zcache_get_free_page(void)
-{
- struct zcache_preload *kp;
- void *page;
-
- kp = &__get_cpu_var(zcache_preloads);
- page = kp->page;
- BUG_ON(page == NULL);
- kp->page = NULL;
- return page;
-}
-
-/*
- * zcache implementation for tmem host ops
- */
-
-static struct tmem_objnode *zcache_objnode_alloc(struct tmem_pool *pool)
-{
- struct tmem_objnode *objnode = NULL;
- unsigned long count;
- struct zcache_preload *kp;
-
- kp = &__get_cpu_var(zcache_preloads);
- if (kp->nr <= 0)
- goto out;
- objnode = kp->objnodes[kp->nr - 1];
- BUG_ON(objnode == NULL);
- kp->objnodes[kp->nr - 1] = NULL;
- kp->nr--;
- count = atomic_inc_return(&zcache_curr_objnode_count);
- if (count > zcache_curr_objnode_count_max)
- zcache_curr_objnode_count_max = count;
-out:
- return objnode;
-}
-
-static void zcache_objnode_free(struct tmem_objnode *objnode,
- struct tmem_pool *pool)
-{
- atomic_dec(&zcache_curr_objnode_count);
- BUG_ON(atomic_read(&zcache_curr_objnode_count) < 0);
- kmem_cache_free(zcache_objnode_cache, objnode);
-}
-
-static struct tmem_obj *zcache_obj_alloc(struct tmem_pool *pool)
-{
- struct tmem_obj *obj = NULL;
- unsigned long count;
- struct zcache_preload *kp;
-
- kp = &__get_cpu_var(zcache_preloads);
- obj = kp->obj;
- BUG_ON(obj == NULL);
- kp->obj = NULL;
- count = atomic_inc_return(&zcache_curr_obj_count);
- if (count > zcache_curr_obj_count_max)
- zcache_curr_obj_count_max = count;
- return obj;
-}
-
-static void zcache_obj_free(struct tmem_obj *obj, struct tmem_pool *pool)
-{
- atomic_dec(&zcache_curr_obj_count);
- BUG_ON(atomic_read(&zcache_curr_obj_count) < 0);
- kmem_cache_free(zcache_obj_cache, obj);
-}
-
-static void zcache_flush_all_obj(void)
-{
- struct tmem_pool *pool;
- int pool_id;
- struct zcache_preload *kp;
-
- kp = &__get_cpu_var(zcache_preloads);
-
- for (pool_id = 0; pool_id < MAX_POOLS_PER_CLIENT; pool_id++) {
- pool = zcache_get_pool_by_id(LOCAL_CLIENT, pool_id);
- tmem_flush_pool(pool);
- if (pool)
- zcache_put_pool(pool);
- }
- if (kp->page) {
- qcache_free(kp->page);
- kp->page = NULL;
- }
- if (zcache_qc_used)
- pr_warn("pages used not 0 after qcache flush all, is %ld\n",
- zcache_qc_used);
-}
-
-/*
- * When zcache is disabled ("frozen"), pools can be created and destroyed,
- * but all puts (and thus all other operations that require memory allocation)
- * must fail. If zcache is unfrozen, accepts puts, then frozen again,
- * data consistency requires all puts while frozen to be converted into
- * flushes.
- */
-static bool zcache_freeze;
-
-static void zcache_control(bool freeze)
-{
- zcache_freeze = freeze;
-}
-
-static struct tmem_hostops zcache_hostops = {
- .obj_alloc = zcache_obj_alloc,
- .obj_free = zcache_obj_free,
- .objnode_alloc = zcache_objnode_alloc,
- .objnode_free = zcache_objnode_free,
- .flush_all_obj = zcache_flush_all_obj,
- .control = zcache_control,
-};
-
-/*
- * zcache implementations for PAM page descriptor ops
- */
-
-static atomic_t zcache_curr_eph_pampd_count = ATOMIC_INIT(0);
-static unsigned long zcache_curr_eph_pampd_count_max;
-
-/* forward reference */
-static int zcache_compress(struct page *from, void **out_va, size_t *out_len);
-
-static void *zcache_pampd_create(char *data, size_t size, bool raw, int eph,
- struct tmem_pool *pool, struct tmem_oid *oid,
- uint32_t index)
-{
- void *pampd = NULL, *cdata;
- size_t clen;
- int ret;
- unsigned long count;
- struct page *page = (struct page *)(data);
- struct zcache_client *cli = pool->client;
- uint16_t client_id = get_client_id_from_client(cli);
-
- ret = zcache_compress(page, &cdata, &clen);
- if (ret == 0)
- goto out;
- if (clen == 0 || clen > zbud_max_buddy_size()) {
- zcache_compress_poor++;
- goto out;
- }
- pampd = (void *)zbud_create(client_id, pool->pool_id, oid,
- index, page, cdata, clen);
- if (pampd != NULL) {
- count = atomic_inc_return(&zcache_curr_eph_pampd_count);
- if (count > zcache_curr_eph_pampd_count_max)
- zcache_curr_eph_pampd_count_max = count;
- }
-out:
- return pampd;
-}
-
-/*
- * fill the pageframe corresponding to the struct page with the data
- * from the passed pampd
- */
-static int zcache_pampd_get_data(char *data, size_t *bufsize, bool raw,
- void *pampd, struct tmem_pool *pool,
- struct tmem_oid *oid, uint32_t index)
-{
- BUG();
- return 0;
-}
-
-/*
- * fill the pageframe corresponding to the struct page with the data
- * from the passed pampd
- */
-static int zcache_pampd_get_data_and_free(char *data, size_t *bufsize, bool raw,
- void *pampd, struct tmem_pool *pool,
- struct tmem_oid *oid, uint32_t index)
-{
- int ret = 0;
-
- zbud_decompress((struct page *)(data), pampd);
- zbud_free_and_delist((struct zbud_hdr *)pampd);
- atomic_dec(&zcache_curr_eph_pampd_count);
- return ret;
-}
-
-/*
- * free the pampd and remove it from any zcache lists
- * pampd must no longer be pointed to from any tmem data structures!
- */
-static void zcache_pampd_free(void *pampd, struct tmem_pool *pool,
- struct tmem_oid *oid, uint32_t index)
-{
- zbud_free_and_delist((struct zbud_hdr *)pampd);
- atomic_dec(&zcache_curr_eph_pampd_count);
- BUG_ON(atomic_read(&zcache_curr_eph_pampd_count) < 0);
-}
-
-static void zcache_pampd_free_obj(struct tmem_pool *pool, struct tmem_obj *obj)
-{
-}
-
-static void zcache_pampd_new_obj(struct tmem_obj *obj)
-{
-}
-
-static int zcache_pampd_replace_in_obj(void *pampd, struct tmem_obj *obj)
-{
- return -1;
-}
-
-static bool zcache_pampd_is_remote(void *pampd)
-{
- return 0;
-}
-
-static struct tmem_pamops zcache_pamops = {
- .create = zcache_pampd_create,
- .get_data = zcache_pampd_get_data,
- .get_data_and_free = zcache_pampd_get_data_and_free,
- .free = zcache_pampd_free,
- .free_obj = zcache_pampd_free_obj,
- .new_obj = zcache_pampd_new_obj,
- .replace_in_obj = zcache_pampd_replace_in_obj,
- .is_remote = zcache_pampd_is_remote,
-};
-
-/*
- * zcache compression/decompression and related per-cpu stuff
- */
-
-#define LZO_WORKMEM_BYTES LZO1X_1_MEM_COMPRESS
-#define LZO_DSTMEM_PAGE_ORDER 1
-static DEFINE_PER_CPU(unsigned char *, zcache_workmem);
-static DEFINE_PER_CPU(unsigned char *, zcache_dstmem);
-
-static int zcache_compress(struct page *from, void **out_va, size_t *out_len)
-{
- int ret = 0;
- unsigned char *dmem = __get_cpu_var(zcache_dstmem);
- unsigned char *wmem = __get_cpu_var(zcache_workmem);
- char *from_va;
-
- BUG_ON(!irqs_disabled());
- if (unlikely(dmem == NULL || wmem == NULL))
- goto out; /* no buffer, so can't compress */
- from_va = kmap_atomic(from);
- mb();
- ret = lzo1x_1_compress(from_va, PAGE_SIZE, dmem, out_len, wmem);
- BUG_ON(ret != LZO_E_OK);
- *out_va = dmem;
- kunmap_atomic(from_va);
- ret = 1;
-out:
- return ret;
-}
-
-#ifdef CONFIG_SYSFS
-#define ZCACHE_SYSFS_RO(_name) \
- static ssize_t zcache_##_name##_show(struct kobject *kobj, \
- struct kobj_attribute *attr, char *buf) \
- { \
- return sprintf(buf, "%lu\n", zcache_##_name); \
- } \
- static struct kobj_attribute zcache_##_name##_attr = { \
- .attr = { .name = __stringify(_name), .mode = 0444 }, \
- .show = zcache_##_name##_show, \
- }
-
-#define ZCACHE_SYSFS_RO_ATOMIC(_name) \
- static ssize_t zcache_##_name##_show(struct kobject *kobj, \
- struct kobj_attribute *attr, char *buf) \
- { \
- return sprintf(buf, "%d\n", atomic_read(&zcache_##_name)); \
- } \
- static struct kobj_attribute zcache_##_name##_attr = { \
- .attr = { .name = __stringify(_name), .mode = 0444 }, \
- .show = zcache_##_name##_show, \
- }
-
-#define ZCACHE_SYSFS_RO_CUSTOM(_name, _func) \
- static ssize_t zcache_##_name##_show(struct kobject *kobj, \
- struct kobj_attribute *attr, char *buf) \
- { \
- return _func(buf); \
- } \
- static struct kobj_attribute zcache_##_name##_attr = { \
- .attr = { .name = __stringify(_name), .mode = 0444 }, \
- .show = zcache_##_name##_show, \
- }
-
-ZCACHE_SYSFS_RO(curr_obj_count_max);
-ZCACHE_SYSFS_RO(curr_objnode_count_max);
-ZCACHE_SYSFS_RO(flush_total);
-ZCACHE_SYSFS_RO(flush_found);
-ZCACHE_SYSFS_RO(flobj_total);
-ZCACHE_SYSFS_RO(flobj_found);
-ZCACHE_SYSFS_RO(failed_eph_puts);
-ZCACHE_SYSFS_RO(zbud_curr_zbytes);
-ZCACHE_SYSFS_RO(zbud_cumul_zpages);
-ZCACHE_SYSFS_RO(zbud_cumul_zbytes);
-ZCACHE_SYSFS_RO(zbud_buddied_count);
-ZCACHE_SYSFS_RO(failed_get_free_pages);
-ZCACHE_SYSFS_RO(failed_alloc);
-ZCACHE_SYSFS_RO(put_to_flush);
-ZCACHE_SYSFS_RO(aborted_preload);
-ZCACHE_SYSFS_RO(aborted_shrink);
-ZCACHE_SYSFS_RO(compress_poor);
-ZCACHE_SYSFS_RO(mean_compress_poor);
-ZCACHE_SYSFS_RO(qc_allocated);
-ZCACHE_SYSFS_RO(qc_freed);
-ZCACHE_SYSFS_RO(qc_used);
-ZCACHE_SYSFS_RO(qc_max_used);
-ZCACHE_SYSFS_RO_ATOMIC(zbud_curr_raw_pages);
-ZCACHE_SYSFS_RO_ATOMIC(zbud_curr_zpages);
-ZCACHE_SYSFS_RO_ATOMIC(curr_obj_count);
-ZCACHE_SYSFS_RO_ATOMIC(curr_objnode_count);
-ZCACHE_SYSFS_RO_CUSTOM(zbud_unbuddied_list_counts,
- zbud_show_unbuddied_list_counts);
-ZCACHE_SYSFS_RO_CUSTOM(zbud_cumul_chunk_counts,
- zbud_show_cumul_chunk_counts);
-
-static struct attribute *qcache_attrs[] = {
- &zcache_curr_obj_count_attr.attr,
- &zcache_curr_obj_count_max_attr.attr,
- &zcache_curr_objnode_count_attr.attr,
- &zcache_curr_objnode_count_max_attr.attr,
- &zcache_flush_total_attr.attr,
- &zcache_flobj_total_attr.attr,
- &zcache_flush_found_attr.attr,
- &zcache_flobj_found_attr.attr,
- &zcache_failed_eph_puts_attr.attr,
- &zcache_compress_poor_attr.attr,
- &zcache_mean_compress_poor_attr.attr,
- &zcache_zbud_curr_raw_pages_attr.attr,
- &zcache_zbud_curr_zpages_attr.attr,
- &zcache_zbud_curr_zbytes_attr.attr,
- &zcache_zbud_cumul_zpages_attr.attr,
- &zcache_zbud_cumul_zbytes_attr.attr,
- &zcache_zbud_buddied_count_attr.attr,
- &zcache_failed_get_free_pages_attr.attr,
- &zcache_failed_alloc_attr.attr,
- &zcache_put_to_flush_attr.attr,
- &zcache_aborted_preload_attr.attr,
- &zcache_aborted_shrink_attr.attr,
- &zcache_zbud_unbuddied_list_counts_attr.attr,
- &zcache_zbud_cumul_chunk_counts_attr.attr,
- &zcache_qc_allocated_attr.attr,
- &zcache_qc_freed_attr.attr,
- &zcache_qc_used_attr.attr,
- &zcache_qc_max_used_attr.attr,
- NULL,
-};
-
-static struct attribute_group qcache_attr_group = {
- .attrs = qcache_attrs,
- .name = "qcache",
-};
-
-#endif /* CONFIG_SYSFS */
-
-/*
- * zcache shims between cleancache ops and tmem
- */
-
-static int zcache_put_page(int cli_id, int pool_id, struct tmem_oid *oidp,
- uint32_t index, struct page *page)
-{
- struct tmem_pool *pool;
- int ret = -1;
-
- BUG_ON(!irqs_disabled());
- pool = zcache_get_pool_by_id(cli_id, pool_id);
- if (unlikely(pool == NULL))
- goto out;
- if (!zcache_freeze && zcache_do_preload(pool) == 0) {
- /* preload does preempt_disable on success */
- ret = tmem_put(pool, oidp, index, (char *)(page),
- PAGE_SIZE, 0, is_ephemeral(pool));
- if (ret < 0) {
- zcache_failed_eph_puts++;
- }
- zcache_put_pool(pool);
- preempt_enable_no_resched();
- } else {
- zcache_put_to_flush++;
- if (atomic_read(&pool->obj_count) > 0)
- /* the put fails whether the flush succeeds or not */
- (void)tmem_flush_page(pool, oidp, index);
- zcache_put_pool(pool);
- }
-out:
- return ret;
-}
-
-static int zcache_get_page(int cli_id, int pool_id, struct tmem_oid *oidp,
- uint32_t index, struct page *page)
-{
- struct tmem_pool *pool;
- int ret = -1;
- unsigned long flags;
- size_t size = PAGE_SIZE;
-
- local_irq_save(flags);
- pool = zcache_get_pool_by_id(cli_id, pool_id);
- if (likely(pool != NULL)) {
- if (atomic_read(&pool->obj_count) > 0)
- ret = tmem_get(pool, oidp, index, (char *)(page),
- &size, 0, is_ephemeral(pool));
- zcache_put_pool(pool);
- }
- local_irq_restore(flags);
- return ret;
-}
-
-static int zcache_flush_page(int cli_id, int pool_id,
- struct tmem_oid *oidp, uint32_t index)
-{
- struct tmem_pool *pool;
- int ret = -1;
- unsigned long flags;
-
- local_irq_save(flags);
- zcache_flush_total++;
- pool = zcache_get_pool_by_id(cli_id, pool_id);
- if (likely(pool != NULL)) {
- if (atomic_read(&pool->obj_count) > 0)
- ret = tmem_flush_page(pool, oidp, index);
- zcache_put_pool(pool);
- }
- if (ret >= 0)
- zcache_flush_found++;
- local_irq_restore(flags);
- return ret;
-}
-
-static int zcache_flush_object(int cli_id, int pool_id,
- struct tmem_oid *oidp)
-{
- struct tmem_pool *pool;
- int ret = -1;
- unsigned long flags;
-
- local_irq_save(flags);
- zcache_flobj_total++;
- pool = zcache_get_pool_by_id(cli_id, pool_id);
- if (likely(pool != NULL)) {
- if (atomic_read(&pool->obj_count) > 0)
- ret = tmem_flush_object(pool, oidp);
- zcache_put_pool(pool);
- }
- if (ret >= 0)
- zcache_flobj_found++;
- local_irq_restore(flags);
- return ret;
-}
-
-static int zcache_destroy_pool(int cli_id, int pool_id)
-{
- struct tmem_pool *pool = NULL;
- struct zcache_client *cli = NULL;
- int ret = -1;
-
- if (pool_id < 0)
- goto out;
- if (cli_id == LOCAL_CLIENT)
- cli = &zcache_host;
- else if ((unsigned int)cli_id < MAX_CLIENTS)
- cli = &zcache_clients[cli_id];
- if (cli == NULL)
- goto out;
- atomic_inc(&cli->refcount);
- pool = cli->tmem_pools[pool_id];
- if (pool == NULL)
- goto out;
- cli->tmem_pools[pool_id] = NULL;
- /* wait for pool activity on other cpus to quiesce */
- while (atomic_read(&pool->refcount) != 0)
- ;
- atomic_dec(&cli->refcount);
- local_bh_disable();
- ret = tmem_destroy_pool(pool);
- local_bh_enable();
- kfree(pool);
- pr_info("qcache: destroyed pool id=%d, cli_id=%d\n",
- pool_id, cli_id);
-out:
- return ret;
-}
-
-static int zcache_new_pool(uint16_t cli_id, uint32_t flags)
-{
- int poolid = -1;
- struct tmem_pool *pool;
- struct zcache_client *cli = NULL;
-
- if (cli_id == LOCAL_CLIENT)
- cli = &zcache_host;
- else if ((unsigned int)cli_id < MAX_CLIENTS)
- cli = &zcache_clients[cli_id];
- if (cli == NULL)
- goto out;
- atomic_inc(&cli->refcount);
- pool = kmalloc(sizeof(struct tmem_pool), GFP_KERNEL);
- if (pool == NULL) {
- pr_info("qcache: pool creation failed: out of memory\n");
- goto out;
- }
-
- for (poolid = 0; poolid < MAX_POOLS_PER_CLIENT; poolid++)
- if (cli->tmem_pools[poolid] == NULL)
- break;
- if (poolid >= MAX_POOLS_PER_CLIENT) {
- pr_info("qcache: pool creation failed: max exceeded\n");
- kfree(pool);
- poolid = -1;
- goto out;
- }
- atomic_set(&pool->refcount, 0);
- pool->client = cli;
- pool->pool_id = poolid;
- tmem_new_pool(pool, flags);
- cli->tmem_pools[poolid] = pool;
- pr_info("qcache: created %s tmem pool, id=%d, client=%d\n",
- flags & TMEM_POOL_PERSIST ? "persistent" : "ephemeral",
- poolid, cli_id);
-out:
- if (cli != NULL)
- atomic_dec(&cli->refcount);
- return poolid;
-}
-
-/**********
- * Two kernel functionalities currently can be layered on top of tmem.
- * These are "cleancache" which is used as a second-chance cache for clean
- * page cache pages; and "frontswap" which is used for swap pages
- * to avoid writes to disk. A generic "shim" is provided here for each
- * to translate in-kernel semantics to zcache semantics.
- */
-
-static void zcache_cleancache_put_page(int pool_id,
- struct cleancache_filekey key,
- pgoff_t index, struct page *page)
-{
- u32 ind = (u32) index;
- struct tmem_oid oid = *(struct tmem_oid *)&key;
-
- if (likely(ind == index))
- (void)zcache_put_page(LOCAL_CLIENT, pool_id, &oid, index, page);
-}
-
-static int zcache_cleancache_get_page(int pool_id,
- struct cleancache_filekey key,
- pgoff_t index, struct page *page)
-{
- u32 ind = (u32) index;
- struct tmem_oid oid = *(struct tmem_oid *)&key;
- int ret = -1;
-
- if (likely(ind == index))
- ret = zcache_get_page(LOCAL_CLIENT, pool_id, &oid, index, page);
- return ret;
-}
-
-static void zcache_cleancache_flush_page(int pool_id,
- struct cleancache_filekey key,
- pgoff_t index)
-{
- u32 ind = (u32) index;
- struct tmem_oid oid = *(struct tmem_oid *)&key;
-
- if (likely(ind == index))
- (void)zcache_flush_page(LOCAL_CLIENT, pool_id, &oid, ind);
-}
-
-static void zcache_cleancache_flush_inode(int pool_id,
- struct cleancache_filekey key)
-{
- struct tmem_oid oid = *(struct tmem_oid *)&key;
-
- (void)zcache_flush_object(LOCAL_CLIENT, pool_id, &oid);
-}
-
-static void zcache_cleancache_flush_fs(int pool_id)
-{
- if (pool_id >= 0)
- (void)zcache_destroy_pool(LOCAL_CLIENT, pool_id);
-}
-
-static int zcache_cleancache_init_fs(size_t pagesize)
-{
- BUG_ON(sizeof(struct cleancache_filekey) !=
- sizeof(struct tmem_oid));
- BUG_ON(pagesize != PAGE_SIZE);
- return zcache_new_pool(LOCAL_CLIENT, 0);
-}
-
-static int zcache_cleancache_init_shared_fs(char *uuid, size_t pagesize)
-{
- /* shared pools are unsupported and map to private */
- BUG_ON(sizeof(struct cleancache_filekey) !=
- sizeof(struct tmem_oid));
- BUG_ON(pagesize != PAGE_SIZE);
- return zcache_new_pool(LOCAL_CLIENT, 0);
-}
-
-static struct cleancache_ops zcache_cleancache_ops = {
- .put_page = zcache_cleancache_put_page,
- .get_page = zcache_cleancache_get_page,
- .invalidate_page = zcache_cleancache_flush_page,
- .invalidate_inode = zcache_cleancache_flush_inode,
- .invalidate_fs = zcache_cleancache_flush_fs,
- .init_shared_fs = zcache_cleancache_init_shared_fs,
- .init_fs = zcache_cleancache_init_fs
-};
-
-struct cleancache_ops zcache_cleancache_register_ops(void)
-{
- struct cleancache_ops old_ops =
- cleancache_register_ops(&zcache_cleancache_ops);
-
- return old_ops;
-}
-
-static int __init qcache_init(void)
-{
- int ret = 0;
- struct qcache_info *qc = &qcache_info;
- struct fmem_data *fdp;
- int bitmap_size;
- unsigned int cpu;
- struct cleancache_ops old_ops;
-
-#ifdef CONFIG_SYSFS
- ret = sysfs_create_group(mm_kobj, &qcache_attr_group);
- if (ret) {
- pr_err("qcache: can't create sysfs\n");
- goto out;
- }
-#endif /* CONFIG_SYSFS */
-
- fdp = fmem_get_info();
- qc->addr = fdp->virt;
- qc->pages = fdp->size >> PAGE_SHIFT;
- if (!qc->pages)
- goto out;
-
- tmem_register_hostops(&zcache_hostops);
- tmem_register_pamops(&zcache_pamops);
- for_each_online_cpu(cpu) {
- per_cpu(zcache_dstmem, cpu) = (void *)__get_free_pages(
- GFP_KERNEL | __GFP_REPEAT,
- LZO_DSTMEM_PAGE_ORDER),
- per_cpu(zcache_workmem, cpu) =
- kzalloc(LZO1X_MEM_COMPRESS,
- GFP_KERNEL | __GFP_REPEAT);
- }
- zcache_objnode_cache = kmem_cache_create("zcache_objnode",
- sizeof(struct tmem_objnode), 0, 0, NULL);
- zcache_obj_cache = kmem_cache_create("zcache_obj",
- sizeof(struct tmem_obj), 0, 0, NULL);
- ret = zcache_new_client(LOCAL_CLIENT);
- if (ret) {
- pr_err("qcache: can't create client\n");
- goto out;
- }
-
- zbud_init();
- old_ops = zcache_cleancache_register_ops();
- pr_info("qcache: cleancache enabled using kernel "
- "transcendent memory and compression buddies\n");
- if (old_ops.init_fs != NULL)
- pr_warning("qcache: cleancache_ops overridden");
-
-
- bitmap_size = BITS_TO_LONGS(qc->pages) * sizeof(long);
-
- qc->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
- if (!qc->bitmap) {
- pr_info("can't allocate qcache bitmap!\n");
- ret = -ENOMEM;
- goto out;
- }
- spin_lock_init(&qc->lock);
-
- fmem_set_state(FMEM_T_STATE);
-
-out:
- return ret;
-}
-
-module_init(qcache_init)
diff --git a/drivers/staging/qcache/tmem.c b/drivers/staging/qcache/tmem.c
deleted file mode 100644
index 40f2246..0000000
--- a/drivers/staging/qcache/tmem.c
+++ /dev/null
@@ -1,833 +0,0 @@
-/*
- * In-kernel transcendent memory (generic implementation)
- *
- * Copyright (c) 2009-2011, Dan Magenheimer, Oracle Corp.
- * Copyright (c) 2011, The Linux Foundation. All rights reserved.
- *
- * The primary purpose of Transcedent Memory ("tmem") is to map object-oriented
- * "handles" (triples containing a pool id, and object id, and an index), to
- * pages in a page-accessible memory (PAM). Tmem references the PAM pages via
- * an abstract "pampd" (PAM page-descriptor), which can be operated on by a
- * set of functions (pamops). Each pampd contains some representation of
- * PAGE_SIZE bytes worth of data. Tmem must support potentially millions of
- * pages and must be able to insert, find, and delete these pages at a
- * potential frequency of thousands per second concurrently across many CPUs,
- * (and, if used with KVM, across many vcpus across many guests).
- * Tmem is tracked with a hierarchy of data structures, organized by
- * the elements in a handle-tuple: pool_id, object_id, and page index.
- * One or more "clients" (e.g. guests) each provide one or more tmem_pools.
- * Each pool, contains a hash table of rb_trees of tmem_objs. Each
- * tmem_obj contains a radix-tree-like tree of pointers, with intermediate
- * nodes called tmem_objnodes. Each leaf pointer in this tree points to
- * a pampd, which is accessible only through a small set of callbacks
- * registered by the PAM implementation (see tmem_register_pamops). Tmem
- * does all memory allocation via a set of callbacks registered by the tmem
- * host implementation (e.g. see tmem_register_hostops).
- */
-
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/atomic.h>
-
-#include "tmem.h"
-
-/* data structure sentinels used for debugging... see tmem.h */
-#define POOL_SENTINEL 0x87658765
-#define OBJ_SENTINEL 0x12345678
-#define OBJNODE_SENTINEL 0xfedcba09
-
-static bool tmem_enabled;
-
-static void lock_tmem_state(void)
-{
- lock_fmem_state();
-}
-
-static void unlock_tmem_state(void)
-{
- unlock_fmem_state();
-}
-
-/*
- * A tmem host implementation must use this function to register callbacks
- * for memory allocation.
- */
-static struct tmem_hostops tmem_hostops;
-
-static void tmem_objnode_tree_init(void);
-
-void tmem_register_hostops(struct tmem_hostops *m)
-{
- tmem_objnode_tree_init();
- tmem_hostops = *m;
-}
-
-/*
- * A tmem host implementation must use this function to register
- * callbacks for a page-accessible memory (PAM) implementation
- */
-static struct tmem_pamops tmem_pamops;
-
-void tmem_register_pamops(struct tmem_pamops *m)
-{
- tmem_pamops = *m;
-}
-
-/*
- * Oid's are potentially very sparse and tmem_objs may have an indeterminately
- * short life, being added and deleted at a relatively high frequency.
- * So an rb_tree is an ideal data structure to manage tmem_objs. But because
- * of the potentially huge number of tmem_objs, each pool manages a hashtable
- * of rb_trees to reduce search, insert, delete, and rebalancing time.
- * Each hashbucket also has a lock to manage concurrent access.
- *
- * The following routines manage tmem_objs. When any tmem_obj is accessed,
- * the hashbucket lock must be held.
- */
-
-/* searches for object==oid in pool, returns locked object if found */
-static struct tmem_obj *tmem_obj_find(struct tmem_hashbucket *hb,
- struct tmem_oid *oidp)
-{
- struct rb_node *rbnode;
- struct tmem_obj *obj;
-
- rbnode = hb->obj_rb_root.rb_node;
- while (rbnode) {
- BUG_ON(RB_EMPTY_NODE(rbnode));
- obj = rb_entry(rbnode, struct tmem_obj, rb_tree_node);
- switch (tmem_oid_compare(oidp, &obj->oid)) {
- case 0: /* equal */
- goto out;
- case -1:
- rbnode = rbnode->rb_left;
- break;
- case 1:
- rbnode = rbnode->rb_right;
- break;
- }
- }
- obj = NULL;
-out:
- return obj;
-}
-
-static void tmem_pampd_destroy_all_in_obj(struct tmem_obj *);
-
-/* free an object that has no more pampds in it */
-static void tmem_obj_free(struct tmem_obj *obj, struct tmem_hashbucket *hb)
-{
- struct tmem_pool *pool;
-
- BUG_ON(obj == NULL);
- ASSERT_SENTINEL(obj, OBJ);
- BUG_ON(obj->pampd_count > 0);
- pool = obj->pool;
- BUG_ON(pool == NULL);
- if (obj->objnode_tree_root != NULL) /* may be "stump" with no leaves */
- tmem_pampd_destroy_all_in_obj(obj);
- BUG_ON(obj->objnode_tree_root != NULL);
- BUG_ON((long)obj->objnode_count != 0);
- atomic_dec(&pool->obj_count);
- BUG_ON(atomic_read(&pool->obj_count) < 0);
- INVERT_SENTINEL(obj, OBJ);
- obj->pool = NULL;
- tmem_oid_set_invalid(&obj->oid);
- rb_erase(&obj->rb_tree_node, &hb->obj_rb_root);
-}
-
-/*
- * initialize, and insert an tmem_object_root (called only if find failed)
- */
-static void tmem_obj_init(struct tmem_obj *obj, struct tmem_hashbucket *hb,
- struct tmem_pool *pool,
- struct tmem_oid *oidp)
-{
- struct rb_root *root = &hb->obj_rb_root;
- struct rb_node **new = &(root->rb_node), *parent = NULL;
- struct tmem_obj *this;
-
- BUG_ON(pool == NULL);
- atomic_inc(&pool->obj_count);
- obj->objnode_tree_height = 0;
- obj->objnode_tree_root = NULL;
- obj->pool = pool;
- obj->oid = *oidp;
- obj->objnode_count = 0;
- obj->pampd_count = 0;
- (*tmem_pamops.new_obj)(obj);
- SET_SENTINEL(obj, OBJ);
- while (*new) {
- BUG_ON(RB_EMPTY_NODE(*new));
- this = rb_entry(*new, struct tmem_obj, rb_tree_node);
- parent = *new;
- switch (tmem_oid_compare(oidp, &this->oid)) {
- case 0:
- BUG(); /* already present; should never happen! */
- break;
- case -1:
- new = &(*new)->rb_left;
- break;
- case 1:
- new = &(*new)->rb_right;
- break;
- }
- }
- rb_link_node(&obj->rb_tree_node, parent, new);
- rb_insert_color(&obj->rb_tree_node, root);
-}
-
-/*
- * Tmem is managed as a set of tmem_pools with certain attributes, such as
- * "ephemeral" vs "persistent". These attributes apply to all tmem_objs
- * and all pampds that belong to a tmem_pool. A tmem_pool is created
- * or deleted relatively rarely (for example, when a filesystem is
- * mounted or unmounted.
- */
-
-/* flush all data from a pool and, optionally, free it */
-static void tmem_pool_flush(struct tmem_pool *pool, bool destroy)
-{
- struct rb_node *rbnode;
- struct tmem_obj *obj;
- struct tmem_hashbucket *hb = &pool->hashbucket[0];
- int i;
-
- BUG_ON(pool == NULL);
- for (i = 0; i < TMEM_HASH_BUCKETS; i++, hb++) {
- spin_lock(&hb->lock);
- rbnode = rb_first(&hb->obj_rb_root);
- while (rbnode != NULL) {
- obj = rb_entry(rbnode, struct tmem_obj, rb_tree_node);
- rbnode = rb_next(rbnode);
- tmem_pampd_destroy_all_in_obj(obj);
- tmem_obj_free(obj, hb);
- (*tmem_hostops.obj_free)(obj, pool);
- }
- spin_unlock(&hb->lock);
- }
- if (destroy)
- list_del(&pool->pool_list);
-}
-
-/*
- * A tmem_obj contains a radix-tree-like tree in which the intermediate
- * nodes are called tmem_objnodes. (The kernel lib/radix-tree.c implementation
- * is very specialized and tuned for specific uses and is not particularly
- * suited for use from this code, though some code from the core algorithms has
- * been reused, thus the copyright notices below). Each tmem_objnode contains
- * a set of pointers which point to either a set of intermediate tmem_objnodes
- * or a set of of pampds.
- *
- * Portions Copyright (C) 2001 Momchil Velikov
- * Portions Copyright (C) 2001 Christoph Hellwig
- * Portions Copyright (C) 2005 SGI, Christoph Lameter <clameter@sgi.com>
- */
-
-struct tmem_objnode_tree_path {
- struct tmem_objnode *objnode;
- int offset;
-};
-
-/* objnode height_to_maxindex translation */
-static unsigned long tmem_objnode_tree_h2max[OBJNODE_TREE_MAX_PATH + 1];
-
-static void tmem_objnode_tree_init(void)
-{
- unsigned int ht, tmp;
-
- for (ht = 0; ht < ARRAY_SIZE(tmem_objnode_tree_h2max); ht++) {
- tmp = ht * OBJNODE_TREE_MAP_SHIFT;
- if (tmp >= OBJNODE_TREE_INDEX_BITS)
- tmem_objnode_tree_h2max[ht] = ~0UL;
- else
- tmem_objnode_tree_h2max[ht] =
- (~0UL >> (OBJNODE_TREE_INDEX_BITS - tmp - 1)) >> 1;
- }
-}
-
-static struct tmem_objnode *tmem_objnode_alloc(struct tmem_obj *obj)
-{
- struct tmem_objnode *objnode;
-
- ASSERT_SENTINEL(obj, OBJ);
- BUG_ON(obj->pool == NULL);
- ASSERT_SENTINEL(obj->pool, POOL);
- objnode = (*tmem_hostops.objnode_alloc)(obj->pool);
- if (unlikely(objnode == NULL))
- goto out;
- objnode->obj = obj;
- SET_SENTINEL(objnode, OBJNODE);
- memset(&objnode->slots, 0, sizeof(objnode->slots));
- objnode->slots_in_use = 0;
- obj->objnode_count++;
-out:
- return objnode;
-}
-
-static void tmem_objnode_free(struct tmem_objnode *objnode)
-{
- struct tmem_pool *pool;
- int i;
-
- BUG_ON(objnode == NULL);
- for (i = 0; i < OBJNODE_TREE_MAP_SIZE; i++)
- BUG_ON(objnode->slots[i] != NULL);
- ASSERT_SENTINEL(objnode, OBJNODE);
- INVERT_SENTINEL(objnode, OBJNODE);
- BUG_ON(objnode->obj == NULL);
- ASSERT_SENTINEL(objnode->obj, OBJ);
- pool = objnode->obj->pool;
- BUG_ON(pool == NULL);
- ASSERT_SENTINEL(pool, POOL);
- objnode->obj->objnode_count--;
- objnode->obj = NULL;
- (*tmem_hostops.objnode_free)(objnode, pool);
-}
-
-/*
- * lookup index in object and return associated pampd (or NULL if not found)
- */
-static void **__tmem_pampd_lookup_in_obj(struct tmem_obj *obj, uint32_t index)
-{
- unsigned int height, shift;
- struct tmem_objnode **slot = NULL;
-
- BUG_ON(obj == NULL);
- ASSERT_SENTINEL(obj, OBJ);
- BUG_ON(obj->pool == NULL);
- ASSERT_SENTINEL(obj->pool, POOL);
-
- height = obj->objnode_tree_height;
- if (index > tmem_objnode_tree_h2max[obj->objnode_tree_height])
- goto out;
- if (height == 0 && obj->objnode_tree_root) {
- slot = &obj->objnode_tree_root;
- goto out;
- }
- shift = (height-1) * OBJNODE_TREE_MAP_SHIFT;
- slot = &obj->objnode_tree_root;
- while (height > 0) {
- if (*slot == NULL)
- goto out;
- slot = (struct tmem_objnode **)
- ((*slot)->slots +
- ((index >> shift) & OBJNODE_TREE_MAP_MASK));
- shift -= OBJNODE_TREE_MAP_SHIFT;
- height--;
- }
-out:
- return slot != NULL ? (void **)slot : NULL;
-}
-
-static void *tmem_pampd_lookup_in_obj(struct tmem_obj *obj, uint32_t index)
-{
- struct tmem_objnode **slot;
-
- slot = (struct tmem_objnode **)__tmem_pampd_lookup_in_obj(obj, index);
- return slot != NULL ? *slot : NULL;
-}
-
-static void *tmem_pampd_replace_in_obj(struct tmem_obj *obj, uint32_t index,
- void *new_pampd)
-{
- struct tmem_objnode **slot;
- void *ret = NULL;
-
- slot = (struct tmem_objnode **)__tmem_pampd_lookup_in_obj(obj, index);
- if ((slot != NULL) && (*slot != NULL)) {
- void *old_pampd = *(void **)slot;
- *(void **)slot = new_pampd;
- (*tmem_pamops.free)(old_pampd, obj->pool, NULL, 0);
- ret = new_pampd;
- }
- return ret;
-}
-
-static int tmem_pampd_add_to_obj(struct tmem_obj *obj, uint32_t index,
- void *pampd)
-{
- int ret = 0;
- struct tmem_objnode *objnode = NULL, *newnode, *slot;
- unsigned int height, shift;
- int offset = 0;
-
- /* if necessary, extend the tree to be higher */
- if (index > tmem_objnode_tree_h2max[obj->objnode_tree_height]) {
- height = obj->objnode_tree_height + 1;
- if (index > tmem_objnode_tree_h2max[height])
- while (index > tmem_objnode_tree_h2max[height])
- height++;
- if (obj->objnode_tree_root == NULL) {
- obj->objnode_tree_height = height;
- goto insert;
- }
- do {
- newnode = tmem_objnode_alloc(obj);
- if (!newnode) {
- ret = -ENOMEM;
- goto out;
- }
- newnode->slots[0] = obj->objnode_tree_root;
- newnode->slots_in_use = 1;
- obj->objnode_tree_root = newnode;
- obj->objnode_tree_height++;
- } while (height > obj->objnode_tree_height);
- }
-insert:
- slot = obj->objnode_tree_root;
- height = obj->objnode_tree_height;
- shift = (height-1) * OBJNODE_TREE_MAP_SHIFT;
- while (height > 0) {
- if (slot == NULL) {
- /* add a child objnode. */
- slot = tmem_objnode_alloc(obj);
- if (!slot) {
- ret = -ENOMEM;
- goto out;
- }
- if (objnode) {
-
- objnode->slots[offset] = slot;
- objnode->slots_in_use++;
- } else
- obj->objnode_tree_root = slot;
- }
- /* go down a level */
- offset = (index >> shift) & OBJNODE_TREE_MAP_MASK;
- objnode = slot;
- slot = objnode->slots[offset];
- shift -= OBJNODE_TREE_MAP_SHIFT;
- height--;
- }
- BUG_ON(slot != NULL);
- if (objnode) {
- objnode->slots_in_use++;
- objnode->slots[offset] = pampd;
- } else
- obj->objnode_tree_root = pampd;
- obj->pampd_count++;
-out:
- return ret;
-}
-
-static void *tmem_pampd_delete_from_obj(struct tmem_obj *obj, uint32_t index)
-{
- struct tmem_objnode_tree_path path[OBJNODE_TREE_MAX_PATH + 1];
- struct tmem_objnode_tree_path *pathp = path;
- struct tmem_objnode *slot = NULL;
- unsigned int height, shift;
- int offset;
-
- BUG_ON(obj == NULL);
- ASSERT_SENTINEL(obj, OBJ);
- BUG_ON(obj->pool == NULL);
- ASSERT_SENTINEL(obj->pool, POOL);
- height = obj->objnode_tree_height;
- if (index > tmem_objnode_tree_h2max[height])
- goto out;
- slot = obj->objnode_tree_root;
- if (height == 0 && obj->objnode_tree_root) {
- obj->objnode_tree_root = NULL;
- goto out;
- }
- shift = (height - 1) * OBJNODE_TREE_MAP_SHIFT;
- pathp->objnode = NULL;
- do {
- if (slot == NULL)
- goto out;
- pathp++;
- offset = (index >> shift) & OBJNODE_TREE_MAP_MASK;
- pathp->offset = offset;
- pathp->objnode = slot;
- slot = slot->slots[offset];
- shift -= OBJNODE_TREE_MAP_SHIFT;
- height--;
- } while (height > 0);
- if (slot == NULL)
- goto out;
- while (pathp->objnode) {
- pathp->objnode->slots[pathp->offset] = NULL;
- pathp->objnode->slots_in_use--;
- if (pathp->objnode->slots_in_use) {
- if (pathp->objnode == obj->objnode_tree_root) {
- while (obj->objnode_tree_height > 0 &&
- obj->objnode_tree_root->slots_in_use == 1 &&
- obj->objnode_tree_root->slots[0]) {
- struct tmem_objnode *to_free =
- obj->objnode_tree_root;
-
- obj->objnode_tree_root =
- to_free->slots[0];
- obj->objnode_tree_height--;
- to_free->slots[0] = NULL;
- to_free->slots_in_use = 0;
- tmem_objnode_free(to_free);
- }
- }
- goto out;
- }
- tmem_objnode_free(pathp->objnode); /* 0 slots used, free it */
- pathp--;
- }
- obj->objnode_tree_height = 0;
- obj->objnode_tree_root = NULL;
-
-out:
- if (slot != NULL)
- obj->pampd_count--;
- BUG_ON(obj->pampd_count < 0);
- return slot;
-}
-
-/* recursively walk the objnode_tree destroying pampds and objnodes */
-static void tmem_objnode_node_destroy(struct tmem_obj *obj,
- struct tmem_objnode *objnode,
- unsigned int ht)
-{
- int i;
-
- if (ht == 0)
- return;
- for (i = 0; i < OBJNODE_TREE_MAP_SIZE; i++) {
- if (objnode->slots[i]) {
- if (ht == 1) {
- obj->pampd_count--;
- (*tmem_pamops.free)(objnode->slots[i],
- obj->pool, NULL, 0);
- objnode->slots[i] = NULL;
- continue;
- }
- tmem_objnode_node_destroy(obj, objnode->slots[i], ht-1);
- tmem_objnode_free(objnode->slots[i]);
- objnode->slots[i] = NULL;
- }
- }
-}
-
-static void tmem_pampd_destroy_all_in_obj(struct tmem_obj *obj)
-{
- if (obj->objnode_tree_root == NULL)
- return;
- if (obj->objnode_tree_height == 0) {
- obj->pampd_count--;
- (*tmem_pamops.free)(obj->objnode_tree_root, obj->pool, NULL, 0);
- } else {
- tmem_objnode_node_destroy(obj, obj->objnode_tree_root,
- obj->objnode_tree_height);
- tmem_objnode_free(obj->objnode_tree_root);
- obj->objnode_tree_height = 0;
- }
- obj->objnode_tree_root = NULL;
- (*tmem_pamops.free_obj)(obj->pool, obj);
-}
-
-/*
- * Tmem is operated on by a set of well-defined actions:
- * "put", "get", "flush", "flush_object", "new pool" and "destroy pool".
- * (The tmem ABI allows for subpages and exchanges but these operations
- * are not included in this implementation.)
- *
- * These "tmem core" operations are implemented in the following functions.
- */
-
-/*
- * "Put" a page, e.g. copy a page from the kernel into newly allocated
- * PAM space (if such space is available). Tmem_put is complicated by
- * a corner case: What if a page with matching handle already exists in
- * tmem? To guarantee coherency, one of two actions is necessary: Either
- * the data for the page must be overwritten, or the page must be
- * "flushed" so that the data is not accessible to a subsequent "get".
- * Since these "duplicate puts" are relatively rare, this implementation
- * always flushes for simplicity.
- */
-int tmem_put(struct tmem_pool *pool, struct tmem_oid *oidp, uint32_t index,
- char *data, size_t size, bool raw, bool ephemeral)
-{
- struct tmem_obj *obj = NULL, *objfound = NULL, *objnew = NULL;
- void *pampd = NULL, *pampd_del = NULL;
- int ret = -ENOMEM;
- struct tmem_hashbucket *hb;
-
- lock_tmem_state();
- if (!tmem_enabled)
- goto disabled;
- hb = &pool->hashbucket[tmem_oid_hash(oidp)];
- spin_lock(&hb->lock);
- obj = objfound = tmem_obj_find(hb, oidp);
- if (obj != NULL) {
- pampd = tmem_pampd_lookup_in_obj(objfound, index);
- if (pampd != NULL) {
- /* if found, is a dup put, flush the old one */
- pampd_del = tmem_pampd_delete_from_obj(obj, index);
- BUG_ON(pampd_del != pampd);
- (*tmem_pamops.free)(pampd, pool, oidp, index);
- if (obj->pampd_count == 0) {
- objnew = obj;
- objfound = NULL;
- }
- pampd = NULL;
- }
- } else {
- obj = objnew = (*tmem_hostops.obj_alloc)(pool);
- if (unlikely(obj == NULL)) {
- ret = -ENOMEM;
- goto out;
- }
- tmem_obj_init(obj, hb, pool, oidp);
- }
- BUG_ON(obj == NULL);
- BUG_ON(((objnew != obj) && (objfound != obj)) || (objnew == objfound));
- pampd = (*tmem_pamops.create)(data, size, raw, ephemeral,
- obj->pool, &obj->oid, index);
- if (unlikely(pampd == NULL))
- goto free;
- ret = tmem_pampd_add_to_obj(obj, index, pampd);
- if (unlikely(ret == -ENOMEM))
- /* may have partially built objnode tree ("stump") */
- goto delete_and_free;
- goto out;
-
-delete_and_free:
- (void)tmem_pampd_delete_from_obj(obj, index);
-free:
- if (pampd)
- (*tmem_pamops.free)(pampd, pool, NULL, 0);
- if (objnew) {
- tmem_obj_free(objnew, hb);
- (*tmem_hostops.obj_free)(objnew, pool);
- }
-out:
- spin_unlock(&hb->lock);
-disabled:
- unlock_tmem_state();
- return ret;
-}
-
-/*
- * "Get" a page, e.g. if one can be found, copy the tmem page with the
- * matching handle from PAM space to the kernel. By tmem definition,
- * when a "get" is successful on an ephemeral page, the page is "flushed",
- * and when a "get" is successful on a persistent page, the page is retained
- * in tmem. Note that to preserve
- * coherency, "get" can never be skipped if tmem contains the data.
- * That is, if a get is done with a certain handle and fails, any
- * subsequent "get" must also fail (unless of course there is a
- * "put" done with the same handle).
-
- */
-int tmem_get(struct tmem_pool *pool, struct tmem_oid *oidp, uint32_t index,
- char *data, size_t *size, bool raw, int get_and_free)
-{
- struct tmem_obj *obj;
- void *pampd;
- bool ephemeral = is_ephemeral(pool);
- int ret = -1;
- struct tmem_hashbucket *hb;
- bool free = (get_and_free == 1) || ((get_and_free == 0) && ephemeral);
- bool lock_held = false;
-
- lock_tmem_state();
- if (!tmem_enabled)
- goto disabled;
- hb = &pool->hashbucket[tmem_oid_hash(oidp)];
- spin_lock(&hb->lock);
- lock_held = true;
- obj = tmem_obj_find(hb, oidp);
- if (obj == NULL)
- goto out;
- if (free)
- pampd = tmem_pampd_delete_from_obj(obj, index);
- else
- pampd = tmem_pampd_lookup_in_obj(obj, index);
- if (pampd == NULL)
- goto out;
- if (free) {
- if (obj->pampd_count == 0) {
- tmem_obj_free(obj, hb);
- (*tmem_hostops.obj_free)(obj, pool);
- obj = NULL;
- }
- }
- if (tmem_pamops.is_remote(pampd)) {
- lock_held = false;
- spin_unlock(&hb->lock);
- }
- if (free)
- ret = (*tmem_pamops.get_data_and_free)(
- data, size, raw, pampd, pool, oidp, index);
- else
- ret = (*tmem_pamops.get_data)(
- data, size, raw, pampd, pool, oidp, index);
- if (ret < 0)
- goto out;
- ret = 0;
-out:
- if (lock_held)
- spin_unlock(&hb->lock);
-disabled:
- unlock_tmem_state();
- return ret;
-}
-
-/*
- * If a page in tmem matches the handle, "flush" this page from tmem such
- * that any subsequent "get" does not succeed (unless, of course, there
- * was another "put" with the same handle).
- */
-int tmem_flush_page(struct tmem_pool *pool,
- struct tmem_oid *oidp, uint32_t index)
-{
- struct tmem_obj *obj;
- void *pampd;
- int ret = -1;
- struct tmem_hashbucket *hb;
-
- hb = &pool->hashbucket[tmem_oid_hash(oidp)];
- spin_lock(&hb->lock);
- obj = tmem_obj_find(hb, oidp);
- if (obj == NULL)
- goto out;
- pampd = tmem_pampd_delete_from_obj(obj, index);
- if (pampd == NULL)
- goto out;
- (*tmem_pamops.free)(pampd, pool, oidp, index);
- if (obj->pampd_count == 0) {
- tmem_obj_free(obj, hb);
- (*tmem_hostops.obj_free)(obj, pool);
- }
- ret = 0;
-
-out:
- spin_unlock(&hb->lock);
- return ret;
-}
-
-/*
- * If a page in tmem matches the handle, replace the page so that any
- * subsequent "get" gets the new page. Returns 0 if
- * there was a page to replace, else returns -1.
- */
-int tmem_replace(struct tmem_pool *pool, struct tmem_oid *oidp,
- uint32_t index, void *new_pampd)
-{
- struct tmem_obj *obj;
- int ret = -1;
- struct tmem_hashbucket *hb;
-
- lock_tmem_state();
- if (!tmem_enabled)
- goto disabled;
- hb = &pool->hashbucket[tmem_oid_hash(oidp)];
- spin_lock(&hb->lock);
- obj = tmem_obj_find(hb, oidp);
- if (obj == NULL)
- goto out;
- new_pampd = tmem_pampd_replace_in_obj(obj, index, new_pampd);
- ret = (*tmem_pamops.replace_in_obj)(new_pampd, obj);
-out:
- spin_unlock(&hb->lock);
-disabled:
- unlock_tmem_state();
- return ret;
-}
-
-/*
- * "Flush" all pages in tmem matching this oid.
- */
-int tmem_flush_object(struct tmem_pool *pool, struct tmem_oid *oidp)
-{
- struct tmem_obj *obj;
- struct tmem_hashbucket *hb;
- int ret = -1;
-
- hb = &pool->hashbucket[tmem_oid_hash(oidp)];
- spin_lock(&hb->lock);
- obj = tmem_obj_find(hb, oidp);
- if (obj == NULL)
- goto out;
- tmem_pampd_destroy_all_in_obj(obj);
- tmem_obj_free(obj, hb);
- (*tmem_hostops.obj_free)(obj, pool);
- ret = 0;
-
-out:
- spin_unlock(&hb->lock);
- return ret;
-}
-
-/*
- * "Flush" all pages (and tmem_objs) from this tmem_pool and disable
- * all subsequent access to this tmem_pool.
- */
-int tmem_destroy_pool(struct tmem_pool *pool)
-{
- int ret = -1;
-
- if (pool == NULL)
- goto out;
- tmem_pool_flush(pool, 1);
- ret = 0;
-out:
- return ret;
-}
-
-int tmem_flush_pool(struct tmem_pool *pool)
-{
- int ret = -1;
-
- if (pool == NULL)
- goto out;
- tmem_pool_flush(pool, 0);
- ret = 0;
-out:
- return ret;
-}
-
-static LIST_HEAD(tmem_global_pool_list);
-
-/*
- * Create a new tmem_pool with the provided flag and return
- * a pool id provided by the tmem host implementation.
- */
-void tmem_new_pool(struct tmem_pool *pool, uint32_t flags)
-{
- int persistent = flags & TMEM_POOL_PERSIST;
- int shared = flags & TMEM_POOL_SHARED;
- struct tmem_hashbucket *hb = &pool->hashbucket[0];
- int i;
-
- for (i = 0; i < TMEM_HASH_BUCKETS; i++, hb++) {
- hb->obj_rb_root = RB_ROOT;
- spin_lock_init(&hb->lock);
- }
- INIT_LIST_HEAD(&pool->pool_list);
- atomic_set(&pool->obj_count, 0);
- SET_SENTINEL(pool, POOL);
- list_add_tail(&pool->pool_list, &tmem_global_pool_list);
- pool->persistent = persistent;
- pool->shared = shared;
-}
-
-/* The following must be called with tmem state locked */
-static void tmem_cleanup(void)
-{
- (*tmem_hostops.flush_all_obj)();
-}
-
-void tmem_enable(void)
-{
- pr_info("turning tmem on\n");
- tmem_enabled = true;
-
- (*tmem_hostops.control)(false);
-}
-
-void tmem_disable(void)
-{
- pr_info("turning tmem off\n");
- tmem_enabled = false;
-
- tmem_cleanup();
- (*tmem_hostops.control)(true);
-}
diff --git a/drivers/staging/qcache/tmem.h b/drivers/staging/qcache/tmem.h
deleted file mode 100644
index 359c201..0000000
--- a/drivers/staging/qcache/tmem.h
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * tmem.h
- *
- * Transcendent memory
- *
- * Copyright (c) 2009-2011, Dan Magenheimer, Oracle Corp.
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
- */
-
-#ifndef _TMEM_H_
-#define _TMEM_H_
-
-#include <linux/types.h>
-#include <linux/highmem.h>
-#include <linux/hash.h>
-#include <linux/atomic.h>
-#include <linux/fmem.h>
-
-/*
- * These are pre-defined by the Xen<->Linux ABI
- */
-#define TMEM_PUT_PAGE 4
-#define TMEM_GET_PAGE 5
-#define TMEM_FLUSH_PAGE 6
-#define TMEM_FLUSH_OBJECT 7
-#define TMEM_POOL_PERSIST 1
-#define TMEM_POOL_SHARED 2
-#define TMEM_POOL_PRECOMPRESSED 4
-#define TMEM_POOL_PAGESIZE_SHIFT 4
-#define TMEM_POOL_PAGESIZE_MASK 0xf
-#define TMEM_POOL_RESERVED_BITS 0x00ffff00
-
-/*
- * sentinels have proven very useful for debugging but can be removed
- * or disabled before final merge.
- */
-#define SENTINELS
-#ifdef SENTINELS
-#define DECL_SENTINEL uint32_t sentinel;
-#define SET_SENTINEL(_x, _y) (_x->sentinel = _y##_SENTINEL)
-#define INVERT_SENTINEL(_x, _y) (_x->sentinel = ~_y##_SENTINEL)
-#define ASSERT_SENTINEL(_x, _y) WARN_ON(_x->sentinel != _y##_SENTINEL)
-#define ASSERT_INVERTED_SENTINEL(_x, _y) WARN_ON(_x->sentinel != ~_y##_SENTINEL)
-#else
-#define DECL_SENTINEL
-#define SET_SENTINEL(_x, _y) do { } while (0)
-#define INVERT_SENTINEL(_x, _y) do { } while (0)
-#define ASSERT_SENTINEL(_x, _y) do { } while (0)
-#define ASSERT_INVERTED_SENTINEL(_x, _y) do { } while (0)
-#endif
-
-/*
- * A pool is the highest-level data structure managed by tmem and
- * usually corresponds to a large independent set of pages such as
- * a filesystem. Each pool has an id, and certain attributes and counters.
- * It also contains a set of hash buckets, each of which contains an rbtree
- * of objects and a lock to manage concurrency within the pool.
- */
-
-#define TMEM_HASH_BUCKET_BITS 8
-#define TMEM_HASH_BUCKETS (1<<TMEM_HASH_BUCKET_BITS)
-
-struct tmem_hashbucket {
- struct rb_root obj_rb_root;
- spinlock_t lock;
-};
-
-struct tmem_pool {
- void *client; /* "up" for some clients, avoids table lookup */
- struct list_head pool_list;
- uint32_t pool_id;
- bool persistent;
- bool shared;
- atomic_t obj_count;
- atomic_t refcount;
- struct tmem_hashbucket hashbucket[TMEM_HASH_BUCKETS];
- DECL_SENTINEL
-};
-
-#define is_persistent(_p) (_p->persistent)
-#define is_ephemeral(_p) (!(_p->persistent))
-
-/*
- * An object id ("oid") is large: 192-bits (to ensure, for example, files
- * in a modern filesystem can be uniquely identified).
- */
-
-struct tmem_oid {
- uint64_t oid[3];
-};
-
-static inline void tmem_oid_set_invalid(struct tmem_oid *oidp)
-{
- oidp->oid[0] = oidp->oid[1] = oidp->oid[2] = -1UL;
-}
-
-static inline bool tmem_oid_valid(struct tmem_oid *oidp)
-{
- return oidp->oid[0] != -1UL || oidp->oid[1] != -1UL ||
- oidp->oid[2] != -1UL;
-}
-
-static inline int tmem_oid_compare(struct tmem_oid *left,
- struct tmem_oid *right)
-{
- int ret;
-
- if (left->oid[2] == right->oid[2]) {
- if (left->oid[1] == right->oid[1]) {
- if (left->oid[0] == right->oid[0])
- ret = 0;
- else if (left->oid[0] < right->oid[0])
- ret = -1;
- else
- return 1;
- } else if (left->oid[1] < right->oid[1])
- ret = -1;
- else
- ret = 1;
- } else if (left->oid[2] < right->oid[2])
- ret = -1;
- else
- ret = 1;
- return ret;
-}
-
-static inline unsigned tmem_oid_hash(struct tmem_oid *oidp)
-{
- return hash_long(oidp->oid[0] ^ oidp->oid[1] ^ oidp->oid[2],
- TMEM_HASH_BUCKET_BITS);
-}
-
-/*
- * A tmem_obj contains an identifier (oid), pointers to the parent
- * pool and the rb_tree to which it belongs, counters, and an ordered
- * set of pampds, structured in a radix-tree-like tree. The intermediate
- * nodes of the tree are called tmem_objnodes.
- */
-
-struct tmem_objnode;
-
-struct tmem_obj {
- struct tmem_oid oid;
- struct tmem_pool *pool;
- struct rb_node rb_tree_node;
- struct tmem_objnode *objnode_tree_root;
- unsigned int objnode_tree_height;
- unsigned long objnode_count;
- long pampd_count;
- void *extra; /* for private use by pampd implementation */
- DECL_SENTINEL
-};
-
-#define OBJNODE_TREE_MAP_SHIFT 6
-#define OBJNODE_TREE_MAP_SIZE (1UL << OBJNODE_TREE_MAP_SHIFT)
-#define OBJNODE_TREE_MAP_MASK (OBJNODE_TREE_MAP_SIZE-1)
-#define OBJNODE_TREE_INDEX_BITS (8 /* CHAR_BIT */ * sizeof(unsigned long))
-#define OBJNODE_TREE_MAX_PATH \
- (OBJNODE_TREE_INDEX_BITS/OBJNODE_TREE_MAP_SHIFT + 2)
-
-struct tmem_objnode {
- struct tmem_obj *obj;
- DECL_SENTINEL
- void *slots[OBJNODE_TREE_MAP_SIZE];
- unsigned int slots_in_use;
-};
-
-/* pampd abstract datatype methods provided by the PAM implementation */
-struct tmem_pamops {
- void *(*create)(char *, size_t, bool, int,
- struct tmem_pool *, struct tmem_oid *, uint32_t);
- int (*get_data)(char *, size_t *, bool, void *, struct tmem_pool *,
- struct tmem_oid *, uint32_t);
- int (*get_data_and_free)(char *, size_t *, bool, void *,
- struct tmem_pool *, struct tmem_oid *,
- uint32_t);
- void (*free)(void *, struct tmem_pool *, struct tmem_oid *, uint32_t);
- void (*free_obj)(struct tmem_pool *, struct tmem_obj *);
- bool (*is_remote)(void *);
- void (*new_obj)(struct tmem_obj *);
- int (*replace_in_obj)(void *, struct tmem_obj *);
-};
-extern void tmem_register_pamops(struct tmem_pamops *m);
-
-/* memory allocation methods provided by the host implementation */
-struct tmem_hostops {
- struct tmem_obj *(*obj_alloc)(struct tmem_pool *);
- void (*obj_free)(struct tmem_obj *, struct tmem_pool *);
- struct tmem_objnode *(*objnode_alloc)(struct tmem_pool *);
- void (*objnode_free)(struct tmem_objnode *, struct tmem_pool *);
- void (*flush_all_obj)(void);
- void (*control)(bool);
-};
-extern void tmem_register_hostops(struct tmem_hostops *m);
-
-/* core tmem accessor functions */
-extern int tmem_put(struct tmem_pool *, struct tmem_oid *, uint32_t index,
- char *, size_t, bool, bool);
-extern int tmem_get(struct tmem_pool *, struct tmem_oid *, uint32_t index,
- char *, size_t *, bool, int);
-extern int tmem_replace(struct tmem_pool *, struct tmem_oid *, uint32_t index,
- void *);
-extern int tmem_flush_page(struct tmem_pool *, struct tmem_oid *,
- uint32_t index);
-extern int tmem_flush_object(struct tmem_pool *, struct tmem_oid *);
-extern int tmem_destroy_pool(struct tmem_pool *);
-extern int tmem_flush_pool(struct tmem_pool *);
-extern void tmem_new_pool(struct tmem_pool *, uint32_t);
-
-extern void tmem_enable(void);
-extern void tmem_disable(void);
-#endif /* _TMEM_H */
diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
index 52608af..6933163 100644
--- a/drivers/thermal/msm8974-tsens.c
+++ b/drivers/thermal/msm8974-tsens.c
@@ -77,6 +77,9 @@
#define TSENS_EEPROM_8X10_1(n) ((n) + 0x1a4)
#define TSENS_EEPROM_8X10_1_OFFSET 8
+#define TSENS_EEPROM_8X10_2(n) ((n) + 0x1a8)
+#define TSENS_EEPROM_8X10_SPARE_1(n) ((n) + 0xd8)
+#define TSENS_EEPROM_8X10_SPARE_2(n) ((n) + 0xdc)
/* TSENS calibration Mask data */
#define TSENS_BASE1_MASK 0xff
@@ -207,6 +210,8 @@
#define TSENS_8X10_TSENS_CAL_SEL 0x70000000
#define TSENS1_8X10_POINT1_MASK 0x3f
#define TSENS1_8X10_POINT2_MASK 0xfc0
+#define TSENS_8X10_REDUN_SEL_MASK 0x6000000
+#define TSENS_8X10_REDUN_SEL_SHIFT 25
#define TSENS_BIT_APPEND 0x3
#define TSENS_CAL_DEGC_POINT1 30
@@ -559,6 +564,9 @@
unsigned int reg_cntl;
int code, hi_code, lo_code, code_err_chk, sensor_sw_id = 0, rc = 0;
+ if (!tm_sensor || trip < 0 || !temp)
+ return -EINVAL;
+
rc = tsens_get_sw_id_mapping(tm_sensor->sensor_hw_num, &sensor_sw_id);
if (rc < 0) {
pr_err("tsens mapping index not found\n");
@@ -721,17 +729,30 @@
int i, tsens_base0_data = 0, tsens0_point1 = 0, tsens1_point1 = 0;
int tsens0_point2 = 0, tsens1_point2 = 0;
int tsens_base1_data = 0, tsens_calibration_mode = 0;
- uint32_t calib_data[2];
+ uint32_t calib_data[2], calib_redun_sel;
uint32_t calib_tsens_point1_data[2], calib_tsens_point2_data[2];
if (tmdev->calibration_less_mode)
goto calibration_less_mode;
- calib_data[0] = readl_relaxed(
+ calib_redun_sel = readl_relaxed(
+ TSENS_EEPROM_8X10_2(tmdev->tsens_calib_addr));
+ calib_redun_sel = calib_redun_sel & TSENS_8X10_REDUN_SEL_MASK;
+ calib_redun_sel >>= TSENS_8X10_REDUN_SEL_SHIFT;
+ pr_debug("calib_redun_sel:%x\n", calib_redun_sel);
+
+ if (calib_redun_sel == TSENS_QFPROM_BACKUP_SEL) {
+ calib_data[0] = readl_relaxed(
+ TSENS_EEPROM_8X10_SPARE_1(tmdev->tsens_calib_addr));
+ calib_data[1] = readl_relaxed(
+ TSENS_EEPROM_8X10_SPARE_2(tmdev->tsens_calib_addr));
+ } else {
+ calib_data[0] = readl_relaxed(
TSENS_EEPROM_8X10_1(tmdev->tsens_calib_addr));
- calib_data[1] = readl_relaxed(
- (TSENS_EEPROM_8X10_1(tmdev->tsens_calib_addr) +
+ calib_data[1] = readl_relaxed(
+ (TSENS_EEPROM_8X10_1(tmdev->tsens_calib_addr) +
TSENS_EEPROM_8X10_1_OFFSET));
+ }
tsens_calibration_mode = (calib_data[0] & TSENS_8X10_TSENS_CAL_SEL)
>> TSENS_8X10_CAL_SEL_SHIFT;
@@ -1325,7 +1346,7 @@
static int get_device_tree_data(struct platform_device *pdev)
{
- const struct device_node *of_node = pdev->dev.of_node;
+ struct device_node *of_node = pdev->dev.of_node;
struct resource *res_mem = NULL;
u32 *tsens_slope_data;
u32 *sensor_id;
@@ -1353,8 +1374,13 @@
return rc;
};
- tsens_calib_mode = of_get_property(of_node,
- "qcom,calib-mode", NULL);
+ rc = of_property_read_string(of_node,
+ "qcom,calib-mode", &tsens_calib_mode);
+ if (rc) {
+ dev_err(&pdev->dev, "missing calib-mode\n");
+ return -ENODEV;
+ }
+
if (!strncmp(tsens_calib_mode, "fuse_map1", 9))
calib_type = TSENS_CALIB_FUSE_MAP_8974;
else if (!strncmp(tsens_calib_mode, "fuse_map2", 9))
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index 03c58a2..974cadc 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -1514,7 +1514,7 @@
goto read_node_fail;
}
- rails[i].curr_level = 0;
+ rails[i].curr_level = -1;
rails[i].reg = NULL;
i++;
}
diff --git a/drivers/thermal/qpnp-adc-tm.c b/drivers/thermal/qpnp-adc-tm.c
index f3b29c9..3b0ef8c 100644
--- a/drivers/thermal/qpnp-adc-tm.c
+++ b/drivers/thermal/qpnp-adc-tm.c
@@ -1315,7 +1315,7 @@
return -ENODEV;
if (param->threshold_notification == NULL) {
- pr_err("No notification for high/low temp??\n");
+ pr_debug("No notification for high/low temp??\n");
return -EINVAL;
}
diff --git a/drivers/tty/n_smux.c b/drivers/tty/n_smux.c
index d1545dc..e36806f 100644
--- a/drivers/tty/n_smux.c
+++ b/drivers/tty/n_smux.c
@@ -297,6 +297,8 @@
[SMUX_HIGH_WM_HIT] = "HIGH_WM_HIT",
[SMUX_RX_RETRY_HIGH_WM_HIT] = "RX_RETRY_HIGH_WM_HIT",
[SMUX_RX_RETRY_LOW_WM_HIT] = "RX_RETRY_LOW_WM_HIT",
+ [SMUX_LOCAL_CLOSED] = "LOCAL_CLOSED",
+ [SMUX_REMOTE_CLOSED] = "REMOTE_CLOSED",
};
static const char * const smux_local_state[] = {
@@ -553,6 +555,8 @@
/* Close all ports */
for (i = 0 ; i < SMUX_NUM_LOGICAL_CHANNELS; i++) {
+ union notifier_metadata meta;
+ int send_disconnect = 0;
ch = &smux_lch[i];
SMUX_DBG("smux: %s: cleaning up lcid %d\n", __func__, i);
@@ -563,14 +567,19 @@
smux_purge_ch_tx_queue(ch, 1);
spin_unlock(&ch->tx_lock_lhb2);
+ meta.disconnected.is_ssr = smux.in_reset;
/* Notify user of disconnect and reset channel state */
if (ch->local_state == SMUX_LCH_LOCAL_OPENED ||
ch->local_state == SMUX_LCH_LOCAL_CLOSING) {
- union notifier_metadata meta;
-
- meta.disconnected.is_ssr = smux.in_reset;
- schedule_notify(ch->lcid, SMUX_DISCONNECTED, &meta);
+ schedule_notify(ch->lcid, SMUX_LOCAL_CLOSED, &meta);
+ send_disconnect = 1;
}
+ if (ch->remote_state != SMUX_LCH_REMOTE_CLOSED) {
+ schedule_notify(ch->lcid, SMUX_REMOTE_CLOSED, &meta);
+ send_disconnect = 1;
+ }
+ if (send_disconnect)
+ schedule_notify(ch->lcid, SMUX_DISCONNECTED, &meta);
ch->local_state = SMUX_LCH_LOCAL_CLOSED;
ch->remote_state = SMUX_LCH_REMOTE_CLOSED;
@@ -857,6 +866,10 @@
IPC_LOG_STR("smux: %s ch:%d\n", event_to_str(event), lcid);
ch = &smux_lch[lcid];
+ if (!ch->notify) {
+ SMUX_DBG("%s: [%d]lcid notify fn is NULL\n", __func__, lcid);
+ return ret;
+ }
notify_handle = kzalloc(sizeof(struct smux_notify_handle),
GFP_ATOMIC);
if (!notify_handle) {
@@ -1173,6 +1186,7 @@
int ret;
struct smux_lch_t *ch;
int enable_powerdown = 0;
+ int tx_ready = 0;
lcid = pkt->hdr.lcid;
ch = &smux_lch[lcid];
@@ -1187,8 +1201,11 @@
enable_powerdown = 1;
ch->local_state = SMUX_LCH_LOCAL_OPENED;
- if (ch->remote_state == SMUX_LCH_REMOTE_OPENED)
+ if (ch->remote_state == SMUX_LCH_REMOTE_OPENED) {
schedule_notify(lcid, SMUX_CONNECTED, NULL);
+ if (!(list_empty(&ch->tx_queue)))
+ tx_ready = 1;
+ }
ret = 0;
} else if (ch->remote_mode == SMUX_LCH_MODE_REMOTE_LOOPBACK) {
SMUX_DBG("smux: Remote loopback OPEN ACK received\n");
@@ -1210,6 +1227,9 @@
spin_unlock(&smux.tx_lock_lha2);
}
+ if (tx_ready)
+ list_channel(ch);
+
return ret;
}
@@ -1232,6 +1252,7 @@
SMUX_LCH_LOCAL_CLOSING,
SMUX_LCH_LOCAL_CLOSED);
ch->local_state = SMUX_LCH_LOCAL_CLOSED;
+ schedule_notify(lcid, SMUX_LOCAL_CLOSED, &meta_disconnected);
if (ch->remote_state == SMUX_LCH_REMOTE_CLOSED)
schedule_notify(lcid, SMUX_DISCONNECTED,
&meta_disconnected);
@@ -1419,6 +1440,7 @@
}
}
+ schedule_notify(lcid, SMUX_REMOTE_CLOSED, &meta_disconnected);
if (ch->local_state == SMUX_LCH_LOCAL_CLOSED)
schedule_notify(lcid, SMUX_DISCONNECTED,
&meta_disconnected);
@@ -2357,8 +2379,11 @@
union notifier_metadata meta_disconnected;
meta_disconnected.disconnected.is_ssr = smux.in_reset;
- schedule_notify(ch->lcid, SMUX_DISCONNECTED,
+ schedule_notify(ch->lcid, SMUX_LOCAL_CLOSED,
&meta_disconnected);
+ if (ch->remote_state == SMUX_LCH_REMOTE_CLOSED)
+ schedule_notify(ch->lcid, SMUX_DISCONNECTED,
+ &meta_disconnected);
}
}
@@ -3086,11 +3111,15 @@
*
* @returns 0 for success, <0 otherwise
*
- * A channel must be fully closed (either not previously opened or
- * msm_smux_close() has been called and the SMUX_DISCONNECTED has been
- * received.
+ * The local channel state must be closed (either not previously
+ * opened or msm_smux_close() has been called and the SMUX_LOCAL_CLOSED
+ * notification has been received).
*
- * One the remote side is opened, the client will receive a SMUX_CONNECTED
+ * If open is called before the SMUX_LOCAL_CLOSED has been received,
+ * then the function will return -EAGAIN and the client will need to
+ * retry the open later.
+ *
+ * Once the remote side is opened, the client will receive a SMUX_CONNECTED
* event.
*/
int msm_smux_open(uint8_t lcid, void *priv,
@@ -3167,7 +3196,8 @@
* @returns 0 for success, <0 otherwise
*
* Once the close event has been acknowledge by the remote side, the client
- * will receive a SMUX_DISCONNECTED notification.
+ * will receive an SMUX_LOCAL_CLOSED notification. If the remote side is also
+ * closed, then an SMUX_DISCONNECTED notification will also be sent.
*/
int msm_smux_close(uint8_t lcid)
{
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 7f669d8..a243a05 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -192,7 +192,7 @@
ktime_t clk_off_delay;
enum msm_hs_clk_states_e clk_state;
enum msm_hs_clk_req_off_state_e clk_req_off_state;
-
+ atomic_t clk_count;
struct msm_hs_wakeup wakeup;
struct wake_lock dma_wake_lock; /* held while any DMA active */
@@ -219,8 +219,67 @@
struct msm_bus_scale_pdata *bus_scale_table;
bool rx_discard_flush_issued;
int rx_count_callback;
+ unsigned int *reg_ptr;
};
+unsigned int regmap_nonblsp[UART_DM_LAST] = {
+ [UART_DM_MR1] = UARTDM_MR1_ADDR,
+ [UART_DM_MR2] = UARTDM_MR2_ADDR,
+ [UART_DM_IMR] = UARTDM_IMR_ADDR,
+ [UART_DM_SR] = UARTDM_SR_ADDR,
+ [UART_DM_CR] = UARTDM_CR_ADDR,
+ [UART_DM_CSR] = UARTDM_CSR_ADDR,
+ [UART_DM_IPR] = UARTDM_IPR_ADDR,
+ [UART_DM_ISR] = UARTDM_ISR_ADDR,
+ [UART_DM_RX_TOTAL_SNAP] = UARTDM_RX_TOTAL_SNAP_ADDR,
+ [UART_DM_TFWR] = UARTDM_TFWR_ADDR,
+ [UART_DM_RFWR] = UARTDM_RFWR_ADDR,
+ [UART_DM_RF] = UARTDM_RF_ADDR,
+ [UART_DM_TF] = UARTDM_TF_ADDR,
+ [UART_DM_MISR] = UARTDM_MISR_ADDR,
+ [UART_DM_DMRX] = UARTDM_DMRX_ADDR,
+ [UART_DM_NCF_TX] = UARTDM_NCF_TX_ADDR,
+ [UART_DM_DMEN] = UARTDM_DMEN_ADDR,
+ [UART_DM_TXFS] = UARTDM_TXFS_ADDR,
+ [UART_DM_RXFS] = UARTDM_RXFS_ADDR,
+ [UART_DM_RX_TRANS_CTRL] = UARTDM_RX_TRANS_CTRL_ADDR,
+};
+
+unsigned int regmap_blsp[UART_DM_LAST] = {
+ [UART_DM_MR1] = 0x0,
+ [UART_DM_MR2] = 0x4,
+ [UART_DM_IMR] = 0xb0,
+ [UART_DM_SR] = 0xa4,
+ [UART_DM_CR] = 0xa8,
+ [UART_DM_CSR] = 0xa0,
+ [UART_DM_IPR] = 0x18,
+ [UART_DM_ISR] = 0xb4,
+ [UART_DM_RX_TOTAL_SNAP] = 0xbc,
+ [UART_DM_TFWR] = 0x1c,
+ [UART_DM_RFWR] = 0x20,
+ [UART_DM_RF] = 0x140,
+ [UART_DM_TF] = 0x100,
+ [UART_DM_MISR] = 0xac,
+ [UART_DM_DMRX] = 0x34,
+ [UART_DM_NCF_TX] = 0x40,
+ [UART_DM_DMEN] = 0x3c,
+ [UART_DM_TXFS] = 0x4c,
+ [UART_DM_RXFS] = 0x50,
+ [UART_DM_RX_TRANS_CTRL] = 0xcc,
+};
+
+static struct of_device_id msm_hs_match_table[] = {
+ { .compatible = "qcom,msm-hsuart-v14",
+ .data = regmap_blsp
+ },
+ {
+ .compatible = "qcom,msm-hsuart-v13",
+ .data = regmap_nonblsp
+ },
+ {}
+};
+
+
#define MSM_UARTDM_BURST_SIZE 16 /* DM burst size (in bytes) */
#define UARTDM_TX_BUF_SIZE UART_XMIT_SIZE
#define UARTDM_RX_BUF_SIZE 512
@@ -241,6 +300,7 @@
static void msm_hs_start_rx_locked(struct uart_port *uport);
static void msm_serial_hs_rx_tlet(unsigned long tlet_ptr);
static void flip_insert_work(struct work_struct *work);
+static void msm_hs_bus_voting(struct msm_hs_port *msm_uport, unsigned int vote);
#define UARTDM_TO_MSM(uart_port) \
container_of((uart_port), struct msm_hs_port, uport)
@@ -287,6 +347,61 @@
return ret;
}
+static int msm_hs_clock_vote(struct msm_hs_port *msm_uport)
+{
+ int rc = 0;
+
+ if (1 == atomic_inc_return(&msm_uport->clk_count)) {
+ msm_hs_bus_voting(msm_uport, BUS_SCALING);
+ /* Turn on core clk and iface clk */
+ rc = clk_prepare_enable(msm_uport->clk);
+ if (rc) {
+ dev_err(msm_uport->uport.dev,
+ "%s: Could not turn on core clk [%d]\n",
+ __func__, rc);
+ return rc;
+ }
+
+ if (msm_uport->pclk) {
+ rc = clk_prepare_enable(msm_uport->pclk);
+ if (rc) {
+ clk_disable_unprepare(msm_uport->clk);
+ dev_err(msm_uport->uport.dev,
+ "%s: Could not turn on pclk [%d]\n",
+ __func__, rc);
+ return rc;
+ }
+ }
+ msm_uport->clk_state = MSM_HS_CLK_ON;
+ }
+
+
+ return rc;
+}
+
+static void msm_hs_clock_unvote(struct msm_hs_port *msm_uport)
+{
+ int rc = atomic_dec_return(&msm_uport->clk_count);
+
+ if (rc < 0) {
+ msm_hs_bus_voting(msm_uport, BUS_RESET);
+ WARN(rc, "msm_uport->clk_count < 0!");
+ dev_err(msm_uport->uport.dev,
+ "%s: Clocks count invalid [%d]\n", __func__,
+ atomic_read(&msm_uport->clk_count));
+ return;
+ }
+
+ if (0 == rc) {
+ msm_hs_bus_voting(msm_uport, BUS_RESET);
+ /* Turn off the core clk and iface clk*/
+ clk_disable_unprepare(msm_uport->clk);
+ if (msm_uport->pclk)
+ clk_disable_unprepare(msm_uport->pclk);
+ msm_uport->clk_state = MSM_HS_CLK_OFF;
+ }
+}
+
static ssize_t show_clock(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -365,14 +480,23 @@
}
static inline unsigned int msm_hs_read(struct uart_port *uport,
- unsigned int offset)
+ unsigned int index)
{
+ struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+ unsigned int offset;
+
+ offset = *(msm_uport->reg_ptr + index);
+
return readl_relaxed(uport->membase + offset);
}
-static inline void msm_hs_write(struct uart_port *uport, unsigned int offset,
+static inline void msm_hs_write(struct uart_port *uport, unsigned int index,
unsigned int value)
{
+ struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+ unsigned int offset;
+
+ offset = *(msm_uport->reg_ptr + index);
writel_relaxed(value, uport->membase + offset);
}
@@ -432,40 +556,33 @@
unsigned long flags;
int ret = 0;
- msm_hs_bus_voting(msm_uport, BUS_SCALING);
-
- clk_prepare_enable(msm_uport->clk);
- if (msm_uport->pclk)
- clk_prepare_enable(msm_uport->pclk);
+ msm_hs_clock_vote(msm_uport);
if (val) {
spin_lock_irqsave(&uport->lock, flags);
- ret = msm_hs_read(uport, UARTDM_MR2_ADDR);
+ ret = msm_hs_read(uport, UART_DM_MR2);
if (is_blsp_uart(msm_uport))
ret |= (UARTDM_MR2_LOOP_MODE_BMSK |
UARTDM_MR2_RFR_CTS_LOOP_MODE_BMSK);
else
ret |= UARTDM_MR2_LOOP_MODE_BMSK;
- msm_hs_write(uport, UARTDM_MR2_ADDR, ret);
+ msm_hs_write(uport, UART_DM_MR2, ret);
spin_unlock_irqrestore(&uport->lock, flags);
} else {
spin_lock_irqsave(&uport->lock, flags);
- ret = msm_hs_read(uport, UARTDM_MR2_ADDR);
+ ret = msm_hs_read(uport, UART_DM_MR2);
if (is_blsp_uart(msm_uport))
ret &= ~(UARTDM_MR2_LOOP_MODE_BMSK |
UARTDM_MR2_RFR_CTS_LOOP_MODE_BMSK);
else
ret &= ~UARTDM_MR2_LOOP_MODE_BMSK;
- msm_hs_write(uport, UARTDM_MR2_ADDR, ret);
+ msm_hs_write(uport, UART_DM_MR2, ret);
spin_unlock_irqrestore(&uport->lock, flags);
}
/* Calling CLOCK API. Hence mb() requires here. */
mb();
- clk_disable_unprepare(msm_uport->clk);
- if (msm_uport->pclk)
- clk_disable_unprepare(msm_uport->pclk);
- msm_hs_bus_voting(msm_uport, BUS_RESET);
+ msm_hs_clock_unvote(msm_uport);
return 0;
}
@@ -476,23 +593,16 @@
unsigned long flags;
int ret = 0;
- msm_hs_bus_voting(msm_uport, BUS_SCALING);
-
- clk_prepare_enable(msm_uport->clk);
- if (msm_uport->pclk)
- clk_prepare_enable(msm_uport->pclk);
+ msm_hs_clock_vote(msm_uport);
spin_lock_irqsave(&uport->lock, flags);
- ret = msm_hs_read(&msm_uport->uport, UARTDM_MR2_ADDR);
+ ret = msm_hs_read(&msm_uport->uport, UART_DM_MR2);
spin_unlock_irqrestore(&uport->lock, flags);
- clk_disable_unprepare(msm_uport->clk);
- if (msm_uport->pclk)
- clk_disable_unprepare(msm_uport->pclk);
+ msm_hs_clock_unvote(msm_uport);
*val = (ret & UARTDM_MR2_LOOP_MODE_BMSK) ? 1 : 0;
- msm_hs_bus_voting(msm_uport, BUS_RESET);
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(loopback_enable_fops, msm_serial_loopback_enable_get,
@@ -585,22 +695,12 @@
return ret;
}
- ret = clk_prepare_enable(msm_uport->clk);
+ ret = msm_hs_clock_vote(msm_uport);
if (ret) {
printk(KERN_ERR "Error could not turn on UART clk\n");
return ret;
}
- if (msm_uport->pclk) {
- ret = clk_prepare_enable(msm_uport->pclk);
- if (ret) {
- clk_disable_unprepare(msm_uport->clk);
- dev_err(uport->dev,
- "Error could not turn on UART pclk\n");
- return ret;
- }
- }
- msm_uport->clk_state = MSM_HS_CLK_ON;
return 0;
}
@@ -705,63 +805,63 @@
switch (bps) {
case 300:
- msm_hs_write(uport, UARTDM_CSR_ADDR, 0x00);
+ msm_hs_write(uport, UART_DM_CSR, 0x00);
rxstale = 1;
break;
case 600:
- msm_hs_write(uport, UARTDM_CSR_ADDR, 0x11);
+ msm_hs_write(uport, UART_DM_CSR, 0x11);
rxstale = 1;
break;
case 1200:
- msm_hs_write(uport, UARTDM_CSR_ADDR, 0x22);
+ msm_hs_write(uport, UART_DM_CSR, 0x22);
rxstale = 1;
break;
case 2400:
- msm_hs_write(uport, UARTDM_CSR_ADDR, 0x33);
+ msm_hs_write(uport, UART_DM_CSR, 0x33);
rxstale = 1;
break;
case 4800:
- msm_hs_write(uport, UARTDM_CSR_ADDR, 0x44);
+ msm_hs_write(uport, UART_DM_CSR, 0x44);
rxstale = 1;
break;
case 9600:
- msm_hs_write(uport, UARTDM_CSR_ADDR, 0x55);
+ msm_hs_write(uport, UART_DM_CSR, 0x55);
rxstale = 2;
break;
case 14400:
- msm_hs_write(uport, UARTDM_CSR_ADDR, 0x66);
+ msm_hs_write(uport, UART_DM_CSR, 0x66);
rxstale = 3;
break;
case 19200:
- msm_hs_write(uport, UARTDM_CSR_ADDR, 0x77);
+ msm_hs_write(uport, UART_DM_CSR, 0x77);
rxstale = 4;
break;
case 28800:
- msm_hs_write(uport, UARTDM_CSR_ADDR, 0x88);
+ msm_hs_write(uport, UART_DM_CSR, 0x88);
rxstale = 6;
break;
case 38400:
- msm_hs_write(uport, UARTDM_CSR_ADDR, 0x99);
+ msm_hs_write(uport, UART_DM_CSR, 0x99);
rxstale = 8;
break;
case 57600:
- msm_hs_write(uport, UARTDM_CSR_ADDR, 0xaa);
+ msm_hs_write(uport, UART_DM_CSR, 0xaa);
rxstale = 16;
break;
case 76800:
- msm_hs_write(uport, UARTDM_CSR_ADDR, 0xbb);
+ msm_hs_write(uport, UART_DM_CSR, 0xbb);
rxstale = 16;
break;
case 115200:
- msm_hs_write(uport, UARTDM_CSR_ADDR, 0xcc);
+ msm_hs_write(uport, UART_DM_CSR, 0xcc);
rxstale = 31;
break;
case 230400:
- msm_hs_write(uport, UARTDM_CSR_ADDR, 0xee);
+ msm_hs_write(uport, UART_DM_CSR, 0xee);
rxstale = 31;
break;
case 460800:
- msm_hs_write(uport, UARTDM_CSR_ADDR, 0xff);
+ msm_hs_write(uport, UART_DM_CSR, 0xff);
rxstale = 31;
break;
case 4000000:
@@ -774,11 +874,11 @@
case 1152000:
case 1000000:
case 921600:
- msm_hs_write(uport, UARTDM_CSR_ADDR, 0xff);
+ msm_hs_write(uport, UART_DM_CSR, 0xff);
rxstale = 31;
break;
default:
- msm_hs_write(uport, UARTDM_CSR_ADDR, 0xff);
+ msm_hs_write(uport, UART_DM_CSR, 0xff);
/* default to 9600 */
bps = 9600;
rxstale = 2;
@@ -816,14 +916,14 @@
data = rxstale & UARTDM_IPR_STALE_LSB_BMSK;
data |= UARTDM_IPR_STALE_TIMEOUT_MSB_BMSK & (rxstale << 2);
- msm_hs_write(uport, UARTDM_IPR_ADDR, data);
+ msm_hs_write(uport, UART_DM_IPR, data);
/*
* It is suggested to do reset of transmitter and receiver after
* changing any protocol configuration. Here Baud rate and stale
* timeout are getting updated. Hence reset transmitter and receiver.
*/
- msm_hs_write(uport, UARTDM_CR_ADDR, RESET_TX);
- msm_hs_write(uport, UARTDM_CR_ADDR, RESET_RX);
+ msm_hs_write(uport, UART_DM_CR, RESET_TX);
+ msm_hs_write(uport, UART_DM_CR, RESET_RX);
}
@@ -835,35 +935,35 @@
switch (bps) {
case 9600:
- msm_hs_write(uport, UARTDM_CSR_ADDR, 0x99);
+ msm_hs_write(uport, UART_DM_CSR, 0x99);
rxstale = 2;
break;
case 14400:
- msm_hs_write(uport, UARTDM_CSR_ADDR, 0xaa);
+ msm_hs_write(uport, UART_DM_CSR, 0xaa);
rxstale = 3;
break;
case 19200:
- msm_hs_write(uport, UARTDM_CSR_ADDR, 0xbb);
+ msm_hs_write(uport, UART_DM_CSR, 0xbb);
rxstale = 4;
break;
case 28800:
- msm_hs_write(uport, UARTDM_CSR_ADDR, 0xcc);
+ msm_hs_write(uport, UART_DM_CSR, 0xcc);
rxstale = 6;
break;
case 38400:
- msm_hs_write(uport, UARTDM_CSR_ADDR, 0xdd);
+ msm_hs_write(uport, UART_DM_CSR, 0xdd);
rxstale = 8;
break;
case 57600:
- msm_hs_write(uport, UARTDM_CSR_ADDR, 0xee);
+ msm_hs_write(uport, UART_DM_CSR, 0xee);
rxstale = 16;
break;
case 115200:
- msm_hs_write(uport, UARTDM_CSR_ADDR, 0xff);
+ msm_hs_write(uport, UART_DM_CSR, 0xff);
rxstale = 31;
break;
default:
- msm_hs_write(uport, UARTDM_CSR_ADDR, 0x99);
+ msm_hs_write(uport, UART_DM_CSR, 0x99);
/* default to 9600 */
bps = 9600;
rxstale = 2;
@@ -873,7 +973,7 @@
data = rxstale & UARTDM_IPR_STALE_LSB_BMSK;
data |= UARTDM_IPR_STALE_TIMEOUT_MSB_BMSK & (rxstale << 2);
- msm_hs_write(uport, UARTDM_IPR_ADDR, data);
+ msm_hs_write(uport, UART_DM_IPR, data);
}
@@ -896,7 +996,7 @@
struct sps_pipe *sps_pipe_handle = rx->prod.pipe_handle;
mutex_lock(&msm_uport->clk_mutex);
- msm_hs_write(uport, UARTDM_IMR_ADDR, 0);
+ msm_hs_write(uport, UART_DM_IMR, 0);
/*
* Disable Rx channel of UARTDM
@@ -907,7 +1007,7 @@
* Note: should not reset the receiver here immediately as it is not
* suggested to do disable/reset or reset/disable at the same time.
*/
- data = msm_hs_read(uport, UARTDM_DMEN_ADDR);
+ data = msm_hs_read(uport, UART_DM_DMEN);
if (is_blsp_uart(msm_uport)) {
/* Disable UARTDM RX BAM Interface */
data &= ~UARTDM_RX_BAM_ENABLE_BMSK;
@@ -915,7 +1015,7 @@
data &= ~UARTDM_RX_DM_EN_BMSK;
}
- msm_hs_write(uport, UARTDM_DMEN_ADDR, data);
+ msm_hs_write(uport, UART_DM_DMEN, data);
/* 300 is the minimum baud support by the driver */
bps = uart_get_baud_rate(uport, termios, oldtermios, 200, 4000000);
@@ -930,7 +1030,7 @@
else
msm_hs_set_bps_locked(uport, bps);
- data = msm_hs_read(uport, UARTDM_MR2_ADDR);
+ data = msm_hs_read(uport, UART_DM_MR2);
data &= ~UARTDM_MR2_PARITY_MODE_BMSK;
/* set parity */
if (PARENB == (c_cflag & PARENB)) {
@@ -969,10 +1069,10 @@
}
data |= UARTDM_MR2_ERROR_MODE_BMSK;
/* write parity/bits per char/stop bit configuration */
- msm_hs_write(uport, UARTDM_MR2_ADDR, data);
+ msm_hs_write(uport, UART_DM_MR2, data);
/* Configure HW flow control */
- data = msm_hs_read(uport, UARTDM_MR1_ADDR);
+ data = msm_hs_read(uport, UART_DM_MR1);
data &= ~(UARTDM_MR1_CTS_CTL_BMSK | UARTDM_MR1_RX_RDY_CTL_BMSK);
@@ -981,7 +1081,7 @@
data |= UARTDM_MR1_RX_RDY_CTL_BMSK;
}
- msm_hs_write(uport, UARTDM_MR1_ADDR, data);
+ msm_hs_write(uport, UART_DM_MR1, data);
uport->ignore_status_mask = termios->c_iflag & INPCK;
uport->ignore_status_mask |= termios->c_iflag & IGNPAR;
@@ -993,8 +1093,8 @@
/* Set Transmit software time out */
uart_update_timeout(uport, c_cflag, bps);
- msm_hs_write(uport, UARTDM_CR_ADDR, RESET_RX);
- msm_hs_write(uport, UARTDM_CR_ADDR, RESET_TX);
+ msm_hs_write(uport, UART_DM_CR, RESET_RX);
+ msm_hs_write(uport, UART_DM_CR, RESET_TX);
if (msm_uport->rx.flush == FLUSH_NONE) {
wake_lock(&msm_uport->rx.wake_lock);
@@ -1027,7 +1127,7 @@
}
}
- msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg);
+ msm_hs_write(uport, UART_DM_IMR, msm_uport->imr_reg);
mb();
mutex_unlock(&msm_uport->clk_mutex);
}
@@ -1040,8 +1140,12 @@
{
unsigned int data;
unsigned int ret = 0;
+ struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+ msm_hs_clock_vote(msm_uport);
data = msm_hs_read(uport, UARTDM_SR_ADDR);
+ msm_hs_clock_unvote(msm_uport);
+
if (data & UARTDM_SR_TXEMT_BMSK)
ret = TIOCSER_TEMT;
@@ -1093,12 +1197,12 @@
unsigned int data;
/* disable dlink */
- data = msm_hs_read(uport, UARTDM_DMEN_ADDR);
+ data = msm_hs_read(uport, UART_DM_DMEN);
if (is_blsp_uart(msm_uport))
data &= ~UARTDM_RX_BAM_ENABLE_BMSK;
else
data &= ~UARTDM_RX_DM_EN_BMSK;
- msm_hs_write(uport, UARTDM_DMEN_ADDR, data);
+ msm_hs_write(uport, UART_DM_DMEN, data);
/* calling DMOV or CLOCK API. Hence mb() */
mb();
@@ -1162,7 +1266,7 @@
if (is_blsp_uart(msm_uport)) {
/* Issue TX BAM Start IFC command */
- msm_hs_write(uport, UARTDM_CR_ADDR, START_TX_BAM_IFC);
+ msm_hs_write(uport, UART_DM_CR, START_TX_BAM_IFC);
} else {
tx->command_ptr->num_rows =
(((tx_count + 15) >> 4) << 16) |
@@ -1178,11 +1282,11 @@
/* Save tx_count to use in Callback */
tx->tx_count = tx_count;
- msm_hs_write(uport, UARTDM_NCF_TX_ADDR, tx_count);
+ msm_hs_write(uport, UART_DM_NCF_TX, tx_count);
/* Disable the tx_ready interrupt */
msm_uport->imr_reg &= ~UARTDM_ISR_TX_READY_BMSK;
- msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg);
+ msm_hs_write(uport, UART_DM_IMR, msm_uport->imr_reg);
/* Calling next DMOV API. Hence mb() here. */
mb();
@@ -1216,16 +1320,16 @@
printk(KERN_ERR "Error: rx started in buffer state = %x",
buffer_pending);
- msm_hs_write(uport, UARTDM_CR_ADDR, RESET_STALE_INT);
- msm_hs_write(uport, UARTDM_DMRX_ADDR, UARTDM_RX_BUF_SIZE);
- msm_hs_write(uport, UARTDM_CR_ADDR, STALE_EVENT_ENABLE);
+ msm_hs_write(uport, UART_DM_CR, RESET_STALE_INT);
+ msm_hs_write(uport, UART_DM_DMRX, UARTDM_RX_BUF_SIZE);
+ msm_hs_write(uport, UART_DM_CR, STALE_EVENT_ENABLE);
msm_uport->imr_reg |= UARTDM_ISR_RXLEV_BMSK;
/*
* Enable UARTDM Rx Interface as previously it has been
* disable in set_termios before configuring baud rate.
*/
- data = msm_hs_read(uport, UARTDM_DMEN_ADDR);
+ data = msm_hs_read(uport, UART_DM_DMEN);
if (is_blsp_uart(msm_uport)) {
/* Enable UARTDM Rx BAM Interface */
data |= UARTDM_RX_BAM_ENABLE_BMSK;
@@ -1233,8 +1337,8 @@
data |= UARTDM_RX_DM_EN_BMSK;
}
- msm_hs_write(uport, UARTDM_DMEN_ADDR, data);
- msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg);
+ msm_hs_write(uport, UART_DM_DMEN, data);
+ msm_hs_write(uport, UART_DM_IMR, msm_uport->imr_reg);
/* Calling next DMOV API. Hence mb() here. */
mb();
@@ -1245,9 +1349,9 @@
*/
data = (RX_STALE_AUTO_RE_EN | RX_TRANS_AUTO_RE_ACTIVATE |
RX_DMRX_CYCLIC_EN);
- msm_hs_write(uport, UARTDM_RX_TRANS_CTRL_ADDR, data);
+ msm_hs_write(uport, UART_DM_RX_TRANS_CTRL, data);
/* Issue RX BAM Start IFC command */
- msm_hs_write(uport, UARTDM_CR_ADDR, START_RX_BAM_IFC);
+ msm_hs_write(uport, UART_DM_CR, START_RX_BAM_IFC);
mb();
}
@@ -1342,12 +1446,12 @@
notify = &msm_uport->notify;
rx = &msm_uport->rx;
- status = msm_hs_read(uport, UARTDM_SR_ADDR);
+ status = msm_hs_read(uport, UART_DM_SR);
spin_lock_irqsave(&uport->lock, flags);
if (!is_blsp_uart(msm_uport))
- msm_hs_write(uport, UARTDM_CR_ADDR, STALE_EVENT_DISABLE);
+ msm_hs_write(uport, UART_DM_CR, STALE_EVENT_DISABLE);
/* overflow is not connect to data in a FIFO */
if (unlikely((status & UARTDM_SR_OVERRUN_BMSK) &&
@@ -1388,7 +1492,7 @@
}
if (error_f)
- msm_hs_write(uport, UARTDM_CR_ADDR, RESET_ERROR_STATUS);
+ msm_hs_write(uport, UART_DM_CR, RESET_ERROR_STATUS);
if (msm_uport->clk_req_off_state == CLK_REQ_OFF_FLUSH_ISSUED)
msm_uport->clk_req_off_state = CLK_REQ_OFF_RXSTALE_FLUSHED;
@@ -1407,7 +1511,7 @@
if (is_blsp_uart(msm_uport)) {
rx_count = msm_uport->rx_count_callback;
} else {
- rx_count = msm_hs_read(uport, UARTDM_RX_TOTAL_SNAP_ADDR);
+ rx_count = msm_hs_read(uport, UART_DM_RX_TOTAL_SNAP);
/* order the read of rx.buffer */
rmb();
}
@@ -1530,7 +1634,7 @@
}
msm_uport->imr_reg |= UARTDM_ISR_TX_READY_BMSK;
- msm_hs_write(&(msm_uport->uport), UARTDM_IMR_ADDR, msm_uport->imr_reg);
+ msm_hs_write(&(msm_uport->uport), UART_DM_IMR, msm_uport->imr_reg);
/* Calling clk API. Hence mb() requires. */
mb();
@@ -1639,17 +1743,17 @@
/* RTS is active low */
set_rts = TIOCM_RTS & mctrl ? 0 : 1;
- data = msm_hs_read(uport, UARTDM_MR1_ADDR);
+ data = msm_hs_read(uport, UART_DM_MR1);
if (set_rts) {
/*disable auto ready-for-receiving */
data &= ~UARTDM_MR1_RX_RDY_CTL_BMSK;
- msm_hs_write(uport, UARTDM_MR1_ADDR, data);
+ msm_hs_write(uport, UART_DM_MR1, data);
/* set RFR_N to high */
- msm_hs_write(uport, UARTDM_CR_ADDR, RFR_HIGH);
+ msm_hs_write(uport, UART_DM_CR, RFR_HIGH);
} else {
/* Enable auto ready-for-receiving */
data |= UARTDM_MR1_RX_RDY_CTL_BMSK;
- msm_hs_write(uport, UARTDM_MR1_ADDR, data);
+ msm_hs_write(uport, UART_DM_MR1, data);
}
mb();
}
@@ -1658,10 +1762,13 @@
unsigned int mctrl)
{
unsigned long flags;
+ struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+ msm_hs_clock_vote(msm_uport);
spin_lock_irqsave(&uport->lock, flags);
msm_hs_set_mctrl_locked(uport, mctrl);
spin_unlock_irqrestore(&uport->lock, flags);
+ msm_hs_clock_unvote(msm_uport);
}
EXPORT_SYMBOL(msm_hs_set_mctrl);
@@ -1672,7 +1779,7 @@
/* Enable DELTA_CTS Interrupt */
msm_uport->imr_reg |= UARTDM_ISR_DELTA_CTS_BMSK;
- msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg);
+ msm_hs_write(uport, UART_DM_IMR, msm_uport->imr_reg);
mb();
}
@@ -1696,7 +1803,7 @@
unsigned long flags;
spin_lock_irqsave(&uport->lock, flags);
- msm_hs_write(uport, UARTDM_CR_ADDR, ctl ? START_BREAK : STOP_BREAK);
+ msm_hs_write(uport, UART_DM_CR, ctl ? START_BREAK : STOP_BREAK);
mb();
spin_unlock_irqrestore(&uport->lock, flags);
}
@@ -1727,7 +1834,7 @@
static void msm_hs_handle_delta_cts_locked(struct uart_port *uport)
{
/* clear interrupt */
- msm_hs_write(uport, UARTDM_CR_ADDR, RESET_CTS);
+ msm_hs_write(uport, UART_DM_CR, RESET_CTS);
/* Calling CLOCK API. Hence mb() requires here. */
mb();
uport->icount.cts++;
@@ -1763,7 +1870,7 @@
}
/* Make sure the uart is finished with the last byte */
- sr_status = msm_hs_read(uport, UARTDM_SR_ADDR);
+ sr_status = msm_hs_read(uport, UARTDM_SR);
if (!(sr_status & UARTDM_SR_TXEMT_BMSK)) {
spin_unlock_irqrestore(&uport->lock, flags);
mutex_unlock(&msm_uport->clk_mutex);
@@ -1776,7 +1883,7 @@
msm_uport->clk_req_off_state = CLK_REQ_OFF_RXSTALE_ISSUED;
if (!is_blsp_uart(msm_uport)) {
- msm_hs_write(uport, UARTDM_CR_ADDR, FORCE_STALE_EVENT);
+ msm_hs_write(uport, UART_DM_CR, FORCE_STALE_EVENT);
/*
* Before returning make sure that device writel
* completed. Hence mb() requires here.
@@ -1825,11 +1932,7 @@
spin_unlock_irqrestore(&uport->lock, flags);
/* we really want to clock off */
- clk_disable_unprepare(msm_uport->clk);
- if (msm_uport->pclk)
- clk_disable_unprepare(msm_uport->pclk);
-
- msm_uport->clk_state = MSM_HS_CLK_OFF;
+ msm_hs_clock_unvote(msm_uport);
spin_lock_irqsave(&uport->lock, flags);
if (use_low_power_wakeup(msm_uport)) {
@@ -1881,20 +1984,20 @@
spin_lock_irqsave(&uport->lock, flags);
- isr_status = msm_hs_read(uport, UARTDM_MISR_ADDR);
+ isr_status = msm_hs_read(uport, UART_DM_MISR);
/* Uart RX starting */
if (isr_status & UARTDM_ISR_RXLEV_BMSK) {
wake_lock(&rx->wake_lock); /* hold wakelock while rx dma */
msm_uport->imr_reg &= ~UARTDM_ISR_RXLEV_BMSK;
- msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg);
+ msm_hs_write(uport, UART_DM_IMR, msm_uport->imr_reg);
/* Complete device write for IMR. Hence mb() requires. */
mb();
}
/* Stale rx interrupt */
if (isr_status & UARTDM_ISR_RXSTALE_BMSK) {
- msm_hs_write(uport, UARTDM_CR_ADDR, STALE_EVENT_DISABLE);
- msm_hs_write(uport, UARTDM_CR_ADDR, RESET_STALE_INT);
+ msm_hs_write(uport, UART_DM_CR, STALE_EVENT_DISABLE);
+ msm_hs_write(uport, UART_DM_CR, RESET_STALE_INT);
/*
* Complete device write before calling DMOV API. Hence
* mb() requires here.
@@ -1914,12 +2017,11 @@
/* tx ready interrupt */
if (isr_status & UARTDM_ISR_TX_READY_BMSK) {
/* Clear TX Ready */
- msm_hs_write(uport, UARTDM_CR_ADDR, CLEAR_TX_READY);
+ msm_hs_write(uport, UART_DM_CR, CLEAR_TX_READY);
if (msm_uport->clk_state == MSM_HS_CLK_REQUEST_OFF) {
msm_uport->imr_reg |= UARTDM_ISR_TXLEV_BMSK;
- msm_hs_write(uport, UARTDM_IMR_ADDR,
- msm_uport->imr_reg);
+ msm_hs_write(uport, UART_DM_IMR, msm_uport->imr_reg);
}
/*
* Complete both writes before starting new TX.
@@ -1948,7 +2050,7 @@
if (isr_status & UARTDM_ISR_TXLEV_BMSK) {
/* TX FIFO is empty */
msm_uport->imr_reg &= ~UARTDM_ISR_TXLEV_BMSK;
- msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg);
+ msm_hs_write(uport, UART_DM_IMR, msm_uport->imr_reg);
/*
* Complete device write before starting clock_off request.
* Hence mb() requires here.
@@ -1992,7 +2094,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_ADDR, msm_uport->imr_reg);
+ msm_hs_write(uport, UARTDM_IMR, msm_uport->imr_reg);
/*
* Complete device write before retuning back.
* Hence mb() requires here.
@@ -2020,37 +2122,25 @@
disable_irq_nosync(msm_uport->wakeup.irq);
spin_unlock_irqrestore(&uport->lock, flags);
- /* Vote for PNOC BUS Scaling */
- msm_hs_bus_voting(msm_uport, BUS_SCALING);
-
- ret = clk_prepare_enable(msm_uport->clk);
+ ret = msm_hs_clock_vote(msm_uport);
if (ret) {
dev_err(uport->dev, "Clock ON Failure"
"For UART CLK Stalling HSUART\n");
break;
}
- if (msm_uport->pclk) {
- ret = clk_prepare_enable(msm_uport->pclk);
- if (unlikely(ret)) {
- clk_disable_unprepare(msm_uport->clk);
- dev_err(uport->dev, "Clock ON Failure"
- "For UART Pclk Stalling HSUART\n");
- break;
- }
- }
spin_lock_irqsave(&uport->lock, flags);
/* else fall-through */
case MSM_HS_CLK_REQUEST_OFF:
if (msm_uport->rx.flush == FLUSH_STOP ||
msm_uport->rx.flush == FLUSH_SHUTDOWN) {
- msm_hs_write(uport, UARTDM_CR_ADDR, RESET_RX);
- data = msm_hs_read(uport, UARTDM_DMEN_ADDR);
+ msm_hs_write(uport, UART_DM_CR, RESET_RX);
+ data = msm_hs_read(uport, UART_DM_DMEN);
if (is_blsp_uart(msm_uport))
data |= UARTDM_RX_BAM_ENABLE_BMSK;
else
data |= UARTDM_RX_DM_EN_BMSK;
- msm_hs_write(uport, UARTDM_DMEN_ADDR, data);
+ msm_hs_write(uport, UART_DM_DMEN, data);
/* Complete above device write. Hence mb() here. */
mb();
}
@@ -2279,18 +2369,18 @@
}
/* Set auto RFR Level */
- data = msm_hs_read(uport, UARTDM_MR1_ADDR);
+ data = msm_hs_read(uport, UART_DM_MR1);
data &= ~UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK;
data &= ~UARTDM_MR1_AUTO_RFR_LEVEL0_BMSK;
data |= (UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK & (rfr_level << 2));
data |= (UARTDM_MR1_AUTO_RFR_LEVEL0_BMSK & rfr_level);
- msm_hs_write(uport, UARTDM_MR1_ADDR, data);
+ msm_hs_write(uport, UART_DM_MR1, data);
/* Make sure RXSTALE count is non-zero */
- data = msm_hs_read(uport, UARTDM_IPR_ADDR);
+ data = msm_hs_read(uport, UART_DM_IPR);
if (!data) {
data |= 0x1f & UARTDM_IPR_STALE_LSB_BMSK;
- msm_hs_write(uport, UARTDM_IPR_ADDR, data);
+ msm_hs_write(uport, UART_DM_IPR, data);
}
if (is_blsp_uart(msm_uport)) {
@@ -2300,21 +2390,21 @@
/* Enable Data Mover Mode */
data = UARTDM_TX_DM_EN_BMSK | UARTDM_RX_DM_EN_BMSK;
}
- msm_hs_write(uport, UARTDM_DMEN_ADDR, data);
+ msm_hs_write(uport, UART_DM_DMEN, data);
/* Reset TX */
- msm_hs_write(uport, UARTDM_CR_ADDR, RESET_TX);
- msm_hs_write(uport, UARTDM_CR_ADDR, RESET_RX);
- msm_hs_write(uport, UARTDM_CR_ADDR, RESET_ERROR_STATUS);
- msm_hs_write(uport, UARTDM_CR_ADDR, RESET_BREAK_INT);
- msm_hs_write(uport, UARTDM_CR_ADDR, RESET_STALE_INT);
- msm_hs_write(uport, UARTDM_CR_ADDR, RESET_CTS);
- msm_hs_write(uport, UARTDM_CR_ADDR, RFR_LOW);
+ msm_hs_write(uport, UART_DM_CR, RESET_TX);
+ msm_hs_write(uport, UART_DM_CR, RESET_RX);
+ msm_hs_write(uport, UART_DM_CR, RESET_ERROR_STATUS);
+ msm_hs_write(uport, UART_DM_CR, RESET_BREAK_INT);
+ msm_hs_write(uport, UART_DM_CR, RESET_STALE_INT);
+ msm_hs_write(uport, UART_DM_CR, RESET_CTS);
+ msm_hs_write(uport, UART_DM_CR, RFR_LOW);
/* Turn on Uart Receiver */
- msm_hs_write(uport, UARTDM_CR_ADDR, UARTDM_CR_RX_EN_BMSK);
+ msm_hs_write(uport, UART_DM_CR, UARTDM_CR_RX_EN_BMSK);
/* Turn on Uart Transmitter */
- msm_hs_write(uport, UARTDM_CR_ADDR, UARTDM_CR_TX_EN_BMSK);
+ msm_hs_write(uport, UART_DM_CR, UARTDM_CR_TX_EN_BMSK);
/* Initialize the tx */
tx->tx_ready_int_en = 0;
@@ -2340,7 +2430,8 @@
/* Enable reading the current CTS, no harm even if CTS is ignored */
msm_uport->imr_reg |= UARTDM_ISR_CURRENT_CTS_BMSK;
- msm_hs_write(uport, UARTDM_TFWR_ADDR, 0); /* TXLEV on empty TX fifo */
+ /* TXLEV on empty TX fifo */
+ msm_hs_write(uport, UART_DM_TFWR, 0);
/*
* Complete all device write related configuration before
* queuing RX request. Hence mb() requires here.
@@ -2375,8 +2466,7 @@
disable_irq(msm_uport->wakeup.irq);
}
- /* Vote for PNOC BUS Scaling */
- msm_hs_bus_voting(msm_uport, BUS_SCALING);
+ msm_hs_clock_vote(msm_uport);
spin_lock_irqsave(&uport->lock, flags);
@@ -2384,6 +2474,8 @@
spin_unlock_irqrestore(&uport->lock, flags);
+ msm_hs_clock_unvote(msm_uport);
+
pm_runtime_enable(uport->dev);
return 0;
@@ -2403,9 +2495,7 @@
if (is_blsp_uart(msm_uport))
msm_hs_unconfig_uart_gpios(uport);
deinit_uart_clk:
- clk_disable_unprepare(msm_uport->clk);
- if (msm_uport->pclk)
- clk_disable_unprepare(msm_uport->pclk);
+ msm_hs_clock_unvote(msm_uport);
wake_unlock(&msm_uport->dma_wake_lock);
return ret;
@@ -2447,9 +2537,9 @@
/* Set up Uart Receive */
if (is_blsp_uart(msm_uport))
- msm_hs_write(uport, UARTDM_RFWR_ADDR, 32);
+ msm_hs_write(uport, UART_DM_RFWR, 32);
else
- msm_hs_write(uport, UARTDM_RFWR_ADDR, 0);
+ msm_hs_write(uport, UART_DM_RFWR, 0);
INIT_DELAYED_WORK(&rx->flip_insert_work, flip_insert_work);
@@ -2835,8 +2925,9 @@
struct resource *core_resource;
struct resource *bam_resource;
struct resource *resource;
- int core_irqres, bam_irqres;
+ int core_irqres, bam_irqres, wakeup_irqres;
struct msm_serial_hs_platform_data *pdata = pdev->dev.platform_data;
+ const struct of_device_id *match;
if (pdev->dev.of_node) {
dev_dbg(&pdev->dev, "device tree enabled\n");
@@ -2883,6 +2974,12 @@
uport = &msm_uport->uport;
uport->dev = &pdev->dev;
+ match = of_match_device(msm_hs_match_table, &pdev->dev);
+ if (match)
+ msm_uport->reg_ptr = (unsigned int *)match->data;
+ else if (is_gsbi_uart(msm_uport))
+ msm_uport->reg_ptr = regmap_nonblsp;
+
if (pdev->dev.of_node)
msm_uport->uart_type = BLSP_HSUART;
@@ -2894,6 +2991,7 @@
IORESOURCE_MEM, "bam_mem");
core_irqres = platform_get_irq_byname(pdev, "core_irq");
bam_irqres = platform_get_irq_byname(pdev, "bam_irq");
+ wakeup_irqres = platform_get_irq_byname(pdev, "wakeup_irq");
if (!core_resource) {
pr_err("Invalid core HSUART Resources.\n");
@@ -2913,6 +3011,8 @@
pr_err("Invalid bam irqres Resources.\n");
return -ENXIO;
}
+ if (!wakeup_irqres)
+ pr_debug("Wakeup irq not specified.\n");
uport->mapbase = core_resource->start;
@@ -2933,6 +3033,7 @@
uport->irq = core_irqres;
msm_uport->bam_irq = bam_irqres;
+ pdata->wakeup_irq = wakeup_irqres;
msm_uport->bus_scale_table = msm_bus_cl_get_pdata(pdev);
if (!msm_uport->bus_scale_table) {
@@ -3053,6 +3154,8 @@
INIT_WORK(&msm_uport->disconnect_rx_endpoint,
hsuart_disconnect_rx_endpoint_work);
mutex_init(&msm_uport->clk_mutex);
+ atomic_set(&msm_uport->clk_count, 0);
+
/* Initialize SPS HW connected with UART core */
if (is_blsp_uart(msm_uport)) {
@@ -3063,11 +3166,7 @@
}
}
- msm_hs_bus_voting(msm_uport, BUS_SCALING);
-
- clk_prepare_enable(msm_uport->clk);
- if (msm_uport->pclk)
- clk_prepare_enable(msm_uport->pclk);
+ msm_hs_clock_vote(msm_uport);
ret = uartdm_init_port(uport);
if (unlikely(ret)) {
@@ -3075,8 +3174,7 @@
}
/* configure the CR Protection to Enable */
- msm_hs_write(uport, UARTDM_CR_ADDR, CR_PROTECTION_EN);
-
+ msm_hs_write(uport, UART_DM_CR, CR_PROTECTION_EN);
/*
* Enable Command register protection before going ahead as this hw
@@ -3102,19 +3200,12 @@
uport->line = pdata->userid;
ret = uart_add_one_port(&msm_hs_driver, uport);
if (!ret) {
- msm_hs_bus_voting(msm_uport, BUS_RESET);
- clk_disable_unprepare(msm_uport->clk);
- if (msm_uport->pclk)
- clk_disable_unprepare(msm_uport->pclk);
+ msm_hs_clock_unvote(msm_uport);
return ret;
}
err_clock:
-
- msm_hs_bus_voting(msm_uport, BUS_RESET);
- clk_disable_unprepare(msm_uport->clk);
- if (msm_uport->pclk)
- clk_disable_unprepare(msm_uport->pclk);
+ msm_hs_clock_unvote(msm_uport);
destroy_mutex:
mutex_destroy(&msm_uport->clk_mutex);
@@ -3185,20 +3276,21 @@
struct msm_hs_tx *tx = &msm_uport->tx;
struct sps_pipe *sps_pipe_handle = tx->cons.pipe_handle;
+ msm_hs_clock_vote(msm_uport);
if (msm_uport->tx.dma_in_flight) {
if (!is_blsp_uart(msm_uport)) {
spin_lock_irqsave(&uport->lock, flags);
/* disable UART TX interface to DM */
- data = msm_hs_read(uport, UARTDM_DMEN_ADDR);
+ data = msm_hs_read(uport, UART_DM_DMEN);
data &= ~UARTDM_TX_DM_EN_BMSK;
- msm_hs_write(uport, UARTDM_DMEN_ADDR, data);
+ msm_hs_write(uport, UART_DM_DMEN, data);
/* turn OFF UART Transmitter */
- msm_hs_write(uport, UARTDM_CR_ADDR,
- UARTDM_CR_TX_DISABLE_BMSK);
+ msm_hs_write(uport, UART_DM_CR,
+ UARTDM_CR_TX_DISABLE_BMSK);
/* reset UART TX */
- msm_hs_write(uport, UARTDM_CR_ADDR, RESET_TX);
+ msm_hs_write(uport, UART_DM_CR, RESET_TX);
/* reset UART TX Error */
- msm_hs_write(uport, UARTDM_CR_ADDR, RESET_TX_ERROR);
+ msm_hs_write(uport, UART_DM_CR, RESET_TX_ERROR);
msm_uport->tx.flush = FLUSH_STOP;
spin_unlock_irqrestore(&uport->lock, flags);
/* discard flush */
@@ -3224,28 +3316,24 @@
pm_runtime_disable(uport->dev);
/* Disable the transmitter */
- msm_hs_write(uport, UARTDM_CR_ADDR, UARTDM_CR_TX_DISABLE_BMSK);
+ msm_hs_write(uport, UART_DM_CR, UARTDM_CR_TX_DISABLE_BMSK);
/* Disable the receiver */
- msm_hs_write(uport, UARTDM_CR_ADDR, UARTDM_CR_RX_DISABLE_BMSK);
+ msm_hs_write(uport, UART_DM_CR, UARTDM_CR_RX_DISABLE_BMSK);
msm_uport->imr_reg = 0;
- msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg);
+ msm_hs_write(uport, UART_DM_IMR, msm_uport->imr_reg);
/*
* Complete all device write before actually disabling uartclk.
* Hence mb() requires here.
*/
mb();
- /* Reset PNOC Bus Scaling */
- msm_hs_bus_voting(msm_uport, BUS_RESET);
-
if (msm_uport->clk_state != MSM_HS_CLK_OFF) {
/* to balance clk_state */
- clk_disable_unprepare(msm_uport->clk);
- if (msm_uport->pclk)
- clk_disable_unprepare(msm_uport->pclk);
+ msm_hs_clock_unvote(msm_uport);
wake_unlock(&msm_uport->dma_wake_lock);
}
+ msm_hs_clock_unvote(msm_uport);
msm_uport->clk_state = MSM_HS_CLK_PORT_OFF;
dma_unmap_single(uport->dev, msm_uport->tx.dma_base,
@@ -3309,10 +3397,6 @@
.runtime_idle = msm_hs_runtime_idle,
};
-static struct of_device_id msm_hs_match_table[] = {
- { .compatible = "qcom,msm-hsuart-v14" },
- {}
-};
static struct platform_driver msm_serial_hs_platform_driver = {
.probe = msm_hs_probe,
diff --git a/drivers/tty/serial/msm_serial_hs_hwreg.h b/drivers/tty/serial/msm_serial_hs_hwreg.h
index cd24f23..d912b9f 100644
--- a/drivers/tty/serial/msm_serial_hs_hwreg.h
+++ b/drivers/tty/serial/msm_serial_hs_hwreg.h
@@ -60,6 +60,30 @@
UARTDM_LAST,
};
+enum msm_hs_regs {
+ UART_DM_MR1,
+ UART_DM_MR2,
+ UART_DM_IMR,
+ UART_DM_SR,
+ UART_DM_CR,
+ UART_DM_CSR,
+ UART_DM_IPR,
+ UART_DM_ISR,
+ UART_DM_RX_TOTAL_SNAP,
+ UART_DM_RFWR,
+ UART_DM_TFWR,
+ UART_DM_RF,
+ UART_DM_TF,
+ UART_DM_MISR,
+ UART_DM_DMRX,
+ UART_DM_NCF_TX,
+ UART_DM_DMEN,
+ UART_DM_TXFS,
+ UART_DM_RXFS,
+ UART_DM_RX_TRANS_CTRL,
+ UART_DM_LAST,
+};
+
#define UARTDM_MR1_ADDR 0x0
#define UARTDM_MR2_ADDR 0x4
@@ -219,70 +243,6 @@
#define UARTDM_TX_BAM_ENABLE_BMSK 0x4
#define UARTDM_RX_BAM_ENABLE_BMSK 0x8
-/*
- * Some of the BLSP Based UART Core(v14) existing register offsets
- * are different compare to GSBI based UART Core(v13)
- * Hence add the changed register offsets for UART Core v14
- */
-#ifdef CONFIG_MSM_UARTDM_Core_v14
-
-/* write only register */
-#define UARTDM_CSR_ADDR 0xa0
-
-/* write only register */
-#define UARTDM_TF_ADDR 0x100
-#define UARTDM_TF2_ADDR 0x104
-#define UARTDM_TF3_ADDR 0x108
-#define UARTDM_TF4_ADDR 0x10c
-#define UARTDM_TF5_ADDR 0x110
-#define UARTDM_TF6_ADDR 0x114
-#define UARTDM_TF7_ADDR 0x118
-#define UARTDM_TF8_ADDR 0x11c
-#define UARTDM_TF9_ADDR 0x120
-#define UARTDM_TF10_ADDR 0x124
-#define UARTDM_TF11_ADDR 0x128
-#define UARTDM_TF12_ADDR 0x12c
-#define UARTDM_TF13_ADDR 0x130
-#define UARTDM_TF14_ADDR 0x134
-#define UARTDM_TF15_ADDR 0x138
-#define UARTDM_TF16_ADDR 0x13c
-
-/* write only register */
-#define UARTDM_CR_ADDR 0xa8
-/* write only register */
-#define UARTDM_IMR_ADDR 0xb0
-#define UARTDM_IRDA_ADDR 0xb8
-
-/* Read Only register */
-#define UARTDM_SR_ADDR 0xa4
-
-/* Read Only register */
-#define UARTDM_RF_ADDR 0x140
-#define UARTDM_RF2_ADDR 0x144
-#define UARTDM_RF3_ADDR 0x148
-#define UARTDM_RF4_ADDR 0x14c
-#define UARTDM_RF5_ADDR 0x150
-#define UARTDM_RF6_ADDR 0x154
-#define UARTDM_RF7_ADDR 0x158
-#define UARTDM_RF8_ADDR 0x15c
-#define UARTDM_RF9_ADDR 0x160
-#define UARTDM_RF10_ADDR 0x164
-#define UARTDM_RF11_ADDR 0x168
-#define UARTDM_RF12_ADDR 0x16c
-#define UARTDM_RF13_ADDR 0x170
-#define UARTDM_RF14_ADDR 0x174
-#define UARTDM_RF15_ADDR 0x178
-#define UARTDM_RF16_ADDR 0x17c
-
-/* Read Only register */
-#define UARTDM_MISR_ADDR 0xac
-
-/* Read Only register */
-#define UARTDM_ISR_ADDR 0xb4
-#define UARTDM_RX_TOTAL_SNAP_ADDR 0xbc
-
-#else
-
/* Register offsets for UART Core v13 */
/* write only register */
@@ -316,6 +276,4 @@
#define UARTDM_ISR_ADDR 0x14
#define UARTDM_RX_TOTAL_SNAP_ADDR 0x38
-#endif
-
#endif /* MSM_SERIAL_HS_HWREG_H */
diff --git a/drivers/tty/smux_test.c b/drivers/tty/smux_test.c
index 8d17674..130b65e 100644
--- a/drivers/tty/smux_test.c
+++ b/drivers/tty/smux_test.c
@@ -194,6 +194,8 @@
int event_high_wm;
int event_rx_retry_high_wm;
int event_rx_retry_low_wm;
+ int event_local_closed;
+ int event_remote_closed;
/* TIOCM changes */
int event_tiocm;
@@ -249,6 +251,8 @@
cb->event_high_wm = 0;
cb->event_rx_retry_high_wm = 0;
cb->event_rx_retry_low_wm = 0;
+ cb->event_local_closed = 0;
+ cb->event_remote_closed = 0;
cb->event_tiocm = 0;
cb->tiocm_meta.tiocm_old = 0;
cb->tiocm_meta.tiocm_new = 0;
@@ -311,6 +315,8 @@
"\tevent_high_wm=%d\n"
"\tevent_rx_retry_high_wm=%d\n"
"\tevent_rx_retry_low_wm=%d\n"
+ "\tevent_local_closed=%d\n"
+ "\tevent_remote_closed=%d\n"
"\tevent_tiocm=%d\n"
"\tevent_read_done=%d\n"
"\tevent_read_failed=%d\n"
@@ -329,6 +335,8 @@
cb->event_high_wm,
cb->event_rx_retry_high_wm,
cb->event_rx_retry_low_wm,
+ cb->event_local_closed,
+ cb->event_remote_closed,
cb->event_tiocm,
cb->event_read_done,
cb->event_read_failed,
@@ -467,6 +475,22 @@
spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
break;
+ case SMUX_LOCAL_CLOSED:
+ spin_lock_irqsave(&cb_data_ptr->lock, flags);
+ ++cb_data_ptr->event_local_closed;
+ cb_data_ptr->event_disconnected_ssr =
+ ((struct smux_meta_disconnected *)metadata)->is_ssr;
+ spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
+ break;
+
+ case SMUX_REMOTE_CLOSED:
+ spin_lock_irqsave(&cb_data_ptr->lock, flags);
+ ++cb_data_ptr->event_remote_closed;
+ cb_data_ptr->event_disconnected_ssr =
+ ((struct smux_meta_disconnected *)metadata)->is_ssr;
+ spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
+ break;
+
default:
pr_err("%s: unknown event %d\n", __func__, event);
};
@@ -609,13 +633,18 @@
/* close port */
ret = msm_smux_close(SMUX_TEST_LCID);
UT_ASSERT_INT(ret, ==, 0);
- UT_ASSERT_INT(
- (int)wait_for_completion_timeout(
- &cb_data.cb_completion, HZ),
- >, 0);
- UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+ while (cb_data.cb_count < 3) {
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion, HZ),
+ >, 0);
+ INIT_COMPLETION(cb_data.cb_completion);
+ }
+ UT_ASSERT_INT(cb_data.cb_count, ==, 3);
UT_ASSERT_INT(cb_data.event_disconnected, ==, 1);
UT_ASSERT_INT(cb_data.event_disconnected_ssr, ==, 0);
+ UT_ASSERT_INT(cb_data.event_local_closed, ==, 1);
+ UT_ASSERT_INT(cb_data.event_remote_closed, ==, 1);
break;
}
@@ -783,13 +812,18 @@
/* verify SSR events */
UT_ASSERT_INT(ret, ==, 0);
- UT_ASSERT_INT(
- (int)wait_for_completion_timeout(
- &cb_data.cb_completion, 5*HZ),
- >, 0);
- UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+ while (cb_data.cb_count < 3) {
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion, 10*HZ),
+ >, 0);
+ INIT_COMPLETION(cb_data.cb_completion);
+ }
+ UT_ASSERT_INT(cb_data.cb_count, ==, 3);
UT_ASSERT_INT(cb_data.event_disconnected, ==, 1);
UT_ASSERT_INT(cb_data.event_disconnected_ssr, ==, 1);
+ UT_ASSERT_INT(cb_data.event_local_closed, ==, 1);
+ UT_ASSERT_INT(cb_data.event_remote_closed, ==, 1);
mock_cb_data_reset(&cb_data);
/* close port */
@@ -894,6 +928,8 @@
break;
UT_ASSERT_INT(cb_data.event_disconnected, ==, 1);
UT_ASSERT_INT(cb_data.event_disconnected_ssr, ==, 1);
+ UT_ASSERT_INT(cb_data.event_local_closed, ==, 1);
+ UT_ASSERT_INT(cb_data.event_remote_closed, ==, 1);
mock_cb_data_reset(&cb_data);
/* close port */
@@ -1272,13 +1308,18 @@
/* close port */
ret = msm_smux_close(SMUX_TEST_LCID);
UT_ASSERT_INT(ret, ==, 0);
- UT_ASSERT_INT(
- (int)wait_for_completion_timeout(
- &cb_data.cb_completion, HZ),
- >, 0);
- UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+ while (cb_data.cb_count < 3) {
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion, HZ),
+ >, 0);
+ INIT_COMPLETION(cb_data.cb_completion);
+ }
+ UT_ASSERT_INT(cb_data.cb_count, ==, 3);
UT_ASSERT_INT(cb_data.event_disconnected, ==, 1);
UT_ASSERT_INT(cb_data.event_disconnected_ssr, ==, 0);
+ UT_ASSERT_INT(cb_data.event_local_closed, ==, 1);
+ UT_ASSERT_INT(cb_data.event_remote_closed, ==, 1);
break;
}
@@ -1442,13 +1483,18 @@
/* close port */
ret = msm_smux_close(SMUX_TEST_LCID);
UT_ASSERT_INT(ret, ==, 0);
- UT_ASSERT_INT(
- (int)wait_for_completion_timeout(
- &cb_data.cb_completion, HZ),
- >, 0);
- UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+ while (cb_data.cb_count < 3) {
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion, HZ),
+ >, 0);
+ INIT_COMPLETION(cb_data.cb_completion);
+ }
+ UT_ASSERT_INT(cb_data.cb_count, ==, 3);
UT_ASSERT_INT(cb_data.event_disconnected, ==, 1);
UT_ASSERT_INT(cb_data.event_disconnected_ssr, ==, 0);
+ UT_ASSERT_INT(cb_data.event_local_closed, ==, 1);
+ UT_ASSERT_INT(cb_data.event_remote_closed, ==, 1);
break;
}
@@ -1552,13 +1598,18 @@
/* close port */
ret = msm_smux_close(SMUX_TEST_LCID);
UT_ASSERT_INT(ret, ==, 0);
- UT_ASSERT_INT(
- (int)wait_for_completion_timeout(
- &cb_data.cb_completion, HZ),
- >, 0);
- UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+ while (cb_data.cb_count < 3) {
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion, HZ),
+ >, 0);
+ INIT_COMPLETION(cb_data.cb_completion);
+ }
+ UT_ASSERT_INT(cb_data.cb_count, ==, 3);
UT_ASSERT_INT(cb_data.event_disconnected, ==, 1);
UT_ASSERT_INT(cb_data.event_disconnected_ssr, ==, 0);
+ UT_ASSERT_INT(cb_data.event_local_closed, ==, 1);
+ UT_ASSERT_INT(cb_data.event_remote_closed, ==, 1);
break;
}
@@ -1884,13 +1935,18 @@
/* close port */
ret = msm_smux_close(SMUX_TEST_LCID);
UT_ASSERT_INT(ret, ==, 0);
- UT_ASSERT_INT(
- (int)wait_for_completion_timeout(
- &cb_data.cb_completion, HZ),
- >, 0);
- UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+ while (cb_data.cb_count < 3) {
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion, HZ),
+ >, 0);
+ INIT_COMPLETION(cb_data.cb_completion);
+ }
+ UT_ASSERT_INT(cb_data.cb_count, ==, 3);
UT_ASSERT_INT(cb_data.event_disconnected, ==, 1);
UT_ASSERT_INT(cb_data.event_disconnected_ssr, ==, 0);
+ UT_ASSERT_INT(cb_data.event_local_closed, ==, 1);
+ UT_ASSERT_INT(cb_data.event_remote_closed, ==, 1);
break;
}
@@ -2010,13 +2066,18 @@
/* close port */
ret = msm_smux_close(SMUX_TEST_LCID);
UT_ASSERT_INT(ret, ==, 0);
- UT_ASSERT_INT(
- (int)wait_for_completion_timeout(
- &cb_data.cb_completion, HZ),
- >, 0);
- UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+ while (cb_data.cb_count < 3) {
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion, HZ),
+ >, 0);
+ INIT_COMPLETION(cb_data.cb_completion);
+ }
+ UT_ASSERT_INT(cb_data.cb_count, ==, 3);
UT_ASSERT_INT(cb_data.event_disconnected, ==, 1);
UT_ASSERT_INT(cb_data.event_disconnected_ssr, ==, 0);
+ UT_ASSERT_INT(cb_data.event_local_closed, ==, 1);
+ UT_ASSERT_INT(cb_data.event_remote_closed, ==, 1);
break;
}
@@ -2139,13 +2200,18 @@
/* close port */
ret = msm_smux_close(SMUX_TEST_LCID);
UT_ASSERT_INT(ret, ==, 0);
- UT_ASSERT_INT(
- (int)wait_for_completion_timeout(
- &cb_data.cb_completion, HZ),
- >, 0);
- UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+ while (cb_data.cb_count < 3) {
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion, HZ),
+ >, 0);
+ INIT_COMPLETION(cb_data.cb_completion);
+ }
+ UT_ASSERT_INT(cb_data.cb_count, ==, 3);
UT_ASSERT_INT(cb_data.event_disconnected, ==, 1);
UT_ASSERT_INT(cb_data.event_disconnected_ssr, ==, 0);
+ UT_ASSERT_INT(cb_data.event_local_closed, ==, 1);
+ UT_ASSERT_INT(cb_data.event_remote_closed, ==, 1);
break;
}
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index bb2879b..db6fec9 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -264,7 +264,7 @@
*
* Returns 0 on success otherwise negative errno.
*/
-static int dwc3_event_buffers_setup(struct dwc3 *dwc)
+int dwc3_event_buffers_setup(struct dwc3 *dwc)
{
struct dwc3_event_buffer *evt;
int n;
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 5db7420..2064c13 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -920,6 +920,7 @@
void dwc3_gadget_restart(struct dwc3 *dwc);
void dwc3_post_host_reset_core_init(struct dwc3 *dwc);
+int dwc3_event_buffers_setup(struct dwc3 *dwc);
extern int dwc3_get_device_id(void);
extern void dwc3_put_device_id(int id);
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index a5f586b..c89f6d8 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -34,7 +34,9 @@
#include <linux/usb/gadget.h>
#include <linux/qpnp-misc.h>
#include <linux/usb/msm_hsusb.h>
+#include <linux/usb/msm_ext_chg.h>
#include <linux/regulator/consumer.h>
+#include <linux/pm_wakeup.h>
#include <linux/power_supply.h>
#include <linux/qpnp/qpnp-adc.h>
#include <linux/cdev.h>
@@ -165,7 +167,7 @@
struct dwc3_msm {
struct device *dev;
void __iomem *base;
- u32 resource_size;
+ struct resource *io_res;
int dbm_num_eps;
u8 ep_num_mapping[DBM_MAX_EPS];
const struct usb_ep_ops *original_ep_ops[DWC3_ENDPOINTS_NUM];
@@ -182,6 +184,7 @@
struct regulator *hsusb_vddcx;
struct regulator *ssusb_1p8;
struct regulator *ssusb_vddcx;
+ struct regulator *dwc3_gdsc;
/* VBUS regulator if no OTG and running in host only mode */
struct regulator *vbus_otg;
@@ -194,7 +197,6 @@
bool lpm_irq_seen;
struct delayed_work resume_work;
struct work_struct restart_usb_work;
- struct wake_lock wlock;
struct dwc3_charger charger;
struct usb_phy *otg_xceiv;
struct delayed_work chg_work;
@@ -211,6 +213,7 @@
struct power_supply *ext_vbus_psy;
unsigned int online;
unsigned int host_mode;
+ unsigned int voltage_max;
unsigned int current_max;
unsigned int vdd_no_vol_level;
unsigned int vdd_low_vol_level;
@@ -244,8 +247,6 @@
#define USB_SSPHY_1P8_VOL_MAX 1800000 /* uV */
#define USB_SSPHY_1P8_HPM_LOAD 23000 /* uA */
-static struct dwc3_msm *context;
-
static struct usb_ext_notification *usb_ext;
/**
@@ -341,8 +342,8 @@
tmp &= mask; /* clear other bits */
if (tmp != val)
- dev_err(context->dev, "%s: write: %x to QSCRATCH: %x FAILED\n",
- __func__, val, offset);
+ pr_err("%s: write: %x to QSCRATCH: %x FAILED\n",
+ __func__, val, offset);
}
/**
@@ -411,12 +412,12 @@
* Return DBM EP number according to usb endpoint number.
*
*/
-static int dwc3_msm_find_matching_dbm_ep(u8 usb_ep)
+static int dwc3_msm_find_matching_dbm_ep(struct dwc3_msm *mdwc, u8 usb_ep)
{
int i;
- for (i = 0; i < context->dbm_num_eps; i++)
- if (context->ep_num_mapping[i] == usb_ep)
+ for (i = 0; i < mdwc->dbm_num_eps; i++)
+ if (mdwc->ep_num_mapping[i] == usb_ep)
return i;
return -ENODEV; /* Not found */
@@ -426,13 +427,13 @@
* Return number of configured DBM endpoints.
*
*/
-static int dwc3_msm_configured_dbm_ep_num(void)
+static int dwc3_msm_configured_dbm_ep_num(struct dwc3_msm *mdwc)
{
int i;
int count = 0;
- for (i = 0; i < context->dbm_num_eps; i++)
- if (context->ep_num_mapping[i])
+ for (i = 0; i < mdwc->dbm_num_eps; i++)
+ if (mdwc->ep_num_mapping[i])
count++;
return count;
@@ -446,12 +447,13 @@
* @size - size of the event buffer.
*
*/
-static int dwc3_msm_event_buffer_config(u32 addr, u16 size)
+static int dwc3_msm_event_buffer_config(struct dwc3_msm *mdwc,
+ u32 addr, u16 size)
{
- dev_dbg(context->dev, "%s\n", __func__);
+ dev_dbg(mdwc->dev, "%s\n", __func__);
- dwc3_msm_write_reg(context->base, DBM_GEVNTADR, addr);
- dwc3_msm_write_reg_field(context->base, DBM_GEVNTSIZ,
+ dwc3_msm_write_reg(mdwc->base, DBM_GEVNTADR, addr);
+ dwc3_msm_write_reg_field(mdwc->base, DBM_GEVNTSIZ,
DBM_GEVNTSIZ_MASK, size);
return 0;
@@ -461,19 +463,19 @@
* Reset the DBM registers upon initialization.
*
*/
-static int dwc3_msm_dbm_soft_reset(int enter_reset)
+static int dwc3_msm_dbm_soft_reset(struct dwc3_msm *mdwc, int enter_reset)
{
- dev_dbg(context->dev, "%s\n", __func__);
+ dev_dbg(mdwc->dev, "%s\n", __func__);
if (enter_reset) {
- dev_dbg(context->dev, "enter DBM reset\n");
- dwc3_msm_write_reg_field(context->base, DBM_SOFT_RESET,
+ dev_dbg(mdwc->dev, "enter DBM reset\n");
+ dwc3_msm_write_reg_field(mdwc->base, DBM_SOFT_RESET,
DBM_SFT_RST_MASK, 1);
} else {
- dev_dbg(context->dev, "exit DBM reset\n");
- dwc3_msm_write_reg_field(context->base, DBM_SOFT_RESET,
+ dev_dbg(mdwc->dev, "exit DBM reset\n");
+ dwc3_msm_write_reg_field(mdwc->base, DBM_SOFT_RESET,
DBM_SFT_RST_MASK, 0);
/*enable DBM*/
- dwc3_msm_write_reg_field(context->base, QSCRATCH_GENERAL_CFG,
+ dwc3_msm_write_reg_field(mdwc->base, QSCRATCH_GENERAL_CFG,
DBM_EN_MASK, 0x1);
}
@@ -490,21 +492,21 @@
* @enter_reset - should we enter a reset state or get out of it.
*
*/
-static int dwc3_msm_dbm_ep_soft_reset(u8 dbm_ep, bool enter_reset)
+static int dwc3_msm_dbm_ep_soft_reset(struct dwc3_msm *mdwc,
+ u8 dbm_ep, bool enter_reset)
{
- dev_dbg(context->dev, "%s\n", __func__);
+ dev_dbg(mdwc->dev, "%s\n", __func__);
- if (dbm_ep >= context->dbm_num_eps) {
- dev_err(context->dev,
- "%s: Invalid DBM ep index\n", __func__);
+ if (dbm_ep >= mdwc->dbm_num_eps) {
+ dev_err(mdwc->dev, "%s: Invalid DBM ep index\n", __func__);
return -ENODEV;
}
if (enter_reset) {
- dwc3_msm_write_reg_field(context->base, DBM_SOFT_RESET,
+ dwc3_msm_write_reg_field(mdwc->base, DBM_SOFT_RESET,
DBM_SFT_RST_EPS_MASK & 1 << dbm_ep, 1);
} else {
- dwc3_msm_write_reg_field(context->base, DBM_SOFT_RESET,
+ dwc3_msm_write_reg_field(mdwc->base, DBM_SOFT_RESET,
DBM_SFT_RST_EPS_MASK & 1 << dbm_ep, 0);
}
@@ -523,43 +525,43 @@
*
* @return int - DBM ep number.
*/
-static int dwc3_msm_dbm_ep_config(u8 usb_ep, u8 bam_pipe,
+static int dwc3_msm_dbm_ep_config(struct dwc3_msm *mdwc, u8 usb_ep, u8 bam_pipe,
bool producer, bool disable_wb,
bool internal_mem, bool ioc)
{
u8 dbm_ep;
u32 ep_cfg;
- dev_dbg(context->dev, "%s\n", __func__);
+ dev_dbg(mdwc->dev, "%s\n", __func__);
- dbm_ep = dwc3_msm_find_matching_dbm_ep(usb_ep);
+ dbm_ep = dwc3_msm_find_matching_dbm_ep(mdwc, usb_ep);
if (dbm_ep < 0) {
- dev_err(context->dev,
+ dev_err(mdwc->dev,
"%s: Invalid usb ep index\n", __func__);
return -ENODEV;
}
/* First, reset the dbm endpoint */
- dwc3_msm_dbm_ep_soft_reset(dbm_ep, 0);
+ dwc3_msm_dbm_ep_soft_reset(mdwc, dbm_ep, 0);
/* Set ioc bit for dbm_ep if needed */
- dwc3_msm_write_reg_field(context->base, DBM_DBG_CNFG,
+ dwc3_msm_write_reg_field(mdwc->base, DBM_DBG_CNFG,
DBM_ENABLE_IOC_MASK & 1 << dbm_ep, ioc ? 1 : 0);
ep_cfg = (producer ? DBM_PRODUCER : 0) |
(disable_wb ? DBM_DISABLE_WB : 0) |
(internal_mem ? DBM_INT_RAM_ACC : 0);
- dwc3_msm_write_reg_field(context->base, DBM_EP_CFG(dbm_ep),
+ dwc3_msm_write_reg_field(mdwc->base, DBM_EP_CFG(dbm_ep),
DBM_PRODUCER | DBM_DISABLE_WB | DBM_INT_RAM_ACC, ep_cfg >> 8);
- dwc3_msm_write_reg_field(context->base, DBM_EP_CFG(dbm_ep), USB3_EPNUM,
+ dwc3_msm_write_reg_field(mdwc->base, DBM_EP_CFG(dbm_ep), USB3_EPNUM,
usb_ep);
- dwc3_msm_write_reg_field(context->base, DBM_EP_CFG(dbm_ep),
+ dwc3_msm_write_reg_field(mdwc->base, DBM_EP_CFG(dbm_ep),
DBM_BAM_PIPE_NUM, bam_pipe);
- dwc3_msm_write_reg_field(context->base, DBM_PIPE_CFG, 0x000000ff,
+ dwc3_msm_write_reg_field(mdwc->base, DBM_PIPE_CFG, 0x000000ff,
0xe4);
- dwc3_msm_write_reg_field(context->base, DBM_EP_CFG(dbm_ep), DBM_EN_EP,
+ dwc3_msm_write_reg_field(mdwc->base, DBM_EP_CFG(dbm_ep), DBM_EN_EP,
1);
return dbm_ep;
@@ -571,35 +573,34 @@
* @usb_ep - USB ep number.
*
*/
-static int dwc3_msm_dbm_ep_unconfig(u8 usb_ep)
+static int dwc3_msm_dbm_ep_unconfig(struct dwc3_msm *mdwc, u8 usb_ep)
{
u8 dbm_ep;
u32 data;
- dev_dbg(context->dev, "%s\n", __func__);
+ dev_dbg(mdwc->dev, "%s\n", __func__);
- dbm_ep = dwc3_msm_find_matching_dbm_ep(usb_ep);
+ dbm_ep = dwc3_msm_find_matching_dbm_ep(mdwc, usb_ep);
if (dbm_ep < 0) {
- dev_err(context->dev,
- "%s: Invalid usb ep index\n", __func__);
+ dev_err(mdwc->dev, "%s: Invalid usb ep index\n", __func__);
return -ENODEV;
}
- context->ep_num_mapping[dbm_ep] = 0;
+ mdwc->ep_num_mapping[dbm_ep] = 0;
- data = dwc3_msm_read_reg(context->base, DBM_EP_CFG(dbm_ep));
+ data = dwc3_msm_read_reg(mdwc->base, DBM_EP_CFG(dbm_ep));
data &= (~0x1);
- dwc3_msm_write_reg(context->base, DBM_EP_CFG(dbm_ep), data);
+ dwc3_msm_write_reg(mdwc->base, DBM_EP_CFG(dbm_ep), data);
/* Reset the dbm endpoint */
- dwc3_msm_dbm_ep_soft_reset(dbm_ep, true);
+ dwc3_msm_dbm_ep_soft_reset(mdwc, dbm_ep, true);
/*
* 10 usec delay is required before deasserting DBM endpoint reset
* according to hardware programming guide.
*/
udelay(10);
- dwc3_msm_dbm_ep_soft_reset(dbm_ep, false);
+ dwc3_msm_dbm_ep_soft_reset(mdwc, dbm_ep, false);
return 0;
}
@@ -618,15 +619,17 @@
{
u8 dbm_ep;
struct dwc3_ep *dep = to_dwc3_ep(ep);
+ struct dwc3 *dwc = dep->dwc;
+ struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
u8 bam_pipe = dst_pipe_idx;
- dev_dbg(context->dev, "%s\n", __func__);
+ dev_dbg(mdwc->dev, "%s\n", __func__);
dbm_ep = bam_pipe;
- context->ep_num_mapping[dbm_ep] = dep->number;
+ mdwc->ep_num_mapping[dbm_ep] = dep->number;
- dwc3_msm_write_reg(context->base, DBM_DATA_FIFO(dbm_ep), addr);
- dwc3_msm_write_reg_field(context->base, DBM_DATA_FIFO_SIZE(dbm_ep),
+ dwc3_msm_write_reg(mdwc->base, DBM_DATA_FIFO(dbm_ep), addr);
+ dwc3_msm_write_reg_field(mdwc->base, DBM_DATA_FIFO_SIZE(dbm_ep),
DBM_DATA_FIFO_SIZE_MASK, size);
return 0;
@@ -646,12 +649,12 @@
struct usb_request *request)
{
struct dwc3_ep *dep = to_dwc3_ep(ep);
+ struct dwc3 *dwc = dep->dwc;
+ struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
struct dwc3_msm_req_complete *req_complete = NULL;
/* Find original request complete function and remove it from list */
- list_for_each_entry(req_complete,
- &context->req_complete_list,
- list_item) {
+ list_for_each_entry(req_complete, &mdwc->req_complete_list, list_item) {
if (req_complete->req == request)
break;
}
@@ -670,14 +673,14 @@
dep->busy_slot++;
/* Unconfigure dbm ep */
- dwc3_msm_dbm_ep_unconfig(dep->number);
+ dwc3_msm_dbm_ep_unconfig(mdwc, dep->number);
/*
* If this is the last endpoint we unconfigured, than reset also
* the event buffers.
*/
- if (0 == dwc3_msm_configured_dbm_ep_num())
- dwc3_msm_event_buffer_config(0, 0);
+ if (0 == dwc3_msm_configured_dbm_ep_num(mdwc))
+ dwc3_msm_event_buffer_config(mdwc, 0, 0);
/*
* Call original complete function, notice that dwc->lock is already
@@ -790,6 +793,7 @@
struct dwc3_request *req = to_dwc3_request(request);
struct dwc3_ep *dep = to_dwc3_ep(ep);
struct dwc3 *dwc = dep->dwc;
+ struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
struct dwc3_msm_req_complete *req_complete;
unsigned long flags;
int ret = 0;
@@ -802,23 +806,23 @@
if (!(request->udc_priv & MSM_SPS_MODE)) {
/* Not SPS mode, call original queue */
- dev_vdbg(dwc->dev, "%s: not sps mode, use regular queue\n",
+ dev_vdbg(mdwc->dev, "%s: not sps mode, use regular queue\n",
__func__);
- return (context->original_ep_ops[dep->number])->queue(ep,
+ return (mdwc->original_ep_ops[dep->number])->queue(ep,
request,
gfp_flags);
}
if (!dep->endpoint.desc) {
- dev_err(dwc->dev,
+ dev_err(mdwc->dev,
"%s: trying to queue request %p to disabled ep %s\n",
__func__, request, ep->name);
return -EPERM;
}
if (dep->number == 0 || dep->number == 1) {
- dev_err(dwc->dev,
+ dev_err(mdwc->dev,
"%s: trying to queue dbm request %p to control ep %s\n",
__func__, request, ep->name);
return -EPERM;
@@ -827,7 +831,7 @@
if (dep->busy_slot != dep->free_slot || !list_empty(&dep->request_list)
|| !list_empty(&dep->req_queued)) {
- dev_err(dwc->dev,
+ dev_err(mdwc->dev,
"%s: trying to queue dbm request %p tp ep %s\n",
__func__, request, ep->name);
return -EPERM;
@@ -842,12 +846,12 @@
*/
req_complete = kzalloc(sizeof(*req_complete), GFP_KERNEL);
if (!req_complete) {
- dev_err(dep->dwc->dev, "%s: not enough memory\n", __func__);
+ dev_err(mdwc->dev, "%s: not enough memory\n", __func__);
return -ENOMEM;
}
req_complete->req = request;
req_complete->orig_complete = request->complete;
- list_add_tail(&req_complete->list_item, &context->req_complete_list);
+ list_add_tail(&req_complete->list_item, &mdwc->req_complete_list);
request->complete = dwc3_msm_req_complete_func;
/*
@@ -859,11 +863,11 @@
internal_mem = ((request->udc_priv & MSM_INTERNAL_MEM) ? true : false);
ioc = ((request->udc_priv & MSM_ETD_IOC) ? true : false);
- ret = dwc3_msm_dbm_ep_config(dep->number,
+ ret = dwc3_msm_dbm_ep_config(mdwc, dep->number,
bam_pipe, producer,
disable_wb, internal_mem, ioc);
if (ret < 0) {
- dev_err(context->dev,
+ dev_err(mdwc->dev,
"error %d after calling dwc3_msm_dbm_ep_config\n",
ret);
return ret;
@@ -883,13 +887,13 @@
ret = __dwc3_msm_ep_queue(dep, req);
spin_unlock_irqrestore(&dwc->lock, flags);
if (ret < 0) {
- dev_err(context->dev,
+ dev_err(mdwc->dev,
"error %d after calling __dwc3_msm_ep_queue\n", ret);
return ret;
}
speed = dwc3_readl(dwc->regs, DWC3_DSTS) & DWC3_DSTS_CONNECTSPD;
- dwc3_msm_write_reg(context->base, DBM_GEN_CFG, speed >> 2);
+ dwc3_msm_write_reg(mdwc->base, DBM_GEN_CFG, speed >> 2);
return 0;
}
@@ -911,25 +915,27 @@
int msm_ep_config(struct usb_ep *ep)
{
struct dwc3_ep *dep = to_dwc3_ep(ep);
+ struct dwc3 *dwc = dep->dwc;
+ struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
struct usb_ep_ops *new_ep_ops;
- dwc3_msm_event_buffer_config(dwc3_msm_read_reg(context->base,
- DWC3_GEVNTADRLO(0)),
- dwc3_msm_read_reg(context->base, DWC3_GEVNTSIZ(0)));
+ dwc3_msm_event_buffer_config(mdwc,
+ dwc3_msm_read_reg(mdwc->base, DWC3_GEVNTADRLO(0)),
+ dwc3_msm_read_reg(mdwc->base, DWC3_GEVNTSIZ(0)));
/* Save original ep ops for future restore*/
- if (context->original_ep_ops[dep->number]) {
- dev_err(context->dev,
+ if (mdwc->original_ep_ops[dep->number]) {
+ dev_err(mdwc->dev,
"ep [%s,%d] already configured as msm endpoint\n",
ep->name, dep->number);
return -EPERM;
}
- context->original_ep_ops[dep->number] = ep->ops;
+ mdwc->original_ep_ops[dep->number] = ep->ops;
/* Set new usb ops as we like */
new_ep_ops = kzalloc(sizeof(struct usb_ep_ops), GFP_KERNEL);
if (!new_ep_ops) {
- dev_err(context->dev,
+ dev_err(mdwc->dev,
"%s: unable to allocate mem for new usb ep ops\n",
__func__);
return -ENOMEM;
@@ -961,18 +967,20 @@
int msm_ep_unconfig(struct usb_ep *ep)
{
struct dwc3_ep *dep = to_dwc3_ep(ep);
+ struct dwc3 *dwc = dep->dwc;
+ struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
struct usb_ep_ops *old_ep_ops;
/* Restore original ep ops */
- if (!context->original_ep_ops[dep->number]) {
- dev_err(context->dev,
+ if (!mdwc->original_ep_ops[dep->number]) {
+ dev_err(mdwc->dev,
"ep [%s,%d] was not configured as msm endpoint\n",
ep->name, dep->number);
return -EINVAL;
}
old_ep_ops = (struct usb_ep_ops *)ep->ops;
- ep->ops = context->original_ep_ops[dep->number];
- context->original_ep_ops[dep->number] = NULL;
+ ep->ops = mdwc->original_ep_ops[dep->number];
+ mdwc->original_ep_ops[dep->number] = NULL;
kfree(old_ep_ops);
/*
@@ -1017,14 +1025,16 @@
* This performs full hardware reset and re-initialization which
* might be required by some DBM client driver during uninit/cleanup.
*/
-void msm_dwc3_restart_usb_session(void)
+void msm_dwc3_restart_usb_session(struct usb_gadget *gadget)
{
- struct dwc3_msm *mdwc = context;
+ struct dwc3 *dwc = container_of(gadget, struct dwc3, gadget);
+ struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
+
+ if (mdwc)
+ return;
dev_dbg(mdwc->dev, "%s\n", __func__);
queue_work(system_nrt_wq, &mdwc->restart_usb_work);
-
- return;
}
EXPORT_SYMBOL(msm_dwc3_restart_usb_session);
@@ -1056,10 +1066,9 @@
EXPORT_SYMBOL(msm_register_usb_ext_notification);
/* HSPHY */
-static int dwc3_hsusb_config_vddcx(int high)
+static int dwc3_hsusb_config_vddcx(struct dwc3_msm *dwc, int high)
{
int min_vol, max_vol, ret;
- struct dwc3_msm *dwc = context;
max_vol = dwc->vdd_high_vol_level;
min_vol = high ? dwc->vdd_low_vol_level : dwc->vdd_no_vol_level;
@@ -1075,10 +1084,9 @@
return ret;
}
-static int dwc3_hsusb_ldo_init(int init)
+static int dwc3_hsusb_ldo_init(struct dwc3_msm *dwc, int init)
{
int rc = 0;
- struct dwc3_msm *dwc = context;
if (!init) {
regulator_set_voltage(dwc->hsusb_1p8, 0, USB_HSPHY_1P8_VOL_MAX);
@@ -1119,10 +1127,9 @@
return rc;
}
-static int dwc3_hsusb_ldo_enable(int on)
+static int dwc3_hsusb_ldo_enable(struct dwc3_msm *dwc, int on)
{
int rc = 0;
- struct dwc3_msm *dwc = context;
dev_dbg(dwc->dev, "reg (%s)\n", on ? "HPM" : "LPM");
@@ -1180,10 +1187,9 @@
}
/* SSPHY */
-static int dwc3_ssusb_config_vddcx(int high)
+static int dwc3_ssusb_config_vddcx(struct dwc3_msm *dwc, int high)
{
int min_vol, max_vol, ret;
- struct dwc3_msm *dwc = context;
max_vol = dwc->vdd_high_vol_level;
min_vol = high ? dwc->vdd_low_vol_level : dwc->vdd_no_vol_level;
@@ -1199,10 +1205,9 @@
}
/* 3.3v supply not needed for SS PHY */
-static int dwc3_ssusb_ldo_init(int init)
+static int dwc3_ssusb_ldo_init(struct dwc3_msm *dwc, int init)
{
int rc = 0;
- struct dwc3_msm *dwc = context;
if (!init) {
regulator_set_voltage(dwc->ssusb_1p8, 0, USB_SSPHY_1P8_VOL_MAX);
@@ -1222,12 +1227,11 @@
return rc;
}
-static int dwc3_ssusb_ldo_enable(int on)
+static int dwc3_ssusb_ldo_enable(struct dwc3_msm *dwc, int on)
{
int rc = 0;
- struct dwc3_msm *dwc = context;
- dev_dbg(context->dev, "reg (%s)\n", on ? "HPM" : "LPM");
+ dev_dbg(dwc->dev, "reg (%s)\n", on ? "HPM" : "LPM");
if (!on)
goto disable_regulators;
@@ -1260,10 +1264,40 @@
return rc < 0 ? rc : 0;
}
-static int dwc3_msm_link_clk_reset(bool assert)
+/*
+ * Config Global Distributed Switch Controller (GDSC)
+ * to support controller power collapse
+ */
+static int dwc3_msm_config_gdsc(struct dwc3_msm *mdwc, int on)
{
int ret = 0;
- struct dwc3_msm *mdwc = context;
+
+ if (IS_ERR(mdwc->dwc3_gdsc))
+ return 0;
+
+ if (!mdwc->dwc3_gdsc) {
+ mdwc->dwc3_gdsc = devm_regulator_get(mdwc->dev,
+ "USB3_GDSC");
+ if (IS_ERR(mdwc->dwc3_gdsc))
+ return 0;
+ }
+
+ if (on) {
+ ret = regulator_enable(mdwc->dwc3_gdsc);
+ if (ret) {
+ dev_err(mdwc->dev, "unable to enable usb3 gdsc\n");
+ return ret;
+ }
+ } else {
+ regulator_disable(mdwc->dwc3_gdsc);
+ }
+
+ return 0;
+}
+
+static int dwc3_msm_link_clk_reset(struct dwc3_msm *mdwc, bool assert)
+{
+ int ret = 0;
if (assert) {
/* Using asynchronous block reset to the hardware */
@@ -1289,7 +1323,7 @@
}
/* Reinitialize SSPHY parameters by overriding using QSCRATCH CR interface */
-static void dwc3_msm_ss_phy_reg_init(struct dwc3_msm *msm)
+static void dwc3_msm_ss_phy_reg_init(struct dwc3_msm *mdwc)
{
u32 data = 0;
@@ -1298,14 +1332,14 @@
* in HS mode instead of SS mode. Workaround it by asserting
* LANE0.TX_ALT_BLOCK.EN_ALT_BUS to enable TX to use alt bus mode
*/
- data = dwc3_msm_ssusb_read_phycreg(msm->base, 0x102D);
+ data = dwc3_msm_ssusb_read_phycreg(mdwc->base, 0x102D);
data |= (1 << 7);
- dwc3_msm_ssusb_write_phycreg(msm->base, 0x102D, data);
+ dwc3_msm_ssusb_write_phycreg(mdwc->base, 0x102D, data);
- data = dwc3_msm_ssusb_read_phycreg(msm->base, 0x1010);
+ data = dwc3_msm_ssusb_read_phycreg(mdwc->base, 0x1010);
data &= ~0xFF0;
data |= 0x20;
- dwc3_msm_ssusb_write_phycreg(msm->base, 0x1010, data);
+ dwc3_msm_ssusb_write_phycreg(mdwc->base, 0x1010, data);
/*
* Fix RX Equalization setting as follows
@@ -1314,13 +1348,13 @@
* LANE0.RX_OVRD_IN_HI.RX_EQ set to 3
* LANE0.RX_OVRD_IN_HI.RX_EQ_OVRD set to 1
*/
- data = dwc3_msm_ssusb_read_phycreg(msm->base, 0x1006);
+ data = dwc3_msm_ssusb_read_phycreg(mdwc->base, 0x1006);
data &= ~(1 << 6);
data |= (1 << 7);
data &= ~(0x7 << 8);
data |= (0x3 << 8);
data |= (0x1 << 11);
- dwc3_msm_ssusb_write_phycreg(msm->base, 0x1006, data);
+ dwc3_msm_ssusb_write_phycreg(mdwc->base, 0x1006, data);
/*
* Set EQ and TX launch amplitudes as follows
@@ -1328,12 +1362,12 @@
* LANE0.TX_OVRD_DRV_LO.AMPLITUDE set to 127
* LANE0.TX_OVRD_DRV_LO.EN set to 1.
*/
- data = dwc3_msm_ssusb_read_phycreg(msm->base, 0x1002);
+ data = dwc3_msm_ssusb_read_phycreg(mdwc->base, 0x1002);
data &= ~0x3F80;
data |= (0x16 << 7);
data &= ~0x7F;
data |= (0x7F | (1 << 14));
- dwc3_msm_ssusb_write_phycreg(msm->base, 0x1002, data);
+ dwc3_msm_ssusb_write_phycreg(mdwc->base, 0x1002, data);
/*
* Set the QSCRATCH SS_PHY_PARAM_CTRL1 parameters as follows
@@ -1341,73 +1375,73 @@
* TX_DEEMPH_3_5DB [13:8] to 22
* LOS_BIAS [2:0] to 0x5
*/
- dwc3_msm_write_readback(msm->base, SS_PHY_PARAM_CTRL_1,
+ dwc3_msm_write_readback(mdwc->base, SS_PHY_PARAM_CTRL_1,
0x07f03f07, 0x07f01605);
}
/* Initialize QSCRATCH registers for HSPHY and SSPHY operation */
-static void dwc3_msm_qscratch_reg_init(struct dwc3_msm *msm)
+static void dwc3_msm_qscratch_reg_init(struct dwc3_msm *mdwc)
{
/* SSPHY Initialization: Use ref_clk from pads and set its parameters */
- dwc3_msm_write_reg(msm->base, SS_PHY_CTRL_REG, 0x10210002);
+ dwc3_msm_write_reg(mdwc->base, SS_PHY_CTRL_REG, 0x10210002);
msleep(30);
/* Assert SSPHY reset */
- dwc3_msm_write_reg(msm->base, SS_PHY_CTRL_REG, 0x10210082);
+ dwc3_msm_write_reg(mdwc->base, SS_PHY_CTRL_REG, 0x10210082);
usleep_range(2000, 2200);
/* De-assert SSPHY reset - power and ref_clock must be ON */
- dwc3_msm_write_reg(msm->base, SS_PHY_CTRL_REG, 0x10210002);
+ dwc3_msm_write_reg(mdwc->base, SS_PHY_CTRL_REG, 0x10210002);
usleep_range(2000, 2200);
/* Ref clock must be stable now, enable ref clock for HS mode */
- dwc3_msm_write_reg(msm->base, SS_PHY_CTRL_REG, 0x10210102);
+ dwc3_msm_write_reg(mdwc->base, SS_PHY_CTRL_REG, 0x10210102);
usleep_range(2000, 2200);
/*
* HSPHY Initialization: Enable UTMI clock and clamp enable HVINTs,
* and disable RETENTION (power-on default is ENABLED)
*/
- dwc3_msm_write_reg(msm->base, HS_PHY_CTRL_REG, 0x5220bb2);
+ dwc3_msm_write_reg(mdwc->base, HS_PHY_CTRL_REG, 0x5220bb2);
usleep_range(2000, 2200);
/* Disable (bypass) VBUS and ID filters */
- dwc3_msm_write_reg(msm->base, QSCRATCH_GENERAL_CFG, 0x78);
+ dwc3_msm_write_reg(mdwc->base, QSCRATCH_GENERAL_CFG, 0x78);
/*
* write HSPHY init value to QSCRATCH reg to set HSPHY parameters like
* VBUS valid threshold, disconnect valid threshold, DC voltage level,
* preempasis and rise/fall time.
*/
if (override_phy_init)
- msm->hsphy_init_seq = override_phy_init;
- if (msm->hsphy_init_seq)
- dwc3_msm_write_readback(msm->base,
+ mdwc->hsphy_init_seq = override_phy_init;
+ if (mdwc->hsphy_init_seq)
+ dwc3_msm_write_readback(mdwc->base,
PARAMETER_OVERRIDE_X_REG, 0x03FFFFFF,
- msm->hsphy_init_seq & 0x03FFFFFF);
+ mdwc->hsphy_init_seq & 0x03FFFFFF);
/* Enable master clock for RAMs to allow BAM to access RAMs when
* RAM clock gating is enabled via DWC3's GCTL. Otherwise, issues
* are seen where RAM clocks get turned OFF in SS mode
*/
- dwc3_msm_write_reg(msm->base, CGCTL_REG,
- dwc3_msm_read_reg(msm->base, CGCTL_REG) | 0x18);
+ dwc3_msm_write_reg(mdwc->base, CGCTL_REG,
+ dwc3_msm_read_reg(mdwc->base, CGCTL_REG) | 0x18);
- dwc3_msm_ss_phy_reg_init(msm);
+ dwc3_msm_ss_phy_reg_init(mdwc);
/*
* This is required to restore the POR value after userspace
* is done with charger detection.
*/
- msm->qscratch_ctl_val = dwc3_msm_read_reg(msm->base, QSCRATCH_CTRL_REG);
+ mdwc->qscratch_ctl_val =
+ dwc3_msm_read_reg(mdwc->base, QSCRATCH_CTRL_REG);
}
-static void dwc3_msm_block_reset(bool core_reset)
+static void dwc3_msm_block_reset(struct dwc3_ext_xceiv *xceiv, bool core_reset)
{
-
- struct dwc3_msm *mdwc = context;
+ struct dwc3_msm *mdwc = container_of(xceiv, struct dwc3_msm, ext_xceiv);
int ret = 0;
if (core_reset) {
- ret = dwc3_msm_link_clk_reset(1);
+ ret = dwc3_msm_link_clk_reset(mdwc, 1);
if (ret)
return;
usleep_range(1000, 1200);
- ret = dwc3_msm_link_clk_reset(0);
+ ret = dwc3_msm_link_clk_reset(mdwc, 0);
if (ret)
return;
@@ -1418,9 +1452,9 @@
}
/* Reset the DBM */
- dwc3_msm_dbm_soft_reset(1);
+ dwc3_msm_dbm_soft_reset(mdwc, 1);
usleep_range(1000, 1200);
- dwc3_msm_dbm_soft_reset(0);
+ dwc3_msm_dbm_soft_reset(mdwc, 0);
}
static void dwc3_chg_enable_secondary_det(struct dwc3_msm *mdwc)
@@ -1525,7 +1559,7 @@
case DWC3_DCP_CHARGER: return "USB_DCP_CHARGER";
case DWC3_CDP_CHARGER: return "USB_CDP_CHARGER";
case DWC3_PROPRIETARY_CHARGER: return "USB_PROPRIETARY_CHARGER";
- case DWC3_UNSUPPORTED_CHARGER: return "INVALID_CHARGER";
+ case DWC3_FLOATED_CHARGER: return "USB_FLOATED_CHARGER";
default: return "UNKNOWN_CHARGER";
}
}
@@ -1539,6 +1573,7 @@
{
struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm, chg_work.work);
bool is_dcd = false, tmout, vout;
+ static bool dcd;
unsigned long delay;
dev_dbg(mdwc->dev, "chg detection work\n");
@@ -1554,19 +1589,15 @@
is_dcd = dwc3_chg_check_dcd(mdwc);
tmout = ++mdwc->dcd_retries == DWC3_CHG_DCD_MAX_RETRIES;
if (is_dcd || tmout) {
+ if (is_dcd)
+ dcd = true;
+ else
+ dcd = false;
dwc3_chg_disable_dcd(mdwc);
+ usleep_range(1000, 1200);
if (dwc3_chg_det_check_linestate(mdwc)) {
- dwc3_chg_enable_primary_det(mdwc);
- usleep_range(1000, 1200);
- vout = dwc3_chg_det_check_output(mdwc);
- if (!vout)
- mdwc->charger.chg_type =
- DWC3_UNSUPPORTED_CHARGER;
- else
- mdwc->charger.chg_type =
+ mdwc->charger.chg_type =
DWC3_PROPRIETARY_CHARGER;
- dwc3_msm_write_reg(mdwc->base,
- CHARGING_DET_CTRL_REG, 0x0);
mdwc->chg_state = USB_CHG_STATE_DETECTED;
delay = 0;
break;
@@ -1585,7 +1616,15 @@
delay = DWC3_CHG_SECONDARY_DET_TIME;
mdwc->chg_state = USB_CHG_STATE_PRIMARY_DONE;
} else {
- mdwc->charger.chg_type = DWC3_SDP_CHARGER;
+ /*
+ * Detect floating charger only if propreitary
+ * charger detection is enabled.
+ */
+ if (!dcd && prop_chg_detect)
+ mdwc->charger.chg_type =
+ DWC3_FLOATED_CHARGER;
+ else
+ mdwc->charger.chg_type = DWC3_SDP_CHARGER;
mdwc->chg_state = USB_CHG_STATE_DETECTED;
delay = 0;
}
@@ -1626,7 +1665,7 @@
static void dwc3_start_chg_det(struct dwc3_charger *charger, bool start)
{
- struct dwc3_msm *mdwc = context;
+ struct dwc3_msm *mdwc = container_of(charger, struct dwc3_msm, charger);
if (start == false) {
dev_dbg(mdwc->dev, "canceling charging detection work\n");
@@ -1729,6 +1768,11 @@
/* make sure above writes are completed before turning off clocks */
wmb();
+
+ /* remove vote for controller power collapse */
+ if (!host_bus_suspend)
+ dwc3_msm_config_gdsc(mdwc, 0);
+
if (!host_bus_suspend || !host_ss_active) {
clk_disable_unprepare(mdwc->core_clk);
mdwc->lpm_flags |= MDWC3_CORECLK_OFF;
@@ -1753,13 +1797,13 @@
if (mdwc->otg_xceiv && mdwc->ext_xceiv.otg_capability && !dcp &&
!host_bus_suspend)
- dwc3_hsusb_ldo_enable(0);
+ dwc3_hsusb_ldo_enable(mdwc, 0);
- dwc3_ssusb_ldo_enable(0);
- dwc3_ssusb_config_vddcx(0);
+ dwc3_ssusb_ldo_enable(mdwc, 0);
+ dwc3_ssusb_config_vddcx(mdwc, 0);
if (!host_bus_suspend && !dcp)
- dwc3_hsusb_config_vddcx(0);
- wake_unlock(&mdwc->wlock);
+ dwc3_hsusb_config_vddcx(mdwc, 0);
+ pm_relax(mdwc->dev);
atomic_set(&mdwc->in_lpm, 1);
dev_info(mdwc->dev, "DWC3 in low power mode\n");
@@ -1787,7 +1831,7 @@
return 0;
}
- wake_lock(&mdwc->wlock);
+ pm_stay_awake(mdwc->dev);
if (mdwc->bus_perf_client) {
ret = msm_bus_scale_client_update_request(
@@ -1809,18 +1853,22 @@
mdwc->lpm_flags &= ~MDWC3_TCXO_SHUTDOWN;
}
+ /* add vote for controller power collapse */
+ if (!host_bus_suspend)
+ dwc3_msm_config_gdsc(mdwc, 1);
+
if (!host_bus_suspend)
clk_prepare_enable(mdwc->utmi_clk);
if (mdwc->otg_xceiv && mdwc->ext_xceiv.otg_capability && !dcp &&
!host_bus_suspend)
- dwc3_hsusb_ldo_enable(1);
+ dwc3_hsusb_ldo_enable(mdwc, 1);
- dwc3_ssusb_ldo_enable(1);
- dwc3_ssusb_config_vddcx(1);
+ dwc3_ssusb_ldo_enable(mdwc, 1);
+ dwc3_ssusb_config_vddcx(mdwc, 1);
if (!host_bus_suspend && !dcp)
- dwc3_hsusb_config_vddcx(1);
+ dwc3_hsusb_config_vddcx(mdwc, 1);
clk_prepare_enable(mdwc->ref_clk);
usleep_range(1000, 1200);
@@ -2072,6 +2120,9 @@
case POWER_SUPPLY_PROP_SCOPE:
val->intval = mdwc->host_mode;
break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+ val->intval = mdwc->voltage_max;
+ break;
case POWER_SUPPLY_PROP_CURRENT_MAX:
val->intval = mdwc->current_max;
break;
@@ -2119,6 +2170,9 @@
case POWER_SUPPLY_PROP_ONLINE:
mdwc->online = val->intval;
break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+ mdwc->voltage_max = val->intval;
+ break;
case POWER_SUPPLY_PROP_CURRENT_MAX:
mdwc->current_max = val->intval;
break;
@@ -2159,6 +2213,20 @@
power_supply_changed(&mdwc->usb_psy);
}
+static int
+dwc3_msm_property_is_writeable(struct power_supply *psy,
+ enum power_supply_property psp)
+{
+ switch (psp) {
+ case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+ return 1;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static char *dwc3_msm_pm_power_supplied_to[] = {
"battery",
@@ -2167,6 +2235,7 @@
static enum power_supply_property dwc3_msm_pm_power_props_usb[] = {
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX,
POWER_SUPPLY_PROP_CURRENT_MAX,
POWER_SUPPLY_PROP_TYPE,
POWER_SUPPLY_PROP_SCOPE,
@@ -2174,9 +2243,9 @@
static void dwc3_init_adc_work(struct work_struct *w);
-static void dwc3_ext_notify_online(int on)
+static void dwc3_ext_notify_online(void *ctx, int on)
{
- struct dwc3_msm *mdwc = context;
+ struct dwc3_msm *mdwc = ctx;
bool notify_otg = false;
if (!mdwc) {
@@ -2224,13 +2293,16 @@
disable_irq(mdwc->pmic_id_irq);
ret = usb_ext->notify(usb_ext->ctxt, mdwc->id_state,
- dwc3_ext_notify_online);
+ dwc3_ext_notify_online, mdwc);
dev_dbg(mdwc->dev, "%s: external handler returned %d\n",
__func__, ret);
if (mdwc->pmic_id_irq) {
+ unsigned long flags;
+ local_irq_save(flags);
/* ID may have changed while IRQ disabled; update it */
mdwc->id_state = !!irq_read_line(mdwc->pmic_id_irq);
+ local_irq_restore(flags);
enable_irq(mdwc->pmic_id_irq);
}
@@ -2317,7 +2389,12 @@
static ssize_t adc_enable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- return snprintf(buf, PAGE_SIZE, "%s\n", context->id_adc_detect ?
+ struct dwc3_msm *mdwc = dev_get_drvdata(dev);
+
+ if (!mdwc)
+ return -EINVAL;
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", mdwc->id_adc_detect ?
"enabled" : "disabled");
}
@@ -2325,13 +2402,18 @@
struct device_attribute *attr, const char
*buf, size_t size)
{
+ struct dwc3_msm *mdwc = dev_get_drvdata(dev);
+
+ if (!mdwc)
+ return -EINVAL;
+
if (!strnicmp(buf, "enable", 6)) {
- if (!context->id_adc_detect)
- dwc3_init_adc_work(&context->init_adc_work.work);
+ if (!mdwc->id_adc_detect)
+ dwc3_init_adc_work(&mdwc->init_adc_work.work);
return size;
} else if (!strnicmp(buf, "disable", 7)) {
qpnp_adc_tm_usbid_end();
- context->id_adc_detect = false;
+ mdwc->id_adc_detect = false;
return size;
}
@@ -2343,55 +2425,78 @@
static int dwc3_msm_ext_chg_open(struct inode *inode, struct file *file)
{
- struct dwc3_msm *mdwc = context;
+ struct dwc3_msm *mdwc =
+ container_of(inode->i_cdev, struct dwc3_msm, ext_chg_cdev);
pr_debug("dwc3-msm ext chg open\n");
-
+ file->private_data = mdwc;
mdwc->ext_chg_opened = true;
+
return 0;
}
-static ssize_t
-dwc3_msm_ext_chg_write(struct file *file, const char __user *ubuf,
- size_t size, loff_t *pos)
+static long
+dwc3_msm_ext_chg_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- struct dwc3_msm *mdwc = context;
- char kbuf[16];
+ struct dwc3_msm *mdwc = file->private_data;
+ struct msm_usb_chg_info info = {0};
+ int ret = 0, val;
- memset(kbuf, 0x00, sizeof(kbuf));
- if (copy_from_user(&kbuf, ubuf, min_t(size_t, sizeof(kbuf) - 1, size)))
- return -EFAULT;
+ switch (cmd) {
+ case MSM_USB_EXT_CHG_INFO:
+ info.chg_block_type = USB_CHG_BLOCK_QSCRATCH;
+ info.page_offset = (mdwc->io_res->start +
+ QSCRATCH_REG_OFFSET) & ~PAGE_MASK;
+ /*
+ * The charger block register address space is only
+ * 512 bytes. But mmap() works on PAGE granularity.
+ */
+ info.length = PAGE_SIZE;
- pr_debug("%s: buf = %s\n", __func__, kbuf);
-
- if (!strncmp(kbuf, "enable", 6)) {
- pr_info("%s: on\n", __func__);
- if (mdwc->charger.chg_type == DWC3_DCP_CHARGER) {
- pm_runtime_get_sync(mdwc->dev);
+ if (copy_to_user((void __user *)arg, &info, sizeof(info))) {
+ pr_err("%s: copy to user failed\n\n", __func__);
+ ret = -EFAULT;
+ }
+ break;
+ case MSM_USB_EXT_CHG_BLOCK_LPM:
+ if (get_user(val, (int __user *)arg)) {
+ pr_err("%s: get_user failed\n\n", __func__);
+ ret = -EFAULT;
+ break;
+ }
+ pr_debug("%s: LPM block request %d\n", __func__, val);
+ if (val) { /* block LPM */
+ if (mdwc->charger.chg_type == DWC3_DCP_CHARGER) {
+ pm_runtime_get_sync(mdwc->dev);
+ } else {
+ mdwc->ext_chg_active = false;
+ complete(&mdwc->ext_chg_wait);
+ ret = -ENODEV;
+ }
} else {
mdwc->ext_chg_active = false;
complete(&mdwc->ext_chg_wait);
- return -ENODEV;
+ pm_runtime_put(mdwc->dev);
}
- } else if (!strncmp(kbuf, "disable", 7)) {
- pr_info("%s: off\n", __func__);
- mdwc->ext_chg_active = false;
- complete(&mdwc->ext_chg_wait);
- pm_runtime_put(mdwc->dev);
- } else {
- return -EINVAL;
+ break;
+ default:
+ ret = -EINVAL;
}
- return size;
+ return ret;
}
static int dwc3_msm_ext_chg_mmap(struct file *file, struct vm_area_struct *vma)
{
+ struct dwc3_msm *mdwc = file->private_data;
unsigned long vsize = vma->vm_end - vma->vm_start;
int ret;
- pr_debug("%s: size = %lu %x\n", __func__, vsize, (int) vma->vm_pgoff);
+ if (vma->vm_pgoff != 0 || vsize > PAGE_SIZE)
+ return -EINVAL;
+ vma->vm_pgoff = __phys_to_pfn(mdwc->io_res->start +
+ QSCRATCH_REG_OFFSET);
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
ret = io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
@@ -2404,7 +2509,7 @@
static int dwc3_msm_ext_chg_release(struct inode *inode, struct file *file)
{
- struct dwc3_msm *mdwc = context;
+ struct dwc3_msm *mdwc = file->private_data;
pr_debug("dwc3-msm ext chg release\n");
@@ -2416,7 +2521,7 @@
static const struct file_operations dwc3_msm_ext_chg_fops = {
.owner = THIS_MODULE,
.open = dwc3_msm_ext_chg_open,
- .write = dwc3_msm_ext_chg_write,
+ .unlocked_ioctl = dwc3_msm_ext_chg_ioctl,
.mmap = dwc3_msm_ext_chg_mmap,
.release = dwc3_msm_ext_chg_release,
};
@@ -2469,7 +2574,7 @@
static int __devinit dwc3_msm_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
- struct dwc3_msm *msm;
+ struct dwc3_msm *mdwc;
struct resource *res;
void __iomem *tcsr;
unsigned long flags;
@@ -2477,32 +2582,38 @@
int len = 0;
u32 tmp[3];
- msm = devm_kzalloc(&pdev->dev, sizeof(*msm), GFP_KERNEL);
- if (!msm) {
+ mdwc = devm_kzalloc(&pdev->dev, sizeof(*mdwc), GFP_KERNEL);
+ if (!mdwc) {
dev_err(&pdev->dev, "not enough memory\n");
return -ENOMEM;
}
- platform_set_drvdata(pdev, msm);
- context = msm;
- msm->dev = &pdev->dev;
+ platform_set_drvdata(pdev, mdwc);
+ mdwc->dev = &pdev->dev;
- INIT_LIST_HEAD(&msm->req_complete_list);
- INIT_DELAYED_WORK(&msm->chg_work, dwc3_chg_detect_work);
- INIT_DELAYED_WORK(&msm->resume_work, dwc3_resume_work);
- INIT_WORK(&msm->restart_usb_work, dwc3_restart_usb_work);
- INIT_WORK(&msm->id_work, dwc3_id_work);
- INIT_DELAYED_WORK(&msm->init_adc_work, dwc3_init_adc_work);
- init_completion(&msm->ext_chg_wait);
+ INIT_LIST_HEAD(&mdwc->req_complete_list);
+ INIT_DELAYED_WORK(&mdwc->chg_work, dwc3_chg_detect_work);
+ INIT_DELAYED_WORK(&mdwc->resume_work, dwc3_resume_work);
+ INIT_WORK(&mdwc->restart_usb_work, dwc3_restart_usb_work);
+ INIT_WORK(&mdwc->id_work, dwc3_id_work);
+ INIT_DELAYED_WORK(&mdwc->init_adc_work, dwc3_init_adc_work);
+ init_completion(&mdwc->ext_chg_wait);
- msm->xo_clk = clk_get(&pdev->dev, "xo");
- if (IS_ERR(msm->xo_clk)) {
- dev_err(&pdev->dev, "%s unable to get TCXO buffer handle\n",
- __func__);
- return PTR_ERR(msm->xo_clk);
+ ret = dwc3_msm_config_gdsc(mdwc, 1);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to configure usb3 gdsc\n");
+ return ret;
}
- ret = clk_prepare_enable(msm->xo_clk);
+ mdwc->xo_clk = clk_get(&pdev->dev, "xo");
+ if (IS_ERR(mdwc->xo_clk)) {
+ dev_err(&pdev->dev, "%s unable to get TCXO buffer handle\n",
+ __func__);
+ ret = PTR_ERR(mdwc->xo_clk);
+ goto disable_dwc3_gdsc;
+ }
+
+ ret = clk_prepare_enable(mdwc->xo_clk);
if (ret) {
dev_err(&pdev->dev, "%s failed to vote for TCXO buffer%d\n",
__func__, ret);
@@ -2513,62 +2624,62 @@
* DWC3 Core requires its CORE CLK (aka master / bus clk) to
* run at 125Mhz in SSUSB mode and >60MHZ for HSUSB mode.
*/
- msm->core_clk = devm_clk_get(&pdev->dev, "core_clk");
- if (IS_ERR(msm->core_clk)) {
+ mdwc->core_clk = devm_clk_get(&pdev->dev, "core_clk");
+ if (IS_ERR(mdwc->core_clk)) {
dev_err(&pdev->dev, "failed to get core_clk\n");
- ret = PTR_ERR(msm->core_clk);
+ ret = PTR_ERR(mdwc->core_clk);
goto disable_xo;
}
- clk_set_rate(msm->core_clk, 125000000);
- clk_prepare_enable(msm->core_clk);
+ clk_set_rate(mdwc->core_clk, 125000000);
+ clk_prepare_enable(mdwc->core_clk);
- msm->iface_clk = devm_clk_get(&pdev->dev, "iface_clk");
- if (IS_ERR(msm->iface_clk)) {
+ mdwc->iface_clk = devm_clk_get(&pdev->dev, "iface_clk");
+ if (IS_ERR(mdwc->iface_clk)) {
dev_err(&pdev->dev, "failed to get iface_clk\n");
- ret = PTR_ERR(msm->iface_clk);
+ ret = PTR_ERR(mdwc->iface_clk);
goto disable_core_clk;
}
- clk_prepare_enable(msm->iface_clk);
+ clk_prepare_enable(mdwc->iface_clk);
- msm->sleep_clk = devm_clk_get(&pdev->dev, "sleep_clk");
- if (IS_ERR(msm->sleep_clk)) {
+ mdwc->sleep_clk = devm_clk_get(&pdev->dev, "sleep_clk");
+ if (IS_ERR(mdwc->sleep_clk)) {
dev_err(&pdev->dev, "failed to get sleep_clk\n");
- ret = PTR_ERR(msm->sleep_clk);
+ ret = PTR_ERR(mdwc->sleep_clk);
goto disable_iface_clk;
}
- clk_prepare_enable(msm->sleep_clk);
+ clk_prepare_enable(mdwc->sleep_clk);
- msm->hsphy_sleep_clk = devm_clk_get(&pdev->dev, "sleep_a_clk");
- if (IS_ERR(msm->hsphy_sleep_clk)) {
+ mdwc->hsphy_sleep_clk = devm_clk_get(&pdev->dev, "sleep_a_clk");
+ if (IS_ERR(mdwc->hsphy_sleep_clk)) {
dev_err(&pdev->dev, "failed to get sleep_a_clk\n");
- ret = PTR_ERR(msm->hsphy_sleep_clk);
+ ret = PTR_ERR(mdwc->hsphy_sleep_clk);
goto disable_sleep_clk;
}
- clk_prepare_enable(msm->hsphy_sleep_clk);
+ clk_prepare_enable(mdwc->hsphy_sleep_clk);
- msm->utmi_clk = devm_clk_get(&pdev->dev, "utmi_clk");
- if (IS_ERR(msm->utmi_clk)) {
+ mdwc->utmi_clk = devm_clk_get(&pdev->dev, "utmi_clk");
+ if (IS_ERR(mdwc->utmi_clk)) {
dev_err(&pdev->dev, "failed to get utmi_clk\n");
- ret = PTR_ERR(msm->utmi_clk);
+ ret = PTR_ERR(mdwc->utmi_clk);
goto disable_sleep_a_clk;
}
- clk_prepare_enable(msm->utmi_clk);
+ clk_prepare_enable(mdwc->utmi_clk);
- msm->ref_clk = devm_clk_get(&pdev->dev, "ref_clk");
- if (IS_ERR(msm->ref_clk)) {
+ mdwc->ref_clk = devm_clk_get(&pdev->dev, "ref_clk");
+ if (IS_ERR(mdwc->ref_clk)) {
dev_err(&pdev->dev, "failed to get ref_clk\n");
- ret = PTR_ERR(msm->ref_clk);
+ ret = PTR_ERR(mdwc->ref_clk);
goto disable_utmi_clk;
}
- clk_prepare_enable(msm->ref_clk);
+ clk_prepare_enable(mdwc->ref_clk);
of_get_property(node, "qcom,vdd-voltage-level", &len);
if (len == sizeof(tmp)) {
of_property_read_u32_array(node, "qcom,vdd-voltage-level",
tmp, len/sizeof(*tmp));
- msm->vdd_no_vol_level = tmp[0];
- msm->vdd_low_vol_level = tmp[1];
- msm->vdd_high_vol_level = tmp[2];
+ mdwc->vdd_no_vol_level = tmp[0];
+ mdwc->vdd_low_vol_level = tmp[1];
+ mdwc->vdd_high_vol_level = tmp[2];
} else {
dev_err(&pdev->dev, "no qcom,vdd-voltage-level property\n");
ret = -EINVAL;
@@ -2576,99 +2687,100 @@
}
/* SS PHY */
- msm->ssusb_vddcx = devm_regulator_get(&pdev->dev, "ssusb_vdd_dig");
- if (IS_ERR(msm->ssusb_vddcx)) {
+ mdwc->ssusb_vddcx = devm_regulator_get(&pdev->dev, "ssusb_vdd_dig");
+ if (IS_ERR(mdwc->ssusb_vddcx)) {
dev_err(&pdev->dev, "unable to get ssusb vddcx\n");
- ret = PTR_ERR(msm->ssusb_vddcx);
+ ret = PTR_ERR(mdwc->ssusb_vddcx);
goto disable_ref_clk;
}
- ret = dwc3_ssusb_config_vddcx(1);
+ ret = dwc3_ssusb_config_vddcx(mdwc, 1);
if (ret) {
dev_err(&pdev->dev, "ssusb vddcx configuration failed\n");
goto disable_ref_clk;
}
- ret = regulator_enable(context->ssusb_vddcx);
+ ret = regulator_enable(mdwc->ssusb_vddcx);
if (ret) {
dev_err(&pdev->dev, "unable to enable the ssusb vddcx\n");
goto unconfig_ss_vddcx;
}
- ret = dwc3_ssusb_ldo_init(1);
+ ret = dwc3_ssusb_ldo_init(mdwc, 1);
if (ret) {
dev_err(&pdev->dev, "ssusb vreg configuration failed\n");
goto disable_ss_vddcx;
}
- ret = dwc3_ssusb_ldo_enable(1);
+ ret = dwc3_ssusb_ldo_enable(mdwc, 1);
if (ret) {
dev_err(&pdev->dev, "ssusb vreg enable failed\n");
goto free_ss_ldo_init;
}
/* HS PHY */
- msm->hsusb_vddcx = devm_regulator_get(&pdev->dev, "hsusb_vdd_dig");
- if (IS_ERR(msm->hsusb_vddcx)) {
+ mdwc->hsusb_vddcx = devm_regulator_get(&pdev->dev, "hsusb_vdd_dig");
+ if (IS_ERR(mdwc->hsusb_vddcx)) {
dev_err(&pdev->dev, "unable to get hsusb vddcx\n");
- ret = PTR_ERR(msm->hsusb_vddcx);
+ ret = PTR_ERR(mdwc->hsusb_vddcx);
goto disable_ss_ldo;
}
- ret = dwc3_hsusb_config_vddcx(1);
+ ret = dwc3_hsusb_config_vddcx(mdwc, 1);
if (ret) {
dev_err(&pdev->dev, "hsusb vddcx configuration failed\n");
goto disable_ss_ldo;
}
- ret = regulator_enable(context->hsusb_vddcx);
+ ret = regulator_enable(mdwc->hsusb_vddcx);
if (ret) {
dev_err(&pdev->dev, "unable to enable the hsusb vddcx\n");
goto unconfig_hs_vddcx;
}
- ret = dwc3_hsusb_ldo_init(1);
+ ret = dwc3_hsusb_ldo_init(mdwc, 1);
if (ret) {
dev_err(&pdev->dev, "hsusb vreg configuration failed\n");
goto disable_hs_vddcx;
}
- ret = dwc3_hsusb_ldo_enable(1);
+ ret = dwc3_hsusb_ldo_enable(mdwc, 1);
if (ret) {
dev_err(&pdev->dev, "hsusb vreg enable failed\n");
goto free_hs_ldo_init;
}
- msm->id_state = msm->ext_xceiv.id = DWC3_ID_FLOAT;
- msm->ext_xceiv.otg_capability = of_property_read_bool(node,
+ mdwc->id_state = mdwc->ext_xceiv.id = DWC3_ID_FLOAT;
+ mdwc->ext_xceiv.otg_capability = of_property_read_bool(node,
"qcom,otg-capability");
- msm->charger.charging_disabled = of_property_read_bool(node,
+ mdwc->charger.charging_disabled = of_property_read_bool(node,
"qcom,charging-disabled");
- msm->charger.skip_chg_detect = of_property_read_bool(node,
+ mdwc->charger.skip_chg_detect = of_property_read_bool(node,
"qcom,skip-charger-detection");
/*
* DWC3 has separate IRQ line for OTG events (ID/BSV) and for
* DP and DM linestate transitions during low power mode.
*/
- msm->hs_phy_irq = platform_get_irq_byname(pdev, "hs_phy_irq");
- if (msm->hs_phy_irq < 0) {
+ mdwc->hs_phy_irq = platform_get_irq_byname(pdev, "hs_phy_irq");
+ if (mdwc->hs_phy_irq < 0) {
dev_dbg(&pdev->dev, "pget_irq for hs_phy_irq failed\n");
- msm->hs_phy_irq = 0;
+ mdwc->hs_phy_irq = 0;
} else {
- ret = devm_request_irq(&pdev->dev, msm->hs_phy_irq,
+ ret = devm_request_irq(&pdev->dev, mdwc->hs_phy_irq,
msm_dwc3_irq, IRQF_TRIGGER_RISING,
- "msm_dwc3", msm);
+ "msm_dwc3", mdwc);
if (ret) {
dev_err(&pdev->dev, "irqreq HSPHYINT failed\n");
goto disable_hs_ldo;
}
- enable_irq_wake(msm->hs_phy_irq);
+ enable_irq_wake(mdwc->hs_phy_irq);
}
- if (msm->ext_xceiv.otg_capability) {
- msm->pmic_id_irq = platform_get_irq_byname(pdev, "pmic_id_irq");
- if (msm->pmic_id_irq > 0) {
+ if (mdwc->ext_xceiv.otg_capability) {
+ mdwc->pmic_id_irq =
+ platform_get_irq_byname(pdev, "pmic_id_irq");
+ if (mdwc->pmic_id_irq > 0) {
/* check if PMIC ID IRQ is supported */
ret = qpnp_misc_irqs_available(&pdev->dev);
@@ -2676,14 +2788,15 @@
/* qpnp hasn't probed yet; defer dwc probe */
goto disable_hs_ldo;
} else if (ret == 0) {
- msm->pmic_id_irq = 0;
+ mdwc->pmic_id_irq = 0;
} else {
ret = devm_request_irq(&pdev->dev,
- msm->pmic_id_irq,
+ mdwc->pmic_id_irq,
dwc3_pmic_id_irq,
IRQF_TRIGGER_RISING |
IRQF_TRIGGER_FALLING,
- "dwc3_msm_pmic_id", msm);
+ "dwc3_msm_pmic_id",
+ mdwc);
if (ret) {
dev_err(&pdev->dev, "irqreq IDINT failed\n");
goto disable_hs_ldo;
@@ -2691,21 +2804,21 @@
local_irq_save(flags);
/* Update initial ID state */
- msm->id_state =
- !!irq_read_line(msm->pmic_id_irq);
- if (msm->id_state == DWC3_ID_GROUND)
+ mdwc->id_state =
+ !!irq_read_line(mdwc->pmic_id_irq);
+ if (mdwc->id_state == DWC3_ID_GROUND)
queue_work(system_nrt_wq,
- &msm->id_work);
+ &mdwc->id_work);
local_irq_restore(flags);
- enable_irq_wake(msm->pmic_id_irq);
+ enable_irq_wake(mdwc->pmic_id_irq);
}
}
- if (msm->pmic_id_irq <= 0) {
+ if (mdwc->pmic_id_irq <= 0) {
/* If no PMIC ID IRQ, use ADC for ID pin detection */
- queue_work(system_nrt_wq, &msm->init_adc_work.work);
+ queue_work(system_nrt_wq, &mdwc->init_adc_work.work);
device_create_file(&pdev->dev, &dev_attr_adc_enable);
- msm->pmic_id_irq = 0;
+ mdwc->pmic_id_irq = 0;
}
}
@@ -2735,59 +2848,62 @@
goto disable_hs_ldo;
}
- msm->base = devm_ioremap_nocache(&pdev->dev, res->start,
+ mdwc->base = devm_ioremap_nocache(&pdev->dev, res->start,
resource_size(res));
- if (!msm->base) {
+ if (!mdwc->base) {
dev_err(&pdev->dev, "ioremap failed\n");
ret = -ENODEV;
goto disable_hs_ldo;
}
- msm->resource_size = resource_size(res);
+ mdwc->io_res = res; /* used to calculate chg block offset */
if (of_property_read_u32(node, "qcom,dwc-hsphy-init",
- &msm->hsphy_init_seq))
+ &mdwc->hsphy_init_seq))
dev_dbg(&pdev->dev, "unable to read hsphy init seq\n");
- else if (!msm->hsphy_init_seq)
+ else if (!mdwc->hsphy_init_seq)
dev_warn(&pdev->dev, "incorrect hsphyinitseq.Using PORvalue\n");
- dwc3_msm_qscratch_reg_init(msm);
+ dwc3_msm_qscratch_reg_init(mdwc);
- pm_runtime_set_active(msm->dev);
- pm_runtime_enable(msm->dev);
+ pm_runtime_set_active(mdwc->dev);
+ pm_runtime_enable(mdwc->dev);
if (of_property_read_u32(node, "qcom,dwc-usb3-msm-dbm-eps",
- &msm->dbm_num_eps)) {
+ &mdwc->dbm_num_eps)) {
dev_err(&pdev->dev,
"unable to read platform data num of dbm eps\n");
- msm->dbm_num_eps = DBM_MAX_EPS;
+ mdwc->dbm_num_eps = DBM_MAX_EPS;
}
- if (msm->dbm_num_eps > DBM_MAX_EPS) {
+ if (mdwc->dbm_num_eps > DBM_MAX_EPS) {
dev_err(&pdev->dev,
"Driver doesn't support number of DBM EPs. "
"max: %d, dbm_num_eps: %d\n",
- DBM_MAX_EPS, msm->dbm_num_eps);
+ DBM_MAX_EPS, mdwc->dbm_num_eps);
ret = -ENODEV;
goto disable_hs_ldo;
}
/* usb_psy required only for vbus_notifications or charging support */
- if (msm->ext_xceiv.otg_capability || !msm->charger.charging_disabled) {
- msm->usb_psy.name = "usb";
- msm->usb_psy.type = POWER_SUPPLY_TYPE_USB;
- msm->usb_psy.supplied_to = dwc3_msm_pm_power_supplied_to;
- msm->usb_psy.num_supplicants = ARRAY_SIZE(
+ if (mdwc->ext_xceiv.otg_capability ||
+ !mdwc->charger.charging_disabled) {
+ mdwc->usb_psy.name = "usb";
+ mdwc->usb_psy.type = POWER_SUPPLY_TYPE_USB;
+ mdwc->usb_psy.supplied_to = dwc3_msm_pm_power_supplied_to;
+ mdwc->usb_psy.num_supplicants = ARRAY_SIZE(
dwc3_msm_pm_power_supplied_to);
- msm->usb_psy.properties = dwc3_msm_pm_power_props_usb;
- msm->usb_psy.num_properties =
+ mdwc->usb_psy.properties = dwc3_msm_pm_power_props_usb;
+ mdwc->usb_psy.num_properties =
ARRAY_SIZE(dwc3_msm_pm_power_props_usb);
- msm->usb_psy.get_property = dwc3_msm_power_get_property_usb;
- msm->usb_psy.set_property = dwc3_msm_power_set_property_usb;
- msm->usb_psy.external_power_changed =
+ mdwc->usb_psy.get_property = dwc3_msm_power_get_property_usb;
+ mdwc->usb_psy.set_property = dwc3_msm_power_set_property_usb;
+ mdwc->usb_psy.external_power_changed =
dwc3_msm_external_power_changed;
+ mdwc->usb_psy.property_is_writeable =
+ dwc3_msm_property_is_writeable;
- ret = power_supply_register(&pdev->dev, &msm->usb_psy);
+ ret = power_supply_register(&pdev->dev, &mdwc->usb_psy);
if (ret < 0) {
dev_err(&pdev->dev,
"%s:power_supply_register usb failed\n",
@@ -2805,27 +2921,28 @@
}
}
- msm->bus_scale_table = msm_bus_cl_get_pdata(pdev);
- if (!msm->bus_scale_table) {
+ mdwc->bus_scale_table = msm_bus_cl_get_pdata(pdev);
+ if (!mdwc->bus_scale_table) {
dev_err(&pdev->dev, "bus scaling is disabled\n");
} else {
- msm->bus_perf_client =
- msm_bus_scale_register_client(msm->bus_scale_table);
+ mdwc->bus_perf_client =
+ msm_bus_scale_register_client(mdwc->bus_scale_table);
ret = msm_bus_scale_client_update_request(
- msm->bus_perf_client, 1);
+ mdwc->bus_perf_client, 1);
if (ret)
dev_err(&pdev->dev, "Failed to vote for bus scaling\n");
}
- msm->otg_xceiv = usb_get_transceiver();
+ mdwc->otg_xceiv = usb_get_transceiver();
/* Register with OTG if present, ignore USB2 OTG using other PHY */
- if (msm->otg_xceiv && !(msm->otg_xceiv->flags & ENABLE_SECONDARY_PHY)) {
+ if (mdwc->otg_xceiv &&
+ !(mdwc->otg_xceiv->flags & ENABLE_SECONDARY_PHY)) {
/* Skip charger detection for simulator targets */
- if (!msm->charger.skip_chg_detect) {
- msm->charger.start_detection = dwc3_start_chg_det;
- ret = dwc3_set_charger(msm->otg_xceiv->otg,
- &msm->charger);
- if (ret || !msm->charger.notify_detection_complete) {
+ if (!mdwc->charger.skip_chg_detect) {
+ mdwc->charger.start_detection = dwc3_start_chg_det;
+ ret = dwc3_set_charger(mdwc->otg_xceiv->otg,
+ &mdwc->charger);
+ if (ret || !mdwc->charger.notify_detection_complete) {
dev_err(&pdev->dev,
"failed to register charger: %d\n",
ret);
@@ -2833,125 +2950,130 @@
}
}
- if (msm->ext_xceiv.otg_capability)
- msm->ext_xceiv.ext_block_reset = dwc3_msm_block_reset;
- ret = dwc3_set_ext_xceiv(msm->otg_xceiv->otg, &msm->ext_xceiv);
- if (ret || !msm->ext_xceiv.notify_ext_events) {
+ if (mdwc->ext_xceiv.otg_capability)
+ mdwc->ext_xceiv.ext_block_reset = dwc3_msm_block_reset;
+ ret = dwc3_set_ext_xceiv(mdwc->otg_xceiv->otg,
+ &mdwc->ext_xceiv);
+ if (ret || !mdwc->ext_xceiv.notify_ext_events) {
dev_err(&pdev->dev, "failed to register xceiver: %d\n",
ret);
goto put_xcvr;
}
} else {
dev_dbg(&pdev->dev, "No OTG, DWC3 running in host only mode\n");
- msm->host_mode = 1;
- msm->vbus_otg = devm_regulator_get(&pdev->dev, "vbus_dwc3");
- if (IS_ERR(msm->vbus_otg)) {
+ mdwc->host_mode = 1;
+ mdwc->vbus_otg = devm_regulator_get(&pdev->dev, "vbus_dwc3");
+ if (IS_ERR(mdwc->vbus_otg)) {
dev_dbg(&pdev->dev, "Failed to get vbus regulator\n");
- msm->vbus_otg = 0;
+ mdwc->vbus_otg = 0;
} else {
- ret = regulator_enable(msm->vbus_otg);
+ ret = regulator_enable(mdwc->vbus_otg);
if (ret) {
- msm->vbus_otg = 0;
+ mdwc->vbus_otg = 0;
dev_err(&pdev->dev, "Failed to enable vbus_otg\n");
}
}
- msm->otg_xceiv = NULL;
+ mdwc->otg_xceiv = NULL;
}
- if (msm->ext_xceiv.otg_capability && msm->charger.start_detection) {
- ret = dwc3_msm_setup_cdev(msm);
+ if (mdwc->ext_xceiv.otg_capability && mdwc->charger.start_detection) {
+ ret = dwc3_msm_setup_cdev(mdwc);
if (ret)
dev_err(&pdev->dev, "Fail to setup dwc3 setup cdev\n");
}
- wake_lock_init(&msm->wlock, WAKE_LOCK_SUSPEND, "msm_dwc3");
- wake_lock(&msm->wlock);
- dwc3_debugfs_init(msm);
+ device_init_wakeup(mdwc->dev, 1);
+ pm_stay_awake(mdwc->dev);
+ dwc3_debugfs_init(mdwc);
return 0;
put_xcvr:
- usb_put_transceiver(msm->otg_xceiv);
+ usb_put_transceiver(mdwc->otg_xceiv);
put_psupply:
- if (msm->usb_psy.dev)
- power_supply_unregister(&msm->usb_psy);
+ if (mdwc->usb_psy.dev)
+ power_supply_unregister(&mdwc->usb_psy);
disable_hs_ldo:
- dwc3_hsusb_ldo_enable(0);
+ dwc3_hsusb_ldo_enable(mdwc, 0);
free_hs_ldo_init:
- dwc3_hsusb_ldo_init(0);
+ dwc3_hsusb_ldo_init(mdwc, 0);
disable_hs_vddcx:
- regulator_disable(context->hsusb_vddcx);
+ regulator_disable(mdwc->hsusb_vddcx);
unconfig_hs_vddcx:
- dwc3_hsusb_config_vddcx(0);
+ dwc3_hsusb_config_vddcx(mdwc, 0);
disable_ss_ldo:
- dwc3_ssusb_ldo_enable(0);
+ dwc3_ssusb_ldo_enable(mdwc, 0);
free_ss_ldo_init:
- dwc3_ssusb_ldo_init(0);
+ dwc3_ssusb_ldo_init(mdwc, 0);
disable_ss_vddcx:
- regulator_disable(context->ssusb_vddcx);
+ regulator_disable(mdwc->ssusb_vddcx);
unconfig_ss_vddcx:
- dwc3_ssusb_config_vddcx(0);
+ dwc3_ssusb_config_vddcx(mdwc, 0);
disable_ref_clk:
- clk_disable_unprepare(msm->ref_clk);
+ clk_disable_unprepare(mdwc->ref_clk);
disable_utmi_clk:
- clk_disable_unprepare(msm->utmi_clk);
+ clk_disable_unprepare(mdwc->utmi_clk);
disable_sleep_a_clk:
- clk_disable_unprepare(msm->hsphy_sleep_clk);
+ clk_disable_unprepare(mdwc->hsphy_sleep_clk);
disable_sleep_clk:
- clk_disable_unprepare(msm->sleep_clk);
+ clk_disable_unprepare(mdwc->sleep_clk);
disable_iface_clk:
- clk_disable_unprepare(msm->iface_clk);
+ clk_disable_unprepare(mdwc->iface_clk);
disable_core_clk:
- clk_disable_unprepare(msm->core_clk);
+ clk_disable_unprepare(mdwc->core_clk);
disable_xo:
- clk_disable_unprepare(msm->xo_clk);
+ clk_disable_unprepare(mdwc->xo_clk);
put_xo:
- clk_put(msm->xo_clk);
+ clk_put(mdwc->xo_clk);
+disable_dwc3_gdsc:
+ dwc3_msm_config_gdsc(mdwc, 0);
return ret;
}
static int __devexit dwc3_msm_remove(struct platform_device *pdev)
{
- struct dwc3_msm *msm = platform_get_drvdata(pdev);
+ struct dwc3_msm *mdwc = platform_get_drvdata(pdev);
- if (!msm->ext_chg_device) {
- device_destroy(msm->ext_chg_class, msm->ext_chg_dev);
- cdev_del(&msm->ext_chg_cdev);
- class_destroy(msm->ext_chg_class);
- unregister_chrdev_region(msm->ext_chg_dev, 1);
+ if (!mdwc->ext_chg_device) {
+ device_destroy(mdwc->ext_chg_class, mdwc->ext_chg_dev);
+ cdev_del(&mdwc->ext_chg_cdev);
+ class_destroy(mdwc->ext_chg_class);
+ unregister_chrdev_region(mdwc->ext_chg_dev, 1);
}
- if (msm->id_adc_detect)
+ if (mdwc->id_adc_detect)
qpnp_adc_tm_usbid_end();
if (dwc3_debugfs_root)
debugfs_remove_recursive(dwc3_debugfs_root);
- if (msm->otg_xceiv) {
- dwc3_start_chg_det(&msm->charger, false);
- usb_put_transceiver(msm->otg_xceiv);
+ if (mdwc->otg_xceiv) {
+ dwc3_start_chg_det(&mdwc->charger, false);
+ usb_put_transceiver(mdwc->otg_xceiv);
}
- if (msm->usb_psy.dev)
- power_supply_unregister(&msm->usb_psy);
- if (msm->vbus_otg)
- regulator_disable(msm->vbus_otg);
+ if (mdwc->usb_psy.dev)
+ power_supply_unregister(&mdwc->usb_psy);
+ if (mdwc->vbus_otg)
+ regulator_disable(mdwc->vbus_otg);
- pm_runtime_disable(msm->dev);
- wake_lock_destroy(&msm->wlock);
+ pm_runtime_disable(mdwc->dev);
+ device_init_wakeup(mdwc->dev, 0);
- dwc3_hsusb_ldo_enable(0);
- dwc3_hsusb_ldo_init(0);
- regulator_disable(msm->hsusb_vddcx);
- dwc3_hsusb_config_vddcx(0);
- dwc3_ssusb_ldo_enable(0);
- dwc3_ssusb_ldo_init(0);
- regulator_disable(msm->ssusb_vddcx);
- dwc3_ssusb_config_vddcx(0);
- clk_disable_unprepare(msm->core_clk);
- clk_disable_unprepare(msm->iface_clk);
- clk_disable_unprepare(msm->sleep_clk);
- clk_disable_unprepare(msm->hsphy_sleep_clk);
- clk_disable_unprepare(msm->ref_clk);
- clk_disable_unprepare(msm->xo_clk);
- clk_put(msm->xo_clk);
+ dwc3_hsusb_ldo_enable(mdwc, 0);
+ dwc3_hsusb_ldo_init(mdwc, 0);
+ regulator_disable(mdwc->hsusb_vddcx);
+ dwc3_hsusb_config_vddcx(mdwc, 0);
+ dwc3_ssusb_ldo_enable(mdwc, 0);
+ dwc3_ssusb_ldo_init(mdwc, 0);
+ regulator_disable(mdwc->ssusb_vddcx);
+ dwc3_ssusb_config_vddcx(mdwc, 0);
+ clk_disable_unprepare(mdwc->core_clk);
+ clk_disable_unprepare(mdwc->iface_clk);
+ clk_disable_unprepare(mdwc->sleep_clk);
+ clk_disable_unprepare(mdwc->hsphy_sleep_clk);
+ clk_disable_unprepare(mdwc->ref_clk);
+ clk_disable_unprepare(mdwc->xo_clk);
+ clk_put(mdwc->xo_clk);
+
+ dwc3_msm_config_gdsc(mdwc, 0);
return 0;
}
diff --git a/drivers/usb/dwc3/dwc3_otg.c b/drivers/usb/dwc3/dwc3_otg.c
index 98c9b4c..0d4d580 100644
--- a/drivers/usb/dwc3/dwc3_otg.c
+++ b/drivers/usb/dwc3/dwc3_otg.c
@@ -218,7 +218,7 @@
*/
if (ext_xceiv && ext_xceiv->otg_capability &&
ext_xceiv->ext_block_reset)
- ext_xceiv->ext_block_reset(true);
+ ext_xceiv->ext_block_reset(ext_xceiv, true);
dwc3_otg_set_peripheral_regs(dotg);
@@ -285,7 +285,7 @@
* DBM reset is required, hence perform only DBM reset here */
if (ext_xceiv && ext_xceiv->otg_capability &&
ext_xceiv->ext_block_reset)
- ext_xceiv->ext_block_reset(false);
+ ext_xceiv->ext_block_reset(ext_xceiv, false);
dwc3_otg_set_peripheral_regs(dotg);
usb_gadget_vbus_connect(otg->gadget);
@@ -726,8 +726,17 @@
phy->state = OTG_STATE_B_PERIPHERAL;
work = 1;
break;
- case DWC3_UNSUPPORTED_CHARGER:
+ case DWC3_FLOATED_CHARGER:
dotg->charger_retry_count++;
+ /*
+ * In case of floating charger, if
+ * retry count equal to max retry count
+ * notify PMIC about floating charger
+ * and put Hw in low power mode. Else
+ * perform charger detection again by
+ * calling start_detection() with false
+ * and then with true argument.
+ */
if (dotg->charger_retry_count ==
max_chgr_retry_count) {
dwc3_otg_set_power(phy, 0);
@@ -795,7 +804,7 @@
*/
dev_dbg(phy->dev, "enter lpm as\n"
"unable to start A-device\n");
- phy->state = OTG_STATE_UNDEFINED;
+ phy->state = OTG_STATE_A_IDLE;
pm_runtime_put_sync(phy->dev);
return;
}
diff --git a/drivers/usb/dwc3/dwc3_otg.h b/drivers/usb/dwc3/dwc3_otg.h
index b00468e..7adf874 100644
--- a/drivers/usb/dwc3/dwc3_otg.h
+++ b/drivers/usb/dwc3/dwc3_otg.h
@@ -64,6 +64,7 @@
* IDEV_CHG_MAX can be drawn irrespective of USB state.
* DWC3_PROPRIETARY_CHARGER A proprietary charger pull DP and DM to specific
* voltages between 2.0-3.3v for identification.
+ * DWC3_FLOATED_CHARGER Non standard charger whose data lines are floating.
*/
enum dwc3_chg_type {
DWC3_INVALID_CHARGER = 0,
@@ -71,7 +72,7 @@
DWC3_DCP_CHARGER,
DWC3_CDP_CHARGER,
DWC3_PROPRIETARY_CHARGER,
- DWC3_UNSUPPORTED_CHARGER,
+ DWC3_FLOATED_CHARGER,
};
struct dwc3_charger {
@@ -113,7 +114,8 @@
void (*notify_ext_events)(struct usb_otg *otg,
enum dwc3_ext_events ext_event);
/* for block reset USB core */
- void (*ext_block_reset)(bool core_reset);
+ void (*ext_block_reset)(struct dwc3_ext_xceiv *ext_xceiv,
+ bool core_reset);
};
/* for external transceiver driver */
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 63698de..acda980 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -43,6 +43,7 @@
#include <linux/spinlock.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/ratelimit.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/list.h>
@@ -1487,10 +1488,12 @@
return 0;
}
+#define DWC3_SOFT_RESET_TIMEOUT 10 /* 10 msec */
static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
{
u32 reg;
u32 timeout = 500;
+ ktime_t start, diff;
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
if (is_on) {
@@ -1501,6 +1504,29 @@
if (dwc->revision >= DWC3_REVISION_194A)
reg &= ~DWC3_DCTL_KEEP_CONNECT;
+
+ start = ktime_get();
+ /* issue device SoftReset */
+ dwc3_writel(dwc->regs, DWC3_DCTL, reg | DWC3_DCTL_CSFTRST);
+ do {
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+ if (!(reg & DWC3_DCTL_CSFTRST))
+ break;
+
+ diff = ktime_sub(ktime_get(), start);
+ /* poll for max. 10ms */
+ if (ktime_to_ms(diff) > DWC3_SOFT_RESET_TIMEOUT) {
+ printk_ratelimited(KERN_ERR
+ "%s:core Reset Timed Out\n", __func__);
+ break;
+ }
+ cpu_relax();
+ } while (true);
+
+
+ dwc3_event_buffers_setup(dwc);
+ dwc3_gadget_restart(dwc);
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg |= DWC3_DCTL_RUN_STOP;
} else {
reg &= ~DWC3_DCTL_RUN_STOP;
@@ -1754,6 +1780,7 @@
dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
dep = dwc->eps[0];
+ dep->endpoint.maxburst = 1;
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
if (ret) {
dev_err(dwc->dev, "failed to enable %s\n", dep->name);
@@ -1761,6 +1788,7 @@
}
dep = dwc->eps[1];
+ dep->endpoint.maxburst = 1;
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
if (ret) {
dev_err(dwc->dev, "failed to enable %s\n", dep->name);
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index e7074a2..3f8d924 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -1853,6 +1853,14 @@
spin_lock_irqsave(mep->lock, flags);
+
+ if (_udc && (!_udc->vbus_active || _udc->suspended)) {
+ pr_debug("ep%d%s prime timer when vbus_active=%d,suspend=%d\n",
+ mep->num, mep->dir ? "IN" : "OUT",
+ _udc->vbus_active, _udc->suspended);
+ goto out;
+ }
+
if (!hw_cread(CAP_ENDPTPRIME, BIT(n)))
goto out;
@@ -2197,6 +2205,9 @@
if (mEp == NULL)
return -EINVAL;
+ del_timer(&mEp->prime_timer);
+ mEp->prime_timer_count = 0;
+
hw_ep_flush(mEp->num, mEp->dir);
while (!list_empty(&mEp->qh.queue)) {
@@ -2926,8 +2937,6 @@
/* only internal SW should disable ctrl endpts */
- del_timer(&mEp->prime_timer);
- mEp->prime_timer_count = 0;
direction = mEp->dir;
do {
dbg_event(_usb_addr(mEp), "DISABLE", 0);
@@ -3282,8 +3291,6 @@
spin_lock_irqsave(mEp->lock, flags);
- del_timer(&mEp->prime_timer);
- mEp->prime_timer_count = 0;
dbg_event(_usb_addr(mEp), "FFLUSH", 0);
/*
* _ep_nuke() takes care of flushing the endpoint.
diff --git a/drivers/usb/gadget/f_diag.c b/drivers/usb/gadget/f_diag.c
index 3355e19..d1b911a 100644
--- a/drivers/usb/gadget/f_diag.c
+++ b/drivers/usb/gadget/f_diag.c
@@ -642,6 +642,8 @@
if (ctxt->ch && ctxt->ch->priv_usb == ctxt)
ctxt->ch->priv_usb = NULL;
list_del(&ctxt->list_item);
+ /* Free any pending USB requests from last session */
+ free_reqs(ctxt);
kfree(ctxt);
}
diff --git a/drivers/usb/gadget/f_qdss.c b/drivers/usb/gadget/f_qdss.c
index cece500..f90967f 100644
--- a/drivers/usb/gadget/f_qdss.c
+++ b/drivers/usb/gadget/f_qdss.c
@@ -790,6 +790,7 @@
void usb_qdss_close(struct usb_qdss_ch *ch)
{
struct f_qdss *qdss = ch->priv_usb;
+ struct usb_gadget *gadget = qdss->cdev->gadget;
unsigned long flags;
pr_debug("usb_qdss_close\n");
@@ -801,7 +802,7 @@
ch->app_conn = 0;
spin_unlock_irqrestore(&d_lock, flags);
- msm_dwc3_restart_usb_session();
+ msm_dwc3_restart_usb_session(gadget);
}
EXPORT_SYMBOL(usb_qdss_close);
diff --git a/drivers/usb/gadget/u_ctrl_hsuart.c b/drivers/usb/gadget/u_ctrl_hsuart.c
index a9bd53e..3443d12 100644
--- a/drivers/usb/gadget/u_ctrl_hsuart.c
+++ b/drivers/usb/gadget/u_ctrl_hsuart.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
@@ -18,11 +18,13 @@
#include <linux/termios.h>
#include <linux/debugfs.h>
#include <linux/smux.h>
+#include <linux/completion.h>
#include <mach/usb_gadget_xport.h>
#define CH_OPENED 0
#define CH_READY 1
+#define CH_CONNECTED 2
static unsigned int num_ctrl_ports;
@@ -37,6 +39,7 @@
enum gadget_type gtype;
spinlock_t port_lock;
void *port_usb;
+ struct completion close_complete;
/* work queue*/
struct workqueue_struct *wq;
struct work_struct connect_w;
@@ -74,6 +77,10 @@
size_t len;
switch (event_type) {
+ case SMUX_LOCAL_CLOSED:
+ clear_bit(CH_OPENED, &port->channel_sts);
+ complete(&port->close_complete);
+ break;
case SMUX_CONNECTED:
spin_lock_irqsave(&port->port_lock, flags);
if (!port->port_usb) {
@@ -81,7 +88,7 @@
return;
}
spin_unlock_irqrestore(&port->port_lock, flags);
- set_bit(CH_OPENED, &port->channel_sts);
+ set_bit(CH_CONNECTED, &port->channel_sts);
if (port->gtype == USB_GADGET_RMNET) {
gr = port->port_usb;
if (gr && gr->connect)
@@ -89,7 +96,7 @@
}
break;
case SMUX_DISCONNECTED:
- clear_bit(CH_OPENED, &port->channel_sts);
+ clear_bit(CH_CONNECTED, &port->channel_sts);
break;
case SMUX_READ_DONE:
len = ((struct smux_meta_read *)metadata)->len;
@@ -163,7 +170,7 @@
return -ENODEV;
}
/* drop cpkt if ch is not open */
- if (!test_bit(CH_OPENED, &port->channel_sts)) {
+ if (!test_bit(CH_CONNECTED, &port->channel_sts)) {
port->drp_cpkt_cnt++;
return 0;
}
@@ -209,7 +216,7 @@
port->cbits_tomodem = cbits;
- if (!test_bit(CH_OPENED, &port->channel_sts))
+ if (!test_bit(CH_CONNECTED, &port->channel_sts))
return;
pr_debug("%s: ctrl_tomodem:%d\n", __func__, cbits);
@@ -228,12 +235,21 @@
pr_debug("%s: port:%p\n", __func__, port);
+ if (test_bit(CH_OPENED, &port->channel_sts)) {
+ retval = wait_for_completion_timeout(
+ &port->close_complete, 3 * HZ);
+ if (retval == 0) {
+ pr_err("%s: smux close timedout\n", __func__);
+ return;
+ }
+ }
retval = msm_smux_open(port->ch_id, port->ctxt, smux_control_event,
rx_control_buffer);
if (retval < 0) {
pr_err(" %s smux_open failed\n", __func__);
return;
}
+ set_bit(CH_OPENED, &port->channel_sts);
}
@@ -283,8 +299,9 @@
if (!test_bit(CH_OPENED, &port->channel_sts))
return;
+ INIT_COMPLETION(port->close_complete);
msm_smux_close(port->ch_id);
- clear_bit(CH_OPENED, &port->channel_sts);
+ clear_bit(CH_CONNECTED, &port->channel_sts);
}
void ghsuart_ctrl_disconnect(void *gptr, int port_num)
@@ -363,6 +380,7 @@
gr->disconnect(gr);
clear_bit(CH_OPENED, &port->channel_sts);
+ clear_bit(CH_CONNECTED, &port->channel_sts);
not_ready:
clear_bit(CH_READY, &port->channel_sts);
@@ -403,6 +421,7 @@
spin_lock_init(&port->port_lock);
+ init_completion(&port->close_complete);
INIT_WORK(&port->connect_w, ghsuart_ctrl_connect_w);
INIT_WORK(&port->disconnect_w, ghsuart_ctrl_disconnect_w);
diff --git a/drivers/usb/gadget/u_data_hsuart.c b/drivers/usb/gadget/u_data_hsuart.c
index 8005a4a..c342437 100644
--- a/drivers/usb/gadget/u_data_hsuart.c
+++ b/drivers/usb/gadget/u_data_hsuart.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
@@ -20,6 +20,7 @@
#include <linux/debugfs.h>
#include <linux/bitops.h>
#include <linux/smux.h>
+#include <linux/completion.h>
#include <mach/usb_gadget_xport.h>
@@ -72,6 +73,7 @@
#define CH_OPENED 0
#define CH_READY 1
+#define CH_CONNECTED 2
struct ghsuart_data_port {
/* port */
@@ -86,6 +88,7 @@
spinlock_t port_lock;
void *port_usb;
+ struct completion close_complete;
/* data transfer queues */
unsigned int tx_q_size;
struct list_head tx_idle;
@@ -502,8 +505,12 @@
pr_debug("%s: event type: %s ", __func__, event_string(event_type));
switch (event_type) {
+ case SMUX_LOCAL_CLOSED:
+ clear_bit(CH_OPENED, &port->channel_sts);
+ complete(&port->close_complete);
+ break;
case SMUX_CONNECTED:
- set_bit(CH_OPENED, &port->channel_sts);
+ set_bit(CH_CONNECTED, &port->channel_sts);
if (port->gtype == USB_GADGET_SERIAL) {
cbits = msm_smux_tiocm_get(port->ch_id);
if (cbits & ACM_CTRL_DCD) {
@@ -515,7 +522,7 @@
ghsuart_data_start_io(port);
break;
case SMUX_DISCONNECTED:
- clear_bit(CH_OPENED, &port->channel_sts);
+ clear_bit(CH_CONNECTED, &port->channel_sts);
break;
case SMUX_READ_DONE:
skb = meta_read->pkt_priv;
@@ -589,6 +596,14 @@
pr_debug("%s: port:%p\n", __func__, port);
+ if (test_bit(CH_OPENED, &port->channel_sts)) {
+ ret = wait_for_completion_timeout(
+ &port->close_complete, 3 * HZ);
+ if (ret == 0) {
+ pr_err("%s: smux close timedout\n", __func__);
+ return;
+ }
+ }
ret = msm_smux_open(port->ch_id, port, &ghsuart_notify_event,
&ghsuart_get_rx_buffer);
if (ret) {
@@ -596,6 +611,7 @@
__func__, port->ch_id, ret);
return;
}
+ set_bit(CH_OPENED, &port->channel_sts);
}
static void ghsuart_data_disconnect_w(struct work_struct *w)
@@ -606,8 +622,9 @@
if (!test_bit(CH_OPENED, &port->channel_sts))
return;
+ INIT_COMPLETION(port->close_complete);
msm_smux_close(port->ch_id);
- clear_bit(CH_OPENED, &port->channel_sts);
+ clear_bit(CH_CONNECTED, &port->channel_sts);
}
static void ghsuart_data_free_buffers(struct ghsuart_data_port *port)
@@ -710,6 +727,7 @@
clear_bit(CH_READY, &port->channel_sts);
clear_bit(CH_OPENED, &port->channel_sts);
+ clear_bit(CH_CONNECTED, &port->channel_sts);
return 0;
}
@@ -747,7 +765,7 @@
port->cbits_tomodem = cbits;
- if (!test_bit(CH_OPENED, &port->channel_sts))
+ if (!test_bit(CH_CONNECTED, &port->channel_sts))
return;
/* if DTR is high, update latest modem info to Host */
@@ -786,6 +804,7 @@
spin_lock_init(&port->rx_lock);
spin_lock_init(&port->tx_lock);
+ init_completion(&port->close_complete);
INIT_WORK(&port->connect_w, ghsuart_data_connect_w);
INIT_WORK(&port->disconnect_w, ghsuart_data_disconnect_w);
INIT_WORK(&port->write_tohost_w, ghsuart_data_write_tohost);
@@ -994,6 +1013,7 @@
"#PORT:%d port#: %p\n"
"data_ch_open: %d\n"
"data_ch_ready: %d\n"
+ "data_ch_connected: %d\n"
"\n******UL INFO*****\n\n"
"dpkts_to_modem: %lu\n"
"tomodem_drp_cnt: %u\n"
@@ -1003,6 +1023,7 @@
i, port,
test_bit(CH_OPENED, &port->channel_sts),
test_bit(CH_READY, &port->channel_sts),
+ test_bit(CH_CONNECTED, &port->channel_sts),
port->to_modem,
port->tomodem_drp_cnt,
port->rx_skb_q.qlen,
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index 9961d00..325c2b5 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -557,6 +557,11 @@
switch (retval) {
default:
DBG(dev, "tx queue err %d\n", retval);
+ new_req->length = 0;
+ spin_lock(&dev->req_lock);
+ list_add_tail(&new_req->list,
+ &dev->tx_reqs);
+ spin_unlock(&dev->req_lock);
break;
case 0:
spin_lock(&dev->req_lock);
@@ -566,7 +571,13 @@
}
} else {
spin_lock(&dev->req_lock);
- list_add(&new_req->list, &dev->tx_reqs);
+ /*
+ * Put the idle request at the back of the
+ * queue. The xmit function will put the
+ * unfinished request at the beginning of the
+ * queue.
+ */
+ list_add_tail(&new_req->list, &dev->tx_reqs);
spin_unlock(&dev->req_lock);
}
} else {
@@ -787,6 +798,8 @@
if (retval) {
if (!multi_pkt_xfer)
dev_kfree_skb_any(skb);
+ else
+ req->length = 0;
drop:
dev->net->stats.tx_dropped++;
spin_lock_irqsave(&dev->req_lock, flags);
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index a09b1ab..20425e2d 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -1229,6 +1229,12 @@
} else {
ehci_writel(ehci, temp, status_reg);
}
+
+ if (ehci->reset_delay) {
+ spin_unlock_irqrestore(&ehci->lock, flags);
+ msleep(ehci->reset_delay);
+ spin_lock_irqsave(&ehci->lock, flags);
+ }
break;
/* For downstream facing ports (these): one hub port is put
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index ef45d49..253658e 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -1878,6 +1878,8 @@
&pdata->strobe_pad_offset);
of_property_read_u32(node, "hsic,data-pad-offset",
&pdata->data_pad_offset);
+ of_property_read_u32(node, "hsic,reset-delay",
+ &pdata->reset_delay);
of_property_read_u32(node, "hsic,log2-itc",
&pdata->log2_irq_thresh);
if (pdata->log2_irq_thresh > 6)
@@ -1981,6 +1983,9 @@
mehci->ehci.resume_sof_bug = 1;
}
+ if (pdata->reset_delay)
+ mehci->ehci.reset_delay = pdata->reset_delay;
+
mehci->ehci.pool_64_bit_align = pdata->pool_64_bit_align;
mehci->enable_hbm = pdata->enable_hbm;
diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c
index 0b89dd0..8b1f3a8 100644
--- a/drivers/usb/host/ehci-msm.c
+++ b/drivers/usb/host/ehci-msm.c
@@ -1,6 +1,6 @@
/* ehci-msm.c - HSUSB Host Controller Driver Implementation
*
- * Copyright (c) 2008-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2008-2013, The Linux Foundation. All rights reserved.
*
* Partly derived from ehci-fsl.c and ehci-hcd.c
* Copyright (c) 2000-2004 by David Brownell
@@ -48,7 +48,7 @@
return retval;
/* bursts of unspecified length. */
- writel(0, USB_AHBBURST);
+ writel_relaxed(0, USB_AHBBURST);
/* Use the AHB transactor */
writel_relaxed(0x08, USB_AHBMODE);
/* Disable streaming mode and select host mode */
@@ -60,6 +60,10 @@
USB_PHY_CTRL2);
}
+ /* Disable ULPI_TX_PKT_EN_CLR_FIX which is valid only for HSIC */
+ writel_relaxed(readl_relaxed(USB_GENCONFIG2) & ~(1<<19),
+ USB_GENCONFIG2);
+
ehci_port_power(ehci, 1);
return 0;
}
@@ -260,15 +264,23 @@
static int ehci_msm_pm_resume(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
+ int ret;
dev_dbg(dev, "ehci-msm PM resume\n");
if (!hcd->rh_registered)
return 0;
- ehci_prepare_ports_for_controller_resume(hcd_to_ehci(hcd));
+ /* Notify OTG to bring hw out of LPM before restoring wakeup flags */
+ ret = usb_phy_set_suspend(phy, 0);
+ if (ret)
+ return ret;
- return usb_phy_set_suspend(phy, 0);
+ ehci_prepare_ports_for_controller_resume(hcd_to_ehci(hcd));
+ /* Resume root-hub to handle USB event if any else initiate LPM again */
+ usb_hcd_resume_root_hub(hcd);
+
+ return ret;
}
#endif
diff --git a/drivers/usb/host/ehci-msm2.c b/drivers/usb/host/ehci-msm2.c
index 60788f5..0aecaad 100644
--- a/drivers/usb/host/ehci-msm2.c
+++ b/drivers/usb/host/ehci-msm2.c
@@ -25,9 +25,12 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/err.h>
-#include <linux/wakelock.h>
+#include <linux/pm_wakeup.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/irq.h>
#include <linux/usb/ulpi.h>
#include <linux/usb/msm_hsusb_hw.h>
@@ -63,11 +66,16 @@
bool pmic_gpio_dp_irq_enabled;
uint32_t pmic_gpio_int_cnt;
atomic_t pm_usage_cnt;
- struct wake_lock wlock;
+ struct wakeup_source ws;
struct work_struct phy_susp_fail_work;
int async_irq;
bool async_irq_enabled;
uint32_t async_int_cnt;
+ int resume_gpio;
+
+ int wakeup_int_cnt;
+ bool wakeup_irq_enabled;
+ int wakeup_irq;
};
static inline struct msm_hcd *hcd_to_mhcd(struct usb_hcd *hcd)
@@ -602,8 +610,8 @@
msm_ehci_vbus_power(mhcd, 1);
}
-#define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000)
-#define PHY_RESUME_TIMEOUT_USEC (100 * 1000)
+#define PHY_SUSP_TIMEOUT_MSEC 500
+#define PHY_RESUME_TIMEOUT_USEC (100 * 1000)
#ifdef CONFIG_PM_SLEEP
static int msm_ehci_suspend(struct msm_hcd *mhcd)
@@ -620,24 +628,42 @@
disable_irq(hcd->irq);
- /* 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
- * mode (LPM). Hence poll for 500 msec and reset the PHY and link
- * in failure case.
+ /* make sure we don't race against a remote wakeup */
+ if (test_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags) ||
+ readl_relaxed(USB_PORTSC) & PORT_RESUME) {
+ dev_dbg(mhcd->dev, "wakeup pending, aborting suspend\n");
+ enable_irq(hcd->irq);
+ return -EBUSY;
+ }
+
+ /* If port is enabled wait 5ms for PHCD to come up. Reset PHY
+ * and link if it fails to do so.
+ * If port is not enabled set the PHCD bit and poll for it to
+ * come up with in 500ms. Reset phy and link if it fails to do so.
*/
portsc = readl_relaxed(USB_PORTSC);
- if (!(portsc & PORTSC_PHCD)) {
- writel_relaxed(portsc | PORTSC_PHCD,
- USB_PORTSC);
+ if (portsc & PORT_PE) {
- timeout = jiffies + usecs_to_jiffies(PHY_SUSPEND_TIMEOUT_USEC);
+ usleep_range(5000, 5000);
+
+ if (!(readl_relaxed(USB_PORTSC) & PORTSC_PHCD)) {
+ dev_err(mhcd->dev,
+ "Unable to suspend PHY. portsc: %8x\n",
+ readl_relaxed(USB_PORTSC));
+ goto reset_phy_and_link;
+ }
+ } else {
+ writel_relaxed(portsc | PORTSC_PHCD, USB_PORTSC);
+
+ timeout = jiffies + msecs_to_jiffies(PHY_SUSP_TIMEOUT_MSEC);
while (!(readl_relaxed(USB_PORTSC) & PORTSC_PHCD)) {
if (time_after(jiffies, timeout)) {
- dev_err(mhcd->dev, "Unable to suspend PHY\n");
- schedule_work(&mhcd->phy_susp_fail_work);
- return -ETIMEDOUT;
+ dev_err(mhcd->dev,
+ "Unable to suspend PHY. portsc: %8x\n",
+ readl_relaxed(USB_PORTSC));
+ goto reset_phy_and_link;
}
- udelay(1);
+ usleep_range(10000, 10000);
}
}
@@ -646,9 +672,14 @@
* power mode (LPM). This interrupt is level triggered. So USB IRQ
* line must be disabled till async interrupt enable bit is cleared
* in USBCMD register. Assert STP (ULPI interface STOP signal) to
- * block data communication from PHY.
+ * block data communication from PHY. Enable asynchronous interrupt
+ * only when wakeup gpio IRQ is not present.
*/
- writel_relaxed(readl_relaxed(USB_USBCMD) | ASYNC_INTR_CTRL |
+ if (mhcd->wakeup_irq)
+ writel_relaxed(readl_relaxed(USB_USBCMD) | ULPI_STP_CTRL,
+ USB_USBCMD);
+ else
+ writel_relaxed(readl_relaxed(USB_USBCMD) | ASYNC_INTR_CTRL |
ULPI_STP_CTRL, USB_USBCMD);
/*
@@ -674,6 +705,13 @@
atomic_set(&mhcd->in_lpm, 1);
enable_irq(hcd->irq);
+
+ if (mhcd->wakeup_irq) {
+ mhcd->wakeup_irq_enabled = 1;
+ enable_irq_wake(mhcd->wakeup_irq);
+ enable_irq(mhcd->wakeup_irq);
+ }
+
if (mhcd->pmic_gpio_dp_irq) {
mhcd->pmic_gpio_dp_irq_enabled = 1;
enable_irq_wake(mhcd->pmic_gpio_dp_irq);
@@ -684,11 +722,15 @@
enable_irq_wake(mhcd->async_irq);
enable_irq(mhcd->async_irq);
}
- wake_unlock(&mhcd->wlock);
+ pm_relax(mhcd->dev);
dev_info(mhcd->dev, "EHCI USB in low power mode\n");
return 0;
+
+reset_phy_and_link:
+ schedule_work(&mhcd->phy_susp_fail_work);
+ return -ETIMEDOUT;
}
static int msm_ehci_resume(struct msm_hcd *mhcd)
@@ -709,15 +751,24 @@
disable_irq_nosync(mhcd->pmic_gpio_dp_irq);
mhcd->pmic_gpio_dp_irq_enabled = 0;
}
+
spin_lock_irqsave(&mhcd->wakeup_lock, flags);
if (mhcd->async_irq_enabled) {
disable_irq_wake(mhcd->async_irq);
disable_irq_nosync(mhcd->async_irq);
mhcd->async_irq_enabled = 0;
}
+
+ if (mhcd->wakeup_irq) {
+ if (mhcd->wakeup_irq_enabled) {
+ disable_irq_wake(mhcd->wakeup_irq);
+ disable_irq_nosync(mhcd->wakeup_irq);
+ mhcd->wakeup_irq_enabled = 0;
+ }
+ }
spin_unlock_irqrestore(&mhcd->wakeup_lock, flags);
- wake_lock(&mhcd->wlock);
+ pm_stay_awake(mhcd->dev);
/* Vote for TCXO when waking up the phy */
if (!IS_ERR(mhcd->xo_clk)) {
@@ -784,6 +835,7 @@
struct msm_hcd *mhcd = hcd_to_mhcd(hcd);
if (atomic_read(&mhcd->in_lpm)) {
+ dev_dbg(mhcd->dev, "phy async intr\n");
disable_irq_nosync(hcd->irq);
mhcd->async_int = true;
pm_runtime_get(mhcd->dev);
@@ -802,7 +854,7 @@
dev_dbg(mhcd->dev, "%s: hsusb host remote wakeup interrupt cnt: %u\n",
__func__, mhcd->async_int_cnt);
- wake_lock(&mhcd->wlock);
+ pm_stay_awake(mhcd->dev);
spin_lock(&mhcd->wakeup_lock);
if (mhcd->async_irq_enabled) {
@@ -833,7 +885,7 @@
__func__, mhcd->pmic_gpio_int_cnt);
- wake_lock(&mhcd->wlock);
+ pm_stay_awake(mhcd->dev);
if (mhcd->pmic_gpio_dp_irq_enabled) {
mhcd->pmic_gpio_dp_irq_enabled = 0;
@@ -897,6 +949,20 @@
return 0;
}
+static int msm_ehci_bus_resume_with_gpio(struct usb_hcd *hcd)
+{
+ struct msm_hcd *mhcd = hcd_to_mhcd(hcd);
+ int ret;
+
+ gpio_direction_output(mhcd->resume_gpio, 1);
+
+ ret = ehci_bus_resume(hcd);
+
+ gpio_direction_output(mhcd->resume_gpio, 0);
+
+ return ret;
+}
+
#if defined(CONFIG_DEBUG_FS)
static u32 addr;
#define BUF_SIZE 32
@@ -1072,6 +1138,46 @@
.bus_resume = ehci_bus_resume,
};
+static irqreturn_t msm_hsusb_wakeup_irq(int irq, void *data)
+{
+ struct msm_hcd *mhcd = data;
+ int ret;
+
+ mhcd->wakeup_int_cnt++;
+ dev_dbg(mhcd->dev, "%s: hsic remote wakeup interrupt cnt: %u\n",
+ __func__, mhcd->wakeup_int_cnt);
+
+ pm_stay_awake(mhcd->dev);
+
+ spin_lock(&mhcd->wakeup_lock);
+ if (mhcd->wakeup_irq_enabled) {
+ mhcd->wakeup_irq_enabled = 0;
+ disable_irq_wake(irq);
+ disable_irq_nosync(irq);
+ }
+ spin_unlock(&mhcd->wakeup_lock);
+
+ if (!atomic_read(&mhcd->pm_usage_cnt)) {
+ ret = pm_runtime_get(mhcd->dev);
+ /*
+ * controller runtime resume can race with us.
+ * if we are active (ret == 1) or resuming
+ * (ret == -EINPROGRESS), decrement the
+ * PM usage counter before returning.
+ */
+ if ((ret == 1) || (ret == -EINPROGRESS)) {
+ pm_runtime_put_noidle(mhcd->dev);
+ } else {
+ /* Let khubd know of hub port status change */
+ if (mhcd->ehci.no_selective_suspend)
+ mhcd->ehci.suspended_ports = 1;
+ atomic_set(&mhcd->pm_usage_cnt, 1);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
static int msm_ehci_init_clocks(struct msm_hcd *mhcd, u32 init)
{
int ret = 0;
@@ -1152,6 +1258,12 @@
"qcom,usb2-enable-hsphy2");
of_property_read_u32(node, "qcom,usb2-power-budget",
&pdata->power_budget);
+ pdata->no_selective_suspend = of_property_read_bool(node,
+ "qcom,no-selective-suspend");
+ pdata->resume_gpio = of_get_named_gpio(node, "qcom,resume-gpio", 0);
+ if (pdata->resume_gpio < 0)
+ pdata->resume_gpio = 0;
+
return pdata;
}
@@ -1175,6 +1287,8 @@
if (!pdev->dev.platform_data)
dev_dbg(&pdev->dev, "No platform data given\n");
+ pdata = pdev->dev.platform_data;
+
if (!pdev->dev.dma_mask)
pdev->dev.dma_mask = &ehci_msm_dma_mask;
if (!pdev->dev.coherent_dma_mask)
@@ -1252,6 +1366,22 @@
goto free_xo_handle;
}
+ if (pdata && pdata->resume_gpio) {
+ mhcd->resume_gpio = pdata->resume_gpio;
+ ret = gpio_request(mhcd->resume_gpio, "hsusb_resume");
+ if (ret) {
+ dev_err(&pdev->dev,
+ "resume gpio(%d) request failed:%d\n",
+ mhcd->resume_gpio, ret);
+ mhcd->resume_gpio = 0;
+ } else {
+ msm_hc2_driver.bus_resume =
+ msm_ehci_bus_resume_with_gpio;
+ }
+ }
+
+ spin_lock_init(&mhcd->wakeup_lock);
+
ret = msm_ehci_init_clocks(mhcd, 1);
if (ret) {
dev_err(&pdev->dev, "unable to initialize clocks\n");
@@ -1307,9 +1437,33 @@
!irq_read_line(pdata->dock_connect_irq)))
msm_ehci_vbus_power(mhcd, 1);
+ /* For peripherals directly conneted to downstream port of root hub
+ * and require to drive suspend and resume by controller driver instead
+ * of root hub.
+ */
+ if (pdata)
+ mhcd->ehci.no_selective_suspend = pdata->no_selective_suspend;
+
+ mhcd->wakeup_irq = platform_get_irq_byname(pdev, "wakeup_irq");
+ if (mhcd->wakeup_irq > 0) {
+ dev_dbg(&pdev->dev, "wakeup irq:%d\n", mhcd->wakeup_irq);
+
+ irq_set_status_flags(mhcd->wakeup_irq, IRQ_NOAUTOEN);
+ ret = request_irq(mhcd->wakeup_irq, msm_hsusb_wakeup_irq,
+ IRQF_TRIGGER_HIGH,
+ "msm_hsusb_wakeup", mhcd);
+ if (ret) {
+ dev_err(&pdev->dev, "request_irq(%d) failed:%d\n",
+ mhcd->wakeup_irq, ret);
+ mhcd->wakeup_irq = 0;
+ }
+ } else {
+ mhcd->wakeup_irq = 0;
+ }
+
device_init_wakeup(&pdev->dev, 1);
- wake_lock_init(&mhcd->wlock, WAKE_LOCK_SUSPEND, dev_name(&pdev->dev));
- wake_lock(&mhcd->wlock);
+ wakeup_source_init(&mhcd->ws, dev_name(&pdev->dev));
+ pm_stay_awake(mhcd->dev);
INIT_WORK(&mhcd->phy_susp_fail_work, msm_ehci_phy_susp_fail_work);
/*
* This pdev->dev is assigned parent of root-hub by USB core,
@@ -1351,6 +1505,8 @@
deinit_clocks:
msm_ehci_init_clocks(mhcd, 0);
devote_xo_handle:
+ if (mhcd->resume_gpio)
+ gpio_free(mhcd->resume_gpio);
if (!IS_ERR(mhcd->xo_clk))
clk_disable_unprepare(mhcd->xo_clk);
else
@@ -1386,6 +1542,16 @@
disable_irq_wake(mhcd->async_irq);
free_irq(mhcd->async_irq, mhcd);
}
+
+ if (mhcd->wakeup_irq) {
+ if (mhcd->wakeup_irq_enabled)
+ disable_irq_wake(mhcd->wakeup_irq);
+ free_irq(mhcd->wakeup_irq, mhcd);
+ }
+
+ if (mhcd->resume_gpio)
+ gpio_free(mhcd->resume_gpio);
+
device_init_wakeup(&pdev->dev, 0);
pm_runtime_set_suspended(&pdev->dev);
@@ -1404,7 +1570,7 @@
msm_ehci_init_vddcx(mhcd, 0);
msm_ehci_init_clocks(mhcd, 0);
- wake_lock_destroy(&mhcd->wlock);
+ wakeup_source_trash(&mhcd->ws);
iounmap(hcd->regs);
usb_put_hcd(hcd);
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 0498a6a..7cd945a 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -155,6 +155,7 @@
unsigned resume_sof_bug:1;/*Chip Idea HC*/
unsigned reset_sof_bug:1; /*Chip Idea HC*/
bool disable_cerr;
+ u32 reset_delay;
/* required for usb32 quirk */
#define OHCI_CTRL_HCFS (3 << 6)
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 717103d..bec0356 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -21,6 +21,7 @@
*/
#include <linux/gfp.h>
+#include <linux/slab.h>
#include <asm/unaligned.h>
#include "xhci.h"
@@ -472,6 +473,149 @@
}
}
+static void xhci_single_step_completion(struct urb *urb)
+{
+ struct completion *done = urb->context;
+
+ complete(done);
+}
+
+/*
+ * Allocate a URB and initialize the various fields of it.
+ * This API is used by the single_step_set_feature test of
+ * EHSET where IN packet of the GetDescriptor request is
+ * sent 15secs after the SETUP packet.
+ * Return NULL if failed.
+ */
+static struct urb *xhci_request_single_step_set_feature_urb(
+ struct usb_device *udev,
+ void *dr,
+ void *buf,
+ struct completion *done)
+{
+ struct urb *urb;
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+ struct usb_host_endpoint *ep;
+
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb)
+ return NULL;
+
+ urb->pipe = usb_rcvctrlpipe(udev, 0);
+ ep = udev->ep_in[usb_pipeendpoint(urb->pipe)];
+ if (!ep) {
+ usb_free_urb(urb);
+ return NULL;
+ }
+
+ /*
+ * Initialize the various URB fields as these are used by the HCD
+ * driver to queue it and as well as when completion happens.
+ */
+ urb->ep = ep;
+ urb->dev = udev;
+ urb->setup_packet = dr;
+ urb->transfer_buffer = buf;
+ urb->transfer_buffer_length = USB_DT_DEVICE_SIZE;
+ urb->complete = xhci_single_step_completion;
+ urb->status = -EINPROGRESS;
+ urb->actual_length = 0;
+ urb->transfer_flags = URB_DIR_IN;
+ usb_get_urb(urb);
+ atomic_inc(&urb->use_count);
+ atomic_inc(&urb->dev->urbnum);
+ usb_hcd_map_urb_for_dma(hcd, urb, GFP_KERNEL);
+ urb->context = done;
+ return urb;
+}
+
+/*
+ * This function implements the USB_PORT_FEAT_TEST handling of the
+ * SINGLE_STEP_SET_FEATURE test mode as defined in the Embedded
+ * High-Speed Electrical Test (EHSET) specification. This simply
+ * issues a GetDescriptor control transfer, with an inserted 15-second
+ * delay after the end of the SETUP stage and before the IN token of
+ * the DATA stage is set. The idea is that this gives the test operator
+ * enough time to configure the oscilloscope to perform a measurement
+ * of the response time between the DATA and ACK packets that follow.
+ */
+static int xhci_ehset_single_step_set_feature(struct usb_hcd *hcd, int port)
+{
+ int retval = -ENOMEM;
+ struct usb_ctrlrequest *dr;
+ struct urb *urb;
+ struct usb_device *udev;
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+ struct usb_device_descriptor *buf;
+ unsigned long flags;
+ DECLARE_COMPLETION_ONSTACK(done);
+
+ /* Obtain udev of the rhub's child port */
+ udev = hcd->self.root_hub->children[port];
+ if (!udev) {
+ xhci_err(xhci, "No device attached to the RootHub\n");
+ return -ENODEV;
+ }
+ buf = kmalloc(USB_DT_DEVICE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+ if (!dr) {
+ kfree(buf);
+ return -ENOMEM;
+ }
+
+ /* Fill Setup packet for GetDescriptor */
+ dr->bRequestType = USB_DIR_IN;
+ dr->bRequest = USB_REQ_GET_DESCRIPTOR;
+ dr->wValue = cpu_to_le16(USB_DT_DEVICE << 8);
+ dr->wIndex = 0;
+ dr->wLength = cpu_to_le16(USB_DT_DEVICE_SIZE);
+ urb = xhci_request_single_step_set_feature_urb(udev, dr, buf, &done);
+ if (!urb)
+ goto cleanup;
+
+ /* Now complete just the SETUP stage */
+ spin_lock_irqsave(&xhci->lock, flags);
+ retval = xhci_submit_single_step_set_feature(hcd, urb, 1);
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ if (retval)
+ goto out1;
+
+ if (!wait_for_completion_timeout(&done, msecs_to_jiffies(2000))) {
+ usb_kill_urb(urb);
+ retval = -ETIMEDOUT;
+ xhci_err(xhci, "%s SETUP stage timed out on ep0\n", __func__);
+ goto out1;
+ }
+
+ /* Sleep for 15 seconds; HC will send SOFs during this period */
+ msleep(15 * 1000);
+
+ /* Complete remaining DATA and status stages. Re-use same URB */
+ urb->status = -EINPROGRESS;
+ usb_get_urb(urb);
+ atomic_inc(&urb->use_count);
+ atomic_inc(&urb->dev->urbnum);
+
+ spin_lock_irqsave(&xhci->lock, flags);
+ retval = xhci_submit_single_step_set_feature(hcd, urb, 0);
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ if (!retval && !wait_for_completion_timeout(&done,
+ msecs_to_jiffies(2000))) {
+ usb_kill_urb(urb);
+ retval = -ETIMEDOUT;
+ xhci_err(xhci, "%s IN stage timed out on ep0\n", __func__);
+ }
+out1:
+ usb_free_urb(urb);
+cleanup:
+ kfree(dr);
+ kfree(buf);
+ return retval;
+}
+
int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u16 wIndex, char *buf, u16 wLength)
{
@@ -778,6 +922,11 @@
temp = xhci_readl(xhci, port_array[wIndex] + 1);
temp |= test_mode << 28;
xhci_writel(xhci, temp, port_array[wIndex] + 1);
+ } else if (test_mode == 6) {
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ retval = xhci_ehset_single_step_set_feature(hcd,
+ wIndex);
+ spin_lock_irqsave(&xhci->lock, flags);
} else {
goto error;
}
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 46b5ce4..cc0c1e0 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -37,9 +37,12 @@
if (!pdata)
return;
- else if (pdata->vendor == SYNOPSIS_DWC3_VENDOR &&
- pdata->revision < 0x230A)
+
+ if (pdata->vendor == SYNOPSIS_DWC3_VENDOR && pdata->revision < 0x230A)
xhci->quirks |= XHCI_PORTSC_DELAY;
+
+ if (pdata->vendor == SYNOPSIS_DWC3_VENDOR && pdata->revision == 0x250A)
+ xhci->quirks |= XHCI_RESET_DELAY;
}
/* called during probe() after chip reset completes */
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 323b481..b3f3fa8 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -3215,6 +3215,150 @@
return 0;
}
+/*
+ * Variant of xhci_queue_ctrl_tx() used to implement EHSET
+ * SINGLE_STEP_SET_FEATURE test mode. It differs in that the control
+ * transfer is broken up so that the SETUP stage can happen and call
+ * the URB's completion handler before the DATA/STATUS stages are
+ * executed by the xHC hardware. This assumes the control transfer is a
+ * GetDescriptor, with a DATA stage in the IN direction, and an OUT
+ * STATUS stage.
+ *
+ * This function is called twice, usually with a 15-second delay in between.
+ * - with is_setup==true, the SETUP stage for the control request
+ * (GetDescriptor) is queued in the TRB ring and sent to HW immediately
+ * - with is_setup==false, the DATA and STATUS TRBs are queued and exceuted
+ *
+ * Caller must have locked xhci->lock
+ */
+int xhci_submit_single_step_set_feature(struct usb_hcd *hcd, struct urb *urb,
+ int is_setup)
+{
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+ struct xhci_ring *ep_ring;
+ int num_trbs;
+ int ret;
+ unsigned int slot_id, ep_index;
+ struct usb_ctrlrequest *setup;
+ struct xhci_generic_trb *start_trb;
+ int start_cycle;
+ u32 field, length_field;
+ struct urb_priv *urb_priv;
+ struct xhci_td *td;
+
+ ep_ring = xhci_urb_to_transfer_ring(xhci, urb);
+ if (!ep_ring)
+ return -EINVAL;
+
+ /* Need buffer for data stage */
+ if (urb->transfer_buffer_length <= 0)
+ return -EINVAL;
+
+ /*
+ * Need to copy setup packet into setup TRB, so we can't use the setup
+ * DMA address.
+ */
+ if (!urb->setup_packet)
+ return -EINVAL;
+ setup = (struct usb_ctrlrequest *) urb->setup_packet;
+
+ slot_id = urb->dev->slot_id;
+ ep_index = xhci_get_endpoint_index(&urb->ep->desc);
+
+ urb_priv = kzalloc(sizeof(struct urb_priv) +
+ sizeof(struct xhci_td *), GFP_ATOMIC);
+ if (!urb_priv)
+ return -ENOMEM;
+
+ td = urb_priv->td[0] = kzalloc(sizeof(struct xhci_td), GFP_ATOMIC);
+ if (!td) {
+ kfree(urb_priv);
+ return -ENOMEM;
+ }
+
+ urb_priv->length = 1;
+ urb_priv->td_cnt = 0;
+ urb->hcpriv = urb_priv;
+
+ num_trbs = is_setup ? 1 : 2;
+
+ ret = prepare_transfer(xhci, xhci->devs[slot_id],
+ ep_index, urb->stream_id,
+ num_trbs, urb, 0, GFP_ATOMIC);
+ if (ret < 0) {
+ kfree(td);
+ kfree(urb_priv);
+ return ret;
+ }
+
+ /*
+ * Don't give the first TRB to the hardware (by toggling the cycle bit)
+ * until we've finished creating all the other TRBs. The ring's cycle
+ * state may change as we enqueue the other TRBs, so save it too.
+ */
+ start_trb = &ep_ring->enqueue->generic;
+ start_cycle = ep_ring->cycle_state;
+
+ if (is_setup) {
+ /* Queue only the setup TRB */
+ field = TRB_IDT | TRB_IOC | TRB_TYPE(TRB_SETUP);
+ if (start_cycle == 0)
+ field |= 0x1;
+
+ /* xHCI 1.0 6.4.1.2.1: Transfer Type field */
+ if (xhci->hci_version == 0x100) {
+ if (setup->bRequestType & USB_DIR_IN)
+ field |= TRB_TX_TYPE(TRB_DATA_IN);
+ else
+ field |= TRB_TX_TYPE(TRB_DATA_OUT);
+ }
+
+ /* Save the DMA address of the last TRB in the TD */
+ td->last_trb = ep_ring->enqueue;
+
+ queue_trb(xhci, ep_ring, false,
+ setup->bRequestType | setup->bRequest << 8 |
+ le16_to_cpu(setup->wValue) << 16,
+ le16_to_cpu(setup->wIndex) |
+ le16_to_cpu(setup->wLength) << 16,
+ TRB_LEN(8) | TRB_INTR_TARGET(0),
+ field);
+ } else {
+ /* Queue data TRB */
+ field = TRB_ISP | TRB_TYPE(TRB_DATA);
+ if (start_cycle == 0)
+ field |= 0x1;
+ if (setup->bRequestType & USB_DIR_IN)
+ field |= TRB_DIR_IN;
+
+ length_field = TRB_LEN(urb->transfer_buffer_length) |
+ xhci_td_remainder(urb->transfer_buffer_length) |
+ TRB_INTR_TARGET(0);
+ queue_trb(xhci, ep_ring, true,
+ lower_32_bits(urb->transfer_dma),
+ upper_32_bits(urb->transfer_dma),
+ length_field,
+ field);
+
+ /* Save the DMA address of the last TRB in the TD */
+ td->last_trb = ep_ring->enqueue;
+
+ /* Queue status TRB */
+ field = TRB_IOC | TRB_TYPE(TRB_STATUS);
+ if (!(setup->bRequestType & USB_DIR_IN))
+ field |= TRB_DIR_IN;
+
+ queue_trb(xhci, ep_ring, false,
+ 0,
+ 0,
+ TRB_INTR_TARGET(0),
+ field | ep_ring->cycle_state);
+ }
+
+ giveback_first_trb(xhci, slot_id, ep_index, 0, start_cycle, start_trb);
+ return 0;
+}
+
static int count_isoc_trbs_needed(struct xhci_hcd *xhci,
struct urb *urb, int i)
{
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index df41b4f..ad09139 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -4055,6 +4055,9 @@
retval = xhci_reset(xhci);
if (retval)
goto error;
+
+ if (xhci->quirks & XHCI_RESET_DELAY)
+ usleep_range(350, 1000);
xhci_dbg(xhci, "Reset complete\n");
temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params);
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 8f3651b..1ba51c2 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1497,6 +1497,14 @@
* (16.66 ns x 5 = 84ns) ~100ns after writing to the PORTSC register.
*/
#define XHCI_PORTSC_DELAY (1 << 10)
+/*
+ * In Synopsis DWC3 controller, XHCI RESET takes some time complete. If PIPE
+ * RESET is not complete by the time USBCMD.RUN bit is set then HC fails to
+ * carry out SS transfers.
+ *
+ * The workaround is to give worst case pipe delay ~350us after resetting HC
+ */
+#define XHCI_RESET_DELAY (1 << 11)
unsigned int num_active_eps;
unsigned int limit_active_eps;
/* There are two roothubs to keep track of bus suspend info for */
@@ -1823,4 +1831,8 @@
struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx);
struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, unsigned int ep_index);
+/* EHSET */
+int xhci_submit_single_step_set_feature(struct usb_hcd *hcd, struct urb *urb,
+ int is_setup);
+
#endif /* __LINUX_XHCI_HCD_H */
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index c0b2771..de7fc02 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -36,6 +36,7 @@
#include <linux/usb/quirks.h>
#include <linux/usb/msm_hsusb.h>
#include <linux/usb/msm_hsusb_hw.h>
+#include <linux/usb/msm_ext_chg.h>
#include <linux/regulator/consumer.h>
#include <linux/mfd/pm8xxx/pm8921-charger.h>
#include <linux/mfd/pm8xxx/misc.h>
@@ -87,6 +88,11 @@
MODULE_PARM_DESC(lpm_disconnect_thresh,
"Delay before entering LPM on USB disconnect");
+static bool floated_charger_enable;
+module_param(floated_charger_enable , bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(floated_charger_enable,
+ "Whether to enable floated charger");
+
static DECLARE_COMPLETION(pmic_vbus_init);
static struct msm_otg *the_msm_otg;
static bool debug_aca_enabled;
@@ -880,9 +886,10 @@
struct msm_otg_platform_data *pdata = motg->pdata;
int cnt = 0;
bool host_bus_suspend, device_bus_suspend, dcp, prop_charger;
+ bool floated_charger;
u32 phy_ctrl_val = 0, cmd_val;
unsigned ret;
- u32 portsc;
+ u32 portsc, config2;
if (atomic_read(&motg->in_lpm))
return 0;
@@ -898,6 +905,18 @@
motg->caps & ALLOW_LPM_ON_DEV_SUSPEND;
dcp = motg->chg_type == USB_DCP_CHARGER;
prop_charger = motg->chg_type == USB_PROPRIETARY_CHARGER;
+ floated_charger = motg->chg_type == USB_FLOATED_CHARGER;
+
+ /* Enable line state difference wakeup fix for only device and host
+ * bus suspend scenarios. Otherwise PHY can not be suspended when
+ * a charger that pulls DP/DM high is connected.
+ */
+ config2 = readl_relaxed(USB_GENCONFIG2);
+ if (device_bus_suspend)
+ config2 |= GENCFG2_LINESTATE_DIFF_WAKEUP_EN;
+ else
+ config2 &= ~GENCFG2_LINESTATE_DIFF_WAKEUP_EN;
+ writel_relaxed(config2, USB_GENCONFIG2);
/*
* Abort suspend when,
@@ -906,7 +925,8 @@
*/
if ((test_bit(B_SESS_VLD, &motg->inputs) && !device_bus_suspend &&
- !dcp && !prop_charger) || test_bit(A_BUS_REQ, &motg->inputs)) {
+ !dcp && !prop_charger && !floated_charger) ||
+ test_bit(A_BUS_REQ, &motg->inputs)) {
enable_irq(motg->irq);
return -EBUSY;
}
@@ -984,8 +1004,9 @@
* BC1.2 spec mandates PD to enable VDP_SRC when charging from DCP.
* PHY retention and collapse can not happen with VDP_SRC enabled.
*/
- if (motg->caps & ALLOW_PHY_RETENTION && !host_bus_suspend &&
- !device_bus_suspend && !dcp) {
+ if (motg->caps & ALLOW_PHY_RETENTION && !device_bus_suspend && !dcp &&
+ (!host_bus_suspend || ((motg->caps & ALLOW_HOST_PHY_RETENTION)
+ && (pdata->dpdm_pulldown_added || !(portsc & PORTSC_CCS))))) {
phy_ctrl_val = readl_relaxed(USB_PHY_CTRL);
if (motg->pdata->otg_control == OTG_PHY_CONTROL) {
/* Enable PHY HV interrupts to wake MPM/Link */
@@ -996,7 +1017,8 @@
else
phy_ctrl_val |= PHY_OTGSESSVLDHV_INTEN;
}
-
+ 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;
}
@@ -1013,7 +1035,8 @@
}
/* usb phy no more require TCXO clock, hence vote for TCXO disable */
- if (!host_bus_suspend) {
+ if (!host_bus_suspend || ((motg->caps & ALLOW_HOST_PHY_RETENTION) &&
+ (pdata->dpdm_pulldown_added || !(portsc & PORTSC_CCS)))) {
if (!IS_ERR(motg->xo_clk)) {
clk_disable_unprepare(motg->xo_clk);
motg->lpm_flags |= XO_SHUTDOWN;
@@ -1054,12 +1077,17 @@
if (pdata->otg_control == OTG_PHY_CONTROL &&
pdata->mpm_otgsessvld_int)
msm_mpm_set_pin_wake(pdata->mpm_otgsessvld_int, 1);
+ if (host_bus_suspend && pdata->mpm_dpshv_int)
+ msm_mpm_set_pin_wake(pdata->mpm_dpshv_int, 1);
+ if (host_bus_suspend && pdata->mpm_dmshv_int)
+ msm_mpm_set_pin_wake(pdata->mpm_dmshv_int, 1);
}
if (bus)
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
msm_otg_bus_vote(motg, USB_NO_PERF_VOTE);
+ motg->host_bus_suspend = host_bus_suspend;
atomic_set(&motg->in_lpm, 1);
/* Enable ASYNC IRQ (if present) during LPM */
if (motg->async_irq)
@@ -1085,6 +1113,9 @@
if (!atomic_read(&motg->in_lpm))
return 0;
+ if (motg->pdata->delay_lpm_hndshk_on_disconnect)
+ msm_bam_notify_lpm_resume();
+
disable_irq(motg->irq);
wake_lock(&motg->wlock);
@@ -1127,6 +1158,7 @@
/* Disable PHY HV interrupts */
phy_ctrl_val &=
~(PHY_IDHV_INTEN | PHY_OTGSESSVLDHV_INTEN);
+ phy_ctrl_val &= ~(PHY_CLAMP_DPDMSE_EN);
writel_relaxed(phy_ctrl_val, USB_PHY_CTRL);
motg->lpm_flags &= ~PHY_RETENTIONED;
}
@@ -1174,6 +1206,10 @@
if (pdata->otg_control == OTG_PHY_CONTROL &&
pdata->mpm_otgsessvld_int)
msm_mpm_set_pin_wake(pdata->mpm_otgsessvld_int, 0);
+ if (motg->host_bus_suspend && pdata->mpm_dpshv_int)
+ msm_mpm_set_pin_wake(pdata->mpm_dpshv_int, 0);
+ if (motg->host_bus_suspend && pdata->mpm_dmshv_int)
+ msm_mpm_set_pin_wake(pdata->mpm_dmshv_int, 0);
}
if (bus)
set_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
@@ -2188,6 +2224,8 @@
/* Clear alt interrupt latch and enable bits */
ulpi_write(phy, 0x1F, 0x92);
ulpi_write(phy, 0x1F, 0x95);
+ /* re-enable DP and DM pull down resistors */
+ ulpi_write(phy, 0x6, 0xB);
break;
default:
break;
@@ -2211,6 +2249,7 @@
case USB_ACA_C_CHARGER: return "USB_ACA_C_CHARGER";
case USB_ACA_DOCK_CHARGER: return "USB_ACA_DOCK_CHARGER";
case USB_PROPRIETARY_CHARGER: return "USB_PROPRIETARY_CHARGER";
+ case USB_FLOATED_CHARGER: return "USB_FLOATED_CHARGER";
default: return "INVALID_CHARGER";
}
}
@@ -2224,6 +2263,7 @@
struct msm_otg *motg = container_of(w, struct msm_otg, chg_work.work);
struct usb_phy *phy = &motg->phy;
bool is_dcd = false, tmout, vout, is_aca;
+ static bool dcd;
u32 line_state, dm_vlgc;
unsigned long delay;
@@ -2268,6 +2308,10 @@
motg->dcd_time += MSM_CHG_DCD_POLL_TIME;
tmout = motg->dcd_time >= MSM_CHG_DCD_TIMEOUT;
if (is_dcd || tmout) {
+ if (is_dcd)
+ dcd = true;
+ else
+ dcd = false;
msm_chg_disable_dcd(motg);
msm_chg_enable_primary_det(motg);
delay = MSM_CHG_PRIMARY_DET_TIME;
@@ -2306,6 +2350,8 @@
if (line_state) /* DP > VLGC or/and DM > VLGC */
motg->chg_type = USB_PROPRIETARY_CHARGER;
+ else if (!dcd && floated_charger_enable)
+ motg->chg_type = USB_FLOATED_CHARGER;
else
motg->chg_type = USB_SDP_CHARGER;
@@ -2421,11 +2467,46 @@
}
}
+static void msm_otg_wait_for_ext_chg_done(struct msm_otg *motg)
+{
+ struct usb_phy *phy = &motg->phy;
+ unsigned long t;
+
+ /*
+ * Defer next cable connect event till external charger
+ * detection is completed.
+ */
+
+ if (motg->ext_chg_active) {
+
+ pr_debug("before msm_otg ext chg wait\n");
+
+ t = wait_for_completion_timeout(&motg->ext_chg_wait,
+ msecs_to_jiffies(3000));
+ if (!t)
+ pr_err("msm_otg ext chg wait timeout\n");
+ else
+ pr_debug("msm_otg ext chg wait done\n");
+ }
+
+ if (motg->ext_chg_opened) {
+ if (phy->flags & ENABLE_DP_MANUAL_PULLUP) {
+ ulpi_write(phy, ULPI_MISC_A_VBUSVLDEXT |
+ ULPI_MISC_A_VBUSVLDEXTSEL,
+ ULPI_CLR(ULPI_MISC_A));
+ }
+ /* clear charging register bits */
+ ulpi_write(phy, 0x3F, 0x86);
+ /* re-enable DP and DM pull-down resistors*/
+ ulpi_write(phy, 0x6, 0xB);
+ }
+}
+
static void msm_otg_sm_work(struct work_struct *w)
{
struct msm_otg *motg = container_of(w, struct msm_otg, sm_work);
struct usb_otg *otg = motg->phy.otg;
- bool work = 0, srp_reqd;
+ bool work = 0, srp_reqd, dcp;
pm_runtime_resume(otg->phy->dev);
pr_debug("%s work\n", otg_state_string(otg->phy->state));
@@ -2475,10 +2556,20 @@
case USB_DCP_CHARGER:
/* Enable VDP_SRC */
ulpi_write(otg->phy, 0x2, 0x85);
+ if (motg->ext_chg_opened) {
+ init_completion(
+ &motg->ext_chg_wait);
+ motg->ext_chg_active = true;
+ }
/* fall through */
case USB_PROPRIETARY_CHARGER:
msm_otg_notify_charger(motg,
IDEV_CHG_MAX);
+ pm_runtime_put_sync(otg->phy->dev);
+ break;
+ case USB_FLOATED_CHARGER:
+ msm_otg_notify_charger(motg,
+ IDEV_CHG_MAX);
pm_runtime_put_noidle(otg->phy->dev);
pm_runtime_suspend(otg->phy->dev);
break;
@@ -2534,9 +2625,12 @@
clear_bit(B_FALSE_SDP, &motg->inputs);
clear_bit(A_BUS_REQ, &motg->inputs);
cancel_delayed_work_sync(&motg->chg_work);
+ dcp = (motg->chg_type == USB_DCP_CHARGER);
motg->chg_state = USB_CHG_STATE_UNDEFINED;
motg->chg_type = USB_INVALID_CHARGER;
msm_otg_notify_charger(motg, 0);
+ if (dcp)
+ msm_otg_wait_for_ext_chg_done(motg);
msm_otg_reset(otg->phy);
/*
* There is a small window where ID interrupt
@@ -3511,14 +3605,20 @@
else
val->intval = POWER_SUPPLY_SCOPE_DEVICE;
break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+ val->intval = motg->voltage_max;
+ break;
case POWER_SUPPLY_PROP_CURRENT_MAX:
- val->intval = motg->current_max;
+ val->intval = motg->current_max;
break;
/* Reflect USB enumeration */
case POWER_SUPPLY_PROP_PRESENT:
case POWER_SUPPLY_PROP_ONLINE:
val->intval = motg->online;
break;
+ case POWER_SUPPLY_PROP_TYPE:
+ val->intval = psy->type;
+ break;
default:
return -EINVAL;
}
@@ -3540,9 +3640,15 @@
case POWER_SUPPLY_PROP_ONLINE:
motg->online = val->intval;
break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+ motg->voltage_max = val->intval;
+ break;
case POWER_SUPPLY_PROP_CURRENT_MAX:
motg->current_max = val->intval;
break;
+ case POWER_SUPPLY_PROP_TYPE:
+ psy->type = val->intval;
+ break;
default:
return -EINVAL;
}
@@ -3557,6 +3663,7 @@
switch (psp) {
case POWER_SUPPLY_PROP_PRESENT:
case POWER_SUPPLY_PROP_ONLINE:
+ case POWER_SUPPLY_PROP_VOLTAGE_MAX:
case POWER_SUPPLY_PROP_CURRENT_MAX:
return 1;
default:
@@ -3573,8 +3680,10 @@
static enum power_supply_property otg_pm_power_props_usb[] = {
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX,
POWER_SUPPLY_PROP_CURRENT_MAX,
POWER_SUPPLY_PROP_SCOPE,
+ POWER_SUPPLY_PROP_TYPE,
};
const struct file_operations msm_otg_bus_fops = {
@@ -3795,6 +3904,199 @@
return 0;
}
+static int msm_otg_ext_chg_open(struct inode *inode, struct file *file)
+{
+ struct msm_otg *motg = the_msm_otg;
+
+ pr_debug("msm_otg ext chg open\n");
+
+ motg->ext_chg_opened = true;
+ file->private_data = (void *)motg;
+ return 0;
+}
+
+static long
+msm_otg_ext_chg_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct msm_otg *motg = file->private_data;
+ struct msm_usb_chg_info info = {0};
+ int ret = 0, val;
+
+ switch (cmd) {
+ case MSM_USB_EXT_CHG_INFO:
+ info.chg_block_type = USB_CHG_BLOCK_ULPI;
+ info.page_offset = motg->io_res->start & ~PAGE_MASK;
+ /* mmap() works on PAGE granularity */
+ info.length = PAGE_SIZE;
+
+ if (copy_to_user((void __user *)arg, &info, sizeof(info))) {
+ pr_err("%s: copy to user failed\n\n", __func__);
+ ret = -EFAULT;
+ }
+ break;
+ case MSM_USB_EXT_CHG_BLOCK_LPM:
+ if (get_user(val, (int __user *)arg)) {
+ pr_err("%s: get_user failed\n\n", __func__);
+ ret = -EFAULT;
+ break;
+ }
+ pr_debug("%s: LPM block request %d\n", __func__, val);
+ if (val) { /* block LPM */
+ if (motg->chg_type == USB_DCP_CHARGER) {
+ /*
+ * If device is already suspended, resume it.
+ * The PM usage counter is incremented in
+ * runtime resume method. if device is not
+ * suspended, cancel the scheduled suspend
+ * and increment the PM usage counter.
+ */
+ if (pm_runtime_suspended(motg->phy.dev))
+ pm_runtime_resume(motg->phy.dev);
+ else
+ pm_runtime_get_sync(motg->phy.dev);
+ } else {
+ motg->ext_chg_active = false;
+ complete(&motg->ext_chg_wait);
+ ret = -ENODEV;
+ }
+ } else {
+ motg->ext_chg_active = false;
+ complete(&motg->ext_chg_wait);
+ pm_runtime_put(motg->phy.dev);
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int msm_otg_ext_chg_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct msm_otg *motg = file->private_data;
+ unsigned long vsize = vma->vm_end - vma->vm_start;
+ int ret;
+
+ if (vma->vm_pgoff || vsize > PAGE_SIZE)
+ return -EINVAL;
+
+ vma->vm_pgoff = __phys_to_pfn(motg->io_res->start);
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ ret = io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+ vsize, vma->vm_page_prot);
+ if (ret < 0) {
+ pr_err("%s: failed with return val %d\n", __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int msm_otg_ext_chg_release(struct inode *inode, struct file *file)
+{
+ struct msm_otg *motg = file->private_data;
+
+ pr_debug("msm_otg ext chg release\n");
+
+ motg->ext_chg_opened = false;
+
+ return 0;
+}
+
+static const struct file_operations msm_otg_ext_chg_fops = {
+ .owner = THIS_MODULE,
+ .open = msm_otg_ext_chg_open,
+ .unlocked_ioctl = msm_otg_ext_chg_ioctl,
+ .mmap = msm_otg_ext_chg_mmap,
+ .release = msm_otg_ext_chg_release,
+};
+
+static int msm_otg_setup_ext_chg_cdev(struct msm_otg *motg)
+{
+ int ret;
+
+ if (motg->pdata->enable_sec_phy || motg->pdata->mode == USB_HOST ||
+ motg->pdata->otg_control != OTG_PMIC_CONTROL ||
+ psy != &motg->usb_psy) {
+ pr_debug("usb ext chg is not supported by msm otg\n");
+ return -ENODEV;
+ }
+
+ ret = alloc_chrdev_region(&motg->ext_chg_dev, 0, 1, "usb_ext_chg");
+ if (ret < 0) {
+ pr_err("Fail to allocate usb ext char dev region\n");
+ return ret;
+ }
+ motg->ext_chg_class = class_create(THIS_MODULE, "msm_ext_chg");
+ if (ret < 0) {
+ pr_err("Fail to create usb ext chg class\n");
+ goto unreg_chrdev;
+ }
+ cdev_init(&motg->ext_chg_cdev, &msm_otg_ext_chg_fops);
+ motg->ext_chg_cdev.owner = THIS_MODULE;
+
+ ret = cdev_add(&motg->ext_chg_cdev, motg->ext_chg_dev, 1);
+ if (ret < 0) {
+ pr_err("Fail to add usb ext chg cdev\n");
+ goto destroy_class;
+ }
+ motg->ext_chg_device = device_create(motg->ext_chg_class,
+ NULL, motg->ext_chg_dev, NULL,
+ "usb_ext_chg");
+ if (IS_ERR(motg->ext_chg_device)) {
+ pr_err("Fail to create usb ext chg device\n");
+ ret = PTR_ERR(motg->ext_chg_device);
+ motg->ext_chg_device = NULL;
+ goto del_cdev;
+ }
+
+ init_completion(&motg->ext_chg_wait);
+ pr_debug("msm otg ext chg cdev setup success\n");
+ return 0;
+
+del_cdev:
+ cdev_del(&motg->ext_chg_cdev);
+destroy_class:
+ class_destroy(motg->ext_chg_class);
+unreg_chrdev:
+ unregister_chrdev_region(motg->ext_chg_dev, 1);
+
+ return ret;
+}
+
+static ssize_t dpdm_pulldown_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct msm_otg *motg = the_msm_otg;
+ struct msm_otg_platform_data *pdata = motg->pdata;
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", pdata->dpdm_pulldown_added ?
+ "enabled" : "disabled");
+}
+
+static ssize_t dpdm_pulldown_enable_store(struct device *dev,
+ struct device_attribute *attr, const char
+ *buf, size_t size)
+{
+ struct msm_otg *motg = the_msm_otg;
+ struct msm_otg_platform_data *pdata = motg->pdata;
+
+ if (!strnicmp(buf, "enable", 6)) {
+ pdata->dpdm_pulldown_added = true;
+ return size;
+ } else if (!strnicmp(buf, "disable", 7)) {
+ pdata->dpdm_pulldown_added = false;
+ return size;
+ }
+
+ return -EINVAL;
+}
+
+static DEVICE_ATTR(dpdm_pulldown_enable, S_IRUGO | S_IWUSR,
+ dpdm_pulldown_enable_show, dpdm_pulldown_enable_store);
+
struct msm_otg_platform_data *msm_otg_dt_to_pdata(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
@@ -3844,6 +4146,10 @@
of_property_read_u32(node, "qcom,hsusb-log2-itc",
&pdata->log2_itc);
+ of_property_read_u32(node, "qcom,hsusb-otg-mpm-dpsehv-int",
+ &pdata->mpm_dpshv_int);
+ of_property_read_u32(node, "qcom,hsusb-otg-mpm-dmsehv-int",
+ &pdata->mpm_dmshv_int);
pdata->pmic_id_irq = platform_get_irq_byname(pdev, "pmic_id_irq");
if (pdata->pmic_id_irq < 0)
pdata->pmic_id_irq = 0;
@@ -3992,6 +4298,7 @@
goto put_pclk;
}
+ motg->io_res = res;
motg->regs = ioremap(res->start, resource_size(res));
if (!motg->regs) {
dev_err(&pdev->dev, "ioremap failed\n");
@@ -4145,6 +4452,11 @@
if (pdata->otg_control == OTG_PHY_CONTROL && pdata->mpm_otgsessvld_int)
msm_mpm_enable_pin(pdata->mpm_otgsessvld_int, 1);
+ if (pdata->mpm_dpshv_int)
+ msm_mpm_enable_pin(pdata->mpm_dpshv_int, 1);
+ if (pdata->mpm_dmshv_int)
+ msm_mpm_enable_pin(pdata->mpm_dmshv_int, 1);
+
phy->init = msm_otg_reset;
phy->set_power = msm_otg_set_power;
phy->set_suspend = msm_otg_set_suspend;
@@ -4208,6 +4520,11 @@
if (motg->pdata->otg_control == OTG_PHY_CONTROL)
motg->caps = ALLOW_PHY_RETENTION |
ALLOW_PHY_REGULATORS_LPM;
+
+ if (motg->pdata->mpm_dpshv_int || motg->pdata->mpm_dmshv_int)
+ motg->caps |= ALLOW_HOST_PHY_RETENTION;
+ device_create_file(&pdev->dev,
+ &dev_attr_dpdm_pulldown_enable);
}
if (motg->pdata->enable_lpm_on_dev_suspend)
@@ -4247,6 +4564,10 @@
if (legacy_power_supply && pdata->otg_control == OTG_PMIC_CONTROL)
pm8921_charger_register_vbus_sn(&msm_otg_set_vbus_state);
+ ret = msm_otg_setup_ext_chg_cdev(motg);
+ if (ret)
+ dev_dbg(&pdev->dev, "fail to setup cdev\n");
+
return 0;
remove_phy:
@@ -4308,6 +4629,13 @@
if (phy->otg->host || phy->otg->gadget)
return -EBUSY;
+ if (!motg->ext_chg_device) {
+ device_destroy(motg->ext_chg_class, motg->ext_chg_dev);
+ cdev_del(&motg->ext_chg_cdev);
+ class_destroy(motg->ext_chg_class);
+ unregister_chrdev_region(motg->ext_chg_dev, 1);
+ }
+
if (pdev->dev.of_node)
msm_otg_setup_devices(pdev, motg->pdata->mode, false);
if (motg->pdata->otg_control == OTG_PMIC_CONTROL)
@@ -4331,10 +4659,19 @@
usb_set_transceiver(NULL);
free_irq(motg->irq, motg);
+ if ((motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY) &&
+ (motg->pdata->mpm_dpshv_int || motg->pdata->mpm_dmshv_int))
+ device_remove_file(&pdev->dev,
+ &dev_attr_dpdm_pulldown_enable);
if (motg->pdata->otg_control == OTG_PHY_CONTROL &&
motg->pdata->mpm_otgsessvld_int)
msm_mpm_enable_pin(motg->pdata->mpm_otgsessvld_int, 0);
+ if (motg->pdata->mpm_dpshv_int)
+ msm_mpm_enable_pin(motg->pdata->mpm_dpshv_int, 0);
+ if (motg->pdata->mpm_dmshv_int)
+ msm_mpm_enable_pin(motg->pdata->mpm_dmshv_int, 0);
+
/*
* Put PHY in low power mode.
*/
@@ -4394,8 +4731,25 @@
if (phy->state == OTG_STATE_UNDEFINED)
return -EAGAIN;
- else
- return 0;
+
+ if (motg->ext_chg_active) {
+ dev_dbg(dev, "Deferring LPM\n");
+ /*
+ * Charger detection may happen in user space.
+ * Delay entering LPM by 3 sec. Otherwise we
+ * have to exit LPM when user space begins
+ * charger detection.
+ *
+ * This timer will be canceled when user space
+ * votes against LPM by incrementing PM usage
+ * counter. We enter low power mode when
+ * PM usage counter is decremented.
+ */
+ pm_schedule_suspend(dev, 3000);
+ return -EAGAIN;
+ }
+
+ return 0;
}
static int msm_otg_runtime_suspend(struct device *dev)
diff --git a/drivers/video/msm/mdss/Makefile b/drivers/video/msm/mdss/Makefile
index 43eda51..017fa8e 100644
--- a/drivers/video/msm/mdss/Makefile
+++ b/drivers/video/msm/mdss/Makefile
@@ -24,6 +24,7 @@
mdss-dsi-objs += msm_mdss_io_8974.o
obj-$(CONFIG_FB_MSM_MDSS) += mdss-dsi.o
obj-$(CONFIG_FB_MSM_MDSS) += mdss_edp.o
+obj-$(CONFIG_FB_MSM_MDSS) += mdss_edp_aux.o
obj-$(CONFIG_FB_MSM_MDSS) += mdss_io_util.o
obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_tx.o
diff --git a/drivers/video/msm/mdss/dsi_host_v2.c b/drivers/video/msm/mdss/dsi_host_v2.c
index 96f0f8c..f2de17d 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.c
+++ b/drivers/video/msm/mdss/dsi_host_v2.c
@@ -857,6 +857,26 @@
return ret;
}
+static int msm_dsi_cont_on(struct mdss_panel_data *pdata)
+{
+ struct mdss_panel_info *pinfo;
+ int ret = 0;
+
+ pr_debug("%s:\n", __func__);
+
+ pinfo = &pdata->panel_info;
+ ret = msm_dsi_regulator_enable();
+ if (ret) {
+ pr_err("%s: DSI power on failed\n", __func__);
+ return ret;
+ }
+
+ msm_dsi_ahb_ctrl(1);
+ msm_dsi_prepare_clocks();
+ msm_dsi_clk_enable();
+ return 0;
+}
+
static int __devinit msm_dsi_probe(struct platform_device *pdev)
{
struct dsi_interface intf;
@@ -925,6 +945,7 @@
dsi_host_private->dis_dev = pdev->dev;
intf.on = msm_dsi_on;
intf.off = msm_dsi_off;
+ intf.cont_on = msm_dsi_cont_on;
intf.op_mode_config = msm_dsi_op_mode_config;
intf.tx = msm_dsi_cmds_tx;
intf.rx = msm_dsi_cmds_rx;
diff --git a/drivers/video/msm/mdss/dsi_io_v2.c b/drivers/video/msm/mdss/dsi_io_v2.c
index 273fb54..f0ad511 100644
--- a/drivers/video/msm/mdss/dsi_io_v2.c
+++ b/drivers/video/msm/mdss/dsi_io_v2.c
@@ -320,7 +320,7 @@
static void msm_dsi_phy_regulator_init(unsigned char *ctrl_base,
struct mdss_dsi_phy_ctrl *pd)
{
- MIPI_OUTP(ctrl_base + DSI_DSIPHY_LDO_CNTRL, 0x04);
+ MIPI_OUTP(ctrl_base + DSI_DSIPHY_LDO_CNTRL, 0x25);
MIPI_OUTP(ctrl_base + DSI_DSIPHY_REGULATOR_CTRL_0, pd->regulator[0]);
MIPI_OUTP(ctrl_base + DSI_DSIPHY_REGULATOR_CTRL_1, pd->regulator[1]);
MIPI_OUTP(ctrl_base + DSI_DSIPHY_REGULATOR_CTRL_2, pd->regulator[2]);
diff --git a/drivers/video/msm/mdss/dsi_panel_v2.c b/drivers/video/msm/mdss/dsi_panel_v2.c
index 5c164e4..022d911 100644
--- a/drivers/video/msm/mdss/dsi_panel_v2.c
+++ b/drivers/video/msm/mdss/dsi_panel_v2.c
@@ -163,7 +163,20 @@
pr_debug("%s: enable = %d\n", __func__, enable);
- if (enable) {
+ if (enable == 2) {
+ dsi_panel_power(1);
+ gpio_request(panel_private->rst_gpio, "panel_reset");
+ if (gpio_is_valid(panel_private->disp_en_gpio)) {
+ gpio_request(panel_private->disp_en_gpio,
+ "panel_enable");
+ }
+ if (gpio_is_valid(panel_private->video_mode_gpio)) {
+ gpio_request(panel_private->video_mode_gpio,
+ "panel_video_mdoe");
+ }
+ if (gpio_is_valid(panel_private->te_gpio))
+ gpio_request(panel_private->te_gpio, "panel_te");
+ } else if (enable == 1) {
dsi_panel_power(1);
gpio_request(panel_private->rst_gpio, "panel_reset");
gpio_set_value(panel_private->rst_gpio, 1);
diff --git a/drivers/video/msm/mdss/dsi_v2.c b/drivers/video/msm/mdss/dsi_v2.c
index 5833796..686ec01 100644
--- a/drivers/video/msm/mdss/dsi_v2.c
+++ b/drivers/video/msm/mdss/dsi_v2.c
@@ -26,15 +26,6 @@
static int dsi_off(struct mdss_panel_data *pdata)
{
int rc = 0;
- if (!panel_common_data || !pdata)
- return -ENODEV;
-
- if (dsi_intf.op_mode_config)
- dsi_intf.op_mode_config(DSI_CMD_MODE, pdata);
-
- pr_debug("panel off commands\n");
- if (panel_common_data->off)
- panel_common_data->off(pdata);
pr_debug("turn off dsi controller\n");
if (dsi_intf.off)
@@ -44,11 +35,6 @@
pr_err("mdss_dsi_off DSI failed %d\n", rc);
return rc;
}
-
- pr_debug("turn off panel power\n");
- if (panel_common_data->reset)
- panel_common_data->reset(pdata, 0);
-
return rc;
}
@@ -56,13 +42,7 @@
{
int rc = 0;
- pr_debug("dsi_on\n");
-
- if (!panel_common_data || !pdata)
- return -ENODEV;
-
-
- pr_debug("dsi_on DSI controller ont\n");
+ pr_debug("dsi_on DSI controller on\n");
if (dsi_intf.on)
rc = dsi_intf.on(pdata);
@@ -70,16 +50,52 @@
pr_err("mdss_dsi_on DSI failed %d\n", rc);
return rc;
}
- pr_debug("dsi_on power on panel\n");
- if (panel_common_data->reset)
- panel_common_data->reset(pdata, 1);
+ return rc;
+}
+static int dsi_panel_handler(struct mdss_panel_data *pdata, int enable)
+{
+ int rc = 0;
- pr_debug("dsi_on DSI panel ont\n");
- if (panel_common_data->on)
- rc = panel_common_data->on(pdata);
+ pr_debug("dsi_panel_handler enable=%d\n", enable);
+ if (!panel_common_data || !pdata)
+ return -ENODEV;
+
+ if (enable) {
+ if (panel_common_data->reset)
+ panel_common_data->reset(pdata, 1);
+
+ if (panel_common_data->on)
+ rc = panel_common_data->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);
+
+ if (panel_common_data->off)
+ panel_common_data->off(pdata);
+
+ if (panel_common_data->reset)
+ panel_common_data->reset(pdata, 0);
+ }
+ return rc;
+}
+
+static int dsi_splash_on(struct mdss_panel_data *pdata)
+{
+ int rc = 0;
+
+ pr_debug("%s:\n", __func__);
+
+ if (panel_common_data->reset)
+ panel_common_data->reset(pdata, 2);
+
+ if (dsi_intf.cont_on)
+ rc = dsi_intf.cont_on(pdata);
if (rc) {
- pr_err("mdss_dsi_on panel failed %d\n", rc);
+ pr_err("mdss_dsi_on DSI failed %d\n", rc);
return rc;
}
return rc;
@@ -96,12 +112,21 @@
}
switch (event) {
- case MDSS_EVENT_PANEL_ON:
+ case MDSS_EVENT_UNBLANK:
rc = dsi_on(pdata);
break;
- case MDSS_EVENT_PANEL_OFF:
+ case MDSS_EVENT_BLANK:
rc = dsi_off(pdata);
break;
+ case MDSS_EVENT_PANEL_ON:
+ rc = dsi_panel_handler(pdata, 1);
+ break;
+ case MDSS_EVENT_PANEL_OFF:
+ rc = dsi_panel_handler(pdata, 0);
+ break;
+ case MDSS_EVENT_CONT_SPLASH_BEGIN:
+ rc = dsi_splash_on(pdata);
+ break;
default:
pr_debug("%s: unhandled event=%d\n", __func__, event);
break;
diff --git a/drivers/video/msm/mdss/dsi_v2.h b/drivers/video/msm/mdss/dsi_v2.h
index 54b772b..96dd390 100644
--- a/drivers/video/msm/mdss/dsi_v2.h
+++ b/drivers/video/msm/mdss/dsi_v2.h
@@ -198,6 +198,7 @@
struct dsi_interface {
int (*on)(struct mdss_panel_data *pdata);
int (*off)(struct mdss_panel_data *pdata);
+ int (*cont_on)(struct mdss_panel_data *pdata);
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);
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index 91e70a7..f6f722e 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -161,12 +161,19 @@
{
int i = 0;
struct mdp3_hw_resource *mdata = (struct mdp3_hw_resource *)ptr;
- u32 mdp_interrupt = MDP3_REG_READ(MDP3_REG_INTR_STATUS);
+ u32 mdp_interrupt = 0;
+ spin_lock(&mdata->irq_lock);
+ 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);
pr_debug("mdp3_irq_handler irq=%d\n", mdp_interrupt);
- spin_lock(&mdata->irq_lock);
mdp_interrupt &= mdata->irq_mask;
while (mdp_interrupt && i < MDP3_MAX_INTR) {
@@ -183,7 +190,6 @@
void mdp3_irq_enable(int type)
{
unsigned long flag;
- int irqEnabled = 0;
pr_debug("mdp3_irq_enable type=%d\n", type);
spin_lock_irqsave(&mdp3_res->irq_lock, flag);
@@ -193,11 +199,10 @@
spin_unlock_irqrestore(&mdp3_res->irq_lock, flag);
return;
}
- irqEnabled = mdp3_res->irq_mask;
+
mdp3_res->irq_mask |= BIT(type);
MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, mdp3_res->irq_mask);
- if (!irqEnabled)
- enable_irq(mdp3_res->irq);
+
spin_unlock_irqrestore(&mdp3_res->irq_lock, flag);
}
@@ -220,8 +225,6 @@
if (mdp3_res->irq_ref_count[type] == 0) {
mdp3_res->irq_mask &= ~BIT(type);
MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, mdp3_res->irq_mask);
- if (!mdp3_res->irq_mask)
- disable_irq_nosync(mdp3_res->irq);
}
}
@@ -229,7 +232,7 @@
{
unsigned long flag;
- pr_debug("interrupt %d callback n", type);
+ pr_debug("interrupt %d callback\n", type);
spin_lock_irqsave(&mdp3_res->irq_lock, flag);
if (cb)
mdp3_res->callbacks[type] = *cb;
@@ -240,6 +243,30 @@
return 0;
}
+void mdp3_irq_register(void)
+{
+ unsigned long flag;
+
+ pr_debug("mdp3_irq_register\n");
+ spin_lock_irqsave(&mdp3_res->irq_lock, flag);
+ enable_irq(mdp3_res->irq);
+ spin_unlock_irqrestore(&mdp3_res->irq_lock, flag);
+}
+
+void mdp3_irq_deregister(void)
+{
+ unsigned long flag;
+
+ pr_debug("mdp3_irq_deregister\n");
+ 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);
+}
+
static int mdp3_bus_scale_register(void)
{
int i;
@@ -932,6 +959,21 @@
return rc;
}
+int mdp3_iommu_is_attached(int client)
+{
+ struct mdp3_iommu_ctx_map *context_map;
+ int context = MDP3_IOMMU_CTX_DMA_0;
+
+ if (!mdp3_res->iommu_contexts)
+ return 0;
+
+ if (client == MDP3_CLIENT_PPP)
+ context = MDP3_IOMMU_CTX_PPP_0;
+
+ context_map = mdp3_res->iommu_contexts + context;
+ return context_map->attached;
+}
+
static int mdp3_init(struct msm_fb_data_type *mfd)
{
int rc;
@@ -955,6 +997,139 @@
return xres * bpp;
}
+void mdp3_fbmem_clear(void)
+{
+ if (mdp3_res->ion_handle && mdp3_res->virt) {
+ pr_debug("mdp3_fbmem_clear\n");
+ memset(mdp3_res->virt, 0, mdp3_res->size);
+ }
+}
+
+static int mdp3_alloc(size_t size, void **virt, unsigned long *phys)
+{
+ int ret = 0;
+
+ if (mdp3_res->ion_handle) {
+ pr_debug("memory already alloc\n");
+ *virt = mdp3_res->virt;
+ *phys = mdp3_res->phys;
+ return 0;
+ }
+
+ mdp3_res->ion_handle = ion_alloc(mdp3_res->ion_client, size,
+ SZ_1M,
+ ION_HEAP(ION_QSECOM_HEAP_ID), 0);
+
+ if (!IS_ERR_OR_NULL(mdp3_res->ion_handle)) {
+ *virt = ion_map_kernel(mdp3_res->ion_client,
+ mdp3_res->ion_handle);
+ if (IS_ERR(*virt)) {
+ pr_err("map kernel error\n");
+ goto ion_map_kernel_err;
+ }
+
+ ret = ion_phys(mdp3_res->ion_client, mdp3_res->ion_handle,
+ phys, &size);
+ if (ret) {
+ pr_err("%s ion_phys error\n", __func__);
+ goto ion_map_phys_err;
+ }
+
+ mdp3_res->virt = *virt;
+ mdp3_res->phys = *phys;
+ mdp3_res->size = size;
+ } else {
+ pr_err("%s ion alloc fail\n", __func__);
+ mdp3_res->ion_handle = NULL;
+ return -ENOMEM;
+ }
+
+ return 0;
+
+ion_map_phys_err:
+ ion_unmap_kernel(mdp3_res->ion_client, mdp3_res->ion_handle);
+ion_map_kernel_err:
+ ion_free(mdp3_res->ion_client, mdp3_res->ion_handle);
+ mdp3_res->ion_handle = NULL;
+ mdp3_res->virt = NULL;
+ mdp3_res->phys = 0;
+ mdp3_res->size = 0;
+ return -ENOMEM;
+}
+
+static int mdp3_fbmem_alloc(struct msm_fb_data_type *mfd)
+{
+ int ret = -ENOMEM, dom;
+ void *virt = NULL;
+ unsigned long phys = 0;
+ size_t size;
+ u32 yres = mfd->fbi->var.yres_virtual;
+
+ size = PAGE_ALIGN(mfd->fbi->fix.line_length * yres);
+
+ if (mfd->index != 0) {
+ mfd->fbi->screen_base = virt;
+ mfd->fbi->fix.smem_start = phys;
+ mfd->fbi->fix.smem_len = 0;
+ return 0;
+ }
+
+ ret = mdp3_alloc(size, &virt, &phys);
+ if (ret) {
+ pr_err("fail to allocate fb memory\n");
+ return ret;
+ }
+
+ dom = (mdp3_res->domains + MDP3_IOMMU_DOMAIN)->domain_idx;
+
+ ret = ion_map_iommu(mdp3_res->ion_client, mdp3_res->ion_handle,
+ dom, 0, SZ_4K, 0, &mfd->iova,
+ (unsigned long *)&size, 0, 0);
+
+ if (ret) {
+ pr_err("%s map IOMMU error\n", __func__);
+ goto ion_map_iommu_err;
+ }
+
+ pr_debug("allocating %u bytes at %p (%lx phys) for fb %d\n",
+ size, virt, phys, mfd->index);
+
+ mfd->fbi->screen_base = virt;
+ mfd->fbi->fix.smem_start = phys;
+ mfd->fbi->fix.smem_len = size;
+ return 0;
+
+ion_map_iommu_err:
+ ion_unmap_kernel(mdp3_res->ion_client, mdp3_res->ion_handle);
+ ion_free(mdp3_res->ion_client, mdp3_res->ion_handle);
+ mdp3_res->ion_handle = NULL;
+ mdp3_res->virt = NULL;
+ mdp3_res->phys = 0;
+ mdp3_res->size = 0;
+ return -ENOMEM;
+}
+
+void mdp3_fbmem_free(struct msm_fb_data_type *mfd)
+{
+ pr_debug("mdp3_fbmem_free\n");
+ if (mdp3_res->ion_handle) {
+ int dom = (mdp3_res->domains + MDP3_IOMMU_DOMAIN)->domain_idx;
+
+ ion_unmap_kernel(mdp3_res->ion_client, mdp3_res->ion_handle);
+ ion_unmap_iommu(mdp3_res->ion_client, mdp3_res->ion_handle,
+ dom, 0);
+ ion_free(mdp3_res->ion_client, mdp3_res->ion_handle);
+ mdp3_res->ion_handle = NULL;
+ mdp3_res->virt = NULL;
+ mdp3_res->phys = 0;
+ mdp3_res->size = 0;
+ mfd->fbi->screen_base = 0;
+ mfd->fbi->fix.smem_start = 0;
+ mfd->fbi->fix.smem_len = 0;
+ mfd->iova = 0;
+ }
+}
+
struct mdp3_dma *mdp3_get_dma_pipe(int capability)
{
int i;
@@ -990,12 +1165,138 @@
return mdp3_res->domains[MDP3_IOMMU_DOMAIN].domain_idx;
}
+int mdp3_continuous_splash_copy(struct mdss_panel_data *pdata)
+{
+ unsigned long splash_phys, phys;
+ void *splash_virt, *virt;
+ u32 height, width, rgb_size, stride;
+ size_t size;
+ int rc;
+
+ rgb_size = MDP3_REG_READ(MDP3_REG_DMA_P_SIZE);
+ stride = MDP3_REG_READ(MDP3_REG_DMA_P_IBUF_Y_STRIDE);
+ stride = stride & 0x3FFF;
+ splash_phys = MDP3_REG_READ(MDP3_REG_DMA_P_IBUF_ADDR);
+
+ height = (rgb_size >> 16) & 0xffff;
+ width = rgb_size & 0xffff;
+ size = PAGE_ALIGN(height * stride * 2);
+ pr_debug("splash_height=%d splash_width=%d Buffer size=%d\n",
+ height, width, size);
+
+ rc = mdp3_alloc(size, &virt, &phys);
+ if (rc) {
+ pr_err("fail to allocate memory for continuous splash image\n");
+ return rc;
+ }
+
+ splash_virt = ioremap(splash_phys, stride * height);
+ memcpy(virt, splash_virt, stride * height);
+ iounmap(splash_virt);
+ MDP3_REG_WRITE(MDP3_REG_DMA_P_IBUF_ADDR, phys);
+
+ return 0;
+}
+
+static int mdp3_is_display_on(struct mdss_panel_data *pdata)
+{
+ int rc = 0;
+ u32 status;
+
+ mdp3_clk_update(MDP3_CLK_AHB, 1);
+ mdp3_clk_update(MDP3_CLK_CORE, 1);
+
+ if (pdata->panel_info.type == MIPI_VIDEO_PANEL) {
+ status = MDP3_REG_READ(MDP3_REG_DSI_VIDEO_EN);
+ rc = status & 0x1;
+ } else {
+ status = MDP3_REG_READ(MDP3_REG_DMA_P_START);
+ rc = status & 01;
+ }
+
+ mdp3_clk_update(MDP3_CLK_AHB, 0);
+ mdp3_clk_update(MDP3_CLK_CORE, 0);
+ return rc;
+}
+
+static int mdp3_continuous_splash_on(struct mdss_panel_data *pdata)
+{
+ struct mdss_panel_info *panel_info = &pdata->panel_info;
+ int ab, ib, rc;
+
+ pr_debug("mdp3__continuous_splash_on\n");
+
+ rc = mdp3_clk_enable(1);
+ if (rc) {
+ pr_err("fail to enable clk\n");
+ return rc;
+ }
+
+ ab = panel_info->xres * panel_info->yres * 4;
+ ab *= panel_info->mipi.frame_rate;
+ ib = (ab * 3) / 2;
+ rc = mdp3_bus_scale_set_quota(MDP3_CLIENT_DMA_P, ab, ib);
+ if (rc) {
+ pr_err("fail to request bus bandwidth\n");
+ goto splash_on_err;
+ }
+
+ rc = mdp3_ppp_init();
+ if (rc) {
+ pr_err("ppp init failed\n");
+ goto splash_on_err;
+ }
+
+ rc = mdp3_continuous_splash_copy(pdata);
+ if (rc) {
+ pr_err("fail to copy continuous splash image\n");
+ goto splash_on_err;
+ }
+
+ mdp3_irq_register();
+
+ if (pdata->event_handler) {
+ rc = pdata->event_handler(pdata, MDSS_EVENT_CONT_SPLASH_BEGIN,
+ NULL);
+ if (rc) {
+ pr_err("MDSS_EVENT_CONT_SPLASH_BEGIN event fail\n");
+ goto splash_on_err;
+ }
+ }
+
+ if (panel_info->type == MIPI_VIDEO_PANEL)
+ mdp3_res->intf[MDP3_DMA_OUTPUT_SEL_DSI_VIDEO].active = 1;
+ else
+ mdp3_res->intf[MDP3_DMA_OUTPUT_SEL_DSI_CMD].active = 1;
+ return 0;
+
+splash_on_err:
+ mdp3_clk_enable(0);
+ return rc;
+}
+
+static int mdp3_panel_register_done(struct mdss_panel_data *pdata)
+{
+ int rc = 0;
+
+ if (pdata->panel_info.cont_splash_enabled) {
+ if (!mdp3_is_display_on(pdata)) {
+ pr_err("continuous splash, but bootloader is not\n");
+ return 0;
+ }
+ rc = mdp3_continuous_splash_on(pdata);
+ }
+ return rc;
+}
+
static int mdp3_probe(struct platform_device *pdev)
{
int rc;
static struct msm_mdp_interface mdp3_interface = {
.init_fnc = mdp3_init,
.fb_mem_get_iommu_domain = mdp3_fb_mem_get_iommu_domain,
+ .fb_mem_alloc_fnc = mdp3_fbmem_alloc,
+ .panel_register_done = mdp3_panel_register_done,
.fb_stride = mdp3_fb_stride,
};
diff --git a/drivers/video/msm/mdss/mdp3.h b/drivers/video/msm/mdss/mdp3.h
index 1afae01..03416c7 100644
--- a/drivers/video/msm/mdss/mdp3.h
+++ b/drivers/video/msm/mdss/mdp3.h
@@ -110,6 +110,10 @@
struct ion_client *ion_client;
struct mdp3_iommu_domain_map *domains;
struct mdp3_iommu_ctx_map *iommu_contexts;
+ struct ion_handle *ion_handle;
+ void *virt;
+ unsigned long phys;
+ size_t size;
struct mdp3_dma dma[MDP3_DMA_MAX];
struct mdp3_intf intf[MDP3_DMA_OUTPUT_SEL_MAX];
@@ -141,6 +145,8 @@
void mdp3_irq_disable(int type);
void mdp3_irq_disable_nosync(int type);
int mdp3_set_intr_callback(u32 type, struct mdp3_intr_cb *cb);
+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_bus_scale_set_quota(int client, u64 ab_quota, u64 ib_quota);
@@ -148,6 +154,10 @@
int mdp3_get_img(struct msmfb_data *img, struct mdp3_img_data *data);
int mdp3_iommu_enable(int client);
int mdp3_iommu_disable(int client);
+int mdp3_iommu_is_attached(int client);
+void mdp3_fbmem_free(struct msm_fb_data_type *mfd);
+void mdp3_fbmem_clear(void);
+
#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 f43d1ed..f77a2b3 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -351,7 +351,11 @@
cfg.dsi_cmd.dsi_cmd_tg_intf_sel = 0;
} else
return -EINVAL;
- rc = mdp3_intf_init(intf, &cfg);
+
+ if (intf->config)
+ rc = intf->config(intf, &cfg);
+ else
+ rc = -EINVAL;
return rc;
}
@@ -390,7 +394,10 @@
(MDP3_DMA_OUTPUT_COMP_BITS_8 << 2)|
MDP3_DMA_OUTPUT_COMP_BITS_8;
- rc = mdp3_dma_init(dma, &sourceConfig, &outputConfig);
+ if (dma->dma_config)
+ rc = dma->dma_config(dma, &sourceConfig, &outputConfig);
+ else
+ rc = -EINVAL;
return rc;
}
@@ -413,6 +420,11 @@
goto on_error;
}
+ if (mdp3_session->intf->active) {
+ pr_debug("continuous splash screen, initialized already\n");
+ goto on_error;
+ }
+
rc = mdp3_iommu_enable(MDP3_CLIENT_DMA_P);
if (rc) {
pr_err("fail to attach MDP DMA SMMU\n");
@@ -427,8 +439,10 @@
}
panel = mdp3_session->panel;
- if (panel->event_handler)
- rc = panel->event_handler(panel, MDSS_EVENT_PANEL_ON, NULL);
+ if (panel->event_handler) {
+ rc = panel->event_handler(panel, MDSS_EVENT_UNBLANK, NULL);
+ rc |= panel->event_handler(panel, MDSS_EVENT_PANEL_ON, NULL);
+ }
if (rc) {
pr_err("fail to turn on the panel\n");
goto on_error;
@@ -439,6 +453,8 @@
goto on_error;
}
+ mdp3_irq_register();
+
rc = mdp3_ctrl_dma_init(mfd, mdp3_session->dma);
if (rc) {
pr_err("dma init failed\n");
@@ -457,6 +473,12 @@
goto on_error;
}
+ mdp3_fbmem_clear();
+
+ if (panel->set_backlight)
+ panel->set_backlight(panel, panel->panel_info.bl_max);
+
+ pr_debug("mdp3_ctrl_on dma start\n");
if (mfd->fbi->screen_base) {
rc = mdp3_session->dma->start(mdp3_session->dma,
mdp3_session->intf);
@@ -488,6 +510,7 @@
return -ENODEV;
}
+ panel = mdp3_session->panel;
mutex_lock(&mdp3_session->lock);
if (!mdp3_session->status) {
@@ -495,30 +518,39 @@
goto off_error;
}
- pr_debug("mdp3_ctrl_off stop mdp3 dma engine\n");
-
mdp3_histogram_stop(mdp3_session, MDP_BLOCK_DMA_P);
- rc = mdp3_session->dma->stop(mdp3_session->dma, mdp3_session->intf);
+ pr_debug("mdp3_ctrl_off turn panel off\n");
+ if (panel->set_backlight)
+ panel->set_backlight(panel, 0);
- if (rc)
- pr_err("fail to stop the MDP3 dma\n");
-
- pr_debug("mdp3_ctrl_off stop dsi panel and controller\n");
- panel = mdp3_session->panel;
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");
- pr_debug("mdp3_ctrl_off release bus and clock\n");
- rc = mdp3_ctrl_res_req_bus(mfd, 0);
+ rc = mdp3_session->dma->stop(mdp3_session->dma, mdp3_session->intf);
if (rc)
- pr_err("mdp bus resource release failed\n");
+ pr_err("fail to stop the MDP3 dma\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");
+ 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 release bus\n");
+ rc = mdp3_ctrl_res_req_bus(mfd, 0);
+ if (rc)
+ pr_err("mdp bus resource release failed\n");
+
rc = mdp3_iommu_disable(MDP3_CLIENT_DMA_P);
if (rc)
pr_err("fail to dettach MDP DMA SMMU\n");
@@ -653,6 +685,12 @@
return -EPERM;
}
+ if (!mdp3_iommu_is_attached(MDP3_CLIENT_DMA_P)) {
+ pr_debug("continuous splash screen, IOMMU not attached\n");
+ mdp3_ctrl_off(mfd);
+ mdp3_ctrl_on(mfd);
+ }
+
mutex_lock(&mdp3_session->lock);
data = mdp3_bufq_pop(&mdp3_session->bufq_in);
@@ -666,6 +704,9 @@
if (mdp3_bufq_count(&mdp3_session->bufq_out) > 2) {
data = mdp3_bufq_pop(&mdp3_session->bufq_out);
mdp3_put_img(data);
+
+ if (mfd->fbi->screen_base)
+ mdp3_fbmem_free(mfd);
}
mutex_unlock(&mdp3_session->lock);
@@ -694,6 +735,12 @@
return;
}
+ if (!mdp3_iommu_is_attached(MDP3_CLIENT_DMA_P)) {
+ pr_debug("continuous splash screen, IOMMU not attached\n");
+ mdp3_ctrl_off(mfd);
+ mdp3_ctrl_on(mfd);
+ }
+
mutex_lock(&mdp3_session->lock);
fbi = mfd->fbi;
@@ -850,7 +897,7 @@
ret = session->dma->get_histo(session->dma);
if (ret) {
- pr_err("mdp3_histogram_collect error = %d\n", ret);
+ pr_debug("mdp3_histogram_collect error = %d\n", ret);
return ret;
}
@@ -899,11 +946,53 @@
return ret;
}
+static int mdp3_csc_config(struct mdp3_session_data *session,
+ struct mdp_csc_cfg_data *data)
+{
+ struct mdp3_dma_color_correct_config config;
+ struct mdp3_dma_ccs ccs;
+ int ret = -EINVAL;
+
+ if (!data->csc_data.csc_mv || !data->csc_data.csc_pre_bv ||
+ !data->csc_data.csc_post_bv || !data->csc_data.csc_pre_lv ||
+ !data->csc_data.csc_post_lv) {
+ pr_err("%s : Invalid csc vectors", __func__);
+ return -EINVAL;
+ }
+
+ session->cc_vect_sel = (session->cc_vect_sel + 1) % 2;
+
+ config.ccs_enable = 1;
+ config.ccs_sel = session->cc_vect_sel;
+ config.pre_limit_sel = session->cc_vect_sel;
+ config.post_limit_sel = session->cc_vect_sel;
+ config.pre_bias_sel = session->cc_vect_sel;
+ config.post_bias_sel = session->cc_vect_sel;
+ config.ccs_dirty = true;
+
+ ccs.mv = data->csc_data.csc_mv;
+ ccs.pre_bv = data->csc_data.csc_pre_bv;
+ ccs.post_bv = data->csc_data.csc_post_bv;
+ ccs.pre_lv = data->csc_data.csc_pre_lv;
+ ccs.post_lv = data->csc_data.csc_post_lv;
+
+ mutex_lock(&session->lock);
+ ret = session->dma->config_ccs(session->dma, &config, &ccs);
+ mutex_unlock(&session->lock);
+ return ret;
+}
+
static int mdp3_pp_ioctl(struct msm_fb_data_type *mfd,
void __user *argp)
{
int ret = -EINVAL;
struct msmfb_mdp_pp mdp_pp;
+ struct mdp3_session_data *mdp3_session;
+
+ if (!mfd || !mfd->mdp.private1)
+ return -EINVAL;
+
+ mdp3_session = mfd->mdp.private1;
ret = copy_from_user(&mdp_pp, argp, sizeof(mdp_pp));
if (ret)
@@ -914,6 +1003,11 @@
ret = mdp3_bl_scale_config(mfd, (struct mdp_bl_scale_data *)
&mdp_pp.data.bl_scale_data);
break;
+ case mdp_op_csc_cfg:
+ ret = mdp3_csc_config(mdp3_session,
+ &(mdp_pp.data.csc_cfg_data));
+ break;
+
default:
pr_err("Unsupported request to MDP_PP IOCTL.\n");
ret = -EINVAL;
@@ -1001,6 +1095,7 @@
lut_config.lut_enable = 7;
lut_config.lut_sel = mdp3_session->lut_sel;
lut_config.lut_position = 0;
+ lut_config.lut_dirty = true;
lut.color0_lut = r;
lut.color1_lut = g;
lut.color2_lut = b;
@@ -1148,12 +1243,23 @@
goto init_done;
}
+ rc = mdp3_dma_init(mdp3_session->dma);
+ if (rc) {
+ pr_err("fail to init dma\n");
+ goto init_done;
+ }
+
intf_type = mdp3_ctrl_get_intf_type(mfd);
mdp3_session->intf = mdp3_get_display_intf(intf_type);
if (!mdp3_session->intf) {
rc = -ENODEV;
goto init_done;
}
+ rc = mdp3_intf_init(mdp3_session->intf);
+ if (rc) {
+ pr_err("fail to init interface\n");
+ goto init_done;
+ }
mdp3_session->mfd = mfd;
mdp3_session->panel = dev_get_platdata(&mfd->pdev->dev);
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.h b/drivers/video/msm/mdss/mdp3_ctrl.h
index 0bbc2ac..9ea1c91 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.h
+++ b/drivers/video/msm/mdss/mdp3_ctrl.h
@@ -50,6 +50,7 @@
int histo_status;
struct mutex histo_lock;
int lut_sel;
+ int cc_vect_sel;
};
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 3b65405..88eedb9 100644
--- a/drivers/video/msm/mdss/mdp3_dma.c
+++ b/drivers/video/msm/mdss/mdp3_dma.c
@@ -219,6 +219,25 @@
}
}
+static void mdp3_dma_clk_auto_gating(struct mdp3_dma *dma, int enable)
+{
+ u32 cgc;
+ int clock_bit = 10;
+
+ clock_bit += dma->dma_sel;
+
+ if (enable) {
+ cgc = MDP3_REG_READ(MDP3_REG_CGC_EN);
+ cgc |= BIT(clock_bit);
+ MDP3_REG_WRITE(MDP3_REG_CGC_EN, cgc);
+
+ } else {
+ cgc = MDP3_REG_READ(MDP3_REG_CGC_EN);
+ cgc &= ~BIT(clock_bit);
+ MDP3_REG_WRITE(MDP3_REG_CGC_EN, cgc);
+ }
+}
+
static int mdp3_dma_sync_config(struct mdp3_dma *dma,
struct mdp3_dma_source *source_config)
{
@@ -347,11 +366,109 @@
return 0;
}
+static void mdp3_ccs_update(struct mdp3_dma *dma)
+{
+ u32 cc_config;
+ int updated = 0;
+
+ cc_config = MDP3_REG_READ(MDP3_REG_DMA_P_COLOR_CORRECT_CONFIG);
+
+ if (dma->ccs_config.ccs_dirty) {
+ cc_config &= DMA_CCS_CONFIG_MASK;
+ if (dma->ccs_config.ccs_enable)
+ cc_config |= BIT(3);
+ else
+ cc_config &= ~BIT(3);
+ cc_config |= dma->ccs_config.ccs_sel << 5;
+ cc_config |= dma->ccs_config.pre_bias_sel << 6;
+ cc_config |= dma->ccs_config.post_bias_sel << 7;
+ cc_config |= dma->ccs_config.pre_limit_sel << 8;
+ cc_config |= dma->ccs_config.post_limit_sel << 9;
+ dma->ccs_config.ccs_dirty = false;
+ updated = 1;
+ }
+
+ if (dma->lut_config.lut_dirty) {
+ cc_config &= DMA_LUT_CONFIG_MASK;
+ cc_config |= dma->lut_config.lut_enable;
+ cc_config |= dma->lut_config.lut_position << 4;
+ cc_config |= dma->lut_config.lut_sel << 10;
+ dma->lut_config.lut_dirty = false;
+ updated = 1;
+ }
+ if (updated) {
+ MDP3_REG_WRITE(MDP3_REG_DMA_P_COLOR_CORRECT_CONFIG, cc_config);
+
+ /* Make sure ccs configuration update is done before continuing
+ with the DMA transfer */
+ wmb();
+ }
+}
+
+static int mdp3_dmap_ccs_config(struct mdp3_dma *dma,
+ struct mdp3_dma_color_correct_config *config,
+ struct mdp3_dma_ccs *ccs)
+{
+ int i;
+ u32 addr;
+
+ if (!ccs)
+ return -EINVAL;
+
+ if (config->ccs_enable) {
+ addr = MDP3_REG_DMA_P_CSC_MV1;
+ if (config->ccs_sel)
+ addr = MDP3_REG_DMA_P_CSC_MV2;
+ for (i = 0; i < 9; i++) {
+ MDP3_REG_WRITE(addr, ccs->mv[i]);
+ addr += 4;
+ }
+
+ addr = MDP3_REG_DMA_P_CSC_PRE_BV1;
+ if (config->pre_bias_sel)
+ addr = MDP3_REG_DMA_P_CSC_PRE_BV2;
+ for (i = 0; i < 3; i++) {
+ MDP3_REG_WRITE(addr, ccs->pre_bv[i]);
+ addr += 4;
+ }
+
+ addr = MDP3_REG_DMA_P_CSC_POST_BV1;
+ if (config->post_bias_sel)
+ addr = MDP3_REG_DMA_P_CSC_POST_BV2;
+ for (i = 0; i < 3; i++) {
+ MDP3_REG_WRITE(addr, ccs->post_bv[i]);
+ addr += 4;
+ }
+
+ addr = MDP3_REG_DMA_P_CSC_PRE_LV1;
+ if (config->pre_limit_sel)
+ addr = MDP3_REG_DMA_P_CSC_PRE_LV2;
+ for (i = 0; i < 6; i++) {
+ MDP3_REG_WRITE(addr, ccs->pre_lv[i]);
+ addr += 4;
+ }
+
+ addr = MDP3_REG_DMA_P_CSC_POST_LV1;
+ if (config->post_limit_sel)
+ addr = MDP3_REG_DMA_P_CSC_POST_LV2;
+ for (i = 0; i < 6; i++) {
+ MDP3_REG_WRITE(addr, ccs->post_lv[i]);
+ addr += 4;
+ }
+ }
+ dma->ccs_config = *config;
+
+ if (dma->output_config.out_sel != MDP3_DMA_OUTPUT_SEL_DSI_CMD)
+ mdp3_ccs_update(dma);
+
+ return 0;
+}
+
static int mdp3_dmap_lut_config(struct mdp3_dma *dma,
struct mdp3_dma_lut_config *config,
struct mdp3_dma_lut *lut)
{
- u32 cc_config, addr, color;
+ u32 addr, color;
int i;
if (config->lut_enable && lut) {
@@ -368,119 +485,11 @@
}
}
- cc_config = MDP3_REG_READ(MDP3_REG_DMA_P_COLOR_CORRECT_CONFIG);
- cc_config &= DMA_LUT_CONFIG_MASK;
- cc_config |= config->lut_enable;
- cc_config |= config->lut_position << 4;
- cc_config |= config->lut_sel << 10;
- MDP3_REG_WRITE(MDP3_REG_DMA_P_COLOR_CORRECT_CONFIG, cc_config);
- wmb();
-
dma->lut_config = *config;
- return 0;
-}
-static int mdp3_dmap_ccs_config(struct mdp3_dma *dma,
- struct mdp3_dma_color_correct_config *config,
- struct mdp3_dma_ccs *ccs)
-{
- int i;
- u32 cc_config, addr;
+ if (dma->output_config.out_sel != MDP3_DMA_OUTPUT_SEL_DSI_CMD)
+ mdp3_ccs_update(dma);
- cc_config = MDP3_REG_READ(MDP3_REG_DMA_P_COLOR_CORRECT_CONFIG);
- cc_config &= DMA_CCS_CONFIG_MASK;
- cc_config |= BIT(3);
- cc_config |= config->ccs_sel << 5;
- cc_config |= config->pre_bias_sel << 6;
- cc_config |= config->post_bias_sel << 7;
- cc_config |= config->pre_limit_sel << 8;
- cc_config |= config->post_limit_sel << 9;
-
- MDP3_REG_WRITE(MDP3_REG_DMA_P_COLOR_CORRECT_CONFIG, cc_config);
-
- if (config->ccs_enable && ccs) {
- if (ccs->mv1) {
- addr = MDP3_REG_DMA_P_CSC_MV1;
- for (i = 0; i < 9; i++) {
- MDP3_REG_WRITE(addr, ccs->mv1[i]);
- addr += 4;
- }
- }
-
- if (ccs->mv2) {
- addr = MDP3_REG_DMA_P_CSC_MV2;
- for (i = 0; i < 9; i++) {
- MDP3_REG_WRITE(addr, ccs->mv2[i]);
- addr += 4;
- }
- }
-
- if (ccs->pre_bv1) {
- addr = MDP3_REG_DMA_P_CSC_PRE_BV1;
- for (i = 0; i < 3; i++) {
- MDP3_REG_WRITE(addr, ccs->pre_bv1[i]);
- addr += 4;
- }
- }
-
- if (ccs->pre_bv2) {
- addr = MDP3_REG_DMA_P_CSC_PRE_BV2;
- for (i = 0; i < 3; i++) {
- MDP3_REG_WRITE(addr, ccs->pre_bv2[i]);
- addr += 4;
- }
- }
-
- if (ccs->post_bv1) {
- addr = MDP3_REG_DMA_P_CSC_POST_BV1;
- for (i = 0; i < 3; i++) {
- MDP3_REG_WRITE(addr, ccs->post_bv1[i]);
- addr += 4;
- }
- }
-
- if (ccs->post_bv2) {
- addr = MDP3_REG_DMA_P_CSC_POST_BV2;
- for (i = 0; i < 3; i++) {
- MDP3_REG_WRITE(addr, ccs->post_bv2[i]);
- addr += 4;
- }
- }
-
- if (ccs->pre_lv1) {
- addr = MDP3_REG_DMA_P_CSC_PRE_LV1;
- for (i = 0; i < 6; i++) {
- MDP3_REG_WRITE(addr, ccs->pre_lv1[i]);
- addr += 4;
- }
- }
-
- if (ccs->pre_lv2) {
- addr = MDP3_REG_DMA_P_CSC_PRE_LV2;
- for (i = 0; i < 6; i++) {
- MDP3_REG_WRITE(addr, ccs->pre_lv2[i]);
- addr += 4;
- }
- }
-
- if (ccs->post_lv1) {
- addr = MDP3_REG_DMA_P_CSC_POST_LV1;
- for (i = 0; i < 6; i++) {
- MDP3_REG_WRITE(addr, ccs->post_lv1[i]);
- addr += 4;
- }
- }
-
- if (ccs->post_lv2) {
- addr = MDP3_REG_DMA_P_CSC_POST_LV2;
- for (i = 0; i < 6; i++) {
- MDP3_REG_WRITE(addr, ccs->post_lv2[i]);
- addr += 4;
- }
- }
- }
-
- dma->ccs_config = *config;
return 0;
}
@@ -528,8 +537,10 @@
spin_lock_irqsave(&dma->dma_lock, flag);
MDP3_REG_WRITE(MDP3_REG_DMA_P_IBUF_ADDR, (u32)buf);
dma->source_config.buf = buf;
- if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD)
+ if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
+ mdp3_ccs_update(dma);
MDP3_REG_WRITE(MDP3_REG_DMA_P_START, 1);
+ }
if (!intf->active) {
pr_debug("mdp3_dmap_update start interface\n");
@@ -610,7 +621,7 @@
ret = wait_for_completion_killable_timeout(&dma->histo_comp, timeout);
if (ret == 0) {
- pr_err("mdp3_dmap_histo_get time out\n");
+ pr_debug("mdp3_dmap_histo_get time out\n");
ret = -ETIMEDOUT;
} else if (ret < 0) {
pr_err("mdp3_dmap_histo_get interrupted\n");
@@ -682,7 +693,6 @@
{
unsigned long flag;
int ret;
- u32 cgc;
if (dma->histo_state == MDP3_DMA_HISTO_STATE_START)
return -EINVAL;
@@ -690,9 +700,8 @@
spin_lock_irqsave(&dma->histo_lock, flag);
init_completion(&dma->histo_comp);
- cgc = MDP3_REG_READ(MDP3_REG_CGC_EN);
- cgc &= ~BIT(10);
- MDP3_REG_WRITE(MDP3_REG_CGC_EN, cgc);
+
+ mdp3_dma_clk_auto_gating(dma, 0);
MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_INTR_ENABLE, BIT(0)|BIT(1));
MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_RESET_SEQ_START, 1);
@@ -714,8 +723,7 @@
ret = 0;
}
mdp3_dma_callback_disable(dma, MDP3_DMA_CALLBACK_TYPE_HIST_RESET_DONE);
- cgc |= BIT(10);
- MDP3_REG_WRITE(MDP3_REG_CGC_EN, cgc);
+ mdp3_dma_clk_auto_gating(dma, 1);
return ret;
}
@@ -732,6 +740,7 @@
MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_INTR_ENABLE, 0);
wmb();
dma->histo_state = MDP3_DMA_HISTO_STATE_IDLE;
+ complete(&dma->histo_comp);
spin_unlock_irqrestore(&dma->histo_lock, flag);
@@ -820,19 +829,14 @@
return ret;
}
-int mdp3_dma_init(struct mdp3_dma *dma,
- struct mdp3_dma_source *source_config,
- struct mdp3_dma_output_config *output_config)
+int mdp3_dma_init(struct mdp3_dma *dma)
{
int ret = 0;
pr_debug("mdp3_dma_init\n");
switch (dma->dma_sel) {
case MDP3_DMA_P:
- ret = mdp3_dmap_config(dma, source_config, output_config);
- if (ret < 0)
- return ret;
-
+ dma->dma_config = mdp3_dmap_config;
dma->config_cursor = mdp3_dmap_cursor_config;
dma->config_ccs = mdp3_dmap_ccs_config;
dma->config_histo = mdp3_dmap_histo_config;
@@ -846,10 +850,7 @@
dma->stop = mdp3_dma_stop;
break;
case MDP3_DMA_S:
- ret = mdp3_dmas_config(dma, source_config, output_config);
- if (ret < 0)
- return ret;
-
+ dma->dma_config = mdp3_dmas_config;
dma->config_cursor = NULL;
dma->config_ccs = NULL;
dma->config_histo = NULL;
@@ -1020,10 +1021,9 @@
return 0;
}
-int mdp3_intf_init(struct mdp3_intf *intf, struct mdp3_intf_cfg *cfg)
+int mdp3_intf_init(struct mdp3_intf *intf)
{
- int ret = 0;
- switch (cfg->type) {
+ switch (intf->cfg.type) {
case MDP3_DMA_OUTPUT_SEL_LCDC:
intf->config = lcdc_config;
intf->start = lcdc_start;
@@ -1043,16 +1043,5 @@
default:
return -EINVAL;
}
-
- intf->active = false;
- if (intf->config)
- ret = intf->config(intf, cfg);
-
- if (ret) {
- pr_err("MDP interface initialization failed\n");
- return ret;
- }
-
- intf->cfg = *cfg;
return 0;
}
diff --git a/drivers/video/msm/mdss/mdp3_dma.h b/drivers/video/msm/mdss/mdp3_dma.h
index 518bd58..e4a28dc 100644
--- a/drivers/video/msm/mdss/mdp3_dma.h
+++ b/drivers/video/msm/mdss/mdp3_dma.h
@@ -176,16 +176,11 @@
};
struct mdp3_dma_ccs {
- u32 *mv1; /*set1 matrix vector, 3x3 */
- u32 *mv2;
- u32 *pre_bv1; /*pre-bias vector for set1, 1x3*/
- u32 *pre_bv2;
- u32 *post_bv1; /*post-bias vecotr for set1, */
- u32 *post_bv2;
- u32 *pre_lv1; /*pre-limit vector for set 1, 1x6*/
- u32 *pre_lv2;
- u32 *post_lv1;
- u32 *post_lv2;
+ u32 *mv; /*set1 matrix vector, 3x3 */
+ u32 *pre_bv; /*pre-bias vector for set1, 1x3*/
+ u32 *post_bv; /*post-bias vecotr for set1, */
+ u32 *pre_lv; /*pre-limit vector for set 1, 1x6*/
+ u32 *post_lv;
};
struct mdp3_dma_lut {
@@ -198,6 +193,7 @@
int lut_enable;
u32 lut_sel;
u32 lut_position;
+ bool lut_dirty;
};
struct mdp3_dma_color_correct_config {
@@ -207,6 +203,7 @@
u32 post_bias_sel;
u32 pre_bias_sel;
u32 ccs_sel;
+ bool ccs_dirty;
};
struct mdp3_dma_histogram_config {
@@ -253,6 +250,10 @@
int histo_state;
struct mdp3_dma_histogram_data histo_data;
+ int (*dma_config)(struct mdp3_dma *dma,
+ struct mdp3_dma_source *source_config,
+ struct mdp3_dma_output_config *output_config);
+
int (*start)(struct mdp3_dma *dma, struct mdp3_intf *intf);
int (*stop)(struct mdp3_dma *dma, struct mdp3_intf *intf);
@@ -326,11 +327,9 @@
int (*stop)(struct mdp3_intf *intf);
};
-int mdp3_dma_init(struct mdp3_dma *dma,
- struct mdp3_dma_source *source_config,
- struct mdp3_dma_output_config *output_config);
+int mdp3_dma_init(struct mdp3_dma *dma);
-int mdp3_intf_init(struct mdp3_intf *intf, struct mdp3_intf_cfg *cfg);
+int mdp3_intf_init(struct mdp3_intf *intf);
void mdp3_dma_callback_enable(struct mdp3_dma *dma, int type);
diff --git a/drivers/video/msm/mdss/mdp3_ppp.c b/drivers/video/msm/mdss/mdp3_ppp.c
index 48ffb72..924ec5a 100644
--- a/drivers/video/msm/mdss/mdp3_ppp.c
+++ b/drivers/video/msm/mdss/mdp3_ppp.c
@@ -23,6 +23,7 @@
#include <linux/sync.h>
#include <linux/sw_sync.h>
#include "linux/proc_fs.h"
+#include <linux/delay.h>
#include "mdss_fb.h"
#include "mdp3_ppp.h"
@@ -30,6 +31,7 @@
#include "mdp3.h"
#define MDP_IS_IMGTYPE_BAD(x) ((x) >= MDP_IMGTYPE_LIMIT)
+#define MDP_RELEASE_BW_TIMEOUT 50
#define MDP_BLIT_CLK_RATE 200000000
#define MDP_PPP_MAX_BPP 4
#define MDP_PPP_DYNAMIC_FACTOR 3
@@ -48,6 +50,7 @@
[MDP_Y_CRCB_H2V2] = true,
[MDP_Y_CBCR_H2V2] = true,
[MDP_Y_CBCR_H2V2_ADRENO] = true,
+ [MDP_Y_CBCR_H2V2_VENUS] = true,
[MDP_YCRYCB_H2V1] = true,
[MDP_Y_CBCR_H2V1] = true,
[MDP_Y_CRCB_H2V1] = true,
@@ -92,6 +95,9 @@
struct sw_sync_timeline *timeline;
int timeline_value;
+ struct timer_list free_bw_timer;
+ struct work_struct free_bw_work;
+ bool bw_on;
};
static struct ppp_status *ppp_stat;
@@ -353,6 +359,7 @@
mdp3_clk_set_rate(MDP3_CLK_CORE, rate, MDP3_CLIENT_PPP);
mdp3_clk_enable(on_off);
mdp3_bus_scale_set_quota(MDP3_CLIENT_PPP, ab, ib);
+ ppp_stat->bw_on = on_off;
return 0;
}
@@ -403,6 +410,11 @@
(void *) ((uint32_t) blit_op->src.p0 +
ALIGN((ALIGN(req->src.width, 32) *
ALIGN(req->src.height, 32)), 4096));
+ else if (blit_op->src.color_fmt == MDP_Y_CBCR_H2V2_VENUS)
+ blit_op->src.p1 =
+ (void *) ((uint32_t) blit_op->src.p0 +
+ ALIGN((ALIGN(req->src.width, 128) *
+ ALIGN(req->src.height, 32)), 4096));
else
blit_op->src.p1 = (void *) ((uint32_t) blit_op->src.p0 +
req->src.width * req->src.height);
@@ -754,9 +766,6 @@
src_data, dst_data);
else
ret = mdp3_ppp_blit(mfd, req, src_data, dst_data);
-
- mdp3_put_img(src_data);
- mdp3_put_img(dst_data);
return ret;
}
@@ -892,28 +901,52 @@
req_q->pop_idx = (req_q->pop_idx + 1) % MDP3_PPP_MAX_LIST_REQ;
}
+void mdp3_free_fw_timer_func(unsigned long arg)
+{
+ schedule_work(&ppp_stat->free_bw_work);
+}
+
+static void mdp3_free_bw_wq_handler(struct work_struct *work)
+{
+ struct msm_fb_data_type *mfd = ppp_stat->mfd;
+ mutex_lock(&ppp_stat->config_ppp_mutex);
+ if (ppp_stat->bw_on) {
+ mdp3_ppp_turnon(mfd, 0);
+ mdp3_iommu_disable(MDP3_CLIENT_PPP);
+ }
+ mutex_unlock(&ppp_stat->config_ppp_mutex);
+}
+
static void mdp3_ppp_blit_wq_handler(struct work_struct *work)
{
struct msm_fb_data_type *mfd = ppp_stat->mfd;
struct blit_req_list *req;
- int i, rc;
+ int i, rc = 0;
- req = mdp3_ppp_next_req(&ppp_stat->req_q);
mutex_lock(&ppp_stat->config_ppp_mutex);
+ req = mdp3_ppp_next_req(&ppp_stat->req_q);
+ if (!req) {
+ mutex_unlock(&ppp_stat->config_ppp_mutex);
+ return;
+ }
- mdp3_iommu_enable(MDP3_CLIENT_PPP);
- mdp3_ppp_turnon(mfd, 1);
+ if (!ppp_stat->bw_on) {
+ mdp3_iommu_enable(MDP3_CLIENT_PPP);
+ mdp3_ppp_turnon(mfd, 1);
+ }
while (req) {
mdp3_ppp_wait_for_fence(req);
for (i = 0; i < req->count; i++) {
if (!(req->req_list[i].flags & MDP_NO_BLIT)) {
/* Do the actual blit. */
- rc = mdp3_ppp_start_blit(mfd,
+ if (!rc) {
+ rc = mdp3_ppp_start_blit(mfd,
&(req->req_list[i]),
&req->src_data[i],
&req->dst_data[i]);
- if (rc)
- break;
+ }
+ mdp3_put_img(&req->src_data[i]);
+ mdp3_put_img(&req->dst_data[i]);
}
}
/* Signal to release fence */
@@ -925,8 +958,8 @@
complete(&ppp_stat->pop_q_comp);
mutex_unlock(&ppp_stat->req_mutex);
}
- mdp3_ppp_turnon(mfd, 0);
- mdp3_iommu_disable(MDP3_CLIENT_PPP);
+ mod_timer(&ppp_stat->free_bw_timer, jiffies +
+ msecs_to_jiffies(MDP_RELEASE_BW_TIMEOUT));
mutex_unlock(&ppp_stat->config_ppp_mutex);
}
@@ -995,14 +1028,14 @@
if (req->cur_rel_fen_fd < 0) {
pr_err("%s: get_unused_fd_flags failed\n", __func__);
rc = -ENOMEM;
- goto parse_err_2;
+ goto parse_err_1;
}
sync_fence_install(req->cur_rel_fence, req->cur_rel_fen_fd);
rc = copy_to_user(req_list_header->sync.rel_fen_fd,
&req->cur_rel_fen_fd, sizeof(int));
if (rc) {
pr_err("%s:copy_to_user failed\n", __func__);
- goto parse_err_3;
+ goto parse_err_2;
}
} else {
fence = req->cur_rel_fence;
@@ -1023,12 +1056,8 @@
}
return 0;
-parse_err_3:
- put_unused_fd(req->cur_rel_fen_fd);
parse_err_2:
- sync_fence_put(req->cur_rel_fence);
- req->cur_rel_fence = NULL;
- req->cur_rel_fen_fd = 0;
+ put_unused_fd(req->cur_rel_fen_fd);
parse_err_1:
for (i--; i >= 0; i--) {
mdp3_put_img(&req->src_data[i]);
@@ -1058,10 +1087,14 @@
}
INIT_WORK(&ppp_stat->blit_work, mdp3_ppp_blit_wq_handler);
+ INIT_WORK(&ppp_stat->free_bw_work, mdp3_free_bw_wq_handler);
init_completion(&ppp_stat->pop_q_comp);
spin_lock_init(&ppp_stat->ppp_lock);
mutex_init(&ppp_stat->req_mutex);
mutex_init(&ppp_stat->config_ppp_mutex);
+ init_timer(&ppp_stat->free_bw_timer);
+ ppp_stat->free_bw_timer.function = mdp3_free_fw_timer_func;
+ ppp_stat->free_bw_timer.data = 0;
ppp_stat->busy = false;
ppp_stat->mfd = mfd;
mdp3_ppp_callback_setup();
diff --git a/drivers/video/msm/mdss/mdp3_ppp_data.c b/drivers/video/msm/mdss/mdp3_ppp_data.c
index d68faad..e1c0f27 100644
--- a/drivers/video/msm/mdss/mdp3_ppp_data.c
+++ b/drivers/video/msm/mdss/mdp3_ppp_data.c
@@ -30,6 +30,7 @@
[MDP_Y_CRCB_H2V2] = MDP_Y_CBCR_H2V2_SRC_REG,
[MDP_Y_CBCR_H2V2] = MDP_Y_CBCR_H2V2_SRC_REG,
[MDP_Y_CBCR_H2V2_ADRENO] = MDP_Y_CBCR_H2V2_SRC_REG,
+ [MDP_Y_CBCR_H2V2_VENUS] = MDP_Y_CBCR_H2V2_SRC_REG,
[MDP_YCRYCB_H2V1] = MDP_YCRYCB_H2V1_SRC_REG,
[MDP_Y_CBCR_H2V1] = MDP_Y_CRCB_H2V1_SRC_REG,
[MDP_Y_CRCB_H2V1] = MDP_Y_CRCB_H2V1_SRC_REG,
@@ -48,6 +49,7 @@
[MDP_Y_CRCB_H2V2] = MDP_Y_CBCR_H2V2_DST_REG,
[MDP_Y_CBCR_H2V2] = MDP_Y_CBCR_H2V2_DST_REG,
[MDP_Y_CBCR_H2V2_ADRENO] = MDP_Y_CBCR_H2V2_DST_REG,
+ [MDP_Y_CBCR_H2V2_VENUS] = MDP_Y_CBCR_H2V2_DST_REG,
[MDP_YCRYCB_H2V1] = MDP_YCRYCB_H2V1_DST_REG,
[MDP_Y_CBCR_H2V1] = MDP_Y_CRCB_H2V1_DST_REG,
[MDP_Y_CRCB_H2V1] = MDP_Y_CRCB_H2V1_DST_REG,
@@ -72,6 +74,8 @@
[MDP_Y_CBCR_H2V2] = PPP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
[MDP_Y_CBCR_H2V2_ADRENO] = PPP_GET_PACK_PATTERN(0, 0, CLR_CB,
CLR_CR, 8),
+ [MDP_Y_CBCR_H2V2_VENUS] = PPP_GET_PACK_PATTERN(0, 0, CLR_CB,
+ CLR_CR, 8),
[MDP_YCRYCB_H2V1] = PPP_GET_PACK_PATTERN(CLR_Y,
CLR_CR, CLR_Y, CLR_CB, 8),
[MDP_Y_CBCR_H2V1] = PPP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
@@ -91,6 +95,8 @@
[MDP_Y_CBCR_H2V2] = PPP_OP_SRC_CHROMA_420 | PPP_OP_COLOR_SPACE_YCBCR,
[MDP_Y_CBCR_H2V2_ADRENO] = PPP_OP_SRC_CHROMA_420 |
PPP_OP_COLOR_SPACE_YCBCR,
+ [MDP_Y_CBCR_H2V2_VENUS] = PPP_OP_SRC_CHROMA_420 |
+ PPP_OP_COLOR_SPACE_YCBCR,
[MDP_Y_CBCR_H2V1] = PPP_OP_SRC_CHROMA_H2V1,
[MDP_Y_CRCB_H2V1] = PPP_OP_SRC_CHROMA_H2V1,
[MDP_YCRYCB_H2V1] = PPP_OP_SRC_CHROMA_H2V1,
@@ -109,6 +115,7 @@
[MDP_Y_CBCR_H2V1] = 1,
[MDP_Y_CBCR_H2V2] = 1,
[MDP_Y_CBCR_H2V2_ADRENO] = 1,
+ [MDP_Y_CBCR_H2V2_VENUS] = 1,
[MDP_Y_CRCB_H2V1] = 1,
[MDP_Y_CRCB_H2V2] = 1,
[MDP_YCRYCB_H2V1] = 2,
diff --git a/drivers/video/msm/mdss/mdp3_ppp_hwio.c b/drivers/video/msm/mdss/mdp3_ppp_hwio.c
index 309effc..199387f 100644
--- a/drivers/video/msm/mdss/mdp3_ppp_hwio.c
+++ b/drivers/video/msm/mdss/mdp3_ppp_hwio.c
@@ -57,6 +57,8 @@
int64_t Od;
int64_t Odprime;
int64_t Oreq;
+ int64_t init_phase_temp;
+ int64_t delta;
uint32_t mult;
/*
@@ -149,7 +151,24 @@
Oreq = (Osprime & int_mask) - one;
/* calculate initial phase */
- init_phase = (int)((Osprime - Oreq) >> 4);
+ init_phase_temp = Osprime - Oreq;
+ delta = ((int64_t) (org) << PQF_PLUS_4) - Oreq;
+ init_phase_temp -= delta;
+
+ /* limit to valid range before the left shift */
+ delta = (init_phase_temp & (1LL << 63)) ?
+ 4 : -4;
+ delta <<= PQF_PLUS_4;
+ while (abs((int)(init_phase_temp >>
+ PQF_PLUS_4)) > 4)
+ init_phase_temp += delta;
+
+ /*
+ * right shift to account for extra bits of
+ * precision
+ */
+ init_phase = (int)(init_phase_temp >> 4);
+
}
} else {
/*
@@ -181,7 +200,18 @@
Oreq = (Osprime & int_mask) - one;
/* calculate initial phase */
- init_phase = (int)((Osprime - Oreq) >> 4);
+ init_phase_temp = Osprime - Oreq;
+ delta = ((int64_t) (org) << PQF_PLUS_4) - Oreq;
+ init_phase_temp -= delta;
+
+ /* limit to valid range before the left shift */
+ delta = (init_phase_temp & (1LL << 63)) ? 4 : -4;
+ delta <<= PQF_PLUS_4;
+ while (abs((int)(init_phase_temp >> PQF_PLUS_4)) > 4)
+ init_phase_temp += delta;
+
+ /* right shift to account for extra bits of precision */
+ init_phase = (int)(init_phase_temp >> 4);
}
}
@@ -331,13 +361,43 @@
return rgb;
}
-static uint8_t *mdp_adjust_rot_addr(struct ppp_blit_op *iBuf,
+uint8_t *mdp_bg_adjust_rot_addr(struct ppp_blit_op *iBuf,
+ uint8_t *addr, uint32_t bpp, uint32_t uv)
+{
+ uint32_t dest_ystride = iBuf->bg.prop.width * bpp;
+ uint32_t h_slice = 1, min_val;
+
+ if (uv && ((iBuf->bg.color_fmt == MDP_Y_CBCR_H2V2) ||
+ (iBuf->bg.color_fmt == MDP_Y_CRCB_H2V2)))
+ h_slice = 2;
+
+ if (((iBuf->mdp_op & MDPOP_ROT90) == MDPOP_ROT90) ^
+ ((iBuf->mdp_op & MDPOP_LR) == MDPOP_LR)) {
+ min_val = (iBuf->bg.roi.width + iBuf->bg.roi.x) % 16;
+ if (!min_val)
+ min_val = 16;
+ addr +=
+ (iBuf->bg.roi.width -
+ MIN(min_val, iBuf->bg.roi.width)) * bpp;
+ }
+ if ((iBuf->mdp_op & MDPOP_UD) == MDPOP_UD) {
+ min_val = (iBuf->bg.roi.height + iBuf->bg.roi.y) % 16;
+ if (!min_val)
+ min_val = 16;
+ addr +=
+ ((iBuf->bg.roi.height -
+ MIN(min_val, iBuf->bg.roi.height))/h_slice) *
+ dest_ystride;
+ }
+
+ return addr;
+}
+
+uint8_t *mdp_dst_adjust_rot_addr(struct ppp_blit_op *iBuf,
uint8_t *addr, uint32_t bpp, uint32_t uv)
{
uint32_t dest_ystride = iBuf->dst.prop.width * bpp;
uint32_t h_slice = 1;
- if (0)
- return 0;
if (uv && ((iBuf->dst.color_fmt == MDP_Y_CBCR_H2V2) ||
(iBuf->dst.color_fmt == MDP_Y_CRCB_H2V2)))
@@ -350,16 +410,10 @@
MIN(16, iBuf->dst.roi.width)) * bpp;
}
if ((iBuf->mdp_op & MDPOP_UD) == MDPOP_UD) {
- if (1) {
- addr +=
- ((iBuf->dst.roi.height -
- MIN(16, iBuf->dst.roi.height))/h_slice) *
- dest_ystride;
- } else {
- addr +=
- (iBuf->dst.roi.width -
- MIN(16, iBuf->dst.roi.width)) * bpp;
- }
+ addr +=
+ ((iBuf->dst.roi.height -
+ MIN(16, iBuf->dst.roi.height))/h_slice) *
+ dest_ystride;
}
return addr;
@@ -376,17 +430,22 @@
if (img->color_fmt == MDP_Y_CBCR_H2V2_ADRENO && layer == 0)
img->p0 += (x + y * ALIGN(width, 32)) * bpp;
+ else if (img->color_fmt == MDP_Y_CBCR_H2V2_VENUS && layer == 0)
+ img->p0 += (x + y * ALIGN(width, 128)) * bpp;
else
img->p0 += (x + y * width) * bpp;
- if (layer != 0)
- img->p0 = mdp_adjust_rot_addr(blit_op, img->p0, bpp, 0);
+ if (layer == 1)
+ img->p0 = mdp_bg_adjust_rot_addr(blit_op, img->p0, bpp, 0);
+ else if (layer == 2)
+ img->p0 = mdp_dst_adjust_rot_addr(blit_op, img->p0, bpp, 0);
if (img->p1) {
/*
* MDP_Y_CBCR_H2V2/MDP_Y_CRCB_H2V2 cosite for now
* we need to shift x direction same as y dir for offsite
*/
- if (img->color_fmt == MDP_Y_CBCR_H2V2_ADRENO
+ if ((img->color_fmt == MDP_Y_CBCR_H2V2_ADRENO ||
+ img->color_fmt == MDP_Y_CBCR_H2V2_VENUS)
&& layer == 0)
img->p1 += ((x / h_slice) * h_slice + ((y == 0) ? 0 :
(((y + 1) / v_slice - 1) * (ALIGN(width/2, 32) * 2))))
@@ -394,8 +453,14 @@
else
img->p1 += ((x / h_slice) * h_slice +
((y == 0) ? 0 : ((y + 1) / v_slice - 1) * width)) * bpp;
- if (layer != 0)
- img->p1 = mdp_adjust_rot_addr(blit_op, img->p1, bpp, 1);
+
+ if (layer == 1) {
+ img->p0 = mdp_bg_adjust_rot_addr(blit_op,
+ img->p0, bpp, 0);
+ } else if (layer == 2) {
+ img->p0 = mdp_dst_adjust_rot_addr(blit_op,
+ img->p0, bpp, 0);
+ }
}
}
@@ -678,6 +743,7 @@
case MDP_Y_CBCR_H2V2:
case MDP_Y_CBCR_H2V2_ADRENO:
+ case MDP_Y_CBCR_H2V2_VENUS:
case MDP_Y_CRCB_H2V2:
er->chroma_interp_point_left = er->luma_interp_point_left >> 1;
er->chroma_interp_point_right =
@@ -716,6 +782,7 @@
break;
case MDP_Y_CBCR_H2V2:
case MDP_Y_CBCR_H2V2_ADRENO:
+ case MDP_Y_CBCR_H2V2_VENUS:
case MDP_Y_CRCB_H2V2:
/*
* cosite in horizontal dir, and offsite in vertical dir
@@ -1044,7 +1111,6 @@
}
if (*pppop_reg_ptr & PPP_OP_BLEND_ON) {
- blit_op->bg = blit_op->dst;
config_ppp_background(&blit_op->bg);
if (blit_op->dst.color_fmt == MDP_YCRYCB_H2V1) {
@@ -1107,6 +1173,7 @@
switch (blit_op->src.color_fmt) {
case MDP_Y_CBCR_H2V2:
case MDP_Y_CBCR_H2V2_ADRENO:
+ case MDP_Y_CBCR_H2V2_VENUS:
case MDP_Y_CRCB_H2V2:
sh_slice = sv_slice = 2;
break;
@@ -1134,6 +1201,10 @@
blit_op->src.stride0 = ALIGN(blit_op->src.prop.width, 32) *
ppp_bpp(blit_op->src.color_fmt);
blit_op->src.stride1 = 2 * ALIGN(blit_op->src.prop.width/2, 32);
+ } else if (blit_op->src.color_fmt == MDP_Y_CBCR_H2V2_VENUS) {
+ blit_op->src.stride0 = ALIGN(blit_op->src.prop.width, 128) *
+ ppp_bpp(blit_op->src.color_fmt);
+ blit_op->src.stride1 = blit_op->src.stride0;
} else {
blit_op->src.stride0 = blit_op->src.prop.width *
ppp_bpp(blit_op->src.color_fmt);
@@ -1152,9 +1223,11 @@
blit_op->dst.p1 = NULL;
}
+ blit_op->bg = blit_op->dst;
/* Jumping from Y-Plane to Chroma Plane */
/* first pixel addr calculation */
mdp_adjust_start_addr(blit_op, &blit_op->src, sv_slice, sh_slice, 0);
+ mdp_adjust_start_addr(blit_op, &blit_op->bg, dv_slice, dh_slice, 1);
mdp_adjust_start_addr(blit_op, &blit_op->dst, dv_slice, dh_slice, 2);
config_ppp_scale(blit_op, &ppp_operation_reg);
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index 1311dab..840af17 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -73,6 +73,7 @@
u32 irq_buzy;
u32 has_bwc;
u32 has_decimation;
+ u8 has_wfd_blk;
u32 mdp_irq_mask;
u32 mdp_hist_irq_mask;
@@ -88,6 +89,7 @@
u32 smp_mb_cnt;
u32 smp_mb_size;
+ u32 smp_mb_per_pipe;
u32 rot_block_size;
@@ -121,6 +123,7 @@
struct early_suspend early_suspend;
void *debug_data;
int current_bus_idx;
+ bool mixer_switched;
};
extern struct mdss_data_type *mdss_res;
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index fb0e8ba..3b0cd20 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -31,9 +31,7 @@
static int mdss_dsi_regulator_init(struct platform_device *pdev)
{
- int ret = 0;
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
- struct dsi_drv_cm_data *dsi_drv = NULL;
if (!pdev) {
pr_err("%s: invalid input\n", __func__);
@@ -46,59 +44,9 @@
return -EINVAL;
}
- dsi_drv = &(ctrl_pdata->shared_pdata);
- if (ctrl_pdata->power_data.num_vreg > 0) {
- ret = msm_dss_config_vreg(&pdev->dev,
- ctrl_pdata->power_data.vreg_config,
- ctrl_pdata->power_data.num_vreg, 1);
- } else {
- dsi_drv->vdd_vreg = devm_regulator_get(&pdev->dev, "vdd");
- if (IS_ERR(dsi_drv->vdd_vreg)) {
- pr_err("%s: could not get vdda vreg, rc=%ld\n",
- __func__, PTR_ERR(dsi_drv->vdd_vreg));
- return PTR_ERR(dsi_drv->vdd_vreg);
- }
-
- ret = regulator_set_voltage(dsi_drv->vdd_vreg, 3000000,
- 3000000);
- if (ret) {
- pr_err("%s: set voltage failed on vdda vreg, rc=%d\n",
- __func__, ret);
- return ret;
- }
-
- dsi_drv->vdd_io_vreg = devm_regulator_get(&pdev->dev, "vddio");
- if (IS_ERR(dsi_drv->vdd_io_vreg)) {
- pr_err("%s: could not get vddio reg, rc=%ld\n",
- __func__, PTR_ERR(dsi_drv->vdd_io_vreg));
- return PTR_ERR(dsi_drv->vdd_io_vreg);
- }
-
- ret = regulator_set_voltage(dsi_drv->vdd_io_vreg, 1800000,
- 1800000);
- if (ret) {
- pr_err("%s: set voltage failed on vddio vreg, rc=%d\n",
- __func__, ret);
- return ret;
- }
-
- dsi_drv->vdda_vreg = devm_regulator_get(&pdev->dev, "vdda");
- if (IS_ERR(dsi_drv->vdda_vreg)) {
- pr_err("%s: could not get vdda vreg, rc=%ld\n",
- __func__, PTR_ERR(dsi_drv->vdda_vreg));
- return PTR_ERR(dsi_drv->vdda_vreg);
- }
-
- ret = regulator_set_voltage(dsi_drv->vdda_vreg, 1200000,
- 1200000);
- if (ret) {
- pr_err("%s: set voltage failed on vdda vreg, rc=%d\n",
- __func__, ret);
- return ret;
- }
- }
-
- return 0;
+ return msm_dss_config_vreg(&pdev->dev,
+ ctrl_pdata->power_data.vreg_config,
+ ctrl_pdata->power_data.num_vreg, 1);
}
static int mdss_dsi_panel_power_on(struct mdss_panel_data *pdata, int enable)
@@ -108,7 +56,8 @@
if (pdata == NULL) {
pr_err("%s: Invalid input data\n", __func__);
- return -EINVAL;
+ ret = -EINVAL;
+ goto error;
}
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
@@ -116,71 +65,13 @@
pr_debug("%s: enable=%d\n", __func__, enable);
if (enable) {
- if (ctrl_pdata->power_data.num_vreg > 0) {
- ret = msm_dss_enable_vreg(
- ctrl_pdata->power_data.vreg_config,
- ctrl_pdata->power_data.num_vreg, 1);
- if (ret) {
- pr_err("%s:Failed to enable regulators.rc=%d\n",
- __func__, ret);
- return ret;
- }
-
- /*
- * A small delay is needed here after enabling
- * all regulators and before issuing panel reset
- */
- msleep(20);
- } else {
- ret = regulator_set_optimum_mode(
- (ctrl_pdata->shared_pdata).vdd_vreg, 100000);
- if (ret < 0) {
- pr_err("%s: vdd_vreg set opt mode failed.\n",
- __func__);
- return ret;
- }
-
- ret = regulator_set_optimum_mode(
- (ctrl_pdata->shared_pdata).vdd_io_vreg, 100000);
- if (ret < 0) {
- pr_err("%s: vdd_io_vreg set opt mode failed.\n",
- __func__);
- return ret;
- }
-
- ret = regulator_set_optimum_mode
- ((ctrl_pdata->shared_pdata).vdda_vreg, 100000);
- if (ret < 0) {
- pr_err("%s: vdda_vreg set opt mode failed.\n",
- __func__);
- return ret;
- }
-
- ret = regulator_enable(
- (ctrl_pdata->shared_pdata).vdd_io_vreg);
- if (ret) {
- pr_err("%s: Failed to enable regulator.\n",
- __func__);
- return ret;
- }
- msleep(20);
-
- ret = regulator_enable(
- (ctrl_pdata->shared_pdata).vdd_vreg);
- if (ret) {
- pr_err("%s: Failed to enable regulator.\n",
- __func__);
- return ret;
- }
- msleep(20);
-
- ret = regulator_enable(
- (ctrl_pdata->shared_pdata).vdda_vreg);
- if (ret) {
- pr_err("%s: Failed to enable regulator.\n",
- __func__);
- return ret;
- }
+ ret = msm_dss_enable_vreg(
+ ctrl_pdata->power_data.vreg_config,
+ ctrl_pdata->power_data.num_vreg, 1);
+ if (ret) {
+ pr_err("%s:Failed to enable vregs.rc=%d\n",
+ __func__, ret);
+ goto error;
}
if (pdata->panel_info.panel_power_on == 0)
@@ -190,65 +81,16 @@
mdss_dsi_panel_reset(pdata, 0);
- if (ctrl_pdata->power_data.num_vreg > 0) {
- ret = msm_dss_enable_vreg(
- ctrl_pdata->power_data.vreg_config,
- ctrl_pdata->power_data.num_vreg, 0);
- if (ret) {
- pr_err("%s: Failed to disable regs.rc=%d\n",
- __func__, ret);
- return ret;
- }
- } else {
- ret = regulator_disable(
- (ctrl_pdata->shared_pdata).vdd_vreg);
- if (ret) {
- pr_err("%s: Failed to disable regulator.\n",
- __func__);
- return ret;
- }
-
- ret = regulator_disable(
- (ctrl_pdata->shared_pdata).vdda_vreg);
- if (ret) {
- pr_err("%s: Failed to disable regulator.\n",
- __func__);
- return ret;
- }
-
- ret = regulator_disable(
- (ctrl_pdata->shared_pdata).vdd_io_vreg);
- if (ret) {
- pr_err("%s: Failed to disable regulator.\n",
- __func__);
- return ret;
- }
-
- ret = regulator_set_optimum_mode(
- (ctrl_pdata->shared_pdata).vdd_vreg, 100);
- if (ret < 0) {
- pr_err("%s: vdd_vreg set opt mode failed.\n",
- __func__);
- return ret;
- }
-
- ret = regulator_set_optimum_mode(
- (ctrl_pdata->shared_pdata).vdd_io_vreg, 100);
- if (ret < 0) {
- pr_err("%s: vdd_io_vreg set opt mode failed.\n",
- __func__);
- return ret;
- }
- ret = regulator_set_optimum_mode(
- (ctrl_pdata->shared_pdata).vdda_vreg, 100);
- if (ret < 0) {
- pr_err("%s: vdda_vreg set opt mode failed.\n",
- __func__);
- return ret;
- }
+ ret = msm_dss_enable_vreg(
+ ctrl_pdata->power_data.vreg_config,
+ ctrl_pdata->power_data.num_vreg, 0);
+ if (ret) {
+ pr_err("%s: Failed to disable vregs.rc=%d\n",
+ __func__, ret);
}
}
- return 0;
+error:
+ return ret;
}
static void mdss_dsi_put_dt_vreg_data(struct device *dev,
@@ -269,10 +111,9 @@
static int mdss_dsi_get_dt_vreg_data(struct device *dev,
struct dss_module_power *mp)
{
- int i, rc = 0;
- int dt_vreg_total = 0;
- u32 *val_array = NULL;
- struct device_node *of_node = NULL;
+ int i = 0, rc = 0;
+ u32 tmp = 0;
+ struct device_node *of_node = NULL, *supply_node = NULL;
if (!dev || !mp) {
pr_err("%s: invalid input\n", __func__);
@@ -283,94 +124,131 @@
of_node = dev->of_node;
mp->num_vreg = 0;
- dt_vreg_total = of_property_count_strings(of_node, "qcom,supply-names");
- if (dt_vreg_total < 0) {
- pr_debug("%s: vreg not found. rc=%d\n", __func__,
- dt_vreg_total);
- rc = 0;
- goto error;
- } else {
- pr_debug("%s: vreg found. count=%d\n", __func__, dt_vreg_total);
+ for_each_child_of_node(of_node, supply_node) {
+ if (!strncmp(supply_node->name, "qcom,platform-supply-entry",
+ 26))
+ ++mp->num_vreg;
}
-
- if (dt_vreg_total > 0) {
- mp->num_vreg = dt_vreg_total;
- mp->vreg_config = devm_kzalloc(dev, sizeof(struct dss_vreg) *
- dt_vreg_total, GFP_KERNEL);
- if (!mp->vreg_config) {
- pr_err("%s: can't alloc vreg mem\n", __func__);
- goto error;
- }
- } else {
+ if (mp->num_vreg == 0) {
pr_debug("%s: no vreg\n", __func__);
- return 0;
+ goto novreg;
+ } else {
+ pr_debug("%s: vreg found. count=%d\n", __func__, mp->num_vreg);
}
- val_array = devm_kzalloc(dev, sizeof(u32) * dt_vreg_total, GFP_KERNEL);
- if (!val_array) {
- pr_err("%s: can't allocate vreg scratch mem\n", __func__);
+ mp->vreg_config = devm_kzalloc(dev, sizeof(struct dss_vreg) *
+ mp->num_vreg, GFP_KERNEL);
+ if (!mp->vreg_config) {
+ pr_err("%s: can't alloc vreg mem\n", __func__);
rc = -ENOMEM;
goto error;
}
- for (i = 0; i < dt_vreg_total; i++) {
- const char *st = NULL;
- /* vreg-name */
- rc = of_property_read_string_index(of_node, "qcom,supply-names",
- i, &st);
- if (rc) {
- pr_err("%s: error reading name. i=%d, rc=%d\n",
- __func__, i, rc);
- goto error;
- }
- snprintf(mp->vreg_config[i].vreg_name,
- ARRAY_SIZE((mp->vreg_config[i].vreg_name)), "%s", st);
+ for_each_child_of_node(of_node, supply_node) {
+ if (!strncmp(supply_node->name, "qcom,platform-supply-entry",
+ 26)) {
+ const char *st = NULL;
+ /* vreg-name */
+ rc = of_property_read_string(supply_node,
+ "qcom,supply-name", &st);
+ if (rc) {
+ pr_err("%s: error reading name. rc=%d\n",
+ __func__, rc);
+ goto error;
+ }
+ snprintf(mp->vreg_config[i].vreg_name,
+ ARRAY_SIZE((mp->vreg_config[i].vreg_name)),
+ "%s", st);
+ /* vreg-min-voltage */
+ rc = of_property_read_u32(supply_node,
+ "qcom,supply-min-voltage", &tmp);
+ if (rc) {
+ pr_err("%s: error reading min volt. rc=%d\n",
+ __func__, rc);
+ goto error;
+ }
+ mp->vreg_config[i].min_voltage = tmp;
- /* vreg-min-voltage */
- memset(val_array, 0, sizeof(u32) * dt_vreg_total);
- rc = of_property_read_u32_array(of_node,
- "qcom,supply-min-voltage-level", val_array,
- dt_vreg_total);
- if (rc) {
- pr_err("%s: error reading min volt. rc=%d\n",
- __func__, rc);
- goto error;
- }
- mp->vreg_config[i].min_voltage = val_array[i];
+ /* vreg-max-voltage */
+ rc = of_property_read_u32(supply_node,
+ "qcom,supply-max-voltage", &tmp);
+ if (rc) {
+ pr_err("%s: error reading max volt. rc=%d\n",
+ __func__, rc);
+ goto error;
+ }
+ mp->vreg_config[i].max_voltage = tmp;
- /* vreg-max-voltage */
- memset(val_array, 0, sizeof(u32) * dt_vreg_total);
- rc = of_property_read_u32_array(of_node,
- "qcom,supply-max-voltage-level", val_array,
- dt_vreg_total);
- if (rc) {
- pr_err("%s: error reading max volt. rc=%d\n",
- __func__, rc);
- goto error;
- }
- mp->vreg_config[i].max_voltage = val_array[i];
+ /* enable-load */
+ rc = of_property_read_u32(supply_node,
+ "qcom,supply-enable-load", &tmp);
+ if (rc) {
+ pr_err("%s: error reading enable load. rc=%d\n",
+ __func__, rc);
+ goto error;
+ }
+ mp->vreg_config[i].enable_load = tmp;
- /* vreg-peak-current*/
- memset(val_array, 0, sizeof(u32) * dt_vreg_total);
- rc = of_property_read_u32_array(of_node,
- "qcom,supply-peak-current", val_array,
- dt_vreg_total);
- if (rc) {
- pr_err("%s: error reading peak current. rc=%d\n",
- __func__, rc);
- goto error;
- }
- mp->vreg_config[i].peak_current = val_array[i];
+ /* disable-load */
+ rc = of_property_read_u32(supply_node,
+ "qcom,supply-disable-load", &tmp);
+ if (rc) {
+ pr_err("%s: error reading disable load. rc=%d\n",
+ __func__, rc);
+ goto error;
+ }
+ mp->vreg_config[i].disable_load = tmp;
- pr_debug("%s: %s min=%d, max=%d, pc=%d\n", __func__,
- mp->vreg_config[i].vreg_name,
- mp->vreg_config[i].min_voltage,
- mp->vreg_config[i].max_voltage,
- mp->vreg_config[i].peak_current);
+ /* pre-sleep */
+ rc = of_property_read_u32(supply_node,
+ "qcom,supply-pre-on-sleep", &tmp);
+ if (rc) {
+ pr_debug("%s: error reading supply pre sleep value. rc=%d\n",
+ __func__, rc);
+ }
+ mp->vreg_config[i].pre_on_sleep = (!rc ? tmp : 0);
+
+ rc = of_property_read_u32(supply_node,
+ "qcom,supply-pre-off-sleep", &tmp);
+ if (rc) {
+ pr_debug("%s: error reading supply pre sleep value. rc=%d\n",
+ __func__, rc);
+ }
+ mp->vreg_config[i].pre_off_sleep = (!rc ? tmp : 0);
+
+ /* post-sleep */
+ rc = of_property_read_u32(supply_node,
+ "qcom,supply-post-on-sleep", &tmp);
+ if (rc) {
+ pr_debug("%s: error reading supply post sleep value. rc=%d\n",
+ __func__, rc);
+ }
+ mp->vreg_config[i].post_on_sleep = (!rc ? tmp : 0);
+
+ rc = of_property_read_u32(supply_node,
+ "qcom,supply-post-off-sleep", &tmp);
+ if (rc) {
+ pr_debug("%s: error reading supply post sleep value. rc=%d\n",
+ __func__, rc);
+ }
+ mp->vreg_config[i].post_off_sleep = (!rc ? tmp : 0);
+
+ pr_debug("%s: %s min=%d, max=%d, enable=%d, disable=%d, preonsleep=%d, postonsleep=%d, preoffsleep=%d, postoffsleep=%d\n",
+ __func__,
+ mp->vreg_config[i].vreg_name,
+ mp->vreg_config[i].min_voltage,
+ mp->vreg_config[i].max_voltage,
+ mp->vreg_config[i].enable_load,
+ mp->vreg_config[i].disable_load,
+ mp->vreg_config[i].pre_on_sleep,
+ mp->vreg_config[i].post_on_sleep,
+ mp->vreg_config[i].pre_off_sleep,
+ mp->vreg_config[i].post_off_sleep
+ );
+ ++i;
+ }
}
- devm_kfree(dev, val_array);
-
return rc;
error:
@@ -378,10 +256,9 @@
devm_kfree(dev, mp->vreg_config);
mp->vreg_config = NULL;
}
+novreg:
mp->num_vreg = 0;
- if (val_array)
- devm_kfree(dev, val_array);
return rc;
}
@@ -937,14 +814,14 @@
struct mdss_panel_common_pdata *panel_data)
{
struct mipi_panel_info *mipi;
- int rc;
+ int rc, i, len;
u8 lanes = 0, bpp;
- u32 h_period, v_period, dsi_pclk_rate;
+ u32 h_period, v_period, dsi_pclk_rate, tmp[9];
struct mdss_dsi_ctrl_pdata *ctrl_pdata;
struct device_node *dsi_ctrl_np = NULL;
struct platform_device *ctrl_pdev = NULL;
- bool broadcast;
bool cont_splash_enabled = false;
+ const char *data;
h_period = ((panel_data->panel_info.lcdc.h_pulse_width)
+ (panel_data->panel_info.lcdc.h_back_porch)
@@ -1010,7 +887,7 @@
mipi->dsi_pclk_rate = dsi_pclk_rate;
dsi_ctrl_np = of_parse_phandle(pdev->dev.of_node,
- "qcom,dsi-ctrl-phandle", 0);
+ "qcom,mdss-dsi-panel-controller", 0);
if (!dsi_ctrl_np) {
pr_err("%s: Dsi controller node not initialized\n", __func__);
return -EPROBE_DEFER;
@@ -1031,13 +908,57 @@
return rc;
}
- broadcast = of_property_read_bool(pdev->dev.of_node,
- "qcom,mdss-pan-broadcast-mode");
- if (broadcast)
- ctrl_pdata->shared_pdata.broadcast_enable = 1;
+ data = of_get_property(ctrl_pdev->dev.of_node,
+ "qcom,platform-strength-ctrl", &len);
+ if ((!data) || (len != 2)) {
+ pr_err("%s:%d, Unable to read Phy Strength ctrl settings",
+ __func__, __LINE__);
+ return -EINVAL;
+ }
+ (panel_data->panel_info.mipi.dsi_phy_db)->strength[0] = data[0];
+ (panel_data->panel_info.mipi.dsi_phy_db)->strength[1] = data[1];
- ctrl_pdata->disp_en_gpio = of_get_named_gpio(pdev->dev.of_node,
- "qcom,enable-gpio", 0);
+ data = of_get_property(ctrl_pdev->dev.of_node,
+ "qcom,platform-regulator-settings", &len);
+ if ((!data) || (len != 7)) {
+ pr_err("%s:%d, Unable to read Phy regulator settings",
+ __func__, __LINE__);
+ return -EINVAL;
+ }
+ for (i = 0; i < len; i++) {
+ (panel_data->panel_info.mipi.dsi_phy_db)->regulator[i]
+ = data[i];
+ }
+
+ data = of_get_property(ctrl_pdev->dev.of_node,
+ "qcom,platform-bist-ctrl", &len);
+ if ((!data) || (len != 6)) {
+ pr_err("%s:%d, Unable to read Phy Bist Ctrl settings",
+ __func__, __LINE__);
+ return -EINVAL;
+ }
+ for (i = 0; i < len; i++) {
+ (panel_data->panel_info.mipi.dsi_phy_db)->bistCtrl[i]
+ = data[i];
+ }
+
+ data = of_get_property(ctrl_pdev->dev.of_node,
+ "qcom,platform-lane-config", &len);
+ if ((!data) || (len != 45)) {
+ pr_err("%s:%d, Unable to read Phy lane configure settings",
+ __func__, __LINE__);
+ return -EINVAL;
+ }
+ for (i = 0; i < len; i++) {
+ (panel_data->panel_info.mipi.dsi_phy_db)->laneCfg[i] =
+ data[i];
+ }
+
+ ctrl_pdata->shared_pdata.broadcast_enable = of_property_read_bool(
+ pdev->dev.of_node, "qcom,mdss-dsi-panel-broadcast-mode");
+
+ ctrl_pdata->disp_en_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node,
+ "qcom,platform-enable-gpio", 0);
if (!gpio_is_valid(ctrl_pdata->disp_en_gpio)) {
pr_err("%s:%d, Disp_en gpio not specified\n",
__func__, __LINE__);
@@ -1051,8 +972,8 @@
}
}
- ctrl_pdata->disp_te_gpio = of_get_named_gpio(pdev->dev.of_node,
- "qcom,te-gpio", 0);
+ ctrl_pdata->disp_te_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node,
+ "qcom,platform-te-gpio", 0);
if (!gpio_is_valid(ctrl_pdata->disp_te_gpio)) {
pr_err("%s:%d, Disp_te gpio not specified\n",
__func__, __LINE__);
@@ -1089,9 +1010,17 @@
ctrl_pdata->disp_te_gpio);
}
+ rc = of_property_read_u32_array(ctrl_pdev->dev.of_node,
+ "qcom,platform-reset-sequence", tmp, MDSS_DSI_RST_SEQ_LEN);
+ if (rc)
+ pr_err("%s:%d, unable to read gpio reset sequence\n",
+ __func__, __LINE__);
+ else
+ for (i = 0; i < MDSS_DSI_RST_SEQ_LEN; ++i)
+ ctrl_pdata->rst_seq[i] = tmp[i];
- ctrl_pdata->rst_gpio = of_get_named_gpio(pdev->dev.of_node,
- "qcom,rst-gpio", 0);
+ ctrl_pdata->rst_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node,
+ "qcom,platform-reset-gpio", 0);
if (!gpio_is_valid(ctrl_pdata->rst_gpio)) {
pr_err("%s:%d, reset gpio not specified\n",
__func__, __LINE__);
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index 8a8e4ca..a8c34f3 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -194,6 +194,8 @@
#define MDSS_DSI_LEN 8 /* 4 x 4 - 6 - 2, bytes dcs header+crc-align */
+#define MDSS_DSI_RST_SEQ_LEN 6
+
struct dsi_buf {
u32 *hdr; /* dsi host header */
char *start; /* buffer start addr */
@@ -346,6 +348,7 @@
u32 pclk_rate;
u32 byte_clk_rate;
struct dss_module_power power_data;
+ int rst_seq[MDSS_DSI_RST_SEQ_LEN];
u32 dsi_irq_mask;
struct mdss_hw *dsi_hw;
@@ -391,9 +394,7 @@
void mdss_dsi_cmd_mdp_start(struct mdss_dsi_ctrl_pdata *ctrl);
void mdss_dsi_cmd_bta_sw_trigger(struct mdss_panel_data *pdata);
void mdss_dsi_ack_err_status(unsigned char *dsi_base);
-void mdss_dsi_clk_enable(struct mdss_dsi_ctrl_pdata *ctrl);
-void mdss_dsi_clk_disable(struct mdss_dsi_ctrl_pdata *ctrl);
-void mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable);
+int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable);
void mdss_dsi_clk_req(struct mdss_dsi_ctrl_pdata *ctrl,
int enable);
void mdss_dsi_controller_cfg(int enable,
@@ -409,8 +410,6 @@
int mdss_dsi_clk_init(struct platform_device *pdev,
struct mdss_dsi_ctrl_pdata *ctrl_pdata);
void mdss_dsi_clk_deinit(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
-void mdss_dsi_prepare_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
-void mdss_dsi_unprepare_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
int mdss_dsi_enable_bus_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
void mdss_dsi_disable_bus_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
void mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable);
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index 2f29b3d..055f233 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -44,6 +44,14 @@
void mdss_dsi_ctrl_init(struct mdss_dsi_ctrl_pdata *ctrl)
{
+ if (ctrl->shared_pdata.broadcast_enable)
+ if (ctrl->panel_data.panel_info.pdest
+ == DISPLAY_1) {
+ pr_debug("%s: Broadcast mode enabled.\n",
+ __func__);
+ left_ctrl_pdata = ctrl;
+ }
+
if (ctrl->panel_data.panel_info.pdest == DISPLAY_1) {
mdss_dsi0_hw.ptr = (void *)(ctrl);
ctrl->dsi_hw = &mdss_dsi0_hw;
@@ -72,34 +80,6 @@
mdss_dsi_buf_alloc(&ctrl->rx_buf, SZ_4K);
}
-/*
- * acquire ctrl->mutex first
- */
-void mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable)
-{
- mutex_lock(&ctrl->mutex);
- if (enable) {
- if (ctrl->clk_cnt == 0) {
- mdss_dsi_enable_bus_clocks(ctrl);
- mdss_dsi_prepare_clocks(ctrl);
- mdss_dsi_clk_enable(ctrl);
- }
- ctrl->clk_cnt++;
- } else {
- if (ctrl->clk_cnt) {
- ctrl->clk_cnt--;
- if (ctrl->clk_cnt == 0) {
- mdss_dsi_clk_disable(ctrl);
- mdss_dsi_unprepare_clocks(ctrl);
- mdss_dsi_disable_bus_clocks(ctrl);
- }
- }
- }
- pr_debug("%s: ctrl ndx=%d enabled=%d clk_cnt=%d\n",
- __func__, ctrl->ndx, enable, ctrl->clk_cnt);
- mutex_unlock(&ctrl->mutex);
-}
-
void mdss_dsi_clk_req(struct mdss_dsi_ctrl_pdata *ctrl, int enable)
{
if (enable == 0) {
@@ -861,13 +841,6 @@
else
MIPI_OUTP(ctrl_pdata->ctrl_base + 0x3C, 0x14000000);
- if (ctrl_pdata->shared_pdata.broadcast_enable)
- if (pdata->panel_info.pdest == DISPLAY_1) {
- pr_debug("%s: Broadcast mode enabled.\n",
- __func__);
- left_ctrl_pdata = ctrl_pdata;
- }
-
data = 0;
if (pinfo->te_sel)
data |= BIT(31);
@@ -1209,6 +1182,8 @@
{
u32 dsi_ctrl, data;
int video_mode;
+ u32 left_dsi_ctrl = 0;
+ bool left_ctrl_restore = false;
if (ctrl->shared_pdata.broadcast_enable) {
if (ctrl->ndx == DSI_CTRL_0) {
@@ -1221,13 +1196,15 @@
if (ctrl->shared_pdata.broadcast_enable) {
if ((ctrl->ndx == DSI_CTRL_1)
&& (left_ctrl_pdata != NULL)) {
- dsi_ctrl = MIPI_INP(left_ctrl_pdata->ctrl_base
+ left_dsi_ctrl = MIPI_INP(left_ctrl_pdata->ctrl_base
+ 0x0004);
- video_mode = dsi_ctrl & 0x02; /* VIDEO_MODE_EN */
+ video_mode =
+ left_dsi_ctrl & 0x02; /* VIDEO_MODE_EN */
if (video_mode) {
- data = dsi_ctrl | 0x04; /* CMD_MODE_EN */
+ data = left_dsi_ctrl | 0x04; /* CMD_MODE_EN */
MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0004,
data);
+ left_ctrl_restore = true;
}
}
}
@@ -1246,6 +1223,10 @@
mdss_dsi_cmds2buf_tx(ctrl, cmds, cnt);
+ if (left_ctrl_restore)
+ MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0004,
+ left_dsi_ctrl); /*restore */
+
if (video_mode)
MIPI_OUTP((ctrl->ctrl_base) + 0x0004,
dsi_ctrl); /* restore */
@@ -1280,6 +1261,45 @@
struct dsi_buf *tp, *rp;
int no_max_pkt_size;
char cmd;
+ u32 dsi_ctrl, data;
+ int video_mode;
+ u32 left_dsi_ctrl = 0;
+ bool left_ctrl_restore = false;
+
+ if (ctrl->shared_pdata.broadcast_enable) {
+ if (ctrl->ndx == DSI_CTRL_0) {
+ pr_debug("%s: Broadcast mode. 1st ctrl\n",
+ __func__);
+ return 0;
+ }
+ }
+
+ if (ctrl->shared_pdata.broadcast_enable) {
+ if ((ctrl->ndx == DSI_CTRL_1)
+ && (left_ctrl_pdata != NULL)) {
+ left_dsi_ctrl = MIPI_INP(left_ctrl_pdata->ctrl_base
+ + 0x0004);
+ video_mode = left_dsi_ctrl & 0x02; /* VIDEO_MODE_EN */
+ if (video_mode) {
+ data = left_dsi_ctrl | 0x04; /* CMD_MODE_EN */
+ MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0004,
+ data);
+ left_ctrl_restore = true;
+ }
+ }
+ }
+
+ /* 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->ctrl_base) + 0x0004);
+ video_mode = dsi_ctrl & 0x02; /* VIDEO_MODE_EN */
+ if (video_mode) {
+ data = dsi_ctrl | 0x04; /* CMD_MODE_EN */
+ MIPI_OUTP((ctrl->ctrl_base) + 0x0004, data);
+ }
no_max_pkt_size = rx_flags & CMD_REQ_NO_MAX_PKT_SIZE;
if (no_max_pkt_size)
@@ -1378,6 +1398,13 @@
break;
}
+ if (left_ctrl_restore)
+ MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0004,
+ left_dsi_ctrl); /*restore */
+ if (video_mode)
+ MIPI_OUTP((ctrl->ctrl_base) + 0x0004,
+ dsi_ctrl); /* restore */
+
return rp->len;
}
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index 05a84e3..9a019f9 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -158,6 +158,7 @@
void mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable)
{
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+ int i;
if (pdata == NULL) {
pr_err("%s: Invalid input data\n", __func__);
@@ -181,12 +182,11 @@
pr_debug("%s: enable = %d\n", __func__, enable);
if (enable) {
- gpio_set_value((ctrl_pdata->rst_gpio), 1);
- msleep(20);
- gpio_set_value((ctrl_pdata->rst_gpio), 0);
- udelay(200);
- gpio_set_value((ctrl_pdata->rst_gpio), 1);
- msleep(20);
+ for (i = 0; i < MDSS_DSI_RST_SEQ_LEN; ++i) {
+ gpio_set_value((ctrl_pdata->rst_gpio),
+ ctrl_pdata->rst_seq[i]);
+ msleep(ctrl_pdata->rst_seq[++i]);
+ }
if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
gpio_set_value((ctrl_pdata->disp_en_gpio), 1);
if (ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT) {
@@ -348,11 +348,11 @@
len -= dchdr->dlen;
}
- pcmds->link_state = DSI_LP_MODE; /* default */
-
data = of_get_property(np, link_key, NULL);
- if (!strncmp(data, "DSI_HS_MODE", 11))
+ if (!strncmp(data, "dsi_hs_mode", 11))
pcmds->link_state = DSI_HS_MODE;
+ else
+ pcmds->link_state = DSI_LP_MODE;
pr_debug("%s: dcs_cmd=%x len=%d, cmd_cnt=%d link_state=%d\n", __func__,
pcmds->buf[0], pcmds->blen, pcmds->cmd_cnt, pcmds->link_state);
@@ -361,44 +361,188 @@
}
+static int mdss_panel_dt_get_dst_fmt(u32 bpp, char mipi_mode, u32 pixel_packing,
+ char *dst_format)
+{
+ int rc = 0;
+ switch (bpp) {
+ case 3:
+ *dst_format = DSI_CMD_DST_FORMAT_RGB111;
+ break;
+ case 8:
+ *dst_format = DSI_CMD_DST_FORMAT_RGB332;
+ break;
+ case 12:
+ *dst_format = DSI_CMD_DST_FORMAT_RGB444;
+ break;
+ case 16:
+ switch (mipi_mode) {
+ case DSI_VIDEO_MODE:
+ *dst_format = DSI_VIDEO_DST_FORMAT_RGB565;
+ break;
+ case DSI_CMD_MODE:
+ *dst_format = DSI_CMD_DST_FORMAT_RGB565;
+ break;
+ default:
+ *dst_format = DSI_VIDEO_DST_FORMAT_RGB565;
+ break;
+ }
+ break;
+ case 18:
+ switch (mipi_mode) {
+ case DSI_VIDEO_MODE:
+ if (pixel_packing == 0)
+ *dst_format = DSI_VIDEO_DST_FORMAT_RGB666;
+ else
+ *dst_format = DSI_VIDEO_DST_FORMAT_RGB666_LOOSE;
+ break;
+ case DSI_CMD_MODE:
+ *dst_format = DSI_CMD_DST_FORMAT_RGB666;
+ break;
+ default:
+ if (pixel_packing == 0)
+ *dst_format = DSI_VIDEO_DST_FORMAT_RGB666;
+ else
+ *dst_format = DSI_VIDEO_DST_FORMAT_RGB666_LOOSE;
+ break;
+ }
+ break;
+ case 24:
+ switch (mipi_mode) {
+ case DSI_VIDEO_MODE:
+ *dst_format = DSI_VIDEO_DST_FORMAT_RGB888;
+ break;
+ case DSI_CMD_MODE:
+ *dst_format = DSI_CMD_DST_FORMAT_RGB888;
+ break;
+ default:
+ *dst_format = DSI_VIDEO_DST_FORMAT_RGB888;
+ break;
+ }
+ break;
+ default:
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+
+
+static int mdss_dsi_parse_fbc_params(struct device_node *np,
+ struct mdss_panel_info *panel_info)
+{
+ int rc, fbc_enabled = 0;
+ u32 tmp;
+
+ fbc_enabled = of_property_read_bool(np, "qcom,mdss-dsi-fbc-enable");
+ if (fbc_enabled) {
+ pr_debug("%s:%d FBC panel enabled.\n", __func__, __LINE__);
+ panel_info->fbc.enabled = 1;
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-fbc-bpp", &tmp);
+ panel_info->fbc.target_bpp = (!rc ? tmp : panel_info->bpp);
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-fbc-packing",
+ &tmp);
+ panel_info->fbc.comp_mode = (!rc ? tmp : 0);
+ panel_info->fbc.qerr_enable = of_property_read_bool(np,
+ "qcom,mdss-dsi-fbc-quant-error");
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-fbc-bias", &tmp);
+ panel_info->fbc.cd_bias = (!rc ? tmp : 0);
+ panel_info->fbc.pat_enable = of_property_read_bool(np,
+ "qcom,mdss-dsi-fbc-pat-mode");
+ panel_info->fbc.vlc_enable = of_property_read_bool(np,
+ "qcom,mdss-dsi-fbc-vlc-mode");
+ panel_info->fbc.bflc_enable = of_property_read_bool(np,
+ "qcom,mdss-dsi-fbc-bflc-mode");
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-fbc-h-line-budget",
+ &tmp);
+ panel_info->fbc.line_x_budget = (!rc ? tmp : 0);
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-fbc-budget-ctrl",
+ &tmp);
+ panel_info->fbc.block_x_budget = (!rc ? tmp : 0);
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-fbc-block-budget",
+ &tmp);
+ panel_info->fbc.block_budget = (!rc ? tmp : 0);
+ rc = of_property_read_u32(np,
+ "qcom,mdss-dsi-fbc-lossless-threshold", &tmp);
+ panel_info->fbc.lossless_mode_thd = (!rc ? tmp : 0);
+ rc = of_property_read_u32(np,
+ "qcom,mdss-dsi-fbc-lossy-threshold", &tmp);
+ panel_info->fbc.lossy_mode_thd = (!rc ? tmp : 0);
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-fbc-rgb-threshold",
+ &tmp);
+ panel_info->fbc.lossy_rgb_thd = (!rc ? tmp : 0);
+ rc = of_property_read_u32(np,
+ "qcom,mdss-dsi-fbc-lossy-mode-idx", &tmp);
+ panel_info->fbc.lossy_mode_idx = (!rc ? tmp : 0);
+ } else {
+ pr_debug("%s:%d Panel does not support FBC.\n",
+ __func__, __LINE__);
+ panel_info->fbc.enabled = 0;
+ panel_info->fbc.target_bpp =
+ panel_info->bpp;
+ }
+ return 0;
+}
+
+
static int mdss_panel_parse_dt(struct platform_device *pdev,
- struct mdss_panel_common_pdata *panel_data)
+ struct mdss_panel_common_pdata *panel_data)
{
struct device_node *np = pdev->dev.of_node;
- u32 res[6], tmp;
- u32 fbc_res[7];
+ u32 tmp;
int rc, i, len;
const char *data;
- static const char *bl_ctrl_type, *pdest;
- bool fbc_enabled = false;
+ static const char *pdest;
- rc = of_property_read_u32_array(np, "qcom,mdss-pan-res", res, 2);
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-panel-width", &tmp);
if (rc) {
- pr_err("%s:%d, panel resolution not specified\n",
+ pr_err("%s:%d, panel width not specified\n",
__func__, __LINE__);
return -EINVAL;
}
- panel_data->panel_info.xres = (!rc ? res[0] : 640);
- panel_data->panel_info.yres = (!rc ? res[1] : 480);
+ panel_data->panel_info.xres = (!rc ? tmp : 640);
- rc = of_property_read_u32_array(np, "qcom,mdss-pan-active-res", res, 2);
- if (rc == 0) {
- panel_data->panel_info.lcdc.xres_pad =
- panel_data->panel_info.xres - res[0];
- panel_data->panel_info.lcdc.yres_pad =
- panel_data->panel_info.yres - res[1];
- }
-
- rc = of_property_read_u32(np, "qcom,mdss-pan-bpp", &tmp);
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-panel-height", &tmp);
if (rc) {
- pr_err("%s:%d, panel bpp not specified\n",
+ pr_err("%s:%d, panel height not specified\n",
__func__, __LINE__);
return -EINVAL;
}
+ panel_data->panel_info.yres = (!rc ? tmp : 480);
+
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-h-left-border", &tmp);
+ panel_data->panel_info.lcdc.xres_pad = (!rc ? tmp : 0);
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-h-right-border", &tmp);
+ if (!rc)
+ panel_data->panel_info.lcdc.xres_pad += tmp;
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-v-top-border", &tmp);
+ panel_data->panel_info.lcdc.yres_pad = (!rc ? tmp : 0);
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-v-bottom-border", &tmp);
+ if (!rc)
+ panel_data->panel_info.lcdc.yres_pad += tmp;
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-bpp", &tmp);
+ if (rc) {
+ pr_err("%s:%d, bpp not specified\n", __func__, __LINE__);
+ return -EINVAL;
+ }
panel_data->panel_info.bpp = (!rc ? tmp : 24);
-
+ panel_data->panel_info.mipi.mode = DSI_VIDEO_MODE;
+ data = of_get_property(np, "qcom,mdss-dsi-panel-type", NULL);
+ if (data && !strncmp(data, "dsi_cmd_mode", 12))
+ panel_data->panel_info.mipi.mode = DSI_CMD_MODE;
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-pixel-packing", &tmp);
+ tmp = (!rc ? tmp : 0);
+ rc = mdss_panel_dt_get_dst_fmt(panel_data->panel_info.bpp,
+ panel_data->panel_info.mipi.mode, tmp,
+ &(panel_data->panel_info.mipi.dst_format));
+ if (rc) {
+ pr_debug("%s: problem determining dst format. Set Default\n",
+ __func__);
+ panel_data->panel_info.mipi.dst_format =
+ DSI_VIDEO_DST_FORMAT_RGB888;
+ }
pdest = of_get_property(pdev->dev.of_node,
- "qcom,mdss-pan-dest", NULL);
+ "qcom,mdss-dsi-panel-destination", NULL);
if (strlen(pdest) != 9) {
pr_err("%s: Unknown pdest specified\n", __func__);
return -EINVAL;
@@ -412,141 +556,132 @@
__func__);
panel_data->panel_info.pdest = DISPLAY_1;
}
-
- rc = of_property_read_u32_array(np,
- "qcom,mdss-pan-porch-values", res, 6);
- panel_data->panel_info.lcdc.h_back_porch = (!rc ? res[0] : 6);
- panel_data->panel_info.lcdc.h_pulse_width = (!rc ? res[1] : 2);
- panel_data->panel_info.lcdc.h_front_porch = (!rc ? res[2] : 6);
- panel_data->panel_info.lcdc.v_back_porch = (!rc ? res[3] : 6);
- panel_data->panel_info.lcdc.v_pulse_width = (!rc ? res[4] : 2);
- panel_data->panel_info.lcdc.v_front_porch = (!rc ? res[5] : 6);
-
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-h-front-porch", &tmp);
+ panel_data->panel_info.lcdc.h_front_porch = (!rc ? tmp : 6);
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-h-back-porch", &tmp);
+ panel_data->panel_info.lcdc.h_back_porch = (!rc ? tmp : 6);
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-h-pulse-width", &tmp);
+ panel_data->panel_info.lcdc.h_pulse_width = (!rc ? tmp : 2);
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-h-sync-skew", &tmp);
+ panel_data->panel_info.lcdc.hsync_skew = (!rc ? tmp : 0);
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-v-back-porch", &tmp);
+ panel_data->panel_info.lcdc.v_back_porch = (!rc ? tmp : 6);
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-v-front-porch", &tmp);
+ panel_data->panel_info.lcdc.v_front_porch = (!rc ? tmp : 6);
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-v-pulse-width", &tmp);
+ panel_data->panel_info.lcdc.v_pulse_width = (!rc ? tmp : 2);
rc = of_property_read_u32(np,
- "qcom,mdss-pan-underflow-clr", &tmp);
+ "qcom,mdss-dsi-underflow-color", &tmp);
panel_data->panel_info.lcdc.underflow_clr = (!rc ? tmp : 0xff);
-
- bl_ctrl_type = of_get_property(pdev->dev.of_node,
- "qcom,mdss-pan-bl-ctrl", NULL);
- if ((bl_ctrl_type) && (!strncmp(bl_ctrl_type, "bl_ctrl_wled", 12))) {
- led_trigger_register_simple("bkl-trigger", &bl_led_trigger);
- pr_debug("%s: SUCCESS-> WLED TRIGGER register\n", __func__);
-
- panel_data->panel_info.bklt_ctrl = BL_WLED;
- } else if (!strncmp(bl_ctrl_type, "bl_ctrl_pwm", 11)) {
- panel_data->panel_info.bklt_ctrl = BL_PWM;
-
- rc = of_property_read_u32(np, "qcom,pwm-period", &tmp);
- if (rc) {
- pr_err("%s:%d, Error, panel pwm_period\n",
+ rc = of_property_read_u32(np,
+ "qcom,mdss-dsi-border-color", &tmp);
+ panel_data->panel_info.lcdc.border_clr = (!rc ? tmp : 0);
+ panel_data->panel_info.bklt_ctrl = UNKNOWN_CTRL;
+ data = of_get_property(np, "qcom,mdss-dsi-bl-pmic-control-type", NULL);
+ if (data) {
+ if (!strncmp(data, "bl_ctrl_wled", 12)) {
+ led_trigger_register_simple("bkl-trigger",
+ &bl_led_trigger);
+ pr_debug("%s: SUCCESS-> WLED TRIGGER register\n",
+ __func__);
+ panel_data->panel_info.bklt_ctrl = BL_WLED;
+ } else if (!strncmp(data, "bl_ctrl_pwm", 11)) {
+ panel_data->panel_info.bklt_ctrl = BL_PWM;
+ rc = of_property_read_u32(np,
+ "qcom,mdss-dsi-bl-pmic-pwm-frequency", &tmp);
+ if (rc) {
+ pr_err("%s:%d, Error, panel pwm_period\n",
__func__, __LINE__);
- return -EINVAL;
- }
- panel_data->panel_info.pwm_period = tmp;
-
- rc = of_property_read_u32(np, "qcom,pwm-lpg-channel", &tmp);
- if (rc) {
- pr_err("%s:%d, Error, dsi lpg channel\n",
+ return -EINVAL;
+ }
+ panel_data->panel_info.pwm_period = tmp;
+ rc = of_property_read_u32(np,
+ "qcom,mdss-dsi-bl-pmic-bank-select", &tmp);
+ if (rc) {
+ pr_err("%s:%d, Error, dsi lpg channel\n",
__func__, __LINE__);
- return -EINVAL;
+ return -EINVAL;
+ }
+ panel_data->panel_info.pwm_lpg_chan = tmp;
+ tmp = of_get_named_gpio(np,
+ "qcom,mdss-dsi-pwm-gpio", 0);
+ panel_data->panel_info.pwm_pmic_gpio = tmp;
+ } else if (!strncmp(data, "bl_ctrl_dcs", 11)) {
+ panel_data->panel_info.bklt_ctrl = BL_DCS_CMD;
}
- panel_data->panel_info.pwm_lpg_chan = tmp;
-
- tmp = of_get_named_gpio(np, "qcom,pwm-pmic-gpio", 0);
- panel_data->panel_info.pwm_pmic_gpio = tmp;
- } else if (!strncmp(bl_ctrl_type, "bl_ctrl_dcs", 11)) {
- panel_data->panel_info.bklt_ctrl = BL_DCS_CMD;
- } else {
- pr_debug("%s: Unknown backlight control\n", __func__);
- panel_data->panel_info.bklt_ctrl = UNKNOWN_CTRL;
}
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-bl-min-level", &tmp);
+ panel_data->panel_info.bl_min = (!rc ? tmp : 0);
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-bl-max-level", &tmp);
+ panel_data->panel_info.bl_max = (!rc ? tmp : 255);
- rc = of_property_read_u32_array(np,
- "qcom,mdss-pan-bl-levels", res, 2);
- panel_data->panel_info.bl_min = (!rc ? res[0] : 0);
- panel_data->panel_info.bl_max = (!rc ? res[1] : 255);
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-interleave-mode", &tmp);
+ panel_data->panel_info.mipi.interleave_mode = (!rc ? tmp : 0);
- rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-mode", &tmp);
- panel_data->panel_info.mipi.mode = (!rc ? tmp : DSI_VIDEO_MODE);
-
- rc = of_property_read_u32(np, "qcom,mdss-vsync-enable", &tmp);
- panel_data->panel_info.mipi.vsync_enable = (!rc ? tmp : 0);
-
- rc = of_property_read_u32(np, "qcom,mdss-hw-vsync-mode", &tmp);
- panel_data->panel_info.mipi.hw_vsync_mode = (!rc ? tmp : 0);
-
+ panel_data->panel_info.mipi.vsync_enable = of_property_read_bool(np,
+ "qcom,mdss-dsi-te-check-enable");
+ panel_data->panel_info.mipi.hw_vsync_mode = of_property_read_bool(np,
+ "qcom,mdss-dsi-te-using-te-pin");
rc = of_property_read_u32(np,
- "qcom,mdss-pan-dsi-h-pulse-mode", &tmp);
+ "qcom,mdss-dsi-h-sync-pulse", &tmp);
panel_data->panel_info.mipi.pulse_mode_hsa_he = (!rc ? tmp : false);
- rc = of_property_read_u32_array(np,
- "qcom,mdss-pan-dsi-h-power-stop", res, 3);
- panel_data->panel_info.mipi.hbp_power_stop = (!rc ? res[0] : false);
- panel_data->panel_info.mipi.hsa_power_stop = (!rc ? res[1] : false);
- panel_data->panel_info.mipi.hfp_power_stop = (!rc ? res[2] : false);
-
- rc = of_property_read_u32_array(np,
- "qcom,mdss-pan-dsi-bllp-power-stop", res, 2);
- panel_data->panel_info.mipi.bllp_power_stop =
- (!rc ? res[0] : false);
- panel_data->panel_info.mipi.eof_bllp_power_stop =
- (!rc ? res[1] : false);
-
+ panel_data->panel_info.mipi.hfp_power_stop = of_property_read_bool(np,
+ "qcom,mdss-dsi-hfp-power-mode");
+ panel_data->panel_info.mipi.hsa_power_stop = of_property_read_bool(np,
+ "qcom,mdss-dsi-hsa-power-mode");
+ panel_data->panel_info.mipi.hbp_power_stop = of_property_read_bool(np,
+ "qcom,mdss-dsi-hbp-power-mode");
+ panel_data->panel_info.mipi.bllp_power_stop = of_property_read_bool(np,
+ "qcom,mdss-dsi-bllp-power-mode");
+ panel_data->panel_info.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-pan-dsi-traffic-mode", &tmp);
+ "qcom,mdss-dsi-traffic-mode", &tmp);
panel_data->panel_info.mipi.traffic_mode =
(!rc ? tmp : DSI_NON_BURST_SYNCH_PULSE);
-
rc = of_property_read_u32(np,
- "qcom,mdss-pan-insert-dcs-cmd", &tmp);
+ "qcom,mdss-dsi-te-dcs-command", &tmp);
panel_data->panel_info.mipi.insert_dcs_cmd =
(!rc ? tmp : 1);
-
rc = of_property_read_u32(np,
- "qcom,mdss-pan-wr-mem-continue", &tmp);
+ "qcom,mdss-dsi-te-v-sync-continue-lines", &tmp);
panel_data->panel_info.mipi.wr_mem_continue =
(!rc ? tmp : 0x3c);
-
rc = of_property_read_u32(np,
- "qcom,mdss-pan-wr-mem-start", &tmp);
+ "qcom,mdss-dsi-te-v-sync-rd-ptr-irq-line", &tmp);
panel_data->panel_info.mipi.wr_mem_start =
(!rc ? tmp : 0x2c);
-
rc = of_property_read_u32(np,
- "qcom,mdss-pan-te-sel", &tmp);
+ "qcom,mdss-dsi-te-pin-select", &tmp);
panel_data->panel_info.mipi.te_sel =
(!rc ? tmp : 1);
-
- rc = of_property_read_u32(np,
- "qcom,mdss-pan-dsi-dst-format", &tmp);
- panel_data->panel_info.mipi.dst_format =
- (!rc ? tmp : DSI_VIDEO_DST_FORMAT_RGB888);
-
- rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-vc", &tmp);
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-virtual-channel-id", &tmp);
panel_data->panel_info.mipi.vc = (!rc ? tmp : 0);
-
- rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-rgb-swap", &tmp);
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-color-order", &tmp);
panel_data->panel_info.mipi.rgb_swap = (!rc ? tmp : DSI_RGB_SWAP_RGB);
+ panel_data->panel_info.mipi.data_lane0 = of_property_read_bool(np,
+ "qcom,mdss-dsi-lane-0-state");
+ panel_data->panel_info.mipi.data_lane1 = of_property_read_bool(np,
+ "qcom,mdss-dsi-lane-1-state");
+ panel_data->panel_info.mipi.data_lane2 = of_property_read_bool(np,
+ "qcom,mdss-dsi-lane-2-state");
+ panel_data->panel_info.mipi.data_lane3 = of_property_read_bool(np,
+ "qcom,mdss-dsi-lane-3-state");
- rc = of_property_read_u32_array(np,
- "qcom,mdss-pan-dsi-data-lanes", res, 4);
- panel_data->panel_info.mipi.data_lane0 = (!rc ? res[0] : true);
- panel_data->panel_info.mipi.data_lane1 = (!rc ? res[1] : false);
- panel_data->panel_info.mipi.data_lane2 = (!rc ? res[2] : false);
- panel_data->panel_info.mipi.data_lane3 = (!rc ? res[3] : false);
-
- rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-dlane-swap", &tmp);
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-lane-map", &tmp);
panel_data->panel_info.mipi.dlane_swap = (!rc ? tmp : 0);
- rc = of_property_read_u32_array(np, "qcom,mdss-pan-dsi-t-clk", res, 2);
- panel_data->panel_info.mipi.t_clk_pre = (!rc ? res[0] : 0x24);
- panel_data->panel_info.mipi.t_clk_post = (!rc ? res[1] : 0x03);
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-t-clk-pre", &tmp);
+ panel_data->panel_info.mipi.t_clk_pre = (!rc ? tmp : 0x24);
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-t-clk-post", &tmp);
+ panel_data->panel_info.mipi.t_clk_post = (!rc ? tmp : 0x03);
- rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-stream", &tmp);
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-stream", &tmp);
panel_data->panel_info.mipi.stream = (!rc ? tmp : 0);
- rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-mdp-tr", &tmp);
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-mdp-trigger", &tmp);
panel_data->panel_info.mipi.mdp_trigger =
(!rc ? tmp : DSI_CMD_TRIGGER_SW);
if (panel_data->panel_info.mipi.mdp_trigger > 6) {
@@ -556,7 +691,7 @@
DSI_CMD_TRIGGER_SW;
}
- rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-dma-tr", &tmp);
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-dma-trigger", &tmp);
panel_data->panel_info.mipi.dma_trigger =
(!rc ? tmp : DSI_CMD_TRIGGER_SW);
if (panel_data->panel_info.mipi.dma_trigger > 6) {
@@ -565,23 +700,11 @@
panel_data->panel_info.mipi.dma_trigger =
DSI_CMD_TRIGGER_SW;
}
-
- rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-frame-rate", &tmp);
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-panel-frame-rate", &tmp);
panel_data->panel_info.mipi.frame_rate = (!rc ? tmp : 60);
-
- rc = of_property_read_u32(np, "qcom,mdss-pan-clk-rate", &tmp);
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-panel-clock-rate", &tmp);
panel_data->panel_info.clk_rate = (!rc ? tmp : 0);
-
- data = of_get_property(np, "qcom,panel-phy-regulatorSettings", &len);
- if ((!data) || (len != 7)) {
- pr_err("%s:%d, Unable to read Phy regulator settings",
- __func__, __LINE__);
- goto error;
- }
- for (i = 0; i < len; i++)
- phy_params.regulator[i] = data[i];
-
- data = of_get_property(np, "qcom,panel-phy-timingSettings", &len);
+ data = of_get_property(np, "qcom,mdss-dsi-panel-timings", &len);
if ((!data) || (len != 12)) {
pr_err("%s:%d, Unable to read Phy timing settings",
__func__, __LINE__);
@@ -590,87 +713,15 @@
for (i = 0; i < len; i++)
phy_params.timing[i] = data[i];
- data = of_get_property(np, "qcom,panel-phy-strengthCtrl", &len);
- if ((!data) || (len != 2)) {
- pr_err("%s:%d, Unable to read Phy Strength ctrl settings",
- __func__, __LINE__);
- goto error;
- }
- phy_params.strength[0] = data[0];
- phy_params.strength[1] = data[1];
-
- data = of_get_property(np, "qcom,panel-phy-bistCtrl", &len);
- if ((!data) || (len != 6)) {
- pr_err("%s:%d, Unable to read Phy Bist Ctrl settings",
- __func__, __LINE__);
- goto error;
- }
- for (i = 0; i < len; i++)
- phy_params.bistCtrl[i] = data[i];
-
- data = of_get_property(np, "qcom,panel-phy-laneConfig", &len);
- if ((!data) || (len != 45)) {
- pr_err("%s:%d, Unable to read Phy lane configure settings",
- __func__, __LINE__);
- goto error;
- }
- for (i = 0; i < len; i++)
- phy_params.laneCfg[i] = data[i];
-
panel_data->panel_info.mipi.dsi_phy_db = &phy_params;
- fbc_enabled = of_property_read_bool(np,
- "qcom,fbc-enabled");
- if (fbc_enabled) {
- pr_debug("%s:%d FBC panel enabled.\n", __func__, __LINE__);
- panel_data->panel_info.fbc.enabled = 1;
-
- rc = of_property_read_u32_array(np,
- "qcom,fbc-mode", fbc_res, 7);
- panel_data->panel_info.fbc.target_bpp =
- (!rc ? fbc_res[0] : panel_data->panel_info.bpp);
- panel_data->panel_info.fbc.comp_mode = (!rc ? fbc_res[1] : 0);
- panel_data->panel_info.fbc.qerr_enable =
- (!rc ? fbc_res[2] : 0);
- panel_data->panel_info.fbc.cd_bias = (!rc ? fbc_res[3] : 0);
- panel_data->panel_info.fbc.pat_enable = (!rc ? fbc_res[4] : 0);
- panel_data->panel_info.fbc.vlc_enable = (!rc ? fbc_res[5] : 0);
- panel_data->panel_info.fbc.bflc_enable =
- (!rc ? fbc_res[6] : 0);
-
- rc = of_property_read_u32_array(np,
- "qcom,fbc-budget-ctl", fbc_res, 3);
- panel_data->panel_info.fbc.line_x_budget =
- (!rc ? fbc_res[0] : 0);
- panel_data->panel_info.fbc.block_x_budget =
- (!rc ? fbc_res[1] : 0);
- panel_data->panel_info.fbc.block_budget =
- (!rc ? fbc_res[2] : 0);
-
- rc = of_property_read_u32_array(np,
- "qcom,fbc-lossy-mode", fbc_res, 4);
- panel_data->panel_info.fbc.lossless_mode_thd =
- (!rc ? fbc_res[0] : 0);
- panel_data->panel_info.fbc.lossy_mode_thd =
- (!rc ? fbc_res[1] : 0);
- panel_data->panel_info.fbc.lossy_rgb_thd =
- (!rc ? fbc_res[2] : 0);
- panel_data->panel_info.fbc.lossy_mode_idx =
- (!rc ? fbc_res[3] : 0);
-
- } else {
- pr_debug("%s:%d Panel does not support FBC.\n",
- __func__, __LINE__);
- panel_data->panel_info.fbc.enabled = 0;
- panel_data->panel_info.fbc.target_bpp =
- panel_data->panel_info.bpp;
- }
+ mdss_dsi_parse_fbc_params(np, &panel_data->panel_info);
mdss_dsi_parse_dcs_cmds(np, &panel_data->on_cmds,
- "qcom,panel-on-cmds", "qcom,on-cmds-dsi-state");
+ "qcom,mdss-dsi-on-command", "qcom,mdss-dsi-on-command-state");
mdss_dsi_parse_dcs_cmds(np, &panel_data->off_cmds,
- "qcom,panel-off-cmds", "qcom,off-cmds-dsi-state");
+ "qcom,mdss-dsi-off-command", "qcom,mdss-dsi-off-command-state");
return 0;
@@ -683,12 +734,12 @@
int rc = 0;
static struct mdss_panel_common_pdata vendor_pdata;
static const char *panel_name;
-
pr_debug("%s:%d, debug info id=%d", __func__, __LINE__, pdev->id);
if (!pdev->dev.of_node)
return -ENODEV;
- panel_name = of_get_property(pdev->dev.of_node, "label", NULL);
+ panel_name = of_get_property(pdev->dev.of_node,
+ "qcom,mdss-dsi-panel-name", NULL);
if (!panel_name)
pr_info("%s:%d, panel name not specified\n",
__func__, __LINE__);
diff --git a/drivers/video/msm/mdss/mdss_edp.c b/drivers/video/msm/mdss/mdss_edp.c
index aea2de0..3e0bc6d 100644
--- a/drivers/video/msm/mdss/mdss_edp.c
+++ b/drivers/video/msm/mdss/mdss_edp.c
@@ -24,14 +24,19 @@
#include <linux/err.h>
#include <linux/regulator/consumer.h>
#include <linux/pwm.h>
-
+#include <linux/clk.h>
+#include <linux/spinlock_types.h>
+#include <linux/kthread.h>
#include <asm/system.h>
#include <asm/mach-types.h>
-
#include <mach/hardware.h>
#include <mach/dma.h>
+#include "mdss.h"
+#include "mdss_panel.h"
+#include "mdss_mdp.h"
#include "mdss_edp.h"
+#include "mdss_debug.h"
#define RGB_COMPONENTS 3
#define VDDA_MIN_UV 1800000 /* uV units */
@@ -39,26 +44,7 @@
#define VDDA_UA_ON_LOAD 100000 /* uA units */
#define VDDA_UA_OFF_LOAD 100 /* uA units */
-static int mdss_edp_get_base_address(struct mdss_edp_drv_pdata *edp_drv);
-static int mdss_edp_get_mmss_cc_base_address(struct mdss_edp_drv_pdata
- *edp_drv);
-static int mdss_edp_regulator_init(struct mdss_edp_drv_pdata *edp_drv);
static int mdss_edp_regulator_on(struct mdss_edp_drv_pdata *edp_drv);
-static int mdss_edp_regulator_off(struct mdss_edp_drv_pdata *edp_drv);
-static int mdss_edp_gpio_panel_en(struct mdss_edp_drv_pdata *edp_drv);
-static int mdss_edp_pwm_config(struct mdss_edp_drv_pdata *edp_drv);
-
-static void mdss_edp_edid2pinfo(struct mdss_edp_drv_pdata *edp_drv);
-static void mdss_edp_fill_edid_data(struct mdss_edp_drv_pdata *edp_drv);
-static void mdss_edp_fill_dpcd_data(struct mdss_edp_drv_pdata *edp_drv);
-
-static int mdss_edp_device_register(struct mdss_edp_drv_pdata *edp_drv);
-
-static void mdss_edp_config_sync(unsigned char *edp_base);
-static void mdss_edp_config_sw_div(unsigned char *edp_base);
-static void mdss_edp_config_static_mdiv(unsigned char *edp_base);
-static void mdss_edp_enable(unsigned char *edp_base, int enable);
-
/*
* Init regulator needed for edp, 8974_l12
*/
@@ -256,79 +242,130 @@
}
}
-void mdss_edp_config_sync(unsigned char *edp_base)
+void mdss_edp_config_sync(unsigned char *base)
{
int ret = 0;
- ret = edp_read(edp_base + 0xc); /* EDP_CONFIGURATION_CTRL */
+ ret = edp_read(base + 0xc); /* EDP_CONFIGURATION_CTRL */
ret &= ~0x733;
ret |= (0x55 & 0x733);
- edp_write(edp_base + 0xc, ret);
- edp_write(edp_base + 0xc, 0x55); /* EDP_CONFIGURATION_CTRL */
+ edp_write(base + 0xc, ret);
+ edp_write(base + 0xc, 0x55); /* EDP_CONFIGURATION_CTRL */
}
-static void mdss_edp_config_sw_div(unsigned char *edp_base)
+static void mdss_edp_config_sw_div(unsigned char *base)
{
- edp_write(edp_base + 0x14, 0x13b); /* EDP_SOFTWARE_MVID */
- edp_write(edp_base + 0x18, 0x266); /* EDP_SOFTWARE_NVID */
+ edp_write(base + 0x14, 0x13b); /* EDP_SOFTWARE_MVID */
+ edp_write(base + 0x18, 0x266); /* EDP_SOFTWARE_NVID */
}
-static void mdss_edp_config_static_mdiv(unsigned char *edp_base)
+static void mdss_edp_config_static_mdiv(unsigned char *base)
{
int ret = 0;
- ret = edp_read(edp_base + 0xc); /* EDP_CONFIGURATION_CTRL */
- edp_write(edp_base + 0xc, ret | 0x2); /* EDP_CONFIGURATION_CTRL */
- edp_write(edp_base + 0xc, 0x57); /* EDP_CONFIGURATION_CTRL */
+ 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 *edp_base, int enable)
+static void mdss_edp_enable(unsigned char *base, int enable)
{
- edp_write(edp_base + 0x8, 0x0); /* EDP_STATE_CTRL */
- edp_write(edp_base + 0x8, 0x40); /* EDP_STATE_CTRL */
- edp_write(edp_base + 0x94, enable); /* EDP_TIMING_ENGINE_EN */
- edp_write(edp_base + 0x4, enable); /* EDP_MAINLINK_CTRL */
+ 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 */
}
+static void mdss_edp_irq_enable(struct mdss_edp_drv_pdata *edp_drv);
+static void mdss_edp_irq_disable(struct mdss_edp_drv_pdata *edp_drv);
+
int mdss_edp_on(struct mdss_panel_data *pdata)
{
struct mdss_edp_drv_pdata *edp_drv = NULL;
- int i;
+ int ret = 0;
- edp_drv = container_of(pdata, struct mdss_edp_drv_pdata,
- panel_data);
- if (!edp_drv) {
+ if (!pdata) {
pr_err("%s: Invalid input data\n", __func__);
return -EINVAL;
}
- mdss_edp_prepare_clocks(edp_drv);
- mdss_edp_phy_sw_reset(edp_drv->edp_base);
- mdss_edp_hw_powerup(edp_drv->edp_base, 1);
- mdss_edp_pll_configure(edp_drv->edp_base, edp_drv->edid.timing[0].pclk);
- mdss_edp_clk_enable(edp_drv);
+ edp_drv = container_of(pdata, struct mdss_edp_drv_pdata,
+ panel_data);
- for (i = 0; i < edp_drv->dpcd.max_lane_count; ++i)
- mdss_edp_enable_lane_bist(edp_drv->edp_base, i, 1);
+ pr_debug("%s:+\n", __func__);
+ if (edp_drv->train_start == 0)
+ edp_drv->train_start++;
- mdss_edp_enable_mainlink(edp_drv->edp_base, 1);
- mdss_edp_config_clk(edp_drv->edp_base, edp_drv->mmss_cc_base);
+ 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_misc_cfg(edp_drv->edp_base);
- mdss_edp_config_sync(edp_drv->edp_base);
- mdss_edp_config_sw_div(edp_drv->edp_base);
- mdss_edp_config_static_mdiv(edp_drv->edp_base);
- mdss_edp_enable(edp_drv->edp_base, 1);
+ 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);
+
+ 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);
+
+ 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_irq_enable(edp_drv);
+ 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;
+}
+
int mdss_edp_off(struct mdss_panel_data *pdata)
{
struct mdss_edp_drv_pdata *edp_drv = NULL;
int ret = 0;
- int i;
edp_drv = container_of(pdata, struct mdss_edp_drv_pdata,
panel_data);
@@ -336,20 +373,26 @@
pr_err("%s: Invalid input data\n", __func__);
return -EINVAL;
}
+ pr_debug("%s:+\n", __func__);
+
+ mdss_edp_irq_disable(edp_drv);
gpio_set_value(edp_drv->gpio_panel_en, 0);
pwm_disable(edp_drv->bl_pwm);
- mdss_edp_enable(edp_drv->edp_base, 0);
- mdss_edp_unconfig_clk(edp_drv->edp_base, edp_drv->mmss_cc_base);
- mdss_edp_enable_mainlink(edp_drv->edp_base, 0);
+ 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);
- for (i = 0; i < edp_drv->dpcd.max_lane_count; ++i)
- mdss_edp_enable_lane_bist(edp_drv->edp_base, i, 0);
-
+ mdss_edp_lane_power_ctrl(edp_drv->base,
+ edp_drv->dpcd.max_lane_count, 0);
mdss_edp_clk_disable(edp_drv);
- mdss_edp_hw_powerup(edp_drv->edp_base, 0);
+ 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);
+
+ pr_debug("%s:-\n", __func__);
return ret;
}
@@ -363,6 +406,9 @@
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;
@@ -382,20 +428,31 @@
pinfo = &edp_drv->panel_data.panel_info;
pinfo->clk_rate = dp->pclk;
+ pr_debug("%s: pclk=%d\n", __func__, pinfo->clk_rate);
pinfo->xres = dp->h_addressable + dp->h_border * 2;
pinfo->yres = dp->v_addressable + dp->v_border * 2;
+ pr_debug("%s: x=%d y=%d\n", __func__, pinfo->xres, pinfo->yres);
+
pinfo->lcdc.h_back_porch = dp->h_blank - dp->h_fporch \
- dp->h_sync_pulse;
pinfo->lcdc.h_front_porch = dp->h_fporch;
pinfo->lcdc.h_pulse_width = dp->h_sync_pulse;
+ pr_debug("%s: hporch= %d %d %d\n", __func__,
+ pinfo->lcdc.h_back_porch, pinfo->lcdc.h_front_porch,
+ pinfo->lcdc.h_pulse_width);
+
pinfo->lcdc.v_back_porch = dp->v_blank - dp->v_fporch \
- dp->v_sync_pulse;
pinfo->lcdc.v_front_porch = dp->v_fporch;
pinfo->lcdc.v_pulse_width = dp->v_sync_pulse;
+ pr_debug("%s: vporch= %d %d %d\n", __func__,
+ pinfo->lcdc.v_back_porch, pinfo->lcdc.v_front_porch,
+ pinfo->lcdc.v_pulse_width);
+
pinfo->type = EDP_PANEL;
pinfo->pdest = DISPLAY_1;
pinfo->wait_cycle = 0;
@@ -415,9 +472,9 @@
gpio_free(edp_drv->gpio_panel_en);
mdss_edp_regulator_off(edp_drv);
- iounmap(edp_drv->edp_base);
+ iounmap(edp_drv->base);
iounmap(edp_drv->mmss_cc_base);
- edp_drv->edp_base = NULL;
+ edp_drv->base = NULL;
return 0;
}
@@ -458,12 +515,19 @@
return -ENOMEM;
}
- edp_drv->edp_base = ioremap(res->start, resource_size(res));
- if (!edp_drv->edp_base) {
+ edp_drv->base_size = resource_size(res);
+ edp_drv->base = ioremap(res->start, resource_size(res));
+ if (!edp_drv->base) {
pr_err("%s: Unable to remap EDP resources", __func__);
return -ENOMEM;
}
+ pr_debug("%s: drv=%x base=%x size=%x\n", __func__,
+ (int)edp_drv, (int)edp_drv->base, edp_drv->base_size);
+
+ mdss_debug_register_base("edp",
+ edp_drv->base, edp_drv->base_size);
+
return 0;
}
@@ -488,52 +552,202 @@
return 0;
}
-static void mdss_edp_fill_edid_data(struct mdss_edp_drv_pdata *edp_drv)
+static void mdss_edp_video_ready(struct mdss_edp_drv_pdata *edp_drv)
{
- struct edp_edid *edid = &edp_drv->edid;
-
- edid->id_name[0] = 'A';
- edid->id_name[0] = 'U';
- edid->id_name[0] = 'O';
- edid->id_name[0] = 0;
- edid->id_product = 0x305D;
- edid->version = 1;
- edid->revision = 4;
- edid->ext_block_cnt = 0;
- edid->video_digital = 0x5;
- edid->color_depth = 6;
- edid->dpm = 0;
- edid->color_format = 0;
- edid->timing[0].pclk = 138500000;
- edid->timing[0].h_addressable = 1920;
- edid->timing[0].h_blank = 160;
- edid->timing[0].v_addressable = 1080;
- edid->timing[0].v_blank = 30;
- edid->timing[0].h_fporch = 48;
- edid->timing[0].h_sync_pulse = 32;
- edid->timing[0].v_sync_pulse = 14;
- edid->timing[0].v_fporch = 8;
- edid->timing[0].width_mm = 256;
- edid->timing[0].height_mm = 144;
- edid->timing[0].h_border = 0;
- edid->timing[0].v_border = 0;
- edid->timing[0].interlaced = 0;
- edid->timing[0].stereo = 0;
- edid->timing[0].sync_type = 1;
- edid->timing[0].sync_separate = 1;
- edid->timing[0].vsync_pol = 0;
- edid->timing[0].hsync_pol = 0;
+ pr_debug("%s: edp_video_ready\n", __func__);
}
-static void mdss_edp_fill_dpcd_data(struct mdss_edp_drv_pdata *edp_drv)
+static int edp_event_thread(void *data)
{
- struct dpcd_cap *cap = &edp_drv->dpcd;
+ struct mdss_edp_drv_pdata *ep;
+ unsigned long flag;
+ u32 todo = 0;
- cap->max_lane_count = 2;
- cap->max_link_clk = 270;
+ ep = (struct mdss_edp_drv_pdata *)data;
+
+ while (1) {
+ wait_event(ep->event_q, (ep->event_pndx != ep->event_gndx));
+ spin_lock_irqsave(&ep->event_lock, flag);
+ if (ep->event_pndx == ep->event_gndx) {
+ spin_unlock_irqrestore(&ep->event_lock, flag);
+ break;
+ }
+ todo = ep->event_todo_list[ep->event_gndx];
+ ep->event_todo_list[ep->event_gndx++] = 0;
+ ep->event_gndx %= HPD_EVENT_MAX;
+ spin_unlock_irqrestore(&ep->event_lock, flag);
+
+ pr_debug("%s: todo=%x\n", __func__, todo);
+
+ if (todo == 0)
+ continue;
+
+ if (todo & EV_EDID_READ)
+ mdss_edp_edid_read(ep, 0);
+
+ if (todo & EV_DPCD_CAP_READ)
+ mdss_edp_dpcd_cap_read(ep);
+
+ 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_VIDEO_READY)
+ mdss_edp_video_ready(ep);
+ }
+
+ return 0;
}
+static void edp_send_events(struct mdss_edp_drv_pdata *ep, u32 events)
+{
+ spin_lock(&ep->event_lock);
+ ep->event_todo_list[ep->event_pndx++] = events;
+ ep->event_pndx %= HPD_EVENT_MAX;
+ wake_up(&ep->event_q);
+ spin_unlock(&ep->event_lock);
+}
+
+irqreturn_t edp_isr(int irq, void *ptr)
+{
+ struct mdss_edp_drv_pdata *ep = (struct mdss_edp_drv_pdata *)ptr;
+ unsigned char *base = ep->base;
+ u32 isr1, isr2, mask1, mask2;
+ u32 ack;
+
+ isr1 = edp_read(base + 0x308);
+ isr2 = edp_read(base + 0x30c);
+
+ mask1 = isr1 & EDP_INTR_MASK1;
+ mask2 = isr2 & EDP_INTR_MASK2;
+
+ isr1 &= ~mask1; /* remove masks bit */
+ isr2 &= ~mask2;
+
+ pr_debug("%s: isr=%x mask=%x isr2=%x mask2=%x\n",
+ __func__, isr1, mask1, isr2, mask2);
+
+ ack = isr1 & EDP_INTR_STATUS1;
+ ack <<= 1; /* ack bits */
+ ack |= mask1;
+ edp_write(base + 0x308, ack);
+
+ ack = isr2 & EDP_INTR_STATUS2;
+ ack <<= 1; /* ack bits */
+ ack |= mask2;
+ edp_write(base + 0x30c, ack);
+
+ if (isr1 & EDP_INTR_HPD) {
+ isr1 &= ~EDP_INTR_HPD; /* clear */
+ if (ep->train_start)
+ edp_send_events(ep, EV_LINK_TRAIN);
+ }
+
+ if (isr2 & EDP_INTR_READY_FOR_VIDEO)
+ edp_send_events(ep, EV_VIDEO_READY);
+
+ if (isr1 && ep->aux_cmd_busy) {
+ /* clear EDP_AUX_TRANS_CTRL */
+ edp_write(base + 0x318, 0);
+ /* read EDP_INTERRUPT_TRANS_NUM */
+ ep->aux_trans_num = edp_read(base + 0x310);
+
+ if (ep->aux_cmd_i2c)
+ edp_aux_i2c_handler(ep, isr1);
+ else
+ edp_aux_native_handler(ep, isr1);
+ }
+
+ return IRQ_HANDLED;
+}
+
+struct mdss_hw mdss_edp_hw = {
+ .hw_ndx = MDSS_HW_EDP,
+ .ptr = NULL,
+ .irq_handler = edp_isr,
+};
+
+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);
+
+ mdss_enable_irq(&mdss_edp_hw);
+}
+
+static void mdss_edp_irq_disable(struct mdss_edp_drv_pdata *edp_drv)
+{
+ edp_write(edp_drv->base + 0x308, 0x0);
+ edp_write(edp_drv->base + 0x30c, 0x0);
+
+ mdss_disable_irq(&mdss_edp_hw);
+}
+
+static int mdss_edp_irq_setup(struct mdss_edp_drv_pdata *edp_drv)
+{
+ 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);
+
+ if (!gpio_is_valid(edp_drv->gpio_panel_hpd)) {
+ pr_err("%s gpio_panel_hpd %d is not valid ", __func__,
+ edp_drv->gpio_panel_hpd);
+ return -ENODEV;
+ }
+
+ ret = gpio_request(edp_drv->gpio_panel_hpd, "edp_hpd_irq_gpio");
+ if (ret) {
+ pr_err("%s unable to request gpio_panel_hpd %d", __func__,
+ edp_drv->gpio_panel_hpd);
+ return -ENODEV;
+ }
+
+ ret = gpio_tlmm_config(GPIO_CFG(
+ edp_drv->gpio_panel_hpd,
+ 1,
+ GPIO_CFG_INPUT,
+ GPIO_CFG_NO_PULL,
+ GPIO_CFG_2MA),
+ GPIO_CFG_ENABLE);
+ if (ret) {
+ pr_err("%s: unable to config tlmm = %d\n", __func__,
+ edp_drv->gpio_panel_hpd);
+ gpio_free(edp_drv->gpio_panel_hpd);
+ return -ENODEV;
+ }
+
+ ret = gpio_direction_input(edp_drv->gpio_panel_hpd);
+ if (ret) {
+ pr_err("%s unable to set direction for gpio_panel_hpd %d",
+ __func__, edp_drv->gpio_panel_hpd);
+ return -ENODEV;
+ }
+
+ mdss_edp_hw.ptr = (void *)(edp_drv);
+
+ if (mdss_register_irq(&mdss_edp_hw))
+ pr_err("%s: mdss_register_irq failed.\n", __func__);
+
+
+ return 0;
+}
+
+
+static void mdss_edp_event_setup(struct mdss_edp_drv_pdata *ep)
+{
+ init_waitqueue_head(&ep->event_q);
+ spin_lock_init(&ep->event_lock);
+
+ kthread_run(edp_event_thread, (void *)ep, "mdss_edp_hpd");
+}
static int __devinit mdss_edp_probe(struct platform_device *pdev)
{
@@ -554,6 +768,7 @@
edp_drv->pdev = pdev;
edp_drv->pdev->id = 1;
edp_drv->clk_on = 0;
+ edp_drv->train_start = 0; /* no link train yet */
ret = mdss_edp_get_base_address(edp_drv);
if (ret)
@@ -579,8 +794,38 @@
if (ret)
goto edp_free_gpio_panel_en;
- mdss_edp_fill_edid_data(edp_drv);
- mdss_edp_fill_dpcd_data(edp_drv);
+ mdss_edp_irq_setup(edp_drv);
+
+ mdss_edp_aux_init(edp_drv);
+
+ mdss_edp_event_setup(edp_drv);
+
+ /* need mdss clock to receive irq */
+ 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);
+
+ mdss_edp_irq_enable(edp_drv);
+
+ mdss_edp_edid_read(edp_drv, 0);
+ mdss_edp_dpcd_cap_read(edp_drv);
+
+ mdss_edp_irq_disable(edp_drv);
+
+ mdss_edp_aux_ctrl(edp_drv->base, 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);
+
mdss_edp_device_register(edp_drv);
return 0;
@@ -594,7 +839,7 @@
mmss_cc_base_unmap:
iounmap(edp_drv->mmss_cc_base);
edp_base_unmap:
- iounmap(edp_drv->edp_base);
+ iounmap(edp_drv->base);
probe_err:
return ret;
diff --git a/drivers/video/msm/mdss/mdss_edp.h b/drivers/video/msm/mdss/mdss_edp.h
index 00ef206..c3f7d0d 100644
--- a/drivers/video/msm/mdss/mdss_edp.h
+++ b/drivers/video/msm/mdss/mdss_edp.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
@@ -14,15 +14,157 @@
#ifndef MDSS_EDP_H
#define MDSS_EDP_H
-#include <linux/platform_device.h>
-#include <linux/regulator/consumer.h>
-#include <linux/clk.h>
-
-#include "mdss_panel.h"
+#include <linux/of_gpio.h>
#define edp_read(offset) readl_relaxed((offset))
#define edp_write(offset, data) writel_relaxed((data), (offset))
+#define AUX_CMD_FIFO_LEN 144
+#define AUX_CMD_MAX 16
+#define AUX_CMD_I2C_MAX 128
+
+#define EDP_PORT_MAX 1
+#define EDP_SINK_CAP_LEN 16
+
+#define EDP_AUX_ERR_NONE 0
+#define EDP_AUX_ERR_ADDR -1
+#define EDP_AUX_ERR_TOUT -2
+#define EDP_AUX_ERR_NACK -3
+
+/* 4 bits of aux command */
+#define EDP_CMD_AUX_WRITE 0x8
+#define EDP_CMD_AUX_READ 0x9
+
+/* 4 bits of i2c command */
+#define EDP_CMD_I2C_MOT 0x4 /* i2c middle of transaction */
+#define EDP_CMD_I2C_WRITE 0x0
+#define EDP_CMD_I2C_READ 0x1
+#define EDP_CMD_I2C_STATUS 0x2 /* i2c write status request */
+
+/* cmd reply: bit 0, 1 for aux */
+#define EDP_AUX_ACK 0x0
+#define EDP_AUX_NACK 0x1
+#define EDP_AUX_DEFER 0x2
+
+/* cmd reply: bit 2, 3 for i2c */
+#define EDP_I2C_ACK 0x0
+#define EDP_I2C_NACK 0x4
+#define EDP_I2C_DEFER 0x8
+
+#define EDP_CMD_TIMEOUT 400 /* us */
+#define EDP_CMD_LEN 16
+
+#define EDP_INTR_ACK_SHIFT 1
+#define EDP_INTR_MASK_SHIFT 2
+
+/* isr */
+#define EDP_INTR_HPD BIT(0)
+#define EDP_INTR_AUX_I2C_DONE BIT(3)
+#define EDP_INTR_WRONG_ADDR BIT(6)
+#define EDP_INTR_TIMEOUT BIT(9)
+#define EDP_INTR_NACK_DEFER BIT(12)
+#define EDP_INTR_WRONG_DATA_CNT BIT(15)
+#define EDP_INTR_I2C_NACK BIT(18)
+#define EDP_INTR_I2C_DEFER BIT(21)
+#define EDP_INTR_PLL_UNLOCKED BIT(24)
+#define EDP_INTR_AUX_ERROR BIT(27)
+
+
+#define EDP_INTR_STATUS1 \
+ (EDP_INTR_HPD | EDP_INTR_AUX_I2C_DONE| \
+ EDP_INTR_WRONG_ADDR | EDP_INTR_TIMEOUT | \
+ EDP_INTR_NACK_DEFER | EDP_INTR_WRONG_DATA_CNT | \
+ EDP_INTR_I2C_NACK | EDP_INTR_I2C_DEFER | \
+ EDP_INTR_PLL_UNLOCKED | EDP_INTR_AUX_ERROR)
+
+#define EDP_INTR_MASK1 (EDP_INTR_STATUS1 << 2)
+
+
+#define EDP_INTR_READY_FOR_VIDEO BIT(0)
+#define EDP_INTR_IDLE_PATTERNs_SENT BIT(3)
+#define EDP_INTR_FRAME_END BIT(6)
+#define EDP_INTR_CRC_UPDATED BIT(9)
+
+#define EDP_INTR_STATUS2 \
+ (EDP_INTR_READY_FOR_VIDEO | EDP_INTR_IDLE_PATTERNs_SENT | \
+ EDP_INTR_FRAME_END | EDP_INTR_CRC_UPDATED)
+
+#define EDP_INTR_MASK2 (EDP_INTR_STATUS2 << 2)
+
+
+#define EDP_MAINLINK_CTRL 0x004
+#define EDP_STATE_CTRL 0x008
+#define EDP_MAINLINK_READY 0x084
+
+#define EDP_AUX_CTRL 0x300
+#define EDP_INTERRUPT_STATUS 0x308
+#define EDP_INTERRUPT_STATUS_2 0x30c
+#define EDP_AUX_DATA 0x314
+#define EDP_AUX_TRANS_CTRL 0x318
+#define EDP_AUX_STATUS 0x324
+
+#define EDP_PHY_EDPPHY_GLB_VM_CFG0 0x510
+#define EDP_PHY_EDPPHY_GLB_VM_CFG1 0x514
+
+struct edp_cmd {
+ char read; /* 1 == read, 0 == write */
+ char i2c; /* 1 == i2c cmd, 0 == native cmd */
+ u32 addr; /* 20 bits */
+ char *datap;
+ int len; /* len to be tx OR len to be rx for read */
+ char next; /* next command */
+};
+
+struct edp_buf {
+ char *start; /* buffer start addr */
+ char *end; /* buffer end addr */
+ int size; /* size of buffer */
+ char *data; /* data pointer */
+ int len; /* dara length */
+ char trans_num; /* transaction number */
+ char i2c; /* 1 == i2c cmd, 0 == native cmd */
+};
+
+#define DPCD_ENHANCED_FRAME BIT(0)
+#define DPCD_TPS3 BIT(1)
+#define DPCD_MAX_DOWNSPREAD_0_5 BIT(2)
+#define DPCD_NO_AUX_HANDSHAKE BIT(3)
+#define DPCD_PORT_0_EDID_PRESENTED BIT(4)
+
+/* event */
+#define EV_EDP_AUX_SETUP BIT(0)
+#define EV_EDID_READ BIT(1)
+#define EV_DPCD_CAP_READ BIT(2)
+#define EV_DPCD_STATUS_READ BIT(3)
+#define EV_LINK_TRAIN BIT(4)
+#define EV_VIDEO_READY BIT(31)
+
+struct dpcd_cap {
+ char major;
+ char minor;
+ char max_lane_count;
+ char num_rx_port;
+ char i2c_speed_ctrl;
+ char scrambler_reset;
+ char enhanced_frame;
+ u32 max_link_rate; /* 162, 270 and 540 Mb, divided by 10 */
+ u32 flags;
+ u32 rx_port0_buf_size;
+ u32 training_read_interval;/* us */
+};
+
+struct dpcd_link_status {
+ char lane_01_status;
+ char lane_23_status;
+ char interlane_align_done;
+ char downstream_port_status_changed;
+ char link_status_updated;
+ char port_0_in_sync;
+ char port_1_in_sync;
+ char req_voltage_swing[4];
+ char req_pre_emphasis[4];
+};
+
struct display_timing_desc {
u32 pclk;
u32 h_addressable; /* addressable + boder = active */
@@ -45,12 +187,14 @@
u32 hsync_pol;
};
+#define EDID_DISPLAY_PORT_SUPPORT 0x05
+
struct edp_edid {
char id_name[4];
short id_product;
char version;
char revision;
- char video_digital;
+ char video_intf; /* edp == 0x5 */
char color_depth; /* 6, 8, 10, 12 and 14 bits */
char color_format; /* RGB 4:4:4, YCrCb 4:4:4, Ycrcb 4:2:2 */
char dpm; /* display power management */
@@ -62,11 +206,32 @@
struct display_timing_desc timing[4];
};
-struct dpcd_cap {
- char max_lane_count;
- u32 max_link_clk; /* 162, 270 and 540 Mb, divided by 10 */
+struct edp_statistic {
+ u32 intr_hpd;
+ u32 intr_aux_i2c_done;
+ u32 intr_wrong_addr;
+ u32 intr_tout;
+ u32 intr_nack_defer;
+ u32 intr_wrong_data_cnt;
+ u32 intr_i2c_nack;
+ u32 intr_i2c_defer;
+ u32 intr_pll_unlock;
+ u32 intr_crc_update;
+ u32 intr_frame_end;
+ u32 intr_idle_pattern_sent;
+ u32 intr_ready_for_video;
+ u32 aux_i2c_tx;
+ u32 aux_i2c_rx;
+ u32 aux_native_tx;
+ u32 aux_native_rx;
};
+
+#define DPCD_LINK_VOLTAGE_MAX 4
+#define DPCD_LINK_PRE_EMPHASIS_MAX 4
+
+#define HPD_EVENT_MAX 8
+
struct mdss_edp_drv_pdata {
/* device driver */
int (*on) (struct mdss_panel_data *pdata);
@@ -74,11 +239,15 @@
struct platform_device *pdev;
/* edp specific */
- struct mdss_panel_data panel_data;
- unsigned char *edp_base;
+ unsigned char *base;
+ int base_size;
unsigned char *mmss_cc_base;
+
+ struct mdss_panel_data panel_data;
+
struct edp_edid edid;
struct dpcd_cap dpcd;
+ int train_start;
/* regulators */
struct regulator *vdda_vreg;
@@ -98,22 +267,82 @@
struct pwm_device *bl_pwm;
int lpg_channel;
int pwm_period;
+
+ /* hpd */
+ int gpio_panel_hpd;
+ enum of_gpio_flags hpd_flags;
+ int hpd_irq;
+
+ /* aux */
+ struct completion aux_comp;
+ struct completion train_comp;
+ struct mutex aux_mutex;
+ u32 aux_cmd_busy;
+ u32 aux_cmd_i2c;
+ int aux_trans_num;
+ int aux_error_num;
+ u32 aux_ctrl_reg;
+ struct edp_buf txp;
+ struct edp_buf rxp;
+ 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 */
+ char tu_desired;
+ char valid_boundary;
+ char delay_start;
+ u32 bpp;
+ struct edp_statistic edp_stat;
+
+ /* event */
+ wait_queue_head_t event_q;
+ u32 event_pndx;
+ u32 event_gndx;
+ u32 event_todo_list[HPD_EVENT_MAX];
+ spinlock_t event_lock;
};
-void mdss_edp_phy_sw_reset(unsigned char *edp_base);
-void mdss_edp_pll_configure(unsigned char *edp_base, int rate);
-void mdss_edp_enable_lane_bist(unsigned char *edp_base, int lane, int enable);
-void mdss_edp_enable_mainlink(unsigned char *edp_base, int enable);
-void mdss_edp_hw_powerup(unsigned char *edp_base, int enable);
-void mdss_edp_clk_enable(struct mdss_edp_drv_pdata *edp_drv);
+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);
void mdss_edp_clk_disable(struct mdss_edp_drv_pdata *edp_drv);
int mdss_edp_clk_init(struct mdss_edp_drv_pdata *edp_drv);
void mdss_edp_clk_deinit(struct mdss_edp_drv_pdata *edp_drv);
-void mdss_edp_prepare_clocks(struct mdss_edp_drv_pdata *edp_drv);
+int mdss_edp_prepare_aux_clocks(struct mdss_edp_drv_pdata *edp_drv);
+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 *edp_base, unsigned char *mmss_cc_base);
-void mdss_edp_unconfig_clk(unsigned char *edp_base,
+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_phy_misc_cfg(unsigned char *edp_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);
+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);
#endif /* MDSS_EDP_H */
diff --git a/drivers/video/msm/mdss/mdss_edp_aux.c b/drivers/video/msm/mdss/mdss_edp_aux.c
new file mode 100644
index 0000000..6d8e2c2
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_edp_aux.c
@@ -0,0 +1,1260 @@
+/* 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/sched.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/semaphore.h>
+#include <linux/uaccess.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/bug.h>
+#include <linux/of_gpio.h>
+
+#include <asm/system.h>
+#include <asm/mach-types.h>
+
+#include <mach/hardware.h>
+#include <mach/gpio.h>
+#include <mach/clk.h>
+#include <mach/dma.h>
+
+#include "mdss_panel.h"
+#include "mdss_edp.h"
+
+/*
+ * edp buffer operation
+ */
+static char *edp_buf_init(struct edp_buf *eb, char *buf, int size)
+{
+ eb->start = buf;
+ eb->size = size;
+ eb->data = eb->start;
+ eb->end = eb->start + eb->size;
+ eb->len = 0;
+ eb->trans_num = 0;
+ eb->i2c = 0;
+ return eb->data;
+}
+
+static char *edp_buf_reset(struct edp_buf *eb)
+{
+ eb->data = eb->start;
+ eb->len = 0;
+ eb->trans_num = 0;
+ eb->i2c = 0;
+ return eb->data;
+}
+
+static char *edp_buf_push(struct edp_buf *eb, int len)
+{
+ eb->data += len;
+ eb->len += len;
+ return eb->data;
+}
+
+static int edp_buf_trailing(struct edp_buf *eb)
+{
+ return (int)(eb->end - eb->data);
+}
+
+/*
+ * edp aux edp_buf_add_cmd:
+ * NO native and i2c command mix allowed
+ */
+static int edp_buf_add_cmd(struct edp_buf *eb, struct edp_cmd *cmd)
+{
+ char data;
+ char *bp, *cp;
+ int i, len;
+
+ if (cmd->read) /* read */
+ len = 4;
+ else
+ len = cmd->len + 4;
+
+ if (edp_buf_trailing(eb) < len)
+ return 0;
+
+ /*
+ * cmd fifo only has depth of 144 bytes
+ * limit buf length to 128 bytes here
+ */
+ if ((eb->len + len) > 128)
+ return 0;
+
+ bp = eb->data;
+ data = cmd->addr >> 16;
+ data &= 0x0f; /* 4 addr bits */
+ if (cmd->read)
+ data |= BIT(4);
+ *bp++ = data;
+ *bp++ = cmd->addr >> 8;
+ *bp++ = cmd->addr;
+ *bp++ = cmd->len - 1;
+
+ if (!cmd->read) { /* write */
+ cp = cmd->datap;
+ for (i = 0; i < cmd->len; i++)
+ *bp++ = *cp++;
+ }
+ edp_buf_push(eb, len);
+
+ if (cmd->i2c)
+ eb->i2c++;
+
+ eb->trans_num++; /* Increase transaction number */
+
+ return cmd->len - 1;
+}
+
+static int edp_cmd_fifo_tx(struct edp_buf *tp, unsigned char *base)
+{
+ u32 data;
+ char *dp;
+ int len, cnt;
+
+ len = tp->len; /* total byte to cmd fifo */
+ if (len == 0)
+ return 0;
+
+ cnt = 0;
+ dp = tp->start;
+
+ while (cnt < len) {
+ data = *dp; /* data byte */
+ data <<= 8;
+ data &= 0x00ff00; /* index = 0, write */
+ if (cnt == 0)
+ data |= BIT(31); /* INDEX_WRITE */
+ pr_debug("%s: data=%x\n", __func__, data);
+ edp_write(base + EDP_AUX_DATA, data);
+ cnt++;
+ dp++;
+ }
+
+ data = (tp->trans_num - 1);
+ if (tp->i2c)
+ data |= BIT(8); /* I2C */
+
+ data |= BIT(9); /* GO */
+ pr_debug("%s: data=%x\n", __func__, data);
+ edp_write(base + EDP_AUX_TRANS_CTRL, data);
+
+ return tp->len;
+}
+
+static int edp_cmd_fifo_rx(struct edp_buf *rp, int len, unsigned char *base)
+{
+ u32 data;
+ char *dp;
+ int i;
+
+ data = 0; /* index = 0 */
+ data |= BIT(31); /* INDEX_WRITE */
+ data |= BIT(0); /* read */
+ edp_write(base + EDP_AUX_DATA, data);
+
+ dp = rp->data;
+
+ /* discard first byte */
+ data = edp_read(base + EDP_AUX_DATA);
+ for (i = 0; i < len; i++) {
+ data = edp_read(base + EDP_AUX_DATA);
+ pr_debug("%s: data=%x\n", __func__, data);
+ *dp++ = (char)((data >> 8) & 0xff);
+ }
+
+ rp->len = len;
+ return len;
+}
+
+static int edp_aux_write_cmds(struct mdss_edp_drv_pdata *ep,
+ struct edp_cmd *cmd)
+{
+ struct edp_cmd *cm;
+ struct edp_buf *tp;
+ int len, ret;
+
+ mutex_lock(&ep->aux_mutex);
+ ep->aux_cmd_busy = 1;
+
+ tp = &ep->txp;
+ edp_buf_reset(tp);
+
+ cm = cmd;
+ while (cm) {
+ pr_debug("%s: i2c=%d read=%d addr=%x len=%d next=%d\n",
+ __func__, cm->i2c, cm->read, cm->addr, cm->len,
+ cm->next);
+ ret = edp_buf_add_cmd(tp, cm);
+ if (ret <= 0)
+ break;
+ if (cm->next == 0)
+ break;
+ cm++;
+ }
+
+ if (tp->i2c)
+ ep->aux_cmd_i2c = 1;
+ else
+ ep->aux_cmd_i2c = 0;
+
+ INIT_COMPLETION(ep->aux_comp);
+
+ len = edp_cmd_fifo_tx(&ep->txp, ep->base);
+
+ wait_for_completion(&ep->aux_comp);
+
+ if (ep->aux_error_num == EDP_AUX_ERR_NONE)
+ ret = len;
+ else
+ ret = ep->aux_error_num;
+
+ ep->aux_cmd_busy = 0;
+ mutex_unlock(&ep->aux_mutex);
+ return ret;
+}
+
+static int edp_aux_read_cmds(struct mdss_edp_drv_pdata *ep,
+ struct edp_cmd *cmds)
+{
+ struct edp_cmd *cm;
+ struct edp_buf *tp;
+ struct edp_buf *rp;
+ int len, ret;
+
+ mutex_lock(&ep->aux_mutex);
+ ep->aux_cmd_busy = 1;
+
+ tp = &ep->txp;
+ rp = &ep->rxp;
+ edp_buf_reset(tp);
+ edp_buf_reset(rp);
+
+ cm = cmds;
+ len = 0;
+ while (cm) {
+ pr_debug("%s: i2c=%d read=%d addr=%x len=%d next=%d\n",
+ __func__, cm->i2c, cm->read, cm->addr, cm->len,
+ cm->next);
+ ret = edp_buf_add_cmd(tp, cm);
+ len += cm->len;
+ if (ret <= 0)
+ break;
+ if (cm->next == 0)
+ break;
+ cm++;
+ }
+
+ if (tp->i2c)
+ ep->aux_cmd_i2c = 1;
+ else
+ ep->aux_cmd_i2c = 0;
+
+ INIT_COMPLETION(ep->aux_comp);
+
+ edp_cmd_fifo_tx(tp, ep->base);
+
+ wait_for_completion(&ep->aux_comp);
+
+ if (ep->aux_error_num == EDP_AUX_ERR_NONE)
+ ret = edp_cmd_fifo_rx(rp, len, ep->base);
+ else
+ ret = ep->aux_error_num;
+
+ ep->aux_cmd_busy = 0;
+ mutex_unlock(&ep->aux_mutex);
+
+ return ret;
+}
+
+void edp_aux_native_handler(struct mdss_edp_drv_pdata *ep, u32 isr)
+{
+
+ pr_debug("%s: isr=%x\n", __func__, isr);
+
+ if (isr & EDP_INTR_AUX_I2C_DONE)
+ ep->aux_error_num = EDP_AUX_ERR_NONE;
+ else if (isr & EDP_INTR_WRONG_ADDR)
+ ep->aux_error_num = EDP_AUX_ERR_ADDR;
+ else if (isr & EDP_INTR_TIMEOUT)
+ ep->aux_error_num = EDP_AUX_ERR_TOUT;
+ if (isr & EDP_INTR_NACK_DEFER)
+ ep->aux_error_num = EDP_AUX_ERR_NACK;
+
+ complete(&ep->aux_comp);
+}
+
+void edp_aux_i2c_handler(struct mdss_edp_drv_pdata *ep, u32 isr)
+{
+
+ pr_debug("%s: isr=%x\n", __func__, isr);
+
+ if (isr & EDP_INTR_AUX_I2C_DONE) {
+ if (isr & (EDP_INTR_I2C_NACK | EDP_INTR_I2C_DEFER))
+ ep->aux_error_num = EDP_AUX_ERR_NACK;
+ else
+ ep->aux_error_num = EDP_AUX_ERR_NONE;
+ } else {
+ if (isr & EDP_INTR_WRONG_ADDR)
+ ep->aux_error_num = EDP_AUX_ERR_ADDR;
+ else if (isr & EDP_INTR_TIMEOUT)
+ ep->aux_error_num = EDP_AUX_ERR_TOUT;
+ if (isr & EDP_INTR_NACK_DEFER)
+ ep->aux_error_num = EDP_AUX_ERR_NACK;
+ if (isr & EDP_INTR_I2C_NACK)
+ ep->aux_error_num = EDP_AUX_ERR_NACK;
+ if (isr & EDP_INTR_I2C_DEFER)
+ ep->aux_error_num = EDP_AUX_ERR_NACK;
+ }
+
+ complete(&ep->aux_comp);
+}
+
+static int edp_aux_write_buf(struct mdss_edp_drv_pdata *ep, u32 addr,
+ char *buf, int len, int i2c)
+{
+ struct edp_cmd cmd;
+
+ cmd.read = 0;
+ cmd.i2c = i2c;
+ cmd.addr = addr;
+ cmd.datap = buf;
+ cmd.len = len & 0x0ff;
+ cmd.next = 0;
+
+ return edp_aux_write_cmds(ep, &cmd);
+}
+
+static int edp_aux_read_buf(struct mdss_edp_drv_pdata *ep, u32 addr,
+ int len, int i2c)
+{
+ struct edp_cmd cmd;
+
+ cmd.read = 1;
+ cmd.i2c = i2c;
+ cmd.addr = addr;
+ cmd.datap = NULL;
+ cmd.len = len & 0x0ff;
+ cmd.next = 0;
+
+ return edp_aux_read_cmds(ep, &cmd);
+}
+
+/*
+ * edid standard header bytes
+ */
+static char edid_hdr[8] = {0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00};
+
+int edp_edid_buf_error(char *buf, int len)
+{
+ char *bp;
+ int i;
+ char csum = 0;
+ int ret = 0;
+
+ bp = buf;
+ if (len < 128) {
+ pr_err("%s: Error: len=%x\n", __func__, len);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < 128; i++)
+ csum += *bp++;
+
+ if (csum != 0) {
+ pr_err("%s: Error: csum=%x\n", __func__, csum);
+ return -EINVAL;
+ }
+
+ if (strncmp(buf, edid_hdr, strlen(edid_hdr))) {
+ pr_err("%s: Error: header\n", __func__);
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+
+void edp_extract_edid_manufacturer(struct edp_edid *edid, char *buf)
+{
+ char *bp;
+ char data;
+
+ bp = &buf[8];
+ data = *bp & 0x7f;
+ data >>= 2;
+ edid->id_name[0] = 'A' + data - 1;
+ data = *bp & 0x03;
+ data <<= 3;
+ bp++;
+ data |= (*bp >> 5);
+ edid->id_name[1] = 'A' + data - 1;
+ data = *bp & 0x1f;
+ edid->id_name[2] = 'A' + data - 1;
+ edid->id_name[3] = 0;
+
+ pr_debug("%s: edid manufacturer = %s", __func__, edid->id_name);
+}
+
+void edp_extract_edid_product(struct edp_edid *edid, char *buf)
+{
+ char *bp;
+ u32 data;
+
+ bp = &buf[0x0a];
+ data = *bp;
+ edid->id_product = *bp++;
+ edid->id_product &= 0x0ff;
+ data = *bp & 0x0ff;
+ data <<= 8;
+ edid->id_product |= data;
+
+ pr_debug("%s: edid product = 0x%x", __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,
+ 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__,
+ edid->ext_block_cnt);
+};
+
+void edp_extract_edid_video_support(struct edp_edid *edid, char *buf)
+{
+ char *bp;
+
+ bp = &buf[0x14];
+ if (*bp & 0x80) {
+ edid->video_intf = *bp & 0x0f;
+ /* 6, 8, 10, 12, 14 and 16 bit per component */
+ edid->color_depth = ((*bp & 0x70) >> 4); /* color bit depth */
+ if (edid->color_depth) {
+ edid->color_depth *= 2;
+ edid->color_depth += 4;
+ }
+ 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__);
+ }
+};
+
+void edp_extract_edid_feature(struct edp_edid *edid, char *buf)
+{
+ char *bp;
+ char data;
+
+ bp = &buf[0x18];
+ data = *bp;
+ data &= 0xe0;
+ data >>= 5;
+ if (data == 0x01)
+ edid->dpm = 1; /* display power management */
+
+ if (edid->video_intf) {
+ if (*bp & 0x80) {
+ /* RGB 4:4:4, YcrCb 4:4:4 and YCrCb 4:2:2 */
+ edid->color_format = *bp & 0x18;
+ edid->color_format >>= 3;
+ }
+ }
+
+ pr_debug("%s: edid dpm=%d color_format=%d", __func__,
+ edid->dpm, edid->color_format);
+};
+
+void edp_extract_edid_detailed_timing_description(struct edp_edid *edid,
+ char *buf)
+{
+ char *bp;
+ u32 data;
+ struct display_timing_desc *dp;
+
+ dp = &edid->timing[0];
+
+ bp = &buf[0x36];
+ dp->pclk = 0;
+ dp->pclk = *bp++; /* byte 0x36 */
+ dp->pclk |= (*bp++ << 8); /* byte 0x37 */
+
+ dp->h_addressable = *bp++; /* byte 0x38 */
+
+ if (dp->pclk == 0 && dp->h_addressable == 0)
+ return; /* Not detailed timing definition */
+
+ dp->pclk *= 10000;
+
+ dp->h_blank = *bp++;/* byte 0x39 */
+ data = *bp & 0xf0; /* byte 0x3A */
+ data <<= 4;
+ dp->h_addressable |= data;
+
+ data = *bp++ & 0x0f;
+ data <<= 8;
+ dp->h_blank |= data;
+
+ dp->v_addressable = *bp++; /* byte 0x3B */
+ dp->v_blank = *bp++; /* byte 0x3C */
+ data = *bp & 0xf0; /* byte 0x3D */
+ data <<= 4;
+ dp->v_addressable |= data;
+
+ data = *bp++ & 0x0f;
+ data <<= 8;
+ dp->v_blank |= data;
+
+ dp->h_fporch = *bp++; /* byte 0x3E */
+ dp->h_sync_pulse = *bp++; /* byte 0x3F */
+
+ dp->v_fporch = *bp & 0x0f0; /* byte 0x40 */
+ dp->v_fporch >>= 4;
+ dp->v_sync_pulse = *bp & 0x0f;
+
+ bp++;
+ data = *bp & 0xc0; /* byte 0x41 */
+ data <<= 2;
+ dp->h_fporch |= data;
+
+ data = *bp & 0x30;
+ data <<= 4;
+ dp->h_sync_pulse |= data;
+
+ data = *bp & 0x0c;
+ data <<= 2;
+ dp->v_fporch |= data;
+
+ data = *bp & 0x03;
+ data <<= 4;
+ dp->v_sync_pulse |= data;
+
+ bp++;
+ dp->width_mm = *bp++; /* byte 0x42 */
+ dp->height_mm = *bp++; /* byte 0x43 */
+ data = *bp & 0x0f0; /* byte 0x44 */
+ data <<= 4;
+ dp->width_mm |= data;
+ data = *bp & 0x0f;
+ data <<= 8;
+ dp->height_mm |= data;
+
+ bp++;
+ dp->h_border = *bp++; /* byte 0x45 */
+ dp->v_border = *bp++; /* byte 0x46 */
+
+ dp->interlaced = *bp & 0x80; /* byte 0x47 */
+
+ dp->stereo = *bp & 0x60;
+ dp->stereo >>= 5;
+
+ data = *bp & 0x1e; /* bit 4,3,2 1*/
+ data >>= 1;
+ dp->sync_type = data & 0x08;
+ dp->sync_type >>= 3; /* analog or digital */
+ if (dp->sync_type) {
+ dp->sync_separate = data & 0x04;
+ dp->sync_separate >>= 2;
+ if (dp->sync_separate) {
+ if (data & 0x02)
+ dp->vsync_pol = 1; /* positive */
+ else
+ dp->vsync_pol = 0;/* negative */
+
+ if (data & 0x01)
+ dp->hsync_pol = 1; /* positive */
+ else
+ dp->hsync_pol = 0; /* negative */
+ }
+ }
+
+ pr_debug("%s: pixel_clock = %d\n", __func__, dp->pclk);
+
+ pr_debug("%s: horizontal=%d, blank=%d, porch=%d, sync=%d\n"
+ , __func__, dp->h_addressable, dp->h_blank,
+ dp->h_fporch, dp->h_sync_pulse);
+ pr_debug("%s: vertical=%d, blank=%d, porch=%d, vsync=%d\n"
+ , __func__, dp->v_addressable, dp->v_blank,
+ dp->v_fporch, dp->v_sync_pulse);
+ pr_debug("%s: panel size in mm, width=%d height=%d\n", __func__,
+ dp->width_mm, dp->height_mm);
+ pr_debug("%s: panel border horizontal=%d vertical=%d\n", __func__,
+ dp->h_border, dp->v_border);
+ pr_debug("%s: flags: interlaced=%d stereo=%d sync_type=%d sync_sep=%d\n"
+ , __func__, dp->interlaced, dp->stereo,
+ dp->sync_type, dp->sync_separate);
+ pr_debug("%s: polarity vsync=%d, hsync=%d", __func__,
+ dp->vsync_pol, dp->hsync_pol);
+}
+
+
+/*
+ * EDID structure can be found in VESA standart here:
+ * http://read.pudn.com/downloads110/ebook/456020/E-EDID%20Standard.pdf
+ *
+ * following table contains default edid
+ * static char edid_raw_data[128] = {
+ * 0, 255, 255, 255, 255, 255, 255, 0,
+ * 6, 175, 93, 48, 0, 0, 0, 0, 0, 22,
+ * 1, 4,
+ * 149, 26, 14, 120, 2,
+ * 164, 21,158, 85, 78, 155, 38, 15, 80, 84,
+ * 0, 0, 0,
+ * 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ * 29, 54, 128, 160, 112, 56, 30, 64, 48, 32, 142, 0, 0, 144, 16,0,0,24,
+ * 19, 36, 128, 160, 112, 56, 30, 64, 48, 32, 142, 0, 0, 144, 16,0,0,24,
+ * 0, 0, 0, 254, 0, 65, 85, 79, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ * 0, 0, 0, 254, 0, 66, 49, 49, 54, 72, 65, 78, 48, 51, 46, 48, 32, 10,
+ * 0, 75 };
+ */
+
+static int edp_aux_chan_ready(struct mdss_edp_drv_pdata *ep)
+{
+ int cnt, ret;
+ char data = 0;
+
+ for (cnt = 5; cnt; cnt--) {
+ ret = edp_aux_write_buf(ep, 0x50, &data, 1, 1);
+ 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)
+ return 0;
+
+ return 1;
+}
+
+static int edp_sink_edid_read(struct mdss_edp_drv_pdata *ep, int block)
+{
+ struct edp_buf *rp;
+ int cnt, rlen;
+ int ret = 0;
+
+ ret = edp_aux_chan_ready(ep);
+ if (ret == 0) {
+ pr_err("%s: aux chan NOT ready\n", __func__);
+ return ret;
+ }
+
+ for (cnt = 5; cnt; cnt--) {
+ rlen = edp_aux_read_buf(ep, 0x50, 128, 1);
+ if (rlen > 0) {
+ pr_debug("%s: rlen=%d\n", __func__, rlen);
+
+ rp = &ep->rxp;
+ if (!edp_edid_buf_error(rp->data, rp->len))
+ break;
+ }
+ }
+
+ if (cnt <= 0) {
+ pr_err("%s: Failed\n", __func__);
+ return -EINVAL;
+ }
+
+ edp_extract_edid_manufacturer(&ep->edid, rp->data);
+ edp_extract_edid_product(&ep->edid, rp->data);
+ edp_extract_edid_version(&ep->edid, rp->data);
+ edp_extract_edid_ext_block_cnt(&ep->edid, rp->data);
+ edp_extract_edid_video_support(&ep->edid, rp->data);
+ edp_extract_edid_feature(&ep->edid, rp->data);
+ edp_extract_edid_detailed_timing_description(&ep->edid, rp->data);
+
+ return 128;
+}
+
+static void edp_sink_capability_read(struct mdss_edp_drv_pdata *ep,
+ int len)
+{
+ char *bp;
+ char data;
+ struct dpcd_cap *cap;
+ struct edp_buf *rp;
+ int rlen;
+
+ rlen = edp_aux_read_buf(ep, 0, len, 0);
+ if (rlen <= 0) {
+ pr_err("%s: edp aux read failed\n", __func__);
+ return;
+ }
+ rp = &ep->rxp;
+ cap = &ep->dpcd;
+ bp = rp->data;
+
+ data = *bp++; /* byte 0 */
+ cap->major = (data >> 4) & 0x0f;
+ cap->minor = data & 0x0f;
+ if (--rlen <= 0)
+ return;
+ pr_debug("%s: version: %d.%d\n", __func__, cap->major, cap->minor);
+
+ data = *bp++; /* byte 1 */
+ /* 162, 270 and 540 MB, symbol rate, NOT bit rate */
+ cap->max_link_rate = data * 27;
+ 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;
+ if (data & 0x40)
+ cap->flags |= DPCD_TPS3;
+ data &= 0x0f;
+ cap->max_lane_count = data;
+ if (--rlen <= 0)
+ return;
+ pr_debug("%s: lane_count=%d\n", __func__, cap->max_lane_count);
+
+ data = *bp++; /* byte 3 */
+ if (data & BIT(0)) {
+ cap->flags |= DPCD_MAX_DOWNSPREAD_0_5;
+ pr_debug("%s: max_downspread\n", __func__);
+ }
+
+ if (data & BIT(6)) {
+ cap->flags |= DPCD_NO_AUX_HANDSHAKE;
+ pr_debug("%s: NO Link Training\n", __func__);
+ }
+ if (--rlen <= 0)
+ return;
+
+ data = *bp++; /* byte 4 */
+ cap->num_rx_port = (data & BIT(0)) + 1;
+ pr_debug("%s: rx_ports=%d", __func__, cap->num_rx_port);
+ if (--rlen <= 0)
+ return;
+
+ bp += 3; /* skip 5, 6 and 7 */
+ rlen -= 3;
+ if (rlen <= 0)
+ return;
+
+ data = *bp++; /* byte 8 */
+ if (data & BIT(1)) {
+ cap->flags |= DPCD_PORT_0_EDID_PRESENTED;
+ pr_debug("%s: edid presented\n", __func__);
+ }
+ if (--rlen <= 0)
+ return;
+
+ data = *bp++; /* byte 9 */
+ cap->rx_port0_buf_size = (data + 1) * 32;
+ pr_debug("%s: lane_buf_size=%d", __func__, cap->rx_port0_buf_size);
+ if (--rlen <= 0)
+ return;
+
+ bp += 2; /* skip 10, 11 port1 capability */
+ rlen -= 2;
+ if (rlen <= 0)
+ return;
+
+ data = *bp++; /* byte 12 */
+ cap->i2c_speed_ctrl = data;
+ if (cap->i2c_speed_ctrl > 0)
+ pr_debug("%s: i2c_rate=%d", __func__, cap->i2c_speed_ctrl);
+ if (--rlen <= 0)
+ return;
+
+ data = *bp++; /* byte 13 */
+ cap->scrambler_reset = data & BIT(0);
+ pr_debug("%s: scrambler_reset=%d\n", __func__,
+ cap->scrambler_reset);
+
+ cap->enhanced_frame = data & BIT(1);
+ pr_debug("%s: enhanced_framing=%d\n", __func__,
+ cap->enhanced_frame);
+ if (--rlen <= 0)
+ return;
+
+ data = *bp++; /* byte 14 */
+ if (data == 0)
+ cap->training_read_interval = 4000; /* us */
+ else
+ cap->training_read_interval = 4000 * data; /* us */
+ pr_debug("%s: training_interval=%d\n", __func__,
+ cap->training_read_interval);
+}
+
+static void edp_link_status_read(struct mdss_edp_drv_pdata *ep, int len)
+{
+ char *bp;
+ char data;
+ struct dpcd_link_status *sp;
+ struct edp_buf *rp;
+ int rlen;
+
+ pr_debug("%s: len=%d", __func__, len);
+ /* skip byte 0x200 and 0x201 */
+ rlen = edp_aux_read_buf(ep, 0x202, len, 0);
+ if (rlen <= 0) {
+ pr_err("%s: edp aux read failed\n", __func__);
+ return;
+ }
+ rp = &ep->rxp;
+ bp = rp->data;
+ sp = &ep->link_status;
+
+ 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;
+ data >>= 2;
+ sp->req_pre_emphasis[0] = data & 0x03;
+ data >>= 2;
+ 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;
+ data >>= 2;
+ sp->req_pre_emphasis[2] = data & 0x03;
+ data >>= 2;
+ sp->req_voltage_swing[3] = data & 0x03;
+ data >>= 2;
+ sp->req_pre_emphasis[3] = data & 0x03;
+}
+
+static int edp_cap_lane_rate_set(struct mdss_edp_drv_pdata *ep)
+{
+ char buf[4];
+ int len = 0;
+
+ 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;
+ len = edp_aux_write_buf(ep, 0x100, buf, 2, 0);
+
+ return len;
+}
+
+static int edp_lane_set_write(struct mdss_edp_drv_pdata *ep, int voltage_level,
+ int pre_emphasis_level)
+{
+ int i;
+ char buf[4];
+
+ if (voltage_level >= DPCD_LINK_VOLTAGE_MAX)
+ voltage_level |= 0x04;
+
+ if (pre_emphasis_level >= DPCD_LINK_PRE_EMPHASIS_MAX)
+ pre_emphasis_level |= 0x04;
+
+ pre_emphasis_level <<= 3;
+
+ for (i = 0; i < 4; i++)
+ buf[i] = voltage_level | pre_emphasis_level;
+
+ pr_debug("%s: p|v=0x%x", __func__, voltage_level | pre_emphasis_level);
+ 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)
+{
+ char buf[4];
+
+ pr_debug("%s: pattern=%x\n", __func__, pattern);
+ buf[0] = pattern;
+ return edp_aux_write_buf(ep, 0x102, buf, 1, 0);
+}
+
+static int edp_sink_clock_recovery_done(struct mdss_edp_drv_pdata *ep)
+{
+ 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;
+ } else if (ep->lane_cnt == 2) {
+ mask = 0x011; /*B lane 0, 1 */
+ data = ep->link_status.lane_01_status;
+ } else {
+ mask = 0x01111; /*B lane 0, 1 */
+ data = ep->link_status.lane_23_status;
+ data <<= 8;
+ data |= ep->link_status.lane_01_status;
+ }
+
+ pr_debug("%s: data=%x mask=%x\n", __func__, data, mask);
+ data &= mask;
+ if (data == mask) /* all done */
+ return 1;
+
+ return 0;
+}
+
+static int edp_sink_channel_eq_done(struct mdss_edp_drv_pdata *ep)
+{
+ u32 mask;
+ u32 data;
+
+ pr_debug("%s:\n", __func__);
+
+ if (!ep->link_status.interlane_align_done) /* not align */
+ return 0;
+
+ if (ep->lane_cnt == 1) {
+ mask = 0x7;
+ data = ep->link_status.lane_01_status;
+ } else if (ep->lane_cnt == 2) {
+ mask = 0x77;
+ data = ep->link_status.lane_01_status;
+ } else {
+ mask = 0x7777;
+ data = ep->link_status.lane_23_status;
+ data <<= 8;
+ data |= ep->link_status.lane_01_status;
+ }
+
+ pr_debug("%s: data=%x mask=%x\n", __func__, data, mask);
+
+ data &= mask;
+ if (data == mask)/* all done */
+ return 1;
+
+ return 0;
+}
+
+void edp_sink_train_set_adjust(struct mdss_edp_drv_pdata *ep)
+{
+ int i;
+ int max = 0;
+
+
+ /* use the max level across lanes */
+ for (i = 0; i < ep->lane_cnt; i++) {
+ pr_debug("%s: lane=%d req_voltage_swing=%d",
+ __func__, i, ep->link_status.req_voltage_swing[i]);
+ if (max < ep->link_status.req_voltage_swing[i])
+ max = ep->link_status.req_voltage_swing[i];
+ }
+
+ ep->v_level = max;
+
+ /* use the max level across lanes */
+ max = 0;
+ for (i = 0; i < ep->lane_cnt; i++) {
+ pr_debug(" %s: lane=%d req_pre_emphasis=%d",
+ __func__, i, ep->link_status.req_pre_emphasis[i]);
+ if (max < ep->link_status.req_pre_emphasis[i])
+ max = ep->link_status.req_pre_emphasis[i];
+ }
+
+ ep->p_level = max;
+ pr_debug("%s: v_level=%d, p_level=%d", __func__,
+ ep->v_level, ep->p_level);
+}
+
+static void edp_host_train_set(struct mdss_edp_drv_pdata *ep, int train)
+{
+ int bit, cnt;
+ u32 data;
+
+
+ bit = 1;
+ bit <<= (train - 1);
+ pr_debug("%s: bit=%d train=%d\n", __func__, bit, train);
+ edp_write(ep->base + EDP_STATE_CTRL, bit);
+
+ bit = 8;
+ bit <<= (train - 1);
+ cnt = 10;
+ while (cnt--) {
+ data = edp_read(ep->base + EDP_MAINLINK_READY);
+ if (data & bit)
+ break;
+ }
+
+ if (cnt == 0)
+ pr_err("%s: set link_train=%d failed\n", __func__, train);
+}
+
+char vm_pre_emphasis[4][4] = {
+ {0x03, 0x06, 0x09, 0x0C}, /* pe0, 0 db */
+ {0x03, 0x06, 0x09, 0xFF}, /* pe1, 3.5 db */
+ {0x03, 0x06, 0xFF, 0xFF}, /* pe2, 6.0 db */
+ {0x03, 0xFF, 0xFF, 0xFF} /* pe3, 9.5 db */
+};
+
+/* voltage swing, 0.2v and 1.0v are not support */
+char vm_voltage_swing[4][4] = {
+ {0x14, 0x18, 0x1A, 0x1E}, /* sw0, 0.4v */
+ {0x18, 0x1A, 0x1E, 0xFF}, /* sw1, 0.6 v */
+ {0x1A, 0x1E, 0xFF, 0xFF}, /* sw1, 0.8 v */
+ {0x1E, 0xFF, 0xFF, 0xFF} /* sw1, 1.2 v, optional */
+};
+
+static void edp_voltage_pre_emphasise_set(struct mdss_edp_drv_pdata *ep)
+{
+ u32 value0 = 0;
+ u32 value1 = 0;
+
+ pr_debug("%s: v=%d p=%d\n", __func__, ep->v_level, ep->p_level);
+
+ value0 = vm_pre_emphasis[(int)(ep->v_level)][(int)(ep->p_level)];
+ value1 = vm_voltage_swing[(int)(ep->v_level)][(int)(ep->p_level)];
+
+ /* Configure host and panel only if both values are allowed */
+ if (value0 != 0xFF && value1 != 0xFF) {
+ edp_write(ep->base + EDP_PHY_EDPPHY_GLB_VM_CFG0, value0);
+ edp_write(ep->base + EDP_PHY_EDPPHY_GLB_VM_CFG1, value1);
+ pr_debug("%s: value0=0x%x value1=0x%x", __func__,
+ value0, value1);
+ edp_lane_set_write(ep, ep->v_level, ep->p_level);
+ }
+
+}
+
+static int edp_start_link_train_1(struct mdss_edp_drv_pdata *ep)
+{
+ int tries, old_v_level;
+ int ret = 0;
+
+ pr_debug("%s:", __func__);
+
+ edp_host_train_set(ep, 0x01); /* train_1 */
+ edp_voltage_pre_emphasise_set(ep);
+ edp_train_pattern_set_write(ep, 0x21); /* train_1 */
+
+ tries = 0;
+ old_v_level = ep->v_level;
+ while (1) {
+ usleep(ep->dpcd.training_read_interval);
+
+ edp_link_status_read(ep, 6);
+ if (edp_sink_clock_recovery_done(ep)) {
+ ret = 0;
+ break;
+ }
+
+ if (ep->v_level == DPCD_LINK_VOLTAGE_MAX) {
+ ret = -1;
+ break; /* quit */
+ }
+
+ if (old_v_level == ep->v_level) {
+ tries++;
+ if (tries >= 5) {
+ ret = -1;
+ break; /* quit */
+ }
+ } else {
+ tries = 0;
+ old_v_level = ep->v_level;
+ }
+
+ edp_sink_train_set_adjust(ep);
+ edp_voltage_pre_emphasise_set(ep);
+ }
+
+ return ret;
+}
+
+static int edp_start_link_train_2(struct mdss_edp_drv_pdata *ep)
+{
+ int tries;
+ int ret = 0;
+ char pattern;
+
+ pr_debug("%s:", __func__);
+
+ if (ep->dpcd.flags & DPCD_TPS3)
+ pattern = 0x03;
+ else
+ pattern = 0x02;
+
+ edp_host_train_set(ep, pattern); /* train_2 */
+ edp_voltage_pre_emphasise_set(ep);
+ edp_train_pattern_set_write(ep, pattern | 0x20);/* train_2 */
+
+ tries = 0;
+ while (1) {
+ usleep(ep->dpcd.training_read_interval);
+
+ edp_link_status_read(ep, 6);
+
+ if (edp_sink_channel_eq_done(ep)) {
+ ret = 0;
+ break;
+ }
+
+ tries++;
+ if (tries > 5) {
+ ret = -1;
+ break;
+ }
+
+ edp_sink_train_set_adjust(ep);
+ edp_voltage_pre_emphasise_set(ep);
+ }
+
+ return ret;
+}
+
+static int edp_link_rate_shift(struct mdss_edp_drv_pdata *ep)
+{
+ /* add calculation later */
+ return -EINVAL;
+}
+
+static void edp_clear_training_pattern(struct mdss_edp_drv_pdata *ep)
+{
+ pr_debug("%s:\n", __func__);
+ edp_write(ep->base + EDP_STATE_CTRL, 0);
+ edp_train_pattern_set_write(ep, 0);
+ usleep(ep->dpcd.training_read_interval);
+}
+
+static int edp_aux_link_train(struct mdss_edp_drv_pdata *ep)
+{
+ int ret = 0;
+
+ pr_debug("%s", __func__);
+ ret = edp_aux_chan_ready(ep);
+ if (ret == 0) {
+ pr_err("%s: LINK Train failed: aux chan NOT ready\n", __func__);
+ complete(&ep->train_comp);
+ 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);
+
+train_start:
+ ep->v_level = 0; /* start from default level */
+ ep->p_level = 0;
+ edp_cap_lane_rate_set(ep);
+
+ 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) {
+ goto train_start;
+ } else {
+ pr_err("%s: Training 1 failed", __func__);
+ ret = -1;
+ goto clear;
+ }
+ }
+
+ pr_debug("%s: Training 1 completed successfully", __func__);
+
+ edp_clear_training_pattern(ep);
+ ret = edp_start_link_train_2(ep);
+ if (ret < 0) {
+ if (edp_link_rate_shift(ep) == 0) {
+ goto train_start;
+ } else {
+ pr_err("%s: Training 2 failed", __func__);
+ ret = -1;
+ goto clear;
+ }
+ }
+
+ pr_debug("%s: Training 2 completed successfully", __func__);
+
+clear:
+ edp_clear_training_pattern(ep);
+
+ complete(&ep->train_comp);
+ return ret;
+}
+
+void mdss_edp_dpcd_cap_read(struct mdss_edp_drv_pdata *ep)
+{
+ edp_sink_capability_read(ep, 16);
+}
+
+void mdss_edp_dpcd_status_read(struct mdss_edp_drv_pdata *ep)
+{
+ edp_link_status_read(ep, 6);
+}
+
+void mdss_edp_edid_read(struct mdss_edp_drv_pdata *ep, int block)
+{
+ edp_sink_edid_read(ep, block);
+}
+
+int mdss_edp_link_train(struct mdss_edp_drv_pdata *ep)
+{
+ return edp_aux_link_train(ep);
+}
+
+void mdss_edp_aux_init(struct mdss_edp_drv_pdata *ep)
+{
+ mutex_init(&ep->aux_mutex);
+ init_completion(&ep->aux_comp);
+ init_completion(&ep->train_comp);
+ complete(&ep->train_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 d9fffa8..ac87cbd 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -111,7 +111,7 @@
return ret;
}
- if (notify > NOTIFY_UPDATE_STOP)
+ if (notify > NOTIFY_UPDATE_POWER_OFF)
return -EINVAL;
if (notify == NOTIFY_UPDATE_START) {
@@ -119,12 +119,19 @@
ret = wait_for_completion_interruptible_timeout(
&mfd->update.comp, 4 * HZ);
to_user = mfd->update.value;
- } else {
+ } else if (notify == NOTIFY_UPDATE_STOP) {
INIT_COMPLETION(mfd->no_update.comp);
ret = wait_for_completion_interruptible_timeout(
&mfd->no_update.comp, 4 * HZ);
to_user = mfd->no_update.value;
+ } else {
+ if (mfd->panel_power_on) {
+ INIT_COMPLETION(mfd->power_off_comp);
+ ret = wait_for_completion_interruptible_timeout(
+ &mfd->power_off_comp, 1 * HZ);
+ }
}
+
if (ret == 0)
ret = -ETIMEDOUT;
else if (ret > 0)
@@ -205,9 +212,42 @@
return ret;
}
+static void mdss_fb_parse_dt_split(struct msm_fb_data_type *mfd)
+{
+ u32 data[2];
+ struct platform_device *pdev = mfd->pdev;
+ if (of_property_read_u32_array(pdev->dev.of_node, "qcom,mdss-fb-split",
+ data, 2))
+ return;
+ if (data[0] && data[1] &&
+ (mfd->panel_info->xres == (data[0] + data[1]))) {
+ mfd->split_fb_left = data[0];
+ mfd->split_fb_right = data[1];
+ pr_info("split framebuffer left=%d right=%d\n",
+ mfd->split_fb_left, mfd->split_fb_right);
+ } else {
+ mfd->split_fb_left = 0;
+ mfd->split_fb_right = 0;
+ }
+}
+
+static ssize_t mdss_fb_get_split(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret = 0;
+ struct fb_info *fbi = dev_get_drvdata(dev);
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
+ ret = snprintf(buf, PAGE_SIZE, "%d %d\n",
+ mfd->split_fb_left, mfd->split_fb_right);
+ return ret;
+}
+
static DEVICE_ATTR(msm_fb_type, S_IRUGO, mdss_fb_get_type, NULL);
+static DEVICE_ATTR(msm_fb_split, S_IRUGO, mdss_fb_get_split, NULL);
+
static struct attribute *mdss_fb_attrs[] = {
&dev_attr_msm_fb_type.attr,
+ &dev_attr_msm_fb_split.attr,
NULL,
};
@@ -230,6 +270,16 @@
sysfs_remove_group(&mfd->fbi->dev->kobj, &mdss_fb_attr_group);
}
+static void mdss_fb_shutdown(struct platform_device *pdev)
+{
+ struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
+
+ if (mfd->ref_cnt > 1)
+ mfd->ref_cnt = 1;
+
+ mdss_fb_release(mfd->fbi, 0);
+}
+
static int mdss_fb_probe(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd = NULL;
@@ -509,6 +559,7 @@
.remove = mdss_fb_remove,
.suspend = mdss_fb_suspend,
.resume = mdss_fb_resume,
+ .shutdown = mdss_fb_shutdown,
.driver = {
.name = "mdss_fb",
.of_match_table = mdss_fb_dt_match,
@@ -605,6 +656,9 @@
if (!op_enable)
return -EPERM;
+ if (mfd->dcm_state == DCM_ENTER)
+ return -EPERM;
+
switch (blank_mode) {
case FB_BLANK_UNBLANK:
if (!mfd->panel_power_on && mfd->mdp.on_fnc) {
@@ -646,6 +700,7 @@
else
mdss_fb_release_fences(mfd);
mfd->op_enable = true;
+ complete(&mfd->power_off_comp);
}
break;
}
@@ -975,6 +1030,9 @@
mfd->ref_cnt = 0;
mfd->panel_power_on = false;
+ mfd->dcm_state = DCM_UNINIT;
+
+ mdss_fb_parse_dt_split(mfd);
if (mdss_fb_alloc_fbmem(mfd)) {
pr_err("unable to allocate framebuffer memory\n");
@@ -991,6 +1049,7 @@
mfd->no_update.timer.data = (unsigned long)mfd;
init_completion(&mfd->update.comp);
init_completion(&mfd->no_update.comp);
+ init_completion(&mfd->power_off_comp);
init_completion(&mfd->commit_comp);
init_completion(&mfd->power_set_comp);
INIT_WORK(&mfd->commit_work, mdss_fb_commit_wq_handler);
@@ -1063,7 +1122,8 @@
ret = mdss_fb_blank_sub(FB_BLANK_POWERDOWN, info,
mfd->op_enable);
if (ret) {
- pr_err("can't turn off display!\n");
+ pr_err("can't turn off display attached to fb%d!\n",
+ mfd->index);
return ret;
}
}
@@ -1475,6 +1535,58 @@
return 0;
}
+int mdss_fb_dcm(struct msm_fb_data_type *mfd, int req_state)
+{
+ int ret = -EINVAL;
+
+ if (req_state == mfd->dcm_state) {
+ pr_warn("Already in correct DCM state");
+ ret = 0;
+ }
+
+ switch (req_state) {
+ case DCM_UNBLANK:
+ if (mfd->dcm_state == DCM_UNINIT &&
+ !mfd->panel_power_on && mfd->mdp.on_fnc) {
+ ret = mfd->mdp.on_fnc(mfd);
+ if (ret == 0) {
+ mfd->panel_power_on = true;
+ mfd->dcm_state = DCM_UNBLANK;
+ }
+ }
+ break;
+ case DCM_ENTER:
+ if (mfd->dcm_state == DCM_UNBLANK) {
+ /* Keep unblank path available for only
+ DCM operation */
+ mfd->panel_power_on = false;
+ mfd->dcm_state = DCM_ENTER;
+ ret = 0;
+ }
+ break;
+ case DCM_EXIT:
+ if (mfd->dcm_state == DCM_ENTER) {
+ /* Release the unblank path for exit */
+ mfd->panel_power_on = true;
+ mfd->dcm_state = DCM_EXIT;
+ ret = 0;
+ }
+ break;
+ case DCM_BLANK:
+ if ((mfd->dcm_state == DCM_EXIT ||
+ mfd->dcm_state == DCM_UNBLANK) &&
+ mfd->panel_power_on && mfd->mdp.off_fnc) {
+ ret = mfd->mdp.off_fnc(mfd);
+ if (ret == 0) {
+ mfd->panel_power_on = false;
+ mfd->dcm_state = DCM_UNINIT;
+ }
+ }
+ break;
+ }
+ return ret;
+}
+
static int mdss_fb_cursor(struct fb_info *info, void __user *p)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index 98bca03..030fd67 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -90,6 +90,8 @@
struct panel_id panel;
struct mdss_panel_info *panel_info;
int split_display;
+ int split_fb_left;
+ int split_fb_right;
u32 dest;
struct fb_info *fbi;
@@ -122,6 +124,7 @@
struct disp_info_notify update;
struct disp_info_notify no_update;
+ struct completion power_off_comp;
struct msm_mdp_interface mdp;
@@ -143,6 +146,8 @@
void *msm_fb_backup;
struct completion power_set_comp;
u32 is_power_setting;
+
+ u32 dcm_state;
};
struct msm_fb_backup_type {
@@ -175,4 +180,5 @@
void mdss_fb_wait_for_fence(struct msm_fb_data_type *mfd);
void mdss_fb_signal_timeline(struct msm_fb_data_type *mfd);
int mdss_fb_register_mdp_instance(struct msm_mdp_interface *mdp);
+int mdss_fb_dcm(struct msm_fb_data_type *mfd, int req_state);
#endif /* MDSS_FB_H */
diff --git a/drivers/video/msm/mdss/mdss_hdmi_edid.c b/drivers/video/msm/mdss/mdss_hdmi_edid.c
index 1876057..65dc19c 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_edid.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_edid.c
@@ -366,8 +366,9 @@
{
const u8 *b = NULL;
u32 ndx, check_sum, print_len;
- int block_size = 0x80;
+ int block_size;
int i, status;
+ int retry_cnt = 0;
struct hdmi_tx_ddc_data ddc_data;
b = edid_buf;
@@ -376,6 +377,9 @@
return -EINVAL;
}
+read_retry:
+ block_size = 0x80;
+ status = 0;
do {
DEV_DBG("EDID: reading block(%d) with block-size=%d\n",
block, block_size);
@@ -422,6 +426,10 @@
ndx, ndx+3,
b[ndx+0], b[ndx+1], b[ndx+2], b[ndx+3]);
status = -EPROTO;
+ if (retry_cnt++ < 3) {
+ DEV_DBG("Retrying reading EDID %d time\n", retry_cnt);
+ goto read_retry;
+ }
goto error;
}
@@ -854,7 +862,8 @@
static void hdmi_edid_get_display_vsd_3d_mode(const u8 *data_buf,
struct hdmi_edid_sink_data *sink_data, u32 num_of_cea_blocks)
{
- u8 len, offset, present_multi_3d, hdmi_vic_len, hdmi_3d_len;
+ u8 len, offset, present_multi_3d, hdmi_vic_len;
+ int hdmi_3d_len;
u16 structure_all, structure_mask;
const u8 *vsd = num_of_cea_blocks ?
hdmi_edid_find_block(data_buf+0x80, DBC_START_OFFSET,
diff --git a/drivers/video/msm/mdss/mdss_hdmi_hdcp.c b/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
index 1f0efd3..bcd5f28 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
@@ -140,6 +140,48 @@
__func__, HDCP_STATE_NAME, hdcp_ddc_status, failure, nack0);
} /* reset_hdcp_ddc_failures */
+static void hdmi_hdcp_hw_ddc_clean(struct hdmi_hdcp_ctrl *hdcp_ctrl)
+{
+ struct dss_io_data *io = NULL;
+ u32 hdcp_ddc_status, ddc_hw_status;
+ u32 ddc_xfer_done, ddc_xfer_req, ddc_hw_done;
+ u32 ddc_hw_not_ready;
+ u32 timeout_count;
+
+ if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ io = hdcp_ctrl->init_data.core_io;
+ if (!io->base) {
+ DEV_ERR("%s: core io not inititalized\n", __func__);
+ return;
+ }
+
+ if (DSS_REG_R(io, HDMI_DDC_HW_STATUS) != 0) {
+ /* Wait to be clean on DDC HW engine */
+ timeout_count = 100;
+ do {
+ hdcp_ddc_status = DSS_REG_R(io, HDMI_HDCP_DDC_STATUS);
+ ddc_hw_status = DSS_REG_R(io, HDMI_DDC_HW_STATUS);
+ ddc_xfer_done = (hdcp_ddc_status & BIT(10)) ;
+ ddc_xfer_req = (hdcp_ddc_status & BIT(4)) ;
+ ddc_hw_done = (ddc_hw_status & BIT(3)) ;
+ ddc_hw_not_ready = ((ddc_xfer_done != 1) ||
+ (ddc_xfer_req != 0) || (ddc_hw_done != 1));
+
+ DEV_DBG("%s: %s: timeout count(%d):ddc hw%sready\n",
+ __func__, HDCP_STATE_NAME, timeout_count,
+ ddc_hw_not_ready ? " not " : " ");
+ DEV_DBG("hdcp_ddc_status[0x%x], ddc_hw_status[0x%x]\n",
+ hdcp_ddc_status, ddc_hw_status);
+ if (ddc_hw_not_ready)
+ msleep(20);
+ } while (ddc_hw_not_ready && --timeout_count);
+ }
+} /* hdmi_hdcp_hw_ddc_clean */
+
static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl)
{
int rc;
@@ -853,6 +895,7 @@
struct delayed_work *dw = to_delayed_work(work);
struct hdmi_hdcp_ctrl *hdcp_ctrl = container_of(dw,
struct hdmi_hdcp_ctrl, hdcp_auth_work);
+ struct dss_io_data *io;
if (!hdcp_ctrl) {
DEV_ERR("%s: invalid input\n", __func__);
@@ -865,6 +908,11 @@
return;
}
+ io = hdcp_ctrl->init_data.core_io;
+ /* Enabling Software DDC */
+ DSS_REG_W_ND(io, HDMI_DDC_ARBITRATION , DSS_REG_R(io,
+ HDMI_DDC_ARBITRATION) & ~(BIT(4)));
+
rc = hdmi_hdcp_authentication_part1(hdcp_ctrl);
if (rc) {
DEV_DBG("%s: %s: HDCP Auth Part I failed\n", __func__,
@@ -878,6 +926,10 @@
HDCP_STATE_NAME);
goto error;
}
+ /* Disabling software DDC before going into part3 to make sure
+ * there is no Arbitratioon between software and hardware for DDC */
+ DSS_REG_W_ND(io, HDMI_DDC_ARBITRATION , DSS_REG_R(io,
+ HDMI_DDC_ARBITRATION) | (BIT(4)));
error:
/*
@@ -969,6 +1021,9 @@
DSS_REG_W(io, HDMI_HDCP_RESET, BIT(0));
+ /* Wait to be clean on DDC HW engine */
+ hdmi_hdcp_hw_ddc_clean(hdcp_ctrl);
+
/* Disable encryption and disable the HDCP block */
DSS_REG_W(io, HDMI_HDCP_CTRL, 0);
@@ -1036,6 +1091,9 @@
DSS_REG_W(io, HDMI_HDCP_RESET, BIT(0));
+ /* Wait to be clean on DDC HW engine */
+ hdmi_hdcp_hw_ddc_clean(hdcp_ctrl);
+
/* Disable encryption and disable the HDCP block */
DSS_REG_W(io, HDMI_HDCP_CTRL, 0);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index 287f2cd..1fef395 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -87,6 +87,9 @@
static void hdmi_tx_hpd_off(struct hdmi_tx_ctrl *hdmi_ctrl);
static int hdmi_tx_enable_power(struct hdmi_tx_ctrl *hdmi_ctrl,
enum hdmi_tx_power_module_type module, int enable);
+static void hdmi_tx_audio_off(struct hdmi_tx_ctrl *hdmi_ctrl,
+ bool wait_audio_tx);
+static int hdmi_tx_audio_setup(struct hdmi_tx_ctrl *hdmi_ctrl);
struct mdss_hw hdmi_tx_hw = {
.hw_ndx = MDSS_HW_HDMI,
@@ -863,13 +866,14 @@
static void hdmi_tx_hpd_int_work(struct work_struct *work)
{
struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+ struct dss_io_data *io;
hdmi_ctrl = container_of(work, struct hdmi_tx_ctrl, hpd_int_work);
if (!hdmi_ctrl || !hdmi_ctrl->hpd_initialized) {
DEV_DBG("%s: invalid input\n", __func__);
return;
}
-
+ io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
DEV_DBG("%s: Got HPD interrupt\n", __func__);
if (hdmi_ctrl->hpd_state) {
@@ -877,6 +881,9 @@
DEV_ERR("%s: Failed to enable ddc power\n", __func__);
return;
}
+ /* Enable SW DDC before EDID read */
+ DSS_REG_W_ND(io, HDMI_DDC_ARBITRATION ,
+ DSS_REG_R(io, HDMI_DDC_ARBITRATION) & ~(BIT(4)));
hdmi_tx_read_sink_info(hdmi_ctrl);
hdmi_tx_send_cable_notification(hdmi_ctrl, 1);
@@ -1676,10 +1683,11 @@
} /* hdmi_tx_powerdown_phy */
static int hdmi_tx_audio_acr_setup(struct hdmi_tx_ctrl *hdmi_ctrl,
- bool enabled, int num_of_channels)
+ bool enabled)
{
/* Read first before writing */
u32 acr_pck_ctrl_reg;
+ u32 sample_rate;
struct dss_io_data *io = NULL;
if (!hdmi_ctrl) {
@@ -1687,6 +1695,8 @@
return -EINVAL;
}
+ sample_rate = hdmi_ctrl->audio_data.sample_rate;
+
io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
if (!io->base) {
DEV_ERR("%s: core io not inititalized\n", __func__);
@@ -1721,18 +1731,19 @@
return -EPERM;
}
- n = audio_acr->lut[hdmi_ctrl->audio_sample_rate].n;
- cts = audio_acr->lut[hdmi_ctrl->audio_sample_rate].cts;
- layout = (MSM_HDMI_AUDIO_CHANNEL_2 == num_of_channels) ? 0 : 1;
+ n = audio_acr->lut[sample_rate].n;
+ cts = audio_acr->lut[sample_rate].cts;
+ layout = (MSM_HDMI_AUDIO_CHANNEL_2 ==
+ hdmi_ctrl->audio_data.channel_num) ? 0 : 1;
if (
- (AUDIO_SAMPLE_RATE_192KHZ == hdmi_ctrl->audio_sample_rate) ||
- (AUDIO_SAMPLE_RATE_176_4KHZ == hdmi_ctrl->audio_sample_rate)) {
+ (AUDIO_SAMPLE_RATE_192KHZ == sample_rate) ||
+ (AUDIO_SAMPLE_RATE_176_4KHZ == sample_rate)) {
multiplier = 4;
n >>= 2; /* divide N by 4 and use multiplier */
} else if (
- (AUDIO_SAMPLE_RATE_96KHZ == hdmi_ctrl->audio_sample_rate) ||
- (AUDIO_SAMPLE_RATE_88_2KHZ == hdmi_ctrl->audio_sample_rate)) {
+ (AUDIO_SAMPLE_RATE_96KHZ == sample_rate) ||
+ (AUDIO_SAMPLE_RATE_88_2KHZ == sample_rate)) {
multiplier = 2;
n >>= 1; /* divide N by 2 and use multiplier */
} else {
@@ -1743,12 +1754,16 @@
/* AUDIO_PRIORITY | SOURCE */
acr_pck_ctrl_reg |= 0x80000100;
+
+ /* Reset multiplier bits */
+ acr_pck_ctrl_reg &= ~(7 << 16);
+
/* N_MULTIPLE(multiplier) */
acr_pck_ctrl_reg |= (multiplier & 7) << 16;
- if ((AUDIO_SAMPLE_RATE_48KHZ == hdmi_ctrl->audio_sample_rate) ||
- (AUDIO_SAMPLE_RATE_96KHZ == hdmi_ctrl->audio_sample_rate) ||
- (AUDIO_SAMPLE_RATE_192KHZ == hdmi_ctrl->audio_sample_rate)) {
+ if ((AUDIO_SAMPLE_RATE_48KHZ == sample_rate) ||
+ (AUDIO_SAMPLE_RATE_96KHZ == sample_rate) ||
+ (AUDIO_SAMPLE_RATE_192KHZ == sample_rate)) {
/* SELECT(3) */
acr_pck_ctrl_reg |= 3 << 4;
/* CTS_48 */
@@ -1759,9 +1774,9 @@
/* N */
DSS_REG_W(io, HDMI_ACR_48_1, n);
} else if (
- (AUDIO_SAMPLE_RATE_44_1KHZ == hdmi_ctrl->audio_sample_rate) ||
- (AUDIO_SAMPLE_RATE_88_2KHZ == hdmi_ctrl->audio_sample_rate) ||
- (AUDIO_SAMPLE_RATE_176_4KHZ == hdmi_ctrl->audio_sample_rate)) {
+ (AUDIO_SAMPLE_RATE_44_1KHZ == sample_rate) ||
+ (AUDIO_SAMPLE_RATE_88_2KHZ == sample_rate) ||
+ (AUDIO_SAMPLE_RATE_176_4KHZ == sample_rate)) {
/* SELECT(2) */
acr_pck_ctrl_reg |= 2 << 4;
/* CTS_44 */
@@ -1800,12 +1815,15 @@
} /* hdmi_tx_audio_acr_setup */
static int hdmi_tx_audio_iframe_setup(struct hdmi_tx_ctrl *hdmi_ctrl,
- bool enabled, u32 num_of_channels, u32 channel_allocation,
- u32 level_shift, bool down_mix)
+ bool enabled)
{
struct dss_io_data *io = NULL;
u32 channel_count = 1; /* Def to 2 channels -> Table 17 in CEA-D */
+ u32 num_of_channels;
+ u32 channel_allocation;
+ u32 level_shift;
+ u32 down_mix;
u32 check_sum, audio_info_0_reg, audio_info_1_reg;
u32 audio_info_ctrl_reg;
u32 aud_pck_ctrl_2_reg;
@@ -1816,6 +1834,11 @@
return -EINVAL;
}
+ num_of_channels = hdmi_ctrl->audio_data.channel_num;
+ channel_allocation = hdmi_ctrl->audio_data.spkr_alloc;
+ level_shift = hdmi_ctrl->audio_data.level_shift;
+ down_mix = hdmi_ctrl->audio_data.down_mix;
+
io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
if (!io->base) {
DEV_ERR("%s: core io not inititalized\n", __func__);
@@ -1926,8 +1949,8 @@
} /* hdmi_tx_audio_iframe_setup */
static int hdmi_tx_audio_info_setup(struct platform_device *pdev,
- u32 num_of_channels, u32 channel_allocation, u32 level_shift,
- bool down_mix)
+ u32 sample_rate, u32 num_of_channels, u32 channel_allocation,
+ u32 level_shift, bool down_mix)
{
int rc = 0;
struct hdmi_tx_ctrl *hdmi_ctrl = platform_get_drvdata(pdev);
@@ -1937,10 +1960,31 @@
return -ENODEV;
}
- if (hdmi_ctrl->panel_power_on) {
- rc = hdmi_tx_audio_iframe_setup(hdmi_ctrl, true,
- num_of_channels, channel_allocation, level_shift,
- down_mix);
+ if (!hdmi_tx_is_dvi_mode(hdmi_ctrl) && hdmi_ctrl->panel_power_on) {
+
+ /* Map given sample rate to Enum */
+ if (sample_rate == 32000)
+ sample_rate = AUDIO_SAMPLE_RATE_32KHZ;
+ else if (sample_rate == 44100)
+ sample_rate = AUDIO_SAMPLE_RATE_44_1KHZ;
+ else if (sample_rate == 48000)
+ sample_rate = AUDIO_SAMPLE_RATE_48KHZ;
+ else if (sample_rate == 88200)
+ sample_rate = AUDIO_SAMPLE_RATE_88_2KHZ;
+ else if (sample_rate == 96000)
+ sample_rate = AUDIO_SAMPLE_RATE_96KHZ;
+ else if (sample_rate == 176400)
+ sample_rate = AUDIO_SAMPLE_RATE_176_4KHZ;
+ else if (sample_rate == 192000)
+ sample_rate = AUDIO_SAMPLE_RATE_192KHZ;
+
+ hdmi_ctrl->audio_data.sample_rate = sample_rate;
+ hdmi_ctrl->audio_data.channel_num = num_of_channels;
+ hdmi_ctrl->audio_data.spkr_alloc = channel_allocation;
+ hdmi_ctrl->audio_data.level_shift = level_shift;
+ hdmi_ctrl->audio_data.down_mix = down_mix;
+
+ rc = hdmi_tx_audio_setup(hdmi_ctrl);
if (rc)
DEV_ERR("%s: hdmi_tx_audio_iframe_setup failed.rc=%d\n",
__func__, rc);
@@ -2047,7 +2091,6 @@
static int hdmi_tx_audio_setup(struct hdmi_tx_ctrl *hdmi_ctrl)
{
int rc = 0;
- const int channels = MSM_HDMI_AUDIO_CHANNEL_2;
struct dss_io_data *io = NULL;
if (!hdmi_ctrl) {
@@ -2061,14 +2104,14 @@
return -EINVAL;
}
- rc = hdmi_tx_audio_acr_setup(hdmi_ctrl, true, channels);
+ rc = hdmi_tx_audio_acr_setup(hdmi_ctrl, true);
if (rc) {
DEV_ERR("%s: hdmi_tx_audio_acr_setup failed. rc=%d\n",
__func__, rc);
return rc;
}
- rc = hdmi_tx_audio_iframe_setup(hdmi_ctrl, true, channels, 0, 0, false);
+ rc = hdmi_tx_audio_iframe_setup(hdmi_ctrl, true);
if (rc) {
DEV_ERR("%s: hdmi_tx_audio_iframe_setup failed. rc=%d\n",
__func__, rc);
@@ -2080,9 +2123,10 @@
return 0;
} /* hdmi_tx_audio_setup */
-static void hdmi_tx_audio_off(struct hdmi_tx_ctrl *hdmi_ctrl)
+static void hdmi_tx_audio_off(struct hdmi_tx_ctrl *hdmi_ctrl,
+ bool wait_audio_tx)
{
- u32 i, status, sleep_us, timeout_us, timeout_sec = 15;
+ u32 i = 0, status, sleep_us, timeout_us, timeout_sec = 15;
struct dss_io_data *io = NULL;
if (!hdmi_ctrl) {
@@ -2096,33 +2140,43 @@
return;
}
- /* Check if audio engine is turned off by QDSP or not */
- /* send off notification after every 1 sec for 15 seconds */
- for (i = 0; i < timeout_sec; i++) {
- sleep_us = 5000; /* Maximum time to sleep between two reads */
- timeout_us = 1000 * 1000; /* Total time for condition to meet */
+ if (wait_audio_tx) {
+ /* Check if audio engine is turned off by QDSP or not */
+ /* send off notification after every 1 sec for 15 seconds */
+ for (i = 0; i < timeout_sec; i++) {
+ /* Maximum time to sleep between two reads */
+ sleep_us = 5000;
+ /* Total time for condition to meet */
+ timeout_us = 1000 * 1000;
- if (readl_poll_timeout((io->base + HDMI_AUDIO_CFG),
- status, ((status & BIT(0)) == 0),
- sleep_us, timeout_us)) {
+ if (readl_poll_timeout((io->base + HDMI_AUDIO_CFG),
+ status, ((status & BIT(0)) == 0),
+ sleep_us, timeout_us)) {
- DEV_ERR("%s: audio still on after %d sec. try again\n",
+ DEV_ERR(
+ "%s: audio still on after %d sec. try again\n",
__func__, i+1);
- hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0, true);
- continue;
+ hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0,
+ true);
+ continue;
+ }
+ break;
}
- break;
}
+
if (i == timeout_sec)
DEV_ERR("%s: Error: cannot turn off audio engine\n", __func__);
- if (hdmi_tx_audio_iframe_setup(hdmi_ctrl, false, 0, 0, 0, false))
+ if (hdmi_tx_audio_iframe_setup(hdmi_ctrl, false))
DEV_ERR("%s: hdmi_tx_audio_iframe_setup failed.\n", __func__);
- if (hdmi_tx_audio_acr_setup(hdmi_ctrl, false, 0))
+ if (hdmi_tx_audio_acr_setup(hdmi_ctrl, false))
DEV_ERR("%s: hdmi_tx_audio_acr_setup failed.\n", __func__);
+ hdmi_ctrl->audio_data.sample_rate = AUDIO_SAMPLE_RATE_48KHZ;
+ hdmi_ctrl->audio_data.channel_num = MSM_HDMI_AUDIO_CHANNEL_2;
+
DEV_INFO("HDMI Audio: Disabled\n");
} /* hdmi_tx_audio_off */
@@ -2239,7 +2293,7 @@
if (!hdmi_tx_is_dvi_mode(hdmi_ctrl)) {
hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0, false);
- hdmi_tx_audio_off(hdmi_ctrl);
+ hdmi_tx_audio_off(hdmi_ctrl, true);
}
hdmi_tx_powerdown_phy(hdmi_ctrl);
@@ -2250,6 +2304,8 @@
*/
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);
if (hdmi_ctrl->hpd_off_pending) {
@@ -2257,8 +2313,6 @@
hdmi_ctrl->hpd_off_pending = false;
}
- hdmi_cec_deconfig(hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC]);
-
mutex_lock(&hdmi_ctrl->mutex);
hdmi_ctrl->panel_power_on = false;
mutex_unlock(&hdmi_ctrl->mutex);
@@ -2656,7 +2710,8 @@
INIT_WORK(&hdmi_ctrl->power_off_work, hdmi_tx_power_off_work);
- hdmi_ctrl->audio_sample_rate = AUDIO_SAMPLE_RATE_48KHZ;
+ hdmi_ctrl->audio_data.sample_rate = AUDIO_SAMPLE_RATE_48KHZ;
+ hdmi_ctrl->audio_data.channel_num = MSM_HDMI_AUDIO_CHANNEL_2;
hdmi_ctrl->sdev.name = "hdmi";
if (switch_dev_register(&hdmi_ctrl->sdev) < 0) {
@@ -3216,13 +3271,13 @@
__func__, hdmi_tx_pm_name(module_type), rc);
goto error;
}
- mp->vreg_config[j].peak_current = val_array[i];
+ mp->vreg_config[j].enable_load = val_array[i];
DEV_DBG("%s: %s min=%d, max=%d, pc=%d\n", __func__,
mp->vreg_config[j].vreg_name,
mp->vreg_config[j].min_voltage,
mp->vreg_config[j].max_voltage,
- mp->vreg_config[j].peak_current);
+ mp->vreg_config[j].enable_load);
ndx_mask >>= 1;
j++;
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.h b/drivers/video/msm/mdss/mdss_hdmi_tx.h
index d4f8e67..18ee782 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.h
@@ -38,12 +38,20 @@
struct dss_module_power power_data[HDMI_TX_MAX_PM];
};
+struct hdmi_audio {
+ int sample_rate;
+ int channel_num;
+ int spkr_alloc;
+ int level_shift;
+ int down_mix;
+};
+
struct hdmi_tx_ctrl {
struct platform_device *pdev;
struct hdmi_tx_platform_data pdata;
struct mdss_panel_data panel_data;
- int audio_sample_rate;
+ struct hdmi_audio audio_data;
struct mutex mutex;
struct kobject *kobj;
diff --git a/drivers/video/msm/mdss/mdss_io_util.c b/drivers/video/msm/mdss/mdss_io_util.c
index 31058f8..c862e78 100644
--- a/drivers/video/msm/mdss/mdss_io_util.c
+++ b/drivers/video/msm/mdss/mdss_io_util.c
@@ -213,7 +213,7 @@
}
msleep(in_vreg[i].pre_on_sleep);
rc = regulator_set_optimum_mode(in_vreg[i].vreg,
- in_vreg[i].peak_current);
+ in_vreg[i].enable_load);
if (rc < 0) {
DEV_ERR("%pS->%s: %s set opt m fail\n",
__builtin_return_address(0), __func__,
@@ -233,7 +233,8 @@
for (i = num_vreg-1; i >= 0; i--)
if (regulator_is_enabled(in_vreg[i].vreg)) {
msleep(in_vreg[i].pre_off_sleep);
- regulator_set_optimum_mode(in_vreg[i].vreg, 0);
+ regulator_set_optimum_mode(in_vreg[i].vreg,
+ in_vreg[i].disable_load);
regulator_disable(in_vreg[i].vreg);
msleep(in_vreg[i].post_off_sleep);
}
@@ -241,12 +242,13 @@
return rc;
disable_vreg:
- regulator_set_optimum_mode(in_vreg[i].vreg, 0);
+ regulator_set_optimum_mode(in_vreg[i].vreg, in_vreg[i].disable_load);
vreg_set_opt_mode_fail:
for (i--; i >= 0; i--) {
msleep(in_vreg[i].pre_off_sleep);
- regulator_set_optimum_mode(in_vreg[i].vreg, 0);
+ regulator_set_optimum_mode(in_vreg[i].vreg,
+ in_vreg[i].disable_load);
regulator_disable(in_vreg[i].vreg);
msleep(in_vreg[i].post_off_sleep);
}
diff --git a/drivers/video/msm/mdss/mdss_io_util.h b/drivers/video/msm/mdss/mdss_io_util.h
index cb0fb70..6ad21e8 100644
--- a/drivers/video/msm/mdss/mdss_io_util.h
+++ b/drivers/video/msm/mdss/mdss_io_util.h
@@ -52,7 +52,8 @@
char vreg_name[32];
int min_voltage;
int max_voltage;
- int peak_current;
+ int enable_load;
+ int disable_load;
int pre_on_sleep;
int post_on_sleep;
int pre_off_sleep;
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index fc8c6e3..6f9c98e 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -68,6 +68,10 @@
.fb_stride = mdss_mdp_fb_stride,
};
+#define DEFAULT_TOTAL_RGB_PIPES 3
+#define DEFAULT_TOTAL_VIG_PIPES 3
+#define DEFAULT_TOTAL_DMA_PIPES 2
+
#define IB_QUOTA 800000000
#define AB_QUOTA 800000000
@@ -129,6 +133,7 @@
struct mdss_hw *mdss_irq_handlers[MDSS_MAX_HW_BLK];
static void mdss_mdp_footswitch_ctrl(struct mdss_data_type *mdata, int on);
+static inline int mdss_mdp_suspend_sub(struct mdss_data_type *mdata);
static int mdss_mdp_parse_dt(struct platform_device *pdev);
static int mdss_mdp_parse_dt_pipe(struct platform_device *pdev);
static int mdss_mdp_parse_dt_mixer(struct platform_device *pdev);
@@ -906,6 +911,18 @@
}
}
+static void mdss_mdp_shutdown(struct platform_device *pdev)
+{
+ struct mdss_data_type *mdata = platform_get_drvdata(pdev);
+
+ if (!mdata)
+ return;
+
+ pr_debug("display shutdown\n");
+
+ mdss_mdp_suspend_sub(mdata);
+}
+
static int mdss_mdp_probe(struct platform_device *pdev)
{
struct resource *res;
@@ -1146,9 +1163,9 @@
static int mdss_mdp_parse_dt_pipe(struct platform_device *pdev)
{
- u32 npipes, off;
+ u32 npipes, dma_off;
int rc = 0;
- u32 nids = 0;
+ u32 nids = 0, setup_cnt = 0, len;
u32 *offsets = NULL, *ftch_id = NULL;
struct mdss_data_type *mdata = platform_get_drvdata(pdev);
@@ -1176,17 +1193,41 @@
offsets = kzalloc(sizeof(u32) * npipes, GFP_KERNEL);
if (!offsets) {
- pr_err("no mem assigned: kzalloc fail\n");
+ pr_err("no mem assigned for offsets: kzalloc fail\n");
return -ENOMEM;
}
ftch_id = kzalloc(sizeof(u32) * nids, GFP_KERNEL);
if (!ftch_id) {
- pr_err("no mem assigned: kzalloc fail\n");
+ pr_err("no mem assigned for ftch_id: kzalloc fail\n");
rc = -ENOMEM;
goto ftch_alloc_fail;
}
+ mdata->vig_pipes = devm_kzalloc(&mdata->pdev->dev,
+ sizeof(struct mdss_mdp_pipe) * mdata->nvig_pipes, GFP_KERNEL);
+ if (!mdata->vig_pipes) {
+ pr_err("no mem for vig_pipes: kzalloc fail\n");
+ rc = -ENOMEM;
+ goto vig_alloc_fail;
+ }
+
+ mdata->rgb_pipes = devm_kzalloc(&mdata->pdev->dev,
+ sizeof(struct mdss_mdp_pipe) * mdata->nrgb_pipes, GFP_KERNEL);
+ if (!mdata->rgb_pipes) {
+ pr_err("no mem for rgb_pipes: kzalloc fail\n");
+ rc = -ENOMEM;
+ goto rgb_alloc_fail;
+ }
+
+ mdata->dma_pipes = devm_kzalloc(&mdata->pdev->dev,
+ sizeof(struct mdss_mdp_pipe) * mdata->ndma_pipes, GFP_KERNEL);
+ if (!mdata->dma_pipes) {
+ pr_err("no mem for dma_pipes: kzalloc fail\n");
+ rc = -ENOMEM;
+ goto dma_alloc_fail;
+ }
+
rc = mdss_mdp_parse_dt_handler(pdev, "qcom,mdss-pipe-vig-fetch-id",
ftch_id, mdata->nvig_pipes);
if (rc)
@@ -1195,47 +1236,91 @@
rc = mdss_mdp_parse_dt_handler(pdev, "qcom,mdss-pipe-vig-off",
offsets, mdata->nvig_pipes);
if (rc)
- goto parse_done;
+ goto parse_fail;
- rc = mdss_mdp_pipe_addr_setup(mdata, offsets, ftch_id,
- MDSS_MDP_PIPE_TYPE_VIG, MDSS_MDP_SSPP_VIG0, mdata->nvig_pipes);
+ len = min_t(int, DEFAULT_TOTAL_VIG_PIPES, (int)mdata->nvig_pipes);
+ rc = mdss_mdp_pipe_addr_setup(mdata, mdata->vig_pipes, offsets, ftch_id,
+ MDSS_MDP_PIPE_TYPE_VIG, MDSS_MDP_SSPP_VIG0, len);
if (rc)
- goto parse_done;
+ goto parse_fail;
+
+ setup_cnt += len;
rc = mdss_mdp_parse_dt_handler(pdev, "qcom,mdss-pipe-rgb-fetch-id",
ftch_id + mdata->nvig_pipes, mdata->nrgb_pipes);
if (rc)
- goto parse_done;
+ goto parse_fail;
rc = mdss_mdp_parse_dt_handler(pdev, "qcom,mdss-pipe-rgb-off",
offsets + mdata->nvig_pipes, mdata->nrgb_pipes);
if (rc)
- goto parse_done;
+ goto parse_fail;
- rc = mdss_mdp_pipe_addr_setup(mdata, offsets + mdata->nvig_pipes,
- ftch_id + mdata->nvig_pipes, MDSS_MDP_PIPE_TYPE_RGB,
- MDSS_MDP_SSPP_RGB0, mdata->nrgb_pipes);
+ len = min_t(int, DEFAULT_TOTAL_RGB_PIPES, (int)mdata->nrgb_pipes);
+ rc = mdss_mdp_pipe_addr_setup(mdata, mdata->rgb_pipes,
+ offsets + mdata->nvig_pipes, ftch_id + mdata->nvig_pipes,
+ MDSS_MDP_PIPE_TYPE_RGB, MDSS_MDP_SSPP_RGB0, len);
if (rc)
- goto parse_done;
+ goto parse_fail;
- off = mdata->nvig_pipes + mdata->nrgb_pipes;
+ setup_cnt += len;
+ dma_off = mdata->nvig_pipes + mdata->nrgb_pipes;
rc = mdss_mdp_parse_dt_handler(pdev, "qcom,mdss-pipe-dma-fetch-id",
- ftch_id + off, mdata->ndma_pipes);
+ ftch_id + dma_off, mdata->ndma_pipes);
if (rc)
- goto parse_done;
+ goto parse_fail;
rc = mdss_mdp_parse_dt_handler(pdev, "qcom,mdss-pipe-dma-off",
- offsets + off, mdata->ndma_pipes);
+ offsets + dma_off, mdata->ndma_pipes);
if (rc)
- goto parse_done;
+ goto parse_fail;
- rc = mdss_mdp_pipe_addr_setup(mdata, offsets + off, ftch_id + off,
- MDSS_MDP_PIPE_TYPE_DMA, MDSS_MDP_SSPP_DMA0, mdata->ndma_pipes);
+ len = mdata->ndma_pipes;
+ rc = mdss_mdp_pipe_addr_setup(mdata, mdata->dma_pipes,
+ offsets + dma_off, ftch_id + dma_off, MDSS_MDP_PIPE_TYPE_DMA,
+ MDSS_MDP_SSPP_DMA0, len);
if (rc)
- goto parse_done;
+ goto parse_fail;
+ setup_cnt += len;
+
+ if (mdata->nvig_pipes > DEFAULT_TOTAL_VIG_PIPES) {
+ rc = mdss_mdp_pipe_addr_setup(mdata,
+ mdata->vig_pipes + DEFAULT_TOTAL_VIG_PIPES,
+ offsets + DEFAULT_TOTAL_VIG_PIPES,
+ ftch_id + DEFAULT_TOTAL_VIG_PIPES,
+ MDSS_MDP_PIPE_TYPE_VIG, setup_cnt,
+ mdata->nvig_pipes - DEFAULT_TOTAL_VIG_PIPES);
+ if (rc)
+ goto parse_fail;
+
+ setup_cnt += mdata->nvig_pipes - DEFAULT_TOTAL_VIG_PIPES;
+ }
+
+ if (mdata->nrgb_pipes > DEFAULT_TOTAL_RGB_PIPES) {
+ rc = mdss_mdp_pipe_addr_setup(mdata,
+ mdata->rgb_pipes + DEFAULT_TOTAL_RGB_PIPES,
+ offsets + mdata->nvig_pipes + DEFAULT_TOTAL_RGB_PIPES,
+ ftch_id + mdata->nvig_pipes + DEFAULT_TOTAL_RGB_PIPES,
+ MDSS_MDP_PIPE_TYPE_RGB, setup_cnt,
+ mdata->nrgb_pipes - DEFAULT_TOTAL_RGB_PIPES);
+ if (rc)
+ goto parse_fail;
+
+ setup_cnt += mdata->nrgb_pipes - DEFAULT_TOTAL_RGB_PIPES;
+ }
+
+ goto parse_done;
+
+parse_fail:
+ kfree(mdata->dma_pipes);
+dma_alloc_fail:
+ kfree(mdata->rgb_pipes);
+rgb_alloc_fail:
+ kfree(mdata->vig_pipes);
parse_done:
+vig_alloc_fail:
kfree(ftch_id);
ftch_alloc_fail:
kfree(offsets);
@@ -1439,10 +1524,16 @@
rc = mdss_mdp_smp_setup(mdata, data[0], data[1]);
- if (rc)
+ if (rc) {
pr_err("unable to setup smp data\n");
+ return rc;
+ }
- return rc;
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,mdss-smp-mb-per-pipe", data);
+ mdata->smp_mb_per_pipe = (!rc ? data[0] : 0);
+
+ return 0;
}
static int mdss_mdp_parse_dt_misc(struct platform_device *pdev)
@@ -1459,6 +1550,8 @@
"qcom,mdss-has-bwc");
mdata->has_decimation = of_property_read_bool(pdev->dev.of_node,
"qcom,mdss-has-decimation");
+ mdata->has_wfd_blk = of_property_read_bool(pdev->dev.of_node,
+ "qcom,mdss-has-wfd-blk");
return 0;
}
@@ -1702,7 +1795,7 @@
.remove = mdss_mdp_remove,
.suspend = mdss_mdp_suspend,
.resume = mdss_mdp_resume,
- .shutdown = NULL,
+ .shutdown = mdss_mdp_shutdown,
.driver = {
/*
* Driver name must match the device name added in
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 7cae18c..aba77e3 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -118,6 +118,11 @@
struct list_head list;
};
+enum mdss_mdp_wb_ctl_type {
+ MDSS_MDP_WB_CTL_TYPE_BLOCK = 1,
+ MDSS_MDP_WB_CTL_TYPE_LINE
+};
+
struct mdss_mdp_ctl {
u32 num;
char __iomem *base;
@@ -151,6 +156,7 @@
struct mdss_mdp_mixer *mixer_left;
struct mdss_mdp_mixer *mixer_right;
struct mutex lock;
+ struct mutex *shared_lock;
struct mdss_panel_data *panel_data;
struct mdss_mdp_vsync_handler vsync_handler;
@@ -168,6 +174,7 @@
struct mdss_mdp_vsync_handler *);
void *priv_data;
+ u32 wb_type;
};
struct mdss_mdp_mixer {
@@ -294,6 +301,11 @@
struct pp_sts_type pp_sts;
};
+struct mdss_mdp_pipe_smp_map {
+ DECLARE_BITMAP(reserved, MDSS_MDP_SMP_MMB_BLOCKS);
+ DECLARE_BITMAP(allocated, MDSS_MDP_SMP_MMB_BLOCKS);
+};
+
struct mdss_mdp_pipe {
u32 num;
u32 type;
@@ -330,8 +342,7 @@
struct mdp_overlay req_data;
u32 params_changed;
- unsigned long smp[MAX_PLANES];
- unsigned long smp_reserved[MAX_PLANES];
+ struct mdss_mdp_pipe_smp_map smp_map[MAX_PLANES];
struct mdss_mdp_data back_buf;
struct mdss_mdp_data front_buf;
@@ -525,8 +536,9 @@
void mdss_mdp_smp_unreserve(struct mdss_mdp_pipe *pipe);
void mdss_mdp_smp_release(struct mdss_mdp_pipe *pipe);
-int mdss_mdp_pipe_addr_setup(struct mdss_data_type *mdata, u32 *offsets,
- u32 *ftch_y_id, u32 type, u32 num_base, u32 len);
+int mdss_mdp_pipe_addr_setup(struct mdss_data_type *mdata,
+ struct mdss_mdp_pipe *head, u32 *offsets, u32 *ftch_y_id, u32 type,
+ u32 num_base, u32 len);
int mdss_mdp_mixer_addr_setup(struct mdss_data_type *mdata, u32 *mixer_offsets,
u32 *dspp_offsets, u32 *pingpong_offsets, u32 type, u32 len);
int mdss_mdp_ctl_addr_setup(struct mdss_data_type *mdata, u32 *ctl_offsets,
@@ -559,8 +571,17 @@
int mdss_panel_register_done(struct mdss_panel_data *pdata);
int mdss_mdp_limited_lut_igc_config(struct mdss_mdp_ctl *ctl);
int mdss_mdp_calib_config(struct mdp_calib_config_data *cfg, u32 *copyback);
+int mdss_mdp_calib_config_buffer(struct mdp_calib_config_buffer *cfg,
+ u32 *copyback);
int mdss_mdp_pipe_is_staged(struct mdss_mdp_pipe *pipe);
+int mdss_mdp_writeback_display_commit(struct mdss_mdp_ctl *ctl, void *arg);
+struct mdss_mdp_ctl *mdss_mdp_ctl_mixer_switch(struct mdss_mdp_ctl *ctl,
+ u32 return_type);
+
+int mdss_mdp_wb_set_format(struct msm_fb_data_type *mfd, int dst_format);
+int mdss_mdp_wb_get_format(struct msm_fb_data_type *mfd,
+ struct mdp_mixer_cfg *mixer_cfg);
#define mfd_to_mdp5_data(mfd) (mfd->mdp.private1)
#define mfd_to_mdata(mfd) (((struct mdss_overlay_private *)\
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 86f632c..b5a5383 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -299,9 +299,13 @@
{
struct mdss_mdp_ctl *ctl = NULL;
u32 cnum;
+ u32 nctl = mdata->nctl;
mutex_lock(&mdss_mdp_ctl_lock);
- for (cnum = off; cnum < mdata->nctl; cnum++) {
+ if (!mdata->has_wfd_blk)
+ nctl++;
+
+ for (cnum = off; cnum < nctl; cnum++) {
ctl = mdata->ctl_off + cnum;
if (ctl->ref_cnt == 0) {
ctl->ref_cnt++;
@@ -399,13 +403,18 @@
(mixer_pool[MDSS_MDP_INTF_LAYERMIXER2].ref_cnt == 0))
mixer_pool += MDSS_MDP_INTF_LAYERMIXER2;
+ /*Allocate virtual wb mixer if no dedicated wfd wb blk is present*/
+ if (!ctl->mdata->has_wfd_blk && (type == MDSS_MDP_MIXER_TYPE_WRITEBACK))
+ nmixers += 1;
+
for (i = 0; i < nmixers; i++) {
mixer = mixer_pool + i;
if (mixer->ref_cnt == 0) {
mixer->ref_cnt++;
mixer->params_changed++;
mixer->ctl = ctl;
- pr_debug("alloc mixer num%d\n", mixer->num);
+ pr_debug("alloc mixer num %d for ctl=%d\n",
+ mixer->num, ctl->num);
break;
}
mixer = NULL;
@@ -440,12 +449,16 @@
struct mdss_mdp_mixer *mixer = NULL;
ctl = mdss_mdp_ctl_alloc(mdss_res, mdss_res->nmixers_intf);
- if (!ctl)
+ if (!ctl) {
+ pr_err("unable to allocate wb ctl\n");
return NULL;
+ }
mixer = mdss_mdp_mixer_alloc(ctl, MDSS_MDP_MIXER_TYPE_WRITEBACK, false);
- if (!mixer)
+ if (!mixer) {
+ pr_err("unable to allocate wb mixer\n");
goto error;
+ }
mixer->rotator_mode = rotator;
@@ -467,6 +480,9 @@
ctl->start_fnc = mdss_mdp_writeback_start;
ctl->power_on = true;
+ ctl->wb_type = (rotator ? MDSS_MDP_WB_CTL_TYPE_BLOCK :
+ MDSS_MDP_WB_CTL_TYPE_LINE);
+ mixer->ctl = ctl;
if (ctl->start_fnc)
ctl->start_fnc(ctl);
@@ -597,6 +613,7 @@
{
struct mdss_mdp_ctl *split_ctl;
u32 width, height;
+ int split_fb;
if (!ctl || !ctl->panel_data) {
pr_err("invalid ctl handle\n");
@@ -608,6 +625,13 @@
width = ctl->panel_data->panel_info.xres;
height = ctl->panel_data->panel_info.yres;
+ split_fb = (ctl->mfd->split_fb_left &&
+ ctl->mfd->split_fb_right &&
+ (ctl->mfd->split_fb_left <= MAX_MIXER_WIDTH) &&
+ (ctl->mfd->split_fb_right <= MAX_MIXER_WIDTH)) ? 1 : 0;
+ pr_debug("max=%d xres=%d left=%d right=%d\n", MAX_MIXER_WIDTH,
+ width, ctl->mfd->split_fb_left, ctl->mfd->split_fb_right);
+
if ((split_ctl && (width > MAX_MIXER_WIDTH)) ||
(width > (2 * MAX_MIXER_WIDTH))) {
pr_err("Unsupported panel resolution: %dx%d\n", width, height);
@@ -620,14 +644,16 @@
if (!ctl->mixer_left) {
ctl->mixer_left =
mdss_mdp_mixer_alloc(ctl, MDSS_MDP_MIXER_TYPE_INTF,
- (width > MAX_MIXER_WIDTH));
+ ((width > MAX_MIXER_WIDTH) || split_fb));
if (!ctl->mixer_left) {
pr_err("unable to allocate layer mixer\n");
return -ENOMEM;
}
}
- if (width > MAX_MIXER_WIDTH)
+ if (split_fb)
+ width = ctl->mfd->split_fb_left;
+ else if (width > MAX_MIXER_WIDTH)
width /= 2;
ctl->mixer_left->width = width;
@@ -638,6 +664,9 @@
return 0;
}
+ if (split_fb)
+ width = ctl->mfd->split_fb_right;
+
if (width < ctl->width) {
if (ctl->mixer_right == NULL) {
ctl->mixer_right = mdss_mdp_mixer_alloc(ctl,
@@ -705,6 +734,7 @@
mdss_mdp_mixer_free(mixer);
return -EINVAL;
}
+ ctl->wb_type = MDSS_MDP_WB_CTL_TYPE_LINE;
}
ctl->mixer_left = mixer;
@@ -1119,7 +1149,13 @@
if (pipe == NULL) {
mixercfg = MDSS_MDP_LM_BORDER_COLOR;
} else {
- mixercfg = 1 << (3 * pipe->num);
+ if (pipe->num == MDSS_MDP_SSPP_VIG3 ||
+ pipe->num == MDSS_MDP_SSPP_RGB3) {
+ /* Add 2 to account for Cursor & Border bits */
+ mixercfg = 1 << ((3 * pipe->num)+2);
+ } else {
+ mixercfg = 1 << (3 * pipe->num);
+ }
if (pipe->src_fmt->alpha_enable)
bgalpha = 1;
secure = pipe->flags & MDP_SECURE_OVERLAY_SESSION;
@@ -1187,7 +1223,10 @@
pr_debug("mixer=%d mixer_cfg=%x\n", mixer->num, mixercfg);
- ctl->flush_bits |= BIT(6) << mixer->num; /* LAYER_MIXER */
+ if (mixer->num == MDSS_MDP_INTF_LAYERMIXER3)
+ ctl->flush_bits |= BIT(20);
+ else
+ ctl->flush_bits |= BIT(6) << mixer->num;
mdp_mixer_write(mixer, MDSS_MDP_REG_LM_OP_MODE, blend_color_out);
off = __mdss_mdp_ctl_get_mixer_off(mixer);
@@ -1203,9 +1242,13 @@
struct mdss_mdp_mixer *head;
u32 i;
int rc = 0;
+ u32 size = len;
+
+ if ((type == MDSS_MDP_MIXER_TYPE_WRITEBACK) && !mdata->has_wfd_blk)
+ size++;
head = devm_kzalloc(&mdata->pdev->dev, sizeof(struct mdss_mdp_mixer) *
- len, GFP_KERNEL);
+ size, GFP_KERNEL);
if (!head) {
pr_err("unable to setup mixer type=%d :kzalloc fail\n",
@@ -1225,6 +1268,13 @@
}
}
+ /*
+ * Duplicate the last writeback mixer for concurrent line and block mode
+ * operations
+ */
+ if ((type == MDSS_MDP_MIXER_TYPE_WRITEBACK) && !mdata->has_wfd_blk)
+ head[len] = head[len - 1];
+
switch (type) {
case MDSS_MDP_MIXER_TYPE_INTF:
@@ -1248,10 +1298,24 @@
u32 *ctl_offsets, u32 *wb_offsets, u32 len)
{
struct mdss_mdp_ctl *head;
+ struct mutex *shared_lock = NULL;
u32 i;
+ u32 size = len;
+
+ if (!mdata->has_wfd_blk) {
+ size++;
+ shared_lock = devm_kzalloc(&mdata->pdev->dev,
+ sizeof(struct mutex),
+ GFP_KERNEL);
+ if (!shared_lock) {
+ pr_err("unable to allocate mem for mutex\n");
+ return -ENOMEM;
+ }
+ mutex_init(shared_lock);
+ }
head = devm_kzalloc(&mdata->pdev->dev, sizeof(struct mdss_mdp_ctl) *
- len, GFP_KERNEL);
+ size, GFP_KERNEL);
if (!head) {
pr_err("unable to setup ctl and wb: kzalloc fail\n");
@@ -1265,6 +1329,16 @@
head[i].ref_cnt = 0;
}
+ if (!mdata->has_wfd_blk) {
+ head[len - 1].shared_lock = shared_lock;
+ /*
+ * Allocate a virtual ctl to be able to perform simultaneous
+ * line mode and block mode operations on the same
+ * writeback block
+ */
+ head[len] = head[len - 1];
+ head[len].num = -1;
+ }
mdata->ctl_off = head;
return 0;
@@ -1349,7 +1423,10 @@
if (pipe->type == MDSS_MDP_PIPE_TYPE_DMA)
ctl->flush_bits |= BIT(pipe->num) << 5;
- else /* RGB/VIG pipe */
+ else if (pipe->num == MDSS_MDP_SSPP_VIG3 ||
+ pipe->num == MDSS_MDP_SSPP_RGB3)
+ ctl->flush_bits |= BIT(pipe->num) << 10;
+ else /* RGB/VIG 0-2 pipes */
ctl->flush_bits |= BIT(pipe->num);
mutex_unlock(&ctl->lock);
@@ -1388,11 +1465,19 @@
static int mdss_mdp_mixer_update(struct mdss_mdp_mixer *mixer)
{
+ u32 off = 0;
+ if (!mixer)
+ return -EINVAL;
+
mixer->params_changed = 0;
/* skip mixer setup for rotator */
- if (!mixer->rotator_mode)
+ if (!mixer->rotator_mode) {
mdss_mdp_mixer_setup(mixer->ctl, mixer);
+ } else {
+ off = __mdss_mdp_ctl_get_mixer_off(mixer);
+ mdss_mdp_ctl_write(mixer->ctl, off, 0);
+ }
return 0;
}
@@ -1521,12 +1606,9 @@
return -ENODEV;
}
+ mutex_lock(&ctl->lock);
pr_debug("commit ctl=%d play_cnt=%d\n", ctl->num, ctl->play_cnt);
- ret = mutex_lock_interruptible(&ctl->lock);
- if (ret)
- return ret;
-
if (!ctl->power_on) {
mutex_unlock(&ctl->lock);
return 0;
@@ -1621,11 +1703,45 @@
return mixer_cnt;
}
+/**
+ * @mdss_mdp_ctl_mixer_switch() - return ctl mixer of @return_type
+ * @ctl: Pointer to ctl structure to be switched.
+ * @return_type: wb_type of the ctl to be switched to.
+ *
+ * Virtual mixer switch should be performed only when there is no
+ * dedicated wfd block and writeback block is shared.
+ */
+struct mdss_mdp_ctl *mdss_mdp_ctl_mixer_switch(struct mdss_mdp_ctl *ctl,
+ u32 return_type)
+{
+ int i;
+ struct mdss_data_type *mdata = ctl->mdata;
+
+ if (ctl->wb_type == return_type) {
+ mdata->mixer_switched = false;
+ return ctl;
+ }
+ for (i = 0; i <= mdata->nctl; i++) {
+ if (mdata->ctl_off[i].wb_type == return_type) {
+ pr_debug("switching mixer from ctl=%d to ctl=%d\n",
+ ctl->num, mdata->ctl_off[i].num);
+ mdata->mixer_switched = true;
+ return mdata->ctl_off + i;
+ }
+ }
+ pr_err("unable to switch mixer to type=%d\n", return_type);
+ return NULL;
+}
+
static inline int __mdss_mdp_ctl_get_mixer_off(struct mdss_mdp_mixer *mixer)
{
- if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF)
- return MDSS_MDP_REG_CTL_LAYER(mixer->num);
- else
+ if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) {
+ if (mixer->num == MDSS_MDP_INTF_LAYERMIXER3)
+ return MDSS_MDP_CTL_X_LAYER_5;
+ else
+ return MDSS_MDP_REG_CTL_LAYER(mixer->num);
+ } else {
return MDSS_MDP_REG_CTL_LAYER(mixer->num +
- MDSS_MDP_INTF_MAX_LAYERMIXER);
+ MDSS_MDP_INTF_LAYERMIXER3);
+ }
}
diff --git a/drivers/video/msm/mdss/mdss_mdp_formats.h b/drivers/video/msm/mdss/mdss_mdp_formats.h
index acb8dc2..f5da8e6 100644
--- a/drivers/video/msm/mdss/mdss_mdp_formats.h
+++ b/drivers/video/msm/mdss/mdss_mdp_formats.h
@@ -124,6 +124,7 @@
FMT_RGB_8888(MDP_RGBA_8888, 1, C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA),
FMT_RGB_8888(MDP_RGBX_8888, 0, C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA),
FMT_RGB_8888(MDP_BGRA_8888, 1, C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA),
+ FMT_RGB_8888(MDP_BGRX_8888, 0, C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA),
FMT_YUV_PSEUDO(MDP_Y_CRCB_H1V1, MDSS_MDP_CHROMA_RGB, C2_R_Cr, C1_B_Cb),
FMT_YUV_PSEUDO(MDP_Y_CBCR_H1V1, MDSS_MDP_CHROMA_RGB, C1_B_Cb, C2_R_Cr),
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index 4779d20..ccd6e56 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -23,6 +23,7 @@
#define MDSS_MDP_HW_REV_100 0x10000000
#define MDSS_MDP_HW_REV_102 0x10020000
+#define MDSS_MDP_HW_REV_103 0x10030000
#define MDSS_REG_HW_VERSION 0x0
#define MDSS_REG_HW_INTR_STATUS 0x10
@@ -57,15 +58,19 @@
#define MDSS_MDP_INTR_PING_PONG_0_DONE BIT(8)
#define MDSS_MDP_INTR_PING_PONG_1_DONE BIT(9)
#define MDSS_MDP_INTR_PING_PONG_2_DONE BIT(10)
+#define MDSS_MDP_INTR_PING_PONG_3_DONE BIT(11)
#define MDSS_MDP_INTR_PING_PONG_0_RD_PTR BIT(12)
#define MDSS_MDP_INTR_PING_PONG_1_RD_PTR BIT(13)
#define MDSS_MDP_INTR_PING_PONG_2_RD_PTR BIT(14)
+#define MDSS_MDP_INTR_PING_PONG_3_RD_PTR BIT(15)
#define MDSS_MDP_INTR_PING_PONG_0_WR_PTR BIT(16)
#define MDSS_MDP_INTR_PING_PONG_1_WR_PTR BIT(17)
#define MDSS_MDP_INTR_PING_PONG_2_WR_PTR BIT(18)
+#define MDSS_MDP_INTR_PING_PONG_3_WR_PTR BIT(19)
#define MDSS_MDP_INTR_PING_PONG_0_AUTOREFRESH_DONE BIT(20)
#define MDSS_MDP_INTR_PING_PONG_1_AUTOREFRESH_DONE BIT(21)
#define MDSS_MDP_INTR_PING_PONG_2_AUTOREFRESH_DONE BIT(22)
+#define MDSS_MDP_INTR_PING_PONG_3_AUTOREFRESH_DONE BIT(23)
#define MDSS_MDP_INTR_INTF_0_UNDERRUN BIT(24)
#define MDSS_MDP_INTR_INTF_0_VSYNC BIT(25)
#define MDSS_MDP_INTR_INTF_1_UNDERRUN BIT(26)
@@ -97,6 +102,7 @@
MDSS_MDP_CTL2,
MDSS_MDP_CTL3,
MDSS_MDP_CTL4,
+ MDSS_MDP_CTL5,
MDSS_MDP_MAX_CTL
};
@@ -132,6 +138,8 @@
MDSS_MDP_SSPP_RGB2,
MDSS_MDP_SSPP_DMA0,
MDSS_MDP_SSPP_DMA1,
+ MDSS_MDP_SSPP_VIG3,
+ MDSS_MDP_SSPP_RGB3,
MDSS_MDP_MAX_SSPP
};
@@ -227,11 +235,13 @@
#define MDSS_MDP_NUM_REG_MIXERS 3
#define MDSS_MDP_NUM_WB_MIXERS 2
+#define MDSS_MDP_CTL_X_LAYER_5 0x24
enum mdss_mdp_mixer_intf_index {
MDSS_MDP_INTF_LAYERMIXER0,
MDSS_MDP_INTF_LAYERMIXER1,
MDSS_MDP_INTF_LAYERMIXER2,
+ MDSS_MDP_INTF_LAYERMIXER3,
MDSS_MDP_INTF_MAX_LAYERMIXER,
};
@@ -248,17 +258,10 @@
MDSS_MDP_STAGE_1,
MDSS_MDP_STAGE_2,
MDSS_MDP_STAGE_3,
+ MDSS_MDP_STAGE_4,
MDSS_MDP_MAX_STAGE
};
-enum mdss_mdp_blend_index {
- MDSS_MDP_BLEND_STAGE0,
- MDSS_MDP_BLEND_STAGE1,
- MDSS_MDP_BLEND_STAGE2,
- MDSS_MDP_BLEND_STAGE3,
- MDSS_MDP_MAX_BLEND_STAGE,
-};
-
#define MDSS_MDP_REG_LM_OFFSET(lm) (0x03200 + ((lm) * 0x400))
#define MDSS_MDP_REG_LM_OP_MODE 0x000
@@ -391,6 +394,7 @@
MDSS_MDP_DSPP0,
MDSS_MDP_DSPP1,
MDSS_MDP_DSPP2,
+ MDSS_MDP_DSPP3,
MDSS_MDP_MAX_DSPP
};
@@ -468,6 +472,7 @@
MDSS_MDP_PINGPONG0,
MDSS_MDP_PINGPONG1,
MDSS_MDP_PINGPONG2,
+ MDSS_MDP_PINGPONG3,
MDSS_MDP_MAX_PINGPONG
};
@@ -492,29 +497,7 @@
#define MDSS_MDP_REG_SMP_ALLOC_W0 0x00180
#define MDSS_MDP_REG_SMP_ALLOC_R0 0x00230
-#define MDSS_MDP_SMP_MMB_BLOCKS 22
-
-enum mdss_mdp_smp_client_index {
- MDSS_MDP_SMP_CLIENT_UNUSED,
- MDSS_MDP_SMP_CLIENT_VIG0_FETCH_Y,
- MDSS_MDP_SMP_CLIENT_VIG0_FETCH_CR,
- MDSS_MDP_SMP_CLIENT_VIG0_FETCH_CB,
- MDSS_MDP_SMP_CLIENT_VIG1_FETCH_Y,
- MDSS_MDP_SMP_CLIENT_VIG1_FETCH_CR,
- MDSS_MDP_SMP_CLIENT_VIG1_FETCH_CB,
- MDSS_MDP_SMP_CLIENT_VIG2_FETCH_Y,
- MDSS_MDP_SMP_CLIENT_VIG2_FETCH_CR,
- MDSS_MDP_SMP_CLIENT_VIG2_FETCH_CB,
- MDSS_MDP_SMP_CLIENT_DMA0_FETCH_Y,
- MDSS_MDP_SMP_CLIENT_DMA0_FETCH_CR,
- MDSS_MDP_SMP_CLIENT_DMA0_FETCH_CB,
- MDSS_MDP_SMP_CLIENT_DMA1_FETCH_Y,
- MDSS_MDP_SMP_CLIENT_DMA1_FETCH_CR,
- MDSS_MDP_SMP_CLIENT_DMA1_FETCH_CB,
- MDSS_MDP_SMP_CLIENT_RGB0_FETCH,
- MDSS_MDP_SMP_CLIENT_RGB1_FETCH,
- MDSS_MDP_SMP_CLIENT_RGB2_FETCH,
-};
+#define MDSS_MDP_SMP_MMB_BLOCKS 44
#define MDSS_MDP_LP_MISR_SEL 0x450
#define MDSS_MDP_LP_MISR_CTRL_MDP 0x454
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
index d0c1818..cb4c1f2 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
@@ -224,7 +224,6 @@
mdss_mdp_ctl_intf_event
(ctx->ctl, MDSS_EVENT_PANEL_CLK_CTRL, (void *)0);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
- complete(&ctx->stop_comp);
}
mutex_unlock(&ctx->clk_mtx);
}
@@ -255,6 +254,7 @@
if (ctx->rdptr_enabled == 0) {
mdss_mdp_irq_disable_nosync
(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctx->pp_num);
+ complete(&ctx->stop_comp);
schedule_work(&ctx->clk_work);
}
@@ -456,7 +456,7 @@
struct mdss_mdp_cmd_ctx *ctx;
unsigned long flags;
int need_wait = 0;
- int ret;
+ int ret = 0;
ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
if (!ctx) {
@@ -474,13 +474,15 @@
}
spin_unlock_irqrestore(&ctx->clk_lock, flags);
- if (need_wait) {
+ if (need_wait)
if (wait_for_completion_timeout(&ctx->stop_comp, STOP_TIMEOUT)
- <= 0) {
+ <= 0)
WARN(1, "stop cmd time out\n");
- mdss_mdp_cmd_clk_off(ctx);
- }
- }
+
+ if (cancel_work_sync(&ctx->clk_work))
+ pr_debug("no pending clk work\n");
+
+ mdss_mdp_cmd_clk_off(ctx);
ctx->panel_on = 0;
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index ab028e4..9b81633 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -573,7 +573,7 @@
mdss_mdp_ctl_write(ctl, 0, MDSS_MDP_LM_BORDER_COLOR);
off = MDSS_MDP_REG_INTF_OFFSET(ctl->intf_num);
- if (mdss_mdp_rev == MDSS_MDP_HW_REV_102)
+ if (mdss_mdp_rev >= MDSS_MDP_HW_REV_102)
mdss_v2_intf_off = 0xEC00;
MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_TIMING_ENGINE_EN -
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
index b7fe1bd..0a37573 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
@@ -219,7 +219,7 @@
if (!ctx)
return -ENODEV;
- if (ctx->initialized) /* already set */
+ if (ctx->initialized && !ctl->shared_lock) /* already set */
return 0;
pr_debug("wfd setup ctl=%d\n", ctl->num);
@@ -347,6 +347,9 @@
rc = wait_for_completion_interruptible_timeout(&ctx->wb_comp,
KOFF_TIMEOUT);
+ mdss_mdp_set_intr_callback(ctx->intr_type, ctx->intf_num,
+ NULL, NULL);
+
if (rc <= 0) {
rc = -ENODEV;
WARN(1, "writeback kickoff timed out (%d) ctl=%d\n",
@@ -389,6 +392,9 @@
return ret;
}
+ mdss_mdp_set_intr_callback(ctx->intr_type, ctx->intf_num,
+ mdss_mdp_writeback_intr_done, ctx);
+
ctx->callback_fnc = wb_args->callback_fnc;
ctx->callback_arg = wb_args->priv_data;
@@ -434,9 +440,6 @@
ctx->initialized = false;
init_completion(&ctx->wb_comp);
- mdss_mdp_set_intr_callback(ctx->intr_type, ctx->intf_num,
- mdss_mdp_writeback_intr_done, ctx);
-
if (ctx->type == MDSS_MDP_WRITEBACK_TYPE_ROTATOR)
ctl->prepare_fnc = mdss_mdp_writeback_prepare_rot;
else /* wfd or line mode */
@@ -447,3 +450,21 @@
return ret;
}
+
+int mdss_mdp_writeback_display_commit(struct mdss_mdp_ctl *ctl, void *arg)
+{
+ 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);
+ return -EINVAL;
+ }
+
+ if (ctl->mdata->mixer_switched) {
+ if (ctl->mixer_left)
+ ctl->mixer_left->params_changed++;
+ if (ctl->mixer_right)
+ ctl->mixer_right->params_changed++;
+ }
+
+ return mdss_mdp_display_commit(ctl, arg);
+}
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 780ff94..4032b91 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -494,6 +494,7 @@
pipe->overfetch_disable = fmt->is_yuv &&
!(pipe->flags & MDP_SOURCE_ROTATED_90);
+ req->id = pipe->ndx;
pipe->req_data = *req;
if (pipe->flags & MDP_OVERLAY_PP_CFG_EN) {
@@ -568,6 +569,10 @@
if (ret)
goto exit_fail;
+ if ((mixer->type == MDSS_MDP_MIXER_TYPE_WRITEBACK) &&
+ !mdp5_data->mdata->has_wfd_blk)
+ mdss_mdp_smp_release(pipe);
+
ret = mdss_mdp_smp_reserve(pipe);
if (ret) {
pr_debug("mdss_mdp_smp_reserve failed. ret=%d\n", ret);
@@ -576,7 +581,6 @@
pipe->params_changed++;
- req->id = pipe->ndx;
req->vert_deci = pipe->vert_deci;
*ppipe = pipe;
@@ -766,8 +770,12 @@
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
struct mdss_mdp_pipe *pipe, *next;
struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
+ struct mdss_mdp_ctl *tmp;
int ret;
+ if (ctl->shared_lock)
+ mutex_lock(ctl->shared_lock);
+
mutex_lock(&mdp5_data->ov_lock);
mutex_lock(&mfd->lock);
@@ -775,15 +783,47 @@
if (ret) {
mutex_unlock(&mfd->lock);
mutex_unlock(&mdp5_data->ov_lock);
+ if (ctl->shared_lock)
+ mutex_unlock(ctl->shared_lock);
return ret;
}
list_for_each_entry_safe(pipe, next, &mdp5_data->pipes_used,
used_list) {
struct mdss_mdp_data *buf;
+ /*
+ * When external is connected and no dedicated wfd is present,
+ * reprogram DMA pipe before kickoff to clear out any previous
+ * block mode configuration.
+ */
+ if ((pipe->type == MDSS_MDP_PIPE_TYPE_DMA) &&
+ (ctl->shared_lock && !ctl->mdata->has_wfd_blk)) {
+ if (ctl->mdata->mixer_switched) {
+ ret = mdss_mdp_overlay_pipe_setup(mfd,
+ &pipe->req_data, &pipe);
+ pr_debug("reseting DMA pipe for ctl=%d",
+ ctl->num);
+ }
+ if (ret) {
+ pr_err("can't reset DMA pipe ret=%d ctl=%d\n",
+ ret, ctl->num);
+ mutex_unlock(&mfd->lock);
+ goto commit_fail;
+ }
+
+ tmp = mdss_mdp_ctl_mixer_switch(ctl,
+ MDSS_MDP_WB_CTL_TYPE_LINE);
+ if (!tmp) {
+ mutex_unlock(&mfd->lock);
+ ret = -EINVAL;
+ goto commit_fail;
+ }
+ pipe->mixer = mdss_mdp_mixer_get(tmp,
+ MDSS_MDP_MIXER_MUX_DEFAULT);
+ }
if (pipe->back_buf.num_planes) {
buf = &pipe->back_buf;
- } else if (ctl->play_cnt == 0) {
+ } else if (ctl->play_cnt == 0 && pipe->front_buf.num_planes) {
pipe->params_changed++;
buf = &pipe->front_buf;
} else if (!pipe->params_changed) {
@@ -831,6 +871,8 @@
mdss_mdp_overlay_cleanup(mfd);
mutex_unlock(&mdp5_data->ov_lock);
+ if (ctl->shared_lock)
+ mutex_unlock(ctl->shared_lock);
return ret;
}
@@ -1199,7 +1241,7 @@
static void mdss_mdp_overlay_pan_display(struct msm_fb_data_type *mfd)
{
- struct mdss_mdp_data data;
+ struct mdss_mdp_data *buf;
struct mdss_mdp_pipe *pipe;
struct fb_info *fbi;
struct mdss_overlay_private *mdp5_data;
@@ -1229,8 +1271,6 @@
return;
}
- memset(&data, 0, sizeof(data));
-
bpp = fbi->var.bits_per_pixel / 8;
offset = fbi->var.xoffset * bpp +
fbi->var.yoffset * fbi->fix.line_length;
@@ -1247,18 +1287,6 @@
goto pan_display_error;
}
- if (is_mdss_iommu_attached()) {
- if (!mfd->iova) {
- pr_err("mfd iova is zero\n");
- goto pan_display_error;
- }
- data.p[0].addr = mfd->iova;
- } else
- data.p[0].addr = fbi->fix.smem_start;
-
- data.p[0].addr += offset;
- data.p[0].len = fbi->fix.smem_len - offset;
- data.num_planes = 1;
ret = mdss_mdp_overlay_get_fb_pipe(mfd, &pipe, MDSS_MDP_MIXER_MUX_LEFT);
if (ret) {
@@ -1270,13 +1298,23 @@
pr_err("unable to map base pipe\n");
goto pan_display_error;
}
- ret = mdss_mdp_pipe_queue_data(pipe, &data);
- mdss_mdp_pipe_unmap(pipe);
- if (ret) {
- pr_err("unable to queue data\n");
- goto pan_display_error;
+
+ buf = &pipe->back_buf;
+ if (is_mdss_iommu_attached()) {
+ if (!mfd->iova) {
+ pr_err("mfd iova is zero\n");
+ goto pan_display_error;
+ }
+ buf->p[0].addr = mfd->iova;
+ } else {
+ buf->p[0].addr = fbi->fix.smem_start;
}
+ buf->p[0].addr += offset;
+ buf->p[0].len = fbi->fix.smem_len - offset;
+ buf->num_planes = 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);
@@ -1288,12 +1326,8 @@
pr_err("unable to map right base pipe\n");
goto pan_display_error;
}
- ret = mdss_mdp_pipe_queue_data(pipe, &data);
+ pipe->back_buf = *buf;
mdss_mdp_pipe_unmap(pipe);
- if (ret) {
- pr_err("unable to queue right data\n");
- goto pan_display_error;
- }
}
mutex_unlock(&mdp5_data->ov_lock);
@@ -1567,6 +1601,13 @@
if (ret)
return ret;
+ /* Supprt only MDP register read/write and
+ exit_dcm in DCM state*/
+ if (mfd->dcm_state == DCM_ENTER &&
+ (mdp_pp.op != mdp_op_calib_buffer &&
+ mdp_pp.op != mdp_op_calib_dcm_state))
+ return -EPERM;
+
switch (mdp_pp.op) {
case mdp_op_pa_cfg:
ret = mdss_mdp_pa_config(mdp5_data->ctl,
@@ -1642,6 +1683,14 @@
case mdp_op_calib_mode:
ret = mdss_mdp_calib_mode(mfd, &mdp_pp.data.mdss_calib_cfg);
break;
+ case mdp_op_calib_buffer:
+ ret = mdss_mdp_calib_config_buffer(
+ (struct mdp_calib_config_buffer *)
+ &mdp_pp.data.calib_buffer, ©back);
+ break;
+ case mdp_op_calib_dcm_state:
+ ret = mdss_fb_dcm(mfd, mdp_pp.data.calib_dcm.dcm_state);
+ break;
default:
pr_err("Unsupported request to MDP_PP IOCTL. %d = op\n",
mdp_pp.op);
@@ -1718,6 +1767,10 @@
return -EPERM;
ret = mdss_misr_crc_set(mdata, &metadata->data.misr_request);
break;
+ case metadata_op_wb_format:
+ ret = mdss_mdp_wb_set_format(mfd,
+ metadata->data.mixer_cfg.writeback_format);
+ break;
default:
pr_warn("unsupported request to MDP META IOCTL\n");
ret = -EINVAL;
@@ -1759,6 +1812,9 @@
return -EPERM;
ret = mdss_misr_crc_get(mdata, &metadata->data.misr_request);
break;
+ case metadata_op_wb_format:
+ ret = mdss_mdp_wb_get_format(mfd, &metadata->data.mixer_cfg);
+ break;
default:
pr_warn("Unsupported request to MDP META IOCTL.\n");
ret = -EINVAL;
@@ -1820,6 +1876,7 @@
case MSMFB_OVERLAY_PLAY_ENABLE:
if (!copy_from_user(&val, argp, sizeof(val))) {
mdp5_data->overlay_play_enable = val;
+ ret = 0;
} else {
pr_err("OVERLAY_PLAY_ENABLE failed (%d)\n", ret);
ret = -EFAULT;
@@ -1939,7 +1996,8 @@
if (!mfd->panel_info->cont_splash_enabled) {
rc = mdss_mdp_overlay_start(mfd);
- if (!IS_ERR_VALUE(rc) && (mfd->panel_info->type != DTV_PANEL))
+ if (!IS_ERR_VALUE(rc) && (mfd->panel_info->type != DTV_PANEL) &&
+ (mfd->panel_info->type != WRITEBACK_PANEL))
rc = mdss_mdp_overlay_kickoff(mfd);
} else {
rc = mdss_mdp_ctl_setup(mdp5_data->ctl);
@@ -1962,6 +2020,8 @@
{
int rc;
struct mdss_overlay_private *mdp5_data;
+ struct mdss_mdp_mixer *mixer;
+
if (!mfd)
return -ENODEV;
@@ -1979,6 +2039,15 @@
return 0;
mdss_mdp_overlay_free_fb_pipe(mfd);
+
+ mixer = mdss_mdp_mixer_get(mdp5_data->ctl, MDSS_MDP_MIXER_MUX_LEFT);
+ if (mixer)
+ mixer->cursor_enabled = 0;
+
+ mixer = mdss_mdp_mixer_get(mdp5_data->ctl, MDSS_MDP_MIXER_MUX_RIGHT);
+ if (mixer)
+ mixer->cursor_enabled = 0;
+
if (!mfd->ref_cnt) {
mdss_mdp_overlay_release_all(mfd);
} else {
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index 3b91ced..3f75053 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -30,6 +30,7 @@
static DECLARE_BITMAP(mdss_mdp_smp_mmb_pool, MDSS_MDP_SMP_MMB_BLOCKS);
static int mdss_mdp_pipe_free(struct mdss_mdp_pipe *pipe);
+static int __mdss_mdp_pipe_smp_mmb_is_empty(unsigned long *smp);
static inline void mdss_mdp_pipe_write(struct mdss_mdp_pipe *pipe,
u32 reg, u32 val)
@@ -87,13 +88,18 @@
{
if (!bitmap_empty(smp, SMP_MB_CNT)) {
if (write)
- mdss_mdp_smp_mmb_set(MDSS_MDP_SMP_CLIENT_UNUSED, smp);
+ mdss_mdp_smp_mmb_set(0, smp);
bitmap_andnot(mdss_mdp_smp_mmb_pool, mdss_mdp_smp_mmb_pool,
smp, SMP_MB_CNT);
bitmap_zero(smp, SMP_MB_CNT);
}
}
+static int __mdss_mdp_pipe_smp_mmb_is_empty(unsigned long *smp)
+{
+ return bitmap_weight(smp, SMP_MB_CNT) == 0;
+}
+
static void mdss_mdp_smp_set_wm_levels(struct mdss_mdp_pipe *pipe, int mb_cnt)
{
u32 fetch_size, val, wm[3];
@@ -132,8 +138,8 @@
mutex_lock(&mdss_mdp_smp_lock);
for (i = 0; i < MAX_PLANES; i++) {
- mdss_mdp_smp_mmb_free(&pipe->smp_reserved[i], false);
- mdss_mdp_smp_mmb_free(&pipe->smp[i], true);
+ mdss_mdp_smp_mmb_free(pipe->smp_map[i].reserved, false);
+ mdss_mdp_smp_mmb_free(pipe->smp_map[i].allocated, true);
}
mutex_unlock(&mdss_mdp_smp_lock);
}
@@ -144,7 +150,7 @@
mutex_lock(&mdss_mdp_smp_lock);
for (i = 0; i < MAX_PLANES; i++)
- mdss_mdp_smp_mmb_free(&pipe->smp_reserved[i], false);
+ mdss_mdp_smp_mmb_free(pipe->smp_map[i].reserved, false);
mutex_unlock(&mdss_mdp_smp_lock);
}
@@ -156,6 +162,9 @@
int i;
int rc = 0, rot_mode = 0;
u32 nlines;
+ u16 width;
+
+ width = pipe->src.w >> pipe->horz_deci;
if (pipe->bwc_mode) {
rc = mdss_mdp_get_rau_strides(pipe->src.w, pipe->src.h,
@@ -166,11 +175,11 @@
ps.ystride[0], ps.ystride[1]);
} else if (mdata->has_decimation && pipe->src_fmt->is_yuv) {
ps.num_planes = 2;
- ps.ystride[0] = pipe->src.w >> pipe->horz_deci;
- ps.ystride[1] = pipe->src.h >> pipe->vert_deci;
+ ps.ystride[0] = width;
+ ps.ystride[1] = ps.ystride[0];
} else {
rc = mdss_mdp_get_plane_sizes(pipe->src_fmt->format,
- pipe->src.w, pipe->src.h, &ps, 0);
+ width, pipe->src.h, &ps, 0);
if (rc)
return rc;
@@ -178,7 +187,7 @@
rot_mode = 1;
else if (ps.num_planes == 1)
ps.ystride[0] = MAX_BPP *
- max(pipe->mixer->width, pipe->src.w);
+ max(pipe->mixer->width, width);
}
nlines = pipe->bwc_mode ? 1 : 2;
@@ -193,13 +202,17 @@
if (mdata->mdp_rev == MDSS_MDP_HW_REV_100)
num_blks = roundup_pow_of_two(num_blks);
+
+ if (mdata->smp_mb_per_pipe &&
+ (num_blks > mdata->smp_mb_per_pipe) &&
+ !(pipe->flags & MDP_FLIP_LR))
+ num_blks = mdata->smp_mb_per_pipe;
}
pr_debug("reserving %d mmb for pnum=%d plane=%d\n",
num_blks, pipe->num, i);
- reserved = mdss_mdp_smp_mmb_reserve(&pipe->smp[i],
- &pipe->smp_reserved[i], num_blks);
-
+ reserved = mdss_mdp_smp_mmb_reserve(pipe->smp_map[i].allocated,
+ pipe->smp_map[i].reserved, num_blks);
if (reserved < num_blks)
break;
}
@@ -207,7 +220,8 @@
if (reserved < num_blks) {
pr_debug("insufficient MMB blocks\n");
for (; i >= 0; i--)
- mdss_mdp_smp_mmb_free(&pipe->smp_reserved[i], false);
+ mdss_mdp_smp_mmb_free(pipe->smp_map[i].reserved,
+ false);
rc = -ENOMEM;
}
mutex_unlock(&mdss_mdp_smp_lock);
@@ -222,8 +236,12 @@
mutex_lock(&mdss_mdp_smp_lock);
for (i = 0; i < MAX_PLANES; i++) {
- mdss_mdp_smp_mmb_amend(&pipe->smp[i], &pipe->smp_reserved[i]);
- cnt += mdss_mdp_smp_mmb_set(pipe->ftch_id + i, &pipe->smp[i]);
+ if (__mdss_mdp_pipe_smp_mmb_is_empty(pipe->smp_map[i].reserved))
+ continue;
+ mdss_mdp_smp_mmb_amend(pipe->smp_map[i].allocated,
+ pipe->smp_map[i].reserved);
+ cnt += mdss_mdp_smp_mmb_set(pipe->ftch_id + i,
+ pipe->smp_map[i].allocated);
}
mdss_mdp_smp_set_wm_levels(pipe, cnt);
mutex_unlock(&mdss_mdp_smp_lock);
@@ -269,12 +287,13 @@
}
static struct mdss_mdp_pipe *mdss_mdp_pipe_init(struct mdss_mdp_mixer *mixer,
- u32 type)
+ u32 type, u32 off)
{
struct mdss_mdp_pipe *pipe;
struct mdss_data_type *mdata;
struct mdss_mdp_pipe *pipe_pool = NULL;
u32 npipes;
+ bool pipe_share = false;
u32 i;
if (!mixer || !mixer->ctl || !mixer->ctl->mdata)
@@ -296,6 +315,9 @@
case MDSS_MDP_PIPE_TYPE_DMA:
pipe_pool = mdata->dma_pipes;
npipes = mdata->ndma_pipes;
+ if (!mdata->has_wfd_blk &&
+ (mixer->type == MDSS_MDP_MIXER_TYPE_WRITEBACK))
+ pipe_share = true;
break;
default:
@@ -304,7 +326,7 @@
break;
}
- for (i = 0; i < npipes; i++) {
+ for (i = off; i < npipes; i++) {
pipe = pipe_pool + i;
if (atomic_cmpxchg(&pipe->ref_cnt, 0, 1) == 0) {
pipe->mixer = mixer;
@@ -317,6 +339,14 @@
pr_debug("type=%x pnum=%d\n", pipe->type, pipe->num);
mutex_init(&pipe->pp_res.hist.hist_mutex);
spin_lock_init(&pipe->pp_res.hist.hist_lock);
+ } else if (pipe_share) {
+ /*
+ * when there is no dedicated wfd blk, DMA pipe can be
+ * shared as long as its attached to a writeback mixer
+ */
+ pipe = mdata->dma_pipes + mixer->num;
+ mdss_mdp_pipe_map(pipe);
+ pr_debug("pipe sharing for pipe=%d\n", pipe->num);
} else {
pr_err("no %d type pipes available\n", type);
}
@@ -328,20 +358,20 @@
{
struct mdss_mdp_pipe *pipe = NULL;
struct mdss_data_type *mdata;
- u32 pnum;
mutex_lock(&mdss_mdp_sspp_lock);
mdata = mixer->ctl->mdata;
- pnum = mixer->num;
-
- if (atomic_cmpxchg(&((mdata->dma_pipes[pnum]).ref_cnt), 0, 1) == 0) {
- pipe = &mdata->dma_pipes[pnum];
- pipe->mixer = mixer;
-
+ pipe = mdss_mdp_pipe_init(mixer, MDSS_MDP_PIPE_TYPE_DMA, mixer->num);
+ if (!pipe) {
+ pr_err("DMA pipes not available for mixer=%d\n", mixer->num);
+ } else if (pipe != &mdata->dma_pipes[mixer->num]) {
+ pr_err("Requested DMA pnum=%d not available\n",
+ mdata->dma_pipes[mixer->num].num);
+ mdss_mdp_pipe_unmap(pipe);
+ pipe = NULL;
} else {
- pr_err("DMA pnum%d\t not available\n", pnum);
+ pipe->mixer = mixer;
}
-
mutex_unlock(&mdss_mdp_sspp_lock);
return pipe;
}
@@ -351,7 +381,7 @@
{
struct mdss_mdp_pipe *pipe;
mutex_lock(&mdss_mdp_sspp_lock);
- pipe = mdss_mdp_pipe_init(mixer, type);
+ pipe = mdss_mdp_pipe_init(mixer, type, 0);
mutex_unlock(&mdss_mdp_sspp_lock);
return pipe;
}
@@ -552,20 +582,15 @@
return 0;
}
-int mdss_mdp_pipe_addr_setup(struct mdss_data_type *mdata, u32 *offsets,
- u32 *ftch_id, u32 type, u32 num_base, u32 len)
+int mdss_mdp_pipe_addr_setup(struct mdss_data_type *mdata,
+ struct mdss_mdp_pipe *head, u32 *offsets, u32 *ftch_id, u32 type,
+ u32 num_base, u32 len)
{
- struct mdss_mdp_pipe *head;
u32 i;
- int rc = 0;
- head = devm_kzalloc(&mdata->pdev->dev, sizeof(struct mdss_mdp_pipe) *
- len, GFP_KERNEL);
-
- if (!head) {
- pr_err("unable to setup pipe type=%d :devm_kzalloc fail\n",
- type);
- return -ENOMEM;
+ if (!head || !mdata) {
+ pr_err("unable to setup pipe type=%d: invalid input\n", type);
+ return -EINVAL;
}
for (i = 0; i < len; i++) {
@@ -576,27 +601,7 @@
head[i].base = mdata->mdp_base + offsets[i];
}
- switch (type) {
-
- case MDSS_MDP_PIPE_TYPE_VIG:
- mdata->vig_pipes = head;
- break;
-
- case MDSS_MDP_PIPE_TYPE_RGB:
- mdata->rgb_pipes = head;
- break;
-
- case MDSS_MDP_PIPE_TYPE_DMA:
- mdata->dma_pipes = head;
- break;
-
- default:
- pr_err("Invalid pipe type=%d\n", type);
- rc = -EINVAL;
- break;
- }
-
- return rc;
+ return 0;
}
static int mdss_mdp_src_addr_setup(struct mdss_mdp_pipe *pipe,
@@ -658,13 +663,14 @@
{
int ret = 0;
u32 params_changed, opmode;
+ struct mdss_mdp_ctl *ctl;
if (!pipe) {
pr_err("pipe not setup properly for queue\n");
return -ENODEV;
}
- if (!pipe->mixer) {
+ if (!pipe->mixer || !pipe->mixer->ctl) {
pr_err("pipe mixer not setup properly for queue\n");
return -ENODEV;
}
@@ -673,8 +679,16 @@
pipe->mixer->num, pipe->play_cnt);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
-
- params_changed = pipe->params_changed;
+ ctl = pipe->mixer->ctl;
+ /*
+ * Reprogram the pipe when there is no dedicated wfd blk and
+ * virtual mixer is allocated for the DMA pipe during concurrent
+ * line and block mode operations
+ */
+ params_changed = (pipe->params_changed) ||
+ ((pipe->type == MDSS_MDP_PIPE_TYPE_DMA) &&
+ (pipe->mixer->type == MDSS_MDP_MIXER_TYPE_WRITEBACK)
+ && (ctl->mdata->mixer_switched));
if (src_data == NULL) {
mdss_mdp_pipe_solidfill_setup(pipe);
goto update_nobuf;
@@ -705,10 +719,9 @@
if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG)
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_VIG_OP_MODE,
opmode);
-
- mdss_mdp_smp_alloc(pipe);
}
+ mdss_mdp_smp_alloc(pipe);
ret = mdss_mdp_src_addr_setup(pipe, src_data);
if (ret) {
pr_err("addr setup error for pnum=%d\n", pipe->num);
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 4dd9dcb..6cedd98 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -3376,3 +3376,69 @@
mutex_unlock(&mdss_pp_mutex);
return 0;
}
+
+int mdss_mdp_calib_config_buffer(struct mdp_calib_config_buffer *cfg,
+ u32 *copyback)
+{
+ int ret = -1;
+ int counter = cfg->size / (sizeof(uint32_t) * 2);
+ uint32_t *buff = NULL, *buff_org = NULL;
+ void *ptr;
+ int i = 0;
+
+ buff_org = buff = kzalloc(cfg->size, GFP_KERNEL);
+ if (buff == NULL) {
+ pr_err("Allocation failed");
+ return ret;
+ }
+
+ if (copy_from_user(buff, cfg->buffer, cfg->size)) {
+ kfree(buff);
+ pr_err("Copy failed");
+ 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;
+ }
+
+ ptr = (void *)(((unsigned int) *buff) +
+ (mdss_res->mdp_base));
+ buff++;
+ *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++;
+ writel_relaxed(*buff, ptr);
+ buff++;
+ }
+ }
+
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+ kfree(buff_org);
+ return ret;
+}
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.c b/drivers/video/msm/mdss/mdss_mdp_rotator.c
index 8c45df8..fcd90e1 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.c
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.c
@@ -73,13 +73,16 @@
struct mdss_mdp_pipe *pipe = NULL;
mixer = mdss_mdp_wb_mixer_alloc(1);
- if (!mixer)
+ if (!mixer) {
+ pr_err("wb mixer alloc failed\n");
return NULL;
+ }
pipe = mdss_mdp_pipe_alloc_dma(mixer);
-
- if (!pipe)
+ if (!pipe) {
mdss_mdp_wb_mixer_destroy(mixer);
+ pr_err("dma pipe allocation failed\n");
+ }
return pipe;
}
@@ -96,12 +99,12 @@
ctl = rot_pipe->mixer->ctl;
mutex_lock(&rot->lock);
if (rot->busy) {
- pr_debug("waiting for rot=%d to complete\n", rot->pipe->num);
mdss_mdp_display_wait4comp(ctl);
rot->busy = false;
- mdss_mdp_smp_release(rot->pipe);
-
+ if (ctl->shared_lock)
+ mutex_unlock(ctl->shared_lock);
}
+ mdss_mdp_smp_release(rot->pipe);
mutex_unlock(&rot->lock);
return 0;
@@ -120,7 +123,7 @@
mutex_lock(&rot->lock);
rot->busy = true;
- ret = mdss_mdp_display_commit(ctl, &wb_args);
+ ret = mdss_mdp_writeback_display_commit(ctl, &wb_args);
if (ret) {
rot->busy = false;
pr_err("problem with kickoff rot pipe=%d", rot->pipe->num);
@@ -188,8 +191,19 @@
pr_debug("queue rotator pnum=%d\n", rot_pipe->num);
ctl = rot_pipe->mixer->ctl;
+ if (ctl->shared_lock)
+ mutex_lock(ctl->shared_lock);
- if (rot->params_changed) {
+ ctl = mdss_mdp_ctl_mixer_switch(ctl,
+ MDSS_MDP_WB_CTL_TYPE_BLOCK);
+ if (!ctl) {
+ ret = -EINVAL;
+ goto error;
+ } else {
+ rot->pipe->mixer = ctl->mixer_left;
+ }
+
+ if (rot->params_changed || ctl->mdata->mixer_switched) {
rot->params_changed = 0;
rot_pipe->flags = rot->flags;
rot_pipe->src_fmt = mdss_mdp_get_format_params(rot->format);
@@ -205,19 +219,23 @@
ret = mdss_mdp_smp_reserve(rot->pipe);
if (ret) {
pr_err("unable to mdss_mdp_smp_reserve rot data\n");
- return ret;
+ goto error;
}
ret = mdss_mdp_pipe_queue_data(rot->pipe, src_data);
if (ret) {
pr_err("unable to queue rot data\n");
mdss_mdp_smp_unreserve(rot->pipe);
- return ret;
+ goto error;
}
ret = mdss_mdp_rotator_kickoff(ctl, rot, dst_data);
return ret;
+error:
+ if (ctl->shared_lock)
+ mutex_unlock(ctl->shared_lock);
+ return ret;
}
int mdss_mdp_rotator_queue(struct mdss_mdp_rotator_session *rot,
@@ -342,6 +360,8 @@
static int mdss_mdp_rotator_finish(struct mdss_mdp_rotator_session *rot)
{
struct mdss_mdp_pipe *rot_pipe;
+ struct mdss_mdp_ctl *tmp;
+ int ret = 0;
if (!rot)
return -ENODEV;
@@ -359,11 +379,16 @@
memset(rot, 0, sizeof(*rot));
if (rot_pipe) {
struct mdss_mdp_mixer *mixer = rot_pipe->mixer;
- mdss_mdp_pipe_destroy(rot_pipe);
+ mdss_mdp_pipe_unmap(rot_pipe);
+ tmp = mdss_mdp_ctl_mixer_switch(mixer->ctl,
+ MDSS_MDP_WB_CTL_TYPE_BLOCK);
+ if (!tmp)
+ return -EINVAL;
+ else
+ mixer = tmp->mixer_left;
mdss_mdp_wb_mixer_destroy(mixer);
}
-
- return 0;
+ return ret;
}
int mdss_mdp_rotator_release(struct mdss_mdp_rotator_session *rot)
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index c7beb0e..b65d894 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -41,9 +41,11 @@
MDP_INTR_PING_PONG_0,
MDP_INTR_PING_PONG_1,
MDP_INTR_PING_PONG_2,
+ MDP_INTR_PING_PONG_3,
MDP_INTR_PING_PONG_0_RD_PTR,
MDP_INTR_PING_PONG_1_RD_PTR,
MDP_INTR_PING_PONG_2_RD_PTR,
+ MDP_INTR_PING_PONG_3_RD_PTR,
MDP_INTR_WB_0,
MDP_INTR_WB_1,
MDP_INTR_WB_2,
@@ -163,6 +165,9 @@
if (isr & MDSS_MDP_INTR_PING_PONG_2_DONE)
mdss_mdp_intr_done(MDP_INTR_PING_PONG_2);
+ if (isr & MDSS_MDP_INTR_PING_PONG_3_DONE)
+ mdss_mdp_intr_done(MDP_INTR_PING_PONG_3);
+
if (isr & MDSS_MDP_INTR_PING_PONG_0_RD_PTR)
mdss_mdp_intr_done(MDP_INTR_PING_PONG_0_RD_PTR);
@@ -172,6 +177,9 @@
if (isr & MDSS_MDP_INTR_PING_PONG_2_RD_PTR)
mdss_mdp_intr_done(MDP_INTR_PING_PONG_2_RD_PTR);
+ if (isr & MDSS_MDP_INTR_PING_PONG_3_RD_PTR)
+ mdss_mdp_intr_done(MDP_INTR_PING_PONG_3_RD_PTR);
+
if (isr & MDSS_MDP_INTR_INTF_0_VSYNC) {
mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_0);
mdss_misr_crc_collect(mdata, DISPLAY_MISR_EDP);
diff --git a/drivers/video/msm/mdss/mdss_mdp_wb.c b/drivers/video/msm/mdss/mdss_mdp_wb.c
index a9deef2..0c74137 100644
--- a/drivers/video/msm/mdss/mdss_mdp_wb.c
+++ b/drivers/video/msm/mdss/mdss_mdp_wb.c
@@ -527,7 +527,7 @@
goto kickoff_fail;
}
- ret = mdss_mdp_display_commit(ctl, &wb_args);
+ ret = mdss_mdp_writeback_display_commit(ctl, &wb_args);
if (ret) {
pr_err("error on commit ctl=%d\n", ctl->num);
goto kickoff_fail;
@@ -577,6 +577,86 @@
}
}
+int mdss_mdp_wb_get_format(struct msm_fb_data_type *mfd,
+ struct mdp_mixer_cfg *mixer_cfg)
+{
+ int dst_format;
+ struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
+
+ if (!ctl) {
+ pr_err("No panel data!\n");
+ return -EINVAL;
+ }
+
+ switch (ctl->dst_format) {
+ case MDP_RGB_888:
+ dst_format = WB_FORMAT_RGB_888;
+ break;
+ case MDP_RGB_565:
+ dst_format = WB_FORMAT_RGB_565;
+ break;
+ case MDP_XRGB_8888:
+ dst_format = WB_FORMAT_xRGB_8888;
+ break;
+ case MDP_ARGB_8888:
+ dst_format = WB_FORMAT_ARGB_8888;
+ break;
+ case MDP_BGRA_8888:
+ dst_format = WB_FORMAT_BGRA_8888;
+ break;
+ case MDP_BGRX_8888:
+ dst_format = WB_FORMAT_BGRX_8888;
+ break;
+ case MDP_Y_CBCR_H2V2_VENUS:
+ dst_format = WB_FORMAT_NV12;
+ break;
+ default:
+ return -EINVAL;
+ }
+ mixer_cfg->writeback_format = dst_format;
+ return 0;
+}
+
+int mdss_mdp_wb_set_format(struct msm_fb_data_type *mfd, int dst_format)
+{
+ struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
+
+ if (!ctl) {
+ pr_err("No panel data!\n");
+ return -EINVAL;
+ }
+
+ switch (dst_format) {
+ case WB_FORMAT_RGB_888:
+ ctl->dst_format = MDP_RGB_888;
+ break;
+ case WB_FORMAT_RGB_565:
+ ctl->dst_format = MDP_RGB_565;
+ break;
+ case WB_FORMAT_xRGB_8888:
+ ctl->dst_format = MDP_XRGB_8888;
+ break;
+ case WB_FORMAT_ARGB_8888:
+ ctl->dst_format = MDP_ARGB_8888;
+ break;
+ case WB_FORMAT_BGRA_8888:
+ ctl->dst_format = MDP_BGRA_8888;
+ break;
+ case WB_FORMAT_BGRX_8888:
+ ctl->dst_format = MDP_BGRX_8888;
+ break;
+ case WB_FORMAT_NV12:
+ ctl->dst_format = MDP_Y_CBCR_H2V2_VENUS;
+ break;
+ default:
+ pr_err("wfd format not supported\n");
+ return -EINVAL;
+ }
+
+ pr_debug("wfd format %d\n", ctl->dst_format);
+ return 0;
+}
+
int mdss_mdp_wb_ioctl_handler(struct msm_fb_data_type *mfd, u32 cmd,
void *arg)
{
diff --git a/drivers/video/msm/mdss/mhl_msc.c b/drivers/video/msm/mdss/mhl_msc.c
index 15811bb..d0f93cf 100644
--- a/drivers/video/msm/mdss/mhl_msc.c
+++ b/drivers/video/msm/mdss/mhl_msc.c
@@ -224,12 +224,16 @@
case MHL_WRITE_STAT:
if (req->offset == MHL_STATUS_REG_LINK_MODE) {
if (req->payload.data[0]
- & MHL_STATUS_PATH_ENABLED)
+ & MHL_STATUS_PATH_ENABLED) {
/* Enable TMDS output */
mhl_tmds_ctrl(mhl_ctrl, TMDS_ENABLE);
- else
+ if (mhl_ctrl->devcap_state == MHL_DEVCAP_ALL)
+ mhl_drive_hpd(mhl_ctrl, HPD_UP);
+ } else {
/* Disable TMDS output */
mhl_tmds_ctrl(mhl_ctrl, TMDS_DISABLE);
+ mhl_drive_hpd(mhl_ctrl, HPD_DOWN);
+ }
}
break;
case MHL_READ_DEVCAP:
@@ -245,8 +249,9 @@
pr_debug("%s: devcap pow bit unset\n",
__func__);
break;
- case DEVCAP_OFFSET_MHL_VERSION:
- case DEVCAP_OFFSET_INT_STAT_SIZE:
+ case DEVCAP_OFFSET_RESERVED:
+ mhl_tmds_ctrl(mhl_ctrl, TMDS_ENABLE);
+ mhl_drive_hpd(mhl_ctrl, HPD_UP);
break;
}
break;
diff --git a/drivers/video/msm/mdss/mhl_sii8334.c b/drivers/video/msm/mdss/mhl_sii8334.c
index 3f03725..add15a4 100644
--- a/drivers/video/msm/mdss/mhl_sii8334.c
+++ b/drivers/video/msm/mdss/mhl_sii8334.c
@@ -373,7 +373,7 @@
/* USB_HANDSHAKING FUNCTIONS */
static int mhl_sii_device_discovery(void *data, int id,
- void (*usb_notify_cb)(int online))
+ void (*usb_notify_cb)(void *, int), void *ctx)
{
int rc;
struct mhl_tx_ctrl *mhl_ctrl = data;
@@ -398,8 +398,10 @@
return -EINVAL;
}
- if (!mhl_ctrl->notify_usb_online)
+ if (!mhl_ctrl->notify_usb_online) {
mhl_ctrl->notify_usb_online = usb_notify_cb;
+ mhl_ctrl->notify_ctx = ctx;
+ }
if (!mhl_ctrl->disc_enabled) {
spin_lock_irqsave(&mhl_ctrl->lock, flags);
@@ -792,12 +794,10 @@
void mhl_tmds_ctrl(struct mhl_tx_ctrl *mhl_ctrl, uint8_t on)
{
struct i2c_client *client = mhl_ctrl->i2c_handle;
- if (on) {
+ if (on)
MHL_SII_REG_NAME_MOD(REG_TMDS_CCTRL, BIT4, BIT4);
- mhl_drive_hpd(mhl_ctrl, HPD_UP);
- } else {
+ else
MHL_SII_REG_NAME_MOD(REG_TMDS_CCTRL, BIT4, 0x00);
- }
}
void mhl_drive_hpd(struct mhl_tx_ctrl *mhl_ctrl, uint8_t to_state)
@@ -904,7 +904,7 @@
mhl_ctrl->mhl_mode = 1;
power_supply_changed(&mhl_ctrl->mhl_psy);
if (mhl_ctrl->notify_usb_online)
- mhl_ctrl->notify_usb_online(1);
+ mhl_ctrl->notify_usb_online(mhl_ctrl->notify_ctx, 1);
} else {
pr_debug("%s: non-mhl sink\n", __func__);
mhl_ctrl->mhl_mode = 0;
@@ -1004,7 +1004,7 @@
mhl_msm_disconnection(mhl_ctrl);
power_supply_changed(&mhl_ctrl->mhl_psy);
if (mhl_ctrl->notify_usb_online)
- mhl_ctrl->notify_usb_online(0);
+ mhl_ctrl->notify_usb_online(mhl_ctrl->notify_ctx, 0);
return 0;
}
@@ -1019,7 +1019,7 @@
mhl_msm_disconnection(mhl_ctrl);
power_supply_changed(&mhl_ctrl->mhl_psy);
if (mhl_ctrl->notify_usb_online)
- mhl_ctrl->notify_usb_online(0);
+ mhl_ctrl->notify_usb_online(mhl_ctrl->notify_ctx, 0);
return 0;
}
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index aab67df..7b89eff 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -209,54 +209,136 @@
clk_disable_unprepare(ctrl_pdata->ahb_clk);
}
-void mdss_dsi_prepare_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+static int mdss_dsi_clk_prepare(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
- clk_prepare(ctrl_pdata->byte_clk);
- clk_prepare(ctrl_pdata->esc_clk);
- clk_prepare(ctrl_pdata->pixel_clk);
-}
+ int rc = 0;
-void mdss_dsi_unprepare_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
-{
- clk_unprepare(ctrl_pdata->esc_clk);
- clk_unprepare(ctrl_pdata->pixel_clk);
+ rc = clk_prepare(ctrl_pdata->esc_clk);
+ if (rc) {
+ pr_err("%s: Failed to prepare dsi esc clk\n", __func__);
+ goto esc_clk_err;
+ }
+
+ rc = clk_prepare(ctrl_pdata->byte_clk);
+ if (rc) {
+ pr_err("%s: Failed to prepare dsi byte clk\n", __func__);
+ goto byte_clk_err;
+ }
+
+ rc = clk_prepare(ctrl_pdata->pixel_clk);
+ if (rc) {
+ pr_err("%s: Failed to prepare dsi pixel clk\n", __func__);
+ goto pixel_clk_err;
+ }
+
+ return rc;
+
+pixel_clk_err:
clk_unprepare(ctrl_pdata->byte_clk);
+byte_clk_err:
+ clk_unprepare(ctrl_pdata->esc_clk);
+esc_clk_err:
+ return rc;
}
-void mdss_dsi_clk_enable(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+static void mdss_dsi_clk_unprepare(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
- u32 esc_clk_rate = 19200000;
-
if (!ctrl_pdata) {
pr_err("%s: Invalid input data\n", __func__);
return;
}
- if (ctrl_pdata->mdss_dsi_clk_on) {
- pr_info("%s: mdss_dsi_clks already ON\n", __func__);
- return;
- }
-
- pr_debug("%s: Setting clock rates: pclk=%d, byteclk=%d escclk=%d\n",
- __func__, ctrl_pdata->pclk_rate,
- ctrl_pdata->byte_clk_rate, esc_clk_rate);
- if (clk_set_rate(ctrl_pdata->esc_clk, esc_clk_rate) < 0)
- pr_err("%s: dsi_esc_clk - clk_set_rate failed\n", __func__);
-
- if (clk_set_rate(ctrl_pdata->byte_clk, ctrl_pdata->byte_clk_rate) < 0)
- pr_err("%s: dsi_byte_clk - clk_set_rate failed\n", __func__);
-
- if (clk_set_rate(ctrl_pdata->pixel_clk, ctrl_pdata->pclk_rate) < 0)
- pr_err("%s: dsi_pixel_clk - clk_set_rate failed\n", __func__);
-
- clk_enable(ctrl_pdata->esc_clk);
- clk_enable(ctrl_pdata->byte_clk);
- clk_enable(ctrl_pdata->pixel_clk);
-
- ctrl_pdata->mdss_dsi_clk_on = 1;
+ clk_unprepare(ctrl_pdata->pixel_clk);
+ clk_unprepare(ctrl_pdata->byte_clk);
+ clk_unprepare(ctrl_pdata->esc_clk);
}
-void mdss_dsi_clk_disable(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+static int mdss_dsi_clk_set_rate(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+{
+ u32 esc_clk_rate = 19200000;
+ int rc = 0;
+
+ if (!ctrl_pdata) {
+ pr_err("%s: Invalid input data\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!ctrl_pdata->panel_data.panel_info.cont_splash_enabled) {
+ pr_debug("%s: Set clk rates: pclk=%d, byteclk=%d escclk=%d\n",
+ __func__, ctrl_pdata->pclk_rate,
+ ctrl_pdata->byte_clk_rate, esc_clk_rate);
+ rc = clk_set_rate(ctrl_pdata->esc_clk, esc_clk_rate);
+ if (rc) {
+ pr_err("%s: dsi_esc_clk - clk_set_rate failed\n",
+ __func__);
+ goto error;
+ }
+
+ rc = clk_set_rate(ctrl_pdata->byte_clk,
+ ctrl_pdata->byte_clk_rate);
+ if (rc) {
+ pr_err("%s: dsi_byte_clk - clk_set_rate failed\n",
+ __func__);
+ goto error;
+ }
+
+ rc = clk_set_rate(ctrl_pdata->pixel_clk, ctrl_pdata->pclk_rate);
+ if (rc) {
+ pr_err("%s: dsi_pixel_clk - clk_set_rate failed\n",
+ __func__);
+ goto error;
+ }
+ }
+
+error:
+ return rc;
+}
+
+static int mdss_dsi_clk_enable(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+{
+ int rc = 0;
+
+ if (!ctrl_pdata) {
+ pr_err("%s: Invalid input data\n", __func__);
+ return -EINVAL;
+ }
+
+ if (ctrl_pdata->mdss_dsi_clk_on) {
+ pr_info("%s: mdss_dsi_clks already ON\n", __func__);
+ return 0;
+ }
+
+ rc = clk_enable(ctrl_pdata->esc_clk);
+ if (rc) {
+ pr_err("%s: Failed to enable dsi esc clk\n", __func__);
+ goto esc_clk_err;
+ }
+
+ rc = clk_enable(ctrl_pdata->byte_clk);
+ if (rc) {
+ pr_err("%s: Failed to enable dsi byte clk\n", __func__);
+ goto byte_clk_err;
+ }
+
+ rc = clk_enable(ctrl_pdata->pixel_clk);
+ if (rc) {
+ pr_err("%s: Failed to enable dsi pixel clk\n", __func__);
+ goto pixel_clk_err;
+ }
+
+ ctrl_pdata->mdss_dsi_clk_on = 1;
+
+ return rc;
+
+pixel_clk_err:
+ clk_disable(ctrl_pdata->byte_clk);
+byte_clk_err:
+ clk_disable(ctrl_pdata->esc_clk);
+esc_clk_err:
+ return rc;
+}
+
+static void mdss_dsi_clk_disable(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
if (!ctrl_pdata) {
pr_err("%s: Invalid input data\n", __func__);
@@ -268,13 +350,71 @@
return;
}
+ clk_disable(ctrl_pdata->esc_clk);
clk_disable(ctrl_pdata->pixel_clk);
clk_disable(ctrl_pdata->byte_clk);
- clk_disable(ctrl_pdata->esc_clk);
ctrl_pdata->mdss_dsi_clk_on = 0;
}
+int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable)
+{
+ int rc = 0;
+
+ mutex_lock(&ctrl->mutex);
+ if (enable) {
+ if (ctrl->clk_cnt == 0) {
+ rc = mdss_dsi_enable_bus_clocks(ctrl);
+ if (rc) {
+ pr_err("%s: failed to enable bus clks. rc=%d\n",
+ __func__, rc);
+ goto error;
+ }
+
+ rc = mdss_dsi_clk_set_rate(ctrl);
+ if (rc) {
+ pr_err("%s: failed to set clk rates. rc=%d\n",
+ __func__, rc);
+ mdss_dsi_disable_bus_clocks(ctrl);
+ goto error;
+ }
+
+ rc = mdss_dsi_clk_prepare(ctrl);
+ if (rc) {
+ pr_err("%s: failed to prepare clks. rc=%d\n",
+ __func__, rc);
+ mdss_dsi_disable_bus_clocks(ctrl);
+ goto error;
+ }
+
+ rc = mdss_dsi_clk_enable(ctrl);
+ if (rc) {
+ pr_err("%s: failed to enable clks. rc=%d\n",
+ __func__, rc);
+ mdss_dsi_clk_unprepare(ctrl);
+ mdss_dsi_disable_bus_clocks(ctrl);
+ goto error;
+ }
+ }
+ ctrl->clk_cnt++;
+ } else {
+ if (ctrl->clk_cnt) {
+ ctrl->clk_cnt--;
+ if (ctrl->clk_cnt == 0) {
+ mdss_dsi_clk_disable(ctrl);
+ mdss_dsi_clk_unprepare(ctrl);
+ mdss_dsi_disable_bus_clocks(ctrl);
+ }
+ }
+ }
+ pr_debug("%s: ctrl ndx=%d enabled=%d clk_cnt=%d\n",
+ __func__, ctrl->ndx, enable, ctrl->clk_cnt);
+
+error:
+ mutex_unlock(&ctrl->mutex);
+ return rc;
+}
+
void mdss_dsi_phy_sw_reset(unsigned char *ctrl_base)
{
/* start phy sw reset */
@@ -450,30 +590,84 @@
}
-/* EDP phy configuration settings */
-void mdss_edp_phy_sw_reset(unsigned char *edp_base)
+void mdss_edp_timing_engine_ctrl(unsigned char *edp_base, int enable)
{
- /* phy sw reset */
- edp_write(edp_base + 0x74, 0x100); /* EDP_PHY_CTRL */
- wmb();
- usleep(1);
- edp_write(edp_base + 0x74, 0x000); /* EDP_PHY_CTRL */
- wmb();
- usleep(1);
-
- /* phy PLL sw reset */
- edp_write(edp_base + 0x74, 0x001); /* EDP_PHY_CTRL */
- wmb();
- usleep(1);
- edp_write(edp_base + 0x74, 0x000); /* EDP_PHY_CTRL */
- wmb();
- usleep(1);
+ /* should eb last reg to program */
+ edp_write(edp_base + 0x94, enable); /* EDP_TIMING_ENGINE_EN */
}
-void mdss_edp_hw_powerup(unsigned char *edp_base, int enable)
+void mdss_edp_mainlink_ctrl(unsigned char *edp_base, int enable)
{
- int ret = 0;
+ 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);
@@ -481,9 +675,6 @@
edp_write(edp_base + 0x528, 0x1);
/* EDP_PHY_PLL_UNIPHY_PLL_GLB_CFG */
edp_write(edp_base + 0x620, 0xf);
- /* EDP_AUX_CTRL */
- ret = edp_read(edp_base + 0x300);
- edp_write(edp_base + 0x300, ret | 0x1);
} else {
/* EDP_PHY_EDPPHY_GLB_PD_CTL */
edp_write(edp_base + 0x52c, 0xc0);
@@ -520,7 +711,7 @@
edp_write(edp_base + 0x620, 0x7);
edp_write(edp_base + 0x620, 0xf);
- } else if (rate == 138500000) {
+ } 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 */
@@ -551,7 +742,7 @@
edp_write(edp_base + 0x620, 0x7); /* UNIPHY_PLL_GLB_CFG */
edp_write(edp_base + 0x620, 0xf); /* UNIPHY_PLL_GLB_CFG */
} else {
- pr_err("%s: Unknown configuration rate\n", __func__);
+ pr_err("%s: rate=%d is NOT supported\n", __func__, rate);
}
}
@@ -591,22 +782,20 @@
}
}
-void mdss_edp_enable_lane_bist(unsigned char *edp_base, int lane, int enable)
+void mdss_edp_lane_power_ctrl(unsigned char *edp_base, int max_lane, int up)
{
- unsigned char *addr_ln_bist_cfg, *addr_ln_pd_ctrl;
+ int i, off;
+ u32 data;
+
+ if (up)
+ data = 0; /* power up */
+ else
+ data = 0x7; /* power down */
/* EDP_PHY_EDPPHY_LNn_PD_CTL */
- addr_ln_pd_ctrl = edp_base + 0x404 + (0x40 * lane);
- /* EDP_PHY_EDPPHY_LNn_BIST_CFG0 */
- addr_ln_bist_cfg = edp_base + 0x408 + (0x40 * lane);
-
- if (enable) {
- edp_write(addr_ln_pd_ctrl, 0x0);
- edp_write(addr_ln_bist_cfg, 0x10);
-
- } else {
- edp_write(addr_ln_pd_ctrl, 0xf);
- edp_write(addr_ln_bist_cfg, 0x10);
+ for (i = 0; i < max_lane; i++) {
+ off = 0x40 * i;
+ edp_write(edp_base + 0x404 + off , data);
}
}
@@ -661,12 +850,47 @@
return -EPERM;
}
-
-void mdss_edp_clk_enable(struct mdss_edp_drv_pdata *edp_drv)
+int mdss_edp_aux_clk_enable(struct mdss_edp_drv_pdata *edp_drv)
{
+ int ret;
+
+ if (clk_set_rate(edp_drv->aux_clk, 19200000) < 0)
+ pr_err("%s: aux_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__);
+ goto c2;
+ }
+
+ ret = clk_enable(edp_drv->ahb_clk);
+ if (ret) {
+ pr_err("%s: Failed to enable ahb clk\n", __func__);
+ goto c1;
+ }
+
+ return 0;
+c1:
+ clk_disable(edp_drv->aux_clk);
+c2:
+ return ret;
+
+}
+
+void mdss_edp_aux_clk_disable(struct mdss_edp_drv_pdata *edp_drv)
+{
+ clk_disable(edp_drv->aux_clk);
+ clk_disable(edp_drv->ahb_clk);
+}
+
+int mdss_edp_clk_enable(struct mdss_edp_drv_pdata *edp_drv)
+{
+ int ret;
+
if (edp_drv->clk_on) {
pr_info("%s: edp clks are already ON\n", __func__);
- return;
+ return 0;
}
if (clk_set_rate(edp_drv->aux_clk, 19200000) < 0)
@@ -681,12 +905,39 @@
pr_err("%s: link_clk - clk_set_rate failed\n",
__func__);
- clk_enable(edp_drv->aux_clk);
- clk_enable(edp_drv->pixel_clk);
- clk_enable(edp_drv->ahb_clk);
- clk_enable(edp_drv->link_clk);
+ ret = clk_enable(edp_drv->aux_clk);
+ if (ret) {
+ pr_err("%s: Failed to enable aux clk\n", __func__);
+ goto c4;
+ }
+ ret = clk_enable(edp_drv->pixel_clk);
+ if (ret) {
+ pr_err("%s: Failed to enable pixel clk\n", __func__);
+ goto c3;
+ }
+ ret = clk_enable(edp_drv->ahb_clk);
+ if (ret) {
+ pr_err("%s: Failed to enable ahb clk\n", __func__);
+ goto c2;
+ }
+ ret = clk_enable(edp_drv->link_clk);
+ if (ret) {
+ pr_err("%s: Failed to enable link clk\n", __func__);
+ goto c1;
+ }
edp_drv->clk_on = 1;
+
+ return 0;
+
+c1:
+ clk_disable(edp_drv->ahb_clk);
+c2:
+ clk_disable(edp_drv->pixel_clk);
+c3:
+ clk_disable(edp_drv->aux_clk);
+c4:
+ return ret;
}
void mdss_edp_clk_disable(struct mdss_edp_drv_pdata *edp_drv)
@@ -704,12 +955,69 @@
edp_drv->clk_on = 0;
}
-void mdss_edp_prepare_clocks(struct mdss_edp_drv_pdata *edp_drv)
+int mdss_edp_prepare_aux_clocks(struct mdss_edp_drv_pdata *edp_drv)
{
- clk_prepare(edp_drv->aux_clk);
- clk_prepare(edp_drv->pixel_clk);
- clk_prepare(edp_drv->ahb_clk);
- clk_prepare(edp_drv->link_clk);
+ 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;
+ }
+
+ return 0;
+c1:
+ clk_unprepare(edp_drv->aux_clk);
+c2:
+ return ret;
+
+}
+
+void mdss_edp_unprepare_aux_clocks(struct mdss_edp_drv_pdata *edp_drv)
+{
+ clk_unprepare(edp_drv->aux_clk);
+ clk_unprepare(edp_drv->ahb_clk);
+}
+
+int mdss_edp_prepare_clocks(struct mdss_edp_drv_pdata *edp_drv)
+{
+ int ret;
+
+ ret = clk_prepare(edp_drv->aux_clk);
+ if (ret) {
+ pr_err("%s: Failed to prepare aux clk\n", __func__);
+ goto c4;
+ }
+ 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);
+ if (ret) {
+ pr_err("%s: Failed to prepare link clk\n", __func__);
+ goto c1;
+ }
+
+ return 0;
+c1:
+ clk_unprepare(edp_drv->ahb_clk);
+c2:
+ clk_unprepare(edp_drv->pixel_clk);
+c3:
+ clk_unprepare(edp_drv->aux_clk);
+c4:
+ return ret;
}
void mdss_edp_unprepare_clocks(struct mdss_edp_drv_pdata *edp_drv)
@@ -768,14 +1076,29 @@
mdss_edp_enable_pixel_clk(edp_base, mmss_cc_base, 0);
}
-void mdss_edp_phy_misc_cfg(unsigned char *edp_base)
+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);
+ 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);
- /* EDP_MISC1_MISC0 */
- edp_write(edp_base + 0x2c, 0x1);
}
diff --git a/include/linux/android_pmem.h b/include/linux/android_pmem.h
index cfca491..f338d15 100644
--- a/include/linux/android_pmem.h
+++ b/include/linux/android_pmem.h
@@ -151,10 +151,6 @@
* indicates that this region should be mapped/unmaped as needed
*/
int map_on_demand;
- /*
- * indicates this pmem may be reused via fmem
- */
- int reusable;
};
int pmem_setup(struct android_pmem_platform_data *pdata,
diff --git a/include/linux/mfd/pm8xxx/batterydata-lib.h b/include/linux/batterydata-lib.h
similarity index 93%
rename from include/linux/mfd/pm8xxx/batterydata-lib.h
rename to include/linux/batterydata-lib.h
index 644eede..fe2d86f 100644
--- a/include/linux/mfd/pm8xxx/batterydata-lib.h
+++ b/include/linux/batterydata-lib.h
@@ -10,8 +10,8 @@
* GNU General Public License for more details.
*/
-#ifndef __PM8XXX_BMS_BATTERYDATA_H
-#define __PM8XXX_BMS_BATTERYDATA_H
+#ifndef __BMS_BATTERYDATA_H
+#define __BMS_BATTERYDATA_H
#include <linux/errno.h>
@@ -95,6 +95,11 @@
* battery capacitance
* @flat_ocv_threshold_uv: the voltage where the battery's discharge curve
* starts flattening out.
+ * @max_voltage_uv: max voltage of the battery
+ * @cutoff_uv: cutoff voltage of the battery
+ * @iterm_ua: termination current of the battery when charging
+ * to 100%
+ * @batt_id_kohm: battery id resistor value
*/
struct bms_battery_data {
@@ -108,6 +113,10 @@
int delta_rbatt_mohm;
int rbatt_capacitive_mohm;
int flat_ocv_threshold_uv;
+ int max_voltage_uv;
+ int cutoff_uv;
+ int iterm_ua;
+ int batt_id_kohm;
};
#if defined(CONFIG_PM8921_BMS) || \
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index 2b4542a..130d0fd 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -152,6 +152,7 @@
__REQ_MIXED_MERGE, /* merge of different types, fail separately */
__REQ_SANITIZE, /* sanitize */
__REQ_URGENT, /* urgent request */
+ __REQ_PM, /* runtime pm request */
__REQ_NR_BITS, /* stops here */
};
@@ -196,5 +197,6 @@
#define REQ_IO_STAT (1 << __REQ_IO_STAT)
#define REQ_MIXED_MERGE (1 << __REQ_MIXED_MERGE)
#define REQ_SECURE (1 << __REQ_SECURE)
+#define REQ_PM (1 << __REQ_PM)
#endif /* __LINUX_BLK_TYPES_H */
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 6502841..651a0fc 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -340,6 +340,12 @@
*/
struct kobject kobj;
+#ifdef CONFIG_PM_RUNTIME
+ struct device *dev;
+ int rpm_status;
+ unsigned int nr_pending;
+#endif
+
/*
* queue settings
*/
@@ -883,6 +889,27 @@
extern void blk_put_queue(struct request_queue *);
/*
+ * block layer runtime pm functions
+ */
+#ifdef CONFIG_PM_RUNTIME
+extern void blk_pm_runtime_init(struct request_queue *q, struct device *dev);
+extern int blk_pre_runtime_suspend(struct request_queue *q);
+extern void blk_post_runtime_suspend(struct request_queue *q, int err);
+extern void blk_pre_runtime_resume(struct request_queue *q);
+extern void blk_post_runtime_resume(struct request_queue *q, int err);
+#else
+static inline void blk_pm_runtime_init(struct request_queue *q,
+ struct device *dev) {}
+static inline int blk_pre_runtime_suspend(struct request_queue *q)
+{
+ return -ENOSYS;
+}
+static inline void blk_post_runtime_suspend(struct request_queue *q, int err) {}
+static inline void blk_pre_runtime_resume(struct request_queue *q) {}
+static inline void blk_post_runtime_resume(struct request_queue *q, int err) {}
+#endif
+
+/*
* blk_plug permits building a queue of related requests by holding the I/O
* fragments for a short period. This allows merging of sequential requests
* into single larger request. As the requests are moved from a per-task list to
diff --git a/include/linux/bug.h b/include/linux/bug.h
index 72961c3..cd141a4 100644
--- a/include/linux/bug.h
+++ b/include/linux/bug.h
@@ -96,4 +96,10 @@
}
#endif /* CONFIG_GENERIC_BUG */
+
+#ifdef CONFIG_PANIC_ON_DATA_CORRUPTION
+#define PANIC_CORRUPTION 1
+#else
+#define PANIC_CORRUPTION 0
+#endif /* CONFIG_PANIC_ON_DATA_CORRUPTION */
#endif /* _LINUX_BUG_H */
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
index cfc690e..5b69884 100644
--- a/include/linux/coresight.h
+++ b/include/linux/coresight.h
@@ -39,8 +39,8 @@
enum coresight_clk_rate {
CORESIGHT_CLK_RATE_OFF,
- CORESIGHT_CLK_RATE_TRACE,
- CORESIGHT_CLK_RATE_HSTRACE,
+ CORESIGHT_CLK_RATE_TRACE = 1000,
+ CORESIGHT_CLK_RATE_HSTRACE = 2000,
};
enum coresight_dev_type {
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index 384f37a..0739ece 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -27,7 +27,6 @@
#define UART_MODE 4
#define SOCKET_MODE 5
#define CALLBACK_MODE 6
-#define MEMORY_DEVICE_MODE_NRT 7
/* different values that go in for diag_data_type */
#define DATA_TYPE_EVENT 0
#define DATA_TYPE_F3 1
@@ -50,6 +49,8 @@
#define DIAG_IOCTL_DCI_CLEAR_LOGS 28
#define DIAG_IOCTL_DCI_CLEAR_EVENTS 29
#define DIAG_IOCTL_REMOTE_DEV 32
+#define DIAG_IOCTL_VOTE_REAL_TIME 33
+#define DIAG_IOCTL_GET_REAL_TIME 34
/* PC Tools IDs */
#define APQ8060_TOOLS_ID 4062
@@ -118,10 +119,10 @@
/* This needs to be modified manually now, when we add
a new RANGE of SSIDs to the msg_mask_tbl */
#define MSG_MASK_TBL_CNT 24
-#define EVENT_LAST_ID 0x09BE
+#define EVENT_LAST_ID 0x09CB
#define MSG_SSID_0 0
-#define MSG_SSID_0_LAST 96
+#define MSG_SSID_0_LAST 97
#define MSG_SSID_1 500
#define MSG_SSID_1_LAST 506
#define MSG_SSID_2 1000
@@ -135,7 +136,7 @@
#define MSG_SSID_6 4500
#define MSG_SSID_6_LAST 4526
#define MSG_SSID_7 4600
-#define MSG_SSID_7_LAST 4613
+#define MSG_SSID_7_LAST 4614
#define MSG_SSID_8 5000
#define MSG_SSID_8_LAST 5030
#define MSG_SSID_9 5500
@@ -270,7 +271,7 @@
MSG_LVL_LOW,
MSG_LVL_LOW,
MSG_LVL_LOW,
- MSG_LVL_HIGH,
+ MSG_LVL_HIGH | MSG_MASK_21,
MSG_LVL_HIGH,
MSG_LVL_LOW,
MSG_LVL_LOW,
@@ -290,6 +291,7 @@
MSG_LVL_LOW,
MSG_LVL_LOW,
MSG_LVL_LOW|MSG_LVL_MED|MSG_LVL_HIGH|MSG_LVL_ERROR|MSG_LVL_FATAL,
+ MSG_LVL_MED,
};
static const uint32_t msg_bld_masks_1[] = {
@@ -402,6 +404,7 @@
MSG_LVL_MED,
MSG_LVL_MED,
MSG_LVL_LOW,
+ MSG_LVL_LOW,
MSG_LVL_LOW
};
@@ -725,7 +728,7 @@
/* LOG CODES */
#define LOG_0 0x0
-#define LOG_1 0x1807
+#define LOG_1 0x1808
#define LOG_2 0x0
#define LOG_3 0x0
#define LOG_4 0x4910
diff --git a/include/linux/dvb/dmx.h b/include/linux/dvb/dmx.h
index bd954ee..dd675f3 100644
--- a/include/linux/dvb/dmx.h
+++ b/include/linux/dvb/dmx.h
@@ -531,6 +531,9 @@
/* Indicates whether TS insertion is supported */
#define DMX_CAP_TS_INSERTION 0x20
+/* Indicates whether playback from secured input is supported */
+#define DMX_CAP_SECURED_INPUT_PLAYBACK 0x40
+
/* Number of decoders demux can output data to */
int num_decoders;
@@ -570,6 +573,12 @@
/* Max bitrate from single memory input. Mbit/sec */
int memory_input_max_bitrate;
+ /* Max number of supported cipher operations per PID */
+ int num_cipher_ops;
+
+ /* Max possible value of STC reported by demux, in 27MHz */
+ __u64 max_stc;
+
struct dmx_buffer_requirement section;
/* For PES not sent to decoder */
@@ -657,6 +666,15 @@
struct dmx_buffer {
unsigned int size;
int handle;
+
+ /*
+ * The following indication is relevant only when setting
+ * DVR input buffer. It indicates whether the input buffer
+ * being set is secured one or not. Secured (locked) buffers
+ * are required for playback from secured input. In such case
+ * write() syscall is not allowed.
+ */
+ int is_protected;
};
struct dmx_decoder_buffers {
@@ -681,16 +699,41 @@
struct dmx_secure_mode {
/*
- * Specifies whether secure mode should be set or not for the filter's
- * pid. Note that DMX_OUT_TSDEMUX_TAP filters can have more than 1 pid
+ * Specifies whether the filter is secure or not.
+ * Filter should be set as secured if the filter's data *may* include
+ * encrypted data that would require decryption configured through
+ * DMX_SET_CIPHER ioctl. The setting may be done while
+ * filter is in idle state only.
*/
int is_secured;
+};
- /* PID to associate with key ladder id */
+struct dmx_cipher_operation {
+ /* Indication whether the operation is encryption or decryption */
+ int encrypt;
+
+ /* The ID of the key used for decryption or encryption */
+ __u32 key_ladder_id;
+};
+
+#define DMX_MAX_CIPHER_OPERATIONS_COUNT 5
+struct dmx_cipher_operations {
+ /*
+ * The PID to perform the cipher operations on.
+ * In case of recording filter, multiple PIDs may exist in the same
+ * filter through DMX_ADD_PID ioctl, each may have different
+ * cipher operations.
+ */
__u16 pid;
- /* key ladder information to associate with the specified pid */
- __u32 key_ladder_id;
+ /* Total number of operations */
+ __u8 operations_count;
+
+ /*
+ * Cipher operation to perform on the given PID.
+ * The operations are performed in the order they are given.
+ */
+ struct dmx_cipher_operation operations[DMX_MAX_CIPHER_OPERATIONS_COUNT];
};
struct dmx_events_mask {
@@ -822,5 +865,7 @@
#define DMX_SET_TS_INSERTION _IOW('o', 70, struct dmx_set_ts_insertion)
#define DMX_ABORT_TS_INSERTION _IOW('o', 71, struct dmx_abort_ts_insertion)
#define DMX_GET_SCRAMBLING_BITS _IOWR('o', 72, struct dmx_scrambling_bits)
+#define DMX_SET_CIPHER _IOW('o', 73, struct dmx_cipher_operations)
+
#endif /*_DVBDMX_H_*/
diff --git a/include/linux/epm_adc.h b/include/linux/epm_adc.h
index 4fa41b5..f94eb94 100644
--- a/include/linux/epm_adc.h
+++ b/include/linux/epm_adc.h
@@ -97,6 +97,23 @@
uint32_t gain;
};
+struct epm_marker_level {
+ uint8_t level;
+};
+
+struct epm_gpio_buffer_request {
+ uint8_t cmd;
+ uint8_t bitmask_monitor_pin;
+ uint8_t status;
+};
+
+struct epm_get_gpio_buffer_resp {
+ uint8_t cmd;
+ uint8_t status;
+ uint8_t bitmask_monitor_pin;
+ uint32_t timestamp;
+};
+
#ifdef __KERNEL__
struct epm_adc_platform_data {
struct epm_chan_properties *channel;
@@ -121,7 +138,19 @@
#define EPM_ADC_DEINIT _IOR(EPM_ADC_IOCTL_CODE, 3, \
uint32_t)
-#define EPM_PSOC_ADC_INIT _IOR(EPM_ADC_IOCTL_CODE, 4, \
+#define EPM_MARKER1_REQUEST _IOWR(EPM_ADC_IOCTL_CODE, 90, \
+ uint32_t)
+
+#define EPM_MARKER1_RELEASE _IOWR(EPM_ADC_IOCTL_CODE, 91, \
+ uint32_t)
+
+#define EPM_MARKER2_REQUEST _IOWR(EPM_ADC_IOCTL_CODE, 95, \
+ uint32_t)
+
+#define EPM_MARKER2_RELEASE _IOWR(EPM_ADC_IOCTL_CODE, 92, \
+ uint32_t)
+
+#define EPM_PSOC_ADC_INIT _IOWR(EPM_ADC_IOCTL_CODE, 4, \
struct epm_psoc_init_resp)
#define EPM_PSOC_ADC_CHANNEL_ENABLE _IOWR(EPM_ADC_IOCTL_CODE, 5, \
@@ -157,4 +186,18 @@
#define EPM_PSOC_ADC_SET_VADC_REFERENCE _IOWR(EPM_ADC_IOCTL_CODE, 15, \
struct epm_psoc_set_vadc)
+#define EPM_PSOC_ADC_DEINIT _IOWR(EPM_ADC_IOCTL_CODE, 16, \
+ uint32_t)
+
+#define EPM_PSOC_GPIO_BUFFER_REQUEST _IOWR(EPM_ADC_IOCTL_CODE, 17, \
+ struct epm_gpio_buffer_request)
+
+#define EPM_PSOC_GET_GPIO_BUFFER_DATA _IOWR(EPM_ADC_IOCTL_CODE, 18, \
+ struct epm_get_gpio_buffer_resp)
+
+#define EPM_PSOC_PAUSE_CONVERSION_REQUEST _IOWR(EPM_ADC_IOCTL_CODE, 19, \
+ uint32_t)
+
+#define EPM_PSOC_UNPAUSE_CONVERSION_REQUEST _IOWR(EPM_ADC_IOCTL_CODE, 20, \
+ uint32_t)
#endif /* __EPM_ADC_H */
diff --git a/include/linux/firmware.h b/include/linux/firmware.h
index 1e7c011..4f6fffb 100644
--- a/include/linux/firmware.h
+++ b/include/linux/firmware.h
@@ -36,6 +36,8 @@
__used __section(.builtin_fw) = { name, blob, size }
#if defined(CONFIG_FW_LOADER) || (defined(CONFIG_FW_LOADER_MODULE) && defined(MODULE))
+int request_firmware_direct(const char *name, struct device *device,
+ phys_addr_t addr, size_t size);
int request_firmware(const struct firmware **fw, const char *name,
struct device *device);
int request_firmware_nowait(
@@ -45,6 +47,12 @@
void release_firmware(const struct firmware *fw);
#else
+static inline int request_firmware_direct(const char *name,
+ struct device *device,
+ phys_addr_t addr, size_t size)
+{
+ return -EINVAL;
+}
static inline int request_firmware(const struct firmware **fw,
const char *name,
struct device *device)
diff --git a/include/linux/fmem.h b/include/linux/fmem.h
deleted file mode 100644
index cda4a0f..0000000
--- a/include/linux/fmem.h
+++ /dev/null
@@ -1,62 +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.
- *
- */
-#ifndef _FMEM_H_
-#define _FMEM_H_
-
-#include <linux/vmalloc.h>
-
-struct fmem_platform_data {
- unsigned long phys;
- unsigned long size;
- unsigned long reserved_size_low;
- unsigned long reserved_size_high;
- unsigned long align;
-};
-
-struct fmem_data {
- unsigned long phys;
- void *virt;
- struct vm_struct *area;
- unsigned long size;
- unsigned long reserved_size_low;
- unsigned long reserved_size_high;
-};
-
-enum fmem_state {
- FMEM_UNINITIALIZED = 0,
- FMEM_C_STATE,
- FMEM_T_STATE,
- FMEM_O_STATE,
-};
-
-#ifdef CONFIG_QCACHE
-struct fmem_data *fmem_get_info(void);
-int fmem_set_state(enum fmem_state);
-void lock_fmem_state(void);
-void unlock_fmem_state(void);
-void *fmem_map_virtual_area(int cacheability);
-void fmem_unmap_virtual_area(void);
-#else
-static inline struct fmem_data *fmem_get_info(void) { return NULL; }
-static inline int fmem_set_state(enum fmem_state f) { return -ENODEV; }
-static inline void lock_fmem_state(void) { return; }
-static inline void unlock_fmem_state(void) { return; }
-static inline void *fmem_map_virtual_area(int cacheability) { return NULL; }
-static inline void fmem_unmap_virtual_area(void) { return; }
-#endif
-
-int request_fmem_c_region(void *unused);
-int release_fmem_c_region(void *unused);
-#endif
diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/i2c/atmel_mxt_ts.h
index b903dfb..e9fbf90 100644
--- a/include/linux/i2c/atmel_mxt_ts.h
+++ b/include/linux/i2c/atmel_mxt_ts.h
@@ -77,6 +77,7 @@
int *key_codes;
bool need_calibration;
bool no_force_update;
+ bool no_lpm_support;
u8 bl_addr;
u8(*read_chg) (void);
diff --git a/include/linux/input/kxtj9.h b/include/linux/input/kxtj9.h
index d415579..65378c0 100644
--- a/include/linux/input/kxtj9.h
+++ b/include/linux/input/kxtj9.h
@@ -46,7 +46,7 @@
/* Output resolution: 8-bit valid or 12-bit valid */
#define RES_8BIT 0
#define RES_12BIT (1 << 6)
- u8 res_12bit;
+ u8 res_ctl;
/* Output g-range: +/-2g, 4g, or 8g */
#define KXTJ9_G_2G 0
#define KXTJ9_G_4G (1 << 3)
diff --git a/include/linux/input/mpu3050.h b/include/linux/input/mpu3050.h
index 61a2920..f87dfe3 100644
--- a/include/linux/input/mpu3050.h
+++ b/include/linux/input/mpu3050.h
@@ -25,6 +25,7 @@
int (*power_off)(void);
int gpio_int;
+ int gpio_en;
int gpio_fsync;
};
diff --git a/include/linux/input/synaptics_dsx.h b/include/linux/input/synaptics_dsx.h
index 73016d6..d121695 100644
--- a/include/linux/input/synaptics_dsx.h
+++ b/include/linux/input/synaptics_dsx.h
@@ -35,8 +35,11 @@
* struct synaptics_rmi4_platform_data - rmi4 platform data
* @x_flip: x flip flag
* @y_flip: y flip flag
+ * @i2c_pull_up: pull up i2c bus with regulator
+ * @power_down_enable: enable complete regulator shutdown in suspend
* @irq_gpio: attention interrupt gpio
* @irq_flags: flags used by the irq
+ * @reset_flags: flags used by reset line
* @reset_gpio: reset gpio
* @panel_x: panel maximum values on the x
* @panel_y: panel maximum values on the y
@@ -47,6 +50,7 @@
bool x_flip;
bool y_flip;
bool i2c_pull_up;
+ bool power_down_enable;
unsigned irq_gpio;
u32 irq_flags;
u32 reset_flags;
diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h
index cd70726..85dec85 100644
--- a/include/linux/mfd/pm8xxx/pm8921-bms.h
+++ b/include/linux/mfd/pm8xxx/pm8921-bms.h
@@ -14,7 +14,7 @@
#define __PM8XXX_BMS_H
#include <linux/errno.h>
-#include <linux/mfd/pm8xxx/batterydata-lib.h>
+#include <linux/batterydata-lib.h>
#define PM8921_BMS_DEV_NAME "pm8921-bms"
diff --git a/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h b/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h
index 412341a..bf76026 100644
--- a/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h
+++ b/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h
@@ -276,5 +276,37 @@
#define WCD9XXX_A_CDC_CLSH_V_PA_MIN_HPH (0x331)
#define WCD9XXX_A_CDC_CLSH_V_PA_MIN_HPH__POR (0x00)
+#define WCD9XXX_A_CDC_RX1_B6_CTL (0x2B5)
+#define WCD9XXX_A_CDC_RX1_B6_CTL__POR (0x80)
+#define WCD9XXX_A_CDC_RX2_B6_CTL (0x2BD)
+#define WCD9XXX_A_CDC_RX2_B6_CTL__POR (0x80)
+#define WCD9XXX_A_RX_HPH_L_GAIN (0x1AE)
+#define WCD9XXX_A_RX_HPH_L_GAIN__POR (0x00)
+#define WCD9XXX_A_RX_HPH_R_GAIN (0x1B4)
+#define WCD9XXX_A_RX_HPH_R_GAIN__POR (0x00)
+#define WCD9XXX_A_RX_HPH_CHOP_CTL (0x1A5)
+#define WCD9XXX_A_RX_HPH_CHOP_CTL__POR (0xB4)
+#define WCD9XXX_A_RX_HPH_L_TEST (0x1AF)
+#define WCD9XXX_A_RX_HPH_L_TEST__POR (0x00)
+#define WCD9XXX_A_RX_HPH_R_TEST (0x1B5)
+#define WCD9XXX_A_RX_HPH_R_TEST__POR (0x00)
+#define WCD9XXX_A_CDC_CLK_RX_B1_CTL (0x30F)
+#define WCD9XXX_A_CDC_CLK_RX_B1_CTL__POR (0x00)
+#define WCD9XXX_A_NCP_CLK (0x193)
+#define WCD9XXX_A_NCP_CLK__POR (0x94)
+#define WCD9XXX_A_RX_HPH_BIAS_WG_OCP (0x1A9)
+#define WCD9XXX_A_RX_HPH_BIAS_WG_OCP__POR (0x2A)
+#define WCD9XXX_A_RX_HPH_CNP_WG_CTL (0x1AC)
+#define WCD9XXX_A_RX_HPH_CNP_WG_CTL__POR (0xDE)
+#define WCD9XXX_A_CDC_CONN_RX2_B1_CTL (0x383)
+#define WCD9XXX_A_CDC_CONN_RX2_B1_CTL__POR (0x00)
+#define WCD9XXX_A_CDC_PA_RAMP_B1_CTL (0x361)
+#define WCD9XXX_A_CDC_PA_RAMP_B1_CTL__POR (0x00)
+#define WCD9XXX_A_CDC_PA_RAMP_B2_CTL (0x362)
+#define WCD9XXX_A_CDC_PA_RAMP_B2_CTL__POR (0x00)
+#define WCD9XXX_A_CDC_PA_RAMP_B3_CTL (0x363)
+#define WCD9XXX_A_CDC_PA_RAMP_B3_CTL__POR (0x00)
+#define WCD9XXX_A_CDC_PA_RAMP_B4_CTL (0x364)
+#define WCD9XXX_A_CDC_PA_RAMP_B4_CTL__POR (0x00)
#endif
diff --git a/include/linux/mhl_8334.h b/include/linux/mhl_8334.h
index 7297ff3..f0a54eb 100644
--- a/include/linux/mhl_8334.h
+++ b/include/linux/mhl_8334.h
@@ -99,7 +99,7 @@
int mhl_mode;
struct completion rgnd_done;
struct completion msc_cmd_done;
- uint8_t devcap_state;
+ uint16_t devcap_state;
uint8_t path_en_state;
struct work_struct mhl_msc_send_work;
struct list_head list_cmd;
@@ -137,7 +137,8 @@
uint8_t chip_rev_id;
int mhl_mode;
struct completion rgnd_done;
- void (*notify_usb_online)(int online);
+ void (*notify_usb_online)(void *ctx, int online);
+ void *notify_ctx;
struct usb_ext_notification *mhl_info;
bool disc_enabled;
struct power_supply mhl_psy;
@@ -145,7 +146,7 @@
int current_val;
struct completion msc_cmd_done;
uint8_t devcap[16];
- uint8_t devcap_state;
+ uint16_t devcap_state;
uint8_t status[2];
uint8_t path_en_state;
void *hdmi_mhl_ops;
diff --git a/include/linux/mhl_defs.h b/include/linux/mhl_defs.h
index f5dacfd..6177f07 100644
--- a/include/linux/mhl_defs.h
+++ b/include/linux/mhl_defs.h
@@ -132,6 +132,7 @@
#define MHL_SCRATCHPAD_SIZE 16
#define MAX_SCRATCHPAD_TRANSFER_SIZE 64
#define ADOPTER_ID_SIZE 2
+#define MHL_DEVCAP_ALL 0xffff
/* manually define highest number */
#define MHL_MAX_BUFFER_SIZE MHL_SCRATCHPAD_SIZE
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index f548721..e3ff5db 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -99,8 +99,8 @@
*/
unsigned int cmd_timeout_ms; /* in milliseconds */
- /* Set this flag only for blocking bkops request */
- bool bkops_busy;
+ /* Set this flag only for commands which can be HPIed */
+ bool ignore_timeout;
struct mmc_data *data; /* data segment associated with cmd */
struct mmc_request *mrq; /* associated request */
@@ -162,6 +162,8 @@
extern int __mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int, bool,
bool);
extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int);
+extern int mmc_switch_ignore_timeout(struct mmc_card *, u8, u8, u8,
+ unsigned int);
extern int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
#define MMC_ERASE_ARG 0x00000000
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index 72e31b2..424b1d9 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -23,6 +23,11 @@
s32 cookie;
};
+enum sdhci_power_policy {
+ SDHCI_PERFORMANCE_MODE,
+ SDHCI_POWER_SAVE_MODE,
+};
+
struct sdhci_host {
/* Data set by hardware interface driver */
const char *hw_name; /* Hardware bus name */
@@ -238,9 +243,13 @@
unsigned int cpu_dma_latency_us;
struct pm_qos_request pm_qos_req_dma;
+ unsigned int pm_qos_timeout_us; /* timeout for PM QoS request */
+ struct device_attribute pm_qos_tout;
struct sdhci_next next_data;
ktime_t data_start_time;
+ struct mutex ios_mutex;
+ enum sdhci_power_policy power_policy;
unsigned long private[0] ____cacheline_aligned;
};
diff --git a/include/linux/msm_audio_acdb.h b/include/linux/msm_audio_acdb.h
index a741107..e8ca1cd 100644
--- a/include/linux/msm_audio_acdb.h
+++ b/include/linux/msm_audio_acdb.h
@@ -54,12 +54,16 @@
#define AUDIO_SET_ASM_CUSTOM_TOPOLOGY _IOW(AUDIO_IOCTL_MAGIC, \
(AUDIO_MAX_COMMON_IOCTL_NUM+24), unsigned)
#define AUDIO_SET_SPEAKER_PROT _IOW(AUDIO_IOCTL_MAGIC, 25, \
- struct msm_spk_prot_cfg)
+ struct msm_spk_prot_cfg)
#define AUDIO_GET_SPEAKER_PROT _IOR(AUDIO_IOCTL_MAGIC, 26, \
- struct msm_spk_prot_status)
+ struct msm_spk_prot_status)
#define AUDIO_SET_AANC_CAL _IOW(AUDIO_IOCTL_MAGIC, \
(AUDIO_MAX_COMMON_IOCTL_NUM+27), unsigned)
-#define AUDIO_MAX_ACDB_IOCTL (AUDIO_MAX_COMMON_IOCTL_NUM+30)
+#define AUDIO_REGISTER_VOCPROC_VOL_TABLE _IOW(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+28), unsigned)
+#define AUDIO_DEREGISTER_VOCPROC_VOL_TABLE _IOW(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+29), unsigned)
+#define AUDIO_MAX_ACDB_IOCTL (AUDIO_MAX_COMMON_IOCTL_NUM+40)
/* ACDB structures */
struct cal_block {
diff --git a/include/linux/msm_ion.h b/include/linux/msm_ion.h
index 20b7317..16a1000 100644
--- a/include/linux/msm_ion.h
+++ b/include/linux/msm_ion.h
@@ -72,6 +72,12 @@
*/
#define ION_FLAG_FORCE_CONTIGUOUS (1 << 30)
+/*
+ * Used in conjunction with heap which pool memory to force an allocation
+ * to come from the page allocator directly instead of from the pool allocation
+ */
+#define ION_FLAG_POOL_FORCE_ALLOC (1 << 16)
+
/**
* Deprecated! Please use the corresponding ION_FLAG_*
*/
@@ -97,7 +103,6 @@
#define ION_PIL1_HEAP_NAME "pil_1"
#define ION_PIL2_HEAP_NAME "pil_2"
#define ION_QSECOM_HEAP_NAME "qsecom"
-#define ION_FMEM_HEAP_NAME "fmem"
#define ION_SET_CACHED(__cache) (__cache | ION_FLAG_CACHED)
#define ION_SET_UNCACHED(__cache) (__cache & ~ION_FLAG_CACHED)
@@ -129,12 +134,7 @@
* @secure_size: Memory size for securing the heap.
* Note: This might be different from actual size
* of this heap in the case of a shared heap.
- * @reusable Flag indicating whether this heap is reusable of not.
- * (see FMEM)
- * @mem_is_fmem Flag indicating whether this memory is coming from fmem
- * or not.
* @fixed_position If nonzero, position in the fixed area.
- * @virt_addr: Virtual address used when using fmem.
* @iommu_map_all: Indicates whether we should map whole heap into IOMMU.
* @iommu_2x_map_domain: Indicates the domain to use for overmapping.
* @request_region: function to be called when the number of allocations
@@ -153,13 +153,10 @@
unsigned int align;
ion_phys_addr_t secure_base; /* Base addr used when heap is shared */
size_t secure_size; /* Size used for securing heap when heap is shared*/
- int reusable;
- int mem_is_fmem;
int is_cma;
enum ion_fixed_position fixed_position;
int iommu_map_all;
int iommu_2x_map_domain;
- void *virt_addr;
int (*request_region)(void *);
int (*release_region)(void *);
void *(*setup_region)(void);
@@ -171,8 +168,6 @@
* struct ion_co_heap_pdata - defines a carveout heap in the given platform
* @adjacent_mem_id: Id of heap that this heap must be adjacent to.
* @align: Alignment requirement for the memory
- * @mem_is_fmem Flag indicating whether this memory is coming from fmem
- * or not.
* @fixed_position If nonzero, position in the fixed area.
* @request_region: function to be called when the number of allocations
* goes from 0 -> 1
@@ -185,7 +180,6 @@
struct ion_co_heap_pdata {
int adjacent_mem_id;
unsigned int align;
- int mem_is_fmem;
enum ion_fixed_position fixed_position;
int (*request_region)(void *);
int (*release_region)(void *);
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index ae88807..87047d2 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -30,6 +30,7 @@
#define KGSL_CONTEXT_TYPE_CL 2
#define KGSL_CONTEXT_TYPE_C2D 3
#define KGSL_CONTEXT_TYPE_RS 4
+#define KGSL_CONTEXT_TYPE_UNKNOWN 0x1E
#define KGSL_CONTEXT_INVALID 0xffffffff
@@ -227,6 +228,7 @@
#define KGSL_PERFCOUNTER_GROUP_VBIF_PWR 0xE
#define KGSL_PERFCOUNTER_NOT_USED 0xFFFFFFFF
+#define KGSL_PERFCOUNTER_BROKEN 0xFFFFFFFE
/* structure holds list of ibs */
struct kgsl_ibdesc {
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 18921a0..2455212 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -87,6 +87,7 @@
enum {
NOTIFY_UPDATE_START,
NOTIFY_UPDATE_STOP,
+ NOTIFY_UPDATE_POWER_OFF,
};
enum {
@@ -606,6 +607,25 @@
uint32_t data;
};
+struct mdp_calib_config_buffer {
+ uint32_t ops;
+ uint32_t size;
+ uint32_t *buffer;
+};
+
+struct mdp_calib_dcm_state {
+ uint32_t ops;
+ uint32_t dcm_state;
+};
+
+enum {
+ DCM_UNINIT,
+ DCM_UNBLANK,
+ DCM_ENTER,
+ DCM_EXIT,
+ DCM_BLANK,
+};
+
#define MDSS_MAX_BL_BRIGHTNESS 255
#define AD_BL_LIN_LEN (MDSS_MAX_BL_BRIGHTNESS + 1)
@@ -697,6 +717,8 @@
mdp_op_ad_cfg,
mdp_op_ad_input,
mdp_op_calib_mode,
+ mdp_op_calib_buffer,
+ mdp_op_calib_dcm_state,
mdp_op_max,
};
@@ -706,6 +728,8 @@
WB_FORMAT_RGB_888,
WB_FORMAT_xRGB_8888,
WB_FORMAT_ARGB_8888,
+ WB_FORMAT_BGRA_8888,
+ WB_FORMAT_BGRX_8888,
WB_FORMAT_ARGB_8888_INPUT_ALPHA /* Need to support */
};
@@ -724,6 +748,8 @@
struct mdss_ad_init_cfg ad_init_cfg;
struct mdss_calib_cfg mdss_calib_cfg;
struct mdss_ad_input ad_input;
+ struct mdp_calib_config_buffer calib_buffer;
+ struct mdp_calib_dcm_state calib_dcm;
} data;
};
diff --git a/include/linux/of_batterydata.h b/include/linux/of_batterydata.h
new file mode 100644
index 0000000..b2ed5a1
--- /dev/null
+++ b/include/linux/of_batterydata.h
@@ -0,0 +1,45 @@
+/* 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/of.h>
+#include <linux/batterydata-lib.h>
+
+#ifdef CONFIG_OF_BATTERYDATA
+/**
+ * of_batterydata_read_data() - Populate battery data from the device tree
+ * @container_node: pointer to the battery-data container device node
+ * containing the profile nodes.
+ * @batt_data: pointer to an allocated bms_battery_data structure that the
+ * loaded profile will be written to.
+ * @batt_id_uv: ADC voltage of the battery id line used to differentiate
+ * between different battery profiles. If there are multiple
+ * battery data in the device tree, the one with the closest
+ * battery id resistance will be automatically loaded.
+ *
+ * This routine loads the closest match battery data from device tree based on
+ * the battery id reading. Then, it will try to load all the relevant data from
+ * the device tree battery data profile.
+ *
+ * If any of the lookup table pointers are NULL, this routine will skip trying
+ * to read them.
+ */
+int of_batterydata_read_data(struct device_node *container_node,
+ struct bms_battery_data *batt_data,
+ int batt_id_uv);
+#else
+static inline int of_batterydata_read_data(struct device_node *container_node,
+ struct bms_battery_data *batt_data,
+ int batt_id_uv);
+{
+ return -ENXIO;
+}
+#endif /* CONFIG_OF_QPNP */
diff --git a/include/linux/pageblock-flags.h b/include/linux/pageblock-flags.h
index eed27f4..be655e4 100644
--- a/include/linux/pageblock-flags.h
+++ b/include/linux/pageblock-flags.h
@@ -71,13 +71,13 @@
#ifdef CONFIG_COMPACTION
#define get_pageblock_skip(page) \
get_pageblock_flags_group(page, PB_migrate_skip, \
- PB_migrate_skip + 1)
+ PB_migrate_skip)
#define clear_pageblock_skip(page) \
set_pageblock_flags_group(page, 0, PB_migrate_skip, \
- PB_migrate_skip + 1)
+ PB_migrate_skip)
#define set_pageblock_skip(page) \
set_pageblock_flags_group(page, 1, PB_migrate_skip, \
- PB_migrate_skip + 1)
+ PB_migrate_skip)
#endif /* CONFIG_COMPACTION */
#define get_pageblock_flags(page) \
diff --git a/include/linux/pinctrl/pinconf-generic.h b/include/linux/pinctrl/pinconf-generic.h
index 72474e1..9fd5ec5 100644
--- a/include/linux/pinctrl/pinconf-generic.h
+++ b/include/linux/pinctrl/pinconf-generic.h
@@ -29,12 +29,21 @@
* if for example some other pin is going to drive the signal connected
* to it for a while. Pins used for input are usually always high
* impedance.
+ * @PIN_CONFIG_BIAS_BUS_HOLD: the pin will be set to weakly latch so that it
+ * weakly drives the last value on a tristate bus, also known as a "bus
+ * holder", "bus keeper" or "repeater". This allows another device on the
+ * bus to change the value by driving the bus high or low and switching to
+ * tristate. The argument is ignored.
* @PIN_CONFIG_BIAS_PULL_UP: the pin will be pulled up (usually with high
* impedance to VDD). If the argument is != 0 pull-up is enabled,
* if it is 0, pull-up is disabled.
* @PIN_CONFIG_BIAS_PULL_DOWN: the pin will be pulled down (usually with high
* impedance to GROUND). If the argument is != 0 pull-down is enabled,
* if it is 0, pull-down is disabled.
+ * @PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: the pin will be pulled up or down based
+ * on embedded knowledge of the controller, like current mux function.
+ * If the argument is != 0 pull up/down is enabled, if it is 0,
+ * the pull is disabled.
* @PIN_CONFIG_DRIVE_PUSH_PULL: the pin will be driven actively high and
* low, this is the most typical case and is typically achieved with two
* active transistors on the output. Sending this config will enabale
@@ -78,8 +87,10 @@
enum pin_config_param {
PIN_CONFIG_BIAS_DISABLE,
PIN_CONFIG_BIAS_HIGH_IMPEDANCE,
+ PIN_CONFIG_BIAS_BUS_HOLD,
PIN_CONFIG_BIAS_PULL_UP,
PIN_CONFIG_BIAS_PULL_DOWN,
+ PIN_CONFIG_BIAS_PULL_PIN_DEFAULT,
PIN_CONFIG_DRIVE_PUSH_PULL,
PIN_CONFIG_DRIVE_OPEN_DRAIN,
PIN_CONFIG_DRIVE_OPEN_SOURCE,
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 3d7b1c9..5d6cdac 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -98,7 +98,9 @@
POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_VOLTAGE_AVG,
+ POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION,
POWER_SUPPLY_PROP_CURRENT_MAX,
+ POWER_SUPPLY_PROP_INPUT_CURRENT_MAX,
POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_CURRENT_AVG,
POWER_SUPPLY_PROP_POWER_NOW,
@@ -283,6 +285,7 @@
case POWER_SUPPLY_PROP_CHARGE_COUNTER:
case POWER_SUPPLY_PROP_CHARGE_COUNTER_SHADOW:
case POWER_SUPPLY_PROP_CURRENT_MAX:
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_MAX:
case POWER_SUPPLY_PROP_CURRENT_NOW:
case POWER_SUPPLY_PROP_CURRENT_AVG:
return 1;
diff --git a/include/linux/qpnp/power-on.h b/include/linux/qpnp/power-on.h
index 5e87259..772bf62 100644
--- a/include/linux/qpnp/power-on.h
+++ b/include/linux/qpnp/power-on.h
@@ -35,12 +35,28 @@
PON_KPDPWR_N,
};
+/**
+ * enum pon_power_off_type: Possible power off actions to perform
+ * %PON_POWER_OFF_WARM_RESET: Reset the MSM but not all PMIC peripherals
+ * %PON_POWER_OFF_SHUTDOWN: Shutdown the MSM and PMIC completely
+ * %PON_POWER_OFF_HARD_RESET: Reset the MSM and all PMIC peripherals
+};
+ */
+enum pon_power_off_type {
+ PON_POWER_OFF_WARM_RESET = 0x01,
+ PON_POWER_OFF_SHUTDOWN = 0x04,
+ PON_POWER_OFF_HARD_RESET = 0x07,
+};
+
#ifdef CONFIG_QPNP_POWER_ON
-int qpnp_pon_system_pwr_off(bool reset);
+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);
#else
-static int qpnp_pon_system_pwr_off(bool reset) { return -ENODEV; }
+static int qpnp_pon_system_pwr_off(enum pon_power_off_type type)
+{
+ return -ENODEV;
+}
static inline int qpnp_pon_is_warm_reset(void) { return -ENODEV; }
static inline int qpnp_pon_trigger_config(enum pon_trigger_source pon_src,
bool enable)
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index dfb156f..013a778 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -1419,11 +1419,16 @@
enum qpnp_iadc_channels i_channel, struct qpnp_iadc_result *i_result,
enum qpnp_vadc_channels v_channel, struct qpnp_vadc_result *v_result);
/**
- * qpnp_iadc_calibrate_for_trim() - Clients can use this API to re-calibrate
- * IADC.
- * @result: 0 on success.
+ * qpnp_iadc_calibrate_for_trim - Clients can use this API to re-calibrate
+ * IADC. The offset and gain values are programmed in the trim
+ * registers. The offset and the gain can be retrieved using
+ * qpnp_iadc_get_gain_and_offset
+ * @batfet_closed: batfet is opened or closed. The IADC chooses proper
+ * channel (internal/external) based on batfet status
+ * for calibration.
+ * RETURNS: 0 on success.
*/
-int32_t qpnp_iadc_calibrate_for_trim(void);
+int32_t qpnp_iadc_calibrate_for_trim(bool batfet_closed);
int32_t qpnp_iadc_comp_result(int64_t *result);
#else
static inline int32_t qpnp_iadc_read(enum qpnp_iadc_channels channel,
@@ -1440,7 +1445,7 @@
enum qpnp_iadc_channels i_channel, struct qpnp_iadc_result *i_result,
enum qpnp_vadc_channels v_channel, struct qpnp_vadc_result *v_result)
{ return -ENXIO; }
-static inline int32_t qpnp_iadc_calibrate_for_trim(void)
+static inline int32_t qpnp_iadc_calibrate_for_trim(bool batfet_closed)
{ return -ENXIO; }
static inline int32_t qpnp_iadc_comp_result(int64_t *result, int32_t sign)
{ return -ENXIO; }
diff --git a/include/linux/qseecom.h b/include/linux/qseecom.h
index 294c881..6d2db8f3 100644
--- a/include/linux/qseecom.h
+++ b/include/linux/qseecom.h
@@ -36,7 +36,6 @@
unsigned int resp_len; /* in/out */
};
-
/*
* struct qseecom_ion_fd_info - ion fd handle data information
* @fd - ion handle to some memory allocated in user space
@@ -62,6 +61,7 @@
unsigned int resp_len; /* in/out */
struct qseecom_ion_fd_info ifd_data[MAX_ION_FD];
};
+
/*
* struct qseecom_listener_send_resp_req - signal to continue the send_cmd req.
* Used as a trigger from HLOS service to notify QSEECOM that it's done with its
@@ -157,6 +157,27 @@
int is_activated; /* out */
};
+enum qseecom_buffer_protection {
+ QSEOS_UNPROTECTED_BUFFER,
+ QSEOS_PROTECT_BUFFER,
+ QSEOS_UNPROTECT_PROTECTED_BUFFER,
+};
+
+/*
+ * struct qseecom_send_modfd_resp - for send command ioctl request
+ * @req_len - command buffer length
+ * @req_buf - command buffer
+ * @ifd_data_fd - ion handle to memory allocated in user space
+ * @cmd_buf_offset - command buffer offset
+ */
+struct qseecom_send_modfd_listener_resp {
+ void *resp_buf_ptr; /* in */
+ unsigned int resp_len; /* in */
+ struct qseecom_ion_fd_info ifd_data[MAX_ION_FD]; /* in */
+ enum qseecom_buffer_protection protection_mode; /* in */
+};
+
+
#define QSEECOM_IOC_MAGIC 0x97
@@ -220,4 +241,9 @@
#define QSEECOM_IOCTL_IS_ES_ACTIVATED_REQ \
_IOWR(QSEECOM_IOC_MAGIC, 20, struct qseecom_is_es_activated_req)
+#define QSEECOM_IOCTL_SEND_MODFD_RESP \
+ _IOWR(QSEECOM_IOC_MAGIC, 21, struct qseecom_send_modfd_listener_resp)
+
+#define QSEECOM_IOCTL_UNPROTECT_BUF \
+ _IOWR(QSEECOM_IOC_MAGIC, 22, int)
#endif /* __QSEECOM_H_ */
diff --git a/include/linux/smux.h b/include/linux/smux.h
index 56b18fa..1157cef 100644
--- a/include/linux/smux.h
+++ b/include/linux/smux.h
@@ -1,6 +1,6 @@
/* include/linux/smux.h
*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-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
@@ -79,6 +79,8 @@
SMUX_HIGH_WM_HIT, /* @metadata is NULL */
SMUX_RX_RETRY_HIGH_WM_HIT, /* @metadata is NULL */
SMUX_RX_RETRY_LOW_WM_HIT, /* @metadata is NULL */
+ SMUX_LOCAL_CLOSED,
+ SMUX_REMOTE_CLOSED,
};
/**
diff --git a/include/linux/test-iosched.h b/include/linux/test-iosched.h
index 89d3b30..5b05b7a 100644
--- a/include/linux/test-iosched.h
+++ b/include/linux/test-iosched.h
@@ -130,7 +130,7 @@
* @check_test_result_fn: Test specific test result checking
* callback
* @get_test_case_str_fn: Test specific function to get the test name
- * @test_duration: A jiffies value saved for timing
+ * @test_duration: A ktime value saved for timing
* calculations
* @data: Test specific private data
* @test_byte_count: Total number of bytes dispatched in
@@ -144,7 +144,7 @@
check_test_result_fn *check_test_result_fn;
post_test_fn *post_test_fn;
get_test_case_str_fn *get_test_case_str_fn;
- unsigned long test_duration;
+ ktime_t test_duration;
get_rq_disk_fn *get_rq_disk_fn;
void *data;
unsigned long test_byte_count;
@@ -263,4 +263,6 @@
void test_iosched_add_urgent_req(struct test_request *test_rq);
int test_is_req_urgent(struct request *rq);
+
+void check_test_completion(void);
#endif /* _LINUX_TEST_IOSCHED_H */
diff --git a/include/linux/usb/Kbuild b/include/linux/usb/Kbuild
index b607f35..087d163 100644
--- a/include/linux/usb/Kbuild
+++ b/include/linux/usb/Kbuild
@@ -5,6 +5,7 @@
header-y += functionfs.h
header-y += gadgetfs.h
header-y += midi.h
+header-y += msm_ext_chg.h
header-y += g_printer.h
header-y += tmc.h
header-y += video.h
diff --git a/include/linux/usb/msm_ext_chg.h b/include/linux/usb/msm_ext_chg.h
new file mode 100644
index 0000000..dcc786d
--- /dev/null
+++ b/include/linux/usb/msm_ext_chg.h
@@ -0,0 +1,31 @@
+#ifndef __LINUX_USB_MSM_EXT_CHG_H
+#define __LINUX_USB_MSM_EXT_CHG_H
+
+#include <linux/ioctl.h>
+
+#define USB_CHG_BLOCK_ULPI 1
+#define USB_CHG_BLOCK_QSCRATCH 2
+
+/**
+ * struct msm_usb_chg_info - MSM USB charger block details.
+ * @chg_block_type: The type of charger block. QSCRATCH/ULPI.
+ * @page_offset: USB charger register base may not be aligned to
+ * PAGE_SIZE. The kernel driver aligns the base
+ * address and use it for memory mapping. This
+ * page_offset is used by user space to calaculate
+ * the corret charger register base address.
+ * @length: The length of the charger register address space.
+ */
+struct msm_usb_chg_info {
+ uint32_t chg_block_type;
+ off_t page_offset;
+ size_t length;
+};
+
+/* Get the MSM USB charger block information */
+#define MSM_USB_EXT_CHG_INFO _IOW('M', 0, struct msm_usb_chg_info)
+
+/* Vote against USB hardware low power mode */
+#define MSM_USB_EXT_CHG_BLOCK_LPM _IOW('M', 1, int)
+
+#endif /* __LINUX_USB_MSM_EXT_CHG_H */
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index bfed960..8d104c6 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -26,6 +26,7 @@
#include <linux/pm_qos.h>
#include <linux/hrtimer.h>
#include <linux/power_supply.h>
+#include <linux/cdev.h>
/*
* The following are bit fields describing the usb_request.udc_priv word.
* These bit fields are set by function drivers that wish to queue
@@ -165,6 +166,7 @@
USB_ACA_C_CHARGER,
USB_ACA_DOCK_CHARGER,
USB_PROPRIETARY_CHARGER,
+ USB_FLOATED_CHARGER,
};
/**
@@ -203,6 +205,10 @@
* @pmic_id_irq: IRQ number assigned for PMIC USB ID line.
* @mpm_otgsessvld_int: MPM wakeup pin assigned for OTG SESSVLD
* interrupt. Used when .otg_control == OTG_PHY_CONTROL.
+ * @mpm_dpshv_int: MPM wakeup pin assigned for DP SHV interrupt.
+ * Used during host bus suspend.
+ * @mpm_dmshv_int: MPM wakeup pin assigned for DM SHV interrupt.
+ * Used during host bus suspend.
* @mhl_enable: indicates MHL connector or not.
* @disable_reset_on_disconnect: perform USB PHY and LINK reset
* on USB cable disconnection.
@@ -222,6 +228,8 @@
* interrupt threshold (ITC), when log2_itc is
* 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.
*/
struct msm_otg_platform_data {
int *phy_init_seq;
@@ -234,6 +242,8 @@
void (*setup_gpio)(enum usb_otg_state state);
int pmic_id_irq;
unsigned int mpm_otgsessvld_int;
+ unsigned int mpm_dpshv_int;
+ unsigned int mpm_dmshv_int;
bool mhl_enable;
bool disable_reset_on_disconnect;
bool pnoc_errata_fix;
@@ -247,6 +257,7 @@
const char *mhl_dev_name;
int log2_itc;
bool l1_supported;
+ bool dpdm_pulldown_added;
};
/* phy related flags */
@@ -325,6 +336,7 @@
* @xo_handle: TCXO buffer handle
* @bus_perf_client: Bus performance client handle to request BUS bandwidth
* @mhl_enabled: MHL driver registration successful and MHL enabled.
+ * @host_bus_suspend: indicates host bus suspend or not.
* @chg_check_timer: The timer used to implement the workaround to detect
* very slow plug in of wall charger.
*/
@@ -339,6 +351,7 @@
struct clk *phy_reset_clk;
struct clk *core_clk;
long core_clk_rate;
+ struct resource *io_res;
void __iomem *regs;
#define ID 0
#define B_SESS_VLD 1
@@ -380,6 +393,7 @@
struct msm_xo_voter *xo_handle;
uint32_t bus_perf_client;
bool mhl_enabled;
+ bool host_bus_suspend;
struct timer_list chg_check_timer;
/*
* Allowing PHY power collpase turns off the HSUSB 3.3v and 1.8v
@@ -404,6 +418,11 @@
* analog regulators into LPM while going to USB low power mode.
*/
#define ALLOW_PHY_REGULATORS_LPM BIT(3)
+ /*
+ * Allow PHY RETENTION mode before turning off the digital
+ * voltage regulator(VDDCX) during host mode.
+ */
+#define ALLOW_HOST_PHY_RETENTION BIT(4)
unsigned long lpm_flags;
#define PHY_PWR_COLLAPSED BIT(0)
#define PHY_RETENTIONED BIT(1)
@@ -419,7 +438,16 @@
struct power_supply usb_psy;
unsigned int online;
unsigned int host_mode;
+ unsigned int voltage_max;
unsigned int current_max;
+
+ dev_t ext_chg_dev;
+ struct cdev ext_chg_cdev;
+ struct class *ext_chg_class;
+ struct device *ext_chg_device;
+ bool ext_chg_opened;
+ bool ext_chg_active;
+ struct completion ext_chg_wait;
};
struct ci13xxx_platform_data {
@@ -438,6 +466,7 @@
unsigned data;
bool ignore_cal_pad_config;
bool phy_sof_workaround;
+ u32 reset_delay;
int strobe_pad_offset;
int data_pad_offset;
@@ -465,6 +494,8 @@
int pmic_gpio_dp_irq;
unsigned int dock_connect_irq;
bool use_sec_phy;
+ bool no_selective_suspend;
+ int resume_gpio;
};
/**
@@ -480,7 +511,7 @@
/**
* struct usb_ext_notification: event notification structure
* @notify: pointer to client function to call when ID event is detected.
- * The last parameter is provided by driver to be called back when
+ * The function parameter is provided by driver to be called back when
* external client indicates it is done using the USB. This function
* should return 0 if handled successfully, otherise an error code.
* @ctxt: client-specific context pointer
@@ -494,17 +525,19 @@
* called with the online parameter set to false.
*/
struct usb_ext_notification {
- int (*notify)(void *, int, void (*)(int online));
+ int (*notify)(void *, int, void (*)(void *, int online), void *);
void *ctxt;
};
#ifdef CONFIG_USB_BAM
bool msm_bam_lpm_ok(void);
+void msm_bam_notify_lpm_resume(void);
void msm_bam_set_hsic_host_dev(struct device *dev);
void msm_bam_wait_for_hsic_prod_granted(void);
bool msm_bam_hsic_lpm_ok(void);
void msm_bam_hsic_notify_on_resume(void);
#else
static inline bool msm_bam_lpm_ok(void) { return true; }
+static inline void msm_bam_notify_lpm_resume(void) {}
static inline void msm_bam_set_hsic_host_dev(struct device *dev) {}
static inline void msm_bam_wait_for_hsic_prod_granted(void) {}
static inline bool msm_bam_hsic_lpm_ok(void) { return true; }
@@ -524,7 +557,7 @@
int msm_data_fifo_config(struct usb_ep *ep, u32 addr, u32 size,
u8 dst_pipe_idx);
-void msm_dwc3_restart_usb_session(void);
+void msm_dwc3_restart_usb_session(struct usb_gadget *gadget);
int msm_register_usb_ext_notification(struct usb_ext_notification *info);
#else
@@ -544,7 +577,7 @@
return -ENODEV;
}
-static inline void msm_dwc3_restart_usb_session(void)
+static inline void msm_dwc3_restart_usb_session(struct usb_gadget *gadget)
{
return;
}
diff --git a/include/linux/usb/msm_hsusb_hw.h b/include/linux/usb/msm_hsusb_hw.h
index f3f4c3b..064d210 100644
--- a/include/linux/usb/msm_hsusb_hw.h
+++ b/include/linux/usb/msm_hsusb_hw.h
@@ -24,6 +24,7 @@
#define USB_HS_GPTIMER_BASE (MSM_USB_BASE + 0x80)
#define GENCFG2_SESS_VLD_CTRL_EN BIT(7)
+#define GENCFG2_LINESTATE_DIFF_WAKEUP_EN BIT(12)
#define USB_USBCMD (MSM_USB_BASE + 0x0140)
#define USB_USBSTS (MSM_USB_BASE + 0x0144)
@@ -82,6 +83,7 @@
#define PHY_RETEN (1 << 1) /* PHY retention enable/disable */
#define PHY_IDHV_INTEN (1 << 8) /* PHY ID HV interrupt */
#define PHY_OTGSESSVLDHV_INTEN (1 << 9) /* PHY Session Valid HV int. */
+#define PHY_CLAMP_DPDMSE_EN (1 << 21) /* PHY mpm DP DM clamp enable */
#define STS_PCI (1 << 2) /* R/WC - Port Change Detect */
#define STS_URI (1 << 6) /* R/WC - RESET recv'd */
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 5c7ae02..2424518 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -703,6 +703,7 @@
#define V4L2_QCOM_BUF_FLAG_IDRFRAME 0x20000 /* Image is a IDR-frame */
#define V4L2_QCOM_BUF_FLAG_DECODEONLY 0x40000
#define V4L2_QCOM_BUF_DATA_CORRUPT 0x80000
+#define V4L2_QCOM_BUF_DROP_FRAME 0x100000
/*
* O V E R L A Y P R E V I E W
@@ -766,7 +767,8 @@
#define V4L2_CAP_QCOM_FRAMESKIP 0x2000 /* frame skipping is supported */
struct v4l2_qcom_frameskip {
- __u64 maxframeinterval;
+ __u64 maxframeinterval;
+ __u8 fpsvariance;
};
struct v4l2_outputparm {
@@ -1836,12 +1838,6 @@
V4L2_MPEG_VIDC_INDEX_EXTRADATA_ASPECT_RATIO,
V4L2_MPEG_VIDC_EXTRADATA_MPEG2_SEQDISP
};
-#define V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO \
- (V4L2_CID_MPEG_MSM_VIDC_BASE + 23)
-enum v4l2_mpeg_vidc_video_h264_vui_timing_info {
- V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_DISABLED = 0,
- V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_ENABLED = 1
-};
#define V4L2_CID_MPEG_VIDC_SET_PERF_LEVEL (V4L2_CID_MPEG_MSM_VIDC_BASE + 26)
enum v4l2_mpeg_vidc_perf_level {
@@ -1851,9 +1847,32 @@
};
#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_GOB \
- (V4L2_CID_MPEG_MSM_VIDC_BASE+27)
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 27)
+
#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_DELIVERY_MODE \
- (V4L2_CID_MPEG_MSM_VIDC_BASE+28)
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 28)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 29)
+enum v4l2_mpeg_vidc_video_h264_vui_timing_info {
+ V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_DISABLED = 0,
+ V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_ENABLED = 1
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE+30)
+enum v4l2_mpeg_vidc_video_alloc_mode_type {
+ V4L2_MPEG_VIDC_VIDEO_STATIC = 0,
+ V4L2_MPEG_VIDC_VIDEO_RING = 1,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_FRAME_ASSEMBLY \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE+31)
+enum v4l2_mpeg_vidc_video_assembly {
+ V4L2_MPEG_VIDC_FRAME_ASSEMBLY_DISABLE = 0,
+ V4L2_MPEG_VIDC_FRAME_ASSEMBLY_ENABLE = 1,
+};
+
/* 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/media/msm_cam_sensor.h b/include/media/msm_cam_sensor.h
index 31798d6..2805401 100644
--- a/include/media/msm_cam_sensor.h
+++ b/include/media/msm_cam_sensor.h
@@ -46,6 +46,8 @@
#define MAX_EEPROM_NAME 32
+#define MAX_AF_ITERATIONS 3
+
enum msm_camera_i2c_reg_addr_type {
MSM_CAMERA_I2C_BYTE_ADDR = 1,
MSM_CAMERA_I2C_WORD_ADDR,
@@ -78,6 +80,11 @@
enum msm_sensor_power_seq_gpio_t {
SENSOR_GPIO_RESET,
SENSOR_GPIO_STANDBY,
+ SENSOR_GPIO_AF_PWDM,
+ SENSOR_GPIO_VIO,
+ SENSOR_GPIO_VANA,
+ SENSOR_GPIO_VDIG,
+ SENSOR_GPIO_VAF,
SENSOR_GPIO_MAX,
};
@@ -133,6 +140,11 @@
REG_GPIO,
};
+enum sensor_af_t {
+ SENSOR_AF_FOCUSSED,
+ SENSOR_AF_NOT_FOCUSSED,
+};
+
struct msm_sensor_power_setting {
enum msm_sensor_power_seq_type_t seq_type;
uint16_t seq_val;
@@ -305,18 +317,19 @@
CFG_EEPROM_READ_CAL_DATA,
CFG_EEPROM_WRITE_DATA,
};
+
struct eeprom_get_t {
- uint16_t num_bytes;
+ uint32_t num_bytes;
};
struct eeprom_read_t {
uint8_t *dbuffer;
- uint16_t num_bytes;
+ uint32_t num_bytes;
};
struct eeprom_write_t {
uint8_t *dbuffer;
- uint16_t num_bytes;
+ uint32_t num_bytes;
};
struct msm_eeprom_cfg_data {
@@ -345,6 +358,11 @@
CFG_SET_RESOLUTION,
CFG_SET_STOP_STREAM,
CFG_SET_START_STREAM,
+ CFG_SET_SATURATION,
+ CFG_SET_CONTRAST,
+ CFG_SET_SHARPNESS,
+ CFG_SET_AUTOFOCUS,
+ CFG_CANCEL_AUTOFOCUS,
};
enum msm_actuator_cfg_type_t {
@@ -508,6 +526,9 @@
#define VIDIOC_MSM_EEPROM_CFG \
_IOWR('V', BASE_VIDIOC_PRIVATE + 8, struct msm_eeprom_cfg_data)
+#define VIDIOC_MSM_SENSOR_GET_AF_STATUS \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 9, uint32_t)
+
#define MSM_V4L2_PIX_FMT_META v4l2_fourcc('M', 'E', 'T', 'A') /* META */
#endif /* __LINUX_MSM_CAM_SENSOR_H */
diff --git a/include/media/msmb_camera.h b/include/media/msmb_camera.h
index 388b308..62e7b27 100644
--- a/include/media/msmb_camera.h
+++ b/include/media/msmb_camera.h
@@ -39,6 +39,13 @@
#define MSM_MAX_CAMERA_SENSORS 5
+/* The below macro is defined to put an upper limit on maximum
+ * number of buffer requested per stream. In case of extremely
+ * large value for number of buffer due to data structure corruption
+ * we return error to avoid integer overflow. This value may be
+ * configured in future*/
+#define MSM_CAMERA_MAX_STREAM_BUF 40
+
/* featur base */
#define MSM_CAMERA_FEATURE_BASE 0x00010000
#define MSM_CAMERA_FEATURE_SHUTDOWN (MSM_CAMERA_FEATURE_BASE + 1)
diff --git a/include/media/msmb_isp.h b/include/media/msmb_isp.h
index 4d36688..5ae852a 100644
--- a/include/media/msmb_isp.h
+++ b/include/media/msmb_isp.h
@@ -11,6 +11,7 @@
#define ISP_NATIVE_BUF_BIT 0x10000
#define ISP0_BIT 0x20000
#define ISP1_BIT 0x40000
+#define ISP_META_CHANNEL_BIT 0x80000
#define ISP_STATS_STREAM_BIT 0x80000000
enum ISP_START_PIXEL_PATTERN {
diff --git a/include/media/msmb_pproc.h b/include/media/msmb_pproc.h
index 8e9aedf..162729a 100644
--- a/include/media/msmb_pproc.h
+++ b/include/media/msmb_pproc.h
@@ -6,6 +6,7 @@
#endif
#include <linux/videodev2.h>
#include <linux/types.h>
+#include <media/msmb_generic_buf_mgr.h>
/* Should be same as VIDEO_MAX_PLANES in videodev2.h */
#define MAX_PLANES VIDEO_MAX_PLANES
@@ -174,6 +175,10 @@
struct msm_vpe_buffer_info_t output_buffer_info;
};
+struct msm_pproc_queue_buf_info {
+ struct msm_buf_mngr_info buff_mgr_info;
+ uint8_t is_buf_dirty;
+};
#define VIDIOC_MSM_CPP_CFG \
_IOWR('V', BASE_VIDIOC_PRIVATE, struct msm_camera_v4l2_ioctl_t)
@@ -218,6 +223,9 @@
#define VIDIOC_MSM_VPE_DEQUEUE_STREAM_BUFF_INFO \
_IOWR('V', BASE_VIDIOC_PRIVATE + 13, struct msm_camera_v4l2_ioctl_t)
+#define VIDIOC_MSM_CPP_QUEUE_BUF \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 14, struct msm_camera_v4l2_ioctl_t)
+
#define V4L2_EVENT_CPP_FRAME_DONE (V4L2_EVENT_PRIVATE_START + 0)
#define V4L2_EVENT_VPE_FRAME_DONE (V4L2_EVENT_PRIVATE_START + 1)
diff --git a/include/media/radio-iris.h b/include/media/radio-iris.h
index d6151c0..419e055 100644
--- a/include/media/radio-iris.h
+++ b/include/media/radio-iris.h
@@ -77,6 +77,9 @@
#define RDS_PS0_LEN 6
#define RX_REPEATE_BYTE_OFFSET 5
+#define FM_AF_LIST_MAX_SIZE 200
+#define AF_LIST_MAX (FM_AF_LIST_MAX_SIZE / 4) /* Each AF frequency consist
+ of sizeof(int) bytes */
/* HCI timeouts */
#define RADIO_HCI_TIMEOUT (10000) /* 10 seconds */
@@ -485,7 +488,7 @@
__le32 tune_freq;
__le16 pi_code;
__u8 af_size;
- __u8 af_list[25];
+ __u8 af_list[FM_AF_LIST_MAX_SIZE];
} __packed;
struct hci_ev_cmd_complete {
@@ -615,6 +618,7 @@
#define PI_CODE_OFFSET 4
#define AF_SIZE_OFFSET 6
#define AF_LIST_OFFSET 7
+#define RT_A_B_FLAG_OFFSET 4
/*FM states*/
enum radio_state_t {
@@ -622,7 +626,8 @@
FM_RECV,
FM_TRANS,
FM_RESET,
- FM_CALIB
+ FM_CALIB,
+ FM_TURNING_OFF
};
enum emphasis_type {
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index c68d427..60845de 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1,6 +1,7 @@
/*
BlueZ - Bluetooth protocol stack for Linux
- Copyright (c) 2000-2001, 2010-2012, The Linux Foundation. All rights reserved.
+ Copyright (c) 2000-2001, The Linux Foundation. All rights reserved.
+ Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
@@ -354,6 +355,7 @@
void *smp_conn;
struct timer_list smp_timer;
__u8 conn_valid;
+ __u8 hidp_session_valid;
void (*connect_cfm_cb) (struct hci_conn *conn, u8 status);
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index 6efb2e1..7c6a558 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -383,10 +383,18 @@
int data_direction, void *buffer, unsigned bufflen,
unsigned char *sense, int timeout, int retries,
int flag, int *resid);
-extern int scsi_execute_req(struct scsi_device *sdev, const unsigned char *cmd,
- int data_direction, void *buffer, unsigned bufflen,
- struct scsi_sense_hdr *, int timeout, int retries,
- int *resid);
+extern int scsi_execute_req_flags(struct scsi_device *sdev,
+ const unsigned char *cmd, int data_direction, void *buffer,
+ unsigned bufflen, struct scsi_sense_hdr *sshdr, int timeout,
+ int retries, int *resid, int flags);
+static inline int scsi_execute_req(struct scsi_device *sdev,
+ const unsigned char *cmd, int data_direction, void *buffer,
+ unsigned bufflen, struct scsi_sense_hdr *sshdr, int timeout,
+ int retries, int *resid)
+{
+ return scsi_execute_req_flags(sdev, cmd, data_direction, buffer,
+ bufflen, sshdr, timeout, retries, resid, 0);
+}
#ifdef CONFIG_PM_RUNTIME
extern int scsi_autopm_get_device(struct scsi_device *);
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 7e98ef3..88fcf61 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -632,43 +632,44 @@
/* Port ID. Update afe_get_port_index
* when a new port is added here. */
-#define PRIMARY_I2S_RX 0 /* index = 0 */
-#define PRIMARY_I2S_TX 1 /* index = 1 */
-#define SECONDARY_I2S_RX 4 /* index = 4 */
-#define SECONDARY_I2S_TX 5 /* index = 5 */
-#define MI2S_RX 6 /* index = 6 */
-#define MI2S_TX 7 /* index = 7 */
-#define HDMI_RX 8 /* index = 8 */
-#define RSVD_2 9 /* index = 9 */
-#define RSVD_3 10 /* index = 10 */
-#define DIGI_MIC_TX 11 /* index = 11 */
-#define VOICE_RECORD_RX 0x8003 /* index = 12 */
-#define VOICE_RECORD_TX 0x8004 /* index = 13 */
-#define VOICE_PLAYBACK_TX 0x8005 /* index = 14 */
+#define PRIMARY_I2S_RX 0
+#define PRIMARY_I2S_TX 1
+#define SECONDARY_I2S_RX 4
+#define SECONDARY_I2S_TX 5
+#define MI2S_RX 6
+#define MI2S_TX 7
+#define HDMI_RX 8
+#define RSVD_2 9
+#define RSVD_3 10
+#define DIGI_MIC_TX 11
+#define VOICE2_PLAYBACK_TX 0x8002
+#define VOICE_RECORD_RX 0x8003
+#define VOICE_RECORD_TX 0x8004
+#define VOICE_PLAYBACK_TX 0x8005
/* Slimbus Multi channel port id pool */
-#define SLIMBUS_0_RX 0x4000 /* index = 15 */
-#define SLIMBUS_0_TX 0x4001 /* index = 16 */
-#define SLIMBUS_1_RX 0x4002 /* index = 17 */
-#define SLIMBUS_1_TX 0x4003 /* index = 18 */
+#define SLIMBUS_0_RX 0x4000
+#define SLIMBUS_0_TX 0x4001
+#define SLIMBUS_1_RX 0x4002
+#define SLIMBUS_1_TX 0x4003
#define SLIMBUS_2_RX 0x4004
#define SLIMBUS_2_TX 0x4005
#define SLIMBUS_3_RX 0x4006
#define SLIMBUS_3_TX 0x4007
#define SLIMBUS_4_RX 0x4008
-#define SLIMBUS_4_TX 0x4009 /* index = 24 */
+#define SLIMBUS_4_TX 0x4009
#define SLIMBUS_5_RX 0x400a
#define SLIMBUS_5_TX 0x400b
#define SLIMBUS_6_RX 0x400c
#define SLIMBUS_6_TX 0x400d
#define SLIMBUS_PORT_LAST SLIMBUS_6_TX
-#define INT_BT_SCO_RX 0x3000 /* index = 25 */
-#define INT_BT_SCO_TX 0x3001 /* index = 26 */
-#define INT_BT_A2DP_RX 0x3002 /* index = 27 */
-#define INT_FM_RX 0x3004 /* index = 28 */
-#define INT_FM_TX 0x3005 /* index = 29 */
-#define RT_PROXY_PORT_001_RX 0x2000 /* index = 30 */
-#define RT_PROXY_PORT_001_TX 0x2001 /* index = 31 */
+#define INT_BT_SCO_RX 0x3000
+#define INT_BT_SCO_TX 0x3001
+#define INT_BT_A2DP_RX 0x3002
+#define INT_FM_RX 0x3004
+#define INT_FM_TX 0x3005
+#define RT_PROXY_PORT_001_RX 0x2000
+#define RT_PROXY_PORT_001_TX 0x2001
#define AFE_PORT_INVALID 0xFFFF
#define SLIMBUS_INVALID AFE_PORT_INVALID
@@ -818,6 +819,7 @@
* to this port from where the voice path delivers them on the
* Rx path.
*/
+#define AFE_PORT_ID_VOICE2_PLAYBACK_TX 0x8002
#define AFE_PORT_ID_VOICE_PLAYBACK_TX 0x8005
#define AFE_PORT_ID_INVALID 0xFFFF
@@ -6922,6 +6924,11 @@
/* Dolby DAP topology */
#define DOLBY_ADM_COPP_TOPOLOGY_ID 0x0001033B
+/* RMS value from DSP */
+#define RMS_MODULEID_APPI_PASSTHRU 0x10009011
+#define RMS_PARAM_FIRST_SAMPLE 0x10009012
+#define RMS_PAYLOAD_LEN 4
+
struct afe_svc_cmd_set_clip_bank_selection {
struct apr_hdr hdr;
struct afe_svc_cmd_set_param param;
diff --git a/include/sound/msm-dai-q6-v2.h b/include/sound/msm-dai-q6-v2.h
index c34a397..e2f9399 100644
--- a/include/sound/msm-dai-q6-v2.h
+++ b/include/sound/msm-dai-q6-v2.h
@@ -40,7 +40,6 @@
};
struct msm_dai_auxpcm_pdata {
- void *clk_cfg;
struct msm_dai_auxpcm_config mode_8k;
struct msm_dai_auxpcm_config mode_16k;
};
diff --git a/include/sound/q6adm-v2.h b/include/sound/q6adm-v2.h
index 795bb99..e07f634 100644
--- a/include/sound/q6adm-v2.h
+++ b/include/sound/q6adm-v2.h
@@ -32,7 +32,7 @@
int adm_open(int port, int path, int rate, int mode, int topology,
bool perf_mode, uint16_t bits_per_sample);
-int adm_dolby_dap_get_params(int port_id, uint32_t module_id, uint32_t param_id,
+int adm_get_params(int port_id, uint32_t module_id, uint32_t param_id,
uint32_t params_length, char *params);
int adm_dolby_dap_send_params(int port_id, char *params,
diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h
index 2e4c7c1..12934aa 100644
--- a/include/sound/q6afe-v2.h
+++ b/include/sound/q6afe-v2.h
@@ -83,6 +83,7 @@
IDX_AFE_PORT_ID_PRIMARY_MI2S_TX = 41,
IDX_AFE_PORT_ID_SECONDARY_PCM_RX = 42,
IDX_AFE_PORT_ID_SECONDARY_PCM_TX = 43,
+ IDX_VOICE2_PLAYBACK_TX = 44,
IDX_GLOBAL_CFG,
AFE_MAX_PORTS
};
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index 2138689..4ad1ca9 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -191,6 +191,9 @@
int q6asm_open_read(struct audio_client *ac, uint32_t format
/*, uint16_t bits_per_sample*/);
+int q6asm_open_read_v2(struct audio_client *ac, uint32_t format,
+ uint16_t bits_per_sample);
+
int q6asm_open_write(struct audio_client *ac, uint32_t format
/*, uint16_t bits_per_sample*/);
@@ -252,6 +255,10 @@
int q6asm_enc_cfg_blk_pcm(struct audio_client *ac,
uint32_t rate, uint32_t channels);
+int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ uint16_t bits_per_sample);
+
int q6asm_set_encdec_chan_map(struct audio_client *ac,
uint32_t num_channels);
diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h
index ea7a203..41f8607 100644
--- a/include/trace/events/sched.h
+++ b/include/trace/events/sched.h
@@ -51,6 +51,44 @@
);
/*
+ * Tracepoint for task enqueue/dequeue:
+ */
+TRACE_EVENT(sched_enq_deq_task,
+
+ TP_PROTO(struct task_struct *p, int enqueue),
+
+ TP_ARGS(p, enqueue),
+
+ TP_STRUCT__entry(
+ __array( char, comm, TASK_COMM_LEN )
+ __field( pid_t, pid )
+ __field( int, prio )
+ __field( int, cpu )
+ __field( int, enqueue )
+ __field(unsigned int, nr_running )
+ __field(unsigned long, cpu_load )
+ __field(unsigned int, rt_nr_running )
+ ),
+
+ TP_fast_assign(
+ memcpy(__entry->comm, p->comm, TASK_COMM_LEN);
+ __entry->pid = p->pid;
+ __entry->prio = p->prio;
+ __entry->cpu = task_cpu(p);
+ __entry->enqueue = enqueue;
+ __entry->nr_running = task_rq(p)->nr_running;
+ __entry->cpu_load = task_rq(p)->cpu_load[0];
+ __entry->rt_nr_running = task_rq(p)->rt.rt_nr_running;
+ ),
+
+ TP_printk("cpu=%d %s comm=%s pid=%d prio=%d nr_running=%u cpu_load=%lu rt_nr_running=%u",
+ __entry->cpu, __entry->enqueue ? "enqueue" : "dequeue",
+ __entry->comm, __entry->pid,
+ __entry->prio, __entry->nr_running,
+ __entry->cpu_load, __entry->rt_nr_running)
+);
+
+/*
* Tracepoint for waking up a task:
*/
DECLARE_EVENT_CLASS(sched_wakeup_template,
@@ -179,6 +217,31 @@
__entry->orig_cpu, __entry->dest_cpu)
);
+/*
+ * Tracepoint for a CPU going offline/online:
+ */
+TRACE_EVENT(sched_cpu_hotplug,
+
+ TP_PROTO(int affected_cpu, int error, int status),
+
+ TP_ARGS(affected_cpu, error, status),
+
+ TP_STRUCT__entry(
+ __field( int, affected_cpu )
+ __field( int, error )
+ __field( int, status )
+ ),
+
+ TP_fast_assign(
+ __entry->affected_cpu = affected_cpu;
+ __entry->error = error;
+ __entry->status = status;
+ ),
+
+ TP_printk("cpu %d %s error=%d", __entry->affected_cpu,
+ __entry->status ? "online" : "offline", __entry->error)
+);
+
DECLARE_EVENT_CLASS(sched_process_template,
TP_PROTO(struct task_struct *p),
diff --git a/kernel/cpu.c b/kernel/cpu.c
index fb4a5ac..d5ab2e6 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -17,6 +17,8 @@
#include <linux/gfp.h>
#include <linux/suspend.h>
+#include <trace/events/sched.h>
+
#ifdef CONFIG_SMP
/* Serializes the updates to cpu_online_mask, cpu_present_mask */
static DEFINE_MUTEX(cpu_add_remove_lock);
@@ -264,6 +266,7 @@
out_release:
cpu_hotplug_done();
+ trace_sched_cpu_hotplug(cpu, err, 0);
if (!err)
cpu_notify_nofail(CPU_POST_DEAD | mod, hcpu);
return err;
@@ -321,6 +324,7 @@
if (ret != 0)
__cpu_notify(CPU_UP_CANCELED | mod, hcpu, nr_calls, NULL);
cpu_hotplug_done();
+ trace_sched_cpu_hotplug(cpu, ret, 1);
return ret;
}
diff --git a/kernel/power/earlysuspend.c b/kernel/power/earlysuspend.c
index 5a6b2fa..b15f02e 100644
--- a/kernel/power/earlysuspend.c
+++ b/kernel/power/earlysuspend.c
@@ -17,6 +17,7 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/rtc.h>
+#include <linux/syscalls.h> /* sys_sync */
#include <linux/wakelock.h>
#include <linux/workqueue.h>
@@ -102,7 +103,10 @@
}
mutex_unlock(&early_suspend_lock);
- suspend_sys_sync_queue();
+ if (debug_mask & DEBUG_SUSPEND)
+ pr_info("early_suspend: sync\n");
+
+ sys_sync();
abort:
spin_lock_irqsave(&state_lock, irqflags);
if (state == SUSPEND_REQUESTED_AND_SUSPENDED)
diff --git a/kernel/power/process.c b/kernel/power/process.c
index a63b9c1..31b6f25 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -173,10 +173,6 @@
{
int error;
- error = sys_sync();
- if (error)
- return error;
-
printk("Freezing remaining freezable tasks ... ");
pm_nosig_freezing = true;
error = try_to_freeze_tasks(false);
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
index 424a389..172e415 100644
--- a/kernel/power/suspend.c
+++ b/kernel/power/suspend.c
@@ -279,7 +279,10 @@
if (!mutex_trylock(&pm_mutex))
return -EBUSY;
+ printk(KERN_INFO "PM: Syncing filesystems ... ");
sys_sync();
+ printk("done.\n");
+
pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);
error = suspend_prepare();
if (error)
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 3513fef..d9c4b64 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -727,6 +727,7 @@
update_rq_clock(rq);
sched_info_queued(p);
p->sched_class->enqueue_task(rq, p, flags);
+ trace_sched_enq_deq_task(p, 1);
}
static void dequeue_task(struct rq *rq, struct task_struct *p, int flags)
@@ -734,6 +735,7 @@
update_rq_clock(rq);
sched_info_dequeued(p);
p->sched_class->dequeue_task(rq, p, flags);
+ trace_sched_enq_deq_task(p, 0);
}
void activate_task(struct rq *rq, struct task_struct *p, int flags)
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index f1a6e9e..90fd57d 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -41,6 +41,7 @@
#include <linux/debug_locks.h>
#include <linux/lockdep.h>
#include <linux/idr.h>
+#include <linux/bug.h>
#include "workqueue_sched.h"
@@ -1878,6 +1879,7 @@
printk(KERN_ERR " last function: ");
print_symbol("%s\n", (unsigned long)f);
debug_show_held_locks(current);
+ BUG_ON(PANIC_CORRUPTION);
dump_stack();
}
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 097d70f..b9060a1 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -1290,6 +1290,13 @@
If unsure, say N.
+config PANIC_ON_DATA_CORRUPTION
+ bool "Cause a Kernel Panic When Data Corruption is detected"
+ help
+ Select this option to upgrade warnings for potentially
+ recoverable data corruption scenarios to system-halting panics,
+ for easier detection and debug.
+
source "samples/Kconfig"
source "lib/Kconfig.kgdb"
diff --git a/lib/list_debug.c b/lib/list_debug.c
index 982b850..6a039a6 100644
--- a/lib/list_debug.c
+++ b/lib/list_debug.c
@@ -10,6 +10,7 @@
#include <linux/list.h>
#include <linux/bug.h>
#include <linux/kernel.h>
+#include <linux/bug.h>
/*
* Insert a new entry between two known consecutive entries.
@@ -30,6 +31,10 @@
"list_add corruption. prev->next should be "
"next (%p), but was %p. (prev=%p).\n",
next, prev->next, prev);
+
+ BUG_ON(((prev->next != next) || (next->prev != prev)) &&
+ PANIC_CORRUPTION);
+
next->prev = new;
new->next = next;
new->prev = prev;
@@ -55,8 +60,10 @@
"but was %p\n", entry, prev->next) ||
WARN(next->prev != entry,
"list_del corruption. next->prev should be %p, "
- "but was %p\n", entry, next->prev))
+ "but was %p\n", entry, next->prev)) {
+ BUG_ON(PANIC_CORRUPTION);
return;
+ }
__list_del(prev, next);
}
diff --git a/lib/spinlock_debug.c b/lib/spinlock_debug.c
index f2aa5de..ac516f4 100644
--- a/lib/spinlock_debug.c
+++ b/lib/spinlock_debug.c
@@ -12,6 +12,7 @@
#include <linux/debug_locks.h>
#include <linux/delay.h>
#include <linux/export.h>
+#include <linux/bug.h>
void __raw_spin_lock_init(raw_spinlock_t *lock, const char *name,
struct lock_class_key *key)
@@ -64,6 +65,7 @@
owner ? owner->comm : "<none>",
owner ? task_pid_nr(owner) : -1,
lock->owner_cpu);
+ BUG_ON(PANIC_CORRUPTION);
dump_stack();
}
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 7ffcc1b..9ffd0f1 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -1,6 +1,7 @@
/*
BlueZ - Bluetooth protocol stack for Linux
- Copyright (c) 2000-2001, 2010-2012 The Linux Foundation. All rights reserved.
+ Copyright (c) 2000-2001, The Linux Foundation. All rights reserved.
+ Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
@@ -659,6 +660,9 @@
hci_conn_put_device(conn);
+ if (conn->hidp_session_valid)
+ hci_conn_put_device(conn);
+
hci_dev_put(hdev);
return 0;
@@ -1267,8 +1271,10 @@
void hci_conn_put_device(struct hci_conn *conn)
{
- if (atomic_dec_and_test(&conn->devref))
+ if (atomic_dec_and_test(&conn->devref)) {
+ conn->hidp_session_valid = false;
hci_conn_del_sysfs(conn);
+ }
}
EXPORT_SYMBOL(hci_conn_put_device);
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index 2353e91..e214cb2 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -1,7 +1,7 @@
/*
HIDP implementation for Linux Bluetooth stack (BlueZ).
Copyright (C) 2003-2004 Marcel Holtmann <marcel@holtmann.org>
- 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 as
@@ -108,7 +108,7 @@
hdev = hci_get_route(dst, BDADDR_ANY);
if (hdev) {
session->conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
- if (session->conn)
+ if (session->conn && session->conn->hidp_session_valid)
dev = &session->conn->dev;
hci_dev_put(hdev);
@@ -661,8 +661,10 @@
hci_dev_lock_bh(hdev);
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
- if (conn)
+ if (conn) {
+ conn->hidp_session_valid = true;
hci_conn_hold_device(conn);
+ }
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
diff --git a/net/core/flow.c b/net/core/flow.c
index e318c7e..9a517c6 100644
--- a/net/core/flow.c
+++ b/net/core/flow.c
@@ -423,6 +423,7 @@
if (!fc->percpu)
return -ENOMEM;
+ get_online_cpus();
for_each_online_cpu(i) {
if (flow_cache_cpu_prepare(fc, i))
goto err;
@@ -431,6 +432,7 @@
.notifier_call = flow_cache_cpu,
};
register_hotcpu_notifier(&fc->hotcpu_notifier);
+ put_online_cpus();
setup_timer(&fc->rnd_timer, flow_cache_new_hashrnd,
(unsigned long) fc);
@@ -440,6 +442,7 @@
return 0;
err:
+ put_online_cpus();
for_each_possible_cpu(i) {
struct flow_cache_percpu *fcp = per_cpu_ptr(fc->percpu, i);
kfree(fcp->hash_table);
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index 0c28508..247c69b 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -14,6 +14,7 @@
#include <linux/vmalloc.h>
#include <linux/init.h>
#include <linux/slab.h>
+#include <linux/kmemleak.h>
#include <net/ip.h>
#include <net/sock.h>
@@ -256,7 +257,7 @@
{
static struct ctl_table empty[1];
- register_sysctl_paths(net_core_path, empty);
+ kmemleak_not_leak(register_sysctl_paths(net_core_path, empty));
register_net_sysctl_rotable(net_core_path, net_core_table);
return register_pernet_subsys(&sysctl_core_ops);
}
diff --git a/net/ipv4/netfilter/ipt_NATTYPE.c b/net/ipv4/netfilter/ipt_NATTYPE.c
index f181be4..be405f7 100644
--- a/net/ipv4/netfilter/ipt_NATTYPE.c
+++ b/net/ipv4/netfilter/ipt_NATTYPE.c
@@ -59,7 +59,7 @@
struct list_head list;
struct timer_list timeout;
unsigned long timeout_value;
- unsigned char is_valid;
+ unsigned int nattype_cookie;
unsigned short proto; /* Protocol: TCP or UDP */
struct nf_nat_ipv4_range range; /* LAN side source information */
unsigned short nat_port; /* Routed NAT port */
@@ -67,6 +67,8 @@
unsigned short dest_port;/* Original egress packets destination port */
};
+#define NATTYPE_COOKIE 0x11abcdef
+
/*
* TODO: It might be better to use a hash table for performance in
* heavy traffic.
@@ -109,7 +111,7 @@
if (!nte)
return false;
spin_lock_bh(&nattype_lock);
- if (!nte->is_valid) {
+ if (nte->nattype_cookie != NATTYPE_COOKIE) {
spin_unlock_bh(&nattype_lock);
return false;
}
@@ -483,7 +485,7 @@
add_timer(&nte->timeout);
list_add(&nte->list, &nattype_list);
ct->nattype_entry = (unsigned long)nte;
- nte->is_valid = 1;
+ nte->nattype_cookie = NATTYPE_COOKIE;
spin_unlock_bh(&nattype_lock);
nattype_nte_debug_print(nte, "ADD");
return XT_CONTINUE;
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 167ea10..d02a8da 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -109,6 +109,7 @@
#include <net/rtnetlink.h>
#ifdef CONFIG_SYSCTL
#include <linux/sysctl.h>
+#include <linux/kmemleak.h>
#endif
#include <net/secure_seq.h>
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index d7eafd5..eb535cc 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -716,6 +716,9 @@
/* Don't set timer yet: wait for confirmation */
setup_timer(&ct->timeout, death_by_timeout, (unsigned long)ct);
write_pnet(&ct->ct_net, net);
+#if defined(CONFIG_IP_NF_TARGET_NATTYPE_MODULE)
+ ct->nattype_entry = 0;
+#endif
#ifdef CONFIG_NF_CONNTRACK_ZONES
if (zone) {
struct nf_conntrack_zone *nf_ct_zone;
diff --git a/net/netfilter/xt_qtaguid.c b/net/netfilter/xt_qtaguid.c
index 2b486b1..21d66c2 100644
--- a/net/netfilter/xt_qtaguid.c
+++ b/net/netfilter/xt_qtaguid.c
@@ -1408,12 +1408,15 @@
ifname, uid, sk, direction, proto, bytes);
+ spin_lock_bh(&iface_stat_list_lock);
iface_entry = get_iface_entry(ifname);
if (!iface_entry) {
+ spin_unlock_bh(&iface_stat_list_lock);
pr_err("qtaguid: iface_stat: stat_update() %s not found\n",
ifname);
return;
}
+ spin_unlock_bh(&iface_stat_list_lock);
/* It is ok to process data when an iface_entry is inactive */
MT_DEBUG("qtaguid: iface_stat: stat_update() dev=%s entry=%p\n",
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 2356791..d85cf09 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -648,6 +648,9 @@
struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr;
int err;
+ if (addr_len < sizeof(struct sockaddr_nl))
+ return -EINVAL;
+
if (nladdr->nl_family != AF_NETLINK)
return -EINVAL;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 68fd9d7..1dee449 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -3031,10 +3031,10 @@
params.listen_interval =
nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
- if (info->attrs[NL80211_ATTR_STA_AID])
- params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
- else
+ if (info->attrs[NL80211_ATTR_PEER_AID])
params.aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]);
+ else
+ params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
if (!params.aid || params.aid > IEEE80211_MAX_AID)
return -EINVAL;
@@ -3104,7 +3104,8 @@
params.sta_modify_mask |= STATION_PARAM_APPLY_UAPSD;
}
/* TDLS peers cannot be added */
- if (params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))
+ if ((params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) ||
+ info->attrs[NL80211_ATTR_PEER_AID])
return -EINVAL;
/* but don't bother the driver with it */
params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
@@ -3116,7 +3117,8 @@
break;
case NL80211_IFTYPE_MESH_POINT:
/* TDLS peers cannot be added */
- if (params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))
+ if ((params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) ||
+ info->attrs[NL80211_ATTR_PEER_AID])
return -EINVAL;
break;
case NL80211_IFTYPE_STATION:
diff --git a/scripts/build-all.py b/scripts/build-all.py
index c585e4a..5a109bb 100755
--- a/scripts/build-all.py
+++ b/scripts/build-all.py
@@ -46,8 +46,8 @@
make_env = os.environ
make_env.update({
'ARCH': 'arm',
- 'CROSS_COMPILE': 'arm-none-linux-gnueabi-',
'KCONFIG_NOTIMESTAMP': 'true' })
+make_env.setdefault('CROSS_COMPILE', 'arm-none-linux-gnueabi-')
all_options = {}
def error(msg):
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index 1260e1c..46b0a91 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -35,9 +35,11 @@
#include <sound/soc-dapm.h>
#include <sound/tlv.h>
#include <mach/qdsp6v2/apr.h>
+#include <mach/subsystem_notif.h>
#include "msm8x10-wcd.h"
#include "wcd9xxx-resmgr.h"
#include "msm8x10_wcd_registers.h"
+#include "../msm/qdsp6v2/q6core.h"
#define MSM8X10_WCD_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000)
@@ -58,7 +60,7 @@
#define MAX_MSM8X10_WCD_DEVICE 4
#define CODEC_DT_MAX_PROP_SIZE 40
-#define MSM8X10_WCD_I2C_GSBI_SLAVE_ID "5-000d"
+#define MAX_ON_DEMAND_SUPPLY_NAME_LENGTH 64
enum {
MSM8X10_WCD_I2C_TOP_LEVEL = 0,
@@ -117,6 +119,12 @@
MSM8X10_WCD_BANDGAP_MBHC_MODE,
};
+enum {
+ ON_DEMAND_MICBIAS = 0,
+ ON_DEMAND_CP,
+ ON_DEMAND_SUPPLIES_MAX,
+};
+
struct hpf_work {
struct msm8x10_wcd_priv *msm8x10_wcd;
u32 decimator;
@@ -126,6 +134,16 @@
static struct hpf_work tx_hpf_work[NUM_DECIMATORS];
+struct on_demand_supply {
+ struct regulator *supply;
+ atomic_t ref;
+};
+
+static char on_demand_supply_name[][MAX_ON_DEMAND_SUPPLY_NAME_LENGTH] = {
+ "cdc-vdd-mic-bias",
+ "cdc-vdda-cp",
+};
+
struct msm8x10_wcd_priv {
struct snd_soc_codec *codec;
u32 adc_count;
@@ -136,6 +154,7 @@
bool clock_active;
bool config_mode_active;
bool mbhc_polling_active;
+ struct on_demand_supply on_demand_list[ON_DEMAND_SUPPLIES_MAX];
struct mutex codec_resource_lock;
/* resmgr module */
struct wcd9xxx_resmgr resmgr;
@@ -159,13 +178,9 @@
int mod_id;
};
-static char *msm8x10_wcd_supplies[] = {
- "cdc-vdda-cp", "cdc-vdda-h", "cdc-vdd-px", "cdc-vdd-1p2v",
- "cdc-vdd-mic-bias",
-};
-
static int msm8x10_wcd_dt_parse_vreg_info(struct device *dev,
- struct msm8x10_wcd_regulator *vreg, const char *vreg_name);
+ struct msm8x10_wcd_regulator *vreg,
+ const char *vreg_name, bool ondemand);
static int msm8x10_wcd_dt_parse_micbias_info(struct device *dev,
struct msm8x10_wcd_micbias_setting *micbias);
static struct msm8x10_wcd_pdata *msm8x10_wcd_populate_dt_pdata(
@@ -173,6 +188,11 @@
struct msm8x10_wcd_i2c msm8x10_wcd_modules[MAX_MSM8X10_WCD_DEVICE];
+static void *adsp_state_notifier;
+
+static struct snd_soc_codec *registered_codec;
+#define ADSP_STATE_READY_TIMEOUT_MS 2000
+
static int get_i2c_msm8x10_wcd_device_info(u16 reg,
struct msm8x10_wcd_i2c **msm8x10_wcd)
@@ -449,7 +469,8 @@
static int msm8x10_wcd_dt_parse_vreg_info(struct device *dev,
- struct msm8x10_wcd_regulator *vreg, const char *vreg_name)
+ struct msm8x10_wcd_regulator *vreg, const char *vreg_name,
+ bool ondemand)
{
int len, ret = 0;
const __be32 *prop;
@@ -471,6 +492,7 @@
prop_name, dev->of_node->full_name);
vreg->name = vreg_name;
+ vreg->ondemand = ondemand;
snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
"qcom,%s-voltage", vreg_name);
@@ -479,7 +501,7 @@
if (!prop || (len != (2 * sizeof(__be32)))) {
dev_err(dev, "%s %s property\n",
prop ? "invalid format" : "no", prop_name);
- return -ENODEV;
+ return -EINVAL;
} else {
vreg->min_uV = be32_to_cpup(&prop[0]);
vreg->max_uV = be32_to_cpup(&prop[1]);
@@ -492,12 +514,12 @@
if (ret) {
dev_err(dev, "Looking up %s property in node %s failed",
prop_name, dev->of_node->full_name);
- return -ENODEV;
+ return -EFAULT;
}
vreg->optimum_uA = prop_val;
- dev_info(dev, "%s: vol=[%d %d]uV, curr=[%d]uA\n", vreg->name,
- vreg->min_uV, vreg->max_uV, vreg->optimum_uA);
+ dev_info(dev, "%s: vol=[%d %d]uV, curr=[%d]uA, ond %d\n\n", vreg->name,
+ vreg->min_uV, vreg->max_uV, vreg->optimum_uA, vreg->ondemand);
return 0;
}
@@ -545,38 +567,72 @@
struct device *dev)
{
struct msm8x10_wcd_pdata *pdata;
- int ret = 0, i;
- char **codec_supplies;
- u32 num_of_supplies = 0;
+ int ret, static_cnt, ond_cnt, idx, i;
+ const char *name = NULL;
+ const char *static_prop_name = "qcom,cdc-static-supplies";
+ const char *ond_prop_name = "qcom,cdc-on-demand-supplies";
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
dev_err(dev, "could not allocate memory for platform data\n");
return NULL;
}
- if ((!strcmp(dev_name(dev), MSM8X10_WCD_I2C_GSBI_SLAVE_ID))) {
- codec_supplies = msm8x10_wcd_supplies;
- num_of_supplies = ARRAY_SIZE(msm8x10_wcd_supplies);
- } else {
- dev_err(dev, "%s unsupported device %s\n",
- __func__, dev_name(dev));
+
+ static_cnt = of_property_count_strings(dev->of_node, static_prop_name);
+ if (IS_ERR_VALUE(static_cnt)) {
+ dev_err(dev, "%s: Failed to get static supplies %d\n", __func__,
+ static_cnt);
+ ret = -EINVAL;
goto err;
}
- if (num_of_supplies > ARRAY_SIZE(pdata->regulator)) {
+ /* On-demand supply list is an optional property */
+ ond_cnt = of_property_count_strings(dev->of_node, ond_prop_name);
+ if (IS_ERR_VALUE(ond_cnt))
+ ond_cnt = 0;
+
+ BUG_ON(static_cnt <= 0 || ond_cnt < 0);
+ if ((static_cnt + ond_cnt) > ARRAY_SIZE(pdata->regulator)) {
dev_err(dev, "%s: Num of supplies %u > max supported %u\n",
- __func__, num_of_supplies,
- ARRAY_SIZE(pdata->regulator));
-
+ __func__, static_cnt, ARRAY_SIZE(pdata->regulator));
+ ret = -EINVAL;
goto err;
}
- for (i = 0; i < num_of_supplies; i++) {
- ret = msm8x10_wcd_dt_parse_vreg_info(dev, &pdata->regulator[i],
- codec_supplies[i]);
+ for (idx = 0; idx < static_cnt; idx++) {
+ ret = of_property_read_string_index(dev->of_node,
+ static_prop_name, idx,
+ &name);
+ if (ret) {
+ dev_err(dev, "%s: of read string %s idx %d error %d\n",
+ __func__, static_prop_name, idx, ret);
+ goto err;
+ }
+
+ dev_dbg(dev, "%s: Found static cdc supply %s\n", __func__,
+ name);
+ ret = msm8x10_wcd_dt_parse_vreg_info(dev,
+ &pdata->regulator[idx],
+ name, false);
if (ret)
goto err;
}
+
+ for (i = 0; i < ond_cnt; i++, idx++) {
+ ret = of_property_read_string_index(dev->of_node, ond_prop_name,
+ i, &name);
+ if (ret)
+ goto err;
+
+ dev_dbg(dev, "%s: Found on-demand cdc supply %s\n", __func__,
+ name);
+ ret = msm8x10_wcd_dt_parse_vreg_info(dev,
+ &pdata->regulator[idx],
+ name, true);
+ if (ret)
+ goto err;
+ }
+
ret = msm8x10_wcd_dt_parse_micbias_info(dev, &pdata->micbias);
if (ret)
goto err;
@@ -588,12 +644,64 @@
return NULL;
}
+static int msm8x10_wcd_codec_enable_on_demand_supply(
+ struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ int ret = 0;
+ struct snd_soc_codec *codec = w->codec;
+ struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
+ struct on_demand_supply *supply;
+
+ if (w->shift >= ON_DEMAND_SUPPLIES_MAX) {
+ ret = -EINVAL;
+ goto out;
+ }
+ dev_dbg(codec->dev, "%s: supply: %s event: %d ref: %d\n",
+ __func__, on_demand_supply_name[w->shift], event,
+ atomic_read(&msm8x10_wcd->on_demand_list[w->shift].ref));
+
+ supply = &msm8x10_wcd->on_demand_list[w->shift];
+ WARN_ONCE(!supply->supply, "%s isn't defined\n",
+ on_demand_supply_name[w->shift]);
+ if (!supply->supply)
+ goto out;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (atomic_inc_return(&supply->ref) == 1)
+ ret = regulator_enable(supply->supply);
+ if (ret)
+ dev_err(codec->dev, "%s: Failed to enable %s\n",
+ __func__,
+ on_demand_supply_name[w->shift]);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (atomic_read(&supply->ref) == 0) {
+ dev_dbg(codec->dev, "%s: %s supply has been disabled.\n",
+ __func__, on_demand_supply_name[w->shift]);
+ goto out;
+ }
+ if (atomic_dec_return(&supply->ref) == 0)
+ ret = regulator_disable(supply->supply);
+ if (ret)
+ dev_err(codec->dev, "%s: Failed to disable %s\n",
+ __func__,
+ on_demand_supply_name[w->shift]);
+ break;
+ default:
+ break;
+ }
+out:
+ return ret;
+}
+
static int msm8x10_wcd_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
- dev_dbg(codec->dev, "%s: event = %d\n", __func__, event);
+ dev_dbg(codec->dev, "%s: event = %d\n", __func__, event);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
/* Enable charge pump clock*/
@@ -625,6 +733,8 @@
snd_soc_update_bits(codec,
MSM8X10_WCD_A_CP_STATIC, 0x08, 0x00);
break;
+ default:
+ break;
}
return 0;
}
@@ -1728,6 +1838,7 @@
{"LINEOUT PA", NULL, "CP"},
{"LINEOUT PA", NULL, "LINEOUT DAC"},
+ {"CP", NULL, "CP_REGULATOR"},
{"CP", NULL, "RX_BIAS"},
{"SPK PA", NULL, "SPK DAC"},
{"SPK DAC", NULL, "RX3 CHAIN"},
@@ -1807,6 +1918,9 @@
{"MIC BIAS Internal1", NULL, "INT_LDO_H"},
{"MIC BIAS Internal2", NULL, "INT_LDO_H"},
{"MIC BIAS External", NULL, "INT_LDO_H"},
+ {"MIC BIAS Internal1", NULL, "MICBIAS_REGULATOR"},
+ {"MIC BIAS Internal2", NULL, "MICBIAS_REGULATOR"},
+ {"MIC BIAS External", NULL, "MICBIAS_REGULATOR"},
};
static int msm8x10_wcd_startup(struct snd_pcm_substream *substream,
@@ -2227,9 +2341,21 @@
SND_SOC_DAPM_MUX("RX2 MIX2 INP1", SND_SOC_NOPM, 0, 0,
&rx2_mix2_inp1_mux),
+ SND_SOC_DAPM_SUPPLY("MICBIAS_REGULATOR", SND_SOC_NOPM,
+ ON_DEMAND_MICBIAS, 0,
+ msm8x10_wcd_codec_enable_on_demand_supply,
+ SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY("CP_REGULATOR", SND_SOC_NOPM,
+ ON_DEMAND_CP, 0,
+ msm8x10_wcd_codec_enable_on_demand_supply,
+ SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
SND_SOC_DAPM_SUPPLY("CP", MSM8X10_WCD_A_CP_EN, 0, 0,
- msm8x10_wcd_codec_enable_charge_pump, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ msm8x10_wcd_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
msm8x10_wcd_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
@@ -2415,6 +2541,68 @@
return 0;
}
+static struct regulator *wcd8x10_wcd_codec_find_regulator(
+ const struct msm8x10_wcd *msm8x10,
+ const char *name)
+{
+ int i;
+
+ for (i = 0; i < msm8x10->num_of_supplies; i++) {
+ if (msm8x10->supplies[i].supply &&
+ !strncmp(msm8x10->supplies[i].supply, name, strlen(name)))
+ return msm8x10->supplies[i].consumer;
+ }
+
+ return NULL;
+}
+
+static int msm8x10_wcd_device_up(struct snd_soc_codec *codec)
+{
+ pr_debug("%s: device up!\n", __func__);
+
+ mutex_lock(&codec->mutex);
+
+ msm8x10_wcd_bringup(codec);
+ msm8x10_wcd_codec_init_reg(codec);
+ msm8x10_wcd_update_reg_defaults(codec);
+
+ mutex_unlock(&codec->mutex);
+
+ return 0;
+}
+
+static int adsp_state_callback(struct notifier_block *nb, unsigned long value,
+ void *priv)
+{
+ bool timedout;
+ unsigned long timeout;
+
+ if (value == SUBSYS_AFTER_POWERUP) {
+ pr_debug("%s: ADSP is about to power up. bring up codec\n",
+ __func__);
+
+ timeout = jiffies +
+ msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS);
+ while (!(timedout = time_after(jiffies, timeout))) {
+ if (!q6core_is_adsp_ready()) {
+ pr_debug("%s: ADSP isn't ready\n", __func__);
+ } else {
+ pr_debug("%s: ADSP is ready\n", __func__);
+ msm8x10_wcd_device_up(registered_codec);
+ break;
+ }
+ }
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block adsp_state_notifier_block = {
+ .notifier_call = adsp_state_callback,
+ .priority = -INT_MAX,
+};
+
+
static int msm8x10_wcd_codec_probe(struct snd_soc_codec *codec)
{
struct msm8x10_wcd_priv *msm8x10_wcd;
@@ -2440,20 +2628,43 @@
msm8x10_wcd_bringup(codec);
msm8x10_wcd_codec_init_reg(codec);
msm8x10_wcd_update_reg_defaults(codec);
-
+ msm8x10_wcd->on_demand_list[ON_DEMAND_CP].supply =
+ wcd8x10_wcd_codec_find_regulator(
+ codec->control_data,
+ on_demand_supply_name[ON_DEMAND_CP]);
+ atomic_set(&msm8x10_wcd->on_demand_list[ON_DEMAND_CP].ref, 0);
+ msm8x10_wcd->on_demand_list[ON_DEMAND_MICBIAS].supply =
+ wcd8x10_wcd_codec_find_regulator(
+ codec->control_data,
+ on_demand_supply_name[ON_DEMAND_MICBIAS]);
+ atomic_set(&msm8x10_wcd->on_demand_list[ON_DEMAND_MICBIAS].ref, 0);
msm8x10_wcd->mclk_enabled = false;
msm8x10_wcd->bandgap_type = MSM8X10_WCD_BANDGAP_OFF;
msm8x10_wcd->clock_active = false;
msm8x10_wcd->config_mode_active = false;
msm8x10_wcd->mbhc_polling_active = false;
mutex_init(&msm8x10_wcd->codec_resource_lock);
- msm8x10_wcd->codec = codec;
+ registered_codec = codec;
+ 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__);
+ registered_codec = NULL;
+ return -ENOMEM;
+ }
return 0;
}
static int msm8x10_wcd_codec_remove(struct snd_soc_codec *codec)
{
+ struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
+ msm8x10_wcd->on_demand_list[ON_DEMAND_CP].supply = NULL;
+ atomic_set(&msm8x10_wcd->on_demand_list[ON_DEMAND_CP].ref, 0);
+ msm8x10_wcd->on_demand_list[ON_DEMAND_MICBIAS].supply = NULL;
+ atomic_set(&msm8x10_wcd->on_demand_list[ON_DEMAND_MICBIAS].ref, 0);
return 0;
}
@@ -2479,7 +2690,7 @@
.num_dapm_routes = ARRAY_SIZE(audio_map),
};
-static int msm8x10_wcd_enable_supplies(struct msm8x10_wcd *msm8x10,
+static int msm8x10_wcd_init_supplies(struct msm8x10_wcd *msm8x10,
struct msm8x10_wcd_pdata *pdata)
{
int ret;
@@ -2517,8 +2728,13 @@
}
for (i = 0; i < msm8x10->num_of_supplies; i++) {
+ if (regulator_count_voltages(msm8x10->supplies[i].consumer) <=
+ 0)
+ continue;
+
ret = regulator_set_voltage(msm8x10->supplies[i].consumer,
- pdata->regulator[i].min_uV, pdata->regulator[i].max_uV);
+ pdata->regulator[i].min_uV,
+ pdata->regulator[i].max_uV);
if (ret) {
dev_err(msm8x10->dev, "%s: Setting regulator voltage failed for regulator %s err = %d\n",
__func__, msm8x10->supplies[i].supply, ret);
@@ -2531,24 +2747,13 @@
dev_err(msm8x10->dev, "%s: Setting regulator optimum mode failed for regulator %s err = %d\n",
__func__, msm8x10->supplies[i].supply, ret);
goto err_get;
+ } else {
+ ret = 0;
}
}
- ret = regulator_bulk_enable(msm8x10->num_of_supplies,
- msm8x10->supplies);
- if (ret != 0) {
- dev_err(msm8x10->dev, "Failed to enable supplies: err = %d\n",
- ret);
- goto err_configure;
- }
return ret;
-err_configure:
- for (i = 0; i < msm8x10->num_of_supplies; i++) {
- regulator_set_voltage(msm8x10->supplies[i].consumer, 0,
- pdata->regulator[i].max_uV);
- regulator_set_optimum_mode(msm8x10->supplies[i].consumer, 0);
- }
err_get:
regulator_bulk_free(msm8x10->num_of_supplies, msm8x10->supplies);
err_supplies:
@@ -2557,6 +2762,35 @@
return ret;
}
+static int msm8x10_wcd_enable_static_supplies(struct msm8x10_wcd *msm8x10,
+ struct msm8x10_wcd_pdata *pdata)
+{
+ int i;
+ int ret = 0;
+
+ for (i = 0; i < msm8x10->num_of_supplies; i++) {
+ if (pdata->regulator[i].ondemand)
+ continue;
+ ret = regulator_enable(msm8x10->supplies[i].consumer);
+ if (ret) {
+ pr_err("%s: Failed to enable %s\n", __func__,
+ msm8x10->supplies[i].supply);
+ break;
+ } else {
+ pr_debug("%s: Enabled regulator %s\n", __func__,
+ msm8x10->supplies[i].supply);
+ }
+ }
+
+ while (ret && --i)
+ if (!pdata->regulator[i].ondemand)
+ regulator_disable(msm8x10->supplies[i].consumer);
+
+ return ret;
+}
+
+
+
static void msm8x10_wcd_disable_supplies(struct msm8x10_wcd *msm8x10,
struct msm8x10_wcd_pdata *pdata)
{
@@ -2565,6 +2799,9 @@
regulator_bulk_disable(msm8x10->num_of_supplies,
msm8x10->supplies);
for (i = 0; i < msm8x10->num_of_supplies; i++) {
+ if (regulator_count_voltages(msm8x10->supplies[i].consumer) <=
+ 0)
+ continue;
regulator_set_voltage(msm8x10->supplies[i].consumer, 0,
pdata->regulator[i].max_uV);
regulator_set_optimum_mode(msm8x10->supplies[i].consumer, 0);
@@ -2654,6 +2891,7 @@
if (client->addr != HELICON_CORE_0_I2C_ADDR)
goto rtn;
+ dev_set_name(&client->dev, "%s", MSM8X10_CODEC_NAME);
dev = &client->dev;
if (client->dev.of_node) {
dev_dbg(&client->dev, "%s:Platform data from device tree\n",
@@ -2677,12 +2915,21 @@
msm8x10->dev = &client->dev;
msm8x10->read_dev = msm8x10_wcd_reg_read;
msm8x10->write_dev = msm8x10_wcd_reg_write;
- ret = msm8x10_wcd_enable_supplies(msm8x10, pdata);
+ ret = msm8x10_wcd_init_supplies(msm8x10, pdata);
if (ret) {
dev_err(&client->dev, "%s: Fail to enable Codec supplies\n",
__func__);
goto err_codec;
}
+
+ ret = msm8x10_wcd_enable_static_supplies(msm8x10, pdata);
+ if (ret) {
+ pr_err("%s: Fail to enable Codec pre-reset supplies\n",
+ __func__);
+ goto err_codec;
+ }
+ usleep_range(5, 5);
+
ret = msm8x10_wcd_device_init(msm8x10);
if (ret) {
dev_err(&client->dev,
diff --git a/sound/soc/codecs/msm8x10-wcd.h b/sound/soc/codecs/msm8x10-wcd.h
index 08a2725..8e561cf 100644
--- a/sound/soc/codecs/msm8x10-wcd.h
+++ b/sound/soc/codecs/msm8x10-wcd.h
@@ -32,6 +32,7 @@
#define MSM8X10_DINO_LPASS_DIGCODEC_CBCR 0xFE02C014
#define MSM8X10_DINO_LPASS_DIGCODEC_AHB_CBCR 0xFE02C018
+#define MSM8X10_CODEC_NAME "msm8x10_wcd_codec"
#define MSM8X10_WCD_IS_DINO_REG(reg) \
(((reg >= 0x400) && (reg <= 0x5FF)) ? 1 : 0)
@@ -147,6 +148,7 @@
int min_uV;
int max_uV;
int optimum_uA;
+ bool ondemand;
struct regulator *regulator;
};
diff --git a/sound/soc/codecs/msm_hdmi_codec_rx.c b/sound/soc/codecs/msm_hdmi_codec_rx.c
index 46bce9e..e5d5c32 100644
--- a/sound/soc/codecs/msm_hdmi_codec_rx.c
+++ b/sound/soc/codecs/msm_hdmi_codec_rx.c
@@ -113,7 +113,7 @@
channel_allocation);
codec_data->hdmi_ops.audio_info_setup(codec_data->hdmi_core_pdev,
- num_channels, channel_allocation,
+ params_rate(params), num_channels, channel_allocation,
level_shift, down_mix);
return 0;
diff --git a/sound/soc/codecs/msm_stub.c b/sound/soc/codecs/msm_stub.c
index 0cbcaf3..bdf1eb4 100644
--- a/sound/soc/codecs/msm_stub.c
+++ b/sound/soc/codecs/msm_stub.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, 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
@@ -36,7 +36,8 @@
.channels_min = 1,
.channels_max = 8,
.rates = SNDRV_PCM_RATE_8000_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
},
},
};
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index b31c7c9..a6390dd 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -4273,6 +4273,12 @@
*/
TAPAN_REG_VAL(TAPAN_A_MICB_2_MBHC, 0x41),
+ /*
+ * Default register settings to support dynamic change of
+ * vdd_buck between 1.8 volts and 2.15 volts.
+ */
+ TAPAN_REG_VAL(TAPAN_A_BUCK_MODE_2, 0xAA),
+
};
static const struct tapan_reg_mask_val tapan_2_x_reg_reset_values[] = {
@@ -4548,7 +4554,6 @@
}
}
- wcd9xxx_resmgr_post_ssr(&tapan->resmgr);
if (spkr_drv_wrnd == 1)
snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80, 0x80);
@@ -4561,6 +4566,8 @@
tapan_slim_interface_init_reg(codec);
+ wcd9xxx_resmgr_post_ssr(&tapan->resmgr);
+
wcd9xxx_mbhc_deinit(&tapan->mbhc);
if (TAPAN_IS_1_0(wcd9xxx->version))
@@ -4569,7 +4576,7 @@
rco_clk_rate = TAPAN_MCLK_CLK_9P6MHZ;
ret = wcd9xxx_mbhc_init(&tapan->mbhc, &tapan->resmgr, codec, NULL,
- &mbhc_cb, rco_clk_rate);
+ &mbhc_cb, rco_clk_rate, false);
if (ret)
pr_err("%s: mbhc init failed %d\n", __func__, ret);
else
@@ -4589,6 +4596,30 @@
return 0;
}
+static enum wcd9xxx_buck_volt tapan_codec_get_buck_mv(
+ struct snd_soc_codec *codec)
+{
+ int buck_volt = WCD9XXX_CDC_BUCK_UNSUPPORTED;
+ struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
+ struct wcd9xxx_pdata *pdata = tapan->resmgr.pdata;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
+ if (!strncmp(pdata->regulator[i].name,
+ WCD9XXX_SUPPLY_BUCK_NAME,
+ sizeof(WCD9XXX_SUPPLY_BUCK_NAME))) {
+ if ((pdata->regulator[i].min_uV ==
+ WCD9XXX_CDC_BUCK_MV_1P8) ||
+ (pdata->regulator[i].min_uV ==
+ WCD9XXX_CDC_BUCK_MV_2P15))
+ buck_volt = pdata->regulator[i].min_uV;
+ break;
+ }
+ }
+ pr_debug("%s: S4 voltage requested is %d\n", __func__, buck_volt);
+ return buck_volt;
+}
+
static int tapan_codec_probe(struct snd_soc_codec *codec)
{
struct wcd9xxx *control;
@@ -4621,10 +4652,6 @@
snd_soc_codec_set_drvdata(codec, tapan);
- /* TODO: Read buck voltage from DT property */
- tapan->clsh_d.buck_mv = WCD9XXX_CDC_BUCK_MV_1P8;
- wcd9xxx_clsh_init(&tapan->clsh_d, &tapan->resmgr);
-
/* codec resmgr module init */
wcd9xxx = codec->control_data;
pdata = dev_get_platdata(codec->dev->parent);
@@ -4635,13 +4662,23 @@
return ret;
}
+ tapan->clsh_d.buck_mv = tapan_codec_get_buck_mv(codec);
+ /*
+ * If 1.8 volts is requested on the vdd_cp line, then
+ * assume that S4 is in a dynamically switchable state
+ * and can switch between 1.8 volts and 2.15 volts
+ */
+ if (tapan->clsh_d.buck_mv == WCD9XXX_CDC_BUCK_MV_1P8)
+ tapan->clsh_d.is_dynamic_vdd_cp = true;
+ wcd9xxx_clsh_init(&tapan->clsh_d, &tapan->resmgr);
+
if (TAPAN_IS_1_0(control->version))
rco_clk_rate = TAPAN_MCLK_CLK_12P288MHZ;
else
rco_clk_rate = TAPAN_MCLK_CLK_9P6MHZ;
ret = wcd9xxx_mbhc_init(&tapan->mbhc, &tapan->resmgr, codec, NULL,
- &mbhc_cb, rco_clk_rate);
+ &mbhc_cb, rco_clk_rate, false);
if (ret) {
pr_err("%s: mbhc init failed %d\n", __func__, ret);
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 69e4cca..212924fd 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -2639,17 +2639,31 @@
case SND_SOC_DAPM_PRE_PMU:
(*dmic_clk_cnt)++;
- if (*dmic_clk_cnt == 1)
+ if (*dmic_clk_cnt == 1) {
+ snd_soc_update_bits(codec,
+ TABLA_A_CDC_DMIC_CLK0_MODE, 0x7, 0x0);
+ snd_soc_update_bits(codec,
+ TABLA_A_CDC_DMIC_CLK1_MODE, 0x7, 0x0);
+ snd_soc_update_bits(codec,
+ TABLA_A_CDC_DMIC_CLK2_MODE, 0x7, 0x0);
snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
dmic_clk_en, dmic_clk_en);
+ }
break;
case SND_SOC_DAPM_POST_PMD:
(*dmic_clk_cnt)--;
- if (*dmic_clk_cnt == 0)
+ if (*dmic_clk_cnt == 0) {
snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
dmic_clk_en, 0);
+ snd_soc_update_bits(codec,
+ TABLA_A_CDC_DMIC_CLK0_MODE, 0x7, 0x4);
+ snd_soc_update_bits(codec,
+ TABLA_A_CDC_DMIC_CLK1_MODE, 0x7, 0x4);
+ snd_soc_update_bits(codec,
+ TABLA_A_CDC_DMIC_CLK2_MODE, 0x7, 0x4);
+ }
break;
}
return 0;
@@ -8772,6 +8786,13 @@
tabla_2_higher_codec_reg_init_val[i].mask,
tabla_2_higher_codec_reg_init_val[i].val);
}
+ snd_soc_update_bits(codec, TABLA_A_CDC_DMIC_CLK0_MODE, 0x7, 0x4);
+ snd_soc_update_bits(codec, TABLA_A_CDC_DMIC_CLK1_MODE, 0x7, 0x4);
+ snd_soc_update_bits(codec, TABLA_A_CDC_DMIC_CLK2_MODE, 0x7, 0x4);
+ snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x90, 0x90);
+ snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x8, 0x8);
+ snd_soc_update_bits(codec, TABLA_A_PIN_CTL_DATA0, 0x90, 0x0);
+ snd_soc_update_bits(codec, TABLA_A_PIN_CTL_DATA1, 0x8, 0x0);
}
static void tabla_update_reg_address(struct tabla_priv *priv)
diff --git a/sound/soc/codecs/wcd9320-tables.c b/sound/soc/codecs/wcd9320-tables.c
index e834b80..af9725c 100644
--- a/sound/soc/codecs/wcd9320-tables.c
+++ b/sound/soc/codecs/wcd9320-tables.c
@@ -680,7 +680,10 @@
[TAIKO_A_CDC_SPKR_CLIPDET_VAL5] = 1,
[TAIKO_A_CDC_SPKR_CLIPDET_VAL6] = 1,
[TAIKO_A_CDC_SPKR_CLIPDET_VAL7] = 1,
-
+ [TAIKO_A_CDC_PA_RAMP_B1_CTL] = 1,
+ [TAIKO_A_CDC_PA_RAMP_B2_CTL] = 1,
+ [TAIKO_A_CDC_PA_RAMP_B3_CTL] = 1,
+ [TAIKO_A_CDC_PA_RAMP_B4_CTL] = 1,
};
const u8 taiko_reset_reg_defaults[TAIKO_CACHE_SIZE] = {
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 516ac4f..c27e085 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -1050,7 +1050,7 @@
0x07, rate);
/* Set the static gain offset */
if (comp == COMPANDER_1
- && buck_mv == WCD9XXX_CDC_BUCK_MV_2P15) {
+ && buck_mv == WCD9XXX_CDC_BUCK_MV_1P8) {
snd_soc_update_bits(codec,
TAIKO_A_CDC_COMP0_B4_CTL + (comp * 8),
0x80, 0x80);
@@ -1456,6 +1456,32 @@
analog_gain),
};
+static int taiko_hph_impedance_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ uint32_t zl, zr;
+ bool hphr;
+ struct soc_multi_mixer_control *mc;
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct taiko_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+ mc = (struct soc_multi_mixer_control *)(kcontrol->private_value);
+
+ hphr = mc->shift;
+ wcd9xxx_mbhc_get_impedance(&priv->mbhc, &zl, &zr);
+ pr_debug("%s: zl %u, zr %u\n", __func__, zl, zr);
+ ucontrol->value.integer.value[0] = hphr ? zr : zl;
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new impedance_detect_controls[] = {
+ SOC_SINGLE_EXT("HPHL Impedance", 0, 0, UINT_MAX, 0,
+ taiko_hph_impedance_get, NULL),
+ SOC_SINGLE_EXT("HPHR Impedance", 0, 1, UINT_MAX, 0,
+ taiko_hph_impedance_get, NULL),
+};
+
static const char * const rx_mix1_text[] = {
"ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
"RX5", "RX6", "RX7"
@@ -3070,6 +3096,8 @@
{
struct snd_soc_codec *codec = w->codec;
struct taiko_priv *taiko_p = snd_soc_codec_get_drvdata(codec);
+ uint32_t impedl, impedr;
+ int ret = 0;
pr_debug("%s %s %d\n", __func__, w->name, event);
@@ -3081,6 +3109,13 @@
WCD9XXX_CLSH_STATE_HPHL,
WCD9XXX_CLSH_REQ_ENABLE,
WCD9XXX_CLSH_EVENT_PRE_DAC);
+ ret = wcd9xxx_mbhc_get_impedance(&taiko_p->mbhc,
+ &impedl, &impedr);
+ if (!ret)
+ wcd9xxx_clsh_imped_config(codec, impedl);
+ else
+ dev_err(codec->dev, "Failed to get mbhc impedance %d\n",
+ ret);
break;
case SND_SOC_DAPM_POST_PMD:
snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_RDAC_CLK_EN_CTL,
@@ -6195,7 +6230,6 @@
codec->reg_size, GFP_KERNEL);
}
- wcd9xxx_resmgr_post_ssr(&taiko->resmgr);
if (spkr_drv_wrnd == 1)
snd_soc_update_bits(codec, TAIKO_A_SPKR_DRV_EN, 0x80, 0x80);
@@ -6208,6 +6242,8 @@
taiko_init_slim_slave_cfg(codec);
taiko_slim_interface_init_reg(codec);
+ wcd9xxx_resmgr_post_ssr(&taiko->resmgr);
+
if (taiko->mbhc_started) {
wcd9xxx_mbhc_deinit(&taiko->mbhc);
taiko->mbhc_started = false;
@@ -6219,7 +6255,7 @@
ret = wcd9xxx_mbhc_init(&taiko->mbhc, &taiko->resmgr, codec,
taiko_enable_mbhc_micbias,
- NULL, rco_clk_rate);
+ NULL, rco_clk_rate, true);
if (ret) {
pr_err("%s: mbhc init failed %d\n", __func__, ret);
} else {
@@ -6389,6 +6425,8 @@
}
taiko->clsh_d.buck_mv = taiko_codec_get_buck_mv(codec);
+ /* Taiko does not support dynamic switching of vdd_cp */
+ taiko->clsh_d.is_dynamic_vdd_cp = false;
wcd9xxx_clsh_init(&taiko->clsh_d, &taiko->resmgr);
if (TAIKO_IS_1_0(core->version))
@@ -6399,7 +6437,7 @@
/* init and start mbhc */
ret = wcd9xxx_mbhc_init(&taiko->mbhc, &taiko->resmgr, codec,
taiko_enable_mbhc_micbias,
- NULL, rco_clk_rate);
+ NULL, rco_clk_rate, true);
if (ret) {
pr_err("%s: mbhc init failed %d\n", __func__, ret);
goto err_init;
@@ -6489,6 +6527,9 @@
ARRAY_SIZE(taiko_2_x_analog_gain_controls));
}
+ snd_soc_add_codec_controls(codec, impedance_detect_controls,
+ ARRAY_SIZE(impedance_detect_controls));
+
control->num_rx_port = TAIKO_RX_MAX;
control->rx_chs = ptr;
memcpy(control->rx_chs, taiko_rx_chs, sizeof(taiko_rx_chs));
diff --git a/sound/soc/codecs/wcd9xxx-common.c b/sound/soc/codecs/wcd9xxx-common.c
index 916ff1a..d00b843 100644
--- a/sound/soc/codecs/wcd9xxx-common.c
+++ b/sound/soc/codecs/wcd9xxx-common.c
@@ -30,6 +30,387 @@
#define BUCK_SETTLE_TIME_US 50
#define NCP_SETTLE_TIME_US 50
+#define MAX_IMPED_PARAMS 13
+
+struct wcd9xxx_imped_val {
+ u32 imped_val;
+ u8 index;
+};
+
+static const struct wcd9xxx_reg_mask_val imped_table[][MAX_IMPED_PARAMS] = {
+ {
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x46},
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x04},
+ {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x11},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x02},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x9B},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x02},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x15},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1C},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x04},
+ {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x0C},
+ },
+ {
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x47},
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x05},
+ {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x11},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x02},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x9B},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x02},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x15},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1C},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x05},
+ {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x0C},
+ },
+ {
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x49},
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x07},
+ {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x02},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x12},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x35},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x4E},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x06},
+ {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x0E},
+ },
+ {
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x49},
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x16},
+ {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAC},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x02},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x17},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x5F},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xCF},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x06},
+ {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x0F},
+ },
+ {
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x59},
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x15},
+ {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x9C},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x02},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1B},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xCE},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xBD},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x07},
+ {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x10},
+ },
+ {
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x66},
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x04},
+ {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x9A},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x02},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2E},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xBD},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xA6},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x07},
+ {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x11},
+ },
+ {
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x79},
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x04},
+ {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x11},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x37},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xA6},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAD},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x08},
+ {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x12},
+ },
+ {
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x76},
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x04},
+ {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x11},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x4E},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAD},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAC},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x09},
+ {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x12},
+ },
+ {
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x78},
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x05},
+ {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x12},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xD0},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAC},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x13},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x0A},
+ {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x13},
+ },
+ {
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x7A},
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x06},
+ {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x14},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xB7},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x13},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x14},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x0B},
+ {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x14},
+ },
+ {
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x60},
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x09},
+ {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1C},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xA4},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x14},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1F},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x0C},
+ {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x14},
+ },
+ {
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x79},
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x17},
+ {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x25},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAE},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1F},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1D},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x0D},
+ {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x15},
+ },
+ {
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x78},
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x16},
+ {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2C},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAC},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1D},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1C},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x0E},
+ {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x16},
+ },
+ {
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x89},
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x05},
+ {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x40},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x13},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1C},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1B},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x10},
+ {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x16},
+ },
+ {
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x97},
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x05},
+ {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xD0},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x14},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1B},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1B},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x12},
+ {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x17},
+ },
+ {
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x8A},
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x06},
+ {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xB7},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x10},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1B},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x24},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x13},
+ {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x17},
+ },
+ {
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x8A},
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x07},
+ {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xA4},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1D},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x24},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x25},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x15},
+ {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x18},
+ },
+ {
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x9A},
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x08},
+ {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAE},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1C},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x25},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x27},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x18},
+ {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x19},
+ },
+ {
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x8B},
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x18},
+ {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAC},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1B},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x20},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2E},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x1A},
+ {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x19},
+ },
+ {
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x9A},
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x17},
+ {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x13},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1B},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2E},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2D},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x1D},
+ {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x1A},
+ },
+ {
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0xA9},
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x06},
+ {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x14},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x24},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2D},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2C},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x1F},
+ {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x19},
+ },
+ {
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0xB9},
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x06},
+ {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x10},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x25},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2C},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2C},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x23},
+ {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x18},
+ },
+ {
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0xA9},
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x07},
+ {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1D},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x27},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2C},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x35},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x26},
+ {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x16},
+ },
+};
+
+static const struct wcd9xxx_imped_val imped_index[] = {
+ {4000, 0},
+ {4500, 1},
+ {5000, 2},
+ {5500, 3},
+ {6000, 4},
+ {6500, 5},
+ {7000, 6},
+ {7700, 7},
+ {8470, 8},
+ {9317, 9},
+ {10248, 10},
+ {11273, 11},
+ {12400, 12},
+ {13641, 13},
+ {15005, 14},
+ {16505, 15},
+ {18156, 16},
+ {19971, 17},
+ {21969, 18},
+ {24165, 19},
+ {26582, 20},
+ {29240, 21},
+ {32164, 22},
+};
+
static inline void wcd9xxx_enable_clsh_block(
struct snd_soc_codec *codec,
bool on)
@@ -165,6 +546,40 @@
}
}
+static int get_impedance_index(u32 imped)
+{
+ int i = 0;
+ if (imped < imped_index[i].imped_val) {
+ pr_debug("%s, detected impedance is less than 4 Ohm\n",
+ __func__);
+ goto ret;
+ }
+ for (i = 0; i < ARRAY_SIZE(imped_index); i++) {
+ if (imped >= imped_index[i].imped_val &&
+ imped < imped_index[i + 1].imped_val)
+ break;
+ }
+ret:
+ pr_debug("%s: selected impedance index = %d\n",
+ __func__, imped_index[i].index);
+ return imped_index[i].index;
+}
+
+void wcd9xxx_clsh_imped_config(struct snd_soc_codec *codec,
+ int imped)
+{
+ int i = 0;
+ int index = 0;
+ index = get_impedance_index(imped);
+ if (index > ARRAY_SIZE(imped_index)) {
+ pr_err("%s, invalid imped = %d\n", __func__, imped);
+ return;
+ }
+ for (i = 0; i < MAX_IMPED_PARAMS; i++)
+ snd_soc_write(codec, imped_table[index][i].reg,
+ imped_table[index][i].val);
+}
+
static void wcd9xxx_clsh_comp_req(struct snd_soc_codec *codec,
struct wcd9xxx_clsh_cdc_data *clsh_d,
int compute_pa, bool on)
@@ -221,20 +636,26 @@
usleep_range(BUCK_SETTLE_TIME_US, BUCK_SETTLE_TIME_US);
}
-static void wcd9xxx_clsh_enable_post_pa(struct snd_soc_codec *codec)
+
+/* This will be called for all states except Lineout */
+static void wcd9xxx_clsh_enable_post_pa(struct snd_soc_codec *codec,
+ struct wcd9xxx_clsh_cdc_data *cdc_clsh_d)
{
int i;
const struct wcd9xxx_reg_mask_val reg_set[] = {
{WCD9XXX_A_BUCK_MODE_5, 0x02, 0x00},
{WCD9XXX_A_NCP_STATIC, 0x20, 0x00},
{WCD9XXX_A_BUCK_MODE_3, 0x04, 0x04},
- {WCD9XXX_A_BUCK_MODE_3, 0x08, 0x08},
};
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 (!cdc_clsh_d->is_dynamic_vdd_cp)
+ snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_3,
+ 0x08, 0x08);
+
dev_dbg(codec->dev, "%s: completed clsh mode settings after PA enable\n",
__func__);
@@ -478,13 +899,17 @@
snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
0x20, 0x01);
wcd9xxx_enable_ncp(codec, true);
- msleep(NCP_SETTLE_TIME_US);
+ /* NCP settle time recommended by codec specification */
+ usleep_range(NCP_SETTLE_TIME_US,
+ NCP_SETTLE_TIME_US + 10);
} else {
snd_soc_update_bits(codec, WCD9XXX_A_NCP_EN,
0x40, 0x00);
wcd9xxx_enable_ncp(codec, true);
- msleep(NCP_SETTLE_TIME_US);
+ /* NCP settle time recommended by codec specification */
+ usleep_range(NCP_SETTLE_TIME_US,
+ NCP_SETTLE_TIME_US + 10);
snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_5,
0x01, 0x01);
snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_5,
@@ -557,7 +982,7 @@
} else if (req_state != WCD9XXX_CLSH_STATE_LO) {
- wcd9xxx_clsh_enable_post_pa(codec);
+ wcd9xxx_clsh_enable_post_pa(codec, cdc_clsh_d);
}
break;
diff --git a/sound/soc/codecs/wcd9xxx-common.h b/sound/soc/codecs/wcd9xxx-common.h
index 316742d..654964e 100644
--- a/sound/soc/codecs/wcd9xxx-common.h
+++ b/sound/soc/codecs/wcd9xxx-common.h
@@ -52,6 +52,7 @@
struct wcd9xxx_clsh_cdc_data {
u8 state;
int buck_mv;
+ bool is_dynamic_vdd_cp;
struct wcd9xxx_resmgr *resmgr;
};
@@ -73,6 +74,9 @@
extern void wcd9xxx_clsh_init(struct wcd9xxx_clsh_cdc_data *clsh,
struct wcd9xxx_resmgr *resmgr);
+extern void wcd9xxx_clsh_imped_config(struct snd_soc_codec *codec,
+ int imped);
+
enum wcd9xxx_codec_event {
WCD9XXX_CODEC_EVENT_CODEC_UP = 0,
};
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index cd11703..6fc8e13 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -18,6 +18,7 @@
#include <linux/printk.h>
#include <linux/ratelimit.h>
#include <linux/debugfs.h>
+#include <linux/list.h>
#include <linux/mfd/wcd9xxx/core.h>
#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
#include <linux/mfd/wcd9xxx/wcd9320_registers.h>
@@ -36,6 +37,7 @@
#include "wcd9306.h"
#include "wcd9xxx-mbhc.h"
#include "wcd9xxx-resmgr.h"
+#include "wcd9xxx-common.h"
#define WCD9XXX_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | \
SND_JACK_OC_HPHR | SND_JACK_LINEOUT | \
@@ -92,7 +94,10 @@
#define WCD9XXX_GM_SWAP_THRES_MAX_MV 650
#define WCD9XXX_THRESHOLD_MIC_THRESHOLD 200
-#define WCD9XXX_USLEEP_RANGE_MARGIN_US 1000
+#define WCD9XXX_USLEEP_RANGE_MARGIN_US 100
+
+/* RX_HPH_CNP_WG_TIME increases by 0.24ms */
+#define WCD9XXX_WG_TIME_FACTOR_US 240
#define WCD9XXX_IRQ_MBHC_JACK_SWITCH_DEFAULT 28
@@ -112,6 +117,12 @@
enum wcd9xxx_mbhc_plug_type _type;
};
+struct wcd9xxx_register_save_node {
+ struct list_head lh;
+ u16 reg;
+ u16 value;
+};
+
enum meas_type {
STA = 0,
DCE,
@@ -142,6 +153,11 @@
WCD9XXX_CURRENT_V_BR_H,
};
+static int wcd9xxx_detect_impedance(struct wcd9xxx_mbhc *mbhc, uint32_t *zl,
+ uint32_t *zr);
+static s16 wcd9xxx_get_current_v(struct wcd9xxx_mbhc *mbhc,
+ const enum wcd9xxx_current_v_idx idx);
+
static bool wcd9xxx_mbhc_polling(struct wcd9xxx_mbhc *mbhc)
{
return mbhc->polling_active;
@@ -171,6 +187,7 @@
/* 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;
@@ -198,6 +215,17 @@
/* 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);
@@ -206,11 +234,15 @@
pr_debug("%s: leave\n", __func__);
}
-/* called under codec_resource_lock acquisition */
-static void __wcd9xxx_switch_micbias(struct wcd9xxx_mbhc *mbhc,
+/*
+ * called under codec_resource_lock acquisition
+ * return old status
+ */
+static bool __wcd9xxx_switch_micbias(struct wcd9xxx_mbhc *mbhc,
int vddio_switch, bool restartpolling,
bool checkpolling)
{
+ bool ret;
int cfilt_k_val;
bool override;
struct snd_soc_codec *codec;
@@ -220,9 +252,11 @@
if (mbhc->micbias_enable) {
pr_debug("%s: micbias is already on\n", __func__);
- return;
+ ret = mbhc->mbhc_micbias_switched;
+ return ret;
}
+ ret = mbhc->mbhc_micbias_switched;
if (vddio_switch && !mbhc->mbhc_micbias_switched &&
(!checkpolling || mbhc->polling_active)) {
if (restartpolling)
@@ -329,11 +363,13 @@
mbhc->mbhc_micbias_switched = false;
pr_debug("%s: VDDIO switch disabled\n", __func__);
}
+
+ return ret;
}
static void wcd9xxx_switch_micbias(struct wcd9xxx_mbhc *mbhc, int vddio_switch)
{
- return __wcd9xxx_switch_micbias(mbhc, vddio_switch, true, true);
+ __wcd9xxx_switch_micbias(mbhc, vddio_switch, true, true);
}
static s16 wcd9xxx_get_current_v(struct wcd9xxx_mbhc *mbhc,
@@ -728,6 +764,7 @@
mbhc->micbias_enable_cb(mbhc->codec, false);
mbhc->micbias_enable = false;
}
+ mbhc->zl = mbhc->zr = 0;
pr_debug("%s: Reporting removal %d(%x)\n", __func__,
jack_type, mbhc->hph_status);
wcd9xxx_jack_report(mbhc, &mbhc->headset_jack, mbhc->hph_status,
@@ -752,6 +789,7 @@
}
pr_debug("%s: Reporting removal (%x)\n",
__func__, mbhc->hph_status);
+ mbhc->zl = mbhc->zr = 0;
wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
0, WCD9XXX_JACK_MASK);
mbhc->hph_status = 0;
@@ -775,6 +813,8 @@
pr_debug("%s: Enabling micbias\n", __func__);
mbhc->micbias_enable_cb(mbhc->codec, true);
}
+ if (mbhc->impedance_detect)
+ wcd9xxx_detect_impedance(mbhc, &mbhc->zl, &mbhc->zr);
pr_debug("%s: Reporting insertion %d(%x)\n", __func__,
jack_type, mbhc->hph_status);
wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
@@ -974,7 +1014,7 @@
* These will be released by wcd9xxx_cleanup_hs_polling
*/
WCD9XXX_BG_CLK_LOCK(mbhc->resmgr);
- wcd9xxx_resmgr_get_bandgap(mbhc->resmgr, WCD9XXX_BANDGAP_MBHC_MODE);
+ wcd9xxx_resmgr_get_bandgap(mbhc->resmgr, WCD9XXX_BANDGAP_AUDIO_MODE);
wcd9xxx_resmgr_get_clk_block(mbhc->resmgr, WCD9XXX_CLK_RCO);
WCD9XXX_BG_CLK_UNLOCK(mbhc->resmgr);
@@ -1106,10 +1146,15 @@
/*
* wcd9xxx_find_plug_type : Find out and return the best plug type with given
* list of wcd9xxx_mbhc_detect structure.
+ * param mbhc wcd9xxx_mbhc structure
+ * param dt collected measurements
+ * param size array size of dt
+ * param event_state mbhc->event_state when dt is collected
*/
static enum wcd9xxx_mbhc_plug_type
wcd9xxx_find_plug_type(struct wcd9xxx_mbhc *mbhc,
- struct wcd9xxx_mbhc_detect *dt, const int size)
+ struct wcd9xxx_mbhc_detect *dt, const int size,
+ unsigned long event_state)
{
int i;
int ch;
@@ -1122,6 +1167,8 @@
const s16 hs_max = plug_type->v_hs_max;
const s16 no_mic = plug_type->v_no_mic;
+ pr_debug("%s: event_state 0x%lx\n", __func__, event_state);
+
for (i = 0, d = dt, ch = 0; i < size; i++, d++) {
vdce = wcd9xxx_codec_sta_dce_v(mbhc, true, d->dce);
if (d->vddio)
@@ -1163,13 +1210,16 @@
goto exit;
}
}
- if (ch != size && ch > 0) {
+
+ if (event_state & (1 << MBHC_EVENT_PA_HPHL)) {
+ pr_debug("%s: HPHL PA was ON\n", __func__);
+ } else if (ch != size && ch > 0) {
pr_debug("%s: Invalid, inconsistent HPHL\n", __func__);
type = PLUG_TYPE_INVALID;
goto exit;
}
- for (i = 0, d = dt; i < size; i++, d++) {
+ for (i = 0, dprev = NULL, d = dt; i < size; i++, d++) {
if (d->vddio) {
dvddio = d;
continue;
@@ -1203,12 +1253,18 @@
maxv))
type = PLUG_TYPE_GND_MIC_SWAP;
}
- if (((type == PLUG_TYPE_HEADSET || type == PLUG_TYPE_HEADPHONE) &&
- ch != size) || (type == PLUG_TYPE_GND_MIC_SWAP && ch)) {
- pr_debug("%s: Invalid, not fully inserted, TYPE %d\n",
- __func__, type);
- type = PLUG_TYPE_INVALID;
+
+ /* if HPHL PA was on, we cannot use hphl status */
+ if (!(event_state & (1UL << MBHC_EVENT_PA_HPHL))) {
+ if (((type == PLUG_TYPE_HEADSET ||
+ type == PLUG_TYPE_HEADPHONE) && ch != size) ||
+ (type == PLUG_TYPE_GND_MIC_SWAP && ch)) {
+ pr_debug("%s: Invalid, not fully inserted, TYPE %d\n",
+ __func__, type);
+ type = PLUG_TYPE_INVALID;
+ }
}
+
if (type == PLUG_TYPE_HEADSET && dvddio) {
if ((dvddio->_vdces > hs_max) ||
(dvddio->_vdces > minv + WCD9XXX_THRESHOLD_MIC_THRESHOLD)) {
@@ -1276,6 +1332,7 @@
wcd9xxx_codec_get_plug_type(struct wcd9xxx_mbhc *mbhc, bool highhph)
{
int i;
+ bool vddioon;
struct wcd9xxx_mbhc_plug_type_cfg *plug_type_ptr;
struct wcd9xxx_mbhc_detect rt[NUM_DCE_PLUG_INS_DETECT];
enum wcd9xxx_mbhc_plug_type type = PLUG_TYPE_INVALID;
@@ -1290,6 +1347,13 @@
/* GND and MIC swap detection requires at least 2 rounds of DCE */
BUG_ON(NUM_DCE_PLUG_INS_DETECT < 2);
+ /*
+ * There are chances vddio switch is on and cfilt voltage is adjusted
+ * to vddio voltage even after plug type removal reported.
+ */
+ vddioon = __wcd9xxx_switch_micbias(mbhc, 0, false, false);
+ pr_debug("%s: vddio switch was %s\n", __func__, vddioon ? "on" : "off");
+
plug_type_ptr =
WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
@@ -1332,7 +1396,11 @@
wcd9xxx_codec_hphr_gnd_switch(codec, false);
}
- type = wcd9xxx_find_plug_type(mbhc, rt, ARRAY_SIZE(rt));
+ if (vddioon)
+ __wcd9xxx_switch_micbias(mbhc, 1, false, false);
+
+ type = wcd9xxx_find_plug_type(mbhc, rt, ARRAY_SIZE(rt),
+ mbhc->event_state);
pr_debug("%s: leave\n", __func__);
return type;
@@ -2116,6 +2184,7 @@
unsigned long timeout;
int retry = 0, pt_gnd_mic_swap_cnt = 0;
bool correction = false;
+ bool wrk_complete = true;
pr_debug("%s: enter\n", __func__);
@@ -2141,12 +2210,14 @@
++retry;
rmb();
if (mbhc->hs_detect_work_stop) {
+ wrk_complete = false;
pr_debug("%s: stop requested\n", __func__);
break;
}
msleep(HS_DETECT_PLUG_INERVAL_MS);
if (wcd9xxx_swch_level_remove(mbhc)) {
+ wrk_complete = false;
pr_debug("%s: Switch level is low\n", __func__);
break;
}
@@ -2220,7 +2291,9 @@
if (plug_type == PLUG_TYPE_HIGH_HPH) {
pr_debug("%s: polling is done, still HPH, so enabling MIC trigger\n",
__func__);
+ WCD9XXX_BCL_LOCK(mbhc->resmgr);
wcd9xxx_find_plug_and_report(mbhc, plug_type);
+ WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
}
/* Turn off override */
if (!correction)
@@ -2230,10 +2303,11 @@
if (mbhc->mbhc_cfg->detect_extn_cable) {
WCD9XXX_BCL_LOCK(mbhc->resmgr);
- if (mbhc->current_plug == PLUG_TYPE_HEADPHONE ||
+ if ((mbhc->current_plug == PLUG_TYPE_HEADPHONE &&
+ wrk_complete) ||
mbhc->current_plug == PLUG_TYPE_GND_MIC_SWAP ||
mbhc->current_plug == PLUG_TYPE_INVALID ||
- plug_type == PLUG_TYPE_INVALID) {
+ (plug_type == PLUG_TYPE_INVALID && wrk_complete)) {
/* Enable removal detection */
wcd9xxx_cleanup_hs_polling(mbhc);
wcd9xxx_enable_hs_detect(mbhc, 0, 0, false);
@@ -2350,36 +2424,6 @@
return r;
}
-/* called under codec_resource_lock acquisition */
-static void wcd9xxx_codec_drive_v_to_micbias(struct wcd9xxx_mbhc *mbhc,
- int usec)
-{
- int cfilt_k_val;
- bool set = true;
-
- if (mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
- mbhc->mbhc_micbias_switched) {
- pr_debug("%s: set mic V to micbias V\n", __func__);
- snd_soc_update_bits(mbhc->codec, WCD9XXX_A_CDC_MBHC_CLK_CTL,
- 0x2, 0x2);
- wcd9xxx_turn_onoff_override(mbhc->codec, true);
- while (1) {
- cfilt_k_val =
- wcd9xxx_resmgr_get_k_val(mbhc->resmgr,
- set ? mbhc->mbhc_data.micb_mv :
- VDDIO_MICBIAS_MV);
- snd_soc_update_bits(mbhc->codec,
- mbhc->mbhc_bias_regs.cfilt_val,
- 0xFC, (cfilt_k_val << 2));
- if (!set)
- break;
- usleep_range(usec, usec);
- set = false;
- }
- wcd9xxx_turn_onoff_override(mbhc->codec, false);
- }
-}
-
static int wcd9xxx_is_fake_press(struct wcd9xxx_mbhc *mbhc)
{
int i;
@@ -2504,12 +2548,43 @@
snd_soc_write(codec, mbhc->mbhc_bias_regs.ctl_reg, reg0);
}
+/*
+ * wcd9xxx_update_rel_threshold : update mbhc release upper bound threshold
+ * to ceilmv + buffer
+ */
+static int wcd9xxx_update_rel_threshold(struct wcd9xxx_mbhc *mbhc, int ceilmv)
+{
+ u16 v_brh, v_b1_hu;
+ int mv;
+ struct wcd9xxx_mbhc_btn_detect_cfg *btn_det;
+ void *calibration = mbhc->mbhc_cfg->calibration;
+ struct snd_soc_codec *codec = mbhc->codec;
+
+ btn_det = WCD9XXX_MBHC_CAL_BTN_DET_PTR(calibration);
+ 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);
+ 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);
+ 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;
+}
+
irqreturn_t wcd9xxx_dce_handler(int irq, void *data)
{
int i, mask;
bool vddio;
u8 mbhc_status;
s16 dce_z, sta_z;
+ s32 stamv, stamv_s;
+ s16 *v_btn_high;
+ struct wcd9xxx_mbhc_btn_detect_cfg *btn_det;
int btn = -1, meas = 0;
struct wcd9xxx_mbhc *mbhc = data;
const struct wcd9xxx_mbhc_btn_detect_cfg *d =
@@ -2517,10 +2592,10 @@
short btnmeas[d->n_btn_meas + 1];
short dce[d->n_btn_meas + 1], sta;
s32 mv[d->n_btn_meas + 1], mv_s[d->n_btn_meas + 1];
- s32 stamv, stamv_s;
struct snd_soc_codec *codec = mbhc->codec;
struct wcd9xxx *core = mbhc->resmgr->core;
int n_btn_meas = d->n_btn_meas;
+ void *calibration = mbhc->mbhc_cfg->calibration;
pr_debug("%s: enter\n", __func__);
@@ -2645,6 +2720,13 @@
__func__);
goto done;
}
+ btn_det = WCD9XXX_MBHC_CAL_BTN_DET_PTR(calibration);
+ v_btn_high = wcd9xxx_mbhc_cal_btn_det_mp(btn_det,
+ MBHC_BTN_DET_V_BTN_HIGH);
+ WARN_ON(btn >= btn_det->num_btn);
+ /* reprogram release threshold to catch voltage ramp up early */
+ wcd9xxx_update_rel_threshold(mbhc, v_btn_high[btn]);
+
mask = wcd9xxx_get_button_mask(btn);
mbhc->buttons_pressed |= mask;
wcd9xxx_lock_sleep(core);
@@ -2673,8 +2755,6 @@
WCD9XXX_BCL_LOCK(mbhc->resmgr);
mbhc->mbhc_state = MBHC_STATE_RELEASE;
- wcd9xxx_codec_drive_v_to_micbias(mbhc, 10000);
-
if (mbhc->buttons_pressed & WCD9XXX_JACK_BUTTON_MASK) {
ret = wcd9xxx_cancel_btn_work(mbhc);
if (ret == 0) {
@@ -2820,7 +2900,8 @@
dce_wait = (1000 * 512 * ncic * (nmeas + 1)) / (rate / 1000);
sta_wait = (1000 * 128 * (navg + 1)) / (rate / 1000);
mbhc->mbhc_data.t_dce = dce_wait;
- mbhc->mbhc_data.t_sta = sta_wait;
+ /* give extra margin to sta for safety */
+ mbhc->mbhc_data.t_sta = sta_wait + 250;
mbhc->mbhc_data.t_sta_dce = ((1000 * 256) / (rate / 1000) *
n_ready[idx]) + 10;
@@ -3575,6 +3656,306 @@
return ret;
}
+static int wcd9xxx_soc_update_bits_push(struct snd_soc_codec *codec,
+ struct list_head *list,
+ uint16_t reg, uint8_t mask,
+ uint8_t value)
+{
+ int rc;
+ struct wcd9xxx_register_save_node *node;
+
+ node = kmalloc(sizeof(*node), GFP_KERNEL);
+ if (unlikely(!node)) {
+ pr_err("%s: Not enough memory\n", __func__);
+ return -ENOMEM;
+ }
+ node->reg = reg;
+ node->value = snd_soc_read(codec, reg);
+ list_add(&node->lh, list);
+ if (mask == 0xFF)
+ rc = snd_soc_write(codec, reg, value);
+ else
+ rc = snd_soc_update_bits(codec, reg, mask, value);
+ return rc;
+}
+
+static int wcd9xxx_prepare_static_pa(struct wcd9xxx_mbhc *mbhc,
+ struct list_head *lh)
+{
+ int i;
+ struct snd_soc_codec *codec = mbhc->codec;
+
+ const struct wcd9xxx_reg_mask_val reg_set_paon[] = {
+ {WCD9XXX_A_RX_HPH_OCP_CTL, 0x18, 0x00},
+ {WCD9XXX_A_RX_HPH_L_TEST, 0x1, 0x0},
+ {WCD9XXX_A_RX_HPH_R_TEST, 0x1, 0x0},
+ {WCD9XXX_A_RX_HPH_BIAS_WG_OCP, 0xff, 0x1A},
+ {WCD9XXX_A_RX_HPH_CNP_WG_CTL, 0xff, 0xDB},
+ {WCD9XXX_A_RX_HPH_CNP_WG_TIME, 0xff, 0x15},
+ {WCD9XXX_A_CDC_RX1_B6_CTL, 0xff, 0x81},
+ {WCD9XXX_A_CDC_CLK_RX_B1_CTL, 0x01, 0x01},
+ {WCD9XXX_A_RX_HPH_CHOP_CTL, 0xff, 0xA4},
+ {WCD9XXX_A_RX_HPH_L_GAIN, 0xff, 0x2C},
+ {WCD9XXX_A_CDC_RX2_B6_CTL, 0xff, 0x81},
+ {WCD9XXX_A_CDC_CLK_RX_B1_CTL, 0x02, 0x02},
+ {WCD9XXX_A_RX_HPH_R_GAIN, 0xff, 0x2C},
+ {WCD9XXX_A_NCP_CLK, 0xff, 0xFC},
+ {WCD9XXX_A_BUCK_CTRL_CCL_3, 0xff, 0x60},
+ {WCD9XXX_A_RX_COM_BIAS, 0xff, 0x80},
+ {WCD9XXX_A_BUCK_MODE_3, 0xff, 0xC6},
+ {WCD9XXX_A_BUCK_MODE_4, 0xff, 0xE6},
+ {WCD9XXX_A_BUCK_MODE_5, 0xff, 0x02},
+ {WCD9XXX_A_BUCK_MODE_1, 0xff, 0xA1},
+ {WCD9XXX_A_NCP_EN, 0xff, 0xFF},
+ {WCD9XXX_A_BUCK_MODE_5, 0xff, 0x7B},
+ {WCD9XXX_A_CDC_CLSH_B1_CTL, 0xff, 0xE6},
+ {WCD9XXX_A_RX_HPH_L_DAC_CTL, 0xff, 0xC0},
+ {WCD9XXX_A_RX_HPH_R_DAC_CTL, 0xff, 0xC0},
+ };
+
+ for (i = 0; i < ARRAY_SIZE(reg_set_paon); i++)
+ wcd9xxx_soc_update_bits_push(codec, lh,
+ reg_set_paon[i].reg,
+ reg_set_paon[i].mask,
+ reg_set_paon[i].val);
+ pr_debug("%s: PAs are prepared\n", __func__);
+
+ return 0;
+}
+
+static void wcd9xxx_restore_registers(struct wcd9xxx_mbhc *mbhc,
+ struct list_head *lh)
+{
+ struct wcd9xxx_register_save_node *node, *nodetmp;
+ struct snd_soc_codec *codec = mbhc->codec;
+
+ list_for_each_entry_safe(node, nodetmp, lh, lh) {
+ snd_soc_write(codec, node->reg, node->value);
+ list_del(&node->lh);
+ kfree(node);
+ }
+}
+
+static void wcd9xxx_unprepare_static_pa(struct wcd9xxx_mbhc *mbhc,
+ struct list_head *lh)
+{
+ wcd9xxx_restore_registers(mbhc, lh);
+}
+
+static int wcd9xxx_enable_static_pa(struct wcd9xxx_mbhc *mbhc, bool enable)
+{
+ struct snd_soc_codec *codec = mbhc->codec;
+ const int wg_time = snd_soc_read(codec, WCD9XXX_A_RX_HPH_CNP_WG_TIME) *
+ WCD9XXX_WG_TIME_FACTOR_US;
+
+ snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_CNP_EN, 0x30,
+ enable ? 0x30 : 0x0);
+ /* Wait for wave gen time to avoid pop noise */
+ usleep_range(wg_time, wg_time + WCD9XXX_USLEEP_RANGE_MARGIN_US);
+ pr_debug("%s: PAs are %s as static mode (wg_time %d)\n", __func__,
+ enable ? "enabled" : "disabled", wg_time);
+ return 0;
+}
+
+static int wcd9xxx_detect_impedance(struct wcd9xxx_mbhc *mbhc, uint32_t *zl,
+ uint32_t *zr)
+{
+ int i;
+ int ret = 0;
+ s16 l[3], r[3];
+ s16 *z[] = {
+ &l[0], &r[0], &r[1], &l[1], &l[2], &r[2],
+ };
+ LIST_HEAD(lh);
+ LIST_HEAD(lhpa);
+ struct snd_soc_codec *codec = mbhc->codec;
+ const int ramp_wait_us = 18 * 1000;
+ const int mux_wait_us = 25;
+ const int alphal = 364; /* 0.005555 * 65536 = 364.05 */
+ const int alphar = 364; /* 0.005555 * 65536 = 364.05 */
+ const int beta = 3855; /* 0.011765 * 5 * 65536 = 3855.15 */
+ const int rref = 11333; /* not scaled up */
+ const int shift = 16;
+ int64_t rl, rr = 0; /* milliohm */
+ const struct wcd9xxx_reg_mask_val reg_set_mux[] = {
+ /* Phase 1 */
+ /* Set MBHC_MUX for HPHL without ical */
+ {WCD9XXX_A_MBHC_SCALING_MUX_2, 0xFF, 0xF0},
+ /* Set MBHC_MUX for HPHR without ical */
+ {WCD9XXX_A_MBHC_SCALING_MUX_1, 0xFF, 0xA0},
+ /* Set MBHC_MUX for HPHR with ical */
+ {WCD9XXX_A_MBHC_SCALING_MUX_2, 0xFF, 0xF8},
+ /* Set MBHC_MUX for HPHL with ical */
+ {WCD9XXX_A_MBHC_SCALING_MUX_1, 0xFF, 0xC0},
+
+ /* Phase 2 */
+ {WCD9XXX_A_MBHC_SCALING_MUX_2, 0xFF, 0xF0},
+ /* Set MBHC_MUX for HPHR without ical and wait for 25us */
+ {WCD9XXX_A_MBHC_SCALING_MUX_1, 0xFF, 0xA0},
+ };
+
+ pr_debug("%s: enter\n", __func__);
+ WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
+
+ /*
+ * Impedance detection is an intrusive function as it mutes RX paths,
+ * enable PAs and etc. Therefore codec drvier including ALSA
+ * shouldn't read and write hardware registers during detection.
+ */
+ mutex_lock(&codec->mutex);
+
+ WCD9XXX_BG_CLK_LOCK(mbhc->resmgr);
+ /*
+ * Fast(mbhc) mode bandagap doesn't need to be enabled explicitly
+ * since fast mode is set by MBHC hardware when override is on.
+ * Enable bandgap mode to avoid unnecessary RCO disable and enable
+ * during clock source change.
+ */
+ wcd9xxx_resmgr_get_bandgap(mbhc->resmgr, WCD9XXX_BANDGAP_AUDIO_MODE);
+ wcd9xxx_resmgr_get_clk_block(mbhc->resmgr, WCD9XXX_CLK_RCO);
+ WCD9XXX_BG_CLK_UNLOCK(mbhc->resmgr);
+
+ pr_debug("%s: Setting impedance detection\n", __func__);
+ wcd9xxx_prepare_static_pa(mbhc, &lhpa);
+ wcd9xxx_enable_static_pa(mbhc, true);
+
+ /*
+ * save old value of registers and write the new value to restore old
+ * value back, WCD9XXX_A_CDC_PA_RAMP_B{1,2,3,4}_CTL registers don't
+ * need to be restored as those are solely used by impedance detection.
+ */
+#define __w(reg, mask, value) \
+ do { \
+ ret = wcd9xxx_soc_update_bits_push(codec, &lh, reg, mask, \
+ value); \
+ if (ret < 0) \
+ return ret; \
+ } while (0)
+
+ /* Reset the PA Ramp */
+ snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x1C);
+ /*
+ * Connect the PA Ramp to PA chain and release reset with keep it
+ * connected.
+ */
+ snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x1F);
+ snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x03);
+ /* Program the PA Ramp to FS_48K, L shift 1 and sample num to 24 */
+ snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B3_CTL, 0x3 << 4 | 0x6);
+ /* 0x56 for 10mv. 0xC0 is for 50mv */
+ snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B4_CTL, 0xC0);
+ /* Enable MBHC MUX, Set MUX current to 37.5uA and ADC7 */
+ __w(WCD9XXX_A_MBHC_SCALING_MUX_1, 0xFF, 0xC0);
+ __w(WCD9XXX_A_MBHC_SCALING_MUX_2, 0xFF, 0xF0);
+ __w(WCD9XXX_A_TX_7_MBHC_TEST_CTL, 0xFF, 0x78);
+ __w(WCD9XXX_A_TX_7_MBHC_EN, 0xFF, 0x8C);
+ /* Change NSA and NAVG */
+ __w(WCD9XXX_A_CDC_MBHC_TIMER_B4_CTL, 0x4 << 4, 0x4 << 4);
+ __w(WCD9XXX_A_CDC_MBHC_TIMER_B5_CTL, 0xFF, 0x10);
+ /* Reset MBHC and set it up for STA */
+ __w(WCD9XXX_A_CDC_MBHC_CLK_CTL, 0xFF, 0x0A);
+ __w(WCD9XXX_A_CDC_MBHC_EN_CTL, 0xFF, 0x02);
+ __w(WCD9XXX_A_CDC_MBHC_CLK_CTL, 0xFF, 0x02);
+
+ /* Set HPH_MBHC for zdet */
+ __w(WCD9XXX_A_MBHC_HPH, 0xB3, 0x80);
+
+ pr_debug("%s: Performing impedance detection\n", __func__);
+ /* Phase 1 */
+ for (i = 0; i < ARRAY_SIZE(reg_set_mux) - 2; i++) {
+ __w(reg_set_mux[i].reg, reg_set_mux[i].mask,
+ reg_set_mux[i].val);
+ /* 25us is required after mux change to settle down */
+ usleep_range(mux_wait_us,
+ mux_wait_us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
+ *(z[i]) = __wcd9xxx_codec_sta_dce(mbhc, 0, false, false);
+ }
+
+ /* Phase 2 */
+ /* Start the PA ramp on HPH L and R */
+ snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B2_CTL, 0x05);
+ /* Ramp generator takes ~17ms */
+ usleep_range(ramp_wait_us,
+ ramp_wait_us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
+
+ /* Disable Ical */
+ snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B2_CTL, 0x00);
+ /* Ramp generator takes ~17ms */
+ usleep_range(ramp_wait_us,
+ ramp_wait_us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
+ for (; i < ARRAY_SIZE(reg_set_mux); i++) {
+ __w(reg_set_mux[i].reg, reg_set_mux[i].mask,
+ reg_set_mux[i].val);
+ /* 25us is required after mux change to settle down */
+ usleep_range(mux_wait_us,
+ mux_wait_us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
+ *(z[i]) = __wcd9xxx_codec_sta_dce(mbhc, 0, false, false);
+ }
+
+ /* Ramp HPH L & R back to Zero */
+ snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B2_CTL, 0x0A);
+ /* Ramp generator takes ~17ms */
+ usleep_range(ramp_wait_us,
+ ramp_wait_us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
+ snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B2_CTL, 0x00);
+#undef __w
+
+ /* Clean up starts */
+ /* Turn off PA ramp generator */
+ snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x0);
+ wcd9xxx_enable_static_pa(mbhc, false);
+ wcd9xxx_restore_registers(mbhc, &lh);
+ wcd9xxx_unprepare_static_pa(mbhc, &lhpa);
+
+ mutex_unlock(&codec->mutex);
+
+ WCD9XXX_BG_CLK_LOCK(mbhc->resmgr);
+ wcd9xxx_resmgr_put_bandgap(mbhc->resmgr, WCD9XXX_BANDGAP_MBHC_MODE);
+ wcd9xxx_resmgr_put_clk_block(mbhc->resmgr, WCD9XXX_CLK_RCO);
+ WCD9XXX_BG_CLK_UNLOCK(mbhc->resmgr);
+
+ rl = (int)(l[0] - l[1]) * 1000 / (l[0] - l[2]);
+ rl = rl * rref * alphal;
+ rl = rl >> shift;
+ rl = rl * beta;
+ rl = rl >> shift;
+ *zl = rl;
+
+ rr = (int)(r[0] - r[1]) * 1000 / (r[0] - r[2]);
+ rr = rr * rref * alphar;
+ rr = rr >> shift;
+ rr = rr * beta;
+ rr = rr >> shift;
+ *zr = rr;
+
+ pr_debug("%s: L0: 0x%x(%d), L1: 0x%x(%d), L2: 0x%x(%d), rl: %lld\n",
+ __func__,
+ l[0] & 0xffff, l[0], l[1] & 0xffff, l[1], l[2] & 0xffff, l[2],
+ rl);
+ pr_debug("%s: R0: 0x%x(%d), R1: 0x%x(%d), R2: 0x%x(%d), rr: %lld\n",
+ __func__,
+ r[0] & 0xffff, r[0], r[1] & 0xffff, r[1], r[2] & 0xffff, r[2],
+ rr);
+ pr_debug("%s: RL %d milliohm, RR %d milliohm\n", __func__, *zl, *zr);
+ pr_debug("%s: Impedance detection completed\n", __func__);
+
+ return ret;
+}
+
+int wcd9xxx_mbhc_get_impedance(struct wcd9xxx_mbhc *mbhc, uint32_t *zl,
+ uint32_t *zr)
+{
+ WCD9XXX_BCL_LOCK(mbhc->resmgr);
+ *zl = mbhc->zl;
+ *zr = mbhc->zr;
+ WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
+
+ if (*zl && *zr)
+ return 0;
+ else
+ return -EINVAL;
+}
+
/*
* wcd9xxx_mbhc_init : initialize MBHC internal structures.
*
@@ -3583,7 +3964,8 @@
int wcd9xxx_mbhc_init(struct wcd9xxx_mbhc *mbhc, struct wcd9xxx_resmgr *resmgr,
struct snd_soc_codec *codec,
int (*micbias_enable_cb) (struct snd_soc_codec*, bool),
- const struct wcd9xxx_mbhc_cb *mbhc_cb, int rco_clk_rate)
+ const struct wcd9xxx_mbhc_cb *mbhc_cb, int rco_clk_rate,
+ bool impedance_det_en)
{
int ret;
void *core;
@@ -3609,6 +3991,7 @@
mbhc->micbias_enable_cb = micbias_enable_cb;
mbhc->rco_clk_rate = rco_clk_rate;
mbhc->mbhc_cb = mbhc_cb;
+ mbhc->impedance_detect = impedance_det_en;
if (mbhc->headset_jack.jack == NULL) {
ret = snd_soc_jack_new(codec, "Headset Jack", WCD9XXX_JACK_MASK,
@@ -3701,6 +4084,9 @@
}
wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
+ wcd9xxx_regmgr_cond_register(resmgr, 1 << WCD9XXX_COND_HPH_MIC |
+ 1 << WCD9XXX_COND_HPH);
+
pr_debug("%s: leave ret %d\n", __func__, ret);
return ret;
@@ -3726,6 +4112,9 @@
{
void *cdata = mbhc->codec->control_data;
+ wcd9xxx_regmgr_cond_deregister(mbhc->resmgr, 1 << WCD9XXX_COND_HPH_MIC |
+ 1 << WCD9XXX_COND_HPH);
+
wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_RELEASE, mbhc);
wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_POTENTIAL, mbhc);
wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_REMOVAL, mbhc);
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.h b/sound/soc/codecs/wcd9xxx-mbhc.h
index 02ecced..0599ccb 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.h
+++ b/sound/soc/codecs/wcd9xxx-mbhc.h
@@ -291,6 +291,10 @@
bool micbias_enable;
int (*micbias_enable_cb) (struct snd_soc_codec*, bool);
+ bool impedance_detect;
+ /* impedance of hphl and hphr */
+ uint32_t zl, zr;
+
u32 rco_clk_rate;
#ifdef CONFIG_DEBUG_FS
@@ -360,9 +364,12 @@
struct snd_soc_codec *codec,
int (*micbias_enable_cb) (struct snd_soc_codec*, bool),
const struct wcd9xxx_mbhc_cb *mbhc_cb,
- int rco_clk_rate);
+ int rco_clk_rate,
+ bool impedance_det_en);
void wcd9xxx_mbhc_deinit(struct wcd9xxx_mbhc *mbhc);
void *wcd9xxx_mbhc_cal_btn_det_mp(
const struct wcd9xxx_mbhc_btn_detect_cfg *btn_det,
const enum wcd9xxx_mbhc_btn_det_mem mem);
+int wcd9xxx_mbhc_get_impedance(struct wcd9xxx_mbhc *mbhc, uint32_t *zl,
+ uint32_t *zr);
#endif /* __WCD9XXX_MBHC_H__ */
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.c b/sound/soc/codecs/wcd9xxx-resmgr.c
index be11e53..9633cc0 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.c
+++ b/sound/soc/codecs/wcd9xxx-resmgr.c
@@ -652,15 +652,17 @@
return rc;
}
-void wcd9xxx_resmgr_cond_trigger_cond(struct wcd9xxx_resmgr *resmgr,
- enum wcd9xxx_resmgr_cond cond)
+static void wcd9xxx_resmgr_cond_trigger_cond(struct wcd9xxx_resmgr *resmgr,
+ enum wcd9xxx_resmgr_cond cond)
{
struct list_head *l;
struct wcd9xxx_resmgr_cond_entry *e;
bool set;
pr_debug("%s: enter\n", __func__);
- set = !!test_bit(cond, &resmgr->cond_flags);
+ /* update bit if cond isn't available or cond is set */
+ set = !test_bit(cond, &resmgr->cond_avail_flags) ||
+ !!test_bit(cond, &resmgr->cond_flags);
list_for_each(l, &resmgr->update_bit_cond_h) {
e = list_entry(l, struct wcd9xxx_resmgr_cond_entry, list);
if (e->cond == cond)
@@ -672,6 +674,44 @@
pr_debug("%s: leave\n", __func__);
}
+/*
+ * wcd9xxx_regmgr_cond_register : notify resmgr conditions in the condbits are
+ * avaliable and notified.
+ * condbits : contains bitmask of enum wcd9xxx_resmgr_cond
+ */
+void wcd9xxx_regmgr_cond_register(struct wcd9xxx_resmgr *resmgr,
+ unsigned long condbits)
+{
+ unsigned int cond;
+
+ for_each_set_bit(cond, &condbits, BITS_PER_BYTE * sizeof(condbits)) {
+ mutex_lock(&resmgr->update_bit_cond_lock);
+ WARN(test_bit(cond, &resmgr->cond_avail_flags),
+ "Condition 0x%0x is already registered\n", cond);
+ set_bit(cond, &resmgr->cond_avail_flags);
+ wcd9xxx_resmgr_cond_trigger_cond(resmgr, cond);
+ mutex_unlock(&resmgr->update_bit_cond_lock);
+ pr_debug("%s: Condition 0x%x is registered\n", __func__, cond);
+ }
+}
+
+void wcd9xxx_regmgr_cond_deregister(struct wcd9xxx_resmgr *resmgr,
+ unsigned long condbits)
+{
+ unsigned int cond;
+
+ for_each_set_bit(cond, &condbits, BITS_PER_BYTE * sizeof(condbits)) {
+ mutex_lock(&resmgr->update_bit_cond_lock);
+ WARN(!test_bit(cond, &resmgr->cond_avail_flags),
+ "Condition 0x%0x isn't registered\n", cond);
+ clear_bit(cond, &resmgr->cond_avail_flags);
+ wcd9xxx_resmgr_cond_trigger_cond(resmgr, cond);
+ mutex_unlock(&resmgr->update_bit_cond_lock);
+ pr_debug("%s: Condition 0x%x is deregistered\n", __func__,
+ cond);
+ }
+}
+
void wcd9xxx_resmgr_cond_update_cond(struct wcd9xxx_resmgr *resmgr,
enum wcd9xxx_resmgr_cond cond, bool set)
{
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.h b/sound/soc/codecs/wcd9xxx-resmgr.h
index aaf7317..e6a8f5d 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.h
+++ b/sound/soc/codecs/wcd9xxx-resmgr.h
@@ -134,6 +134,7 @@
struct wcd9xxx_mbhc *mbhc;
unsigned long cond_flags;
+ unsigned long cond_avail_flags;
struct list_head update_bit_cond_h;
struct mutex update_bit_cond_lock;
@@ -227,6 +228,10 @@
WCD9XXX_COND_HPH = 0x01, /* Headphone */
WCD9XXX_COND_HPH_MIC = 0x02, /* Microphone on the headset */
};
+void wcd9xxx_regmgr_cond_register(struct wcd9xxx_resmgr *resmgr,
+ unsigned long condbits);
+void wcd9xxx_regmgr_cond_deregister(struct wcd9xxx_resmgr *resmgr,
+ unsigned long condbits);
int wcd9xxx_resmgr_rm_cond_update_bits(struct wcd9xxx_resmgr *resmgr,
enum wcd9xxx_resmgr_cond cond,
unsigned short reg, int shift,
diff --git a/sound/soc/msm/apq8074.c b/sound/soc/msm/apq8074.c
index 9a2f83b..3a055e2 100644
--- a/sound/soc/msm/apq8074.c
+++ b/sound/soc/msm/apq8074.c
@@ -123,7 +123,7 @@
.gpio = 0,
.gpio_irq = 0,
.gpio_level_insert = 1,
- .detect_extn_cable = true,
+ .detect_extn_cable = false,
.insert_detect = true,
.swap_gnd_mic = NULL,
};
@@ -1922,7 +1922,7 @@
{
.name = LPASS_BE_AUXPCM_RX,
.stream_name = "AUX PCM Playback",
- .cpu_dai_name = "msm-dai-q6.4106",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.1",
.platform_name = "msm-pcm-routing",
.codec_name = "msm-stub-codec.1",
.codec_dai_name = "msm-stub-rx",
@@ -1937,7 +1937,7 @@
{
.name = LPASS_BE_AUXPCM_TX,
.stream_name = "AUX PCM Capture",
- .cpu_dai_name = "msm-dai-q6.4107",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.1",
.platform_name = "msm-pcm-routing",
.codec_name = "msm-stub-codec.1",
.codec_dai_name = "msm-stub-tx",
diff --git a/sound/soc/msm/mdm9625.c b/sound/soc/msm/mdm9625.c
index fd21c38..ad8d85a 100644
--- a/sound/soc/msm/mdm9625.c
+++ b/sound/soc/msm/mdm9625.c
@@ -928,7 +928,7 @@
{
.name = LPASS_BE_AUXPCM_RX,
.stream_name = "AUX PCM Playback",
- .cpu_dai_name = "msm-dai-q6.4106",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.1",
.platform_name = "msm-pcm-routing",
.codec_name = "msm-stub-codec.1",
.codec_dai_name = "msm-stub-rx",
@@ -942,7 +942,7 @@
{
.name = LPASS_BE_AUXPCM_TX,
.stream_name = "AUX PCM Capture",
- .cpu_dai_name = "msm-dai-q6.4107",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.1",
.platform_name = "msm-pcm-routing",
.codec_name = "msm-stub-codec.1",
.codec_dai_name = "msm-stub-tx",
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 1b51595..41fe8aa 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -67,7 +67,8 @@
.aif_name = "MM_UL1",
.rates = (SNDRV_PCM_RATE_8000_48000|
SNDRV_PCM_RATE_KNOT),
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
.channels_min = 1,
.channels_max = 4,
.rate_min = 8000,
@@ -713,6 +714,57 @@
.ops = &msm_fe_dai_ops,
.name = "VOICE2_STUB",
},
+ {
+ .playback = {
+ .stream_name = "Multimedia9 Playback",
+ .aif_name = "MM_DL9",
+ .rates = (SNDRV_PCM_RATE_8000_192000|
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
+ .capture = {
+ .stream_name = "Multimedia9 Capture",
+ .aif_name = "MM_UL9",
+ .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 = "MultiMedia9",
+ },
+ {
+ .playback = {
+ .stream_name = "QCHAT Playback",
+ .aif_name = "QCHAT_DL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .capture = {
+ .stream_name = "QCHAT Capture",
+ .aif_name = "QCHAT_UL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "QCHAT",
+ },
};
static __devinit int msm_fe_dai_dev_probe(struct platform_device *pdev)
diff --git a/sound/soc/msm/msm8226.c b/sound/soc/msm/msm8226.c
index 5dfd326..d3ba3d5 100644
--- a/sound/soc/msm/msm8226.c
+++ b/sound/soc/msm/msm8226.c
@@ -36,12 +36,20 @@
#define BTSCO_RATE_8KHZ 8000
#define BTSCO_RATE_16KHZ 16000
+/* It takes about 13ms for Class-D PAs to ramp-up */
+#define EXT_CLASS_D_EN_DELAY 13000
+#define EXT_CLASS_D_DIS_DELAY 3000
+#define EXT_CLASS_D_DELAY_DELTA 2000
+
#define WCD9XXX_MBHC_DEF_BUTTONS 8
#define WCD9XXX_MBHC_DEF_RLOADS 5
#define TAPAN_EXT_CLK_RATE 9600000
#define NUM_OF_AUXPCM_GPIOS 4
+#define LO_1_SPK_AMP 0x1
+#define LO_2_SPK_AMP 0x2
+
static int msm8226_auxpcm_rate = 8000;
static atomic_t auxpcm_rsc_ref;
static const char *const auxpcm_rate_text[] = {"rate_8000", "rate_16000"};
@@ -116,6 +124,7 @@
SLIM_4_TX_1 = 150, /* In-call musid delivery TX */
};
+static int msm8226_ext_spk_pamp;
static int msm_slim_0_rx_ch = 1;
static int msm_slim_0_tx_ch = 1;
@@ -125,6 +134,7 @@
static struct mutex cdc_mclk_mutex;
static struct clk *codec_clk;
static int clk_users;
+static int ext_spk_amp_gpio = -1;
static int vdd_spkr_gpio = -1;
static int msm_proxy_rx_ch = 2;
@@ -189,6 +199,99 @@
return 0;
}
+static void msm8226_ext_spk_power_amp_enable(u32 enable)
+{
+ if (enable) {
+ gpio_direction_output(ext_spk_amp_gpio, enable);
+ /* time takes enable the external power amplifier */
+ usleep_range(EXT_CLASS_D_EN_DELAY,
+ EXT_CLASS_D_EN_DELAY + EXT_CLASS_D_DELAY_DELTA);
+ } else {
+ gpio_direction_output(ext_spk_amp_gpio, enable);
+ /* time takes disable the external power amplifier */
+ usleep_range(EXT_CLASS_D_DIS_DELAY,
+ EXT_CLASS_D_DIS_DELAY + EXT_CLASS_D_DELAY_DELTA);
+ }
+
+ pr_debug("%s: %s external speaker PAs.\n", __func__,
+ enable ? "Enable" : "Disable");
+}
+
+static void msm8226_ext_spk_power_amp_on(u32 spk)
+{
+ if (gpio_is_valid(ext_spk_amp_gpio)) {
+ if (spk & (LO_1_SPK_AMP | LO_2_SPK_AMP)) {
+ pr_debug("%s:Enable left and right speakers case spk = 0x%x\n",
+ __func__, spk);
+
+ msm8226_ext_spk_pamp |= spk;
+
+ if ((msm8226_ext_spk_pamp & LO_1_SPK_AMP) &&
+ (msm8226_ext_spk_pamp & LO_2_SPK_AMP))
+ if (ext_spk_amp_gpio >= 0) {
+ pr_debug("%s enable power", __func__);
+ msm8226_ext_spk_power_amp_enable(1);
+ }
+ } else {
+ pr_err("%s: Invalid external speaker ampl. spk = 0x%x\n",
+ __func__, spk);
+ }
+ }
+}
+
+static void msm8226_ext_spk_power_amp_off(u32 spk)
+{
+ if (gpio_is_valid(ext_spk_amp_gpio)) {
+ if (spk & (LO_1_SPK_AMP | LO_2_SPK_AMP)) {
+ pr_debug("%s Disable left and right speakers case spk = 0x%08x",
+ __func__, spk);
+
+ msm8226_ext_spk_pamp &= ~spk;
+
+ if (!msm8226_ext_spk_pamp) {
+ if (ext_spk_amp_gpio >= 0) {
+ pr_debug("%s disable power", __func__);
+ msm8226_ext_spk_power_amp_enable(0);
+ }
+ msm8226_ext_spk_pamp = 0;
+ }
+ } else {
+ pr_err("%s: ERROR : Invalid Ext Spk Ampl. spk = 0x%08x\n",
+ __func__, spk);
+ }
+ }
+}
+
+static int msm8226_ext_spkramp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ pr_debug("%s()\n", __func__);
+
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ if (!strncmp(w->name, "Lineout_1 amp", 14))
+ msm8226_ext_spk_power_amp_on(LO_1_SPK_AMP);
+ else if (!strncmp(w->name, "Lineout_2 amp", 14))
+ msm8226_ext_spk_power_amp_on(LO_2_SPK_AMP);
+ else {
+ pr_err("%s() Invalid Speaker Widget = %s\n",
+ __func__, w->name);
+ return -EINVAL;
+ }
+ } else {
+ if (!strncmp(w->name, "Lineout_1 amp", 14))
+ msm8226_ext_spk_power_amp_off(LO_1_SPK_AMP);
+ else if (!strncmp(w->name, "Lineout_2 amp", 14))
+ msm8226_ext_spk_power_amp_off(LO_2_SPK_AMP);
+ else {
+ pr_err("%s() Invalid Speaker Widget = %s\n",
+ __func__, w->name);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
static int msm8226_vdd_spkr_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -230,6 +333,9 @@
SND_SOC_DAPM_MIC("Digital Mic5", NULL),
SND_SOC_DAPM_MIC("Digital Mic6", NULL),
+ SND_SOC_DAPM_SPK("Lineout_1 amp", msm8226_ext_spkramp_event),
+ SND_SOC_DAPM_SPK("Lineout_2 amp", msm8226_ext_spkramp_event),
+
SND_SOC_DAPM_SUPPLY("EXT_VDD_SPKR", SND_SOC_NOPM, 0, 0,
msm8226_vdd_spkr_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
};
@@ -1025,6 +1131,21 @@
.ignore_pmdown_time = 1,
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
},
+ {
+ .name = "MSM8226 Media9",
+ .stream_name = "MultiMedia9",
+ .cpu_dai_name = "MultiMedia9",
+ .platform_name = "msm-pcm-dsp.0",
+ .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,
+ /* This dailink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA9,
+ },
/* Backend BT/FM DAI Links */
{
.name = LPASS_BE_INT_BT_SCO_RX,
@@ -1124,7 +1245,7 @@
{
.name = LPASS_BE_AUXPCM_RX,
.stream_name = "AUX PCM Playback",
- .cpu_dai_name = "msm-dai-q6.4106",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.1",
.platform_name = "msm-pcm-routing",
.codec_name = "msm-stub-codec.1",
.codec_dai_name = "msm-stub-rx",
@@ -1139,7 +1260,7 @@
{
.name = LPASS_BE_AUXPCM_TX,
.stream_name = "AUX PCM Capture",
- .cpu_dai_name = "msm-dai-q6.4107",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.1",
.platform_name = "msm-pcm-routing",
.codec_name = "msm-stub-codec.1",
.codec_dai_name = "msm-stub-tx",
@@ -1301,6 +1422,19 @@
.be_hw_params_fixup = msm_be_hw_params_fixup,
.ignore_suspend = 1,
},
+ /* Incall Music 2 BACK END DAI Link */
+ {
+ .name = LPASS_BE_VOICE2_PLAYBACK_TX,
+ .stream_name = "Voice2 Farend Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.32770",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
};
struct snd_soc_card snd_soc_card_msm8226 = {
@@ -1409,7 +1543,7 @@
pdata->us_euro_gpio = of_get_named_gpio(pdev->dev.of_node,
"qcom,cdc-us-euro-gpios", 0);
if (pdata->us_euro_gpio < 0) {
- dev_info(&pdev->dev,
+ dev_dbg(&pdev->dev,
"property %s in node %s not found %d\n",
"qcom,cdc-us-euro-gpios", pdev->dev.of_node->full_name,
pdata->us_euro_gpio);
@@ -1499,7 +1633,7 @@
vdd_spkr_gpio = of_get_named_gpio(pdev->dev.of_node,
"qcom,cdc-vdd-spkr-gpios", 0);
if (vdd_spkr_gpio < 0) {
- dev_err(&pdev->dev,
+ dev_dbg(&pdev->dev,
"Looking up %s property in node %s failed %d\n",
"qcom, cdc-vdd-spkr-gpios",
pdev->dev.of_node->full_name, vdd_spkr_gpio);
@@ -1514,19 +1648,38 @@
}
}
+ ext_spk_amp_gpio = of_get_named_gpio(pdev->dev.of_node,
+ "qcom,cdc-lineout-spkr-gpios", 0);
+ if (ext_spk_amp_gpio < 0) {
+ dev_err(&pdev->dev,
+ "Looking up %s property in node %s failed %d\n",
+ "qcom, cdc-lineout-spkr-gpios",
+ pdev->dev.of_node->full_name, ext_spk_amp_gpio);
+ } else {
+ ret = gpio_request(ext_spk_amp_gpio,
+ "TAPAN_CODEC_LINEOUT_SPKR");
+ if (ret) {
+ /* GPIO to enable EXT AMP exists, but failed request */
+ dev_err(card->dev,
+ "%s: Failed to request tapan amp spkr gpio %d\n",
+ __func__, ext_spk_amp_gpio);
+ goto err_vdd_spkr;
+ }
+ }
+
mbhc_cfg.gpio_level_insert = of_property_read_bool(pdev->dev.of_node,
"qcom,headset-jack-type-NO");
msm8226_setup_hs_jack(pdev, pdata);
ret = msm8226_prepare_codec_mclk(card);
if (ret)
- goto err_vdd_spkr;
+ goto err_lineout_spkr;
ret = snd_soc_register_card(card);
if (ret) {
dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
ret);
- goto err_vdd_spkr;
+ goto err_lineout_spkr;
}
mutex_init(&cdc_mclk_mutex);
@@ -1536,7 +1689,7 @@
dev_err(&pdev->dev, "Looking up %s property in node %s failed",
"qcom,prim-auxpcm-gpio-set",
pdev->dev.of_node->full_name);
- goto err_vdd_spkr;
+ goto err_lineout_spkr;
}
if (!strcmp(auxpcm_pri_gpio_set, "prim-gpio-prim")) {
lpaif_pri_muxsel_virt_addr = ioremap(LPAIF_PRI_MODE_MUXSEL, 4);
@@ -1546,16 +1699,22 @@
dev_err(&pdev->dev, "Invalid value %s for AUXPCM GPIO set\n",
auxpcm_pri_gpio_set);
ret = -EINVAL;
- goto err_vdd_spkr;
+ goto err_lineout_spkr;
}
if (lpaif_pri_muxsel_virt_addr == NULL) {
pr_err("%s Pri muxsel virt addr is null\n", __func__);
ret = -EINVAL;
- goto err_vdd_spkr;
+ goto err_lineout_spkr;
}
return 0;
+err_lineout_spkr:
+ if (ext_spk_amp_gpio >= 0) {
+ gpio_free(ext_spk_amp_gpio);
+ ext_spk_amp_gpio = -1;
+ }
+
err_vdd_spkr:
if (vdd_spkr_gpio >= 0) {
gpio_free(vdd_spkr_gpio);
@@ -1579,11 +1738,15 @@
struct msm8226_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
gpio_free(pdata->mclk_gpio);
- gpio_free(vdd_spkr_gpio);
+ if (vdd_spkr_gpio >= 0)
+ gpio_free(vdd_spkr_gpio);
+ if (ext_spk_amp_gpio >= 0)
+ gpio_free(ext_spk_amp_gpio);
if (pdata->us_euro_gpio > 0)
gpio_free(pdata->us_euro_gpio);
vdd_spkr_gpio = -1;
+ ext_spk_amp_gpio = -1;
snd_soc_unregister_card(card);
return 0;
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 0a86221..b28f0f49 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -208,6 +208,7 @@
static int msm_hdmi_rx_ch = 2;
static int slim0_rx_sample_rate = SAMPLING_RATE_48KHZ;
static int msm_proxy_rx_ch = 2;
+static int hdmi_rx_sample_rate = SAMPLING_RATE_48KHZ;
static struct mutex cdc_mclk_mutex;
static struct clk *codec_clk;
@@ -481,13 +482,12 @@
pr_debug("%s Left and right speakers case spk = 0x%08x",
__func__, spk);
-
+ msm8974_ext_spk_pamp &= ~spk;
if (!msm8974_ext_spk_pamp) {
if (ext_spk_amp_gpio >= 0 &&
msm8974_liquid_dock_dev != NULL &&
msm8974_liquid_dock_dev->dock_plug_det == 0)
msm8974_liquid_ext_spk_power_amp_enable(0);
- msm8974_ext_spk_pamp = 0;
}
} else {
@@ -721,6 +721,8 @@
static const char *const proxy_rx_ch_text[] = {"One", "Two", "Three", "Four",
"Five", "Six", "Seven", "Eight"};
+static char const *hdmi_rx_sample_rate_text[] = {"KHZ_48", "KHZ_96",
+ "KHZ_192"};
static const char *const btsco_rate_text[] = {"8000", "16000"};
static const struct soc_enum msm_btsco_enum[] = {
SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
@@ -941,6 +943,57 @@
return 1;
}
+static int hdmi_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int sample_rate_val = 0;
+
+ switch (hdmi_rx_sample_rate) {
+ case SAMPLING_RATE_192KHZ:
+ sample_rate_val = 2;
+ break;
+
+ case SAMPLING_RATE_96KHZ:
+ sample_rate_val = 1;
+ break;
+
+ case SAMPLING_RATE_48KHZ:
+ default:
+ sample_rate_val = 0;
+ break;
+ }
+
+ ucontrol->value.integer.value[0] = sample_rate_val;
+ pr_debug("%s: hdmi_rx_sample_rate = %d\n", __func__,
+ hdmi_rx_sample_rate);
+
+ return 0;
+}
+
+static int hdmi_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: ucontrol value = %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 2:
+ hdmi_rx_sample_rate = SAMPLING_RATE_192KHZ;
+ break;
+ case 1:
+ hdmi_rx_sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 0:
+ default:
+ hdmi_rx_sample_rate = SAMPLING_RATE_48KHZ;
+ }
+
+ pr_debug("%s: hdmi_rx_sample_rate = %d\n", __func__,
+ hdmi_rx_sample_rate);
+
+ return 0;
+}
+
static int msm_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -1056,7 +1109,7 @@
hdmi_rx_bit_format);
if (channels->max < 2)
channels->min = channels->max = 2;
- rate->min = rate->max = 48000;
+ rate->min = rate->max = hdmi_rx_sample_rate;
channels->min = channels->max = msm_hdmi_rx_ch;
return 0;
@@ -1325,6 +1378,7 @@
SOC_ENUM_SINGLE_EXT(2, rx_bit_format_text),
SOC_ENUM_SINGLE_EXT(3, slim0_rx_sample_rate_text),
SOC_ENUM_SINGLE_EXT(8, proxy_rx_ch_text),
+ SOC_ENUM_SINGLE_EXT(3, hdmi_rx_sample_rate_text),
};
static const struct snd_kcontrol_new msm_snd_controls[] = {
@@ -1348,6 +1402,8 @@
msm_proxy_rx_ch_get, msm_proxy_rx_ch_put),
SOC_ENUM_EXT("Internal BTSCO SampleRate", msm_btsco_enum[0],
msm_btsco_rate_get, msm_btsco_rate_put),
+ SOC_ENUM_EXT("HDMI_RX SampleRate", msm_snd_enum[7],
+ hdmi_rx_sample_rate_get, hdmi_rx_sample_rate_put),
};
static bool msm8974_swap_gnd_mic(struct snd_soc_codec *codec)
@@ -2094,6 +2150,22 @@
/* this dainlink has playback support */
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA8,
},
+ {
+ .name = "QCHAT",
+ .stream_name = "QCHAT",
+ .cpu_dai_name = "QCHAT",
+ .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_QCHAT,
+ },
/* HDMI Hostless */
{
.name = "HDMI_RX_HOSTLESS",
@@ -2230,7 +2302,7 @@
{
.name = LPASS_BE_AUXPCM_RX,
.stream_name = "AUX PCM Playback",
- .cpu_dai_name = "msm-dai-q6.4106",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.1",
.platform_name = "msm-pcm-routing",
.codec_name = "msm-stub-codec.1",
.codec_dai_name = "msm-stub-rx",
@@ -2245,7 +2317,7 @@
{
.name = LPASS_BE_AUXPCM_TX,
.stream_name = "AUX PCM Capture",
- .cpu_dai_name = "msm-dai-q6.4107",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.1",
.platform_name = "msm-pcm-routing",
.codec_name = "msm-stub-codec.1",
.codec_dai_name = "msm-stub-tx",
@@ -2259,7 +2331,7 @@
{
.name = LPASS_BE_SEC_AUXPCM_RX,
.stream_name = "Sec AUX PCM Playback",
- .cpu_dai_name = "msm-dai-q6.4108",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.2",
.platform_name = "msm-pcm-routing",
.codec_name = "msm-stub-codec.1",
.codec_dai_name = "msm-stub-rx",
@@ -2274,7 +2346,7 @@
{
.name = LPASS_BE_SEC_AUXPCM_TX,
.stream_name = "Sec AUX PCM Capture",
- .cpu_dai_name = "msm-dai-q6.4109",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.2",
.platform_name = "msm-pcm-routing",
.codec_name = "msm-stub-codec.1",
.codec_dai_name = "msm-stub-tx",
diff --git a/sound/soc/msm/msm8x10.c b/sound/soc/msm/msm8x10.c
index 4d9632c..340d3db 100644
--- a/sound/soc/msm/msm8x10.c
+++ b/sound/soc/msm/msm8x10.c
@@ -587,7 +587,7 @@
.stream_name = "Secondary MI2S Playback",
.cpu_dai_name = "msm-dai-q6-mi2s.1",
.platform_name = "msm-pcm-routing",
- .codec_name = "msm8x10-wcd-i2c-core.5-000d",
+ .codec_name = MSM8X10_CODEC_NAME,
.codec_dai_name = "msm8x10_wcd_i2s_rx1",
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
@@ -601,7 +601,7 @@
.stream_name = "Primary MI2S Capture",
.cpu_dai_name = "msm-dai-q6-mi2s.0",
.platform_name = "msm-pcm-routing",
- .codec_name = "msm8x10-wcd-i2c-core.5-000d",
+ .codec_name = MSM8X10_CODEC_NAME,
.codec_dai_name = "msm8x10_wcd_i2s_tx1",
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_PRI_MI2S_TX,
diff --git a/sound/soc/msm/qdsp6/q6voice.c b/sound/soc/msm/qdsp6/q6voice.c
index 60f4669..094c58b 100644
--- a/sound/soc/msm/qdsp6/q6voice.c
+++ b/sound/soc/msm/qdsp6/q6voice.c
@@ -2356,10 +2356,11 @@
}
if (common.ec_ref_ext == true) {
ret = voice_send_set_device_cmd_v2(v);
- if (ret < 0)
+ if (ret < 0) {
pr_err("%s: set device V2 failed rc =%x\n",
__func__, ret);
goto fail;
+ }
}
/* send cvs cal */
ret = voice_send_cvs_map_memory_cmd(v);
@@ -3354,10 +3355,11 @@
if (v->voc_state == VOC_CHANGE) {
if (common.ec_ref_ext == true) {
ret = voice_send_set_device_cmd_v2(v);
- if (ret < 0)
+ if (ret < 0) {
pr_err("%s: set device V2 failed\n"
"rc =%x\n", __func__, ret);
goto fail;
+ }
} else {
ret = voice_send_set_device_cmd(v);
if (ret < 0) {
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.c b/sound/soc/msm/qdsp6v2/audio_acdb.c
index 3b6a415..2836b87 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.c
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.c
@@ -20,6 +20,7 @@
#include <linux/mm.h>
#include <linux/msm_audio_ion.h>
#include "audio_acdb.h"
+#include "q6voice.h"
#define MAX_NETWORKS 15
@@ -153,15 +154,18 @@
atomic_set(&acdb_data.valid_asm_custom_top, 1);
}
-void get_adm_custom_topology(struct acdb_cal_block *cal_block)
+int get_adm_custom_topology(struct acdb_cal_block *cal_block)
{
+ 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;
}
+ /* Only return allow one access after memory registered */
if (atomic_read(&acdb_data.valid_adm_custom_top) == 0) {
cal_block->cal_size = 0;
goto done;
@@ -175,17 +179,19 @@
cal_block->cal_kvaddr =
atomic_read(&acdb_data.adm_custom_topology.cal_kvaddr);
done:
- return;
+ return result;
}
-void store_adm_custom_topology(struct cal_block *cal_block)
+int store_adm_custom_topology(struct cal_block *cal_block)
{
+ 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));
+ result = -EINVAL;
goto done;
}
@@ -197,18 +203,21 @@
cal_block->cal_offset +
atomic64_read(&acdb_data.kvaddr));
done:
- return;
+ return result;
}
-void get_asm_custom_topology(struct acdb_cal_block *cal_block)
+int get_asm_custom_topology(struct acdb_cal_block *cal_block)
{
- pr_debug("%s\n", __func__);
+ 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;
}
+ /* Only return allow one access after memory registered */
if (atomic_read(&acdb_data.valid_asm_custom_top) == 0) {
cal_block->cal_size = 0;
goto done;
@@ -222,17 +231,19 @@
cal_block->cal_kvaddr =
atomic_read(&acdb_data.asm_custom_topology.cal_kvaddr);
done:
- return;
+ return result;
}
-void store_asm_custom_topology(struct cal_block *cal_block)
+int store_asm_custom_topology(struct cal_block *cal_block)
{
+ 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));
+ result = -EINVAL;
goto done;
}
@@ -244,24 +255,37 @@
cal_block->cal_offset +
atomic64_read(&acdb_data.kvaddr));
done:
- return;
+ return result;
}
-void get_voice_cal_allocation(struct acdb_cal_block *cal_block)
+int get_voice_cal_allocation(struct acdb_cal_block *cal_block)
{
+ 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;
+ }
+
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);
+done:
+ return result;
}
-void get_aanc_cal(struct acdb_cal_block *cal_block)
+int get_aanc_cal(struct acdb_cal_block *cal_block)
{
- pr_debug("%s\n", __func__);
+ 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;
}
@@ -272,18 +296,20 @@
cal_block->cal_kvaddr =
atomic_read(&acdb_data.aanc_cal.cal_kvaddr);
done:
- return;
+ return result;
}
-void store_aanc_cal(struct cal_block *cal_block)
+int store_aanc_cal(struct cal_block *cal_block)
{
+ 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));
- goto done;
+ result = -EINVAL;
+ goto done;
}
atomic_set(&acdb_data.aanc_cal.cal_size,
@@ -293,15 +319,17 @@
atomic_set(&acdb_data.aanc_cal.cal_kvaddr,
cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
done:
- return;
+ return result;
}
-void get_lsm_cal(struct acdb_cal_block *cal_block)
+int get_lsm_cal(struct acdb_cal_block *cal_block)
{
- pr_debug("%s\n", __func__);
+ 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;
}
@@ -312,17 +340,19 @@
cal_block->cal_kvaddr =
atomic_read(&acdb_data.lsm_cal.cal_kvaddr);
done:
- return;
+ return result;
}
-void store_lsm_cal(struct cal_block *cal_block)
+int store_lsm_cal(struct cal_block *cal_block)
{
+ 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));
+ result = -EINVAL;
goto done;
}
@@ -333,15 +363,17 @@
atomic_set(&acdb_data.lsm_cal.cal_kvaddr,
cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
done:
- return;
+ return result;
}
-void get_anc_cal(struct acdb_cal_block *cal_block)
+int get_anc_cal(struct acdb_cal_block *cal_block)
{
- pr_debug("%s\n", __func__);
+ 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;
}
@@ -352,17 +384,19 @@
cal_block->cal_kvaddr =
atomic_read(&acdb_data.anc_cal.cal_kvaddr);
done:
- return;
+ return result;
}
-void store_anc_cal(struct cal_block *cal_block)
+int store_anc_cal(struct cal_block *cal_block)
{
+ 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));
+ result = -EINVAL;
goto done;
}
@@ -373,22 +407,25 @@
atomic_set(&acdb_data.anc_cal.cal_kvaddr,
cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
done:
- return;
+ return result;
}
-void store_afe_cal(int32_t path, struct cal_block *cal_block)
+int store_afe_cal(int32_t path, struct cal_block *cal_block)
{
+ 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));
+ result = -EINVAL;
goto done;
}
if ((path >= MAX_AUDPROC_TYPES) || (path < 0)) {
pr_err("ACDB=> Bad path sent to %s, path: %d\n",
__func__, path);
+ result = -EINVAL;
goto done;
}
@@ -399,20 +436,23 @@
atomic_set(&acdb_data.afe_cal[path].cal_kvaddr,
cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
done:
- return;
+ return result;
}
-void get_afe_cal(int32_t path, struct acdb_cal_block *cal_block)
+int get_afe_cal(int32_t path, struct acdb_cal_block *cal_block)
{
+ int result = 0;
pr_debug("%s, path = %d\n", __func__, path);
if (cal_block == NULL) {
pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+ result = -EINVAL;
goto done;
}
if ((path >= MAX_AUDPROC_TYPES) || (path < 0)) {
pr_err("ACDB=> Bad path sent to %s, path: %d\n",
__func__, path);
+ result = -EINVAL;
goto done;
}
@@ -423,22 +463,25 @@
cal_block->cal_kvaddr =
atomic_read(&acdb_data.afe_cal[path].cal_kvaddr);
done:
- return;
+ return result;
}
-void store_audproc_cal(int32_t path, struct cal_block *cal_block)
+int store_audproc_cal(int32_t path, struct cal_block *cal_block)
{
+ 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));
+ result = -EINVAL;
goto done;
}
if (path >= MAX_AUDPROC_TYPES) {
pr_err("ACDB=> Bad path sent to %s, path: %d\n",
__func__, path);
+ result = -EINVAL;
goto done;
}
@@ -449,20 +492,23 @@
atomic_set(&acdb_data.audproc_cal[path].cal_kvaddr,
cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
done:
- return;
+ return result;
}
-void get_audproc_cal(int32_t path, struct acdb_cal_block *cal_block)
+int get_audproc_cal(int32_t path, struct acdb_cal_block *cal_block)
{
+ int result = 0;
pr_debug("%s, path = %d\n", __func__, path);
if (cal_block == NULL) {
pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+ result = -EINVAL;
goto done;
}
if (path >= MAX_AUDPROC_TYPES) {
pr_err("ACDB=> Bad path sent to %s, path: %d\n",
__func__, path);
+ result = -EINVAL;
goto done;
}
@@ -473,22 +519,25 @@
cal_block->cal_kvaddr =
atomic_read(&acdb_data.audproc_cal[path].cal_kvaddr);
done:
- return;
+ return result;
}
-void store_audstrm_cal(int32_t path, struct cal_block *cal_block)
+int store_audstrm_cal(int32_t path, struct cal_block *cal_block)
{
+ 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));
+ result = -EINVAL;
goto done;
}
if (path >= MAX_AUDPROC_TYPES) {
pr_err("ACDB=> Bad path sent to %s, path: %d\n",
__func__, path);
+ result = -EINVAL;
goto done;
}
@@ -499,20 +548,23 @@
atomic_set(&acdb_data.audstrm_cal[path].cal_kvaddr,
cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
done:
- return;
+ return result;
}
-void get_audstrm_cal(int32_t path, struct acdb_cal_block *cal_block)
+int get_audstrm_cal(int32_t path, struct acdb_cal_block *cal_block)
{
+ int result = 0;
pr_debug("%s, path = %d\n", __func__, path);
if (cal_block == NULL) {
pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+ result = -EINVAL;
goto done;
}
if (path >= MAX_AUDPROC_TYPES) {
pr_err("ACDB=> Bad path sent to %s, path: %d\n",
__func__, path);
+ result = -EINVAL;
goto done;
}
@@ -523,22 +575,25 @@
cal_block->cal_kvaddr =
atomic_read(&acdb_data.audstrm_cal[path].cal_kvaddr);
done:
- return;
+ return result;
}
-void store_audvol_cal(int32_t path, struct cal_block *cal_block)
+int store_audvol_cal(int32_t path, struct cal_block *cal_block)
{
+ 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));
+ result = -EINVAL;
goto done;
}
if (path >= MAX_AUDPROC_TYPES) {
pr_err("ACDB=> Bad path sent to %s, path: %d\n",
__func__, path);
+ result = -EINVAL;
goto done;
}
@@ -549,20 +604,23 @@
atomic_set(&acdb_data.audvol_cal[path].cal_kvaddr,
cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
done:
- return;
+ return result;
}
-void get_audvol_cal(int32_t path, struct acdb_cal_block *cal_block)
+int get_audvol_cal(int32_t path, struct acdb_cal_block *cal_block)
{
+ int result = 0;
pr_debug("%s, path = %d\n", __func__, path);
if (cal_block == NULL) {
pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+ result = -EINVAL;
goto done;
}
if (path >= MAX_AUDPROC_TYPES || path < 0) {
pr_err("ACDB=> Bad path sent to %s, path: %d\n",
__func__, path);
+ result = -EINVAL;
goto done;
}
@@ -573,15 +631,19 @@
cal_block->cal_kvaddr =
atomic_read(&acdb_data.audvol_cal[path].cal_kvaddr);
done:
- return;
+ return result;
}
-void store_voice_col_data(uint32_t vocproc_type, uint32_t cal_size,
+int store_voice_col_data(uint32_t vocproc_type, uint32_t cal_size,
uint32_t *cal_block)
{
+ int result = 0;
+ pr_debug("%s,\n", __func__);
+
if (cal_size > MAX_COL_SIZE) {
pr_err("%s: col size is to big %d\n", __func__,
cal_size);
+ result = -EINVAL;
goto done;
}
if (copy_from_user(acdb_data.col_data[vocproc_type],
@@ -589,19 +651,24 @@
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);
done:
- return;
+ return result;
}
-void get_voice_col_data(uint32_t vocproc_type,
+int get_voice_col_data(uint32_t vocproc_type,
struct acdb_cal_block *cal_block)
{
+ 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;
}
@@ -612,12 +679,13 @@
cal_block->cal_kvaddr = atomic_read(&acdb_data.
vocproc_col_cal[vocproc_type].cal_kvaddr);
done:
- return;
+ return result;
}
-void store_vocproc_dev_cfg_cal(struct cal_block *cal_block)
+int store_vocproc_dev_cfg_cal(struct cal_block *cal_block)
{
- pr_debug("%s\n", __func__);
+ int result = 0;
+ pr_debug("%s,\n", __func__);
if (cal_block->cal_offset >
@@ -626,6 +694,7 @@
__func__, cal_block->cal_offset,
(long)atomic64_read(&acdb_data.mem_len));
atomic_set(&acdb_data.vocproc_dev_cal.cal_size, 0);
+ result = -EINVAL;
goto done;
}
@@ -639,12 +708,19 @@
atomic64_read(&acdb_data.kvaddr));
done:
- return;
+ return result;
}
-void get_vocproc_dev_cfg_cal(struct acdb_cal_block *cal_block)
+int get_vocproc_dev_cfg_cal(struct acdb_cal_block *cal_block)
{
- pr_debug("%s\n", __func__);
+ 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;
+ }
cal_block->cal_size =
atomic_read(&acdb_data.vocproc_dev_cal.cal_size);
@@ -652,13 +728,16 @@
atomic_read(&acdb_data.vocproc_dev_cal.cal_paddr);
cal_block->cal_kvaddr =
atomic_read(&acdb_data.vocproc_dev_cal.cal_kvaddr);
+done:
+ return result;
}
-void store_vocproc_cal(struct cal_block *cal_block)
+int store_vocproc_cal(struct cal_block *cal_block)
{
- pr_debug("%s\n", __func__);
+ int result = 0;
+ pr_debug("%s,\n", __func__);
if (cal_block->cal_offset >
atomic64_read(&acdb_data.mem_len)) {
@@ -666,6 +745,7 @@
__func__, cal_block->cal_offset,
(long)atomic64_read(&acdb_data.mem_len));
atomic_set(&acdb_data.vocproc_cal.cal_size, 0);
+ result = -EINVAL;
goto done;
}
@@ -679,15 +759,17 @@
atomic64_read(&acdb_data.kvaddr));
done:
- return;
+ return result;
}
-void get_vocproc_cal(struct acdb_cal_block *cal_block)
+int get_vocproc_cal(struct acdb_cal_block *cal_block)
{
- pr_debug("%s\n", __func__);
+ 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;
}
@@ -698,12 +780,13 @@
cal_block->cal_kvaddr =
atomic_read(&acdb_data.vocproc_cal.cal_kvaddr);
done:
- return;
+ return result;
}
-void store_vocstrm_cal(struct cal_block *cal_block)
+int store_vocstrm_cal(struct cal_block *cal_block)
{
- pr_debug("%s\n", __func__);
+ int result = 0;
+ pr_debug("%s,\n", __func__);
if (cal_block->cal_offset >
atomic64_read(&acdb_data.mem_len)) {
@@ -711,6 +794,7 @@
__func__, cal_block->cal_offset,
(long)atomic64_read(&acdb_data.mem_len));
atomic_set(&acdb_data.vocstrm_cal.cal_size, 0);
+ result = -EINVAL;
goto done;
}
@@ -724,15 +808,17 @@
atomic64_read(&acdb_data.kvaddr));
done:
- return;
+ return result;
}
-void get_vocstrm_cal(struct acdb_cal_block *cal_block)
+int get_vocstrm_cal(struct acdb_cal_block *cal_block)
{
- pr_debug("%s\n", __func__);
+ 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;
}
@@ -743,12 +829,13 @@
cal_block->cal_kvaddr =
atomic_read(&acdb_data.vocstrm_cal.cal_kvaddr);
done:
- return;
+ return result;
}
-void store_vocvol_cal(struct cal_block *cal_block)
+int store_vocvol_cal(struct cal_block *cal_block)
{
- pr_debug("%s\n", __func__);
+ int result = 0;
+ pr_debug("%s,\n", __func__);
if (cal_block->cal_offset >
atomic64_read(&acdb_data.mem_len)) {
@@ -756,6 +843,7 @@
__func__, cal_block->cal_offset,
(long)atomic64_read(&acdb_data.mem_len));
atomic_set(&acdb_data.vocvol_cal.cal_size, 0);
+ result = -EINVAL;
goto done;
}
@@ -769,15 +857,17 @@
atomic64_read(&acdb_data.kvaddr));
done:
- return;
+ return result;
}
-void get_vocvol_cal(struct acdb_cal_block *cal_block)
+int get_vocvol_cal(struct acdb_cal_block *cal_block)
{
- pr_debug("%s\n", __func__);
+ 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;
}
@@ -788,47 +878,60 @@
cal_block->cal_kvaddr =
atomic_read(&acdb_data.vocvol_cal.cal_kvaddr);
done:
- return;
+ return result;
}
void store_sidetone_cal(struct sidetone_cal *cal_data)
{
- pr_debug("%s\n", __func__);
+ 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);
}
-
-void get_sidetone_cal(struct sidetone_cal *cal_data)
+int get_sidetone_cal(struct sidetone_cal *cal_data)
{
- pr_debug("%s\n", __func__);
+ int result = 0;
+ pr_debug("%s,\n", __func__);
if (cal_data == NULL) {
pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+ result = -EINVAL;
goto done;
}
cal_data->enable = atomic_read(&acdb_data.sidetone_cal.enable);
cal_data->gain = atomic_read(&acdb_data.sidetone_cal.gain);
done:
- return;
+ return result;
}
-void get_spk_protection_cfg(struct msm_spk_prot_cfg *prot_cfg)
+
+int get_spk_protection_cfg(struct msm_spk_prot_cfg *prot_cfg)
{
+ int result = 0;
+ pr_debug("%s,\n", __func__);
+
mutex_lock(&acdb_data.acdb_mutex);
if (prot_cfg) {
prot_cfg->mode = acdb_data.spk_prot_cfg.mode;
prot_cfg->r0 = acdb_data.spk_prot_cfg.r0;
prot_cfg->t0 = acdb_data.spk_prot_cfg.t0;
- } else
+ } else {
pr_err("%s prot_cfg is NULL\n", __func__);
+ result = -EINVAL;
+ }
mutex_unlock(&acdb_data.acdb_mutex);
+
+ return result;
}
-static void get_spk_protection_status(struct msm_spk_prot_status *status)
+
+static int get_spk_protection_status(struct msm_spk_prot_status *status)
{
+ int result = 0;
+ struct afe_spkr_prot_get_vi_calib calib_resp;
+ pr_debug("%s,\n", __func__);
+
/*Call AFE function here to query the status*/
- struct afe_spkr_prot_get_vi_calib calib_resp;
if (status) {
status->status = -EINVAL;
if (!afe_spk_prot_get_calib_data(&calib_resp)) {
@@ -839,8 +942,42 @@
status->r0 = calib_resp.res_cfg.r0_cali_q24;
}
}
- } else
+ } else {
pr_err("%s invalid params\n", __func__);
+ result = -EINVAL;
+ }
+
+ return result;
+}
+
+static int register_vocvol_table(void)
+{
+ int result = 0;
+ pr_debug("%s\n", __func__);
+
+ result = voc_register_vocproc_vol_table();
+ if (result < 0) {
+ pr_err("%s: Register vocproc vol failed!\n", __func__);
+ goto done;
+ }
+
+done:
+ return result;
+}
+
+static int deregister_vocvol_table(void)
+{
+ int result = 0;
+ pr_debug("%s\n", __func__);
+
+ result = voc_deregister_vocproc_vol_table();
+ if (result < 0) {
+ pr_err("%s: Deregister vocproc vol failed!\n", __func__);
+ goto done;
+ }
+
+done:
+ return result;
}
static int acdb_open(struct inode *inode, struct file *f)
@@ -1033,10 +1170,16 @@
}
if (copy_to_user((void *)arg, &prot_status,
sizeof(prot_status))) {
- pr_err("%s Failed to update prot_status\n", __func__);
+ 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();
+ goto done;
+ case AUDIO_DEREGISTER_VOCPROC_VOL_TABLE:
+ result = deregister_vocvol_table();
+ goto done;
}
if (copy_from_user(&size, (void *) arg, sizeof(size))) {
@@ -1054,13 +1197,16 @@
switch (cmd) {
case AUDIO_SET_VOCPROC_COL_CAL:
- store_voice_col_data(VOCPROC_CAL, size, (uint32_t *)arg);
+ result = store_voice_col_data(VOCPROC_CAL,
+ size, (uint32_t *)arg);
goto done;
case AUDIO_SET_VOCSTRM_COL_CAL:
- store_voice_col_data(VOCSTRM_CAL, size, (uint32_t *)arg);
+ result = store_voice_col_data(VOCSTRM_CAL,
+ size, (uint32_t *)arg);
goto done;
case AUDIO_SET_VOCVOL_COL_CAL:
- store_voice_col_data(VOCVOL_CAL, size, (uint32_t *)arg);
+ result = store_voice_col_data(VOCVOL_CAL,
+ size, (uint32_t *)arg);
goto done;
}
@@ -1083,61 +1229,63 @@
switch (cmd) {
case AUDIO_SET_AUDPROC_TX_CAL:
- store_audproc_cal(TX_CAL, (struct cal_block *)data);
+ result = store_audproc_cal(TX_CAL, (struct cal_block *)data);
goto done;
case AUDIO_SET_AUDPROC_RX_CAL:
- store_audproc_cal(RX_CAL, (struct cal_block *)data);
+ result = store_audproc_cal(RX_CAL, (struct cal_block *)data);
goto done;
case AUDIO_SET_AUDPROC_TX_STREAM_CAL:
- store_audstrm_cal(TX_CAL, (struct cal_block *)data);
+ result = store_audstrm_cal(TX_CAL, (struct cal_block *)data);
goto done;
case AUDIO_SET_AUDPROC_RX_STREAM_CAL:
- store_audstrm_cal(RX_CAL, (struct cal_block *)data);
+ result = store_audstrm_cal(RX_CAL, (struct cal_block *)data);
goto done;
case AUDIO_SET_AUDPROC_TX_VOL_CAL:
- store_audvol_cal(TX_CAL, (struct cal_block *)data);
+ result = store_audvol_cal(TX_CAL, (struct cal_block *)data);
goto done;
case AUDIO_SET_AUDPROC_RX_VOL_CAL:
- store_audvol_cal(RX_CAL, (struct cal_block *)data);
+ result = store_audvol_cal(RX_CAL, (struct cal_block *)data);
goto done;
case AUDIO_SET_AFE_TX_CAL:
- store_afe_cal(TX_CAL, (struct cal_block *)data);
+ result = store_afe_cal(TX_CAL, (struct cal_block *)data);
goto done;
case AUDIO_SET_AFE_RX_CAL:
- store_afe_cal(RX_CAL, (struct cal_block *)data);
+ result = store_afe_cal(RX_CAL, (struct cal_block *)data);
goto done;
case AUDIO_SET_VOCPROC_CAL:
- store_vocproc_cal((struct cal_block *)data);
+ result = store_vocproc_cal((struct cal_block *)data);
goto done;
case AUDIO_SET_VOCPROC_STREAM_CAL:
- store_vocstrm_cal((struct cal_block *)data);
+ result = store_vocstrm_cal((struct cal_block *)data);
goto done;
case AUDIO_SET_VOCPROC_VOL_CAL:
- store_vocvol_cal((struct cal_block *)data);
+ result = store_vocvol_cal((struct cal_block *)data);
goto done;
case AUDIO_SET_VOCPROC_DEV_CFG_CAL:
- store_vocproc_dev_cfg_cal((struct cal_block *)data);
+ result = store_vocproc_dev_cfg_cal((struct cal_block *)data);
goto done;
case AUDIO_SET_SIDETONE_CAL:
store_sidetone_cal((struct sidetone_cal *)data);
goto done;
case AUDIO_SET_ANC_CAL:
- store_anc_cal((struct cal_block *)data);
+ result = store_anc_cal((struct cal_block *)data);
goto done;
case AUDIO_SET_LSM_CAL:
- store_lsm_cal((struct cal_block *)data);
+ result = store_lsm_cal((struct cal_block *)data);
goto done;
case AUDIO_SET_ADM_CUSTOM_TOPOLOGY:
- store_adm_custom_topology((struct cal_block *)data);
+ result = store_adm_custom_topology((struct cal_block *)data);
goto done;
case AUDIO_SET_ASM_CUSTOM_TOPOLOGY:
- store_asm_custom_topology((struct cal_block *)data);
+ result = store_asm_custom_topology((struct cal_block *)data);
goto done;
case AUDIO_SET_AANC_CAL:
- store_aanc_cal((struct cal_block *)data);
+ result = store_aanc_cal((struct cal_block *)data);
goto done;
default:
pr_err("ACDB=> ACDB ioctl not found!\n");
+ result = -EFAULT;
+ goto done;
}
done:
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.h b/sound/soc/msm/qdsp6v2/audio_acdb.h
index 3c644ed..1685894 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.h
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.h
@@ -48,23 +48,23 @@
uint32_t get_adm_tx_topology(void);
uint32_t get_asm_topology(void);
void reset_custom_topology_flags(void);
-void get_adm_custom_topology(struct acdb_cal_block *cal_block);
-void get_asm_custom_topology(struct acdb_cal_block *cal_block);
-void get_voice_cal_allocation(struct acdb_cal_block *cal_block);
-void get_lsm_cal(struct acdb_cal_block *cal_block);
-void get_anc_cal(struct acdb_cal_block *cal_block);
-void get_afe_cal(int32_t path, struct acdb_cal_block *cal_block);
-void get_audproc_cal(int32_t path, struct acdb_cal_block *cal_block);
-void get_audstrm_cal(int32_t path, struct acdb_cal_block *cal_block);
-void get_audvol_cal(int32_t path, struct acdb_cal_block *cal_block);
-void get_voice_col_data(uint32_t vocproc_type,
+int get_adm_custom_topology(struct acdb_cal_block *cal_block);
+int get_asm_custom_topology(struct acdb_cal_block *cal_block);
+int get_voice_cal_allocation(struct acdb_cal_block *cal_block);
+int get_lsm_cal(struct acdb_cal_block *cal_block);
+int get_anc_cal(struct acdb_cal_block *cal_block);
+int get_afe_cal(int32_t path, struct acdb_cal_block *cal_block);
+int get_audproc_cal(int32_t path, struct acdb_cal_block *cal_block);
+int get_audstrm_cal(int32_t path, struct acdb_cal_block *cal_block);
+int get_audvol_cal(int32_t path, struct acdb_cal_block *cal_block);
+int get_voice_col_data(uint32_t vocproc_type,
struct acdb_cal_block *cal_block);
-void get_vocproc_dev_cfg_cal(struct acdb_cal_block *cal_block);
-void get_vocproc_cal(struct acdb_cal_block *cal_block);
-void get_vocstrm_cal(struct acdb_cal_block *cal_block);
-void get_vocvol_cal(struct acdb_cal_block *cal_block);
-void get_sidetone_cal(struct sidetone_cal *cal_data);
-void get_spk_protection_cfg(struct msm_spk_prot_cfg *prot_cfg);
-void get_aanc_cal(struct acdb_cal_block *cal_block);
+int get_vocproc_dev_cfg_cal(struct acdb_cal_block *cal_block);
+int get_vocproc_cal(struct acdb_cal_block *cal_block);
+int get_vocstrm_cal(struct acdb_cal_block *cal_block);
+int get_vocvol_cal(struct acdb_cal_block *cal_block);
+int get_sidetone_cal(struct sidetone_cal *cal_data);
+int get_spk_protection_cfg(struct msm_spk_prot_cfg *prot_cfg);
+int get_aanc_cal(struct acdb_cal_block *cal_block);
#endif
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
index 687f10d..aa6ef6b 100644
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -36,6 +36,7 @@
#include "msm-compr-q6-v2.h"
#include "msm-pcm-routing-v2.h"
#include "audio_ocmem.h"
+#include <sound/tlv.h>
#define COMPRE_CAPTURE_NUM_PERIODS 16
/* Allocate the worst case frame size for compressed audio */
@@ -48,13 +49,14 @@
COMPRE_CAPTURE_HEADER_SIZE) * \
MAX_NUM_FRAMES_PER_BUFFER)
#define COMPRE_OUTPUT_METADATA_SIZE (sizeof(struct output_meta_data_st))
+#define COMPRESSED_LR_VOL_MAX_STEPS 0x20002000
+const DECLARE_TLV_DB_LINEAR(compr_rx_vol_gain, 0,
+ COMPRESSED_LR_VOL_MAX_STEPS);
struct snd_msm {
- struct msm_audio *prtd;
- unsigned volume;
atomic_t audio_ocmem_req;
};
-static struct snd_msm compressed_audio = {NULL, 0x20002000} ;
+static struct snd_msm compressed_audio;
static struct audio_locks the_locks;
@@ -125,6 +127,7 @@
int i = 0;
int time_stamp_flag = 0;
int buffer_length = 0;
+ int stop_playback = 0;
pr_debug("%s opcode =%08x\n", __func__, opcode);
switch (opcode) {
@@ -149,9 +152,15 @@
/*
* check for underrun
*/
+ snd_pcm_stream_lock_irq(substream);
if (runtime->status->hw_ptr >= runtime->control->appl_ptr) {
- pr_info("render stopped");
runtime->render_flag |= SNDRV_RENDER_STOPPED;
+ stop_playback = 1;
+ }
+ snd_pcm_stream_unlock_irq(substream);
+
+ if (stop_playback) {
+ pr_err("underrun! render stopped\n");
break;
}
@@ -609,7 +618,6 @@
populate_codec_list(compr, runtime);
runtime->private_data = compr;
atomic_set(&prtd->eos, 0);
- compressed_audio.prtd = &compr->prtd;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
if (!atomic_cmpxchg(&compressed_audio.audio_ocmem_req, 0, 1))
audio_ocmem_process_req(AUDIO, true);
@@ -621,33 +629,29 @@
return 0;
}
-int compressed_set_volume(unsigned volume)
+static int compressed_set_volume(struct msm_audio *prtd, uint32_t volume)
{
int rc = 0;
int avg_vol = 0;
int lgain = (volume >> 16) & 0xFFFF;
int rgain = volume & 0xFFFF;
- if (compressed_audio.prtd && compressed_audio.prtd->audio_client) {
+ if (prtd && prtd->audio_client) {
pr_debug("%s: channels %d volume 0x%x\n", __func__,
- compressed_audio.prtd->channel_mode, volume);
- if ((compressed_audio.prtd->channel_mode <= 2) &&
+ prtd->channel_mode, volume);
+ if ((prtd->channel_mode == 2) &&
(lgain != rgain)) {
pr_debug("%s: call q6asm_set_lrgain\n", __func__);
- rc = q6asm_set_lrgain(
- compressed_audio.prtd->audio_client,
- lgain, rgain);
+ rc = q6asm_set_lrgain(prtd->audio_client, lgain, rgain);
} else {
avg_vol = (lgain + rgain)/2;
pr_debug("%s: call q6asm_set_volume\n", __func__);
- rc = q6asm_set_volume(
- compressed_audio.prtd->audio_client, avg_vol);
+ rc = q6asm_set_volume(prtd->audio_client, avg_vol);
}
if (rc < 0) {
pr_err("%s: Send Volume command failed rc=%d\n",
__func__, rc);
}
}
- compressed_audio.volume = volume;
return rc;
}
@@ -673,7 +677,6 @@
atomic_read(&compressed_audio.audio_ocmem_req));
prtd->pcm_irq_pos = 0;
q6asm_cmd(prtd->audio_client, CMD_CLOSE);
- compressed_audio.prtd = NULL;
q6asm_audio_client_buf_free_contiguous(dir,
prtd->audio_client);
msm_pcm_routing_dereg_phy_stream(
@@ -815,17 +818,15 @@
(params_periods(params) <= runtime->hw.channels_max))
prtd->channel_mode = params_channels(params);
- ret = compressed_set_volume(0);
+ ret = compressed_set_volume(prtd, 0);
if (ret < 0)
pr_err("%s : Set Volume failed : %d", __func__, ret);
- ret = q6asm_set_softpause(compressed_audio.prtd->audio_client,
- &softpause);
+ ret = q6asm_set_softpause(prtd->audio_client, &softpause);
if (ret < 0)
pr_err("%s: Send SoftPause Param failed ret=%d\n",
__func__, ret);
- ret = q6asm_set_softvolume(compressed_audio.prtd->audio_client,
- &softvol);
+ ret = q6asm_set_softvolume(prtd->audio_client, &softvol);
if (ret < 0)
pr_err("%s: Send SoftVolume Param failed ret=%d\n",
__func__, ret);
@@ -1165,6 +1166,66 @@
return 0;
}
+static int msm_compr_volume_ctl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int rc = 0;
+ struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
+ struct snd_pcm_substream *substream =
+ vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+ struct msm_audio *prtd;
+ int volume = ucontrol->value.integer.value[0];
+
+ pr_debug("%s: volume : %x\n", __func__, volume);
+ if (!substream)
+ return -ENODEV;
+ if (!substream->runtime)
+ return 0;
+ prtd = substream->runtime->private_data;
+ if (prtd)
+ rc = compressed_set_volume(prtd, volume);
+
+ return rc;
+}
+
+static int msm_compr_volume_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
+ struct snd_pcm_substream *substream =
+ vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+ struct msm_audio *prtd;
+
+ pr_debug("%s\n", __func__);
+ if (!substream)
+ return -ENODEV;
+ if (!substream->runtime)
+ return 0;
+ prtd = substream->runtime->private_data;
+ if (prtd)
+ ucontrol->value.integer.value[0] = prtd->volume;
+ return 0;
+}
+
+static int msm_compr_add_controls(struct snd_soc_pcm_runtime *rtd)
+{
+ int ret = 0;
+ struct snd_pcm *pcm = rtd->pcm;
+ struct snd_pcm_volume *volume_info;
+ struct snd_kcontrol *kctl;
+
+ 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_compr_volume_ctl_put;
+ kctl->get = msm_compr_volume_ctl_get;
+ kctl->tlv.p = compr_rx_vol_gain;
+ return 0;
+}
static struct snd_pcm_ops msm_compr_ops = {
.open = msm_compr_open,
@@ -1185,6 +1246,10 @@
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+ ret = msm_compr_add_controls(rtd);
+ if (ret)
+ pr_err("%s, kctl add failed\n", __func__);
return ret;
}
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 16df886..0cf044c 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c
@@ -264,11 +264,12 @@
static struct snd_soc_dai_driver msm_dai_q6_hdmi_hdmi_rx_dai = {
.playback = {
- .rates = SNDRV_PCM_RATE_48000,
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
.channels_min = 2,
.channels_max = 8,
- .rate_max = 48000,
+ .rate_max = 192000,
.rate_min = 48000,
},
.ops = &msm_dai_q6_hdmi_ops,
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index b07e91e..1434970 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -28,6 +28,9 @@
#include <sound/pcm_params.h>
#include <mach/clk.h>
+#define MSM_DAI_PRI_AUXPCM_DT_DEV_ID 1
+#define MSM_DAI_SEC_AUXPCM_DT_DEV_ID 2
+
static const struct afe_clk_cfg lpass_clk_cfg_default = {
AFE_API_VERSION_I2S_CONFIG,
Q6AFE_LPASS_OSR_CLK_2_P048_MHZ,
@@ -39,6 +42,10 @@
};
enum {
STATUS_PORT_STARTED, /* track if AFE port has started */
+ /* track AFE Tx port status for bi-directional transfers */
+ STATUS_TX_PORT,
+ /* track AFE Rx port status for bi-directional transfers */
+ STATUS_RX_PORT,
STATUS_MAX
};
@@ -66,6 +73,16 @@
struct msm_dai_q6_mi2s_dai_config rx_dai;
};
+struct msm_dai_q6_auxpcm_dai_data {
+ /* BITMAP to track Rx and Tx port usage count */
+ DECLARE_BITMAP(auxpcm_port_status, STATUS_MAX);
+ struct mutex rlock; /* auxpcm dev resource lock */
+ u16 rx_pid; /* AUXPCM RX AFE port ID */
+ u16 tx_pid; /* AUXPCM TX AFE port ID */
+ struct afe_clk_cfg clk_cfg; /* hold LPASS clock configuration */
+ struct msm_dai_q6_dai_data bdai_data; /* incoporate base DAI data */
+};
+
/* MI2S format field for AFE_PORT_CMD_I2S_CONFIG command
* 0: linear PCM
* 1: non-linear PCM
@@ -83,27 +100,43 @@
SOC_ENUM_SINGLE_EXT(4, mi2s_format),
};
-static DEFINE_MUTEX(aux_pcm_mutex);
-static int aux_pcm_count;
-
static int msm_dai_q6_auxpcm_hw_params(
struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+ struct msm_dai_q6_auxpcm_dai_data *aux_dai_data =
+ dev_get_drvdata(dai->dev);
+ struct msm_dai_q6_dai_data *dai_data = &aux_dai_data->bdai_data;
struct msm_dai_auxpcm_pdata *auxpcm_pdata =
(struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
+ int rc = 0;
- if (params_channels(params) != 1) {
- dev_err(dai->dev, "AUX PCM supports only mono stream\n");
+ if (params_channels(params) != 1 || (params_rate(params) != 8000 &&
+ params_rate(params) != 16000)) {
+ dev_err(dai->dev, "%s: invalid param chan %d rate %d\n",
+ __func__, params_channels(params), params_rate(params));
return -EINVAL;
}
+
+ mutex_lock(&aux_dai_data->rlock);
+
+ if (test_bit(STATUS_TX_PORT, aux_dai_data->auxpcm_port_status) ||
+ test_bit(STATUS_RX_PORT, aux_dai_data->auxpcm_port_status)) {
+ /* AUXPCM DAI in use */
+ if (dai_data->rate != params_rate(params)) {
+ dev_err(dai->dev, "%s: rate mismatch of running DAI\n",
+ __func__);
+ rc = -EINVAL;
+ }
+ mutex_unlock(&aux_dai_data->rlock);
+ return rc;
+ }
+
dai_data->channels = params_channels(params);
dai_data->rate = params_rate(params);
- switch (dai_data->rate) {
- case 8000:
+ if (dai_data->rate == 8000) {
dai_data->port_config.pcm.pcm_cfg_minor_version =
AFE_API_VERSION_PCM_CONFIG;
dai_data->port_config.pcm.aux_mode = auxpcm_pdata->mode_8k.mode;
@@ -119,8 +152,7 @@
dai_data->port_config.pcm.bit_width = 16;
dai_data->port_config.pcm.slot_number_mapping[0] =
auxpcm_pdata->mode_8k.slot;
- break;
- case 16000:
+ } else {
dai_data->port_config.pcm.pcm_cfg_minor_version =
AFE_API_VERSION_PCM_CONFIG;
dai_data->port_config.pcm.aux_mode =
@@ -138,12 +170,19 @@
dai_data->port_config.pcm.bit_width = 16;
dai_data->port_config.pcm.slot_number_mapping[0] =
auxpcm_pdata->mode_16k.slot;
- break;
- default:
- dev_err(dai->dev, "AUX PCM supports only 8kHz and 16kHz sampling rate\n");
- return -EINVAL;
}
- return 0;
+
+ dev_dbg(dai->dev, "%s: aux_mode %x sync_src %x frame_setting %x\n",
+ __func__, dai_data->port_config.pcm.aux_mode,
+ dai_data->port_config.pcm.sync_src,
+ dai_data->port_config.pcm.frame_setting);
+ dev_dbg(dai->dev, "%s: qtype %x dout %x num_map %x\n",
+ __func__, dai_data->port_config.pcm.quantype,
+ dai_data->port_config.pcm.ctrl_data_out_enable,
+ dai_data->port_config.pcm.slot_number_mapping[0]);
+
+ mutex_unlock(&aux_dai_data->rlock);
+ return rc;
}
static void msm_dai_q6_auxpcm_shutdown(struct snd_pcm_substream *substream,
@@ -151,114 +190,115 @@
{
int rc = 0;
struct afe_clk_cfg *lpass_pcm_src_clk = NULL;
- struct afe_clk_cfg lpass_pcm_oe_clk;
- struct msm_dai_auxpcm_pdata *auxpcm_pdata = NULL;
- unsigned int rx_port = 0;
- unsigned int tx_port = 0;
+ struct msm_dai_q6_auxpcm_dai_data *aux_dai_data =
+ dev_get_drvdata(dai->dev);
- mutex_lock(&aux_pcm_mutex);
+ mutex_lock(&aux_dai_data->rlock);
- if (aux_pcm_count == 0) {
- dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 0. Just return\n",
+ if (!(test_bit(STATUS_TX_PORT, aux_dai_data->auxpcm_port_status) ||
+ test_bit(STATUS_RX_PORT, aux_dai_data->auxpcm_port_status))) {
+ dev_dbg(dai->dev, "%s(): dai->id %d PCM ports already closed\n",
__func__, dai->id);
- mutex_unlock(&aux_pcm_mutex);
- return;
+ goto exit;
}
- aux_pcm_count--;
-
- if (aux_pcm_count > 0) {
- dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d\n",
- __func__, dai->id, aux_pcm_count);
- mutex_unlock(&aux_pcm_mutex);
- return;
- } else if (aux_pcm_count < 0) {
- dev_err(dai->dev, "%s(): ERROR: dai->id %d aux_pcm_count = %d < 0\n",
- __func__, dai->id, aux_pcm_count);
- aux_pcm_count = 0;
- mutex_unlock(&aux_pcm_mutex);
- return;
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ if (test_bit(STATUS_TX_PORT, aux_dai_data->auxpcm_port_status))
+ clear_bit(STATUS_TX_PORT,
+ aux_dai_data->auxpcm_port_status);
+ else {
+ dev_dbg(dai->dev, "%s(): PCM_TX port already closed\n",
+ __func__);
+ goto exit;
+ }
+ } else if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (test_bit(STATUS_RX_PORT, aux_dai_data->auxpcm_port_status))
+ clear_bit(STATUS_RX_PORT,
+ aux_dai_data->auxpcm_port_status);
+ else {
+ dev_dbg(dai->dev, "%s(): PCM_RX port already closed\n",
+ __func__);
+ goto exit;
+ }
+ }
+ if (test_bit(STATUS_TX_PORT, aux_dai_data->auxpcm_port_status) ||
+ test_bit(STATUS_RX_PORT, aux_dai_data->auxpcm_port_status)) {
+ dev_dbg(dai->dev, "%s(): cannot shutdown PCM ports\n",
+ __func__);
+ goto exit;
}
- pr_debug("%s: dai->id = %d aux_pcm_count = %d\n", __func__,
- dai->id, aux_pcm_count);
+ dev_dbg(dai->dev, "%s: dai->id = %d closing PCM AFE ports\n",
+ __func__, dai->id);
- auxpcm_pdata = (struct msm_dai_auxpcm_pdata *)dai->dev->platform_data;
- lpass_pcm_src_clk = (struct afe_clk_cfg *)auxpcm_pdata->clk_cfg;
+ lpass_pcm_src_clk = (struct afe_clk_cfg *) &aux_dai_data->clk_cfg;
- if (dai->id == AFE_PORT_ID_PRIMARY_PCM_RX
- || dai->id == AFE_PORT_ID_PRIMARY_PCM_TX) {
- rx_port = AFE_PORT_ID_PRIMARY_PCM_RX;
- tx_port = AFE_PORT_ID_PRIMARY_PCM_TX;
- } else if (dai->id == AFE_PORT_ID_SECONDARY_PCM_RX
- || dai->id == AFE_PORT_ID_SECONDARY_PCM_TX) {
- rx_port = AFE_PORT_ID_SECONDARY_PCM_RX;
- tx_port = AFE_PORT_ID_SECONDARY_PCM_TX;
- }
-
- rc = afe_close(rx_port); /* can block */
+ rc = afe_close(aux_dai_data->rx_pid); /* can block */
if (IS_ERR_VALUE(rc))
dev_err(dai->dev, "fail to close PCM_RX AFE port\n");
- rc = afe_close(tx_port);
+ rc = afe_close(aux_dai_data->tx_pid);
if (IS_ERR_VALUE(rc))
dev_err(dai->dev, "fail to close AUX PCM TX port\n");
lpass_pcm_src_clk->clk_val1 = 0;
- afe_set_lpass_clock(tx_port, lpass_pcm_src_clk);
- afe_set_lpass_clock(rx_port, lpass_pcm_src_clk);
+ afe_set_lpass_clock(aux_dai_data->rx_pid, lpass_pcm_src_clk);
+ afe_set_lpass_clock(aux_dai_data->tx_pid, lpass_pcm_src_clk);
- memcpy(&lpass_pcm_oe_clk, &lpass_clk_cfg_default,
- sizeof(struct afe_clk_cfg));
- lpass_pcm_oe_clk.clk_val1 = 0;
- afe_set_lpass_clock(rx_port, &lpass_pcm_oe_clk);
-
- mutex_unlock(&aux_pcm_mutex);
+exit:
+ mutex_unlock(&aux_dai_data->rlock);
+ return;
}
static int msm_dai_q6_auxpcm_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+ struct msm_dai_q6_auxpcm_dai_data *aux_dai_data =
+ dev_get_drvdata(dai->dev);
+ struct msm_dai_q6_dai_data *dai_data = &aux_dai_data->bdai_data;
struct msm_dai_auxpcm_pdata *auxpcm_pdata = NULL;
int rc = 0;
unsigned long pcm_clk_rate;
- struct afe_clk_cfg lpass_pcm_oe_clk;
struct afe_clk_cfg *lpass_pcm_src_clk = NULL;
- unsigned int rx_port = 0;
- unsigned int tx_port = 0;
auxpcm_pdata = dai->dev->platform_data;
- lpass_pcm_src_clk = (struct afe_clk_cfg *)auxpcm_pdata->clk_cfg;
+ lpass_pcm_src_clk = (struct afe_clk_cfg *) &aux_dai_data->clk_cfg;
- mutex_lock(&aux_pcm_mutex);
+ mutex_lock(&aux_dai_data->rlock);
- if (aux_pcm_count == 2) {
- dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 2. Just return.\n",
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ if (test_bit(STATUS_TX_PORT,
+ aux_dai_data->auxpcm_port_status)) {
+ dev_dbg(dai->dev, "%s(): PCM_TX port already ON\n",
+ __func__);
+ goto exit;
+ } else
+ set_bit(STATUS_TX_PORT,
+ aux_dai_data->auxpcm_port_status);
+ } else if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (test_bit(STATUS_RX_PORT,
+ aux_dai_data->auxpcm_port_status)) {
+ dev_dbg(dai->dev, "%s(): PCM_RX port already ON\n",
+ __func__);
+ goto exit;
+ } else
+ set_bit(STATUS_RX_PORT,
+ aux_dai_data->auxpcm_port_status);
+ }
+ if (test_bit(STATUS_TX_PORT, aux_dai_data->auxpcm_port_status) &&
+ test_bit(STATUS_RX_PORT, aux_dai_data->auxpcm_port_status)) {
+ dev_dbg(dai->dev, "%s(): PCM ports already set\n", __func__);
+ goto exit;
+ }
+
+ dev_dbg(dai->dev, "%s: dai->id:%d opening afe ports\n",
__func__, dai->id);
- mutex_unlock(&aux_pcm_mutex);
- return 0;
- } else if (aux_pcm_count > 2) {
- dev_err(dai->dev, "%s(): ERROR: dai->id %d aux_pcm_count = %d > 2\n",
- __func__, dai->id, aux_pcm_count);
- mutex_unlock(&aux_pcm_mutex);
- return 0;
- }
-
- aux_pcm_count++;
- if (aux_pcm_count == 2) {
- dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d after increment\n",
- __func__, dai->id, aux_pcm_count);
- mutex_unlock(&aux_pcm_mutex);
- return 0;
- }
-
- pr_debug("%s:dai->id:%d aux_pcm_count = %d. opening afe\n",
- __func__, dai->id, aux_pcm_count);
rc = afe_q6_interface_prepare();
- if (IS_ERR_VALUE(rc))
+ if (IS_ERR_VALUE(rc)) {
dev_err(dai->dev, "fail to open AFE APR\n");
+ goto fail;
+ }
/*
* For AUX PCM Interface the below sequence of clk
@@ -279,54 +319,42 @@
} else {
dev_err(dai->dev, "%s: Invalid AUX PCM rate %d\n", __func__,
dai_data->rate);
- mutex_unlock(&aux_pcm_mutex);
- return -EINVAL;
+ rc = -EINVAL;
+ goto fail;
}
memcpy(lpass_pcm_src_clk, &lpass_clk_cfg_default,
sizeof(struct afe_clk_cfg));
lpass_pcm_src_clk->clk_val1 = pcm_clk_rate;
- memcpy(&lpass_pcm_oe_clk, &lpass_clk_cfg_default,
- sizeof(struct afe_clk_cfg));
- lpass_pcm_oe_clk.clk_val1 = Q6AFE_LPASS_OSR_CLK_12_P288_MHZ;
-
- if (dai->id == AFE_PORT_ID_PRIMARY_PCM_RX ||
- dai->id == AFE_PORT_ID_PRIMARY_PCM_TX) {
- rx_port = AFE_PORT_ID_PRIMARY_PCM_RX;
- tx_port = AFE_PORT_ID_PRIMARY_PCM_TX;
- } else if (dai->id == AFE_PORT_ID_SECONDARY_PCM_RX ||
- dai->id == AFE_PORT_ID_SECONDARY_PCM_TX) {
- rx_port = AFE_PORT_ID_SECONDARY_PCM_RX;
- tx_port = AFE_PORT_ID_SECONDARY_PCM_TX;
- }
-
- rc = afe_set_lpass_clock(rx_port, lpass_pcm_src_clk);
+ rc = afe_set_lpass_clock(aux_dai_data->rx_pid, lpass_pcm_src_clk);
if (rc < 0) {
- pr_err("%s:afe_set_lpass_clock on RX pcm_src_clk failed\n",
- __func__);
+ dev_err(dai->dev,
+ "%s:afe_set_lpass_clock on RX pcm_src_clk failed\n",
+ __func__);
goto fail;
}
- rc = afe_set_lpass_clock(tx_port, lpass_pcm_src_clk);
+ rc = afe_set_lpass_clock(aux_dai_data->tx_pid, lpass_pcm_src_clk);
if (rc < 0) {
- pr_err("%s:afe_set_lpass_clock on TX pcm_src_clk failed\n",
- __func__);
+ dev_err(dai->dev,
+ "%s:afe_set_lpass_clock on TX pcm_src_clk failed\n",
+ __func__);
goto fail;
}
- rc = afe_set_lpass_clock(rx_port, &lpass_pcm_oe_clk);
- if (rc < 0) {
- pr_err("%s:afe_set_lpass_clock on pcm_oe_clk failed\n",
- __func__);
- goto fail;
- }
-
- afe_open(rx_port, &dai_data->port_config, dai_data->rate);
- afe_open(tx_port, &dai_data->port_config, dai_data->rate);
+ afe_open(aux_dai_data->rx_pid, &dai_data->port_config, dai_data->rate);
+ afe_open(aux_dai_data->tx_pid, &dai_data->port_config, dai_data->rate);
+ goto exit;
fail:
- mutex_unlock(&aux_pcm_mutex);
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ clear_bit(STATUS_TX_PORT, aux_dai_data->auxpcm_port_status);
+ else if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ clear_bit(STATUS_RX_PORT, aux_dai_data->auxpcm_port_status);
+
+exit:
+ mutex_unlock(&aux_dai_data->rlock);
return rc;
}
@@ -335,8 +363,8 @@
{
int rc = 0;
- pr_debug("%s:port:%d cmd:%d aux_pcm_count= %d\n",
- __func__, dai->id, cmd, aux_pcm_count);
+ pr_debug("%s:port:%d cmd:%d\n",
+ __func__, dai->id, cmd);
switch (cmd) {
@@ -359,84 +387,33 @@
}
-static int msm_dai_q6_dai_auxpcm_probe(struct snd_soc_dai *dai)
-{
- struct msm_dai_q6_dai_data *dai_data;
- int rc = 0;
- struct msm_dai_auxpcm_pdata *auxpcm_pdata = NULL;
-
- auxpcm_pdata = (struct msm_dai_auxpcm_pdata *)
- dev_get_drvdata(dai->dev);
- dai->dev->platform_data = auxpcm_pdata;
- dai->id = dai->dev->id;
-
-
- dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data), GFP_KERNEL);
-
- if (!dai_data) {
- dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
- dai->id);
- rc = -ENOMEM;
- } else
- dev_set_drvdata(dai->dev, dai_data);
-
- pr_debug("%s : probe done for dai->id %d\n", __func__, dai->id);
- return rc;
-}
-
static int msm_dai_q6_dai_auxpcm_remove(struct snd_soc_dai *dai)
{
- struct msm_dai_q6_dai_data *dai_data;
+ struct msm_dai_q6_auxpcm_dai_data *aux_dai_data;
+ struct afe_clk_cfg *lpass_pcm_src_clk = NULL;
int rc;
- unsigned int rx_port = 0;
- unsigned int tx_port = 0;
- dai_data = dev_get_drvdata(dai->dev);
+ aux_dai_data = dev_get_drvdata(dai->dev);
- mutex_lock(&aux_pcm_mutex);
+ dev_dbg(dai->dev, "%s(): dai->id %d closing afe\n",
+ __func__, dai->id);
- if (aux_pcm_count == 0) {
- dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 0. clean up and return\n",
- __func__, dai->id);
- goto done;
+ if (test_bit(STATUS_TX_PORT, aux_dai_data->auxpcm_port_status) ||
+ test_bit(STATUS_RX_PORT, aux_dai_data->auxpcm_port_status)) {
+ rc = afe_close(aux_dai_data->rx_pid); /* can block */
+ if (IS_ERR_VALUE(rc))
+ dev_err(dai->dev, "fail to close AUXPCM RX AFE port\n");
+ rc = afe_close(aux_dai_data->tx_pid);
+ if (IS_ERR_VALUE(rc))
+ dev_err(dai->dev, "fail to close AUXPCM TX AFE port\n");
+ clear_bit(STATUS_TX_PORT, aux_dai_data->auxpcm_port_status);
+ clear_bit(STATUS_RX_PORT, aux_dai_data->auxpcm_port_status);
}
- aux_pcm_count--;
-
- if (aux_pcm_count > 0) {
- dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d\n",
- __func__, dai->id, aux_pcm_count);
- goto done;
- } else if (aux_pcm_count < 0) {
- dev_err(dai->dev, "%s(): ERROR: dai->id %d aux_pcm_count = %d < 0\n",
- __func__, dai->id, aux_pcm_count);
- goto done;
- }
-
- dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d.closing afe\n",
- __func__, dai->id, aux_pcm_count);
-
- if (dai->id == AFE_PORT_ID_PRIMARY_PCM_RX ||
- dai->id == AFE_PORT_ID_PRIMARY_PCM_TX) {
- rx_port = AFE_PORT_ID_PRIMARY_PCM_RX;
- tx_port = AFE_PORT_ID_PRIMARY_PCM_TX;
- } else if (dai->id == AFE_PORT_ID_SECONDARY_PCM_RX ||
- dai->id == AFE_PORT_ID_SECONDARY_PCM_TX) {
- rx_port = AFE_PORT_ID_SECONDARY_PCM_RX;
- tx_port = AFE_PORT_ID_SECONDARY_PCM_TX;
- }
- rc = afe_close(rx_port); /* can block */
- if (IS_ERR_VALUE(rc))
- dev_err(dai->dev, "fail to close AUX PCM RX AFE port\n");
-
- rc = afe_close(tx_port);
- if (IS_ERR_VALUE(rc))
- dev_err(dai->dev, "fail to close AUX PCM TX AFE port\n");
-done:
- kfree(dai_data);
- snd_soc_unregister_dai(dai->dev);
-
- mutex_unlock(&aux_pcm_mutex);
+ lpass_pcm_src_clk = (struct afe_clk_cfg *) &aux_dai_data->clk_cfg;
+ lpass_pcm_src_clk->clk_val1 = 0;
+ afe_set_lpass_clock(aux_dai_data->rx_pid, lpass_pcm_src_clk);
+ afe_set_lpass_clock(aux_dai_data->tx_pid, lpass_pcm_src_clk);
return 0;
}
@@ -448,31 +425,24 @@
.shutdown = msm_dai_q6_auxpcm_shutdown,
};
-static struct snd_soc_dai_driver msm_dai_q6_aux_pcm_rx_dai = {
+static struct snd_soc_dai_driver msm_dai_q6_aux_pcm_dai = {
.playback = {
- .rates = SNDRV_PCM_RATE_8000,
+ .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
.channels_max = 1,
- .rate_max = 8000,
+ .rate_max = 16000,
.rate_min = 8000,
},
- .ops = &msm_dai_q6_auxpcm_ops,
- .probe = msm_dai_q6_dai_auxpcm_probe,
- .remove = msm_dai_q6_dai_auxpcm_remove,
-};
-
-static struct snd_soc_dai_driver msm_dai_q6_aux_pcm_tx_dai = {
.capture = {
- .rates = SNDRV_PCM_RATE_8000,
+ .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
.channels_max = 1,
- .rate_max = 8000,
+ .rate_max = 16000,
.rate_min = 8000,
},
.ops = &msm_dai_q6_auxpcm_ops,
- .probe = msm_dai_q6_dai_auxpcm_probe,
.remove = msm_dai_q6_dai_auxpcm_remove,
};
@@ -749,6 +719,7 @@
rc = msm_dai_q6_afe_rtproxy_hw_params(params, dai);
break;
case VOICE_PLAYBACK_TX:
+ case VOICE2_PLAYBACK_TX:
case VOICE_RECORD_RX:
case VOICE_RECORD_TX:
rc = msm_dai_q6_psuedo_port_hw_params(params,
@@ -1090,72 +1061,38 @@
static int __devinit msm_auxpcm_dev_probe(struct platform_device *pdev)
{
- int id;
- void *plat_data;
- int rc = 0;
-
- if (pdev->dev.parent == NULL)
- return -ENODEV;
-
- plat_data = dev_get_drvdata(pdev->dev.parent);
-
- rc = of_property_read_u32(pdev->dev.of_node,
- "qcom,msm-auxpcm-dev-id", &id);
- if (rc) {
- dev_err(&pdev->dev, "%s: qcom,msm-auxpcm-dev-id missing in DT node\n",
- __func__);
- return rc;
- }
-
- pdev->id = id;
- dev_set_name(&pdev->dev, "%s.%d", "msm-dai-q6", id);
- dev_dbg(&pdev->dev, "dev name %s\n", dev_name(&pdev->dev));
-
- dev_set_drvdata(&pdev->dev, plat_data);
- pdev->dev.id = id;
-
- switch (id) {
- case AFE_PORT_ID_PRIMARY_PCM_RX:
- case AFE_PORT_ID_SECONDARY_PCM_RX:
- rc = snd_soc_register_dai(&pdev->dev,
- &msm_dai_q6_aux_pcm_rx_dai);
- break;
- case AFE_PORT_ID_PRIMARY_PCM_TX:
- case AFE_PORT_ID_SECONDARY_PCM_TX:
- rc = snd_soc_register_dai(&pdev->dev,
- &msm_dai_q6_aux_pcm_tx_dai);
- break;
- default:
- rc = -ENODEV;
- break;
- }
-
- return rc;
-}
-
-static int __devinit msm_auxpcm_resource_probe(
- struct platform_device *pdev)
-{
- int rc = 0;
- struct msm_dai_auxpcm_pdata *auxpcm_pdata = NULL;
- struct afe_clk_cfg *clk_cfg = NULL;
+ struct msm_dai_q6_auxpcm_dai_data *dai_data;
+ struct msm_dai_auxpcm_pdata *auxpcm_pdata;
uint32_t val_array[RATE_MAX_NUM_OF_AUX_PCM_RATES];
+ const char *intf_name;
+ int rc = 0;
+
+ dai_data = kzalloc(sizeof(struct msm_dai_q6_auxpcm_dai_data),
+ GFP_KERNEL);
+ if (!dai_data) {
+ dev_err(&pdev->dev,
+ "Failed to allocate memory for auxpcm DAI data\n");
+ return -ENOMEM;
+ }
auxpcm_pdata = kzalloc(sizeof(struct msm_dai_auxpcm_pdata),
GFP_KERNEL);
if (!auxpcm_pdata) {
dev_err(&pdev->dev, "Failed to allocate memory for platform data\n");
- return -ENOMEM;
+ goto fail_pdata_nomem;
}
+ dev_dbg(&pdev->dev, "%s: dev %p, dai_data %p, auxpcm_pdata %p\n",
+ __func__, &pdev->dev, dai_data, auxpcm_pdata);
+
rc = of_property_read_u32_array(pdev->dev.of_node,
"qcom,msm-cpudai-auxpcm-mode",
val_array, RATE_MAX_NUM_OF_AUX_PCM_RATES);
if (rc) {
dev_err(&pdev->dev, "%s: qcom,msm-cpudai-auxpcm-mode missing in DT node\n",
__func__);
- goto fail_free_plat;
+ goto fail_invalid_dt;
}
auxpcm_pdata->mode_8k.mode = (u16)val_array[RATE_8KHZ];
auxpcm_pdata->mode_16k.mode = (u16)val_array[RATE_16KHZ];
@@ -1166,7 +1103,7 @@
if (rc) {
dev_err(&pdev->dev, "%s: qcom,msm-cpudai-auxpcm-sync missing in DT node\n",
__func__);
- goto fail_free_plat;
+ goto fail_invalid_dt;
}
auxpcm_pdata->mode_8k.sync = (u16)val_array[RATE_8KHZ];
auxpcm_pdata->mode_16k.sync = (u16)val_array[RATE_16KHZ];
@@ -1178,7 +1115,7 @@
if (rc) {
dev_err(&pdev->dev, "%s: qcom,msm-cpudai-auxpcm-frame missing in DT node\n",
__func__);
- goto fail_free_plat;
+ goto fail_invalid_dt;
}
auxpcm_pdata->mode_8k.frame = (u16)val_array[RATE_8KHZ];
auxpcm_pdata->mode_16k.frame = (u16)val_array[RATE_16KHZ];
@@ -1189,7 +1126,7 @@
if (rc) {
dev_err(&pdev->dev, "%s: qcom,msm-cpudai-auxpcm-quant missing in DT node\n",
__func__);
- goto fail_free_plat;
+ goto fail_invalid_dt;
}
auxpcm_pdata->mode_8k.quant = (u16)val_array[RATE_8KHZ];
auxpcm_pdata->mode_16k.quant = (u16)val_array[RATE_16KHZ];
@@ -1200,7 +1137,7 @@
if (rc) {
dev_err(&pdev->dev, "%s: qcom,msm-cpudai-auxpcm-slot missing in DT node\n",
__func__);
- goto fail_free_plat;
+ goto fail_invalid_dt;
}
auxpcm_pdata->mode_8k.slot = (u16)val_array[RATE_8KHZ];
auxpcm_pdata->mode_16k.slot = (u16)val_array[RATE_16KHZ];
@@ -1211,7 +1148,7 @@
if (rc) {
dev_err(&pdev->dev, "%s: qcom,msm-cpudai-auxpcm-data missing in DT node\n",
__func__);
- goto fail_free_plat;
+ goto fail_invalid_dt;
}
auxpcm_pdata->mode_8k.data = (u16)val_array[RATE_8KHZ];
auxpcm_pdata->mode_16k.data = (u16)val_array[RATE_16KHZ];
@@ -1219,60 +1156,79 @@
rc = of_property_read_u32_array(pdev->dev.of_node,
"qcom,msm-cpudai-auxpcm-pcm-clk-rate",
val_array, RATE_MAX_NUM_OF_AUX_PCM_RATES);
-
+ if (rc) {
+ dev_err(&pdev->dev,
+ "%s: qcom,msm-cpudai-auxpcm-pcm-clk-rate missing in DT\n",
+ __func__);
+ goto fail_invalid_dt;
+ }
auxpcm_pdata->mode_8k.pcm_clk_rate = (int)val_array[RATE_8KHZ];
auxpcm_pdata->mode_16k.pcm_clk_rate = (int)val_array[RATE_16KHZ];
- clk_cfg = kzalloc(sizeof(struct afe_clk_cfg), GFP_KERNEL);
- if (clk_cfg == NULL) {
- pr_err("%s: Failed to allocate memory for clk cfg\n", __func__);
- goto fail_free_plat;
- }
- auxpcm_pdata->clk_cfg = clk_cfg;
-
- platform_set_drvdata(pdev, auxpcm_pdata);
-
- rc = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+ rc = of_property_read_string(pdev->dev.of_node,
+ "qcom,msm-auxpcm-interface", &intf_name);
if (rc) {
- dev_err(&pdev->dev, "%s: failed to add child nodes, rc=%d\n",
+ dev_err(&pdev->dev,
+ "%s: qcom,msm-auxpcm-interface missing in DT node\n",
+ __func__);
+ goto fail_nodev_intf;
+ }
+
+ if (!strncmp(intf_name, "primary", sizeof("primary"))) {
+ dai_data->rx_pid = AFE_PORT_ID_PRIMARY_PCM_RX;
+ dai_data->tx_pid = AFE_PORT_ID_PRIMARY_PCM_TX;
+ pdev->id = MSM_DAI_PRI_AUXPCM_DT_DEV_ID;
+ } else if (!strncmp(intf_name, "secondary", sizeof("secondary"))) {
+ dai_data->rx_pid = AFE_PORT_ID_SECONDARY_PCM_RX;
+ dai_data->tx_pid = AFE_PORT_ID_SECONDARY_PCM_TX;
+ pdev->id = MSM_DAI_SEC_AUXPCM_DT_DEV_ID;
+ } else {
+ dev_err(&pdev->dev, "%s: invalid DT intf name %s\n",
+ __func__, intf_name);
+ goto fail_invalid_intf;
+ }
+
+ mutex_init(&dai_data->rlock);
+ dev_set_name(&pdev->dev, "%s.%d", "msm-dai-q6-auxpcm", pdev->id);
+ dev_dbg(&pdev->dev, "dev name %s\n", dev_name(&pdev->dev));
+
+ dev_set_drvdata(&pdev->dev, dai_data);
+ pdev->dev.platform_data = (void *) auxpcm_pdata;
+
+ rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_aux_pcm_dai);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: auxpcm dai reg failed, rc=%d\n",
__func__, rc);
- goto fail_free_plat1;
+ goto fail_reg_dai;
}
return rc;
-fail_free_plat1:
- kfree(clk_cfg);
-fail_free_plat:
+fail_reg_dai:
+fail_invalid_intf:
+fail_nodev_intf:
+fail_invalid_dt:
kfree(auxpcm_pdata);
+fail_pdata_nomem:
+ kfree(dai_data);
return rc;
}
static int __devexit msm_auxpcm_dev_remove(struct platform_device *pdev)
{
+ struct msm_dai_q6_auxpcm_dai_data *dai_data;
+
+ dai_data = dev_get_drvdata(&pdev->dev);
+
snd_soc_unregister_dai(&pdev->dev);
- return 0;
-}
-static int __devexit msm_auxpcm_resource_remove(
- struct platform_device *pdev)
-{
- struct msm_dai_auxpcm_pdata *auxpcm_pdata;
- struct afe_clk_cfg *clk_cfg;
-
- auxpcm_pdata = dev_get_drvdata(&pdev->dev);
- clk_cfg = (struct afe_clk_cfg *)auxpcm_pdata->clk_cfg;
- kfree(clk_cfg);
- kfree(auxpcm_pdata);
+ mutex_destroy(&dai_data->rlock);
+ kfree(dai_data);
+ kfree(pdev->dev.platform_data);
return 0;
}
-static struct of_device_id msm_auxpcm_resource_dt_match[] = {
- { .compatible = "qcom,msm-auxpcm-resource", },
- {}
-};
-
static struct of_device_id msm_auxpcm_dev_dt_match[] = {
{ .compatible = "qcom,msm-auxpcm-dev", },
{}
@@ -1289,16 +1245,6 @@
},
};
-static struct platform_driver msm_auxpcm_resource_driver = {
- .probe = msm_auxpcm_resource_probe,
- .remove = __devexit_p(msm_auxpcm_resource_remove),
- .driver = {
- .name = "msm-auxpcm-resource",
- .owner = THIS_MODULE,
- .of_match_table = msm_auxpcm_resource_dt_match,
- },
-};
-
static struct snd_soc_dai_driver msm_dai_q6_slimbus_rx_dai = {
.playback = {
.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
@@ -1638,8 +1584,21 @@
goto error_invalid_data;
}
dai_data->rate = params_rate(params);
- dai_data->port_config.i2s.bit_width = 16;
- dai_data->bitwidth = 16;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ case SNDRV_PCM_FORMAT_SPECIAL:
+ dai_data->port_config.i2s.bit_width = 16;
+ dai_data->bitwidth = 16;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ dai_data->port_config.i2s.bit_width = 24;
+ dai_data->bitwidth = 24;
+ break;
+ default:
+ return -EINVAL;
+ }
+
dai_data->port_config.i2s.i2s_cfg_minor_version =
AFE_API_VERSION_I2S_CONFIG;
dai_data->port_config.i2s.sample_rate = dai_data->rate;
@@ -1759,7 +1718,7 @@
.capture = {
.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
SNDRV_PCM_RATE_16000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
.rate_min = 8000,
.rate_max = 48000,
},
@@ -2080,6 +2039,7 @@
rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_afe_tx_dai);
break;
case VOICE_PLAYBACK_TX:
+ case VOICE2_PLAYBACK_TX:
rc = snd_soc_register_dai(&pdev->dev,
&msm_dai_q6_voice_playback_tx_dai);
break;
@@ -2210,14 +2170,9 @@
int rc;
rc = platform_driver_register(&msm_auxpcm_dev_driver);
- if (rc)
- goto fail;
-
- rc = platform_driver_register(&msm_auxpcm_resource_driver);
-
if (rc) {
- pr_err("%s: fail to register cpu dai driver\n", __func__);
- goto aux_pcm_resource_fail;
+ pr_err("%s: fail to register auxpcm dev driver", __func__);
+ goto fail;
}
rc = platform_driver_register(&msm_dai_q6);
@@ -2252,8 +2207,6 @@
dai_q6_dev_fail:
platform_driver_unregister(&msm_dai_q6);
dai_q6_fail:
- platform_driver_unregister(&msm_auxpcm_resource_driver);
-aux_pcm_resource_fail:
platform_driver_unregister(&msm_auxpcm_dev_driver);
fail:
return rc;
@@ -2265,7 +2218,6 @@
platform_driver_unregister(&msm_dai_q6_dev);
platform_driver_unregister(&msm_dai_q6);
platform_driver_unregister(&msm_auxpcm_dev_driver);
- platform_driver_unregister(&msm_auxpcm_resource_driver);
}
module_exit(msm_dai_q6_exit);
diff --git a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
index 9ace410..cd08b39 100644
--- a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
+++ b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
@@ -231,7 +231,7 @@
static int map_device_to_dolby_endpoint(int device)
{
- int i, dolby_dap_device = DOLBY_ENDP_INT_SPEAKERS;
+ int i, dolby_dap_device = DOLBY_ENDP_EXT_SPEAKERS;
for (i = 0; i < NUM_DOLBY_ENDP_DEVICE; i++) {
if (dolby_dap_endp_params[i].device == device) {
dolby_dap_device = dolby_dap_endp_params[i].dap_device;
@@ -557,7 +557,7 @@
return -ENOMEM;
}
if (DOLBY_PARAM_ID_VER == dolby_dap_params_get.param_id) {
- rc = adm_dolby_dap_get_params(dolby_dap_params_get.port_id,
+ rc = adm_get_params(dolby_dap_params_get.port_id,
DOLBY_BUNDLE_MODULE_ID,
DOLBY_PARAM_ID_VER,
params_length +
@@ -575,7 +575,7 @@
params_length = (dolby_dap_params_length[i] +
DOLBY_PARAM_PAYLOAD_SIZE) *
sizeof(uint32_t);
- rc = adm_dolby_dap_get_params(
+ rc = adm_get_params(
dolby_dap_params_get.port_id,
DOLBY_BUNDLE_MODULE_ID,
dolby_dap_params_id[i],
@@ -652,7 +652,7 @@
}
offset = 0;
params_length = length * sizeof(uint32_t);
- rc = adm_dolby_dap_get_params(dolby_dap_params_states.port_id,
+ rc = adm_get_params(dolby_dap_params_states.port_id,
DOLBY_BUNDLE_MODULE_ID,
DOLBY_PARAM_ID_VCBG,
params_length + param_payload_len,
@@ -664,7 +664,7 @@
}
offset = length * sizeof(uint32_t);
- rc = adm_dolby_dap_get_params(dolby_dap_params_states.port_id,
+ rc = adm_get_params(dolby_dap_params_states.port_id,
DOLBY_BUNDLE_MODULE_ID,
DOLBY_PARAM_ID_VCBE,
params_length + param_payload_len,
diff --git a/sound/soc/msm/qdsp6v2/msm-multi-ch-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-multi-ch-pcm-q6-v2.c
index 4297ddb..39e6934 100644
--- a/sound/soc/msm/qdsp6v2/msm-multi-ch-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-multi-ch-pcm-q6-v2.c
@@ -141,7 +141,7 @@
}
case ASM_DATA_EVENT_RENDERED_EOS:
pr_debug("ASM_DATA_CMDRSP_EOS\n");
- prtd->cmd_ack = 1;
+ clear_bit(CMD_EOS, &prtd->cmd_pending);
wake_up(&the_locks.eos_wait);
break;
case ASM_DATA_EVENT_READ_DONE_V2: {
@@ -241,7 +241,7 @@
atomic_set(&prtd->out_count, runtime->periods);
prtd->enabled = 1;
- prtd->cmd_ack = 0;
+ prtd->cmd_pending = 0;
prtd->cmd_interrupt = 0;
return 0;
@@ -299,8 +299,12 @@
atomic_set(&prtd->start, 0);
if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
break;
- prtd->cmd_ack = 0;
+ /* pending CMD_EOS isn't expected */
+ WARN_ON_ONCE(test_bit(CMD_EOS, &prtd->cmd_pending));
+ set_bit(CMD_EOS, &prtd->cmd_pending);
q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
+ if (ret)
+ clear_bit(CMD_EOS, &prtd->cmd_pending);
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
@@ -379,9 +383,6 @@
prtd->audio_client->perf_mode,
prtd->session_id, substream->stream);
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- prtd->cmd_ack = 1;
-
ret = snd_pcm_hw_constraint_list(runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
&constraints_sample_rates);
@@ -502,13 +503,15 @@
int dir = 0;
int ret = 0;
- pr_debug("%s\n", __func__);
+ pr_debug("%s: cmd_pending 0x%lx\n", __func__, prtd->cmd_pending);
dir = IN;
ret = wait_event_timeout(the_locks.eos_wait,
- prtd->cmd_ack, 5 * HZ);
+ !test_bit(CMD_EOS, &prtd->cmd_pending),
+ 5 * HZ);
if (!ret)
- pr_err("%s: CMD_EOS failed\n", __func__);
+ pr_err("%s: CMD_EOS failed, cmd_pending 0x%lx\n",
+ __func__, prtd->cmd_pending);
q6asm_cmd(prtd->audio_client, CMD_CLOSE);
q6asm_audio_client_buf_free_contiguous(dir,
prtd->audio_client);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
index eeb1745..caf77ee 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
@@ -41,12 +41,15 @@
#include "msm-pcm-routing-v2.h"
#include "audio_ocmem.h"
#include <sound/pcm.h>
+#include <sound/tlv.h>
+#define LPA_LR_VOL_MAX_STEPS 0x20002000
+
+const DECLARE_TLV_DB_LINEAR(lpa_rx_vol_gain, 0,
+ LPA_LR_VOL_MAX_STEPS);
static struct audio_locks the_locks;
struct snd_msm {
- struct msm_audio *prtd;
- unsigned volume;
atomic_t audio_ocmem_req;
};
static struct snd_msm lpa_audio;
@@ -414,7 +417,6 @@
atomic_set(&prtd->stop, 1);
atomic_set(&lpa_audio.audio_ocmem_req, 0);
runtime->private_data = prtd;
- lpa_audio.prtd = prtd;
if (!atomic_cmpxchg(&lpa_audio.audio_ocmem_req, 0, 1))
audio_ocmem_process_req(AUDIO, true);
else
@@ -424,19 +426,19 @@
return 0;
}
-int lpa_set_volume(unsigned volume)
+static int lpa_set_volume(struct msm_audio *prtd, uint32_t volume)
{
int rc = 0;
- if (lpa_audio.prtd && lpa_audio.prtd->audio_client) {
- rc = q6asm_set_lrgain(lpa_audio.prtd->audio_client,
- (volume >> 16) & 0xFFFF,
- volume & 0xFFFF);
+ if (prtd && prtd->audio_client) {
+ rc = q6asm_set_lrgain(prtd->audio_client,
+ (volume >> 16) & 0xFFFF, volume & 0xFFFF);
if (rc < 0) {
pr_err("%s: Send Volume command failed rc=%d\n",
- __func__, rc);
+ __func__, rc);
+ } else {
+ prtd->volume = volume;
}
}
- lpa_audio.volume = volume;
return rc;
}
@@ -476,10 +478,8 @@
atomic_dec(&lpa_audio.audio_ocmem_req);
else if (atomic_cmpxchg(&lpa_audio.audio_ocmem_req, 1, 0))
audio_ocmem_process_req(AUDIO, false);
-
pr_debug("%s: req: %d\n", __func__,
atomic_read(&lpa_audio.audio_ocmem_req));
- lpa_audio.prtd = NULL;
q6asm_cmd(prtd->audio_client, CMD_CLOSE);
q6asm_audio_client_buf_free_contiguous(dir,
prtd->audio_client);
@@ -594,12 +594,12 @@
prtd->audio_client->perf_mode,
prtd->session_id, substream->stream);
- lpa_set_volume(0);
- ret = q6asm_set_softpause(lpa_audio.prtd->audio_client, &softpause);
+ lpa_set_volume(prtd, 0);
+ ret = q6asm_set_softpause(prtd->audio_client, &softpause);
if (ret < 0)
pr_err("%s: Send SoftPause Param failed ret=%d\n",
__func__, ret);
- ret = q6asm_set_softvolume(lpa_audio.prtd->audio_client, &softvol);
+ ret = q6asm_set_softvolume(prtd->audio_client, &softvol);
if (ret < 0)
pr_err("%s: Send SoftVolume Param failed ret=%d\n",
__func__, ret);
@@ -695,6 +695,67 @@
return snd_pcm_lib_ioctl(substream, cmd, arg);
}
+static int msm_lpa_volume_ctl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int rc = 0;
+ struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
+ struct snd_pcm_substream *substream =
+ vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+ struct msm_audio *prtd;
+ int volume = ucontrol->value.integer.value[0];
+
+ pr_debug("%s: volume : %x\n", __func__, volume);
+ if (!substream)
+ return -ENODEV;
+ if (!substream->runtime)
+ return 0;
+ prtd = substream->runtime->private_data;
+ if (prtd)
+ rc = lpa_set_volume(prtd, volume);
+
+ return rc;
+}
+
+static int msm_lpa_volume_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
+ struct snd_pcm_substream *substream =
+ vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+ struct msm_audio *prtd;
+
+ pr_debug("%s\n", __func__);
+ if (!substream)
+ return -ENODEV;
+ if (!substream->runtime)
+ return 0;
+ prtd = substream->runtime->private_data;
+ if (prtd)
+ ucontrol->value.integer.value[0] = prtd->volume;
+ return 0;
+}
+
+static int msm_lpa_add_controls(struct snd_soc_pcm_runtime *rtd)
+{
+ int ret = 0;
+ struct snd_pcm *pcm = rtd->pcm->streams[0].pcm;
+ struct snd_pcm_volume *volume_info;
+ struct snd_kcontrol *kctl;
+
+ 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_lpa_volume_ctl_put;
+ kctl->get = msm_lpa_volume_ctl_get;
+ kctl->tlv.p = lpa_rx_vol_gain;
+ return 0;
+}
+
static struct snd_pcm_ops msm_pcm_ops = {
.open = msm_pcm_open,
.hw_params = msm_pcm_hw_params,
@@ -714,6 +775,10 @@
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+ ret = msm_lpa_add_controls(rtd);
+ if (ret)
+ pr_err("%s, kctl add failed\n", __func__);
return ret;
}
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index 11f9e72..11326f6 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -57,7 +57,8 @@
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
.rates = SNDRV_PCM_RATE_8000_48000,
.rate_min = 8000,
.rate_max = 48000,
@@ -142,7 +143,7 @@
}
case ASM_DATA_EVENT_RENDERED_EOS:
pr_debug("ASM_DATA_EVENT_RENDERED_EOS\n");
- prtd->cmd_ack = 1;
+ clear_bit(CMD_EOS, &prtd->cmd_pending);
wake_up(&the_locks.eos_wait);
break;
case ASM_DATA_EVENT_READ_DONE_V2: {
@@ -242,7 +243,7 @@
atomic_set(&prtd->out_count, runtime->periods);
prtd->enabled = 1;
- prtd->cmd_ack = 0;
+ prtd->cmd_pending = 0;
prtd->cmd_interrupt = 0;
return 0;
@@ -254,6 +255,8 @@
struct msm_audio *prtd = runtime->private_data;
int ret = 0;
int i = 0;
+ uint16_t bits_per_sample = 16;
+
pr_debug("%s\n", __func__);
prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
@@ -266,10 +269,19 @@
if (prtd->enabled)
return 0;
+ switch (runtime->format) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ bits_per_sample = 16;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ bits_per_sample = 24;
+ break;
+ }
pr_debug("Samp_rate = %d\n", prtd->samp_rate);
pr_debug("Channel = %d\n", prtd->channel_mode);
- ret = q6asm_enc_cfg_blk_pcm(prtd->audio_client, prtd->samp_rate,
- prtd->channel_mode);
+ ret = q6asm_enc_cfg_blk_pcm_format_support(prtd->audio_client,
+ prtd->samp_rate, prtd->channel_mode,
+ bits_per_sample);
if (ret < 0)
pr_debug("%s: cmd cfg pcm was block failed", __func__);
@@ -300,8 +312,12 @@
atomic_set(&prtd->start, 0);
if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
break;
- prtd->cmd_ack = 0;
+ /* pending CMD_EOS isn't expected */
+ WARN_ON_ONCE(test_bit(CMD_EOS, &prtd->cmd_pending));
+ set_bit(CMD_EOS, &prtd->cmd_pending);
ret = q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
+ if (ret)
+ clear_bit(CMD_EOS, &prtd->cmd_pending);
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
@@ -461,14 +477,16 @@
int dir = 0;
int ret = 0;
- pr_debug("%s\n", __func__);
+ pr_debug("%s: cmd_pending 0x%lx\n", __func__, prtd->cmd_pending);
if (prtd->audio_client) {
dir = IN;
ret = wait_event_timeout(the_locks.eos_wait,
- prtd->cmd_ack, 5 * HZ);
+ !test_bit(CMD_EOS, &prtd->cmd_pending),
+ 5 * HZ);
if (!ret)
- pr_err("%s: CMD_EOS failed\n", __func__);
+ pr_err("%s: CMD_EOS failed, cmd_pending 0x%lx\n",
+ __func__, prtd->cmd_pending);
q6asm_cmd(prtd->audio_client, CMD_CLOSE);
q6asm_audio_client_buf_free_contiguous(dir,
prtd->audio_client);
@@ -689,15 +707,17 @@
msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
prtd->audio_client->perf_mode,
prtd->session_id, substream->stream);
- prtd->cmd_ack = 1;
}
/* Capture Path */
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ if (params_format(params) == SNDRV_PCM_FORMAT_S24_LE)
+ bits_per_sample = 24;
pr_debug("%s Opening %d-ch PCM read stream\n",
__func__, params_channels(params));
- ret = q6asm_open_read(prtd->audio_client, FORMAT_LINEAR_PCM);
+ ret = q6asm_open_read_v2(prtd->audio_client, FORMAT_LINEAR_PCM,
+ bits_per_sample);
if (ret < 0) {
pr_err("%s: q6asm_open_read failed\n", __func__);
q6asm_audio_client_free(prtd->audio_client);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
index 6ded0d9..5d5c995 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
@@ -72,6 +72,13 @@
int enabled;
int close_ack;
int cmd_ack;
+ /*
+ * cmd_ack doesn't tell if paticular command has been sent so can't
+ * determine if it needs to wait for completion.
+ * Use cmd_pending instead when checking whether a command is been
+ * sent or not.
+ */
+ unsigned long cmd_pending;
atomic_t start;
atomic_t stop;
atomic_t out_count;
@@ -86,6 +93,7 @@
char channel_map[8];
int cmd_interrupt;
bool meta_data_mode;
+ uint32_t volume;
};
struct output_meta_data_st {
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 97803b3..edb24fc 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -30,6 +30,7 @@
#include <sound/tlv.h>
#include <sound/asound.h>
#include <sound/pcm_params.h>
+#include <linux/slab.h>
#include "msm-pcm-routing-v2.h"
#include "msm-dolby-dap-config.h"
@@ -40,7 +41,10 @@
u16 port_id; /* AFE port ID */
u8 active; /* track if this backend is enabled */
unsigned long fe_sessions; /* Front-end sessions */
- unsigned long port_sessions; /* track Tx BE ports -> Rx BE */
+ u64 port_sessions; /* track Tx BE ports -> Rx BE
+ * number of BE should not exceed
+ * the size of this field
+ */
unsigned int sample_rate;
unsigned int channel;
unsigned int format;
@@ -82,23 +86,14 @@
#define INT_RX_VOL_MAX_STEPS 0x2000
#define INT_RX_VOL_GAIN 0x2000
-#define INT_RX_LR_VOL_MAX_STEPS 0x20002000
static int msm_route_fm_vol_control;
static const DECLARE_TLV_DB_LINEAR(fm_rx_vol_gain, 0,
INT_RX_VOL_MAX_STEPS);
-static int msm_route_lpa_vol_control;
-static const DECLARE_TLV_DB_LINEAR(lpa_rx_vol_gain, 0,
- INT_RX_LR_VOL_MAX_STEPS);
-
static int msm_route_multimedia2_vol_control;
static const DECLARE_TLV_DB_LINEAR(multimedia2_rx_vol_gain, 0,
INT_RX_VOL_MAX_STEPS);
-static int msm_route_compressed_vol_control;
-static const DECLARE_TLV_DB_LINEAR(compressed_rx_vol_gain, 0,
- INT_RX_LR_VOL_MAX_STEPS);
-
static int msm_route_multimedia5_vol_control;
static const DECLARE_TLV_DB_LINEAR(multimedia5_rx_vol_gain, 0,
INT_RX_VOL_MAX_STEPS);
@@ -217,6 +212,7 @@
{ AFE_PORT_ID_PRIMARY_PCM_RX, 0, 0, 0, 0, 0},
{ AFE_PORT_ID_PRIMARY_PCM_TX, 0, 0, 0, 0, 0},
{ VOICE_PLAYBACK_TX, 0, 0, 0, 0, 0},
+ { VOICE2_PLAYBACK_TX, 0, 0, 0, 0, 0},
{ VOICE_RECORD_RX, 0, 0, 0, 0, 0},
{ VOICE_RECORD_TX, 0, 0, 0, 0, 0},
{ MI2S_RX, 0, 0, 0, 0, 0},
@@ -264,6 +260,8 @@
{INVALID_SESSION, INVALID_SESSION},
/* MULTIMEDIA8 */
{INVALID_SESSION, INVALID_SESSION},
+ /* MULTIMEDIA9 */
+ {INVALID_SESSION, INVALID_SESSION},
};
static uint8_t is_be_dai_extproc(int be_dai)
@@ -511,8 +509,9 @@
topology = get_topology(path_type);
if (set) {
if (!test_bit(val, &msm_bedais[reg].fe_sessions) &&
- (msm_bedais[reg].port_id == VOICE_PLAYBACK_TX))
- voc_start_playback(set);
+ ((msm_bedais[reg].port_id == VOICE_PLAYBACK_TX) ||
+ (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] !=
INVALID_SESSION) {
@@ -555,8 +554,9 @@
}
} else {
if (test_bit(val, &msm_bedais[reg].fe_sessions) &&
- (msm_bedais[reg].port_id == VOICE_PLAYBACK_TX))
- voc_start_playback(set);
+ ((msm_bedais[reg].port_id == VOICE_PLAYBACK_TX) ||
+ (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] !=
INVALID_SESSION) {
@@ -628,6 +628,8 @@
session_id = voc_get_session_id(VOLTE_SESSION_NAME);
else if (val == MSM_FRONTEND_DAI_VOICE2)
session_id = voc_get_session_id(VOICE2_SESSION_NAME);
+ else if (val == MSM_FRONTEND_DAI_QCHAT)
+ session_id = voc_get_session_id(QCHAT_SESSION_NAME);
else
session_id = voc_get_session_id(VOIP_SESSION_NAME);
@@ -970,7 +972,8 @@
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- if (test_bit(mc->shift, &msm_bedais[mc->reg].port_sessions))
+ if (test_bit(mc->shift,
+ (unsigned long *)&msm_bedais[mc->reg].port_sessions))
ucontrol->value.integer.value[0] = 1;
else
ucontrol->value.integer.value[0] = 0;
@@ -987,19 +990,19 @@
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- pr_debug("%s: reg %x shift %x val %ld\n", __func__, mc->reg,
+ pr_debug("%s: reg 0x%x shift 0x%x val %ld\n", __func__, mc->reg,
mc->shift, ucontrol->value.integer.value[0]);
if (ucontrol->value.integer.value[0]) {
afe_loopback(1, msm_bedais[mc->reg].port_id,
msm_bedais[mc->shift].port_id);
set_bit(mc->shift,
- &msm_bedais[mc->reg].port_sessions);
+ (unsigned long *)&msm_bedais[mc->reg].port_sessions);
} else {
afe_loopback(0, msm_bedais[mc->reg].port_id,
msm_bedais[mc->shift].port_id);
clear_bit(mc->shift,
- &msm_bedais[mc->reg].port_sessions);
+ (unsigned long *)&msm_bedais[mc->reg].port_sessions);
}
return 1;
@@ -1022,23 +1025,6 @@
return 0;
}
-static int msm_routing_get_lpa_vol_mixer(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] = msm_route_lpa_vol_control;
- return 0;
-}
-
-static int msm_routing_set_lpa_vol_mixer(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- if (!lpa_set_volume(ucontrol->value.integer.value[0]))
- msm_route_lpa_vol_control =
- ucontrol->value.integer.value[0];
-
- return 0;
-}
-
static int msm_routing_get_multimedia2_vol_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -1077,24 +1063,6 @@
return 0;
}
-static int msm_routing_get_compressed_vol_mixer(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
-
- ucontrol->value.integer.value[0] = msm_route_compressed_vol_control;
- return 0;
-}
-
-static int msm_routing_set_compressed_vol_mixer(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- if (!compressed_set_volume(ucontrol->value.integer.value[0]))
- msm_route_compressed_vol_control =
- ucontrol->value.integer.value[0];
-
- return 0;
-}
-
static int msm_routing_get_channel_map_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -1418,6 +1386,9 @@
SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_PRI_I2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new sec_i2s_rx_mixer_controls[] = {
@@ -1445,6 +1416,9 @@
SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SEC_I2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new slimbus_rx_mixer_controls[] = {
@@ -1472,6 +1446,9 @@
SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SLIMBUS_0_RX,
MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new mi2s_rx_mixer_controls[] = {
@@ -1499,6 +1476,9 @@
SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_MI2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new quaternary_mi2s_rx_mixer_controls[] = {
@@ -1526,6 +1506,9 @@
SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new tertiary_mi2s_rx_mixer_controls[] = {
@@ -1568,6 +1551,9 @@
SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new mi2s_hl_mixer_controls[] = {
@@ -1604,6 +1590,9 @@
SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_PRI_MI2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new hdmi_mixer_controls[] = {
@@ -1631,6 +1620,9 @@
SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_HDMI_RX,
MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
/* incall music delivery mixer */
static const struct snd_kcontrol_new incall_music_delivery_mixer_controls[] = {
@@ -1640,6 +1632,21 @@
SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new incall_music2_delivery_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new slimbus_4_rx_mixer_controls[] = {
@@ -1676,6 +1683,9 @@
SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_INT_BT_SCO_RX,
MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new int_fm_rx_mixer_controls[] = {
@@ -1703,6 +1713,9 @@
SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_INT_FM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_INT_FM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new afe_pcm_rx_mixer_controls[] = {
@@ -1730,6 +1743,9 @@
SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_AFE_PCM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new auxpcm_rx_mixer_controls[] = {
@@ -1757,6 +1773,9 @@
SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_AUXPCM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new sec_auxpcm_rx_mixer_controls[] = {
@@ -1784,6 +1803,9 @@
SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new mmul1_mixer_controls[] = {
@@ -1850,6 +1872,9 @@
SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
MSM_FRONTEND_DAI_MULTIMEDIA4, 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_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new mmul5_mixer_controls[] = {
@@ -1895,6 +1920,9 @@
SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_PRI_I2S_RX,
MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new sec_i2s_rx_voice_mixer_controls[] = {
@@ -1913,6 +1941,9 @@
SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SEC_I2S_RX,
MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new sec_mi2s_rx_voice_mixer_controls[] = {
@@ -1931,6 +1962,9 @@
SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new slimbus_rx_voice_mixer_controls[] = {
@@ -1952,6 +1986,9 @@
SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SLIMBUS_0_RX ,
MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_SLIMBUS_0_RX ,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new bt_sco_rx_voice_mixer_controls[] = {
@@ -1973,6 +2010,9 @@
SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_INT_BT_SCO_RX ,
MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_INT_BT_SCO_RX ,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new mi2s_rx_voice_mixer_controls[] = {
@@ -1994,6 +2034,9 @@
SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_MI2S_RX,
MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new afe_pcm_rx_voice_mixer_controls[] = {
@@ -2015,6 +2058,9 @@
SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_AFE_PCM_RX,
MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new aux_pcm_rx_voice_mixer_controls[] = {
@@ -2036,6 +2082,9 @@
SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_AUXPCM_RX,
MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new sec_aux_pcm_rx_voice_mixer_controls[] = {
@@ -2054,6 +2103,9 @@
SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new hdmi_rx_voice_mixer_controls[] = {
@@ -2075,6 +2127,9 @@
SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_HDMI_RX,
MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new stub_rx_mixer_controls[] = {
@@ -2141,6 +2196,9 @@
SOC_SINGLE_EXT("AUX_PCM_TX_Voice2", MSM_BACKEND_DAI_AUXPCM_TX,
MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX_Voice2", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new tx_volte_mixer_controls[] = {
@@ -2221,6 +2279,33 @@
msm_routing_put_voice_stub_mixer),
};
+static const struct snd_kcontrol_new tx_qchat_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_TX_QCHAT", MSM_BACKEND_DAI_PRI_I2S_TX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX_QCHAT", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX_QCHAT",
+ MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_QCHAT, 1, 0,
+ msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX_QCHAT", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_TX_QCHAT", MSM_BACKEND_DAI_AUXPCM_TX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_TX_QCHAT", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("MI2S_TX_QCHAT", MSM_BACKEND_DAI_MI2S_TX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX_QCHAT", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
static const struct snd_kcontrol_new sbus_0_rx_port_mixer_controls[] = {
SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer,
@@ -2249,7 +2334,7 @@
SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_AUXPCM_RX,
MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer,
msm_routing_put_port_mixer),
- SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_AUXPCM_RX,
MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer,
msm_routing_put_port_mixer),
};
@@ -2262,7 +2347,7 @@
MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer,
msm_routing_put_port_mixer),
SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
- MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer,
+ MSM_BACKEND_DAI_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer,
msm_routing_put_port_mixer),
};
@@ -2381,12 +2466,6 @@
msm_routing_set_fm_vol_mixer, fm_rx_vol_gain),
};
-static const struct snd_kcontrol_new lpa_vol_mixer_controls[] = {
- SOC_SINGLE_EXT_TLV("LPA RX Volume", SND_SOC_NOPM, 0,
- INT_RX_VOL_GAIN, 0, msm_routing_get_lpa_vol_mixer,
- msm_routing_set_lpa_vol_mixer, lpa_rx_vol_gain),
-};
-
static const struct snd_kcontrol_new multimedia2_vol_mixer_controls[] = {
SOC_SINGLE_EXT_TLV("HIFI2 RX Volume", SND_SOC_NOPM, 0,
INT_RX_VOL_GAIN, 0, msm_routing_get_multimedia2_vol_mixer,
@@ -2399,12 +2478,6 @@
msm_routing_set_multimedia5_vol_mixer, multimedia5_rx_vol_gain),
};
-static const struct snd_kcontrol_new compressed_vol_mixer_controls[] = {
- SOC_SINGLE_EXT_TLV("COMPRESSED RX Volume", SND_SOC_NOPM, 0,
- INT_RX_VOL_GAIN, 0, msm_routing_get_compressed_vol_mixer,
- msm_routing_set_compressed_vol_mixer, compressed_rx_vol_gain),
-};
-
static const struct snd_kcontrol_new multi_ch_channel_map_mixer_controls[] = {
SOC_SINGLE_MULTI_EXT("Playback Channel Map", SND_SOC_NOPM, 0, 16,
0, 8, msm_routing_get_channel_map_mixer,
@@ -2516,6 +2589,49 @@
msm_routing_put_dolby_dap_endpoint_control),
};
+int msm_routing_get_rms_value_control(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol) {
+ int rc = 0;
+ char *param_value;
+ int *update_param_value;
+ uint32_t param_length = sizeof(uint32_t);
+ uint32_t param_payload_len = RMS_PAYLOAD_LEN * sizeof(uint32_t);
+ param_value = kzalloc(param_length, GFP_KERNEL);
+ if (!param_value) {
+ pr_err("%s, param memory alloc failed\n", __func__);
+ return -ENOMEM;
+ }
+ rc = adm_get_params(SLIMBUS_0_TX,
+ RMS_MODULEID_APPI_PASSTHRU,
+ RMS_PARAM_FIRST_SAMPLE,
+ param_length + param_payload_len,
+ param_value);
+ if (rc) {
+ pr_err("%s: get parameters failed\n", __func__);
+ kfree(param_value);
+ return -EINVAL;
+ }
+ update_param_value = (int *)param_value;
+ ucontrol->value.integer.value[0] = update_param_value[0];
+
+ pr_debug("%s: FROM DSP value[0] 0x%x\n",
+ __func__, update_param_value[0]);
+ kfree(param_value);
+ return 0;
+}
+
+int msm_routing_put_rms_value_control(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol) {
+ /* not used */
+ return 0;
+}
+
+static const struct snd_kcontrol_new get_rms_controls[] = {
+ SOC_SINGLE_EXT("Get RMS", SND_SOC_NOPM, 0, 0xFFFFFFFF,
+ 0, msm_routing_get_rms_value_control,
+ msm_routing_put_rms_value_control),
+};
+
static const struct snd_kcontrol_new eq_enable_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia1 EQ Enable", SND_SOC_NOPM,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_eq_enable_mixer,
@@ -2763,11 +2879,13 @@
SND_SOC_DAPM_AIF_IN("MM_DL6", "MultiMedia6 Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("MM_DL7", "MultiMedia7 Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("MM_DL8", "MultiMedia8 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("MM_DL9", "MultiMedia9 Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("VOIP_DL", "VoIP Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, 0, 0, 0),
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_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),
SND_SOC_DAPM_AIF_IN("VOICE2_DL", "Voice2 Playback", 0, 0, 0, 0),
@@ -2819,6 +2937,8 @@
/* LSM */
SND_SOC_DAPM_AIF_OUT("LSM_UL_HL", "Listen Audio Service Capture",
0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QCHAT_DL", "QCHAT Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QCHAT_UL", "QCHAT Capture", 0, 0, 0, 0),
/* Backend AIF */
/* Stream name equals to backend dai link stream name
*/
@@ -2862,6 +2982,8 @@
/* incall */
SND_SOC_DAPM_AIF_OUT("VOICE_PLAYBACK_TX", "Voice Farend Playback",
0, 0, 0 , 0),
+ SND_SOC_DAPM_AIF_OUT("VOICE2_PLAYBACK_TX", "Voice2 Farend Playback",
+ 0, 0, 0 , 0),
SND_SOC_DAPM_AIF_OUT("SLIMBUS_4_RX", "Slimbus4 Playback",
0, 0, 0 , 0),
SND_SOC_DAPM_AIF_IN("INCALL_RECORD_TX", "Voice Uplink Capture",
@@ -2945,11 +3067,14 @@
sec_auxpcm_rx_mixer_controls, ARRAY_SIZE(sec_auxpcm_rx_mixer_controls)),
/* incall */
SND_SOC_DAPM_MIXER("Incall_Music Audio Mixer", SND_SOC_NOPM, 0, 0,
- incall_music_delivery_mixer_controls,
- ARRAY_SIZE(incall_music_delivery_mixer_controls)),
+ incall_music_delivery_mixer_controls,
+ ARRAY_SIZE(incall_music_delivery_mixer_controls)),
+ SND_SOC_DAPM_MIXER("Incall_Music_2 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ incall_music2_delivery_mixer_controls,
+ ARRAY_SIZE(incall_music2_delivery_mixer_controls)),
SND_SOC_DAPM_MIXER("SLIMBUS_4_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
- slimbus_4_rx_mixer_controls,
- ARRAY_SIZE(slimbus_4_rx_mixer_controls)),
+ slimbus_4_rx_mixer_controls,
+ ARRAY_SIZE(slimbus_4_rx_mixer_controls)),
/* Voice Mixer */
SND_SOC_DAPM_MIXER("PRI_RX_Voice Mixer",
SND_SOC_NOPM, 0, 0, pri_rx_voice_mixer_controls,
@@ -3048,6 +3173,9 @@
SND_SOC_DAPM_MIXER("PRI_MI2S_RX Port Mixer", SND_SOC_NOPM, 0, 0,
primary_mi2s_rx_port_mixer_controls,
ARRAY_SIZE(primary_mi2s_rx_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QCHAT_Tx Mixer",
+ SND_SOC_NOPM, 0, 0, tx_qchat_mixer_controls,
+ ARRAY_SIZE(tx_qchat_mixer_controls)),
/* Virtual Pins to force backends ON atm */
SND_SOC_DAPM_OUTPUT("BE_OUT"),
SND_SOC_DAPM_INPUT("BE_IN"),
@@ -3066,6 +3194,7 @@
{"PRI_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
{"PRI_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
{"PRI_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"PRI_RX Audio Mixer", "MultiMedia9", "MM_DL9"},
{"PRI_I2S_RX", NULL, "PRI_RX Audio Mixer"},
{"SEC_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -3076,6 +3205,7 @@
{"SEC_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
{"SEC_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
{"SEC_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"SEC_RX Audio Mixer", "MultiMedia9", "MM_DL9"},
{"SEC_I2S_RX", NULL, "SEC_RX Audio Mixer"},
{"SLIMBUS_0_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -3086,6 +3216,7 @@
{"SLIMBUS_0_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
{"SLIMBUS_0_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
{"SLIMBUS_0_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"SLIMBUS_0_RX Audio Mixer", "MultiMedia9", "MM_DL9"},
{"SLIMBUS_0_RX", NULL, "SLIMBUS_0_RX Audio Mixer"},
{"HDMI Mixer", "MultiMedia1", "MM_DL1"},
@@ -3096,12 +3227,18 @@
{"HDMI Mixer", "MultiMedia6", "MM_DL6"},
{"HDMI Mixer", "MultiMedia7", "MM_DL7"},
{"HDMI Mixer", "MultiMedia8", "MM_DL8"},
+ {"HDMI Mixer", "MultiMedia9", "MM_DL9"},
{"HDMI", NULL, "HDMI Mixer"},
/* incall */
{"Incall_Music Audio Mixer", "MultiMedia1", "MM_DL1"},
{"Incall_Music Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"Incall_Music Audio Mixer", "MultiMedia9", "MM_DL9"},
{"VOICE_PLAYBACK_TX", NULL, "Incall_Music Audio Mixer"},
+ {"Incall_Music_2 Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"Incall_Music_2 Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"Incall_Music_2 Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"VOICE2_PLAYBACK_TX", NULL, "Incall_Music_2 Audio Mixer"},
{"SLIMBUS_4_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"SLIMBUS_4_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"SLIMBUS_4_RX", NULL, "SLIMBUS_4_RX Audio Mixer"},
@@ -3110,6 +3247,7 @@
{"MultiMedia1 Mixer", "VOC_REC_DL", "INCALL_RECORD_RX"},
{"MultiMedia1 Mixer", "SLIM_4_TX", "SLIMBUS_4_TX"},
{"MultiMedia4 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+ {"MultiMedia4 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"},
@@ -3119,6 +3257,7 @@
{"MI2S_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
{"MI2S_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
{"MI2S_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"MI2S_RX Audio Mixer", "MultiMedia9", "MM_DL9"},
{"MI2S_RX", NULL, "MI2S_RX Audio Mixer"},
{"QUAT_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -3174,6 +3313,7 @@
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
{"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"},
{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX Audio Mixer"},
{"INTERNAL_FM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -3184,6 +3324,7 @@
{"INTERNAL_FM_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
{"INTERNAL_FM_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
{"INTERNAL_FM_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"INTERNAL_FM_RX Audio Mixer", "MultiMedia9", "MM_DL9"},
{"INT_FM_RX", NULL, "INTERNAL_FM_RX Audio Mixer"},
{"AFE_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -3194,6 +3335,7 @@
{"AFE_PCM_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
{"AFE_PCM_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
{"AFE_PCM_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"AFE_PCM_RX Audio Mixer", "MultiMedia9", "MM_DL9"},
{"PCM_RX", NULL, "AFE_PCM_RX Audio Mixer"},
{"MultiMedia1 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
@@ -3217,6 +3359,7 @@
{"AUX_PCM_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"AUX_PCM_RX Audio Mixer", "MultiMedia9", "MM_DL9"},
{"AUX_PCM_RX", NULL, "AUX_PCM_RX Audio Mixer"},
{"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -3227,6 +3370,7 @@
{"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
{"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
{"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia9", "MM_DL9"},
{"SEC_AUX_PCM_RX", NULL, "SEC_AUX_PCM_RX Audio Mixer"},
{"MI2S_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -3234,6 +3378,7 @@
{"MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"MI2S_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
{"MI2S_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"MI2S_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
{"MI2S_RX", NULL, "MI2S_RX_Voice Mixer"},
{"PRI_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -3241,6 +3386,7 @@
{"PRI_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"PRI_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"PRI_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"PRI_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
{"PRI_I2S_RX", NULL, "PRI_RX_Voice Mixer"},
{"SEC_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -3248,6 +3394,7 @@
{"SEC_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"SEC_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"SEC_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"SEC_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
{"SEC_I2S_RX", NULL, "SEC_RX_Voice Mixer"},
{"SEC_MI2S_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -3255,6 +3402,7 @@
{"SEC_MI2S_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"SEC_MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"SEC_MI2S_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"SEC_MI2S_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
{"SEC_MI2S_RX", NULL, "SEC_MI2S_RX_Voice Mixer"},
{"SLIM_0_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -3263,6 +3411,7 @@
{"SLIM_0_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"SLIM_0_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"SLIM_0_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"SLIM_0_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
{"SLIMBUS_0_RX", NULL, "SLIM_0_RX_Voice Mixer"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -3270,6 +3419,7 @@
{"INTERNAL_BT_SCO_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"INTERNAL_BT_SCO_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX_Voice Mixer"},
{"AFE_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -3277,6 +3427,7 @@
{"AFE_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"AFE_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"AFE_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"AFE_PCM_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
{"PCM_RX", NULL, "AFE_PCM_RX_Voice Mixer"},
{"AUX_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -3285,6 +3436,7 @@
{"AUX_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"AUX_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"AUX_PCM_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"AUX_PCM_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
{"AUX_PCM_RX", NULL, "AUX_PCM_RX_Voice Mixer"},
{"SEC_AUX_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -3292,6 +3444,7 @@
{"SEC_AUX_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"SEC_AUX_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"SEC_AUX_PCM_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"SEC_AUX_PCM_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
{"SEC_AUX_PCM_RX", NULL, "SEC_AUX_PCM_RX_Voice Mixer"},
{"HDMI_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -3299,6 +3452,7 @@
{"HDMI_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"HDMI_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"HDMI_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"HDMI_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
{"HDMI", NULL, "HDMI_RX_Voice Mixer"},
{"HDMI", NULL, "HDMI_DL_HL"},
@@ -3307,6 +3461,7 @@
{"MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"MI2S_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"MI2S_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"MI2S_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
{"MI2S_RX", NULL, "MI2S_RX_Voice Mixer"},
{"Voice_Tx Mixer", "PRI_TX_Voice", "PRI_I2S_TX"},
@@ -3320,6 +3475,7 @@
{"CS-VOICE_UL1", NULL, "Voice_Tx Mixer"},
{"Voice2_Tx Mixer", "PRI_TX_Voice2", "PRI_I2S_TX"},
+ {"Voice2_Tx Mixer", "PRI_MI2S_TX_Voice2", "PRI_MI2S_TX"},
{"Voice2_Tx Mixer", "MI2S_TX_Voice2", "MI2S_TX"},
{"Voice2_Tx Mixer", "SLIM_0_TX_Voice2", "SLIMBUS_0_TX"},
{"Voice2_Tx Mixer", "INTERNAL_BT_SCO_TX_Voice2", "INT_BT_SCO_TX"},
@@ -3365,6 +3521,16 @@
{"LSM1 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
{"LSM_UL_HL", NULL, "LSM1 MUX"},
+ {"QCHAT_Tx Mixer", "PRI_TX_QCHAT", "PRI_I2S_TX"},
+ {"QCHAT_Tx Mixer", "SLIM_0_TX_QCHAT", "SLIMBUS_0_TX"},
+ {"QCHAT_Tx Mixer", "INTERNAL_BT_SCO_TX_QCHAT", "INT_BT_SCO_TX"},
+ {"QCHAT_Tx Mixer", "AFE_PCM_TX_QCHAT", "PCM_TX"},
+ {"QCHAT_Tx Mixer", "AUX_PCM_TX_QCHAT", "AUX_PCM_TX"},
+ {"QCHAT_Tx Mixer", "SEC_AUX_PCM_TX_QCHAT", "SEC_AUX_PCM_TX"},
+ {"QCHAT_Tx Mixer", "MI2S_TX_QCHAT", "MI2S_TX"},
+ {"QCHAT_Tx Mixer", "PRI_MI2S_TX_QCHAT", "PRI_MI2S_TX"},
+ {"QCHAT_UL", NULL, "QCHAT_Tx Mixer"},
+
{"INT_FM_RX", NULL, "INTFM_DL_HL"},
{"INTFM_UL_HL", NULL, "INT_FM_TX"},
{"AUX_PCM_RX", NULL, "AUXPCM_DL_HL"},
@@ -3466,6 +3632,7 @@
{"BE_OUT", NULL, "AUX_PCM_RX"},
{"BE_OUT", NULL, "SEC_AUX_PCM_RX"},
{"BE_OUT", NULL, "VOICE_PLAYBACK_TX"},
+ {"BE_OUT", NULL, "VOICE2_PLAYBACK_TX"},
{"PRI_I2S_TX", NULL, "BE_IN"},
{"MI2S_TX", NULL, "BE_IN"},
@@ -3674,10 +3841,6 @@
ARRAY_SIZE(int_fm_vol_mixer_controls));
snd_soc_add_platform_controls(platform,
- lpa_vol_mixer_controls,
- ARRAY_SIZE(lpa_vol_mixer_controls));
-
- snd_soc_add_platform_controls(platform,
eq_enable_mixer_controls,
ARRAY_SIZE(eq_enable_mixer_controls));
@@ -3698,10 +3861,6 @@
ARRAY_SIZE(multimedia5_vol_mixer_controls));
snd_soc_add_platform_controls(platform,
- compressed_vol_mixer_controls,
- ARRAY_SIZE(compressed_vol_mixer_controls));
-
- snd_soc_add_platform_controls(platform,
lpa_SRS_trumedia_controls,
ARRAY_SIZE(lpa_SRS_trumedia_controls));
@@ -3747,6 +3906,10 @@
snd_soc_add_platform_controls(platform,
ec_ref_rx_mixer_controls,
ARRAY_SIZE(ec_ref_rx_mixer_controls));
+
+ snd_soc_add_platform_controls(platform,
+ get_rms_controls,
+ ARRAY_SIZE(get_rms_controls));
return 0;
}
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
index 9750756..10be150 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
@@ -29,6 +29,7 @@
#define LPASS_BE_SEC_AUXPCM_RX "SEC_AUX_PCM_RX"
#define LPASS_BE_SEC_AUXPCM_TX "SEC_AUX_PCM_TX"
#define LPASS_BE_VOICE_PLAYBACK_TX "VOICE_PLAYBACK_TX"
+#define LPASS_BE_VOICE2_PLAYBACK_TX "VOICE2_PLAYBACK_TX"
#define LPASS_BE_INCALL_RECORD_RX "INCALL_RECORD_TX"
#define LPASS_BE_INCALL_RECORD_TX "INCALL_RECORD_RX"
#define LPASS_BE_SEC_I2S_RX "SECONDARY_I2S_RX"
@@ -70,6 +71,7 @@
MSM_FRONTEND_DAI_MULTIMEDIA6,
MSM_FRONTEND_DAI_MULTIMEDIA7,
MSM_FRONTEND_DAI_MULTIMEDIA8,
+ MSM_FRONTEND_DAI_MULTIMEDIA9,
MSM_FRONTEND_DAI_CS_VOICE,
MSM_FRONTEND_DAI_VOIP,
MSM_FRONTEND_DAI_AFE_RX,
@@ -79,11 +81,12 @@
MSM_FRONTEND_DAI_DTMF_RX,
MSM_FRONTEND_DAI_LSM1,
MSM_FRONTEND_DAI_VOICE2,
+ MSM_FRONTEND_DAI_QCHAT,
MSM_FRONTEND_DAI_MAX,
};
-#define MSM_FRONTEND_DAI_MM_SIZE (MSM_FRONTEND_DAI_MULTIMEDIA8 + 1)
-#define MSM_FRONTEND_DAI_MM_MAX_ID MSM_FRONTEND_DAI_MULTIMEDIA8
+#define MSM_FRONTEND_DAI_MM_SIZE (MSM_FRONTEND_DAI_MULTIMEDIA9 + 1)
+#define MSM_FRONTEND_DAI_MM_MAX_ID MSM_FRONTEND_DAI_MULTIMEDIA9
enum {
MSM_BACKEND_DAI_PRI_I2S_RX = 0,
@@ -100,6 +103,7 @@
MSM_BACKEND_DAI_AUXPCM_RX,
MSM_BACKEND_DAI_AUXPCM_TX,
MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+ MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX,
MSM_BACKEND_DAI_INCALL_RECORD_RX,
MSM_BACKEND_DAI_INCALL_RECORD_TX,
MSM_BACKEND_DAI_MI2S_RX,
@@ -140,14 +144,10 @@
void msm_pcm_routing_dereg_phy_stream(int fedai_id, int stream_type);
-int lpa_set_volume(unsigned volume);
-
int msm_routing_check_backend_enabled(int fedai_id);
int multi_ch_pcm_set_volume(unsigned volume);
-int compressed_set_volume(unsigned volume);
-
uint32_t get_adm_rx_topology(void);
uint32_t get_adm_tx_topology(void);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
index 5c420ed..1074d76 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
@@ -51,7 +51,7 @@
.fifo_size = 0,
};
-static int is_volte(struct msm_voice *pvolte)
+static bool is_volte(struct msm_voice *pvolte)
{
if (pvolte == &voice_info[VOLTE_SESSION_INDEX])
return true;
@@ -59,7 +59,7 @@
return false;
}
-static int is_voice2(struct msm_voice *pvoice2)
+static bool is_voice2(struct msm_voice *pvoice2)
{
if (pvoice2 == &voice_info[VOICE2_SESSION_INDEX])
return true;
@@ -67,6 +67,14 @@
return false;
}
+static bool is_qchat(struct msm_voice *pqchat)
+{
+ if (pqchat == &voice_info[QCHAT_SESSION_INDEX])
+ return true;
+ else
+ return false;
+}
+
static uint32_t get_session_id(struct msm_voice *pvoc)
{
uint32_t session_id = 0;
@@ -75,6 +83,8 @@
session_id = voc_get_session_id(VOLTE_SESSION_NAME);
else if (is_voice2(pvoc))
session_id = voc_get_session_id(VOICE2_SESSION_NAME);
+ else if (is_qchat(pvoc))
+ session_id = voc_get_session_id(QCHAT_SESSION_NAME);
else
session_id = voc_get_session_id(VOICE_SESSION_NAME);
@@ -120,6 +130,10 @@
voice = &voice_info[VOICE2_SESSION_INDEX];
pr_debug("%s: Open Voice2 Substream Id=%s\n",
__func__, substream->pcm->id);
+ } else if (!strncmp("QCHAT", substream->pcm->id, 5)) {
+ voice = &voice_info[QCHAT_SESSION_INDEX];
+ pr_debug("%s: Open QCHAT Substream Id=%s\n",
+ __func__, substream->pcm->id);
} else {
voice = &voice_info[VOICE_SESSION_INDEX];
pr_debug("%s: Open VOICE Substream Id=%s\n",
@@ -333,174 +347,83 @@
return ret;
}
-static int msm_voice_volume_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int msm_voice_gain_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
- ucontrol->value.integer.value[0] = 0;
- return 0;
-}
-
-static int msm_voice_volume_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
+ int ret = 0;
int volume = ucontrol->value.integer.value[0];
- pr_debug("%s: volume: %d\n", __func__, volume);
- voc_set_rx_vol_index(voc_get_session_id(VOICE_SESSION_NAME),
- RX_PATH, volume);
- return 0;
-}
+ uint32_t session_id = ucontrol->value.integer.value[1];
+ int ramp_duration = ucontrol->value.integer.value[2];
-static int msm_volte_volume_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] = 0;
- return 0;
-}
+ if ((volume < 0) || (ramp_duration < 0)
+ || (ramp_duration > MAX_RAMP_DURATION)) {
+ pr_err(" %s Invalid arguments", __func__);
-static int msm_volte_volume_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int volume = ucontrol->value.integer.value[0];
- pr_debug("%s: volume: %d\n", __func__, volume);
- voc_set_rx_vol_index(voc_get_session_id(VOLTE_SESSION_NAME),
- RX_PATH, volume);
- return 0;
-}
+ ret = -EINVAL;
+ goto done;
+ }
-static int msm_voice2_volume_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] = 0;
- return 0;
-}
+ pr_debug("%s: volume: %d session_id: %#x ramp_duration: %d\n", __func__,
+ volume, session_id, ramp_duration);
-static int msm_voice2_volume_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int volume = ucontrol->value.integer.value[0];
- pr_debug("%s: volume: %d\n", __func__, volume);
+ voc_set_rx_vol_step(session_id, RX_PATH, volume, ramp_duration);
- voc_set_rx_vol_index(voc_get_session_id(VOICE2_SESSION_NAME),
- RX_PATH, volume);
- return 0;
-}
-
-static int msm_voice_mute_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] = 0;
- return 0;
+done:
+ return ret;
}
static int msm_voice_mute_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+ struct snd_ctl_elem_value *ucontrol)
{
+ int ret = 0;
int mute = ucontrol->value.integer.value[0];
+ uint32_t session_id = ucontrol->value.integer.value[1];
+ int ramp_duration = ucontrol->value.integer.value[2];
- pr_debug("%s: mute=%d\n", __func__, mute);
+ if ((mute < 0) || (mute > 1) || (ramp_duration < 0)
+ || (ramp_duration > MAX_RAMP_DURATION)) {
+ pr_err(" %s Invalid arguments", __func__);
- voc_set_tx_mute(voc_get_session_id(VOICE_SESSION_NAME), TX_PATH, mute);
+ ret = -EINVAL;
+ goto done;
+ }
- return 0;
+ pr_debug("%s: mute=%d session_id=%#x ramp_duration=%d\n", __func__,
+ mute, session_id, ramp_duration);
+
+ voc_set_tx_mute(session_id, TX_PATH, mute, ramp_duration);
+
+done:
+ return ret;
}
-static int msm_volte_mute_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] = 0;
- return 0;
-}
-
-static int msm_volte_mute_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int mute = ucontrol->value.integer.value[0];
-
- pr_debug("%s: mute=%d\n", __func__, mute);
-
- voc_set_tx_mute(voc_get_session_id(VOLTE_SESSION_NAME), TX_PATH, mute);
-
- return 0;
-}
-
-static int msm_voice2_mute_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] = 0;
- return 0;
-}
-
-static int msm_voice2_mute_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int mute = ucontrol->value.integer.value[0];
-
- pr_debug("%s: mute=%d\n", __func__, mute);
-
- voc_set_tx_mute(voc_get_session_id(VOICE2_SESSION_NAME), TX_PATH, mute);
-
- return 0;
-}
-
-static int msm_voice_rx_device_mute_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] =
- voc_get_rx_device_mute(voc_get_session_id(VOICE_SESSION_NAME));
- return 0;
-}
static int msm_voice_rx_device_mute_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
+ int ret = 0;
int mute = ucontrol->value.integer.value[0];
+ uint32_t session_id = ucontrol->value.integer.value[1];
+ int ramp_duration = ucontrol->value.integer.value[2];
- pr_debug("%s: mute=%d\n", __func__, mute);
+ if ((mute < 0) || (mute > 1) || (ramp_duration < 0)
+ || (ramp_duration > MAX_RAMP_DURATION)) {
+ pr_err(" %s Invalid arguments", __func__);
- voc_set_rx_device_mute(voc_get_session_id(VOICE_SESSION_NAME), mute);
+ ret = -EINVAL;
+ goto done;
+ }
- return 0;
+ pr_debug("%s: mute=%d session_id=%#x ramp_duration=%d\n", __func__,
+ mute, session_id, ramp_duration);
+
+ voc_set_rx_device_mute(session_id, mute, ramp_duration);
+
+done:
+ return ret;
}
-static int msm_volte_rx_device_mute_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] =
- voc_get_rx_device_mute(voc_get_session_id(VOLTE_SESSION_NAME));
- return 0;
-}
-static int msm_volte_rx_device_mute_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int mute = ucontrol->value.integer.value[0];
-
- pr_debug("%s: mute=%d\n", __func__, mute);
-
- voc_set_rx_device_mute(voc_get_session_id(VOLTE_SESSION_NAME), mute);
-
- return 0;
-}
-
-static int msm_voice2_rx_device_mute_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] =
- voc_get_rx_device_mute(voc_get_session_id(VOICE2_SESSION_NAME));
- return 0;
-}
-
-static int msm_voice2_rx_device_mute_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int mute = ucontrol->value.integer.value[0];
-
- pr_debug("%s: mute=%d\n", __func__, mute);
-
- voc_set_rx_device_mute(voc_get_session_id(VOICE2_SESSION_NAME), mute);
-
- return 0;
-}
static const char const *tty_mode[] = {"OFF", "HCO", "VCO", "FULL"};
static const struct soc_enum msm_tty_mode_enum[] = {
@@ -533,52 +456,28 @@
struct snd_ctl_elem_value *ucontrol)
{
int st_enable = ucontrol->value.integer.value[0];
+ uint32_t session_id = ucontrol->value.integer.value[1];
- pr_debug("%s: st enable=%d\n", __func__, st_enable);
+ pr_debug("%s: st enable=%d session_id=%#x\n", __func__, st_enable,
+ session_id);
- voc_set_pp_enable(voc_get_session_id(VOICE_SESSION_NAME),
- MODULE_ID_VOICE_MODULE_ST, st_enable);
- voc_set_pp_enable(voc_get_session_id(VOICE2_SESSION_NAME),
+ voc_set_pp_enable(session_id,
MODULE_ID_VOICE_MODULE_ST, st_enable);
return 0;
}
-static int msm_voice_slowtalk_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] =
- voc_get_pp_enable(voc_get_session_id(VOICE_SESSION_NAME),
- MODULE_ID_VOICE_MODULE_ST);
- return 0;
-}
-
static struct snd_kcontrol_new msm_voice_controls[] = {
- SOC_SINGLE_EXT("Voice Rx Device Mute", SND_SOC_NOPM, 0, 1, 0,
- msm_voice_rx_device_mute_get,
- msm_voice_rx_device_mute_put),
- SOC_SINGLE_EXT("Voice Tx Mute", SND_SOC_NOPM, 0, 1, 0,
- msm_voice_mute_get, msm_voice_mute_put),
- SOC_SINGLE_EXT("Voice Rx Volume", SND_SOC_NOPM, 0, 5, 0,
- msm_voice_volume_get, msm_voice_volume_put),
+ SOC_SINGLE_MULTI_EXT("Voice Rx Device Mute", SND_SOC_NOPM, 0, VSID_MAX,
+ 0, 3, NULL, msm_voice_rx_device_mute_put),
+ SOC_SINGLE_MULTI_EXT("Voice Tx Mute", SND_SOC_NOPM, 0, VSID_MAX,
+ 0, 3, NULL, msm_voice_mute_put),
+ SOC_SINGLE_MULTI_EXT("Voice Rx Gain", SND_SOC_NOPM, 0, VSID_MAX, 0, 3,
+ NULL, msm_voice_gain_put),
SOC_ENUM_EXT("TTY Mode", msm_tty_mode_enum[0], msm_voice_tty_mode_get,
msm_voice_tty_mode_put),
- SOC_SINGLE_EXT("Slowtalk Enable", SND_SOC_NOPM, 0, 1, 0,
- msm_voice_slowtalk_get, msm_voice_slowtalk_put),
- SOC_SINGLE_EXT("VoLTE Rx Device Mute", SND_SOC_NOPM, 0, 1, 0,
- msm_volte_rx_device_mute_get,
- msm_volte_rx_device_mute_put),
- SOC_SINGLE_EXT("VoLTE Tx Mute", SND_SOC_NOPM, 0, 1, 0,
- msm_volte_mute_get, msm_volte_mute_put),
- SOC_SINGLE_EXT("VoLTE Rx Volume", SND_SOC_NOPM, 0, 5, 0,
- msm_volte_volume_get, msm_volte_volume_put),
- SOC_SINGLE_EXT("Voice2 Rx Device Mute", SND_SOC_NOPM, 0, 1, 0,
- msm_voice2_rx_device_mute_get,
- msm_voice2_rx_device_mute_put),
- SOC_SINGLE_EXT("Voice2 Tx Mute", SND_SOC_NOPM, 0, 1, 0,
- msm_voice2_mute_get, msm_voice2_mute_put),
- SOC_SINGLE_EXT("Voice2 Rx Volume", SND_SOC_NOPM, 0, 5, 0,
- msm_voice2_volume_get, msm_voice2_volume_put),
+ SOC_SINGLE_MULTI_EXT("Slowtalk Enable", SND_SOC_NOPM, 0, VSID_MAX, 0, 2,
+ NULL, msm_voice_slowtalk_put),
};
static struct snd_pcm_ops msm_pcm_ops = {
@@ -617,12 +516,36 @@
static __devinit int msm_pcm_probe(struct platform_device *pdev)
{
+ int rc;
+
+ if (!is_voc_initialized()) {
+ pr_debug("%s: voice module not initialized yet, deferring probe()\n",
+ __func__);
+
+ rc = -EPROBE_DEFER;
+ goto done;
+ }
+
+ rc = voc_alloc_cal_shared_memory();
+ if (rc == -EPROBE_DEFER) {
+ pr_debug("%s: memory allocation for calibration deferred %d\n",
+ __func__, rc);
+
+ goto done;
+ } else if (rc < 0) {
+ pr_err("%s: memory allocation for calibration failed %d\n",
+ __func__, rc);
+ }
+
if (pdev->dev.of_node)
dev_set_name(&pdev->dev, "%s", "msm-pcm-voice");
pr_debug("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
- return snd_soc_register_platform(&pdev->dev,
- &msm_soc_platform);
+ rc = snd_soc_register_platform(&pdev->dev,
+ &msm_soc_platform);
+
+done:
+ return rc;
}
static int msm_pcm_remove(struct platform_device *pdev)
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h
index 5425c46..f199be6 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h
@@ -17,6 +17,7 @@
VOICE_SESSION_INDEX,
VOLTE_SESSION_INDEX,
VOICE2_SESSION_INDEX,
+ QCHAT_SESSION_INDEX,
VOICE_SESSION_INDEX_MAX,
};
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
index f17fe5b..4a829fd 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
@@ -173,41 +173,53 @@
static int msm_voip_mute_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+ struct snd_ctl_elem_value *ucontrol)
{
+ int ret = 0;
int mute = ucontrol->value.integer.value[0];
+ int ramp_duration = ucontrol->value.integer.value[1];
- pr_debug("%s: mute=%d\n", __func__, mute);
+ if ((mute < 0) || (mute > 1) || (ramp_duration < 0)) {
+ pr_err(" %s Invalid arguments", __func__);
- voc_set_tx_mute(voc_get_session_id(VOIP_SESSION_NAME), TX_PATH, mute);
+ ret = -EINVAL;
+ goto done;
+ }
- return 0;
+ pr_debug("%s: mute=%d ramp_duration=%d\n", __func__, mute,
+ ramp_duration);
+
+ voc_set_tx_mute(voc_get_session_id(VOIP_SESSION_NAME), TX_PATH, mute,
+ ramp_duration);
+
+done:
+ return ret;
}
-static int msm_voip_mute_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int msm_voip_gain_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
- ucontrol->value.integer.value[0] = 0;
- return 0;
-}
-
-static int msm_voip_volume_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
+ int ret = 0;
int volume = ucontrol->value.integer.value[0];
+ int ramp_duration = ucontrol->value.integer.value[1];
- pr_debug("%s: volume: %d\n", __func__, volume);
+ if ((volume < 0) || (ramp_duration < 0)) {
+ pr_err(" %s Invalid arguments", __func__);
- voc_set_rx_vol_index(voc_get_session_id(VOIP_SESSION_NAME),
- RX_PATH,
- volume);
- return 0;
-}
-static int msm_voip_volume_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] = 0;
- return 0;
+ ret = -EINVAL;
+ goto done;
+ }
+
+ pr_debug("%s: volume: %d ramp_duration: %d\n", __func__, volume,
+ ramp_duration);
+
+ voc_set_rx_vol_step(voc_get_session_id(VOIP_SESSION_NAME),
+ RX_PATH,
+ volume,
+ ramp_duration);
+
+done:
+ return ret;
}
static int msm_voip_dtx_mode_put(struct snd_kcontrol *kcontrol,
@@ -236,15 +248,17 @@
}
static struct snd_kcontrol_new msm_voip_controls[] = {
- SOC_SINGLE_EXT("Voip Tx Mute", SND_SOC_NOPM, 0, 1, 0,
- msm_voip_mute_get, msm_voip_mute_put),
- SOC_SINGLE_EXT("Voip Rx Volume", SND_SOC_NOPM, 0, 5, 0,
- msm_voip_volume_get, msm_voip_volume_put),
+ SOC_SINGLE_MULTI_EXT("Voip Tx Mute", SND_SOC_NOPM, 0,
+ MAX_RAMP_DURATION,
+ 0, 2, NULL, msm_voip_mute_put),
+ 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),
+ 0, 2, msm_voip_mode_rate_config_get,
+ msm_voip_mode_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),
+ msm_voip_dtx_mode_get, msm_voip_dtx_mode_put),
};
static int msm_pcm_voip_probe(struct snd_soc_platform *platform)
@@ -817,8 +831,15 @@
}
voc_register_mvs_cb(voip_process_ul_pkt,
voip_process_dl_pkt, prtd);
- voc_start_voice_call(voc_get_session_id(VOIP_SESSION_NAME));
+ ret = voc_start_voice_call(
+ voc_get_session_id(VOIP_SESSION_NAME));
+ if (ret < 0) {
+ pr_err("%s: voc_start_voice_call() failed err %d",
+ __func__, ret);
+
+ goto done;
+ }
prtd->state = VOIP_STARTED;
}
done:
@@ -1132,12 +1153,42 @@
static __devinit int msm_pcm_probe(struct platform_device *pdev)
{
+ int rc;
+
+ if (!is_voc_initialized()) {
+ pr_debug("%s: voice module not initialized yet, deferring probe()\n",
+ __func__);
+
+ rc = -EPROBE_DEFER;
+ goto done;
+ }
+
+ rc = voc_alloc_cal_shared_memory();
+ if (rc == -EPROBE_DEFER) {
+ pr_debug("%s: memory allocation for calibration deferred %d\n",
+ __func__, rc);
+
+ goto done;
+ } else if (rc < 0) {
+ pr_err("%s: memory allocation for calibration failed %d\n",
+ __func__, rc);
+ }
+
+ rc = voc_alloc_voip_shared_memory();
+ if (rc < 0) {
+ pr_err("%s: error allocating shared mem err %d\n",
+ __func__, rc);
+ }
+
if (pdev->dev.of_node)
dev_set_name(&pdev->dev, "%s", "msm-voip-dsp");
pr_debug("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
- return snd_soc_register_platform(&pdev->dev,
- &msm_soc_platform);
+ rc = snd_soc_register_platform(&pdev->dev,
+ &msm_soc_platform);
+
+done:
+ return rc;
}
static int msm_pcm_remove(struct platform_device *pdev)
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index a6ae357..df0fa6a 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -69,7 +69,7 @@
{0, 0, 0, 0, 0, 0, 0, 0}
};
-static int adm_dolby_get_parameters[ADM_GET_PARAMETER_LENGTH];
+static int adm_get_parameters[ADM_GET_PARAMETER_LENGTH];
int srs_trumedia_open(int port_id, int srs_tech_id, void *srs_params)
{
@@ -333,10 +333,10 @@
return rc;
}
-int adm_dolby_dap_get_params(int port_id, uint32_t module_id, uint32_t param_id,
- uint32_t params_length, char *params)
+int adm_get_params(int port_id, uint32_t module_id, uint32_t param_id,
+ uint32_t params_length, char *params)
{
- struct adm_cmd_get_pp_params_v5 *adm_params = NULL;
+ struct adm_cmd_get_pp_params_v5 *adm_params = NULL;
int sz, rc = 0, i = 0, index = afe_get_port_index(port_id);
int *params_data = (int *)params;
@@ -345,17 +345,17 @@
__func__, index, port_id);
return -EINVAL;
}
- sz = sizeof(struct adm_cmd_set_pp_params_v5) + params_length;
+ sz = sizeof(struct adm_cmd_get_pp_params_v5) + params_length;
adm_params = kzalloc(sz, GFP_KERNEL);
if (!adm_params) {
pr_err("%s, adm params memory alloc failed", __func__);
return -ENOMEM;
}
- memcpy(((u8 *)adm_params + sizeof(struct adm_cmd_set_pp_params_v5)),
- params, params_length);
+ memcpy(((u8 *)adm_params + sizeof(struct adm_cmd_get_pp_params_v5)),
+ params, params_length);
adm_params->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
- APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
adm_params->hdr.pkt_size = sz;
adm_params->hdr.src_svc = APR_SVC_ADM;
adm_params->hdr.src_domain = APR_DOMAIN_APPS;
@@ -376,31 +376,33 @@
atomic_set(&this_adm.copp_stat[index], 0);
rc = apr_send_pkt(this_adm.apr, (uint32_t *)adm_params);
if (rc < 0) {
- pr_err("%s: Failed to Get DOLBY Params on port %d\n", __func__,
+ pr_err("%s: Failed to Get Params on port %d\n", __func__,
port_id);
rc = -EINVAL;
- goto dolby_dap_get_param_return;
+ goto adm_get_param_return;
}
/* Wait for the callback with copp id */
rc = wait_event_timeout(this_adm.wait[index],
- atomic_read(&this_adm.copp_stat[index]),
- msecs_to_jiffies(TIMEOUT_MS));
+ atomic_read(&this_adm.copp_stat[index]),
+ msecs_to_jiffies(TIMEOUT_MS));
if (!rc) {
- pr_err("%s: DOLBY get params timed out port = %d\n", __func__,
+ pr_err("%s: get params timed out port = %d\n", __func__,
port_id);
rc = -EINVAL;
- goto dolby_dap_get_param_return;
+ goto adm_get_param_return;
}
if (params_data) {
- for (i = 0; i < adm_dolby_get_parameters[0]; i++)
- params_data[i] = adm_dolby_get_parameters[1+i];
+ for (i = 0; i < adm_get_parameters[0]; i++)
+ params_data[i] = adm_get_parameters[1+i];
}
rc = 0;
-dolby_dap_get_param_return:
+adm_get_param_return:
kfree(adm_params);
+
return rc;
}
+
static void adm_callback_debug_print(struct apr_client_data *data)
{
uint32_t *payload;
@@ -574,11 +576,11 @@
__func__, payload[0]);
rtac_make_adm_callback(payload,
data->payload_size);
- adm_dolby_get_parameters[0] = payload[3];
+ adm_get_parameters[0] = payload[3];
pr_debug("GET_PP PARAM:received parameter length: %x\n",
- adm_dolby_get_parameters[0]);
+ adm_get_parameters[0]);
for (i = 0; i < payload[3]; i++)
- adm_dolby_get_parameters[1+i] = payload[4+i];
+ adm_get_parameters[1+i] = payload[4+i];
atomic_set(&this_adm.copp_stat[index], 1);
wake_up(&this_adm.wait[index]);
break;
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 9882ec7..1810770 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -139,13 +139,13 @@
pr_debug("%s:opcode = 0x%x cmd = 0x%x status = 0x%x token=%d\n",
__func__, data->opcode,
payload[0], payload[1], data->token);
- /* payload[1] contains the error status for response */
- if (payload[1] != 0) {
- atomic_set(&this_afe.status, -1);
- pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
- __func__, payload[0], payload[1]);
- }
if (data->opcode == APR_BASIC_RSP_RESULT) {
+ /* payload[1] contains the error status for response */
+ if (payload[1] != 0) {
+ atomic_set(&this_afe.status, -1);
+ pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
+ __func__, payload[0], payload[1]);
+ }
switch (payload[0]) {
case AFE_PORT_CMD_DEVICE_STOP:
case AFE_PORT_CMD_DEVICE_START:
@@ -175,8 +175,9 @@
}
} else if (data->opcode ==
AFE_SERVICE_CMDRSP_SHARED_MEM_MAP_REGIONS) {
- pr_debug("%s: mmap_handle: 0x%x\n",
- __func__, payload[0]);
+ pr_debug("%s: mmap_handle: 0x%x, cal index %d\n",
+ __func__, payload[0],
+ atomic_read(&this_afe.mem_map_cal_index));
if (atomic_read(&this_afe.mem_map_cal_index) != -1)
atomic_set(&this_afe.mem_map_cal_handles[
atomic_read(
@@ -234,6 +235,7 @@
case INT_BT_A2DP_RX:
case INT_FM_RX:
case VOICE_PLAYBACK_TX:
+ case VOICE2_PLAYBACK_TX:
case RT_PROXY_PORT_001_RX:
case AUDIO_PORT_ID_I2S_RX:
case AFE_PORT_ID_PRIMARY_MI2S_RX:
@@ -303,6 +305,7 @@
ret_size = SIZEOF_CFG_CMD(afe_param_id_slimbus_cfg);
break;
case VOICE_PLAYBACK_TX:
+ case VOICE2_PLAYBACK_TX:
case VOICE_RECORD_RX:
case VOICE_RECORD_TX:
ret_size = SIZEOF_CFG_CMD(afe_param_id_pseudo_port_cfg);
@@ -377,8 +380,10 @@
int size = 4096;
struct acdb_cal_block cal_block;
struct afe_audioif_config_command_no_payload afe_cal;
- pr_debug("%s: path %d\n", __func__, path);
+ atomic_t *hptr;
+ u32 handle;
+ pr_debug("%s: path %d\n", __func__, path);
if (path == AANC_TX_CAL) {
get_aanc_cal(&cal_block);
} else {
@@ -394,11 +399,17 @@
(cal_block.cal_size > this_afe.afe_cal_addr[path].cal_size)) {
atomic_set(&this_afe.mem_map_cal_index, path);
if (this_afe.afe_cal_addr[path].cal_paddr != 0) {
- result = afe_cmd_memory_unmap(
- this_afe.afe_cal_addr[path].cal_paddr);
+ hptr = &this_afe.mem_map_cal_handles[path];
+ handle = atomic_xchg(hptr, 0);
+ if (!handle) {
+ pr_err("%s: invalid NULL handle\n", __func__);
+ result = -EINVAL;
+ goto done;
+ }
+ result = afe_cmd_memory_unmap(handle);
if (result) {
- pr_err("%s: AFE memory unmap failed\n",
- __func__);
+ WARN(1, "%s: AFE memory unmap failed %d, handle 0x%x\n",
+ __func__, result, handle);
atomic_set(&this_afe.mem_map_cal_index, -1);
goto done;
}
@@ -1263,6 +1274,7 @@
cfg_type = AFE_PARAM_ID_HDMI_CONFIG;
break;
case VOICE_PLAYBACK_TX:
+ case VOICE2_PLAYBACK_TX:
case VOICE_RECORD_RX:
case VOICE_RECORD_TX:
cfg_type = AFE_PARAM_ID_PSEUDO_PORT_CONFIG;
@@ -1356,6 +1368,7 @@
case VOICE_RECORD_RX: return IDX_VOICE_RECORD_RX;
case VOICE_RECORD_TX: return IDX_VOICE_RECORD_TX;
case VOICE_PLAYBACK_TX: return IDX_VOICE_PLAYBACK_TX;
+ case VOICE2_PLAYBACK_TX: return IDX_VOICE2_PLAYBACK_TX;
case SLIMBUS_0_RX: return IDX_SLIMBUS_0_RX;
case SLIMBUS_0_TX: return IDX_SLIMBUS_0_TX;
case SLIMBUS_1_RX: return IDX_SLIMBUS_1_RX;
@@ -2114,7 +2127,7 @@
struct afe_service_cmd_shared_mem_unmap_regions mregion;
int index = 0;
- pr_debug("%s:\n", __func__);
+ pr_debug("%s: handle 0x%x\n", __func__, mem_map_handle);
if (this_afe.apr == NULL) {
this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
@@ -2157,7 +2170,7 @@
int ret = 0;
struct afe_service_cmd_shared_mem_unmap_regions mregion;
- pr_debug("%s:\n", __func__);
+ pr_debug("%s: handle 0x%x\n", __func__, mem_map_handle);
if (this_afe.apr == NULL) {
this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
@@ -2663,6 +2676,7 @@
case VOICE_RECORD_RX:
case VOICE_RECORD_TX:
case VOICE_PLAYBACK_TX:
+ case VOICE2_PLAYBACK_TX:
case SLIMBUS_0_RX:
case SLIMBUS_0_TX:
case SLIMBUS_1_RX:
@@ -3138,12 +3152,15 @@
static void __exit afe_exit(void)
{
int i;
+ atomic_t *hptr;
+ u32 handle;
config_debug_fs_exit();
- for (i = 0; i < MAX_AUDPROC_TYPES; i++) {
- if (this_afe.afe_cal_addr[i].cal_paddr != 0)
- afe_cmd_memory_unmap_nowait(
- this_afe.afe_cal_addr[i].cal_paddr);
+ for (i = 0; i < ARRAY_SIZE(this_afe.mem_map_cal_handles); i++) {
+ hptr = &this_afe.mem_map_cal_handles[i];
+ handle = atomic_xchg(hptr, 0);
+ if (handle != 0)
+ afe_cmd_memory_unmap_nowait(handle);
}
}
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index c65222b..6a34470 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -542,6 +542,7 @@
}
apr_deregister(ac->apr);
+ ac->apr = NULL;
ac->mmap_apr = NULL;
q6asm_session_free(ac);
q6asm_mmap_apr_dereg();
@@ -550,6 +551,7 @@
/*done:*/
kfree(ac);
+ ac = NULL;
return;
}
@@ -1327,6 +1329,11 @@
{
pr_debug("%s:pkt_size=%d cmd_flg=%d session=%d\n", __func__, pkt_size,
cmd_flg, ac->session);
+ 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)),\
@@ -1354,6 +1361,10 @@
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;
@@ -1383,15 +1394,12 @@
hdr->pkt_size = pkt_size;
return;
}
-int q6asm_open_read(struct audio_client *ac,
- uint32_t format)
+static int __q6asm_open_read(struct audio_client *ac,
+ uint32_t format, uint16_t bits_per_sample)
{
int rc = 0x00;
struct asm_stream_cmd_open_read_v3 open;
- uint16_t bits_per_sample = 16;
-
-
config_debug_fs_reset_index();
if ((ac == NULL) || (ac->apr == NULL)) {
@@ -1466,6 +1474,18 @@
return -EINVAL;
}
+int q6asm_open_read(struct audio_client *ac,
+ uint32_t format)
+{
+ return __q6asm_open_read(ac, format, 16);
+}
+
+int q6asm_open_read_v2(struct audio_client *ac, uint32_t format,
+ uint16_t bits_per_sample)
+{
+ return __q6asm_open_read(ac, format, bits_per_sample);
+}
+
static int __q6asm_open_write(struct audio_client *ac, uint32_t format,
uint16_t bits_per_sample)
{
@@ -1820,8 +1840,8 @@
return rc;
}
-int q6asm_enc_cfg_blk_pcm(struct audio_client *ac,
- uint32_t rate, uint32_t channels)
+static int __q6asm_enc_cfg_blk_pcm(struct audio_client *ac,
+ uint32_t rate, uint32_t channels, uint16_t bits_per_sample)
{
struct asm_multi_channel_pcm_enc_cfg_v2 enc_cfg;
u8 *channel_mapping;
@@ -1842,7 +1862,7 @@
sizeof(struct asm_enc_cfg_blk_param_v2);
enc_cfg.num_channels = channels;
- enc_cfg.bits_per_sample = 16;
+ enc_cfg.bits_per_sample = bits_per_sample;
enc_cfg.sample_rate = rate;
enc_cfg.is_signed = 1;
channel_mapping = enc_cfg.channel_mapping;
@@ -1869,6 +1889,18 @@
return -EINVAL;
}
+int q6asm_enc_cfg_blk_pcm(struct audio_client *ac,
+ uint32_t rate, uint32_t channels)
+{
+ return __q6asm_enc_cfg_blk_pcm(ac, rate, channels, 16);
+}
+
+int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac,
+ uint32_t rate, uint32_t channels, uint16_t bits_per_sample)
+{
+ return __q6asm_enc_cfg_blk_pcm(ac, rate, channels, bits_per_sample);
+}
+
int q6asm_enc_cfg_blk_pcm_native(struct audio_client *ac,
uint32_t rate, uint32_t channels)
{
@@ -2887,6 +2919,12 @@
int sz = 0;
int rc = 0;
+ if (!ac || ac->apr == NULL) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
sz = sizeof(struct asm_volume_ctrl_lr_chan_gain);
q6asm_add_hdr_async(ac, &lrgain.hdr, sz, TRUE);
lrgain.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
@@ -2929,6 +2967,12 @@
int sz = 0;
int rc = 0;
+ if (!ac || ac->apr == NULL) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
sz = sizeof(struct asm_volume_ctrl_mute_config);
q6asm_add_hdr_async(ac, &mute.hdr, sz, TRUE);
mute.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
@@ -2970,6 +3014,12 @@
int sz = 0;
int rc = 0;
+ if (!ac || ac->apr == NULL) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
sz = sizeof(struct asm_volume_ctrl_master_gain);
q6asm_add_hdr_async(ac, &vol.hdr, sz, TRUE);
vol.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
@@ -3013,6 +3063,12 @@
int sz = 0;
int rc = 0;
+ if (!ac || ac->apr == NULL) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
sz = sizeof(struct asm_soft_pause_params);
q6asm_add_hdr_async(ac, &softpause.hdr, sz, TRUE);
softpause.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
@@ -3060,6 +3116,12 @@
int sz = 0;
int rc = 0;
+ if (!ac || ac->apr == NULL) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
sz = sizeof(struct asm_soft_step_volume_params);
q6asm_add_hdr_async(ac, &softvol.hdr, sz, TRUE);
softvol.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
@@ -3106,6 +3168,12 @@
int sz = 0;
int rc = 0;
+ if (!ac || ac->apr == NULL) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
if (eq_p == NULL) {
pr_err("%s[%d]: Invalid Eq param\n", __func__, ac->session);
rc = -EINVAL;
diff --git a/sound/soc/msm/qdsp6v2/q6audio-v2.c b/sound/soc/msm/qdsp6v2/q6audio-v2.c
index bc7ad4d..57ea2a7 100644
--- a/sound/soc/msm/qdsp6v2/q6audio-v2.c
+++ b/sound/soc/msm/qdsp6v2/q6audio-v2.c
@@ -43,6 +43,7 @@
case VOICE_RECORD_RX: return IDX_VOICE_RECORD_RX;
case VOICE_RECORD_TX: return IDX_VOICE_RECORD_TX;
case VOICE_PLAYBACK_TX: return IDX_VOICE_PLAYBACK_TX;
+ case VOICE2_PLAYBACK_TX: return IDX_VOICE2_PLAYBACK_TX;
case SLIMBUS_0_RX: return IDX_SLIMBUS_0_RX;
case SLIMBUS_0_TX: return IDX_SLIMBUS_0_TX;
case SLIMBUS_1_RX: return IDX_SLIMBUS_1_RX;
@@ -103,6 +104,7 @@
case VOICE_RECORD_RX: return AFE_PORT_ID_VOICE_RECORD_RX;
case VOICE_RECORD_TX: return AFE_PORT_ID_VOICE_RECORD_TX;
case VOICE_PLAYBACK_TX: return AFE_PORT_ID_VOICE_PLAYBACK_TX;
+ case VOICE2_PLAYBACK_TX: return AFE_PORT_ID_VOICE2_PLAYBACK_TX;
case SLIMBUS_0_RX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_RX;
case SLIMBUS_0_TX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_TX;
case SLIMBUS_1_RX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_1_RX;
@@ -213,6 +215,7 @@
case VOICE_RECORD_RX:
case VOICE_RECORD_TX:
case VOICE_PLAYBACK_TX:
+ case VOICE2_PLAYBACK_TX:
case SLIMBUS_0_RX:
case SLIMBUS_0_TX:
case SLIMBUS_1_RX:
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index 87bee75..7243f19 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -48,13 +48,14 @@
};
static struct common_data common;
+static bool module_initialized;
static int voice_send_enable_vocproc_cmd(struct voice_data *v);
static int voice_send_netid_timing_cmd(struct voice_data *v);
static int voice_send_attach_vocproc_cmd(struct voice_data *v);
static int voice_send_set_device_cmd(struct voice_data *v);
static int voice_send_disable_vocproc_cmd(struct voice_data *v);
-static int voice_send_vol_index_cmd(struct voice_data *v);
+static int voice_send_vol_step_cmd(struct voice_data *v);
static int voice_send_mvm_unmap_memory_physical_cmd(struct voice_data *v,
uint32_t mem_handle);
static int voice_send_mvm_cal_network_cmd(struct voice_data *v);
@@ -84,9 +85,50 @@
static int voice_send_set_pp_enable_cmd(struct voice_data *v,
uint32_t module_id, int enable);
+static int is_cal_memory_allocated(void);
+static int is_voip_memory_allocated(void);
+static int voice_alloc_cal_mem_map_table(void);
+static int voice_alloc_oob_shared_mem(void);
+static int voice_free_oob_shared_mem(void);
+static int voice_alloc_oob_mem_table(void);
+static int voice_alloc_and_map_cal_mem(struct voice_data *v);
+static int voice_alloc_and_map_oob_mem(struct voice_data *v);
static struct voice_data *voice_get_session_by_idx(int idx);
-static int voice_get_idx_for_session(u32 session_id);
+
+static void voice_itr_init(struct voice_session_itr *itr,
+ u32 session_id)
+{
+ if (itr == NULL)
+ return;
+ itr->session_idx = voice_get_idx_for_session(session_id);
+ if (session_id == ALL_SESSION_VSID)
+ itr->cur_idx = 0;
+ else
+ itr->cur_idx = itr->session_idx;
+
+}
+
+static bool voice_itr_get_next_session(struct voice_session_itr *itr,
+ struct voice_data **voice)
+{
+ bool ret = false;
+
+ if (itr == NULL)
+ return false;
+ pr_debug("%s : cur idx = %d session idx = %d",
+ __func__, itr->cur_idx, itr->session_idx);
+
+ if (itr->cur_idx <= itr->session_idx) {
+ ret = true;
+ *voice = voice_get_session_by_idx(itr->cur_idx);
+ itr->cur_idx++;
+ } else {
+ *voice = NULL;
+ }
+
+ return ret;
+}
static u16 voice_get_mvm_handle(struct voice_data *v)
{
@@ -166,6 +208,9 @@
} else if (session_id ==
common.voice[VOC_PATH_VOLTE_PASSIVE].session_id) {
session_name = VOLTE_SESSION_NAME;
+ } else if (session_id ==
+ common.voice[VOC_PATH_QCHAT_PASSIVE].session_id) {
+ session_name = QCHAT_SESSION_NAME;
} else if (session_id == common.voice[VOC_PATH_FULL].session_id) {
session_name = VOIP_SESSION_NAME;
}
@@ -185,6 +230,9 @@
else if (!strncmp(name, "VoLTE session", 13))
session_id =
common.voice[VOC_PATH_VOLTE_PASSIVE].session_id;
+ else if (!strncmp(name, "QCHAT session", 13))
+ session_id =
+ common.voice[VOC_PATH_QCHAT_PASSIVE].session_id;
else
session_id = common.voice[VOC_PATH_FULL].session_id;
@@ -216,6 +264,10 @@
v = &common.voice[VOC_PATH_FULL];
break;
+ case QCHAT_SESSION_VSID:
+ v = &common.voice[VOC_PATH_QCHAT_PASSIVE];
+ break;
+
case ALL_SESSION_VSID:
break;
@@ -231,7 +283,7 @@
return v;
}
-static int voice_get_idx_for_session(u32 session_id)
+int voice_get_idx_for_session(u32 session_id)
{
int idx = 0;
@@ -252,6 +304,10 @@
idx = VOC_PATH_FULL;
break;
+ case QCHAT_SESSION_VSID:
+ idx = VOC_PATH_QCHAT_PASSIVE;
+ break;
+
case ALL_SESSION_VSID:
idx = MAX_VOC_SESSIONS - 1;
break;
@@ -271,11 +327,6 @@
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);
@@ -291,6 +342,21 @@
return (session_id == common.voice[VOC_PATH_VOICE2_PASSIVE].session_id);
}
+static bool is_qchat_session(u32 session_id)
+{
+ return (session_id == common.voice[VOC_PATH_QCHAT_PASSIVE].session_id);
+}
+
+static bool is_voc_state_active(int voc_state)
+{
+ if ((voc_state == VOC_RUN) ||
+ (voc_state == VOC_CHANGE) ||
+ (voc_state == VOC_STANDBY))
+ return true;
+
+ return false;
+}
+
static bool is_other_session_active(u32 session_id)
{
int i;
@@ -301,9 +367,7 @@
if (common.voice[i].session_id == session_id)
continue;
- if ((common.voice[i].voc_state == VOC_RUN) ||
- (common.voice[i].voc_state == VOC_CHANGE) ||
- (common.voice[i].voc_state == VOC_STANDBY)) {
+ if (is_voc_state_active(common.voice[i].voc_state)) {
ret = true;
break;
}
@@ -313,12 +377,19 @@
return ret;
}
+static bool is_voice_app_id(u32 session_id)
+{
+ return (((session_id & APP_ID_MASK) >> APP_ID_SHIFT) ==
+ VSID_APP_CS_VOICE);
+}
+
static void init_session_id(void)
{
common.voice[VOC_PATH_PASSIVE].session_id = VOICE_SESSION_VSID;
common.voice[VOC_PATH_VOLTE_PASSIVE].session_id = VOLTE_SESSION_VSID;
common.voice[VOC_PATH_VOICE2_PASSIVE].session_id = VOICE2_SESSION_VSID;
common.voice[VOC_PATH_FULL].session_id = VOIP_SESSION_VSID;
+ common.voice[VOC_PATH_QCHAT_PASSIVE].session_id = QCHAT_SESSION_VSID;
}
static int voice_apr_register(void)
@@ -443,10 +514,8 @@
pr_err("%s: apr_mvm is NULL.\n", __func__);
return -EINVAL;
}
- pr_debug("%s: VoLTE command to MVM\n", __func__);
- if (is_volte_session(v->session_id) ||
- is_voice_session(v->session_id) ||
- is_voice2_session(v->session_id)) {
+ pr_debug("%s: Send Dual Control command to MVM\n", __func__);
+ if (!is_voip_session(v->session_id)) {
mvm_handle = voice_get_mvm_handle(v);
mvm_voice_ctl_cmd.hdr.hdr_field = APR_HDR_FIELD(
APR_MSG_TYPE_SEQ_CMD,
@@ -520,9 +589,7 @@
/* send cmd to create mvm session and wait for response */
if (!mvm_handle) {
- if (is_voice_session(v->session_id) ||
- is_volte_session(v->session_id) ||
- is_voice2_session(v->session_id)) {
+ if (!is_voip_session(v->session_id)) {
mvm_session_cmd.hdr.hdr_field = APR_HDR_FIELD(
APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE),
@@ -547,6 +614,10 @@
strlcpy(mvm_session_cmd.mvm_session.name,
VOICE2_SESSION_VSID_STR,
sizeof(mvm_session_cmd.mvm_session.name));
+ } else if (is_qchat_session(v->session_id)) {
+ strlcpy(mvm_session_cmd.mvm_session.name,
+ QCHAT_SESSION_VSID_STR,
+ sizeof(mvm_session_cmd.mvm_session.name));
} else {
strlcpy(mvm_session_cmd.mvm_session.name,
"default modem voice",
@@ -609,9 +680,7 @@
}
/* send cmd to create cvs session */
if (!cvs_handle) {
- if (is_voice_session(v->session_id) ||
- is_volte_session(v->session_id) ||
- is_voice2_session(v->session_id)) {
+ if (!is_voip_session(v->session_id)) {
pr_debug("%s: creating CVS passive session\n",
__func__);
@@ -637,6 +706,10 @@
strlcpy(cvs_session_cmd.cvs_session.name,
VOICE2_SESSION_VSID_STR,
sizeof(cvs_session_cmd.cvs_session.name));
+ } else if (is_qchat_session(v->session_id)) {
+ strlcpy(cvs_session_cmd.cvs_session.name,
+ QCHAT_SESSION_VSID_STR,
+ sizeof(cvs_session_cmd.cvs_session.name));
} else {
strlcpy(cvs_session_cmd.cvs_session.name,
"default modem voice",
@@ -825,7 +898,9 @@
}
}
- if (is_voip_session(v->session_id) || v->voc_state == VOC_ERROR) {
+ if (is_voip_session(v->session_id) ||
+ is_qchat_session(v->session_id) ||
+ v->voc_state == VOC_ERROR) {
/* Destroy CVS. */
pr_debug("%s: CVS destroy session\n", __func__);
@@ -1204,9 +1279,8 @@
for (i = 0; i < MAX_VOC_SESSIONS; i++) {
v = &common.voice[i];
if ((v->dtmf_rx_detect_en) &&
- ((v->voc_state == VOC_RUN) ||
- (v->voc_state == VOC_CHANGE) ||
- (v->voc_state == VOC_STANDBY))) {
+ is_voc_state_active(v->voc_state)) {
+
pr_debug("disable dtmf det on ses_id=%d\n",
v->session_id);
voice_send_dtmf_rx_detection_cmd(v, 0);
@@ -1227,9 +1301,7 @@
mutex_lock(&v->lock);
v->dtmf_rx_detect_en = enable;
- if ((v->voc_state == VOC_RUN) ||
- (v->voc_state == VOC_CHANGE) ||
- (v->voc_state == VOC_STANDBY))
+ if (is_voc_state_active(v->voc_state))
ret = voice_send_dtmf_rx_detection_cmd(v,
v->dtmf_rx_detect_en);
@@ -1238,6 +1310,89 @@
return ret;
}
+int voc_alloc_cal_shared_memory(void)
+{
+ int rc = 0;
+
+ mutex_lock(&common.common_lock);
+ if (is_cal_memory_allocated()) {
+ pr_debug("%s: Calibration shared buffer already allocated",
+ __func__);
+ } else {
+ /* Allocate memory for calibration memory map table. */
+ rc = voice_alloc_cal_mem_map_table();
+ if (rc < 0) {
+ pr_err("%s: Failed to allocate cal memory, err=%d",
+ __func__, rc);
+ }
+ }
+ mutex_unlock(&common.common_lock);
+
+ return rc;
+}
+
+int voc_alloc_voip_shared_memory(void)
+{
+ int rc = 0;
+
+ /* Allocate shared memory for OOB Voip */
+ rc = voice_alloc_oob_shared_mem();
+ if (rc < 0) {
+ pr_err("%s: Failed to alloc shared memory for OOB rc:%d\n",
+ __func__, rc);
+ } else {
+ /* Allocate mem map table for OOB */
+ rc = voice_alloc_oob_mem_table();
+ if (rc < 0) {
+ pr_err("%s: Failed to alloc mem map talbe rc:%d\n",
+ __func__, rc);
+
+ voice_free_oob_shared_mem();
+ }
+ }
+
+ return rc;
+}
+
+static int is_cal_memory_allocated(void)
+{
+ bool ret;
+
+ if (common.cal_mem_map_table.client != NULL &&
+ common.cal_mem_map_table.handle != NULL)
+ ret = true;
+ else
+ ret = false;
+
+ return ret;
+}
+
+static int is_voip_memory_allocated(void)
+{
+ bool ret;
+ struct voice_data *v = voice_get_session(
+ common.voice[VOC_PATH_FULL].session_id);
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL, session_id:%d\n", __func__,
+ common.voice[VOC_PATH_FULL].session_id);
+
+ ret = false;
+ goto done;
+ }
+
+ mutex_lock(&common.common_lock);
+ if (v->shmem_info.sh_buf.client != NULL &&
+ v->shmem_info.sh_buf.handle != NULL)
+ ret = true;
+ else
+ ret = false;
+ mutex_unlock(&common.common_lock);
+
+done:
+ return ret;
+}
+
static int voice_config_cvs_vocoder(struct voice_data *v)
{
int ret = 0;
@@ -1691,26 +1846,28 @@
if (v == NULL) {
pr_err("%s: v is NULL\n", __func__);
- goto fail;
+ ret = -EINVAL;
+ goto done;
}
if (!common.apr_q6_cvs) {
pr_err("%s: apr_cvs is NULL\n", __func__);
- goto fail;
+ ret = -EINVAL;
+ goto done;
}
if (!common.cal_mem_handle) {
- pr_err("%s: Cal mem handle is NULL\n", __func__);
+ pr_debug("%s: Cal mem handle is NULL\n", __func__);
- goto fail;
+ goto done;
}
get_vocstrm_cal(&cal_block);
if (cal_block.cal_size == 0) {
pr_err("%s: CVS cal size is 0\n", __func__);
- goto fail;
+ goto done;
}
cvs_reg_cal_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
@@ -1739,7 +1896,7 @@
if (ret < 0) {
pr_err("%s: Error %d registering CVS cal\n", __func__, ret);
- goto fail;
+ goto done;
}
ret = wait_event_timeout(v->cvs_wait,
(v->cvs_state == CMD_STATUS_SUCCESS),
@@ -1747,13 +1904,11 @@
if (!ret) {
pr_err("%s: Command timeout\n", __func__);
- goto fail;
+ goto done;
}
- return 0;
-
-fail:
- return -EINVAL;
+done:
+ return ret;
}
static int voice_send_cvs_deregister_cal_cmd(struct voice_data *v)
@@ -1766,18 +1921,26 @@
if (v == NULL) {
pr_err("%s: v is NULL\n", __func__);
- goto fail;
+ ret = -EINVAL;
+ goto done;
}
if (!common.apr_q6_cvs) {
pr_err("%s: apr_cvs is NULL\n", __func__);
- goto fail;
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (!common.cal_mem_handle) {
+ pr_debug("%s: Cal mem handle is NULL\n", __func__);
+
+ goto done;
}
get_vocstrm_cal(&cal_block);
if (cal_block.cal_size == 0)
- return 0;
+ goto done;
cvs_dereg_cal_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
@@ -1795,7 +1958,7 @@
if (ret < 0) {
pr_err("%s: Error %d de-registering CVS cal\n", __func__, ret);
- goto fail;
+ goto done;
}
ret = wait_event_timeout(v->cvs_wait,
(v->cvs_state == CMD_STATUS_SUCCESS),
@@ -1803,13 +1966,11 @@
if (!ret) {
pr_err("%s: Command timeout\n", __func__);
- goto fail;
+ goto done;
}
- return 0;
-
-fail:
- return -EINVAL;
+done:
+ return ret;
}
@@ -1823,26 +1984,28 @@
if (v == NULL) {
pr_err("%s: v is NULL\n", __func__);
- goto fail;
+ ret = -EINVAL;
+ goto done;
}
if (!common.apr_q6_cvp) {
pr_err("%s: apr_cvp is NULL\n", __func__);
- goto fail;
+ ret = -EINVAL;
+ goto done;
}
if (!common.cal_mem_handle) {
- pr_err("%s: Cal mem handle is NULL\n", __func__);
+ pr_debug("%s: Cal mem handle is NULL\n", __func__);
- goto fail;
+ goto done;
}
get_vocproc_dev_cfg_cal(&cal_block);
if (cal_block.cal_size == 0) {
pr_err("%s: CVP cal size is 0\n", __func__);
- goto fail;
+ goto done;
}
cvp_reg_dev_cfg_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
@@ -1867,7 +2030,7 @@
pr_err("%s: Error %d registering CVP dev cfg cal\n",
__func__, ret);
- goto fail;
+ goto done;
}
ret = wait_event_timeout(v->cvp_wait,
(v->cvp_state == CMD_STATUS_SUCCESS),
@@ -1875,13 +2038,11 @@
if (!ret) {
pr_err("%s: Command timeout\n", __func__);
- goto fail;
+ goto done;
}
- return 0;
-
-fail:
- return -EINVAL;
+done:
+ return ret;
}
static int voice_send_cvp_deregister_dev_cfg_cmd(struct voice_data *v)
@@ -1894,18 +2055,26 @@
if (v == NULL) {
pr_err("%s: v is NULL\n", __func__);
- goto fail;
+ ret = -EINVAL;
+ goto done;
}
if (!common.apr_q6_cvp) {
- pr_err("%s: apr_cvp is NULL.\n", __func__);
+ pr_err("%s: apr_cvp is NULL\n", __func__);
- goto fail;
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (!common.cal_mem_handle) {
+ pr_debug("%s: Cal mem handle is NULL\n", __func__);
+
+ goto done;
}
get_vocproc_dev_cfg_cal(&cal_block);
if (cal_block.cal_size == 0)
- return 0;
+ goto done;
cvp_dereg_dev_cfg_cmd.hdr.hdr_field =
APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
@@ -1926,7 +2095,7 @@
pr_err("%s: Error %d de-registering CVP dev cfg cal\n",
__func__, ret);
- goto fail;
+ goto done;
}
ret = wait_event_timeout(v->cvp_wait,
(v->cvp_state == CMD_STATUS_SUCCESS),
@@ -1934,13 +2103,11 @@
if (!ret) {
pr_err("%s: Command timeout\n", __func__);
- goto fail;
+ goto done;
}
- return 0;
-
-fail:
- return -EINVAL;
+done:
+ return ret;
}
static int voice_send_cvp_register_cal_cmd(struct voice_data *v)
@@ -1953,26 +2120,28 @@
if (v == NULL) {
pr_err("%s: v is NULL\n", __func__);
- goto fail;
+ ret = -EINVAL;
+ goto done;
}
if (!common.apr_q6_cvp) {
pr_err("%s: apr_cvp is NULL\n", __func__);
- goto fail;
+ ret = -EINVAL;
+ goto done;
}
if (!common.cal_mem_handle) {
- pr_err("%s: Cal mem handle is NULL\n", __func__);
+ pr_debug("%s: Cal mem handle is NULL\n", __func__);
- goto fail;
+ goto done;
}
get_vocproc_cal(&cal_block);
if (cal_block.cal_size == 0) {
pr_err("%s: CVP cal size is 0\n", __func__);
- goto fail;
+ goto done;
}
cvp_reg_cal_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
@@ -2001,7 +2170,7 @@
if (ret < 0) {
pr_err("%s: Error %d registering CVP cal\n", __func__, ret);
- goto fail;
+ goto done;
}
ret = wait_event_timeout(v->cvp_wait,
(v->cvp_state == CMD_STATUS_SUCCESS),
@@ -2009,13 +2178,11 @@
if (!ret) {
pr_err("%s: Command timeout\n", __func__);
- goto fail;
+ goto done;
}
- return 0;
-
-fail:
- return -EINVAL;
+done:
+ return ret;
}
static int voice_send_cvp_deregister_cal_cmd(struct voice_data *v)
@@ -2028,18 +2195,26 @@
if (v == NULL) {
pr_err("%s: v is NULL\n", __func__);
- goto fail;
+ ret = -EINVAL;
+ goto done;
}
if (!common.apr_q6_cvp) {
pr_err("%s: apr_cvp is NULL.\n", __func__);
- goto fail;
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (!common.cal_mem_handle) {
+ pr_debug("%s: Cal mem handle is NULL\n", __func__);
+
+ goto done;
}
get_vocproc_cal(&cal_block);
if (cal_block.cal_size == 0)
- return 0;
+ goto done;
cvp_dereg_cal_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
@@ -2057,7 +2232,7 @@
if (ret < 0) {
pr_err("%s: Error %d de-registering CVP cal\n", __func__, ret);
- goto fail;
+ goto done;
}
ret = wait_event_timeout(v->cvp_wait,
(v->cvp_state == CMD_STATUS_SUCCESS),
@@ -2065,12 +2240,10 @@
if (!ret) {
pr_err("%s: Command timeout\n", __func__);
- goto fail;
+ goto done;
}
- return 0;
-
-fail:
+done:
return -EINVAL;
}
@@ -2084,26 +2257,28 @@
if (v == NULL) {
pr_err("%s: v is NULL\n", __func__);
- goto fail;
+ ret = -EINVAL;
+ goto done;
}
if (!common.apr_q6_cvp) {
- pr_err("%s: apr_cvp is NULL.\n", __func__);
+ pr_err("%s: apr_cvp is NULL\n", __func__);
- goto fail;
+ ret = -EINVAL;
+ goto done;
}
if (!common.cal_mem_handle) {
- pr_err("%s: Cal mem handle is NULL\n", __func__);
+ pr_debug("%s: Cal mem handle is NULL\n", __func__);
- goto fail;
+ goto done;
}
get_vocvol_cal(&cal_block);
if (cal_block.cal_size == 0) {
pr_err("%s: CVP vol cal size is 0\n", __func__);
- goto fail;
+ goto done;
}
cvp_reg_vol_cal_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
@@ -2135,7 +2310,7 @@
if (ret < 0) {
pr_err("%s: Error %d registering CVP vol cal\n", __func__, ret);
- goto fail;
+ goto done;
}
ret = wait_event_timeout(v->cvp_wait,
(v->cvp_state == CMD_STATUS_SUCCESS),
@@ -2143,13 +2318,11 @@
if (!ret) {
pr_err("%s: Command timeout\n", __func__);
- goto fail;
+ goto done;
}
- return 0;
-
-fail:
- return -EINVAL;
+done:
+ return ret;
}
static int voice_send_cvp_deregister_vol_cal_cmd(struct voice_data *v)
@@ -2162,18 +2335,26 @@
if (v == NULL) {
pr_err("%s: v is NULL\n", __func__);
- goto fail;
+ ret = -EINVAL;
+ goto done;
}
if (!common.apr_q6_cvp) {
pr_err("%s: apr_cvp is NULL\n", __func__);
- goto fail;
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (!common.cal_mem_handle) {
+ pr_debug("%s: Cal mem handle is NULL\n", __func__);
+
+ goto done;
}
get_vocvol_cal(&cal_block);
if (cal_block.cal_size == 0)
- return 0;
+ goto done;
cvp_dereg_vol_cal_cmd.hdr.hdr_field =
APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
@@ -2194,7 +2375,7 @@
pr_err("%s: Error %d de-registering CVP vol cal\n",
__func__, ret);
- goto fail;
+ goto done;
}
ret = wait_event_timeout(v->cvp_wait,
(v->cvp_state == CMD_STATUS_SUCCESS),
@@ -2202,13 +2383,67 @@
if (!ret) {
pr_err("%s: Command timeout\n", __func__);
- goto fail;
+ goto done;
}
- return 0;
+done:
+ return ret;
+}
-fail:
- return -EINVAL;
+int voc_register_vocproc_vol_table(void)
+{
+ int result = 0;
+ int i;
+ struct voice_data *v = NULL;
+ pr_debug("%s\n", __func__);
+
+ mutex_lock(&common.common_lock);
+ for (i = 0; i < MAX_VOC_SESSIONS; i++) {
+ v = &common.voice[i];
+
+ mutex_lock(&v->lock);
+ if (is_voc_state_active(v->voc_state)) {
+ result = voice_send_cvp_register_vol_cal_cmd(v);
+ if (result) {
+ pr_err("%s: Failed to register vocvol table for session 0x%x!\n",
+ __func__, v->session_id);
+ mutex_unlock(&v->lock);
+ goto done;
+ }
+ }
+ mutex_unlock(&v->lock);
+ }
+done:
+ mutex_unlock(&common.common_lock);
+ return result;
+}
+
+int voc_deregister_vocproc_vol_table(void)
+{
+ int result = 0;
+ int i;
+ struct voice_data *v = NULL;
+ pr_debug("%s\n", __func__);
+
+ mutex_lock(&common.common_lock);
+ for (i = 0; i < MAX_VOC_SESSIONS; i++) {
+ v = &common.voice[i];
+
+ mutex_lock(&v->lock);
+ if (is_voc_state_active(v->voc_state)) {
+ result = voice_send_cvp_deregister_vol_cal_cmd(v);
+ if (result) {
+ pr_err("%s: Failed to deregister vocvol table for session 0x%x!\n",
+ __func__, v->session_id);
+ mutex_unlock(&v->lock);
+ goto done;
+ }
+ }
+ mutex_unlock(&v->lock);
+ }
+done:
+ mutex_unlock(&common.common_lock);
+ return result;
}
static int voice_map_memory_physical_cmd(struct voice_data *v,
@@ -2320,10 +2555,11 @@
return -EINVAL;
}
+ mutex_lock(&common.common_lock);
if (common.cal_mem_handle != 0) {
pr_debug("%s: Cal block already mem mapped\n", __func__);
- return ret;
+ goto done;
}
/* Get the physical address of calibration memory block from ACDB. */
@@ -2332,7 +2568,8 @@
if (!cal_block.cal_paddr) {
pr_err("%s: Cal block not allocated\n", __func__);
- return -EINVAL;
+ ret = -EINVAL;
+ goto done;
}
ret = voice_map_memory_physical_cmd(v,
@@ -2341,6 +2578,8 @@
cal_block.cal_size,
VOC_CAL_MEM_MAP_TOKEN);
+done:
+ mutex_unlock(&common.common_lock);
return ret;
}
@@ -2414,7 +2653,6 @@
}
voice_send_cvs_register_cal_cmd(v);
-
voice_send_cvp_register_dev_cfg_cmd(v);
voice_send_cvp_register_cal_cmd(v);
voice_send_cvp_register_vol_cal_cmd(v);
@@ -3041,7 +3279,8 @@
cvs_mute_cmd.hdr.opcode = VSS_IVOLUME_CMD_MUTE_V2;
cvs_mute_cmd.cvs_set_mute.direction = VSS_IVOLUME_DIRECTION_TX;
cvs_mute_cmd.cvs_set_mute.mute_flag = v->stream_tx.stream_mute;
- cvs_mute_cmd.cvs_set_mute.ramp_duration_ms = DEFAULT_MUTE_RAMP_DURATION;
+ cvs_mute_cmd.cvs_set_mute.ramp_duration_ms =
+ v->stream_tx.stream_mute_ramp_duration_ms;
v->cvs_state = CMD_STATUS_FAIL;
ret = apr_send_pkt(common.apr_q6_cvs, (uint32_t *) &cvs_mute_cmd);
@@ -3066,7 +3305,7 @@
}
static int voice_send_device_mute_cmd(struct voice_data *v, uint16_t direction,
- uint16_t mute_flag)
+ uint16_t mute_flag, uint32_t ramp_duration)
{
struct cvp_set_mute_cmd cvp_mute_cmd;
int ret = 0;
@@ -3095,7 +3334,7 @@
cvp_mute_cmd.hdr.opcode = VSS_IVOLUME_CMD_MUTE_V2;
cvp_mute_cmd.cvp_set_mute.direction = direction;
cvp_mute_cmd.cvp_set_mute.mute_flag = mute_flag;
- cvp_mute_cmd.cvp_set_mute.ramp_duration_ms = DEFAULT_MUTE_RAMP_DURATION;
+ cvp_mute_cmd.cvp_set_mute.ramp_duration_ms = ramp_duration;
v->cvp_state = CMD_STATUS_FAIL;
ret = apr_send_pkt(common.apr_q6_cvp, (uint32_t *) &cvp_mute_cmd);
@@ -3119,9 +3358,9 @@
return -EINVAL;
}
-static int voice_send_vol_index_cmd(struct voice_data *v)
+static int voice_send_vol_step_cmd(struct voice_data *v)
{
- struct cvp_set_rx_volume_index_cmd cvp_vol_cmd;
+ struct cvp_set_rx_volume_step_cmd cvp_vol_step_cmd;
int ret = 0;
void *apr_cvp;
u16 cvp_handle;
@@ -3138,21 +3377,29 @@
cvp_handle = voice_get_cvp_handle(v);
/* send volume index to cvp */
- cvp_vol_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ cvp_vol_step_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE),
APR_PKT_VER);
- cvp_vol_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
- sizeof(cvp_vol_cmd) - APR_HDR_SIZE);
- cvp_vol_cmd.hdr.src_port =
+ cvp_vol_step_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvp_vol_step_cmd) - APR_HDR_SIZE);
+ cvp_vol_step_cmd.hdr.src_port =
voice_get_idx_for_session(v->session_id);
- cvp_vol_cmd.hdr.dest_port = cvp_handle;
- cvp_vol_cmd.hdr.token = 0;
- cvp_vol_cmd.hdr.opcode = VSS_IVOCPROC_CMD_SET_RX_VOLUME_INDEX;
- cvp_vol_cmd.cvp_set_vol_idx.vol_index = v->dev_rx.volume;
+ cvp_vol_step_cmd.hdr.dest_port = cvp_handle;
+ cvp_vol_step_cmd.hdr.token = 0;
+ cvp_vol_step_cmd.hdr.opcode = VSS_IVOLUME_CMD_SET_STEP;
+ cvp_vol_step_cmd.cvp_set_vol_step.direction = VSS_IVOLUME_DIRECTION_RX;
+ cvp_vol_step_cmd.cvp_set_vol_step.value = v->dev_rx.volume_step_value;
+ cvp_vol_step_cmd.cvp_set_vol_step.ramp_duration_ms =
+ v->dev_rx.volume_ramp_duration_ms;
+ pr_debug("%s step_value:%d, ramp_duration_ms:%d",
+ __func__,
+ cvp_vol_step_cmd.cvp_set_vol_step.value,
+ cvp_vol_step_cmd.cvp_set_vol_step.ramp_duration_ms);
+
v->cvp_state = CMD_STATUS_FAIL;
- ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_vol_cmd);
+ ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_vol_step_cmd);
if (ret < 0) {
- pr_err("Fail in sending RX VOL INDEX\n");
+ pr_err("Fail in sending RX VOL step\n");
return -EINVAL;
}
ret = wait_event_timeout(v->cvp_wait,
@@ -3457,7 +3704,8 @@
cvs_start_playback.hdr.token = 0;
cvs_start_playback.hdr.opcode = VSS_IPLAYBACK_CMD_START;
cvs_start_playback.playback_mode.port_id =
- VSS_IPLAYBACK_PORT_ID_DEFAULT;
+ v->music_info.port_id;
+
v->cvs_state = CMD_STATUS_FAIL;
ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_start_playback);
@@ -3555,17 +3803,21 @@
return ret;
}
-int voc_start_playback(uint32_t set)
+int voc_start_playback(uint32_t set, uint16_t port_id)
{
int ret = 0;
u16 cvs_handle;
- int i;
+ struct voice_data *v = NULL;
- for (i = 0; i < MAX_VOC_SESSIONS; i++) {
- struct voice_data *v = &common.voice[i];
+ if (port_id == VOICE_PLAYBACK_TX)
+ 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));
+ if (v != NULL) {
mutex_lock(&v->lock);
+ v->music_info.port_id = port_id;
v->music_info.play_enable = set;
if (set)
v->music_info.count++;
@@ -3583,6 +3835,8 @@
}
mutex_unlock(&v->lock);
+ } else {
+ pr_err("%s: Invalid port_id 0x%x", __func__, port_id);
}
return ret;
@@ -3650,22 +3904,28 @@
pr_debug("%s: TX and RX mute ON\n", __func__);
voice_send_device_mute_cmd(v,
- VSS_IVOLUME_DIRECTION_TX,
- VSS_IVOLUME_MUTE_ON);
+ VSS_IVOLUME_DIRECTION_TX,
+ VSS_IVOLUME_MUTE_ON,
+ DEFAULT_MUTE_RAMP_DURATION);
voice_send_device_mute_cmd(v,
- VSS_IVOLUME_DIRECTION_RX,
- VSS_IVOLUME_MUTE_ON);
+ VSS_IVOLUME_DIRECTION_RX,
+ VSS_IVOLUME_MUTE_ON,
+ DEFAULT_MUTE_RAMP_DURATION);
} else if (v->lch_mode == VOICE_LCH_STOP) {
pr_debug("%s: TX and RX mute OFF\n", __func__);
voice_send_device_mute_cmd(v,
- VSS_IVOLUME_DIRECTION_TX,
- VSS_IVOLUME_MUTE_OFF);
+ VSS_IVOLUME_DIRECTION_TX,
+ VSS_IVOLUME_MUTE_OFF,
+ DEFAULT_MUTE_RAMP_DURATION);
voice_send_device_mute_cmd(v,
- VSS_IVOLUME_DIRECTION_RX,
- VSS_IVOLUME_MUTE_OFF);
+ VSS_IVOLUME_DIRECTION_RX,
+ VSS_IVOLUME_MUTE_OFF,
+ DEFAULT_MUTE_RAMP_DURATION);
/* Reset lch mode when VOICE_LCH_STOP is recieved */
v->lch_mode = 0;
+ /* Apply cached mute setting */
+ voice_send_stream_mute_cmd(v);
} else {
pr_debug("%s: Mute commands not sent for lch_mode=%d\n",
__func__, v->lch_mode);
@@ -3729,53 +3989,67 @@
return -EINVAL;
}
-int voc_set_tx_mute(uint32_t session_id, uint32_t dir, uint32_t mute)
+int voc_set_tx_mute(uint32_t session_id, uint32_t dir, uint32_t mute,
+ uint32_t ramp_duration)
{
- struct voice_data *v = voice_get_session(session_id);
+ struct voice_data *v = NULL;
int ret = 0;
+ struct voice_session_itr itr;
- if (v == NULL) {
- pr_err("%s: invalid session_id 0x%x\n", __func__, session_id);
+ voice_itr_init(&itr, session_id);
+ while (voice_itr_get_next_session(&itr, &v)) {
+ if (v != NULL) {
+ mutex_lock(&v->lock);
+ v->stream_tx.stream_mute = mute;
+ v->stream_tx.stream_mute_ramp_duration_ms =
+ ramp_duration;
+ if (is_voc_state_active(v->voc_state) &&
+ (v->lch_mode == 0))
+ ret = voice_send_stream_mute_cmd(v);
+ mutex_unlock(&v->lock);
+ } else {
+ pr_err("%s: invalid session_id 0x%x\n", __func__,
+ session_id);
- return -EINVAL;
+ ret = -EINVAL;
+ break;
+ }
}
- mutex_lock(&v->lock);
-
- v->stream_tx.stream_mute = mute;
-
- if ((v->voc_state == VOC_RUN) ||
- (v->voc_state == VOC_CHANGE) ||
- (v->voc_state == VOC_STANDBY))
- ret = voice_send_stream_mute_cmd(v);
-
- mutex_unlock(&v->lock);
-
return ret;
}
-int voc_set_rx_device_mute(uint32_t session_id, uint32_t mute)
+int voc_set_rx_device_mute(uint32_t session_id, uint32_t mute,
+ uint32_t ramp_duration)
{
- struct voice_data *v = voice_get_session(session_id);
+ struct voice_data *v = NULL;
int ret = 0;
+ struct voice_session_itr itr;
- if (v == NULL) {
- pr_err("%s: invalid session_id 0x%x\n", __func__, session_id);
+ voice_itr_init(&itr, session_id);
+ while (voice_itr_get_next_session(&itr, &v)) {
+ if (v != NULL) {
+ mutex_lock(&v->lock);
+ v->dev_rx.dev_mute = mute;
+ v->dev_rx.dev_mute_ramp_duration_ms =
+ ramp_duration;
+ if (((v->voc_state == VOC_RUN) ||
+ (v->voc_state == VOC_STANDBY)) &&
+ (v->lch_mode == 0))
+ ret = voice_send_device_mute_cmd(v,
+ VSS_IVOLUME_DIRECTION_RX,
+ v->dev_rx.dev_mute,
+ ramp_duration);
+ mutex_unlock(&v->lock);
+ } else {
+ pr_err("%s: invalid session_id 0x%x\n", __func__,
+ session_id);
- return -EINVAL;
+ ret = -EINVAL;
+ break;
+ }
}
- mutex_lock(&v->lock);
-
- v->dev_rx.dev_mute = mute;
-
- if (v->voc_state == VOC_RUN)
- ret = voice_send_device_mute_cmd(v,
- VSS_IVOLUME_DIRECTION_RX,
- v->dev_rx.dev_mute);
-
- mutex_unlock(&v->lock);
-
return ret;
}
@@ -3841,28 +4115,37 @@
int voc_set_pp_enable(uint32_t session_id, uint32_t module_id, uint32_t enable)
{
- struct voice_data *v = voice_get_session(session_id);
+ struct voice_data *v = NULL;
int ret = 0;
+ struct voice_session_itr itr;
- if (v == NULL) {
- pr_err("%s: invalid session_id 0x%x\n", __func__, session_id);
+ voice_itr_init(&itr, session_id);
+ while (voice_itr_get_next_session(&itr, &v)) {
+ if (v != NULL) {
+ if (!(is_voice_app_id(v->session_id) ||
+ is_volte_session(v->session_id)))
+ continue;
- return -EINVAL;
- }
+ mutex_lock(&v->lock);
+ if (module_id == MODULE_ID_VOICE_MODULE_ST)
+ v->st_enable = enable;
- mutex_lock(&v->lock);
- if (module_id == MODULE_ID_VOICE_MODULE_ST)
- v->st_enable = enable;
-
- if (v->voc_state == VOC_RUN) {
- if (module_id == MODULE_ID_VOICE_MODULE_ST)
- ret = voice_send_set_pp_enable_cmd(v,
+ if (v->voc_state == VOC_RUN) {
+ if (module_id ==
+ MODULE_ID_VOICE_MODULE_ST)
+ ret = voice_send_set_pp_enable_cmd(v,
MODULE_ID_VOICE_MODULE_ST,
enable);
+ }
+ mutex_unlock(&v->lock);
+ } else {
+ pr_err("%s: invalid session_id 0x%x\n", __func__,
+ session_id);
+ ret = -EINVAL;
+ break;
+ }
}
- mutex_unlock(&v->lock);
-
return ret;
}
@@ -3885,28 +4168,34 @@
return ret;
}
-int voc_set_rx_vol_index(uint32_t session_id, uint32_t dir, uint32_t vol_idx)
+int voc_set_rx_vol_step(uint32_t session_id, uint32_t dir, uint32_t vol_step,
+ uint32_t ramp_duration)
{
- struct voice_data *v = voice_get_session(session_id);
+ struct voice_data *v = NULL;
int ret = 0;
+ struct voice_session_itr itr;
- if (v == NULL) {
- pr_err("%s: invalid session_id 0x%x\n", __func__, session_id);
+ pr_debug("%s session id = %#x vol = %u", __func__, session_id,
+ vol_step);
- return -EINVAL;
+ voice_itr_init(&itr, session_id);
+ while (voice_itr_get_next_session(&itr, &v)) {
+ if (v != NULL) {
+ mutex_lock(&v->lock);
+ v->dev_rx.volume_step_value = vol_step;
+ v->dev_rx.volume_ramp_duration_ms = ramp_duration;
+ if (is_voc_state_active(v->voc_state))
+ ret = voice_send_vol_step_cmd(v);
+ mutex_unlock(&v->lock);
+ } else {
+ pr_err("%s: invalid session_id 0x%x\n", __func__,
+ session_id);
+
+ ret = -EINVAL;
+ break;
+ }
}
- mutex_lock(&v->lock);
-
- v->dev_rx.volume = vol_idx;
-
- if ((v->voc_state == VOC_RUN) ||
- (v->voc_state == VOC_CHANGE) ||
- (v->voc_state == VOC_STANDBY))
- ret = voice_send_vol_index_cmd(v);
-
- mutex_unlock(&v->lock);
-
return ret;
}
@@ -4150,31 +4439,34 @@
goto fail;
}
- /* Memory map the calibration memory block. */
- ret = voice_mem_map_cal_block(v);
+ /* Allocate cal mem if not already allocated and memory map
+ * the calibration memory block.
+ */
+ ret = voice_alloc_and_map_cal_mem(v);
if (ret < 0) {
- pr_err("%s: Memory map of cal block failed %d\n",
- __func__, ret);
- /* Allow call to continue, call quality will be bad. */
+ pr_debug("%s: Continue without calibration %d\n",
+ __func__, ret);
}
if (is_voip_session(session_id)) {
- ret = voice_map_memory_physical_cmd(v,
- &v->shmem_info.memtbl,
- v->shmem_info.sh_buf.buf[0].phys,
- v->shmem_info.sh_buf.buf[0].size * NUM_OF_BUFFERS,
- VOIP_MEM_MAP_TOKEN);
- if (ret) {
- pr_err("%s: mvm_map_memory_phy failed %d\n",
- __func__, ret);
+ /* Allocate oob mem if not already allocated and
+ * memory map the oob memory block.
+ */
+ ret = voice_alloc_and_map_oob_mem(v);
+ if (ret < 0) {
+ pr_err("%s: voice_alloc_and_map_oob_mem() failed, ret:%d\n",
+ __func__, ret);
+
goto fail;
}
+
ret = voice_set_packet_exchange_mode_and_config(
session_id,
VSS_ISTREAM_PACKET_EXCHANGE_MODE_OUT_OF_BAND);
if (ret) {
pr_err("%s: Err: exchange_mode_and_config %d\n",
__func__, ret);
+
goto fail;
}
}
@@ -4189,7 +4481,7 @@
goto fail;
}
- ret = voice_send_vol_index_cmd(v);
+ ret = voice_send_vol_step_cmd(v);
if (ret < 0)
pr_err("voice volume failed\n");
@@ -4278,15 +4570,25 @@
v = voice_get_session(session_id);
if (v != NULL)
v->voc_state = VOC_ERROR;
+
+ session_id = voc_get_session_id(QCHAT_SESSION_NAME);
+ v = voice_get_session(session_id);
+ if (v != NULL)
+ v->voc_state = VOC_ERROR;
} else {
pr_debug("%s: Reset event received in Voice service\n",
__func__);
apr_reset(c->apr_q6_mvm);
c->apr_q6_mvm = NULL;
+ /* clean up memory handle */
+ c->cal_mem_handle = 0;
+
/* Sub-system restart is applicable to all sessions. */
- for (i = 0; i < MAX_VOC_SESSIONS; i++)
+ for (i = 0; i < MAX_VOC_SESSIONS; i++) {
c->voice[i].mvm_handle = 0;
+ c->voice[i].shmem_info.mem_handle = 0;
+ }
}
return 0;
}
@@ -4416,6 +4718,11 @@
v = voice_get_session(session_id);
if (v != NULL)
v->voc_state = VOC_ERROR;
+
+ session_id = voc_get_session_id(QCHAT_SESSION_NAME);
+ v = voice_get_session(session_id);
+ if (v != NULL)
+ v->voc_state = VOC_ERROR;
} else {
pr_debug("%s: Reset event received in Voice service\n",
__func__);
@@ -4688,6 +4995,11 @@
v = voice_get_session(session_id);
if (v != NULL)
v->voc_state = VOC_ERROR;
+
+ session_id = voc_get_session_id(QCHAT_SESSION_NAME);
+ v = voice_get_session(session_id);
+ if (v != NULL)
+ v->voc_state = VOC_ERROR;
} else {
pr_debug("%s: Reset event received in Voice service\n",
__func__);
@@ -4732,7 +5044,7 @@
wake_up(&v->cvp_wait);
break;
case VSS_IVOCPROC_CMD_SET_DEVICE_V2:
- case VSS_IVOCPROC_CMD_SET_RX_VOLUME_INDEX:
+ case VSS_IVOLUME_CMD_SET_STEP:
case VSS_IVOCPROC_CMD_ENABLE:
case VSS_IVOCPROC_CMD_DISABLE:
case APRV2_IBASIC_CMD_DESTROY_SESSION:
@@ -4787,6 +5099,45 @@
return 0;
}
+static int voice_free_oob_shared_mem(void)
+{
+ int rc = 0;
+ int cnt = 0;
+ int bufcnt = NUM_OF_BUFFERS;
+ struct voice_data *v = voice_get_session(
+ common.voice[VOC_PATH_FULL].session_id);
+
+ mutex_lock(&common.common_lock);
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+
+ rc = -EINVAL;
+ goto done;
+ }
+
+ rc = msm_audio_ion_free(v->shmem_info.sh_buf.client,
+ v->shmem_info.sh_buf.handle);
+ if (rc < 0) {
+ pr_err("%s: Error:%d freeing memory\n", __func__, rc);
+
+ goto done;
+ }
+
+
+ while (cnt < bufcnt) {
+ v->shmem_info.sh_buf.buf[cnt].data = NULL;
+ v->shmem_info.sh_buf.buf[cnt].phys = 0;
+ cnt++;
+ }
+
+ v->shmem_info.sh_buf.client = NULL;
+ v->shmem_info.sh_buf.handle = NULL;
+
+done:
+ mutex_unlock(&common.common_lock);
+ return rc;
+}
+
static int voice_alloc_oob_shared_mem(void)
{
int cnt = 0;
@@ -4799,9 +5150,12 @@
struct voice_data *v = voice_get_session(
common.voice[VOC_PATH_FULL].session_id);
+ mutex_lock(&common.common_lock);
if (v == NULL) {
pr_err("%s: v is NULL\n", __func__);
- return -EINVAL;
+
+ rc = -EINVAL;
+ goto done;
}
rc = msm_audio_ion_alloc("voip_client", &(v->shmem_info.sh_buf.client),
@@ -4809,10 +5163,11 @@
bufsz*bufcnt,
(ion_phys_addr_t *)&phys, (size_t *)&len,
&mem_addr);
- if (rc) {
+ if (rc < 0) {
pr_err("%s: audio ION alloc failed, rc = %d\n",
__func__, rc);
- return -EINVAL;
+
+ goto done;
}
while (cnt < bufcnt) {
@@ -4835,7 +5190,9 @@
memset((void *)v->shmem_info.sh_buf.buf[0].data, 0, (bufsz * bufcnt));
- return 0;
+done:
+ mutex_unlock(&common.common_lock);
+ return rc;
}
static int voice_alloc_oob_mem_table(void)
@@ -4845,9 +5202,12 @@
struct voice_data *v = voice_get_session(
common.voice[VOC_PATH_FULL].session_id);
+ mutex_lock(&common.common_lock);
if (v == NULL) {
pr_err("%s: v is NULL\n", __func__);
- return -EINVAL;
+
+ rc = -EINVAL;
+ goto done;
}
rc = msm_audio_ion_alloc("voip_client", &(v->shmem_info.memtbl.client),
@@ -4856,21 +5216,22 @@
(ion_phys_addr_t *)&v->shmem_info.memtbl.phys,
(size_t *)&len,
&(v->shmem_info.memtbl.data));
- if (rc) {
+ if (rc < 0) {
pr_err("%s: audio ION alloc failed, rc = %d\n",
__func__, rc);
- return -EINVAL;
+
+ goto done;
}
v->shmem_info.memtbl.size = sizeof(struct vss_imemory_table_t);
-
pr_debug("%s data[%p]phys[%p][%p]\n", __func__,
(void *)v->shmem_info.memtbl.data,
(void *)v->shmem_info.memtbl.phys,
(void *)&v->shmem_info.memtbl.phys);
- return 0;
-
+done:
+ mutex_unlock(&common.common_lock);
+ return rc;
}
static int voice_alloc_cal_mem_map_table(void)
@@ -4878,17 +5239,17 @@
int ret = 0;
int len;
- ret = msm_audio_ion_alloc("voip_client",
+ ret = msm_audio_ion_alloc("voc_cal",
&(common.cal_mem_map_table.client),
&(common.cal_mem_map_table.handle),
sizeof(struct vss_imemory_table_t),
(ion_phys_addr_t *)&common.cal_mem_map_table.phys,
(size_t *) &len,
&(common.cal_mem_map_table.data));
- if (ret) {
+ if (ret < 0) {
pr_err("%s: audio ION alloc failed, rc = %d\n",
__func__, ret);
- return -EINVAL;
+ goto done;
}
common.cal_mem_map_table.size = sizeof(struct vss_imemory_table_t);
@@ -4896,7 +5257,78 @@
(unsigned int) common.cal_mem_map_table.data,
common.cal_mem_map_table.phys);
- return 0;
+done:
+ return ret;
+}
+
+static int voice_alloc_and_map_cal_mem(struct voice_data *v)
+{
+ int ret = 0;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+
+ return -EINVAL;
+ }
+
+ ret = voc_alloc_cal_shared_memory();
+ if (ret < 0) {
+ pr_err("%s: Memory allocation of cal block failed %d\n",
+ __func__, ret);
+
+ goto done;
+ }
+
+ /* Memory map the calibration memory block. */
+ ret = voice_mem_map_cal_block(v);
+ if (ret < 0) {
+ pr_err("%s: Memory map of cal block failed %d\n",
+ __func__, ret);
+ }
+
+done:
+ return ret;
+}
+
+static int voice_alloc_and_map_oob_mem(struct voice_data *v)
+{
+ int ret = 0;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+
+ return -EINVAL;
+ }
+
+ if (!is_voip_memory_allocated()) {
+ ret = voc_alloc_voip_shared_memory();
+ if (ret < 0) {
+ pr_err("%s: Failed to create voip oob memory %d\n",
+ __func__, ret);
+
+ goto done;
+ }
+ }
+
+ ret = voice_map_memory_physical_cmd(v,
+ &v->shmem_info.memtbl,
+ v->shmem_info.sh_buf.buf[0].phys,
+ v->shmem_info.sh_buf.buf[0].size * NUM_OF_BUFFERS,
+ VOIP_MEM_MAP_TOKEN);
+ if (ret) {
+ pr_err("%s: mvm_map_memory_phy failed %d\n",
+ __func__, ret);
+
+ goto done;
+ }
+
+done:
+ return ret;
+}
+
+int is_voc_initialized(void)
+{
+ return module_initialized;
}
static int __init voice_init(void)
@@ -4907,8 +5339,10 @@
/* set default value */
common.default_mute_val = 0; /* default is un-mute */
- common.default_vol_val = 0;
common.default_sample_val = 8000;
+ 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;
/* Initialize MVS info. */
common.mvs_info.network_type = VSS_NETWORK_ID_DEFAULT;
@@ -4921,9 +5355,16 @@
for (i = 0; i < MAX_VOC_SESSIONS; i++) {
/* initialize dev_rx and dev_tx */
- common.voice[i].dev_rx.volume = common.default_vol_val;
common.voice[i].dev_rx.dev_mute = common.default_mute_val;
common.voice[i].dev_tx.dev_mute = common.default_mute_val;
+ common.voice[i].dev_rx.volume_step_value =
+ common.default_vol_step_val;
+ common.voice[i].dev_rx.volume_ramp_duration_ms =
+ common.default_vol_ramp_duration_ms;
+ common.voice[i].dev_rx.dev_mute_ramp_duration_ms =
+ common.default_mute_ramp_duration_ms;
+ common.voice[i].dev_tx.dev_mute_ramp_duration_ms =
+ common.default_mute_ramp_duration_ms;
common.voice[i].stream_rx.stream_mute = common.default_mute_val;
common.voice[i].stream_tx.stream_mute = common.default_mute_val;
@@ -4942,21 +5383,11 @@
mutex_init(&common.voice[i].lock);
}
- /* Allocate shared memory for OOB Voip */
- rc = voice_alloc_oob_shared_mem();
- if (rc < 0)
- pr_err("failed to alloc shared memory for OOB %d\n", rc);
- else {
- /* Allocate mem map table for OOB */
- rc = voice_alloc_oob_mem_table();
- if (rc < 0)
- pr_err("failed to alloc mem map talbe %d\n", rc);
- }
+ if (rc == 0)
+ module_initialized = true;
- /* Allocate memory for calibration memory map table. */
- rc = voice_alloc_cal_mem_map_table();
-
+ pr_debug("%s: rc=%d\n", __func__, rc);
return rc;
}
-late_initcall(voice_init);
+device_initcall(voice_init);
diff --git a/sound/soc/msm/qdsp6v2/q6voice.h b/sound/soc/msm/qdsp6v2/q6voice.h
index 5a16115..1e9c813 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.h
+++ b/sound/soc/msm/qdsp6v2/q6voice.h
@@ -45,16 +45,19 @@
/* Stream information payload structure */
struct stream_data {
uint32_t stream_mute;
+ uint32_t stream_mute_ramp_duration_ms;
};
/* Device information payload structure */
struct device_data {
- uint32_t volume; /* in index */
uint32_t dev_mute;
uint32_t sample;
uint32_t enabled;
uint32_t dev_id;
uint32_t port_id;
+ uint32_t volume_step_value;
+ uint32_t volume_ramp_duration_ms;
+ uint32_t dev_mute_ramp_duration_ms;
};
struct voice_dev_route_state {
@@ -486,6 +489,12 @@
#define VSS_IPLAYBACK_PORT_ID_DEFAULT 0x0000FFFF
/* Default AFE port ID. */
+#define VSS_IPLAYBACK_PORT_ID_VOICE 0x00008005
+/* AFE port ID for VOICE 1. */
+
+#define VSS_IPLAYBACK_PORT_ID_VOICE2 0x00008002
+/* AFE port ID for VOICE 2. */
+
#define VSS_IRECORD_CMD_START 0x000112BE
/* Start in-call conversation recording. */
#define VSS_IRECORD_CMD_STOP 0x00011237
@@ -582,6 +591,8 @@
#define VSS_IVOLUME_MUTE_ON 1
#define DEFAULT_MUTE_RAMP_DURATION 500
+#define DEFAULT_VOLUME_RAMP_DURATION 20
+#define MAX_RAMP_DURATION 5000
struct vss_ivolume_cmd_mute_v2_t {
uint16_t direction;
@@ -896,7 +907,7 @@
#define VSS_IVOCPROC_CMD_SET_VP3_DATA 0x000110EB
-#define VSS_IVOCPROC_CMD_SET_RX_VOLUME_INDEX 0x000110EE
+#define VSS_IVOLUME_CMD_SET_STEP 0x000112C2
#define VSS_IVOCPROC_CMD_ENABLE 0x000100C6
/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
@@ -1030,6 +1041,25 @@
*/
} __packed;
+struct vss_ivolume_cmd_set_step_t {
+ uint16_t direction;
+ /*
+ * The direction field sets the direction to apply the volume command.
+ * The supported values:
+ * #VSS_IVOLUME_DIRECTION_RX
+ */
+ uint32_t value;
+ /*
+ * Volume step used to find the corresponding linear volume and
+ * the best match index in the registered volume calibration table.
+ */
+ uint16_t ramp_duration_ms;
+ /*
+ * Volume change ramp duration in milliseconds.
+ * The supported values: 0 to 5000.
+ */
+} __packed;
+
struct vss_ivocproc_cmd_set_device_v2_t {
uint16_t tx_port_id;
/*
@@ -1137,6 +1167,11 @@
struct vss_ivocproc_cmd_set_volume_index_t cvp_set_vol_idx;
} __packed;
+struct cvp_set_rx_volume_step_cmd {
+ struct apr_hdr hdr;
+ struct vss_ivolume_cmd_set_step_t cvp_set_vol_step;
+} __packed;
+
struct cvp_register_dev_cfg_cmd {
struct apr_hdr hdr;
struct vss_ivocproc_cmd_register_device_config_t cvp_dev_cfg_data;
@@ -1209,6 +1244,7 @@
uint32_t playing;
int count;
int force;
+ uint16_t port_id;
};
struct share_memory_info {
@@ -1273,13 +1309,15 @@
void *buf;
};
-#define MAX_VOC_SESSIONS 4
+#define MAX_VOC_SESSIONS 5
struct common_data {
/* these default values are for all devices */
uint32_t default_mute_val;
- uint32_t default_vol_val;
uint32_t default_sample_val;
+ uint32_t default_vol_step_val;
+ uint32_t default_vol_ramp_duration_ms;
+ uint32_t default_mute_ramp_duration_ms;
/* APR to MVM in the Q6 */
void *apr_q6_mvm;
@@ -1302,6 +1340,11 @@
struct voice_data voice[MAX_VOC_SESSIONS];
};
+struct voice_session_itr {
+ int cur_idx;
+ int session_idx;
+};
+
void voc_register_mvs_cb(ul_cb_fn ul_cb,
dl_cb_fn dl_cb,
void *private_data);
@@ -1329,19 +1372,35 @@
#define VOC_PATH_FULL 1
#define VOC_PATH_VOLTE_PASSIVE 2
#define VOC_PATH_VOICE2_PASSIVE 3
+#define VOC_PATH_QCHAT_PASSIVE 4
#define MAX_SESSION_NAME_LEN 32
#define VOICE_SESSION_NAME "Voice session"
#define VOIP_SESSION_NAME "VoIP session"
#define VOLTE_SESSION_NAME "VoLTE session"
#define VOICE2_SESSION_NAME "Voice2 session"
+#define QCHAT_SESSION_NAME "QCHAT session"
#define VOICE2_SESSION_VSID_STR "10DC1000"
+#define QCHAT_SESSION_VSID_STR "10803000"
#define VOICE_SESSION_VSID 0x10C01000
#define VOICE2_SESSION_VSID 0x10DC1000
#define VOLTE_SESSION_VSID 0x10C02000
#define VOIP_SESSION_VSID 0x10004000
+#define QCHAT_SESSION_VSID 0x10803000
#define ALL_SESSION_VSID 0xFFFFFFFF
+#define VSID_MAX ALL_SESSION_VSID
+
+#define APP_ID_MASK 0x3F000
+#define APP_ID_SHIFT 12
+enum vsid_app_type {
+ VSID_APP_NONE = 0,
+ VSID_APP_CS_VOICE = 1,
+ VSID_APP_IMS = 2, /* IMS voice services covering VoLTE etc */
+ VSID_APP_QCHAT = 3,
+ VSID_APP_VOIP = 4, /* VoIP on AP HLOS without modem processor */
+ VSID_APP_MAX,
+};
/* called by alsa driver */
int voc_set_pp_enable(uint32_t session_id, uint32_t module_id,
@@ -1357,9 +1416,12 @@
int voc_set_rxtx_port(uint32_t session_id,
uint32_t dev_port_id,
uint32_t dev_type);
-int voc_set_rx_vol_index(uint32_t session_id, uint32_t dir, uint32_t voc_idx);
-int voc_set_tx_mute(uint32_t session_id, uint32_t dir, uint32_t mute);
-int voc_set_rx_device_mute(uint32_t session_id, uint32_t mute);
+int voc_set_rx_vol_step(uint32_t session_id, uint32_t dir, uint32_t vol_step,
+ uint32_t ramp_duration);
+int voc_set_tx_mute(uint32_t session_id, uint32_t dir, uint32_t mute,
+ uint32_t ramp_duration);
+int voc_set_rx_device_mute(uint32_t session_id, uint32_t mute,
+ uint32_t ramp_duration);
int voc_get_rx_device_mute(uint32_t session_id);
int voc_disable_cvp(uint32_t session_id);
int voc_enable_cvp(uint32_t session_id);
@@ -1367,9 +1429,16 @@
uint8_t voc_get_route_flag(uint32_t session_id, uint8_t path_dir);
int voc_enable_dtmf_rx_detection(uint32_t session_id, uint32_t enable);
void voc_disable_dtmf_det_on_active_sessions(void);
+int voc_alloc_cal_shared_memory(void);
+int voc_alloc_voip_shared_memory(void);
+int is_voc_initialized(void);
+int voc_register_vocproc_vol_table(void);
+int voc_deregister_vocproc_vol_table(void);
uint32_t voc_get_session_id(char *name);
-int voc_start_playback(uint32_t set);
+int voc_start_playback(uint32_t set, uint16_t port_id);
int voc_start_record(uint32_t port_id, uint32_t set);
+int voice_get_idx_for_session(u32 session_id);
+
#endif
diff --git a/sound/soc/msm/qdsp6v2/rtac.c b/sound/soc/msm/qdsp6v2/rtac.c
index 1f2a487..a4983d3 100644
--- a/sound/soc/msm/qdsp6v2/rtac.c
+++ b/sound/soc/msm/qdsp6v2/rtac.c
@@ -24,7 +24,7 @@
#include <sound/q6asm-v2.h>
#include <sound/q6afe-v2.h>
#include <sound/apr_audio-v2.h>
-
+#include <q6voice.h>
#include "audio_acdb.h"
@@ -352,13 +352,13 @@
return;
}
-static int get_voice_index_cvs(u32 cvs_handle)
+static u32 get_voice_session_id_cvs(u32 cvs_handle)
{
u32 i;
for (i = 0; i < rtac_voice_data.num_of_voice_combos; i++) {
if (rtac_voice_data.voice[i].cvs_handle == cvs_handle)
- return i;
+ return voice_session_id[i];
}
pr_err("%s: No voice index for CVS handle %d found returning 0\n",
@@ -366,13 +366,13 @@
return 0;
}
-static int get_voice_index_cvp(u32 cvp_handle)
+static u32 get_voice_session_id_cvp(u32 cvp_handle)
{
u32 i;
for (i = 0; i < rtac_voice_data.num_of_voice_combos; i++) {
if (rtac_voice_data.voice[i].cvp_handle == cvp_handle)
- return i;
+ return voice_session_id[i];
}
pr_err("%s: No voice index for CVP handle %d found returning 0\n",
@@ -383,9 +383,11 @@
static int get_voice_index(u32 mode, u32 handle)
{
if (mode == RTAC_CVP)
- return get_voice_index_cvp(handle);
+ return voice_get_idx_for_session(
+ get_voice_session_id_cvp(handle));
if (mode == RTAC_CVS)
- return get_voice_index_cvs(handle);
+ return voice_get_idx_for_session(
+ get_voice_session_id_cvs(handle));
pr_err("%s: Invalid mode %d, returning 0\n",
__func__, mode);
@@ -847,8 +849,7 @@
payload_size);
voice_params.src_svc = 0;
voice_params.src_domain = APR_DOMAIN_APPS;
- voice_params.src_port = voice_session_id[
- get_voice_index(mode, dest_port)];
+ voice_params.src_port = get_voice_index(mode, dest_port);
voice_params.dest_svc = 0;
voice_params.dest_domain = APR_DOMAIN_MODEM;
voice_params.dest_port = (u16)dest_port;