Merge "msm: vidc: Add error check before calling release buffers to FW"
diff --git a/Documentation/block/row-iosched.txt b/Documentation/block/row-iosched.txt
index 987bd88..fe8b88b 100644
--- a/Documentation/block/row-iosched.txt
+++ b/Documentation/block/row-iosched.txt
@@ -8,16 +8,28 @@
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.
+The main idea of the ROW scheduling policy is just that:
+- If there are READ requests in pipe - dispatch them, while write
+starvation is considered.
Software description
====================
+The elevator defines a registering mechanism for different IO scheduler
+to implement. This makes implementing a new algorithm quite straight
+forward and requires almost no changes to block/elevator framework. A
+new IO scheduler just has to implement a set of callback functions
+defined by the elevator.
+These callbacks cover all the required IO operations such as
+adding/removing request to/from the scheduler, merging two requests,
+dispatching a request etc.
+
+Design
+======
+
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
+queue is set according to the queues priority. READ queues are
given bigger dispatch quantum than the WRITE queues, within a dispatch
cycle.
@@ -30,88 +42,93 @@
- Regular priority WRITE queue
- Low priority READ queue
+The marking of request as high/low priority will be done by the
+application adding the request and not the scheduler. See TODO section.
+If the request is not marked in any way (high/low) the scheduler
+assigns it to one of the regular priority queues:
+read/write/sync write.
+
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
+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.
+queue Y.
-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 READ request queues ROW IO scheduler allows idling 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
+the ROW IO scheduler identifies the application is inserting requests
+in a high frequency.
+Not all queues can idle. ROW scheduler exposes an enablement struct
+for idling.
+For idling on READ queues, the ROW IO scheduler uses timer mechanism.
+When the timer expires we schedule a delayed work that will signal the
+device driver to fetch another request for dispatch.
-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.
+ROW scheduler will support additional services for block devices that
+supports Urgent Requests. That is, the scheduler may inform the
+device driver upon urgent requests using a newly defined callback.
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.
+interrupted. For example if the device driver issues a long write
+request and a sudden urgent request is received by the scheduler.
+The scheduler will inform the device driver about the urgent request,
+so the device driver can stop the current write request and serve the
+urgent request. In such a case the device driver may also insert back
+to the scheduler the remainder of the interrupted write request, such
+that the scheduler may continue sending urgent 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.
SMP/multi-core
==============
-At the moment the code is acceded from 2 contexts:
+At the moment the code is accessed 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.
+- device 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.
+by the block device 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
+ (default is 100 requests)
+2. rp_read_quantum: dispatch quantum for the regular priority READ
+ queue (default is 100 requests)
+3. hp_swrite_quantum: dispatch quantum for the high priority
+ Synchronous WRITE queue (default is 2 requests)
4. rp_swrite_quantum: dispatch quantum for the regular priority
- Synchronous WRITE queue
+ Synchronous WRITE queue (default is 1 requests)
5. rp_write_quantum: dispatch quantum for the regular priority WRITE
- queue
+ queue (default is 1 requests)
6. lp_read_quantum: dispatch quantum for the low priority READ queue
+ (default is 1 requests)
7. lp_swrite_quantum: dispatch quantum for the low priority Synchronous
- WRITE queue
+ WRITE queue (default is 1 requests)
8. read_idle: how long to idle on read queue in Msec (in case idling
- is enabled on that queue).
+ is enabled on that queue). (default is 5 Msec)
9. read_idle_freq: frequency of inserting READ requests that will
trigger idling. This is the time in Msec between inserting two READ
- requests
+ requests. (default is 8 Msec)
+Note: Dispatch quantum is number of requests that will be dispatched
+from a certain queue in a dispatch cycle.
+
+To do
+=====
+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 than other.
+The former will go to the High priority READ queue, that is given the
+bigger dispatch quantum than any other queue.
+
+Still need to design the way applications will "hint" on the urgency of
+their requests. May be done by ioctl(). We need to look into concrete
+use-cases in order to determine the best solution for this.
+This will be implemented as a second phase.
+
+Design and implement additional services for block devices that
+supports High Priority Requests.
\ No newline at end of file
diff --git a/Documentation/devicetree/bindings/dma/sps/sps.txt b/Documentation/devicetree/bindings/dma/sps/sps.txt
new file mode 100644
index 0000000..094acb1
--- /dev/null
+++ b/Documentation/devicetree/bindings/dma/sps/sps.txt
@@ -0,0 +1,27 @@
+SPS (Smart Peripheral Switch) may be used as a DMA engine to move data
+in either the Peripheral-to-Peripheral (a.k.a. BAM-to-BAM) mode or the
+Peripheral-to-Memory (a.k.a. BAM-System) mode. SPS includes BAM (Bus
+Access Module) hardware block, BAM DMA peripheral, and pipe memory.
+
+Required property:
+ - compatible: should be "qcom,msm_sps"
+
+Optional properties:
+ - reg: offset and size of the register set in the memory map
+ - interrupts: IRQ line
+ - qcom,device-type: specify the device configuration of BAM DMA and
+ pipe memory. Can be one of
+ 1 - With BAM DMA and without pipe memory
+ 2 - With BAM DMA and with pipe memory
+ 3 - Without BAM DMA and without pipe memory
+
+Example:
+
+ qcom,sps@f9980000 {
+ compatible = "qcom,msm_sps";
+ reg = <0xf9984000 0x15000>,
+ <0xf9999000 0xb000>,
+ <0xfe803000 0x4800>;
+ interrupts = <0 94 0>;
+ qcom,device-type = <2>;
+ };
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp.txt b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
index 10732cf..da0708f 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
@@ -6,14 +6,14 @@
SPMI bus. This driver supports various LED modules such as
WLED (white LED), RGB LED and flash LED.
-Required Properties:
-- compatible : should be "qcom,leds-qpnp"
-
Each LED module is represented as a node of "leds-qpnp". This
node will further contain the type of LED supported and its
-properties.
+properties. At least one child node is required for each LED
+module. Each must have the required properties below, in addition
+to the properties for the LED type, WLED, Flash or RGB.
-Required properties:
+Required properties for each child node, WLED, Flash and RGB:
+- compatible : should be "qcom,leds-qpnp"
- qcom,id : must be one of values supported in enum qpnp_led
- label : type of led that will be used, ie "wled"
- qcom,max-current : maximum current that the LED can sustain
diff --git a/Documentation/devicetree/bindings/media/video/msm-camera-flash.txt b/Documentation/devicetree/bindings/media/video/msm-camera-flash.txt
new file mode 100644
index 0000000..72b32be
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-camera-flash.txt
@@ -0,0 +1,23 @@
+* Qualcomm MSM CAMERA FLASH
+
+Required properties:
+- cell-index : Should contain flash source index to diffentiate
+ between different flash devices. These indexes represent flash devices
+ for multiple sensors.
+ - 0, 1, 2, 3
+- compatible :
+ - "qcom,camera-led-flash"
+- qcom,flash-type : Should contain type flash device
+ - 1 for LED flash
+ - 2 for strobe flash
+- qcom,flash-source : Should contain array of phandles to flash source nodes.
+ - pm8941_flash0 pm8941_flash1
+
+Example:
+
+qcom,camera-led-flash {
+ cell-index = <0>;
+ compatible = "qcom,camera-led-flash";
+ qcom,flash-type = <1>;
+ qcom,flash-source = <&pm8941_flash0 &pm8941_flash1>;
+};
diff --git a/Documentation/devicetree/bindings/media/video/msm-cci.txt b/Documentation/devicetree/bindings/media/video/msm-cci.txt
index 6b03fab..e256265 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cci.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cci.txt
@@ -62,9 +62,9 @@
- 1 -> yuv format
Optional properties:
-- qcom,flash-type : should contain flash type if flash is supported for this
- sensor
- - 0 if flash is not supported, 1 if flash is supported
+- qcom,flash-src-index : should contain phandle to flash source node if flash
+ is supported for this sensor
+ - led_flash0, led_flash1
- qcom,mount-angle : should contain the physical mount angle of the sensor on
the target
- 0, 90, 180, 360
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
index 802716c..5bef9b8 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
@@ -14,6 +14,7 @@
"metadata_base" are expected.
- interrupts: The modem watchdog interrupt
- vdd_mss-supply: Reference to the regulator that supplies the processor.
+- vdd_mx-supply: Reference to the regulator that supplies the memory rail.
- qcom,firmware-name: Base name of the firmware image. Ex. "mdsp"
- qcom,pil-self-auth: <0> if the hardware does not require self-authenticating
images and self-authentication is not desired;
@@ -32,6 +33,7 @@
"restart_reg", metadata_base";
interrupts = <0 24 1>;
vdd_mss-supply = <&pm8841_s3>;
+ vdd_mx-supply = <&pm8841_s1>;
qcom,is-loadable;
qcom,firmware-name = "mba";
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 213da90..c47d442 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -72,6 +72,11 @@
- compatible : "msm-dai-q6"
+Optional properties:
+
+ - qcom,ext-spk-amp-supply : External speaker amplifier power supply.
+ - qcom,ext-spk-amp-gpio : External speaker amplifier enable signal.
+
[Second Level Nodes]
Required properties:
diff --git a/Documentation/mmc/mmc-dev-attrs.txt b/Documentation/mmc/mmc-dev-attrs.txt
index 7dde34f..86d38ca 100644
--- a/Documentation/mmc/mmc-dev-attrs.txt
+++ b/Documentation/mmc/mmc-dev-attrs.txt
@@ -51,6 +51,8 @@
serial Product Serial Number (from CID Register)
erase_size Erase group size
preferred_erase_size Preferred erase size
+ raw_rpmb_size_mult RPMB partition size
+ rel_sectors Reliable write sector count
Note on Erase Size and Preferred Erase Size:
@@ -91,6 +93,11 @@
"preferred_erase_size" is in bytes.
+Note on raw_rpmb_size_mult:
+ "raw_rpmb_size_mult" is a mutliple of 128kB block.
+ RPMB size in byte is calculated by using the following equation:
+ RPMB partition size = 128kB x raw_rpmb_size_mult
+
SD/MMC/SDIO Clock Gating Attribute
==================================
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 81b5dc9..2f2603f 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -265,7 +265,12 @@
KBUILD_IMAGE := zImage
endif
-all: $(KBUILD_IMAGE)
+# Build the DT binary blobs if we have OF configured
+ifeq ($(CONFIG_USE_OF),y)
+KBUILD_DTBS := dtbs
+endif
+
+all: $(KBUILD_IMAGE) $(KBUILD_DTBS)
boot := arch/arm/boot
@@ -281,10 +286,10 @@
zinstall uinstall install: vmlinux
$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $@
-%.dtb:
+%.dtb: scripts
$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
-dtbs:
+dtbs: scripts
$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
# We use MRPROPER_FILES and CLEAN_FILES now
@@ -303,7 +308,7 @@
echo ' uImage - U-Boot wrapped zImage'
echo ' bootpImage - Combined zImage and initial RAM disk'
echo ' (supply initrd image via make variable INITRD=<path>)'
- echo ' dtbs - Build device tree blobs for enabled boards'
+ echo '* dtbs - Build device tree blobs for enabled boards'
echo ' install - Install uncompressed kernel'
echo ' zinstall - Install compressed kernel'
echo ' uinstall - Install U-Boot wrapped compressed kernel'
diff --git a/arch/arm/boot/dts/mpq8092.dtsi b/arch/arm/boot/dts/mpq8092.dtsi
index 502d34a..0decddc 100644
--- a/arch/arm/boot/dts/mpq8092.dtsi
+++ b/arch/arm/boot/dts/mpq8092.dtsi
@@ -38,7 +38,7 @@
};
timer {
- compatible = "qcom,msm-qtimer", "arm,armv7-timer";
+ compatible = "arm,armv7-timer";
interrupts = <1 2 0>, <1 3 0>;
clock-frequency = <19200000>;
};
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index b900c3f..927ebcd 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -36,7 +36,7 @@
};
timer {
- compatible = "qcom,msm-qtimer", "arm,armv7-timer";
+ compatible = "arm,armv7-timer";
interrupts = <1 2 0 1 3 0>;
clock-frequency = <19200000>;
};
@@ -83,6 +83,74 @@
qcom,ipi-ping = <1>;
};
+ qcom,smem@fa00000 {
+ compatible = "qcom,smem";
+ reg = <0xfa00000 0x200000>,
+ <0xfa006000 0x1000>,
+ <0xfc428000 0x4000>;
+ reg-names = "smem", "irq-reg-base", "aux-mem1";
+
+ qcom,smd-modem {
+ compatible = "qcom,smd";
+ qcom,smd-edge = <0>;
+ qcom,smd-irq-offset = <0x8>;
+ qcom,smd-irq-bitmask = <0x1000>;
+ qcom,pil-string = "modem";
+ interrupts = <0 25 1>;
+ };
+
+ qcom,smsm-modem {
+ compatible = "qcom,smsm";
+ qcom,smsm-edge = <0>;
+ qcom,smsm-irq-offset = <0x8>;
+ qcom,smsm-irq-bitmask = <0x2000>;
+ interrupts = <0 26 1>;
+ };
+
+ qcom,smd-adsp {
+ compatible = "qcom,smd";
+ qcom,smd-edge = <1>;
+ qcom,smd-irq-offset = <0x8>;
+ qcom,smd-irq-bitmask = <0x100>;
+ qcom,pil-string = "adsp";
+ interrupts = <0 156 1>;
+ };
+
+ qcom,smsm-adsp {
+ compatible = "qcom,smsm";
+ qcom,smsm-edge = <1>;
+ qcom,smsm-irq-offset = <0x8>;
+ qcom,smsm-irq-bitmask = <0x200>;
+ interrupts = <0 157 1>;
+ };
+
+ qcom,smd-wcnss {
+ compatible = "qcom,smd";
+ qcom,smd-edge = <6>;
+ qcom,smd-irq-offset = <0x8>;
+ qcom,smd-irq-bitmask = <0x20000>;
+ qcom,pil-string = "wcnss";
+ interrupts = <0 142 1>;
+ };
+
+ qcom,smsm-wcnss {
+ compatible = "qcom,smsm";
+ qcom,smsm-edge = <6>;
+ qcom,smsm-irq-offset = <0x8>;
+ qcom,smsm-irq-bitmask = <0x80000>;
+ interrupts = <0 144 1>;
+ };
+
+ qcom,smd-rpm {
+ compatible = "qcom,smd";
+ qcom,smd-edge = <15>;
+ qcom,smd-irq-offset = <0x8>;
+ qcom,smd-irq-bitmask = <0x1>;
+ interrupts = <0 168 1>;
+ qcom,irq-no-suspend;
+ };
+ };
+
};
&gdsc_venus {
diff --git a/arch/arm/boot/dts/msm8910.dtsi b/arch/arm/boot/dts/msm8910.dtsi
index 9514e5a..3786b02 100644
--- a/arch/arm/boot/dts/msm8910.dtsi
+++ b/arch/arm/boot/dts/msm8910.dtsi
@@ -12,6 +12,7 @@
/include/ "skeleton.dtsi"
/include/ "msm8910-ion.dtsi"
+/include/ "msm-gdsc.dtsi"
/ {
model = "Qualcomm MSM 8910";
@@ -35,7 +36,7 @@
};
timer {
- compatible = "qcom,msm-qtimer", "arm,armv7-timer";
+ compatible = "arm,armv7-timer";
interrupts = <1 2 0 1 3 0>;
clock-frequency = <19200000>;
};
@@ -127,6 +128,11 @@
qcom,current-limit = <800>;
};
+ qcom,sps {
+ compatible = "qcom,msm_sps";
+ qcom,device-type = <3>;
+ };
+
qcom,smem@fa00000 {
compatible = "qcom,smem";
reg = <0xfa00000 0x200000>,
@@ -194,6 +200,23 @@
qcom,irq-no-suspend;
};
};
+
+ qcom,wdt@f9017000 {
+ compatible = "qcom,msm-watchdog";
+ reg = <0xf9017000 0x1000>;
+ interrupts = <0 3 0>, <0 4 0>;
+ qcom,bark-time = <11000>;
+ qcom,pet-time = <10000>;
+ qcom,ipi-ping = <1>;
+ };
+};
+
+&gdsc_vfe {
+ status = "ok";
+};
+
+&gdsc_oxili_cx {
+ status = "ok";
};
/include/ "msm8910-regulator.dtsi"
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
index 25f79f8..c9b999f 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
@@ -19,7 +19,7 @@
reg = <0x6e 0x0>;
qcom,csi-if = <1>;
qcom,csid-core = <0>;
- qcom,flash-type = <0>;
+ qcom,flash-src-index = <&led_flash0>;
qcom,mount-angle = <0>;
qcom,sensor-name = "s5k3l1yx";
cam_vdig-supply = <&pm8941_l3>;
@@ -61,7 +61,6 @@
reg = <0x6c 0x0>;
qcom,csi-if = <1>;
qcom,csid-core = <0>;
- qcom,flash-type = <0>;
qcom,mount-angle = <180>;
qcom,sensor-name = "ov2720";
cam_vdig-supply = <&pm8941_l3>;
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor.dtsi
index d804355..68da844 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor.dtsi
@@ -18,7 +18,7 @@
reg = <0x6e 0x0>;
qcom,csi-if = <1>;
qcom,csid-core = <0>;
- qcom,flash-type = <0>;
+ qcom,flash-src-index = <&led_flash0>;
qcom,mount-angle = <90>;
qcom,sensor-name = "s5k3l1yx";
cam_vdig-supply = <&pm8941_l3>;
@@ -60,7 +60,6 @@
reg = <0x6c 0x0>;
qcom,csi-if = <1>;
qcom,csid-core = <0>;
- qcom,flash-type = <0>;
qcom,mount-angle = <180>;
qcom,sensor-name = "ov2720";
cam_vdig-supply = <&pm8941_l3>;
diff --git a/arch/arm/boot/dts/msm8974-camera.dtsi b/arch/arm/boot/dts/msm8974-camera.dtsi
index 4b96811..48dd4dc 100644
--- a/arch/arm/boot/dts/msm8974-camera.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera.dtsi
@@ -165,6 +165,13 @@
vdd-supply = <&gdsc_vfe>;
};
+ led_flash0: qcom,camera-led-flash {
+ cell-index = <0>;
+ compatible = "qcom,camera-led-flash";
+ qcom,flash-type = <1>;
+ qcom,flash-source = <&pm8941_flash0 &pm8941_flash1>;
+ };
+
cci: qcom,cci@fda0C000 {
cell-index = <0>;
compatible = "qcom,cci";
@@ -189,7 +196,6 @@
reg = <0x90 0x0>;
qcom,csi-if = <1>;
qcom,csid-core = <0>;
- qcom,flash-type = <0>;
qcom,mount-angle = <0>;
qcom,sensor-name = "mt9m114";
cam_vdig-supply = <&pm8941_l3>;
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index 7557fd1..bd02d89 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -11,8 +11,8 @@
*/
/include/ "dsi-panel-toshiba-720p-video.dtsi"
-/include/ "msm8974-camera-sensor.dtsi"
/include/ "msm8974-leds.dtsi"
+/include/ "msm8974-camera-sensor.dtsi"
/ {
serial@f991e000 {
@@ -42,7 +42,6 @@
atmel,panel-coords = <0 0 760 1424>;
atmel,display-coords = <0 0 720 1280>;
atmel,i2c-pull-up;
- atmel,no-force-update;
atmel,cfg_1 {
atmel,family-id = <0x82>;
atmel,variant-id = <0x19>;
@@ -156,40 +155,7 @@
};
sound {
- compatible = "qcom,msm8974-audio-taiko";
qcom,model = "msm8974-taiko-cdp-snd-card";
-
- qcom,audio-routing =
- "RX_BIAS", "MCLK",
- "LDO_H", "MCLK",
- "Ext Spk Bottom Pos", "LINEOUT1",
- "Ext Spk Bottom Neg", "LINEOUT3",
- "Ext Spk Top Pos", "LINEOUT2",
- "Ext Spk Top Neg", "LINEOUT4",
- "AMIC1", "MIC BIAS1 Internal1",
- "MIC BIAS1 Internal1", "Handset Mic",
- "AMIC2", "MIC BIAS2 External",
- "MIC BIAS2 External", "Headset Mic",
- "AMIC3", "MIC BIAS2 External",
- "MIC BIAS2 External", "ANCRight Headset Mic",
- "AMIC4", "MIC BIAS2 External",
- "MIC BIAS2 External", "ANCLeft Headset Mic",
- "DMIC1", "MIC BIAS1 External",
- "MIC BIAS1 External", "Digital Mic1",
- "DMIC2", "MIC BIAS1 External",
- "MIC BIAS1 External", "Digital Mic2",
- "DMIC3", "MIC BIAS3 External",
- "MIC BIAS3 External", "Digital Mic3",
- "DMIC4", "MIC BIAS3 External",
- "MIC BIAS3 External", "Digital Mic4",
- "DMIC5", "MIC BIAS4 External",
- "MIC BIAS4 External", "Digital Mic5",
- "DMIC6", "MIC BIAS4 External",
- "MIC BIAS4 External", "Digital Mic6";
-
- qcom,cdc-mclk-gpios = <&pm8941_gpios 15 0>;
- taiko-mclk-clk = <&pm8941_clkdiv1>;
- qcom,taiko-mclk-clk-freq = <9600000>;
};
};
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index cf45ceb..8479dfa 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -42,7 +42,6 @@
atmel,panel-coords = <0 0 760 1424>;
atmel,display-coords = <0 0 720 1280>;
atmel,i2c-pull-up;
- atmel,no-force-update;
atmel,cfg_1 {
atmel,family-id = <0x82>;
atmel,variant-id = <0x19>;
@@ -172,40 +171,7 @@
};
sound {
- compatible = "qcom,msm8974-audio-taiko";
qcom,model = "msm8974-taiko-fluid-snd-card";
-
- qcom,audio-routing =
- "RX_BIAS", "MCLK",
- "LDO_H", "MCLK",
- "Ext Spk Bottom Pos", "LINEOUT1",
- "Ext Spk Bottom Neg", "LINEOUT3",
- "Ext Spk Top Pos", "LINEOUT2",
- "Ext Spk Top Neg", "LINEOUT4",
- "AMIC1", "MIC BIAS1 Internal1",
- "MIC BIAS1 Internal1", "Handset Mic",
- "AMIC2", "MIC BIAS2 External",
- "MIC BIAS2 External", "Headset Mic",
- "AMIC3", "MIC BIAS2 External",
- "MIC BIAS2 External", "ANCRight Headset Mic",
- "AMIC4", "MIC BIAS2 External",
- "MIC BIAS2 External", "ANCLeft Headset Mic",
- "DMIC1", "MIC BIAS1 External",
- "MIC BIAS1 External", "Digital Mic1",
- "DMIC2", "MIC BIAS1 External",
- "MIC BIAS1 External", "Digital Mic2",
- "DMIC3", "MIC BIAS3 External",
- "MIC BIAS3 External", "Digital Mic3",
- "DMIC4", "MIC BIAS3 External",
- "MIC BIAS3 External", "Digital Mic4",
- "DMIC5", "MIC BIAS4 External",
- "MIC BIAS4 External", "Digital Mic5",
- "DMIC6", "MIC BIAS4 External",
- "MIC BIAS4 External", "Digital Mic6";
-
- qcom,cdc-mclk-gpios = <&pm8941_gpios 15 0>;
- taiko-mclk-clk = <&pm8941_clkdiv1>;
- qcom,taiko-mclk-clk-freq = <9600000>;
};
};
diff --git a/arch/arm/boot/dts/msm8974-leds.dtsi b/arch/arm/boot/dts/msm8974-leds.dtsi
index 89bb687..8ba3470 100644
--- a/arch/arm/boot/dts/msm8974-leds.dtsi
+++ b/arch/arm/boot/dts/msm8974-leds.dtsi
@@ -45,13 +45,13 @@
status = "disabled";
};
- qcom,leds@d2000 {
+ qcom,leds@d200 {
status = "disabled";
};
qcom,leds@d300 {
status = "okay";
- qcom,flash_0 {
+ pm8941_flash0: qcom,flash_0 {
qcom,max-current = <1000>;
qcom,default-state = "off";
qcom,headroom = <0>;
@@ -67,7 +67,7 @@
qcom,current = <625>;
};
- qcom,flash_1 {
+ pm8941_flash1: qcom,flash_1 {
qcom,max-current = <1000>;
qcom,default-state = "off";
qcom,headroom = <0>;
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index 0f65dc8..f412d177 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -10,8 +10,8 @@
* GNU General Public License for more details.
*/
-/include/ "msm8974-camera-sensor-liquid.dtsi"
/include/ "msm8974-leds.dtsi"
+/include/ "msm8974-camera-sensor-liquid.dtsi"
/ {
serial@f991e000 {
@@ -121,7 +121,6 @@
atmel,panel-coords = <0 0 1080 1920>;
atmel,display-coords = <0 0 1080 1920>;
atmel,i2c-pull-up;
- atmel,no-force-update;
atmel,cfg_1 {
atmel,family-id = <0xa2>;
atmel,variant-id = <0x00>;
@@ -214,6 +213,35 @@
sound {
qcom,model = "msm8974-taiko-liquid-snd-card";
+
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "LDO_H", "MCLK",
+ "Lineout_1 amp", "LINEOUT1",
+ "Lineout_3 amp", "LINEOUT3",
+ "Lineout_2 amp", "LINEOUT2",
+ "Lineout_4 amp", "LINEOUT4",
+ "AMIC1", "MIC BIAS1 Internal1",
+ "MIC BIAS1 Internal1", "Handset Mic",
+ "AMIC2", "MIC BIAS2 External",
+ "MIC BIAS2 External", "Headset Mic",
+ "AMIC3", "MIC BIAS2 External",
+ "MIC BIAS2 External", "ANCRight Headset Mic",
+ "AMIC4", "MIC BIAS2 External",
+ "MIC BIAS2 External", "ANCLeft Headset Mic",
+ "DMIC1", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Digital Mic1",
+ "DMIC2", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Digital Mic2",
+ "DMIC3", "MIC BIAS3 External",
+ "MIC BIAS3 External", "Digital Mic3",
+ "DMIC4", "MIC BIAS3 External",
+ "MIC BIAS3 External", "Digital Mic4",
+ "DMIC5", "MIC BIAS4 External",
+ "MIC BIAS4 External", "Digital Mic5",
+ "DMIC6", "MIC BIAS4 External",
+ "MIC BIAS4 External", "Digital Mic6";
+
qcom,ext-spk-amp-supply = <&ext_5v>;
qcom,ext-spk-amp-gpio = <&pm8841_mpps 1 0>;
};
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index 8563996..9fb7d0e 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -42,7 +42,6 @@
atmel,panel-coords = <0 0 760 1424>;
atmel,display-coords = <0 0 720 1280>;
atmel,i2c-pull-up;
- atmel,no-force-update;
atmel,cfg_1 {
atmel,family-id = <0x82>;
atmel,variant-id = <0x19>;
@@ -156,40 +155,7 @@
};
sound {
- compatible = "qcom,msm8974-audio-taiko";
qcom,model = "msm8974-taiko-mtp-snd-card";
-
- qcom,audio-routing =
- "RX_BIAS", "MCLK",
- "LDO_H", "MCLK",
- "Ext Spk Bottom Pos", "LINEOUT1",
- "Ext Spk Bottom Neg", "LINEOUT3",
- "Ext Spk Top Pos", "LINEOUT2",
- "Ext Spk Top Neg", "LINEOUT4",
- "AMIC1", "MIC BIAS1 Internal1",
- "MIC BIAS1 Internal1", "Handset Mic",
- "AMIC2", "MIC BIAS2 External",
- "MIC BIAS2 External", "Headset Mic",
- "AMIC3", "MIC BIAS2 External",
- "MIC BIAS2 External", "ANCRight Headset Mic",
- "AMIC4", "MIC BIAS2 External",
- "MIC BIAS2 External", "ANCLeft Headset Mic",
- "DMIC1", "MIC BIAS1 External",
- "MIC BIAS1 External", "Digital Mic1",
- "DMIC2", "MIC BIAS1 External",
- "MIC BIAS1 External", "Digital Mic2",
- "DMIC3", "MIC BIAS3 External",
- "MIC BIAS3 External", "Digital Mic3",
- "DMIC4", "MIC BIAS3 External",
- "MIC BIAS3 External", "Digital Mic4",
- "DMIC5", "MIC BIAS4 External",
- "MIC BIAS4 External", "Digital Mic5",
- "DMIC6", "MIC BIAS4 External",
- "MIC BIAS4 External", "Digital Mic6";
-
- qcom,cdc-mclk-gpios = <&pm8941_gpios 15 0>;
- taiko-mclk-clk = <&pm8941_clkdiv1>;
- qcom,taiko-mclk-clk-freq = <9600000>;
};
};
diff --git a/arch/arm/boot/dts/msm8974-rumi.dtsi b/arch/arm/boot/dts/msm8974-rumi.dtsi
index 33656cd..4919391 100644
--- a/arch/arm/boot/dts/msm8974-rumi.dtsi
+++ b/arch/arm/boot/dts/msm8974-rumi.dtsi
@@ -10,6 +10,7 @@
* GNU General Public License for more details.
*/
+/include/ "msm8974-leds.dtsi"
/include/ "msm8974-camera-sensor.dtsi"
/ {
@@ -106,4 +107,36 @@
qcom,mss@fc880000 {
status = "disable";
};
+
+ qcom,kgsl-3d0@fdb00000 {
+ status = "disabled";
+ };
+};
+
+&gdsc_venus {
+ status = "disabled";
+};
+
+&gdsc_mdss {
+ status = "disabled";
+};
+
+&gdsc_jpeg {
+ status = "disabled";
+};
+
+&gdsc_vfe {
+ status = "disabled";
+};
+
+&gdsc_oxili_gx {
+ status = "disabled";
+};
+
+&gdsc_oxili_cx {
+ status = "disabled";
+};
+
+&gdsc_usb_hsic {
+ status = "disabled";
};
diff --git a/arch/arm/boot/dts/msm8974-sim.dtsi b/arch/arm/boot/dts/msm8974-sim.dtsi
index 8e8b3c3..fb638f7 100644
--- a/arch/arm/boot/dts/msm8974-sim.dtsi
+++ b/arch/arm/boot/dts/msm8974-sim.dtsi
@@ -11,6 +11,7 @@
*/
/include/ "dsi-panel-sim-video.dtsi"
+/include/ "msm8974-leds.dtsi"
/include/ "msm8974-camera-sensor.dtsi"
/ {
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 0fd5c97..eeb05d4 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -52,7 +52,7 @@
};
timer {
- compatible = "qcom,msm-qtimer", "arm,armv7-timer";
+ compatible = "arm,armv7-timer";
interrupts = <1 2 0 1 3 0>;
clock-frequency = <19200000>;
};
@@ -151,24 +151,25 @@
qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
- qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+ qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 200000000>;
qcom,sup-voltages = <2950 2950>;
qcom,bus-width = <8>;
qcom,nonremovable;
qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
qcom,msm-bus,name = "sdcc1";
- qcom,msm-bus,num-cases = <7>;
+ qcom,msm-bus,num-cases = <8>;
qcom,msm-bus,active-only = <0>;
qcom,msm-bus,num-paths = <1>;
qcom,msm-bus,vectors-KBps = <78 512 0 0>, /* No vote */
- <78 512 6656 13312>, /* 13 MB/s*/
- <78 512 13312 26624>, /* 26 MB/s */
- <78 512 26624 53248>, /* 52 MB/s */
- <78 512 53248 106496>, /* 104 MB/s */
- <78 512 106496 212992>, /* 208 MB/s */
- <78 512 2147483647 4294967295>; /* Max. bandwidth */
- qcom,bus-bw-vectors-bps = <0 13631488 27262976 54525952 109051904 218103808 4294967295>;
+ <78 512 1600 3200>, /* 400 KB/s*/
+ <78 512 80000 160000>, /* 20 MB/s */
+ <78 512 100000 200000>, /* 25 MB/s */
+ <78 512 200000 400000>, /* 50 MB/s */
+ <78 512 400000 800000>, /* 100 MB/s */
+ <78 512 800000 1600000>, /* 200 MB/s */
+ <78 512 2048000 4096000>; /* Max. bandwidth */
+ qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 100000000 200000000 4294967295>;
qcom,dat1-mpm-int = <42>;
};
@@ -197,7 +198,7 @@
qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
- qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+ qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 200000000>;
qcom,sup-voltages = <2950 2950>;
qcom,bus-width = <4>;
qcom,xpc;
@@ -205,17 +206,18 @@
qcom,current-limit = <800>;
qcom,msm-bus,name = "sdcc2";
- qcom,msm-bus,num-cases = <7>;
+ qcom,msm-bus,num-cases = <8>;
qcom,msm-bus,active-only = <0>;
qcom,msm-bus,num-paths = <1>;
qcom,msm-bus,vectors-KBps = <81 512 0 0>, /* No vote */
- <81 512 6656 13312>, /* 13 MB/s*/
- <81 512 13312 26624>, /* 26 MB/s */
- <81 512 26624 53248>, /* 52 MB/s */
- <81 512 53248 106496>, /* 104 MB/s */
- <81 512 106496 212992>, /* 208 MB/s */
- <81 512 2147483647 4294967295>; /* Max. bandwidth */
- qcom,bus-bw-vectors-bps = <0 13631488 27262976 54525952 109051904 218103808 4294967295>;
+ <81 512 1600 3200>, /* 400 KB/s*/
+ <81 512 80000 160000>, /* 20 MB/s */
+ <81 512 100000 200000>, /* 25 MB/s */
+ <81 512 200000 400000>, /* 50 MB/s */
+ <81 512 400000 800000>, /* 100 MB/s */
+ <81 512 800000 1600000>, /* 200 MB/s */
+ <81 512 2048000 4096000>; /* Max. bandwidth */
+ qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 100000000 200000000 4294967295>;
qcom,dat1-mpm-int = <44>;
};
@@ -244,23 +246,24 @@
<&msmgpio 35 0>; /* DATA3 */
qcom,gpio-names = "CLK", "CMD", "DAT0", "DAT1", "DAT2", "DAT3";
- qcom,clk-rates = <400000 25000000 50000000 100000000>;
+ qcom,clk-rates = <400000 20000000 25000000 50000000 100000000>;
qcom,sup-voltages = <1800 1800>;
qcom,bus-width = <4>;
qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50";
qcom,msm-bus,name = "sdcc3";
- qcom,msm-bus,num-cases = <7>;
+ qcom,msm-bus,num-cases = <8>;
qcom,msm-bus,active-only = <0>;
qcom,msm-bus,num-paths = <1>;
qcom,msm-bus,vectors-KBps = <79 512 0 0>, /* No vote */
- <79 512 6656 13312>, /* 13 MB/s*/
- <79 512 13312 26624>, /* 26 MB/s */
- <79 512 26624 53248>, /* 52 MB/s */
- <79 512 53248 106496>, /* 104 MB/s */
- <79 512 106496 212992>, /* 208 MB/s */
- <79 512 2147483647 4294967295>; /* Max. bandwidth */
- qcom,bus-bw-vectors-bps = <0 13631488 27262976 54525952 109051904 218103808 4294967295>;
+ <79 512 1600 3200>, /* 400 KB/s*/
+ <79 512 80000 160000>, /* 20 MB/s */
+ <79 512 100000 200000>, /* 25 MB/s */
+ <79 512 200000 400000>, /* 50 MB/s */
+ <79 512 400000 800000>, /* 100 MB/s */
+ <79 512 800000 1600000>, /* 200 MB/s */
+ <79 512 2048000 4096000>; /* Max. bandwidth */
+ qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 100000000 200000000 4294967295>;
status = "disable";
};
@@ -289,23 +292,24 @@
<&msmgpio 92 0>; /* DATA3 */
qcom,gpio-names = "CLK", "CMD", "DAT0", "DAT1", "DAT2", "DAT3";
- qcom,clk-rates = <400000 25000000 50000000 100000000>;
+ qcom,clk-rates = <400000 20000000 25000000 50000000 100000000>;
qcom,sup-voltages = <1800 1800>;
qcom,bus-width = <4>;
qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50";
qcom,msm-bus,name = "sdcc4";
- qcom,msm-bus,num-cases = <7>;
+ qcom,msm-bus,num-cases = <8>;
qcom,msm-bus,active-only = <0>;
qcom,msm-bus,num-paths = <1>;
qcom,msm-bus,vectors-KBps = <80 512 0 0>, /* No vote */
- <80 512 6656 13312>, /* 13 MB/s*/
- <80 512 13312 26624>, /* 26 MB/s */
- <80 512 26624 53248>, /* 52 MB/s */
- <80 512 53248 106496>, /* 104 MB/s */
- <80 512 106496 212992>, /* 208 MB/s */
- <80 512 2147483647 4294967295>; /* Max. bandwidth */
- qcom,bus-bw-vectors-bps = <0 13631488 27262976 54525952 109051904 218103808 4294967295>;
+ <80 512 1600 3200>, /* 400 KB/s*/
+ <80 512 80000 160000>, /* 20 MB/s */
+ <80 512 100000 200000>, /* 25 MB/s */
+ <80 512 200000 400000>, /* 50 MB/s */
+ <80 512 400000 800000>, /* 100 MB/s */
+ <80 512 800000 1600000>, /* 200 MB/s */
+ <80 512 2048000 4096000>; /* Max. bandwidth */
+ qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 100000000 200000000 4294967295>;
status = "disable";
};
@@ -416,10 +420,6 @@
qcom,audio-routing =
"RX_BIAS", "MCLK",
"LDO_H", "MCLK",
- "Ext Spk Bottom Pos", "LINEOUT1",
- "Ext Spk Bottom Neg", "LINEOUT3",
- "Ext Spk Top Pos", "LINEOUT2",
- "Ext Spk Top Neg", "LINEOUT4",
"AMIC1", "MIC BIAS1 Internal1",
"MIC BIAS1 Internal1", "Handset Mic",
"AMIC2", "MIC BIAS2 External",
@@ -886,6 +886,7 @@
interrupts = <0 24 1>;
vdd_mss-supply = <&pm8841_s3>;
+ vdd_mx-supply = <&pm8841_s1>;
qcom,is-loadable;
qcom,firmware-name = "mba";
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index d1c731e..cbd93df 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -45,7 +45,7 @@
};
timer: msm-qtimer@f9021000 {
- compatible = "qcom,msm-qtimer", "arm,armv7-timer";
+ compatible = "arm,armv7-timer";
reg = <0xF9021000 0x1000>;
interrupts = <0 7 0>;
irq-is-not-percpu;
@@ -523,6 +523,57 @@
compatible = "qcom,pil-q6v5-mss";
interrupts = <0 24 1>;
};
+
+ qcom,smem@fa00000 {
+ compatible = "qcom,smem";
+ reg = <0xfa00000 0x200000>,
+ <0xfa006000 0x1000>,
+ <0xfc428000 0x4000>;
+ reg-names = "smem", "irq-reg-base", "aux-mem1";
+
+ qcom,smd-modem {
+ compatible = "qcom,smd";
+ qcom,smd-edge = <0>;
+ qcom,smd-irq-offset = <0x8>;
+ qcom,smd-irq-bitmask = <0x1000>;
+ qcom,pil-string = "modem";
+ interrupts = <0 25 1>;
+ };
+
+ qcom,smsm-modem {
+ compatible = "qcom,smsm";
+ qcom,smsm-edge = <0>;
+ qcom,smsm-irq-offset = <0x8>;
+ qcom,smsm-irq-bitmask = <0x2000>;
+ interrupts = <0 26 1>;
+ };
+
+ qcom,smd-adsp {
+ compatible = "qcom,smd";
+ qcom,smd-edge = <1>;
+ qcom,smd-irq-offset = <0x8>;
+ qcom,smd-irq-bitmask = <0x100>;
+ qcom,pil-string = "adsp";
+ interrupts = <0 156 1>;
+ };
+
+ qcom,smsm-adsp {
+ compatible = "qcom,smsm";
+ qcom,smsm-edge = <1>;
+ qcom,smsm-irq-offset = <0x8>;
+ qcom,smsm-irq-bitmask = <0x200>;
+ interrupts = <0 157 1>;
+ };
+
+ qcom,smd-rpm {
+ compatible = "qcom,smd";
+ qcom,smd-edge = <15>;
+ qcom,smd-irq-offset = <0x8>;
+ qcom,smd-irq-bitmask = <0x1>;
+ interrupts = <0 168 1>;
+ qcom,irq-no-suspend;
+ };
+ };
};
/include/ "msm-pm8019-rpm-regulator.dtsi"
diff --git a/arch/arm/configs/msm8910_defconfig b/arch/arm/configs/msm8910_defconfig
index 2dd4b30..de78559 100644
--- a/arch/arm/configs/msm8910_defconfig
+++ b/arch/arm/configs/msm8910_defconfig
@@ -99,6 +99,9 @@
CONFIG_SERIAL_MSM_HSL_CONSOLE=y
CONFIG_DIAG_CHAR=y
CONFIG_HW_RANDOM=y
+CONFIG_SPMI=y
+CONFIG_SPMI_MSM_PMIC_ARB=y
+CONFIG_MSM_QPNP_INT=y
CONFIG_DEBUG_GPIO=y
CONFIG_GPIO_SYSFS=y
# CONFIG_HWMON is not set
@@ -125,6 +128,8 @@
CONFIG_MMC_BLOCK_MINORS=32
CONFIG_MMC_TEST=m
CONFIG_MMC_MSM=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
CONFIG_STAGING=y
CONFIG_ANDROID=y
CONFIG_ANDROID_BINDER_IPC=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index e4b60ff..bf44665 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -47,6 +47,7 @@
CONFIG_MSM_BAM_DMUX=y
CONFIG_MSM_IPC_ROUTER=y
CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_IPC_ROUTER_SECURITY=y
CONFIG_MSM_QMI_INTERFACE=y
# CONFIG_MSM_HW3D is not set
CONFIG_MSM_SUBSYSTEM_RESTART=y
@@ -296,6 +297,8 @@
CONFIG_MSM_CAMERA_V4L2=y
CONFIG_MT9M114=y
CONFIG_OV2720=y
+CONFIG_MSM_CAMERA_FLASH=y
+CONFIG_MSM_CAMERA_LED_TRIGGER_FLASH=y
CONFIG_MSM_CAMERA_SENSOR=y
CONFIG_MSM_ACTUATOR=y
CONFIG_MSM_JPEG=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 0042406..f9dbc85 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -46,6 +46,7 @@
CONFIG_MSM_BAM_DMUX=y
CONFIG_MSM_IPC_ROUTER=y
CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_IPC_ROUTER_SECURITY=y
CONFIG_MSM_QMI_INTERFACE=y
# CONFIG_MSM_HW3D is not set
CONFIG_MSM_SUBSYSTEM_RESTART=y
@@ -298,6 +299,8 @@
CONFIG_MSM_CAMERA_V4L2=y
CONFIG_MT9M114=y
CONFIG_OV2720=y
+CONFIG_MSM_CAMERA_FLASH=y
+CONFIG_MSM_CAMERA_LED_TRIGGER_FLASH=y
CONFIG_MSM_CAMERA_SENSOR=y
CONFIG_MSM_ACTUATOR=y
CONFIG_MSM_JPEG=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index d47870e..80f16d4 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -111,7 +111,7 @@
# CONFIG_NET_VENDOR_SEEQ is not set
# CONFIG_NET_VENDOR_SMSC is not set
# CONFIG_NET_VENDOR_STMICRO is not set
-# CONFIG_WLAN is not set
+CONFIG_ATH6K_LEGACY_EXT=y
# CONFIG_INPUT_MOUSEDEV is not set
CONFIG_INPUT_EVDEV=y
# CONFIG_INPUT_KEYBOARD is not set
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 2464140..3a52ddc 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -439,12 +439,12 @@
if (plat && plat->request_pmu_irq)
armpmu->request_pmu_irq = plat->request_pmu_irq;
- else
+ else if (!armpmu->request_pmu_irq)
armpmu->request_pmu_irq = armpmu_generic_request_irq;
if (plat && plat->free_pmu_irq)
armpmu->free_pmu_irq = plat->free_pmu_irq;
- else
+ else if (!armpmu->request_pmu_irq)
armpmu->free_pmu_irq = armpmu_generic_free_irq;
irqs = min(pmu_device->num_resources, num_possible_cpus());
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index ac17480..e7a9237 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -252,11 +252,6 @@
tick_nohz_idle_enter();
rcu_idle_enter();
while (!need_resched()) {
-#ifdef CONFIG_HOTPLUG_CPU
- if (cpu_is_offline(smp_processor_id()))
- cpu_die();
-#endif
-
/*
* We need to disable interrupts here
* to ensure we don't miss a wakeup call.
@@ -285,6 +280,10 @@
tick_nohz_idle_exit();
idle_notifier_call_chain(IDLE_END);
schedule_preempt_disabled();
+#ifdef CONFIG_HOTPLUG_CPU
+ if (cpu_is_offline(smp_processor_id()))
+ cpu_die();
+#endif
}
}
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 42e250d..a567db0 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -142,6 +142,7 @@
select MSM_PM8X60 if PM
select MSM_RUN_QUEUE_STATS
select ARM_HAS_SG_CHAIN
+ select USE_DEV_CTRL_VOLUME
config ARCH_MSM8960
bool "MSM8960"
@@ -1538,6 +1539,16 @@
help
SMD Transport Layer for IPC Router
+config MSM_IPC_ROUTER_SECURITY
+ depends on MSM_IPC_ROUTER
+ bool "MSM IPC Router Security support"
+ help
+ This feature of IPC Router will enforce security rules
+ configured by a security script from the user-space. IPC Router
+ once configured with the security rules will ensure that the
+ sender of the message to a service belongs to the relevant
+ Linux group as configured by the security script.
+
config MSM_QMI_INTERFACE
depends on MSM_IPC_ROUTER
depends on QMI_ENCDEC
@@ -2689,4 +2700,9 @@
Enables MSM-specific user accessible timers via a shared
memory page containing the cycle counter.
+config USE_DEV_CTRL_VOLUME
+ bool "Use Device Control Volume"
+ help
+ Use Device Control Volume as opposed to ALSA volume control.
+
endif
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 2c7424e..7555e51 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -138,6 +138,7 @@
obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_device.o
obj-$(CONFIG_MSM_IPC_ROUTER) += ipc_router.o
obj-$(CONFIG_MSM_IPC_ROUTER)+= ipc_socket.o
+obj-$(CONFIG_MSM_IPC_ROUTER_SECURITY)+= msm_ipc_router_security.o
obj-$(CONFIG_MSM_QMI_INTERFACE) += msm_qmi_interface.o
obj-$(CONFIG_DEBUG_FS) += smd_rpc_sym.o
obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_servers.o
@@ -296,6 +297,7 @@
obj-$(CONFIG_ARCH_MSM8974) += gdsc.o
obj-$(CONFIG_ARCH_MSM9625) += gdsc.o
obj-$(CONFIG_ARCH_MSM8226) += gdsc.o
+obj-$(CONFIG_ARCH_MSM8910) += gdsc.o
obj-$(CONFIG_ARCH_MSM8974) += krait-regulator.o
obj-$(CONFIG_ARCH_MSM9625) += board-9625.o board-9625-gpiomux.o
obj-$(CONFIG_ARCH_MSM9625) += clock-local2.o clock-pll.o clock-9625.o clock-rpm.o clock-voter.o acpuclock-9625.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index cf1f401..e74d61a 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -47,15 +47,25 @@
# MSM8974
zreladdr-$(CONFIG_ARCH_MSM8974) := 0x00008000
+ dtb-$(CONFIG_ARCH_MSM8974) += msm8974-cdp.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += msm8974-fluid.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += msm8974-liquid.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += msm8974-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += msm8974-rumi.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += msm8974-sim.dtb
# MSM9615
zreladdr-$(CONFIG_ARCH_MSM9615) := 0x40808000
# MSM9625
zreladdr-$(CONFIG_ARCH_MSM9625) := 0x00208000
+ dtb-$(CONFIG_ARCH_MSM9625) += msm9625-cdp.dtb
+ dtb-$(CONFIG_ARCH_MSM9625) += msm9625-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM9625) += msm9625-rumi.dtb
# MSM8226
zreladdr-$(CONFIG_ARCH_MSM8226) := 0x00008000
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8226-sim.dtb
# FSM9XXX
zreladdr-$(CONFIG_ARCH_FSM9XXX) := 0x10008000
@@ -67,3 +77,5 @@
# MSM8910
zreladdr-$(CONFIG_ARCH_MSM8910) := 0x00008000
+ dtb-$(CONFIG_ARCH_MSM8910) += msm8910-rumi.dtb
+ dtb-$(CONFIG_ARCH_MSM8910) += msm8910-sim.dtb
diff --git a/arch/arm/mach-msm/acpuclock-7627.c b/arch/arm/mach-msm/acpuclock-7627.c
index dd27123..00b6458 100644
--- a/arch/arm/mach-msm/acpuclock-7627.c
+++ b/arch/arm/mach-msm/acpuclock-7627.c
@@ -857,8 +857,7 @@
goto out;
/* Change the AXI bus frequency if we can. */
- if (reason != SETRATE_PC &&
- strt_s->axiclk_khz != tgt_s->axiclk_khz) {
+ if (strt_s->axiclk_khz != tgt_s->axiclk_khz) {
res = clk_set_rate(drv_state.ebi1_clk,
tgt_s->axiclk_khz * 1000);
if (res < 0)
diff --git a/arch/arm/mach-msm/acpuclock-8064.c b/arch/arm/mach-msm/acpuclock-8064.c
index 5c1d3e1..8174370 100644
--- a/arch/arm/mach-msm/acpuclock-8064.c
+++ b/arch/arm/mach-msm/acpuclock-8064.c
@@ -241,20 +241,127 @@
static struct acpu_level tbl_PVS0_1700MHz[] __initdata = {
{ 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 950000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(6), 975000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(6), 1000000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(6), 1025000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(6), 1075000 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(6), 1100000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(6), 1125000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1175000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1200000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1225000 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1237500 },
- { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1250000 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1250000 },
- { 1, { 1620000, HFPLL, 1, 0x3C }, L2(15), 1250000 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1250000 },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(6), 950000 },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(6), 950000 },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(6), 962500 },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(6), 1000000 },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(6), 1025000 },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(6), 1037500 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1075000 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1087500 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1125000 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1150000 },
+ { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1175000 },
+ { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1225000 },
+ { 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1250000 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level tbl_PVS1_1700MHz[] __initdata = {
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 950000 },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(6), 950000 },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(6), 950000 },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(6), 962500 },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(6), 975000 },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(6), 1000000 },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(6), 1012500 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1037500 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1050000 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1087500 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1112500 },
+ { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1150000 },
+ { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1187500 },
+ { 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1200000 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level tbl_PVS2_1700MHz[] __initdata = {
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 925000 },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(6), 925000 },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(6), 925000 },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(6), 925000 },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(6), 937500 },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(6), 950000 },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(6), 975000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1000000 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1012500 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1037500 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1075000 },
+ { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1100000 },
+ { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1137500 },
+ { 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1162500 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level tbl_PVS3_1700MHz[] __initdata = {
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 900000 },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(6), 900000 },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(6), 900000 },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(6), 900000 },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(6), 900000 },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(6), 925000 },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(6), 950000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 975000 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 987500 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1000000 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1037500 },
+ { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1062500 },
+ { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1100000 },
+ { 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1125000 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level tbl_PVS4_1700MHz[] __initdata = {
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 875000 },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(6), 875000 },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(6), 875000 },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(6), 875000 },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(6), 887500 },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(6), 900000 },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(6), 925000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 950000 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 962500 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 975000 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1000000 },
+ { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1037500 },
+ { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1075000 },
+ { 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1100000 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level tbl_PVS5_1700MHz[] __initdata = {
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 875000 },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(6), 875000 },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(6), 875000 },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(6), 875000 },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(6), 887500 },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(6), 900000 },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(6), 925000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 937500 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 950000 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 962500 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 987500 },
+ { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1012500 },
+ { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1050000 },
+ { 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1075000 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level tbl_PVS6_1700MHz[] __initdata = {
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 875000 },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(6), 875000 },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(6), 875000 },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(6), 875000 },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(6), 887500 },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(6), 900000 },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(6), 925000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 937500 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 950000 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 962500 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 975000 },
+ { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1000000 },
+ { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1025000 },
+ { 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1050000 },
{ 0, { 0 } }
};
@@ -398,12 +505,12 @@
[0][PVS_FASTER] = {tbl_faster, sizeof(tbl_faster), 25000 },
[1][0] = { tbl_PVS0_1700MHz, sizeof(tbl_PVS0_1700MHz), 0 },
- [1][1] = { tbl_PVS0_1700MHz, sizeof(tbl_PVS0_1700MHz), 0 },
- [1][2] = { tbl_PVS0_1700MHz, sizeof(tbl_PVS0_1700MHz), 0 },
- [1][3] = { tbl_PVS0_1700MHz, sizeof(tbl_PVS0_1700MHz), 0 },
- [1][4] = { tbl_PVS0_1700MHz, sizeof(tbl_PVS0_1700MHz), 0 },
- [1][5] = { tbl_PVS0_1700MHz, sizeof(tbl_PVS0_1700MHz), 0 },
- [1][6] = { tbl_PVS0_1700MHz, sizeof(tbl_PVS0_1700MHz), 0 },
+ [1][1] = { tbl_PVS1_1700MHz, sizeof(tbl_PVS1_1700MHz), 0 },
+ [1][2] = { tbl_PVS2_1700MHz, sizeof(tbl_PVS2_1700MHz), 0 },
+ [1][3] = { tbl_PVS3_1700MHz, sizeof(tbl_PVS3_1700MHz), 0 },
+ [1][4] = { tbl_PVS4_1700MHz, sizeof(tbl_PVS4_1700MHz), 0 },
+ [1][5] = { tbl_PVS5_1700MHz, sizeof(tbl_PVS5_1700MHz), 0 },
+ [1][6] = { tbl_PVS6_1700MHz, sizeof(tbl_PVS6_1700MHz), 0 },
[2][0] = { tbl_PVS0_2000MHz, sizeof(tbl_PVS0_2000MHz), 0 },
[2][1] = { tbl_PVS1_2000MHz, sizeof(tbl_PVS1_2000MHz), 0 },
diff --git a/arch/arm/mach-msm/acpuclock-8930.c b/arch/arm/mach-msm/acpuclock-8930.c
index e46599a..948ecdd 100644
--- a/arch/arm/mach-msm/acpuclock-8930.c
+++ b/arch/arm/mach-msm/acpuclock-8930.c
@@ -155,19 +155,19 @@
static struct acpu_level acpu_freq_tbl_slow[] __initdata = {
{ 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 950000 },
- { 1, { 432000, HFPLL, 2, 0x20 }, L2(5), 975000 },
+ { 0, { 432000, HFPLL, 2, 0x20 }, L2(5), 975000 },
{ 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 975000 },
- { 1, { 540000, HFPLL, 2, 0x28 }, L2(5), 1000000 },
+ { 0, { 540000, HFPLL, 2, 0x28 }, L2(5), 1000000 },
{ 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 1000000 },
- { 1, { 648000, HFPLL, 1, 0x18 }, L2(5), 1025000 },
+ { 0, { 648000, HFPLL, 1, 0x18 }, L2(5), 1025000 },
{ 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 1025000 },
- { 1, { 756000, HFPLL, 1, 0x1C }, L2(10), 1075000 },
+ { 0, { 756000, HFPLL, 1, 0x1C }, L2(10), 1075000 },
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(10), 1075000 },
- { 1, { 864000, HFPLL, 1, 0x20 }, L2(10), 1100000 },
+ { 0, { 864000, HFPLL, 1, 0x20 }, L2(10), 1100000 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(10), 1100000 },
- { 1, { 972000, HFPLL, 1, 0x24 }, L2(10), 1125000 },
+ { 0, { 972000, HFPLL, 1, 0x24 }, L2(10), 1125000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(10), 1125000 },
- { 1, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
+ { 0, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
{ 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1175000 },
{ 1, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
{ 0, { 0 } }
@@ -175,19 +175,19 @@
static struct acpu_level acpu_freq_tbl_nom[] __initdata = {
{ 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 925000 },
- { 1, { 432000, HFPLL, 2, 0x20 }, L2(5), 950000 },
+ { 0, { 432000, HFPLL, 2, 0x20 }, L2(5), 950000 },
{ 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 950000 },
- { 1, { 540000, HFPLL, 2, 0x28 }, L2(5), 975000 },
+ { 0, { 540000, HFPLL, 2, 0x28 }, L2(5), 975000 },
{ 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 975000 },
- { 1, { 648000, HFPLL, 1, 0x18 }, L2(5), 1000000 },
+ { 0, { 648000, HFPLL, 1, 0x18 }, L2(5), 1000000 },
{ 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 1000000 },
- { 1, { 756000, HFPLL, 1, 0x1C }, L2(10), 1050000 },
+ { 0, { 756000, HFPLL, 1, 0x1C }, L2(10), 1050000 },
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(10), 1050000 },
- { 1, { 864000, HFPLL, 1, 0x20 }, L2(10), 1075000 },
+ { 0, { 864000, HFPLL, 1, 0x20 }, L2(10), 1075000 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(10), 1075000 },
- { 1, { 972000, HFPLL, 1, 0x24 }, L2(10), 1100000 },
+ { 0, { 972000, HFPLL, 1, 0x24 }, L2(10), 1100000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(10), 1100000 },
- { 1, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1150000 },
+ { 0, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1150000 },
{ 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1150000 },
{ 1, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1175000 },
{ 0, { 0 } }
@@ -195,19 +195,19 @@
static struct acpu_level acpu_freq_tbl_fast[] __initdata = {
{ 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 900000 },
- { 1, { 432000, HFPLL, 2, 0x20 }, L2(5), 900000 },
+ { 0, { 432000, HFPLL, 2, 0x20 }, L2(5), 900000 },
{ 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 900000 },
- { 1, { 540000, HFPLL, 2, 0x28 }, L2(5), 925000 },
+ { 0, { 540000, HFPLL, 2, 0x28 }, L2(5), 925000 },
{ 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 925000 },
- { 1, { 648000, HFPLL, 1, 0x18 }, L2(5), 950000 },
+ { 0, { 648000, HFPLL, 1, 0x18 }, L2(5), 950000 },
{ 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 950000 },
- { 1, { 756000, HFPLL, 1, 0x1C }, L2(10), 1000000 },
+ { 0, { 756000, HFPLL, 1, 0x1C }, L2(10), 1000000 },
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(10), 1000000 },
- { 1, { 864000, HFPLL, 1, 0x20 }, L2(10), 1025000 },
+ { 0, { 864000, HFPLL, 1, 0x20 }, L2(10), 1025000 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(10), 1025000 },
- { 1, { 972000, HFPLL, 1, 0x24 }, L2(10), 1050000 },
+ { 0, { 972000, HFPLL, 1, 0x24 }, L2(10), 1050000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(10), 1050000 },
- { 1, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1100000 },
+ { 0, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1100000 },
{ 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1100000 },
{ 1, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1125000 },
{ 0, { 0 } }
diff --git a/arch/arm/mach-msm/acpuclock-8930aa.c b/arch/arm/mach-msm/acpuclock-8930aa.c
index 9d2b6fc..8d48b54 100644
--- a/arch/arm/mach-msm/acpuclock-8930aa.c
+++ b/arch/arm/mach-msm/acpuclock-8930aa.c
@@ -119,23 +119,23 @@
static struct acpu_level acpu_freq_tbl_slow[] __initdata = {
{ 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 950000 },
- { 1, { 432000, HFPLL, 2, 0x20 }, L2(5), 975000 },
+ { 0, { 432000, HFPLL, 2, 0x20 }, L2(5), 975000 },
{ 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 975000 },
- { 1, { 540000, HFPLL, 2, 0x28 }, L2(5), 1000000 },
+ { 0, { 540000, HFPLL, 2, 0x28 }, L2(5), 1000000 },
{ 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 1000000 },
- { 1, { 648000, HFPLL, 1, 0x18 }, L2(5), 1025000 },
+ { 0, { 648000, HFPLL, 1, 0x18 }, L2(5), 1025000 },
{ 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 1025000 },
- { 1, { 756000, HFPLL, 1, 0x1C }, L2(10), 1075000 },
+ { 0, { 756000, HFPLL, 1, 0x1C }, L2(10), 1075000 },
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(10), 1075000 },
- { 1, { 864000, HFPLL, 1, 0x20 }, L2(10), 1100000 },
+ { 0, { 864000, HFPLL, 1, 0x20 }, L2(10), 1100000 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(10), 1100000 },
- { 1, { 972000, HFPLL, 1, 0x24 }, L2(10), 1125000 },
+ { 0, { 972000, HFPLL, 1, 0x24 }, L2(10), 1125000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(10), 1125000 },
- { 1, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
+ { 0, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
{ 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1175000 },
- { 1, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
+ { 0, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
{ 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1200000 },
- { 1, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1225000 },
+ { 0, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1225000 },
{ 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1225000 },
{ 1, { 1404000, HFPLL, 1, 0x34 }, L2(15), 1237500 },
{ 0, { 0 } }
@@ -143,23 +143,23 @@
static struct acpu_level acpu_freq_tbl_nom[] __initdata = {
{ 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 925000 },
- { 1, { 432000, HFPLL, 2, 0x20 }, L2(5), 950000 },
+ { 0, { 432000, HFPLL, 2, 0x20 }, L2(5), 950000 },
{ 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 950000 },
- { 1, { 540000, HFPLL, 2, 0x28 }, L2(5), 975000 },
+ { 0, { 540000, HFPLL, 2, 0x28 }, L2(5), 975000 },
{ 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 975000 },
- { 1, { 648000, HFPLL, 1, 0x18 }, L2(5), 1000000 },
+ { 0, { 648000, HFPLL, 1, 0x18 }, L2(5), 1000000 },
{ 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 1000000 },
- { 1, { 756000, HFPLL, 1, 0x1C }, L2(10), 1050000 },
+ { 0, { 756000, HFPLL, 1, 0x1C }, L2(10), 1050000 },
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(10), 1050000 },
- { 1, { 864000, HFPLL, 1, 0x20 }, L2(10), 1075000 },
+ { 0, { 864000, HFPLL, 1, 0x20 }, L2(10), 1075000 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(10), 1075000 },
- { 1, { 972000, HFPLL, 1, 0x24 }, L2(10), 1100000 },
+ { 0, { 972000, HFPLL, 1, 0x24 }, L2(10), 1100000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(10), 1100000 },
- { 1, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1150000 },
+ { 0, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1150000 },
{ 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1150000 },
- { 1, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1175000 },
+ { 0, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1175000 },
{ 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1175000 },
- { 1, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1200000 },
+ { 0, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1200000 },
{ 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1200000 },
{ 1, { 1404000, HFPLL, 1, 0x34 }, L2(15), 1212500 },
{ 0, { 0 } }
@@ -167,23 +167,23 @@
static struct acpu_level acpu_freq_tbl_fast[] __initdata = {
{ 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 900000 },
- { 1, { 432000, HFPLL, 2, 0x20 }, L2(5), 900000 },
+ { 0, { 432000, HFPLL, 2, 0x20 }, L2(5), 900000 },
{ 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 900000 },
- { 1, { 540000, HFPLL, 2, 0x28 }, L2(5), 925000 },
+ { 0, { 540000, HFPLL, 2, 0x28 }, L2(5), 925000 },
{ 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 925000 },
- { 1, { 648000, HFPLL, 1, 0x18 }, L2(5), 950000 },
+ { 0, { 648000, HFPLL, 1, 0x18 }, L2(5), 950000 },
{ 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 950000 },
- { 1, { 756000, HFPLL, 1, 0x1C }, L2(10), 1000000 },
+ { 0, { 756000, HFPLL, 1, 0x1C }, L2(10), 1000000 },
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(10), 1000000 },
- { 1, { 864000, HFPLL, 1, 0x20 }, L2(10), 1025000 },
+ { 0, { 864000, HFPLL, 1, 0x20 }, L2(10), 1025000 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(10), 1025000 },
- { 1, { 972000, HFPLL, 1, 0x24 }, L2(10), 1050000 },
+ { 0, { 972000, HFPLL, 1, 0x24 }, L2(10), 1050000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(10), 1050000 },
- { 1, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1100000 },
+ { 0, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1100000 },
{ 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1100000 },
- { 1, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1125000 },
+ { 0, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1125000 },
{ 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1125000 },
- { 1, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1150000 },
+ { 0, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1150000 },
{ 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1150000 },
{ 1, { 1404000, HFPLL, 1, 0x34 }, L2(15), 1162500 },
{ 0, { 0 } }
diff --git a/arch/arm/mach-msm/acpuclock-8930ab.c b/arch/arm/mach-msm/acpuclock-8930ab.c
index 764ae41..96029b4 100644
--- a/arch/arm/mach-msm/acpuclock-8930ab.c
+++ b/arch/arm/mach-msm/acpuclock-8930ab.c
@@ -153,29 +153,29 @@
static struct acpu_level acpu_freq_tbl_slow[] __initdata = {
{ 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 950000 },
- { 1, { 432000, HFPLL, 2, 0x20 }, L2(5), 975000 },
+ { 0, { 432000, HFPLL, 2, 0x20 }, L2(5), 975000 },
{ 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 975000 },
- { 1, { 540000, HFPLL, 2, 0x28 }, L2(5), 1000000 },
+ { 0, { 540000, HFPLL, 2, 0x28 }, L2(5), 1000000 },
{ 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 1000000 },
- { 1, { 648000, HFPLL, 1, 0x18 }, L2(5), 1025000 },
+ { 0, { 648000, HFPLL, 1, 0x18 }, L2(5), 1025000 },
{ 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 1025000 },
- { 1, { 756000, HFPLL, 1, 0x1C }, L2(10), 1075000 },
+ { 0, { 756000, HFPLL, 1, 0x1C }, L2(10), 1075000 },
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(10), 1075000 },
- { 1, { 864000, HFPLL, 1, 0x20 }, L2(10), 1100000 },
+ { 0, { 864000, HFPLL, 1, 0x20 }, L2(10), 1100000 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(10), 1100000 },
- { 1, { 972000, HFPLL, 1, 0x24 }, L2(10), 1125000 },
+ { 0, { 972000, HFPLL, 1, 0x24 }, L2(10), 1125000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(10), 1125000 },
- { 1, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
+ { 0, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
{ 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1175000 },
- { 1, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
+ { 0, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
{ 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1200000 },
- { 1, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1225000 },
+ { 0, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1225000 },
{ 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1225000 },
- { 1, { 1404000, HFPLL, 1, 0x34 }, L2(15), 1237500 },
+ { 0, { 1404000, HFPLL, 1, 0x34 }, L2(15), 1237500 },
{ 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1237500 },
- { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1250000 },
+ { 0, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1250000 },
{ 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1250000 },
- { 1, { 1620000, HFPLL, 1, 0x3C }, L2(15), 1262500 },
+ { 0, { 1620000, HFPLL, 1, 0x3C }, L2(15), 1262500 },
{ 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1262500 },
{ 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1287500 },
{ 0, { 0 } }
@@ -183,29 +183,29 @@
static struct acpu_level acpu_freq_tbl_nom[] __initdata = {
{ 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 950000 },
- { 1, { 432000, HFPLL, 2, 0x20 }, L2(5), 975000 },
+ { 0, { 432000, HFPLL, 2, 0x20 }, L2(5), 975000 },
{ 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 975000 },
- { 1, { 540000, HFPLL, 2, 0x28 }, L2(5), 1000000 },
+ { 0, { 540000, HFPLL, 2, 0x28 }, L2(5), 1000000 },
{ 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 1000000 },
- { 1, { 648000, HFPLL, 1, 0x18 }, L2(5), 1025000 },
+ { 0, { 648000, HFPLL, 1, 0x18 }, L2(5), 1025000 },
{ 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 1025000 },
- { 1, { 756000, HFPLL, 1, 0x1C }, L2(10), 1075000 },
+ { 0, { 756000, HFPLL, 1, 0x1C }, L2(10), 1075000 },
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(10), 1075000 },
- { 1, { 864000, HFPLL, 1, 0x20 }, L2(10), 1100000 },
+ { 0, { 864000, HFPLL, 1, 0x20 }, L2(10), 1100000 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(10), 1100000 },
- { 1, { 972000, HFPLL, 1, 0x24 }, L2(10), 1125000 },
+ { 0, { 972000, HFPLL, 1, 0x24 }, L2(10), 1125000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(10), 1125000 },
- { 1, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
+ { 0, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
{ 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1175000 },
- { 1, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
+ { 0, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
{ 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1200000 },
- { 1, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1225000 },
+ { 0, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1225000 },
{ 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1225000 },
- { 1, { 1404000, HFPLL, 1, 0x34 }, L2(15), 1237500 },
+ { 0, { 1404000, HFPLL, 1, 0x34 }, L2(15), 1237500 },
{ 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1237500 },
- { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1250000 },
+ { 0, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1250000 },
{ 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1250000 },
- { 1, { 1620000, HFPLL, 1, 0x3C }, L2(15), 1262500 },
+ { 0, { 1620000, HFPLL, 1, 0x3C }, L2(15), 1262500 },
{ 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1262500 },
{ 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1287500 },
{ 0, { 0 } }
@@ -213,29 +213,29 @@
static struct acpu_level acpu_freq_tbl_fast[] __initdata = {
{ 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 950000 },
- { 1, { 432000, HFPLL, 2, 0x20 }, L2(5), 975000 },
+ { 0, { 432000, HFPLL, 2, 0x20 }, L2(5), 975000 },
{ 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 975000 },
- { 1, { 540000, HFPLL, 2, 0x28 }, L2(5), 1000000 },
+ { 0, { 540000, HFPLL, 2, 0x28 }, L2(5), 1000000 },
{ 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 1000000 },
- { 1, { 648000, HFPLL, 1, 0x18 }, L2(5), 1025000 },
+ { 0, { 648000, HFPLL, 1, 0x18 }, L2(5), 1025000 },
{ 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 1025000 },
- { 1, { 756000, HFPLL, 1, 0x1C }, L2(10), 1075000 },
+ { 0, { 756000, HFPLL, 1, 0x1C }, L2(10), 1075000 },
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(10), 1075000 },
- { 1, { 864000, HFPLL, 1, 0x20 }, L2(10), 1100000 },
+ { 0, { 864000, HFPLL, 1, 0x20 }, L2(10), 1100000 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(10), 1100000 },
- { 1, { 972000, HFPLL, 1, 0x24 }, L2(10), 1125000 },
+ { 0, { 972000, HFPLL, 1, 0x24 }, L2(10), 1125000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(10), 1125000 },
- { 1, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
+ { 0, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
{ 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1175000 },
- { 1, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
+ { 0, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
{ 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1200000 },
- { 1, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1225000 },
+ { 0, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1225000 },
{ 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1225000 },
- { 1, { 1404000, HFPLL, 1, 0x34 }, L2(15), 1237500 },
+ { 0, { 1404000, HFPLL, 1, 0x34 }, L2(15), 1237500 },
{ 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1237500 },
- { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1250000 },
+ { 0, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1250000 },
{ 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1250000 },
- { 1, { 1620000, HFPLL, 1, 0x3C }, L2(15), 1262500 },
+ { 0, { 1620000, HFPLL, 1, 0x3C }, L2(15), 1262500 },
{ 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1262500 },
{ 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1287500 },
{ 0, { 0 } }
diff --git a/arch/arm/mach-msm/board-8064-gpiomux.c b/arch/arm/mach-msm/board-8064-gpiomux.c
index fc44b18..cd3e636 100644
--- a/arch/arm/mach-msm/board-8064-gpiomux.c
+++ b/arch/arm/mach-msm/board-8064-gpiomux.c
@@ -479,6 +479,12 @@
.pull = GPIOMUX_PULL_NONE,
};
+static struct gpiomux_setting gsbi5_uart_cfg = {
+ .func = GPIOMUX_FUNC_2,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
static struct gpiomux_setting gsbi6_spi_cfg = {
.func = GPIOMUX_FUNC_2,
.drv = GPIOMUX_DRV_16MA,
@@ -1547,6 +1553,21 @@
},
};
+static struct msm_gpiomux_config mpq8064_gsbi5_uart_configs[] __initdata = {
+ {
+ .gpio = 51, /* GSBI5 UART TX */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi5_uart_cfg,
+ },
+ },
+ {
+ .gpio = 52, /* GSBI5 UART RX */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi5_uart_cfg,
+ },
+ },
+};
+
void __init apq8064_init_gpiomux(void)
{
int rc;
@@ -1565,6 +1586,8 @@
machine_is_mpq8064_dtv()) {
msm_gpiomux_install(mpq8064_gsbi5_i2c_configs,
ARRAY_SIZE(mpq8064_gsbi5_i2c_configs));
+ msm_gpiomux_install(mpq8064_gsbi5_uart_configs,
+ ARRAY_SIZE(mpq8064_gsbi5_uart_configs));
#ifdef CONFIG_MSM_VCAP
msm_gpiomux_install(vcap_configs,
ARRAY_SIZE(vcap_configs));
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index f9d1533..f6dd2ea 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -405,7 +405,7 @@
.resume_charge_percent = 99,
.term_current = CHG_TERM_MA,
.cool_temp = 10,
- .warm_temp = 40,
+ .warm_temp = 45,
.temp_check_period = 1,
.max_bat_chg_current = 1100,
.cool_bat_chg_current = 350,
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 95246a7..a8ad0d6 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -25,6 +25,7 @@
#include <linux/mfd/pm8xxx/misc.h>
#include <linux/msm_ssbi.h>
#include <linux/spi/spi.h>
+#include <linux/dma-contiguous.h>
#include <linux/dma-mapping.h>
#include <linux/platform_data/qcom_crypto_device.h>
#include <linux/msm_ion.h>
@@ -101,6 +102,7 @@
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
#define HOLE_SIZE 0x20000
+#define MSM_ION_MFC_META_SIZE 0x40000 /* 256 Kbytes */
#define MSM_CONTIG_MEM_SIZE 0x65000
#ifdef CONFIG_MSM_IOMMU
#define MSM_ION_MM_SIZE 0x3800000
@@ -114,7 +116,7 @@
#define MSM_ION_HEAP_NUM 8
#endif
#define MSM_ION_MM_FW_SIZE (0x200000 - HOLE_SIZE) /* (2MB - 128KB) */
-#define MSM_ION_MFC_SIZE SZ_8K
+#define MSM_ION_MFC_SIZE (SZ_8K + MSM_ION_MFC_META_SIZE)
#define MSM_ION_AUDIO_SIZE MSM_PMEM_AUDIO_SIZE
#else
#define MSM_CONTIG_MEM_SIZE 0x110C000
@@ -319,6 +321,17 @@
};
#endif
+static u64 msm_dmamask = DMA_BIT_MASK(32);
+
+static struct platform_device ion_mm_heap_device = {
+ .name = "ion-mm-heap-device",
+ .id = -1,
+ .dev = {
+ .dma_mask = &msm_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ }
+};
+
/**
* These heaps are listed in the order they will be allocated. Due to
* video hardware restrictions and content protection the FW heap has to
@@ -330,9 +343,7 @@
* to each other.
* Don't swap the order unless you know what you are doing!
*/
-static struct ion_platform_data apq8064_ion_pdata = {
- .nr = MSM_ION_HEAP_NUM,
- .heaps = {
+struct ion_platform_heap apq8064_heaps[] = {
{
.id = ION_SYSTEM_HEAP_ID,
.type = ION_HEAP_TYPE_SYSTEM,
@@ -346,6 +357,7 @@
.size = MSM_ION_MM_SIZE,
.memory_type = ION_EBI_TYPE,
.extra_data = (void *) &cp_mm_apq8064_ion_pdata,
+ .priv = &ion_mm_heap_device.dev
},
{
.id = ION_MM_FIRMWARE_HEAP_ID,
@@ -395,7 +407,11 @@
.extra_data = (void *) &co_apq8064_ion_pdata,
},
#endif
- }
+};
+
+static struct ion_platform_data apq8064_ion_pdata = {
+ .nr = MSM_ION_HEAP_NUM,
+ .heaps = apq8064_heaps,
};
static struct platform_device apq8064_ion_dev = {
@@ -451,26 +467,45 @@
{
#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
unsigned int i;
+ unsigned int ret;
unsigned int fixed_size = 0;
unsigned int fixed_low_size, fixed_middle_size, fixed_high_size;
unsigned long fixed_low_start, fixed_middle_start, fixed_high_start;
+ unsigned long cma_alignment;
+ unsigned int low_use_cma = 0;
+ unsigned int middle_use_cma = 0;
+ unsigned int high_use_cma = 0;
+
fixed_low_size = 0;
fixed_middle_size = 0;
fixed_high_size = 0;
+ cma_alignment = PAGE_SIZE << max(MAX_ORDER, pageblock_order);
+
for (i = 0; i < apq8064_ion_pdata.nr; ++i) {
- const struct ion_platform_heap *heap =
+ struct ion_platform_heap *heap =
&(apq8064_ion_pdata.heaps[i]);
+ int use_cma = 0;
+
if (heap->extra_data) {
int fixed_position = NOT_FIXED;
switch ((int)heap->type) {
case ION_HEAP_TYPE_CP:
+ if (((struct ion_cp_heap_pdata *)
+ heap->extra_data)->is_cma) {
+ heap->size = ALIGN(heap->size,
+ cma_alignment);
+ use_cma = 1;
+ }
fixed_position = ((struct ion_cp_heap_pdata *)
heap->extra_data)->fixed_position;
break;
+ case ION_HEAP_TYPE_DMA:
+ use_cma = 1;
+ /* Purposely fall through here */
case ION_HEAP_TYPE_CARVEOUT:
fixed_position = ((struct ion_co_heap_pdata *)
heap->extra_data)->fixed_position;
@@ -484,28 +519,70 @@
else
reserve_mem_for_ion(MEMTYPE_EBI1, heap->size);
- if (fixed_position == FIXED_LOW)
+ if (fixed_position == FIXED_LOW) {
fixed_low_size += heap->size;
- else if (fixed_position == FIXED_MIDDLE)
+ low_use_cma = use_cma;
+ } else if (fixed_position == FIXED_MIDDLE) {
fixed_middle_size += heap->size;
- else if (fixed_position == FIXED_HIGH)
+ middle_use_cma = use_cma;
+ } else if (fixed_position == FIXED_HIGH) {
fixed_high_size += heap->size;
+ high_use_cma = use_cma;
+ } else if (use_cma) {
+ /*
+ * Heaps that use CMA but are not part of the
+ * fixed set. Create wherever.
+ */
+ dma_declare_contiguous(
+ heap->priv,
+ heap->size,
+ 0,
+ 0xb0000000);
+
+ }
}
}
if (!fixed_size)
return;
- /* Since the fixed area may be carved out of lowmem,
- * make sure the length is a multiple of 1M.
+ /*
+ * Given the setup for the fixed area, we can't round up all sizes.
+ * Some sizes must be set up exactly and aligned correctly. Incorrect
+ * alignments are considered a configuration issue
*/
- fixed_size = (fixed_size + HOLE_SIZE + SECTION_SIZE - 1)
- & SECTION_MASK;
- apq8064_reserve_fixed_area(fixed_size);
fixed_low_start = APQ8064_FIXED_AREA_START;
+ if (low_use_cma) {
+ BUG_ON(!IS_ALIGNED(fixed_low_size + HOLE_SIZE, cma_alignment));
+ BUG_ON(!IS_ALIGNED(fixed_low_start, cma_alignment));
+ } else {
+ BUG_ON(!IS_ALIGNED(fixed_low_size + HOLE_SIZE, SECTION_SIZE));
+ ret = memblock_remove(fixed_low_start,
+ fixed_low_size + HOLE_SIZE);
+ BUG_ON(ret);
+ }
+
fixed_middle_start = fixed_low_start + fixed_low_size + HOLE_SIZE;
+ if (middle_use_cma) {
+ BUG_ON(!IS_ALIGNED(fixed_middle_start, cma_alignment));
+ BUG_ON(!IS_ALIGNED(fixed_middle_size, cma_alignment));
+ } else {
+ BUG_ON(!IS_ALIGNED(fixed_middle_size, SECTION_SIZE));
+ ret = memblock_remove(fixed_middle_start, fixed_middle_size);
+ BUG_ON(ret);
+ }
+
fixed_high_start = fixed_middle_start + fixed_middle_size;
+ if (high_use_cma) {
+ fixed_high_size = ALIGN(fixed_high_size, cma_alignment);
+ BUG_ON(!IS_ALIGNED(fixed_high_start, cma_alignment));
+ } else {
+ /* This is the end of the fixed area so it's okay to round up */
+ fixed_high_size = ALIGN(fixed_high_size, SECTION_SIZE);
+ ret = memblock_remove(fixed_high_start, fixed_high_size);
+ BUG_ON(ret);
+ }
for (i = 0; i < apq8064_ion_pdata.nr; ++i) {
struct ion_platform_heap *heap = &(apq8064_ion_pdata.heaps[i]);
@@ -521,6 +598,7 @@
fixed_position = pdata->fixed_position;
break;
case ION_HEAP_TYPE_CARVEOUT:
+ case ION_HEAP_TYPE_DMA:
fixed_position = ((struct ion_co_heap_pdata *)
heap->extra_data)->fixed_position;
break;
@@ -534,6 +612,14 @@
break;
case FIXED_MIDDLE:
heap->base = fixed_middle_start;
+ if (middle_use_cma) {
+ ret = dma_declare_contiguous(
+ heap->priv,
+ heap->size,
+ fixed_middle_start,
+ 0xa0000000);
+ WARN_ON(ret);
+ }
pdata->secure_base = fixed_middle_start
- HOLE_SIZE;
pdata->secure_size = HOLE_SIZE + heap->size;
@@ -2696,6 +2782,7 @@
#endif
static struct platform_device *mpq_devices[] __initdata = {
+ &mpq8064_device_uart_gsbi5,
&msm_device_sps_apq8064,
&mpq8064_device_qup_i2c_gsbi5,
#ifdef CONFIG_MSM_ROTATOR
@@ -2792,10 +2879,21 @@
#define GSBI_DUAL_MODE_CODE 0x60
#define MSM_GSBI1_PHYS 0x12440000
+#define MSM_GSBI5_PHYS 0x1A200000
static void __init apq8064_i2c_init(void)
{
void __iomem *gsbi_mem;
-
+ if (machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd() ||
+ machine_is_mpq8064_dtv()) {
+ gsbi_mem = ioremap_nocache(MSM_GSBI5_PHYS, 4);
+ writel_relaxed(GSBI_DUAL_MODE_CODE, gsbi_mem);
+ /* Ensure protocol code is written before proceeding */
+ wmb();
+ iounmap(gsbi_mem);
+ mpq8064_i2c_qup_gsbi5_pdata.use_gsbi_shared_mode = 1;
+ mpq8064_device_qup_i2c_gsbi5.dev.platform_data =
+ &mpq8064_i2c_qup_gsbi5_pdata;
+ }
apq8064_device_qup_i2c_gsbi1.dev.platform_data =
&apq8064_i2c_qup_gsbi1_pdata;
gsbi_mem = ioremap_nocache(MSM_GSBI1_PHYS, 4);
diff --git a/arch/arm/mach-msm/board-8910.c b/arch/arm/mach-msm/board-8910.c
index 42fe1ea..b4a95ee 100644
--- a/arch/arm/mach-msm/board-8910.c
+++ b/arch/arm/mach-msm/board-8910.c
@@ -69,6 +69,7 @@
CLK_DUMMY("iface_clk", NULL, "msm_sdcc.2", OFF),
CLK_DUMMY("core_clk", NULL, "msm_sdcc.2", OFF),
CLK_DUMMY("bus_clk", NULL, "msm_sdcc.2", OFF),
+ CLK_DUMMY("dfab_clk", DFAB_CLK, "msm_sps", OFF),
};
static struct clock_init_data msm_dummy_clock_init_data __initdata = {
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index dd4b67e..a5fded4 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -325,7 +325,7 @@
.resume_charge_percent = 99,
.term_current = CHG_TERM_MA,
.cool_temp = 10,
- .warm_temp = 40,
+ .warm_temp = 45,
.temp_check_period = 1,
.max_bat_chg_current = 1100,
.cool_bat_chg_current = 350,
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 512ae72..f0c33eb 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -29,6 +29,7 @@
#ifdef CONFIG_ANDROID_PMEM
#include <linux/android_pmem.h>
#endif
+#include <linux/dma-contiguous.h>
#include <linux/dma-mapping.h>
#include <linux/platform_data/qcom_crypto_device.h>
#include <linux/platform_data/qcom_wcnss_device.h>
@@ -132,7 +133,7 @@
#endif
#define MSM_PMEM_ADSP_SIZE 0x7800000
-#define MSM_PMEM_AUDIO_SIZE 0x314000
+#define MSM_PMEM_AUDIO_SIZE 0x408000
#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
#define MSM_PMEM_SIZE 0x4000000 /* 64 Mbytes */
#else
@@ -365,6 +366,18 @@
};
#endif
+
+static u64 msm_dmamask = DMA_BIT_MASK(32);
+
+static struct platform_device ion_mm_heap_device = {
+ .name = "ion-mm-heap-device",
+ .id = -1,
+ .dev = {
+ .dma_mask = &msm_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ }
+};
+
/**
* These heaps are listed in the order they will be allocated. Due to
* video hardware restrictions and content protection the FW heap has to
@@ -376,9 +389,7 @@
* to each other.
* Don't swap the order unless you know what you are doing!
*/
-static struct ion_platform_data msm8930_ion_pdata = {
- .nr = MSM_ION_HEAP_NUM,
- .heaps = {
+struct ion_platform_heap msm8930_heaps[] = {
{
.id = ION_SYSTEM_HEAP_ID,
.type = ION_HEAP_TYPE_SYSTEM,
@@ -392,6 +403,7 @@
.size = MSM_ION_MM_SIZE,
.memory_type = ION_EBI_TYPE,
.extra_data = (void *) &cp_mm_msm8930_ion_pdata,
+ .priv = &ion_mm_heap_device.dev
},
{
.id = ION_MM_FIRMWARE_HEAP_ID,
@@ -441,7 +453,12 @@
.extra_data = (void *) &co_msm8930_ion_pdata,
},
#endif
- }
+};
+
+static struct ion_platform_data msm8930_ion_pdata = {
+ .nr = MSM_ION_HEAP_NUM,
+ .heaps = msm8930_heaps,
+
};
static struct platform_device msm8930_ion_dev = {
@@ -497,26 +514,44 @@
{
#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
unsigned int i;
+ int ret;
unsigned int fixed_size = 0;
unsigned int fixed_low_size, fixed_middle_size, fixed_high_size;
unsigned long fixed_low_start, fixed_middle_start, fixed_high_start;
+ unsigned long cma_alignment;
+ unsigned int low_use_cma = 0;
+ unsigned int middle_use_cma = 0;
+ unsigned int high_use_cma = 0;
fixed_low_size = 0;
fixed_middle_size = 0;
fixed_high_size = 0;
+ cma_alignment = PAGE_SIZE << max(MAX_ORDER, pageblock_order);
+
for (i = 0; i < msm8930_ion_pdata.nr; ++i) {
- const struct ion_platform_heap *heap =
+ struct ion_platform_heap *heap =
&(msm8930_ion_pdata.heaps[i]);
+ int use_cma = 0;
+
if (heap->extra_data) {
int fixed_position = NOT_FIXED;
switch ((int) heap->type) {
case ION_HEAP_TYPE_CP:
+ if (((struct ion_cp_heap_pdata *)
+ heap->extra_data)->is_cma) {
+ heap->size = ALIGN(heap->size,
+ cma_alignment);
+ use_cma = 1;
+ }
fixed_position = ((struct ion_cp_heap_pdata *)
heap->extra_data)->fixed_position;
break;
+ case ION_HEAP_TYPE_DMA:
+ use_cma = 1;
+ /* Purposely fall through here */
case ION_HEAP_TYPE_CARVEOUT:
fixed_position = ((struct ion_co_heap_pdata *)
heap->extra_data)->fixed_position;
@@ -530,29 +565,68 @@
else
reserve_mem_for_ion(MEMTYPE_EBI1, heap->size);
- if (fixed_position == FIXED_LOW)
+ if (fixed_position == FIXED_LOW) {
fixed_low_size += heap->size;
- else if (fixed_position == FIXED_MIDDLE)
+ low_use_cma = use_cma;
+ } else if (fixed_position == FIXED_MIDDLE) {
fixed_middle_size += heap->size;
- else if (fixed_position == FIXED_HIGH)
+ middle_use_cma = use_cma;
+ } else if (fixed_position == FIXED_HIGH) {
fixed_high_size += heap->size;
-
+ high_use_cma = use_cma;
+ } else if (use_cma) {
+ /*
+ * Heaps that use CMA but are not part of the
+ * fixed set. Create wherever.
+ */
+ dma_declare_contiguous(
+ heap->priv,
+ heap->size,
+ 0,
+ 0xb0000000);
+ }
}
}
if (!fixed_size)
return;
-
- /* Since the fixed area may be carved out of lowmem,
- * make sure the length is a multiple of 1M.
+ /*
+ * Given the setup for the fixed area, we can't round up all sizes.
+ * Some sizes must be set up exactly and aligned correctly. Incorrect
+ * alignments are considered a configuration issue
*/
- fixed_size = (fixed_size + MSM_MM_FW_SIZE + SECTION_SIZE - 1)
- & SECTION_MASK;
- msm8930_reserve_fixed_area(fixed_size);
fixed_low_start = MSM8930_FIXED_AREA_START;
+ if (low_use_cma) {
+ BUG_ON(!IS_ALIGNED(fixed_low_size + HOLE_SIZE, cma_alignment));
+ BUG_ON(!IS_ALIGNED(fixed_low_start, cma_alignment));
+ } else {
+ BUG_ON(!IS_ALIGNED(fixed_low_size + HOLE_SIZE, SECTION_SIZE));
+ ret = memblock_remove(fixed_low_start,
+ fixed_low_size + HOLE_SIZE);
+ BUG_ON(ret);
+ }
+
fixed_middle_start = fixed_low_start + fixed_low_size + HOLE_SIZE;
+ if (middle_use_cma) {
+ BUG_ON(!IS_ALIGNED(fixed_middle_start, cma_alignment));
+ BUG_ON(!IS_ALIGNED(fixed_middle_size, cma_alignment));
+ } else {
+ BUG_ON(!IS_ALIGNED(fixed_middle_size, SECTION_SIZE));
+ ret = memblock_remove(fixed_middle_start, fixed_middle_size);
+ BUG_ON(ret);
+ }
+
fixed_high_start = fixed_middle_start + fixed_middle_size;
+ if (high_use_cma) {
+ fixed_high_size = ALIGN(fixed_high_size, cma_alignment);
+ BUG_ON(!IS_ALIGNED(fixed_high_start, cma_alignment));
+ } else {
+ /* This is the end of the fixed area so it's okay to round up */
+ fixed_high_size = ALIGN(fixed_high_size, SECTION_SIZE);
+ ret = memblock_remove(fixed_high_start, fixed_high_size);
+ BUG_ON(ret);
+ }
for (i = 0; i < msm8930_ion_pdata.nr; ++i) {
struct ion_platform_heap *heap = &(msm8930_ion_pdata.heaps[i]);
@@ -567,6 +641,7 @@
(struct ion_cp_heap_pdata *)heap->extra_data;
fixed_position = pdata->fixed_position;
break;
+ case ION_HEAP_TYPE_DMA:
case ION_HEAP_TYPE_CARVEOUT:
fixed_position = ((struct ion_co_heap_pdata *)
heap->extra_data)->fixed_position;
@@ -581,6 +656,12 @@
break;
case FIXED_MIDDLE:
heap->base = fixed_middle_start;
+ if (middle_use_cma)
+ dma_declare_contiguous(
+ &ion_mm_heap_device.dev,
+ heap->size,
+ fixed_middle_start,
+ 0xa0000000);
pdata->secure_base = fixed_middle_start
- HOLE_SIZE;
pdata->secure_size = HOLE_SIZE + heap->size;
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index 95a157a..f0ba1c9 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -406,7 +406,7 @@
.resume_charge_percent = 99,
.term_current = CHG_TERM_MA,
.cool_temp = 10,
- .warm_temp = 40,
+ .warm_temp = 45,
.temp_check_period = 1,
.max_bat_chg_current = 1100,
.cool_bat_chg_current = 350,
@@ -615,6 +615,6 @@
pm8921_bms_pdata.rconn_mohm = 20;
if (!machine_is_msm8960_fluid() && !machine_is_msm8960_liquid()
- && !machine_is_msm8960_fluid())
+ && !machine_is_msm8960_mtp())
pm8921_chg_pdata.battery_less_hardware = 1;
}
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index b9b3a1f..64ada24 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -30,6 +30,7 @@
#include <linux/android_pmem.h>
#endif
#include <linux/cyttsp-qc.h>
+#include <linux/dma-contiguous.h>
#include <linux/dma-mapping.h>
#include <linux/platform_data/qcom_crypto_device.h>
#include <linux/platform_data/qcom_wcnss_device.h>
@@ -151,6 +152,7 @@
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
#define HOLE_SIZE 0x20000
+#define MSM_ION_MFC_META_SIZE 0x40000 /* 256 Kbytes */
#define MSM_CONTIG_MEM_SIZE 0x65000
#ifdef CONFIG_MSM_IOMMU
#define MSM_ION_MM_SIZE 0x3800000 /* Need to be multiple of 64K */
@@ -164,7 +166,7 @@
#define MSM_ION_HEAP_NUM 8
#endif
#define MSM_ION_MM_FW_SIZE (0x200000 - HOLE_SIZE) /* 128kb */
-#define MSM_ION_MFC_SIZE SZ_8K
+#define MSM_ION_MFC_SIZE (SZ_8K + MSM_ION_MFC_META_SIZE)
#define MSM_ION_AUDIO_SIZE MSM_PMEM_AUDIO_SIZE
#define MSM_LIQUID_ION_MM_SIZE (MSM_ION_MM_SIZE + 0x600000)
@@ -387,6 +389,17 @@
};
#endif
+static u64 msm_dmamask = DMA_BIT_MASK(32);
+
+static struct platform_device ion_mm_heap_device = {
+ .name = "ion-mm-heap-device",
+ .id = -1,
+ .dev = {
+ .dma_mask = &msm_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ }
+};
+
/**
* These heaps are listed in the order they will be allocated. Due to
* video hardware restrictions and content protection the FW heap has to
@@ -398,9 +411,7 @@
* to each other.
* Don't swap the order unless you know what you are doing!
*/
-static struct ion_platform_data msm8960_ion_pdata = {
- .nr = MSM_ION_HEAP_NUM,
- .heaps = {
+struct ion_platform_heap msm8960_heaps[] = {
{
.id = ION_SYSTEM_HEAP_ID,
.type = ION_HEAP_TYPE_SYSTEM,
@@ -414,6 +425,7 @@
.size = MSM_ION_MM_SIZE,
.memory_type = ION_EBI_TYPE,
.extra_data = (void *) &cp_mm_msm8960_ion_pdata,
+ .priv = &ion_mm_heap_device.dev,
},
{
.id = ION_MM_FIRMWARE_HEAP_ID,
@@ -463,7 +475,11 @@
.extra_data = (void *) &co_msm8960_ion_pdata,
},
#endif
- }
+};
+
+static struct ion_platform_data msm8960_ion_pdata = {
+ .nr = MSM_ION_HEAP_NUM,
+ .heaps = msm8960_heaps,
};
static struct platform_device msm8960_ion_dev = {
@@ -546,21 +562,29 @@
{
#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
unsigned int i;
+ int ret;
unsigned int fixed_size = 0;
unsigned int fixed_low_size, fixed_middle_size, fixed_high_size;
unsigned long fixed_low_start, fixed_middle_start, fixed_high_start;
+ unsigned long cma_alignment;
+ unsigned int low_use_cma = 0;
+ unsigned int middle_use_cma = 0;
+ unsigned int high_use_cma = 0;
adjust_mem_for_liquid();
fixed_low_size = 0;
fixed_middle_size = 0;
fixed_high_size = 0;
+ cma_alignment = PAGE_SIZE << max(MAX_ORDER, pageblock_order);
+
for (i = 0; i < msm8960_ion_pdata.nr; ++i) {
struct ion_platform_heap *heap =
&(msm8960_ion_pdata.heaps[i]);
int align = SZ_4K;
int iommu_map_all = 0;
int adjacent_mem_id = INVALID_HEAP_ID;
+ int use_cma = 0;
if (heap->extra_data) {
int fixed_position = NOT_FIXED;
@@ -574,7 +598,16 @@
iommu_map_all =
((struct ion_cp_heap_pdata *)
heap->extra_data)->iommu_map_all;
+ if (((struct ion_cp_heap_pdata *)
+ heap->extra_data)->is_cma) {
+ heap->size = ALIGN(heap->size,
+ cma_alignment);
+ use_cma = 1;
+ }
break;
+ case ION_HEAP_TYPE_DMA:
+ use_cma = 1;
+ /* Purposely fall through here */
case ION_HEAP_TYPE_CARVEOUT:
fixed_position = ((struct ion_co_heap_pdata *)
heap->extra_data)->fixed_position;
@@ -598,28 +631,71 @@
else
reserve_mem_for_ion(MEMTYPE_EBI1, heap->size);
- if (fixed_position == FIXED_LOW)
+ if (fixed_position == FIXED_LOW) {
fixed_low_size += heap->size;
- else if (fixed_position == FIXED_MIDDLE)
+ low_use_cma = use_cma;
+ } else if (fixed_position == FIXED_MIDDLE) {
fixed_middle_size += heap->size;
- else if (fixed_position == FIXED_HIGH)
+ middle_use_cma = use_cma;
+ } else if (fixed_position == FIXED_HIGH) {
fixed_high_size += heap->size;
+ high_use_cma = use_cma;
+ } else if (use_cma) {
+ /*
+ * Heaps that use CMA but are not part of the
+ * fixed set. Create wherever.
+ */
+ dma_declare_contiguous(
+ heap->priv,
+ heap->size,
+ 0,
+ 0xb0000000);
+ }
}
}
if (!fixed_size)
return;
- /* Since the fixed area may be carved out of lowmem,
- * make sure the length is a multiple of 1M.
+ /*
+ * Given the setup for the fixed area, we can't round up all sizes.
+ * Some sizes must be set up exactly and aligned correctly. Incorrect
+ * alignments are considered a configuration issue
*/
- fixed_size = (fixed_size + MSM_MM_FW_SIZE + SECTION_SIZE - 1)
- & SECTION_MASK;
- msm8960_reserve_fixed_area(fixed_size);
fixed_low_start = MSM8960_FIXED_AREA_START;
+ if (low_use_cma) {
+ BUG_ON(!IS_ALIGNED(fixed_low_start, cma_alignment));
+ BUG_ON(!IS_ALIGNED(fixed_low_size + HOLE_SIZE, cma_alignment));
+ } else {
+ BUG_ON(!IS_ALIGNED(fixed_low_size + HOLE_SIZE, SECTION_SIZE));
+ ret = memblock_remove(fixed_low_start,
+ fixed_low_size + HOLE_SIZE);
+ BUG_ON(ret);
+ }
+
fixed_middle_start = fixed_low_start + fixed_low_size + HOLE_SIZE;
+ if (middle_use_cma) {
+ BUG_ON(!IS_ALIGNED(fixed_middle_start, cma_alignment));
+ BUG_ON(!IS_ALIGNED(fixed_middle_size, cma_alignment));
+ } else {
+ BUG_ON(!IS_ALIGNED(fixed_middle_size, SECTION_SIZE));
+ ret = memblock_remove(fixed_middle_start, fixed_middle_size);
+ BUG_ON(ret);
+ }
+
fixed_high_start = fixed_middle_start + fixed_middle_size;
+ if (high_use_cma) {
+ fixed_high_size = ALIGN(fixed_high_size, cma_alignment);
+ BUG_ON(!IS_ALIGNED(fixed_high_start, cma_alignment));
+ } else {
+ /* This is the end of the fixed area so it's okay to round up */
+ fixed_high_size = ALIGN(fixed_high_size, SECTION_SIZE);
+ ret = memblock_remove(fixed_high_start, fixed_high_size);
+ BUG_ON(ret);
+ }
+
+
for (i = 0; i < msm8960_ion_pdata.nr; ++i) {
struct ion_platform_heap *heap = &(msm8960_ion_pdata.heaps[i]);
@@ -635,6 +711,7 @@
fixed_position = pdata->fixed_position;
break;
case ION_HEAP_TYPE_CARVEOUT:
+ case ION_HEAP_TYPE_DMA:
fixed_position = ((struct ion_co_heap_pdata *)
heap->extra_data)->fixed_position;
break;
@@ -648,6 +725,14 @@
break;
case FIXED_MIDDLE:
heap->base = fixed_middle_start;
+ if (middle_use_cma) {
+ ret = dma_declare_contiguous(
+ &ion_mm_heap_device.dev,
+ heap->size,
+ fixed_middle_start,
+ 0xa0000000);
+ WARN_ON(ret);
+ }
pdata->secure_base = fixed_middle_start
- HOLE_SIZE;
pdata->secure_size = HOLE_SIZE + heap->size;
@@ -3316,7 +3401,8 @@
msm8960_init_pmic();
if (machine_is_msm8960_liquid() || (machine_is_msm8960_mtp() &&
- (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE)))
+ (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE ||
+ cpu_is_msm8960ab())))
msm_isa1200_board_info[0].platform_data = &isa1200_1_pdata;
msm8960_i2c_init();
msm8960_gfx_init();
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index 89ad4ef..0f6c000 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -16,6 +16,7 @@
#include <mach/board.h>
#include <mach/gpio.h>
#include <mach/gpiomux.h>
+#include <mach/socinfo.h>
#define KS8851_IRQ_GPIO 94
@@ -152,6 +153,53 @@
};
+static struct gpiomux_setting hsic_sus_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+ .dir = GPIOMUX_OUT_LOW,
+};
+
+static struct gpiomux_setting hsic_act_cfg = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_12MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting hsic_hub_act_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_UP,
+ .dir = GPIOMUX_IN,
+};
+
+static struct msm_gpiomux_config msm_hsic_configs[] = {
+ {
+ .gpio = 144, /*HSIC_STROBE */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &hsic_act_cfg,
+ [GPIOMUX_SUSPENDED] = &hsic_sus_cfg,
+ },
+ },
+ {
+ .gpio = 145, /* HSIC_DATA */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &hsic_act_cfg,
+ [GPIOMUX_SUSPENDED] = &hsic_sus_cfg,
+ },
+ },
+};
+
+static struct msm_gpiomux_config msm_hsic_hub_configs[] = {
+ {
+ .gpio = 50, /* HSIC_HUB_INT_N */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &hsic_hub_act_cfg,
+ [GPIOMUX_SUSPENDED] = &hsic_sus_cfg,
+ },
+ },
+};
+
static struct gpiomux_setting mhl_suspend_config = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_2MA,
@@ -171,7 +219,6 @@
.pull = GPIOMUX_PULL_UP,
};
-
static struct gpiomux_setting hdmi_suspend_cfg = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_2MA,
@@ -249,6 +296,21 @@
},
};
+static struct msm_gpiomux_config msm_rumi_blsp_configs[] __initdata = {
+ {
+ .gpio = 45, /* BLSP2 UART8 TX */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_uart_config,
+ },
+ },
+ {
+ .gpio = 46, /* BLSP2 UART8 RX */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_uart_config,
+ },
+ },
+};
+
static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
{
@@ -622,6 +684,14 @@
msm_gpiomux_install(msm_taiko_config, ARRAY_SIZE(msm_taiko_config));
+ msm_gpiomux_install(msm_hsic_configs, ARRAY_SIZE(msm_hsic_configs));
+ msm_gpiomux_install(msm_hsic_hub_configs,
+ ARRAY_SIZE(msm_hsic_hub_configs));
+
msm_gpiomux_install(msm_hdmi_configs, ARRAY_SIZE(msm_hdmi_configs));
msm_gpiomux_install(msm_mhl_configs, ARRAY_SIZE(msm_mhl_configs));
+
+ if (machine_is_msm8974_rumi())
+ msm_gpiomux_install(msm_rumi_blsp_configs,
+ ARRAY_SIZE(msm_rumi_blsp_configs));
}
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index c47b688..ca8f68a 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -304,8 +304,6 @@
"usb_bam", NULL),
OF_DEV_AUXDATA("qcom,spi-qup-v2", 0xF9924000, \
"spi_qsd.1", NULL),
- OF_DEV_AUXDATA("qcom,spmi-pmic-arb", 0xFC4C0000, \
- "spmi-pmic-arb.0", NULL),
OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF9824000, \
"msm_sdcc.1", NULL),
OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF98A4000, \
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index 1022616..1dcd54f 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -81,9 +81,7 @@
.align = PAGE_SIZE,
};
-static struct ion_platform_data ion_pdata = {
- .nr = MSM_ION_HEAP_NUM,
- .heaps = {
+static struct ion_platform_heap msm9615_heaps[] = {
{
.id = ION_SYSTEM_HEAP_ID,
.type = ION_HEAP_TYPE_SYSTEM,
@@ -102,7 +100,11 @@
.memory_type = ION_EBI_TYPE,
.extra_data = (void *) &co_ion_pdata,
},
- }
+};
+
+static struct ion_platform_data ion_pdata = {
+ .nr = MSM_ION_HEAP_NUM,
+ .heaps = msm9615_heaps,
};
static struct platform_device ion_dev = {
diff --git a/arch/arm/mach-msm/board-9625.c b/arch/arm/mach-msm/board-9625.c
index 42f3f41..f6a354f 100644
--- a/arch/arm/mach-msm/board-9625.c
+++ b/arch/arm/mach-msm/board-9625.c
@@ -125,135 +125,6 @@
msm_reserve();
}
-static struct resource smd_resource[] = {
- {
- .name = "modem_smd_in",
- .start = 32 + 25, /* mss_sw_to_kpss_ipc_irq0 */
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "modem_smsm_in",
- .start = 32 + 26, /* mss_sw_to_kpss_ipc_irq1 */
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "adsp_smd_in",
- .start = 32 + 156, /* lpass_to_kpss_ipc_irq0 */
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "adsp_smsm_in",
- .start = 32 + 157, /* lpass_to_kpss_ipc_irq1 */
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "rpm_smd_in",
- .start = 32 + 168, /* rpm_to_kpss_ipc_irq4 */
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct smd_subsystem_config smd_config_list[] = {
- {
- .irq_config_id = SMD_MODEM,
- .subsys_name = "modem",
- .edge = SMD_APPS_MODEM,
-
- .smd_int.irq_name = "modem_smd_in",
- .smd_int.flags = IRQF_TRIGGER_RISING,
- .smd_int.irq_id = -1,
- .smd_int.device_name = "smd_dev",
- .smd_int.dev_id = 0,
- .smd_int.out_bit_pos = 1 << 12,
- .smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
- .smd_int.out_offset = 0x8,
-
- .smsm_int.irq_name = "modem_smsm_in",
- .smsm_int.flags = IRQF_TRIGGER_RISING,
- .smsm_int.irq_id = -1,
- .smsm_int.device_name = "smsm_dev",
- .smsm_int.dev_id = 0,
- .smsm_int.out_bit_pos = 1 << 13,
- .smsm_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
- .smsm_int.out_offset = 0x8,
- },
- {
- .irq_config_id = SMD_Q6,
- .subsys_name = "adsp",
- .edge = SMD_APPS_QDSP,
-
- .smd_int.irq_name = "adsp_smd_in",
- .smd_int.flags = IRQF_TRIGGER_RISING,
- .smd_int.irq_id = -1,
- .smd_int.device_name = "smd_dev",
- .smd_int.dev_id = 0,
- .smd_int.out_bit_pos = 1 << 8,
- .smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
- .smd_int.out_offset = 0x8,
-
- .smsm_int.irq_name = "adsp_smsm_in",
- .smsm_int.flags = IRQF_TRIGGER_RISING,
- .smsm_int.irq_id = -1,
- .smsm_int.device_name = "smsm_dev",
- .smsm_int.dev_id = 0,
- .smsm_int.out_bit_pos = 1 << 9,
- .smsm_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
- .smsm_int.out_offset = 0x8,
- },
- {
- .irq_config_id = SMD_RPM,
- .subsys_name = NULL, /* do not use PIL to load RPM */
- .edge = SMD_APPS_RPM,
-
- .smd_int.irq_name = "rpm_smd_in",
- .smd_int.flags = IRQF_TRIGGER_RISING,
- .smd_int.irq_id = -1,
- .smd_int.device_name = "smd_dev",
- .smd_int.dev_id = 0,
- .smd_int.out_bit_pos = 1 << 0,
- .smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
- .smd_int.out_offset = 0x8,
-
- .smsm_int.irq_name = NULL, /* RPM does not support SMSM */
- .smsm_int.flags = 0,
- .smsm_int.irq_id = 0,
- .smsm_int.device_name = NULL,
- .smsm_int.dev_id = 0,
- .smsm_int.out_bit_pos = 0,
- .smsm_int.out_base = NULL,
- .smsm_int.out_offset = 0,
- },
-};
-
-static struct smd_smem_regions aux_smem_areas[] = {
- {
- .phys_addr = (void *)(0xfc428000),
- .size = 0x4000,
- },
-};
-
-static struct smd_subsystem_restart_config smd_ssr_cfg = {
- .disable_smsm_reset_handshake = 1,
-};
-
-static struct smd_platform smd_platform_data = {
- .num_ss_configs = ARRAY_SIZE(smd_config_list),
- .smd_ss_configs = smd_config_list,
- .smd_ssr_config = &smd_ssr_cfg,
- .num_smem_areas = ARRAY_SIZE(aux_smem_areas),
- .smd_smem_areas = aux_smem_areas,
-};
-
-struct platform_device msm_device_smd_9625 = {
- .name = "msm_smd",
- .id = -1,
- .resource = smd_resource,
- .num_resources = ARRAY_SIZE(smd_resource),
- .dev = {
- .platform_data = &smd_platform_data,
- }
-};
-
#define BIMC_BASE 0xfc380000
#define BIMC_SIZE 0x0006A000
#define SYS_NOC_BASE 0xfc460000
@@ -345,11 +216,6 @@
ARRAY_SIZE(msm_bus_9625_devices));
}
-void __init msm9625_add_devices(void)
-{
- platform_device_register(&msm_device_smd_9625);
-}
-
/*
* Used to satisfy dependencies for devices that need to be
* run early or in a particular order. Most likely your device doesn't fall
@@ -376,7 +242,6 @@
msm9625_init_gpiomux();
of_platform_populate(NULL, of_default_bus_match_table,
msm9625_auxdata_lookup, NULL);
- msm9625_add_devices();
msm9625_add_drivers();
}
diff --git a/arch/arm/mach-msm/board-msm7627a-io.c b/arch/arm/mach-msm/board-msm7627a-io.c
index 2983dc0..8c52456 100644
--- a/arch/arm/mach-msm/board-msm7627a-io.c
+++ b/arch/arm/mach-msm/board-msm7627a-io.c
@@ -727,6 +727,15 @@
[KP_INDEX_SKU3(1, 1)] = KEY_CAMERA,
};
+static unsigned int kp_row_gpios_skud[] = {31, 32};
+static unsigned int kp_col_gpios_skud[] = {37};
+
+static const unsigned short keymap_skud[] = {
+ [KP_INDEX_SKU3(0, 0)] = KEY_VOLUMEUP,
+ [KP_INDEX_SKU3(0, 1)] = KEY_VOLUMEDOWN,
+};
+
+
static struct gpio_event_matrix_info kp_matrix_info_sku3 = {
.info.func = gpio_event_matrix_func,
.keymap = keymap_sku3,
@@ -887,13 +896,23 @@
#endif
/* keypad */
+
+ if (machine_is_qrd_skud_prime()) {
+ kp_matrix_info_sku3.keymap = keymap_skud;
+ kp_matrix_info_sku3.output_gpios = kp_row_gpios_skud;
+ kp_matrix_info_sku3.input_gpios = kp_col_gpios_skud;
+ kp_matrix_info_sku3.noutputs = ARRAY_SIZE(kp_row_gpios_skud);
+ kp_matrix_info_sku3.ninputs = ARRAY_SIZE(kp_col_gpios_skud);
+ }
+
if (machine_is_msm8625_evt())
kp_matrix_info_8625.keymap = keymap_8625_evt;
if (machine_is_msm7627a_evb() || machine_is_msm8625_evb() ||
machine_is_msm8625_evt())
platform_device_register(&kp_pdev_8625);
- else if (machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7())
+ else if (machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7()
+ || machine_is_qrd_skud_prime())
platform_device_register(&kp_pdev_sku3);
/* leds */
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index 4e14ff3..9fd5218 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -767,10 +767,7 @@
* These heaps are listed in the order they will be allocated.
* Don't swap the order unless you know what you are doing!
*/
-static struct ion_platform_data ion_pdata = {
- .nr = MSM_ION_HEAP_NUM,
- .has_outer_cache = 1,
- .heaps = {
+struct ion_platform_heap msm7627a_heaps[] = {
{
.id = ION_SYSTEM_HEAP_ID,
.type = ION_HEAP_TYPE_SYSTEM,
@@ -802,7 +799,12 @@
.extra_data = (void *)&co_ion_pdata,
},
#endif
- }
+};
+
+static struct ion_platform_data ion_pdata = {
+ .nr = MSM_ION_HEAP_NUM,
+ .has_outer_cache = 1,
+ .heaps = msm7627a_heaps,
};
static struct platform_device ion_dev = {
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index ee13e04..9822aa9 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -7161,9 +7161,7 @@
* These heaps are listed in the order they will be allocated.
* Don't swap the order unless you know what you are doing!
*/
-static struct ion_platform_data ion_pdata = {
- .nr = MSM_ION_HEAP_NUM,
- .heaps = {
+struct ion_platform_heap msm7x30_heaps[] = {
{
.id = ION_SYSTEM_HEAP_ID,
.type = ION_HEAP_TYPE_SYSTEM,
@@ -7195,7 +7193,11 @@
.extra_data = (void *)&co_ion_pdata,
},
#endif
- }
+};
+
+static struct ion_platform_data ion_pdata = {
+ .nr = MSM_ION_HEAP_NUM,
+ .heaps = msm7x30_heaps,
};
static struct platform_device ion_dev = {
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index d831ad2..08e6a0d 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -5347,9 +5347,7 @@
* to each other.
* Don't swap the order unless you know what you are doing!
*/
-static struct ion_platform_data ion_pdata = {
- .nr = MSM_ION_HEAP_NUM,
- .heaps = {
+struct ion_platform_heap msm8x60_heaps [] = {
{
.id = ION_SYSTEM_HEAP_ID,
.type = ION_HEAP_TYPE_SYSTEM,
@@ -5424,7 +5422,11 @@
.extra_data = (void *)&co_ion_pdata,
},
#endif
- }
+};
+
+static struct ion_platform_data ion_pdata = {
+ .nr = MSM_ION_HEAP_NUM,
+ .heaps = msm8x60_heaps,
};
static struct platform_device ion_dev = {
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index a25290f..47a3120 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -802,10 +802,7 @@
* These heaps are listed in the order they will be allocated.
* Don't swap the order unless you know what you are doing!
*/
-static struct ion_platform_data ion_pdata = {
- .nr = MSM_ION_HEAP_NUM,
- .has_outer_cache = 1,
- .heaps = {
+struct ion_platform_heap qrd7627a_heaps[] = {
{
.id = ION_SYSTEM_HEAP_ID,
.type = ION_HEAP_TYPE_SYSTEM,
@@ -837,7 +834,12 @@
.extra_data = (void *)&co_ion_pdata,
},
#endif
- }
+};
+
+static struct ion_platform_data ion_pdata = {
+ .nr = MSM_ION_HEAP_NUM,
+ .has_outer_cache = 1,
+ .heaps = qrd7627a_heaps,
};
static struct platform_device ion_dev = {
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index c394982..f6386b4 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -5282,7 +5282,7 @@
CLK_LOOKUP("core_clk", gsbi2_uart_clk.c, ""),
CLK_LOOKUP("core_clk", gsbi3_uart_clk.c, ""),
CLK_LOOKUP("core_clk", gsbi4_uart_clk.c, ""),
- CLK_LOOKUP("core_clk", gsbi5_uart_clk.c, ""),
+ CLK_LOOKUP("core_clk", gsbi5_uart_clk.c, "msm_serial_hsl.2"),
CLK_LOOKUP("core_clk", gsbi6_uart_clk.c, "msm_serial_hs.0"),
CLK_LOOKUP("core_clk", gsbi7_uart_clk.c, "msm_serial_hsl.0"),
CLK_LOOKUP("core_clk", gsbi1_qup_clk.c, "qup_i2c.0"),
@@ -5331,6 +5331,7 @@
CLK_LOOKUP("iface_clk", gsbi2_p_clk.c, ""),
CLK_LOOKUP("iface_clk", gsbi3_p_clk.c, "qup_i2c.3"),
CLK_LOOKUP("iface_clk", gsbi4_p_clk.c, "qup_i2c.4"),
+ CLK_LOOKUP("iface_clk", gsbi5_p_clk.c, "msm_serial_hsl.2"),
CLK_LOOKUP("iface_clk", gsbi5_p_clk.c, "spi_qsd.0"),
CLK_LOOKUP("iface_clk", gsbi5_p_clk.c, "qup_i2c.5"),
CLK_LOOKUP("iface_clk", gsbi6_p_clk.c, "msm_serial_hs.0"),
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 68bffa5..95f9327 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -522,6 +522,14 @@
#define dsipll0_pixel_mm_source_val 1
#define hdmipll_mm_source_val 3
+#define F_GCC_GND \
+ { \
+ .freq_hz = 0, \
+ .m_val = 0, \
+ .n_val = 0, \
+ .div_src_val = BVAL(4, 0, 1) | BVAL(10, 8, gnd_source_val), \
+ }
+
#define F(f, s, div, m, n) \
{ \
.freq_hz = (f), \
@@ -792,11 +800,6 @@
static DEFINE_CLK_VOTER(ocmemgx_msmbus_a_clk, &ocmemgx_a_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(ocmemgx_core_clk, &ocmemgx_clk.c, LONG_MAX);
-static DEFINE_CLK_VOTER(pnoc_sdcc1_clk, &pnoc_clk.c, 0);
-static DEFINE_CLK_VOTER(pnoc_sdcc2_clk, &pnoc_clk.c, 0);
-static DEFINE_CLK_VOTER(pnoc_sdcc3_clk, &pnoc_clk.c, 0);
-static DEFINE_CLK_VOTER(pnoc_sdcc4_clk, &pnoc_clk.c, 0);
-
static DEFINE_CLK_VOTER(pnoc_sps_clk, &pnoc_clk.c, 0);
static struct clk_freq_tbl ftbl_gcc_usb30_master_clk[] = {
@@ -914,6 +917,7 @@
};
static struct clk_freq_tbl ftbl_gcc_blsp1_2_uart1_6_apps_clk[] = {
+ F_GCC_GND,
F( 3686400, gpll0, 1, 96, 15625),
F( 7372800, gpll0, 1, 192, 15625),
F(14745600, gpll0, 1, 384, 15625),
@@ -2960,7 +2964,7 @@
};
static struct clk_freq_tbl ftbl_mdss_edppixel_clk[] = {
- F_MDSS(148500000, edppll_350, 2, 0, 0),
+ F_MDSS(138500000, edppll_350, 2, 0, 0),
F_MDSS(350000000, edppll_350, 11, 0, 0),
F_END
};
@@ -3065,9 +3069,11 @@
*/
F_HDMI( 0, hdmipll, 1, 0, 0),
F_HDMI( 25200000, hdmipll, 1, 0, 0),
+ F_HDMI( 27000000, hdmipll, 1, 0, 0),
F_HDMI( 27030000, hdmipll, 1, 0, 0),
F_HDMI( 74250000, hdmipll, 1, 0, 0),
F_HDMI(148500000, hdmipll, 1, 0, 0),
+ F_HDMI(268500000, hdmipll, 1, 0, 0),
F_HDMI(297000000, hdmipll, 1, 0, 0),
F_END
};
@@ -4976,16 +4982,12 @@
static struct clk_lookup msm_clocks_8974_rumi[] = {
CLK_LOOKUP("iface_clk", gcc_sdcc1_ahb_clk.c, "msm_sdcc.1"),
CLK_LOOKUP("core_clk", gcc_sdcc1_apps_clk.c, "msm_sdcc.1"),
- CLK_LOOKUP("bus_clk", pnoc_sdcc1_clk.c, "msm_sdcc.1"),
CLK_LOOKUP("iface_clk", gcc_sdcc2_ahb_clk.c, "msm_sdcc.2"),
CLK_LOOKUP("core_clk", gcc_sdcc2_apps_clk.c, "msm_sdcc.2"),
- CLK_LOOKUP("bus_clk", pnoc_sdcc2_clk.c, "msm_sdcc.2"),
CLK_LOOKUP("iface_clk", gcc_sdcc3_ahb_clk.c, "msm_sdcc.3"),
CLK_LOOKUP("core_clk", gcc_sdcc3_apps_clk.c, "msm_sdcc.3"),
- CLK_LOOKUP("bus_clk", pnoc_sdcc3_clk.c, "msm_sdcc.3"),
CLK_LOOKUP("iface_clk", gcc_sdcc4_ahb_clk.c, "msm_sdcc.4"),
CLK_LOOKUP("core_clk", gcc_sdcc4_apps_clk.c, "msm_sdcc.4"),
- CLK_LOOKUP("bus_clk", pnoc_sdcc4_clk.c, "msm_sdcc.4"),
CLK_DUMMY("xo", XO_CLK, NULL, OFF),
CLK_DUMMY("xo", XO_CLK, "pil_pronto", OFF),
CLK_DUMMY("core_clk", BLSP2_UART_CLK, "f991f000.serial", OFF),
@@ -5101,16 +5103,12 @@
CLK_LOOKUP("iface_clk", gcc_sdcc1_ahb_clk.c, "msm_sdcc.1"),
CLK_LOOKUP("core_clk", gcc_sdcc1_apps_clk.c, "msm_sdcc.1"),
- CLK_LOOKUP("bus_clk", pnoc_sdcc1_clk.c, "msm_sdcc.1"),
CLK_LOOKUP("iface_clk", gcc_sdcc2_ahb_clk.c, "msm_sdcc.2"),
CLK_LOOKUP("core_clk", gcc_sdcc2_apps_clk.c, "msm_sdcc.2"),
- CLK_LOOKUP("bus_clk", pnoc_sdcc2_clk.c, "msm_sdcc.2"),
CLK_LOOKUP("iface_clk", gcc_sdcc3_ahb_clk.c, "msm_sdcc.3"),
CLK_LOOKUP("core_clk", gcc_sdcc3_apps_clk.c, "msm_sdcc.3"),
- CLK_LOOKUP("bus_clk", pnoc_sdcc3_clk.c, "msm_sdcc.3"),
CLK_LOOKUP("iface_clk", gcc_sdcc4_ahb_clk.c, "msm_sdcc.4"),
CLK_LOOKUP("core_clk", gcc_sdcc4_apps_clk.c, "msm_sdcc.4"),
- CLK_LOOKUP("bus_clk", pnoc_sdcc4_clk.c, "msm_sdcc.4"),
CLK_LOOKUP("iface_clk", gcc_tsif_ahb_clk.c, ""),
CLK_LOOKUP("ref_clk", gcc_tsif_ref_clk.c, ""),
diff --git a/arch/arm/mach-msm/clock-9625.c b/arch/arm/mach-msm/clock-9625.c
index b284168..2e85006 100644
--- a/arch/arm/mach-msm/clock-9625.c
+++ b/arch/arm/mach-msm/clock-9625.c
@@ -246,6 +246,14 @@
#define lpapll0_lpass_source_val 1
#define gpll0_lpass_source_val 5
+#define F_GCC_GND \
+ { \
+ .freq_hz = 0, \
+ .m_val = 0, \
+ .n_val = 0, \
+ .div_src_val = BVAL(4, 0, 1) | BVAL(10, 8, gnd_source_val), \
+ }
+
#define F(f, s, div, m, n) \
{ \
.freq_hz = (f), \
@@ -611,6 +619,7 @@
};
static struct clk_freq_tbl ftbl_gcc_blsp1_uart1_6_apps_clk[] = {
+ F_GCC_GND,
F( 3686400, gpll0, 1, 96, 15625),
F( 7372800, gpll0, 1, 192, 15625),
F(14745600, gpll0, 1, 384, 15625),
@@ -1309,6 +1318,17 @@
},
};
+static struct branch_clk gcc_ipa_sleep_clk = {
+ .cbcr_reg = IPA_SLEEP_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_ipa_sleep_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_ipa_sleep_clk.c),
+ },
+};
+
static struct branch_clk gcc_pdm2_clk = {
.cbcr_reg = PDM2_CBCR,
.has_sibling = 0,
@@ -2063,6 +2083,7 @@
CLK_LOOKUP("core_clk", gcc_ipa_clk.c, "fd4c0000.qcom,ipa"),
CLK_LOOKUP("bus_clk", gcc_sys_noc_ipa_axi_clk.c, "fd4c0000.qcom,ipa"),
CLK_LOOKUP("iface_clk", gcc_ipa_cnoc_clk.c, "fd4c0000.qcom,ipa"),
+ CLK_LOOKUP("inactivity_clk", gcc_ipa_sleep_clk.c, "fd4c0000.qcom,ipa"),
CLK_LOOKUP("core_clk", gcc_pdm2_clk.c, ""),
CLK_LOOKUP("iface_clk", gcc_pdm_ahb_clk.c, ""),
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index e7a596d..c30e566 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -37,30 +37,65 @@
#define HDMI_PHY_PLL_SIZE 0x000000D4
/* hdmi phy registers */
-#define HDMI_PHY_PD_CTRL0 (0x0010)
-#define HDMI_PHY_GLB_CFG (0x0018)
-#define HDMI_PHY_STATUS (0x005C)
+#define HDMI_PHY_ANA_CFG0 (0x0000)
+#define HDMI_PHY_ANA_CFG1 (0x0004)
+#define HDMI_PHY_ANA_CFG2 (0x0008)
+#define HDMI_PHY_ANA_CFG3 (0x000C)
+#define HDMI_PHY_PD_CTRL0 (0x0010)
+#define HDMI_PHY_PD_CTRL1 (0x0014)
+#define HDMI_PHY_GLB_CFG (0x0018)
+#define HDMI_PHY_DCC_CFG0 (0x001C)
+#define HDMI_PHY_DCC_CFG1 (0x0020)
+#define HDMI_PHY_TXCAL_CFG0 (0x0024)
+#define HDMI_PHY_TXCAL_CFG1 (0x0028)
+#define HDMI_PHY_TXCAL_CFG2 (0x002C)
+#define HDMI_PHY_TXCAL_CFG3 (0x0030)
+#define HDMI_PHY_BIST_CFG0 (0x0034)
+#define HDMI_PHY_BIST_CFG1 (0x0038)
+#define HDMI_PHY_BIST_PATN0 (0x003C)
+#define HDMI_PHY_BIST_PATN1 (0x0040)
+#define HDMI_PHY_BIST_PATN2 (0x0044)
+#define HDMI_PHY_BIST_PATN3 (0x0048)
+#define HDMI_PHY_STATUS (0x005C)
/* hdmi phy unified pll registers */
-#define HDMI_UNI_PLL_REFCLK_CF (0x0000)
-#define HDMI_UNI_PLL_POSTDIV1_CFG (0x0004)
-#define HDMI_UNI_PLL_VCOLPF_CFG (0x000C)
-#define HDMI_UNI_PLL_GLB_CFG (0x0020)
-#define HDMI_UNI_PLL_POSTDIV2_CFG (0x0024)
-#define HDMI_UNI_PLL_POSTDIV3_CFG (0x0028)
-#define HDMI_UNI_PLL_SDM_CFG0 (0x0038)
-#define HDMI_UNI_PLL_SDM_CFG1 (0x003C)
-#define HDMI_UNI_PLL_SDM_CFG2 (0x0040)
-#define HDMI_UNI_PLL_SDM_CFG3 (0x0044)
-#define HDMI_UNI_PLL_SDM_CFG4 (0x0048)
-#define HDMI_UNI_PLL_LKDET_CFG0 (0x005C)
-#define HDMI_UNI_PLL_LKDET_CFG1 (0x0060)
-#define HDMI_UNI_PLL_LKDET_CFG2 (0x0064)
-#define HDMI_UNI_PLL_CAL_CFG8 (0x008C)
-#define HDMI_UNI_PLL_CAL_CFG9 (0x0090)
-#define HDMI_UNI_PLL_CAL_CFG10 (0x0094)
-#define HDMI_UNI_PLL_CAL_CFG11 (0x0098)
-#define HDMI_UNI_PLL_STATUS (0x00C0)
+#define HDMI_UNI_PLL_REFCLK_CFG (0x0000)
+#define HDMI_UNI_PLL_POSTDIV1_CFG (0x0004)
+#define HDMI_UNI_PLL_CHFPUMP_CFG (0x0008)
+#define HDMI_UNI_PLL_VCOLPF_CFG (0x000C)
+#define HDMI_UNI_PLL_VREG_CFG (0x0010)
+#define HDMI_UNI_PLL_PWRGEN_CFG (0x0014)
+#define HDMI_UNI_PLL_GLB_CFG (0x0020)
+#define HDMI_UNI_PLL_POSTDIV2_CFG (0x0024)
+#define HDMI_UNI_PLL_POSTDIV3_CFG (0x0028)
+#define HDMI_UNI_PLL_LPFR_CFG (0x002C)
+#define HDMI_UNI_PLL_LPFC1_CFG (0x0030)
+#define HDMI_UNI_PLL_LPFC2_CFG (0x0034)
+#define HDMI_UNI_PLL_SDM_CFG0 (0x0038)
+#define HDMI_UNI_PLL_SDM_CFG1 (0x003C)
+#define HDMI_UNI_PLL_SDM_CFG2 (0x0040)
+#define HDMI_UNI_PLL_SDM_CFG3 (0x0044)
+#define HDMI_UNI_PLL_SDM_CFG4 (0x0048)
+#define HDMI_UNI_PLL_SSC_CFG0 (0x004C)
+#define HDMI_UNI_PLL_SSC_CFG1 (0x0050)
+#define HDMI_UNI_PLL_SSC_CFG2 (0x0054)
+#define HDMI_UNI_PLL_SSC_CFG3 (0x0058)
+#define HDMI_UNI_PLL_LKDET_CFG0 (0x005C)
+#define HDMI_UNI_PLL_LKDET_CFG1 (0x0060)
+#define HDMI_UNI_PLL_LKDET_CFG2 (0x0064)
+#define HDMI_UNI_PLL_CAL_CFG0 (0x006C)
+#define HDMI_UNI_PLL_CAL_CFG1 (0x0070)
+#define HDMI_UNI_PLL_CAL_CFG2 (0x0074)
+#define HDMI_UNI_PLL_CAL_CFG3 (0x0078)
+#define HDMI_UNI_PLL_CAL_CFG4 (0x007C)
+#define HDMI_UNI_PLL_CAL_CFG5 (0x0080)
+#define HDMI_UNI_PLL_CAL_CFG6 (0x0084)
+#define HDMI_UNI_PLL_CAL_CFG7 (0x0088)
+#define HDMI_UNI_PLL_CAL_CFG8 (0x008C)
+#define HDMI_UNI_PLL_CAL_CFG9 (0x0090)
+#define HDMI_UNI_PLL_CAL_CFG10 (0x0094)
+#define HDMI_UNI_PLL_CAL_CFG11 (0x0098)
+#define HDMI_UNI_PLL_STATUS (0x00C0)
#define VCO_CLK 424000000
static unsigned char *mdss_dsi_base;
@@ -391,32 +426,106 @@
case 25200000:
/* 640x480p60 */
- REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CF);
- REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
- REG_W(0x36, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
- REG_W(0x4C, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
+ REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CFG);
+ REG_W(0x19, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
+ REG_W(0x0E, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFR_CFG);
+ REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC1_CFG);
+ REG_W(0x0D, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC2_CFG);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
+ REG_W(0x52, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
- REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
+ REG_W(0xB0, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG4);
REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
- REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
+ REG_W(0x03, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
REG_W(0x60, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG8);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG9);
- REG_W(0xFC, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);
- REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
+ REG_W(0xF4, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);
+ REG_W(0x02, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
+ REG_W(0x1F, hdmi_phy_base + HDMI_PHY_PD_CTRL0);
+ udelay(50);
+
+ REG_W(0x0F, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL1);
+ REG_W(0x10, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+ REG_W(0xDB, hdmi_phy_base + HDMI_PHY_ANA_CFG0);
+ REG_W(0x43, hdmi_phy_base + HDMI_PHY_ANA_CFG1);
+ REG_W(0x02, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_ANA_CFG3);
+ REG_W(0x04, hdmi_phy_pll_base + HDMI_UNI_PLL_VREG_CFG);
+ REG_W(0xD0, hdmi_phy_base + HDMI_PHY_DCC_CFG0);
+ REG_W(0x1A, hdmi_phy_base + HDMI_PHY_DCC_CFG1);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG0);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG1);
+ REG_W(0x02, hdmi_phy_base + HDMI_PHY_TXCAL_CFG2);
+ REG_W(0x05, hdmi_phy_base + HDMI_PHY_TXCAL_CFG3);
+ udelay(200);
+ break;
+
+ case 27000000:
+ /* 576p50/576i50 case */
+ REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CFG);
+ REG_W(0x19, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
+ REG_W(0X0E, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFR_CFG);
+ REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC1_CFG);
+ REG_W(0X0D, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC2_CFG);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
+ REG_W(0x54, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
+ REG_W(0x18, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG4);
+ REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
+ REG_W(0X1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
+ REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
+ REG_W(0x03, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
+ REG_W(0x60, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG8);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG9);
+ REG_W(0x2a, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);
+ REG_W(0x03, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
+ REG_W(0X1F, hdmi_phy_base + HDMI_PHY_PD_CTRL0);
+ udelay(50);
+
+ REG_W(0X0F, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL1);
+ REG_W(0x10, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+ REG_W(0XDB, hdmi_phy_base + HDMI_PHY_ANA_CFG0);
+ REG_W(0x43, hdmi_phy_base + HDMI_PHY_ANA_CFG1);
+ REG_W(0x02, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_ANA_CFG3);
+ REG_W(0x04, hdmi_phy_pll_base + HDMI_UNI_PLL_VREG_CFG);
+ REG_W(0XD0, hdmi_phy_base + HDMI_PHY_DCC_CFG0);
+ REG_W(0X1A, hdmi_phy_base + HDMI_PHY_DCC_CFG1);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG0);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG1);
+ REG_W(0x02, hdmi_phy_base + HDMI_PHY_TXCAL_CFG2);
+ REG_W(0x05, hdmi_phy_base + HDMI_PHY_TXCAL_CFG3);
+ udelay(200);
break;
case 27030000:
/* 480p60/480i60 case */
- REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CF);
- REG_W(0x18, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
- REG_W(0x36, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
- REG_W(0x14, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
- REG_W(0x63, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
+ REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CFG);
+ REG_W(0x19, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
+ REG_W(0x0E, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFR_CFG);
+ REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC1_CFG);
+ REG_W(0x0D, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC2_CFG);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
+ REG_W(0x54, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
+ REG_W(0x66, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
REG_W(0x1D, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG4);
REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
@@ -425,10 +534,29 @@
REG_W(0x03, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
REG_W(0x60, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG8);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG9);
REG_W(0x2A, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);
REG_W(0x03, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
+ REG_W(0x1F, hdmi_phy_base + HDMI_PHY_PD_CTRL0);
+ udelay(50);
+
+ REG_W(0x0F, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL1);
+ REG_W(0x10, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+ REG_W(0xDB, hdmi_phy_base + HDMI_PHY_ANA_CFG0);
+ REG_W(0x43, hdmi_phy_base + HDMI_PHY_ANA_CFG1);
+ REG_W(0x02, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_ANA_CFG3);
+ REG_W(0x04, hdmi_phy_pll_base + HDMI_UNI_PLL_VREG_CFG);
+ REG_W(0xD0, hdmi_phy_base + HDMI_PHY_DCC_CFG0);
+ REG_W(0x1A, hdmi_phy_base + HDMI_PHY_DCC_CFG1);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG0);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG1);
+ REG_W(0x02, hdmi_phy_base + HDMI_PHY_TXCAL_CFG2);
+ REG_W(0x05, hdmi_phy_base + HDMI_PHY_TXCAL_CFG3);
+ udelay(200);
break;
case 74250000:
@@ -436,51 +564,148 @@
* 720p60/720p50/1080i60/1080i50
* 1080p24/1080p30/1080p25 case
*/
- REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CF);
- REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
- REG_W(0x36, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
+ REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CFG);
+ REG_W(0x19, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
+ REG_W(0x0E, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFR_CFG);
+ REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC1_CFG);
+ REG_W(0x0D, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC2_CFG);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
REG_W(0x52, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
- REG_W(0xFD, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
- REG_W(0x55, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
+ REG_W(0x56, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG4);
REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
- REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
- REG_W(0x60, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG8);
- REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG9);
- REG_W(0x73, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);
- REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
- break;
-
- case 148500000:
- REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CF);
- REG_W(0x18, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
- REG_W(0x36, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
- REG_W(0x52, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
- REG_W(0xFD, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
- REG_W(0x55, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
- REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG4);
- REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
- REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
- REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
- REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
- REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
- REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
REG_W(0x60, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG8);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG9);
REG_W(0xE6, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);
REG_W(0x02, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
+ REG_W(0x1F, hdmi_phy_base + HDMI_PHY_PD_CTRL0);
+ udelay(50);
+
+ REG_W(0x0F, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL1);
+ REG_W(0x10, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+ REG_W(0xDB, hdmi_phy_base + HDMI_PHY_ANA_CFG0);
+ REG_W(0x43, hdmi_phy_base + HDMI_PHY_ANA_CFG1);
+ REG_W(0x02, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_ANA_CFG3);
+ REG_W(0x04, hdmi_phy_pll_base + HDMI_UNI_PLL_VREG_CFG);
+ REG_W(0xD0, hdmi_phy_base + HDMI_PHY_DCC_CFG0);
+ REG_W(0x1A, hdmi_phy_base + HDMI_PHY_DCC_CFG1);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG0);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG1);
+ REG_W(0x02, hdmi_phy_base + HDMI_PHY_TXCAL_CFG2);
+ REG_W(0x05, hdmi_phy_base + HDMI_PHY_TXCAL_CFG3);
+ udelay(200);
+ break;
+
+ case 148500000:
+ REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CFG);
+ REG_W(0x19, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
+ REG_W(0x0E, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFR_CFG);
+ REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC1_CFG);
+ REG_W(0x0D, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC2_CFG);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
+ REG_W(0x52, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
+ REG_W(0x56, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG4);
+ REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
+ REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
+ REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
+ REG_W(0x60, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG8);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG9);
+ REG_W(0xE6, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);
+ REG_W(0x02, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
+ REG_W(0x1F, hdmi_phy_base + HDMI_PHY_PD_CTRL0);
+ udelay(50);
+
+ REG_W(0x0F, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL1);
+ REG_W(0x10, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+ REG_W(0xDB, hdmi_phy_base + HDMI_PHY_ANA_CFG0);
+ REG_W(0x43, hdmi_phy_base + HDMI_PHY_ANA_CFG1);
+ REG_W(0x02, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_ANA_CFG3);
+ REG_W(0x04, hdmi_phy_pll_base + HDMI_UNI_PLL_VREG_CFG);
+ REG_W(0xD0, hdmi_phy_base + HDMI_PHY_DCC_CFG0);
+ REG_W(0x1A, hdmi_phy_base + HDMI_PHY_DCC_CFG1);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG0);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG1);
+ REG_W(0x02, hdmi_phy_base + HDMI_PHY_TXCAL_CFG2);
+ REG_W(0x05, hdmi_phy_base + HDMI_PHY_TXCAL_CFG3);
+ udelay(200);
+ break;
+
+ case 268500000:
+ REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CFG);
+ REG_W(0x19, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
+ REG_W(0x0E, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFR_CFG);
+ REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC1_CFG);
+ REG_W(0x0D, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC2_CFG);
+ REG_W(0x36, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
+ REG_W(0x61, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
+ REG_W(0xF6, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG4);
+ REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
+ REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
+ REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
+ REG_W(0x60, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG8);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG9);
+ REG_W(0x3E, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);
+ REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
+ REG_W(0x1F, hdmi_phy_base + HDMI_PHY_PD_CTRL0);
+ udelay(50);
+
+ REG_W(0x0F, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL1);
+ REG_W(0x10, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+ REG_W(0xDB, hdmi_phy_base + HDMI_PHY_ANA_CFG0);
+ REG_W(0x43, hdmi_phy_base + HDMI_PHY_ANA_CFG1);
+ REG_W(0x05, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_ANA_CFG3);
+ REG_W(0x04, hdmi_phy_pll_base + HDMI_UNI_PLL_VREG_CFG);
+ REG_W(0xD0, hdmi_phy_base + HDMI_PHY_DCC_CFG0);
+ REG_W(0x1A, hdmi_phy_base + HDMI_PHY_DCC_CFG1);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG0);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG1);
+ REG_W(0x11, hdmi_phy_base + HDMI_PHY_TXCAL_CFG2);
+ REG_W(0x05, hdmi_phy_base + HDMI_PHY_TXCAL_CFG3);
+ udelay(200);
break;
case 297000000:
- REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CF);
- REG_W(0x18, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
- REG_W(0x36, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
+ REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CFG);
+ REG_W(0x19, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
+ REG_W(0x0E, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFR_CFG);
+ REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC1_CFG);
+ REG_W(0x0D, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC2_CFG);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
REG_W(0x65, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
- REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
REG_W(0xAC, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG4);
REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
@@ -489,14 +714,31 @@
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
REG_W(0x60, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG8);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG9);
REG_W(0xCD, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);
REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
+ REG_W(0x1F, hdmi_phy_base + HDMI_PHY_PD_CTRL0);
+ udelay(50);
+
+ REG_W(0x0F, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL1);
+ REG_W(0x10, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+ REG_W(0xDB, hdmi_phy_base + HDMI_PHY_ANA_CFG0);
+ REG_W(0x43, hdmi_phy_base + HDMI_PHY_ANA_CFG1);
+ REG_W(0x06, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+ REG_W(0x03, hdmi_phy_base + HDMI_PHY_ANA_CFG3);
+ REG_W(0x04, hdmi_phy_pll_base + HDMI_UNI_PLL_VREG_CFG);
+ REG_W(0xD0, hdmi_phy_base + HDMI_PHY_DCC_CFG0);
+ REG_W(0x1A, hdmi_phy_base + HDMI_PHY_DCC_CFG1);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG0);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG1);
+ REG_W(0x02, hdmi_phy_base + HDMI_PHY_TXCAL_CFG2);
+ REG_W(0x05, hdmi_phy_base + HDMI_PHY_TXCAL_CFG3);
+ udelay(200);
break;
- case 27000000:
- /* 576p50/576i50 case */
default:
pr_err("%s: not supported rate=%ld\n", __func__, rate);
}
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index f559629..8d10d6a 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -59,6 +59,7 @@
/* GSBI UART devices */
#define MSM_UART1DM_PHYS (MSM_GSBI1_PHYS + 0x10000)
#define MSM_UART3DM_PHYS (MSM_GSBI3_PHYS + 0x40000)
+#define MSM_UART5DM_PHYS (MSM_GSBI5_PHYS + 0x40000)
#define MSM_UART6DM_PHYS (MSM_GSBI6_PHYS + 0x40000)
#define MSM_UART7DM_PHYS (MSM_GSBI7_PHYS + 0x40000)
@@ -465,6 +466,33 @@
.resource = resources_qup_i2c_gsbi5,
};
+static struct resource resources_uart_gsbi5[] = {
+ {
+ .start = GSBI5_UARTDM_IRQ,
+ .end = GSBI5_UARTDM_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = MSM_UART5DM_PHYS,
+ .end = MSM_UART5DM_PHYS + PAGE_SIZE - 1,
+ .name = "uartdm_resource",
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MSM_GSBI5_PHYS,
+ .end = MSM_GSBI5_PHYS + PAGE_SIZE - 1,
+ .name = "gsbi_resource",
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct platform_device mpq8064_device_uart_gsbi5 = {
+ .name = "msm_serial_hsl",
+ .id = 2,
+ .num_resources = ARRAY_SIZE(resources_uart_gsbi5),
+ .resource = resources_uart_gsbi5,
+};
+
/* GSBI 6 used into UARTDM Mode */
static struct resource msm_uart_dm6_resources[] = {
{
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index 0faf500..aad512e 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -143,12 +143,12 @@
MSM_RPM_MAP(8930, PM8038_CLK2_0, PM8038_CLK2, 2),
MSM_RPM_MAP(8930, PM8038_LVS1, PM8038_LVS1, 1),
MSM_RPM_MAP(8930, PM8038_LVS2, PM8038_LVS2, 1),
- MSM_RPM_MAP(8930, NCP_0, NCP, 2),
- MSM_RPM_MAP(8930, CXO_BUFFERS, CXO_BUFFERS, 1),
- MSM_RPM_MAP(8930, USB_OTG_SWITCH, USB_OTG_SWITCH, 1),
- MSM_RPM_MAP(8930, HDMI_SWITCH, HDMI_SWITCH, 1),
- MSM_RPM_MAP(8930, QDSS_CLK, QDSS_CLK, 1),
- MSM_RPM_MAP(8930, VOLTAGE_CORNER, VOLTAGE_CORNER, 1),
+ MSM_RPM_MAP_PMIC(8930, 8038, NCP_0, NCP, 2),
+ MSM_RPM_MAP_PMIC(8930, 8038, CXO_BUFFERS, CXO_BUFFERS, 1),
+ MSM_RPM_MAP_PMIC(8930, 8038, USB_OTG_SWITCH, USB_OTG_SWITCH, 1),
+ MSM_RPM_MAP_PMIC(8930, 8038, HDMI_SWITCH, HDMI_SWITCH, 1),
+ MSM_RPM_MAP_PMIC(8930, 8038, QDSS_CLK, QDSS_CLK, 1),
+ MSM_RPM_MAP_PMIC(8930, 8038, VOLTAGE_CORNER, VOLTAGE_CORNER, 1),
},
.target_status = {
MSM_RPM_STATUS_ID_MAP(8930, VERSION_MAJOR),
@@ -369,12 +369,12 @@
MSM_RPM_MAP(8930, PM8917_LVS5, PM8917_LVS5, 1),
MSM_RPM_MAP(8930, PM8917_LVS6, PM8917_LVS6, 1),
MSM_RPM_MAP(8930, PM8917_LVS7, PM8917_LVS7, 1),
- MSM_RPM_MAP(8930, NCP_0, NCP, 2),
- MSM_RPM_MAP(8930, CXO_BUFFERS, CXO_BUFFERS, 1),
- MSM_RPM_MAP(8930, USB_OTG_SWITCH, USB_OTG_SWITCH, 1),
- MSM_RPM_MAP(8930, HDMI_SWITCH, HDMI_SWITCH, 1),
- MSM_RPM_MAP(8930, QDSS_CLK, QDSS_CLK, 1),
- MSM_RPM_MAP(8930, VOLTAGE_CORNER, VOLTAGE_CORNER, 1),
+ MSM_RPM_MAP_PMIC(8930, 8917, NCP_0, NCP, 2),
+ MSM_RPM_MAP_PMIC(8930, 8917, CXO_BUFFERS, CXO_BUFFERS, 1),
+ MSM_RPM_MAP_PMIC(8930, 8917, USB_OTG_SWITCH, USB_OTG_SWITCH, 1),
+ MSM_RPM_MAP_PMIC(8930, 8917, HDMI_SWITCH, HDMI_SWITCH, 1),
+ MSM_RPM_MAP_PMIC(8930, 8917, QDSS_CLK, QDSS_CLK, 1),
+ MSM_RPM_MAP_PMIC(8930, 8917, VOLTAGE_CORNER, VOLTAGE_CORNER, 1),
},
.target_status = {
MSM_RPM_STATUS_ID_MAP(8930, VERSION_MAJOR),
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index bd9ea49..c0d73c2 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -56,6 +56,7 @@
extern struct platform_device msm_device_uart_dm8;
extern struct platform_device msm_device_uart_dm9;
extern struct platform_device mpq8064_device_uartdm_gsbi6;
+extern struct platform_device mpq8064_device_uart_gsbi5;
extern struct platform_device msm8960_device_uart_gsbi2;
extern struct platform_device msm8960_device_uart_gsbi5;
diff --git a/arch/arm/mach-msm/dma.c b/arch/arm/mach-msm/dma.c
index 12f5aa9..22fc1ac 100644
--- a/arch/arm/mach-msm/dma.c
+++ b/arch/arm/mach-msm/dma.c
@@ -373,9 +373,8 @@
spin_lock_irqsave(&dmov_conf[adm].list_lock, flags);
list_add_tail(&cmd->list, &dmov_conf[adm].staged_commands[ch]);
- spin_unlock_irqrestore(&dmov_conf[adm].list_lock, flags);
-
queue_work(dmov_conf[adm].cmd_wq, &cmd->work);
+ spin_unlock_irqrestore(&dmov_conf[adm].list_lock, flags);
}
void msm_dmov_enqueue_cmd_ext(unsigned id, struct msm_dmov_cmd *cmd)
diff --git a/arch/arm/mach-msm/event_timer.c b/arch/arm/mach-msm/event_timer.c
index e06dad4..9f46f68 100644
--- a/arch/arm/mach-msm/event_timer.c
+++ b/arch/arm/mach-msm/event_timer.c
@@ -193,21 +193,7 @@
unsigned long flags;
struct event_timer_info *event =
(struct event_timer_info *)data;
-
- local_irq_save(flags);
- create_hrtimer(event->node.expires);
- local_irq_restore(flags);
-}
-
-/**
- * setup_timer() : Helper function to setup timer on primary
- * core during hrtimer callback.
- * @event: event handle causing the wakeup.
- */
-static void setup_event_hrtimer(struct event_timer_info *event)
-{
struct timerqueue_node *next;
- unsigned long flags;
spin_lock_irqsave(&event_timer_lock, flags);
if (is_event_active(event))
@@ -223,9 +209,18 @@
if (msm_event_debug_mask && MSM_EVENT_TIMER_DEBUG)
pr_info("%s: Setting timer for %lu", __func__,
(unsigned long)ktime_to_ns(event->node.expires));
+ create_hrtimer(event->node.expires);
+ }
+}
- smp_call_function_single(0, create_timer_smp, event, 1);
- }
+/**
+ * setup_timer() : Helper function to setup timer on primary
+ * core during hrtimer callback.
+ * @event: event handle causing the wakeup.
+ */
+static void setup_event_hrtimer(struct event_timer_info *event)
+{
+ smp_call_function_single(0, create_timer_smp, event, 1);
}
/**
diff --git a/arch/arm/mach-msm/include/mach/irqs-8064.h b/arch/arm/mach-msm/include/mach/irqs-8064.h
index 973034b..f4129fe 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8064.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8064.h
@@ -15,15 +15,6 @@
/* MSM ACPU Interrupt Numbers */
-/*
- * 0-15: STI/SGI (software triggered/generated interrupts)
- * 16-31: PPI (private peripheral interrupts)
- * 32+: SPI (shared peripheral interrupts)
- */
-
-#define GIC_PPI_START 16
-#define GIC_SPI_START 32
-
#define INT_VGIC (GIC_PPI_START + 0)
#define INT_DEBUG_TIMER_EXP (GIC_PPI_START + 1)
#define INT_GP_TIMER_EXP (GIC_PPI_START + 2)
diff --git a/arch/arm/mach-msm/include/mach/irqs-8092.h b/arch/arm/mach-msm/include/mach/irqs-8092.h
index ae9634e..955e669 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8092.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8092.h
@@ -15,31 +15,12 @@
/* MSM ACPU Interrupt Numbers */
-/*
- * 0-15: STI/SGI (software triggered/generated interrupts)
- * 16-31: PPI (private peripheral interrupts)
- * 32+: SPI (shared peripheral interrupts)
- */
-
-#define GIC_PPI_START 16
-#define GIC_SPI_START 32
-
-#define AVS_SVICINT (GIC_PPI_START + 6)
-#define AVS_SVICINTSWDONE (GIC_PPI_START + 7)
#define INT_ARMQC_PERFMON (GIC_PPI_START + 10)
/* PPI 15 is unused */
#define APCC_QGICL2PERFMONIRPTREQ (GIC_SPI_START + 1)
#define SC_SICL2PERFMONIRPTREQ APCC_QGICL2PERFMONIRPTREQ
#define TLMM_MSM_SUMMARY_IRQ (GIC_SPI_START + 208)
-#define SPS_BAM_DMA_IRQ (GIC_SPI_START + 105)
-
-#define NR_MSM_IRQS 1020 /* Should be 256 - but higher due to bug in sim */
-#define NR_GPIO_IRQS 146
-#define NR_QPNP_IRQS 32768 /* SPARSE_IRQ is required to support this */
-#define NR_BOARD_IRQS NR_QPNP_IRQS
-#define NR_TLMM_MSM_DIR_CONN_IRQ 8
-#define NR_MSM_GPIOS NR_GPIO_IRQS
#endif
diff --git a/arch/arm/mach-msm/include/mach/irqs-8226.h b/arch/arm/mach-msm/include/mach/irqs-8226.h
deleted file mode 100644
index 72602b1..0000000
--- a/arch/arm/mach-msm/include/mach/irqs-8226.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#ifndef __ASM_ARCH_MSM_IRQS_8226_H
-#define __ASM_ARCH_MSM_IRQS_8226_H
-
-/* MSM ACPU Interrupt Numbers */
-
-/*
- * 0-15: STI/SGI (software triggered/generated interrupts)
- * 16-31: PPI (private peripheral interrupts)
- * 32+: SPI (shared peripheral interrupts)
- */
-
-#define GIC_PPI_START 16
-#define GIC_SPI_START 32
-
-#define INT_ARMQC_PERFMON (GIC_PPI_START + 10)
-/* PPI 15 is unused */
-
-#define APCC_QGICL2PERFMONIRPTREQ (GIC_SPI_START + 1)
-#define SC_SICL2PERFMONIRPTREQ APCC_QGICL2PERFMONIRPTREQ
-#define TLMM_MSM_SUMMARY_IRQ (GIC_SPI_START + 208)
-
-#define NR_MSM_IRQS 256
-#define NR_GPIO_IRQS 117
-#define NR_QPNP_IRQS 32768 /* SPARSE_IRQ is required to support this */
-#define NR_BOARD_IRQS NR_QPNP_IRQS
-#define NR_TLMM_MSM_DIR_CONN_IRQ 8
-#define NR_MSM_GPIOS NR_GPIO_IRQS
-
-#endif
diff --git a/arch/arm/mach-msm/include/mach/irqs-8625.h b/arch/arm/mach-msm/include/mach/irqs-8625.h
index f591a9e..a83dd2e 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8625.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8625.h
@@ -13,9 +13,6 @@
#ifndef __ASM_ARCH_MSM_IRQS_8625_H
#define __ASM_ARCH_MSM_IRQS_8625_H
-#define GIC_PPI_START 16
-#define GIC_SPI_START 32
-
#ifdef CONFIG_MSM_FIQ
#define FIQ_START 0
#endif
diff --git a/arch/arm/mach-msm/include/mach/irqs-8910.h b/arch/arm/mach-msm/include/mach/irqs-8910.h
deleted file mode 100644
index e883214..0000000
--- a/arch/arm/mach-msm/include/mach/irqs-8910.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#ifndef __ASM_ARCH_MSM_IRQS_8910_H
-#define __ASM_ARCH_MSM_IRQS_8910_H
-
-/* MSM ACPU Interrupt Numbers */
-
-/*
- * 0-15: STI/SGI (software triggered/generated interrupts)
- * 16-31: PPI (private peripheral interrupts)
- * 32+: SPI (shared peripheral interrupts)
- */
-
-#define GIC_PPI_START 16
-#define GIC_SPI_START 32
-
-#define INT_ARMQC_PERFMON (GIC_PPI_START + 10)
-
-#define APCC_QGICL2PERFMONIRPTREQ (GIC_SPI_START + 1)
-#define SC_SICL2PERFMONIRPTREQ APCC_QGICL2PERFMONIRPTREQ
-#define TLMM_MSM_SUMMARY_IRQ (GIC_SPI_START + 208)
-
-#define NR_MSM_IRQS 256
-#define NR_GPIO_IRQS 102
-#define NR_QPNP_IRQS 32768 /* SPARSE_IRQ is required to support this */
-#define NR_BOARD_IRQS NR_QPNP_IRQS
-#define NR_TLMM_MSM_DIR_CONN_IRQ 8
-#define NR_MSM_GPIOS NR_GPIO_IRQS
-
-#endif
diff --git a/arch/arm/mach-msm/include/mach/irqs-8930.h b/arch/arm/mach-msm/include/mach/irqs-8930.h
index bfc32f6..fbde7cb 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8930.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8930.h
@@ -15,13 +15,6 @@
/* MSM ACPU Interrupt Numbers */
-/* 0-15: STI/SGI (software triggered/generated interrupts)
- 16-31: PPI (private peripheral interrupts)
- 32+: SPI (shared peripheral interrupts) */
-
-#define GIC_PPI_START 16
-#define GIC_SPI_START 32
-
#define INT_VGIC (GIC_PPI_START + 0)
#define INT_DEBUG_TIMER_EXP (GIC_PPI_START + 1)
#define INT_GP_TIMER_EXP (GIC_PPI_START + 2)
diff --git a/arch/arm/mach-msm/include/mach/irqs-8960.h b/arch/arm/mach-msm/include/mach/irqs-8960.h
index 012dd74..64be113 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8960.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8960.h
@@ -15,13 +15,6 @@
/* MSM ACPU Interrupt Numbers */
-/* 0-15: STI/SGI (software triggered/generated interrupts)
- 16-31: PPI (private peripheral interrupts)
- 32+: SPI (shared peripheral interrupts) */
-
-#define GIC_PPI_START 16
-#define GIC_SPI_START 32
-
#define INT_VGIC (GIC_PPI_START + 0)
#define INT_DEBUG_TIMER_EXP (GIC_PPI_START + 1)
#define INT_GP_TIMER_EXP (GIC_PPI_START + 2)
diff --git a/arch/arm/mach-msm/include/mach/irqs-8974.h b/arch/arm/mach-msm/include/mach/irqs-8974.h
index 8152eca..f18b3df 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8974.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8974.h
@@ -15,29 +15,12 @@
/* MSM ACPU Interrupt Numbers */
-/*
- * 0-15: STI/SGI (software triggered/generated interrupts)
- * 16-31: PPI (private peripheral interrupts)
- * 32+: SPI (shared peripheral interrupts)
- */
-
-#define GIC_PPI_START 16
-#define GIC_SPI_START 32
-
#define INT_ARMQC_PERFMON (GIC_PPI_START + 7)
/* PPI 15 is unused */
#define APCC_QGICL2PERFMONIRPTREQ (GIC_SPI_START + 1)
#define SC_SICL2PERFMONIRPTREQ APCC_QGICL2PERFMONIRPTREQ
#define TLMM_MSM_SUMMARY_IRQ (GIC_SPI_START + 208)
-#define SPS_BAM_DMA_IRQ (GIC_SPI_START + 105)
-
-#define NR_MSM_IRQS 1020 /* Should be 256 - but higher due to bug in sim */
-#define NR_GPIO_IRQS 146
-#define NR_QPNP_IRQS 32768 /* SPARSE_IRQ is required to support this */
-#define NR_BOARD_IRQS NR_QPNP_IRQS
-#define NR_TLMM_MSM_DIR_CONN_IRQ 8
-#define NR_MSM_GPIOS NR_GPIO_IRQS
#endif
diff --git a/arch/arm/mach-msm/include/mach/irqs-8x60.h b/arch/arm/mach-msm/include/mach/irqs-8x60.h
index c9729f4..d08f645 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8x60.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8x60.h
@@ -16,13 +16,6 @@
/* MSM ACPU Interrupt Numbers */
-/* 0-15: STI/SGI (software triggered/generated interrupts)
- 16-31: PPI (private peripheral interrupts)
- 32+: SPI (shared peripheral interrupts) */
-
-#define GIC_PPI_START 16
-#define GIC_SPI_START 32
-
#define INT_DEBUG_TIMER_EXP (GIC_PPI_START + 0)
#define INT_GP_TIMER_EXP (GIC_PPI_START + 1)
#define INT_GP_TIMER2_EXP (GIC_PPI_START + 2)
diff --git a/arch/arm/mach-msm/include/mach/irqs-9615.h b/arch/arm/mach-msm/include/mach/irqs-9615.h
index 39058a6..b9c66c3 100644
--- a/arch/arm/mach-msm/include/mach/irqs-9615.h
+++ b/arch/arm/mach-msm/include/mach/irqs-9615.h
@@ -15,15 +15,7 @@
/* MSM ACPU Interrupt Numbers */
-/*
- * 0-15: STI/SGI (software triggered/generated interrupts)
- * 16-31: PPI (private peripheral interrupts)
- * 32+: SPI (shared peripheral interrupts)
- */
-
#define FIQ_START 16
-#define GIC_PPI_START 16
-#define GIC_SPI_START 32
#define INT_DEBUG_TIMER_EXP (GIC_PPI_START + 1)
#define INT_GP_TIMER_EXP (GIC_PPI_START + 2)
diff --git a/arch/arm/mach-msm/include/mach/irqs-9625.h b/arch/arm/mach-msm/include/mach/irqs-9625.h
index b1f65d1..15c7010 100644
--- a/arch/arm/mach-msm/include/mach/irqs-9625.h
+++ b/arch/arm/mach-msm/include/mach/irqs-9625.h
@@ -15,18 +15,8 @@
/* MSM ACPU Interrupt Numbers */
-/*
- * 0-15: STI/SGI (software triggered/generated interrupts)
- * 16-31: PPI (private peripheral interrupts)
- * 32+: SPI (shared peripheral interrupts)
- */
-
-#define GIC_PPI_START 16
-
#define INT_ARMQC_PERFMON (GIC_PPI_START + 7)
-#define GIC_SPI_START 32
-
#define APCC_QGICL2PERFMONIRPTREQ (GIC_SPI_START + 1)
#define SC_SICL2PERFMONIRPTREQ APCC_QGICL2PERFMONIRPTREQ
#define TLMM_MSM_SUMMARY_IRQ (GIC_SPI_START + 208)
diff --git a/arch/arm/mach-msm/include/mach/irqs.h b/arch/arm/mach-msm/include/mach/irqs.h
index 8d96192..f5822fc 100644
--- a/arch/arm/mach-msm/include/mach/irqs.h
+++ b/arch/arm/mach-msm/include/mach/irqs.h
@@ -17,9 +17,44 @@
#ifndef __ASM_ARCH_MSM_IRQS_H
#define __ASM_ARCH_MSM_IRQS_H
+/*
+ * 0-15: STI/SGI (software triggered/generated interrupts)
+ * 16-31: PPI (private peripheral interrupts)
+ * 32+: SPI (shared peripheral interrupts)
+ */
+#define GIC_PPI_START 16
+#define GIC_SPI_START 32
+
#define MSM_IRQ_BIT(irq) (1 << ((irq) & 31))
-#if defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_APQ8064) || \
+#if defined(CONFIG_ARCH_MSM8974) || defined(CONFIG_ARCH_MPQ8092)
+
+#ifdef CONFIG_ARCH_MSM8974
+#include "irqs-8974.h"
+#endif
+
+#ifdef CONFIG_ARCH_MPQ8092
+#include "irqs-8092.h"
+#endif
+
+#define NR_MSM_IRQS 1020 /* Should be 256 - but higher due to bug in sim */
+#define NR_GPIO_IRQS 146
+#define NR_QPNP_IRQS 32768
+#define NR_BOARD_IRQS NR_QPNP_IRQS
+#define NR_TLMM_MSM_DIR_CONN_IRQ 8
+#define NR_MSM_GPIOS NR_GPIO_IRQS
+
+#elif defined(CONFIG_ARCH_MSM8910) || defined(CONFIG_ARCH_MSM8226)
+
+#define TLMM_MSM_SUMMARY_IRQ (GIC_SPI_START + 208)
+#define NR_MSM_IRQS 256
+#define NR_GPIO_IRQS 117
+#define NR_QPNP_IRQS 32768
+#define NR_BOARD_IRQS NR_QPNP_IRQS
+#define NR_TLMM_MSM_DIR_CONN_IRQ 8
+#define NR_MSM_GPIOS NR_GPIO_IRQS
+
+#elif defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_APQ8064) || \
defined(CONFIG_ARCH_MSM8930)
#ifdef CONFIG_ARCH_MSM8960
@@ -56,18 +91,10 @@
#else
-#if defined(CONFIG_ARCH_MSM8974)
-#include "irqs-8974.h"
-#elif defined(CONFIG_ARCH_MSM8910)
-#include "irqs-8910.h"
-#elif defined(CONFIG_ARCH_MPQ8092)
-#include "irqs-8092.h"
-#elif defined(CONFIG_ARCH_MSM9615)
+#if defined(CONFIG_ARCH_MSM9615)
#include "irqs-9615.h"
#elif defined(CONFIG_ARCH_MSM9625)
#include "irqs-9625.h"
-#elif defined(CONFIG_ARCH_MSM8226)
-#include "irqs-8226.h"
#elif defined(CONFIG_ARCH_MSM7X30)
#include "irqs-7x30.h"
#elif defined(CONFIG_ARCH_QSD8X50)
diff --git a/arch/arm/mach-msm/include/mach/msm_ipc_router.h b/arch/arm/mach-msm/include/mach/msm_ipc_router.h
index 45a7e19..c68c783 100644
--- a/arch/arm/mach-msm/include/mach/msm_ipc_router.h
+++ b/arch/arm/mach-msm/include/mach/msm_ipc_router.h
@@ -55,6 +55,7 @@
void *endpoint;
void (*notify)(unsigned event, void *priv);
+ int (*check_send_permissions)(void *data);
uint32_t num_tx;
uint32_t num_rx;
diff --git a/arch/arm/mach-msm/include/mach/ocmem.h b/arch/arm/mach-msm/include/mach/ocmem.h
index 6124cd6..5355215 100644
--- a/arch/arm/mach-msm/include/mach/ocmem.h
+++ b/arch/arm/mach-msm/include/mach/ocmem.h
@@ -16,6 +16,7 @@
#include <asm/page.h>
#include <linux/module.h>
#include <linux/notifier.h>
+#include <linux/err.h>
#define OCMEM_MIN_ALLOC SZ_64K
#define OCMEM_MIN_ALIGN SZ_64K
@@ -99,6 +100,7 @@
};
/* APIS */
+#ifdef CONFIG_MSM_OCMEM
/* Notification APIs */
struct ocmem_notifier *ocmem_notifier_register(int client_id,
struct notifier_block *nb);
@@ -151,4 +153,111 @@
struct ocmem_vectors *ocmem_get_vectors(int client_id,
struct ocmem_buf *buf);
+
+#else
+/* Notification APIs */
+static inline struct ocmem_notifier *ocmem_notifier_register
+ (int client_id, struct notifier_block *nb)
+{
+ return ERR_PTR(-ENODEV);
+}
+
+static inline int ocmem_notifier_unregister(struct ocmem_notifier *notif_hndl,
+ struct notifier_block *nb)
+{
+ return -ENODEV;
+}
+
+/* Obtain the maximum quota for the client */
+static inline unsigned long get_max_quota(int client_id)
+{
+ return 0;
+}
+
+/* Allocation APIs */
+static inline struct ocmem_buf *ocmem_allocate(int client_id,
+ unsigned long size)
+{
+ return ERR_PTR(-ENODEV);
+}
+
+static inline struct ocmem_buf *ocmem_allocate_nowait(int client_id,
+ unsigned long size)
+{
+ return ERR_PTR(-ENODEV);
+}
+
+static inline struct ocmem_buf *ocmem_allocate_nb(int client_id,
+ unsigned long size)
+{
+ return ERR_PTR(-ENODEV);
+}
+
+static inline struct ocmem_buf *ocmem_allocate_range(int client_id,
+ unsigned long min, unsigned long goal, unsigned long step)
+{
+ return ERR_PTR(-ENODEV);
+}
+
+/* Free APIs */
+static inline int ocmem_free(int client_id, struct ocmem_buf *buf)
+{
+ return -ENODEV;
+}
+
+/* Dynamic Resize APIs */
+static inline int ocmem_shrink(int client_id, struct ocmem_buf *buf,
+ unsigned long new_size)
+{
+ return -ENODEV;
+}
+
+/* Transfer APIs */
+static inline int ocmem_map(int client_id, struct ocmem_buf *buffer,
+ struct ocmem_map_list *list)
+{
+ return -ENODEV;
+}
+
+static inline int ocmem_unmap(int client_id, struct ocmem_buf *buffer,
+ struct ocmem_map_list *list)
+{
+ return -ENODEV;
+}
+
+static inline int ocmem_dump(int client_id, struct ocmem_buf *buffer,
+ unsigned long dst_phys_addr)
+{
+ return -ENODEV;
+}
+
+/* Priority Enforcement APIs */
+static inline int ocmem_evict(int client_id)
+{
+ return -ENODEV;
+}
+
+static inline int ocmem_restore(int client_id)
+{
+ return -ENODEV;
+}
+
+/* Power Control APIs */
+static inline int ocmem_set_power_state(int client_id,
+ struct ocmem_buf *buf, enum ocmem_power_state new_state)
+{
+ return -ENODEV;
+}
+
+static inline enum ocmem_power_state ocmem_get_power_state(int client_id,
+ struct ocmem_buf *buf)
+{
+ return -ENODEV;
+}
+static inline struct ocmem_vectors *ocmem_get_vectors(int client_id,
+ struct ocmem_buf *buf)
+{
+ return ERR_PTR(-ENODEV);
+}
+#endif
#endif
diff --git a/arch/arm/mach-msm/include/mach/rpm-8930.h b/arch/arm/mach-msm/include/mach/rpm-8930.h
index 4ac9192..bc1b918 100644
--- a/arch/arm/mach-msm/include/mach/rpm-8930.h
+++ b/arch/arm/mach-msm/include/mach/rpm-8930.h
@@ -219,182 +219,190 @@
MSM_RPM_8930_ID_MM_FABRIC_ARB_0 + 10,
/* PMIC 8038 */
- MSM_RPM_8930_ID_PM8038_S1_0 = 90,
- MSM_RPM_8930_ID_PM8038_S1_1 = 91,
- MSM_RPM_8930_ID_PM8038_S2_0 = 92,
- MSM_RPM_8930_ID_PM8038_S2_1 = 93,
- MSM_RPM_8930_ID_PM8038_S3_0 = 94,
- MSM_RPM_8930_ID_PM8038_S3_1 = 95,
- MSM_RPM_8930_ID_PM8038_S4_0 = 96,
- MSM_RPM_8930_ID_PM8038_S4_1 = 97,
- MSM_RPM_8930_ID_PM8038_S5_0 = 98,
- MSM_RPM_8930_ID_PM8038_S5_1 = 99,
- MSM_RPM_8930_ID_PM8038_S6_0 = 100,
- MSM_RPM_8930_ID_PM8038_S6_1 = 101,
- MSM_RPM_8930_ID_PM8038_L1_0 = 102,
- MSM_RPM_8930_ID_PM8038_L1_1 = 103,
- MSM_RPM_8930_ID_PM8038_L2_0 = 104,
- MSM_RPM_8930_ID_PM8038_L2_1 = 105,
- MSM_RPM_8930_ID_PM8038_L3_0 = 106,
- MSM_RPM_8930_ID_PM8038_L3_1 = 107,
- MSM_RPM_8930_ID_PM8038_L4_0 = 108,
- MSM_RPM_8930_ID_PM8038_L4_1 = 109,
- MSM_RPM_8930_ID_PM8038_L5_0 = 110,
- MSM_RPM_8930_ID_PM8038_L5_1 = 111,
- MSM_RPM_8930_ID_PM8038_L6_0 = 112,
- MSM_RPM_8930_ID_PM8038_L6_1 = 113,
- MSM_RPM_8930_ID_PM8038_L7_0 = 114,
- MSM_RPM_8930_ID_PM8038_L7_1 = 115,
- MSM_RPM_8930_ID_PM8038_L8_0 = 116,
- MSM_RPM_8930_ID_PM8038_L8_1 = 117,
- MSM_RPM_8930_ID_PM8038_L9_0 = 118,
- MSM_RPM_8930_ID_PM8038_L9_1 = 119,
- MSM_RPM_8930_ID_PM8038_L10_0 = 120,
- MSM_RPM_8930_ID_PM8038_L10_1 = 121,
- MSM_RPM_8930_ID_PM8038_L11_0 = 122,
- MSM_RPM_8930_ID_PM8038_L11_1 = 123,
- MSM_RPM_8930_ID_PM8038_L12_0 = 124,
- MSM_RPM_8930_ID_PM8038_L12_1 = 125,
- MSM_RPM_8930_ID_PM8038_L13_0 = 126,
- MSM_RPM_8930_ID_PM8038_L13_1 = 127,
- MSM_RPM_8930_ID_PM8038_L14_0 = 128,
- MSM_RPM_8930_ID_PM8038_L14_1 = 129,
- MSM_RPM_8930_ID_PM8038_L15_0 = 130,
- MSM_RPM_8930_ID_PM8038_L15_1 = 131,
- MSM_RPM_8930_ID_PM8038_L16_0 = 132,
- MSM_RPM_8930_ID_PM8038_L16_1 = 133,
- MSM_RPM_8930_ID_PM8038_L17_0 = 134,
- MSM_RPM_8930_ID_PM8038_L17_1 = 135,
- MSM_RPM_8930_ID_PM8038_L18_0 = 136,
- MSM_RPM_8930_ID_PM8038_L18_1 = 137,
- MSM_RPM_8930_ID_PM8038_L19_0 = 138,
- MSM_RPM_8930_ID_PM8038_L19_1 = 139,
- MSM_RPM_8930_ID_PM8038_L20_0 = 140,
- MSM_RPM_8930_ID_PM8038_L20_1 = 141,
- MSM_RPM_8930_ID_PM8038_L21_0 = 142,
- MSM_RPM_8930_ID_PM8038_L21_1 = 143,
- MSM_RPM_8930_ID_PM8038_L22_0 = 144,
- MSM_RPM_8930_ID_PM8038_L22_1 = 145,
- MSM_RPM_8930_ID_PM8038_L23_0 = 146,
- MSM_RPM_8930_ID_PM8038_L23_1 = 147,
- MSM_RPM_8930_ID_PM8038_L24_0 = 148,
- MSM_RPM_8930_ID_PM8038_L24_1 = 149,
- MSM_RPM_8930_ID_PM8038_L25_0 = 150,
- MSM_RPM_8930_ID_PM8038_L25_1 = 151,
- MSM_RPM_8930_ID_PM8038_L26_0 = 152,
- MSM_RPM_8930_ID_PM8038_L26_1 = 153,
- MSM_RPM_8930_ID_PM8038_L27_0 = 154,
- MSM_RPM_8930_ID_PM8038_L27_1 = 155,
- MSM_RPM_8930_ID_PM8038_CLK1_0 = 156,
- MSM_RPM_8930_ID_PM8038_CLK1_1 = 157,
- MSM_RPM_8930_ID_PM8038_CLK2_0 = 158,
- MSM_RPM_8930_ID_PM8038_CLK2_1 = 159,
- MSM_RPM_8930_ID_PM8038_LVS1 = 160,
- MSM_RPM_8930_ID_PM8038_LVS2 = 161,
+ MSM_RPM_8930_ID_PM8038_S1_0 = 90,
+ MSM_RPM_8930_ID_PM8038_S1_1 = 91,
+ MSM_RPM_8930_ID_PM8038_S2_0 = 92,
+ MSM_RPM_8930_ID_PM8038_S2_1 = 93,
+ MSM_RPM_8930_ID_PM8038_S3_0 = 94,
+ MSM_RPM_8930_ID_PM8038_S3_1 = 95,
+ MSM_RPM_8930_ID_PM8038_S4_0 = 96,
+ MSM_RPM_8930_ID_PM8038_S4_1 = 97,
+ MSM_RPM_8930_ID_PM8038_S5_0 = 98,
+ MSM_RPM_8930_ID_PM8038_S5_1 = 99,
+ MSM_RPM_8930_ID_PM8038_S6_0 = 100,
+ MSM_RPM_8930_ID_PM8038_S6_1 = 101,
+ MSM_RPM_8930_ID_PM8038_L1_0 = 102,
+ MSM_RPM_8930_ID_PM8038_L1_1 = 103,
+ MSM_RPM_8930_ID_PM8038_L2_0 = 104,
+ MSM_RPM_8930_ID_PM8038_L2_1 = 105,
+ MSM_RPM_8930_ID_PM8038_L3_0 = 106,
+ MSM_RPM_8930_ID_PM8038_L3_1 = 107,
+ MSM_RPM_8930_ID_PM8038_L4_0 = 108,
+ MSM_RPM_8930_ID_PM8038_L4_1 = 109,
+ MSM_RPM_8930_ID_PM8038_L5_0 = 110,
+ MSM_RPM_8930_ID_PM8038_L5_1 = 111,
+ MSM_RPM_8930_ID_PM8038_L6_0 = 112,
+ MSM_RPM_8930_ID_PM8038_L6_1 = 113,
+ MSM_RPM_8930_ID_PM8038_L7_0 = 114,
+ MSM_RPM_8930_ID_PM8038_L7_1 = 115,
+ MSM_RPM_8930_ID_PM8038_L8_0 = 116,
+ MSM_RPM_8930_ID_PM8038_L8_1 = 117,
+ MSM_RPM_8930_ID_PM8038_L9_0 = 118,
+ MSM_RPM_8930_ID_PM8038_L9_1 = 119,
+ MSM_RPM_8930_ID_PM8038_L10_0 = 120,
+ MSM_RPM_8930_ID_PM8038_L10_1 = 121,
+ MSM_RPM_8930_ID_PM8038_L11_0 = 122,
+ MSM_RPM_8930_ID_PM8038_L11_1 = 123,
+ MSM_RPM_8930_ID_PM8038_L12_0 = 124,
+ MSM_RPM_8930_ID_PM8038_L12_1 = 125,
+ MSM_RPM_8930_ID_PM8038_L13_0 = 126,
+ MSM_RPM_8930_ID_PM8038_L13_1 = 127,
+ MSM_RPM_8930_ID_PM8038_L14_0 = 128,
+ MSM_RPM_8930_ID_PM8038_L14_1 = 129,
+ MSM_RPM_8930_ID_PM8038_L15_0 = 130,
+ MSM_RPM_8930_ID_PM8038_L15_1 = 131,
+ MSM_RPM_8930_ID_PM8038_L16_0 = 132,
+ MSM_RPM_8930_ID_PM8038_L16_1 = 133,
+ MSM_RPM_8930_ID_PM8038_L17_0 = 134,
+ MSM_RPM_8930_ID_PM8038_L17_1 = 135,
+ MSM_RPM_8930_ID_PM8038_L18_0 = 136,
+ MSM_RPM_8930_ID_PM8038_L18_1 = 137,
+ MSM_RPM_8930_ID_PM8038_L19_0 = 138,
+ MSM_RPM_8930_ID_PM8038_L19_1 = 139,
+ MSM_RPM_8930_ID_PM8038_L20_0 = 140,
+ MSM_RPM_8930_ID_PM8038_L20_1 = 141,
+ MSM_RPM_8930_ID_PM8038_L21_0 = 142,
+ MSM_RPM_8930_ID_PM8038_L21_1 = 143,
+ MSM_RPM_8930_ID_PM8038_L22_0 = 144,
+ MSM_RPM_8930_ID_PM8038_L22_1 = 145,
+ MSM_RPM_8930_ID_PM8038_L23_0 = 146,
+ MSM_RPM_8930_ID_PM8038_L23_1 = 147,
+ MSM_RPM_8930_ID_PM8038_L24_0 = 148,
+ MSM_RPM_8930_ID_PM8038_L24_1 = 149,
+ MSM_RPM_8930_ID_PM8038_L25_0 = 150,
+ MSM_RPM_8930_ID_PM8038_L25_1 = 151,
+ MSM_RPM_8930_ID_PM8038_L26_0 = 152,
+ MSM_RPM_8930_ID_PM8038_L26_1 = 153,
+ MSM_RPM_8930_ID_PM8038_L27_0 = 154,
+ MSM_RPM_8930_ID_PM8038_L27_1 = 155,
+ MSM_RPM_8930_ID_PM8038_CLK1_0 = 156,
+ MSM_RPM_8930_ID_PM8038_CLK1_1 = 157,
+ MSM_RPM_8930_ID_PM8038_CLK2_0 = 158,
+ MSM_RPM_8930_ID_PM8038_CLK2_1 = 159,
+ MSM_RPM_8930_ID_PM8038_LVS1 = 160,
+ MSM_RPM_8930_ID_PM8038_LVS2 = 161,
+ MSM_RPM_8930_ID_PM8038_NCP_0 = 162,
+ MSM_RPM_8930_ID_PM8038_NCP_1 = 163,
+ MSM_RPM_8930_ID_PM8038_CXO_BUFFERS = 164,
+ MSM_RPM_8930_ID_PM8038_USB_OTG_SWITCH = 165,
+ MSM_RPM_8930_ID_PM8038_HDMI_SWITCH = 166,
+ MSM_RPM_8930_ID_PM8038_QDSS_CLK = 167,
+ MSM_RPM_8930_ID_PM8038_VOLTAGE_CORNER = 168,
+ MSM_RPM_8930_ID_PM8038_LAST = MSM_RPM_8930_ID_PM8038_VOLTAGE_CORNER,
/* PMIC 8917 */
- MSM_RPM_8930_ID_PM8917_S1_0 = 90,
- MSM_RPM_8930_ID_PM8917_S1_1 = 91,
- MSM_RPM_8930_ID_PM8917_S2_0 = 92,
- MSM_RPM_8930_ID_PM8917_S2_1 = 93,
- MSM_RPM_8930_ID_PM8917_S3_0 = 94,
- MSM_RPM_8930_ID_PM8917_S3_1 = 95,
- MSM_RPM_8930_ID_PM8917_S4_0 = 96,
- MSM_RPM_8930_ID_PM8917_S4_1 = 97,
- MSM_RPM_8930_ID_PM8917_S5_0 = 98,
- MSM_RPM_8930_ID_PM8917_S5_1 = 99,
- MSM_RPM_8930_ID_PM8917_S6_0 = 100,
- MSM_RPM_8930_ID_PM8917_S6_1 = 101,
- MSM_RPM_8930_ID_PM8917_S7_0 = 102,
- MSM_RPM_8930_ID_PM8917_S7_1 = 103,
- MSM_RPM_8930_ID_PM8917_S8_0 = 104,
- MSM_RPM_8930_ID_PM8917_S8_1 = 105,
- MSM_RPM_8930_ID_PM8917_L1_0 = 106,
- MSM_RPM_8930_ID_PM8917_L1_1 = 107,
- MSM_RPM_8930_ID_PM8917_L2_0 = 108,
- MSM_RPM_8930_ID_PM8917_L2_1 = 109,
- MSM_RPM_8930_ID_PM8917_L3_0 = 110,
- MSM_RPM_8930_ID_PM8917_L3_1 = 111,
- MSM_RPM_8930_ID_PM8917_L4_0 = 112,
- MSM_RPM_8930_ID_PM8917_L4_1 = 113,
- MSM_RPM_8930_ID_PM8917_L5_0 = 114,
- MSM_RPM_8930_ID_PM8917_L5_1 = 115,
- MSM_RPM_8930_ID_PM8917_L6_0 = 116,
- MSM_RPM_8930_ID_PM8917_L6_1 = 117,
- MSM_RPM_8930_ID_PM8917_L7_0 = 118,
- MSM_RPM_8930_ID_PM8917_L7_1 = 119,
- MSM_RPM_8930_ID_PM8917_L8_0 = 120,
- MSM_RPM_8930_ID_PM8917_L8_1 = 121,
- MSM_RPM_8930_ID_PM8917_L9_0 = 122,
- MSM_RPM_8930_ID_PM8917_L9_1 = 123,
- MSM_RPM_8930_ID_PM8917_L10_0 = 124,
- MSM_RPM_8930_ID_PM8917_L10_1 = 125,
- MSM_RPM_8930_ID_PM8917_L11_0 = 126,
- MSM_RPM_8930_ID_PM8917_L11_1 = 127,
- MSM_RPM_8930_ID_PM8917_L12_0 = 128,
- MSM_RPM_8930_ID_PM8917_L12_1 = 129,
- MSM_RPM_8930_ID_PM8917_L14_0 = 130,
- MSM_RPM_8930_ID_PM8917_L14_1 = 131,
- MSM_RPM_8930_ID_PM8917_L15_0 = 132,
- MSM_RPM_8930_ID_PM8917_L15_1 = 133,
- MSM_RPM_8930_ID_PM8917_L16_0 = 134,
- MSM_RPM_8930_ID_PM8917_L16_1 = 135,
- MSM_RPM_8930_ID_PM8917_L17_0 = 136,
- MSM_RPM_8930_ID_PM8917_L17_1 = 137,
- MSM_RPM_8930_ID_PM8917_L18_0 = 138,
- MSM_RPM_8930_ID_PM8917_L18_1 = 139,
- MSM_RPM_8930_ID_PM8917_L21_0 = 140,
- MSM_RPM_8930_ID_PM8917_L21_1 = 141,
- MSM_RPM_8930_ID_PM8917_L22_0 = 142,
- MSM_RPM_8930_ID_PM8917_L22_1 = 143,
- MSM_RPM_8930_ID_PM8917_L23_0 = 144,
- MSM_RPM_8930_ID_PM8917_L23_1 = 145,
- MSM_RPM_8930_ID_PM8917_L24_0 = 146,
- MSM_RPM_8930_ID_PM8917_L24_1 = 147,
- MSM_RPM_8930_ID_PM8917_L25_0 = 148,
- MSM_RPM_8930_ID_PM8917_L25_1 = 149,
- MSM_RPM_8930_ID_PM8917_L26_0 = 150,
- MSM_RPM_8930_ID_PM8917_L26_1 = 151,
- MSM_RPM_8930_ID_PM8917_L27_0 = 152,
- MSM_RPM_8930_ID_PM8917_L27_1 = 153,
- MSM_RPM_8930_ID_PM8917_L28_0 = 154,
- MSM_RPM_8930_ID_PM8917_L28_1 = 155,
- MSM_RPM_8930_ID_PM8917_L29_0 = 156,
- MSM_RPM_8930_ID_PM8917_L29_1 = 157,
- MSM_RPM_8930_ID_PM8917_L30_0 = 158,
- MSM_RPM_8930_ID_PM8917_L30_1 = 159,
- MSM_RPM_8930_ID_PM8917_L31_0 = 160,
- MSM_RPM_8930_ID_PM8917_L31_1 = 161,
- MSM_RPM_8930_ID_PM8917_L32_0 = 162,
- MSM_RPM_8930_ID_PM8917_L32_1 = 163,
- MSM_RPM_8930_ID_PM8917_L33_0 = 164,
- MSM_RPM_8930_ID_PM8917_L33_1 = 165,
- MSM_RPM_8930_ID_PM8917_L34_0 = 166,
- MSM_RPM_8930_ID_PM8917_L34_1 = 167,
- MSM_RPM_8930_ID_PM8917_L35_0 = 168,
- MSM_RPM_8930_ID_PM8917_L35_1 = 169,
- MSM_RPM_8930_ID_PM8917_L36_0 = 170,
- MSM_RPM_8930_ID_PM8917_L36_1 = 171,
- MSM_RPM_8930_ID_PM8917_CLK1_0 = 172,
- MSM_RPM_8930_ID_PM8917_CLK1_1 = 173,
- MSM_RPM_8930_ID_PM8917_CLK2_0 = 174,
- MSM_RPM_8930_ID_PM8917_CLK2_1 = 175,
- MSM_RPM_8930_ID_PM8917_LVS1 = 176,
- MSM_RPM_8930_ID_PM8917_LVS3 = 177,
- MSM_RPM_8930_ID_PM8917_LVS4 = 178,
- MSM_RPM_8930_ID_PM8917_LVS5 = 179,
- MSM_RPM_8930_ID_PM8917_LVS6 = 180,
- MSM_RPM_8930_ID_PM8917_LVS7 = 181,
+ MSM_RPM_8930_ID_PM8917_S1_0 = 90,
+ MSM_RPM_8930_ID_PM8917_S1_1 = 91,
+ MSM_RPM_8930_ID_PM8917_S2_0 = 92,
+ MSM_RPM_8930_ID_PM8917_S2_1 = 93,
+ MSM_RPM_8930_ID_PM8917_S3_0 = 94,
+ MSM_RPM_8930_ID_PM8917_S3_1 = 95,
+ MSM_RPM_8930_ID_PM8917_S4_0 = 96,
+ MSM_RPM_8930_ID_PM8917_S4_1 = 97,
+ MSM_RPM_8930_ID_PM8917_S5_0 = 98,
+ MSM_RPM_8930_ID_PM8917_S5_1 = 99,
+ MSM_RPM_8930_ID_PM8917_S6_0 = 100,
+ MSM_RPM_8930_ID_PM8917_S6_1 = 101,
+ MSM_RPM_8930_ID_PM8917_S7_0 = 102,
+ MSM_RPM_8930_ID_PM8917_S7_1 = 103,
+ MSM_RPM_8930_ID_PM8917_S8_0 = 104,
+ MSM_RPM_8930_ID_PM8917_S8_1 = 105,
+ MSM_RPM_8930_ID_PM8917_L1_0 = 106,
+ MSM_RPM_8930_ID_PM8917_L1_1 = 107,
+ MSM_RPM_8930_ID_PM8917_L2_0 = 108,
+ MSM_RPM_8930_ID_PM8917_L2_1 = 109,
+ MSM_RPM_8930_ID_PM8917_L3_0 = 110,
+ MSM_RPM_8930_ID_PM8917_L3_1 = 111,
+ MSM_RPM_8930_ID_PM8917_L4_0 = 112,
+ MSM_RPM_8930_ID_PM8917_L4_1 = 113,
+ MSM_RPM_8930_ID_PM8917_L5_0 = 114,
+ MSM_RPM_8930_ID_PM8917_L5_1 = 115,
+ MSM_RPM_8930_ID_PM8917_L6_0 = 116,
+ MSM_RPM_8930_ID_PM8917_L6_1 = 117,
+ MSM_RPM_8930_ID_PM8917_L7_0 = 118,
+ MSM_RPM_8930_ID_PM8917_L7_1 = 119,
+ MSM_RPM_8930_ID_PM8917_L8_0 = 120,
+ MSM_RPM_8930_ID_PM8917_L8_1 = 121,
+ MSM_RPM_8930_ID_PM8917_L9_0 = 122,
+ MSM_RPM_8930_ID_PM8917_L9_1 = 123,
+ MSM_RPM_8930_ID_PM8917_L10_0 = 124,
+ MSM_RPM_8930_ID_PM8917_L10_1 = 125,
+ MSM_RPM_8930_ID_PM8917_L11_0 = 126,
+ MSM_RPM_8930_ID_PM8917_L11_1 = 127,
+ MSM_RPM_8930_ID_PM8917_L12_0 = 128,
+ MSM_RPM_8930_ID_PM8917_L12_1 = 129,
+ MSM_RPM_8930_ID_PM8917_L14_0 = 130,
+ MSM_RPM_8930_ID_PM8917_L14_1 = 131,
+ MSM_RPM_8930_ID_PM8917_L15_0 = 132,
+ MSM_RPM_8930_ID_PM8917_L15_1 = 133,
+ MSM_RPM_8930_ID_PM8917_L16_0 = 134,
+ MSM_RPM_8930_ID_PM8917_L16_1 = 135,
+ MSM_RPM_8930_ID_PM8917_L17_0 = 136,
+ MSM_RPM_8930_ID_PM8917_L17_1 = 137,
+ MSM_RPM_8930_ID_PM8917_L18_0 = 138,
+ MSM_RPM_8930_ID_PM8917_L18_1 = 139,
+ MSM_RPM_8930_ID_PM8917_L21_0 = 140,
+ MSM_RPM_8930_ID_PM8917_L21_1 = 141,
+ MSM_RPM_8930_ID_PM8917_L22_0 = 142,
+ MSM_RPM_8930_ID_PM8917_L22_1 = 143,
+ MSM_RPM_8930_ID_PM8917_L23_0 = 144,
+ MSM_RPM_8930_ID_PM8917_L23_1 = 145,
+ MSM_RPM_8930_ID_PM8917_L24_0 = 146,
+ MSM_RPM_8930_ID_PM8917_L24_1 = 147,
+ MSM_RPM_8930_ID_PM8917_L25_0 = 148,
+ MSM_RPM_8930_ID_PM8917_L25_1 = 149,
+ MSM_RPM_8930_ID_PM8917_L26_0 = 150,
+ MSM_RPM_8930_ID_PM8917_L26_1 = 151,
+ MSM_RPM_8930_ID_PM8917_L27_0 = 152,
+ MSM_RPM_8930_ID_PM8917_L27_1 = 153,
+ MSM_RPM_8930_ID_PM8917_L28_0 = 154,
+ MSM_RPM_8930_ID_PM8917_L28_1 = 155,
+ MSM_RPM_8930_ID_PM8917_L29_0 = 156,
+ MSM_RPM_8930_ID_PM8917_L29_1 = 157,
+ MSM_RPM_8930_ID_PM8917_L30_0 = 158,
+ MSM_RPM_8930_ID_PM8917_L30_1 = 159,
+ MSM_RPM_8930_ID_PM8917_L31_0 = 160,
+ MSM_RPM_8930_ID_PM8917_L31_1 = 161,
+ MSM_RPM_8930_ID_PM8917_L32_0 = 162,
+ MSM_RPM_8930_ID_PM8917_L32_1 = 163,
+ MSM_RPM_8930_ID_PM8917_L33_0 = 164,
+ MSM_RPM_8930_ID_PM8917_L33_1 = 165,
+ MSM_RPM_8930_ID_PM8917_L34_0 = 166,
+ MSM_RPM_8930_ID_PM8917_L34_1 = 167,
+ MSM_RPM_8930_ID_PM8917_L35_0 = 168,
+ MSM_RPM_8930_ID_PM8917_L35_1 = 169,
+ MSM_RPM_8930_ID_PM8917_L36_0 = 170,
+ MSM_RPM_8930_ID_PM8917_L36_1 = 171,
+ MSM_RPM_8930_ID_PM8917_CLK1_0 = 172,
+ MSM_RPM_8930_ID_PM8917_CLK1_1 = 173,
+ MSM_RPM_8930_ID_PM8917_CLK2_0 = 174,
+ MSM_RPM_8930_ID_PM8917_CLK2_1 = 175,
+ MSM_RPM_8930_ID_PM8917_LVS1 = 176,
+ MSM_RPM_8930_ID_PM8917_LVS3 = 177,
+ MSM_RPM_8930_ID_PM8917_LVS4 = 178,
+ MSM_RPM_8930_ID_PM8917_LVS5 = 179,
+ MSM_RPM_8930_ID_PM8917_LVS6 = 180,
+ MSM_RPM_8930_ID_PM8917_LVS7 = 181,
+ MSM_RPM_8930_ID_PM8917_NCP_0 = 182,
+ MSM_RPM_8930_ID_PM8917_NCP_1 = 183,
+ MSM_RPM_8930_ID_PM8917_CXO_BUFFERS = 184,
+ MSM_RPM_8930_ID_PM8917_USB_OTG_SWITCH = 185,
+ MSM_RPM_8930_ID_PM8917_HDMI_SWITCH = 186,
+ MSM_RPM_8930_ID_PM8917_QDSS_CLK = 187,
+ MSM_RPM_8930_ID_PM8917_VOLTAGE_CORNER = 188,
- MSM_RPM_8930_ID_NCP_0 = 182,
- MSM_RPM_8930_ID_NCP_1 = 183,
- MSM_RPM_8930_ID_CXO_BUFFERS = 184,
- MSM_RPM_8930_ID_USB_OTG_SWITCH = 185,
- MSM_RPM_8930_ID_HDMI_SWITCH = 186,
- MSM_RPM_8930_ID_QDSS_CLK = 187,
- MSM_RPM_8930_ID_VOLTAGE_CORNER = 188,
-
- MSM_RPM_8930_ID_LAST = MSM_RPM_8930_ID_VOLTAGE_CORNER,
+ MSM_RPM_8930_ID_LAST = MSM_RPM_8930_ID_PM8917_VOLTAGE_CORNER,
+ MSM_RPM_8930_ID_PM8917_LAST = MSM_RPM_8930_ID_LAST,
};
/* RPM status ID enum */
diff --git a/arch/arm/mach-msm/include/mach/rpm.h b/arch/arm/mach-msm/include/mach/rpm.h
index 4ee1997..200a8cf 100644
--- a/arch/arm/mach-msm/include/mach/rpm.h
+++ b/arch/arm/mach-msm/include/mach/rpm.h
@@ -1086,6 +1086,14 @@
.count = c, \
}
+#define MSM_RPM_MAP_PMIC(_target, _pmic, _id, _select, _count) \
+ [MSM_RPM_ID_##_id] = \
+ {\
+ .id = MSM_RPM_##_target##_ID_PM##_pmic##_##_id, \
+ .sel = MSM_RPM_##_target##_SEL_##_select, \
+ .count = _count, \
+ }
+
#define MSM_RPM_STATUS_ID_VALID BIT(31)
#define MSM_RPM_STATUS_ID_MAP(t, i) \
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 8f1d197..fde43b0 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -37,6 +37,7 @@
#include "ipc_router.h"
#include "modem_notifier.h"
+#include "msm_ipc_router_security.h"
enum {
SMEM_LOG = 1U << 0,
@@ -114,6 +115,7 @@
struct msm_ipc_port_name name;
char pdev_name[32];
int next_pdev_id;
+ int synced_sec_rule;
struct list_head server_port_list;
};
@@ -133,6 +135,7 @@
wait_queue_head_t quota_wait;
uint32_t tx_quota_cnt;
struct mutex quota_lock;
+ void *sec_rule;
};
struct msm_ipc_router_xprt_info {
@@ -651,6 +654,7 @@
rport_ptr->port_id = port_id;
rport_ptr->node_id = node_id;
rport_ptr->restart_state = RESTART_NORMAL;
+ rport_ptr->sec_rule = NULL;
rport_ptr->tx_quota_cnt = 0;
init_waitqueue_head(&rport_ptr->quota_wait);
mutex_init(&rport_ptr->quota_lock);
@@ -770,6 +774,7 @@
}
server->name.service = service;
server->name.instance = instance;
+ server->synced_sec_rule = 0;
INIT_LIST_HEAD(&server->server_port_list);
list_add_tail(&server->list, &server_list[key]);
scnprintf(server->pdev_name, sizeof(server->pdev_name),
@@ -1312,6 +1317,95 @@
msm_ipc_cleanup_routing_table(xprt_info);
}
+/**
+ * sync_sec_rule() - Synchrnoize the security rule into the server structure
+ * @server: Server structure where the rule has to be synchronized.
+ * @rule: Security tule to be synchronized.
+ *
+ * This function is used to update the server structure with the security
+ * rule configured for the <service:instance> corresponding to that server.
+ */
+static void sync_sec_rule(struct msm_ipc_server *server, void *rule)
+{
+ struct msm_ipc_server_port *server_port;
+ struct msm_ipc_router_remote_port *rport_ptr = NULL;
+
+ list_for_each_entry(server_port, &server->server_port_list, list) {
+ rport_ptr = msm_ipc_router_lookup_remote_port(
+ server_port->server_addr.node_id,
+ server_port->server_addr.port_id);
+ if (!rport_ptr)
+ continue;
+ rport_ptr->sec_rule = rule;
+ }
+ server->synced_sec_rule = 1;
+}
+
+/**
+ * msm_ipc_sync_sec_rule() - Sync the security rule to the service
+ * @service: Service for which the rule has to be synchronized.
+ * @instance: Instance for which the rule has to be synchronized.
+ * @rule: Security rule to be synchronized.
+ *
+ * This function is used to syncrhonize the security rule with the server
+ * hash table, if the user-space script configures the rule after the service
+ * has come up. This function is used to synchronize the security rule to a
+ * specific service and optionally a specific instance.
+ */
+void msm_ipc_sync_sec_rule(uint32_t service, uint32_t instance, void *rule)
+{
+ int key = (service & (SRV_HASH_SIZE - 1));
+ struct msm_ipc_server *server;
+
+ mutex_lock(&server_list_lock);
+ list_for_each_entry(server, &server_list[key], list) {
+ if (server->name.service != service)
+ continue;
+
+ if (server->name.instance != instance &&
+ instance != ALL_INSTANCE)
+ continue;
+
+ /*
+ * If the rule applies to all instances and if the specific
+ * instance of a service has a rule synchronized already,
+ * do not apply the rule for that specific instance.
+ */
+ if (instance == ALL_INSTANCE && server->synced_sec_rule)
+ continue;
+
+ sync_sec_rule(server, rule);
+ }
+ mutex_unlock(&server_list_lock);
+}
+
+/**
+ * msm_ipc_sync_default_sec_rule() - Default security rule to all services
+ * @rule: Security rule to be synchronized.
+ *
+ * This function is used to syncrhonize the security rule with the server
+ * hash table, if the user-space script configures the rule after the service
+ * has come up. This function is used to synchronize the security rule that
+ * applies to all services, if the concerned service do not have any rule
+ * defined.
+ */
+void msm_ipc_sync_default_sec_rule(void *rule)
+{
+ int key;
+ struct msm_ipc_server *server;
+
+ mutex_lock(&server_list_lock);
+ for (key = 0; key < SRV_HASH_SIZE; key++) {
+ list_for_each_entry(server, &server_list[key], list) {
+ if (server->synced_sec_rule)
+ continue;
+
+ sync_sec_rule(server, rule);
+ }
+ }
+ mutex_unlock(&server_list_lock);
+}
+
static int process_hello_msg(struct msm_ipc_router_xprt_info *xprt_info,
struct rr_header *hdr)
{
@@ -1491,6 +1585,9 @@
if (!rport_ptr)
pr_err("%s: Remote port create "
"failed\n", __func__);
+ rport_ptr->sec_rule =
+ msm_ipc_get_security_rule(
+ msg->srv.service, msg->srv.instance);
}
wake_up(&newserver_wait);
}
@@ -1989,6 +2086,15 @@
return -ENOMEM;
}
+ if (src->check_send_permissions) {
+ ret = src->check_send_permissions(rport_ptr->sec_rule);
+ if (ret <= 0) {
+ pr_err("%s: permission failure for %s\n",
+ __func__, current->comm);
+ return -EPERM;
+ }
+ }
+
pkt = create_pkt(data);
if (!pkt) {
pr_err("%s: Pkt creation failed\n", __func__);
@@ -2781,6 +2887,10 @@
if (ret < 0)
pr_err("%s: Init sockets failed\n", __func__);
+ ret = msm_ipc_router_security_init();
+ if (ret < 0)
+ pr_err("%s: Security Init failed\n", __func__);
+
complete_all(&msm_ipc_local_router_up);
return ret;
}
diff --git a/arch/arm/mach-msm/ipc_router.h b/arch/arm/mach-msm/ipc_router.h
index 39038f2..39bde30 100644
--- a/arch/arm/mach-msm/ipc_router.h
+++ b/arch/arm/mach-msm/ipc_router.h
@@ -52,6 +52,9 @@
#define ALIGN_SIZE(x) ((4 - ((x) & 3)) & 3)
+#define ALL_SERVICE 0xFFFFFFFF
+#define ALL_INSTANCE 0xFFFFFFFF
+
union rr_control_msg {
uint32_t cmd;
struct {
@@ -139,6 +142,10 @@
int msm_ipc_router_init_sockets(void);
void msm_ipc_router_exit_sockets(void);
+void msm_ipc_sync_sec_rule(uint32_t service, uint32_t instance, void *rule);
+
+void msm_ipc_sync_default_sec_rule(void *rule);
+
#if defined CONFIG_MSM_IPC_ROUTER_SMD_XPRT
extern void *msm_ipc_load_default_node(void);
diff --git a/arch/arm/mach-msm/ipc_socket.c b/arch/arm/mach-msm/ipc_socket.c
index 3a6abbd..5d21fa5 100644
--- a/arch/arm/mach-msm/ipc_socket.c
+++ b/arch/arm/mach-msm/ipc_socket.c
@@ -21,10 +21,6 @@
#include <linux/gfp.h>
#include <linux/msm_ipc.h>
-#ifdef CONFIG_ANDROID_PARANOID_NETWORK
-#include <linux/android_aid.h>
-#endif
-
#include <asm/string.h>
#include <asm/atomic.h>
@@ -33,6 +29,7 @@
#include <mach/msm_ipc_router.h>
#include "ipc_router.h"
+#include "msm_ipc_router_security.h"
#define msm_ipc_sk(sk) ((struct msm_ipc_sock *)(sk))
#define msm_ipc_sk_port(sk) ((struct msm_ipc_port *)(msm_ipc_sk(sk)->port))
@@ -41,21 +38,6 @@
static struct proto msm_ipc_proto;
static const struct proto_ops msm_ipc_proto_ops;
-#ifdef CONFIG_ANDROID_PARANOID_NETWORK
-static inline int check_permissions(void)
-{
- int rc = 0;
- if (!current_euid() || in_egroup_p(AID_NET_RAW))
- rc = 1;
- return rc;
-}
-# else
-static inline int check_permissions(void)
-{
- return 1;
-}
-#endif
-
static struct sk_buff_head *msm_ipc_router_build_msg(unsigned int num_sect,
struct iovec const *msg_sect,
size_t total_len)
@@ -193,7 +175,8 @@
void *pil;
if (!check_permissions()) {
- pr_err("%s: Do not have permissions\n", __func__);
+ pr_err("%s: %s Do not have permissions\n",
+ __func__, current->comm);
return -EPERM;
}
@@ -223,6 +206,7 @@
return -ENOMEM;
}
+ port_ptr->check_send_permissions = msm_ipc_check_send_permissions;
sock->ops = &msm_ipc_proto_ops;
sock_init_data(sock, sk);
sk->sk_rcvtimeo = DEFAULT_RCV_TIMEO;
@@ -445,6 +429,10 @@
ret = msm_ipc_router_bind_control_port(port_ptr);
break;
+ case IPC_ROUTER_IOCTL_CONFIG_SEC_RULES:
+ ret = msm_ipc_config_sec_rules((void *)arg);
+ break;
+
default:
ret = -EINVAL;
}
diff --git a/arch/arm/mach-msm/mdm_common.c b/arch/arm/mach-msm/mdm_common.c
index b81832e..aef4ac9 100644
--- a/arch/arm/mach-msm/mdm_common.c
+++ b/arch/arm/mach-msm/mdm_common.c
@@ -300,6 +300,7 @@
if (ret)
pr_err("%s: Graceful shutdown of the external modem failed, ret = %d\n",
__func__, ret);
+ put_user(ret, (unsigned long __user *) arg);
break;
default:
pr_err("%s: invalid ioctl cmd = %d\n", __func__, _IOC_NR(cmd));
diff --git a/arch/arm/mach-msm/msm_dcvs.c b/arch/arm/mach-msm/msm_dcvs.c
index 41afd24..3b9656e 100644
--- a/arch/arm/mach-msm/msm_dcvs.c
+++ b/arch/arm/mach-msm/msm_dcvs.c
@@ -65,6 +65,7 @@
struct kobj_attribute thermal_poll_ms;
struct kobj_attribute freq_tbl;
+ struct kobj_attribute offset_tbl;
struct attribute_group attrib_group;
};
@@ -295,9 +296,14 @@
continue;
if (gpu->pending_freq != STOP_FREQ_CHANGE &&
- gpu->set_floor_frequency)
+ gpu->set_floor_frequency) {
gpu->set_floor_frequency(gpu->type_core_num,
gpu_floor_freq);
+ /* TZ will know about a freq change (if any)
+ * at next idle exit. */
+ gpu->actual_freq =
+ gpu->get_frequency(gpu->type_core_num);
+ }
}
mutex_unlock(&gpu_floor_mutex);
@@ -715,6 +721,77 @@
DCVS_PARAM_STORE(thermal_poll_ms)
+static ssize_t msm_dcvs_attr_offset_tbl_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ struct msm_dcvs_freq_entry *freq_tbl;
+ char *buf_idx = buf;
+ int i, len;
+ struct dcvs_core *core = CORE_FROM_ATTRIBS(attr, offset_tbl);
+
+ freq_tbl = core->info->freq_tbl;
+ *buf_idx = '\0';
+
+ /* limit the number of frequencies we will print into
+ * the PAGE_SIZE sysfs show buffer. */
+ if (core->info->power_param.num_freq > 64)
+ return 0;
+
+ for (i = 0; i < core->info->power_param.num_freq; i++) {
+ len = snprintf(buf_idx, 30, "%7d %7d %7d\n",
+ freq_tbl[i].freq,
+ freq_tbl[i].active_energy_offset,
+ freq_tbl[i].leakage_energy_offset);
+ /* buf_idx always points at terminating null */
+ buf_idx += len;
+ }
+ return buf_idx - buf;
+}
+
+static ssize_t msm_dcvs_attr_offset_tbl_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct msm_dcvs_freq_entry *freq_tbl;
+ uint32_t freq, active_energy_offset, leakage_energy_offset;
+ int i, ret;
+ struct dcvs_core *core = CORE_FROM_ATTRIBS(attr, offset_tbl);
+
+ freq_tbl = core->info->freq_tbl;
+
+ ret = sscanf(buf, "%u %u %u",
+ &freq, &active_energy_offset, &leakage_energy_offset);
+ if (ret != 3) {
+ __err("Invalid input %s for offset_tbl\n", buf);
+ return count;
+ }
+
+ for (i = 0; i < core->info->power_param.num_freq; i++)
+ if (freq_tbl[i].freq == freq) {
+ freq_tbl[i].active_energy_offset =
+ active_energy_offset;
+ freq_tbl[i].leakage_energy_offset =
+ leakage_energy_offset;
+ break;
+ }
+
+ if (i >= core->info->power_param.num_freq) {
+ __err("Invalid frequency for offset_tbl: %d\n", freq);
+ return count;
+ }
+
+ ret = msm_dcvs_scm_set_power_params(core->dcvs_core_id,
+ &core->info->power_param,
+ &core->info->freq_tbl[0],
+ &core->coeffs);
+ if (ret)
+ __err("Error %d in updating active/leakage energy\n", ret);
+
+ return count;
+}
+
static ssize_t msm_dcvs_attr_freq_tbl_show(struct kobject *kobj,
struct kobj_attribute *attr,
char *buf)
@@ -791,7 +868,7 @@
{
int ret = 0;
struct kobject *core_kobj = NULL;
- const int attr_count = 25;
+ const int attr_count = 26;
BUG_ON(!cores_kobj);
@@ -830,8 +907,9 @@
DCVS_RW_ATTRIB(22, thermal_poll_ms);
DCVS_RW_ATTRIB(23, freq_tbl);
+ DCVS_RW_ATTRIB(24, offset_tbl);
- core->attrib.attrib_group.attrs[24] = NULL;
+ core->attrib.attrib_group.attrs[25] = NULL;
core_kobj = kobject_create_and_add(core->core_name, cores_kobj);
if (!core_kobj) {
@@ -919,27 +997,6 @@
num_cpu_freqs++;
}
-static void update_cpu_dcvs_params(struct msm_dcvs_core_info *info)
-{
- int i;
-
- BUG_ON(num_cpu_freqs == 0);
-
- info->freq_tbl = cpu_freq_tbl;
- info->power_param.num_freq = num_cpu_freqs;
-
- if (!dcvs_pdata || dcvs_pdata->num_sync_rules == 0)
- return;
-
- /* the first sync rule shows what the turbo frequencies are -
- * these frequencies need energy offsets set */
- for (i = 0; i < DCVS_MAX_NUM_FREQS && cpu_freq_tbl[i].freq != 0; i++)
- if (cpu_freq_tbl[i].freq > dcvs_pdata->sync_rules[0].cpu_khz) {
- cpu_freq_tbl[i].active_energy_offset = 100;
- cpu_freq_tbl[i].leakage_energy_offset = 100;
- }
-}
-
int msm_dcvs_register_core(
enum msm_dcvs_core_type type,
int type_core_num,
@@ -975,8 +1032,11 @@
core->set_floor_frequency = set_floor_frequency;
core->info = info;
- if (type == MSM_DCVS_CORE_TYPE_CPU)
- update_cpu_dcvs_params(info);
+ if (type == MSM_DCVS_CORE_TYPE_CPU) {
+ BUG_ON(num_cpu_freqs == 0);
+ info->freq_tbl = cpu_freq_tbl;
+ info->power_param.num_freq = num_cpu_freqs;
+ }
memcpy(&core->algo_param, &info->algo_param,
sizeof(struct msm_dcvs_algo_param));
diff --git a/arch/arm/mach-msm/msm_ipc_router_security.c b/arch/arm/mach-msm/msm_ipc_router_security.c
new file mode 100644
index 0000000..27cf524
--- /dev/null
+++ b/arch/arm/mach-msm/msm_ipc_router_security.c
@@ -0,0 +1,271 @@
+/* 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/module.h>
+#include <linux/types.h>
+#include <linux/net.h>
+#include <linux/socket.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/poll.h>
+#include <linux/fcntl.h>
+#include <linux/gfp.h>
+#include <linux/uaccess.h>
+#include <linux/kernel.h>
+#include <linux/msm_ipc.h>
+
+#include <asm/uaccess.h>
+
+#include <net/sock.h>
+#include "ipc_router.h"
+#include "msm_ipc_router_security.h"
+
+#define SEC_RULES_HASH_SZ 32
+struct security_rule {
+ struct list_head list;
+ uint32_t service_id;
+ uint32_t instance_id;
+ unsigned reserved;
+ int num_group_info;
+ int *group_id;
+};
+
+static DEFINE_MUTEX(security_rules_lock);
+static struct list_head security_rules[SEC_RULES_HASH_SZ];
+
+/**
+ * check_permisions() - Check whether the process has permissions to
+ * create an interface handle with IPC Router
+ *
+ * @return: true if the process has permissions, else false.
+ */
+int check_permissions(void)
+{
+ int rc = 0;
+ if (!current_euid() || in_egroup_p(AID_NET_RAW))
+ rc = 1;
+ return rc;
+}
+EXPORT_SYMBOL(check_permissions);
+
+/**
+ * msm_ipc_config_sec_rules() - Add a security rule to the database
+ * @arg: Pointer to the buffer containing the rule.
+ *
+ * @return: 0 if successfully added, < 0 for error.
+ *
+ * A security rule is defined using <Service_ID: Group_ID> tuple. The rule
+ * implies that a user-space process in order to send a QMI message to
+ * service Service_ID should belong to the Linux group Group_ID.
+ */
+int msm_ipc_config_sec_rules(void *arg)
+{
+ struct config_sec_rules_args sec_rules_arg;
+ struct security_rule *rule, *temp_rule;
+ int key;
+ int ret;
+
+ if (current_euid())
+ return -EPERM;
+
+ ret = copy_from_user(&sec_rules_arg, (void *)arg,
+ sizeof(sec_rules_arg));
+ if (ret)
+ return -EFAULT;
+
+ if (sec_rules_arg.num_group_info <= 0)
+ return -EINVAL;
+
+ rule = kzalloc(sizeof(struct security_rule), GFP_KERNEL);
+ if (!rule) {
+ pr_err("%s: security_rule alloc failed\n", __func__);
+ return -ENOMEM;
+ }
+
+ rule->group_id = kzalloc((sec_rules_arg.num_group_info * sizeof(int)),
+ GFP_KERNEL);
+ if (!rule->group_id) {
+ pr_err("%s: group_id alloc failed\n", __func__);
+ kfree(rule);
+ return -ENOMEM;
+ }
+
+ rule->service_id = sec_rules_arg.service_id;
+ rule->instance_id = sec_rules_arg.instance_id;
+ rule->reserved = sec_rules_arg.reserved;
+ rule->num_group_info = sec_rules_arg.num_group_info;
+ ret = copy_from_user(rule->group_id,
+ ((void *)(arg + sizeof(sec_rules_arg))),
+ (rule->num_group_info * sizeof(uint32_t)));
+ if (ret) {
+ kfree(rule->group_id);
+ kfree(rule);
+ return -EFAULT;
+ }
+
+ key = rule->service_id & (SEC_RULES_HASH_SZ - 1);
+ mutex_lock(&security_rules_lock);
+ if (rule->service_id == ALL_SERVICE) {
+ temp_rule = list_first_entry(&security_rules[key],
+ struct security_rule, list);
+ list_del(&temp_rule->list);
+ kfree(temp_rule->group_id);
+ kfree(temp_rule);
+ }
+ list_add_tail(&rule->list, &security_rules[key]);
+ mutex_unlock(&security_rules_lock);
+
+ if (rule->service_id == ALL_SERVICE)
+ msm_ipc_sync_default_sec_rule((void *)rule);
+ else
+ msm_ipc_sync_sec_rule(rule->service_id, rule->instance_id,
+ (void *)rule);
+
+ return 0;
+}
+EXPORT_SYMBOL(msm_ipc_config_sec_rules);
+
+/**
+ * msm_ipc_add_default_rule() - Add default security rule
+ *
+ * @return: 0 on success, < 0 on error/
+ *
+ * This function is used to ensure the basic security, if there is no
+ * security rule defined for a service. It can be overwritten by the
+ * default security rule from user-space script.
+ */
+static int msm_ipc_add_default_rule(void)
+{
+ struct security_rule *rule;
+ int key;
+
+ rule = kzalloc(sizeof(struct security_rule), GFP_KERNEL);
+ if (!rule) {
+ pr_err("%s: security_rule alloc failed\n", __func__);
+ return -ENOMEM;
+ }
+
+ rule->group_id = kzalloc(sizeof(int), GFP_KERNEL);
+ if (!rule->group_id) {
+ pr_err("%s: group_id alloc failed\n", __func__);
+ kfree(rule);
+ return -ENOMEM;
+ }
+
+ rule->service_id = ALL_SERVICE;
+ rule->instance_id = ALL_INSTANCE;
+ rule->num_group_info = 1;
+ *(rule->group_id) = AID_NET_RAW;
+ mutex_lock(&security_rules_lock);
+ key = (ALL_SERVICE & (SEC_RULES_HASH_SZ - 1));
+ list_add_tail(&rule->list, &security_rules[key]);
+ mutex_unlock(&security_rules_lock);
+ return 0;
+}
+
+/**
+ * msm_ipc_get_security_rule() - Get the security rule corresponding to a
+ * service
+ * @service_id: Service ID for which the rule has to be got.
+ * @instance_id: Instance ID for which the rule has to be got.
+ *
+ * @return: Returns the rule info on success, NULL on error.
+ *
+ * This function is used when the service comes up and gets registered with
+ * the IPC Router.
+ */
+void *msm_ipc_get_security_rule(uint32_t service_id, uint32_t instance_id)
+{
+ int key;
+ struct security_rule *rule;
+
+ key = (service_id & (SEC_RULES_HASH_SZ - 1));
+ mutex_lock(&security_rules_lock);
+ /* Return the rule for a specific <service:instance>, if found. */
+ list_for_each_entry(rule, &security_rules[key], list) {
+ if ((rule->service_id == service_id) &&
+ (rule->instance_id == instance_id)) {
+ mutex_unlock(&security_rules_lock);
+ return (void *)rule;
+ }
+ }
+
+ /* Return the rule for a specific service, if found. */
+ list_for_each_entry(rule, &security_rules[key], list) {
+ if ((rule->service_id == service_id) &&
+ (rule->instance_id == ALL_INSTANCE)) {
+ mutex_unlock(&security_rules_lock);
+ return (void *)rule;
+ }
+ }
+
+ /* Return the default rule, if no rule defined for a service. */
+ key = (ALL_SERVICE & (SEC_RULES_HASH_SZ - 1));
+ list_for_each_entry(rule, &security_rules[key], list) {
+ if ((rule->service_id == ALL_SERVICE) &&
+ (rule->instance_id == ALL_INSTANCE)) {
+ mutex_unlock(&security_rules_lock);
+ return (void *)rule;
+ }
+ }
+ return NULL;
+}
+EXPORT_SYMBOL(msm_ipc_get_security_rule);
+
+/**
+ * msm_ipc_check_send_permissions() - Check if the sendng process has
+ * permissions specified as per the rule
+ * @data: Security rule to be checked.
+ *
+ * @return: true if the process has permissions, else false.
+ *
+ * This function is used to check if the current executing process has
+ * permissions to send message to the remote entity. The security rule
+ * corresponding to the remote entity is specified by "data" parameter
+ */
+int msm_ipc_check_send_permissions(void *data)
+{
+ int i;
+ struct security_rule *rule = (struct security_rule *)data;
+
+ /* Source/Sender is Root user */
+ if (!current_euid())
+ return 1;
+
+ /* Destination has no rules defined, possibly a client. */
+ if (!rule)
+ return 1;
+
+ for (i = 0; i < rule->num_group_info; i++) {
+ if (in_egroup_p(rule->group_id[i]))
+ return 1;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(msm_ipc_check_send_permissions);
+
+/**
+ * msm_ipc_router_security_init() - Initialize the security rule database
+ *
+ * @return: 0 if successful, < 0 for error.
+ */
+int msm_ipc_router_security_init(void)
+{
+ int i;
+
+ for (i = 0; i < SEC_RULES_HASH_SZ; i++)
+ INIT_LIST_HEAD(&security_rules[i]);
+
+ msm_ipc_add_default_rule();
+ return 0;
+}
+EXPORT_SYMBOL(msm_ipc_router_security_init);
diff --git a/arch/arm/mach-msm/msm_ipc_router_security.h b/arch/arm/mach-msm/msm_ipc_router_security.h
new file mode 100644
index 0000000..8701343
--- /dev/null
+++ b/arch/arm/mach-msm/msm_ipc_router_security.h
@@ -0,0 +1,104 @@
+/* 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 _MSM_IPC_ROUTER_SECURITY_H
+#define _MSM_IPC_ROUTER_SECURITY_H
+
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/errno.h>
+
+#ifdef CONFIG_MSM_IPC_ROUTER_SECURITY
+#include <linux/android_aid.h>
+
+/**
+ * check_permisions() - Check whether the process has permissions to
+ * create an interface handle with IPC Router
+ *
+ * @return: true if the process has permissions, else false.
+ */
+int check_permissions(void);
+
+/**
+ * msm_ipc_config_sec_rules() - Add a security rule to the database
+ * @arg: Pointer to the buffer containing the rule.
+ *
+ * @return: 0 if successfully added, < 0 for error.
+ *
+ * A security rule is defined using <Service_ID: Group_ID> tuple. The rule
+ * implies that a user-space process in order to send a QMI message to
+ * service Service_ID should belong to the Linux group Group_ID.
+ */
+int msm_ipc_config_sec_rules(void *arg);
+
+/**
+ * msm_ipc_get_security_rule() - Get the security rule corresponding to a
+ * service
+ * @service_id: Service ID for which the rule has to be got.
+ * @instance_id: Instance ID for which the rule has to be got.
+ *
+ * @return: Returns the rule info on success, NULL on error.
+ *
+ * This function is used when the service comes up and gets registered with
+ * the IPC Router.
+ */
+void *msm_ipc_get_security_rule(uint32_t service_id, uint32_t instance_id);
+
+/**
+ * msm_ipc_check_send_permissions() - Check if the sendng process has
+ * permissions specified as per the rule
+ * @data: Security rule to be checked.
+ *
+ * @return: true if the process has permissions, else false.
+ *
+ * This function is used to check if the current executing process has
+ * permissions to send message to the remote entity. The security rule
+ * corresponding to the remote entity is specified by "data" parameter
+ */
+int msm_ipc_check_send_permissions(void *data);
+
+/**
+ * msm_ipc_router_security_init() - Initialize the security rule database
+ *
+ * @return: 0 if successful, < 0 for error.
+ */
+int msm_ipc_router_security_init(void);
+
+#else
+
+static inline int check_permissions(void)
+{
+ return 1;
+}
+
+static inline int msm_ipc_config_sec_rules(void *arg)
+{
+ return -ENODEV;
+}
+
+static inline void *msm_ipc_get_security_rule(uint32_t service_id,
+ uint32_t instance_id)
+{
+ return NULL;
+}
+
+static inline int msm_ipc_check_send_permissions(void *data)
+{
+ return 1;
+}
+
+static inline int msm_ipc_router_security_init(void)
+{
+ return 0;
+}
+#endif
+#endif
diff --git a/arch/arm/mach-msm/msm_mpdecision.c b/arch/arm/mach-msm/msm_mpdecision.c
index 94b546a..910804b 100644
--- a/arch/arm/mach-msm/msm_mpdecision.c
+++ b/arch/arm/mach-msm/msm_mpdecision.c
@@ -360,6 +360,7 @@
int cpu;
while (1) {
+ msm_dcvs_update_algo_params();
wait_event(msm_mpd.wait_hpq, *event || kthread_should_stop());
if (kthread_should_stop())
break;
@@ -392,7 +393,6 @@
}
msm_mpd.hpupdate = HPUPDATE_WAITING;
msm_dcvs_apply_gpu_floor(0);
- msm_dcvs_update_algo_params();
}
return 0;
diff --git a/arch/arm/mach-msm/peripheral-loader.c b/arch/arm/mach-msm/peripheral-loader.c
index 65e05a9..e3a3563 100644
--- a/arch/arm/mach-msm/peripheral-loader.c
+++ b/arch/arm/mach-msm/peripheral-loader.c
@@ -382,6 +382,7 @@
if (priv->region)
ion_free(ion, priv->region);
+ priv->region = NULL;
list_for_each_entry_safe(p, tmp, &priv->segs, list) {
list_del(&p->list);
kfree(p);
diff --git a/arch/arm/mach-msm/pil-pronto.c b/arch/arm/mach-msm/pil-pronto.c
index 6e8d127..162a7f7 100644
--- a/arch/arm/mach-msm/pil-pronto.c
+++ b/arch/arm/mach-msm/pil-pronto.c
@@ -229,6 +229,30 @@
.proxy_unvote = pil_pronto_remove_proxy_vote,
};
+static int pil_pronto_init_image_trusted(struct pil_desc *pil,
+ const u8 *metadata, size_t size)
+{
+ return pas_init_image(PAS_WCNSS, metadata, size);
+}
+
+static int pil_pronto_reset_trusted(struct pil_desc *pil)
+{
+ return pas_auth_and_reset(PAS_WCNSS);
+}
+
+static int pil_pronto_shutdown_trusted(struct pil_desc *pil)
+{
+ return pas_shutdown(PAS_WCNSS);
+}
+
+static struct pil_reset_ops pil_pronto_ops_trusted = {
+ .init_image = pil_pronto_init_image_trusted,
+ .auth_and_reset = pil_pronto_reset_trusted,
+ .shutdown = pil_pronto_shutdown_trusted,
+ .proxy_vote = pil_pronto_make_proxy_vote,
+ .proxy_unvote = pil_pronto_remove_proxy_vote,
+};
+
#define subsys_to_drv(d) container_of(d, struct pronto_data, subsys_desc)
static int pronto_start(const struct subsys_desc *desc)
@@ -418,9 +442,13 @@
desc->owner = THIS_MODULE;
desc->proxy_timeout = 10000;
- /* TODO: need to add secure boot when the support is available */
- desc->ops = &pil_pronto_ops;
- dev_info(&pdev->dev, "using non-secure boot\n");
+ if (pas_supported(PAS_WCNSS) > 0) {
+ desc->ops = &pil_pronto_ops_trusted;
+ dev_info(&pdev->dev, "using secure boot\n");
+ } else {
+ desc->ops = &pil_pronto_ops;
+ dev_info(&pdev->dev, "using non-secure boot\n");
+ }
drv->vreg = devm_regulator_get(&pdev->dev, "vdd_pronto_pll");
if (IS_ERR(drv->vreg)) {
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
index 07cbe19..b8309e5 100644
--- a/arch/arm/mach-msm/pil-q6v5-mss.c
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -56,6 +56,9 @@
#define RMB_PMI_CODE_START 0x14
#define RMB_PMI_CODE_LENGTH 0x18
+#define VDD_MSS_UV 1050000
+#define MAX_VDD_MX_UV 1050000
+
#define PROXY_TIMEOUT_MS 10000
#define POLL_INTERVAL_US 50
@@ -99,7 +102,7 @@
ret = regulator_enable(drv->vreg);
if (ret)
- dev_err(dev, "Failed to enable regulator.\n");
+ dev_err(dev, "Failed to enable modem regulator.\n");
return ret;
}
@@ -264,9 +267,44 @@
return ret;
}
+static int pil_q6v5_mss_make_proxy_votes(struct pil_desc *pil)
+{
+ int ret;
+ struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
+
+ ret = regulator_set_voltage(drv->vreg_mx, VDD_MSS_UV, MAX_VDD_MX_UV);
+ if (ret) {
+ dev_err(pil->dev, "Failed to request vreg_mx voltage\n");
+ return ret;
+ }
+
+ ret = regulator_enable(drv->vreg_mx);
+ if (ret) {
+ dev_err(pil->dev, "Failed to enable vreg_mx\n");
+ regulator_set_voltage(drv->vreg_mx, 0, MAX_VDD_MX_UV);
+ return ret;
+ }
+
+ ret = pil_q6v5_make_proxy_votes(pil);
+ if (ret) {
+ regulator_disable(drv->vreg_mx);
+ regulator_set_voltage(drv->vreg_mx, 0, MAX_VDD_MX_UV);
+ }
+
+ return ret;
+}
+
+static void pil_q6v5_mss_remove_proxy_votes(struct pil_desc *pil)
+{
+ struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
+ pil_q6v5_remove_proxy_votes(pil);
+ regulator_disable(drv->vreg_mx);
+ regulator_set_voltage(drv->vreg_mx, 0, MAX_VDD_MX_UV);
+}
+
static struct pil_reset_ops pil_mss_ops = {
- .proxy_vote = pil_q6v5_make_proxy_votes,
- .proxy_unvote = pil_q6v5_remove_proxy_votes,
+ .proxy_vote = pil_q6v5_mss_make_proxy_votes,
+ .proxy_unvote = pil_q6v5_mss_remove_proxy_votes,
.auth_and_reset = pil_mss_reset,
.shutdown = pil_mss_shutdown,
};
@@ -674,7 +712,11 @@
if (IS_ERR(q6->vreg))
return PTR_ERR(q6->vreg);
- ret = regulator_set_voltage(q6->vreg, 1050000, 1050000);
+ q6->vreg_mx = devm_regulator_get(&pdev->dev, "vdd_mx");
+ if (IS_ERR(q6->vreg_mx))
+ return PTR_ERR(q6->vreg_mx);
+
+ ret = regulator_set_voltage(q6->vreg, VDD_MSS_UV, VDD_MSS_UV);
if (ret)
dev_err(&pdev->dev, "Failed to set regulator's voltage.\n");
diff --git a/arch/arm/mach-msm/pil-q6v5.h b/arch/arm/mach-msm/pil-q6v5.h
index ecdaf9b..d9ad6ae 100644
--- a/arch/arm/mach-msm/pil-q6v5.h
+++ b/arch/arm/mach-msm/pil-q6v5.h
@@ -31,6 +31,7 @@
void __iomem *axi_halt_base;
void __iomem *restart_reg;
struct regulator *vreg;
+ struct regulator *vreg_mx;
bool is_booted;
struct pil_desc desc;
};
diff --git a/arch/arm/mach-msm/pil-riva.c b/arch/arm/mach-msm/pil-riva.c
index 7993090..74fae98 100644
--- a/arch/arm/mach-msm/pil-riva.c
+++ b/arch/arm/mach-msm/pil-riva.c
@@ -542,7 +542,7 @@
}
ret = devm_request_irq(&pdev->dev, drv->irq, riva_wdog_bite_irq_hdlr,
- IRQF_TRIGGER_HIGH, "riva_wdog", drv);
+ IRQF_TRIGGER_RISING, "riva_wdog", drv);
if (ret < 0)
goto err;
diff --git a/arch/arm/mach-msm/pil-venus.c b/arch/arm/mach-msm/pil-venus.c
index 47799cc..103fd9f 100644
--- a/arch/arm/mach-msm/pil-venus.c
+++ b/arch/arm/mach-msm/pil-venus.c
@@ -28,6 +28,8 @@
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
#include <mach/subsystem_restart.h>
+#include <mach/msm_bus_board.h>
+#include <mach/msm_bus.h>
#include "peripheral-loader.h"
#include "scm-pas.h"
@@ -77,6 +79,7 @@
u32 fw_sz;
u32 fw_min_paddr;
u32 fw_max_paddr;
+ u32 bus_perf_client;
};
#define subsys_to_drv(d) container_of(d, struct venus_data, subsys_desc)
@@ -147,6 +150,41 @@
clk_disable_unprepare(drv->clks[i]);
}
+static struct msm_bus_vectors pil_venus_unvote_bw_vector[] = {
+ {
+ .src = MSM_BUS_MASTER_VIDEO_P0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+};
+
+static struct msm_bus_vectors pil_venus_vote_bw_vector[] = {
+ {
+ .src = MSM_BUS_MASTER_VIDEO_P0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 16 * 19 * 1000000UL, /* At least 19.2MHz on bus. */
+ },
+};
+
+static struct msm_bus_paths pil_venus_bw_tbl[] = {
+ {
+ .num_paths = ARRAY_SIZE(pil_venus_unvote_bw_vector),
+ .vectors = pil_venus_unvote_bw_vector,
+ },
+ {
+ .num_paths = ARRAY_SIZE(pil_venus_vote_bw_vector),
+ .vectors = pil_venus_vote_bw_vector,
+ },
+};
+
+static struct msm_bus_scale_pdata pil_venus_client_pdata = {
+ .usecase = pil_venus_bw_tbl,
+ .num_usecases = ARRAY_SIZE(pil_venus_bw_tbl),
+ .name = "pil-venus",
+};
+
static int pil_venus_make_proxy_vote(struct pil_desc *pil)
{
struct venus_data *drv = dev_get_drvdata(pil->dev);
@@ -161,13 +199,28 @@
rc = regulator_enable(drv->gdsc);
if (rc) {
dev_err(pil->dev, "GDSC enable failed\n");
- return rc;
+ goto err_regulator;
}
rc = venus_clock_prepare_enable(pil->dev);
- if (rc)
- regulator_disable(drv->gdsc);
+ if (rc) {
+ dev_err(pil->dev, "clock prepare and enable failed\n");
+ goto err_clock;
+ }
+ rc = msm_bus_scale_client_update_request(drv->bus_perf_client, 1);
+ if (rc) {
+ dev_err(pil->dev, "bandwith request failed\n");
+ goto err_bw;
+ }
+
+ return 0;
+
+err_bw:
+ venus_clock_disable_unprepare(pil->dev);
+err_clock:
+ regulator_disable(drv->gdsc);
+err_regulator:
return rc;
}
@@ -175,6 +228,8 @@
{
struct venus_data *drv = dev_get_drvdata(pil->dev);
+ msm_bus_scale_client_update_request(drv->bus_perf_client, 0);
+
venus_clock_disable_unprepare(pil->dev);
/* Disable GDSC */
@@ -438,6 +493,13 @@
if (rc)
return rc;
+ drv->bus_perf_client =
+ msm_bus_scale_register_client(&pil_venus_client_pdata);
+ if (!drv->bus_perf_client) {
+ dev_err(&pdev->dev, "Failed to register bus client\n");
+ return -EINVAL;
+ }
+
drv->iommu_fw_ctx = msm_iommu_get_ctx("venus_fw");
if (!drv->iommu_fw_ctx) {
dev_err(&pdev->dev, "No iommu fw context found\n");
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index 0933d20..b1d2464 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -175,6 +175,9 @@
{
BUG_ON(cpu >= get_core_count());
+ if (machine_is_msm8974_rumi())
+ return 0;
+
if (cpu_is_msm8x60())
return scorpion_release_secondary();
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
index fb0ace7..ad5f1b5 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
@@ -25,6 +25,9 @@
#include <asm/ioctls.h>
#include <linux/debugfs.h>
#include "audio_utils_aio.h"
+#ifdef CONFIG_USE_DEV_CTRL_VOLUME
+#include <mach/qdsp6v2/audio_dev_ctl.h>
+#endif /*CONFIG_USE_DEV_CTRL_VOLUME*/
#ifdef CONFIG_DEBUG_FS
ssize_t audio_aio_debug_open(struct inode *inode, struct file *file)
@@ -424,6 +427,67 @@
}
}
+#ifdef CONFIG_USE_DEV_CTRL_VOLUME
+
+static void audio_aio_listner(u32 evt_id, union auddev_evt_data *evt_payload,
+ void *private_data)
+{
+ struct q6audio_aio *audio = (struct q6audio_aio *) private_data;
+ int rc = 0;
+
+ switch (evt_id) {
+ case AUDDEV_EVT_STREAM_VOL_CHG:
+ audio->volume = evt_payload->session_vol;
+ pr_debug("%s[%p]: AUDDEV_EVT_STREAM_VOL_CHG, stream vol %d, enabled = %d\n",
+ __func__, audio, audio->volume, audio->enabled);
+ if (audio->enabled == 1) {
+ if (audio->ac) {
+ rc = q6asm_set_volume(audio->ac, audio->volume);
+ if (rc < 0) {
+ pr_err("%s[%p]: Send Volume command failed rc=%d\n",
+ __func__, audio, rc);
+ }
+ }
+ }
+ break;
+ default:
+ pr_err("%s[%p]:ERROR:wrong event\n", __func__, audio);
+ break;
+ }
+}
+
+int register_volume_listener(struct q6audio_aio *audio)
+{
+ int rc = 0;
+ audio->device_events = AUDDEV_EVT_STREAM_VOL_CHG;
+ audio->drv_status &= ~ADRV_STATUS_PAUSE;
+
+ rc = auddev_register_evt_listner(audio->device_events,
+ AUDDEV_CLNT_DEC,
+ audio->ac->session,
+ audio_aio_listner,
+ (void *)audio);
+ if (rc < 0) {
+ pr_err("%s[%p]: Event listener failed\n", __func__, audio);
+ rc = -EACCES;
+ }
+ return rc;
+}
+void unregister_volume_listener(struct q6audio_aio *audio)
+{
+ auddev_unregister_evt_listner(AUDDEV_CLNT_DEC, audio->ac->session);
+}
+#else /*CONFIG_USE_DEV_CTRL_VOLUME*/
+int register_volume_listener(struct q6audio_aio *audio)
+{
+ return 0;/* do nothing */
+}
+void unregister_volume_listener(struct q6audio_aio *audio)
+{
+ return;/* do nothing */
+}
+#endif /*CONFIG_USE_DEV_CTRL_VOLUME*/
+
int audio_aio_release(struct inode *inode, struct file *file)
{
struct q6audio_aio *audio = file->private_data;
@@ -448,6 +512,8 @@
mutex_destroy(&audio->read_lock);
mutex_destroy(&audio->write_lock);
mutex_destroy(&audio->get_event_lock);
+ unregister_volume_listener(audio);
+
#ifdef CONFIG_DEBUG_FS
if (audio->dentry)
debugfs_remove(audio->dentry);
@@ -1049,7 +1115,13 @@
goto fail;
}
pr_debug("Ion client create in audio_aio_open %p", audio->client);
+
+ rc = register_volume_listener(audio);
+ if (rc < 0)
+ goto fail;
+
return 0;
+
fail:
q6asm_audio_client_free(audio->ac);
kfree(audio->codec_cfg);
@@ -1142,6 +1214,11 @@
mutex_unlock(&audio->lock);
break;
}
+ if (audio->drv_status & ADRV_STATUS_FSYNC) {
+ pr_debug("%s[%p] Waking up the audio_aio_fsync\n",
+ __func__, audio);
+ wake_up(&audio->write_wait);
+ }
mutex_unlock(&audio->lock);
break;
}
@@ -1178,6 +1255,11 @@
mutex_lock(&audio->lock);
audio->rflush = 1;
audio->wflush = 1;
+ if (audio->drv_status & ADRV_STATUS_FSYNC) {
+ pr_debug("%s[%p] Waking up the audio_aio_fsync\n",
+ __func__, audio);
+ wake_up(&audio->write_wait);
+ }
/* Flush DSP */
rc = audio_aio_flush(audio);
/* Flush input / Output buffer in software*/
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h
index dedf991..d518254 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h
@@ -1,6 +1,6 @@
/* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-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
@@ -176,7 +176,8 @@
struct ion_client *client;
struct audio_aio_drv_operations drv_ops;
union msm_audio_event_payload eos_write_payload;
-
+ uint32_t device_events;
+ uint16_t volume;
uint32_t drv_status;
int event_abort;
int eos_rsp;
diff --git a/arch/arm/mach-msm/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c
index a59b338..1db3d34 100644
--- a/arch/arm/mach-msm/rpm-smd.c
+++ b/arch/arm/mach-msm/rpm-smd.c
@@ -973,7 +973,7 @@
static bool msm_rpm_set_standalone(void)
{
- if (machine_is_msm9625()) {
+ if (machine_is_msm9625() || machine_is_msm8974_rumi()) {
pr_warn("%s(): Running in standalone mode, requests "
"will not be sent to RPM\n", __func__);
standalone = true;
diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
index 50b3362..b5531d6 100644
--- a/drivers/bluetooth/hci_ath.c
+++ b/drivers/bluetooth/hci_ath.c
@@ -43,6 +43,9 @@
#include <net/bluetooth/hci_core.h>
#include "hci_uart.h"
+#ifdef CONFIG_SERIAL_MSM_HS
+#include <mach/msm_serial_hs.h>
+#endif
unsigned int enableuartsleep = 1;
module_param(enableuartsleep, uint, 0644);
@@ -52,8 +55,8 @@
/** Global state flags */
static unsigned long flags;
-/** Tasklet to respond to change in hostwake line */
-static struct tasklet_struct hostwake_task;
+/** Workqueue to respond to change in hostwake line */
+static void wakeup_host_work(struct work_struct *work);
/** Transmission timer */
static void bluesleep_tx_timer_expire(unsigned long data);
@@ -89,11 +92,23 @@
struct sk_buff_head txq;
struct work_struct ctxtsw;
+ struct work_struct ws_sleep;
};
-static void hostwake_interrupt(unsigned long data)
+static void hsuart_serial_clock_on(struct tty_struct *tty)
{
- BT_INFO(" wakeup host\n");
+ struct uart_state *state = tty->driver_data;
+ struct uart_port *port = state->uart_port;
+ BT_DBG("");
+ msm_hs_request_clock_on(port);
+}
+
+static void hsuart_serial_clock_off(struct tty_struct *tty)
+{
+ struct uart_state *state = tty->driver_data;
+ struct uart_port *port = state->uart_port;
+ BT_DBG("");
+ msm_hs_request_clock_off(port);
}
static void modify_timer_task(void)
@@ -109,6 +124,7 @@
{
int status = 0;
if (test_bit(BT_TXEXPIRED, &flags)) {
+ hsuart_serial_clock_on(tty);
BT_INFO("wakeup device\n");
gpio_set_value(bsi->ext_wake, 0);
msleep(20);
@@ -118,6 +134,19 @@
return status;
}
+static void wakeup_host_work(struct work_struct *work)
+{
+ struct ath_struct *ath =
+ container_of(work, struct ath_struct, ws_sleep);
+
+ BT_INFO("wake up host");
+ if (test_bit(BT_SLEEPENABLE, &flags)) {
+ if (test_bit(BT_TXEXPIRED, &flags))
+ hsuart_serial_clock_on(ath->hu->tty);
+ }
+ modify_timer_task();
+}
+
static void ath_hci_uart_work(struct work_struct *work)
{
int status;
@@ -141,11 +170,14 @@
static irqreturn_t bluesleep_hostwake_isr(int irq, void *dev_id)
{
/* schedule a tasklet to handle the change in the host wake line */
- tasklet_schedule(&hostwake_task);
+ struct ath_struct *ath = (struct ath_struct *)dev_id;
+
+ schedule_work(&ath->ws_sleep);
+
return IRQ_HANDLED;
}
-static int ath_bluesleep_gpio_config(int on)
+static int ath_bluesleep_gpio_config(struct ath_struct *ath, int on)
{
int ret = 0;
@@ -193,19 +225,16 @@
/* Initialize timer */
init_timer(&tx_timer);
tx_timer.function = bluesleep_tx_timer_expire;
- tx_timer.data = 0;
-
- /* initialize host wake tasklet */
- tasklet_init(&hostwake_task, hostwake_interrupt, 0);
+ tx_timer.data = (u_long)ath->hu;
if (bsi->irq_polarity == POLARITY_LOW) {
ret = request_irq(bsi->host_wake_irq, bluesleep_hostwake_isr,
IRQF_DISABLED | IRQF_TRIGGER_FALLING,
- "bluetooth hostwake", NULL);
+ "bluetooth hostwake", (void *)ath);
} else {
ret = request_irq(bsi->host_wake_irq, bluesleep_hostwake_isr,
IRQF_DISABLED | IRQF_TRIGGER_RISING,
- "bluetooth hostwake", NULL);
+ "bluetooth hostwake", (void *)ath);
}
if (ret < 0) {
BT_ERR("Couldn't acquire BT_HOST_WAKE IRQ");
@@ -221,7 +250,7 @@
return 0;
free_host_wake_irq:
- free_irq(bsi->host_wake_irq, NULL);
+ free_irq(bsi->host_wake_irq, (void *)ath);
delete_timer:
del_timer(&tx_timer);
gpio_ext_wake:
@@ -242,11 +271,6 @@
if (!bsi)
return -EIO;
- if (ath_bluesleep_gpio_config(1) < 0) {
- BT_ERR("HCIATH3K GPIO Config failed");
- return -EIO;
- }
-
ath = kzalloc(sizeof(*ath), GFP_ATOMIC);
if (!ath)
return -ENOMEM;
@@ -256,13 +280,20 @@
hu->priv = ath;
ath->hu = hu;
+ if (ath_bluesleep_gpio_config(ath, 1) < 0) {
+ BT_ERR("HCIATH3K GPIO Config failed");
+ hu->priv = NULL;
+ kfree(ath);
+ return -EIO;
+ }
+
ath->cur_sleep = enableuartsleep;
if (ath->cur_sleep == 1) {
set_bit(BT_SLEEPENABLE, &flags);
modify_timer_task();
}
INIT_WORK(&ath->ctxtsw, ath_hci_uart_work);
-
+ INIT_WORK(&ath->ws_sleep, wakeup_host_work);
return 0;
}
@@ -289,11 +320,13 @@
cancel_work_sync(&ath->ctxtsw);
- hu->priv = NULL;
- kfree(ath);
+ cancel_work_sync(&ath->ws_sleep);
if (bsi)
- ath_bluesleep_gpio_config(0);
+ ath_bluesleep_gpio_config(ath, 0);
+
+ hu->priv = NULL;
+ kfree(ath);
return 0;
}
@@ -383,11 +416,14 @@
static void bluesleep_tx_timer_expire(unsigned long data)
{
+ struct hci_uart *hu = (struct hci_uart *) data;
+
if (!test_bit(BT_SLEEPENABLE, &flags))
return;
BT_INFO("Tx timer expired\n");
set_bit(BT_TXEXPIRED, &flags);
+ hsuart_serial_clock_off(hu->tty);
}
static struct hci_uart_proto athp = {
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index e78a2aa..24fc99a 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -38,6 +38,8 @@
struct mutex dci_log_mask_mutex;
struct mutex dci_event_mask_mutex;
+smd_channel_t *ch_dci_temp;
+
#define DCI_CHK_CAPACITY(entry, new_data_len) \
((entry->data_len + new_data_len > entry->total_capacity) ? 1 : 0) \
@@ -306,28 +308,100 @@
diag_smd_dci_send_req(MODEM_PROC);
}
-static void diag_smd_dci_notify(void *ctxt, unsigned event)
+void diag_update_smd_dci_work_fn(struct work_struct *work)
{
- queue_work(driver->diag_dci_wq, &(driver->diag_read_smd_dci_work));
+ int i, j;
+ char dirty_bits[16];
+ uint8_t *client_log_mask_ptr;
+ uint8_t *log_mask_ptr;
+ int ret;
+
+ /* Update the peripheral(s) with the dci log and event masks */
+
+ /* If the cntl channel is not up, we can't update logs and events */
+ if (!driver->ch_cntl)
+ return;
+
+ memset(dirty_bits, 0, 16 * sizeof(uint8_t));
+
+ /*
+ * From each log entry used by each client, determine
+ * which log entries in the cumulative logs that need
+ * to be updated on the peripheral.
+ */
+ for (i = 0; i < MAX_DCI_CLIENTS; i++) {
+ if (driver->dci_client_tbl[i].client) {
+ client_log_mask_ptr =
+ driver->dci_client_tbl[i].dci_log_mask;
+ for (j = 0; j < 16; j++) {
+ if (*(client_log_mask_ptr+1))
+ dirty_bits[j] = 1;
+ client_log_mask_ptr += 514;
+ }
+ }
+ }
+
+ mutex_lock(&dci_log_mask_mutex);
+ /* Update the appropriate dirty bits in the cumulative mask */
+ log_mask_ptr = dci_cumulative_log_mask;
+ for (i = 0; i < 16; i++) {
+ if (dirty_bits[i])
+ *(log_mask_ptr+1) = dirty_bits[i];
+
+ log_mask_ptr += 514;
+ }
+ mutex_unlock(&dci_log_mask_mutex);
+
+ ret = diag_send_dci_log_mask(driver->ch_cntl);
+
+ ret = diag_send_dci_event_mask(driver->ch_cntl);
}
-void diag_dci_notify_client(int peripheral_mask)
+void diag_dci_notify_client(int peripheral_mask, int data)
{
int i, stat;
+ struct siginfo info;
+ memset(&info, 0, sizeof(struct siginfo));
+ info.si_code = SI_QUEUE;
+ info.si_int = (peripheral_mask | data);
/* Notify the DCI process that the peripheral DCI Channel is up */
for (i = 0; i < MAX_DCI_CLIENTS; i++) {
if (driver->dci_client_tbl[i].list & peripheral_mask) {
- pr_info("diag: sending signal now\n");
- stat = send_sig(driver->dci_client_tbl[i].signal_type,
- driver->dci_client_tbl[i].client, 0);
+ info.si_signo = driver->dci_client_tbl[i].signal_type;
+ stat = send_sig_info(
+ driver->dci_client_tbl[i].signal_type,
+ &info, driver->dci_client_tbl[i].client);
if (stat)
- pr_err("diag: Err send sig stat: %d\n", stat);
+ pr_err("diag: Err sending dci signal to client, signal data: 0x%x, stat: %d\n",
+ info.si_int, stat);
break;
}
} /* end of loop for all DCI clients */
}
+static void diag_smd_dci_notify(void *ctxt, unsigned event)
+{
+ if (event == SMD_EVENT_CLOSE) {
+ driver->ch_dci = 0;
+ /* Notify the clients of the close */
+ diag_dci_notify_client(DIAG_CON_MPSS, DIAG_STATUS_CLOSED);
+ return;
+ } else if (event == SMD_EVENT_OPEN) {
+
+ if (ch_dci_temp)
+ driver->ch_dci = ch_dci_temp;
+
+ queue_work(driver->diag_dci_wq,
+ &(driver->diag_update_smd_dci_work));
+
+ /* Notify the clients of the open */
+ diag_dci_notify_client(DIAG_CON_MPSS, DIAG_STATUS_OPEN);
+ }
+
+ queue_work(driver->diag_dci_wq, &(driver->diag_read_smd_dci_work));
+}
+
static int diag_dci_probe(struct platform_device *pdev)
{
int err = 0;
@@ -339,12 +413,11 @@
pr_err("diag: cannot open DCI port, Id = %d, err ="
" %d\n", pdev->id, err);
else
- diag_dci_notify_client(DIAG_CON_MPSS);
+ ch_dci_temp = driver->ch_dci;
}
return err;
}
-
int diag_send_dci_pkt(struct diag_master_table entry, unsigned char *buf,
int len, int index)
{
@@ -414,6 +487,11 @@
uint8_t *event_mask_ptr;
int offset = 0;
+ if (!driver->ch_dci) {
+ pr_err("diag: ch_dci not valid for dci updates\n");
+ return DIAG_DCI_SEND_DATA_FAIL;
+ }
+
/* This is Pkt request/response transaction */
if (*(int *)temp > 0) {
/* enter this UID into kernel table and return index */
@@ -535,7 +613,7 @@
ret = DIAG_DCI_NO_ERROR;
}
/* send updated mask to peripherals */
- diag_send_dci_log_mask(driver->ch_cntl);
+ ret = diag_send_dci_log_mask(driver->ch_cntl);
} else if (*(int *)temp == DCI_EVENT_TYPE) {
/* find client id and table */
for (i = 0; i < MAX_DCI_CLIENTS; i++) {
@@ -581,7 +659,7 @@
ret = DIAG_DCI_NO_ERROR;
}
/* send updated mask to peripherals */
- diag_send_dci_event_mask(driver->ch_cntl);
+ ret = diag_send_dci_event_mask(driver->ch_cntl);
} else {
pr_alert("diag: Incorrect DCI transaction\n");
}
@@ -614,11 +692,12 @@
mutex_unlock(&dci_event_mask_mutex);
}
-void diag_send_dci_event_mask(smd_channel_t *ch)
+int diag_send_dci_event_mask(smd_channel_t *ch)
{
void *buf = driver->buf_event_mask_update;
int header_size = sizeof(struct diag_ctrl_event_mask);
int wr_size = -ENOMEM, retry_count = 0, timer;
+ int ret = DIAG_DCI_NO_ERROR;
mutex_lock(&driver->diag_cntl_mutex);
/* send event mask update */
@@ -642,12 +721,18 @@
break;
}
}
- if (wr_size != header_size + DCI_EVENT_MASK_SIZE)
+ if (wr_size != header_size + DCI_EVENT_MASK_SIZE) {
pr_err("diag: error writing dci event mask %d, tried %d\n",
wr_size, header_size + DCI_EVENT_MASK_SIZE);
- } else
+ ret = DIAG_DCI_SEND_DATA_FAIL;
+ }
+ } else {
pr_err("diag: ch not valid for dci event mask update\n");
+ ret = DIAG_DCI_SEND_DATA_FAIL;
+ }
mutex_unlock(&driver->diag_cntl_mutex);
+
+ return ret;
}
void update_dci_cumulative_log_mask(int offset, int byte_index,
@@ -686,12 +771,18 @@
mutex_unlock(&dci_log_mask_mutex);
}
-void diag_send_dci_log_mask(smd_channel_t *ch)
+int diag_send_dci_log_mask(smd_channel_t *ch)
{
void *buf = driver->buf_log_mask_update;
int header_size = sizeof(struct diag_ctrl_log_mask);
uint8_t *log_mask_ptr = dci_cumulative_log_mask;
int i, wr_size = -ENOMEM, retry_count = 0, timer;
+ int ret = DIAG_DCI_NO_ERROR;
+
+ if (!ch) {
+ pr_err("diag: ch not valid for dci log mask update\n");
+ return DIAG_DCI_SEND_DATA_FAIL;
+ }
mutex_lock(&driver->diag_cntl_mutex);
for (i = 0; i < 16; i++) {
@@ -715,10 +806,12 @@
} else
break;
}
- if (wr_size != header_size + 512)
+ if (wr_size != header_size + 512) {
pr_err("diag: dci log mask update failed %d, tried %d",
wr_size, header_size + 512);
- else {
+ ret = DIAG_DCI_SEND_DATA_FAIL;
+
+ } else {
*(log_mask_ptr+1) = 0; /* clear dirty byte */
pr_debug("diag: updated dci log equip ID %d\n",
*log_mask_ptr);
@@ -727,6 +820,8 @@
log_mask_ptr += 514;
}
mutex_unlock(&driver->diag_cntl_mutex);
+
+ return ret;
}
void create_dci_log_mask_tbl(unsigned char *tbl_buf)
@@ -778,6 +873,8 @@
{
int success = 0;
+ ch_dci_temp = NULL;
+
driver->dci_tag = 0;
driver->dci_client_id = 0;
driver->num_dci_client = 0;
diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h
index 435c750..3f62e5e 100644
--- a/drivers/char/diag/diag_dci.h
+++ b/drivers/char/diag/diag_dci.h
@@ -79,6 +79,7 @@
int diag_dci_init(void);
void diag_dci_exit(void);
void diag_read_smd_dci_work_fn(struct work_struct *);
+void diag_update_smd_dci_work_fn(struct work_struct *);
int diag_process_dci_transaction(unsigned char *buf, int len);
int diag_send_dci_pkt(struct diag_master_table entry, unsigned char *buf,
int len, int index);
@@ -87,11 +88,11 @@
void create_dci_log_mask_tbl(unsigned char *tbl_buf);
void update_dci_cumulative_log_mask(int offset, int byte_index,
uint8_t byte_mask);
-void diag_send_dci_log_mask(smd_channel_t *ch);
+int diag_send_dci_log_mask(smd_channel_t *ch);
void extract_dci_log(unsigned char *buf);
/* DCI event streaming functions */
void update_dci_cumulative_event_mask(int offset, uint8_t byte_mask);
-void diag_send_dci_event_mask(smd_channel_t *ch);
+int diag_send_dci_event_mask(smd_channel_t *ch);
void extract_dci_events(unsigned char *buf);
void create_dci_event_mask_tbl(unsigned char *tbl_buf);
#endif
diff --git a/drivers/char/diag/diag_debugfs.c b/drivers/char/diag/diag_debugfs.c
index 7863f74..c404229 100644
--- a/drivers/char/diag/diag_debugfs.c
+++ b/drivers/char/diag/diag_debugfs.c
@@ -113,7 +113,8 @@
"diag_modem_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",
+ "diag_read_smd_dci_work: %d\n"
+ "diag_update_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)),
@@ -124,7 +125,8 @@
work_pending(&(driver->diag_modem_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)));
+ work_pending(&(driver->diag_read_smd_dci_work)),
+ work_pending(&(driver->diag_update_smd_dci_work)));
#ifdef CONFIG_DIAG_OVER_USB
ret += scnprintf(buf+ret, DEBUG_BUF_SIZE,
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index d1ec5f2..ec3bb81 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -67,6 +67,15 @@
#define DIAG_CON_LPASS (0x0004) /* Bit mask for LPASS */
#define DIAG_CON_WCNSS (0x0008) /* Bit mask for WCNSS */
+/*
+ * The status bit masks when received in a signal handler are to be
+ * used in conjunction with the peripheral list bit mask to determine the
+ * status for a peripheral. For instance, 0x00010002 would denote an open
+ * status on the MPSS
+ */
+#define DIAG_STATUS_OPEN (0x00010000) /* DCI channel open status mask */
+#define DIAG_STATUS_CLOSED (0x00020000) /* DCI channel closed status mask */
+
/* Maximum number of pkt reg supported at initialization*/
extern unsigned int diag_max_reg;
extern unsigned int diag_threshold_reg;
@@ -235,6 +244,7 @@
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_update_smd_dci_work;
struct work_struct diag_clean_modem_reg_work;
struct work_struct diag_clean_lpass_reg_work;
struct work_struct diag_clean_wcnss_reg_work;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 645d916..34ff345 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -1613,7 +1613,9 @@
INIT_WORK(&(driver->diag_read_smd_wcnss_cntl_work),
diag_read_smd_wcnss_cntl_work_fn);
INIT_WORK(&(driver->diag_read_smd_dci_work),
- diag_read_smd_dci_work_fn);
+ diag_read_smd_dci_work_fn);
+ INIT_WORK(&(driver->diag_update_smd_dci_work),
+ diag_update_smd_dci_work_fn);
INIT_WORK(&(driver->diag_clean_modem_reg_work),
diag_clean_modem_reg_fn);
INIT_WORK(&(driver->diag_clean_lpass_reg_work),
diff --git a/drivers/gpu/ion/Makefile b/drivers/gpu/ion/Makefile
index c9e8a94..51349f6 100644
--- a/drivers/gpu/ion/Makefile
+++ b/drivers/gpu/ion/Makefile
@@ -1,3 +1,4 @@
obj-$(CONFIG_ION) += ion.o ion_heap.o ion_system_heap.o ion_carveout_heap.o ion_iommu_heap.o ion_cp_heap.o
+obj-$(CONFIG_CMA) += ion_cma_heap.o
obj-$(CONFIG_ION_TEGRA) += tegra/
obj-$(CONFIG_ION_MSM) += msm/
diff --git a/drivers/gpu/ion/ion_cma_heap.c b/drivers/gpu/ion/ion_cma_heap.c
new file mode 100644
index 0000000..bef6b6f
--- /dev/null
+++ b/drivers/gpu/ion/ion_cma_heap.c
@@ -0,0 +1,342 @@
+/*
+ * drivers/gpu/ion/ion_cma_heap.c
+ *
+ * Copyright (C) Linaro 2012
+ * Author: <benjamin.gaignard@linaro.org> for ST-Ericsson.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/ion.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/dma-mapping.h>
+#include <linux/msm_ion.h>
+#include <mach/iommu_domains.h>
+
+#include <asm/cacheflush.h>
+
+/* for ion_heap_ops structure */
+#include "ion_priv.h"
+
+#define ION_CMA_ALLOCATE_FAILED -1
+
+struct ion_cma_buffer_info {
+ void *cpu_addr;
+ dma_addr_t handle;
+ struct sg_table *table;
+ bool is_cached;
+};
+
+static int cma_heap_has_outer_cache;
+/*
+ * Create scatter-list for the already allocated DMA buffer.
+ * This function could be replace by dma_common_get_sgtable
+ * as soon as it will avalaible.
+ */
+int ion_cma_get_sgtable(struct device *dev, struct sg_table *sgt,
+ void *cpu_addr, dma_addr_t handle, size_t size)
+{
+ struct page *page = virt_to_page(cpu_addr);
+ int ret;
+
+ ret = sg_alloc_table(sgt, 1, GFP_KERNEL);
+ if (unlikely(ret))
+ return ret;
+
+ sg_set_page(sgt->sgl, page, PAGE_ALIGN(size), 0);
+ return 0;
+}
+
+/* ION CMA heap operations functions */
+static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer,
+ unsigned long len, unsigned long align,
+ unsigned long flags)
+{
+ struct device *dev = heap->priv;
+ struct ion_cma_buffer_info *info;
+
+ dev_dbg(dev, "Request buffer allocation len %ld\n", len);
+
+ info = kzalloc(sizeof(struct ion_cma_buffer_info), GFP_KERNEL);
+ if (!info) {
+ dev_err(dev, "Can't allocate buffer info\n");
+ return ION_CMA_ALLOCATE_FAILED;
+ }
+
+ if (!ION_IS_CACHED(flags))
+ info->cpu_addr = dma_alloc_writecombine(dev, len,
+ &(info->handle), 0);
+ else
+ info->cpu_addr = dma_alloc_nonconsistent(dev, len,
+ &(info->handle), 0);
+
+ if (!info->cpu_addr) {
+ dev_err(dev, "Fail to allocate buffer\n");
+ goto err;
+ }
+
+ info->table = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
+ if (!info->table) {
+ dev_err(dev, "Fail to allocate sg table\n");
+ goto err;
+ }
+
+ info->is_cached = ION_IS_CACHED(flags);
+
+ ion_cma_get_sgtable(dev,
+ info->table, info->cpu_addr, info->handle, len);
+
+ /* keep this for memory release */
+ buffer->priv_virt = info;
+ dev_dbg(dev, "Allocate buffer %p\n", buffer);
+ return 0;
+
+err:
+ kfree(info);
+ return ION_CMA_ALLOCATE_FAILED;
+}
+
+static void ion_cma_free(struct ion_buffer *buffer)
+{
+ struct device *dev = buffer->heap->priv;
+ struct ion_cma_buffer_info *info = buffer->priv_virt;
+
+ dev_dbg(dev, "Release buffer %p\n", buffer);
+ /* release memory */
+ dma_free_coherent(dev, buffer->size, info->cpu_addr, info->handle);
+ /* release sg table */
+ kfree(info->table);
+ kfree(info);
+}
+
+/* return physical address in addr */
+static int ion_cma_phys(struct ion_heap *heap, struct ion_buffer *buffer,
+ ion_phys_addr_t *addr, size_t *len)
+{
+ struct device *dev = heap->priv;
+ struct ion_cma_buffer_info *info = buffer->priv_virt;
+
+ dev_dbg(dev, "Return buffer %p physical address 0x%x\n", buffer,
+ info->handle);
+
+ *addr = info->handle;
+ *len = buffer->size;
+
+ return 0;
+}
+
+struct sg_table *ion_cma_heap_map_dma(struct ion_heap *heap,
+ struct ion_buffer *buffer)
+{
+ struct ion_cma_buffer_info *info = buffer->priv_virt;
+
+ return info->table;
+}
+
+void ion_cma_heap_unmap_dma(struct ion_heap *heap,
+ struct ion_buffer *buffer)
+{
+ return;
+}
+
+static int ion_cma_mmap(struct ion_heap *mapper, struct ion_buffer *buffer,
+ struct vm_area_struct *vma)
+{
+ struct device *dev = buffer->heap->priv;
+ struct ion_cma_buffer_info *info = buffer->priv_virt;
+
+ if (info->is_cached)
+ return dma_mmap_nonconsistent(dev, vma, info->cpu_addr,
+ info->handle, buffer->size);
+ else
+ return dma_mmap_writecombine(dev, vma, info->cpu_addr,
+ info->handle, buffer->size);
+}
+
+static void *ion_cma_map_kernel(struct ion_heap *heap,
+ struct ion_buffer *buffer)
+{
+ struct ion_cma_buffer_info *info = buffer->priv_virt;
+
+ return info->cpu_addr;
+}
+
+static void ion_cma_unmap_kernel(struct ion_heap *heap,
+ struct ion_buffer *buffer)
+{
+ return;
+}
+
+int ion_cma_map_iommu(struct ion_buffer *buffer,
+ struct ion_iommu_map *data,
+ unsigned int domain_num,
+ unsigned int partition_num,
+ unsigned long align,
+ unsigned long iova_length,
+ unsigned long flags)
+{
+ int ret = 0;
+ struct iommu_domain *domain;
+ unsigned long extra;
+ unsigned long extra_iova_addr;
+ struct ion_cma_buffer_info *info = buffer->priv_virt;
+ struct sg_table *table = info->table;
+ int prot = IOMMU_WRITE | IOMMU_READ;
+
+ data->mapped_size = iova_length;
+
+ if (!msm_use_iommu()) {
+ data->iova_addr = info->handle;
+ return 0;
+ }
+
+ extra = iova_length - buffer->size;
+
+ ret = msm_allocate_iova_address(domain_num, partition_num,
+ data->mapped_size, align,
+ &data->iova_addr);
+
+ if (ret)
+ goto out;
+
+ domain = msm_get_iommu_domain(domain_num);
+
+ if (!domain) {
+ ret = -EINVAL;
+ goto out1;
+ }
+
+ ret = iommu_map_range(domain, data->iova_addr, table->sgl,
+ buffer->size, prot);
+
+ if (ret) {
+ pr_err("%s: could not map %lx in domain %p\n",
+ __func__, data->iova_addr, domain);
+ goto out1;
+ }
+
+ extra_iova_addr = data->iova_addr + buffer->size;
+ if (extra) {
+ ret = msm_iommu_map_extra(domain, extra_iova_addr, extra, SZ_4K,
+ prot);
+ if (ret)
+ goto out2;
+ }
+ return ret;
+
+out2:
+ iommu_unmap_range(domain, data->iova_addr, buffer->size);
+out1:
+ msm_free_iova_address(data->iova_addr, domain_num, partition_num,
+ data->mapped_size);
+out:
+ return ret;
+}
+
+
+void ion_cma_unmap_iommu(struct ion_iommu_map *data)
+{
+ unsigned int domain_num;
+ unsigned int partition_num;
+ struct iommu_domain *domain;
+
+ if (!msm_use_iommu())
+ return;
+
+ domain_num = iommu_map_domain(data);
+ partition_num = iommu_map_partition(data);
+
+ domain = msm_get_iommu_domain(domain_num);
+
+ if (!domain) {
+ WARN(1, "Could not get domain %d. Corruption?\n", domain_num);
+ return;
+ }
+
+ iommu_unmap_range(domain, data->iova_addr, data->mapped_size);
+ msm_free_iova_address(data->iova_addr, domain_num, partition_num,
+ data->mapped_size);
+
+ return;
+}
+
+int ion_cma_cache_ops(struct ion_heap *heap,
+ struct ion_buffer *buffer, void *vaddr,
+ unsigned int offset, unsigned int length,
+ unsigned int cmd)
+{
+ void (*outer_cache_op)(phys_addr_t, phys_addr_t);
+
+ switch (cmd) {
+ case ION_IOC_CLEAN_CACHES:
+ dmac_clean_range(vaddr, vaddr + length);
+ outer_cache_op = outer_clean_range;
+ break;
+ case ION_IOC_INV_CACHES:
+ dmac_inv_range(vaddr, vaddr + length);
+ outer_cache_op = outer_inv_range;
+ break;
+ case ION_IOC_CLEAN_INV_CACHES:
+ dmac_flush_range(vaddr, vaddr + length);
+ outer_cache_op = outer_flush_range;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (cma_heap_has_outer_cache) {
+ struct ion_cma_buffer_info *info = buffer->priv_virt;
+
+ outer_cache_op(info->handle, info->handle + length);
+ }
+
+ return 0;
+}
+
+static struct ion_heap_ops ion_cma_ops = {
+ .allocate = ion_cma_allocate,
+ .free = ion_cma_free,
+ .map_dma = ion_cma_heap_map_dma,
+ .unmap_dma = ion_cma_heap_unmap_dma,
+ .phys = ion_cma_phys,
+ .map_user = ion_cma_mmap,
+ .map_kernel = ion_cma_map_kernel,
+ .unmap_kernel = ion_cma_unmap_kernel,
+ .map_iommu = ion_cma_map_iommu,
+ .unmap_iommu = ion_cma_unmap_iommu,
+ .cache_op = ion_cma_cache_ops,
+};
+
+struct ion_heap *ion_cma_heap_create(struct ion_platform_heap *data)
+{
+ struct ion_heap *heap;
+
+ heap = kzalloc(sizeof(struct ion_heap), GFP_KERNEL);
+
+ if (!heap)
+ return ERR_PTR(-ENOMEM);
+
+ heap->ops = &ion_cma_ops;
+ /* set device as private heaps data, later it will be
+ * used to make the link with reserved CMA memory */
+ heap->priv = data->priv;
+ heap->type = ION_HEAP_TYPE_DMA;
+ cma_heap_has_outer_cache = data->has_outer_cache;
+ return heap;
+}
+
+void ion_cma_heap_destroy(struct ion_heap *heap)
+{
+ kfree(heap);
+}
diff --git a/drivers/gpu/ion/ion_cp_heap.c b/drivers/gpu/ion/ion_cp_heap.c
index aa3469c..96a3cdc 100644
--- a/drivers/gpu/ion/ion_cp_heap.c
+++ b/drivers/gpu/ion/ion_cp_heap.c
@@ -2,7 +2,7 @@
* drivers/gpu/ion/ion_cp_heap.c
*
* Copyright (C) 2011 Google, Inc.
- * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-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
@@ -15,7 +15,7 @@
*
*/
#include <linux/spinlock.h>
-
+#include <linux/delay.h>
#include <linux/err.h>
#include <linux/genalloc.h>
#include <linux/io.h>
@@ -28,6 +28,7 @@
#include <linux/seq_file.h>
#include <linux/fmem.h>
#include <linux/iommu.h>
+#include <linux/dma-mapping.h>
#include <asm/mach/map.h>
@@ -99,6 +100,10 @@
int iommu_2x_map_domain;
unsigned int has_outer_cache;
atomic_t protect_cnt;
+ void *cpu_addr;
+ size_t heap_size;
+ dma_addr_t handle;
+ int cma;
};
enum {
@@ -126,6 +131,8 @@
void *data;
};
+#define DMA_ALLOC_TRIES 5
+
static int ion_cp_protect_mem(unsigned int phy_base, unsigned int size,
unsigned int permission_type, int version,
void *data);
@@ -134,6 +141,71 @@
unsigned int permission_type, int version,
void *data);
+static int allocate_heap_memory(struct ion_heap *heap)
+{
+ struct device *dev = heap->priv;
+ struct ion_cp_heap *cp_heap =
+ container_of(heap, struct ion_cp_heap, heap);
+ int ret;
+ int tries = 0;
+ DEFINE_DMA_ATTRS(attrs);
+ dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &attrs);
+
+
+ if (cp_heap->cpu_addr)
+ return 0;
+
+ while (!cp_heap->cpu_addr && (++tries < DMA_ALLOC_TRIES)) {
+ cp_heap->cpu_addr = dma_alloc_attrs(dev,
+ cp_heap->heap_size,
+ &(cp_heap->handle),
+ 0,
+ &attrs);
+ if (!cp_heap->cpu_addr)
+ msleep(20);
+ }
+
+ if (!cp_heap->cpu_addr)
+ goto out;
+
+ cp_heap->base = cp_heap->handle;
+
+ cp_heap->pool = gen_pool_create(12, -1);
+ if (!cp_heap->pool)
+ goto out_free;
+
+ ret = gen_pool_add(cp_heap->pool, cp_heap->base,
+ cp_heap->heap_size, -1);
+ if (ret < 0)
+ goto out_pool;
+
+ return 0;
+
+out_pool:
+ gen_pool_destroy(cp_heap->pool);
+out_free:
+ dma_free_coherent(dev, cp_heap->heap_size, cp_heap->cpu_addr,
+ cp_heap->handle);
+out:
+ return ION_CP_ALLOCATE_FAIL;
+}
+
+static void free_heap_memory(struct ion_heap *heap)
+{
+ struct device *dev = heap->priv;
+ struct ion_cp_heap *cp_heap =
+ container_of(heap, struct ion_cp_heap, heap);
+
+ /* release memory */
+ dma_free_coherent(dev, cp_heap->heap_size, cp_heap->cpu_addr,
+ cp_heap->handle);
+ gen_pool_destroy(cp_heap->pool);
+ cp_heap->pool = NULL;
+ cp_heap->cpu_addr = 0;
+}
+
+
+
/**
* Get the total number of kernel mappings.
* Must be called with heap->lock locked.
@@ -155,6 +227,12 @@
if (ret_value)
return 1;
}
+
+ if (cp_heap->cma) {
+ ret_value = allocate_heap_memory(heap);
+ if (ret_value)
+ return 1;
+ }
return 0;
}
@@ -167,6 +245,9 @@
if (fmem_set_state(FMEM_T_STATE) != 0)
pr_err("%s: unable to transition heap to T-state\n",
__func__);
+
+ if (cp_heap->cma)
+ free_heap_memory(heap);
}
/* Must be protected by ion_cp_buffer lock */
@@ -688,7 +769,24 @@
if (cp_heap->reusable) {
ret_value = ion_map_fmem_buffer(buffer, cp_heap->base,
cp_heap->reserved_vrange, buffer->flags);
+ } else if (cp_heap->cma) {
+ int npages = PAGE_ALIGN(buffer->size) / PAGE_SIZE;
+ struct page **pages = vmalloc(
+ sizeof(struct page *) * npages);
+ int i;
+ pgprot_t pgprot;
+ if (ION_IS_CACHED(buffer->flags))
+ pgprot = PAGE_KERNEL;
+ else
+ pgprot = pgprot_writecombine(PAGE_KERNEL);
+
+ for (i = 0; i < npages; i++) {
+ pages[i] = phys_to_page(buf->buffer +
+ i * PAGE_SIZE);
+ }
+ ret_value = vmap(pages, npages, VM_IOREMAP, pgprot);
+ vfree(pages);
} else {
if (ION_IS_CACHED(buffer->flags))
ret_value = ioremap_cached(buf->buffer,
@@ -721,6 +819,8 @@
if (cp_heap->reusable)
unmap_kernel_range((unsigned long)buffer->vaddr, buffer->size);
+ else if (cp_heap->cma)
+ vunmap(buffer->vaddr);
else
__arm_iounmap(buffer->vaddr);
@@ -1148,14 +1248,6 @@
mutex_init(&cp_heap->lock);
- cp_heap->pool = gen_pool_create(12, -1);
- if (!cp_heap->pool)
- goto free_heap;
-
- cp_heap->base = heap_data->base;
- ret = gen_pool_add(cp_heap->pool, cp_heap->base, heap_data->size, -1);
- if (ret < 0)
- goto destroy_pool;
cp_heap->allocated_bytes = 0;
cp_heap->umap_count = 0;
@@ -1165,9 +1257,11 @@
cp_heap->heap.ops = &cp_heap_ops;
cp_heap->heap.type = (enum ion_heap_type) ION_HEAP_TYPE_CP;
cp_heap->heap_protected = HEAP_NOT_PROTECTED;
- cp_heap->secure_base = cp_heap->base;
+ cp_heap->secure_base = heap_data->base;
cp_heap->secure_size = heap_data->size;
cp_heap->has_outer_cache = heap_data->has_outer_cache;
+ cp_heap->heap_size = heap_data->size;
+
atomic_set(&cp_heap->protect_cnt, 0);
if (heap_data->extra_data) {
struct ion_cp_heap_pdata *extra_data =
@@ -1191,9 +1285,26 @@
extra_data->iommu_map_all;
cp_heap->iommu_2x_map_domain =
extra_data->iommu_2x_map_domain;
+ cp_heap->cma = extra_data->is_cma;
}
+ if (cp_heap->cma) {
+ cp_heap->pool = NULL;
+ cp_heap->cpu_addr = 0;
+ cp_heap->heap.priv = heap_data->priv;
+ } else {
+ cp_heap->pool = gen_pool_create(12, -1);
+ if (!cp_heap->pool)
+ goto free_heap;
+
+ cp_heap->base = heap_data->base;
+ ret = gen_pool_add(cp_heap->pool, cp_heap->base,
+ heap_data->size, -1);
+ if (ret < 0)
+ goto destroy_pool;
+
+ }
return &cp_heap->heap;
destroy_pool:
diff --git a/drivers/gpu/ion/ion_heap.c b/drivers/gpu/ion/ion_heap.c
index 4c83d75..0670468 100644
--- a/drivers/gpu/ion/ion_heap.c
+++ b/drivers/gpu/ion/ion_heap.c
@@ -40,6 +40,11 @@
case ION_HEAP_TYPE_CP:
heap = ion_cp_heap_create(heap_data);
break;
+#ifdef CONFIG_CMA
+ case ION_HEAP_TYPE_DMA:
+ heap = ion_cma_heap_create(heap_data);
+ break;
+#endif
default:
pr_err("%s: Invalid heap type %d\n", __func__,
heap_data->type);
@@ -55,6 +60,7 @@
heap->name = heap_data->name;
heap->id = heap_data->id;
+ heap->priv = heap_data->priv;
return heap;
}
@@ -79,6 +85,11 @@
case ION_HEAP_TYPE_CP:
ion_cp_heap_destroy(heap);
break;
+#ifdef CONFIG_CMA
+ case ION_HEAP_TYPE_DMA:
+ ion_cma_heap_destroy(heap);
+ break;
+#endif
default:
pr_err("%s: Invalid heap type %d\n", __func__,
heap->type);
diff --git a/drivers/gpu/ion/ion_priv.h b/drivers/gpu/ion/ion_priv.h
index 991a310..7713875 100644
--- a/drivers/gpu/ion/ion_priv.h
+++ b/drivers/gpu/ion/ion_priv.h
@@ -162,6 +162,7 @@
* allocating. These are specified by platform data and
* MUST be unique
* @name: used for debugging
+ * @priv: private heap data
*
* Represents a pool of memory from which buffers can be made. In some
* systems the only heap is regular system memory allocated via vmalloc.
@@ -175,6 +176,7 @@
struct ion_heap_ops *ops;
int id;
const char *name;
+ void *priv;
};
/**
@@ -257,6 +259,10 @@
void ion_carveout_free(struct ion_heap *heap, ion_phys_addr_t addr,
unsigned long size);
+#ifdef CONFIG_CMA
+struct ion_heap *ion_cma_heap_create(struct ion_platform_heap *);
+void ion_cma_heap_destroy(struct ion_heap *);
+#endif
struct ion_heap *msm_get_contiguous_heap(void);
/**
diff --git a/drivers/gpu/ion/ion_system_heap.c b/drivers/gpu/ion/ion_system_heap.c
index ad2ef83..8b63216 100644
--- a/drivers/gpu/ion/ion_system_heap.c
+++ b/drivers/gpu/ion/ion_system_heap.c
@@ -518,14 +518,26 @@
return ret;
}
+void *ion_system_contig_heap_map_kernel(struct ion_heap *heap,
+ struct ion_buffer *buffer)
+{
+ return buffer->priv_virt;
+}
+
+void ion_system_contig_heap_unmap_kernel(struct ion_heap *heap,
+ struct ion_buffer *buffer)
+{
+ return;
+}
+
static struct ion_heap_ops kmalloc_ops = {
.allocate = ion_system_contig_heap_allocate,
.free = ion_system_contig_heap_free,
.phys = ion_system_contig_heap_phys,
.map_dma = ion_system_contig_heap_map_dma,
.unmap_dma = ion_system_heap_unmap_dma,
- .map_kernel = ion_system_heap_map_kernel,
- .unmap_kernel = ion_system_heap_unmap_kernel,
+ .map_kernel = ion_system_contig_heap_map_kernel,
+ .unmap_kernel = ion_system_contig_heap_unmap_kernel,
.map_user = ion_system_contig_heap_map_user,
.cache_op = ion_system_contig_heap_cache_ops,
.print_debug = ion_system_contig_print_debug,
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index 8699178..e422fd26 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -424,6 +424,7 @@
unsigned int i;
for (i = 0; i < pdata->nr; ++i)
kfree(pdata->heaps[i].extra_data);
+ kfree(pdata->heaps);
kfree(pdata);
}
@@ -553,6 +554,7 @@
const struct device_node *dt_node)
{
struct ion_platform_data *pdata = 0;
+ struct ion_platform_heap *heaps = NULL;
struct device_node *node;
uint32_t val = 0;
int ret = 0;
@@ -565,11 +567,17 @@
if (!num_heaps)
return ERR_PTR(-EINVAL);
- pdata = kzalloc(sizeof(struct ion_platform_data) +
- num_heaps*sizeof(struct ion_platform_heap), GFP_KERNEL);
+ pdata = kzalloc(sizeof(struct ion_platform_data), GFP_KERNEL);
if (!pdata)
return ERR_PTR(-ENOMEM);
+ heaps = kzalloc(sizeof(struct ion_platform_heap)*num_heaps, GFP_KERNEL);
+ if (!heaps) {
+ kfree(pdata);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ pdata->heaps = heaps;
pdata->nr = num_heaps;
for_each_child_of_node(dt_node, node) {
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 060e89a..fdabf0b 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -29,6 +29,7 @@
#include "kgsl_cffdump.h"
#include "kgsl_sharedmem.h"
#include "kgsl_iommu.h"
+#include "kgsl_trace.h"
#include "adreno.h"
#include "adreno_pm4types.h"
@@ -2067,6 +2068,8 @@
if (!in_interrupt())
kgsl_pre_hwaccess(device);
+ trace_kgsl_regwrite(device, offsetwords, value);
+
kgsl_cffdump_regwrite(device->id, offsetwords << 2, value);
reg = (unsigned int *)(device->reg_virt + (offsetwords << 2));
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 61378fe..cf16995 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -168,6 +168,9 @@
extern const unsigned int a3xx_registers[];
extern const unsigned int a3xx_registers_count;
+extern const unsigned int a3xx_hlsq_registers[];
+extern const unsigned int a3xx_hlsq_registers_count;
+
extern const unsigned int a330_registers[];
extern const unsigned int a330_registers_count;
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index feced43..2466a5c 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -40,8 +40,8 @@
0x0578, 0x057f, 0x0600, 0x0602, 0x0605, 0x0607, 0x060a, 0x060e,
0x0612, 0x0614, 0x0c01, 0x0c02, 0x0c06, 0x0c1d, 0x0c3d, 0x0c3f,
0x0c48, 0x0c4b, 0x0c80, 0x0c80, 0x0c88, 0x0c8b, 0x0ca0, 0x0cb7,
- 0x0cc0, 0x0cc1, 0x0cc6, 0x0cc7, 0x0ce4, 0x0ce5, 0x0e00, 0x0e05,
- 0x0e0c, 0x0e0c, 0x0e22, 0x0e23, 0x0e41, 0x0e45, 0x0e64, 0x0e65,
+ 0x0cc0, 0x0cc1, 0x0cc6, 0x0cc7, 0x0ce4, 0x0ce5,
+ 0x0e41, 0x0e45, 0x0e64, 0x0e65,
0x0e80, 0x0e82, 0x0e84, 0x0e89, 0x0ea0, 0x0ea1, 0x0ea4, 0x0ea7,
0x0ec4, 0x0ecb, 0x0ee0, 0x0ee0, 0x0f00, 0x0f01, 0x0f03, 0x0f09,
0x2040, 0x2040, 0x2044, 0x2044, 0x2048, 0x204d, 0x2068, 0x2069,
@@ -49,7 +49,7 @@
0x2079, 0x207a, 0x20c0, 0x20d3, 0x20e4, 0x20ef, 0x2100, 0x2109,
0x210c, 0x210c, 0x210e, 0x210e, 0x2110, 0x2111, 0x2114, 0x2115,
0x21e4, 0x21e4, 0x21ea, 0x21ea, 0x21ec, 0x21ed, 0x21f0, 0x21f0,
- 0x2200, 0x2212, 0x2214, 0x2217, 0x221a, 0x221a, 0x2240, 0x227e,
+ 0x2240, 0x227e,
0x2280, 0x228b, 0x22c0, 0x22c0, 0x22c4, 0x22ce, 0x22d0, 0x22d8,
0x22df, 0x22e6, 0x22e8, 0x22e9, 0x22ec, 0x22ec, 0x22f0, 0x22f7,
0x22ff, 0x22ff, 0x2340, 0x2343, 0x2348, 0x2349, 0x2350, 0x2356,
@@ -58,7 +58,7 @@
0x2474, 0x2475, 0x2479, 0x247a, 0x24c0, 0x24d3, 0x24e4, 0x24ef,
0x2500, 0x2509, 0x250c, 0x250c, 0x250e, 0x250e, 0x2510, 0x2511,
0x2514, 0x2515, 0x25e4, 0x25e4, 0x25ea, 0x25ea, 0x25ec, 0x25ed,
- 0x25f0, 0x25f0, 0x2600, 0x2612, 0x2614, 0x2617, 0x261a, 0x261a,
+ 0x25f0, 0x25f0,
0x2640, 0x267e, 0x2680, 0x268b, 0x26c0, 0x26c0, 0x26c4, 0x26ce,
0x26d0, 0x26d8, 0x26df, 0x26e6, 0x26e8, 0x26e9, 0x26ec, 0x26ec,
0x26f0, 0x26f7, 0x26ff, 0x26ff, 0x2740, 0x2743, 0x2748, 0x2749,
@@ -69,6 +69,18 @@
const unsigned int a3xx_registers_count = ARRAY_SIZE(a3xx_registers) / 2;
+/* Removed the following HLSQ register ranges from being read during
+ * recovery since reading the registers may cause the device to hang:
+ */
+const unsigned int a3xx_hlsq_registers[] = {
+ 0x0e00, 0x0e05, 0x0e0c, 0x0e0c, 0x0e22, 0x0e23,
+ 0x2200, 0x2212, 0x2214, 0x2217, 0x221a, 0x221a,
+ 0x2600, 0x2612, 0x2614, 0x2617, 0x261a, 0x261a,
+};
+
+const unsigned int a3xx_hlsq_registers_count =
+ ARRAY_SIZE(a3xx_hlsq_registers) / 2;
+
/* The set of additional registers to be dumped for A330 */
const unsigned int a330_registers[] = {
diff --git a/drivers/gpu/msm/adreno_a3xx_snapshot.c b/drivers/gpu/msm/adreno_a3xx_snapshot.c
index 1243dd0..de95951 100644
--- a/drivers/gpu/msm/adreno_a3xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a3xx_snapshot.c
@@ -341,6 +341,41 @@
return snapshot;
}
+static void _snapshot_a3xx_regs(struct kgsl_snapshot_registers *regs,
+ struct kgsl_snapshot_registers_list *list)
+{
+ regs[list->count].regs = (unsigned int *) a3xx_registers;
+ regs[list->count].count = a3xx_registers_count;
+ list->count++;
+}
+
+static void _snapshot_hlsq_regs(struct kgsl_snapshot_registers *regs,
+ struct kgsl_snapshot_registers_list *list,
+ struct adreno_device *adreno_dev)
+{
+ /* HLSQ specific registers */
+ /*
+ * Don't dump any a3xx HLSQ registers just yet. Reading the HLSQ
+ * registers can cause the device to hang if the HLSQ block is
+ * busy. Add specific checks for each a3xx core as the requirements
+ * are discovered. Disable by default for now.
+ */
+ if (!adreno_is_a3xx(adreno_dev)) {
+ regs[list->count].regs = (unsigned int *) a3xx_hlsq_registers;
+ regs[list->count].count = a3xx_hlsq_registers_count;
+ list->count++;
+ }
+}
+
+static void _snapshot_a330_regs(struct kgsl_snapshot_registers *regs,
+ struct kgsl_snapshot_registers_list *list)
+{
+ /* For A330, append the additional list of new registers to grab */
+ regs[list->count].regs = (unsigned int *) a330_registers;
+ regs[list->count].count = a330_registers_count;
+ list->count++;
+}
+
/* A3XX GPU snapshot function - this is where all of the A3XX specific
* bits and pieces are grabbed into the snapshot memory
*/
@@ -350,21 +385,20 @@
{
struct kgsl_device *device = &adreno_dev->dev;
struct kgsl_snapshot_registers_list list;
- struct kgsl_snapshot_registers regs[2];
+ struct kgsl_snapshot_registers regs[5];
int size;
- regs[0].regs = (unsigned int *) a3xx_registers;
- regs[0].count = a3xx_registers_count;
-
list.registers = regs;
- list.count = 1;
+ list.count = 0;
- /* For A330, append the additional list of new registers to grab */
- if (adreno_is_a330(adreno_dev)) {
- regs[1].regs = (unsigned int *) a330_registers;
- regs[1].count = a330_registers_count;
- list.count++;
- }
+ /* Disable Clock gating temporarily for the debug bus to work */
+ adreno_regwrite(device, A3XX_RBBM_CLOCK_CTL, 0x00);
+
+ /* Store relevant registers in list to snapshot */
+ _snapshot_a3xx_regs(regs, &list);
+ _snapshot_hlsq_regs(regs, &list, adreno_dev);
+ if (adreno_is_a330(adreno_dev))
+ _snapshot_a330_regs(regs, &list);
/* Master set of (non debug) registers */
snapshot = kgsl_snapshot_add_section(device,
@@ -385,9 +419,6 @@
remain, REG_CP_ME_CNTL, REG_CP_ME_STATUS,
64, 44);
- /* Disable Clock gating temporarily for the debug bus to work */
- adreno_regwrite(device, A3XX_RBBM_CLOCK_CTL, 0x00);
-
/* VPC memory */
snapshot = kgsl_snapshot_add_section(device,
KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain,
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 27343c5..8af361a 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -513,7 +513,7 @@
if (context && context->flags & CTXT_FLAGS_PER_CONTEXT_TS)
context_id = context->id;
- if ((context->flags & CTXT_FLAGS_USER_GENERATED_TS) &&
+ if ((context && context->flags & CTXT_FLAGS_USER_GENERATED_TS) &&
(!(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE))) {
if (timestamp_cmp(rb->timestamp[context_id],
timestamp) >= 0) {
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index e61b040..deafa7a 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -28,6 +28,7 @@
#include <linux/msm_ion.h>
#include <linux/io.h>
#include <mach/socinfo.h>
+#include <linux/mman.h>
#include "kgsl.h"
#include "kgsl_debugfs.h"
@@ -323,9 +324,19 @@
}
EXPORT_SYMBOL(kgsl_mem_entry_destroy);
-static
-void kgsl_mem_entry_attach_process(struct kgsl_mem_entry *entry,
- struct kgsl_process_private *process)
+/**
+ * kgsl_mem_entry_track_gpuaddr - Insert a mem_entry in the address tree
+ * @process: the process that owns the memory
+ * @entry: the memory entry
+ *
+ * Insert a kgsl_mem_entry in to the rb_tree for searching by GPU address.
+ * Not all mem_entries will have gpu addresses when first created, so this
+ * function may be called after creation when the GPU address is finally
+ * assigned.
+ */
+static void
+kgsl_mem_entry_track_gpuaddr(struct kgsl_process_private *process,
+ struct kgsl_mem_entry *entry)
{
struct rb_node **node;
struct rb_node *parent = NULL;
@@ -350,8 +361,48 @@
rb_insert_color(&entry->node, &process->mem_rb);
spin_unlock(&process->mem_lock);
+}
+/**
+ * kgsl_mem_entry_attach_process - Attach a mem_entry to its owner process
+ * @entry: the memory entry
+ * @process: the owner process
+ *
+ * Attach a newly created mem_entry to its owner process so that
+ * it can be found later. The mem_entry will be added to mem_idr and have
+ * its 'id' field assigned. If the GPU address has been set, the entry
+ * will also be added to the mem_rb tree.
+ *
+ * @returns - 0 on success or error code on failure.
+ */
+static int
+kgsl_mem_entry_attach_process(struct kgsl_mem_entry *entry,
+ struct kgsl_process_private *process)
+{
+ int ret;
+
+ while (1) {
+ if (idr_pre_get(&process->mem_idr, GFP_KERNEL) == 0) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ spin_lock(&process->mem_lock);
+ ret = idr_get_new_above(&process->mem_idr, entry, 1,
+ &entry->id);
+ spin_unlock(&process->mem_lock);
+
+ if (ret == 0)
+ break;
+ else if (ret != -EAGAIN)
+ goto err;
+ }
entry->priv = process;
+
+ if (entry->memdesc.gpuaddr != 0)
+ kgsl_mem_entry_track_gpuaddr(process, entry);
+err:
+ return ret;
}
/* Detach a memory entry from a process and unmap it from the MMU */
@@ -361,6 +412,17 @@
if (entry == NULL)
return;
+ spin_lock(&entry->priv->mem_lock);
+
+ if (entry->id != 0)
+ idr_remove(&entry->priv->mem_idr, entry->id);
+ entry->id = 0;
+
+ if (entry->memdesc.gpuaddr != 0)
+ rb_erase(&entry->node, &entry->priv->mem_rb);
+
+ spin_unlock(&entry->priv->mem_lock);
+
entry->priv->stats[entry->memtype].cur -= entry->memdesc.size;
entry->priv = NULL;
@@ -777,6 +839,8 @@
private->pid = task_tgid_nr(current);
private->mem_rb = RB_ROOT;
+ idr_init(&private->mem_idr);
+
if (kgsl_mmu_enabled())
{
unsigned long pt_name;
@@ -805,7 +869,7 @@
struct kgsl_process_private *private)
{
struct kgsl_mem_entry *entry = NULL;
- struct rb_node *node;
+ int next = 0;
if (!private)
return;
@@ -820,14 +884,22 @@
list_del(&private->list);
- for (node = rb_first(&private->mem_rb); node; ) {
- entry = rb_entry(node, struct kgsl_mem_entry, node);
- node = rb_next(&entry->node);
-
- rb_erase(&entry->node, &private->mem_rb);
+ while (1) {
+ rcu_read_lock();
+ entry = idr_get_next(&private->mem_idr, &next);
+ rcu_read_unlock();
+ if (entry == NULL)
+ break;
kgsl_mem_entry_detach_process(entry);
+ /*
+ * Always start back at the beginning, to
+ * ensure all entries are removed,
+ * like list_for_each_entry_safe.
+ */
+ next = 0;
}
kgsl_mmu_putpagetable(private->pagetable);
+ idr_destroy(&private->mem_idr);
kfree(private);
unlock:
mutex_unlock(&kgsl_driver.process_mutex);
@@ -1006,6 +1078,77 @@
return kgsl_sharedmem_find_region(private, gpuaddr, 1);
}
+/**
+ * kgsl_sharedmem_region_empty - Check if an addression region is empty
+ *
+ * @private: private data for the process to check.
+ * @gpuaddr: start address of the region
+ * @size: length of the region.
+ *
+ * Checks that there are no existing allocations within an address
+ * region. Note that unlike other kgsl_sharedmem* search functions,
+ * this one manages locking on its own.
+ */
+int
+kgsl_sharedmem_region_empty(struct kgsl_process_private *private,
+ unsigned int gpuaddr, size_t size)
+{
+ int result = 1;
+ unsigned int gpuaddr_end = gpuaddr + size;
+
+ struct rb_node *node = private->mem_rb.rb_node;
+
+ if (!kgsl_mmu_gpuaddr_in_range(gpuaddr))
+ return 0;
+
+ /* don't overflow */
+ if (gpuaddr_end < gpuaddr)
+ return 0;
+
+ spin_lock(&private->mem_lock);
+ node = private->mem_rb.rb_node;
+ while (node != NULL) {
+ struct kgsl_mem_entry *entry;
+ unsigned int memdesc_start, memdesc_end;
+
+ entry = rb_entry(node, struct kgsl_mem_entry, node);
+
+ memdesc_start = entry->memdesc.gpuaddr;
+ memdesc_end = memdesc_start
+ + kgsl_memdesc_mmapsize(&entry->memdesc);
+
+ if (gpuaddr_end <= memdesc_start)
+ node = node->rb_left;
+ else if (memdesc_end <= gpuaddr)
+ node = node->rb_right;
+ else {
+ result = 0;
+ break;
+ }
+ }
+ spin_unlock(&private->mem_lock);
+ return result;
+}
+
+/**
+ * kgsl_sharedmem_find_id - find a memory entry by id
+ * @process: the owning process
+ * @id: id to find
+ *
+ * @returns - the mem_entry or NULL
+ */
+static inline struct kgsl_mem_entry *
+kgsl_sharedmem_find_id(struct kgsl_process_private *process, unsigned int id)
+{
+ struct kgsl_mem_entry *entry;
+
+ rcu_read_lock();
+ entry = idr_find(&process->mem_idr, id);
+ rcu_read_unlock();
+
+ return entry;
+}
+
/*call all ioctl sub functions with driver locked*/
static long kgsl_ioctl_device_getproperty(struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data)
@@ -1293,9 +1436,6 @@
void *priv, u32 id, u32 timestamp)
{
struct kgsl_mem_entry *entry = priv;
- spin_lock(&entry->priv->mem_lock);
- rb_erase(&entry->node, &entry->priv->mem_rb);
- spin_unlock(&entry->priv->mem_lock);
trace_kgsl_mem_timestamp_free(device, entry, id, timestamp, 0);
kgsl_mem_entry_detach_process(entry);
}
@@ -1407,34 +1547,52 @@
static long kgsl_ioctl_sharedmem_free(struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data)
{
- int result = 0;
struct kgsl_sharedmem_free *param = data;
struct kgsl_process_private *private = dev_priv->process_priv;
struct kgsl_mem_entry *entry = NULL;
spin_lock(&private->mem_lock);
entry = kgsl_sharedmem_find(private, param->gpuaddr);
- if (entry)
- rb_erase(&entry->node, &private->mem_rb);
-
spin_unlock(&private->mem_lock);
- if (entry) {
- trace_kgsl_mem_free(entry);
-
- kgsl_memfree_hist_set_event(
- entry->priv->pid,
- entry->memdesc.gpuaddr,
- entry->memdesc.size,
- entry->memdesc.flags);
-
- kgsl_mem_entry_detach_process(entry);
- } else {
- KGSL_CORE_ERR("invalid gpuaddr %08x\n", param->gpuaddr);
- result = -EINVAL;
+ if (!entry) {
+ KGSL_MEM_INFO(dev_priv->device, "invalid gpuaddr %08x\n",
+ param->gpuaddr);
+ return -EINVAL;
}
+ trace_kgsl_mem_free(entry);
- return result;
+ kgsl_memfree_hist_set_event(entry->priv->pid,
+ entry->memdesc.gpuaddr,
+ entry->memdesc.size,
+ entry->memdesc.flags);
+
+ kgsl_mem_entry_detach_process(entry);
+ return 0;
+}
+
+static long kgsl_ioctl_gpumem_free_id(struct kgsl_device_private *dev_priv,
+ unsigned int cmd, void *data)
+{
+ struct kgsl_gpumem_free_id *param = data;
+ struct kgsl_process_private *private = dev_priv->process_priv;
+ struct kgsl_mem_entry *entry = NULL;
+
+ entry = kgsl_sharedmem_find_id(private, param->id);
+
+ if (!entry) {
+ KGSL_MEM_INFO(dev_priv->device, "invalid id %d\n", param->id);
+ return -EINVAL;
+ }
+ trace_kgsl_mem_free(entry);
+
+ kgsl_memfree_hist_set_event(entry->priv->pid,
+ entry->memdesc.gpuaddr,
+ entry->memdesc.size,
+ entry->memdesc.flags);
+
+ kgsl_mem_entry_detach_process(entry);
+ return 0;
}
static struct vm_area_struct *kgsl_get_vma_from_start_addr(unsigned int addr)
@@ -1543,6 +1701,8 @@
entry->memdesc.size = size;
entry->memdesc.physaddr = phys + offset;
entry->memdesc.hostptr = (void *) (virt + offset);
+ /* USE_CPU_MAP is not impemented for PMEM. */
+ entry->memdesc.flags &= ~KGSL_MEMFLAGS_USE_CPU_MAP;
ret = memdesc_sg_phys(&entry->memdesc, phys + offset, size);
if (ret)
@@ -1659,6 +1819,8 @@
entry->memdesc.pagetable = pagetable;
entry->memdesc.size = size;
entry->memdesc.useraddr = useraddr + (offset & PAGE_MASK);
+ if (kgsl_memdesc_use_cpu_map(&entry->memdesc))
+ entry->memdesc.gpuaddr = entry->memdesc.useraddr;
return memdesc_sg_virt(&entry->memdesc, entry->memdesc.useraddr,
size);
@@ -1711,6 +1873,8 @@
entry->memdesc.pagetable = pagetable;
entry->memdesc.size = ALIGN(size, PAGE_SIZE);
entry->memdesc.useraddr = useraddr;
+ if (kgsl_memdesc_use_cpu_map(&entry->memdesc))
+ entry->memdesc.gpuaddr = entry->memdesc.useraddr;
ret = memdesc_sg_virt(&entry->memdesc, useraddr, size);
if (ret)
@@ -1756,6 +1920,8 @@
entry->priv_data = handle;
entry->memdesc.pagetable = pagetable;
entry->memdesc.size = 0;
+ /* USE_CPU_MAP is not impemented for ION. */
+ entry->memdesc.flags &= ~KGSL_MEMFLAGS_USE_CPU_MAP;
sg_table = ion_sg_table(kgsl_ion_client, handle);
@@ -1779,6 +1945,13 @@
return -ENOMEM;
}
+static inline int
+can_use_cpu_map(void)
+{
+ return (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_IOMMU
+ && kgsl_mmu_is_perprocess());
+}
+
static long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data)
{
@@ -1798,7 +1971,20 @@
else
memtype = param->memtype;
+ /*
+ * Mask off unknown flags from userspace. This way the caller can
+ * check if a flag is supported by looking at the returned flags.
+ * Note: CACHEMODE is ignored for this call. Caching should be
+ * determined by type of allocation being mapped.
+ */
+ param->flags &= KGSL_MEMFLAGS_GPUREADONLY
+ | KGSL_MEMTYPE_MASK
+ | KGSL_MEMALIGN_MASK
+ | KGSL_MEMFLAGS_USE_CPU_MAP;
+
entry->memdesc.flags = param->flags;
+ if (!can_use_cpu_map())
+ entry->memdesc.flags &= ~KGSL_MEMFLAGS_USE_CPU_MAP;
switch (memtype) {
case KGSL_USER_MEM_TYPE_PMEM:
@@ -1872,18 +2058,25 @@
/* Adjust the returned value for a non 4k aligned offset */
param->gpuaddr = entry->memdesc.gpuaddr + (param->offset & ~PAGE_MASK);
+ /* echo back flags */
+ param->flags = entry->memdesc.flags;
+
+ result = kgsl_mem_entry_attach_process(entry, private);
+ if (result)
+ goto error_unmap;
KGSL_STATS_ADD(param->len, kgsl_driver.stats.mapped,
kgsl_driver.stats.mapped_max);
kgsl_process_add_stats(private, entry->memtype, param->len);
- kgsl_mem_entry_attach_process(entry, private);
trace_kgsl_mem_map(entry, param->fd);
kgsl_check_idle(dev_priv->device);
return result;
+error_unmap:
+ kgsl_mmu_unmap(private->pagetable, &entry->memdesc);
error_put_file_ptr:
switch (entry->memtype) {
case KGSL_MEM_ENTRY_PMEM:
@@ -1903,33 +2096,134 @@
return result;
}
-/*This function flushes a graphics memory allocation from CPU cache
- *when caching is enabled with MMU*/
+static int _kgsl_gpumem_sync_cache(struct kgsl_mem_entry *entry, int op)
+{
+ int ret = 0;
+ int cacheop;
+ int mode;
+
+ /*
+ * Flush is defined as (clean | invalidate). If both bits are set, then
+ * do a flush, otherwise check for the individual bits and clean or inv
+ * as requested
+ */
+
+ if ((op & KGSL_GPUMEM_CACHE_FLUSH) == KGSL_GPUMEM_CACHE_FLUSH)
+ cacheop = KGSL_CACHE_OP_FLUSH;
+ else if (op & KGSL_GPUMEM_CACHE_CLEAN)
+ cacheop = KGSL_CACHE_OP_CLEAN;
+ else if (op & KGSL_GPUMEM_CACHE_INV)
+ cacheop = KGSL_CACHE_OP_INV;
+ else {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ mode = kgsl_memdesc_get_cachemode(&entry->memdesc);
+ if (mode != KGSL_CACHEMODE_UNCACHED
+ && mode != KGSL_CACHEMODE_WRITECOMBINE)
+ kgsl_cache_range_op(&entry->memdesc, cacheop);
+
+done:
+ return ret;
+}
+
+/* New cache sync function - supports both directions (clean and invalidate) */
+
+static long
+kgsl_ioctl_gpumem_sync_cache(struct kgsl_device_private *dev_priv,
+ unsigned int cmd, void *data)
+{
+ struct kgsl_gpumem_sync_cache *param = data;
+ struct kgsl_process_private *private = dev_priv->process_priv;
+ struct kgsl_mem_entry *entry = NULL;
+
+ if (param->id != 0) {
+ entry = kgsl_sharedmem_find_id(private, param->id);
+ if (entry == NULL) {
+ KGSL_MEM_INFO(dev_priv->device, "can't find id %d\n",
+ param->id);
+ return -EINVAL;
+ }
+ } else if (param->gpuaddr != 0) {
+ spin_lock(&private->mem_lock);
+ entry = kgsl_sharedmem_find(private, param->gpuaddr);
+ spin_unlock(&private->mem_lock);
+ if (entry == NULL) {
+ KGSL_MEM_INFO(dev_priv->device,
+ "can't find gpuaddr %x\n",
+ param->gpuaddr);
+ return -EINVAL;
+ }
+ } else {
+ return -EINVAL;
+ }
+
+ return _kgsl_gpumem_sync_cache(entry, param->op);
+}
+
+/* Legacy cache function, does a flush (clean + invalidate) */
+
static long
kgsl_ioctl_sharedmem_flush_cache(struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data)
{
- int result = 0;
- struct kgsl_mem_entry *entry;
struct kgsl_sharedmem_free *param = data;
struct kgsl_process_private *private = dev_priv->process_priv;
+ struct kgsl_mem_entry *entry = NULL;
spin_lock(&private->mem_lock);
entry = kgsl_sharedmem_find(private, param->gpuaddr);
- if (!entry) {
- KGSL_CORE_ERR("invalid gpuaddr %08x\n", param->gpuaddr);
- result = -EINVAL;
- goto done;
- }
- if (!entry->memdesc.hostptr) {
- KGSL_CORE_ERR("invalid hostptr with gpuaddr %08x\n",
- param->gpuaddr);
- goto done;
+ spin_unlock(&private->mem_lock);
+ if (entry == NULL) {
+ KGSL_MEM_INFO(dev_priv->device,
+ "can't find gpuaddr %x\n",
+ param->gpuaddr);
+ return -EINVAL;
}
- kgsl_cache_range_op(&entry->memdesc, KGSL_CACHE_OP_CLEAN);
-done:
- spin_unlock(&private->mem_lock);
+ return _kgsl_gpumem_sync_cache(entry, KGSL_GPUMEM_CACHE_FLUSH);
+}
+
+/*
+ * The common parts of kgsl_ioctl_gpumem_alloc and kgsl_ioctl_gpumem_alloc_id.
+ */
+int
+_gpumem_alloc(struct kgsl_device_private *dev_priv,
+ struct kgsl_mem_entry **ret_entry,
+ unsigned int size, unsigned int flags)
+{
+ int result;
+ struct kgsl_process_private *private = dev_priv->process_priv;
+ struct kgsl_mem_entry *entry;
+
+ /*
+ * Mask off unknown flags from userspace. This way the caller can
+ * check if a flag is supported by looking at the returned flags.
+ */
+ flags &= KGSL_MEMFLAGS_GPUREADONLY
+ | KGSL_CACHEMODE_MASK
+ | KGSL_MEMTYPE_MASK
+ | KGSL_MEMALIGN_MASK
+ | KGSL_MEMFLAGS_USE_CPU_MAP;
+
+ entry = kgsl_mem_entry_create();
+ if (entry == NULL)
+ return -ENOMEM;
+
+ result = kgsl_allocate_user(&entry->memdesc, private->pagetable, size,
+ flags);
+ if (result != 0)
+ goto err;
+
+ entry->memtype = KGSL_MEM_ENTRY_KERNEL;
+
+ kgsl_check_idle(dev_priv->device);
+ *ret_entry = entry;
+ return result;
+err:
+ kfree(entry);
+ *ret_entry = NULL;
return result;
}
@@ -1939,29 +2233,117 @@
{
struct kgsl_process_private *private = dev_priv->process_priv;
struct kgsl_gpumem_alloc *param = data;
- struct kgsl_mem_entry *entry;
+ struct kgsl_mem_entry *entry = NULL;
int result;
- entry = kgsl_mem_entry_create();
- if (entry == NULL)
- return -ENOMEM;
+ param->flags &= ~KGSL_MEMFLAGS_USE_CPU_MAP;
+ result = _gpumem_alloc(dev_priv, &entry, param->size, param->flags);
+ if (result)
+ return result;
- result = kgsl_allocate_user(&entry->memdesc, private->pagetable,
- param->size, param->flags);
+ result = kgsl_mmu_map(private->pagetable, &entry->memdesc,
+ kgsl_memdesc_protflags(&entry->memdesc));
+ if (result)
+ goto err;
- if (result == 0) {
- entry->memtype = KGSL_MEM_ENTRY_KERNEL;
- kgsl_mem_entry_attach_process(entry, private);
- param->gpuaddr = entry->memdesc.gpuaddr;
+ result = kgsl_mem_entry_attach_process(entry, private);
+ if (result != 0)
+ goto err;
- kgsl_process_add_stats(private, entry->memtype, param->size);
- trace_kgsl_mem_alloc(entry);
- } else
- kfree(entry);
+ kgsl_process_add_stats(private, entry->memtype, param->size);
+ trace_kgsl_mem_alloc(entry);
- kgsl_check_idle(dev_priv->device);
+ param->gpuaddr = entry->memdesc.gpuaddr;
+ param->size = entry->memdesc.size;
+ param->flags = entry->memdesc.flags;
+ return result;
+err:
+ kgsl_sharedmem_free(&entry->memdesc);
+ kfree(entry);
return result;
}
+
+static long
+kgsl_ioctl_gpumem_alloc_id(struct kgsl_device_private *dev_priv,
+ unsigned int cmd, void *data)
+{
+ struct kgsl_process_private *private = dev_priv->process_priv;
+ struct kgsl_gpumem_alloc_id *param = data;
+ struct kgsl_mem_entry *entry = NULL;
+ int result;
+
+ if (!can_use_cpu_map())
+ param->flags &= ~KGSL_MEMFLAGS_USE_CPU_MAP;
+
+ result = _gpumem_alloc(dev_priv, &entry, param->size, param->flags);
+ if (result != 0)
+ goto err;
+
+ if (!kgsl_memdesc_use_cpu_map(&entry->memdesc)) {
+ result = kgsl_mmu_map(private->pagetable, &entry->memdesc,
+ kgsl_memdesc_protflags(&entry->memdesc));
+ if (result)
+ goto err;
+ }
+
+ result = kgsl_mem_entry_attach_process(entry, private);
+ if (result != 0)
+ goto err;
+
+ kgsl_process_add_stats(private, entry->memtype, param->size);
+ trace_kgsl_mem_alloc(entry);
+
+ param->id = entry->id;
+ param->flags = entry->memdesc.flags;
+ param->size = entry->memdesc.size;
+ param->mmapsize = kgsl_memdesc_mmapsize(&entry->memdesc);
+ param->gpuaddr = entry->memdesc.gpuaddr;
+ return result;
+err:
+ if (entry)
+ kgsl_sharedmem_free(&entry->memdesc);
+ kfree(entry);
+ return result;
+}
+
+static long
+kgsl_ioctl_gpumem_get_info(struct kgsl_device_private *dev_priv,
+ unsigned int cmd, void *data)
+{
+ struct kgsl_process_private *private = dev_priv->process_priv;
+ struct kgsl_gpumem_get_info *param = data;
+ struct kgsl_mem_entry *entry = NULL;
+ int result = 0;
+
+ if (param->id != 0) {
+ entry = kgsl_sharedmem_find_id(private, param->id);
+ if (entry == NULL) {
+ KGSL_MEM_INFO(dev_priv->device, "can't find id %d\n",
+ param->id);
+ return -EINVAL;
+ }
+ } else if (param->gpuaddr != 0) {
+ spin_lock(&private->mem_lock);
+ entry = kgsl_sharedmem_find(private, param->gpuaddr);
+ spin_unlock(&private->mem_lock);
+ if (entry == NULL) {
+ KGSL_MEM_INFO(dev_priv->device,
+ "can't find gpuaddr %lx\n",
+ param->gpuaddr);
+ return -EINVAL;
+ }
+ } else {
+ return -EINVAL;
+ }
+ param->gpuaddr = entry->memdesc.gpuaddr;
+ param->id = entry->id;
+ param->flags = entry->memdesc.flags;
+ param->size = entry->memdesc.size;
+ param->mmapsize = kgsl_memdesc_mmapsize(&entry->memdesc);
+ param->useraddr = entry->memdesc.useraddr;
+ return result;
+}
+
static long kgsl_ioctl_cff_syncmem(struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data)
{
@@ -2161,6 +2543,14 @@
kgsl_ioctl_timestamp_event, 1),
KGSL_IOCTL_FUNC(IOCTL_KGSL_SETPROPERTY,
kgsl_ioctl_device_setproperty, 1),
+ KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_ALLOC_ID,
+ kgsl_ioctl_gpumem_alloc_id, 0),
+ KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_FREE_ID,
+ kgsl_ioctl_gpumem_free_id, 0),
+ KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_GET_INFO,
+ kgsl_ioctl_gpumem_get_info, 0),
+ KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_SYNC_CACHE,
+ kgsl_ioctl_gpumem_sync_cache, 0),
};
static long kgsl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
@@ -2328,33 +2718,26 @@
.close = kgsl_gpumem_vm_close,
};
-static int kgsl_mmap(struct file *file, struct vm_area_struct *vma)
+static int
+get_mmap_entry(struct kgsl_process_private *private,
+ struct kgsl_mem_entry **out_entry, unsigned long pgoff,
+ unsigned long len)
{
- unsigned int ret;
- unsigned long vma_offset = vma->vm_pgoff << PAGE_SHIFT;
- struct kgsl_device_private *dev_priv = file->private_data;
- struct kgsl_process_private *private = dev_priv->process_priv;
- struct kgsl_mem_entry *entry = NULL;
- struct kgsl_device *device = dev_priv->device;
+ int ret = -EINVAL;
+ struct kgsl_mem_entry *entry;
- /* Handle leagacy behavior for memstore */
+ entry = kgsl_sharedmem_find_id(private, pgoff);
+ if (entry == NULL) {
+ spin_lock(&private->mem_lock);
+ entry = kgsl_sharedmem_find(private, pgoff << PAGE_SHIFT);
+ spin_unlock(&private->mem_lock);
+ }
- if (vma_offset == device->memstore.gpuaddr)
- return kgsl_mmap_memstore(device, vma);
-
- /* Find a chunk of GPU memory */
-
- spin_lock(&private->mem_lock);
- entry = kgsl_sharedmem_find(private, vma_offset);
-
- if (entry)
- kgsl_mem_entry_get(entry);
-
- spin_unlock(&private->mem_lock);
-
- if (entry == NULL)
+ if (!entry)
return -EINVAL;
+ kgsl_mem_entry_get(entry);
+
if (!entry->memdesc.ops ||
!entry->memdesc.ops->vmflags ||
!entry->memdesc.ops->vmfault) {
@@ -2367,24 +2750,173 @@
goto err_put;
}
- if (entry->memdesc.size != (vma->vm_end - vma->vm_start)) {
+ if (len != kgsl_memdesc_mmapsize(&entry->memdesc)) {
ret = -ERANGE;
goto err_put;
}
+ *out_entry = entry;
+ return 0;
+err_put:
+ kgsl_mem_entry_put(entry);
+ return ret;
+}
+
+static unsigned long
+kgsl_get_unmapped_area(struct file *file, unsigned long addr,
+ unsigned long len, unsigned long pgoff,
+ unsigned long flags)
+{
+ unsigned long ret = 0;
+ unsigned long vma_offset = pgoff << PAGE_SHIFT;
+ struct kgsl_device_private *dev_priv = file->private_data;
+ struct kgsl_process_private *private = dev_priv->process_priv;
+ struct kgsl_device *device = dev_priv->device;
+ struct kgsl_mem_entry *entry = NULL;
+ unsigned int align;
+ unsigned int retry = 0;
+
+ if (vma_offset == device->memstore.gpuaddr)
+ return get_unmapped_area(NULL, addr, len, pgoff, flags);
+
+ ret = get_mmap_entry(private, &entry, pgoff, len);
+ if (ret)
+ return ret;
+
+ if (!kgsl_memdesc_use_cpu_map(&entry->memdesc) || (flags & MAP_FIXED)) {
+ /*
+ * If we're not going to use the same mapping on the gpu,
+ * any address is fine.
+ * For MAP_FIXED, hopefully the caller knows what they're doing,
+ * but we may fail in mmap() if there is already something
+ * at the virtual address chosen.
+ */
+ ret = get_unmapped_area(NULL, addr, len, pgoff, flags);
+ goto put;
+ }
+ if (entry->memdesc.gpuaddr != 0) {
+ KGSL_MEM_INFO(device,
+ "pgoff %lx already mapped to gpuaddr %x\n",
+ pgoff, entry->memdesc.gpuaddr);
+ ret = -EBUSY;
+ goto put;
+ }
+
+ align = kgsl_memdesc_get_align(&entry->memdesc);
+ if (align >= ilog2(SZ_1M))
+ align = ilog2(SZ_1M);
+ else if (align >= ilog2(SZ_64K))
+ align = ilog2(SZ_64K);
+ else if (align <= PAGE_SHIFT)
+ align = 0;
+
+ if (align)
+ len += 1 << align;
+ do {
+ ret = get_unmapped_area(NULL, addr, len, pgoff, flags);
+ if (IS_ERR_VALUE(ret))
+ break;
+ if (align)
+ ret = ALIGN(ret, (1 << align));
+
+ /*make sure there isn't a GPU only mapping at this address */
+ if (kgsl_sharedmem_region_empty(private, ret, len))
+ break;
+
+ trace_kgsl_mem_unmapped_area_collision(entry, addr, len, ret);
+
+ /*
+ * If we collided, bump the hint address so that
+ * get_umapped_area knows to look somewhere else.
+ */
+ addr = (addr == 0) ? ret + len : addr + len;
+
+ /*
+ * The addr hint can be set by userspace to be near
+ * the end of the address space. Make sure we search
+ * the whole address space at least once by wrapping
+ * back around once.
+ */
+ if (!retry && (addr + len >= TASK_SIZE)) {
+ addr = 0;
+ retry = 1;
+ } else {
+ ret = -EBUSY;
+ }
+ } while (addr + len < TASK_SIZE);
+
+ if (IS_ERR_VALUE(ret))
+ KGSL_MEM_INFO(device,
+ "pid %d pgoff %lx len %ld failed error %ld\n",
+ private->pid, pgoff, len, ret);
+put:
+ kgsl_mem_entry_put(entry);
+ return ret;
+}
+
+static int kgsl_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ unsigned int ret, cache;
+ unsigned long vma_offset = vma->vm_pgoff << PAGE_SHIFT;
+ struct kgsl_device_private *dev_priv = file->private_data;
+ struct kgsl_process_private *private = dev_priv->process_priv;
+ struct kgsl_mem_entry *entry = NULL;
+ struct kgsl_device *device = dev_priv->device;
+
+ /* Handle leagacy behavior for memstore */
+
+ if (vma_offset == device->memstore.gpuaddr)
+ return kgsl_mmap_memstore(device, vma);
+
+ ret = get_mmap_entry(private, &entry, vma->vm_pgoff,
+ vma->vm_end - vma->vm_start);
+ if (ret)
+ return ret;
+
+ if (kgsl_memdesc_use_cpu_map(&entry->memdesc)) {
+ entry->memdesc.gpuaddr = vma->vm_start;
+
+ ret = kgsl_mmu_map(private->pagetable, &entry->memdesc,
+ kgsl_memdesc_protflags(&entry->memdesc));
+ if (ret) {
+ kgsl_mem_entry_put(entry);
+ return ret;
+ }
+ kgsl_mem_entry_track_gpuaddr(private, entry);
+ }
+
vma->vm_flags |= entry->memdesc.ops->vmflags(&entry->memdesc);
vma->vm_private_data = entry;
- vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+ /* Determine user-side caching policy */
+
+ cache = kgsl_memdesc_get_cachemode(&entry->memdesc);
+
+ switch (cache) {
+ case KGSL_CACHEMODE_UNCACHED:
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ break;
+ case KGSL_CACHEMODE_WRITETHROUGH:
+ vma->vm_page_prot = pgprot_writethroughcache(vma->vm_page_prot);
+ break;
+ case KGSL_CACHEMODE_WRITEBACK:
+ vma->vm_page_prot = pgprot_writebackcache(vma->vm_page_prot);
+ break;
+ case KGSL_CACHEMODE_WRITECOMBINE:
+ default:
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+ break;
+ }
+
vma->vm_ops = &kgsl_gpumem_vm_ops;
vma->vm_file = file;
entry->memdesc.useraddr = vma->vm_start;
+ trace_kgsl_mem_mmap(entry);
+
return 0;
-err_put:
- kgsl_mem_entry_put(entry);
- return ret;
}
static irqreturn_t kgsl_irq_handler(int irq, void *data)
@@ -2400,6 +2932,7 @@
.release = kgsl_release,
.open = kgsl_open,
.mmap = kgsl_mmap,
+ .get_unmapped_area = kgsl_get_unmapped_area,
.unlocked_ioctl = kgsl_ioctl,
};
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index d22cb6d..72e7776 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -185,6 +185,7 @@
int flags;
void *priv_data;
struct rb_node node;
+ unsigned int id;
unsigned int context_id;
/* back pointer to private structure under whose context this
* allocation is made */
@@ -241,6 +242,10 @@
static inline int kgsl_gpuaddr_in_memdesc(const struct kgsl_memdesc *memdesc,
unsigned int gpuaddr, unsigned int size)
{
+ /* don't overflow */
+ if ((gpuaddr + size) < gpuaddr)
+ return 0;
+
if (gpuaddr >= memdesc->gpuaddr &&
((gpuaddr + size) <= (memdesc->gpuaddr + memdesc->size))) {
return 1;
diff --git a/drivers/gpu/msm/kgsl_debugfs.c b/drivers/gpu/msm/kgsl_debugfs.c
index 07a5ff4..3bc107f 100644
--- a/drivers/gpu/msm/kgsl_debugfs.c
+++ b/drivers/gpu/msm/kgsl_debugfs.c
@@ -221,35 +221,70 @@
return '-';
}
+static char get_cacheflag(const struct kgsl_memdesc *m)
+{
+ static const char table[] = {
+ [KGSL_CACHEMODE_WRITECOMBINE] = '-',
+ [KGSL_CACHEMODE_UNCACHED] = 'u',
+ [KGSL_CACHEMODE_WRITEBACK] = 'b',
+ [KGSL_CACHEMODE_WRITETHROUGH] = 't',
+ };
+ return table[kgsl_memdesc_get_cachemode(m)];
+}
+
+static void print_mem_entry(struct seq_file *s, struct kgsl_mem_entry *entry)
+{
+ char flags[6];
+ char usage[16];
+ struct kgsl_memdesc *m = &entry->memdesc;
+
+ flags[0] = kgsl_memdesc_is_global(m) ? 'g' : '-';
+ flags[1] = m->flags & KGSL_MEMFLAGS_GPUREADONLY ? 'r' : '-';
+ flags[2] = get_alignflag(m);
+ flags[3] = get_cacheflag(m);
+ flags[4] = kgsl_memdesc_use_cpu_map(m) ? 'p' : '-';
+ flags[5] = '\0';
+
+ kgsl_get_memory_usage(usage, sizeof(usage), m->flags);
+
+ seq_printf(s, "%08x %8d %5d %5s %10s %16s %5d\n",
+ m->gpuaddr, m->size, entry->id, flags,
+ memtype_str(entry->memtype), usage, m->sglen);
+}
+
static int process_mem_print(struct seq_file *s, void *unused)
{
struct kgsl_mem_entry *entry;
struct rb_node *node;
struct kgsl_process_private *private = s->private;
- char flags[4];
- char usage[16];
+ int next = 0;
+ seq_printf(s, "%8s %8s %5s %5s %10s %16s %5s\n",
+ "gpuaddr", "size", "id", "flags", "type", "usage", "sglen");
+
+ /* print all entries with a GPU address */
spin_lock(&private->mem_lock);
- seq_printf(s, "%8s %8s %5s %10s %16s %5s\n",
- "gpuaddr", "size", "flags", "type", "usage", "sglen");
+
for (node = rb_first(&private->mem_rb); node; node = rb_next(node)) {
- struct kgsl_memdesc *m;
-
entry = rb_entry(node, struct kgsl_mem_entry, node);
- m = &entry->memdesc;
-
- flags[0] = kgsl_memdesc_is_global(m) ? 'g' : '-';
- flags[1] = m->flags & KGSL_MEMFLAGS_GPUREADONLY ? 'r' : '-';
- flags[2] = get_alignflag(m);
- flags[3] = '\0';
-
- kgsl_get_memory_usage(usage, sizeof(usage), m->flags);
-
- seq_printf(s, "%08x %8d %5s %10s %16s %5d\n",
- m->gpuaddr, m->size, flags,
- memtype_str(entry->memtype), usage, m->sglen);
+ print_mem_entry(s, entry);
}
+
spin_unlock(&private->mem_lock);
+
+ /* now print all the unbound entries */
+ while (1) {
+ rcu_read_lock();
+ entry = idr_get_next(&private->mem_idr, &next);
+ rcu_read_unlock();
+
+ if (entry == NULL)
+ break;
+ if (entry->memdesc.gpuaddr == 0)
+ print_mem_entry(s, entry);
+ next++;
+ }
+
return 0;
}
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 35ffc1b..ce3820c 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -268,6 +268,7 @@
pid_t pid;
spinlock_t mem_lock;
struct rb_root mem_rb;
+ struct idr mem_idr;
struct kgsl_pagetable *pagetable;
struct list_head list;
struct kobject kobj;
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 1bccd4d..31491d5 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -897,8 +897,6 @@
kgsl_regwrite(mmu->device, MH_MMU_MPU_END,
mh->mpu_base + mh->mpu_range);
- } else {
- kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
}
mmu->hwpagetable = mmu->defaultpagetable;
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index bf39587..533f02f 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -27,9 +27,6 @@
#include "kgsl_sharedmem.h"
#include "adreno.h"
-#define KGSL_MMU_ALIGN_SHIFT 13
-#define KGSL_MMU_ALIGN_MASK (~((1 << KGSL_MMU_ALIGN_SHIFT) - 1))
-
static enum kgsl_mmutype kgsl_mmu_type;
static void pagetable_remove_sysfs_objects(struct kgsl_pagetable *pagetable);
@@ -447,10 +444,10 @@
if ((KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype()) &&
((KGSL_MMU_GLOBAL_PT == name) ||
(KGSL_MMU_PRIV_BANK_TABLE_NAME == name))) {
- pagetable->kgsl_pool = gen_pool_create(PAGE_SHIFT, -1);
+ pagetable->kgsl_pool = gen_pool_create(ilog2(SZ_8K), -1);
if (pagetable->kgsl_pool == NULL) {
KGSL_CORE_ERR("gen_pool_create(%d) failed\n",
- KGSL_MMU_ALIGN_SHIFT);
+ ilog2(SZ_8K));
goto err_alloc;
}
if (gen_pool_add(pagetable->kgsl_pool,
@@ -461,10 +458,10 @@
}
}
- pagetable->pool = gen_pool_create(KGSL_MMU_ALIGN_SHIFT, -1);
+ pagetable->pool = gen_pool_create(PAGE_SHIFT, -1);
if (pagetable->pool == NULL) {
KGSL_CORE_ERR("gen_pool_create(%d) failed\n",
- KGSL_MMU_ALIGN_SHIFT);
+ PAGE_SHIFT);
goto err_kgsl_pool;
}
@@ -585,7 +582,7 @@
unsigned int protflags)
{
int ret;
- struct gen_pool *pool;
+ struct gen_pool *pool = NULL;
int size;
int page_align = ilog2(PAGE_SIZE);
@@ -635,6 +632,10 @@
pagetable->name);
return -EINVAL;
}
+ } else if (kgsl_memdesc_use_cpu_map(memdesc)) {
+ if (memdesc->gpuaddr == 0)
+ return -EINVAL;
+ pool = NULL;
}
}
if (pool) {
@@ -715,9 +716,11 @@
pool = pagetable->pool;
- if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype()
- && kgsl_memdesc_is_global(memdesc)) {
- pool = pagetable->kgsl_pool;
+ if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype()) {
+ if (kgsl_memdesc_is_global(memdesc))
+ pool = pagetable->kgsl_pool;
+ else if (kgsl_memdesc_use_cpu_map(memdesc))
+ pool = NULL;
}
if (pool)
gen_pool_free(pool, memdesc->gpuaddr, size);
@@ -854,8 +857,13 @@
{
if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type)
return 1;
- return ((gpuaddr >= KGSL_PAGETABLE_BASE) &&
- (gpuaddr < (KGSL_PAGETABLE_BASE + kgsl_mmu_get_ptsize())));
+ if (gpuaddr >= kgsl_mmu_get_base_addr() &&
+ gpuaddr < kgsl_mmu_get_base_addr() + kgsl_mmu_get_ptsize())
+ return 1;
+ if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_IOMMU
+ && kgsl_mmu_is_perprocess())
+ return (gpuaddr > 0 && gpuaddr < TASK_SIZE);
+ return 0;
}
EXPORT_SYMBOL(kgsl_mmu_gpuaddr_in_range);
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index b8eff60..c8d637e 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -19,11 +19,10 @@
* These defines control the address range for allocations that
* are mapped into all pagetables.
*/
-#define KGSL_IOMMU_GLOBAL_MEM_BASE 0xC0000000
+#define KGSL_IOMMU_GLOBAL_MEM_BASE 0xf8000000
#define KGSL_IOMMU_GLOBAL_MEM_SIZE SZ_4M
-#define KGSL_MMU_ALIGN_SHIFT 13
-#define KGSL_MMU_ALIGN_MASK (~((1 << KGSL_MMU_ALIGN_SHIFT) - 1))
+#define KGSL_MMU_ALIGN_MASK (~((1 << PAGE_SHIFT) - 1))
/* Identifier for the global page table */
/* Per process page tables will probably pass in the thread group
@@ -350,32 +349,52 @@
/*
* kgsl_mmu_base_addr() - Get gpu virtual address base.
*
- * Returns the start address of the gpu
- * virtual address space.
+ * Returns the start address of the allocatable gpu
+ * virtual address space. Other mappings that mirror
+ * the CPU address space are possible outside this range.
*/
static inline unsigned int kgsl_mmu_get_base_addr(void)
{
- return KGSL_PAGETABLE_BASE;
+ if (KGSL_MMU_TYPE_GPU == kgsl_mmu_get_mmutype()
+ || !kgsl_mmu_is_perprocess())
+ return KGSL_PAGETABLE_BASE;
+ /*
+ * This is the start of the kernel address
+ * space, so allocations from this range will
+ * never conflict with userpace addresses
+ */
+ return PAGE_OFFSET;
}
/*
* kgsl_mmu_get_ptsize() - Get gpu pagetable size
*
- * Returns the usable size of the gpu address space.
+ * Returns the usable size of the gpu allocatable
+ * address space.
*/
static inline unsigned int kgsl_mmu_get_ptsize(void)
{
/*
- * For IOMMU, we could do up to 4G virtual range if we wanted to, but
- * it makes more sense to return a smaller range and leave the rest of
- * the virtual range for future improvements
+ * For IOMMU per-process pagetables, the allocatable range
+ * and the kernel global range must both be outside
+ * the userspace address range. There is a 1Mb gap
+ * between these address ranges to make overrun
+ * detection easier.
+ * For the shared pagetable case use 2GB and because
+ * mirroring the CPU address space is not possible and
+ * we're better off with extra room.
*/
enum kgsl_mmutype mmu_type = kgsl_mmu_get_mmutype();
if (KGSL_MMU_TYPE_GPU == mmu_type)
return CONFIG_MSM_KGSL_PAGE_TABLE_SIZE;
- else if (KGSL_MMU_TYPE_IOMMU == mmu_type)
- return SZ_2G;
+ else if (KGSL_MMU_TYPE_IOMMU == mmu_type) {
+ if (kgsl_mmu_is_perprocess())
+ return KGSL_IOMMU_GLOBAL_MEM_BASE
+ - kgsl_mmu_get_base_addr() - SZ_1M;
+ else
+ return SZ_2G;
+ }
return 0;
}
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 27f198b..4919c24 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -113,6 +113,7 @@
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
struct kgsl_pwrlevel *pwrlevel;
int delta;
+ int level;
/* Adjust the power level to the current constraints */
new_level = _adjust_pwrlevel(pwr, new_level);
@@ -124,6 +125,16 @@
update_clk_statistics(device, true);
+ level = pwr->active_pwrlevel;
+
+ /*
+ * Set the active powerlevel first in case the clocks are off - if we
+ * don't do this then the pwrlevel change won't take effect when the
+ * clocks come back
+ */
+
+ pwr->active_pwrlevel = new_level;
+
if (test_bit(KGSL_PWRFLAGS_CLK_ON, &pwr->power_flags) ||
(device->state == KGSL_STATE_NAP)) {
@@ -141,11 +152,11 @@
* avoid glitches.
*/
- while (pwr->active_pwrlevel != new_level) {
- pwr->active_pwrlevel += delta;
+ while (level != new_level) {
+ level += delta;
clk_set_rate(pwr->grp_clks[0],
- pwr->pwrlevels[pwr->active_pwrlevel].gpu_freq);
+ pwr->pwrlevels[level].gpu_freq);
}
}
@@ -677,6 +688,9 @@
clkstats->on_time_old = on_time;
clkstats->elapsed_old = clkstats->elapsed;
clkstats->elapsed = 0;
+
+ trace_kgsl_gpubusy(device, clkstats->on_time_old,
+ clkstats->elapsed_old);
}
/* Track the amount of time the gpu is on vs the total system time. *
@@ -1259,6 +1273,7 @@
pm_qos_update_request(&device->pm_qos_req_dma,
GPU_SWFI_LATENCY);
case KGSL_STATE_ACTIVE:
+ kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
break;
default:
KGSL_PWR_WARN(device, "unhandled state %s\n",
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index be51c11..08353ee 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -511,7 +511,14 @@
void kgsl_cache_range_op(struct kgsl_memdesc *memdesc, int op)
{
- void *addr = memdesc->hostptr;
+ /*
+ * If the buffer is mapped in the kernel operate on that address
+ * otherwise use the user address
+ */
+
+ void *addr = (memdesc->hostptr) ?
+ memdesc->hostptr : (void *) memdesc->useraddr;
+
int size = memdesc->size;
if (addr != NULL) {
@@ -534,7 +541,7 @@
static int
_kgsl_sharedmem_page_alloc(struct kgsl_memdesc *memdesc,
struct kgsl_pagetable *pagetable,
- size_t size, unsigned int protflags)
+ size_t size)
{
int pcount = 0, order, ret = 0;
int j, len, page_size, sglen_alloc, sglen = 0;
@@ -548,7 +555,8 @@
page_size = (align >= ilog2(SZ_64K) && size >= SZ_64K)
? SZ_64K : PAGE_SIZE;
/* update align flags for what we actually use */
- kgsl_memdesc_set_align(memdesc, ilog2(page_size));
+ if (page_size != PAGE_SIZE)
+ kgsl_memdesc_set_align(memdesc, ilog2(page_size));
/*
* There needs to be enough room in the sg structure to be able to
@@ -698,11 +706,6 @@
outer_cache_range_op_sg(memdesc->sg, memdesc->sglen,
KGSL_CACHE_OP_FLUSH);
- ret = kgsl_mmu_map(pagetable, memdesc, protflags);
-
- if (ret)
- goto done;
-
KGSL_STATS_ADD(size, kgsl_driver.stats.page_alloc,
kgsl_driver.stats.page_alloc_max);
@@ -729,8 +732,7 @@
size = ALIGN(size, PAGE_SIZE * 2);
- ret = _kgsl_sharedmem_page_alloc(memdesc, pagetable, size,
- GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
+ ret = _kgsl_sharedmem_page_alloc(memdesc, pagetable, size);
if (!ret)
ret = kgsl_page_alloc_map_kernel(memdesc);
if (ret)
@@ -744,17 +746,7 @@
struct kgsl_pagetable *pagetable,
size_t size)
{
- unsigned int protflags;
-
- if (size == 0)
- return -EINVAL;
-
- protflags = GSL_PT_PAGE_RV;
- if (!(memdesc->flags & KGSL_MEMFLAGS_GPUREADONLY))
- protflags |= GSL_PT_PAGE_WV;
-
- return _kgsl_sharedmem_page_alloc(memdesc, pagetable, size,
- protflags);
+ return _kgsl_sharedmem_page_alloc(memdesc, pagetable, PAGE_ALIGN(size));
}
EXPORT_SYMBOL(kgsl_sharedmem_page_alloc_user);
@@ -832,12 +824,6 @@
if (result)
goto err;
- result = kgsl_mmu_map(pagetable, memdesc,
- GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
-
- if (result)
- goto err;
-
KGSL_STATS_ADD(size, kgsl_driver.stats.coherent,
kgsl_driver.stats.coherent_max);
diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h
index 53e88be..d937699 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.h
+++ b/drivers/gpu/msm/kgsl_sharedmem.h
@@ -83,6 +83,18 @@
}
/*
+ * kgsl_memdesc_get_cachemode - Get cache mode of a memdesc
+ * @memdesc: the memdesc
+ *
+ * Returns a KGSL_CACHEMODE* value.
+ */
+static inline int
+kgsl_memdesc_get_cachemode(const struct kgsl_memdesc *memdesc)
+{
+ return (memdesc->flags & KGSL_CACHEMODE_MASK) >> KGSL_CACHEMODE_SHIFT;
+}
+
+/*
* kgsl_memdesc_set_align - Set alignment flags of a memdesc
* @memdesc - the memdesc
* @align - alignment requested, as a power of 2 exponent.
@@ -168,14 +180,79 @@
return (memdesc->priv & KGSL_MEMDESC_GLOBAL) != 0;
}
+/*
+ * kgsl_memdesc_has_guard_page - is the last page a guard page?
+ * @memdesc - the memdesc
+ *
+ * Returns nonzero if there is a guard page, 0 otherwise
+ */
+static inline int
+kgsl_memdesc_has_guard_page(const struct kgsl_memdesc *memdesc)
+{
+ return (memdesc->priv & KGSL_MEMDESC_GUARD_PAGE) != 0;
+}
+
+/*
+ * kgsl_memdesc_protflags - get mmu protection flags
+ * @memdesc - the memdesc
+ * Returns a mask of GSL_PT_PAGE* values based on the
+ * memdesc flags.
+ */
+static inline unsigned int
+kgsl_memdesc_protflags(const struct kgsl_memdesc *memdesc)
+{
+ unsigned int protflags = GSL_PT_PAGE_RV;
+ if (!(memdesc->flags & KGSL_MEMFLAGS_GPUREADONLY))
+ protflags |= GSL_PT_PAGE_WV;
+ return protflags;
+}
+
+/*
+ * kgsl_memdesc_use_cpu_map - use the same virtual mapping on CPU and GPU?
+ * @memdesc - the memdesc
+ */
+static inline int
+kgsl_memdesc_use_cpu_map(const struct kgsl_memdesc *memdesc)
+{
+ return (memdesc->flags & KGSL_MEMFLAGS_USE_CPU_MAP) != 0;
+}
+
+/*
+ * kgsl_memdesc_mmapsize - get the size of the mmap region
+ * @memdesc - the memdesc
+ *
+ * The entire memdesc must be mapped. Additionally if the
+ * CPU mapping is going to be mirrored, there must be room
+ * for the guard page to be mapped so that the address spaces
+ * match up.
+ */
+static inline unsigned int
+kgsl_memdesc_mmapsize(const struct kgsl_memdesc *memdesc)
+{
+ unsigned int size = memdesc->size;
+ if (kgsl_memdesc_use_cpu_map(memdesc) &&
+ kgsl_memdesc_has_guard_page(memdesc))
+ size += SZ_4K;
+ return size;
+}
+
static inline int
kgsl_allocate(struct kgsl_memdesc *memdesc,
struct kgsl_pagetable *pagetable, size_t size)
{
+ int ret;
+ memdesc->priv |= (KGSL_MEMTYPE_KERNEL << KGSL_MEMTYPE_SHIFT);
if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_NONE)
return kgsl_sharedmem_ebimem(memdesc, pagetable, size);
- memdesc->flags |= (KGSL_MEMTYPE_KERNEL << KGSL_MEMTYPE_SHIFT);
- return kgsl_sharedmem_page_alloc(memdesc, pagetable, size);
+
+ ret = kgsl_sharedmem_page_alloc(memdesc, pagetable, size);
+ if (ret)
+ return ret;
+ ret = kgsl_mmu_map(pagetable, memdesc,
+ kgsl_memdesc_protflags(memdesc));
+ if (ret)
+ kgsl_sharedmem_free(memdesc);
+ return ret;
}
static inline int
@@ -185,6 +262,9 @@
{
int ret;
+ if (size == 0)
+ return -EINVAL;
+
memdesc->flags = flags;
if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_NONE)
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
index 0b247e5..bbef139 100644
--- a/drivers/gpu/msm/kgsl_trace.h
+++ b/drivers/gpu/msm/kgsl_trace.h
@@ -274,6 +274,32 @@
)
);
+TRACE_EVENT(kgsl_gpubusy,
+ TP_PROTO(struct kgsl_device *device, unsigned int busy,
+ unsigned int elapsed),
+
+ TP_ARGS(device, busy, elapsed),
+
+ TP_STRUCT__entry(
+ __string(device_name, device->name)
+ __field(unsigned int, busy)
+ __field(unsigned int, elapsed)
+ ),
+
+ TP_fast_assign(
+ __assign_str(device_name, device->name);
+ __entry->busy = busy;
+ __entry->elapsed = elapsed;
+ ),
+
+ TP_printk(
+ "d_name=%s busy=%d elapsed=%d",
+ __get_str(device_name),
+ __entry->busy,
+ __entry->elapsed
+ )
+);
+
DECLARE_EVENT_CLASS(kgsl_pwrstate_template,
TP_PROTO(struct kgsl_device *device, unsigned int state),
@@ -317,6 +343,8 @@
__field(unsigned int, size)
__field(unsigned int, tgid)
__array(char, usage, 16)
+ __field(unsigned int, id)
+ __field(unsigned int, flags)
),
TP_fast_assign(
@@ -325,12 +353,76 @@
__entry->tgid = mem_entry->priv->pid;
kgsl_get_memory_usage(__entry->usage, sizeof(__entry->usage),
mem_entry->memdesc.flags);
+ __entry->id = mem_entry->id;
+ __entry->flags = mem_entry->memdesc.flags;
),
TP_printk(
- "gpuaddr=0x%08x size=%d tgid=%d usage=%s",
+ "gpuaddr=0x%08x size=%d tgid=%d usage=%s id=%d flags=0x%08x",
__entry->gpuaddr, __entry->size, __entry->tgid,
- __entry->usage
+ __entry->usage, __entry->id, __entry->flags
+ )
+);
+
+TRACE_EVENT(kgsl_mem_mmap,
+
+ TP_PROTO(struct kgsl_mem_entry *mem_entry),
+
+ TP_ARGS(mem_entry),
+
+ TP_STRUCT__entry(
+ __field(unsigned long, useraddr)
+ __field(unsigned int, gpuaddr)
+ __field(unsigned int, size)
+ __array(char, usage, 16)
+ __field(unsigned int, id)
+ __field(unsigned int, flags)
+ ),
+
+ TP_fast_assign(
+ __entry->useraddr = mem_entry->memdesc.useraddr;
+ __entry->gpuaddr = mem_entry->memdesc.gpuaddr;
+ __entry->size = mem_entry->memdesc.size;
+ kgsl_get_memory_usage(__entry->usage, sizeof(__entry->usage),
+ mem_entry->memdesc.flags);
+ __entry->id = mem_entry->id;
+ __entry->flags = mem_entry->memdesc.flags;
+ ),
+
+ TP_printk(
+ "useraddr=%lx gpuaddr=0x%08x size=%d usage=%s id=%d"
+ " flags=0x%08x",
+ __entry->useraddr, __entry->gpuaddr, __entry->size,
+ __entry->usage, __entry->id, __entry->flags
+ )
+);
+
+TRACE_EVENT(kgsl_mem_unmapped_area_collision,
+
+ TP_PROTO(struct kgsl_mem_entry *mem_entry,
+ unsigned long hint,
+ unsigned long len,
+ unsigned long addr),
+
+ TP_ARGS(mem_entry, hint, len, addr),
+
+ TP_STRUCT__entry(
+ __field(unsigned int, id)
+ __field(unsigned long, hint)
+ __field(unsigned long, len)
+ __field(unsigned long, addr)
+ ),
+
+ TP_fast_assign(
+ __entry->id = mem_entry->id;
+ __entry->hint = hint;
+ __entry->len = len;
+ __entry->addr = addr;
+ ),
+
+ TP_printk(
+ "id=%d hint=0x%lx len=%ld addr=0x%lx",
+ __entry->id, __entry->hint, __entry->len, __entry->addr
)
);
@@ -347,6 +439,7 @@
__field(int, type)
__field(unsigned int, tgid)
__array(char, usage, 16)
+ __field(unsigned int, id)
),
TP_fast_assign(
@@ -357,13 +450,14 @@
__entry->tgid = mem_entry->priv->pid;
kgsl_get_memory_usage(__entry->usage, sizeof(__entry->usage),
mem_entry->memdesc.flags);
+ __entry->id = mem_entry->id;
),
TP_printk(
- "gpuaddr=0x%08x size=%d type=%d fd=%d tgid=%d usage %s",
+ "gpuaddr=0x%08x size=%d type=%d fd=%d tgid=%d usage=%s id=%d",
__entry->gpuaddr, __entry->size,
__entry->type, __entry->fd, __entry->tgid,
- __entry->usage
+ __entry->usage, __entry->id
)
);
@@ -380,6 +474,7 @@
__field(int, fd)
__field(unsigned int, tgid)
__array(char, usage, 16)
+ __field(unsigned int, id)
),
TP_fast_assign(
@@ -389,12 +484,13 @@
__entry->tgid = mem_entry->priv->pid;
kgsl_get_memory_usage(__entry->usage, sizeof(__entry->usage),
mem_entry->memdesc.flags);
+ __entry->id = mem_entry->id;
),
TP_printk(
- "gpuaddr=0x%08x size=%d type=%d tgid=%d usage=%s",
+ "gpuaddr=0x%08x size=%d type=%d tgid=%d usage=%s id=%d",
__entry->gpuaddr, __entry->size, __entry->type,
- __entry->tgid, __entry->usage
+ __entry->tgid, __entry->usage, __entry->id
)
);
@@ -411,6 +507,7 @@
__field(unsigned int, size)
__field(int, type)
__array(char, usage, 16)
+ __field(unsigned int, id)
__field(unsigned int, drawctxt_id)
__field(unsigned int, curr_ts)
__field(unsigned int, free_ts)
@@ -422,6 +519,7 @@
__entry->size = mem_entry->memdesc.size;
kgsl_get_memory_usage(__entry->usage, sizeof(__entry->usage),
mem_entry->memdesc.flags);
+ __entry->id = mem_entry->id;
__entry->drawctxt_id = id;
__entry->type = mem_entry->memtype;
__entry->curr_ts = curr_ts;
@@ -429,13 +527,14 @@
),
TP_printk(
- "d_name=%s gpuaddr=0x%08x size=%d type=%d usage=%s ctx=%u"
+ "d_name=%s gpuaddr=0x%08x size=%d type=%d usage=%s id=%d ctx=%u"
" curr_ts=0x%x free_ts=0x%x",
__get_str(device_name),
__entry->gpuaddr,
__entry->size,
__entry->type,
__entry->usage,
+ __entry->id,
__entry->drawctxt_id,
__entry->curr_ts,
__entry->free_ts
@@ -535,6 +634,31 @@
)
);
+TRACE_EVENT(kgsl_regwrite,
+
+ TP_PROTO(struct kgsl_device *device, unsigned int offset,
+ unsigned int value),
+
+ TP_ARGS(device, offset, value),
+
+ TP_STRUCT__entry(
+ __string(device_name, device->name)
+ __field(unsigned int, offset)
+ __field(unsigned int, value)
+ ),
+
+ TP_fast_assign(
+ __assign_str(device_name, device->name);
+ __entry->offset = offset;
+ __entry->value = value;
+ ),
+
+ TP_printk(
+ "d_name=%s reg=%x value=%x",
+ __get_str(device_name), __entry->offset, __entry->value
+ )
+);
+
#endif /* _KGSL_TRACE_H */
/* This part must be outside protection */
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index d658217..e7d514e 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -1260,10 +1260,10 @@
static int __devinit qpnp_leds_probe(struct spmi_device *spmi)
{
- struct qpnp_led_data *led;
+ struct qpnp_led_data *led, *led_array;
struct resource *led_resource;
struct device_node *node, *temp;
- int rc, i, num_leds = 0;
+ int rc, i, num_leds = 0, parsed_leds = 0;
const char *led_label;
node = spmi->dev.of_node;
@@ -1274,34 +1274,34 @@
while ((temp = of_get_next_child(node, temp)))
num_leds++;
- led = devm_kzalloc(&spmi->dev,
+ if (!num_leds)
+ return -ECHILD;
+
+ led_array = devm_kzalloc(&spmi->dev,
(sizeof(struct qpnp_led_data) * num_leds), GFP_KERNEL);
- if (!led) {
+ if (!led_array) {
dev_err(&spmi->dev, "Unable to allocate memory\n");
return -ENOMEM;
}
- led->num_leds = num_leds;
- num_leds = 0;
-
for_each_child_of_node(node, temp) {
+ led = &led_array[parsed_leds];
+ led->num_leds = num_leds;
led->spmi_dev = spmi;
led_resource = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
if (!led_resource) {
dev_err(&spmi->dev, "Unable to get LED base address\n");
- return -ENXIO;
+ rc = -ENXIO;
+ goto fail_id_check;
}
led->base = led_resource->start;
- dev_set_drvdata(&spmi->dev, led);
-
-
rc = of_property_read_string(temp, "label", &led_label);
if (rc < 0) {
dev_err(&led->spmi_dev->dev,
"Failure reading label, rc = %d\n", rc);
- return rc;
+ goto fail_id_check;
}
rc = of_property_read_string(temp, "linux,name",
@@ -1309,7 +1309,7 @@
if (rc < 0) {
dev_err(&led->spmi_dev->dev,
"Failure reading led name, rc = %d\n", rc);
- return rc;
+ goto fail_id_check;
}
rc = of_property_read_u32(temp, "qcom,max-current",
@@ -1317,14 +1317,14 @@
if (rc < 0) {
dev_err(&led->spmi_dev->dev,
"Failure reading max_current, rc = %d\n", rc);
- return rc;
+ goto fail_id_check;
}
rc = of_property_read_u32(temp, "qcom,id", &led->id);
if (rc < 0) {
dev_err(&led->spmi_dev->dev,
"Failure reading led id, rc = %d\n", rc);
- return rc;
+ goto fail_id_check;
}
rc = qpnp_get_common_configs(led, temp);
@@ -1332,7 +1332,7 @@
dev_err(&led->spmi_dev->dev,
"Failure reading common led configuration," \
" rc = %d\n", rc);
- return rc;
+ goto fail_id_check;
}
led->cdev.brightness_set = qpnp_led_set;
@@ -1343,7 +1343,7 @@
if (rc < 0) {
dev_err(&led->spmi_dev->dev,
"Unable to read wled config data\n");
- return rc;
+ goto fail_id_check;
}
} else if (strncmp(led_label, "flash", sizeof("flash"))
== 0) {
@@ -1351,18 +1351,19 @@
if (rc < 0) {
dev_err(&led->spmi_dev->dev,
"Unable to read flash config data\n");
- return rc;
+ goto fail_id_check;
}
} else if (strncmp(led_label, "rgb", sizeof("rgb")) == 0) {
rc = qpnp_get_config_rgb(led, temp);
if (rc < 0) {
dev_err(&led->spmi_dev->dev,
"Unable to read rgb config data\n");
- return rc;
+ goto fail_id_check;
}
} else {
dev_err(&led->spmi_dev->dev, "No LED matching label\n");
- return -EINVAL;
+ rc = -EINVAL;
+ goto fail_id_check;
}
spin_lock_init(&led->lock);
@@ -1388,24 +1389,25 @@
led->cdev.brightness = LED_OFF;
qpnp_led_set(&led->cdev, led->cdev.brightness);
- led++;
- num_leds++;
+
+ parsed_leds++;
}
+ dev_set_drvdata(&spmi->dev, led_array);
return 0;
fail_id_check:
- for (i = 0; i < num_leds; i++)
- led_classdev_unregister(&led[i].cdev);
+ for (i = 0; i < parsed_leds; i++)
+ led_classdev_unregister(&led_array[i].cdev);
return rc;
}
static int __devexit qpnp_leds_remove(struct spmi_device *spmi)
{
- struct qpnp_led_data *led = dev_get_drvdata(&spmi->dev);
- int i;
+ struct qpnp_led_data *led_array = dev_get_drvdata(&spmi->dev);
+ int i, parsed_leds = led_array->num_leds;
- for (i = 0; i < led->num_leds; i++)
- led_classdev_unregister(&led[i].cdev);
+ for (i = 0; i < parsed_leds; i++)
+ led_classdev_unregister(&led_array[i].cdev);
return 0;
}
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 6d66d45..978cb38d 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -42,8 +42,6 @@
*/
// #define DVB_DEMUX_SECTION_LOSS_LOG
-#define TIMESTAMP_LEN 4
-
static int dvb_demux_tscheck;
module_param(dvb_demux_tscheck, int, 0644);
MODULE_PARM_DESC(dvb_demux_tscheck,
@@ -608,7 +606,7 @@
((f)->feed.ts.is_filtering) && \
(((f)->ts_type & (TS_PACKET | TS_DEMUX)) == TS_PACKET))
-static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf,
+void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf,
const u8 timestamp[TIMESTAMP_LEN])
{
struct dvb_demux_feed *feed;
@@ -688,6 +686,7 @@
dvb_dmx_swfilter_output_packet(feed, buf, timestamp);
}
}
+EXPORT_SYMBOL(dvb_dmx_swfilter_packet);
void dvb_dmx_swfilter_section_packets(struct dvb_demux *demux, const u8 *buf,
size_t count)
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h
index 4e6dfaf..f89367b 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.h
+++ b/drivers/media/dvb/dvb-core/dvb_demux.h
@@ -47,6 +47,8 @@
#define MAX_PID 0x1fff
+#define TIMESTAMP_LEN 4
+
#define SPEED_PKTS_INTERVAL 50000
struct dvb_demux_filter {
@@ -189,6 +191,8 @@
struct dvb_demux *demux, const u8 *buf,
size_t count,
enum dmx_tsp_format_t tsp_format);
+void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf,
+ const u8 timestamp[TIMESTAMP_LEN]);
#endif /* _DVB_DEMUX_H_ */
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 51d66cd..e2ef6a0 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
@@ -473,16 +473,23 @@
* when dvb-demux is terminated.
*/
mpq_demux->hw_notification_count = 0;
- mpq_demux->hw_notification_rate = 0;
+ mpq_demux->hw_notification_interval = 0;
mpq_demux->hw_notification_size = 0;
mpq_demux->decoder_tsp_drop_count = 0;
+ mpq_demux->hw_notification_min_size = 0xFFFFFFFF;
if (mpq_demux->demux.dmx.debugfs_demux_dir != NULL) {
debugfs_create_u32(
- "hw_notification_rate",
+ "hw_notification_interval",
S_IRUGO|S_IWUGO,
mpq_demux->demux.dmx.debugfs_demux_dir,
- &mpq_demux->hw_notification_rate);
+ &mpq_demux->hw_notification_interval);
+
+ debugfs_create_u32(
+ "hw_notification_min_interval",
+ S_IRUGO|S_IWUGO,
+ mpq_demux->demux.dmx.debugfs_demux_dir,
+ &mpq_demux->hw_notification_min_interval);
debugfs_create_u32(
"hw_notification_count",
@@ -497,6 +504,12 @@
&mpq_demux->hw_notification_size);
debugfs_create_u32(
+ "hw_notification_min_size",
+ S_IRUGO|S_IWUGO,
+ mpq_demux->demux.dmx.debugfs_demux_dir,
+ &mpq_demux->hw_notification_min_size);
+
+ debugfs_create_u32(
"decoder_tsp_drop_count",
S_IRUGO|S_IWUGO,
mpq_demux->demux.dmx.debugfs_demux_dir,
@@ -520,10 +533,17 @@
curr_time,
mpq_demux->last_notification_time);
- delta_time_ms = (u64)timespec_to_ns(&delta_time);
- delta_time_ms = div64_u64(delta_time_ms, 1000000); /* ns->ms */
+ delta_time_ms = ((u64)delta_time.tv_sec * MSEC_PER_SEC) +
+ delta_time.tv_nsec / NSEC_PER_MSEC;
- mpq_demux->hw_notification_rate = delta_time_ms;
+ mpq_demux->hw_notification_interval = delta_time_ms;
+
+ if ((mpq_demux->hw_notification_count == 1) ||
+ (mpq_demux->hw_notification_interval &&
+ mpq_demux->hw_notification_interval <
+ mpq_demux->hw_notification_min_interval))
+ mpq_demux->hw_notification_min_interval =
+ mpq_demux->hw_notification_interval;
}
mpq_demux->hw_notification_count++;
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 e9987c2..69305b6 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h
@@ -44,9 +44,14 @@
* initialized or not.
* @ion_client: ION demux client used to allocate memory from ION.
* @feed_lock: Lock used to protect against private feed data
- * @hw_notification_rate: Notification rate in msec, exposed in debugfs.
+ * @hw_notification_interval: Notification interval in msec,
+ * exposed in debugfs.
+ * @hw_notification_min_interval: Minimum notification internal in msec,
+ * exposed in debugfs.
* @hw_notification_count: Notification count, exposed in debugfs.
* @hw_notification_size: Notification size in bytes, exposed in debugfs.
+ * @hw_notification_min_size: Minimum notification size in bytes,
+ * exposed in debugfs.
* @decoder_tsp_drop_count: Counter of number of dropped TS packets
* due to decoder buffer fullness, exposed in debugfs.
* @last_notification_time: Time of last HW notification.
@@ -61,9 +66,11 @@
spinlock_t feed_lock;
/* debug-fs */
- u32 hw_notification_rate;
+ u32 hw_notification_interval;
+ u32 hw_notification_min_interval;
u32 hw_notification_count;
u32 hw_notification_size;
+ u32 hw_notification_min_size;
u32 decoder_tsp_drop_count;
struct timespec last_notification_time;
};
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 f5c01e1..ac03e43 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
@@ -35,45 +35,36 @@
#define TSPP_GET_TSIF_NUM(ch_id) (ch_id >> 1)
/* mask that set to care for all bits in pid filter */
-#define TSPP_PID_MASK 0x1FFF
+#define TSPP_PID_MASK 0x1FFF
/* dvb-demux defines pid 0x2000 as full capture pid */
-#define TSPP_PASS_THROUGH_PID 0x2000
+#define TSPP_PASS_THROUGH_PID 0x2000
-/* TODO - NEED TO SET THESE PROPERLY
- * once TSPP driver is ready, reduce TSPP_BUFFER_SIZE
- * to single packet and set TSPP_BUFFER_COUNT accordingly
- */
+#define TSPP_RAW_TTS_SIZE 192
+#define TSPP_RAW_SIZE 188
-#define TSPP_RAW_TTS_SIZE 192
+#define MAX_BAM_DESCRIPTOR_SIZE (32*1024 - 1)
-#define MAX_BAM_DESCRIPTOR_SIZE (32*1024 - 1)
+#define TSPP_BUFFER_SIZE (500 * 1024) /* 500KB */
-/* Size of single descriptor for PES/rec pipe.
+#define TSPP_PES_BUFFER_SIZE (TSPP_RAW_TTS_SIZE)
+
+#define TSPP_SECTION_BUFFER_SIZE (TSPP_RAW_TTS_SIZE)
+
+#define TSPP_BUFFER_COUNT(buffer_size) \
+ ((buffer_size) / TSPP_RAW_TTS_SIZE)
+
+/* When TSPP notifies demux that new packets are received.
* Using max descriptor size (170 packets).
* Assuming 20MBit/sec stream, with 170 packets
* per descriptor there would be about 82 descriptors,
* Meanning about 82 notifications per second.
*/
-#define TSPP_PES_BUFFER_SIZE \
- ((MAX_BAM_DESCRIPTOR_SIZE / TSPP_RAW_TTS_SIZE) * TSPP_RAW_TTS_SIZE)
-
-/* Size of single descriptor for section pipe.
- * Assuming 8MBit/sec section rate, with 65 packets
- * per descriptor there would be about 85 descriptors,
- * Meanning about 85 notifications per second.
- */
-#define TSPP_SECTION_BUFFER_SIZE \
- (65 * TSPP_RAW_TTS_SIZE)
-
-/* Number of descriptors, total size: TSPP_BUFFER_SIZE*TSPP_BUFFER_COUNT */
-#define TSPP_BUFFER_COUNT (32)
-
-/* When TSPP notifies demux that new packets are received */
-#define TSPP_NOTIFICATION_SIZE 1
+#define TSPP_NOTIFICATION_SIZE(desc_size) \
+ (MAX_BAM_DESCRIPTOR_SIZE / (desc_size))
/* Channel timeout in msec */
-#define TSPP_CHANNEL_TIMEOUT 16
+#define TSPP_CHANNEL_TIMEOUT 100
enum mem_buffer_allocation_mode {
MPQ_DMX_TSPP_INTERNAL_ALLOC = 0,
@@ -84,9 +75,16 @@
static int clock_inv;
static int tsif_mode = 2;
static int allocation_mode = MPQ_DMX_TSPP_INTERNAL_ALLOC;
+static int tspp_out_buffer_size = TSPP_BUFFER_SIZE;
+static int tspp_notification_size = TSPP_NOTIFICATION_SIZE(TSPP_RAW_TTS_SIZE);
+static int tspp_channel_timeout = TSPP_CHANNEL_TIMEOUT;
+
module_param(tsif_mode, int, S_IRUGO | S_IWUSR);
module_param(clock_inv, int, S_IRUGO | S_IWUSR);
module_param(allocation_mode, int, S_IRUGO);
+module_param(tspp_out_buffer_size, int, S_IRUGO);
+module_param(tspp_notification_size, int, S_IRUGO | S_IWUSR);
+module_param(tspp_channel_timeout, int, S_IRUGO | S_IWUSR);
/* The following structure hold singelton information
@@ -134,6 +132,8 @@
/* buffer allocation index */
int section_index;
+ u32 buffer_count;
+
/*
* Holds PIDs of allocated TSPP filters along with
* how many feeds are opened on same PID.
@@ -168,7 +168,8 @@
int i = TSPP_GET_TSIF_NUM(channel_id);
if (TSPP_IS_PES_CHANNEL(channel_id)) {
- if (mpq_dmx_tspp_info.tsif[i].pes_index == TSPP_BUFFER_COUNT)
+ if (mpq_dmx_tspp_info.tsif[i].pes_index ==
+ mpq_dmx_tspp_info.tsif[i].buffer_count)
return NULL;
virt_addr =
(mpq_dmx_tspp_info.tsif[i].pes_mem_heap_virt_base +
@@ -179,7 +180,7 @@
mpq_dmx_tspp_info.tsif[i].pes_index++;
} else {
if (mpq_dmx_tspp_info.tsif[i].section_index ==
- TSPP_BUFFER_COUNT)
+ mpq_dmx_tspp_info.tsif[i].buffer_count)
return NULL;
virt_addr =
(mpq_dmx_tspp_info.tsif[i].section_mem_heap_virt_base +
@@ -277,9 +278,11 @@
struct mpq_demux *mpq_demux;
const struct tspp_data_descriptor *tspp_data_desc;
atomic_t *data_cnt;
+ u32 notif_size;
int ref_count;
int ret;
int i;
+ int j;
do {
ret = wait_event_interruptible(
@@ -331,16 +334,20 @@
*/
while ((tspp_data_desc =
tspp_get_buffer(0, channel_id)) != NULL) {
+ notif_size =
+ tspp_data_desc->size /
+ TSPP_RAW_TTS_SIZE;
+
mpq_demux->hw_notification_size +=
- (tspp_data_desc->size /
- TSPP_RAW_TTS_SIZE);
+ notif_size;
- dvb_dmx_swfilter_format(
- &mpq_demux->demux,
- tspp_data_desc->virt_base,
- tspp_data_desc->size,
- DMX_TSP_FORMAT_192_TAIL);
-
+ for (j = 0; j < notif_size; j++)
+ dvb_dmx_swfilter_packet(
+ &mpq_demux->demux,
+ ((u8 *)tspp_data_desc->virt_base) +
+ j * TSPP_RAW_TTS_SIZE,
+ ((u8 *)tspp_data_desc->virt_base) +
+ j * TSPP_RAW_TTS_SIZE + TSPP_RAW_SIZE);
/*
* Notify TSPP that the buffer
* is no longer needed
@@ -348,6 +355,12 @@
tspp_release_buffer(0,
channel_id, tspp_data_desc->id);
}
+
+ if (mpq_demux->hw_notification_size &&
+ (mpq_demux->hw_notification_size <
+ mpq_demux->hw_notification_min_size))
+ mpq_demux->hw_notification_min_size =
+ mpq_demux->hw_notification_size;
}
mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex);
@@ -466,7 +479,6 @@
/* check if required TSPP pipe is already allocated or not */
if (*channel_ref_count == 0) {
ret = tspp_open_channel(0, channel_id);
-
if (ret < 0) {
MPQ_DVB_ERR_PRINT(
"%s: tspp_open_channel(%d) failed (%d)\n",
@@ -495,7 +507,7 @@
channel_id,
mpq_tspp_callback,
(void *)tsif,
- TSPP_CHANNEL_TIMEOUT);
+ tspp_channel_timeout);
/* register allocater and provide allocation function
* that allocates from continous memory so that we can have
@@ -507,23 +519,15 @@
* allocate TSPP data buffers
*/
if (allocation_mode == MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC) {
- ret = tspp_allocate_buffers(0,
- channel_id,
- TSPP_BUFFER_COUNT,
- buffer_size,
- TSPP_NOTIFICATION_SIZE,
- tspp_mem_allocator,
- tspp_mem_free,
- NULL);
+ ret = tspp_allocate_buffers(0, channel_id,
+ mpq_dmx_tspp_info.tsif[tsif].buffer_count,
+ buffer_size, tspp_notification_size,
+ tspp_mem_allocator, tspp_mem_free, NULL);
} else {
- ret = tspp_allocate_buffers(0,
- channel_id,
- TSPP_BUFFER_COUNT,
- buffer_size,
- TSPP_NOTIFICATION_SIZE,
- NULL,
- NULL,
- NULL);
+ ret = tspp_allocate_buffers(0, channel_id,
+ mpq_dmx_tspp_info.tsif[tsif].buffer_count,
+ buffer_size, tspp_notification_size,
+ NULL, NULL, NULL);
}
if (ret < 0) {
MPQ_DVB_ERR_PRINT(
@@ -767,7 +771,7 @@
ret = mpq_dmx_init_video_feed(feed);
if (ret < 0) {
- MPQ_DVB_DBG_PRINT(
+ MPQ_DVB_ERR_PRINT(
"%s: mpq_dmx_init_video_feed failed(%d)\n",
__func__,
ret);
@@ -949,11 +953,11 @@
for (i = 0; i < TSIF_COUNT; i++) {
mpq_dmx_tspp_info.tsif[i].pes_mem_heap_handle =
ion_alloc(mpq_dmx_tspp_info.ion_client,
- (TSPP_BUFFER_COUNT *
- TSPP_PES_BUFFER_SIZE),
- TSPP_RAW_TTS_SIZE,
- ION_HEAP(ION_CP_MM_HEAP_ID),
- 0); /* non-cached */
+ (mpq_dmx_tspp_info.tsif[i].buffer_count *
+ TSPP_PES_BUFFER_SIZE),
+ TSPP_RAW_TTS_SIZE,
+ ION_HEAP(ION_CP_MM_HEAP_ID),
+ 0); /* non-cached */
if (IS_ERR_OR_NULL(mpq_dmx_tspp_info.tsif[i].
pes_mem_heap_handle)) {
MPQ_DVB_ERR_PRINT("%s: ion_alloc() failed\n",
@@ -988,11 +992,11 @@
mpq_dmx_tspp_info.tsif[i].section_mem_heap_handle =
ion_alloc(mpq_dmx_tspp_info.ion_client,
- (TSPP_BUFFER_COUNT *
- TSPP_SECTION_BUFFER_SIZE),
- TSPP_RAW_TTS_SIZE,
- ION_HEAP(ION_CP_MM_HEAP_ID),
- 0); /* non-cached */
+ (mpq_dmx_tspp_info.tsif[i].buffer_count *
+ TSPP_SECTION_BUFFER_SIZE),
+ TSPP_RAW_TTS_SIZE,
+ ION_HEAP(ION_CP_MM_HEAP_ID),
+ 0); /* non-cached */
if (IS_ERR_OR_NULL(mpq_dmx_tspp_info.tsif[i].
section_mem_heap_handle)) {
MPQ_DVB_ERR_PRINT("%s: ion_alloc() failed\n",
@@ -1106,6 +1110,9 @@
MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
for (i = 0; i < TSIF_COUNT; i++) {
+ mpq_dmx_tspp_info.tsif[i].buffer_count =
+ TSPP_BUFFER_COUNT(tspp_out_buffer_size);
+
mpq_dmx_tspp_info.tsif[i].pes_channel_ref = 0;
mpq_dmx_tspp_info.tsif[i].pes_index = 0;
mpq_dmx_tspp_info.tsif[i].pes_mem_heap_handle = NULL;
diff --git a/drivers/media/video/msm/Kconfig b/drivers/media/video/msm/Kconfig
index be9c43c..24f6556 100644
--- a/drivers/media/video/msm/Kconfig
+++ b/drivers/media/video/msm/Kconfig
@@ -186,6 +186,17 @@
It is a Texas Instruments multiple LED Flash
for camera flash and video light applications.
+config MSM_CAMERA_LED_TRIGGER_FLASH
+ bool "Qualcomm MSM LED trigger flash support"
+ depends on MSM_CAMERA
+ default n
+ ---help---
+ Enable support for LED flash for msm camera.
+ It creates LED trigger client, reads LED flash
+ hardware properties provided in board file /
+ device tree and uses these information to configure
+ LED flash using LED trigger event function.
+
config IMX072
bool "Sensor imx072 (Sony 5M)"
default n
diff --git a/drivers/media/video/msm/flash/Makefile b/drivers/media/video/msm/flash/Makefile
index e83f052..8d0812b 100644
--- a/drivers/media/video/msm/flash/Makefile
+++ b/drivers/media/video/msm/flash/Makefile
@@ -7,3 +7,4 @@
obj-$(CONFIG_MSM_CAMERA_FLASH_PMIC_FLASH) += pmic8058_flash.o
obj-$(CONFIG_MSM_CAMERA_FLASH_SGM3141) += sgm3141.o
obj-$(CONFIG_MSM_CAMERA_FLASH_PMIC8058_PWM) += pmic8058_pwm.o
+obj-$(CONFIG_MSM_CAMERA_LED_TRIGGER_FLASH) += led_trigger_flash.o
diff --git a/drivers/media/video/msm/flash/led_trigger_flash.c b/drivers/media/video/msm/flash/led_trigger_flash.c
new file mode 100644
index 0000000..cd34cde
--- /dev/null
+++ b/drivers/media/video/msm/flash/led_trigger_flash.c
@@ -0,0 +1,162 @@
+/* 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/module.h>
+#include <linux/export.h>
+#include "msm_flash.h"
+
+#define FLASH_NAME "camera-led-flash"
+static struct msm_flash_ctrl_t fctrl;
+
+static int msm_camera_led_trigger_flash(struct msm_flash_ctrl_t *fctrl,
+ uint8_t led_state)
+{
+ int rc = 0;
+ CDBG("%s:%d called led_state %d\n", __func__, __LINE__, led_state);
+
+ if (!fctrl->led_trigger[0]) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ return -EINVAL;
+ }
+ switch (led_state) {
+ case MSM_CAMERA_LED_OFF:
+ led_trigger_event(fctrl->led_trigger[0], 0);
+ break;
+
+ case MSM_CAMERA_LED_LOW:
+ led_trigger_event(fctrl->led_trigger[0],
+ fctrl->max_current[0] / 2);
+ break;
+
+ case MSM_CAMERA_LED_HIGH:
+ led_trigger_event(fctrl->led_trigger[0], fctrl->max_current[0]);
+ break;
+
+ case MSM_CAMERA_LED_INIT:
+ case MSM_CAMERA_LED_RELEASE:
+ led_trigger_event(fctrl->led_trigger[0], 0);
+ break;
+
+ default:
+ rc = -EFAULT;
+ break;
+ }
+ CDBG("flash_set_led_state: return %d\n", rc);
+ return rc;
+}
+
+static const struct of_device_id msm_camera_flash_dt_match[] = {
+ {.compatible = "qcom,camera-led-flash"},
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, msm_camera_flash_dt_match);
+
+static struct platform_driver msm_led_trigger_flash_driver = {
+ .driver = {
+ .name = FLASH_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = msm_camera_flash_dt_match,
+ },
+};
+
+static int32_t msm_led_trigger_flash_probe(struct platform_device *pdev)
+{
+ int32_t rc = 0, i = 0;
+ struct device_node *of_node = pdev->dev.of_node;
+ struct device_node *flash_src_node = NULL;
+ uint32_t count = 0;
+
+ CDBG("%s called\n", __func__);
+
+ if (!of_node) {
+ pr_err("%s of_node NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ fctrl.pdev = pdev;
+
+ rc = of_property_read_u32(of_node, "cell-index", &pdev->id);
+ if (rc < 0) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ return -EINVAL;
+ }
+ CDBG("%s:%d pdev id %d\n", __func__, __LINE__, pdev->id);
+
+ if (of_get_property(of_node, "qcom,flash-source", &count)) {
+ count /= sizeof(uint32_t);
+ CDBG("%s count %d\n", __func__, count);
+ if (count > MAX_LED_TRIGGERS) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ return -EINVAL;
+ }
+ for (i = 0; i < count; i++) {
+ flash_src_node = of_parse_phandle(of_node,
+ "qcom,flash-source", i);
+ if (!flash_src_node) {
+ pr_err("%s:%d flash_src_node NULL\n", __func__,
+ __LINE__);
+ continue;
+ }
+
+ rc = of_property_read_string(flash_src_node,
+ "linux,default-trigger",
+ &fctrl.led_trigger_name[i]);
+ if (rc < 0) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ of_node_put(flash_src_node);
+ continue;
+ }
+
+ CDBG("%s default trigger %s\n", __func__,
+ fctrl.led_trigger_name[i]);
+
+ rc = of_property_read_u32(flash_src_node,
+ "qcom,max-current", &fctrl.max_current[i]);
+ if (rc < 0) {
+ pr_err("%s:%d failed rc %d\n", __func__,
+ __LINE__, rc);
+ of_node_put(flash_src_node);
+ continue;
+ }
+
+ of_node_put(flash_src_node);
+
+ CDBG("%s max_current[%d] %d\n", __func__, i,
+ fctrl.max_current[i]);
+
+ led_trigger_register_simple(fctrl.led_trigger_name[i],
+ &fctrl.led_trigger[i]);
+ }
+ }
+ rc = msm_flash_platform_probe(pdev, &fctrl);
+ return rc;
+}
+
+static int __init msm_flash_add_driver(void)
+{
+ CDBG("%s called\n", __func__);
+ return platform_driver_probe(&msm_led_trigger_flash_driver,
+ msm_led_trigger_flash_probe);
+}
+
+static struct msm_flash_fn_t msm_led_trigger_flash_func_tbl = {
+ .flash_led_config = msm_camera_led_trigger_flash,
+};
+
+static struct msm_flash_ctrl_t fctrl = {
+ .func_tbl = &msm_led_trigger_flash_func_tbl,
+};
+
+module_init(msm_flash_add_driver);
+MODULE_DESCRIPTION("LED TRIGGER FLASH");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/flash/msm_flash.h b/drivers/media/video/msm/flash/msm_flash.h
index a7c8846..2513995 100644
--- a/drivers/media/video/msm/flash/msm_flash.h
+++ b/drivers/media/video/msm/flash/msm_flash.h
@@ -55,7 +55,7 @@
struct msm_flash_reg_t *reg_setting;
const char *led_trigger_name[MAX_LED_TRIGGERS];
struct led_trigger *led_trigger[MAX_LED_TRIGGERS];
- uint32_t max_brightness[MAX_LED_TRIGGERS];
+ uint32_t max_current[MAX_LED_TRIGGERS];
void *data;
};
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 ff99aa3..31286dd 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
@@ -126,5 +126,11 @@
#define JPEG_VBIF_OUT_WR_LIM_CONF0 0xD4
#define JPEG_VBIF_DDR_OUT_MAX_BURST 0xD8
#define JPEG_VBIF_OCMEM_OUT_MAX_BURST 0xDC
+#define JPEG_VBIF_ARB_CTL 0xF0
+#define JPEG_VBIF_OUT_AXI_AOOO_EN 0x178
+#define JPEG_VBIF_OUT_AXI_AOOO 0x17c
+#define JPEG_VBIF_ROUND_ROBIN_QOS_ARB 0x124
+#define JPEG_VBIF_OUT_AXI_AMEMTYPE_CONF0 0x160
+#define JPEG_VBIF_OUT_AXI_AMEMTYPE_CONF1 0x164
#endif /* MSM_JPEG_HW_REG_H */
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 06135ec..38a0ffb 100644
--- a/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.c
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.c
@@ -108,12 +108,26 @@
jpeg_vbif_base + JPEG_VBIF_IN_WR_LIM_CONF2);
writel_relaxed(0x00001010,
jpeg_vbif_base + JPEG_VBIF_OUT_RD_LIM_CONF0);
- writel_relaxed(0x00001010,
+ writel_relaxed(0x00000110,
jpeg_vbif_base + JPEG_VBIF_OUT_WR_LIM_CONF0);
writel_relaxed(0x00000707,
jpeg_vbif_base + JPEG_VBIF_DDR_OUT_MAX_BURST);
- writel_relaxed(0x00000707,
+ writel_relaxed(0x7,
jpeg_vbif_base + JPEG_VBIF_OCMEM_OUT_MAX_BURST);
+ writel_relaxed(0x00000030,
+ jpeg_vbif_base + JPEG_VBIF_ARB_CTL);
+ writel_relaxed(0x00000FFF,
+ jpeg_vbif_base + JPEG_VBIF_OUT_AXI_AOOO_EN);
+ writel_relaxed(0x0FFF0FFF,
+ jpeg_vbif_base + JPEG_VBIF_OUT_AXI_AOOO);
+ /*FE and WE QOS configuration need to be set when
+ QOS RR arbitration is enabled*/
+ writel_relaxed(0x00000001,
+ jpeg_vbif_base + JPEG_VBIF_ROUND_ROBIN_QOS_ARB);
+ writel_relaxed(0x22222222,
+ jpeg_vbif_base + JPEG_VBIF_OUT_AXI_AMEMTYPE_CONF0);
+ writel_relaxed(0x2222,
+ jpeg_vbif_base + JPEG_VBIF_OUT_AXI_AMEMTYPE_CONF1);
}
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index 63cf38e..907523c 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.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
@@ -603,6 +603,8 @@
{
int32_t rc = 0;
uint32_t val = 0;
+ struct msm_camera_sensor_flash_data *flash_data = NULL;
+ struct device_node *flash_src_node = NULL;
sensordata->flash_data = kzalloc(sizeof(
struct msm_camera_sensor_flash_data), GFP_KERNEL);
@@ -611,16 +613,42 @@
return -ENOMEM;
}
- rc = of_property_read_u32(of_node, "qcom,flash-type", &val);
+ if (!of_get_property(of_node, "qcom,flash-src-index", &val)) {
+ CDBG("%s flash not available\n", __func__);
+ return rc;
+ }
+ flash_data = sensordata->flash_data;
+
+ flash_src_node = of_parse_phandle(of_node, "qcom,flash-src-index", 0);
+ if (!flash_src_node) {
+ pr_err("%s:%d flash_src_node NULL\n", __func__,
+ __LINE__);
+ goto ERROR1;
+ }
+
+ rc = of_property_read_u32(flash_src_node, "qcom,flash-type", &val);
CDBG("%s qcom,flash-type %d, rc %d\n", __func__, val, rc);
if (rc < 0) {
pr_err("%s failed %d\n", __func__, __LINE__);
- goto ERROR;
+ goto ERROR2;
}
- sensordata->flash_data->flash_type = val;
+ flash_data->flash_type = val;
+
+ rc = of_property_read_u32(flash_src_node, "cell-index", &val);
+ CDBG("%s qcom,flash-src-index %d, rc %d\n", __func__, val, rc);
+ if (rc < 0) {
+ pr_err("%s failed %d\n", __func__, __LINE__);
+ goto ERROR2;
+ }
+ flash_data->flash_src_index = val;
+
+ of_node_put(flash_src_node);
+
return rc;
-ERROR:
- kfree(sensordata->flash_data);
+ERROR2:
+ of_node_put(flash_src_node);
+ERROR1:
+ flash_data->flash_type = MSM_CAMERA_FLASH_NONE;
return rc;
}
diff --git a/drivers/media/video/msm/vfe/msm_vfe40.c b/drivers/media/video/msm/vfe/msm_vfe40.c
index 287c77c..81a6dd2 100644
--- a/drivers/media/video/msm/vfe/msm_vfe40.c
+++ b/drivers/media/video/msm/vfe/msm_vfe40.c
@@ -5170,39 +5170,44 @@
static void msm_vfe40_init_vbif_parms(void __iomem *vfe_vbif_base)
{
- msm_camera_io_w_mb(0x1,
+ msm_camera_io_w(0x1,
vfe_vbif_base + VFE40_VBIF_CLKON);
- msm_camera_io_w_mb(0x1,
- vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB);
- msm_camera_io_w_mb(0xFFFF,
- vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN);
- msm_camera_io_w_mb(0xFFFFFFFF,
- vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO);
-
- msm_camera_io_w_mb(0x10101010,
+ msm_camera_io_w(0x01010101,
vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0);
- msm_camera_io_w_mb(0x10101010,
+ msm_camera_io_w(0x01010101,
vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1);
- msm_camera_io_w_mb(0x10101010,
+ msm_camera_io_w(0x10010110,
vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF2);
- msm_camera_io_w_mb(0x10101010,
+ msm_camera_io_w(0x10101010,
vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0);
- msm_camera_io_w_mb(0x10101010,
+ msm_camera_io_w(0x10101010,
vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1);
- msm_camera_io_w_mb(0x10101010,
+ msm_camera_io_w(0x10101010,
vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF2);
- msm_camera_io_w_mb(0x00001010,
+ msm_camera_io_w(0x00001010,
vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0);
- msm_camera_io_w_mb(0x00001010,
+ msm_camera_io_w(0x00001010,
vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0);
- msm_camera_io_w_mb(0x00000707,
+ msm_camera_io_w(0x00000707,
vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST);
- msm_camera_io_w_mb(0x00000030,
+ msm_camera_io_w(0x00000707,
+ vfe_vbif_base + VFE40_VBIF_OCMEM_OUT_MAX_BURST);
+ msm_camera_io_w(0x00000030,
vfe_vbif_base + VFE40_VBIF_ARB_CTL);
- msm_camera_io_w_mb(0x04210842,
+ msm_camera_io_w(0x04210842,
vfe_vbif_base + VFE40_VBIF_DDR_ARB_CONF0);
- msm_camera_io_w_mb(0x04210842,
+ msm_camera_io_w(0x04210842,
vfe_vbif_base + VFE40_VBIF_DDR_ARB_CONF1);
+ msm_camera_io_w(0x00000001,
+ vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB);
+ msm_camera_io_w(0x22222222,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0);
+ msm_camera_io_w(0x00002222,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF1);
+ msm_camera_io_w(0x00000FFF,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN);
+ msm_camera_io_w(0x0FFF0FFF,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO);
}
int msm_axi_subdev_init(struct v4l2_subdev *sd)
diff --git a/drivers/media/video/msm/vfe/msm_vfe40.h b/drivers/media/video/msm/vfe/msm_vfe40.h
index 4acc7e4..a94c428 100644
--- a/drivers/media/video/msm/vfe/msm_vfe40.h
+++ b/drivers/media/video/msm/vfe/msm_vfe40.h
@@ -901,22 +901,25 @@
#define VFE40_OUTPUT_MODE_TERTIARY1 BIT(10)
#define VFE40_OUTPUT_MODE_TERTIARY2 BIT(11)
-#define VFE40_VBIF_CLKON 0x4
-#define VFE40_VBIF_IN_RD_LIM_CONF0 0xB0
-#define VFE40_VBIF_IN_RD_LIM_CONF1 0xB4
-#define VFE40_VBIF_IN_RD_LIM_CONF2 0xB8
-#define VFE40_VBIF_IN_WR_LIM_CONF0 0xC0
-#define VFE40_VBIF_IN_WR_LIM_CONF1 0xC4
-#define VFE40_VBIF_IN_WR_LIM_CONF2 0xC8
-#define VFE40_VBIF_OUT_RD_LIM_CONF0 0xD0
-#define VFE40_VBIF_OUT_WR_LIM_CONF0 0xD4
-#define VFE40_VBIF_DDR_OUT_MAX_BURST 0xD8
-#define VFE40_VBIF_ARB_CTL 0xF0
-#define VFE40_VBIF_DDR_ARB_CONF0 0xF4
-#define VFE40_VBIF_DDR_ARB_CONF1 0xF8
-#define VFE40_VBIF_ROUND_ROBIN_QOS_ARB 0x124
-#define VFE40_VBIF_OUT_AXI_AOOO_EN 0x178
-#define VFE40_VBIF_OUT_AXI_AOOO 0x17C
+#define VFE40_VBIF_CLKON 0x4
+#define VFE40_VBIF_IN_RD_LIM_CONF0 0xB0
+#define VFE40_VBIF_IN_RD_LIM_CONF1 0xB4
+#define VFE40_VBIF_IN_RD_LIM_CONF2 0xB8
+#define VFE40_VBIF_IN_WR_LIM_CONF0 0xC0
+#define VFE40_VBIF_IN_WR_LIM_CONF1 0xC4
+#define VFE40_VBIF_IN_WR_LIM_CONF2 0xC8
+#define VFE40_VBIF_OUT_RD_LIM_CONF0 0xD0
+#define VFE40_VBIF_OUT_WR_LIM_CONF0 0xD4
+#define VFE40_VBIF_DDR_OUT_MAX_BURST 0xD8
+#define VFE40_VBIF_OCMEM_OUT_MAX_BURST 0xDC
+#define VFE40_VBIF_ARB_CTL 0xF0
+#define VFE40_VBIF_DDR_ARB_CONF0 0xF4
+#define VFE40_VBIF_DDR_ARB_CONF1 0xF8
+#define VFE40_VBIF_ROUND_ROBIN_QOS_ARB 0x124
+#define VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0 0x160
+#define VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF1 0x164
+#define VFE40_VBIF_OUT_AXI_AOOO_EN 0x178
+#define VFE40_VBIF_OUT_AXI_AOOO 0x17C
struct vfe_stats_control {
uint32_t droppedStatsFrameCount;
diff --git a/drivers/media/video/msm_vidc/msm_smem.c b/drivers/media/video/msm_vidc/msm_smem.c
index 83f33a1..e1b73ef 100644
--- a/drivers/media/video/msm_vidc/msm_smem.c
+++ b/drivers/media/video/msm_vidc/msm_smem.c
@@ -32,8 +32,6 @@
clnt, hndl, iova, buffer_size);
return -EINVAL;
}
- if (align < 4096)
- align = 4096;
dprintk(VIDC_DBG, "domain: %d, partition: %d\n",
domain_num, partition_num);
if (flags & SMEM_SECURE) {
@@ -74,6 +72,7 @@
unsigned long iova = 0;
unsigned long buffer_size = 0;
int rc = 0;
+ int align = SZ_4K;
hndl = ion_import_dma_buf(client->clnt, fd);
if (IS_ERR_OR_NULL(hndl)) {
dprintk(VIDC_ERR, "Failed to get handle: %p, %d, %d, %p\n",
@@ -85,8 +84,12 @@
mem->domain = domain;
mem->partition_num = partition;
mem->flags = flags;
+
+ if (flags & SMEM_SECURE)
+ align = ALIGN(align, SZ_1M);
+
rc = get_device_address(client->clnt, hndl, mem->domain,
- mem->partition_num, 4096, &iova, &buffer_size, flags);
+ mem->partition_num, align, &iova, &buffer_size, flags);
if (rc) {
dprintk(VIDC_ERR, "Failed to get device address: %d\n", rc);
goto fail_device_address;
@@ -121,15 +124,16 @@
else
ionflags = ION_SET_UNCACHED(ionflags);
+ align = ALIGN(align, SZ_4K);
+ size = ALIGN(size, SZ_4K);
+
if (flags & SMEM_SECURE) {
ionflags |= ION_SECURE;
- size = (size + 0xfffff) & (~0xfffff);
+ size = ALIGN(size, SZ_1M);
+ align = ALIGN(align, SZ_1M);
}
heap_mask = ION_HEAP(ION_CP_MM_HEAP_ID);
- if (align < 4096)
- align = 4096;
- size = (size + 4095) & (~4095);
dprintk(VIDC_DBG, "domain: %d, partition: %d\n",
domain, partition);
hndl = ion_alloc(client->clnt, size, align, heap_mask, ionflags);
diff --git a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
index 4f2373e..38e8de1 100644
--- a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
@@ -591,7 +591,7 @@
}
v4l2_inst->vidc_inst = msm_vidc_open(core->id, vid_dev->type);
- if (rc) {
+ if (!v4l2_inst->vidc_inst) {
dprintk(VIDC_ERR,
"Failed to create video instance, core: %d, type = %d\n",
core->id, vid_dev->type);
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
index 4d9b92d..711b3007 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.c
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -470,7 +470,7 @@
b->m.planes[extra_idx].m.userptr;
else
buffer_info.extradata_addr = 0;
-
+ buffer_info.response_required = false;
rc = vidc_hal_session_release_buffers(
(void *)inst->session, &buffer_info);
if (rc)
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
index f598dfd..41518d7 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -1575,6 +1575,7 @@
b->m.planes[i].m.userptr;
buffer_info.extradata_size = 0;
buffer_info.extradata_addr = 0;
+ buffer_info.response_required = false;
rc = vidc_hal_session_release_buffers(
(void *)inst->session, &buffer_info);
if (rc)
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index 87f53ac..46a88c2 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -354,6 +354,48 @@
}
}
+static void handle_session_release_buf_done(enum command_response cmd,
+ void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_inst *inst;
+ struct internal_buf *buf;
+ struct list_head *ptr, *next;
+ struct hal_buffer_info *buffer;
+ u32 address, buf_found = false;
+
+ if (!response || !response->data) {
+ dprintk(VIDC_ERR, "Invalid release_buf_done response\n");
+ return;
+ }
+
+ inst = (struct msm_vidc_inst *)response->session_id;
+ buffer = (struct hal_buffer_info *) response->data;
+ address = (u32) buffer->buffer_addr;
+
+ list_for_each_safe(ptr, next, &inst->internalbufs) {
+ buf = list_entry(ptr, struct internal_buf, list);
+ if (address == buf->handle->device_addr) {
+ dprintk(VIDC_DBG, "releasing scratch: 0x%x",
+ (u32) buf->handle->device_addr);
+ buf_found = true;
+ }
+ }
+
+ list_for_each_safe(ptr, next, &inst->persistbufs) {
+ buf = list_entry(ptr, struct internal_buf, list);
+ if (address == (u32) buf->handle->device_addr) {
+ dprintk(VIDC_DBG, "releasing persist: 0x%x",
+ (u32) buf->handle->device_addr);
+ buf_found = true;
+ }
+ }
+
+ if (!buf_found)
+ dprintk(VIDC_ERR, "invalid buffer received from firmware");
+ complete(&inst->completions[SESSION_MSG_INDEX(cmd)]);
+}
+
static void handle_sys_release_res_done(
enum command_response cmd, void *data)
{
@@ -892,6 +934,9 @@
case SESSION_ERROR:
handle_session_error(cmd, data);
break;
+ case SESSION_RELEASE_BUFFER_DONE:
+ handle_session_release_buf_done(cmd, data);
+ break;
default:
dprintk(VIDC_ERR, "response unhandled\n");
break;
@@ -1225,6 +1270,12 @@
goto core_already_inited;
}
+ rc = msm_comm_scale_bus(core, inst->session_type, DDR_MEM);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to scale DDR bus: %d\n", rc);
+ goto fail_scale_bus;
+ }
+
rc = msm_comm_load_fw(core);
if (rc) {
dprintk(VIDC_ERR, "Failed to load video firmware\n");
@@ -1236,11 +1287,6 @@
goto fail_core_init;
}
- rc = msm_comm_scale_bus(core, inst->session_type, DDR_MEM);
- if (rc) {
- dprintk(VIDC_ERR, "Failed to scale DDR bus: %d\n", rc);
- goto fail_core_init;
- }
init_completion(&core->completions[SYS_MSG_INDEX(SYS_INIT_DONE)]);
rc = vidc_hal_core_init(core->device,
core->resources.io_map[NS_MAP].domain);
@@ -1257,8 +1303,9 @@
return rc;
fail_core_init:
msm_comm_unload_fw(core);
- msm_comm_unvote_buses(core, DDR_MEM);
fail_load_fw:
+ msm_comm_unvote_buses(core, DDR_MEM);
+fail_scale_bus:
mutex_unlock(&core->sync_lock);
return rc;
}
@@ -1838,6 +1885,10 @@
buffer_info.align_device_addr = handle->device_addr;
if (inst->state != MSM_VIDC_CORE_INVALID &&
core->state != VIDC_CORE_INVALID) {
+ buffer_info.response_required = true;
+ init_completion(
+ &inst->completions[SESSION_MSG_INDEX
+ (SESSION_RELEASE_BUFFER_DONE)]);
rc = vidc_hal_session_release_buffers(
(void *) inst->session,
&buffer_info);
@@ -1846,6 +1897,10 @@
"Rel scrtch buf fail:0x%x, %d",
buffer_info.align_device_addr,
buffer_info.buffer_size);
+ spin_unlock_irqrestore(&inst->lock, flags);
+ rc = wait_for_sess_signal_receipt(inst,
+ SESSION_RELEASE_BUFFER_DONE);
+ spin_lock_irqsave(&inst->lock, flags);
}
list_del(&buf->list);
spin_unlock_irqrestore(&inst->lock, flags);
@@ -1890,6 +1945,10 @@
buffer_info.align_device_addr = handle->device_addr;
if (inst->state != MSM_VIDC_CORE_INVALID &&
core->state != VIDC_CORE_INVALID) {
+ buffer_info.response_required = true;
+ init_completion(
+ &inst->completions[SESSION_MSG_INDEX
+ (SESSION_RELEASE_BUFFER_DONE)]);
rc = vidc_hal_session_release_buffers(
(void *) inst->session,
&buffer_info);
@@ -1898,6 +1957,10 @@
"Rel prst buf fail:0x%x, %d",
buffer_info.align_device_addr,
buffer_info.buffer_size);
+ spin_unlock_irqrestore(&inst->lock, flags);
+ rc = wait_for_sess_signal_receipt(inst,
+ SESSION_RELEASE_BUFFER_DONE);
+ spin_lock_irqsave(&inst->lock, flags);
}
list_del(&buf->list);
spin_unlock_irqrestore(&inst->lock, flags);
@@ -1980,6 +2043,8 @@
buffer_info.buffer_type = HAL_BUFFER_INTERNAL_SCRATCH;
buffer_info.num_buffers = 1;
buffer_info.align_device_addr = handle->device_addr;
+ dprintk(VIDC_DBG, "Scratch buffer address: %x",
+ buffer_info.align_device_addr);
rc = vidc_hal_session_set_buffers(
(void *) inst->session, &buffer_info);
if (rc) {
@@ -2051,6 +2116,8 @@
buffer_info.buffer_type = HAL_BUFFER_INTERNAL_PERSIST;
buffer_info.num_buffers = 1;
buffer_info.align_device_addr = handle->device_addr;
+ dprintk(VIDC_DBG, "Persist buffer address: %x",
+ buffer_info.align_device_addr);
rc = vidc_hal_session_set_buffers(
(void *) inst->session, &buffer_info);
if (rc) {
diff --git a/drivers/media/video/msm_vidc/vidc_hal.c b/drivers/media/video/msm_vidc/vidc_hal.c
index e449821..207bfe4 100644
--- a/drivers/media/video/msm_vidc/vidc_hal.c
+++ b/drivers/media/video/msm_vidc/vidc_hal.c
@@ -1954,6 +1954,7 @@
pkt->size = sizeof(struct hfi_cmd_session_set_buffers_packet) +
((buffer_info->num_buffers - 1) * sizeof(u32));
}
+ pkt->response_req = buffer_info->response_required;
buffer = get_hfi_buffer(buffer_info->buffer_type);
if (buffer)
pkt->buffer_type = buffer;
diff --git a/drivers/media/video/msm_vidc/vidc_hal.h b/drivers/media/video/msm_vidc/vidc_hal.h
index 57d685b..c8a7d43 100644
--- a/drivers/media/video/msm_vidc/vidc_hal.h
+++ b/drivers/media/video/msm_vidc/vidc_hal.h
@@ -271,6 +271,8 @@
(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x013)
#define HFI_PROPERTY_PARAM_VDEC_INTERLACE_VIDEO_EXTRADATA \
(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x014)
+#define HFI_PROPERTY_PARAM_VDEC_AVC_SESSION_SELECT \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x015)
#define HFI_PROPERTY_CONFIG_VDEC_OX_START \
(HFI_DOMAIN_BASE_VDEC + HFI_ARCH_OX_OFFSET + 0x0000)
@@ -479,6 +481,7 @@
u32 input_tag;
u8 *packet_buffer;
u8 *extra_data_buffer;
+ u32 rgData[0];
};
struct hfi_cmd_session_empty_buffer_uncompressed_plane0_packet {
@@ -497,6 +500,7 @@
u32 input_tag;
u8 *packet_buffer;
u8 *extra_data_buffer;
+ u32 rgData[0];
};
struct hfi_cmd_session_empty_buffer_uncompressed_plane1_packet {
@@ -505,6 +509,7 @@
u32 filled_len;
u32 offset;
u8 *packet_buffer2;
+ u32 rgData[0];
};
struct hfi_cmd_session_empty_buffer_uncompressed_plane2_packet {
@@ -513,6 +518,7 @@
u32 filled_len;
u32 offset;
u8 *packet_buffer3;
+ u32 rgData[0];
};
struct hfi_cmd_session_fill_buffer_packet {
@@ -526,6 +532,7 @@
u32 output_tag;
u8 *packet_buffer;
u8 *extra_data_buffer;
+ u32 rgData[0];
};
struct hfi_cmd_session_flush_packet {
@@ -659,6 +666,7 @@
u32 input_tag;
u8 *packet_buffer;
u8 *extra_data_buffer;
+ u32 rgData[0];
};
struct hfi_msg_session_fill_buffer_done_compressed_packet {
@@ -680,6 +688,7 @@
u32 picture_type;
u8 *packet_buffer;
u8 *extra_data_buffer;
+ u32 rgData[0];
};
struct hfi_msg_session_fbd_uncompressed_plane0_packet {
@@ -708,6 +717,7 @@
u32 picture_type;
u8 *packet_buffer;
u8 *extra_data_buffer;
+ u32 rgData[0];
};
struct hfi_msg_session_fill_buffer_done_uncompressed_plane1_packet {
@@ -716,6 +726,7 @@
u32 filled_len;
u32 offset;
u8 *packet_buffer2;
+ u32 rgData[0];
};
struct hfi_msg_session_fill_buffer_done_uncompressed_plane2_packet {
@@ -724,6 +735,7 @@
u32 filled_len;
u32 offset;
u8 *packet_buffer3;
+ u32 rgData[0];
};
struct hfi_msg_session_parse_sequence_header_done_packet {
diff --git a/drivers/media/video/msm_vidc/vidc_hal_api.h b/drivers/media/video/msm_vidc/vidc_hal_api.h
index 9d20a31..3b83424 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_api.h
+++ b/drivers/media/video/msm_vidc/vidc_hal_api.h
@@ -777,6 +777,12 @@
u32 align_device_addr;
u32 extradata_size;
u32 extradata_addr;
+ u32 response_required;
+};
+
+struct hal_buffer_info {
+ u32 buffer_addr;
+ u32 extra_data_addr;
};
struct vidc_frame_plane_config {
diff --git a/drivers/media/video/msm_vidc/vidc_hal_helper.h b/drivers/media/video/msm_vidc/vidc_hal_helper.h
index 9412eed..9f805d7 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_helper.h
+++ b/drivers/media/video/msm_vidc/vidc_hal_helper.h
@@ -224,6 +224,8 @@
(HFI_PROPERTY_PARAM_COMMON_START + 0x00D)
#define HFI_PROPERTY_PARAM_CODEC_MASK_SUPPORTED \
(HFI_PROPERTY_PARAM_COMMON_START + 0x00E)
+#define HFI_PROPERTY_PARAM_MVC_BUFFER_LAYOUT \
+ (HFI_PROPERTY_PARAM_COMMON_START + 0x00F)
#define HFI_PROPERTY_CONFIG_COMMON_START \
(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + 0x2000)
@@ -632,6 +634,15 @@
u32 aspect_width;
u32 aspect_height;
};
+#define HFI_MVC_BUFFER_LAYOUT_TOP_BOTTOM (0)
+#define HFI_MVC_BUFFER_LAYOUT_SIDEBYSIDE (1)
+#define HFI_MVC_BUFFER_LAYOUT_SEQ (2)
+struct hfi_mvc_buffer_lauout_descp_type {
+ u32 layout_type;
+ u32 bright_view_first;
+ u32 ngap;
+};
+
#define HFI_CMD_SYS_COMMON_START \
(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + HFI_CMD_START_OFFSET \
diff --git a/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c b/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
index 8231bd4..3bedb92 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
+++ b/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
@@ -533,7 +533,7 @@
dprintk(VIDC_DBG, "RECEIVED:SESSION_ETB_DONE");
- if (!pkt || pkt->size !=
+ if (!pkt || pkt->size <
sizeof(struct hfi_msg_session_empty_buffer_done_packet)) {
dprintk(VIDC_ERR, "hal_process_session_etb_done:bad_pkt_size");
return;
@@ -579,7 +579,7 @@
msg_hdr;
if (sizeof(struct
hfi_msg_session_fill_buffer_done_compressed_packet)
- != pkt->size) {
+ > pkt->size) {
dprintk(VIDC_ERR,
"hal_process_session_ftb_done: bad_pkt_size");
return;
@@ -732,6 +732,31 @@
device->callback(SESSION_RELEASE_RESOURCE_DONE, &cmd_done);
}
+static void hal_process_session_rel_buf_done(struct hal_device *device,
+ struct hfi_msg_session_release_buffers_done_packet *pkt)
+{
+ struct msm_vidc_cb_cmd_done cmd_done;
+ if (!pkt || pkt->size !=
+ sizeof(struct
+ hfi_msg_session_release_buffers_done_packet)) {
+ dprintk(VIDC_ERR, "bad packet/packet size: %d", pkt->size);
+ return;
+ }
+ memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
+ cmd_done.device_id = device->device_id;
+ cmd_done.size = sizeof(struct msm_vidc_cb_cmd_done);
+ cmd_done.session_id =
+ ((struct hal_session *) pkt->session_id)->session_id;
+ cmd_done.status = vidc_map_hal_err_status((u32)pkt->error_type);
+ if (pkt->rg_buffer_info) {
+ cmd_done.data = (void *) &pkt->rg_buffer_info;
+ cmd_done.size = sizeof(struct hfi_buffer_info);
+ } else {
+ dprintk(VIDC_ERR, "invalid payload in rel_buff_done\n");
+ }
+ device->callback(SESSION_RELEASE_BUFFER_DONE, &cmd_done);
+}
+
static void hal_process_session_end_done(struct hal_device *device,
struct hfi_msg_sys_session_end_done_packet *pkt)
{
@@ -870,6 +895,11 @@
hfi_msg_session_get_sequence_header_done_packet
*) msg_hdr);
break;
+ case HFI_MSG_SESSION_RELEASE_BUFFERS_DONE:
+ hal_process_session_rel_buf_done(device, (struct
+ hfi_msg_session_release_buffers_done_packet
+ *) msg_hdr);
+ break;
default:
dprintk(VIDC_ERR, "UNKNOWN_MSG_TYPE : %d", msg_hdr->packet);
break;
diff --git a/drivers/media/video/msm_wfd/enc-mfc-subdev.c b/drivers/media/video/msm_wfd/enc-mfc-subdev.c
index 45532a9..21fc719 100644
--- a/drivers/media/video/msm_wfd/enc-mfc-subdev.c
+++ b/drivers/media/video/msm_wfd/enc-mfc-subdev.c
@@ -40,6 +40,7 @@
int secure;
struct mem_region unqueued_op_bufs;
bool streaming;
+ enum venc_framerate_modes framerate_mode;
};
struct venc {
@@ -301,6 +302,8 @@
inst->cbdata = vmops->cbdata;
inst->secure = vmops->secure;
inst->streaming = false;
+ inst->framerate_mode = VENC_MODE_VFR;
+
if (vmops->secure) {
WFD_MSG_ERR("OPENING SECURE SESSION\n");
flags |= VCD_CP_SESSION;
@@ -1123,6 +1126,14 @@
return rc;
}
+static long venc_set_framerate_mode(struct v4l2_subdev *sd,
+ void *arg)
+{
+ struct venc_inst *inst = sd->dev_priv;
+ inst->framerate_mode = *(enum venc_framerate_modes *)arg;
+ return 0;
+}
+
static long venc_set_qp_value(struct video_client_ctx *client_ctx,
__s32 frametype, __s32 qp)
{
@@ -1400,6 +1411,51 @@
return rc;
}
+static long venc_set_vui_timing_info(struct video_client_ctx *client_ctx,
+ struct venc_inst *inst, __s32 flag)
+{
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_vui_timing_info_enable vui_timing_info_enable;
+
+ if (!client_ctx)
+ return -EINVAL;
+ if (inst->framerate_mode == VENC_MODE_VFR) {
+ WFD_MSG_ERR("VUI timing info not suported in VFR mode ");
+ return -EINVAL;
+ }
+ vcd_property_hdr.prop_id = VCD_I_ENABLE_VUI_TIMING_INFO;
+ vcd_property_hdr.sz =
+ sizeof(struct vcd_property_vui_timing_info_enable);
+ vui_timing_info_enable.vui_timing_info = flag;
+ return vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &vui_timing_info_enable);
+}
+
+static long venc_get_vui_timing_info(struct video_client_ctx *client_ctx,
+ __s32 *flag)
+{
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_vui_timing_info_enable vui_timing_info_enable;
+ int rc = 0;
+
+ if (!client_ctx || !flag)
+ return -EINVAL;
+
+ vcd_property_hdr.prop_id = VCD_I_ENABLE_VUI_TIMING_INFO;
+ vcd_property_hdr.sz =
+ sizeof(struct vcd_property_vui_timing_info_enable);
+ rc = vcd_get_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &vui_timing_info_enable);
+
+ if (rc < 0) {
+ WFD_MSG_ERR("Failed getting property for VUI timing info");
+ return rc;
+ }
+
+ *flag = vui_timing_info_enable.vui_timing_info;
+ return rc;
+}
+
static long venc_set_header_mode(struct video_client_ctx *client_ctx,
__s32 mode)
{
@@ -2285,6 +2341,9 @@
case V4L2_CID_MPEG_VIDC_VIDEO_H264_AU_DELIMITER:
rc = venc_set_avc_delimiter(client_ctx, ctrl->value);
break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO:
+ rc = venc_set_vui_timing_info(client_ctx, inst, ctrl->value);
+ break;
case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
rc = venc_set_entropy_mode(client_ctx, ctrl->value);
break;
@@ -2359,6 +2418,9 @@
case V4L2_CID_MPEG_VIDC_VIDEO_H264_AU_DELIMITER:
rc = venc_get_avc_delimiter(client_ctx, &ctrl->value);
break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO:
+ rc = venc_get_vui_timing_info(client_ctx, &ctrl->value);
+ break;
default:
WFD_MSG_ERR("Get property not suported: %d\n", ctrl->id);
rc = -ENOTSUPP;
@@ -2503,6 +2565,9 @@
case ENC_MUNMAP:
rc = venc_munmap(sd, arg);
break;
+ case SET_FRAMERATE_MODE:
+ rc = venc_set_framerate_mode(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 c6c854e..25373e4 100644
--- a/drivers/media/video/msm_wfd/enc-subdev.h
+++ b/drivers/media/video/msm_wfd/enc-subdev.h
@@ -20,6 +20,11 @@
#include <media/videobuf2-core.h>
#define VENC_MAGIC_IOCTL 'V'
+enum venc_framerate_modes {
+ VENC_MODE_CFR,
+ VENC_MODE_VFR,
+};
+
struct mem_region {
struct list_head list;
u8 *kvaddr;
@@ -101,6 +106,7 @@
#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 *)
+#define SET_FRAMERATE_MODE _IO('V', 27)
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
index 150c667..480fe35 100644
--- a/drivers/media/video/msm_wfd/enc-venus-subdev.c
+++ b/drivers/media/video/msm_wfd/enc-venus-subdev.c
@@ -136,7 +136,7 @@
msm_vidc_dqevent(inst->vidc_context, &event);
if (event.type == V4L2_EVENT_MSM_VIDC_CLOSE_DONE) {
- WFD_MSG_ERR("enc callback thread shutting " \
+ WFD_MSG_DBG("enc callback thread shutting " \
"down normally\n");
bail_out = true;
} else {
@@ -1141,6 +1141,15 @@
return 0;
}
+static long venc_set_framerate_mode(struct v4l2_subdev *sd,
+ void *arg)
+{
+ /* TODO: Unsupported for now, but return false success
+ * to preserve binary compatibility for userspace apps
+ * across targets */
+ return 0;
+}
+
long venc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
long rc = 0;
@@ -1210,6 +1219,9 @@
case ENC_MUNMAP:
rc = venc_munmap(sd, arg);
break;
+ case SET_FRAMERATE_MODE:
+ rc = venc_set_framerate_mode(sd, arg);
+ break;
default:
WFD_MSG_ERR("Unknown ioctl %d to enc-subdev\n", cmd);
rc = -ENOTSUPP;
diff --git a/drivers/media/video/msm_wfd/wfd-ioctl.c b/drivers/media/video/msm_wfd/wfd-ioctl.c
index 5f67a96..74194ff 100644
--- a/drivers/media/video/msm_wfd/wfd-ioctl.c
+++ b/drivers/media/video/msm_wfd/wfd-ioctl.c
@@ -240,6 +240,7 @@
int rc;
unsigned long flags;
struct mdp_buf_info mdp_buf = {0};
+ struct mem_region_map mmap_context = {0};
spin_lock_irqsave(&inst->inst_lock, flags);
if (inst->input_bufs_allocated) {
spin_unlock_irqrestore(&inst->inst_lock, flags);
@@ -249,7 +250,6 @@
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);
@@ -278,6 +278,10 @@
rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
SET_INPUT_BUFFER, (void *)enc_mregion);
+ if (rc) {
+ WFD_MSG_ERR("Setting enc input buffer failed\n");
+ goto set_input_fail;
+ }
/* map the buffer from encoder to mdp */
mdp_mregion->kvaddr = enc_mregion->kvaddr;
@@ -301,7 +305,7 @@
mdp_mregion->kvaddr = NULL;
mdp_mregion->paddr = NULL;
mdp_mregion->ion_handle = NULL;
- goto alloc_fail;
+ goto mdp_mmap_fail;
}
mdp_buf.inst = inst->mdp_inst;
@@ -314,34 +318,58 @@
((int)mdp_mregion->paddr + mdp_mregion->size),
mdp_mregion->kvaddr);
- INIT_LIST_HEAD(&mpair->list);
- mpair->enc = enc_mregion;
- mpair->mdp = mdp_mregion;
- list_add_tail(&mpair->list, &inst->input_mem_list);
-
rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
MDP_Q_BUFFER, (void *)&mdp_buf);
if (rc) {
WFD_MSG_ERR("Unable to queue the"
" buffer to mdp\n");
- break;
+ goto mdp_q_fail;
} else {
wfd_stats_update(&inst->stats,
WFD_STAT_EVENT_MDP_QUEUE);
}
+
+ INIT_LIST_HEAD(&mpair->list);
+ mpair->enc = enc_mregion;
+ mpair->mdp = mdp_mregion;
+ list_add_tail(&mpair->list, &inst->input_mem_list);
+
}
+
rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
ALLOC_RECON_BUFFERS, NULL);
if (rc) {
WFD_MSG_ERR("Failed to allocate recon buffers\n");
- goto alloc_fail;
+ goto recon_alloc_fail;
}
return rc;
+ /*
+ * Clean up only the buffer that we failed in setting up.
+ * Caller will clean up the rest by calling free_input_buffers()
+ */
+mdp_q_fail:
+ 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;
+ v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
+ MDP_MUNMAP, (void *)&mmap_context);
+mdp_mmap_fail:
+ v4l2_subdev_call(&wfd_dev->enc_sdev,
+ core, ioctl, FREE_INPUT_BUFFER,
+ (void *)enc_mregion);
+set_input_fail:
+ memset(&mmap_context, 0, sizeof(mmap_context));
+ mmap_context.ion_client = wfd_dev->ion_client;
+ mmap_context.mregion = enc_mregion;
+ v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
+ ENC_MUNMAP, &mmap_context);
alloc_fail:
kfree(mpair);
kfree(enc_mregion);
kfree(mdp_mregion);
+recon_alloc_fail:
return rc;
}
void wfd_free_input_buffers(struct wfd_device *wfd_dev,
@@ -508,7 +536,7 @@
struct mem_region mregion;
if (minfo == NULL) {
- WFD_MSG_ERR("not freeing buffers since allocation failed");
+ WFD_MSG_DBG("not freeing buffers since allocation failed");
return;
}
@@ -1047,7 +1075,8 @@
struct v4l2_qcom_frameskip frameskip;
int64_t frame_interval, max_frame_interval;
void *extendedmode = NULL;
- enum vsg_modes mode = VSG_MODE_VFR;
+ enum vsg_modes vsg_mode = VSG_MODE_VFR;
+ enum venc_framerate_modes venc_mode = VENC_MODE_VFR;
if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
@@ -1097,7 +1126,8 @@
goto set_parm_fail;
max_frame_interval = (int64_t)frameskip.maxframeinterval;
- mode = VSG_MODE_VFR;
+ vsg_mode = VSG_MODE_VFR;
+ venc_mode = VENC_MODE_VFR;
rc = v4l2_subdev_call(&wfd_dev->vsg_sdev, core,
ioctl, VSG_SET_MAX_FRAME_INTERVAL,
@@ -1105,19 +1135,24 @@
if (rc)
goto set_parm_fail;
-
- rc = v4l2_subdev_call(&wfd_dev->vsg_sdev, core,
- ioctl, VSG_SET_MODE, &mode);
-
- if (rc)
- goto set_parm_fail;
} else {
- mode = VSG_MODE_CFR;
- rc = v4l2_subdev_call(&wfd_dev->vsg_sdev, core,
- ioctl, VSG_SET_MODE, &mode);
+ vsg_mode = VSG_MODE_CFR;
+ venc_mode = VENC_MODE_CFR;
+ }
- if (rc)
- goto set_parm_fail;
+ rc = v4l2_subdev_call(&wfd_dev->vsg_sdev, core,
+ ioctl, VSG_SET_MODE, &vsg_mode);
+ if (rc) {
+ WFD_MSG_ERR("Setting FR mode for VSG failed\n");
+ goto set_parm_fail;
+ }
+
+ rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core,
+ ioctl, SET_FRAMERATE_MODE,
+ &venc_mode);
+ if (rc) {
+ WFD_MSG_ERR("Setting FR mode for VENC failed\n");
+ goto set_parm_fail;
}
set_parm_fail:
diff --git a/drivers/media/video/msm_wfd/wfd-util.c b/drivers/media/video/msm_wfd/wfd-util.c
index 5c00e5c..28a6084 100644
--- a/drivers/media/video/msm_wfd/wfd-util.c
+++ b/drivers/media/video/msm_wfd/wfd-util.c
@@ -198,7 +198,7 @@
int wfd_stats_deinit(struct wfd_stats *stats)
{
- WFD_MSG_ERR("Latencies: avg enc. latency %d",
+ WFD_MSG_DBG("Latencies: avg enc. latency %d",
stats->enc_avg_latency);
/* Delete all debugfs files in one shot :) */
if (stats->d_parent)
diff --git a/drivers/media/video/vcap_v4l2.c b/drivers/media/video/vcap_v4l2.c
index f009e06..5b76c35 100644
--- a/drivers/media/video/vcap_v4l2.c
+++ b/drivers/media/video/vcap_v4l2.c
@@ -568,6 +568,17 @@
return 0;
}
+void free_ion_on_q_bufs(struct vb2_queue *vq)
+{
+ struct vcap_client_data *c_data = vb2_get_drv_priv(vq);
+ struct vb2_buffer *vb;
+
+ if (!vq->streaming) {
+ list_for_each_entry(vb, &vq->queued_list, queued_entry)
+ free_ion_handle_work(c_data, vb);
+ }
+}
+
/* VC Videobuf operations */
static void wait_prepare(struct vb2_queue *q)
{
@@ -1874,6 +1885,10 @@
}
v4l2_fh_del(&c_data->vfh);
v4l2_fh_exit(&c_data->vfh);
+ free_ion_on_q_bufs(&c_data->vp_out_vidq);
+ free_ion_on_q_bufs(&c_data->vp_in_vidq);
+ free_ion_on_q_bufs(&c_data->vc_vidq);
+
vb2_queue_release(&c_data->vp_out_vidq);
vb2_queue_release(&c_data->vp_in_vidq);
vb2_queue_release(&c_data->vc_vidq);
diff --git a/drivers/misc/tspp.c b/drivers/misc/tspp.c
index f310524..eebaab9 100644
--- a/drivers/misc/tspp.c
+++ b/drivers/misc/tspp.c
@@ -35,6 +35,8 @@
#include <mach/sps.h> /* BAM stuff */
#include <mach/gpio.h>
#include <linux/wakelock.h> /* Locking functions */
+#include <linux/timer.h> /* Timer services */
+#include <linux/jiffies.h> /* Jiffies counter */
#include <mach/dma.h>
#include <mach/msm_tspp.h>
#include <linux/debugfs.h>
@@ -49,11 +51,24 @@
#define TSPP_NUM_PRIORITIES 16
#define TSPP_NUM_KEYS 8
#define INVALID_CHANNEL 0xFFFFFFFF
-#define TSPP_SPS_DESCRIPTOR_COUNT 128
+
+/*
+ * BAM descriptor FIFO size (in number of descriptors).
+ * Max number of descriptors allowed by SPS which is 8K-1.
+ * Restrict it to half of this to save DMA memory.
+ */
+#define TSPP_SPS_DESCRIPTOR_COUNT (4 * 1024 - 1)
#define TSPP_PACKET_LENGTH 188
#define TSPP_MIN_BUFFER_SIZE (TSPP_PACKET_LENGTH)
-#define TSPP_MAX_BUFFER_SIZE (32 * 1024)
-#define TSPP_NUM_BUFFERS 64
+
+/* Max descriptor buffer size allowed by SPS */
+#define TSPP_MAX_BUFFER_SIZE (32 * 1024 - 1)
+
+/*
+ * Max allowed TSPP buffers/descriptors.
+ * If SPS desc FIFO holds X descriptors, we can queue up to X-1 descriptors.
+ */
+#define TSPP_NUM_BUFFERS (TSPP_SPS_DESCRIPTOR_COUNT - 1)
#define TSPP_TSIF_DEFAULT_TIME_LIMIT 60
#define SPS_DESCRIPTOR_SIZE 8
#define MIN_ACCEPTABLE_BUFFER_COUNT 2
@@ -307,6 +322,8 @@
#define CONTEXT_UNSPEC_LENGTH BIT(11)
#define CONTEXT_GET_CONT_COUNT(_a) ((_a >> 12) & 0xF)
+#define MSEC_TO_JIFFIES(msec) ((msec) * HZ / 1000)
+
struct tspp_pipe_performance_regs {
u32 tsp_total;
u32 ps_duplicate_tsp;
@@ -379,7 +396,8 @@
enum tspp_mode mode;
tspp_notifier *notifier; /* used only with kernel api */
void *notify_data; /* data to be passed with the notifier */
- u32 notify_timer; /* notification for partially filled buffers */
+ u32 expiration_period_ms; /* notification on partially filled buffers */
+ struct timer_list expiration_timer;
tspp_memfree *memfree; /* user defined memory free function */
void *user_info; /* user cookie passed to memory alloc/free function */
};
@@ -539,6 +557,14 @@
tasklet_schedule(&pdev->tlet);
}
+static void tspp_expiration_timer(unsigned long data)
+{
+ struct tspp_device *pdev = (struct tspp_device *)data;
+
+ if (pdev)
+ tasklet_schedule(&pdev->tlet);
+}
+
/*** tasklet ***/
static void tspp_sps_complete_tlet(unsigned long data)
{
@@ -553,9 +579,14 @@
for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
complete = 0;
channel = &device->channels[i];
+
if (!channel->used || !channel->waiting)
continue;
+ /* stop the expiration timer */
+ if (channel->expiration_period_ms)
+ del_timer(&channel->expiration_timer);
+
/* get completions */
while (channel->waiting->state == TSPP_BUF_STATE_WAITING) {
if (sps_get_iovec(channel->pipe, &iovec) != 0) {
@@ -593,6 +624,13 @@
channel->notifier(channel->id,
channel->notify_data);
}
+
+ /* restart expiration timer */
+ if (channel->expiration_period_ms)
+ mod_timer(&channel->expiration_timer,
+ jiffies +
+ MSEC_TO_JIFFIES(
+ channel->expiration_period_ms));
}
spin_unlock_irqrestore(&device->spinlock, flags);
@@ -897,7 +935,7 @@
/* generate interrupt according to requested frequency */
if (buffer->desc.id % channel->int_freq == channel->int_freq-1)
- flags = SPS_IOVEC_FLAG_INT | SPS_IOVEC_FLAG_EOB;
+ flags = SPS_IOVEC_FLAG_INT;
/* start the transfer */
rc = sps_transfer_one(channel->pipe,
@@ -1034,7 +1072,7 @@
channel->mode = TSPP_MODE_DISABLED;
channel->notifier = NULL;
channel->notify_data = NULL;
- channel->notify_timer = 0;
+ channel->expiration_period_ms = 0;
channel->memfree = NULL;
channel->user_info = NULL;
init_waitqueue_head(&channel->in_queue);
@@ -1394,10 +1432,11 @@
SPS_O_AUTO_ENABLE | /* connection is auto-enabled */
SPS_O_STREAMING | /* streaming mode */
SPS_O_DESC_DONE | /* interrupt on end of descriptor */
- SPS_O_ACK_TRANSFERS; /* must use sps_get_iovec() */
+ SPS_O_ACK_TRANSFERS | /* must use sps_get_iovec() */
+ SPS_O_HYBRID; /* Read actual descriptors in sps_get_iovec() */
config->src_pipe_index = channel->id;
config->desc.size =
- (TSPP_SPS_DESCRIPTOR_COUNT + 1) * SPS_DESCRIPTOR_SIZE;
+ TSPP_SPS_DESCRIPTOR_COUNT * SPS_DESCRIPTOR_SIZE;
config->desc.base = dma_alloc_coherent(NULL,
config->desc.size,
&config->desc.phys_base,
@@ -1428,6 +1467,11 @@
goto err_event;
}
+ init_timer(&channel->expiration_timer);
+ channel->expiration_timer.function = tspp_expiration_timer;
+ channel->expiration_timer.data = (unsigned long)pdev;
+ channel->expiration_timer.expires = 0xffffffffL;
+
rc = pm_runtime_get(&pdev->pdev->dev);
if (rc < 0) {
dev_err(&pdev->pdev->dev,
@@ -1482,9 +1526,12 @@
if (!channel->used)
return 0;
+ if (channel->expiration_period_ms)
+ del_timer(&channel->expiration_timer);
+
channel->notifier = NULL;
channel->notify_data = NULL;
- channel->notify_timer = 0;
+ channel->expiration_period_ms = 0;
config = &channel->config;
pdev = channel->pdev;
@@ -1833,7 +1880,8 @@
channel = &pdev->channels[channel_id];
channel->notifier = pNotify;
channel->notify_data = userdata;
- channel->notify_timer = timer_ms;
+ channel->expiration_period_ms = timer_ms;
+
return 0;
}
EXPORT_SYMBOL(tspp_register_notification);
@@ -2113,6 +2161,13 @@
channel->read = channel->data;
channel->locked = channel->data;
+ /* Now that buffers are scheduled to HW, kick data expiration timer */
+ if (channel->expiration_period_ms)
+ mod_timer(&channel->expiration_timer,
+ jiffies +
+ MSEC_TO_JIFFIES(
+ channel->expiration_period_ms));
+
return 0;
}
EXPORT_SYMBOL(tspp_allocate_buffers);
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index fde13c7..76e9b9c 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -1022,9 +1022,6 @@
goto out;
}
- if (mmc_can_sanitize(card))
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_SANITIZE_START, 1, 0);
out_retry:
if (err && !mmc_blk_reset(md, card->host, type))
goto retry;
@@ -1429,6 +1426,10 @@
if (!(host->caps2 & MMC_CAP2_PACKED_WR))
return;
+ /* Support for the write packing on eMMC 4.5 or later */
+ if (mq->card->ext_csd.rev <= 5)
+ return;
+
/*
* In case the packing control is not supported by the host, it should
* not have an effect on the write packing. Therefore we have to enable
@@ -2115,6 +2116,8 @@
md->disk->driverfs_dev = parent;
set_disk_ro(md->disk, md->read_only || default_ro);
md->disk->flags = GENHD_FL_EXT_DEVT;
+ if (area_type & MMC_BLK_DATA_AREA_RPMB)
+ md->disk->flags |= GENHD_FL_NO_PART_SCAN;
/*
* As discussed on lkml, GENHD_FL_REMOVABLE should:
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 48516b6..f91ba89 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -29,6 +29,7 @@
#include <linux/wakelock.h>
#include <linux/pm.h>
#include <linux/slab.h>
+#include <linux/jiffies.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
@@ -44,6 +45,8 @@
#include "sd_ops.h"
#include "sdio_ops.h"
+static void mmc_clk_scaling(struct mmc_host *host, bool from_wq);
+
/*
* Background operations can take a long time, depending on the housekeeping
* operations the card has to perform.
@@ -171,6 +174,10 @@
#ifdef CONFIG_MMC_PERF_PROFILING
ktime_t diff;
#endif
+ if (host->card && host->clk_scaling.enable)
+ host->clk_scaling.busy_time_us +=
+ ktime_to_us(ktime_sub(ktime_get(),
+ host->clk_scaling.start_busy));
if (err && cmd->retries && mmc_host_is_spi(host)) {
if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND)
@@ -300,6 +307,19 @@
}
mmc_host_clk_hold(host);
led_trigger_event(host->led, LED_FULL);
+
+ if (host->card && host->clk_scaling.enable) {
+ /*
+ * Check if we need to scale the clocks. Clocks
+ * will be scaled up immediately if necessary
+ * conditions are satisfied. Scaling down the
+ * frequency will be done after current thread
+ * releases host.
+ */
+ mmc_clk_scaling(host, false);
+ host->clk_scaling.start_busy = ktime_get();
+ }
+
host->ops->request(host, mrq);
}
@@ -2286,6 +2306,289 @@
}
EXPORT_SYMBOL(mmc_hw_reset_check);
+/**
+ * mmc_reset_clk_scale_stats() - reset clock scaling statistics
+ * @host: pointer to mmc host structure
+ */
+void mmc_reset_clk_scale_stats(struct mmc_host *host)
+{
+ host->clk_scaling.busy_time_us = 0;
+ host->clk_scaling.window_time = jiffies;
+}
+EXPORT_SYMBOL_GPL(mmc_reset_clk_scale_stats);
+
+/**
+ * mmc_get_max_frequency() - get max. frequency supported
+ * @host: pointer to mmc host structure
+ *
+ * Returns max. frequency supported by card/host. If the
+ * timing mode is SDR50/SDR104/HS200/DDR50 return appropriate
+ * max. frequency in these modes else, use the current frequency.
+ * Also, allow host drivers to overwrite the frequency in case
+ * they support "get_max_frequency" host ops.
+ */
+unsigned long mmc_get_max_frequency(struct mmc_host *host)
+{
+ unsigned long freq;
+
+ if (host->ops && host->ops->get_max_frequency) {
+ freq = host->ops->get_max_frequency(host);
+ goto out;
+ }
+
+ switch (host->ios.timing) {
+ case MMC_TIMING_UHS_SDR50:
+ freq = UHS_SDR50_MAX_DTR;
+ break;
+ case MMC_TIMING_UHS_SDR104:
+ freq = UHS_SDR104_MAX_DTR;
+ break;
+ case MMC_TIMING_MMC_HS200:
+ freq = MMC_HS200_MAX_DTR;
+ break;
+ case MMC_TIMING_UHS_DDR50:
+ freq = UHS_DDR50_MAX_DTR;
+ break;
+ default:
+ mmc_host_clk_hold(host);
+ freq = host->ios.clock;
+ mmc_host_clk_release(host);
+ break;
+ }
+
+out:
+ return freq;
+}
+EXPORT_SYMBOL_GPL(mmc_get_max_frequency);
+
+/**
+ * mmc_get_min_frequency() - get min. frequency supported
+ * @host: pointer to mmc host structure
+ *
+ * Returns min. frequency supported by card/host which doesn't impair
+ * performance for most usecases. If the timing mode is SDR50/SDR104/HS200
+ * return 50MHz value. If timing mode is DDR50 return 25MHz so that
+ * throughput would be equivalent to SDR50/SDR104 in 50MHz. Also, allow
+ * host drivers to overwrite the frequency in case they support
+ * "get_min_frequency" host ops.
+ */
+static unsigned long mmc_get_min_frequency(struct mmc_host *host)
+{
+ unsigned long freq;
+
+ if (host->ops && host->ops->get_min_frequency) {
+ freq = host->ops->get_min_frequency(host);
+ goto out;
+ }
+
+ switch (host->ios.timing) {
+ case MMC_TIMING_UHS_SDR50:
+ case MMC_TIMING_UHS_SDR104:
+ freq = UHS_SDR25_MAX_DTR;
+ break;
+ case MMC_TIMING_MMC_HS200:
+ freq = MMC_HIGH_52_MAX_DTR;
+ break;
+ case MMC_TIMING_UHS_DDR50:
+ freq = UHS_DDR50_MAX_DTR / 2;
+ break;
+ default:
+ mmc_host_clk_hold(host);
+ freq = host->ios.clock;
+ mmc_host_clk_release(host);
+ break;
+ }
+
+out:
+ return freq;
+}
+
+/*
+ * Scale down clocks to minimum frequency supported.
+ * The delayed work re-arms itself in case it cannot
+ * claim the host.
+ */
+static void mmc_clk_scale_work(struct work_struct *work)
+{
+ struct mmc_host *host = container_of(work, struct mmc_host,
+ clk_scaling.work.work);
+
+ if (!host->card || !host->bus_ops ||
+ !host->bus_ops->change_bus_speed ||
+ !host->clk_scaling.enable || !host->ios.clock)
+ goto out;
+
+ if (!mmc_try_claim_host(host)) {
+ /* retry after a timer tick */
+ queue_delayed_work(system_nrt_wq, &host->clk_scaling.work, 1);
+ goto out;
+ }
+
+ mmc_clk_scaling(host, true);
+ mmc_release_host(host);
+out:
+ return;
+}
+
+
+/**
+ * mmc_clk_scaling() - clock scaling decision algorithm
+ * @host: pointer to mmc host structure
+ * @from_wq: variable that specifies the context in which
+ * mmc_clk_scaling() is called.
+ *
+ * Calculate load percentage based on host busy time
+ * and total sampling interval and decide clock scaling
+ * based on scale up/down thresholds.
+ * If load is greater than up threshold increase the
+ * frequency to maximum as supported by host. Else,
+ * if load is less than down threshold, scale down the
+ * frequency to minimum supported by the host. Otherwise,
+ * retain current frequency and do nothing.
+ */
+static void mmc_clk_scaling(struct mmc_host *host, bool from_wq)
+{
+ int err = 0;
+ struct mmc_card *card = host->card;
+ unsigned long total_time_ms = 0;
+ unsigned long busy_time_ms = 0;
+ unsigned long freq;
+ unsigned int up_threshold = host->clk_scaling.up_threshold;
+ unsigned int down_threshold = host->clk_scaling.down_threshold;
+ bool queue_scale_down_work = false;
+
+ if (!card || !host->bus_ops || !host->bus_ops->change_bus_speed) {
+ pr_err("%s: %s: invalid entry\n", mmc_hostname(host), __func__);
+ goto out;
+ }
+
+ /* Check if the clocks are already gated. */
+ if (!host->ios.clock)
+ goto out;
+
+ if (time_is_after_jiffies(host->clk_scaling.window_time +
+ msecs_to_jiffies(host->clk_scaling.polling_delay_ms)))
+ goto out;
+
+ /* handle time wrap */
+ total_time_ms = jiffies_to_msecs((long)jiffies -
+ (long)host->clk_scaling.window_time);
+
+ /* Check if we re-enter during clock switching */
+ if (unlikely(host->clk_scaling.in_progress))
+ goto out;
+
+ host->clk_scaling.in_progress = true;
+
+ busy_time_ms = host->clk_scaling.busy_time_us / USEC_PER_MSEC;
+
+ freq = host->clk_scaling.curr_freq;
+
+ /*
+ * Note that the max. and min. frequency should be based
+ * on the timing modes that the card and host handshake
+ * during initialization.
+ */
+ if ((busy_time_ms * 100 > total_time_ms * up_threshold)) {
+ freq = mmc_get_max_frequency(host);
+ } else if ((busy_time_ms * 100 < total_time_ms * down_threshold)) {
+ if (!from_wq)
+ queue_scale_down_work = true;
+ freq = mmc_get_min_frequency(host);
+ }
+
+ if (freq != host->clk_scaling.curr_freq) {
+ if (!queue_scale_down_work) {
+ if (!from_wq)
+ cancel_delayed_work_sync(
+ &host->clk_scaling.work);
+ err = host->bus_ops->change_bus_speed(host, &freq);
+ if (!err)
+ host->clk_scaling.curr_freq = freq;
+ else
+ pr_err("%s: %s: failed (%d) at freq=%lu\n",
+ mmc_hostname(host), __func__, err,
+ freq);
+ } else {
+ /*
+ * We hold claim host while queueing the scale down
+ * work, so delay atleast one timer tick to release
+ * host and re-claim while scaling down the clocks.
+ */
+ queue_delayed_work(system_nrt_wq,
+ &host->clk_scaling.work, 1);
+ host->clk_scaling.in_progress = false;
+ goto out;
+ }
+ }
+
+ mmc_reset_clk_scale_stats(host);
+ host->clk_scaling.in_progress = false;
+out:
+ return;
+}
+
+/**
+ * mmc_disable_clk_scaling() - Disable clock scaling
+ * @host: pointer to mmc host structure
+ *
+ * Disables clock scaling temporarily by setting enable
+ * property to false. To disable completely, one also
+ * need to set 'initialized' variable to false.
+ */
+void mmc_disable_clk_scaling(struct mmc_host *host)
+{
+ cancel_delayed_work_sync(&host->clk_scaling.work);
+ host->clk_scaling.enable = false;
+}
+EXPORT_SYMBOL_GPL(mmc_disable_clk_scaling);
+
+/**
+ * mmc_can_scale_clk() - Check if clock scaling is initialized
+ * @host: pointer to mmc host structure
+ */
+bool mmc_can_scale_clk(struct mmc_host *host)
+{
+ return host->clk_scaling.initialized;
+}
+EXPORT_SYMBOL_GPL(mmc_can_scale_clk);
+
+/**
+ * mmc_init_clk_scaling() - Initialize clock scaling
+ * @host: pointer to mmc host structure
+ *
+ * Initialize clock scaling for supported hosts.
+ * It is assumed that the caller ensure clock is
+ * running at maximum possible frequency before
+ * calling this function.
+ */
+void mmc_init_clk_scaling(struct mmc_host *host)
+{
+ if (!host->card || !(host->caps2 & MMC_CAP2_CLK_SCALE))
+ return;
+
+ INIT_DELAYED_WORK(&host->clk_scaling.work, mmc_clk_scale_work);
+ host->clk_scaling.curr_freq = mmc_get_max_frequency(host);
+ mmc_reset_clk_scale_stats(host);
+ host->clk_scaling.enable = true;
+ host->clk_scaling.initialized = true;
+ pr_debug("%s: clk scaling enabled\n", mmc_hostname(host));
+}
+EXPORT_SYMBOL_GPL(mmc_init_clk_scaling);
+
+/**
+ * mmc_exit_clk_scaling() - Disable clock scaling
+ * @host: pointer to mmc host structure
+ *
+ * Disable clock scaling permanently.
+ */
+void mmc_exit_clk_scaling(struct mmc_host *host)
+{
+ cancel_delayed_work_sync(&host->clk_scaling.work);
+ memset(&host->clk_scaling, 0, sizeof(host->clk_scaling));
+}
+EXPORT_SYMBOL_GPL(mmc_exit_clk_scaling);
+
static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
{
host->f_init = freq;
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index de87e82..c85f5aa 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -81,5 +81,11 @@
void mmc_add_card_debugfs(struct mmc_card *card);
void mmc_remove_card_debugfs(struct mmc_card *card);
+extern void mmc_disable_clk_scaling(struct mmc_host *host);
+extern bool mmc_can_scale_clk(struct mmc_host *host);
+extern void mmc_init_clk_scaling(struct mmc_host *host);
+extern void mmc_exit_clk_scaling(struct mmc_host *host);
+extern void mmc_reset_clk_scale_stats(struct mmc_host *host);
+extern unsigned long mmc_get_max_frequency(struct mmc_host *host);
#endif
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 850872d..d30f10f 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -163,6 +163,9 @@
if (host->clk_gated) {
spin_unlock_irqrestore(&host->clk_lock, flags);
mmc_ungate_clock(host);
+
+ /* Reset clock scaling stats as host is out of idle */
+ mmc_reset_clk_scale_stats(host);
spin_lock_irqsave(&host->clk_lock, flags);
pr_debug("%s: ungated MCI clock\n", mmc_hostname(host));
}
@@ -446,6 +449,10 @@
#endif
mmc_host_clk_sysfs_init(host);
+ host->clk_scaling.up_threshold = 35;
+ host->clk_scaling.down_threshold = 5;
+ host->clk_scaling.polling_delay_ms = 100;
+
err = sysfs_create_group(&host->parent->kobj, &dev_attr_grp);
if (err)
pr_err("%s: failed to create sysfs group with err %d\n",
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index a98ed3d..c1a6b28 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -501,6 +501,17 @@
card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM];
card->ext_csd.rst_n_function = ext_csd[EXT_CSD_RST_N_FUNCTION];
+
+ /*
+ * RPMB regions are defined in multiples of 128K.
+ */
+ card->ext_csd.raw_rpmb_size_mult = ext_csd[EXT_CSD_RPMB_MULT];
+ if (ext_csd[EXT_CSD_RPMB_MULT]) {
+ mmc_part_add(card, ext_csd[EXT_CSD_RPMB_MULT] << 17,
+ EXT_CSD_PART_CONFIG_ACC_RPMB,
+ "rpmb", 0, false,
+ MMC_BLK_DATA_AREA_RPMB);
+ }
}
card->ext_csd.raw_erased_mem_count = ext_csd[EXT_CSD_ERASED_MEM_CONT];
@@ -632,6 +643,8 @@
MMC_DEV_ATTR(enhanced_area_offset, "%llu\n",
card->ext_csd.enhanced_area_offset);
MMC_DEV_ATTR(enhanced_area_size, "%u\n", card->ext_csd.enhanced_area_size);
+MMC_DEV_ATTR(raw_rpmb_size_mult, "%#x\n", card->ext_csd.raw_rpmb_size_mult);
+MMC_DEV_ATTR(rel_sectors, "%#x\n", card->ext_csd.rel_sectors);
static struct attribute *mmc_std_attrs[] = {
&dev_attr_cid.attr,
@@ -647,6 +660,8 @@
&dev_attr_serial.attr,
&dev_attr_enhanced_area_offset.attr,
&dev_attr_enhanced_area_size.attr,
+ &dev_attr_raw_rpmb_size_mult.attr,
+ &dev_attr_rel_sectors.attr,
NULL,
};
@@ -1460,6 +1475,7 @@
mmc_claim_host(host);
host->card = NULL;
+ mmc_exit_clk_scaling(host);
mmc_release_host(host);
}
@@ -1510,6 +1526,12 @@
BUG_ON(!host);
BUG_ON(!host->card);
+ /*
+ * Disable clock scaling before suspend and enable it after resume so
+ * as to avoid clock scaling decisions kicking in during this window.
+ */
+ mmc_disable_clk_scaling(host);
+
mmc_claim_host(host);
if (mmc_can_poweroff_notify(host->card))
err = mmc_poweroff_notify(host->card, EXT_CSD_POWER_OFF_SHORT);
@@ -1540,6 +1562,13 @@
err = mmc_init_card(host, host->ocr, host->card);
mmc_release_host(host);
+ /*
+ * We have done full initialization of the card,
+ * reset the clk scale stats and current frequency.
+ */
+ if (mmc_can_scale_clk(host))
+ mmc_init_clk_scaling(host);
+
return err;
}
@@ -1547,11 +1576,17 @@
{
int ret;
+ /* Disable clk scaling to avoid switching frequencies intermittently */
+ mmc_disable_clk_scaling(host);
+
host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
mmc_claim_host(host);
ret = mmc_init_card(host, host->ocr, host->card);
mmc_release_host(host);
+ if (mmc_can_scale_clk(host))
+ mmc_init_clk_scaling(host);
+
return ret;
}
@@ -1686,6 +1721,10 @@
if (err)
goto remove_card;
+ /* Initialize clock scaling only for high frequency modes */
+ if (mmc_card_hs200(host->card) || mmc_card_ddr_mode(host->card))
+ mmc_init_clk_scaling(host);
+
return 0;
remove_card:
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 8661929..318d590 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1121,6 +1121,7 @@
mmc_claim_host(host);
host->card = NULL;
+ mmc_exit_clk_scaling(host);
mmc_release_host(host);
}
@@ -1187,6 +1188,12 @@
BUG_ON(!host);
BUG_ON(!host->card);
+ /*
+ * Disable clock scaling before suspend and enable it after resume so
+ * as to avoid clock scaling decisions kicking in during this window.
+ */
+ mmc_disable_clk_scaling(host);
+
mmc_claim_host(host);
if (!mmc_host_is_spi(host))
mmc_deselect_cards(host);
@@ -1235,6 +1242,13 @@
#endif
mmc_release_host(host);
+ /*
+ * We have done full initialization of the card,
+ * reset the clk scale stats and current frequency.
+ */
+ if (mmc_can_scale_clk(host))
+ mmc_init_clk_scaling(host);
+
return err;
}
@@ -1242,11 +1256,17 @@
{
int ret;
+ /* Disable clk scaling to avoid switching frequencies intermittently */
+ mmc_disable_clk_scaling(host);
+
host->card->state &= ~MMC_STATE_HIGHSPEED;
mmc_claim_host(host);
ret = mmc_sd_init_card(host, host->ocr, host->card);
mmc_release_host(host);
+ if (mmc_can_scale_clk(host))
+ mmc_init_clk_scaling(host);
+
return ret;
}
@@ -1385,6 +1405,10 @@
if (err)
goto remove_card;
+ /* Initialize clock scaling only for high frequency modes */
+ if (mmc_card_uhs(host->card))
+ mmc_init_clk_scaling(host);
+
return 0;
remove_card:
diff --git a/drivers/net/ethernet/msm/msm_rmnet.c b/drivers/net/ethernet/msm/msm_rmnet.c
index 4af2d8c..cc9ed74 100644
--- a/drivers/net/ethernet/msm/msm_rmnet.c
+++ b/drivers/net/ethernet/msm/msm_rmnet.c
@@ -94,6 +94,7 @@
struct sk_buff *skb;
spinlock_t lock;
struct tasklet_struct tsklt;
+ struct tasklet_struct rx_tasklet;
u32 operation_mode; /* IOCTL specified mode (protocol, QoS header) */
struct platform_driver pdrv;
struct completion complete;
@@ -257,7 +258,6 @@
}
static void smd_net_data_handler(unsigned long arg);
-static DECLARE_TASKLET(smd_net_data_tasklet, smd_net_data_handler, 0);
/* Called in soft-irq context */
static void smd_net_data_handler(unsigned long arg)
@@ -280,8 +280,8 @@
pr_err("[%s] rmnet_recv() cannot allocate skb\n",
dev->name);
/* out of memory, reschedule a later attempt */
- smd_net_data_tasklet.data = (unsigned long)dev;
- tasklet_schedule(&smd_net_data_tasklet);
+ p->rx_tasklet.data = (unsigned long)dev;
+ tasklet_schedule(&p->rx_tasklet);
break;
} else {
skb->dev = dev;
@@ -449,8 +449,8 @@
if (smd_read_avail(p->ch) &&
(smd_read_avail(p->ch) >= smd_cur_packet_size(p->ch))) {
- smd_net_data_tasklet.data = (unsigned long) _dev;
- tasklet_schedule(&smd_net_data_tasklet);
+ p->rx_tasklet.data = (unsigned long) _dev;
+ tasklet_schedule(&p->rx_tasklet);
}
break;
@@ -788,6 +788,8 @@
spin_lock_init(&p->lock);
tasklet_init(&p->tsklt, _rmnet_resume_flow,
(unsigned long)dev);
+ tasklet_init(&p->rx_tasklet, smd_net_data_handler,
+ (unsigned long)dev);
wake_lock_init(&p->wake_lock, WAKE_LOCK_SUSPEND, ch_name[n]);
#ifdef CONFIG_MSM_RMNET_DEBUG
p->timeout_us = timeout_us;
diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig
index 75cc086..872a9b5 100644
--- a/drivers/platform/msm/Kconfig
+++ b/drivers/platform/msm/Kconfig
@@ -12,11 +12,7 @@
config SPS
bool "SPS support"
- depends on (HAS_IOMEM && (ARCH_MSM8960 || ARCH_MSM8X60 \
- || ARCH_APQ8064 || ARCH_MSM9615 \
- || ARCH_MSM9625 || ARCH_MSM8974))
select GENERIC_ALLOCATOR
- default n
help
The SPS (Smart Peripheral Switch) is a DMA engine.
It can move data in the following modes:
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index b193810..05b47cc 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -55,6 +55,9 @@
#define TEMP_IAVG_STORAGE 0x105
#define TEMP_IAVG_STORAGE_USE_MASK 0x0F
+#define PON_CNTRL_6 0x018
+#define WD_BIT BIT(7)
+
enum pmic_bms_interrupts {
PM8921_BMS_SBI_WRITE_OK,
PM8921_BMS_CC_THR,
@@ -127,7 +130,7 @@
int default_rbatt_mohm;
int amux_2_trim_delta;
uint16_t prev_last_good_ocv_raw;
- unsigned int rconn_mohm;
+ int rconn_mohm;
struct mutex last_ocv_uv_mutex;
int last_ocv_uv;
int pon_ocv_uv;
@@ -630,17 +633,17 @@
return 0;
}
-#define MBG_TRANSIENT_ERROR_RAW 51
-static void adjust_pon_ocv_raw(struct pm8921_bms_chip *chip,
- struct pm8921_soc_params *raw)
+#define MBG_TRANSIENT_ERROR_UV 15000
+static void adjust_pon_ocv(struct pm8921_bms_chip *chip, int *uv)
{
- /* in 8921 parts the PON ocv is taken when the MBG is not settled.
+ /*
+ * In 8921 parts the PON ocv is taken when the MBG is not settled.
* decrease the pon ocv by 15mV raw value to account for it
* Since a 1/3rd of vbatt is supplied to the adc the raw value
* needs to be adjusted by 5mV worth bits
*/
- if (raw->last_good_ocv_raw >= MBG_TRANSIENT_ERROR_RAW)
- raw->last_good_ocv_raw -= MBG_TRANSIENT_ERROR_RAW;
+ if (*uv >= MBG_TRANSIENT_ERROR_UV)
+ *uv -= MBG_TRANSIENT_ERROR_UV;
}
#define SEL_ALT_OREG_BIT BIT(2)
@@ -663,10 +666,71 @@
return compensated_ocv;
}
+#define RESET_CC_BIT BIT(3)
+static int reset_cc(struct pm8921_bms_chip *chip)
+{
+ int rc;
+
+ rc = pm_bms_masked_write(chip, BMS_TEST1, RESET_CC_BIT, RESET_CC_BIT);
+ if (rc < 0) {
+ pr_err("err setting cc reset rc = %d\n", rc);
+ return rc;
+ }
+
+ /* sleep 100uS for the coulomb counter to reset */
+ udelay(100);
+
+ rc = pm_bms_masked_write(chip, BMS_TEST1, RESET_CC_BIT, 0);
+ if (rc < 0)
+ pr_err("err clearing cc reset rc = %d\n", rc);
+ return rc;
+}
+
+static int estimate_ocv(struct pm8921_bms_chip *chip)
+{
+ int ibat_ua, vbat_uv, ocv_est_uv;
+ int rc;
+
+ int rbatt_mohm = chip->default_rbatt_mohm + chip->rconn_mohm;
+
+ rc = pm8921_bms_get_simultaneous_battery_voltage_and_current(
+ &ibat_ua,
+ &vbat_uv);
+ if (rc) {
+ pr_err("simultaneous failed rc = %d\n", rc);
+ return rc;
+ }
+
+ ocv_est_uv = vbat_uv + (ibat_ua * rbatt_mohm) / 1000;
+ pr_debug("estimated pon ocv = %d\n", ocv_est_uv);
+ return ocv_est_uv;
+}
+
+static bool is_warm_restart(struct pm8921_bms_chip *chip)
+{
+ u8 reg;
+ int rc;
+
+ rc = pm8xxx_readb(chip->dev->parent, PON_CNTRL_6, ®);
+ if (rc) {
+ pr_err("err reading pon 6 rc = %d\n", rc);
+ return false;
+ }
+ return reg & WD_BIT;
+}
+/*
+ * This reflects what should the CC readings should be for
+ * a 5mAh discharge. This value is dependent on
+ * CC_RESOLUTION_N, CC_RESOLUTION_D, CC_READING_TICKS
+ * and rsense
+ */
+#define CC_RAW_5MAH 0x00110000
+#define MIN_OCV_UV 2000000
static int read_soc_params_raw(struct pm8921_bms_chip *chip,
struct pm8921_soc_params *raw)
{
int usb_chg;
+ int est_ocv_uv;
mutex_lock(&chip->bms_output_lock);
pm_bms_lock_output_data(chip);
@@ -682,12 +746,40 @@
if (chip->prev_last_good_ocv_raw == 0) {
chip->prev_last_good_ocv_raw = raw->last_good_ocv_raw;
- adjust_pon_ocv_raw(chip, raw);
+
convert_vbatt_raw_to_uv(chip, usb_chg,
raw->last_good_ocv_raw, &raw->last_good_ocv_uv);
+ adjust_pon_ocv(chip, &raw->last_good_ocv_uv);
raw->last_good_ocv_uv = ocv_ir_compensation(chip,
raw->last_good_ocv_uv);
chip->last_ocv_uv = raw->last_good_ocv_uv;
+
+ if (is_warm_restart(chip)
+ || raw->cc > CC_RAW_5MAH
+ || (raw->last_good_ocv_uv < MIN_OCV_UV
+ && raw->cc > 0)) {
+ /*
+ * The CC value is higher than 5mAh.
+ * The phone started without going through a pon
+ * sequence
+ * OR
+ * The ocv was very small and there was no
+ * charging in the bootloader
+ * - reset the CC and take an ocv again
+ */
+ pr_debug("cc_raw = 0x%x may be > 5mAh(0x%x)\n",
+ raw->cc, CC_RAW_5MAH);
+ pr_debug("ocv_uv = %d ocv_raw = 0x%x may be < 2V\n",
+ chip->last_ocv_uv,
+ raw->last_good_ocv_raw);
+ est_ocv_uv = estimate_ocv(chip);
+ if (est_ocv_uv > 0) {
+ raw->last_good_ocv_uv = est_ocv_uv;
+ chip->last_ocv_uv = est_ocv_uv;
+ reset_cc(chip);
+ raw->cc = 0;
+ }
+ }
pr_debug("PON_OCV_UV = %d\n", chip->last_ocv_uv);
} else if (chip->prev_last_good_ocv_raw != raw->last_good_ocv_raw) {
chip->prev_last_good_ocv_raw = raw->last_good_ocv_raw;
@@ -1304,14 +1396,16 @@
int fcc_uah, int cc_uah, int uuc_uah)
{
int chg_soc;
+ int vbat_batt_terminal_uv = vbat_uv
+ + (ibat_ua * chip->rconn_mohm) / 1000;
if (chip->soc_at_cv == -EINVAL) {
/* In constant current charging return the calc soc */
- if (vbat_uv <= chip->max_voltage_uv)
+ if (vbat_batt_terminal_uv <= chip->max_voltage_uv)
pr_debug("CC CHG SOC %d\n", soc);
/* Note the CC to CV point */
- if (vbat_uv >= chip->max_voltage_uv) {
+ if (vbat_batt_terminal_uv >= chip->max_voltage_uv) {
chip->soc_at_cv = soc;
chip->prev_chg_soc = soc;
chip->ibat_at_cv_ua = ibat_ua;
@@ -1327,17 +1421,18 @@
*/
/*
- * if voltage lessened (possibly because of a system load)
- * keep reporting the prev chg soc
+ * if voltage lessened by more than 10mV (possibly because of
+ * a sudden increase in system load) keep reporting the prev chg soc
*/
- if (vbat_uv <= chip->max_voltage_uv) {
- pr_debug("vbat %d < max = %d CC CHG SOC %d\n",
- vbat_uv, chip->max_voltage_uv, chip->prev_chg_soc);
+ if (vbat_batt_terminal_uv <= chip->max_voltage_uv - 10000) {
+ pr_debug("vbat_terminals %d < max = %d CC CHG SOC %d\n",
+ vbat_batt_terminal_uv,
+ chip->max_voltage_uv, chip->prev_chg_soc);
return chip->prev_chg_soc;
}
chg_soc = linear_interpolate(chip->soc_at_cv, chip->ibat_at_cv_ua,
- 100, -100000,
+ 100, -1 * chip->chg_term_ua,
ibat_ua);
/* always report a higher soc */
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index 94ef4f9..c6dd57b 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -87,6 +87,7 @@
#define EOC_CHECK_PERIOD_MS 10000
/* check for USB unplug every 200 msecs */
#define UNPLUG_CHECK_WAIT_PERIOD_MS 200
+#define UNPLUG_CHECK_RAMP_MS 25
#define USB_TRIM_ENTRIES 16
enum chg_fsm_state {
@@ -1311,20 +1312,6 @@
return 0;
}
- if (charging_disabled)
- return 0;
-
- /* check external charger first before the dc path */
- if (is_ext_charging(the_chip)) {
- val->intval = 1;
- return 0;
- }
-
- if (pm_is_chg_charge_dis(the_chip)) {
- val->intval = 0;
- return 0;
- }
-
if (the_chip->dc_present) {
val->intval = 1;
return 0;
@@ -1460,7 +1447,7 @@
POWER_SUPPLY_PROP_CURRENT_MAX,
POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_TEMP,
- POWER_SUPPLY_PROP_ENERGY_FULL,
+ POWER_SUPPLY_PROP_CHARGE_FULL,
POWER_SUPPLY_PROP_CHARGE_NOW,
};
@@ -1746,8 +1733,8 @@
case POWER_SUPPLY_PROP_TEMP:
val->intval = get_prop_batt_temp(chip);
break;
- case POWER_SUPPLY_PROP_ENERGY_FULL:
- val->intval = get_prop_batt_fcc(chip) * 1000;
+ case POWER_SUPPLY_PROP_CHARGE_FULL:
+ val->intval = get_prop_batt_fcc(chip);
break;
case POWER_SUPPLY_PROP_CHARGE_NOW:
val->intval = get_prop_batt_charge_now(chip);
@@ -1799,6 +1786,12 @@
return;
}
+ if (usb_max_current && mA > usb_max_current) {
+ pr_debug("restricting usb current to %d instead of %d\n",
+ usb_max_current, mA);
+ mA = usb_max_current;
+ }
+
if (mA <= 2) {
usb_chg_current = 0;
rc = pm_chg_iusbmax_set(the_chip, 0);
@@ -2214,8 +2207,7 @@
}
if (usb_present) {
schedule_delayed_work(&chip->unplug_check_work,
- round_jiffies_relative(msecs_to_jiffies
- (UNPLUG_CHECK_WAIT_PERIOD_MS)));
+ msecs_to_jiffies(UNPLUG_CHECK_RAMP_MS));
pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
} else {
/* USB unplugged reset target current */
@@ -2294,8 +2286,7 @@
}
schedule_delayed_work(&chip->unplug_check_work,
- round_jiffies_relative(msecs_to_jiffies
- (UNPLUG_CHECK_WAIT_PERIOD_MS)));
+ msecs_to_jiffies(UNPLUG_CHECK_RAMP_MS));
power_supply_set_online(chip->ext_psy, dc_present);
power_supply_set_charge_type(chip->ext_psy,
@@ -2543,15 +2534,25 @@
struct pm8921_chg_chip *chip = container_of(dwork,
struct pm8921_chg_chip, vin_collapse_check_work);
- /* AICL only for wall-chargers */
- if (is_usb_chg_plugged_in(chip) &&
- usb_target_ma > USB_WALL_THRESHOLD_MA) {
+ /*
+ * AICL only for wall-chargers. If the charger appears to be plugged
+ * back in now, the corresponding unplug must have been because of we
+ * were trying to draw more current than the charger can support. In
+ * such a case reset usb current to 500mA and decrease the target.
+ * The AICL algorithm will step up the current from 500mA to target
+ */
+ if (is_usb_chg_plugged_in(chip)
+ && usb_target_ma > USB_WALL_THRESHOLD_MA) {
/* decrease usb_target_ma */
decrease_usb_ma_value(&usb_target_ma);
/* reset here, increase in unplug_check_worker */
__pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
pr_debug("usb_now=%d, usb_target = %d\n",
USB_WALL_THRESHOLD_MA, usb_target_ma);
+ if (!delayed_work_pending(&chip->unplug_check_work))
+ schedule_delayed_work(&chip->unplug_check_work,
+ msecs_to_jiffies
+ (UNPLUG_CHECK_WAIT_PERIOD_MS));
} else {
handle_usb_insertion_removal(chip);
}
@@ -2750,6 +2751,7 @@
u8 reg_loop, active_path;
int rc, ibat, active_chg_plugged_in, usb_ma;
int chg_gone = 0;
+ bool ramp = false;
reg_loop = 0;
@@ -2847,15 +2849,20 @@
__pm8921_charger_vbus_draw(usb_ma);
pr_debug("usb_now=%d, usb_target = %d\n",
usb_ma, usb_target_ma);
+ ramp = true;
} else {
usb_target_ma = usb_ma;
}
}
check_again_later:
+ pr_debug("ramp: %d\n", ramp);
/* schedule to check again later */
- schedule_delayed_work(&chip->unplug_check_work,
- round_jiffies_relative(msecs_to_jiffies
- (UNPLUG_CHECK_WAIT_PERIOD_MS)));
+ if (ramp)
+ schedule_delayed_work(&chip->unplug_check_work,
+ msecs_to_jiffies(UNPLUG_CHECK_RAMP_MS));
+ else
+ schedule_delayed_work(&chip->unplug_check_work,
+ msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
}
static irqreturn_t loop_change_irq_handler(int irq, void *data)
@@ -3069,8 +3076,7 @@
} else {
if (dc_present)
schedule_delayed_work(&chip->unplug_check_work,
- round_jiffies_relative(msecs_to_jiffies
- (UNPLUG_CHECK_WAIT_PERIOD_MS)));
+ msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
power_supply_changed(&chip->dc_psy);
}
@@ -3618,8 +3624,7 @@
notify_usb_of_the_plugin_event(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)));
+ msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
}
@@ -4469,6 +4474,8 @@
chip->temp_check_period = pdata->temp_check_period;
chip->max_bat_chg_current = pdata->max_bat_chg_current;
+ /* Assign to corresponding module parameter */
+ usb_max_current = pdata->usb_max_current;
chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
chip->warm_bat_chg_current = pdata->warm_bat_chg_current;
chip->cool_bat_voltage = pdata->cool_bat_voltage;
@@ -4563,7 +4570,6 @@
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[BAT_TEMP_OK_IRQ]);
enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
enable_irq_wake(chip->pmic_chg_irq[FASTCHG_IRQ]);
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 3b813d8..12b186d 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -176,7 +176,8 @@
int soc_at_cv;
int prev_chg_soc;
int calculated_soc;
- int last_vbat_read_uv;
+ int prev_voltage_based_soc;
+ bool use_voltage_soc;
};
static struct of_device_id qpnp_bms_match_table[] = {
@@ -196,37 +197,6 @@
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
};
-static bool use_voltage_soc;
-
-/* module params */
-static int bms_param_set_bool(const char *val, const struct kernel_param *kp)
-{
- int rc;
- struct power_supply *bms_psy;
-
- rc = param_set_bool(val, kp);
- if (rc) {
- pr_err("failed to set %s, rc = %d\n", kp->name, rc);
- return rc;
- }
-
- bms_psy = power_supply_get_by_name("bms");
-
- if (bms_psy)
- power_supply_changed(bms_psy);
- else
- pr_debug("%s changed but bms has not been initialized yet\n",
- kp->name);
-
- return 0;
-}
-
-static struct kernel_param_ops bms_param_ops = {
- .set = bms_param_set_bool,
- .get = param_get_bool,
-};
-
-module_param_cb(use_voltage_soc, &bms_param_ops, &use_voltage_soc, 0644);
static int qpnp_read_wrapper(struct qpnp_bms_chip *chip, u8 *val,
u16 base, int count)
@@ -370,6 +340,10 @@
s64 result_uv;
pr_debug("adjusting_uv = %lld\n", uv);
+ if (gain == 0) {
+ pr_debug("gain is %d, not adjusting\n", gain);
+ return uv;
+ }
pr_debug("adjusting by factor: %lld/%hu = %lld%%\n",
QPNP_ADC_GAIN_NV, gain,
div_s64(QPNP_ADC_GAIN_NV * 100LL, (s64)gain));
@@ -1280,6 +1254,34 @@
return soc;
}
+static int clamp_soc_based_on_voltage(struct qpnp_bms_chip *chip, int soc)
+{
+ int rc, vbat_uv;
+ struct qpnp_vadc_result result;
+
+ rc = qpnp_vadc_read(VBAT_SNS, &result);
+ if (rc) {
+ pr_err("error reading vbat_sns adc channel = %d, rc = %d\n",
+ VBAT_SNS, rc);
+ return rc;
+ }
+
+ vbat_uv = (int)result.physical;
+ if (soc == 0 && vbat_uv > chip->v_cutoff_uv) {
+ pr_debug("clamping soc to 1, vbat (%d) > cutoff (%d)\n",
+ vbat_uv, chip->v_cutoff_uv);
+ return 1;
+ } else if (soc > 0 && vbat_uv < chip->v_cutoff_uv) {
+ pr_debug("forcing soc to 0, vbat (%d) < cutoff (%d)\n",
+ vbat_uv, chip->v_cutoff_uv);
+ return 0;
+ } else {
+ pr_debug("not clamping, using soc = %d, vbat = %d and cutoff = %d\n",
+ soc, vbat_uv, chip->v_cutoff_uv);
+ return soc;
+ }
+}
+
static int calculate_state_of_charge(struct qpnp_bms_chip *chip,
struct raw_soc_params *raw,
int batt_temp)
@@ -1374,6 +1376,11 @@
pr_debug("SOC before adjustment = %d\n", soc);
new_calculated_soc = adjust_soc(chip, ¶ms, soc, batt_temp);
+ /* clamp soc due to BMS HW inaccuracies in pm8941v2.0 */
+ if (chip->revision1 == 0 && chip->revision2 == 0)
+ new_calculated_soc = clamp_soc_based_on_voltage(chip,
+ new_calculated_soc);
+
if (new_calculated_soc != chip->calculated_soc
&& chip->bms_psy.name != NULL) {
power_supply_changed(&chip->bms_psy);
@@ -1381,12 +1388,12 @@
}
chip->calculated_soc = new_calculated_soc;
- pr_debug("Set calculated SOC = %d\n", chip->calculated_soc);
+ pr_debug("CC based calculated SOC = %d\n", chip->calculated_soc);
chip->first_time_calc_soc = 0;
return chip->calculated_soc;
}
-static void read_vbat(struct qpnp_bms_chip *chip)
+static int read_vbat(struct qpnp_bms_chip *chip)
{
int rc;
struct qpnp_vadc_result result;
@@ -1395,9 +1402,35 @@
if (rc) {
pr_err("error reading vadc VBAT_SNS = %d, rc = %d\n",
VBAT_SNS, rc);
- return;
+ return rc;
}
- chip->last_vbat_read_uv = (int)result.physical;
+ pr_debug("read %duv from vadc\n", (int)result.physical);
+ return (int)result.physical;
+}
+
+static int calculate_soc_from_voltage(struct qpnp_bms_chip *chip)
+{
+ int voltage_range_uv, voltage_remaining_uv, voltage_based_soc;
+ int vbat_uv;
+
+ vbat_uv = read_vbat(chip);
+
+ voltage_range_uv = chip->max_voltage_uv - chip->v_cutoff_uv;
+ voltage_remaining_uv = vbat_uv - chip->v_cutoff_uv;
+ voltage_based_soc = voltage_remaining_uv * 100 / voltage_range_uv;
+
+ voltage_based_soc = clamp(voltage_based_soc, 0, 100);
+
+ if (chip->prev_voltage_based_soc != voltage_based_soc
+ && chip->bms_psy.name != NULL) {
+ power_supply_changed(&chip->bms_psy);
+ pr_debug("power supply changed\n");
+ }
+ chip->prev_voltage_based_soc = voltage_based_soc;
+
+ pr_debug("vbat used = %duv\n", vbat_uv);
+ pr_debug("Calculated voltage based soc = %d\n", voltage_based_soc);
+ return voltage_based_soc;
}
static void calculate_soc_work(struct work_struct *work)
@@ -1409,22 +1442,25 @@
struct qpnp_vadc_result result;
struct raw_soc_params raw;
- read_vbat(chip);
-
- rc = qpnp_vadc_read(LR_MUX1_BATT_THERM, &result);
- if (rc) {
- pr_err("error reading vadc LR_MUX1_BATT_THERM = %d, rc = %d\n",
- LR_MUX1_BATT_THERM, rc);
- return;
- }
- pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
+ if (chip->use_voltage_soc) {
+ soc = calculate_soc_from_voltage(chip);
+ } else {
+ rc = qpnp_vadc_read(LR_MUX1_BATT_THERM, &result);
+ if (rc) {
+ pr_err("error reading vadc LR_MUX1_BATT_THERM = %d, rc = %d\n",
+ LR_MUX1_BATT_THERM, rc);
+ return;
+ }
+ pr_debug("batt_temp phy = %lld meas = 0x%llx\n",
+ result.physical,
result.measurement);
- batt_temp = (int)result.physical;
+ batt_temp = (int)result.physical;
- mutex_lock(&chip->last_ocv_uv_mutex);
- read_soc_params_raw(chip, &raw);
- soc = calculate_state_of_charge(chip, &raw, batt_temp);
- mutex_unlock(&chip->last_ocv_uv_mutex);
+ mutex_lock(&chip->last_ocv_uv_mutex);
+ read_soc_params_raw(chip, &raw);
+ soc = calculate_state_of_charge(chip, &raw, batt_temp);
+ mutex_unlock(&chip->last_ocv_uv_mutex);
+ }
if (soc < chip->low_soc_calc_threshold)
schedule_delayed_work(&chip->calculate_soc_delayed_work,
@@ -1514,7 +1550,14 @@
static int bms_fake_battery = -EINVAL;
module_param(bms_fake_battery, int, 0644);
-static int report_state_of_charge(struct qpnp_bms_chip *chip)
+static int report_voltage_based_soc(struct qpnp_bms_chip *chip)
+{
+ pr_debug("Reported voltage based soc = %d\n",
+ chip->prev_voltage_based_soc);
+ return chip->prev_voltage_based_soc;
+}
+
+static int report_cc_based_soc(struct qpnp_bms_chip *chip)
{
int soc;
int delta_time_us;
@@ -1523,11 +1566,6 @@
int batt_temp;
int rc;
- if (bms_fake_battery != -EINVAL) {
- pr_debug("Returning Fake SOC = %d%%\n", bms_fake_battery);
- return bms_fake_battery;
- }
-
soc = chip->calculated_soc;
rc = qpnp_vadc_read(LR_MUX1_BATT_THERM, &result);
@@ -1598,27 +1636,21 @@
return chip->last_soc;
}
-static int calculate_soc_from_voltage(struct qpnp_bms_chip *chip)
+static int report_state_of_charge(struct qpnp_bms_chip *chip)
{
- int voltage_range_uv, voltage_remaining_uv, voltage_based_soc;
-
- if (chip->last_vbat_read_uv < 0)
- read_vbat(chip);
-
- voltage_range_uv = chip->max_voltage_uv - chip->v_cutoff_uv;
- voltage_remaining_uv = chip->last_vbat_read_uv - chip->v_cutoff_uv;
- voltage_based_soc = voltage_remaining_uv * 100 / voltage_range_uv;
-
- return clamp(voltage_based_soc, 0, 100);
+ if (bms_fake_battery != -EINVAL) {
+ pr_debug("Returning Fake SOC = %d%%\n", bms_fake_battery);
+ return bms_fake_battery;
+ } else if (chip->use_voltage_soc)
+ return report_voltage_based_soc(chip);
+ else
+ return report_cc_based_soc(chip);
}
/* Returns capacity as a SoC percentage between 0 and 100 */
static int get_prop_bms_capacity(struct qpnp_bms_chip *chip)
{
- if (use_voltage_soc)
- return calculate_soc_from_voltage(chip);
- else
- return report_state_of_charge(chip);
+ return report_state_of_charge(chip);
}
/* Returns instantaneous current in uA */
@@ -1873,7 +1905,7 @@
chip->ignore_shutdown_soc = of_property_read_bool(
chip->spmi->dev.of_node,
"qcom,bms-ignore-shutdown-soc");
- use_voltage_soc = of_property_read_bool(chip->spmi->dev.of_node,
+ chip->use_voltage_soc = of_property_read_bool(chip->spmi->dev.of_node,
"qcom,bms-use-voltage-soc");
if (chip->adjust_soc_low_threshold >= 45)
@@ -1889,7 +1921,7 @@
chip->adjust_soc_high_threshold, chip->chg_term_ua,
chip->batt_type);
pr_debug("ignore_shutdown_soc:%d, use_voltage_soc:%d\n",
- chip->ignore_shutdown_soc, use_voltage_soc);
+ chip->ignore_shutdown_soc, chip->use_voltage_soc);
return 0;
}
@@ -1902,7 +1934,6 @@
chip->soc_at_cv = -EINVAL;
chip->calculated_soc = -EINVAL;
chip->last_soc = -EINVAL;
- chip->last_vbat_read_uv = -EINVAL;
chip->last_soc_est = -EINVAL;
chip->first_time_calc_soc = 1;
chip->first_time_calc_uuc = 1;
diff --git a/drivers/power/smb137c-charger.c b/drivers/power/smb137c-charger.c
index 9cdf5b5..fc3277f 100644
--- a/drivers/power/smb137c-charger.c
+++ b/drivers/power/smb137c-charger.c
@@ -31,6 +31,7 @@
bool charging_enabled;
bool otg_mode_enabled;
bool charging_allowed;
+ bool usb_suspend_enabled;
};
struct input_current_config {
@@ -130,6 +131,9 @@
#define VAR_FUNC_REG 0x0C
#define VAR_FUNC_USB_MODE_MASK 0x80
+#define VAR_FUNC_USB_SUSPEND_CTRL_MASK 0x20
+#define VAR_FUNC_USB_SUSPEND_CTRL_REG 0x00
+#define VAR_FUNC_USB_SUSPEND_CTRL_PIN 0x20
#define VAR_FUNC_BMD_MASK 0x0C
#define VAR_FUNC_BMD_DISABLED 0x00
#define VAR_FUNC_BMD_ALGO_PERIODIC 0x04
@@ -146,6 +150,9 @@
#define CMD_A_OTG_MASK 0x10
#define CMD_A_OTG_ENABLED 0x10
#define CMD_A_OTG_DISABLED 0x00
+#define CMD_A_USB_SUSPEND_MASK 0x04
+#define CMD_A_USB_SUSPEND_DISABLED 0x00
+#define CMD_A_USB_SUSPEND_ENABLED 0x04
#define CMD_A_CHARGING_MASK 0x02
#define CMD_A_CHARGING_ENABLED 0x00
#define CMD_A_CHARGING_DISABLED 0x02
@@ -257,17 +264,16 @@
chip->charging_allowed = true;
- if (chip->input_current_limit_ua > 0
- && chip->charge_current_limit_ua > 0) {
- if (!chip->charging_enabled)
- rc = smb137c_masked_write_reg(chip, CMD_A_REG,
- CMD_A_CHARGING_MASK, CMD_A_CHARGING_ENABLED);
- chip->charging_enabled = true;
-
+ if (!chip->charging_enabled && chip->charge_current_limit_ua > 0) {
+ rc = smb137c_masked_write_reg(chip, CMD_A_REG,
+ CMD_A_CHARGING_MASK, CMD_A_CHARGING_ENABLED);
if (!rc)
- dev_dbg(&chip->client->dev, "%s\n", __func__);
+ chip->charging_enabled = true;
}
+ if (!rc)
+ dev_dbg(&chip->client->dev, "%s\n", __func__);
+
return rc;
}
@@ -280,10 +286,10 @@
if (chip->charging_enabled) {
rc = smb137c_masked_write_reg(chip, CMD_A_REG,
CMD_A_CHARGING_MASK, CMD_A_CHARGING_DISABLED);
+ if (!rc)
+ chip->charging_enabled = false;
}
- chip->charging_enabled = false;
-
if (!rc)
dev_dbg(&chip->client->dev, "%s\n", __func__);
@@ -297,7 +303,8 @@
if (!chip->otg_mode_enabled) {
rc = smb137c_masked_write_reg(chip, CMD_A_REG, CMD_A_OTG_MASK,
CMD_A_OTG_ENABLED);
- chip->otg_mode_enabled = true;
+ if (!rc)
+ chip->otg_mode_enabled = true;
}
if (!rc)
@@ -313,7 +320,42 @@
if (chip->otg_mode_enabled) {
rc = smb137c_masked_write_reg(chip, CMD_A_REG, CMD_A_OTG_MASK,
CMD_A_OTG_DISABLED);
- chip->otg_mode_enabled = false;
+ if (!rc)
+ chip->otg_mode_enabled = false;
+ }
+
+ if (!rc)
+ dev_dbg(&chip->client->dev, "%s\n", __func__);
+
+ return rc;
+}
+
+static int smb137c_enable_usb_suspend(struct smb137c_chip *chip)
+{
+ int rc = 0;
+
+ if (!chip->usb_suspend_enabled) {
+ rc = smb137c_masked_write_reg(chip, CMD_A_REG,
+ CMD_A_USB_SUSPEND_MASK, CMD_A_USB_SUSPEND_ENABLED);
+ if (!rc)
+ chip->usb_suspend_enabled = true;
+ }
+
+ if (!rc)
+ dev_dbg(&chip->client->dev, "%s\n", __func__);
+
+ return rc;
+}
+
+static int smb137c_disable_usb_suspend(struct smb137c_chip *chip)
+{
+ int rc = 0;
+
+ if (chip->input_current_limit_ua > 0 && chip->usb_suspend_enabled) {
+ rc = smb137c_masked_write_reg(chip, CMD_A_REG,
+ CMD_A_USB_SUSPEND_MASK, CMD_A_USB_SUSPEND_DISABLED);
+ if (!rc)
+ chip->usb_suspend_enabled = false;
}
if (!rc)
@@ -371,13 +413,11 @@
chip->input_current_limit_ua = config->current_limit_ua;
}
- if (chip->charging_allowed)
- rc = smb137c_enable_charging(chip);
+ rc = smb137c_disable_usb_suspend(chip);
} else {
- /* Current limit is below all set points so disable charging. */
chip->input_current_limit_ua = 0;
- rc = smb137c_disable_charging(chip);
+ rc = smb137c_enable_usb_suspend(chip);
}
if (!rc)
@@ -993,7 +1033,7 @@
struct smb137c_chip *chip = container_of(psy, struct smb137c_chip, psy);
union power_supply_propval prop = {0,};
int scope = POWER_SUPPLY_SCOPE_DEVICE;
- int current_limit = USB_MIN_CURRENT_UA;
+ int current_limit = 0;
int online = 0;
int rc;
@@ -1037,7 +1077,8 @@
/* USB offline */
smb137c_disable_charging(chip);
smb137c_disable_otg_mode(chip);
- smb137c_set_usb_input_current_limit(chip, USB_MIN_CURRENT_UA);
+ smb137c_set_usb_input_current_limit(chip,
+ min(current_limit, USB_MIN_CURRENT_UA));
}
dev_dbg(&chip->client->dev, "%s: end\n", __func__);
@@ -1086,6 +1127,14 @@
val = CTRL_A_AUTO_RECHARGE_ENABLED | CTRL_A_THERM_MONITOR_ENABLED;
mask = CTRL_A_AUTO_RECHARGE_MASK | CTRL_A_THERM_MONITOR_MASK;
rc = smb137c_masked_write_reg(chip, CTRL_A_REG, mask, val);
+ if (rc)
+ return rc;
+
+ /* Use register value instead of pin to control USB suspend. */
+ rc = smb137c_masked_write_reg(chip, VAR_FUNC_REG,
+ VAR_FUNC_USB_SUSPEND_CTRL_MASK, VAR_FUNC_USB_SUSPEND_CTRL_REG);
+ if (rc)
+ return rc;
return rc;
}
diff --git a/drivers/regulator/onsemi-ncp6335d.c b/drivers/regulator/onsemi-ncp6335d.c
index a0c90f0..4574862 100644
--- a/drivers/regulator/onsemi-ncp6335d.c
+++ b/drivers/regulator/onsemi-ncp6335d.c
@@ -369,8 +369,16 @@
.remove = __devexit_p(ncp6335d_regulator_remove),
.id_table = ncp6335d_id,
};
+static int __init ncp6335d_regulator_init(void)
+{
+ return i2c_add_driver(&ncp6335d_regulator_driver);
+}
+subsys_initcall(ncp6335d_regulator_init);
-module_i2c_driver(ncp6335d_regulator_driver);
-
+static void __exit ncp6335d_regulator_exit(void)
+{
+ i2c_del_driver(&ncp6335d_regulator_driver);
+}
+module_exit(ncp6335d_regulator_exit);
MODULE_DESCRIPTION("OnSemi-NCP6335D regulator driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index 02e1952..78e8a6f 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -172,13 +172,16 @@
u8 *tid, struct completion *done)
{
struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
+ mutex_lock(&ctrl->m_ctrl);
if (ctrl->last_tid <= 255) {
ctrl->txnt = krealloc(ctrl->txnt,
(ctrl->last_tid + 1) *
sizeof(struct slim_msg_txn *),
GFP_KERNEL);
- if (!ctrl->txnt)
+ if (!ctrl->txnt) {
+ mutex_unlock(&ctrl->m_ctrl);
return -ENOMEM;
+ }
dev->msg_cnt = ctrl->last_tid;
ctrl->last_tid++;
} else {
@@ -190,6 +193,7 @@
}
if (i >= 256) {
dev_err(&ctrl->dev, "out of TID");
+ mutex_unlock(&ctrl->m_ctrl);
return -ENOMEM;
}
}
@@ -197,6 +201,7 @@
txn->tid = dev->msg_cnt;
txn->comp = done;
*tid = dev->msg_cnt;
+ mutex_unlock(&ctrl->m_ctrl);
return 0;
}
static int ngd_xfer_msg(struct slim_controller *ctrl, struct slim_msg_txn *txn)
@@ -369,6 +374,9 @@
pr_err("connect/disc :0x%x, tid:%d timed out", txn->mc,
txn->tid);
ret = -ETIMEDOUT;
+ mutex_lock(&ctrl->m_ctrl);
+ ctrl->txnt[txn->tid] = NULL;
+ mutex_unlock(&ctrl->m_ctrl);
} else {
ret = txn->ec;
}
@@ -394,6 +402,9 @@
pr_err("master req:0x%x, tid:%d timed out", txn->mc,
txn->tid);
ret = -ETIMEDOUT;
+ mutex_lock(&ctrl->m_ctrl);
+ ctrl->txnt[txn->tid] = NULL;
+ mutex_unlock(&ctrl->m_ctrl);
} else {
ret = txn->ec;
}
@@ -526,10 +537,8 @@
txn.dt = SLIM_MSG_DEST_LOGICALADDR;
txn.la = SLIM_LA_MGR;
txn.ec = 0;
- mutex_lock(&ctrl->m_ctrl);
ret = ngd_get_tid(ctrl, &txn, &wbuf[0], &done);
if (ret) {
- mutex_unlock(&ctrl->m_ctrl);
return ret;
}
memcpy(&wbuf[1], ea, elen);
@@ -543,7 +552,6 @@
ret = -ENXIO;
else if (!ret)
*laddr = txn.la;
- mutex_unlock(&ctrl->m_ctrl);
return ret;
}
@@ -606,20 +614,33 @@
}
if (mc == SLIM_USR_MC_ADDR_REPLY &&
mt == SLIM_MSG_MT_SRC_REFERRED_USER) {
- struct slim_msg_txn *txn = dev->ctrl.txnt[buf[3]];
+ struct slim_msg_txn *txn;
u8 failed_ea[6] = {0, 0, 0, 0, 0, 0};
- if (!txn)
+ mutex_lock(&dev->ctrl.m_ctrl);
+ txn = dev->ctrl.txnt[buf[3]];
+ if (!txn) {
+ pr_err("LADDR response after timeout, tid:0x%x",
+ buf[3]);
+ mutex_unlock(&dev->ctrl.m_ctrl);
return;
+ }
if (memcmp(&buf[4], failed_ea, 6))
txn->la = buf[10];
dev->ctrl.txnt[buf[3]] = NULL;
+ mutex_unlock(&dev->ctrl.m_ctrl);
complete(txn->comp);
}
if (mc == SLIM_USR_MC_GENERIC_ACK &&
mt == SLIM_MSG_MT_SRC_REFERRED_USER) {
- struct slim_msg_txn *txn = dev->ctrl.txnt[buf[3]];
- if (!txn)
+ struct slim_msg_txn *txn;
+ mutex_lock(&dev->ctrl.m_ctrl);
+ txn = dev->ctrl.txnt[buf[3]];
+ if (!txn) {
+ pr_err("ACK received after timeout, tid:0x%x",
+ buf[3]);
+ mutex_unlock(&dev->ctrl.m_ctrl);
return;
+ }
dev_dbg(dev->dev, "got response:tid:%d, response:0x%x",
(int)buf[3], buf[4]);
if (!(buf[4] & MSM_SAT_SUCCSS)) {
@@ -628,6 +649,7 @@
txn->ec = -EIO;
}
dev->ctrl.txnt[buf[3]] = NULL;
+ mutex_unlock(&dev->ctrl.m_ctrl);
complete(txn->comp);
}
}
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index d5d6e0c..c320e46 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -1216,7 +1216,7 @@
if (flow != SLIM_SRC)
return -EINVAL;
- mutex_lock(&ctrl->m_ctrl);
+ mutex_lock(&ctrl->sched.m_reconf);
if (slc->state == SLIM_CH_FREE) {
ret = -ENOTCONN;
@@ -1238,7 +1238,7 @@
slc->srch = srch;
connect_src_err:
- mutex_unlock(&ctrl->m_ctrl);
+ mutex_unlock(&ctrl->sched.m_reconf);
return ret;
}
EXPORT_SYMBOL_GPL(slim_connect_src);
@@ -1265,7 +1265,7 @@
if (!sinkh || !nsink)
return -EINVAL;
- mutex_lock(&ctrl->m_ctrl);
+ mutex_lock(&ctrl->sched.m_reconf);
/*
* Once channel is removed, its ports can be considered disconnected
@@ -1303,7 +1303,7 @@
slc->nsink += nsink;
connect_sink_err:
- mutex_unlock(&ctrl->m_ctrl);
+ mutex_unlock(&ctrl->sched.m_reconf);
return ret;
}
EXPORT_SYMBOL_GPL(slim_connect_sink);
@@ -1320,11 +1320,11 @@
struct slim_controller *ctrl = sb->ctrl;
int i;
- mutex_lock(&ctrl->m_ctrl);
+ mutex_lock(&ctrl->sched.m_reconf);
for (i = 0; i < nph; i++)
disconnect_port_ch(ctrl, ph[i]);
- mutex_unlock(&ctrl->m_ctrl);
+ mutex_unlock(&ctrl->sched.m_reconf);
return 0;
}
EXPORT_SYMBOL_GPL(slim_disconnect_ports);
@@ -1660,13 +1660,13 @@
if (!ctrl)
return -EINVAL;
- mutex_lock(&ctrl->m_ctrl);
+ mutex_lock(&ctrl->sched.m_reconf);
for (i = 0; i < ctrl->nchans; i++) {
if (ctrl->chans[i].state == SLIM_CH_FREE)
break;
}
if (i >= ctrl->nchans) {
- mutex_unlock(&ctrl->m_ctrl);
+ mutex_unlock(&ctrl->sched.m_reconf);
return -EXFULL;
}
*chanh = i;
@@ -1674,7 +1674,7 @@
ctrl->chans[i].state = SLIM_CH_ALLOCATED;
ctrl->chans[i].chan = (u8)(ctrl->reserved + i);
- mutex_unlock(&ctrl->m_ctrl);
+ mutex_unlock(&ctrl->sched.m_reconf);
return 0;
}
EXPORT_SYMBOL_GPL(slim_alloc_ch);
@@ -1698,7 +1698,7 @@
int ret = 0;
if (!ctrl || !chanh)
return -EINVAL;
- mutex_lock(&ctrl->m_ctrl);
+ mutex_lock(&ctrl->sched.m_reconf);
/* start with modulo number */
i = ch % ctrl->nchans;
@@ -1729,7 +1729,7 @@
i = (i + 1) % ctrl->nchans;
}
query_out:
- mutex_unlock(&ctrl->m_ctrl);
+ mutex_unlock(&ctrl->sched.m_reconf);
dev_dbg(&ctrl->dev, "query ch:%d,hdl:%d,ref:%d,ret:%d",
ch, i, ctrl->chans[i].ref, ret);
return ret;
@@ -1751,26 +1751,26 @@
if (!ctrl)
return -EINVAL;
- mutex_lock(&ctrl->m_ctrl);
+ mutex_lock(&ctrl->sched.m_reconf);
if (slc->state == SLIM_CH_FREE) {
- mutex_unlock(&ctrl->m_ctrl);
+ mutex_unlock(&ctrl->sched.m_reconf);
return -ENOTCONN;
}
if (slc->ref > 1) {
slc->ref--;
- mutex_unlock(&ctrl->m_ctrl);
+ mutex_unlock(&ctrl->sched.m_reconf);
dev_dbg(&ctrl->dev, "remove chan:%d,hdl:%d,ref:%d",
slc->chan, chanh, slc->ref);
return 0;
}
if (slc->state >= SLIM_CH_PENDING_ACTIVE) {
dev_err(&ctrl->dev, "Channel:%d should be removed first", chan);
- mutex_unlock(&ctrl->m_ctrl);
+ mutex_unlock(&ctrl->sched.m_reconf);
return -EISCONN;
}
slc->ref--;
slc->state = SLIM_CH_FREE;
- mutex_unlock(&ctrl->m_ctrl);
+ mutex_unlock(&ctrl->sched.m_reconf);
dev_dbg(&ctrl->dev, "remove chan:%d,hdl:%d,ref:%d",
slc->chan, chanh, slc->ref);
return 0;
@@ -1812,7 +1812,7 @@
if (!ctrl || !chanh || !prop || !nchan)
return -EINVAL;
- mutex_lock(&ctrl->m_ctrl);
+ mutex_lock(&ctrl->sched.m_reconf);
for (i = 0; i < nchan; i++) {
u8 chan = SLIM_HDL_TO_CHIDX(chanh[i]);
struct slim_ich *slc = &ctrl->chans[chan];
@@ -1856,7 +1856,7 @@
}
err_define_ch:
dev_dbg(&ctrl->dev, "define_ch: ch:%d, ret:%d", *chanh, ret);
- mutex_unlock(&ctrl->m_ctrl);
+ mutex_unlock(&ctrl->sched.m_reconf);
return ret;
}
EXPORT_SYMBOL_GPL(slim_define_ch);
@@ -2607,7 +2607,6 @@
struct slim_pending_ch *pch;
mutex_lock(&ctrl->sched.m_reconf);
- mutex_lock(&ctrl->m_ctrl);
/*
* If there are no pending changes from this client, avoid sending
* the reconfiguration sequence
@@ -2631,7 +2630,6 @@
}
}
if (list_empty(&sb->mark_removal)) {
- mutex_unlock(&ctrl->m_ctrl);
mutex_unlock(&ctrl->sched.m_reconf);
pr_info("SLIM_CL: skip reconfig sequence");
return 0;
@@ -2820,7 +2818,6 @@
ctrl->sched.msgsl = ctrl->sched.pending_msgsl;
sb->cur_msgsl = sb->pending_msgsl;
slim_chan_changes(sb, false);
- mutex_unlock(&ctrl->m_ctrl);
mutex_unlock(&ctrl->sched.m_reconf);
return 0;
}
@@ -2828,7 +2825,6 @@
revert_reconfig:
/* Revert channel changes */
slim_chan_changes(sb, true);
- mutex_unlock(&ctrl->m_ctrl);
mutex_unlock(&ctrl->sched.m_reconf);
return ret;
}
@@ -2876,7 +2872,6 @@
return -EINVAL;
mutex_lock(&sb->sldev_reconf);
- mutex_lock(&ctrl->m_ctrl);
do {
struct slim_pending_ch *pch;
u8 add_mark_removal = true;
@@ -2935,7 +2930,6 @@
if (nchan < SLIM_GRP_TO_NCHAN(chanh))
chan = SLIM_HDL_TO_CHIDX(slc->nextgrp);
} while (nchan < SLIM_GRP_TO_NCHAN(chanh));
- mutex_unlock(&ctrl->m_ctrl);
if (!ret && commit == true)
ret = slim_reconfigure_now(sb);
mutex_unlock(&sb->sldev_reconf);
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index 0497a32..dba02f8 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -288,6 +288,18 @@
return spi_op & SPI_OP_STATE_VALID;
}
+static inline void msm_spi_udelay(unsigned long delay_usecs)
+{
+ /*
+ * For smaller values of delay, context switch time
+ * would negate the usage of usleep
+ */
+ if (delay_usecs > 20)
+ usleep_range(delay_usecs, delay_usecs);
+ else if (delay_usecs)
+ udelay(delay_usecs);
+}
+
static inline int msm_spi_wait_valid(struct msm_spi *dd)
{
unsigned long delay = 0;
@@ -321,14 +333,7 @@
} else
return 0;
}
- /*
- * For smaller values of delay, context switch time
- * would negate the usage of usleep
- */
- if (delay > 20)
- usleep(delay);
- else if (delay)
- udelay(delay);
+ msm_spi_udelay(delay);
}
return 0;
}
@@ -1412,6 +1417,7 @@
}
} while (msm_spi_dm_send_next(dd));
+ msm_spi_udelay(dd->cur_transfer->delay_usecs);
transfer_end:
msm_spi_dma_unmap_buffers(dd);
dd->mode = SPI_MODE_NONE;
@@ -1504,6 +1510,8 @@
int xfrs_grped = 0;
int cs_num;
int rc;
+ bool xfer_delay = false;
+ struct spi_transfer *tr;
dd->write_xfr_cnt = dd->read_xfr_cnt = 0;
cs_num = dd->cur_msg->spi->chip_select;
@@ -1521,8 +1529,21 @@
dd->cs_gpios[cs_num].valid = 1;
}
- if (dd->qup_ver) {
- write_force_cs(dd, 0);
+ list_for_each_entry(tr,
+ &dd->cur_msg->transfers,
+ transfer_list) {
+ if (tr->delay_usecs) {
+ dev_info(dd->dev, "SPI slave requests delay per txn :%d",
+ tr->delay_usecs);
+ xfer_delay = true;
+ break;
+ }
+ }
+
+ /* Don't combine xfers if delay is needed after every xfer */
+ if (dd->qup_ver || xfer_delay) {
+ if (dd->qup_ver)
+ write_force_cs(dd, 0);
list_for_each_entry(dd->cur_transfer,
&dd->cur_msg->transfers,
transfer_list) {
@@ -1534,9 +1555,10 @@
struct spi_transfer,
transfer_list);
- if (t->cs_change == nxt->cs_change)
+ if (dd->qup_ver &&
+ t->cs_change == nxt->cs_change)
write_force_cs(dd, 1);
- else
+ else if (dd->qup_ver)
write_force_cs(dd, 0);
}
@@ -2658,7 +2680,8 @@
err_probe_reg_master:
err_probe_irq:
err_probe_state:
- dd->dma_teardown(dd);
+ if (dd->dma_teardown)
+ dd->dma_teardown(dd);
err_probe_dma:
err_probe_gsbi:
if (pclk_enabled)
@@ -2741,7 +2764,8 @@
spi_debugfs_exit(dd);
sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
- dd->dma_teardown(dd);
+ if (dd->dma_teardown)
+ dd->dma_teardown(dd);
clk_put(dd->clk);
clk_put(dd->pclk);
destroy_workqueue(dd->workqueue);
diff --git a/drivers/tty/serial/msm_serial_hs_lite.c b/drivers/tty/serial/msm_serial_hs_lite.c
index cc9ffaa..3de990c 100644
--- a/drivers/tty/serial/msm_serial_hs_lite.c
+++ b/drivers/tty/serial/msm_serial_hs_lite.c
@@ -18,6 +18,8 @@
* This file is based on msm_serial.c, originally
* Written by Robert Love <rlove@google.com> */
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
#if defined(CONFIG_SERIAL_MSM_HSL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif
@@ -62,6 +64,7 @@
unsigned int old_snap_state;
unsigned int ver_id;
int tx_timeout;
+ struct mutex clk_mutex;
};
#define UARTDM_VERSION_11_13 0
@@ -188,11 +191,12 @@
unsigned long flags;
int ret = 0;
- ret = clk_set_rate(msm_hsl_port->clk, 7372800);
- if (!ret)
+ ret = clk_set_rate(msm_hsl_port->clk, port->uartclk);
+ if (!ret) {
clk_en(port, 1);
- else {
- pr_err("%s(): Error: Setting the clock rate\n", __func__);
+ } else {
+ pr_err("Error: setting uartclk rate as %u\n",
+ port->uartclk);
return -EINVAL;
}
@@ -221,11 +225,12 @@
unsigned long flags;
int ret = 0;
- ret = clk_set_rate(msm_hsl_port->clk, 7372800);
- if (!ret)
+ ret = clk_set_rate(msm_hsl_port->clk, port->uartclk);
+ if (!ret) {
clk_en(port, 1);
- else {
- pr_err("%s(): Error setting clk rate\n", __func__);
+ } else {
+ pr_err("Error setting uartclk rate as %u\n",
+ port->uartclk);
return -EINVAL;
}
@@ -258,8 +263,7 @@
&loopback_enable_fops);
if (IS_ERR_OR_NULL(msm_uport->loopback_dir))
- pr_err("%s(): Cannot create loopback.%d debug entry",
- __func__, id);
+ pr_err("Cannot create loopback.%d debug entry", id);
}
static void msm_hsl_stop_tx(struct uart_port *port)
{
@@ -561,7 +565,13 @@
msm_hsl_write(port, STOP_BREAK, regmap[vid][UARTDM_CR]);
}
-static void msm_hsl_set_baud_rate(struct uart_port *port, unsigned int baud)
+/**
+ * msm_hsl_set_baud_rate: set requested baud rate
+ * @port: uart port
+ * @baud: baud rate to set (in bps)
+ */
+static void msm_hsl_set_baud_rate(struct uart_port *port,
+ unsigned int baud)
{
unsigned int baud_code, rxstale, watermark;
unsigned int data;
@@ -625,18 +635,54 @@
baud_code = UARTDM_CSR_115200;
rxstale = 31;
break;
- default: /* 115200 baud rate */
+ case 4000000:
+ case 3686400:
+ case 3200000:
+ case 3500000:
+ case 3000000:
+ case 2500000:
+ case 1500000:
+ case 1152000:
+ case 1000000:
+ case 921600:
+ baud_code = 0xff;
+ rxstale = 31;
+ break;
+ default: /*115200 baud rate */
baud_code = UARTDM_CSR_28800;
rxstale = 31;
break;
}
- /* Set timeout to be ~600x the character transmit time */
- msm_hsl_port->tx_timeout = (1000000000 / baud) * 6;
-
vid = msm_hsl_port->ver_id;
msm_hsl_write(port, baud_code, regmap[vid][UARTDM_CSR]);
+ /*
+ * uart baud rate depends on CSR and MND Values
+ * we are updating CSR before and then calling
+ * clk_set_rate which updates MND Values. Hence
+ * dsb requires here.
+ */
+ mb();
+
+ /*
+ * Check requested baud rate and for higher baud rate than 460800,
+ * calculate required uart clock frequency and set the same.
+ */
+ if (baud > 460800) {
+
+ port->uartclk = baud * 16;
+ if (clk_set_rate(msm_hsl_port->clk, port->uartclk)) {
+ pr_err("%s(): Error setting uartclk rate %u\n",
+ __func__, port->uartclk);
+ WARN_ON(1);
+ return;
+ }
+ }
+
+ /* Set timeout to be ~600x the character transmit time */
+ msm_hsl_port->tx_timeout = (1000000000 / baud) * 6;
+
/* RX stale watermark */
watermark = UARTDM_IPR_STALE_LSB_BMSK & rxstale;
watermark |= UARTDM_IPR_STALE_TIMEOUT_MSB_BMSK & (rxstale << 2);
@@ -710,15 +756,15 @@
ret = gpio_request(pdata->uart_tx_gpio,
"UART_TX_GPIO");
if (unlikely(ret)) {
- pr_err("%s: gpio request failed for:%d\n",
- __func__, pdata->uart_tx_gpio);
+ pr_err("gpio request failed for:%d\n",
+ pdata->uart_tx_gpio);
return ret;
}
ret = gpio_request(pdata->uart_rx_gpio, "UART_RX_GPIO");
if (unlikely(ret)) {
- pr_err("%s: gpio request failed for:%d\n",
- __func__, pdata->uart_rx_gpio);
+ pr_err("gpio request failed for:%d\n",
+ pdata->uart_rx_gpio);
gpio_free(pdata->uart_tx_gpio);
return ret;
}
@@ -756,7 +802,7 @@
ret = request_irq(port->irq, msm_hsl_irq, IRQF_TRIGGER_HIGH,
msm_hsl_port->name, port);
if (unlikely(ret)) {
- printk(KERN_ERR "%s: failed to request_irq\n", __func__);
+ pr_err("failed to request_irq\n");
return ret;
}
return 0;
@@ -792,17 +838,28 @@
struct ktermios *termios,
struct ktermios *old)
{
- unsigned long flags;
unsigned int baud, mr;
unsigned int vid;
+ struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port);
if (!termios->c_cflag)
return;
- spin_lock_irqsave(&port->lock, flags);
+ mutex_lock(&msm_hsl_port->clk_mutex);
- /* calculate and set baud rate */
- baud = uart_get_baud_rate(port, termios, old, 300, 460800);
+ /*
+ * Calculate and set baud rate
+ * 300 is the minimum and 4 Mbps is the maximum baud rate
+ * supported by driver.
+ */
+ baud = uart_get_baud_rate(port, termios, old, 200, 4000000);
+
+ /*
+ * Due to non-availability of 3.2 Mbps baud rate as standard baud rate
+ * with TTY/serial core. Map 200 BAUD to 3.2 Mbps
+ */
+ if (baud == 200)
+ baud = 3200000;
msm_hsl_set_baud_rate(port, baud);
@@ -865,7 +922,7 @@
uart_update_timeout(port, termios->c_cflag, baud);
- spin_unlock_irqrestore(&port->lock, flags);
+ mutex_unlock(&msm_hsl_port->clk_mutex);
}
static const char *msm_hsl_type(struct uart_port *port)
@@ -913,14 +970,14 @@
if (!uart_resource)
uart_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (unlikely(!uart_resource)) {
- pr_err("%s: can't get uartdm resource\n", __func__);
+ pr_err("can't get uartdm resource\n");
return -ENXIO;
}
size = uart_resource->end - uart_resource->start + 1;
if (unlikely(!request_mem_region(port->mapbase, size,
"msm_serial_hsl"))) {
- pr_err("%s: can't get mem region for uartdm\n", __func__);
+ pr_err("can't get mem region for uartdm\n");
return -EBUSY;
}
@@ -938,7 +995,7 @@
gsbi_resource = platform_get_resource(pdev,
IORESOURCE_MEM, 1);
if (unlikely(!gsbi_resource)) {
- pr_err("%s: can't get gsbi resource\n", __func__);
+ pr_err("can't get gsbi resource\n");
return -ENXIO;
}
@@ -991,22 +1048,20 @@
switch (state) {
case 0:
- ret = clk_set_rate(msm_hsl_port->clk, 7372800);
+ ret = clk_set_rate(msm_hsl_port->clk, port->uartclk);
if (ret)
- pr_err("%s(): Error setting UART clock rate\n",
- __func__);
+ pr_err("Error setting UART clock rate to %u\n",
+ port->uartclk);
clk_en(port, 1);
break;
case 3:
clk_en(port, 0);
ret = clk_set_rate(msm_hsl_port->clk, 0);
if (ret)
- pr_err("%s(): Error setting UART clock rate to zero.\n",
- __func__);
+ pr_err("Error setting UART clock rate to zero.\n");
break;
default:
- pr_err("%s(): msm_serial_hsl: Unknown PM state %d\n",
- __func__, state);
+ pr_err("Unknown PM state %d\n", state);
}
}
@@ -1093,15 +1148,15 @@
msm_hsl_console_state[6] = rxfs;
msm_hsl_console_state[7] = con_state;
- pr_info("%s(): Timeout: %d uS\n", __func__, msm_hsl_port->tx_timeout);
- pr_info("%s(): SR: %08x\n", __func__, sr);
- pr_info("%s(): ISR: %08x\n", __func__, isr);
- pr_info("%s(): MR1: %08x\n", __func__, mr1);
- pr_info("%s(): MR2: %08x\n", __func__, mr2);
- pr_info("%s(): NCF: %08x\n", __func__, ncf);
- pr_info("%s(): TXFS: %08x\n", __func__, txfs);
- pr_info("%s(): RXFS: %08x\n", __func__, rxfs);
- pr_info("%s(): Console state: %d\n", __func__, con_state);
+ pr_info("Timeout: %d uS\n", msm_hsl_port->tx_timeout);
+ pr_info("SR: %08x\n", sr);
+ pr_info("ISR: %08x\n", isr);
+ pr_info("MR1: %08x\n", mr1);
+ pr_info("MR2: %08x\n", mr2);
+ pr_info("NCF: %08x\n", ncf);
+ pr_info("TXFS: %08x\n", txfs);
+ pr_info("RXFS: %08x\n", rxfs);
+ pr_info("Console state: %d\n", con_state);
}
/*
@@ -1228,8 +1283,7 @@
msm_hsl_write(port, 1, regmap[vid][UARTDM_NCF_TX]);
msm_hsl_read(port, regmap[vid][UARTDM_NCF_TX]);
- printk(KERN_INFO "msm_serial_hsl: console setup on port #%d\n",
- port->line);
+ pr_info("console setup on port #%d\n", port->line);
return ret;
}
@@ -1302,9 +1356,9 @@
switch (enable) {
case 0:
- pr_debug("%s(): Calling stop_console\n", __func__);
+ pr_debug("Calling stop_console\n");
console_stop(port->cons);
- pr_debug("%s(): Calling unregister_console\n", __func__);
+ pr_debug("Calling unregister_console\n");
unregister_console(port->cons);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
@@ -1316,7 +1370,7 @@
msm_hsl_power(port, 3, 1);
break;
case 1:
- pr_debug("%s(): Calling register_console\n", __func__);
+ pr_debug("Calling register_console\n");
/*
* Disable UART Core clk
* 0 - to enable the UART clock
@@ -1379,11 +1433,11 @@
if (unlikely(line < 0 || line >= UART_NR))
return -ENXIO;
- printk(KERN_INFO "msm_serial_hsl: detected port #%d (ttyHSL%d)\n",
- pdev->id, line);
+ pr_info("detected port #%d (ttyHSL%d)\n", pdev->id, line);
port = get_port_from_line(line);
port->dev = &pdev->dev;
+ port->uartclk = 7372800;
msm_hsl_port = UART_TO_MSM(port);
match = of_match_device(msm_hsl_match_table, &pdev->dev);
@@ -1406,11 +1460,11 @@
msm_hsl_port->is_uartdm = 0;
if (unlikely(IS_ERR(msm_hsl_port->clk))) {
- printk(KERN_ERR "%s: Error getting clk\n", __func__);
+ pr_err("Error getting clk\n");
return PTR_ERR(msm_hsl_port->clk);
}
if (unlikely(IS_ERR(msm_hsl_port->pclk))) {
- printk(KERN_ERR "%s: Error getting pclk\n", __func__);
+ pr_err("Error getting pclk\n");
return PTR_ERR(msm_hsl_port->pclk);
}
@@ -1420,14 +1474,14 @@
if (!uart_resource)
uart_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (unlikely(!uart_resource)) {
- printk(KERN_ERR "getting uartdm_resource failed\n");
+ pr_err("getting uartdm_resource failed\n");
return -ENXIO;
}
port->mapbase = uart_resource->start;
port->irq = platform_get_irq(pdev, 0);
if (unlikely((int)port->irq < 0)) {
- printk(KERN_ERR "%s: getting irq failed\n", __func__);
+ pr_err("getting irq failed\n");
return -ENXIO;
}
@@ -1437,9 +1491,10 @@
#ifdef CONFIG_SERIAL_MSM_HSL_CONSOLE
ret = device_create_file(&pdev->dev, &dev_attr_console);
if (unlikely(ret))
- pr_err("%s():Can't create console attribute\n", __func__);
+ pr_err("Can't create console attribute\n");
#endif
msm_hsl_debugfs_init(msm_hsl_port, get_line(pdev));
+ mutex_init(&msm_hsl_port->clk_mutex);
/* Temporarily increase the refcount on the GSBI clock to avoid a race
* condition with the earlyprintk handover mechanism.
@@ -1466,6 +1521,7 @@
device_set_wakeup_capable(&pdev->dev, 0);
platform_set_drvdata(pdev, NULL);
+ mutex_destroy(&msm_hsl_port->clk_mutex);
uart_remove_one_port(&msm_hsl_uart_driver, port);
clk_put(msm_hsl_port->pclk);
@@ -1568,13 +1624,13 @@
debug_base = debugfs_create_dir("msm_serial_hsl", NULL);
if (IS_ERR_OR_NULL(debug_base))
- pr_err("%s():Cannot create debugfs dir\n", __func__);
+ pr_err("Cannot create debugfs dir\n");
ret = platform_driver_register(&msm_hsl_platform_driver);
if (unlikely(ret))
uart_unregister_driver(&msm_hsl_uart_driver);
- printk(KERN_INFO "msm_serial_hsl: driver initialized\n");
+ pr_info("driver initialized\n");
return ret;
}
diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c
index d4a30f1..be4eff7 100644
--- a/drivers/usb/dwc3/debugfs.c
+++ b/drivers/usb/dwc3/debugfs.c
@@ -56,7 +56,7 @@
#define dump_register(nm) \
{ \
.name = __stringify(nm), \
- .offset = DWC3_ ##nm, \
+ .offset = DWC3_ ##nm - DWC3_GLOBALS_REGS_START, \
}
static const struct debugfs_reg32 dwc3_regs[] = {
diff --git a/drivers/usb/gadget/f_qc_rndis.c b/drivers/usb/gadget/f_qc_rndis.c
index f86bf12..82ef2a8 100644
--- a/drivers/usb/gadget/f_qc_rndis.c
+++ b/drivers/usb/gadget/f_qc_rndis.c
@@ -85,6 +85,7 @@
u8 ethaddr[ETH_ALEN];
u32 vendorID;
u8 max_pkt_per_xfer;
+ u32 max_pkt_size;
const char *manufacturer;
int config;
atomic_t ioctl_excl;
@@ -125,6 +126,7 @@
#define RNDIS_QC_IOCTL_MAGIC 'i'
#define RNDIS_QC_GET_MAX_PKT_PER_XFER _IOR(RNDIS_QC_IOCTL_MAGIC, 1, u8)
+#define RNDIS_QC_GET_MAX_PKT_SIZE _IOR(RNDIS_QC_IOCTL_MAGIC, 2, u32)
/* interface descriptor: */
@@ -552,14 +554,22 @@
static void rndis_qc_command_complete(struct usb_ep *ep,
struct usb_request *req)
{
- struct f_rndis_qc *rndis = req->context;
+ struct f_rndis_qc *rndis = req->context;
int status;
+ rndis_init_msg_type *buf;
/* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */
status = rndis_msg_parser(rndis->config, (u8 *) req->buf);
if (status < 0)
pr_err("RNDIS command error %d, %d/%d\n",
status, req->actual, req->length);
+
+ buf = (rndis_init_msg_type *)req->buf;
+
+ if (buf->MessageType == REMOTE_NDIS_INITIALIZE_MSG) {
+ rndis->max_pkt_size = buf->MaxTransferSize;
+ pr_debug("MaxTransferSize: %d\n", buf->MaxTransferSize);
+ }
}
static int
@@ -1110,6 +1120,17 @@
pr_info("Sent max packets per xfer %d",
rndis->max_pkt_per_xfer);
break;
+ case RNDIS_QC_GET_MAX_PKT_SIZE:
+ ret = copy_to_user((void __user *)arg,
+ &rndis->max_pkt_size,
+ sizeof(rndis->max_pkt_size));
+ if (ret) {
+ pr_err("copying to user space failed");
+ ret = -EFAULT;
+ }
+ pr_debug("Sent max packet size %d",
+ rndis->max_pkt_size);
+ break;
default:
pr_err("Unsupported IOCTL");
ret = -EINVAL;
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index c6fe765..dde9312 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -485,6 +485,9 @@
ret = msm_otg_phy_clk_reset(motg);
if (ret)
return ret;
+ /* 10 usec delay is required according to spec */
+ if (IS_ERR(motg->phy_reset_clk))
+ usleep_range(10, 12);
ret = msm_otg_link_clk_reset(motg, 0);
if (ret)
return ret;
@@ -771,10 +774,12 @@
if (aca_enabled())
return 0;
- if (atomic_read(&motg->in_lpm) == suspend &&
- !atomic_read(&motg->suspend_work_pending))
- return 0;
-
+ /*
+ * UDC and HCD call usb_phy_set_suspend() to enter/exit LPM
+ * during bus suspend/resume. Update the relevant state
+ * machine inputs and trigger LPM entry/exit. Checking
+ * in_lpm flag would avoid unnecessary work scheduling.
+ */
if (suspend) {
switch (phy->state) {
case OTG_STATE_A_WAIT_BCON:
@@ -784,16 +789,18 @@
case OTG_STATE_A_HOST:
pr_debug("host bus suspend\n");
clear_bit(A_BUS_REQ, &motg->inputs);
- queue_work(system_nrt_wq, &motg->sm_work);
+ if (!atomic_read(&motg->in_lpm))
+ queue_work(system_nrt_wq, &motg->sm_work);
break;
case OTG_STATE_B_PERIPHERAL:
pr_debug("peripheral bus suspend\n");
if (!(motg->caps & ALLOW_LPM_ON_DEV_SUSPEND))
break;
set_bit(A_BUS_SUSPEND, &motg->inputs);
- atomic_set(&motg->suspend_work_pending, 1);
- queue_delayed_work(system_nrt_wq, &motg->suspend_work,
- USB_SUSPEND_DELAY_TIME);
+ if (!atomic_read(&motg->in_lpm))
+ queue_delayed_work(system_nrt_wq,
+ &motg->suspend_work,
+ USB_SUSPEND_DELAY_TIME);
break;
default:
@@ -801,20 +808,29 @@
}
} else {
switch (phy->state) {
+ case OTG_STATE_A_WAIT_BCON:
+ /* Remote wakeup or resume */
+ set_bit(A_BUS_REQ, &motg->inputs);
+ /* ensure hardware is not in low power mode */
+ if (atomic_read(&motg->in_lpm))
+ pm_runtime_resume(phy->dev);
+ break;
case OTG_STATE_A_SUSPEND:
/* Remote wakeup or resume */
set_bit(A_BUS_REQ, &motg->inputs);
phy->state = OTG_STATE_A_HOST;
/* ensure hardware is not in low power mode */
- pm_runtime_resume(phy->dev);
+ if (atomic_read(&motg->in_lpm))
+ pm_runtime_resume(phy->dev);
break;
case OTG_STATE_B_PERIPHERAL:
pr_debug("peripheral bus resume\n");
if (!(motg->caps & ALLOW_LPM_ON_DEV_SUSPEND))
break;
clear_bit(A_BUS_SUSPEND, &motg->inputs);
- queue_work(system_nrt_wq, &motg->sm_work);
+ if (atomic_read(&motg->in_lpm))
+ queue_work(system_nrt_wq, &motg->sm_work);
break;
default:
break;
@@ -2945,8 +2961,10 @@
{
struct msm_otg *motg =
container_of(w, struct msm_otg, suspend_work.work);
- atomic_set(&motg->suspend_work_pending, 0);
- msm_otg_sm_work(&motg->sm_work);
+
+ /* This work is only for device bus suspend */
+ if (test_bit(A_BUS_SUSPEND, &motg->inputs))
+ msm_otg_sm_work(&motg->sm_work);
}
static irqreturn_t msm_otg_irq(int irq, void *data)
@@ -3475,6 +3493,21 @@
return 0;
}
+static int otg_power_property_is_writeable_usb(struct power_supply *psy,
+ enum power_supply_property psp)
+{
+ switch (psp) {
+ case POWER_SUPPLY_PROP_PRESENT:
+ case POWER_SUPPLY_PROP_ONLINE:
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ return 1;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static char *otg_pm_power_supplied_to[] = {
"battery",
};
@@ -4055,6 +4088,8 @@
motg->usb_psy.num_properties = ARRAY_SIZE(otg_pm_power_props_usb);
motg->usb_psy.get_property = otg_power_get_property_usb;
motg->usb_psy.set_property = otg_power_set_property_usb;
+ motg->usb_psy.property_is_writeable
+ = otg_power_property_is_writeable_usb;
if (!pm8921_charger_register_vbus_sn(NULL)) {
/* if pm8921 use legacy implementation */
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index a827d6a..372122c 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -886,7 +886,7 @@
outp32(MDP_INTR_CLEAR, mgmt->intr);
mdp_intr_mask &= ~mgmt->intr;
outp32(MDP_INTR_ENABLE, mdp_intr_mask);
- mdp_disable_irq(mgmt->irq_term);
+ mdp_disable_irq_nosync(mgmt->irq_term);
spin_unlock_irqrestore(&mdp_spin_lock, flag);
if (mdp_rev >= MDP_REV_42)
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index ee2405e..67ef8bf 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -96,11 +96,6 @@
#define MDP4_PANEL_WRITEBACK BIT(6)
enum {
- OVERLAY_MODE_NONE,
- OVERLAY_MODE_BLT
-};
-
-enum {
OVERLAY_REFRESH_ON_DEMAND,
OVERLAY_REFRESH_VSYNC,
OVERLAY_REFRESH_VSYNC_HALF,
@@ -451,7 +446,6 @@
void mdp4_intr_clear_set(ulong clear, ulong set);
void mdp4_dma_p_cfg(void);
unsigned is_mdp4_hw_reset(void);
-void mdp4_overlay_cfg_init(void);
void mdp4_hw_init(void);
void mdp4_isr_read(int);
void mdp4_clear_lcdc(void);
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 05344fc..f4332dd 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -53,7 +53,6 @@
uint32 flush[MDP4_MIXER_MAX];
struct iommu_free_list iommu_free[MDP4_MIXER_MAX];
uint32 cs_controller;
- uint32 hw_version;
uint32 panel_3d;
uint32 panel_mode;
uint32 mixer0_played;
@@ -253,7 +252,7 @@
pipe->pipe_ndx, plane);
if (ion_map_iommu(display_iclient, *srcp_ihdl,
DISPLAY_READ_DOMAIN, GEN_POOL, SZ_4K, 0, start,
- len, 0, ION_IOMMU_UNMAP_DELAYED)) {
+ len, 0, 0)) {
ion_free(display_iclient, *srcp_ihdl);
pr_err("ion_map_iommu() failed\n");
return -EINVAL;
@@ -354,23 +353,9 @@
return ctrl->panel_mode;
}
-void mdp4_overlay_cfg_init(void)
-{
- if (ctrl->hw_version == 0) {
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- ctrl->hw_version = inpdw(MDP_BASE + 0x0); /* MDP_HW_VERSION */
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
- }
-
- if (ctrl->hw_version >= 0x0402030b) {
- /* MDP_LAYERMIXER_IN_CFG_UPDATE_METHOD */
- outpdw(MDP_BASE + 0x100fc, 0x01);
- }
-}
-
int mdp4_overlay_borderfill_supported(void)
{
- return (ctrl->hw_version >= 0x0402030b);
+ return (mdp_rev >= MDP_REV_42);
}
void mdp4_overlay_dmae_cfg(struct msm_fb_data_type *mfd, int atv)
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index 239d9f5..450f1de 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -56,7 +56,8 @@
int wait_vsync_cnt;
int blt_change;
int blt_free;
- int blt_ctrl;
+ u32 blt_ctrl;
+ u32 blt_mode;
int sysfs_created;
struct mutex update_lock;
struct completion ov_comp;
@@ -197,18 +198,6 @@
}
spin_unlock_irqrestore(&vctrl->spin_lock, flags);
- if (vctrl->blt_change) {
- pipe = vctrl->base_pipe;
- spin_lock_irqsave(&vctrl->spin_lock, flags);
- INIT_COMPLETION(vctrl->dmap_comp);
- INIT_COMPLETION(vctrl->ov_comp);
- vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM);
- spin_unlock_irqrestore(&vctrl->spin_lock, flags);
- mdp4_dsi_video_wait4dmap(0);
- if (pipe->ov_blt_addr)
- mdp4_dsi_video_wait4ov(0);
- }
-
pipe = vp->plist;
for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) {
@@ -498,7 +487,6 @@
vctrl = &vsync_ctrl_db[cndx];
mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
- pinfo = &mfd->panel_info;
if (!mfd)
return -ENODEV;
@@ -508,7 +496,9 @@
vctrl->mfd = mfd;
vctrl->dev = mfd->fbi->dev;
+ pinfo = &mfd->panel_info;
vctrl->blt_ctrl = pinfo->lcd.blt_ctrl;
+ vctrl->blt_mode = pinfo->lcd.blt_mode;
/* mdp clock on */
mdp_clk_ctrl(1);
@@ -551,6 +541,7 @@
mfd->cont_splash_done = 1;
mdp4_dsi_video_wait4dmap_done(0);
MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 0);
+ dsi_video_enabled = 0;
mipi_dsi_controller_cfg(0);
/* Clks are enabled in probe.
Disabling clocks now */
@@ -940,20 +931,8 @@
if (vctrl->blt_change) {
mdp4_overlayproc_cfg(pipe);
mdp4_overlay_dmap_xy(pipe);
- if (pipe->ov_blt_addr) {
- mdp4_dsi_video_blt_ov_update(pipe);
- pipe->ov_cnt++;
- /* Prefill one frame */
- vsync_irq_enable(INTR_OVERLAY0_DONE,
- MDP_OVERLAY0_TERM);
- /* kickoff overlay0 engine */
- mdp4_stat.kickoff_ov0++;
- vctrl->ov_koff++; /* make up for prefill */
- outpdw(MDP_BASE + 0x0004, 0);
- }
vctrl->blt_change = 0;
}
-
complete_all(&vctrl->dmap_comp);
mdp4_overlay_dma_commit(cndx);
spin_unlock(&vctrl->spin_lock);
@@ -997,19 +976,43 @@
struct vsycn_ctrl *vctrl;
struct mdp4_overlay_pipe *pipe;
long long vtime;
+ u32 mode, ctrl;
vctrl = &vsync_ctrl_db[cndx];
pipe = vctrl->base_pipe;
- mdp4_allocate_writeback_buf(mfd, MDP4_MIXER0);
+ mode = (dbg_force_ov0_blt & 0x0f) ?
+ (dbg_force_ov0_blt & 0x0f) : vctrl->blt_mode;
+ ctrl = (dbg_force_ov0_blt >> 4) ?
+ (dbg_force_ov0_blt >> 4) : vctrl->blt_ctrl;
- if (mfd->ov0_wb_buf->write_addr == 0) {
- pr_info("%s: no blt_base assigned\n", __func__);
+ pr_debug("%s: mode=%d, enable=%d ov_blt_addr=%x\n",
+ __func__, mode, enable, (int)pipe->ov_blt_addr);
+
+ if ((mode == MDP4_OVERLAY_MODE_BLT_ALWAYS_OFF) &&
+ !pipe->ov_blt_addr)
return;
+ else if ((mode == MDP4_OVERLAY_MODE_BLT_ALWAYS_ON) &&
+ pipe->ov_blt_addr)
+ return;
+ else if (enable && pipe->ov_blt_addr)
+ return;
+ else if (!enable && !pipe->ov_blt_addr)
+ return;
+
+ if (pipe->ov_blt_addr == 0) {
+ mdp4_allocate_writeback_buf(mfd, MDP4_MIXER0);
+ if (mfd->ov0_wb_buf->write_addr == 0) {
+ pr_warning("%s: no blt_base assigned\n", __func__);
+ return;
+ }
}
+ pr_debug("%s: mode=%d, enable=%d ov_blt_addr=%x\n",
+ __func__, mode, enable, (int)pipe->ov_blt_addr);
+
spin_lock_irqsave(&vctrl->spin_lock, flag);
- if (enable && pipe->ov_blt_addr == 0) {
+ if (pipe->ov_blt_addr == 0) {
pipe->ov_blt_addr = mfd->ov0_wb_buf->write_addr;
pipe->dma_blt_addr = mfd->ov0_wb_buf->read_addr;
pipe->ov_cnt = 0;
@@ -1018,36 +1021,38 @@
vctrl->ov_done = 0;
vctrl->blt_free = 0;
mdp4_stat.blt_dsi_video++;
- vctrl->blt_change++;
- } else if (enable == 0 && pipe->ov_blt_addr) {
+ } else {
pipe->ov_blt_addr = 0;
pipe->dma_blt_addr = 0;
vctrl->blt_free = 4; /* 4 commits to free wb buf */
- vctrl->blt_change++;
- }
-
- pr_info("%s: changed=%d enable=%d ov_blt_addr=%x\n", __func__,
- vctrl->blt_change, enable, (int)pipe->ov_blt_addr);
-
- if (!vctrl->blt_change) {
- spin_unlock_irqrestore(&vctrl->spin_lock, flag);
- return;
}
spin_unlock_irqrestore(&vctrl->spin_lock, flag);
- if (vctrl->blt_ctrl == BLT_SWITCH_TG_OFF) {
- int tg_enabled;
-
- vctrl->blt_change = 0;
- tg_enabled = inpdw(MDP_BASE + DSI_VIDEO_BASE) & 0x01;
- if (tg_enabled) {
+ if (ctrl == MDP4_OVERLAY_BLT_SWITCH_TG_ON) {
+ spin_lock_irqsave(&vctrl->spin_lock, flag);
+ if (!dsi_video_enabled) {
+ pr_debug("%s: blt switched not in ISR dsi_video_enabled=%d\n",
+ __func__, dsi_video_enabled);
+ mdp4_overlayproc_cfg(pipe);
+ mdp4_overlay_dmap_xy(pipe);
+ } else {
+ pr_debug("%s: blt switched in ISR dsi_video_enabled=%d\n",
+ __func__, dsi_video_enabled);
+ vctrl->blt_change++;
+ }
+ spin_unlock_irqrestore(&vctrl->spin_lock, flag);
+ if (dsi_video_enabled)
+ mdp4_dsi_video_wait4dmap_done(0);
+ } else if (ctrl == MDP4_OVERLAY_BLT_SWITCH_TG_OFF) {
+ pr_debug("%s: blt switched by turning TG off\n", __func__);
+ if (dsi_video_enabled) {
mdp4_dsi_video_wait4vsync(0, &vtime);
MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 0);
mdp4_dsi_video_wait4dmap_done(0);
}
mdp4_overlayproc_cfg(pipe);
mdp4_overlay_dmap_xy(pipe);
- if (tg_enabled) {
+ if (dsi_video_enabled) {
/*
* need wait for more than 1 ms to
* make sure dsi lanes' fifo is empty and
@@ -1058,7 +1063,15 @@
mipi_dsi_sw_reset();
MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 1);
}
- }
+ } else if (ctrl == MDP4_OVERLAY_BLT_SWITCH_POLL) {
+ pr_debug("%s: blt switched by polling mdp status\n", __func__);
+ if (dsi_video_enabled)
+ while (inpdw(MDP_BASE + 0x0018) & 0x05)
+ cpu_relax();
+ mdp4_overlayproc_cfg(pipe);
+ mdp4_overlay_dmap_xy(pipe);
+ } else
+ pr_err("%s: ctrl=%d is not supported\n", __func__, ctrl);
}
void mdp4_dsi_video_overlay_blt(struct msm_fb_data_type *mfd,
@@ -1125,4 +1138,3 @@
mdp4_overlay_mdp_perf_upd(mfd, 0);
mutex_unlock(&mfd->dma->ov_mutex);
}
-
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index 1de5d6e..7de2e2a 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -66,6 +66,9 @@
int dmae_wait_cnt;
int wait_vsync_cnt;
int blt_change;
+ int blt_ctrl;
+ int blt_mode;
+ int blt_free;
int sysfs_created;
struct mutex update_lock;
struct completion ov_comp;
@@ -159,6 +162,7 @@
}
static void mdp4_dtv_blt_ov_update(struct mdp4_overlay_pipe *pipe);
+static void mdp4_dtv_wait4ov(int cndx);
static void mdp4_dtv_wait4dmae(int cndx);
int mdp4_dtv_pipe_commit(int cndx, int wait)
@@ -191,6 +195,13 @@
vctrl->update_ndx++;
vctrl->update_ndx &= 0x01;
vp->update_cnt = 0; /* reset */
+
+ if (vctrl->blt_free) {
+ vctrl->blt_free--;
+ if (vctrl->blt_free == 0)
+ mdp4_free_writeback_buf(vctrl->mfd, mixer);
+ }
+
mutex_unlock(&vctrl->update_lock);
pipe = vp->plist;
@@ -220,6 +231,7 @@
if (pipe->ov_blt_addr) {
mdp4_dtv_blt_ov_update(pipe);
pipe->blt_ov_done++;
+ INIT_COMPLETION(vctrl->ov_comp);
vsync_irq_enable(INTR_OVERLAY1_DONE, MDP_OVERLAY1_TERM);
mb();
pipe->blt_ov_koff++;
@@ -234,9 +246,12 @@
spin_unlock_irqrestore(&vctrl->spin_lock, flags);
mdp4_stat.overlay_commit[pipe->mixer_num]++;
- if (wait)
- mdp4_dtv_wait4dmae(cndx);
-
+ if (wait) {
+ if (pipe->ov_blt_addr)
+ mdp4_dtv_wait4ov(cndx);
+ else
+ mdp4_dtv_wait4dmae(cndx);
+ }
return cnt;
}
@@ -296,6 +311,23 @@
*vtime = ktime_to_ns(vctrl->vsync_time);
}
+static void mdp4_dtv_wait4ov(int cndx)
+{
+ struct vsycn_ctrl *vctrl;
+
+ if (cndx >= MAX_CONTROLLER) {
+ pr_err("%s: out or range: cndx=%d\n", __func__, cndx);
+ return;
+ }
+
+ vctrl = &vsync_ctrl_db[cndx];
+
+ if (atomic_read(&vctrl->suspend) > 0)
+ return;
+
+ wait_for_completion(&vctrl->ov_comp);
+}
+
static void mdp4_dtv_wait4dmae(int cndx)
{
struct vsycn_ctrl *vctrl;
@@ -367,6 +399,28 @@
return ret;
}
+static void mdp4_dtv_wait4dmae_done(int cndx)
+{
+ unsigned long flags;
+ struct vsycn_ctrl *vctrl;
+
+ if (cndx >= MAX_CONTROLLER) {
+ pr_err("%s: out or range: cndx=%d\n", __func__, cndx);
+ return;
+ }
+
+ vctrl = &vsync_ctrl_db[cndx];
+
+ if (atomic_read(&vctrl->suspend) > 0)
+ return;
+
+ spin_lock_irqsave(&vctrl->spin_lock, flags);
+ INIT_COMPLETION(vctrl->dmae_comp);
+ vsync_irq_enable(INTR_DMA_E_DONE, MDP_DMA_E_TERM);
+ spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+ mdp4_dtv_wait4dmae(cndx);
+}
+
void mdp4_dtv_vsync_init(int cndx)
{
struct vsycn_ctrl *vctrl;
@@ -554,6 +608,7 @@
/* enable DTV block */
MDP_OUTP(MDP_BASE + DTV_BASE, 1);
+ dtv_enabled = 1;
return 0;
}
@@ -568,6 +623,7 @@
return -EINVAL;
MDP_OUTP(MDP_BASE + DTV_BASE, 0);
+ dtv_enabled = 0;
return 0;
}
@@ -578,6 +634,7 @@
int ret = 0;
int cndx = 0;
struct vsycn_ctrl *vctrl;
+ struct msm_panel_info *pinfo;
vctrl = &vsync_ctrl_db[cndx];
@@ -589,7 +646,12 @@
if (mfd->key != MFD_KEY)
return -EINVAL;
+ vctrl->mfd = mfd;
vctrl->dev = mfd->fbi->dev;
+ pinfo = &mfd->panel_info;
+
+ vctrl->blt_ctrl = pinfo->lcd.blt_ctrl;
+ vctrl->blt_mode = pinfo->lcd.blt_mode;
mdp_footswitch_ctrl(TRUE);
/* Mdp clock enable */
@@ -673,7 +735,7 @@
if (vctrl->vsync_irq_enabled) {
vctrl->vsync_irq_enabled = 0;
- vsync_irq_disable(INTR_PRIMARY_VSYNC, MDP_PRIM_VSYNC_TERM);
+ vsync_irq_disable(INTR_EXTERNAL_VSYNC, MDP_EXTER_VSYNC_TERM);
}
undx = vctrl->update_ndx;
@@ -748,11 +810,6 @@
MDP_OUTP(MDP_BASE + 0xb0008, addr);
}
-void mdp4_overlay_dtv_set_perf(struct msm_fb_data_type *mfd)
-{
-
-}
-
static void mdp4_overlay_dtv_alloc_pipe(struct msm_fb_data_type *mfd,
int32 ptype, struct vsycn_ctrl *vctrl)
{
@@ -940,18 +997,8 @@
spin_lock(&vctrl->spin_lock);
if (vctrl->blt_change) {
- if (pipe->ov_blt_addr) {
- mdp4_overlayproc_cfg(pipe);
- mdp4_overlay_dmae_xy(pipe);
- mdp4_dtv_blt_ov_update(pipe);
- pipe->blt_ov_done++;
-
- /* Prefill one frame */
- vsync_irq_enable(INTR_OVERLAY1_DONE, MDP_OVERLAY1_TERM);
- /* kickoff overlay1 engine */
- mdp4_stat.kickoff_ov1++;
- outpdw(MDP_BASE + 0x0008, 0);
- }
+ mdp4_overlayproc_cfg(pipe);
+ mdp4_overlay_dmae_xy(pipe);
vctrl->blt_change = 0;
}
@@ -986,6 +1033,7 @@
}
mdp4_dtv_blt_dmae_update(pipe);
+ complete_all(&vctrl->ov_comp);
pipe->blt_dmap_done++;
vsync_irq_disable(INTR_OVERLAY1_DONE, MDP_OVERLAY1_TERM);
spin_unlock(&vctrl->spin_lock);
@@ -1039,63 +1087,100 @@
static void mdp4_dtv_do_blt(struct msm_fb_data_type *mfd, int enable)
{
unsigned long flag;
- int data;
int cndx = 0;
struct vsycn_ctrl *vctrl;
struct mdp4_overlay_pipe *pipe;
+ u32 mode, ctrl;
vctrl = &vsync_ctrl_db[cndx];
pipe = vctrl->base_pipe;
- mdp4_allocate_writeback_buf(mfd, MDP4_MIXER1);
+ mode = (dbg_force_ov1_blt & 0x0f) ?
+ (dbg_force_ov1_blt & 0x0f) : vctrl->blt_mode;
+ ctrl = (dbg_force_ov1_blt >> 4) ?
+ (dbg_force_ov1_blt >> 4) : vctrl->blt_ctrl;
- if (!mfd->ov1_wb_buf->write_addr) {
- pr_info("%s: ctrl=%d blt_base NOT assigned\n", __func__, cndx);
+ pr_debug("%s: mode=%d, ctrl = %d, enable=%d ov_blt_addr=%x\n",
+ __func__, mode, ctrl, enable, (int)pipe->ov_blt_addr);
+
+ if ((mode == MDP4_OVERLAY_MODE_BLT_ALWAYS_OFF) &&
+ !pipe->ov_blt_addr)
return;
+ else if ((mode == MDP4_OVERLAY_MODE_BLT_ALWAYS_ON) &&
+ pipe->ov_blt_addr)
+ return;
+ else if (enable && pipe->ov_blt_addr)
+ return;
+ else if (!enable && !pipe->ov_blt_addr)
+ return;
+
+ if (pipe->ov_blt_addr == 0) {
+ mdp4_allocate_writeback_buf(vctrl->mfd, MDP4_MIXER1);
+ if (!vctrl->mfd->ov1_wb_buf->write_addr) {
+ pr_warning("%s: ctrl=%d blt_base NOT assigned\n",
+ __func__, cndx);
+ return;
+ }
}
+ pr_debug("%s: mode=%d, ctrl=%d, enable=%d ov_blt_addr=%x\n",
+ __func__, mode, ctrl, enable, (int)pipe->ov_blt_addr);
+
spin_lock_irqsave(&vctrl->spin_lock, flag);
if (enable && pipe->ov_blt_addr == 0) {
- pipe->ov_blt_addr = mfd->ov1_wb_buf->write_addr;
- pipe->dma_blt_addr = mfd->ov1_wb_buf->read_addr;
+ pipe->ov_blt_addr = vctrl->mfd->ov1_wb_buf->write_addr;
+ pipe->dma_blt_addr = vctrl->mfd->ov1_wb_buf->read_addr;
pipe->blt_cnt = 0;
pipe->ov_cnt = 0;
pipe->blt_dmap_done = 0;
pipe->blt_ov_koff = 0;
pipe->blt_ov_done = 0;
mdp4_stat.blt_dtv++;
- vctrl->blt_change++;
+ vctrl->blt_free = 0;
} else if (enable == 0 && pipe->ov_blt_addr) {
pipe->ov_blt_addr = 0;
pipe->dma_blt_addr = 0;
- vctrl->blt_change++;
+ vctrl->blt_free = 4;
}
-
- pr_info("%s: enable=%d change=%d blt_addr=%x\n", __func__,
- enable, vctrl->blt_change, (int)pipe->ov_blt_addr);
-
- if (!vctrl->blt_change) {
- spin_unlock_irqrestore(&vctrl->spin_lock, flag);
- return;
- }
-
- atomic_set(&vctrl->suspend, 1);
spin_unlock_irqrestore(&vctrl->spin_lock, flag);
- data = inpdw(MDP_BASE + DTV_BASE);
- data &= 0x01;
- if (data) /* timing generator enabled */
- mdp4_dtv_wait4dmae(0);
+ if (ctrl == MDP4_OVERLAY_BLT_SWITCH_TG_ON) {
+ spin_lock_irqsave(&vctrl->spin_lock, flag);
+ if (!dtv_enabled) {
+ pr_debug("%s: blt switched not in isr dtv_enabled=%d\n",
+ __func__, dtv_enabled);
+ mdp4_overlayproc_cfg(pipe);
+ mdp4_overlay_dmae_xy(pipe);
+ } else {
+ pr_debug("%s: blt switched in ISR dtv_enabled=%d\n",
+ __func__, dtv_enabled);
+ vctrl->blt_change++;
- if (pipe->ov_blt_addr == 0) {
- MDP_OUTP(MDP_BASE + DTV_BASE, 0); /* stop dtv */
- msleep(20);
+ }
+ spin_unlock_irqrestore(&vctrl->spin_lock, flag);
+ if (dtv_enabled)
+ mdp4_dtv_wait4dmae_done(0);
+ } else if (ctrl == MDP4_OVERLAY_BLT_SWITCH_TG_OFF) {
+ pr_debug("%s: dtv blt switched by turning TG off\n",
+ __func__);
+ if (dtv_enabled) {
+ mdp4_dtv_wait4dmae_done(0);
+ MDP_OUTP(MDP_BASE + DTV_BASE, 0);
+ msleep(20);
+ }
mdp4_overlayproc_cfg(pipe);
mdp4_overlay_dmae_xy(pipe);
- MDP_OUTP(MDP_BASE + DTV_BASE, 1); /* start dtv */
- }
-
- atomic_set(&vctrl->suspend, 0);
+ if (dtv_enabled)
+ MDP_OUTP(MDP_BASE + DTV_BASE, 1);
+ } else if (ctrl == MDP4_OVERLAY_BLT_SWITCH_POLL) {
+ pr_debug("%s: dtv blt change by polling status\n",
+ __func__);
+ while (inpdw(MDP_BASE + 0x0018) & 0x12)
+ cpu_relax();
+ mdp4_overlayproc_cfg(pipe);
+ mdp4_overlay_dmae_xy(pipe);
+ } else
+ pr_err("%s: ctrl=%d is not supported\n", __func__, ctrl);
}
void mdp4_dtv_overlay_blt_start(struct msm_fb_data_type *mfd)
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index ee9ca3c..b6c2634 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -454,8 +454,6 @@
clk_rate = mdp_get_core_clk();
mdp4_fetch_cfg(clk_rate);
- mdp4_overlay_cfg_init();
-
/* Mark hardware as initialized. Only revisions > v2.1 have a register
* for tracking core reset status. */
if (mdp_hw_revision > MDP4_REVISION_V2_1)
diff --git a/drivers/video/msm/mdss/Makefile b/drivers/video/msm/mdss/Makefile
index 88a7c45..a0d707e 100644
--- a/drivers/video/msm/mdss/Makefile
+++ b/drivers/video/msm/mdss/Makefile
@@ -7,6 +7,7 @@
mdss-mdp-objs += mdss_mdp_wb.o
obj-$(CONFIG_FB_MSM_MDSS) += mdss-mdp.o
obj-$(CONFIG_FB_MSM_MDSS) += mdss_fb.o
+obj-$(CONFIG_DEBUG_FS) += mdss_debug.o
mdss-dsi-objs := mdss_dsi.o mdss_dsi_host.o
mdss-dsi-objs += mdss_dsi_panel.o
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index d041125..9e13418 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -61,6 +61,7 @@
struct delayed_work clk_ctrl_worker;
struct platform_device *pdev;
char __iomem *mdp_base;
+ size_t mdp_reg_size;
char __iomem *vbif_base;
u32 irq;
@@ -93,6 +94,7 @@
struct mdss_iommu_map_type *iommu_map;
struct early_suspend early_suspend;
+ void *debug_data;
};
extern struct mdss_data_type *mdss_res;
diff --git a/drivers/video/msm/mdss/mdss_debug.c b/drivers/video/msm/mdss/mdss_debug.c
new file mode 100644
index 0000000..abef27d
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_debug.c
@@ -0,0 +1,348 @@
+/* Copyright (c) 2009-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/debugfs.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/printk.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+#include "mdss.h"
+#include "mdss_mdp.h"
+#include "mdss_debug.h"
+
+#define DEFAULT_BASE_REG_CNT 128
+#define GROUP_BYTES 4
+#define ROW_BYTES 16
+
+struct mdss_debug_data {
+ struct dentry *root;
+ struct list_head base_list;
+};
+
+struct mdss_debug_base {
+ struct mdss_debug_data *mdd;
+ void __iomem *base;
+ size_t off;
+ size_t cnt;
+ size_t max_offset;
+ char *buf;
+ size_t buf_len;
+ struct list_head head;
+};
+
+static int mdss_debug_base_open(struct inode *inode, struct file *file)
+{
+ /* non-seekable */
+ file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static int mdss_debug_base_release(struct inode *inode, struct file *file)
+{
+ struct mdss_debug_base *dbg = file->private_data;
+ if (dbg && dbg->buf) {
+ kfree(dbg->buf);
+ dbg->buf_len = 0;
+ dbg->buf = NULL;
+ }
+ return 0;
+}
+
+static ssize_t mdss_debug_base_offset_write(struct file *file,
+ const char __user *user_buf, size_t count, loff_t *ppos)
+{
+ struct mdss_debug_base *dbg = file->private_data;
+ u32 off, cnt;
+ char buf[24];
+
+ if (!dbg)
+ return -ENODEV;
+
+ if (count >= sizeof(buf))
+ return -EFAULT;
+
+ if (copy_from_user(buf, user_buf, count))
+ return -EFAULT;
+
+ buf[count] = 0; /* end of string */
+
+ sscanf(buf, "%5x %d", &off, &cnt);
+
+ if (off > dbg->max_offset)
+ return -EINVAL;
+
+ if (cnt <= 0)
+ cnt = DEFAULT_BASE_REG_CNT;
+
+ if (cnt > (dbg->max_offset - off))
+ cnt = dbg->max_offset - off;
+
+ dbg->off = off;
+ dbg->cnt = cnt;
+
+ pr_debug("offset=%x cnt=%x\n", off, cnt);
+
+ return count;
+}
+
+static ssize_t mdss_debug_base_offset_read(struct file *file,
+ char __user *buff, size_t count, loff_t *ppos)
+{
+ struct mdss_debug_base *dbg = file->private_data;
+ int len = 0;
+ char buf[24];
+
+ if (!dbg)
+ return -ENODEV;
+
+ if (*ppos)
+ return 0; /* the end */
+
+ len = snprintf(buf, sizeof(buf), "0x%08x %d\n", dbg->off, dbg->off);
+ if (len < 0)
+ return 0;
+
+ if (copy_to_user(buff, buf, len))
+ return -EFAULT;
+
+ *ppos += len; /* increase offset */
+
+ return len;
+}
+
+static ssize_t mdss_debug_base_reg_write(struct file *file,
+ const char __user *user_buf, size_t count, loff_t *ppos)
+{
+ struct mdss_debug_base *dbg = file->private_data;
+ size_t off;
+ u32 data, cnt;
+ char buf[24];
+
+ if (!dbg)
+ return -ENODEV;
+
+ if (count >= sizeof(buf))
+ return -EFAULT;
+
+ if (copy_from_user(buf, user_buf, count))
+ return -EFAULT;
+
+ buf[count] = 0; /* end of string */
+
+ cnt = sscanf(buf, "%x %x", &off, &data);
+
+ if (cnt < 2)
+ return -EFAULT;
+
+ if (off >= dbg->max_offset)
+ return -EFAULT;
+
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ writel_relaxed(data, dbg->base + off);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+ pr_debug("addr=%x data=%x\n", off, data);
+
+ return count;
+}
+
+static ssize_t mdss_debug_base_reg_read(struct file *file,
+ char __user *user_buf, size_t count, loff_t *ppos)
+{
+ struct mdss_debug_base *dbg = file->private_data;
+ size_t len;
+
+ if (!dbg) {
+ pr_err("invalid handle\n");
+ return -ENODEV;
+ }
+
+ if (!dbg->buf) {
+ char dump_buf[64];
+ char *ptr;
+ int cnt, tot;
+
+ dbg->buf_len = sizeof(dump_buf) *
+ DIV_ROUND_UP(dbg->cnt, ROW_BYTES);
+ dbg->buf = kzalloc(dbg->buf_len, GFP_KERNEL);
+
+ if (!dbg->buf) {
+ pr_err("not enough memory to hold reg dump\n");
+ return -ENOMEM;
+ }
+
+ ptr = dbg->base + dbg->off;
+ tot = 0;
+
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ for (cnt = dbg->cnt; cnt > 0; cnt -= ROW_BYTES) {
+ hex_dump_to_buffer(ptr, min(cnt, ROW_BYTES),
+ ROW_BYTES, GROUP_BYTES, dump_buf,
+ sizeof(dump_buf), false);
+ len = scnprintf(dbg->buf + tot, dbg->buf_len - tot,
+ "0x%08x: %s\n",
+ ((int)ptr) - ((int)dbg->base),
+ dump_buf);
+
+ ptr += ROW_BYTES;
+ tot += len;
+ if (tot >= dbg->buf_len)
+ break;
+ }
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+ dbg->buf_len = tot;
+ }
+
+ if (*ppos >= dbg->buf_len)
+ return 0; /* done reading */
+
+ len = min(count, dbg->buf_len - (size_t) *ppos);
+ if (copy_to_user(user_buf, dbg->buf + *ppos, len)) {
+ pr_err("failed to copy to user\n");
+ return -EFAULT;
+ }
+
+ *ppos += len; /* increase offset */
+
+ return len;
+}
+
+static const struct file_operations mdss_off_fops = {
+ .open = mdss_debug_base_open,
+ .release = mdss_debug_base_release,
+ .read = mdss_debug_base_offset_read,
+ .write = mdss_debug_base_offset_write,
+};
+
+static const struct file_operations mdss_reg_fops = {
+ .open = mdss_debug_base_open,
+ .release = mdss_debug_base_release,
+ .read = mdss_debug_base_reg_read,
+ .write = mdss_debug_base_reg_write,
+};
+
+int mdss_debug_register_base(const char *name, void __iomem *base,
+ size_t max_offset)
+{
+ struct mdss_data_type *mdata = mdss_res;
+ struct mdss_debug_data *mdd;
+ struct mdss_debug_base *dbg;
+ struct dentry *ent_off, *ent_reg;
+ char dn[80] = "";
+ int prefix_len = 0;
+
+ if (!mdata || !mdata->debug_data)
+ return -ENODEV;
+
+ mdd = mdata->debug_data;
+
+ dbg = kzalloc(sizeof(*dbg), GFP_KERNEL);
+ if (!dbg)
+ return -ENOMEM;
+
+ dbg->base = base;
+ dbg->max_offset = max_offset;
+ dbg->off = 0;
+ dbg->cnt = DEFAULT_BASE_REG_CNT;
+
+ if (name)
+ prefix_len = snprintf(dn, sizeof(dn), "%s_", name);
+
+ strlcpy(dn + prefix_len, "off", sizeof(dn) - prefix_len);
+ ent_off = debugfs_create_file(dn, 0644, mdd->root, dbg, &mdss_off_fops);
+ if (IS_ERR_OR_NULL(ent_off)) {
+ pr_err("debugfs_create_file: offset fail\n");
+ goto off_fail;
+ }
+
+ strlcpy(dn + prefix_len, "reg", sizeof(dn) - prefix_len);
+ ent_reg = debugfs_create_file(dn, 0644, mdd->root, dbg, &mdss_reg_fops);
+ if (IS_ERR_OR_NULL(ent_reg)) {
+ pr_err("debugfs_create_file: reg fail\n");
+ goto reg_fail;
+ }
+
+ list_add(&dbg->head, &mdd->base_list);
+
+ return 0;
+reg_fail:
+ debugfs_remove(ent_off);
+off_fail:
+ kfree(dbg);
+ return -ENODEV;
+}
+
+static int mdss_debugfs_cleanup(struct mdss_debug_data *mdd)
+{
+ struct mdss_debug_base *base, *tmp;
+
+ if (!mdd)
+ return 0;
+
+ list_for_each_entry_safe(base, tmp, &mdd->base_list, head) {
+ list_del(&base->head);
+ kfree(base);
+ }
+
+ if (mdd->root)
+ debugfs_remove_recursive(mdd->root);
+
+ kfree(mdd);
+
+ return 0;
+}
+
+int mdss_debugfs_init(struct mdss_data_type *mdata)
+{
+ struct mdss_debug_data *mdd;
+
+ if (mdata->debug_data) {
+ pr_warn("mdss debugfs already initialized\n");
+ return -EBUSY;
+ }
+
+ mdd = kzalloc(sizeof(*mdd), GFP_KERNEL);
+ if (!mdd) {
+ pr_err("no memory to create mdss debug data\n");
+ return -ENOMEM;
+ }
+ INIT_LIST_HEAD(&mdd->base_list);
+
+ mdd->root = debugfs_create_dir("mdp", NULL);
+ if (IS_ERR_OR_NULL(mdd->root)) {
+ pr_err("debugfs_create_dir fail, error %ld\n",
+ PTR_ERR(mdd->root));
+ mdd->root = NULL;
+ mdss_debugfs_cleanup(mdd);
+ return -ENODEV;
+ }
+
+ mdata->debug_data = mdd;
+
+ return 0;
+}
+
+int mdss_debugfs_remove(struct mdss_data_type *mdata)
+{
+ struct mdss_debug_data *mdd = mdata->debug_data;
+
+ mdss_debugfs_cleanup(mdd);
+
+ return 0;
+}
diff --git a/drivers/video/msm/mdss/mdss_debug.h b/drivers/video/msm/mdss/mdss_debug.h
new file mode 100644
index 0000000..167fa8a
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_debug.h
@@ -0,0 +1,39 @@
+/* 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 MDSS_DEBUG_H
+#define MDSS_DEBUG_H
+
+#include "mdss.h"
+
+#ifdef CONFIG_DEBUG_FS
+int mdss_debugfs_init(struct mdss_data_type *mdata);
+int mdss_debugfs_remove(struct mdss_data_type *mdata);
+int mdss_debug_register_base(const char *name, void __iomem *base,
+ size_t max_offset);
+#else
+static inline int mdss_debugfs_init(struct mdss_data_type *mdata)
+{
+ return 0;
+}
+static inline int mdss_debugfs_remove(struct mdss_data_type *mdata)
+{
+ return 0;
+}
+static inline int mdss_debug_register_base(const char *name, void __iomem *base,
+ size_t max_offset)
+{
+ return 0;
+}
+#endif
+#endif /* MDSS_DEBUG_H */
diff --git a/drivers/video/msm/mdss/mdss_edp.c b/drivers/video/msm/mdss/mdss_edp.c
index 1cf3101..227619f 100644
--- a/drivers/video/msm/mdss/mdss_edp.c
+++ b/drivers/video/msm/mdss/mdss_edp.c
@@ -303,10 +303,10 @@
}
mdss_edp_prepare_clocks(edp_drv);
- mdss_edp_clk_enable(edp_drv);
mdss_edp_phy_sw_reset(edp_drv->edp_base);
mdss_edp_hw_powerup(edp_drv->edp_base, 1);
mdss_edp_pll_configure(edp_drv->edp_base, edp_drv->edid.timing[0].pclk);
+ mdss_edp_clk_enable(edp_drv);
for (i = 0; i < edp_drv->dpcd.max_lane_count; ++i)
mdss_edp_enable_lane_bist(edp_drv->edp_base, i, 1);
@@ -346,8 +346,8 @@
for (i = 0; i < edp_drv->dpcd.max_lane_count; ++i)
mdss_edp_enable_lane_bist(edp_drv->edp_base, i, 0);
- mdss_edp_hw_powerup(edp_drv->edp_base, 0);
mdss_edp_clk_disable(edp_drv);
+ mdss_edp_hw_powerup(edp_drv->edp_base, 0);
mdss_edp_unprepare_clocks(edp_drv);
return ret;
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 4ec4046..f363206 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -131,8 +131,8 @@
/* This maps android backlight level 0 to 255 into
driver backlight level 0 to bl_max with rounding */
- bl_lvl = (2 * value * mfd->panel_info.bl_max + MAX_BACKLIGHT_BRIGHTNESS)
- /(2 * MAX_BACKLIGHT_BRIGHTNESS);
+ bl_lvl = (2 * value * mfd->panel_info->bl_max +
+ MAX_BACKLIGHT_BRIGHTNESS) / (2 * MAX_BACKLIGHT_BRIGHTNESS);
if (!bl_lvl && value)
bl_lvl = 1;
@@ -155,7 +155,7 @@
struct fb_info *fbi = dev_get_drvdata(dev);
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
- switch (mfd->panel_info.type) {
+ switch (mfd->panel.type) {
case NO_PANEL:
ret = snprintf(buf, PAGE_SIZE, "no panel\n");
break;
@@ -239,13 +239,13 @@
mfd = (struct msm_fb_data_type *)fbi->par;
mfd->key = MFD_KEY;
mfd->fbi = fbi;
- mfd->panel_info = pdata->panel_info;
+ mfd->panel_info = &pdata->panel_info;
mfd->panel.type = pdata->panel_info.type;
mfd->panel.id = mfd->index;
mfd->fb_page = MDSS_FB_NUM;
mfd->index = fbi_list_index;
mfd->mdp_fb_page_protection = MDP_FB_PAGE_PROTECTION_WRITECOMBINE;
- mfd->panel_info.frame_count = 0;
+
mfd->bl_level = 0;
mfd->bl_scale = 1024;
mfd->bl_min_lvl = 30;
@@ -263,14 +263,6 @@
if (rc)
return rc;
- /*
- * todo: Currently mfd keeps a full copy of panel data rather than
- * pointer to it.
- * Following line shares the fbi with panel drivers for their
- * sysfs or any external communications with the panel driver.
- */
- pdata->panel_info.fbi = fbi;
-
rc = pm_runtime_set_active(mfd->fbi->dev);
if (rc < 0)
pr_err("pm_runtime: fail to set active.\n");
@@ -439,52 +431,11 @@
return result;
}
-#if defined(CONFIG_PM) && defined(CONFIG_SUSPEND)
-static int mdss_fb_ext_suspend(struct device *dev)
-{
- struct msm_fb_data_type *mfd = dev_get_drvdata(dev);
- int ret = 0;
-
- if ((!mfd) || (mfd->key != MFD_KEY))
- return 0;
-
- if (mfd->panel_info.type == HDMI_PANEL ||
- mfd->panel_info.type == DTV_PANEL)
- ret = mdss_fb_suspend_sub(mfd);
-
- return ret;
-}
-
-static int mdss_fb_ext_resume(struct device *dev)
-{
- struct msm_fb_data_type *mfd = dev_get_drvdata(dev);
- int ret = 0;
-
- if ((!mfd) || (mfd->key != MFD_KEY))
- return 0;
-
- if (mfd->panel_info.type == HDMI_PANEL ||
- mfd->panel_info.type == DTV_PANEL)
- ret = mdss_fb_resume_sub(mfd);
-
- return ret;
-}
-#else
-#define mdss_fb_ext_suspend NULL
-#define mdss_fb_ext_resume NULL
-#endif
-
-static const struct dev_pm_ops mdss_fb_dev_pm_ops = {
- .suspend = mdss_fb_ext_suspend,
- .resume = mdss_fb_ext_resume,
-};
-
static struct platform_driver mdss_fb_driver = {
.probe = mdss_fb_probe,
.remove = mdss_fb_remove,
.driver = {
.name = "mdss_fb",
- .pm = &mdss_fb_dev_pm_ops,
},
};
@@ -716,9 +667,9 @@
void *virt = NULL;
unsigned long phys = 0;
size_t size;
+ u32 yres = mfd->fbi->var.yres_virtual;
- size = PAGE_ALIGN(mfd->fbi->fix.line_length * mfd->panel_info.yres);
- size *= mfd->fb_page;
+ size = PAGE_ALIGN(mfd->fbi->fix.line_length * yres);
if (mfd->index == 0) {
int dom;
@@ -751,7 +702,7 @@
{
int ret = -ENODEV;
int bpp;
- struct mdss_panel_info *panel_info = &mfd->panel_info;
+ struct mdss_panel_info *panel_info = mfd->panel_info;
struct fb_info *fbi = mfd->fbi;
struct fb_fix_screeninfo *fix;
struct fb_var_screeninfo *var;
@@ -1050,8 +1001,6 @@
mfd->panel.type);
mdss_fb_update_backlight(mfd);
-
- ++mfd->panel_info.frame_count;
return 0;
}
@@ -1147,8 +1096,8 @@
if ((var->xres == 0) || (var->yres == 0))
return -EINVAL;
- if ((var->xres > mfd->panel_info.xres) ||
- (var->yres > mfd->panel_info.yres))
+ if ((var->xres > mfd->panel_info->xres) ||
+ (var->yres > mfd->panel_info->yres))
return -EINVAL;
if (var->xoffset > (var->xres_virtual - var->xres))
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index b760388..b7bd4e6 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -55,7 +55,7 @@
u32 fb_page;
struct panel_id panel;
- struct mdss_panel_info panel_info;
+ struct mdss_panel_info *panel_info;
u32 dest;
struct fb_info *fbi;
@@ -64,6 +64,9 @@
u32 fb_imgType;
u32 dst_format;
int vsync_pending;
+ ktime_t vsync_time;
+ struct completion vsync_comp;
+ spinlock_t vsync_lock;
int hw_refresh;
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index bcb3aee..b59d193 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -49,6 +49,7 @@
#include "mdss.h"
#include "mdss_fb.h"
#include "mdss_mdp.h"
+#include "mdss_debug.h"
struct mdss_data_type *mdss_res;
@@ -772,6 +773,19 @@
return 0;
}
+static int mdss_mdp_debug_init(struct mdss_data_type *mdata)
+{
+ int rc;
+
+ rc = mdss_debugfs_init(mdata);
+ if (rc)
+ return rc;
+
+ mdss_debug_register_base(NULL, mdata->mdp_base, mdata->mdp_reg_size);
+
+ return 0;
+}
+
static int mdss_hw_init(struct mdss_data_type *mdata)
{
char *base = mdata->vbif_base;
@@ -875,8 +889,9 @@
goto probe_done;
}
+ mdata->mdp_reg_size = resource_size(res);
mdata->mdp_base = devm_ioremap(&pdev->dev, res->start,
- resource_size(res));
+ mdata->mdp_reg_size);
if (unlikely(!mdata->mdp_base)) {
pr_err("unable to map MDP base\n");
rc = -ENOMEM;
@@ -933,6 +948,11 @@
pr_err("unable to register early suspend\n");
goto probe_done;
}
+
+ rc = mdss_mdp_debug_init(mdata);
+ if (rc)
+ pr_err("unable to initialize mdp debugging\n");
+
probe_done:
if (IS_ERR_VALUE(rc)) {
mdss_res = NULL;
@@ -1099,6 +1119,7 @@
mdss_mdp_pp_term(&pdev->dev);
mdss_mdp_bus_scale_unregister(mdata);
mdss_mdp_remove_early_suspend(mdata);
+ mdss_debugfs_remove(mdata);
return 0;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 2e92591..157a7eb 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -137,6 +137,8 @@
struct mdss_mdp_mixer *mixer_right;
struct mutex lock;
+ struct mdss_panel_data *panel_data;
+
int (*start_fnc) (struct mdss_mdp_ctl *ctl);
int (*stop_fnc) (struct mdss_mdp_ctl *ctl);
int (*prepare_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 00f5874..bd7371b 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -107,7 +107,7 @@
int is_writeback = false;
if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) {
struct mdss_panel_info *pinfo;
- pinfo = &mixer->ctl->mfd->panel_info;
+ pinfo = &mixer->ctl->panel_data->panel_info;
v_total = (pinfo->yres + pinfo->lcdc.v_back_porch +
pinfo->lcdc.v_front_porch +
pinfo->lcdc.v_pulse_width);
@@ -378,12 +378,19 @@
static int mdss_mdp_ctl_init(struct msm_fb_data_type *mfd)
{
struct mdss_mdp_ctl *ctl;
+ struct mdss_panel_data *pdata;
u32 width, height;
int ret = 0;
if (!mfd)
return -ENODEV;
+ pdata = dev_get_platdata(&mfd->pdev->dev);
+ if (!pdata) {
+ pr_err("no panel connected for fb%d\n", mfd->index);
+ return -ENODEV;
+ }
+
width = mfd->fbi->var.xres;
height = mfd->fbi->var.yres;
@@ -400,6 +407,7 @@
}
ctl->mfd = mfd;
mfd->ctl = ctl;
+ ctl->panel_data = pdata;
} else {
ctl = mfd->ctl;
}
@@ -441,7 +449,7 @@
mdss_mdp_mixer_free(ctl->mixer_right);
}
- switch (mfd->panel_info.type) {
+ switch (pdata->panel_info.type) {
case EDP_PANEL:
ctl->intf_num = MDSS_MDP_INTF0;
ctl->intf_type = MDSS_INTF_EDP;
@@ -449,7 +457,7 @@
ctl->start_fnc = mdss_mdp_video_start;
break;
case MIPI_VIDEO_PANEL:
- if (mfd->panel_info.pdest == DISPLAY_1)
+ if (pdata->panel_info.pdest == DISPLAY_1)
ctl->intf_num = MDSS_MDP_INTF1;
else
ctl->intf_num = MDSS_MDP_INTF2;
@@ -469,7 +477,7 @@
ctl->start_fnc = mdss_mdp_writeback_start;
break;
default:
- pr_err("unsupported panel type (%d)\n", mfd->panel_info.type);
+ pr_err("unsupported panel type (%d)\n", pdata->panel_info.type);
ret = -EINVAL;
goto ctl_init_fail;
}
@@ -477,14 +485,14 @@
ctl->opmode |= (ctl->intf_num << 4);
if (ctl->intf_num == MDSS_MDP_NO_INTF) {
- ctl->dst_format = mfd->panel_info.out_format;
+ ctl->dst_format = pdata->panel_info.out_format;
} else {
struct mdp_dither_cfg_data dither = {
.block = mfd->index + MDP_LOGICAL_BLOCK_DISP_0,
.flags = MDP_PP_OPS_DISABLE,
};
- switch (mfd->panel_info.bpp) {
+ switch (pdata->panel_info.bpp) {
case 18:
ctl->dst_format = MDSS_MDP_PANEL_FORMAT_RGB666;
dither.flags = MDP_PP_OPS_ENABLE | MDP_PP_OPS_WRITE;
@@ -539,14 +547,10 @@
int mdss_mdp_ctl_intf_event(struct mdss_mdp_ctl *ctl, int event, void *arg)
{
struct mdss_panel_data *pdata;
- if (!ctl || !ctl->mfd)
+ if (!ctl || !ctl->panel_data)
return -ENODEV;
- pdata = dev_get_platdata(&ctl->mfd->pdev->dev);
- if (!pdata) {
- pr_err("no panel connected\n");
- return -ENODEV;
- }
+ pdata = ctl->panel_data;
pr_debug("sending ctl=%d event=%d\n", ctl->num, event);
@@ -596,7 +600,7 @@
ret = ctl->start_fnc(ctl);
else
pr_warn("no start function for ctl=%d type=%d\n", ctl->num,
- mfd->panel_info.type);
+ ctl->panel_data->panel_info.type);
if (ret) {
pr_err("unable to start intf\n");
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index 9508846..4757c63 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.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
@@ -13,8 +13,6 @@
#define pr_fmt(fmt) "%s: " fmt, __func__
-#include <linux/workqueue.h>
-
#include "mdss_fb.h"
#include "mdss_mdp.h"
@@ -39,7 +37,6 @@
#define MAX_SESSIONS 3
struct mdss_mdp_video_ctx {
- u32 ctl_num;
u32 pp_num;
u8 ref_cnt;
@@ -47,11 +44,9 @@
struct completion pp_comp;
struct completion vsync_comp;
- struct mutex vsync_lock;
- struct work_struct vsync_work;
+ atomic_t vsync_ref;
+ spinlock_t vsync_lock;
mdp_vsync_handler_t vsync_handler;
- void *vsync_ptr;
- ktime_t vsync_time;
};
struct mdss_mdp_video_ctx mdss_mdp_video_ctx_list[MAX_SESSIONS];
@@ -157,43 +152,43 @@
return 0;
}
-static void send_vsync_work(struct work_struct *work)
-{
- struct mdss_mdp_video_ctx *ctx;
- ctx = container_of(work, typeof(*ctx), vsync_work);
- mutex_lock(&ctx->vsync_lock);
- if (ctx->vsync_handler)
- ctx->vsync_handler(ctx->vsync_ptr, ctx->vsync_time);
- mutex_unlock(&ctx->vsync_lock);
+static inline void video_vsync_irq_enable(struct mdss_mdp_ctl *ctl)
+{
+ struct mdss_mdp_video_ctx *ctx = ctl->priv_data;
+
+ if (atomic_inc_return(&ctx->vsync_ref) == 1)
+ mdss_mdp_irq_enable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
+}
+
+static inline void video_vsync_irq_disable(struct mdss_mdp_ctl *ctl)
+{
+ struct mdss_mdp_video_ctx *ctx = ctl->priv_data;
+
+ if (atomic_dec_return(&ctx->vsync_ref) == 0)
+ mdss_mdp_irq_disable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
}
static int mdss_mdp_video_set_vsync_handler(struct mdss_mdp_ctl *ctl,
mdp_vsync_handler_t vsync_handler)
{
struct mdss_mdp_video_ctx *ctx;
+ unsigned long flags;
ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data;
if (!ctx) {
pr_err("invalid ctx for ctl=%d\n", ctl->num);
return -ENODEV;
}
- if (mutex_lock_interruptible(&ctx->vsync_lock))
- return -EINTR;
- if (vsync_handler && !ctx->timegen_en) {
- ctx->vsync_time = ktime_get();
- schedule_work(&ctx->vsync_work);
- }
-
+ spin_lock_irqsave(&ctx->vsync_lock, flags);
if (!ctx->vsync_handler && vsync_handler)
- mdss_mdp_irq_enable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
+ video_vsync_irq_enable(ctl);
else if (ctx->vsync_handler && !vsync_handler)
- mdss_mdp_irq_disable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
+ video_vsync_irq_disable(ctl);
ctx->vsync_handler = vsync_handler;
- ctx->vsync_ptr = ctl;
- mutex_unlock(&ctx->vsync_lock);
+ spin_unlock_irqrestore(&ctx->vsync_lock, flags);
return 0;
}
@@ -229,8 +224,7 @@
WARN(rc, "intf %d timegen off error (%d)\n", ctl->intf_num, rc);
}
- if (ctx->vsync_handler)
- mdss_mdp_video_set_vsync_handler(ctl, NULL);
+ mdss_mdp_video_set_vsync_handler(ctl, NULL);
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num,
NULL, NULL);
@@ -244,9 +238,9 @@
static void mdss_mdp_video_pp_intr_done(void *arg)
{
- struct mdss_mdp_video_ctx *ctx;
+ struct mdss_mdp_ctl *ctl = arg;
+ struct mdss_mdp_video_ctx *ctx = ctl->priv_data;
- ctx = (struct mdss_mdp_video_ctx *) arg;
if (!ctx) {
pr_err("invalid ctx\n");
return;
@@ -259,20 +253,24 @@
static void mdss_mdp_video_vsync_intr_done(void *arg)
{
- struct mdss_mdp_video_ctx *ctx;
+ struct mdss_mdp_ctl *ctl = arg;
+ struct mdss_mdp_video_ctx *ctx = ctl->priv_data;
+ ktime_t vsync_time;
- ctx = (struct mdss_mdp_video_ctx *) arg;
if (!ctx) {
pr_err("invalid ctx\n");
return;
}
- ctx->vsync_time = ktime_get();
- pr_debug("intr ctl=%d\n", ctx->ctl_num);
+ vsync_time = ktime_get();
+
+ pr_debug("intr ctl=%d\n", ctl->num);
complete(&ctx->vsync_comp);
+ spin_lock(&ctx->vsync_lock);
if (ctx->vsync_handler)
- schedule_work(&ctx->vsync_work);
+ ctx->vsync_handler(ctl, vsync_time);
+ spin_unlock(&ctx->vsync_lock);
}
static int mdss_mdp_video_prepare(struct mdss_mdp_ctl *ctl, void *arg)
@@ -309,11 +307,7 @@
return -ENODEV;
}
INIT_COMPLETION(ctx->vsync_comp);
-
- if (mutex_lock_interruptible(&ctx->vsync_lock))
- return -EINTR;
- if (!ctx->vsync_handler)
- mdss_mdp_irq_enable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
+ video_vsync_irq_enable(ctl);
if (!ctx->timegen_en) {
int off = MDSS_MDP_REG_INTF_OFFSET(ctl->intf_num);
@@ -335,26 +329,21 @@
rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_TIMEGEN_ON, NULL);
WARN(rc, "intf %d timegen on error (%d)\n", ctl->intf_num, rc);
}
- if (!ctx->vsync_handler)
- mdss_mdp_irq_disable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
- mutex_unlock(&ctx->vsync_lock);
+
+ video_vsync_irq_disable(ctl);
return 0;
}
int mdss_mdp_video_start(struct mdss_mdp_ctl *ctl)
{
- struct msm_fb_data_type *mfd;
struct mdss_panel_info *pinfo;
struct mdss_mdp_video_ctx *ctx;
struct mdss_mdp_mixer *mixer;
struct intf_timing_params itp = {0};
- struct fb_info *fbi;
int i;
- mfd = ctl->mfd;
- fbi = mfd->fbi;
- pinfo = &mfd->panel_info;
+ pinfo = &ctl->panel_data->panel_info;
mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_LEFT);
if (!mixer) {
@@ -376,17 +365,16 @@
return -ENOMEM;
}
ctl->priv_data = ctx;
- ctx->ctl_num = ctl->num;
ctx->pp_num = mixer->num;
init_completion(&ctx->pp_comp);
init_completion(&ctx->vsync_comp);
+ spin_lock_init(&ctx->vsync_lock);
+ atomic_set(&ctx->vsync_ref, 0);
- INIT_WORK(&ctx->vsync_work, send_vsync_work);
- mutex_init(&ctx->vsync_lock);
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num,
- mdss_mdp_video_vsync_intr_done, ctx);
+ mdss_mdp_video_vsync_intr_done, ctl);
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num,
- mdss_mdp_video_pp_intr_done, ctx);
+ mdss_mdp_video_pp_intr_done, ctl);
itp.width = pinfo->xres + pinfo->lcdc.xres_pad;
itp.height = pinfo->yres + pinfo->lcdc.yres_pad;
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index f537c39..61c1e9f 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -26,6 +26,7 @@
#include "mdss_mdp.h"
#include "mdss_mdp_rotator.h"
+#define VSYNC_PERIOD 16
#define CHECK_BOUNDS(offset, size, max_size) \
(((size) > (max_size)) || ((offset) > ((max_size) - (size))))
@@ -681,7 +682,7 @@
} else {
ret = mdss_mdp_overlay_queue(mfd, req);
- if ((ret == 0) && (mfd->panel_info.type == WRITEBACK_PANEL)) {
+ if ((ret == 0) && (mfd->panel.type == WRITEBACK_PANEL)) {
mutex_unlock(&mfd->ov_lock);
ret = mdss_mdp_overlay_kickoff(mfd->ctl);
return ret;
@@ -837,30 +838,27 @@
mdss_mdp_overlay_kickoff(mfd->ctl);
}
+/* function is called in irq context should have minimum processing */
static void mdss_mdp_overlay_handle_vsync(struct mdss_mdp_ctl *ctl, ktime_t t)
{
- struct device *dev;
- char buf[64];
- char *envp[2];
-
- if (!ctl || !ctl->mfd || !ctl->mfd->fbi) {
+ struct msm_fb_data_type *mfd = ctl->mfd;
+ if (!mfd) {
pr_warn("Invalid handle for vsync\n");
return;
}
- dev = ctl->mfd->fbi->dev;
+ pr_debug("vsync on fb%d play_cnt=%d\n", mfd->index, ctl->play_cnt);
- snprintf(buf, sizeof(buf), "VSYNC=%llu", ktime_to_ns(t));
- envp[0] = buf;
- envp[1] = NULL;
- kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
-
- pr_debug("sent vsync on ctl=%d ts=%llu\n", ctl->num, ktime_to_ns(t));
+ spin_lock(&mfd->vsync_lock);
+ mfd->vsync_time = t;
+ complete(&mfd->vsync_comp);
+ spin_unlock(&mfd->vsync_lock);
}
int mdss_mdp_overlay_vsync_ctrl(struct msm_fb_data_type *mfd, int en)
{
struct mdss_mdp_ctl *ctl = mfd->ctl;
+ unsigned long flags;
int rc;
if (!ctl)
@@ -868,13 +866,23 @@
if (!ctl->set_vsync_handler)
return -ENOTSUPP;
- pr_debug("vsync en=%d\n", en);
-
if (!ctl->power_on) {
+ pr_debug("fb%d vsync pending first update en=%d\n",
+ mfd->index, en);
mfd->vsync_pending = en;
return 0;
}
+ pr_debug("fb%d vsync en=%d\n", mfd->index, en);
+
+ spin_lock_irqsave(&mfd->vsync_lock, flags);
+ INIT_COMPLETION(mfd->vsync_comp);
+ if (en && ctl->play_cnt == 0) {
+ mfd->vsync_time = ktime_get();
+ complete(&mfd->vsync_comp);
+ }
+ spin_unlock_irqrestore(&mfd->vsync_lock, flags);
+
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
if (en)
rc = ctl->set_vsync_handler(ctl, mdss_mdp_overlay_handle_vsync);
@@ -885,6 +893,47 @@
return rc;
}
+static ssize_t mdss_mdp_vsync_show_event(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fb_info *fbi = dev_get_drvdata(dev);
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
+ unsigned long flags;
+ u64 vsync_ticks;
+ int ret;
+
+ if (!mfd->ctl || !mfd->ctl->power_on)
+ return 0;
+
+ ret = wait_for_completion_interruptible_timeout(&mfd->vsync_comp,
+ msecs_to_jiffies(VSYNC_PERIOD * 5));
+ if (ret <= 0) {
+ pr_warn("vsync wait on fb%d interrupted (%d)\n",
+ mfd->index, ret);
+ return -EBUSY;
+ }
+
+ spin_lock_irqsave(&mfd->vsync_lock, flags);
+ vsync_ticks = ktime_to_ns(mfd->vsync_time);
+ spin_unlock_irqrestore(&mfd->vsync_lock, flags);
+
+ pr_debug("fb%d vsync=%llu", mfd->index, vsync_ticks);
+ ret = snprintf(buf, PAGE_SIZE, "VSYNC=%llu", vsync_ticks);
+
+ return ret;
+}
+
+static DEVICE_ATTR(vsync_event, S_IRUGO, mdss_mdp_vsync_show_event, NULL);
+
+static struct attribute *vsync_fs_attrs[] = {
+ &dev_attr_vsync_event.attr,
+ NULL,
+};
+
+static struct attribute_group vsync_fs_attr_group = {
+ .attrs = vsync_fs_attrs,
+};
+
static int mdss_mdp_hw_cursor_update(struct msm_fb_data_type *mfd,
struct fb_cursor *cursor)
{
@@ -1118,7 +1167,7 @@
ret = mdss_mdp_overlay_kickoff(mfd->ctl);
break;
default:
- if (mfd->panel_info.type == WRITEBACK_PANEL)
+ if (mfd->panel.type == WRITEBACK_PANEL)
ret = mdss_mdp_wb_ioctl_handler(mfd, cmd, argp);
break;
}
@@ -1154,6 +1203,9 @@
int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd)
{
+ struct device *dev = mfd->fbi->dev;
+ int rc;
+
mfd->on_fnc = mdss_mdp_overlay_on;
mfd->off_fnc = mdss_mdp_overlay_off;
mfd->hw_refresh = true;
@@ -1163,12 +1215,23 @@
mfd->dma_fnc = mdss_mdp_overlay_pan_display;
mfd->ioctl_handler = mdss_mdp_overlay_ioctl_handler;
- if (mfd->panel_info.type == WRITEBACK_PANEL)
+ if (mfd->panel.type == WRITEBACK_PANEL)
mfd->kickoff_fnc = mdss_mdp_wb_kickoff;
INIT_LIST_HEAD(&mfd->pipes_used);
INIT_LIST_HEAD(&mfd->pipes_cleanup);
+ init_completion(&mfd->vsync_comp);
+ spin_lock_init(&mfd->vsync_lock);
mutex_init(&mfd->ov_lock);
- return 0;
+ rc = sysfs_create_group(&dev->kobj, &vsync_fs_attr_group);
+ if (rc) {
+ pr_err("vsync sysfs group creation failed, ret=%d\n", rc);
+ return rc;
+ }
+
+ kobject_uevent(&dev->kobj, KOBJ_ADD);
+ pr_debug("vsync kobject_uevent(KOBJ_ADD)\n");
+
+ return rc;
}
diff --git a/drivers/video/msm/msm_fb_panel.h b/drivers/video/msm/msm_fb_panel.h
index bdd4f3bb..505928e 100644
--- a/drivers/video/msm/msm_fb_panel.h
+++ b/drivers/video/msm/msm_fb_panel.h
@@ -71,6 +71,7 @@
__u32 hw_vsync_mode;
__u32 vsync_notifier_period;
__u32 blt_ctrl;
+ __u32 blt_mode;
__u32 rev;
};
@@ -204,6 +205,18 @@
int (*clk_func) (int enable);
};
+enum {
+ MDP4_OVERLAY_BLT_SWITCH_TG_OFF,
+ MDP4_OVERLAY_BLT_SWITCH_TG_ON,
+ MDP4_OVERLAY_BLT_SWITCH_POLL
+};
+
+enum {
+ MDP4_OVERLAY_MODE_BLT_CTRL,
+ MDP4_OVERLAY_MODE_BLT_ALWAYS_ON,
+ MDP4_OVERLAY_MODE_BLT_ALWAYS_OFF
+};
+
/*===========================================================================
FUNCTIONS PROTOTYPES
============================================================================*/
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
index 2a850d8..8836b33 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
@@ -275,6 +275,7 @@
struct ddl_enc_buffers hw_bufs;
struct ddl_yuv_buffer_size input_buf_size;
struct vidc_1080p_enc_frame_info enc_frame_info;
+ u32 plusptype_enable;
u32 meta_data_enable_flag;
u32 suffix;
u32 meta_data_offset;
@@ -293,6 +294,7 @@
struct vcd_property_slice_delivery_info slice_delivery_info;
struct ddl_batch_frame_data batch_frame;
u32 avc_delimiter_enable;
+ u32 vui_timinginfo_enable;
};
struct ddl_decoder_data {
struct ddl_codec_data_hdr hdr;
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 d6558c3..2b65d7e 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
@@ -1061,6 +1061,35 @@
}
break;
}
+ case VCD_I_ENABLE_VUI_TIMING_INFO:
+ {
+ struct vcd_property_vui_timing_info_enable *vui_timing_enable =
+ (struct vcd_property_vui_timing_info_enable *)
+ property_value;
+ if (sizeof(struct vcd_property_vui_timing_info_enable) ==
+ property_hdr->sz &&
+ encoder->codec.codec == VCD_CODEC_H264) {
+ encoder->vui_timinginfo_enable =
+ vui_timing_enable->vui_timing_info;
+ vcd_status = VCD_S_SUCCESS;
+ }
+ break;
+ }
+ case VCD_I_H263_PLUSPTYPE:
+ {
+ struct vcd_property_plusptype *plusptype =
+ (struct vcd_property_plusptype *)property_value;
+
+ if ((sizeof(struct vcd_property_plusptype) ==
+ property_hdr->sz) && encoder->codec.codec ==
+ VCD_CODEC_H263) {
+ encoder->plusptype_enable = plusptype->plusptype_enable;
+ DDL_MSG_LOW("\nencoder->plusptype_enable = %u",
+ encoder->plusptype_enable);
+ vcd_status = VCD_S_SUCCESS;
+ }
+ break;
+ }
default:
DDL_MSG_ERROR("INVALID ID %d\n", (int)property_hdr->prop_id);
vcd_status = VCD_ERR_ILLEGAL_OP;
@@ -1553,6 +1582,15 @@
vcd_status = VCD_S_SUCCESS;
}
break;
+ case VCD_I_ENABLE_VUI_TIMING_INFO:
+ if (sizeof(struct vcd_property_vui_timing_info_enable) ==
+ property_hdr->sz) {
+ ((struct vcd_property_vui_timing_info_enable *)
+ property_value)->vui_timing_info =
+ encoder->vui_timinginfo_enable;
+ vcd_status = VCD_S_SUCCESS;
+ }
+ break;
default:
vcd_status = VCD_ERR_ILLEGAL_OP;
break;
@@ -1715,6 +1753,7 @@
encoder->slice_delivery_info.num_slices = 0;
encoder->slice_delivery_info.num_slices_enc = 0;
encoder->avc_delimiter_enable = 0;
+ encoder->vui_timinginfo_enable = 0;
}
static void ddl_set_default_enc_profile(struct ddl_encoder_data *encoder)
@@ -2145,5 +2184,6 @@
encoder->frame_rate.fps_denominator = 1;
ddl_set_default_enc_property(ddl);
encoder->sps_pps.sps_pps_for_idr_enable_flag = false;
+ encoder->plusptype_enable = 0;
}
}
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
index 40dc2aa..de3fc4f 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
@@ -83,6 +83,8 @@
#define VIDC_SM_ENC_EXT_CTRL_ADDR 0x0028
#define VIDC_SM_ENC_EXT_CTRL_VBV_BUFFER_SIZE_BMSK 0xffff0000
#define VIDC_SM_ENC_EXT_CTRL_VBV_BUFFER_SIZE_SHFT 16
+#define VIDC_SM_ENC_EXT_CTRL_TIMING_INFO_EN_BMSK 0x00004000
+#define VIDC_SM_ENC_EXT_CTRL_TIMING_INFO_EN_SHFT 14
#define VIDC_SM_ENC_EXT_CTRL_AU_DELIMITER_EN_BMSK 0x00000800
#define VIDC_SM_ENC_EXT_CTRL_AU_DELIMITER_EN_SHFT 11
#define VIDC_SM_ENC_EXT_CTRL_H263_CPCFC_ENABLE_BMSK 0x80
@@ -176,6 +178,13 @@
#define VIDC_SM_ENC_NUM_OF_SLICE_COMP_ADDR 0x01d0
#define VIDC_SM_ENC_NUM_OF_SLICE_COMP_VALUE_BMSK 0xffffffff
#define VIDC_SM_ENC_NUM_OF_SLICE_COMP_VALUE_SHFT 0
+#define VIDC_SM_ENC_NUM_UNITS_IN_TICK_ADDR 0x01dc
+#define VIDC_SM_ENC_NUM_UNITS_IN_TICK_VALUE_BMSK 0xffffffff
+#define VIDC_SM_ENC_NUM_UNITS_IN_TICK_VALUE_SHFT 0
+#define VIDC_SM_ENC_TIME_SCALE_ADDR 0x01e0
+#define VIDC_SM_ENC_TIME_SCALE_VALUE_BMSK 0xffffffff
+#define VIDC_SM_ENC_TIME_SCALE_VALUE_SHFT 0
+
#define VIDC_SM_ALLOCATED_LUMA_DPB_SIZE_ADDR 0x0064
#define VIDC_SM_ALLOCATED_CHROMA_DPB_SIZE_ADDR 0x0068
@@ -449,7 +458,8 @@
enum VIDC_SM_frame_skip frame_skip_mode,
u32 seq_hdr_in_band, u32 vbv_buffer_size, u32 cpcfc_enable,
u32 sps_pps_control, u32 closed_gop_enable,
- u32 au_delim_enable)
+ u32 au_delim_enable,
+ u32 vui_timing_info_enable)
{
u32 enc_ctrl;
enc_ctrl = VIDC_SETFIELD((hec_enable) ? 1 : 0,
@@ -475,7 +485,10 @@
VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_BMSK) |
VIDC_SETFIELD((au_delim_enable) ? 1 : 0,
VIDC_SM_ENC_EXT_CTRL_AU_DELIMITER_EN_SHFT,
- VIDC_SM_ENC_EXT_CTRL_AU_DELIMITER_EN_BMSK);
+ VIDC_SM_ENC_EXT_CTRL_AU_DELIMITER_EN_BMSK) |
+ VIDC_SETFIELD((vui_timing_info_enable) ? 1 : 0,
+ VIDC_SM_ENC_EXT_CTRL_TIMING_INFO_EN_SHFT,
+ VIDC_SM_ENC_EXT_CTRL_TIMING_INFO_EN_BMSK);
DDL_MEM_WRITE_32(shared_mem, VIDC_SM_ENC_EXT_CTRL_ADDR, enc_ctrl);
}
@@ -962,20 +975,12 @@
(codec == VCD_CODEC_DIVX_4) ||
(codec == VCD_CODEC_DIVX_5) ||
(codec == VCD_CODEC_DIVX_6) ||
- (codec == VCD_CODEC_XVID) ||
- (codec == VCD_CODEC_MPEG2)) {
+ (codec == VCD_CODEC_XVID)) {
- if (codec == VCD_CODEC_MPEG2) {
- aspect_ratio_info->aspect_ratio =
- VIDC_GETFIELD(aspect_ratio,
- VIDC_SM_MPEG2_ASPECT_RATIO_INFO_BMSK,
- VIDC_SM_MPEG2_ASPECT_RATIO_INFO_SHFT);
- } else {
- aspect_ratio_info->aspect_ratio =
- VIDC_GETFIELD(aspect_ratio,
- VIDC_SM_MPEG4_ASPECT_RATIO_INFO_BMSK,
- VIDC_SM_MPEG4_ASPECT_RATIO_INFO_SHFT);
- }
+ aspect_ratio_info->aspect_ratio =
+ VIDC_GETFIELD(aspect_ratio,
+ VIDC_SM_MPEG4_ASPECT_RATIO_INFO_BMSK,
+ VIDC_SM_MPEG4_ASPECT_RATIO_INFO_SHFT);
switch (aspect_ratio_info->aspect_ratio) {
case 1:
@@ -1016,7 +1021,38 @@
aspect_ratio_info->par_height = 1;
break;
}
+ } else if (codec == VCD_CODEC_MPEG2) {
+
+ aspect_ratio_info->aspect_ratio =
+ VIDC_GETFIELD(aspect_ratio,
+ VIDC_SM_MPEG2_ASPECT_RATIO_INFO_BMSK,
+ VIDC_SM_MPEG2_ASPECT_RATIO_INFO_SHFT);
+
+ switch (aspect_ratio_info->aspect_ratio) {
+ case 1:
+ aspect_ratio_info->par_width = 1;
+ aspect_ratio_info->par_height = 1;
+ break;
+ case 2:
+ aspect_ratio_info->par_width = 4;
+ aspect_ratio_info->par_height = 3;
+ break;
+ case 3:
+ aspect_ratio_info->par_width = 16;
+ aspect_ratio_info->par_height = 9;
+ break;
+ case 4:
+ aspect_ratio_info->par_width = 221;
+ aspect_ratio_info->par_height = 100;
+ break;
+ default:
+ DDL_MSG_LOW("Incorrect Aspect Ratio.");
+ aspect_ratio_info->par_width = 1;
+ aspect_ratio_info->par_height = 1;
+ break;
+ }
}
+
}
void vidc_sm_set_encoder_slice_batch_int_ctrl(struct ddl_buf_addr *shared_mem,
@@ -1139,3 +1175,15 @@
VIDC_SM_MP2_DATA_DUMP_BUFFER_SIZE_ADDR,
mp2datadumpsize);
}
+
+void vidc_sm_set_h264_encoder_timing_info(struct ddl_buf_addr *shared_mem,
+ u32 num_units_in_tick, u32 time_scale)
+{
+ DDL_MEM_WRITE_32(shared_mem,
+ VIDC_SM_ENC_NUM_UNITS_IN_TICK_ADDR,
+ num_units_in_tick);
+
+ DDL_MEM_WRITE_32(shared_mem,
+ VIDC_SM_ENC_TIME_SCALE_ADDR,
+ time_scale);
+}
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
index c4d577b..2eef99d 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
@@ -106,7 +106,7 @@
struct ddl_buf_addr *shared_mem, u32 hec_enable,
enum VIDC_SM_frame_skip frame_skip_mode, u32 seq_hdr_in_band,
u32 vbv_buffer_size, u32 cpcfc_enable, u32 sps_pps_control,
- u32 closed_gop_enable, u32 au_delim_enable);
+ u32 closed_gop_enable, u32 au_delim_enable, u32 vui_timing_info_enable);
void vidc_sm_set_encoder_param_change(struct ddl_buf_addr *shared_mem,
u32 bit_rate_chg, u32 frame_rate_chg, u32 i_period_chg);
void vidc_sm_set_encoder_vop_time(struct ddl_buf_addr *shared_mem,
@@ -198,6 +198,8 @@
void vidc_sm_set_mp2datadump_enable(struct ddl_buf_addr *shared_mem,
struct ddl_mp2_datadumpenabletype *ddl_mp2_datadump_enable);
void vidc_sm_set_mp2datadumpbuffer(struct ddl_buf_addr *shared_mem,
- u32 mp2datadumpaddr, u32 mp2datadumpsize);
+ u32 mp2datadumpaddr, u32 mp2datadumpsize);
+void vidc_sm_set_h264_encoder_timing_info(struct ddl_buf_addr *shared_mem,
+ u32 num_units_in_tick, u32 time_scale);
#endif
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h
index bbde7ae..6817101 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h
@@ -62,7 +62,8 @@
#define DDL_GET_ALIGNED_VITUAL(x) ((x).align_virtual_addr)
#define DDL_KILO_BYTE(x) ((x)*1024)
#define DDL_MEGA_BYTE(x) ((x)*1024*1024)
-#define DDL_FRAMERATE_SCALE(x) ((x) * 1000)
+#define DDL_FRAMERATE_SCALE_FACTOR (1000)
+#define DDL_FRAMERATE_SCALE(x) ((x) * DDL_FRAMERATE_SCALE_FACTOR)
#define DDL_MIN(x, y) ((x < y) ? x : y)
#define DDL_MAX(x, y) ((x > y) ? x : y)
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 5eed305..1bf242d 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
@@ -370,6 +370,15 @@
(u32)(DDL_FRAMERATE_SCALE(encoder->\
frame_rate.fps_numerator) /
encoder->frame_rate.fps_denominator));
+ if (encoder->vui_timinginfo_enable &&
+ encoder->frame_rate.fps_denominator) {
+ vidc_sm_set_h264_encoder_timing_info(
+ &ddl->shared_mem[ddl->command_channel],
+ DDL_FRAMERATE_SCALE_FACTOR,
+ (u32)(DDL_FRAMERATE_SCALE(encoder->\
+ frame_rate.fps_numerator) / encoder->\
+ frame_rate.fps_denominator) << 1);
+ }
encoder->dynamic_prop_change &=
~(DDL_ENC_CHANGE_FRAMERATE);
}
@@ -590,13 +599,20 @@
encoder->frame_rate.fps_denominator;
if ((encoder->codec.codec == VCD_CODEC_H263) &&
(DDL_FRAMERATE_SCALE(DDL_INITIAL_FRAME_RATE)
- != scaled_frame_rate))
+ != scaled_frame_rate) && encoder->plusptype_enable)
h263_cpfc_enable = true;
vidc_sm_set_extended_encoder_control(&ddl->shared_mem
[ddl->command_channel], hdr_ext_control,
r_cframe_skip, false, 0,
h263_cpfc_enable, encoder->sps_pps.sps_pps_for_idr_enable_flag,
- encoder->closed_gop, encoder->avc_delimiter_enable);
+ encoder->closed_gop, encoder->avc_delimiter_enable,
+ encoder->vui_timinginfo_enable);
+ if (encoder->vui_timinginfo_enable) {
+ vidc_sm_set_h264_encoder_timing_info(
+ &ddl->shared_mem[ddl->command_channel],
+ DDL_FRAMERATE_SCALE_FACTOR,
+ scaled_frame_rate << 1);
+ }
vidc_sm_set_encoder_init_rc_value(&ddl->shared_mem
[ddl->command_channel],
encoder->target_bit_rate.target_bitrate);
diff --git a/drivers/video/msm/vidc/common/enc/venc.c b/drivers/video/msm/vidc/common/enc/venc.c
index c7237e4..763fbda 100644
--- a/drivers/video/msm/vidc/common/enc/venc.c
+++ b/drivers/video/msm/vidc/common/enc/venc.c
@@ -1624,6 +1624,29 @@
}
break;
}
+ case VEN_IOCTL_SET_H263_PLUSPTYPE:
+ {
+ struct vcd_property_hdr vcd_property_hdr;
+ struct venc_plusptype plusptype;
+ u32 enable;
+ u32 vcd_status = VCD_ERR_FAIL;
+ if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
+ return -EFAULT;
+ if (copy_from_user(&plusptype, venc_msg.in,
+ sizeof(plusptype)))
+ return -EFAULT;
+ vcd_property_hdr.prop_id = VCD_I_H263_PLUSPTYPE;
+ vcd_property_hdr.sz = sizeof(u32);
+ enable = plusptype.plusptype_enable;
+ DBG("VEN_IOCTL_SET PLUSPTYPE = %d\n", enable);
+ vcd_status = vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &enable);
+ if (vcd_status) {
+ pr_err(" Setting plusptype failed");
+ return -EIO;
+ }
+ break;
+ }
case VEN_IOCTL_SET_AC_PREDICTION:
case VEN_IOCTL_GET_AC_PREDICTION:
case VEN_IOCTL_SET_RVLC:
diff --git a/drivers/video/msm/vidc/common/vcd/vcd.h b/drivers/video/msm/vidc/common/vcd/vcd.h
index 8f44a56..a22adeb 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd.h
+++ b/drivers/video/msm/vidc/common/vcd/vcd.h
@@ -398,4 +398,8 @@
u32 vcd_update_decoder_perf_level(struct vcd_dev_ctxt *dev_ctxt, u32 perf_lvl);
u32 vcd_set_perf_turbo_level(struct vcd_clnt_ctxt *cctxt);
+
+struct vcd_transc *vcd_get_first_in_use_trans_for_clnt(
+ struct vcd_clnt_ctxt *cctxt);
+
#endif
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_sub.c b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
index b84ae44..a4c44f3 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_sub.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
@@ -1684,7 +1684,7 @@
void vcd_send_frame_done_in_eos(struct vcd_clnt_ctxt *cctxt,
struct vcd_frame_data *input_frame, u32 valid_opbuf)
{
- VCD_MSG_LOW("vcd_send_frame_done_in_eos:");
+ VCD_MSG_HIGH("vcd_send_frame_done_in_eos:");
if (!input_frame->virtual && !valid_opbuf) {
VCD_MSG_MED("Sending NULL output with EOS");
@@ -1804,12 +1804,41 @@
}
}
+struct vcd_transc *vcd_get_first_in_use_trans_for_clnt(
+ struct vcd_clnt_ctxt *cctxt)
+{
+ u32 i;
+ struct vcd_dev_ctxt *dev_ctxt;
+ VCD_MSG_HIGH("%s: ", __func__);
+ dev_ctxt = cctxt->dev_ctxt;
+ if (!dev_ctxt->trans_tbl) {
+ VCD_MSG_ERROR("%s: Null trans_tbl", __func__);
+ return NULL;
+ }
+ i = 0;
+ while (i < dev_ctxt->trans_tbl_size) {
+ if ((cctxt == dev_ctxt->trans_tbl[i].cctxt) &&
+ (dev_ctxt->trans_tbl[i].in_use)) {
+ VCD_MSG_MED("%s: found transc = 0x%p",
+ __func__, &dev_ctxt->trans_tbl[i]);
+ break;
+ }
+ i++;
+ }
+ if (i == dev_ctxt->trans_tbl_size) {
+ VCD_MSG_ERROR("%s: in_use transction not found",
+ __func__);
+ return NULL;
+ } else
+ return &dev_ctxt->trans_tbl[i];
+}
+
u32 vcd_handle_recvd_eos(
struct vcd_clnt_ctxt *cctxt,
struct vcd_frame_data *input_frame, u32 *pb_eos_handled)
{
u32 rc;
-
+ struct vcd_transc *transc;
VCD_MSG_LOW("vcd_handle_recvd_eos:");
*pb_eos_handled = false;
@@ -1827,13 +1856,21 @@
*pb_eos_handled = true;
else if (cctxt->decoding && !input_frame->virtual)
cctxt->sched_clnt_hdl->tkns++;
- else if (!cctxt->decoding) {
- vcd_send_frame_done_in_eos(cctxt, input_frame, false);
- if (cctxt->status.mask & VCD_EOS_WAIT_OP_BUF) {
- vcd_do_client_state_transition(cctxt,
- VCD_CLIENT_STATE_EOS,
- CLIENT_STATE_EVENT_NUMBER
- (encode_frame));
+ else if (!cctxt->decoding && !cctxt->status.frame_delayed) {
+ if (!cctxt->status.frame_submitted) {
+ vcd_send_frame_done_in_eos(cctxt, input_frame, false);
+ if (cctxt->status.mask & VCD_EOS_WAIT_OP_BUF)
+ vcd_do_client_state_transition(cctxt,
+ VCD_CLIENT_STATE_EOS,
+ CLIENT_STATE_EVENT_NUMBER
+ (encode_frame));
+ } else {
+ transc = vcd_get_first_in_use_trans_for_clnt(cctxt);
+ if (transc) {
+ transc->flags |= VCD_FRAME_FLAG_EOS;
+ VCD_MSG_HIGH("%s: Add EOS flag to transc",
+ __func__);
+ }
}
*pb_eos_handled = true;
}
diff --git a/fs/buffer.c b/fs/buffer.c
index ad5938c..35ac651 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -1399,12 +1399,49 @@
return 0;
}
+static void __evict_bh_lru(void *arg)
+{
+ struct bh_lru *b = &get_cpu_var(bh_lrus);
+ struct buffer_head *bh = arg;
+ int i;
+
+ for (i = 0; i < BH_LRU_SIZE; i++) {
+ if (b->bhs[i] == bh) {
+ brelse(b->bhs[i]);
+ b->bhs[i] = NULL;
+ goto out;
+ }
+ }
+out:
+ put_cpu_var(bh_lrus);
+}
+
+static bool bh_exists_in_lru(int cpu, void *arg)
+{
+ struct bh_lru *b = per_cpu_ptr(&bh_lrus, cpu);
+ struct buffer_head *bh = arg;
+ int i;
+
+ for (i = 0; i < BH_LRU_SIZE; i++) {
+ if (b->bhs[i] == bh)
+ return 1;
+ }
+
+ return 0;
+
+}
void invalidate_bh_lrus(void)
{
on_each_cpu_cond(has_bh_in_lru, invalidate_bh_lru, NULL, 1, GFP_KERNEL);
}
EXPORT_SYMBOL_GPL(invalidate_bh_lrus);
+void evict_bh_lrus(struct buffer_head *bh)
+{
+ on_each_cpu_cond(bh_exists_in_lru, __evict_bh_lru, bh, 1, GFP_ATOMIC);
+}
+EXPORT_SYMBOL_GPL(evict_bh_lrus);
+
void set_bh_page(struct buffer_head *bh,
struct page *page, unsigned long offset)
{
@@ -3054,8 +3091,15 @@
do {
if (buffer_write_io_error(bh) && page->mapping)
set_bit(AS_EIO, &page->mapping->flags);
- if (buffer_busy(bh))
- goto failed;
+ if (buffer_busy(bh)) {
+ /*
+ * Check if the busy failure was due to an
+ * outstanding LRU reference
+ */
+ evict_bh_lrus(bh);
+ if (buffer_busy(bh))
+ goto failed;
+ }
bh = bh->b_this_page;
} while (bh != head);
diff --git a/include/linux/ion.h b/include/linux/ion.h
index 211327f..3a29f20 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -33,12 +33,14 @@
* @ION_HEAP_TYPE_CP: memory allocated from a prereserved
* carveout heap, allocations are physically
* contiguous. Used for content protection.
+ * @ION_HEAP_TYPE_DMA: memory allocated via DMA API
* @ION_HEAP_END: helper for iterating over heaps
*/
enum ion_heap_type {
ION_HEAP_TYPE_SYSTEM,
ION_HEAP_TYPE_SYSTEM_CONTIG,
ION_HEAP_TYPE_CARVEOUT,
+ ION_HEAP_TYPE_DMA,
ION_HEAP_TYPE_CUSTOM, /* must be last so device specific heaps always
are at the end of this enum */
ION_NUM_HEAPS,
@@ -47,6 +49,7 @@
#define ION_HEAP_SYSTEM_MASK (1 << ION_HEAP_TYPE_SYSTEM)
#define ION_HEAP_SYSTEM_CONTIG_MASK (1 << ION_HEAP_TYPE_SYSTEM_CONTIG)
#define ION_HEAP_CARVEOUT_MASK (1 << ION_HEAP_TYPE_CARVEOUT)
+#define ION_HEAP_TYPE_DMA_MASK (1 << ION_HEAP_TYPE_DMA)
/**
* heap flags - the lower 16 bits are used by core ion, the upper 16
@@ -84,6 +87,7 @@
* @memory_type:Memory type used for the heap
* @has_outer_cache: set to 1 if outer cache is used, 0 otherwise.
* @extra_data: Extra data specific to each heap type
+ * @priv: heap private data
*/
struct ion_platform_heap {
enum ion_heap_type type;
@@ -94,6 +98,7 @@
enum ion_memory_types memory_type;
unsigned int has_outer_cache;
void *extra_data;
+ void *priv;
};
/**
@@ -115,7 +120,7 @@
int (*request_region)(void *);
int (*release_region)(void *);
void *(*setup_region)(void);
- struct ion_platform_heap heaps[];
+ struct ion_platform_heap *heaps;
};
#ifdef CONFIG_ION
diff --git a/include/linux/mfd/pm8xxx/pm8921-charger.h b/include/linux/mfd/pm8xxx/pm8921-charger.h
index 12094e2..ae2c3d8 100644
--- a/include/linux/mfd/pm8xxx/pm8921-charger.h
+++ b/include/linux/mfd/pm8xxx/pm8921-charger.h
@@ -89,6 +89,7 @@
* area
* @max_bat_chg_current: Max charge current of the battery in mA
* Usually 70% of full charge capacity
+ * @usb_max_current: Maximum USB current in mA
* @cool_bat_chg_current: chg current (mA) when the battery is cool
* @warm_bat_chg_current: chg current (mA) when the battery is warm
* @cool_bat_voltage: chg voltage (mV) when the battery is cool
@@ -140,6 +141,7 @@
int warm_temp;
unsigned int temp_check_period;
unsigned int max_bat_chg_current;
+ unsigned int usb_max_current;
unsigned int cool_bat_chg_current;
unsigned int warm_bat_chg_current;
unsigned int cool_bat_voltage;
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 2046198..ec1d619 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -88,6 +88,7 @@
bool boot_ro_lockable;
u8 raw_exception_status; /* 53 */
u8 raw_partition_support; /* 160 */
+ u8 raw_rpmb_size_mult; /* 168 */
u8 raw_erased_mem_count; /* 181 */
u8 raw_ext_csd_structure; /* 194 */
u8 raw_card_type; /* 196 */
@@ -228,6 +229,7 @@
#define MMC_BLK_DATA_AREA_MAIN (1<<0)
#define MMC_BLK_DATA_AREA_BOOT (1<<1)
#define MMC_BLK_DATA_AREA_GP (1<<2)
+#define MMC_BLK_DATA_AREA_RPMB (1<<3)
};
#define BKOPS_NUM_OF_SEVERITY_LEVELS 3
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index c798cf9..6c43ec7 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -138,6 +138,8 @@
void (*enable_preset_value)(struct mmc_host *host, bool enable);
int (*select_drive_strength)(unsigned int max_dtr, int host_drv, int card_drv);
void (*hw_reset)(struct mmc_host *host);
+ unsigned long (*get_max_frequency)(struct mmc_host *host);
+ unsigned long (*get_min_frequency)(struct mmc_host *host);
};
struct mmc_card;
@@ -250,6 +252,7 @@
#define MMC_CAP2_SANITIZE (1 << 13) /* Support Sanitize */
#define MMC_CAP2_INIT_BKOPS (1 << 15) /* Need to set BKOPS_EN */
+#define MMC_CAP2_CLK_SCALE (1 << 16) /* Allow dynamic clk scaling */
mmc_pm_flag_t pm_caps; /* supported pm features */
int clk_requests; /* internal reference counter */
@@ -353,6 +356,19 @@
#endif
struct mmc_ios saved_ios;
+ struct {
+ unsigned long busy_time_us;
+ unsigned long window_time;
+ unsigned long curr_freq;
+ unsigned long polling_delay_ms;
+ unsigned int up_threshold;
+ unsigned int down_threshold;
+ ktime_t start_busy;
+ bool enable;
+ bool initialized;
+ bool in_progress;
+ struct delayed_work work;
+ } clk_scaling;
unsigned long private[0] ____cacheline_aligned;
};
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 237a92e..46479a7 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -290,6 +290,7 @@
#define EXT_CSD_BKOPS_START 164 /* W */
#define EXT_CSD_SANITIZE_START 165 /* W */
#define EXT_CSD_WR_REL_PARAM 166 /* RO */
+#define EXT_CSD_RPMB_MULT 168 /* RO */
#define EXT_CSD_BOOT_WP 173 /* R/W */
#define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */
#define EXT_CSD_PART_CONFIG 179 /* R/W */
@@ -346,6 +347,7 @@
#define EXT_CSD_PART_CONFIG_ACC_MASK (0x7)
#define EXT_CSD_PART_CONFIG_ACC_BOOT0 (0x1)
#define EXT_CSD_PART_CONFIG_ACC_BOOT1 (0x2)
+#define EXT_CSD_PART_CONFIG_ACC_RPMB (0x3)
#define EXT_CSD_PART_CONFIG_ACC_GP0 (0x4)
#define EXT_CSD_PART_SUPPORT_PART_EN (0x1)
diff --git a/include/linux/msm_ion.h b/include/linux/msm_ion.h
index ec043dd..21648ad 100644
--- a/include/linux/msm_ion.h
+++ b/include/linux/msm_ion.h
@@ -146,6 +146,7 @@
size_t secure_size; /* Size used for securing heap when heap is shared*/
int reusable;
int mem_is_fmem;
+ int is_cma;
enum ion_fixed_position fixed_position;
int iommu_map_all;
int iommu_2x_map_domain;
diff --git a/include/linux/msm_ipc.h b/include/linux/msm_ipc.h
index 44fa8eb..7b6bf41 100644
--- a/include/linux/msm_ipc.h
+++ b/include/linux/msm_ipc.h
@@ -45,6 +45,14 @@
unsigned char reserved;
};
+struct config_sec_rules_args {
+ int num_group_info;
+ uint32_t service_id;
+ uint32_t instance_id;
+ unsigned reserved;
+ gid_t group_id[0];
+};
+
#define IPC_ROUTER_IOCTL_MAGIC (0xC3)
#define IPC_ROUTER_IOCTL_GET_VERSION \
@@ -62,6 +70,9 @@
#define IPC_ROUTER_IOCTL_BIND_CONTROL_PORT \
_IOR(IPC_ROUTER_IOCTL_MAGIC, 4, unsigned int)
+#define IPC_ROUTER_IOCTL_CONFIG_SEC_RULES \
+ _IOR(IPC_ROUTER_IOCTL_MAGIC, 5, struct config_sec_rules_args)
+
struct msm_ipc_server_info {
uint32_t node_id;
uint32_t port_id;
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index 6912087..4e62b4f 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -1,6 +1,13 @@
#ifndef _MSM_KGSL_H
#define _MSM_KGSL_H
+/*
+ * The KGSL version has proven not to be very useful in userspace if features
+ * are cherry picked into other trees out of order so it is frozen as of 3.14.
+ * It is left here for backwards compatabilty and as a reminder that
+ * software releases are never linear. Also, I like pie.
+ */
+
#define KGSL_VERSION_MAJOR 3
#define KGSL_VERSION_MINOR 14
@@ -16,13 +23,25 @@
#define KGSL_CONTEXT_INVALID 0xffffffff
-/* Memory allocayion flags */
-#define KGSL_MEMFLAGS_GPUREADONLY 0x01000000
+/* --- Memory allocation flags --- */
+/* General allocation hints */
+#define KGSL_MEMFLAGS_GPUREADONLY 0x01000000
+#define KGSL_MEMFLAGS_USE_CPU_MAP 0x10000000
+
+/* Memory caching hints */
+#define KGSL_CACHEMODE_MASK 0x0C000000
+#define KGSL_CACHEMODE_SHIFT 26
+
+#define KGSL_CACHEMODE_WRITECOMBINE 0
+#define KGSL_CACHEMODE_UNCACHED 1
+#define KGSL_CACHEMODE_WRITETHROUGH 2
+#define KGSL_CACHEMODE_WRITEBACK 3
+
+/* Memory types for which allocations are made */
#define KGSL_MEMTYPE_MASK 0x0000FF00
#define KGSL_MEMTYPE_SHIFT 8
-/* Memory types for which allocations are made */
#define KGSL_MEMTYPE_OBJECTANY 0
#define KGSL_MEMTYPE_FRAMEBUFFER 1
#define KGSL_MEMTYPE_RENDERBUFFER 2
@@ -53,7 +72,8 @@
#define KGSL_MEMALIGN_MASK 0x00FF0000
#define KGSL_MEMALIGN_SHIFT 16
-/* generic flag values */
+/* --- generic KGSL flag values --- */
+
#define KGSL_FLAGS_NORMALMODE 0x00000000
#define KGSL_FLAGS_SAFEMODE 0x00000001
#define KGSL_FLAGS_INITIALIZED0 0x00000002
@@ -419,6 +439,14 @@
#define IOCTL_KGSL_SHAREDMEM_FROM_VMALLOC \
_IOWR(KGSL_IOC_TYPE, 0x23, struct kgsl_sharedmem_from_vmalloc)
+/*
+ * This is being deprecated in favor of IOCTL_KGSL_GPUMEM_CACHE_SYNC which
+ * supports both directions (flush and invalidate). This code will still
+ * work, but by definition it will do a flush of the cache which might not be
+ * what you want to have happen on a buffer following a GPU operation. It is
+ * safer to go with IOCTL_KGSL_GPUMEM_CACHE_SYNC
+ */
+
#define IOCTL_KGSL_SHAREDMEM_FLUSH_CACHE \
_IOW(KGSL_IOC_TYPE, 0x24, struct kgsl_sharedmem_free)
@@ -511,6 +539,115 @@
#define IOCTL_KGSL_TIMESTAMP_EVENT \
_IOWR(KGSL_IOC_TYPE, 0x33, struct kgsl_timestamp_event)
+/**
+ * struct kgsl_gpumem_alloc_id - argument to IOCTL_KGSL_GPUMEM_ALLOC_ID
+ * @id: returned id value for this allocation.
+ * @flags: mask of KGSL_MEM* values requested and actual flags on return.
+ * @size: requested size of the allocation and actual size on return.
+ * @mmapsize: returned size to pass to mmap() which may be larger than 'size'
+ * @gpuaddr: returned GPU address for the allocation
+ *
+ * Allocate memory for access by the GPU. The flags and size fields are echoed
+ * back by the kernel, so that the caller can know if the request was
+ * adjusted.
+ *
+ * Supported flags:
+ * KGSL_MEMFLAGS_GPUREADONLY: the GPU will be unable to write to the buffer
+ * KGSL_MEMTYPE*: usage hint for debugging aid
+ * KGSL_MEMALIGN*: alignment hint, may be ignored or adjusted by the kernel.
+ * KGSL_MEMFLAGS_USE_CPU_MAP: If set on call and return, the returned GPU
+ * address will be 0. Calling mmap() will set the GPU address.
+ */
+struct kgsl_gpumem_alloc_id {
+ unsigned int id;
+ unsigned int flags;
+ unsigned int size;
+ unsigned int mmapsize;
+ unsigned long gpuaddr;
+/* private: reserved for future use*/
+ unsigned int __pad[2];
+};
+
+#define IOCTL_KGSL_GPUMEM_ALLOC_ID \
+ _IOWR(KGSL_IOC_TYPE, 0x34, struct kgsl_gpumem_alloc_id)
+
+/**
+ * struct kgsl_gpumem_free_id - argument to IOCTL_KGSL_GPUMEM_FREE_ID
+ * @id: GPU allocation id to free
+ *
+ * Free an allocation by id, in case a GPU address has not been assigned or
+ * is unknown. Freeing an allocation by id with this ioctl or by GPU address
+ * with IOCTL_KGSL_SHAREDMEM_FREE are equivalent.
+ */
+struct kgsl_gpumem_free_id {
+ unsigned int id;
+/* private: reserved for future use*/
+ unsigned int __pad;
+};
+
+#define IOCTL_KGSL_GPUMEM_FREE_ID \
+ _IOWR(KGSL_IOC_TYPE, 0x35, struct kgsl_gpumem_free_id)
+
+/**
+ * struct kgsl_gpumem_get_info - argument to IOCTL_KGSL_GPUMEM_GET_INFO
+ * @gpuaddr: GPU address to query. Also set on return.
+ * @id: GPU allocation id to query. Also set on return.
+ * @flags: returned mask of KGSL_MEM* values.
+ * @size: returned size of the allocation.
+ * @mmapsize: returned size to pass mmap(), which may be larger than 'size'
+ * @useraddr: returned address of the userspace mapping for this buffer
+ *
+ * This ioctl allows querying of all user visible attributes of an existing
+ * allocation, by either the GPU address or the id returned by a previous
+ * call to IOCTL_KGSL_GPUMEM_ALLOC_ID. Legacy allocation ioctls may not
+ * return all attributes so this ioctl can be used to look them up if needed.
+ *
+ */
+struct kgsl_gpumem_get_info {
+ unsigned long gpuaddr;
+ unsigned int id;
+ unsigned int flags;
+ unsigned int size;
+ unsigned int mmapsize;
+ unsigned long useraddr;
+/* private: reserved for future use*/
+ unsigned int __pad[4];
+};
+
+#define IOCTL_KGSL_GPUMEM_GET_INFO\
+ _IOWR(KGSL_IOC_TYPE, 0x36, struct kgsl_gpumem_get_info)
+
+/**
+ * struct kgsl_gpumem_sync_cache - argument to IOCTL_KGSL_GPUMEM_SYNC_CACHE
+ * @gpuaddr: GPU address of the buffer to sync.
+ * @id: id of the buffer to sync. Either gpuaddr or id is sufficient.
+ * @op: a mask of KGSL_GPUMEM_CACHE_* values
+ *
+ * Sync the L2 cache for memory headed to and from the GPU - this replaces
+ * KGSL_SHAREDMEM_FLUSH_CACHE since it can handle cache management for both
+ * directions
+ *
+ */
+struct kgsl_gpumem_sync_cache {
+ unsigned int gpuaddr;
+ unsigned int id;
+ unsigned int op;
+/* private: reserved for future use*/
+ unsigned int __pad[2]; /* For future binary compatibility */
+};
+
+#define KGSL_GPUMEM_CACHE_CLEAN (1 << 0)
+#define KGSL_GPUMEM_CACHE_TO_GPU KGSL_GPUMEM_CACHE_CLEAN
+
+#define KGSL_GPUMEM_CACHE_INV (1 << 1)
+#define KGSL_GPUMEM_CACHE_FROM_GPU KGSL_GPUMEM_CACHE_INV
+
+#define KGSL_GPUMEM_CACHE_FLUSH \
+ (KGSL_GPUMEM_CACHE_CLEAN | KGSL_GPUMEM_CACHE_INV)
+
+#define IOCTL_KGSL_GPUMEM_SYNC_CACHE \
+ _IOW(KGSL_IOC_TYPE, 0x37, struct kgsl_gpumem_sync_cache)
+
#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/msm_vidc_enc.h b/include/linux/msm_vidc_enc.h
index 519c537..ea7db81 100644
--- a/include/linux/msm_vidc_enc.h
+++ b/include/linux/msm_vidc_enc.h
@@ -458,6 +458,9 @@
#define VEN_IOCTL_SET_SLICE_DELIVERY_MODE \
_IO(VEN_IOCTLBASE_ENC, 50)
+#define VEN_IOCTL_SET_H263_PLUSPTYPE \
+ _IOW(VEN_IOCTLBASE_ENC, 51, struct venc_ioctl_msg)
+
struct venc_switch{
unsigned char status;
};
@@ -519,6 +522,11 @@
unsigned long maxqp;
unsigned long minqp;
};
+
+struct venc_plusptype {
+ unsigned long plusptype_enable;
+};
+
struct venc_intraperiod{
unsigned long num_pframes;
unsigned long num_bframes;
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index d6fbc64..5b7820d 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -333,7 +333,6 @@
bool sm_work_pending;
atomic_t pm_suspended;
atomic_t in_lpm;
- atomic_t suspend_work_pending;
int async_int;
unsigned cur_power;
struct delayed_work chg_work;
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index b1f534d..e5e0bb4 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1833,6 +1833,12 @@
V4L2_MPEG_VIDC_INDEX_EXTRADATA_DIGITAL_ZOOM,
V4L2_MPEG_VIDC_INDEX_EXTRADATA_ASPECT_RATIO,
};
+#define V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 23)
+enum v4l2_mpeg_vidc_video_h264_vui_timing_info {
+ V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_DISABLED = 0,
+ V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_ENABLED = 1
+};
/* Camera class control IDs */
#define V4L2_CID_CAMERA_CLASS_BASE (V4L2_CTRL_CLASS_CAMERA | 0x900)
diff --git a/include/media/msm/vcd_property.h b/include/media/msm/vcd_property.h
index 180b38d..2ce1a88 100644
--- a/include/media/msm/vcd_property.h
+++ b/include/media/msm/vcd_property.h
@@ -56,6 +56,9 @@
#define VCD_I_VOP_TIMING_CONSTANT_DELTA (VCD_START_BASE + 0x28)
#define VCD_I_SET_TURBO_CLK (VCD_START_BASE + 0x29)
#define VCD_I_ENABLE_DELIMITER_FLAG (VCD_START_BASE + 0x2A)
+#define VCD_I_ENABLE_VUI_TIMING_INFO (VCD_START_BASE + 0x2B)
+#define VCD_I_H263_PLUSPTYPE (VCD_START_BASE + 0x2C)
+
#define VCD_START_REQ (VCD_START_BASE + 0x1000)
#define VCD_I_REQ_IFRAME (VCD_START_REQ + 0x1)
@@ -292,6 +295,10 @@
u32 min_qp;
};
+struct vcd_property_plusptype {
+ u32 plusptype_enable;
+};
+
struct vcd_property_session_qp {
u32 i_frame_qp;
u32 p_frame_qp;
@@ -378,4 +385,8 @@
u32 avc_delimiter_enable_flag;
};
+struct vcd_property_vui_timing_info_enable {
+ u32 vui_timing_info;
+};
+
#endif
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index a932011..971c9b3 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -1032,7 +1032,13 @@
#define CAMERA_EFFECT_EMBOSS 9
#define CAMERA_EFFECT_SKETCH 10
#define CAMERA_EFFECT_NEON 11
-#define CAMERA_EFFECT_MAX 12
+#define CAMERA_EFFECT_FADED 12
+#define CAMERA_EFFECT_VINTAGECOOL 13
+#define CAMERA_EFFECT_VINTAGEWARM 14
+#define CAMERA_EFFECT_ACCENT_BLUE 15
+#define CAMERA_EFFECT_ACCENT_GREEN 16
+#define CAMERA_EFFECT_ACCENT_ORANGE 17
+#define CAMERA_EFFECT_MAX 18
/* QRD */
#define CAMERA_EFFECT_BW 10
diff --git a/include/media/vcap_fmt.h b/include/media/vcap_fmt.h
index 84d9b42..369cf45 100644
--- a/include/media/vcap_fmt.h
+++ b/include/media/vcap_fmt.h
@@ -38,8 +38,8 @@
};
enum hal_vcap_polar {
- HAL_VCAP_POLAR_NEG = 0,
- HAL_VCAP_POLAR_POS,
+ HAL_VCAP_POLAR_POS = 0,
+ HAL_VCAP_POLAR_NEG,
};
enum hal_vcap_color {
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 14ccf3e..3bf514f 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -247,6 +247,11 @@
bdaddr_t bdaddr;
} __packed;
+#define MGMT_OP_CANCEL_RESOLVE_NAME 0x0024
+struct mgmt_cp_cancel_resolve_name {
+ bdaddr_t bdaddr;
+} __packed;
+
#define MGMT_OP_LE_READ_WHITE_LIST_SIZE 0xE000
#define MGMT_OP_LE_CLEAR_WHITE_LIST 0xE001
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 45a8d86..a2bad88 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -401,9 +401,16 @@
static void __hrtick_start(void *arg)
{
struct rq *rq = arg;
+ struct hrtimer *timer = &rq->hrtick_timer;
+ ktime_t soft, hard;
+ unsigned long delta;
+
+ soft = hrtimer_get_softexpires(timer);
+ hard = hrtimer_get_expires(timer);
+ delta = ktime_to_ns(ktime_sub(hard, soft));
raw_spin_lock(&rq->lock);
- hrtimer_restart(&rq->hrtick_timer);
+ __hrtimer_start_range_ns(timer, soft, delta, HRTIMER_MODE_ABS, 0);
rq->hrtick_csd_pending = 0;
raw_spin_unlock(&rq->lock);
}
@@ -421,7 +428,8 @@
hrtimer_set_expires(timer, time);
if (rq == this_rq()) {
- hrtimer_restart(timer);
+ __hrtimer_start_range_ns(timer, ns_to_ktime(delay), 0,
+ HRTIMER_MODE_REL_PINNED, 0);
} else if (!rq->hrtick_csd_pending) {
__smp_call_function_single(cpu_of(rq), &rq->hrtick_csd, 0);
rq->hrtick_csd_pending = 1;
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index e5f43ec..ea116e9 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1840,15 +1840,6 @@
struct hci_cp_auth_requested cp;
hci_remove_link_key(hdev, &conn->dst);
cp.handle = cpu_to_le16(conn->handle);
- /*Initiates dedicated bonding as pin or key is missing
- on remote device*/
- /*In case if remote device is ssp supported,
- reduce the security level to MEDIUM if it is HIGH*/
- if (conn->ssp_mode && conn->auth_initiator &&
- conn->io_capability != 0x03) {
- conn->pending_sec_level = BT_SECURITY_HIGH;
- conn->auth_type = HCI_AT_DEDICATED_BONDING_MITM;
- }
hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED,
sizeof(cp), &cp);
hci_dev_unlock(hdev);
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index fa2469e..44e2feb 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -93,6 +93,13 @@
static void l2cap_conn_del(struct hci_conn *hcon, int err, u8 is_process);
static u16 l2cap_get_smallest_flushto(struct l2cap_chan_list *l);
static void l2cap_set_acl_flushto(struct hci_conn *hcon, u16 flush_to);
+static void l2cap_queue_acl_data(struct work_struct *worker);
+static struct att_channel_parameters{
+ struct sk_buff *skb;
+ struct l2cap_conn *conn;
+ __le16 cid;
+ int dir;
+} att_chn_params;
/* ---- L2CAP channels ---- */
static struct sock *__l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, u16 cid)
@@ -1209,6 +1216,8 @@
kfree(conn);
}
+ att_chn_params.conn = NULL;
+ BT_DBG("att_chn_params.conn set to NULL");
}
static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk)
@@ -3600,8 +3609,7 @@
if (mtu < L2CAP_DEFAULT_MIN_MTU) {
result = L2CAP_CONF_UNACCEPT;
pi->omtu = L2CAP_DEFAULT_MIN_MTU;
- }
- else {
+ } else {
pi->omtu = mtu;
pi->conf_state |= L2CAP_CONF_MTU_DONE;
}
@@ -7275,6 +7283,7 @@
struct sk_buff *skb_rsp;
struct l2cap_hdr *lh;
int dir;
+ struct work_struct *open_worker;
u8 err_rsp[] = {L2CAP_ATT_ERROR, 0x00, 0x00, 0x00,
L2CAP_ATT_NOT_SUPPORTED};
@@ -7310,8 +7319,18 @@
BT_DBG("sk %p, len %d", sk, skb->len);
- if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED)
- goto drop;
+ if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED) {
+ att_chn_params.cid = cid;
+ att_chn_params.conn = conn;
+ att_chn_params.dir = dir;
+ att_chn_params.skb = skb;
+ open_worker = kzalloc(sizeof(*open_worker), GFP_ATOMIC);
+ if (!open_worker)
+ BT_ERR("Out of memory");
+ INIT_WORK(open_worker, l2cap_queue_acl_data);
+ schedule_work(open_worker);
+ goto done;
+ }
if (l2cap_pi(sk)->imtu < skb->len)
goto drop;
@@ -7787,6 +7806,80 @@
return 0;
}
+static void l2cap_queue_acl_data(struct work_struct *worker)
+{
+ struct sock *sk = NULL;
+ int attempts = 0;
+ struct sk_buff *skb_rsp;
+ struct l2cap_hdr *lh;
+ u8 err_rsp[] = {L2CAP_ATT_ERROR, 0x00, 0x00, 0x00,
+ L2CAP_ATT_NOT_SUPPORTED};
+
+ for (attempts = 0; attempts < 40; attempts++) {
+ msleep(50);
+ if (!att_chn_params.conn) {
+ BT_DBG("att_chn_params.conn is NULL");
+ return;
+ }
+ sk = l2cap_find_sock_by_fixed_cid_and_dir
+ (att_chn_params.cid,
+ att_chn_params.conn->src,
+ att_chn_params.conn->dst,
+ att_chn_params.dir);
+ bh_lock_sock(sk);
+ if (sk->sk_state == BT_CONNECTED) {
+ sock_queue_rcv_skb(sk, att_chn_params.skb);
+ if (sk)
+ bh_unlock_sock(sk);
+ return;
+ }
+ bh_unlock_sock(sk);
+ }
+ bh_lock_sock(sk);
+
+ if (att_chn_params.skb->data[0] != L2CAP_ATT_INDICATE)
+ goto not_indicate;
+
+ /* If this is an incoming Indication, we are required to confirm */
+ skb_rsp = bt_skb_alloc(sizeof(u8) + L2CAP_HDR_SIZE, GFP_ATOMIC);
+ if (!skb_rsp)
+ goto free_skb;
+
+ lh = (struct l2cap_hdr *) skb_put(skb_rsp, L2CAP_HDR_SIZE);
+ lh->len = cpu_to_le16(sizeof(u8));
+ lh->cid = cpu_to_le16(L2CAP_CID_LE_DATA);
+ err_rsp[0] = L2CAP_ATT_CONFIRM;
+ memcpy(skb_put(skb_rsp, sizeof(u8)), err_rsp, sizeof(u8));
+ hci_send_acl(att_chn_params.conn->hcon, NULL, skb_rsp, 0);
+ goto free_skb;
+
+not_indicate:
+ if (att_chn_params.skb->data[0] & L2CAP_ATT_RESPONSE_BIT ||
+ att_chn_params.skb->data[0] == L2CAP_ATT_CONFIRM)
+ goto free_skb;
+
+ /* If this is an incoming PDU that requires a response, respond with
+ * a generic error so remote device doesn't hang */
+
+ skb_rsp = bt_skb_alloc(sizeof(err_rsp) + L2CAP_HDR_SIZE, GFP_ATOMIC);
+ if (!skb_rsp)
+ goto free_skb;
+
+ lh = (struct l2cap_hdr *) skb_put(skb_rsp, L2CAP_HDR_SIZE);
+ lh->len = cpu_to_le16(sizeof(err_rsp));
+ lh->cid = cpu_to_le16(L2CAP_CID_LE_DATA);
+ err_rsp[1] = att_chn_params.skb->data[0];
+ memcpy(skb_put(skb_rsp, sizeof(err_rsp)), err_rsp, sizeof(err_rsp));
+ hci_send_acl(att_chn_params.conn->hcon, NULL, skb_rsp, 0);
+
+free_skb:
+ kfree_skb(att_chn_params.skb);
+
+ if (sk)
+ bh_unlock_sock(sk);
+
+}
+
static int l2cap_debugfs_open(struct inode *inode, struct file *file)
{
return single_open(file, l2cap_debugfs_show, inode->i_private);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 28eb7ea..23526f3 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -390,12 +390,17 @@
goto failed;
}
+ hci_dev_unlock_bh(hdev);
+
if (cp->val)
queue_work(hdev->workqueue, &hdev->power_on);
else
queue_work(hdev->workqueue, &hdev->power_off);
err = 0;
+ hci_dev_put(hdev);
+
+ return err;
failed:
hci_dev_unlock_bh(hdev);
@@ -1956,6 +1961,38 @@
return err;
}
+static int cancel_resolve_name(struct sock *sk, u16 index, unsigned char *data,
+ u16 len)
+{
+ struct mgmt_cp_cancel_resolve_name *mgmt_cp = (void *) data;
+ struct hci_cp_remote_name_req_cancel hci_cp;
+ struct hci_dev *hdev;
+ int err;
+
+ BT_DBG("");
+
+ if (len != sizeof(*mgmt_cp))
+ return cmd_status(sk, index, MGMT_OP_CANCEL_RESOLVE_NAME,
+ EINVAL);
+
+ hdev = hci_dev_get(index);
+ if (!hdev)
+ return cmd_status(sk, index, MGMT_OP_CANCEL_RESOLVE_NAME,
+ ENODEV);
+
+ hci_dev_lock_bh(hdev);
+
+ memset(&hci_cp, 0, sizeof(hci_cp));
+ bacpy(&hci_cp.bdaddr, &mgmt_cp->bdaddr);
+ err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(hci_cp),
+ &hci_cp);
+
+ hci_dev_unlock_bh(hdev);
+ hci_dev_put(hdev);
+
+ return err;
+}
+
static int set_connection_params(struct sock *sk, u16 index,
unsigned char *data, u16 len)
{
@@ -2189,10 +2226,11 @@
struct mgmt_mode cp = {0};
int err = -1;
- BT_DBG("");
-
hdev = hci_dev_get(index);
+ if (hdev)
+ BT_DBG("disco_state: %d", hdev->disco_state);
+
if (!hdev || !lmp_le_capable(hdev)) {
mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
@@ -2200,6 +2238,8 @@
mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
+ hdev->disco_state = SCAN_IDLE;
+
if (hdev)
goto done;
else
@@ -2315,6 +2355,7 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
+ BT_DBG("disco_state: %d", hdev->disco_state);
hci_dev_lock_bh(hdev);
if (hdev->disco_state && timer_pending(&hdev->disco_timer)) {
@@ -2395,6 +2436,8 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
+ BT_DBG("disco_state: %d", hdev->disco_state);
+
hci_dev_lock_bh(hdev);
state = hdev->disco_state;
@@ -2659,6 +2702,9 @@
case MGMT_OP_RESOLVE_NAME:
err = resolve_name(sk, index, buf + sizeof(*hdr), len);
break;
+ case MGMT_OP_CANCEL_RESOLVE_NAME:
+ err = cancel_resolve_name(sk, index, buf + sizeof(*hdr), len);
+ break;
case MGMT_OP_SET_CONNECTION_PARAMS:
err = set_connection_params(sk, index, buf + sizeof(*hdr), len);
break;
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 276ff71..56b2cfa 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -756,8 +756,7 @@
hcon->smp_conn = conn;
hcon->pending_sec_level = sec_level;
-
- if ((hcon->link_mode & HCI_LM_MASTER) && !hcon->sec_req) {
+ if (hcon->link_mode & HCI_LM_MASTER) {
struct link_key *key;
key = hci_find_link_key_type(hcon->hdev, conn->dst,
diff --git a/net/rfkill/core.c b/net/rfkill/core.c
index 04afd89..b7a3656 100644
--- a/net/rfkill/core.c
+++ b/net/rfkill/core.c
@@ -256,6 +256,7 @@
static void rfkill_set_block(struct rfkill *rfkill, bool blocked)
{
unsigned long flags;
+ bool prev, curr;
int err;
if (unlikely(rfkill->dev.power.power_state.event & PM_EVENT_SLEEP))
@@ -270,6 +271,8 @@
rfkill->ops->query(rfkill, rfkill->data);
spin_lock_irqsave(&rfkill->lock, flags);
+ prev = rfkill->state & RFKILL_BLOCK_SW;
+
if (rfkill->state & RFKILL_BLOCK_SW)
rfkill->state |= RFKILL_BLOCK_SW_PREV;
else
@@ -299,10 +302,15 @@
}
rfkill->state &= ~RFKILL_BLOCK_SW_SETCALL;
rfkill->state &= ~RFKILL_BLOCK_SW_PREV;
+ curr = rfkill->state & RFKILL_BLOCK_SW;
+
spin_unlock_irqrestore(&rfkill->lock, flags);
rfkill_led_trigger_event(rfkill);
- rfkill_event(rfkill);
+
+ if (prev != curr)
+ rfkill_event(rfkill);
+
}
#ifdef CONFIG_RFKILL_INPUT
diff --git a/scripts/build-all.py b/scripts/build-all.py
index 296d9ad..c59ffae 100755
--- a/scripts/build-all.py
+++ b/scripts/build-all.py
@@ -35,13 +35,14 @@
import subprocess
import os
import os.path
+import re
import shutil
import sys
version = 'build-all.py, version 0.01'
build_dir = '../all-kernels'
-make_command = ["vmlinux", "modules"]
+make_command = ["vmlinux", "modules", "dtbs"]
make_env = os.environ
make_env.update({
'ARCH': 'arm',
@@ -83,12 +84,15 @@
def scan_configs():
"""Get the full list of defconfigs appropriate for this tree."""
names = {}
- for n in glob.glob('arch/arm/configs/[fm]sm[0-9-]*_defconfig'):
- names[os.path.basename(n)[:-10]] = n
- for n in glob.glob('arch/arm/configs/qsd*_defconfig'):
- names[os.path.basename(n)[:-10]] = n
- for n in glob.glob('arch/arm/configs/apq*_defconfig'):
- names[os.path.basename(n)[:-10]] = n
+ arch_pats = (
+ r'[fm]sm[0-9]*_defconfig',
+ r'apq*_defconfig',
+ r'qsd*_defconfig',
+ r'omap2*_defconfig',
+ )
+ for p in arch_pats:
+ for n in glob.glob('arch/arm/configs/' + p):
+ names[os.path.basename(n)[:-10]] = n
return names
class Builder:
@@ -142,23 +146,41 @@
savedefconfig = '%s/defconfig' % dest_dir
shutil.copyfile(defconfig, dotconfig)
+ staging_dir = 'install_staging'
+ modi_dir = '%s' % staging_dir
+ hdri_dir = '%s/usr' % staging_dir
+ shutil.rmtree(os.path.join(dest_dir, staging_dir), ignore_errors=True)
+
devnull = open('/dev/null', 'r')
subprocess.check_call(['make', 'O=%s' % dest_dir,
'%s_defconfig' % target], env=make_env, stdin=devnull)
devnull.close()
if not all_options.updateconfigs:
- build = Builder(log_name)
-
- result = build.run(['make', 'O=%s' % dest_dir] + make_command)
-
- if result != 0:
- if all_options.keep_going:
- failed_targets.append(target)
- fail_or_error = error
+ # Build targets can be dependent upon the completion of previous
+ # build targets, so build them one at a time.
+ cmd_line = ['make',
+ 'INSTALL_HDR_PATH=%s' % hdri_dir,
+ 'INSTALL_MOD_PATH=%s' % modi_dir,
+ 'O=%s' % dest_dir]
+ build_targets = []
+ for c in make_command:
+ if re.match(r'^-{1,2}\w', c):
+ cmd_line.append(c)
else:
- fail_or_error = fail
- fail_or_error("Failed to build %s, see %s" % (target, build.logname))
+ build_targets.append(c)
+ for t in build_targets:
+ build = Builder(log_name)
+
+ result = build.run(cmd_line + [t])
+ if result != 0:
+ if all_options.keep_going:
+ failed_targets.append(target)
+ fail_or_error = error
+ else:
+ fail_or_error = fail
+ fail_or_error("Failed to build %s, see %s" %
+ (target, build.logname))
# Copy the defconfig back.
if all_options.configs or all_options.updateconfigs:
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index fd9d825..3fc3f32 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -1212,6 +1212,42 @@
return 0;
}
+static void sitar_enable_classg(struct snd_soc_codec *codec,
+ bool enable)
+{
+
+ if (enable) {
+ snd_soc_update_bits(codec,
+ SITAR_A_CDC_CLK_OTHR_RESET_CTL, 0x10, 0x00);
+ snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x07, 0x00);
+ snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x08, 0x00);
+ snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x10, 0x00);
+
+ } else {
+ snd_soc_update_bits(codec,
+ SITAR_A_CDC_CLK_OTHR_RESET_CTL, 0x10, 0x10);
+ snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x07, 0x03);
+ snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x08, 0x08);
+ snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x10, 0x10);
+ }
+}
+
+static bool sitar_is_hph_pa_on(struct snd_soc_codec *codec)
+{
+ u8 hph_reg_val = 0;
+ hph_reg_val = snd_soc_read(codec, SITAR_A_RX_HPH_CNP_EN);
+
+ return (hph_reg_val & 0x30) ? true : false;
+}
+
+static bool sitar_is_line_pa_on(struct snd_soc_codec *codec)
+{
+ u8 line_reg_val = 0;
+ line_reg_val = snd_soc_read(codec, SITAR_A_RX_LINE_CNP_EN);
+
+ return (line_reg_val & 0x03) ? true : false;
+}
+
static int sitar_codec_enable_lineout(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -1235,6 +1271,15 @@
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
+ if (sitar_is_hph_pa_on(codec)) {
+ snd_soc_update_bits(codec, SITAR_A_CDC_RX1_B6_CTL,
+ 0x20, 0x00);
+ sitar_enable_classg(codec, false);
+ } else {
+ snd_soc_update_bits(codec, SITAR_A_CDC_RX1_B6_CTL,
+ 0x20, 0x20);
+ sitar_enable_classg(codec, true);
+ }
snd_soc_update_bits(codec, lineout_gain_reg, 0x10, 0x10);
break;
case SND_SOC_DAPM_POST_PMU:
@@ -1243,6 +1288,11 @@
usleep_range(32000, 32000);
break;
case SND_SOC_DAPM_POST_PMD:
+ if (sitar_is_hph_pa_on(codec))
+ sitar_enable_classg(codec, true);
+ else
+ sitar_enable_classg(codec, false);
+
snd_soc_update_bits(codec, lineout_gain_reg, 0x10, 0x00);
break;
}
@@ -1585,14 +1635,6 @@
return rc;
}
-static bool sitar_is_hph_pa_on(struct snd_soc_codec *codec)
-{
- u8 hph_reg_val = 0;
- hph_reg_val = snd_soc_read(codec, SITAR_A_RX_HPH_CNP_EN);
-
- return (hph_reg_val & 0x30) ? true : false;
-}
-
static bool sitar_is_hph_dac_on(struct snd_soc_codec *codec, int left)
{
u8 hph_reg_val = 0;
@@ -1947,6 +1989,11 @@
SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
}
+ if (sitar_is_line_pa_on(codec))
+ sitar_enable_classg(codec, false);
+ else
+ sitar_enable_classg(codec, true);
+
break;
case SND_SOC_DAPM_POST_PMD:
@@ -1979,6 +2026,11 @@
w->name);
usleep_range(10000, 10000);
+ if (sitar_is_line_pa_on(codec))
+ sitar_enable_classg(codec, true);
+ else
+ sitar_enable_classg(codec, false);
+
break;
}
return 0;
@@ -2033,24 +2085,21 @@
pr_debug("%s %d\n", __func__, event);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_RESET_CTL, 0x10,
- 0x00);
snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_CTL, 0x01,
0x01);
snd_soc_update_bits(codec, SITAR_A_CDC_CLSG_CTL, 0x08, 0x08);
usleep_range(200, 200);
- snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x10, 0x00);
break;
case SND_SOC_DAPM_PRE_PMD:
- snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_RESET_CTL, 0x10,
- 0x10);
- usleep_range(20, 20);
- snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x08, 0x08);
- snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x10, 0x10);
snd_soc_update_bits(codec, SITAR_A_CDC_CLSG_CTL, 0x08, 0x00);
+ /*
+ * This delay is for the class G controller to settle down
+ * after turn OFF. The delay is as per the hardware spec for
+ * the codec
+ */
+ usleep_range(20, 20);
snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_CTL, 0x01,
0x00);
- snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x08, 0x00);
break;
}
return 0;
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index e11b985..e672cdb 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -295,6 +295,11 @@
(1 << AIF1_CAP) | (1 << AIF2_CAP), /* AIF2_CAP */
};
+static const u32 vport_i2s_check_table[NUM_CODEC_DAIS] = {
+ 0, /* AIF1_PB */
+ 0, /* AIF1_CAP */
+};
+
struct tabla_priv {
struct snd_soc_codec *codec;
struct tabla_reg_address reg_addr;
@@ -1746,6 +1751,7 @@
u32 dai_id = widget->shift;
u32 port_id = mixer->shift;
u32 enable = ucontrol->value.integer.value[0];
+ u32 vtable = vport_check_table[dai_id];
pr_debug("%s: wname %s cname %s value %u shift %d item %ld\n", __func__,
widget->name, ucontrol->id.name, widget->value, widget->shift,
@@ -1767,8 +1773,13 @@
/* only add to the list if value not set
*/
if (enable && !(widget->value & 1 << port_id)) {
+ if (tabla_p->intf_type ==
+ WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+ vtable = vport_check_table[dai_id];
+ if (tabla_p->intf_type == WCD9XXX_INTERFACE_TYPE_I2C)
+ vtable = vport_i2s_check_table[dai_id];
if (wcd9xxx_tx_vport_validation(
- vport_check_table[dai_id],
+ vtable,
port_id,
tabla_p->dai)) {
pr_info("%s: TX%u is used by other virtual port\n",
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 5ffb60a..ebb0421 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -181,6 +181,11 @@
(1 << AIF1_CAP) | (1 << AIF2_CAP), /* AIF2_CAP */
};
+static const u32 vport_i2s_check_table[NUM_CODEC_DAIS] = {
+ 0, /* AIF1_PB */
+ 0, /* AIF1_CAP */
+};
+
struct taiko_priv {
struct snd_soc_codec *codec;
u32 adc_count;
@@ -1523,6 +1528,7 @@
u32 dai_id = widget->shift;
u32 port_id = mixer->shift;
u32 enable = ucontrol->value.integer.value[0];
+ u32 vtable = vport_check_table[dai_id];
pr_debug("%s: wname %s cname %s value %u shift %d item %ld\n", __func__,
@@ -1539,7 +1545,6 @@
return -EINVAL;
}
}
- if (taiko_p->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
switch (dai_id) {
case AIF1_CAP:
case AIF2_CAP:
@@ -1547,8 +1552,16 @@
/* only add to the list if value not set
*/
if (enable && !(widget->value & 1 << port_id)) {
+
+ if (taiko_p->intf_type ==
+ WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+ vtable = vport_check_table[dai_id];
+ if (taiko_p->intf_type ==
+ WCD9XXX_INTERFACE_TYPE_I2C)
+ vtable = vport_i2s_check_table[dai_id];
+
if (wcd9xxx_tx_vport_validation(
- vport_check_table[dai_id],
+ vtable,
port_id,
taiko_p->dai)) {
pr_debug("%s: TX%u is used by other\n"
@@ -1583,7 +1596,6 @@
mutex_unlock(&codec->mutex);
return -EINVAL;
}
- }
pr_debug("%s: name %s sname %s updated value %u shift %d\n", __func__,
widget->name, widget->sname, widget->value, widget->shift);
diff --git a/sound/soc/msm/mdm9615.c b/sound/soc/msm/mdm9615.c
index 76cd625..7190ae9 100644
--- a/sound/soc/msm/mdm9615.c
+++ b/sound/soc/msm/mdm9615.c
@@ -1024,6 +1024,9 @@
}
codec_clk = clk_get(cpu_dai->dev, "osr_clk");
err = tabla_hs_detect(codec, &mbhc_cfg);
+ msm_gpiomux_install(
+ msm9615_audio_prim_i2s_codec_configs,
+ ARRAY_SIZE(msm9615_audio_prim_i2s_codec_configs));
return err;
}
@@ -1617,6 +1620,7 @@
codec_clk = clk_get(cpu_dai->dev, "osr_clk");
if (hs_detect_use_gpio) {
+ pr_debug("%s: GPIO Headset detection enabled\n", __func__);
mbhc_cfg.gpio = PM8018_GPIO_PM_TO_SYS(JACK_DETECT_GPIO);
mbhc_cfg.gpio_irq = JACK_DETECT_INT;
}
@@ -2428,6 +2432,8 @@
sif_virt_addr = ioremap(LPASS_SIF_MUX_ADDR, 4);
secpcm_portslc_virt_addr = ioremap(SEC_PCM_PORT_SLC_ADDR, 4);
+ hs_detect_use_gpio = true;
+
return ret;
}
module_init(mdm9615_audio_init);
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 58205e9..f8185bb 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -18,6 +18,7 @@
#include <linux/slab.h>
#include <linux/mfd/pm8xxx/pm8921.h>
#include <linux/qpnp/clkdiv.h>
+#include <linux/regulator/consumer.h>
#include <sound/core.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
@@ -30,9 +31,6 @@
#define DRV_NAME "msm8974-asoc-taiko"
-#define PM8921_GPIO_BASE NR_GPIO_IRQS
-#define PM8921_GPIO_PM_TO_SYS(pm_gpio) (pm_gpio - 1 + PM8921_GPIO_BASE)
-
#define MSM8974_SPK_ON 1
#define MSM8974_SPK_OFF 0
@@ -42,10 +40,10 @@
#define BTSCO_RATE_8KHZ 8000
#define BTSCO_RATE_16KHZ 16000
-#define BOTTOM_SPK_AMP_POS 0x1
-#define BOTTOM_SPK_AMP_NEG 0x2
-#define TOP_SPK_AMP_POS 0x4
-#define TOP_SPK_AMP_NEG 0x8
+#define LO_1_SPK_AMP 0x1
+#define LO_3_SPK_AMP 0x2
+#define LO_2_SPK_AMP 0x4
+#define LO_4_SPK_AMP 0x8
#define GPIO_AUX_PCM_DOUT 43
#define GPIO_AUX_PCM_DIN 44
@@ -56,6 +54,9 @@
#define WCD9XXX_MBHC_DEF_RLOADS 5
#define TAIKO_EXT_CLK_RATE 9600000
+/* It takes about 13ms for Class-D PAs to ramp-up */
+#define EXT_CLASS_D_EN_DELAY 13000
+
void *def_taiko_mbhc_cal(void);
static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
bool dapm);
@@ -89,11 +90,11 @@
SLIM_4_TX_1 = 150, /* In-call musid delivery TX */
};
-static u32 top_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(18);
-static u32 bottom_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(19);
-static int msm_spk_control;
-static int msm_ext_bottom_spk_pamp;
-static int msm_ext_top_spk_pamp;
+static struct platform_device *spdev;
+static struct regulator *ext_spk_amp_regulator;
+static int ext_spk_amp_gpio = -1;
+static int msm8974_spk_control = 1;
+static int msm8974_ext_spk_pamp;
static int msm_slim_0_rx_ch = 1;
static int msm_slim_0_tx_ch = 1;
@@ -105,103 +106,70 @@
static int clk_users;
static atomic_t auxpcm_rsc_ref;
-static void msm_enable_ext_spk_amp_gpio(u32 spk_amp_gpio)
+static int msm8974_liquid_ext_spk_power_amp_init(void)
{
int ret = 0;
- struct pm_gpio param = {
- .direction = PM_GPIO_DIR_OUT,
- .output_buffer = PM_GPIO_OUT_BUF_CMOS,
- .output_value = 1,
- .pull = PM_GPIO_PULL_NO,
- .vin_sel = PM_GPIO_VIN_S4,
- .out_strength = PM_GPIO_STRENGTH_MED,
- .
- function = PM_GPIO_FUNC_NORMAL,
- };
-
- if (spk_amp_gpio == bottom_spk_pamp_gpio) {
-
- ret = gpio_request(bottom_spk_pamp_gpio, "BOTTOM_SPK_AMP");
+ ext_spk_amp_gpio = of_get_named_gpio(spdev->dev.of_node,
+ "qcom,ext-spk-amp-gpio", 0);
+ if (ext_spk_amp_gpio >= 0) {
+ ret = gpio_request(ext_spk_amp_gpio, "ext_spk_amp_gpio");
if (ret) {
- pr_err("%s: Error requesting BOTTOM SPK AMP GPIO %u\n",
- __func__, bottom_spk_pamp_gpio);
- return;
+ pr_err("%s: gpio_request failed for ext_spk_amp_gpio.\n",
+ __func__);
+ return -EINVAL;
}
- ret = pm8xxx_gpio_config(bottom_spk_pamp_gpio, ¶m);
- if (ret)
- pr_err("%s: Failed to configure Bottom Spk Ampl gpio %u\n",
- __func__, bottom_spk_pamp_gpio);
- else {
- pr_debug("%s: enable Bottom spkr amp gpio\n", __func__);
- gpio_direction_output(bottom_spk_pamp_gpio, 1);
- }
+ gpio_direction_output(ext_spk_amp_gpio, 0);
- } else if (spk_amp_gpio == top_spk_pamp_gpio) {
+ if (ext_spk_amp_regulator == NULL) {
+ ext_spk_amp_regulator = regulator_get(&spdev->dev,
+ "qcom,ext-spk-amp");
- ret = gpio_request(top_spk_pamp_gpio, "TOP_SPK_AMP");
- if (ret) {
- pr_err("%s: Error requesting GPIO %d\n", __func__,
- top_spk_pamp_gpio);
- return;
+ if (IS_ERR(ext_spk_amp_regulator)) {
+ pr_err("%s: Cannot get regulator %s.\n",
+ __func__, "qcom,ext-spk-amp");
+
+ gpio_free(ext_spk_amp_gpio);
+ return PTR_ERR(ext_spk_amp_regulator);
+ }
}
- ret = pm8xxx_gpio_config(top_spk_pamp_gpio, ¶m);
- if (ret)
- pr_err("%s: Failed to configure Top Spk Ampl gpio %u\n",
- __func__, top_spk_pamp_gpio);
- else {
- pr_debug("%s: enable Top spkr amp gpio\n", __func__);
- gpio_direction_output(top_spk_pamp_gpio, 1);
- }
- } else {
- pr_err("%s: ERROR : Invalid External Speaker Ampl GPIO. gpio = %u\n",
- __func__, spk_amp_gpio);
- return;
}
+
+ return 0;
}
-static void msm_ext_spk_power_amp_on(u32 spk)
+static void msm8974_liquid_ext_spk_power_amp_enable(u32 on)
{
- if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
+ if (on)
+ regulator_enable(ext_spk_amp_regulator);
+ else
+ regulator_disable(ext_spk_amp_regulator);
- if ((msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
- (msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
+ gpio_direction_output(ext_spk_amp_gpio, on);
+ usleep_range(EXT_CLASS_D_EN_DELAY, EXT_CLASS_D_EN_DELAY);
+ pr_debug("%s: %s external speaker PAs.\n", __func__,
+ on ? "Enable" : "Disable");
+}
- pr_debug("%s() External Bottom Speaker Ampl already turned on. spk = 0x%08x\n",
+static void msm8974_ext_spk_power_amp_on(u32 spk)
+{
+ if (spk & (LO_1_SPK_AMP |
+ LO_3_SPK_AMP |
+ LO_2_SPK_AMP |
+ LO_4_SPK_AMP)) {
+
+ pr_debug("%s() External Left/Right Speakers already turned on. spk = 0x%08x\n",
__func__, spk);
- return;
- }
- msm_ext_bottom_spk_pamp |= spk;
+ msm8974_ext_spk_pamp |= spk;
- if ((msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
- (msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
+ if ((msm8974_ext_spk_pamp & LO_1_SPK_AMP) &&
+ (msm8974_ext_spk_pamp & LO_3_SPK_AMP) &&
+ (msm8974_ext_spk_pamp & LO_2_SPK_AMP) &&
+ (msm8974_ext_spk_pamp & LO_4_SPK_AMP)) {
- msm_enable_ext_spk_amp_gpio(bottom_spk_pamp_gpio);
- pr_debug("%s: slepping 4 ms after turning on external Bottom Speaker Ampl\n",
- __func__);
- usleep_range(4000, 4000);
- }
-
- } else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG)) {
-
- if ((msm_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
- (msm_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
-
- pr_debug("%s() External Top Speaker Ampl already turned on. spk = 0x%08x\n",
- __func__, spk);
- return;
- }
-
- msm_ext_top_spk_pamp |= spk;
-
- if ((msm_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
- (msm_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
-
- msm_enable_ext_spk_amp_gpio(top_spk_pamp_gpio);
- pr_debug("%s: sleeping 4 ms after turning on external Top Speaker Ampl\n",
- __func__);
- usleep_range(4000, 4000);
+ if (ext_spk_amp_gpio >= 0)
+ msm8974_liquid_ext_spk_power_amp_enable(1);
}
} else {
@@ -211,35 +179,22 @@
}
}
-static void msm_ext_spk_power_amp_off(u32 spk)
+static void msm8974_ext_spk_power_amp_off(u32 spk)
{
- if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
+ if (spk & (LO_1_SPK_AMP |
+ LO_3_SPK_AMP |
+ LO_2_SPK_AMP |
+ LO_4_SPK_AMP)) {
- if (!msm_ext_bottom_spk_pamp)
- return;
+ pr_debug("%s Left and right speakers case spk = 0x%08x",
+ __func__, spk);
- gpio_direction_output(bottom_spk_pamp_gpio, 0);
- gpio_free(bottom_spk_pamp_gpio);
- msm_ext_bottom_spk_pamp = 0;
+ if (!msm8974_ext_spk_pamp) {
+ if (ext_spk_amp_gpio >= 0)
+ msm8974_liquid_ext_spk_power_amp_enable(0);
+ msm8974_ext_spk_pamp = 0;
+ }
- pr_debug("%s: sleeping 4 ms after turning off external Bottom Speaker Ampl\n",
- __func__);
-
- usleep_range(4000, 4000);
-
- } else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG)) {
-
- if (!msm_ext_top_spk_pamp)
- return;
-
- gpio_direction_output(top_spk_pamp_gpio, 0);
- gpio_free(top_spk_pamp_gpio);
- msm_ext_top_spk_pamp = 0;
-
- pr_debug("%s: sleeping 4 ms after turning off external Top Spkaker Ampl\n",
- __func__);
-
- usleep_range(4000, 4000);
} else {
pr_err("%s: ERROR : Invalid Ext Spk Ampl. spk = 0x%08x\n",
@@ -248,87 +203,89 @@
}
}
-static void msm_ext_control(struct snd_soc_codec *codec)
+static void msm8974_ext_control(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = &codec->dapm;
mutex_lock(&dapm->codec->mutex);
- pr_debug("%s: msm_spk_control = %d", __func__, msm_spk_control);
- if (msm_spk_control == MSM8974_SPK_ON) {
- snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
- snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
- snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
- snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
+ pr_debug("%s: msm8974_spk_control = %d", __func__, msm8974_spk_control);
+ if (msm8974_spk_control == MSM8974_SPK_ON) {
+ snd_soc_dapm_enable_pin(dapm, "Lineout_1 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_3 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_2 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_4 amp");
} else {
- snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Pos");
- snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Neg");
- snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Pos");
- snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Neg");
+ snd_soc_dapm_disable_pin(dapm, "Lineout_1 amp");
+ snd_soc_dapm_disable_pin(dapm, "Lineout_3 amp");
+ snd_soc_dapm_disable_pin(dapm, "Lineout_2 amp");
+ snd_soc_dapm_disable_pin(dapm, "Lineout_4 amp");
}
snd_soc_dapm_sync(dapm);
mutex_unlock(&dapm->codec->mutex);
}
-static int msm_get_spk(struct snd_kcontrol *kcontrol,
+static int msm8974_get_spk(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- pr_debug("%s: msm_spk_control = %d", __func__, msm_spk_control);
- ucontrol->value.integer.value[0] = msm_spk_control;
+ pr_debug("%s: msm8974_spk_control = %d", __func__, msm8974_spk_control);
+ ucontrol->value.integer.value[0] = msm8974_spk_control;
return 0;
}
-static int msm_set_spk(struct snd_kcontrol *kcontrol,
+static int msm8974_set_spk(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
pr_debug("%s()\n", __func__);
- if (msm_spk_control == ucontrol->value.integer.value[0])
+ if (msm8974_spk_control == ucontrol->value.integer.value[0])
return 0;
- msm_spk_control = ucontrol->value.integer.value[0];
- msm_ext_control(codec);
+ msm8974_spk_control = ucontrol->value.integer.value[0];
+ msm8974_ext_control(codec);
return 1;
}
-static int msm_spkramp_event(struct snd_soc_dapm_widget *w,
+
+static int msm_ext_spkramp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
- pr_debug("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event));
+ pr_debug("%s()\n", __func__);
if (SND_SOC_DAPM_EVENT_ON(event)) {
- if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
- msm_ext_spk_power_amp_on(BOTTOM_SPK_AMP_POS);
- else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
- msm_ext_spk_power_amp_on(BOTTOM_SPK_AMP_NEG);
- else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
- msm_ext_spk_power_amp_on(TOP_SPK_AMP_POS);
- else if (!strncmp(w->name, "Ext Spk Top Neg", 15))
- msm_ext_spk_power_amp_on(TOP_SPK_AMP_NEG);
+ if (!strncmp(w->name, "Lineout_1 amp", 14))
+ msm8974_ext_spk_power_amp_on(LO_1_SPK_AMP);
+ else if (!strncmp(w->name, "Lineout_3 amp", 14))
+ msm8974_ext_spk_power_amp_on(LO_3_SPK_AMP);
+ else if (!strncmp(w->name, "Lineout_2 amp", 14))
+ msm8974_ext_spk_power_amp_on(LO_2_SPK_AMP);
+ else if (!strncmp(w->name, "Lineout_4 amp", 14))
+ msm8974_ext_spk_power_amp_on(LO_4_SPK_AMP);
else {
pr_err("%s() Invalid Speaker Widget = %s\n",
__func__, w->name);
return -EINVAL;
}
-
} else {
- if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
- msm_ext_spk_power_amp_off(BOTTOM_SPK_AMP_POS);
- else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
- msm_ext_spk_power_amp_off(BOTTOM_SPK_AMP_NEG);
- else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
- msm_ext_spk_power_amp_off(TOP_SPK_AMP_POS);
- else if (!strncmp(w->name, "Ext Spk Top Neg", 15))
- msm_ext_spk_power_amp_off(TOP_SPK_AMP_NEG);
+ if (!strncmp(w->name, "Lineout_1 amp", 14))
+ msm8974_ext_spk_power_amp_off(LO_1_SPK_AMP);
+ else if (!strncmp(w->name, "Lineout_3 amp", 14))
+ msm8974_ext_spk_power_amp_off(LO_3_SPK_AMP);
+ else if (!strncmp(w->name, "Lineout_2 amp", 14))
+ msm8974_ext_spk_power_amp_off(LO_2_SPK_AMP);
+ else if (!strncmp(w->name, "Lineout_4 amp", 14))
+ msm8974_ext_spk_power_amp_off(LO_4_SPK_AMP);
else {
pr_err("%s() Invalid Speaker Widget = %s\n",
__func__, w->name);
return -EINVAL;
}
}
+
return 0;
+
}
static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
@@ -397,11 +354,11 @@
SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0,
msm8974_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_SPK("Ext Spk Bottom Pos", msm_spkramp_event),
- SND_SOC_DAPM_SPK("Ext Spk Bottom Neg", msm_spkramp_event),
+ SND_SOC_DAPM_SPK("Lineout_1 amp", msm_ext_spkramp_event),
+ SND_SOC_DAPM_SPK("Lineout_3 amp", msm_ext_spkramp_event),
- SND_SOC_DAPM_SPK("Ext Spk Top Pos", msm_spkramp_event),
- SND_SOC_DAPM_SPK("Ext Spk Top Neg", msm_spkramp_event),
+ SND_SOC_DAPM_SPK("Lineout_2 amp", msm_ext_spkramp_event),
+ SND_SOC_DAPM_SPK("Lineout_4 amp", msm_ext_spkramp_event),
SND_SOC_DAPM_MIC("Handset Mic", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
@@ -693,8 +650,8 @@
};
static const struct snd_kcontrol_new msm_snd_controls[] = {
- SOC_ENUM_EXT("Speaker Function", msm_snd_enum[0], msm_get_spk,
- msm_set_spk),
+ SOC_ENUM_EXT("Speaker Function", msm_snd_enum[0], msm8974_get_spk,
+ msm8974_set_spk),
SOC_ENUM_EXT("SLIM_0_RX Channels", msm_snd_enum[1],
msm_slim_0_rx_ch_get, msm_slim_0_rx_ch_put),
SOC_ENUM_EXT("SLIM_0_TX Channels", msm_snd_enum[2],
@@ -723,11 +680,6 @@
pr_info("%s(), dev_name%s\n", __func__, dev_name(cpu_dai->dev));
- if (machine_is_msm8960_liquid()) {
- top_spk_pamp_gpio = (PM8921_GPIO_PM_TO_SYS(19));
- bottom_spk_pamp_gpio = (PM8921_GPIO_PM_TO_SYS(18));
- }
-
rtd->pmdown_time = 0;
err = snd_soc_add_codec_controls(codec, msm_snd_controls,
@@ -735,13 +687,21 @@
if (err < 0)
return err;
+ err = msm8974_liquid_ext_spk_power_amp_init();
+ if (err) {
+ pr_err("%s: LiQUID 8974 CLASS_D PAs init failed (%d)\n",
+ __func__, err);
+ return err;
+ }
+
snd_soc_dapm_new_controls(dapm, msm8974_dapm_widgets,
ARRAY_SIZE(msm8974_dapm_widgets));
- snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
- snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
- snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
- snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_1 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_3 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_2 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_4 amp");
+
snd_soc_dapm_sync(dapm);
@@ -1116,6 +1076,22 @@
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
},
+ {
+ .name = "VoLTE",
+ .stream_name = "VoLTE",
+ .cpu_dai_name = "VoLTE",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_VOLTE,
+ },
/* Backend BT/FM DAI Links */
{
.name = LPASS_BE_INT_BT_SCO_RX,
@@ -1458,9 +1434,13 @@
ret);
goto err;
}
+
mutex_init(&cdc_mclk_mutex);
atomic_set(&auxpcm_rsc_ref, 0);
+ spdev = pdev;
+ ext_spk_amp_regulator = NULL;
+
return 0;
err:
devm_kfree(&pdev->dev, pdata);
@@ -1472,7 +1452,13 @@
struct snd_soc_card *card = platform_get_drvdata(pdev);
struct msm8974_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ if (ext_spk_amp_regulator)
+ regulator_put(ext_spk_amp_regulator);
+
gpio_free(pdata->mclk_gpio);
+ if (ext_spk_amp_gpio >= 0)
+ gpio_free(ext_spk_amp_gpio);
+
snd_soc_unregister_card(card);
return 0;
diff --git a/sound/soc/msm/qdsp6/q6adm.c b/sound/soc/msm/qdsp6/q6adm.c
index 00394aa..119e017 100644
--- a/sound/soc/msm/qdsp6/q6adm.c
+++ b/sound/soc/msm/qdsp6/q6adm.c
@@ -853,24 +853,15 @@
} else if (channel_mode == 4) {
open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
- open.dev_channel_mapping[2] = PCM_CHANNEL_RB;
- open.dev_channel_mapping[3] = PCM_CHANNEL_LB;
+ open.dev_channel_mapping[2] = PCM_CHANNEL_LS;
+ open.dev_channel_mapping[3] = PCM_CHANNEL_RS;
} else if (channel_mode == 6) {
- open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
- open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
- open.dev_channel_mapping[2] = PCM_CHANNEL_LFE;
- open.dev_channel_mapping[3] = PCM_CHANNEL_FC;
- open.dev_channel_mapping[4] = PCM_CHANNEL_LB;
- open.dev_channel_mapping[5] = PCM_CHANNEL_RB;
- } else if (channel_mode == 8) {
- open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
- open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
- open.dev_channel_mapping[2] = PCM_CHANNEL_LFE;
- open.dev_channel_mapping[3] = PCM_CHANNEL_FC;
- open.dev_channel_mapping[4] = PCM_CHANNEL_LB;
- open.dev_channel_mapping[5] = PCM_CHANNEL_RB;
- open.dev_channel_mapping[6] = PCM_CHANNEL_FLC;
- open.dev_channel_mapping[7] = PCM_CHANNEL_FRC;
+ open.dev_channel_mapping[0] = PCM_CHANNEL_FC;
+ open.dev_channel_mapping[1] = PCM_CHANNEL_FL;
+ open.dev_channel_mapping[2] = PCM_CHANNEL_FR;
+ open.dev_channel_mapping[3] = PCM_CHANNEL_LS;
+ open.dev_channel_mapping[4] = PCM_CHANNEL_RS;
+ open.dev_channel_mapping[5] = PCM_CHANNEL_LFE;
} else {
pr_err("%s invalid num_chan %d\n", __func__,
channel_mode);
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index 1dfa605..52e481a 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -1152,7 +1152,9 @@
enc_cfg.enc_blk.cfg_size = sizeof(struct asm_dts_enc_cfg);
enc_cfg.enc_blk.cfg.dts.sample_rate = sample_rate;
enc_cfg.enc_blk.cfg.dts.num_channels = channels;
- if (channels == 2) {
+ if (channels == 1) {
+ enc_cfg.enc_blk.cfg.dts.channel_mapping[0] = PCM_CHANNEL_FC;
+ } else if (channels == 2) {
enc_cfg.enc_blk.cfg.dts.channel_mapping[0] = PCM_CHANNEL_FL;
enc_cfg.enc_blk.cfg.dts.channel_mapping[1] = PCM_CHANNEL_FR;
enc_cfg.enc_blk.cfg.dts.channel_mapping[2] = 0;
@@ -1167,12 +1169,12 @@
enc_cfg.enc_blk.cfg.dts.channel_mapping[4] = 0;
enc_cfg.enc_blk.cfg.dts.channel_mapping[5] = 0;
} else if (channels == 6) {
- enc_cfg.enc_blk.cfg.dts.channel_mapping[0] = PCM_CHANNEL_FL;
- enc_cfg.enc_blk.cfg.dts.channel_mapping[1] = PCM_CHANNEL_FR;
- enc_cfg.enc_blk.cfg.dts.channel_mapping[2] = PCM_CHANNEL_LFE;
+ enc_cfg.enc_blk.cfg.dts.channel_mapping[0] = PCM_CHANNEL_FC;
+ enc_cfg.enc_blk.cfg.dts.channel_mapping[1] = PCM_CHANNEL_FL;
+ enc_cfg.enc_blk.cfg.dts.channel_mapping[2] = PCM_CHANNEL_FR;
enc_cfg.enc_blk.cfg.dts.channel_mapping[3] = PCM_CHANNEL_LS;
enc_cfg.enc_blk.cfg.dts.channel_mapping[4] = PCM_CHANNEL_RS;
- enc_cfg.enc_blk.cfg.dts.channel_mapping[5] = PCM_CHANNEL_FC;
+ enc_cfg.enc_blk.cfg.dts.channel_mapping[5] = PCM_CHANNEL_LFE;
}
rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
if (rc < 0) {
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
index f1e0f3a..a1e461d 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
@@ -33,7 +33,9 @@
static struct snd_pcm_hardware msm_pcm_hardware = {
- .info = SNDRV_PCM_INFO_INTERLEAVED,
+ .info = (SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_RESUME),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
.rate_min = 8000,
@@ -205,6 +207,55 @@
return 0;
}
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ int ret = 0;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_voice *prtd = runtime->private_data;
+ uint16_t session_id = 0;
+
+ pr_debug("%s: cmd = %d\n", __func__, cmd);
+ if (is_volte(prtd))
+ session_id = voc_get_session_id(VOLTE_SESSION_NAME);
+ else
+ session_id = voc_get_session_id(VOICE_SESSION_NAME);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_STOP:
+ pr_debug("Start & Stop Voice call not handled in Trigger.\n");
+ break;
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ pr_debug("%s: resume call session_id = %d\n", __func__,
+ session_id);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ ret = msm_pcm_playback_prepare(substream);
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ ret = msm_pcm_capture_prepare(substream);
+ if (prtd->playback_start && prtd->capture_start)
+ voc_resume_voice_call(session_id);
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ pr_debug("%s: pause call session_id=%d\n",
+ __func__, session_id);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (prtd->playback_start)
+ prtd->playback_start = 0;
+ } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ if (prtd->capture_start)
+ prtd->capture_start = 0;
+ }
+ voc_standby_voice_call(session_id);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
static int msm_voice_volume_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -437,6 +488,7 @@
.hw_params = msm_pcm_hw_params,
.close = msm_pcm_close,
.prepare = msm_pcm_prepare,
+ .trigger = msm_pcm_trigger,
};
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index b799e59..263f47f 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -505,9 +505,9 @@
cvs_session_cmd.hdr.opcode =
VSS_ISTREAM_CMD_CREATE_PASSIVE_CONTROL_SESSION;
if (is_volte_session(v->session_id)) {
- strlcpy(mvm_session_cmd.mvm_session.name,
+ strlcpy(cvs_session_cmd.cvs_session.name,
"default volte voice",
- sizeof(mvm_session_cmd.mvm_session.name));
+ sizeof(cvs_session_cmd.cvs_session.name));
} else {
strlcpy(cvs_session_cmd.cvs_session.name,
"default modem voice",
@@ -3455,7 +3455,9 @@
v->dev_tx.mute = mute;
- if (v->voc_state == VOC_RUN)
+ if ((v->voc_state == VOC_RUN) ||
+ (v->voc_state == VOC_CHANGE) ||
+ (v->voc_state == VOC_STANDBY))
ret = voice_send_mute_cmd(v);
mutex_unlock(&v->lock);
@@ -3661,7 +3663,9 @@
v->dev_rx.volume = vol_idx;
- if (v->voc_state == VOC_RUN)
+ if ((v->voc_state == VOC_RUN) ||
+ (v->voc_state == VOC_CHANGE) ||
+ (v->voc_state == VOC_STANDBY))
ret = voice_send_vol_index_cmd(v);
mutex_unlock(&v->lock);
@@ -3753,7 +3757,9 @@
mutex_lock(&v->lock);
- if (v->voc_state == VOC_RUN || v->voc_state == VOC_ERROR) {
+ if (v->voc_state == VOC_RUN || v->voc_state == VOC_ERROR ||
+ v->voc_state == VOC_STANDBY) {
+
pr_debug("%s: VOC_STATE: %d\n", __func__, v->voc_state);
ret = voice_destroy_vocproc(v);
@@ -3767,6 +3773,69 @@
return ret;
}
+int voc_standby_voice_call(uint16_t session_id)
+{
+ struct voice_data *v = voice_get_session(session_id);
+ struct apr_hdr mvm_standby_voice_cmd;
+ void *apr_mvm;
+ u16 mvm_handle;
+ int ret = 0;
+
+ pr_debug("%s: voc state=%d", __func__, v->voc_state);
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (v->voc_state == VOC_RUN) {
+ apr_mvm = common.apr_q6_mvm;
+ if (!apr_mvm) {
+ pr_err("%s: apr_mvm is NULL.\n", __func__);
+ ret = -EINVAL;
+ goto fail;
+ }
+ mvm_handle = voice_get_mvm_handle(v);
+ mvm_standby_voice_cmd.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ mvm_standby_voice_cmd.pkt_size =
+ APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(mvm_standby_voice_cmd) - APR_HDR_SIZE);
+ pr_debug("send mvm_standby_voice_cmd pkt size = %d\n",
+ mvm_standby_voice_cmd.pkt_size);
+ mvm_standby_voice_cmd.src_port = v->session_id;
+ mvm_standby_voice_cmd.dest_port = mvm_handle;
+ mvm_standby_voice_cmd.token = 0;
+ mvm_standby_voice_cmd.opcode = VSS_IMVM_CMD_STANDBY_VOICE;
+ v->mvm_state = CMD_STATUS_FAIL;
+ ret = apr_send_pkt(apr_mvm,
+ (uint32_t *)&mvm_standby_voice_cmd);
+ if (ret < 0) {
+ pr_err("Fail in sending VSS_IMVM_CMD_STANDBY_VOICE\n");
+ ret = -EINVAL;
+ goto fail;
+ }
+ v->voc_state = VOC_STANDBY;
+ }
+fail:
+ return ret;
+}
+
+int voc_resume_voice_call(uint16_t session_id)
+{
+ struct voice_data *v = voice_get_session(session_id);
+ int ret = 0;
+
+ ret = voice_send_start_voice_cmd(v);
+ if (ret < 0) {
+ pr_err("Fail in sending START_VOICE\n");
+ goto fail;
+ }
+ v->voc_state = VOC_RUN;
+ return 0;
+fail:
+ return -EINVAL;
+}
+
int voc_start_voice_call(uint16_t session_id)
{
struct voice_data *v = voice_get_session(session_id);
@@ -3845,6 +3914,10 @@
}
v->voc_state = VOC_RUN;
+ } else if (v->voc_state == VOC_STANDBY) {
+ pr_err("Error: start voice in Standby\n");
+ ret = -EINVAL;
+ goto fail;
}
fail:
mutex_unlock(&v->lock);
@@ -3961,6 +4034,7 @@
case VSS_IMVM_CMD_SET_CAL_NETWORK:
case VSS_IMVM_CMD_SET_CAL_MEDIA_TYPE:
case VSS_IMEMORY_CMD_UNMAP:
+ case VSS_IMVM_CMD_STANDBY_VOICE:
pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
v->mvm_state = CMD_STATUS_SUCCESS;
wake_up(&v->mvm_wait);
diff --git a/sound/soc/msm/qdsp6v2/q6voice.h b/sound/soc/msm/qdsp6v2/q6voice.h
index aef463f..6fb4b04 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.h
+++ b/sound/soc/msm/qdsp6v2/q6voice.h
@@ -68,6 +68,7 @@
VOC_CHANGE,
VOC_RELEASE,
VOC_ERROR,
+ VOC_STANDBY,
};
struct mem_buffer {
@@ -171,6 +172,9 @@
#define VSS_IMVM_CMD_START_VOICE 0x00011190
/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+#define VSS_IMVM_CMD_STANDBY_VOICE 0x00011191
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
#define VSS_IMVM_CMD_STOP_VOICE 0x00011192
/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
@@ -1227,6 +1231,8 @@
int voc_set_tty_mode(uint16_t session_id, uint8_t tty_mode);
int voc_start_voice_call(uint16_t session_id);
int voc_end_voice_call(uint16_t session_id);
+int voc_standby_voice_call(uint16_t session_id);
+int voc_resume_voice_call(uint16_t session_id);
int voc_set_rxtx_port(uint16_t session_id,
uint32_t dev_port_id,
uint32_t dev_type);