Merge "ASoC: msm: qdsp6v2: Fix bug in device V2 command"
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/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/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/coresight/coresight.txt b/Documentation/devicetree/bindings/coresight/coresight.txt
index 8d1d46d..d24e671 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
@@ -236,3 +241,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-mdp.txt b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
index 9bc949e..514160e 100644
--- a/Documentation/devicetree/bindings/fb/mdss-mdp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
@@ -123,7 +123,9 @@
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.
Optional subnodes:
Child nodes representing the frame buffer virtual devices.
@@ -161,6 +163,7 @@
qcom,mdss-rot-block-size = <64>;
qcom,mdss-has-bwc;
qcom,mdss-has-decimation;
+ qcom,mdss-has-wfd-blk;
qcom,mdss-ctl-off = <0x00000600 0x00000700 0x00000800
0x00000900 0x0000A00>;
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/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 4c6569e..c799ffb 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";
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 70bf993..e724c62 100644
--- a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
@@ -65,6 +65,14 @@
5 (2^5 = 32) 32 micro frame interrupt threshold aka 4ms interrupt threshold
6 (2^6 = 64) 64 micro frame interrupt threshold aka 8ms interrupt threshold
+- hsic,disable-cerr: CERR is 2bit down error counter that keeps track of number
+ of consecutive errors detected on single usb transaction. When set to non
+ zero value, hw decrements the count and updates qTD when transaction fails.
+ If counter reaches zero, hw marks the qTD inactive and triggers the interrupt.
+ When CERR is programmed to zero, hw ignores transaction failures. ECHI stack
+ programs the CERR to 3 by default. When this flag is true, CERR is set to
+ zero and transaction errors are ignored.
+
- 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..f687e77 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -81,6 +81,7 @@
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.
Example HSUSB OTG controller device node :
usb@f9690000 {
@@ -128,6 +129,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/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 96%
rename from arch/arm/boot/dts/apq8026.dtsi
rename to arch/arm/boot/dts/apq8026-v1.dtsi
index db6576a..f15a96f 100644
--- a/arch/arm/boot/dts/apq8026.dtsi
+++ b/arch/arm/boot/dts/apq8026-v1.dtsi
@@ -16,7 +16,7 @@
* file.
*/
-/include/ "msm8226.dtsi"
+/include/ "msm8226-v1.dtsi"
/ {
model = "Qualcomm APQ 8026";
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 96%
copy from arch/arm/boot/dts/apq8026.dtsi
copy to arch/arm/boot/dts/apq8026-v2.dtsi
index db6576a..d87b500 100644
--- a/arch/arm/boot/dts/apq8026.dtsi
+++ b/arch/arm/boot/dts/apq8026-v2.dtsi
@@ -16,7 +16,7 @@
* file.
*/
-/include/ "msm8226.dtsi"
+/include/ "msm8226-v2.dtsi"
/ {
model = "Qualcomm APQ 8026";
diff --git a/arch/arm/boot/dts/apq8074-dragonboard.dtsi b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
index 4b20e9f..311e968 100644
--- a/arch/arm/boot/dts/apq8074-dragonboard.dtsi
+++ b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
@@ -484,6 +484,7 @@
&pm8941_mpps {
mpp@a000 { /* MPP 1 */
+ status = "disabled";
};
mpp@a100 { /* MPP 2 */
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
new file mode 100644
index 0000000..610d80b
--- /dev/null
+++ b/arch/arm/boot/dts/apq8084-coresight.dtsi
@@ -0,0 +1,145 @@
+/* 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 {
+ tmc_etr: tmc@fc326000 {
+ compatible = "arm,coresight-tmc";
+ reg = <0xfc326000 0x1000>,
+ <0xfc37c000 0x3000>;
+ reg-names = "tmc-base", "bam-base";
+
+ qcom,memory-reservation-type = "EBI1";
+ qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
+
+ coresight-id = <0>;
+ coresight-name = "coresight-tmc-etr";
+ coresight-nr-inports = <1>;
+ };
+
+ replicator: replicator@fc324000 {
+ compatible = "qcom,coresight-replicator";
+ reg = <0xfc324000 0x1000>;
+ reg-names = "replicator-base";
+
+ coresight-id = <2>;
+ coresight-name = "coresight-replicator";
+ coresight-nr-inports = <1>;
+ coresight-outports = <0>;
+ coresight-child-list = <&tmc_etr>;
+ coresight-child-ports = <0>;
+ };
+
+ tmc_etf: tmc@fc325000 {
+ compatible = "arm,coresight-tmc";
+ reg = <0xfc325000 0x1000>;
+ reg-names = "tmc-base";
+
+ coresight-id = <3>;
+ coresight-name = "coresight-tmc-etf";
+ coresight-nr-inports = <1>;
+ coresight-outports = <0>;
+ coresight-child-list = <&replicator>;
+ coresight-child-ports = <0>;
+ coresight-default-sink;
+ };
+
+ funnel_merg: funnel@fc323000 {
+ compatible = "arm,coresight-funnel";
+ reg = <0xfc323000 0x1000>;
+ reg-names = "funnel-base";
+
+ coresight-id = <4>;
+ coresight-name = "coresight-funnel-merg";
+ coresight-nr-inports = <2>;
+ coresight-outports = <0>;
+ coresight-child-list = <&tmc_etf>;
+ coresight-child-ports = <0>;
+ };
+
+ funnel_in0: funnel@fc321000 {
+ compatible = "arm,coresight-funnel";
+ reg = <0xfc321000 0x1000>;
+ reg-names = "funnel-base";
+
+ coresight-id = <5>;
+ coresight-name = "coresight-funnel-in0";
+ coresight-nr-inports = <8>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_merg>;
+ coresight-child-ports = <0>;
+ };
+
+ funnel_in1: funnel@fc322000 {
+ compatible = "arm,coresight-funnel";
+ reg = <0xfc322000 0x1000>;
+ reg-names = "funnel-base";
+
+ coresight-id = <6>;
+ coresight-name = "coresight-funnel-in1";
+ coresight-nr-inports = <8>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_merg>;
+ coresight-child-ports = <1>;
+ };
+
+ funnel_kpss: funnel@fc355000 {
+ compatible = "arm,coresight-funnel";
+ reg = <0xfc355000 0x1000>;
+ reg-names = "funnel-base";
+
+ coresight-id = <7>;
+ coresight-name = "coresight-funnel-kpss";
+ coresight-nr-inports = <4>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_in1>;
+ coresight-child-ports = <5>;
+ };
+
+ funnel_mmss: funnel@fc36c000 {
+ compatible = "arm,coresight-funnel";
+ reg = <0xfc36c000 0x1000>;
+ reg-names = "funnel-base";
+
+ coresight-id = <8>;
+ coresight-name = "coresight-funnel-mmss";
+ coresight-nr-inports = <8>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_in1>;
+ coresight-child-ports = <1>;
+ };
+
+ stm: stm@fc302000 {
+ compatible = "arm,coresight-stm";
+ reg = <0xfc302000 0x1000>,
+ <0xfa280000 0x180000>;
+ reg-names = "stm-base", "stm-data-base";
+
+ coresight-id = <9>;
+ coresight-name = "coresight-stm";
+ coresight-nr-inports = <0>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_in1>;
+ coresight-child-ports = <7>;
+ };
+
+ csr: csr@fc301000 {
+ compatible = "qcom,coresight-csr";
+ reg = <0xfc301000 0x1000>;
+ reg-names = "csr-base";
+
+ coresight-id = <14>;
+ coresight-name = "coresight-csr";
+ coresight-nr-inports = <0>;
+
+ qcom,blk-size = <3>;
+ };
+};
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..b9609cc
--- /dev/null
+++ b/arch/arm/boot/dts/apq8084-mdss.dtsi
@@ -0,0 +1,77 @@
+/* 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>;
+
+ 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.dtsi b/arch/arm/boot/dts/apq8084.dtsi
index e5f083a..39eae2e 100644
--- a/arch/arm/boot/dts/apq8084.dtsi
+++ b/arch/arm/boot/dts/apq8084.dtsi
@@ -19,8 +19,12 @@
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"
&soc {
#address-cells = <1>;
@@ -282,6 +286,16 @@
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";
+ };
};
/include/ "msm-pma8084.dtsi"
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..d742b30 100644
--- a/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
@@ -514,7 +514,8 @@
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];
+ 29 01 00 00 78 00 02 29 00
+ 29 01 00 00 78 00 02 53 2C];
qcom,on-cmds-dsi-state = "DSI_LP_MODE";
qcom,panel-off-cmds = [05 01 00 00 32 00 02 28 00
diff --git a/arch/arm/boot/dts/mpq8092.dtsi b/arch/arm/boot/dts/mpq8092.dtsi
index e8674a0..2eaa32f 100644
--- a/arch/arm/boot/dts/mpq8092.dtsi
+++ b/arch/arm/boot/dts/mpq8092.dtsi
@@ -210,6 +210,41 @@
qcom,pet-time = <10000>;
qcom,ipi-ping;
};
+
+ qcom,ocmem@fdd00000 {
+ compatible = "qcom,msm-ocmem";
+ reg = <0xfdd00000 0x2000>,
+ <0xfdd02000 0x2000>,
+ <0xfe070000 0x400>,
+ <0xfec00000 0x180000>;
+ reg-names = "ocmem_ctrl_physical", "dm_ctrl_physical", "br_ctrl_physical", "ocmem_physical";
+ interrupts = <0 76 0>, <0 77 0>;
+ interrupt-names = "ocmem_irq", "dm_irq";
+ qcom,ocmem-num-regions = <0x3>;
+ qcom,ocmem-num-macros = <0x18>;
+ qcom,resource-type = <0x706d636f>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0xfec00000 0x180000>;
+
+ partition@0 {
+ reg = <0x0 0x100000>;
+ qcom,ocmem-part-name = "graphics";
+ qcom,ocmem-part-min = <0x80000>;
+ };
+
+ partition@80000 {
+ reg = <0x100000 0x80000>;
+ qcom,ocmem-part-name = "lp_audio";
+ qcom,ocmem-part-min = <0x80000>;
+ };
+
+ partition@100000 {
+ reg = <0x100000 0x80000>;
+ qcom,ocmem-part-name = "video";
+ qcom,ocmem-part-min = <0x55000>;
+ };
+ };
};
&gdsc_venus {
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-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index b801da8..40f9a7c 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -555,7 +555,7 @@
};
};
- vadc@3100 {
+ pm8941_vadc: vadc@3100 {
compatible = "qcom,qpnp-vadc";
reg = <0x3100 0x100>;
#address-cells = <1>;
@@ -797,7 +797,7 @@
};
};
- iadc@3600 {
+ pm8941_iadc: iadc@3600 {
compatible = "qcom,qpnp-iadc";
reg = <0x3600 0x100>;
#address-cells = <1>;
@@ -819,7 +819,7 @@
};
};
- qcom,vadc@3400 {
+ pm8941_adc_tm: qcom,vadc@3400 {
compatible = "qcom,qpnp-adc-tm";
reg = <0x3400 0x100>;
#address-cells = <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-cdp.dtsi b/arch/arm/boot/dts/msm8226-cdp.dtsi
index 308a6f5..e5683fb 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 */
diff --git a/arch/arm/boot/dts/msm8226-coresight.dtsi b/arch/arm/boot/dts/msm8226-coresight.dtsi
index e11c963..2be7d1f 100644
--- a/arch/arm/boot/dts/msm8226-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8226-coresight.dtsi
@@ -365,8 +365,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";
diff --git a/arch/arm/boot/dts/msm8226-ion.dtsi b/arch/arm/boot/dts/msm8226-ion.dtsi
index dee64e5..9574b7d 100644
--- a/arch/arm/boot/dts/msm8226-ion.dtsi
+++ b/arch/arm/boot/dts/msm8226-ion.dtsi
@@ -35,6 +35,13 @@
reg = <25>;
};
+ qcom,ion-heap@22 { /* adsp heap */
+ compatible = "qcom,msm-ion-reserve";
+ reg = <22>;
+ qcom,heap-align = <0x1000>;
+ linux,contiguous-region = <&adsp_mem>;
+ };
+
qcom,ion-heap@27 { /* QSECOM HEAP */
compatible = "qcom,msm-ion-reserve";
reg = <27>;
diff --git a/arch/arm/boot/dts/msm8226-mtp.dtsi b/arch/arm/boot/dts/msm8226-mtp.dtsi
index acab5e4..0df3feb 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 */
@@ -37,6 +38,17 @@
};
};
+ i2c@f9925000 { /* BLSP1 QUP3 */
+ nfc-nci@0e {
+ compatible = "qcom,nfc-nci";
+ reg = <0x0e>;
+ qcom,irq-gpio = <&msmgpio 21 0x00>;
+ qcom,dis-gpio = <&msmgpio 20 0x00>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <21 0>;
+ qcom,clk-gpio = <&pm8226_gpios 3 0>;
+ };
+ };
gpio_keys {
compatible = "gpio-keys";
input-name = "gpio-keys";
@@ -342,6 +354,11 @@
};
gpio@c200 { /* GPIO 3 */
+ qcom,mode = <0>; /* QPNP_PIN_MODE_DIG_IN */
+ qcom,pull = <5>; /* QPNP_PIN_PULL_NO */
+ qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
+ qcom,src-sel = <2>; /* QPNP_PIN_SEL_FUNC_1 */
+ qcom,master-en = <1>;
};
gpio@c300 { /* GPIO 4 */
diff --git a/arch/arm/boot/dts/msm8226-qrd.dtsi b/arch/arm/boot/dts/msm8226-qrd.dtsi
index 64cbb10..74ecc68 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8226-qrd.dtsi
@@ -10,16 +10,12 @@
* GNU General Public License for more details.
*/
-/include/ "dsi-panel-nt35590-720p-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 */
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index e1a0f0b..8006da2 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -95,6 +95,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 +119,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";
};
};
diff --git a/arch/arm/boot/dts/msm8226-v1-qrd.dts b/arch/arm/boot/dts/msm8226-v1-qrd-dvt.dts
similarity index 73%
copy from arch/arm/boot/dts/msm8226-v1-qrd.dts
copy to arch/arm/boot/dts/msm8226-v1-qrd-dvt.dts
index d2aabac..d36e93e 100644
--- a/arch/arm/boot/dts/msm8226-v1-qrd.dts
+++ b/arch/arm/boot/dts/msm8226-v1-qrd-dvt.dts
@@ -13,13 +13,19 @@
/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";
+ };
};
diff --git a/arch/arm/boot/dts/msm8226-v1-qrd.dts b/arch/arm/boot/dts/msm8226-v1-qrd-evt.dts
similarity index 84%
rename from arch/arm/boot/dts/msm8226-v1-qrd.dts
rename to arch/arm/boot/dts/msm8226-v1-qrd-evt.dts
index d2aabac..bf94d04 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,9 @@
<198 11 0>,
<205 11 0>;
};
+
+&soc {
+ qcom,mdss_dsi_nt35590_720p_video {
+ status = "ok";
+ };
+};
diff --git a/arch/arm/boot/dts/msm8226-v1-qrd.dts b/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts
similarity index 73%
copy from arch/arm/boot/dts/msm8226-v1-qrd.dts
copy to arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts
index d2aabac..8520ae3 100644
--- a/arch/arm/boot/dts/msm8226-v1-qrd.dts
+++ b/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts
@@ -13,13 +13,21 @@
/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,msm-id = <145 11 0>,
- <158 11 0>,
- <159 11 0>,
- <198 11 0>,
- <205 11 0>;
+ 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";
+ };
};
diff --git a/arch/arm/boot/dts/msm8226-v2-qrd.dts b/arch/arm/boot/dts/msm8226-v2-qrd-dvt.dts
similarity index 70%
copy from arch/arm/boot/dts/msm8226-v2-qrd.dts
copy to arch/arm/boot/dts/msm8226-v2-qrd-dvt.dts
index ad6d154..f35e2e4 100644
--- a/arch/arm/boot/dts/msm8226-v2-qrd.dts
+++ b/arch/arm/boot/dts/msm8226-v2-qrd-dvt.dts
@@ -14,13 +14,20 @@
/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";
+ };
};
diff --git a/arch/arm/boot/dts/msm8226-v2-qrd.dts b/arch/arm/boot/dts/msm8226-v2-qrd-evt.dts
similarity index 85%
rename from arch/arm/boot/dts/msm8226-v2-qrd.dts
rename to arch/arm/boot/dts/msm8226-v2-qrd-evt.dts
index ad6d154..3b09d92 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,9 @@
<198 11 0x20000>,
<205 11 0x20000>;
};
+
+&soc {
+ qcom,mdss_dsi_nt35590_720p_video {
+ status = "ok";
+ };
+};
diff --git a/arch/arm/boot/dts/msm8226-v2-qrd.dts b/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts
similarity index 69%
copy from arch/arm/boot/dts/msm8226-v2-qrd.dts
copy to arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts
index ad6d154..1c43589 100644
--- a/arch/arm/boot/dts/msm8226-v2-qrd.dts
+++ b/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts
@@ -13,14 +13,22 @@
/dts-v1/;
/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";
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,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";
+ };
};
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index b14a406..527a582 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -30,6 +30,12 @@
label = "secure_mem";
};
+ adsp_mem: adsp_region {
+ linux,contiguous-region;
+ reg = <0 0x2000000>;
+ label = "adsp_mem";
+ };
+
qsecom_mem: qsecom_region {
linux,contiguous-region;
reg = <0 0x780000>;
@@ -260,11 +266,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 {
@@ -302,7 +309,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>;
@@ -502,15 +509,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>;
@@ -518,16 +529,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 {
@@ -714,6 +716,18 @@
qcom,pmic-arb-channel = <0>;
};
+ i2c@f9925000 { /* BLSP-1 QUP-3 */
+ cell-index = <2>;
+ compatible = "qcom,i2c-qup";
+ reg = <0xf9925000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ interrupts = <0 97 0>;
+ interrupt-names = "qup_err_intr";
+ qcom,i2c-bus-freq = <400000>;
+ qcom,i2c-src-freq = <19200000>;
+ };
i2c@f9926000 { /* BLSP-1 QUP-4 */
cell-index = <0>;
compatible = "qcom,i2c-qup";
diff --git a/arch/arm/boot/dts/msm8610-cdp.dts b/arch/arm/boot/dts/msm8610-cdp.dts
index 6891b90..6b61317 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dts
+++ b/arch/arm/boot/dts/msm8610-cdp.dts
@@ -149,12 +149,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 +171,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{
diff --git a/arch/arm/boot/dts/msm8610-coresight.dtsi b/arch/arm/boot/dts/msm8610-coresight.dtsi
index 516522e..7cf6c4f 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";
diff --git a/arch/arm/boot/dts/msm8610-mtp.dts b/arch/arm/boot/dts/msm8610-mtp.dts
index ddbe3a0..27381e2 100644
--- a/arch/arm/boot/dts/msm8610-mtp.dts
+++ b/arch/arm/boot/dts/msm8610-mtp.dts
@@ -149,7 +149,7 @@
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>;
@@ -171,6 +171,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{
diff --git a/arch/arm/boot/dts/msm8610-qrd.dts b/arch/arm/boot/dts/msm8610-qrd.dts
index 7b45194..4a2c57c 100644
--- a/arch/arm/boot/dts/msm8610-qrd.dts
+++ b/arch/arm/boot/dts/msm8610-qrd.dts
@@ -65,11 +65,11 @@
interrupts = <81 0x2>;
vdd-supply = <&pm8110_l19>;
vio-supply = <&pm8110_l14>;
- kionix,min_interval = <5>;
- kionix,init_interval = <200>;
- kionix,axis_map_x = <1>;
- kionix,axis_map_y = <0>;
- kionix,axis_map_z = <2>;
+ kionix,min-interval = <5>;
+ kionix,init-interval = <200>;
+ kionix,axis-map-x = <1>;
+ kionix,axis-map-y = <0>;
+ kionix,axis-map-z = <2>;
kionix,g-range = <2>;
kionix,negate-x;
kionix,negate-y;
diff --git a/arch/arm/boot/dts/msm8610-regulator.dtsi b/arch/arm/boot/dts/msm8610-regulator.dtsi
index 09520c5..0d47e5d 100644
--- a/arch/arm/boot/dts/msm8610-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8610-regulator.dtsi
@@ -96,6 +96,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 +121,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";
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index ad0980c..b99e6f8 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -772,6 +772,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 {
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-dragonboard.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-dragonboard.dtsi
index 31f3a90..b9f2125 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-dragonboard.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-dragonboard.dtsi
@@ -36,6 +36,8 @@
qcom,mount-angle = <0>;
qcom,actuator-src = <&actuator0>;
qcom,sensor-name = "s5k3l1yx";
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs3>;
@@ -73,6 +75,8 @@
qcom,csid-sd-index = <0>;
qcom,mount-angle = <0>;
qcom,sensor-name = "imx135";
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
qcom,actuator-src = <&actuator1>;
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
@@ -111,6 +115,8 @@
qcom,csid-sd-index = <0>;
qcom,mount-angle = <180>;
qcom,sensor-name = "ov2720";
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs3>;
@@ -146,6 +152,8 @@
qcom,csid-sd-index = <0>;
qcom,mount-angle = <0>;
qcom,sensor-name = "mt9m114";
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs3>;
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index 2a60df4..bcdaf1b 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -48,6 +48,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>;
@@ -406,6 +407,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-coresight.dtsi b/arch/arm/boot/dts/msm8974-coresight.dtsi
index 9fee2e5..e41adac 100644
--- a/arch/arm/boot/dts/msm8974-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8974-coresight.dtsi
@@ -379,4 +379,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..638e6dd 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -43,6 +43,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>;
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index 2dc52b6..ddf5b60 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -813,7 +813,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..46bb71a 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>,
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index 28111fa..4af48cc 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -43,6 +43,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>;
diff --git a/arch/arm/boot/dts/msm8974-regulator.dtsi b/arch/arm/boot/dts/msm8974-regulator.dtsi
index 7c191fc..d9d5aaa 100644
--- a/arch/arm/boot/dts/msm8974-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974-regulator.dtsi
@@ -468,6 +468,7 @@
#size-cells = <1>;
ranges;
qcom,pfm-threshold = <73>;
+ qcom,use-phase-scaling-factor;
krait0_vreg: regulator@f9088000 {
compatible = "qcom,krait-regulator";
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-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.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 068f581..89cbc4c 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -585,11 +585,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 {
@@ -819,11 +819,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 +854,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 +872,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 +1100,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 +1109,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 {
@@ -1369,6 +1369,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";
@@ -1518,8 +1524,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>;
diff --git a/arch/arm/boot/dts/msm8226-v2-qrd.dts b/arch/arm/boot/dts/msm8974pro-ab-cdp.dts
similarity index 61%
copy from arch/arm/boot/dts/msm8226-v2-qrd.dts
copy to arch/arm/boot/dts/msm8974pro-ab-cdp.dts
index ad6d154..74bd23d 100644
--- a/arch/arm/boot/dts/msm8226-v2-qrd.dts
+++ b/arch/arm/boot/dts/msm8974pro-ab-cdp.dts
@@ -11,16 +11,18 @@
*/
/dts-v1/;
-/include/ "msm8226-v2.dtsi"
-/include/ "msm8226-qrd.dtsi"
-/include/ "msm8226-camera-sensor-cdp.dtsi"
+
+/include/ "msm8974pro-ab.dtsi"
+/include/ "msm8974-cdp.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>;
+ model = "Qualcomm MSM 8974Pro CDP";
+ compatible = "qcom,msm8974-cdp", "qcom,msm8974", "qcom,cdp";
+ qcom,msm-id = <209 1 0x10000>,
+ <211 1 0x10000>,
+ <212 1 0x10000>,
+ <214 1 0x10000>,
+ <215 1 0x10000>,
+ <217 1 0x10000>,
+ <218 1 0x10000>;
};
diff --git a/arch/arm/boot/dts/apq8026-xpm.dts b/arch/arm/boot/dts/msm8974pro-ab-fluid.dts
similarity index 61%
copy from arch/arm/boot/dts/apq8026-xpm.dts
copy to arch/arm/boot/dts/msm8974pro-ab-fluid.dts
index 67152af..9a31834 100644
--- a/arch/arm/boot/dts/apq8026-xpm.dts
+++ b/arch/arm/boot/dts/msm8974pro-ab-fluid.dts
@@ -10,13 +10,19 @@
* GNU General Public License for more details.
*/
-
/dts-v1/;
-/include/ "apq8026.dtsi"
-/include/ "msm8226-cdp.dtsi"
+
+/include/ "msm8974pro-ab.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 8974Pro FLUID";
+ compatible = "qcom,msm8974-fluid", "qcom,msm8974", "qcom,fluid";
+ qcom,msm-id = <209 3 0x10000>,
+ <211 3 0x10000>,
+ <212 3 0x10000>,
+ <214 3 0x10000>,
+ <215 3 0x10000>,
+ <217 3 0x10000>,
+ <218 3 0x10000>;
};
diff --git a/arch/arm/boot/dts/msm8226-v2-qrd.dts b/arch/arm/boot/dts/msm8974pro-ab-liquid.dts
similarity index 60%
copy from arch/arm/boot/dts/msm8226-v2-qrd.dts
copy to arch/arm/boot/dts/msm8974pro-ab-liquid.dts
index ad6d154..0ec9d8a 100644
--- a/arch/arm/boot/dts/msm8226-v2-qrd.dts
+++ b/arch/arm/boot/dts/msm8974pro-ab-liquid.dts
@@ -11,16 +11,18 @@
*/
/dts-v1/;
-/include/ "msm8226-v2.dtsi"
-/include/ "msm8226-qrd.dtsi"
-/include/ "msm8226-camera-sensor-cdp.dtsi"
+
+/include/ "msm8974pro-ab.dtsi"
+/include/ "msm8974-liquid.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>;
+ model = "Qualcomm MSM 8974Pro LIQUID";
+ compatible = "qcom,msm8974-liquid", "qcom,msm8974", "qcom,liquid";
+ qcom,msm-id = <209 9 0x10000>,
+ <211 9 0x10000>,
+ <212 9 0x10000>,
+ <214 9 0x10000>,
+ <215 9 0x10000>,
+ <217 9 0x10000>,
+ <218 9 0x10000>;
};
diff --git a/arch/arm/boot/dts/msm8226-v2-qrd.dts b/arch/arm/boot/dts/msm8974pro-ab-mtp.dts
similarity index 61%
copy from arch/arm/boot/dts/msm8226-v2-qrd.dts
copy to arch/arm/boot/dts/msm8974pro-ab-mtp.dts
index ad6d154..002baf7 100644
--- a/arch/arm/boot/dts/msm8226-v2-qrd.dts
+++ b/arch/arm/boot/dts/msm8974pro-ab-mtp.dts
@@ -11,16 +11,18 @@
*/
/dts-v1/;
-/include/ "msm8226-v2.dtsi"
-/include/ "msm8226-qrd.dtsi"
-/include/ "msm8226-camera-sensor-cdp.dtsi"
+
+/include/ "msm8974pro-ab.dtsi"
+/include/ "msm8974-mtp.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>;
+ model = "Qualcomm MSM 8974Pro MTP";
+ compatible = "qcom,msm8974-mtp", "qcom,msm8974", "qcom,mtp";
+ qcom,msm-id = <209 8 0x10000>,
+ <211 8 0x10000>,
+ <212 8 0x10000>,
+ <214 8 0x10000>,
+ <215 8 0x10000>,
+ <217 8 0x10000>,
+ <218 8 0x10000>;
};
diff --git a/arch/arm/boot/dts/apq8026-xpm.dts b/arch/arm/boot/dts/msm8974pro-ab.dtsi
similarity index 69%
copy from arch/arm/boot/dts/apq8026-xpm.dts
copy to arch/arm/boot/dts/msm8974pro-ab.dtsi
index 67152af..9240514 100644
--- a/arch/arm/boot/dts/apq8026-xpm.dts
+++ b/arch/arm/boot/dts/msm8974pro-ab.dtsi
@@ -10,13 +10,10 @@
* GNU General Public License for more details.
*/
+/*
+ * As a general rule, only chipset-specific property overrides should be placed
+ * inside this file. However, device definitions should be placed inside the
+ * msm8974.dtsi / msm8974pro.dtsi file(s).
+ */
-/dts-v1/;
-/include/ "apq8026.dtsi"
-/include/ "msm8226-cdp.dtsi"
-
-/ {
- model = "Qualcomm APQ 8026 XPM";
- compatible = "qcom,apq8026-xpm", "qcom,apq8026", "qcom,xpm";
- qcom,msm-id = <199 14 0>;
-};
+/include/ "msm8974pro.dtsi"
diff --git a/arch/arm/boot/dts/apq8026-mtp.dts b/arch/arm/boot/dts/msm8974pro-ac-mtp.dts
similarity index 67%
copy from arch/arm/boot/dts/apq8026-mtp.dts
copy to arch/arm/boot/dts/msm8974pro-ac-mtp.dts
index e14a6856..c5042b7 100644
--- a/arch/arm/boot/dts/apq8026-mtp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ac-mtp.dts
@@ -10,13 +10,16 @@
* GNU General Public License for more details.
*/
-
/dts-v1/;
-/include/ "apq8026.dtsi"
-/include/ "msm8226-mtp.dtsi"
+
+/include/ "msm8974pro-ac.dtsi"
+/include/ "msm8974-mtp.dtsi"
/ {
- model = "Qualcomm APQ 8026 MTP";
- compatible = "qcom,apq8026-mtp", "qcom,apq8026", "qcom,mtp";
- qcom,msm-id = <199 8 0>;
+ model = "Qualcomm MSM 8974Pro-AC MTP";
+ compatible = "qcom,msm8974-mtp", "qcom,msm8974", "qcom,mtp";
+ qcom,msm-id = <194 8 0x10000>,
+ <210 8 0x10000>,
+ <213 8 0x10000>,
+ <216 8 0x10000>;
};
diff --git a/arch/arm/boot/dts/apq8026-xpm.dts b/arch/arm/boot/dts/msm8974pro-ac.dtsi
similarity index 69%
copy from arch/arm/boot/dts/apq8026-xpm.dts
copy to arch/arm/boot/dts/msm8974pro-ac.dtsi
index 67152af..9240514 100644
--- a/arch/arm/boot/dts/apq8026-xpm.dts
+++ b/arch/arm/boot/dts/msm8974pro-ac.dtsi
@@ -10,13 +10,10 @@
* GNU General Public License for more details.
*/
+/*
+ * As a general rule, only chipset-specific property overrides should be placed
+ * inside this file. However, device definitions should be placed inside the
+ * msm8974.dtsi / msm8974pro.dtsi file(s).
+ */
-/dts-v1/;
-/include/ "apq8026.dtsi"
-/include/ "msm8226-cdp.dtsi"
-
-/ {
- model = "Qualcomm APQ 8026 XPM";
- compatible = "qcom,apq8026-xpm", "qcom,apq8026", "qcom,xpm";
- qcom,msm-id = <199 14 0>;
-};
+/include/ "msm8974pro.dtsi"
diff --git a/arch/arm/boot/dts/msm8974pro.dtsi b/arch/arm/boot/dts/msm8974pro.dtsi
new file mode 100644
index 0000000..96e78ac
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974pro.dtsi
@@ -0,0 +1,138 @@
+/* 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.dtsi"
+/include/ "msm8974-v2-iommu.dtsi"
+/include/ "msm8974-v2-iommu-domains.dtsi"
+/include/ "msm8974-v2-pm.dtsi"
+
+&soc {
+ android_usb@fe8050c8 {
+ compatible = "qcom,android-usb";
+ reg = <0xfe8050c8 0xc8>;
+ qcom,android-usb-swfi-latency = <1>;
+ };
+
+ qcom,msm-imem@fe805000 {
+ compatible = "qcom,msm-imem";
+ reg = <0xfe805000 0x1000>; /* Address and size of IMEM */
+ };
+};
+
+/* GPU overrides */
+&msm_gpu {
+ /* Updated chip ID */
+ qcom,chipid = <0x03030001>;
+
+ /* 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>;
+};
+
+&mdss_mdp {
+ qcom,vbif-settings = <0x0004 0x00000001>;
+
+ qcom,mdss-wb-off = <0x00011100 0x00011500
+ 0x00011900 0x00011D00 0x00012100>;
+ qcom,mdss-intf-off = <0x00012500 0x00012700
+ 0x00012900 0x00012b00>;
+ qcom,mdss-pingpong-off = <0x00012D00 0x00012E00 0x00012F00>;
+ qcom,mdss-has-bwc;
+ qcom,mdss-has-decimation;
+ qcom,mdss-ad-off = <0x0013100 0x00013300>;
+};
+
+&mdss_hdmi_tx {
+ reg = <0xfd922100 0x370>,
+ <0xfd922500 0x7C>,
+ <0xfc4b8000 0x60F0>;
+ reg-names = "core_physical", "phy_physical", "qfprom_physical";
+};
+
+&msm_vidc {
+ qcom,vidc-ns-map = <0x40000000 0x40000000>;
+ qcom,load-freq-tbl = <979200 465000000>,
+ <783360 465000000>,
+ <489600 266670000>,
+ <244800 133330000>;
+ qcom,reg-presets = <0x80004 0x1>,
+ <0x80070 0x11FFF>,
+ <0x80074 0xA4>,
+ <0x800A8 0x1FFF>,
+ <0x80124 0x3>,
+ <0xE0020 0x5555556>,
+ <0xE0024 0x0>;
+ qcom,bus-ports = <1>;
+ qcom,enc-ocmem-ab-ib = <0 0>,
+ <138000 1034000>,
+ <414000 1034000>,
+ <940000 1034000>,
+ <1880000 2068000>,
+ <3008000 3309000>,
+ <3760000 4136000>,
+ <4468000 2457000>;
+ qcom,dec-ocmem-ab-ib = <0 0>,
+ <176000 519000>,
+ <456000 519000>,
+ <864000 519000>,
+ <1728000 1038000>,
+ <2766000 1661000>,
+ <3456000 2076000>,
+ <3662000 2198000>;
+ qcom,enc-ddr-ab-ib = <0 0>,
+ <120000 302000>,
+ <364000 302000>,
+ <804000 302000>,
+ <1608000 604000>,
+ <2576000 967000>,
+ <4680000 1404000>,
+ <49880000 1496000>;
+ qcom,dec-ddr-ab-ib = <0 0>,
+ <208000 303000>,
+ <536000 303000>,
+ <1012000 303000>,
+ <2024000 606000>,
+ <3240000 970000>,
+ <4048000 1212000>,
+ <4264000 1279000>;
+ qcom,iommu-groups = <&venus_domain_ns &venus_domain_sec_bitstream
+ &venus_domain_sec_pixel &venus_domain_sec_non_pixel>;
+ qcom,iommu-group-buffer-types = <0xfff 0x91 0x42 0x120>;
+ qcom,buffer-type-tz-usage-table = <0x91 0x1>,
+ <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.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index 616995f..638ab6b 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -195,6 +195,7 @@
hsic,consider-ipa-handshake;
hsic,log2-itc = <3>;
qcom,ahb-async-bridge-bypass;
+ hsic,disable-cerr;
};
qcom,usbbam@f9a44000 {
@@ -748,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>;
@@ -758,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 {
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..e743989 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,85 @@
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;
+ };
+ };
+
+ qcom,bam_dmux@fc834000 {
+ compatible = "qcom,bam_dmux";
+ reg = <0xfc834000 0x7000>;
+ interrupts = <0 29 1>;
+ qcom,rx-ring-size = <64>;
+ };
};
diff --git a/arch/arm/configs/apq8084_defconfig b/arch/arm/configs/apq8084_defconfig
index 9cd37d1..2965607 100644
--- a/arch/arm/configs/apq8084_defconfig
+++ b/arch/arm/configs/apq8084_defconfig
@@ -399,3 +399,8 @@
CONFIG_CRYPTO_DEV_QCE=m
CONFIG_CRYPTO_DEV_QCEDEV=m
CONFIG_CRC_CCITT=y
+CONFIG_CORESIGHT=y
+CONFIG_CORESIGHT_TMC=y
+CONFIG_CORESIGHT_FUNNEL=y
+CONFIG_CORESIGHT_REPLICATOR=y
+CONFIG_CORESIGHT_STM=y
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
index 4a5c9a7..f618297 100644
--- a/arch/arm/configs/msm8226-perf_defconfig
+++ b/arch/arm/configs/msm8226-perf_defconfig
@@ -292,6 +292,7 @@
CONFIG_MSM_ISPIF=y
CONFIG_MSMB_CAMERA=y
CONFIG_OV9724=y
+CONFIG_MT9M114=y
CONFIG_MSMB_JPEG=y
CONFIG_MSM_VIDC_V4L2=y
CONFIG_MSM_WFD=y
@@ -398,20 +399,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..e249d81 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -295,6 +295,7 @@
CONFIG_MSM_ISPIF=y
CONFIG_MSMB_CAMERA=y
CONFIG_OV9724=y
+CONFIG_MT9M114=y
CONFIG_MSMB_JPEG=y
CONFIG_MSM_VIDC_V4L2=y
CONFIG_MSM_WFD=y
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index 07f7ed9..010bc10 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -384,3 +384,4 @@
CONFIG_CRC_CCITT=y
CONFIG_INPUT_KXTJ9=y
CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
+CONFIG_SENSORS_STK3X1X=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 34c0905..7225ec5 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -427,3 +427,4 @@
CONFIG_CRC_CCITT=y
CONFIG_INPUT_KXTJ9=y
CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
+CONFIG_SENSORS_STK3X1X=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index cdf4263..a26d8e6 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -398,8 +398,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..8447dd55 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -404,8 +404,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 +454,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
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/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index e0f9e8a..174a576 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -528,6 +528,7 @@
select ARM_HAS_SG_CHAIN
select MSM_RUN_QUEUE_STATS
select ARCH_WANT_KMAP_ATOMIC_FLUSH
+ select QMI_ENCDEC
endmenu
choice
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 17db01e..68e9282 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
@@ -87,7 +87,7 @@
obj-$(CONFIG_MSM_PIL_LPASS_QDSP6V4) += pil-q6v4.o pil-q6v4-lpass.o
obj-$(CONFIG_MSM_PIL_MODEM_QDSP6V4) += pil-q6v4.o pil-q6v4-mss.o
obj-$(CONFIG_MSM_PIL_LPASS_QDSP6V5) += pil-q6v5.o pil-q6v5-lpass.o
-obj-$(CONFIG_MSM_PIL_MSS_QDSP6V5) += pil-q6v5.o pil-q6v5-mss.o
+obj-$(CONFIG_MSM_PIL_MSS_QDSP6V5) += pil-q6v5.o pil-msa.o pil-q6v5-mss.o
obj-$(CONFIG_MSM_PIL_RIVA) += pil-riva.o
obj-$(CONFIG_MSM_PIL_TZAPPS) += pil-tzapps.o
obj-$(CONFIG_MSM_PIL_VIDC) += pil-vidc.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index 3469c66..cdee5b7 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -86,15 +86,21 @@
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-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += apq8026-v2-xpm.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += apq8026-v2-mtp.dtb
# FSM9XXX
zreladdr-$(CONFIG_ARCH_FSM9XXX) := 0x10008000
diff --git a/arch/arm/mach-msm/board-8084.c b/arch/arm/mach-msm/board-8084.c
index 7dc9a90..2a6bbb7 100644
--- a/arch/arm/mach-msm/board-8084.c
+++ b/arch/arm/mach-msm/board-8084.c
@@ -28,6 +28,7 @@
#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"
@@ -84,6 +85,7 @@
*/
void __init apq8084_add_drivers(void)
{
+ msm_smem_init();
msm_init_modem_notifier_list();
msm_smd_init();
msm_clock_init(&msm8084_clock_init_data);
diff --git a/arch/arm/mach-msm/board-8226.c b/arch/arm/mach-msm/board-8226.c
index 39efcd8..5ad6175 100644
--- a/arch/arm/mach-msm/board-8226.c
+++ b/arch/arm/mach-msm/board-8226.c
@@ -44,6 +44,7 @@
#include <mach/msm_smd.h>
#include <mach/rpm-smd.h>
#include <mach/rpm-regulator-smd.h>
+#include <mach/msm_smem.h>
#include <linux/msm_thermal.h>
#include "board-dt.h"
#include "clock.h"
@@ -107,6 +108,7 @@
*/
void __init msm8226_add_drivers(void)
{
+ msm_smem_init();
msm_init_modem_notifier_list();
msm_smd_init();
msm_rpm_driver_init();
diff --git a/arch/arm/mach-msm/board-8610.c b/arch/arm/mach-msm/board-8610.c
index b4d77f1..c6c9d14 100644
--- a/arch/arm/mach-msm/board-8610.c
+++ b/arch/arm/mach-msm/board-8610.c
@@ -45,6 +45,7 @@
#include <mach/msm_smd.h>
#include <mach/rpm-smd.h>
#include <mach/rpm-regulator-smd.h>
+#include <mach/msm_smem.h>
#include <linux/msm_thermal.h>
#include "board-dt.h"
#include "clock.h"
@@ -102,6 +103,7 @@
void __init msm8610_add_drivers(void)
{
+ msm_smem_init();
msm_init_modem_notifier_list();
msm_smd_init();
msm_rpm_driver_init();
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index 771359c..68af757 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -40,6 +40,7 @@
#include <mach/rpm-smd.h>
#include <mach/rpm-regulator-smd.h>
#include <mach/socinfo.h>
+#include <mach/msm_smem.h>
#include "board-dt.h"
#include "clock.h"
#include "devices.h"
@@ -91,6 +92,7 @@
*/
void __init msm8974_add_drivers(void)
{
+ msm_smem_init();
msm_init_modem_notifier_list();
msm_smd_init();
msm_rpm_driver_init();
diff --git a/arch/arm/mach-msm/board-9625.c b/arch/arm/mach-msm/board-9625.c
index 56246dd..fad2efc 100644
--- a/arch/arm/mach-msm/board-9625.c
+++ b/arch/arm/mach-msm/board-9625.c
@@ -39,6 +39,7 @@
#include <mach/rpm-regulator-smd.h>
#include "board-dt.h"
#include <mach/msm_bus_board.h>
+#include <mach/msm_smem.h>
#include "clock.h"
#include "modem_notifier.h"
#include "lpm_resources.h"
@@ -231,6 +232,7 @@
*/
void __init msm9625_add_drivers(void)
{
+ msm_smem_init();
msm_init_modem_notifier_list();
msm_smd_init();
msm_rpm_driver_init();
diff --git a/arch/arm/mach-msm/board-samarium.c b/arch/arm/mach-msm/board-samarium.c
index 574c979..be09b54 100644
--- a/arch/arm/mach-msm/board-samarium.c
+++ b/arch/arm/mach-msm/board-samarium.c
@@ -26,10 +26,13 @@
#include <mach/restart.h>
#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),
@@ -38,6 +41,9 @@
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),
};
static struct clock_init_data msm_dummy_clock_init_data __initdata = {
@@ -50,6 +56,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),
{},
};
@@ -95,6 +103,9 @@
*/
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/clock-8084.c b/arch/arm/mach-msm/clock-8084.c
index bec9f1b4..ef8b5bb 100644
--- a/arch/arm/mach-msm/clock-8084.c
+++ b/arch/arm/mach-msm/clock-8084.c
@@ -341,6 +341,12 @@
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),
@@ -369,6 +375,27 @@
CLK_DUMMY("core_clk", NULL, "fe054000.qcom,iommu", OFF),
CLK_DUMMY("iface_clk", NULL, "fe064000.qcom,iommu", OFF),
CLK_DUMMY("core_clk", NULL, "fe064000.qcom,iommu", OFF),
+
+ /* CoreSight clocks */
+ CLK_DUMMY("core_clk", qdss_clk.c, "fc326000.tmc", OFF),
+ CLK_DUMMY("core_clk", qdss_clk.c, "fc324000.replicator", OFF),
+ CLK_DUMMY("core_clk", qdss_clk.c, "fc325000.tmc", OFF),
+ CLK_DUMMY("core_clk", qdss_clk.c, "fc323000.funnel", OFF),
+ 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, "fc36c000.funnel", OFF),
+ CLK_DUMMY("core_clk", qdss_clk.c, "fc302000.stm", 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),
+ CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc325000.tmc", OFF),
+ CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc323000.funnel", OFF),
+ 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, "fc36c000.funnel", OFF),
+ CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc302000.stm", OFF),
};
struct clock_init_data msm8084_clock_init_data __initdata = {
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index 2a4617d..452bc28 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -2857,7 +2857,6 @@
static struct clk_freq_tbl ftbl_kpss_ahb_clk[] = {
F_GCC(19200000, xo_a_clk, 0, 0, 0),
F_GCC(37500000, gpll0, 16, 0, 0),
- F_GCC(75000000, gpll0, 8, 0, 0),
F_END
};
@@ -2870,7 +2869,6 @@
.c = {
.dbg_name = "kpss_ahb_clk_src",
.ops = &clk_ops_rcg,
- VDD_DIG_FMAX_MAP2(LOW, 37500000, NOMINAL, 75000000),
CLK_INIT(kpss_ahb_clk_src.c),
},
};
@@ -3378,10 +3376,10 @@
/* 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_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"),
/* CCI clocks */
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index bd5a12e..4b8fb45 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);
@@ -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,
@@ -4432,6 +4456,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},
@@ -4956,6 +4982,8 @@
CLK_LOOKUP("iface_clk", gcc_sdcc1_ahb_clk.c, "msm_sdcc.1"),
CLK_LOOKUP("core_clk", gcc_sdcc1_apps_clk.c, "msm_sdcc.1"),
+ 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"),
CLK_LOOKUP("iface_clk", gcc_sdcc2_ahb_clk.c, "msm_sdcc.2"),
CLK_LOOKUP("core_clk", gcc_sdcc2_apps_clk.c, "msm_sdcc.2"),
CLK_LOOKUP("iface_clk", gcc_sdcc3_ahb_clk.c, "msm_sdcc.3"),
@@ -5262,6 +5290,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 +5308,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"),
@@ -5535,6 +5563,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.
*/
diff --git a/arch/arm/mach-msm/clock-generic.c b/arch/arm/mach-msm/clock-generic.c
index e66764f..bea82d5 100644
--- a/arch/arm/mach-msm/clock-generic.c
+++ b/arch/arm/mach-msm/clock-generic.c
@@ -266,6 +266,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 +305,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 +313,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 +321,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 +395,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-pll.c b/arch/arm/mach-msm/clock-pll.c
index 908107e..69c3751 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,
};
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/cpufreq.c b/arch/arm/mach-msm/cpufreq.c
index 2e70c83..231a7e0 100644
--- a/arch/arm/mach-msm/cpufreq.c
+++ b/arch/arm/mach-msm/cpufreq.c
@@ -402,8 +402,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/hsic_sysmon.c b/arch/arm/mach-msm/hsic_sysmon.c
index 8270197..79fb1a3 100644
--- a/arch/arm/mach-msm/hsic_sysmon.c
+++ b/arch/arm/mach-msm/hsic_sysmon.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
@@ -239,7 +239,7 @@
if (!hs)
continue;
- ret += scnprintf(buf, DEBUG_BUF_SIZE,
+ ret += scnprintf(buf + ret, DEBUG_BUF_SIZE - ret,
"---HSIC Sysmon #%d---\n"
"epin:%d, epout:%d\n"
"bytes to host: %d\n"
@@ -324,15 +324,6 @@
struct usb_endpoint_descriptor *ep_desc;
int i;
int ret = -ENOMEM;
- __u8 ifc_num;
-
- pr_debug("id:%lu", id->driver_info);
-
- ifc_num = ifc->cur_altsetting->desc.bInterfaceNumber;
-
- /* is this the interface we're looking for? */
- if (ifc_num != id->driver_info)
- return -ENODEV;
hs = kzalloc(sizeof(*hs), GFP_KERNEL);
if (!hs) {
@@ -367,12 +358,17 @@
goto error;
}
- hs->id = HSIC_SYSMON_DEV_EXT_MODEM;
- hsic_sysmon_devices[HSIC_SYSMON_DEV_EXT_MODEM] = hs;
+ hs->id = HSIC_SYSMON_DEV_EXT_MODEM + id->driver_info;
+ if (hs->id >= NUM_HSIC_SYSMON_DEVS) {
+ pr_warn("invalid dev id(%d)", hs->id);
+ hs->id = 0;
+ }
+
+ hsic_sysmon_devices[hs->id] = hs;
usb_set_intfdata(ifc, hs);
hs->pdev.name = "sys_mon";
- hs->pdev.id = SYSMON_SS_EXT_MODEM;
+ hs->pdev.id = SYSMON_SS_EXT_MODEM + hs->id;
hs->pdev.dev.release = hsic_sysmon_pdev_release;
platform_device_register(&hs->pdev);
@@ -406,11 +402,12 @@
return 0;
}
-/* driver_info maps to the interface number corresponding to sysmon */
+/* driver_info is the instance number when multiple devices are present */
static const struct usb_device_id hsic_sysmon_ids[] = {
- { USB_DEVICE(0x5c6, 0x9048), .driver_info = 1, },
- { USB_DEVICE(0x5c6, 0x904C), .driver_info = 1, },
- { USB_DEVICE(0x5c6, 0x9075), .driver_info = 1, },
+ { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9048, 1), .driver_info = 0, },
+ { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x904C, 1), .driver_info = 0, },
+ { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9075, 1), .driver_info = 0, },
+ { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9079, 1), .driver_info = 1, },
{} /* terminating entry */
};
MODULE_DEVICE_TABLE(usb, hsic_sysmon_ids);
diff --git a/arch/arm/mach-msm/hsic_sysmon.h b/arch/arm/mach-msm/hsic_sysmon.h
index 983f464..9655dc0 100644
--- a/arch/arm/mach-msm/hsic_sysmon.h
+++ b/arch/arm/mach-msm/hsic_sysmon.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
@@ -18,6 +18,7 @@
*/
enum hsic_sysmon_device_id {
HSIC_SYSMON_DEV_EXT_MODEM,
+ HSIC_SYSMON_DEV_EXT_MODEM_2,
NUM_HSIC_SYSMON_DEVS
};
diff --git a/arch/arm/mach-msm/hsic_sysmon_test.c b/arch/arm/mach-msm/hsic_sysmon_test.c
index bc60c6e..fac6575 100644
--- a/arch/arm/mach-msm/hsic_sysmon_test.c
+++ b/arch/arm/mach-msm/hsic_sysmon_test.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
@@ -15,6 +15,7 @@
#include <linux/slab.h>
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/device.h>
#include <linux/debugfs.h>
#include <linux/uaccess.h>
@@ -36,13 +37,14 @@
size_t count, loff_t *ppos)
{
struct sysmon_test_dev *dev = sysmon_dev;
+ enum hsic_sysmon_device_id id =
+ (enum hsic_sysmon_device_id)file->private_data;
int ret;
if (!dev)
return -ENODEV;
- ret = hsic_sysmon_read(HSIC_SYSMON_DEV_EXT_MODEM, dev->buf, RD_BUF_SIZE,
- &dev->buflen, 3000);
+ ret = hsic_sysmon_read(id, dev->buf, RD_BUF_SIZE, &dev->buflen, 3000);
if (!ret)
return simple_read_from_buffer(ubuf, count, ppos,
dev->buf, dev->buflen);
@@ -53,7 +55,9 @@
static ssize_t sysmon_test_write(struct file *file, const char __user *ubuf,
size_t count, loff_t *ppos)
{
- struct sysmon_test_dev *dev = sysmon_dev;
+ struct sysmon_test_dev *dev = sysmon_dev;
+ enum hsic_sysmon_device_id id =
+ (enum hsic_sysmon_device_id)file->private_data;
int ret;
if (!dev)
@@ -64,8 +68,7 @@
return 0;
}
- ret = hsic_sysmon_write(HSIC_SYSMON_DEV_EXT_MODEM,
- dev->buf, count, 1000);
+ ret = hsic_sysmon_write(id, dev->buf, count, 1000);
if (ret < 0) {
pr_err("error writing to hsic_sysmon");
return ret;
@@ -76,38 +79,44 @@
static int sysmon_test_open(struct inode *inode, struct file *file)
{
- return hsic_sysmon_open(HSIC_SYSMON_DEV_EXT_MODEM);
+ file->private_data = inode->i_private;
+ return hsic_sysmon_open((enum hsic_sysmon_device_id)inode->i_private);
}
static int sysmon_test_release(struct inode *inode, struct file *file)
{
- hsic_sysmon_close(HSIC_SYSMON_DEV_EXT_MODEM);
+ hsic_sysmon_close((enum hsic_sysmon_device_id)inode->i_private);
return 0;
}
-static struct dentry *dfile;
-const struct file_operations sysmon_test_ops = {
+static const struct file_operations sysmon_test_ops = {
.read = sysmon_test_read,
.write = sysmon_test_write,
.open = sysmon_test_open,
.release = sysmon_test_release
};
+static struct dentry *dfile0, *dfile1;
+
static int __init sysmon_test_init(void)
{
sysmon_dev = kzalloc(sizeof(*sysmon_dev), GFP_KERNEL);
if (!sysmon_dev)
return -ENOMEM;
- dfile = debugfs_create_file("hsic_sysmon_test", 0666, NULL,
- 0, &sysmon_test_ops);
+ dfile0 = debugfs_create_file("hsic_sysmon_test.0", 0666, NULL,
+ (void *)HSIC_SYSMON_DEV_EXT_MODEM, &sysmon_test_ops);
+ dfile1 = debugfs_create_file("hsic_sysmon_test.1", 0666, NULL,
+ (void *)HSIC_SYSMON_DEV_EXT_MODEM_2, &sysmon_test_ops);
return 0;
}
static void __exit sysmon_test_exit(void)
{
- if (dfile)
- debugfs_remove(dfile);
+ if (dfile0)
+ debugfs_remove(dfile0);
+ if (dfile1)
+ debugfs_remove(dfile1);
kfree(sysmon_dev);
}
diff --git a/arch/arm/mach-msm/include/mach/clk-provider.h b/arch/arm/mach-msm/include/mach/clk-provider.h
index 27c6df4..1fad7f6 100644
--- a/arch/arm/mach-msm/include/mach/clk-provider.h
+++ b/arch/arm/mach-msm/include/mach/clk-provider.h
@@ -108,7 +108,9 @@
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);
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..c979e0c 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];
diff --git a/arch/arm/mach-msm/include/mach/ipa.h b/arch/arm/mach-msm/include/mach/ipa.h
index 697de5e..b6acef2 100644
--- a/arch/arm/mach-msm/include/mach/ipa.h
+++ b/arch/arm/mach-msm/include/mach/ipa.h
@@ -648,6 +648,8 @@
int a2_mux_write(enum a2_mux_logical_channel_id lcid, struct sk_buff *skb);
+int a2_mux_is_ch_empty(enum a2_mux_logical_channel_id lcid);
+
int a2_mux_is_ch_low(enum a2_mux_logical_channel_id lcid);
int a2_mux_is_ch_full(enum a2_mux_logical_channel_id lcid);
@@ -667,6 +669,8 @@
int teth_bridge_set_aggr_params(struct teth_aggr_params *aggr_params);
+void ipa_bam_reg_dump(void);
+
#else /* CONFIG_IPA */
static inline int a2_mux_open_channel(enum a2_mux_logical_channel_id lcid,
@@ -686,6 +690,11 @@
return -EPERM;
}
+static inline int a2_mux_is_ch_empty(enum a2_mux_logical_channel_id lcid)
+{
+ return -EPERM;
+}
+
static inline int a2_mux_is_ch_low(enum a2_mux_logical_channel_id lcid)
{
return -EPERM;
@@ -1099,6 +1108,11 @@
return -EPERM;
}
+static inline void ipa_bam_reg_dump(void)
+{
+ return;
+}
+
#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/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_smd.h b/arch/arm/mach-msm/include/mach/msm_smd.h
index 2cc7b10..62fada1 100644
--- a/arch/arm/mach-msm/include/mach/msm_smd.h
+++ b/arch/arm/mach-msm/include/mach/msm_smd.h
@@ -134,25 +134,10 @@
int disable_smsm_reset_handshake;
};
-/*
- * Shared Memory Regions
- *
- * the array of these regions is expected to be in ascending order by phys_addr
- *
- * @phys_addr: physical base address of the region
- * @size: size of the region in bytes
- */
-struct smd_smem_regions {
- phys_addr_t phys_addr;
- resource_size_t size;
-};
-
struct smd_platform {
uint32_t num_ss_configs;
struct smd_subsystem_config *smd_ss_configs;
struct smd_subsystem_restart_config *smd_ssr_config;
- uint32_t num_smem_areas;
- struct smd_smem_regions *smd_smem_areas;
};
#ifdef CONFIG_MSM_SMD
@@ -322,24 +307,6 @@
*/
int smd_is_pkt_avail(smd_channel_t *ch);
-/**
- * smd_module_init_notifier_register() - Register a smd module
- * init notifier block
- * @nb: Notifier block to be registered
- *
- * In order to mark the dependency on SMD Driver module initialization
- * register a notifier using this API. Once the smd module_init is
- * done, notification will be passed to the registered module.
- */
-int smd_module_init_notifier_register(struct notifier_block *nb);
-
-/**
- * smd_module_init_notifier_register() - Unregister a smd module
- * init notifier block
- * @nb: Notifier block to be registered
- */
-int smd_module_init_notifier_unregister(struct notifier_block *nb);
-
/*
* SMD initialization function that registers for a SMD platform driver.
*
@@ -474,16 +441,6 @@
return -ENODEV;
}
-static inline int smd_module_init_notifier_register(struct notifier_block *nb)
-{
- return -ENODEV;
-}
-
-static inline int smd_module_init_notifier_unregister(struct notifier_block *nb)
-{
- return -ENODEV;
-}
-
static inline int __init msm_smd_init(void)
{
return 0;
diff --git a/arch/arm/mach-msm/include/mach/msm_smem.h b/arch/arm/mach-msm/include/mach/msm_smem.h
index 78d2b00..64ab6bf 100644
--- a/arch/arm/mach-msm/include/mach/msm_smem.h
+++ b/arch/arm/mach-msm/include/mach/msm_smem.h
@@ -169,6 +169,13 @@
*/
phys_addr_t smem_virt_to_phys(void *smem_address);
+/**
+ * SMEM initialization function that registers for a SMEM platform driver.
+ *
+ * @returns: success on successful driver registration.
+ */
+int __init msm_smem_init(void);
+
#else
static inline void *smem_alloc(unsigned id, unsigned size)
{
@@ -194,5 +201,9 @@
{
return (phys_addr_t) NULL;
}
+static int __init msm_smem_init(void)
+{
+ return 0;
+}
#endif /* CONFIG_MSM_SMD */
#endif /* _ARCH_ARM_MACH_MSM_SMEM_H_ */
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 d52686c..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")
@@ -115,6 +116,9 @@
MSM_CPU_7X27AA,
MSM_CPU_9615,
MSM_CPU_8974,
+ MSM_CPU_8974PRO_AA,
+ MSM_CPU_8974PRO_AB,
+ MSM_CPU_8974PRO_AC,
MSM_CPU_8627,
MSM_CPU_8625,
MSM_CPU_9625,
@@ -434,6 +438,42 @@
#endif
}
+static inline int cpu_is_msm8974pro_aa(void)
+{
+#ifdef CONFIG_ARCH_MSM8974
+ enum msm_cpu cpu = socinfo_get_msm_cpu();
+
+ BUG_ON(cpu == MSM_CPU_UNKNOWN);
+ return cpu == MSM_CPU_8974PRO_AA;
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_msm8974pro_ab(void)
+{
+#ifdef CONFIG_ARCH_MSM8974
+ enum msm_cpu cpu = socinfo_get_msm_cpu();
+
+ BUG_ON(cpu == MSM_CPU_UNKNOWN);
+ return cpu == MSM_CPU_8974PRO_AB;
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_msm8974pro_ac(void)
+{
+#ifdef CONFIG_ARCH_MSM8974
+ enum msm_cpu cpu = socinfo_get_msm_cpu();
+
+ BUG_ON(cpu == MSM_CPU_UNKNOWN);
+ return cpu == MSM_CPU_8974PRO_AC;
+#else
+ return 0;
+#endif
+}
+
static inline int cpu_is_mpq8092(void)
{
#ifdef CONFIG_ARCH_MPQ8092
@@ -499,4 +539,10 @@
cpu_is_msm8627();
}
+static inline int soc_class_is_msm8974(void)
+{
+ return cpu_is_msm8974() || cpu_is_msm8974pro_aa() ||
+ cpu_is_msm8974pro_ab() || cpu_is_msm8974pro_ac();
+}
+
#endif
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..aba5fee 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;
}
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/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/perf_debug.c b/arch/arm/mach-msm/perf_debug.c
index 70420db..643d945 100644
--- a/arch/arm/mach-msm/perf_debug.c
+++ b/arch/arm/mach-msm/perf_debug.c
@@ -32,6 +32,7 @@
"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"
;
static ssize_t desc_read(struct file *fp, char __user *buf,
diff --git a/arch/arm/mach-msm/pil-msa.c b/arch/arm/mach-msm/pil-msa.c
new file mode 100644
index 0000000..a8f5b0e
--- /dev/null
+++ b/arch/arm/mach-msm/pil-msa.c
@@ -0,0 +1,407 @@
+/* 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/io.h>
+#include <linux/iopoll.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/regulator/consumer.h>
+#include <linux/dma-mapping.h>
+
+#include "peripheral-loader.h"
+#include "pil-q6v5.h"
+#include "pil-msa.h"
+
+/* Q6 Register Offsets */
+#define QDSP6SS_RST_EVB 0x010
+
+/* AXI Halting Registers */
+#define MSS_Q6_HALT_BASE 0x180
+#define MSS_MODEM_HALT_BASE 0x200
+#define MSS_NC_HALT_BASE 0x280
+
+/* RMB Status Register Values */
+#define STATUS_PBL_SUCCESS 0x1
+#define STATUS_XPU_UNLOCKED 0x1
+#define STATUS_XPU_UNLOCKED_SCRIBBLED 0x2
+
+/* PBL/MBA interface registers */
+#define RMB_MBA_IMAGE 0x00
+#define RMB_PBL_STATUS 0x04
+#define RMB_MBA_COMMAND 0x08
+#define RMB_MBA_STATUS 0x0C
+#define RMB_PMI_META_DATA 0x10
+#define RMB_PMI_CODE_START 0x14
+#define RMB_PMI_CODE_LENGTH 0x18
+
+#define MAX_VDD_MX_UV 1150000
+
+#define POLL_INTERVAL_US 50
+
+#define CMD_META_DATA_READY 0x1
+#define CMD_LOAD_READY 0x2
+
+#define STATUS_META_DATA_AUTH_SUCCESS 0x3
+#define STATUS_AUTH_COMPLETE 0x4
+
+/* External BHS */
+#define EXTERNAL_BHS_ON BIT(0)
+#define EXTERNAL_BHS_STATUS BIT(4)
+#define BHS_TIMEOUT_US 50
+
+static int pbl_mba_boot_timeout_ms = 1000;
+module_param(pbl_mba_boot_timeout_ms, int, S_IRUGO | S_IWUSR);
+
+static int modem_auth_timeout_ms = 10000;
+module_param(modem_auth_timeout_ms, int, S_IRUGO | S_IWUSR);
+
+static int pil_msa_pbl_power_up(struct q6v5_data *drv)
+{
+ int ret = 0;
+ struct device *dev = drv->desc.dev;
+ u32 regval;
+
+ if (drv->vreg) {
+ ret = regulator_enable(drv->vreg);
+ if (ret)
+ dev_err(dev, "Failed to enable modem regulator.\n");
+ }
+
+ if (drv->cxrail_bhs) {
+ regval = readl_relaxed(drv->cxrail_bhs);
+ regval |= EXTERNAL_BHS_ON;
+ writel_relaxed(regval, drv->cxrail_bhs);
+
+ ret = readl_poll_timeout(drv->cxrail_bhs, regval,
+ regval & EXTERNAL_BHS_STATUS, 1, BHS_TIMEOUT_US);
+ }
+
+ return ret;
+}
+
+static int pil_msa_pbl_power_down(struct q6v5_data *drv)
+{
+ u32 regval;
+
+ if (drv->cxrail_bhs) {
+ regval = readl_relaxed(drv->cxrail_bhs);
+ regval &= ~EXTERNAL_BHS_ON;
+ writel_relaxed(regval, drv->cxrail_bhs);
+ }
+
+ if (drv->vreg)
+ return regulator_disable(drv->vreg);
+
+ return 0;
+}
+
+static int pil_msa_pbl_enable_clks(struct q6v5_data *drv)
+{
+ int ret;
+
+ ret = clk_prepare_enable(drv->ahb_clk);
+ if (ret)
+ goto err_ahb_clk;
+ ret = clk_prepare_enable(drv->axi_clk);
+ if (ret)
+ goto err_axi_clk;
+ ret = clk_prepare_enable(drv->rom_clk);
+ if (ret)
+ goto err_rom_clk;
+
+ return 0;
+
+err_rom_clk:
+ clk_disable_unprepare(drv->axi_clk);
+err_axi_clk:
+ clk_disable_unprepare(drv->ahb_clk);
+err_ahb_clk:
+ return ret;
+}
+
+static void pil_msa_pbl_disable_clks(struct q6v5_data *drv)
+{
+ clk_disable_unprepare(drv->rom_clk);
+ clk_disable_unprepare(drv->axi_clk);
+ clk_disable_unprepare(drv->ahb_clk);
+}
+
+static int pil_msa_wait_for_mba_ready(struct q6v5_data *drv)
+{
+ struct device *dev = drv->desc.dev;
+ int ret;
+ u32 status;
+
+ /* Wait for PBL completion. */
+ ret = readl_poll_timeout(drv->rmb_base + RMB_PBL_STATUS, status,
+ status != 0, POLL_INTERVAL_US, pbl_mba_boot_timeout_ms * 1000);
+ if (ret) {
+ dev_err(dev, "PBL boot timed out\n");
+ return ret;
+ }
+ if (status != STATUS_PBL_SUCCESS) {
+ dev_err(dev, "PBL returned unexpected status %d\n", status);
+ return -EINVAL;
+ }
+
+ /* Wait for MBA completion. */
+ ret = readl_poll_timeout(drv->rmb_base + RMB_MBA_STATUS, status,
+ status != 0, POLL_INTERVAL_US, pbl_mba_boot_timeout_ms * 1000);
+ if (ret) {
+ dev_err(dev, "MBA boot timed out\n");
+ return ret;
+ }
+ if (status != STATUS_XPU_UNLOCKED &&
+ status != STATUS_XPU_UNLOCKED_SCRIBBLED) {
+ dev_err(dev, "MBA returned unexpected status %d\n", status);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int pil_msa_pbl_shutdown(struct pil_desc *pil)
+{
+ struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
+
+ pil_q6v5_halt_axi_port(pil, drv->axi_halt_base + MSS_Q6_HALT_BASE);
+ pil_q6v5_halt_axi_port(pil, drv->axi_halt_base + MSS_MODEM_HALT_BASE);
+ pil_q6v5_halt_axi_port(pil, drv->axi_halt_base + MSS_NC_HALT_BASE);
+
+ writel_relaxed(1, drv->restart_reg);
+
+ if (drv->is_booted) {
+ pil_msa_pbl_disable_clks(drv);
+ pil_msa_pbl_power_down(drv);
+ drv->is_booted = false;
+ }
+
+ return 0;
+}
+
+static int pil_msa_pbl_reset(struct pil_desc *pil)
+{
+ struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
+ phys_addr_t start_addr = pil_get_entry_addr(pil);
+ int ret;
+
+ /*
+ * Bring subsystem out of reset and enable required
+ * regulators and clocks.
+ */
+ ret = pil_msa_pbl_power_up(drv);
+ if (ret)
+ goto err_power;
+
+ /* Deassert reset to subsystem and wait for propagation */
+ writel_relaxed(0, drv->restart_reg);
+ mb();
+ udelay(2);
+
+ ret = pil_msa_pbl_enable_clks(drv);
+ if (ret)
+ goto err_clks;
+
+ /* Program Image Address */
+ if (drv->self_auth) {
+ writel_relaxed(start_addr, drv->rmb_base + RMB_MBA_IMAGE);
+ /* Ensure write to RMB base occurs before reset is released. */
+ mb();
+ } else {
+ writel_relaxed((start_addr >> 4) & 0x0FFFFFF0,
+ drv->reg_base + QDSP6SS_RST_EVB);
+ }
+
+ ret = pil_q6v5_reset(pil);
+ if (ret)
+ goto err_q6v5_reset;
+
+ /* Wait for MBA to start. Check for PBL and MBA errors while waiting. */
+ if (drv->self_auth) {
+ ret = pil_msa_wait_for_mba_ready(drv);
+ if (ret)
+ goto err_auth;
+ }
+
+ drv->is_booted = true;
+
+ return 0;
+
+err_auth:
+ pil_q6v5_shutdown(pil);
+err_q6v5_reset:
+ pil_msa_pbl_disable_clks(drv);
+err_clks:
+ pil_msa_pbl_power_down(drv);
+err_power:
+ return ret;
+}
+
+static int pil_msa_pbl_make_proxy_votes(struct pil_desc *pil)
+{
+ int ret;
+ struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
+
+ ret = regulator_set_voltage(drv->vreg_mx, VDD_MSS_UV, MAX_VDD_MX_UV);
+ if (ret) {
+ dev_err(pil->dev, "Failed to request vreg_mx voltage\n");
+ return ret;
+ }
+
+ ret = regulator_enable(drv->vreg_mx);
+ if (ret) {
+ dev_err(pil->dev, "Failed to enable vreg_mx\n");
+ regulator_set_voltage(drv->vreg_mx, 0, MAX_VDD_MX_UV);
+ return ret;
+ }
+
+ ret = pil_q6v5_make_proxy_votes(pil);
+ if (ret) {
+ regulator_disable(drv->vreg_mx);
+ regulator_set_voltage(drv->vreg_mx, 0, MAX_VDD_MX_UV);
+ }
+
+ return ret;
+}
+
+static void pil_msa_pbl_remove_proxy_votes(struct pil_desc *pil)
+{
+ struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
+ pil_q6v5_remove_proxy_votes(pil);
+ regulator_disable(drv->vreg_mx);
+ regulator_set_voltage(drv->vreg_mx, 0, MAX_VDD_MX_UV);
+}
+
+struct pil_reset_ops pil_msa_pbl_ops = {
+ .proxy_vote = pil_msa_pbl_make_proxy_votes,
+ .proxy_unvote = pil_msa_pbl_remove_proxy_votes,
+ .auth_and_reset = pil_msa_pbl_reset,
+ .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)
+{
+ struct mba_data *drv = container_of(pil, struct mba_data, desc);
+ void *mdata_virt;
+ dma_addr_t mdata_phys;
+ s32 status;
+ int ret;
+
+ /* Make metadata physically contiguous and 4K aligned. */
+ mdata_virt = dma_alloc_coherent(pil->dev, size, &mdata_phys,
+ GFP_KERNEL);
+ if (!mdata_virt) {
+ dev_err(pil->dev, "MBA metadata buffer allocation failed\n");
+ return -ENOMEM;
+ }
+ memcpy(mdata_virt, metadata, size);
+ /* wmb() ensures copy completes prior to starting authentication. */
+ wmb();
+
+ /* Initialize length counter to 0 */
+ writel_relaxed(0, drv->rmb_base + RMB_PMI_CODE_LENGTH);
+
+ /* Pass address of meta-data to the MBA and perform authentication */
+ writel_relaxed(mdata_phys, drv->rmb_base + RMB_PMI_META_DATA);
+ writel_relaxed(CMD_META_DATA_READY, drv->rmb_base + RMB_MBA_COMMAND);
+ ret = readl_poll_timeout(drv->rmb_base + RMB_MBA_STATUS, status,
+ status == STATUS_META_DATA_AUTH_SUCCESS || status < 0,
+ POLL_INTERVAL_US, modem_auth_timeout_ms * 1000);
+ if (ret) {
+ dev_err(pil->dev, "MBA authentication of headers timed out\n");
+ } else if (status < 0) {
+ dev_err(pil->dev, "MBA returned error %d for headers\n",
+ status);
+ ret = -EINVAL;
+ }
+
+ dma_free_coherent(pil->dev, size, mdata_virt, mdata_phys);
+
+ return ret;
+}
+
+static int pil_msa_mba_verify_blob(struct pil_desc *pil, phys_addr_t phy_addr,
+ size_t size)
+{
+ struct mba_data *drv = container_of(pil, struct mba_data, desc);
+ s32 status;
+ u32 img_length = readl_relaxed(drv->rmb_base + RMB_PMI_CODE_LENGTH);
+
+ /* Begin image authentication */
+ if (img_length == 0) {
+ writel_relaxed(phy_addr, drv->rmb_base + RMB_PMI_CODE_START);
+ writel_relaxed(CMD_LOAD_READY, drv->rmb_base + RMB_MBA_COMMAND);
+ }
+ /* Increment length counter */
+ img_length += size;
+ writel_relaxed(img_length, drv->rmb_base + RMB_PMI_CODE_LENGTH);
+
+ status = readl_relaxed(drv->rmb_base + RMB_MBA_STATUS);
+ if (status < 0) {
+ dev_err(pil->dev, "MBA returned error %d\n", status);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int pil_msa_mba_auth(struct pil_desc *pil)
+{
+ struct mba_data *drv = container_of(pil, struct mba_data, desc);
+ int ret;
+ s32 status;
+
+ /* Wait for all segments to be authenticated or an error to occur */
+ ret = readl_poll_timeout(drv->rmb_base + RMB_MBA_STATUS, status,
+ status == STATUS_AUTH_COMPLETE || status < 0,
+ 50, modem_auth_timeout_ms * 1000);
+ if (ret) {
+ dev_err(pil->dev, "MBA authentication of image timed out\n");
+ } else if (status < 0) {
+ dev_err(pil->dev, "MBA returned error %d for image\n", status);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+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-msa.h b/arch/arm/mach-msm/pil-msa.h
new file mode 100644
index 0000000..9a7b56e
--- /dev/null
+++ b/arch/arm/mach-msm/pil-msa.h
@@ -0,0 +1,29 @@
+/* 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 __MSM_PIL_MSA_H
+#define __MSM_PIL_MSA_H
+
+#include "peripheral-loader.h"
+
+#define VDD_MSS_UV 1050000
+
+struct mba_data {
+ void __iomem *rmb_base;
+ struct clk *xo;
+ struct pil_desc desc;
+};
+
+extern struct pil_reset_ops pil_msa_pbl_ops;
+extern struct pil_reset_ops pil_msa_mba_ops;
+
+#endif
diff --git a/arch/arm/mach-msm/pil-pronto.c b/arch/arm/mach-msm/pil-pronto.c
index 1085408..80c0862 100644
--- a/arch/arm/mach-msm/pil-pronto.c
+++ b/arch/arm/mach-msm/pil-pronto.c
@@ -336,6 +336,7 @@
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);
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
index b83202b..4d76c08 100644
--- a/arch/arm/mach-msm/pil-q6v5-mss.c
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -35,64 +35,21 @@
#include "peripheral-loader.h"
#include "pil-q6v5.h"
+#include "pil-msa.h"
#include "sysmon.h"
-/* Q6 Register Offsets */
-#define QDSP6SS_RST_EVB 0x010
+#define MAX_VDD_MSS_UV 1150000
+#define PROXY_TIMEOUT_MS 10000
+#define MAX_SSR_REASON_LEN 81U
+#define STOP_ACK_TIMEOUT_MS 1000
-/* AXI Halting Registers */
-#define MSS_Q6_HALT_BASE 0x180
-#define MSS_MODEM_HALT_BASE 0x200
-#define MSS_NC_HALT_BASE 0x280
-
-/* RMB Status Register Values */
-#define STATUS_PBL_SUCCESS 0x1
-#define STATUS_XPU_UNLOCKED 0x1
-#define STATUS_XPU_UNLOCKED_SCRIBBLED 0x2
-
-/* PBL/MBA interface registers */
-#define RMB_MBA_IMAGE 0x00
-#define RMB_PBL_STATUS 0x04
-#define RMB_MBA_COMMAND 0x08
-#define RMB_MBA_STATUS 0x0C
-#define RMB_PMI_META_DATA 0x10
-#define RMB_PMI_CODE_START 0x14
-#define RMB_PMI_CODE_LENGTH 0x18
-
-#define VDD_MSS_UV 1050000
-#define MAX_VDD_MSS_UV 1150000
-#define MAX_VDD_MX_UV 1150000
-
-#define PROXY_TIMEOUT_MS 10000
-#define POLL_INTERVAL_US 50
-
-#define CMD_META_DATA_READY 0x1
-#define CMD_LOAD_READY 0x2
-
-#define STATUS_META_DATA_AUTH_SUCCESS 0x3
-#define STATUS_AUTH_COMPLETE 0x4
-
-#define MAX_SSR_REASON_LEN 81U
-
-/* External BHS */
-#define EXTERNAL_BHS_ON BIT(0)
-#define EXTERNAL_BHS_STATUS BIT(4)
-#define BHS_TIMEOUT_US 50
-
-#define STOP_ACK_TIMEOUT_MS 1000
-
-struct mba_data {
- void __iomem *rmb_base;
- void __iomem *io_clamp_reg;
- struct pil_desc desc;
+struct modem_data {
+ struct mba_data *mba;
+ struct q6v5_data *q6;
struct subsys_device *subsys;
struct subsys_desc subsys_desc;
void *adsp_state_notifier;
- u32 img_length;
- struct q6v5_data *q6;
- bool self_auth;
void *ramdump_dev;
- void *smem_ramdump_dev;
bool crash_shutdown;
bool ignore_errors;
int err_fatal_irq;
@@ -101,363 +58,16 @@
struct completion stop_ack;
};
-static int pbl_mba_boot_timeout_ms = 1000;
-module_param(pbl_mba_boot_timeout_ms, int, S_IRUGO | S_IWUSR);
-
-static int modem_auth_timeout_ms = 10000;
-module_param(modem_auth_timeout_ms, int, S_IRUGO | S_IWUSR);
-
-static int pil_mss_power_up(struct q6v5_data *drv)
-{
- int ret = 0;
- struct device *dev = drv->desc.dev;
- u32 regval;
-
- if (drv->vreg) {
- ret = regulator_enable(drv->vreg);
- if (ret)
- dev_err(dev, "Failed to enable modem regulator.\n");
- }
-
- if (drv->cxrail_bhs) {
- regval = readl_relaxed(drv->cxrail_bhs);
- regval |= EXTERNAL_BHS_ON;
- writel_relaxed(regval, drv->cxrail_bhs);
-
- ret = readl_poll_timeout(drv->cxrail_bhs, regval,
- regval & EXTERNAL_BHS_STATUS, 1, BHS_TIMEOUT_US);
- }
-
- return ret;
-}
-
-static int pil_mss_power_down(struct q6v5_data *drv)
-{
- u32 regval;
-
- if (drv->cxrail_bhs) {
- regval = readl_relaxed(drv->cxrail_bhs);
- regval &= ~EXTERNAL_BHS_ON;
- writel_relaxed(regval, drv->cxrail_bhs);
- }
-
- if (drv->vreg)
- return regulator_disable(drv->vreg);
-
- return 0;
-}
-
-static int pil_mss_enable_clks(struct q6v5_data *drv)
-{
- int ret;
-
- ret = clk_prepare_enable(drv->ahb_clk);
- if (ret)
- goto err_ahb_clk;
- ret = clk_prepare_enable(drv->axi_clk);
- if (ret)
- goto err_axi_clk;
- ret = clk_prepare_enable(drv->rom_clk);
- if (ret)
- goto err_rom_clk;
-
- return 0;
-
-err_rom_clk:
- clk_disable_unprepare(drv->axi_clk);
-err_axi_clk:
- clk_disable_unprepare(drv->ahb_clk);
-err_ahb_clk:
- return ret;
-}
-
-static void pil_mss_disable_clks(struct q6v5_data *drv)
-{
- clk_disable_unprepare(drv->rom_clk);
- clk_disable_unprepare(drv->axi_clk);
- clk_disable_unprepare(drv->ahb_clk);
-}
-
-static int wait_for_mba_ready(struct q6v5_data *drv)
-{
- struct device *dev = drv->desc.dev;
- struct mba_data *mba = platform_get_drvdata(to_platform_device(dev));
- int ret;
- u32 status;
-
- /* Wait for PBL completion. */
- ret = readl_poll_timeout(mba->rmb_base + RMB_PBL_STATUS, status,
- status != 0, POLL_INTERVAL_US, pbl_mba_boot_timeout_ms * 1000);
- if (ret) {
- dev_err(dev, "PBL boot timed out\n");
- return ret;
- }
- if (status != STATUS_PBL_SUCCESS) {
- dev_err(dev, "PBL returned unexpected status %d\n", status);
- return -EINVAL;
- }
-
- /* Wait for MBA completion. */
- ret = readl_poll_timeout(mba->rmb_base + RMB_MBA_STATUS, status,
- status != 0, POLL_INTERVAL_US, pbl_mba_boot_timeout_ms * 1000);
- if (ret) {
- dev_err(dev, "MBA boot timed out\n");
- return ret;
- }
- if (status != STATUS_XPU_UNLOCKED &&
- status != STATUS_XPU_UNLOCKED_SCRIBBLED) {
- dev_err(dev, "MBA returned unexpected status %d\n", status);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int pil_mss_shutdown(struct pil_desc *pil)
-{
- struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
-
- pil_q6v5_halt_axi_port(pil, drv->axi_halt_base + MSS_Q6_HALT_BASE);
- pil_q6v5_halt_axi_port(pil, drv->axi_halt_base + MSS_MODEM_HALT_BASE);
- pil_q6v5_halt_axi_port(pil, drv->axi_halt_base + MSS_NC_HALT_BASE);
-
- writel_relaxed(1, drv->restart_reg);
-
- if (drv->is_booted) {
- pil_mss_disable_clks(drv);
- pil_mss_power_down(drv);
- drv->is_booted = false;
- }
-
- return 0;
-}
-
-static int pil_mss_reset(struct pil_desc *pil)
-{
- struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
- struct platform_device *pdev = to_platform_device(pil->dev);
- struct mba_data *mba = platform_get_drvdata(pdev);
- phys_addr_t start_addr = pil_get_entry_addr(pil);
- int ret;
-
- /*
- * Bring subsystem out of reset and enable required
- * regulators and clocks.
- */
- ret = pil_mss_power_up(drv);
- if (ret)
- goto err_power;
-
- /* Deassert reset to subsystem and wait for propagation */
- writel_relaxed(0, drv->restart_reg);
- mb();
- udelay(2);
-
- ret = pil_mss_enable_clks(drv);
- if (ret)
- goto err_clks;
-
- /* Program Image Address */
- if (mba->self_auth) {
- writel_relaxed(start_addr, mba->rmb_base + RMB_MBA_IMAGE);
- /* Ensure write to RMB base occurs before reset is released. */
- mb();
- } else {
- writel_relaxed((start_addr >> 4) & 0x0FFFFFF0,
- drv->reg_base + QDSP6SS_RST_EVB);
- }
-
- ret = pil_q6v5_reset(pil);
- if (ret)
- goto err_q6v5_reset;
-
- /* Wait for MBA to start. Check for PBL and MBA errors while waiting. */
- if (mba->self_auth) {
- ret = wait_for_mba_ready(drv);
- if (ret)
- goto err_auth;
- }
-
- drv->is_booted = true;
-
- return 0;
-
-err_auth:
- pil_q6v5_shutdown(pil);
-err_q6v5_reset:
- pil_mss_disable_clks(drv);
-err_clks:
- pil_mss_power_down(drv);
-err_power:
- return ret;
-}
-
-static int pil_q6v5_mss_make_proxy_votes(struct pil_desc *pil)
-{
- int ret;
- struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
-
- ret = regulator_set_voltage(drv->vreg_mx, VDD_MSS_UV, MAX_VDD_MX_UV);
- if (ret) {
- dev_err(pil->dev, "Failed to request vreg_mx voltage\n");
- return ret;
- }
-
- ret = regulator_enable(drv->vreg_mx);
- if (ret) {
- dev_err(pil->dev, "Failed to enable vreg_mx\n");
- regulator_set_voltage(drv->vreg_mx, 0, MAX_VDD_MX_UV);
- return ret;
- }
-
- ret = pil_q6v5_make_proxy_votes(pil);
- if (ret) {
- regulator_disable(drv->vreg_mx);
- regulator_set_voltage(drv->vreg_mx, 0, MAX_VDD_MX_UV);
- }
-
- return ret;
-}
-
-static void pil_q6v5_mss_remove_proxy_votes(struct pil_desc *pil)
-{
- struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
- pil_q6v5_remove_proxy_votes(pil);
- regulator_disable(drv->vreg_mx);
- regulator_set_voltage(drv->vreg_mx, 0, MAX_VDD_MX_UV);
-}
-
-static struct pil_reset_ops pil_mss_ops = {
- .proxy_vote = pil_q6v5_mss_make_proxy_votes,
- .proxy_unvote = pil_q6v5_mss_remove_proxy_votes,
- .auth_and_reset = pil_mss_reset,
- .shutdown = pil_mss_shutdown,
-};
-
-static int pil_mba_make_proxy_votes(struct pil_desc *pil)
-{
- int ret;
- struct mba_data *drv = dev_get_drvdata(pil->dev);
-
- ret = clk_prepare_enable(drv->q6->xo);
- if (ret) {
- dev_err(pil->dev, "Failed to enable XO\n");
- return ret;
- }
- return 0;
-}
-
-static void pil_mba_remove_proxy_votes(struct pil_desc *pil)
-{
- struct mba_data *drv = dev_get_drvdata(pil->dev);
- clk_disable_unprepare(drv->q6->xo);
-}
-
-static int pil_mba_init_image(struct pil_desc *pil,
- const u8 *metadata, size_t size)
-{
- struct mba_data *drv = dev_get_drvdata(pil->dev);
- void *mdata_virt;
- dma_addr_t mdata_phys;
- s32 status;
- int ret;
-
- /* Make metadata physically contiguous and 4K aligned. */
- mdata_virt = dma_alloc_coherent(pil->dev, size, &mdata_phys,
- GFP_KERNEL);
- if (!mdata_virt) {
- dev_err(pil->dev, "MBA metadata buffer allocation failed\n");
- return -ENOMEM;
- }
- memcpy(mdata_virt, metadata, size);
- /* wmb() ensures copy completes prior to starting authentication. */
- wmb();
-
- /* Initialize length counter to 0 */
- writel_relaxed(0, drv->rmb_base + RMB_PMI_CODE_LENGTH);
- drv->img_length = 0;
-
- /* Pass address of meta-data to the MBA and perform authentication */
- writel_relaxed(mdata_phys, drv->rmb_base + RMB_PMI_META_DATA);
- writel_relaxed(CMD_META_DATA_READY, drv->rmb_base + RMB_MBA_COMMAND);
- ret = readl_poll_timeout(drv->rmb_base + RMB_MBA_STATUS, status,
- status == STATUS_META_DATA_AUTH_SUCCESS || status < 0,
- POLL_INTERVAL_US, modem_auth_timeout_ms * 1000);
- if (ret) {
- dev_err(pil->dev, "MBA authentication of headers timed out\n");
- } else if (status < 0) {
- dev_err(pil->dev, "MBA returned error %d for headers\n",
- status);
- ret = -EINVAL;
- }
-
- dma_free_coherent(pil->dev, size, mdata_virt, mdata_phys);
-
- return ret;
-}
-
-static int pil_mba_verify_blob(struct pil_desc *pil, phys_addr_t phy_addr,
- size_t size)
-{
- struct mba_data *drv = dev_get_drvdata(pil->dev);
- s32 status;
-
- /* Begin image authentication */
- if (drv->img_length == 0) {
- writel_relaxed(phy_addr, drv->rmb_base + RMB_PMI_CODE_START);
- writel_relaxed(CMD_LOAD_READY, drv->rmb_base + RMB_MBA_COMMAND);
- }
- /* Increment length counter */
- drv->img_length += size;
- writel_relaxed(drv->img_length, drv->rmb_base + RMB_PMI_CODE_LENGTH);
-
- status = readl_relaxed(drv->rmb_base + RMB_MBA_STATUS);
- if (status < 0) {
- dev_err(pil->dev, "MBA returned error %d\n", status);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int pil_mba_auth(struct pil_desc *pil)
-{
- struct mba_data *drv = dev_get_drvdata(pil->dev);
- int ret;
- s32 status;
-
- /* Wait for all segments to be authenticated or an error to occur */
- ret = readl_poll_timeout(drv->rmb_base + RMB_MBA_STATUS, status,
- status == STATUS_AUTH_COMPLETE || status < 0,
- 50, modem_auth_timeout_ms * 1000);
- if (ret) {
- dev_err(pil->dev, "MBA authentication of image timed out\n");
- } else if (status < 0) {
- dev_err(pil->dev, "MBA returned error %d for image\n", status);
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-static struct pil_reset_ops pil_mba_ops = {
- .init_image = pil_mba_init_image,
- .proxy_vote = pil_mba_make_proxy_votes,
- .proxy_unvote = pil_mba_remove_proxy_votes,
- .verify_blob = pil_mba_verify_blob,
- .auth_and_reset = pil_mba_auth,
-};
-
-#define subsys_to_drv(d) container_of(d, struct mba_data, subsys_desc)
+#define subsys_to_drv(d) container_of(d, struct modem_data, subsys_desc)
static void log_modem_sfr(void)
{
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]) {
@@ -472,7 +82,7 @@
wmb();
}
-static void restart_modem(struct mba_data *drv)
+static void restart_modem(struct modem_data *drv)
{
log_modem_sfr();
drv->ignore_errors = true;
@@ -481,7 +91,7 @@
static irqreturn_t modem_err_fatal_intr_handler(int irq, void *dev_id)
{
- struct mba_data *drv = dev_id;
+ struct modem_data *drv = dev_id;
/* Ignore if we're the one that set the force stop GPIO */
if (drv->crash_shutdown)
@@ -495,7 +105,7 @@
static irqreturn_t modem_stop_ack_intr_handler(int irq, void *dev_id)
{
- struct mba_data *drv = dev_id;
+ struct modem_data *drv = dev_id;
pr_info("Received stop ack interrupt from modem\n");
complete(&drv->stop_ack);
return IRQ_HANDLED;
@@ -503,7 +113,7 @@
static int modem_shutdown(const struct subsys_desc *subsys)
{
- struct mba_data *drv = subsys_to_drv(subsys);
+ struct modem_data *drv = subsys_to_drv(subsys);
unsigned long ret;
if (subsys->is_not_loadable)
@@ -518,14 +128,14 @@
gpio_set_value(drv->force_stop_gpio, 0);
}
- pil_shutdown(&drv->desc);
+ pil_shutdown(&drv->mba->desc);
pil_shutdown(&drv->q6->desc);
return 0;
}
static int modem_powerup(const struct subsys_desc *subsys)
{
- struct mba_data *drv = subsys_to_drv(subsys);
+ struct modem_data *drv = subsys_to_drv(subsys);
int ret;
if (subsys->is_not_loadable)
@@ -535,12 +145,12 @@
* 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)
return ret;
- ret = pil_boot(&drv->desc);
+ ret = pil_boot(&drv->mba->desc);
if (ret)
pil_shutdown(&drv->q6->desc);
return ret;
@@ -548,7 +158,7 @@
static void modem_crash_shutdown(const struct subsys_desc *subsys)
{
- struct mba_data *drv = subsys_to_drv(subsys);
+ 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);
@@ -556,13 +166,9 @@
}
}
-static struct ramdump_segment smem_segments[] = {
- {0x0FA00000, 0x0FC00000 - 0x0FA00000},
-};
-
static int modem_ramdump(int enable, const struct subsys_desc *subsys)
{
- struct mba_data *drv = subsys_to_drv(subsys);
+ struct modem_data *drv = subsys_to_drv(subsys);
int ret;
if (!enable)
@@ -572,20 +178,10 @@
if (ret)
return ret;
- ret = pil_do_ramdump(&drv->desc, drv->ramdump_dev);
- if (ret < 0) {
+ ret = pil_do_ramdump(&drv->mba->desc, drv->ramdump_dev);
+ 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;
}
@@ -606,7 +202,7 @@
static irqreturn_t modem_wdog_bite_irq(int irq, void *dev_id)
{
- struct mba_data *drv = dev_id;
+ struct modem_data *drv = dev_id;
if (drv->ignore_errors)
return IRQ_HANDLED;
pr_err("Watchdog bite received from modem software!\n");
@@ -618,16 +214,16 @@
static int mss_start(const struct subsys_desc *desc)
{
int ret;
- struct mba_data *drv = subsys_to_drv(desc);
+ struct modem_data *drv = subsys_to_drv(desc);
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;
- ret = pil_boot(&drv->desc);
+ ret = pil_boot(&drv->mba->desc);
if (ret)
pil_shutdown(&drv->q6->desc);
return ret;
@@ -635,16 +231,16 @@
static void mss_stop(const struct subsys_desc *desc)
{
- struct mba_data *drv = subsys_to_drv(desc);
+ struct modem_data *drv = subsys_to_drv(desc);
if (desc->is_not_loadable)
return;
- pil_shutdown(&drv->desc);
+ pil_shutdown(&drv->mba->desc);
pil_shutdown(&drv->q6->desc);
}
-static int __devinit pil_subsys_init(struct mba_data *drv,
+static int __devinit pil_subsys_init(struct modem_data *drv,
struct platform_device *pdev)
{
int irq, ret;
@@ -688,14 +284,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) {
@@ -731,8 +319,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);
@@ -740,10 +326,11 @@
return ret;
}
-static int __devinit pil_mss_loadable_init(struct mba_data *drv,
+static int __devinit pil_mss_loadable_init(struct modem_data *drv,
struct platform_device *pdev)
{
struct q6v5_data *q6;
+ struct mba_data *mba;
struct pil_desc *q6_desc, *mba_desc;
struct resource *res;
struct property *prop;
@@ -758,25 +345,32 @@
if (clk_ready < 0)
return clk_ready;
+ mba = devm_kzalloc(&pdev->dev, sizeof(*mba), GFP_KERNEL);
+ if (IS_ERR(mba))
+ return PTR_ERR(mba);
+ drv->mba = mba;
+
q6 = pil_q6v5_init(pdev);
if (IS_ERR(q6))
return PTR_ERR(q6);
drv->q6 = q6;
+ drv->mba->xo = q6->xo;
q6_desc = &q6->desc;
- q6_desc->ops = &pil_mss_ops;
+ 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;
- drv->self_auth = of_property_read_bool(pdev->dev.of_node,
+ q6->self_auth = of_property_read_bool(pdev->dev.of_node,
"qcom,pil-self-auth");
- if (drv->self_auth) {
+ if (q6->self_auth) {
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"rmb_base");
- drv->rmb_base = devm_request_and_ioremap(&pdev->dev, res);
- if (!drv->rmb_base)
+ q6->rmb_base = devm_request_and_ioremap(&pdev->dev, res);
+ if (!q6->rmb_base)
return -ENOMEM;
+ mba->rmb_base = q6->rmb_base;
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "restart_reg");
@@ -830,10 +424,10 @@
if (ret)
return ret;
- mba_desc = &drv->desc;
+ mba_desc = &mba->desc;
mba_desc->name = "modem";
mba_desc->dev = &pdev->dev;
- mba_desc->ops = &pil_mba_ops;
+ 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;
@@ -852,7 +446,7 @@
static int __devinit pil_mss_driver_probe(struct platform_device *pdev)
{
- struct mba_data *drv;
+ struct modem_data *drv;
int ret, err_fatal_gpio, is_not_loadable, stop_ack_gpio;
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
@@ -870,6 +464,8 @@
return ret;
}
+ init_completion(&drv->stop_ack);
+
/* 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);
@@ -901,14 +497,13 @@
static int __devexit pil_mss_driver_exit(struct platform_device *pdev)
{
- struct mba_data *drv = platform_get_drvdata(pdev);
+ struct modem_data *drv = platform_get_drvdata(pdev);
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->desc);
+ pil_desc_release(&drv->mba->desc);
pil_desc_release(&drv->q6->desc);
return 0;
}
diff --git a/arch/arm/mach-msm/pil-q6v5.h b/arch/arm/mach-msm/pil-q6v5.h
index 48d10df..b2fb7f7 100644
--- a/arch/arm/mach-msm/pil-q6v5.h
+++ b/arch/arm/mach-msm/pil-q6v5.h
@@ -22,6 +22,7 @@
struct q6v5_data {
void __iomem *reg_base;
+ void __iomem *rmb_base;
void __iomem *cxrail_bhs; /* External BHS register */
struct clk *xo; /* XO clock source */
struct clk *ahb_clk; /* PIL access to registers */
@@ -37,6 +38,7 @@
struct regulator *vreg_pll;
bool is_booted;
struct pil_desc desc;
+ bool self_auth;
};
int pil_q6v5_make_proxy_votes(struct pil_desc *pil);
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 146dc0b..dd0599b 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>
@@ -134,7 +133,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,24 +1132,9 @@
pm_sleep_ops = *ops;
}
-int msm_suspend_prepare(void)
-{
- if (pnoc_clk != NULL)
- clk_disable_unprepare(pnoc_clk);
- return 0;
-}
-
-void msm_suspend_wake(void)
-{
- if (pnoc_clk != NULL)
- clk_prepare_enable(pnoc_clk);
-}
-
static const struct platform_suspend_ops msm_pm_ops = {
.enter = msm_pm_enter,
.valid = suspend_valid_only_mem,
- .prepare_late = msm_suspend_prepare,
- .wake = msm_suspend_wake,
};
static int __devinit msm_pm_snoc_client_probe(struct platform_device *pdev)
@@ -1285,14 +1268,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 +1360,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);
+
+ 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 +1402,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 +1698,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/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c
index 38ed867..2bae37a 100644
--- a/arch/arm/mach-msm/rpm-smd.c
+++ b/arch/arm/mach-msm/rpm-smd.c
@@ -60,12 +60,13 @@
spinlock_t smd_lock_write;
spinlock_t smd_lock_read;
struct completion smd_open;
+ struct completion remote_open;
};
#define DEFAULT_BUFFER_SIZE 256
#define DEBUG_PRINT_BUFFER_SIZE 512
#define MAX_SLEEP_BUFFER 128
-
+#define SMD_CHANNEL_NOTIF_TIMEOUT 5000
#define GFP_FLAG(noirq) (noirq ? GFP_ATOMIC : GFP_KERNEL)
#define INV_RSC "resource does not exist"
#define ERR "err\0"
@@ -1303,6 +1304,20 @@
}
EXPORT_SYMBOL(msm_rpm_exit_sleep);
+static int __devinit msm_rpm_smd_remote_probe(struct platform_device *pdev)
+{
+ if (pdev && pdev->id == msm_rpm_data.ch_type)
+ complete(&msm_rpm_data.remote_open);
+ return 0;
+}
+
+static struct platform_driver msm_rpm_smd_remote_driver = {
+ .probe = msm_rpm_smd_remote_probe,
+ .driver = {
+ .owner = THIS_MODULE,
+ },
+};
+
static int __devinit msm_rpm_dev_probe(struct platform_device *pdev)
{
char *key = NULL;
@@ -1323,13 +1338,21 @@
key = "rpm-standalone";
standalone = of_property_read_bool(pdev->dev.of_node, key);
+ msm_rpm_smd_remote_driver.driver.name = msm_rpm_data.ch_name;
+ init_completion(&msm_rpm_data.remote_open);
init_completion(&msm_rpm_data.smd_open);
spin_lock_init(&msm_rpm_data.smd_lock_write);
spin_lock_init(&msm_rpm_data.smd_lock_read);
INIT_WORK(&msm_rpm_data.work, msm_rpm_smd_work);
- if (smd_named_open_on_edge(msm_rpm_data.ch_name, msm_rpm_data.ch_type,
- &msm_rpm_data.ch_info, &msm_rpm_data,
+ platform_driver_register(&msm_rpm_smd_remote_driver);
+ ret = wait_for_completion_timeout(&msm_rpm_data.remote_open,
+ msecs_to_jiffies(SMD_CHANNEL_NOTIF_TIMEOUT));
+
+ if (!ret || smd_named_open_on_edge(msm_rpm_data.ch_name,
+ msm_rpm_data.ch_type,
+ &msm_rpm_data.ch_info,
+ &msm_rpm_data,
msm_rpm_notify)) {
pr_info("Cannot open RPM channel %s %d\n", msm_rpm_data.ch_name,
msm_rpm_data.ch_type);
diff --git a/arch/arm/mach-msm/scm-pas.c b/arch/arm/mach-msm/scm-pas.c
index 4cb43b1..b244c6f 100644
--- a/arch/arm/mach-msm/scm-pas.c
+++ b/arch/arm/mach-msm/scm-pas.c
@@ -268,7 +268,7 @@
rate = clk_round_rate(scm_clocks[CORE_CLK_SRC], 1);
clk_set_rate(scm_clocks[CORE_CLK_SRC], rate);
- if (cpu_is_msm8974() || cpu_is_msm8226() || cpu_is_msm8610()) {
+ 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 {
diff --git a/arch/arm/mach-msm/scm.c b/arch/arm/mach-msm/scm.c
index 6e05177..e9f44e3 100644
--- a/arch/arm/mach-msm/scm.c
+++ b/arch/arm/mach-msm/scm.c
@@ -191,12 +191,12 @@
u32 cmd_addr = virt_to_phys(cmd);
/*
- * Flush the entire cache here so callers don't have to remember
- * to flush the cache when passing physical addresses to the secure
- * side in the buffer.
+ * Flush the command buffer so that the secure world sees
+ * the correct data.
*/
- flush_cache_all();
- outer_flush_all();
+ __cpuc_flush_dcache_area((void *)cmd, cmd->len);
+ outer_flush_range(cmd_addr, cmd_addr + cmd->len);
+
ret = smc(cmd_addr);
if (ret < 0)
ret = scm_remap_error(ret);
@@ -233,6 +233,13 @@
* @resp_len: length of the response buffer
*
* Sends a command to the SCM and waits for the command to finish processing.
+ *
+ * A note on cache maintenance:
+ * Note that any buffers that are expected to be accessed by the secure world
+ * must be flushed before invoking scm_call and invalidated in the cache
+ * immediately after scm_call returns. Cache maintenance on the command and
+ * response buffers is taken care of by scm_call; however, callers are
+ * responsible for any other cached buffers passed over to the secure world.
*/
int scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, size_t cmd_len,
void *resp_buf, size_t resp_len)
diff --git a/arch/arm/mach-msm/smcmod.c b/arch/arm/mach-msm/smcmod.c
index 705bab5..221a522 100644
--- a/arch/arm/mach-msm/smcmod.c
+++ b/arch/arm/mach-msm/smcmod.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
@@ -92,27 +92,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();
-}
-
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)
{
@@ -234,10 +213,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 = 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)) {
@@ -355,45 +342,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 = 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 */
@@ -424,7 +402,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;
@@ -492,6 +469,14 @@
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 = scm_call(SMCMOD_SVC_CRYPTO,
@@ -506,20 +491,9 @@
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 */
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index 4649390..c97ba68 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -176,8 +176,6 @@
},
};
-static void *smd_dev;
-
struct interrupt_stat interrupt_stats[NUM_SMD_SUBSYSTEMS];
#define SMSM_STATE_ADDR(entry) (smsm_info.state + entry)
@@ -381,14 +379,6 @@
static DEFINE_MUTEX(smsm_lock);
static struct smsm_state_info *smsm_states;
-/**
- * Variables to indicate smd module initialization.
- * Dependents to register for smd module init notifier.
- */
-static int smd_module_inited;
-static RAW_NOTIFIER_HEAD(smd_module_init_notifier_list);
-static DEFINE_MUTEX(smd_module_init_notifier_lock);
-static void smd_module_init_notify(uint32_t state, void *data);
static int smd_stream_write_avail(struct smd_channel *ch);
static int smd_stream_read_avail(struct smd_channel *ch);
@@ -708,6 +698,7 @@
uint32_t local_pid;
uint32_t remote_pid;
char subsys_name[SMD_MAX_CH_NAME_LEN];
+ bool initialized;
};
/**
@@ -762,6 +753,11 @@
static int smd_alloc_channel(struct smd_alloc_elm *alloc_elm);
+static bool smd_edge_inited(int edge)
+{
+ return edge_to_pids[edge].initialized;
+}
+
/* on smp systems, the probe might get called from multiple cores,
hence use a lock */
static DEFINE_MUTEX(smd_probe_lock);
@@ -795,6 +791,11 @@
if (!shared[n].name[0])
continue;
+ if (!smd_initialized && !smd_edge_inited(type)) {
+ SMD_INFO("Probe skipping ch %d, edge not inited\n", n);
+ continue;
+ }
+
if (!smd_alloc_channel(&shared[n]))
smd_ch_allocated[n] = 1;
else
@@ -1913,7 +1914,7 @@
struct smd_channel *ch;
unsigned long flags;
- if (smd_initialized == 0) {
+ if (smd_initialized == 0 && !smd_edge_inited(edge)) {
SMD_INFO("smd_open() before smd_init()\n");
return -ENODEV;
}
@@ -2436,16 +2437,23 @@
struct smsm_size_info_type *smsm_size_info;
unsigned long flags;
unsigned long j_start;
+ static int first = 1;
+ remote_spinlock_t *remote_spinlock;
+
+ if (!first)
+ return 0;
+ first = 0;
/* Verify that remote spinlock is not deadlocked */
+ remote_spinlock = smem_get_remote_spinlock();
j_start = jiffies;
- while (!remote_spin_trylock_irqsave(&remote_spinlock, flags)) {
+ while (!remote_spin_trylock_irqsave(remote_spinlock, flags)) {
if (jiffies_to_msecs(jiffies - j_start) > RSPIN_INIT_WAIT_MS) {
panic("%s: Remote processor %d will not release spinlock\n",
- __func__, remote_spin_owner(&remote_spinlock));
+ __func__, remote_spin_owner(remote_spinlock));
}
}
- remote_spin_unlock_irqrestore(&remote_spinlock, flags);
+ remote_spin_unlock_irqrestore(remote_spinlock, flags);
smsm_size_info = smem_alloc(SMEM_SMSM_SIZE_INFO,
sizeof(struct smsm_size_info_type));
@@ -2860,9 +2868,6 @@
int ret;
unsigned long flags;
- if (!smd_initialized)
- return;
-
while (kfifo_len(&smsm_snapshot_fifo) >= SMSM_SNAPSHOT_SIZE) {
mutex_lock(&smsm_lock);
for (n = 0; n < SMSM_NUM_ENTRIES; n++) {
@@ -3084,42 +3089,6 @@
}
EXPORT_SYMBOL(smsm_state_cb_deregister);
-int smd_module_init_notifier_register(struct notifier_block *nb)
-{
- int ret;
- if (!nb)
- return -EINVAL;
- mutex_lock(&smd_module_init_notifier_lock);
- ret = raw_notifier_chain_register(&smd_module_init_notifier_list, nb);
- if (smd_module_inited)
- nb->notifier_call(nb, 0, NULL);
- mutex_unlock(&smd_module_init_notifier_lock);
- return ret;
-}
-EXPORT_SYMBOL(smd_module_init_notifier_register);
-
-int smd_module_init_notifier_unregister(struct notifier_block *nb)
-{
- int ret;
- if (!nb)
- return -EINVAL;
- mutex_lock(&smd_module_init_notifier_lock);
- ret = raw_notifier_chain_unregister(&smd_module_init_notifier_list,
- nb);
- mutex_unlock(&smd_module_init_notifier_lock);
- return ret;
-}
-EXPORT_SYMBOL(smd_module_init_notifier_unregister);
-
-static void smd_module_init_notify(uint32_t state, void *data)
-{
- mutex_lock(&smd_module_init_notifier_lock);
- smd_module_inited = 1;
- raw_notifier_call_chain(&smd_module_init_notifier_list,
- state, data);
- mutex_unlock(&smd_module_init_notifier_lock);
-}
-
int smd_core_init(void)
{
int r;
@@ -3315,9 +3284,6 @@
struct smd_subsystem_config *smd_ss_config_list;
struct smd_subsystem_config *cfg;
int err_ret = 0;
- struct smd_smem_regions *smd_smem_areas;
- struct smem_area *smem_areas_tmp = NULL;
- int smem_idx;
smd_platform_data = pdev->dev.platform_data;
num_ss = smd_platform_data->num_ss_configs;
@@ -3327,57 +3293,6 @@
disable_smsm_reset_handshake = smd_platform_data->
smd_ssr_config->disable_smsm_reset_handshake;
- smd_smem_areas = smd_platform_data->smd_smem_areas;
- num_smem_areas = smd_platform_data->num_smem_areas + 1;
-
- /* Initialize main SMEM region */
- smem_areas_tmp = kmalloc_array(num_smem_areas, sizeof(struct smem_area),
- GFP_KERNEL);
- if (!smem_areas_tmp) {
- pr_err("%s: smem_areas kmalloc failed\n", __func__);
- err_ret = -ENOMEM;
- goto smem_areas_alloc_fail;
- }
-
- smem_areas_tmp[0].phys_addr = msm_shared_ram_phys;
- smem_areas_tmp[0].size = MSM_SHARED_RAM_SIZE;
- smem_areas_tmp[0].virt_addr = MSM_SHARED_RAM_BASE;
-
- /* Configure auxiliary SMEM regions */
- for (smem_idx = 1; smem_idx < num_smem_areas; ++smem_idx) {
- smem_areas_tmp[smem_idx].phys_addr =
- smd_smem_areas[smem_idx].phys_addr;
- smem_areas_tmp[smem_idx].size =
- smd_smem_areas[smem_idx].size;
- smem_areas_tmp[smem_idx].virt_addr = ioremap_nocache(
- (unsigned long)(smem_areas_tmp[smem_idx].phys_addr),
- smem_areas_tmp[smem_idx].size);
- if (!smem_areas_tmp[smem_idx].virt_addr) {
- pr_err("%s: ioremap_nocache() of addr: %pa size: %pa\n",
- __func__,
- &smem_areas_tmp[smem_idx].phys_addr,
- &smem_areas_tmp[smem_idx].size);
- err_ret = -ENOMEM;
- goto smem_failed;
- }
-
- if (OVERFLOW_ADD_UNSIGNED(uintptr_t,
- (uintptr_t)smem_areas_tmp[smem_idx].virt_addr,
- smem_areas_tmp[smem_idx].size)) {
- pr_err("%s: invalid virtual address block %i: %p:%pa\n",
- __func__, smem_idx,
- smem_areas_tmp[smem_idx].virt_addr,
- &smem_areas_tmp[smem_idx].size);
- ++smem_idx;
- err_ret = -EINVAL;
- goto smem_failed;
- }
-
- SMD_DBG("%s: %d = %pa %pa", __func__, smem_idx,
- &smd_smem_areas[smem_idx].phys_addr,
- &smd_smem_areas[smem_idx].size);
- }
-
for (i = 0; i < num_ss; i++) {
cfg = &smd_ss_config_list[i];
@@ -3421,7 +3336,6 @@
SMD_INFO("smd_core_platform_init() done\n");
- smem_areas = smem_areas_tmp;
return 0;
intr_failed:
@@ -3438,19 +3352,105 @@
(void *)cfg->smsm_int.dev_id
);
}
-smem_failed:
- for (smem_idx = smem_idx - 1; smem_idx >= 1; --smem_idx)
- iounmap(smem_areas_tmp[smem_idx].virt_addr);
-
- num_smem_areas = 0;
- kfree(smem_areas_tmp);
-
-smem_areas_alloc_fail:
return err_ret;
}
-static int __devinit parse_smd_devicetree(struct device_node *node,
- void *irq_out_base)
+static int msm_smsm_probe(struct platform_device *pdev)
+{
+ uint32_t edge;
+ char *key;
+ int ret;
+ uint32_t irq_offset;
+ uint32_t irq_bitmask;
+ uint32_t irq_line;
+ struct interrupt_config_item *private_irq;
+ struct device_node *node;
+ void *irq_out_base;
+ resource_size_t irq_out_size;
+ struct platform_device *parent_pdev;
+ struct resource *r;
+
+ disable_smsm_reset_handshake = 1;
+
+ node = pdev->dev.of_node;
+
+ if (!pdev->dev.parent) {
+ pr_err("%s: missing link to parent device\n", __func__);
+ return -ENODEV;
+ }
+
+ 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);
+ irq_out_size = resource_size(r);
+ irq_out_base = ioremap_nocache(r->start, irq_out_size);
+ if (!irq_out_base) {
+ pr_err("%s: ioremap_nocache() of irq_out_base addr:%pr size:%pr\n",
+ __func__, &r->start, &irq_out_size);
+ return -ENOMEM;
+ }
+ SMSM_DBG("%s: %s = %p", __func__, key, irq_out_base);
+
+ key = "qcom,smsm-edge";
+ ret = of_property_read_u32(node, key, &edge);
+ if (ret)
+ goto missing_key;
+ SMSM_DBG("%s: %s = %d", __func__, key, edge);
+
+ key = "qcom,smsm-irq-offset";
+ ret = of_property_read_u32(node, key, &irq_offset);
+ if (ret)
+ goto missing_key;
+ SMSM_DBG("%s: %s = %x", __func__, key, irq_offset);
+
+ key = "qcom,smsm-irq-bitmask";
+ ret = of_property_read_u32(node, key, &irq_bitmask);
+ if (ret)
+ goto missing_key;
+ SMSM_DBG("%s: %s = %x", __func__, key, irq_bitmask);
+
+ key = "interrupts";
+ irq_line = irq_of_parse_and_map(node, 0);
+ if (!irq_line)
+ goto missing_key;
+ SMSM_DBG("%s: %s = %d", __func__, key, irq_line);
+
+ private_irq = &private_intr_config[edge_to_pids[edge].remote_pid].smsm;
+ private_irq->out_bit_pos = irq_bitmask;
+ private_irq->out_offset = irq_offset;
+ private_irq->out_base = irq_out_base;
+ private_irq->irq_id = irq_line;
+
+ ret = request_irq(irq_line,
+ private_irq->irq_handler,
+ IRQF_TRIGGER_RISING,
+ "smsm_dev",
+ NULL);
+ if (ret < 0) {
+ pr_err("%s: request_irq() failed on %d\n", __func__, irq_line);
+ return ret;
+ } else {
+ ret = enable_irq_wake(irq_line);
+ if (ret < 0)
+ pr_err("%s: enable_irq_wake() failed on %d\n", __func__,
+ irq_line);
+ }
+
+ if (smsm_init())
+ pr_err("smsm_init() failed\n");
+
+ smsm_irq_handler(0, 0);
+
+ return 0;
+
+missing_key:
+ pr_err("%s: missing key: %s", __func__, key);
+ return -ENODEV;
+}
+
+static int msm_smd_probe(struct platform_device *pdev)
{
uint32_t edge;
char *key;
@@ -3461,6 +3461,32 @@
unsigned long irq_flags = IRQF_TRIGGER_RISING;
const char *pilstr;
struct interrupt_config_item *private_irq;
+ struct device_node *node;
+ void *irq_out_base;
+ resource_size_t irq_out_size;
+ struct platform_device *parent_pdev;
+ struct resource *r;
+
+ node = pdev->dev.of_node;
+
+ if (!pdev->dev.parent) {
+ pr_err("%s: missing link to parent device\n", __func__);
+ return -ENODEV;
+ }
+
+ 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);
+ irq_out_size = resource_size(r);
+ irq_out_base = ioremap_nocache(r->start, irq_out_size);
+ if (!irq_out_base) {
+ pr_err("%s: ioremap_nocache() of irq_out_base addr:%pr size:%pr\n",
+ __func__, &r->start, &irq_out_size);
+ return -ENOMEM;
+ }
+ SMD_DBG("%s: %s = %p", __func__, key, irq_out_base);
key = "qcom,smd-edge";
ret = of_property_read_u32(node, key, &edge);
@@ -3521,68 +3547,9 @@
strlcpy(edge_to_pids[edge].subsys_name, pilstr,
SMD_MAX_CH_NAME_LEN);
- return 0;
+ edge_to_pids[edge].initialized = true;
-missing_key:
- pr_err("%s: missing key: %s", __func__, key);
- return -ENODEV;
-}
-
-static int __devinit parse_smsm_devicetree(struct device_node *node,
- void *irq_out_base)
-{
- uint32_t edge;
- char *key;
- int ret;
- uint32_t irq_offset;
- uint32_t irq_bitmask;
- uint32_t irq_line;
- struct interrupt_config_item *private_irq;
-
- key = "qcom,smsm-edge";
- ret = of_property_read_u32(node, key, &edge);
- if (ret)
- goto missing_key;
- SMD_DBG("%s: %s = %d", __func__, key, edge);
-
- key = "qcom,smsm-irq-offset";
- ret = of_property_read_u32(node, key, &irq_offset);
- if (ret)
- goto missing_key;
- SMD_DBG("%s: %s = %x", __func__, key, irq_offset);
-
- key = "qcom,smsm-irq-bitmask";
- ret = of_property_read_u32(node, key, &irq_bitmask);
- if (ret)
- goto missing_key;
- SMD_DBG("%s: %s = %x", __func__, key, irq_bitmask);
-
- key = "interrupts";
- irq_line = irq_of_parse_and_map(node, 0);
- if (!irq_line)
- goto missing_key;
- SMD_DBG("%s: %s = %d", __func__, key, irq_line);
-
- private_irq = &private_intr_config[edge_to_pids[edge].remote_pid].smsm;
- private_irq->out_bit_pos = irq_bitmask;
- private_irq->out_offset = irq_offset;
- private_irq->out_base = irq_out_base;
- private_irq->irq_id = irq_line;
-
- ret = request_irq(irq_line,
- private_irq->irq_handler,
- IRQF_TRIGGER_RISING,
- "smsm_dev",
- NULL);
- if (ret < 0) {
- pr_err("%s: request_irq() failed on %d\n", __func__, irq_line);
- return ret;
- } else {
- ret = enable_irq_wake(irq_line);
- if (ret < 0)
- pr_err("%s: enable_irq_wake() failed on %d\n", __func__,
- irq_line);
- }
+ schedule_work(&probe_work);
return 0;
@@ -3591,213 +3558,7 @@
return -ENODEV;
}
-static void __devinit unparse_smd_devicetree(struct device_node *node)
-{
- uint32_t irq_line;
-
- irq_line = irq_of_parse_and_map(node, 0);
-
- free_irq(irq_line, NULL);
-}
-
-static void __devinit unparse_smsm_devicetree(struct device_node *node)
-{
- uint32_t irq_line;
-
- irq_line = irq_of_parse_and_map(node, 0);
-
- free_irq(irq_line, NULL);
-}
-
-static int __devinit smd_core_devicetree_init(struct platform_device *pdev)
-{
- char *key;
- struct resource *r;
- void *irq_out_base;
- phys_addr_t aux_mem_base;
- resource_size_t aux_mem_size;
- int temp_string_size = 11; /* max 3 digit count */
- char temp_string[temp_string_size];
- struct device_node *node;
- int ret;
- const char *compatible;
- struct ramdump_segment *ramdump_segments_tmp = NULL;
- struct smem_area *smem_areas_tmp = NULL;
- int smem_idx = 0;
- int subnode_num = 0;
- int i;
- resource_size_t irq_out_size;
-
- disable_smsm_reset_handshake = 1;
-
- key = "irq-reg-base";
- r = platform_get_resource_byname(pdev, IORESOURCE_MEM, key);
- if (!r) {
- pr_err("%s: missing '%s'\n", __func__, key);
- return -ENODEV;
- }
- irq_out_size = resource_size(r);
- irq_out_base = ioremap_nocache(r->start, irq_out_size);
- if (!irq_out_base) {
- pr_err("%s: ioremap_nocache() of irq_out_base addr:%pr size:%pr\n",
- __func__, &r->start, &irq_out_size);
- return -ENOMEM;
- }
- SMD_DBG("%s: %s = %p", __func__, key, irq_out_base);
-
- num_smem_areas = 1;
- while (1) {
- scnprintf(temp_string, temp_string_size, "aux-mem%d",
- num_smem_areas);
- r = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- temp_string);
- if (!r)
- break;
-
- ++num_smem_areas;
- if (num_smem_areas > 999) {
- pr_err("%s: max num aux mem regions reached\n",
- __func__);
- break;
- }
- }
-
- /* Initialize main SMEM region and SSR ramdump region */
- key = "smem";
- r = platform_get_resource_byname(pdev, IORESOURCE_MEM, key);
- if (!r) {
- pr_err("%s: missing '%s'\n", __func__, key);
- return -ENODEV;
- }
-
- smem_areas_tmp = kmalloc_array(num_smem_areas, sizeof(struct smem_area),
- GFP_KERNEL);
- if (!smem_areas_tmp) {
- pr_err("%s: smem areas kmalloc failed\n", __func__);
- ret = -ENOMEM;
- goto free_smem_areas;
- }
-
- ramdump_segments_tmp = kmalloc_array(num_smem_areas,
- sizeof(struct ramdump_segment), GFP_KERNEL);
- if (!ramdump_segments_tmp) {
- pr_err("%s: ramdump segment kmalloc failed\n", __func__);
- ret = -ENOMEM;
- goto free_smem_areas;
- }
-
- smem_areas_tmp[smem_idx].phys_addr = r->start;
- smem_areas_tmp[smem_idx].size = resource_size(r);
- smem_areas_tmp[smem_idx].virt_addr = MSM_SHARED_RAM_BASE;
-
- ramdump_segments_tmp[smem_idx].address = r->start;
- ramdump_segments_tmp[smem_idx].size = resource_size(r);
- ++smem_idx;
-
- /* Configure auxiliary SMEM regions */
- while (1) {
- scnprintf(temp_string, temp_string_size, "aux-mem%d",
- smem_idx);
- r = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- temp_string);
- if (!r)
- break;
- aux_mem_base = r->start;
- aux_mem_size = resource_size(r);
-
- ramdump_segments_tmp[smem_idx].address = aux_mem_base;
- ramdump_segments_tmp[smem_idx].size = aux_mem_size;
-
- smem_areas_tmp[smem_idx].phys_addr = aux_mem_base;
- smem_areas_tmp[smem_idx].size = aux_mem_size;
- smem_areas_tmp[smem_idx].virt_addr = ioremap_nocache(
- (unsigned long)(smem_areas_tmp[smem_idx].phys_addr),
- smem_areas_tmp[smem_idx].size);
- SMD_DBG("%s: %s = %pa %pa -> %p", __func__, temp_string,
- &aux_mem_base, &aux_mem_size,
- smem_areas_tmp[smem_idx].virt_addr);
-
- if (!smem_areas_tmp[smem_idx].virt_addr) {
- pr_err("%s: ioremap_nocache() of addr:%pa size: %pa\n",
- __func__,
- &smem_areas_tmp[smem_idx].phys_addr,
- &smem_areas_tmp[smem_idx].size);
- ret = -ENOMEM;
- goto free_smem_areas;
- }
-
- if (OVERFLOW_ADD_UNSIGNED(uintptr_t,
- (uintptr_t)smem_areas_tmp[smem_idx].virt_addr,
- smem_areas_tmp[smem_idx].size)) {
- pr_err("%s: invalid virtual address block %i: %p:%pa\n",
- __func__, smem_idx,
- smem_areas_tmp[smem_idx].virt_addr,
- &smem_areas_tmp[smem_idx].size);
- ++smem_idx;
- ret = -EINVAL;
- goto free_smem_areas;
- }
-
- ++smem_idx;
- if (smem_idx > 999) {
- pr_err("%s: max num aux mem regions reached\n",
- __func__);
- break;
- }
- }
-
- for_each_child_of_node(pdev->dev.of_node, node) {
- compatible = of_get_property(node, "compatible", NULL);
- if (!compatible) {
- pr_err("%s: invalid child node: compatible null\n",
- __func__);
- ret = -ENODEV;
- goto rollback_subnodes;
- }
- if (!strcmp(compatible, "qcom,smd")) {
- ret = parse_smd_devicetree(node, irq_out_base);
- if (ret)
- goto rollback_subnodes;
- } else if (!strcmp(compatible, "qcom,smsm")) {
- ret = parse_smsm_devicetree(node, irq_out_base);
- if (ret)
- goto rollback_subnodes;
- } else {
- pr_err("%s: invalid child node named: %s\n", __func__,
- compatible);
- ret = -ENODEV;
- goto rollback_subnodes;
- }
- ++subnode_num;
- }
-
- smem_areas = smem_areas_tmp;
- smem_ramdump_segments = ramdump_segments_tmp;
- return 0;
-
-rollback_subnodes:
- i = 0;
- for_each_child_of_node(pdev->dev.of_node, node) {
- if (i >= subnode_num)
- break;
- ++i;
- compatible = of_get_property(node, "compatible", NULL);
- if (!strcmp(compatible, "qcom,smd"))
- unparse_smd_devicetree(node);
- else
- unparse_smsm_devicetree(node);
- }
-free_smem_areas:
- for (smem_idx = smem_idx - 1; smem_idx >= 1; --smem_idx)
- iounmap(smem_areas_tmp[smem_idx].virt_addr);
-
- num_smem_areas = 0;
- kfree(ramdump_segments_tmp);
- kfree(smem_areas_tmp);
- return ret;
-}
-
-static int __devinit msm_smd_probe(struct platform_device *pdev)
+static int msm_smd_probe_legacy(struct platform_device *pdev)
{
int ret;
@@ -3805,13 +3566,6 @@
return -ENODEV;
SMD_INFO("smd probe\n");
- INIT_WORK(&probe_work, smd_channel_probe_worker);
-
- channel_close_wq = create_singlethread_workqueue("smd_channel_close");
- if (IS_ERR(channel_close_wq)) {
- pr_err("%s: create_singlethread_workqueue ENOMEM\n", __func__);
- return -ENOMEM;
- }
if (smsm_init()) {
pr_err("smsm_init() failed\n");
@@ -3820,13 +3574,8 @@
if (pdev) {
if (pdev->dev.of_node) {
- ret = smd_core_devicetree_init(pdev);
- if (ret) {
- pr_err("%s: device tree init failed\n",
- __func__);
- return ret;
- }
- smd_dev = &pdev->dev;
+ pr_err("%s: invalid device tree init\n", __func__);
+ return -ENODEV;
} else if (pdev->dev.platform_data) {
ret = smd_core_platform_init(pdev);
if (ret) {
@@ -3872,6 +3621,8 @@
unsigned long code,
void *data)
{
+ remote_spinlock_t *remote_spinlock;
+
/*
* Some SMD or SMSM clients assume SMD/SMSM SSR handling will be
* done in the AFTER_SHUTDOWN level. If this ever changes, extra
@@ -3886,7 +3637,8 @@
__func__, notifier->processor,
notifier->name);
- remote_spin_release(&remote_spinlock, notifier->processor);
+ remote_spinlock = smem_get_remote_spinlock();
+ remote_spin_release(remote_spinlock, notifier->processor);
remote_spin_release_all(notifier->processor);
smd_channel_reset(notifier->processor);
@@ -3912,17 +3664,39 @@
}
late_initcall(modem_restart_late_init);
-static struct of_device_id msm_smem_match_table[] = {
- { .compatible = "qcom,smem" },
+static struct of_device_id msm_smd_match_table[] = {
+ { .compatible = "qcom,smd" },
{},
};
static struct platform_driver msm_smd_driver = {
.probe = msm_smd_probe,
.driver = {
+ .name = "msm_smd_dt",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_smd_match_table,
+ },
+};
+
+static struct of_device_id msm_smsm_match_table[] = {
+ { .compatible = "qcom,smsm" },
+ {},
+};
+
+static struct platform_driver msm_smsm_driver = {
+ .probe = msm_smsm_probe,
+ .driver = {
+ .name = "msm_smsm",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_smsm_match_table,
+ },
+};
+
+static struct platform_driver msm_smd_driver_legacy = {
+ .probe = msm_smd_probe_legacy,
+ .driver = {
.name = MODULE_NAME,
.owner = THIS_MODULE,
- .of_match_table = msm_smem_match_table,
},
};
@@ -3941,9 +3715,19 @@
}
registered = true;
- rc = init_smem_remote_spinlock();
+
+ INIT_WORK(&probe_work, smd_channel_probe_worker);
+
+ channel_close_wq = create_singlethread_workqueue("smd_channel_close");
+ if (IS_ERR(channel_close_wq)) {
+ pr_err("%s: create_singlethread_workqueue ENOMEM\n", __func__);
+ return -ENOMEM;
+ }
+
+ rc = platform_driver_register(&msm_smd_driver_legacy);
if (rc) {
- pr_err("%s: remote spinlock init failed %d\n", __func__, rc);
+ pr_err("%s: msm_smd_driver_legacy register failed %d\n",
+ __func__, rc);
return rc;
}
@@ -3954,7 +3738,12 @@
return rc;
}
- smd_module_init_notify(0, NULL);
+ rc = platform_driver_register(&msm_smsm_driver);
+ if (rc) {
+ pr_err("%s: msm_smsm_driver register failed %d\n",
+ __func__, rc);
+ return rc;
+ }
return 0;
}
diff --git a/arch/arm/mach-msm/smd_tty.c b/arch/arm/mach-msm/smd_tty.c
index 0b270b7..3461e49 100644
--- a/arch/arm/mach-msm/smd_tty.c
+++ b/arch/arm/mach-msm/smd_tty.c
@@ -175,8 +175,10 @@
if (dev == smd_tty[num_dev].device_ptr)
break;
}
- if (num_dev >= MAX_SMD_TTYS)
+ if (num_dev >= MAX_SMD_TTYS) {
SMD_TTY_ERR("[%s]: Device Not Found", __func__);
+ return -EINVAL;
+ }
return snprintf(buf, PAGE_SIZE, "%d\n",
smd_tty[num_dev].open_wait);
diff --git a/arch/arm/mach-msm/smem.c b/arch/arm/mach-msm/smem.c
index 181b504..1ec2a78 100644
--- a/arch/arm/mach-msm/smem.c
+++ b/arch/arm/mach-msm/smem.c
@@ -15,6 +15,7 @@
#include <linux/kernel.h>
#include <linux/moduleparam.h>
#include <linux/printk.h>
+#include <linux/notifier.h>
#include <mach/board.h>
#include <mach/msm_iomap.h>
@@ -53,15 +54,20 @@
pr_debug(x); \
} while (0)
-remote_spinlock_t remote_spinlock;
-int spinlocks_initialized;
-uint32_t num_smem_areas;
-struct smem_area *smem_areas;
-struct ramdump_segment *smem_ramdump_segments;
+#define SMEM_SPINLOCK_SMEM_ALLOC "S:3"
+static remote_spinlock_t remote_spinlock;
+static uint32_t num_smem_areas;
+static struct smem_area *smem_areas;
+static struct ramdump_segment *smem_ramdump_segments;
+static int spinlocks_initialized;
static void *smem_ramdump_dev;
static DEFINE_MUTEX(spinlock_init_lock);
static DEFINE_SPINLOCK(smem_init_check_lock);
+static int smem_module_inited;
+static RAW_NOTIFIER_HEAD(smem_module_init_notifier_list);
+static DEFINE_MUTEX(smem_module_init_notifier_lock);
+
struct restart_notifier_block {
unsigned processor;
@@ -82,6 +88,8 @@
{SMEM_Q6, "adsp", .nb.notifier_call = restart_notifier_cb},
};
+static int init_smem_remote_spinlock(void);
+
/**
* smem_phys_to_virt() - Convert a physical base and offset to virtual address
*
@@ -350,6 +358,8 @@
*/
remote_spinlock_t *smem_get_remote_spinlock(void)
{
+ if (unlikely(!spinlocks_initialized))
+ init_smem_remote_spinlock();
return &remote_spinlock;
}
EXPORT_SYMBOL(smem_get_remote_spinlock);
@@ -359,7 +369,7 @@
*
* @returns: sucess or error code for failure
*/
-int init_smem_remote_spinlock(void)
+static int init_smem_remote_spinlock(void)
{
int rc = 0;
@@ -499,3 +509,223 @@
return 0;
}
late_initcall(modem_restart_late_init);
+
+int smem_module_init_notifier_register(struct notifier_block *nb)
+{
+ int ret;
+ if (!nb)
+ return -EINVAL;
+ mutex_lock(&smem_module_init_notifier_lock);
+ ret = raw_notifier_chain_register(&smem_module_init_notifier_list, nb);
+ if (smem_module_inited)
+ nb->notifier_call(nb, 0, NULL);
+ mutex_unlock(&smem_module_init_notifier_lock);
+ return ret;
+}
+EXPORT_SYMBOL(smem_module_init_notifier_register);
+
+int smem_module_init_notifier_unregister(struct notifier_block *nb)
+{
+ int ret;
+ if (!nb)
+ return -EINVAL;
+ mutex_lock(&smem_module_init_notifier_lock);
+ ret = raw_notifier_chain_unregister(&smem_module_init_notifier_list,
+ nb);
+ mutex_unlock(&smem_module_init_notifier_lock);
+ return ret;
+}
+EXPORT_SYMBOL(smem_module_init_notifier_unregister);
+
+static void smem_module_init_notify(uint32_t state, void *data)
+{
+ mutex_lock(&smem_module_init_notifier_lock);
+ smem_module_inited = 1;
+ raw_notifier_call_chain(&smem_module_init_notifier_list,
+ state, data);
+ mutex_unlock(&smem_module_init_notifier_lock);
+}
+
+static int msm_smem_probe(struct platform_device *pdev)
+{
+ char *key;
+ struct resource *r;
+ phys_addr_t aux_mem_base;
+ resource_size_t aux_mem_size;
+ int temp_string_size = 11; /* max 3 digit count */
+ char temp_string[temp_string_size];
+ int ret;
+ struct ramdump_segment *ramdump_segments_tmp = NULL;
+ struct smem_area *smem_areas_tmp = NULL;
+ int smem_idx = 0;
+
+ if (!smem_initialized_check())
+ return -ENODEV;
+
+ key = "irq-reg-base";
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, key);
+ if (!r) {
+ pr_err("%s: missing '%s'\n", __func__, key);
+ return -ENODEV;
+ }
+
+ num_smem_areas = 1;
+ while (1) {
+ scnprintf(temp_string, temp_string_size, "aux-mem%d",
+ num_smem_areas);
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ temp_string);
+ if (!r)
+ break;
+
+ ++num_smem_areas;
+ if (num_smem_areas > 999) {
+ pr_err("%s: max num aux mem regions reached\n",
+ __func__);
+ break;
+ }
+ }
+ /* Initialize main SMEM region and SSR ramdump region */
+ key = "smem";
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, key);
+ if (!r) {
+ pr_err("%s: missing '%s'\n", __func__, key);
+ return -ENODEV;
+ }
+
+ smem_areas_tmp = kmalloc_array(num_smem_areas, sizeof(struct smem_area),
+ GFP_KERNEL);
+ if (!smem_areas_tmp) {
+ pr_err("%s: smem areas kmalloc failed\n", __func__);
+ ret = -ENOMEM;
+ goto free_smem_areas;
+ }
+
+ ramdump_segments_tmp = kmalloc_array(num_smem_areas,
+ sizeof(struct ramdump_segment), GFP_KERNEL);
+ if (!ramdump_segments_tmp) {
+ pr_err("%s: ramdump segment kmalloc failed\n", __func__);
+ ret = -ENOMEM;
+ goto free_smem_areas;
+ }
+ smem_areas_tmp[smem_idx].phys_addr = r->start;
+ smem_areas_tmp[smem_idx].size = resource_size(r);
+ smem_areas_tmp[smem_idx].virt_addr = MSM_SHARED_RAM_BASE;
+
+ ramdump_segments_tmp[smem_idx].address = r->start;
+ ramdump_segments_tmp[smem_idx].size = resource_size(r);
+ ++smem_idx;
+
+ /* Configure auxiliary SMEM regions */
+ while (1) {
+ scnprintf(temp_string, temp_string_size, "aux-mem%d",
+ smem_idx);
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ temp_string);
+ if (!r)
+ break;
+ aux_mem_base = r->start;
+ aux_mem_size = resource_size(r);
+
+ ramdump_segments_tmp[smem_idx].address = aux_mem_base;
+ ramdump_segments_tmp[smem_idx].size = aux_mem_size;
+
+ smem_areas_tmp[smem_idx].phys_addr = aux_mem_base;
+ smem_areas_tmp[smem_idx].size = aux_mem_size;
+ smem_areas_tmp[smem_idx].virt_addr = ioremap_nocache(
+ (unsigned long)(smem_areas_tmp[smem_idx].phys_addr),
+ smem_areas_tmp[smem_idx].size);
+ SMEM_DBG("%s: %s = %pa %pa -> %p", __func__, temp_string,
+ &aux_mem_base, &aux_mem_size,
+ smem_areas_tmp[smem_idx].virt_addr);
+
+ if (!smem_areas_tmp[smem_idx].virt_addr) {
+ pr_err("%s: ioremap_nocache() of addr:%pa size: %pa\n",
+ __func__,
+ &smem_areas_tmp[smem_idx].phys_addr,
+ &smem_areas_tmp[smem_idx].size);
+ ret = -ENOMEM;
+ goto free_smem_areas;
+ }
+
+ if (OVERFLOW_ADD_UNSIGNED(uintptr_t,
+ (uintptr_t)smem_areas_tmp[smem_idx].virt_addr,
+ smem_areas_tmp[smem_idx].size)) {
+ pr_err("%s: invalid virtual address block %i: %p:%pa\n",
+ __func__, smem_idx,
+ smem_areas_tmp[smem_idx].virt_addr,
+ &smem_areas_tmp[smem_idx].size);
+ ++smem_idx;
+ ret = -EINVAL;
+ goto free_smem_areas;
+ }
+
+ ++smem_idx;
+ if (smem_idx > 999) {
+ pr_err("%s: max num aux mem regions reached\n",
+ __func__);
+ break;
+ }
+ }
+
+ ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+ if (ret)
+ pr_err("%s: of_platform_populate failed %d\n", __func__, ret);
+
+ smem_areas = smem_areas_tmp;
+ smem_ramdump_segments = ramdump_segments_tmp;
+ return 0;
+
+free_smem_areas:
+ for (smem_idx = smem_idx - 1; smem_idx >= 1; --smem_idx)
+ iounmap(smem_areas_tmp[smem_idx].virt_addr);
+
+ num_smem_areas = 0;
+ kfree(ramdump_segments_tmp);
+ kfree(smem_areas_tmp);
+ return ret;
+}
+
+static struct of_device_id msm_smem_match_table[] = {
+ { .compatible = "qcom,smem" },
+ {},
+};
+
+static struct platform_driver msm_smem_driver = {
+ .probe = msm_smem_probe,
+ .driver = {
+ .name = "msm_smem",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_smem_match_table,
+ },
+};
+
+int __init msm_smem_init(void)
+{
+ static bool registered;
+ int rc;
+
+ if (registered)
+ return 0;
+
+ registered = true;
+
+ rc = init_smem_remote_spinlock();
+ if (rc) {
+ pr_err("%s: remote spinlock init failed %d\n", __func__, rc);
+ return rc;
+ }
+
+ rc = platform_driver_register(&msm_smem_driver);
+ if (rc) {
+ pr_err("%s: msm_smem_driver register failed %d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ smem_module_init_notify(0, NULL);
+
+ return 0;
+}
+
+module_init(msm_smem_init);
diff --git a/arch/arm/mach-msm/smem_log.c b/arch/arm/mach-msm/smem_log.c
index 87f141d2..35a6e15 100644
--- a/arch/arm/mach-msm/smem_log.c
+++ b/arch/arm/mach-msm/smem_log.c
@@ -39,6 +39,7 @@
#include "smd_private.h"
#include "smd_rpc_sym.h"
#include "modem_notifier.h"
+#include "smem_private.h"
#define DEBUG
#undef DEBUG
@@ -158,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[] = {
@@ -2005,7 +2009,7 @@
return ret;
}
-static int smd_module_init_notifier(struct notifier_block *this,
+static int smem_module_init_notifier(struct notifier_block *this,
unsigned long code,
void *_cmd)
{
@@ -2016,12 +2020,12 @@
}
static struct notifier_block nb = {
- .notifier_call = smd_module_init_notifier,
+ .notifier_call = smem_module_init_notifier,
};
static int __init smem_log_init(void)
{
- return smd_module_init_notifier_register(&nb);
+ return smem_module_init_notifier_register(&nb);
}
diff --git a/arch/arm/mach-msm/smem_private.h b/arch/arm/mach-msm/smem_private.h
index c4f9a77..ceb8028 100644
--- a/arch/arm/mach-msm/smem_private.h
+++ b/arch/arm/mach-msm/smem_private.h
@@ -17,10 +17,6 @@
#include <mach/ramdump.h>
-#define SMEM_SPINLOCK_SMEM_ALLOC "S:3"
-extern remote_spinlock_t remote_spinlock;
-extern int spinlocks_initialized; /* only modify in init_smem_remote_spinlock */
-
#define SMD_HEAP_SIZE 512
struct smem_heap_info {
@@ -58,19 +54,26 @@
void __iomem *virt_addr;
};
-extern uint32_t num_smem_areas;
-extern struct smem_area *smem_areas;
-
-extern struct ramdump_segment *smem_ramdump_segments;
-
/* used for unit testing spinlocks */
remote_spinlock_t *smem_get_remote_spinlock(void);
-/*
- * used to ensure the remote spinlock is only inited once since local
- * spinlock init code appears non-reentrant
- */
-int init_smem_remote_spinlock(void);
-
bool smem_initialized_check(void);
+
+/**
+ * smem_module_init_notifier_register() - Register a smem module
+ * init notifier block
+ * @nb: Notifier block to be registered
+ *
+ * In order to mark the dependency on SMEM Driver module initialization
+ * register a notifier using this API. Once the smem module_init is
+ * done, notification will be passed to the registered module.
+ */
+int smem_module_init_notifier_register(struct notifier_block *nb);
+
+/**
+ * smem_module_init_notifier_register() - Unregister a smem module
+ * init notifier block
+ * @nb: Notifier block to be unregistered
+ */
+int smem_module_init_notifier_unregister(struct notifier_block *nb);
#endif /* _ARCH_ARM_MACH_MSM_SMEM_PRIVATE_H_ */
diff --git a/arch/arm/mach-msm/smp2p.c b/arch/arm/mach-msm/smp2p.c
index ee262b0..4b69cf0 100644
--- a/arch/arm/mach-msm/smp2p.c
+++ b/arch/arm/mach-msm/smp2p.c
@@ -379,7 +379,7 @@
struct smp2p_out_list_item *out_item)
{
void *item_ptr = NULL;
- unsigned size;
+ unsigned size = 0;
if (!out_item)
return item_ptr;
@@ -1241,7 +1241,7 @@
{
unsigned long flags;
struct smp2p_out_list_item *out_item;
- uint32_t *entry_ptr;
+ uint32_t *entry_ptr = NULL;
if (remote_pid >= SMP2P_NUM_PROCS)
return -EINVAL;
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 575cb49..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,
@@ -282,6 +297,24 @@
[185] = MSM_CPU_8974,
[186] = MSM_CPU_8974,
+ /* 8974AA IDs */
+ [208] = MSM_CPU_8974PRO_AA,
+ [211] = MSM_CPU_8974PRO_AA,
+ [214] = MSM_CPU_8974PRO_AA,
+ [217] = MSM_CPU_8974PRO_AA,
+
+ /* 8974AB IDs */
+ [209] = MSM_CPU_8974PRO_AB,
+ [212] = MSM_CPU_8974PRO_AB,
+ [215] = MSM_CPU_8974PRO_AB,
+ [218] = MSM_CPU_8974PRO_AB,
+
+ /* 8974AC IDs */
+ [194] = MSM_CPU_8974PRO_AC,
+ [210] = MSM_CPU_8974PRO_AC,
+ [213] = MSM_CPU_8974PRO_AC,
+ [216] = MSM_CPU_8974PRO_AC,
+
/* 8625 IDs */
[127] = MSM_CPU_8625,
[128] = MSM_CPU_8625,
@@ -629,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/block/blk-core.c b/block/blk-core.c
index 153240e..8e12c45 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
@@ -2979,6 +3019,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_runtime_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/elevator.c b/block/elevator.c
index 27adf7c..44193a8 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) {
diff --git a/block/row-iosched.c b/block/row-iosched.c
index e71f6af..3fa3b1a 100644
--- a/block/row-iosched.c
+++ b/block/row-iosched.c
@@ -97,7 +97,7 @@
/* Default values for idling on read queues (in msec) */
#define ROW_IDLE_TIME_MSEC 5
-#define ROW_READ_FREQ_MSEC 20
+#define ROW_READ_FREQ_MSEC 5
/**
* struct rowq_idling_data - parameters for idling on the queue
@@ -331,6 +331,10 @@
struct row_queue *rqueue = RQ_ROWQ(rq);
s64 diff_ms;
bool queue_was_empty = list_empty(&rqueue->fifo);
+ unsigned long bv_page_flags = 0;
+
+ if (rq->bio && rq->bio->bi_io_vec && rq->bio->bi_io_vec->bv_page)
+ bv_page_flags = rq->bio->bi_io_vec->bv_page->flags;
list_add_tail(&rq->queuelist, &rqueue->fifo);
rd->nr_reqs[rq_data_dir(rq)]++;
@@ -360,7 +364,9 @@
rqueue->idle_data.begin_idling = false;
return;
}
- if (diff_ms < rd->rd_idle_data.freq_ms) {
+
+ if ((bv_page_flags & (1L << PG_readahead)) ||
+ (diff_ms < rd->rd_idle_data.freq_ms)) {
rqueue->idle_data.begin_idling = true;
row_log_rowq(rd, rqueue->prio, "Enable idling");
} else {
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 5027107..d01496e 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -515,6 +515,7 @@
if (!temp) {
pr_err("diag: Invalid buffer in %s\n", __func__);
+ return -ENOMEM;
}
/* This is Pkt request/response transaction */
@@ -1239,6 +1240,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 +1386,25 @@
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;
+}
diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h
index 22f2cad..2335d37 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 */
@@ -135,4 +136,6 @@
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);
+uint8_t diag_dci_get_cumulative_real_time(void);
+int diag_dci_set_real_time(int client_id, uint8_t real_time);
#endif
diff --git a/drivers/char/diag/diag_debugfs.c b/drivers/char/diag/diag_debugfs.c
index 6b0931c..81c5e57 100644
--- a/drivers/char/diag/diag_debugfs.c
+++ b/drivers/char/diag/diag_debugfs.c
@@ -70,7 +70,8 @@
"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",
+ "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 +101,8 @@
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->logging_mode,
+ driver->real_time_mode);
#ifdef CONFIG_DIAG_OVER_USB
ret += scnprintf(buf+ret, DEBUG_BUF_SIZE,
@@ -137,8 +139,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
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index 5aed793..d838714 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -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;
}
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 1f45a32..1495ad5 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -113,6 +113,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 +190,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 {
@@ -286,7 +299,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 +318,14 @@
unsigned hdlc_count;
unsigned hdlc_escape;
int in_busy_pktdata;
+ /* 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;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 1a2f431..12c40da 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -270,20 +270,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();
@@ -796,7 +800,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 +809,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 +816,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 +915,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 +972,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 +999,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 +1048,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 +1151,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;
}
@@ -1422,7 +1480,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
@@ -1862,6 +1921,21 @@
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,6 +2137,7 @@
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();
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 6851fd8..d07cc04 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -1384,6 +1384,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 +1421,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))
diff --git a/drivers/char/diag/diagfwd_bridge.c b/drivers/char/diag/diagfwd_bridge.c
index 8c07219b..e5a6734 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;
@@ -65,6 +65,12 @@
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 +80,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..b36b7dd 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -151,15 +151,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)
{
@@ -343,6 +413,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..ddefe10 100644
--- a/drivers/char/diag/diagfwd_cntl.h
+++ b/drivers/char/diag/diagfwd_cntl.h
@@ -124,8 +124,9 @@
void diag_clean_reg_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);
#endif
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..132df90 100644
--- a/drivers/coresight/coresight-csr.c
+++ b/drivers/coresight/coresight-csr.c
@@ -168,6 +168,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..d0900d1 100644
--- a/drivers/coresight/coresight-cti.c
+++ b/drivers/coresight/coresight-cti.c
@@ -388,6 +388,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..b570252 100644
--- a/drivers/coresight/coresight-priv.h
+++ b/drivers/coresight/coresight-priv.h
@@ -36,6 +36,13 @@
#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);
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..085f721 100644
--- a/drivers/coresight/coresight-stm.c
+++ b/drivers/coresight/coresight-stm.c
@@ -791,6 +791,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..4186abe 100644
--- a/drivers/coresight/coresight-tmc.c
+++ b/drivers/coresight/coresight-tmc.c
@@ -1134,6 +1134,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))
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/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_iommu_heap.c b/drivers/gpu/ion/ion_iommu_heap.c
index b1c1c5d..a80b0c6 100644
--- a/drivers/gpu/ion/ion_iommu_heap.c
+++ b/drivers/gpu/ion/ion_iommu_heap.c
@@ -94,8 +94,10 @@
}
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/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/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 44c9c29..95eabcd 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -123,20 +123,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
@@ -258,6 +245,10 @@
struct adreno_perfcount_group *group;
unsigned int i, j;
+ /* perfcounter start does nothing on a2xx */
+ if (adreno_is_a2xx(adreno_dev))
+ return;
+
/* group id iter */
for (i = 0; i < counters->group_count; i++) {
group = &(counters->groups[i]);
@@ -265,7 +256,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)
@@ -726,6 +719,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;
@@ -755,7 +749,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);
@@ -1047,9 +1043,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,
@@ -1138,6 +1134,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[] = {
@@ -1698,6 +1705,7 @@
{
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);
@@ -1739,9 +1747,21 @@
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);
@@ -2091,7 +2111,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,
@@ -2927,7 +2947,7 @@
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:
@@ -2940,8 +2960,8 @@
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);
+ adreno_readreg(adreno_dev, ADRENO_REG_RBBM_STATUS,
+ &rbbm_status);
if (adreno_is_a2xx(adreno_dev)) {
if (rbbm_status == 0x110)
return 0;
@@ -2986,9 +3006,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)
@@ -3119,6 +3138,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)
@@ -3151,7 +3171,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,
@@ -3171,7 +3191,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;
@@ -3350,9 +3371,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);
}
@@ -3375,7 +3398,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]);
}
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 70b07c4..b53d16f 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -168,14 +168,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 +277,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 +322,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)
@@ -295,16 +373,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);
@@ -555,4 +632,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..42137fe 100644
--- a/drivers/gpu/msm/adreno_a2xx.c
+++ b/drivers/gpu/msm/adreno_a2xx.c
@@ -1707,11 +1707,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 +1752,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 +1767,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 +1794,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 +1803,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 +1828,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 +1847,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 +1929,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 +1969,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 +1981,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 +1990,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 +2003,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 +2015,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 +2263,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..7e5638c 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2545,7 +2545,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 +2559,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 +2738,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 +2766,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 +2780,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 +2796,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 +2806,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 +2846,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 +2875,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 +2945,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 +2964,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 +2974,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 +2995,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,215 +3136,6 @@
{ adreno_is_a305b, a305b_vbif },
};
-static void a3xx_perfcounter_init(struct adreno_device *adreno_dev)
-{
- /*
- * Set SP to count SP_ALU_ACTIVE_CYCLES, it includes
- * all ALU instruction execution regardless precision or shader ID.
- * Set SP to count SP0_ICL1_MISSES, It counts
- * USP L1 instruction miss request.
- * Set SP to count SP_FS_FULL_ALU_INSTRUCTIONS, it
- * counts USP flow control instruction execution.
- * we will use this to augment our hang detection
- */
- if (adreno_dev->fast_hang_detect) {
- adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
- SP_ALU_ACTIVE_CYCLES, &ft_detect_regs[6],
- PERFCOUNTER_FLAG_KERNEL);
- ft_detect_regs[7] = ft_detect_regs[6] + 1;
- adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
- SP0_ICL1_MISSES, &ft_detect_regs[8],
- PERFCOUNTER_FLAG_KERNEL);
- ft_detect_regs[9] = ft_detect_regs[8] + 1;
- adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
- SP_FS_CFLOW_INSTRUCTIONS, &ft_detect_regs[10],
- PERFCOUNTER_FLAG_KERNEL);
- ft_detect_regs[11] = ft_detect_regs[10] + 1;
- }
-
- adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
- SP_FS_FULL_ALU_INSTRUCTIONS, NULL, PERFCOUNTER_FLAG_KERNEL);
-
- /* Reserve and start countable 1 in the PWR perfcounter group */
- adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_PWR, 1,
- NULL, PERFCOUNTER_FLAG_KERNEL);
-}
-
-static void a3xx_start(struct adreno_device *adreno_dev)
-{
- struct kgsl_device *device = &adreno_dev->dev;
- struct a3xx_vbif_data *vbif = NULL;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(a3xx_vbif_platforms); i++) {
- if (a3xx_vbif_platforms[i].devfunc(adreno_dev)) {
- vbif = a3xx_vbif_platforms[i].vbif;
- break;
- }
- }
-
- BUG_ON(vbif == NULL);
-
- while (vbif->reg != 0) {
- adreno_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);
-
- /* 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);
-
- /* Enable the RBBM error reporting bits. This lets us get
- useful information on failure */
-
- adreno_regwrite(device, A3XX_RBBM_AHB_CTL0, 0x00000001);
-
- /* Enable AHB error reporting */
- adreno_regwrite(device, A3XX_RBBM_AHB_CTL1, 0xA6FFFFFF);
-
- /* Turn on the power counters */
- adreno_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,
- (1 << 16) | 0xFFF);
-
- /* Enable 64-byte cacheline size. HW Default is 32-byte (0x000000E0). */
- adreno_regwrite(device, A3XX_UCHE_CACHE_MODE_CONTROL_REG, 0x00000001);
-
- /* Enable Clock gating */
- adreno_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,
- A330v2_RBBM_GPR0_CTL_DEFAULT);
- else if (adreno_is_a330(adreno_dev))
- adreno_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,
- (unsigned int)(adreno_dev->ocmem_base >> 14));
- }
-
- /* Turn on performance counters */
- adreno_regwrite(device, A3XX_RBBM_PERFCTR_CTL, 0x01);
-
- /* Turn on the GPU busy counter and let it run free */
-
- adreno_dev->gpu_cycles = 0;
-}
-
-/**
- * a3xx_coresight_enable() - Enables debugging through coresight
- * debug bus for adreno a3xx devices.
- * @device: Pointer to GPU device structure
- */
-int a3xx_coresight_enable(struct kgsl_device *device)
-{
- 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,
- 0x00000000);
- adreno_regwrite(device, A3XX_RBBM_DEBUG_BUS_STB_CTL1,
- 0xFFFFFFFE);
- adreno_regwrite(device, A3XX_RBBM_INT_TRACE_BUS_CTL,
- 0x00201111);
- adreno_regwrite(device, A3XX_RBBM_EXT_TRACE_BUS_CTL,
- 0x89100010);
- adreno_regwrite(device, A3XX_RBBM_EXT_TRACE_STOP_CNT,
- 0x00017fff);
- adreno_regwrite(device, A3XX_RBBM_EXT_TRACE_START_CNT,
- 0x0001000f);
- adreno_regwrite(device, A3XX_RBBM_EXT_TRACE_PERIOD_CNT ,
- 0x0001ffff);
- adreno_regwrite(device, A3XX_RBBM_EXT_TRACE_CMD,
- 0x00000001);
- kgsl_active_count_put(device);
- }
- mutex_unlock(&device->mutex);
- return 0;
-}
-
-/**
- * a3xx_coresight_disable() - Disables debugging through coresight
- * debug bus for adreno a3xx devices.
- * @device: Pointer to GPU device structure
- */
-void a3xx_coresight_disable(struct kgsl_device *device)
-{
- 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_active_count_put(device);
- }
- mutex_unlock(&device->mutex);
-}
-
-static void a3xx_coresight_write_reg(struct kgsl_device *device,
- unsigned int wordoffset, unsigned int val)
-{
- mutex_lock(&device->mutex);
- if (!kgsl_active_count_get(device)) {
- adreno_regwrite(device, wordoffset, val);
- kgsl_active_count_put(device);
- }
- mutex_unlock(&device->mutex);
-}
-
-void a3xx_coresight_config_debug_reg(struct kgsl_device *device,
- int debug_reg, unsigned int val)
-{
- switch (debug_reg) {
-
- case DEBUG_BUS_CTL:
- a3xx_coresight_write_reg(device, A3XX_RBBM_DEBUG_BUS_CTL, val);
- break;
-
- case TRACE_STOP_CNT:
- a3xx_coresight_write_reg(device, A3XX_RBBM_EXT_TRACE_STOP_CNT,
- val);
- break;
-
- case TRACE_START_CNT:
- a3xx_coresight_write_reg(device, A3XX_RBBM_EXT_TRACE_START_CNT,
- val);
- break;
-
- case TRACE_PERIOD_CNT:
- a3xx_coresight_write_reg(device, A3XX_RBBM_EXT_TRACE_PERIOD_CNT,
- val);
- break;
-
- case TRACE_CMD:
- a3xx_coresight_write_reg(device, A3XX_RBBM_EXT_TRACE_CMD, val);
- break;
-
- case TRACE_BUS_CTL:
- a3xx_coresight_write_reg(device, A3XX_RBBM_EXT_TRACE_BUS_CTL,
- val);
- break;
- }
-
-}
-
/*
* Define the available perfcounter groups - these get used by
* adreno_perfcounter_get and adreno_perfcounter_put
@@ -3467,6 +3258,219 @@
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.
+ * Set SP to count SP0_ICL1_MISSES, It counts
+ * USP L1 instruction miss request.
+ * Set SP to count SP_FS_FULL_ALU_INSTRUCTIONS, it
+ * counts USP flow control instruction execution.
+ * we will use this to augment our hang detection
+ */
+ if (adreno_dev->fast_hang_detect) {
+ adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
+ SP_ALU_ACTIVE_CYCLES, &ft_detect_regs[6],
+ PERFCOUNTER_FLAG_KERNEL);
+ ft_detect_regs[7] = ft_detect_regs[6] + 1;
+ adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
+ SP0_ICL1_MISSES, &ft_detect_regs[8],
+ PERFCOUNTER_FLAG_KERNEL);
+ ft_detect_regs[9] = ft_detect_regs[8] + 1;
+ adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
+ SP_FS_CFLOW_INSTRUCTIONS, &ft_detect_regs[10],
+ PERFCOUNTER_FLAG_KERNEL);
+ ft_detect_regs[11] = ft_detect_regs[10] + 1;
+ }
+
+ adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
+ SP_FS_FULL_ALU_INSTRUCTIONS, NULL, PERFCOUNTER_FLAG_KERNEL);
+
+ /* Reserve and start countable 1 in the PWR perfcounter group */
+ adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_PWR, 1,
+ NULL, PERFCOUNTER_FLAG_KERNEL);
+}
+
+static void a3xx_start(struct adreno_device *adreno_dev)
+{
+ struct kgsl_device *device = &adreno_dev->dev;
+ struct a3xx_vbif_data *vbif = NULL;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(a3xx_vbif_platforms); i++) {
+ if (a3xx_vbif_platforms[i].devfunc(adreno_dev)) {
+ vbif = a3xx_vbif_platforms[i].vbif;
+ break;
+ }
+ }
+
+ BUG_ON(vbif == NULL);
+
+ while (vbif->reg != 0) {
+ kgsl_regwrite(device, vbif->reg, vbif->val);
+ vbif++;
+ }
+
+ /* Make all blocks contribute to the GPU BUSY perf counter */
+ kgsl_regwrite(device, A3XX_RBBM_GPU_BUSY_MASKED, 0xFFFFFFFF);
+
+ /* Tune the hystersis counters for SP and CP idle detection */
+ 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 */
+
+ kgsl_regwrite(device, A3XX_RBBM_AHB_CTL0, 0x00000001);
+
+ /* Enable AHB error reporting */
+ kgsl_regwrite(device, A3XX_RBBM_AHB_CTL1, 0xA6FFFFFF);
+
+ /* Turn on the power counters */
+ 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 */
+
+ kgsl_regwrite(device, A3XX_RBBM_INTERFACE_HANG_INT_CTL,
+ (1 << 16) | 0xFFF);
+
+ /* Enable 64-byte cacheline size. HW Default is 32-byte (0x000000E0). */
+ kgsl_regwrite(device, A3XX_UCHE_CACHE_MODE_CONTROL_REG, 0x00000001);
+
+ /* Enable Clock gating */
+ kgsl_regwrite(device, A3XX_RBBM_CLOCK_CTL,
+ adreno_a3xx_rbbm_clock_ctl_default(adreno_dev));
+
+ if (adreno_is_a330v2(adreno_dev))
+ kgsl_regwrite(device, A3XX_RBBM_GPR0_CTL,
+ A330v2_RBBM_GPR0_CTL_DEFAULT);
+ else if (adreno_is_a330(adreno_dev))
+ 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)) {
+ kgsl_regwrite(device, A3XX_RB_GMEM_BASE_ADDR,
+ (unsigned int)(adreno_dev->ocmem_base >> 14));
+ }
+
+ /* Turn on performance counters */
+ kgsl_regwrite(device, A3XX_RBBM_PERFCTR_CTL, 0x01);
+
+ /* Turn on the GPU busy counter and let it run free */
+
+ adreno_dev->gpu_cycles = 0;
+}
+
+/**
+ * a3xx_coresight_enable() - Enables debugging through coresight
+ * debug bus for adreno a3xx devices.
+ * @device: Pointer to GPU device structure
+ */
+int a3xx_coresight_enable(struct kgsl_device *device)
+{
+ mutex_lock(&device->mutex);
+ if (!kgsl_active_count_get(device)) {
+ kgsl_regwrite(device, A3XX_RBBM_DEBUG_BUS_CTL, 0x0001093F);
+ kgsl_regwrite(device, A3XX_RBBM_DEBUG_BUS_STB_CTL0,
+ 0x00000000);
+ kgsl_regwrite(device, A3XX_RBBM_DEBUG_BUS_STB_CTL1,
+ 0xFFFFFFFE);
+ kgsl_regwrite(device, A3XX_RBBM_INT_TRACE_BUS_CTL,
+ 0x00201111);
+ kgsl_regwrite(device, A3XX_RBBM_EXT_TRACE_BUS_CTL,
+ 0x89100010);
+ kgsl_regwrite(device, A3XX_RBBM_EXT_TRACE_STOP_CNT,
+ 0x00017fff);
+ kgsl_regwrite(device, A3XX_RBBM_EXT_TRACE_START_CNT,
+ 0x0001000f);
+ kgsl_regwrite(device, A3XX_RBBM_EXT_TRACE_PERIOD_CNT ,
+ 0x0001ffff);
+ kgsl_regwrite(device, A3XX_RBBM_EXT_TRACE_CMD,
+ 0x00000001);
+ kgsl_active_count_put(device);
+ }
+ mutex_unlock(&device->mutex);
+ return 0;
+}
+
+/**
+ * a3xx_coresight_disable() - Disables debugging through coresight
+ * debug bus for adreno a3xx devices.
+ * @device: Pointer to GPU device structure
+ */
+void a3xx_coresight_disable(struct kgsl_device *device)
+{
+ mutex_lock(&device->mutex);
+ if (!kgsl_active_count_get(device)) {
+ 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);
+}
+
+static void a3xx_coresight_write_reg(struct kgsl_device *device,
+ unsigned int wordoffset, unsigned int val)
+{
+ mutex_lock(&device->mutex);
+ if (!kgsl_active_count_get(device)) {
+ kgsl_regwrite(device, wordoffset, val);
+ kgsl_active_count_put(device);
+ }
+ mutex_unlock(&device->mutex);
+}
+
+void a3xx_coresight_config_debug_reg(struct kgsl_device *device,
+ int debug_reg, unsigned int val)
+{
+ switch (debug_reg) {
+
+ case DEBUG_BUS_CTL:
+ a3xx_coresight_write_reg(device, A3XX_RBBM_DEBUG_BUS_CTL, val);
+ break;
+
+ case TRACE_STOP_CNT:
+ a3xx_coresight_write_reg(device, A3XX_RBBM_EXT_TRACE_STOP_CNT,
+ val);
+ break;
+
+ case TRACE_START_CNT:
+ a3xx_coresight_write_reg(device, A3XX_RBBM_EXT_TRACE_START_CNT,
+ val);
+ break;
+
+ case TRACE_PERIOD_CNT:
+ a3xx_coresight_write_reg(device, A3XX_RBBM_EXT_TRACE_PERIOD_CNT,
+ val);
+ break;
+
+ case TRACE_CMD:
+ a3xx_coresight_write_reg(device, A3XX_RBBM_EXT_TRACE_CMD, val);
+ break;
+
+ case TRACE_BUS_CTL:
+ a3xx_coresight_write_reg(device, A3XX_RBBM_EXT_TRACE_BUS_CTL,
+ val);
+ break;
+ }
+
+}
+
/*
* a3xx_soft_reset() - Soft reset GPU
* @adreno_dev: Pointer to adreno device
@@ -3482,23 +3486,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 +3746,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_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c
index c7b6b5b..ebfd837 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[] = {
@@ -89,8 +89,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 +102,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 +260,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 +276,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 +328,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 +369,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 +389,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 +420,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) {
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 2d87263..fcef296 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
@@ -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,66 @@
/* 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);
+ adreno_writereg(adreno_dev, ADRENO_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);
+ kgsl_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);
+ 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 */
- 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);
+ 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 */
- adreno_regwrite(device, A3XX_CP_PROTECT_REG_B, 0x60003300);
+ kgsl_regwrite(device, A3XX_CP_PROTECT_REG_B, 0x60003300);
/* VBIF registers */
- adreno_regwrite(device, A3XX_CP_PROTECT_REG_C, 0x6B00C000);
+ kgsl_regwrite(device, A3XX_CP_PROTECT_REG_C, 0x6B00C000);
}
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 +531,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;
}
@@ -704,7 +706,8 @@
/* 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]);
@@ -1373,12 +1376,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_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..5c454f1 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -2370,7 +2370,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 +2430,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 +2442,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;
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
index 48c7301..abb7c35 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"
)
@@ -304,7 +304,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 +327,7 @@
),
TP_printk(
- "d_name=%s %s",
+ "d_name=%s state=%s",
__get_str(device_name),
kgsl_pwrstate_to_str(__entry->state)
)
@@ -369,7 +369,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 +401,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 +432,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 +465,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 +499,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 +531,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 +599,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,
@@ -700,7 +700,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 +726,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,7 +743,7 @@
__entry->timestamp = timestamp;
),
TP_printk(
- "ctx=%d ts=%d",
+ "ctx=%u ts=%u",
__entry->id, __entry->timestamp)
);
@@ -762,7 +762,7 @@
__entry->age = age;
),
TP_printk(
- "ctx=%d ts=%d age=%u",
+ "ctx=%u ts=%u age=%u",
__entry->id, __entry->ts, __entry->age)
);
@@ -785,7 +785,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/input/misc/kxtj9.c b/drivers/input/misc/kxtj9.c
index 204ad94..dd2e5d8 100644
--- a/drivers/input/misc/kxtj9.c
+++ b/drivers/input/misc/kxtj9.c
@@ -144,6 +144,13 @@
y = le16_to_cpu(acc_data[tj9->pdata.axis_map_y]);
z = le16_to_cpu(acc_data[tj9->pdata.axis_map_z]);
+ /* 8 bits output mode support */
+ if (!(tj9->ctrl_reg1 & RES_12BIT)) {
+ x <<= 4;
+ y <<= 4;
+ z <<= 4;
+ }
+
x >>= tj9->shift;
y >>= tj9->shift;
z >>= tj9->shift;
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/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index cb8d821..2db25a6 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -39,7 +39,7 @@
#define VFE40_BURST_LEN 3
#define VFE40_STATS_BURST_LEN 2
#define VFE40_UB_SIZE 1536
-#define VFE40_EQUAL_SLICE_UB 286
+#define VFE40_EQUAL_SLICE_UB 228
#define VFE40_WM_BASE(idx) (0x6C + 0x24 * idx)
#define VFE40_RDI_BASE(idx) (0x2E8 + 0x4 * idx)
#define VFE40_XBAR_BASE(idx) (0x58 + 0x4 * (idx / 2))
@@ -1299,7 +1299,7 @@
}
static struct msm_vfe_axi_hardware_info msm_vfe40_axi_hw_info = {
- .num_wm = 4,
+ .num_wm = 5,
.num_comp_mask = 3,
.num_rdi = 3,
.num_rdi_master = 3,
diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c
index 27aba5c..8d53e35 100644
--- a/drivers/media/platform/msm/camera_v2/msm.c
+++ b/drivers/media/platform/msm/camera_v2/msm.c
@@ -852,16 +852,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/sensor/cci/msm_cci.c b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
index a6c5639..a27ca99 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
@@ -795,10 +795,7 @@
rc = msm_cci_config(sd, arg);
break;
case MSM_SD_SHUTDOWN: {
- struct msm_camera_cci_ctrl ctrl_cmd;
- ctrl_cmd.cmd = MSM_CCI_RELEASE;
- rc = msm_cci_config(sd, &ctrl_cmd);
- break;
+ return rc;
}
default:
rc = -ENOIOCTLCMD;
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/io/msm_camera_cci_i2c.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c
index 80b1ccb..40d1155 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;
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 34f4428..7f474bb 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
@@ -1175,9 +1175,10 @@
case VIDIOC_MSM_SENSOR_CFG:
return s_ctrl->func_tbl->sensor_config(s_ctrl, argp);
case VIDIOC_MSM_SENSOR_RELEASE:
- case MSM_SD_SHUTDOWN:
msm_sensor_stop_stream(s_ctrl);
return 0;
+ case MSM_SD_SHUTDOWN:
+ return 0;
default:
return -ENOIOCTLCMD;
}
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..23e05e2 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
@@ -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;
}
/*
@@ -3776,8 +3777,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;
}
@@ -4525,19 +4528,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 +4546,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 +4631,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 +4662,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;
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..31fd9b5 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
@@ -403,14 +407,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;
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..5daa842 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
@@ -562,6 +562,9 @@
caps->demod_input_max_bitrate = 72;
caps->memory_input_max_bitrate = 72;
+ /* TSIF reports 3 bytes STC at unit of 27MHz/256 */
+ caps->max_stc = (u64)0xFFFFFF * 256;
+
/* Buffer requirements */
caps->section.flags =
DMX_BUFFER_EXTERNAL_SUPPORT |
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..5bd008d 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
@@ -1628,6 +1628,9 @@
caps->demod_input_max_bitrate = 96;
caps->memory_input_max_bitrate = 96;
+ /* TSIF reports 3 bytes STC at unit of 27MHz/256 */
+ caps->max_stc = (u64)0xFFFFFF * 256;
+
/* Buffer requirements */
caps->section.flags =
DMX_BUFFER_EXTERNAL_SUPPORT |
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..9837e9f 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
@@ -86,6 +86,9 @@
caps->demod_input_max_bitrate = 96;
caps->memory_input_max_bitrate = 80;
+ /* TSIF reports 7 bytes STC at unit of 27MHz */
+ caps->max_stc = 0x00FFFFFFFFFFFFFF;
+
return 0;
}
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/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
index 687bd71..96d95989 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,
@@ -736,578 +692,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 +905,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_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..28ea41a 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -2852,8 +2852,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/misc/tspp.c b/drivers/misc/tspp.c
index a395b7c..aa71b74 100644
--- a/drivers/misc/tspp.c
+++ b/drivers/misc/tspp.c
@@ -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/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c
index b81af11..d8cff35 100644
--- a/drivers/mmc/core/sdio_cis.c
+++ b/drivers/mmc/core/sdio_cis.c
@@ -55,7 +55,7 @@
for (i = 0; i < nr_strings; i++) {
buffer[i] = string;
- strlcpy(string, buf, strlen(buf));
+ strlcpy(string, buf, strlen(buf) + 1);
string += strlen(string) + 1;
buf += strlen(buf) + 1;
}
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index e285bfa..476e75c 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);
@@ -5380,6 +5383,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)
diff --git a/drivers/net/ethernet/msm/ecm_ipa.c b/drivers/net/ethernet/msm/ecm_ipa.c
index f000df7..644a751 100644
--- a/drivers/net/ethernet/msm/ecm_ipa.c
+++ b/drivers/net/ethernet/msm/ecm_ipa.c
@@ -1307,6 +1307,8 @@
next_state = ECM_IPA_INITIALIZED;
else if (operation == ECM_IPA_CONNECT)
next_state = ECM_IPA_CONNECTED_AND_UP;
+ else if (operation == ECM_IPA_CLEANUP)
+ next_state = ECM_IPA_UNLOADED;
break;
case ECM_IPA_CONNECTED_AND_UP:
if (operation == ECM_IPA_STOP)
diff --git a/drivers/net/ethernet/msm/msm_rmnet_wwan.c b/drivers/net/ethernet/msm/msm_rmnet_wwan.c
index 98bdccc..3e4605f 100644
--- a/drivers/net/ethernet/msm/msm_rmnet_wwan.c
+++ b/drivers/net/ethernet/msm/msm_rmnet_wwan.c
@@ -188,6 +188,9 @@
__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]);
spin_unlock_irqrestore(&wwan_ptr->lock, flags);
}
@@ -533,6 +536,7 @@
__func__, skb);
}
spin_unlock_irqrestore(&wwan_ptr->lock, flags);
+ return ret;
exit:
ipa_rm_inactivity_timer_release_resource(
ipa_rm_resource_by_ch_id[wwan_ptr->ch_id]);
@@ -548,6 +552,7 @@
static void wwan_tx_timeout(struct net_device *dev)
{
pr_warning("[%s] wwan_tx_timeout(), data stall in UL\n", dev->name);
+ ipa_bam_reg_dump();
}
/**
diff --git a/drivers/net/ethernet/msm/qfec.c b/drivers/net/ethernet/msm/qfec.c
index 164b734..e68c395 100644
--- a/drivers/net/ethernet/msm/qfec.c
+++ b/drivers/net/ethernet/msm/qfec.c
@@ -2921,6 +2921,8 @@
priv->mii.dev = dev;
priv->mii.mdio_read = qfec_mdio_read;
priv->mii.mdio_write = qfec_mdio_write;
+ /* initialize mdio clock */
+ priv->mdio_clk = GMII_ADR_REG_CR_62;
/* map register regions */
ret = qfec_map_resource(
diff --git a/drivers/net/ethernet/msm/qfec.h b/drivers/net/ethernet/msm/qfec.h
index 525fd9c..a25436f 100644
--- a/drivers/net/ethernet/msm/qfec.h
+++ b/drivers/net/ethernet/msm/qfec.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-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
@@ -411,6 +411,14 @@
# define GMII_ADR_REG_GR 0x000007c0 /* addr bits */
# define GMII_ADR_REG_RSVRD1 0x00000020 /* */
# define GMII_ADR_REG_CR 0x0000001c /* csr clock range */
+
+# define GMII_ADR_REG_CR_42 0x00000000 /* csr clock 42 */
+# define GMII_ADR_REG_CR_62 0x00000001 /* csr clock 62 */
+# define GMII_ADR_REG_CR_16 0x00000002 /* csr clock 16 */
+# define GMII_ADR_REG_CR_26 0x00000003 /* csr clock 26 */
+# define GMII_ADR_REG_CR_102 0x00000004 /* csr clock 102 */
+# define GMII_ADR_REG_CR_124 0x00000005 /* csr clock 124 */
+
# define GMII_ADR_REG_GW 0x00000002 /* gmii write */
# define GMII_ADR_REG_GB 0x00000001 /* gmii busy */
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index a3d7f12..5e22c35 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -112,6 +112,9 @@
#define CCU_PRONTO_LAST_ADDR1_OFFSET 0x10
#define CCU_PRONTO_LAST_ADDR2_OFFSET 0x14
+#define MSM_PRONTO_SAW2_BASE 0xfb219000
+#define PRONTO_SAW2_SPM_STS_OFFSET 0x0c
+
#define WCNSS_DEF_WLAN_RX_BUFF_COUNT 1024
#define WCNSS_CTRL_CHANNEL "WCNSS_CTRL"
@@ -288,6 +291,7 @@
void __iomem *riva_ccu_base;
void __iomem *pronto_a2xb_base;
void __iomem *pronto_ccpu_base;
+ void __iomem *pronto_saw2_base;
void __iomem *fiq_reg;
int ssr_boot;
int nv_downloaded;
@@ -479,6 +483,10 @@
reg = readl_relaxed(reg_addr);
pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR2 %08x\n", __func__, reg);
+ reg_addr = penv->pronto_saw2_base + PRONTO_SAW2_SPM_STS_OFFSET;
+ reg = readl_relaxed(reg_addr);
+ pr_info_ratelimited("%s: PRONTO_SAW2_SPM_STS %08x\n", __func__, reg);
+
tst_addr = penv->pronto_a2xb_base + A2XB_TSTBUS_OFFSET;
tst_ctrl_addr = penv->pronto_a2xb_base + A2XB_TSTBUS_CTRL_OFFSET;
@@ -1683,6 +1691,14 @@
ret = -ENOMEM;
goto fail_ioremap4;
}
+ penv->pronto_saw2_base = ioremap_nocache(MSM_PRONTO_SAW2_BASE,
+ SZ_32);
+ if (!penv->pronto_saw2_base) {
+ pr_err("%s: ioremap wcnss physical(saw2) failed\n",
+ __func__);
+ ret = -ENOMEM;
+ goto fail_ioremap5;
+ }
}
/* trigger initialization of the WCNSS */
@@ -1699,6 +1715,9 @@
fail_pil:
if (penv->riva_ccu_base)
iounmap(penv->riva_ccu_base);
+ if (penv->pronto_saw2_base)
+ iounmap(penv->pronto_saw2_base);
+fail_ioremap5:
if (penv->fiq_reg)
iounmap(penv->fiq_reg);
fail_ioremap4:
diff --git a/drivers/platform/msm/ipa/a2_service.c b/drivers/platform/msm/ipa/a2_service.c
index 4921ec2..ae9277e 100644
--- a/drivers/platform/msm/ipa/a2_service.c
+++ b/drivers/platform/msm/ipa/a2_service.c
@@ -1469,6 +1469,35 @@
return ret;
}
+/**
+ * a2_mux_is_ch_empty() - checks if channel is empty.
+ * @lcid: logical channel ID
+ *
+ * Returns: true if the channel is empty,
+ * false otherwise
+ */
+int a2_mux_is_ch_empty(enum a2_mux_logical_channel_id lcid)
+{
+ unsigned long flags;
+ int ret;
+
+ if (lcid >= A2_MUX_NUM_CHANNELS ||
+ lcid < 0)
+ return -EINVAL;
+ if (!a2_mux_ctx->a2_mux_initialized)
+ return -ENODEV;
+ spin_lock_irqsave(&a2_mux_ctx->bam_ch[lcid].lock, flags);
+ a2_mux_ctx->bam_ch[lcid].use_wm = 1;
+ ret = a2_mux_ctx->bam_ch[lcid].num_tx_pkts == 0;
+ if (!bam_ch_is_local_open(lcid)) {
+ ret = -ENODEV;
+ IPAERR("%s: port not open: %d\n", __func__,
+ a2_mux_ctx->bam_ch[lcid].status);
+ }
+ spin_unlock_irqrestore(&a2_mux_ctx->bam_ch[lcid].lock, flags);
+ return ret;
+}
+
static int a2_mux_initialize_context(int handle)
{
int i;
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 83c4db0..f9401f0 100644
--- a/drivers/platform/msm/ipa/ipa_bridge.c
+++ b/drivers/platform/msm/ipa/ipa_bridge.c
@@ -468,7 +468,7 @@
{
int i;
- ipa_ctx->smem_pipe_mem = smem_alloc(SMEM_BAM_PIPE_MEMORY,
+ ipa_ctx->smem_pipe_mem = smem_alloc2(SMEM_BAM_PIPE_MEMORY,
IPA_SMEM_PIPE_MEM_SZ);
if (!ipa_ctx->smem_pipe_mem) {
IPAERR("smem alloc failed\n");
diff --git a/drivers/platform/msm/ipa/ipa_client.c b/drivers/platform/msm/ipa/ipa_client.c
index e98c9b7..f20f37f 100644
--- a/drivers/platform/msm/ipa/ipa_client.c
+++ b/drivers/platform/msm/ipa/ipa_client.c
@@ -203,6 +203,7 @@
}
memset(&ipa_ctx->ep[ipa_ep_idx], 0, sizeof(struct ipa_ep_context));
+ ipa_enable_data_path(ipa_ep_idx);
ep->valid = 1;
ep->client = in->client;
@@ -380,7 +381,6 @@
return -EPERM;
}
- ipa_enable_data_path(clnt_hdl);
memset(&ipa_ctx->ep[clnt_hdl], 0, sizeof(struct ipa_ep_context));
ipa_dec_client_disable_clks();
diff --git a/drivers/platform/msm/ipa/ipa_dp.c b/drivers/platform/msm/ipa/ipa_dp.c
index 1f232d4..e2856cf 100644
--- a/drivers/platform/msm/ipa/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_dp.c
@@ -641,7 +641,7 @@
switch (notify->event_id) {
case SPS_EVENT_EOT:
tx_pkt = notify->data.transfer.user;
- queue_work(ipa_ctx->tx_wq, &tx_pkt->work);
+ schedule_work(&tx_pkt->work);
break;
default:
IPAERR("recieved unexpected event id %d\n", notify->event_id);
diff --git a/drivers/platform/msm/ipa/ipa_utils.c b/drivers/platform/msm/ipa/ipa_utils.c
index b1e2d93..e38b796 100644
--- a/drivers/platform/msm/ipa/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_utils.c
@@ -13,7 +13,9 @@
#include <net/ip.h>
#include <linux/genalloc.h> /* gen_pool_alloc() */
#include <linux/io.h>
+#include <linux/ratelimit.h>
#include "ipa_i.h"
+
static const int ipa_ofst_meq32[] = { IPA_OFFSET_MEQ32_0,
IPA_OFFSET_MEQ32_1, -1 };
static const int ipa_ofst_meq128[] = { IPA_OFFSET_MEQ128_0,
@@ -1382,3 +1384,26 @@
else
return 0;
}
+
+/**
+ * ipa_bam_reg_dump() - Dump selected BAM registers for IPA and DMA-BAM
+ *
+ * Function is rate limited to avoid flooding kernel log buffer
+ */
+void ipa_bam_reg_dump(void)
+{
+ static DEFINE_RATELIMIT_STATE(_rs, 500*HZ, 1);
+ 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, 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();
+ }
+}
+EXPORT_SYMBOL(ipa_bam_reg_dump);
+
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index fae09fc..4889a79 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -153,7 +153,6 @@
bool prod_stopped;
struct completion prod_avail[MAX_BAMS];
- struct completion cons_released[MAX_BAMS];
struct completion prod_released[MAX_BAMS];
struct mutex suspend_resume_mutex;
@@ -175,7 +174,6 @@
static int __usb_bam_register_wake_cb(u8 idx, int (*callback)(void *user),
void *param, bool trigger_cb_per_pipe);
static void wait_for_prod_release(enum usb_bam cur_bam);
-static void wait_for_cons_release(enum usb_bam cur_bam);
void msm_bam_set_hsic_host_dev(struct device *dev)
{
@@ -936,7 +934,6 @@
__func__, bam_enable_strings[cur_bam]);
info.cur_cons_state[cur_bam] = IPA_RM_RESOURCE_RELEASED;
- complete_all(&info.cons_released[cur_bam]);
spin_lock(&usb_bam_lock);
if (!ctx.pipes_enabled_per_bam[cur_bam]) {
@@ -1078,7 +1075,6 @@
pr_debug("%s producer already released\n", __func__);
init_completion(&info.prod_released[cur_bam]);
- init_completion(&info.cons_released[cur_bam]);
pr_debug("%s: Releasing %s_PROD\n", __func__,
bam_enable_strings[cur_bam]);
ret = ipa_rm_release_resource(ipa_rm_resource_prod[cur_bam]);
@@ -1908,19 +1904,6 @@
return 0;
}
-static void wait_for_cons_release(enum usb_bam cur_bam)
-{
- pr_debug("%s: Waiting for CONS release\n", __func__);
- if (info.cur_cons_state[cur_bam] != IPA_RM_RESOURCE_RELEASED) {
- if (!wait_for_completion_timeout(&info.cons_released[cur_bam],
- USB_BAM_TIMEOUT))
- pr_err("%s: Timeout wainting for CONS_RELEASE\n",
- __func__);
- } else
- pr_debug("%s Didn't need to wait for CONS release\n",
- __func__);
-}
-
int usb_bam_disconnect_ipa(struct usb_bam_connect_ipa_params *ipa_params)
{
int ret;
@@ -1987,7 +1970,6 @@
pipe_connect->priv = NULL;
cur_bam = pipe_connect->bam_type;
- wait_for_cons_release(cur_bam);
/* close IPA -> USB pipe */
ret = ipa_disconnect(ipa_params->cons_clnt_hdl);
if (ret) {
@@ -2542,8 +2524,6 @@
ctx.is_bam_inactivity[i] = false;
init_completion(&info.prod_avail[i]);
complete(&info.prod_avail[i]);
- init_completion(&info.cons_released[i]);
- complete(&info.cons_released[i]);
init_completion(&info.prod_released[i]);
complete(&info.prod_released[i]);
info.cur_prod_state[i] = IPA_RM_RESOURCE_RELEASED;
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 12aef1c..4df511b 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -280,6 +280,7 @@
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,
};
@@ -1413,6 +1414,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;
@@ -2985,6 +3001,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;
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 85bdd67..983a901 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -1066,6 +1066,7 @@
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_CURRENT_NOW,
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,
@@ -1245,6 +1246,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)
@@ -1380,6 +1397,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;
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/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/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 5f21c7a..48a7645 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
*
@@ -913,8 +805,8 @@
cpu_to_le16(ALIGNED_UPIU_SIZE);
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/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index 53aa475..c7db832 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.
@@ -1681,6 +1748,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 +2381,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 +2394,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 +2442,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);
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/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 7f669d8..cab7c12 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -2835,7 +2835,7 @@
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;
if (pdev->dev.of_node) {
@@ -2894,6 +2894,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 +2914,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 +2936,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) {
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index a5f586b..2600001 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -182,6 +182,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;
@@ -1260,6 +1261,37 @@
return rc < 0 ? rc : 0;
}
+/*
+ * Config Global Distributed Switch Controller (GDSC)
+ * to support controller power collapse
+ */
+static int dwc3_msm_config_gdsc(struct dwc3_msm *msm, int on)
+{
+ int ret = 0;
+
+ if (IS_ERR(msm->dwc3_gdsc))
+ return 0;
+
+ if (!msm->dwc3_gdsc) {
+ msm->dwc3_gdsc = devm_regulator_get(msm->dev,
+ "USB3_GDSC");
+ if (IS_ERR(msm->dwc3_gdsc))
+ return 0;
+ }
+
+ if (on) {
+ ret = regulator_enable(msm->dwc3_gdsc);
+ if (ret) {
+ dev_err(msm->dev, "unable to enable usb3 gdsc\n");
+ return ret;
+ }
+ } else {
+ regulator_disable(msm->dwc3_gdsc);
+ }
+
+ return 0;
+}
+
static int dwc3_msm_link_clk_reset(bool assert)
{
int ret = 0;
@@ -1729,6 +1761,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;
@@ -1809,6 +1846,10 @@
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);
@@ -2495,11 +2536,18 @@
INIT_DELAYED_WORK(&msm->init_adc_work, dwc3_init_adc_work);
init_completion(&msm->ext_chg_wait);
+ ret = dwc3_msm_config_gdsc(msm, 1);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to configure usb3 gdsc\n");
+ return ret;
+ }
+
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 = PTR_ERR(msm->xo_clk);
+ goto disable_dwc3_gdsc;
}
ret = clk_prepare_enable(msm->xo_clk);
@@ -2906,6 +2954,8 @@
clk_disable_unprepare(msm->xo_clk);
put_xo:
clk_put(msm->xo_clk);
+disable_dwc3_gdsc:
+ dwc3_msm_config_gdsc(msm, 0);
return ret;
}
@@ -2953,6 +3003,8 @@
clk_disable_unprepare(msm->xo_clk);
clk_put(msm->xo_clk);
+ dwc3_msm_config_gdsc(msm, 0);
+
return 0;
}
diff --git a/drivers/usb/gadget/u_bam_data.c b/drivers/usb/gadget/u_bam_data.c
index 3322da5..577a4fe 100644
--- a/drivers/usb/gadget/u_bam_data.c
+++ b/drivers/usb/gadget/u_bam_data.c
@@ -200,7 +200,6 @@
int ret;
pr_debug("%s: Connect workqueue started", __func__);
- usb_bam_reset_complete();
if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
if (d->func_type == USB_FUNC_MBIM) {
@@ -268,17 +267,18 @@
}
}
} else { /* transport type is USB_GADGET_XPORT_BAM2BAM */
- ret = usb_bam_connect(d->src_connection_idx, &d->src_pipe_idx);
- if (ret) {
- pr_err("usb_bam_connect (src) failed: err:%d\n", ret);
- return;
+ usb_bam_reset_complete();
+ ret = usb_bam_connect(d->src_connection_idx, &d->src_pipe_idx);
+ if (ret) {
+ pr_err("usb_bam_connect (src) failed: err:%d\n", ret);
+ return;
+ }
+ ret = usb_bam_connect(d->dst_connection_idx, &d->dst_pipe_idx);
+ if (ret) {
+ pr_err("usb_bam_connect (dst) failed: err:%d\n", ret);
+ return;
+ }
}
- ret = usb_bam_connect(d->dst_connection_idx, &d->dst_pipe_idx);
- if (ret) {
- pr_err("usb_bam_connect (dst) failed: err:%d\n", ret);
- return;
- }
-}
if (!port->port_usb) {
pr_err("port_usb is NULL");
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-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 14c3323..ef45d49 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -1895,6 +1895,8 @@
"hsic,consider-ipa-handshake"));
pdata->ahb_async_bridge_bypass = of_property_read_bool(node,
"qcom,ahb-async-bridge-bypass");
+ pdata->disable_cerr = of_property_read_bool(node,
+ "hsic,disable-cerr");
return pdata;
}
@@ -1982,8 +1984,10 @@
mehci->ehci.pool_64_bit_align = pdata->pool_64_bit_align;
mehci->enable_hbm = pdata->enable_hbm;
- if (pdata)
+ if (pdata) {
mehci->ehci.log2_irq_thresh = pdata->log2_irq_thresh;
+ mehci->ehci.disable_cerr = pdata->disable_cerr;
+ }
ret = msm_hsic_init_gdsc(mehci, 1);
if (ret) {
diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c
index 0b89dd0..823229b 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
@@ -260,15 +260,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-q.c b/drivers/usb/host/ehci-q.c
index db49c07..b029be2 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -637,7 +637,8 @@
qtd->urb = urb;
token = QTD_STS_ACTIVE;
- token |= (EHCI_TUNE_CERR << 10);
+ if (!ehci->disable_cerr)
+ token |= (EHCI_TUNE_CERR << 10);
/* for split transactions, SplitXState initialized to zero */
len = urb->transfer_buffer_length;
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index edf2a73..0498a6a 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -154,6 +154,7 @@
unsigned susp_sof_bug:1; /*Chip Idea HC*/
unsigned resume_sof_bug:1;/*Chip Idea HC*/
unsigned reset_sof_bug:1; /*Chip Idea HC*/
+ bool disable_cerr;
/* 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..1b6d15e 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;
+ 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-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.h b/drivers/usb/host/xhci.h
index 8f3651b..e47f46c 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1823,4 +1823,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..72c3c7d 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -87,6 +87,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,6 +885,7 @@
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;
@@ -898,6 +904,7 @@
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;
/*
* Abort suspend when,
@@ -906,7 +913,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;
}
@@ -2211,6 +2219,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 +2233,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 +2278,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 +2320,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;
@@ -2482,6 +2498,12 @@
pm_runtime_put_noidle(otg->phy->dev);
pm_runtime_suspend(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;
case USB_ACA_B_CHARGER:
msm_otg_notify_charger(motg,
IDEV_ACA_CHG_MAX);
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index aecb19d..91e70a7 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -539,13 +539,6 @@
return 0;
}
-static int mdp3_iommu_fault_handler(struct iommu_domain *domain,
- struct device *dev, unsigned long iova, int flags, void *token)
-{
- pr_err("MDP IOMMU page fault: iova 0x%lx\n", iova);
- return 0;
-}
-
int mdp3_iommu_attach(int context)
{
struct mdp3_iommu_ctx_map *context_map;
@@ -621,9 +614,6 @@
else
return PTR_ERR(mdp3_iommu_domains[i].domain);
}
- iommu_set_fault_handler(mdp3_iommu_domains[i].domain,
- mdp3_iommu_fault_handler,
- NULL);
}
mdp3_res->domains = mdp3_iommu_domains;
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index 1311dab..078960b 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;
@@ -121,6 +122,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 366209b..fb0e8ba 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -416,6 +416,14 @@
mdss_dsi_clk_ctrl(ctrl_pdata, 0);
+ ret = mdss_dsi_enable_bus_clocks(ctrl_pdata);
+ if (ret) {
+ pr_err("%s: failed to enable bus clocks. rc=%d\n", __func__,
+ ret);
+ mdss_dsi_panel_power_on(pdata, 0);
+ return ret;
+ }
+
/* disable DSI phy */
mdss_dsi_phy_enable(ctrl_pdata, 0);
@@ -479,6 +487,7 @@
mdss_dsi_phy_sw_reset((ctrl_pdata->ctrl_base));
mdss_dsi_phy_init(pdata);
+ mdss_dsi_disable_bus_clocks(ctrl_pdata);
mdss_dsi_clk_ctrl(ctrl_pdata, 1);
@@ -593,6 +602,13 @@
}
mdss_dsi_op_mode_config(mipi->mode, pdata);
+ if (pdata->panel_info.type == MIPI_CMD_PANEL) {
+ if (mipi->vsync_enable && mipi->hw_vsync_mode
+ && gpio_is_valid(ctrl_pdata->disp_te_gpio)) {
+ mdss_dsi_set_tear_on(ctrl_pdata);
+ }
+ }
+
pr_debug("%s-:\n", __func__);
return ret;
@@ -601,6 +617,7 @@
static int mdss_dsi_blank(struct mdss_panel_data *pdata)
{
int ret = 0;
+ struct mipi_panel_info *mipi;
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
pr_debug("%s+:\n", __func__);
@@ -612,9 +629,17 @@
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
panel_data);
+ mipi = &pdata->panel_info.mipi;
mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata);
+ if (pdata->panel_info.type == MIPI_CMD_PANEL) {
+ if (mipi->vsync_enable && mipi->hw_vsync_mode
+ && gpio_is_valid(ctrl_pdata->disp_te_gpio)) {
+ mdss_dsi_set_tear_off(ctrl_pdata);
+ }
+ }
+
if (ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT) {
ret = ctrl_pdata->off(pdata);
if (ret) {
@@ -1143,15 +1168,6 @@
return rc;
}
- rc = mdss_dsi_enable_bus_clocks(ctrl_pdata);
- if (rc) {
- pr_err("%s: failed to enable bus clocks. rc=%d\n",
- __func__, rc);
- rc = mdss_dsi_panel_power_on(
- &(ctrl_pdata->panel_data), 0);
- return rc;
- }
-
mdss_dsi_clk_ctrl(ctrl_pdata, 1);
ctrl_pdata->ctrl_state |=
(CTRL_STATE_PANEL_INIT | CTRL_STATE_MDP_ACTIVE);
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index 965a23f..8a8e4ca 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -382,6 +382,8 @@
void mdss_dsi_host_init(struct mipi_panel_info *pinfo,
struct mdss_panel_data *pdata);
+void mdss_dsi_set_tear_on(struct mdss_dsi_ctrl_pdata *ctrl);
+void mdss_dsi_set_tear_off(struct mdss_dsi_ctrl_pdata *ctrl);
void mdss_dsi_op_mode_config(int mode,
struct mdss_panel_data *pdata);
void mdss_dsi_cmd_mode_ctrl(int enable);
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index 60b8b2e..2f29b3d 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -80,6 +80,7 @@
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);
}
@@ -90,6 +91,7 @@
if (ctrl->clk_cnt == 0) {
mdss_dsi_clk_disable(ctrl);
mdss_dsi_unprepare_clocks(ctrl);
+ mdss_dsi_disable_bus_clocks(ctrl);
}
}
}
@@ -1098,6 +1100,40 @@
pr_debug("%s: BTA done, status = %d\n", __func__, status);
}
+static char set_tear_on[2] = {0x35, 0x00};
+static struct dsi_cmd_desc dsi_tear_on_cmd = {
+ {DTYPE_DCS_WRITE1, 1, 0, 0, 0, sizeof(set_tear_on)}, set_tear_on};
+
+static char set_tear_off[2] = {0x34, 0x00};
+static struct dsi_cmd_desc dsi_tear_off_cmd = {
+ {DTYPE_DCS_WRITE, 1, 0, 0, 0, sizeof(set_tear_off)}, set_tear_off};
+
+void mdss_dsi_set_tear_on(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ struct dcs_cmd_req cmdreq;
+
+ cmdreq.cmds = &dsi_tear_on_cmd;
+ cmdreq.cmds_cnt = 1;
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+
+ mdss_dsi_cmdlist_put(ctrl, &cmdreq);
+}
+
+void mdss_dsi_set_tear_off(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ struct dcs_cmd_req cmdreq;
+
+ cmdreq.cmds = &dsi_tear_off_cmd;
+ cmdreq.cmds_cnt = 1;
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+
+ mdss_dsi_cmdlist_put(ctrl, &cmdreq);
+}
+
int mdss_dsi_cmd_reg_tx(u32 data,
unsigned char *ctrl_base)
{
diff --git a/drivers/video/msm/mdss/mdss_hdmi_edid.c b/drivers/video/msm/mdss/mdss_hdmi_edid.c
index 1876057..9a5b20b 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_edid.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_edid.c
@@ -854,7 +854,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_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index 287f2cd..91e5660 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -2250,6 +2250,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 +2259,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);
diff --git a/drivers/video/msm/mdss/mdss_io_util.c b/drivers/video/msm/mdss/mdss_io_util.c
index 809db43..31058f8 100644
--- a/drivers/video/msm/mdss/mdss_io_util.c
+++ b/drivers/video/msm/mdss/mdss_io_util.c
@@ -13,6 +13,7 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
+#include <linux/delay.h>
#include "mdss_io_util.h"
#define MAX_I2C_CMDS 16
@@ -160,19 +161,6 @@
curr_vreg->vreg_name);
goto vreg_set_voltage_fail;
}
- if (curr_vreg->peak_current >= 0) {
- rc = regulator_set_optimum_mode(
- curr_vreg->vreg,
- curr_vreg->peak_current);
- if (rc < 0) {
- DEV_ERR(
- "%pS->%s: %s set opt m fail\n",
- __builtin_return_address(0),
- __func__,
- curr_vreg->vreg_name);
- goto vreg_set_opt_mode_fail;
- }
- }
}
}
} else {
@@ -183,10 +171,6 @@
curr_vreg->vreg) > 0)
? DSS_REG_LDO : DSS_REG_VS;
if (type == DSS_REG_LDO) {
- if (curr_vreg->peak_current >= 0) {
- regulator_set_optimum_mode(
- curr_vreg->vreg, 0);
- }
regulator_set_voltage(curr_vreg->vreg,
0, curr_vreg->max_voltage);
}
@@ -201,10 +185,6 @@
if (type == DSS_REG_LDO)
regulator_set_optimum_mode(curr_vreg->vreg, 0);
-vreg_set_opt_mode_fail:
-if (type == DSS_REG_LDO)
- regulator_set_voltage(curr_vreg->vreg, 0, curr_vreg->max_voltage);
-
vreg_set_voltage_fail:
regulator_put(curr_vreg->vreg);
curr_vreg->vreg = NULL;
@@ -229,9 +209,19 @@
DEV_ERR("%pS->%s: %s regulator error. rc=%d\n",
__builtin_return_address(0), __func__,
in_vreg[i].vreg_name, rc);
- goto disable_vreg;
+ goto vreg_set_opt_mode_fail;
+ }
+ msleep(in_vreg[i].pre_on_sleep);
+ rc = regulator_set_optimum_mode(in_vreg[i].vreg,
+ in_vreg[i].peak_current);
+ if (rc < 0) {
+ DEV_ERR("%pS->%s: %s set opt m fail\n",
+ __builtin_return_address(0), __func__,
+ in_vreg[i].vreg_name);
+ goto vreg_set_opt_mode_fail;
}
rc = regulator_enable(in_vreg[i].vreg);
+ msleep(in_vreg[i].post_on_sleep);
if (rc < 0) {
DEV_ERR("%pS->%s: %s enable failed\n",
__builtin_return_address(0), __func__,
@@ -241,14 +231,26 @@
}
} else {
for (i = num_vreg-1; i >= 0; i--)
- if (regulator_is_enabled(in_vreg[i].vreg))
+ 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_disable(in_vreg[i].vreg);
+ msleep(in_vreg[i].post_off_sleep);
+ }
}
return rc;
disable_vreg:
- for (i--; i >= 0; i--)
+ regulator_set_optimum_mode(in_vreg[i].vreg, 0);
+
+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_disable(in_vreg[i].vreg);
+ msleep(in_vreg[i].post_off_sleep);
+ }
+
return rc;
} /* msm_dss_enable_vreg */
diff --git a/drivers/video/msm/mdss/mdss_io_util.h b/drivers/video/msm/mdss/mdss_io_util.h
index 23341d6..cb0fb70 100644
--- a/drivers/video/msm/mdss/mdss_io_util.h
+++ b/drivers/video/msm/mdss/mdss_io_util.h
@@ -53,6 +53,10 @@
int min_voltage;
int max_voltage;
int peak_current;
+ int pre_on_sleep;
+ int post_on_sleep;
+ int pre_off_sleep;
+ int post_off_sleep;
};
struct dss_gpio {
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index c4bf67e..56a4ac4 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
@@ -703,13 +707,6 @@
return 0;
}
-static int mdss_iommu_fault_handler(struct iommu_domain *domain,
- struct device *dev, unsigned long iova, int flags, void *token)
-{
- pr_err("MDP IOMMU page fault: iova 0x%lx\n", iova);
- return 0;
-}
-
int mdss_iommu_attach(struct mdss_data_type *mdata)
{
struct iommu_domain *domain;
@@ -796,7 +793,6 @@
iomap->domain_idx);
return -EINVAL;
}
- iommu_set_fault_handler(domain, mdss_iommu_fault_handler, NULL);
iomap->ctx = msm_iommu_get_ctx(iomap->ctx_name);
if (!iomap->ctx) {
@@ -1154,9 +1150,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);
@@ -1184,17 +1180,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)
@@ -1203,47 +1223,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);
@@ -1467,6 +1531,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;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 52224e2..39952c9 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 {
@@ -430,6 +437,7 @@
struct mdss_mdp_ctl *mdss_mdp_ctl_init(struct mdss_panel_data *pdata,
struct msm_fb_data_type *mfd);
int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl);
+int mdss_mdp_cmd_reconfigure_splash_done(struct mdss_mdp_ctl *ctl);
int mdss_mdp_video_copy_splash_screen(struct mdss_panel_data *pdata);
void mdss_mdp_ctl_splash_start(struct mdss_panel_data *pdata);
int mdss_mdp_ctl_splash_finish(struct mdss_mdp_ctl *ctl);
@@ -524,8 +532,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,
@@ -560,6 +569,9 @@
int mdss_mdp_calib_config(struct mdp_calib_config_data *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);
#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 9eaff61..e656131 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);
@@ -517,6 +533,7 @@
case MIPI_VIDEO_PANEL:
return mdss_mdp_video_reconfigure_splash_done(ctl);
case MIPI_CMD_PANEL:
+ return mdss_mdp_cmd_reconfigure_splash_done(ctl);
default:
return 0;
}
@@ -704,6 +721,7 @@
mdss_mdp_mixer_free(mixer);
return -EINVAL;
}
+ ctl->wb_type = MDSS_MDP_WB_CTL_TYPE_LINE;
}
ctl->mixer_left = mixer;
@@ -1118,7 +1136,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;
@@ -1186,7 +1210,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);
@@ -1202,9 +1229,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",
@@ -1224,6 +1255,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:
@@ -1247,10 +1285,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");
@@ -1264,6 +1316,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;
@@ -1348,7 +1410,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);
@@ -1387,11 +1452,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;
}
@@ -1520,12 +1593,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;
@@ -1620,6 +1690,36 @@
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)
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index 4779d20..8e5534d 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
};
@@ -232,6 +240,7 @@
MDSS_MDP_INTF_LAYERMIXER0,
MDSS_MDP_INTF_LAYERMIXER1,
MDSS_MDP_INTF_LAYERMIXER2,
+ MDSS_MDP_INTF_LAYERMIXER3,
MDSS_MDP_INTF_MAX_LAYERMIXER,
};
@@ -248,17 +257,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 +393,7 @@
MDSS_MDP_DSPP0,
MDSS_MDP_DSPP1,
MDSS_MDP_DSPP2,
+ MDSS_MDP_DSPP3,
MDSS_MDP_MAX_DSPP
};
@@ -468,6 +471,7 @@
MDSS_MDP_PINGPONG0,
MDSS_MDP_PINGPONG1,
MDSS_MDP_PINGPONG2,
+ MDSS_MDP_PINGPONG3,
MDSS_MDP_MAX_PINGPONG
};
@@ -494,28 +498,6 @@
#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_LP_MISR_SEL 0x450
#define MDSS_MDP_LP_MISR_CTRL_MDP 0x454
#define MDSS_MDP_LP_MISR_CTRL_HDMI 0x458
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
index 89e21d2..d0c1818 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
@@ -357,6 +357,24 @@
return 0;
}
+int mdss_mdp_cmd_reconfigure_splash_done(struct mdss_mdp_ctl *ctl)
+{
+ struct mdss_panel_data *pdata;
+ int ret = 0;
+
+ pdata = ctl->panel_data;
+
+ pdata->panel_info.cont_splash_enabled = 0;
+
+ ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_CONT_SPLASH_FINISH,
+ NULL);
+
+ mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_CLK_CTRL, (void *)0);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+ return ret;
+}
+
static int mdss_mdp_cmd_wait4pingpong(struct mdss_mdp_ctl *ctl, void *arg)
{
struct mdss_mdp_cmd_ctx *ctx;
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..328f045 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,12 +783,44 @@
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) {
@@ -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);
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index 3b91ced..137da66 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -87,7 +87,7 @@
{
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);
@@ -269,12 +269,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 +297,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 +308,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 +321,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 +340,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 +363,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 +564,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 +583,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 +645,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 +661,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;
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 75b6056..4dd9dcb 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -3329,6 +3329,14 @@
ret = 1;
else if (ptr >= 0x3200 || ptr == 0x100)
ret = 1;
+ else if (ptr == 0x104 || ptr == 0x614 || ptr == 0x714 ||
+ ptr == 0x814 || ptr == 0x914 || ptr == 0xa14)
+ ret = 1;
+ else if (ptr == 0x618 || ptr == 0x718 || ptr == 0x818 ||
+ ptr == 0x918 || ptr == 0xa18)
+ ret = 1;
+ else if (ptr == 0x2234 || ptr == 0x1e34 || ptr == 0x2634)
+ ret = 1;
}
end:
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..ff54067 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;
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/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..3ae83d6 100644
--- a/include/linux/dvb/dmx.h
+++ b/include/linux/dvb/dmx.h
@@ -570,6 +570,9 @@
/* Max bitrate from single memory input. Mbit/sec */
int memory_input_max_bitrate;
+ /* Max possible value of STC reported by demux, in 27MHz */
+ __u64 max_stc;
+
struct dmx_buffer_requirement section;
/* For PES not sent to decoder */
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index ae88807..f8b78a4 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -227,6 +227,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/page-flags.h b/include/linux/page-flags.h
index c88d2a9..86e4c91 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -108,6 +108,7 @@
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
PG_compound_lock,
#endif
+ PG_readahead, /* page in a readahead window */
__NR_PAGEFLAGS,
/* Filesystems */
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 44c6d7f..2f18351 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -165,6 +165,7 @@
USB_ACA_C_CHARGER,
USB_ACA_DOCK_CHARGER,
USB_PROPRIETARY_CHARGER,
+ USB_FLOATED_CHARGER,
};
/**
@@ -457,6 +458,7 @@
bool disable_park_mode;
bool consider_ipa_handshake;
bool ahb_async_bridge_bypass;
+ bool disable_cerr;
};
struct msm_usb_host_platform_data {
@@ -464,6 +466,8 @@
int pmic_gpio_dp_irq;
unsigned int dock_connect_irq;
bool use_sec_phy;
+ bool no_selective_suspend;
+ int resume_gpio;
};
/**
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 5c7ae02..81187aa 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1836,12 +1836,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 +1845,17 @@
};
#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
+};
/* 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..6358f8a 100644
--- a/include/media/msm_cam_sensor.h
+++ b/include/media/msm_cam_sensor.h
@@ -305,18 +305,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 {
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/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..364de9a 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
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/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/mm/page_alloc.c b/mm/page_alloc.c
index 5148c1a..9cc2f45 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -6093,6 +6093,7 @@
#ifdef CONFIG_MEMORY_FAILURE
{1UL << PG_hwpoison, "hwpoison" },
#endif
+ {1UL << PG_readahead, "PG_readahead" },
{-1UL, NULL },
};
diff --git a/mm/readahead.c b/mm/readahead.c
index 728a7a3..56f8a24 100644
--- a/mm/readahead.c
+++ b/mm/readahead.c
@@ -184,6 +184,9 @@
if (!page)
break;
page->index = page_offset;
+
+ page->flags |= (1L << PG_readahead);
+
list_add(&page->lru, &page_pool);
if (page_idx == nr_to_read - lookahead_size)
SetPageReadahead(page);
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/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/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/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index 1260e1c..53cfb3e 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -58,7 +58,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 +117,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 +132,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 +152,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 +176,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(
@@ -449,7 +462,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 +485,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 +494,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 +507,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 +560,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 +637,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 +726,8 @@
snd_soc_update_bits(codec,
MSM8X10_WCD_A_CP_STATIC, 0x08, 0x00);
break;
+ default:
+ break;
}
return 0;
}
@@ -1728,6 +1831,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 +1911,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 +2334,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 +2534,21 @@
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_codec_probe(struct snd_soc_codec *codec)
{
struct msm8x10_wcd_priv *msm8x10_wcd;
@@ -2440,20 +2574,33 @@
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;
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 +2626,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 +2664,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 +2683,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 +2698,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 +2735,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);
@@ -2677,12 +2850,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..d8f6ace 100644
--- a/sound/soc/codecs/msm8x10-wcd.h
+++ b/sound/soc/codecs/msm8x10-wcd.h
@@ -147,6 +147,7 @@
int min_uV;
int max_uV;
int optimum_uA;
+ bool ondemand;
struct regulator *regulator;
};
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..7b896c2 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[] = {
@@ -4589,6 +4595,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 +4651,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,6 +4661,16 @@
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
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 516ac4f..4edcec6 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);
@@ -6389,6 +6389,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))
diff --git a/sound/soc/codecs/wcd9xxx-common.c b/sound/soc/codecs/wcd9xxx-common.c
index 916ff1a..bfd66ea 100644
--- a/sound/soc/codecs/wcd9xxx-common.c
+++ b/sound/soc/codecs/wcd9xxx-common.c
@@ -221,20 +221,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 +484,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 +567,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..50381c9 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;
};
diff --git a/sound/soc/msm/apq8074.c b/sound/soc/msm/apq8074.c
index 9a2f83b..cb101bd 100644
--- a/sound/soc/msm/apq8074.c
+++ b/sound/soc/msm/apq8074.c
@@ -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..a0ed887 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,33 @@
.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",
+ },
};
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..043a998 100644
--- a/sound/soc/msm/msm8226.c
+++ b/sound/soc/msm/msm8226.c
@@ -1025,6 +1025,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 +1139,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 +1154,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 +1316,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 = {
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 0a86221..f67af9b 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -481,13 +481,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 {
@@ -2230,7 +2229,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 +2244,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 +2258,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 +2273,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/qdsp6v2/audio_acdb.c b/sound/soc/msm/qdsp6v2/audio_acdb.c
index 3b6a415..d6090cf 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.c
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.c
@@ -153,15 +153,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 +178,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 +202,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 +230,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 +254,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 +295,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 +318,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 +339,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 +362,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 +383,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 +406,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 +435,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 +462,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 +491,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 +518,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 +547,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 +574,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 +603,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 +630,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 +650,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 +678,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 +693,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 +707,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 +727,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 +744,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 +758,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 +779,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 +793,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 +807,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 +828,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 +842,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 +856,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 +877,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 +941,12 @@
status->r0 = calib_resp.res_cfg.r0_cali_q24;
}
}
- } else
+ } else {
pr_err("%s invalid params\n", __func__);
+ result = -EINVAL;
+ }
+
+ return result;
}
static int acdb_open(struct inode *inode, struct file *f)
@@ -1054,13 +1160,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 +1192,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 4a20af1..687f10d 100644
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -625,20 +625,26 @@
{
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 (compressed_audio.prtd->channel_mode > 2) {
- avg_vol = (((volume >> 16) & 0xFFFF) +
- (volume & 0xFFFF)) / 2;
- rc = q6asm_set_volume(
- compressed_audio.prtd->audio_client, avg_vol);
- } else {
+ pr_debug("%s: channels %d volume 0x%x\n", __func__,
+ compressed_audio.prtd->channel_mode, volume);
+ if ((compressed_audio.prtd->channel_mode <= 2) &&
+ (lgain != rgain)) {
+ pr_debug("%s: call q6asm_set_lrgain\n", __func__);
rc = q6asm_set_lrgain(
compressed_audio.prtd->audio_client,
- (volume >> 16) & 0xFFFF, volume & 0xFFFF);
+ 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);
}
if (rc < 0) {
pr_err("%s: Send Volume command failed rc=%d\n",
- __func__, rc);
+ __func__, rc);
}
}
compressed_audio.volume = volume;
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index b07e91e..d31e2c5 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,
@@ -66,6 +69,15 @@
struct msm_dai_q6_mi2s_dai_config rx_dai;
};
+struct msm_dai_q6_auxpcm_dai_data {
+ struct mutex rlock; /* auxpcm dev resource lock */
+ int rcnt; /* auxpcm dev resource usage count */
+ 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 +95,42 @@
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 (aux_dai_data->rcnt) {
+ /* 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 +146,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 +164,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,
@@ -152,109 +185,97 @@
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) {
+ if (aux_dai_data->rcnt == 0) {
dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 0. Just return\n",
__func__, dai->id);
- mutex_unlock(&aux_pcm_mutex);
+ mutex_unlock(&aux_dai_data->rlock);
return;
}
- aux_pcm_count--;
+ aux_dai_data->rcnt--;
- if (aux_pcm_count > 0) {
+ if (aux_dai_data->rcnt > 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);
+ __func__, dai->id, aux_dai_data->rcnt);
+ mutex_unlock(&aux_dai_data->rlock);
return;
- } else if (aux_pcm_count < 0) {
+ } else if (aux_dai_data->rcnt < 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);
+ __func__, dai->id, aux_dai_data->rcnt);
+ aux_dai_data->rcnt = 0;
+ mutex_unlock(&aux_dai_data->rlock);
return;
}
- 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 aux_pcm_count = %d\n", __func__,
+ dai->id, aux_dai_data->rcnt);
- 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);
+ afe_set_lpass_clock(aux_dai_data->rx_pid, &lpass_pcm_oe_clk);
- mutex_unlock(&aux_pcm_mutex);
+ mutex_unlock(&aux_dai_data->rlock);
}
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) {
+ if (aux_dai_data->rcnt == 2) { /* xrun case ? */
dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 2. Just return.\n",
__func__, dai->id);
- mutex_unlock(&aux_pcm_mutex);
+ mutex_unlock(&aux_dai_data->rlock);
return 0;
- } else if (aux_pcm_count > 2) {
+ } else if (aux_dai_data->rcnt > 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);
+ __func__, dai->id, aux_dai_data->rcnt);
+ mutex_unlock(&aux_dai_data->rlock);
return 0;
}
- aux_pcm_count++;
- if (aux_pcm_count == 2) {
+ aux_dai_data->rcnt++;
+ if (aux_dai_data->rcnt == 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);
+ __func__, dai->id, aux_dai_data->rcnt);
+ mutex_unlock(&aux_dai_data->rlock);
return 0;
}
- pr_debug("%s:dai->id:%d aux_pcm_count = %d. opening afe\n",
- __func__, dai->id, aux_pcm_count);
+ dev_dbg(dai->dev, "%s:dai->id:%d aux_pcm_count = %d. opening afe\n",
+ __func__, dai->id, aux_dai_data->rcnt);
rc = afe_q6_interface_prepare();
if (IS_ERR_VALUE(rc))
@@ -279,7 +300,7 @@
} else {
dev_err(dai->dev, "%s: Invalid AUX PCM rate %d\n", __func__,
dai_data->rate);
- mutex_unlock(&aux_pcm_mutex);
+ mutex_unlock(&aux_dai_data->rlock);
return -EINVAL;
}
@@ -291,42 +312,35 @@
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);
+ rc = afe_set_lpass_clock(aux_dai_data->rx_pid, &lpass_pcm_oe_clk);
if (rc < 0) {
- pr_err("%s:afe_set_lpass_clock on pcm_oe_clk failed\n",
- __func__);
+ dev_err(dai->dev,
+ "%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);
fail:
- mutex_unlock(&aux_pcm_mutex);
+ mutex_unlock(&aux_dai_data->rlock);
return rc;
}
@@ -335,8 +349,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,85 +373,44 @@
}
-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;
+ struct afe_clk_cfg lpass_pcm_oe_clk;
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);
-
- if (aux_pcm_count == 0) {
+ if (aux_dai_data->rcnt == 0) {
dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 0. clean up and return\n",
- __func__, dai->id);
+ __func__, dai->id);
goto done;
}
- aux_pcm_count--;
+ 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 = %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 */
+ rc = afe_close(aux_dai_data->rx_pid); /* 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);
+ rc = afe_close(aux_dai_data->tx_pid);
if (IS_ERR_VALUE(rc))
dev_err(dai->dev, "fail to close AUX PCM TX AFE port\n");
+
+ 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);
+
+ 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(aux_dai_data->rx_pid, &lpass_pcm_oe_clk);
+
done:
- kfree(dai_data);
- snd_soc_unregister_dai(dai->dev);
-
- mutex_unlock(&aux_pcm_mutex);
-
return 0;
}
@@ -448,31 +421,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 +715,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 +1057,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 +1099,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 +1111,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 +1122,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 +1133,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 +1144,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 +1152,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 +1241,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 +1580,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 +1714,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 +2035,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 +2166,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 +2203,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 +2214,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-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index 77f3a07..49bc488 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -42,12 +42,6 @@
struct snd_pcm *pcm;
};
-struct snd_msm_volume {
- struct msm_audio *prtd;
- unsigned volume;
-};
-static struct snd_msm_volume pcm_audio = {NULL, 0x2000};
-
#define PLAYBACK_MIN_NUM_PERIODS 2
#define PLAYBACK_MAX_NUM_PERIODS 8
#define PLAYBACK_MAX_PERIOD_SIZE 12288
@@ -63,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,
@@ -260,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);
@@ -272,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__);
@@ -390,7 +396,6 @@
prtd->dsp_cnt = 0;
prtd->set_channel_map = false;
runtime->private_data = prtd;
- pcm_audio.prtd = prtd;
return 0;
}
@@ -479,7 +484,6 @@
q6asm_cmd(prtd->audio_client, CMD_CLOSE);
q6asm_audio_client_buf_free_contiguous(dir,
prtd->audio_client);
- pcm_audio.prtd = NULL;
q6asm_audio_client_free(prtd->audio_client);
}
msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
@@ -702,10 +706,13 @@
/* 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);
@@ -760,30 +767,71 @@
.mmap = msm_pcm_mmap,
};
-static int pcm_chmap_ctl_put(struct snd_kcontrol *kcontrol,
+static int msm_pcm_chmap_ctl_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int i;
- char channel_mapping[PCM_FORMAT_MAX_NUM_CHANNEL];
+ struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+ unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ struct snd_pcm_substream *substream;
+ struct msm_audio *prtd;
pr_debug("%s", __func__);
- for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
- channel_mapping[i] = (char)(ucontrol->value.integer.value[i]);
- if (pcm_audio.prtd) {
- pcm_audio.prtd->set_channel_map = true;
- memcpy(pcm_audio.prtd->channel_map, channel_mapping,
- PCM_FORMAT_MAX_NUM_CHANNEL);
+ substream = snd_pcm_chmap_substream(info, idx);
+ if (!substream)
+ return -ENODEV;
+ if (!substream->runtime)
+ return 0;
+
+ prtd = substream->runtime->private_data;
+ if (prtd) {
+ prtd->set_channel_map = true;
+ for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+ prtd->channel_map[i] =
+ (char)(ucontrol->value.integer.value[i]);
}
return 0;
}
+static int msm_pcm_chmap_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int i;
+ struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+ unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ struct snd_pcm_substream *substream;
+ struct msm_audio *prtd;
+
+ pr_debug("%s", __func__);
+ substream = snd_pcm_chmap_substream(info, idx);
+ if (!substream)
+ return -ENODEV;
+ memset(ucontrol->value.integer.value, 0,
+ sizeof(ucontrol->value.integer.value));
+ if (!substream->runtime)
+ return 0; /* no channels set */
+
+ prtd = substream->runtime->private_data;
+
+ if (prtd && prtd->set_channel_map == true) {
+ for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+ ucontrol->value.integer.value[i] =
+ (int)prtd->channel_map[i];
+ } else {
+ for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+ ucontrol->value.integer.value[i] = 0;
+ }
+
+ return 0;
+}
+
static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_card *card = rtd->card->snd_card;
- struct snd_pcm *pcm = rtd->pcm->streams[0].pcm;
+ struct snd_pcm *pcm = rtd->pcm;
struct snd_pcm_chmap *chmap_info;
struct snd_kcontrol *kctl;
- char device_num[3];
+ char device_num[12];
int i, ret = 0;
if (!card->dev->coherent_dma_mask)
@@ -791,8 +839,9 @@
pr_debug("%s, Channel map cntrl add\n", __func__);
ret = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
- NULL, PCM_FORMAT_MAX_NUM_CHANNEL, 0,
- &chmap_info);
+ snd_pcm_std_chmaps,
+ PCM_FORMAT_MAX_NUM_CHANNEL, 0,
+ &chmap_info);
if (ret < 0)
return ret;
kctl = chmap_info->kctl;
@@ -802,7 +851,8 @@
strlcat(kctl->id.name, device_num, sizeof(kctl->id.name));
pr_debug("%s, Overwriting channel map control name to: %s",
__func__, kctl->id.name);
- kctl->put = pcm_chmap_ctl_put;
+ kctl->put = msm_pcm_chmap_ctl_put;
+ kctl->get = msm_pcm_chmap_ctl_get;
return ret;
}
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 97803b3..c1bc17b 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -40,7 +40,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;
@@ -217,6 +220,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 +268,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 +517,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 +562,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) {
@@ -970,7 +978,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 +996,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;
@@ -1418,6 +1427,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 +1457,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 +1487,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 +1517,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 +1547,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 +1592,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 +1631,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 +1661,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 +1673,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 +1724,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 +1754,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 +1784,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 +1814,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 +1844,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[] = {
@@ -2141,6 +2204,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[] = {
@@ -2763,11 +2829,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),
@@ -2862,6 +2930,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 +3015,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,
@@ -3066,6 +3139,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 +3150,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 +3161,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 +3172,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"},
@@ -3119,6 +3201,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 +3257,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 +3268,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 +3279,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 +3303,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 +3314,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"},
@@ -3320,6 +3408,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"},
@@ -3466,6 +3555,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"},
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
index 9750756..0d87735 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,
@@ -82,8 +84,8 @@
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 +102,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,
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 9882ec7..0eb13d4 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -234,6 +234,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 +304,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);
@@ -1263,6 +1265,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 +1359,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;
@@ -2663,6 +2667,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/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index c65222b..869d642 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -1383,15 +1383,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 +1463,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 +1829,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 +1851,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 +1878,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)
{
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..9fb4eae 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -3457,7 +3457,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 +3556,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 +3588,8 @@
}
mutex_unlock(&v->lock);
+ } else {
+ pr_err("%s: Invalid port_id 0x%x", __func__, port_id);
}
return ret;
diff --git a/sound/soc/msm/qdsp6v2/q6voice.h b/sound/soc/msm/qdsp6v2/q6voice.h
index 5a16115..52cf940 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.h
+++ b/sound/soc/msm/qdsp6v2/q6voice.h
@@ -486,6 +486,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
@@ -1209,6 +1215,7 @@
uint32_t playing;
int count;
int force;
+ uint16_t port_id;
};
struct share_memory_info {
@@ -1370,6 +1377,6 @@
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);
#endif