Merge "ASoC: msm: Mixer control to update the sample rate of SEC I2S interface"
diff --git a/AndroidKernel.mk b/AndroidKernel.mk
index 717dd8c..843da69 100644
--- a/AndroidKernel.mk
+++ b/AndroidKernel.mk
@@ -70,7 +70,7 @@
$(TARGET_PREBUILT_INT_KERNEL): $(KERNEL_OUT) $(KERNEL_CONFIG) $(KERNEL_HEADERS_INSTALL)
$(MAKE) -C kernel O=../$(KERNEL_OUT) ARCH=arm CROSS_COMPILE=arm-eabi-
$(MAKE) -C kernel O=../$(KERNEL_OUT) ARCH=arm CROSS_COMPILE=arm-eabi- modules
- $(MAKE) -C kernel O=../$(KERNEL_OUT) INSTALL_MOD_PATH=../../$(KERNEL_MODULES_INSTALL) ARCH=arm CROSS_COMPILE=arm-eabi- modules_install
+ $(MAKE) -C kernel O=../$(KERNEL_OUT) INSTALL_MOD_PATH=../../$(KERNEL_MODULES_INSTALL) INSTALL_MOD_STRIP=1 ARCH=arm CROSS_COMPILE=arm-eabi- modules_install
$(mv-modules)
$(clean-module-folder)
$(append-dtb)
diff --git a/Documentation/arm/msm/adsprpc-drv.txt b/Documentation/arm/msm/adsprpc-drv.txt
new file mode 100644
index 0000000..f468ddb
--- /dev/null
+++ b/Documentation/arm/msm/adsprpc-drv.txt
@@ -0,0 +1,198 @@
+Introduction
+============
+
+The MSM ADSPRPC driver implements an IPC (Inter-Processor Communication)
+mechanism that allows for clients to transparently make remote method
+invocations across processor boundaries.
+
+The below diagram depicts invocation of a single method where the client
+and objects reside on different processors. An object could expose
+multiple methods which can be grouped together and referred to as an
+interface.
+
+: ,--------, ,------, ,-----------, ,------, ,--------,
+: | | method | | | | | | method | |
+: | Client |------->| Stub |->| Transport |->| Skel |------->| Object |
+: | | | | | | | | | |
+: `--------` `------` `-----------` `------` `--------`
+
+Client: Linux user mode process that initiates the remote invocation
+Stub: Auto generated code linked in with the user mode process that
+ takes care of marshaling parameters
+Transport: Involved in carrying an invocation from a client to an
+ object. This involves two portions: 1) MSM ADSPRPC Linux
+ kernel driver that receives the remote invocation, queues
+ them up and then waits for the response after signaling the
+ remote side. 2) Service running on the remote side that
+ dequeues the messages from the queue and dispatches them for
+ processing.
+Skel: Auto generated code that takes care of un-marshaling
+ parameters
+Object: Method implementation
+
+Hardware description
+====================
+
+The driver interfaces with the components in the DSP subsystem and does
+not drive or manage any hardware resources.
+
+Software description
+====================
+
+The MSM ADSPRPC driver uses SMD (Shared Memory Driver) to send and
+receive messages with the remote processor. The SMD channel used for
+communication is opened during initialization of the driver and is
+closed when the driver module is unloaded. The driver does not expose
+HLOS memory to the remote processor but rather communication of
+invocation parameters happen over ION allocated buffers.
+
+The driver receives remote call invocations via an ioctl call. When a
+remote call invocation is received, the driver does the following:
+- Retrieves the invocation parameters
+- Copies input buffers in HLOS memory to ION allocated buffers
+- Allocates ION buffers for output buffers in HLOS memory as required
+- Scatter-gathers list of pages for ION allocated input and output
+ buffers
+- Coalesces information about the contiguous page buffers
+- Builds up a message with the received information
+- Sends the message to a remote processor through an SMD channel
+- Waits for a response from the remote processor through the SMD channel
+- Reads the message available from the shared memory SMD channel
+- Copies back from ION buffers to HLOS memory for output buffers
+- Returns the response of the remote invocation
+
+Design
+======
+
+The design goals of this transport mechanism are:
+- Fast and efficient ways to transfer huge buffers across
+ inter-processor boundaries
+- Zero copy of ION allocated buffers passed during invocations
+
+To achieve the zero copy approach of ION allocated user space buffers,
+the driver scatter-gathers the list of pages of the buffers being passed
+in. This information is then sent over to the remote processor for it
+to map into its address space.
+
+The invocation requests sent over the SMD channel carry context
+information as to whom the request is originating from. The responses
+received over the SMD channel have context information in the message
+which is then used to wake the thread waiting for a response.
+
+If the remote processor goes down and gets restarted, the SMD channel
+is re-initialized when the remote processor comes back up. An
+error code would be returned to the client for all invocations that
+happen before the SMD channel could get completely re-initialized.
+
+Power Management
+================
+
+None
+
+SMP/multi-core
+==============
+
+The driver uses semaphores to wake up clients waiting for a remote
+invocation response.
+
+Security
+========
+
+Use of the zero copy approach results in a page-size granularity of
+all buffers being passed to the remote processor. The objects that will
+be manipulating these buffers on the remote processor will be signed
+and trusted entities, thereby alleviating any fear of intentional
+scribbling of these buffers.
+
+Performance
+===========
+
+In order to minimize latencies across remote invocations:
+- messages exchanged between the remote processors are kept short
+- zero copy approach for ION allocated user space buffers
+
+Interface
+=========
+
+The driver exposes a user space interface through /dev/adsprpc-smd and
+the user space clients send commands to the driver by using the
+following ioctl command:
+
+- FASTRPC_IOCTL_INVOKE: Parameters passed in includes the buffers and
+ data related to remote invocation.
+
+ /*
+ * Information about the input/output buffer or an handle to the
+ * object being passed in the remote invocation
+ *
+ * @pv: Pointer to input/output buffer
+ * @len: Length of the input/output buffer
+ * @handle: Handle to the remote object
+ */
+ typedef union {
+ struct remote_buf {
+ void *pv;
+ int len;
+ } buf;
+ unsigned int handle;
+ } remote_arg;
+
+ /*
+ * Invocation parameters passed via ioctl call by the client
+ *
+ * @handle: Handle to the object on which the method is to be
+ * invoked
+ * @sc: Scalars detailing the parameters being passed in
+ * bits 0-3: Number of output handles
+ * bits 4-7: Number of input handles
+ * bits 8-15: Number of output buffers
+ * bits 16-23: Number of input buffers
+ * bits 24-28: Method to be invoked
+ * bits 29-31: Method attributes
+ * @pra: Remote arguments to be passed for method invocation
+ */
+ struct fastrpc_ioctl_invoke {
+ unsigned int handle;
+ unsigned int sc;
+ remote_arg *pra;
+ };
+
+Driver parameters
+=================
+
+None
+
+Config options
+==============
+
+None
+
+Dependencies
+============
+
+The ADSPRPC driver requires that the ADSP RPC SMD channel be created and
+the SMD subsystem be initialized. During initialization, the driver
+opens an existing SMD edge channel between ADSP and Apps processor. On
+success, the driver waits for the "channel opened" event from SMD,
+acknowledging the channel availability from the remote SMD driver for
+communication to begin.
+
+User space utilities
+====================
+
+None
+
+Other
+=====
+
+None
+
+Known issues
+============
+
+None
+
+To do
+=====
+
+None
diff --git a/Documentation/block/row-iosched.txt b/Documentation/block/row-iosched.txt
new file mode 100644
index 0000000..987bd88
--- /dev/null
+++ b/Documentation/block/row-iosched.txt
@@ -0,0 +1,117 @@
+Introduction
+============
+
+The ROW scheduling algorithm will be used in mobile devices as default
+block layer IO scheduling algorithm. ROW stands for "READ Over WRITE"
+which is the main requests dispatch policy of this algorithm.
+
+The ROW IO scheduler was developed with the mobile devices needs in
+mind. In mobile devices we favor user experience upon everything else,
+thus we want to give READ IO requests as much priority as possible.
+The main idea of the ROW scheduling policy is:
+If there are READ requests in pipe - dispatch them but don't starve
+the WRITE requests too much.
+
+Software description
+====================
+The requests are kept in queues according to their priority. The
+dispatching of requests is done in a Round Robin manner with a
+different slice for each queue. The dispatch quantum for a specific
+queue is defined according to the queues priority. READ queues are
+given bigger dispatch quantum than the WRITE queues, within a dispatch
+cycle.
+
+At the moment there are 6 types of queues the requests are
+distributed to:
+- High priority READ queue
+- High priority Synchronous WRITE queue
+- Regular priority READ queue
+- Regular priority Synchronous WRITE queue
+- Regular priority WRITE queue
+- Low priority READ queue
+
+If in a certain dispatch cycle one of the queues was empty and didn't
+use its quantum that queue will be marked as "un-served". If we're in a
+middle of a dispatch cycle dispatching from queue Y and a request
+arrives for queue X that was un-served in the previous cycle, if X's
+priority is higher than Y's, queue X will be preempted in the favor of
+queue Y. This won't mean that cycle is restarted. The "dispatched"
+counter of queue X will remain unchanged. Once queue Y uses up it's quantum
+(or there will be no more requests left on it) we'll switch back to queue X
+and allow it to finish it's quantum.
+
+For READ requests queues we allow idling in within a dispatch quantum in
+order to give the application a chance to insert more requests. Idling
+means adding some extra time for serving a certain queue even if the
+queue is empty. The idling is enabled if we identify the application is
+inserting requests in a high frequency.
+
+For idling on READ queues we use timer mechanism. When the timer expires,
+if there are requests in the scheduler we will signal the underlying driver
+(for example the MMC driver) to fetch another request for dispatch.
+
+The ROW algorithm takes the scheduling policy one step further, making
+it a bit more "user-needs oriented", by allowing the application to
+hint on the urgency of its requests. For example: even among the READ
+requests several requests may be more urgent for completion then others.
+The former will go to the High priority READ queue, that is given the
+bigger dispatch quantum than any other queue.
+
+ROW scheduler will support special services for block devices that
+supports High Priority Requests. That is, the scheduler may inform the
+device upon urgent requests using new callback make_urgent_request.
+In addition it will support rescheduling of requests that were
+interrupted. For example, if the device issues a long write request and
+a sudden high priority read interrupt pops in, the scheduler will
+inform the device about the urgent request, so the device can stop the
+current write request and serve the high priority read request. In such
+a case the device may also send back to the scheduler the reminder of
+the interrupted write request, such that the scheduler may continue
+sending high priority requests without the need to interrupt the
+ongoing write again and again. The write remainder will be sent later on
+according to the scheduler policy.
+
+Design
+======
+Existing algorithms (cfq, deadline) sort the io requests according LBA.
+When deciding on the next request to dispatch they choose the closest
+request to the current disk head position (from handling last
+dispatched request). This is done in order to reduce the disk head
+movement to a minimum.
+We feel that this functionality isn't really needed in mobile devices.
+Usually applications that write/read large chunks of data insert the
+requests in already sorted LBA order. Thus dealing with sort trees adds
+unnecessary complexity.
+
+We're planing to try this enhancement in the future to check if the
+performance is influenced by it.
+
+SMP/multi-core
+==============
+At the moment the code is acceded from 2 contexts:
+- Application context (from block/elevator layer): adding the requests.
+- Underlying driver context (for example the mmc driver thread): dispatching
+ the requests and notifying on completion.
+
+One lock is used to synchronize between the two. This lock is provided
+by the underlying driver along with the dispatch queue.
+
+Config options
+==============
+1. hp_read_quantum: dispatch quantum for the high priority READ queue
+2. rp_read_quantum: dispatch quantum for the regular priority READ queue
+3. hp_swrite_quantum: dispatch quantum for the high priority Synchronous
+ WRITE queue
+4. rp_swrite_quantum: dispatch quantum for the regular priority
+ Synchronous WRITE queue
+5. rp_write_quantum: dispatch quantum for the regular priority WRITE
+ queue
+6. lp_read_quantum: dispatch quantum for the low priority READ queue
+7. lp_swrite_quantum: dispatch quantum for the low priority Synchronous
+ WRITE queue
+8. read_idle: how long to idle on read queue in Msec (in case idling
+ is enabled on that queue).
+9. read_idle_freq: frequency of inserting READ requests that will
+ trigger idling. This is the time in Msec between inserting two READ
+ requests
+
diff --git a/Documentation/devicetree/bindings/cache/msm_cache_dump.txt b/Documentation/devicetree/bindings/cache/msm_cache_dump.txt
new file mode 100644
index 0000000..b7a68b5
--- /dev/null
+++ b/Documentation/devicetree/bindings/cache/msm_cache_dump.txt
@@ -0,0 +1,24 @@
+* Qualcomm Krait L1 / L2 cache dumping device
+This is a virtual device that dumps the contents of L1 and L2 caches in the
+event of a kernel panic or a watchdog trigger.
+
+Required properties:
+- compatible: Should be "qcom,cache_dump"
+- qcom,l1-dump-size: Amount of memory needed for L1 dump(s), in bytes
+- qcom,l2-dump-size: Amount of memory needed for L2 dump, in bytes
+- qcom,memory-reservation-size: Combined reserved memory for the dump buffers
+- qcom,memory-reservation-type: Type of memory to be reserved
+
+Optional properties:
+- qcom,use-imem-dump-offset: If specified, store cache dump buffer addresses
+ in IMEM rather than using the memory dump reservation table.
+
+Example:
+ qcom,cache_dump {
+ compatible = "qcom,cache_dump";
+ qcom,l1-dump-size = <0x100000>;
+ qcom,l2-dump-size = <0x400000>;
+ qcom,memory-reservation-type = "EBI1";
+ qcom,memory-reservation-size = <0x500000>;
+ };
+
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index 82e76fc..26bddd9 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -14,7 +14,7 @@
- qcom,mdss-pan-bpp: Specifies the panel bits per pixel. Default value is 24(rgb888).
18 = for rgb666
16 = for rgb565
-- qcom,panel-phy-regulatorSettings: An array of length 8 that specifies the PHY
+- qcom,panel-phy-regulatorSettings: An array of length 7 that specifies the PHY
regulator settings for the panel.
- qcom,panel-phy-timingSettings: An array of length 12 that specifies the PHY
timing settings for the panel.
diff --git a/Documentation/devicetree/bindings/hwmon/epm_adc.txt b/Documentation/devicetree/bindings/hwmon/epm_adc.txt
new file mode 100644
index 0000000..89edc16
--- /dev/null
+++ b/Documentation/devicetree/bindings/hwmon/epm_adc.txt
@@ -0,0 +1,25 @@
+Embedded Power Measurement(EPM) using Cypress Progammable System on a chip (PSOC)
+
+The EPM using the PSoC5 is used by clients to measure on target power
+measurement on supported channels. The PSoC5 is a microcontroller
+that is communicated over the SPI from the MSM. Primary configuration
+supports upto 31 channels and the scope of the driver is to support
+userspace clients.
+
+EPM node
+
+Required properties:
+- compatible : should be "qcom,epm-adc" for EPM using PSoC5.
+- reg : chip select for the device.
+- interrupt-parent : should be phandle of the interrupt controller
+ servicing the interrupt for this device.
+- spi-max-frequency : existing support is set for 960kHz.
+- qcom,channels : The number of voltage and current channels that
+ are supported.
+- qcom,gain : The gain for each of the supported channels.
+- qcom,rsense : The rsense value for each channel. The current channels
+ rsense values units are in milliohms. The voltage channels
+ rsense value is 1.
+- qcom,channel-type : Bitmak of channels to set as voltage and current.
+ These are platform dependent and the appropriate scaling
+ functions are used for returning voltage and current.
diff --git a/Documentation/devicetree/bindings/media/video/msm-wfd.txt b/Documentation/devicetree/bindings/media/video/msm-wfd.txt
new file mode 100644
index 0000000..0cd8c9d
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-wfd.txt
@@ -0,0 +1,11 @@
+* Qualcomm MSM Wifi Display (WFD)
+
+Required properties:
+- compatible :
+ - "qcom,msm-wfd"
+
+Example:
+
+ qcom,wfd {
+ compatible = "qcom,msm-wfd";
+ };
diff --git a/Documentation/devicetree/bindings/power/qpnp-bms.txt b/Documentation/devicetree/bindings/power/qpnp-bms.txt
new file mode 100644
index 0000000..1d3c2db
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/qpnp-bms.txt
@@ -0,0 +1,80 @@
+Qualcomm's QPNP PMIC Battery Management System driver
+
+QPNP PMIC BMS provides interface to clients to read properties related
+to the battery. It's main function is to calculate the State of Charge (SOC),
+a 0-100 percentage representing the amount of charge left in the battery.
+
+BMS node
+
+Required properties:
+- compatible : should be "qcom,qpnp-bms" for the BM driver.
+- reg : offset and length of the PMIC BMS register map.
+- interrupts : the interrupt mappings for bms.
+ The format should be
+ <slave-id peripheral-id interrupt-number>.
+- interrupt-names : names for the mapped bms interrupt
+ The following interrupts are required:
+ 0 : vsense_for_r
+ 1 : vsense_avg
+ 2 : sw_cc_thr
+ 3 : ocv_thr
+ 4 : charge_begin
+ 5 : good_ocv
+ 6 : ocv_for_r
+ 7 : cc_thr
+- qcom,bms-r-sense-mohm : sensor resistance in in milli-ohms.
+- qcom,bms-v-cutoff-uv : cutoff voltage where the battery is considered dead in
+ micro-volts.
+- qcom,bms-max-voltage-uv : maximum voltage for the battery in micro-volts.
+- qcom,bms-r-conn-mohm : connector resistance in milli-ohms.
+- qcom,bms-shutdown-soc-valid-limit : If the ocv upon restart is within this
+ distance of the shutdown ocv, the BMS will try to force
+ the new SoC to the old one to provide charge continuity.
+ That is to say,
+ if (abs(shutdown-soc - current-soc) < limit)
+ then use old SoC.
+- qcom,bms-adjust-soc-low-threshold : The low threshold for the "flat portion"
+ of the charging curve. The BMS will not adjust SoC
+ based on voltage during this time.
+- qcom,bms-adjust-soc-high-threshold : The high threshold for the "flat
+ portion" of the charging curve. The BMS will not
+ adjust SoC based on voltage during this time.
+- qcom,bms-chg-term-ua : current in micro-amps when charging is considered done.
+ As soon as current passes this point, charging is
+ stopped.
+
+Example:
+ bms@4000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ compatible = "qcom,qpnp-bms";
+ reg = <0x4000 0x100>;
+
+ interrupts = <0x0 0x40 0x0>,
+ <0x0 0x40 0x1>,
+ <0x0 0x40 0x2>,
+ <0x0 0x40 0x3>,
+ <0x0 0x40 0x4>,
+ <0x0 0x40 0x5>,
+ <0x0 0x40 0x6>,
+ <0x0 0x40 0x7>;
+
+ interrupt-names = "vsense_for_r",
+ "vsense_avg",
+ "sw_cc_thr",
+ "ocv_thr",
+ "charge_begin",
+ "good_ocv",
+ "ocv_for_r",
+ "cc_thr";
+
+ qcom,bms-r-sense-mohm = <10>;
+ qcom,bms-v-cutoff-uv = <3400000>;
+ qcom,bms-max-voltage-uv = <4200000>;
+ qcom,bms-r-conn-mohm = <18>;
+ qcom,bms-shutdown-soc-valid-limit = <20>;
+ qcom,bms-adjust-soc-low-threshold = <25>;
+ qcom,bms-adjust-soc-high-threshold = <45>;
+ qcom,bms-chg-term-ua = <100000>;
+ };
diff --git a/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
index 1f7e488..7731b33 100644
--- a/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
@@ -39,17 +39,17 @@
qcom,mdss-pan-dsi-dma-tr = <0x04>;
qcom,mdss-pan-frame-rate = <60>;
qcom,panel-phy-regulatorSettings = [03 01 01 00 /* Regualotor settings */
- 20 00 01 00];
+ 20 00 01];
qcom,panel-phy-timingSettings = [69 29 1f 00 55 55
19 2a 2a 03 04 00];
qcom,panel-phy-strengthCtrl = [77 06];
- qcom,panel-phy-bistCtrl = [00 00 01 ff /* BIST Ctrl settings */
+ qcom,panel-phy-bistCtrl = [00 00 b1 ff /* BIST Ctrl settings */
00 00];
- qcom,panel-phy-laneConfig = [05 c2 00 00 00 00 00 01 75 /* lane0 config */
- 05 c2 00 00 00 00 00 01 75 /* lane1 config */
- 05 c2 00 00 00 00 00 01 75 /* lane2 config */
- 05 c2 00 00 00 00 00 01 75 /* lane3 config */
- 00 c2 00 00 00 00 00 01 97]; /* Clk ln config */
+ qcom,panel-phy-laneConfig = [00 c2 45 00 00 00 00 01 75 /* lane0 config */
+ 00 c2 45 00 00 00 00 01 75 /* lane1 config */
+ 00 c2 45 00 00 00 00 01 75 /* lane2 config */
+ 00 c2 45 00 00 00 00 01 75 /* lane3 config */
+ 00 02 45 00 00 00 00 01 97]; /* Clk ln config */
qcom,panel-on-cmds = [23 01 00 00 0a 02 b0 00
23 01 00 00 0a 02 b2 00
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index facb1a8..8560f9f 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -49,6 +49,41 @@
};
};
+ bms@4000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ compatible = "qcom,qpnp-bms";
+ reg = <0x4000 0x100>;
+
+ interrupts = <0x0 0x40 0x0>,
+ <0x0 0x40 0x1>,
+ <0x0 0x40 0x2>,
+ <0x0 0x40 0x3>,
+ <0x0 0x40 0x4>,
+ <0x0 0x40 0x5>,
+ <0x0 0x40 0x6>,
+ <0x0 0x40 0x7>;
+
+ interrupt-names = "vsense_for_r",
+ "vsense_avg",
+ "sw_cc_thr",
+ "ocv_thr",
+ "charge_begin",
+ "good_ocv",
+ "ocv_for_r",
+ "cc_thr";
+
+ qcom,bms-r-sense-mohm = <10>;
+ qcom,bms-v-cutoff-uv = <3400000>;
+ qcom,bms-max-voltage-uv = <4200000>;
+ qcom,bms-r-conn-mohm = <18>;
+ qcom,bms-shutdown-soc-valid-limit = <20>;
+ qcom,bms-adjust-soc-low-threshold = <25>;
+ qcom,bms-adjust-soc-high-threshold = <45>;
+ qcom,bms-chg-term-ua = <100000>;
+ };
+
clkdiv@5b00 {
reg = <0x5b00 0x100>;
compatible = "qcom,qpnp-clkdiv";
@@ -67,6 +102,107 @@
qcom,cxo-freq = <19200000>;
};
+ pm8941-chg {
+ spmi-dev-container;
+ compatible = "qcom,qpnp-charger";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ qcom,chg-vddmax-mv = <4200>;
+ qcom,chg-vddsafe-mv = <4200>;
+ qcom,chg-vinmin-mv = <4200>;
+ qcom,chg-ibatmax-ma = <1500>;
+ qcom,chg-ibatterm-ma = <200>;
+
+ qcom,chg-chgr@1000 {
+ reg = <0x1000 0x100>;
+ interrupts = <0x0 0x10 0x0>,
+ <0x0 0x10 0x1>,
+ <0x0 0x10 0x2>,
+ <0x0 0x10 0x3>,
+ <0x0 0x10 0x4>,
+ <0x0 0x10 0x5>,
+ <0x0 0x10 0x6>,
+ <0x0 0x10 0x7>;
+
+ interrupt-names = "chg-done",
+ "chg-failed",
+ "fast-chg-on",
+ "trkl-chg-on",
+ "state-change",
+ "chgwdog",
+ "vbat-det-hi",
+ "vbat-det-lo";
+ };
+
+ qcom,chg-buck@1100 {
+ reg = <0x1100 0x100>;
+ interrupts = <0x0 0x11 0x0>,
+ <0x0 0x11 0x1>,
+ <0x0 0x11 0x2>,
+ <0x0 0x11 0x3>,
+ <0x0 0x11 0x4>,
+ <0x0 0x11 0x5>,
+ <0x0 0x11 0x6>;
+
+ interrupt-names = "vdd-loop",
+ "ibat-loop",
+ "ichg-loop",
+ "vchg-loop",
+ "overtemp",
+ "vref-ov",
+ "vbat-ov";
+ };
+
+ qcom,chg-bat-if@1200 {
+ reg = <0x1200 0x100>;
+ interrupts = <0x0 0x12 0x0>,
+ <0x0 0x12 0x1>,
+ <0x0 0x12 0x2>,
+ <0x0 0x12 0x3>,
+ <0x0 0x12 0x4>;
+
+ interrupt-names = "psi",
+ "vcp-on",
+ "bat-fet-on",
+ "bat-temp-ok",
+ "batt-pres";
+ };
+
+ qcom,chg-usb-chgpth@1300 {
+ reg = <0x1300 0x100>;
+ interrupts = <0 0x13 0x0>,
+ <0 0x13 0x1>,
+ <0x0 0x13 0x2>;
+
+ interrupt-names = "usbin-valid",
+ "coarse-det-usb",
+ "chg-gone";
+ };
+
+ qcom,chg-dc-chgpth@1400 {
+ reg = <0x1400 0x100>;
+ interrupts = <0x0 0x14 0x0>,
+ <0x0 0x14 0x1>;
+
+ interrupt-names = "dcin-valid",
+ "coarse-det-dc";
+ };
+
+ qcom,chg-boost@1500 {
+ reg = <0x1500 0x100>;
+ interrupts = <0x0 0x15 0x0>,
+ <0x0 0x15 0x1>;
+
+ interrupt-names = "limit-error",
+ "boost-pwr-ok";
+ };
+
+ qcom,chg-misc@1600 {
+ reg = <0x1600 0x100>;
+ };
+ };
+
pm8941_gpios {
spmi-dev-container;
compatible = "qcom,qpnp-pin";
diff --git a/arch/arm/boot/dts/msm8974-gpio.dtsi b/arch/arm/boot/dts/msm8974-gpio.dtsi
index e7c742c..dac87a3 100644
--- a/arch/arm/boot/dts/msm8974-gpio.dtsi
+++ b/arch/arm/boot/dts/msm8974-gpio.dtsi
@@ -109,6 +109,13 @@
gpio@d200 {
status = "ok";
+ qcom,mode = <1>; /* QPNP_PIN_MODE_DIG_OUT */
+ qcom,output-type = <0>; /* QPNP_PIN_OUT_BUF_CMOS */
+ qcom,pull = <5>; /* QPNP_PIN_PULL_NO */
+ qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
+ qcom,out-strength = <2>; /* QPNP_PIN_OUT_STRENGTH_MED */
+ qcom,src-select = <0>; /* QPNP_PIN_SEL_FUNC_CONSTANT */
+ qcom,master-en = <1>;
};
gpio@d300 {
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index fe60c83..da0e1e5 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -60,6 +60,10 @@
<244800 133330000>;
};
+ qcom,wfd {
+ compatible = "qcom,msm-wfd";
+ };
+
serial@f991f000 {
compatible = "qcom,msm-lsuart-v14";
reg = <0xf991f000 0x1000>;
@@ -860,6 +864,14 @@
interrupt-names = "l1_irq", "l2_irq";
};
+ qcom,cache_dump {
+ compatible = "qcom,cache_dump";
+ qcom,l1-dump-size = <0x100000>;
+ qcom,l2-dump-size = <0x500000>;
+ qcom,memory-reservation-type = "EBI1";
+ qcom,memory-reservation-size = <0x600000>; /* 6M EBI1 buffer */
+ };
+
tsens@fc4a8000 {
compatible = "qcom,msm-tsens";
reg = <0xfc4a8000 0x2000>,
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index 7b7adca..8ad3b66 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -55,7 +55,7 @@
compatible = "qcom,msm_sps";
reg = <0xf9984000 0x15000>,
<0xf9999000 0xb000>,
- <0xfe800000 0x4800>;
+ <0xfe803000 0x4800>;
interrupts = <0 94 0>;
qcom,device-type = <2>;
};
diff --git a/arch/arm/configs/fsm9xxx-perf_defconfig b/arch/arm/configs/fsm9xxx-perf_defconfig
index 4ba55de..93e84e9 100644
--- a/arch/arm/configs/fsm9xxx-perf_defconfig
+++ b/arch/arm/configs/fsm9xxx-perf_defconfig
@@ -39,6 +39,9 @@
# CONFIG_QSD_AUDIO is not set
# CONFIG_SURF_FFA_GPIO_KEYPAD is not set
CONFIG_MSM_WATCHDOG=y
+CONFIG_MSM_RPC_PMIC=y
+CONFIG_MSM_RPC_USB=y
+CONFIG_MSM_RPC_PMAPP=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_VMSPLIT_2G=y
diff --git a/arch/arm/configs/fsm9xxx_defconfig b/arch/arm/configs/fsm9xxx_defconfig
index ad1b6a6..c45063f 100644
--- a/arch/arm/configs/fsm9xxx_defconfig
+++ b/arch/arm/configs/fsm9xxx_defconfig
@@ -38,6 +38,9 @@
# CONFIG_QSD_AUDIO is not set
# CONFIG_SURF_FFA_GPIO_KEYPAD is not set
CONFIG_MSM_WATCHDOG=y
+CONFIG_MSM_RPC_PMIC=y
+CONFIG_MSM_RPC_USB=y
+CONFIG_MSM_RPC_PMAPP=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_VMSPLIT_2G=y
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index 7f10641..9a0bfba 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -55,6 +55,9 @@
CONFIG_MSM_MULTIMEDIA_USE_ION=y
CONFIG_MSM_CPR=y
CONFIG_MSM_VP_REGULATOR=y
+CONFIG_MSM_RPC_PMIC=y
+CONFIG_MSM_RPC_USB=y
+CONFIG_MSM_RPC_PMAPP=y
CONFIG_ARM_THUMBEE=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
diff --git a/arch/arm/configs/msm7627a_defconfig b/arch/arm/configs/msm7627a_defconfig
index 0e0653f..60a2d72 100644
--- a/arch/arm/configs/msm7627a_defconfig
+++ b/arch/arm/configs/msm7627a_defconfig
@@ -57,6 +57,9 @@
CONFIG_MSM_RTB_SEPARATE_CPUS=y
CONFIG_MSM_CPR=y
CONFIG_MSM_VP_REGULATOR=y
+CONFIG_MSM_RPC_PMIC=y
+CONFIG_MSM_RPC_USB=y
+CONFIG_MSM_RPC_PMAPP=y
CONFIG_ARM_THUMBEE=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
diff --git a/arch/arm/configs/msm7630-perf_defconfig b/arch/arm/configs/msm7630-perf_defconfig
index 1bf888b..401654d 100644
--- a/arch/arm/configs/msm7630-perf_defconfig
+++ b/arch/arm/configs/msm7630-perf_defconfig
@@ -44,6 +44,9 @@
CONFIG_MSM_IDLE_WAIT_ON_MODEM=2000
CONFIG_MSM_STANDALONE_POWER_COLLAPSE=y
CONFIG_MSM_MULTIMEDIA_USE_ION=y
+CONFIG_MSM_RPC_PMIC=y
+CONFIG_MSM_RPC_USB=y
+CONFIG_MSM_RPC_PMAPP=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_PREEMPT=y
@@ -278,6 +281,7 @@
CONFIG_FB_MSM_MDP40=y
CONFIG_FB_MSM_OVERLAY=y
CONFIG_FB_MSM_OVERLAY0_WRITEBACK=y
+CONFIG_FB_MSM_NO_MDP_PIPE_CTRL=y
CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM=y
CONFIG_FB_MSM_HDMI_ADV7520_PANEL=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
diff --git a/arch/arm/configs/msm7630_defconfig b/arch/arm/configs/msm7630_defconfig
index 5c5a152..0e066d9 100644
--- a/arch/arm/configs/msm7630_defconfig
+++ b/arch/arm/configs/msm7630_defconfig
@@ -44,6 +44,9 @@
CONFIG_MSM_IDLE_WAIT_ON_MODEM=2000
CONFIG_MSM_STANDALONE_POWER_COLLAPSE=y
CONFIG_MSM_MULTIMEDIA_USE_ION=y
+CONFIG_MSM_RPC_PMIC=y
+CONFIG_MSM_RPC_USB=y
+CONFIG_MSM_RPC_PMAPP=y
CONFIG_STRICT_MEMORY_RWX=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index db184cd..afe528d 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -391,6 +391,7 @@
CONFIG_FB_MSM_WRITEBACK_MSM_PANEL=y
CONFIG_FB_MSM_LVDS_MIPI_PANEL_DETECT=y
CONFIG_FB_MSM_HDMI_MSM_PANEL=y
+CONFIG_FB_MSM_HDMI_MHL_8334=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_BACKLIGHT_CLASS_DEVICE=y
CONFIG_SOUND=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 5415425..4c9383d 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -394,6 +394,7 @@
CONFIG_FB_MSM_WRITEBACK_MSM_PANEL=y
CONFIG_FB_MSM_LVDS_MIPI_PANEL_DETECT=y
CONFIG_FB_MSM_HDMI_MSM_PANEL=y
+CONFIG_FB_MSM_HDMI_MHL_8334=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_BACKLIGHT_CLASS_DEVICE=y
CONFIG_SOUND=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
new file mode 100644
index 0000000..392e062
--- /dev/null
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -0,0 +1,401 @@
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCALVERSION="-perf"
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_KALLSYMS_ALL=y
+CONFIG_ASHMEM=y
+CONFIG_EMBEDDED=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+CONFIG_KPROBES=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
+CONFIG_ARCH_MSM=y
+CONFIG_ARCH_MSM8974=y
+CONFIG_ARCH_MSM8226=y
+CONFIG_MSM_KRAIT_TBB_ABORT_HANDLER=y
+# CONFIG_MSM_STACKED_MEMORY is not set
+CONFIG_CPU_HAS_L2_PMU=y
+# CONFIG_MSM_FIQ_SUPPORT is not set
+# CONFIG_MSM_PROC_COMM is not set
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_PKG4=y
+CONFIG_MSM_BAM_DMUX=y
+CONFIG_MSM_IPC_ROUTER=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+# CONFIG_MSM_HW3D is not set
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_PIL_LPASS_QDSP6V5=y
+CONFIG_MSM_PIL_MSS_QDSP6V5=y
+CONFIG_MSM_PIL_MBA=y
+CONFIG_MSM_PIL_VENUS=y
+CONFIG_MSM_PIL_PRONTO=y
+CONFIG_MSM_MODEM_SSR_8974=y
+CONFIG_MSM_ADSP_SSR_8974=y
+CONFIG_MSM_TZ_LOG=y
+CONFIG_MSM_DIRECT_SCLK_ACCESS=y
+CONFIG_MSM_BUS_SCALING=y
+CONFIG_MSM_WATCHDOG_V2=y
+CONFIG_MSM_MEMORY_DUMP=y
+CONFIG_MSM_DLOAD_MODE=y
+CONFIG_MSM_ADSP_LOADER=m
+CONFIG_MSM_OCMEM=y
+CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
+CONFIG_MSM_OCMEM_DEBUG=y
+CONFIG_MSM_OCMEM_NONSECURE=y
+CONFIG_MSM_CACHE_ERP=y
+CONFIG_MSM_L1_ERR_PANIC=y
+CONFIG_MSM_L1_ERR_LOG=y
+CONFIG_MSM_L2_ERP_2BIT_PANIC=y
+CONFIG_STRICT_MEMORY_RWX=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+# CONFIG_SMP_ON_UP is not set
+CONFIG_ARM_ARCH_TIMER=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_VMALLOC_RESERVE=0x19000000
+CONFIG_CC_STACKPROTECTOR=y
+CONFIG_CP_ACCESS=y
+CONFIG_USE_OF=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_WAKELOCK=y
+CONFIG_PM_RUNTIME=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_CLS_FW=y
+CONFIG_NET_CLS_U32=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_FLOW=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=y
+CONFIG_NET_EMATCH_NBYTE=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_EMATCH_META=y
+CONFIG_NET_EMATCH_TEXT=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_BT=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=y
+CONFIG_BT_HCISMD=y
+CONFIG_MSM_BT_POWER=y
+CONFIG_CFG80211=m
+CONFIG_RFKILL=y
+CONFIG_GENLOCK=y
+CONFIG_GENLOCK_MISCDEVICE=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_QSEECOM=y
+CONFIG_SCSI=y
+CONFIG_SCSI_TGT=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_TUN=y
+CONFIG_KS8851=m
+# CONFIG_MSM_RMNET is not set
+CONFIG_MSM_RMNET_BAM=y
+CONFIG_SLIP=y
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_MODE_SLIP6=y
+CONFIG_WCNSS_CORE=y
+CONFIG_WCNSS_CORE_PRONTO=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ATMEL_MXT=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_SERIAL_MSM_HSL=y
+CONFIG_SERIAL_MSM_HSL_CONSOLE=y
+CONFIG_DIAG_CHAR=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_QUP=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=m
+CONFIG_SPMI=y
+CONFIG_SPMI_MSM_PMIC_ARB=y
+CONFIG_MSM_QPNP_INT=y
+CONFIG_SLIMBUS_MSM_CTRL=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_QPNP_PIN=y
+CONFIG_GPIO_QPNP_PIN_DEBUG=y
+CONFIG_POWER_SUPPLY=y
+# CONFIG_BATTERY_MSM is not set
+CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
+CONFIG_SENSORS_QPNP_ADC_CURRENT=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_TSENS8974=y
+CONFIG_WCD9320_CODEC=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_STUB=y
+CONFIG_REGULATOR_QPNP=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_VIDEOBUF2_MSM_MEM=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_MSM_CAMERA_V4L2=y
+CONFIG_OV2720=y
+CONFIG_MSM_CAMERA_SENSOR=y
+CONFIG_MSM_ACTUATOR=y
+CONFIG_MSM_JPEG=y
+CONFIG_MSM_CCI=y
+CONFIG_MSM_CSI30_HEADER=y
+CONFIG_MSM_CSIPHY=y
+CONFIG_MSM_CSID=y
+CONFIG_MSM_CSI2_REGISTER=y
+CONFIG_MSM_ISPIF=y
+CONFIG_S5K3L1YX=y
+CONFIG_RADIO_IRIS=y
+CONFIG_RADIO_IRIS_TRANSPORT=m
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_MSM_KGSL=y
+CONFIG_FB=y
+CONFIG_FB_MSM=y
+# CONFIG_FB_MSM_BACKLIGHT is not set
+CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_WRITEBACK=y
+CONFIG_FB_MSM_MDSS_HDMI_PANEL=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_MSM8974=y
+CONFIG_USB=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_STORAGE_ALAUDA=y
+CONFIG_USB_STORAGE_ONETOUCH=y
+CONFIG_USB_STORAGE_KARMA=y
+CONFIG_USB_STORAGE_CYPRESS_ATACB=y
+CONFIG_USB_STORAGE_ENE_UB6250=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_CI13XXX_MSM=y
+CONFIG_USB_G_ANDROID=y
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_BLOCK_MINORS=32
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_TEST=m
+CONFIG_MMC_MSM=y
+CONFIG_MMC_MSM_SPS_SUPPORT=y
+CONFIG_LEDS_QPNP=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_BACKLIGHT=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+CONFIG_SWITCH=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_DRV_MSM is not set
+CONFIG_RTC_DRV_QPNP=y
+CONFIG_STAGING=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_RAM_CONSOLE=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_MSM_SSBI=y
+CONFIG_SPS=y
+CONFIG_USB_BAM=y
+CONFIG_SPS_SUPPORT_BAMDMA=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_QPNP_POWER_ON=y
+CONFIG_QPNP_CLKDIV=y
+CONFIG_MSM_IOMMU=y
+CONFIG_MSM_QDSS=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_ENABLE_DEFAULT_TRACERS=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_USER=y
+CONFIG_PID_IN_CONTEXTIDR=y
+CONFIG_KEYS=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_DEV_QCRYPTO=m
+CONFIG_CRYPTO_DEV_QCE=m
+CONFIG_CRYPTO_DEV_QCEDEV=m
+CONFIG_CRC_CCITT=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 471ecd9..d54e19e 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -20,14 +20,18 @@
CONFIG_BLK_DEV_INITRD=y
CONFIG_RD_BZIP2=y
CONFIG_RD_LZMA=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_PANIC_TIMEOUT=5
CONFIG_KALLSYMS_ALL=y
CONFIG_ASHMEM=y
CONFIG_EMBEDDED=y
CONFIG_PROFILING=y
-CONFIG_OPROFILE=m
+CONFIG_OPROFILE=y
+CONFIG_KPROBES=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
CONFIG_PARTITION_ADVANCED=y
CONFIG_EFI_PARTITION=y
CONFIG_ARCH_MSM=y
@@ -35,39 +39,41 @@
CONFIG_ARCH_MSM8226=y
CONFIG_MSM_KRAIT_TBB_ABORT_HANDLER=y
# CONFIG_MSM_STACKED_MEMORY is not set
-CONFIG_KERNEL_PMEM_EBI_REGION=y
CONFIG_CPU_HAS_L2_PMU=y
# CONFIG_MSM_FIQ_SUPPORT is not set
# CONFIG_MSM_PROC_COMM is not set
CONFIG_MSM_SMD=y
CONFIG_MSM_SMD_PKG4=y
+CONFIG_MSM_BAM_DMUX=y
CONFIG_MSM_IPC_ROUTER=y
CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
# CONFIG_MSM_HW3D is not set
+CONFIG_MSM_SUBSYSTEM_RESTART=y
CONFIG_MSM_PIL_LPASS_QDSP6V5=y
CONFIG_MSM_PIL_MSS_QDSP6V5=y
CONFIG_MSM_PIL_MBA=y
CONFIG_MSM_PIL_VENUS=y
CONFIG_MSM_PIL_PRONTO=y
-CONFIG_MSM_SUBSYSTEM_RESTART=y
CONFIG_MSM_MODEM_SSR_8974=y
CONFIG_MSM_ADSP_SSR_8974=y
CONFIG_MSM_TZ_LOG=y
CONFIG_MSM_DIRECT_SCLK_ACCESS=y
-CONFIG_MSM_QDSS=y
+CONFIG_MSM_BUS_SCALING=y
+CONFIG_MSM_WATCHDOG_V2=y
+CONFIG_MSM_MEMORY_DUMP=y
+CONFIG_MSM_DLOAD_MODE=y
+CONFIG_MSM_ADSP_LOADER=m
CONFIG_MSM_OCMEM=y
CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
CONFIG_MSM_OCMEM_DEBUG=y
CONFIG_MSM_OCMEM_NONSECURE=y
-CONFIG_MSM_MEMORY_DUMP=y
-CONFIG_MSM_WATCHDOG_V2=y
-CONFIG_MSM_DLOAD_MODE=y
-CONFIG_PANIC_TIMEOUT=5
CONFIG_MSM_CACHE_ERP=y
CONFIG_MSM_L1_ERR_PANIC=y
+CONFIG_MSM_L1_ERR_LOG=y
CONFIG_MSM_L2_ERP_PRINT_ACCESS_ERRORS=y
+CONFIG_MSM_L2_ERP_1BIT_PANIC=y
CONFIG_MSM_L2_ERP_2BIT_PANIC=y
-CONFIG_MSM_ADSP_LOADER=m
+CONFIG_STRICT_MEMORY_RWX=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_SMP=y
@@ -77,6 +83,8 @@
CONFIG_AEABI=y
CONFIG_HIGHMEM=y
CONFIG_VMALLOC_RESERVE=0x19000000
+CONFIG_CC_STACKPROTECTOR=y
+CONFIG_CP_ACCESS=y
CONFIG_USE_OF=y
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
@@ -113,10 +121,100 @@
CONFIG_IPV6_MIP6=y
CONFIG_IPV6_MULTIPLE_TABLES=y
CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_HTB=y
CONFIG_NET_SCH_PRIO=y
CONFIG_NET_CLS_FW=y
+CONFIG_NET_CLS_U32=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_FLOW=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=y
+CONFIG_NET_EMATCH_NBYTE=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_EMATCH_META=y
+CONFIG_NET_EMATCH_TEXT=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_BT=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=y
+CONFIG_BT_HCISMD=y
+CONFIG_MSM_BT_POWER=y
+CONFIG_CFG80211=m
+CONFIG_RFKILL=y
CONFIG_GENLOCK=y
CONFIG_GENLOCK_MISCDEVICE=y
CONFIG_BLK_DEV_LOOP=y
@@ -136,15 +234,20 @@
CONFIG_DM_CRYPT=y
CONFIG_NETDEVICES=y
CONFIG_DUMMY=y
+CONFIG_TUN=y
CONFIG_KS8851=m
# CONFIG_MSM_RMNET is not set
CONFIG_MSM_RMNET_BAM=y
+CONFIG_SLIP=y
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_MODE_SLIP6=y
+CONFIG_WCNSS_CORE=y
+CONFIG_WCNSS_CORE_PRONTO=y
CONFIG_INPUT_EVDEV=y
CONFIG_INPUT_EVBUG=m
CONFIG_KEYBOARD_GPIO=y
CONFIG_INPUT_JOYSTICK=y
CONFIG_INPUT_TOUCHSCREEN=y
-CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH=n
CONFIG_TOUCHSCREEN_ATMEL_MXT=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_UINPUT=y
@@ -156,14 +259,12 @@
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_QUP=y
-CONFIG_MSM_BUS_SCALING=y
CONFIG_SPI=y
CONFIG_SPI_QUP=y
CONFIG_SPI_SPIDEV=m
CONFIG_SPMI=y
CONFIG_SPMI_MSM_PMIC_ARB=y
CONFIG_MSM_QPNP_INT=y
-CONFIG_SLIMBUS=y
CONFIG_SLIMBUS_MSM_CTRL=y
CONFIG_DEBUG_GPIO=y
CONFIG_GPIO_SYSFS=y
@@ -171,11 +272,12 @@
CONFIG_GPIO_QPNP_PIN_DEBUG=y
CONFIG_POWER_SUPPLY=y
# CONFIG_BATTERY_MSM is not set
-CONFIG_HWMON=y
CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
CONFIG_SENSORS_QPNP_ADC_CURRENT=y
+CONFIG_QPNP_BMS=y
CONFIG_THERMAL=y
CONFIG_THERMAL_TSENS8974=y
+CONFIG_WCD9320_CODEC=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_STUB=y
CONFIG_REGULATOR_QPNP=y
@@ -186,9 +288,11 @@
CONFIG_VIDEOBUF2_MSM_MEM=y
CONFIG_V4L_PLATFORM_DRIVERS=y
CONFIG_MSM_CAMERA_V4L2=y
+CONFIG_MSM_WFD=y
+CONFIG_OV2720=y
CONFIG_MSM_CAMERA_SENSOR=y
CONFIG_MSM_ACTUATOR=y
-CONFIG_MSM_CAM_IRQ_ROUTER=n
+CONFIG_MSM_JPEG=y
CONFIG_MSM_CCI=y
CONFIG_MSM_CSI30_HEADER=y
CONFIG_MSM_CSIPHY=y
@@ -196,11 +300,8 @@
CONFIG_MSM_CSI2_REGISTER=y
CONFIG_MSM_ISPIF=y
CONFIG_S5K3L1YX=y
-CONFIG_OV2720=y
-CONFIG_MSM_JPEG=y
CONFIG_RADIO_IRIS=y
CONFIG_RADIO_IRIS_TRANSPORT=m
-CONFIG_RADIO_ADAPTERS=y
CONFIG_ION=y
CONFIG_ION_MSM=y
CONFIG_MSM_KGSL=y
@@ -218,7 +319,6 @@
CONFIG_SND=y
CONFIG_SND_SOC=y
CONFIG_SND_SOC_MSM8974=y
-CONFIG_WCD9320_CODEC=y
CONFIG_USB=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_STORAGE=y
@@ -248,8 +348,6 @@
CONFIG_MMC_TEST=m
CONFIG_MMC_MSM=y
CONFIG_MMC_MSM_SPS_SUPPORT=y
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=y
CONFIG_LEDS_QPNP=y
CONFIG_LEDS_TRIGGERS=y
CONFIG_LEDS_TRIGGER_BACKLIGHT=y
@@ -273,6 +371,7 @@
CONFIG_QPNP_POWER_ON=y
CONFIG_QPNP_CLKDIV=y
CONFIG_MSM_IOMMU=y
+CONFIG_MSM_QDSS=y
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT3_FS=y
@@ -286,48 +385,34 @@
CONFIG_NLS_ISO8859_1=y
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_FS=y
+CONFIG_LOCKUP_DETECTOR=y
+# CONFIG_DETECT_HUNG_TASK is not set
# CONFIG_SCHED_DEBUG is not set
CONFIG_TIMER_STATS=y
+CONFIG_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
# CONFIG_DEBUG_PREEMPT is not set
+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
+CONFIG_PID_IN_CONTEXTIDR=y
CONFIG_KEYS=y
CONFIG_CRYPTO_MD4=y
-CONFIG_CRYPTO_SHA256=y
-CONFIG_CRYPTO_AES=y
CONFIG_CRYPTO_ARC4=y
CONFIG_CRYPTO_TWOFISH=y
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=m
CONFIG_CRYPTO_DEV_QCEDEV=m
CONFIG_CRC_CCITT=y
-CONFIG_LIBCRC32C=y
-
-CONFIG_BT=y
-CONFIG_BT_L2CAP=y
-CONFIG_BT_SCO=y
-CONFIG_BT_RFCOMM=y
-CONFIG_BT_RFCOMM_TTY=y
-CONFIG_BT_BNEP=y
-CONFIG_BT_BNEP_MC_FILTER=y
-CONFIG_BT_BNEP_PROTO_FILTER=y
-CONFIG_BT_HIDP=y
-
-CONFIG_BT_HCISMD=y
-CONFIG_MSM_BT_POWER=y
-
-CONFIG_RADIO_IRIS=y
-CONFIG_RADIO_IRIS_TRANSPORT=m
-CONFIG_MSM_BAM_DMUX=y
-CONFIG_WCNSS_CORE=y
-CONFIG_WCNSS_CORE_PRONTO=y
-CONFIG_CFG80211=m
-CONFIG_RFKILL=y
-CONFIG_VIDEO_V4L2=y
-CONFIG_VIDEO_DEV=y
-CONFIG_VIDEO_V4L2_COMMON=y
-CONFIG_VIDEO_MEDIA=y
diff --git a/arch/arm/mach-msm/cp14.h b/arch/arm/include/asm/hardware/cp14.h
similarity index 99%
rename from arch/arm/mach-msm/cp14.h
rename to arch/arm/include/asm/hardware/cp14.h
index d640412..8acf0c7 100644
--- a/arch/arm/mach-msm/cp14.h
+++ b/arch/arm/include/asm/hardware/cp14.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -10,8 +10,8 @@
* GNU General Public License for more details.
*/
-#ifndef _ARCH_ARM_MACH_MSM_CP14_H_
-#define _ARCH_ARM_MACH_MSM_CP14_H_
+#ifndef __ASM_HARDWARE_CP14_H
+#define __ASM_HARDWARE_CP14_H
#include <linux/types.h>
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 63d402f..1e9504b 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -37,6 +37,8 @@
#include "signal.h"
+#include <trace/events/exception.h>
+
static const char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" };
void *vectors_page;
@@ -410,6 +412,8 @@
if (call_undef_hook(regs, instr) == 0)
return;
+ trace_undef_instr(regs, (void *)pc);
+
#ifdef CONFIG_DEBUG_USER
if (user_debug & UDBG_UNDEFINED) {
printk(KERN_INFO "%s (%d): undefined instruction: pc=%p\n",
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index c9b786c..2efba47 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -2607,4 +2607,31 @@
can be read and written to send character data to the sysmon port of
the modem over USB.
+config MSM_RPC_PMIC
+ tristate "MSM RPC PMIC driver"
+ depends on MSM_ONCRPCROUTER
+ help
+ This driver supports the PMIC functionality over RPC for those MSM's
+ which do not have a direct access to PMIC. It supports ability to
+ configure MPP, GPIO and all the other supported peripherals of the
+ PMIC.
+
+config MSM_RPC_USB
+ tristate "MSM RPC USB driver"
+ depends on MSM_ONCRPCROUTER
+ help
+ This driver supports the USB configuration support over the RPC
+ interface. It support the HS USB module connected to the MSM
+ and FS USB which is connected over the PMIC. This support is
+ required for MSMs on which the APPS does not have a direct access
+ to the PMIC.
+
+config MSM_RPC_PMAPP
+ tristate "MSM RPC PMIC APP driver"
+ depends on MSM_ONCRPCROUTER
+ help
+ This driver supports the configuration of various PMIC APP modules
+ such as display backlight, vreg pin-ctrl, smps clock over the RPC
+ interface. This support is required for MSMs on which the APPS
+ does not have a direct access to the PMIC.
endif
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index d8e625a..3c44a06 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -98,20 +98,6 @@
endif
obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o remote_spinlock.o smd_private.o
obj-y += socinfo.o
-ifndef CONFIG_ARCH_MSM9615
-ifndef CONFIG_ARCH_APQ8064
-ifndef CONFIG_ARCH_MSM8960
-ifndef CONFIG_ARCH_MSM8X60
-ifndef CONFIG_ARCH_MSM8974
-ifndef CONFIG_ARCH_MPQ8092
- obj-$(CONFIG_MSM_SMD) += pmic.o
- obj-$(CONFIG_MSM_ONCRPCROUTER) += rpc_hsusb.o rpc_pmapp.o rpc_fsusb.o
-endif
-endif
-endif
-endif
-endif
-endif
ifndef CONFIG_ARCH_MSM8960
ifndef CONFIG_ARCH_MSM8X60
ifndef CONFIG_ARCH_APQ8064
@@ -393,6 +379,10 @@
obj-$(CONFIG_MSM_RPM_SMD) += rpm-smd.o
obj-$(CONFIG_MSM_CPR) += msm_cpr.o
obj-$(CONFIG_MSM_VP_REGULATOR) += msm_vp.o
+obj-$(CONFIG_MSM_RPC_PMIC) += pmic.o
+obj-$(CONFIG_MSM_RPC_USB) += rpc_hsusb.o rpc_fsusb.o
+obj-$(CONFIG_MSM_RPC_PMAPP) += rpc_pmapp.o
+
ifdef CONFIG_MSM_CPR
obj-$(CONFIG_DEBUG_FS) += msm_cpr-debug.o
diff --git a/arch/arm/mach-msm/acpuclock-7627.c b/arch/arm/mach-msm/acpuclock-7627.c
index 1a2ae48..6788cbe 100644
--- a/arch/arm/mach-msm/acpuclock-7627.c
+++ b/arch/arm/mach-msm/acpuclock-7627.c
@@ -32,13 +32,13 @@
#include <mach/board.h>
#include <mach/msm_iomap.h>
+#include <mach/clk-provider.h>
#include <mach/socinfo.h>
#include <asm/mach-types.h>
#include <asm/cpu.h>
#include "smd_private.h"
#include "acpuclock.h"
-#include "clock.h"
#define A11S_CLK_CNTL_ADDR (MSM_CSR_BASE + 0x100)
#define A11S_CLK_SEL_ADDR (MSM_CSR_BASE + 0x104)
diff --git a/arch/arm/mach-msm/acpuclock-7x30.c b/arch/arm/mach-msm/acpuclock-7x30.c
index b49613e..5b947e6 100644
--- a/arch/arm/mach-msm/acpuclock-7x30.c
+++ b/arch/arm/mach-msm/acpuclock-7x30.c
@@ -32,7 +32,6 @@
#include <asm/mach-types.h>
#include "smd_private.h"
-#include "clock.h"
#include "acpuclock.h"
#include "spm.h"
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 1a02fce..d5e4638 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -1809,6 +1809,10 @@
in_global_reset = 0;
vote_dfab();
if (!power_management_only_mode) {
+ sps_disconnect(bam_tx_pipe);
+ sps_disconnect(bam_rx_pipe);
+ __memzero(rx_desc_mem_buf.base, rx_desc_mem_buf.size);
+ __memzero(tx_desc_mem_buf.base, tx_desc_mem_buf.size);
i = sps_device_reset(a2_device_handle);
if (i)
pr_err("%s: device reset failed rc = %d\n", __func__,
@@ -1861,12 +1865,6 @@
/* tear down BAM connection */
INIT_COMPLETION(bam_connection_completion);
- if (!power_management_only_mode) {
- sps_disconnect(bam_tx_pipe);
- sps_disconnect(bam_rx_pipe);
- __memzero(rx_desc_mem_buf.base, rx_desc_mem_buf.size);
- __memzero(tx_desc_mem_buf.base, tx_desc_mem_buf.size);
- }
unvote_dfab();
mutex_lock(&bam_rx_pool_mutexlock);
diff --git a/arch/arm/mach-msm/board-8064-camera.c b/arch/arm/mach-msm/board-8064-camera.c
index bc1eded..c79f82f 100644
--- a/arch/arm/mach-msm/board-8064-camera.c
+++ b/arch/arm/mach-msm/board-8064-camera.c
@@ -396,11 +396,13 @@
static struct msm_camera_device_platform_data msm_camera_csi_device_data[] = {
{
+ .csiphy_core = 0,
.csid_core = 0,
.is_vpe = 1,
.cam_bus_scale_table = &cam_bus_client_pdata,
},
{
+ .csiphy_core = 1,
.csid_core = 1,
.is_vpe = 1,
.cam_bus_scale_table = &cam_bus_client_pdata,
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 8755f08..07acac6 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -78,6 +78,7 @@
#include "msm_watchdog.h"
#include "board-8064.h"
+#include "clock.h"
#include "spm.h"
#include <mach/mpm.h>
#include "rpm_resources.h"
diff --git a/arch/arm/mach-msm/board-8226.c b/arch/arm/mach-msm/board-8226.c
index c845a3a..9545c7a 100644
--- a/arch/arm/mach-msm/board-8226.c
+++ b/arch/arm/mach-msm/board-8226.c
@@ -40,6 +40,7 @@
#include <mach/msm_memtypes.h>
#include <mach/socinfo.h>
#include <mach/board.h>
+#include <mach/clk-provider.h>
#include "clock.h"
static struct clk_lookup msm_clocks_dummy[] = {
diff --git a/arch/arm/mach-msm/board-8930-camera.c b/arch/arm/mach-msm/board-8930-camera.c
index 883e04d..eb00f34 100644
--- a/arch/arm/mach-msm/board-8930-camera.c
+++ b/arch/arm/mach-msm/board-8930-camera.c
@@ -392,11 +392,13 @@
static struct msm_camera_device_platform_data msm_camera_csi_device_data[] = {
{
+ .csiphy_core = 0,
.csid_core = 0,
.is_vpe = 1,
.cam_bus_scale_table = &cam_bus_client_pdata,
},
{
+ .csiphy_core = 1,
.csid_core = 1,
.is_vpe = 1,
.cam_bus_scale_table = &cam_bus_client_pdata,
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index aad0f3d..ab35948 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -96,6 +96,7 @@
#include <mach/cpuidle.h>
#include "rpm_resources.h"
#include <mach/mpm.h>
+#include "clock.h"
#include "smd_private.h"
#include "pm-boot.h"
#include "msm_watchdog.h"
diff --git a/arch/arm/mach-msm/board-8960-camera.c b/arch/arm/mach-msm/board-8960-camera.c
index 792eea4..9bb6e09 100644
--- a/arch/arm/mach-msm/board-8960-camera.c
+++ b/arch/arm/mach-msm/board-8960-camera.c
@@ -474,16 +474,19 @@
static struct msm_camera_device_platform_data msm_camera_csi_device_data[] = {
{
+ .csiphy_core = 0,
.csid_core = 0,
.is_vpe = 1,
.cam_bus_scale_table = &cam_bus_client_pdata,
},
{
+ .csiphy_core = 1,
.csid_core = 1,
.is_vpe = 1,
.cam_bus_scale_table = &cam_bus_client_pdata,
},
{
+ .csiphy_core = 2,
.csid_core = 2,
.is_vpe = 1,
.cam_bus_scale_table = &cam_bus_client_pdata,
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index 244125c..ae74285 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -249,8 +249,8 @@
static const unsigned int keymap[] = {
KEY(0, 0, KEY_VOLUMEUP),
KEY(0, 1, KEY_VOLUMEDOWN),
- KEY(0, 2, KEY_CAMERA_SNAPSHOT),
- KEY(0, 3, KEY_CAMERA_FOCUS),
+ KEY(0, 2, KEY_CAMERA_FOCUS),
+ KEY(0, 3, KEY_CAMERA_SNAPSHOT),
};
static struct matrix_keymap_data keymap_data = {
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 06efc03..8ed9666 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -98,6 +98,7 @@
#include <mach/cpuidle.h>
#include "rpm_resources.h"
#include <mach/mpm.h>
+#include "clock.h"
#include "smd_private.h"
#include "pm-boot.h"
#include "msm_watchdog.h"
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index 4523cf7..ca95b62 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -50,6 +50,7 @@
#include "devices.h"
#include "board-9615.h"
#include "pm.h"
+#include "clock.h"
#include "pm-boot.h"
#include <mach/gpiomux.h>
#include "ci13xxx_udc.h"
diff --git a/arch/arm/mach-msm/board-9625.c b/arch/arm/mach-msm/board-9625.c
index e7ef1a9..99b9f16 100644
--- a/arch/arm/mach-msm/board-9625.c
+++ b/arch/arm/mach-msm/board-9625.c
@@ -29,6 +29,7 @@
#include <mach/socinfo.h>
#include <mach/board.h>
#include <mach/gpio.h>
+#include <mach/clk-provider.h>
#include "clock.h"
#define L2CC_AUX_CTRL ((0x1 << L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT) | \
diff --git a/arch/arm/mach-msm/board-fsm9xxx.c b/arch/arm/mach-msm/board-fsm9xxx.c
index 24d54e4..b4f6968 100644
--- a/arch/arm/mach-msm/board-fsm9xxx.c
+++ b/arch/arm/mach-msm/board-fsm9xxx.c
@@ -38,6 +38,7 @@
#include <mach/socinfo.h>
#include "devices.h"
#include "timer.h"
+#include "clock.h"
#include "pm.h"
#include "spm.h"
#include <linux/regulator/consumer.h>
diff --git a/arch/arm/mach-msm/board-msm7627a-camera.c b/arch/arm/mach-msm/board-msm7627a-camera.c
index 7a1e2ff..b5f214b 100644
--- a/arch/arm/mach-msm/board-msm7627a-camera.c
+++ b/arch/arm/mach-msm/board-msm7627a-camera.c
@@ -139,12 +139,14 @@
struct msm_camera_device_platform_data msm_camera_device_data_csi1[] = {
{
+ .csiphy_core = 1,
.csid_core = 1,
.ioclk = {
.vfe_clk_rate = 192000000,
},
},
{
+ .csiphy_core = 1,
.csid_core = 1,
.ioclk = {
.vfe_clk_rate = 266667000,
@@ -154,12 +156,14 @@
struct msm_camera_device_platform_data msm_camera_device_data_csi0[] = {
{
+ .csiphy_core = 0,
.csid_core = 0,
.ioclk = {
.vfe_clk_rate = 192000000,
},
},
{
+ .csiphy_core = 0,
.csid_core = 0,
.ioclk = {
.vfe_clk_rate = 266667000,
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index f16751d..205db58 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -82,6 +82,7 @@
#include "pm-boot.h"
#include "spm.h"
#include "acpuclock.h"
+#include "clock.h"
#include <mach/dal_axi.h>
#include <mach/msm_serial_hs.h>
#include <mach/qdsp5v2/mi2s.h>
@@ -884,6 +885,7 @@
#ifdef CONFIG_MSM_CAMERA_V4L2
static struct msm_camera_device_platform_data msm_camera_csi_device_data[] = {
{
+ .csiphy_core = 0,
.csid_core = 0,
.is_vpe = 1,
.ioclk = {
@@ -891,6 +893,7 @@
},
},
{
+ .csiphy_core = 0,
.csid_core = 0,
.is_vpe = 1,
.ioclk = {
diff --git a/arch/arm/mach-msm/board-msm8x60-camera.c b/arch/arm/mach-msm/board-msm8x60-camera.c
index acd7f74..7e5f022 100644
--- a/arch/arm/mach-msm/board-msm8x60-camera.c
+++ b/arch/arm/mach-msm/board-msm8x60-camera.c
@@ -360,6 +360,7 @@
static struct msm_camera_device_platform_data msm_camera_csi_device_data[] = {
{
+ .csiphy_core = 0,
.csid_core = 0,
.is_vpe = 1,
.cam_bus_scale_table = &cam_bus_client_pdata,
@@ -368,6 +369,7 @@
},
},
{
+ .csiphy_core = 1,
.csid_core = 1,
.is_vpe = 1,
.cam_bus_scale_table = &cam_bus_client_pdata,
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 281d055..a889d39 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -100,6 +100,7 @@
#include "peripheral-loader.h"
#include <linux/platform_data/qcom_crypto_device.h>
#include "rpm_resources.h"
+#include "clock.h"
#include "pm-boot.h"
#include "board-storage-common-a.h"
diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c
index 4df4266..146c8a8 100644
--- a/arch/arm/mach-msm/board-qsd8x50.c
+++ b/arch/arm/mach-msm/board-qsd8x50.c
@@ -55,6 +55,7 @@
#include "timer.h"
#include "msm-keypad-devices.h"
#include "acpuclock.h"
+#include "clock.h"
#include "pm.h"
#include "irq.h"
#include "pm-boot.h"
diff --git a/arch/arm/mach-msm/clock-7x30.c b/arch/arm/mach-msm/clock-7x30.c
index 8cce34b..e42fe65 100644
--- a/arch/arm/mach-msm/clock-7x30.c
+++ b/arch/arm/mach-msm/clock-7x30.c
@@ -24,7 +24,6 @@
#include <linux/string.h>
#include <mach/msm_iomap.h>
-#include <mach/clk.h>
#include <mach/proc_comm.h>
#include "clock.h"
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 6ddb462..9ff039f0 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -24,10 +24,10 @@
#include <asm/mach-types.h>
#include <mach/msm_iomap.h>
-#include <mach/clk.h>
#include <mach/rpm-regulator.h>
#include <mach/socinfo.h>
+#include "clock.h"
#include "clock-local.h"
#include "clock-rpm.h"
#include "clock-voter.h"
@@ -5330,6 +5330,7 @@
CLK_LOOKUP("cam_clk", cam0_clk.c, "4-0020"),
CLK_LOOKUP("cam_clk", cam1_clk.c, "4-0048"),
CLK_LOOKUP("cam_clk", cam1_clk.c, "4-006c"),
+ CLK_LOOKUP("cam_clk", cam2_clk.c, ""),
CLK_LOOKUP("csi_src_clk", csi0_src_clk.c, "msm_csid.0"),
CLK_LOOKUP("csi_src_clk", csi1_src_clk.c, "msm_csid.1"),
CLK_LOOKUP("csi_src_clk", csi2_src_clk.c, "msm_csid.2"),
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 62e8f0f..ca0dd20 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -20,7 +20,6 @@
#include <linux/clk.h>
#include <linux/iopoll.h>
-#include <mach/clk.h>
#include <mach/rpm-regulator-smd.h>
#include <mach/socinfo.h>
#include <mach/rpm-smd.h>
@@ -30,6 +29,7 @@
#include "clock-rpm.h"
#include "clock-voter.h"
#include "clock-mdss-8974.h"
+#include "clock.h"
enum {
GCC_BASE,
diff --git a/arch/arm/mach-msm/clock-8x60.c b/arch/arm/mach-msm/clock-8x60.c
index 24c06c9..6ae66fe 100644
--- a/arch/arm/mach-msm/clock-8x60.c
+++ b/arch/arm/mach-msm/clock-8x60.c
@@ -23,11 +23,11 @@
#include <linux/clkdev.h>
#include <mach/msm_iomap.h>
-#include <mach/clk.h>
#include <mach/scm-io.h>
#include <mach/rpm.h>
#include <mach/rpm-regulator.h>
+#include "clock.h"
#include "clock-local.h"
#include "clock-rpm.h"
#include "clock-voter.h"
diff --git a/arch/arm/mach-msm/clock-9615.c b/arch/arm/mach-msm/clock-9615.c
index 15eaa4b..fee8445 100644
--- a/arch/arm/mach-msm/clock-9615.c
+++ b/arch/arm/mach-msm/clock-9615.c
@@ -24,10 +24,10 @@
#include <asm/mach-types.h>
#include <mach/msm_iomap.h>
-#include <mach/clk.h>
#include <mach/rpm-9615.h>
#include <mach/rpm-regulator.h>
+#include "clock.h"
#include "clock-local.h"
#include "clock-voter.h"
#include "clock-rpm.h"
diff --git a/arch/arm/mach-msm/clock-debug.c b/arch/arm/mach-msm/clock-debug.c
index c996ff4..e942173 100644
--- a/arch/arm/mach-msm/clock-debug.c
+++ b/arch/arm/mach-msm/clock-debug.c
@@ -21,6 +21,7 @@
#include <linux/clk.h>
#include <linux/list.h>
#include <linux/clkdev.h>
+#include <mach/clk-provider.h>
#include "clock.h"
@@ -145,74 +146,39 @@
DEFINE_SIMPLE_ATTRIBUTE(clock_hwcg_fops, clock_debug_hwcg_get,
NULL, "%llu\n");
-static struct dentry *debugfs_base;
-static u32 debug_suspend;
-static struct clk_lookup *msm_clocks;
-static size_t num_msm_clocks;
-
-int __init clock_debug_init(struct clock_init_data *data)
+static int fmax_rates_show(struct seq_file *m, void *unused)
{
- debugfs_base = debugfs_create_dir("clk", NULL);
- if (!debugfs_base)
- return -ENOMEM;
- if (!debugfs_create_u32("debug_suspend", S_IRUGO | S_IWUSR,
- debugfs_base, &debug_suspend)) {
- debugfs_remove_recursive(debugfs_base);
- return -ENOMEM;
- }
- msm_clocks = data->table;
- num_msm_clocks = data->size;
+ struct clk *clock = m->private;
+ int level = 0;
- measure = clk_get_sys("debug", "measure");
- if (IS_ERR(measure))
- measure = NULL;
+ int vdd_level = find_vdd_level(clock, clock->rate);
+ if (vdd_level < 0) {
+ seq_printf(m, "could not find_vdd_level for %s, %ld\n",
+ clock->dbg_name, clock->rate);
+ return 0;
+ }
+ for (level = 0; level < ARRAY_SIZE(clock->fmax); level++) {
+ if (vdd_level == level)
+ seq_printf(m, "[%lu] ", clock->fmax[level]);
+ else
+ seq_printf(m, "%lu ", clock->fmax[level]);
+ }
+ seq_printf(m, "\n");
return 0;
}
-
-static int clock_debug_print_clock(struct clk *c)
+static int fmax_rates_open(struct inode *inode, struct file *file)
{
- char *start = "";
-
- if (!c || !c->prepare_count)
- return 0;
-
- pr_info("\t");
- do {
- if (c->vdd_class)
- pr_cont("%s%s:%u:%u [%ld, %lu]", start, c->dbg_name,
- c->prepare_count, c->count, c->rate,
- c->vdd_class->cur_level);
- else
- pr_cont("%s%s:%u:%u [%ld]", start, c->dbg_name,
- c->prepare_count, c->count, c->rate);
- start = " -> ";
- } while ((c = clk_get_parent(c)));
-
- pr_cont("\n");
-
- return 1;
+ return single_open(file, fmax_rates_show, inode->i_private);
}
-void clock_debug_print_enabled(void)
-{
- unsigned i;
- int cnt = 0;
-
- if (likely(!debug_suspend))
- return;
-
- pr_info("Enabled clocks:\n");
- for (i = 0; i < num_msm_clocks; i++)
- cnt += clock_debug_print_clock(msm_clocks[i].clk);
-
- if (cnt)
- pr_info("Enabled clock count: %d\n", cnt);
- else
- pr_info("No clocks enabled.\n");
-
-}
+static const struct file_operations fmax_rates_fops = {
+ .open = fmax_rates_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
static int list_rates_show(struct seq_file *m, void *unused)
{
@@ -252,41 +218,16 @@
.release = seq_release,
};
-static int fmax_rates_show(struct seq_file *m, void *unused)
-{
- struct clk *clock = m->private;
- int level = 0;
+static struct dentry *debugfs_base;
+static u32 debug_suspend;
- int vdd_level = find_vdd_level(clock, clock->rate);
- if (vdd_level < 0) {
- seq_printf(m, "could not find_vdd_level for %s, %ld\n",
- clock->dbg_name, clock->rate);
- return 0;
- }
- for (level = 0; level < ARRAY_SIZE(clock->fmax); level++) {
- if (vdd_level == level)
- seq_printf(m, "[%lu] ", clock->fmax[level]);
- else
- seq_printf(m, "%lu ", clock->fmax[level]);
- }
- seq_printf(m, "\n");
-
- return 0;
-}
-
-static int fmax_rates_open(struct inode *inode, struct file *file)
-{
- return single_open(file, fmax_rates_show, inode->i_private);
-}
-
-static const struct file_operations fmax_rates_fops = {
- .open = fmax_rates_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release,
+struct clk_table {
+ struct list_head node;
+ struct clk_lookup *clocks;
+ size_t num_clocks;
};
-int __init clock_debug_add(struct clk *clock)
+static int clock_debug_add(struct clk *clock)
{
char temp[50], *ptr;
struct dentry *clk_dir;
@@ -333,9 +274,118 @@
S_IRUGO, clk_dir, clock, &fmax_rates_fops))
goto error;
-
return 0;
error:
debugfs_remove_recursive(clk_dir);
return -ENOMEM;
}
+static LIST_HEAD(clk_list);
+static DEFINE_SPINLOCK(clk_list_lock);
+
+/**
+ * clock_debug_register() - Add additional clocks to clock debugfs hierarchy
+ * @table: Table of clocks to create debugfs nodes for
+ * @size: Size of @table
+ *
+ * Use this function to register additional clocks in debugfs. The clock debugfs
+ * hierarchy must have already been initialized with clock_debug_init() prior to
+ * calling this function. Unlike clock_debug_init(), this may be called multiple
+ * times with different clock lists and can be used after the kernel has
+ * finished booting.
+ */
+int clock_debug_register(struct clk_lookup *table, size_t size)
+{
+ struct clk_table *clk_table;
+ unsigned long flags;
+ int i;
+
+ clk_table = kmalloc(sizeof(*clk_table), GFP_KERNEL);
+ if (!clk_table)
+ return -ENOMEM;
+
+ clk_table->clocks = table;
+ clk_table->num_clocks = size;
+
+ spin_lock_irqsave(&clk_list_lock, flags);
+ list_add_tail(&clk_table->node, &clk_list);
+ spin_unlock_irqrestore(&clk_list_lock, flags);
+
+ for (i = 0; i < size; i++)
+ clock_debug_add(table[i].clk);
+
+ return 0;
+}
+
+/**
+ * clock_debug_init() - Initialize clock debugfs
+ */
+int __init clock_debug_init(void)
+{
+ debugfs_base = debugfs_create_dir("clk", NULL);
+ if (!debugfs_base)
+ return -ENOMEM;
+ if (!debugfs_create_u32("debug_suspend", S_IRUGO | S_IWUSR,
+ debugfs_base, &debug_suspend)) {
+ debugfs_remove_recursive(debugfs_base);
+ return -ENOMEM;
+ }
+
+ measure = clk_get_sys("debug", "measure");
+ if (IS_ERR(measure))
+ measure = NULL;
+
+ return 0;
+}
+
+static int clock_debug_print_clock(struct clk *c)
+{
+ char *start = "";
+
+ if (!c || !c->prepare_count)
+ return 0;
+
+ pr_info("\t");
+ do {
+ if (c->vdd_class)
+ pr_cont("%s%s:%u:%u [%ld, %lu]", start, c->dbg_name,
+ c->prepare_count, c->count, c->rate,
+ c->vdd_class->cur_level);
+ else
+ pr_cont("%s%s:%u:%u [%ld]", start, c->dbg_name,
+ c->prepare_count, c->count, c->rate);
+ start = " -> ";
+ } while ((c = clk_get_parent(c)));
+
+ pr_cont("\n");
+
+ return 1;
+}
+
+/**
+ * clock_debug_print_enabled() - Print names of enabled clocks for suspend debug
+ *
+ * Print the names of enabled clocks and their parents if debug_suspend is set
+ */
+void clock_debug_print_enabled(void)
+{
+ struct clk_table *table;
+ unsigned long flags;
+ int i, cnt = 0;
+
+ if (likely(!debug_suspend))
+ return;
+
+ pr_info("Enabled clocks:\n");
+ spin_lock_irqsave(&clk_list_lock, flags);
+ list_for_each_entry(table, &clk_list, node) {
+ for (i = 0; i < table->num_clocks; i++)
+ cnt += clock_debug_print_clock(table->clocks[i].clk);
+ }
+ spin_unlock_irqrestore(&clk_list_lock, flags);
+
+ if (cnt)
+ pr_info("Enabled clock count: %d\n", cnt);
+ else
+ pr_info("No clocks enabled.\n");
+
+}
diff --git a/arch/arm/mach-msm/clock-dummy.c b/arch/arm/mach-msm/clock-dummy.c
index 54c9de8..fda7a92 100644
--- a/arch/arm/mach-msm/clock-dummy.c
+++ b/arch/arm/mach-msm/clock-dummy.c
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-#include "clock.h"
+#include <mach/clk-provider.h>
static int dummy_clk_reset(struct clk *clk, enum clk_reset_action action)
{
diff --git a/arch/arm/mach-msm/clock-fsm9xxx.c b/arch/arm/mach-msm/clock-fsm9xxx.c
index c188ba6..2900d45 100644
--- a/arch/arm/mach-msm/clock-fsm9xxx.c
+++ b/arch/arm/mach-msm/clock-fsm9xxx.c
@@ -12,9 +12,7 @@
*/
#include <linux/kernel.h>
#include <linux/clk.h>
-
-#include <mach/clk.h>
-
+#include <mach/clk-provider.h>
#include "clock.h"
/*
diff --git a/arch/arm/mach-msm/clock-local.c b/arch/arm/mach-msm/clock-local.c
index b952f2f..ca031ad 100644
--- a/arch/arm/mach-msm/clock-local.c
+++ b/arch/arm/mach-msm/clock-local.c
@@ -24,10 +24,10 @@
#include <linux/clk.h>
#include <mach/msm_iomap.h>
+#include <mach/clk-provider.h>
#include <mach/clk.h>
#include <mach/scm-io.h>
-#include "clock.h"
#include "clock-local.h"
#ifdef CONFIG_MSM_SECURE_IO
diff --git a/arch/arm/mach-msm/clock-local.h b/arch/arm/mach-msm/clock-local.h
index 81085ef..1873343 100644
--- a/arch/arm/mach-msm/clock-local.h
+++ b/arch/arm/mach-msm/clock-local.h
@@ -15,7 +15,7 @@
#define __ARCH_ARM_MACH_MSM_CLOCK_LOCAL_H
#include <linux/spinlock.h>
-#include "clock.h"
+#include <mach/clk-provider.h>
#define MN_MODE_DUAL_EDGE 0x2
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index 3f19b2a..b9c3036 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -24,8 +24,8 @@
#include <linux/clk.h>
#include <mach/clk.h>
+#include <mach/clk-provider.h>
-#include "clock.h"
#include "clock-local2.h"
/*
@@ -474,10 +474,10 @@
if (branch->has_sibling == 1)
return -ENXIO;
- if (branch->parent)
- return rcg_clk_list_rate(branch->parent, n);
+ if (branch->parent && branch->parent->ops->list_rate)
+ return branch->parent->ops->list_rate(branch->parent, n);
else
- return 0;
+ return -ENXIO;
}
static enum handoff branch_clk_handoff(struct clk *c)
diff --git a/arch/arm/mach-msm/clock-local2.h b/arch/arm/mach-msm/clock-local2.h
index 46e9e0c..101dc2d 100644
--- a/arch/arm/mach-msm/clock-local2.h
+++ b/arch/arm/mach-msm/clock-local2.h
@@ -15,7 +15,8 @@
#define __ARCH_ARM_MACH_MSM_CLOCK_LOCAL_2_H
#include <linux/spinlock.h>
-#include "clock.h"
+#include <mach/clk-provider.h>
+#include <mach/clk.h>
/*
* Generic frequency-definition structs and macros
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index 4d147c3..1603c93 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -20,8 +20,8 @@
#include <asm/processor.h>
#include <mach/msm_iomap.h>
+#include <mach/clk-provider.h>
-#include "clock.h"
#include "clock-mdss-8974.h"
#define REG_R(addr) readl_relaxed(addr)
@@ -67,7 +67,9 @@
static int pll_byte_clk_rate;
static int pll_pclk_rate;
static int pll_initialized;
+static int pll_enabled;
static struct clk *mdss_dsi_ahb_clk;
+static unsigned long dsi_pll_rate;
static void __iomem *hdmi_phy_base;
static void __iomem *hdmi_phy_pll_base;
@@ -135,6 +137,7 @@
int pll_divcfg1, pll_divcfg2;
int half_bitclk_rate;
+ pr_debug("%s:\n", __func__);
if (pll_initialized)
return 0;
@@ -193,10 +196,13 @@
REG_W(0x00, mdss_dsi_base + 0x0290); /* CAL CFG9 */
REG_W(0x20, mdss_dsi_base + 0x029c); /* EFUSE CFG */
+ dsi_pll_rate = rate;
+
pll_byte_clk_rate = 53000000;
pll_pclk_rate = 105000000;
clk_disable(mdss_dsi_ahb_clk);
+ pr_debug("%s: **** PLL initialized success\n", __func__);
pll_initialized = 1;
return 0;
@@ -206,11 +212,19 @@
{
u32 status;
u32 max_reads, timeout_us;
- static int pll_enabled;
+ int i;
if (pll_enabled)
return 0;
+ if (!pll_initialized) {
+ if (dsi_pll_rate)
+ mdss_dsi_pll_byte_set_rate(c, dsi_pll_rate);
+ else
+ pr_err("%s: Calling clk_en before set_rate\n",
+ __func__);
+ }
+
if (!mdss_dsi_ahb_clk) {
pr_err("%s: mdss_dsi_ahb_clk not initialized\n",
__func__);
@@ -218,26 +232,39 @@
}
clk_enable(mdss_dsi_ahb_clk);
- /* PLL power up */
- REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
- REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(20);
- REG_W(0x07, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(20);
- REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
- /* poll for PLL ready status */
- max_reads = 20;
- timeout_us = 100;
- if (readl_poll_timeout_noirq((mdss_dsi_base + 0x02c0),
- status,
- ((status & 0x01) == 1),
- max_reads, timeout_us)) {
+ /* PLL power up */
+ for (i = 0; i < 3; i++) {
+ REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
+ REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
+ udelay(20);
+ REG_W(0x07, mdss_dsi_base + 0x0220); /* GLB CFG */
+ udelay(20);
+ REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
+
+ /* poll for PLL ready status */
+ max_reads = 20;
+ timeout_us = 100;
+ if (readl_poll_timeout_noirq((mdss_dsi_base + 0x02c0),
+ status,
+ ((status & 0x01) == 1),
+ max_reads, timeout_us)) {
+ pr_debug("%s: DSI PLL status=%x failed to Lock\n",
+ __func__, status);
+ pr_debug("%s:Trying to power UP PLL again\n",
+ __func__);
+ } else
+ break;
+ }
+
+ if ((status & 0x01) != 1) {
pr_err("%s: DSI PLL status=%x failed to Lock\n",
__func__, status);
clk_disable(mdss_dsi_ahb_clk);
return -EINVAL;
}
+
+ pr_debug("%s: **** PLL Lock success\n", __func__);
clk_disable(mdss_dsi_ahb_clk);
pll_enabled = 1;
@@ -253,6 +280,9 @@
clk_enable(mdss_dsi_ahb_clk);
writel_relaxed(0x00, mdss_dsi_base + 0x0220); /* GLB CFG */
clk_disable(mdss_dsi_ahb_clk);
+ pr_debug("%s: **** disable pll Initialize\n", __func__);
+ pll_initialized = 0;
+ pll_enabled = 0;
}
void hdmi_pll_disable(void)
diff --git a/arch/arm/mach-msm/clock-pcom.c b/arch/arm/mach-msm/clock-pcom.c
index 428423a..801b40a 100644
--- a/arch/arm/mach-msm/clock-pcom.c
+++ b/arch/arm/mach-msm/clock-pcom.c
@@ -17,6 +17,7 @@
#include <linux/err.h>
#include <mach/clk.h>
+#include <mach/clk-provider.h>
#include <mach/socinfo.h>
#include <mach/proc_comm.h>
diff --git a/arch/arm/mach-msm/clock-pcom.h b/arch/arm/mach-msm/clock-pcom.h
index 723c53c..82a90ab 100644
--- a/arch/arm/mach-msm/clock-pcom.h
+++ b/arch/arm/mach-msm/clock-pcom.h
@@ -13,6 +13,8 @@
#ifndef __ARCH_ARM_MACH_MSM_CLOCK_PCOM_H
#define __ARCH_ARM_MACH_MSM_CLOCK_PCOM_H
+#include <mach/clk-provider.h>
+
/* clock IDs used by the modem processor */
#define P_ACPU_CLK 0 /* Applications processor clock */
diff --git a/arch/arm/mach-msm/clock-pll.h b/arch/arm/mach-msm/clock-pll.h
index 30f595b..5c7c304 100644
--- a/arch/arm/mach-msm/clock-pll.h
+++ b/arch/arm/mach-msm/clock-pll.h
@@ -15,6 +15,8 @@
#ifndef __ARCH_ARM_MACH_MSM_CLOCK_PLL_H
#define __ARCH_ARM_MACH_MSM_CLOCK_PLL_H
+#include <mach/clk-provider.h>
+
/**
* enum - For PLL IDs
*/
diff --git a/arch/arm/mach-msm/clock-rpm.c b/arch/arm/mach-msm/clock-rpm.c
index 149a0511..e06eb4b 100644
--- a/arch/arm/mach-msm/clock-rpm.c
+++ b/arch/arm/mach-msm/clock-rpm.c
@@ -12,10 +12,9 @@
*/
#include <linux/err.h>
-#include <mach/clk.h>
+#include <mach/clk-provider.h>
#include "rpm_resources.h"
-#include "clock.h"
#include "clock-rpm.h"
#define __clk_rpmrs_set_rate(r, value, ctx, noirq) \
diff --git a/arch/arm/mach-msm/clock-rpm.h b/arch/arm/mach-msm/clock-rpm.h
index 7952a33..2f0b729 100644
--- a/arch/arm/mach-msm/clock-rpm.h
+++ b/arch/arm/mach-msm/clock-rpm.h
@@ -16,6 +16,7 @@
#include <mach/rpm.h>
#include <mach/rpm-smd.h>
+#include <mach/clk-provider.h>
#define RPM_SMD_KEY_RATE 0x007A484B
#define RPM_SMD_KEY_ENABLE 0x62616E45
diff --git a/arch/arm/mach-msm/clock-voter.c b/arch/arm/mach-msm/clock-voter.c
index 3e1cbb9..fa170bf4 100644
--- a/arch/arm/mach-msm/clock-voter.c
+++ b/arch/arm/mach-msm/clock-voter.c
@@ -14,8 +14,7 @@
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/clk.h>
-
-#include "clock.h"
+#include <mach/clk-provider.h>
#include "clock-voter.h"
static DEFINE_MUTEX(voter_clk_lock);
diff --git a/arch/arm/mach-msm/clock-voter.h b/arch/arm/mach-msm/clock-voter.h
index 407aac6..82c071b 100644
--- a/arch/arm/mach-msm/clock-voter.h
+++ b/arch/arm/mach-msm/clock-voter.h
@@ -14,6 +14,8 @@
#ifndef __ARCH_ARM_MACH_MSM_CLOCK_VOTER_H
#define __ARCH_ARM_MACH_MSM_CLOCK_VOTER_H
+#include <mach/clk-provider.h>
+
struct clk_ops;
extern struct clk_ops clk_ops_voter;
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index 27f2405..1ea18f4 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -23,7 +23,7 @@
#include <linux/clkdev.h>
#include <linux/list.h>
#include <trace/events/power.h>
-
+#include <mach/clk-provider.h>
#include "clock.h"
struct handoff_clk {
@@ -412,7 +412,32 @@
}
EXPORT_SYMBOL(clk_set_flags);
-static struct clock_init_data __initdata *clk_init_data;
+static struct clock_init_data *clk_init_data;
+
+/**
+ * msm_clock_register() - Register additional clock tables
+ * @table: Table of clocks
+ * @size: Size of @table
+ *
+ * Upon return, clock APIs may be used to control clocks registered using this
+ * function. This API may only be used after msm_clock_init() has completed.
+ * Unlike msm_clock_init(), this function may be called multiple times with
+ * different clock lists and used after the kernel has finished booting.
+ */
+int msm_clock_register(struct clk_lookup *table, size_t size)
+{
+ if (!clk_init_data)
+ return -ENODEV;
+
+ if (!table)
+ return -EINVAL;
+
+ clkdev_add_table(table, size);
+ clock_debug_register(table, size);
+
+ return 0;
+}
+EXPORT_SYMBOL(msm_clock_register);
static enum handoff __init __handoff_clk(struct clk *clk)
{
@@ -466,13 +491,23 @@
return ret;
}
-void __init msm_clock_init(struct clock_init_data *data)
+/**
+ * msm_clock_init() - Register and initialize a clock driver
+ * @data: Driver-specific clock initialization data
+ *
+ * Upon return from this call, clock APIs may be used to control
+ * clocks registered with this API.
+ */
+int __init msm_clock_init(struct clock_init_data *data)
{
unsigned n;
struct clk_lookup *clock_tbl;
size_t num_clocks;
struct clk *clk;
+ if (!data)
+ return -EINVAL;
+
clk_init_data = data;
if (clk_init_data->pre_init)
clk_init_data->pre_init();
@@ -499,16 +534,17 @@
if (clk_init_data->post_init)
clk_init_data->post_init();
+
+ clock_debug_init();
+ clock_debug_register(clock_tbl, num_clocks);
+
+ return 0;
}
static int __init clock_late_init(void)
{
struct handoff_clk *h, *h_temp;
- int n, ret = 0;
-
- clock_debug_init(clk_init_data);
- for (n = 0; n < clk_init_data->size; n++)
- clock_debug_add(clk_init_data->table[n].clk);
+ int ret = 0;
pr_info("%s: Removing enables held for handed-off clocks\n", __func__);
list_for_each_entry_safe(h, h_temp, &handoff_list, list) {
diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h
index 45d2f71..48f897b 100644
--- a/arch/arm/mach-msm/clock.h
+++ b/arch/arm/mach-msm/clock.h
@@ -1,7 +1,5 @@
-/* arch/arm/mach-msm/clock.h
- *
- * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2007-2012, Code Aurora Forum. All rights reserved.
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -17,127 +15,7 @@
#ifndef __ARCH_ARM_MACH_MSM_CLOCK_H
#define __ARCH_ARM_MACH_MSM_CLOCK_H
-#include <linux/types.h>
-#include <linux/list.h>
#include <linux/clkdev.h>
-#include <linux/spinlock.h>
-#include <linux/mutex.h>
-
-#include <mach/clk.h>
-
-#define CLKFLAG_INVERT 0x00000001
-#define CLKFLAG_NOINVERT 0x00000002
-#define CLKFLAG_NONEST 0x00000004
-#define CLKFLAG_NORESET 0x00000008
-#define CLKFLAG_RETAIN 0x00000040
-#define CLKFLAG_NORETAIN 0x00000080
-#define CLKFLAG_SKIP_HANDOFF 0x00000100
-#define CLKFLAG_MIN 0x00000400
-#define CLKFLAG_MAX 0x00000800
-
-/*
- * Bit manipulation macros
- */
-#define BM(msb, lsb) (((((uint32_t)-1) << (31-msb)) >> (31-msb+lsb)) << lsb)
-#define BVAL(msb, lsb, val) (((val) << lsb) & BM(msb, lsb))
-
-/*
- * Halt/Status Checking Mode Macros
- */
-#define HALT 0 /* Bit pol: 1 = halted */
-#define NOCHECK 1 /* No bit to check, do nothing */
-#define HALT_VOTED 2 /* Bit pol: 1 = halted; delay on disable */
-#define ENABLE 3 /* Bit pol: 1 = running */
-#define ENABLE_VOTED 4 /* Bit pol: 1 = running; delay on disable */
-#define DELAY 5 /* No bit to check, just delay */
-
-#define MAX_VDD_LEVELS 4
-
-/**
- * struct clk_vdd_class - Voltage scaling class
- * @class_name: name of the class
- * @set_vdd: function to call when applying a new voltage setting
- * @level_votes: array of votes for each level
- * @cur_level: the currently set voltage level
- * @lock: lock to protect this struct
- */
-struct clk_vdd_class {
- const char *class_name;
- int (*set_vdd)(struct clk_vdd_class *v_class, int level);
- int level_votes[MAX_VDD_LEVELS];
- unsigned long cur_level;
- spinlock_t lock;
-};
-
-#define DEFINE_VDD_CLASS(_name, _set_vdd) \
- struct clk_vdd_class _name = { \
- .class_name = #_name, \
- .set_vdd = _set_vdd, \
- .cur_level = ARRAY_SIZE(_name.level_votes), \
- .lock = __SPIN_LOCK_UNLOCKED(lock) \
- }
-
-enum handoff {
- HANDOFF_ENABLED_CLK,
- HANDOFF_DISABLED_CLK,
- HANDOFF_UNKNOWN_RATE,
-};
-
-struct clk_ops {
- int (*prepare)(struct clk *clk);
- int (*enable)(struct clk *clk);
- void (*disable)(struct clk *clk);
- void (*unprepare)(struct clk *clk);
- void (*enable_hwcg)(struct clk *clk);
- void (*disable_hwcg)(struct clk *clk);
- int (*in_hwcg_mode)(struct clk *clk);
- enum handoff (*handoff)(struct clk *clk);
- int (*reset)(struct clk *clk, enum clk_reset_action action);
- int (*set_rate)(struct clk *clk, unsigned long rate);
- int (*set_max_rate)(struct clk *clk, unsigned long rate);
- int (*set_flags)(struct clk *clk, unsigned flags);
- unsigned long (*get_rate)(struct clk *clk);
- int (*list_rate)(struct clk *clk, unsigned n);
- int (*is_enabled)(struct clk *clk);
- long (*round_rate)(struct clk *clk, unsigned long rate);
- int (*set_parent)(struct clk *clk, struct clk *parent);
- struct clk *(*get_parent)(struct clk *clk);
- bool (*is_local)(struct clk *clk);
-};
-
-/**
- * struct clk
- * @prepare_count: prepare refcount
- * @prepare_lock: protects clk_prepare()/clk_unprepare() path and @prepare_count
- * @count: enable refcount
- * @lock: protects clk_enable()/clk_disable() path and @count
- * @depends: non-direct parent of clock to enable when this clock is enabled
- * @vdd_class: voltage scaling requirement class
- * @fmax: maximum frequency in Hz supported at each voltage level
- */
-struct clk {
- uint32_t flags;
- struct clk_ops *ops;
- const char *dbg_name;
- struct clk *depends;
- struct clk_vdd_class *vdd_class;
- unsigned long fmax[MAX_VDD_LEVELS];
- unsigned long rate;
-
- struct list_head children;
- struct list_head siblings;
-
- unsigned count;
- spinlock_t lock;
- unsigned prepare_count;
- struct mutex prepare_lock;
-};
-
-#define CLK_INIT(name) \
- .lock = __SPIN_LOCK_UNLOCKED((name).lock), \
- .prepare_lock = __MUTEX_INITIALIZER((name).prepare_lock), \
- .children = LIST_HEAD_INIT((name).children), \
- .siblings = LIST_HEAD_INIT((name).siblings)
/**
* struct clock_init_data - SoC specific clock initialization data
@@ -171,30 +49,20 @@
extern struct clock_init_data msm8974_clock_init_data;
extern struct clock_init_data msm8974_rumi_clock_init_data;
-void msm_clock_init(struct clock_init_data *data);
-int vote_vdd_level(struct clk_vdd_class *vdd_class, int level);
-int unvote_vdd_level(struct clk_vdd_class *vdd_class, int level);
+int msm_clock_init(struct clock_init_data *data);
int find_vdd_level(struct clk *clk, unsigned long rate);
#ifdef CONFIG_DEBUG_FS
-int clock_debug_init(struct clock_init_data *data);
-int clock_debug_add(struct clk *clock);
+int clock_debug_init(void);
+int clock_debug_register(struct clk_lookup *t, size_t s);
void clock_debug_print_enabled(void);
#else
-static inline int clock_debug_init(struct clock_init_data *data) { return 0; }
-static inline int clock_debug_add(struct clk *clock) { return 0; }
+static inline int clock_debug_init(void) { return 0; }
+static inline int clock_debug_register(struct clk_lookup *t, size_t s)
+{
+ return 0;
+}
static inline void clock_debug_print_enabled(void) { return; }
#endif
-extern struct clk dummy_clk;
-
-#define CLK_DUMMY(clk_name, clk_id, clk_dev, flags) { \
- .con_id = clk_name, \
- .dev_id = clk_dev, \
- .clk = &dummy_clk, \
- }
-
-#define CLK_LOOKUP(con, c, dev) { .con_id = con, .clk = &c, .dev_id = dev }
-
#endif
-
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 4ad5580..e66881b 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -26,6 +26,7 @@
#include <mach/msm_sps.h>
#include <mach/dma.h>
#include <mach/msm_dsps.h>
+#include <mach/clk-provider.h>
#include <sound/msm-dai-q6.h>
#include <sound/apr_audio.h>
#include <mach/msm_tsif.h>
@@ -2316,8 +2317,8 @@
};
static struct msm_rpmstats_platform_data msm_rpm_stat_pdata = {
- .phys_addr_base = 0x0010D204,
- .phys_size = SZ_8K,
+ .phys_addr_base = 0x0010DD04,
+ .phys_size = SZ_256,
};
struct platform_device apq8064_rpm_stat_device = {
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index 292f58d..ad89a86 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -530,8 +530,8 @@
};
static struct msm_rpmstats_platform_data msm_rpm_stat_pdata = {
- .phys_addr_base = 0x0010D204,
- .phys_size = SZ_8K,
+ .phys_addr_base = 0x0010DD04,
+ .phys_size = SZ_256,
};
struct platform_device msm8930_rpm_stat_device = {
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 33782ab..64b901f 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -35,6 +35,7 @@
#include <mach/msm_dcvs.h>
#include <mach/msm_rtb.h>
#include <mach/msm_cache_dump.h>
+#include <mach/clk-provider.h>
#include <sound/msm-dai-q6.h>
#include <sound/apr_audio.h>
#include <mach/msm_tsif.h>
@@ -3668,8 +3669,8 @@
};
static struct msm_rpmstats_platform_data msm_rpm_stat_pdata = {
- .phys_addr_base = 0x0010D204,
- .phys_size = SZ_8K,
+ .phys_addr_base = 0x0010DD04,
+ .phys_size = SZ_256,
};
struct platform_device msm8960_rpm_stat_device = {
diff --git a/arch/arm/mach-msm/devices-iommu.c b/arch/arm/mach-msm/devices-iommu.c
index b65bd1f..acf577e 100644
--- a/arch/arm/mach-msm/devices-iommu.c
+++ b/arch/arm/mach-msm/devices-iommu.c
@@ -365,25 +365,25 @@
static struct msm_iommu_dev gfx3d_iommu = {
.name = "gfx3d",
.ncb = 3,
- .ttbr_split = 2,
+ .ttbr_split = 1,
};
static struct msm_iommu_dev gfx3d1_iommu = {
.name = "gfx3d1",
.ncb = 3,
- .ttbr_split = 2,
+ .ttbr_split = 1,
};
static struct msm_iommu_dev gfx2d0_iommu = {
.name = "gfx2d0",
.ncb = 2,
- .ttbr_split = 2,
+ .ttbr_split = 1,
};
static struct msm_iommu_dev gfx2d1_iommu = {
.name = "gfx2d1",
.ncb = 2,
- .ttbr_split = 2,
+ .ttbr_split = 1,
};
static struct msm_iommu_dev vcap_iommu = {
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index c877ba9..343ea76 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -30,6 +30,7 @@
#include <asm/cacheflush.h>
#include <mach/rpc_hsusb.h>
#include <mach/socinfo.h>
+#include <mach/clk-provider.h>
#include "devices.h"
#include "devices-msm7x2xa.h"
diff --git a/arch/arm/mach-msm/etm.c b/arch/arm/mach-msm/etm.c
index 6cceff2..ae42733 100644
--- a/arch/arm/mach-msm/etm.c
+++ b/arch/arm/mach-msm/etm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -24,8 +24,7 @@
#include <linux/pm_qos.h>
#include <asm/atomic.h>
-
-#include "cp14.h"
+#include <asm/hardware/cp14.h>
#define LOG_BUF_LEN 32768
/* each slot is 4 bytes, 8kb total */
diff --git a/arch/arm/mach-msm/footswitch-8x60.c b/arch/arm/mach-msm/footswitch-8x60.c
index 84735aa..a7b26c1 100644
--- a/arch/arm/mach-msm/footswitch-8x60.c
+++ b/arch/arm/mach-msm/footswitch-8x60.c
@@ -24,7 +24,7 @@
#include <mach/msm_iomap.h>
#include <mach/msm_bus.h>
#include <mach/scm-io.h>
-#include "clock.h"
+#include <mach/clk.h>
#include "footswitch.h"
#ifdef CONFIG_MSM_SECURE_IO
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 5b8729a..433fee3 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -63,6 +63,7 @@
uint8_t csid_core;
uint8_t is_vpe;
struct msm_bus_scale_pdata *cam_bus_scale_table;
+ uint8_t csiphy_core;
};
#ifdef CONFIG_SENSORS_MT9T013
@@ -177,7 +178,6 @@
struct msm_camera_csi_lane_params {
uint16_t csi_lane_assign;
uint16_t csi_lane_mask;
- uint8_t csi_phy_sel;
};
struct msm_camera_gpio_conf {
diff --git a/arch/arm/mach-msm/include/mach/clk-provider.h b/arch/arm/mach-msm/include/mach/clk-provider.h
new file mode 100644
index 0000000..0da0b33
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/clk-provider.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2007-2012, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MACH_CLK_PROVIDER_H
+#define __MACH_CLK_PROVIDER_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/clkdev.h>
+#include <linux/spinlock.h>
+#include <mach/clk.h>
+
+/*
+ * Bit manipulation macros
+ */
+#define BM(msb, lsb) (((((uint32_t)-1) << (31-msb)) >> (31-msb+lsb)) << lsb)
+#define BVAL(msb, lsb, val) (((val) << lsb) & BM(msb, lsb))
+
+/*
+ * Halt/Status Checking Mode Macros
+ */
+#define HALT 0 /* Bit pol: 1 = halted */
+#define NOCHECK 1 /* No bit to check, do nothing */
+#define HALT_VOTED 2 /* Bit pol: 1 = halted; delay on disable */
+#define ENABLE 3 /* Bit pol: 1 = running */
+#define ENABLE_VOTED 4 /* Bit pol: 1 = running; delay on disable */
+#define DELAY 5 /* No bit to check, just delay */
+
+#define MAX_VDD_LEVELS 4
+
+/**
+ * struct clk_vdd_class - Voltage scaling class
+ * @class_name: name of the class
+ * @set_vdd: function to call when applying a new voltage setting
+ * @level_votes: array of votes for each level
+ * @cur_level: the currently set voltage level
+ * @lock: lock to protect this struct
+ */
+struct clk_vdd_class {
+ const char *class_name;
+ int (*set_vdd)(struct clk_vdd_class *v_class, int level);
+ int level_votes[MAX_VDD_LEVELS];
+ unsigned long cur_level;
+ spinlock_t lock;
+};
+
+#define DEFINE_VDD_CLASS(_name, _set_vdd) \
+ struct clk_vdd_class _name = { \
+ .class_name = #_name, \
+ .set_vdd = _set_vdd, \
+ .cur_level = ARRAY_SIZE(_name.level_votes), \
+ .lock = __SPIN_LOCK_UNLOCKED(lock) \
+ }
+
+enum handoff {
+ HANDOFF_ENABLED_CLK,
+ HANDOFF_DISABLED_CLK,
+ HANDOFF_UNKNOWN_RATE,
+};
+
+struct clk_ops {
+ int (*prepare)(struct clk *clk);
+ int (*enable)(struct clk *clk);
+ void (*disable)(struct clk *clk);
+ void (*unprepare)(struct clk *clk);
+ void (*enable_hwcg)(struct clk *clk);
+ void (*disable_hwcg)(struct clk *clk);
+ int (*in_hwcg_mode)(struct clk *clk);
+ enum handoff (*handoff)(struct clk *clk);
+ int (*reset)(struct clk *clk, enum clk_reset_action action);
+ int (*set_rate)(struct clk *clk, unsigned long rate);
+ int (*set_max_rate)(struct clk *clk, unsigned long rate);
+ int (*set_flags)(struct clk *clk, unsigned flags);
+ unsigned long (*get_rate)(struct clk *clk);
+ int (*list_rate)(struct clk *clk, unsigned n);
+ int (*is_enabled)(struct clk *clk);
+ long (*round_rate)(struct clk *clk, unsigned long rate);
+ int (*set_parent)(struct clk *clk, struct clk *parent);
+ struct clk *(*get_parent)(struct clk *clk);
+ bool (*is_local)(struct clk *clk);
+};
+
+/**
+ * struct clk
+ * @prepare_count: prepare refcount
+ * @prepare_lock: protects clk_prepare()/clk_unprepare() path and @prepare_count
+ * @count: enable refcount
+ * @lock: protects clk_enable()/clk_disable() path and @count
+ * @depends: non-direct parent of clock to enable when this clock is enabled
+ * @vdd_class: voltage scaling requirement class
+ * @fmax: maximum frequency in Hz supported at each voltage level
+ */
+struct clk {
+ uint32_t flags;
+ struct clk_ops *ops;
+ const char *dbg_name;
+ struct clk *depends;
+ struct clk_vdd_class *vdd_class;
+ unsigned long fmax[MAX_VDD_LEVELS];
+ unsigned long rate;
+
+ struct list_head children;
+ struct list_head siblings;
+
+ unsigned count;
+ spinlock_t lock;
+ unsigned prepare_count;
+ struct mutex prepare_lock;
+};
+
+#define CLK_INIT(name) \
+ .lock = __SPIN_LOCK_UNLOCKED((name).lock), \
+ .prepare_lock = __MUTEX_INITIALIZER((name).prepare_lock), \
+ .children = LIST_HEAD_INIT((name).children), \
+ .siblings = LIST_HEAD_INIT((name).siblings)
+
+int vote_vdd_level(struct clk_vdd_class *vdd_class, int level);
+int unvote_vdd_level(struct clk_vdd_class *vdd_class, int level);
+
+/* Register clocks with the MSM clock driver */
+int msm_clock_register(struct clk_lookup *table, size_t size);
+
+extern struct clk dummy_clk;
+
+#define CLK_DUMMY(clk_name, clk_id, clk_dev, flags) { \
+ .con_id = clk_name, \
+ .dev_id = clk_dev, \
+ .clk = &dummy_clk, \
+ }
+
+#define CLK_LOOKUP(con, c, dev) { .con_id = con, .clk = &c, .dev_id = dev }
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/clk.h b/arch/arm/mach-msm/include/mach/clk.h
index 8c0ebfa..d69b372 100644
--- a/arch/arm/mach-msm/include/mach/clk.h
+++ b/arch/arm/mach-msm/include/mach/clk.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009, 2012 Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -12,19 +12,24 @@
#ifndef __MACH_CLK_H
#define __MACH_CLK_H
-/* Magic rate value for use with PM QOS to request the board's maximum
- * supported AXI rate. PM QOS will only pass positive s32 rate values
- * through to the clock driver, so INT_MAX is used.
- */
-#define MSM_AXI_MAX_FREQ LONG_MAX
+#define CLKFLAG_INVERT 0x00000001
+#define CLKFLAG_NOINVERT 0x00000002
+#define CLKFLAG_NONEST 0x00000004
+#define CLKFLAG_NORESET 0x00000008
+#define CLKFLAG_RETAIN 0x00000040
+#define CLKFLAG_NORETAIN 0x00000080
+#define CLKFLAG_SKIP_HANDOFF 0x00000100
+#define CLKFLAG_MIN 0x00000400
+#define CLKFLAG_MAX 0x00000800
+
+struct clk_lookup;
+struct clk;
enum clk_reset_action {
CLK_RESET_DEASSERT = 0,
CLK_RESET_ASSERT = 1
};
-struct clk;
-
/* Rate is maximum clock rate in Hz */
int clk_set_max_rate(struct clk *clk, unsigned long rate);
diff --git a/arch/arm/mach-msm/include/mach/msm_memory_dump.h b/arch/arm/mach-msm/include/mach/msm_memory_dump.h
index 5e686bf..729a077 100644
--- a/arch/arm/mach-msm/include/mach/msm_memory_dump.h
+++ b/arch/arm/mach-msm/include/mach/msm_memory_dump.h
@@ -17,7 +17,8 @@
enum dump_client_type {
MSM_CPU_CTXT = 0,
- MSM_CACHE,
+ MSM_L1_CACHE,
+ MSM_L2_CACHE,
MSM_OCMEM,
MSM_TMC_ETFETB,
MSM_ETM0_REG,
diff --git a/arch/arm/mach-msm/jtag.c b/arch/arm/mach-msm/jtag.c
index 4f14b19..24e1c41 100644
--- a/arch/arm/mach-msm/jtag.c
+++ b/arch/arm/mach-msm/jtag.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -20,11 +20,10 @@
#include <linux/printk.h>
#include <linux/ratelimit.h>
#include <linux/coresight.h>
+#include <asm/hardware/cp14.h>
#include <mach/scm.h>
#include <mach/jtag.h>
-#include "cp14.h"
-
/* DBGv7 with baseline CP14 registers implemented */
#define ARM_DEBUG_ARCH_V7B (0x3)
/* DBGv7 with all CP14 registers implemented */
diff --git a/arch/arm/mach-msm/mdm.c b/arch/arm/mach-msm/mdm.c
index 4280fb4..02978cf 100644
--- a/arch/arm/mach-msm/mdm.c
+++ b/arch/arm/mach-msm/mdm.c
@@ -28,7 +28,6 @@
#include <linux/debugfs.h>
#include <linux/completion.h>
#include <linux/workqueue.h>
-#include <linux/clk.h>
#include <asm/mach-types.h>
#include <asm/uaccess.h>
#include <linux/mfd/pm8xxx/misc.h>
@@ -39,7 +38,6 @@
#include <linux/msm_charm.h>
#include "msm_watchdog.h"
#include "devices.h"
-#include "clock.h"
#define CHARM_MODEM_TIMEOUT 6000
#define CHARM_HOLD_TIME 4000
diff --git a/arch/arm/mach-msm/mdm2.c b/arch/arm/mach-msm/mdm2.c
index 43c85bb..f548417 100644
--- a/arch/arm/mach-msm/mdm2.c
+++ b/arch/arm/mach-msm/mdm2.c
@@ -28,7 +28,6 @@
#include <linux/debugfs.h>
#include <linux/completion.h>
#include <linux/workqueue.h>
-#include <linux/clk.h>
#include <linux/mfd/pmic8058.h>
#include <asm/mach-types.h>
#include <asm/uaccess.h>
@@ -39,7 +38,6 @@
#include <linux/msm_charm.h>
#include "msm_watchdog.h"
#include "devices.h"
-#include "clock.h"
#include "mdm_private.h"
#define MDM_PBLRDY_CNT 20
diff --git a/arch/arm/mach-msm/msm_cache_dump.c b/arch/arm/mach-msm/msm_cache_dump.c
index 9759d5a..8b4978f 100644
--- a/arch/arm/mach-msm/msm_cache_dump.c
+++ b/arch/arm/mach-msm/msm_cache_dump.c
@@ -21,10 +21,13 @@
#include <linux/pm.h>
#include <linux/memory_alloc.h>
#include <linux/notifier.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <mach/scm.h>
#include <mach/msm_cache_dump.h>
#include <mach/memory.h>
#include <mach/msm_iomap.h>
+#include <mach/msm_memory_dump.h>
#define L2_DUMP_OFFSET 0x14
@@ -37,6 +40,7 @@
*/
static struct l1_cache_dump *l1_dump;
static struct l2_cache_dump *l2_dump;
+static int use_imem_dump_offset;
static int msm_cache_dump_panic(struct notifier_block *this,
unsigned long event, void *ptr)
@@ -45,7 +49,8 @@
/*
* Clear the bootloader magic so the dumps aren't overwritten
*/
- __raw_writel(0, MSM_IMEM_BASE + L2_DUMP_OFFSET);
+ if (use_imem_dump_offset)
+ __raw_writel(0, MSM_IMEM_BASE + L2_DUMP_OFFSET);
scm_call_atomic1(L1C_SERVICE_ID, CACHE_BUFFER_DUMP_COMMAND_ID, 2);
scm_call_atomic1(L1C_SERVICE_ID, CACHE_BUFFER_DUMP_COMMAND_ID, 1);
@@ -65,14 +70,38 @@
static int msm_cache_dump_probe(struct platform_device *pdev)
{
struct msm_cache_dump_platform_data *d = pdev->dev.platform_data;
+ struct msm_client_dump l1_dump_entry, l2_dump_entry;
int ret;
struct {
unsigned long buf;
unsigned long size;
} l1_cache_data;
void *temp;
- unsigned long total_size = d->l1_size + d->l2_size;
+ u32 l1_size, l2_size;
+ unsigned long total_size;
+ if (pdev->dev.of_node) {
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "qcom,l1-dump-size", &l1_size);
+ if (ret)
+ return ret;
+
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "qcom,l2-dump-size", &l2_size);
+ if (ret)
+ return ret;
+
+ use_imem_dump_offset = of_property_read_bool(pdev->dev.of_node,
+ "qcom,use-imem-dump-offset");
+ } else {
+ l1_size = d->l1_size;
+ l2_size = d->l2_size;
+
+ /* Non-DT targets assume the IMEM dump offset shall be used */
+ use_imem_dump_offset = 1;
+ };
+
+ total_size = l1_size + l2_size;
msm_cache_dump_addr = allocate_contiguous_ebi_nomap(total_size, SZ_4K);
if (!msm_cache_dump_addr) {
@@ -86,7 +115,7 @@
iounmap(temp);
l1_cache_data.buf = msm_cache_dump_addr;
- l1_cache_data.size = d->l1_size;
+ l1_cache_data.size = l1_size;
ret = scm_call(L1C_SERVICE_ID, L1C_BUFFER_SET_COMMAND_ID,
&l1_cache_data, sizeof(l1_cache_data), NULL, 0);
@@ -96,10 +125,11 @@
__func__, ret);
l1_dump = (struct l1_cache_dump *)msm_cache_dump_addr;
+ l2_dump = (struct l2_cache_dump *)(msm_cache_dump_addr + l1_size);
#if defined(CONFIG_MSM_CACHE_DUMP_ON_PANIC)
- l1_cache_data.buf = msm_cache_dump_addr + d->l1_size;
- l1_cache_data.size = d->l2_size;
+ l1_cache_data.buf = msm_cache_dump_addr + l1_size;
+ l1_cache_data.size = l2_size;
ret = scm_call(L1C_SERVICE_ID, L2C_BUFFER_SET_COMMAND_ID,
&l1_cache_data, sizeof(l1_cache_data), NULL, 0);
@@ -108,11 +138,27 @@
pr_err("%s: could not register L2 buffer ret = %d.\n",
__func__, ret);
#endif
- __raw_writel(msm_cache_dump_addr + d->l1_size,
+
+ if (use_imem_dump_offset)
+ __raw_writel(msm_cache_dump_addr + l1_size,
MSM_IMEM_BASE + L2_DUMP_OFFSET);
+ else {
+ l1_dump_entry.id = MSM_L1_CACHE;
+ l1_dump_entry.start_addr = msm_cache_dump_addr;
+ l1_dump_entry.end_addr = l1_dump_entry.start_addr + l1_size - 1;
+ l2_dump_entry.id = MSM_L2_CACHE;
+ l2_dump_entry.start_addr = msm_cache_dump_addr + l1_size;
+ l2_dump_entry.end_addr = l2_dump_entry.start_addr + l2_size - 1;
- l2_dump = (struct l2_cache_dump *)(msm_cache_dump_addr + d->l1_size);
+ ret = msm_dump_table_register(&l1_dump_entry);
+ if (ret)
+ pr_err("Could not register L1 dump area: %d\n", ret);
+
+ ret = msm_dump_table_register(&l2_dump_entry);
+ if (ret)
+ pr_err("Could not register L2 dump area: %d\n", ret);
+ }
atomic_notifier_chain_register(&panic_notifier_list,
&msm_cache_dump_blk);
@@ -126,11 +172,18 @@
return 0;
}
+static struct of_device_id cache_dump_match_table[] = {
+ { .compatible = "qcom,cache_dump", },
+ {}
+};
+EXPORT_COMPAT("qcom,cache_dump");
+
static struct platform_driver msm_cache_dump_driver = {
.remove = __devexit_p(msm_cache_dump_remove),
.driver = {
.name = "msm_cache_dump",
- .owner = THIS_MODULE
+ .owner = THIS_MODULE,
+ .of_match_table = cache_dump_match_table,
},
};
diff --git a/arch/arm/mach-msm/pil-riva.c b/arch/arm/mach-msm/pil-riva.c
index ba0e242..3040a31 100644
--- a/arch/arm/mach-msm/pil-riva.c
+++ b/arch/arm/mach-msm/pil-riva.c
@@ -21,7 +21,6 @@
#include <linux/regulator/consumer.h>
#include <linux/clk.h>
-#include <asm/mach-types.h>
#include <mach/msm_iomap.h>
#include "peripheral-loader.h"
@@ -359,18 +358,12 @@
static int __init pil_riva_init(void)
{
- if (machine_is_mpq8064_hrd()) {
- pr_err("pil_riva not supported on this target\n");
- return 0;
- }
return platform_driver_register(&pil_riva_driver);
}
module_init(pil_riva_init);
static void __exit pil_riva_exit(void)
{
- if (machine_is_mpq8064_hrd())
- return;
platform_driver_unregister(&pil_riva_driver);
}
module_exit(pil_riva_exit);
diff --git a/arch/arm/mach-msm/qdsp6v2/Makefile b/arch/arm/mach-msm/qdsp6v2/Makefile
index 0c75f66..ed8cb345 100644
--- a/arch/arm/mach-msm/qdsp6v2/Makefile
+++ b/arch/arm/mach-msm/qdsp6v2/Makefile
@@ -26,3 +26,4 @@
obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_mp3.o audio_amrnb.o audio_amrwb.o audio_evrc.o audio_qcelp.o amrwb_in.o
obj-$(CONFIG_MSM_ADSP_LOADER) += adsp-loader.o
obj-$(CONFIG_MSM_ULTRASOUND) += ultrasound/
+obj-m += adsprpc.o
diff --git a/arch/arm/mach-msm/qdsp6v2/adsprpc.c b/arch/arm/mach-msm/qdsp6v2/adsprpc.c
new file mode 100644
index 0000000..6e6f8e8
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/adsprpc.c
@@ -0,0 +1,706 @@
+/*
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include "adsprpc.h"
+
+struct smq_invoke_ctx {
+ struct completion work;
+ int retval;
+ atomic_t free;
+};
+
+struct smq_context_list {
+ struct smq_invoke_ctx *ls;
+ int size;
+ int last;
+};
+
+struct fastrpc_apps {
+ smd_channel_t *chan;
+ struct smq_context_list clst;
+ struct completion work;
+ struct ion_client *iclient;
+ struct cdev cdev;
+ dev_t dev_no;
+ spinlock_t wrlock;
+ spinlock_t hlock;
+ struct hlist_head htbl[RPC_HASH_SZ];
+};
+
+struct fastrpc_buf {
+ struct ion_handle *handle;
+ void *virt;
+ ion_phys_addr_t phys;
+ int size;
+ int used;
+};
+
+struct fastrpc_device {
+ uint32_t tgid;
+ struct hlist_node hn;
+ struct fastrpc_buf buf;
+};
+
+static struct fastrpc_apps gfa;
+
+static void free_mem(struct fastrpc_buf *buf)
+{
+ struct fastrpc_apps *me = &gfa;
+
+ if (buf->handle) {
+ if (buf->virt) {
+ ion_unmap_kernel(me->iclient, buf->handle);
+ buf->virt = 0;
+ }
+ ion_free(me->iclient, buf->handle);
+ buf->handle = 0;
+ }
+}
+
+static int alloc_mem(struct fastrpc_buf *buf)
+{
+ struct ion_client *clnt = gfa.iclient;
+ int err = 0;
+
+ buf->handle = ion_alloc(clnt, buf->size, SZ_4K,
+ ION_HEAP(ION_AUDIO_HEAP_ID));
+ VERIFY(0 == IS_ERR_OR_NULL(buf->handle));
+ buf->virt = 0;
+ VERIFY(0 != (buf->virt = ion_map_kernel(clnt, buf->handle,
+ ION_SET_CACHE(CACHED))));
+ VERIFY(0 == ion_phys(clnt, buf->handle, &buf->phys, &buf->size));
+ bail:
+ if (err && !IS_ERR_OR_NULL(buf->handle))
+ free_mem(buf);
+ return err;
+}
+
+static int context_list_ctor(struct smq_context_list *me, int size)
+{
+ int err = 0;
+ VERIFY(0 != (me->ls = kzalloc(size, GFP_KERNEL)));
+ me->size = size / sizeof(*me->ls);
+ me->last = 0;
+ bail:
+ return err;
+}
+
+static void context_list_dtor(struct smq_context_list *me)
+{
+ kfree(me->ls);
+ me->ls = 0;
+}
+
+static void context_list_alloc_ctx(struct smq_context_list *me,
+ struct smq_invoke_ctx **po)
+{
+ int ii = me->last;
+ struct smq_invoke_ctx *ctx;
+
+ for (;;) {
+ ii = ii % me->size;
+ ctx = &me->ls[ii];
+ if (atomic_read(&ctx->free) == 0)
+ if (0 == atomic_cmpxchg(&ctx->free, 0, 1))
+ break;
+ ii++;
+ }
+ me->last = ii;
+ ctx->retval = -1;
+ init_completion(&ctx->work);
+ *po = ctx;
+}
+
+static void context_free(struct smq_invoke_ctx *me)
+{
+ if (me)
+ atomic_set(&me->free, 0);
+}
+
+static void context_notify_user(struct smq_invoke_ctx *me, int retval)
+{
+ me->retval = retval;
+ complete(&me->work);
+}
+
+static void context_notify_all_users(struct smq_context_list *me)
+{
+ int ii;
+
+ if (!me->ls)
+ return;
+ for (ii = 0; ii < me->size; ++ii) {
+ if (atomic_read(&me->ls[ii].free) != 0)
+ complete(&me->ls[ii].work);
+ }
+}
+
+static int get_page_list(uint32_t kernel, uint32_t sc, remote_arg_t *pra,
+ struct fastrpc_buf *ibuf, struct fastrpc_buf *obuf)
+{
+ struct smq_phy_page *pgstart, *pages;
+ struct smq_invoke_buf *list;
+ int ii, rlen, err = 0;
+ int inbufs = REMOTE_SCALARS_INBUFS(sc);
+ int outbufs = REMOTE_SCALARS_OUTBUFS(sc);
+
+ VERIFY(0 != try_module_get(THIS_MODULE));
+ LOCK_MMAP(kernel);
+ *obuf = *ibuf;
+ retry:
+ list = smq_invoke_buf_start((remote_arg_t *)obuf->virt, sc);
+ pgstart = smq_phy_page_start(sc, list);
+ pages = pgstart + 1;
+ rlen = obuf->size - ((uint32_t)pages - (uint32_t)obuf->virt);
+ if (rlen < 0) {
+ rlen = ((uint32_t)pages - (uint32_t)obuf->virt) - obuf->size;
+ obuf->size += buf_page_size(rlen);
+ obuf->handle = 0;
+ VERIFY(0 == alloc_mem(obuf));
+ goto retry;
+ }
+ pgstart->addr = obuf->phys;
+ pgstart->size = obuf->size;
+ for (ii = 0; ii < inbufs + outbufs; ++ii) {
+ void *buf;
+ int len, num;
+
+ len = pra[ii].buf.len;
+ if (!len)
+ continue;
+ buf = pra[ii].buf.pv;
+ num = buf_num_pages(buf, len);
+ if (!kernel)
+ list[ii].num = buf_get_pages(buf, len, num,
+ ii >= inbufs, pages, rlen / sizeof(*pages));
+ else
+ list[ii].num = 0;
+ VERIFY(list[ii].num >= 0);
+ if (list[ii].num) {
+ list[ii].pgidx = pages - pgstart;
+ pages = pages + list[ii].num;
+ } else if (rlen > sizeof(*pages)) {
+ list[ii].pgidx = pages - pgstart;
+ pages = pages + 1;
+ } else {
+ if (obuf->handle != ibuf->handle)
+ free_mem(obuf);
+ obuf->size += buf_page_size(sizeof(*pages));
+ obuf->handle = 0;
+ VERIFY(0 == alloc_mem(obuf));
+ goto retry;
+ }
+ rlen = obuf->size - ((uint32_t) pages - (uint32_t) obuf->virt);
+ }
+ obuf->used = obuf->size - rlen;
+ bail:
+ if (err && (obuf->handle != ibuf->handle))
+ free_mem(obuf);
+ UNLOCK_MMAP(kernel);
+ module_put(THIS_MODULE);
+ return err;
+}
+
+static int get_args(uint32_t kernel, uint32_t sc, remote_arg_t *pra,
+ remote_arg_t *rpra, remote_arg_t *upra,
+ struct fastrpc_buf *ibuf, struct fastrpc_buf **abufs,
+ int *nbufs)
+{
+ struct smq_invoke_buf *list;
+ struct fastrpc_buf *pbuf = ibuf, *obufs = 0;
+ struct smq_phy_page *pages;
+ void *args;
+ int ii, rlen, size, used, inh, bufs = 0, err = 0;
+ int inbufs = REMOTE_SCALARS_INBUFS(sc);
+ int outbufs = REMOTE_SCALARS_OUTBUFS(sc);
+
+ list = smq_invoke_buf_start(rpra, sc);
+ pages = smq_phy_page_start(sc, list);
+ used = ALIGN_8(pbuf->used);
+ args = (void *)((char *)pbuf->virt + used);
+ rlen = pbuf->size - used;
+ for (ii = 0; ii < inbufs + outbufs; ++ii) {
+ int num;
+
+ rpra[ii].buf.len = pra[ii].buf.len;
+ if (list[ii].num) {
+ rpra[ii].buf.pv = pra[ii].buf.pv;
+ continue;
+ }
+ if (rlen < pra[ii].buf.len) {
+ struct fastrpc_buf *b;
+ pbuf->used = pbuf->size - rlen;
+ VERIFY(0 != (b = krealloc(obufs,
+ (bufs + 1) * sizeof(*obufs), GFP_KERNEL)));
+ obufs = b;
+ pbuf = obufs + bufs;
+ pbuf->size = buf_num_pages(0, pra[ii].buf.len) *
+ PAGE_SIZE;
+ VERIFY(0 == alloc_mem(pbuf));
+ bufs++;
+ args = pbuf->virt;
+ rlen = pbuf->size;
+ }
+ num = buf_num_pages(args, pra[ii].buf.len);
+ if (pbuf == ibuf) {
+ list[ii].num = num;
+ list[ii].pgidx = 0;
+ } else {
+ list[ii].num = 1;
+ pages[list[ii].pgidx].addr =
+ buf_page_start((void *)(pbuf->phys +
+ (pbuf->size - rlen)));
+ pages[list[ii].pgidx].size =
+ buf_page_size(pra[ii].buf.len);
+ }
+ if (ii < inbufs) {
+ if (!kernel)
+ VERIFY(0 == copy_from_user(args, pra[ii].buf.pv,
+ pra[ii].buf.len));
+ else
+ memmove(args, pra[ii].buf.pv, pra[ii].buf.len);
+ }
+ rpra[ii].buf.pv = args;
+ args = (void *)((char *)args + ALIGN_8(pra[ii].buf.len));
+ rlen -= ALIGN_8(pra[ii].buf.len);
+ }
+ for (ii = 0; ii < inbufs; ++ii) {
+ if (rpra[ii].buf.len)
+ dmac_flush_range(rpra[ii].buf.pv,
+ (char *)rpra[ii].buf.pv + rpra[ii].buf.len);
+ }
+ pbuf->used = pbuf->size - rlen;
+ size = sizeof(*rpra) * REMOTE_SCALARS_INHANDLES(sc);
+ if (size) {
+ inh = inbufs + outbufs;
+ if (!kernel)
+ VERIFY(0 == copy_from_user(&rpra[inh], &upra[inh],
+ size));
+ else
+ memmove(&rpra[inh], &upra[inh], size);
+ }
+ dmac_flush_range(rpra, (char *)rpra + used);
+ bail:
+ *abufs = obufs;
+ *nbufs = bufs;
+ return err;
+}
+
+static int put_args(uint32_t kernel, uint32_t sc, remote_arg_t *pra,
+ remote_arg_t *rpra, remote_arg_t *upra)
+{
+ int ii, inbufs, outbufs, outh, size;
+ int err = 0;
+
+ inbufs = REMOTE_SCALARS_INBUFS(sc);
+ outbufs = REMOTE_SCALARS_OUTBUFS(sc);
+ for (ii = inbufs; ii < inbufs + outbufs; ++ii) {
+ if (rpra[ii].buf.pv != pra[ii].buf.pv)
+ VERIFY(0 == copy_to_user(pra[ii].buf.pv,
+ rpra[ii].buf.pv, rpra[ii].buf.len));
+ }
+ size = sizeof(*rpra) * REMOTE_SCALARS_OUTHANDLES(sc);
+ if (size) {
+ outh = inbufs + outbufs + REMOTE_SCALARS_INHANDLES(sc);
+ if (!kernel)
+ VERIFY(0 == copy_to_user(&upra[outh], &rpra[outh],
+ size));
+ else
+ memmove(&upra[outh], &rpra[outh], size);
+ }
+ bail:
+ return err;
+}
+
+static void inv_args(uint32_t sc, remote_arg_t *rpra, int used)
+{
+ int ii, inbufs, outbufs;
+ int inv = 0;
+
+ inbufs = REMOTE_SCALARS_INBUFS(sc);
+ outbufs = REMOTE_SCALARS_OUTBUFS(sc);
+ for (ii = inbufs; ii < inbufs + outbufs; ++ii) {
+ if (buf_page_start(rpra) == buf_page_start(rpra[ii].buf.pv))
+ inv = 1;
+ else
+ dmac_inv_range(rpra[ii].buf.pv,
+ (char *)rpra[ii].buf.pv + rpra[ii].buf.len);
+ }
+
+ if (inv || REMOTE_SCALARS_OUTHANDLES(sc))
+ dmac_inv_range(rpra, (char *)rpra + used);
+}
+
+static int fastrpc_invoke_send(struct fastrpc_apps *me, remote_handle_t handle,
+ uint32_t sc, struct smq_invoke_ctx *ctx,
+ struct fastrpc_buf *buf)
+{
+ struct smq_msg msg;
+ int err = 0, len;
+
+ msg.pid = current->tgid;
+ msg.tid = current->pid;
+ msg.invoke.header.ctx = ctx;
+ msg.invoke.header.handle = handle;
+ msg.invoke.header.sc = sc;
+ msg.invoke.page.addr = buf->phys;
+ msg.invoke.page.size = buf_page_size(buf->used);
+ spin_lock(&me->wrlock);
+ len = smd_write(me->chan, &msg, sizeof(msg));
+ spin_unlock(&me->wrlock);
+ VERIFY(len == sizeof(msg));
+ bail:
+ return err;
+}
+
+static void fastrpc_deinit(void)
+{
+ struct fastrpc_apps *me = &gfa;
+
+ if (me->chan)
+ (void)smd_close(me->chan);
+ context_list_dtor(&me->clst);
+ ion_client_destroy(me->iclient);
+ me->iclient = 0;
+ me->chan = 0;
+}
+
+static void fastrpc_read_handler(void)
+{
+ struct fastrpc_apps *me = &gfa;
+ struct smq_invoke_rsp rsp;
+ int err = 0;
+
+ do {
+ VERIFY(sizeof(rsp) ==
+ smd_read_from_cb(me->chan, &rsp, sizeof(rsp)));
+ context_notify_user(rsp.ctx, rsp.retval);
+ } while (!err);
+ bail:
+ return;
+}
+
+static void smd_event_handler(void *priv, unsigned event)
+{
+ struct fastrpc_apps *me = (struct fastrpc_apps *)priv;
+
+ switch (event) {
+ case SMD_EVENT_OPEN:
+ complete(&(me->work));
+ break;
+ case SMD_EVENT_CLOSE:
+ context_notify_all_users(&me->clst);
+ break;
+ case SMD_EVENT_DATA:
+ fastrpc_read_handler();
+ break;
+ }
+}
+
+static int fastrpc_init(void)
+{
+ int err = 0;
+ struct fastrpc_apps *me = &gfa;
+
+ if (me->chan == 0) {
+ int ii;
+ spin_lock_init(&me->hlock);
+ spin_lock_init(&me->wrlock);
+ init_completion(&me->work);
+ for (ii = 0; ii < RPC_HASH_SZ; ++ii)
+ INIT_HLIST_HEAD(&me->htbl[ii]);
+ VERIFY(0 == context_list_ctor(&me->clst, SZ_4K));
+ me->iclient = msm_ion_client_create(ION_HEAP_CARVEOUT_MASK,
+ DEVICE_NAME);
+ VERIFY(0 == IS_ERR_OR_NULL(me->iclient));
+ VERIFY(0 == smd_named_open_on_edge(FASTRPC_SMD_GUID,
+ SMD_APPS_QDSP, &me->chan,
+ me, smd_event_handler));
+ VERIFY(0 != wait_for_completion_timeout(&me->work,
+ RPC_TIMEOUT));
+ }
+ bail:
+ if (err)
+ fastrpc_deinit();
+ return err;
+}
+
+static void free_dev(struct fastrpc_device *dev)
+{
+ if (dev) {
+ module_put(THIS_MODULE);
+ free_mem(&dev->buf);
+ kfree(dev);
+ }
+}
+
+static int alloc_dev(struct fastrpc_device **dev)
+{
+ int err = 0;
+ struct fastrpc_device *fd = 0;
+
+ VERIFY(0 != try_module_get(THIS_MODULE));
+ VERIFY(0 != (fd = kzalloc(sizeof(*fd), GFP_KERNEL)));
+ fd->buf.size = PAGE_SIZE;
+ VERIFY(0 == alloc_mem(&fd->buf));
+ fd->tgid = current->tgid;
+ INIT_HLIST_NODE(&fd->hn);
+ *dev = fd;
+ bail:
+ if (err)
+ free_dev(fd);
+ return err;
+}
+
+static int get_dev(struct fastrpc_apps *me, struct fastrpc_device **rdev)
+{
+ struct hlist_head *head;
+ struct fastrpc_device *dev = 0;
+ struct hlist_node *n;
+ uint32_t h = hash_32(current->tgid, RPC_HASH_BITS);
+ int err = 0;
+
+ spin_lock(&me->hlock);
+ head = &me->htbl[h];
+ hlist_for_each_entry(dev, n, head, hn) {
+ if (dev->tgid == current->tgid) {
+ hlist_del(&dev->hn);
+ break;
+ }
+ }
+ spin_unlock(&me->hlock);
+ VERIFY(dev != 0);
+ *rdev = dev;
+ bail:
+ if (err) {
+ free_dev(dev);
+ err = alloc_dev(rdev);
+ }
+ return err;
+}
+
+static void add_dev(struct fastrpc_apps *me, struct fastrpc_device *dev)
+{
+ struct hlist_head *head;
+ uint32_t h = hash_32(current->tgid, RPC_HASH_BITS);
+
+ spin_lock(&me->hlock);
+ head = &me->htbl[h];
+ hlist_add_head(&dev->hn, head);
+ spin_unlock(&me->hlock);
+ return;
+}
+
+static int fastrpc_release_current_dsp_process(void);
+
+static int fastrpc_internal_invoke(struct fastrpc_apps *me, uint32_t kernel,
+ struct fastrpc_ioctl_invoke *invoke, remote_arg_t *pra)
+{
+ remote_arg_t *rpra = 0;
+ struct fastrpc_device *dev = 0;
+ struct smq_invoke_ctx *ctx = 0;
+ struct fastrpc_buf obuf, *abufs = 0, *b;
+ int interrupted = 0;
+ uint32_t sc;
+ int ii, nbufs = 0, err = 0;
+
+ sc = invoke->sc;
+ obuf.handle = 0;
+ if (REMOTE_SCALARS_LENGTH(sc)) {
+ VERIFY(0 == get_dev(me, &dev));
+ VERIFY(0 == get_page_list(kernel, sc, pra, &dev->buf, &obuf));
+ rpra = (remote_arg_t *)obuf.virt;
+ VERIFY(0 == get_args(kernel, sc, pra, rpra, invoke->pra, &obuf,
+ &abufs, &nbufs));
+ }
+
+ context_list_alloc_ctx(&me->clst, &ctx);
+ VERIFY(0 == fastrpc_invoke_send(me, invoke->handle, sc, ctx, &obuf));
+ inv_args(sc, rpra, obuf.used);
+ VERIFY(0 == (interrupted =
+ wait_for_completion_interruptible(&ctx->work)));
+ VERIFY(0 == (err = ctx->retval));
+ VERIFY(0 == put_args(kernel, sc, pra, rpra, invoke->pra));
+ bail:
+ if (interrupted) {
+ init_completion(&ctx->work);
+ if (!kernel)
+ (void)fastrpc_release_current_dsp_process();
+ wait_for_completion(&ctx->work);
+ }
+ context_free(ctx);
+ for (ii = 0, b = abufs; ii < nbufs; ++ii, ++b)
+ free_mem(b);
+ kfree(abufs);
+ if (dev) {
+ add_dev(me, dev);
+ if (obuf.handle != dev->buf.handle)
+ free_mem(&obuf);
+ }
+ return err;
+}
+
+static int fastrpc_create_current_dsp_process(void)
+{
+ int err = 0;
+ struct fastrpc_ioctl_invoke ioctl;
+ struct fastrpc_apps *me = &gfa;
+ remote_arg_t ra[1];
+ int tgid = 0;
+
+ tgid = current->tgid;
+ ra[0].buf.pv = &tgid;
+ ra[0].buf.len = sizeof(tgid);
+ ioctl.handle = 1;
+ ioctl.sc = REMOTE_SCALARS_MAKE(0, 1, 0);
+ ioctl.pra = ra;
+ VERIFY(0 == fastrpc_internal_invoke(me, 1, &ioctl, ra));
+ bail:
+ return err;
+}
+
+static int fastrpc_release_current_dsp_process(void)
+{
+ int err = 0;
+ struct fastrpc_apps *me = &gfa;
+ struct fastrpc_ioctl_invoke ioctl;
+ remote_arg_t ra[1];
+ int tgid = 0;
+
+ tgid = current->tgid;
+ ra[0].buf.pv = &tgid;
+ ra[0].buf.len = sizeof(tgid);
+ ioctl.handle = 1;
+ ioctl.sc = REMOTE_SCALARS_MAKE(1, 1, 0);
+ ioctl.pra = ra;
+ VERIFY(0 == fastrpc_internal_invoke(me, 1, &ioctl, ra));
+ bail:
+ return err;
+}
+
+static void cleanup_current_dev(void)
+{
+ struct fastrpc_apps *me = &gfa;
+ uint32_t h = hash_32(current->tgid, RPC_HASH_BITS);
+ struct hlist_head *head;
+ struct hlist_node *pos;
+ struct fastrpc_device *dev;
+
+ rnext:
+ dev = 0;
+ spin_lock(&me->hlock);
+ head = &me->htbl[h];
+ hlist_for_each_entry(dev, pos, head, hn) {
+ if (dev->tgid == current->tgid) {
+ hlist_del(&dev->hn);
+ break;
+ }
+ }
+ spin_unlock(&me->hlock);
+ if (dev) {
+ free_dev(dev);
+ goto rnext;
+ }
+ return;
+}
+
+static int fastrpc_device_release(struct inode *inode, struct file *file)
+{
+ (void)fastrpc_release_current_dsp_process();
+ cleanup_current_dev();
+ return 0;
+}
+
+static int fastrpc_device_open(struct inode *inode, struct file *filp)
+{
+ int err = 0;
+
+ if (0 != try_module_get(THIS_MODULE)) {
+ /* This call will cause a dev to be created
+ * which will addref this module
+ */
+ VERIFY(0 == fastrpc_create_current_dsp_process());
+ bail:
+ if (err)
+ cleanup_current_dev();
+ module_put(THIS_MODULE);
+ }
+ return err;
+}
+
+
+static long fastrpc_device_ioctl(struct file *file, unsigned int ioctl_num,
+ unsigned long ioctl_param)
+{
+ struct fastrpc_apps *me = &gfa;
+ struct fastrpc_ioctl_invoke invoke;
+ remote_arg_t *pra = 0;
+ void *param = (char *)ioctl_param;
+ int bufs, err = 0;
+
+ switch (ioctl_num) {
+ case FASTRPC_IOCTL_INVOKE:
+ VERIFY(0 == copy_from_user(&invoke, param, sizeof(invoke)));
+ bufs = REMOTE_SCALARS_INBUFS(invoke.sc) +
+ REMOTE_SCALARS_OUTBUFS(invoke.sc);
+ if (bufs) {
+ bufs = bufs * sizeof(*pra);
+ VERIFY(0 != (pra = kmalloc(bufs, GFP_KERNEL)));
+ }
+ VERIFY(0 == copy_from_user(pra, invoke.pra, bufs));
+ VERIFY(0 == (err = fastrpc_internal_invoke(me, 0, &invoke,
+ pra)));
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+ bail:
+ kfree(pra);
+ return err;
+}
+
+static const struct file_operations fops = {
+ .open = fastrpc_device_open,
+ .release = fastrpc_device_release,
+ .unlocked_ioctl = fastrpc_device_ioctl,
+};
+
+static int __init fastrpc_device_init(void)
+{
+ struct fastrpc_apps *me = &gfa;
+ int err = 0;
+
+ VERIFY(0 == fastrpc_init());
+ VERIFY(0 == alloc_chrdev_region(&me->dev_no, 0, 1, DEVICE_NAME));
+ cdev_init(&me->cdev, &fops);
+ me->cdev.owner = THIS_MODULE;
+ VERIFY(0 == cdev_add(&me->cdev, MKDEV(MAJOR(me->dev_no), 0), 1));
+ pr_info("'mknod /dev/%s c %d 0'\n", DEVICE_NAME, MAJOR(me->dev_no));
+ bail:
+ return err;
+}
+
+static void __exit fastrpc_device_exit(void)
+{
+ struct fastrpc_apps *me = &gfa;
+
+ fastrpc_deinit();
+ cdev_del(&me->cdev);
+ unregister_chrdev_region(me->dev_no, 1);
+}
+
+module_init(fastrpc_device_init);
+module_exit(fastrpc_device_exit);
+
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp6v2/adsprpc.h b/arch/arm/mach-msm/qdsp6v2/adsprpc.h
new file mode 100644
index 0000000..368b8e6
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/adsprpc.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef ADSPRPC_H
+#define ADSPRPC_H
+
+#include <linux/slab.h>
+#include <linux/completion.h>
+#include <linux/pagemap.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/cdev.h>
+#include <linux/list.h>
+#include <linux/hash.h>
+#include <linux/ion.h>
+#include <mach/msm_smd.h>
+#include <mach/ion.h>
+#include "adsprpc_shared.h"
+
+#ifndef ION_ADSPRPC_HEAP_ID
+#define ION_ADSPRPC_HEAP_ID ION_AUDIO_HEAP_ID
+#endif
+
+#define RPC_TIMEOUT (5 * HZ)
+#define RPC_HASH_BITS 5
+#define RPC_HASH_SZ (1 << RPC_HASH_BITS)
+
+#define ALIGN_8(a) ALIGN(a, 8)
+
+#define LOCK_MMAP(kernel)\
+ do {\
+ if (!kernel)\
+ down_read(¤t->mm->mmap_sem);\
+ } while (0)
+
+#define UNLOCK_MMAP(kernel)\
+ do {\
+ if (!kernel)\
+ up_read(¤t->mm->mmap_sem);\
+ } while (0)
+
+
+static inline uint32_t buf_page_start(void *buf)
+{
+ uint32_t start = (uint32_t) buf & PAGE_MASK;
+ return start;
+}
+
+static inline uint32_t buf_page_offset(void *buf)
+{
+ uint32_t offset = (uint32_t) buf & (PAGE_SIZE - 1);
+ return offset;
+}
+
+static inline int buf_num_pages(void *buf, int len)
+{
+ uint32_t start = buf_page_start(buf) >> PAGE_SHIFT;
+ uint32_t end = (((uint32_t) buf + len - 1) & PAGE_MASK) >> PAGE_SHIFT;
+ int nPages = end - start + 1;
+ return nPages;
+}
+
+static inline uint32_t buf_page_size(uint32_t size)
+{
+ uint32_t sz = (size + (PAGE_SIZE - 1)) & PAGE_MASK;
+ return sz > PAGE_SIZE ? sz : PAGE_SIZE;
+}
+
+static inline int buf_get_pages(void *addr, int sz, int nr_pages, int access,
+ struct smq_phy_page *pages, int nr_elems)
+{
+ struct vm_area_struct *vma;
+ uint32_t start = buf_page_start(addr);
+ uint32_t len = nr_pages << PAGE_SHIFT;
+ uint32_t pfn;
+ int n = -1, err = 0;
+
+ VERIFY(0 != access_ok(access ? VERIFY_WRITE : VERIFY_READ,
+ (void __user *)start, len));
+ VERIFY(0 != (vma = find_vma(current->mm, start)));
+ VERIFY(((uint32_t)addr + sz) <= vma->vm_end);
+ n = 0;
+ VERIFY(0 != (vma->vm_flags & VM_PFNMAP));
+ VERIFY(0 != (vma->vm_flags & VM_PFN_AT_MMAP));
+ VERIFY(nr_elems > 0);
+ pfn = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
+ pages->addr = __pfn_to_phys(pfn);
+ pages->size = len;
+ n++;
+ bail:
+ return n;
+}
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp6v2/adsprpc_shared.h b/arch/arm/mach-msm/qdsp6v2/adsprpc_shared.h
new file mode 100644
index 0000000..04b1d4a
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/adsprpc_shared.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef ADSPRPC_SHARED_H
+#define ADSPRPC_SHARED_H
+
+#define FASTRPC_IOCTL_INVOKE _IOWR('R', 1, struct fastrpc_ioctl_invoke)
+#define FASTRPC_SMD_GUID "fastrpcsmd-apps-dsp"
+#define DEVICE_NAME "adsprpc-smd"
+
+/* Retrives number of input buffers from the scalars parameter */
+#define REMOTE_SCALARS_INBUFS(sc) (((sc) >> 16) & 0x0ff)
+
+/* Retrives number of output buffers from the scalars parameter */
+#define REMOTE_SCALARS_OUTBUFS(sc) (((sc) >> 8) & 0x0ff)
+
+/* Retrives number of input handles from the scalars parameter */
+#define REMOTE_SCALARS_INHANDLES(sc) (((sc) >> 4) & 0x0f)
+
+/* Retrives number of output handles from the scalars parameter */
+#define REMOTE_SCALARS_OUTHANDLES(sc) ((sc) & 0x0f)
+
+#define REMOTE_SCALARS_LENGTH(sc) (REMOTE_SCALARS_INBUFS(sc) +\
+ REMOTE_SCALARS_OUTBUFS(sc) +\
+ REMOTE_SCALARS_INHANDLES(sc) +\
+ REMOTE_SCALARS_OUTHANDLES(sc))
+
+#define REMOTE_SCALARS_MAKEX(attr, method, in, out, oin, oout) \
+ ((((uint32_t) (attr) & 0x7) << 29) | \
+ (((uint32_t) (method) & 0x1f) << 24) | \
+ (((uint32_t) (in) & 0xff) << 16) | \
+ (((uint32_t) (out) & 0xff) << 8) | \
+ (((uint32_t) (oin) & 0x0f) << 4) | \
+ ((uint32_t) (oout) & 0x0f))
+
+#define REMOTE_SCALARS_MAKE(method, in, out) \
+ REMOTE_SCALARS_MAKEX(0, method, in, out, 0, 0)
+
+
+#ifndef VERIFY_PRINT_ERROR
+#define VERIFY_EPRINTF(format, args) (void)0
+#endif
+
+#ifndef VERIFY_PRINT_INFO
+#define VERIFY_IPRINTF(args) (void)0
+#endif
+
+#ifndef VERIFY
+#define __STR__(x) #x ":"
+#define __TOSTR__(x) __STR__(x)
+#define __FILE_LINE__ __FILE__ ":" __TOSTR__(__LINE__)
+
+#define VERIFY(val) \
+do {\
+ VERIFY_IPRINTF(__FILE_LINE__"info: calling: " #val "\n");\
+ if (0 == (val)) {\
+ err = err == 0 ? -1 : err;\
+ VERIFY_EPRINTF(__FILE_LINE__"error: %d: " #val "\n", err);\
+ goto bail;\
+ } else {\
+ VERIFY_IPRINTF(__FILE_LINE__"info: passed: " #val "\n");\
+ } \
+} while (0)
+#endif
+
+#define remote_handle_t uint32_t
+#define remote_arg_t union remote_arg
+
+struct remote_buf {
+ void *pv; /* buffer pointer */
+ int len; /* length of buffer */
+};
+
+union remote_arg {
+ struct remote_buf buf; /* buffer info */
+ remote_handle_t h; /* remote handle */
+};
+
+struct fastrpc_ioctl_invoke {
+ remote_handle_t handle; /* remote handle */
+ uint32_t sc; /* scalars describing the data */
+ remote_arg_t *pra; /* remote arguments list */
+};
+
+struct smq_null_invoke {
+ struct smq_invoke_ctx *ctx; /* invoke caller context */
+ remote_handle_t handle; /* handle to invoke */
+ uint32_t sc; /* scalars structure describing the data */
+};
+
+struct smq_phy_page {
+ uint32_t addr; /* physical address */
+ uint32_t size; /* size of contiguous region */
+};
+
+struct smq_invoke_buf {
+ int num; /* number of contiguous regions */
+ int pgidx; /* index to start of contiguous region */
+};
+
+struct smq_invoke {
+ struct smq_null_invoke header;
+ struct smq_phy_page page; /* remote arg and list of pages address */
+};
+
+struct smq_msg {
+ uint32_t pid; /* process group id */
+ uint32_t tid; /* thread id */
+ struct smq_invoke invoke;
+};
+
+struct smq_invoke_rsp {
+ struct smq_invoke_ctx *ctx; /* invoke caller context */
+ int retval; /* invoke return value */
+};
+
+static inline struct smq_invoke_buf *smq_invoke_buf_start(remote_arg_t *pra,
+ uint32_t sc)
+{
+ int len = REMOTE_SCALARS_LENGTH(sc);
+ return (struct smq_invoke_buf *)(&pra[len]);
+}
+
+static inline struct smq_phy_page *smq_phy_page_start(uint32_t sc,
+ struct smq_invoke_buf *buf)
+{
+ int nTotal = REMOTE_SCALARS_INBUFS(sc) + REMOTE_SCALARS_OUTBUFS(sc);
+ return (struct smq_phy_page *)(&buf[nTotal]);
+}
+
+static inline int smq_invoke_buf_size(uint32_t sc, int nPages)
+{
+ struct smq_phy_page *start = smq_phy_page_start(sc, 0);
+ return (int)(&(start[nPages]));
+}
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
index a7e34d9..84a79cd 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
@@ -471,13 +471,20 @@
pr_debug("%s[%p]:\n", __func__, audio);
- mutex_lock(&audio->write_lock);
audio->eos_rsp = 0;
+ pr_debug("%s[%p]Wait for write done from DSP\n", __func__, audio);
rc = wait_event_interruptible(audio->write_wait,
(list_empty(&audio->out_queue)) ||
audio->wflush || audio->stopped);
+ if (audio->stopped || audio->wflush) {
+ pr_debug("%s[%p]: Audio Flushed or Stopped,this is not EOS\n"
+ , __func__, audio);
+ audio->wflush = 0;
+ rc = -EBUSY;
+ }
+
if (rc < 0) {
pr_err("%s[%p]: wait event for list_empty failed, rc = %d\n",
__func__, audio, rc);
@@ -485,11 +492,14 @@
}
rc = q6asm_cmd(audio->ac, CMD_EOS);
+ pr_debug("%s[%p]: EOS cmd sent to DSP\n", __func__, audio);
if (rc < 0)
pr_err("%s[%p]: q6asm_cmd failed, rc = %d",
__func__, audio, rc);
+ pr_debug("%s[%p]: wait for RENDERED_EOS from DSP\n"
+ , __func__, audio);
rc = wait_event_interruptible(audio->write_wait,
(audio->eos_rsp || audio->wflush ||
audio->stopped));
@@ -500,22 +510,18 @@
goto done;
}
- if (audio->eos_rsp == 1) {
- rc = audio_aio_enable(audio);
- if (rc)
- pr_err("%s[%p]: audio enable failed\n",
- __func__, audio);
- else {
- audio->drv_status &= ~ADRV_STATUS_PAUSE;
- audio->enabled = 1;
- }
+ if (audio->stopped || audio->wflush) {
+ audio->wflush = 0;
+ pr_debug("%s[%p]: Audio Flushed or Stopped,this is not EOS\n"
+ , __func__, audio);
+ rc = -EBUSY;
}
- if (audio->stopped || audio->wflush)
- rc = -EBUSY;
+ if (audio->eos_rsp == 1)
+ pr_debug("%s[%p]: EOS\n", __func__, audio);
+
done:
- mutex_unlock(&audio->write_lock);
mutex_lock(&audio->lock);
audio->drv_status &= ~ADRV_STATUS_FSYNC;
mutex_unlock(&audio->lock);
@@ -963,7 +969,8 @@
audio->drv_ops.out_flush(audio);
} else
audio->drv_ops.out_flush(audio);
- audio->drv_ops.in_flush(audio);
+ if (audio->feedback == NON_TUNNEL_MODE)
+ audio->drv_ops.in_flush(audio);
}
}
@@ -1050,8 +1057,14 @@
switch (cmd) {
case AUDIO_GET_STATS: {
struct msm_audio_stats stats;
+ uint64_t timestamp;
stats.byte_count = atomic_read(&audio->in_bytes);
stats.sample_count = atomic_read(&audio->in_samples);
+ timestamp = q6asm_get_session_time(audio->ac);
+ if (timestamp >= 0)
+ memcpy(&stats.unused[0], ×tamp, sizeof(timestamp));
+ else
+ pr_debug("Error while getting timestamp\n");
if (copy_to_user((void *)arg, &stats, sizeof(stats)))
rc = -EFAULT;
break;
@@ -1167,7 +1180,11 @@
rc = -EINTR;
} else {
audio->rflush = 0;
- audio->wflush = 0;
+ if (audio->drv_status & ADRV_STATUS_FSYNC)
+ wake_up(&audio->write_wait);
+ else
+ audio->wflush = 0;
+
}
audio->eos_flag = 0;
audio->eos_rsp = 0;
diff --git a/arch/arm/mach-msm/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c
index a190342..a9d1ed8 100644
--- a/arch/arm/mach-msm/rpm-smd.c
+++ b/arch/arm/mach-msm/rpm-smd.c
@@ -289,9 +289,10 @@
if (!handle)
return;
- for (i = 0; i < handle->write_idx; i++)
+ for (i = 0; i < handle->num_elements; i++)
kfree(handle->kvp[i].value);
kfree(handle->kvp);
+ kfree(handle->buf);
kfree(handle);
}
EXPORT_SYMBOL(msm_rpm_free_request);
diff --git a/arch/arm/mach-msm/smd_pkt.c b/arch/arm/mach-msm/smd_pkt.c
index 30acebf..928e59b 100644
--- a/arch/arm/mach-msm/smd_pkt.c
+++ b/arch/arm/mach-msm/smd_pkt.c
@@ -35,6 +35,7 @@
#include <mach/msm_smd.h>
#include <mach/peripheral-loader.h>
+#include <mach/msm_ipc_logging.h>
#include "smd_private.h"
#ifdef CONFIG_ARCH_FSM9XXX
@@ -89,6 +90,9 @@
static void check_and_wakeup_writer(struct smd_pkt_dev *smd_pkt_devp);
static uint32_t is_modem_smsm_inited(void);
+#define SMD_PKT_IPC_LOG_PAGE_CNT 2
+static void *smd_pkt_ilctxt;
+
static int msm_smd_pkt_debug_mask;
module_param_named(debug_mask, msm_smd_pkt_debug_mask,
int, S_IRUGO | S_IWUSR | S_IWGRP);
@@ -105,22 +109,44 @@
#define DEBUG
#ifdef DEBUG
+
+#define SMD_PKT_LOG_STRING(x...) \
+do { \
+ if (smd_pkt_ilctxt) \
+ ipc_log_string(smd_pkt_ilctxt, "<SMD_PKT>: "x); \
+} while (0)
+
+#define SMD_PKT_LOG_BUF(buf, cnt) \
+do { \
+ char log_buf[128]; \
+ int i; \
+ if (smd_pkt_ilctxt) { \
+ i = cnt < 16 ? cnt : 16; \
+ hex_dump_to_buffer(buf, i, 16, 1, log_buf, \
+ sizeof(log_buf), false); \
+ ipc_log_string(smd_pkt_ilctxt, "<SMD_PKT>: %s", log_buf); \
+ } \
+} while (0)
+
#define D_STATUS(x...) \
do { \
if (msm_smd_pkt_debug_mask & SMD_PKT_STATUS) \
pr_info("Status: "x); \
+ SMD_PKT_LOG_STRING(x); \
} while (0)
#define D_READ(x...) \
do { \
if (msm_smd_pkt_debug_mask & SMD_PKT_READ) \
pr_info("Read: "x); \
+ SMD_PKT_LOG_STRING(x); \
} while (0)
#define D_WRITE(x...) \
do { \
if (msm_smd_pkt_debug_mask & SMD_PKT_WRITE) \
pr_info("Write: "x); \
+ SMD_PKT_LOG_STRING(x); \
} while (0)
#define D_READ_DUMP_BUFFER(prestr, cnt, buf) \
@@ -129,6 +155,7 @@
print_hex_dump(KERN_INFO, prestr, \
DUMP_PREFIX_NONE, 16, 1, \
buf, cnt, 1); \
+ SMD_PKT_LOG_BUF(buf, cnt); \
} while (0)
#define D_WRITE_DUMP_BUFFER(prestr, cnt, buf) \
@@ -137,12 +164,14 @@
print_hex_dump(KERN_INFO, prestr, \
DUMP_PREFIX_NONE, 16, 1, \
buf, cnt, 1); \
+ SMD_PKT_LOG_BUF(buf, cnt); \
} while (0)
#define D_POLL(x...) \
do { \
if (msm_smd_pkt_debug_mask & SMD_PKT_POLL) \
pr_info("Poll: "x); \
+ SMD_PKT_LOG_STRING(x); \
} while (0)
#define E_SMD_PKT_SSR(x) \
@@ -1032,6 +1061,9 @@
INIT_DELAYED_WORK(&loopback_work, loopback_probe_worker);
+ smd_pkt_ilctxt = ipc_log_context_create(SMD_PKT_IPC_LOG_PAGE_CNT,
+ "smd_pkt");
+
D_STATUS("SMD Packet Port Driver Initialized.\n");
return 0;
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index 0318a70..bae1ab0 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -58,11 +58,13 @@
enum subsys_state {
SUBSYS_OFFLINE,
SUBSYS_ONLINE,
+ SUBSYS_CRASHED,
};
static const char * const subsys_states[] = {
[SUBSYS_OFFLINE] = "OFFLINE",
[SUBSYS_ONLINE] = "ONLINE",
+ [SUBSYS_CRASHED] = "CRASHED",
};
struct subsys_device {
@@ -71,7 +73,7 @@
char wlname[64];
struct work_struct work;
spinlock_t restart_lock;
- int restart_count;
+ bool restarting;
void *notify;
struct device dev;
@@ -107,6 +109,21 @@
return snprintf(buf, PAGE_SIZE, "%s\n", subsys_states[state]);
}
+static void subsys_set_state(struct subsys_device *subsys,
+ enum subsys_state state)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&subsys->restart_lock, flags);
+ if (subsys->state != state) {
+ subsys->state = state;
+ spin_unlock_irqrestore(&subsys->restart_lock, flags);
+ sysfs_notify(&subsys->dev.kobj, NULL, "state");
+ return;
+ }
+ spin_unlock_irqrestore(&subsys->restart_lock, flags);
+}
+
static struct device_attribute subsys_attrs[] = {
__ATTR_RO(name),
__ATTR_RO(state),
@@ -333,6 +350,7 @@
if (dev->desc->shutdown(dev->desc) < 0)
panic("subsys-restart: [%p]: Failed to shutdown %s!",
current, name);
+ subsys_set_state(dev, SUBSYS_OFFLINE);
}
static void subsystem_ramdump(struct subsys_device *dev, void *data)
@@ -351,6 +369,7 @@
pr_info("[%p]: Powering up %s\n", current, name);
if (dev->desc->powerup(dev->desc) < 0)
panic("[%p]: Failed to powerup %s!", current, name);
+ subsys_set_state(dev, SUBSYS_ONLINE);
}
static int __find_subsys(struct device *dev, void *data)
@@ -418,7 +437,10 @@
* Now that we've acquired the shutdown lock, either we're the first to
* restart these subsystems or some other thread is doing the powerup
* sequence for these subsystems. In the latter case, panic and bail
- * out, since a subsystem died in its powerup sequence.
+ * out, since a subsystem died in its powerup sequence. This catches
+ * the case where a subsystem in a restart order isn't the one
+ * who initiated the original restart but has crashed while the restart
+ * order is being rebooted.
*/
if (!mutex_trylock(powerup_lock))
panic("%s[%p]: Subsystem died during powerup!",
@@ -465,32 +487,36 @@
out:
spin_lock_irqsave(&dev->restart_lock, flags);
- dev->restart_count--;
- if (!dev->restart_count)
- wake_unlock(&dev->wake_lock);
+ dev->restarting = false;
+ wake_unlock(&dev->wake_lock);
spin_unlock_irqrestore(&dev->restart_lock, flags);
}
static void __subsystem_restart_dev(struct subsys_device *dev)
{
struct subsys_desc *desc = dev->desc;
+ const char *name = dev->desc->name;
unsigned long flags;
pr_debug("Restarting %s [level=%d]!\n", desc->name, restart_level);
+ /*
+ * We want to allow drivers to call subsystem_restart{_dev}() as many
+ * times as they want up until the point where the subsystem is
+ * shutdown.
+ */
spin_lock_irqsave(&dev->restart_lock, flags);
- if (!dev->restart_count)
- wake_lock(&dev->wake_lock);
- dev->restart_count++;
- spin_unlock_irqrestore(&dev->restart_lock, flags);
-
- if (!queue_work(ssr_wq, &dev->work)) {
- spin_lock_irqsave(&dev->restart_lock, flags);
- dev->restart_count--;
- if (!dev->restart_count)
- wake_unlock(&dev->wake_lock);
- spin_unlock_irqrestore(&dev->restart_lock, flags);
+ if (dev->state != SUBSYS_CRASHED) {
+ if (dev->state == SUBSYS_ONLINE && !dev->restarting) {
+ dev->restarting = true;
+ dev->state = SUBSYS_CRASHED;
+ wake_lock(&dev->wake_lock);
+ queue_work(ssr_wq, &dev->work);
+ } else {
+ panic("Subsystem %s crashed during SSR!", name);
+ }
}
+ spin_unlock_irqrestore(&dev->restart_lock, flags);
}
int subsystem_restart_dev(struct subsys_device *dev)
@@ -644,6 +670,7 @@
subsys->dev.parent = desc->dev;
subsys->dev.bus = &subsys_bus_type;
subsys->dev.release = subsys_device_release;
+ subsys->state = SUBSYS_ONLINE; /* Until proper refcounting appears */
subsys->notify = subsys_notif_add_subsys(desc->name);
subsys->restart_order = update_restart_order(subsys);
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index ed03b33..19ef5a6 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -37,6 +37,9 @@
#include "fault.h"
+#define CREATE_TRACE_POINTS
+#include <trace/events/exception.h>
+
#ifdef CONFIG_MMU
#ifdef CONFIG_KPROBES
@@ -173,6 +176,8 @@
{
struct siginfo si;
+ trace_user_fault(tsk, addr, fsr);
+
#ifdef CONFIG_DEBUG_USER
if (((user_debug & UDBG_SEGV) && (sig == SIGSEGV)) ||
((user_debug & UDBG_BUS) && (sig == SIGBUS))) {
diff --git a/block/Kconfig.iosched b/block/Kconfig.iosched
index 4142d91..5fd98ea 100644
--- a/block/Kconfig.iosched
+++ b/block/Kconfig.iosched
@@ -32,6 +32,17 @@
a new point in the service tree and doing a batch of IO from there
in case of expiry.
+config IOSCHED_ROW
+ tristate "ROW I/O scheduler"
+ default y
+ ---help---
+ The ROW I/O scheduler gives priority to READ requests over the
+ WRITE requests when dispatching, without starving WRITE requests.
+ Requests are kept in priority queues. Dispatching is done in a RR
+ manner when the dispatch quantum for each queue is calculated
+ according to queue priority.
+ Most suitable for mobile devices.
+
config IOSCHED_CFQ
tristate "CFQ I/O scheduler"
# If BLK_CGROUP is a module, CFQ has to be built as module.
@@ -64,6 +75,16 @@
config DEFAULT_DEADLINE
bool "Deadline" if IOSCHED_DEADLINE=y
+ config DEFAULT_ROW
+ bool "ROW" if IOSCHED_ROW=y
+ help
+ The ROW I/O scheduler gives priority to READ requests
+ over the WRITE requests when dispatching, without starving
+ WRITE requests. Requests are kept in priority queues.
+ Dispatching is done in a RR manner when the dispatch quantum
+ for each queue is defined according to queue priority.
+ Most suitable for mobile devices.
+
config DEFAULT_CFQ
bool "CFQ" if IOSCHED_CFQ=y
@@ -75,6 +96,7 @@
config DEFAULT_IOSCHED
string
default "deadline" if DEFAULT_DEADLINE
+ default "row" if DEFAULT_ROW
default "cfq" if DEFAULT_CFQ
default "noop" if DEFAULT_NOOP
diff --git a/block/Makefile b/block/Makefile
index 436b220..b5e6637 100644
--- a/block/Makefile
+++ b/block/Makefile
@@ -14,6 +14,7 @@
obj-$(CONFIG_BLK_DEV_THROTTLING) += blk-throttle.o
obj-$(CONFIG_IOSCHED_NOOP) += noop-iosched.o
obj-$(CONFIG_IOSCHED_DEADLINE) += deadline-iosched.o
+obj-$(CONFIG_IOSCHED_ROW) += row-iosched.o
obj-$(CONFIG_IOSCHED_CFQ) += cfq-iosched.o
obj-$(CONFIG_IOSCHED_TEST) += test-iosched.o
diff --git a/block/row-iosched.c b/block/row-iosched.c
new file mode 100644
index 0000000..f24437c
--- /dev/null
+++ b/block/row-iosched.c
@@ -0,0 +1,681 @@
+/*
+ * ROW (Read Over Write) I/O scheduler.
+ *
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/* See Documentation/block/row-iosched.txt */
+
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/blkdev.h>
+#include <linux/elevator.h>
+#include <linux/bio.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/compiler.h>
+#include <linux/blktrace_api.h>
+#include <linux/jiffies.h>
+
+/*
+ * enum row_queue_prio - Priorities of the ROW queues
+ *
+ * This enum defines the priorities (and the number of queues)
+ * the requests will be disptributed to. The higher priority -
+ * the bigger is the dispatch quantum given to that queue.
+ * ROWQ_PRIO_HIGH_READ - is the higher priority queue.
+ *
+ */
+enum row_queue_prio {
+ ROWQ_PRIO_HIGH_READ = 0,
+ ROWQ_PRIO_REG_READ,
+ ROWQ_PRIO_HIGH_SWRITE,
+ ROWQ_PRIO_REG_SWRITE,
+ ROWQ_PRIO_REG_WRITE,
+ ROWQ_PRIO_LOW_READ,
+ ROWQ_PRIO_LOW_SWRITE,
+ ROWQ_MAX_PRIO,
+};
+
+/* Flags indicating whether idling is enabled on the queue */
+static const bool queue_idling_enabled[] = {
+ true, /* ROWQ_PRIO_HIGH_READ */
+ true, /* ROWQ_PRIO_REG_READ */
+ false, /* ROWQ_PRIO_HIGH_SWRITE */
+ false, /* ROWQ_PRIO_REG_SWRITE */
+ false, /* ROWQ_PRIO_REG_WRITE */
+ false, /* ROWQ_PRIO_LOW_READ */
+ false, /* ROWQ_PRIO_LOW_SWRITE */
+};
+
+/* Default values for row queues quantums in each dispatch cycle */
+static const int queue_quantum[] = {
+ 100, /* ROWQ_PRIO_HIGH_READ */
+ 100, /* ROWQ_PRIO_REG_READ */
+ 2, /* ROWQ_PRIO_HIGH_SWRITE */
+ 1, /* ROWQ_PRIO_REG_SWRITE */
+ 1, /* ROWQ_PRIO_REG_WRITE */
+ 1, /* ROWQ_PRIO_LOW_READ */
+ 1 /* ROWQ_PRIO_LOW_SWRITE */
+};
+
+/* Default values for idling on read queues */
+#define ROW_IDLE_TIME 50 /* 5 msec */
+#define ROW_READ_FREQ 70 /* 7 msec */
+
+/**
+ * struct rowq_idling_data - parameters for idling on the queue
+ * @idle_trigger_time: time (in jiffies). If a new request was
+ * inserted before this time value, idling
+ * will be enabled.
+ * @begin_idling: flag indicating wether we should idle
+ *
+ */
+struct rowq_idling_data {
+ unsigned long idle_trigger_time;
+ bool begin_idling;
+};
+
+/**
+ * struct row_queue - requests grouping structure
+ * @rdata: parent row_data structure
+ * @fifo: fifo of requests
+ * @prio: queue priority (enum row_queue_prio)
+ * @nr_dispatched: number of requests already dispatched in
+ * the current dispatch cycle
+ * @slice: number of requests to dispatch in a cycle
+ * @idle_data: data for idling on queues
+ *
+ */
+struct row_queue {
+ struct row_data *rdata;
+ struct list_head fifo;
+ enum row_queue_prio prio;
+
+ unsigned int nr_dispatched;
+ unsigned int slice;
+
+ /* used only for READ queues */
+ struct rowq_idling_data idle_data;
+};
+
+/**
+ * struct idling_data - data for idling on empty rqueue
+ * @idle_time: idling duration (msec)
+ * @freq: min time between two requests that
+ * triger idling (msec)
+ * @idle_work: pointer to struct delayed_work
+ *
+ */
+struct idling_data {
+ unsigned long idle_time;
+ unsigned long freq;
+
+ struct workqueue_struct *idle_workqueue;
+ struct delayed_work idle_work;
+};
+
+/**
+ * struct row_queue - Per block device rqueue structure
+ * @dispatch_queue: dispatch rqueue
+ * @row_queues: array of priority request queues with
+ * dispatch quantum per rqueue
+ * @curr_queue: index in the row_queues array of the
+ * currently serviced rqueue
+ * @read_idle: data for idling after READ request
+ * @nr_reqs: nr_reqs[0] holds the number of all READ requests in
+ * scheduler, nr_reqs[1] holds the number of all WRITE
+ * requests in scheduler
+ * @cycle_flags: used for marking unserved queueus
+ *
+ */
+struct row_data {
+ struct request_queue *dispatch_queue;
+
+ struct {
+ struct row_queue rqueue;
+ int disp_quantum;
+ } row_queues[ROWQ_MAX_PRIO];
+
+ enum row_queue_prio curr_queue;
+
+ struct idling_data read_idle;
+ unsigned int nr_reqs[2];
+
+ unsigned int cycle_flags;
+};
+
+#define RQ_ROWQ(rq) ((struct row_queue *) ((rq)->elv.priv[0]))
+
+#define row_log(q, fmt, args...) \
+ blk_add_trace_msg(q, "%s():" fmt , __func__, ##args)
+#define row_log_rowq(rdata, rowq_id, fmt, args...) \
+ blk_add_trace_msg(rdata->dispatch_queue, "rowq%d " fmt, \
+ rowq_id, ##args)
+
+static inline void row_mark_rowq_unserved(struct row_data *rd,
+ enum row_queue_prio qnum)
+{
+ rd->cycle_flags |= (1 << qnum);
+}
+
+static inline void row_clear_rowq_unserved(struct row_data *rd,
+ enum row_queue_prio qnum)
+{
+ rd->cycle_flags &= ~(1 << qnum);
+}
+
+static inline int row_rowq_unserved(struct row_data *rd,
+ enum row_queue_prio qnum)
+{
+ return rd->cycle_flags & (1 << qnum);
+}
+
+/******************** Static helper functions ***********************/
+/*
+ * kick_queue() - Wake up device driver queue thread
+ * @work: pointer to struct work_struct
+ *
+ * This is a idling delayed work function. It's purpose is to wake up the
+ * device driver in order for it to start fetching requests.
+ *
+ */
+static void kick_queue(struct work_struct *work)
+{
+ struct delayed_work *idle_work = to_delayed_work(work);
+ struct idling_data *read_data =
+ container_of(idle_work, struct idling_data, idle_work);
+ struct row_data *rd =
+ container_of(read_data, struct row_data, read_idle);
+
+ row_log_rowq(rd, rd->curr_queue, "Performing delayed work");
+ /* Mark idling process as done */
+ rd->row_queues[rd->curr_queue].rqueue.idle_data.begin_idling = false;
+
+ if (!(rd->nr_reqs[0] + rd->nr_reqs[1]))
+ row_log(rd->dispatch_queue, "No requests in scheduler");
+ else {
+ spin_lock_irq(rd->dispatch_queue->queue_lock);
+ __blk_run_queue(rd->dispatch_queue);
+ spin_unlock_irq(rd->dispatch_queue->queue_lock);
+ }
+}
+
+/*
+ * row_restart_disp_cycle() - Restart the dispatch cycle
+ * @rd: pointer to struct row_data
+ *
+ * This function restarts the dispatch cycle by:
+ * - Setting current queue to ROWQ_PRIO_HIGH_READ
+ * - For each queue: reset the number of requests dispatched in
+ * the cycle
+ */
+static inline void row_restart_disp_cycle(struct row_data *rd)
+{
+ int i;
+
+ for (i = 0; i < ROWQ_MAX_PRIO; i++)
+ rd->row_queues[i].rqueue.nr_dispatched = 0;
+
+ rd->curr_queue = ROWQ_PRIO_HIGH_READ;
+ row_log(rd->dispatch_queue, "Restarting cycle");
+}
+
+static inline void row_get_next_queue(struct row_data *rd)
+{
+ rd->curr_queue++;
+ if (rd->curr_queue == ROWQ_MAX_PRIO)
+ row_restart_disp_cycle(rd);
+}
+
+/******************* Elevator callback functions *********************/
+
+/*
+ * row_add_request() - Add request to the scheduler
+ * @q: requests queue
+ * @rq: request to add
+ *
+ */
+static void row_add_request(struct request_queue *q,
+ struct request *rq)
+{
+ struct row_data *rd = (struct row_data *)q->elevator->elevator_data;
+ struct row_queue *rqueue = RQ_ROWQ(rq);
+
+ list_add_tail(&rq->queuelist, &rqueue->fifo);
+ rd->nr_reqs[rq_data_dir(rq)]++;
+ rq_set_fifo_time(rq, jiffies); /* for statistics*/
+
+ if (queue_idling_enabled[rqueue->prio]) {
+ if (delayed_work_pending(&rd->read_idle.idle_work))
+ (void)cancel_delayed_work(
+ &rd->read_idle.idle_work);
+ if (time_before(jiffies, rqueue->idle_data.idle_trigger_time)) {
+ rqueue->idle_data.begin_idling = true;
+ row_log_rowq(rd, rqueue->prio, "Enable idling");
+ } else
+ rqueue->idle_data.begin_idling = false;
+
+ rqueue->idle_data.idle_trigger_time =
+ jiffies + msecs_to_jiffies(rd->read_idle.freq);
+ }
+ row_log_rowq(rd, rqueue->prio, "added request");
+}
+
+/*
+ * row_remove_request() - Remove given request from scheduler
+ * @q: requests queue
+ * @rq: request to remove
+ *
+ */
+static void row_remove_request(struct request_queue *q,
+ struct request *rq)
+{
+ struct row_data *rd = (struct row_data *)q->elevator->elevator_data;
+
+ rq_fifo_clear(rq);
+ rd->nr_reqs[rq_data_dir(rq)]--;
+}
+
+/*
+ * row_dispatch_insert() - move request to dispatch queue
+ * @rd: pointer to struct row_data
+ *
+ * This function moves the next request to dispatch from
+ * rd->curr_queue to the dispatch queue
+ *
+ */
+static void row_dispatch_insert(struct row_data *rd)
+{
+ struct request *rq;
+
+ rq = rq_entry_fifo(rd->row_queues[rd->curr_queue].rqueue.fifo.next);
+ row_remove_request(rd->dispatch_queue, rq);
+ elv_dispatch_add_tail(rd->dispatch_queue, rq);
+ rd->row_queues[rd->curr_queue].rqueue.nr_dispatched++;
+ row_clear_rowq_unserved(rd, rd->curr_queue);
+ row_log_rowq(rd, rd->curr_queue, " Dispatched request nr_disp = %d",
+ rd->row_queues[rd->curr_queue].rqueue.nr_dispatched);
+}
+
+/*
+ * row_choose_queue() - choose the next queue to dispatch from
+ * @rd: pointer to struct row_data
+ *
+ * Updates rd->curr_queue. Returns 1 if there are requests to
+ * dispatch, 0 if there are no requests in scheduler
+ *
+ */
+static int row_choose_queue(struct row_data *rd)
+{
+ int prev_curr_queue = rd->curr_queue;
+
+ if (!(rd->nr_reqs[0] + rd->nr_reqs[1])) {
+ row_log(rd->dispatch_queue, "No more requests in scheduler");
+ return 0;
+ }
+
+ row_get_next_queue(rd);
+
+ /*
+ * Loop over all queues to find the next queue that is not empty.
+ * Stop when you get back to curr_queue
+ */
+ while (list_empty(&rd->row_queues[rd->curr_queue].rqueue.fifo)
+ && rd->curr_queue != prev_curr_queue) {
+ /* Mark rqueue as unserved */
+ row_mark_rowq_unserved(rd, rd->curr_queue);
+ row_get_next_queue(rd);
+ }
+
+ return 1;
+}
+
+/*
+ * row_dispatch_requests() - selects the next request to dispatch
+ * @q: requests queue
+ * @force: ignored
+ *
+ * Return 0 if no requests were moved to the dispatch queue.
+ * 1 otherwise
+ *
+ */
+static int row_dispatch_requests(struct request_queue *q, int force)
+{
+ struct row_data *rd = (struct row_data *)q->elevator->elevator_data;
+ int ret = 0, currq, i;
+
+ currq = rd->curr_queue;
+
+ /*
+ * Find the first unserved queue (with higher priority then currq)
+ * that is not empty
+ */
+ for (i = 0; i < currq; i++) {
+ if (row_rowq_unserved(rd, i) &&
+ !list_empty(&rd->row_queues[i].rqueue.fifo)) {
+ row_log_rowq(rd, currq,
+ " Preemting for unserved rowq%d", i);
+ rd->curr_queue = i;
+ row_dispatch_insert(rd);
+ ret = 1;
+ goto done;
+ }
+ }
+
+ if (rd->row_queues[currq].rqueue.nr_dispatched >=
+ rd->row_queues[currq].disp_quantum) {
+ rd->row_queues[currq].rqueue.nr_dispatched = 0;
+ row_log_rowq(rd, currq, "Expiring rqueue");
+ ret = row_choose_queue(rd);
+ if (ret)
+ row_dispatch_insert(rd);
+ goto done;
+ }
+
+ /* Dispatch from curr_queue */
+ if (list_empty(&rd->row_queues[currq].rqueue.fifo)) {
+ /* check idling */
+ if (delayed_work_pending(&rd->read_idle.idle_work)) {
+ row_log_rowq(rd, currq,
+ "Delayed work pending. Exiting");
+ goto done;
+ }
+
+ if (queue_idling_enabled[currq] &&
+ rd->row_queues[currq].rqueue.idle_data.begin_idling) {
+ if (!queue_delayed_work(rd->read_idle.idle_workqueue,
+ &rd->read_idle.idle_work,
+ jiffies +
+ msecs_to_jiffies(rd->read_idle.idle_time))) {
+ row_log_rowq(rd, currq,
+ "Work already on queue!");
+ pr_err("ROW_BUG: Work already on queue!");
+ } else
+ row_log_rowq(rd, currq,
+ "Scheduled delayed work. exiting");
+ goto done;
+ } else {
+ row_log_rowq(rd, currq,
+ "Currq empty. Choose next queue");
+ ret = row_choose_queue(rd);
+ if (!ret)
+ goto done;
+ }
+ }
+
+ ret = 1;
+ row_dispatch_insert(rd);
+
+done:
+ return ret;
+}
+
+/*
+ * row_init_queue() - Init scheduler data structures
+ * @q: requests queue
+ *
+ * Return pointer to struct row_data to be saved in elevator for
+ * this dispatch queue
+ *
+ */
+static void *row_init_queue(struct request_queue *q)
+{
+
+ struct row_data *rdata;
+ int i;
+
+ rdata = kmalloc_node(sizeof(*rdata),
+ GFP_KERNEL | __GFP_ZERO, q->node);
+ if (!rdata)
+ return NULL;
+
+ for (i = 0; i < ROWQ_MAX_PRIO; i++) {
+ INIT_LIST_HEAD(&rdata->row_queues[i].rqueue.fifo);
+ rdata->row_queues[i].disp_quantum = queue_quantum[i];
+ rdata->row_queues[i].rqueue.rdata = rdata;
+ rdata->row_queues[i].rqueue.prio = i;
+ rdata->row_queues[i].rqueue.idle_data.begin_idling = false;
+ }
+
+ /*
+ * Currently idling is enabled only for READ queues. If we want to
+ * enable it for write queues also, note that idling frequency will
+ * be the same in both cases
+ */
+ rdata->read_idle.idle_time = ROW_IDLE_TIME;
+ rdata->read_idle.freq = ROW_READ_FREQ;
+ rdata->read_idle.idle_workqueue = alloc_workqueue("row_idle_work",
+ WQ_MEM_RECLAIM | WQ_HIGHPRI, 0);
+ if (!rdata->read_idle.idle_workqueue)
+ panic("Failed to create idle workqueue\n");
+ INIT_DELAYED_WORK(&rdata->read_idle.idle_work, kick_queue);
+
+ rdata->curr_queue = ROWQ_PRIO_HIGH_READ;
+ rdata->dispatch_queue = q;
+
+ rdata->nr_reqs[READ] = rdata->nr_reqs[WRITE] = 0;
+
+ return rdata;
+}
+
+/*
+ * row_exit_queue() - called on unloading the RAW scheduler
+ * @e: poiner to struct elevator_queue
+ *
+ */
+static void row_exit_queue(struct elevator_queue *e)
+{
+ struct row_data *rd = (struct row_data *)e->elevator_data;
+ int i;
+
+ for (i = 0; i < ROWQ_MAX_PRIO; i++)
+ BUG_ON(!list_empty(&rd->row_queues[i].rqueue.fifo));
+ (void)cancel_delayed_work_sync(&rd->read_idle.idle_work);
+ kfree(rd);
+}
+
+/*
+ * row_merged_requests() - Called when 2 requests are merged
+ * @q: requests queue
+ * @rq: request the two requests were merged into
+ * @next: request that was merged
+ */
+static void row_merged_requests(struct request_queue *q, struct request *rq,
+ struct request *next)
+{
+ struct row_queue *rqueue = RQ_ROWQ(next);
+
+ list_del_init(&next->queuelist);
+
+ rqueue->rdata->nr_reqs[rq_data_dir(rq)]--;
+}
+
+/*
+ * get_queue_type() - Get queue type for a given request
+ *
+ * This is a helping function which purpose is to determine what
+ * ROW queue the given request should be added to (and
+ * dispatched from leter on)
+ *
+ * TODO: Right now only 3 queues are used REG_READ, REG_WRITE
+ * and REG_SWRITE
+ */
+static enum row_queue_prio get_queue_type(struct request *rq)
+{
+ const int data_dir = rq_data_dir(rq);
+ const bool is_sync = rq_is_sync(rq);
+
+ if (data_dir == READ)
+ return ROWQ_PRIO_REG_READ;
+ else if (is_sync)
+ return ROWQ_PRIO_REG_SWRITE;
+ else
+ return ROWQ_PRIO_REG_WRITE;
+}
+
+/*
+ * row_set_request() - Set ROW data structures associated with this request.
+ * @q: requests queue
+ * @rq: pointer to the request
+ * @gfp_mask: ignored
+ *
+ */
+static int
+row_set_request(struct request_queue *q, struct request *rq, gfp_t gfp_mask)
+{
+ struct row_data *rd = (struct row_data *)q->elevator->elevator_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(q->queue_lock, flags);
+ rq->elv.priv[0] =
+ (void *)(&rd->row_queues[get_queue_type(rq)]);
+ spin_unlock_irqrestore(q->queue_lock, flags);
+
+ return 0;
+}
+
+/********** Helping sysfs functions/defenitions for ROW attributes ******/
+static ssize_t row_var_show(int var, char *page)
+{
+ return snprintf(page, 100, "%d\n", var);
+}
+
+static ssize_t row_var_store(int *var, const char *page, size_t count)
+{
+ int err;
+ err = kstrtoul(page, 10, (unsigned long *)var);
+
+ return count;
+}
+
+#define SHOW_FUNCTION(__FUNC, __VAR, __CONV) \
+static ssize_t __FUNC(struct elevator_queue *e, char *page) \
+{ \
+ struct row_data *rowd = e->elevator_data; \
+ int __data = __VAR; \
+ if (__CONV) \
+ __data = jiffies_to_msecs(__data); \
+ return row_var_show(__data, (page)); \
+}
+SHOW_FUNCTION(row_hp_read_quantum_show,
+ rowd->row_queues[ROWQ_PRIO_HIGH_READ].disp_quantum, 0);
+SHOW_FUNCTION(row_rp_read_quantum_show,
+ rowd->row_queues[ROWQ_PRIO_REG_READ].disp_quantum, 0);
+SHOW_FUNCTION(row_hp_swrite_quantum_show,
+ rowd->row_queues[ROWQ_PRIO_HIGH_SWRITE].disp_quantum, 0);
+SHOW_FUNCTION(row_rp_swrite_quantum_show,
+ rowd->row_queues[ROWQ_PRIO_REG_SWRITE].disp_quantum, 0);
+SHOW_FUNCTION(row_rp_write_quantum_show,
+ rowd->row_queues[ROWQ_PRIO_REG_WRITE].disp_quantum, 0);
+SHOW_FUNCTION(row_lp_read_quantum_show,
+ rowd->row_queues[ROWQ_PRIO_LOW_READ].disp_quantum, 0);
+SHOW_FUNCTION(row_lp_swrite_quantum_show,
+ rowd->row_queues[ROWQ_PRIO_LOW_SWRITE].disp_quantum, 0);
+SHOW_FUNCTION(row_read_idle_show, rowd->read_idle.idle_time, 1);
+SHOW_FUNCTION(row_read_idle_freq_show, rowd->read_idle.freq, 1);
+#undef SHOW_FUNCTION
+
+#define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV) \
+static ssize_t __FUNC(struct elevator_queue *e, \
+ const char *page, size_t count) \
+{ \
+ struct row_data *rowd = e->elevator_data; \
+ int __data; \
+ int ret = row_var_store(&__data, (page), count); \
+ if (__CONV) \
+ __data = (int)msecs_to_jiffies(__data); \
+ if (__data < (MIN)) \
+ __data = (MIN); \
+ else if (__data > (MAX)) \
+ __data = (MAX); \
+ *(__PTR) = __data; \
+ return ret; \
+}
+STORE_FUNCTION(row_hp_read_quantum_store,
+ &rowd->row_queues[ROWQ_PRIO_HIGH_READ].disp_quantum, 0,
+ INT_MAX, 0);
+STORE_FUNCTION(row_rp_read_quantum_store,
+ &rowd->row_queues[ROWQ_PRIO_REG_READ].disp_quantum, 0,
+ INT_MAX, 0);
+STORE_FUNCTION(row_hp_swrite_quantum_store,
+ &rowd->row_queues[ROWQ_PRIO_HIGH_SWRITE].disp_quantum, 0,
+ INT_MAX, 0);
+STORE_FUNCTION(row_rp_swrite_quantum_store,
+ &rowd->row_queues[ROWQ_PRIO_REG_SWRITE].disp_quantum, 0,
+ INT_MAX, 0);
+STORE_FUNCTION(row_rp_write_quantum_store,
+ &rowd->row_queues[ROWQ_PRIO_REG_WRITE].disp_quantum, 0,
+ INT_MAX, 0);
+STORE_FUNCTION(row_lp_read_quantum_store,
+ &rowd->row_queues[ROWQ_PRIO_LOW_READ].disp_quantum, 0,
+ INT_MAX, 0);
+STORE_FUNCTION(row_lp_swrite_quantum_store,
+ &rowd->row_queues[ROWQ_PRIO_LOW_SWRITE].disp_quantum, 0,
+ INT_MAX, 1);
+STORE_FUNCTION(row_read_idle_store, &rowd->read_idle.idle_time, 1, INT_MAX, 1);
+STORE_FUNCTION(row_read_idle_freq_store, &rowd->read_idle.freq,
+ 1, INT_MAX, 1);
+
+#undef STORE_FUNCTION
+
+#define ROW_ATTR(name) \
+ __ATTR(name, S_IRUGO|S_IWUSR, row_##name##_show, \
+ row_##name##_store)
+
+static struct elv_fs_entry row_attrs[] = {
+ ROW_ATTR(hp_read_quantum),
+ ROW_ATTR(rp_read_quantum),
+ ROW_ATTR(hp_swrite_quantum),
+ ROW_ATTR(rp_swrite_quantum),
+ ROW_ATTR(rp_write_quantum),
+ ROW_ATTR(lp_read_quantum),
+ ROW_ATTR(lp_swrite_quantum),
+ ROW_ATTR(read_idle),
+ ROW_ATTR(read_idle_freq),
+ __ATTR_NULL
+};
+
+static struct elevator_type iosched_row = {
+ .ops = {
+ .elevator_merge_req_fn = row_merged_requests,
+ .elevator_dispatch_fn = row_dispatch_requests,
+ .elevator_add_req_fn = row_add_request,
+ .elevator_former_req_fn = elv_rb_former_request,
+ .elevator_latter_req_fn = elv_rb_latter_request,
+ .elevator_set_req_fn = row_set_request,
+ .elevator_init_fn = row_init_queue,
+ .elevator_exit_fn = row_exit_queue,
+ },
+
+ .elevator_attrs = row_attrs,
+ .elevator_name = "row",
+ .elevator_owner = THIS_MODULE,
+};
+
+static int __init row_init(void)
+{
+ elv_register(&iosched_row);
+ return 0;
+}
+
+static void __exit row_exit(void)
+{
+ elv_unregister(&iosched_row);
+}
+
+module_init(row_init);
+module_exit(row_exit);
+
+MODULE_LICENSE("GPLv2");
+MODULE_DESCRIPTION("Read Over Write IO scheduler");
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index b18d709..a8e33b5 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -39,16 +39,16 @@
#define POOL_TYPE_HSIC 8
#define POOL_TYPE_HSIC_WRITE 16
#define POOL_TYPE_ALL 7
-#define MODEM_DATA 1
-#define QDSP_DATA 2
-#define APPS_DATA 3
+#define MODEM_DATA 1
+#define LPASS_DATA 2
+#define APPS_DATA 3
#define SDIO_DATA 4
#define WCNSS_DATA 5
#define HSIC_DATA 6
#define SMUX_DATA 7
#define MODEM_PROC 0
#define APPS_PROC 1
-#define QDSP_PROC 2
+#define LPASS_PROC 2
#define WCNSS_PROC 3
#define MSG_MASK_SIZE 10000
#define LOG_MASK_SIZE 8000
@@ -181,9 +181,9 @@
unsigned char *buf_in_1;
unsigned char *buf_in_2;
unsigned char *buf_in_cntl;
- unsigned char *buf_in_qdsp_1;
- unsigned char *buf_in_qdsp_2;
- unsigned char *buf_in_qdsp_cntl;
+ unsigned char *buf_in_lpass_1;
+ unsigned char *buf_in_lpass_2;
+ unsigned char *buf_in_lpass_cntl;
unsigned char *buf_in_wcnss_1;
unsigned char *buf_in_wcnss_2;
unsigned char *buf_in_wcnss_cntl;
@@ -198,14 +198,14 @@
smd_channel_t *ch;
smd_channel_t *ch_cntl;
smd_channel_t *ch_dci;
- smd_channel_t *chqdsp;
- smd_channel_t *chqdsp_cntl;
+ smd_channel_t *chlpass;
+ smd_channel_t *chlpass_cntl;
smd_channel_t *ch_wcnss;
smd_channel_t *ch_wcnss_cntl;
int in_busy_1;
int in_busy_2;
- int in_busy_qdsp_1;
- int in_busy_qdsp_2;
+ int in_busy_lpass_1;
+ int in_busy_lpass_2;
int in_busy_wcnss_1;
int in_busy_wcnss_2;
int in_busy_dci;
@@ -223,13 +223,13 @@
struct work_struct diag_drain_work;
struct work_struct diag_read_smd_work;
struct work_struct diag_read_smd_cntl_work;
- struct work_struct diag_read_smd_qdsp_work;
- struct work_struct diag_read_smd_qdsp_cntl_work;
+ struct work_struct diag_read_smd_lpass_work;
+ struct work_struct diag_read_smd_lpass_cntl_work;
struct work_struct diag_read_smd_wcnss_work;
struct work_struct diag_read_smd_wcnss_cntl_work;
struct workqueue_struct *diag_cntl_wq;
struct work_struct diag_modem_mask_update_work;
- struct work_struct diag_qdsp_mask_update_work;
+ struct work_struct diag_lpass_mask_update_work;
struct work_struct diag_wcnss_mask_update_work;
struct work_struct diag_read_smd_dci_work;
struct work_struct diag_clean_modem_reg_work;
@@ -246,8 +246,8 @@
struct diag_request *write_ptr_2;
struct diag_request *usb_read_ptr;
struct diag_request *write_ptr_svc;
- struct diag_request *write_ptr_qdsp_1;
- struct diag_request *write_ptr_qdsp_2;
+ struct diag_request *write_ptr_lpass_1;
+ struct diag_request *write_ptr_lpass_2;
struct diag_request *write_ptr_wcnss_1;
struct diag_request *write_ptr_wcnss_2;
struct diag_write_device *write_ptr_dci;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 59139dc..814fe64 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -151,9 +151,9 @@
__diag_smd_send_req();
}
-void diag_read_smd_qdsp_work_fn(struct work_struct *work)
+void diag_read_smd_lpass_work_fn(struct work_struct *work)
{
- __diag_smd_qdsp_send_req();
+ __diag_smd_lpass_send_req();
}
void diag_read_smd_wcnss_work_fn(struct work_struct *work)
@@ -548,8 +548,8 @@
== NO_LOGGING_MODE) {
driver->in_busy_1 = 1;
driver->in_busy_2 = 1;
- driver->in_busy_qdsp_1 = 1;
- driver->in_busy_qdsp_2 = 1;
+ driver->in_busy_lpass_1 = 1;
+ driver->in_busy_lpass_2 = 1;
driver->in_busy_wcnss_1 = 1;
driver->in_busy_wcnss_2 = 1;
#ifdef CONFIG_DIAG_SDIO_PIPE
@@ -563,17 +563,17 @@
== MEMORY_DEVICE_MODE) {
driver->in_busy_1 = 0;
driver->in_busy_2 = 0;
- driver->in_busy_qdsp_1 = 0;
- driver->in_busy_qdsp_2 = 0;
+ driver->in_busy_lpass_1 = 0;
+ driver->in_busy_lpass_2 = 0;
driver->in_busy_wcnss_1 = 0;
driver->in_busy_wcnss_2 = 0;
/* Poll SMD channels to check for data*/
if (driver->ch)
queue_work(driver->diag_wq,
&(driver->diag_read_smd_work));
- if (driver->chqdsp)
+ if (driver->chlpass)
queue_work(driver->diag_wq,
- &(driver->diag_read_smd_qdsp_work));
+ &(driver->diag_read_smd_lpass_work));
if (driver->ch_wcnss)
queue_work(driver->diag_wq,
&(driver->diag_read_smd_wcnss_work));
@@ -606,8 +606,8 @@
diagfwd_disconnect();
driver->in_busy_1 = 0;
driver->in_busy_2 = 0;
- driver->in_busy_qdsp_1 = 0;
- driver->in_busy_qdsp_2 = 0;
+ driver->in_busy_lpass_1 = 0;
+ driver->in_busy_lpass_2 = 0;
driver->in_busy_wcnss_1 = 0;
driver->in_busy_wcnss_2 = 0;
@@ -615,9 +615,9 @@
if (driver->ch)
queue_work(driver->diag_wq,
&(driver->diag_read_smd_work));
- if (driver->chqdsp)
+ if (driver->chlpass)
queue_work(driver->diag_wq,
- &(driver->diag_read_smd_qdsp_work));
+ &(driver->diag_read_smd_lpass_work));
if (driver->ch_wcnss)
queue_work(driver->diag_wq,
&(driver->diag_read_smd_wcnss_work));
@@ -747,27 +747,27 @@
driver->in_busy_2 = 0;
}
/* copy lpass data */
- if (driver->in_busy_qdsp_1 == 1) {
+ if (driver->in_busy_lpass_1 == 1) {
num_data++;
/*Copy the length of data being passed*/
COPY_USER_SPACE_OR_EXIT(buf+ret,
- (driver->write_ptr_qdsp_1->length), 4);
+ (driver->write_ptr_lpass_1->length), 4);
/*Copy the actual data being passed*/
COPY_USER_SPACE_OR_EXIT(buf+ret, *(driver->
- buf_in_qdsp_1),
- driver->write_ptr_qdsp_1->length);
- driver->in_busy_qdsp_1 = 0;
+ buf_in_lpass_1),
+ driver->write_ptr_lpass_1->length);
+ driver->in_busy_lpass_1 = 0;
}
- if (driver->in_busy_qdsp_2 == 1) {
+ if (driver->in_busy_lpass_2 == 1) {
num_data++;
/*Copy the length of data being passed*/
COPY_USER_SPACE_OR_EXIT(buf+ret,
- (driver->write_ptr_qdsp_2->length), 4);
+ (driver->write_ptr_lpass_2->length), 4);
/*Copy the actual data being passed*/
COPY_USER_SPACE_OR_EXIT(buf+ret, *(driver->
- buf_in_qdsp_2), driver->
- write_ptr_qdsp_2->length);
- driver->in_busy_qdsp_2 = 0;
+ buf_in_lpass_2), driver->
+ write_ptr_lpass_2->length);
+ driver->in_busy_lpass_2 = 0;
}
/* copy wncss data */
if (driver->in_busy_wcnss_1 == 1) {
@@ -886,9 +886,9 @@
if (driver->ch)
queue_work(driver->diag_wq,
&(driver->diag_read_smd_work));
- if (driver->chqdsp)
+ if (driver->chlpass)
queue_work(driver->diag_wq,
- &(driver->diag_read_smd_qdsp_work));
+ &(driver->diag_read_smd_lpass_work));
if (driver->ch_wcnss)
queue_work(driver->diag_wq,
&(driver->diag_read_smd_wcnss_work));
@@ -1403,10 +1403,10 @@
INIT_WORK(&(driver->diag_read_smd_work), diag_read_smd_work_fn);
INIT_WORK(&(driver->diag_read_smd_cntl_work),
diag_read_smd_cntl_work_fn);
- INIT_WORK(&(driver->diag_read_smd_qdsp_work),
- diag_read_smd_qdsp_work_fn);
- INIT_WORK(&(driver->diag_read_smd_qdsp_cntl_work),
- diag_read_smd_qdsp_cntl_work_fn);
+ INIT_WORK(&(driver->diag_read_smd_lpass_work),
+ diag_read_smd_lpass_work_fn);
+ INIT_WORK(&(driver->diag_read_smd_lpass_cntl_work),
+ diag_read_smd_lpass_cntl_work_fn);
INIT_WORK(&(driver->diag_read_smd_wcnss_work),
diag_read_smd_wcnss_work_fn);
INIT_WORK(&(driver->diag_read_smd_wcnss_cntl_work),
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index c827ec7..737edbf 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -50,7 +50,7 @@
unsigned char diag_debug_buf[1024];
static unsigned int buf_tbl_size = 8; /*Number of entries in table of buffers */
struct diag_master_table entry;
-smd_channel_t *ch_temp = NULL, *chqdsp_temp = NULL, *ch_wcnss_temp = NULL;
+smd_channel_t *ch_temp = NULL, *chlpass_temp = NULL, *ch_wcnss_temp = NULL;
int diag_event_num_bytes;
int diag_event_config;
struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
@@ -353,11 +353,11 @@
driver->in_busy_2 = 0;
queue_work(driver->diag_wq, &(driver->
diag_read_smd_work));
- } else if (proc_num == QDSP_DATA) {
- driver->in_busy_qdsp_1 = 0;
- driver->in_busy_qdsp_2 = 0;
+ } else if (proc_num == LPASS_DATA) {
+ driver->in_busy_lpass_1 = 0;
+ driver->in_busy_lpass_2 = 0;
queue_work(driver->diag_wq, &(driver->
- diag_read_smd_qdsp_work));
+ diag_read_smd_lpass_work));
} else if (proc_num == WCNSS_DATA) {
driver->in_busy_wcnss_1 = 0;
driver->in_busy_wcnss_2 = 0;
@@ -403,7 +403,7 @@
buf, write_ptr->length, 1);
#endif /* DIAG DEBUG */
err = usb_diag_write(driver->legacy_ch, write_ptr);
- } else if (proc_num == QDSP_DATA) {
+ } else if (proc_num == LPASS_DATA) {
write_ptr->buf = buf;
err = usb_diag_write(driver->legacy_ch, write_ptr);
} else if (proc_num == WCNSS_DATA) {
@@ -510,24 +510,24 @@
}
}
-void __diag_smd_qdsp_send_req(void)
+void __diag_smd_lpass_send_req(void)
{
void *buf = NULL;
- int *in_busy_qdsp_ptr = NULL;
- struct diag_request *write_ptr_qdsp = NULL;
+ int *in_busy_lpass_ptr = NULL;
+ struct diag_request *write_ptr_lpass = NULL;
- if (!driver->in_busy_qdsp_1) {
- buf = driver->buf_in_qdsp_1;
- write_ptr_qdsp = driver->write_ptr_qdsp_1;
- in_busy_qdsp_ptr = &(driver->in_busy_qdsp_1);
- } else if (!driver->in_busy_qdsp_2) {
- buf = driver->buf_in_qdsp_2;
- write_ptr_qdsp = driver->write_ptr_qdsp_2;
- in_busy_qdsp_ptr = &(driver->in_busy_qdsp_2);
+ if (!driver->in_busy_lpass_1) {
+ buf = driver->buf_in_lpass_1;
+ write_ptr_lpass = driver->write_ptr_lpass_1;
+ in_busy_lpass_ptr = &(driver->in_busy_lpass_1);
+ } else if (!driver->in_busy_lpass_2) {
+ buf = driver->buf_in_lpass_2;
+ write_ptr_lpass = driver->write_ptr_lpass_2;
+ in_busy_lpass_ptr = &(driver->in_busy_lpass_2);
}
- if (driver->chqdsp && buf) {
- int r = smd_read_avail(driver->chqdsp);
+ if (driver->chlpass && buf) {
+ int r = smd_read_avail(driver->chlpass);
if (r > IN_BUF_SIZE) {
if (r < MAX_IN_BUF_SIZE) {
@@ -542,18 +542,18 @@
}
if (r > 0) {
if (!buf)
- printk(KERN_INFO "Out of diagmem for QDSP\n");
+ printk(KERN_INFO "Out of diagmem for LPASS\n");
else {
APPEND_DEBUG('i');
- smd_read(driver->chqdsp, buf, r);
+ smd_read(driver->chlpass, buf, r);
APPEND_DEBUG('j');
- write_ptr_qdsp->length = r;
- *in_busy_qdsp_ptr = 1;
- diag_device_write(buf, QDSP_DATA,
- write_ptr_qdsp);
+ write_ptr_lpass->length = r;
+ *in_busy_lpass_ptr = 1;
+ diag_device_write(buf, LPASS_DATA,
+ write_ptr_lpass);
}
}
- } else if (driver->chqdsp && !buf &&
+ } else if (driver->chlpass && !buf &&
(driver->logging_mode == MEMORY_DEVICE_MODE)) {
chk_logging_wakeup();
}
@@ -856,9 +856,9 @@
RESET_ID)
return;
smd_write(driver->ch, buf, len);
- } else if (entry.client_id == QDSP_PROC &&
- driver->chqdsp) {
- smd_write(driver->chqdsp, buf, len);
+ } else if (entry.client_id == LPASS_PROC &&
+ driver->chlpass) {
+ smd_write(driver->chlpass, buf, len);
} else if (entry.client_id == WCNSS_PROC &&
driver->ch_wcnss) {
smd_write(driver->ch_wcnss, buf, len);
@@ -877,12 +877,12 @@
diag_send_event_mask_update(driver->ch_cntl, diag_event_num_bytes);
}
-void diag_qdsp_mask_update_fn(struct work_struct *work)
+void diag_lpass_mask_update_fn(struct work_struct *work)
{
- diag_send_msg_mask_update(driver->chqdsp_cntl, ALL_SSID,
- ALL_SSID, QDSP_PROC);
- diag_send_log_mask_update(driver->chqdsp_cntl, ALL_EQUIP_ID);
- diag_send_event_mask_update(driver->chqdsp_cntl, diag_event_num_bytes);
+ diag_send_msg_mask_update(driver->chlpass_cntl, ALL_SSID,
+ ALL_SSID, LPASS_PROC);
+ diag_send_log_mask_update(driver->chlpass_cntl, ALL_EQUIP_ID);
+ diag_send_event_mask_update(driver->chlpass_cntl, diag_event_num_bytes);
}
void diag_wcnss_mask_update_fn(struct work_struct *work)
@@ -1078,8 +1078,8 @@
if (driver->ch_cntl)
diag_send_log_mask_update(driver->ch_cntl,
*(int *)buf);
- if (driver->chqdsp_cntl)
- diag_send_log_mask_update(driver->chqdsp_cntl,
+ if (driver->chlpass_cntl)
+ diag_send_log_mask_update(driver->chlpass_cntl,
*(int *)buf);
if (driver->ch_wcnss_cntl)
diag_send_log_mask_update(driver->ch_wcnss_cntl,
@@ -1124,16 +1124,17 @@
driver->apps_rsp_buf[2] = 0x0;
driver->apps_rsp_buf[3] = 0x0;
*(int *)(driver->apps_rsp_buf + 4) = 0x0;
+ *(int *)(driver->apps_rsp_buf + 8) = 0x0; /* status */
if (driver->ch_cntl)
diag_send_log_mask_update(driver->ch_cntl,
ALL_EQUIP_ID);
- if (driver->chqdsp_cntl)
- diag_send_log_mask_update(driver->chqdsp_cntl,
+ if (driver->chlpass_cntl)
+ diag_send_log_mask_update(driver->chlpass_cntl,
ALL_EQUIP_ID);
if (driver->ch_wcnss_cntl)
diag_send_log_mask_update(driver->ch_wcnss_cntl,
ALL_EQUIP_ID);
- ENCODE_RSP_AND_SEND(7);
+ ENCODE_RSP_AND_SEND(11);
return 0;
}
#endif
@@ -1186,9 +1187,9 @@
if (driver->ch_cntl)
diag_send_msg_mask_update(driver->ch_cntl,
ssid_first, ssid_last, MODEM_PROC);
- if (driver->chqdsp_cntl)
- diag_send_msg_mask_update(driver->chqdsp_cntl,
- ssid_first, ssid_last, QDSP_PROC);
+ if (driver->chlpass_cntl)
+ diag_send_msg_mask_update(driver->chlpass_cntl,
+ ssid_first, ssid_last, LPASS_PROC);
if (driver->ch_wcnss_cntl)
diag_send_msg_mask_update(driver->ch_wcnss_cntl,
ssid_first, ssid_last, WCNSS_PROC);
@@ -1213,9 +1214,9 @@
if (driver->ch_cntl)
diag_send_msg_mask_update(driver->ch_cntl,
ALL_SSID, ALL_SSID, MODEM_PROC);
- if (driver->chqdsp_cntl)
- diag_send_msg_mask_update(driver->chqdsp_cntl,
- ALL_SSID, ALL_SSID, QDSP_PROC);
+ if (driver->chlpass_cntl)
+ diag_send_msg_mask_update(driver->chlpass_cntl,
+ ALL_SSID, ALL_SSID, LPASS_PROC);
if (driver->ch_wcnss_cntl)
diag_send_msg_mask_update(driver->ch_wcnss_cntl,
ALL_SSID, ALL_SSID, WCNSS_PROC);
@@ -1241,9 +1242,10 @@
if (driver->ch_cntl)
diag_send_event_mask_update(driver->ch_cntl,
diag_event_num_bytes);
- if (driver->chqdsp_cntl)
- diag_send_event_mask_update(driver->chqdsp_cntl,
- diag_event_num_bytes);
+ if (driver->chlpass_cntl)
+ diag_send_event_mask_update(
+ driver->chlpass_cntl,
+ diag_event_num_bytes);
if (driver->ch_wcnss_cntl)
diag_send_event_mask_update(
driver->ch_wcnss_cntl, diag_event_num_bytes);
@@ -1264,9 +1266,10 @@
if (driver->ch_cntl)
diag_send_event_mask_update(driver->ch_cntl,
diag_event_num_bytes);
- if (driver->chqdsp_cntl)
- diag_send_event_mask_update(driver->chqdsp_cntl,
- diag_event_num_bytes);
+ if (driver->chlpass_cntl)
+ diag_send_event_mask_update(
+ driver->chlpass_cntl,
+ diag_event_num_bytes);
if (driver->ch_wcnss_cntl)
diag_send_event_mask_update(
driver->ch_wcnss_cntl, diag_event_num_bytes);
@@ -1650,8 +1653,8 @@
if (chk_apps_only()) {
diag_send_error_rsp(hdlc.dest_idx);
} else { /* APQ 8060, Let Q6 respond */
- if (driver->chqdsp)
- smd_write(driver->chqdsp, driver->hdlc_buf,
+ if (driver->chlpass)
+ smd_write(driver->chlpass, driver->hdlc_buf,
hdlc.dest_idx - 3);
}
type = 0;
@@ -1694,18 +1697,18 @@
driver->usb_connected = 1;
driver->in_busy_1 = 0;
driver->in_busy_2 = 0;
- driver->in_busy_qdsp_1 = 0;
- driver->in_busy_qdsp_2 = 0;
+ driver->in_busy_lpass_1 = 0;
+ driver->in_busy_lpass_2 = 0;
driver->in_busy_wcnss_1 = 0;
driver->in_busy_wcnss_2 = 0;
/* Poll SMD channels to check for data*/
queue_work(driver->diag_wq, &(driver->diag_read_smd_work));
- queue_work(driver->diag_wq, &(driver->diag_read_smd_qdsp_work));
+ queue_work(driver->diag_wq, &(driver->diag_read_smd_lpass_work));
queue_work(driver->diag_wq, &(driver->diag_read_smd_wcnss_work));
/* Poll SMD CNTL channels to check for data */
diag_smd_cntl_notify(NULL, SMD_EVENT_DATA);
- diag_smd_qdsp_cntl_notify(NULL, SMD_EVENT_DATA);
+ diag_smd_lpass_cntl_notify(NULL, SMD_EVENT_DATA);
diag_smd_wcnss_cntl_notify(NULL, SMD_EVENT_DATA);
/* Poll USB channel to check for data*/
queue_work(driver->diag_wq, &(driver->diag_read_work));
@@ -1729,8 +1732,8 @@
if (driver->logging_mode == USB_MODE) {
driver->in_busy_1 = 1;
driver->in_busy_2 = 1;
- driver->in_busy_qdsp_1 = 1;
- driver->in_busy_qdsp_2 = 1;
+ driver->in_busy_lpass_1 = 1;
+ driver->in_busy_lpass_2 = 1;
driver->in_busy_wcnss_1 = 1;
driver->in_busy_wcnss_2 = 1;
}
@@ -1756,14 +1759,16 @@
driver->in_busy_2 = 0;
APPEND_DEBUG('O');
queue_work(driver->diag_wq, &(driver->diag_read_smd_work));
- } else if (buf == (void *)driver->buf_in_qdsp_1) {
- driver->in_busy_qdsp_1 = 0;
+ } else if (buf == (void *)driver->buf_in_lpass_1) {
+ driver->in_busy_lpass_1 = 0;
APPEND_DEBUG('p');
- queue_work(driver->diag_wq, &(driver->diag_read_smd_qdsp_work));
- } else if (buf == (void *)driver->buf_in_qdsp_2) {
- driver->in_busy_qdsp_2 = 0;
+ queue_work(driver->diag_wq,
+ &(driver->diag_read_smd_lpass_work));
+ } else if (buf == (void *)driver->buf_in_lpass_2) {
+ driver->in_busy_lpass_2 = 0;
APPEND_DEBUG('P');
- queue_work(driver->diag_wq, &(driver->diag_read_smd_qdsp_work));
+ queue_work(driver->diag_wq,
+ &(driver->diag_read_smd_lpass_work));
} else if (buf == driver->buf_in_wcnss_1) {
driver->in_busy_wcnss_1 = 0;
APPEND_DEBUG('r');
@@ -1889,18 +1894,18 @@
}
#if defined(CONFIG_MSM_N_WAY_SMD)
-static void diag_smd_qdsp_notify(void *ctxt, unsigned event)
+static void diag_smd_lpass_notify(void *ctxt, unsigned event)
{
if (event == SMD_EVENT_CLOSE) {
queue_work(driver->diag_cntl_wq,
&(driver->diag_clean_lpass_reg_work));
- driver->chqdsp = 0;
+ driver->chlpass = 0;
return;
} else if (event == SMD_EVENT_OPEN) {
- if (chqdsp_temp)
- driver->chqdsp = chqdsp_temp;
+ if (chlpass_temp)
+ driver->chlpass = chlpass_temp;
}
- queue_work(driver->diag_wq, &(driver->diag_read_smd_qdsp_work));
+ queue_work(driver->diag_wq, &(driver->diag_read_smd_lpass_work));
}
#endif
@@ -1928,9 +1933,9 @@
}
#if defined(CONFIG_MSM_N_WAY_SMD)
if (pdev->id == SMD_APPS_QDSP) {
- r = smd_named_open_on_edge("DIAG", SMD_APPS_QDSP
- , &driver->chqdsp, driver, diag_smd_qdsp_notify);
- chqdsp_temp = driver->chqdsp;
+ r = smd_named_open_on_edge("DIAG", SMD_APPS_QDSP,
+ &driver->chlpass, driver, diag_smd_lpass_notify);
+ chlpass_temp = driver->chlpass;
}
#endif
if (pdev->id == SMD_APPS_WCNSS) {
@@ -2022,17 +2027,17 @@
goto err;
kmemleak_not_leak(driver->buf_in_2);
}
- if (driver->buf_in_qdsp_1 == NULL) {
- driver->buf_in_qdsp_1 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
- if (driver->buf_in_qdsp_1 == NULL)
+ if (driver->buf_in_lpass_1 == NULL) {
+ driver->buf_in_lpass_1 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
+ if (driver->buf_in_lpass_1 == NULL)
goto err;
- kmemleak_not_leak(driver->buf_in_qdsp_1);
+ kmemleak_not_leak(driver->buf_in_lpass_1);
}
- if (driver->buf_in_qdsp_2 == NULL) {
- driver->buf_in_qdsp_2 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
- if (driver->buf_in_qdsp_2 == NULL)
+ if (driver->buf_in_lpass_2 == NULL) {
+ driver->buf_in_lpass_2 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
+ if (driver->buf_in_lpass_2 == NULL)
goto err;
- kmemleak_not_leak(driver->buf_in_qdsp_2);
+ kmemleak_not_leak(driver->buf_in_lpass_2);
}
if (driver->buf_in_wcnss_1 == NULL) {
driver->buf_in_wcnss_1 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
@@ -2136,19 +2141,19 @@
goto err;
kmemleak_not_leak(driver->write_ptr_2);
}
- if (driver->write_ptr_qdsp_1 == NULL) {
- driver->write_ptr_qdsp_1 = kzalloc(
+ if (driver->write_ptr_lpass_1 == NULL) {
+ driver->write_ptr_lpass_1 = kzalloc(
sizeof(struct diag_request), GFP_KERNEL);
- if (driver->write_ptr_qdsp_1 == NULL)
+ if (driver->write_ptr_lpass_1 == NULL)
goto err;
- kmemleak_not_leak(driver->write_ptr_qdsp_1);
+ kmemleak_not_leak(driver->write_ptr_lpass_1);
}
- if (driver->write_ptr_qdsp_2 == NULL) {
- driver->write_ptr_qdsp_2 = kzalloc(
+ if (driver->write_ptr_lpass_2 == NULL) {
+ driver->write_ptr_lpass_2 = kzalloc(
sizeof(struct diag_request), GFP_KERNEL);
- if (driver->write_ptr_qdsp_2 == NULL)
+ if (driver->write_ptr_lpass_2 == NULL)
goto err;
- kmemleak_not_leak(driver->write_ptr_qdsp_2);
+ kmemleak_not_leak(driver->write_ptr_lpass_2);
}
if (driver->write_ptr_wcnss_1 == NULL) {
driver->write_ptr_wcnss_1 = kzalloc(
@@ -2189,8 +2194,8 @@
INIT_WORK(&(driver->diag_read_work), diag_read_work_fn);
INIT_WORK(&(driver->diag_modem_mask_update_work),
diag_modem_mask_update_fn);
- INIT_WORK(&(driver->diag_qdsp_mask_update_work),
- diag_qdsp_mask_update_fn);
+ INIT_WORK(&(driver->diag_lpass_mask_update_work),
+ diag_lpass_mask_update_fn);
INIT_WORK(&(driver->diag_wcnss_mask_update_work),
diag_wcnss_mask_update_fn);
driver->legacy_ch = usb_diag_open(DIAG_LEGACY, driver,
@@ -2211,8 +2216,8 @@
kfree(driver->msg_mask);
kfree(driver->buf_in_1);
kfree(driver->buf_in_2);
- kfree(driver->buf_in_qdsp_1);
- kfree(driver->buf_in_qdsp_2);
+ kfree(driver->buf_in_lpass_1);
+ kfree(driver->buf_in_lpass_2);
kfree(driver->buf_in_wcnss_1);
kfree(driver->buf_in_wcnss_2);
kfree(driver->buf_msg_mask_update);
@@ -2230,8 +2235,8 @@
kfree(driver->pkt_buf);
kfree(driver->write_ptr_1);
kfree(driver->write_ptr_2);
- kfree(driver->write_ptr_qdsp_1);
- kfree(driver->write_ptr_qdsp_2);
+ kfree(driver->write_ptr_lpass_1);
+ kfree(driver->write_ptr_lpass_2);
kfree(driver->write_ptr_wcnss_1);
kfree(driver->write_ptr_wcnss_2);
kfree(driver->usb_read_ptr);
@@ -2244,10 +2249,10 @@
void diagfwd_exit(void)
{
smd_close(driver->ch);
- smd_close(driver->chqdsp);
+ smd_close(driver->chlpass);
smd_close(driver->ch_wcnss);
driver->ch = 0; /* SMD can make this NULL */
- driver->chqdsp = 0;
+ driver->chlpass = 0;
driver->ch_wcnss = 0;
#ifdef CONFIG_DIAG_OVER_USB
if (driver->usb_connected)
@@ -2262,8 +2267,8 @@
kfree(driver->msg_mask);
kfree(driver->buf_in_1);
kfree(driver->buf_in_2);
- kfree(driver->buf_in_qdsp_1);
- kfree(driver->buf_in_qdsp_2);
+ kfree(driver->buf_in_lpass_1);
+ kfree(driver->buf_in_lpass_2);
kfree(driver->buf_in_wcnss_1);
kfree(driver->buf_in_wcnss_2);
kfree(driver->buf_msg_mask_update);
@@ -2281,8 +2286,8 @@
kfree(driver->pkt_buf);
kfree(driver->write_ptr_1);
kfree(driver->write_ptr_2);
- kfree(driver->write_ptr_qdsp_1);
- kfree(driver->write_ptr_qdsp_2);
+ kfree(driver->write_ptr_lpass_1);
+ kfree(driver->write_ptr_lpass_2);
kfree(driver->write_ptr_wcnss_1);
kfree(driver->write_ptr_wcnss_2);
kfree(driver->usb_read_ptr);
diff --git a/drivers/char/diag/diagfwd.h b/drivers/char/diag/diagfwd.h
index f5de2ac..cf7fda6 100644
--- a/drivers/char/diag/diagfwd.h
+++ b/drivers/char/diag/diagfwd.h
@@ -20,7 +20,7 @@
void diagfwd_exit(void);
void diag_process_hdlc(void *data, unsigned len);
void __diag_smd_send_req(void);
-void __diag_smd_qdsp_send_req(void);
+void __diag_smd_lpass_send_req(void);
void __diag_smd_wcnss_send_req(void);
void diag_usb_legacy_notifier(void *, unsigned, struct diag_request *);
long diagchar_ioctl(struct file *, unsigned int, unsigned long);
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index e417d5a..9fc1164 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -36,7 +36,7 @@
{
pr_debug("diag: clean lpass registration\n");
reg_dirty |= DIAG_CON_LPASS;
- diag_clear_reg(QDSP_PROC);
+ diag_clear_reg(LPASS_PROC);
reg_dirty ^= DIAG_CON_LPASS;
}
@@ -72,26 +72,26 @@
}
}
-void diag_smd_qdsp_cntl_notify(void *ctxt, unsigned event)
+void diag_smd_lpass_cntl_notify(void *ctxt, unsigned event)
{
int r1, r2;
- if (!(driver->chqdsp_cntl))
+ if (!(driver->chlpass_cntl))
return;
switch (event) {
case SMD_EVENT_DATA:
- r1 = smd_read_avail(driver->chqdsp_cntl);
- r2 = smd_cur_packet_size(driver->chqdsp_cntl);
+ r1 = smd_read_avail(driver->chlpass_cntl);
+ r2 = smd_cur_packet_size(driver->chlpass_cntl);
if (r1 > 0 && r1 == r2)
queue_work(driver->diag_wq,
- &(driver->diag_read_smd_qdsp_cntl_work));
+ &(driver->diag_read_smd_lpass_cntl_work));
else
pr_debug("diag: incomplete pkt on LPASS CNTL ch\n");
break;
case SMD_EVENT_OPEN:
queue_work(driver->diag_cntl_wq,
- &(driver->diag_qdsp_mask_update_work));
+ &(driver->diag_lpass_mask_update_work));
break;
}
}
@@ -142,9 +142,9 @@
buf = driver->buf_in_cntl;
smd_ch = driver->ch_cntl;
reg_mask = DIAG_CON_MPSS;
- } else if (proc_num == QDSP_PROC) {
- buf = driver->buf_in_qdsp_cntl;
- smd_ch = driver->chqdsp_cntl;
+ } else if (proc_num == LPASS_PROC) {
+ buf = driver->buf_in_lpass_cntl;
+ smd_ch = driver->chlpass_cntl;
reg_mask = DIAG_CON_LPASS;
} else if (proc_num == WCNSS_PROC) {
buf = driver->buf_in_wcnss_cntl;
@@ -230,8 +230,8 @@
/* Poll SMD CNTL channels to check for data */
if (proc_num == MODEM_PROC)
diag_smd_cntl_notify(NULL, SMD_EVENT_DATA);
- else if (proc_num == QDSP_PROC)
- diag_smd_qdsp_cntl_notify(NULL, SMD_EVENT_DATA);
+ else if (proc_num == LPASS_PROC)
+ diag_smd_lpass_cntl_notify(NULL, SMD_EVENT_DATA);
else if (proc_num == WCNSS_PROC)
diag_smd_wcnss_cntl_notify(NULL, SMD_EVENT_DATA);
}
@@ -242,9 +242,9 @@
diag_smd_cntl_send_req(MODEM_PROC);
}
-void diag_read_smd_qdsp_cntl_work_fn(struct work_struct *work)
+void diag_read_smd_lpass_cntl_work_fn(struct work_struct *work)
{
- diag_smd_cntl_send_req(QDSP_PROC);
+ diag_smd_cntl_send_req(LPASS_PROC);
}
void diag_read_smd_wcnss_cntl_work_fn(struct work_struct *work)
@@ -263,8 +263,8 @@
diag_smd_cntl_notify);
if (pdev->id == SMD_APPS_QDSP)
r = smd_named_open_on_edge("DIAG_CNTL", SMD_APPS_QDSP
- , &driver->chqdsp_cntl, driver,
- diag_smd_qdsp_cntl_notify);
+ , &driver->chlpass_cntl, driver,
+ diag_smd_lpass_cntl_notify);
if (pdev->id == SMD_APPS_WCNSS)
r = smd_named_open_on_edge("APPS_RIVA_CTRL",
SMD_APPS_WCNSS, &driver->ch_wcnss_cntl,
@@ -322,11 +322,11 @@
goto err;
kmemleak_not_leak(driver->buf_in_cntl);
}
- if (driver->buf_in_qdsp_cntl == NULL) {
- driver->buf_in_qdsp_cntl = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
- if (driver->buf_in_qdsp_cntl == NULL)
+ if (driver->buf_in_lpass_cntl == NULL) {
+ driver->buf_in_lpass_cntl = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
+ if (driver->buf_in_lpass_cntl == NULL)
goto err;
- kmemleak_not_leak(driver->buf_in_qdsp_cntl);
+ kmemleak_not_leak(driver->buf_in_lpass_cntl);
}
if (driver->buf_in_wcnss_cntl == NULL) {
driver->buf_in_wcnss_cntl = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
@@ -341,7 +341,7 @@
err:
pr_err("diag: Could not initialize diag buffers");
kfree(driver->buf_in_cntl);
- kfree(driver->buf_in_qdsp_cntl);
+ kfree(driver->buf_in_lpass_cntl);
kfree(driver->buf_in_wcnss_cntl);
if (driver->diag_cntl_wq)
destroy_workqueue(driver->diag_cntl_wq);
@@ -350,17 +350,17 @@
void diagfwd_cntl_exit(void)
{
smd_close(driver->ch_cntl);
- smd_close(driver->chqdsp_cntl);
+ smd_close(driver->chlpass_cntl);
smd_close(driver->ch_wcnss_cntl);
driver->ch_cntl = 0;
- driver->chqdsp_cntl = 0;
+ driver->chlpass_cntl = 0;
driver->ch_wcnss_cntl = 0;
destroy_workqueue(driver->diag_cntl_wq);
platform_driver_unregister(&msm_smd_ch1_cntl_driver);
platform_driver_unregister(&diag_smd_lite_cntl_driver);
kfree(driver->buf_in_cntl);
- kfree(driver->buf_in_qdsp_cntl);
+ kfree(driver->buf_in_lpass_cntl);
kfree(driver->buf_in_wcnss_cntl);
}
@@ -397,18 +397,18 @@
"uses device tree: %d\n"
"in_busy_1: %d\n"
"in_busy_2: %d\n"
- "in_busy_qdsp_1: %d\n"
- "in_busy_qdsp_2: %d\n"
+ "in_busy_lpass_1: %d\n"
+ "in_busy_lpass_2: %d\n"
"in_busy_wcnss_1: %d\n"
"in_busy_wcnss_2: %d\n"
"in_busy_dci: %d\n"
"logging_mode: %d\n",
(unsigned int)driver->ch,
- (unsigned int)driver->chqdsp,
+ (unsigned int)driver->chlpass,
(unsigned int)driver->ch_wcnss,
(unsigned int)driver->ch_dci,
(unsigned int)driver->ch_cntl,
- (unsigned int)driver->chqdsp_cntl,
+ (unsigned int)driver->chlpass_cntl,
(unsigned int)driver->ch_wcnss_cntl,
chk_config_get_id(),
chk_apps_only(),
@@ -418,8 +418,8 @@
driver->use_device_tree,
driver->in_busy_1,
driver->in_busy_2,
- driver->in_busy_qdsp_1,
- driver->in_busy_qdsp_2,
+ driver->in_busy_lpass_1,
+ driver->in_busy_lpass_2,
driver->in_busy_wcnss_1,
driver->in_busy_wcnss_2,
driver->in_busy_dci,
@@ -453,23 +453,23 @@
"diag_drain_work: %d\n"
"diag_read_smd_work: %d\n"
"diag_read_smd_cntl_work: %d\n"
- "diag_read_smd_qdsp_work: %d\n"
- "diag_read_smd_qdsp_cntl_work: %d\n"
+ "diag_read_smd_lpass_work: %d\n"
+ "diag_read_smd_lpass_cntl_work: %d\n"
"diag_read_smd_wcnss_work: %d\n"
"diag_read_smd_wcnss_cntl_work: %d\n"
"diag_modem_mask_update_work: %d\n"
- "diag_qdsp_mask_update_work: %d\n"
+ "diag_lpass_mask_update_work: %d\n"
"diag_wcnss_mask_update_work: %d\n"
"diag_read_smd_dci_work: %d\n",
work_pending(&(driver->diag_drain_work)),
work_pending(&(driver->diag_read_smd_work)),
work_pending(&(driver->diag_read_smd_cntl_work)),
- work_pending(&(driver->diag_read_smd_qdsp_work)),
- work_pending(&(driver->diag_read_smd_qdsp_cntl_work)),
+ work_pending(&(driver->diag_read_smd_lpass_work)),
+ work_pending(&(driver->diag_read_smd_lpass_cntl_work)),
work_pending(&(driver->diag_read_smd_wcnss_work)),
work_pending(&(driver->diag_read_smd_wcnss_cntl_work)),
work_pending(&(driver->diag_modem_mask_update_work)),
- work_pending(&(driver->diag_qdsp_mask_update_work)),
+ work_pending(&(driver->diag_lpass_mask_update_work)),
work_pending(&(driver->diag_wcnss_mask_update_work)),
work_pending(&(driver->diag_read_smd_dci_work)));
diff --git a/drivers/char/diag/diagfwd_cntl.h b/drivers/char/diag/diagfwd_cntl.h
index 59e5e6b..e6f5352 100644
--- a/drivers/char/diag/diagfwd_cntl.h
+++ b/drivers/char/diag/diagfwd_cntl.h
@@ -80,10 +80,10 @@
void diagfwd_cntl_init(void);
void diagfwd_cntl_exit(void);
void diag_read_smd_cntl_work_fn(struct work_struct *);
-void diag_read_smd_qdsp_cntl_work_fn(struct work_struct *);
+void diag_read_smd_lpass_cntl_work_fn(struct work_struct *);
void diag_read_smd_wcnss_cntl_work_fn(struct work_struct *);
void diag_smd_cntl_notify(void *ctxt, unsigned event);
-void diag_smd_qdsp_cntl_notify(void *ctxt, unsigned event);
+void diag_smd_lpass_cntl_notify(void *ctxt, unsigned event);
void diag_smd_wcnss_cntl_notify(void *ctxt, unsigned event);
void diag_clean_modem_reg_fn(struct work_struct *);
void diag_clean_lpass_reg_fn(struct work_struct *);
diff --git a/drivers/coresight/Kconfig b/drivers/coresight/Kconfig
index 1219af1..a23fff0 100644
--- a/drivers/coresight/Kconfig
+++ b/drivers/coresight/Kconfig
@@ -30,3 +30,12 @@
For production builds, you should probably say 'N' here to avoid
potential power, performance and memory penalty.
+
+config CONTROL_TRACE
+ tristate "Turn on to control tracing"
+ help
+ Builds module to abort tracing on a user space data, instruction
+ or prefetch abort.
+
+ For production builds, you should probably say 'N' here to avoid
+ potential power, performance and memory penalty.
diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile
index 4ee93cf..a2815de 100644
--- a/drivers/coresight/Makefile
+++ b/drivers/coresight/Makefile
@@ -1,3 +1,3 @@
-
+obj-$(CONFIG_CONTROL_TRACE) += control_trace.o
obj-$(CONFIG_OF) += of_coresight.o
obj-$(CONFIG_MSM_QDSS) += coresight.o coresight-csr.o coresight-tmc.o coresight-tpiu.o coresight-etb.o coresight-funnel.o coresight-replicator.o coresight-stm.o coresight-etm.o
diff --git a/drivers/coresight/control_trace.c b/drivers/coresight/control_trace.c
new file mode 100644
index 0000000..aa8bfc5
--- /dev/null
+++ b/drivers/coresight/control_trace.c
@@ -0,0 +1,71 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * DLKM to register a callback with a ftrace event
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/tracepoint.h>
+#include <linux/coresight.h>
+
+#include <trace/events/exception.h>
+
+static void abort_coresight_tracing(void *ignore, struct task_struct *task,\
+ unsigned long addr, unsigned int fsr)
+{
+ coresight_abort();
+ pr_debug("control_trace: task_name: %s, addr: %lu, fsr:%u",\
+ (char *)task->comm, addr, fsr);
+}
+
+static void abort_tracing_undef_instr(void *ignore, struct pt_regs *regs,\
+ void *pc)
+{
+ if (user_mode(regs)) {
+ coresight_abort();
+ pr_debug("control_trace: pc: %p", pc);
+ }
+}
+
+static int __init control_trace_init(void)
+{
+ int ret_user_fault, ret_undef_instr;
+ ret_user_fault = register_trace_user_fault(abort_coresight_tracing,\
+ NULL);
+ ret_undef_instr = register_trace_undef_instr(abort_tracing_undef_instr,\
+ NULL);
+ if (ret_user_fault != 0 || ret_undef_instr != 0) {
+ pr_info("control_trace: Module Not Registered\n");
+ return (ret_user_fault < 0 ?\
+ ret_user_fault : ret_undef_instr);
+ }
+ pr_info("control_trace: Module Registered\n");
+ return 0;
+}
+
+module_init(control_trace_init);
+
+static void __exit control_trace_exit(void)
+{
+ unregister_trace_user_fault(abort_coresight_tracing, NULL);
+ unregister_trace_undef_instr(abort_tracing_undef_instr, NULL);
+ pr_info("control_trace: Module Removed\n");
+}
+
+module_exit(control_trace_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Kernel Module to abort tracing");
diff --git a/drivers/coresight/coresight-etm.c b/drivers/coresight/coresight-etm.c
index f4c4d08..427cd7d 100644
--- a/drivers/coresight/coresight-etm.c
+++ b/drivers/coresight/coresight-etm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -214,22 +214,22 @@
* clock vote in the driver and the save-restore code uses 1. above
* for its vote
*/
-static void etm_set_pwrdwn(struct etm_drvdata *drvdata)
+static void etm_set_pwrup(struct etm_drvdata *drvdata)
{
- uint32_t etmcr;
+ uint32_t etmpdcr;
- etmcr = etm_readl(drvdata, ETMCR);
- etmcr |= BIT(0);
- etm_writel(drvdata, etmcr, ETMCR);
+ etmpdcr = etm_readl(drvdata, ETMPDCR);
+ etmpdcr |= BIT(3);
+ etm_writel(drvdata, etmpdcr, ETMPDCR);
}
-static void etm_clr_pwrdwn(struct etm_drvdata *drvdata)
+static void etm_clr_pwrup(struct etm_drvdata *drvdata)
{
- uint32_t etmcr;
+ uint32_t etmpdcr;
- etmcr = etm_readl(drvdata, ETMCR);
- etmcr &= ~BIT(0);
- etm_writel(drvdata, etmcr, ETMCR);
+ etmpdcr = etm_readl(drvdata, ETMPDCR);
+ etmpdcr &= ~BIT(3);
+ etm_writel(drvdata, etmpdcr, ETMPDCR);
}
static void etm_set_prog(struct etm_drvdata *drvdata)
@@ -269,7 +269,7 @@
ETM_UNLOCK(drvdata);
/* Vote for ETM power/clock enable */
- etm_clr_pwrdwn(drvdata);
+ etm_set_pwrup(drvdata);
etm_set_prog(drvdata);
etm_writel(drvdata, drvdata->ctrl | BIT(10), ETMCR);
@@ -352,7 +352,7 @@
etm_writel(drvdata, 0x6F | BIT(14), ETMTEEVR);
/* Vote for ETM power/clock disable */
- etm_set_pwrdwn(drvdata);
+ etm_clr_pwrup(drvdata);
ETM_LOCK(drvdata);
dev_dbg(drvdata->dev, "cpu: %d disable smp call done\n", drvdata->cpu);
@@ -1426,7 +1426,7 @@
smp_call_function(etm_os_unlock, NULL, 1);
ETM_UNLOCK(drvdata);
/* Vote for ETM power/clock enable */
- etm_clr_pwrdwn(drvdata);
+ etm_set_pwrup(drvdata);
/* Set prog bit. It will be set from reset but this is included to
* ensure it is set
*/
@@ -1444,7 +1444,7 @@
drvdata->nr_ctxid_cmp = BMVAL(etmccr, 24, 25);
/* Vote for ETM power/clock disable */
- etm_set_pwrdwn(drvdata);
+ etm_clr_pwrup(drvdata);
ETM_LOCK(drvdata);
}
diff --git a/drivers/gpio/gpio-msm-common.c b/drivers/gpio/gpio-msm-common.c
index 46f6460..800c376 100644
--- a/drivers/gpio/gpio-msm-common.c
+++ b/drivers/gpio/gpio-msm-common.c
@@ -300,9 +300,11 @@
spin_lock_irqsave(&tlmm_lock, irq_flags);
__set_bit(gpio, msm_gpio.enabled_irqs);
- __msm_gpio_set_intr_status(gpio);
- __msm_gpio_set_intr_cfg_enable(gpio, 1);
- mb();
+ if (!__msm_gpio_get_intr_cfg_enable(gpio)) {
+ __msm_gpio_set_intr_status(gpio);
+ __msm_gpio_set_intr_cfg_enable(gpio, 1);
+ mb();
+ }
spin_unlock_irqrestore(&tlmm_lock, irq_flags);
if (msm_gpio_irq_extn.irq_mask)
diff --git a/drivers/gpio/gpio-msm-common.h b/drivers/gpio/gpio-msm-common.h
index c9ea3da..b1590ef 100644
--- a/drivers/gpio/gpio-msm-common.h
+++ b/drivers/gpio/gpio-msm-common.h
@@ -21,6 +21,7 @@
unsigned __msm_gpio_get_intr_status(unsigned gpio);
void __msm_gpio_set_intr_status(unsigned gpio);
unsigned __msm_gpio_get_intr_config(unsigned gpio);
+unsigned __msm_gpio_get_intr_cfg_enable(unsigned gpio);
void __msm_gpio_set_intr_cfg_enable(unsigned gpio, unsigned val);
void __msm_gpio_set_intr_cfg_type(unsigned gpio, unsigned type);
void __gpio_tlmm_config(unsigned config);
diff --git a/drivers/gpio/gpio-msm-v2.c b/drivers/gpio/gpio-msm-v2.c
index 943a4a2..592391e 100644
--- a/drivers/gpio/gpio-msm-v2.c
+++ b/drivers/gpio/gpio-msm-v2.c
@@ -155,6 +155,11 @@
}
}
+unsigned __msm_gpio_get_intr_cfg_enable(unsigned gpio)
+{
+ return __msm_gpio_get_intr_config(gpio) & INTR_ENABLE;
+}
+
void __msm_gpio_set_intr_cfg_type(unsigned gpio, unsigned type)
{
unsigned cfg;
diff --git a/drivers/gpio/gpio-msm-v3.c b/drivers/gpio/gpio-msm-v3.c
index 26716a0..1da276f 100644
--- a/drivers/gpio/gpio-msm-v3.c
+++ b/drivers/gpio/gpio-msm-v3.c
@@ -163,6 +163,11 @@
__raw_writel(cfg, GPIO_INTR_CFG(gpio));
}
+unsigned __msm_gpio_get_intr_cfg_enable(unsigned gpio)
+{
+ return __msm_gpio_get_intr_config(gpio) & INTR_ENABLE;
+}
+
void __msm_gpio_set_intr_cfg_type(unsigned gpio, unsigned type)
{
unsigned cfg;
diff --git a/drivers/gpu/msm/Makefile b/drivers/gpu/msm/Makefile
index c7ed329..aacd355 100644
--- a/drivers/gpu/msm/Makefile
+++ b/drivers/gpu/msm/Makefile
@@ -17,6 +17,7 @@
msm_kgsl_core-$(CONFIG_MSM_SCM) += kgsl_pwrscale_trustzone.o
msm_kgsl_core-$(CONFIG_MSM_SLEEP_STATS_DEVICE) += kgsl_pwrscale_idlestats.o
msm_kgsl_core-$(CONFIG_MSM_DCVS) += kgsl_pwrscale_msm.o
+msm_kgsl_core-$(CONFIG_SYNC) += kgsl_sync.o
msm_adreno-y += \
adreno_ringbuffer.o \
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index b8fca38..7bf928f 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2706,62 +2706,100 @@
return val;
}
+struct a3xx_vbif_data {
+ unsigned int reg;
+ unsigned int val;
+};
+
+/* VBIF registers start after 0x3000 so use 0x0 as end of list marker */
+static struct a3xx_vbif_data a305_vbif[] = {
+ /* Set up 16 deep read/write request queues */
+ { A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010 },
+ { A3XX_VBIF_IN_RD_LIM_CONF1, 0x10101010 },
+ { A3XX_VBIF_OUT_RD_LIM_CONF0, 0x10101010 },
+ { A3XX_VBIF_OUT_WR_LIM_CONF0, 0x10101010 },
+ { A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303 },
+ { A3XX_VBIF_IN_WR_LIM_CONF0, 0x10101010 },
+ { A3XX_VBIF_IN_WR_LIM_CONF1, 0x10101010 },
+ /* Enable WR-REQ */
+ { A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x0000FF },
+ /* Set up round robin arbitration between both AXI ports */
+ { A3XX_VBIF_ARB_CTL, 0x00000030 },
+ /* Set up AOOO */
+ { A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003C },
+ { A3XX_VBIF_OUT_AXI_AOOO, 0x003C003C },
+ {0, 0},
+};
+
+static struct a3xx_vbif_data a320_vbif[] = {
+ /* Set up 16 deep read/write request queues */
+ { A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010 },
+ { A3XX_VBIF_IN_RD_LIM_CONF1, 0x10101010 },
+ { A3XX_VBIF_OUT_RD_LIM_CONF0, 0x10101010 },
+ { A3XX_VBIF_OUT_WR_LIM_CONF0, 0x10101010 },
+ { A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303 },
+ { A3XX_VBIF_IN_WR_LIM_CONF0, 0x10101010 },
+ { A3XX_VBIF_IN_WR_LIM_CONF1, 0x10101010 },
+ /* Enable WR-REQ */
+ { A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x0000FF },
+ /* Set up round robin arbitration between both AXI ports */
+ { A3XX_VBIF_ARB_CTL, 0x00000030 },
+ /* Set up AOOO */
+ { A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003C },
+ { A3XX_VBIF_OUT_AXI_AOOO, 0x003C003C },
+ /* Enable 1K sort */
+ { A3XX_VBIF_ABIT_SORT, 0x000000FF },
+ { A3XX_VBIF_ABIT_SORT_CONF, 0x000000A4 },
+ {0, 0},
+};
+
+static struct a3xx_vbif_data a330_vbif[] = {
+ /* Set up 16 deep read/write request queues */
+ { A3XX_VBIF_IN_RD_LIM_CONF0, 0x18181818 },
+ { A3XX_VBIF_IN_RD_LIM_CONF1, 0x18181818 },
+ { A3XX_VBIF_OUT_RD_LIM_CONF0, 0x18181818 },
+ { A3XX_VBIF_OUT_WR_LIM_CONF0, 0x18181818 },
+ { A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303 },
+ { A3XX_VBIF_IN_WR_LIM_CONF0, 0x18181818 },
+ { A3XX_VBIF_IN_WR_LIM_CONF1, 0x18181818 },
+ /* Enable WR-REQ */
+ { A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x00003F },
+ /* Set up round robin arbitration between both AXI ports */
+ { A3XX_VBIF_ARB_CTL, 0x00000030 },
+ /* Set up VBIF_ROUND_ROBIN_QOS_ARB */
+ { A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0001 },
+ /* Set up AOOO */
+ { A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000FFFF },
+ { A3XX_VBIF_OUT_AXI_AOOO, 0xFFFFFFFF },
+ /* Enable 1K sort */
+ { A3XX_VBIF_ABIT_SORT, 0x1FFFF },
+ { A3XX_VBIF_ABIT_SORT_CONF, 0x000000A4 },
+ /* Disable VBIF clock gating. This is to enable AXI running
+ * higher frequency than GPU.
+ */
+ { A3XX_VBIF_CLKON, 1 },
+ {0, 0},
+};
+
static void a3xx_start(struct adreno_device *adreno_dev)
{
struct kgsl_device *device = &adreno_dev->dev;
+ struct a3xx_vbif_data *vbif = NULL;
- /* Set up 16 deep read/write request queues */
- if (adreno_is_a330(adreno_dev)) {
- adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF0, 0x18181818);
- adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF1, 0x18181818);
- adreno_regwrite(device, A3XX_VBIF_OUT_RD_LIM_CONF0, 0x18181818);
- adreno_regwrite(device, A3XX_VBIF_OUT_WR_LIM_CONF0, 0x18181818);
- adreno_regwrite(device, A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303);
- adreno_regwrite(device, A3XX_VBIF_IN_WR_LIM_CONF0, 0x18181818);
- adreno_regwrite(device, A3XX_VBIF_IN_WR_LIM_CONF1, 0x18181818);
- /* Enable WR-REQ */
- adreno_regwrite(device, A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x00003F);
+ if (adreno_is_a305(adreno_dev))
+ vbif = a305_vbif;
+ else if (adreno_is_a320(adreno_dev))
+ vbif = a320_vbif;
+ else if (adreno_is_a330(adreno_dev))
+ vbif = a330_vbif;
- /* Set up round robin arbitration between both AXI ports */
- adreno_regwrite(device, A3XX_VBIF_ARB_CTL, 0x00000030);
- /* Set up VBIF_ROUND_ROBIN_QOS_ARB */
- adreno_regwrite(device, A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0001);
+ BUG_ON(vbif == NULL);
- /* Set up AOOO */
- adreno_regwrite(device, A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000FFFF);
- adreno_regwrite(device, A3XX_VBIF_OUT_AXI_AOOO, 0xFFFFFFFF);
-
- /* Enable 1K sort */
- adreno_regwrite(device, A3XX_VBIF_ABIT_SORT, 0x1FFFF);
- adreno_regwrite(device, A3XX_VBIF_ABIT_SORT_CONF, 0x000000A4);
-
- /* Diable VBIF clock gating. This is to enable AXI running
- * higher frequency than GPU.
- */
- adreno_regwrite(device, A3XX_VBIF_CLKON, 1);
- } else {
- adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010);
- adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF1, 0x10101010);
- adreno_regwrite(device, A3XX_VBIF_OUT_RD_LIM_CONF0, 0x10101010);
- adreno_regwrite(device, A3XX_VBIF_OUT_WR_LIM_CONF0, 0x10101010);
- adreno_regwrite(device, A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303);
- adreno_regwrite(device, A3XX_VBIF_IN_WR_LIM_CONF0, 0x10101010);
- adreno_regwrite(device, A3XX_VBIF_IN_WR_LIM_CONF1, 0x10101010);
- /* Enable WR-REQ */
- adreno_regwrite(device, A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x0000FF);
-
- /* Set up round robin arbitration between both AXI ports */
- adreno_regwrite(device, A3XX_VBIF_ARB_CTL, 0x00000030);
- /* Set up AOOO */
- adreno_regwrite(device, A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003C);
- adreno_regwrite(device, A3XX_VBIF_OUT_AXI_AOOO, 0x003C003C);
+ while (vbif->reg != 0) {
+ adreno_regwrite(device, vbif->reg, vbif->val);
+ vbif++;
}
- if (cpu_is_apq8064()) {
- /* Enable 1K sort */
- adreno_regwrite(device, A3XX_VBIF_ABIT_SORT, 0x000000FF);
- adreno_regwrite(device, A3XX_VBIF_ABIT_SORT_CONF, 0x000000A4);
- }
/* Make all blocks contribute to the GPU BUSY perf counter */
adreno_regwrite(device, A3XX_RBBM_GPU_BUSY_MASKED, 0xFFFFFFFF);
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index 70ad81c..7cbc7a8 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -226,7 +226,8 @@
adreno_drawctxt_switch(adreno_dev, NULL, 0);
}
- adreno_idle(device);
+ if (device->state != KGSL_STATE_HUNG)
+ adreno_idle(device);
kgsl_sharedmem_free(&drawctxt->gpustate);
kgsl_sharedmem_free(&drawctxt->context_gmem_shadow.gmemshadow);
diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c
index 08a01b0..93be980 100644
--- a/drivers/gpu/msm/adreno_snapshot.c
+++ b/drivers/gpu/msm/adreno_snapshot.c
@@ -328,8 +328,8 @@
ret = kgsl_snapshot_get_object(device, ptbase,
sp_vs_pvt_mem_addr, 8192,
SNAPSHOT_GPU_OBJECT_GENERIC);
-
snapshot_frozen_objsize += ret;
+ sp_vs_pvt_mem_addr = 0;
}
if (sp_fs_pvt_mem_addr) {
@@ -337,6 +337,7 @@
sp_fs_pvt_mem_addr, 8192,
SNAPSHOT_GPU_OBJECT_GENERIC);
snapshot_frozen_objsize += ret;
+ sp_fs_pvt_mem_addr = 0;
}
/* Finally: VBOs */
@@ -359,7 +360,13 @@
0, SNAPSHOT_GPU_OBJECT_GENERIC);
snapshot_frozen_objsize += ret;
}
+
+ vbo[i].base = 0;
+ vbo[i].stride = 0;
}
+
+ vfd_control_0 = 0;
+ vfd_index_max = 0;
}
/*
@@ -473,21 +480,33 @@
unsigned int gpuaddr, unsigned int dwords)
{
int i, ret, rem = dwords;
- unsigned int *src = (unsigned int *) adreno_convertaddr(device, ptbase,
- gpuaddr, dwords << 2);
+ unsigned int *src;
+
+ /*
+ * If the object is already in the list, we don't need to parse it again
+ */
+
+ if (kgsl_snapshot_have_object(device, ptbase, gpuaddr, dwords << 2))
+ return;
+
+ src = (unsigned int *) adreno_convertaddr(device, ptbase, gpuaddr,
+ dwords << 2);
if (src == NULL)
return;
- for (i = 0; rem != 0; rem--, i++) {
+ for (i = 0; rem > 0; rem--, i++) {
int pktsize;
+ /* If the packet isn't a type 1 or a type 3, then don't bother
+ * parsing it - it is likely corrupted */
+
if (!pkt_is_type0(src[i]) && !pkt_is_type3(src[i]))
- continue;
+ break;
pktsize = type3_pkt_size(src[i]);
- if ((pktsize + 1) > rem)
+ if (!pktsize || (pktsize + 1) > rem)
break;
if (pkt_is_type3(src[i])) {
@@ -650,27 +669,11 @@
*data = rbptr[index];
/*
- * Sometimes the rptr is located in the middle of a packet.
- * try to adust for that by modifying the rptr to match a
- * packet boundary. Unfortunately for us, it is hard to tell
- * which dwords are legitimate type0 header and which are just
- * random data so only do the adjustments for type3 packets
- */
-
- if (pkt_is_type3(rbptr[index])) {
- unsigned int pktsize =
- type3_pkt_size(rbptr[index]);
- if (index + pktsize > rptr)
- rptr = (index + pktsize) %
- rb->sizedwords;
- }
-
- /*
* Only parse IBs between the start and the rptr or the next
* context switch, whichever comes first
*/
- if (index == ib_parse_start)
+ if (parse_ibs == 0 && index == ib_parse_start)
parse_ibs = 1;
else if (index == rptr || adreno_rb_ctxtswitch(&rbptr[index]))
parse_ibs = 0;
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 21227a0..5904abb 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -36,6 +36,7 @@
#include "kgsl_sharedmem.h"
#include "kgsl_device.h"
#include "kgsl_trace.h"
+#include "kgsl_sync.h"
#undef MODULE_PARAM_PREFIX
#define MODULE_PARAM_PREFIX "kgsl."
@@ -368,6 +369,12 @@
context->id = id;
context->dev_priv = dev_priv;
+ if (kgsl_sync_timeline_create(context)) {
+ idr_remove(&dev_priv->device->context_idr, id);
+ kfree(context);
+ return NULL;
+ }
+
return context;
}
@@ -412,6 +419,7 @@
{
struct kgsl_context *context = container_of(kref, struct kgsl_context,
refcount);
+ kgsl_sync_timeline_destroy(context);
kfree(context);
}
@@ -1435,42 +1443,43 @@
if (ret)
return ret;
- if (phys == 0) {
- ret = -EINVAL;
+ ret = -ERANGE;
+
+ if (phys == 0)
+ goto err;
+
+ /* Make sure the length of the region, the offset and the desired
+ * size are all page aligned or bail
+ */
+ if ((len & ~PAGE_MASK) ||
+ (offset & ~PAGE_MASK) ||
+ (size & ~PAGE_MASK)) {
+ KGSL_CORE_ERR("length offset or size is not page aligned\n");
goto err;
}
- if (offset >= len) {
- ret = -EINVAL;
+ /* The size or offset can never be greater than the PMEM length */
+ if (offset >= len || size > len)
goto err;
- }
+ /* If size is 0, then adjust it to default to the size of the region
+ * minus the offset. If size isn't zero, then make sure that it will
+ * fit inside of the region.
+ */
if (size == 0)
- size = len;
+ size = len - offset;
- /* Adjust the size of the region to account for the offset */
- size += offset & ~PAGE_MASK;
-
- size = ALIGN(size, PAGE_SIZE);
-
- if (_check_region(offset & PAGE_MASK, size, len)) {
- KGSL_CORE_ERR("Offset (%ld) + size (%d) is larger"
- "than pmem region length %ld\n",
- offset & PAGE_MASK, size, len);
- ret = -EINVAL;
+ else if (_check_region(offset, size, len))
goto err;
- }
-
entry->priv_data = filep;
entry->memdesc.pagetable = pagetable;
entry->memdesc.size = size;
- entry->memdesc.physaddr = phys + (offset & PAGE_MASK);
- entry->memdesc.hostptr = (void *) (virt + (offset & PAGE_MASK));
+ entry->memdesc.physaddr = phys + offset;
+ entry->memdesc.hostptr = (void *) (virt + offset);
- ret = memdesc_sg_phys(&entry->memdesc,
- phys + (offset & PAGE_MASK), size);
+ ret = memdesc_sg_phys(&entry->memdesc, phys + offset, size);
if (ret)
goto err;
@@ -2016,6 +2025,11 @@
param->context_id, param->timestamp, param->priv,
param->len, dev_priv);
break;
+ case KGSL_TIMESTAMP_EVENT_FENCE:
+ ret = kgsl_add_fence_event(dev_priv->device,
+ param->context_id, param->timestamp, param->priv,
+ param->len, dev_priv);
+ break;
default:
ret = -EINVAL;
}
@@ -2092,6 +2106,8 @@
cmd = IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP;
else if (cmd == IOCTL_KGSL_CMDSTREAM_READTIMESTAMP_OLD)
cmd = IOCTL_KGSL_CMDSTREAM_READTIMESTAMP;
+ else if (cmd == IOCTL_KGSL_TIMESTAMP_EVENT_OLD)
+ cmd = IOCTL_KGSL_TIMESTAMP_EVENT;
nr = _IOC_NR(cmd);
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 2a2e916..2ca3a4f 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -22,6 +22,7 @@
#include "kgsl_pwrctrl.h"
#include "kgsl_log.h"
#include "kgsl_pwrscale.h"
+#include <linux/sync.h>
#define KGSL_TIMEOUT_NONE 0
#define KGSL_TIMEOUT_DEFAULT 0xFFFFFFFF
@@ -236,6 +237,12 @@
* context was responsible for causing it
*/
unsigned int reset_status;
+
+ /*
+ * Timeline used to create fences that can be signaled when a
+ * sync_pt timestamp expires.
+ */
+ struct sync_timeline *timeline;
};
struct kgsl_process_private {
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index dee889d..0e1e100 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -320,7 +320,7 @@
if (KGSL_MMU_TYPE_GPU == kgsl_mmu_type)
return CONFIG_MSM_KGSL_PAGE_TABLE_SIZE;
else if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_type)
- return SZ_2G;
+ return SZ_2G - KGSL_PAGETABLE_BASE;
else
return 0;
}
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index a2ab5b1..0bfcfd8 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -289,6 +289,32 @@
kfree(obj);
}
+/* ksgl_snapshot_have_object - Return 1 if the object has been processed
+ *@device - the device that is being snapshotted
+ * @ptbase - the pagetable base of the object to freeze
+ * @gpuaddr - The gpu address of the object to freeze
+ * @size - the size of the object (may not always be the size of the region)
+ *
+ * Return 1 if the object is already in the list - this can save us from
+ * having to parse the sme thing over again.
+*/
+int kgsl_snapshot_have_object(struct kgsl_device *device, unsigned int ptbase,
+ unsigned int gpuaddr, unsigned int size)
+{
+ struct kgsl_snapshot_object *obj;
+
+ list_for_each_entry(obj, &device->snapshot_obj_list, node) {
+ if (obj->ptbase != ptbase)
+ continue;
+
+ if ((gpuaddr >= obj->gpuaddr) &&
+ ((gpuaddr + size) <= (obj->gpuaddr + obj->size)))
+ return 1;
+ }
+
+ return 0;
+}
+
/* kgsl_snapshot_get_object - Mark a GPU buffer to be frozen
* @device - the device that is being snapshotted
* @ptbase - the pagetable base of the object to freeze
diff --git a/drivers/gpu/msm/kgsl_snapshot.h b/drivers/gpu/msm/kgsl_snapshot.h
index 6d81bcf..bc29863 100644
--- a/drivers/gpu/msm/kgsl_snapshot.h
+++ b/drivers/gpu/msm/kgsl_snapshot.h
@@ -311,5 +311,8 @@
int kgsl_snapshot_get_object(struct kgsl_device *device, unsigned int ptbase,
unsigned int gpuaddr, unsigned int size, unsigned int type);
+int kgsl_snapshot_have_object(struct kgsl_device *device, unsigned int ptbase,
+ unsigned int gpuaddr, unsigned int size);
+
#endif
#endif
diff --git a/drivers/gpu/msm/kgsl_sync.c b/drivers/gpu/msm/kgsl_sync.c
new file mode 100644
index 0000000..a2dfe3b
--- /dev/null
+++ b/drivers/gpu/msm/kgsl_sync.c
@@ -0,0 +1,214 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/file.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+#include "kgsl_sync.h"
+
+struct sync_pt *kgsl_sync_pt_create(struct sync_timeline *timeline,
+ unsigned int timestamp)
+{
+ struct sync_pt *pt;
+ pt = sync_pt_create(timeline, (int) sizeof(struct kgsl_sync_pt));
+ if (pt) {
+ struct kgsl_sync_pt *kpt = (struct kgsl_sync_pt *) pt;
+ kpt->timestamp = timestamp;
+ }
+ return pt;
+}
+
+/*
+ * This should only be called on sync_pts which have been created but
+ * not added to a fence.
+ */
+void kgsl_sync_pt_destroy(struct sync_pt *pt)
+{
+ sync_pt_free(pt);
+}
+
+static struct sync_pt *kgsl_sync_pt_dup(struct sync_pt *pt)
+{
+ struct kgsl_sync_pt *kpt = (struct kgsl_sync_pt *) pt;
+ return kgsl_sync_pt_create(pt->parent, kpt->timestamp);
+}
+
+static int kgsl_sync_pt_has_signaled(struct sync_pt *pt)
+{
+ struct kgsl_sync_pt *kpt = (struct kgsl_sync_pt *) pt;
+ struct kgsl_sync_timeline *ktimeline =
+ (struct kgsl_sync_timeline *) pt->parent;
+ unsigned int ts = kpt->timestamp;
+ unsigned int last_ts = ktimeline->last_timestamp;
+ if (timestamp_cmp(last_ts, ts) >= 0) {
+ /* signaled */
+ return 1;
+ }
+ return 0;
+}
+
+static int kgsl_sync_pt_compare(struct sync_pt *a, struct sync_pt *b)
+{
+ struct kgsl_sync_pt *kpt_a = (struct kgsl_sync_pt *) a;
+ struct kgsl_sync_pt *kpt_b = (struct kgsl_sync_pt *) b;
+ unsigned int ts_a = kpt_a->timestamp;
+ unsigned int ts_b = kpt_b->timestamp;
+ return timestamp_cmp(ts_a, ts_b);
+}
+
+struct kgsl_fence_event_priv {
+ struct kgsl_context *context;
+};
+
+/**
+ * kgsl_fence_event_cb - Event callback for a fence timestamp event
+ * @device - The KGSL device that expired the timestamp
+ * @priv - private data for the event
+ * @context_id - the context id that goes with the timestamp
+ * @timestamp - the timestamp that triggered the event
+ *
+ * Signal a fence following the expiration of a timestamp
+ */
+
+static inline void kgsl_fence_event_cb(struct kgsl_device *device,
+ void *priv, u32 context_id, u32 timestamp)
+{
+ struct kgsl_fence_event_priv *ev = priv;
+ kgsl_sync_timeline_signal(ev->context->timeline, timestamp);
+ kgsl_context_put(ev->context);
+ kfree(ev);
+}
+
+/**
+ * kgsl_add_fence_event - Create a new fence event
+ * @device - KGSL device to create the event on
+ * @timestamp - Timestamp to trigger the event
+ * @data - Return fence fd stored in struct kgsl_timestamp_event_fence
+ * @len - length of the fence event
+ * @owner - driver instance that owns this event
+ * @returns 0 on success or error code on error
+ *
+ * Create a fence and register an event to signal the fence when
+ * the timestamp expires
+ */
+
+int kgsl_add_fence_event(struct kgsl_device *device,
+ u32 context_id, u32 timestamp, void __user *data, int len,
+ struct kgsl_device_private *owner)
+{
+ struct kgsl_fence_event_priv *event;
+ struct kgsl_timestamp_event_fence priv;
+ struct kgsl_context *context;
+ struct sync_pt *pt;
+ struct sync_fence *fence = NULL;
+ int ret = -EINVAL;
+
+ if (len != sizeof(priv))
+ return -EINVAL;
+
+ context = kgsl_find_context(owner, context_id);
+ if (context == NULL)
+ return -EINVAL;
+
+ event = kzalloc(sizeof(*event), GFP_KERNEL);
+ if (event == NULL)
+ return -ENOMEM;
+ event->context = context;
+ kgsl_context_get(context);
+
+ pt = kgsl_sync_pt_create(context->timeline, timestamp);
+ if (pt == NULL) {
+ KGSL_DRV_ERR(device, "kgsl_sync_pt_create failed\n");
+ ret = -ENOMEM;
+ goto fail_pt;
+ }
+
+ fence = sync_fence_create("kgsl-fence", pt);
+ if (fence == NULL) {
+ /* only destroy pt when not added to fence */
+ kgsl_sync_pt_destroy(pt);
+ KGSL_DRV_ERR(device, "sync_fence_create failed\n");
+ ret = -ENOMEM;
+ goto fail_fence;
+ }
+
+ priv.fence_fd = get_unused_fd_flags(0);
+ if (priv.fence_fd < 0) {
+ KGSL_DRV_ERR(device, "invalid fence fd\n");
+ ret = -EINVAL;
+ goto fail_fd;
+ }
+ sync_fence_install(fence, priv.fence_fd);
+
+ if (copy_to_user(data, &priv, sizeof(priv))) {
+ ret = -EFAULT;
+ goto fail_copy_fd;
+ }
+
+ ret = kgsl_add_event(device, context_id, timestamp,
+ kgsl_fence_event_cb, event, owner);
+ if (ret)
+ goto fail_event;
+
+ return 0;
+
+fail_event:
+fail_copy_fd:
+ /* clean up sync_fence_install */
+ sync_fence_put(fence);
+ put_unused_fd(priv.fence_fd);
+fail_fd:
+ /* clean up sync_fence_create */
+ sync_fence_put(fence);
+fail_fence:
+fail_pt:
+ kgsl_context_put(context);
+ kfree(event);
+ return ret;
+}
+
+static const struct sync_timeline_ops kgsl_sync_timeline_ops = {
+ .dup = kgsl_sync_pt_dup,
+ .has_signaled = kgsl_sync_pt_has_signaled,
+ .compare = kgsl_sync_pt_compare,
+};
+
+int kgsl_sync_timeline_create(struct kgsl_context *context)
+{
+ struct kgsl_sync_timeline *ktimeline;
+
+ context->timeline = sync_timeline_create(&kgsl_sync_timeline_ops,
+ (int) sizeof(struct kgsl_sync_timeline), "kgsl-timeline");
+ if (context->timeline == NULL)
+ return -EINVAL;
+
+ ktimeline = (struct kgsl_sync_timeline *) context->timeline;
+ ktimeline->last_timestamp = 0;
+
+ return 0;
+}
+
+void kgsl_sync_timeline_signal(struct sync_timeline *timeline,
+ unsigned int timestamp)
+{
+ struct kgsl_sync_timeline *ktimeline =
+ (struct kgsl_sync_timeline *) timeline;
+ ktimeline->last_timestamp = timestamp;
+ sync_timeline_signal(timeline);
+}
+
+void kgsl_sync_timeline_destroy(struct kgsl_context *context)
+{
+ sync_timeline_destroy(context->timeline);
+}
diff --git a/drivers/gpu/msm/kgsl_sync.h b/drivers/gpu/msm/kgsl_sync.h
new file mode 100644
index 0000000..06b3ad0
--- /dev/null
+++ b/drivers/gpu/msm/kgsl_sync.h
@@ -0,0 +1,75 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __KGSL_SYNC_H
+#define __KGSL_SYNC_H
+
+#include <linux/sync.h>
+#include "kgsl_device.h"
+
+struct kgsl_sync_timeline {
+ struct sync_timeline timeline;
+ unsigned int last_timestamp;
+};
+
+struct kgsl_sync_pt {
+ struct sync_pt pt;
+ unsigned int timestamp;
+};
+
+#if defined(CONFIG_SYNC)
+struct sync_pt *kgsl_sync_pt_create(struct sync_timeline *timeline,
+ unsigned int timestamp);
+void kgsl_sync_pt_destroy(struct sync_pt *pt);
+int kgsl_add_fence_event(struct kgsl_device *device,
+ u32 context_id, u32 timestamp, void __user *data, int len,
+ struct kgsl_device_private *owner);
+int kgsl_sync_timeline_create(struct kgsl_context *context);
+void kgsl_sync_timeline_signal(struct sync_timeline *timeline,
+ unsigned int timestamp);
+void kgsl_sync_timeline_destroy(struct kgsl_context *context);
+#else
+static inline struct sync_pt
+*kgsl_sync_pt_create(struct sync_timeline *timeline, unsigned int timestamp)
+{
+ return NULL;
+}
+
+static inline void kgsl_sync_pt_destroy(struct sync_pt *pt)
+{
+}
+
+static inline int kgsl_add_fence_event(struct kgsl_device *device,
+ u32 context_id, u32 timestamp, void __user *data, int len,
+ struct kgsl_device_private *owner)
+{
+ return -EINVAL;
+}
+
+static int kgsl_sync_timeline_create(struct kgsl_context *context)
+{
+ context->timeline = NULL;
+ return 0;
+}
+
+static inline void
+kgsl_sync_timeline_signal(struct sync_timeline *timeline,
+ unsigned int timestamp)
+{
+}
+
+static inline void kgsl_sync_timeline_destroy(struct kgsl_context *context)
+{
+}
+#endif
+
+#endif /* __KGSL_SYNC_H */
diff --git a/drivers/hwmon/epm_adc.c b/drivers/hwmon/epm_adc.c
index 56b8841..368aac4 100644
--- a/drivers/hwmon/epm_adc.c
+++ b/drivers/hwmon/epm_adc.c
@@ -99,6 +99,17 @@
#define EPM_GLOBAL_ENABLE_MIN_DELAY 5000
#define EPM_GLOBAL_ENABLE_MAX_DELAY 5100
+#define EPM_AVG_BUF_MASK1 0xfff00000
+#define EPM_AVG_BUF_MASK2 0xfff00
+#define EPM_AVG_BUF_MASK3 0xff
+#define EPM_AVG_BUF_MASK4 0xf0000000
+#define EPM_AVG_BUF_MASK5 0xfff0000
+#define EPM_AVG_BUF_MASK6 0xfff0
+#define EPM_AVG_BUF_MASK7 0xf
+#define EPM_AVG_BUF_MASK8 0xff000000
+#define EPM_AVG_BUF_MASK9 0xfff000
+#define EPM_AVG_BUF_MASK10 0xfff
+
#define EPM_PSOC_BUFFERED_DATA_LENGTH 48
#define EPM_PSOC_BUFFERED_DATA_LENGTH2 54
@@ -109,6 +120,7 @@
struct mutex conv_lock;
uint32_t bus_id;
struct miscdevice misc;
+ uint32_t channel_mask;
struct epm_chan_properties epm_psoc_ch_prop[0];
};
@@ -567,21 +579,26 @@
adc_scaled_data *= sign_bit;
}
}
+
conv->physical = (int32_t) adc_scaled_data;
return 0;
}
-static int epm_psoc_scale_result(uint16_t *adc_raw_data, uint32_t index)
+static int epm_psoc_scale_result(uint32_t result, uint32_t index)
{
struct epm_adc_drv *epm_adc = epm_adc_drv;
+ int32_t result_cur;
+
/* result = 2.048V/(32767 * gain * rsense) */
- *adc_raw_data = (EPM_PSOC_VREF_VOLTAGE/EPM_PSOC_MAX_ADC_CODE_16_BIT)
- * (*adc_raw_data);
- *adc_raw_data = *adc_raw_data/
+ result_cur = (((EPM_PSOC_VREF_VOLTAGE * result)/
+ EPM_PSOC_MAX_ADC_CODE_16_BIT) * 1000);
+
+ result_cur = (result_cur/
(epm_adc->epm_psoc_ch_prop[index].gain *
- epm_adc->epm_psoc_ch_prop[index].resistorvalue);
- return 0;
+ epm_adc->epm_psoc_ch_prop[index].resistorvalue));
+
+ return result_cur;
}
static int epm_adc_blocking_conversion(struct epm_adc_drv *epm_adc,
@@ -702,6 +719,9 @@
if (rc)
return rc;
+ rc = spi_sync(epm_adc->epm_spi_client, &m);
+ if (rc)
+ return rc;
init_resp->cmd = rx_buf[0];
init_resp->version = rx_buf[1];
init_resp->compatible_ver = rx_buf[2];
@@ -757,7 +777,6 @@
chan_num = rx_buf[2] << 24 | (rx_buf[3] << 16) | (rx_buf[4] << 8) |
rx_buf[5];
psoc_chan_configure->channel_num = chan_num;
- pr_debug("dev_num:%d, chan_num:%d\n", rx_buf[1], chan_num);
return rc;
}
@@ -949,7 +968,7 @@
struct spi_message m;
struct spi_transfer t;
char tx_buf[64], rx_buf[64];
- int rc = 0, i;
+ int rc = 0, i = 0, j = 0, z = 0;
spi_setup(epm_adc->epm_spi_client);
@@ -986,6 +1005,57 @@
for (i = 0; i < EPM_PSOC_BUFFERED_DATA_LENGTH2; i++)
psoc_get_meas->avg_data[i] = rx_buf[10 + i];
+ i = j = 0;
+ for (z = 0; z < 4; z++) {
+ psoc_get_meas->data[i].channel = i;
+ psoc_get_meas->data[i].avg_buffer_sample =
+ rx_buf[10 + j] & EPM_AVG_BUF_MASK1;
+ i++;
+ j++;
+ psoc_get_meas->data[i].avg_buffer_sample =
+ rx_buf[10 + j] & EPM_AVG_BUF_MASK2;
+ i++;
+ j++;
+ psoc_get_meas->data[i].avg_buffer_sample =
+ rx_buf[10 + j] & EPM_AVG_BUF_MASK3;
+ psoc_get_meas->data[i].avg_buffer_sample <<= 8;
+ j++;
+ psoc_get_meas->data[i].avg_buffer_sample =
+ psoc_get_meas->data[i].avg_buffer_sample |
+ (rx_buf[10 + j] & EPM_AVG_BUF_MASK4);
+ i++;
+ j++;
+ psoc_get_meas->data[i].avg_buffer_sample =
+ rx_buf[10 + j] & EPM_AVG_BUF_MASK5;
+ i++;
+ j++;
+ psoc_get_meas->data[i].avg_buffer_sample =
+ rx_buf[10 + j] & EPM_AVG_BUF_MASK6;
+ i++;
+ j++;
+ psoc_get_meas->data[i].avg_buffer_sample =
+ rx_buf[10 + j] & EPM_AVG_BUF_MASK7;
+ psoc_get_meas->data[i].avg_buffer_sample <<= 4;
+ j++;
+ psoc_get_meas->data[i].avg_buffer_sample =
+ psoc_get_meas->data[i].avg_buffer_sample |
+ (rx_buf[10 + j] & EPM_AVG_BUF_MASK8);
+ i++;
+ j++;
+ psoc_get_meas->data[i].avg_buffer_sample =
+ rx_buf[10 + j] & EPM_AVG_BUF_MASK9;
+ i++;
+ j++;
+ psoc_get_meas->data[i].avg_buffer_sample =
+ rx_buf[10 + j] & EPM_AVG_BUF_MASK10;
+ }
+
+ for (z = 0; z < 32; z++) {
+ if (psoc_get_meas->data[z].avg_buffer_sample != 0)
+ psoc_get_meas->data[z].result = epm_psoc_scale_result(
+ psoc_get_meas->data[z].avg_buffer_sample, z);
+ }
+
return rc;
}
@@ -1407,7 +1477,6 @@
struct epm_psoc_init_resp init_resp;
struct epm_psoc_channel_configure psoc_chan_configure;
struct epm_psoc_get_data psoc_get_meas;
- int16_t *adc_code = 0;
int rc = 0;
rc = epm_adc_psoc_gpio_init(true);
@@ -1421,15 +1490,16 @@
init_resp.cmd = EPM_PSOC_INIT_CMD;
rc = epm_psoc_init(epm_adc, &init_resp);
if (rc) {
- pr_info("PSOC init failed %d\n", rc);
+ pr_err("PSOC init failed %d\n", rc);
return 0;
}
+
psoc_chan_configure.channel_num = (1 << attr->index);
psoc_chan_configure.cmd = EPM_PSOC_CHANNEL_ENABLE_DISABLE_CMD;
rc = epm_psoc_channel_configure(epm_adc, &psoc_chan_configure);
if (rc) {
- pr_info("PSOC channel configure failed\n");
+ pr_err("PSOC channel configure failed\n");
return 0;
}
@@ -1441,20 +1511,13 @@
psoc_get_meas.chan_num = attr->index;
rc = epm_psoc_get_data(epm_adc, &psoc_get_meas);
if (rc) {
- pr_info("PSOC get data failed\n");
+ pr_err("PSOC get data failed\n");
return 0;
}
- *adc_code = psoc_get_meas.reading_value;
-
- rc = epm_psoc_scale_result(adc_code,
- psoc_chan_configure.channel_num);
- if (rc) {
- pr_info("Scale result failed\n");
- return 0;
- }
-
- psoc_get_meas.reading_value = *adc_code;
+ psoc_get_meas.reading_value = epm_psoc_scale_result(
+ psoc_get_meas.reading_value,
+ attr->index);
rc = epm_adc_psoc_gpio_init(false);
if (rc) {
@@ -1503,7 +1566,7 @@
static int __devinit epm_adc_psoc_init_hwmon(struct spi_device *spi,
struct epm_adc_drv *epm_adc)
{
- int i, rc, num_chans = 15;
+ int i, rc, num_chans = 31;
for (i = 0; i < num_chans; i++) {
rc = device_create_file(&spi->dev,
@@ -1521,8 +1584,8 @@
{
const struct device_node *node = spi->dev.of_node;
struct epm_adc_drv *epm_adc;
- int32_t *epm_ch_gain, *epm_ch_rsense;
- u32 rc = 0, epm_num_channels, i;
+ u32 *epm_ch_gain, *epm_ch_rsense;
+ u32 rc = 0, epm_num_channels, i, channel_mask;
if (!node)
return -EINVAL;
@@ -1535,14 +1598,14 @@
}
epm_ch_gain = devm_kzalloc(&spi->dev,
- epm_num_channels, GFP_KERNEL);
+ epm_num_channels * sizeof(u32), GFP_KERNEL);
if (!epm_ch_gain) {
dev_err(&spi->dev, "cannot allocate gain\n");
return -ENOMEM;
}
epm_ch_rsense = devm_kzalloc(&spi->dev,
- epm_num_channels, GFP_KERNEL);
+ epm_num_channels * sizeof(u32), GFP_KERNEL);
if (!epm_ch_rsense) {
dev_err(&spi->dev, "cannot allocate rsense\n");
return -ENOMEM;
@@ -1562,6 +1625,13 @@
return rc;
}
+ rc = of_property_read_u32(node,
+ "qcom,channel-type", &channel_mask);
+ if (rc) {
+ dev_err(&spi->dev, "missing channel mask\n");
+ return -ENODEV;
+ }
+
epm_adc = devm_kzalloc(&spi->dev,
sizeof(struct epm_adc_drv) +
(epm_num_channels *
@@ -1579,6 +1649,7 @@
epm_ch_gain[i];
}
+ epm_adc->channel_mask = channel_mask;
epm_adc_drv = epm_adc;
return 0;
@@ -1586,13 +1657,16 @@
static int __devinit epm_adc_psoc_spi_probe(struct spi_device *spi)
{
+
struct epm_adc_drv *epm_adc;
struct device_node *node = spi->dev.of_node;
int rc = 0;
- if (node)
+ if (node) {
rc = get_device_tree_data(spi);
- else {
+ if (rc)
+ return rc;
+ } else {
epm_adc = epm_adc_drv;
epm_adc_drv->epm_spi_client = spi;
epm_adc_drv->epm_spi_client->bits_per_word =
@@ -1619,7 +1693,6 @@
}
mutex_init(&epm_adc->conv_lock);
-
return rc;
}
@@ -1656,8 +1729,9 @@
conv.device_idx = attr->index / pdata->chan_per_adc;
conv.channel_idx = attr->index % pdata->chan_per_adc;
conv.physical = 0;
- pr_debug("%s: device_idx=%d channel_idx=%d", __func__, conv.device_idx,
+ pr_info("%s: device_idx=%d channel_idx=%d", __func__, conv.device_idx,
conv.channel_idx);
+
if (!epm_adc_expander_register) {
rc = epm_adc_i2c_expander_register();
if (rc) {
@@ -1680,6 +1754,7 @@
__func__, rc);
return 0;
}
+
rc = epm_adc_hw_deinit(epm_adc);
if (rc) {
pr_err("%s: epm_adc_hw_deinit() failed, rc = %d",
diff --git a/drivers/hwmon/pm8xxx-adc.c b/drivers/hwmon/pm8xxx-adc.c
index 8e35252..181a97e 100644
--- a/drivers/hwmon/pm8xxx-adc.c
+++ b/drivers/hwmon/pm8xxx-adc.c
@@ -31,6 +31,7 @@
#include <linux/mfd/pm8xxx/core.h>
#include <linux/regulator/consumer.h>
#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
+#include <mach/msm_xo.h>
/* User Bank register set */
#define PM8XXX_ADC_ARB_USRP_CNTRL1 0x197
@@ -141,6 +142,7 @@
struct work_struct cool_work;
uint32_t mpp_base;
struct device *hwmon;
+ struct msm_xo_voter *adc_voter;
int msm_suspend_check;
struct pm8xxx_adc_amux_properties *conv;
struct pm8xxx_adc_arb_btm_param batt;
@@ -290,14 +292,34 @@
return rc;
}
+static int32_t pm8xxx_adc_xo_vote(bool on)
+{
+ struct pm8xxx_adc *adc_pmic = pmic_adc;
+
+ if (on)
+ msm_xo_mode_vote(adc_pmic->adc_voter, MSM_XO_MODE_ON);
+ else
+ msm_xo_mode_vote(adc_pmic->adc_voter, MSM_XO_MODE_OFF);
+
+ return 0;
+}
+
static int32_t pm8xxx_adc_channel_power_enable(uint32_t channel,
bool power_cntrl)
{
int rc = 0;
- switch (channel)
+ switch (channel) {
case ADC_MPP_1_AMUX8:
rc = pm8xxx_adc_patherm_power(power_cntrl);
+ break;
+ case CHANNEL_DIE_TEMP:
+ case CHANNEL_MUXOFF:
+ rc = pm8xxx_adc_xo_vote(power_cntrl);
+ break;
+ default:
+ break;
+ }
return rc;
}
@@ -1147,6 +1169,7 @@
struct pm8xxx_adc *adc_pmic = pmic_adc;
int i;
+ msm_xo_put(adc_pmic->adc_voter);
platform_set_drvdata(pdev, NULL);
pmic_adc = NULL;
if (!pa_therm) {
@@ -1265,6 +1288,14 @@
}
adc_pmic->hwmon = hwmon_device_register(adc_pmic->dev);
+ if (adc_pmic->adc_voter == NULL) {
+ adc_pmic->adc_voter = msm_xo_get(MSM_XO_TCXO_D0, "pmic_xoadc");
+ if (IS_ERR(adc_pmic->adc_voter)) {
+ dev_err(&pdev->dev, "Failed to get XO vote\n");
+ return PTR_ERR(adc_pmic->adc_voter);
+ }
+ }
+
pa_therm = regulator_get(adc_pmic->dev, "pa_therm");
if (IS_ERR(pa_therm)) {
rc = PTR_ERR(pa_therm);
diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h
index 071d209..7190af8 100644
--- a/drivers/media/dvb/dvb-core/demux.h
+++ b/drivers/media/dvb/dvb-core/demux.h
@@ -109,6 +109,24 @@
};
};
+/*
+ * struct data_buffer: Parameters of buffer allocated by
+ * demux device for input/output. Can be used to directly map the
+ * demux-device buffer to HW output if HW supports it.
+ */
+struct data_buffer {
+ /* dvb_ringbuffer managed by demux-device */
+ const struct dvb_ringbuffer *ringbuff;
+
+
+ /*
+ * Private handle returned by kernel demux when
+ * map_buffer is called in case external buffer
+ * is used. NULL if buffer is allocated internally.
+ */
+ void *priv_handle;
+};
+
/*--------------------------------------------------------------------------*/
/* TS packet reception */
/*--------------------------------------------------------------------------*/
@@ -168,7 +186,7 @@
struct dmx_ts_feed {
int is_filtering; /* Set to non-zero when filtering in progress */
struct dmx_demux *parent; /* Back-pointer */
- const struct dvb_ringbuffer *buffer;
+ struct data_buffer buffer;
void *priv; /* Pointer to private data of the API client */
int (*set) (struct dmx_ts_feed *feed,
u16 pid,
@@ -198,7 +216,7 @@
u8 filter_mask [DMX_MAX_FILTER_SIZE];
u8 filter_mode [DMX_MAX_FILTER_SIZE];
struct dmx_section_feed* parent; /* Back-pointer */
- const struct dvb_ringbuffer *buffer;
+ struct data_buffer buffer;
void* priv; /* Pointer to private data of the API client */
};
@@ -316,6 +334,8 @@
u32 capabilities; /* Bitfield of capability flags */
struct dmx_frontend* frontend; /* Front-end connected to the demux */
void* priv; /* Pointer to private data of the API client */
+ struct data_buffer dvr_input; /* DVR input buffer */
+
int (*open) (struct dmx_demux* demux);
int (*close) (struct dmx_demux* demux);
int (*write) (struct dmx_demux *demux, const char *buf, size_t count);
@@ -359,6 +379,13 @@
int (*get_stc) (struct dmx_demux* demux, unsigned int num,
u64 *stc, unsigned int *base);
+
+ int (*map_buffer) (struct dmx_demux *demux,
+ struct dmx_buffer *dmx_buffer,
+ void **priv_handle, void **mem);
+
+ int (*unmap_buffer) (struct dmx_demux *demux,
+ void *priv_handle);
};
#endif /* #ifndef __DEMUX_H */
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 8353f6f..d9f62ad 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -490,6 +490,8 @@
dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE);
dvb_dmxdev_flush_events(&dmxdev->dvr_output_events);
dmxdev->dvr_feeds_count = 0;
+ dmxdev->dvr_buffer_mode = DMX_BUFFER_MODE_INTERNAL;
+ dmxdev->dvr_priv_buff_handle = NULL;
dvbdev->readers--;
} else if (!dvbdev->writers) {
@@ -517,10 +519,14 @@
dmxdev->demux->disconnect_frontend(dmxdev->demux);
dmxdev->demux->connect_frontend(dmxdev->demux, front);
+ dmxdev->dvr_input_buffer_mode = DMX_BUFFER_MODE_INTERNAL;
dvb_ringbuffer_init(&dmxdev->dvr_input_buffer,
mem,
DVR_BUFFER_SIZE);
+
+ dmxdev->demux->dvr_input.priv_handle = NULL;
+ dmxdev->demux->dvr_input.ringbuff = &dmxdev->dvr_input_buffer;
dvbdev->writers--;
}
@@ -545,7 +551,16 @@
dmxdev->dvr_buffer.data = NULL;
spin_unlock_irq(&dmxdev->lock);
wake_up_all(&dmxdev->dvr_buffer.queue);
- vfree(mem);
+
+ if (dmxdev->dvr_buffer_mode == DMX_BUFFER_MODE_INTERNAL)
+ vfree(mem);
+ }
+
+ if ((dmxdev->dvr_buffer_mode == DMX_BUFFER_MODE_EXTERNAL) &&
+ dmxdev->dvr_priv_buff_handle) {
+ dmxdev->demux->unmap_buffer(dmxdev->demux,
+ dmxdev->dvr_priv_buff_handle);
+ dmxdev->dvr_priv_buff_handle = NULL;
}
} else {
int i;
@@ -589,7 +604,17 @@
spin_lock_irq(&dmxdev->dvr_in_lock);
dmxdev->dvr_input_buffer.data = NULL;
spin_unlock_irq(&dmxdev->dvr_in_lock);
- vfree(mem);
+
+ if (dmxdev->dvr_buffer_mode == DMX_BUFFER_MODE_INTERNAL)
+ vfree(mem);
+ }
+
+ if ((dmxdev->dvr_input_buffer_mode ==
+ DMX_BUFFER_MODE_EXTERNAL) &&
+ (dmxdev->demux->dvr_input.priv_handle)) {
+ dmxdev->demux->unmap_buffer(dmxdev->demux,
+ dmxdev->demux->dvr_input.priv_handle);
+ dmxdev->demux->dvr_input.priv_handle = NULL;
}
}
/* TODO */
@@ -611,6 +636,7 @@
struct dvb_device *dvbdev = filp->private_data;
struct dmxdev *dmxdev = dvbdev->priv;
struct dvb_ringbuffer *buffer;
+ enum dmx_buffer_mode buffer_mode;
int vma_size;
int buffer_size;
int ret;
@@ -627,10 +653,18 @@
return -ENODEV;
}
- if ((filp->f_flags & O_ACCMODE) == O_RDONLY)
+ if ((filp->f_flags & O_ACCMODE) == O_RDONLY) {
buffer = &dmxdev->dvr_buffer;
- else
+ buffer_mode = dmxdev->dvr_buffer_mode;
+ } else {
buffer = &dmxdev->dvr_input_buffer;
+ buffer_mode = dmxdev->dvr_input_buffer_mode;
+ }
+
+ if (buffer_mode == DMX_BUFFER_MODE_EXTERNAL) {
+ mutex_unlock(&dmxdev->mutex);
+ return -EINVAL;
+ }
vma_size = vma->vm_end - vma->vm_start;
@@ -669,7 +703,8 @@
if (!dmxdev->demux->write)
return -EOPNOTSUPP;
- if ((file->f_flags & O_ACCMODE) == O_RDONLY)
+ if (((file->f_flags & O_ACCMODE) == O_RDONLY) ||
+ (!src->data))
return -EINVAL;
if ((file->f_flags & O_NONBLOCK) &&
@@ -859,20 +894,23 @@
void *newmem;
void *oldmem;
spinlock_t *lock;
+ enum dmx_buffer_mode buffer_mode;
dprintk("function : %s\n", __func__);
if ((f_flags & O_ACCMODE) == O_RDONLY) {
buf = &dmxdev->dvr_buffer;
lock = &dmxdev->lock;
+ buffer_mode = dmxdev->dvr_buffer_mode;
} else {
buf = &dmxdev->dvr_input_buffer;
lock = &dmxdev->dvr_in_lock;
+ buffer_mode = dmxdev->dvr_input_buffer_mode;
}
if (buf->size == size)
return 0;
- if (!size)
+ if ((!size) || (buffer_mode == DMX_BUFFER_MODE_EXTERNAL))
return -EINVAL;
newmem = vmalloc_user(size);
@@ -903,6 +941,72 @@
return 0;
}
+static int dvb_dvr_set_buffer_mode(struct dmxdev *dmxdev,
+ unsigned int f_flags, enum dmx_buffer_mode mode)
+{
+ if ((mode != DMX_BUFFER_MODE_INTERNAL) &&
+ (mode != DMX_BUFFER_MODE_EXTERNAL))
+ return -EINVAL;
+
+ if ((mode == DMX_BUFFER_MODE_INTERNAL) &&
+ (dmxdev->capabilities & DMXDEV_CAP_EXTERNAL_BUFFS_ONLY))
+ return -EINVAL;
+
+ if ((mode == DMX_BUFFER_MODE_EXTERNAL) &&
+ (!dmxdev->demux->map_buffer || !dmxdev->demux->unmap_buffer))
+ return -EINVAL;
+
+ if ((f_flags & O_ACCMODE) == O_RDONLY)
+ dmxdev->dvr_buffer_mode = mode;
+ else
+ dmxdev->dvr_input_buffer_mode = mode;
+
+ return 0;
+}
+
+static int dvb_dvr_set_buffer(struct dmxdev *dmxdev,
+ unsigned int f_flags, struct dmx_buffer *dmx_buffer)
+{
+ struct dvb_ringbuffer *buf;
+ spinlock_t *lock;
+ enum dmx_buffer_mode buffer_mode;
+ void **buff_handle;
+ void *newmem;
+ void *oldmem;
+
+ if ((f_flags & O_ACCMODE) == O_RDONLY) {
+ buf = &dmxdev->dvr_buffer;
+ lock = &dmxdev->lock;
+ buffer_mode = dmxdev->dvr_buffer_mode;
+ buff_handle = &dmxdev->dvr_priv_buff_handle;
+ } else {
+ buf = &dmxdev->dvr_input_buffer;
+ lock = &dmxdev->dvr_in_lock;
+ buffer_mode = dmxdev->dvr_input_buffer_mode;
+ buff_handle = &dmxdev->demux->dvr_input.priv_handle;
+ }
+
+ if ((!dmx_buffer->size) ||
+ (buffer_mode == DMX_BUFFER_MODE_INTERNAL))
+ return -EINVAL;
+
+ oldmem = *buff_handle;
+ if (dmxdev->demux->map_buffer(dmxdev->demux, dmx_buffer,
+ buff_handle, &newmem))
+ return -ENOMEM;
+
+ spin_lock_irq(lock);
+ buf->data = newmem;
+ buf->size = dmx_buffer->size;
+ dvb_ringbuffer_reset(buf);
+ spin_unlock_irq(lock);
+
+ if (oldmem)
+ dmxdev->demux->unmap_buffer(dmxdev->demux, oldmem);
+
+ return 0;
+}
+
static int dvb_dvr_get_event(struct dmxdev *dmxdev,
unsigned int f_flags,
struct dmx_filter_event *event)
@@ -1058,7 +1162,7 @@
if (buf->size == size)
return 0;
- if (!size)
+ if ((!size) || (dmxdevfilter->buffer_mode == DMX_BUFFER_MODE_EXTERNAL))
return -EINVAL;
if (dmxdevfilter->state >= DMXDEV_STATE_GO)
return -EBUSY;
@@ -1081,6 +1185,85 @@
return 0;
}
+static int dvb_dmxdev_set_buffer_mode(struct dmxdev_filter *dmxdevfilter,
+ enum dmx_buffer_mode mode)
+{
+ struct dvb_ringbuffer *buf = &dmxdevfilter->buffer;
+ struct dmxdev *dmxdev = dmxdevfilter->dev;
+ void *oldmem;
+
+ if (dmxdevfilter->state >= DMXDEV_STATE_GO)
+ return -EBUSY;
+
+ if ((mode != DMX_BUFFER_MODE_INTERNAL) &&
+ (mode != DMX_BUFFER_MODE_EXTERNAL))
+ return -EINVAL;
+
+ if ((mode == DMX_BUFFER_MODE_INTERNAL) &&
+ (dmxdev->capabilities & DMXDEV_CAP_EXTERNAL_BUFFS_ONLY))
+ return -EINVAL;
+
+ if ((mode == DMX_BUFFER_MODE_EXTERNAL) &&
+ (!dmxdev->demux->map_buffer || !dmxdev->demux->unmap_buffer))
+ return -EINVAL;
+
+ if (mode == dmxdevfilter->buffer_mode)
+ return 0;
+
+ oldmem = buf->data;
+ spin_lock_irq(&dmxdevfilter->dev->lock);
+ buf->data = NULL;
+ spin_unlock_irq(&dmxdevfilter->dev->lock);
+
+ dmxdevfilter->buffer_mode = mode;
+
+ if (mode == DMX_BUFFER_MODE_INTERNAL) {
+ /* switched from external to internal */
+ if (dmxdevfilter->priv_buff_handle) {
+ dmxdev->demux->unmap_buffer(dmxdev->demux,
+ dmxdevfilter->priv_buff_handle);
+ dmxdevfilter->priv_buff_handle = NULL;
+ }
+ } else if (oldmem) {
+ /* switched from internal to external */
+ vfree(oldmem);
+ }
+
+ return 0;
+}
+
+static int dvb_dmxdev_set_buffer(struct dmxdev_filter *dmxdevfilter,
+ struct dmx_buffer *buffer)
+{
+ struct dvb_ringbuffer *buf = &dmxdevfilter->buffer;
+ struct dmxdev *dmxdev = dmxdevfilter->dev;
+ void *newmem;
+ void *oldmem;
+
+ if (dmxdevfilter->state >= DMXDEV_STATE_GO)
+ return -EBUSY;
+
+ if ((!buffer->size) ||
+ (dmxdevfilter->buffer_mode == DMX_BUFFER_MODE_INTERNAL))
+ return -EINVAL;
+
+ oldmem = dmxdevfilter->priv_buff_handle;
+ if (dmxdev->demux->map_buffer(dmxdev->demux, buffer,
+ &dmxdevfilter->priv_buff_handle, &newmem))
+ return -ENOMEM;
+
+ spin_lock_irq(&dmxdevfilter->dev->lock);
+ buf->data = newmem;
+ buf->size = buffer->size;
+ dvb_ringbuffer_reset(buf);
+ spin_unlock_irq(&dmxdevfilter->dev->lock);
+
+ if (oldmem)
+ dmxdev->demux->unmap_buffer(dmxdev->demux, oldmem);
+
+ return 0;
+}
+
static int dvb_dmxdev_set_pes_buffer_size(struct dmxdev_filter *dmxdevfilter,
unsigned long size)
{
@@ -1962,12 +2145,14 @@
tsfeed->priv = filter;
if (filter->params.pes.output == DMX_OUT_TS_TAP) {
- tsfeed->buffer = &dmxdev->dvr_buffer;
+ tsfeed->buffer.ringbuff = &dmxdev->dvr_buffer;
+ tsfeed->buffer.priv_handle = dmxdev->dvr_priv_buff_handle;
if (!dmxdev->dvr_feeds_count)
dmxdev->dvr_feed = filter;
dmxdev->dvr_feeds_count++;
} else {
- tsfeed->buffer = &filter->buffer;
+ tsfeed->buffer.ringbuff = &filter->buffer;
+ tsfeed->buffer.priv_handle = filter->priv_buff_handle;
}
if (tsfeed->data_ready_cb) {
@@ -2028,6 +2213,9 @@
dvb_dmxdev_filter_stop(filter);
if (!filter->buffer.data) {
+ if ((filter->buffer_mode == DMX_BUFFER_MODE_EXTERNAL) ||
+ (dmxdev->capabilities & DMXDEV_CAP_EXTERNAL_BUFFS_ONLY))
+ return -ENOMEM;
mem = vmalloc_user(filter->buffer.size);
if (!mem)
return -ENOMEM;
@@ -2105,7 +2293,8 @@
}
(*secfilter)->priv = filter;
- (*secfilter)->buffer = &filter->buffer;
+ (*secfilter)->buffer.ringbuff = &filter->buffer;
+ (*secfilter)->buffer.priv_handle = filter->priv_buff_handle;
memcpy(&((*secfilter)->filter_value[3]),
&(para->filter.filter[1]), DMX_FILTER_SIZE - 1);
@@ -2182,6 +2371,8 @@
mutex_init(&dmxdevfilter->mutex);
file->private_data = dmxdevfilter;
+ dmxdevfilter->buffer_mode = DMX_BUFFER_MODE_INTERNAL;
+ dmxdevfilter->priv_buff_handle = NULL;
dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192);
dvb_dmxdev_flush_events(&dmxdevfilter->events);
@@ -2212,7 +2403,15 @@
spin_lock_irq(&dmxdev->lock);
dmxdevfilter->buffer.data = NULL;
spin_unlock_irq(&dmxdev->lock);
- vfree(mem);
+ if (dmxdevfilter->buffer_mode == DMX_BUFFER_MODE_INTERNAL)
+ vfree(mem);
+ }
+
+ if ((dmxdevfilter->buffer_mode == DMX_BUFFER_MODE_EXTERNAL) &&
+ (dmxdevfilter->priv_buff_handle)) {
+ dmxdev->demux->unmap_buffer(dmxdev->demux,
+ dmxdevfilter->priv_buff_handle);
+ dmxdevfilter->priv_buff_handle = NULL;
}
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_FREE);
@@ -2487,6 +2686,25 @@
mutex_unlock(&dmxdevfilter->mutex);
break;
+ case DMX_SET_BUFFER_MODE:
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ERESTARTSYS;
+ }
+ ret = dvb_dmxdev_set_buffer_mode(dmxdevfilter,
+ *(enum dmx_buffer_mode *)parg);
+ mutex_unlock(&dmxdevfilter->mutex);
+ break;
+
+ case DMX_SET_BUFFER:
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ERESTARTSYS;
+ }
+ ret = dvb_dmxdev_set_buffer(dmxdevfilter, parg);
+ mutex_unlock(&dmxdevfilter->mutex);
+ break;
+
case DMX_GET_BUFFER_STATUS:
if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
mutex_unlock(&dmxdev->mutex);
@@ -2679,7 +2897,8 @@
return -ERESTARTSYS;
}
- if (!dmxdevfilter->buffer.data) {
+ if ((!dmxdevfilter->buffer.data) ||
+ (dmxdevfilter->buffer_mode == DMX_BUFFER_MODE_EXTERNAL)) {
mutex_unlock(&dmxdevfilter->mutex);
mutex_unlock(&dmxdev->mutex);
return -EINVAL;
@@ -2767,6 +2986,15 @@
ret = dvb_dvr_set_buffer_size(dmxdev, file->f_flags, arg);
break;
+ case DMX_SET_BUFFER_MODE:
+ ret = dvb_dvr_set_buffer_mode(dmxdev, file->f_flags,
+ *(enum dmx_buffer_mode *)parg);
+ break;
+
+ case DMX_SET_BUFFER:
+ ret = dvb_dvr_set_buffer(dmxdev, file->f_flags, parg);
+ break;
+
case DMX_GET_BUFFER_STATUS:
ret = dvb_dvr_get_buffer_status(dmxdev, file->f_flags, parg);
break;
diff --git a/drivers/media/dvb/dvb-core/dmxdev.h b/drivers/media/dvb/dvb-core/dmxdev.h
index 9fd900e..e30c2c3 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.h
+++ b/drivers/media/dvb/dvb-core/dmxdev.h
@@ -113,6 +113,8 @@
enum dmxdev_state state;
struct dmxdev *dev;
struct dvb_ringbuffer buffer;
+ void *priv_buff_handle;
+ enum dmx_buffer_mode buffer_mode;
u32 flush_data_len;
struct mutex mutex;
@@ -139,9 +141,10 @@
int filternum;
int capabilities;
-#define DMXDEV_CAP_DUPLEX 0x1
-#define DMXDEV_CAP_PULL_MODE 0x2
-#define DMXDEV_CAP_INDEXING 0x4
+#define DMXDEV_CAP_DUPLEX 0x01
+#define DMXDEV_CAP_PULL_MODE 0x02
+#define DMXDEV_CAP_INDEXING 0x04
+#define DMXDEV_CAP_EXTERNAL_BUFFS_ONLY 0x08
enum dmx_playback_mode_t playback_mode;
dmx_source_t source;
@@ -153,12 +156,15 @@
struct dmx_frontend *dvr_orig_fe;
struct dvb_ringbuffer dvr_buffer;
+ void *dvr_priv_buff_handle;
+ enum dmx_buffer_mode dvr_buffer_mode;
struct dmxdev_events_queue dvr_output_events;
struct dmxdev_filter *dvr_feed;
u32 dvr_flush_data_len;
int dvr_feeds_count;
struct dvb_ringbuffer dvr_input_buffer;
+ enum dmx_buffer_mode dvr_input_buffer_mode;
struct workqueue_struct *dvr_input_workqueue;
#define DVR_BUFFER_SIZE (10*188*1024)
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index df71f76..de7b28d 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -1794,6 +1794,8 @@
dmx->release_ts_feed = dvbdmx_release_ts_feed;
dmx->allocate_section_feed = dvbdmx_allocate_section_feed;
dmx->release_section_feed = dvbdmx_release_section_feed;
+ dmx->map_buffer = NULL;
+ dmx->unmap_buffer = NULL;
dmx->add_frontend = dvbdmx_add_frontend;
dmx->remove_frontend = dvbdmx_remove_frontend;
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
index a01cf5b..836ca65 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
@@ -595,7 +595,7 @@
* for decoder's buffers.
*/
mpq_dmx_info.ion_client =
- msm_ion_client_create(UINT_MAX, "demux client");
+ msm_ion_client_create(UINT_MAX, "demux_client");
if (IS_ERR_OR_NULL(mpq_dmx_info.ion_client)) {
MPQ_DVB_ERR_PRINT(
@@ -603,6 +603,8 @@
__func__);
result = PTR_ERR(mpq_dmx_info.ion_client);
+ if (!result)
+ result = -ENOMEM;
mpq_dmx_info.ion_client = NULL;
goto init_failed_free_demux_devices;
}
@@ -683,7 +685,7 @@
if (mpq_dmx_info.devices != NULL) {
for (i = 0; i < mpq_demux_device_num; i++) {
- mpq_demux = mpq_dmx_info.devices+i;
+ mpq_demux = mpq_dmx_info.devices + i;
if (mpq_demux->is_initialized) {
mpq_demux->demux.dmx.remove_frontend(
@@ -764,6 +766,107 @@
}
EXPORT_SYMBOL(mpq_dmx_set_source);
+int mpq_dmx_map_buffer(struct dmx_demux *demux, struct dmx_buffer *dmx_buffer,
+ void **priv_handle, void **kernel_mem)
+{
+ struct dvb_demux *dvb_demux = demux->priv;
+ struct mpq_demux *mpq_demux;
+ struct ion_handle *ion_handle;
+ unsigned long ionflag = 0;
+ int ret;
+
+ if ((mpq_dmx_info.devices == NULL) || (dvb_demux == NULL) ||
+ (priv_handle == NULL) || (kernel_mem == NULL)) {
+ MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ mpq_demux = dvb_demux->priv;
+ if (mpq_demux == NULL) {
+ MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ ion_handle = ion_import_dma_buf(mpq_demux->ion_client,
+ dmx_buffer->handle);
+ if (IS_ERR_OR_NULL(ion_handle)) {
+ ret = PTR_ERR(ion_handle);
+ if (!ret)
+ ret = -ENOMEM;
+
+ MPQ_DVB_ERR_PRINT("%s: ion_import_dma_buf failed %d\n",
+ __func__, ret);
+ goto map_buffer_failed;
+ }
+
+ ret = ion_handle_get_flags(mpq_demux->ion_client, ion_handle, &ionflag);
+ if (ret) {
+ MPQ_DVB_ERR_PRINT("%s: ion_handle_get_flags failed %d\n",
+ __func__, ret);
+ goto map_buffer_failed_free_buff;
+ }
+
+ if (ionflag & ION_SECURE) {
+ MPQ_DVB_DBG_PRINT("%s: secured buffer\n", __func__);
+ /* TBD: Set buffer as secured */
+ *kernel_mem = NULL;
+ } else {
+ *kernel_mem = ion_map_kernel(mpq_demux->ion_client,
+ ion_handle, ionflag);
+ if (*kernel_mem == NULL) {
+ MPQ_DVB_ERR_PRINT("%s: ion_map_kernel failed\n",
+ __func__);
+ ret = -ENOMEM;
+ goto map_buffer_failed_free_buff;
+ }
+ }
+
+ *priv_handle = (void *)ion_handle;
+ return 0;
+
+map_buffer_failed_free_buff:
+ ion_free(mpq_demux->ion_client, ion_handle);
+map_buffer_failed:
+ return ret;
+}
+EXPORT_SYMBOL(mpq_dmx_map_buffer);
+
+int mpq_dmx_unmap_buffer(struct dmx_demux *demux,
+ void *priv_handle)
+{
+ struct dvb_demux *dvb_demux = demux->priv;
+ struct ion_handle *ion_handle = priv_handle;
+ struct mpq_demux *mpq_demux;
+ unsigned long ionflag = 0;
+ int ret;
+
+ if ((mpq_dmx_info.devices == NULL) || (dvb_demux == NULL) ||
+ (priv_handle == NULL)) {
+ MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ mpq_demux = dvb_demux->priv;
+ if (mpq_demux == NULL) {
+ MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ ret = ion_handle_get_flags(mpq_demux->ion_client, ion_handle, &ionflag);
+ if (ret) {
+ MPQ_DVB_ERR_PRINT("%s: ion_handle_get_flags failed %d\n",
+ __func__, ret);
+ return -EINVAL;
+ }
+
+ if (!(ionflag & ION_SECURE))
+ ion_unmap_kernel(mpq_demux->ion_client, ion_handle);
+
+ ion_free(mpq_demux->ion_client, ion_handle);
+
+ return 0;
+}
+EXPORT_SYMBOL(mpq_dmx_unmap_buffer);
int mpq_dmx_init_video_feed(struct dvb_demux_feed *feed)
{
@@ -836,9 +939,10 @@
MPQ_DVB_ERR_PRINT(
"%s: FAILED to allocate payload buffer %d\n",
- __func__,
- ret);
+ __func__, ret);
+ if (!ret)
+ ret = -ENOMEM;
goto init_failed_free_packet_buffer;
}
@@ -852,9 +956,10 @@
MPQ_DVB_ERR_PRINT(
"%s: FAILED to map payload buffer %d\n",
- __func__,
- ret);
+ __func__, ret);
+ if (!ret)
+ ret = -ENOMEM;
goto init_failed_free_payload_buffer;
}
@@ -922,8 +1027,7 @@
MPQ_DVB_ERR_PRINT(
"%s: mpq_adapter_register_stream_if failed, "
"err = %d\n",
- __func__,
- ret);
+ __func__, ret);
goto init_failed_unmap_payload_buffer;
}
@@ -991,8 +1095,7 @@
wake_up_all(&feed_data->video_buffer->raw_data.queue);
- mpq_adapter_unregister_stream_if(
- feed_data->stream_interface);
+ mpq_adapter_unregister_stream_if(feed_data->stream_interface);
vfree(feed_data->video_buffer->packet_data.data);
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h
index 893273d..3500eda 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h
@@ -332,7 +332,7 @@
* them to the dvb adapter.
*
* @dmx_init_func: Pointer to the function to be used
- * to initialize demux of the udnerlying HW plugin.
+ * to initialize demux of the underlying HW plugin.
*
* Return error code
*
@@ -361,6 +361,38 @@
int mpq_dmx_set_source(struct dmx_demux *demux, const dmx_source_t *src);
/**
+ * mpq_dmx_map_buffer - map user-space buffer into kernel space.
+ *
+ * @demux: The demux device.
+ * @dmx_buffer: The demux buffer from user-space, assumes that
+ * buffer handle is ION file-handle.
+ * @priv_handle: Saves ION-handle of the buffer imported by this function.
+ * @kernel_mem: Saves kernel mapped address of the buffer.
+ *
+ * Return error code
+ *
+ * The function maps the buffer into kernel memory only if the buffer
+ * was not allocated with secure flag, otherwise the returned kernel
+ * memory address is set to NULL.
+ */
+int mpq_dmx_map_buffer(struct dmx_demux *demux, struct dmx_buffer *dmx_buffer,
+ void **priv_handle, void **kernel_mem);
+
+/**
+ * mpq_dmx_unmap_buffer - unmap user-space buffer from kernel space memory.
+ *
+ * @demux: The demux device.
+ * @priv_handle: ION-handle of the buffer returned from mpq_dmx_map_buffer.
+ *
+ * Return error code
+ *
+ * The function unmaps the buffer from kernel memory only if the buffer
+ * was not allocated with secure flag.
+ */
+int mpq_dmx_unmap_buffer(struct dmx_demux *demux,
+ void *priv_handle);
+
+/**
* mpq_dmx_init_video_feed - Initializes video feed
* used to pass data to decoder directly.
*
@@ -396,8 +428,7 @@
*
* Return error code.
*/
-int mpq_dmx_decoder_fullness_init(
- struct dvb_demux_feed *feed);
+int mpq_dmx_decoder_fullness_init(struct dvb_demux_feed *feed);
/**
* mpq_dmx_decoder_fullness_wait - Checks whether decoder buffer
@@ -408,8 +439,7 @@
*
* Return error code.
*/
-int mpq_dmx_decoder_fullness_wait(
- struct dvb_demux_feed *feed,
+int mpq_dmx_decoder_fullness_wait(struct dvb_demux_feed *feed,
size_t required_space);
/**
@@ -422,8 +452,7 @@
*
* Return error code.
*/
-int mpq_dmx_decoder_fullness_abort(
- struct dvb_demux_feed *feed);
+int mpq_dmx_decoder_fullness_abort(struct dvb_demux_feed *feed);
/**
* mpq_dmx_decoder_buffer_status - Returns the
@@ -452,9 +481,7 @@
* the packet and does not write them to the output buffer.
* Scrambled packets are bypassed.
*/
-int mpq_dmx_process_video_packet(
- struct dvb_demux_feed *feed,
- const u8 *buf);
+int mpq_dmx_process_video_packet(struct dvb_demux_feed *feed, const u8 *buf);
/**
* mpq_dmx_process_pcr_packet - Extract PCR/STC pairs from
@@ -475,9 +502,7 @@
* The function callbacks dmxdev after extraction of the pcr/stc
* pair.
*/
-int mpq_dmx_process_pcr_packet(
- struct dvb_demux_feed *feed,
- const u8 *buf);
+int mpq_dmx_process_pcr_packet(struct dvb_demux_feed *feed, const u8 *buf);
/**
* mpq_dmx_is_video_feed - Returns whether the PES feed
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c
index 74a0dbe..627c5a2 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c
@@ -579,6 +579,24 @@
caps->max_bitrate = 144;
caps->demod_input_max_bitrate = 72;
caps->memory_input_max_bitrate = 72;
+ caps->section.flags = 0;
+ caps->section.max_size = 0xFFFFFFFF;
+ caps->section.size_alignment = 0;
+ caps->pes.flags = 0;
+ caps->pes.max_size = 0xFFFFFFFF;
+ caps->pes.size_alignment = 0;
+ caps->recording_188_tsp.flags = 0;
+ caps->recording_188_tsp.max_size = 0xFFFFFFFF;
+ caps->recording_188_tsp.size_alignment = 0;
+ caps->recording_192_tsp.flags = 0;
+ caps->recording_192_tsp.max_size = 0xFFFFFFFF;
+ caps->recording_192_tsp.size_alignment = 0;
+ caps->playback_188_tsp.flags = 0;
+ caps->playback_188_tsp.max_size = 0xFFFFFFFF;
+ caps->playback_188_tsp.size_alignment = 0;
+ caps->playback_192_tsp.flags = 0;
+ caps->playback_192_tsp.max_size = 0xFFFFFFFF;
+ caps->playback_192_tsp.size_alignment = 0;
return 0;
}
@@ -645,6 +663,8 @@
mpq_demux->dmxdev.demux->set_source = mpq_dmx_set_source;
mpq_demux->dmxdev.demux->get_caps = mpq_tsif_dmx_get_caps;
+ mpq_demux->dmxdev.demux->map_buffer = mpq_dmx_map_buffer;
+ mpq_demux->dmxdev.demux->unmap_buffer = mpq_dmx_unmap_buffer;
result = dvb_dmxdev_init(&mpq_demux->dmxdev, mpq_adapter);
if (result < 0) {
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
index c1d1462..e4f00c0 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
@@ -708,6 +708,24 @@
caps->max_bitrate = 144;
caps->demod_input_max_bitrate = 72;
caps->memory_input_max_bitrate = 72;
+ caps->section.flags = 0;
+ caps->section.max_size = 0xFFFFFFFF;
+ caps->section.size_alignment = 0;
+ caps->pes.flags = 0;
+ caps->pes.max_size = 0xFFFFFFFF;
+ caps->pes.size_alignment = 0;
+ caps->recording_188_tsp.flags = 0;
+ caps->recording_188_tsp.max_size = 0xFFFFFFFF;
+ caps->recording_188_tsp.size_alignment = 0;
+ caps->recording_192_tsp.flags = 0;
+ caps->recording_192_tsp.max_size = 0xFFFFFFFF;
+ caps->recording_192_tsp.size_alignment = 0;
+ caps->playback_188_tsp.flags = 0;
+ caps->playback_188_tsp.max_size = 0xFFFFFFFF;
+ caps->playback_188_tsp.size_alignment = 0;
+ caps->playback_192_tsp.flags = 0;
+ caps->playback_192_tsp.max_size = 0xFFFFFFFF;
+ caps->playback_192_tsp.size_alignment = 0;
return 0;
}
@@ -766,6 +784,8 @@
mpq_demux->dmxdev.demux->set_source = mpq_dmx_set_source;
mpq_demux->dmxdev.demux->get_caps = mpq_tspp_dmx_get_caps;
+ mpq_demux->dmxdev.demux->map_buffer = mpq_dmx_map_buffer;
+ mpq_demux->dmxdev.demux->unmap_buffer = mpq_dmx_unmap_buffer;
result = dvb_dmxdev_init(&mpq_demux->dmxdev, mpq_adapter);
if (result < 0) {
diff --git a/drivers/media/dvb/mpq/video/mpq_dvb_video.c b/drivers/media/dvb/mpq/video/mpq_dvb_video.c
index 3dc31bb..4b3fb0c 100644
--- a/drivers/media/dvb/mpq/video/mpq_dvb_video.c
+++ b/drivers/media/dvb/mpq/video/mpq_dvb_video.c
@@ -868,7 +868,7 @@
if (rc)
DBG("Failed in mpq_int_vid_dec_get_buffer_req : %d\n", rc);
- vdec_buf_req.num_output_buffers = 15;
+ vdec_buf_req.num_output_buffers = 12;
rc = mpq_int_set_out_buffer_req(client_ctx, &vdec_buf_req);
if (rc)
DBG("Failed in mpq_int_set_out_buffer_req (15) : %d\n", rc);
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index ae020e8..0d2d91c 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -1262,3 +1262,4 @@
endif # V4L_MEM2MEM_DRIVERS
source "drivers/media/video/msm_vidc/Kconfig"
+source "drivers/media/video/msm_wfd/Kconfig"
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 082ee3d..fd736c3 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -215,7 +215,7 @@
obj-$(CONFIG_MSM_CAMERA) += msm/
obj-$(CONFIG_ARCH_OMAP) += omap/
obj-$(CONFIG_MSM_VIDC_V4L2) += msm_vidc/
-obj-$(CONFIG_FB_MSM_WRITEBACK_MSM_PANEL) += msm_wfd/
+obj-$(CONFIG_MSM_WFD) += msm_wfd/
ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
ccflags-y += -I$(srctree)/drivers/media/dvb/frontends
diff --git a/drivers/media/video/msm/csi/msm_csi2_register.c b/drivers/media/video/msm/csi/msm_csi2_register.c
index aa539ff..5f2183b 100644
--- a/drivers/media/video/msm/csi/msm_csi2_register.c
+++ b/drivers/media/video/msm/csi/msm_csi2_register.c
@@ -16,18 +16,21 @@
#include "msm_csi_register.h"
int msm_csi_register_subdevs(struct msm_cam_media_controller *p_mctl,
- int core_index, struct msm_cam_server_dev *server_dev)
+ uint8_t csiphy_code_index, uint8_t csid_core_index,
+ struct msm_cam_server_dev *server_dev)
{
int rc = -ENODEV;
+ CDBG("%s csiphy sel %d csid sel %d\n", __func__, csiphy_code_index,
+ csid_core_index);
/* register csiphy subdev */
- p_mctl->csiphy_sdev = server_dev->csiphy_device[core_index];
+ p_mctl->csiphy_sdev = server_dev->csiphy_device[csiphy_code_index];
if (!p_mctl->csiphy_sdev)
goto out;
v4l2_set_subdev_hostdata(p_mctl->csiphy_sdev, p_mctl);
/* register csid subdev */
- p_mctl->csid_sdev = server_dev->csid_device[core_index];
+ p_mctl->csid_sdev = server_dev->csid_device[csid_core_index];
if (!p_mctl->csid_sdev)
goto out;
v4l2_set_subdev_hostdata(p_mctl->csid_sdev, p_mctl);
diff --git a/drivers/media/video/msm/csi/msm_csi_register.h b/drivers/media/video/msm/csi/msm_csi_register.h
index ebb001c..4214feb 100644
--- a/drivers/media/video/msm/csi/msm_csi_register.h
+++ b/drivers/media/video/msm/csi/msm_csi_register.h
@@ -12,5 +12,5 @@
*/
int msm_csi_register_subdevs(struct msm_cam_media_controller *p_mctl,
- int core_index,
+ uint8_t csiphy_code_index, uint8_t csid_core_index,
struct msm_cam_server_dev *server_dev);
diff --git a/drivers/media/video/msm/csi/msm_csic_register.c b/drivers/media/video/msm/csi/msm_csic_register.c
index dc3641a..af50101 100644
--- a/drivers/media/video/msm/csi/msm_csic_register.c
+++ b/drivers/media/video/msm/csi/msm_csic_register.c
@@ -16,11 +16,12 @@
#include "msm_csi_register.h"
int msm_csi_register_subdevs(struct msm_cam_media_controller *p_mctl,
- int core_index, struct msm_cam_server_dev *server_dev)
+ uint8_t csiphy_code_index, uint8_t csid_core_index,
+ struct msm_cam_server_dev *server_dev)
{
int rc = -ENODEV;
- p_mctl->csic_sdev = server_dev->csic_device[core_index];
+ p_mctl->csic_sdev = server_dev->csic_device[csid_core_index];
if (!p_mctl->csic_sdev)
goto out;
v4l2_set_subdev_hostdata(p_mctl->csic_sdev, p_mctl);
diff --git a/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c b/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c
index d508c1d..9e7ede4 100644
--- a/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c
+++ b/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c
@@ -145,13 +145,10 @@
case S_PREVIEW:
break;
case S_VIDEO:
- update_axi_qos(MSM_AXI_QOS_RECORDING);
break;
case S_CAPTURE:
- update_axi_qos(MSM_AXI_QOS_SNAPSHOT);
break;
case S_DEFAULT:
- update_axi_qos(PM_QOS_DEFAULT_VALUE);
break;
case S_EXIT:
axi_free(AXI_FLOW_VIEWFINDER_HI);
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_common.h b/drivers/media/video/msm/jpeg_10/msm_jpeg_common.h
index 88ec1ad..04af6b6 100644
--- a/drivers/media/video/msm/jpeg_10/msm_jpeg_common.h
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_common.h
@@ -14,12 +14,13 @@
#define MSM_JPEG_COMMON_H
#ifdef MSM_JPEG_DEBUG
-#define JPEG_DBG(fmt, args...) printk(fmt, ##args)
+#define JPEG_DBG(fmt, args...) pr_info(fmt, ##args)
#else
#define JPEG_DBG(fmt, args...) do { } while (0)
#endif
#define JPEG_PR_ERR pr_err
+#define JPEG_DBG_HIGH pr_err
enum JPEG_MODE {
JPEG_MODE_DISABLE,
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_core.c b/drivers/media/video/msm/jpeg_10/msm_jpeg_core.c
index 7905ff3..b67245c 100644
--- a/drivers/media/video/msm/jpeg_10/msm_jpeg_core.c
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_core.c
@@ -17,122 +17,130 @@
#include "msm_jpeg_platform.h"
#include "msm_jpeg_common.h"
-static struct msm_jpeg_hw_pingpong fe_pingpong_buf;
-static struct msm_jpeg_hw_pingpong we_pingpong_buf;
-static int we_pingpong_index;
-static int reset_done_ack;
-static spinlock_t reset_lock;
-static wait_queue_head_t reset_wait;
-
-int msm_jpeg_core_reset(uint8_t op_mode, void *base, int size)
-{
+int msm_jpeg_core_reset(struct msm_jpeg_device *pgmn_dev, uint8_t op_mode,
+ void *base, int size) {
unsigned long flags;
int rc = 0;
int tm = 500; /*500ms*/
- memset(&fe_pingpong_buf, 0, sizeof(fe_pingpong_buf));
- fe_pingpong_buf.is_fe = 1;
- we_pingpong_index = 0;
- memset(&we_pingpong_buf, 0, sizeof(we_pingpong_buf));
- spin_lock_irqsave(&reset_lock, flags);
- reset_done_ack = 0;
+ JPEG_DBG("%s:%d] reset", __func__, __LINE__);
+ memset(&pgmn_dev->fe_pingpong_buf, 0,
+ sizeof(pgmn_dev->fe_pingpong_buf));
+ pgmn_dev->fe_pingpong_buf.is_fe = 1;
+ memset(&pgmn_dev->we_pingpong_buf, 0,
+ sizeof(pgmn_dev->we_pingpong_buf));
+ spin_lock_irqsave(&pgmn_dev->reset_lock, flags);
+ pgmn_dev->reset_done_ack = 0;
msm_jpeg_hw_reset(base, size);
- spin_unlock_irqrestore(&reset_lock, flags);
+ spin_unlock_irqrestore(&pgmn_dev->reset_lock, flags);
rc = wait_event_interruptible_timeout(
- reset_wait,
- reset_done_ack,
+ pgmn_dev->reset_wait,
+ pgmn_dev->reset_done_ack,
msecs_to_jiffies(tm));
- if (!reset_done_ack) {
+ if (!pgmn_dev->reset_done_ack) {
JPEG_DBG("%s: reset ACK failed %d", __func__, rc);
return -EBUSY;
}
JPEG_DBG("%s: reset_done_ack rc %d", __func__, rc);
- spin_lock_irqsave(&reset_lock, flags);
- reset_done_ack = 0;
- spin_unlock_irqrestore(&reset_lock, flags);
+ spin_lock_irqsave(&pgmn_dev->reset_lock, flags);
+ pgmn_dev->reset_done_ack = 0;
+ spin_unlock_irqrestore(&pgmn_dev->reset_lock, flags);
return 0;
}
-void msm_jpeg_core_release(int release_buf, int domain_num)
-{
+void msm_jpeg_core_release(struct msm_jpeg_device *pgmn_dev,
+ int domain_num) {
int i = 0;
for (i = 0; i < 2; i++) {
- if (we_pingpong_buf.buf_status[i] && release_buf)
- msm_jpeg_platform_p2v(we_pingpong_buf.buf[i].file,
- &we_pingpong_buf.buf[i].handle, domain_num);
- we_pingpong_buf.buf_status[i] = 0;
+ if (pgmn_dev->we_pingpong_buf.buf_status[i] &&
+ pgmn_dev->release_buf)
+ msm_jpeg_platform_p2v(pgmn_dev,
+ pgmn_dev->we_pingpong_buf.buf[i].file,
+ &pgmn_dev->we_pingpong_buf.buf[i].handle,
+ domain_num);
+ pgmn_dev->we_pingpong_buf.buf_status[i] = 0;
}
}
-void msm_jpeg_core_init(void)
+void msm_jpeg_core_init(struct msm_jpeg_device *pgmn_dev)
{
- init_waitqueue_head(&reset_wait);
- spin_lock_init(&reset_lock);
+ init_waitqueue_head(&pgmn_dev->reset_wait);
+ spin_lock_init(&pgmn_dev->reset_lock);
}
-int msm_jpeg_core_fe_start(void)
+int msm_jpeg_core_fe_start(struct msm_jpeg_device *pgmn_dev)
{
- msm_jpeg_hw_fe_start();
+ msm_jpeg_hw_fe_start(pgmn_dev->base);
return 0;
}
/* fetch engine */
-int msm_jpeg_core_fe_buf_update(struct msm_jpeg_core_buf *buf)
+int msm_jpeg_core_fe_buf_update(struct msm_jpeg_device *pgmn_dev,
+ struct msm_jpeg_core_buf *buf)
{
+ if (0 == buf->cbcr_len)
+ buf->cbcr_buffer_addr = 0x0;
JPEG_DBG("%s:%d] 0x%08x %d 0x%08x %d\n", __func__, __LINE__,
(int) buf->y_buffer_addr, buf->y_len,
(int) buf->cbcr_buffer_addr, buf->cbcr_len);
- return msm_jpeg_hw_pingpong_update(&fe_pingpong_buf, buf);
+ return msm_jpeg_hw_pingpong_update(&pgmn_dev->fe_pingpong_buf, buf,
+ pgmn_dev->base);
}
-void *msm_jpeg_core_fe_pingpong_irq(int jpeg_irq_status, void *context)
+void *msm_jpeg_core_fe_pingpong_irq(int jpeg_irq_status,
+ struct msm_jpeg_device *pgmn_dev)
{
- return msm_jpeg_hw_pingpong_irq(&fe_pingpong_buf);
+ return msm_jpeg_hw_pingpong_irq(&pgmn_dev->fe_pingpong_buf);
}
/* write engine */
-int msm_jpeg_core_we_buf_update(struct msm_jpeg_core_buf *buf)
-{
+int msm_jpeg_core_we_buf_update(struct msm_jpeg_device *pgmn_dev,
+ struct msm_jpeg_core_buf *buf) {
JPEG_DBG("%s:%d] 0x%08x 0x%08x %d\n", __func__, __LINE__,
(int) buf->y_buffer_addr, (int) buf->cbcr_buffer_addr,
buf->y_len);
- we_pingpong_buf.buf[0] = *buf;
- we_pingpong_buf.buf_status[0] = 1;
+ pgmn_dev->we_pingpong_buf.buf[0] = *buf;
+ pgmn_dev->we_pingpong_buf.buf_status[0] = 1;
msm_jpeg_hw_we_buffer_update(
- &we_pingpong_buf.buf[0], 0);
+ &pgmn_dev->we_pingpong_buf.buf[0], 0, pgmn_dev->base);
return 0;
}
-int msm_jpeg_core_we_buf_reset(struct msm_jpeg_hw_buf *buf)
+int msm_jpeg_core_we_buf_reset(struct msm_jpeg_device *pgmn_dev,
+ struct msm_jpeg_hw_buf *buf)
{
int i = 0;
for (i = 0; i < 2; i++) {
- if (we_pingpong_buf.buf[i].y_buffer_addr
- == buf->y_buffer_addr)
- we_pingpong_buf.buf_status[i] = 0;
+ if (pgmn_dev->we_pingpong_buf.buf[i].y_buffer_addr
+ == buf->y_buffer_addr)
+ pgmn_dev->we_pingpong_buf.buf_status[i] = 0;
}
return 0;
}
-void *msm_jpeg_core_we_pingpong_irq(int jpeg_irq_status, void *context)
+void *msm_jpeg_core_we_pingpong_irq(int jpeg_irq_status,
+ struct msm_jpeg_device *pgmn_dev)
{
JPEG_DBG("%s:%d]\n", __func__, __LINE__);
- return msm_jpeg_hw_pingpong_irq(&we_pingpong_buf);
+ return msm_jpeg_hw_pingpong_irq(&pgmn_dev->we_pingpong_buf);
}
-void *msm_jpeg_core_framedone_irq(int jpeg_irq_status, void *context)
+void *msm_jpeg_core_framedone_irq(int jpeg_irq_status,
+ struct msm_jpeg_device *pgmn_dev)
{
struct msm_jpeg_hw_buf *buf_p;
JPEG_DBG("%s:%d]\n", __func__, __LINE__);
- buf_p = msm_jpeg_hw_pingpong_active_buffer(&we_pingpong_buf);
- if (buf_p) {
- buf_p->framedone_len = msm_jpeg_hw_encode_output_size();
+ buf_p = msm_jpeg_hw_pingpong_active_buffer(
+ &pgmn_dev->we_pingpong_buf);
+ if (buf_p && !pgmn_dev->decode_flag) {
+ buf_p->framedone_len =
+ msm_jpeg_hw_encode_output_size(pgmn_dev->base);
JPEG_DBG("%s:%d] framedone_len %d\n", __func__, __LINE__,
buf_p->framedone_len);
}
@@ -140,14 +148,16 @@
return buf_p;
}
-void *msm_jpeg_core_reset_ack_irq(int jpeg_irq_status, void *context)
+void *msm_jpeg_core_reset_ack_irq(int jpeg_irq_status,
+ struct msm_jpeg_device *pgmn_dev)
{
/* @todo return the status back to msm_jpeg_core_reset */
JPEG_DBG("%s:%d]\n", __func__, __LINE__);
return NULL;
}
-void *msm_jpeg_core_err_irq(int jpeg_irq_status, void *context)
+void *msm_jpeg_core_err_irq(int jpeg_irq_status,
+ struct msm_jpeg_device *pgmn_dev)
{
JPEG_PR_ERR("%s:%d]\n", __func__, jpeg_irq_status);
return NULL;
@@ -155,15 +165,32 @@
static int (*msm_jpeg_irq_handler) (int, void *, void *);
+void msm_jpeg_core_return_buffers(struct msm_jpeg_device *pgmn_dev,
+ int jpeg_irq_status)
+{
+ void *data = NULL;
+ data = msm_jpeg_core_fe_pingpong_irq(jpeg_irq_status,
+ pgmn_dev);
+ if (msm_jpeg_irq_handler)
+ msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_FE,
+ pgmn_dev, data);
+ data = msm_jpeg_core_we_pingpong_irq(jpeg_irq_status,
+ pgmn_dev);
+ if (msm_jpeg_irq_handler)
+ msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_WE,
+ pgmn_dev, data);
+}
+
irqreturn_t msm_jpeg_core_irq(int irq_num, void *context)
{
void *data = NULL;
unsigned long flags;
int jpeg_irq_status;
+ struct msm_jpeg_device *pgmn_dev = (struct msm_jpeg_device *)context;
JPEG_DBG("%s:%d] irq_num = %d\n", __func__, __LINE__, irq_num);
- jpeg_irq_status = msm_jpeg_hw_irq_get_status();
+ jpeg_irq_status = msm_jpeg_hw_irq_get_status(pgmn_dev->base);
JPEG_DBG("%s:%d] jpeg_irq_status = %0x\n", __func__, __LINE__,
jpeg_irq_status);
@@ -171,18 +198,26 @@
/*For reset and framedone IRQs, clear all bits*/
if (jpeg_irq_status & 0x10000000) {
msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK,
- JPEG_IRQ_CLEAR_ALL);
+ JPEG_IRQ_CLEAR_ALL, pgmn_dev->base);
} else if (jpeg_irq_status & 0x1) {
msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK,
- JPEG_IRQ_CLEAR_ALL);
+ JPEG_IRQ_CLEAR_ALL, pgmn_dev->base);
+ if (pgmn_dev->decode_flag)
+ msm_jpeg_decode_status(pgmn_dev->base);
} else {
msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK,
- jpeg_irq_status);
+ jpeg_irq_status, pgmn_dev->base);
}
if (msm_jpeg_hw_irq_is_frame_done(jpeg_irq_status)) {
+ /* send fe ping pong irq */
+ data = msm_jpeg_core_fe_pingpong_irq(jpeg_irq_status,
+ pgmn_dev);
+ if (msm_jpeg_irq_handler)
+ msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_FE,
+ context, data);
data = msm_jpeg_core_framedone_irq(jpeg_irq_status,
- context);
+ pgmn_dev);
if (msm_jpeg_irq_handler)
msm_jpeg_irq_handler(
MSM_JPEG_HW_MASK_COMP_FRAMEDONE,
@@ -190,11 +225,11 @@
}
if (msm_jpeg_hw_irq_is_reset_ack(jpeg_irq_status)) {
data = msm_jpeg_core_reset_ack_irq(jpeg_irq_status,
- context);
- spin_lock_irqsave(&reset_lock, flags);
- reset_done_ack = 1;
- spin_unlock_irqrestore(&reset_lock, flags);
- wake_up(&reset_wait);
+ pgmn_dev);
+ spin_lock_irqsave(&pgmn_dev->reset_lock, flags);
+ pgmn_dev->reset_done_ack = 1;
+ spin_unlock_irqrestore(&pgmn_dev->reset_lock, flags);
+ wake_up(&pgmn_dev->reset_wait);
if (msm_jpeg_irq_handler)
msm_jpeg_irq_handler(
MSM_JPEG_HW_MASK_COMP_RESET_ACK,
@@ -203,7 +238,10 @@
/* Unexpected/unintended HW interrupt */
if (msm_jpeg_hw_irq_is_err(jpeg_irq_status)) {
- data = msm_jpeg_core_err_irq(jpeg_irq_status, context);
+ if (pgmn_dev->decode_flag)
+ msm_jpeg_decode_status(pgmn_dev->base);
+ msm_jpeg_core_return_buffers(pgmn_dev, jpeg_irq_status);
+ data = msm_jpeg_core_err_irq(jpeg_irq_status, pgmn_dev);
if (msm_jpeg_irq_handler)
msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_ERR,
context, data);
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_core.h b/drivers/media/video/msm/jpeg_10/msm_jpeg_core.h
index b5c725c..212eaff 100644
--- a/drivers/media/video/msm/jpeg_10/msm_jpeg_core.h
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_core.h
@@ -15,6 +15,7 @@
#include <linux/interrupt.h>
#include "msm_jpeg_hw.h"
+#include "msm_jpeg_sync.h"
#define msm_jpeg_core_buf msm_jpeg_hw_buf
@@ -23,13 +24,17 @@
void msm_jpeg_core_irq_install(int (*irq_handler) (int, void *, void *));
void msm_jpeg_core_irq_remove(void);
-int msm_jpeg_core_fe_buf_update(struct msm_jpeg_core_buf *buf);
-int msm_jpeg_core_we_buf_update(struct msm_jpeg_core_buf *buf);
-int msm_jpeg_core_we_buf_reset(struct msm_jpeg_hw_buf *buf);
+int msm_jpeg_core_fe_buf_update(struct msm_jpeg_device *pgmn_dev,
+ struct msm_jpeg_core_buf *buf);
+int msm_jpeg_core_we_buf_update(struct msm_jpeg_device *pgmn_dev,
+ struct msm_jpeg_core_buf *buf);
+int msm_jpeg_core_we_buf_reset(struct msm_jpeg_device *pgmn_dev,
+ struct msm_jpeg_hw_buf *buf);
-int msm_jpeg_core_reset(uint8_t op_mode, void *base, int size);
-int msm_jpeg_core_fe_start(void);
+int msm_jpeg_core_reset(struct msm_jpeg_device *pgmn_dev, uint8_t op_mode,
+ void *base, int size);
+int msm_jpeg_core_fe_start(struct msm_jpeg_device *);
-void msm_jpeg_core_release(int, int);
-void msm_jpeg_core_init(void);
+void msm_jpeg_core_release(struct msm_jpeg_device *, int);
+void msm_jpeg_core_init(struct msm_jpeg_device *);
#endif /* MSM_JPEG_CORE_H */
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_dev.c b/drivers/media/video/msm/jpeg_10/msm_jpeg_dev.c
index 45a9a38..0662f54 100644
--- a/drivers/media/video/msm/jpeg_10/msm_jpeg_dev.c
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_dev.c
@@ -31,9 +31,7 @@
#include "msm_jpeg_common.h"
#define MSM_JPEG_NAME "jpeg"
-#define MSM_JPEGE1_NAME "jpege1"
-#define MSM_JPEGD_NAME "jpegd"
-
+#define DEV_NAME_LEN 10
static int msm_jpeg_open(struct inode *inode, struct file *filp)
{
@@ -146,7 +144,7 @@
int rc = -1;
struct device *dev;
struct msm_jpeg_device *msm_jpeg_device_p;
- char devname[10];
+ char devname[DEV_NAME_LEN];
msm_jpeg_device_p = kzalloc(sizeof(struct msm_jpeg_device), GFP_ATOMIC);
if (!msm_jpeg_device_p) {
@@ -158,7 +156,7 @@
if (pdev->dev.of_node)
of_property_read_u32((&pdev->dev)->of_node, "cell-index",
- &pdev->id);
+ &pdev->id);
snprintf(devname, sizeof(devname), "%s%d", MSM_JPEG_NAME, pdev->id);
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_hw.c b/drivers/media/video/msm/jpeg_10/msm_jpeg_hw.c
index 0bfb6a8..e311e4c 100644
--- a/drivers/media/video/msm/jpeg_10/msm_jpeg_hw.c
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_hw.c
@@ -17,11 +17,8 @@
#include <linux/io.h>
-static void *jpeg_region_base;
-static uint32_t jpeg_region_size;
-
int msm_jpeg_hw_pingpong_update(struct msm_jpeg_hw_pingpong *pingpong_hw,
- struct msm_jpeg_hw_buf *buf)
+ struct msm_jpeg_hw_buf *buf, void *base)
{
int buf_free_index = -1;
@@ -41,11 +38,13 @@
if (pingpong_hw->is_fe) {
/* it is fe */
msm_jpeg_hw_fe_buffer_update(
- &pingpong_hw->buf[buf_free_index], buf_free_index);
+ &pingpong_hw->buf[buf_free_index], buf_free_index,
+ base);
} else {
/* it is we */
msm_jpeg_hw_we_buffer_update(
- &pingpong_hw->buf[buf_free_index], buf_free_index);
+ &pingpong_hw->buf[buf_free_index], buf_free_index,
+ base);
}
return 0;
}
@@ -81,12 +80,10 @@
JPEG_IRQ_STATUS_BMSK, {0} },
};
-int msm_jpeg_hw_irq_get_status(void)
+int msm_jpeg_hw_irq_get_status(void *base)
{
uint32_t n_irq_status = 0;
- rmb();
- n_irq_status = msm_jpeg_hw_read(&hw_cmd_irq_get_status[0]);
- rmb();
+ n_irq_status = msm_jpeg_hw_read(&hw_cmd_irq_get_status[0], base);
return n_irq_status;
}
@@ -97,11 +94,12 @@
JPEG_ENCODE_OUTPUT_SIZE_STATUS_BMSK, {0} } ,
};
-long msm_jpeg_hw_encode_output_size(void)
+long msm_jpeg_hw_encode_output_size(void *base)
{
uint32_t encode_output_size = 0;
- encode_output_size = msm_jpeg_hw_read(&hw_cmd_encode_output_size[0]);
+ encode_output_size = msm_jpeg_hw_read(&hw_cmd_encode_output_size[0],
+ base);
return encode_output_size;
}
@@ -112,12 +110,12 @@
JPEG_IRQ_CLEAR_BMSK, {JPEG_IRQ_CLEAR_ALL} },
};
-void msm_jpeg_hw_irq_clear(uint32_t mask, uint32_t data)
+void msm_jpeg_hw_irq_clear(uint32_t mask, uint32_t data, void *base)
{
JPEG_DBG("%s:%d] mask %0x data %0x", __func__, __LINE__, mask, data);
hw_cmd_irq_clear[0].mask = mask;
hw_cmd_irq_clear[0].data = data;
- msm_jpeg_hw_write(&hw_cmd_irq_clear[0]);
+ msm_jpeg_hw_write(&hw_cmd_irq_clear[0], base);
}
struct msm_jpeg_hw_cmd hw_cmd_fe_ping_update[] = {
@@ -137,26 +135,26 @@
};
void msm_jpeg_hw_fe_buffer_update(struct msm_jpeg_hw_buf *p_input,
- uint8_t pingpong_index)
+ uint8_t pingpong_index, void *base)
{
struct msm_jpeg_hw_cmd *hw_cmd_p;
if (pingpong_index == 0) {
hw_cmd_p = &hw_cmd_fe_ping_update[0];
wmb();
- msm_jpeg_hw_write(hw_cmd_p++);
+ msm_jpeg_hw_write(hw_cmd_p++, base);
wmb();
- msm_jpeg_hw_write(hw_cmd_p++);
+ msm_jpeg_hw_write(hw_cmd_p++, base);
wmb();
- msm_jpeg_hw_write(hw_cmd_p++);
+ msm_jpeg_hw_write(hw_cmd_p++, base);
wmb();
hw_cmd_p->data = p_input->y_buffer_addr;
- msm_jpeg_hw_write(hw_cmd_p++);
+ msm_jpeg_hw_write(hw_cmd_p++, base);
wmb();
- msm_jpeg_hw_write(hw_cmd_p++);
+ msm_jpeg_hw_write(hw_cmd_p++, base);
wmb();
hw_cmd_p->data = p_input->cbcr_buffer_addr;
- msm_jpeg_hw_write(hw_cmd_p++);
+ msm_jpeg_hw_write(hw_cmd_p++, base);
wmb();
}
@@ -169,9 +167,9 @@
JPEG_CMD_BMSK, {JPEG_OFFLINE_CMD_START} },
};
-void msm_jpeg_hw_fe_start(void)
+void msm_jpeg_hw_fe_start(void *base)
{
- msm_jpeg_hw_write(&hw_cmd_fe_start[0]);
+ msm_jpeg_hw_write(&hw_cmd_fe_start[0], base);
return;
}
@@ -180,20 +178,46 @@
/* type, repeat n times, offset, mask, data or pdata */
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN0_WR_PNTR_ADDR,
JPEG_PLN0_WR_PNTR_BMSK, {0} },
+ {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN1_WR_PNTR_ADDR,
+ JPEG_PLN0_WR_PNTR_BMSK, {0} },
+ {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN2_WR_PNTR_ADDR,
+ JPEG_PLN0_WR_PNTR_BMSK, {0} },
};
+void msm_jpeg_decode_status(void *base)
+{
+ uint32_t data;
+ data = readl_relaxed(base + JPEG_DECODE_MCUS_DECODED_STATUS);
+ JPEG_DBG_HIGH("Decode MCUs decode status %u", data);
+ data = readl_relaxed(base + JPEG_DECODE_BITS_CONSUMED_STATUS);
+ JPEG_DBG_HIGH("Decode bits consumed status %u", data);
+ data = readl_relaxed(base + JPEG_DECODE_PRED_Y_STATE);
+ JPEG_DBG_HIGH("Decode prediction Y state %u", data);
+ data = readl_relaxed(base + JPEG_DECODE_PRED_C_STATE);
+ JPEG_DBG_HIGH("Decode prediction C state %u", data);
+ data = readl_relaxed(base + JPEG_DECODE_RSM_STATE);
+ JPEG_DBG_HIGH("Decode prediction RSM state %u", data);
+}
+
+
void msm_jpeg_hw_we_buffer_update(struct msm_jpeg_hw_buf *p_input,
- uint8_t pingpong_index)
+ uint8_t pingpong_index, void *base)
{
struct msm_jpeg_hw_cmd *hw_cmd_p;
if (pingpong_index == 0) {
hw_cmd_p = &hw_cmd_we_ping_update[0];
hw_cmd_p->data = p_input->y_buffer_addr;
- JPEG_PR_ERR("%s Output buffer address is %x\n", __func__,
- p_input->y_buffer_addr);
- msm_jpeg_hw_write(hw_cmd_p++);
-
+ JPEG_PR_ERR("%s Output pln0 buffer address is %x\n", __func__,
+ p_input->y_buffer_addr);
+ msm_jpeg_hw_write(hw_cmd_p++, base);
+ hw_cmd_p->data = p_input->cbcr_buffer_addr;
+ JPEG_PR_ERR("%s Output pln1 buffer address is %x\n", __func__,
+ p_input->cbcr_buffer_addr);
+ msm_jpeg_hw_write(hw_cmd_p++, base);
+ JPEG_PR_ERR("%s Output pln2 buffer address is %x\n", __func__,
+ p_input->pln2_addr);
+ msm_jpeg_hw_write(hw_cmd_p++, base);
}
return;
}
@@ -210,31 +234,26 @@
JPEG_RESET_CMD_RMSK, {JPEG_RESET_DEFAULT} },
};
-void msm_jpeg_hw_init(void *base, int size)
-{
- jpeg_region_base = base;
- jpeg_region_size = size;
-}
-
void msm_jpeg_hw_reset(void *base, int size)
{
struct msm_jpeg_hw_cmd *hw_cmd_p;
hw_cmd_p = &hw_cmd_reset[0];
wmb();
- msm_jpeg_hw_write(hw_cmd_p++);
+ msm_jpeg_hw_write(hw_cmd_p++, base);
wmb();
- msm_jpeg_hw_write(hw_cmd_p++);
+ msm_jpeg_hw_write(hw_cmd_p++, base);
wmb();
- msm_jpeg_hw_write(hw_cmd_p++);
+ msm_jpeg_hw_write(hw_cmd_p++, base);
wmb();
- msm_jpeg_hw_write(hw_cmd_p);
+ msm_jpeg_hw_write(hw_cmd_p, base);
wmb();
return;
}
-uint32_t msm_jpeg_hw_read(struct msm_jpeg_hw_cmd *hw_cmd_p)
+uint32_t msm_jpeg_hw_read(struct msm_jpeg_hw_cmd *hw_cmd_p,
+ void *jpeg_region_base)
{
uint32_t *paddr;
uint32_t data;
@@ -247,7 +266,8 @@
return data;
}
-void msm_jpeg_hw_write(struct msm_jpeg_hw_cmd *hw_cmd_p)
+void msm_jpeg_hw_write(struct msm_jpeg_hw_cmd *hw_cmd_p,
+ void *jpeg_region_base)
{
uint32_t *paddr;
uint32_t old_data, new_data;
@@ -266,17 +286,18 @@
writel_relaxed(new_data, paddr);
}
-int msm_jpeg_hw_wait(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_us)
+int msm_jpeg_hw_wait(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_us,
+ void *base)
{
int tm = hw_cmd_p->n;
uint32_t data;
uint32_t wait_data = hw_cmd_p->data & hw_cmd_p->mask;
- data = msm_jpeg_hw_read(hw_cmd_p);
+ data = msm_jpeg_hw_read(hw_cmd_p, base);
if (data != wait_data) {
while (tm) {
udelay(m_us);
- data = msm_jpeg_hw_read(hw_cmd_p);
+ data = msm_jpeg_hw_read(hw_cmd_p, base);
if (data == wait_data)
break;
tm--;
@@ -295,41 +316,42 @@
}
}
-int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_cmds)
+int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_cmds,
+ uint32_t max_size, void *base)
{
int is_copy_to_user = -1;
uint32_t data;
while (m_cmds--) {
- if (hw_cmd_p->offset > jpeg_region_size) {
+ if (hw_cmd_p->offset > max_size) {
JPEG_PR_ERR("%s:%d] %d exceed hw region %d\n", __func__,
- __LINE__, hw_cmd_p->offset, jpeg_region_size);
+ __LINE__, hw_cmd_p->offset, max_size);
return -EFAULT;
}
switch (hw_cmd_p->type) {
case MSM_JPEG_HW_CMD_TYPE_READ:
- hw_cmd_p->data = msm_jpeg_hw_read(hw_cmd_p);
+ hw_cmd_p->data = msm_jpeg_hw_read(hw_cmd_p, base);
is_copy_to_user = 1;
break;
case MSM_JPEG_HW_CMD_TYPE_WRITE:
- msm_jpeg_hw_write(hw_cmd_p);
+ msm_jpeg_hw_write(hw_cmd_p, base);
break;
case MSM_JPEG_HW_CMD_TYPE_WRITE_OR:
- data = msm_jpeg_hw_read(hw_cmd_p);
+ data = msm_jpeg_hw_read(hw_cmd_p, base);
hw_cmd_p->data = (hw_cmd_p->data & hw_cmd_p->mask) |
data;
- msm_jpeg_hw_write(hw_cmd_p);
+ msm_jpeg_hw_write(hw_cmd_p, base);
break;
case MSM_JPEG_HW_CMD_TYPE_UWAIT:
- msm_jpeg_hw_wait(hw_cmd_p, 1);
+ msm_jpeg_hw_wait(hw_cmd_p, 1, base);
break;
case MSM_JPEG_HW_CMD_TYPE_MWAIT:
- msm_jpeg_hw_wait(hw_cmd_p, 1000);
+ msm_jpeg_hw_wait(hw_cmd_p, 1000, base);
break;
case MSM_JPEG_HW_CMD_TYPE_UDELAY:
@@ -350,15 +372,14 @@
return is_copy_to_user;
}
-void msm_jpeg_io_dump(int size)
+void msm_jpeg_io_dump(void *base, int size)
{
char line_str[128], *p_str;
- void __iomem *addr = jpeg_region_base;
+ void __iomem *addr = (void __iomem *)base;
int i;
u32 *p = (u32 *) addr;
u32 data;
- JPEG_PR_ERR("%s: %p %d reg_size %d\n", __func__, addr, size,
- jpeg_region_size);
+ JPEG_DBG_HIGH("%s:%d] %p %d", __func__, __LINE__, addr, size);
line_str[0] = '\0';
p_str = line_str;
for (i = 0; i < size/4; i++) {
@@ -370,11 +391,12 @@
snprintf(p_str, 12, "%08x ", data);
p_str += 9;
if ((i + 1) % 4 == 0) {
- JPEG_PR_ERR("%s\n", line_str);
+ JPEG_DBG_HIGH("%s\n", line_str);
line_str[0] = '\0';
p_str = line_str;
}
}
if (line_str[0] != '\0')
- JPEG_PR_ERR("%s\n", line_str);
+ JPEG_DBG_HIGH("%s\n", line_str);
}
+
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_hw.h b/drivers/media/video/msm/jpeg_10/msm_jpeg_hw.h
index 73a0e27..e90b941 100644
--- a/drivers/media/video/msm/jpeg_10/msm_jpeg_hw.h
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_hw.h
@@ -28,6 +28,8 @@
uint32_t cbcr_len;
uint32_t num_of_mcu_rows;
struct ion_handle *handle;
+ uint32_t pln2_addr;
+ uint32_t pln2_offset;
};
struct msm_jpeg_hw_pingpong {
@@ -38,14 +40,14 @@
};
int msm_jpeg_hw_pingpong_update(struct msm_jpeg_hw_pingpong *pingpong_hw,
- struct msm_jpeg_hw_buf *buf);
+ struct msm_jpeg_hw_buf *buf, void *);
void *msm_jpeg_hw_pingpong_irq(struct msm_jpeg_hw_pingpong *pingpong_hw);
void *msm_jpeg_hw_pingpong_active_buffer(struct msm_jpeg_hw_pingpong
*pingpong_hw);
-void msm_jpeg_hw_irq_clear(uint32_t, uint32_t);
-int msm_jpeg_hw_irq_get_status(void);
-long msm_jpeg_hw_encode_output_size(void);
+void msm_jpeg_hw_irq_clear(uint32_t, uint32_t, void *);
+int msm_jpeg_hw_irq_get_status(void *);
+long msm_jpeg_hw_encode_output_size(void *);
#define MSM_JPEG_HW_MASK_COMP_FRAMEDONE \
MSM_JPEG_HW_IRQ_STATUS_FRAMEDONE_MASK
#define MSM_JPEG_HW_MASK_COMP_FE \
@@ -56,13 +58,14 @@
#define MSM_JPEG_HW_MASK_COMP_RESET_ACK \
MSM_JPEG_HW_IRQ_STATUS_RESET_ACK_MASK
#define MSM_JPEG_HW_MASK_COMP_ERR \
- (MSM_JPEG_HW_IRQ_STATUS_FE_RTOVF_MASK | \
- MSM_JPEG_HW_IRQ_STATUS_FE_VFE_OVERFLOW_MASK | \
- MSM_JPEG_HW_IRQ_STATUS_WE_Y_BUFFER_OVERFLOW_MASK | \
- MSM_JPEG_HW_IRQ_STATUS_WE_CBCR_BUFFER_OVERFLOW_MASK | \
- MSM_JPEG_HW_IRQ_STATUS_WE_CH0_DATAFIFO_OVERFLOW_MASK | \
- MSM_JPEG_HW_IRQ_STATUS_WE_CH1_DATAFIFO_OVERFLOW_MASK | \
- MSM_JPEG_HW_IRQ_STATUS_BUS_ERROR_MASK | \
+ (MSM_JPEG_HW_IRQ_STATUS_DCD_UNESCAPED_FF | \
+ MSM_JPEG_HW_IRQ_STATUS_DCD_HUFFMAN_ERROR | \
+ MSM_JPEG_HW_IRQ_STATUS_DCD_COEFFICIENT_ERR | \
+ MSM_JPEG_HW_IRQ_STATUS_DCD_MISSING_BIT_STUFF | \
+ MSM_JPEG_HW_IRQ_STATUS_DCD_SCAN_UNDERFLOW | \
+ MSM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM | \
+ MSM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM_SEQ | \
+ MSM_JPEG_HW_IRQ_STATUS_DCD_MISSING_RSM | \
MSM_JPEG_HW_IRQ_STATUS_VIOLATION_MASK)
#define msm_jpeg_hw_irq_is_frame_done(jpeg_irq_status) \
@@ -77,25 +80,26 @@
(jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_ERR)
void msm_jpeg_hw_fe_buffer_update(struct msm_jpeg_hw_buf *p_input,
- uint8_t pingpong_index);
+ uint8_t pingpong_index, void *);
void msm_jpeg_hw_we_buffer_update(struct msm_jpeg_hw_buf *p_input,
- uint8_t pingpong_index);
+ uint8_t pingpong_index, void *);
void msm_jpeg_hw_we_buffer_cfg(uint8_t is_realtime);
-void msm_jpeg_hw_fe_start(void);
+void msm_jpeg_hw_fe_start(void *);
void msm_jpeg_hw_clk_cfg(void);
void msm_jpeg_hw_reset(void *base, int size);
void msm_jpeg_hw_irq_cfg(void);
-void msm_jpeg_hw_init(void *base, int size);
-uint32_t msm_jpeg_hw_read(struct msm_jpeg_hw_cmd *hw_cmd_p);
-void msm_jpeg_hw_write(struct msm_jpeg_hw_cmd *hw_cmd_p);
-int msm_jpeg_hw_wait(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_us);
-void msm_jpeg_hw_delay(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_us);
-int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_cmds);
+uint32_t msm_jpeg_hw_read(struct msm_jpeg_hw_cmd *, void *);
+void msm_jpeg_hw_write(struct msm_jpeg_hw_cmd *, void *);
+int msm_jpeg_hw_wait(struct msm_jpeg_hw_cmd *, int, void *);
+void msm_jpeg_hw_delay(struct msm_jpeg_hw_cmd *, int);
+int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *, int ,
+ uint32_t , void *);
void msm_jpeg_hw_region_dump(int size);
-void msm_jpeg_io_dump(int size);
+void msm_jpeg_io_dump(void *base, int size);
+void msm_jpeg_decode_status(void *base);
#endif /* MSM_JPEG_HW_H */
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_hw_reg.h b/drivers/media/video/msm/jpeg_10/msm_jpeg_hw_reg.h
index ae64c32..928d59e 100644
--- a/drivers/media/video/msm/jpeg_10/msm_jpeg_hw_reg.h
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_hw_reg.h
@@ -37,30 +37,25 @@
#define MSM_JPEG_HW_IRQ_STATUS_WE_CBCR_PINGPONG_MASK 0x00000020
#define MSM_JPEG_HW_IRQ_STATUS_WE_CBCR_PINGPONG_SHIFT 0x00000005
-#define MSM_JPEG_HW_IRQ_STATUS_WE_Y_BUFFER_OVERFLOW_MASK 0x00000040
-#define MSM_JPEG_HW_IRQ_STATUS_WE_Y_BUFFER_OVERFLOW_SHIFT 0x00000006
-
-#define MSM_JPEG_HW_IRQ_STATUS_WE_CBCR_BUFFER_OVERFLOW_MASK 0x00000080
-#define MSM_JPEG_HW_IRQ_STATUS_WE_CBCR_BUFFER_OVERFLOW_SHIFT 0x00000007
-
-#define MSM_JPEG_HW_IRQ_STATUS_WE_CH0_DATAFIFO_OVERFLOW_MASK 0x00000100
-#define MSM_JPEG_HW_IRQ_STATUS_WE_CH0_DATAFIFO_OVERFLOW_SHIFT 0x00000008
-
-#define MSM_JPEG_HW_IRQ_STATUS_WE_CH1_DATAFIFO_OVERFLOW_MASK 0x00000200
-#define MSM_JPEG_HW_IRQ_STATUS_WE_CH1_DATAFIFO_OVERFLOW_SHIFT 0x00000009
-
#define MSM_JPEG_HW_IRQ_STATUS_RESET_ACK_MASK 0x10000000
#define MSM_JPEG_HW_IRQ_STATUS_RESET_ACK_SHIFT 0x0000000a
#define MSM_JPEG_HW_IRQ_STATUS_BUS_ERROR_MASK 0x00000800
#define MSM_JPEG_HW_IRQ_STATUS_BUS_ERROR_SHIFT 0x0000000b
-#define MSM_JPEG_HW_IRQ_STATUS_VIOLATION_MASK 0x00001000
-#define MSM_JPEG_HW_IRQ_STATUS_VIOLATION_SHIFT 0x0000000c
+#define MSM_JPEG_HW_IRQ_STATUS_DCD_UNESCAPED_FF (0x1<<19)
+#define MSM_JPEG_HW_IRQ_STATUS_DCD_HUFFMAN_ERROR (0x1<<20)
+#define MSM_JPEG_HW_IRQ_STATUS_DCD_COEFFICIENT_ERR (0x1<<21)
+#define MSM_JPEG_HW_IRQ_STATUS_DCD_MISSING_BIT_STUFF (0x1<<22)
+#define MSM_JPEG_HW_IRQ_STATUS_DCD_SCAN_UNDERFLOW (0x1<<23)
+#define MSM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM (0x1<<24)
+#define MSM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM_SEQ (0x1<<25)
+#define MSM_JPEG_HW_IRQ_STATUS_DCD_MISSING_RSM (0x1<<26)
+#define MSM_JPEG_HW_IRQ_STATUS_VIOLATION_MASK (0x1<<29)
#define JPEG_OFFLINE_CMD_START 0x00000001
-#define JPEG_RESET_DEFAULT 0x00000003 /* cfff? */
+#define JPEG_RESET_DEFAULT 0x00020000
#define JPEG_IRQ_DISABLE_ALL 0x00000000
#define JPEG_IRQ_CLEAR_ALL 0xFFFFFFFF
@@ -87,6 +82,9 @@
#define JPEG_PLN1_WR_PNTR_ADDR (JPEG_REG_BASE + 0x000000D0)
#define JPEG_PLN1_WR_PNTR_BMSK 0xFFFFFFFF
+#define JPEG_PLN2_WR_PNTR_ADDR (JPEG_REG_BASE + 0x000000D4)
+#define JPEG_PLN2_WR_PNTR_BMSK 0xFFFFFFFF
+
#define JPEG_IRQ_MASK_ADDR (JPEG_REG_BASE + 0x00000018)
#define JPEG_IRQ_MASK_BMSK 0xFFFFFFFF
#define JPEG_IRQ_ALLSOURCES_ENABLE 0xFFFFFFFF
@@ -103,6 +101,11 @@
#define JPEG_ENCODE_OUTPUT_SIZE_STATUS_ADDR (JPEG_REG_BASE + 0x00000180)
#define JPEG_ENCODE_OUTPUT_SIZE_STATUS_BMSK 0x1FFFFFFF
+#define JPEG_DECODE_MCUS_DECODED_STATUS (JPEG_REG_BASE + 0x00000258)
+#define JPEG_DECODE_BITS_CONSUMED_STATUS (JPEG_REG_BASE + 0x0000025C)
+#define JPEG_DECODE_PRED_Y_STATE (JPEG_REG_BASE + 0x00000260)
+#define JPEG_DECODE_PRED_C_STATE (JPEG_REG_BASE + 0x00000264)
+#define JPEG_DECODE_RSM_STATE (JPEG_REG_BASE + 0x00000268)
#define VBIF_BASE_ADDRESS 0xFDA60000
#define VBIF_REGION_SIZE 0xC30
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.c b/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.c
index 981c56c..0370f63 100644
--- a/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.c
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.c
@@ -26,36 +26,32 @@
#include "msm_jpeg_common.h"
#include "msm_jpeg_hw.h"
-/* AXI rate in KHz */
-struct ion_client *jpeg_client;
-static void *jpeg_vbif;
-
-void msm_jpeg_platform_p2v(struct file *file,
- struct ion_handle **ionhandle, int domain_num)
+void msm_jpeg_platform_p2v(struct msm_jpeg_device *pgmn_dev, struct file *file,
+ struct ion_handle **ionhandle, int domain_num)
{
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
- ion_unmap_iommu(jpeg_client, *ionhandle, domain_num, 0);
- ion_free(jpeg_client, *ionhandle);
+ ion_unmap_iommu(pgmn_dev->jpeg_client, *ionhandle, domain_num, 0);
+ ion_free(pgmn_dev->jpeg_client, *ionhandle);
*ionhandle = NULL;
#elif CONFIG_ANDROID_PMEM
put_pmem_file(file);
#endif
}
-uint32_t msm_jpeg_platform_v2p(int fd, uint32_t len, struct file **file_p,
- struct ion_handle **ionhandle, int domain_num)
-{
+uint32_t msm_jpeg_platform_v2p(struct msm_jpeg_device *pgmn_dev, int fd,
+ uint32_t len, struct file **file_p, struct ion_handle **ionhandle,
+ int domain_num) {
unsigned long paddr;
unsigned long size;
int rc;
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
- *ionhandle = ion_import_dma_buf(jpeg_client, fd);
+ *ionhandle = ion_import_dma_buf(pgmn_dev->jpeg_client, fd);
if (IS_ERR_OR_NULL(*ionhandle))
return 0;
- rc = ion_map_iommu(jpeg_client, *ionhandle, domain_num, 0,
- SZ_4K, 0, &paddr, (unsigned long *)&size, UNCACHED, 0);
- JPEG_DBG("%s:%d] addr 0x%x size %ld", __func__, __LINE__,
+ rc = ion_map_iommu(pgmn_dev->jpeg_client, *ionhandle, domain_num, 0,
+ SZ_4K, 0, &paddr, (unsigned long *)&size, UNCACHED,
+0); JPEG_DBG("%s:%d] addr 0x%x size %ld", __func__, __LINE__,
(uint32_t)paddr, size);
#elif CONFIG_ANDROID_PMEM
@@ -81,7 +77,7 @@
return paddr;
error1:
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
- ion_free(jpeg_client, *ionhandle);
+ ion_free(pgmn_dev->jpeg_client, *ionhandle);
#endif
return 0;
}
@@ -149,10 +145,10 @@
}
jpeg_irq = jpeg_irq_res->start;
JPEG_DBG("%s base address: 0x%x, jpeg irq number: %d\n", __func__,
- jpeg_mem->start, jpeg_irq);
+ jpeg_mem->start, jpeg_irq);
jpeg_io = request_mem_region(jpeg_mem->start,
- resource_size(jpeg_mem), pdev->name);
+ resource_size(jpeg_mem), pdev->name);
if (!jpeg_io) {
JPEG_PR_ERR("%s: region already claimed\n", __func__);
return -EBUSY;
@@ -165,14 +161,14 @@
goto fail1;
}
- jpeg_vbif = ioremap(VBIF_BASE_ADDRESS, VBIF_REGION_SIZE);
- if (!jpeg_vbif) {
+ pgmn_dev->jpeg_vbif = ioremap(VBIF_BASE_ADDRESS, VBIF_REGION_SIZE);
+ if (!pgmn_dev->jpeg_vbif) {
rc = -ENOMEM;
JPEG_PR_ERR("%s:%d] ioremap failed\n", __func__, __LINE__);
goto fail1;
}
JPEG_DBG("%s:%d] jpeg_vbif 0x%x", __func__, __LINE__,
- (uint32_t)jpeg_vbif);
+ (uint32_t)pgmn_dev->jpeg_vbif);
pgmn_dev->jpeg_fs = regulator_get(&pgmn_dev->pdev->dev, "vdd");
rc = regulator_enable(pgmn_dev->jpeg_fs);
@@ -202,9 +198,8 @@
(uint32_t)pgmn_dev->iommu_ctx_arr[i]);
}
#endif
- set_vbif_params(jpeg_vbif);
+ set_vbif_params(pgmn_dev->jpeg_vbif);
- msm_jpeg_hw_init(jpeg_base, resource_size(jpeg_mem));
rc = request_irq(jpeg_irq, handler, IRQF_TRIGGER_RISING, "jpeg",
context);
if (rc) {
@@ -218,7 +213,7 @@
*irq = jpeg_irq;
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
- jpeg_client = msm_ion_client_create(-1, "camera/jpeg");
+ pgmn_dev->jpeg_client = msm_ion_client_create(-1, "camera/jpeg");
#endif
JPEG_DBG("%s:%d] success\n", __func__, __LINE__);
@@ -276,11 +271,11 @@
regulator_disable(pgmn_dev->jpeg_fs);
pgmn_dev->jpeg_fs = NULL;
}
- iounmap(jpeg_vbif);
+ iounmap(pgmn_dev->jpeg_vbif);
iounmap(base);
release_mem_region(mem->start, resource_size(mem));
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
- ion_client_destroy(jpeg_client);
+ ion_client_destroy(pgmn_dev->jpeg_client);
#endif
JPEG_DBG("%s:%d] success\n", __func__, __LINE__);
return result;
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.h b/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.h
index 8a37cef..cd80d2e 100644
--- a/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.h
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.h
@@ -18,12 +18,13 @@
#include <linux/ion.h>
#include <linux/iommu.h>
#include <mach/iommu.h>
+#include "msm_jpeg_sync.h"
-
-void msm_jpeg_platform_p2v(struct file *file,
- struct ion_handle **ionhandle, int domain_num);
-uint32_t msm_jpeg_platform_v2p(int fd, uint32_t len, struct file **file,
- struct ion_handle **ionhandle, int domain_num);
+void msm_jpeg_platform_p2v(struct msm_jpeg_device *pgmn_dev, struct file *file,
+ struct ion_handle **ionhandle, int domain_num);
+uint32_t msm_jpeg_platform_v2p(struct msm_jpeg_device *pgmn_dev, int fd,
+ uint32_t len, struct file **file, struct ion_handle **ionhandle,
+ int domain_num);
int msm_jpeg_platform_clk_enable(void);
int msm_jpeg_platform_clk_disable(void);
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.c b/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.c
index 6ac4a5e..a0aaf03 100644
--- a/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.c
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.c
@@ -22,7 +22,9 @@
#include "msm_jpeg_platform.h"
#include "msm_jpeg_common.h"
-static int release_buf;
+#define JPEG_REG_SIZE 0x308
+#define JPEG_DEV_CNT 3
+#define JPEG_DEC_ID 2
inline void msm_jpeg_q_init(char const *name, struct msm_jpeg_q *q_p)
{
@@ -143,15 +145,15 @@
return 0;
}
-inline void msm_jpeg_outbuf_q_cleanup(struct msm_jpeg_q *q_p,
- int domain_num)
+inline void msm_jpeg_outbuf_q_cleanup(struct msm_jpeg_device *pgmn_dev,
+ struct msm_jpeg_q *q_p, int domain_num)
{
struct msm_jpeg_core_buf *buf_p;
JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
do {
buf_p = msm_jpeg_q_out(q_p);
if (buf_p) {
- msm_jpeg_platform_p2v(buf_p->file,
+ msm_jpeg_platform_p2v(pgmn_dev, buf_p->file,
&buf_p->handle, domain_num);
JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
kfree(buf_p);
@@ -289,10 +291,10 @@
if (buf_out) {
JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
(int) buf_out->y_buffer_addr, buf_out->y_len);
- rc = msm_jpeg_core_we_buf_update(buf_out);
+ rc = msm_jpeg_core_we_buf_update(pgmn_dev, buf_out);
kfree(buf_out);
} else {
- msm_jpeg_core_we_buf_reset(buf_in);
+ msm_jpeg_core_we_buf_reset(pgmn_dev, buf_in);
JPEG_DBG("%s:%d] no output buffer\n", __func__, __LINE__);
rc = -2;
}
@@ -320,7 +322,7 @@
}
buf_cmd = buf_p->vbuf;
- msm_jpeg_platform_p2v(buf_p->file, &buf_p->handle,
+ msm_jpeg_platform_p2v(pgmn_dev, buf_p->file, &buf_p->handle,
pgmn_dev->domain_num);
kfree(buf_p);
@@ -347,6 +349,7 @@
{
struct msm_jpeg_buf buf_cmd;
struct msm_jpeg_core_buf *buf_p;
+ memset(&buf_cmd, 0x0, sizeof(struct msm_jpeg_buf));
JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_jpeg_buf))) {
@@ -364,7 +367,7 @@
__func__, __LINE__, (int) buf_cmd.vaddr, buf_cmd.y_len,
buf_cmd.fd);
- buf_p->y_buffer_addr = msm_jpeg_platform_v2p(buf_cmd.fd,
+ buf_p->y_buffer_addr = msm_jpeg_platform_v2p(pgmn_dev, buf_cmd.fd,
buf_cmd.y_len, &buf_p->file, &buf_p->handle,
pgmn_dev->domain_num);
if (!buf_p->y_buffer_addr) {
@@ -372,9 +375,18 @@
kfree(buf_p);
return -EFAULT;
}
- JPEG_DBG("%s:%d]After v2p y_address =0x%08x, handle = %p\n",
- __func__, __LINE__, buf_p->y_buffer_addr, buf_p->handle);
+
+ if (buf_cmd.cbcr_len)
+ buf_p->cbcr_buffer_addr = buf_p->y_buffer_addr +
+ buf_cmd.y_len;
+ else
+ buf_p->cbcr_buffer_addr = 0x0;
+
+ JPEG_DBG("%s:%d] After v2p pln0_addr =0x%x,pln0_len %d pl1_len %d",
+ __func__, __LINE__, buf_p->y_buffer_addr,
+ buf_cmd.y_len, buf_cmd.cbcr_len);
buf_p->y_len = buf_cmd.y_len;
+ buf_p->cbcr_len = buf_cmd.cbcr_len;
buf_p->vbuf = buf_cmd;
msm_jpeg_q_in(&pgmn_dev->output_buf_q, buf_p);
@@ -403,9 +415,9 @@
buf_out = msm_jpeg_q_out(&pgmn_dev->input_buf_q);
if (buf_out) {
- rc = msm_jpeg_core_fe_buf_update(buf_out);
+ rc = msm_jpeg_core_fe_buf_update(pgmn_dev, buf_out);
kfree(buf_out);
- msm_jpeg_core_fe_start();
+ msm_jpeg_core_fe_start(pgmn_dev);
} else {
JPEG_DBG("%s:%d] no input buffer\n", __func__, __LINE__);
rc = -EFAULT;
@@ -433,8 +445,8 @@
}
buf_cmd = buf_p->vbuf;
- msm_jpeg_platform_p2v(buf_p->file, &buf_p->handle,
- pgmn_dev->domain_num);
+ msm_jpeg_platform_p2v(pgmn_dev, buf_p->file, &buf_p->handle,
+ pgmn_dev->domain_num);
kfree(buf_p);
JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
@@ -460,6 +472,7 @@
{
struct msm_jpeg_core_buf *buf_p;
struct msm_jpeg_buf buf_cmd;
+ memset(&buf_cmd, 0x0, sizeof(struct msm_jpeg_buf));
if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_jpeg_buf))) {
JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
@@ -475,20 +488,26 @@
JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
(int) buf_cmd.vaddr, buf_cmd.y_len);
- buf_p->y_buffer_addr = msm_jpeg_platform_v2p(buf_cmd.fd,
+ buf_p->y_buffer_addr = msm_jpeg_platform_v2p(pgmn_dev, buf_cmd.fd,
buf_cmd.y_len + buf_cmd.cbcr_len, &buf_p->file,
&buf_p->handle, pgmn_dev->domain_num) + buf_cmd.offset
+ buf_cmd.y_off;
buf_p->y_len = buf_cmd.y_len;
- buf_p->cbcr_buffer_addr = buf_p->y_buffer_addr + buf_cmd.y_len
- + buf_cmd.cbcr_off;
buf_p->cbcr_len = buf_cmd.cbcr_len;
buf_p->num_of_mcu_rows = buf_cmd.num_of_mcu_rows;
+ buf_p->y_len = buf_cmd.y_len;
+ buf_p->cbcr_len = buf_cmd.cbcr_len;
+ if (buf_cmd.cbcr_len)
+ buf_p->cbcr_buffer_addr = buf_p->y_buffer_addr + buf_cmd.y_len
+ + buf_cmd.cbcr_off;
+ else
+ buf_p->cbcr_buffer_addr = 0x0;
+
JPEG_DBG("%s: y_addr=%x, y_len=%x, cbcr_addr=%x, cbcr_len=%x, fd =%d\n",
__func__, buf_p->y_buffer_addr, buf_p->y_len,
buf_p->cbcr_buffer_addr, buf_p->cbcr_len, buf_cmd.fd);
- if (!buf_p->y_buffer_addr || !buf_p->cbcr_buffer_addr) {
+ if (!buf_p->y_buffer_addr) {
JPEG_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__);
kfree(buf_p);
return -EFAULT;
@@ -559,13 +578,15 @@
JPEG_DBG("%s:%d] platform resources - mem %p, base %p, irq %d\n",
__func__, __LINE__,
pgmn_dev->mem, pgmn_dev->base, pgmn_dev->irq);
+ pgmn_dev->res_size = resource_size(pgmn_dev->mem);
msm_jpeg_q_cleanup(&pgmn_dev->evt_q);
msm_jpeg_q_cleanup(&pgmn_dev->output_rtn_q);
- msm_jpeg_outbuf_q_cleanup(&pgmn_dev->output_buf_q,
- pgmn_dev->domain_num); msm_jpeg_q_cleanup(&pgmn_dev->input_rtn_q);
+ msm_jpeg_outbuf_q_cleanup(pgmn_dev, &pgmn_dev->output_buf_q,
+ pgmn_dev->domain_num);
+ msm_jpeg_q_cleanup(&pgmn_dev->input_rtn_q);
msm_jpeg_q_cleanup(&pgmn_dev->input_buf_q);
- msm_jpeg_core_init();
+ msm_jpeg_core_init(pgmn_dev);
JPEG_DBG("%s:%d] success\n", __func__, __LINE__);
return rc;
@@ -583,13 +604,14 @@
pgmn_dev->open_count--;
mutex_unlock(&pgmn_dev->lock);
- msm_jpeg_core_release(release_buf, pgmn_dev->domain_num);
+ msm_jpeg_core_release(pgmn_dev, pgmn_dev->domain_num);
msm_jpeg_q_cleanup(&pgmn_dev->evt_q);
msm_jpeg_q_cleanup(&pgmn_dev->output_rtn_q);
- msm_jpeg_outbuf_q_cleanup(&pgmn_dev->output_buf_q,
- pgmn_dev->domain_num);
+ msm_jpeg_outbuf_q_cleanup(pgmn_dev, &pgmn_dev->output_buf_q,
+ pgmn_dev->domain_num);
msm_jpeg_q_cleanup(&pgmn_dev->input_rtn_q);
- msm_jpeg_outbuf_q_cleanup(&pgmn_dev->input_buf_q, pgmn_dev->domain_num);
+ msm_jpeg_outbuf_q_cleanup(pgmn_dev, &pgmn_dev->input_buf_q,
+ pgmn_dev->domain_num);
JPEG_DBG("%s:%d]\n", __func__, __LINE__);
if (pgmn_dev->open_count)
@@ -598,6 +620,7 @@
msm_jpeg_platform_release(pgmn_dev->mem, pgmn_dev->base,
pgmn_dev->irq, pgmn_dev);
+ JPEG_DBG("%s:%d]\n", __func__, __LINE__);
return 0;
}
@@ -612,7 +635,8 @@
return -EFAULT;
}
- is_copy_to_user = msm_jpeg_hw_exec_cmds(&hw_cmd, 1);
+ is_copy_to_user = msm_jpeg_hw_exec_cmds(&hw_cmd, 1,
+ pgmn_dev->res_size, pgmn_dev->base);
JPEG_DBG("%s:%d] type %d, n %d, offset %d, mask %x, data %x,pdata %x\n",
__func__, __LINE__, hw_cmd.type, hw_cmd.n, hw_cmd.offset,
hw_cmd.mask, hw_cmd.data, (int) hw_cmd.pdata);
@@ -657,7 +681,8 @@
hw_cmd_p = (struct msm_jpeg_hw_cmd *) &(hw_cmds_p->hw_cmd);
- is_copy_to_user = msm_jpeg_hw_exec_cmds(hw_cmd_p, m);
+ is_copy_to_user = msm_jpeg_hw_exec_cmds(hw_cmd_p, m,
+ pgmn_dev->res_size, pgmn_dev->base);
if (is_copy_to_user >= 0) {
if (copy_to_user(arg, hw_cmds_p, len)) {
@@ -678,12 +703,12 @@
JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
- release_buf = 1;
+ pgmn_dev->release_buf = 1;
for (i = 0; i < 2; i++) {
buf_out = msm_jpeg_q_out(&pgmn_dev->input_buf_q);
if (buf_out) {
- msm_jpeg_core_fe_buf_update(buf_out);
+ msm_jpeg_core_fe_buf_update(pgmn_dev, buf_out);
kfree(buf_out);
} else {
JPEG_DBG("%s:%d] no input buffer\n", __func__,
@@ -696,8 +721,8 @@
buf_out_free[i] = msm_jpeg_q_out(&pgmn_dev->output_buf_q);
if (buf_out_free[i]) {
- msm_jpeg_core_we_buf_update(buf_out_free[i]);
- release_buf = 0;
+ msm_jpeg_core_we_buf_update(pgmn_dev, buf_out_free[i]);
+ pgmn_dev->release_buf = 0;
} else {
JPEG_DBG("%s:%d] no output buffer\n",
__func__, __LINE__);
@@ -708,6 +733,7 @@
for (i = 0; i < 2; i++)
kfree(buf_out_free[i]);
+ msm_jpeg_io_dump(pgmn_dev->base, JPEG_REG_SIZE);
rc = msm_jpeg_ioctl_hw_cmds(pgmn_dev, arg);
JPEG_DBG("%s:%d]\n", __func__, __LINE__);
return rc;
@@ -727,7 +753,7 @@
pgmn_dev->op_mode = ctrl_cmd.type;
- rc = msm_jpeg_core_reset(pgmn_dev->op_mode, pgmn_dev->base,
+ rc = msm_jpeg_core_reset(pgmn_dev, pgmn_dev->op_mode, pgmn_dev->base,
resource_size(pgmn_dev->mem));
return rc;
}
@@ -736,7 +762,7 @@
unsigned long arg)
{
JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
- msm_jpeg_io_dump(arg);
+ msm_jpeg_io_dump(pgmn_dev->base, JPEG_REG_SIZE);
return 0;
}
@@ -836,9 +862,10 @@
int __msm_jpeg_init(struct msm_jpeg_device *pgmn_dev)
{
- int rc = 0, i = 0;
+ int rc = 0, i = 0, j = 0;
int idx = 0;
- char *iommu_name[3] = {"jpeg_enc0", "jpeg_enc1", "jpeg_dec"};
+ char *iommu_name[JPEG_DEV_CNT] = {"jpeg_enc0", "jpeg_enc1",
+ "jpeg_dec"};
mutex_init(&pgmn_dev->lock);
@@ -847,6 +874,7 @@
idx = pgmn_dev->pdev->id;
pgmn_dev->idx = idx;
pgmn_dev->iommu_cnt = 1;
+ pgmn_dev->decode_flag = (idx == JPEG_DEC_ID);
msm_jpeg_q_init("evt_q", &pgmn_dev->evt_q);
msm_jpeg_q_init("output_rtn_q", &pgmn_dev->output_rtn_q);
@@ -855,21 +883,23 @@
msm_jpeg_q_init("input_buf_q", &pgmn_dev->input_buf_q);
#ifdef CONFIG_MSM_IOMMU
-/*get device context for IOMMU*/
+ j = (pgmn_dev->iommu_cnt <= 1) ? idx : 0;
+ /*get device context for IOMMU*/
for (i = 0; i < pgmn_dev->iommu_cnt; i++) {
- pgmn_dev->iommu_ctx_arr[i] = msm_iommu_get_ctx(iommu_name[i]);
- JPEG_DBG("%s:%d] name %s", __func__, __LINE__, iommu_name[i]);
+ pgmn_dev->iommu_ctx_arr[i] = msm_iommu_get_ctx(iommu_name[j]);
+ JPEG_DBG("%s:%d] name %s", __func__, __LINE__, iommu_name[j]);
JPEG_DBG("%s:%d] ctx 0x%x", __func__, __LINE__,
- (uint32_t)pgmn_dev->iommu_ctx_arr[i]);
+ (uint32_t)pgmn_dev->iommu_ctx_arr[i]);
if (!pgmn_dev->iommu_ctx_arr[i]) {
JPEG_PR_ERR("%s: No iommu fw context found\n",
__func__);
goto error;
}
+ j++;
}
pgmn_dev->domain_num = camera_register_domain();
JPEG_DBG("%s:%d] dom_num 0x%x", __func__, __LINE__,
- pgmn_dev->domain_num);
+ pgmn_dev->domain_num);
if (pgmn_dev->domain_num < 0) {
JPEG_PR_ERR("%s: could not register domain\n", __func__);
goto error;
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.h b/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.h
index 1d82060..1ac4838 100644
--- a/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.h
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.h
@@ -21,7 +21,7 @@
#include <linux/platform_device.h>
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
-#include "msm_jpeg_core.h"
+#include "msm_jpeg_hw.h"
#define JPEG_7X 0x1
#define JPEG_8X60 (0x1 << 1)
@@ -88,6 +88,17 @@
struct iommu_domain *domain;
struct device *iommu_ctx_arr[3];
int iommu_cnt;
+ int decode_flag;
+ struct ion_client *jpeg_client;
+ void *jpeg_vbif;
+ int release_buf;
+ struct msm_jpeg_hw_pingpong fe_pingpong_buf;
+ struct msm_jpeg_hw_pingpong we_pingpong_buf;
+ int we_pingpong_index;
+ int reset_done_ack;
+ spinlock_t reset_lock;
+ wait_queue_head_t reset_wait;
+ uint32_t res_size;
};
int __msm_jpeg_open(struct msm_jpeg_device *pgmn_dev);
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index cb59d68..2d9296c 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -720,7 +720,7 @@
int msm_cam_register_subdev_node(struct v4l2_subdev *sd,
struct msm_cam_subdev_info *sd_info);
int msm_mctl_find_sensor_subdevs(struct msm_cam_media_controller *p_mctl,
- int core_index);
+ uint8_t csiphy_core_index, uint8_t csid_core_index);
int msm_server_open_client(int *p_qidx);
int msm_server_send_ctrl(struct msm_ctrl_cmd *out, int ctrl_id);
int msm_server_close_client(int idx);
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index c94da2a..3b678c4 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -267,6 +267,11 @@
core, ioctl, VIDIOC_MSM_SENSOR_CFG, argp);
break;
+ case MSM_CAM_IOCTL_OEM:
+ rc = v4l2_subdev_call(p_mctl->sensor_sdev,
+ core, ioctl, VIDIOC_MSM_SENSOR_CFG, argp);
+ break;
+
case MSM_CAM_IOCTL_SENSOR_V4l2_S_CTRL: {
struct v4l2_control v4l2_ctrl;
CDBG("subdev call\n");
@@ -529,7 +534,8 @@
wake_lock(&p_mctl->wake_lock);
csid_core = camdev->csid_core;
- rc = msm_mctl_find_sensor_subdevs(p_mctl, csid_core);
+ rc = msm_mctl_find_sensor_subdevs(p_mctl, camdev->csiphy_core,
+ csid_core);
if (rc < 0) {
pr_err("%s: msm_mctl_find_sensor_subdevs failed:%d\n",
__func__, rc);
diff --git a/drivers/media/video/msm/sensors/imx091.h b/drivers/media/video/msm/sensors/imx091.h
index 3618b4c..411b90c 100644
--- a/drivers/media/video/msm/sensors/imx091.h
+++ b/drivers/media/video/msm/sensors/imx091.h
@@ -82,6 +82,7 @@
.sensor_power_up = msm_sensor_bayer_power_up,
.sensor_power_down = msm_sensor_bayer_power_down,
.sensor_get_csi_params = msm_sensor_bayer_get_csi_params,
+ .sensor_read_eeprom = msm_sensor_bayer_eeprom_read,
};
static struct msm_sensor_ctrl_t imx091_s_ctrl = {
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index 999783e..f5c9a73 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.c
@@ -402,7 +402,8 @@
csi_lane_assign;
sensor_output_info->csi_lane_mask = csi_lane_params->
csi_lane_mask;
- sensor_output_info->csi_phy_sel = csi_lane_params->csi_phy_sel;
+ sensor_output_info->csi_phy_sel =
+ s_ctrl->sensordata->pdata->csiphy_core;
}
sensor_output_info->csi_if = s_ctrl->sensordata->csi_if;
for (index = 0; index < sensor_output_info->csi_if; index++)
@@ -1184,8 +1185,7 @@
pr_err("%s failed %d\n", __func__, __LINE__);
goto ERROR3;
}
- pinfo->csi_lane_params->csi_phy_sel = val;
-
+ sensordata->pdata->csiphy_core = val;
kfree(val_array);
return rc;
ERROR3:
@@ -1762,6 +1762,8 @@
s_ctrl->sensor_i2c_addr >> 1;
s_ctrl->sensor_i2c_client->cci_client->retries = 3;
s_ctrl->sensor_i2c_client->cci_client->id_map = 0;
+ if (!s_ctrl->wait_num_frames)
+ s_ctrl->wait_num_frames = 1 * Q10;
rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
if (rc < 0) {
@@ -1777,6 +1779,8 @@
if (rc < 0)
goto probe_fail;
+ pr_err("%s %s probe succeeded\n", __func__,
+ s_ctrl->sensordata->sensor_name);
v4l2_subdev_init(&s_ctrl->sensor_v4l2_subdev,
s_ctrl->sensor_v4l2_subdev_ops);
snprintf(s_ctrl->sensor_v4l2_subdev.name,
diff --git a/drivers/media/video/msm/sensors/msm_sensor_bayer.c b/drivers/media/video/msm/sensors/msm_sensor_bayer.c
index c867867..31313d2 100644
--- a/drivers/media/video/msm/sensors/msm_sensor_bayer.c
+++ b/drivers/media/video/msm/sensors/msm_sensor_bayer.c
@@ -332,7 +332,7 @@
}
case CFG_GET_EEPROM_DATA: {
if (copy_to_user((void *)cdata.cfg.eeprom_data.eeprom_data,
- &s_ctrl->eeprom_data, s_ctrl->eeprom_data.length)) {
+ &s_ctrl->eeprom_data.data, s_ctrl->eeprom_data.length)){
pr_err("%s:%d failed\n", __func__, __LINE__);
rc = -EFAULT;
}
@@ -658,7 +658,7 @@
return rc;
}
-static int32_t msm_sensor_bayer_eeprom_read(struct msm_sensor_ctrl_t *s_ctrl)
+int32_t msm_sensor_bayer_eeprom_read(struct msm_sensor_ctrl_t *s_ctrl)
{
uint32_t reg_addr = 0;
uint8_t *data = s_ctrl->eeprom_data.data;
@@ -749,7 +749,10 @@
msm_sensor_register(&s_ctrl->sensor_v4l2_subdev);
s_ctrl->sensor_v4l2_subdev.entity.revision =
s_ctrl->sensor_v4l2_subdev.devnode->num;
- msm_sensor_bayer_eeprom_read(s_ctrl);
+ if (s_ctrl->func_tbl->sensor_read_eeprom != NULL)
+ s_ctrl->func_tbl->sensor_read_eeprom(s_ctrl);
+ else
+ msm_sensor_bayer_eeprom_read(s_ctrl);
goto power_down;
probe_fail:
pr_err("%s %s_i2c_probe failed\n", __func__, client->name);
diff --git a/drivers/media/video/msm/sensors/msm_sensor_bayer.h b/drivers/media/video/msm/sensors/msm_sensor_bayer.h
index d12244b..34e654b 100644
--- a/drivers/media/video/msm/sensors/msm_sensor_bayer.h
+++ b/drivers/media/video/msm/sensors/msm_sensor_bayer.h
@@ -65,6 +65,8 @@
int32_t msm_sensor_bayer_get_csi_params(struct msm_sensor_ctrl_t *s_ctrl,
struct csi_lane_params_t *sensor_output_info);
+int32_t msm_sensor_bayer_eeprom_read(struct msm_sensor_ctrl_t *s_ctrl);
+
#define VIDIOC_MSM_SENSOR_CFG \
_IOWR('V', BASE_VIDIOC_PRIVATE + 4, void __user *)
diff --git a/drivers/media/video/msm/sensors/msm_sensor_common.h b/drivers/media/video/msm/sensors/msm_sensor_common.h
index 79fe52e..1f34a0f 100644
--- a/drivers/media/video/msm/sensors/msm_sensor_common.h
+++ b/drivers/media/video/msm/sensors/msm_sensor_common.h
@@ -156,6 +156,7 @@
void (*sensor_adjust_frame_lines) (struct msm_sensor_ctrl_t *s_ctrl);
int32_t (*sensor_get_csi_params)(struct msm_sensor_ctrl_t *,
struct csi_lane_params_t *);
+ int32_t (*sensor_read_eeprom)(struct msm_sensor_ctrl_t *);
};
struct msm_sensor_csi_info {
diff --git a/drivers/media/video/msm/server/msm_cam_server.c b/drivers/media/video/msm/server/msm_cam_server.c
index b78e20d..74dd3f2 100644
--- a/drivers/media/video/msm/server/msm_cam_server.c
+++ b/drivers/media/video/msm/server/msm_cam_server.c
@@ -1801,13 +1801,14 @@
}
int msm_mctl_find_sensor_subdevs(struct msm_cam_media_controller *p_mctl,
- int core_index)
+ uint8_t csiphy_core_index, uint8_t csid_core_index)
{
int rc = -ENODEV;
v4l2_set_subdev_hostdata(p_mctl->sensor_sdev, p_mctl);
- rc = msm_csi_register_subdevs(p_mctl, core_index, &g_server_dev);
+ rc = msm_csi_register_subdevs(p_mctl, csiphy_core_index,
+ csid_core_index, &g_server_dev);
if (rc < 0)
pr_err("%s: Could not find sensor subdevs\n", __func__);
diff --git a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
index a4c4b83..7fa4f26 100644
--- a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
@@ -561,22 +561,69 @@
fail_nomem:
return rc;
}
+static int msm_v4l2_release_output_buffers(struct msm_v4l2_vid_inst *v4l2_inst)
+{
+ struct list_head *ptr, *next;
+ struct buffer_info *bi;
+ struct v4l2_buffer buffer_info;
+ struct v4l2_plane plane;
+ int rc = 0;
+ list_for_each_safe(ptr, next, &v4l2_inst->registered_bufs) {
+ bi = list_entry(ptr, struct buffer_info, list);
+ if (bi->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ buffer_info.type = bi->type;
+ plane.reserved[0] = bi->fd;
+ plane.reserved[1] = bi->buff_off;
+ plane.length = bi->size;
+ plane.m.userptr = bi->device_addr;
+ buffer_info.m.planes = &plane;
+ buffer_info.length = 1;
+ dprintk(VIDC_DBG,
+ "Releasing buffer: %d, %d, %d\n",
+ buffer_info.m.planes[0].reserved[0],
+ buffer_info.m.planes[0].reserved[1],
+ buffer_info.m.planes[0].length);
+ rc = msm_vidc_release_buf(&v4l2_inst->vidc_inst,
+ &buffer_info);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "Failed Release buffer: %d, %d, %d\n",
+ buffer_info.m.planes[0].reserved[0],
+ buffer_info.m.planes[0].reserved[1],
+ buffer_info.m.planes[0].length);
+ list_del(&bi->list);
+ if (bi->handle)
+ msm_smem_free(v4l2_inst->mem_client,
+ bi->handle);
+ kfree(bi);
+ }
+ }
+ return rc;
+}
static int msm_v4l2_close(struct file *filp)
{
- int rc;
+ int rc = 0;
struct list_head *ptr, *next;
- struct buffer_info *binfo;
+ struct buffer_info *bi;
struct msm_vidc_inst *vidc_inst;
struct msm_v4l2_vid_inst *v4l2_inst;
vidc_inst = get_vidc_inst(filp, NULL);
v4l2_inst = get_v4l2_inst(filp, NULL);
+ rc = msm_v4l2_release_output_buffers(v4l2_inst);
+ if (rc)
+ dprintk(VIDC_WARN,
+ "Failed in %s for release output buffers\n", __func__);
rc = msm_vidc_close(vidc_inst);
list_for_each_safe(ptr, next, &v4l2_inst->registered_bufs) {
- binfo = list_entry(ptr, struct buffer_info, list);
- list_del(&binfo->list);
- msm_smem_free(v4l2_inst->mem_client, binfo->handle);
- kfree(binfo);
+ bi = list_entry(ptr, struct buffer_info, list);
+ if (bi->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ list_del(&bi->list);
+ if (bi->handle)
+ msm_smem_free(v4l2_inst->mem_client,
+ bi->handle);
+ kfree(bi);
+ }
}
msm_smem_delete_client(v4l2_inst->mem_client);
kfree(v4l2_inst);
@@ -630,38 +677,13 @@
{
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
struct msm_v4l2_vid_inst *v4l2_inst;
- struct list_head *ptr, *next;
- int rc;
- struct buffer_info *bi;
- struct v4l2_buffer buffer_info;
- struct v4l2_plane plane;
+ int rc = 0;
v4l2_inst = get_v4l2_inst(file, NULL);
- if (b->count == 0) {
- list_for_each_safe(ptr, next, &v4l2_inst->registered_bufs) {
- bi = list_entry(ptr, struct buffer_info, list);
- if (bi->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- buffer_info.type = bi->type;
- plane.reserved[0] = bi->fd;
- plane.reserved[1] = bi->buff_off;
- plane.length = bi->size;
- plane.m.userptr = bi->device_addr;
- buffer_info.m.planes = &plane;
- buffer_info.length = 1;
- dprintk(VIDC_DBG,
- "Releasing buffer: %d, %d, %d\n",
- buffer_info.m.planes[0].reserved[0],
- buffer_info.m.planes[0].reserved[1],
- buffer_info.m.planes[0].length);
- rc = msm_vidc_release_buf(v4l2_inst->vidc_inst,
- &buffer_info);
- list_del(&bi->list);
- if (bi->handle)
- msm_smem_free(v4l2_inst->mem_client,
- bi->handle);
- kfree(bi);
- }
- }
- }
+ if (b->count == 0)
+ rc = msm_v4l2_release_output_buffers(v4l2_inst);
+ if (rc)
+ dprintk(VIDC_WARN,
+ "Failed in %s for release output buffers\n", __func__);
return msm_vidc_reqbufs((void *)vidc_inst, b);
}
@@ -824,7 +846,15 @@
static int msm_v4l2_decoder_cmd(struct file *file, void *fh,
struct v4l2_decoder_cmd *dec)
{
+ struct msm_v4l2_vid_inst *v4l2_inst;
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+ int rc = 0;
+ v4l2_inst = get_v4l2_inst(file, NULL);
+ if (dec->cmd == V4L2_DEC_CMD_STOP)
+ rc = msm_v4l2_release_output_buffers(v4l2_inst);
+ if (rc)
+ dprintk(VIDC_WARN,
+ "Failed in %s for release output buffers\n", __func__);
return msm_vidc_decoder_cmd((void *)vidc_inst, dec);
}
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
index be2e848..ead118d 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.c
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -747,6 +747,16 @@
return rc;
}
+static inline int stop_streaming(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ rc = msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "Failed to move inst: %p to start done state\n", inst);
+ return rc;
+}
+
static int msm_vdec_start_streaming(struct vb2_queue *q, unsigned int count)
{
struct msm_vidc_inst *inst;
@@ -788,13 +798,11 @@
switch (q->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
if (!inst->vb2_bufq[CAPTURE_PORT].streaming)
- rc = msm_comm_try_state(inst,
- MSM_VIDC_RELEASE_RESOURCES_DONE);
+ rc = stop_streaming(inst);
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
if (!inst->vb2_bufq[OUTPUT_PORT].streaming)
- rc = msm_comm_try_state(inst,
- MSM_VIDC_RELEASE_RESOURCES_DONE);
+ rc = stop_streaming(inst);
break;
default:
dprintk(VIDC_ERR,
@@ -830,6 +838,12 @@
rc = msm_comm_flush(inst, dec->flags);
break;
case V4L2_DEC_CMD_STOP:
+ rc = msm_comm_release_scratch_buffers(inst);
+ if (rc)
+ pr_err("Failed to release scratch buffers: %d\n", rc);
+ rc = msm_comm_release_persist_buffers(inst);
+ if (rc)
+ pr_err("Failed to release persist buffers: %d\n", rc);
rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
break;
default:
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
index 6c0f224..c137c08 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -95,7 +95,7 @@
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = MIN_FRAME_RATE,
.maximum = MAX_FRAME_RATE,
- .default_value = DEFAULT_FRAME_RATE,
+ .default_value = MIN_FRAME_RATE,
.step = 1,
.menu_skip_mask = 0,
.qmenu = NULL,
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index 7f3096a..2aed0b7 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -1566,6 +1566,68 @@
return rc;
}
+int msm_comm_release_scratch_buffers(struct msm_vidc_inst *inst)
+{
+ struct msm_smem *handle;
+ struct list_head *ptr, *next;
+ struct internal_buf *buf;
+ struct vidc_buffer_addr_info buffer_info;
+ int rc = 0;
+ unsigned long flags;
+ spin_lock_irqsave(&inst->lock, flags);
+ if (!list_empty(&inst->internalbufs)) {
+ list_for_each_safe(ptr, next, &inst->internalbufs) {
+ buf = list_entry(ptr, struct internal_buf,
+ list);
+ handle = buf->handle;
+ buffer_info.buffer_size = handle->size;
+ buffer_info.buffer_type = HAL_BUFFER_INTERNAL_SCRATCH;
+ buffer_info.num_buffers = 1;
+ buffer_info.align_device_addr = handle->device_addr;
+ rc = vidc_hal_session_release_buffers(
+ (void *) inst->session, &buffer_info);
+ list_del(&buf->list);
+ msm_smem_free(inst->mem_client, buf->handle);
+ kfree(buf);
+ }
+ }
+ spin_unlock_irqrestore(&inst->lock, flags);
+ return rc;
+}
+
+int msm_comm_release_persist_buffers(struct msm_vidc_inst *inst)
+{
+ struct msm_smem *handle;
+ struct list_head *ptr, *next;
+ struct internal_buf *buf;
+ struct vidc_buffer_addr_info buffer_info;
+ int rc = 0;
+ unsigned long flags;
+ spin_lock_irqsave(&inst->lock, flags);
+ if (!list_empty(&inst->persistbufs)) {
+ list_for_each_safe(ptr, next, &inst->persistbufs) {
+ buf = list_entry(ptr, struct internal_buf,
+ list);
+ handle = buf->handle;
+ buffer_info.buffer_size = handle->size;
+ buffer_info.buffer_type = HAL_BUFFER_INTERNAL_PERSIST;
+ buffer_info.num_buffers = 1;
+ buffer_info.align_device_addr = handle->device_addr;
+ rc = vidc_hal_session_release_buffers(
+ (void *) inst->session, &buffer_info);
+ if (rc)
+ dprintk(VIDC_WARN,
+ "Failed in %s for buffer %ld\n",
+ __func__, handle->device_addr);
+ list_del(&buf->list);
+ msm_smem_free(inst->mem_client, buf->handle);
+ kfree(buf);
+ }
+ }
+ spin_unlock_irqrestore(&inst->lock, flags);
+ return rc;
+}
+
int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst)
{
int rc = 0;
@@ -1586,6 +1648,17 @@
list_for_each_safe(ptr, next, &inst->internalbufs) {
binfo = list_entry(ptr, struct internal_buf,
list);
+ handle = binfo->handle;
+ buffer_info.buffer_size = handle->size;
+ buffer_info.buffer_type = HAL_BUFFER_INTERNAL_SCRATCH;
+ buffer_info.num_buffers = 1;
+ buffer_info.align_device_addr = handle->device_addr;
+ rc = vidc_hal_session_release_buffers(
+ (void *) inst->session, &buffer_info);
+ if (rc)
+ dprintk(VIDC_WARN,
+ "Failed in release %s for buffer %ld\n",
+ __func__, handle->device_addr);
list_del(&binfo->list);
msm_smem_free(inst->mem_client, binfo->handle);
kfree(binfo);
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.h b/drivers/media/video/msm_vidc/msm_vidc_common.h
index 69aa53a..1301e5c 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.h
@@ -32,6 +32,8 @@
int msm_comm_qbuf(struct vb2_buffer *vb);
int msm_comm_scale_clocks(struct msm_vidc_core *core, enum session_type type);
int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags);
+int msm_comm_release_scratch_buffers(struct msm_vidc_inst *inst);
+int msm_comm_release_persist_buffers(struct msm_vidc_inst *inst);
#define IS_PRIV_CTRL(idx) (\
(V4L2_CTRL_ID2CLASS(idx) == V4L2_CTRL_CLASS_MPEG) && \
V4L2_CTRL_DRIVER_PRIV(idx))
diff --git a/drivers/media/video/msm_vidc/vidc_hal.c b/drivers/media/video/msm_vidc/vidc_hal.c
index 0639dea..e610f8e 100644
--- a/drivers/media/video/msm_vidc/vidc_hal.c
+++ b/drivers/media/video/msm_vidc/vidc_hal.c
@@ -177,7 +177,7 @@
new_write_idx -= queue->qhdr_q_size;
memcpy(write_ptr, packet, (packet_size_in_words -
new_write_idx) << 2);
- memcpy((void *)queue->qhdr_start_addr,
+ memcpy((void *)qinfo->q_array.align_virtual_addr,
packet + ((packet_size_in_words - new_write_idx) << 2),
new_write_idx << 2);
}
@@ -285,8 +285,9 @@
memcpy(packet, read_ptr,
(packet_size_in_words - new_read_idx) << 2);
memcpy(packet + ((packet_size_in_words -
- new_read_idx) << 2),
- (u8 *)queue->qhdr_start_addr, new_read_idx << 2);
+ new_read_idx) << 2),
+ (u8 *)qinfo->q_array.align_virtual_addr,
+ new_read_idx << 2);
}
queue->qhdr_read_idx = new_read_idx;
diff --git a/drivers/media/video/msm_wfd/Kconfig b/drivers/media/video/msm_wfd/Kconfig
new file mode 100644
index 0000000..6050d73
--- /dev/null
+++ b/drivers/media/video/msm_wfd/Kconfig
@@ -0,0 +1,6 @@
+menuconfig MSM_WFD
+ bool "Qualcomm MSM Wifi Display Driver"
+ depends on (MSM_VIDC_1080P || MSM_VIDC_V4L2)
+ ---help---
+ Enables the Wifi Display driver.
+
diff --git a/drivers/media/video/msm_wfd/Makefile b/drivers/media/video/msm_wfd/Makefile
index 5decaca..813bc64 100644
--- a/drivers/media/video/msm_wfd/Makefile
+++ b/drivers/media/video/msm_wfd/Makefile
@@ -1,5 +1,14 @@
-obj-y += mdp-subdev.o
-obj-y += enc-subdev.o
-obj-y += vsg-subdev.o
-obj-y += wfd-ioctl.o
-obj-y += wfd-util.o
+ifeq ($(CONFIG_MSM_WFD),y)
+ obj-y += wfd-ioctl.o
+ obj-y += wfd-util.o
+ obj-y += vsg-subdev.o
+ ifeq ($(CONFIG_FB_MSM_WRITEBACK_MSM_PANEL),y)
+ obj-y += mdp-4-subdev.o
+ else ifeq ($(CONFIG_FB_MSM_MDSS_WRITEBACK),y)
+ obj-y += mdp-5-subdev.o
+ else
+ obj-y += mdp-dummy-subdev.o
+ endif
+ obj-$(CONFIG_MSM_VIDC_1080P) += enc-mfc-subdev.o
+ obj-$(CONFIG_MSM_VIDC_V4L2) += enc-venus-subdev.o
+endif
diff --git a/drivers/media/video/msm_wfd/enc-subdev.c b/drivers/media/video/msm_wfd/enc-mfc-subdev.c
similarity index 96%
rename from drivers/media/video/msm_wfd/enc-subdev.c
rename to drivers/media/video/msm_wfd/enc-mfc-subdev.c
index e1cabf9..5997345 100644
--- a/drivers/media/video/msm_wfd/enc-subdev.c
+++ b/drivers/media/video/msm_wfd/enc-mfc-subdev.c
@@ -227,7 +227,7 @@
BUFFER_TYPE_OUTPUT, pmem_fd,
kvaddr, buffer_index, &ion_handle);
else
- WFD_MSG_ERR("Got an output buffer that we "
+ WFD_MSG_ERR("Got an output buffer that we " \
"couldn't recognize!\n");
if (msm_ion_do_cache_op(client_ctx->user_ion_client,
@@ -547,8 +547,8 @@
if (vcd_property_level.level < VCD_LEVEL_MPEG4_0
|| vcd_property_level.level > VCD_LEVEL_MPEG4_X) {
- WFD_MSG_ERR("Level (%d) out of range"
- "for codec (%d)\n", level, codec);
+ WFD_MSG_ERR("Level (%d) out of range for codec (%d)\n",
+ level, codec);
rc = -EINVAL;
goto err;
@@ -558,8 +558,8 @@
if (vcd_property_level.level < VCD_LEVEL_H264_1
|| vcd_property_level.level > VCD_LEVEL_H264_5p1) {
- WFD_MSG_ERR("Level (%d) out of range"
- "for codec (%d)\n", level, codec);
+ WFD_MSG_ERR("Level (%d) out of range for codec (%d)\n",
+ level, codec);
rc = -EINVAL;
goto err;
@@ -678,9 +678,9 @@
vcd_property_profile.profile = VCD_PROFILE_MPEG4_ASP;
break;
default:
- WFD_MSG_ERR("Profile %d not supported,"
- "defaulting to simple (%d)",
- profile, VCD_PROFILE_MPEG4_SP);
+ WFD_MSG_ERR("Profile %d not supported, defaulting " \
+ "to simple (%d)", profile,
+ VCD_PROFILE_MPEG4_SP);
vcd_property_profile.profile = VCD_PROFILE_MPEG4_SP;
break;
}
@@ -697,17 +697,16 @@
vcd_property_profile.profile = VCD_PROFILE_H264_HIGH;
break;
default:
- WFD_MSG_ERR("Profile %d not supported,"
- "defaulting to baseline (%d)",
- profile, VCD_PROFILE_H264_BASELINE);
+ WFD_MSG_ERR("Profile %d not supported, defaulting " \
+ "to baseline (%d)", profile,
+ VCD_PROFILE_H264_BASELINE);
vcd_property_profile.profile =
VCD_PROFILE_H264_BASELINE;
break;
}
} else {
- WFD_MSG_ERR("Codec (%d) not supported,"
- "not setting profile (%d)",
- codec, profile);
+ WFD_MSG_ERR("Codec (%d) not supported, not "\
+ "setting profile (%d)", codec, profile);
rc = -ENOTSUPP;
goto err_set_profile;
}
@@ -2312,6 +2311,73 @@
return rc;
}
+long venc_mmap(struct v4l2_subdev *sd, void *arg)
+{
+ struct venc_inst *inst = sd->dev_priv;
+ struct mem_region_map *mmap = arg;
+ struct mem_region *mregion = NULL;
+ unsigned long rc = 0, size = 0;
+ void *paddr = NULL;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ return -EINVAL;
+ } else if (!mmap || !mmap->mregion) {
+ WFD_MSG_ERR("Memregion required for %s\n", __func__);
+ return -EINVAL;
+ }
+
+ mregion = mmap->mregion;
+ if (mregion->size % SZ_4K != 0) {
+ WFD_MSG_ERR("Memregion not aligned to %d\n", SZ_4K);
+ return -EINVAL;
+ }
+
+ if (inst->secure) {
+ rc = ion_phys(mmap->ion_client, mregion->ion_handle,
+ (unsigned long *)&paddr,
+ (size_t *)&size);
+ } else {
+ rc = ion_map_iommu(mmap->ion_client, mregion->ion_handle,
+ VIDEO_DOMAIN, VIDEO_MAIN_POOL, SZ_4K,
+ 0, (unsigned long *)&paddr,
+ &size, 0, 0);
+ }
+
+ if (rc) {
+ WFD_MSG_ERR("Failed to get physical addr\n");
+ paddr = NULL;
+ } else if (size < mregion->size) {
+ WFD_MSG_ERR("Failed to map enough memory\n");
+ rc = -ENOMEM;
+ }
+
+ mregion->paddr = paddr;
+ return rc;
+}
+
+long venc_munmap(struct v4l2_subdev *sd, void *arg)
+{
+ struct venc_inst *inst = sd->dev_priv;
+ struct mem_region_map *mmap = arg;
+ struct mem_region *mregion = NULL;
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ return -EINVAL;
+ } else if (!mregion) {
+ WFD_MSG_ERR("Memregion required for %s\n", __func__);
+ return -EINVAL;
+ }
+
+ mregion = mmap->mregion;
+ if (!inst->secure) {
+ ion_unmap_iommu(mmap->ion_client, mregion->ion_handle,
+ VIDEO_DOMAIN, VIDEO_MAIN_POOL);
+ }
+
+ return 0;
+}
+
long venc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
long rc = 0;
@@ -2375,6 +2441,12 @@
case ENCODE_FLUSH:
rc = venc_flush_buffers(sd, arg);
break;
+ case ENC_MMAP:
+ rc = venc_mmap(sd, arg);
+ break;
+ case ENC_MUNMAP:
+ rc = venc_munmap(sd, arg);
+ break;
default:
rc = -1;
break;
diff --git a/drivers/media/video/msm_wfd/enc-subdev.h b/drivers/media/video/msm_wfd/enc-subdev.h
index 00eb6da..c6c854e 100644
--- a/drivers/media/video/msm_wfd/enc-subdev.h
+++ b/drivers/media/video/msm_wfd/enc-subdev.h
@@ -14,6 +14,7 @@
#ifndef _WFD_ENC_SUBDEV_
#define _WFD_ENC_SUBDEV_
+#include <linux/list.h>
#include <linux/msm_ion.h>
#include <media/v4l2-subdev.h>
#include <media/videobuf2-core.h>
@@ -29,6 +30,15 @@
u32 cookie;
struct ion_handle *ion_handle;
};
+
+/* FIXME: need to come with a less stupid name */
+struct mem_region_map {
+ struct mem_region *mregion;
+ struct ion_client *ion_client;
+ uint32_t flags;
+ void *cookie;
+};
+
struct bufreq {
u32 count;
u32 height;
@@ -44,13 +54,27 @@
struct venc_msg_ops {
void *cookie;
void *cbdata;
- int secure;
+ bool secure;
void (*op_buffer_done)(void *cookie, u32 status,
struct vb2_buffer *buf);
void (*ip_buffer_done)(void *cookie, u32 status,
struct mem_region *mregion);
};
+static inline bool mem_region_equals(struct mem_region *a,
+ struct mem_region *b)
+{
+ if (a == b)
+ return true;
+ else if (a->fd || b->fd)
+ return (a->fd == b->fd) &&
+ (a->offset == b->offset);
+ else if (a->kvaddr || b->kvaddr)
+ return a->kvaddr == b->kvaddr;
+ else
+ return false;
+}
+
#define OPEN _IOR('V', 1, void *)
#define CLOSE _IO('V', 2)
#define ENCODE_START _IO('V', 3)
@@ -75,6 +99,8 @@
#define FREE_INPUT_BUFFER _IOWR('V', 22, struct mem_region *)
#define FREE_RECON_BUFFERS _IO('V', 23)
#define ENCODE_FLUSH _IO('V', 24)
+#define ENC_MMAP _IOWR('V', 25, struct mem_region_map *)
+#define ENC_MUNMAP _IOWR('V', 26, struct mem_region_map *)
extern int venc_init(struct v4l2_subdev *sd, u32 val);
extern int venc_load_fw(struct v4l2_subdev *sd);
diff --git a/drivers/media/video/msm_wfd/enc-venus-subdev.c b/drivers/media/video/msm_wfd/enc-venus-subdev.c
new file mode 100644
index 0000000..04e42f5
--- /dev/null
+++ b/drivers/media/video/msm_wfd/enc-venus-subdev.c
@@ -0,0 +1,1218 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 and
+* only version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+*/
+
+#include <linux/bitmap.h>
+#include <linux/completion.h>
+#include <linux/ion.h>
+#include <linux/kthread.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <mach/iommu_domains.h>
+#include <media/msm_vidc.h>
+#include <media/v4l2-subdev.h>
+#include "enc-subdev.h"
+#include "wfd-util.h"
+
+#define BUF_TYPE_OUTPUT V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
+#define BUF_TYPE_INPUT V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
+
+static struct ion_client *venc_ion_client;
+
+struct index_bitmap {
+ unsigned long *bitmap;
+ int size;
+ int size_bits; /*Size in bits, not necessarily size/8 */
+};
+
+struct venc_inst {
+ void *vidc_context;
+ struct mutex lock;
+ struct venc_msg_ops vmops;
+ struct mem_region registered_input_bufs, registered_output_bufs;
+ struct index_bitmap free_input_indices, free_output_indices;
+ int num_output_planes, num_input_planes;
+ struct task_struct *callback_thread;
+ bool callback_thread_running;
+ struct completion dq_complete, cmd_complete;
+ bool secure;
+ int domain;
+};
+
+int venc_load_fw(struct v4l2_subdev *sd)
+{
+ /*No need to explicitly load the fw */
+ return 0;
+}
+
+int venc_init(struct v4l2_subdev *sd, u32 val)
+{
+ if (!venc_ion_client)
+ venc_ion_client = msm_ion_client_create(-1, "wfd_enc_subdev");
+
+ return venc_ion_client ? 0 : -ENOMEM;
+}
+
+static int next_free_index(struct index_bitmap *index_bitmap)
+{
+ int index = find_first_zero_bit(index_bitmap->bitmap,
+ index_bitmap->size_bits);
+
+ return (index >= index_bitmap->size_bits) ?
+ -1 : index;
+}
+
+static int mark_index_busy(struct index_bitmap *index_bitmap, int index)
+{
+ if (index > index_bitmap->size_bits) {
+ WFD_MSG_WARN("Marking unknown index as busy\n");
+ return -EINVAL;
+ }
+ set_bit(index, index_bitmap->bitmap);
+ return 0;
+}
+
+static int mark_index_free(struct index_bitmap *index_bitmap, int index)
+{
+ if (index > index_bitmap->size_bits) {
+ WFD_MSG_WARN("Marking unknown index as free\n");
+ return -EINVAL;
+ }
+ clear_bit(index, index_bitmap->bitmap);
+ return 0;
+}
+
+static int get_list_len(struct mem_region *list)
+{
+ struct mem_region *curr = NULL;
+ int index = 0;
+ list_for_each_entry(curr, &list->list, list) {
+ ++index;
+ }
+
+ return index;
+}
+
+static struct mem_region *get_registered_mregion(struct mem_region *list,
+ struct mem_region *mregion)
+{
+ struct mem_region *curr = NULL;
+ list_for_each_entry(curr, &list->list, list) {
+ if (unlikely(mem_region_equals(curr, mregion)))
+ return curr;
+ }
+
+ return NULL;
+}
+
+static int venc_vidc_callback_thread(void *data)
+{
+ struct venc_inst *inst = data;
+ WFD_MSG_DBG("Starting callback thread\n");
+ while (!kthread_should_stop()) {
+ bool dequeue_buf = false;
+ struct v4l2_buffer buffer = {0};
+ struct v4l2_event event = {0};
+ int num_planes = 0;
+ int flags = msm_vidc_wait(inst->vidc_context);
+
+ if (flags & POLLERR) {
+ WFD_MSG_ERR("Encoder reported error\n");
+ break;
+ }
+
+ if (flags & POLLPRI) {
+ bool bail_out = false;
+
+ msm_vidc_dqevent(inst->vidc_context, &event);
+ if (event.type == V4L2_EVENT_MSM_VIDC_CLOSE_DONE) {
+ WFD_MSG_ERR("enc callback thread shutting " \
+ "down normally\n");
+ bail_out = true;
+ } else {
+ WFD_MSG_ERR("Got unknown event %d, ignoring\n",
+ event.id);
+ }
+
+ complete_all(&inst->cmd_complete);
+ if (bail_out)
+ break;
+ }
+
+ if (flags & POLLIN || flags & POLLRDNORM) {
+ buffer.type = BUF_TYPE_OUTPUT;
+ dequeue_buf = true;
+ num_planes = inst->num_output_planes;
+ WFD_MSG_DBG("Output buffer ready!\n");
+ }
+
+ if (flags & POLLOUT || flags & POLLWRNORM) {
+ buffer.type = BUF_TYPE_INPUT;
+ dequeue_buf = true;
+ num_planes = inst->num_input_planes;
+ WFD_MSG_DBG("Input buffer ready!\n");
+ }
+
+ if (dequeue_buf) {
+ int rc = 0;
+ struct v4l2_plane *planes = NULL;
+ struct mem_region *curr = NULL, *mregion = NULL;
+ struct list_head *reg_bufs = NULL;
+ struct index_bitmap *bitmap = NULL;
+
+ planes = kzalloc(sizeof(*planes) * num_planes,
+ GFP_KERNEL);
+ buffer.m.planes = planes;
+ buffer.length = 1;
+ buffer.memory = V4L2_MEMORY_USERPTR;
+ rc = msm_vidc_dqbuf(inst->vidc_context, &buffer);
+
+ if (rc) {
+ WFD_MSG_ERR("Error dequeuing buffer" \
+ "from vidc: %d", rc);
+ goto abort_dequeue;
+ }
+
+ reg_bufs = buffer.type == BUF_TYPE_OUTPUT ?
+ &inst->registered_output_bufs.list :
+ &inst->registered_input_bufs.list;
+
+ bitmap = buffer.type == BUF_TYPE_OUTPUT ?
+ &inst->free_output_indices :
+ &inst->free_input_indices;
+
+ list_for_each_entry(curr, reg_bufs, list) {
+ if ((u32)curr->paddr ==
+ buffer.m.planes[0].m.userptr) {
+ mregion = curr;
+ break;
+ }
+ }
+
+ if (!mregion) {
+ WFD_MSG_ERR("Got done msg for unknown buf\n");
+ goto abort_dequeue;
+ }
+
+ if (buffer.type == BUF_TYPE_OUTPUT &&
+ inst->vmops.op_buffer_done) {
+ struct vb2_buffer *vb =
+ (struct vb2_buffer *)mregion->cookie;
+
+ vb->v4l2_buf.flags = buffer.flags;
+ vb->v4l2_buf.timestamp = buffer.timestamp;
+ vb->v4l2_planes[0].bytesused =
+ buffer.m.planes[0].bytesused;
+
+ inst->vmops.op_buffer_done(
+ inst->vmops.cbdata, 0, vb);
+ } else if (buffer.type == BUF_TYPE_INPUT &&
+ inst->vmops.ip_buffer_done) {
+ inst->vmops.ip_buffer_done(
+ inst->vmops.cbdata,
+ 0, mregion);
+ }
+
+ complete_all(&inst->dq_complete);
+ mutex_lock(&inst->lock);
+ mark_index_free(bitmap, buffer.index);
+ mutex_unlock(&inst->lock);
+abort_dequeue:
+ kfree(planes);
+ }
+ }
+
+
+ WFD_MSG_DBG("Exiting callback thread\n");
+ mutex_lock(&inst->lock);
+ inst->callback_thread_running = false;
+ mutex_unlock(&inst->lock);
+ return 0;
+}
+
+static long venc_open(struct v4l2_subdev *sd, void *arg)
+{
+ struct venc_inst *inst = NULL;
+ struct venc_msg_ops *vmops = arg;
+ struct v4l2_event_subscription event = {0};
+ struct msm_vidc_iommu_info maps[MAX_MAP];
+ int rc = 0;
+
+ if (!vmops) {
+ WFD_MSG_ERR("Callbacks required for %s\n", __func__);
+ rc = -EINVAL;
+ goto venc_open_fail;
+ } else if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ rc = -EINVAL;
+ goto venc_open_fail;
+ }
+
+ inst = kzalloc(sizeof(*inst), GFP_KERNEL);
+ if (!inst) {
+ WFD_MSG_ERR("Failed to allocate memory\n");
+ rc = -EINVAL;
+ goto venc_open_fail;
+ }
+
+ inst->secure = false;
+ inst->vmops = *vmops;
+ INIT_LIST_HEAD(&inst->registered_output_bufs.list);
+ INIT_LIST_HEAD(&inst->registered_input_bufs.list);
+ init_completion(&inst->dq_complete);
+ init_completion(&inst->cmd_complete);
+ mutex_init(&inst->lock);
+ inst->vidc_context = msm_vidc_open(MSM_VIDC_CORE_0, MSM_VIDC_ENCODER);
+ if (!inst->vidc_context) {
+ WFD_MSG_ERR("Failed to create vidc context\n");
+ rc = -ENXIO;
+ goto vidc_open_fail;
+ }
+
+ event.type = V4L2_EVENT_MSM_VIDC_CLOSE_DONE;
+ rc = msm_vidc_subscribe_event(inst->vidc_context, &event);
+ if (rc) {
+ WFD_MSG_ERR("Failed to subscribe to CLOSE_DONE event\n");
+ goto vidc_subscribe_fail;
+ }
+
+ event.type = V4L2_EVENT_MSM_VIDC_FLUSH_DONE;
+ rc = msm_vidc_subscribe_event(inst->vidc_context, &event);
+ if (rc) {
+ WFD_MSG_ERR("Failed to subscribe to FLUSH_DONE event\n");
+ goto vidc_subscribe_fail;
+ }
+
+ rc = msm_vidc_get_iommu_maps(inst->vidc_context, maps);
+ if (rc) {
+ WFD_MSG_ERR("Failed to retreive domain mappings\n");
+ rc = -ENODATA;
+ goto vidc_subscribe_fail;
+ }
+
+ inst->domain = maps[inst->secure ? CP_MAP : NS_MAP].domain;
+
+ inst->callback_thread = kthread_run(venc_vidc_callback_thread, inst,
+ "venc_vidc_callback_thread");
+ if (IS_ERR(inst->callback_thread)) {
+ WFD_MSG_ERR("Failed to create callback thread\n");
+ rc = PTR_ERR(inst->callback_thread);
+ inst->callback_thread = NULL;
+ goto vidc_kthread_create_fail;
+ }
+ inst->callback_thread_running = true;
+
+ sd->dev_priv = inst;
+ vmops->cookie = inst;
+ return 0;
+vidc_kthread_create_fail:
+ event.type = V4L2_EVENT_MSM_VIDC_CLOSE_DONE;
+ msm_vidc_unsubscribe_event(inst->vidc_context, &event);
+
+ event.type = V4L2_EVENT_MSM_VIDC_FLUSH_DONE;
+ msm_vidc_unsubscribe_event(inst->vidc_context, &event);
+vidc_subscribe_fail:
+ msm_vidc_close(inst->vidc_context);
+vidc_open_fail:
+ kfree(inst);
+venc_open_fail:
+ return rc;
+}
+
+static long venc_close(struct v4l2_subdev *sd, void *arg)
+{
+ struct venc_inst *inst = NULL;
+ struct v4l2_event_subscription event = {0};
+ struct v4l2_encoder_cmd enc_cmd = {0};
+ int rc = 0;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ rc = -EINVAL;
+ goto venc_close_fail;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+ enc_cmd.cmd = V4L2_ENC_CMD_STOP;
+ msm_vidc_encoder_cmd(inst->vidc_context, &enc_cmd);
+
+ wait_for_completion(&inst->cmd_complete);
+
+ if (inst->callback_thread && inst->callback_thread_running)
+ kthread_stop(inst->callback_thread);
+
+ event.type = V4L2_EVENT_MSM_VIDC_CLOSE_DONE;
+ rc = msm_vidc_unsubscribe_event(inst->vidc_context, &event);
+ if (rc)
+ WFD_MSG_WARN("Failed to unsubscribe close event\n");
+
+ event.type = V4L2_EVENT_MSM_VIDC_FLUSH_DONE;
+ rc = msm_vidc_unsubscribe_event(inst->vidc_context, &event);
+ if (rc)
+ WFD_MSG_WARN("Failed to unsubscribe flush event\n");
+
+ rc = msm_vidc_close(inst->vidc_context);
+ if (rc)
+ WFD_MSG_WARN("Failed to close vidc context\n");
+
+ kfree(inst);
+ sd->dev_priv = inst = NULL;
+venc_close_fail:
+ return rc;
+}
+
+static long venc_get_buffer_req(struct v4l2_subdev *sd, void *arg)
+{
+ int rc = 0;
+ struct venc_inst *inst = NULL;
+ struct bufreq *bufreq = arg;
+ struct v4l2_requestbuffers v4l2_bufreq = {0};
+ struct v4l2_format v4l2_format = {0};
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ rc = -EINVAL;
+ goto venc_buf_req_fail;
+ } else if (!arg) {
+ WFD_MSG_ERR("Invalid buffer requirements\n");
+ rc = -EINVAL;
+ goto venc_buf_req_fail;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+ /* Get buffer count */
+ v4l2_bufreq = (struct v4l2_requestbuffers) {
+ .count = bufreq->count,
+ .type = BUF_TYPE_OUTPUT,
+ .memory = V4L2_MEMORY_USERPTR,
+ };
+
+ rc = msm_vidc_reqbufs(inst->vidc_context, &v4l2_bufreq);
+ if (rc) {
+ WFD_MSG_ERR("Failed getting buffer requirements\n");
+ goto venc_buf_req_fail;
+ }
+
+ /* Get buffer size */
+ v4l2_format.type = BUF_TYPE_OUTPUT;
+ rc = msm_vidc_g_fmt(inst->vidc_context, &v4l2_format);
+ if (rc) {
+ WFD_MSG_ERR("Failed getting OP buffer size\n");
+ goto venc_buf_req_fail;
+ }
+
+ bufreq->count = v4l2_bufreq.count;
+ bufreq->size = v4l2_format.fmt.pix_mp.plane_fmt[0].sizeimage;
+
+ inst->free_output_indices.size_bits = bufreq->count;
+ inst->free_output_indices.size = roundup(bufreq->count,
+ sizeof(unsigned long)) / sizeof(unsigned long);
+ inst->free_output_indices.bitmap = kzalloc(inst->free_output_indices.
+ size, GFP_KERNEL);
+venc_buf_req_fail:
+ return rc;
+}
+
+static long venc_set_buffer_req(struct v4l2_subdev *sd, void *arg)
+{
+ int rc = 0;
+ struct venc_inst *inst = NULL;
+ struct bufreq *bufreq = arg;
+ struct v4l2_requestbuffers v4l2_bufreq = {0};
+ struct v4l2_format v4l2_format = {0};
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ rc = -EINVAL;
+ goto venc_buf_req_fail;
+ } else if (!arg) {
+ WFD_MSG_ERR("Invalid buffer requirements\n");
+ rc = -EINVAL;
+ goto venc_buf_req_fail;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+
+ /* Attempt to set buffer count */
+ v4l2_bufreq = (struct v4l2_requestbuffers) {
+ .count = bufreq->count,
+ .type = BUF_TYPE_INPUT,
+ .memory = V4L2_MEMORY_USERPTR,
+ };
+
+ rc = msm_vidc_reqbufs(inst->vidc_context, &v4l2_bufreq);
+ if (rc) {
+ WFD_MSG_ERR("Failed getting buffer requirements");
+ goto venc_buf_req_fail;
+ }
+
+ /* Get buffer size */
+ v4l2_format.type = BUF_TYPE_INPUT;
+ rc = msm_vidc_g_fmt(inst->vidc_context, &v4l2_format);
+ if (rc) {
+ WFD_MSG_ERR("Failed getting OP buffer size\n");
+ goto venc_buf_req_fail;
+ }
+
+ bufreq->count = v4l2_bufreq.count;
+ bufreq->size = v4l2_format.fmt.pix_mp.plane_fmt[0].sizeimage;
+
+ inst->free_input_indices.size_bits = bufreq->count;
+ inst->free_input_indices.size = roundup(bufreq->count,
+ sizeof(unsigned long)) / sizeof(unsigned long);
+ inst->free_input_indices.bitmap = kzalloc(inst->free_input_indices.
+ size, GFP_KERNEL);
+venc_buf_req_fail:
+ return rc;
+}
+
+static long venc_start(struct v4l2_subdev *sd)
+{
+ struct venc_inst *inst = NULL;
+ int rc = 0;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ rc = -EINVAL;
+ goto venc_start_fail;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+
+ rc = msm_vidc_streamon(inst->vidc_context, BUF_TYPE_OUTPUT);
+ if (rc) {
+ WFD_MSG_ERR("Failed to streamon vidc's output port");
+ goto venc_start_fail;
+ }
+
+ rc = msm_vidc_streamon(inst->vidc_context, BUF_TYPE_INPUT);
+ if (rc) {
+ WFD_MSG_ERR("Failed to streamon vidc's input port");
+ goto venc_start_fail;
+ }
+
+venc_start_fail:
+ return rc;
+}
+
+static long venc_stop(struct v4l2_subdev *sd)
+{
+ struct venc_inst *inst = NULL;
+ int rc = 0;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ rc = -EINVAL;
+ goto venc_stop_fail;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+
+ rc = msm_vidc_streamoff(inst->vidc_context, BUF_TYPE_INPUT);
+ if (rc) {
+ WFD_MSG_ERR("Failed to streamoff vidc's input port");
+ goto venc_stop_fail;
+ }
+
+ rc = msm_vidc_streamoff(inst->vidc_context, BUF_TYPE_OUTPUT);
+ if (rc) {
+ WFD_MSG_ERR("Failed to streamoff vidc's output port");
+ goto venc_stop_fail;
+ }
+
+venc_stop_fail:
+ return rc;
+}
+
+static long venc_set_input_buffer(struct v4l2_subdev *sd, void *arg)
+{
+ int rc = 0;
+ struct venc_inst *inst = NULL;
+ struct v4l2_buffer buf = {0};
+ struct v4l2_plane plane = {0};
+ struct mem_region *mregion = arg;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ rc = -EINVAL;
+ goto set_input_buffer_fail;
+ } else if (!arg) {
+ WFD_MSG_ERR("Invalid input buffer\n");
+ rc = -EINVAL;
+ goto set_input_buffer_fail;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+ if (get_registered_mregion(&inst->registered_input_bufs, mregion)) {
+ WFD_MSG_ERR("Duplicate input buffer\n");
+ rc = -EEXIST;
+ goto set_input_buffer_fail;
+ }
+
+ mregion = kzalloc(sizeof(*mregion), GFP_KERNEL);
+ *mregion = *(struct mem_region *)arg;
+
+ plane = (struct v4l2_plane) {
+ .length = mregion->size,
+ .m.userptr = (u32)mregion->paddr,
+ };
+
+ buf = (struct v4l2_buffer) {
+ .index = get_list_len(&inst->registered_input_bufs),
+ .type = BUF_TYPE_INPUT,
+ .bytesused = 0,
+ .memory = V4L2_MEMORY_USERPTR,
+ .m.planes = &plane,
+ .length = 1,
+ };
+
+ WFD_MSG_DBG("Prepare %p with index, %d",
+ (void *)buf.m.planes[0].m.userptr, buf.index);
+ rc = msm_vidc_prepare_buf(inst->vidc_context, &buf);
+ if (rc) {
+ WFD_MSG_ERR("Failed to prepare input buffer\n");
+ goto set_input_buffer_fail;
+ }
+
+ list_add_tail(&mregion->list, &inst->registered_input_bufs.list);
+ return 0;
+set_input_buffer_fail:
+ kfree(mregion);
+ return rc;
+}
+
+static int venc_map_user_to_kernel(struct venc_inst *inst,
+ struct mem_region *mregion)
+{
+ int rc = 0;
+ unsigned long flags = 0, size = 0;
+ if (!mregion) {
+ rc = -EINVAL;
+ goto venc_map_fail;
+ }
+
+ mregion->ion_handle = ion_import_dma_buf(venc_ion_client, mregion->fd);
+ if (IS_ERR_OR_NULL(mregion->ion_handle)) {
+ rc = PTR_ERR(mregion->ion_handle);
+ WFD_MSG_ERR("Failed to get handle: %p, %d, %d, %d\n",
+ venc_ion_client, mregion->fd, mregion->offset, rc);
+ mregion->ion_handle = NULL;
+ goto venc_map_fail;
+ }
+
+ rc = ion_handle_get_flags(venc_ion_client, mregion->ion_handle, &flags);
+ if (rc) {
+ WFD_MSG_ERR("Failed to get ion flags %d\n", rc);
+ goto venc_map_fail;
+ }
+
+ mregion->kvaddr = ion_map_kernel(venc_ion_client,
+ mregion->ion_handle, flags);
+
+ if (IS_ERR_OR_NULL(mregion->kvaddr)) {
+ WFD_MSG_ERR("Failed to map buffer into kernel\n");
+ rc = PTR_ERR(mregion->kvaddr);
+ mregion->kvaddr = NULL;
+ goto venc_map_fail;
+ }
+
+ rc = ion_map_iommu(venc_ion_client, mregion->ion_handle,
+ inst->domain, 0, SZ_4K, 0,
+ (unsigned long *)&mregion->paddr, &size, flags, 0);
+
+ if (rc) {
+ WFD_MSG_ERR("Failed to map into iommu\n");
+ goto venc_map_iommu_map_fail;
+ } else if (size < mregion->size) {
+ WFD_MSG_ERR("Failed to iommu map the correct size\n");
+ goto venc_map_iommu_size_fail;
+ }
+
+ return 0;
+venc_map_iommu_size_fail:
+ ion_unmap_iommu(venc_ion_client, mregion->ion_handle,
+ inst->domain, 0);
+venc_map_iommu_map_fail:
+ ion_unmap_kernel(venc_ion_client, mregion->ion_handle);
+venc_map_fail:
+ return rc;
+}
+
+static int venc_unmap_user_to_kernel(struct venc_inst *inst,
+ struct mem_region *mregion)
+{
+ if (!mregion || !mregion->ion_handle)
+ return 0;
+
+ if (mregion->paddr) {
+ ion_unmap_iommu(venc_ion_client, mregion->ion_handle,
+ inst->domain, 0);
+ mregion->paddr = NULL;
+ }
+
+ if (mregion->kvaddr) {
+ ion_unmap_kernel(venc_ion_client, mregion->ion_handle);
+ mregion->kvaddr = NULL;
+ }
+
+
+ return 0;
+}
+
+static long venc_set_output_buffer(struct v4l2_subdev *sd, void *arg)
+{
+ int rc = 0;
+ struct venc_inst *inst = NULL;
+ struct v4l2_buffer buf = {0};
+ struct v4l2_plane plane = {0};
+ struct mem_region *mregion = arg;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ rc = -EINVAL;
+ goto venc_set_output_buffer_fail;
+ } else if (!mregion) {
+ WFD_MSG_ERR("Invalid output buffer\n");
+ rc = -EINVAL;
+ goto venc_set_output_buffer_fail;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+
+ /* Check if buf already registered */
+ if (get_registered_mregion(&inst->registered_output_bufs, mregion)) {
+ WFD_MSG_ERR("Duplicate output buffer\n");
+ rc = -EEXIST;
+ goto venc_set_output_buffer_fail;
+ }
+
+ mregion = kzalloc(sizeof(*mregion), GFP_KERNEL);
+
+ if (!mregion) {
+ WFD_MSG_ERR("Failed to allocate memory\n");
+ goto venc_set_output_buffer_fail;
+ }
+
+ *mregion = *(struct mem_region *)arg;
+ INIT_LIST_HEAD(&mregion->list);
+
+ rc = venc_map_user_to_kernel(inst, mregion);
+ if (rc) {
+ WFD_MSG_ERR("Failed to map output buffer\n");
+ goto venc_set_output_buffer_map_fail;
+ }
+
+ plane = (struct v4l2_plane) {
+ .length = mregion->size,
+ .m.userptr = (u32)mregion->paddr,
+ };
+
+ buf = (struct v4l2_buffer) {
+ .index = get_list_len(&inst->registered_output_bufs),
+ .type = BUF_TYPE_OUTPUT,
+ .bytesused = 0,
+ .memory = V4L2_MEMORY_USERPTR,
+ .m.planes = &plane,
+ .length = 1,
+ };
+
+ WFD_MSG_DBG("Prepare %p with index, %d",
+ (void *)buf.m.planes[0].m.userptr, buf.index);
+ rc = msm_vidc_prepare_buf(inst->vidc_context, &buf);
+ if (rc) {
+ WFD_MSG_ERR("Failed to prepare output buffer\n");
+ goto venc_set_output_buffer_prepare_fail;
+ }
+
+ list_add_tail(&mregion->list, &inst->registered_output_bufs.list);
+ return rc;
+venc_set_output_buffer_prepare_fail:
+ venc_unmap_user_to_kernel(inst, mregion);
+venc_set_output_buffer_map_fail:
+ kfree(mregion);
+venc_set_output_buffer_fail:
+ return rc;
+}
+
+static long venc_set_format(struct v4l2_subdev *sd, void *arg)
+{
+ struct venc_inst *inst = NULL;
+ struct v4l2_format *fmt = arg, temp;
+ int rc = 0;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ rc = -EINVAL;
+ goto venc_set_format_fail;
+ } else if (!fmt) {
+ WFD_MSG_ERR("Invalid format\n");
+ rc = -EINVAL;
+ goto venc_set_format_fail;
+ } else if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ WFD_MSG_ERR("Invalid buffer type %d\n", fmt->type);
+ rc = -ENOTSUPP;
+ goto venc_set_format_fail;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+ temp = (struct v4l2_format) {
+ .type = BUF_TYPE_OUTPUT,
+ .fmt.pix_mp = (struct v4l2_pix_format_mplane) {
+ .width = fmt->fmt.pix.width,
+ .height = fmt->fmt.pix.height,
+ .pixelformat = fmt->fmt.pix.pixelformat,
+ },
+ };
+
+ rc = msm_vidc_s_fmt(inst->vidc_context, &temp);
+
+ if (rc) {
+ WFD_MSG_ERR("Failed to format for output port\n");
+ goto venc_set_format_fail;
+ } else if (!temp.fmt.pix_mp.num_planes) {
+ WFD_MSG_ERR("No. of planes for output buffers make no sense\n");
+ rc = -EINVAL;
+ goto venc_set_format_fail;
+ }
+ fmt->fmt.pix.sizeimage = temp.fmt.pix_mp.plane_fmt[0].sizeimage;
+ inst->num_output_planes = temp.fmt.pix_mp.num_planes;
+
+ temp.type = BUF_TYPE_INPUT;
+ temp.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12;
+ rc = msm_vidc_s_fmt(inst->vidc_context, &temp);
+ inst->num_input_planes = temp.fmt.pix_mp.num_planes;
+
+ if (rc) {
+ WFD_MSG_ERR("Failed to format for input port\n");
+ goto venc_set_format_fail;
+ }
+venc_set_format_fail:
+ return rc;
+}
+
+static long venc_set_framerate(struct v4l2_subdev *sd, void *arg)
+{
+ struct venc_inst *inst = NULL;
+ struct v4l2_control ctrl = {0};
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ return -EINVAL;
+ } else if (!arg) {
+ WFD_MSG_ERR("Invalid framerate\n");
+ return -EINVAL;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+ ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE;
+ ctrl.value = 30;
+ return msm_vidc_s_ctrl(inst->vidc_context, &ctrl);
+}
+
+static long venc_fill_outbuf(struct v4l2_subdev *sd, void *arg)
+{
+ struct venc_inst *inst = NULL;
+ struct mem_region *mregion = NULL;
+ struct v4l2_buffer buffer = {0};
+ struct v4l2_plane plane = {0};
+ int index = 0, rc = 0;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ return -EINVAL;
+ } else if (!arg) {
+ WFD_MSG_ERR("Invalid output buffer ot fill\n");
+ return -EINVAL;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+ mregion = get_registered_mregion(&inst->registered_output_bufs, arg);
+
+ if (!mregion) {
+ WFD_MSG_ERR("Output buffer not registered\n");
+ return -ENOENT;
+ }
+
+ plane = (struct v4l2_plane) {
+ .length = mregion->size,
+ .m.userptr = (u32)mregion->paddr,
+ };
+
+ while (true) {
+ mutex_lock(&inst->lock);
+ index = next_free_index(&inst->free_output_indices);
+ mutex_unlock(&inst->lock);
+
+ if (index < 0)
+ wait_for_completion(&inst->dq_complete);
+ else
+ break;
+ }
+
+ buffer = (struct v4l2_buffer) {
+ .index = index,
+ .type = BUF_TYPE_OUTPUT,
+ .memory = V4L2_MEMORY_USERPTR,
+ .m.planes = &plane,
+ .length = 1,
+ };
+
+ WFD_MSG_DBG("Fill buffer %p with index, %d",
+ (void *)buffer.m.planes[0].m.userptr, buffer.index);
+ rc = msm_vidc_qbuf(inst->vidc_context, &buffer);
+ if (!rc) {
+ mutex_lock(&inst->lock);
+ mark_index_busy(&inst->free_output_indices, index);
+ mutex_unlock(&inst->lock);
+ }
+ return rc;
+
+}
+
+static long venc_encode_frame(struct v4l2_subdev *sd, void *arg)
+{
+ struct venc_inst *inst = NULL;
+ struct venc_buf_info *venc_buf = arg;
+ struct mem_region *mregion = NULL;
+ struct v4l2_buffer buffer = {0};
+ struct v4l2_plane plane = {0};
+ int index = 0, rc = 0;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ return -EINVAL;
+ } else if (!venc_buf) {
+ WFD_MSG_ERR("Invalid output buffer ot fill\n");
+ return -EINVAL;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+ mregion = venc_buf->mregion;
+
+ plane = (struct v4l2_plane) {
+ .length = mregion->size,
+ .m.userptr = (u32)mregion->paddr,
+ .bytesused = mregion->size,
+ };
+
+ while (true) {
+ mutex_lock(&inst->lock);
+ index = next_free_index(&inst->free_input_indices);
+ mutex_unlock(&inst->lock);
+
+ if (index < 0)
+ wait_for_completion(&inst->dq_complete);
+ else
+ break;
+ }
+
+ buffer = (struct v4l2_buffer) {
+ .index = index,
+ .type = BUF_TYPE_INPUT,
+ .timestamp = ns_to_timeval(venc_buf->timestamp),
+ .memory = V4L2_MEMORY_USERPTR,
+ .m.planes = &plane,
+ .length = 1,
+ };
+
+ WFD_MSG_DBG("Encode buffer %p with index, %d",
+ (void *)buffer.m.planes[0].m.userptr, buffer.index);
+ rc = msm_vidc_qbuf(inst->vidc_context, &buffer);
+ if (!rc) {
+ mutex_lock(&inst->lock);
+ mark_index_busy(&inst->free_input_indices, index);
+ mutex_unlock(&inst->lock);
+ }
+ return rc;
+}
+
+static long venc_alloc_recon_buffers(struct v4l2_subdev *sd, void *arg)
+{
+ /* vidc driver allocates internally on streamon */
+ return 0;
+}
+
+static long venc_free_buffer(struct venc_inst *inst, int type,
+ struct mem_region *to_free, bool unmap_user_buffer)
+{
+ struct mem_region *mregion = NULL;
+ struct mem_region *buf_list = NULL;
+
+ if (type == BUF_TYPE_OUTPUT) {
+ buf_list = &inst->registered_output_bufs;
+ } else if (type == BUF_TYPE_INPUT) {
+ buf_list = &inst->registered_input_bufs;
+ } else {
+ WFD_MSG_ERR("Trying to free a buffer of unknown type\n");
+ return -EINVAL;
+ }
+
+ mregion = get_registered_mregion(buf_list, to_free);
+
+ if (!mregion) {
+ WFD_MSG_ERR("Buffer not registered, cannot free\n");
+ return -ENOENT;
+ }
+
+ if (unmap_user_buffer) {
+ int rc = venc_unmap_user_to_kernel(inst, mregion);
+ if (rc)
+ WFD_MSG_WARN("Unable to unmap user buffer\n");
+ }
+
+ list_del(&mregion->list);
+ kfree(mregion);
+ return 0;
+}
+static long venc_free_output_buffer(struct v4l2_subdev *sd, void *arg)
+{
+ int rc = 0;
+ struct venc_inst *inst = NULL;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ rc = -EINVAL;
+ goto venc_free_output_buffer_fail;
+ } else if (!arg) {
+ WFD_MSG_ERR("Invalid output buffer\n");
+ rc = -EINVAL;
+ goto venc_free_output_buffer_fail;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+ return venc_free_buffer(inst, BUF_TYPE_OUTPUT, arg, true);
+venc_free_output_buffer_fail:
+ return rc;
+}
+
+static long venc_flush_buffers(struct v4l2_subdev *sd, void *arg)
+{
+ struct venc_inst *inst = NULL;
+ struct v4l2_encoder_cmd enc_cmd = {0};
+ int rc = 0;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ rc = -EINVAL;
+ goto venc_flush_buffers_fail;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+
+ enc_cmd.cmd = V4L2_ENC_QCOM_CMD_FLUSH;
+ enc_cmd.flags = BUF_TYPE_INPUT | BUF_TYPE_OUTPUT;
+ msm_vidc_encoder_cmd(inst->vidc_context, &enc_cmd);
+
+ wait_for_completion(&inst->cmd_complete);
+venc_flush_buffers_fail:
+ return rc;
+}
+
+static long venc_free_input_buffer(struct v4l2_subdev *sd, void *arg)
+{
+ int rc = 0;
+ struct venc_inst *inst = NULL;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ rc = -EINVAL;
+ goto venc_free_input_buffer_fail;
+ } else if (!arg) {
+ WFD_MSG_ERR("Invalid output buffer\n");
+ rc = -EINVAL;
+ goto venc_free_input_buffer_fail;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+ return venc_free_buffer(inst, BUF_TYPE_INPUT, arg, false);
+venc_free_input_buffer_fail:
+ return rc;
+}
+
+static long venc_free_recon_buffers(struct v4l2_subdev *sd, void *arg)
+{
+ /* vidc driver takes care of this */
+ return 0;
+}
+
+static long venc_set_property(struct v4l2_subdev *sd, void *arg)
+{
+ struct venc_inst *inst = NULL;
+ struct v4l2_control *ctrl = arg;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ return -EINVAL;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+ if (ctrl->id == V4L2_CID_MPEG_VIDEO_HEADER_MODE) {
+ /* XXX: We don't support this yet, but to prevent unncessary
+ * target specific code for the client, we'll not error out.
+ * The client ideally shouldn't notice this */
+ return 0;
+ }
+
+ return msm_vidc_s_ctrl(inst->vidc_context, (struct v4l2_control *)arg);
+}
+
+static long venc_get_property(struct v4l2_subdev *sd, void *arg)
+{
+ struct venc_inst *inst = NULL;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ return -EINVAL;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+ return msm_vidc_g_ctrl(inst->vidc_context, (struct v4l2_control *)arg);
+}
+
+long venc_mmap(struct v4l2_subdev *sd, void *arg)
+{
+ struct mem_region_map *mmap = arg;
+ struct mem_region *mregion = NULL;
+ unsigned long rc = 0, size = 0;
+ void *paddr = NULL;
+ struct venc_inst *inst = NULL;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ return -EINVAL;
+ } else if (!mmap || !mmap->mregion) {
+ WFD_MSG_ERR("Memregion required for %s\n", __func__);
+ return -EINVAL;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+ mregion = mmap->mregion;
+ if (mregion->size % SZ_4K != 0) {
+ WFD_MSG_ERR("Memregion not aligned to %d\n", SZ_4K);
+ return -EINVAL;
+ }
+
+ rc = ion_map_iommu(mmap->ion_client, mregion->ion_handle,
+ inst->domain, 0, SZ_4K, 0, (unsigned long *)&paddr,
+ &size, 0, 0);
+
+ if (rc) {
+ WFD_MSG_ERR("Failed to get physical addr\n");
+ paddr = NULL;
+ } else if (size < mregion->size) {
+ WFD_MSG_ERR("Failed to map enough memory\n");
+ rc = -ENOMEM;
+ }
+
+ mregion->paddr = paddr;
+ return rc;
+}
+
+long venc_munmap(struct v4l2_subdev *sd, void *arg)
+{
+ struct mem_region_map *mmap = arg;
+ struct mem_region *mregion = NULL;
+ struct venc_inst *inst = NULL;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ return -EINVAL;
+ } else if (!mmap || !mmap->mregion) {
+ WFD_MSG_ERR("Memregion required for %s\n", __func__);
+ return -EINVAL;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+ mregion = mmap->mregion;
+
+ ion_unmap_iommu(mmap->ion_client, mregion->ion_handle,
+ inst->domain, 0);
+ return 0;
+}
+
+long venc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+ long rc = 0;
+ switch (cmd) {
+ case OPEN:
+ rc = venc_open(sd, arg);
+ break;
+ case CLOSE:
+ rc = venc_close(sd, arg);
+ break;
+ case ENCODE_START:
+ rc = venc_start(sd);
+ break;
+ case ENCODE_FRAME:
+ venc_encode_frame(sd, arg);
+ break;
+ case ENCODE_STOP:
+ rc = venc_stop(sd);
+ break;
+ case SET_PROP:
+ rc = venc_set_property(sd, arg);
+ break;
+ case GET_PROP:
+ rc = venc_get_property(sd, arg);
+ break;
+ case GET_BUFFER_REQ:
+ rc = venc_get_buffer_req(sd, arg);
+ break;
+ case SET_BUFFER_REQ:
+ rc = venc_set_buffer_req(sd, arg);
+ break;
+ case FREE_BUFFER:
+ break;
+ case FILL_OUTPUT_BUFFER:
+ rc = venc_fill_outbuf(sd, arg);
+ break;
+ case SET_FORMAT:
+ rc = venc_set_format(sd, arg);
+ break;
+ case SET_FRAMERATE:
+ rc = venc_set_framerate(sd, arg);
+ break;
+ case SET_INPUT_BUFFER:
+ rc = venc_set_input_buffer(sd, arg);
+ break;
+ case SET_OUTPUT_BUFFER:
+ rc = venc_set_output_buffer(sd, arg);
+ break;
+ case ALLOC_RECON_BUFFERS:
+ rc = venc_alloc_recon_buffers(sd, arg);
+ break;
+ case FREE_OUTPUT_BUFFER:
+ rc = venc_free_output_buffer(sd, arg);
+ break;
+ case FREE_INPUT_BUFFER:
+ rc = venc_free_input_buffer(sd, arg);
+ break;
+ case FREE_RECON_BUFFERS:
+ rc = venc_free_recon_buffers(sd, arg);
+ break;
+ case ENCODE_FLUSH:
+ rc = venc_flush_buffers(sd, arg);
+ break;
+ case ENC_MMAP:
+ rc = venc_mmap(sd, arg);
+ break;
+ case ENC_MUNMAP:
+ rc = venc_munmap(sd, arg);
+ break;
+ default:
+ WFD_MSG_ERR("Unknown ioctl %d to enc-subdev\n", cmd);
+ rc = -ENOTSUPP;
+ break;
+ }
+ return rc;
+}
diff --git a/drivers/media/video/msm_wfd/mdp-subdev.c b/drivers/media/video/msm_wfd/mdp-4-subdev.c
similarity index 67%
copy from drivers/media/video/msm_wfd/mdp-subdev.c
copy to drivers/media/video/msm_wfd/mdp-4-subdev.c
index 886b0ba..c68d5d4 100644
--- a/drivers/media/video/msm_wfd/mdp-subdev.c
+++ b/drivers/media/video/msm_wfd/mdp-4-subdev.c
@@ -10,53 +10,66 @@
* GNU General Public License for more details.
*
*/
+#include <linux/msm_mdp.h>
+#include <mach/iommu_domains.h>
+#include <media/videobuf2-core.h>
+#include "enc-subdev.h"
#include "mdp-subdev.h"
#include "wfd-util.h"
-#include <media/videobuf2-core.h>
-#include <linux/msm_mdp.h>
struct mdp_instance {
struct fb_info *mdp;
u32 height;
u32 width;
+ bool secure;
+ bool uses_iommu_split_domain;
};
int mdp_init(struct v4l2_subdev *sd, u32 val)
{
return 0;
}
+
int mdp_open(struct v4l2_subdev *sd, void *arg)
{
struct mdp_instance *inst = kzalloc(sizeof(struct mdp_instance),
GFP_KERNEL);
- void **cookie = (void **)arg;
+ struct mdp_msg_ops *mops = arg;
int rc = 0;
struct fb_info *fbi = NULL;
if (!inst) {
WFD_MSG_ERR("Out of memory\n");
- return -ENOMEM;
+ rc = -ENOMEM;
+ goto mdp_open_fail;
+ } else if (!mops) {
+ WFD_MSG_ERR("Invalid arguments\n");
+ rc = -EINVAL;
+ goto mdp_open_fail;
}
fbi = msm_fb_get_writeback_fb();
if (!fbi) {
WFD_MSG_ERR("Failed to acquire mdp instance\n");
rc = -ENODEV;
- goto exit;
+ goto mdp_open_fail;
}
/*Tell HDMI daemon to open fb2*/
rc = kobject_uevent(&fbi->dev->kobj, KOBJ_ADD);
if (rc) {
WFD_MSG_ERR("Failed add to kobj");
- goto exit;
+ goto mdp_open_fail;
}
msm_fb_writeback_init(fbi);
inst->mdp = fbi;
- *cookie = inst;
+ inst->secure = mops->secure;
+ inst->uses_iommu_split_domain = mops->iommu_split_domain;
+
+ mops->cookie = inst;
return rc;
-exit:
+mdp_open_fail:
kfree(inst);
return rc;
}
@@ -134,8 +147,8 @@
fbdata.flags = 0;
fbdata.priv = (uint32_t)binfo->cookie;
- WFD_MSG_INFO("queue buffer to mdp with offset = %u,"
- "fd = %u, priv = %p, iova = %p\n",
+ WFD_MSG_INFO("queue buffer to mdp with offset = %u, fd = %u, "\
+ "priv = %p, iova = %p\n",
fbdata.offset, fbdata.memory_id,
(void *)fbdata.priv, (void *)fbdata.iova);
rc = msm_fb_writeback_queue_buffer(inst->mdp, &fbdata);
@@ -179,6 +192,84 @@
inst->width = prop->width;
return 0;
}
+
+int mdp_mmap(struct v4l2_subdev *sd, void *arg)
+{
+ int rc = 0, domain = -1;
+ struct mem_region_map *mmap = arg;
+ struct mem_region *mregion;
+ bool use_iommu = true;
+ struct mdp_instance *inst = NULL;
+
+ if (!mmap || !mmap->mregion || !mmap->cookie) {
+ WFD_MSG_ERR("Invalid argument\n");
+ return -EINVAL;
+ }
+
+ inst = mmap->cookie;
+ mregion = mmap->mregion;
+ if (mregion->size % SZ_4K != 0) {
+ WFD_MSG_ERR("Memregion not aligned to %d\n", SZ_4K);
+ return -EINVAL;
+ }
+
+ if (inst->uses_iommu_split_domain) {
+ if (inst->secure)
+ use_iommu = false;
+ else
+ domain = DISPLAY_WRITE_DOMAIN;
+ } else {
+ domain = DISPLAY_READ_DOMAIN;
+ }
+
+ if (use_iommu) {
+ rc = ion_map_iommu(mmap->ion_client, mregion->ion_handle,
+ domain, GEN_POOL, SZ_4K, 0,
+ (unsigned long *)&mregion->paddr,
+ (unsigned long *)&mregion->size,
+ 0, 0);
+ } else {
+ rc = ion_phys(mmap->ion_client, mregion->ion_handle,
+ (unsigned long *)&mregion->paddr,
+ (size_t *)&mregion->size);
+ }
+
+ return rc;
+}
+
+int mdp_munmap(struct v4l2_subdev *sd, void *arg)
+{
+ struct mem_region_map *mmap = arg;
+ struct mem_region *mregion;
+ bool use_iommu = false;
+ int domain = -1;
+ struct mdp_instance *inst = NULL;
+
+ if (!mmap || !mmap->mregion || !mmap->cookie) {
+ WFD_MSG_ERR("Invalid argument\n");
+ return -EINVAL;
+ }
+
+ inst = mmap->cookie;
+ mregion = mmap->mregion;
+
+ if (inst->uses_iommu_split_domain) {
+ if (inst->secure)
+ use_iommu = false;
+ else
+ domain = DISPLAY_WRITE_DOMAIN;
+ } else {
+ domain = DISPLAY_READ_DOMAIN;
+ }
+
+ if (use_iommu)
+ ion_unmap_iommu(mmap->ion_client,
+ mregion->ion_handle,
+ domain, GEN_POOL);
+
+ return 0;
+}
+
long mdp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
int rc = 0;
@@ -208,6 +299,12 @@
case MDP_CLOSE:
rc = mdp_close(sd, arg);
break;
+ case MDP_MMAP:
+ rc = mdp_mmap(sd, arg);
+ break;
+ case MDP_MUNMAP:
+ rc = mdp_munmap(sd, arg);
+ break;
default:
WFD_MSG_ERR("IOCTL: %u not supported\n", cmd);
rc = -EINVAL;
diff --git a/drivers/media/video/msm_wfd/mdp-subdev.c b/drivers/media/video/msm_wfd/mdp-5-subdev.c
similarity index 72%
rename from drivers/media/video/msm_wfd/mdp-subdev.c
rename to drivers/media/video/msm_wfd/mdp-5-subdev.c
index 886b0ba..4f29389 100644
--- a/drivers/media/video/msm_wfd/mdp-subdev.c
+++ b/drivers/media/video/msm_wfd/mdp-5-subdev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -10,53 +10,63 @@
* GNU General Public License for more details.
*
*/
+#include <linux/msm_mdp.h>
+#include <mach/iommu_domains.h>
+#include <media/videobuf2-core.h>
+#include "enc-subdev.h"
#include "mdp-subdev.h"
#include "wfd-util.h"
-#include <media/videobuf2-core.h>
-#include <linux/msm_mdp.h>
+
struct mdp_instance {
struct fb_info *mdp;
u32 height;
u32 width;
+ bool secure;
};
int mdp_init(struct v4l2_subdev *sd, u32 val)
{
return 0;
}
+
int mdp_open(struct v4l2_subdev *sd, void *arg)
{
struct mdp_instance *inst = kzalloc(sizeof(struct mdp_instance),
GFP_KERNEL);
- void **cookie = (void **)arg;
+ struct mdp_msg_ops *mops = arg;
int rc = 0;
struct fb_info *fbi = NULL;
if (!inst) {
WFD_MSG_ERR("Out of memory\n");
- return -ENOMEM;
+ rc = -ENOMEM;
+ goto mdp_open_fail;
+ } else if (!mops) {
+ WFD_MSG_ERR("Invalid arguments\n");
+ rc = -EINVAL;
+ goto mdp_open_fail;
}
fbi = msm_fb_get_writeback_fb();
if (!fbi) {
WFD_MSG_ERR("Failed to acquire mdp instance\n");
rc = -ENODEV;
- goto exit;
+ goto mdp_open_fail;
}
/*Tell HDMI daemon to open fb2*/
rc = kobject_uevent(&fbi->dev->kobj, KOBJ_ADD);
- if (rc) {
+ if (rc)
WFD_MSG_ERR("Failed add to kobj");
- goto exit;
- }
msm_fb_writeback_init(fbi);
inst->mdp = fbi;
- *cookie = inst;
+ inst->secure = mops->secure;
+
+ mops->cookie = inst;
return rc;
-exit:
+mdp_open_fail:
kfree(inst);
return rc;
}
@@ -85,6 +95,7 @@
exit:
return rc;
}
+
int mdp_stop(struct v4l2_subdev *sd, void *arg)
{
struct mdp_instance *inst = arg;
@@ -134,8 +145,8 @@
fbdata.flags = 0;
fbdata.priv = (uint32_t)binfo->cookie;
- WFD_MSG_INFO("queue buffer to mdp with offset = %u,"
- "fd = %u, priv = %p, iova = %p\n",
+ WFD_MSG_DBG("queue buffer to mdp with offset = %u, fd = %u, "\
+ "priv = %p, iova = %p\n",
fbdata.offset, fbdata.memory_id,
(void *)fbdata.priv, (void *)fbdata.iova);
rc = msm_fb_writeback_queue_buffer(inst->mdp, &fbdata);
@@ -179,6 +190,58 @@
inst->width = prop->width;
return 0;
}
+
+int mdp_mmap(struct v4l2_subdev *sd, void *arg)
+{
+ int rc = 0;
+ struct mem_region_map *mmap = arg;
+ struct mem_region *mregion;
+ bool domain = -1;
+ struct mdp_instance *inst = NULL;
+
+ if (!mmap || !mmap->mregion || !mmap->cookie) {
+ WFD_MSG_ERR("Invalid argument\n");
+ return -EINVAL;
+ }
+
+ inst = mmap->cookie;
+ mregion = mmap->mregion;
+ if (mregion->size % SZ_4K != 0) {
+ WFD_MSG_ERR("Memregion not aligned to %d\n", SZ_4K);
+ return -EINVAL;
+ }
+
+ domain = msm_fb_get_iommu_domain();
+ rc = ion_map_iommu(mmap->ion_client, mregion->ion_handle,
+ domain, 0, SZ_4K, 0,
+ (unsigned long *)&mregion->paddr,
+ (unsigned long *)&mregion->size,
+ 0, 0);
+ return rc;
+}
+
+int mdp_munmap(struct v4l2_subdev *sd, void *arg)
+{
+ struct mem_region_map *mmap = arg;
+ struct mem_region *mregion;
+ bool domain = -1;
+ struct mdp_instance *inst = NULL;
+
+ if (!mmap || !mmap->mregion || !mmap->cookie) {
+ WFD_MSG_ERR("Invalid argument\n");
+ return -EINVAL;
+ }
+
+ inst = mmap->cookie;
+ mregion = mmap->mregion;
+
+ domain = msm_fb_get_iommu_domain();
+ ion_unmap_iommu(mmap->ion_client,
+ mregion->ion_handle,
+ domain, 0);
+ return 0;
+}
+
long mdp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
int rc = 0;
@@ -208,6 +271,12 @@
case MDP_CLOSE:
rc = mdp_close(sd, arg);
break;
+ case MDP_MMAP:
+ rc = mdp_mmap(sd, arg);
+ break;
+ case MDP_MUNMAP:
+ rc = mdp_munmap(sd, arg);
+ break;
default:
WFD_MSG_ERR("IOCTL: %u not supported\n", cmd);
rc = -EINVAL;
diff --git a/drivers/media/video/msm_wfd/mdp-dummy-subdev.c b/drivers/media/video/msm_wfd/mdp-dummy-subdev.c
new file mode 100644
index 0000000..b2db208
--- /dev/null
+++ b/drivers/media/video/msm_wfd/mdp-dummy-subdev.c
@@ -0,0 +1,187 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 and
+* only version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+*/
+#include <linux/list.h>
+#include <linux/msm_mdp.h>
+#include <media/videobuf2-core.h>
+
+#include "enc-subdev.h"
+#include "mdp-subdev.h"
+#include "wfd-util.h"
+
+struct mdp_buf_queue {
+ struct mdp_buf_info mdp_buf_info;
+ struct list_head node;
+};
+
+struct mdp_instance {
+ struct mdp_buf_queue mdp_bufs;
+ struct mutex mutex;
+};
+
+int mdp_init(struct v4l2_subdev *sd, u32 val)
+{
+ return 0;
+}
+int mdp_open(struct v4l2_subdev *sd, void *arg)
+{
+ struct mdp_instance *inst = kzalloc(sizeof(struct mdp_instance),
+ GFP_KERNEL);
+ void **cookie = (void **)arg;
+ int rc = 0;
+
+ if (!inst) {
+ WFD_MSG_ERR("Out of memory\n");
+ return -ENOMEM;
+ }
+
+ INIT_LIST_HEAD(&inst->mdp_bufs.node);
+ mutex_init(&inst->mutex);
+ *cookie = inst;
+ return rc;
+}
+
+int mdp_start(struct v4l2_subdev *sd, void *arg)
+{
+ return 0;
+}
+int mdp_stop(struct v4l2_subdev *sd, void *arg)
+{
+ return 0;
+}
+int mdp_close(struct v4l2_subdev *sd, void *arg)
+{
+ return 0;
+}
+int mdp_q_buffer(struct v4l2_subdev *sd, void *arg)
+{
+ static int foo;
+ int rc = 0;
+ struct mdp_buf_info *binfo = arg;
+ struct mdp_instance *inst = NULL;
+
+ if (!binfo || !binfo->inst || !binfo->cookie) {
+ WFD_MSG_ERR("Invalid argument\n");
+ return -EINVAL;
+ }
+
+
+ inst = binfo->inst;
+ if (binfo->kvaddr) {
+ struct mdp_buf_queue *new_entry = kzalloc(sizeof(*new_entry),
+ GFP_KERNEL);
+ memset((void *)binfo->kvaddr, foo++, 1024);
+ new_entry->mdp_buf_info = *binfo;
+ mutex_lock(&inst->mutex);
+ list_add_tail(&new_entry->node, &inst->mdp_bufs.node);
+ mutex_unlock(&inst->mutex);
+ WFD_MSG_DBG("Queue %p with cookie %p\n",
+ (void *)binfo->paddr, (void *)binfo->cookie);
+ } else {
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+int mdp_dq_buffer(struct v4l2_subdev *sd, void *arg)
+{
+ struct mdp_buf_info *binfo = arg;
+ struct mdp_buf_queue *head = NULL;
+ struct mdp_instance *inst = NULL;
+
+ inst = binfo->inst;
+
+ while (head == NULL) {
+ mutex_lock(&inst->mutex);
+ if (!list_empty(&inst->mdp_bufs.node))
+ head = list_first_entry(&inst->mdp_bufs.node,
+ struct mdp_buf_queue, node);
+ mutex_unlock(&inst->mutex);
+ }
+
+ if (head == NULL)
+ return -ENOBUFS;
+
+ mutex_lock(&inst->mutex);
+ list_del(&head->node);
+ mutex_unlock(&inst->mutex);
+
+ *binfo = head->mdp_buf_info;
+ WFD_MSG_DBG("Dequeue %p with cookie %p\n",
+ (void *)binfo->paddr, (void *)binfo->cookie);
+ return 0;
+
+}
+int mdp_set_prop(struct v4l2_subdev *sd, void *arg)
+{
+ return 0;
+}
+
+int mdp_mmap(struct v4l2_subdev *sd, void *arg)
+{
+ int rc = 0;
+ struct mem_region_map *mmap = arg;
+ struct mem_region *mregion;
+
+ mregion = mmap->mregion;
+ mregion->paddr = mregion->kvaddr;
+ return rc;
+}
+
+int mdp_munmap(struct v4l2_subdev *sd, void *arg)
+{
+ /* Whatever */
+ return 0;
+}
+
+long mdp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+ int rc = 0;
+ if (!sd) {
+ WFD_MSG_ERR("Invalid arguments\n");
+ return -EINVAL;
+ }
+ switch (cmd) {
+ case MDP_Q_BUFFER:
+ rc = mdp_q_buffer(sd, arg);
+ break;
+ case MDP_DQ_BUFFER:
+ rc = mdp_dq_buffer(sd, arg);
+ break;
+ case MDP_OPEN:
+ rc = mdp_open(sd, arg);
+ break;
+ case MDP_START:
+ rc = mdp_start(sd, arg);
+ break;
+ case MDP_STOP:
+ rc = mdp_stop(sd, arg);
+ break;
+ case MDP_SET_PROP:
+ rc = mdp_set_prop(sd, arg);
+ break;
+ case MDP_CLOSE:
+ rc = mdp_close(sd, arg);
+ break;
+ case MDP_MMAP:
+ rc = mdp_mmap(sd, arg);
+ break;
+ case MDP_MUNMAP:
+ rc = mdp_munmap(sd, arg);
+ break;
+ default:
+ WFD_MSG_ERR("IOCTL: %u not supported\n", cmd);
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
diff --git a/drivers/media/video/msm_wfd/mdp-subdev.h b/drivers/media/video/msm_wfd/mdp-subdev.h
index 081fead..5e81e3c 100644
--- a/drivers/media/video/msm_wfd/mdp-subdev.h
+++ b/drivers/media/video/msm_wfd/mdp-subdev.h
@@ -34,6 +34,12 @@
u32 width;
};
+struct mdp_msg_ops {
+ void *cookie;
+ bool secure;
+ bool iommu_split_domain;
+};
+
static inline bool mdp_buf_info_equals(struct mdp_buf_info *a,
struct mdp_buf_info *b)
{
@@ -51,6 +57,10 @@
#define MDP_CLOSE _IOR(MDP_MAGIC_IOCTL, 5, void *)
#define MDP_START _IOR(MDP_MAGIC_IOCTL, 6, void *)
#define MDP_STOP _IOR(MDP_MAGIC_IOCTL, 7, void *)
+#define MDP_MMAP _IOR(MDP_MAGIC_IOCTL, 8, struct mem_region_map *)
+#define MDP_MUNMAP _IOR(MDP_MAGIC_IOCTL, 9, struct mem_region_map *)
+
+
extern int mdp_init(struct v4l2_subdev *sd, u32 val);
extern long mdp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg);
diff --git a/drivers/media/video/msm_wfd/wfd-ioctl.c b/drivers/media/video/msm_wfd/wfd-ioctl.c
index 8981c1a..d3c5936 100644
--- a/drivers/media/video/msm_wfd/wfd-ioctl.c
+++ b/drivers/media/video/msm_wfd/wfd-ioctl.c
@@ -10,7 +10,6 @@
* GNU General Public License for more details.
*
*/
-
#include <linux/module.h>
#include <linux/types.h>
#include <linux/list.h>
@@ -40,8 +39,8 @@
#define WFD_NUM_DEVICES 2
#define WFD_DEVICE_NUMBER_BASE 38
#define WFD_DEVICE_SECURE (WFD_DEVICE_NUMBER_BASE + 1)
-#define DEFAULT_WFD_WIDTH 640
-#define DEFAULT_WFD_HEIGHT 480
+#define DEFAULT_WFD_WIDTH 1280
+#define DEFAULT_WFD_HEIGHT 720
#define VENC_INPUT_BUFFERS 4
struct wfd_device {
@@ -152,11 +151,10 @@
static int wfd_allocate_ion_buffer(struct ion_client *client,
bool secure, struct mem_region *mregion)
{
- struct ion_handle *handle;
- void *kvaddr = NULL, *phys_addr = NULL;
- unsigned long size;
+ struct ion_handle *handle = NULL;
+ void *kvaddr = NULL;
unsigned int alloc_regions = 0;
- int rc;
+ int rc = 0;
alloc_regions = ION_HEAP(ION_CP_MM_HEAP_ID);
alloc_regions |= secure ? ION_SECURE :
@@ -178,32 +176,7 @@
goto alloc_fail;
}
- if (secure) {
- WFD_MSG_INFO("%s: calling ion_phys", __func__);
- rc = ion_phys(client,
- handle,
- (unsigned long *)&phys_addr, (size_t *)&size);
- } else {
- WFD_MSG_INFO("%s: calling ion_map_iommu", __func__);
- rc = ion_map_iommu(client, handle,
- VIDEO_DOMAIN, VIDEO_MAIN_POOL, SZ_4K,
- 0, (unsigned long *)&phys_addr,
- &size, 0, 0);
- }
-
- if (rc || !phys_addr) {
- WFD_MSG_ERR(
- "Failed to get physical addr, rc = %d, phys_addr = 0x%p\n",
- rc, phys_addr);
- goto alloc_fail;
- } else if (size < mregion->size) {
- WFD_MSG_ERR("Failed to map enough memory\n");
- rc = -ENOMEM;
- goto alloc_fail;
- }
-
mregion->kvaddr = kvaddr;
- mregion->paddr = phys_addr;
mregion->ion_handle = handle;
return rc;
@@ -273,6 +246,7 @@
spin_unlock_irqrestore(&inst->inst_lock, flags);
for (i = 0; i < VENC_INPUT_BUFFERS; ++i) {
+ struct mem_region_map mmap_context = {0};
mpair = kzalloc(sizeof(*mpair), GFP_KERNEL);
enc_mregion = kzalloc(sizeof(*enc_mregion), GFP_KERNEL);
mdp_mregion = kzalloc(sizeof(*enc_mregion), GFP_KERNEL);
@@ -281,12 +255,20 @@
rc = wfd_allocate_ion_buffer(wfd_dev->ion_client,
wfd_dev->secure_device, enc_mregion);
if (rc) {
- WFD_MSG_ERR("Failed to allocate input memory."
- " This error causes memory leak!!!\n");
+ WFD_MSG_ERR("Failed to allocate input memory\n");
goto alloc_fail;
}
- WFD_MSG_DBG("NOTE: enc paddr = %p, kvaddr = %p\n",
+ mmap_context.mregion = enc_mregion;
+ mmap_context.ion_client = wfd_dev->ion_client;
+ rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
+ ENC_MMAP, &mmap_context);
+ if (rc || !enc_mregion->paddr) {
+ WFD_MSG_ERR("Failed to map input memory\n");
+ goto alloc_fail;
+ }
+
+ WFD_MSG_ERR("NOTE: enc paddr = %p, kvaddr = %p\n",
enc_mregion->paddr,
enc_mregion->kvaddr);
@@ -301,27 +283,12 @@
mdp_mregion->cookie = 0;
mdp_mregion->ion_handle = enc_mregion->ion_handle;
- if (wfd_dev->mdp_iommu_split_domain) {
- if (wfd_dev->secure_device) {
- rc = ion_phys(wfd_dev->ion_client,
- mdp_mregion->ion_handle,
- (unsigned long *)&mdp_mregion->paddr,
- (size_t *)&mdp_mregion->size);
- } else {
- rc = ion_map_iommu(wfd_dev->ion_client,
- mdp_mregion->ion_handle,
- DISPLAY_WRITE_DOMAIN, GEN_POOL, SZ_4K,
- 0, (unsigned long *)&mdp_mregion->paddr,
- (unsigned long *)&mdp_mregion->size,
- 0, 0);
- }
- } else {
- rc = ion_map_iommu(wfd_dev->ion_client,
- mdp_mregion->ion_handle,
- DISPLAY_READ_DOMAIN, GEN_POOL, SZ_4K,
- 0, (unsigned long *)&mdp_mregion->paddr,
- (unsigned long *)&mdp_mregion->size, 0, 0);
- }
+ memset(&mmap_context, 0, sizeof(mmap_context));
+ mmap_context.mregion = mdp_mregion;
+ mmap_context.ion_client = wfd_dev->ion_client;
+ mmap_context.cookie = inst->mdp_inst;
+ rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
+ MDP_MMAP, (void *)&mmap_context);
if (rc || !mdp_mregion->paddr) {
WFD_MSG_ERR(
@@ -401,24 +368,24 @@
"from encoder\n");
if (mpair->mdp->paddr) {
- if (wfd_dev->mdp_iommu_split_domain) {
- if (!wfd_dev->secure_device)
- ion_unmap_iommu(wfd_dev->
- ion_client,
- mpair->mdp->ion_handle,
- DISPLAY_WRITE_DOMAIN,
- GEN_POOL);
- } else {
- ion_unmap_iommu(wfd_dev->ion_client,
- mpair->mdp->ion_handle,
- DISPLAY_READ_DOMAIN, GEN_POOL);
- }
+ struct mem_region_map temp = {0};
+
+ temp.ion_client = wfd_dev->ion_client;
+ temp.mregion = mpair->mdp;
+ temp.cookie = inst->mdp_inst;
+
+ v4l2_subdev_call(&wfd_dev->mdp_sdev, core,
+ ioctl, MDP_MUNMAP,
+ (void *)&temp);
}
- if (mpair->enc->paddr && !wfd_dev->secure_device)
- ion_unmap_iommu(wfd_dev->ion_client,
- mpair->enc->ion_handle,
- VIDEO_DOMAIN, VIDEO_MAIN_POOL);
+ if (mpair->enc->paddr) {
+ struct mem_region_map temp = {0};
+ temp.ion_client = wfd_dev->ion_client;
+ temp.mregion = mpair->enc;
+ v4l2_subdev_call(&wfd_dev->enc_sdev,
+ core, ioctl, ENC_MUNMAP, &temp);
+ }
wfd_free_ion_buffer(wfd_dev->ion_client, mpair->enc);
list_del(&mpair->list);
@@ -884,7 +851,7 @@
list_add_tail(&minfo_entry->list, &inst->minfo_list);
spin_unlock_irqrestore(&inst->inst_lock, flags);
} else
- WFD_MSG_INFO("Buffer already registered\n");
+ WFD_MSG_DBG("Buffer already registered\n");
return 0;
}
@@ -970,7 +937,7 @@
struct wfd_inst *inst = filp->private_data;
int rc;
- WFD_MSG_INFO("Waiting to dequeue buffer\n");
+ WFD_MSG_DBG("Waiting to dequeue buffer\n");
rc = vb2_dqbuf(&inst->vid_bufq, b, 0);
if (rc)
@@ -1306,6 +1273,7 @@
struct wfd_inst *inst = NULL;
struct wfd_device *wfd_dev = NULL;
struct venc_msg_ops enc_mops;
+ struct mdp_msg_ops mdp_mops;
struct vsg_msg_ops vsg_mops;
WFD_MSG_DBG("wfd_open: E\n");
@@ -1339,12 +1307,15 @@
wfd_stats_init(&inst->stats, MINOR(filp->f_dentry->d_inode->i_rdev));
+ mdp_mops.secure = wfd_dev->secure_device;
+ mdp_mops.iommu_split_domain = wfd_dev->mdp_iommu_split_domain;
rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl, MDP_OPEN,
- (void *)&inst->mdp_inst);
+ (void *)&mdp_mops);
if (rc) {
WFD_MSG_ERR("Failed to open mdp subdevice: %d\n", rc);
goto err_mdp_open;
}
+ inst->mdp_inst = mdp_mops.cookie;
rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, load_fw);
if (rc) {
@@ -1625,12 +1596,21 @@
kfree(wfd_dev);
return 0;
}
+
+static const struct of_device_id msm_wfd_dt_match[] = {
+ {.compatible = "qcom,msm-wfd"},
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, msm_vidc_dt_match);
+
static struct platform_driver wfd_driver = {
.probe = __wfd_probe,
.remove = __wfd_remove,
.driver = {
.name = "msm_wfd",
.owner = THIS_MODULE,
+ .of_match_table = msm_wfd_dt_match,
}
};
diff --git a/drivers/media/video/msm_wfd/wfd-util.h b/drivers/media/video/msm_wfd/wfd-util.h
index b6bb245..2fe7360 100644
--- a/drivers/media/video/msm_wfd/wfd-util.h
+++ b/drivers/media/video/msm_wfd/wfd-util.h
@@ -21,16 +21,11 @@
/*#define DEBUG_WFD*/
#define WFD_TAG "wfd: "
-#ifdef DEBUG_WFD
- #define WFD_MSG_INFO(fmt...) pr_info(WFD_TAG fmt)
- #define WFD_MSG_WARN(fmt...) pr_warning(WFD_TAG fmt)
-#else
- #define WFD_MSG_INFO(fmt...)
- #define WFD_MSG_WARN(fmt...)
-#endif
- #define WFD_MSG_ERR(fmt...) pr_err(KERN_ERR WFD_TAG fmt)
- #define WFD_MSG_CRIT(fmt...) pr_crit(KERN_CRIT WFD_TAG fmt)
- #define WFD_MSG_DBG(fmt...) pr_debug(WFD_TAG fmt)
+#define WFD_MSG_INFO(fmt...) pr_info(WFD_TAG fmt)
+#define WFD_MSG_WARN(fmt...) pr_warning(WFD_TAG fmt)
+#define WFD_MSG_ERR(fmt...) pr_err(KERN_ERR WFD_TAG fmt)
+#define WFD_MSG_CRIT(fmt...) pr_crit(KERN_CRIT WFD_TAG fmt)
+#define WFD_MSG_DBG(fmt...) pr_debug(WFD_TAG fmt)
struct wfd_stats_encode_sample {
diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c
index 7da4657..47b36ae 100644
--- a/drivers/media/video/v4l2-ctrls.c
+++ b/drivers/media/video/v4l2-ctrls.c
@@ -577,6 +577,8 @@
case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: return "MPEG4 Level";
case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: return "MPEG4 Profile";
case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL: return "Quarter Pixel Search Enable";
+ case V4L2_CID_QCOM_VIDEO_SYNC_FRAME_SEQ_HDR:
+ return "CodecConfig with sync frame";
case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES: return "Maximum Bytes in a Slice";
case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB: return "Number of MBs in a Slice";
case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: return "Slice Partitioning Method";
@@ -795,6 +797,11 @@
*type = V4L2_CTRL_TYPE_INTEGER64;
*flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE;
break;
+ case V4L2_CID_QCOM_VIDEO_SYNC_FRAME_SEQ_HDR:
+ *type = V4L2_CTRL_TYPE_BOOLEAN;
+ *min = 0;
+ *max = *step = 1;
+ break;
default:
*type = V4L2_CTRL_TYPE_INTEGER;
break;
diff --git a/drivers/media/video/vcap_v4l2.c b/drivers/media/video/vcap_v4l2.c
index 48532e5..e6cbae3 100644
--- a/drivers/media/video/vcap_v4l2.c
+++ b/drivers/media/video/vcap_v4l2.c
@@ -257,6 +257,8 @@
rc = config_gpios(1, dev->vcap_pdata);
if (rc < 0)
goto gpio_failed;
+ writel_relaxed(0x00030003, VCAP_OFFSET(0xD78));
+ writel_relaxed(0x00030003, VCAP_OFFSET(0xD7C));
return 0;
gpio_failed:
@@ -341,6 +343,7 @@
}
vb->v4l2_buf.timestamp = b->timestamp;
+ vb->v4l2_buf.field = b->field;
list_add_tail(&vb->queued_entry, &q->queued_list);
vb->state = VB2_BUF_STATE_QUEUED;
diff --git a/drivers/media/video/vcap_vc.c b/drivers/media/video/vcap_vc.c
index 5ae362f..572c272 100644
--- a/drivers/media/video/vcap_vc.c
+++ b/drivers/media/video/vcap_vc.c
@@ -205,6 +205,10 @@
done_count++;
}
+ /* Assign field value in case somehow got out of sync */
+ if (c_data->vc_format.mode == HAL_VCAP_MODE_INT && done_count == 1)
+ c_data->vc_action.top_field = !(irq & 0x1);
+
/* Double check expected buffers are done */
buf_num = c_data->vc_action.buf_num;
tot = c_data->vc_action.tot_buf;
@@ -248,6 +252,8 @@
v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
VCAP_VC_BUF_OVERWRITE_EVENT;
v4l2_event_queue(dev->vfd, &v4l2_evt);
+ c_data->vc_action.top_field =
+ !c_data->vc_action.top_field;
continue;
}
buf = list_entry(c_data->vc_action.active.next,
@@ -261,6 +267,14 @@
c_data->vc_action.vc_ts,
1000000 / c_data->vc_format.frame_rate *
(done_count - 1 - i));
+ if (c_data->vc_format.mode == HAL_VCAP_MODE_INT) {
+ if (c_data->vc_action.top_field)
+ vb->v4l2_buf.field = V4L2_FIELD_TOP;
+ else
+ vb->v4l2_buf.field = V4L2_FIELD_BOTTOM;
+ c_data->vc_action.top_field =
+ !c_data->vc_action.top_field;
+ }
vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
work_todo = true;
c_data->vc_action.buf[idx] = buf;
diff --git a/drivers/media/video/vcap_vp.c b/drivers/media/video/vcap_vp.c
index c81206f..4c3ff16 100644
--- a/drivers/media/video/vcap_vp.c
+++ b/drivers/media/video/vcap_vp.c
@@ -200,9 +200,7 @@
unsigned long flags = 0;
uint32_t irq;
int rc;
-#ifndef TOP_FIELD_FIX
- bool top_field;
-#endif
+ bool top_field = 0;
if (vp_work && vp_work->cd && vp_work->cd->dev)
dev = vp_work->cd->dev;
@@ -242,9 +240,6 @@
/* Cycle to next state */
if (vp_act->vp_state != VP_NORMAL)
vp_act->vp_state++;
-#ifdef TOP_FIELD_FIX
- vp_act->top_field = !vp_act->top_field;
-#endif
/* Cycle Buffers*/
if (dev->nr_param.mode) {
@@ -277,18 +272,11 @@
}
/* Config VP */
-#ifndef TOP_FIELD_FIX
if (vp_act->bufT2->vb.v4l2_buf.field == V4L2_FIELD_TOP)
top_field = 1;
-#endif
-#ifdef TOP_FIELD_FIX
- writel_iowmb(0x00000000 | vp_act->top_field << 0, VCAP_VP_CTRL);
- writel_iowmb(0x00010000 | vp_act->top_field << 0, VCAP_VP_CTRL);
-#else
writel_iowmb(0x00000000 | top_field, VCAP_VP_CTRL);
writel_iowmb(0x00010000 | top_field, VCAP_VP_CTRL);
-#endif
enable_irq(dev->vpirq->start);
writel_iowmb(irq, VCAP_VP_INT_CLEAR);
}
@@ -746,9 +734,7 @@
unsigned long flags = 0;
unsigned int chroma_fmt = 0;
int size;
-#ifndef TOP_FIELD_FIX
- bool top_field;
-#endif
+ bool top_field = 0;
if (!c_data->streaming)
return -ENOEXEC;
@@ -821,21 +807,12 @@
chroma_fmt << 11 | 0x1 << 4, VCAP_VP_OUT_CONFIG);
/* Enable Interrupt */
-#ifdef TOP_FIELD_FIX
- vp_act->top_field = 1;
-#else
if (vp_act->bufT2->vb.v4l2_buf.field == V4L2_FIELD_TOP)
top_field = 1;
-#endif
vp_act->vp_state = VP_FRAME2;
writel_relaxed(0x01100001, VCAP_VP_INTERRUPT_ENABLE);
-#ifdef TOP_FIELD_FIX
- writel_iowmb(0x00000000 | vp_act->top_field << 0, VCAP_VP_CTRL);
- writel_iowmb(0x00010000 | vp_act->top_field << 0, VCAP_VP_CTRL);
-#else
writel_iowmb(0x00000000 | top_field, VCAP_VP_CTRL);
writel_iowmb(0x00010000 | top_field, VCAP_VP_CTRL);
-#endif
atomic_set(&c_data->dev->vp_enabled, 1);
enable_irq(dev->vpirq->start);
return 0;
@@ -846,9 +823,7 @@
struct vcap_dev *dev;
struct vp_action *vp_act;
int rc;
-#ifndef TOP_FIELD_FIX
- bool top_field;
-#endif
+ bool top_field = 0;
dprintk(2, "Start Continue\n");
dev = c_data->dev;
@@ -869,20 +844,13 @@
if (rc < 0)
return rc;
-#ifndef TOP_FIELD_FIX
if (vp_act->bufT2->vb.v4l2_buf.field == V4L2_FIELD_TOP)
top_field = 1;
-#endif
/* Config VP & Enable Interrupt */
writel_relaxed(0x01100001, VCAP_VP_INTERRUPT_ENABLE);
-#ifdef TOP_FIELD_FIX
- writel_iowmb(0x00000000 | vp_act->top_field << 0, VCAP_VP_CTRL);
- writel_iowmb(0x00010000 | vp_act->top_field << 0, VCAP_VP_CTRL);
-#else
writel_iowmb(0x00000000 | top_field, VCAP_VP_CTRL);
writel_iowmb(0x00010000 | top_field, VCAP_VP_CTRL);
-#endif
atomic_set(&c_data->dev->vp_enabled, 1);
enable_irq(dev->vpirq->start);
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index c785a7e..8b9d08b 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -1793,13 +1793,6 @@
type = rq_data_dir(req) == READ ? MMC_BLK_READ : MMC_BLK_WRITE;
mmc_queue_bounce_post(mq_rq);
- /*
- * Check BKOPS urgency from each R1 response
- */
- if (mmc_card_mmc(card) &&
- (brq->cmd.resp[0] & R1_EXCEPTION_EVENT))
- mmc_card_set_check_bkops(card);
-
switch (status) {
case MMC_BLK_SUCCESS:
case MMC_BLK_PARTIAL:
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index ebcf7ed..e1e4408 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -74,9 +74,6 @@
spin_unlock_irq(q->queue_lock);
if (req || mq->mqrq_prev->req) {
- if (mmc_card_doing_bkops(mq->card))
- mmc_interrupt_bkops(mq->card);
-
set_current_state(TASK_RUNNING);
mq->issue_fn(mq, req);
} else {
@@ -84,8 +81,6 @@
set_current_state(TASK_RUNNING);
break;
}
-
- mmc_start_bkops(mq->card);
up(&mq->thread_sem);
schedule();
down(&mq->thread_sem);
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index e4d0fc1..9b316bb 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -28,6 +28,7 @@
#include <linux/random.h>
#include <linux/wakelock.h>
#include <linux/pm.h>
+#include <linux/slab.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
@@ -44,10 +45,10 @@
#include "sdio_ops.h"
/*
- * The Background operations can take a long time, depends on the house keeping
- * operations the card has to perform
+ * Background operations can take a long time, depending on the housekeeping
+ * operations the card has to perform.
*/
-#define MMC_BKOPS_MAX_TIMEOUT (4 * 60 * 1000) /* max time to wait in ms */
+#define MMC_BKOPS_MAX_TIMEOUT (4 * 60 * 1000) /* max time to wait in ms */
static struct workqueue_struct *workqueue;
@@ -281,66 +282,62 @@
/**
* mmc_start_bkops - start BKOPS for supported cards
* @card: MMC card to start BKOPS
+ * @form_exception: A flag to indicate if this function was
+ * called due to an exception raised by the card
*
* Start background operations whenever requested.
- * when the urgent BKOPS bit is set in a R1 command response
+ * When the urgent BKOPS bit is set in a R1 command response
* then background operations should be started immediately.
*/
-void mmc_start_bkops(struct mmc_card *card)
+void mmc_start_bkops(struct mmc_card *card, bool from_exception)
{
int err;
- unsigned long flags;
int timeout;
+ bool use_busy_signal;
BUG_ON(!card);
- if (!card->ext_csd.bkops_en || !(card->host->caps2 & MMC_CAP2_BKOPS))
+
+ if (!card->ext_csd.bkops_en || mmc_card_doing_bkops(card))
return;
- if (mmc_card_check_bkops(card)) {
- spin_lock_irqsave(&card->host->lock, flags);
- mmc_card_clr_check_bkops(card);
- spin_unlock_irqrestore(&card->host->lock, flags);
- if (mmc_is_exception_event(card, EXT_CSD_URGENT_BKOPS))
- if (card->ext_csd.raw_bkops_status)
- mmc_card_set_need_bkops(card);
+ err = mmc_read_bkops_status(card);
+ if (err) {
+ pr_err("%s: Failed to read bkops status: %d\n",
+ mmc_hostname(card->host), err);
+ return;
}
- /*
- * If card is already doing bkops or need for
- * bkops flag is not set, then do nothing just
- * return
- */
- if (mmc_card_doing_bkops(card) || !mmc_card_need_bkops(card))
+ if (!card->ext_csd.raw_bkops_status)
+ return;
+
+ if (card->ext_csd.raw_bkops_status < EXT_CSD_BKOPS_LEVEL_2 &&
+ from_exception)
return;
mmc_claim_host(card->host);
-
- timeout = (card->ext_csd.raw_bkops_status >= EXT_CSD_BKOPS_LEVEL_2) ?
- MMC_BKOPS_MAX_TIMEOUT : 0;
-
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_BKOPS_START, 1, timeout);
- if (err) {
- pr_warning("%s: error %d starting bkops\n",
- mmc_hostname(card->host), err);
- mmc_card_clr_need_bkops(card);
- goto out;
+ if (card->ext_csd.raw_bkops_status >= EXT_CSD_BKOPS_LEVEL_2) {
+ timeout = MMC_BKOPS_MAX_TIMEOUT;
+ use_busy_signal = true;
+ } else {
+ timeout = 0;
+ use_busy_signal = false;
}
- spin_lock_irqsave(&card->host->lock, flags);
- mmc_card_clr_need_bkops(card);
+ err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_BKOPS_START, 1, timeout, use_busy_signal);
+ if (err) {
+ pr_warn("%s: Error %d starting bkops\n",
+ mmc_hostname(card->host), err);
+ goto out;
+ }
/*
* For urgent bkops status (LEVEL_2 and more)
* bkops executed synchronously, otherwise
* the operation is in progress
*/
- if (card->ext_csd.raw_bkops_status >= EXT_CSD_BKOPS_LEVEL_2)
- mmc_card_set_check_bkops(card);
- else
+ if (!use_busy_signal)
mmc_card_set_doing_bkops(card);
-
- spin_unlock_irqrestore(&card->host->lock, flags);
out:
mmc_release_host(card->host);
}
@@ -455,6 +452,14 @@
if (host->areq) {
mmc_wait_for_req_done(host, host->areq->mrq);
err = host->areq->err_check(host->card, host->areq);
+ /*
+ * Check BKOPS urgency for each R1 response
+ */
+ if (host->card && mmc_card_mmc(host->card) &&
+ ((mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1) ||
+ (mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1B)) &&
+ (host->areq->mrq->cmd->resp[0] & R1_EXCEPTION_EVENT))
+ mmc_start_bkops(host->card, true);
}
if (!err && areq)
@@ -499,7 +504,7 @@
* @card: the MMC card associated with the HPI transfer
*
* Issued High Priority Interrupt, and check for card status
- * util out-of prg-state.
+ * until out-of prg-state.
*/
int mmc_interrupt_hpi(struct mmc_card *card)
{
@@ -581,68 +586,63 @@
EXPORT_SYMBOL(mmc_wait_for_cmd);
/**
- * mmc_interrupt_bkops - interrupt ongoing BKOPS
+ * mmc_stop_bkops - stop ongoing BKOPS
* @card: MMC card to check BKOPS
*
- * Send HPI command to interrupt ongoing background operations,
- * to allow rapid servicing of foreground operations,e.g. read/
+ * Send HPI command to stop ongoing background operations to
+ * allow rapid servicing of foreground operations, e.g. read/
* writes. Wait until the card comes out of the programming state
* to avoid errors in servicing read/write requests.
*/
-int mmc_interrupt_bkops(struct mmc_card *card)
+int mmc_stop_bkops(struct mmc_card *card)
{
int err = 0;
- unsigned long flags;
BUG_ON(!card);
-
err = mmc_interrupt_hpi(card);
- spin_lock_irqsave(&card->host->lock, flags);
- mmc_card_clr_doing_bkops(card);
- spin_unlock_irqrestore(&card->host->lock, flags);
+ /*
+ * If err is EINVAL, we can't issue an HPI.
+ * It should complete the BKOPS.
+ */
+ if (!err || (err == -EINVAL)) {
+ mmc_card_clr_doing_bkops(card);
+ err = 0;
+ }
return err;
}
-EXPORT_SYMBOL(mmc_interrupt_bkops);
+EXPORT_SYMBOL(mmc_stop_bkops);
int mmc_read_bkops_status(struct mmc_card *card)
{
int err;
- u8 ext_csd[512];
+ u8 *ext_csd;
+
+ /*
+ * In future work, we should consider storing the entire ext_csd.
+ */
+ ext_csd = kmalloc(512, GFP_KERNEL);
+ if (!ext_csd) {
+ pr_err("%s: could not allocate buffer to receive the ext_csd.\n",
+ mmc_hostname(card->host));
+ return -ENOMEM;
+ }
mmc_claim_host(card->host);
err = mmc_send_ext_csd(card, ext_csd);
mmc_release_host(card->host);
if (err)
- return err;
+ goto out;
card->ext_csd.raw_bkops_status = ext_csd[EXT_CSD_BKOPS_STATUS];
card->ext_csd.raw_exception_status = ext_csd[EXT_CSD_EXP_EVENTS_STATUS];
-
- return 0;
+out:
+ kfree(ext_csd);
+ return err;
}
EXPORT_SYMBOL(mmc_read_bkops_status);
-int mmc_is_exception_event(struct mmc_card *card, unsigned int value)
-{
- int err;
-
- err = mmc_read_bkops_status(card);
- if (err) {
- pr_err("%s: Didn't read bkops status : %d\n",
- mmc_hostname(card->host), err);
- return 0;
- }
-
- /* In eMMC 4.41, R1_EXCEPTION_EVENT is URGENT_BKOPS */
- if (card->ext_csd.rev == 5)
- return 1;
-
- return (card->ext_csd.raw_exception_status & value) ? 1 : 0;
-}
-EXPORT_SYMBOL(mmc_is_exception_event);
-
/**
* mmc_set_data_timeout - set the timeout for a data command
* @data: data phase for command
@@ -1297,7 +1297,7 @@
bit = fls(host->ocr_avail) - 1;
host->ios.vdd = bit;
- if (mmc_host_is_spi(host))
+ if (mmc_host_is_spi(host))
host->ios.chip_select = MMC_CS_HIGH;
else {
host->ios.chip_select = MMC_CS_DONTCARE;
@@ -1334,7 +1334,7 @@
host->ios.clock = 0;
host->ios.vdd = 0;
-
+
/*
* Reset ocr mask to be the highest possible voltage supported for
@@ -2508,9 +2508,11 @@
if (!err) {
if (host->bus_ops->suspend) {
- if (mmc_card_doing_bkops(host->card))
- mmc_interrupt_bkops(host->card);
-
+ if (mmc_card_doing_bkops(host->card)) {
+ err = mmc_stop_bkops(host->card);
+ if (err)
+ goto stop_bkops_err;
+ }
err = host->bus_ops->suspend(host);
}
if (!(host->card && mmc_card_sdio(host->card)))
@@ -2542,6 +2544,10 @@
out:
return err;
+stop_bkops_err:
+ if (!(host->card && mmc_card_sdio(host->card)))
+ mmc_release_host(host);
+ return err;
}
EXPORT_SYMBOL(mmc_suspend_host);
@@ -2604,11 +2610,21 @@
struct mmc_host *host = container_of(
notify_block, struct mmc_host, pm_notify);
unsigned long flags;
-
+ int err = 0;
switch (mode) {
case PM_HIBERNATION_PREPARE:
case PM_SUSPEND_PREPARE:
+ if (host->card && mmc_card_mmc(host->card) &&
+ mmc_card_doing_bkops(host->card)) {
+ err = mmc_stop_bkops(host->card);
+ if (err) {
+ pr_err("%s: didn't stop bkops\n",
+ mmc_hostname(host));
+ return err;
+ }
+ mmc_card_clr_doing_bkops(host->card);
+ }
spin_lock_irqsave(&host->lock, flags);
if (mmc_bus_needs_resume(host)) {
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index b1b8892..6343760 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -463,22 +463,15 @@
}
if (card->ext_csd.rev >= 5) {
- /* check whether the eMMC card support BKOPS */
+ /* check whether the eMMC card supports BKOPS */
if (ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) {
card->ext_csd.bkops = 1;
card->ext_csd.bkops_en = ext_csd[EXT_CSD_BKOPS_EN];
card->ext_csd.raw_bkops_status =
ext_csd[EXT_CSD_BKOPS_STATUS];
- if (!card->ext_csd.bkops_en &&
- card->host->caps2 & MMC_CAP2_INIT_BKOPS) {
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_BKOPS_EN, 1, 0);
- if (err)
- pr_warning("%s: Enabling BKOPS failed\n",
- mmc_hostname(card->host));
- else
- card->ext_csd.bkops_en = 1;
- }
+ if (!card->ext_csd.bkops_en)
+ pr_info("%s: BKOPS_EN bit is not set\n",
+ mmc_hostname(card->host));
}
/* check whether the eMMC card supports HPI */
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index d82c353..4f46ed1 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -368,18 +368,19 @@
}
/**
- * mmc_switch - modify EXT_CSD register
+ * __mmc_switch - modify EXT_CSD register
* @card: the MMC card associated with the data transfer
* @set: cmd set values
* @index: EXT_CSD register index
* @value: value to program into EXT_CSD register
* @timeout_ms: timeout (ms) for operation performed by register write,
* timeout of zero implies maximum possible timeout
+ * @use_busy_signal: use the busy signal as response type
*
* Modifies the EXT_CSD register for selected card.
*/
-int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
- unsigned int timeout_ms)
+int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
+ unsigned int timeout_ms, bool use_busy_signal)
{
int err;
struct mmc_command cmd = {0};
@@ -393,20 +394,21 @@
(index << 16) |
(value << 8) |
set;
- cmd.flags = MMC_CMD_AC;
- if (index == EXT_CSD_BKOPS_START &&
- card->ext_csd.raw_bkops_status < EXT_CSD_BKOPS_LEVEL_2)
- cmd.flags |= MMC_RSP_SPI_R1 | MMC_RSP_R1;
- else
+ cmd.flags = MMC_CMD_AC;
+ if (use_busy_signal)
cmd.flags |= MMC_RSP_SPI_R1B | MMC_RSP_R1B;
+ else
+ cmd.flags |= MMC_RSP_SPI_R1 | MMC_RSP_R1;
+
+
cmd.cmd_timeout_ms = timeout_ms;
err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
if (err)
return err;
- /* No need to check card status in case of BKOPS switch*/
- if (index == EXT_CSD_BKOPS_START)
+ /* No need to check card status in case of unblocking command */
+ if (!use_busy_signal)
return 0;
/* Must check status to be sure of no errors */
@@ -433,6 +435,13 @@
return 0;
}
+EXPORT_SYMBOL_GPL(__mmc_switch);
+
+int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
+ unsigned int timeout_ms)
+{
+ return __mmc_switch(card, set, index, value, timeout_ms, true);
+}
EXPORT_SYMBOL_GPL(mmc_switch);
int mmc_send_status(struct mmc_card *card, u32 *status)
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index b153b27..c4b41e1 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -1336,34 +1336,41 @@
msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
unsigned int status)
{
- if (status & MCI_DATACRCFAIL) {
- if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
- || data->mrq->cmd->opcode == MMC_BUS_TEST_R
- || data->mrq->cmd->opcode ==
- MMC_SEND_TUNING_BLOCK_HS200)) {
- pr_err("%s: Data CRC error\n",
- mmc_hostname(host->mmc));
- pr_err("%s: opcode 0x%.8x\n", __func__,
- data->mrq->cmd->opcode);
- pr_err("%s: blksz %d, blocks %d\n", __func__,
- data->blksz, data->blocks);
- data->error = -EILSEQ;
+ if ((status & MCI_DATACRCFAIL) || (status & MCI_DATATIMEOUT)) {
+ u32 opcode = data->mrq->cmd->opcode;
+
+ if (!((!host->tuning_in_progress && opcode == MMC_BUS_TEST_W)
+ || (opcode == MMC_BUS_TEST_R) ||
+ (host->tuning_in_progress &&
+ (opcode == MMC_SEND_TUNING_BLOCK_HS200 ||
+ opcode == MMC_SEND_TUNING_BLOCK)))) {
+ if (status & MCI_DATACRCFAIL) {
+ pr_err("%s: Data CRC error\n",
+ mmc_hostname(host->mmc));
+ pr_err("%s: opcode 0x%.8x\n", __func__, opcode);
+ pr_err("%s: blksz %d, blocks %d\n", __func__,
+ data->blksz, data->blocks);
+ } else {
+ pr_err("%s: CMD%d: Data timeout. DAT0 => %d\n",
+ mmc_hostname(host->mmc), opcode,
+ (readl_relaxed(host->base
+ + MCI_TEST_INPUT) & 0x2) ? 1 : 0);
+ msmsdcc_dump_sdcc_state(host);
+ }
}
- } else if (status & MCI_DATATIMEOUT) {
- /* CRC is optional for the bus test commands, not all
+
+ /*
+ * CRC is optional for the bus test commands, not all
* cards respond back with CRC. However controller
* waits for the CRC and times out. Hence ignore the
* data timeouts during the Bustest.
*/
- if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
- || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
- pr_err("%s: CMD%d: Data timeout. DAT0 => %d\n",
- mmc_hostname(host->mmc),
- data->mrq->cmd->opcode,
- (readl_relaxed(host->base
- + MCI_TEST_INPUT) & 0x2) ? 1 : 0);
- data->error = -ETIMEDOUT;
- msmsdcc_dump_sdcc_state(host);
+ if (!((!host->tuning_in_progress && opcode == MMC_BUS_TEST_W)
+ || (opcode == MMC_BUS_TEST_R))) {
+ if (status & MCI_DATACRCFAIL)
+ data->error = -EILSEQ;
+ else
+ data->error = -ETIMEDOUT;
}
} else if (status & MCI_RXOVERRUN) {
pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
@@ -5804,8 +5811,6 @@
mmc->caps |= MMC_CAP_NONREMOVABLE;
mmc->caps |= MMC_CAP_SDIO_IRQ;
- mmc->caps2 |= MMC_CAP2_INIT_BKOPS | MMC_CAP2_BKOPS;
-
if (plat->is_sdio_al_client)
mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
diff --git a/drivers/net/usb/rmnet_usb_ctrl.c b/drivers/net/usb/rmnet_usb_ctrl.c
index ba16ed9..7ed8ffa 100644
--- a/drivers/net/usb/rmnet_usb_ctrl.c
+++ b/drivers/net/usb/rmnet_usb_ctrl.c
@@ -122,6 +122,55 @@
return 0;
}
+static void get_encap_work(struct work_struct *w)
+{
+ struct usb_device *udev;
+ struct rmnet_ctrl_dev *dev =
+ container_of(w, struct rmnet_ctrl_dev, get_encap_work);
+ int status;
+
+ udev = interface_to_usbdev(dev->intf);
+
+ status = usb_autopm_get_interface(dev->intf);
+ if (status < 0 && status != -EAGAIN && status != -EACCES) {
+ dev->get_encap_failure_cnt++;
+ return;
+ }
+
+ usb_fill_control_urb(dev->rcvurb, udev,
+ usb_rcvctrlpipe(udev, 0),
+ (unsigned char *)dev->in_ctlreq,
+ dev->rcvbuf,
+ DEFAULT_READ_URB_LENGTH,
+ resp_avail_cb, dev);
+
+
+ usb_anchor_urb(dev->rcvurb, &dev->rx_submitted);
+ status = usb_submit_urb(dev->rcvurb, GFP_KERNEL);
+ if (status) {
+ dev->get_encap_failure_cnt++;
+ usb_unanchor_urb(dev->rcvurb);
+ usb_autopm_put_interface(dev->intf);
+ dev_err(dev->devicep,
+ "%s: Error submitting Read URB %d\n", __func__, status);
+ goto resubmit_int_urb;
+ }
+
+ return;
+
+resubmit_int_urb:
+ /*check if it is already submitted in resume*/
+ if (!dev->inturb->anchor) {
+ usb_anchor_urb(dev->inturb, &dev->rx_submitted);
+ status = usb_submit_urb(dev->inturb, GFP_KERNEL);
+ if (status) {
+ usb_unanchor_urb(dev->inturb);
+ dev_err(dev->devicep, "%s: Error re-submitting Int URB %d\n",
+ __func__, status);
+ }
+ }
+}
+
static void notification_available_cb(struct urb *urb)
{
int status;
@@ -133,12 +182,13 @@
switch (urb->status) {
case 0:
+ /*if non zero lenght of data received while unlink*/
+ case -ENOENT:
/*success*/
break;
/*do not resubmit*/
case -ESHUTDOWN:
- case -ENOENT:
case -ECONNRESET:
case -EPROTO:
return;
@@ -156,26 +206,17 @@
goto resubmit_int_urb;
}
+ if (!urb->actual_length)
+ return;
+
ctrl = urb->transfer_buffer;
switch (ctrl->bNotificationType) {
case USB_CDC_NOTIFY_RESPONSE_AVAILABLE:
dev->resp_avail_cnt++;
- usb_fill_control_urb(dev->rcvurb, udev,
- usb_rcvctrlpipe(udev, 0),
- (unsigned char *)dev->in_ctlreq,
- dev->rcvbuf,
- DEFAULT_READ_URB_LENGTH,
- resp_avail_cb, dev);
-
- status = usb_submit_urb(dev->rcvurb, GFP_ATOMIC);
- if (status) {
- dev_err(dev->devicep,
- "%s: Error submitting Read URB %d\n", __func__, status);
- goto resubmit_int_urb;
- }
usb_mark_last_busy(udev);
+ queue_work(dev->wq, &dev->get_encap_work);
if (!dev->resp_available) {
dev->resp_available = true;
@@ -189,10 +230,13 @@
}
resubmit_int_urb:
+ usb_anchor_urb(urb, &dev->rx_submitted);
status = usb_submit_urb(urb, GFP_ATOMIC);
- if (status)
+ if (status) {
+ usb_unanchor_urb(urb);
dev_err(dev->devicep, "%s: Error re-submitting Int URB %d\n",
__func__, status);
+ }
return;
}
@@ -208,6 +252,8 @@
udev = interface_to_usbdev(dev->intf);
+ usb_autopm_put_interface_async(dev->intf);
+
switch (urb->status) {
case 0:
/*success*/
@@ -263,41 +309,41 @@
wake_up(&dev->read_wait_queue);
resubmit_int_urb:
- /*re-submit int urb to check response available*/
- usb_mark_last_busy(udev);
- status = usb_submit_urb(dev->inturb, GFP_ATOMIC);
- if (status)
- dev_err(dev->devicep, "%s: Error re-submitting Int URB %d\n",
- __func__, status);
+ /*check if it is already submitted in resume*/
+ if (!dev->inturb->anchor) {
+ usb_mark_last_busy(udev);
+ usb_anchor_urb(dev->inturb, &dev->rx_submitted);
+ status = usb_submit_urb(dev->inturb, GFP_ATOMIC);
+ if (status) {
+ usb_unanchor_urb(dev->inturb);
+ dev_err(dev->devicep, "%s: Error re-submitting Int URB %d\n",
+ __func__, status);
+ }
+ }
}
int rmnet_usb_ctrl_start_rx(struct rmnet_ctrl_dev *dev)
{
int retval = 0;
+ usb_anchor_urb(dev->inturb, &dev->rx_submitted);
retval = usb_submit_urb(dev->inturb, GFP_KERNEL);
- if (retval < 0)
- dev_err(dev->devicep, "%s Intr submit %d\n", __func__, retval);
+ if (retval < 0) {
+ usb_unanchor_urb(dev->inturb);
+ dev_err(dev->devicep, "%s Intr submit %d\n", __func__,
+ retval);
+ }
return retval;
}
-int rmnet_usb_ctrl_stop_rx(struct rmnet_ctrl_dev *dev)
+int rmnet_usb_ctrl_suspend(struct rmnet_ctrl_dev *dev)
{
- if (!is_dev_connected(dev)) {
- dev_dbg(dev->devicep, "%s: Ctrl device disconnected\n",
- __func__);
- return -ENODEV;
- }
-
- dev_dbg(dev->devicep, "%s\n", __func__);
-
- usb_kill_urb(dev->rcvurb);
- usb_kill_urb(dev->inturb);
+ if (!flush_work_sync(&dev->get_encap_work))
+ usb_kill_anchored_urbs(&dev->rx_submitted);
return 0;
}
-
static int rmnet_usb_ctrl_alloc_rx(struct rmnet_ctrl_dev *dev)
{
int retval = -ENOMEM;
@@ -826,7 +872,6 @@
void rmnet_usb_ctrl_disconnect(struct rmnet_ctrl_dev *dev)
{
- rmnet_usb_ctrl_stop_rx(dev);
mutex_lock(&dev->dev_lock);
@@ -839,13 +884,16 @@
wake_up(&dev->read_wait_queue);
+ cancel_work_sync(&dev->get_encap_work);
+
+ usb_kill_anchored_urbs(&dev->tx_submitted);
+ usb_kill_anchored_urbs(&dev->rx_submitted);
+
usb_free_urb(dev->inturb);
dev->inturb = NULL;
kfree(dev->intbuf);
dev->intbuf = NULL;
-
- usb_kill_anchored_urbs(&dev->tx_submitted);
}
#if defined(CONFIG_DEBUG_FS)
@@ -879,6 +927,7 @@
"cbits_tomdm: %d\n"
"mdm_wait_timeout: %u\n"
"zlp_cnt: %u\n"
+ "get_encap_failure_cnt %u\n"
"dev opened: %s\n",
dev, dev->name,
dev->snd_encap_cmd_cnt,
@@ -890,6 +939,7 @@
dev->cbits_tomdm,
dev->mdm_wait_timeout,
dev->zlp_cnt,
+ dev->get_encap_failure_cnt,
dev->is_opened ? "OPEN" : "CLOSE");
}
@@ -968,12 +1018,21 @@
/*for debug purpose*/
snprintf(dev->name, CTRL_DEV_MAX_LEN, "hsicctl%d", n);
+ dev->wq = create_singlethread_workqueue(dev->name);
+ if (!dev->wq) {
+ pr_err("unable to allocate workqueue");
+ kfree(dev);
+ goto error0;
+ }
+
mutex_init(&dev->dev_lock);
spin_lock_init(&dev->rx_lock);
init_waitqueue_head(&dev->read_wait_queue);
init_waitqueue_head(&dev->open_wait_queue);
INIT_LIST_HEAD(&dev->rx_list);
init_usb_anchor(&dev->tx_submitted);
+ init_usb_anchor(&dev->rx_submitted);
+ INIT_WORK(&dev->get_encap_work, get_encap_work);
status = rmnet_usb_ctrl_alloc_rx(dev);
if (status < 0) {
@@ -1074,6 +1133,7 @@
device_remove_file(ctrl_dev[i]->devicep, &dev_attr_modem_wait);
#endif
cdev_del(&ctrl_dev[i]->cdev);
+ destroy_workqueue(ctrl_dev[i]->wq);
kfree(ctrl_dev[i]);
ctrl_dev[i] = NULL;
device_destroy(ctrldev_classp, MKDEV(MAJOR(ctrldev_num), i));
diff --git a/drivers/net/usb/rmnet_usb_ctrl.h b/drivers/net/usb/rmnet_usb_ctrl.h
index 7a84817..a8f8079 100644
--- a/drivers/net/usb/rmnet_usb_ctrl.h
+++ b/drivers/net/usb/rmnet_usb_ctrl.h
@@ -34,6 +34,7 @@
struct urb *rcvurb;
struct urb *inturb;
struct usb_anchor tx_submitted;
+ struct usb_anchor rx_submitted;
void *rcvbuf;
void *intbuf;
struct usb_ctrlrequest *in_ctlreq;
@@ -44,6 +45,9 @@
wait_queue_head_t read_wait_queue;
wait_queue_head_t open_wait_queue;
+ struct workqueue_struct *wq;
+ struct work_struct get_encap_work;
+
unsigned is_opened;
bool is_connected;
@@ -66,6 +70,7 @@
unsigned int snd_encap_cmd_cnt;
unsigned int get_encap_resp_cnt;
unsigned int resp_avail_cnt;
+ unsigned int get_encap_failure_cnt;
unsigned int set_ctrl_line_state_cnt;
unsigned int tx_ctrl_err_cnt;
unsigned int zlp_cnt;
@@ -74,7 +79,7 @@
extern struct rmnet_ctrl_dev *ctrl_dev[];
extern int rmnet_usb_ctrl_start_rx(struct rmnet_ctrl_dev *);
-extern int rmnet_usb_ctrl_stop_rx(struct rmnet_ctrl_dev *);
+extern int rmnet_usb_ctrl_suspend(struct rmnet_ctrl_dev *dev);
extern int rmnet_usb_ctrl_init(void);
extern void rmnet_usb_ctrl_exit(void);
extern int rmnet_usb_ctrl_probe(struct usb_interface *intf,
diff --git a/drivers/net/usb/rmnet_usb_data.c b/drivers/net/usb/rmnet_usb_data.c
index b8c6140..17ff067 100644
--- a/drivers/net/usb/rmnet_usb_data.c
+++ b/drivers/net/usb/rmnet_usb_data.c
@@ -87,7 +87,6 @@
{
struct usbnet *unet;
struct rmnet_ctrl_dev *dev;
- int time = 0;
int retval = 0;
unet = usb_get_intfdata(iface);
@@ -107,19 +106,12 @@
retval = usbnet_suspend(iface, message);
if (!retval) {
- if (message.event & PM_EVENT_SUSPEND) {
- time = usb_wait_anchor_empty_timeout(&dev->tx_submitted,
- 1000);
- if (!time)
- usb_kill_anchored_urbs(&dev->tx_submitted);
-
- retval = rmnet_usb_ctrl_stop_rx(dev);
- iface->dev.power.power_state.event = message.event;
- }
- /* TBD : do we need to set/clear usbnet->udev->reset_resume*/
- } else
+ retval = rmnet_usb_ctrl_suspend(dev);
+ iface->dev.power.power_state.event = message.event;
+ } else {
dev_dbg(&iface->dev,
"%s: device is busy can not suspend\n", __func__);
+ }
fail:
return retval;
diff --git a/drivers/platform/msm/sps/bam.c b/drivers/platform/msm/sps/bam.c
index eb9e8ee..bcb4cdb 100644
--- a/drivers/platform/msm/sps/bam.c
+++ b/drivers/platform/msm/sps/bam.c
@@ -679,7 +679,7 @@
bam_write_reg_field(base, CTRL, BAM_EN, 1);
#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
- bam_write_reg_field(base, CTRL, CACHE_MISS_ERR_RESP_EN, 1);
+ bam_write_reg_field(base, CTRL, CACHE_MISS_ERR_RESP_EN, 0);
bam_write_reg_field(base, CTRL, LOCAL_CLK_GATING, 1);
#endif
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index d8baa29..2542845 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -442,4 +442,13 @@
help
Say Y to enable battery temperature measurements using
thermistor connected on BATCTRL ADC.
+
+config QPNP_BMS
+ tristate "QPNP Battery Monitoring System driver"
+ depends on SPMI
+ depends on MSM_QPNP_INT
+ help
+ Say Y here to enable support for QPNP chip bms device.
+ It registers a fuelgauge bms power supply to report
+ State of Charge.
endif # POWER_SUPPLY
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index f84b527..9dc1960 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -55,6 +55,7 @@
obj-$(CONFIG_SMB137B_CHARGER) += smb137b.o
obj-$(CONFIG_PM8XXX_CCADC) += pm8xxx-ccadc.o
obj-$(CONFIG_PM8921_BMS) += pm8921-bms.o
+obj-$(CONFIG_QPNP_BMS) += qpnp-bms.o
obj-$(CONFIG_PM8921_CHARGER) += pm8921-charger.o
obj-$(CONFIG_LTC4088_CHARGER) += ltc4088-charger.o
obj-$(CONFIG_CHARGER_SMB347) += smb347-charger.o
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index b3d31d5..c63c99f 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -3248,7 +3248,10 @@
check_initial_ocv(chip);
/* start periodic hkadc calibration */
- schedule_delayed_work(&chip->calib_hkadc_delayed_work, 0);
+ calib_hkadc(chip);
+ schedule_delayed_work(&chip->calib_hkadc_delayed_work,
+ round_jiffies_relative(msecs_to_jiffies
+ (HKADC_CALIB_DELAY_MS)));
/* enable the vbatt reading interrupts for scheduling hkadc calib */
pm8921_bms_enable_irq(chip, PM8921_BMS_GOOD_OCV);
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index 28b641d..e4e0004 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -1852,6 +1852,9 @@
}
if (disable)
pr_warn("current drawn from chg=0, battery provides current\n");
+
+ pm_chg_usb_suspend_enable(the_chip, disable);
+
return pm_chg_charge_dis(the_chip, disable);
}
EXPORT_SYMBOL(pm8921_disable_source_current);
@@ -2495,11 +2498,6 @@
pr_debug("USB charger active\n");
pm_chg_iusbmax_get(chip, &usb_ma);
- if (usb_ma == 500 && !usb_target_ma) {
- pr_debug("Stopping Unplug Check Worker USB == 500mA\n");
- disable_input_voltage_regulation(chip);
- return;
- }
if (usb_ma <= 100) {
pr_debug(
@@ -3316,7 +3314,7 @@
chip->usb_present = !!is_usb_chg_plugged_in(chip);
notify_usb_of_the_plugin_event(chip->usb_present);
- if (chip->usb_present) {
+ if (chip->usb_present || chip->dc_present) {
schedule_delayed_work(&chip->unplug_check_work,
round_jiffies_relative(msecs_to_jiffies
(UNPLUG_CHECK_WAIT_PERIOD_MS)));
@@ -4150,6 +4148,7 @@
}
enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]);
+ enable_irq_wake(chip->pmic_chg_irq[DCIN_VALID_IRQ]);
enable_irq_wake(chip->pmic_chg_irq[USBIN_OV_IRQ]);
enable_irq_wake(chip->pmic_chg_irq[USBIN_UV_IRQ]);
enable_irq_wake(chip->pmic_chg_irq[BAT_TEMP_OK_IRQ]);
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
new file mode 100644
index 0000000..7b4d97e
--- /dev/null
+++ b/drivers/power/qpnp-bms.c
@@ -0,0 +1,353 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/power_supply.h>
+#include <linux/spmi.h>
+
+/* Interrupt offsets */
+#define INT_RT_STS(base) (base + 0x10)
+#define INT_SET_TYPE(base) (base + 0x11)
+#define INT_POLARITY_HIGH(base) (base + 0x12)
+#define INT_POLARITY_LOW(base) (base + 0x13)
+#define INT_LATCHED_CLR(base) (base + 0x14)
+#define INT_EN_SET(base) (base + 0x15)
+#define INT_EN_CLR(base) (base + 0x16)
+#define INT_LATCHED_STS(base) (base + 0x18)
+#define INT_PENDING_STS(base) (base + 0x19)
+#define INT_MID_SEL(base) (base + 0x1A)
+#define INT_PRIORITY(base) (base + 0x1B)
+
+/* BMS Register Offsets */
+#define BMS1_REVISION1 0x0
+#define BMS1_REVISION2 0x1
+#define BMS1_STATUS1 0x8
+#define BMS1_MODE_CTL 0X40
+/* Columb counter clear registers */
+#define BMS1_CC_DATA_CTL 0x42
+#define BMS1_CC_CLEAR_CTRL 0x43
+/* OCV limit registers */
+#define BMS1_OCV_USE_LOW_LIMIT_THR0 0x48
+#define BMS1_OCV_USE_LOW_LIMIT_THR1 0x49
+#define BMS1_OCV_USE_HIGH_LIMIT_THR0 0x4A
+#define BMS1_OCV_USE_HIGH_LIMIT_THR1 0x4B
+#define BMS1_OCV_USE_LIMIT_CTL 0x4C
+/* CC interrupt threshold */
+#define BMS1_CC_THR0 0x7A
+#define BMS1_CC_THR1 0x7B
+#define BMS1_CC_THR2 0x7C
+#define BMS1_CC_THR3 0x7D
+#define BMS1_CC_THR4 0x7E
+/* OCV for r registers */
+#define BMS1_OCV_FOR_R_DATA0 0x80
+#define BMS1_OCV_FOR_R_DATA1 0x81
+#define BMS1_VSENSE_FOR_R_DATA0 0x82
+#define BMS1_VSENSE_FOR_R_DATA1 0x83
+/* Columb counter data */
+#define BMS1_CC_DATA0 0x8A
+#define BMS1_CC_DATA1 0x8B
+#define BMS1_CC_DATA2 0x8C
+#define BMS1_CC_DATA3 0x8D
+#define BMS1_CC_DATA4 0x8E
+/* OCV for soc data */
+#define BMS1_OCV_FOR_SOC_DATA0 0x90
+#define BMS1_OCV_FOR_SOC_DATA1 0x91
+#define BMS1_VSENSE_PON_DATA0 0x94
+#define BMS1_VSENSE_PON_DATA1 0x95
+#define BMS1_VBAT_AVG_DATA0 0x9E
+#define BMS1_VBAT_AVG_DATA1 0x9F
+/* Extra bms registers */
+#define BMS1_BMS_DATA_REG_0 0xB0
+#define BMS1_BMS_DATA_REG_1 0xB1
+#define BMS1_BMS_DATA_REG_2 0xB2
+#define BMS1_BMS_DATA_REG_3 0xB3
+
+#define QPNP_BMS_DEV_NAME "qcom,qpnp-bms"
+
+struct qpnp_bms_chip {
+ struct device *dev;
+ struct power_supply bms_psy;
+ struct spmi_device *spmi;
+ u16 base;
+
+ u8 revision1;
+ u8 revision2;
+ int charger_status;
+ bool online;
+ /* platform data */
+ unsigned int r_sense_mohm;
+ unsigned int v_cutoff;
+ unsigned int max_voltage;
+ unsigned int r_conn_mohm;
+ int shutdown_soc_valid_limit;
+ int adjust_soc_low_threshold;
+ int adjust_soc_high_threshold;
+ int chg_term;
+};
+
+static struct of_device_id qpnp_bms_match_table[] = {
+ { .compatible = QPNP_BMS_DEV_NAME },
+ {}
+};
+
+static char *qpnp_bms_supplicants[] = {
+ "battery"
+};
+
+static enum power_supply_property msm_bms_power_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+};
+
+static int qpnp_read_wrapper(struct qpnp_bms_chip *chip, u8 *val,
+ u16 base, int count)
+{
+ int rc;
+ struct spmi_device *spmi = chip->spmi;
+
+ rc = spmi_ext_register_readl(spmi->ctrl, spmi->sid, base, val, count);
+ if (rc)
+ pr_err("SPMI read failed rc=%d\n", rc);
+
+ return 0;
+}
+
+/* Returns capacity as a SoC percentage between 0 and 100 */
+static int get_prop_bms_capacity(struct qpnp_bms_chip *chip)
+{
+ /* return 50 until a real algorithm is implemented */
+ return 50;
+}
+
+/* Returns instantaneous current in uA */
+static int get_prop_bms_current_now(struct qpnp_bms_chip *chip)
+{
+ /* temporarily return 0 until a real algorithm is put in */
+ return 0;
+}
+
+/* Returns full charge design in uAh */
+static int get_prop_bms_charge_full_design(struct qpnp_bms_chip *chip)
+{
+ /* temporarily return 0 until a real algorithm is put in */
+ return 0;
+}
+
+static void set_prop_bms_online(struct qpnp_bms_chip *chip, bool online)
+{
+ chip->online = online;
+}
+
+static void set_prop_bms_status(struct qpnp_bms_chip *chip, int status)
+{
+ chip->charger_status = status;
+}
+
+static void qpnp_bms_external_power_changed(struct power_supply *psy)
+{
+}
+
+static int qpnp_bms_power_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct qpnp_bms_chip *chip = container_of(psy, struct qpnp_bms_chip,
+ bms_psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CAPACITY:
+ val->intval = get_prop_bms_capacity(chip);
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ val->intval = get_prop_bms_current_now(chip);
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+ val->intval = get_prop_bms_charge_full_design(chip);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int qpnp_bms_power_set_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ struct qpnp_bms_chip *chip = container_of(psy, struct qpnp_bms_chip,
+ bms_psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ set_prop_bms_online(chip, val->intval);
+ break;
+ case POWER_SUPPLY_PROP_STATUS:
+ set_prop_bms_status(chip, (bool)val->intval);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+#define SPMI_PROPERTY_READ(chip_prop, qpnp_spmi_property, retval, errlabel)\
+do { \
+ retval = of_property_read_u32(spmi->dev.of_node, \
+ "qcom,bms-" qpnp_spmi_property, \
+ &chip->chip_prop); \
+ if (retval) { \
+ pr_err("Error reading " #qpnp_spmi_property \
+ " property %d\n", rc); \
+ goto errlabel; \
+ } \
+} while (0)
+
+static int __devinit
+qpnp_bms_probe(struct spmi_device *spmi)
+{
+ struct qpnp_bms_chip *chip;
+ struct resource *bms_resource;
+ int rc;
+
+ chip = kzalloc(sizeof *chip, GFP_KERNEL);
+
+ if (chip == NULL) {
+ pr_err("kzalloc() failed.\n");
+ return -ENOMEM;
+ }
+
+ chip->dev = &(spmi->dev);
+ chip->spmi = spmi;
+
+ bms_resource = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
+ if (!bms_resource) {
+ dev_err(&spmi->dev, "Unable to get BMS base address\n");
+ return -ENXIO;
+ }
+ chip->base = bms_resource->start;
+
+ rc = qpnp_read_wrapper(chip, &chip->revision1,
+ chip->base + BMS1_REVISION1, 1);
+ if (rc) {
+ pr_err("error reading version register %d\n", rc);
+ goto error_read;
+ }
+
+ rc = qpnp_read_wrapper(chip, &chip->revision2,
+ chip->base + BMS1_REVISION2, 1);
+ if (rc) {
+ pr_err("Error reading version register %d\n", rc);
+ goto error_read;
+ }
+
+ SPMI_PROPERTY_READ(r_sense_mohm, "r-sense-mohm", rc, error_read);
+ SPMI_PROPERTY_READ(v_cutoff, "v-cutoff-uv", rc, error_read);
+ SPMI_PROPERTY_READ(max_voltage, "max-voltage-uv", rc, error_read);
+ SPMI_PROPERTY_READ(r_conn_mohm, "r-conn-mohm", rc, error_read);
+ SPMI_PROPERTY_READ(shutdown_soc_valid_limit,
+ "shutdown-soc-valid-limit", rc, error_read);
+ SPMI_PROPERTY_READ(adjust_soc_low_threshold,
+ "adjust-soc-low-threshold", rc, error_read);
+ SPMI_PROPERTY_READ(adjust_soc_high_threshold,
+ "adjust-soc-high-threshold", rc, error_read);
+ SPMI_PROPERTY_READ(chg_term, "chg-term-ua", rc, error_read);
+
+ pr_debug("dts data: r_sense_mohm:%d, v_cutoff:%d, max_v:%d, r_conn:%d, shutdown_soc: %d, adjust_soc_low:%d, adjust_soc_high:%d, chg_term:%d\n",
+ chip->r_sense_mohm, chip->v_cutoff,
+ chip->max_voltage, chip->r_conn_mohm,
+ chip->shutdown_soc_valid_limit,
+ chip->adjust_soc_low_threshold,
+ chip->adjust_soc_high_threshold,
+ chip->chg_term);
+
+ dev_set_drvdata(&spmi->dev, chip);
+ device_init_wakeup(&spmi->dev, 1);
+
+ /* setup & register the battery power supply */
+ chip->bms_psy.name = "bms";
+ chip->bms_psy.type = POWER_SUPPLY_TYPE_BMS;
+ chip->bms_psy.properties = msm_bms_power_props;
+ chip->bms_psy.num_properties = ARRAY_SIZE(msm_bms_power_props);
+ chip->bms_psy.get_property = qpnp_bms_power_get_property;
+ chip->bms_psy.set_property = qpnp_bms_power_set_property;
+ chip->bms_psy.external_power_changed =
+ qpnp_bms_external_power_changed;
+ chip->bms_psy.supplied_to = qpnp_bms_supplicants;
+ chip->bms_psy.num_supplicants = ARRAY_SIZE(qpnp_bms_supplicants);
+
+ rc = power_supply_register(chip->dev, &chip->bms_psy);
+
+ if (rc < 0) {
+ pr_err("power_supply_register bms failed rc = %d\n", rc);
+ goto unregister_dc;
+ }
+
+ pr_info("probe success\n");
+ return 0;
+
+unregister_dc:
+ power_supply_unregister(&chip->bms_psy);
+ dev_set_drvdata(&spmi->dev, NULL);
+error_read:
+ kfree(chip);
+ return rc;
+}
+
+static int __devexit
+qpnp_bms_remove(struct spmi_device *spmi)
+{
+ struct qpnp_bms_chip *chip = dev_get_drvdata(&spmi->dev);
+
+ dev_set_drvdata(&spmi->dev, NULL);
+ kfree(chip);
+ return 0;
+}
+
+static struct spmi_driver qpnp_bms_driver = {
+ .probe = qpnp_bms_probe,
+ .remove = __devexit_p(qpnp_bms_remove),
+ .driver = {
+ .name = QPNP_BMS_DEV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = qpnp_bms_match_table,
+ },
+};
+
+static int __init qpnp_bms_init(void)
+{
+ pr_info("QPNP BMS INIT\n");
+ return spmi_driver_register(&qpnp_bms_driver);
+}
+
+static void __exit qpnp_bms_exit(void)
+{
+ pr_info("QPNP BMS EXIT\n");
+ return spmi_driver_unregister(&qpnp_bms_driver);
+}
+
+module_init(qpnp_bms_init);
+module_exit(qpnp_bms_exit);
+
+MODULE_DESCRIPTION("QPNP BMS Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" QPNP_BMS_DEV_NAME);
diff --git a/drivers/slimbus/slim-msm-ctrl.c b/drivers/slimbus/slim-msm-ctrl.c
index 6cddf2d..e2f37cc 100644
--- a/drivers/slimbus/slim-msm-ctrl.c
+++ b/drivers/slimbus/slim-msm-ctrl.c
@@ -699,7 +699,8 @@
for (i = 0; i < 6; i++)
e_addr[i] = buf[7-i];
- ret = slim_assign_laddr(&dev->ctrl, e_addr, 6, &laddr);
+ ret = slim_assign_laddr(&dev->ctrl, e_addr, 6, &laddr,
+ false);
/* Is this Qualcomm ported generic device? */
if (!ret && e_addr[5] == QC_MFGID_LSB &&
e_addr[4] == QC_MFGID_MSB &&
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index 6d96d3b..bd25875 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -681,13 +681,13 @@
}
static int ctrl_getlogical_addr(struct slim_controller *ctrl, const u8 *eaddr,
- u8 e_len, u8 *laddr)
+ u8 e_len, u8 *entry)
{
u8 i;
for (i = 0; i < ctrl->num_dev; i++) {
if (ctrl->addrt[i].valid &&
memcmp(ctrl->addrt[i].eaddr, eaddr, e_len) == 0) {
- *laddr = i;
+ *entry = i;
return 0;
}
}
@@ -699,23 +699,28 @@
* @ctrl: Controller with which device is enumerated.
* @e_addr: 6-byte elemental address of the device.
* @e_len: buffer length for e_addr
- * @laddr: Return logical address.
+ * @laddr: Return logical address (if valid flag is false)
+ * @valid: true if laddr holds a valid address that controller wants to
+ * set for this enumeration address. Otherwise framework sets index into
+ * address table as logical address.
* Called by controller in response to REPORT_PRESENT. Framework will assign
* a logical address to this enumeration address.
* Function returns -EXFULL to indicate that all logical addresses are already
* taken.
*/
int slim_assign_laddr(struct slim_controller *ctrl, const u8 *e_addr,
- u8 e_len, u8 *laddr)
+ u8 e_len, u8 *laddr, bool valid)
{
int ret;
u8 i = 0;
+ bool exists = false;
struct slim_device *sbdev;
mutex_lock(&ctrl->m_ctrl);
/* already assigned */
- if (ctrl_getlogical_addr(ctrl, e_addr, e_len, laddr) == 0)
- i = *laddr;
- else {
+ if (ctrl_getlogical_addr(ctrl, e_addr, e_len, &i) == 0) {
+ *laddr = ctrl->addrt[i].laddr;
+ exists = true;
+ } else {
if (ctrl->num_dev >= 254) {
ret = -EXFULL;
goto ret_assigned_laddr;
@@ -737,22 +742,26 @@
}
memcpy(ctrl->addrt[i].eaddr, e_addr, e_len);
ctrl->addrt[i].valid = true;
+ /* Preferred address is index into table */
+ if (!valid)
+ *laddr = i;
}
- ret = ctrl->set_laddr(ctrl, ctrl->addrt[i].eaddr, 6, i);
+ ret = ctrl->set_laddr(ctrl, (const u8 *)&ctrl->addrt[i].eaddr, 6,
+ *laddr);
if (ret) {
ctrl->addrt[i].valid = false;
goto ret_assigned_laddr;
}
- *laddr = i;
+ ctrl->addrt[i].laddr = *laddr;
- dev_dbg(&ctrl->dev, "setting slimbus l-addr:%x\n", i);
+ dev_dbg(&ctrl->dev, "setting slimbus l-addr:%x\n", *laddr);
ret_assigned_laddr:
mutex_unlock(&ctrl->m_ctrl);
- if (ret)
+ if (exists || ret)
return ret;
- pr_info("slimbus laddr:0x%x, EAPC:0x%x:0x%x", i,
+ pr_info("slimbus:%d laddr:0x%x, EAPC:0x%x:0x%x", ctrl->nr, *laddr,
e_addr[1], e_addr[2]);
mutex_lock(&ctrl->m_ctrl);
list_for_each_entry(sbdev, &ctrl->devs, dev_list) {
@@ -785,12 +794,21 @@
u8 e_len, u8 *laddr)
{
int ret = 0;
+ u8 entry;
struct slim_controller *ctrl = sb->ctrl;
if (!ctrl || !laddr || !e_addr || e_len != 6)
return -EINVAL;
mutex_lock(&ctrl->m_ctrl);
- ret = ctrl_getlogical_addr(ctrl, e_addr, e_len, laddr);
+ ret = ctrl_getlogical_addr(ctrl, e_addr, e_len, &entry);
+ if (!ret)
+ *laddr = ctrl->addrt[entry].laddr;
mutex_unlock(&ctrl->m_ctrl);
+ if (ret == -ENXIO && ctrl->get_laddr) {
+ ret = ctrl->get_laddr(ctrl, e_addr, e_len, laddr);
+ if (!ret)
+ ret = slim_assign_laddr(ctrl, e_addr, e_len, laddr,
+ true);
+ }
return ret;
}
EXPORT_SYMBOL_GPL(slim_get_logical_addr);
@@ -943,8 +961,6 @@
u16 ec;
u8 tid, mlen = 6;
- if (sbdev->laddr != SLIM_LA_MANAGER && sbdev->laddr >= ctrl->num_dev)
- return -ENXIO;
ret = slim_ele_access_sanity(msg, mc, rbuf, wbuf, len);
if (ret)
goto xfer_err;
diff --git a/drivers/tty/smux_ctl.c b/drivers/tty/smux_ctl.c
index 7e0e6f8..c17495b 100644
--- a/drivers/tty/smux_ctl.c
+++ b/drivers/tty/smux_ctl.c
@@ -770,12 +770,13 @@
poll_wait(file, &devp->read_wait_queue, wait);
readable = smux_ctl_readable(devp->id);
- if (readable < 0) {
+ if (readable > 0) {
+ mask = POLLIN | POLLRDNORM;
+ } else if ((readable < 0) && (readable != -ERESTARTSYS)) {
+ /* error case (non-signal) received */
pr_err(SMUX_CTL_MODULE_NAME ": %s err%d during poll for smuxctl%d\n",
__func__, readable, devp->id);
mask = POLLERR;
- } else if (readable) {
- mask = POLLIN | POLLRDNORM;
}
return mask;
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index a6eb335..46f21a7 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -80,6 +80,8 @@
#ifdef CONFIG_TARGET_CORE
#include "f_tcm.c"
#endif
+#include "u_uac1.c"
+#include "f_uac1.c"
MODULE_AUTHOR("Mike Lockwood");
MODULE_DESCRIPTION("Android Composite USB Driver");
@@ -702,6 +704,18 @@
.init = mbim_function_init,
};
+/* PERIPHERAL AUDIO */
+static int audio_function_bind_config(struct android_usb_function *f,
+ struct usb_configuration *c)
+{
+ return audio_bind_config(c);
+}
+
+static struct android_usb_function audio_function = {
+ .name = "audio",
+ .bind_config = audio_function_bind_config,
+};
+
/* DIAG */
static char diag_clients[32]; /*enabled DIAG clients- "diag[,diag_mdm]" */
@@ -1506,6 +1520,7 @@
static struct android_usb_function *supported_functions[] = {
&mbim_function,
&ecm_qc_function,
+ &audio_function,
&rmnet_smd_function,
&rmnet_sdio_function,
&rmnet_smd_sdio_function,
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 5b39336..b8b7f68 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -2575,7 +2575,7 @@
int retval = 0;
unsigned long flags;
- trace("%p, %p", ep, desc);
+ trace("ep = %p, desc = %p", ep, desc);
if (ep == NULL || desc == NULL)
return -EINVAL;
@@ -2601,9 +2601,10 @@
if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
mEp->qh.ptr->cap |= QH_IOS;
- else if (mEp->type == USB_ENDPOINT_XFER_ISOC)
+ else if (mEp->type == USB_ENDPOINT_XFER_ISOC) {
mEp->qh.ptr->cap &= ~QH_MULT;
- else
+ mEp->qh.ptr->cap |= BIT(30);
+ } else
mEp->qh.ptr->cap |= QH_ZLT;
mEp->qh.ptr->cap |=
diff --git a/drivers/usb/gadget/f_adb.c b/drivers/usb/gadget/f_adb.c
index 9778673..045fc6c 100644
--- a/drivers/usb/gadget/f_adb.c
+++ b/drivers/usb/gadget/f_adb.c
@@ -301,7 +301,7 @@
requeue_req:
/* queue a request */
req = dev->rx_req;
- req->length = count;
+ req->length = ADB_BULK_BUFFER_SIZE;
dev->rx_done = 0;
ret = usb_ep_queue(dev->ep_out, req, GFP_ATOMIC);
if (ret < 0) {
diff --git a/drivers/usb/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
index 6883b78..7a84ca3 100644
--- a/drivers/usb/gadget/f_mbim.c
+++ b/drivers/usb/gadget/f_mbim.c
@@ -67,8 +67,8 @@
};
struct f_mbim {
- struct usb_function function;
- struct usb_composite_dev *cdev;
+ struct usb_function function;
+ struct usb_composite_dev *cdev;
atomic_t online;
bool is_open;
@@ -1255,6 +1255,20 @@
pr_info("mbim deactivated\n");
}
+#define MBIM_ACTIVE_PORT 0
+
+static void mbim_suspend(struct usb_function *f)
+{
+ pr_info("mbim suspended\n");
+ bam_data_suspend(MBIM_ACTIVE_PORT);
+}
+
+static void mbim_resume(struct usb_function *f)
+{
+ pr_info("mbim resumed\n");
+ bam_data_resume(MBIM_ACTIVE_PORT);
+}
+
/*---------------------- function driver setup/binding ---------------------*/
static int
@@ -1288,6 +1302,8 @@
mbim_data_intf.bInterfaceNumber = status;
mbim_union_desc.bSlaveInterface0 = status;
+ mbim->bam_port.cdev = cdev;
+
status = -ENODEV;
/* allocate instance-specific endpoints */
@@ -1461,6 +1477,8 @@
mbim->function.get_alt = mbim_get_alt;
mbim->function.setup = mbim_setup;
mbim->function.disable = mbim_disable;
+ mbim->function.suspend = mbim_suspend;
+ mbim->function.resume = mbim_resume;
INIT_LIST_HEAD(&mbim->cpkt_req_q);
INIT_LIST_HEAD(&mbim->cpkt_resp_q);
diff --git a/drivers/usb/gadget/f_qc_ecm.c b/drivers/usb/gadget/f_qc_ecm.c
index 98a29ae..7fedaf6 100644
--- a/drivers/usb/gadget/f_qc_ecm.c
+++ b/drivers/usb/gadget/f_qc_ecm.c
@@ -305,7 +305,7 @@
{
int ret;
- ecm_qc_bam_port.func = dev->port.func;
+ ecm_qc_bam_port.cdev = dev->port.func.config->cdev;
ecm_qc_bam_port.in = dev->port.in_ep;
ecm_qc_bam_port.out = dev->port.out_ep;
diff --git a/drivers/usb/gadget/f_qc_rndis.c b/drivers/usb/gadget/f_qc_rndis.c
index a740d95..60b96fe 100644
--- a/drivers/usb/gadget/f_qc_rndis.c
+++ b/drivers/usb/gadget/f_qc_rndis.c
@@ -417,7 +417,7 @@
{
int ret;
- rndis_qc_bam_port.func = dev->port.func;
+ rndis_qc_bam_port.cdev = dev->port.func.config->cdev;
rndis_qc_bam_port.in = dev->port.in_ep;
rndis_qc_bam_port.out = dev->port.out_ep;
diff --git a/drivers/usb/gadget/f_uac1.c b/drivers/usb/gadget/f_uac1.c
index 1a5dcd5..b385592 100644
--- a/drivers/usb/gadget/f_uac1.c
+++ b/drivers/usb/gadget/f_uac1.c
@@ -1,6 +1,7 @@
/*
* f_audio.c -- USB Audio class function driver
- *
+ *
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
* Copyright (C) 2008 Bryan Wu <cooloney@kernel.org>
* Copyright (C) 2008 Analog Devices, Inc
*
@@ -9,29 +10,21 @@
* Licensed under the GPL-2 or later.
*/
+#ifdef pr_fmt
+#undef pr_fmt
+#endif
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/atomic.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+
#include "u_uac1.h"
-#define OUT_EP_MAX_PACKET_SIZE 200
-static int req_buf_size = OUT_EP_MAX_PACKET_SIZE;
-module_param(req_buf_size, int, S_IRUGO);
-MODULE_PARM_DESC(req_buf_size, "ISO OUT endpoint request buffer size");
-
-static int req_count = 256;
-module_param(req_count, int, S_IRUGO);
-MODULE_PARM_DESC(req_count, "ISO OUT endpoint request count");
-
-static int audio_buf_size = 48000;
-module_param(audio_buf_size, int, S_IRUGO);
-MODULE_PARM_DESC(audio_buf_size, "Audio buffer size");
-
-static int generic_set_cmd(struct usb_audio_control *con, u8 cmd, int value);
-static int generic_get_cmd(struct usb_audio_control *con, u8 cmd);
-
/*
* DESCRIPTORS ... most are static, but strings and full
* configuration descriptors are built on demand.
@@ -39,180 +32,376 @@
/*
* We have two interfaces- AudioControl and AudioStreaming
- * TODO: only supcard playback currently
*/
-#define F_AUDIO_AC_INTERFACE 0
-#define F_AUDIO_AS_INTERFACE 1
-#define F_AUDIO_NUM_INTERFACES 2
+#define PLAYBACK_EP_MAX_PACKET_SIZE 32
+static int req_playback_buf_size = PLAYBACK_EP_MAX_PACKET_SIZE;
+module_param(req_playback_buf_size, int, S_IRUGO);
+MODULE_PARM_DESC(req_playback_buf_size, "ISO OUT endpoint (playback) request buffer size");
-/* B.3.1 Standard AC Interface Descriptor */
-static struct usb_interface_descriptor ac_interface_desc __initdata = {
- .bLength = USB_DT_INTERFACE_SIZE,
- .bDescriptorType = USB_DT_INTERFACE,
- .bNumEndpoints = 0,
- .bInterfaceClass = USB_CLASS_AUDIO,
- .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
-};
+static int req_playback_count = 48;
+module_param(req_playback_count, int, S_IRUGO);
+MODULE_PARM_DESC(req_playback_count, "ISO OUT endpoint (playback) request count");
+
+static int audio_playback_buf_size = 256*32;
+module_param(audio_playback_buf_size, int, S_IRUGO);
+MODULE_PARM_DESC(audio_playback_buf_size, "Audio buffer size");
+
+#define CAPTURE_EP_MAX_PACKET_SIZE 32
+static int req_capture_buf_size = CAPTURE_EP_MAX_PACKET_SIZE;
+module_param(req_capture_buf_size, int, S_IRUGO);
+MODULE_PARM_DESC(req_capture_buf_size, "ISO IN endpoint (capture) request buffer size");
+
+static int req_capture_count = 48;
+module_param(req_capture_count, int, S_IRUGO);
+MODULE_PARM_DESC(req_capture_count, "ISO IN endpoint (capture) request count");
+
+static int audio_capture_buf_size = 256*32;
+module_param(audio_capture_buf_size, int, S_IRUGO);
+MODULE_PARM_DESC(audio_capture_buf_size, "Microphone Audio buffer size");
+
+static int generic_set_cmd(struct usb_audio_control *con, u8 cmd, int value);
+static int generic_get_cmd(struct usb_audio_control *con, u8 cmd);
DECLARE_UAC_AC_HEADER_DESCRIPTOR(2);
+DECLARE_UAC_FORMAT_TYPE_I_DISCRETE_DESC(1);
-#define UAC_DT_AC_HEADER_LENGTH UAC_DT_AC_HEADER_SIZE(F_AUDIO_NUM_INTERFACES)
-/* 1 input terminal, 1 output terminal and 1 feature unit */
-#define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH + UAC_DT_INPUT_TERMINAL_SIZE \
- + UAC_DT_OUTPUT_TERMINAL_SIZE + UAC_DT_FEATURE_UNIT_SIZE(0))
-/* B.3.2 Class-Specific AC Interface Descriptor */
-static struct uac1_ac_header_descriptor_2 ac_header_desc = {
- .bLength = UAC_DT_AC_HEADER_LENGTH,
- .bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubtype = UAC_HEADER,
- .bcdADC = __constant_cpu_to_le16(0x0100),
- .wTotalLength = __constant_cpu_to_le16(UAC_DT_TOTAL_LENGTH),
- .bInCollection = F_AUDIO_NUM_INTERFACES,
- .baInterfaceNr = {
- [0] = F_AUDIO_AC_INTERFACE,
- [1] = F_AUDIO_AS_INTERFACE,
- }
+#define SPEAKER_INPUT_TERMINAL_ID 3
+#define SPEAKER_OUTPUT_TERMINAL_ID 4
+
+#define MICROPHONE_INPUT_TERMINAL_ID 1
+#define MICROPHONE_OUTPUT_TERMINAL_ID 2
+
+
+ /*
+ * We have two interfaces- AudioControl and AudioStreaming
+ */
+
+#define F_AUDIO_INTERFACE_MICROPHONE 2
+#define F_AUDIO_INTERFACE_SPEAKER 3
+#define F_AUDIO_NUM_INTERFACES 2
+
+ /* B.3.1 Standard AC Interface Descriptor */
+struct usb_interface_descriptor ac_interface_desc = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bNumEndpoints = 0,
+ .bInterfaceClass = USB_CLASS_AUDIO,
+ .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
};
-#define INPUT_TERMINAL_ID 1
-static struct uac_input_terminal_descriptor input_terminal_desc = {
- .bLength = UAC_DT_INPUT_TERMINAL_SIZE,
- .bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubtype = UAC_INPUT_TERMINAL,
- .bTerminalID = INPUT_TERMINAL_ID,
- .wTerminalType = UAC_TERMINAL_STREAMING,
- .bAssocTerminal = 0,
- .wChannelConfig = 0x3,
-};
+#define TOTAL_LENGTH ( \
+ UAC_DT_AC_HEADER_SIZE(2) + \
+ UAC_DT_INPUT_TERMINAL_SIZE + \
+ UAC_DT_OUTPUT_TERMINAL_SIZE + \
+ UAC_DT_INPUT_TERMINAL_SIZE + \
+ UAC_DT_OUTPUT_TERMINAL_SIZE \
+ )
-DECLARE_UAC_FEATURE_UNIT_DESCRIPTOR(0);
-
-#define FEATURE_UNIT_ID 2
-static struct uac_feature_unit_descriptor_0 feature_unit_desc = {
- .bLength = UAC_DT_FEATURE_UNIT_SIZE(0),
+ /* B.3.2 Class-Specific AC Interface Descriptor */
+struct uac1_ac_header_descriptor_2 ac_header_desc = {
+ .bLength = UAC_DT_AC_HEADER_SIZE(2),
.bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubtype = UAC_FEATURE_UNIT,
- .bUnitID = FEATURE_UNIT_ID,
- .bSourceID = INPUT_TERMINAL_ID,
- .bControlSize = 2,
- .bmaControls[0] = (UAC_FU_MUTE | UAC_FU_VOLUME),
+ .bDescriptorSubtype = UAC_HEADER,
+ .bcdADC = __constant_cpu_to_le16(0x0100),
+ .wTotalLength = __constant_cpu_to_le16(TOTAL_LENGTH),
+ .bInCollection = F_AUDIO_NUM_INTERFACES,
+ /*.baInterfaceNr = {
+ [0] = F_AUDIO_INTERFACE_MICROPHONE,
+ [1] = F_AUDIO_INTERFACE_SPEAKER,
+ }
+ */
};
-static struct usb_audio_control mute_control = {
- .list = LIST_HEAD_INIT(mute_control.list),
- .name = "Mute Control",
+/*---------------------------------*/
+
+struct uac_input_terminal_descriptor speaker_input_terminal_desc = {
+ .bLength = UAC_DT_INPUT_TERMINAL_SIZE,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = UAC_INPUT_TERMINAL,
+ .bTerminalID = SPEAKER_INPUT_TERMINAL_ID,
+ .wTerminalType = UAC_TERMINAL_STREAMING,
+ .bAssocTerminal = SPEAKER_OUTPUT_TERMINAL_ID,
+ .wChannelConfig = 0x3,
+};
+
+struct uac1_output_terminal_descriptor speaker_output_terminal_desc = {
+ .bLength = UAC_DT_OUTPUT_TERMINAL_SIZE,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = UAC_OUTPUT_TERMINAL,
+ .bTerminalID = SPEAKER_OUTPUT_TERMINAL_ID,
+ .wTerminalType = UAC_OUTPUT_TERMINAL_SPEAKER,
+ .bAssocTerminal = SPEAKER_INPUT_TERMINAL_ID,
+ .bSourceID = SPEAKER_INPUT_TERMINAL_ID,
+};
+
+static struct usb_audio_control speaker_mute_control = {
+ .list = LIST_HEAD_INIT(speaker_mute_control.list),
+ .name = "Speaker Mute Control",
.type = UAC_FU_MUTE,
/* Todo: add real Mute control code */
.set = generic_set_cmd,
.get = generic_get_cmd,
};
-static struct usb_audio_control volume_control = {
- .list = LIST_HEAD_INIT(volume_control.list),
- .name = "Volume Control",
+static struct usb_audio_control speaker_volume_control = {
+ .list = LIST_HEAD_INIT(speaker_volume_control.list),
+ .name = "Speaker Volume Control",
.type = UAC_FU_VOLUME,
/* Todo: add real Volume control code */
.set = generic_set_cmd,
.get = generic_get_cmd,
};
-static struct usb_audio_control_selector feature_unit = {
- .list = LIST_HEAD_INIT(feature_unit.list),
- .id = FEATURE_UNIT_ID,
- .name = "Mute & Volume Control",
- .type = UAC_FEATURE_UNIT,
- .desc = (struct usb_descriptor_header *)&feature_unit_desc,
+static struct usb_audio_control_selector speaker_fu_controls = {
+ .list = LIST_HEAD_INIT(speaker_fu_controls.list),
+ .name = "Speaker Function Unit Controls",
};
-#define OUTPUT_TERMINAL_ID 3
-static struct uac1_output_terminal_descriptor output_terminal_desc = {
+static struct uac_input_terminal_descriptor microphone_input_terminal_desc = {
+ .bLength = UAC_DT_INPUT_TERMINAL_SIZE,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = UAC_INPUT_TERMINAL,
+ .bTerminalID = MICROPHONE_INPUT_TERMINAL_ID,
+ .wTerminalType = UAC_INPUT_TERMINAL_MICROPHONE,
+ .bAssocTerminal = MICROPHONE_OUTPUT_TERMINAL_ID,
+ .bNrChannels = 1,
+ .wChannelConfig = 0x3,
+};
+
+static struct
+uac1_output_terminal_descriptor microphone_output_terminal_desc = {
.bLength = UAC_DT_OUTPUT_TERMINAL_SIZE,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = UAC_OUTPUT_TERMINAL,
- .bTerminalID = OUTPUT_TERMINAL_ID,
- .wTerminalType = UAC_OUTPUT_TERMINAL_SPEAKER,
- .bAssocTerminal = FEATURE_UNIT_ID,
- .bSourceID = FEATURE_UNIT_ID,
+ .bTerminalID = MICROPHONE_OUTPUT_TERMINAL_ID,
+ .wTerminalType = UAC_TERMINAL_STREAMING,
+ .bAssocTerminal = MICROPHONE_INPUT_TERMINAL_ID,
+ .bSourceID = MICROPHONE_INPUT_TERMINAL_ID,
};
-/* B.4.1 Standard AS Interface Descriptor */
-static struct usb_interface_descriptor as_interface_alt_0_desc = {
- .bLength = USB_DT_INTERFACE_SIZE,
- .bDescriptorType = USB_DT_INTERFACE,
- .bAlternateSetting = 0,
- .bNumEndpoints = 0,
- .bInterfaceClass = USB_CLASS_AUDIO,
- .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING,
+static struct usb_audio_control microphone_mute_control = {
+ .list = LIST_HEAD_INIT(microphone_mute_control.list),
+ .name = "Microphone Mute Control",
+ .type = UAC_FU_MUTE,
+ /* Todo: add real Mute control code */
+ .set = generic_set_cmd,
+ .get = generic_get_cmd,
};
-static struct usb_interface_descriptor as_interface_alt_1_desc = {
- .bLength = USB_DT_INTERFACE_SIZE,
- .bDescriptorType = USB_DT_INTERFACE,
- .bAlternateSetting = 1,
- .bNumEndpoints = 1,
- .bInterfaceClass = USB_CLASS_AUDIO,
- .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING,
+static struct usb_audio_control microphone_volume_control = {
+ .list = LIST_HEAD_INIT(microphone_volume_control.list),
+ .name = "Microphone Volume Control",
+ .type = UAC_FU_VOLUME,
+ /* Todo: add real Volume control code */
+ .set = generic_set_cmd,
+ .get = generic_get_cmd,
};
-/* B.4.2 Class-Specific AS Interface Descriptor */
-static struct uac1_as_header_descriptor as_header_desc = {
- .bLength = UAC_DT_AS_HEADER_SIZE,
- .bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubtype = UAC_AS_GENERAL,
- .bTerminalLink = INPUT_TERMINAL_ID,
- .bDelay = 1,
- .wFormatTag = UAC_FORMAT_TYPE_I_PCM,
+static struct usb_audio_control_selector microphone_fu_controls = {
+ .list = LIST_HEAD_INIT(microphone_fu_controls.list),
+ .name = "Microphone Feature Unit Controls",
};
-DECLARE_UAC_FORMAT_TYPE_I_DISCRETE_DESC(1);
+/*---------------------------------*/
-static struct uac_format_type_i_discrete_descriptor_1 as_type_i_desc = {
- .bLength = UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1),
- .bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubtype = UAC_FORMAT_TYPE,
- .bFormatType = UAC_FORMAT_TYPE_I,
- .bSubframeSize = 2,
- .bBitResolution = 16,
- .bSamFreqType = 1,
+ /* B.4.1 Standard AS Interface Descriptor */
+static struct usb_interface_descriptor speaker_as_interface_alt_0_desc = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 0,
+ .bInterfaceClass = USB_CLASS_AUDIO,
+ .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING,
};
-/* Standard ISO OUT Endpoint Descriptor */
-static struct usb_endpoint_descriptor as_out_ep_desc = {
- .bLength = USB_DT_ENDPOINT_AUDIO_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_SYNC_ADAPTIVE
- | USB_ENDPOINT_XFER_ISOC,
- .wMaxPacketSize = __constant_cpu_to_le16(OUT_EP_MAX_PACKET_SIZE),
- .bInterval = 4,
+static struct usb_interface_descriptor speaker_as_interface_alt_1_desc = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bAlternateSetting = 1,
+ .bNumEndpoints = 1,
+ .bInterfaceClass = USB_CLASS_AUDIO,
+ .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING,
+};
+
+ /* B.4.2 Class-Specific AS Interface Descriptor */
+static struct uac1_as_header_descriptor speaker_as_header_desc = {
+ .bLength = UAC_DT_AS_HEADER_SIZE,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = UAC_AS_GENERAL,
+ .bTerminalLink = SPEAKER_INPUT_TERMINAL_ID,
+ .bDelay = 1,
+ .wFormatTag = UAC_FORMAT_TYPE_I_PCM,
+};
+
+static struct uac_format_type_i_discrete_descriptor_1 speaker_as_type_i_desc = {
+ .bLength = UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = UAC_FORMAT_TYPE,
+ .bFormatType = UAC_FORMAT_TYPE_I,
+ .bSubframeSize = 2,
+ .bBitResolution = 16,
+ .bSamFreqType = 1,
+};
+
+ /* Standard ISO OUT Endpoint Descriptor */
+static struct usb_endpoint_descriptor speaker_as_ep_out_desc = {
+ .bLength = USB_DT_ENDPOINT_AUDIO_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_SYNC_ADAPTIVE |
+ USB_ENDPOINT_XFER_ISOC,
+ .wMaxPacketSize =
+ __constant_cpu_to_le16(PLAYBACK_EP_MAX_PACKET_SIZE),
+ .bInterval = 4,
};
/* Class-specific AS ISO OUT Endpoint Descriptor */
-static struct uac_iso_endpoint_descriptor as_iso_out_desc __initdata = {
- .bLength = UAC_ISO_ENDPOINT_DESC_SIZE,
- .bDescriptorType = USB_DT_CS_ENDPOINT,
- .bDescriptorSubtype = UAC_EP_GENERAL,
- .bmAttributes = 1,
- .bLockDelayUnits = 1,
- .wLockDelay = __constant_cpu_to_le16(1),
+static struct uac_iso_endpoint_descriptor speaker_as_iso_out_desc = {
+ .bLength = UAC_ISO_ENDPOINT_DESC_SIZE,
+ .bDescriptorType = USB_DT_CS_ENDPOINT,
+ .bDescriptorSubtype = UAC_EP_GENERAL,
+ .bmAttributes = 1,
+ .bLockDelayUnits = 1,
+ .wLockDelay = __constant_cpu_to_le16(1),
};
-static struct usb_descriptor_header *f_audio_desc[] __initdata = {
+static struct usb_audio_control speaker_sample_freq_control = {
+ .list = LIST_HEAD_INIT(speaker_sample_freq_control.list),
+ .name = "Speaker Sampling Frequency Control",
+ .type = UAC_EP_CS_ATTR_SAMPLE_RATE,
+ .set = generic_set_cmd,
+ .get = generic_get_cmd,
+};
+
+static struct usb_audio_control_selector speaker_as_iso_out = {
+ .list = LIST_HEAD_INIT(speaker_as_iso_out.list),
+ .name = "Speaker Iso-out Endpoint Control",
+ .type = UAC_EP_GENERAL,
+ .desc = (struct usb_descriptor_header *)&speaker_as_iso_out_desc,
+};
+
+/*---------------------------------*/
+
+/* B.4.1 Standard AS Interface Descriptor */
+static struct usb_interface_descriptor microphone_as_interface_alt_0_desc = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 0,
+ .bInterfaceClass = USB_CLASS_AUDIO,
+ .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING,
+};
+
+static struct usb_interface_descriptor microphone_as_interface_alt_1_desc = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bAlternateSetting = 1,
+ .bNumEndpoints = 1,
+ .bInterfaceClass = USB_CLASS_AUDIO,
+ .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING,
+};
+
+/* B.4.2 Class-Specific AS Interface Descriptor */
+static struct uac1_as_header_descriptor microphone_as_header_desc = {
+ .bLength = UAC_DT_AS_HEADER_SIZE,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = UAC_AS_GENERAL,
+ .bTerminalLink = MICROPHONE_OUTPUT_TERMINAL_ID,
+ .bDelay = 1,
+ .wFormatTag = UAC_FORMAT_TYPE_I_PCM,
+};
+
+static struct
+uac_format_type_i_discrete_descriptor_1 microphone_as_type_i_desc = {
+ .bLength = UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = UAC_FORMAT_TYPE,
+ .bFormatType = UAC_FORMAT_TYPE_I,
+ .bNrChannels = 1,
+ .bSubframeSize = 2,
+ .bBitResolution = 16,
+ .bSamFreqType = 1,
+};
+
+/* Standard ISO IN Endpoint Descriptor */
+static struct usb_endpoint_descriptor microphone_as_ep_in_desc = {
+ .bLength = USB_DT_ENDPOINT_AUDIO_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes =
+ USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
+ .wMaxPacketSize =
+ __constant_cpu_to_le16(CAPTURE_EP_MAX_PACKET_SIZE),
+ .bInterval = 4,
+};
+
+ /* Class-specific AS ISO OUT Endpoint Descriptor */
+static struct uac_iso_endpoint_descriptor microphone_as_iso_in_desc = {
+ .bLength = UAC_ISO_ENDPOINT_DESC_SIZE,
+ .bDescriptorType = USB_DT_CS_ENDPOINT,
+ .bDescriptorSubtype = UAC_EP_GENERAL,
+ .bmAttributes = 1,
+ .bLockDelayUnits = 1,
+ .wLockDelay = __constant_cpu_to_le16(1),
+};
+
+static struct usb_audio_control microphone_sample_freq_control = {
+ .list = LIST_HEAD_INIT(microphone_sample_freq_control.list),
+ .name = "Microphone Sampling Frequency Control",
+ .type = UAC_EP_CS_ATTR_SAMPLE_RATE,
+ .set = generic_set_cmd,
+ .get = generic_get_cmd,
+};
+
+static struct usb_audio_control_selector microphone_as_iso_in = {
+ .list = LIST_HEAD_INIT(microphone_as_iso_in.list),
+ .name = "Microphone Iso-IN Endpoint Control",
+ .type = UAC_EP_GENERAL,
+ .desc = (struct usb_descriptor_header *)µphone_as_iso_in_desc,
+};
+
+/*--------------------------------- */
+
+static struct usb_descriptor_header *f_audio_desc[] = {
(struct usb_descriptor_header *)&ac_interface_desc,
(struct usb_descriptor_header *)&ac_header_desc,
- (struct usb_descriptor_header *)&input_terminal_desc,
- (struct usb_descriptor_header *)&output_terminal_desc,
- (struct usb_descriptor_header *)&feature_unit_desc,
+ (struct usb_descriptor_header *)µphone_input_terminal_desc,
+ (struct usb_descriptor_header *)µphone_output_terminal_desc,
- (struct usb_descriptor_header *)&as_interface_alt_0_desc,
- (struct usb_descriptor_header *)&as_interface_alt_1_desc,
- (struct usb_descriptor_header *)&as_header_desc,
+ (struct usb_descriptor_header *)&speaker_input_terminal_desc,
+ (struct usb_descriptor_header *)&speaker_output_terminal_desc,
- (struct usb_descriptor_header *)&as_type_i_desc,
+ (struct usb_descriptor_header *)µphone_as_interface_alt_0_desc,
+ (struct usb_descriptor_header *)µphone_as_interface_alt_1_desc,
+ (struct usb_descriptor_header *)µphone_as_header_desc,
+ (struct usb_descriptor_header *)µphone_as_type_i_desc,
+ (struct usb_descriptor_header *)µphone_as_ep_in_desc,
+ (struct usb_descriptor_header *)µphone_as_iso_in_desc,
- (struct usb_descriptor_header *)&as_out_ep_desc,
- (struct usb_descriptor_header *)&as_iso_out_desc,
+ (struct usb_descriptor_header *)&speaker_as_interface_alt_0_desc,
+ (struct usb_descriptor_header *)&speaker_as_interface_alt_1_desc,
+ (struct usb_descriptor_header *)&speaker_as_header_desc,
+ (struct usb_descriptor_header *)&speaker_as_type_i_desc,
+ (struct usb_descriptor_header *)&speaker_as_ep_out_desc,
+ (struct usb_descriptor_header *)&speaker_as_iso_out_desc,
+
+ NULL,
+};
+
+/* string IDs are assigned dynamically */
+
+static struct usb_string audio_string_defs[] = {
+ { } /* end of list */
+};
+
+static struct usb_gadget_strings audio_stringtab_dev = {
+ .language = 0x0409, /* en-us */
+ .strings = audio_string_defs,
+};
+
+static struct usb_gadget_strings *audio_strings[] = {
+ &audio_stringtab_dev,
NULL,
};
@@ -229,25 +418,32 @@
static struct f_audio_buf *f_audio_buffer_alloc(int buf_size)
{
- struct f_audio_buf *copy_buf;
+ struct f_audio_buf *playback_copy_buf;
- copy_buf = kzalloc(sizeof *copy_buf, GFP_ATOMIC);
- if (!copy_buf)
- return ERR_PTR(-ENOMEM);
-
- copy_buf->buf = kzalloc(buf_size, GFP_ATOMIC);
- if (!copy_buf->buf) {
- kfree(copy_buf);
+ playback_copy_buf = kzalloc(sizeof *playback_copy_buf, GFP_ATOMIC);
+ if (!playback_copy_buf) {
+ pr_err("Failed to allocate playback_copy_buf");
return ERR_PTR(-ENOMEM);
}
- return copy_buf;
+ playback_copy_buf->buf = kzalloc(buf_size, GFP_ATOMIC);
+ if (!playback_copy_buf->buf) {
+ pr_err("Failed to allocate playback_copy_buf buffer");
+ kfree(playback_copy_buf);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ return playback_copy_buf;
}
static void f_audio_buffer_free(struct f_audio_buf *audio_buf)
{
- kfree(audio_buf->buf);
- kfree(audio_buf);
+ if (audio_buf) {
+ kfree(audio_buf->buf);
+ kfree(audio_buf);
+ audio_buf->buf = NULL;
+ audio_buf = NULL;
+ }
}
/*-------------------------------------------------------------------------*/
@@ -256,16 +452,24 @@
/* endpoints handle full and/or high speeds */
struct usb_ep *out_ep;
+ struct usb_ep *in_ep;
- spinlock_t lock;
- struct f_audio_buf *copy_buf;
- struct work_struct playback_work;
- struct list_head play_queue;
+ spinlock_t playback_lock;
+ struct f_audio_buf *playback_copy_buf;
+ struct work_struct playback_work;
+ struct list_head play_queue;
+
+ spinlock_t capture_lock;
+ struct f_audio_buf *capture_copy_buf;
+ struct work_struct capture_work;
+ struct list_head capture_queue;
+ struct usb_request *capture_req;
/* Control Set command */
- struct list_head cs;
- u8 set_cmd;
- struct usb_audio_control *set_con;
+ struct list_head fu_cs;
+ struct list_head ep_cs;
+ u8 set_cmd;
+ struct usb_audio_control *set_con;
};
static inline struct f_audio *func_to_audio(struct usb_function *f)
@@ -280,50 +484,126 @@
struct f_audio *audio = container_of(data, struct f_audio,
playback_work);
struct f_audio_buf *play_buf;
+ unsigned long flags;
+ int res = 0;
- spin_lock_irq(&audio->lock);
+ spin_lock_irqsave(&audio->playback_lock, flags);
if (list_empty(&audio->play_queue)) {
- spin_unlock_irq(&audio->lock);
+ pr_err("playback_buf is empty");
+ spin_unlock_irqrestore(&audio->playback_lock, flags);
return;
}
play_buf = list_first_entry(&audio->play_queue,
struct f_audio_buf, list);
list_del(&play_buf->list);
- spin_unlock_irq(&audio->lock);
+ spin_unlock_irqrestore(&audio->playback_lock, flags);
- u_audio_playback(&audio->card, play_buf->buf, play_buf->actual);
+ pr_debug("play_buf->actual = %d", play_buf->actual);
+
+ res = u_audio_playback(&audio->card, play_buf->buf, play_buf->actual);
+ if (res)
+ pr_err("copying failed");
+
f_audio_buffer_free(play_buf);
}
-static int f_audio_out_ep_complete(struct usb_ep *ep, struct usb_request *req)
+static int
+f_audio_playback_ep_complete(struct usb_ep *ep, struct usb_request *req)
{
struct f_audio *audio = req->context;
- struct usb_composite_dev *cdev = audio->card.func.config->cdev;
- struct f_audio_buf *copy_buf = audio->copy_buf;
+ struct f_audio_buf *copy_buf = audio->playback_copy_buf;
int err;
if (!copy_buf)
return -EINVAL;
/* Copy buffer is full, add it to the play_queue */
- if (audio_buf_size - copy_buf->actual < req->actual) {
+ if (audio_playback_buf_size - copy_buf->actual < req->actual) {
+ pr_debug("audio_playback_buf_size %d - copy_buf->actual %d, req->actual %d",
+ audio_playback_buf_size, copy_buf->actual, req->actual);
list_add_tail(©_buf->list, &audio->play_queue);
schedule_work(&audio->playback_work);
- copy_buf = f_audio_buffer_alloc(audio_buf_size);
- if (IS_ERR(copy_buf))
+ copy_buf = f_audio_buffer_alloc(audio_playback_buf_size);
+ if (IS_ERR(copy_buf)) {
+ pr_err("Failed to allocate playback_copy_buf");
return -ENOMEM;
+ }
}
memcpy(copy_buf->buf + copy_buf->actual, req->buf, req->actual);
copy_buf->actual += req->actual;
- audio->copy_buf = copy_buf;
+ audio->playback_copy_buf = copy_buf;
err = usb_ep_queue(ep, req, GFP_ATOMIC);
if (err)
- ERROR(cdev, "%s queue req: %d\n", ep->name, err);
+ pr_err("Failed to queue %s req: err - %d\n", ep->name, err);
- return 0;
+ return err;
+}
+static void f_audio_capture_work(struct work_struct *data)
+{
+ struct f_audio *audio =
+ container_of(data, struct f_audio, capture_work);
+ struct f_audio_buf *capture_buf;
+ unsigned long flags;
+ int res = 0;
+
+ capture_buf = f_audio_buffer_alloc(audio_capture_buf_size);
+ if (capture_buf <= 0) {
+ pr_err("%s: buffer alloc failed\n", __func__);
+ return;
+ }
+
+ res = u_audio_capture(&audio->card, capture_buf->buf,
+ audio_capture_buf_size);
+ if (res)
+ pr_err("copying failed");
+
+ pr_debug("Queue capture packet: size %d", audio_capture_buf_size);
+ spin_lock_irqsave(&audio->capture_lock, flags);
+ list_add_tail(&capture_buf->list, &audio->capture_queue);
+ spin_unlock_irqrestore(&audio->capture_lock, flags);
+}
+
+static int
+f_audio_capture_ep_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ struct f_audio *audio = req->context;
+ struct f_audio_buf *copy_buf = audio->capture_copy_buf;
+ unsigned long flags;
+ int err = 0;
+
+ if (copy_buf == 0) {
+ pr_debug("copy_buf == 0");
+ spin_lock_irqsave(&audio->capture_lock, flags);
+ if (list_empty(&audio->capture_queue)) {
+ spin_unlock_irqrestore(&audio->capture_lock, flags);
+ schedule_work(&audio->capture_work);
+ goto done;
+ }
+ copy_buf = list_first_entry(&audio->capture_queue,
+ struct f_audio_buf, list);
+ list_del(©_buf->list);
+ audio->capture_copy_buf = copy_buf;
+ spin_unlock_irqrestore(&audio->capture_lock, flags);
+ }
+
+ pr_debug("Copy %d bytes", req->actual);
+ memcpy(req->buf, copy_buf->buf + copy_buf->actual, req->actual);
+ copy_buf->actual += req->actual;
+
+ if (audio_capture_buf_size - copy_buf->actual < req->actual) {
+ f_audio_buffer_free(copy_buf);
+ audio->capture_copy_buf = 0;
+ schedule_work(&audio->capture_work);
+ }
+done:
+ err = usb_ep_queue(ep, req, GFP_ATOMIC);
+ if (err)
+ pr_err("Failed to queue %s req: err - %d\n", ep->name, err);
+
+ return err;
}
static void f_audio_complete(struct usb_ep *ep, struct usb_request *req)
@@ -331,14 +611,14 @@
struct f_audio *audio = req->context;
int status = req->status;
u32 data = 0;
- struct usb_ep *out_ep = audio->out_ep;
switch (status) {
-
- case 0: /* normal completion? */
- if (ep == out_ep)
- f_audio_out_ep_complete(ep, req);
- else if (audio->set_con) {
+ case 0: /* normal completion? */
+ if (ep == audio->out_ep) {
+ f_audio_playback_ep_complete(ep, req);
+ } else if (ep == audio->in_ep) {
+ f_audio_capture_ep_complete(ep, req);
+ } else if (audio->set_con) {
memcpy(&data, req->buf, req->length);
audio->set_con->set(audio->set_con, audio->set_cmd,
le16_to_cpu(data));
@@ -346,6 +626,7 @@
}
break;
default:
+ pr_err("Failed completion: status %d", status);
break;
}
}
@@ -364,10 +645,10 @@
struct usb_audio_control_selector *cs;
struct usb_audio_control *con;
- DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, entity %d\n",
+ pr_debug("bRequest 0x%x, w_value 0x%04x, len %d, entity %d\n",
ctrl->bRequest, w_value, len, id);
- list_for_each_entry(cs, &audio->cs, list) {
+ list_for_each_entry(cs, &audio->fu_cs, list) {
if (cs->id == id) {
list_for_each_entry(con, &cs->control, list) {
if (con->type == con_sel) {
@@ -401,10 +682,10 @@
struct usb_audio_control_selector *cs;
struct usb_audio_control *con;
- DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, entity %d\n",
+ pr_debug("bRequest 0x%x, w_value 0x%04x, len %d, entity %d\n",
ctrl->bRequest, w_value, len, id);
- list_for_each_entry(cs, &audio->cs, list) {
+ list_for_each_entry(cs, &audio->fu_cs, list) {
if (cs->id == id) {
list_for_each_entry(con, &cs->control, list) {
if (con->type == con_sel && con->get) {
@@ -423,36 +704,68 @@
return len;
}
+static void audio_set_endpoint_complete(struct usb_ep *ep,
+ struct usb_request *req)
+{
+ struct f_audio *audio = req->context;
+ u32 data = 0;
+
+ if (req->status == 0 && audio->set_con) {
+ memcpy(&data, req->buf, req->length);
+ audio->set_con->set(audio->set_con, audio->set_cmd,
+ le32_to_cpu(data));
+ audio->set_con = NULL;
+ }
+}
+
static int audio_set_endpoint_req(struct usb_function *f,
const struct usb_ctrlrequest *ctrl)
{
+ int value = -EOPNOTSUPP;
+ u16 ep = le16_to_cpu(ctrl->wIndex);
+ u16 len = le16_to_cpu(ctrl->wLength);
+ u16 w_value = le16_to_cpu(ctrl->wValue);
+
+ struct f_audio *audio = func_to_audio(f);
struct usb_composite_dev *cdev = f->config->cdev;
- int value = -EOPNOTSUPP;
- u16 ep = le16_to_cpu(ctrl->wIndex);
- u16 len = le16_to_cpu(ctrl->wLength);
- u16 w_value = le16_to_cpu(ctrl->wValue);
+ struct usb_request *req = cdev->req;
+ struct usb_audio_control_selector *cs;
+ struct usb_audio_control *con;
- DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n",
- ctrl->bRequest, w_value, len, ep);
+ u8 epnum = ep & ~0x80;
+ u8 con_sel = (w_value >> 8) & 0xFF;
+ u8 cmd = (ctrl->bRequest & 0x0F);
- switch (ctrl->bRequest) {
- case UAC_SET_CUR:
- value = len;
- break;
+ pr_debug("bRequest 0x%x, w_value 0x%04x, len %d, endp %d, epnum %d\n",
+ ctrl->bRequest, w_value, len, ep, epnum);
- case UAC_SET_MIN:
- break;
+ list_for_each_entry(cs, &audio->ep_cs, list) {
+ if (cs->id != epnum)
+ continue;
- case UAC_SET_MAX:
- break;
+ list_for_each_entry(con, &cs->control, list) {
+ if (con->type != con_sel)
+ continue;
- case UAC_SET_RES:
- break;
-
- case UAC_SET_MEM:
- break;
-
- default:
+ switch (cmd) {
+ case UAC__CUR:
+ case UAC__MIN:
+ case UAC__MAX:
+ case UAC__RES:
+ audio->set_con = con;
+ audio->set_cmd = cmd;
+ req->context = audio;
+ req->complete = audio_set_endpoint_complete;
+ value = len;
+ break;
+ case UAC__MEM:
+ break;
+ default:
+ pr_err("Unknown command");
+ break;
+ }
+ break;
+ }
break;
}
@@ -462,25 +775,48 @@
static int audio_get_endpoint_req(struct usb_function *f,
const struct usb_ctrlrequest *ctrl)
{
+ struct f_audio *audio = func_to_audio(f);
struct usb_composite_dev *cdev = f->config->cdev;
- int value = -EOPNOTSUPP;
- u8 ep = ((le16_to_cpu(ctrl->wIndex) >> 8) & 0xFF);
- u16 len = le16_to_cpu(ctrl->wLength);
- u16 w_value = le16_to_cpu(ctrl->wValue);
+ struct usb_request *req = cdev->req;
+ struct usb_audio_control_selector *cs;
+ struct usb_audio_control *con;
+ int data;
- DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n",
+ int value = -EOPNOTSUPP;
+ u8 ep = (le16_to_cpu(ctrl->wIndex) & 0x7F);
+ u8 epnum = ep & ~0x80;
+ u16 len = le16_to_cpu(ctrl->wLength);
+ u16 w_value = le16_to_cpu(ctrl->wValue);
+ u8 con_sel = (w_value >> 8) & 0xFF;
+ u8 cmd = (ctrl->bRequest & 0x0F);
+
+ pr_debug("bRequest 0x%x, w_value 0x%04x, len %d, ep %d\n",
ctrl->bRequest, w_value, len, ep);
- switch (ctrl->bRequest) {
- case UAC_GET_CUR:
- case UAC_GET_MIN:
- case UAC_GET_MAX:
- case UAC_GET_RES:
- value = len;
- break;
- case UAC_GET_MEM:
- break;
- default:
+ list_for_each_entry(cs, &audio->ep_cs, list) {
+ if (cs->id != epnum)
+ continue;
+
+ list_for_each_entry(con, &cs->control, list) {
+ if (con->type != con_sel)
+ continue;
+
+ switch (cmd) {
+ case UAC__CUR:
+ case UAC__MIN:
+ case UAC__MAX:
+ case UAC__RES:
+ data = cpu_to_le32(generic_get_cmd(con, cmd));
+ memcpy(req->buf, &data, len);
+ value = len;
+ break;
+ case UAC__MEM:
+ break;
+ default:
+ break;
+ }
+ break;
+ }
break;
}
@@ -500,39 +836,47 @@
/* composite driver infrastructure handles everything; interface
* activation uses set_alt().
*/
+
switch (ctrl->bRequestType) {
case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE:
+ pr_debug("USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE");
value = audio_set_intf_req(f, ctrl);
break;
case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE:
+ pr_debug("USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE");
value = audio_get_intf_req(f, ctrl);
break;
case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT:
+ pr_debug("USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT");
value = audio_set_endpoint_req(f, ctrl);
break;
case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT:
+ pr_debug("USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT");
value = audio_get_endpoint_req(f, ctrl);
break;
default:
- ERROR(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n",
+ pr_err("Unknown control request %02x.%02x v%04x i%04x l%d\n",
ctrl->bRequestType, ctrl->bRequest,
w_value, w_index, w_length);
+
}
/* respond with data transfer or status phase? */
if (value >= 0) {
- DBG(cdev, "audio req%02x.%02x v%04x i%04x l%d\n",
+ pr_debug("audio req %02x.%02x v%04x i%04x l%d\n",
ctrl->bRequestType, ctrl->bRequest,
w_value, w_index, w_length);
- req->zero = 0;
+ req->zero = 1;
req->length = value;
value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
if (value < 0)
- ERROR(cdev, "audio response on err %d\n", value);
+ pr_err("audio response failed on err %d\n", value);
+ } else {
+ pr_err("STALL\n");
}
/* device either stalls (value < 0) or reports success */
@@ -542,55 +886,114 @@
static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
{
struct f_audio *audio = func_to_audio(f);
- struct usb_composite_dev *cdev = f->config->cdev;
- struct usb_ep *out_ep = audio->out_ep;
- struct usb_request *req;
+ struct usb_ep *out_ep = audio->out_ep;
+ struct usb_ep *in_ep = audio->in_ep;
+ struct usb_request *req;
+ unsigned long flags;
int i = 0, err = 0;
- DBG(cdev, "intf %d, alt %d\n", intf, alt);
+ pr_debug("intf %d, alt %d\n", intf, alt);
- if (intf == 1) {
+ if (intf == ac_header_desc.baInterfaceNr[0]) {
if (alt == 1) {
- usb_ep_enable(out_ep);
- out_ep->driver_data = audio;
- audio->copy_buf = f_audio_buffer_alloc(audio_buf_size);
- if (IS_ERR(audio->copy_buf))
+ err = usb_ep_enable(in_ep);
+ if (err) {
+ pr_err("Failed to enable capture ep");
+ return err;
+ }
+ in_ep->driver_data = audio;
+ audio->capture_copy_buf = 0;
+
+ /* Allocate a write buffer */
+ req = usb_ep_alloc_request(in_ep, GFP_ATOMIC);
+ if (!req) {
+ pr_err("request allocation failed\n");
return -ENOMEM;
+ }
+ req->buf = kzalloc(req_capture_buf_size,
+ GFP_ATOMIC);
+ if (!req->buf) {
+ pr_err("request buffer allocation failed\n");
+ return -ENOMEM;
+ }
+
+ req->length = req_capture_buf_size;
+ req->context = audio;
+ req->complete = f_audio_complete;
+ audio->capture_req = req;
+ err = usb_ep_queue(in_ep, req, GFP_ATOMIC);
+ if (err)
+ pr_err("Failed to queue %s req: err %d\n",
+ in_ep->name, err);
+ schedule_work(&audio->capture_work);
+ } else {
+ struct f_audio_buf *capture_buf;
+ spin_lock_irqsave(&audio->capture_lock, flags);
+ while (!list_empty(&audio->capture_queue)) {
+ capture_buf =
+ list_first_entry(
+ &audio->capture_queue,
+ struct f_audio_buf,
+ list);
+ list_del(&capture_buf->list);
+ f_audio_buffer_free(capture_buf);
+ }
+ spin_unlock_irqrestore(&audio->capture_lock, flags);
+ }
+ } else if (intf == ac_header_desc.baInterfaceNr[1]) {
+ if (alt == 1) {
+ err = usb_ep_enable(out_ep);
+ if (err) {
+ pr_err("Failed to enable playback ep");
+ return err;
+ }
+ out_ep->driver_data = audio;
+ audio->playback_copy_buf =
+ f_audio_buffer_alloc(audio_playback_buf_size);
+ if (IS_ERR(audio->playback_copy_buf)) {
+ pr_err("Failed to allocate playback_copy_buf");
+ return -ENOMEM;
+ }
/*
* allocate a bunch of read buffers
* and queue them all at once.
*/
- for (i = 0; i < req_count && err == 0; i++) {
+ for (i = 0; i < req_playback_count && err == 0; i++) {
req = usb_ep_alloc_request(out_ep, GFP_ATOMIC);
- if (req) {
- req->buf = kzalloc(req_buf_size,
- GFP_ATOMIC);
- if (req->buf) {
- req->length = req_buf_size;
- req->context = audio;
- req->complete =
- f_audio_complete;
- err = usb_ep_queue(out_ep,
- req, GFP_ATOMIC);
- if (err)
- ERROR(cdev,
- "%s queue req: %d\n",
- out_ep->name, err);
- } else
- err = -ENOMEM;
- } else
- err = -ENOMEM;
+ if (!req) {
+ pr_err("request allocation failed\n");
+ return -ENOMEM;
+ }
+ req->buf = kzalloc(req_playback_buf_size,
+ GFP_ATOMIC);
+ if (!req->buf) {
+ pr_err("request buffer allocation failed\n");
+ return -ENOMEM;
+ }
+ req->length = req_playback_buf_size;
+ req->context = audio;
+ req->complete = f_audio_complete;
+ err = usb_ep_queue(out_ep, req, GFP_ATOMIC);
+ if (err)
+ pr_err("Failed to queue %s queue req: err %d\n",
+ out_ep->name, err);
}
-
+ pr_debug("Allocated %d requests\n", req_playback_count);
} else {
- struct f_audio_buf *copy_buf = audio->copy_buf;
- if (copy_buf) {
- list_add_tail(©_buf->list,
+ struct f_audio_buf *playback_copy_buf =
+ audio->playback_copy_buf;
+ if (playback_copy_buf) {
+ pr_err("Schedule playback_work");
+ list_add_tail(&playback_copy_buf->list,
&audio->play_queue);
schedule_work(&audio->playback_work);
+ } else {
+ pr_err("playback_buf is empty. Stop.");
}
}
+ } else {
+ pr_err("Interface %d. Do nothing. Return %d\n", intf, err);
}
return err;
@@ -598,7 +1001,7 @@
static void f_audio_disable(struct usb_function *f)
{
- return;
+ u_audio_clear();
}
/*-------------------------------------------------------------------------*/
@@ -610,12 +1013,23 @@
int rate;
/* Set channel numbers */
- input_terminal_desc.bNrChannels = u_audio_get_playback_channels(card);
- as_type_i_desc.bNrChannels = u_audio_get_playback_channels(card);
+ speaker_input_terminal_desc.bNrChannels =
+ u_audio_get_playback_channels(card);
+ speaker_as_type_i_desc.bNrChannels =
+ u_audio_get_playback_channels(card);
+
+ microphone_input_terminal_desc.bNrChannels =
+ u_audio_get_capture_channels(card);
+ microphone_as_type_i_desc.bNrChannels =
+ u_audio_get_capture_channels(card);
/* Set sample rates */
rate = u_audio_get_playback_rate(card);
- sam_freq = as_type_i_desc.tSamFreq[0];
+ sam_freq = speaker_as_type_i_desc.tSamFreq[0];
+ memcpy(sam_freq, &rate, 3);
+
+ rate = u_audio_get_capture_rate(card);
+ sam_freq = microphone_as_type_i_desc.tSamFreq[0];
memcpy(sam_freq, &rate, 3);
/* Todo: Set Sample bits and other parameters */
@@ -624,64 +1038,101 @@
}
/* audio function driver setup/binding */
-static int __init
+static int
f_audio_bind(struct usb_configuration *c, struct usb_function *f)
{
struct usb_composite_dev *cdev = c->cdev;
struct f_audio *audio = func_to_audio(f);
int status;
struct usb_ep *ep;
+ u8 epaddr;
+
f_audio_build_desc(audio);
/* allocate instance-specific interface IDs, and patch descriptors */
status = usb_interface_id(c, f);
- if (status < 0)
+ if (status < 0) {
+ pr_err("%s: failed to allocate desc interface", __func__);
goto fail;
+ }
ac_interface_desc.bInterfaceNumber = status;
+ status = -ENOMEM;
+
status = usb_interface_id(c, f);
- if (status < 0)
+ if (status < 0) {
+ pr_err("%s: failed to allocate alt interface", __func__);
goto fail;
- as_interface_alt_0_desc.bInterfaceNumber = status;
- as_interface_alt_1_desc.bInterfaceNumber = status;
+ }
+ microphone_as_interface_alt_0_desc.bInterfaceNumber = status;
+ microphone_as_interface_alt_1_desc.bInterfaceNumber = status;
+ ac_header_desc.baInterfaceNr[0] = status;
+
+ status = -ENODEV;
+
+ status = usb_interface_id(c, f);
+ if (status < 0) {
+ pr_err("%s: failed to allocate alt interface", __func__);
+ goto fail;
+ }
+ speaker_as_interface_alt_0_desc.bInterfaceNumber = status;
+ speaker_as_interface_alt_1_desc.bInterfaceNumber = status;
+ ac_header_desc.baInterfaceNr[1] = status;
status = -ENODEV;
/* allocate instance-specific endpoints */
- ep = usb_ep_autoconfig(cdev->gadget, &as_out_ep_desc);
- if (!ep)
+ ep = usb_ep_autoconfig(cdev->gadget, µphone_as_ep_in_desc);
+ if (!ep) {
+ pr_err("%s: failed to autoconfig in endpoint", __func__);
goto fail;
- audio->out_ep = ep;
- audio->out_ep->desc = &as_out_ep_desc;
- ep->driver_data = cdev; /* claim */
+ }
+ audio->in_ep = ep;
+ ep->desc = µphone_as_ep_in_desc;
+ ep->driver_data = cdev;
status = -ENOMEM;
- /* copy descriptors, and track endpoint copies */
- f->descriptors = usb_copy_descriptors(f_audio_desc);
+ ep = usb_ep_autoconfig(cdev->gadget, &speaker_as_ep_out_desc);
+ if (!ep) {
+ pr_err("%s: failed to autoconfig out endpoint", __func__);
+ goto fail;
+ }
+ audio->out_ep = ep;
+ ep->desc = &speaker_as_ep_out_desc;
+ ep->driver_data = cdev;
- /*
- * support all relevant hardware speeds... we expect that when
+ /* associate bEndpointAddress with usb_function */
+ epaddr = microphone_as_ep_in_desc.bEndpointAddress & ~USB_DIR_IN;
+ microphone_as_iso_in.id = epaddr;
+
+ epaddr = speaker_as_ep_out_desc.bEndpointAddress & ~USB_DIR_IN;
+ speaker_as_iso_out.id = epaddr;
+
+ /* support all relevant hardware speeds. we expect that when
* hardware is dual speed, all bulk-capable endpoints work at
* both speeds
*/
+
+ /* copy descriptors, and track endpoint copies */
if (gadget_is_dualspeed(c->cdev->gadget)) {
c->highspeed = true;
f->hs_descriptors = usb_copy_descriptors(f_audio_desc);
+ } else {
+ f->descriptors = usb_copy_descriptors(f_audio_desc);
}
return 0;
fail:
-
return status;
}
static void
f_audio_unbind(struct usb_configuration *c, struct usb_function *f)
{
- struct f_audio *audio = func_to_audio(f);
+ struct f_audio *audio = func_to_audio(f);
usb_free_descriptors(f->descriptors);
usb_free_descriptors(f->hs_descriptors);
@@ -703,31 +1154,58 @@
}
/* Todo: add more control selecotor dynamically */
-int __init control_selector_init(struct f_audio *audio)
+int control_selector_init(struct f_audio *audio)
{
- INIT_LIST_HEAD(&audio->cs);
- list_add(&feature_unit.list, &audio->cs);
+ INIT_LIST_HEAD(&audio->fu_cs);
+ list_add(µphone_fu_controls.list, &audio->fu_cs);
+ list_add(&speaker_fu_controls.list, &audio->fu_cs);
- INIT_LIST_HEAD(&feature_unit.control);
- list_add(&mute_control.list, &feature_unit.control);
- list_add(&volume_control.list, &feature_unit.control);
+ INIT_LIST_HEAD(µphone_fu_controls.control);
+ list_add(µphone_mute_control.list,
+ µphone_fu_controls.control);
+ list_add(µphone_volume_control.list,
+ µphone_fu_controls.control);
- volume_control.data[UAC__CUR] = 0xffc0;
- volume_control.data[UAC__MIN] = 0xe3a0;
- volume_control.data[UAC__MAX] = 0xfff0;
- volume_control.data[UAC__RES] = 0x0030;
+ INIT_LIST_HEAD(&speaker_fu_controls.control);
+ list_add(&speaker_mute_control.list,
+ &speaker_fu_controls.control);
+ list_add(&speaker_volume_control.list,
+ &speaker_fu_controls.control);
+
+ microphone_volume_control.data[UAC__CUR] = 0xffc0;
+ microphone_volume_control.data[UAC__MIN] = 0xe3a0;
+ microphone_volume_control.data[UAC__MAX] = 0xfff0;
+ microphone_volume_control.data[UAC__RES] = 0x0030;
+
+ speaker_volume_control.data[UAC__CUR] = 0xffc0;
+ speaker_volume_control.data[UAC__MIN] = 0xe3a0;
+ speaker_volume_control.data[UAC__MAX] = 0xfff0;
+ speaker_volume_control.data[UAC__RES] = 0x0030;
+
+ INIT_LIST_HEAD(&audio->ep_cs);
+ list_add(&speaker_as_iso_out.list, &audio->ep_cs);
+ list_add(µphone_as_iso_in.list, &audio->ep_cs);
+
+ INIT_LIST_HEAD(µphone_as_iso_in.control);
+ list_add(µphone_sample_freq_control.list,
+ µphone_as_iso_in.control);
+
+ INIT_LIST_HEAD(&speaker_as_iso_out.control);
+ list_add(&speaker_sample_freq_control.list,
+ &speaker_as_iso_out.control);
return 0;
+
}
/**
* audio_bind_config - add USB audio function to a configuration
- * @c: the configuration to supcard the USB audio function
+ * @c: the configuration to support the USB audio function
* Context: single threaded during gadget setup
*
* Returns zero on success, else negative errno.
*/
-int __init audio_bind_config(struct usb_configuration *c)
+int audio_bind_config(struct usb_configuration *c)
{
struct f_audio *audio;
int status;
@@ -737,17 +1215,15 @@
if (!audio)
return -ENOMEM;
- audio->card.func.name = "g_audio";
audio->card.gadget = c->cdev->gadget;
INIT_LIST_HEAD(&audio->play_queue);
- spin_lock_init(&audio->lock);
+ spin_lock_init(&audio->playback_lock);
- /* set up ASLA audio devices */
- status = gaudio_setup(&audio->card);
- if (status < 0)
- goto setup_fail;
+ INIT_LIST_HEAD(&audio->capture_queue);
+ spin_lock_init(&audio->capture_lock);
+ audio->card.func.name = "audio";
audio->card.func.strings = audio_strings;
audio->card.func.bind = f_audio_bind;
audio->card.func.unbind = f_audio_unbind;
@@ -756,15 +1232,20 @@
audio->card.func.disable = f_audio_disable;
control_selector_init(audio);
-
INIT_WORK(&audio->playback_work, f_audio_playback_work);
+ INIT_WORK(&audio->capture_work, f_audio_capture_work);
- status = usb_add_function(c, &audio->card.func);
- if (status)
+ /* set up ASLA audio devices */
+ status = gaudio_setup(&audio->card);
+ if (status < 0)
goto add_fail;
- INFO(c->cdev, "audio_buf_size %d, req_buf_size %d, req_count %d\n",
- audio_buf_size, req_buf_size, req_count);
+ status = usb_add_function(c, &audio->card.func);
+ if (status) {
+ pr_err("%s: Failed to add usb audio function, err = %d",
+ __func__, status);
+ goto setup_fail;
+ }
return status;
diff --git a/drivers/usb/gadget/u_bam_data.c b/drivers/usb/gadget/u_bam_data.c
index a105f5d..32f683e 100644
--- a/drivers/usb/gadget/u_bam_data.c
+++ b/drivers/usb/gadget/u_bam_data.c
@@ -35,7 +35,7 @@
#define MSM_VENDOR_ID BIT(16)
struct data_port {
- struct usb_function func;
+ struct usb_composite_dev *cdev;
struct usb_ep *in;
struct usb_ep *out;
};
@@ -326,3 +326,54 @@
return ret;
}
+static int bam_data_wake_cb(void *param)
+{
+ struct bam_data_port *port = (struct bam_data_port *)param;
+ struct data_port *d_port = port->port_usb;
+
+ pr_info("%s: woken up by peer\n", __func__);
+
+ if (!d_port) {
+ pr_err("FAILED: d_port == NULL");
+ return -ENODEV;
+ }
+
+ if (!d_port->cdev) {
+ pr_err("FAILED: d_port->cdev == NULL");
+ return -ENODEV;
+ }
+
+ if (!d_port->cdev->gadget) {
+ pr_err("FAILED: d_port->cdev->gadget == NULL");
+ return -ENODEV;
+ }
+
+ return usb_gadget_wakeup(d_port->cdev->gadget);
+}
+
+void bam_data_suspend(u8 port_num)
+{
+
+ struct bam_data_port *port;
+ struct bam_data_ch_info *d;
+
+ port = bam2bam_data_ports[port_num];
+ d = &port->data_ch;
+
+ pr_info("%s: suspended port %d\n", __func__, port_num);
+ usb_bam_register_wake_cb(d->connection_idx, bam_data_wake_cb, port);
+}
+
+void bam_data_resume(u8 port_num)
+{
+
+ struct bam_data_port *port;
+ struct bam_data_ch_info *d;
+
+ port = bam2bam_data_ports[port_num];
+ d = &port->data_ch;
+
+ pr_info("%s: resumed port %d\n", __func__, port_num);
+ usb_bam_register_wake_cb(d->connection_idx, NULL, NULL);
+}
+
diff --git a/drivers/usb/gadget/u_data_hsic.c b/drivers/usb/gadget/u_data_hsic.c
index 89d2887..746c041 100644
--- a/drivers/usb/gadget/u_data_hsic.c
+++ b/drivers/usb/gadget/u_data_hsic.c
@@ -220,6 +220,7 @@
req->context = skb;
req->buf = skb->data;
req->length = skb->len;
+ req->zero = 1;
port->n_tx_req_queued++;
if (port->n_tx_req_queued == ghsic_data_tx_intr_thld) {
diff --git a/drivers/usb/gadget/u_uac1.c b/drivers/usb/gadget/u_uac1.c
index af98989..fc4fb7a 100644
--- a/drivers/usb/gadget/u_uac1.c
+++ b/drivers/usb/gadget/u_uac1.c
@@ -1,6 +1,7 @@
/*
- * u_uac1.c -- ALSA audio utilities for Gadget stack
+ * u_audio.c -- ALSA audio utilities for Gadget stack
*
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
* Copyright (C) 2008 Bryan Wu <cooloney@kernel.org>
* Copyright (C) 2008 Analog Devices, Inc
*
@@ -19,12 +20,17 @@
#include "u_uac1.h"
+#ifdef pr_fmt
+#undef pr_fmt
+#endif
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
/*
* This component encapsulates the ALSA devices for USB audio gadget
*/
-#define FILE_PCM_PLAYBACK "/dev/snd/pcmC0D0p"
-#define FILE_PCM_CAPTURE "/dev/snd/pcmC0D0c"
+#define FILE_PCM_PLAYBACK "/dev/snd/pcmC0D5p"
+#define FILE_PCM_CAPTURE "/dev/snd/pcmC0D6c"
#define FILE_CONTROL "/dev/snd/controlC0"
static char *fn_play = FILE_PCM_PLAYBACK;
@@ -39,6 +45,10 @@
module_param(fn_cntl, charp, S_IRUGO);
MODULE_PARM_DESC(fn_cntl, "Control device file name");
+static struct gaudio *the_card;
+
+static bool audio_reinit;
+
/*-------------------------------------------------------------------------*/
/**
@@ -94,8 +104,9 @@
}
changed = snd_interval_refine(i, &t);
}
- } else
+ } else {
return -EINVAL;
+ }
if (changed) {
params->cmask |= 1 << var;
params->rmask |= 1 << var;
@@ -104,10 +115,32 @@
}
/*-------------------------------------------------------------------------*/
+static inline
+struct snd_interval *param_to_interval(struct snd_pcm_hw_params *p, int n)
+{
+ return &(p->intervals[n - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL]);
+}
+
+int pcm_buffer_size(struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *i =
+ param_to_interval(params, SNDRV_PCM_HW_PARAM_BUFFER_BYTES);
+ pr_debug("buffer_bytes = (%d,%d) omin=%d omax=%d int=%d empty=%d\n",
+ i->min, i->max, i->openmin, i->openmax, i->integer, i->empty);
+ return i->min;
+}
+
+int pcm_period_size(struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *i =
+ param_to_interval(params, SNDRV_PCM_HW_PARAM_PERIOD_BYTES);
+ return i->min;
+}
+
/**
* Set default hardware params
*/
-static int playback_default_hw_params(struct gaudio_snd_dev *snd)
+static int playback_prepare_params(struct gaudio_snd_dev *snd)
{
struct snd_pcm_substream *substream = snd->substream;
struct snd_pcm_hw_params *params;
@@ -117,12 +150,12 @@
* SNDRV_PCM_ACCESS_RW_INTERLEAVED,
* SNDRV_PCM_FORMAT_S16_LE
* CHANNELS: 2
- * RATE: 48000
+ * RATE: 8000
*/
snd->access = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
snd->format = SNDRV_PCM_FORMAT_S16_LE;
snd->channels = 2;
- snd->rate = 48000;
+ snd->rate = 8000;
params = kzalloc(sizeof(*params), GFP_KERNEL);
if (!params)
@@ -138,17 +171,23 @@
_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_RATE,
snd->rate, 0);
- snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
- snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_HW_PARAMS, params);
+ result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
+ if (result < 0)
+ pr_err("SNDRV_PCM_IOCTL_DROP failed: %d\n", (int)result);
- result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL);
+ result = snd_pcm_kernel_ioctl(substream,
+ SNDRV_PCM_IOCTL_HW_PARAMS, params);
if (result < 0) {
- ERROR(snd->card,
- "Preparing sound card failed: %d\n", (int)result);
+ pr_err("SNDRV_PCM_IOCTL_HW_PARAMS failed: %d\n", (int)result);
kfree(params);
return result;
}
+ result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL);
+ if (result < 0)
+ pr_err("Preparing playback failed: %d\n", (int)result);
+
+
/* Store the hardware parameters */
snd->access = params_access(params);
snd->format = params_format(params);
@@ -157,13 +196,236 @@
kfree(params);
- INFO(snd->card,
- "Hardware params: access %x, format %x, channels %d, rate %d\n",
+ pr_debug("playback params: access %x, format %x, channels %d, rate %d\n",
snd->access, snd->format, snd->channels, snd->rate);
return 0;
}
+static int capture_prepare_params(struct gaudio_snd_dev *snd)
+{
+ struct snd_pcm_substream *substream = snd->substream;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_pcm_hw_params *params;
+ struct snd_pcm_sw_params *swparams;
+ unsigned long period_size;
+ unsigned long buffer_size;
+ snd_pcm_sframes_t result = 0;
+
+ /*
+ * SNDRV_PCM_ACCESS_RW_INTERLEAVED,
+ * SNDRV_PCM_FORMAT_S16_LE
+ * CHANNELS: 1
+ * RATE: 8000
+ */
+ snd->access = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
+ snd->format = SNDRV_PCM_FORMAT_S16_LE;
+ snd->channels = 1;
+ snd->rate = 8000;
+
+ params = kzalloc(sizeof(*params), GFP_KERNEL);
+ if (!params) {
+ pr_err("Failed to allocate hw params");
+ return -ENOMEM;
+ }
+
+ _snd_pcm_hw_params_any(params);
+ _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_ACCESS,
+ snd->access, 0);
+ _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ snd->format, 0);
+ _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_CHANNELS,
+ snd->channels, 0);
+ _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_RATE,
+ snd->rate, 0);
+
+ result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
+ if (result < 0)
+ pr_err("SNDRV_PCM_IOCTL_DROP failed: %d\n", (int)result);
+
+ result = snd_pcm_kernel_ioctl(substream,
+ SNDRV_PCM_IOCTL_HW_PARAMS, params);
+ if (result < 0) {
+ pr_err("SNDRV_PCM_IOCTL_HW_PARAMS failed: %d\n", (int)result);
+ kfree(params);
+ return result;
+ }
+
+ result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE,
+ NULL);
+ if (result < 0)
+ pr_err("Preparing capture failed: %d\n", (int)result);
+
+ /* Store the hardware parameters */
+ snd->access = params_access(params);
+ snd->format = params_format(params);
+ snd->channels = params_channels(params);
+ snd->rate = params_rate(params);
+
+ runtime->frame_bits = snd_pcm_format_physical_width(runtime->format);
+
+ kfree(params);
+
+ swparams = kzalloc(sizeof(*swparams), GFP_KERNEL);
+ if (!swparams) {
+ pr_err("Failed to allocate sw params");
+ return -ENOMEM;
+ }
+
+ buffer_size = pcm_buffer_size(params);
+ period_size = pcm_period_size(params);
+ swparams->avail_min = period_size/2;
+ swparams->xfer_align = period_size/2;
+
+ swparams->tstamp_mode = SNDRV_PCM_TSTAMP_NONE;
+ swparams->period_step = 1;
+ swparams->start_threshold = 1;
+ swparams->stop_threshold = INT_MAX;
+ swparams->silence_size = 0;
+ swparams->silence_threshold = 0;
+
+ result = snd_pcm_kernel_ioctl(substream,
+ SNDRV_PCM_IOCTL_SW_PARAMS, swparams);
+ if (result < 0)
+ pr_err("SNDRV_PCM_IOCTL_SW_PARAMS failed: %d\n", (int)result);
+
+ kfree(swparams);
+
+ pr_debug("capture params: access %x, format %x, channels %d, rate %d\n",
+ snd->access, snd->format, snd->channels, snd->rate);
+
+ return result;
+}
+
+/**
+ * Set default hardware params
+ */
+static int playback_default_hw_params(struct gaudio_snd_dev *snd)
+{
+ struct snd_pcm_hw_params *params;
+
+ /*
+ * SNDRV_PCM_ACCESS_RW_INTERLEAVED,
+ * SNDRV_PCM_FORMAT_S16_LE
+ * CHANNELS: 2
+ * RATE: 8000
+ */
+ snd->access = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
+ snd->format = SNDRV_PCM_FORMAT_S16_LE;
+ snd->channels = 2;
+ snd->rate = 8000;
+
+ params = kzalloc(sizeof(*params), GFP_KERNEL);
+ if (!params)
+ return -ENOMEM;
+
+ _snd_pcm_hw_params_any(params);
+ _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_ACCESS,
+ snd->access, 0);
+ _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ snd->format, 0);
+ _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_CHANNELS,
+ snd->channels, 0);
+ _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_RATE,
+ snd->rate, 0);
+
+ /* Store the hardware parameters */
+ snd->access = params_access(params);
+ snd->format = params_format(params);
+ snd->channels = params_channels(params);
+ snd->rate = params_rate(params);
+
+ kfree(params);
+
+ pr_debug("playback params: access %x, format %x, channels %d, rate %d\n",
+ snd->access, snd->format, snd->channels, snd->rate);
+
+ return 0;
+}
+
+static int capture_default_hw_params(struct gaudio_snd_dev *snd)
+{
+ struct snd_pcm_hw_params *params;
+
+ /*
+ * SNDRV_PCM_ACCESS_RW_INTERLEAVED,
+ * SNDRV_PCM_FORMAT_S16_LE
+ * CHANNELS: 1
+ * RATE: 8000
+ */
+ snd->access = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
+ snd->format = SNDRV_PCM_FORMAT_S16_LE;
+ snd->channels = 1;
+ snd->rate = 8000;
+
+ params = kzalloc(sizeof(*params), GFP_KERNEL);
+ if (!params)
+ return -ENOMEM;
+
+ _snd_pcm_hw_params_any(params);
+ _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_ACCESS,
+ snd->access, 0);
+ _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ snd->format, 0);
+ _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_CHANNELS,
+ snd->channels, 0);
+ _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_RATE,
+ snd->rate, 0);
+
+ /* Store the hardware parameters */
+ snd->access = params_access(params);
+ snd->format = params_format(params);
+ snd->channels = params_channels(params);
+ snd->rate = params_rate(params);
+
+ kfree(params);
+
+ pr_debug("capture params: access %x, format %x, channels %d, rate %d\n",
+ snd->access, snd->format, snd->channels, snd->rate);
+
+ return 0;
+}
+
+static int gaudio_open_streams(void)
+{
+ struct gaudio_snd_dev *snd;
+ int res = 0;
+
+ if (!the_card) {
+ pr_err("%s: Card is NULL", __func__);
+ return -ENODEV;
+ }
+
+ pr_debug("Initialize hw params");
+
+ /* Open PCM playback device and setup substream */
+ snd = &the_card->playback;
+ res = playback_prepare_params(snd);
+ if (res) {
+ pr_err("Setting playback params failed: err %d", res);
+ return res;
+ }
+
+ pr_debug("Initialized playback params");
+
+ /* Open PCM capture device and setup substream */
+ snd = &the_card->capture;
+ res = capture_prepare_params(snd);
+ if (res) {
+ pr_err("Setting capture params failed: err %d", res);
+ return res;
+ }
+
+ pr_info("Initialized capture params");
+
+ return 0;
+}
+
+void u_audio_clear(void)
+{
+ audio_reinit = false;
+}
+
/**
* Playback audio buffer data by ALSA PCM device
*/
@@ -175,28 +437,106 @@
mm_segment_t old_fs;
ssize_t result;
snd_pcm_sframes_t frames;
+ int err = 0;
+
+ if (!count) {
+ pr_err("Buffer is empty, no data to play");
+ return 0;
+ }
+
+ if (!audio_reinit) {
+ err = gaudio_open_streams();
+ if (err) {
+ pr_err("Failed to init audio streams");
+ return 0;
+ }
+ audio_reinit = 1;
+ }
try_again:
if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
- runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
+ runtime->status->state == SNDRV_PCM_STATE_SUSPENDED ||
+ runtime->status->state == SNDRV_PCM_STATE_SETUP) {
result = snd_pcm_kernel_ioctl(substream,
SNDRV_PCM_IOCTL_PREPARE, NULL);
if (result < 0) {
- ERROR(card, "Preparing sound card failed: %d\n",
+ pr_err("Preparing playback failed: %d\n",
+ (int)result);
+ return result;
+ }
+ }
+
+ if (!runtime->frame_bits) {
+ pr_err("SND failure - runtime->frame_bits == 0");
+ return 0;
+ }
+
+ frames = bytes_to_frames(runtime, count);
+ pr_debug("runtime->frame_bits = %d, count = %d, frames = %d",
+ runtime->frame_bits, (int)count, (int)frames);
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ result = snd_pcm_lib_write(snd->substream, buf, frames);
+ if (result != frames) {
+ pr_err("snd_pcm_lib_write failed with err %d\n", (int)result);
+ set_fs(old_fs);
+ goto try_again;
+ }
+ set_fs(old_fs);
+
+ pr_debug("Done. Sent %d frames", (int)frames);
+
+ return 0;
+}
+
+static size_t u_audio_capture(struct gaudio *card, void *buf, size_t count)
+{
+ ssize_t result;
+ mm_segment_t old_fs;
+ snd_pcm_sframes_t frames;
+ int err = 0;
+
+ struct gaudio_snd_dev *snd = &card->capture;
+ struct snd_pcm_substream *substream = snd->substream;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ if (!audio_reinit) {
+ err = gaudio_open_streams();
+ if (err) {
+ pr_err("Failed to init audio streams: err %d", err);
+ return 0;
+ }
+ audio_reinit = 1;
+ }
+
+try_again:
+ if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
+ runtime->status->state == SNDRV_PCM_STATE_SUSPENDED ||
+ runtime->status->state == SNDRV_PCM_STATE_SETUP) {
+ result = snd_pcm_kernel_ioctl(substream,
+ SNDRV_PCM_IOCTL_PREPARE, NULL);
+ if (result < 0) {
+ pr_err("Preparing capture failed: %d\n",
(int)result);
return result;
}
}
frames = bytes_to_frames(runtime, count);
+
old_fs = get_fs();
set_fs(KERNEL_DS);
- result = snd_pcm_lib_write(snd->substream, buf, frames);
+
+ pr_debug("frames = %d, count = %d", (int)frames, count);
+
+ result = snd_pcm_lib_read(substream, buf, frames);
if (result != frames) {
- ERROR(card, "Playback error: %d\n", (int)result);
+ pr_err("Capture error: %d\n", (int)result);
set_fs(old_fs);
goto try_again;
}
+
set_fs(old_fs);
return 0;
@@ -204,14 +544,29 @@
static int u_audio_get_playback_channels(struct gaudio *card)
{
+ pr_debug("Return %d", card->playback.channels);
return card->playback.channels;
}
static int u_audio_get_playback_rate(struct gaudio *card)
{
+ pr_debug("Return %d", card->playback.rate);
return card->playback.rate;
}
+static int u_audio_get_capture_channels(struct gaudio *card)
+{
+ pr_debug("Return %d", card->capture.channels);
+ return card->capture.channels;
+}
+
+static int u_audio_get_capture_rate(struct gaudio *card)
+{
+ pr_debug("Return %d", card->capture.rate);
+ return card->capture.rate;
+}
+
+
/**
* Open ALSA PCM and control device files
* Initial the PCM or control device
@@ -220,16 +575,18 @@
{
struct snd_pcm_file *pcm_file;
struct gaudio_snd_dev *snd;
+ int res = 0;
- if (!card)
+ if (!card) {
+ pr_err("%s: Card is NULL", __func__);
return -ENODEV;
-
+ }
/* Open control device */
snd = &card->control;
snd->filp = filp_open(fn_cntl, O_RDWR, 0);
if (IS_ERR(snd->filp)) {
int ret = PTR_ERR(snd->filp);
- ERROR(card, "unable to open sound control device file: %s\n",
+ pr_err("unable to open sound control device file: %s\n",
fn_cntl);
snd->filp = NULL;
return ret;
@@ -240,29 +597,41 @@
snd = &card->playback;
snd->filp = filp_open(fn_play, O_WRONLY, 0);
if (IS_ERR(snd->filp)) {
- ERROR(card, "No such PCM playback device: %s\n", fn_play);
+ pr_err("No such PCM playback device: %s\n", fn_play);
snd->filp = NULL;
+ return -EINVAL;
}
+ pr_debug("Initialized PCM playback device: %s\n", fn_play);
+
pcm_file = snd->filp->private_data;
snd->substream = pcm_file->substream;
snd->card = card;
- playback_default_hw_params(snd);
+ res = playback_default_hw_params(snd);
+ if (res) {
+ pr_err("Setting playback HW params failed: err %d", res);
+ return res;
+ }
/* Open PCM capture device and setup substream */
snd = &card->capture;
snd->filp = filp_open(fn_cap, O_RDONLY, 0);
if (IS_ERR(snd->filp)) {
- ERROR(card, "No such PCM capture device: %s\n", fn_cap);
+ pr_err("No such PCM capture device: %s\n", fn_cap);
snd->substream = NULL;
snd->card = NULL;
snd->filp = NULL;
- } else {
- pcm_file = snd->filp->private_data;
- snd->substream = pcm_file->substream;
- snd->card = card;
+ return -EINVAL;
}
- return 0;
+ pcm_file = snd->filp->private_data;
+ snd->substream = pcm_file->substream;
+ snd->card = card;
+ res = capture_default_hw_params(snd);
+
+ if (res)
+ pr_err("Setting capture HW params failed: err %d", res);
+
+ return res;
}
/**
@@ -272,6 +641,7 @@
{
struct gaudio_snd_dev *snd;
+ pr_debug("Enter");
/* Close control device */
snd = &gau->control;
if (snd->filp)
@@ -290,7 +660,7 @@
return 0;
}
-static struct gaudio *the_card;
+
/**
* gaudio_setup - setup ALSA interface and preparing for USB transfer
*
@@ -298,18 +668,17 @@
*
* Returns negative errno, or zero on success
*/
-int __init gaudio_setup(struct gaudio *card)
+int gaudio_setup(struct gaudio *card)
{
int ret;
ret = gaudio_open_snd_dev(card);
if (ret)
- ERROR(card, "we need at least one control device\n");
+ pr_err("Failed to open snd devices\n");
else if (!the_card)
the_card = card;
return ret;
-
}
/**
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 8d967cd..adbf217 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -94,7 +94,7 @@
*/
#define EHCI_TUNE_FLS 1 /* (medium) 512-frame schedule */
-#define EHCI_IAA_MSECS 10 /* arbitrary */
+#define EHCI_IAA_MSECS 100 /* arbitrary */
#define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */
#define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */
#define EHCI_SHRINK_JIFFIES (DIV_ROUND_UP(HZ, 200) + 1)
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index fee7a09..b7f1878 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -659,12 +659,6 @@
return 0;
}
- if (!(readl_relaxed(USB_PORTSC) & PORT_PE)) {
- dev_dbg(mehci->dev, "%s:port is not enabled skip suspend\n",
- __func__);
- return -EAGAIN;
- }
-
disable_irq(hcd->irq);
/* make sure we don't race against a remote wakeup */
@@ -934,6 +928,15 @@
static int ehci_hsic_bus_suspend(struct usb_hcd *hcd)
{
+ struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
+
+ if (!(readl_relaxed(USB_PORTSC) & PORT_PE)) {
+ dbg_log_event(NULL, "RH suspend attempt failed", 0);
+ dev_dbg(mehci->dev, "%s:port is not enabled skip suspend\n",
+ __func__);
+ return -EAGAIN;
+ }
+
dbg_log_event(NULL, "Suspend RH", 0);
return ehci_bus_suspend(hcd);
}
diff --git a/drivers/usb/misc/ks_bridge.c b/drivers/usb/misc/ks_bridge.c
index 8753c0d..87f43e1c 100644
--- a/drivers/usb/misc/ks_bridge.c
+++ b/drivers/usb/misc/ks_bridge.c
@@ -262,6 +262,8 @@
return;
}
+ usb_free_urb(urb);
+
spin_lock_irqsave(&ksb->lock, flags);
}
spin_unlock_irqrestore(&ksb->lock, flags);
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 6e3567f..f6d9eb7 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -606,7 +606,7 @@
static int mdp_hist_init_mgmt(struct mdp_hist_mgmt *mgmt, uint32_t block)
{
- uint32_t bins, extra, index, term = 0;
+ uint32_t bins, extra, index, intr = 0, term = 0;
init_completion(&mgmt->mdp_hist_comp);
mutex_init(&mgmt->mdp_hist_mutex);
mutex_init(&mgmt->mdp_do_hist_mutex);
@@ -622,6 +622,8 @@
switch (block) {
case MDP_BLOCK_DMA_P:
term = MDP_HISTOGRAM_TERM_DMA_P;
+ intr = (mdp_rev >= MDP_REV_40) ? INTR_DMA_P_HISTOGRAM :
+ MDP_HIST_DONE;
bins = (mdp_rev >= MDP_REV_42) ? MDP_REV42_HIST_MAX_BIN :
MDP_REV41_HIST_MAX_BIN;
extra = 2;
@@ -630,6 +632,7 @@
break;
case MDP_BLOCK_DMA_S:
term = MDP_HISTOGRAM_TERM_DMA_S;
+ intr = INTR_DMA_S_HISTOGRAM;
bins = MDP_REV42_HIST_MAX_BIN;
extra = 2;
mgmt->base += 0x5000;
@@ -637,6 +640,7 @@
break;
case MDP_BLOCK_VG_1:
term = MDP_HISTOGRAM_TERM_VG_1;
+ intr = INTR_VG1_HISTOGRAM;
bins = MDP_REV42_HIST_MAX_BIN;
extra = 1;
mgmt->base += 0x6000;
@@ -644,6 +648,7 @@
break;
case MDP_BLOCK_VG_2:
term = MDP_HISTOGRAM_TERM_VG_2;
+ intr = INTR_VG2_HISTOGRAM;
bins = MDP_REV42_HIST_MAX_BIN;
extra = 1;
mgmt->base += 0x6000;
@@ -651,6 +656,8 @@
break;
default:
term = MDP_HISTOGRAM_TERM_DMA_P;
+ intr = (mdp_rev >= MDP_REV_40) ? INTR_DMA_P_HISTOGRAM :
+ MDP_HIST_DONE;
bins = (mdp_rev >= MDP_REV_42) ? MDP_REV42_HIST_MAX_BIN :
MDP_REV41_HIST_MAX_BIN;
extra = 2;
@@ -658,6 +665,7 @@
index = MDP_HIST_MGMT_DMA_P;
}
mgmt->irq_term = term;
+ mgmt->intr = intr;
mgmt->c0 = kmalloc(bins * sizeof(uint32_t), GFP_KERNEL);
if (mgmt->c0 == NULL)
@@ -802,20 +810,45 @@
static int mdp_histogram_enable(struct mdp_hist_mgmt *mgmt)
{
uint32_t base;
+ unsigned long flag;
if (mgmt->mdp_is_hist_data == TRUE) {
pr_err("%s histogram already started\n", __func__);
return -EINVAL;
}
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- mdp_enable_irq(mgmt->irq_term);
+ base = (uint32_t) (MDP_BASE + mgmt->base);
+ /*First make sure that device is not collecting histogram*/
+ mgmt->mdp_is_hist_data = FALSE;
+ mgmt->mdp_is_hist_valid = FALSE;
+ mgmt->mdp_is_hist_init = FALSE;
+ spin_lock_irqsave(&mdp_spin_lock, flag);
+ outp32(MDP_INTR_CLEAR, mgmt->intr);
+ mdp_intr_mask &= ~mgmt->intr;
+ outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+ MDP_OUTP(base + 0x001C, 0);
+ MDP_OUTP(base + 0x0018, INTR_HIST_DONE | INTR_HIST_RESET_SEQ_DONE);
+ MDP_OUTP(base + 0x0024, 0);
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
+
+ mutex_unlock(&mgmt->mdp_hist_mutex);
+ cancel_work_sync(&mgmt->mdp_histogram_worker);
+ mutex_lock(&mgmt->mdp_hist_mutex);
+
+ /*Then initialize histogram*/
INIT_COMPLETION(mgmt->mdp_hist_comp);
- base = (uint32_t) (MDP_BASE + mgmt->base);
+ spin_lock_irqsave(&mdp_spin_lock, flag);
MDP_OUTP(base + 0x0018, INTR_HIST_DONE | INTR_HIST_RESET_SEQ_DONE);
MDP_OUTP(base + 0x0010, 1);
MDP_OUTP(base + 0x001C, INTR_HIST_DONE | INTR_HIST_RESET_SEQ_DONE);
+ outp32(MDP_INTR_CLEAR, mgmt->intr);
+ mdp_intr_mask |= mgmt->intr;
+ outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+ mdp_enable_irq(mgmt->irq_term);
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
+
MDP_OUTP(base + 0x0004, mgmt->frame_cnt);
if (mgmt->block != MDP_BLOCK_VG_1 && mgmt->block != MDP_BLOCK_VG_2)
MDP_OUTP(base + 0x0008, mgmt->bit_mask);
@@ -830,6 +863,7 @@
static int mdp_histogram_disable(struct mdp_hist_mgmt *mgmt)
{
uint32_t base, status;
+ unsigned long flag;
if (mgmt->mdp_is_hist_data == FALSE) {
pr_err("%s histogram already stopped\n", __func__);
return -EINVAL;
@@ -842,6 +876,13 @@
base = (uint32_t) (MDP_BASE + mgmt->base);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ spin_lock_irqsave(&mdp_spin_lock, flag);
+ outp32(MDP_INTR_CLEAR, mgmt->intr);
+ mdp_intr_mask &= ~mgmt->intr;
+ outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+ mdp_disable_irq(mgmt->irq_term);
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
+
if (mdp_rev >= MDP_REV_42)
MDP_OUTP(base + 0x0020, 1);
status = inpdw(base + 0x001C);
@@ -856,7 +897,6 @@
complete(&mgmt->mdp_hist_comp);
}
- mdp_disable_irq(mgmt->irq_term);
return 0;
}
@@ -1102,6 +1142,7 @@
struct mdp_hist_mgmt *mgmt = container_of(data, struct mdp_hist_mgmt,
mdp_histogram_worker);
int ret = 0;
+ bool hist_ready;
mutex_lock(&mgmt->mdp_hist_mutex);
if (mgmt->mdp_is_hist_data == FALSE) {
pr_debug("%s, Histogram disabled before read.\n", __func__);
@@ -1116,8 +1157,9 @@
pr_err("mgmt->hist invalid NULL\n");
ret = -EINVAL;
}
+ hist_ready = (mgmt->mdp_is_hist_init && mgmt->mdp_is_hist_valid);
- if (!ret) {
+ if (!ret && hist_ready) {
switch (mgmt->block) {
case MDP_BLOCK_DMA_P:
case MDP_BLOCK_DMA_S:
@@ -1138,7 +1180,7 @@
* if read was triggered by an underrun or failed copying,
* don't wake up readers
*/
- if (!ret && mgmt->mdp_is_hist_valid && mgmt->mdp_is_hist_init) {
+ if (!ret && hist_ready) {
mgmt->hist = NULL;
if (waitqueue_active(&mgmt->mdp_hist_comp.wait))
complete(&mgmt->mdp_hist_comp);
@@ -1150,7 +1192,7 @@
mgmt->mdp_is_hist_init = TRUE;
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- if (!ret)
+ if (!ret && hist_ready)
__mdp_histogram_kickoff(mgmt);
else
__mdp_histogram_reset(mgmt);
@@ -1728,10 +1770,8 @@
isr &= mask;
if (isr & INTR_HIST_RESET_SEQ_DONE)
__mdp_histogram_kickoff(mgmt);
-
- if (isr & INTR_HIST_DONE) {
+ else if (isr & INTR_HIST_DONE)
queue_work(mdp_hist_wq, &mgmt->mdp_histogram_worker);
- }
}
#ifndef CONFIG_FB_MSM_MDP40
@@ -1741,7 +1781,6 @@
struct mdp_dma_data *dma;
unsigned long flag;
struct mdp_hist_mgmt *mgmt = NULL;
- char *base_addr;
int i, ret;
int vsync_isr;
/* Ensure all the register write are complete */
@@ -1813,13 +1852,7 @@
mgmt = mdp_hist_mgmt_array[i];
if (!mgmt)
continue;
-
- base_addr = MDP_BASE + mgmt->base;
- outpdw(base_addr + 0x010, 1);
- outpdw(base_addr + 0x01C, INTR_HIST_DONE |
- INTR_HIST_RESET_SEQ_DONE);
mgmt->mdp_is_hist_valid = FALSE;
- __mdp_histogram_reset(mgmt);
}
}
diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h
index 1397507..371174c 100644
--- a/drivers/video/msm/mdp.h
+++ b/drivers/video/msm/mdp.h
@@ -256,6 +256,7 @@
struct mdp_hist_mgmt {
uint32_t block;
uint32_t irq_term;
+ uint32_t intr;
uint32_t base;
struct completion mdp_hist_comp;
struct mutex mdp_hist_mutex;
@@ -323,6 +324,14 @@
#define TV_OUT_DMA3_START BIT(13)
#define MDP_HIST_DONE BIT(20)
+/*MDP4 MDP histogram interrupts*/
+/*note: these are only applicable on MDP4+ targets*/
+#define INTR_VG1_HISTOGRAM BIT(5)
+#define INTR_VG2_HISTOGRAM BIT(6)
+#define INTR_DMA_P_HISTOGRAM BIT(17)
+#define INTR_DMA_S_HISTOGRAM BIT(26)
+/*end MDP4 MDP histogram interrupts*/
+
/* histogram interrupts */
#define INTR_HIST_DONE BIT(1)
#define INTR_HIST_RESET_SEQ_DONE BIT(0)
@@ -337,7 +346,6 @@
MDP_DMA_S_DONE| \
MDP_DMA_E_DONE| \
LCDC_UNDERFLOW| \
- MDP_HIST_DONE| \
TV_ENC_UNDERRUN)
#endif
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index 6fc83df..005e87c 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -111,33 +111,23 @@
};
/* system interrupts */
+/*note histogram interrupts defined in mdp.h*/
#define INTR_OVERLAY0_DONE BIT(0)
#define INTR_OVERLAY1_DONE BIT(1)
#define INTR_DMA_S_DONE BIT(2)
#define INTR_DMA_E_DONE BIT(3)
#define INTR_DMA_P_DONE BIT(4)
-#define INTR_VG1_HISTOGRAM BIT(5)
-#define INTR_VG2_HISTOGRAM BIT(6)
#define INTR_PRIMARY_VSYNC BIT(7)
#define INTR_PRIMARY_INTF_UDERRUN BIT(8)
#define INTR_EXTERNAL_VSYNC BIT(9)
#define INTR_EXTERNAL_INTF_UDERRUN BIT(10)
#define INTR_PRIMARY_RDPTR BIT(11) /* read pointer */
-#define INTR_DMA_P_HISTOGRAM BIT(17)
-#define INTR_DMA_S_HISTOGRAM BIT(26)
#define INTR_OVERLAY2_DONE BIT(30)
#ifdef CONFIG_FB_MSM_OVERLAY
-#define MDP4_ANY_INTR_MASK (INTR_DMA_P_HISTOGRAM | \
- INTR_DMA_S_HISTOGRAM | \
- INTR_VG1_HISTOGRAM | \
- INTR_VG2_HISTOGRAM)
+#define MDP4_ANY_INTR_MASK (0)
#else
-#define MDP4_ANY_INTR_MASK (INTR_DMA_P_DONE| \
- INTR_DMA_P_HISTOGRAM | \
- INTR_DMA_S_HISTOGRAM | \
- INTR_VG1_HISTOGRAM | \
- INTR_VG2_HISTOGRAM)
+#define MDP4_ANY_INTR_MASK (INTR_DMA_P_DONE)
#endif
enum {
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 63f0aa1..18cf817 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -3092,6 +3092,7 @@
int mdp4_overlay_unset_mixer(int mixer)
{
struct mdp4_overlay_pipe *pipe;
+ struct mdp4_overlay_pipe *orgpipe;
int i, cnt = 0;
/* free pipe besides base layer pipe */
@@ -3103,6 +3104,10 @@
mdp4_overlay_reg_flush(pipe, 1);
mdp4_mixer_stage_down(pipe, 1);
mdp4_overlay_pipe_free(pipe);
+ /*Clear real pipe attributes as well */
+ orgpipe = mdp4_overlay_ndx2pipe(pipe->pipe_ndx);
+ if (orgpipe != NULL)
+ orgpipe->pipe_used = 0;
cnt++;
}
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index fcdccca..2d21929 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -677,6 +677,11 @@
/* adb stop */
if (pipe->pipe_type == OVERLAY_TYPE_BF)
mdp4_overlay_borderfill_stage_down(pipe);
+
+ /* base pipe may change after borderfill_stage_down */
+ pipe = vctrl->base_pipe;
+ mdp4_mixer_stage_down(pipe, 1);
+ mdp4_overlay_pipe_free(pipe);
vctrl->base_pipe = NULL;
} else {
/* system suspending */
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index f3bd775..f01543b 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -579,6 +579,10 @@
if (pipe->pipe_type == OVERLAY_TYPE_BF)
mdp4_overlay_borderfill_stage_down(pipe);
+ /* base pipe may change after borderfill_stage_down */
+ pipe = vctrl->base_pipe;
+ mdp4_mixer_stage_down(pipe, 1);
+ mdp4_overlay_pipe_free(pipe);
/* pipe == rgb2 */
vctrl->base_pipe = NULL;
} else {
@@ -1009,6 +1013,8 @@
}
mutex_lock(&mfd->dma->ov_mutex);
+ mdp4_overlay_mdp_perf_upd(mfd, 1);
mdp4_dtv_pipe_commit();
+ mdp4_overlay_mdp_perf_upd(mfd, 0);
mutex_unlock(&mfd->dma->ov_mutex);
}
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index 323a8fe..bc8ded5 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -664,6 +664,11 @@
/* adb stop */
if (pipe->pipe_type == OVERLAY_TYPE_BF)
mdp4_overlay_borderfill_stage_down(pipe);
+
+ /* base pipe may change after borderfill_stage_down */
+ pipe = vctrl->base_pipe;
+ mdp4_mixer_stage_down(pipe, 1);
+ mdp4_overlay_pipe_free(pipe);
vctrl->base_pipe = NULL;
} else {
/* system suspending */
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index 359f37e..b35acfb 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -500,7 +500,6 @@
uint32 isr, mask, panel;
struct mdp_dma_data *dma;
struct mdp_hist_mgmt *mgmt = NULL;
- char *base_addr;
int i, ret;
mdp_is_in_isr = TRUE;
@@ -528,12 +527,7 @@
mgmt = mdp_hist_mgmt_array[i];
if (!mgmt)
continue;
- base_addr = MDP_BASE + mgmt->base;
- MDP_OUTP(base_addr + 0x010, 1);
- outpdw(base_addr + 0x01c, INTR_HIST_DONE |
- INTR_HIST_RESET_SEQ_DONE);
mgmt->mdp_is_hist_valid = FALSE;
- __mdp_histogram_reset(mgmt);
}
}
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index 6f42565..758f074 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -15,6 +15,7 @@
#define MDSS_H
#include <linux/msm_ion.h>
+#include <linux/earlysuspend.h>
#include <linux/msm_mdp.h>
#include <linux/spinlock.h>
#include <linux/types.h>
@@ -74,6 +75,8 @@
struct ion_client *iclient;
int iommu_domain;
int iommu_attached;
+
+ struct early_suspend early_suspend;
};
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 e685785..e409a0b 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -100,17 +100,21 @@
return ret;
}
- ret = regulator_enable(dsi_drv.vdd_vreg);
- if (ret) {
- pr_err("%s: Failed to enable regulator.\n", __func__);
- return ret;
- }
-
ret = regulator_enable(dsi_drv.vdd_io_vreg);
if (ret) {
pr_err("%s: Failed to enable regulator.\n", __func__);
return ret;
}
+ msleep(20);
+ wmb();
+
+ ret = regulator_enable(dsi_drv.vdd_vreg);
+ if (ret) {
+ pr_err("%s: Failed to enable regulator.\n", __func__);
+ return ret;
+ }
+ msleep(20);
+ wmb();
ret = regulator_enable(dsi_drv.dsi_vreg);
if (ret) {
@@ -130,13 +134,13 @@
return ret;
}
- ret = regulator_disable(dsi_drv.vdd_io_vreg);
+ ret = regulator_disable(dsi_drv.dsi_vreg);
if (ret) {
pr_err("%s: Failed to disable regulator.\n", __func__);
return ret;
}
- ret = regulator_disable(dsi_drv.dsi_vreg);
+ ret = regulator_disable(dsi_drv.vdd_io_vreg);
if (ret) {
pr_err("%s: Failed to disable regulator.\n", __func__);
return ret;
@@ -165,11 +169,11 @@
return 0;
}
-static int mdss_dsi_off(struct mdss_panel_data *pdata)
+static int mdss_dsi_ctrl_unprepare(struct mdss_panel_data *pdata)
{
- int ret = 0;
struct mdss_panel_info *pinfo;
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+ int ret = 0;
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
panel_data);
@@ -180,9 +184,6 @@
pinfo = &pdata->panel_info;
- if (pdata->panel_info.type == MIPI_VIDEO_PANEL)
- mdss_dsi_controller_cfg(0, pdata);
-
mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata);
ret = ctrl_pdata->off(pdata);
@@ -191,16 +192,23 @@
return ret;
}
+ return ret;
+}
+
+static int mdss_dsi_off(struct mdss_panel_data *pdata)
+{
+ int ret = 0;
+
spin_lock_bh(&dsi_clk_lock);
mdss_dsi_clk_disable(pdata);
- /* disable dsi engine */
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004, 0);
-
spin_unlock_bh(&dsi_clk_lock);
mdss_dsi_unprepare_clocks();
+ /* disable DSI controller */
+ mdss_dsi_controller_cfg(0, pdata);
+
ret = mdss_dsi_panel_power_on(0);
if (ret) {
pr_err("%s: Panel power off failed\n", __func__);
@@ -232,11 +240,13 @@
pinfo = &pdata->panel_info;
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x118, 1);
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x118, 0);
+ ret = mdss_dsi_panel_power_on(1);
+ if (ret) {
+ pr_err("%s: Panel power on failed\n", __func__);
+ return ret;
+ }
mdss_dsi_phy_sw_reset((ctrl_pdata->ctrl_base));
- mdss_dsi_phy_enable((ctrl_pdata->ctrl_base), 1);
mdss_dsi_phy_init(pdata);
mdss_dsi_prepare_clocks();
@@ -312,12 +322,6 @@
wmb();
}
- ret = mdss_dsi_panel_power_on(1);
- if (ret) {
- pr_err("%s: Panel power on failed\n", __func__);
- return ret;
- }
-
ret = ctrl_pdata->on(pdata);
if (ret) {
pr_err("%s: unable to initialize the panel\n", __func__);
@@ -481,6 +485,7 @@
(ctrl_pdata->panel_data).on = mdss_dsi_on;
(ctrl_pdata->panel_data).off = mdss_dsi_off;
+ (ctrl_pdata->panel_data).intf_unprepare = mdss_dsi_ctrl_unprepare;
memcpy(&((ctrl_pdata->panel_data).panel_info),
&(panel_data->panel_info),
sizeof(struct mdss_panel_info));
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index e47891e..5d0d578 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -861,6 +861,16 @@
sleep_us, timeout_us))
pr_info("%s: FIFO status=%x failed\n", __func__, status);
+ /* Check for VIDEO_MODE_ENGINE_BUSY */
+ if (readl_poll_timeout(((ctrl_pdata->ctrl_base) + 0x0008),
+ status,
+ ((status & 0x08) == 0),
+ sleep_us, timeout_us)) {
+ pr_debug("%s: DSI status=%x\n", __func__, status);
+ pr_debug("%s: Doing sw reset\n", __func__);
+ mdss_dsi_sw_reset(pdata);
+ }
+
dsi_ctrl = MIPI_INP((ctrl_pdata->ctrl_base) + 0x0004);
if (enable)
dsi_ctrl |= 0x01;
@@ -884,14 +894,21 @@
return;
}
-
dsi_ctrl = MIPI_INP((ctrl_pdata->ctrl_base) + 0x0004);
- dsi_ctrl &= ~0x07;
+ /*If Video enabled, Keep Video and Cmd mode ON */
+ if (dsi_ctrl & 0x02)
+ dsi_ctrl &= ~0x05;
+ else
+ dsi_ctrl &= ~0x07;
+
if (mode == DSI_VIDEO_MODE) {
dsi_ctrl |= 0x03;
intr_ctrl = DSI_INTR_CMD_DMA_DONE_MASK;
} else { /* command mode */
dsi_ctrl |= 0x05;
+ if (pdata->panel_info.type == MIPI_VIDEO_PANEL)
+ dsi_ctrl |= 0x02;
+
intr_ctrl = DSI_INTR_CMD_DMA_DONE_MASK | DSI_INTR_ERROR_MASK |
DSI_INTR_CMD_MDP_DONE_MASK;
}
@@ -1102,6 +1119,7 @@
mdss_dsi_buf_init(tp);
mdss_dsi_cmd_dma_add(tp, pkt_size_cmd);
mdss_dsi_cmd_dma_tx(tp, pdata);
+ pr_debug("%s: Max packet size sent\n", __func__);
}
mdss_dsi_buf_init(tp);
@@ -1161,6 +1179,7 @@
rp->len -= diff; /* align bytes */
break;
default:
+ pr_debug("%s: Unknown cmd received\n", __func__);
break;
}
@@ -1261,6 +1280,8 @@
for (i = 0; i < cnt; i++) {
data = (u32)MIPI_INP((ctrl_pdata->ctrl_base) + off);
*lp++ = ntohl(data); /* to network byte order */
+ pr_debug("%s: data = 0x%x and ntohl(data) = 0x%x\n",
+ __func__, data, ntohl(data));
off -= 4;
rp->len += sizeof(*lp);
}
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index 63ad5cc..b247e4d 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -40,20 +40,6 @@
static int rst_gpio;
static int disp_en;
-struct qpnp_pin_cfg param = {
- .mode = QPNP_PIN_MODE_DIG_OUT,
- .output_type = QPNP_PIN_OUT_BUF_OPEN_DRAIN_NMOS,
- .invert = QPNP_PIN_INVERT_ENABLE,
- .pull = QPNP_PIN_MPP_PULL_UP_30KOHM,
- .vin_sel = QPNP_PIN_VIN3,
- .out_strength = QPNP_PIN_OUT_STRENGTH_HIGH,
- .select = QPNP_PIN_SEL_DTEST3,
- .master_en = QPNP_PIN_MASTER_ENABLE,
- .aout_ref = QPNP_PIN_AOUT_0V625,
- .ain_route = QPNP_PIN_AIN_AMUX_CH7,
- .cs_out = QPNP_PIN_CS_OUT_20MA,
-};
-
void mdss_dsi_panel_reset(int enable)
{
if (!disp_en)
@@ -64,13 +50,20 @@
pr_debug("%s:%d, reset line not configured\n",
__func__, __LINE__);
+ pr_debug("%s: enable = %d\n", __func__, enable);
+
if (enable) {
- gpio_set_value(disp_en, 1);
gpio_set_value(rst_gpio, 1);
- usleep(10);
+ msleep(20);
+ wmb();
gpio_set_value(rst_gpio, 0);
- usleep(200);
+ udelay(200);
+ wmb();
gpio_set_value(rst_gpio, 1);
+ msleep(20);
+ wmb();
+ gpio_set_value(disp_en, 1);
+ wmb();
} else {
gpio_set_value(rst_gpio, 0);
gpio_set_value(disp_en, 0);
@@ -113,7 +106,7 @@
pr_debug("%s:%d, debug info (mode) : %d\n", __func__, __LINE__,
mipi->mode);
- mdss_dsi_panel_reset(1);
+ mdss_dsi_sw_reset(pdata);
if (mipi->mode == DSI_VIDEO_MODE) {
mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf, dsi_panel_on_cmds,
@@ -142,8 +135,6 @@
return -EINVAL;
}
- mdss_dsi_panel_reset(0);
-
return 0;
}
@@ -202,14 +193,6 @@
pr_err("%s:%d, reset gpio not specified\n",
__func__, __LINE__);
} else {
- rc = qpnp_pin_config(rst_gpio, ¶m);
- if (rc) {
- pr_err("request reset gpio failed, rc=%d\n",
- rc);
- gpio_free(disp_en);
- return rc;
- }
-
rc = gpio_request(rst_gpio, "disp_rst_n");
if (rc) {
pr_err("request reset gpio failed, rc=%d\n",
@@ -328,7 +311,7 @@
panel_data->panel_info.mipi.frame_rate = (!rc ? tmp : 60);
data = of_get_property(np, "qcom,panel-phy-regulatorSettings", &len);
- if ((!data) || (len != 8)) {
+ if ((!data) || (len != 7)) {
pr_err("%s:%d, Unable to read Phy regulator settings",
__func__, __LINE__);
goto error;
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 06d8769..396407d 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -316,6 +316,9 @@
mfd->op_enable);
if (ret)
pr_warn("can't turn on display!\n");
+
+ if (mfd->vsync_pending)
+ mdss_mdp_overlay_vsync_ctrl(mfd, mfd->vsync_pending);
}
return ret;
@@ -326,7 +329,6 @@
struct fb_info *fbi;
int ret, i;
int result = 0;
- console_lock();
for (i = 0; i < fbi_list_index; i++) {
fbi = fbi_list[i];
fb_set_suspend(fbi, FBINFO_STATE_SUSPENDED);
@@ -337,7 +339,6 @@
result = ret;
}
}
- console_unlock();
return result;
}
@@ -347,7 +348,6 @@
int ret, i;
int result = 0;
- console_lock();
for (i = 0; i < fbi_list_index; i++) {
fbi = fbi_list[i];
@@ -355,7 +355,6 @@
if (ret == 0)
fb_set_suspend(fbi, FBINFO_STATE_RUNNING);
}
- console_unlock();
return result;
}
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index a10e5e4..80ebc4f 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -56,6 +56,7 @@
int op_enable;
u32 fb_imgType;
u32 dst_format;
+ int vsync_pending;
int hw_refresh;
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 3fb70bd..20fce7c 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -128,6 +128,8 @@
static DEFINE_SPINLOCK(mdss_lock);
struct mdss_hw *mdss_irq_handlers[MDSS_MAX_HW_BLK];
+static int mdss_mdp_register_early_suspend(struct mdss_data_type *mdata);
+
static inline int mdss_irq_dispatch(u32 hw_ndx, int irq, void *ptr)
{
struct mdss_hw *hw;
@@ -852,6 +854,16 @@
goto probe_done;
}
rc = mdss_mdp_bus_scale_register(mdata);
+ if (rc) {
+ pr_err("unable to register bus scaling\n");
+ goto probe_done;
+ }
+
+ rc = mdss_mdp_register_early_suspend(mdata);
+ if (rc) {
+ pr_err("unable to register early suspend\n");
+ goto probe_done;
+ }
probe_done:
if (IS_ERR_VALUE(rc)) {
mdss_res = NULL;
@@ -861,88 +873,154 @@
return rc;
}
-void mdss_mdp_footswitch_ctrl(int on)
+static void mdss_mdp_footswitch_ctrl(struct mdss_data_type *mdata, int on)
{
mutex_lock(&mdp_suspend_mutex);
- if (!mdss_res->suspend || mdss_res->eintf_ena || !mdss_res->fs) {
+ if (!mdata->suspend || mdata->eintf_ena || !mdata->fs) {
mutex_unlock(&mdp_suspend_mutex);
return;
}
- if (on && !mdss_res->fs_ena) {
+ if (on && !mdata->fs_ena) {
pr_debug("Enable MDP FS\n");
- regulator_enable(mdss_res->fs);
+ regulator_enable(mdata->fs);
mdss_iommu_attach();
- mdss_res->fs_ena = true;
- } else if (!on && mdss_res->fs_ena) {
+ mdata->fs_ena = true;
+ } else if (!on && mdata->fs_ena) {
pr_debug("Disable MDP FS\n");
mdss_iommu_dettach();
- regulator_disable(mdss_res->fs);
- mdss_res->fs_ena = false;
+ regulator_disable(mdata->fs);
+ mdata->fs_ena = false;
}
mutex_unlock(&mdp_suspend_mutex);
}
-#ifdef CONFIG_PM
-static void mdss_mdp_suspend_sub(void)
-{
- cancel_delayed_work(&mdss_res->clk_ctrl_worker);
-
- flush_workqueue(mdss_res->clk_ctrl_wq);
-
- mdss_mdp_clk_ctrl(MDP_BLOCK_MASTER_OFF, false);
-
- mutex_lock(&mdp_suspend_mutex);
- mdss_res->suspend = true;
- mutex_unlock(&mdp_suspend_mutex);
-}
-
-static int mdss_mdp_suspend(struct platform_device *pdev, pm_message_t state)
+static inline int mdss_mdp_suspend_sub(struct mdss_data_type *mdata)
{
int ret;
- pr_debug("display suspend");
ret = mdss_fb_suspend_all();
if (IS_ERR_VALUE(ret)) {
pr_err("Unable to suspend all fb panels (%d)\n", ret);
return ret;
}
- mdss_mdp_suspend_sub();
- if (mdss_res->clk_ena) {
+
+ cancel_delayed_work(&mdata->clk_ctrl_worker);
+
+ flush_workqueue(mdata->clk_ctrl_wq);
+
+ mdss_mdp_clk_ctrl(MDP_BLOCK_MASTER_OFF, false);
+
+ mutex_lock(&mdp_suspend_mutex);
+ mdata->suspend = true;
+ mutex_unlock(&mdp_suspend_mutex);
+
+ if (mdata->clk_ena) {
pr_err("MDP suspend failed\n");
return -EBUSY;
}
- mdss_mdp_footswitch_ctrl(false);
+ mdss_mdp_footswitch_ctrl(mdata, false);
+
+ pr_debug("suspend done\n");
return 0;
}
+static inline int mdss_mdp_resume_sub(struct mdss_data_type *mdata)
+{
+ int ret = 0;
+
+ mdss_mdp_footswitch_ctrl(mdata, true);
+ mutex_lock(&mdp_suspend_mutex);
+ mdata->suspend = false;
+ mutex_unlock(&mdp_suspend_mutex);
+ mdss_hw_init(mdata);
+ ret = mdss_fb_resume_all();
+ if (IS_ERR_VALUE(ret))
+ pr_err("Unable to resume all fb panels (%d)\n", ret);
+
+ pr_debug("resume done\n");
+
+ return ret;
+}
+
+#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND)
+static int mdss_mdp_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct mdss_data_type *mdata = platform_get_drvdata(pdev);
+
+ if (!mdata)
+ return -ENODEV;
+
+ pr_debug("display suspend\n");
+
+ return mdss_mdp_suspend_sub(mdata);
+}
+
static int mdss_mdp_resume(struct platform_device *pdev)
{
struct mdss_data_type *mdata = platform_get_drvdata(pdev);
- int ret = 0;
if (!mdata)
return -ENODEV;
- pr_debug("resume display");
+ pr_debug("display resume\n");
- mdss_mdp_footswitch_ctrl(true);
- mutex_lock(&mdp_suspend_mutex);
- mdss_res->suspend = false;
- mutex_unlock(&mdp_suspend_mutex);
- ret = mdss_fb_resume_all();
- if (IS_ERR_VALUE(ret))
- pr_err("Unable to resume all fb panels (%d)\n", ret);
-
- mdss_hw_init(mdata);
- return ret;
+ return mdss_mdp_resume_sub(mdata);
}
#else
#define mdss_mdp_suspend NULL
#define mdss_mdp_resume NULL
#endif
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void mdss_mdp_early_suspend(struct early_suspend *h)
+{
+ struct mdss_data_type *mdata;
+ mdata = container_of(h, struct mdss_data_type, early_suspend);
+
+ pr_debug("display early suspend\n");
+
+ mdss_mdp_suspend_sub(mdata);
+}
+
+static void mdss_mdp_late_resume(struct early_suspend *h)
+{
+ struct mdss_data_type *mdata;
+ mdata = container_of(h, struct mdss_data_type, early_suspend);
+
+ pr_debug("display early resume\n");
+
+ mdss_mdp_resume_sub(mdata);
+}
+
+static int mdss_mdp_register_early_suspend(struct mdss_data_type *mdata)
+{
+ mdata->early_suspend.suspend = mdss_mdp_early_suspend;
+ mdata->early_suspend.resume = mdss_mdp_late_resume;
+ mdata->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN;
+ register_early_suspend(&mdata->early_suspend);
+
+ return 0;
+}
+
+static int mdss_mdp_remove_early_suspend(struct mdss_data_type *mdata)
+{
+ unregister_early_suspend(&mdata->early_suspend);
+
+ return 0;
+}
+#else
+static int mdss_mdp_register_early_suspend(struct mdss_data_type *mdata)
+{
+ return 0;
+}
+static int mdss_mdp_remove_early_suspend(struct mdss_data_type *mdata)
+{
+ return 0;
+}
+#endif
+
static int mdss_mdp_remove(struct platform_device *pdev)
{
struct mdss_data_type *mdata = platform_get_drvdata(pdev);
@@ -951,6 +1029,7 @@
pm_runtime_disable(&pdev->dev);
mdss_mdp_pp_term(&pdev->dev);
mdss_mdp_bus_scale_unregister(mdata);
+ mdss_mdp_remove_early_suspend(mdata);
return 0;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 610c132..8a9f9c9 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -275,10 +275,10 @@
unsigned long mdss_mdp_get_clk_rate(u32 clk_idx);
int mdss_mdp_vsync_clk_enable(int enable);
void mdss_mdp_clk_ctrl(int enable, int isr);
-void mdss_mdp_footswitch_ctrl(int on);
int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd);
int mdss_mdp_overlay_release_all(struct msm_fb_data_type *mfd);
+int mdss_mdp_overlay_vsync_ctrl(struct msm_fb_data_type *mfd, int en);
int mdss_mdp_video_start(struct mdss_mdp_ctl *ctl);
int mdss_mdp_writeback_start(struct mdss_mdp_ctl *ctl);
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 26fbca1..f72ff8d 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -494,6 +494,11 @@
}
ctl = mfd->ctl;
+ if (ctl->power_on) {
+ WARN(1, "already on!\n");
+ return 0;
+ }
+
mutex_lock(&ctl->lock);
ctl->power_on = true;
@@ -571,12 +576,30 @@
ctl = mfd->ctl;
+ if (!ctl->power_on) {
+ WARN(1, "already off!\n");
+ return 0;
+ }
+
pr_debug("ctl_num=%d\n", mfd->ctl->num);
+ mdss_mdp_overlay_release_all(mfd);
+
+ /* request bus bandwidth for panel commands */
+ ctl->bus_ib_quota = SZ_1M;
+ mdss_mdp_ctl_perf_commit(MDSS_MDP_PERF_UPDATE_ALL);
+
mutex_lock(&ctl->lock);
ctl->power_on = false;
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
+ if (pdata->intf_unprepare)
+ ret = pdata->intf_unprepare(pdata);
+
+ if (ret)
+ pr_err("%s: intf_unprepare failed\n", __func__);
+
if (ctl->stop_fnc)
ret = ctl->stop_fnc(ctl);
else
@@ -586,6 +609,7 @@
pr_warn("error powering off intf ctl=%d\n", ctl->num);
ret = pdata->off(pdata);
+
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
ctl->play_cnt = 0;
@@ -594,8 +618,6 @@
mutex_unlock(&ctl->lock);
- mdss_mdp_overlay_release_all(mfd);
-
if (!mfd->ref_cnt)
mdss_mdp_ctl_destroy(mfd);
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index 5d8dd86..3c7c362 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -183,7 +183,7 @@
if (mutex_lock_interruptible(&ctx->vsync_lock))
return -EINTR;
- if (!ctx->timegen_en) {
+ if (vsync_handler && !ctx->timegen_en) {
ctx->vsync_time = ktime_get();
schedule_work(&ctx->vsync_work);
}
@@ -213,6 +213,9 @@
return -ENODEV;
}
+ if (ctx->vsync_handler)
+ mdss_mdp_video_set_vsync_handler(ctl, NULL);
+
if (ctx->timegen_en) {
off = MDSS_MDP_REG_INTF_OFFSET(ctl->intf_num);
MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 0);
@@ -274,6 +277,7 @@
}
if (ctx->timegen_en) {
+ INIT_COMPLETION(ctx->pp_comp);
pr_debug("waiting for ping pong %d done\n", ctx->pp_num);
mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num);
wait_for_completion_interruptible(&ctx->pp_comp);
@@ -312,7 +316,7 @@
wmb();
}
- wait_for_completion_interruptible(&ctx->vsync_comp);
+ wait_for_completion(&ctx->vsync_comp);
if (!ctx->vsync_handler)
mdss_mdp_irq_disable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
mutex_unlock(&ctx->vsync_lock);
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index e8e8163..bb400bc 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -765,7 +765,7 @@
pr_debug("sent vsync on ctl=%d ts=%llu\n", ctl->num, ktime_to_ns(t));
}
-static int mdss_mdp_overlay_vsync_ctrl(struct msm_fb_data_type *mfd, int en)
+int mdss_mdp_overlay_vsync_ctrl(struct msm_fb_data_type *mfd, int en)
{
struct mdss_mdp_ctl *ctl = mfd->ctl;
int rc;
@@ -777,6 +777,11 @@
pr_debug("vsync en=%d\n", en);
+ if (!ctl->power_on) {
+ mfd->vsync_pending = en;
+ return 0;
+ }
+
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
if (en)
rc = ctl->set_vsync_handler(ctl, mdss_mdp_overlay_handle_vsync);
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index f1a4e50..5cdfe34 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -86,7 +86,7 @@
/* DSI PHY configuration */
struct mdss_dsi_phy_ctrl {
- uint32_t regulator[8];
+ uint32_t regulator[7];
uint32_t timing[12];
uint32_t ctrl[4];
uint32_t strength[2];
@@ -180,6 +180,7 @@
struct mdss_panel_info panel_info;
void (*set_backlight) (struct mdss_panel_data *pdata,
u32 bl_level);
+ int (*intf_unprepare) (struct mdss_panel_data *pdata);
unsigned char *mmss_cc_base;
/* function entry chain */
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index 545d53c..1232ec6 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -212,25 +212,34 @@
{
/* start phy sw reset */
MIPI_OUTP(ctrl_base + 0x12c, 0x0001);
+ udelay(1000);
wmb();
- usleep(1);
/* end phy sw reset */
MIPI_OUTP(ctrl_base + 0x12c, 0x0000);
+ udelay(100);
wmb();
- usleep(1);
}
void mdss_dsi_phy_enable(unsigned char *ctrl_base, int on)
{
if (on) {
+ MIPI_OUTP(ctrl_base + 0x03cc, 0x03);
+ wmb();
+ usleep(100);
MIPI_OUTP(ctrl_base + 0x0220, 0x006);
- usleep(10);
+ wmb();
+ usleep(100);
MIPI_OUTP(ctrl_base + 0x0268, 0x001);
- usleep(10);
+ wmb();
+ usleep(100);
MIPI_OUTP(ctrl_base + 0x0268, 0x000);
- usleep(10);
+ wmb();
+ usleep(100);
MIPI_OUTP(ctrl_base + 0x0220, 0x007);
wmb();
+ MIPI_OUTP(ctrl_base + 0x03cc, 0x01);
+ wmb();
+ usleep(100);
/* MMSS_DSI_0_PHY_DSIPHY_CTRL_0 */
MIPI_OUTP(ctrl_base + 0x0470, 0x07e);
@@ -266,12 +275,25 @@
pd = ((ctrl_pdata->panel_data).panel_info.mipi).dsi_phy_db;
+ /* Strength ctrl 0 */
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0484, 0x07);
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0484, pd->strength[0]);
+
off = 0x0580; /* phy regulator ctrl settings */
- for (i = 0; i < 8; i++) {
- MIPI_OUTP((ctrl_pdata->ctrl_base) + off, pd->regulator[i]);
- wmb();
- off += 4;
- }
+ /* Regulator ctrl - CAL_PWD_CFG */
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 6), pd->regulator[6]);
+ /* Regulator ctrl - TEST */
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 5), pd->regulator[5]);
+ /* Regulator ctrl 3 */
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 3), pd->regulator[3]);
+ /* Regulator ctrl 2 */
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 2), pd->regulator[2]);
+ /* Regulator ctrl 1 */
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 1), pd->regulator[1]);
+ /* Regulator ctrl 0 */
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 0), pd->regulator[0]);
+ /* Regulator ctrl 4 */
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 4), pd->regulator[4]);
off = 0x0440; /* phy timing ctrl 0 - 11 */
for (i = 0; i < 12; i++) {
@@ -280,17 +302,15 @@
off += 4;
}
- /* Strength ctrl 0 - 1 */
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0484, pd->strength[0]);
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0488, pd->strength[1]);
+ /* MMSS_DSI_0_PHY_DSIPHY_CTRL_1 */
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0474, 0x00);
+ /* MMSS_DSI_0_PHY_DSIPHY_CTRL_0 */
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0470, 0x5f);
wmb();
- off = 0x04b4; /* phy BIST ctrl 0 - 5 */
- for (i = 0; i < 6; i++) {
- MIPI_OUTP((ctrl_pdata->ctrl_base) + off, pd->bistCtrl[i]);
- wmb();
- off += 4;
- }
+ /* Strength ctrl 1 */
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0488, pd->strength[1]);
+ wmb();
/* 4 lanes + clk lane configuration */
/* lane config n * (0 - 4) & DataPath setup */
@@ -304,4 +324,20 @@
off += 4;
}
}
+
+ /* MMSS_DSI_0_PHY_DSIPHY_CTRL_0 */
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0470, 0x7f);
+ wmb();
+
+ /* DSI_0_PHY_DSIPHY_GLBL_TEST_CTRL */
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x04d4, 0x01);
+ wmb();
+
+ off = 0x04b4; /* phy BIST ctrl 0 - 5 */
+ for (i = 0; i < 6; i++) {
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + off, pd->bistCtrl[i]);
+ wmb();
+ off += 4;
+ }
+
}
diff --git a/drivers/video/msm/mipi_NT35510.c b/drivers/video/msm/mipi_NT35510.c
index 0c6ff79..d75198a 100644
--- a/drivers/video/msm/mipi_NT35510.c
+++ b/drivers/video/msm/mipi_NT35510.c
@@ -32,8 +32,8 @@
static char write_ram[2] = {0x2c, 0x00}; /* write ram */
static struct dsi_cmd_desc nt35510_display_off_cmds[] = {
- {DTYPE_DCS_WRITE, 1, 0, 0, 150, sizeof(display_off), display_off},
- {DTYPE_DCS_WRITE, 1, 0, 0, 150, sizeof(enter_sleep), enter_sleep}
+ {DTYPE_DCS_WRITE, 1, 0, 0, 50, sizeof(display_off), display_off},
+ {DTYPE_DCS_WRITE, 1, 0, 0, 50, sizeof(enter_sleep), enter_sleep}
};
static char cmd0[6] = {
@@ -213,46 +213,46 @@
};
static char config_MADCTL[2] = {0x36, 0x00};
static struct dsi_cmd_desc nt35510_cmd_display_on_cmds[] = {
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd0), cmd0},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd1), cmd1},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd2), cmd2},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd3), cmd3},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd4), cmd4},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd5), cmd5},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd6), cmd6},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd7), cmd7},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd8), cmd8},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd9), cmd9},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd10), cmd10},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd11), cmd11},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd12), cmd12},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd13), cmd13},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd14), cmd14},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd15), cmd15},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd16), cmd16},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd17), cmd17},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd18), cmd18},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd19), cmd19},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd20), cmd20},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd21), cmd21},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd22), cmd22},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd23), cmd23},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd24), cmd24},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd25), cmd25},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd26), cmd26},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd27), cmd27},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd0), cmd0},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd1), cmd1},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd2), cmd2},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd3), cmd3},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd4), cmd4},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd5), cmd5},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd6), cmd6},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd7), cmd7},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd8), cmd8},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd9), cmd9},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd10), cmd10},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd11), cmd11},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd12), cmd12},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd13), cmd13},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd14), cmd14},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd15), cmd15},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd16), cmd16},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd17), cmd17},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd18), cmd18},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd19), cmd19},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd20), cmd20},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd21), cmd21},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd22), cmd22},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd23), cmd23},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd24), cmd24},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd25), cmd25},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd26), cmd26},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd27), cmd27},
- {DTYPE_DCS_WRITE, 1, 0, 0, 150, sizeof(exit_sleep), exit_sleep},
- {DTYPE_DCS_WRITE, 1, 0, 0, 10, sizeof(display_on), display_on},
+ {DTYPE_DCS_WRITE, 1, 0, 0, 0, sizeof(exit_sleep), exit_sleep},
+ {DTYPE_DCS_WRITE, 1, 0, 0, 0, sizeof(display_on), display_on},
- {DTYPE_DCS_WRITE1, 1, 0, 0, 150,
+ {DTYPE_DCS_WRITE1, 1, 0, 0, 0,
sizeof(config_MADCTL), config_MADCTL},
- {DTYPE_DCS_WRITE, 1, 0, 0, 10, sizeof(write_ram), write_ram},
+ {DTYPE_DCS_WRITE, 1, 0, 0, 0, sizeof(write_ram), write_ram},
};
static struct dsi_cmd_desc nt35510_cmd_display_on_cmds_rotate[] = {
- {DTYPE_DCS_LWRITE, 1, 0, 0, 50,
+ {DTYPE_DCS_LWRITE, 1, 0, 0, 0,
sizeof(cmd19_rotate), cmd19_rotate},
};
@@ -430,34 +430,34 @@
};
static char config_video_MADCTL[2] = {0x36, 0xC0};
static struct dsi_cmd_desc nt35510_video_display_on_cmds[] = {
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video0), video0},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video1), video1},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video2), video2},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video3), video3},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video4), video4},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video5), video5},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video6), video6},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video7), video7},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video8), video8},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video9), video9},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video10), video10},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video11), video11},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video12), video12},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video13), video13},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video14), video14},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video15), video15},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video16), video16},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video17), video17},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video18), video18},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video19), video19},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video20), video20},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video21), video21},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video22), video22},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video23), video23},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video24), video24},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video25), video25},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video26), video26},
- {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video27), video27},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video0), video0},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video1), video1},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video2), video2},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video3), video3},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video4), video4},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video5), video5},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video6), video6},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video7), video7},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video8), video8},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video9), video9},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video10), video10},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video11), video11},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video12), video12},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video13), video13},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video14), video14},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video15), video15},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video16), video16},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video17), video17},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video18), video18},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video19), video19},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video20), video20},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video21), video21},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video22), video22},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video23), video23},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video24), video24},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video25), video25},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video26), video26},
+ {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video27), video27},
{DTYPE_DCS_WRITE, 1, 0, 0, NT35510_SLEEP_OFF_DELAY, sizeof(exit_sleep),
exit_sleep},
{DTYPE_DCS_WRITE, 1, 0, 0, NT35510_DISPLAY_ON_DELAY, sizeof(display_on),
@@ -465,7 +465,7 @@
};
static struct dsi_cmd_desc nt35510_video_display_on_cmds_rotate[] = {
- {DTYPE_DCS_WRITE1, 1, 0, 0, 150,
+ {DTYPE_DCS_WRITE1, 1, 0, 0, 0,
sizeof(config_video_MADCTL), config_video_MADCTL},
};
static int mipi_nt35510_lcd_on(struct platform_device *pdev)
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
index 4f19de9..d94bc5b 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
@@ -1258,6 +1258,8 @@
output_vcd_frm->flags |=
VCD_FRAME_FLAG_DATACORRUPT;
}
+ if (decoder->codec.codec != VCD_CODEC_H264)
+ output_vcd_frm->flags &= ~VCD_FRAME_FLAG_DATACORRUPT;
output_vcd_frm->ip_frm_tag = dec_disp_info->tag_top;
vidc_sm_get_picture_times(&ddl->shared_mem
[ddl->command_channel],
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
index 596c86f..931c1c8 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
@@ -1859,6 +1859,7 @@
struct vcd_buffer_requirement *input_buf_req;
struct vcd_buffer_requirement *output_buf_req;
u32 min_dpb, y_cb_cr_size;
+ u32 frame_height_actual = 0;
if (!decoder->codec.codec)
return false;
@@ -1882,6 +1883,7 @@
if ((decoder->buf_format.buffer_format ==
VCD_BUFFER_FORMAT_TILE_4x2) &&
(frame_size->height < MDP_MIN_TILE_HEIGHT)) {
+ frame_height_actual = frame_size->height;
frame_size->height = MDP_MIN_TILE_HEIGHT;
ddl_calculate_stride(frame_size,
!decoder->progressive_only);
@@ -1920,6 +1922,10 @@
input_buf_req->sz = (1024 * 1024 * 2);
input_buf_req->align = DDL_LINEAR_BUFFER_ALIGN_BYTES;
decoder->min_input_buf_req = *input_buf_req;
+ if (frame_height_actual) {
+ frame_size->height = frame_height_actual;
+ ddl_calculate_stride(frame_size, !decoder->progressive_only);
+ }
return true;
}
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
index 978d1de..4687915 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
@@ -15,6 +15,7 @@
#include "vcd_ddl_metadata.h"
#include "vcd_ddl_shared_mem.h"
#include "vcd_core.h"
+#include "vcd_res_tracker_api.h"
#if defined(PIX_CACHE_DISABLE)
#define DDL_PIX_CACHE_ENABLE false
@@ -108,7 +109,8 @@
dec_pix_cache = VIDC_1080P_DECODE_PCACHE_DISABLE;
const enum vidc_1080p_encode_p_cache_enable
enc_pix_cache = VIDC_1080P_ENCODE_PCACHE_ENABLE;
- u32 pix_cache_ctrl, ctxt_mem_offset, ctxt_mem_size;
+ u32 pix_cache_ctrl, ctxt_mem_offset, ctxt_mem_size, arg1 = 0;
+ u8 *hw_ctxt = NULL;
if (ddl->decoding) {
ddl_set_core_start_time(__func__, DEC_OP_TIME);
@@ -116,6 +118,8 @@
pix_cache_ctrl = (u32)dec_pix_cache;
ctxt_mem_offset = DDL_ADDR_OFFSET(ddl_context->dram_base_a,
ddl->codec_data.decoder.hw_bufs.context) >> 11;
+ hw_ctxt =
+ ddl->codec_data.decoder.hw_bufs.context.virtual_base_addr;
ctxt_mem_size =
ddl->codec_data.decoder.hw_bufs.context.buffer_size;
} else {
@@ -123,9 +127,15 @@
pix_cache_ctrl = (u32)enc_pix_cache;
ctxt_mem_offset = DDL_ADDR_OFFSET(ddl_context->dram_base_a,
ddl->codec_data.encoder.hw_bufs.context) >> 11;
+ hw_ctxt =
+ ddl->codec_data.encoder.hw_bufs.context.virtual_base_addr;
ctxt_mem_size =
ddl->codec_data.encoder.hw_bufs.context.buffer_size;
}
+ if (!res_trk_check_for_sec_session() && hw_ctxt) {
+ memset(hw_ctxt, 0, ctxt_mem_size);
+ arg1 = 1 << 29;
+ }
switch (*vcd_codec) {
default:
case VCD_CODEC_MPEG4:
@@ -184,8 +194,9 @@
DDL_MSG_LOW("ddl_state_transition: %s ~~> DDL_CLIENT_WAIT_FOR_CHDONE",
ddl_get_state_string(ddl->client_state));
ddl->client_state = DDL_CLIENT_WAIT_FOR_CHDONE;
+ arg1 |= (u32)codec;
vidc_1080p_set_host2risc_cmd(VIDC_1080P_HOST2RISC_CMD_OPEN_CH,
- (u32)codec, pix_cache_ctrl, ctxt_mem_offset,
+ arg1, pix_cache_ctrl, ctxt_mem_offset,
ctxt_mem_size);
}
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index 45d51ce..288ed43 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -109,7 +109,7 @@
/* 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 0x08AD
+#define EVENT_LAST_ID 0x08C5
#define MSG_SSID_0 0
#define MSG_SSID_0_LAST 93
diff --git a/include/linux/dvb/dmx.h b/include/linux/dvb/dmx.h
index d19dfa5..257e069 100644
--- a/include/linux/dvb/dmx.h
+++ b/include/linux/dvb/dmx.h
@@ -307,6 +307,22 @@
} params;
};
+/* Filter's buffer requirement returned in dmx_caps */
+struct dmx_buffer_requirement {
+ /* Buffer size alignment, 0 means no special requirement */
+ __u32 size_alignment;
+
+ /* Maximum buffer size allowed */
+ __u32 max_size;
+ __u32 flags;
+
+/* Buffer allocated as physically contiguous memory */
+#define DMX_BUFFER_CONTIGEOUS_MEM 0x1
+
+/* If the filter's data is decrypted, the buffer should be secured one */
+#define DMX_BUFFER_SECURED_IF_DECRYPTED 0x2
+};
+
typedef struct dmx_caps {
__u32 caps;
@@ -363,6 +379,23 @@
/* Max bitrate from single memory input. Mbit/sec */
int memory_input_max_bitrate;
+
+ struct dmx_buffer_requirement section;
+
+ /* For PES not sent to decoder */
+ struct dmx_buffer_requirement pes;
+
+ /* Recording buffer for recording of 188 bytes packets */
+ struct dmx_buffer_requirement recording_188_tsp;
+
+ /* Recording buffer for recording of 192 bytes packets */
+ struct dmx_buffer_requirement recording_192_tsp;
+
+ /* DVR input buffer for playback of 188 bytes packets */
+ struct dmx_buffer_requirement playback_188_tsp;
+
+ /* DVR input buffer for playback of 192 bytes packets */
+ struct dmx_buffer_requirement playback_192_tsp;
} dmx_caps_t;
typedef enum {
@@ -410,6 +443,28 @@
__u64 stc; /* output: stc in 'base'*90 kHz units */
};
+enum dmx_buffer_mode {
+ /*
+ * demux buffers are allocated internally
+ * by the demux driver. This is the default mode.
+ * DMX_SET_BUFFER_SIZE can be used to set the size of
+ * this buffer.
+ */
+ DMX_BUFFER_MODE_INTERNAL,
+
+ /*
+ * demux buffers are allocated externally and provided
+ * to demux through DMX_SET_BUFFER.
+ * When this mode is used DMX_SET_BUFFER_SIZE and
+ * mmap are prohibited.
+ */
+ DMX_BUFFER_MODE_EXTERNAL,
+};
+
+struct dmx_buffer {
+ unsigned int size;
+ int handle;
+};
#define DMX_START _IO('o', 41)
#define DMX_STOP _IO('o', 42)
@@ -430,5 +485,7 @@
#define DMX_FEED_DATA _IO('o', 58)
#define DMX_SET_PLAYBACK_MODE _IOW('o', 59, enum dmx_playback_mode_t)
#define DMX_GET_EVENT _IOR('o', 60, struct dmx_filter_event)
+#define DMX_SET_BUFFER_MODE _IOW('o', 61, enum dmx_buffer_mode)
+#define DMX_SET_BUFFER _IOW('o', 62, struct dmx_buffer)
#endif /*_DVBDMX_H_*/
diff --git a/include/linux/epm_adc.h b/include/linux/epm_adc.h
index 076302b..b7b7d90 100644
--- a/include/linux/epm_adc.h
+++ b/include/linux/epm_adc.h
@@ -64,12 +64,19 @@
uint32_t channel_mask;
};
+struct result_buffer {
+ uint32_t channel;
+ uint32_t avg_buffer_sample;
+ uint32_t result;
+};
+
struct epm_psoc_get_avg_buffered_switch_data {
- u8 cmd;
- u8 status;
- uint32_t timestamp_start;
- uint32_t channel_mask;
- u8 avg_data[54];
+ u8 cmd;
+ u8 status;
+ uint32_t timestamp_start;
+ uint32_t channel_mask;
+ u8 avg_data[54];
+ struct result_buffer data[54];
};
struct epm_psoc_set_channel_switch {
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 19ca831..87e06ed 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -79,12 +79,12 @@
bool hpi_en; /* HPI enablebit */
bool hpi; /* HPI support bit */
unsigned int hpi_cmd; /* cmd used as HPI */
+ bool bkops; /* background support bit */
+ bool bkops_en; /* background enable bit */
unsigned int data_sector_size; /* 512 bytes or 4KB */
unsigned int data_tag_unit_size; /* DATA TAG UNIT size */
unsigned int boot_ro_lock; /* ro lock support */
bool boot_ro_lockable;
- bool bkops; /* background support bit */
- bool bkops_en; /* background enable bit */
u8 raw_exception_status; /* 53 */
u8 raw_partition_support; /* 160 */
u8 raw_erased_mem_count; /* 181 */
@@ -251,9 +251,7 @@
#define MMC_CARD_REMOVED (1<<7) /* card has been removed */
#define MMC_STATE_HIGHSPEED_200 (1<<8) /* card is in HS200 mode */
#define MMC_STATE_SLEEP (1<<9) /* card is in sleep state */
-#define MMC_STATE_NEED_BKOPS (1<<10) /* card need to do BKOPS */
-#define MMC_STATE_DOING_BKOPS (1<<11) /* card is doing BKOPS */
-#define MMC_STATE_CHECK_BKOPS (1<<12) /* card need to check BKOPS */
+#define MMC_STATE_DOING_BKOPS (1<<10) /* card is doing BKOPS */
unsigned int quirks; /* card quirks */
#define MMC_QUIRK_LENIENT_FN0 (1<<0) /* allow SDIO FN0 writes outside of the VS CCCR range */
#define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func->cur_blksize */
@@ -422,9 +420,7 @@
#define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
#define mmc_card_removed(c) ((c) && ((c)->state & MMC_CARD_REMOVED))
#define mmc_card_is_sleep(c) ((c)->state & MMC_STATE_SLEEP)
-#define mmc_card_need_bkops(c) ((c)->state & MMC_STATE_NEED_BKOPS)
#define mmc_card_doing_bkops(c) ((c)->state & MMC_STATE_DOING_BKOPS)
-#define mmc_card_check_bkops(c) ((c)->state & MMC_STATE_CHECK_BKOPS)
#define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT)
#define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
@@ -437,13 +433,9 @@
#define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
#define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
#define mmc_card_set_sleep(c) ((c)->state |= MMC_STATE_SLEEP)
-#define mmc_card_set_need_bkops(c) ((c)->state |= MMC_STATE_NEED_BKOPS)
#define mmc_card_set_doing_bkops(c) ((c)->state |= MMC_STATE_DOING_BKOPS)
-#define mmc_card_set_check_bkops(c) ((c)->state |= MMC_STATE_CHECK_BKOPS)
-#define mmc_card_clr_need_bkops(c) ((c)->state &= ~MMC_STATE_NEED_BKOPS)
#define mmc_card_clr_doing_bkops(c) ((c)->state &= ~MMC_STATE_DOING_BKOPS)
-#define mmc_card_clr_check_bkops(c) ((c)->state &= ~MMC_STATE_CHECK_BKOPS)
#define mmc_card_clr_sleep(c) ((c)->state &= ~MMC_STATE_SLEEP)
/*
* Quirk add/remove for MMC products.
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 338c891..3f26a80 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -138,9 +138,8 @@
struct mmc_card;
struct mmc_async_req;
-extern int mmc_interrupt_bkops(struct mmc_card *);
+extern int mmc_stop_bkops(struct mmc_card *);
extern int mmc_read_bkops_status(struct mmc_card *);
-extern int mmc_is_exception_event(struct mmc_card *, unsigned int);
extern struct mmc_async_req *mmc_start_req(struct mmc_host *,
struct mmc_async_req *, int *);
extern int mmc_interrupt_hpi(struct mmc_card *);
@@ -149,6 +148,8 @@
extern int mmc_app_cmd(struct mmc_host *, struct mmc_card *);
extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *,
struct mmc_command *, int);
+extern void mmc_start_bkops(struct mmc_card *card, bool from_exception);
+extern int __mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int, bool);
extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int);
extern int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
@@ -172,7 +173,6 @@
extern int mmc_can_poweroff_notify(const struct mmc_card *card);
extern int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from,
unsigned int nr);
-extern void mmc_start_bkops(struct mmc_card *card);
extern unsigned int mmc_calc_max_discard(struct mmc_card *card);
extern int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen);
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 05a6b5b..dcd9a6f 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -247,8 +247,6 @@
MMC_CAP2_PACKED_WR) /* Allow packed commands */
#define MMC_CAP2_PACKED_WR_CONTROL (1 << 12) /* Allow write packing control */
#define MMC_CAP2_SANITIZE (1 << 13) /* Support Sanitize */
-#define MMC_CAP2_BKOPS (1 << 14) /* BKOPS supported */
-#define MMC_CAP2_INIT_BKOPS (1 << 15) /* Need to set BKOPS_EN */
#define MMC_CAP2_POWER_OFF_VCCQ_DURING_SUSPEND (1 << 16)
mmc_pm_flag_t pm_caps; /* supported pm features */
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index b867c62..87cdba8 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -402,12 +402,23 @@
#define EXT_CSD_PACKED_EVENT_EN (1 << 3)
-#define EXT_CSD_PACKED_FAILURE (1 << 3)
-
#define EXT_CSD_PACKED_GENERIC_ERROR (1 << 0)
#define EXT_CSD_PACKED_INDEXED_ERROR (1 << 1)
/*
+ * EXCEPTION_EVENT_STATUS field
+ */
+#define EXT_CSD_URGENT_BKOPS BIT(0)
+#define EXT_CSD_DYNCAP_NEEDED BIT(1)
+#define EXT_CSD_SYSPOOL_EXHAUSTED BIT(2)
+#define EXT_CSD_PACKED_FAILURE BIT(3)
+
+/*
+ * BKOPS status level
+ */
+#define EXT_CSD_BKOPS_LEVEL_2 0x2
+
+/*
* MMC_SWITCH access modes
*/
@@ -423,16 +434,4 @@
#define MMC_PW_OFF_NOTIFY_SHORT 1
#define MMC_PW_OFF_NOTIFY_LONG 2
-/*
- * BKOPS status level
- */
-#define EXT_CSD_BKOPS_LEVEL_2 0x2
-
-/*
- * EXCEPTION_EVENT_STATUS field (eMMC4.5)
- */
-#define EXT_CSD_URGENT_BKOPS BIT(0)
-#define EXT_CSD_DYNCAP_NEEDED BIT(1)
-#define EXT_CSD_SYSPOOL_EXHAUSTED BIT(2)
-
#endif /* LINUX_MMC_MMC_H */
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index 2253655..71ff639 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -2,7 +2,7 @@
#define _MSM_KGSL_H
#define KGSL_VERSION_MAJOR 3
-#define KGSL_VERSION_MINOR 11
+#define KGSL_VERSION_MINOR 12
/*context flags */
#define KGSL_CONTEXT_SAVE_GMEM 0x00000001
@@ -432,7 +432,8 @@
/*
* A timestamp event allows the user space to register an action following an
- * expired timestamp.
+ * expired timestamp. Note IOCTL_KGSL_TIMESTAMP_EVENT has been redefined to
+ * _IOWR to support fences which need to return a fd for the priv parameter.
*/
struct kgsl_timestamp_event {
@@ -443,7 +444,7 @@
size_t len; /* Size of the event specific blob */
};
-#define IOCTL_KGSL_TIMESTAMP_EVENT \
+#define IOCTL_KGSL_TIMESTAMP_EVENT_OLD \
_IOW(KGSL_IOC_TYPE, 0x31, struct kgsl_timestamp_event)
/* A genlock timestamp event releases an existing lock on timestamp expire */
@@ -454,6 +455,14 @@
int handle; /* Handle of the genlock lock to release */
};
+/* A fence timestamp event releases an existing lock on timestamp expire */
+
+#define KGSL_TIMESTAMP_EVENT_FENCE 2
+
+struct kgsl_timestamp_event_fence {
+ int fence_fd; /* Fence to signal */
+};
+
/*
* Set a property within the kernel. Uses the same structure as
* IOCTL_KGSL_GETPROPERTY
@@ -462,6 +471,9 @@
#define IOCTL_KGSL_SETPROPERTY \
_IOW(KGSL_IOC_TYPE, 0x32, struct kgsl_device_getproperty)
+#define IOCTL_KGSL_TIMESTAMP_EVENT \
+ _IOWR(KGSL_IOC_TYPE, 0x33, struct kgsl_timestamp_event)
+
#ifdef __KERNEL__
#ifdef CONFIG_MSM_KGSL_DRM
int kgsl_gem_obj_addr(int drm_fd, int handle, unsigned long *start,
diff --git a/include/linux/slimbus/slimbus.h b/include/linux/slimbus/slimbus.h
index e92201f..e333235 100644
--- a/include/linux/slimbus/slimbus.h
+++ b/include/linux/slimbus/slimbus.h
@@ -143,10 +143,15 @@
* struct slim_addrt: slimbus address used internally by the slimbus framework.
* @valid: If the device is still there or if the address can be reused.
* @eaddr: 6-bytes-long elemental address
+ * @laddr: It is possible that controller will set a predefined logical address
+ * rather than the one assigned by framework. (i.e. logical address may
+ * not be same as index into this table). This entry will store the
+ * logical address value for this enumeration address.
*/
struct slim_addrt {
bool valid;
u8 eaddr[6];
+ u8 laddr;
};
/*
@@ -500,6 +505,9 @@
* send unicast message to this device with its logical address.
* @allocbw: Controller can override default reconfiguration and channel
* scheduling algorithm.
+ * @get_laddr: It is possible that controller needs to set fixed logical
+ * address table and get_laddr can be used in that case so that controller
+ * can do this assignment.
* @wakeup: This function pointer implements controller-specific procedure
* to wake it up from clock-pause. Framework will call this to bring
* the controller out of clock pause.
@@ -546,6 +554,8 @@
const u8 *ea, u8 elen, u8 laddr);
int (*allocbw)(struct slim_device *sb,
int *subfrmc, int *clkgear);
+ int (*get_laddr)(struct slim_controller *ctrl,
+ const u8 *ea, u8 elen, u8 *laddr);
int (*wakeup)(struct slim_controller *ctrl);
int (*config_port)(struct slim_controller *ctrl,
u8 port);
@@ -983,14 +993,17 @@
* @ctrl: Controller with which device is enumerated.
* @e_addr: 6-byte elemental address of the device.
* @e_len: buffer length for e_addr
- * @laddr: Return logical address.
+ * @laddr: Return logical address (if valid flag is false)
+ * @valid: true if laddr holds a valid address that controller wants to
+ * set for this enumeration address. Otherwise framework sets index into
+ * address table as logical address.
* Called by controller in response to REPORT_PRESENT. Framework will assign
* a logical address to this enumeration address.
* Function returns -EXFULL to indicate that all logical addresses are already
* taken.
*/
extern int slim_assign_laddr(struct slim_controller *ctrl, const u8 *e_addr,
- u8 e_len, u8 *laddr);
+ u8 e_len, u8 *laddr, bool valid);
/*
* slim_msg_response: Deliver Message response received from a device to the
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 7b5aa0b..b265eb9 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1618,6 +1618,7 @@
V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY = 4,
};
#define V4L2_CID_MPEG_VIDEO_MPEG4_QPEL (V4L2_CID_MPEG_BASE+407)
+#define V4L2_CID_QCOM_VIDEO_SYNC_FRAME_SEQ_HDR (V4L2_CID_MPEG_BASE+408)
/* MPEG-class control IDs specific to the CX2341x driver as defined by V4L2 */
#define V4L2_CID_MPEG_CX2341X_BASE (V4L2_CTRL_CLASS_MPEG | 0x1000)
diff --git a/include/media/msm_jpeg.h b/include/media/msm_jpeg.h
index 11c3247..56829f1 100644
--- a/include/media/msm_jpeg.h
+++ b/include/media/msm_jpeg.h
@@ -85,6 +85,8 @@
uint32_t num_of_mcu_rows;
uint32_t offset;
+ uint32_t pln2_off;
+ uint32_t pln2_len;
};
#define MSM_JPEG_HW_CMD_TYPE_READ 0
diff --git a/include/media/vcap_v4l2.h b/include/media/vcap_v4l2.h
index 7b6d817..b2a538c 100644
--- a/include/media/vcap_v4l2.h
+++ b/include/media/vcap_v4l2.h
@@ -14,7 +14,6 @@
#ifndef VCAP_V4L2_H
#define VCAP_V4L2_H
-#define TOP_FIELD_FIX
#ifdef __KERNEL__
#include <linux/types.h>
#include <linux/videodev2.h>
@@ -88,6 +87,8 @@
uint8_t tot_buf;
uint8_t buf_num;
+ bool top_field;
+
struct timeval vc_ts;
uint32_t last_ts;
@@ -107,9 +108,6 @@
/* Buffer index */
enum vp_state vp_state;
-#ifdef TOP_FIELD_FIX
- bool top_field;
-#endif
/* Buffers inside vc */
struct vcap_buffer *bufTm1;
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index ac4ec09..1da6aa2 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -242,18 +242,18 @@
*/
struct adm_cmd_set_pp_params_v5 {
struct apr_hdr hdr;
- u32 data_payload_addr_lsw;
+ u32 payload_addr_lsw;
/* LSW of parameter data payload address.*/
- u32 data_payload_addr_msw;
+ u32 payload_addr_msw;
/* MSW of parameter data payload address.*/
- u32 mem_map_handle;
+ u32 mem_map_handle;
/* Memory map handle returned by ADM_CMD_SHARED_MEM_MAP_REGIONS
* command */
/* If mem_map_handle is zero implies the message is in
* the payload */
- u32 data_payload_size;
+ u32 payload_size;
/* Size in bytes of the variable payload accompanying this
* message or
* in shared memory. This is used for parsing the parameter
diff --git a/include/trace/events/exception.h b/include/trace/events/exception.h
new file mode 100644
index 0000000..110e920
--- /dev/null
+++ b/include/trace/events/exception.h
@@ -0,0 +1,68 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM exception
+
+#if !defined(_TRACE_EXCEPTION_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_EXCEPTION_H
+
+#include <linux/tracepoint.h>
+
+struct task_struct;
+
+TRACE_EVENT(user_fault,
+
+ TP_PROTO(struct task_struct *tsk, unsigned long addr, unsigned int fsr),
+
+ TP_ARGS(tsk, addr, fsr),
+
+ TP_STRUCT__entry(
+ __string(task_name, tsk->comm)
+ __field(unsigned long, addr)
+ __field(unsigned int, fsr)
+ ),
+
+ TP_fast_assign(
+ __assign_str(task_name, tsk->comm)
+ __entry->addr = addr;
+ __entry->fsr = fsr;
+ ),
+
+ TP_printk("task_name:%s addr:%lu, fsr:%u", __get_str(task_name),\
+ __entry->addr, __entry->fsr)
+);
+
+struct pt_regs;
+
+TRACE_EVENT(undef_instr,
+
+ TP_PROTO(struct pt_regs *regs, void *prog_cnt),
+
+ TP_ARGS(regs, prog_cnt),
+
+ TP_STRUCT__entry(
+ __field(void *, prog_cnt)
+ __field(struct pt_regs *, regs)
+ ),
+
+ TP_fast_assign(
+ __entry->regs = regs;
+ __entry->prog_cnt = prog_cnt;
+ ),
+
+ TP_printk("pc:%p", __entry->prog_cnt)
+);
+
+#endif
+
+#include <trace/define_trace.h>
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index ac11f1a..a47e446 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -8379,8 +8379,9 @@
{
struct platform_device *pdev = to_platform_device(dev);
struct tabla_priv *tabla = platform_get_drvdata(pdev);
- dev_dbg(dev, "%s: system resume\n", __func__);
- tabla->mbhc_last_resume = jiffies;
+ dev_dbg(dev, "%s: system resume tabla %p\n", __func__, tabla);
+ if (tabla)
+ tabla->mbhc_last_resume = jiffies;
return 0;
}
diff --git a/sound/soc/msm/apq8064-i2s.c b/sound/soc/msm/apq8064-i2s.c
index 162f39d..f57d686 100644
--- a/sound/soc/msm/apq8064-i2s.c
+++ b/sound/soc/msm/apq8064-i2s.c
@@ -208,6 +208,7 @@
static struct snd_soc_jack hs_jack;
static struct snd_soc_jack button_jack;
+static atomic_t auxpcm_rsc_ref;
static int apq8064_i2s_hs_detect_use_gpio = -1;
module_param(apq8064_i2s_hs_detect_use_gpio, int, 0444);
@@ -2095,8 +2096,10 @@
{
int ret = 0;
- pr_debug("%s(): substream = %s\n", __func__, substream->name);
- ret = msm_aux_pcm_get_gpios();
+ pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
+ __func__, substream->name, atomic_read(&auxpcm_rsc_ref));
+ if (atomic_inc_return(&auxpcm_rsc_ref) == 1)
+ ret = msm_aux_pcm_get_gpios();
if (ret < 0) {
pr_err("%s: Aux PCM GPIO request failed\n", __func__);
return -EINVAL;
@@ -2120,8 +2123,10 @@
static void msm_auxpcm_shutdown(struct snd_pcm_substream *substream)
{
- pr_debug("%s(): substream = %s\n", __func__, substream->name);
- msm_aux_pcm_free_gpios();
+ pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
+ __func__, substream->name, atomic_read(&auxpcm_rsc_ref));
+ if (atomic_dec_return(&auxpcm_rsc_ref) == 0)
+ msm_aux_pcm_free_gpios();
}
static void msm_shutdown(struct snd_pcm_substream *substream)
@@ -2710,6 +2715,7 @@
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_AUXPCM_TX,
.be_hw_params_fixup = msm_auxpcm_be_params_fixup,
+ .ops = &msm_auxpcm_be_ops,
},
};
@@ -2785,6 +2791,7 @@
mutex_init(&cdc_mclk_mutex);
atomic_set(&mi2s_rsc_ref, 0);
+ atomic_set(&auxpcm_rsc_ref, 0);
return ret;
}
diff --git a/sound/soc/msm/apq8064.c b/sound/soc/msm/apq8064.c
index 9bc565e..c8cf681 100644
--- a/sound/soc/msm/apq8064.c
+++ b/sound/soc/msm/apq8064.c
@@ -100,6 +100,7 @@
static struct snd_soc_jack hs_jack;
static struct snd_soc_jack button_jack;
+static atomic_t auxpcm_rsc_ref;
static int apq8064_hs_detect_use_gpio = -1;
module_param(apq8064_hs_detect_use_gpio, int, 0444);
@@ -1310,6 +1311,24 @@
return 0;
}
+static int msm_slim_4_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 1;
+
+ pr_debug("%s channels->min %u channels->max %u ()\n", __func__,
+ channels->min, channels->max);
+ return 0;
+}
+
+
static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -1450,8 +1469,10 @@
{
int ret = 0;
- pr_debug("%s(): substream = %s\n", __func__, substream->name);
- ret = msm_aux_pcm_get_gpios();
+ pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
+ __func__, substream->name, atomic_read(&auxpcm_rsc_ref));
+ if (atomic_inc_return(&auxpcm_rsc_ref) == 1)
+ ret = msm_aux_pcm_get_gpios();
if (ret < 0) {
pr_err("%s: Aux PCM GPIO request failed\n", __func__);
return -EINVAL;
@@ -1475,8 +1496,10 @@
static void msm_auxpcm_shutdown(struct snd_pcm_substream *substream)
{
- pr_debug("%s(): substream = %s\n", __func__, substream->name);
- msm_aux_pcm_free_gpios();
+ pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
+ __func__, substream->name, atomic_read(&auxpcm_rsc_ref));
+ if (atomic_dec_return(&auxpcm_rsc_ref) == 0)
+ msm_aux_pcm_free_gpios();
}
static void msm_shutdown(struct snd_pcm_substream *substream)
@@ -1915,6 +1938,7 @@
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_AUXPCM_TX,
.be_hw_params_fixup = msm_auxpcm_be_params_fixup,
+ .ops = &msm_auxpcm_be_ops,
},
{
.name = LPASS_BE_STUB_RX,
@@ -2002,7 +2026,7 @@
.codec_dai_name = "msm-stub-rx",
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_SLIMBUS_4_RX,
- .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .be_hw_params_fixup = msm_slim_4_rx_be_hw_params_fixup,
.ops = &msm_slimbus_4_be_ops,
.ignore_pmdown_time = 1, /* this dainlink has playback support */
},
@@ -2109,6 +2133,7 @@
}
mutex_init(&cdc_mclk_mutex);
+ atomic_set(&auxpcm_rsc_ref, 0);
return ret;
}
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 41f259d..4d0caa3 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -1480,6 +1480,9 @@
SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_PRI_I2S_RX,
MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
};
static const struct snd_kcontrol_new sec_i2s_rx_voice_mixer_controls[] = {
@@ -1743,6 +1746,12 @@
SOC_SINGLE_EXT("SLIM_3_TX", MSM_BACKEND_DAI_SLIMBUS_3_TX,
MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("PRIMARY_I2S_TX", MSM_BACKEND_DAI_PRI_I2S_TX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
};
static const struct snd_kcontrol_new sbus_0_rx_port_mixer_controls[] = {
@@ -1773,6 +1782,9 @@
SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_SLIMBUS_1_RX,
MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_port_mixer,
msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_SLIMBUS_1_RX,
+ MSM_BACKEND_DAI_AFE_PCM_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
};
static const struct snd_kcontrol_new sbus_3_rx_port_mixer_controls[] = {
@@ -1782,6 +1794,9 @@
SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_SLIMBUS_3_RX,
MSM_BACKEND_DAI_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_RX", MSM_BACKEND_DAI_SLIMBUS_3_RX,
+ MSM_BACKEND_DAI_AFE_PCM_RX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
};
static const struct snd_kcontrol_new bt_sco_rx_port_mixer_controls[] = {
SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_INT_BT_SCO_RX,
@@ -1793,6 +1808,9 @@
SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_AFE_PCM_RX,
MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer,
msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_BACKEND_DAI_SLIMBUS_1_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
};
@@ -1805,6 +1823,13 @@
msm_routing_put_port_mixer),
};
+static const struct snd_kcontrol_new pri_i2s_rx_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_BACKEND_DAI_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+
+};
+
static const struct snd_kcontrol_new sec_i2s_rx_port_mixer_controls[] = {
SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_SEC_I2S_RX,
MSM_BACKEND_DAI_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
@@ -1815,6 +1840,9 @@
SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_MI2S_RX,
MSM_BACKEND_DAI_SLIMBUS_1_TX, 1, 0, msm_routing_get_port_mixer,
msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("PRIMARY_I2S_TX", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_BACKEND_DAI_PRI_I2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
};
static const struct snd_kcontrol_new fm_switch_mixer_controls =
@@ -2307,6 +2335,9 @@
SND_SOC_DAPM_MIXER("HDMI_RX Port Mixer",
SND_SOC_NOPM, 0, 0, hdmi_rx_port_mixer_controls,
ARRAY_SIZE(hdmi_rx_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("PRI_I2S_RX Port Mixer",
+ SND_SOC_NOPM, 0, 0, pri_i2s_rx_port_mixer_controls,
+ ARRAY_SIZE(pri_i2s_rx_port_mixer_controls)),
SND_SOC_DAPM_MIXER("SEC_I2S_RX Port Mixer",
SND_SOC_NOPM, 0, 0, sec_i2s_rx_port_mixer_controls,
ARRAY_SIZE(sec_i2s_rx_port_mixer_controls)),
@@ -2441,6 +2472,7 @@
{"PRI_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"PRI_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
{"PRI_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"PRI_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
{"PRI_I2S_RX", NULL, "PRI_RX_Voice Mixer"},
{"SEC_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -2535,6 +2567,7 @@
{"SLIMBUS_0_RX Port Mixer", "MI2S_TX", "MI2S_TX"},
{"SLIMBUS_0_RX", NULL, "SLIMBUS_0_RX Port Mixer"},
{"AFE_PCM_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"AFE_PCM_RX Port Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
{"PCM_RX", NULL, "AFE_PCM_RX Port Mixer"},
{"AUXPCM_RX Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
@@ -2547,6 +2580,8 @@
{"Voice Stub Tx Mixer", "STUB_1_TX_HL", "STUB_1_TX"},
{"Voice Stub Tx Mixer", "MI2S_TX", "MI2S_TX"},
{"Voice Stub Tx Mixer", "SLIM_3_TX", "SLIMBUS_3_TX"},
+ {"Voice Stub Tx Mixer", "PRIMARY_I2S_TX", "PRI_I2S_TX"},
+ {"Voice Stub Tx Mixer", "AFE_PCM_TX", "PCM_TX"},
{"VOICE_STUB_UL", NULL, "Voice Stub Tx Mixer"},
{"STUB_RX Mixer", "Voice Stub", "VOICE_STUB_DL"},
@@ -2557,16 +2592,19 @@
{"MI2S_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
{"MI2S_RX", NULL, "MI2S_RX_Voice Mixer"},
{"HDMI_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"AFE_PCM_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
{"SLIMBUS_3_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
{"SLIMBUS_3_RX", NULL, "SLIMBUS_3_RX_Voice Mixer"},
{"SLIMBUS_1_RX Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"SLIMBUS_1_RX Port Mixer", "AFE_PCM_TX", "PCM_TX"},
{"SLIMBUS_1_RX", NULL, "SLIMBUS_1_RX Port Mixer"},
{"INTERNAL_BT_SCO_RX Port Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX Port Mixer"},
{"SLIMBUS_3_RX Port Mixer", "INTERNAL_BT_SCO_RX", "INT_BT_SCO_RX"},
{"SLIMBUS_3_RX Port Mixer", "MI2S_TX", "MI2S_TX"},
+ {"SLIMBUS_3_RX Port Mixer", "AFE_PCM_RX", "PCM_RX"},
{"SLIMBUS_3_RX", NULL, "SLIMBUS_3_RX Port Mixer"},
@@ -2577,7 +2615,12 @@
{"SEC_I2S_RX Port Mixer", "MI2S_TX", "MI2S_TX"},
{"SEC_I2S_RX", NULL, "SEC_I2S_RX Port Mixer"},
+ {"PRI_I2S_RX Port Mixer", "MI2S_TX", "MI2S_TX"},
+ {"PRI_I2S_RX", NULL, "PRI_I2S_RX Port Mixer"},
+
+
{"MI2S_RX Port Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
+ {"MI2S_RX Port Mixer", "PRIMARY_I2S_TX", "PRI_I2S_TX"},
{"MI2S_RX", NULL, "MI2S_RX Port Mixer"},
/* Backend Enablement */
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
index c8d4b02..4725e8e 100644
--- a/sound/soc/msm/msm8930.c
+++ b/sound/soc/msm/msm8930.c
@@ -66,6 +66,7 @@
static struct snd_soc_jack hs_jack;
static struct snd_soc_jack button_jack;
+static atomic_t auxpcm_rsc_ref;
static int msm8930_enable_codec_ext_clk(
struct snd_soc_codec *codec, int enable,
@@ -860,8 +861,10 @@
{
int ret = 0;
- pr_debug("%s(): substream = %s\n", __func__, substream->name);
- ret = msm8930_aux_pcm_get_gpios();
+ pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
+ __func__, substream->name, atomic_read(&auxpcm_rsc_ref));
+ if (atomic_inc_return(&auxpcm_rsc_ref) == 1)
+ ret = msm8930_aux_pcm_get_gpios();
if (ret < 0) {
pr_err("%s: Aux PCM GPIO request failed\n", __func__);
return -EINVAL;
@@ -872,8 +875,10 @@
static void msm8930_auxpcm_shutdown(struct snd_pcm_substream *substream)
{
- pr_debug("%s(): substream = %s\n", __func__, substream->name);
- msm8930_aux_pcm_free_gpios();
+ pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
+ __func__, substream->name, atomic_read(&auxpcm_rsc_ref));
+ if (atomic_dec_return(&auxpcm_rsc_ref) == 0)
+ msm8930_aux_pcm_free_gpios();
}
static void msm8930_shutdown(struct snd_pcm_substream *substream)
@@ -1229,6 +1234,7 @@
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_AUXPCM_TX,
.be_hw_params_fixup = msm8930_auxpcm_be_params_fixup,
+ .ops = &msm8930_auxpcm_be_ops,
},
/* Incall Music BACK END DAI Link */
{
@@ -1336,6 +1342,7 @@
} else
msm8930_headset_gpios_configured = 1;
+ atomic_set(&auxpcm_rsc_ref, 0);
return ret;
}
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index 1338e2f..59d118e 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -83,6 +83,7 @@
static struct snd_soc_jack hs_jack;
static struct snd_soc_jack button_jack;
+static atomic_t auxpcm_rsc_ref;
static bool hs_detect_use_gpio;
module_param(hs_detect_use_gpio, bool, 0444);
@@ -1131,8 +1132,11 @@
{
int ret = 0;
- pr_debug("%s(): substream = %s\n", __func__, substream->name);
- ret = msm8960_aux_pcm_get_gpios();
+ pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
+ __func__, substream->name, atomic_read(&auxpcm_rsc_ref));
+ if (atomic_inc_return(&auxpcm_rsc_ref) == 1)
+ ret = msm8960_aux_pcm_get_gpios();
+
if (ret < 0) {
pr_err("%s: Aux PCM GPIO request failed\n", __func__);
return -EINVAL;
@@ -1142,9 +1146,10 @@
static void msm8960_auxpcm_shutdown(struct snd_pcm_substream *substream)
{
-
- pr_debug("%s(): substream = %s\n", __func__, substream->name);
- msm8960_aux_pcm_free_gpios();
+ pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
+ __func__, substream->name, atomic_read(&auxpcm_rsc_ref));
+ if (atomic_dec_return(&auxpcm_rsc_ref) == 0)
+ msm8960_aux_pcm_free_gpios();
}
static void msm8960_shutdown(struct snd_pcm_substream *substream)
@@ -1522,6 +1527,7 @@
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_AUXPCM_TX,
.be_hw_params_fixup = msm8960_auxpcm_be_params_fixup,
+ .ops = &msm8960_auxpcm_be_ops,
},
/* Incall Music BACK END DAI Link */
{
@@ -1819,7 +1825,7 @@
}
mutex_init(&cdc_mclk_mutex);
-
+ atomic_set(&auxpcm_rsc_ref, 0);
return ret;
}
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index c7820dd..92b7324 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -88,6 +88,7 @@
static struct mutex cdc_mclk_mutex;
static struct q_clkdiv *codec_clk;
static int clk_users;
+static atomic_t auxpcm_rsc_ref;
static void msm_enable_ext_spk_amp_gpio(u32 spk_amp_gpio)
{
@@ -553,8 +554,10 @@
{
int ret = 0;
- pr_debug("%s(): substream = %s\n", __func__, substream->name);
- ret = msm_aux_pcm_get_gpios();
+ pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
+ __func__, substream->name, atomic_read(&auxpcm_rsc_ref));
+ if (atomic_inc_return(&auxpcm_rsc_ref) == 1)
+ ret = msm_aux_pcm_get_gpios();
if (ret < 0) {
pr_err("%s: Aux PCM GPIO request failed\n", __func__);
return -EINVAL;
@@ -565,8 +568,10 @@
static void msm_auxpcm_shutdown(struct snd_pcm_substream *substream)
{
- pr_debug("%s(): substream = %s\n", __func__, substream->name);
- msm_aux_pcm_free_gpios();
+ pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
+ __func__, substream->name, atomic_read(&auxpcm_rsc_ref));
+ if (atomic_dec_return(&auxpcm_rsc_ref) == 0)
+ msm_aux_pcm_free_gpios();
}
static struct snd_soc_ops msm_auxpcm_be_ops = {
.startup = msm_auxpcm_startup,
@@ -865,7 +870,20 @@
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
},
-
+ {
+ .name = "MSM8974 Media2",
+ .stream_name = "MultiMedia2",
+ .cpu_dai_name = "MultiMedia2",
+ .platform_name = "msm-pcm-dsp",
+ .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,
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
+ },
/* AUX PCM Backend DAI Links */
{
.name = LPASS_BE_AUXPCM_RX,
@@ -891,6 +909,7 @@
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_AUXPCM_TX,
.be_hw_params_fixup = msm_auxpcm_be_params_fixup,
+ .ops = &msm_auxpcm_be_ops,
},
/* Backend DAI Links */
{
@@ -1028,6 +1047,8 @@
goto err;
}
mutex_init(&cdc_mclk_mutex);
+ atomic_set(&auxpcm_rsc_ref, 0);
+
return 0;
err:
devm_kfree(&pdev->dev, pdata);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index fbbb3a5..3db5418 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -1075,6 +1075,9 @@
SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX,
MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = {
@@ -1803,6 +1806,7 @@
{"MultiMedia2 Mixer", "MI2S_TX", "MI2S_TX"},
{"MultiMedia1 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia1 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"MultiMedia2 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
index 492569b..c7a8031 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
@@ -32,8 +32,9 @@
#include "q6voice.h"
#include "audio_ocmem.h"
+#define SHARED_MEM_BUF 2
#define VOIP_MAX_Q_LEN 10
-#define VOIP_MAX_VOC_PKT_SIZE 640
+#define VOIP_MAX_VOC_PKT_SIZE 4096
#define VOIP_MIN_VOC_PKT_SIZE 320
/* Length of the DSP frame info header added to the voc packet. */
@@ -259,8 +260,8 @@
/* capture path */
static void voip_process_ul_pkt(uint8_t *voc_pkt,
- uint32_t pkt_len,
- void *private_data)
+ uint32_t pkt_len,
+ void *private_data)
{
struct voip_buf_node *buf_node = NULL;
struct voip_drv_info *prtd = private_data;
@@ -315,8 +316,8 @@
default: {
buf_node->frame.len = pkt_len;
memcpy(&buf_node->frame.voc_pkt[0],
- voc_pkt,
- buf_node->frame.len);
+ voc_pkt,
+ buf_node->frame.len);
list_add_tail(&buf_node->list, &prtd->out_queue);
}
}
@@ -334,15 +335,12 @@
}
/* playback path */
-static void voip_process_dl_pkt(uint8_t *voc_pkt,
- uint32_t *pkt_len,
- void *private_data)
+static void voip_process_dl_pkt(uint8_t *voc_pkt, void *private_data)
{
struct voip_buf_node *buf_node = NULL;
struct voip_drv_info *prtd = private_data;
unsigned long dsp_flags;
-
if (prtd->playback_substream == NULL)
return;
@@ -355,14 +353,18 @@
switch (prtd->mode) {
case MODE_AMR:
case MODE_AMR_WB: {
- /* Add the DSP frame info header. Header format:
+ *((uint32_t *)voc_pkt) = buf_node->frame.len +
+ DSP_FRAME_HDR_LEN;
+ /* Advance to the header of voip packet */
+ voc_pkt = voc_pkt + sizeof(uint32_t);
+ /*
+ * Add the DSP frame info header. Header format:
* Bits 0-3: Frame rate
* Bits 4-7: Frame type
*/
*voc_pkt = ((buf_node->frame.header.frame_type &
0x0F) << 4) | (prtd->rate_type & 0x0F);
voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
- *pkt_len = buf_node->frame.len + DSP_FRAME_HDR_LEN;
memcpy(voc_pkt,
&buf_node->frame.voc_pkt[0],
buf_node->frame.len);
@@ -372,12 +374,16 @@
case MODE_IS127:
case MODE_4GV_NB:
case MODE_4GV_WB: {
- /* Add the DSP frame info header. Header format:
+ *((uint32_t *)voc_pkt) = buf_node->frame.len +
+ DSP_FRAME_HDR_LEN;
+ /* Advance to the header of voip packet */
+ voc_pkt = voc_pkt + sizeof(uint32_t);
+ /*
+ * Add the DSP frame info header. Header format:
* Bits 0-3 : Frame rate
- */
+ */
*voc_pkt = buf_node->frame.header.packet_rate & 0x0F;
voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
- *pkt_len = buf_node->frame.len + DSP_FRAME_HDR_LEN;
memcpy(voc_pkt,
&buf_node->frame.voc_pkt[0],
@@ -387,22 +393,19 @@
break;
}
default: {
- *pkt_len = buf_node->frame.len;
-
+ *((uint32_t *)voc_pkt) = buf_node->frame.len;
+ voc_pkt = voc_pkt + sizeof(uint32_t);
memcpy(voc_pkt,
- &buf_node->frame.voc_pkt[0],
- buf_node->frame.len);
-
+ &buf_node->frame.voc_pkt[0],
+ buf_node->frame.len);
list_add_tail(&buf_node->list, &prtd->free_in_queue);
}
}
- pr_debug("dl_pkt: pkt_len=%d, frame_len=%d\n", *pkt_len,
- buf_node->frame.len);
prtd->pcm_playback_irq_pos += prtd->pcm_count;
spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
snd_pcm_period_elapsed(prtd->playback_substream);
} else {
- *pkt_len = 0;
+ *((uint32_t *)voc_pkt) = 0;
spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
pr_err("DL data not available\n");
}
@@ -556,7 +559,7 @@
pr_err("%s: No free DL buffs\n", __func__);
ret = -ETIMEDOUT;
} else {
- pr_err("%s: playback copy was interrupted\n", __func__);
+ pr_err("%s: playback copy was interrupted %d\n", __func__, ret);
}
return ret;
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index e5837b2..62257b4 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -41,6 +41,14 @@
wait_queue_head_t wait[Q6_AFE_MAX_PORTS];
};
+static struct acdb_cal_block mem_addr_audproc[MAX_AUDPROC_TYPES];
+static struct acdb_cal_block mem_addr_audvol[MAX_AUDPROC_TYPES];
+
+/* 0 - (MAX_AUDPROC_TYPES -1): audproc handles */
+/* (MAX_AUDPROC_TYPES -1) - (2 * MAX_AUDPROC_TYPES -1): audvol handles */
+atomic_t mem_map_handles[(2 * MAX_AUDPROC_TYPES)];
+atomic_t mem_map_index;
+
static struct adm_ctl this_adm;
static int32_t adm_callback(struct apr_client_data *data, void *priv)
@@ -63,6 +71,18 @@
}
this_adm.apr = NULL;
}
+ pr_debug("Resetting calibration blocks");
+ for (i = 0; i < MAX_AUDPROC_TYPES; i++) {
+ /* Device calibration */
+ mem_addr_audproc[i].cal_size = 0;
+ mem_addr_audproc[i].cal_kvaddr = 0;
+ mem_addr_audproc[i].cal_paddr = 0;
+
+ /* Volume calibration */
+ mem_addr_audvol[i].cal_size = 0;
+ mem_addr_audvol[i].cal_kvaddr = 0;
+ mem_addr_audvol[i].cal_paddr = 0;
+ }
return 0;
}
@@ -82,18 +102,23 @@
switch (payload[0]) {
case ADM_CMD_SET_PP_PARAMS_V5:
if (rtac_make_adm_callback(
- payload, data->payload_size))
+ payload, data->payload_size)) {
pr_debug("%s: payload[0]: 0x%x\n",
__func__, payload[0]);
break;
+ }
case ADM_CMD_DEVICE_CLOSE_V5:
case ADM_CMD_SHARED_MEM_UNMAP_REGIONS:
- case ADM_CMD_SHARED_MEM_MAP_REGIONS:
case ADM_CMD_MATRIX_MAP_ROUTINGS_V5:
- pr_debug("ADM_CMD_MATRIX_MAP_ROUTINGS\n");
+ pr_debug("%s: Basic callback received, wake up.\n",
+ __func__);
atomic_set(&this_adm.copp_stat[index], 1);
wake_up(&this_adm.wait[index]);
break;
+ case ADM_CMD_SHARED_MEM_MAP_REGIONS:
+ /* Block until memory handle comes back */
+ /* via ADM_CMDRSP_SHARED_MEM_MAP_REGIONS */
+ break;
default:
pr_err("%s: Unknown Cmd: 0x%x\n", __func__,
payload[0]);
@@ -125,6 +150,14 @@
rtac_make_adm_callback(payload,
data->payload_size);
break;
+ case ADM_CMDRSP_SHARED_MEM_MAP_REGIONS:
+ pr_debug("%s: ADM_CMDRSP_SHARED_MEM_MAP_REGIONS\n",
+ __func__);
+ atomic_set(&mem_map_handles[
+ atomic_read(&mem_map_index)], *payload);
+ atomic_set(&this_adm.copp_stat[0], 1);
+ wake_up(&this_adm.wait[index]);
+ break;
default:
pr_err("%s: Unknown cmd:0x%x\n", __func__,
data->opcode);
@@ -134,12 +167,143 @@
return 0;
}
-/* TODO: send_adm_cal_block function to be defined
- when calibration available for 8974 */
+static int send_adm_cal_block(int port_id, struct acdb_cal_block *aud_cal)
+{
+ s32 result = 0;
+ struct adm_cmd_set_pp_params_v5 adm_params;
+ int index = afe_get_port_index(port_id);
+ if (index < 0 || index >= AFE_MAX_PORTS) {
+ pr_err("%s: invalid port idx %d portid %d\n",
+ __func__, index, port_id);
+ return 0;
+ }
+
+ pr_debug("%s: Port id %d, index %d\n", __func__, port_id, index);
+
+ if (!aud_cal || aud_cal->cal_size == 0) {
+ pr_debug("%s: No ADM cal to send for port_id = %d!\n",
+ __func__, port_id);
+ result = -EINVAL;
+ goto done;
+ }
+
+ adm_params.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(20), APR_PKT_VER);
+ adm_params.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(adm_params));
+ adm_params.hdr.src_svc = APR_SVC_ADM;
+ adm_params.hdr.src_domain = APR_DOMAIN_APPS;
+ adm_params.hdr.src_port = port_id;
+ adm_params.hdr.dest_svc = APR_SVC_ADM;
+ adm_params.hdr.dest_domain = APR_DOMAIN_ADSP;
+ adm_params.hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+ adm_params.hdr.token = port_id;
+ adm_params.hdr.opcode = ADM_CMD_SET_PP_PARAMS_V5;
+ adm_params.payload_addr_lsw = aud_cal->cal_paddr;
+ adm_params.payload_addr_msw = 0;
+ adm_params.mem_map_handle = atomic_read(&mem_map_handles[
+ atomic_read(&mem_map_index)]);
+ adm_params.payload_size = aud_cal->cal_size;
+
+ atomic_set(&this_adm.copp_stat[index], 0);
+ pr_debug("%s: Sending SET_PARAMS payload = 0x%x, size = %d\n",
+ __func__, adm_params.payload_addr_lsw,
+ adm_params.payload_size);
+ result = apr_send_pkt(this_adm.apr, (uint32_t *)&adm_params);
+ if (result < 0) {
+ pr_err("%s: Set params failed port = %d payload = 0x%x\n",
+ __func__, port_id, aud_cal->cal_paddr);
+ result = -EINVAL;
+ goto done;
+ }
+ /* Wait for the callback */
+ result = wait_event_timeout(this_adm.wait[index],
+ atomic_read(&this_adm.copp_stat[index]),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!result) {
+ pr_err("%s: Set params timed out port = %d, payload = 0x%x\n",
+ __func__, port_id, aud_cal->cal_paddr);
+ result = -EINVAL;
+ goto done;
+ }
+
+ result = 0;
+done:
+ return result;
+}
+
static void send_adm_cal(int port_id, int path)
{
- /* function to be defined when calibration available for 8974 */
+ int result = 0;
+ s32 acdb_path;
+ struct acdb_cal_block aud_cal;
+ int size = 4096;
pr_debug("%s\n", __func__);
+
+ /* Maps audio_dev_ctrl path definition to ACDB definition */
+ acdb_path = path - 1;
+
+ pr_debug("%s: Sending audproc cal\n", __func__);
+ get_audproc_cal(acdb_path, &aud_cal);
+
+ /* map & cache buffers used */
+ if (((mem_addr_audproc[acdb_path].cal_paddr != aud_cal.cal_paddr) &&
+ (aud_cal.cal_size > 0)) ||
+ (aud_cal.cal_size > mem_addr_audproc[acdb_path].cal_size)) {
+
+ atomic_set(&mem_map_index, acdb_path);
+ if (mem_addr_audproc[acdb_path].cal_paddr != 0)
+ adm_memory_unmap_regions(port_id,
+ &mem_addr_audproc[acdb_path].cal_paddr,
+ &size, 1);
+
+ result = adm_memory_map_regions(port_id, &aud_cal.cal_paddr,
+ 0, &aud_cal.cal_size, 1);
+ if (result < 0)
+ pr_err("ADM audproc mmap did not work! path = %d, addr = 0x%x, size = %d\n",
+ acdb_path, aud_cal.cal_paddr,
+ aud_cal.cal_size);
+ else
+ mem_addr_audproc[acdb_path] = aud_cal;
+ }
+
+ if (!send_adm_cal_block(port_id, &aud_cal))
+ pr_debug("%s: Audproc cal sent for port id: %d, path %d\n",
+ __func__, port_id, acdb_path);
+ else
+ pr_debug("%s: Audproc cal not sent for port id: %d, path %d\n",
+ __func__, port_id, acdb_path);
+
+ pr_debug("%s: Sending audvol cal\n", __func__);
+ get_audvol_cal(acdb_path, &aud_cal);
+
+ /* map & cache buffers used */
+ if (((mem_addr_audvol[acdb_path].cal_paddr != aud_cal.cal_paddr) &&
+ (aud_cal.cal_size > 0)) ||
+ (aud_cal.cal_size > mem_addr_audvol[acdb_path].cal_size)) {
+
+ atomic_set(&mem_map_index, (acdb_path + MAX_AUDPROC_TYPES));
+ if (mem_addr_audvol[acdb_path].cal_paddr != 0)
+ adm_memory_unmap_regions(port_id,
+ &mem_addr_audvol[acdb_path].cal_paddr,
+ &size, 1);
+
+ result = adm_memory_map_regions(port_id, &aud_cal.cal_paddr,
+ 0, &aud_cal.cal_size, 1);
+ if (result < 0)
+ pr_err("ADM audvol mmap did not work! path = %d, addr = 0x%x, size = %d\n",
+ acdb_path, aud_cal.cal_paddr,
+ aud_cal.cal_size);
+ else
+ mem_addr_audvol[acdb_path] = aud_cal;
+ }
+
+ if (!send_adm_cal_block(port_id, &aud_cal))
+ pr_debug("%s: Audvol cal sent for port id: %d, path %d\n",
+ __func__, port_id, acdb_path);
+ else
+ pr_debug("%s: Audvol cal not sent for port id: %d, path %d\n",
+ __func__, port_id, acdb_path);
}
int adm_connect_afe_port(int mode, int session_id, int port_id)
@@ -572,7 +736,8 @@
unmap_regions.hdr.dest_port = 0;
unmap_regions.hdr.token = 0;
unmap_regions.hdr.opcode = ADM_CMD_SHARED_MEM_UNMAP_REGIONS;
- unmap_regions.mem_map_handle = this_adm.mem_map_handle[index];
+ unmap_regions.mem_map_handle = atomic_read(&mem_map_handles[
+ atomic_read(&mem_map_index)]);
atomic_set(&this_adm.copp_stat[0], 0);
ret = apr_send_pkt(this_adm.apr, (uint32_t *) &unmap_regions);
if (ret < 0) {
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index f84b456..0a057fa 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -50,6 +50,15 @@
static int voice_send_set_device_cmd(struct voice_data *v);
static int voice_send_disable_vocproc_cmd(struct voice_data *v);
static int voice_send_vol_index_cmd(struct voice_data *v);
+static int voice_send_mvm_map_memory_physical_cmd(struct voice_data *v);
+static int voice_send_mvm_unmap_memory_physical_cmd(struct voice_data *v,
+ unsigned int bufcnt);
+static int voice_send_mvm_cal_network_cmd(struct voice_data *v);
+static int voice_send_mvm_media_type_cmd(struct voice_data *v);
+static int voice_send_cvs_data_exchange_mode_cmd(struct voice_data *v);
+static int voice_send_cvs_packet_exchange_config_cmd(struct voice_data *v);
+static int voice_set_packet_exchange_mode_and_config(uint16_t session_id,
+ uint32_t mode);
static int voice_cvs_stop_playback(struct voice_data *v);
static int voice_cvs_start_playback(struct voice_data *v);
static int voice_cvs_start_record(struct voice_data *v, uint32_t rec_mode);
@@ -594,7 +603,6 @@
detach_stream.detach_stream.handle = cvs_handle;
v->mvm_state = CMD_STATUS_FAIL;
-
ret = apr_send_pkt(apr_mvm, (uint32_t *) &detach_stream);
if (ret < 0) {
pr_err("%s: Error %d sending DETACH_STREAM\n",
@@ -608,6 +616,7 @@
pr_err("%s: wait event timeout\n", __func__);
goto fail;
}
+
/* Destroy CVS. */
pr_debug("%s: CVS destroy session\n", __func__);
@@ -622,7 +631,6 @@
cvs_destroy.opcode = APRV2_IBASIC_CMD_DESTROY_SESSION;
v->cvs_state = CMD_STATUS_FAIL;
-
ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_destroy);
if (ret < 0) {
pr_err("%s: Error %d sending CVS DESTROY\n",
@@ -640,6 +648,13 @@
cvs_handle = 0;
voice_set_cvs_handle(v, cvs_handle);
+ ret = voice_send_mvm_unmap_memory_physical_cmd(v,
+ NUM_OF_BUFFERS);
+ if (ret < 0) {
+ pr_err("%s CMD Memory_unmap_regions failed %d\n",
+ __func__, ret);
+ }
+
/* Destroy MVM. */
pr_debug("MVM destroy session\n");
@@ -667,7 +682,6 @@
msecs_to_jiffies(TIMEOUT_MS));
if (!ret) {
pr_err("%s: wait event timeout\n", __func__);
-
goto fail;
}
mvm_handle = 0;
@@ -788,6 +802,58 @@
return 0;
}
+static int voice_send_mvm_media_type_cmd(struct voice_data *v)
+{
+ struct vss_imvm_cmd_set_cal_media_type_t mvm_set_cal_media_type;
+ int ret = 0;
+ void *apr_mvm;
+ u16 mvm_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_mvm = common.apr_q6_mvm;
+
+ if (!apr_mvm) {
+ pr_err("%s: apr_mvm is NULL.\n", __func__);
+ return -EINVAL;
+ }
+ mvm_handle = voice_get_mvm_handle(v);
+
+ mvm_set_cal_media_type.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ mvm_set_cal_media_type.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(mvm_set_cal_media_type) -
+ APR_HDR_SIZE);
+ mvm_set_cal_media_type.hdr.src_port = v->session_id;
+ mvm_set_cal_media_type.hdr.dest_port = mvm_handle;
+ mvm_set_cal_media_type.hdr.token = 0;
+ mvm_set_cal_media_type.hdr.opcode = VSS_IMVM_CMD_SET_CAL_MEDIA_TYPE;
+ mvm_set_cal_media_type.media_id = common.mvs_info.media_type;
+ pr_debug("%s: setting media_id as %x\n",
+ __func__ , mvm_set_cal_media_type.media_id);
+
+ v->mvm_state = CMD_STATUS_FAIL;
+ ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_set_cal_media_type);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending media type\n", __func__, ret);
+ goto fail;
+ }
+
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout %d\n", __func__, ret);
+ goto fail;
+ }
+ return 0;
+fail:
+ return -EINVAL;
+}
static int voice_config_cvs_vocoder(struct voice_data *v)
{
int ret = 0;
@@ -813,7 +879,8 @@
APR_HDR_LEN(APR_HDR_SIZE),
APR_PKT_VER);
cvs_set_media_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
- sizeof(cvs_set_media_cmd) - APR_HDR_SIZE);
+ sizeof(cvs_set_media_cmd) -
+ APR_HDR_SIZE);
cvs_set_media_cmd.hdr.src_port = v->session_id;
cvs_set_media_cmd.hdr.dest_port = cvs_handle;
cvs_set_media_cmd.hdr.token = 0;
@@ -826,7 +893,7 @@
ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_media_cmd);
if (ret < 0) {
pr_err("%s: Error %d sending SET_MEDIA_TYPE\n",
- __func__, ret);
+ __func__, ret);
goto fail;
}
@@ -1196,6 +1263,102 @@
return -EINVAL;
}
+static int voice_send_mvm_map_memory_physical_cmd(struct voice_data *v)
+{
+ struct vss_imemory_cmd_map_physical_t mvm_map_phys_cmd;
+ uint32_t *memtable;
+ int ret = 0;
+ void *apr_mvm;
+ u16 mvm_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ apr_mvm = common.apr_q6_mvm;
+
+ if (!apr_mvm) {
+ pr_err("%s: apr_mvm is NULL.\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!v->shmem_info.memtbl.data) {
+ pr_err("%s: shmem_info.memtbl.data is NULL.\n", __func__);
+ return -EINVAL;
+ }
+
+ memtable = (uint32_t *)v->shmem_info.memtbl.data;
+
+ /*
+ * Store next table descriptor's address(64 bit) as NULL as there
+ * is only one memory block
+ */
+ memtable[0] = (uint32_t)NULL;
+ memtable[1] = (uint32_t)NULL;
+
+ /* Store next table descriptor's size */
+ memtable[2] = 0;
+
+ /* Store shared mem add */
+ memtable[3] = v->shmem_info.sh_buf.buf[0].phys;
+ memtable[4] = 0;
+
+ /* Store shared memory size */
+ memtable[5] = v->shmem_info.sh_buf.buf[0].size * NUM_OF_BUFFERS;
+
+ mvm_handle = voice_get_mvm_handle(v);
+
+ mvm_map_phys_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ mvm_map_phys_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(mvm_map_phys_cmd) - APR_HDR_SIZE);
+ mvm_map_phys_cmd.hdr.src_port = v->session_id;
+ mvm_map_phys_cmd.hdr.dest_port = mvm_handle;
+ mvm_map_phys_cmd.hdr.token = 0;
+ mvm_map_phys_cmd.hdr.opcode = VSS_IMEMORY_CMD_MAP_PHYSICAL;
+
+ mvm_map_phys_cmd.table_descriptor.mem_address =
+ v->shmem_info.memtbl.phys;
+ mvm_map_phys_cmd.table_descriptor.mem_size =
+ sizeof(struct vss_imemory_block_t) +
+ sizeof(struct vss_imemory_table_descriptor_t);
+ mvm_map_phys_cmd.is_cached = true;
+ mvm_map_phys_cmd.cache_line_size = 128;
+ mvm_map_phys_cmd.access_mask = 3;
+ mvm_map_phys_cmd.page_align = 4096;
+ mvm_map_phys_cmd.min_data_width = 8;
+ mvm_map_phys_cmd.max_data_width = 64;
+
+ pr_debug("%s: ntd->add: %lld, ntd->size: %d, table->add: 0x%x\n",
+ __func__,
+ *((uint64_t *)v->shmem_info.memtbl.data),
+ *(((uint32_t *)(v->shmem_info.memtbl.data)) + 2),
+ *(((uint32_t *)(v->shmem_info.memtbl.data)) + 3));
+ pr_debug("%s: table->size: %d, pkt_size: %d, mvm_handle: 0x%x\n",
+ __func__,
+ *(((uint32_t *)(v->shmem_info.memtbl.data)) + 5),
+ mvm_map_phys_cmd.hdr.pkt_size, mvm_handle);
+
+ v->mvm_state = CMD_STATUS_FAIL;
+ ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_map_phys_cmd);
+ if (ret < 0) {
+ pr_err("Fail: sending mvm map phy cmd %d\n", ret);
+ goto fail;
+ }
+
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout %d\n", __func__, ret);
+ goto fail;
+ }
+
+ return 0;
+fail:
+ return -EINVAL;
+}
static int voice_setup_vocproc(struct voice_data *v)
{
@@ -1225,7 +1388,7 @@
cvp_session_cmd.hdr.dest_port = 0;
cvp_session_cmd.hdr.token = 0;
cvp_session_cmd.hdr.opcode =
- VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION;
+ VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION_V2;
/* Use default topology if invalid value in ACDB */
cvp_session_cmd.cvp_session.tx_topology_id =
@@ -1241,16 +1404,24 @@
VSS_IVOCPROC_TOPOLOGY_ID_RX_DEFAULT;
cvp_session_cmd.cvp_session.direction = 2; /*tx and rx*/
- cvp_session_cmd.cvp_session.network_id = VSS_NETWORK_ID_DEFAULT;
cvp_session_cmd.cvp_session.tx_port_id = v->dev_tx.port_id;
cvp_session_cmd.cvp_session.rx_port_id = v->dev_rx.port_id;
+ cvp_session_cmd.cvp_session.profile_id =
+ VSS_ICOMMON_CAL_NETWORK_ID_NONE;
+ cvp_session_cmd.cvp_session.vocproc_mode =
+ VSS_IVOCPROC_VOCPROC_MODE_EC_INT_MIXING;
+ cvp_session_cmd.cvp_session.ec_ref_port_id =
+ VSS_IVOCPROC_PORT_ID_NONE;
- pr_debug("topology=%d net_id=%d, dir=%d tx_port_id=%d, rx_port_id=%d\n",
+ pr_debug("tx_topology: %d tx_port_id=%d, rx_port_id=%d, mode: 0x%x\n",
cvp_session_cmd.cvp_session.tx_topology_id,
- cvp_session_cmd.cvp_session.network_id,
- cvp_session_cmd.cvp_session.direction,
cvp_session_cmd.cvp_session.tx_port_id,
- cvp_session_cmd.cvp_session.rx_port_id);
+ cvp_session_cmd.cvp_session.rx_port_id,
+ cvp_session_cmd.cvp_session.vocproc_mode);
+ pr_debug("rx_topology: %d, profile_id: 0x%x, pkt_size: %d\n",
+ cvp_session_cmd.cvp_session.rx_topology_id,
+ cvp_session_cmd.cvp_session.profile_id,
+ cvp_session_cmd.hdr.pkt_size);
v->cvp_state = CMD_STATUS_FAIL;
ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_session_cmd);
@@ -1266,7 +1437,6 @@
goto fail;
}
-
/* enable vocproc */
ret = voice_send_enable_vocproc_cmd(v);
if (ret < 0)
@@ -1280,9 +1450,19 @@
/* send tty mode if tty device is used */
voice_send_tty_mode_cmd(v);
+ if (is_voip_session(v->session_id)) {
+ ret = voice_send_mvm_cal_network_cmd(v);
+ if (ret < 0)
+ pr_err("%s: voice_send_mvm_cal_network_cmd: %d\n",
+ __func__, ret);
- if (is_voip_session(v->session_id))
+ ret = voice_send_mvm_media_type_cmd(v);
+ if (ret < 0)
+ pr_err("%s: voice_send_mvm_media_type_cmd: %d\n",
+ __func__, ret);
+
voice_send_netid_timing_cmd(v);
+ }
/* Start in-call music delivery if this feature is enabled */
if (v->music_info.play_enable)
@@ -1350,6 +1530,55 @@
return -EINVAL;
}
+static int voice_send_mvm_cal_network_cmd(struct voice_data *v)
+{
+ struct vss_imvm_cmd_set_cal_network_t mvm_set_cal_network;
+ int ret = 0;
+ void *apr_mvm;
+ u16 mvm_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_mvm = common.apr_q6_mvm;
+
+ if (!apr_mvm) {
+ pr_err("%s: apr_mvm is NULL.\n", __func__);
+ return -EINVAL;
+ }
+ mvm_handle = voice_get_mvm_handle(v);
+
+ mvm_set_cal_network.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ mvm_set_cal_network.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(mvm_set_cal_network) - APR_HDR_SIZE);
+ mvm_set_cal_network.hdr.src_port = v->session_id;
+ mvm_set_cal_network.hdr.dest_port = mvm_handle;
+ mvm_set_cal_network.hdr.token = 0;
+ mvm_set_cal_network.hdr.opcode = VSS_IMVM_CMD_SET_CAL_NETWORK;
+ mvm_set_cal_network.network_id = VSS_ICOMMON_CAL_NETWORK_ID_NONE;
+
+ v->mvm_state = CMD_STATUS_FAIL;
+ ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_set_cal_network);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending SET_NETWORK\n", __func__, ret);
+ goto fail;
+ }
+
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout %d\n", __func__, ret);
+ goto fail;
+ }
+ return 0;
+fail:
+ return -EINVAL;
+}
+
static int voice_send_netid_timing_cmd(struct voice_data *v)
{
int ret = 0;
@@ -1590,10 +1819,177 @@
cvp_handle = 0;
voice_set_cvp_handle(v, cvp_handle);
+ return 0;
+fail:
+ return -EINVAL;
+}
+static int voice_send_mvm_unmap_memory_physical_cmd(struct voice_data *v,
+ unsigned int bufcnt)
+{
+ struct vss_imemory_cmd_unmap_t mem_unmap;
+ int ret = 0;
+ void *apr_mvm;
+ u16 mvm_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_mvm = common.apr_q6_mvm;
+
+ if (!apr_mvm) {
+ pr_err("%s: apr_mvm is NULL.\n", __func__);
+ return -EINVAL;
+ }
+ mvm_handle = voice_get_mvm_handle(v);
+
+ mem_unmap.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ mem_unmap.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(mem_unmap) - APR_HDR_SIZE);
+ mem_unmap.hdr.src_port = v->session_id;
+ mem_unmap.hdr.dest_port = mvm_handle;
+ mem_unmap.hdr.token = 0;
+ mem_unmap.hdr.opcode = VSS_IMEMORY_CMD_UNMAP;
+ mem_unmap.mem_handle = v->shmem_info.mem_handle;
+
+ pr_debug("%s: mem_handle: ox%x\n", __func__, mem_unmap.mem_handle);
+
+ v->mvm_state = CMD_STATUS_FAIL;
+ ret = apr_send_pkt(apr_mvm, (uint32_t *) &mem_unmap);
+ if (ret < 0) {
+ pr_err("mem_unmap op[0x%x]ret[%d]\n",
+ mem_unmap.hdr.opcode, ret);
+ goto fail;
+ }
+
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout %d\n", __func__, ret);
+ goto fail;
+ }
return 0;
fail:
+ return ret;
+}
+
+static int voice_send_cvs_packet_exchange_config_cmd(struct voice_data *v)
+{
+ struct vss_istream_cmd_set_oob_packet_exchange_config_t
+ packet_exchange_config_pkt;
+ int ret = 0;
+ uint64_t *dec_buf;
+ uint64_t *enc_buf;
+ void *apr_cvs;
+ u16 cvs_handle;
+ dec_buf = (uint64_t *)v->shmem_info.sh_buf.buf[0].phys;
+ enc_buf = (uint64_t *)v->shmem_info.sh_buf.buf[1].phys;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_cvs = common.apr_q6_cvs;
+
+ if (!apr_cvs) {
+ pr_err("%s: apr_cvs is NULL.\n", __func__);
+ return -EINVAL;
+ }
+ cvs_handle = voice_get_cvs_handle(v);
+
+ packet_exchange_config_pkt.hdr.hdr_field = APR_HDR_FIELD(
+ APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ packet_exchange_config_pkt.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(packet_exchange_config_pkt) -
+ APR_HDR_SIZE);
+ packet_exchange_config_pkt.hdr.src_port = v->session_id;
+ packet_exchange_config_pkt.hdr.dest_port = cvs_handle;
+ packet_exchange_config_pkt.hdr.token = 0;
+ packet_exchange_config_pkt.hdr.opcode =
+ VSS_ISTREAM_CMD_SET_OOB_PACKET_EXCHANGE_CONFIG;
+ packet_exchange_config_pkt.mem_handle = v->shmem_info.mem_handle;
+ packet_exchange_config_pkt.dec_buf_addr = (uint32_t)dec_buf;
+ packet_exchange_config_pkt.dec_buf_size = 4096;
+ packet_exchange_config_pkt.enc_buf_addr = (uint32_t)enc_buf;
+ packet_exchange_config_pkt.enc_buf_size = 4096;
+
+ pr_debug("%s: dec buf: add %p, size %d, enc buf: add %p, size %d\n",
+ __func__,
+ dec_buf,
+ packet_exchange_config_pkt.dec_buf_size,
+ enc_buf,
+ packet_exchange_config_pkt.enc_buf_size);
+
+ v->cvs_state = CMD_STATUS_FAIL;
+ ret = apr_send_pkt(apr_cvs, (uint32_t *) &packet_exchange_config_pkt);
+ if (ret < 0) {
+ pr_err("Failed to send packet exchange config cmd %d\n", ret);
+ goto fail;
+ }
+
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret)
+ pr_err("%s: wait_event timeout %d\n", __func__, ret);
+
+ return 0;
+fail:
+ return -EINVAL;
+}
+
+static int voice_send_cvs_data_exchange_mode_cmd(struct voice_data *v)
+{
+ struct vss_istream_cmd_set_packet_exchange_mode_t data_exchange_pkt;
+ int ret = 0;
+ void *apr_cvs;
+ u16 cvs_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_cvs = common.apr_q6_cvs;
+
+ if (!apr_cvs) {
+ pr_err("%s: apr_cvs is NULL.\n", __func__);
+ return -EINVAL;
+ }
+ cvs_handle = voice_get_cvs_handle(v);
+
+ data_exchange_pkt.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ data_exchange_pkt.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(data_exchange_pkt) - APR_HDR_SIZE);
+ data_exchange_pkt.hdr.src_port = v->session_id;
+ data_exchange_pkt.hdr.dest_port = cvs_handle;
+ data_exchange_pkt.hdr.token = 0;
+ data_exchange_pkt.hdr.opcode = VSS_ISTREAM_CMD_SET_PACKET_EXCHANGE_MODE;
+ data_exchange_pkt.mode = VSS_ISTREAM_PACKET_EXCHANGE_MODE_OUT_OF_BAND;
+
+ v->cvs_state = CMD_STATUS_FAIL;
+ ret = apr_send_pkt(apr_cvs, (uint32_t *) &data_exchange_pkt);
+ if (ret < 0) {
+ pr_err("Failed to send data exchange mode %d\n", ret);
+ goto fail;
+ }
+
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret)
+ pr_err("%s: wait_event timeout %d\n", __func__, ret);
+
+ return 0;
+fail:
return -EINVAL;
}
@@ -1878,7 +2274,6 @@
return 0;
fail:
-
return ret;
}
@@ -2202,16 +2597,54 @@
pr_err("%s: set device failed\n", __func__);
goto fail;
}
- /* send tty mode if tty device is used */
- voice_send_tty_mode_cmd(v);
- v->voc_state = VOC_RUN;
+ ret = voice_send_enable_vocproc_cmd(v);
+ if (ret < 0) {
+ pr_err("%s: enable vocproc failed %d\n", __func__, ret);
+ goto fail;
+ }
+
+ /* Send tty mode if tty device is used */
+ voice_send_tty_mode_cmd(v);
+
+ v->voc_state = VOC_RUN;
}
fail:
mutex_unlock(&v->lock);
+ return ret;
+}
+
+static int voice_set_packet_exchange_mode_and_config(uint16_t session_id,
+ uint32_t mode)
+{
+ struct voice_data *v = voice_get_session(session_id);
+ int ret = 0;
+
+ if (v == NULL) {
+ pr_err("%s: invalid session_id 0x%x\n", __func__, session_id);
+ return -EINVAL;
+ }
+
+ if (v->voc_state != VOC_RUN)
+ ret = voice_send_cvs_data_exchange_mode_cmd(v);
+
+ if (ret) {
+ pr_err("%s: Error voice_send_data_exchange_mode_cmd %d\n",
+ __func__, ret);
+ goto fail;
+ }
+
+ ret = voice_send_cvs_packet_exchange_config_cmd(v);
+ if (ret) {
+ pr_err("%s: Error: voice_send_packet_exchange_config_cmd %d\n",
+ __func__, ret);
+ goto fail;
+ }
return ret;
+fail:
+ return -EINVAL;
}
int voc_set_tx_mute(uint16_t session_id, uint32_t dir, uint32_t mute)
@@ -2552,6 +2985,22 @@
pr_err("create mvm and cvs failed\n");
goto fail;
}
+ if (is_voip_session(session_id)) {
+ ret = voice_send_mvm_map_memory_physical_cmd(v);
+ if (ret) {
+ pr_err("%s: mvm_map_memory_phy failed %d\n",
+ __func__, ret);
+ goto fail;
+ }
+ ret = voice_set_packet_exchange_mode_and_config(
+ session_id,
+ VSS_ISTREAM_PACKET_EXCHANGE_MODE_OUT_OF_BAND);
+ if (ret) {
+ pr_err("%s: Err: exchange_mode_and_config %d\n",
+ __func__, ret);
+ goto fail;
+ }
+ }
ret = voice_send_dual_control_cmd(v);
if (ret < 0) {
pr_err("Err Dual command failed\n");
@@ -2570,7 +3019,8 @@
v->voc_state = VOC_RUN;
}
-fail: mutex_unlock(&v->lock);
+fail:
+ mutex_unlock(&v->lock);
return ret;
}
@@ -2638,6 +3088,7 @@
if (data->payload_size) {
ptr = data->payload;
+ pr_info("%x %x\n", ptr[0], ptr[1]);
/* ping mvm service ACK */
switch (ptr[0]) {
case VSS_IMVM_CMD_CREATE_PASSIVE_CONTROL_SESSION:
@@ -2666,6 +3117,9 @@
case VSS_ICOMMON_CMD_SET_VOICE_TIMING:
case VSS_IWIDEVOICE_CMD_SET_WIDEVOICE:
case VSS_IMVM_CMD_SET_POLICY_DUAL_CONTROL:
+ case VSS_IMVM_CMD_SET_CAL_NETWORK:
+ case VSS_IMVM_CMD_SET_CAL_MEDIA_TYPE:
+ case VSS_IMEMORY_CMD_UNMAP:
pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
v->mvm_state = CMD_STATUS_SUCCESS;
wake_up(&v->mvm_wait);
@@ -2676,8 +3130,19 @@
break;
}
}
+ } else if (data->opcode == VSS_IMEMORY_RSP_MAP) {
+ pr_debug("%s, Revd VSS_IMEMORY_RSP_MAP response\n", __func__);
+ if (data->payload_size) {
+ ptr = data->payload;
+ if (ptr[0]) {
+ v->shmem_info.mem_handle = ptr[0];
+ pr_debug("%s: shared mem_handle: 0x[%x]\n",
+ __func__, v->shmem_info.mem_handle);
+ v->mvm_state = CMD_STATUS_SUCCESS;
+ wake_up(&v->mvm_wait);
+ }
+ }
}
-
return 0;
}
@@ -2725,6 +3190,7 @@
if (data->payload_size) {
ptr = data->payload;
+ pr_info("%x %x\n", ptr[0], ptr[1]);
/*response from CVS */
switch (ptr[0]) {
case VSS_ISTREAM_CMD_CREATE_PASSIVE_CONTROL_SESSION:
@@ -2754,6 +3220,8 @@
case VSS_ISTREAM_CMD_STOP_PLAYBACK:
case VSS_ISTREAM_CMD_START_RECORD:
case VSS_ISTREAM_CMD_STOP_RECORD:
+ case VSS_ISTREAM_CMD_SET_PACKET_EXCHANGE_MODE:
+ case VSS_ISTREAM_CMD_SET_OOB_PACKET_EXCHANGE_CONFIG:
pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
v->cvs_state = CMD_STATUS_SUCCESS;
wake_up(&v->cvs_wait);
@@ -2765,63 +3233,117 @@
break;
}
}
- } else if (data->opcode == VSS_ISTREAM_EVT_SEND_ENC_BUFFER) {
- uint32_t *voc_pkt = data->payload;
- uint32_t pkt_len = data->payload_size;
-
- if (voc_pkt != NULL && c->mvs_info.ul_cb != NULL) {
- pr_debug("%s: Media type is 0x%x\n",
- __func__, voc_pkt[0]);
-
- /* Remove media ID from payload. */
- voc_pkt++;
- pkt_len = pkt_len - 4;
-
- c->mvs_info.ul_cb((uint8_t *)voc_pkt,
- pkt_len,
- c->mvs_info.private_data);
- } else
- pr_err("%s: voc_pkt is 0x%x ul_cb is 0x%x\n",
- __func__, (unsigned int)voc_pkt,
- (unsigned int) c->mvs_info.ul_cb);
- } else if (data->opcode == VSS_ISTREAM_EVT_REQUEST_DEC_BUFFER) {
- struct cvs_send_dec_buf_cmd send_dec_buf;
+ } else if (data->opcode ==
+ VSS_ISTREAM_EVT_OOB_NOTIFY_ENC_BUFFER_READY) {
int ret = 0;
- uint32_t pkt_len = 0;
+ u16 cvs_handle;
+ uint32_t *cvs_voc_pkt;
+ struct cvs_enc_buffer_consumed_cmd send_enc_buf_consumed_cmd;
+ void *apr_cvs;
- if (c->mvs_info.dl_cb != NULL) {
- send_dec_buf.dec_buf.media_id = c->mvs_info.media_type;
+ pr_debug("Encoder buffer is ready\n");
- c->mvs_info.dl_cb(
- (uint8_t *)&send_dec_buf.dec_buf.packet_data,
- &pkt_len,
- c->mvs_info.private_data);
+ apr_cvs = common.apr_q6_cvs;
+ if (!apr_cvs) {
+ pr_err("%s: apr_cvs is NULL\n", __func__);
+ return -EINVAL;
+ }
+ cvs_handle = voice_get_cvs_handle(v);
- send_dec_buf.hdr.hdr_field =
- APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
- APR_HDR_LEN(APR_HDR_SIZE),
- APR_PKT_VER);
- send_dec_buf.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
- sizeof(send_dec_buf.dec_buf.media_id) + pkt_len);
- send_dec_buf.hdr.src_port = v->session_id;
- send_dec_buf.hdr.dest_port = voice_get_cvs_handle(v);
- send_dec_buf.hdr.token = 0;
- send_dec_buf.hdr.opcode =
- VSS_ISTREAM_EVT_SEND_DEC_BUFFER;
+ send_enc_buf_consumed_cmd.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ send_enc_buf_consumed_cmd.hdr.pkt_size =
+ APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(send_enc_buf_consumed_cmd) - APR_HDR_SIZE);
- ret = apr_send_pkt(c->apr_q6_cvs,
- (uint32_t *) &send_dec_buf);
+ send_enc_buf_consumed_cmd.hdr.src_port = v->session_id;
+ send_enc_buf_consumed_cmd.hdr.dest_port = cvs_handle;
+ send_enc_buf_consumed_cmd.hdr.token = 0;
+ send_enc_buf_consumed_cmd.hdr.opcode =
+ VSS_ISTREAM_EVT_OOB_NOTIFY_ENC_BUFFER_CONSUMED;
+
+ cvs_voc_pkt = v->shmem_info.sh_buf.buf[1].data;
+ if (cvs_voc_pkt != NULL && common.mvs_info.ul_cb != NULL) {
+ common.mvs_info.ul_cb((uint8_t *)&cvs_voc_pkt[3],
+ cvs_voc_pkt[2],
+ common.mvs_info.private_data);
+ } else
+ pr_err("%s: cvs_voc_pkt or ul_cb is NULL\n", __func__);
+
+ ret = apr_send_pkt(apr_cvs,
+ (uint32_t *) &send_enc_buf_consumed_cmd);
+ if (ret < 0) {
+ pr_err("%s: Err send ENC_BUF_CONSUMED_NOTIFY %d\n",
+ __func__, ret);
+ goto fail;
+ }
+ } else if (data->opcode == VSS_ISTREAM_EVT_SEND_ENC_BUFFER) {
+ pr_debug("Recd VSS_ISTREAM_EVT_SEND_ENC_BUFFER\n");
+ } else if (data->opcode ==
+ VSS_ISTREAM_EVT_OOB_NOTIFY_DEC_BUFFER_REQUEST) {
+ int ret = 0;
+ u16 cvs_handle;
+ uint32_t *cvs_voc_pkt;
+ struct cvs_dec_buffer_ready_cmd send_dec_buf;
+ void *apr_cvs;
+ apr_cvs = common.apr_q6_cvs;
+
+ if (!apr_cvs) {
+ pr_err("%s: apr_cvs is NULL\n", __func__);
+ return -EINVAL;
+ }
+ cvs_handle = voice_get_cvs_handle(v);
+
+ send_dec_buf.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+
+ send_dec_buf.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(send_dec_buf) - APR_HDR_SIZE);
+
+ send_dec_buf.hdr.src_port = v->session_id;
+ send_dec_buf.hdr.dest_port = cvs_handle;
+ send_dec_buf.hdr.token = 0;
+ send_dec_buf.hdr.opcode =
+ VSS_ISTREAM_EVT_OOB_NOTIFY_DEC_BUFFER_READY;
+
+ cvs_voc_pkt = (uint32_t *)(v->shmem_info.sh_buf.buf[0].data);
+ if (cvs_voc_pkt != NULL && common.mvs_info.dl_cb != NULL) {
+ /* Set timestamp to 0 and advance the pointer */
+ cvs_voc_pkt[0] = 0;
+ /* Set media_type and advance the pointer */
+ cvs_voc_pkt[1] = common.mvs_info.media_type;
+ common.mvs_info.dl_cb(
+ (uint8_t *)&cvs_voc_pkt[2],
+ common.mvs_info.private_data);
+ ret = apr_send_pkt(apr_cvs, (uint32_t *) &send_dec_buf);
if (ret < 0) {
- pr_err("%s: Error %d sending DEC_BUF\n",
- __func__, ret);
+ pr_err("%s: Err send DEC_BUF_READY_NOTIFI %d\n",
+ __func__, ret);
goto fail;
}
- } else
- pr_debug("%s: dl_cb is NULL\n", __func__);
+ } else {
+ pr_debug("%s: voc_pkt or dl_cb is NULL\n", __func__);
+ goto fail;
+ }
+ } else if (data->opcode == VSS_ISTREAM_EVT_REQUEST_DEC_BUFFER) {
+ pr_debug("Recd VSS_ISTREAM_EVT_REQUEST_DEC_BUFFER\n");
} else if (data->opcode == VSS_ISTREAM_EVT_SEND_DEC_BUFFER) {
pr_debug("Send dec buf resp\n");
+ } else if (data->opcode == APR_RSP_ACCEPTED) {
+ ptr = data->payload;
+ if (ptr[0])
+ pr_debug("%s: APR_RSP_ACCEPTED for 0x%x:\n",
+ __func__, ptr[0]);
+ } else if (data->opcode == VSS_ISTREAM_EVT_NOT_READY) {
+ pr_debug("Recd VSS_ISTREAM_EVT_NOT_READY\n");
+ } else if (data->opcode == VSS_ISTREAM_EVT_READY) {
+ pr_debug("Recd VSS_ISTREAM_EVT_READY\n");
} else
- pr_debug("Unknown opcode 0x%x\n", data->opcode);
+ pr_err("Unknown opcode 0x%x\n", data->opcode);
fail:
return 0;
@@ -2869,13 +3391,15 @@
if (data->payload_size) {
ptr = data->payload;
+ pr_info("%x %x\n", ptr[0], ptr[1]);
switch (ptr[0]) {
- case VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION:
+ case VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION_V2:
/*response from CVP */
pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
if (!ptr[1]) {
voice_set_cvp_handle(v, data->src_port);
- pr_debug("cvphdl=%d\n", data->src_port);
+ pr_debug("status: %d, cvphdl=%d\n",
+ ptr[1], data->src_port);
} else
pr_err("got NACK from CVP create session response\n");
v->cvp_state = CMD_STATUS_SUCCESS;
@@ -2908,6 +3432,138 @@
return 0;
}
+static int voice_alloc_oob_shared_mem(void)
+{
+ int cnt = 0;
+ int rc = 0;
+ int len;
+ void *mem_addr;
+ dma_addr_t phys;
+ int bufsz = BUFFER_BLOCK_SIZE;
+ int bufcnt = NUM_OF_BUFFERS;
+ struct voice_data *v = voice_get_session(
+ common.voice[VOC_PATH_FULL].session_id);
+
+ v->shmem_info.sh_buf.client = msm_ion_client_create(UINT_MAX,
+ "voip_client");
+ if (IS_ERR_OR_NULL((void *)v->shmem_info.sh_buf.client)) {
+ pr_err("%s: ION create client failed\n", __func__);
+ goto err;
+ }
+
+ v->shmem_info.sh_buf.handle = ion_alloc(v->shmem_info.sh_buf.client,
+ bufsz * bufcnt, SZ_4K,
+ (0x1 << ION_AUDIO_HEAP_ID));
+ if (IS_ERR_OR_NULL((void *)v->shmem_info.sh_buf.handle)) {
+ pr_err("%s: ION memory allocation failed\n",
+ __func__);
+ goto err_ion_client;
+ }
+
+ rc = ion_phys(v->shmem_info.sh_buf.client, v->shmem_info.sh_buf.handle,
+ (ion_phys_addr_t *)&phys, (size_t *)&len);
+ if (rc) {
+ pr_err("%s: ION Get Physical failed, rc = %d\n",
+ __func__, rc);
+ goto err_ion_handle;
+ }
+
+ mem_addr = ion_map_kernel(v->shmem_info.sh_buf.client,
+ v->shmem_info.sh_buf.handle, 0);
+ if (IS_ERR_OR_NULL(mem_addr)) {
+ pr_err("%s: ION memory mapping failed\n", __func__);
+ goto err_ion_handle;
+ }
+
+ while (cnt < bufcnt) {
+ v->shmem_info.sh_buf.buf[cnt].data = mem_addr + (cnt * bufsz);
+ v->shmem_info.sh_buf.buf[cnt].phys = phys + (cnt * bufsz);
+ v->shmem_info.sh_buf.buf[cnt].size = bufsz;
+ cnt++;
+ }
+
+ pr_debug("%s buf[0].data:[%p], buf[0].phys:[%p], &buf[0].phys:[%p],\n",
+ __func__,
+ (void *)v->shmem_info.sh_buf.buf[0].data,
+ (void *)v->shmem_info.sh_buf.buf[0].phys,
+ (void *)&v->shmem_info.sh_buf.buf[0].phys);
+ pr_debug("%s: buf[1].data:[%p], buf[1].phys[%p], &buf[1].phys[%p]\n",
+ __func__,
+ (void *)v->shmem_info.sh_buf.buf[1].data,
+ (void *)v->shmem_info.sh_buf.buf[1].phys,
+ (void *)&v->shmem_info.sh_buf.buf[1].phys);
+
+ memset((void *)v->shmem_info.sh_buf.buf[0].data, 0, (bufsz * bufcnt));
+
+ return 0;
+
+err_ion_handle:
+ ion_free(v->shmem_info.sh_buf.client, v->shmem_info.sh_buf.handle);
+err_ion_client:
+ ion_client_destroy(v->shmem_info.sh_buf.client);
+err:
+ return -EINVAL;
+}
+
+static int voice_alloc_oob_mem_table(void)
+{
+ int rc = 0;
+ int len;
+ struct voice_data *v = voice_get_session(
+ common.voice[VOC_PATH_FULL].session_id);
+
+ v->shmem_info.memtbl.client = msm_ion_client_create(UINT_MAX,
+ "voip_client");
+ if (IS_ERR_OR_NULL((void *)v->shmem_info.memtbl.client)) {
+ pr_err("%s: ION create client for memtbl failed\n", __func__);
+ goto err;
+ }
+
+ v->shmem_info.memtbl.handle = ion_alloc(v->shmem_info.memtbl.client,
+ sizeof(struct vss_imemory_table_t), SZ_4K,
+ (0x1 << ION_AUDIO_HEAP_ID));
+ if (IS_ERR_OR_NULL((void *) v->shmem_info.memtbl.handle)) {
+ pr_err("%s: ION memory allocation for memtbl failed\n",
+ __func__);
+ goto err_ion_client;
+ }
+
+ rc = ion_phys(v->shmem_info.memtbl.client, v->shmem_info.memtbl.handle,
+ (ion_phys_addr_t *)&v->shmem_info.memtbl.phys, (size_t *)&len);
+ if (rc) {
+ pr_err("%s: ION Get Physical for memtbl failed, rc = %d\n",
+ __func__, rc);
+ goto err_ion_handle;
+ }
+
+ v->shmem_info.memtbl.data = ion_map_kernel(v->shmem_info.memtbl.client,
+ v->shmem_info.memtbl.handle,
+ 0);
+ if (IS_ERR_OR_NULL((void *)v->shmem_info.memtbl.data)) {
+ pr_err("%s: ION memory mapping for memtbl failed\n",
+ __func__);
+ goto err_ion_handle;
+ }
+
+ memset(v->shmem_info.memtbl.data, 0,
+ sizeof(struct vss_imemory_table_t));
+
+ v->shmem_info.memtbl.size = sizeof(struct vss_imemory_table_t);
+
+ pr_debug("%s data[%p]phys[%p][%p]\n", __func__,
+ (void *)v->shmem_info.memtbl.data,
+ (void *)v->shmem_info.memtbl.phys,
+ (void *)&v->shmem_info.memtbl.phys);
+
+ return 0;
+
+err_ion_handle:
+ ion_free(v->shmem_info.memtbl.client, v->shmem_info.memtbl.handle);
+err_ion_client:
+ ion_client_destroy(v->shmem_info.memtbl.client);
+err:
+ return -EINVAL;
+}
static int __init voice_init(void)
{
@@ -2946,6 +3602,17 @@
mutex_init(&common.voice[i].lock);
}
+ /* Allocate shared memory for OOB Voip */
+ rc = voice_alloc_oob_shared_mem();
+ if (rc < 0)
+ pr_err("failed to alloc shared memory for OOB %d\n", rc);
+ else {
+ /* Allocate mem map table for OOB */
+ rc = voice_alloc_oob_mem_table();
+ if (rc < 0)
+ pr_err("failed to alloc mem map talbe %d\n", rc);
+ }
+
return rc;
}
diff --git a/sound/soc/msm/qdsp6v2/q6voice.h b/sound/soc/msm/qdsp6v2/q6voice.h
index 8bafe04..df0cbec 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.h
+++ b/sound/soc/msm/qdsp6v2/q6voice.h
@@ -17,6 +17,13 @@
#define MAX_VOC_PKT_SIZE 642
#define SESSION_NAME_LEN 20
+#define NUM_OF_MEMORY_BLOCKS 1
+#define NUM_OF_BUFFERS 2
+/*
+ * BUFFER BLOCK SIZE based on
+ * the supported page size
+ */
+#define BUFFER_BLOCK_SIZE 4096
#define VOC_REC_UPLINK 0x00
#define VOC_REC_DOWNLINK 0x01
@@ -60,6 +67,26 @@
VOC_RELEASE,
};
+struct mem_buffer {
+ dma_addr_t phys;
+ void *data;
+ uint32_t size; /* size of buffer */
+};
+
+struct share_mem_buf {
+ struct ion_handle *handle;
+ struct ion_client *client;
+ struct mem_buffer buf[NUM_OF_BUFFERS];
+};
+
+struct mem_map_table {
+ dma_addr_t phys;
+ void *data;
+ uint32_t size; /* size of buffer */
+ struct ion_handle *handle;
+ struct ion_client *client;
+};
+
/* Common */
#define VSS_ICOMMON_CMD_SET_UI_PROPERTY 0x00011103
/* Set a UI property */
@@ -119,8 +146,6 @@
#define VSS_IMVM_CMD_CREATE_FULL_CONTROL_SESSION 0x000110FE
/* Create a new full control MVM session. */
-#define VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION_V2 0x000112BF
-
#define APRV2_IBASIC_CMD_DESTROY_SESSION 0x0001003C
/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
@@ -165,6 +190,12 @@
#define VSS_IWIDEVOICE_CMD_SET_WIDEVOICE 0x00011243
/* Enable/disable WideVoice */
+#define VSS_IMEMORY_CMD_MAP_PHYSICAL 0x00011334
+#define VSS_IMEMORY_RSP_MAP 0x00011336
+#define VSS_IMEMORY_CMD_UNMAP 0x00011337
+#define VSS_IMVM_CMD_SET_CAL_NETWORK 0x0001137A
+#define VSS_IMVM_CMD_SET_CAL_MEDIA_TYPE 0x0001137B
+
enum msm_audio_voc_rate {
VOC_0_RATE, /* Blank frame */
VOC_8_RATE, /* 1/8 rate */
@@ -311,6 +342,92 @@
struct vss_iwidevoice_cmd_set_widevoice_t vss_set_wv;
} __packed;
+struct vss_imemory_table_descriptor_t {
+ uint64_t mem_address;
+ /*
+ * Base physical address of the table. The address must be aligned
+ * to LCM( cache_line_size, page_align, max_data_width ), where the
+ * attributes are specified in #VSS_IMEMORY_CMD_MAP_PHYSICAL, and
+ * LCM = Least Common Multiple. The table at the address must have
+ * the format specified by #vss_imemory_table_t.
+ */
+ uint32_t mem_size;
+ /* Size in bytes of the table. */
+} __packed;
+
+struct vss_imemory_block_t {
+ uint64_t mem_address;
+ /*
+ * Base address of the memory block. The address is virtual for virtual
+ * memory and physical for physical memory. The address must be aligned
+ * to LCM( cache_line_size, page_align, max_data_width ), where the
+ * attributes are specified in VSS_IMEMORY_CMD_MAP_VIRTUAL or
+ * VSS_IMEMORY_CMD_MAP_PHYSICAL, and LCM = Least Common Multiple.
+ */
+ uint32_t mem_size;
+ /*
+ * Size in bytes of the memory block. The size must be multiple of
+ * page_align, where page_align is specified in
+ * VSS_IMEMORY_CMD_MAP_VIRTUAL or #VSS_IMEMORY_CMD_MAP_PHYSICAL.
+ */
+} __packed;
+
+struct vss_imemory_table_t {
+ struct vss_imemory_table_descriptor_t next_table_descriptor;
+ /*
+ * Specifies the next table. If there is no next table,
+ * set the size of the table to 0 and the table address is ignored.
+ */
+ struct vss_imemory_block_t blocks[NUM_OF_MEMORY_BLOCKS];
+ /* Specifies one ore more memory blocks. */
+} __packed;
+
+struct vss_imemory_cmd_map_physical_t {
+ struct apr_hdr hdr;
+ struct vss_imemory_table_descriptor_t table_descriptor;
+ bool is_cached;
+ /*
+ * Indicates cached or uncached memory. Supported values:
+ * TRUE - Cached.
+ */
+ uint16_t cache_line_size;
+ /* Cache line size in bytes. Supported values: 128 */
+ uint32_t access_mask;
+ /*
+ * CVD's access permission to the memory while it is mapped.
+ * Supported values:
+ * bit 0 - If set, the memory is readable.
+ * bit 1 - If set, the memory is writable.
+ */
+ uint32_t page_align;
+ /* Page frame alignment in bytes. Supported values: 4096 */
+ uint8_t min_data_width;
+ /*
+ * Minimum native data type width in bits that can be accessed.
+ * Supported values: 8
+ */
+ uint8_t max_data_width;
+ /*
+ * Maximum native data type width in bits that can be accessed.
+ * Supported values: 64
+ */
+} __packed;
+
+struct vss_imvm_cmd_set_cal_network_t {
+ struct apr_hdr hdr;
+ uint32_t network_id;
+} __packed;
+
+struct vss_imvm_cmd_set_cal_media_type_t {
+ struct apr_hdr hdr;
+ uint32_t media_id;
+} __packed;
+
+struct vss_imemory_cmd_unmap_t {
+ struct apr_hdr hdr;
+ uint32_t mem_handle;
+} __packed;
+
/* TO CVS commands */
#define VSS_ISTREAM_CMD_CREATE_PASSIVE_CONTROL_SESSION 0x00011140
/**< Wait for APRV2_IBASIC_RSP_RESULT response. */
@@ -337,6 +454,8 @@
* The client should respond with a VSS_ISTREAM_EVT_SEND_DEC_BUFFER event.
*/
+#define VSS_ISTREAM_EVT_OOB_NOTIFY_DEC_BUFFER_REQUEST 0x0001136E
+
#define VSS_ISTREAM_EVT_SEND_DEC_BUFFER 0x00011016
/* Event sent by the client to the stream in response to a
* VSS_ISTREAM_EVT_REQUEST_DEC_BUFFER event, providing a decoder packet.
@@ -376,6 +495,29 @@
#define VSS_TAP_POINT_STREAM_END 0x00010F79
/* Indicates that specified path should be tapped at the end of the stream. */
+#define VSS_ISTREAM_EVT_NOT_READY 0x000110FD
+
+#define VSS_ISTREAM_EVT_READY 0x000110FC
+
+#define VSS_ISTREAM_EVT_OOB_NOTIFY_DEC_BUFFER_READY 0x0001136F
+/*notify dsp that decoder buffer is ready*/
+
+#define VSS_ISTREAM_EVT_OOB_NOTIFY_ENC_BUFFER_READY 0x0001136C
+/*dsp notifying client that encoder buffer is ready*/
+
+#define VSS_ISTREAM_EVT_OOB_NOTIFY_ENC_BUFFER_CONSUMED 0x0001136D
+/*notify dsp that encoder buffer is consumed*/
+
+#define VSS_ISTREAM_CMD_SET_OOB_PACKET_EXCHANGE_CONFIG 0x0001136B
+
+#define VSS_ISTREAM_PACKET_EXCHANGE_MODE_INBAND 0
+/* In-band packet exchange mode. */
+
+#define VSS_ISTREAM_PACKET_EXCHANGE_MODE_OUT_OF_BAND 1
+/* Out-of-band packet exchange mode. */
+
+#define VSS_ISTREAM_CMD_SET_PACKET_EXCHANGE_MODE 0x0001136A
+
struct vss_istream_cmd_start_record_t {
uint32_t rx_tap_point;
/* Tap point to use on the Rx path. Supported values are:
@@ -614,6 +756,28 @@
struct vss_istream_cmd_start_record_t rec_mode;
} __packed;
+struct cvs_dec_buffer_ready_cmd {
+ struct apr_hdr hdr;
+} __packed;
+
+struct cvs_enc_buffer_consumed_cmd {
+ struct apr_hdr hdr;
+} __packed;
+
+struct vss_istream_cmd_set_oob_packet_exchange_config_t {
+ struct apr_hdr hdr;
+ uint32_t mem_handle;
+ uint64_t enc_buf_addr;
+ uint32_t enc_buf_size;
+ uint64_t dec_buf_addr;
+ uint32_t dec_buf_size;
+} __packed;
+
+struct vss_istream_cmd_set_packet_exchange_mode_t {
+ struct apr_hdr hdr;
+ uint32_t mode;
+} __packed;
+
/* TO CVP commands */
#define VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION 0x000100C3
@@ -646,6 +810,17 @@
#define VSS_IVOCPROC_TOPOLOGY_ID_RX_DEFAULT 0x00010F77
/* Newtwork IDs */
+#define VSS_ICOMMON_CAL_NETWORK_ID_NONE 0x0001135E
+
+/* Select internal mixing mode. */
+#define VSS_IVOCPROC_VOCPROC_MODE_EC_INT_MIXING 0x00010F7C
+
+/* Select external mixing mode. */
+#define VSS_IVOCPROC_VOCPROC_MODE_EC_EXT_MIXING 0x00010F7D
+
+/* Default AFE port ID. Applicable to Tx and Rx. */
+#define VSS_IVOCPROC_PORT_ID_NONE 0xFFFF
+
#define VSS_NETWORK_ID_DEFAULT 0x00010037
#define VSS_NETWORK_ID_VOIP_NB 0x00011240
#define VSS_NETWORK_ID_VOIP_WB 0x00011241
@@ -678,73 +853,92 @@
#define VOICE_CMD_GET_PARAM 0x00011007
#define VOICE_EVT_GET_PARAM_ACK 0x00011008
-struct vss_ivocproc_cmd_create_full_control_session_t {
+#define VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION_V2 0x000112BF
+
+struct vss_ivocproc_cmd_create_full_control_session_v2_t {
uint16_t direction;
/*
- * stream direction.
- * 0 : TX only
- * 1 : RX only
- * 2 : TX and RX
+ * Vocproc direction. The supported values:
+ * VSS_IVOCPROC_DIRECTION_RX
+ * VSS_IVOCPROC_DIRECTION_TX
+ * VSS_IVOCPROC_DIRECTION_RX_TX
*/
- uint32_t tx_port_id;
+ uint16_t tx_port_id;
/*
- * TX device port ID which vocproc will connect to. If not supplying a
- * port ID set to VSS_IVOCPROC_PORT_ID_NONE.
+ * Tx device port ID to which the vocproc connects. If a port ID is
+ * not being supplied, set this to #VSS_IVOCPROC_PORT_ID_NONE.
*/
uint32_t tx_topology_id;
/*
- * Tx leg topology ID. If not supplying a topology ID set to
- * VSS_IVOCPROC_TOPOLOGY_ID_NONE.
+ * Tx path topology ID. If a topology ID is not being supplied, set
+ * this to #VSS_IVOCPROC_TOPOLOGY_ID_NONE.
*/
- uint32_t rx_port_id;
+ uint16_t rx_port_id;
/*
- * RX device port ID which vocproc will connect to. If not supplying a
- * port ID set to VSS_IVOCPROC_PORT_ID_NONE.
+ * Rx device port ID to which the vocproc connects. If a port ID is
+ * not being supplied, set this to #VSS_IVOCPROC_PORT_ID_NONE.
*/
uint32_t rx_topology_id;
/*
- * Rx leg topology ID. If not supplying a topology ID set to
- * VSS_IVOCPROC_TOPOLOGY_ID_NONE.
+ * Rx path topology ID. If a topology ID is not being supplied, set
+ * this to #VSS_IVOCPROC_TOPOLOGY_ID_NONE.
*/
- int32_t network_id;
+ uint32_t profile_id;
+ /* Voice calibration profile ID. */
+ uint32_t vocproc_mode;
/*
- * Network ID. (Refer to VSS_NETWORK_ID_XXX). If not supplying a network
- * ID set to VSS_NETWORK_ID_DEFAULT.
+ * Vocproc mode. The supported values:
+ * VSS_IVOCPROC_VOCPROC_MODE_EC_INT_MIXING
+ * VSS_IVOCPROC_VOCPROC_MODE_EC_EXT_MIXING
+ */
+ uint16_t ec_ref_port_id;
+ /*
+ * Port ID to which the vocproc connects for receiving echo
+ * cancellation reference signal. If a port ID is not being supplied,
+ * set this to #VSS_IVOCPROC_PORT_ID_NONE. This parameter value is
+ * ignored when the vocproc_mode parameter is set to
+ * VSS_IVOCPROC_VOCPROC_MODE_EC_INT_MIXING.
+ */
+ char name[SESSION_NAME_LEN];
+ /*
+ * Session name string used to identify a session that can be shared
+ * with passive controllers (optional). The string size, including the
+ * NULL termination character, is limited to 31 characters.
*/
} __packed;
struct vss_ivocproc_cmd_set_volume_index_t {
uint16_t vol_index;
- /**<
- * Volume index utilized by the vocproc to index into the volume table
- * provided in VSS_IVOCPROC_CMD_CACHE_VOLUME_CALIBRATION_TABLE and set
- * volume on the VDSP.
- */
+ /*
+ * Volume index utilized by the vocproc to index into the volume table
+ * provided in VSS_IVOCPROC_CMD_CACHE_VOLUME_CALIBRATION_TABLE and set
+ * volume on the VDSP.
+ */
} __packed;
struct vss_ivocproc_cmd_set_device_t {
uint32_t tx_port_id;
- /**<
- * TX device port ID which vocproc will connect to.
- * VSS_IVOCPROC_PORT_ID_NONE means vocproc will not connect to any port.
- */
+ /*
+ * TX device port ID which vocproc will connect to.
+ * VSS_IVOCPROC_PORT_ID_NONE means vocproc will not connect to any port.
+ */
uint32_t tx_topology_id;
- /**<
- * TX leg topology ID.
- * VSS_IVOCPROC_TOPOLOGY_ID_NONE means vocproc does not contain any
- * pre/post-processing blocks and is pass-through.
- */
+ /*
+ * TX leg topology ID.
+ * VSS_IVOCPROC_TOPOLOGY_ID_NONE means vocproc does not contain any
+ * pre/post-processing blocks and is pass-through.
+ */
int32_t rx_port_id;
- /**<
- * RX device port ID which vocproc will connect to.
- * VSS_IVOCPROC_PORT_ID_NONE means vocproc will not connect to any port.
- */
+ /*
+ * RX device port ID which vocproc will connect to.
+ * VSS_IVOCPROC_PORT_ID_NONE means vocproc will not connect to any port.
+ */
uint32_t rx_topology_id;
- /**<
- * RX leg topology ID.
- * VSS_IVOCPROC_TOPOLOGY_ID_NONE means vocproc does not contain any
- * pre/post-processing blocks and is pass-through.
- */
+ /*
+ * RX leg topology ID.
+ * VSS_IVOCPROC_TOPOLOGY_ID_NONE means vocproc does not contain any
+ * pre/post-processing blocks and is pass-through.
+ */
} __packed;
struct vss_ivocproc_cmd_register_calibration_data_t {
@@ -784,7 +978,7 @@
struct cvp_create_full_ctl_session_cmd {
struct apr_hdr hdr;
- struct vss_ivocproc_cmd_create_full_control_session_t cvp_session;
+ struct vss_ivocproc_cmd_create_full_control_session_v2_t cvp_session;
} __packed;
struct cvp_command {
@@ -835,7 +1029,6 @@
/* CB for down-link packets. */
typedef void (*dl_cb_fn)(uint8_t *voc_pkt,
- uint32_t *pkt_len,
void *private_data);
@@ -862,9 +1055,18 @@
int force;
};
+struct share_memory_info {
+ u32 mem_handle;
+ struct share_mem_buf sh_buf;
+ struct mem_map_table memtbl;
+};
+
struct voice_data {
int voc_state;/*INIT, CHANGE, RELEASE, RUN */
+ /* Shared mem to store decoder and encoder packets */
+ struct share_memory_info shmem_info;
+
wait_queue_head_t mvm_wait;
wait_queue_head_t cvs_wait;
wait_queue_head_t cvp_wait;
@@ -959,7 +1161,8 @@
};
/* called by alsa driver */
-int voc_set_pp_enable(uint16_t session_id, uint32_t module_id, uint32_t enable);
+int voc_set_pp_enable(uint16_t session_id, uint32_t module_id,
+ uint32_t enable);
int voc_get_pp_enable(uint16_t session_id, uint32_t module_id);
int voc_set_widevoice_enable(uint16_t session_id, uint32_t wv_enable);
uint32_t voc_get_widevoice_enable(uint16_t session_id);