Merge "msm_vidc: Remove SSR related code"
diff --git a/Documentation/devicetree/bindings/arm/msm/dcvs-core-info.txt b/Documentation/devicetree/bindings/arm/msm/dcvs-core-info.txt
index b7dd427..f8152cfb 100644
--- a/Documentation/devicetree/bindings/arm/msm/dcvs-core-info.txt
+++ b/Documentation/devicetree/bindings/arm/msm/dcvs-core-info.txt
@@ -37,9 +37,9 @@
- qcom,algo-ss-win-size-max-us: sets maximum steady state window size.
- qcom,algo-ss-util-pct: sets target CPU utilization during
steady-state.
-- qcom,algo-ss-iobusy-conv: specifies how wait time (i/o busy time)
- is incorporated into the steady-state
- algorithm.
+- qcom,algo-ss-no-corr-below-freq: specifies frequency below which DCVS
+ will not attempt to correlate busy or
+ idle information from different CPUs
- qcom,energy-active-coeff-a: sets active power equation coefficient a.
- qcom,energy-active-coeff-b: sets active power equation coefficient b.
@@ -89,7 +89,7 @@
qcom,algo-ss-win-size-min-us = <1000000>;
qcom,algo-ss-win-size-max-us = <1000000>;
qcom,algo-ss-util-pct = <95>;
- qcom,algo-ss-iobusy-conv = <100>;
+ qcom,algo-ss-no-corr-below-freq = <0>;
qcom,energy-active-coeff-a = <2492>;
qcom,energy-active-coeff-b = <0>;
diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.txt b/Documentation/devicetree/bindings/ata/ahci-platform.txt
index 8bb8a76..3e309e4 100644
--- a/Documentation/devicetree/bindings/ata/ahci-platform.txt
+++ b/Documentation/devicetree/bindings/ata/ahci-platform.txt
@@ -4,7 +4,8 @@
Each SATA controller should have its own node.
Required properties:
-- compatible : compatible list, contains "calxeda,hb-ahci" or "snps,spear-ahci"
+- compatible : compatible list, contains "calxeda,hb-ahci" or
+ "snps,spear-ahci" or "qcom,msm-ahci"
- interrupts : <interrupt mapping for SATA IRQ>
- reg : <registers mapping>
diff --git a/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt b/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt
index e777094..a30d1d6 100644
--- a/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt
+++ b/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt
@@ -6,6 +6,7 @@
- reg: offset and length of the register regions(s) for the device.
- reg-names: a list of strings that map in order to the list of regs.
+- hpd-gdsc-supply: phandle to the mdss gdsc regulator device tree node.
- hpd-5v-supply: phandle to the 5V regulator device tree node.
- core-vdda-supply: phandle to the HDMI vdda regulator device tree node.
- core-vcc-supply: phandle to the HDMI vcc regulator device tree node.
@@ -33,6 +34,14 @@
- qcom,hdmi-tx-mux-en: gpio required to enable mux for HDMI output
on liquid devices. Required property for liquid devices.
+[Optional child nodes]: These nodes are for devices which are
+dependent on HDMI Tx controller. If HDMI Tx controller is disabled then
+these devices will be disabled as well. Ex. HDMI Audio Codec device.
+
+- qcom,msm-hdmi-audio-rx: Node for HDMI audio codec.
+Required properties:
+- compatible : "msm-hdmi-audio-codec-rx";
+
Example:
qcom,hdmi_tx@fd922100 {
cell-index = <0>;
@@ -42,17 +51,22 @@
<0xfc4b8000 0x60F0>;
reg-names = "core_physical", "phy_physical", "qfprom_physical";
+ hpd-gdsc-supply = <&gdsc_mdss>;
hpd-5v-supply = <&pm8941_mvs2>;
core-vdda-supply = <&pm8941_l12>;
core-vcc-supply = <&pm8941_s3>;
- qcom,hdmi-tx-supply-names = "hpd-5v", "core-vdda", "core-vcc";
- qcom,hdmi-tx-supply-type = <0 1 1>;
- qcom,hdmi-tx-min-voltage-level = <0 1800000 1800000>;
- qcom,hdmi-tx-max-voltage-level = <0 1800000 1800000>;
- qcom,hdmi-tx-op-mode = <0 1800000 0>;
+ qcom,hdmi-tx-supply-names = "hpd-gdsc", "hpd-5v", "core-vdda", "core-vcc";
+ qcom,hdmi-tx-supply-type = <1 1 0 0>;
+ qcom,hdmi-tx-min-voltage-level = <0 0 1800000 1800000>;
+ qcom,hdmi-tx-max-voltage-level = <0 0 1800000 1800000>;
+ qcom,hdmi-tx-op-mode = <0 0 1800000 0>;
qcom,hdmi-tx-cec = <&msmgpio 31 0>;
qcom,hdmi-tx-ddc-clk = <&msmgpio 32 0>;
qcom,hdmi-tx-ddc-data = <&msmgpio 33 0>;
qcom,hdmi-tx-hpd = <&msmgpio 34 0>;
+
+ qcom,msm-hdmi-audio-rx {
+ compatible = "qcom,msm-hdmi-audio-codec-rx";
+ };
};
diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
index 9164647..2ea9ba9 100644
--- a/Documentation/devicetree/bindings/gpu/adreno.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno.txt
@@ -132,7 +132,7 @@
qcom,algo-ss-window-size = <1000000>;
qcom,algo-ss-util-pct = <95>;
qcom,algo-em-max-util-pct = <97>;
- qcom,algo-ss-iobusy-conv = <100>;
+ qcom,algo-ss-no-corr-below-freq = <0>;
qcom,dcvs-freq@0 {
reg = <0>;
diff --git a/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt b/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt
index e458ea0..fbe8ffa 100644
--- a/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt
+++ b/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt
@@ -10,6 +10,8 @@
Required properties:
- compatible : should be "qcom,qpnp-iadc" for Current ADC driver.
- reg : offset and length of the PMIC Aribter register map.
+- address-cells : Must be one.
+- size-cells : Must be zero.
- interrupts : The USR bank peripheral IADC interrupt.
- interrupt-names : Should contain "eoc-int-en-set".
- qcom,adc-bit-resolution : Bit resolution of the ADC.
@@ -21,6 +23,7 @@
Required properties:
- label : Channel name used for sysfs entry.
+- reg : AMUX channel number.
- qcom,channel-num : Channel number associated to the AMUX input.
- qcom,decimation : Sampling rate to use for the individual channel measurement.
Select from the following unsigned int.
@@ -84,6 +87,8 @@
qcom,iadc@3200 {
compatible = "qcom,qpnp-iadc";
reg = <0x3200 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
interrupts = <0 0x36 0>;
interrupt-names = "eoc-int-en-set";
qcom,adc-bit-resolution = <16>;
@@ -93,7 +98,7 @@
/* Channel Node */
chan@0 = {
label = "rsense";
- qcom,channel-num = <0>;
+ reg = <0>;
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <20>;
qcom,calibration-type = "fresh";
diff --git a/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
index e23605c..bb66e7b 100644
--- a/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
+++ b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
@@ -10,6 +10,8 @@
Required properties:
- compatible : should be "qcom,qpnp-vadc" for Voltage ADC driver.
- reg : offset and length of the PMIC Aribter register map.
+- address-cells : Must be one.
+- size-cells : Must be zero.
- interrupts : The USR bank peripheral VADC interrupt.
- interrupt-names : Should contain "eoc-int-en-set".
- qcom,adc-bit-resolution : Bit resolution of the ADC.
@@ -20,7 +22,7 @@
Required properties:
- label : Channel name used for sysfs entry.
-- qcom,channel-num : Channel number associated to the AMUX input.
+- reg : AMUX channel number.
- qcom,decimation : Sampling rate to use for the individual channel measurement.
Select from following unsigned int.
0 : 512
@@ -82,6 +84,8 @@
qcom,vadc@3100 {
compatible = "qcom,qpnp-vadc";
reg = <0x3100 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
interrupts = <0x0 0x31 0x0>;
interrupt-names = "eoc-int-en-set";
qcom,adc-bit-resolution = <15>;
@@ -90,7 +94,7 @@
/* Channel Node */
chan@0 {
label = "usb_in";
- qcom,channel-num = <0>;
+ reg = <0>;
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <20>;
qcom,calibration-type = "absolute";
diff --git a/Documentation/devicetree/bindings/power/qpnp-bms.txt b/Documentation/devicetree/bindings/power/qpnp-bms.txt
index af8d45c..d91086f 100644
--- a/Documentation/devicetree/bindings/power/qpnp-bms.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-bms.txt
@@ -57,6 +57,9 @@
- qcom,bms-use-voltage-soc : A boolean that controls whether BMS will use
voltage-based SoC instead of a coulomb counter based
one. Voltage-based SoC will not guarantee linearity.
+- qcom,bms-use-external-rsense : A boolean that controls whether BMS will use
+ an external sensor resistor instead of the default
+ RDS of the batfet.
All sub node required properties:
- reg : offset and length of the PMIC peripheral register map.
diff --git a/Documentation/devicetree/bindings/power/qpnp-charger.txt b/Documentation/devicetree/bindings/power/qpnp-charger.txt
index 2103bbc..59a9fd9 100644
--- a/Documentation/devicetree/bindings/power/qpnp-charger.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-charger.txt
@@ -26,14 +26,20 @@
- qcom,chg-vddmax-mv: Target voltage of battery in mV
- qcom,chg-vddsafe-mv: Maximum Vdd voltage in mV
- qcom,chg-vinmin-mv: Minimum input voltage in mV
+- qcom,chg-vbatdet-mv: Battery voltage at which charging resumes
- qcom,chg-ibatmax-ma: Maximum battery charge current in mA
- qcom,chg-ibatterm-ma: Current at which charging is terminated in mA.
+- qcom,chg-ibatsafe-ma: Safety battery current setting
Parent node optional properties:
-- qcom,chg-charging-disabled: Set this property to disable charging
- by default. This can then be overriden
- writing the the module parameter
- "charging_disabled".
+- qcom,chg-charging-disabled: Set this property to disable charging
+ by default. This can then be overriden
+ writing the the module parameter
+ "charging_disabled".
+- qcom,chg-use-default-batt-values: Set this flag to force reporting of
+ battery temperature of 250 decidegree
+ Celsius, state of charge to be 50%
+ and disable charging.
Sub node required structure:
- A qcom,chg node must be a child of an SPMI node that has specified
diff --git a/Documentation/devicetree/bindings/qdsp/msm-adsp-sensors.txt b/Documentation/devicetree/bindings/qdsp/msm-adsp-sensors.txt
new file mode 100644
index 0000000..ff0b1ef
--- /dev/null
+++ b/Documentation/devicetree/bindings/qdsp/msm-adsp-sensors.txt
@@ -0,0 +1,19 @@
+* msm-adsp-sensors
+
+Required properties:
+
+ - compatible: "qcom,msm-adsp-sensors"
+ - qcom,src-id: Master port id
+ - qcom,dst-id: Slave port id
+ - qcom,ab: Arbitrated bandwidth in bytes/s
+ - qcom,ib: Instantaneous bandwidth in bytes/s
+
+Example:
+
+ qcom,msm-adsp-sensors {
+ compatible = "qcom,msm-adsp-sensors";
+ qcom,src-id = <11>;
+ qcom,dst-id = <604>;
+ qcom,ab = <209715200>;
+ qcom,ib = <471859200>;
+ };
diff --git a/Documentation/devicetree/bindings/sound/taiko_codec.txt b/Documentation/devicetree/bindings/sound/taiko_codec.txt
index 090d8db..74c25a0 100644
--- a/Documentation/devicetree/bindings/sound/taiko_codec.txt
+++ b/Documentation/devicetree/bindings/sound/taiko_codec.txt
@@ -34,7 +34,7 @@
- qcom,cdc-micbias2-ext-cap: Boolean. Enable micbias 2 external capacitor mode.
- qcom,cdc-micbias3-ext-cap: Boolean. Enable micbias 3 external capacitor mode.
- qcom,cdc-micbias4-ext-cap: Boolean. Enable micbias 4 external capacitor mode.
-
+ - qcom,cdc-mclk-clk-rate - Specifies the master clock rate in Hz required for codec.
- qcom,cdc-slim-ifd-dev - namme of the codec slim interface device.
- qcom,cdc-slim-ifd-elemental-addr - codec slimbus slave interface device
enumeration address.
@@ -86,7 +86,7 @@
qcom,cdc-micbias2-ext-cap;
qcom,cdc-micbias3-ext-cap;
qcom,cdc-micbias4-ext-cap;
-
+ qcom,cdc-mclk-clk-rate = <9600000>;
qcom,cdc-slim-ifd = "taiko-slim-ifd";
qcom,cdc-slim-ifd-elemental-addr = [00 00 A0 00 17 02];
};
@@ -123,6 +123,7 @@
- qcom,cdc-micbias2-ext-cap: Boolean. Enable micbias 2 external capacitor mode.
- qcom,cdc-micbias3-ext-cap: Boolean. Enable micbias 3 external capacitor mode.
- qcom,cdc-micbias4-ext-cap: Boolean. Enable micbias 4 external capacitor mode.
+ - qcom,cdc-mclk-clk-rate - Specifies the master clock rate in Hz required for codec.
Example:
i2c@f9925000 {
@@ -180,6 +181,7 @@
qcom,cdc-micbias2-cfilt-sel = <0x1>;
qcom,cdc-micbias3-cfilt-sel = <0x2>;
qcom,cdc-micbias4-cfilt-sel = <0x2>;
+ qcom,cdc-mclk-clk-rate = <12288000>;
};
wcd9xxx_codec@77{
diff --git a/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt b/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt
new file mode 100644
index 0000000..f1f4e94
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt
@@ -0,0 +1,120 @@
+Qualcomm's QPNP PMIC thermal monitor ADC driver (VADC_TM)
+
+QPNP PMIC thermal monitoring (TM) provides interface to thermal clients
+to set temperature thresholds and receive notification when the thresholds
+are crossed. A 15 bit ADC is used for measurements. The driver is part
+of the sysfs thermal framework that provides support to read the trip
+points, set threshold for the trip points and enable the trip points.
+Seperate kernel api's are provided to usb_id and batt_therm
+to set thresholds and receive threshold notifications.
+
+VADC_TM node
+
+Required properties:
+- compatible : should be "qcom,qpnp-adc-tm" for thermal ADC driver.
+- reg : offset and length of the PMIC Aribter register map.
+- address-cells : Must be one.
+- size-cells : Must be zero.
+- interrupts : The thermal ADC bank peripheral interrupts for eoc, high and low interrupts.
+- interrupt-names : Should be "eoc-int-en-set", "high-thr-en-set" and "low-thr-en-set".
+- qcom,adc-bit-resolution : Bit resolution of the ADC.
+- qcom,adc-vdd-reference : Voltage reference used by the ADC.
+
+Channel nodes
+NOTE: Atleast one Channel node is required.
+
+Required properties:
+- label : Channel name used for sysfs entry.
+- reg : AMUX channel number.
+- qcom,decimation : Sampling rate to use for the individual channel measurement.
+ Select from the following unsigned int.
+ 0 : 512
+ 1 : 1K
+ 2 : 2K
+ 3 : 4K
+- qcom,pre-div-channel-scaling : Pre-div used for the channel before the signal is being measured.
+ Select from the following unsigned int for the corresponding
+ numerator/denominator pre-div ratio.
+ 0 : pre-div ratio of {1, 1}
+ 1 : pre-div ratio of {1, 3}
+ 2 : pre-div ratio of {1, 4}
+ 3 : pre-div ratio of {1, 6}
+ 4 : pre-div ratio of {1, 20}
+- qcom,calibration-type : Reference voltage to use for channel calibration.
+ Channel calibration is dependendent on the channel.
+ Certain channels like XO_THERM, BATT_THERM use ratiometric
+ calibration. Most other channels fall under absolute calibration.
+ Select from the following strings.
+ "absolute" : Uses the 625mv and 1.25V reference channels.
+ "ratiometric" : Uses the reference Voltage/GND for calibration.
+- qcom,scale-function : Scaling fuction used to convert raw ADC code to units specific to
+ a given channel.
+ Select from the following unsigned int.
+ 0 : Default scaling to convert raw adc code to voltage.
+ 1 : Conversion to temperature based on btm parameters.
+ 2 : Returns result in milli degree's Centigrade.
+ 3 : Returns current across 0.1 ohm resistor.
+ 4 : Returns XO thermistor voltage in degree's Centigrade.
+- qcom,hw-settle-time : Settling period for the channel before ADC read.
+ Select from the following unsigned int.
+ 0 : 0us
+ 1 : 100us
+ 2 : 200us
+ 3 : 300us
+ 4 : 400us
+ 5 : 500us
+ 6 : 600us
+ 7 : 700us
+ 8 : 800us
+ 9 : 900us
+ 0xa : 1ms
+ 0xb : 2ms
+ 0xc : 4ms
+ 0xd : 6ms
+ 0xe : 8ms
+ 0xf : 10ms
+- qcom,fast-avg-setup : Average number of samples to be used for measurement. Fast averaging
+ provides the option to obtain a single measurement from the ADC that
+ is an average of multiple samples. The value selected is 2^(value)
+ Select from
+ 0 : 1
+ 1 : 2
+ 2 : 4
+ 3 : 8
+ 4 : 16
+ 5 : 32
+ 6 : 64
+ 7 : 128
+ 8 : 256
+- qcom,btm-channel-number : There are 5 BTM channels. The BTM channel numbers are statically
+ allocated to the corresponding channel node.
+
+Example:
+ /* Main Node */
+ qcom,vadc@3400 {
+ compatible = "qcom,qpnp-adc-tm";
+ reg = <0x3400 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0x0 0x34 0x0>,
+ <0x0 0x34 0x3>,
+ <0x0 0x34 0x4>;
+ interrupt-names = "eoc-int-en-set",
+ "high-thr-en-set",
+ "low-thr-en-set";
+ qcom,adc-bit-resolution = <15>;
+ qcom,adc-vdd-reference = <1800>;
+
+ /* Channel Node */
+ chan@b5 {
+ label = "pa_therm1";
+ reg = <0xb5>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ qcom,btm-channel-number = <0x70>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
index 0e59f69..ffb0c6a 100644
--- a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
@@ -9,6 +9,17 @@
- <supply-name>-supply: handle to the regulator device tree node
Required "supply-name" is "HSIC_VDDCX" and optionally - "HSIC_GDSC".
+Optional properties :
+- hsic,<gpio-name>-gpio : handle to the GPIO node, see "gpios property"
+ in Documentation/devicetree/bindings/gpio/gpio.txt.
+ Optional "gpio-name" can be "strobe" and "data".
+- hsic,ignore-cal-pad-config : If present then HSIC CAL PAD configuration
+ using TLMM is not performed.
+- hsic,strobe-pad-offset : Offset of TLMM register for configuring HSIC
+ STROBE GPIO PAD.
+- hsic,data-pad-offset : Offset of TLMM register for configuring HSIC
+ DATA GPIO PAD.
+
Example MSM HSIC EHCI controller device node :
hsic@f9a15000 {
compatible = "qcom,hsic-host";
@@ -17,4 +28,47 @@
interrupt-names = "core_irq";
HSIC_VDDCX-supply = <&pm8019_l12>;
HSIC_GDSC-supply = <&gdsc_usb_hsic>;
+ hsic,strobe-gpio = <&msmgpio 144 0x00>;
+ hsic,data-gpio = <&msmgpio 145 0x00>;
+ hsic,ignore-cal-pad-config;
+ hsic,strobe-pad-offset = <0x2050>;
+ hsic,data-pad-offset = <0x2054>;
};
+
+SMSC HSIC HUB
+
+Required properties :
+- compatible : should be "qcom,hsic-smsc-hub"
+- smsc,<gpio-name>-gpio : handle to the GPIO node, see "gpios property"
+ in Documentation/devicetree/bindings/gpio/gpio.txt.
+ Required "gpio-name" is "reset" and optionally - "refclk", "int".
+- <supply-name>-supply: handle to the regulator device tree node
+ Required "supply-name" is "hub_init" and optionally - "hub_vbus".
+- Sub node for "MSM HSIC EHCI controller".
+ Sub node has the required properties mentioned above.
+
+Example SMSC HSIC HUB :
+ hsic_hub {
+ compatible = "qcom,hsic-smsc-hub";
+ ranges;
+ smsc,reset-gpio = <&pm8941_gpios 8 0x00>;
+ smsc,refclk-gpio = <&pm8941_gpios 16 0x00>;
+ smsc,int-gpio = <&msmgpio 50 0x00>;
+ hub_int-supply = <&pm8941_l10>;
+ hub_vbus-supply = <&pm8941_mvs1>;
+
+ hsic@f9a00000 {
+ compatible = "qcom,hsic-host";
+ reg = <0xf9a00000 0x400>;
+ interrupts = <0 136 0>;
+ interrupt-names = "core_irq";
+ HSIC_VDDCX-supply = <&pm8841_s2>;
+ HSIC_GDSC-supply = <&gdsc_usb_hsic>;
+ hsic,strobe-gpio = <&msmgpio 144 0x00>;
+ hsic,data-gpio = <&msmgpio 145 0x00>;
+ hsic,ignore-cal-pad-config;
+ hsic,strobe-pad-offset = <0x2050>;
+ hsic,data-pad-offset = <0x2054>;
+ };
+ };
+
diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
index ace2dee..64a6d6f 100644
--- a/arch/arm/boot/compressed/head.S
+++ b/arch/arm/boot/compressed/head.S
@@ -567,6 +567,12 @@
mcr p15, 0, r0, c7, c0, 0 @ invalidate whole cache v3
mov pc, lr
+#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
+#define CB_BITS 0x08
+#else
+#define CB_BITS 0x0c
+#endif
+
__setup_mmu: sub r3, r4, #16384 @ Page directory size
bic r3, r3, #0xff @ Align the pointer
bic r3, r3, #0x3f00
@@ -578,17 +584,14 @@
mov r9, r0, lsr #18
mov r9, r9, lsl #18 @ start of RAM
add r10, r9, #0x10000000 @ a reasonable RAM size
- mov r1, #0x12
- orr r1, r1, #3 << 10
+ mov r1, #0x12 @ XN|U + section mapping
+ orr r1, r1, #3 << 10 @ AP=11
add r2, r3, #16384
1: cmp r1, r9 @ if virt > start of RAM
-#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
- orrhs r1, r1, #0x08 @ set cacheable
-#else
- orrhs r1, r1, #0x0c @ set cacheable, bufferable
-#endif
- cmp r1, r10 @ if virt > end of RAM
- bichs r1, r1, #0x0c @ clear cacheable, bufferable
+ cmphs r10, r1 @ && end of RAM > virt
+ bic r1, r1, #0x1c @ clear XN|U + C + B
+ orrlo r1, r1, #0x10 @ Set XN|U for non-RAM
+ orrhs r1, r1, r6 @ set RAM section settings
str r1, [r0], #4 @ 1:1 mapping
add r1, r1, #1048576
teq r0, r2
@@ -599,7 +602,7 @@
* so there is no map overlap problem for up to 1 MB compressed kernel.
* If the execution is in RAM then we would only be duplicating the above.
*/
- mov r1, #0x1e
+ orr r1, r6, #0x04 @ ensure B is set for this
orr r1, r1, #3 << 10
mov r2, pc
mov r2, r2, lsr #20
@@ -620,6 +623,7 @@
__armv4_mmu_cache_on:
mov r12, lr
#ifdef CONFIG_MMU
+ mov r6, #CB_BITS | 0x12 @ U
bl __setup_mmu
mov r0, #0
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
@@ -641,6 +645,7 @@
#ifdef CONFIG_MMU
mrc p15, 0, r11, c0, c1, 4 @ read ID_MMFR0
tst r11, #0xf @ VMSA
+ movne r6, #CB_BITS | 0x02 @ !XN
blne __setup_mmu
mov r0, #0
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
@@ -655,7 +660,7 @@
orr r0, r0, #1 << 25 @ big-endian page tables
#endif
orrne r0, r0, #1 @ MMU enabled
- movne r1, #-1
+ movne r1, #0xfffffffd @ domain 0 = client
mcrne p15, 0, r3, c2, c0, 0 @ load page table pointer
mcrne p15, 0, r1, c3, c0, 0 @ load domain access control
#endif
@@ -668,6 +673,7 @@
__fa526_cache_on:
mov r12, lr
+ mov r6, #CB_BITS | 0x12 @ U
bl __setup_mmu
mov r0, #0
mcr p15, 0, r0, c7, c7, 0 @ Invalidate whole cache
@@ -682,6 +688,7 @@
__arm6_mmu_cache_on:
mov r12, lr
+ mov r6, #CB_BITS | 0x12 @ U
bl __setup_mmu
mov r0, #0
mcr p15, 0, r0, c7, c0, 0 @ invalidate whole cache v3
diff --git a/arch/arm/boot/dts/mpq8092.dtsi b/arch/arm/boot/dts/mpq8092.dtsi
index f9e3bd5..0ab0a0c 100644
--- a/arch/arm/boot/dts/mpq8092.dtsi
+++ b/arch/arm/boot/dts/mpq8092.dtsi
@@ -271,6 +271,12 @@
qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
qcom,current-limit = <800>;
};
+
+ sata: sata@fc580000 {
+ compatible = "qcom,msm-ahci";
+ reg = <0xfc580000 0x17c>;
+ interrupts = <0 243 0>;
+ };
};
&gdsc_venus {
diff --git a/arch/arm/boot/dts/msm-pm8019.dtsi b/arch/arm/boot/dts/msm-pm8019.dtsi
index 2105e8a..322e601 100755
--- a/arch/arm/boot/dts/msm-pm8019.dtsi
+++ b/arch/arm/boot/dts/msm-pm8019.dtsi
@@ -156,13 +156,15 @@
pm8019_vadc: vadc@3100 {
compatible = "qcom,qpnp-vadc";
reg = <0x3100 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
interrupts = <0x0 0x31 0x0>;
qcom,adc-bit-resolution = <15>;
qcom,adc-vdd-reference = <1800>;
chan@8 {
label = "die_temp";
- qcom,channel-num = <8>;
+ reg = <8>;
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "absolute";
@@ -173,7 +175,7 @@
chan@9 {
label = "ref_625mv";
- qcom,channel-num = <9>;
+ reg = <9>;
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "absolute";
@@ -182,9 +184,9 @@
qcom,fast-avg-setup = <0>;
};
- chan@10 {
+ chan@a {
label = "ref_1250v";
- qcom,channel-num = <10>;
+ reg = <0xa>;
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "absolute";
diff --git a/arch/arm/boot/dts/msm-pm8026.dtsi b/arch/arm/boot/dts/msm-pm8026.dtsi
new file mode 100644
index 0000000..94db3ea
--- /dev/null
+++ b/arch/arm/boot/dts/msm-pm8026.dtsi
@@ -0,0 +1,18 @@
+/* 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.
+ */
+
+&spmi_bus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupt-controller;
+ #interrupt-cells = <3>;
+};
diff --git a/arch/arm/boot/dts/msm-pm8110.dtsi b/arch/arm/boot/dts/msm-pm8110.dtsi
new file mode 100644
index 0000000..94db3ea
--- /dev/null
+++ b/arch/arm/boot/dts/msm-pm8110.dtsi
@@ -0,0 +1,18 @@
+/* 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.
+ */
+
+&spmi_bus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupt-controller;
+ #interrupt-cells = <3>;
+};
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index fe7b3e9..098f543 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -77,6 +77,7 @@
qcom,bms-calculate-soc-ms = <20000>;
qcom,bms-chg-term-ua = <100000>;
qcom,bms-batt-type = <0>;
+ qcom,bms-use-external-rsense;
qcom,bms-iadc@3800 {
reg = <0x3800 0x100>;
@@ -132,8 +133,10 @@
qcom,chg-vddmax-mv = <4200>;
qcom,chg-vddsafe-mv = <4200>;
qcom,chg-vinmin-mv = <4200>;
+ qcom,chg-vbatdet-mv = <4100>;
qcom,chg-ibatmax-ma = <1500>;
qcom,chg-ibatterm-ma = <200>;
+ qcom,chg-ibatsafe-ma = <1500>;
qcom,chg-chgr@1000 {
status = "disabled";
@@ -492,6 +495,8 @@
vadc@3100 {
compatible = "qcom,qpnp-vadc";
reg = <0x3100 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
interrupts = <0x0 0x31 0x0>;
interrupt-names = "eoc-int-en-set";
qcom,adc-bit-resolution = <15>;
@@ -499,7 +504,7 @@
chan@0 {
label = "usb_in";
- qcom,channel-num = <0>;
+ reg = <0>;
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <4>;
qcom,calibration-type = "absolute";
@@ -510,7 +515,7 @@
chan@1 {
label = "dc_in";
- qcom,channel-num = <1>;
+ reg = <1>;
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <4>;
qcom,calibration-type = "absolute";
@@ -521,7 +526,7 @@
chan@2 {
label = "vchg_sns";
- qcom,channel-num = <2>;
+ reg = <2>;
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <3>;
qcom,calibration-type = "absolute";
@@ -532,7 +537,7 @@
chan@3 {
label = "spare1";
- qcom,channel-num = <3>;
+ reg = <3>;
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <6>;
qcom,calibration-type = "absolute";
@@ -543,7 +548,7 @@
chan@4 {
label = "spare2";
- qcom,channel-num = <4>;
+ reg = <4>;
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <6>;
qcom,calibration-type = "absolute";
@@ -554,7 +559,7 @@
chan@5 {
label = "vcoin";
- qcom,channel-num = <5>;
+ reg = <5>;
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <1>;
qcom,calibration-type = "absolute";
@@ -565,7 +570,7 @@
chan@6 {
label = "vbat_sns";
- qcom,channel-num = <6>;
+ reg = <6>;
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <1>;
qcom,calibration-type = "absolute";
@@ -576,7 +581,7 @@
chan@7 {
label = "vph_pwr";
- qcom,channel-num = <7>;
+ reg = <7>;
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <1>;
qcom,calibration-type = "absolute";
@@ -587,7 +592,7 @@
chan@8 {
label = "die_temp";
- qcom,channel-num = <8>;
+ reg = <8>;
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "absolute";
@@ -598,7 +603,7 @@
chan@9 {
label = "ref_625mv";
- qcom,channel-num = <9>;
+ reg = <9>;
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "absolute";
@@ -607,9 +612,9 @@
qcom,fast-avg-setup = <0>;
};
- chan@10 {
+ chan@a {
label = "ref_1250v";
- qcom,channel-num = <10>;
+ reg = <0xa>;
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "absolute";
@@ -618,9 +623,9 @@
qcom,fast-avg-setup = <0>;
};
- chan@48 {
+ chan@30 {
label = "batt_therm";
- qcom,channel-num = <48>;
+ reg = <0x30>;
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "ratiometric";
@@ -629,9 +634,9 @@
qcom,fast-avg-setup = <0>;
};
- chan@49 {
+ chan@31 {
label = "batt_id";
- qcom,channel-num = <49>;
+ reg = <0x31>;
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "ratiometric";
@@ -640,9 +645,9 @@
qcom,fast-avg-setup = <0>;
};
- chan@178 {
+ chan@b2 {
label = "xo_therm_pu2";
- qcom,channel-num = <178>;
+ reg = <0xb2>;
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "ratiometric";
@@ -651,9 +656,9 @@
qcom,fast-avg-setup = <0>;
};
- chan@179 {
+ chan@b3 {
label = "msm_therm";
- qcom,channel-num = <179>;
+ reg = <0xb3>;
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "ratiometric";
@@ -662,9 +667,9 @@
qcom,fast-avg-setup = <0>;
};
- chan@180 {
+ chan@b4 {
label = "emmc_therm";
- qcom,channel-num = <180>;
+ reg = <0xb4>;
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "ratiometric";
@@ -673,9 +678,9 @@
qcom,fast-avg-setup = <0>;
};
- chan@181 {
+ chan@b5 {
label = "pa_therm1";
- qcom,channel-num = <181>;
+ reg = <0xb5>;
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "ratiometric";
@@ -684,9 +689,9 @@
qcom,fast-avg-setup = <0>;
};
- chan@183 {
+ chan@b7 {
label = "pa_therm2";
- qcom,channel-num = <183>;
+ reg = <0xb7>;
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "ratiometric";
@@ -695,9 +700,9 @@
qcom,fast-avg-setup = <0>;
};
- chan@184 {
+ chan@b8 {
label = "quiet_therm";
- qcom,channel-num = <184>;
+ reg = <0xb8>;
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "ratiometric";
@@ -706,9 +711,9 @@
qcom,fast-avg-setup = <0>;
};
- chan@185 {
+ chan@b9 {
label = "usb_id";
- qcom,channel-num = <185>;
+ reg = <0xb9>;
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "ratiometric";
@@ -721,6 +726,8 @@
iadc@3600 {
compatible = "qcom,qpnp-iadc";
reg = <0x3600 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
interrupts = <0x0 0x36 0x0>;
interrupt-names = "eoc-int-en-set";
qcom,adc-bit-resolution = <16>;
@@ -729,7 +736,7 @@
chan@0 {
label = "internal_rsense";
- qcom,channel-num = <0>;
+ reg = <0>;
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <1>;
qcom,calibration-type = "absolute";
@@ -738,6 +745,82 @@
qcom,fast-avg-setup = <0>;
};
};
+
+ qcom,vadc@3400 {
+ compatible = "qcom,qpnp-adc-tm";
+ reg = <0x3400 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0x0 0x34 0x0>,
+ <0x0 0x34 0x3>,
+ <0x0 0x34 0x4>;
+ interrupt-names = "eoc-int-en-set",
+ "high-thr-en-set",
+ "low-thr-en-set";
+ qcom,adc-bit-resolution = <15>;
+ qcom,adc-vdd-reference = <1800>;
+
+ /* Channel Node */
+ chan@b9 {
+ label = "usb_id";
+ reg = <0xb9>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ qcom,btm-channel-number = <0x48>;
+ };
+
+ chan@30 {
+ label = "batt_therm";
+ reg = <0x30>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <1>;
+ qcom,hw-settle-time = <0xf>;
+ qcom,fast-avg-setup = <0>;
+ qcom,btm-channel-number = <0x68>;
+ };
+
+ chan@b5 {
+ label = "pa_therm1";
+ reg = <0xb5>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ qcom,btm-channel-number = <0x70>;
+ };
+
+ chan@b7 {
+ label = "pa_therm2";
+ reg = <0xb7>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ qcom,btm-channel-number = <0x78>;
+ };
+
+ chan@b4 {
+ label = "emmc_therm";
+ reg = <0xb4>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ qcom,btm-channel-number = <0x80>;
+ };
+ };
};
qcom,pm8941@1 {
diff --git a/arch/arm/boot/dts/msm8226-sim.dts b/arch/arm/boot/dts/msm8226-sim.dts
index 41ac69d..9a0ec17 100644
--- a/arch/arm/boot/dts/msm8226-sim.dts
+++ b/arch/arm/boot/dts/msm8226-sim.dts
@@ -23,3 +23,54 @@
status = "ok";
};
};
+
+&sdcc1 {
+ qcom,vdd-always-on;
+ qcom,vdd-lpm-sup;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <800 500000>;
+
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <250 154000>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+ qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+ vdd-supply = <&pm8026_l17>;
+ vdd-io-supply = <&pm8026_l6>;
+ qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+ qcom,sup-voltages = <2950 2950>;
+
+ qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+ qcom,nonremovable;
+ status = "ok";
+};
+
+&sdcc2 {
+ vdd-supply = <&pm8026_l18>;
+ vdd-io-supply = <&pm8026_l21>;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <9000 800000>;
+
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-lpm-sup;
+ qcom,vdd-io-voltage-level = <1800000 2950000>;
+ qcom,vdd-io-current-level = <6 22000>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ 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,sup-voltages = <2950 2950>;
+
+ qcom,xpc;
+ qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+ qcom,current-limit = <800>;
+
+ status = "ok";
+};
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index a69e1b7..475ed40 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -32,6 +32,7 @@
interrupt-controller;
#interrupt-cells = <2>;
reg = <0xfd510000 0x4000>;
+ gpio-controller;
#gpio-cells = <2>;
interrupts = <0 208 0>;
};
@@ -159,6 +160,165 @@
};
};
+ sdcc1: qcom,sdcc@f9824000 {
+ cell-index = <1>; /* SDC1 eMMC slot */
+ compatible = "qcom,msm-sdcc";
+
+ reg = <0xf9824000 0x800>,
+ <0xf9824800 0x100>,
+ <0xf9804000 0x7000>;
+ reg-names = "core_mem", "dml_mem", "bam_mem";
+ interrupts = <0 123 0>, <0 137 0>;
+ interrupt-names = "core_irq", "bam_irq";
+
+ qcom,bus-width = <8>;
+ status = "disabled";
+ };
+
+ sdcc2: qcom,sdcc@f98a4000 {
+ cell-index = <2>; /* SDC2 SD card slot */
+ compatible = "qcom,msm-sdcc";
+
+ reg = <0xf98a4000 0x800>,
+ <0xf98a4800 0x100>,
+ <0xf9884000 0x7000>;
+ reg-names = "core_mem", "dml_mem", "bam_mem";
+ interrupts = <0 125 0>, <0 220 0>;
+ interrupt-names = "core_irq", "bam_irq";
+
+ qcom,bus-width = <4>;
+ status = "disabled";
+ };
+
+ spmi_bus: qcom,spmi@fc4c0000 {
+ cell-index = <0>;
+ compatible = "qcom,spmi-pmic-arb";
+ reg = <0xfc4cf000 0x1000>,
+ <0Xfc4cb000 0x1000>;
+ /* 190,ee0_krait_hlos_spmi_periph_irq */
+ /* 187,channel_0_krait_hlos_trans_done_irq */
+ interrupts = <0 190 0>, <0 187 0>;
+ qcom,not-wakeup;
+ qcom,pmic-arb-ee = <0>;
+ qcom,pmic-arb-channel = <0>;
+ qcom,pmic-arb-ppid-map = <0x001000a0>, /* PM8026_0 */
+ <0x005000a2>, /* INTERRUPT */
+ <0x006000a3>, /* SPMI_0 */
+ <0x00800000>, /* PON0 */
+ <0x00a000a5>, /* VREF_LPDDR3 */
+ <0x01000001>, /* SMBB_CHG */
+ <0x01100002>, /* SMBB_BUCK */
+ <0x01200003>, /* SMBB_BIF */
+ <0x01300004>, /* SMBB_USB */
+ <0x01500005>, /* SMBB_BOOST */
+ <0x01600006>, /* SMBB_MISC */
+ <0x02800009>, /* COINCELL */
+ <0x02c000a6>, /* MBG */
+ <0x0310000a>, /* VADC1_USR */
+ <0x03200041>, /* VADC1_MDM */
+ <0x0330000b>, /* VADC1_BMS */
+ <0x0340000c>, /* VADC2_BTM */
+ <0x0360000d>, /* IADC1_USR */
+ <0x03700042>, /* IADC1_MDM */
+ <0x0380000e>, /* IADC1_BMS */
+ <0x0400000f>, /* BMS_1 */
+ <0x050000a7>, /* SHARED_XO */
+ <0x051000a8>, /* BB_CLK1 */
+ <0x05200010>, /* BB_CLK2 */
+ <0x05a000ac>, /* SLEEP_CLK */
+ <0x06000045>, /* RTC_RW */
+ <0x06100012>, /* RTC_ALARM */
+ <0x070000ae>, /* PBS_CORE */
+ <0x071000af>, /* PBS_CLIENT_1 */
+ <0x072000b0>, /* PBS_CLIENT_2 */
+ <0x073000b1>, /* PBS_CLIENT_3 */
+ <0x074000b2>, /* PBS_CLIENT_4 */
+ <0x075000b3>, /* PBS_CLIENT_5 */
+ <0x076000b4>, /* PBS_CLIENT_6 */
+ <0x07700046>, /* PBS_CLIENT_7 */
+ <0x07800047>, /* PBS_CLIENT_8 */
+ <0x079000b5>, /* PBS_CLIENT_9 */
+ <0x07a000b6>, /* PBS_CLIENT_10 */
+ <0x07b000b7>, /* PBS_CLIENT_11 */
+ <0x07c000b8>, /* PBS_CLIENT_12 */
+ <0x07d000b9>, /* PBS_CLIENT_13 */
+ <0x07e000ba>, /* PBS_CLIENT_14 */
+ <0x07f000bb>, /* PBS_CLIENT_15 */
+ <0x0a0000bd>, /* MPP_1 */
+ <0x0a100014>, /* MPP_2 */
+ <0x0a200015>, /* MPP_3 */
+ <0x0a300016>, /* MPP_4 */
+ <0x0a400048>, /* MPP_5 */
+ <0x0a500017>, /* MPP_6 */
+ <0x0a600018>, /* MPP_7 */
+ <0x0a700049>, /* MPP_8 */
+ <0x0c000019>, /* GPIO_1 */
+ <0x0c10001a>, /* GPIO_2 */
+ <0x0c20004a>, /* GPIO_3 */
+ <0x0c30004b>, /* GPIO_4 */
+ <0x0c40001b>, /* GPIO_5 */
+ <0x0c50001c>, /* GPIO_6 */
+ <0x0c60001d>, /* GPIO_7 */
+ <0x0c70004c>, /* GPIO_8 */
+ <0x0fe000be>, /* TRIM_0 */
+ <0x110000bf>, /* BUCK_CMN_1 */
+ <0x114000c0>, /* SMPS1 */
+ <0x115000c1>, /* FTPS1_1 */
+ <0x116000c2>, /* BUCK_FREQ_1 */
+ <0x1170001e>, /* SMPS2 */
+ <0x1180001f>, /* FTPS1_2 */
+ <0x11900020>, /* BUCK_FREQ_2 */
+ <0x11a000c3>, /* SMPS3 */
+ <0x11b000c4>, /* SMPS_3_PS1 */
+ <0x11c000c5>, /* BUCK_FREQ_3 */
+ <0x11d000c6>, /* SMPS4 */
+ <0x11e000c7>, /* SMPS_4_PS1 */
+ <0x11f000c8>, /* BUCK_FREQ_4 */
+ <0x120000c9>, /* SMPS5 */
+ <0x121000ca>, /* SMPS_5_PS1 */
+ <0x122000cb>, /* BUCK_FREQ_5 */
+ <0x140000cc>, /* LDO_1 */
+ <0x141000cd>, /* LDO_2 */
+ <0x142000ce>, /* LDO_3 */
+ <0x143000cf>, /* LDO_4 */
+ <0x144000d0>, /* LDO_5 */
+ <0x145000d1>, /* LDO_6 */
+ <0x146000d2>, /* LDO_7 */
+ <0x147000d3>, /* LDO_8 */
+ <0x148000d4>, /* LDO_9 */
+ <0x149000d5>, /* LDO_10 */
+ <0x14a000d6>, /* LDO_11 */
+ <0x14b000d7>, /* LDO_12 */
+ <0x14c000d8>, /* LDO_13 */
+ <0x14d000d9>, /* LDO_14 */
+ <0x14e000da>, /* LDO_15 */
+ <0x14f000db>, /* LDO_16 */
+ <0x150000dc>, /* LDO_17 */
+ <0x151000dd>, /* LDO_18 */
+ <0x152000de>, /* LDO_19 */
+ <0x153000df>, /* LDO_20 */
+ <0x154000e0>, /* LDO_21 */
+ <0x155000e1>, /* LDO_22 */
+ <0x156000e2>, /* LDO_23 */
+ <0x157000e3>, /* LDO_24 */
+ <0x158000e4>, /* LDO_25 */
+ <0x159000e5>, /* LDO_26 */
+ <0x15a000e6>, /* LDO_27 */
+ <0x15b000e7>, /* LDO_28 */
+ <0x180000e8>, /* LVS_1 */
+ <0x1b0000e9>, /* LPG_LUT */
+ <0x1b1000ea>, /* LPG_CHAN_1 */
+ <0x1b200023>, /* LPG_CHAN_2 */
+ <0x1b300024>, /* LPG_CHAN_3 */
+ <0x1b400025>, /* LPG_CHAN_4 */
+ <0x1b500026>, /* LPG_CHAN_5 */
+ <0x1b600027>, /* LPG_CHAN_6 */
+ <0x1bc00028>, /* PWM_3D */
+ <0x1c000029>, /* VIB1 */
+ <0x1d30002a>, /* FLASH_DRV */
+ <0x1d80002b>; /* WLED */
+ };
+
};
&gdsc_venus {
@@ -186,3 +346,4 @@
};
/include/ "msm8226-regulator.dtsi"
+/include/ "msm-pm8026.dtsi"
diff --git a/arch/arm/boot/dts/msm8910.dtsi b/arch/arm/boot/dts/msm8910.dtsi
index e1e608b..8ad4eda 100644
--- a/arch/arm/boot/dts/msm8910.dtsi
+++ b/arch/arm/boot/dts/msm8910.dtsi
@@ -33,6 +33,7 @@
interrupt-controller;
#interrupt-cells = <2>;
reg = <0xfd510000 0x4000>;
+ gpio-controller;
#gpio-cells = <2>;
interrupts = <0 208 0>;
};
@@ -215,6 +216,96 @@
qcom,pet-time = <10000>;
qcom,ipi-ping = <1>;
};
+
+ spmi_bus: qcom,spmi@fc4c0000 {
+ cell-index = <0>;
+ compatible = "qcom,spmi-pmic-arb";
+ reg = <0xfc4cf000 0x1000>,
+ <0Xfc4cb000 0x1000>;
+ /* 190,ee0_krait_hlos_spmi_periph_irq */
+ /* 187,channel_0_krait_hlos_trans_done_irq */
+ interrupts = <0 190 0>, <0 187 0>;
+ qcom,not-wakeup;
+ qcom,pmic-arb-ee = <0>;
+ qcom,pmic-arb-channel = <0>;
+ qcom,pmic-arb-ppid-map = <0x001000a0>, /* PM8110 */
+ <0x005000a2>, /* INTERRUPT */
+ <0x006000a3>, /* SPMI_0 */
+ <0x00800000>, /* PON0 */
+ <0x01000002>, /* SMBB_CHG */
+ <0x01100003>, /* SMBB_BUCK */
+ <0x01200004>, /* SMBB_BIF */
+ <0x01300005>, /* SMBB_USB */
+ <0x01500006>, /* SMBB_BOOST */
+ <0x01600007>, /* SMBB_MISC */
+ <0x0280000a>, /* COINCELL */
+ <0x02c000a5>, /* MBG */
+ <0x0310000b>, /* VADC1_LC_USR */
+ <0x03200041>, /* VADC3_LC_MDM */
+ <0x0330000c>, /* VADC3_LC_BMS */
+ <0x0340000d>, /* VADC2_LC_BTM */
+ <0x0360000e>, /* IADC1_USR */
+ <0x03700042>, /* IADC2_MDM */
+ <0x0380000f>, /* IADC2_BMS */
+ <0x04000010>, /* BMS_1 */
+ <0x050000a6>, /* SHARED_XO */
+ <0x051000a7>, /* BB_CLK1 */
+ <0x054000a8>, /* RF_CLK1 */
+ <0x055000a9>, /* RF_CLK1 */
+ <0x05a000ab>, /* SLEEP_CLK */
+ <0x06000043>, /* RTC_RW */
+ <0x06100011>, /* RTC_ALARM */
+ <0x070000ac>, /* PBS_CORE */
+ <0x071000ad>, /* PBS_CLIENT_1 */
+ <0x072000ae>, /* PBS_CLIENT_2 */
+ <0x07300013>, /* PBS_CLIENT_3 */
+ <0x07400044>, /* PBS_CLIENT_4 */
+ <0x0a000014>, /* MPP_1 */
+ <0x0a100015>, /* MPP_2 */
+ <0x0a200016>, /* MPP_3 */
+ <0x0a300045>, /* MPP_4 */
+ <0x0c000046>, /* GPIO_1 */
+ <0x0c1000f0>, /* GPIO_2 */
+ <0x0c2000af>, /* GPIO_3 */
+ <0x0c300047>, /* GPIO_4 */
+ <0x0fe000b0>, /* TRIM_0 */
+ <0x110000b1>, /* BUCK_CMN_1 */
+ <0x11400048>, /* SMPS1 */
+ <0x115000b2>, /* SMPS_1_PS1 */
+ <0x116000b3>, /* BUCK_FREQ_1 */
+ <0x11700017>, /* SMPS2 */
+ <0x11800018>, /* FTPS1_2 */
+ <0x11900019>, /* BUCK_FREQ_2 */
+ <0x11a000b4>, /* SMPS3 */
+ <0x11b000b5>, /* SMPS_3_PS1 */
+ <0x11c000b6>, /* BUCK_FREQ_3 */
+ <0x11d000b7>, /* SMPS4 */
+ <0x11e000b8>, /* SMPS_4_PS1 */
+ <0x11f000b9>, /* BUCK_FREQ_4 */
+ <0x140000ba>, /* LDO_1 */
+ <0x141000bb>, /* LDO_2 */
+ <0x142000bc>, /* LDO_3 */
+ <0x143000bd>, /* LDO_4 */
+ <0x144000be>, /* LDO_5 */
+ <0x145000bf>, /* LDO_6 */
+ <0x146000c0>, /* LDO_7 */
+ <0x147000c1>, /* LDO_8 */
+ <0x148000c2>, /* LDO_9 */
+ <0x149000c3>, /* LDO_10 */
+ <0x14a000c4>, /* LDO_11 */
+ <0x14b000c5>, /* LDO_12 */
+ <0x14c000c6>, /* LDO_13 */
+ <0x14d000c7>, /* LDO_14 */
+ <0x14e000c8>, /* LDO_15 */
+ <0x14f000c9>, /* LDO_16 */
+ <0x150000ca>, /* LDO_17 */
+ <0x151000cb>, /* LDO_18 */
+ <0x152000cc>, /* LDO_19 */
+ <0x153000cd>, /* LDO_20 */
+ <0x154000ce>, /* LDO_21 */
+ <0x155000cf>; /* LDO_22 */
+ };
+
};
&gdsc_vfe {
@@ -250,3 +341,4 @@
};
/include/ "msm8910-regulator.dtsi"
+/include/ "msm-pm8110.dtsi"
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index 570eb0f..d922b36 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -233,10 +233,15 @@
wp-gpios = <&pm8941_gpios 29 0x1>;
};
+&usb3 {
+ qcom,otg-capability;
+};
+
&pm8941_chg {
status = "ok";
qcom,chg-charging-disabled;
+ qcom,chg-use-default-batt-values;
qcom,chg-chgr@1000 {
status = "ok";
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index e4211b3..9eade15 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -252,6 +252,10 @@
cd-gpios = <&msmgpio 62 0x1>;
};
+&usb3 {
+ qcom,otg-capability;
+};
+
&pm8941_chg {
status = "ok";
@@ -491,3 +495,22 @@
mpp@a300 { /* MPP 4 */
};
};
+
+&spi_epm {
+ epm-adc@0 {
+ compatible = "cy,epm-adc-cy8c5568lti-114";
+ reg = <0>;
+ interrupt-parent = <&msmgpio>;
+ spi-max-frequency = <960000>;
+ qcom,channels = <31>;
+ qcom,gain = <100 100 100 50 100 100 1 100 1 50
+ 1 100 1 100 50 50 50 50 50 50
+ 100 50 100 50 50 50 50 50 50 50
+ 50>;
+ qcom,rsense = <2 2 2 200 20 2 1 2 1 30
+ 1 10 1 30 50 30 500 30 100 30
+ 100 500 20 200 1000 20 1000 1000 70 200
+ 50>;
+ qcom,channel-type = <0x1540>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974-gpu.dtsi b/arch/arm/boot/dts/msm8974-gpu.dtsi
index 6623568..480a034 100644
--- a/arch/arm/boot/dts/msm8974-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8974-gpu.dtsi
@@ -36,8 +36,8 @@
qcom,msm-bus,num-paths = <2>;
qcom,msm-bus,vectors-KBps =
<26 512 0 0>, <89 604 0 0>,
- <26 512 0 2000000>, <89 604 0 3000000>,
- <26 512 0 4000000>, <89 604 0 5000000>,
+ <26 512 0 1600000>, <89 604 0 3000000>,
+ <26 512 0 4000000>, <89 604 0 4500000>,
<26 512 0 6400000>, <89 604 0 7600000>;
/* GDSC oxili regulators */
@@ -108,7 +108,7 @@
qcom,algo-ss-win-size-min-us = <1000000>;
qcom,algo-ss-win-size-max-us = <1000000>;
qcom,algo-ss-util-pct = <95>;
- qcom,algo-ss-iobusy-conv = <100>;
+ qcom,algo-ss-no-corr-below-freq = <0>;
qcom,energy-active-coeff-a = <2492>;
qcom,energy-active-coeff-b = <0>;
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index 7bd1aac..627ba9d 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -245,6 +245,32 @@
qcom,ext-spk-amp-supply = <&ext_5v>;
qcom,ext-spk-amp-gpio = <&pm8841_mpps 1 0>;
};
+
+ hsic_hub {
+ compatible = "qcom,hsic-smsc-hub";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ smsc,reset-gpio = <&pm8941_gpios 8 0x00>;
+ smsc,refclk-gpio = <&pm8941_gpios 16 0x00>;
+ smsc,int-gpio = <&msmgpio 50 0x00>;
+ hub_int-supply = <&pm8941_l10>;
+ hub_vbus-supply = <&ext_5v>;
+
+ hsic@f9a00000 {
+ compatible = "qcom,hsic-host";
+ reg = <0xf9a00000 0x400>;
+ interrupts = <0 136 0>;
+ interrupt-names = "core_irq";
+ HSIC_VDDCX-supply = <&pm8841_s2>;
+ HSIC_GDSC-supply = <&gdsc_usb_hsic>;
+ hsic,strobe-gpio = <&msmgpio 144 0x00>;
+ hsic,data-gpio = <&msmgpio 145 0x00>;
+ hsic,ignore-cal-pad-config;
+ hsic,strobe-pad-offset = <0x2050>;
+ hsic,data-pad-offset = <0x2054>;
+ };
+ };
};
&usb3 {
@@ -294,6 +320,11 @@
};
gpio@c700 { /* GPIO 8 */
+ /* HSIC_HUB-RESET */
+ qcom,mode = <1>; /* DIG_OUT */
+ qcom,pull = <5>; /* PULL_NO */
+ qcom,out-strength = <2>; /* STRENGTH_MED */
+ qcom,master-en = <1>;
};
gpio@c800 { /* GPIO 9 */
@@ -341,6 +372,14 @@
};
gpio@cf00 { /* GPIO 16 */
+ /* HSIC_HUB-INT_N */
+ qcom,mode = <1>;
+ qcom,output-type = <0>;
+ qcom,pull = <5>;
+ qcom,vin-sel = <2>;
+ qcom,out-strength = <3>;
+ qcom,src-sel = <2>;
+ qcom,master-en = <1>;
};
gpio@d000 { /* GPIO 17 */
@@ -520,3 +559,22 @@
qcom,master-en = <1>; /* ENABLE MPP */
};
};
+
+&spi_epm {
+ epm-adc@0 {
+ compatible = "cy,epm-adc-cy8c5568lti-114";
+ reg = <0>;
+ interrupt-parent = <&msmgpio>;
+ spi-max-frequency = <960000>;
+ qcom,channels = <31>;
+ qcom,gain = <50 50 50 50 50 100 50 50 50 50
+ 50 50 50 50 100 50 50 50 50 100
+ 50 50 50 100 50 50 50 1 1 1
+ 1>;
+ qcom,rsense = <40 10 10 25 10 1000 75 25 10 25
+ 33 500 200 10 500 100 33 200 25 100
+ 75 500 50 200 5 5 3 1 1 1
+ 1>;
+ qcom,channel-type = <0xf0000000>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974-mdss.dtsi b/arch/arm/boot/dts/msm8974-mdss.dtsi
index b765611..8d05b1d 100644
--- a/arch/arm/boot/dts/msm8974-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8974-mdss.dtsi
@@ -39,14 +39,15 @@
<0xfc4b8000 0x60F0>;
reg-names = "core_physical", "phy_physical", "qfprom_physical";
+ hpd-gdsc-supply = <&gdsc_mdss>;
hpd-5v-supply = <&pm8941_mvs2>;
core-vdda-supply = <&pm8941_l12>;
core-vcc-supply = <&pm8941_s3>;
- qcom,hdmi-tx-supply-names = "hpd-5v", "core-vdda", "core-vcc";
- qcom,hdmi-tx-supply-type = <1 0 0>;
- qcom,hdmi-tx-min-voltage-level = <0 1800000 1800000>;
- qcom,hdmi-tx-max-voltage-level = <0 1800000 1800000>;
- qcom,hdmi-tx-op-mode = <0 1800000 0>;
+ qcom,hdmi-tx-supply-names = "hpd-gdsc", "hpd-5v", "core-vdda", "core-vcc";
+ qcom,hdmi-tx-supply-type = <1 1 0 0>;
+ qcom,hdmi-tx-min-voltage-level = <0 0 1800000 1800000>;
+ qcom,hdmi-tx-max-voltage-level = <0 0 1800000 1800000>;
+ qcom,hdmi-tx-op-mode = <0 0 1800000 0>;
qcom,hdmi-tx-cec = <&msmgpio 31 0>;
qcom,hdmi-tx-ddc-clk = <&msmgpio 32 0>;
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index 9fb7d0e..48bb5ba 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -476,3 +476,22 @@
qcom,cdc-micbias2-ext-cap;
};
};
+
+&spi_epm {
+ epm-adc@0 {
+ compatible = "cy,epm-adc-cy8c5568lti-114";
+ reg = <0>;
+ interrupt-parent = <&msmgpio>;
+ spi-max-frequency = <960000>;
+ qcom,channels = <31>;
+ qcom,gain = <100 100 100 50 100 100 1 100 1 50
+ 1 100 1 100 50 50 50 50 50 50
+ 100 50 100 50 50 50 50 50 50 50
+ 50>;
+ qcom,rsense = <2 2 2 200 20 2 1 2 1 30
+ 1 10 1 30 50 30 500 30 100 30
+ 100 500 20 200 1000 20 1000 1000 70 200
+ 50>;
+ qcom,channel-type = <0x1540>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974-pm.dtsi b/arch/arm/boot/dts/msm8974-pm.dtsi
index c877134..b8a977b 100644
--- a/arch/arm/boot/dts/msm8974-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-pm.dtsi
@@ -188,10 +188,10 @@
qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
qcom,vdd-dig-upper-bound = <5>; /* MAX */
qcom,vdd-dig-lower-bound = <3>; /* ACTIVE */
- qcom,latency-us = <100>;
- qcom,ss-power = <650>;
- qcom,energy-overhead = <801>;
- qcom,time-overhead = <200>;
+ qcom,latency-us = <1>;
+ qcom,ss-power = <784>;
+ qcom,energy-overhead = <190000>;
+ qcom,time-overhead = <100>;
};
qcom,lpm-level@1 {
@@ -203,10 +203,10 @@
qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
qcom,vdd-dig-upper-bound = <5>; /* MAX */
qcom,vdd-dig-lower-bound = <3>; /* ACTIVE */
- qcom,latency-us = <1500>;
- qcom,ss-power = <200>;
- qcom,energy-overhead = <576000>;
- qcom,time-overhead = <2000>;
+ qcom,latency-us = <75>;
+ qcom,ss-power = <735>;
+ qcom,energy-overhead = <77341>;
+ qcom,time-overhead = <105>;
};
@@ -219,10 +219,10 @@
qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
qcom,vdd-dig-upper-bound = <5>; /* MAX */
qcom,vdd-dig-lower-bound = <3>; /* ACTIVE */
- qcom,latency-us = <2000>;
- qcom,ss-power = <200>;
- qcom,energy-overhead = <576000>;
- qcom,time-overhead = <2000>;
+ qcom,latency-us = <95>;
+ qcom,ss-power = <725>;
+ qcom,energy-overhead = <99500>;
+ qcom,time-overhead = <130>;
};
qcom,lpm-level@3 {
@@ -234,10 +234,10 @@
qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
qcom,vdd-dig-upper-bound = <5>; /* MAX */
qcom,vdd-dig-lower-bound = <3>; /* ACTIVE */
- qcom,latency-us = <8500>;
- qcom,ss-power = <51>;
- qcom,energy-overhead = <1122000>;
- qcom,time-overhead = <8500>;
+ qcom,latency-us = <2000>;
+ qcom,ss-power = <138>;
+ qcom,energy-overhead = <1208400>;
+ qcom,time-overhead = <3200>;
};
qcom,lpm-level@4 {
@@ -245,33 +245,18 @@
qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
qcom,xo = <1>; /* ON */
qcom,l2 = <0>; /* OFF */
- qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
- qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
- qcom,vdd-dig-upper-bound = <5>; /* MAX */
- qcom,vdd-dig-lower-bound = <3>; /* ACTIVE */
- qcom,latency-us = <9000>;
- qcom,ss-power = <51>;
- qcom,energy-overhead = <1130300>;
- qcom,time-overhead = <9000>;
- };
-
- qcom,lpm-level@5 {
- reg = <0x5>;
- qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
- qcom,xo = <1>; /* ON */
- qcom,l2 = <0>; /* OFF */
qcom,vdd-mem-upper-bound = <1050000>; /* ACTIVE */
qcom,vdd-mem-lower-bound = <750000>; /* RETENTION HIGH */
qcom,vdd-dig-upper-bound = <3>; /* ACTIVE */
qcom,vdd-dig-lower-bound = <2>; /* RETENTION HIGH */
- qcom,latency-us = <10000>;
- qcom,ss-power = <51>;
- qcom,energy-overhead = <1130300>;
- qcom,time-overhead = <10000>;
+ qcom,latency-us = <3000>;
+ qcom,ss-power = <110>;
+ qcom,energy-overhead = <1250300>;
+ qcom,time-overhead = <3500>;
};
- qcom,lpm-level@6 {
- reg = <0x6>;
+ qcom,lpm-level@5 {
+ reg = <0x5>;
qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
qcom,xo = <0>; /* OFF */
qcom,l2 = <1>; /* GDHS */
@@ -279,14 +264,14 @@
qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
qcom,vdd-dig-upper-bound = <5>; /* MAX */
qcom,vdd-dig-lower-bound = <3>; /* ACTIVE */
- qcom,latency-us = <12000>;
- qcom,ss-power = <14>;
- qcom,energy-overhead = <2205900>;
- qcom,time-overhead = <12000>;
+ qcom,latency-us = <3000>;
+ qcom,ss-power = <68>;
+ qcom,energy-overhead = <1350200>;
+ qcom,time-overhead = <4000>;
};
- qcom,lpm-level@7 {
- reg = <0x7>;
+ qcom,lpm-level@6 {
+ reg = <0x6>;
qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
qcom,xo = <0>; /* OFF */
qcom,l2 = <0>; /* OFF */
@@ -294,14 +279,14 @@
qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
qcom,vdd-dig-upper-bound = <5>; /* MAX */
qcom,vdd-dig-lower-bound = <3>; /* ACTIVE */
- qcom,latency-us = <18000>;
- qcom,ss-power = <12>;
- qcom,energy-overhead = <2364250>;
- qcom,time-overhead = <18000>;
+ qcom,latency-us = <10300>;
+ qcom,ss-power = <63>;
+ qcom,energy-overhead = <2128000>;
+ qcom,time-overhead = <18200>;
};
- qcom,lpm-level@8 {
- reg = <0x8>;
+ qcom,lpm-level@7 {
+ reg = <0x7>;
qcom,mode= <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
qcom,xo = <0>; /* OFF */
qcom,l2 = <0>; /* OFF */
@@ -309,14 +294,14 @@
qcom,vdd-mem-lower-bound = <750000>; /* RETENTION HIGH */
qcom,vdd-dig-upper-bound = <3>; /* ACTIVE */
qcom,vdd-dig-lower-bound = <2>; /* RETIONTION HIGH */
- qcom,latency-us = <23500>;
+ qcom,latency-us = <18000>;
qcom,ss-power = <10>;
- qcom,energy-overhead = <2667000>;
- qcom,time-overhead = <23500>;
+ qcom,energy-overhead = <3202600>;
+ qcom,time-overhead = <27000>;
};
- qcom,lpm-level@9 {
- reg = <0x9>;
+ qcom,lpm-level@8 {
+ reg = <0x8>;
qcom,mode= <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
qcom,xo = <0>; /* OFF */
qcom,l2 = <0>; /* OFF */
@@ -324,10 +309,10 @@
qcom,vdd-mem-lower-bound = <750000>; /* RETENTION LOW */
qcom,vdd-dig-upper-bound = <2>; /* RETENTION HIGH */
qcom,vdd-dig-lower-bound = <0>; /* RETENTION LOW */
- qcom,latency-us = <29700>;
- qcom,ss-power = <5>;
- qcom,energy-overhead = <2867000>;
- qcom,time-overhead = <30000>;
+ qcom,latency-us = <20000>;
+ qcom,ss-power = <2>;
+ qcom,energy-overhead = <4252000>;
+ qcom,time-overhead = <32000>;
};
};
diff --git a/arch/arm/boot/dts/msm8974-regulator.dtsi b/arch/arm/boot/dts/msm8974-regulator.dtsi
index 2cef567..a7a7c88 100644
--- a/arch/arm/boot/dts/msm8974-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974-regulator.dtsi
@@ -108,9 +108,9 @@
rpm-regulator-smpb4 {
status = "okay";
pm8841_s4: regulator-s4 {
- regulator-min-microvolt = <900000>;
+ regulator-min-microvolt = <815000>;
regulator-max-microvolt = <900000>;
- qcom,init-voltage = <900000>;
+ qcom,init-voltage = <815000>;
status = "okay";
};
};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index a892d24..74b6521 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -321,7 +321,7 @@
qcom,bam-dma-res-pipes = <6>;
};
- spi@f9966000 {
+ spi_epm: spi@f9966000 {
compatible = "qcom,spi-qup-v2";
cell-index = <7>;
reg = <0xf9966000 0x1000>;
@@ -333,23 +333,6 @@
<&msmgpio 54 0>, /* MISO */
<&msmgpio 53 0>; /* MOSI */
cs-gpios = <&msmgpio 55 0>;
-
- epm-adc@0 {
- compatible = "cy,epm-adc-cy8c5568lti-114";
- reg = <0>;
- interrupt-parent = <&msmgpio>;
- spi-max-frequency = <960000>;
- qcom,channels = <31>;
- qcom,gain = <100 100 100 50 100 100 1 100 1 50
- 1 100 1 100 50 50 50 50 50 50
- 100 50 100 50 50 50 50 50 50 50
- 50>;
- qcom,rsense = <2 2 2 200 20 2 1 2 1 30
- 1 10 1 30 50 30 500 30 100 30
- 100 500 20 200 1000 20 1000 1000 70 200
- 50>;
- qcom,channel-type = <0x2a40>;
- };
};
slim_msm: slim@fe12f000 {
@@ -406,7 +389,7 @@
qcom,cdc-micbias2-cfilt-sel = <0x1>;
qcom,cdc-micbias3-cfilt-sel = <0x2>;
qcom,cdc-micbias4-cfilt-sel = <0x2>;
-
+ qcom,cdc-mclk-clk-rate = <9600000>;
qcom,cdc-slim-ifd = "taiko-slim-ifd";
qcom,cdc-slim-ifd-elemental-addr = [00 00 A0 00 17 02];
};
@@ -878,6 +861,14 @@
<11 604 32506 32506>;
};
+ qcom,msm-adsp-sensors {
+ compatible = "qcom,msm-adsp-sensors";
+ qcom,src-id = <11>;
+ qcom,dst-id = <604>;
+ qcom,ab = <32505856>;
+ qcom,ib = <32505856>;
+ };
+
qcom,mss@fc880000 {
compatible = "qcom,pil-q6v5-mss";
reg = <0xfc880000 0x100>,
diff --git a/arch/arm/boot/dts/msm9625-pm.dtsi b/arch/arm/boot/dts/msm9625-pm.dtsi
index dbdddb6..71fcfd6 100644
--- a/arch/arm/boot/dts/msm9625-pm.dtsi
+++ b/arch/arm/boot/dts/msm9625-pm.dtsi
@@ -177,7 +177,8 @@
qcom,ipc-bit-offset = <1>;
qcom,gic-parent = <&intc>;
- qcom,gic-map = <41 172>, /* usb2_hsic_async_wakeup_irq */
+ qcom,gic-map = <47 172>, /* usb2_hsic_async_wakeup_irq */
+ <62 222>, /* ee0_krait_hlos_spmi_periph_irq */
<0xff 208>; /* summary_irq_kpss */
qcom,gpio-parent = <&msmgpio>;
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index dfa5223..6fee4e6 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -87,6 +87,7 @@
android_usb@fc42b0c8 {
compatible = "qcom,android-usb";
reg = <0xfc42b0c8 0xc8>;
+ qcom,android-usb-swfi-latency = <100>;
};
hsic@f9a15000 {
@@ -417,6 +418,7 @@
qcom,cdc-micbias2-cfilt-sel = <0x1>;
qcom,cdc-micbias3-cfilt-sel = <0x2>;
qcom,cdc-micbias4-cfilt-sel = <0x2>;
+ qcom,cdc-mclk-clk-rate = <12288000>;
};
wcd9xxx_codec@77{
@@ -582,9 +584,9 @@
/include/ "msm9625-regulator.dtsi"
&pm8019_vadc {
- chan@49 {
+ chan@31 {
label = "batt_id_therm";
- qcom,channel-num = <49>;
+ reg = <0x31>;
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "ratiometric";
@@ -593,9 +595,9 @@
qcom,fast-avg-setup = <0>;
};
- chan@51 {
+ chan@33 {
label = "pa_therm1";
- qcom,channel-num = <51>;
+ reg = <0x33>;
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "ratiometric";
@@ -604,9 +606,9 @@
qcom,fast-avg-setup = <0>;
};
- chan@52 {
+ chan@34 {
label = "pa_therm2";
- qcom,channel-num = <52>;
+ reg = <0x34>;
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "ratiometric";
@@ -615,9 +617,9 @@
qcom,fast-avg-setup = <0>;
};
- chan@50 {
+ chan@32 {
label = "xo_therm";
- qcom,channel-num = <50>;
+ reg = <0x32>;
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "ratiometric";
@@ -626,9 +628,9 @@
qcom,fast-avg-setup = <0>;
};
- chan@60 {
+ chan@3c {
label = "xo_therm_amux";
- qcom,channel-num = <60>;
+ reg = <0x3c>;
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "ratiometric";
diff --git a/arch/arm/configs/msm8910_defconfig b/arch/arm/configs/msm8910_defconfig
index 28d8f61..0fcfa97 100644
--- a/arch/arm/configs/msm8910_defconfig
+++ b/arch/arm/configs/msm8910_defconfig
@@ -129,8 +129,6 @@
CONFIG_MMC_BLOCK_MINORS=32
CONFIG_MMC_TEST=m
CONFIG_MMC_MSM=y
-CONFIG_SPS=y
-CONFIG_SPS_SUPPORT_NDP_BAM=y
CONFIG_MMC_MSM_SPS_SUPPORT=y
CONFIG_STAGING=y
CONFIG_ANDROID=y
@@ -139,6 +137,8 @@
CONFIG_ANDROID_RAM_CONSOLE=y
CONFIG_ANDROID_TIMED_GPIO=y
CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
CONFIG_MSM_IOMMU=y
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index e5fd0d5..c95472f 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -89,6 +89,7 @@
CONFIG_MSM_EBI_ERP=y
CONFIG_MSM_CACHE_ERP=y
CONFIG_MSM_L1_ERR_PANIC=y
+CONFIG_MSM_L1_RECOV_ERR_PANIC=y
CONFIG_MSM_L1_ERR_LOG=y
CONFIG_MSM_L2_ERP_2BIT_PANIC=y
CONFIG_MSM_DCVS=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index f9d7800..1842b6e 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -90,6 +90,7 @@
CONFIG_MSM_EBI_ERP=y
CONFIG_MSM_CACHE_ERP=y
CONFIG_MSM_L1_ERR_PANIC=y
+CONFIG_MSM_L1_RECOV_ERR_PANIC=y
CONFIG_MSM_L1_ERR_LOG=y
CONFIG_MSM_L2_ERP_PRINT_ACCESS_ERRORS=y
CONFIG_MSM_L2_ERP_1BIT_PANIC=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index 94e2f36..ad6dc6a 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -67,8 +67,11 @@
CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
CONFIG_MSM_OCMEM_DEBUG=y
CONFIG_MSM_OCMEM_NONSECURE=y
+CONFIG_MSM_RTB=y
+CONFIG_MSM_RTB_SEPARATE_CPUS=y
CONFIG_MSM_CACHE_ERP=y
CONFIG_MSM_L1_ERR_PANIC=y
+CONFIG_MSM_L1_RECOV_ERR_PANIC=y
CONFIG_MSM_L1_ERR_LOG=y
CONFIG_MSM_L2_ERP_2BIT_PANIC=y
CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
@@ -219,8 +222,9 @@
CONFIG_GENLOCK_MISCDEVICE=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
-CONFIG_TI_DRV2667=y
CONFIG_QSEECOM=y
+CONFIG_USB_HSIC_SMSC_HUB=y
+CONFIG_TI_DRV2667=y
CONFIG_SCSI=y
CONFIG_SCSI_TGT=y
CONFIG_BLK_DEV_SD=y
@@ -286,6 +290,7 @@
CONFIG_THERMAL_TSENS8974=y
CONFIG_THERMAL_MONITOR=y
CONFIG_THERMAL_QPNP=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
CONFIG_WCD9320_CODEC=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_STUB=y
@@ -299,9 +304,8 @@
CONFIG_V4L_PLATFORM_DRIVERS=y
CONFIG_MSM_CAMERA_V4L2=y
CONFIG_MT9M114=y
-CONFIG_OV2720=y
-CONFIG_MSM_CAMERA_FLASH=y
CONFIG_MSM_CAMERA_LED_TRIGGER_FLASH=y
+CONFIG_OV2720=y
CONFIG_MSM_CAMERA_SENSOR=y
CONFIG_MSM_ACTUATOR=y
CONFIG_MSM_JPEG=y
@@ -333,8 +337,10 @@
CONFIG_SND_USB_AUDIO=y
CONFIG_SND_SOC=y
CONFIG_SND_SOC_MSM8974=y
-CONFIG_USB=y
CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_EHCI_MSM_HSIC=y
CONFIG_USB_ACM=y
CONFIG_USB_STORAGE=y
CONFIG_USB_STORAGE_DATAFAB=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 0428362..ca60319 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -66,8 +66,11 @@
CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
CONFIG_MSM_OCMEM_DEBUG=y
CONFIG_MSM_OCMEM_NONSECURE=y
+CONFIG_MSM_RTB=y
+CONFIG_MSM_RTB_SEPARATE_CPUS=y
CONFIG_MSM_CACHE_ERP=y
CONFIG_MSM_L1_ERR_PANIC=y
+CONFIG_MSM_L1_RECOV_ERR_PANIC=y
CONFIG_MSM_L1_ERR_LOG=y
CONFIG_MSM_L2_ERP_PRINT_ACCESS_ERRORS=y
CONFIG_MSM_L2_ERP_2BIT_PANIC=y
@@ -221,8 +224,9 @@
CONFIG_GENLOCK_MISCDEVICE=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
-CONFIG_TI_DRV2667=y
CONFIG_QSEECOM=y
+CONFIG_USB_HSIC_SMSC_HUB=y
+CONFIG_TI_DRV2667=y
CONFIG_SCSI=y
CONFIG_SCSI_TGT=y
CONFIG_BLK_DEV_SD=y
@@ -286,8 +290,8 @@
CONFIG_SENSORS_QPNP_ADC_CURRENT=y
CONFIG_THERMAL=y
CONFIG_THERMAL_TSENS8974=y
-CONFIG_THERMAL_MONTIOR=y
CONFIG_THERMAL_QPNP=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
CONFIG_WCD9320_CODEC=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_STUB=y
@@ -301,9 +305,8 @@
CONFIG_V4L_PLATFORM_DRIVERS=y
CONFIG_MSM_CAMERA_V4L2=y
CONFIG_MT9M114=y
-CONFIG_OV2720=y
-CONFIG_MSM_CAMERA_FLASH=y
CONFIG_MSM_CAMERA_LED_TRIGGER_FLASH=y
+CONFIG_OV2720=y
CONFIG_MSM_CAMERA_SENSOR=y
CONFIG_MSM_ACTUATOR=y
CONFIG_MSM_JPEG=y
@@ -335,8 +338,10 @@
CONFIG_SND_USB_AUDIO=y
CONFIG_SND_SOC=y
CONFIG_SND_SOC_MSM8974=y
-CONFIG_USB=y
CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_EHCI_MSM_HSIC=y
CONFIG_USB_ACM=y
CONFIG_USB_STORAGE=y
CONFIG_USB_STORAGE_DATAFAB=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index a81b8a3..a3e7b98 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -47,8 +47,10 @@
CONFIG_MSM_PIL=y
CONFIG_MSM_PIL_MSS_QDSP6V5=y
CONFIG_MSM_DIRECT_SCLK_ACCESS=y
+CONFIG_MSM_BUS_SCALING=y
CONFIG_MSM_WATCHDOG_V2=y
CONFIG_MSM_DLOAD_MODE=y
+CONFIG_MSM_ADSP_LOADER=m
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_ARM_ARCH_TIMER=y
@@ -71,7 +73,14 @@
CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V2=y
CONFIG_IPV6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
CONFIG_NETFILTER=y
CONFIG_NETFILTER_DEBUG=y
CONFIG_NETFILTER_NETLINK_QUEUE=y
@@ -83,6 +92,47 @@
CONFIG_NF_CONNTRACK_PPTP=y
CONFIG_NF_CONNTRACK_SIP=y
CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NETFILTER_XT_MARK=y
+CONFIG_NETFILTER_XT_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_IP_SET=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_REJECT_SKERR=y
+CONFIG_IP_NF_TARGET_ULOG=y
+CONFIG_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NATTYPE_MODULE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_TARGET_ECN=y
+CONFIG_IP_NF_TARGET_TTL=y
+CONFIG_IP_NF_RAW=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_MATCH_AH=y
+CONFIG_IP6_NF_MATCH_FRAG=y
+CONFIG_IP6_NF_MATCH_OPTS=y
+CONFIG_IP6_NF_MATCH_HL=y
+CONFIG_IP6_NF_MATCH_IPV6HEADER=y
+CONFIG_IP6_NF_MATCH_MH=y
+CONFIG_IP6_NF_MATCH_RT=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_TARGET_REJECT_SKERR=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_HTB=y
CONFIG_NET_SCH_PRIO=y
@@ -129,7 +179,6 @@
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_QUP=y
-CONFIG_MSM_BUS_SCALING=y
CONFIG_SPI=y
CONFIG_SPI_QUP=y
CONFIG_SPI_SPIDEV=m
@@ -145,6 +194,7 @@
CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
CONFIG_THERMAL=y
CONFIG_THERMAL_TSENS8974=y
+CONFIG_WCD9320_CODEC=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_QPNP=y
@@ -153,6 +203,7 @@
CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_SOC=y
+CONFIG_SND_SOC_MDM9625=y
CONFIG_USB_GADGET=y
CONFIG_USB_CI13XXX_MSM=y
CONFIG_USB_G_ANDROID=y
@@ -169,12 +220,13 @@
CONFIG_RTC_CLASS=y
# CONFIG_RTC_DRV_MSM is not set
CONFIG_RTC_DRV_QPNP=y
-CONFIG_IPA=y
CONFIG_SPS=y
CONFIG_USB_BAM=y
CONFIG_SPS_SUPPORT_BAMDMA=y
CONFIG_SPS_SUPPORT_NDP_BAM=y
CONFIG_QPNP_POWER_ON=y
+CONFIG_IPA=y
+CONFIG_MSM_QDSS=y
CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
CONFIG_YAFFS_FS=y
@@ -184,12 +236,12 @@
CONFIG_NLS_ISO8859_1=y
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_FS=y
CONFIG_SCHEDSTATS=y
CONFIG_TIMER_STATS=y
# CONFIG_DEBUG_PREEMPT is not set
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_ENABLE_DEFAULT_TRACERS=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_USER=y
CONFIG_KEYS=y
@@ -208,58 +260,3 @@
# CONFIG_CRYPTO_HW is not set
CONFIG_CRC_CCITT=y
CONFIG_LIBCRC32C=y
-CONFIG_ENABLE_DEFAULT_TRACERS=y
-CONFIG_MSM_QDSS=y
-CONFIG_IP_MULTICAST=y
-CONFIG_IP_ADVANCED_ROUTER=y
-CONFIG_IP_MULTIPLE_TABLES=y
-CONFIG_IP_MROUTE=y
-CONFIG_IP_PIMSM_V2=y
-CONFIG_IPV6_MULTIPLE_TABLES=y
-CONFIG_IPV6_SUBTREES=y
-CONFIG_NETFILTER_XT_MARK=y
-CONFIG_NETFILTER_XT_CONNMARK=y
-CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=y
-CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
-CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
-CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
-CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
-CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_IP_SET=y
-CONFIG_NF_CONNTRACK_IPV4=y
-CONFIG_IP_NF_IPTABLES=y
-CONFIG_IP_NF_MATCH_AH=y
-CONFIG_IP_NF_MATCH_ECN=y
-CONFIG_IP_NF_MATCH_TTL=y
-CONFIG_IP_NF_FILTER=y
-CONFIG_IP_NF_TARGET_REJECT=y
-CONFIG_IP_NF_TARGET_REJECT_SKERR=y
-CONFIG_IP_NF_TARGET_ULOG=y
-CONFIG_NF_NAT=y
-CONFIG_IP_NF_TARGET_MASQUERADE=y
-CONFIG_IP_NF_TARGET_NETMAP=y
-CONFIG_IP_NF_TARGET_REDIRECT=y
-CONFIG_IP_NF_MANGLE=y
-CONFIG_IP_NF_TARGET_ECN=y
-CONFIG_IP_NF_TARGET_TTL=y
-CONFIG_IP_NF_RAW=y
-CONFIG_NF_CONNTRACK_IPV6=y
-CONFIG_IP6_NF_IPTABLES=y
-CONFIG_IP6_NF_MATCH_AH=y
-CONFIG_IP6_NF_MATCH_FRAG=y
-CONFIG_IP6_NF_MATCH_OPTS=y
-CONFIG_IP6_NF_MATCH_HL=y
-CONFIG_IP6_NF_MATCH_IPV6HEADER=y
-CONFIG_IP6_NF_MATCH_MH=y
-CONFIG_IP6_NF_MATCH_RT=y
-CONFIG_IP6_NF_FILTER=y
-CONFIG_IP6_NF_TARGET_REJECT=y
-CONFIG_IP6_NF_TARGET_REJECT_SKERR=y
-CONFIG_IP6_NF_MANGLE=y
-CONFIG_IP6_NF_RAW=y
-CONFIG_WCD9320_CODEC=y
-CONFIG_SOUND=y
-CONFIG_SND=y
-CONFIG_SND_SOC=y
-CONFIG_SND_SOC_MDM9625=y
-CONFIG_MSM_ADSP_LOADER=m
diff --git a/arch/arm/include/asm/mach/arch.h b/arch/arm/include/asm/mach/arch.h
index 669a626..6ea1a1e 100644
--- a/arch/arm/include/asm/mach/arch.h
+++ b/arch/arm/include/asm/mach/arch.h
@@ -14,6 +14,12 @@
struct meminfo;
struct sys_timer;
struct pt_regs;
+struct smp_operations;
+#ifdef CONFIG_SMP
+#define smp_ops(ops) (&(ops))
+#else
+#define smp_ops(ops) (struct smp_operations *)NULL
+#endif
struct machine_desc {
unsigned int nr; /* architecture number */
@@ -35,6 +41,7 @@
unsigned char reserve_lp1 :1; /* never has lp1 */
unsigned char reserve_lp2 :1; /* never has lp2 */
char restart_mode; /* default restart mode */
+ struct smp_operations *smp; /* SMP operations */
void (*fixup)(struct tag *, char **,
struct meminfo *);
void (*reserve)(void);/* reserve mem blocks */
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 7f74b59..581f4fa 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -95,4 +95,37 @@
extern void smp_send_all_cpu_backtrace(void);
+struct smp_operations {
+#ifdef CONFIG_SMP
+/*
+ * Setup the set of possible CPUs (via set_cpu_possible)
+ */
+void (*smp_init_cpus)(void);
+/*
+ * Initialize cpu_possible map, and enable coherency
+ */
+void (*smp_prepare_cpus)(unsigned int max_cpus);
+
+/*
+ * Perform platform specific initialisation of the specified CPU.
+ */
+void (*smp_secondary_init)(unsigned int cpu);
+/*
+ * Boot a secondary CPU, and assign it the specified idle task.
+ * This also gives us the initial stack to use for this CPU.
+ */
+int (*smp_boot_secondary)(unsigned int cpu, struct task_struct *idle);
+#ifdef CONFIG_HOTPLUG_CPU
+int (*cpu_kill)(unsigned int cpu);
+void (*cpu_die)(unsigned int cpu);
+int (*cpu_disable)(unsigned int cpu);
+#endif
+#endif
+};
+
+/*
+ * set platform specific SMP operations
+ */
+extern void smp_set_ops(struct smp_operations *);
+
#endif /* ifndef __ASM_ARM_SMP_H */
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index b012f0f..4aabf0e 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -974,8 +974,10 @@
unflatten_device_tree();
#ifdef CONFIG_SMP
- if (is_smp())
+ if (is_smp()) {
+ smp_set_ops(mdesc->smp);
smp_init_cpus();
+ }
#endif
reserve_crashkernel();
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index e46fd92..dea0f1f 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -19,7 +19,6 @@
#include <linux/mm.h>
#include <linux/err.h>
#include <linux/cpu.h>
-#include <linux/smp.h>
#include <linux/seq_file.h>
#include <linux/irq.h>
#include <linux/percpu.h>
@@ -27,6 +26,7 @@
#include <linux/completion.h>
#include <linux/atomic.h>
+#include <asm/smp.h>
#include <asm/cacheflush.h>
#include <asm/cpu.h>
#include <asm/cputype.h>
@@ -42,6 +42,7 @@
#include <asm/ptrace.h>
#include <asm/localtimer.h>
#include <asm/smp_plat.h>
+#include <asm/mach/arch.h>
/*
* as from 2.5, kernels no longer have an init_tasks structure
@@ -62,6 +63,14 @@
static DECLARE_COMPLETION(cpu_running);
+static struct smp_operations smp_ops;
+
+void __init smp_set_ops(struct smp_operations *ops)
+{
+ if (ops)
+ smp_ops = *ops;
+};
+
int __cpuinit __cpu_up(unsigned int cpu)
{
struct cpuinfo_arm *ci = &per_cpu(cpu_data, cpu);
@@ -123,9 +132,61 @@
return ret;
}
+/* platform specific SMP operations */
+void __attribute__((weak)) __init smp_init_cpus(void)
+{
+ if (smp_ops.smp_init_cpus)
+ smp_ops.smp_init_cpus();
+}
+
+void __attribute__((weak)) __init platform_smp_prepare_cpus(unsigned int max_cpus)
+{
+ if (smp_ops.smp_prepare_cpus)
+ smp_ops.smp_prepare_cpus(max_cpus);
+}
+
+void __attribute__((weak)) __cpuinit platform_secondary_init(unsigned int cpu)
+{
+ if (smp_ops.smp_secondary_init)
+ smp_ops.smp_secondary_init(cpu);
+}
+
+int __attribute__((weak)) __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+ if (smp_ops.smp_boot_secondary)
+ return smp_ops.smp_boot_secondary(cpu, idle);
+ return -ENOSYS;
+}
+
#ifdef CONFIG_HOTPLUG_CPU
static void percpu_timer_stop(void);
+int __attribute__((weak)) platform_cpu_kill(unsigned int cpu)
+{
+ if (smp_ops.cpu_kill)
+ return smp_ops.cpu_kill(cpu);
+ return 1;
+}
+
+void __attribute__((weak)) platform_cpu_die(unsigned int cpu)
+{
+ if (smp_ops.cpu_die)
+ smp_ops.cpu_die(cpu);
+}
+
+int __attribute__((weak)) platform_cpu_disable(unsigned int cpu)
+{
+ if (smp_ops.cpu_disable)
+ return smp_ops.cpu_disable(cpu);
+
+ /*
+ * By default, allow disabling all CPUs except the first one,
+ * since this is special on a lot of platforms, e.g. because
+ * of clock tick interrupts.
+ */
+ return cpu == 0 ? -EPERM : 0;
+}
+
/*
* __cpu_disable runs on the processor to be shutdown.
*/
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index e6255f2..8dd8579 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -167,7 +167,6 @@
select MSM_NATIVE_RESTART
select DONT_MAP_HOLE_AFTER_MEMBANK0
select MSM_REMOTE_SPINLOCK_SFPB
- select ARCH_SPARSEMEM_ENABLE
select ARCH_HAS_HOLES_MEMORYMODEL
select CLEANCACHE
select QCACHE
@@ -184,6 +183,7 @@
select USE_USER_ACCESSIBLE_TIMERS
select ARM_USE_USER_ACCESSIBLE_TIMERS
select MSM_USE_USER_ACCESSIBLE_TIMERS
+ select MSM_CPU_PWRCTL
config ARCH_MSM8930
bool "MSM8930"
@@ -208,7 +208,6 @@
select MSM_NATIVE_RESTART
select DONT_MAP_HOLE_AFTER_MEMBANK0
select MSM_REMOTE_SPINLOCK_SFPB
- select ARCH_SPARSEMEM_ENABLE
select ARCH_HAS_HOLES_MEMORYMODEL
select MSM_ULTRASOUND_A
select MULTI_IRQ_HANDLER
@@ -221,6 +220,7 @@
select USE_USER_ACCESSIBLE_TIMERS
select ARM_USE_USER_ACCESSIBLE_TIMERS
select MSM_USE_USER_ACCESSIBLE_TIMERS
+ select MSM_CPU_PWRCTL
config ARCH_APQ8064
bool "APQ8064"
@@ -254,6 +254,7 @@
select USE_USER_ACCESSIBLE_TIMERS
select ARM_USE_USER_ACCESSIBLE_TIMERS
select MSM_USE_USER_ACCESSIBLE_TIMERS
+ select MSM_CPU_PWRCTL
config ARCH_MSM8974
bool "MSM8974"
@@ -285,6 +286,7 @@
select MSM_RPM_STATS_LOG
select QMI_ENCDEC
select DONT_MAP_HOLE_AFTER_MEMBANK0
+ select SENSORS_ADSP
config ARCH_MPQ8092
bool "MPQ8092"
@@ -1686,17 +1688,6 @@
endif # CPU_FREQ_MSM
-config MSM_CPU_AVS
- bool "Enable software controlled Adaptive Voltage Scaling (AVS)"
- depends on (ARCH_MSM_SCORPION && QSD_SVS)
- depends on ARCH_QSD8X50
- default n
- select MSM_AVS_HW
- help
- This enables the s/w control of Adaptive Voltage Scaling feature
- in Qualcomm ARMv7 CPUs. It adjusts the voltage for each frequency
- based on feedback from three ring oscillators in the CPU.
-
config MSM_AVS_HW
bool "Enable Adaptive Voltage Scaling (AVS)"
default n
@@ -2492,6 +2483,14 @@
never allowing them to be turned OFF. Both local power
management and RPM assisted power modes are supported.
+config SENSORS_ADSP
+ bool "Enable Sensors Driver Support for ADSP"
+ help
+ Add support for sensors ADSP driver.
+ This driver is used for exercising different sensors use cases,
+ such as for lower-power OCMEM use cases, and for time syncing
+ with ADSP clock.
+
config MSM_RTB
bool "Register tracing"
help
@@ -2540,6 +2539,21 @@
For production builds, you should probably say 'N' here.
+config MSM_L1_RECOV_ERR_PANIC
+ bool "Panic on recoverable L1 cache errors"
+ depends on MSM_CACHE_ERP && MSM_L1_ERR_PANIC
+ help
+ Certain CPU designs may be able to automatically recover from certain
+ kinds of L1 cache errors, even though the L1 cache itself may not
+ support error correction. These errors should not result in any kind
+ of corruption, but their presence is nevertheless an indication of
+ poor system health. To cause the kernel to panic whenever a
+ recoverable L1 cache error is detected, say 'Y' here. This may be
+ useful as a debugging technique if general system instability is
+ suspected.
+
+ For production builds, you should definitely say 'N' here.
+
config MSM_L1_ERR_LOG
bool "Log CPU ERP events to system memory"
depends on MSM_CACHE_ERP
@@ -2715,4 +2729,11 @@
help
Use Device Control Volume as opposed to ALSA volume control.
+config MSM_CPU_PWRCTL
+ bool "Ensures that krait droop detectors are always off"
+ help
+ Droop detector mechanism can adversely affect krait plls during
+ stand alone power collapse operation. Selecting this option
+ ensures that they are always off.
+
endif
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 64fa9e2..ff21190 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -45,20 +45,13 @@
obj-$(CONFIG_MSM_SOC_REV_NONE) += acpuclock-8x50.o
endif
-obj-$(CONFIG_SMP) += headsmp.o
-ifdef CONFIG_ARCH_MSM_CORTEXMP
+obj-$(CONFIG_SMP) += headsmp.o platsmp.o
ifdef CONFIG_ARCH_MSM8625
obj-$(CONFIG_SMP) += platsmp-8625.o
-else
- obj-$(CONFIG_SMP) += platsmp-8910.o
-endif
-else
- obj-$(CONFIG_SMP) += platsmp.o
endif
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
-obj-$(CONFIG_MSM_CPU_AVS) += avs.o
-obj-$(CONFIG_MSM_AVS_HW) += avs_hw.o
+obj-$(CONFIG_MSM_AVS_HW) += avs.o
obj-$(CONFIG_CPU_V6) += idle-v6.o
obj-$(CONFIG_CPU_V7) += idle-v7.o
obj-$(CONFIG_MSM_JTAG) += jtag.o
@@ -305,6 +298,7 @@
obj-$(CONFIG_ARCH_MPQ8092) += board-8092.o board-8092-gpiomux.o
obj-$(CONFIG_ARCH_MSM8226) += board-8226.o board-8226-gpiomux.o
obj-$(CONFIG_ARCH_MSM8910) += board-8910.o board-8910-gpiomux.o
+obj-$(CONFIG_ARCH_MSM8910) += clock-local2.o clock-pll.o clock-8910.o clock-rpm.o clock-voter.o
obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire.o board-sapphire-gpio.o
obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-keypad.o board-sapphire-panel.o
@@ -357,6 +351,7 @@
endif
obj-$(CONFIG_MSM_OCMEM) += ocmem.o ocmem_allocator.o ocmem_notifier.o
obj-$(CONFIG_MSM_OCMEM) += ocmem_sched.o ocmem_api.o ocmem_rdm.o ocmem_core.o
+obj-$(CONFIG_SENSORS_ADSP) += sensors_adsp.o
obj-$(CONFIG_ARCH_MSM7X27) += gpiomux-7x27.o gpiomux-v1.o gpiomux.o
obj-$(CONFIG_ARCH_MSM7X30) += gpiomux-7x30.o gpiomux-v1.o gpiomux.o
@@ -418,3 +413,4 @@
obj-$(CONFIG_MEMORY_HOLE_CARVEOUT) += msm_mem_hole.o
obj-$(CONFIG_MSM_SMCMOD) += smcmod.o
+obj-$(CONFIG_MSM_CPU_PWRCTL) += msm_cpu_pwrctl.o
diff --git a/arch/arm/mach-msm/acpuclock-8064.c b/arch/arm/mach-msm/acpuclock-8064.c
index 8174370..db77a34 100644
--- a/arch/arm/mach-msm/acpuclock-8064.c
+++ b/arch/arm/mach-msm/acpuclock-8064.c
@@ -505,20 +505,20 @@
[0][PVS_FASTER] = {tbl_faster, sizeof(tbl_faster), 25000 },
[1][0] = { tbl_PVS0_1700MHz, sizeof(tbl_PVS0_1700MHz), 0 },
- [1][1] = { tbl_PVS1_1700MHz, sizeof(tbl_PVS1_1700MHz), 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 },
+ [1][1] = { tbl_PVS1_1700MHz, sizeof(tbl_PVS1_1700MHz), 25000 },
+ [1][2] = { tbl_PVS2_1700MHz, sizeof(tbl_PVS2_1700MHz), 25000 },
+ [1][3] = { tbl_PVS3_1700MHz, sizeof(tbl_PVS3_1700MHz), 25000 },
+ [1][4] = { tbl_PVS4_1700MHz, sizeof(tbl_PVS4_1700MHz), 25000 },
+ [1][5] = { tbl_PVS5_1700MHz, sizeof(tbl_PVS5_1700MHz), 25000 },
+ [1][6] = { tbl_PVS6_1700MHz, sizeof(tbl_PVS6_1700MHz), 25000 },
[2][0] = { tbl_PVS0_2000MHz, sizeof(tbl_PVS0_2000MHz), 0 },
- [2][1] = { tbl_PVS1_2000MHz, sizeof(tbl_PVS1_2000MHz), 0 },
- [2][2] = { tbl_PVS2_2000MHz, sizeof(tbl_PVS2_2000MHz), 0 },
- [2][3] = { tbl_PVS3_2000MHz, sizeof(tbl_PVS3_2000MHz), 0 },
- [2][4] = { tbl_PVS4_2000MHz, sizeof(tbl_PVS4_2000MHz), 0 },
- [2][5] = { tbl_PVS5_2000MHz, sizeof(tbl_PVS5_2000MHz), 0 },
- [2][6] = { tbl_PVS6_2000MHz, sizeof(tbl_PVS6_2000MHz), 0 },
+ [2][1] = { tbl_PVS1_2000MHz, sizeof(tbl_PVS1_2000MHz), 25000 },
+ [2][2] = { tbl_PVS2_2000MHz, sizeof(tbl_PVS2_2000MHz), 25000 },
+ [2][3] = { tbl_PVS3_2000MHz, sizeof(tbl_PVS3_2000MHz), 25000 },
+ [2][4] = { tbl_PVS4_2000MHz, sizeof(tbl_PVS4_2000MHz), 25000 },
+ [2][5] = { tbl_PVS5_2000MHz, sizeof(tbl_PVS5_2000MHz), 25000 },
+ [2][6] = { tbl_PVS6_2000MHz, sizeof(tbl_PVS6_2000MHz), 25000 },
};
static struct acpuclk_krait_params acpuclk_8064_params __initdata = {
diff --git a/arch/arm/mach-msm/acpuclock-8625q.c b/arch/arm/mach-msm/acpuclock-8625q.c
index 00022ff..0a6dfbe 100644
--- a/arch/arm/mach-msm/acpuclock-8625q.c
+++ b/arch/arm/mach-msm/acpuclock-8625q.c
@@ -554,7 +554,9 @@
#define MHZ 1000000
-static void __devinit select_freq_plan(unsigned int pvs_voltage)
+static void __devinit select_freq_plan(unsigned int pvs_voltage,
+ unsigned int nominal_vol_uv,
+ unsigned int default_vol_uv)
{
unsigned long pll_mhz[ACPU_PLL_END];
int i;
@@ -628,6 +630,8 @@
*/
for (tbl = acpu_freq_tbl; tbl->a11clk_khz; tbl++) {
if (tbl->a11clk_khz >= 1008000) {
+ if (tbl->a11clk_khz == 1209600)
+ tbl->vdd = default_vol_uv;
/*
* Change voltage as per PVS formula,
* i is initialized above with 2 or 1
@@ -639,11 +643,13 @@
tbl->vdd = max((int)(pvs_voltage - delta[i]), tbl->vdd);
i--;
- }
+ } else if (tbl->a11clk_khz != 600000
+ && tbl->a11clk_khz != 19200)
+ tbl->vdd = nominal_vol_uv;
}
- /* find the backup PLL entry from the table */
+ /* find the backup PLL entry from the table */
for (tbl = acpu_freq_tbl; tbl->a11clk_khz; tbl++) {
if (tbl->pll == ACPU_PLL_2 &&
tbl->a11clk_src_div == 1) {
@@ -723,6 +729,8 @@
{
const struct acpuclk_pdata_8625q *pdata = pdev->dev.platform_data;
unsigned int pvs_voltage = pdata->pvs_voltage_uv;
+ unsigned int nom_vol_uv = pdata->nominal_voltage;
+ unsigned int default_vol_uv = pdata->default_turbo_voltage;
drv_state.max_speed_delta_khz = pdata->acpu_clk_data->
max_speed_delta_khz;
@@ -731,7 +739,7 @@
BUG_ON(IS_ERR(drv_state.ebi1_clk));
mutex_init(&drv_state.lock);
- select_freq_plan(pvs_voltage);
+ select_freq_plan(pvs_voltage, nom_vol_uv, default_vol_uv);
acpuclk_8625q_data.wait_for_irq_khz = find_wait_for_irq_khz();
if (acpuclk_hw_init() < 0)
diff --git a/arch/arm/mach-msm/acpuclock-8625q.h b/arch/arm/mach-msm/acpuclock-8625q.h
index ca2058f..c91e3bd 100644
--- a/arch/arm/mach-msm/acpuclock-8625q.h
+++ b/arch/arm/mach-msm/acpuclock-8625q.h
@@ -23,6 +23,8 @@
struct acpuclk_pdata_8625q {
struct acpuclk_pdata *acpu_clk_data;
unsigned int pvs_voltage_uv;
+ unsigned int nominal_voltage;
+ unsigned int default_turbo_voltage;
};
#endif /* __ARCH_ARM_MACH_MSM_ACPUCLOCK_8625Q_H */
diff --git a/arch/arm/mach-msm/acpuclock-8930ab.c b/arch/arm/mach-msm/acpuclock-8930ab.c
index 96029b4..5003862 100644
--- a/arch/arm/mach-msm/acpuclock-8930ab.c
+++ b/arch/arm/mach-msm/acpuclock-8930ab.c
@@ -243,9 +243,9 @@
/* TODO: Update boost voltage once the pvs data is available */
static struct pvs_table pvs_tables[NUM_SPEED_BINS][NUM_PVS] __initdata = {
-[0][PVS_SLOW] = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow), 0 },
-[0][PVS_NOMINAL] = { acpu_freq_tbl_nom, sizeof(acpu_freq_tbl_nom), 0 },
-[0][PVS_FAST] = { acpu_freq_tbl_fast, sizeof(acpu_freq_tbl_fast), 0 },
+[0][PVS_SLOW] = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow), 0 },
+[0][PVS_NOMINAL] = { acpu_freq_tbl_nom, sizeof(acpu_freq_tbl_nom), 25000 },
+[0][PVS_FAST] = { acpu_freq_tbl_fast, sizeof(acpu_freq_tbl_fast), 25000 },
};
static struct acpuclk_krait_params acpuclk_8930ab_params __initdata = {
diff --git a/arch/arm/mach-msm/acpuclock-8960ab.c b/arch/arm/mach-msm/acpuclock-8960ab.c
index 03a2004..d2e88fb 100644
--- a/arch/arm/mach-msm/acpuclock-8960ab.c
+++ b/arch/arm/mach-msm/acpuclock-8960ab.c
@@ -105,140 +105,142 @@
{ }
};
+#define AVS(x) .avsdscr_setting = (x)
+
static struct acpu_level freq_tbl_PVS0[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 950000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(3), 950000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(3), 975000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(3), 1000000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(3), 1025000 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(3), 1050000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(3), 1075000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(9), 1100000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(9), 1125000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(9), 1150000 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(9), 1175000 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(9), 1200000 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(9), 1225000 },
- { 1, { 1728000, HFPLL, 1, 0x40 }, L2(9), 1250000 },
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 950000, AVS(0x70001F) },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(3), 950000, AVS(0x0) },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(3), 975000, AVS(0x0) },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(3), 1000000, AVS(0x0) },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(3), 1025000, AVS(0x0) },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(3), 1050000, AVS(0x0) },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(3), 1075000, AVS(0x0) },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(9), 1100000, AVS(0x70000D) },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(9), 1125000, AVS(0x0) },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(9), 1150000, AVS(0x0) },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(9), 1175000, AVS(0x0) },
+ { 1, { 1566000, HFPLL, 1, 0x3A }, L2(9), 1200000, AVS(0x0) },
+ { 1, { 1674000, HFPLL, 1, 0x3E }, L2(9), 1225000, AVS(0x0) },
+ { 1, { 1728000, HFPLL, 1, 0x40 }, L2(9), 1250000, AVS(0x70000B) },
{ 0, { 0 } }
};
static struct acpu_level freq_tbl_PVS1[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 925000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(3), 925000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(3), 950000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(3), 975000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(3), 1000000 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(3), 1025000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(3), 1050000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(9), 1075000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(9), 1100000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(9), 1125000 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(9), 1150000 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(9), 1175000 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(9), 1200000 },
- { 1, { 1728000, HFPLL, 1, 0x40 }, L2(9), 1225000 },
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 925000, AVS(0x70001F) },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(3), 925000, AVS(0x0) },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(3), 950000, AVS(0x0) },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(3), 975000, AVS(0x0) },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(3), 1000000, AVS(0x0) },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(3), 1025000, AVS(0x0) },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(3), 1050000, AVS(0x0) },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(9), 1075000, AVS(0x70000D) },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(9), 1100000, AVS(0x0) },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(9), 1125000, AVS(0x0) },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(9), 1150000, AVS(0x0) },
+ { 1, { 1566000, HFPLL, 1, 0x3A }, L2(9), 1175000, AVS(0x0) },
+ { 1, { 1674000, HFPLL, 1, 0x3E }, L2(9), 1200000, AVS(0x0) },
+ { 1, { 1728000, HFPLL, 1, 0x40 }, L2(9), 1225000, AVS(0x70000B) },
{ 0, { 0 } }
};
static struct acpu_level freq_tbl_PVS2[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 900000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(3), 900000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(3), 925000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(3), 950000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(3), 975000 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(3), 1000000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(3), 1025000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(9), 1050000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(9), 1075000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(9), 1100000 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(9), 1125000 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(9), 1150000 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(9), 1175000 },
- { 1, { 1728000, HFPLL, 1, 0x40 }, L2(9), 1200000 },
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 900000, AVS(0x70001F) },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(3), 900000, AVS(0x0) },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(3), 925000, AVS(0x0) },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(3), 950000, AVS(0x0) },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(3), 975000, AVS(0x0) },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(3), 1000000, AVS(0x0) },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(3), 1025000, AVS(0x0) },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(9), 1050000, AVS(0x70000D) },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(9), 1075000, AVS(0x0) },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(9), 1100000, AVS(0x0) },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(9), 1125000, AVS(0x0) },
+ { 1, { 1566000, HFPLL, 1, 0x3A }, L2(9), 1150000, AVS(0x0) },
+ { 1, { 1674000, HFPLL, 1, 0x3E }, L2(9), 1175000, AVS(0x0) },
+ { 1, { 1728000, HFPLL, 1, 0x40 }, L2(9), 1200000, AVS(0x70000B) },
{ 0, { 0 } }
};
static struct acpu_level freq_tbl_PVS3[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 900000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(3), 900000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(3), 900000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(3), 925000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(3), 950000 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(3), 975000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(3), 1000000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(9), 1025000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(9), 1050000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(9), 1075000 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(9), 1100000 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(9), 1125000 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(9), 1150000 },
- { 1, { 1728000, HFPLL, 1, 0x40 }, L2(9), 1175000 },
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 900000, AVS(0x70001F) },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(3), 900000, AVS(0x0) },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(3), 900000, AVS(0x0) },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(3), 925000, AVS(0x0) },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(3), 950000, AVS(0x0) },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(3), 975000, AVS(0x0) },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(3), 1000000, AVS(0x0) },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(9), 1025000, AVS(0x70000D) },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(9), 1050000, AVS(0x0) },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(9), 1075000, AVS(0x0) },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(9), 1100000, AVS(0x0) },
+ { 1, { 1566000, HFPLL, 1, 0x3A }, L2(9), 1125000, AVS(0x0) },
+ { 1, { 1674000, HFPLL, 1, 0x3E }, L2(9), 1150000, AVS(0x0) },
+ { 1, { 1728000, HFPLL, 1, 0x40 }, L2(9), 1175000, AVS(0x70000B) },
{ 0, { 0 } }
};
static struct acpu_level freq_tbl_PVS4[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 875000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(3), 875000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(3), 875000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(3), 900000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(3), 925000 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(3), 950000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(3), 975000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(9), 1000000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(9), 1025000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(9), 1050000 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(9), 1075000 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(9), 1100000 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(9), 1125000 },
- { 1, { 1728000, HFPLL, 1, 0x40 }, L2(9), 1150000 },
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 875000, AVS(0x70001F) },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(3), 875000, AVS(0x0) },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(3), 875000, AVS(0x0) },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(3), 900000, AVS(0x0) },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(3), 925000, AVS(0x0) },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(3), 950000, AVS(0x0) },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(3), 975000, AVS(0x0) },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(9), 1000000, AVS(0x70000D) },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(9), 1025000, AVS(0x0) },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(9), 1050000, AVS(0x0) },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(9), 1075000, AVS(0x0) },
+ { 1, { 1566000, HFPLL, 1, 0x3A }, L2(9), 1100000, AVS(0x0) },
+ { 1, { 1674000, HFPLL, 1, 0x3E }, L2(9), 1125000, AVS(0x0) },
+ { 1, { 1728000, HFPLL, 1, 0x40 }, L2(9), 1150000, AVS(0x70000B) },
{ 0, { 0 } }
};
static struct acpu_level freq_tbl_PVS5[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 875000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(3), 875000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(3), 875000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(3), 875000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(3), 900000 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(3), 925000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(3), 950000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(9), 975000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(9), 1000000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(9), 1025000 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(9), 1050000 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(9), 1075000 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(9), 1100000 },
- { 1, { 1728000, HFPLL, 1, 0x40 }, L2(9), 1125000 },
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 875000, AVS(0x70001F) },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(3), 875000, AVS(0x0) },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(3), 875000, AVS(0x0) },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(3), 875000, AVS(0x0) },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(3), 900000, AVS(0x0) },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(3), 925000, AVS(0x0) },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(3), 950000, AVS(0x0) },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(9), 975000, AVS(0x70000D) },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(9), 1000000, AVS(0x0) },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(9), 1025000, AVS(0x0) },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(9), 1050000, AVS(0x0) },
+ { 1, { 1566000, HFPLL, 1, 0x3A }, L2(9), 1075000, AVS(0x0) },
+ { 1, { 1674000, HFPLL, 1, 0x3E }, L2(9), 1100000, AVS(0x0) },
+ { 1, { 1728000, HFPLL, 1, 0x40 }, L2(9), 1125000, AVS(0x70000B) },
{ 0, { 0 } }
};
static struct acpu_level freq_tbl_PVS6[] __initdata = {
- { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 850000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(3), 850000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(3), 850000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(3), 850000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(3), 875000 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(3), 900000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(3), 925000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(9), 950000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(9), 975000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(9), 1000000 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(9), 1025000 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(9), 1050000 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(9), 1075000 },
- { 1, { 1728000, HFPLL, 1, 0x40 }, L2(9), 1100000 },
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 850000, AVS(0x70001F) },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(3), 850000, AVS(0x0) },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(3), 850000, AVS(0x0) },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(3), 850000, AVS(0x0) },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(3), 875000, AVS(0x0) },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(3), 900000, AVS(0x0) },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(3), 925000, AVS(0x0) },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(9), 950000, AVS(0x70000D) },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(9), 975000, AVS(0x0) },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(9), 1000000, AVS(0x0) },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(9), 1025000, AVS(0x0) },
+ { 1, { 1566000, HFPLL, 1, 0x3A }, L2(9), 1050000, AVS(0x0) },
+ { 1, { 1674000, HFPLL, 1, 0x3E }, L2(9), 1075000, AVS(0x0) },
+ { 1, { 1728000, HFPLL, 1, 0x40 }, L2(9), 1100000, AVS(0x70000B) },
{ 0, { 0 } }
};
static struct pvs_table pvs_tables[NUM_SPEED_BINS][NUM_PVS] __initdata = {
[0][0] = { freq_tbl_PVS0, sizeof(freq_tbl_PVS0), 0 },
-[0][1] = { freq_tbl_PVS1, sizeof(freq_tbl_PVS1), 0 },
-[0][2] = { freq_tbl_PVS2, sizeof(freq_tbl_PVS2), 0 },
-[0][3] = { freq_tbl_PVS3, sizeof(freq_tbl_PVS3), 0 },
-[0][4] = { freq_tbl_PVS4, sizeof(freq_tbl_PVS4), 0 },
-[0][5] = { freq_tbl_PVS5, sizeof(freq_tbl_PVS5), 0 },
-[0][6] = { freq_tbl_PVS6, sizeof(freq_tbl_PVS6), 0 },
+[0][1] = { freq_tbl_PVS1, sizeof(freq_tbl_PVS1), 25000 },
+[0][2] = { freq_tbl_PVS2, sizeof(freq_tbl_PVS2), 25000 },
+[0][3] = { freq_tbl_PVS3, sizeof(freq_tbl_PVS3), 25000 },
+[0][4] = { freq_tbl_PVS4, sizeof(freq_tbl_PVS4), 25000 },
+[0][5] = { freq_tbl_PVS5, sizeof(freq_tbl_PVS5), 25000 },
+[0][6] = { freq_tbl_PVS6, sizeof(freq_tbl_PVS6), 25000 },
};
static struct acpuclk_krait_params acpuclk_8960ab_params __initdata = {
diff --git a/arch/arm/mach-msm/acpuclock-8974.c b/arch/arm/mach-msm/acpuclock-8974.c
index d25d503..f929943 100644
--- a/arch/arm/mach-msm/acpuclock-8974.c
+++ b/arch/arm/mach-msm/acpuclock-8974.c
@@ -94,10 +94,14 @@
};
static struct msm_bus_paths bw_level_tbl[] __initdata = {
- [0] = BW_MBPS(552), /* At least 69 MHz on bus. */
- [1] = BW_MBPS(1112), /* At least 139 MHz on bus. */
- [2] = BW_MBPS(2224), /* At least 278 MHz on bus. */
- [3] = BW_MBPS(4448), /* At least 556 MHz on bus. */
+ [0] = BW_MBPS(600), /* At least 75 MHz on bus. */
+ [1] = BW_MBPS(800), /* At least 100 MHz on bus. */
+ [2] = BW_MBPS(1200), /* At least 150 MHz on bus. */
+ [3] = BW_MBPS(1600), /* At least 200 MHz on bus. */
+ [4] = BW_MBPS(2224), /* At least 278 MHz on bus. */
+ [5] = BW_MBPS(3200), /* At least 400 MHz on bus. */
+ [6] = BW_MBPS(4448), /* At least 556 MHz on bus. */
+ [7] = BW_MBPS(6400), /* At least 800 MHz on bus. */
};
static struct msm_bus_scale_pdata bus_scale_data __initdata = {
@@ -113,51 +117,51 @@
[2] = { { 422400, HFPLL, 2, 44 }, LVL_NOM, 1050000, 1 },
[3] = { { 499200, HFPLL, 2, 52 }, LVL_NOM, 1050000, 2 },
[4] = { { 576000, HFPLL, 1, 30 }, LVL_NOM, 1050000, 2 },
- [5] = { { 652800, HFPLL, 1, 34 }, LVL_NOM, 1050000, 2 },
- [6] = { { 729600, HFPLL, 1, 38 }, LVL_NOM, 1050000, 2 },
- [7] = { { 806400, HFPLL, 1, 42 }, LVL_NOM, 1050000, 2 },
- [8] = { { 883200, HFPLL, 1, 46 }, LVL_HIGH, 1050000, 2 },
- [9] = { { 960000, HFPLL, 1, 50 }, LVL_HIGH, 1050000, 2 },
- [10] = { { 1036800, HFPLL, 1, 54 }, LVL_HIGH, 1050000, 3 },
- [11] = { { 1113600, HFPLL, 1, 58 }, LVL_HIGH, 1050000, 3 },
- [12] = { { 1190400, HFPLL, 1, 62 }, LVL_HIGH, 1050000, 3 },
- [13] = { { 1267200, HFPLL, 1, 66 }, LVL_HIGH, 1050000, 3 },
- [14] = { { 1344000, HFPLL, 1, 70 }, LVL_HIGH, 1050000, 3 },
- [15] = { { 1420800, HFPLL, 1, 74 }, LVL_HIGH, 1050000, 3 },
- [16] = { { 1497600, HFPLL, 1, 78 }, LVL_HIGH, 1050000, 3 },
- [17] = { { 1574400, HFPLL, 1, 82 }, LVL_HIGH, 1050000, 3 },
- [18] = { { 1651200, HFPLL, 1, 86 }, LVL_HIGH, 1050000, 3 },
- [19] = { { 1728000, HFPLL, 1, 90 }, LVL_HIGH, 1050000, 3 },
- [20] = { { 1804800, HFPLL, 1, 94 }, LVL_HIGH, 1050000, 3 },
- [21] = { { 1881600, HFPLL, 1, 98 }, LVL_HIGH, 1050000, 3 },
- [22] = { { 1958400, HFPLL, 1, 102 }, LVL_HIGH, 1050000, 3 },
- [23] = { { 2035200, HFPLL, 1, 106 }, LVL_HIGH, 1050000, 3 },
- [24] = { { 2112000, HFPLL, 1, 110 }, LVL_HIGH, 1050000, 3 },
- [25] = { { 2188800, HFPLL, 1, 114 }, LVL_HIGH, 1050000, 3 },
+ [5] = { { 652800, HFPLL, 1, 34 }, LVL_NOM, 1050000, 3 },
+ [6] = { { 729600, HFPLL, 1, 38 }, LVL_NOM, 1050000, 3 },
+ [7] = { { 806400, HFPLL, 1, 42 }, LVL_NOM, 1050000, 3 },
+ [8] = { { 883200, HFPLL, 1, 46 }, LVL_HIGH, 1050000, 4 },
+ [9] = { { 960000, HFPLL, 1, 50 }, LVL_HIGH, 1050000, 4 },
+ [10] = { { 1036800, HFPLL, 1, 54 }, LVL_HIGH, 1050000, 4 },
+ [11] = { { 1113600, HFPLL, 1, 58 }, LVL_HIGH, 1050000, 5 },
+ [12] = { { 1190400, HFPLL, 1, 62 }, LVL_HIGH, 1050000, 5 },
+ [13] = { { 1267200, HFPLL, 1, 66 }, LVL_HIGH, 1050000, 6 },
+ [14] = { { 1344000, HFPLL, 1, 70 }, LVL_HIGH, 1050000, 6 },
+ [15] = { { 1420800, HFPLL, 1, 74 }, LVL_HIGH, 1050000, 7 },
+ [16] = { { 1497600, HFPLL, 1, 78 }, LVL_HIGH, 1050000, 7 },
+ [17] = { { 1574400, HFPLL, 1, 82 }, LVL_HIGH, 1050000, 7 },
+ [18] = { { 1651200, HFPLL, 1, 86 }, LVL_HIGH, 1050000, 7 },
+ [19] = { { 1728000, HFPLL, 1, 90 }, LVL_HIGH, 1050000, 7 },
+ [20] = { { 1804800, HFPLL, 1, 94 }, LVL_HIGH, 1050000, 7 },
+ [21] = { { 1881600, HFPLL, 1, 98 }, LVL_HIGH, 1050000, 7 },
+ [22] = { { 1958400, HFPLL, 1, 102 }, LVL_HIGH, 1050000, 7 },
+ [23] = { { 2035200, HFPLL, 1, 106 }, LVL_HIGH, 1050000, 7 },
+ [24] = { { 2112000, HFPLL, 1, 110 }, LVL_HIGH, 1050000, 7 },
+ [25] = { { 2188800, HFPLL, 1, 114 }, LVL_HIGH, 1050000, 7 },
{ }
};
static struct acpu_level acpu_freq_tbl[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 950000, 100000 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(0), 950000, 3200000 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(0), 950000, 3200000 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(0), 950000, 3200000 },
- { 1, { 576000, HFPLL, 1, 30 }, L2(0), 950000, 3200000 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(16), 950000, 3200000 },
- { 0, { 729600, HFPLL, 1, 38 }, L2(16), 950000, 3200000 },
- { 1, { 806400, HFPLL, 1, 42 }, L2(16), 950000, 3200000 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(16), 950000, 3200000 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(16), 950000, 3200000 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(16), 950000, 3200000 },
- { 1, { 1113600, HFPLL, 1, 58 }, L2(16), 1050000, 3200000 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(16), 1050000, 3200000 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(16), 1050000, 3200000 },
- { 1, { 1344000, HFPLL, 1, 70 }, L2(16), 1050000, 3200000 },
- { 1, { 1420800, HFPLL, 1, 74 }, L2(16), 1050000, 3200000 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 1050000, 3200000 },
- { 0, { 1574400, HFPLL, 1, 82 }, L2(16), 1050000, 3200000 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(16), 1050000, 3200000 },
- { 0, { 1728000, HFPLL, 1, 90 }, L2(16), 1050000, 3200000 },
+ { 1, { 300000, PLL_0, 0, 0 }, L2(0), 850000, 100000 },
+ { 0, { 345600, HFPLL, 2, 36 }, L2(0), 850000, 3200000 },
+ { 1, { 422400, HFPLL, 2, 44 }, L2(0), 850000, 3200000 },
+ { 0, { 499200, HFPLL, 2, 52 }, L2(0), 850000, 3200000 },
+ { 1, { 576000, HFPLL, 1, 30 }, L2(0), 850000, 3200000 },
+ { 1, { 652800, HFPLL, 1, 34 }, L2(16), 850000, 3200000 },
+ { 0, { 729600, HFPLL, 1, 38 }, L2(16), 850000, 3200000 },
+ { 1, { 806400, HFPLL, 1, 42 }, L2(16), 850000, 3200000 },
+ { 1, { 883200, HFPLL, 1, 46 }, L2(16), 870000, 3200000 },
+ { 1, { 960000, HFPLL, 1, 50 }, L2(16), 880000, 3200000 },
+ { 1, { 1036800, HFPLL, 1, 54 }, L2(16), 900000, 3200000 },
+ { 1, { 1113600, HFPLL, 1, 58 }, L2(16), 915000, 3200000 },
+ { 1, { 1190400, HFPLL, 1, 62 }, L2(16), 935000, 3200000 },
+ { 1, { 1267200, HFPLL, 1, 66 }, L2(16), 950000, 3200000 },
+ { 1, { 1344000, HFPLL, 1, 70 }, L2(16), 970000, 3200000 },
+ { 1, { 1420800, HFPLL, 1, 74 }, L2(16), 985000, 3200000 },
+ { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 1000000, 3200000 },
+ { 1, { 1574400, HFPLL, 1, 82 }, L2(16), 1015000, 3200000 },
+ { 1, { 1651200, HFPLL, 1, 86 }, L2(16), 1030000, 3200000 },
+ { 1, { 1728000, HFPLL, 1, 90 }, L2(16), 1050000, 3200000 },
{ 0, { 1804800, HFPLL, 1, 94 }, L2(16), 1050000, 3200000 },
{ 0, { 1881600, HFPLL, 1, 98 }, L2(16), 1050000, 3200000 },
{ 0, { 1958400, HFPLL, 1, 102 }, L2(16), 1050000, 3200000 },
diff --git a/arch/arm/mach-msm/acpuclock-8x50.c b/arch/arm/mach-msm/acpuclock-8x50.c
index 996f883..eed8000 100644
--- a/arch/arm/mach-msm/acpuclock-8x50.c
+++ b/arch/arm/mach-msm/acpuclock-8x50.c
@@ -423,14 +423,6 @@
}
if (reason == SETRATE_CPUFREQ) {
-#ifdef CONFIG_MSM_CPU_AVS
- /* Notify avs before changing frequency */
- rc = avs_adjust_freq(freq_index, 1);
- if (rc) {
- pr_err("Unable to increase ACPU vdd (%d)\n", rc);
- goto out;
- }
-#endif
/* Increase VDD if needed. */
if (tgt_s->vdd > strt_s->vdd) {
rc = acpuclk_set_vdd_level(tgt_s->vdd);
@@ -485,13 +477,6 @@
if (reason == SETRATE_PC)
goto out;
-#ifdef CONFIG_MSM_CPU_AVS
- /* notify avs after changing frequency */
- res = avs_adjust_freq(freq_index, 0);
- if (res)
- pr_warning("Unable to drop ACPU vdd (%d)\n", res);
-#endif
-
/* Drop VDD level if we can. */
if (tgt_s->vdd < strt_s->vdd) {
res = acpuclk_set_vdd_level(tgt_s->vdd);
@@ -658,22 +643,6 @@
}
}
-#ifdef CONFIG_MSM_CPU_AVS
-static int __devinit acpu_avs_init(int (*set_vdd) (int), int khz)
-{
- int i;
- int freq_count = 0;
- int freq_index = -1;
-
- for (i = 0; acpu_freq_tbl[i].acpuclk_khz; i++) {
- freq_count++;
- if (acpu_freq_tbl[i].acpuclk_khz == khz)
- freq_index = i;
- }
-
- return avs_init(set_vdd, freq_count, freq_index);
-}
-#endif
static int qsd8x50_tps65023_set_dcdc1(int mVolts)
{
@@ -728,13 +697,6 @@
cpufreq_table_init();
cpufreq_frequency_table_get_attr(freq_table, smp_processor_id());
#endif
-#ifdef CONFIG_MSM_CPU_AVS
- if (!acpu_avs_init(drv_state.acpu_set_vdd,
- drv_state.current_speed->acpuclk_khz)) {
- /* avs init successful. avs will handle voltage changes */
- drv_state.acpu_set_vdd = NULL;
- }
-#endif
return 0;
}
diff --git a/arch/arm/mach-msm/avs.c b/arch/arm/mach-msm/avs.c
index 827adab..aa257ef 100644
--- a/arch/arm/mach-msm/avs.c
+++ b/arch/arm/mach-msm/avs.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 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
@@ -11,270 +11,86 @@
* GNU General Public License for more details.
*/
-#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/delay.h>
-#include <linux/kernel_stat.h>
-#include <linux/workqueue.h>
-#include <linux/slab.h>
-
+#include <linux/kernel.h>
+#include <asm/mach-types.h>
+#include <asm/cputype.h>
#include "avs.h"
-#define AVSDSCR_INPUT 0x01004860 /* magic # from circuit designer */
-#define TSCSR_INPUT 0x00000001 /* enable temperature sense */
-
-#define TEMPRS 16 /* total number of temperature regions */
-#define GET_TEMPR() (avs_get_tscsr() >> 28) /* scale TSCSR[CTEMP] to regions */
-
-struct mutex avs_lock;
-
-static struct avs_state_s
+u32 avs_get_avscsr(void)
{
- u32 freq_cnt; /* Frequencies supported list */
- short *avs_v; /* Dyanmically allocated storage for
- * 2D table of voltages over temp &
- * freq. Used as a set of 1D tables.
- * Each table is for a single temp.
- * For usage see avs_get_voltage
- */
- int (*set_vdd) (int); /* Function Ptr for setting voltage */
- int changing; /* Clock frequency is changing */
- u32 freq_idx; /* Current frequency index */
- int vdd; /* Current ACPU voltage */
-} avs_state;
+ u32 val = 0;
-/*
- * Update the AVS voltage vs frequency table, for current temperature
- * Adjust based on the AVS delay circuit hardware status
- */
-static void avs_update_voltage_table(short *vdd_table)
+ asm volatile ("mrc p15, 7, %[avscsr], c15, c1, 7\n\t"
+ : [avscsr]"=r" (val)
+ );
+
+ return val;
+}
+EXPORT_SYMBOL(avs_get_avscsr);
+
+void avs_set_avscsr(u32 avscsr)
{
- u32 avscsr;
- int cpu;
- int vu;
- int l2;
- int i;
- u32 cur_freq_idx;
- short cur_voltage;
+ asm volatile ("mcr p15, 7, %[avscsr], c15, c1, 7\n\t"
+ "isb\n\t"
+ :
+ : [avscsr]"r" (avscsr)
+ );
+}
+EXPORT_SYMBOL(avs_set_avscsr);
- cur_freq_idx = avs_state.freq_idx;
- cur_voltage = avs_state.vdd;
+u32 avs_get_avsdscr(void)
+{
+ u32 val = 0;
- avscsr = avs_test_delays();
- AVSDEBUG("avscsr=%x, avsdscr=%x\n", avscsr, avs_get_avsdscr());
+ asm volatile ("mrc p15, 7, %[avsdscr], c15, c0, 6\n\t"
+ : [avsdscr]"=r" (val)
+ );
- /*
- * Read the results for the various unit's AVS delay circuits
- * 2=> up, 1=>down, 0=>no-change
- */
- cpu = ((avscsr >> 23) & 2) + ((avscsr >> 16) & 1);
- vu = ((avscsr >> 28) & 2) + ((avscsr >> 21) & 1);
- l2 = ((avscsr >> 29) & 2) + ((avscsr >> 22) & 1);
+ return val;
+}
+EXPORT_SYMBOL(avs_get_avsdscr);
- if ((cpu == 3) || (vu == 3) || (l2 == 3)) {
- printk(KERN_ERR "AVS: Dly Synth O/P error\n");
- } else if ((cpu == 2) || (l2 == 2) || (vu == 2)) {
- /*
- * even if one oscillator asks for up, increase the voltage,
- * as its an indication we are running outside the
- * critical acceptable range of v-f combination.
- */
- AVSDEBUG("cpu=%d l2=%d vu=%d\n", cpu, l2, vu);
- AVSDEBUG("Voltage up at %d\n", cur_freq_idx);
+void avs_set_avsdscr(u32 avsdscr)
+{
+ asm volatile("mcr p15, 7, %[avsdscr], c15, c0, 6\n\t"
+ "isb\n\t"
+ :
+ : [avsdscr]"r" (avsdscr)
+ );
+}
+EXPORT_SYMBOL(avs_set_avsdscr);
- if (cur_voltage >= VOLTAGE_MAX)
- printk(KERN_ERR
- "AVS: Voltage can not get high enough!\n");
+static void avs_enable_local(void *data)
+{
+ u32 avsdscr = (u32) data;
+ u32 avscsr_enable = 0x61;
- /* Raise the voltage for all frequencies */
- for (i = 0; i < avs_state.freq_cnt; i++) {
- vdd_table[i] = cur_voltage + VOLTAGE_STEP;
- if (vdd_table[i] > VOLTAGE_MAX)
- vdd_table[i] = VOLTAGE_MAX;
- }
- } else if ((cpu == 1) && (l2 == 1) && (vu == 1)) {
- if ((cur_voltage - VOLTAGE_STEP >= VOLTAGE_MIN) &&
- (cur_voltage <= vdd_table[cur_freq_idx])) {
- vdd_table[cur_freq_idx] = cur_voltage - VOLTAGE_STEP;
- AVSDEBUG("Voltage down for %d and lower levels\n",
- cur_freq_idx);
-
- /* clamp to this voltage for all lower levels */
- for (i = 0; i < cur_freq_idx; i++) {
- if (vdd_table[i] > vdd_table[cur_freq_idx])
- vdd_table[i] = vdd_table[cur_freq_idx];
- }
- }
- }
+ avs_set_avsdscr(avsdscr);
+ avs_set_avscsr(avscsr_enable);
}
-/*
- * Return the voltage for the target performance freq_idx and optionally
- * use AVS hardware to check the present voltage freq_idx
- */
-static short avs_get_target_voltage(int freq_idx, bool update_table)
+static void avs_disable_local(void *data)
{
- unsigned cur_tempr = GET_TEMPR();
- unsigned temp_index = cur_tempr*avs_state.freq_cnt;
-
- /* Table of voltages vs frequencies for this temp */
- short *vdd_table = avs_state.avs_v + temp_index;
-
- if (update_table)
- avs_update_voltage_table(vdd_table);
-
- return vdd_table[freq_idx];
+ avs_set_avscsr(0);
}
-
-/*
- * Set the voltage for the freq_idx and optionally
- * use AVS hardware to update the voltage
- */
-static int avs_set_target_voltage(int freq_idx, bool update_table)
+void avs_enable(int cpu, u32 avsdscr)
{
- int rc = 0;
- int new_voltage = avs_get_target_voltage(freq_idx, update_table);
- if (avs_state.vdd != new_voltage) {
- AVSDEBUG("AVS setting V to %d mV @%d\n",
- new_voltage, freq_idx);
- rc = avs_state.set_vdd(new_voltage);
- if (rc)
- return rc;
- avs_state.vdd = new_voltage;
- }
- return rc;
-}
+ int ret;
-/*
- * Notify avs of clk frquency transition begin & end
- */
-int avs_adjust_freq(u32 freq_idx, int begin)
+ ret = smp_call_function_single(cpu, avs_enable_local,
+ (void *)avsdscr, true);
+ WARN_ON(ret);
+}
+EXPORT_SYMBOL(avs_enable);
+
+void avs_disable(int cpu)
{
- int rc = 0;
+ int ret;
- if (!avs_state.set_vdd) {
- /* AVS not initialized */
- return 0;
- }
-
- if (freq_idx >= avs_state.freq_cnt) {
- AVSDEBUG("Out of range :%d\n", freq_idx);
- return -EINVAL;
- }
-
- mutex_lock(&avs_lock);
- if ((begin && (freq_idx > avs_state.freq_idx)) ||
- (!begin && (freq_idx < avs_state.freq_idx))) {
- /* Update voltage before increasing frequency &
- * after decreasing frequency
- */
- rc = avs_set_target_voltage(freq_idx, 0);
- if (rc)
- goto aaf_out;
-
- avs_state.freq_idx = freq_idx;
- }
- avs_state.changing = begin;
-aaf_out:
- mutex_unlock(&avs_lock);
-
- return rc;
+ ret = smp_call_function_single(cpu, avs_disable_local,
+ (void *) 0, true);
+ WARN_ON(ret);
}
-
-
-static struct delayed_work avs_work;
-static struct workqueue_struct *kavs_wq;
-#define AVS_DELAY ((CONFIG_HZ * 50 + 999) / 1000)
-
-static void do_avs_timer(struct work_struct *work)
-{
- int cur_freq_idx;
-
- mutex_lock(&avs_lock);
- if (!avs_state.changing) {
- /* Only adjust the voltage if clk is stable */
- cur_freq_idx = avs_state.freq_idx;
- avs_set_target_voltage(cur_freq_idx, 1);
- }
- mutex_unlock(&avs_lock);
- queue_delayed_work_on(0, kavs_wq, &avs_work, AVS_DELAY);
-}
-
-
-static void __init avs_timer_init(void)
-{
- INIT_DELAYED_WORK_DEFERRABLE(&avs_work, do_avs_timer);
- queue_delayed_work_on(0, kavs_wq, &avs_work, AVS_DELAY);
-}
-
-static void __exit avs_timer_exit(void)
-{
- cancel_delayed_work(&avs_work);
-}
-
-static int __init avs_work_init(void)
-{
- kavs_wq = create_workqueue("avs");
- if (!kavs_wq) {
- printk(KERN_ERR "AVS initialization failed\n");
- return -EFAULT;
- }
- avs_timer_init();
-
- return 1;
-}
-
-static void __exit avs_work_exit(void)
-{
- avs_timer_exit();
- destroy_workqueue(kavs_wq);
-}
-
-int __init avs_init(int (*set_vdd)(int), u32 freq_cnt, u32 freq_idx)
-{
- int i;
-
- mutex_init(&avs_lock);
-
- if (freq_cnt == 0)
- return -EINVAL;
-
- avs_state.freq_cnt = freq_cnt;
-
- if (freq_idx >= avs_state.freq_cnt)
- return -EINVAL;
-
- avs_state.avs_v = kmalloc(TEMPRS * avs_state.freq_cnt *
- sizeof(avs_state.avs_v[0]), GFP_KERNEL);
-
- if (avs_state.avs_v == 0)
- return -ENOMEM;
-
- for (i = 0; i < TEMPRS*avs_state.freq_cnt; i++)
- avs_state.avs_v[i] = VOLTAGE_MAX;
-
- avs_reset_delays(AVSDSCR_INPUT);
- avs_set_tscsr(TSCSR_INPUT);
-
- avs_state.set_vdd = set_vdd;
- avs_state.changing = 0;
- avs_state.freq_idx = -1;
- avs_state.vdd = -1;
- avs_adjust_freq(freq_idx, 0);
-
- avs_work_init();
-
- return 0;
-}
-
-void __exit avs_exit()
-{
- avs_work_exit();
-
- kfree(avs_state.avs_v);
-}
-
-
+EXPORT_SYMBOL(avs_disable);
diff --git a/arch/arm/mach-msm/avs.h b/arch/arm/mach-msm/avs.h
index e87bded..f8b311c 100644
--- a/arch/arm/mach-msm/avs.h
+++ b/arch/arm/mach-msm/avs.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ * 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
@@ -14,63 +14,25 @@
#ifndef AVS_H
#define AVS_H
-#define VOLTAGE_MIN 1000 /* mV */
-#define VOLTAGE_MAX 1250
-#define VOLTAGE_STEP 25
-
-int __init avs_init(int (*set_vdd)(int), u32 freq_cnt, u32 freq_idx);
-void __exit avs_exit(void);
-
-int avs_adjust_freq(u32 freq_index, int begin);
-
-/* Routines exported from avs_hw.S */
-#ifdef CONFIG_MSM_CPU_AVS
-u32 avs_test_delays(void);
-#else
-static inline u32 avs_test_delays(void)
-{ return 0; }
-#endif
-
#ifdef CONFIG_MSM_AVS_HW
-u32 avs_reset_delays(u32 avsdscr);
u32 avs_get_avscsr(void);
+void avs_set_avscsr(u32 avscsr);
u32 avs_get_avsdscr(void);
-u32 avs_get_tscsr(void);
-void avs_set_tscsr(u32 to_tscsr);
-u32 avs_disable(void);
-void avs_enable(u32 avscsr);
+void avs_set_avsdscr(u32 avsdscr);
+void avs_disable(int cpu);
+void avs_enable(int cpu, u32 avsdscr);
#else
-static inline u32 avs_reset_delays(u32 avsdscr)
-{ return 0; }
static inline u32 avs_get_avscsr(void)
{ return 0; }
+static inline void avs_set_avscsr(u32 avscsr) {}
static inline u32 avs_get_avsdscr(void)
{ return 0; }
-static inline u32 avs_get_tscsr(void)
-{ return 0; }
-static inline void avs_set_tscsr(u32 to_tscsr) {}
-static inline u32 avs_disable(void)
-{return 0; }
-static inline void avs_enable(u32 avscsr) {}
+static inline void avs_set_avsdscr(u32 avsdscr) {}
+static inline void avs_disable(int cpu) {}
+static inline void avs_enable(int cpu, u32 avsdscr) {}
#endif
-/*#define AVSDEBUG(x...) pr_info("AVS: " x);*/
-#define AVSDEBUG(...)
+#define AVS_DISABLE(cpu) avs_disable(cpu)
+#define AVS_ENABLE(cpu, x) avs_enable(cpu, x)
-#define AVS_DISABLE(cpu) do { \
- if (get_cpu() == (cpu)) \
- avs_disable(); \
- put_cpu(); \
- } while (0);
-
-/* AVSCSR(0x61) to enable CPU, V and L2 AVS module */
-
-#define AVS_ENABLE(cpu, x) do { \
- if (get_cpu() == (cpu)) { \
- avs_reset_delays((x)); \
- avs_enable(0x61); \
- } \
- put_cpu(); \
- } while (0);
-
-#endif /* AVS_H */
+#endif
diff --git a/arch/arm/mach-msm/avs_hw.S b/arch/arm/mach-msm/avs_hw.S
deleted file mode 100644
index efb9c47..0000000
--- a/arch/arm/mach-msm/avs_hw.S
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * 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.
- */
-
- .text
-
-#ifdef CONFIG_MSM_CPU_AVS
- .global avs_test_delays
-avs_test_delays:
-
-/* Read r1=CPMR and enable Never Sleep for VSLPDLY */
- mrc p15, 7, r1, c15, c0, 5
- orr r12, r1, #3, 24
- mcr p15, 7, r12, c15, c0, 5
-
-/* Read r2=CPACR and enable full access to CP10 and CP11 space */
- mrc p15, 0, r2, c1, c0, 2
- orr r12, r2, #(0xf << 20)
- mcr p15, 0, r12, c1, c0, 2
- isb
-
-/* Read r3=FPEXC and or in FP enable, VFP/ASE enable = FPEXC[30]; */
- fmrx r3, fpexc
- orr r12, r3, #1, 2
- fmxr fpexc, r12
-
-/*
- * Do floating-point operations to prime the VFP pipeline. Use
- * fcpyd d0, d0 as a floating point nop. This avoids changing VFP
- * state.
- */
- fcpyd d0, d0
- fcpyd d0, d0
- fcpyd d0, d0
-
-/* Read r0=AVSCSR to get status from CPU, VFP, and L2 ring oscillators */
- mrc p15, 7, r0, c15, c1, 7
-
-/* Restore FPEXC */
- fmxr fpexc, r3
-
-/* Restore CPACR */
- MCR p15, 0, r2, c1, c0, 2
-
-/* Restore CPMR */
- mcr p15, 7, r1, c15, c0, 5
- isb
-
- bx lr
-#endif
-
-
- .global avs_get_avscsr
-/* Read r0=AVSCSR to get status from CPU, VFP, and L2 ring oscillators */
-
-avs_get_avscsr:
- mrc p15, 7, r0, c15, c1, 7
- bx lr
-
- .global avs_get_avsdscr
-/* Read r0=AVSDSCR to get the AVS Delay Synthesizer control settings */
-
-avs_get_avsdscr:
- mrc p15, 7, r0, c15, c0, 6
- bx lr
-
-
-
-
- .global avs_get_tscsr
-/* Read r0=TSCSR to get temperature sensor control and status */
-
-avs_get_tscsr:
- mrc p15, 7, r0, c15, c1, 0
- bx lr
-
- .global avs_set_tscsr
-/* Write TSCSR=r0 to set temperature sensor control and status */
-
-avs_set_tscsr:
- mcr p15, 7, r0, c15, c1, 0
- bx lr
-
-
-
-
-
- .global avs_reset_delays
-avs_reset_delays:
-
-/* AVSDSCR(dly) to program delay */
- mcr p15, 7, r0, c15, c0, 6
-
-/* Read r0=AVSDSCR */
- mrc p15, 7, r0, c15, c0, 6
- bx lr
-
- .global avs_enable
-avs_enable:
-/* Restore the avs_scr register */
- mcr p15, 7, r0, c15, c1, 7
- bx lr
-
- .global avs_disable
-avs_disable:
-
-/* Get the AVSCSR value */
- mrc p15, 7, r0, c15, c1, 7
-/* Clear AVSCSR */
- mov r1, #0
-/* Write AVSCSR */
- mcr p15, 7, r1, c15, c1, 7
-
- bx lr
-
- .end
-
-
diff --git a/arch/arm/mach-msm/board-8064-gpiomux.c b/arch/arm/mach-msm/board-8064-gpiomux.c
index cd3e636..9e34f47 100644
--- a/arch/arm/mach-msm/board-8064-gpiomux.c
+++ b/arch/arm/mach-msm/board-8064-gpiomux.c
@@ -1647,7 +1647,8 @@
msm_gpiomux_install(mpq8064_mi2s_configs,
ARRAY_SIZE(mpq8064_mi2s_configs));
- msm_gpiomux_install(apq8064_ext_regulator_configs,
+ if (!machine_is_mpq8064_hrd())
+ msm_gpiomux_install(apq8064_ext_regulator_configs,
ARRAY_SIZE(apq8064_ext_regulator_configs));
if (machine_is_apq8064_mtp()) {
diff --git a/arch/arm/mach-msm/board-8064-gpu.c b/arch/arm/mach-msm/board-8064-gpu.c
index 38ac83e..6b15883 100644
--- a/arch/arm/mach-msm/board-8064-gpu.c
+++ b/arch/arm/mach-msm/board-8064-gpu.c
@@ -51,7 +51,7 @@
.ss_win_size_min_us = 1000000,
.ss_win_size_max_us = 1000000,
.ss_util_pct = 95,
- .ss_iobusy_conv = 100,
+ .ss_no_corr_below_freq = 0,
},
.energy_coeffs = {
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index a66495d..1a8e7e4 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -1,5 +1,5 @@
/*
- * 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
@@ -97,6 +97,7 @@
};
VREG_CONSUMERS(L14) = {
REGULATOR_SUPPLY("8921_l14", NULL),
+ REGULATOR_SUPPLY("vreg_xoadc", "pm8921-charger"),
};
VREG_CONSUMERS(L15) = {
REGULATOR_SUPPLY("8921_l15", NULL),
@@ -259,6 +260,7 @@
REGULATOR_SUPPLY("dsi1_vccs_3p3v", "mipi_dsi.1"),
REGULATOR_SUPPLY("hdmi_mux_vdd", "hdmi_msm.0"),
REGULATOR_SUPPLY("pcie_ext_3p3v", "msm_pcie"),
+ REGULATOR_SUPPLY("sata_ext_3p3v", "ahci.0"),
};
VREG_CONSUMERS(EXT_TS_SW) = {
REGULATOR_SUPPLY("ext_ts_sw", NULL),
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index ed03e46..549a029 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -88,6 +88,7 @@
#include "pm-boot.h"
#include "devices-msm8x60.h"
#include "smd_private.h"
+#include "platsmp.h"
#define MHL_GPIO_INT 30
#define MHL_GPIO_RESET 35
@@ -298,6 +299,7 @@
.mem_is_fmem = FMEM_ENABLED,
.fixed_position = FIXED_MIDDLE,
.is_cma = 1,
+ .no_nonsecure_alloc = 1,
};
static struct ion_cp_heap_pdata cp_mfc_apq8064_ion_pdata = {
@@ -306,6 +308,7 @@
.reusable = 0,
.mem_is_fmem = FMEM_ENABLED,
.fixed_position = FIXED_HIGH,
+ .no_nonsecure_alloc = 1,
};
static struct ion_co_heap_pdata co_apq8064_ion_pdata = {
@@ -1635,10 +1638,10 @@
static struct cyttsp_platform_data cyttsp_pdata = {
.panel_maxx = 634,
.panel_maxy = 1166,
- .disp_maxx = 599,
- .disp_maxy = 1023,
- .disp_minx = 0,
- .disp_miny = 0,
+ .disp_minx = 18,
+ .disp_maxx = 617,
+ .disp_miny = 18,
+ .disp_maxy = 1041,
.flags = 0x01,
.gen = CY_GEN3,
.use_st = CY_USE_ST,
@@ -2527,6 +2530,13 @@
&apq8064_device_ssbi_pmic2,
};
+static struct platform_device *pm8921_mpq_hrd_common_devices[] __initdata = {
+ &apq8064_device_ext_5v_vreg,
+ &apq8064_device_ext_mpp8_vreg,
+ &apq8064_device_ssbi_pmic1,
+ &apq8064_device_ssbi_pmic2,
+};
+
static struct platform_device *pm8917_common_devices[] __initdata = {
&apq8064_device_ext_mpp8_vreg,
&apq8064_device_ext_3p3v_vreg,
@@ -3556,9 +3566,14 @@
platform_add_devices(early_common_devices,
ARRAY_SIZE(early_common_devices));
- if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917)
- platform_add_devices(pm8921_common_devices,
- ARRAY_SIZE(pm8921_common_devices));
+ if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917) {
+ if (!machine_is_mpq8064_hrd())
+ platform_add_devices(pm8921_common_devices,
+ ARRAY_SIZE(pm8921_common_devices));
+ else
+ platform_add_devices(pm8921_mpq_hrd_common_devices,
+ ARRAY_SIZE(pm8921_mpq_hrd_common_devices));
+ }
else
platform_add_devices(pm8917_common_devices,
ARRAY_SIZE(pm8917_common_devices));
@@ -3711,6 +3726,7 @@
.init_early = apq8064_allocate_memory_regions,
.init_very_early = apq8064_early_reserve,
.restart = msm_restart,
+ .smp = &msm8960_smp_ops,
MACHINE_END
MACHINE_START(APQ8064_MTP, "QCT APQ8064 MTP")
@@ -3723,6 +3739,7 @@
.init_early = apq8064_allocate_memory_regions,
.init_very_early = apq8064_early_reserve,
.restart = msm_restart,
+ .smp = &msm8960_smp_ops,
MACHINE_END
MACHINE_START(APQ8064_LIQUID, "QCT APQ8064 LIQUID")
@@ -3735,6 +3752,7 @@
.init_early = apq8064_allocate_memory_regions,
.init_very_early = apq8064_early_reserve,
.restart = msm_restart,
+ .smp = &msm8960_smp_ops,
MACHINE_END
MACHINE_START(MPQ8064_CDP, "QCT MPQ8064 CDP")
@@ -3747,6 +3765,7 @@
.init_early = apq8064_allocate_memory_regions,
.init_very_early = apq8064_early_reserve,
.restart = msm_restart,
+ .smp = &msm8960_smp_ops,
MACHINE_END
MACHINE_START(MPQ8064_HRD, "QCT MPQ8064 HRD")
@@ -3759,6 +3778,7 @@
.init_early = apq8064_allocate_memory_regions,
.init_very_early = apq8064_early_reserve,
.restart = msm_restart,
+ .smp = &msm8960_smp_ops,
MACHINE_END
MACHINE_START(MPQ8064_DTV, "QCT MPQ8064 DTV")
@@ -3771,4 +3791,5 @@
.init_early = apq8064_allocate_memory_regions,
.init_very_early = apq8064_early_reserve,
.restart = msm_restart,
+ .smp = &msm8960_smp_ops,
MACHINE_END
diff --git a/arch/arm/mach-msm/board-8064.h b/arch/arm/mach-msm/board-8064.h
index 5d6f988..2bc0981 100644
--- a/arch/arm/mach-msm/board-8064.h
+++ b/arch/arm/mach-msm/board-8064.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -16,6 +16,7 @@
#include <linux/regulator/msm-gpio-regulator.h>
#include <linux/mfd/pm8xxx/pm8921.h>
#include <linux/mfd/pm8xxx/pm8821.h>
+#include <linux/ahci_platform.h>
#include <mach/msm_memtypes.h>
#include <mach/irqs.h>
#include <mach/rpm-regulator.h>
@@ -80,6 +81,7 @@
struct mmc_platform_data *plat);
void apq8064_init_mmc(void);
+int __init apq8064_add_ahci(struct ahci_platform_data *platd);
void apq8064_init_gpiomux(void);
void apq8064_init_pmic(void);
diff --git a/arch/arm/mach-msm/board-8092.c b/arch/arm/mach-msm/board-8092.c
index 3e31f68..cbd257f 100644
--- a/arch/arm/mach-msm/board-8092.c
+++ b/arch/arm/mach-msm/board-8092.c
@@ -31,6 +31,7 @@
#include "board-dt.h"
#include "clock.h"
+#include "platsmp.h"
static struct clk_lookup msm_clocks_dummy[] = {
CLK_DUMMY("core_clk", BLSP1_UART_CLK, "msm_serial_hsl.0", OFF),
@@ -117,4 +118,5 @@
.dt_compat = mpq8092_dt_match,
.reserve = mpq8092_dt_reserve,
.init_very_early = mpq8092_early_memory,
+ .smp = &msm8974_smp_ops,
MACHINE_END
diff --git a/arch/arm/mach-msm/board-8226.c b/arch/arm/mach-msm/board-8226.c
index fde82f4..a5cb481 100644
--- a/arch/arm/mach-msm/board-8226.c
+++ b/arch/arm/mach-msm/board-8226.c
@@ -43,6 +43,7 @@
#include <mach/clk-provider.h>
#include "board-dt.h"
#include "clock.h"
+#include "platsmp.h"
static struct memtype_reserve msm8226_reserve_table[] __initdata = {
[MEMTYPE_SMI] = {
@@ -103,7 +104,6 @@
msm_reserve();
}
-
void __init msm8226_init(void)
{
struct of_dev_auxdata *adata = msm8226_auxdata_lookup;
@@ -133,4 +133,5 @@
.reserve = msm8226_reserve,
.init_very_early = msm8226_early_memory,
.restart = msm_restart,
+ .smp = &arm_smp_ops,
MACHINE_END
diff --git a/arch/arm/mach-msm/board-8910.c b/arch/arm/mach-msm/board-8910.c
index f9c5367..2ff4567 100644
--- a/arch/arm/mach-msm/board-8910.c
+++ b/arch/arm/mach-msm/board-8910.c
@@ -41,6 +41,7 @@
#include <mach/clk-provider.h>
#include "board-dt.h"
#include "clock.h"
+#include "platsmp.h"
static struct memtype_reserve msm8910_reserve_table[] __initdata = {
[MEMTYPE_SMI] = {
@@ -58,37 +59,6 @@
return MEMTYPE_EBI1;
}
-static struct clk_lookup msm_clocks_dummy[] = {
- CLK_DUMMY("core_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
- CLK_DUMMY("iface_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
- CLK_DUMMY("iface_clk", HSUSB_IFACE_CLK, "f9a55000.usb", OFF),
- CLK_DUMMY("core_clk", HSUSB_CORE_CLK, "f9a55000.usb", OFF),
- CLK_DUMMY("iface_clk", NULL, "msm_sdcc.1", OFF),
- CLK_DUMMY("core_clk", NULL, "msm_sdcc.1", OFF),
- CLK_DUMMY("bus_clk", NULL, "msm_sdcc.1", OFF),
- 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),
- CLK_DUMMY("iface_clk", NULL, "fd890000.qcom,iommu", OFF),
- CLK_DUMMY("core_clk", NULL, "fd890000.qcom,iommu", OFF),
- CLK_DUMMY("iface_clk", NULL, "fd860000.qcom,iommu", OFF),
- CLK_DUMMY("core_clk", NULL, "fd860000.qcom,iommu", OFF),
- CLK_DUMMY("iface_clk", NULL, "fd870000.qcom,iommu", OFF),
- CLK_DUMMY("core_clk", NULL, "fd870000.qcom,iommu", OFF),
- CLK_DUMMY("iface_clk", NULL, "fd880000.qcom,iommu", OFF),
- CLK_DUMMY("core_clk", NULL, "fd880000.qcom,iommu", OFF),
- CLK_DUMMY("iface_clk", NULL, "fd000000.qcom,iommu", OFF),
- CLK_DUMMY("core_clk", NULL, "fd000000.qcom,iommu", OFF),
- CLK_DUMMY("iface_clk", NULL, "fd010000.qcom,iommu", OFF),
- CLK_DUMMY("core_clk", NULL, "fd010000.qcom,iommu", OFF),
-};
-
-static struct clock_init_data msm_dummy_clock_init_data __initdata = {
- .table = msm_clocks_dummy,
- .size = ARRAY_SIZE(msm_clocks_dummy),
-};
-
static struct of_dev_auxdata msm8910_auxdata_lookup[] __initdata = {
OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF9824000, \
"msm_sdcc.1", NULL),
@@ -118,7 +88,11 @@
struct of_dev_auxdata *adata = msm8910_auxdata_lookup;
msm8910_init_gpiomux();
- msm_clock_init(&msm_dummy_clock_init_data);
+
+ if (machine_is_msm8910_rumi())
+ msm_clock_init(&msm8910_rumi_clock_init_data);
+ else
+ msm_clock_init(&msm8910_clock_init_data);
if (socinfo_init() < 0)
pr_err("%s: socinfo_init() failed\n", __func__);
@@ -140,5 +114,6 @@
.dt_compat = msm8910_dt_match,
.restart = msm_restart,
.reserve = msm8910_reserve,
- .init_very_early = msm8910_early_memory
+ .init_very_early = msm8910_early_memory,
+ .smp = &arm_smp_ops,
MACHINE_END
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 13b16f2..1a953da 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -103,6 +103,7 @@
#include "msm_watchdog.h"
#include "board-8930.h"
#include "acpuclock-krait.h"
+#include "platsmp.h"
static struct platform_device msm_fm_platform_init = {
.name = "iris_fm",
@@ -343,6 +344,7 @@
.mem_is_fmem = FMEM_ENABLED,
.fixed_position = FIXED_MIDDLE,
.is_cma = 1,
+ .no_nonsecure_alloc = 1,
};
static struct ion_cp_heap_pdata cp_mfc_msm8930_ion_pdata = {
@@ -351,6 +353,7 @@
.reusable = 0,
.mem_is_fmem = FMEM_ENABLED,
.fixed_position = FIXED_HIGH,
+ .no_nonsecure_alloc = 1,
};
static struct ion_co_heap_pdata co_msm8930_ion_pdata = {
@@ -2970,6 +2973,7 @@
.init_early = msm8930_allocate_memory_regions,
.init_very_early = msm8930_early_memory,
.restart = msm_restart,
+ .smp = &msm8960_smp_ops,
MACHINE_END
MACHINE_START(MSM8930_MTP, "QCT MSM8930 MTP")
@@ -2982,6 +2986,7 @@
.init_early = msm8930_allocate_memory_regions,
.init_very_early = msm8930_early_memory,
.restart = msm_restart,
+ .smp = &msm8960_smp_ops,
MACHINE_END
MACHINE_START(MSM8930_FLUID, "QCT MSM8930 FLUID")
@@ -2994,6 +2999,7 @@
.init_early = msm8930_allocate_memory_regions,
.init_very_early = msm8930_early_memory,
.restart = msm_restart,
+ .smp = &msm8960_smp_ops,
MACHINE_END
MACHINE_START(MSM8627_CDP, "QCT MSM8627 CDP")
@@ -3006,6 +3012,7 @@
.init_early = msm8930_allocate_memory_regions,
.init_very_early = msm8930_early_memory,
.restart = msm_restart,
+ .smp = &msm8960_smp_ops,
MACHINE_END
MACHINE_START(MSM8627_MTP, "QCT MSM8627 MTP")
@@ -3018,4 +3025,5 @@
.init_early = msm8930_allocate_memory_regions,
.init_very_early = msm8930_early_memory,
.restart = msm_restart,
+ .smp = &msm8960_smp_ops,
MACHINE_END
diff --git a/arch/arm/mach-msm/board-8960-regulator.c b/arch/arm/mach-msm/board-8960-regulator.c
index 397411d..22c16c7 100644
--- a/arch/arm/mach-msm/board-8960-regulator.c
+++ b/arch/arm/mach-msm/board-8960-regulator.c
@@ -92,6 +92,7 @@
VREG_CONSUMERS(L14) = {
REGULATOR_SUPPLY("8921_l14", NULL),
REGULATOR_SUPPLY("pa_therm", "pm8xxx-adc"),
+ REGULATOR_SUPPLY("vreg_xoadc", "pm8921-charger"),
};
VREG_CONSUMERS(L15) = {
REGULATOR_SUPPLY("8921_l15", NULL),
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 97639d6..9b19810 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -103,6 +103,7 @@
#include "smd_private.h"
#include "pm-boot.h"
#include "msm_watchdog.h"
+#include "platsmp.h"
#if defined(CONFIG_BT) && defined(CONFIG_BT_HCIUART_ATH3K)
#include <linux/wlan_plat.h>
@@ -366,6 +367,7 @@
.iommu_map_all = 1,
.iommu_2x_map_domain = VIDEO_DOMAIN,
.is_cma = 1,
+ .no_nonsecure_alloc = 1,
};
static struct ion_cp_heap_pdata cp_mfc_msm8960_ion_pdata = {
@@ -374,6 +376,7 @@
.reusable = 0,
.mem_is_fmem = FMEM_ENABLED,
.fixed_position = FIXED_HIGH,
+ .no_nonsecure_alloc = 1,
};
static struct ion_co_heap_pdata co_msm8960_ion_pdata = {
@@ -749,6 +752,29 @@
#endif
}
+static void ion_adjust_secure_allocation(void)
+{
+ int i;
+
+ for (i = 0; i < msm8960_ion_pdata.nr; i++) {
+ struct ion_platform_heap *heap =
+ &(msm8960_ion_pdata.heaps[i]);
+
+
+ if (heap->extra_data) {
+ switch ((int) heap->type) {
+ case ION_HEAP_TYPE_CP:
+ if (cpu_is_msm8960()) {
+ ((struct ion_cp_heap_pdata *)
+ heap->extra_data)->no_nonsecure_alloc =
+ 0;
+ }
+
+ }
+ }
+ }
+}
+
static void __init reserve_mdp_memory(void)
{
msm8960_mdp_writeback(msm8960_reserve_table);
@@ -3329,13 +3355,6 @@
{
int i;
- /* Reset the AVS registers until we have support for AVS */
- for (i = 0; i < ARRAY_SIZE(msm_spm_data); i++) {
- struct msm_spm_platform_data *pdata = &msm_spm_data[i];
- pdata->reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0;
- pdata->reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0;
- }
-
/* Update the SPM sequences for SPC and PC */
for (i = 0; i < ARRAY_SIZE(msm_spm_data); i++) {
int j;
@@ -3476,6 +3495,7 @@
platform_device_register(&mdm_sglte_device);
}
msm_pm_set_tz_retention_flag(1);
+ ion_adjust_secure_allocation();
}
MACHINE_START(MSM8960_CDP, "QCT MSM8960 CDP")
@@ -3488,6 +3508,7 @@
.init_early = msm8960_allocate_memory_regions,
.init_very_early = msm8960_early_memory,
.restart = msm_restart,
+ .smp = &msm8960_smp_ops,
MACHINE_END
MACHINE_START(MSM8960_MTP, "QCT MSM8960 MTP")
@@ -3500,6 +3521,7 @@
.init_early = msm8960_allocate_memory_regions,
.init_very_early = msm8960_early_memory,
.restart = msm_restart,
+ .smp = &msm8960_smp_ops,
MACHINE_END
MACHINE_START(MSM8960_FLUID, "QCT MSM8960 FLUID")
@@ -3512,6 +3534,7 @@
.init_early = msm8960_allocate_memory_regions,
.init_very_early = msm8960_early_memory,
.restart = msm_restart,
+ .smp = &msm8960_smp_ops,
MACHINE_END
MACHINE_START(MSM8960_LIQUID, "QCT MSM8960 LIQUID")
@@ -3524,4 +3547,5 @@
.init_early = msm8960_allocate_memory_regions,
.init_very_early = msm8960_early_memory,
.restart = msm_restart,
+ .smp = &msm8960_smp_ops,
MACHINE_END
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index f0b6389..2f6d3d0 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -48,6 +48,7 @@
#include "spm.h"
#include "modem_notifier.h"
#include "lpm_resources.h"
+#include "platsmp.h"
static struct memtype_reserve msm8974_reserve_table[] __initdata = {
@@ -392,4 +393,5 @@
.reserve = msm_8974_reserve,
.init_very_early = msm8974_init_very_early,
.restart = msm_restart,
+ .smp = &msm8974_smp_ops,
MACHINE_END
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index 1dcd54f..2392f57 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -882,7 +882,9 @@
&msm_device_hsic_host,
&msm_device_usb_bam,
&msm_android_usb_device,
+#ifdef CONFIG_USB_CI13XXX_MSM_HSIC
&msm_android_usb_hsic_device,
+#endif
&msm9615_device_uart_gsbi4,
&msm9615_device_ext_2p95v_vreg,
&msm9615_device_ssbi_pmic1,
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index 5cabe64..3104aac 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -58,6 +58,7 @@
#include <mach/socinfo.h>
#include "pm-boot.h"
#include "board-msm7627a.h"
+#include "platsmp.h"
#define RESERVE_KERNEL_EBI1_SIZE 0x3A000
#define MSM_RESERVE_AUDIO_SIZE 0x1F4000
@@ -403,7 +404,7 @@
.idle_enabled = 0,
.suspend_enabled = 0,
.latency = 500,
- .residency = 6000,
+ .residency = 500,
},
[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
@@ -422,7 +423,7 @@
.idle_enabled = 0,
.suspend_enabled = 0,
.latency = 500,
- .residency = 6000,
+ .residency = 500,
},
[MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
@@ -441,7 +442,7 @@
.idle_enabled = 0,
.suspend_enabled = 0,
.latency = 500,
- .residency = 6000,
+ .residency = 500,
},
[MSM_PM_MODE(2, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
@@ -460,7 +461,7 @@
.idle_enabled = 0,
.suspend_enabled = 0,
.latency = 500,
- .residency = 6000,
+ .residency = 500,
},
[MSM_PM_MODE(3, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
@@ -1173,6 +1174,7 @@
.init_machine = msm8625_rumi3_init,
.timer = &msm_timer,
.handle_irq = gic_handle_irq,
+ .smp = &msm8625_smp_ops,
MACHINE_END
MACHINE_START(MSM8625_SURF, "QCT MSM8625 SURF")
.atag_offset = 0x100,
@@ -1183,6 +1185,7 @@
.timer = &msm_timer,
.init_early = msm7x2x_init_early,
.handle_irq = gic_handle_irq,
+ .smp = &msm8625_smp_ops,
MACHINE_END
MACHINE_START(MSM8625_FFA, "QCT MSM8625 FFA")
.atag_offset = 0x100,
@@ -1193,4 +1196,5 @@
.timer = &msm_timer,
.init_early = msm7x2x_init_early,
.handle_irq = gic_handle_irq,
+ .smp = &msm8625_smp_ops,
MACHINE_END
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 08e6a0d..d4205bd 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -103,6 +103,7 @@
#include "clock.h"
#include "pm-boot.h"
#include "board-storage-common-a.h"
+#include "platsmp.h"
#include <linux/msm_ion.h>
#include <mach/ion.h>
@@ -10506,6 +10507,7 @@
.timer = &msm_timer,
.init_early = msm8x60_charm_init_early,
.restart = msm_restart,
+ .smp = &scorpion_smp_ops,
MACHINE_END
MACHINE_START(MSM8X60_FFA, "QCT MSM8X60 FFA")
@@ -10517,6 +10519,7 @@
.timer = &msm_timer,
.init_early = msm8x60_charm_init_early,
.restart = msm_restart,
+ .smp = &scorpion_smp_ops,
MACHINE_END
MACHINE_START(MSM8X60_FLUID, "QCT MSM8X60 FLUID")
@@ -10528,6 +10531,7 @@
.timer = &msm_timer,
.init_early = msm8x60_charm_init_early,
.restart = msm_restart,
+ .smp = &scorpion_smp_ops,
MACHINE_END
MACHINE_START(MSM8X60_FUSION, "QCT MSM8X60 FUSION SURF")
@@ -10539,6 +10543,7 @@
.timer = &msm_timer,
.init_early = msm8x60_charm_init_early,
.restart = msm_restart,
+ .smp = &scorpion_smp_ops,
MACHINE_END
MACHINE_START(MSM8X60_FUSN_FFA, "QCT MSM8X60 FUSION FFA")
@@ -10550,6 +10555,7 @@
.timer = &msm_timer,
.init_early = msm8x60_charm_init_early,
.restart = msm_restart,
+ .smp = &scorpion_smp_ops,
MACHINE_END
MACHINE_START(MSM8X60_DRAGON, "QCT MSM8X60 DRAGON")
@@ -10561,4 +10567,5 @@
.timer = &msm_timer,
.init_early = msm8x60_charm_init_early,
.restart = msm_restart,
+ .smp = &scorpion_smp_ops,
MACHINE_END
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index d15b67d..ab2f1c3 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -62,6 +62,7 @@
#include "pm-boot.h"
#include "board-msm7x27a-regulator.h"
#include "board-msm7627a.h"
+#include "platsmp.h"
#define RESERVE_KERNEL_EBI1_SIZE 0x3A000
#define MSM_RESERVE_AUDIO_SIZE 0x1F4000
@@ -135,24 +136,24 @@
.msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,
};
-static struct msm_gpio i2c_gpio_config[] = {
+static struct msm_gpio msm8625q_i2c_gpio_config[] = {
{ GPIO_CFG(39, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
"qup_scl" },
{ GPIO_CFG(36, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
"qup_sda" },
};
-static struct i2c_gpio_platform_data i2c_gpio_pdata = {
+static struct i2c_gpio_platform_data msm8625q_i2c_gpio_pdata = {
.scl_pin = 39,
.sda_pin = 36,
.udelay = 5, /* 100 Khz */
};
-static struct platform_device msm_i2c_gpio = {
+static struct platform_device msm8625q_i2c_gpio = {
.name = "i2c-gpio",
.id = 2,
.dev = {
- .platform_data = &i2c_gpio_pdata,
+ .platform_data = &msm8625q_i2c_gpio_pdata,
}
};
@@ -382,7 +383,7 @@
.idle_enabled = 0,
.suspend_enabled = 0,
.latency = 500,
- .residency = 6000,
+ .residency = 500,
},
[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
@@ -401,7 +402,7 @@
.idle_enabled = 0,
.suspend_enabled = 0,
.latency = 500,
- .residency = 6000,
+ .residency = 500,
},
[MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
@@ -420,7 +421,7 @@
.idle_enabled = 0,
.suspend_enabled = 0,
.latency = 500,
- .residency = 6000,
+ .residency = 500,
},
[MSM_PM_MODE(2, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
@@ -439,7 +440,7 @@
.idle_enabled = 0,
.suspend_enabled = 0,
.latency = 500,
- .residency = 6000,
+ .residency = 500,
},
[MSM_PM_MODE(3, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
@@ -667,6 +668,10 @@
/* Regulator configuration for the NCP6335D buck */
struct regulator_consumer_supply ncp6335d_consumer_supplies[] = {
REGULATOR_SUPPLY("ncp6335d", NULL),
+ /* TO DO: NULL entry needs to be fixed once
+ * we fix the cross-dependencies.
+ */
+ REGULATOR_SUPPLY("vddx_cx", NULL),
};
static struct regulator_init_data ncp6335d_init_data = {
@@ -753,7 +758,6 @@
&msm8625_device_smd,
&msm8625_gsbi0_qup_i2c_device,
&msm8625_gsbi1_qup_i2c_device,
- &msm_i2c_gpio, /* TODO: Make this specific to 8625q */
&msm8625_device_uart1,
&msm8625_device_uart_dm1,
&msm8625_device_otg,
@@ -958,13 +962,18 @@
= &msm_gsbi0_qup_i2c_pdata;
msm8625_gsbi1_qup_i2c_device.dev.platform_data
= &msm_gsbi1_qup_i2c_pdata;
- if (machine_is_qrd_skud_prime()) {
- for (i = 0 ; i < ARRAY_SIZE(i2c_gpio_config); i++) {
- rc = gpio_tlmm_config(i2c_gpio_config[i].gpio_cfg,
+ if (machine_is_qrd_skud_prime() || cpu_is_msm8625q()) {
+ for (i = 0 ; i < ARRAY_SIZE(msm8625q_i2c_gpio_config); i++) {
+ rc = gpio_tlmm_config(
+ msm8625q_i2c_gpio_config[i].gpio_cfg,
GPIO_CFG_ENABLE);
if (rc)
pr_err("I2C-gpio tlmm config failed\n");
}
+ rc = platform_device_register(&msm8625q_i2c_gpio);
+ if (rc)
+ pr_err("%s: could not register i2c-gpio device: %d\n",
+ __func__, rc);
}
}
@@ -1172,6 +1181,7 @@
.timer = &msm_timer,
.init_early = qrd7627a_init_early,
.handle_irq = gic_handle_irq,
+ .smp = &msm8625_smp_ops,
MACHINE_END
MACHINE_START(MSM8625_QRD7, "QRD MSM8625 QRD7")
.atag_offset = 0x100,
@@ -1182,6 +1192,7 @@
.timer = &msm_timer,
.init_early = qrd7627a_init_early,
.handle_irq = gic_handle_irq,
+ .smp = &msm8625_smp_ops,
MACHINE_END
MACHINE_START(MSM8625_EVT, "QRD MSM8625 EVT")
.atag_offset = 0x100,
@@ -1192,6 +1203,7 @@
.timer = &msm_timer,
.init_early = qrd7627a_init_early,
.handle_irq = gic_handle_irq,
+ .smp = &msm8625_smp_ops,
MACHINE_END
MACHINE_START(QRD_SKUD_PRIME, "QRD MSM8625 SKUD PRIME")
.atag_offset = 0x100,
@@ -1202,4 +1214,5 @@
.timer = &msm_timer,
.init_early = qrd7627a_init_early,
.handle_irq = gic_handle_irq,
+ .smp = &msm8625_smp_ops,
MACHINE_END
diff --git a/arch/arm/mach-msm/cache_erp.c b/arch/arm/mach-msm/cache_erp.c
index 8a73c84..6b8f58b 100644
--- a/arch/arm/mach-msm/cache_erp.c
+++ b/arch/arm/mach-msm/cache_erp.c
@@ -20,6 +20,7 @@
#include <linux/io.h>
#include <mach/msm-krait-l2-accessors.h>
#include <mach/msm_iomap.h>
+#include <mach/socinfo.h>
#include <asm/cputype.h>
#include "acpuclock.h"
@@ -32,6 +33,8 @@
#define CESR_TLBMH BIT(16)
#define CESR_I_MASK 0x000000CC
+#define CESR_VALID_MASK 0x000100FF
+
/* Print a message for everything but TLB MH events */
#define CESR_PRINT_MASK 0x000000FF
@@ -64,6 +67,12 @@
#define ERP_L1_ERR(a) do { } while (0)
#endif
+#ifdef CONFIG_MSM_L1_RECOV_ERR_PANIC
+#define ERP_L1_RECOV_ERR(a) panic(a)
+#else
+#define ERP_L1_RECOV_ERR(a) do { } while (0)
+#endif
+
#ifdef CONFIG_MSM_L2_ERP_PORT_PANIC
#define ERP_PORT_ERR(a) panic(a)
#else
@@ -319,8 +328,13 @@
/* Clear the interrupt bits we processed */
write_cesr(cesr);
- if (print_regs)
- ERP_L1_ERR("L1 cache error detected");
+ if (print_regs) {
+ if ((cesr & (~CESR_I_MASK & CESR_VALID_MASK)) ||
+ cpu_is_krait_v1() || cpu_is_krait_v2())
+ ERP_L1_ERR("L1 nonrecoverable cache error detected");
+ else
+ ERP_L1_RECOV_ERR("L1 recoverable error detected\n");
+ }
return IRQ_HANDLED;
}
diff --git a/arch/arm/mach-msm/clock-8910.c b/arch/arm/mach-msm/clock-8910.c
new file mode 100644
index 0000000..c5541b4
--- /dev/null
+++ b/arch/arm/mach-msm/clock-8910.c
@@ -0,0 +1,3443 @@
+/* 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/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+
+#include <mach/rpm-regulator-smd.h>
+#include <mach/socinfo.h>
+#include <mach/rpm-smd.h>
+
+#include "clock-local2.h"
+#include "clock-pll.h"
+#include "clock-rpm.h"
+#include "clock-voter.h"
+#include "clock.h"
+
+enum {
+ GCC_BASE,
+ MMSS_BASE,
+ LPASS_BASE,
+ APCS_BASE,
+ N_BASES,
+};
+
+static void __iomem *virt_bases[N_BASES];
+
+#define GCC_REG_BASE(x) (void __iomem *)(virt_bases[GCC_BASE] + (x))
+#define MMSS_REG_BASE(x) (void __iomem *)(virt_bases[MMSS_BASE] + (x))
+#define LPASS_REG_BASE(x) (void __iomem *)(virt_bases[LPASS_BASE] + (x))
+#define APCS_REG_BASE(x) (void __iomem *)(virt_bases[APCS_BASE] + (x))
+
+#define GPLL0_MODE 0x0000
+#define GPLL0_L_VAL 0x0004
+#define GPLL0_M_VAL 0x0008
+#define GPLL0_N_VAL 0x000C
+#define GPLL0_USER_CTL 0x0010
+#define GPLL0_STATUS 0x001C
+#define GPLL2_MODE 0x0080
+#define GPLL2_L_VAL 0x0084
+#define GPLL2_M_VAL 0x0088
+#define GPLL2_N_VAL 0x008C
+#define GPLL2_USER_CTL 0x0090
+#define GPLL2_STATUS 0x009C
+#define CONFIG_NOC_BCR 0x0140
+#define MMSS_BCR 0x0240
+#define MMSS_NOC_CFG_AHB_CBCR 0x024C
+#define MSS_CFG_AHB_CBCR 0x0280
+#define MSS_Q6_BIMC_AXI_CBCR 0x0284
+#define USB_HS_BCR 0x0480
+#define USB_HS_SYSTEM_CBCR 0x0484
+#define USB_HS_AHB_CBCR 0x0488
+#define USB_HS_SYSTEM_CMD_RCGR 0x0490
+#define USB2A_PHY_BCR 0x04A8
+#define USB2A_PHY_SLEEP_CBCR 0x04AC
+#define SDCC1_BCR 0x04C0
+#define SDCC1_APPS_CMD_RCGR 0x04D0
+#define SDCC1_APPS_CBCR 0x04C4
+#define SDCC1_AHB_CBCR 0x04C8
+#define SDCC2_BCR 0x0500
+#define SDCC2_APPS_CMD_RCGR 0x0510
+#define SDCC2_APPS_CBCR 0x0504
+#define SDCC2_AHB_CBCR 0x0508
+#define BLSP1_BCR 0x05C0
+#define BLSP1_AHB_CBCR 0x05C4
+#define BLSP1_QUP1_BCR 0x0640
+#define BLSP1_QUP1_SPI_APPS_CBCR 0x0644
+#define BLSP1_QUP1_I2C_APPS_CBCR 0x0648
+#define BLSP1_QUP1_SPI_APPS_CMD_RCGR 0x064C
+#define BLSP1_UART1_BCR 0x0680
+#define BLSP1_UART1_APPS_CBCR 0x0684
+#define BLSP1_UART1_SIM_CBCR 0x0688
+#define BLSP1_UART1_APPS_CMD_RCGR 0x068C
+#define BLSP1_QUP2_BCR 0x06C0
+#define BLSP1_QUP2_SPI_APPS_CBCR 0x06C4
+#define BLSP1_QUP2_I2C_APPS_CBCR 0x06C8
+#define BLSP1_QUP2_SPI_APPS_CMD_RCGR 0x06CC
+#define BLSP1_UART2_BCR 0x0700
+#define BLSP1_UART2_APPS_CBCR 0x0704
+#define BLSP1_UART2_SIM_CBCR 0x0708
+#define BLSP1_UART2_APPS_CMD_RCGR 0x070C
+#define BLSP1_QUP3_BCR 0x0740
+#define BLSP1_QUP3_SPI_APPS_CBCR 0x0744
+#define BLSP1_QUP3_I2C_APPS_CBCR 0x0748
+#define BLSP1_QUP3_SPI_APPS_CMD_RCGR 0x074C
+#define BLSP1_UART3_BCR 0x0780
+#define BLSP1_UART3_APPS_CBCR 0x0784
+#define BLSP1_UART3_SIM_CBCR 0x0788
+#define BLSP1_UART3_APPS_CMD_RCGR 0x078C
+#define BLSP1_QUP4_BCR 0x07C0
+#define BLSP1_QUP4_SPI_APPS_CBCR 0x07C4
+#define BLSP1_QUP4_I2C_APPS_CBCR 0x07C8
+#define BLSP1_QUP4_SPI_APPS_CMD_RCGR 0x07CC
+#define BLSP1_UART4_BCR 0x0800
+#define BLSP1_UART4_APPS_CBCR 0x0804
+#define BLSP1_UART4_SIM_CBCR 0x0808
+#define BLSP1_UART4_APPS_CMD_RCGR 0x080C
+#define BLSP1_QUP5_BCR 0x0840
+#define BLSP1_QUP5_SPI_APPS_CBCR 0x0844
+#define BLSP1_QUP5_I2C_APPS_CBCR 0x0848
+#define BLSP1_QUP5_SPI_APPS_CMD_RCGR 0x084C
+#define BLSP1_UART5_BCR 0x0880
+#define BLSP1_UART5_APPS_CBCR 0x0884
+#define BLSP1_UART5_SIM_CBCR 0x0888
+#define BLSP1_UART5_APPS_CMD_RCGR 0x088C
+#define BLSP1_QUP6_BCR 0x08C0
+#define BLSP1_QUP6_SPI_APPS_CBCR 0x08C4
+#define BLSP1_QUP6_I2C_APPS_CBCR 0x08C8
+#define BLSP1_QUP6_SPI_APPS_CMD_RCGR 0x08CC
+#define BLSP1_UART6_BCR 0x0900
+#define BLSP1_UART6_APPS_CBCR 0x0904
+#define BLSP1_UART6_SIM_CBCR 0x0908
+#define BLSP1_UART6_APPS_CMD_RCGR 0x090C
+#define PDM_BCR 0x0CC0
+#define PDM_AHB_CBCR 0x0CC4
+#define PDM2_CBCR 0x0CCC
+#define PDM2_CMD_RCGR 0x0CD0
+#define PRNG_BCR 0x0D00
+#define PRNG_AHB_CBCR 0x0D04
+#define BOOT_ROM_BCR 0x0E00
+#define BOOT_ROM_AHB_CBCR 0x0E04
+#define CE1_BCR 0x1040
+#define CE1_CMD_RCGR 0x1050
+#define CE1_CBCR 0x1044
+#define CE1_AXI_CBCR 0x1048
+#define CE1_AHB_CBCR 0x104C
+#define COPSS_SMMU_AHB_CBCR 0x015C
+#define LPSS_SMMU_AHB_CBCR 0x0158
+#define LPASS_Q6_AXI_CBCR 0x11C0
+#define APCS_GPLL_ENA_VOTE 0x1480
+#define APCS_CLOCK_BRANCH_ENA_VOTE 0x1484
+#define APCS_CLOCK_SLEEP_ENA_VOTE 0x1488
+#define GP1_CBCR 0x1900
+#define GP1_CMD_RCGR 0x1904
+#define GP2_CBCR 0x1940
+#define GP2_CMD_RCGR 0x1944
+#define GP3_CBCR 0x1980
+#define GP3_CMD_RCGR 0x1984
+#define XO_CBCR 0x0034
+
+#define MMPLL0_PLL_MODE 0x0000
+#define MMPLL0_PLL_L_VAL 0x0004
+#define MMPLL0_PLL_M_VAL 0x0008
+#define MMPLL0_PLL_N_VAL 0x000C
+#define MMPLL0_PLL_USER_CTL 0x0010
+#define MMPLL0_PLL_STATUS 0x001C
+#define MMSS_PLL_VOTE_APCS_REG 0x0100
+#define MMPLL1_PLL_MODE 0x4100
+#define MMPLL1_PLL_L_VAL 0x4104
+#define MMPLL1_PLL_M_VAL 0x4108
+#define MMPLL1_PLL_N_VAL 0x410C
+#define MMPLL1_PLL_USER_CTL 0x4110
+#define MMPLL1_PLL_STATUS 0x411C
+#define DSI_PCLK_CMD_RCGR 0x2000
+#define DSI_CMD_RCGR 0x2020
+#define MDP_VSYNC_CMD_RCGR 0x2080
+#define DSI_BYTE_CMD_RCGR 0x2120
+#define DSI_ESC_CMD_RCGR 0x2160
+#define DSI_BCR 0x2200
+#define DSI_BYTE_BCR 0x2204
+#define DSI_ESC_BCR 0x2208
+#define DSI_AHB_BCR 0x220C
+#define DSI_PCLK_BCR 0x2214
+#define MDP_LCDC_BCR 0x2218
+#define MDP_DSI_BCR 0x221C
+#define MDP_VSYNC_BCR 0x2220
+#define MDP_AXI_BCR 0x2224
+#define MDP_AHB_BCR 0x2228
+#define MDP_AXI_CBCR 0x2314
+#define MDP_VSYNC_CBCR 0x231C
+#define MDP_AHB_CBCR 0x2318
+#define DSI_PCLK_CBCR 0x233C
+#define GMEM_GFX3D_CBCR 0x4038
+#define MDP_LCDC_CBCR 0x2340
+#define MDP_DSI_CBCR 0x2320
+#define DSI_CBCR 0x2324
+#define DSI_BYTE_CBCR 0x2328
+#define DSI_ESC_CBCR 0x232C
+#define DSI_AHB_CBCR 0x2330
+#define CSI0PHYTIMER_CMD_RCGR 0x3000
+#define CSI0PHYTIMER_BCR 0x3020
+#define CSI0PHYTIMER_CBCR 0x3024
+#define CSI1PHYTIMER_CMD_RCGR 0x3030
+#define CSI1PHYTIMER_BCR 0x3050
+#define CSI1PHYTIMER_CBCR 0x3054
+#define CSI0_CMD_RCGR 0x3090
+#define CSI0_BCR 0x30B0
+#define CSI0_CBCR 0x30B4
+#define CSI_AHB_BCR 0x30B8
+#define CSI_AHB_CBCR 0x30BC
+#define CSI0PHY_BCR 0x30C0
+#define CSI0PHY_CBCR 0x30C4
+#define CSI0RDI_BCR 0x30D0
+#define CSI0RDI_CBCR 0x30D4
+#define CSI0PIX_BCR 0x30E0
+#define CSI0PIX_CBCR 0x30E4
+#define CSI1_CMD_RCGR 0x3100
+#define CSI1_BCR 0x3120
+#define CSI1_CBCR 0x3124
+#define CSI1PHY_BCR 0x3130
+#define CSI1PHY_CBCR 0x3134
+#define CSI1RDI_BCR 0x3140
+#define CSI1RDI_CBCR 0x3144
+#define CSI1PIX_BCR 0x3150
+#define CSI1PIX_CBCR 0x3154
+#define MCLK0_CMD_RCGR 0x3360
+#define MCLK0_BCR 0x3380
+#define MCLK0_CBCR 0x3384
+#define MCLK1_CMD_RCGR 0x3390
+#define MCLK1_BCR 0x33B0
+#define MCLK1_CBCR 0x33B4
+#define VFE_CMD_RCGR 0x3600
+#define VFE_BCR 0x36A0
+#define VFE_AHB_BCR 0x36AC
+#define VFE_AXI_BCR 0x36B0
+#define VFE_CBCR 0x36A8
+#define VFE_AHB_CBCR 0x36B8
+#define VFE_AXI_CBCR 0x36BC
+#define CSI_VFE_BCR 0x3700
+#define CSI_VFE_CBCR 0x3704
+#define GFX3D_CMD_RCGR 0x4000
+#define OXILI_GFX3D_CBCR 0x4028
+#define OXILI_GFX3D_BCR 0x4030
+#define OXILI_AHB_BCR 0x4044
+#define OXILI_AHB_CBCR 0x403C
+#define AHB_CMD_RCGR 0x5000
+#define MMSSNOCAHB_BCR 0x5020
+#define MMSSNOCAHB_BTO_BCR 0x5030
+#define MMSS_MISC_AHB_BCR 0x5034
+#define MMSS_MMSSNOC_AHB_CBCR 0x5024
+#define MMSS_MMSSNOC_BTO_AHB_CBCR 0x5028
+#define MMSS_MISC_AHB_CBCR 0x502C
+#define AXI_CMD_RCGR 0x5040
+#define MMSSNOCAXI_BCR 0x5060
+#define MMSS_S0_AXI_BCR 0x5068
+#define MMSS_S0_AXI_CBCR 0x5064
+#define MMSS_MMSSNOC_AXI_CBCR 0x506C
+#define BIMC_GFX_BCR 0x5090
+#define BIMC_GFX_CBCR 0x5094
+
+#define AUDIO_CORE_GDSCR 0x7000
+#define SPDM_BCR 0x1000
+#define LPAAUDIO_PLL_MODE 0x0000
+#define LPAAUDIO_PLL_L_VAL 0x0004
+#define LPAAUDIO_PLL_M_VAL 0x0008
+#define LPAAUDIO_PLL_N_VAL 0x000C
+#define LPAAUDIO_PLL_USER_CTL 0x0010
+#define LPAAUDIO_PLL_STATUS 0x001C
+#define LPAQ6_PLL_MODE 0x1000
+#define LPAQ6_PLL_USER_CTL 0x1010
+#define LPAQ6_PLL_STATUS 0x101C
+#define LPA_PLL_VOTE_APPS 0x2000
+#define AUDIO_CORE_BCR_SLP_CBCR 0x4004
+#define Q6SS_BCR_SLP_CBCR 0x6004
+#define AUDIO_CORE_GDSC_XO_CBCR 0x7004
+#define AUDIO_CORE_LPAIF_DMA_CBCR 0x9000
+#define AUDIO_CORE_LPAIF_CSR_CBCR 0x9004
+#define LPAIF_SPKR_CMD_RCGR 0xA000
+#define AUDIO_CORE_LPAIF_CODEC_SPKR_OSR_CBCR 0xA014
+#define AUDIO_CORE_LPAIF_CODEC_SPKR_IBIT_CBCR 0xA018
+#define AUDIO_CORE_LPAIF_CODEC_SPKR_EBIT_CBCR 0xA01C
+#define LPAIF_PRI_CMD_RCGR 0xB000
+#define AUDIO_CORE_LPAIF_PRI_OSR_CBCR 0xB014
+#define AUDIO_CORE_LPAIF_PRI_IBIT_CBCR 0xB018
+#define AUDIO_CORE_LPAIF_PRI_EBIT_CBCR 0xB01C
+#define LPAIF_SEC_CMD_RCGR 0xC000
+#define AUDIO_CORE_LPAIF_SEC_OSR_CBCR 0xC014
+#define AUDIO_CORE_LPAIF_SEC_IBIT_CBCR 0xC018
+#define AUDIO_CORE_LPAIF_SEC_EBIT_CBCR 0xC01C
+#define LPAIF_TER_CMD_RCGR 0xD000
+#define AUDIO_CORE_LPAIF_TER_OSR_CBCR 0xD014
+#define AUDIO_CORE_LPAIF_TER_IBIT_CBCR 0xD018
+#define AUDIO_CORE_LPAIF_TER_EBIT_CBCR 0xD01C
+#define LPAIF_QUAD_CMD_RCGR 0xE000
+#define AUDIO_CORE_LPAIF_QUAD_OSR_CBCR 0xE014
+#define AUDIO_CORE_LPAIF_QUAD_IBIT_CBCR 0xE018
+#define AUDIO_CORE_LPAIF_QUAD_EBIT_CBCR 0xE01C
+#define LPAIF_PCM0_CMD_RCGR 0xF000
+#define AUDIO_CORE_LPAIF_PCM0_IBIT_CBCR 0xF014
+#define AUDIO_CORE_LPAIF_PCM0_EBIT_CBCR 0xF018
+#define LPAIF_PCM1_CMD_RCGR 0x10000
+#define AUDIO_CORE_LPAIF_PCM1_IBIT_CBCR 0x10014
+#define AUDIO_CORE_LPAIF_PCM1_EBIT_CBCR 0x10018
+#define SLIMBUS_CMD_RCGR 0x12000
+#define AUDIO_CORE_SLIMBUS_CORE_CBCR 0x12014
+#define LPAIF_PCMOE_CMD_RCGR 0x13000
+#define AUDIO_CORE_LPAIF_PCM_DATA_OE_CBCR 0x13014
+#define Q6CORE_CMD_RCGR 0x14000
+#define SLEEP_CMD_RCGR 0x15000
+#define SPDM_CMD_RCGR 0x16000
+#define AUDIO_WRAPPER_SPDM_CBCR 0x16014
+#define XO_CMD_RCGR 0x17000
+#define AHBFABRIC_CMD_RCGR 0x18000
+#define AUDIO_CORE_LPM_CBCR 0x19000
+#define AUDIO_CORE_AVSYNC_CSR_CBCR 0x1A000
+#define AUDIO_CORE_AVSYNC_XO_CBCR 0x1A004
+#define AUDIO_CORE_AVSYNC_BT_XO_CBCR 0x1A008
+#define AUDIO_CORE_AVSYNC_FM_XO_CBCR 0x1A00C
+#define AUDIO_CORE_IXFABRIC_CBCR 0x1B000
+#define AUDIO_WRAPPER_EFABRIC_CBCR 0x1B004
+#define AUDIO_CORE_TCM_SLAVE_CBCR 0x1C000
+#define AUDIO_CORE_CSR_CBCR 0x1D000
+#define AUDIO_CORE_DML_CBCR 0x1E000
+#define AUDIO_CORE_SYSNOC_CBCR 0x1F000
+#define AUDIO_WRAPPER_SYSNOC_SWAY_CBCR 0x1F004
+#define AUDIO_CORE_TIMEOUT_CBCR 0x20000
+#define AUDIO_WRAPPER_TIMEOUT_CBCR 0x20004
+#define AUDIO_CORE_SECURITY_CBCR 0x21000
+#define AUDIO_WRAPPER_SECURITY_CBCR 0x21004
+#define Q6SS_AHB_LFABIF_CBCR 0x22000
+#define Q6SS_AHBM_CBCR 0x22004
+#define AUDIO_WRAPPER_LCC_CSR_CBCR 0x23000
+#define AUDIO_WRAPPER_BR_CBCR 0x24000
+#define AUDIO_WRAPPER_SMEM_CBCR 0x25000
+#define Q6SS_XO_CBCR 0x26000
+#define Q6SS_SLP_CBCR 0x26004
+#define LPASS_Q6SS_BCR 0x6000
+#define AUDIO_WRAPPER_STM_XO_CBCR 0x27000
+#define AUDIO_CORE_IXFABRIC_SPDMTM_CSR_CBCR 0x28000
+#define AUDIO_WRAPPER_EFABRIC_SPDMTM_CSR_CBCR 0x28004
+
+/* Mux source select values */
+#define gcc_xo_source_val 0
+#define gpll0_source_val 1
+#define gnd_source_val 5
+#define mmpll0_mm_source_val 1
+#define mmpll1_mm_source_val 2
+#define gpll0_mm_source_val 5
+#define gcc_xo_mm_source_val 0
+#define mm_gnd_source_val 6
+#define cxo_lpass_source_val 0
+#define lpapll0_lpass_source_val 1
+#define gpll0_lpass_source_val 5
+#define dsipll_mm_source_val 1
+
+#define F(f, s, div, m, n) \
+ { \
+ .freq_hz = (f), \
+ .src_clk = &s##_clk_src.c, \
+ .m_val = (m), \
+ .n_val = ~((n)-(m)) * !!(n), \
+ .d_val = ~(n),\
+ .div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+ | BVAL(10, 8, s##_source_val), \
+ }
+
+#define F_MM(f, s, div, m, n) \
+ { \
+ .freq_hz = (f), \
+ .src_clk = &s##_clk_src.c, \
+ .m_val = (m), \
+ .n_val = ~((n)-(m)) * !!(n), \
+ .d_val = ~(n),\
+ .div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+ | BVAL(10, 8, s##_mm_source_val), \
+ }
+
+#define F_HDMI(f, s, div, m, n) \
+ { \
+ .freq_hz = (f), \
+ .src_clk = &s##_clk_src, \
+ .m_val = (m), \
+ .n_val = ~((n)-(m)) * !!(n), \
+ .d_val = ~(n),\
+ .div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+ | BVAL(10, 8, s##_mm_source_val), \
+ }
+
+#define F_MDSS(f, s, div, m, n) \
+ { \
+ .freq_hz = (f), \
+ .m_val = (m), \
+ .n_val = ~((n)-(m)) * !!(n), \
+ .d_val = ~(n),\
+ .div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+ | BVAL(10, 8, s##_mm_source_val), \
+ }
+
+#define F_LPASS(f, s, div, m, n) \
+ { \
+ .freq_hz = (f), \
+ .src_clk = &s##_clk_src.c, \
+ .m_val = (m), \
+ .n_val = ~((n)-(m)) * !!(n), \
+ .d_val = ~(n),\
+ .div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+ | BVAL(10, 8, s##_lpass_source_val), \
+ }
+
+#define VDD_DIG_FMAX_MAP1(l1, f1) \
+ .vdd_class = &vdd_dig, \
+ .fmax = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ }, \
+ .num_fmax = VDD_DIG_NUM
+#define VDD_DIG_FMAX_MAP2(l1, f1, l2, f2) \
+ .vdd_class = &vdd_dig, \
+ .fmax = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ [VDD_DIG_##l2] = (f2), \
+ }, \
+ .num_fmax = VDD_DIG_NUM
+#define VDD_DIG_FMAX_MAP3(l1, f1, l2, f2, l3, f3) \
+ .vdd_class = &vdd_dig, \
+ .fmax = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ [VDD_DIG_##l2] = (f2), \
+ [VDD_DIG_##l3] = (f3), \
+ }, \
+ .num_fmax = VDD_DIG_NUM
+
+enum vdd_dig_levels {
+ VDD_DIG_NONE,
+ VDD_DIG_LOW,
+ VDD_DIG_NOMINAL,
+ VDD_DIG_HIGH,
+ VDD_DIG_NUM
+};
+
+static const int vdd_corner[] = {
+ [VDD_DIG_NONE] = RPM_REGULATOR_CORNER_NONE,
+ [VDD_DIG_LOW] = RPM_REGULATOR_CORNER_SVS_SOC,
+ [VDD_DIG_NOMINAL] = RPM_REGULATOR_CORNER_NORMAL,
+ [VDD_DIG_HIGH] = RPM_REGULATOR_CORNER_SUPER_TURBO,
+};
+
+static struct rpm_regulator *vdd_dig_reg;
+
+static int set_vdd_dig(struct clk_vdd_class *vdd_class, int level)
+{
+ return rpm_regulator_set_voltage(vdd_dig_reg, vdd_corner[level],
+ RPM_REGULATOR_CORNER_SUPER_TURBO);
+}
+
+static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig, VDD_DIG_NUM);
+
+#define RPM_MISC_CLK_TYPE 0x306b6c63
+#define RPM_BUS_CLK_TYPE 0x316b6c63
+#define RPM_MEM_CLK_TYPE 0x326b6c63
+
+#define RPM_SMD_KEY_ENABLE 0x62616E45
+
+#define CXO_ID 0x0
+#define QDSS_ID 0x1
+#define RPM_SCALING_ENABLE_ID 0x2
+
+#define PNOC_ID 0x0
+#define SNOC_ID 0x1
+#define CNOC_ID 0x2
+#define MMSSNOC_AHB_ID 0x3
+
+#define BIMC_ID 0x0
+#define OXILI_ID 0x1
+#define OCMEM_ID 0x2
+
+#define D0_ID 1
+#define D1_ID 2
+#define A0_ID 3
+#define A1_ID 4
+#define A2_ID 5
+#define DIFF_CLK_ID 7
+#define DIV_CLK_ID 11
+
+DEFINE_CLK_RPM_SMD(pnoc_clk, pnoc_a_clk, RPM_BUS_CLK_TYPE, PNOC_ID, NULL);
+DEFINE_CLK_RPM_SMD(snoc_clk, snoc_a_clk, RPM_BUS_CLK_TYPE, SNOC_ID, NULL);
+DEFINE_CLK_RPM_SMD(cnoc_clk, cnoc_a_clk, RPM_BUS_CLK_TYPE, CNOC_ID, NULL);
+DEFINE_CLK_RPM_SMD(mmssnoc_ahb_clk, mmssnoc_ahb_a_clk, RPM_BUS_CLK_TYPE,
+ MMSSNOC_AHB_ID, NULL);
+
+DEFINE_CLK_RPM_SMD(bimc_clk, bimc_a_clk, RPM_MEM_CLK_TYPE, BIMC_ID, NULL);
+
+DEFINE_CLK_RPM_SMD_BRANCH(gcc_xo_clk_src, gcc_xo_a_clk_src,
+ RPM_MISC_CLK_TYPE, CXO_ID, 19200000);
+DEFINE_CLK_RPM_SMD_QDSS(qdss_clk, qdss_a_clk, RPM_MISC_CLK_TYPE, QDSS_ID);
+
+DEFINE_CLK_RPM_SMD_XO_BUFFER(cxo_d0, cxo_d0_a, D0_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(cxo_d1, cxo_d1_a, D1_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(cxo_a0, cxo_a0_a, A0_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(cxo_a1, cxo_a1_a, A1_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(cxo_a2, cxo_a2_a, A2_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(div_clk, div_a_clk, DIV_CLK_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(diff_clk, diff_a_clk, DIFF_CLK_ID);
+
+DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(cxo_d0_pin, cxo_d0_a_pin, D0_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(cxo_d1_pin, cxo_d1_a_pin, D1_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(cxo_a0_pin, cxo_a0_a_pin, A0_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(cxo_a1_pin, cxo_a1_a_pin, A1_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(cxo_a2_pin, cxo_a2_a_pin, A2_ID);
+
+static DEFINE_CLK_VOTER(pnoc_msmbus_clk, &pnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(snoc_msmbus_clk, &snoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(cnoc_msmbus_clk, &cnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pnoc_msmbus_a_clk, &pnoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(snoc_msmbus_a_clk, &snoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(cnoc_msmbus_a_clk, &cnoc_a_clk.c, LONG_MAX);
+
+static DEFINE_CLK_VOTER(bimc_msmbus_clk, &bimc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(bimc_msmbus_a_clk, &bimc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(bimc_acpu_a_clk, &bimc_a_clk.c, LONG_MAX);
+
+static DEFINE_CLK_VOTER(pnoc_sps_clk, &pnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pnoc_iommu_clk, &pnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pnoc_qseecom_clk, &pnoc_clk.c, LONG_MAX);
+
+static struct pll_vote_clk gpll0_clk_src = {
+ .en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+ .en_mask = BIT(0),
+ .status_reg = (void __iomem *)GPLL0_STATUS,
+ .status_mask = BIT(17),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .parent = &gcc_xo_clk_src.c,
+ .rate = 600000000,
+ .dbg_name = "gpll0_clk_src",
+ .ops = &clk_ops_pll_vote,
+ CLK_INIT(gpll0_clk_src.c),
+ },
+};
+
+static struct pll_vote_clk mmpll0_clk_src = {
+ .en_reg = (void __iomem *)MMSS_PLL_VOTE_APCS_REG,
+ .en_mask = BIT(0),
+ .status_reg = (void __iomem *)MMPLL0_PLL_STATUS,
+ .status_mask = BIT(17),
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .parent = &gcc_xo_clk_src.c,
+ .dbg_name = "mmpll0_clk_src",
+ .rate = 800000000,
+ .ops = &clk_ops_pll_vote,
+ CLK_INIT(mmpll0_clk_src.c),
+ },
+};
+
+static struct pll_config_regs mmpll0_regs __initdata = {
+ .l_reg = (void __iomem *)MMPLL0_PLL_L_VAL,
+ .m_reg = (void __iomem *)MMPLL0_PLL_M_VAL,
+ .n_reg = (void __iomem *)MMPLL0_PLL_N_VAL,
+ .config_reg = (void __iomem *)MMPLL0_PLL_USER_CTL,
+ .mode_reg = (void __iomem *)MMPLL0_PLL_MODE,
+ .base = &virt_bases[MMSS_BASE],
+};
+
+static struct pll_clk mmpll1_clk_src = {
+ .mode_reg = (void __iomem *)MMPLL1_PLL_MODE,
+ .status_reg = (void __iomem *)MMPLL1_PLL_STATUS,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .parent = &gcc_xo_clk_src.c,
+ .dbg_name = "mmpll1_clk_src",
+ .rate = 1200000000,
+ .ops = &clk_ops_local_pll,
+ CLK_INIT(mmpll1_clk_src.c),
+ },
+};
+
+static struct pll_config_regs mmpll1_regs __initdata = {
+ .l_reg = (void __iomem *)MMPLL1_PLL_L_VAL,
+ .m_reg = (void __iomem *)MMPLL1_PLL_M_VAL,
+ .n_reg = (void __iomem *)MMPLL1_PLL_N_VAL,
+ .config_reg = (void __iomem *)MMPLL1_PLL_USER_CTL,
+ .mode_reg = (void __iomem *)MMPLL1_PLL_MODE,
+ .base = &virt_bases[MMSS_BASE],
+};
+
+static struct pll_vote_clk lpapll0_clk_src = {
+ .en_reg = (void __iomem *)LPA_PLL_VOTE_APPS,
+ .en_mask = BIT(0),
+ .status_reg = (void __iomem *)LPAAUDIO_PLL_STATUS,
+ .status_mask = BIT(17),
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .parent = &gcc_xo_clk_src.c,
+ .rate = 491520000,
+ .dbg_name = "lpapll0_clk_src",
+ .ops = &clk_ops_pll_vote,
+ CLK_INIT(lpapll0_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_blsp1_qup1_6_spi_apps_clk[] = {
+ F( 960000, gcc_xo, 10, 1, 2),
+ F( 4800000, gcc_xo, 4, 0, 0),
+ F( 9600000, gcc_xo, 2, 0, 0),
+ F(15000000, gpll0, 10, 1, 4),
+ F(19200000, gcc_xo, 1, 0, 0),
+ F(25000000, gpll0, 12, 1, 2),
+ F(50000000, gpll0, 12, 0, 0),
+ F_END,
+};
+
+static struct rcg_clk blsp1_qup1_spi_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP1_SPI_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup1_spi_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+ CLK_INIT(blsp1_qup1_spi_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_qup2_spi_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP2_SPI_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup2_spi_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+ CLK_INIT(blsp1_qup2_spi_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_qup3_spi_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP3_SPI_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup3_spi_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+ CLK_INIT(blsp1_qup3_spi_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_qup4_spi_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP4_SPI_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup4_spi_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+ CLK_INIT(blsp1_qup4_spi_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_qup5_spi_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP5_SPI_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup5_spi_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+ CLK_INIT(blsp1_qup5_spi_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_qup6_spi_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP6_SPI_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup6_spi_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+ CLK_INIT(blsp1_qup6_spi_apps_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_blsp1_uart1_6_apps_clk[] = {
+ F( 3686400, gpll0, 1, 96, 15625),
+ F( 7372800, gpll0, 1, 192, 15625),
+ F(14745600, gpll0, 1, 384, 15625),
+ F(16000000, gpll0, 5, 2, 15),
+ F(19200000, gcc_xo, 1, 0, 0),
+ F(24000000, gpll0, 5, 1, 5),
+ F(32000000, gpll0, 1, 4, 75),
+ F(40000000, gpll0, 15, 0, 0),
+ F(46400000, gpll0, 1, 29, 375),
+ F(48000000, gpll0, 12.5, 0, 0),
+ F(51200000, gpll0, 1, 32, 375),
+ F(56000000, gpll0, 1, 7, 75),
+ F(58982400, gpll0, 1, 1536, 15625),
+ F(60000000, gpll0, 10, 0, 0),
+ F_END,
+};
+
+static struct rcg_clk blsp1_uart1_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_UART1_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_blsp1_uart1_6_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_uart1_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+ CLK_INIT(blsp1_uart1_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_uart2_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_UART2_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_blsp1_uart1_6_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_uart2_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+ CLK_INIT(blsp1_uart2_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_uart3_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_UART3_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_blsp1_uart1_6_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_uart3_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+ CLK_INIT(blsp1_uart3_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_uart4_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_UART4_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_blsp1_uart1_6_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_uart4_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+ CLK_INIT(blsp1_uart4_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_uart5_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_UART5_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_blsp1_uart1_6_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_uart5_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+ CLK_INIT(blsp1_uart5_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_uart6_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_UART6_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_blsp1_uart1_6_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_uart6_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+ CLK_INIT(blsp1_uart6_apps_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_ce1_clk[] = {
+ F(50000000, gpll0, 12, 0, 0),
+ F(100000000, gpll0, 6, 0, 0),
+ F_END,
+};
+
+static struct rcg_clk ce1_clk_src = {
+ .cmd_rcgr_reg = CE1_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_ce1_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "ce1_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP2(LOW, 50000000, NOMINAL, 100000000),
+ CLK_INIT(ce1_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_gp1_3_clk[] = {
+ F(19200000, gcc_xo, 1, 0, 0),
+ F_END,
+};
+
+static struct rcg_clk gp1_clk_src = {
+ .cmd_rcgr_reg = GP1_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_gp1_3_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gp1_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+ CLK_INIT(gp1_clk_src.c),
+ },
+};
+
+static struct rcg_clk gp2_clk_src = {
+ .cmd_rcgr_reg = GP2_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_gp1_3_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gp2_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+ CLK_INIT(gp2_clk_src.c),
+ },
+};
+
+static struct rcg_clk gp3_clk_src = {
+ .cmd_rcgr_reg = GP3_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_gp1_3_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gp3_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+ CLK_INIT(gp3_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_pdm2_clk[] = {
+ F(60000000, gpll0, 10, 0, 0),
+ F_END,
+};
+
+static struct rcg_clk pdm2_clk_src = {
+ .cmd_rcgr_reg = PDM2_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_pdm2_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "pdm2_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOW, 120000000),
+ CLK_INIT(pdm2_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_sdcc1_2_apps_clk[] = {
+ F( 144000, gcc_xo, 16, 3, 25),
+ F( 400000, gcc_xo, 12, 1, 4),
+ F( 20000000, gpll0, 15, 1, 2),
+ F( 25000000, gpll0, 12, 1, 2),
+ F( 50000000, gpll0, 12, 0, 0),
+ F(100000000, gpll0, 6, 0, 0),
+ F(200000000, gpll0, 3, 0, 0),
+ F_END,
+};
+
+static struct rcg_clk sdcc1_apps_clk_src = {
+ .cmd_rcgr_reg = SDCC1_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_sdcc1_2_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "sdcc1_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+ CLK_INIT(sdcc1_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk sdcc2_apps_clk_src = {
+ .cmd_rcgr_reg = SDCC2_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_sdcc1_2_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "sdcc2_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+ CLK_INIT(sdcc2_apps_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb_hs_system_clk[] = {
+ F(75000000, gpll0, 8, 0, 0),
+ F_END,
+};
+
+static struct rcg_clk usb_hs_system_clk_src = {
+ .cmd_rcgr_reg = USB_HS_SYSTEM_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_usb_hs_system_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "usb_hs_system_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP2(LOW, 60000000, NOMINAL, 100000000),
+ CLK_INIT(usb_hs_system_clk_src.c),
+ },
+};
+
+static struct local_vote_clk gcc_blsp1_ahb_clk = {
+ .cbcr_reg = BLSP1_AHB_CBCR,
+ .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(17),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_ahb_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_blsp1_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup1_i2c_apps_clk = {
+ .cbcr_reg = BLSP1_QUP1_I2C_APPS_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .parent = &gcc_xo_clk_src.c,
+ .dbg_name = "gcc_blsp1_qup1_i2c_apps_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup1_i2c_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup1_spi_apps_clk = {
+ .cbcr_reg = BLSP1_QUP1_SPI_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .parent = &blsp1_qup1_spi_apps_clk_src.c,
+ .dbg_name = "gcc_blsp1_qup1_spi_apps_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup1_spi_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup2_i2c_apps_clk = {
+ .cbcr_reg = BLSP1_QUP2_I2C_APPS_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .parent = &gcc_xo_clk_src.c,
+ .dbg_name = "gcc_blsp1_qup2_i2c_apps_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup2_i2c_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup2_spi_apps_clk = {
+ .cbcr_reg = BLSP1_QUP2_SPI_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .parent = &blsp1_qup2_spi_apps_clk_src.c,
+ .dbg_name = "gcc_blsp1_qup2_spi_apps_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup2_spi_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup3_i2c_apps_clk = {
+ .cbcr_reg = BLSP1_QUP3_I2C_APPS_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .parent = &gcc_xo_clk_src.c,
+ .dbg_name = "gcc_blsp1_qup3_i2c_apps_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup3_i2c_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup3_spi_apps_clk = {
+ .cbcr_reg = BLSP1_QUP3_SPI_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .parent = &blsp1_qup3_spi_apps_clk_src.c,
+ .dbg_name = "gcc_blsp1_qup3_spi_apps_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup3_spi_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup4_i2c_apps_clk = {
+ .cbcr_reg = BLSP1_QUP4_I2C_APPS_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .parent = &gcc_xo_clk_src.c,
+ .dbg_name = "gcc_blsp1_qup4_i2c_apps_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup4_i2c_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup4_spi_apps_clk = {
+ .cbcr_reg = BLSP1_QUP4_SPI_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .parent = &blsp1_qup4_spi_apps_clk_src.c,
+ .dbg_name = "gcc_blsp1_qup4_spi_apps_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup4_spi_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup5_i2c_apps_clk = {
+ .cbcr_reg = BLSP1_QUP5_I2C_APPS_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .parent = &gcc_xo_clk_src.c,
+ .dbg_name = "gcc_blsp1_qup5_i2c_apps_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup5_i2c_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup5_spi_apps_clk = {
+ .cbcr_reg = BLSP1_QUP5_SPI_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .parent = &blsp1_qup5_spi_apps_clk_src.c,
+ .dbg_name = "gcc_blsp1_qup5_spi_apps_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup5_spi_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup6_i2c_apps_clk = {
+ .cbcr_reg = BLSP1_QUP6_I2C_APPS_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .parent = &gcc_xo_clk_src.c,
+ .dbg_name = "gcc_blsp1_qup6_i2c_apps_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup6_i2c_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup6_spi_apps_clk = {
+ .cbcr_reg = BLSP1_QUP6_SPI_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .parent = &blsp1_qup6_spi_apps_clk_src.c,
+ .dbg_name = "gcc_blsp1_qup6_spi_apps_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup6_spi_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_uart1_apps_clk = {
+ .cbcr_reg = BLSP1_UART1_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .parent = &blsp1_uart1_apps_clk_src.c,
+ .dbg_name = "gcc_blsp1_uart1_apps_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_uart1_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_uart2_apps_clk = {
+ .cbcr_reg = BLSP1_UART2_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .parent = &blsp1_uart2_apps_clk_src.c,
+ .dbg_name = "gcc_blsp1_uart2_apps_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_uart2_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_uart3_apps_clk = {
+ .cbcr_reg = BLSP1_UART3_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .parent = &blsp1_uart3_apps_clk_src.c,
+ .dbg_name = "gcc_blsp1_uart3_apps_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_uart3_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_uart4_apps_clk = {
+ .cbcr_reg = BLSP1_UART4_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .parent = &blsp1_uart4_apps_clk_src.c,
+ .dbg_name = "gcc_blsp1_uart4_apps_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_uart4_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_uart5_apps_clk = {
+ .cbcr_reg = BLSP1_UART5_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .parent = &blsp1_uart5_apps_clk_src.c,
+ .dbg_name = "gcc_blsp1_uart5_apps_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_uart5_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_uart6_apps_clk = {
+ .cbcr_reg = BLSP1_UART6_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .parent = &blsp1_uart6_apps_clk_src.c,
+ .dbg_name = "gcc_blsp1_uart6_apps_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_uart6_apps_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_boot_rom_ahb_clk = {
+ .cbcr_reg = BOOT_ROM_AHB_CBCR,
+ .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(10),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_boot_rom_ahb_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_boot_rom_ahb_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_ce1_ahb_clk = {
+ .cbcr_reg = CE1_AHB_CBCR,
+ .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(3),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_ce1_ahb_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_ce1_ahb_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_ce1_axi_clk = {
+ .cbcr_reg = CE1_AXI_CBCR,
+ .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(4),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_ce1_axi_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_ce1_axi_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_ce1_clk = {
+ .cbcr_reg = CE1_CBCR,
+ .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(5),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_ce1_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_ce1_clk.c),
+ },
+};
+
+static struct branch_clk gcc_copss_smmu_ahb_clk = {
+ .cbcr_reg = COPSS_SMMU_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_copss_smmu_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_copss_smmu_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_lpss_smmu_ahb_clk = {
+ .cbcr_reg = LPSS_SMMU_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_lpss_smmu_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_lpss_smmu_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_gp1_clk = {
+ .cbcr_reg = GP1_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .parent = &gp1_clk_src.c,
+ .dbg_name = "gcc_gp1_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_gp1_clk.c),
+ },
+};
+
+static struct branch_clk gcc_gp2_clk = {
+ .cbcr_reg = GP2_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .parent = &gp2_clk_src.c,
+ .dbg_name = "gcc_gp2_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_gp2_clk.c),
+ },
+};
+
+static struct branch_clk gcc_gp3_clk = {
+ .cbcr_reg = GP3_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .parent = &gp3_clk_src.c,
+ .dbg_name = "gcc_gp3_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_gp3_clk.c),
+ },
+};
+
+static struct branch_clk gcc_lpass_q6_axi_clk = {
+ .cbcr_reg = LPASS_Q6_AXI_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_lpass_q6_axi_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_lpass_q6_axi_clk.c),
+ },
+};
+
+static struct branch_clk gcc_mmss_noc_cfg_ahb_clk = {
+ .cbcr_reg = MMSS_NOC_CFG_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_mmss_noc_cfg_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_mmss_noc_cfg_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_mss_cfg_ahb_clk = {
+ .cbcr_reg = MSS_CFG_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_mss_cfg_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_mss_cfg_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_mss_q6_bimc_axi_clk = {
+ .cbcr_reg = MSS_Q6_BIMC_AXI_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_mss_q6_bimc_axi_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_mss_q6_bimc_axi_clk.c),
+ },
+};
+
+static struct branch_clk gcc_pdm2_clk = {
+ .cbcr_reg = PDM2_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .parent = &pdm2_clk_src.c,
+ .dbg_name = "gcc_pdm2_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_pdm2_clk.c),
+ },
+};
+
+static struct branch_clk gcc_pdm_ahb_clk = {
+ .cbcr_reg = PDM_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_pdm_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_pdm_ahb_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_prng_ahb_clk = {
+ .cbcr_reg = PRNG_AHB_CBCR,
+ .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(13),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_prng_ahb_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_prng_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_sdcc1_ahb_clk = {
+ .cbcr_reg = SDCC1_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_sdcc1_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_sdcc1_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_sdcc1_apps_clk = {
+ .cbcr_reg = SDCC1_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .parent = &sdcc1_apps_clk_src.c,
+ .dbg_name = "gcc_sdcc1_apps_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_sdcc1_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_sdcc2_ahb_clk = {
+ .cbcr_reg = SDCC2_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_sdcc2_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_sdcc2_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_sdcc2_apps_clk = {
+ .cbcr_reg = SDCC2_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .parent = &sdcc2_apps_clk_src.c,
+ .dbg_name = "gcc_sdcc2_apps_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_sdcc2_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_usb2a_phy_sleep_clk = {
+ .cbcr_reg = USB2A_PHY_SLEEP_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_usb2a_phy_sleep_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_usb2a_phy_sleep_clk.c),
+ },
+};
+
+static struct branch_clk gcc_usb_hs_ahb_clk = {
+ .cbcr_reg = USB_HS_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_usb_hs_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_usb_hs_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_usb_hs_system_clk = {
+ .cbcr_reg = USB_HS_SYSTEM_CBCR,
+ .has_sibling = 0,
+ .bcr_reg = USB_HS_BCR,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .parent = &usb_hs_system_clk_src.c,
+ .dbg_name = "gcc_usb_hs_system_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_usb_hs_system_clk.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_csi0_1_clk[] = {
+ F_MM(100000000, gpll0, 6, 0, 0),
+ F_MM(200000000, mmpll0, 4, 0, 0),
+ F_END,
+};
+
+static struct rcg_clk csi0_clk_src = {
+ .cmd_rcgr_reg = CSI0_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_csi0_1_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .dbg_name = "csi0_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+ CLK_INIT(csi0_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_mmss_mmssnoc_ahb_clk[] = {
+ F_MM(19200000, gcc_xo, 1, 0, 0),
+ F_MM(40000000, gpll0, 15, 0, 0),
+ F_MM(80000000, mmpll0, 10, 0, 0),
+ F_END,
+};
+
+static struct rcg_clk ahb_clk_src = {
+ .cmd_rcgr_reg = AHB_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_mmss_mmssnoc_ahb_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .dbg_name = "ahb_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP2(LOW, 40000000, NOMINAL, 80000000),
+ CLK_INIT(ahb_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_mmss_mmssnoc_axi_clk[] = {
+ F_MM( 19200000, gcc_xo, 1, 0, 0),
+ F_MM( 37500000, gpll0, 16, 0, 0),
+ F_MM( 50000000, gpll0, 12, 0, 0),
+ F_MM( 75000000, gpll0, 8, 0, 0),
+ F_MM(100000000, gpll0, 6, 0, 0),
+ F_MM(150000000, gpll0, 4, 0, 0),
+ F_MM(200000000, mmpll0, 4, 0, 0),
+ F_END,
+};
+
+static struct rcg_clk axi_clk_src = {
+ .cmd_rcgr_reg = AXI_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_mmss_mmssnoc_axi_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .dbg_name = "axi_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+ CLK_INIT(axi_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_dsi_pclk_clk[] = {
+ F_MDSS( 50000000, dsipll, 10, 0, 0),
+ F_MDSS(103330000, dsipll, 9, 0, 0),
+ F_END,
+};
+
+static struct rcg_clk dsi_pclk_clk_src = {
+ .cmd_rcgr_reg = DSI_PCLK_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_dsi_pclk_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .dbg_name = "dsi_pclk_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 50000000, NOMINAL, 103330000),
+ CLK_INIT(dsi_pclk_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_oxili_gfx3d_clk[] = {
+ F_MM( 19200000, gcc_xo, 1, 0, 0),
+ F_MM( 37500000, gpll0, 16, 0, 0),
+ F_MM( 50000000, gpll0, 12, 0, 0),
+ F_MM( 75000000, gpll0, 8, 0, 0),
+ F_MM(100000000, gpll0, 6, 0, 0),
+ F_MM(150000000, gpll0, 4, 0, 0),
+ F_MM(200000000, gpll0, 3, 0, 0),
+ F_MM(300000000, gpll0, 2, 0, 0),
+ F_MM(400000000, mmpll1, 3, 0, 0),
+ F_END,
+};
+
+static struct rcg_clk gfx3d_clk_src = {
+ .cmd_rcgr_reg = GFX3D_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_oxili_gfx3d_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .dbg_name = "gfx3d_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP3(LOW, 150000000, NOMINAL, 300000000, HIGH,
+ 400000000),
+ CLK_INIT(gfx3d_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_vfe_clk[] = {
+ F_MM( 37500000, gpll0, 16, 0, 0),
+ F_MM( 50000000, gpll0, 12, 0, 0),
+ F_MM( 60000000, gpll0, 10, 0, 0),
+ F_MM( 80000000, gpll0, 7.5, 0, 0),
+ F_MM(100000000, gpll0, 6, 0, 0),
+ F_MM(109090000, gpll0, 5.5, 0, 0),
+ F_MM(133330000, gpll0, 4.5, 0, 0),
+ F_MM(200000000, gpll0, 3, 0, 0),
+ F_MM(228570000, mmpll0, 3.5, 0, 0),
+ F_MM(266670000, mmpll0, 3, 0, 0),
+ F_MM(320000000, mmpll0, 2.5, 0, 0),
+ F_END,
+};
+
+static struct rcg_clk vfe_clk_src = {
+ .cmd_rcgr_reg = VFE_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_vfe_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .dbg_name = "vfe_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP3(LOW, 133330000, NOMINAL, 266670000, HIGH,
+ 320000000),
+ CLK_INIT(vfe_clk_src.c),
+ },
+};
+
+static struct rcg_clk csi1_clk_src = {
+ .cmd_rcgr_reg = CSI1_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_csi0_1_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .dbg_name = "csi1_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+ CLK_INIT(csi1_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_csi0_1phytimer_clk[] = {
+ F_MM(100000000, gpll0, 6, 0, 0),
+ F_MM(200000000, mmpll0, 4, 0, 0),
+ F_END,
+};
+
+static struct rcg_clk csi0phytimer_clk_src = {
+ .cmd_rcgr_reg = CSI0PHYTIMER_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_csi0_1phytimer_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .dbg_name = "csi0phytimer_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+ CLK_INIT(csi0phytimer_clk_src.c),
+ },
+};
+
+static struct rcg_clk csi1phytimer_clk_src = {
+ .cmd_rcgr_reg = CSI1PHYTIMER_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_csi0_1phytimer_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .dbg_name = "csi1phytimer_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+ CLK_INIT(csi1phytimer_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_dsi_clk[] = {
+ F_MDSS(155000000, dsipll, 6, 0, 0),
+ F_MDSS(310000000, dsipll, 3, 0, 0),
+ F_END,
+};
+
+static struct rcg_clk dsi_clk_src = {
+ .cmd_rcgr_reg = DSI_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_dsi_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .dbg_name = "dsi_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 155000000, NOMINAL, 310000000),
+ CLK_INIT(dsi_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_dsi_byte_clk[] = {
+ F_MDSS( 62500000, dsipll, 12, 0, 0),
+ F_MDSS(125000000, dsipll, 6, 0, 0),
+ F_END,
+};
+
+static struct rcg_clk dsi_byte_clk_src = {
+ .cmd_rcgr_reg = DSI_BYTE_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_dsi_byte_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .dbg_name = "dsi_byte_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP2(LOW, 62500000, NOMINAL, 125000000),
+ CLK_INIT(dsi_byte_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_dsi_esc_clk[] = {
+ F_MM(19200000, gcc_xo, 1, 0, 0),
+ F_END,
+};
+
+static struct rcg_clk dsi_esc_clk_src = {
+ .cmd_rcgr_reg = DSI_ESC_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_dsi_esc_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .dbg_name = "dsi_esc_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOW, 19200000),
+ CLK_INIT(dsi_esc_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_mclk0_1_clk[] = {
+ F_MM(66670000, gpll0, 9, 0, 0),
+ F_END,
+};
+
+static struct rcg_clk mclk0_clk_src = {
+ .cmd_rcgr_reg = MCLK0_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_mclk0_1_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .dbg_name = "mclk0_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP1(LOW, 66670000),
+ CLK_INIT(mclk0_clk_src.c),
+ },
+};
+
+static struct rcg_clk mclk1_clk_src = {
+ .cmd_rcgr_reg = MCLK1_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_mclk0_1_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .dbg_name = "mclk1_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP1(LOW, 66670000),
+ CLK_INIT(mclk1_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_mdp_vsync_clk[] = {
+ F_MM(19200000, gcc_xo, 1, 0, 0),
+ F_END,
+};
+
+static struct rcg_clk mdp_vsync_clk_src = {
+ .cmd_rcgr_reg = MDP_VSYNC_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_mdp_vsync_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .dbg_name = "mdp_vsync_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOW, 19200000),
+ CLK_INIT(mdp_vsync_clk_src.c),
+ },
+};
+
+static struct branch_clk bimc_gfx_clk = {
+ .cbcr_reg = BIMC_GFX_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .dbg_name = "bimc_gfx_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(bimc_gfx_clk.c),
+ },
+};
+
+static struct branch_clk csi0_clk = {
+ .cbcr_reg = CSI0_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .parent = &csi0_clk_src.c,
+ .dbg_name = "csi0_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(csi0_clk.c),
+ },
+};
+
+static struct branch_clk csi0phy_clk = {
+ .cbcr_reg = CSI0PHY_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .parent = &csi0_clk_src.c,
+ .dbg_name = "csi0phy_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(csi0phy_clk.c),
+ },
+};
+
+static struct branch_clk csi0phytimer_clk = {
+ .cbcr_reg = CSI0PHYTIMER_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .parent = &csi0phytimer_clk_src.c,
+ .dbg_name = "csi0phytimer_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(csi0phytimer_clk.c),
+ },
+};
+
+static struct branch_clk csi0pix_clk = {
+ .cbcr_reg = CSI0PIX_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .parent = &csi0_clk_src.c,
+ .dbg_name = "csi0pix_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(csi0pix_clk.c),
+ },
+};
+
+static struct branch_clk csi0rdi_clk = {
+ .cbcr_reg = CSI0RDI_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .parent = &csi0_clk_src.c,
+ .dbg_name = "csi0rdi_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(csi0rdi_clk.c),
+ },
+};
+
+static struct branch_clk csi1_clk = {
+ .cbcr_reg = CSI1_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .parent = &csi1_clk_src.c,
+ .dbg_name = "csi1_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(csi1_clk.c),
+ },
+};
+
+static struct branch_clk csi1phy_clk = {
+ .cbcr_reg = CSI1PHY_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .parent = &csi1_clk_src.c,
+ .dbg_name = "csi1phy_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(csi1phy_clk.c),
+ },
+};
+
+static struct branch_clk csi1phytimer_clk = {
+ .cbcr_reg = CSI1PHYTIMER_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .parent = &csi1phytimer_clk_src.c,
+ .dbg_name = "csi1phytimer_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(csi1phytimer_clk.c),
+ },
+};
+
+static struct branch_clk csi1pix_clk = {
+ .cbcr_reg = CSI1PIX_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .parent = &csi0_clk_src.c,
+ .dbg_name = "csi1pix_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(csi1pix_clk.c),
+ },
+};
+
+static struct branch_clk csi1rdi_clk = {
+ .cbcr_reg = CSI1RDI_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .parent = &csi0_clk_src.c,
+ .dbg_name = "csi1rdi_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(csi1rdi_clk.c),
+ },
+};
+
+static struct branch_clk csi_ahb_clk = {
+ .cbcr_reg = CSI_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .dbg_name = "csi_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(csi_ahb_clk.c),
+ },
+};
+
+static struct branch_clk csi_vfe_clk = {
+ .cbcr_reg = CSI_VFE_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .parent = &vfe_clk_src.c,
+ .dbg_name = "csi_vfe_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(csi_vfe_clk.c),
+ },
+};
+
+static struct branch_clk dsi_clk = {
+ .cbcr_reg = DSI_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .parent = &dsi_clk_src.c,
+ .dbg_name = "dsi_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(dsi_clk.c),
+ },
+};
+
+static struct branch_clk dsi_ahb_clk = {
+ .cbcr_reg = DSI_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .dbg_name = "dsi_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(dsi_ahb_clk.c),
+ },
+};
+
+static struct branch_clk dsi_byte_clk = {
+ .cbcr_reg = DSI_BYTE_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .parent = &dsi_byte_clk_src.c,
+ .dbg_name = "dsi_byte_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(dsi_byte_clk.c),
+ },
+};
+
+static struct branch_clk dsi_esc_clk = {
+ .cbcr_reg = DSI_ESC_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .parent = &dsi_esc_clk_src.c,
+ .dbg_name = "dsi_esc_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(dsi_esc_clk.c),
+ },
+};
+
+static struct branch_clk dsi_pclk_clk = {
+ .cbcr_reg = DSI_PCLK_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .parent = &dsi_pclk_clk_src.c,
+ .dbg_name = "dsi_pclk_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(dsi_pclk_clk.c),
+ },
+};
+
+static struct branch_clk gmem_gfx3d_clk = {
+ .cbcr_reg = GMEM_GFX3D_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .parent = &gfx3d_clk_src.c,
+ .dbg_name = "gmem_gfx3d_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gmem_gfx3d_clk.c),
+ },
+};
+
+static struct branch_clk mclk0_clk = {
+ .cbcr_reg = MCLK0_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .parent = &mclk0_clk_src.c,
+ .dbg_name = "mclk0_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(mclk0_clk.c),
+ },
+};
+
+static struct branch_clk mclk1_clk = {
+ .cbcr_reg = MCLK1_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .parent = &mclk1_clk_src.c,
+ .dbg_name = "mclk1_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(mclk1_clk.c),
+ },
+};
+
+static struct branch_clk mdp_ahb_clk = {
+ .cbcr_reg = MDP_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .dbg_name = "mdp_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(mdp_ahb_clk.c),
+ },
+};
+
+static struct branch_clk mdp_axi_clk = {
+ .cbcr_reg = MDP_AXI_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .parent = &axi_clk_src.c,
+ .dbg_name = "mdp_axi_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(mdp_axi_clk.c),
+ },
+};
+
+static struct branch_clk mdp_dsi_clk = {
+ .cbcr_reg = MDP_DSI_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .parent = &dsi_pclk_clk_src.c,
+ .dbg_name = "mdp_dsi_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(mdp_dsi_clk.c),
+ },
+};
+
+static struct branch_clk mdp_lcdc_clk = {
+ .cbcr_reg = MDP_LCDC_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .parent = &dsi_pclk_clk_src.c,
+ .dbg_name = "mdp_lcdc_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(mdp_lcdc_clk.c),
+ },
+};
+
+static struct branch_clk mdp_vsync_clk = {
+ .cbcr_reg = MDP_VSYNC_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .parent = &mdp_vsync_clk_src.c,
+ .dbg_name = "mdp_vsync_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(mdp_vsync_clk.c),
+ },
+};
+
+static struct branch_clk mmss_misc_ahb_clk = {
+ .cbcr_reg = MMSS_MISC_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .dbg_name = "mmss_misc_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(mmss_misc_ahb_clk.c),
+ },
+};
+
+static struct branch_clk mmss_mmssnoc_axi_clk = {
+ .cbcr_reg = MMSS_MMSSNOC_AXI_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .parent = &axi_clk_src.c,
+ .dbg_name = "mmss_mmssnoc_axi_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(mmss_mmssnoc_axi_clk.c),
+ },
+};
+
+static struct branch_clk mmss_s0_axi_clk = {
+ .cbcr_reg = MMSS_S0_AXI_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .parent = &axi_clk_src.c,
+ .dbg_name = "mmss_s0_axi_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(mmss_s0_axi_clk.c),
+ .depends = &mmss_mmssnoc_axi_clk.c,
+ },
+};
+
+static struct branch_clk mmss_mmssnoc_ahb_clk = {
+ .cbcr_reg = MMSS_MMSSNOC_AHB_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .parent = &ahb_clk_src.c,
+ .dbg_name = "mmss_mmssnoc_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(mmss_mmssnoc_ahb_clk.c),
+ },
+};
+
+static struct branch_clk mmss_mmssnoc_bto_ahb_clk = {
+ .cbcr_reg = MMSS_MMSSNOC_BTO_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .dbg_name = "mmss_mmssnoc_bto_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(mmss_mmssnoc_bto_ahb_clk.c),
+ },
+};
+
+static struct branch_clk oxili_ahb_clk = {
+ .cbcr_reg = OXILI_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .dbg_name = "oxili_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(oxili_ahb_clk.c),
+ },
+};
+
+static struct branch_clk oxili_gfx3d_clk = {
+ .cbcr_reg = OXILI_GFX3D_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .parent = &gfx3d_clk_src.c,
+ .dbg_name = "oxili_gfx3d_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(oxili_gfx3d_clk.c),
+ },
+};
+
+static struct branch_clk vfe_clk = {
+ .cbcr_reg = VFE_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .parent = &vfe_clk_src.c,
+ .dbg_name = "vfe_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(vfe_clk.c),
+ },
+};
+
+static struct branch_clk vfe_ahb_clk = {
+ .cbcr_reg = VFE_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .dbg_name = "vfe_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(vfe_ahb_clk.c),
+ },
+};
+
+static struct branch_clk vfe_axi_clk = {
+ .cbcr_reg = VFE_AXI_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .parent = &axi_clk_src.c,
+ .dbg_name = "vfe_axi_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(vfe_axi_clk.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_audio_core_lpaif_clk[] = {
+ F_LPASS( 512000, lpapll0, 16, 1, 60),
+ F_LPASS( 768000, lpapll0, 16, 1, 40),
+ F_LPASS( 1024000, lpapll0, 16, 1, 30),
+ F_LPASS( 1536000, lpapll0, 16, 1, 20),
+ F_LPASS( 2048000, lpapll0, 16, 1, 15),
+ F_LPASS( 3072000, lpapll0, 16, 1, 10),
+ F_LPASS( 4096000, lpapll0, 15, 1, 8),
+ F_LPASS( 6144000, lpapll0, 10, 1, 8),
+ F_LPASS( 8192000, lpapll0, 15, 1, 4),
+ F_LPASS(12288000, lpapll0, 10, 1, 4),
+ F_END,
+};
+
+static struct rcg_clk lpaif_pri_clk_src = {
+ .cmd_rcgr_reg = LPAIF_PRI_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_audio_core_lpaif_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .dbg_name = "lpaif_pri_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 12290000, NOMINAL, 24580000),
+ CLK_INIT(lpaif_pri_clk_src.c),
+ },
+};
+
+static struct rcg_clk lpaif_quad_clk_src = {
+ .cmd_rcgr_reg = LPAIF_QUAD_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_audio_core_lpaif_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .dbg_name = "lpaif_quad_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 12290000, NOMINAL, 24580000),
+ CLK_INIT(lpaif_quad_clk_src.c),
+ },
+};
+
+static struct rcg_clk lpaif_sec_clk_src = {
+ .cmd_rcgr_reg = LPAIF_SEC_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_audio_core_lpaif_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .dbg_name = "lpaif_sec_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 12290000, NOMINAL, 24580000),
+ CLK_INIT(lpaif_sec_clk_src.c),
+ },
+};
+
+static struct rcg_clk lpaif_spkr_clk_src = {
+ .cmd_rcgr_reg = LPAIF_SPKR_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_audio_core_lpaif_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .dbg_name = "lpaif_spkr_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 12290000, NOMINAL, 24580000),
+ CLK_INIT(lpaif_spkr_clk_src.c),
+ },
+};
+
+static struct rcg_clk lpaif_ter_clk_src = {
+ .cmd_rcgr_reg = LPAIF_TER_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_audio_core_lpaif_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .dbg_name = "lpaif_ter_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 12290000, NOMINAL, 24580000),
+ CLK_INIT(lpaif_ter_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_audio_core_lpaif_pcm0_1_clk[] = {
+ F_LPASS( 512000, lpapll0, 16, 1, 60),
+ F_LPASS( 768000, lpapll0, 16, 1, 40),
+ F_LPASS(1024000, lpapll0, 16, 1, 30),
+ F_LPASS(1536000, lpapll0, 16, 1, 20),
+ F_LPASS(2048000, lpapll0, 16, 1, 15),
+ F_LPASS(3072000, lpapll0, 16, 1, 10),
+ F_LPASS(4096000, lpapll0, 15, 1, 8),
+ F_LPASS(6144000, lpapll0, 10, 1, 8),
+ F_LPASS(8192000, lpapll0, 15, 1, 4),
+ F_END,
+};
+
+static struct rcg_clk lpaif_pcm0_clk_src = {
+ .cmd_rcgr_reg = LPAIF_PCM0_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_audio_core_lpaif_pcm0_1_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .dbg_name = "lpaif_pcm0_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 4100000, NOMINAL, 8192000),
+ CLK_INIT(lpaif_pcm0_clk_src.c),
+ },
+};
+
+static struct rcg_clk lpaif_pcm1_clk_src = {
+ .cmd_rcgr_reg = LPAIF_PCM1_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_audio_core_lpaif_pcm0_1_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .dbg_name = "lpaif_pcm1_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 4100000, NOMINAL, 8192000),
+ CLK_INIT(lpaif_pcm1_clk_src.c),
+ },
+};
+
+static struct rcg_clk lpaif_pcmoe_clk_src = {
+ .cmd_rcgr_reg = LPAIF_PCMOE_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_audio_core_lpaif_pcm0_1_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .dbg_name = "lpaif_pcmoe_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 6140000, NOMINAL, 12290000),
+ CLK_INIT(lpaif_pcmoe_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_audio_core_slimbus_core_clock[] = {
+ F_LPASS(24576000, lpapll0, 4, 1, 5),
+ F_END
+};
+
+static struct rcg_clk audio_core_slimbus_core_clk_src = {
+ .cmd_rcgr_reg = SLIMBUS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_audio_core_slimbus_core_clock,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .dbg_name = "audio_core_slimbus_core_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 12935000, NOMINAL, 25869000),
+ CLK_INIT(audio_core_slimbus_core_clk_src.c),
+ },
+};
+
+static struct branch_clk audio_core_slimbus_core_clk = {
+ .cbcr_reg = AUDIO_CORE_SLIMBUS_CORE_CBCR,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .parent = &audio_core_slimbus_core_clk_src.c,
+ .dbg_name = "audio_core_slimbus_core_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(audio_core_slimbus_core_clk.c),
+ },
+};
+
+static struct branch_clk audio_core_ixfabric_clk = {
+ .cbcr_reg = AUDIO_CORE_IXFABRIC_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .dbg_name = "audio_core_ixfabric_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(audio_core_ixfabric_clk.c),
+ },
+};
+
+static struct branch_clk audio_wrapper_br_clk = {
+ .cbcr_reg = AUDIO_WRAPPER_BR_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .dbg_name = "audio_wrapper_br_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(audio_wrapper_br_clk.c),
+ },
+};
+
+static struct branch_clk q6ss_ahb_lfabif_clk = {
+ .cbcr_reg = Q6SS_AHB_LFABIF_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .dbg_name = "q6ss_ahb_lfabif_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(q6ss_ahb_lfabif_clk.c),
+ },
+};
+
+static struct branch_clk q6ss_ahbm_clk = {
+ .cbcr_reg = Q6SS_AHBM_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .dbg_name = "q6ss_ahbm_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(q6ss_ahbm_clk.c),
+ },
+};
+
+static struct branch_clk q6ss_xo_clk = {
+ .cbcr_reg = Q6SS_XO_CBCR,
+ .has_sibling = 1,
+ .bcr_reg = LPASS_Q6SS_BCR,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .parent = &gcc_xo_clk_src.c,
+ .dbg_name = "q6ss_xo_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(q6ss_xo_clk.c),
+ },
+};
+
+static struct branch_clk audio_core_lpaif_pcm_data_oe_clk = {
+ .cbcr_reg = AUDIO_CORE_LPAIF_PCM_DATA_OE_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .parent = &lpaif_pcmoe_clk_src.c,
+ .dbg_name = "audio_core_lpaif_pcm_data_oe_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(audio_core_lpaif_pcm_data_oe_clk.c),
+ },
+};
+
+static struct branch_clk audio_core_lpaif_pri_ebit_clk = {
+ .cbcr_reg = AUDIO_CORE_LPAIF_PRI_EBIT_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .dbg_name = "audio_core_lpaif_pri_ebit_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(audio_core_lpaif_pri_ebit_clk.c),
+ },
+};
+
+static struct branch_clk audio_core_lpaif_pri_ibit_clk = {
+ .cbcr_reg = AUDIO_CORE_LPAIF_PRI_IBIT_CBCR,
+ .has_sibling = 0,
+ .max_div = 511,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .parent = &lpaif_pri_clk_src.c,
+ .dbg_name = "audio_core_lpaif_pri_ibit_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(audio_core_lpaif_pri_ibit_clk.c),
+ },
+};
+
+static struct branch_clk audio_core_lpaif_pri_osr_clk = {
+ .cbcr_reg = AUDIO_CORE_LPAIF_PRI_OSR_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .parent = &lpaif_pri_clk_src.c,
+ .dbg_name = "audio_core_lpaif_pri_osr_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(audio_core_lpaif_pri_osr_clk.c),
+ },
+};
+
+static struct branch_clk audio_core_lpaif_pcm0_ebit_clk = {
+ .cbcr_reg = AUDIO_CORE_LPAIF_PCM0_EBIT_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .dbg_name = "audio_core_lpaif_pcm0_ebit_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(audio_core_lpaif_pcm0_ebit_clk.c),
+ },
+};
+
+static struct branch_clk audio_core_lpaif_pcm0_ibit_clk = {
+ .cbcr_reg = AUDIO_CORE_LPAIF_PCM0_IBIT_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .parent = &lpaif_pcm0_clk_src.c,
+ .dbg_name = "audio_core_lpaif_pcm0_ibit_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(audio_core_lpaif_pcm0_ibit_clk.c),
+ },
+};
+
+static struct branch_clk audio_core_lpaif_quad_ebit_clk = {
+ .cbcr_reg = AUDIO_CORE_LPAIF_QUAD_EBIT_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .dbg_name = "audio_core_lpaif_quad_ebit_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(audio_core_lpaif_quad_ebit_clk.c),
+ },
+};
+
+static struct branch_clk audio_core_lpaif_quad_ibit_clk = {
+ .cbcr_reg = AUDIO_CORE_LPAIF_QUAD_IBIT_CBCR,
+ .has_sibling = 0,
+ .max_div = 511,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .parent = &lpaif_quad_clk_src.c,
+ .dbg_name = "audio_core_lpaif_quad_ibit_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(audio_core_lpaif_quad_ibit_clk.c),
+ },
+};
+
+static struct branch_clk audio_core_lpaif_quad_osr_clk = {
+ .cbcr_reg = AUDIO_CORE_LPAIF_QUAD_OSR_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .parent = &lpaif_quad_clk_src.c,
+ .dbg_name = "audio_core_lpaif_quad_osr_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(audio_core_lpaif_quad_osr_clk.c),
+ },
+};
+
+static struct branch_clk audio_core_lpaif_sec_ebit_clk = {
+ .cbcr_reg = AUDIO_CORE_LPAIF_SEC_EBIT_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .dbg_name = "audio_core_lpaif_sec_ebit_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(audio_core_lpaif_sec_ebit_clk.c),
+ },
+};
+
+static struct branch_clk audio_core_lpaif_sec_ibit_clk = {
+ .cbcr_reg = AUDIO_CORE_LPAIF_SEC_IBIT_CBCR,
+ .has_sibling = 0,
+ .max_div = 511,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .parent = &lpaif_sec_clk_src.c,
+ .dbg_name = "audio_core_lpaif_sec_ibit_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(audio_core_lpaif_sec_ibit_clk.c),
+ },
+};
+
+static struct branch_clk audio_core_lpaif_sec_osr_clk = {
+ .cbcr_reg = AUDIO_CORE_LPAIF_SEC_OSR_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .parent = &lpaif_sec_clk_src.c,
+ .dbg_name = "audio_core_lpaif_sec_osr_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(audio_core_lpaif_sec_osr_clk.c),
+ },
+};
+
+static struct branch_clk audio_core_lpaif_pcm1_ebit_clk = {
+ .cbcr_reg = AUDIO_CORE_LPAIF_PCM1_EBIT_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .dbg_name = "audio_core_lpaif_pcm1_ebit_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(audio_core_lpaif_pcm1_ebit_clk.c),
+ },
+};
+
+static struct branch_clk audio_core_lpaif_pcm1_ibit_clk = {
+ .cbcr_reg = AUDIO_CORE_LPAIF_PCM1_IBIT_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .parent = &lpaif_pcm1_clk_src.c,
+ .dbg_name = "audio_core_lpaif_pcm1_ibit_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(audio_core_lpaif_pcm1_ibit_clk.c),
+ },
+};
+
+static struct branch_clk audio_core_lpaif_codec_spkr_ebit_clk = {
+ .cbcr_reg = AUDIO_CORE_LPAIF_CODEC_SPKR_EBIT_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .dbg_name = "audio_core_lpaif_codec_spkr_ebit_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(audio_core_lpaif_codec_spkr_ebit_clk.c),
+ },
+};
+
+static struct branch_clk audio_core_lpaif_codec_spkr_ibit_clk = {
+ .cbcr_reg = AUDIO_CORE_LPAIF_CODEC_SPKR_IBIT_CBCR,
+ .has_sibling = 1,
+ .max_div = 511,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .parent = &lpaif_spkr_clk_src.c,
+ .dbg_name = "audio_core_lpaif_codec_spkr_ibit_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(audio_core_lpaif_codec_spkr_ibit_clk.c),
+ },
+};
+
+static struct branch_clk audio_core_lpaif_codec_spkr_osr_clk = {
+ .cbcr_reg = AUDIO_CORE_LPAIF_CODEC_SPKR_OSR_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .parent = &lpaif_spkr_clk_src.c,
+ .dbg_name = "audio_core_lpaif_codec_spkr_osr_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(audio_core_lpaif_codec_spkr_osr_clk.c),
+ },
+};
+
+static struct branch_clk audio_core_lpaif_ter_ebit_clk = {
+ .cbcr_reg = AUDIO_CORE_LPAIF_TER_EBIT_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .dbg_name = "audio_core_lpaif_ter_ebit_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(audio_core_lpaif_ter_ebit_clk.c),
+ },
+};
+
+static struct branch_clk audio_core_lpaif_ter_ibit_clk = {
+ .cbcr_reg = AUDIO_CORE_LPAIF_TER_IBIT_CBCR,
+ .has_sibling = 0,
+ .max_div = 511,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .parent = &lpaif_ter_clk_src.c,
+ .dbg_name = "audio_core_lpaif_ter_ibit_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(audio_core_lpaif_ter_ibit_clk.c),
+ },
+};
+
+static struct branch_clk audio_core_lpaif_ter_osr_clk = {
+ .cbcr_reg = AUDIO_CORE_LPAIF_TER_OSR_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .parent = &lpaif_ter_clk_src.c,
+ .dbg_name = "audio_core_lpaif_ter_osr_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(audio_core_lpaif_ter_osr_clk.c),
+ },
+};
+
+#ifdef CONFIG_DEBUG_FS
+
+struct measure_mux_entry {
+ struct clk *c;
+ int base;
+ u32 debug_mux;
+};
+
+static struct measure_mux_entry measure_mux[] = {
+ { &snoc_clk.c, GCC_BASE, 0x0000},
+ { &cnoc_clk.c, GCC_BASE, 0x0008},
+ { &gcc_copss_smmu_ahb_clk.c, GCC_BASE, 0x000c},
+ { &gcc_lpss_smmu_ahb_clk.c, GCC_BASE, 0x000d},
+ { &pnoc_clk.c, GCC_BASE, 0x0010},
+ { &gcc_mmss_noc_cfg_ahb_clk.c, GCC_BASE, 0x002a},
+ { &gcc_mss_cfg_ahb_clk.c, GCC_BASE, 0x0030},
+ { &gcc_mss_q6_bimc_axi_clk.c, GCC_BASE, 0x0031},
+ { &gcc_usb_hs_system_clk.c, GCC_BASE, 0x0060},
+ { &gcc_usb_hs_ahb_clk.c, GCC_BASE, 0x0061},
+ { &gcc_usb2a_phy_sleep_clk.c, GCC_BASE, 0x0063},
+ { &gcc_sdcc1_apps_clk.c, GCC_BASE, 0x0068},
+ { &gcc_sdcc1_ahb_clk.c, GCC_BASE, 0x0069},
+ { &gcc_sdcc2_apps_clk.c, GCC_BASE, 0x0070},
+ { &gcc_sdcc2_ahb_clk.c, GCC_BASE, 0x0071},
+ { &gcc_blsp1_ahb_clk.c, GCC_BASE, 0x0088},
+ {&gcc_blsp1_qup1_spi_apps_clk.c, GCC_BASE, 0x008a},
+ {&gcc_blsp1_qup1_i2c_apps_clk.c, GCC_BASE, 0x008b},
+ { &gcc_blsp1_uart1_apps_clk.c, GCC_BASE, 0x008c},
+ {&gcc_blsp1_qup2_spi_apps_clk.c, GCC_BASE, 0x008e},
+ {&gcc_blsp1_qup2_i2c_apps_clk.c, GCC_BASE, 0x0090},
+ { &gcc_blsp1_uart2_apps_clk.c, GCC_BASE, 0x0091},
+ {&gcc_blsp1_qup3_spi_apps_clk.c, GCC_BASE, 0x0093},
+ {&gcc_blsp1_qup3_i2c_apps_clk.c, GCC_BASE, 0x0094},
+ { &gcc_blsp1_uart3_apps_clk.c, GCC_BASE, 0x0095},
+ {&gcc_blsp1_qup4_spi_apps_clk.c, GCC_BASE, 0x0098},
+ {&gcc_blsp1_qup4_i2c_apps_clk.c, GCC_BASE, 0x0099},
+ { &gcc_blsp1_uart4_apps_clk.c, GCC_BASE, 0x009a},
+ {&gcc_blsp1_qup5_spi_apps_clk.c, GCC_BASE, 0x009c},
+ {&gcc_blsp1_qup5_i2c_apps_clk.c, GCC_BASE, 0x009d},
+ { &gcc_blsp1_uart5_apps_clk.c, GCC_BASE, 0x009e},
+ {&gcc_blsp1_qup6_spi_apps_clk.c, GCC_BASE, 0x00a1},
+ {&gcc_blsp1_qup6_i2c_apps_clk.c, GCC_BASE, 0x00a2},
+ { &gcc_blsp1_uart6_apps_clk.c, GCC_BASE, 0x00a3},
+ { &gcc_pdm_ahb_clk.c, GCC_BASE, 0x00d0},
+ { &gcc_pdm2_clk.c, GCC_BASE, 0x00d2},
+ { &gcc_prng_ahb_clk.c, GCC_BASE, 0x00d8},
+ { &gcc_boot_rom_ahb_clk.c, GCC_BASE, 0x00f8},
+ { &gcc_ce1_clk.c, GCC_BASE, 0x0138},
+ { &gcc_ce1_axi_clk.c, GCC_BASE, 0x0139},
+ { &gcc_ce1_ahb_clk.c, GCC_BASE, 0x013a},
+ { &gcc_xo_clk_src.c, GCC_BASE, 0x0149},
+ { &bimc_clk.c, GCC_BASE, 0x0154},
+ { &gcc_lpass_q6_axi_clk.c, GCC_BASE, 0x0160},
+
+ {&mmss_mmssnoc_ahb_clk.c, MMSS_BASE, 0x0001},
+ { &mmss_misc_ahb_clk.c, MMSS_BASE, 0x0003},
+ {&mmss_mmssnoc_axi_clk.c, MMSS_BASE, 0x0004},
+ { &mmss_s0_axi_clk.c, MMSS_BASE, 0x0005},
+ { &oxili_ahb_clk.c, MMSS_BASE, 0x0007},
+ { &oxili_gfx3d_clk.c, MMSS_BASE, 0x0008},
+ { &gmem_gfx3d_clk.c, MMSS_BASE, 0x0009},
+ { &mdp_axi_clk.c, MMSS_BASE, 0x000a},
+ { &mdp_vsync_clk.c, MMSS_BASE, 0x000b},
+ { &mdp_ahb_clk.c, MMSS_BASE, 0x000c},
+ { &dsi_pclk_clk.c, MMSS_BASE, 0x000d},
+ { &mdp_dsi_clk.c, MMSS_BASE, 0x000e},
+ { &mdp_lcdc_clk.c, MMSS_BASE, 0x000f},
+ { &dsi_clk.c, MMSS_BASE, 0x0010},
+ { &dsi_byte_clk.c, MMSS_BASE, 0x0011},
+ { &dsi_esc_clk.c, MMSS_BASE, 0x0012},
+ { &dsi_ahb_clk.c, MMSS_BASE, 0x0013},
+ { &mclk0_clk.c, MMSS_BASE, 0x0015},
+ { &mclk1_clk.c, MMSS_BASE, 0x0016},
+ { &csi0phytimer_clk.c, MMSS_BASE, 0x0017},
+ { &csi1phytimer_clk.c, MMSS_BASE, 0x0018},
+ { &vfe_clk.c, MMSS_BASE, 0x0019},
+ { &vfe_ahb_clk.c, MMSS_BASE, 0x001a},
+ { &vfe_axi_clk.c, MMSS_BASE, 0x001b},
+ { &csi_vfe_clk.c, MMSS_BASE, 0x001c},
+ { &csi0_clk.c, MMSS_BASE, 0x001d},
+ { &csi_ahb_clk.c, MMSS_BASE, 0x001e},
+ { &csi0phy_clk.c, MMSS_BASE, 0x001f},
+ { &csi0rdi_clk.c, MMSS_BASE, 0x0020},
+ { &csi0pix_clk.c, MMSS_BASE, 0x0021},
+ { &csi1_clk.c, MMSS_BASE, 0x0022},
+ { &csi1phy_clk.c, MMSS_BASE, 0x0023},
+ { &csi1rdi_clk.c, MMSS_BASE, 0x0024},
+ { &csi1pix_clk.c, MMSS_BASE, 0x0025},
+ { &bimc_gfx_clk.c, MMSS_BASE, 0x0032},
+
+ { &lpaif_pcmoe_clk_src.c, LPASS_BASE, 0x000f},
+ { &lpaif_pcm1_clk_src.c, LPASS_BASE, 0x0012},
+ { &lpaif_pcm0_clk_src.c, LPASS_BASE, 0x0013},
+ { &lpaif_quad_clk_src.c, LPASS_BASE, 0x0014},
+ { &lpaif_ter_clk_src.c, LPASS_BASE, 0x0015},
+ { &lpaif_sec_clk_src.c, LPASS_BASE, 0x0016},
+ { &lpaif_pri_clk_src.c, LPASS_BASE, 0x0017},
+ { &lpaif_spkr_clk_src.c, LPASS_BASE, 0x0018},
+ { &q6ss_ahbm_clk.c, LPASS_BASE, 0x001d},
+ { &q6ss_ahb_lfabif_clk.c, LPASS_BASE, 0x001e},
+ { &audio_wrapper_br_clk.c, LPASS_BASE, 0x0022},
+ { &q6ss_xo_clk.c, LPASS_BASE, 0x002b},
+ {&audio_core_lpaif_pcm_data_oe_clk.c, LPASS_BASE, 0x0030},
+ { &audio_core_ixfabric_clk.c, LPASS_BASE, 0x0059},
+
+ {&dummy_clk, N_BASES, 0x0000},
+};
+
+#define GCC_DEBUG_CLK_CTL 0x1880
+#define MMSS_DEBUG_CLK_CTL 0x0900
+#define LPASS_DEBUG_CLK_CTL 0x29000
+#define GLB_CLK_DIAG 0x001C
+
+static int measure_clk_set_parent(struct clk *c, struct clk *parent)
+{
+ struct measure_clk *clk = to_measure_clk(c);
+ unsigned long flags;
+ u32 regval, clk_sel, i;
+
+ if (!parent)
+ return -EINVAL;
+
+ for (i = 0; i < (ARRAY_SIZE(measure_mux) - 1); i++)
+ if (measure_mux[i].c == parent)
+ break;
+
+ if (measure_mux[i].c == &dummy_clk)
+ return -EINVAL;
+
+ spin_lock_irqsave(&local_clock_reg_lock, flags);
+ /*
+ * Program the test vector, measurement period (sample_ticks)
+ * and scaling multiplier.
+ */
+ clk->sample_ticks = 0x10000;
+ clk->multiplier = 1;
+
+ switch (measure_mux[i].base) {
+
+ case GCC_BASE:
+ writel_relaxed(0, GCC_REG_BASE(GCC_DEBUG_CLK_CTL));
+ clk_sel = measure_mux[i].debug_mux;
+ break;
+
+ case MMSS_BASE:
+ writel_relaxed(0, MMSS_REG_BASE(MMSS_DEBUG_CLK_CTL));
+ clk_sel = 0x02C;
+ regval = BVAL(11, 0, measure_mux[i].debug_mux);
+ writel_relaxed(regval, MMSS_REG_BASE(MMSS_DEBUG_CLK_CTL));
+
+ /* Activate debug clock output */
+ regval |= BIT(16);
+ writel_relaxed(regval, MMSS_REG_BASE(MMSS_DEBUG_CLK_CTL));
+ break;
+
+ case LPASS_BASE:
+ writel_relaxed(0, LPASS_REG_BASE(LPASS_DEBUG_CLK_CTL));
+ clk_sel = 0x161;
+ regval = BVAL(11, 0, measure_mux[i].debug_mux);
+ writel_relaxed(regval, LPASS_REG_BASE(LPASS_DEBUG_CLK_CTL));
+
+ /* Activate debug clock output */
+ regval |= BIT(20);
+ writel_relaxed(regval, LPASS_REG_BASE(LPASS_DEBUG_CLK_CTL));
+ break;
+
+ case APCS_BASE:
+ clk->multiplier = 4;
+ clk_sel = 0x16A;
+ regval = measure_mux[i].debug_mux;
+ writel_relaxed(regval, APCS_REG_BASE(GLB_CLK_DIAG));
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ /* Set debug mux clock index */
+ regval = BVAL(8, 0, clk_sel);
+ writel_relaxed(regval, GCC_REG_BASE(GCC_DEBUG_CLK_CTL));
+
+ /* Activate debug clock output */
+ regval |= BIT(16);
+ writel_relaxed(regval, GCC_REG_BASE(GCC_DEBUG_CLK_CTL));
+
+ /* Make sure test vector is set before starting measurements. */
+ mb();
+ spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+ return 0;
+}
+
+#define CLOCK_FRQ_MEASURE_CTL 0x1884
+#define CLOCK_FRQ_MEASURE_STATUS 0x1888
+
+/* Sample clock for 'ticks' reference clock ticks. */
+static u32 run_measurement(unsigned ticks)
+{
+ /* Stop counters and set the XO4 counter start value. */
+ writel_relaxed(ticks, GCC_REG_BASE(CLOCK_FRQ_MEASURE_CTL));
+
+ /* Wait for timer to become ready. */
+ while ((readl_relaxed(GCC_REG_BASE(CLOCK_FRQ_MEASURE_STATUS)) &
+ BIT(25)) != 0)
+ cpu_relax();
+
+ /* Run measurement and wait for completion. */
+ writel_relaxed(BIT(20)|ticks, GCC_REG_BASE(CLOCK_FRQ_MEASURE_CTL));
+ while ((readl_relaxed(GCC_REG_BASE(CLOCK_FRQ_MEASURE_STATUS)) &
+ BIT(25)) == 0)
+ cpu_relax();
+
+ /* Return measured ticks. */
+ return readl_relaxed(GCC_REG_BASE(CLOCK_FRQ_MEASURE_STATUS)) &
+ BM(24, 0);
+}
+
+#define GCC_XO_DIV4_CBCR 0x10C8
+#define PLLTEST_PAD_CFG 0x188C
+
+/*
+ * Perform a hardware rate measurement for a given clock.
+ * FOR DEBUG USE ONLY: Measurements take ~15 ms!
+ */
+static unsigned long measure_clk_get_rate(struct clk *c)
+{
+ unsigned long flags;
+ u32 gcc_xo4_reg_backup;
+ u64 raw_count_short, raw_count_full;
+ struct measure_clk *clk = to_measure_clk(c);
+ unsigned ret;
+
+ ret = clk_prepare_enable(&gcc_xo_clk_src.c);
+ if (ret) {
+ pr_warning("CXO clock failed to enable. Can't measure\n");
+ return 0;
+ }
+
+ spin_lock_irqsave(&local_clock_reg_lock, flags);
+
+ /* Enable CXO/4 and RINGOSC branch. */
+ gcc_xo4_reg_backup = readl_relaxed(GCC_REG_BASE(GCC_XO_DIV4_CBCR));
+ writel_relaxed(0x1, GCC_REG_BASE(GCC_XO_DIV4_CBCR));
+
+ /*
+ * The ring oscillator counter will not reset if the measured clock
+ * is not running. To detect this, run a short measurement before
+ * the full measurement. If the raw results of the two are the same
+ * then the clock must be off.
+ */
+
+ /* Run a short measurement. (~1 ms) */
+ raw_count_short = run_measurement(0x1000);
+ /* Run a full measurement. (~14 ms) */
+ raw_count_full = run_measurement(clk->sample_ticks);
+
+ writel_relaxed(gcc_xo4_reg_backup, GCC_REG_BASE(GCC_XO_DIV4_CBCR));
+
+ /* Return 0 if the clock is off. */
+ if (raw_count_full == raw_count_short) {
+ ret = 0;
+ } else {
+ /* Compute rate in Hz. */
+ raw_count_full = ((raw_count_full * 10) + 15) * 4800000;
+ do_div(raw_count_full, ((clk->sample_ticks * 10) + 35));
+ ret = (raw_count_full * clk->multiplier);
+ }
+
+ writel_relaxed(0x51A00, GCC_REG_BASE(PLLTEST_PAD_CFG));
+ spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+ clk_disable_unprepare(&gcc_xo_clk_src.c);
+
+ return ret;
+}
+#else /* !CONFIG_DEBUG_FS */
+static int measure_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ return -EINVAL;
+}
+
+static unsigned long measure_clk_get_rate(struct clk *clk)
+{
+ return 0;
+}
+#endif /* CONFIG_DEBUG_FS */
+
+static struct clk_ops clk_ops_measure = {
+ .set_parent = measure_clk_set_parent,
+ .get_rate = measure_clk_get_rate,
+};
+
+static struct measure_clk measure_clk = {
+ .c = {
+ .dbg_name = "measure_clk",
+ .ops = &clk_ops_measure,
+ CLK_INIT(measure_clk.c),
+ },
+ .multiplier = 1,
+};
+
+static struct clk_lookup msm_clocks_8910[] = {
+ CLK_LOOKUP("xo", gcc_xo_clk_src.c, "msm_otg"),
+ CLK_LOOKUP("xo", gcc_xo_clk_src.c, "fe200000.qcom,lpass"),
+ CLK_LOOKUP("xo", gcc_xo_clk_src.c, "pil-q6v5-mss"),
+ CLK_LOOKUP("xo", gcc_xo_clk_src.c, "pil-mba"),
+ CLK_LOOKUP("xo", gcc_xo_clk_src.c, "fb000000.qcom,wcnss-wlan"),
+ CLK_LOOKUP("xo", gcc_xo_clk_src.c, "pil_pronto"),
+ CLK_LOOKUP("measure", measure_clk.c, "debug"),
+
+ CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f991f000.serial"),
+ CLK_LOOKUP("core_clk", gcc_blsp1_uart3_apps_clk.c, "f991f000.serial"),
+
+ CLK_LOOKUP("dfab_clk", pnoc_sps_clk.c, "msm_sps"),
+ CLK_LOOKUP("bus_clk", pnoc_qseecom_clk.c, "qseecom"),
+
+ CLK_LOOKUP("bus_clk", snoc_clk.c, ""),
+ CLK_LOOKUP("bus_clk", pnoc_clk.c, ""),
+ CLK_LOOKUP("bus_clk", cnoc_clk.c, ""),
+ CLK_LOOKUP("mem_clk", bimc_clk.c, ""),
+ CLK_LOOKUP("bus_clk", snoc_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", pnoc_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", cnoc_a_clk.c, ""),
+ CLK_LOOKUP("mem_clk", bimc_a_clk.c, ""),
+
+ CLK_LOOKUP("bus_clk", cnoc_msmbus_clk.c, "msm_config_noc"),
+ CLK_LOOKUP("bus_a_clk", cnoc_msmbus_a_clk.c, "msm_config_noc"),
+ CLK_LOOKUP("bus_clk", snoc_msmbus_clk.c, "msm_sys_noc"),
+ CLK_LOOKUP("bus_a_clk", snoc_msmbus_a_clk.c, "msm_sys_noc"),
+ CLK_LOOKUP("bus_clk", pnoc_msmbus_clk.c, "msm_periph_noc"),
+ CLK_LOOKUP("bus_a_clk", pnoc_msmbus_a_clk.c, "msm_periph_noc"),
+ CLK_LOOKUP("mem_clk", bimc_msmbus_clk.c, "msm_bimc"),
+ CLK_LOOKUP("mem_a_clk", bimc_msmbus_a_clk.c, "msm_bimc"),
+ CLK_LOOKUP("mem_clk", bimc_acpu_a_clk.c, ""),
+
+ CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-tmc-etr"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-tpiu"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-replicator"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-tmc-etf"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-merg"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-in0"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-in1"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-kpss"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-mmss"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-stm"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-etm0"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-etm1"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-etm2"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-etm3"),
+
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-tmc-etr"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-tpiu"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-replicator"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-tmc-etf"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-merg"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-in0"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-in1"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-kpss"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-mmss"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-stm"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-etm0"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-etm1"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-etm2"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-etm3"),
+
+ CLK_LOOKUP("core_clk_src", blsp1_qup1_spi_apps_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", blsp1_qup2_spi_apps_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", blsp1_qup3_spi_apps_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", blsp1_qup4_spi_apps_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", blsp1_qup5_spi_apps_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", blsp1_qup6_spi_apps_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", blsp1_uart1_apps_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", blsp1_uart2_apps_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", blsp1_uart3_apps_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", blsp1_uart4_apps_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", blsp1_uart5_apps_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", blsp1_uart6_apps_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", ce1_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", gp1_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", gp2_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", gp3_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", pdm2_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", sdcc1_apps_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", sdcc2_apps_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", usb_hs_system_clk_src.c, ""),
+
+ CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup1_i2c_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup1_spi_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup2_i2c_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup2_spi_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup3_i2c_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup3_spi_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup4_i2c_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup4_spi_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup5_i2c_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup5_spi_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup6_i2c_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup6_spi_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_uart1_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_uart2_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_uart3_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_uart4_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_uart5_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_uart6_apps_clk.c, ""),
+ CLK_LOOKUP("iface_clk", gcc_boot_rom_ahb_clk.c, ""),
+ CLK_LOOKUP("iface_clk", gcc_ce1_ahb_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_ce1_axi_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_ce1_clk.c, ""),
+ CLK_LOOKUP("iface_clk", gcc_copss_smmu_ahb_clk.c, ""),
+ CLK_LOOKUP("iface_clk", gcc_lpss_smmu_ahb_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_gp1_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_gp2_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_gp3_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_lpass_q6_axi_clk.c, ""),
+ CLK_LOOKUP("iface_clk", gcc_mss_cfg_ahb_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_mss_q6_bimc_axi_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_pdm2_clk.c, ""),
+ CLK_LOOKUP("iface_clk", gcc_pdm_ahb_clk.c, ""),
+ CLK_LOOKUP("iface_clk", gcc_prng_ahb_clk.c, ""),
+ 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("iface_clk", gcc_sdcc2_ahb_clk.c, "msm_sdcc.2"),
+ CLK_LOOKUP("core_clk", gcc_sdcc2_apps_clk.c, "msm_sdcc.2"),
+ CLK_LOOKUP("core_clk", gcc_usb2a_phy_sleep_clk.c, ""),
+ CLK_LOOKUP("iface_clk", gcc_usb_hs_ahb_clk.c, "f9a55000.usb"),
+ CLK_LOOKUP("core_clk", gcc_usb_hs_system_clk.c, "f9a55000.usb"),
+
+ CLK_LOOKUP("core_clk_src", csi0_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", axi_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", dsi_pclk_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", gfx3d_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", vfe_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", csi1_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", csi0phytimer_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", csi1phytimer_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", dsi_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", dsi_byte_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", dsi_esc_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", mclk0_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", mclk1_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", mdp_vsync_clk_src.c, ""),
+
+ CLK_LOOKUP("core_clk", bimc_gfx_clk.c, ""),
+ CLK_LOOKUP("core_clk", csi0_clk.c, ""),
+ CLK_LOOKUP("core_clk", csi0phy_clk.c, ""),
+ CLK_LOOKUP("core_clk", csi0phytimer_clk.c, ""),
+ CLK_LOOKUP("core_clk", csi0pix_clk.c, ""),
+ CLK_LOOKUP("core_clk", csi0rdi_clk.c, ""),
+ CLK_LOOKUP("core_clk", csi1_clk.c, ""),
+ CLK_LOOKUP("core_clk", csi1phy_clk.c, ""),
+ CLK_LOOKUP("core_clk", csi1phytimer_clk.c, ""),
+ CLK_LOOKUP("core_clk", csi1pix_clk.c, ""),
+ CLK_LOOKUP("core_clk", csi1rdi_clk.c, ""),
+ CLK_LOOKUP("core_clk", csi_ahb_clk.c, ""),
+ CLK_LOOKUP("core_clk", csi_vfe_clk.c, ""),
+ CLK_LOOKUP("core_clk", dsi_clk.c, ""),
+ CLK_LOOKUP("core_clk", dsi_ahb_clk.c, ""),
+ CLK_LOOKUP("core_clk", dsi_byte_clk.c, ""),
+ CLK_LOOKUP("core_clk", dsi_esc_clk.c, ""),
+ CLK_LOOKUP("core_clk", dsi_pclk_clk.c, ""),
+ CLK_LOOKUP("core_clk", gmem_gfx3d_clk.c, ""),
+ CLK_LOOKUP("core_clk", mclk0_clk.c, ""),
+ CLK_LOOKUP("core_clk", mclk1_clk.c, ""),
+ CLK_LOOKUP("core_clk", mdp_ahb_clk.c, ""),
+ CLK_LOOKUP("core_clk", mdp_axi_clk.c, ""),
+ CLK_LOOKUP("core_clk", mdp_dsi_clk.c, ""),
+ CLK_LOOKUP("core_clk", mdp_lcdc_clk.c, ""),
+ CLK_LOOKUP("core_clk", mdp_vsync_clk.c, ""),
+ CLK_LOOKUP("core_clk", mmss_misc_ahb_clk.c, ""),
+ CLK_LOOKUP("core_clk", mmss_s0_axi_clk.c, ""),
+ CLK_LOOKUP("core_clk", mmss_mmssnoc_ahb_clk.c, ""),
+ CLK_LOOKUP("core_clk", mmss_mmssnoc_bto_ahb_clk.c, ""),
+ CLK_LOOKUP("core_clk", mmss_mmssnoc_axi_clk.c, ""),
+ CLK_LOOKUP("core_clk", vfe_clk.c, ""),
+ CLK_LOOKUP("core_clk", vfe_ahb_clk.c, ""),
+ CLK_LOOKUP("core_clk", vfe_axi_clk.c, ""),
+
+ CLK_LOOKUP("core_clk", oxili_gfx3d_clk.c, "fdc00000.qcom,kgsl-3d0"),
+ CLK_LOOKUP("iface_clk", oxili_ahb_clk.c, "fdc00000.qcom,kgsl-3d0"),
+ CLK_LOOKUP("mem_iface_clk", bimc_gfx_clk.c, "fdc00000.qcom,kgsl-3d0"),
+ CLK_LOOKUP("mem_clk", gmem_gfx3d_clk.c, "fdc00000.qcom,kgsl-3d0"),
+
+ CLK_LOOKUP("iface_clk", vfe_ahb_clk.c, "fd890000.qcom,iommu"),
+ CLK_LOOKUP("core_clk", vfe_axi_clk.c, "fd890000.qcom,iommu"),
+ CLK_LOOKUP("iface_clk", mdp_ahb_clk.c, "fd860000.qcom,iommu"),
+ CLK_LOOKUP("core_clk", mdp_axi_clk.c, "fd860000.qcom,iommu"),
+ CLK_LOOKUP("iface_clk", mdp_ahb_clk.c, "fd870000.qcom,iommu"),
+ CLK_LOOKUP("core_clk", mdp_axi_clk.c, "fd870000.qcom,iommu"),
+ CLK_LOOKUP("iface_clk", oxili_ahb_clk.c, "fd880000.qcom,iommu"),
+ CLK_LOOKUP("core_clk", bimc_gfx_clk.c, "fd880000.qcom,iommu"),
+ CLK_LOOKUP("iface_clk", gcc_lpss_smmu_ahb_clk.c, "fd000000.qcom,iommu"),
+ CLK_LOOKUP("core_clk", gcc_lpass_q6_axi_clk.c, "fd000000.qcom,iommu"),
+ CLK_LOOKUP("iface_clk", gcc_copss_smmu_ahb_clk.c,
+ "fd010000.qcom,iommu"),
+ CLK_LOOKUP("core_clk", pnoc_iommu_clk.c, "fd010000.qcom,iommu"),
+
+ CLK_LOOKUP("core_clk_src", lpaif_pri_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", lpaif_quad_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", lpaif_sec_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", lpaif_spkr_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", lpaif_ter_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", lpaif_pcm0_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", lpaif_pcm1_clk_src.c, ""),
+ CLK_LOOKUP("core_clk_src", lpaif_pcmoe_clk_src.c, ""),
+ CLK_LOOKUP("core_clk", audio_core_ixfabric_clk.c, ""),
+ CLK_LOOKUP("core_clk", audio_wrapper_br_clk.c, ""),
+ CLK_LOOKUP("core_clk", q6ss_ahb_lfabif_clk.c, ""),
+ CLK_LOOKUP("core_clk", q6ss_ahbm_clk.c, ""),
+ CLK_LOOKUP("core_clk", q6ss_xo_clk.c, ""),
+ CLK_LOOKUP("core_clk", audio_core_lpaif_pcm_data_oe_clk.c, ""),
+ CLK_LOOKUP("core_clk", audio_core_lpaif_pri_ebit_clk.c, ""),
+ CLK_LOOKUP("core_clk", audio_core_lpaif_pri_ibit_clk.c, ""),
+ CLK_LOOKUP("core_clk", audio_core_lpaif_pri_osr_clk.c, ""),
+ CLK_LOOKUP("core_clk", audio_core_lpaif_pcm0_ebit_clk.c, ""),
+ CLK_LOOKUP("core_clk", audio_core_lpaif_pcm0_ibit_clk.c, ""),
+ CLK_LOOKUP("core_clk", audio_core_lpaif_quad_ebit_clk.c, ""),
+ CLK_LOOKUP("core_clk", audio_core_lpaif_quad_ibit_clk.c, ""),
+ CLK_LOOKUP("core_clk", audio_core_lpaif_quad_osr_clk.c, ""),
+ CLK_LOOKUP("core_clk", audio_core_lpaif_sec_ebit_clk.c, ""),
+ CLK_LOOKUP("core_clk", audio_core_lpaif_sec_ibit_clk.c, ""),
+ CLK_LOOKUP("core_clk", audio_core_lpaif_sec_osr_clk.c, ""),
+ CLK_LOOKUP("core_clk", audio_core_lpaif_pcm1_ebit_clk.c, ""),
+ CLK_LOOKUP("core_clk", audio_core_lpaif_pcm1_ibit_clk.c, ""),
+ CLK_LOOKUP("core_clk", audio_core_lpaif_codec_spkr_ebit_clk.c, ""),
+ CLK_LOOKUP("core_clk", audio_core_lpaif_codec_spkr_ibit_clk.c, ""),
+ CLK_LOOKUP("core_clk", audio_core_lpaif_codec_spkr_osr_clk.c, ""),
+ CLK_LOOKUP("core_clk", audio_core_lpaif_ter_ebit_clk.c, ""),
+ CLK_LOOKUP("core_clk", audio_core_lpaif_ter_ibit_clk.c, ""),
+ CLK_LOOKUP("core_clk", audio_core_lpaif_ter_osr_clk.c, ""),
+
+ CLK_LOOKUP("core_clk", q6ss_xo_clk.c, "fe200000.qcom,lpass"),
+ CLK_LOOKUP("bus_clk", gcc_lpass_q6_axi_clk.c, "fe200000.qcom,lpass"),
+ CLK_LOOKUP("iface_clk", q6ss_ahb_lfabif_clk.c, "fe200000.qcom,lpass"),
+ CLK_LOOKUP("reg_clk", q6ss_ahbm_clk.c, "fe200000.qcom,lpass"),
+};
+
+static struct clk_lookup msm_clocks_8910_rumi[] = {
+ CLK_DUMMY("core_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
+ CLK_DUMMY("iface_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
+ CLK_DUMMY("iface_clk", HSUSB_IFACE_CLK, "f9a55000.usb", OFF),
+ CLK_DUMMY("core_clk", HSUSB_CORE_CLK, "f9a55000.usb", OFF),
+ CLK_DUMMY("iface_clk", NULL, "msm_sdcc.1", OFF),
+ CLK_DUMMY("core_clk", NULL, "msm_sdcc.1", OFF),
+ CLK_DUMMY("bus_clk", NULL, "msm_sdcc.1", OFF),
+ 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),
+ CLK_DUMMY("iface_clk", NULL, "fd890000.qcom,iommu", OFF),
+ CLK_DUMMY("core_clk", NULL, "fd890000.qcom,iommu", OFF),
+ CLK_DUMMY("iface_clk", NULL, "fd860000.qcom,iommu", OFF),
+ CLK_DUMMY("core_clk", NULL, "fd860000.qcom,iommu", OFF),
+ CLK_DUMMY("iface_clk", NULL, "fd870000.qcom,iommu", OFF),
+ CLK_DUMMY("core_clk", NULL, "fd870000.qcom,iommu", OFF),
+ CLK_DUMMY("iface_clk", NULL, "fd880000.qcom,iommu", OFF),
+ CLK_DUMMY("core_clk", NULL, "fd880000.qcom,iommu", OFF),
+ CLK_DUMMY("iface_clk", NULL, "fd000000.qcom,iommu", OFF),
+ CLK_DUMMY("core_clk", NULL, "fd000000.qcom,iommu", OFF),
+ CLK_DUMMY("iface_clk", NULL, "fd010000.qcom,iommu", OFF),
+ CLK_DUMMY("core_clk", NULL, "fd010000.qcom,iommu", OFF),
+};
+
+struct clock_init_data msm8910_rumi_clock_init_data __initdata = {
+ .table = msm_clocks_8910_rumi,
+ .size = ARRAY_SIZE(msm_clocks_8910_rumi),
+};
+
+static struct pll_config_regs gpll0_regs __initdata = {
+ .l_reg = (void __iomem *)GPLL0_L_VAL,
+ .m_reg = (void __iomem *)GPLL0_M_VAL,
+ .n_reg = (void __iomem *)GPLL0_N_VAL,
+ .config_reg = (void __iomem *)GPLL0_USER_CTL,
+ .mode_reg = (void __iomem *)GPLL0_MODE,
+ .base = &virt_bases[GCC_BASE],
+};
+
+/* GPLL0 at 600 MHz, main output enabled. */
+static struct pll_config gpll0_config __initdata = {
+ .l = 0x1f,
+ .m = 0x1,
+ .n = 0x4,
+ .vco_val = 0x0,
+ .vco_mask = BM(21, 20),
+ .pre_div_val = 0x0,
+ .pre_div_mask = BM(14, 12),
+ .post_div_val = 0x0,
+ .post_div_mask = BM(9, 8),
+ .mn_ena_val = BIT(24),
+ .mn_ena_mask = BIT(24),
+ .main_output_val = BIT(0),
+ .main_output_mask = BIT(0),
+};
+
+/* MMPLL0 at 800 MHz, main output enabled. */
+static struct pll_config mmpll0_config __initdata = {
+ .l = 0x29,
+ .m = 0x2,
+ .n = 0x3,
+ .vco_val = 0x0,
+ .vco_mask = BM(21, 20),
+ .pre_div_val = 0x0,
+ .pre_div_mask = BM(14, 12),
+ .post_div_val = 0x0,
+ .post_div_mask = BM(9, 8),
+ .mn_ena_val = BIT(24),
+ .mn_ena_mask = BIT(24),
+ .main_output_val = BIT(0),
+ .main_output_mask = BIT(0),
+};
+
+/* MMPLL1 at 1200 MHz, main output enabled. */
+static struct pll_config mmpll1_config __initdata = {
+ .l = 0x3E,
+ .m = 0x1,
+ .n = 0x2,
+ .vco_val = 0x0,
+ .vco_mask = BM(21, 20),
+ .pre_div_val = 0x0,
+ .pre_div_mask = BM(14, 12),
+ .post_div_val = 0x0,
+ .post_div_mask = BM(9, 8),
+ .mn_ena_val = BIT(24),
+ .mn_ena_mask = BIT(24),
+ .main_output_val = BIT(0),
+ .main_output_mask = BIT(0),
+};
+
+static struct pll_config_regs lpapll0_regs __initdata = {
+ .l_reg = (void __iomem *)LPAAUDIO_PLL_L_VAL,
+ .m_reg = (void __iomem *)LPAAUDIO_PLL_M_VAL,
+ .n_reg = (void __iomem *)LPAAUDIO_PLL_N_VAL,
+ .config_reg = (void __iomem *)LPAAUDIO_PLL_USER_CTL,
+ .mode_reg = (void __iomem *)LPAAUDIO_PLL_MODE,
+ .base = &virt_bases[LPASS_BASE],
+};
+
+/* LPAPLL0 at 491.52 MHz, main output enabled. */
+static struct pll_config lpapll0_config __initdata = {
+ .l = 0x33,
+ .m = 0x1,
+ .n = 0x5,
+ .vco_val = 0x0,
+ .vco_mask = BM(21, 20),
+ .pre_div_val = BVAL(14, 12, 0x1),
+ .pre_div_mask = BM(14, 12),
+ .post_div_val = 0x0,
+ .post_div_mask = BM(9, 8),
+ .mn_ena_val = BIT(24),
+ .mn_ena_mask = BIT(24),
+ .main_output_val = BIT(0),
+ .main_output_mask = BIT(0),
+};
+
+#define PLL_AUX_OUTPUT_BIT 1
+#define PLL_AUX2_OUTPUT_BIT 2
+
+#define PWR_ON_MASK BIT(31)
+#define EN_REST_WAIT_MASK (0xF << 20)
+#define EN_FEW_WAIT_MASK (0xF << 16)
+#define CLK_DIS_WAIT_MASK (0xF << 12)
+#define SW_OVERRIDE_MASK BIT(2)
+#define HW_CONTROL_MASK BIT(1)
+#define SW_COLLAPSE_MASK BIT(0)
+
+/* Wait 2^n CXO cycles between all states. Here, n=2 (4 cycles). */
+#define EN_REST_WAIT_VAL (0x2 << 20)
+#define EN_FEW_WAIT_VAL (0x2 << 16)
+#define CLK_DIS_WAIT_VAL (0x2 << 12)
+#define GDSC_TIMEOUT_US 50000
+
+static void __init reg_init(void)
+{
+ u32 regval, status;
+ int ret;
+
+ if (!(readl_relaxed(GCC_REG_BASE(GPLL0_STATUS))
+ & gpll0_clk_src.status_mask))
+ configure_sr_hpm_lp_pll(&gpll0_config, &gpll0_regs, 1);
+
+ configure_sr_hpm_lp_pll(&mmpll0_config, &mmpll0_regs, 1);
+ configure_sr_hpm_lp_pll(&mmpll1_config, &mmpll1_regs, 1);
+ configure_sr_hpm_lp_pll(&lpapll0_config, &lpapll0_regs, 1);
+
+ /* Enable GPLL0's aux outputs. */
+ regval = readl_relaxed(GCC_REG_BASE(GPLL0_USER_CTL));
+ regval |= BIT(PLL_AUX_OUTPUT_BIT) | BIT(PLL_AUX2_OUTPUT_BIT);
+ writel_relaxed(regval, GCC_REG_BASE(GPLL0_USER_CTL));
+
+ /* Vote for GPLL0 to turn on. Needed by acpuclock. */
+ regval = readl_relaxed(GCC_REG_BASE(APCS_GPLL_ENA_VOTE));
+ regval |= BIT(0);
+ writel_relaxed(regval, GCC_REG_BASE(APCS_GPLL_ENA_VOTE));
+
+ /*
+ * TODO: Confirm that no clocks need to be voted on in this sleep vote
+ * register.
+ */
+ writel_relaxed(0x0, GCC_REG_BASE(APCS_CLOCK_SLEEP_ENA_VOTE));
+
+ /*
+ * TODO: The following sequence enables the LPASS audio core GDSC.
+ * Remove when this becomes unnecessary.
+ */
+
+ /*
+ * Disable HW trigger: collapse/restore occur based on registers writes.
+ * Disable SW override: Use hardware state-machine for sequencing.
+ */
+ regval = readl_relaxed(LPASS_REG_BASE(AUDIO_CORE_GDSCR));
+ regval &= ~(HW_CONTROL_MASK | SW_OVERRIDE_MASK);
+
+ /* Configure wait time between states. */
+ regval &= ~(EN_REST_WAIT_MASK | EN_FEW_WAIT_MASK | CLK_DIS_WAIT_MASK);
+ regval |= EN_REST_WAIT_VAL | EN_FEW_WAIT_VAL | CLK_DIS_WAIT_VAL;
+ writel_relaxed(regval, LPASS_REG_BASE(AUDIO_CORE_GDSCR));
+
+ regval = readl_relaxed(LPASS_REG_BASE(AUDIO_CORE_GDSCR));
+ regval &= ~BIT(0);
+ writel_relaxed(regval, LPASS_REG_BASE(AUDIO_CORE_GDSCR));
+
+ ret = readl_poll_timeout(LPASS_REG_BASE(AUDIO_CORE_GDSCR), status,
+ status & PWR_ON_MASK, 50, GDSC_TIMEOUT_US);
+ WARN(ret, "LPASS Audio Core GDSC did not power on.\n");
+}
+
+static void __init msm8910_clock_post_init(void)
+{
+ /*
+ * Hold an active set vote for CXO; this is because CXO is expected
+ * to remain on whenever CPUs aren't power collapsed.
+ */
+ clk_prepare_enable(&gcc_xo_a_clk_src.c);
+
+
+ /* Set rates for single-rate clocks. */
+ clk_set_rate(&usb_hs_system_clk_src.c,
+ usb_hs_system_clk_src.freq_tbl[0].freq_hz);
+ clk_set_rate(&pdm2_clk_src.c, pdm2_clk_src.freq_tbl[0].freq_hz);
+ clk_set_rate(&mclk0_clk_src.c, mclk0_clk_src.freq_tbl[0].freq_hz);
+ clk_set_rate(&mclk1_clk_src.c, mclk1_clk_src.freq_tbl[0].freq_hz);
+ clk_set_rate(&audio_core_slimbus_core_clk_src.c,
+ audio_core_slimbus_core_clk_src.freq_tbl[0].freq_hz);
+}
+
+#define GCC_CC_PHYS 0xFC400000
+#define GCC_CC_SIZE SZ_16K
+
+#define MMSS_CC_PHYS 0xFD8C0000
+#define MMSS_CC_SIZE SZ_256K
+
+#define LPASS_CC_PHYS 0xFE000000
+#define LPASS_CC_SIZE SZ_256K
+
+#define APCS_GCC_CC_PHYS 0xF9011000
+#define APCS_GCC_CC_SIZE SZ_4K
+
+static void __init msm8910_clock_pre_init(void)
+{
+ virt_bases[GCC_BASE] = ioremap(GCC_CC_PHYS, GCC_CC_SIZE);
+ if (!virt_bases[GCC_BASE])
+ panic("clock-8910: Unable to ioremap GCC memory!");
+
+ virt_bases[MMSS_BASE] = ioremap(MMSS_CC_PHYS, MMSS_CC_SIZE);
+ if (!virt_bases[MMSS_BASE])
+ panic("clock-8910: Unable to ioremap MMSS_CC memory!");
+
+ virt_bases[LPASS_BASE] = ioremap(LPASS_CC_PHYS, LPASS_CC_SIZE);
+ if (!virt_bases[LPASS_BASE])
+ panic("clock-8910: Unable to ioremap LPASS_CC memory!");
+
+ virt_bases[APCS_BASE] = ioremap(APCS_GCC_CC_PHYS, APCS_GCC_CC_SIZE);
+ if (!virt_bases[APCS_BASE])
+ panic("clock-8910: Unable to ioremap APCS_GCC_CC memory!");
+
+ clk_ops_local_pll.enable = sr_hpm_lp_pll_clk_enable;
+
+ vdd_dig_reg = rpm_regulator_get(NULL, "vdd_dig");
+ if (IS_ERR(vdd_dig_reg))
+ panic("clock-8910: Unable to get the vdd_dig regulator!");
+
+ /*
+ * TODO: Set a voltage and enable vdd_dig, leaving the voltage high
+ * until late_init. This may not be necessary with clock handoff;
+ * Investigate this code on a real non-simulator target to determine
+ * its necessity.
+ */
+ vote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
+ rpm_regulator_enable(vdd_dig_reg);
+
+ enable_rpm_scaling();
+
+ /* Enable a clock to allow access to MMSS clock registers */
+ clk_prepare_enable(&gcc_mmss_noc_cfg_ahb_clk.c),
+
+ reg_init();
+
+ /* TODO: Remove this once the bus driver is in place */
+ clk_set_rate(&ahb_clk_src.c, 40000000);
+ clk_set_rate(&axi_clk_src.c, 200000000);
+ clk_prepare_enable(&mmss_mmssnoc_ahb_clk.c);
+ clk_prepare_enable(&mmss_s0_axi_clk.c);
+
+ /* TODO: Temporarily enable a clock to allow access to LPASS core
+ * registers.
+ */
+ clk_prepare_enable(&audio_core_ixfabric_clk.c);
+}
+
+static int __init msm8910_clock_late_init(void)
+{
+ return unvote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
+}
+
+struct clock_init_data msm8910_clock_init_data __initdata = {
+ .table = msm_clocks_8910,
+ .size = ARRAY_SIZE(msm_clocks_8910),
+ .pre_init = msm8910_clock_pre_init,
+ .post_init = msm8910_clock_post_init,
+ .late_init = msm8910_clock_late_init,
+};
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 4a885c8..760587f 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -2326,6 +2326,7 @@
static struct branch_clk gcc_usb_hsic_system_clk = {
.cbcr_reg = USB_HSIC_SYSTEM_CBCR,
+ .bcr_reg = USB_HS_HSIC_BCR,
.base = &virt_bases[GCC_BASE],
.c = {
.parent = &usb_hsic_system_clk_src.c,
@@ -3020,34 +3021,17 @@
static int hdmi_pll_clk_enable(struct clk *c)
{
- int ret;
- unsigned long flags;
-
- spin_lock_irqsave(&local_clock_reg_lock, flags);
- ret = hdmi_pll_enable();
- spin_unlock_irqrestore(&local_clock_reg_lock, flags);
- return ret;
+ return hdmi_pll_enable();
}
static void hdmi_pll_clk_disable(struct clk *c)
{
- unsigned long flags;
-
- spin_lock_irqsave(&local_clock_reg_lock, flags);
hdmi_pll_disable();
- spin_unlock_irqrestore(&local_clock_reg_lock, flags);
}
static int hdmi_pll_clk_set_rate(struct clk *c, unsigned long rate)
{
- unsigned long flags;
- int rc;
-
- spin_lock_irqsave(&local_clock_reg_lock, flags);
- rc = hdmi_pll_set_rate(rate);
- spin_unlock_irqrestore(&local_clock_reg_lock, flags);
-
- return rc;
+ return hdmi_pll_set_rate(rate);
}
static struct clk_ops clk_ops_hdmi_pll = {
@@ -3084,21 +3068,39 @@
* Unlike other clocks, the HDMI rate is adjusted through PLL
* re-programming. It is also routed through an HID divider.
*/
-static void set_rate_hdmi(struct rcg_clk *rcg, struct clk_freq_tbl *nf)
+static int rcg_clk_set_rate_hdmi(struct clk *c, unsigned long rate)
{
- clk_set_rate(nf->src_clk, nf->freq_hz);
+ struct clk_freq_tbl *nf;
+ struct rcg_clk *rcg = to_rcg_clk(c);
+ int rc;
+
+ for (nf = rcg->freq_tbl; nf->freq_hz != rate; nf++)
+ if (nf->freq_hz == FREQ_END) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ rc = clk_set_rate(nf->src_clk, rate);
+ if (rc < 0)
+ goto out;
set_rate_hid(rcg, nf);
+
+ rcg->current_freq = nf;
+ c->parent = nf->src_clk;
+out:
+ return rc;
}
+static struct clk_ops clk_ops_rcg_hdmi;
+
static struct rcg_clk extpclk_clk_src = {
.cmd_rcgr_reg = EXTPCLK_CMD_RCGR,
- .set_rate = set_rate_hdmi,
.freq_tbl = ftbl_mdss_extpclk_clk,
.current_freq = &rcg_dummy_freq,
.base = &virt_bases[MMSS_BASE],
.c = {
.dbg_name = "extpclk_clk_src",
- .ops = &clk_ops_rcg,
+ .ops = &clk_ops_rcg_hdmi,
VDD_DIG_FMAX_MAP2(LOW, 148500000, NOMINAL, 297000000),
CLK_INIT(extpclk_clk_src.c),
},
@@ -5140,11 +5142,11 @@
CLK_LOOKUP("pixel_clk", mdss_edppixel_clk.c, "fd923400.qcom,mdss_edp"),
CLK_LOOKUP("link_clk", mdss_edplink_clk.c, "fd923400.qcom,mdss_edp"),
CLK_LOOKUP("byte_clk", mdss_byte0_clk.c, "fd922800.qcom,mdss_dsi"),
- CLK_LOOKUP("byte_clk", mdss_byte1_clk.c, ""),
+ CLK_LOOKUP("byte_clk", mdss_byte1_clk.c, "fd922e00.qcom,mdss_dsi"),
CLK_LOOKUP("core_clk", mdss_esc0_clk.c, "fd922800.qcom,mdss_dsi"),
- CLK_LOOKUP("core_clk", mdss_esc1_clk.c, ""),
+ CLK_LOOKUP("core_clk", mdss_esc1_clk.c, "fd922e00.qcom,mdss_dsi"),
CLK_LOOKUP("pixel_clk", mdss_pclk0_clk.c, "fd922800.qcom,mdss_dsi"),
- CLK_LOOKUP("pixel_clk", mdss_pclk1_clk.c, ""),
+ CLK_LOOKUP("pixel_clk", mdss_pclk1_clk.c, "fd922e00.qcom,mdss_dsi"),
CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd922100.qcom,hdmi_tx"),
CLK_LOOKUP("alt_iface_clk", mdss_hdmi_ahb_clk.c,
"fd922100.qcom,hdmi_tx"),
@@ -5687,6 +5689,9 @@
clk_ops_pixel = clk_ops_rcg;
clk_ops_pixel.set_rate = set_rate_pixel;
+ clk_ops_rcg_hdmi = clk_ops_rcg;
+ clk_ops_rcg_hdmi.set_rate = rcg_clk_set_rate_hdmi;
+
mdss_clk_ctrl_init();
}
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index 5923951..cf42355 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -461,13 +461,28 @@
static int branch_clk_list_rate(struct clk *c, unsigned n)
{
+ int level, fmax = 0, rate;
struct branch_clk *branch = to_branch_clk(c);
+ struct clk *parent = c->parent;
if (branch->has_sibling == 1)
return -ENXIO;
- if (c->parent && c->parent->ops->list_rate)
- return c->parent->ops->list_rate(c->parent, n);
+ if (!parent || !parent->ops->list_rate)
+ return -ENXIO;
+
+ /* Find max frequency supported within voltage constraints. */
+ if (!parent->vdd_class) {
+ fmax = INT_MAX;
+ } else {
+ for (level = 0; level < parent->num_fmax; level++)
+ if (parent->fmax[level])
+ fmax = parent->fmax[level];
+ }
+
+ rate = parent->ops->list_rate(parent, n);
+ if (rate <= fmax)
+ return rate;
else
return -ENXIO;
}
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index c30e566..79bc639 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -350,9 +350,11 @@
void hdmi_pll_disable(void)
{
+ clk_enable(mdss_dsi_ahb_clk);
REG_W(0x0, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
udelay(5);
REG_W(0x0, hdmi_phy_base + HDMI_PHY_GLB_CFG);
+ clk_disable(mdss_dsi_ahb_clk);
hdmi_pll_on = 0;
} /* hdmi_pll_disable */
@@ -362,6 +364,7 @@
u32 status;
u32 max_reads, timeout_us;
+ clk_enable(mdss_dsi_ahb_clk);
/* Global Enable */
REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
/* Power up power gen */
@@ -387,6 +390,7 @@
pr_err("%s: hdmi phy pll status=%x failed to Lock\n",
__func__, status);
hdmi_pll_disable();
+ clk_disable(mdss_dsi_ahb_clk);
return -EINVAL;
}
pr_debug("%s: hdmi phy pll is locked\n", __func__);
@@ -400,9 +404,11 @@
pr_err("%s: hdmi phy status=%x failed to Lock\n",
__func__, status);
hdmi_pll_disable();
+ clk_disable(mdss_dsi_ahb_clk);
return -EINVAL;
}
pr_debug("%s: hdmi phy is locked\n", __func__);
+ clk_disable(mdss_dsi_ahb_clk);
hdmi_pll_on = 1;
@@ -418,6 +424,7 @@
set_power_dwn = 1;
}
+ clk_enable(mdss_dsi_ahb_clk);
pr_debug("%s: rate=%ld\n", __func__, rate);
switch (rate) {
case 0:
@@ -746,6 +753,8 @@
/* Make sure writes complete before disabling iface clock */
mb();
+ clk_disable(mdss_dsi_ahb_clk);
+
if (set_power_dwn)
hdmi_pll_enable();
diff --git a/arch/arm/mach-msm/clock-pll.c b/arch/arm/mach-msm/clock-pll.c
index 8e11d37..cd4ead1 100644
--- a/arch/arm/mach-msm/clock-pll.c
+++ b/arch/arm/mach-msm/clock-pll.c
@@ -54,6 +54,7 @@
static DEFINE_SPINLOCK(pll_reg_lock);
#define ENABLE_WAIT_MAX_LOOPS 200
+#define PLL_LOCKED_BIT BIT(16)
static int pll_vote_clk_enable(struct clk *c)
{
@@ -148,6 +149,51 @@
writel_relaxed(regval, pll_config);
}
+static int sr2_pll_clk_enable(struct clk *c)
+{
+ unsigned long flags;
+ struct pll_clk *pll = to_pll_clk(c);
+ int ret = 0, count;
+ u32 mode = readl_relaxed(PLL_MODE_REG(pll));
+
+ spin_lock_irqsave(&pll_reg_lock, flags);
+
+ /* Disable PLL bypass mode. */
+ mode |= PLL_BYPASSNL;
+ writel_relaxed(mode, PLL_MODE_REG(pll));
+
+ /*
+ * H/W requires a 5us delay between disabling the bypass and
+ * de-asserting the reset. Delay 10us just to be safe.
+ */
+ mb();
+ udelay(10);
+
+ /* De-assert active-low PLL reset. */
+ mode |= PLL_RESET_N;
+ writel_relaxed(mode, PLL_MODE_REG(pll));
+
+ /* Wait for pll to lock. */
+ for (count = ENABLE_WAIT_MAX_LOOPS; count > 0; count--) {
+ if (readl_relaxed(PLL_STATUS_REG(pll)) & PLL_LOCKED_BIT)
+ break;
+ udelay(1);
+ }
+
+ if (!(readl_relaxed(PLL_STATUS_REG(pll)) & PLL_LOCKED_BIT))
+ pr_err("PLL %s didn't lock after enabling it!\n", c->dbg_name);
+
+ /* Enable PLL output. */
+ mode |= PLL_OUTCTRL;
+ writel_relaxed(mode, PLL_MODE_REG(pll));
+
+ /* Ensure that the write above goes through before returning. */
+ mb();
+
+ spin_unlock_irqrestore(&pll_reg_lock, flags);
+ return ret;
+}
+
static void __pll_clk_enable_reg(void __iomem *mode_reg)
{
u32 mode = readl_relaxed(mode_reg);
@@ -290,8 +336,6 @@
return 0;
}
-#define PLL_LOCKED_BIT BIT(16)
-
int sr_hpm_lp_pll_clk_enable(struct clk *c)
{
unsigned long flags;
@@ -337,6 +381,13 @@
.handoff = local_pll_clk_handoff,
};
+struct clk_ops clk_ops_sr2_pll = {
+ .enable = sr2_pll_clk_enable,
+ .disable = local_pll_clk_disable,
+ .set_rate = local_pll_clk_set_rate,
+ .handoff = local_pll_clk_handoff,
+};
+
struct pll_rate {
unsigned int lvalue;
unsigned long rate;
diff --git a/arch/arm/mach-msm/clock-pll.h b/arch/arm/mach-msm/clock-pll.h
index cb334d7..823103a 100644
--- a/arch/arm/mach-msm/clock-pll.h
+++ b/arch/arm/mach-msm/clock-pll.h
@@ -160,6 +160,7 @@
};
extern struct clk_ops clk_ops_local_pll;
+extern struct clk_ops clk_ops_sr2_pll;
static inline struct pll_clk *to_pll_clk(struct clk *c)
{
diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h
index 8a75d390..181cf4c 100644
--- a/arch/arm/mach-msm/clock.h
+++ b/arch/arm/mach-msm/clock.h
@@ -49,6 +49,8 @@
extern struct clock_init_data msm8930_pm8917_clock_init_data;
extern struct clock_init_data msm8974_clock_init_data;
extern struct clock_init_data msm8974_rumi_clock_init_data;
+extern struct clock_init_data msm8910_clock_init_data;
+extern struct clock_init_data msm8910_rumi_clock_init_data;
int msm_clock_init(struct clock_init_data *data);
int find_vdd_level(struct clk *clk, unsigned long rate);
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 0bfaa71..dcd90d0 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -20,6 +20,7 @@
#include <linux/dma-mapping.h>
#include <linux/coresight.h>
#include <linux/avtimer.h>
+#include <linux/ahci_platform.h>
#include <mach/irqs-8064.h>
#include <mach/board.h>
#include <mach/msm_iomap.h>
@@ -1777,6 +1778,48 @@
return platform_device_register(pdev);
}
+#define MSM_SATA_AHCI_BASE 0x29000000
+#define MSM_SATA_AHCI_REGS_SZ 0x17C
+
+static struct resource resources_ahci[] = {
+ {
+ .name = "ahci_mem",
+ .flags = IORESOURCE_MEM,
+ .start = MSM_SATA_AHCI_BASE,
+ .end = MSM_SATA_AHCI_BASE + MSM_SATA_AHCI_REGS_SZ - 1,
+ },
+ {
+ .name = "ahci_irq",
+ .flags = IORESOURCE_IRQ,
+ .start = SATA_CONTROLLER_IRQ,
+ .end = SATA_CONTROLLER_IRQ,
+ },
+};
+
+static u64 ahci_dma_mask = DMA_BIT_MASK(32);
+static struct platform_device apq8064_device_ahci = {
+ .name = "ahci",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(resources_ahci),
+ .resource = resources_ahci,
+ .dev = {
+ .dma_mask = &ahci_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
+int __init apq8064_add_ahci(struct ahci_platform_data *platd)
+{
+ struct platform_device *pdev;
+
+ if (!platd)
+ return -EINVAL;
+
+ pdev = &apq8064_device_ahci;
+ pdev->dev.platform_data = platd;
+ return platform_device_register(pdev);
+}
+
static struct resource resources_sps[] = {
{
.name = "pipe_mem",
@@ -2796,7 +2839,7 @@
.slack_weight_thresh_pct = 3,
.slack_time_min_us = 45000,
.slack_time_max_us = 45000,
- .ss_iobusy_conv = 100,
+ .ss_no_corr_below_freq = 0,
.ss_win_size_min_us = 1000000,
.ss_win_size_max_us = 1000000,
.ss_util_pct = 95,
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 0b10784..4780c57 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -3030,7 +3030,7 @@
.ss_win_size_min_us = 1000000,
.ss_win_size_max_us = 1000000,
.ss_util_pct = 95,
- .ss_iobusy_conv = 100,
+ .ss_no_corr_below_freq = 0,
},
.energy_coeffs = {
.active_coeff_a = 2492,
@@ -3067,7 +3067,7 @@
.ss_win_size_min_us = 1000000,
.ss_win_size_max_us = 1000000,
.ss_util_pct = 95,
- .ss_iobusy_conv = 100,
+ .ss_no_corr_below_freq = 0,
},
.energy_coeffs = {
.active_coeff_a = 2492,
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index b3d887e..2d9872e 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -36,6 +36,7 @@
#include "devices-msm7x2xa.h"
#include "footswitch.h"
#include "acpuclock.h"
+#include "acpuclock-8625q.h"
#include "spm.h"
#include "mpm-8625.h"
#include "irq.h"
@@ -240,6 +241,21 @@
.dev.platform_data = &msm7x27aa_acpuclk_pdata,
};
+static struct acpuclk_pdata msm8625q_pdata = {
+ .max_speed_delta_khz = 801600,
+};
+
+static struct acpuclk_pdata_8625q msm8625q_acpuclk_pdata = {
+ .acpu_clk_data = &msm8625q_pdata,
+ .pvs_voltage_uv = 1350000,
+};
+
+struct platform_device msm8625q_device_acpuclk = {
+ .name = "acpuclock-8625q",
+ .id = -1,
+ .dev.platform_data = &msm8625q_acpuclk_pdata,
+};
+
static struct acpuclk_pdata msm8625_acpuclk_pdata = {
/* TODO: Need to update speed delta from H/w Team */
.max_speed_delta_khz = 604800,
@@ -1775,13 +1791,6 @@
},
};
-struct msm_cpr_vp_data vp_data = {
- .min_volt = 1000000,
- .max_volt = 1350000,
- .default_volt = 1300000,
- .step_size = 12500,
-};
-
static uint32_t
msm_cpr_get_quot(uint32_t max_quot, uint32_t max_freq, uint32_t new_freq)
{
@@ -1823,7 +1832,7 @@
.max_freq = 1401600,
.max_quot = 0,
.disable_cpr = false,
- .vp_data = &vp_data,
+ .step_size = 12500,
.get_quot = msm_cpr_get_quot,
.clk_enable = msm_cpr_clk_enable,
};
@@ -1930,6 +1939,8 @@
else if (msm8625_cpu_id() == MSM8625)
msm_cpr_pdata.max_freq = 1008000;
+ if (machine_is_qrd_skud_prime() || cpu_is_msm8625q())
+ msm_cpr_pdata.step_size = 6250;
platform_device_register(&msm8625_vp_device);
platform_device_register(&msm8625_device_cpr);
}
@@ -2036,6 +2047,24 @@
return ret;
}
+static int __init msm_acpuclock_init(int nominal_voltage,
+ int default_turbo_voltage)
+{
+ struct cpr_info_type *acpu_info = NULL;
+ acpu_info = kzalloc(sizeof(struct cpr_info_type), GFP_KERNEL);
+ if (!acpu_info) {
+ pr_err("%s: Out of memory %d\n", __func__, -ENOMEM);
+ return -ENOMEM;
+ }
+ msm_smem_get_cpr_info(acpu_info);
+ msm8625q_acpuclk_pdata.pvs_voltage_uv =
+ msm_c2_pmic_mv[acpu_info->pvs_fuse & 0x1F];
+ kfree(acpu_info);
+ msm8625q_acpuclk_pdata.nominal_voltage = nominal_voltage;
+ msm8625q_acpuclk_pdata.default_turbo_voltage = default_turbo_voltage;
+ return 0;
+}
+
int __init msm7x2x_misc_init(void)
{
if (machine_is_msm8625_rumi3()) {
@@ -2047,8 +2076,14 @@
msm_clock_init(&msm7x27a_clock_init_data);
if (cpu_is_msm7x27aa() || cpu_is_msm7x25ab())
platform_device_register(&msm7x27aa_device_acpuclk);
- else if (cpu_is_msm8625() || cpu_is_msm8625q()) {
- if (msm8625_cpu_id() == MSM8625)
+ else if (cpu_is_msm8625q()) {
+ msm_acpuclock_init(1050000, 0);
+ platform_device_register(&msm8625q_device_acpuclk);
+ } else if (cpu_is_msm8625()) {
+ if (machine_is_qrd_skud_prime()) {
+ msm_acpuclock_init(1150000, 1275000);
+ platform_device_register(&msm8625q_device_acpuclk);
+ } else if (msm8625_cpu_id() == MSM8625)
platform_device_register(&msm7x27aa_device_acpuclk);
else if (msm8625_cpu_id() == MSM8625A)
platform_device_register(&msm8625_device_acpuclk);
diff --git a/arch/arm/mach-msm/hsic_sysmon.c b/arch/arm/mach-msm/hsic_sysmon.c
index 153e1b4..e088435 100644
--- a/arch/arm/mach-msm/hsic_sysmon.c
+++ b/arch/arm/mach-msm/hsic_sysmon.c
@@ -410,6 +410,7 @@
static const struct usb_device_id hsic_sysmon_ids[] = {
{ USB_DEVICE(0x5c6, 0x9048), .driver_info = 1, },
{ USB_DEVICE(0x5c6, 0x904C), .driver_info = 1, },
+ { USB_DEVICE(0x5c6, 0x9075), .driver_info = 1, },
{} /* terminating entry */
};
MODULE_DEVICE_TABLE(usb, hsic_sysmon_ids);
diff --git a/arch/arm/mach-msm/idle-v7.S b/arch/arm/mach-msm/idle-v7.S
index ccd0bf7..9a22996 100644
--- a/arch/arm/mach-msm/idle-v7.S
+++ b/arch/arm/mach-msm/idle-v7.S
@@ -96,20 +96,6 @@
mrc p15, 0, r9, c13, c0, 3 /* TPIDRURO */
mrc p15, 0, ip, c13, c0, 1 /* context ID */
stmia r0!, {r1-r9, ip}
-#ifdef CONFIG_MSM_CPU_AVS
- mrc p15, 7, r1, c15, c1, 7 /* AVSCSR is the Adaptive Voltage Scaling
- * Control and Status Register */
- mrc p15, 7, r2, c15, c0, 6 /* AVSDSCR is the Adaptive Voltage
- * Scaling Delay Synthesizer Control
- * Register */
-#ifndef CONFIG_ARCH_MSM_KRAIT
- mrc p15, 7, r3, c15, c1, 0 /* TSCSR is the Temperature Status and
- * Control Register
- */
-#endif
-
- stmia r0!, {r1-r3}
-#endif
#ifdef CONFIG_MSM_JTAG
bl msm_jtag_save_state
@@ -240,14 +226,6 @@
add r1, r1, r2
#endif
-#ifdef CONFIG_MSM_CPU_AVS
- ldmdb r1!, {r2-r4}
-#ifndef CONFIG_ARCH_MSM_KRAIT
- mcr p15, 7, r4, c15, c1, 0 /* TSCSR */
-#endif
- mcr p15, 7, r3, c15, c0, 6 /* AVSDSCR */
- mcr p15, 7, r2, c15, c1, 7 /* AVSCSR */
-#endif
ldmdb r1!, {r2-r11}
mcr p15, 0, r4, c3, c0, 0 /* dacr */
mcr p15, 0, r3, c2, c0, 0 /* TTBR0 */
diff --git a/arch/arm/mach-msm/idle.h b/arch/arm/mach-msm/idle.h
index ee3209c..5550e96 100644
--- a/arch/arm/mach-msm/idle.h
+++ b/arch/arm/mach-msm/idle.h
@@ -14,13 +14,8 @@
#ifndef _ARCH_ARM_MACH_MSM_IDLE_H_
#define _ARCH_ARM_MACH_MSM_IDLE_H_
-#ifdef CONFIG_MSM_CPU_AVS
-/* 11 general purpose registers (r4-r14), 10 cp15 registers, 3 AVS registers */
-#define CPU_SAVED_STATE_SIZE (4 * 11 + 4 * 10 + 4 * 3)
-#else
/* 11 general purpose registers (r4-r14), 10 cp15 registers */
#define CPU_SAVED_STATE_SIZE (4 * 11 + 4 * 10)
-#endif
#define ON 1
#define OFF 0
diff --git a/arch/arm/mach-msm/include/mach/msm_dcvs_scm.h b/arch/arm/mach-msm/include/mach/msm_dcvs_scm.h
index 597fdc0..7eefd54 100644
--- a/arch/arm/mach-msm/include/mach/msm_dcvs_scm.h
+++ b/arch/arm/mach-msm/include/mach/msm_dcvs_scm.h
@@ -48,7 +48,7 @@
uint32_t slack_time_min_us;
uint32_t slack_time_max_us;
uint32_t slack_weight_thresh_pct;
- uint32_t ss_iobusy_conv;
+ uint32_t ss_no_corr_below_freq;
uint32_t ss_win_size_min_us;
uint32_t ss_win_size_max_us;
uint32_t ss_util_pct;
diff --git a/arch/arm/mach-msm/include/mach/msm_hdmi_audio_codec.h b/arch/arm/mach-msm/include/mach/msm_hdmi_audio_codec.h
new file mode 100644
index 0000000..95f33d5
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_hdmi_audio_codec.h
@@ -0,0 +1,37 @@
+/* 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_HDMI_AUDIO_CODEC_H__
+#define __MSM_HDMI_AUDIO_CODEC_H__
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+
+struct msm_hdmi_audio_edid_blk {
+ u8 *audio_data_blk;
+ unsigned int audio_data_blk_size; /* in bytes */
+ u8 *spk_alloc_data_blk;
+ unsigned int spk_alloc_data_blk_size; /* in bytes */
+};
+
+struct msm_hdmi_audio_codec_ops {
+ int (*audio_info_setup)(struct platform_device *pdev,
+ u32 num_of_channels, u32 channel_allocation, u32 level_shift,
+ bool down_mix);
+ int (*get_audio_edid_blk) (struct platform_device *pdev,
+ struct msm_hdmi_audio_edid_blk *blk);
+};
+
+int msm_hdmi_register_audio_codec(struct platform_device *pdev,
+ struct msm_hdmi_audio_codec_ops *ops);
+
+#endif /* __MSM_HDMI_AUDIO_CODEC_H__ */
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8910.h b/arch/arm/mach-msm/include/mach/msm_iomap-8910.h
index 08f21b6..64990da 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8910.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8910.h
@@ -22,7 +22,7 @@
*
*/
-#define MSM8910_MSM_SHARED_RAM_PHYS 0x0FA00000
+#define MSM8910_MSM_SHARED_RAM_PHYS 0x0D600000
#define MSM8910_APCS_GCC_PHYS 0xF9011000
#define MSM8910_APCS_GCC_SIZE SZ_4K
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h b/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
index 17156b1..fe928b9 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
@@ -127,6 +127,7 @@
#define MSM_HDMI_SIZE SZ_4K
/* Needed to keep the unified iomap happy */
+#define MSM_APCS_GCC_BASE IOMEM(0xFA006000) /* 4K */
#define MSM_MPM2_PSHOLD_BASE MSM_TLMM_BASE
#ifdef CONFIG_DEBUG_MSM8660_UART
diff --git a/arch/arm/mach-msm/include/mach/sensors_adsp.h b/arch/arm/mach-msm/include/mach/sensors_adsp.h
new file mode 100644
index 0000000..3c65e37
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/sensors_adsp.h
@@ -0,0 +1,111 @@
+/* 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 SENSORS_ADSP_H
+#define SENSORS_ADSP_H
+
+#include <linux/types.h>
+
+/** Maximum number of segments that may be mapped from DDR to OCMEM */
+#define SNS_OCMEM_MAX_NUM_SEG_V01 16
+
+/** Maximum size of the ocmem_vectors structure */
+#define SNS_OCMEM_MAX_VECTORS_SIZE_V01 512
+
+/* Sensor OCMEM message id */
+
+#define SNS_OCMEM_CANCEL_REQ_V01 0x0000
+#define SNS_OCMEM_CANCEL_RESP_V01 0x0000
+#define SNS_OCMEM_VERSION_REQ_V01 0x0001
+#define SNS_OCMEM_VERSION_RESP_V01 0x0001
+#define SNS_OCMEM_PHYS_ADDR_REQ_V01 0x0002
+#define SNS_OCMEM_PHYS_ADDR_RESP_V01 0x0002
+#define SNS_OCMEM_HAS_CLIENT_IND_V01 0x0002
+#define SNS_OCMEM_BW_VOTE_REQ_V01 0x0003
+#define SNS_OCMEM_BW_VOTE_RESP_V01 0x0003
+#define SNS_OCMEM_BW_VOTE_IND_V01 0x0003
+
+enum {
+ SNS_OCMEM_MODULE_KERNEL = 0,
+ SNS_OCMEM_MODULE_ADSP
+};
+
+/**
+ * Defines the types of response messages
+ */
+enum {
+ SNS_OCMEM_MSG_TYPE_REQ = 0, /* Request */
+ SNS_OCMEM_MSG_TYPE_RESP, /* Response to a request */
+ SNS_OCMEM_MSG_TYPE_IND /* Asynchronous indication */
+};
+
+/**
+ * The message header. Used in both incoming and outgoing messages
+ */
+struct sns_ocmem_hdr_s {
+ int32_t msg_id ; /* Message ID, as defined in the IDL */
+ uint16_t msg_size; /* Size of message, in bytes */
+ uint8_t dst_module; /* Destination module */
+ uint8_t src_module; /* Source module */
+ uint8_t msg_type; /* The message type */
+} __packed;
+
+struct sns_ocmem_common_resp_s_v01 {
+ /* This shall be the first element of every response message */
+ uint8_t sns_result_t;
+ /**< 0 == SUCCESS; 1 == FAILURE
+ A result of FAILURE indicates that that any data contained in the
+ response should not be used other than sns_err_t, to determine the
+ type of error */
+ uint8_t sns_err_t;
+ /**< See sns_ocmem_error_e in ocmem_sensors.h */
+};
+
+/* This structure represents a single memory region that must be
+mapped from DDR to OCMEM */
+struct sns_mem_segment_s_v01 {
+
+ uint64_t start_address; /* Physical start address of segment */
+ uint32_t size; /* Size (in bytes) of this segment */
+ uint16_t type; /* 1 == Read only; 2 == Read/Write Data */
+} __packed;
+
+struct sns_ocmem_phys_addr_resp_msg_v01 {
+ struct sns_ocmem_common_resp_s_v01 resp; /* response */
+ uint32_t segments_len; /* number of elements in segments */
+ /* Segments mapped from DDR to OCMEM */
+ struct sns_mem_segment_s_v01 segments[SNS_OCMEM_MAX_NUM_SEG_V01];
+ uint8_t segments_valid; /* true if segments is being passed */
+} __packed ;
+
+struct sns_ocmem_has_client_ind_msg_v01 {
+ uint16_t num_clients; /* Number of active clients on the ADSP */
+} __packed;
+
+struct sns_ocmem_bw_vote_req_msg_v01 {
+ uint8_t is_map; /* True if mapping; false if unmapping */
+ uint8_t vectors_valid; /* True if vectors is being passed */
+ uint32_t vectors_len; /* Number of elements in vectors */
+ uint8_t vectors[SNS_OCMEM_MAX_VECTORS_SIZE_V01]; /* vectors */
+} __packed;
+
+struct sns_ocmem_bw_vote_resp_msg_v01 {
+ struct sns_ocmem_common_resp_s_v01 resp;
+};
+
+struct sns_ocmem_bw_vote_ind_msg_v01 {
+ /* If the ADSP just voted for, or took away its vote for
+ OCMEM bandwidth */
+ uint8_t is_vote_on;
+} __packed;
+
+#endif /* SENSORS_ADSP_H */
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index 0499a7a..c0624bb 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -54,12 +54,16 @@
of_machine_is_compatible("qcom,msm8226")
#define machine_is_msm8226_sim() \
of_machine_is_compatible("qcom,msm8226-sim")
+#define machine_is_msm8226_rumi() \
+ of_machine_is_compatible("qcom,msm8226-rumi")
#define early_machine_is_msm8910() \
of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8910")
#define machine_is_msm8910() \
of_machine_is_compatible("qcom,msm8910")
#define machine_is_msm8910_sim() \
of_machine_is_compatible("qcom,msm8910-sim")
+#define machine_is_msm8910_rumi() \
+ of_machine_is_compatible("qcom,msm8910-rumi")
#else
#define early_machine_is_msm8974() 0
#define machine_is_msm8974() 0
@@ -72,9 +76,11 @@
#define early_machine_is_msm8226() 0
#define machine_is_msm8226() 0
#define machine_is_msm8226_sim() 0
+#define machine_is_msm8226_rumi() 0
#define early_machine_is_msm8910() 0
#define machine_is_msm8910() 0
#define machine_is_msm8910_sim() 0
+#define machine_is_msm8910_rumi() 0
#endif
diff --git a/arch/arm/mach-msm/mdm2.c b/arch/arm/mach-msm/mdm2.c
index 77eeb53..0e3e8e0 100644
--- a/arch/arm/mach-msm/mdm2.c
+++ b/arch/arm/mach-msm/mdm2.c
@@ -118,11 +118,13 @@
}
msleep(100);
}
+
+ /* Assert the soft reset line whether mdm2ap_status went low or not */
+ gpio_direction_output(mdm_drv->ap2mdm_soft_reset_gpio,
+ soft_reset_direction);
if (i == 0) {
pr_err("%s: MDM2AP_STATUS never went low. Doing a hard reset\n",
__func__);
- gpio_direction_output(mdm_drv->ap2mdm_soft_reset_gpio,
- soft_reset_direction);
/*
* Currently, there is a debounce timer on the charm PMIC. It is
* necessary to hold the PMIC RESET low for ~3.5 seconds
diff --git a/arch/arm/mach-msm/msm_cpr.c b/arch/arm/mach-msm/msm_cpr.c
index c7a8b98..dd6ffab 100644
--- a/arch/arm/mach-msm/msm_cpr.c
+++ b/arch/arm/mach-msm/msm_cpr.c
@@ -91,7 +91,7 @@
struct regulator *vreg_cx;
const struct msm_cpr_config *config;
struct notifier_block freq_transition;
- struct msm_cpr_vp_data *vp;
+ uint32_t step_size;
};
/* Need to maintain state data for suspend and resume APIs */
@@ -219,7 +219,7 @@
*
*/
level_uV = chip_data->turbo_Vmax -
- (chip_data->tgt_volt_offset * cpr->vp->step_size);
+ (chip_data->tgt_volt_offset * cpr->step_size);
msm_cpr_debug(MSM_CPR_DEBUG_CONFIG,
"tgt_volt_uV = %d\n", level_uV);
@@ -260,7 +260,7 @@
quot1 = (cpr_read_reg(cpr, RBCPR_DEBUG1) & QUOT_SLOW_M) >> 12;
/* Take second CPR measurement at a lower voltage to get QUOT2 */
- level_uV -= 4 * cpr->vp->step_size;
+ level_uV -= 4 * cpr->step_size;
msm_cpr_debug(MSM_CPR_DEBUG_CONFIG,
"tgt_volt_uV = %d\n", level_uV);
@@ -493,7 +493,7 @@
error_step += 1;
/* Calculte new PMIC voltage */
- new_volt = curr_volt + (error_step * cpr->vp->step_size);
+ new_volt = curr_volt + (error_step * cpr->step_size);
msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
"UP_INT: new_volt: %d, error_step=%d\n",
new_volt, error_step);
@@ -531,7 +531,7 @@
error_step = 2;
/* Calculte new PMIC voltage */
- new_volt = curr_volt - (error_step * cpr->vp->step_size);
+ new_volt = curr_volt - (error_step * cpr->step_size);
msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
"DOWN_INT: new_volt: %d, error_step=%d\n",
new_volt, error_step);
@@ -953,7 +953,7 @@
cpr->base = base;
- cpr->vp = pdata->vp_data;
+ cpr->step_size = pdata->step_size;
spin_lock_init(&cpr->cpr_lock);
diff --git a/arch/arm/mach-msm/msm_cpr.h b/arch/arm/mach-msm/msm_cpr.h
index 3d10478..d9c8e9b 100644
--- a/arch/arm/mach-msm/msm_cpr.h
+++ b/arch/arm/mach-msm/msm_cpr.h
@@ -122,20 +122,6 @@
};
/**
- * struct msm_vp_data - structure for VP configuration
- * @min_volt: minimum microvolt level for VP
- * @max_volt: maximum microvolt level for VP
- * @default_volt: default microvolt for VP
- * @step_size: step size of voltage in microvolt
- */
-struct msm_cpr_vp_data {
- int min_volt;
- int max_volt;
- int default_volt;
- int step_size;
-};
-
-/**
* struct msm_cpr_osc - Data for CPR ring oscillator
* @gcnt: gate count value for the oscillator
* @quot: target value for ring oscillator
@@ -189,7 +175,7 @@
uint32_t max_freq;
uint32_t max_quot;
bool disable_cpr;
- struct msm_cpr_vp_data *vp_data;
+ uint32_t step_size;
uint32_t (*get_quot)(uint32_t max_quot, uint32_t max_freq,
uint32_t new_freq);
void (*clk_enable)(void);
diff --git a/arch/arm/mach-msm/msm_cpu_pwrctl.c b/arch/arm/mach-msm/msm_cpu_pwrctl.c
new file mode 100644
index 0000000..6e339dd
--- /dev/null
+++ b/arch/arm/mach-msm/msm_cpu_pwrctl.c
@@ -0,0 +1,93 @@
+/* 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/kernel.h>
+#include <linux/types.h>
+#include <linux/cpu.h>
+#include <linux/cpumask.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/compiler.h>
+#include <linux/notifier.h>
+#include <linux/percpu.h>
+#include <linux/workqueue.h>
+
+#define MSM_CPU_SECONDARY_CORE_OFFSET 0x10000
+
+static const phys_addr_t primary_cpu_pwrctl_phys = 0x2088004;
+static DEFINE_PER_CPU(int, pll_clamp_set);
+static void msm_cpu_pwrctl_work_cb(struct work_struct *work);
+static __cpuinitdata DECLARE_WORK(msm_cpu_pwrctl_work, msm_cpu_pwrctl_work_cb);
+static int nr_cpus_done;
+static int __cpuinit msm_cpu_pwrctl_cpu_callback(struct notifier_block *nfb,
+ unsigned long action, void *hcpu);
+static struct notifier_block __cpuinitdata msm_cpu_pwrctl_cpu_notifier = {
+ .notifier_call = msm_cpu_pwrctl_cpu_callback,
+};
+
+static void __cpuinit msm_cpu_pwrctl_work_cb(struct work_struct *work)
+{
+ unregister_hotcpu_notifier(&msm_cpu_pwrctl_cpu_notifier);
+}
+
+static int __cpuinit msm_cpu_pwrctl_cpu_callback(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ int cpu = (int) hcpu;
+ int *pll_clamp;
+ void *pwrctl_ptr;
+ unsigned int value;
+
+ switch (action & ~CPU_TASKS_FROZEN) {
+ case CPU_ONLINE:
+ pll_clamp = &per_cpu(pll_clamp_set, cpu);
+ if (likely(*pll_clamp))
+ goto done;
+
+ pwrctl_ptr = ioremap_nocache(primary_cpu_pwrctl_phys +
+ (cpu * MSM_CPU_SECONDARY_CORE_OFFSET), SZ_4K);
+ if (unlikely(!pwrctl_ptr))
+ goto done;
+
+ value = readl_relaxed(pwrctl_ptr);
+ value |= 0x100;
+ writel_relaxed(value, pwrctl_ptr);
+ *pll_clamp = 1;
+ iounmap(pwrctl_ptr);
+
+ if (++nr_cpus_done == cpumask_weight(cpu_possible_mask))
+ schedule_work(&msm_cpu_pwrctl_work);
+done:
+ break;
+ default:
+ break;
+ }
+
+ return NOTIFY_OK;
+
+}
+
+static int __init msm_cpu_pwrctl_init(void)
+{
+ int cpu = smp_processor_id();
+
+ /* We won't get cpu online notification for this CPU,
+ * so take this opportunity to process this CPU.
+ */
+ msm_cpu_pwrctl_cpu_callback(&msm_cpu_pwrctl_cpu_notifier,
+ CPU_ONLINE, (void *) cpu);
+
+ register_hotcpu_notifier(&msm_cpu_pwrctl_cpu_notifier);
+ return 0;
+}
+
+early_initcall(msm_cpu_pwrctl_init);
diff --git a/arch/arm/mach-msm/msm_dcvs.c b/arch/arm/mach-msm/msm_dcvs.c
index 3b9656e..9e0be63 100644
--- a/arch/arm/mach-msm/msm_dcvs.c
+++ b/arch/arm/mach-msm/msm_dcvs.c
@@ -49,7 +49,7 @@
struct kobj_attribute slack_time_min_us;
struct kobj_attribute slack_time_max_us;
struct kobj_attribute slack_weight_thresh_pct;
- struct kobj_attribute ss_iobusy_conv;
+ struct kobj_attribute ss_no_corr_below_freq;
struct kobj_attribute ss_win_size_min_us;
struct kobj_attribute ss_win_size_max_us;
struct kobj_attribute ss_util_pct;
@@ -151,6 +151,7 @@
static unsigned num_cpu_freqs;
static struct msm_dcvs_platform_data *dcvs_pdata;
+static DEFINE_MUTEX(param_update_mutex);
static DEFINE_MUTEX(gpu_floor_mutex);
static void force_stop_slack_timer(struct dcvs_core *core)
@@ -309,6 +310,20 @@
mutex_unlock(&gpu_floor_mutex);
}
+static void check_power_collapse_modes(struct dcvs_core *core)
+{
+ struct msm_dcvs_algo_param *params;
+
+ params = &core_list[CPU_OFFSET + num_online_cpus() - 1].algo_param;
+
+ if (core->actual_freq >= params->disable_pc_threshold)
+ core->idle_enable(core->type_core_num,
+ MSM_DCVS_DISABLE_HIGH_LATENCY_MODES);
+ else
+ core->idle_enable(core->type_core_num,
+ MSM_DCVS_ENABLE_HIGH_LATENCY_MODES);
+}
+
static int __msm_dcvs_change_freq(struct dcvs_core *core)
{
int ret = 0;
@@ -355,16 +370,11 @@
core->freq_change_us = (uint32_t)ktime_to_us(
ktime_sub(ktime_get(), time_start));
- /**
- * Disable low power modes if the actual frequency is >
- * disable_pc_threshold.
- */
- if (core->actual_freq > core->algo_param.disable_pc_threshold) {
- core->idle_enable(core->type_core_num,
- MSM_DCVS_DISABLE_HIGH_LATENCY_MODES);
- } else if (core->actual_freq <= core->algo_param.disable_pc_threshold) {
- core->idle_enable(core->type_core_num,
- MSM_DCVS_ENABLE_HIGH_LATENCY_MODES);
+ if (core->type == MSM_DCVS_CORE_TYPE_CPU &&
+ core->type_core_num == 0) {
+ mutex_lock(¶m_update_mutex);
+ check_power_collapse_modes(core);
+ mutex_unlock(¶m_update_mutex);
}
/**
@@ -556,7 +566,6 @@
int msm_dcvs_update_algo_params(void)
{
static struct msm_dcvs_algo_param curr_params;
- static DEFINE_MUTEX(param_update_mutex);
struct msm_dcvs_algo_param *new_params;
int cpu, ret = 0;
@@ -566,6 +575,7 @@
if (memcmp(&curr_params, new_params,
sizeof(struct msm_dcvs_algo_param))) {
for_each_possible_cpu(cpu) {
+ struct dcvs_core *core = &core_list[CPU_OFFSET + cpu];
ret = msm_dcvs_scm_set_algo_params(CPU_OFFSET + cpu,
new_params);
if (ret) {
@@ -574,6 +584,8 @@
mutex_unlock(¶m_update_mutex);
return ret;
}
+ if (cpu == 0)
+ check_power_collapse_modes(core);
}
memcpy(&curr_params, new_params,
sizeof(struct msm_dcvs_algo_param));
@@ -706,7 +718,7 @@
DCVS_ALGO_PARAM(slack_time_min_us)
DCVS_ALGO_PARAM(slack_time_max_us)
DCVS_ALGO_PARAM(slack_weight_thresh_pct)
-DCVS_ALGO_PARAM(ss_iobusy_conv)
+DCVS_ALGO_PARAM(ss_no_corr_below_freq)
DCVS_ALGO_PARAM(ss_win_size_min_us)
DCVS_ALGO_PARAM(ss_win_size_max_us)
DCVS_ALGO_PARAM(ss_util_pct)
@@ -892,7 +904,7 @@
DCVS_RW_ATTRIB(8, slack_weight_thresh_pct);
DCVS_RW_ATTRIB(9, slack_time_min_us);
DCVS_RW_ATTRIB(10, slack_time_max_us);
- DCVS_RW_ATTRIB(11, ss_iobusy_conv);
+ DCVS_RW_ATTRIB(11, ss_no_corr_below_freq);
DCVS_RW_ATTRIB(12, ss_win_size_min_us);
DCVS_RW_ATTRIB(13, ss_win_size_max_us);
DCVS_RW_ATTRIB(14, ss_util_pct);
diff --git a/arch/arm/mach-msm/msm_mpdecision.c b/arch/arm/mach-msm/msm_mpdecision.c
index 910804b..746bbe8 100644
--- a/arch/arm/mach-msm/msm_mpdecision.c
+++ b/arch/arm/mach-msm/msm_mpdecision.c
@@ -41,12 +41,14 @@
#include <trace/events/mpdcvs_trace.h>
#define DEFAULT_RQ_AVG_POLL_MS (1)
+#define DEFAULT_RQ_AVG_DIVIDE (25)
struct mpd_attrib {
struct kobj_attribute enabled;
struct kobj_attribute rq_avg_poll_ms;
- struct kobj_attribute iowait_threshold_pct;
+ struct kobj_attribute iowait_threshold_pct;
+ struct kobj_attribute rq_avg_divide;
struct kobj_attribute em_win_size_min_us;
struct kobj_attribute em_win_size_max_us;
struct kobj_attribute em_max_util_pct;
@@ -75,6 +77,7 @@
atomic_t algo_cpu_mask;
uint32_t rq_avg_poll_ms;
uint32_t iowait_threshold_pct;
+ uint32_t rq_avg_divide;
ktime_t next_update;
uint32_t slack_us;
struct msm_mpd_algo_param mp_param;
@@ -125,20 +128,19 @@
static int num_present_hundreds;
static ktime_t last_down_time;
-#define RQ_AVG_INSIGNIFICANT_BITS 3
static bool ok_to_update_tz(int nr, int last_nr)
{
/*
* Exclude unnecessary TZ reports if run queue haven't changed much from
- * the last reported value. The left shift by INSIGNIFICANT_BITS is to
+ * the last reported value. The divison by rq_avg_divide is to
* filter out small changes in the run queue average which won't cause
* a online cpu mask change. Also if the cpu online count does not match
* the count requested by TZ and we are not in the process of bringing
* cpus online as indicated by a HPUPDATE_IN_PROGRESS in msm_mpd.hpdata
*/
return
- (((nr >> RQ_AVG_INSIGNIFICANT_BITS)
- != (last_nr >> RQ_AVG_INSIGNIFICANT_BITS))
+ (((nr / msm_mpd.rq_avg_divide)
+ != (last_nr / msm_mpd.rq_avg_divide))
|| ((hweight32(atomic_read(&msm_mpd.algo_cpu_mask))
!= num_online_cpus())
&& (msm_mpd.hpupdate != HPUPDATE_IN_PROGRESS)));
@@ -509,6 +511,20 @@
return 0;
}
+static int msm_mpd_set_rq_avg_divide(uint32_t val)
+{
+ /*
+ * No need to do anything. New value will be used next time
+ * the decision is made as to whether to update tz.
+ */
+
+ if (val == 0)
+ return -EINVAL;
+
+ msm_mpd.rq_avg_divide = val;
+ return 0;
+}
+
#define MPD_ALGO_PARAM(_name, _param) \
static ssize_t msm_mpd_attr_##_name##_show(struct kobject *kobj, \
struct kobj_attribute *attr, char *buf) \
@@ -580,6 +596,7 @@
MPD_PARAM(enabled, msm_mpd.enabled);
MPD_PARAM(rq_avg_poll_ms, msm_mpd.rq_avg_poll_ms);
MPD_PARAM(iowait_threshold_pct, msm_mpd.iowait_threshold_pct);
+MPD_PARAM(rq_avg_divide, msm_mpd.rq_avg_divide);
MPD_ALGO_PARAM(em_win_size_min_us, msm_mpd.mp_param.em_win_size_min_us);
MPD_ALGO_PARAM(em_win_size_max_us, msm_mpd.mp_param.em_win_size_max_us);
MPD_ALGO_PARAM(em_max_util_pct, msm_mpd.mp_param.em_max_util_pct);
@@ -602,7 +619,7 @@
{
struct kobject *module_kobj = NULL;
int ret = 0;
- const int attr_count = 19;
+ const int attr_count = 20;
struct msm_mpd_algo_param *param = NULL;
param = pdev->dev.platform_data;
@@ -624,28 +641,30 @@
MPD_RW_ATTRIB(0, enabled);
MPD_RW_ATTRIB(1, rq_avg_poll_ms);
MPD_RW_ATTRIB(2, iowait_threshold_pct);
- MPD_RW_ATTRIB(3, em_win_size_min_us);
- MPD_RW_ATTRIB(4, em_win_size_max_us);
- MPD_RW_ATTRIB(5, em_max_util_pct);
- MPD_RW_ATTRIB(6, mp_em_rounding_point_min);
- MPD_RW_ATTRIB(7, mp_em_rounding_point_max);
- MPD_RW_ATTRIB(8, online_util_pct_min);
- MPD_RW_ATTRIB(9, online_util_pct_max);
- MPD_RW_ATTRIB(10, slack_time_min_us);
- MPD_RW_ATTRIB(11, slack_time_max_us);
- MPD_RW_ATTRIB(12, hp_up_max_ms);
- MPD_RW_ATTRIB(13, hp_up_ms);
- MPD_RW_ATTRIB(14, hp_up_count);
- MPD_RW_ATTRIB(15, hp_dw_max_ms);
- MPD_RW_ATTRIB(16, hp_dw_ms);
- MPD_RW_ATTRIB(17, hp_dw_count);
+ MPD_RW_ATTRIB(3, rq_avg_divide);
+ MPD_RW_ATTRIB(4, em_win_size_min_us);
+ MPD_RW_ATTRIB(5, em_win_size_max_us);
+ MPD_RW_ATTRIB(6, em_max_util_pct);
+ MPD_RW_ATTRIB(7, mp_em_rounding_point_min);
+ MPD_RW_ATTRIB(8, mp_em_rounding_point_max);
+ MPD_RW_ATTRIB(9, online_util_pct_min);
+ MPD_RW_ATTRIB(10, online_util_pct_max);
+ MPD_RW_ATTRIB(11, slack_time_min_us);
+ MPD_RW_ATTRIB(12, slack_time_max_us);
+ MPD_RW_ATTRIB(13, hp_up_max_ms);
+ MPD_RW_ATTRIB(14, hp_up_ms);
+ MPD_RW_ATTRIB(15, hp_up_count);
+ MPD_RW_ATTRIB(16, hp_dw_max_ms);
+ MPD_RW_ATTRIB(17, hp_dw_ms);
+ MPD_RW_ATTRIB(18, hp_dw_count);
- msm_mpd.attrib.attrib_group.attrs[18] = NULL;
+ msm_mpd.attrib.attrib_group.attrs[19] = NULL;
ret = sysfs_create_group(module_kobj, &msm_mpd.attrib.attrib_group);
if (ret)
pr_err("Unable to create sysfs objects :%d\n", ret);
msm_mpd.rq_avg_poll_ms = DEFAULT_RQ_AVG_POLL_MS;
+ msm_mpd.rq_avg_divide = DEFAULT_RQ_AVG_DIVIDE;
memcpy(&msm_mpd.mp_param, param, sizeof(struct msm_mpd_algo_param));
diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
index 94632da..5e03aa8 100644
--- a/arch/arm/mach-msm/pil-q6v5-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v5-lpass.c
@@ -195,15 +195,10 @@
void *ss_handle)
{
int ret;
- switch (code) {
- case SUBSYS_BEFORE_SHUTDOWN:
- pr_debug("%s: M-Notify: Shutdown started\n", __func__);
- ret = sysmon_send_event(SYSMON_SS_LPASS, "modem",
- SUBSYS_BEFORE_SHUTDOWN);
- if (ret < 0)
- pr_err("%s: sysmon_send_event error %d", __func__, ret);
- break;
- }
+ pr_debug("%s: M-Notify: event %lu\n", __func__, code);
+ ret = sysmon_send_event(SYSMON_SS_LPASS, "modem", code);
+ if (ret < 0)
+ pr_err("%s: sysmon_send_event error %d", __func__, ret);
return NOTIFY_DONE;
}
@@ -295,15 +290,8 @@
{
struct lpass_data *drv = subsys_to_lpass(subsys);
int ret = 0;
-
- if (get_restart_level() == RESET_SUBSYS_INDEPENDENT) {
- pr_debug("%s: Wait for ADSP power up!", __func__);
- msleep(10000);
- }
-
ret = pil_boot(&drv->q6->desc);
enable_irq(drv->wdog_irq);
-
return ret;
}
diff --git a/arch/arm/mach-msm/pil-venus.c b/arch/arm/mach-msm/pil-venus.c
index 103fd9f..eb222e3 100644
--- a/arch/arm/mach-msm/pil-venus.c
+++ b/arch/arm/mach-msm/pil-venus.c
@@ -33,6 +33,7 @@
#include "peripheral-loader.h"
#include "scm-pas.h"
+#include "ramdump.h"
/* VENUS WRAPPER registers */
#define VENUS_WRAPPER_CLOCK_CONFIG 0x4
@@ -76,6 +77,7 @@
struct iommu_domain *iommu_fw_domain;
int venus_domain_num;
bool is_booted;
+ void *ramdump_dev;
u32 fw_sz;
u32 fw_min_paddr;
u32 fw_max_paddr;
@@ -459,6 +461,29 @@
pil_shutdown(&drv->desc);
}
+static int venus_shutdown(const struct subsys_desc *desc)
+{
+ struct venus_data *drv = subsys_to_drv(desc);
+ pil_shutdown(&drv->desc);
+ return 0;
+}
+
+static int venus_powerup(const struct subsys_desc *desc)
+{
+ struct venus_data *drv = subsys_to_drv(desc);
+ return pil_boot(&drv->desc);
+}
+
+static int venus_ramdump(int enable, const struct subsys_desc *desc)
+{
+ struct venus_data *drv = subsys_to_drv(desc);
+
+ if (!enable)
+ return 0;
+
+ return pil_do_ramdump(&drv->desc, drv->ramdump_dev);
+}
+
static int __devinit pil_venus_probe(struct platform_device *pdev)
{
struct venus_data *drv;
@@ -524,23 +549,34 @@
dev_info(&pdev->dev, "using non-secure boot\n");
}
+ drv->ramdump_dev = create_ramdump_device("venus", &pdev->dev);
+ if (!drv->ramdump_dev)
+ return -ENOMEM;
+
rc = pil_desc_init(desc);
if (rc)
- return rc;
+ goto err_ramdump;
drv->subsys_desc.name = desc->name;
drv->subsys_desc.owner = THIS_MODULE;
drv->subsys_desc.dev = &pdev->dev;
drv->subsys_desc.start = venus_start;
drv->subsys_desc.stop = venus_stop;
+ drv->subsys_desc.shutdown = venus_shutdown;
+ drv->subsys_desc.powerup = venus_powerup;
+ drv->subsys_desc.ramdump = venus_ramdump;
drv->subsys = subsys_register(&drv->subsys_desc);
if (IS_ERR(drv->subsys)) {
- pil_desc_release(desc);
- return PTR_ERR(drv->subsys);
+ rc = PTR_ERR(drv->subsys);
+ goto err_subsys;
}
-
- return 0;
+ return rc;
+err_subsys:
+ pil_desc_release(desc);
+err_ramdump:
+ destroy_ramdump_device(drv->ramdump_dev);
+ return rc;
}
static int __devexit pil_venus_remove(struct platform_device *pdev)
diff --git a/arch/arm/mach-msm/platsmp-8625.c b/arch/arm/mach-msm/platsmp-8625.c
index 0e75cae..bbb5a51 100644
--- a/arch/arm/mach-msm/platsmp-8625.c
+++ b/arch/arm/mach-msm/platsmp-8625.c
@@ -20,23 +20,16 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
-#include <asm/cacheflush.h>
#include <asm/hardware/gic.h>
-#include <asm/hardware/cache-l2x0.h>
#include <asm/smp_scu.h>
#include <asm/unified.h>
#include <mach/msm_iomap.h>
#include "pm.h"
+#include "platsmp.h"
#define CORE_RESET_BASE 0xA8600590
#define MSM_CORE_STATUS_MSK 0x02800000
-/*
- * control for which core is the next to come out of the secondary
- * boot "holding pen"
- */
-volatile int pen_release = -1;
-
static DEFINE_PER_CPU(bool, cold_boot_done);
struct per_cpu_data {
@@ -48,22 +41,8 @@
static uint32_t *msm8625_boot_vector;
-
static struct per_cpu_data cpu_data[CONFIG_NR_CPUS];
-/*
- * Write pen_release in a way that is guaranteed to be visible to all
- * observers, irrespective of whether they're taking part in coherency
- * or not. This is necessary for the hotplug code to work reliably.
- */
-static void __cpuinit write_pen_release(int val)
-{
- pen_release = val;
- smp_wmb();
- __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
- outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
-}
-
static void __iomem *scu_base_addr(void)
{
return MSM_SCU_BASE;
@@ -101,10 +80,8 @@
local_irq_enable();
}
-void __cpuinit platform_secondary_init(unsigned int cpu)
+void __cpuinit msm8625_platform_secondary_init(unsigned int cpu)
{
- pr_debug("CPU%u: Booted secondary processor\n", cpu);
-
WARN_ON(msm_platform_secondary_init(cpu));
/*
@@ -134,7 +111,7 @@
spin_unlock(&boot_lock);
}
-static int __cpuinit msm8625_release_secondary(unsigned int cpu)
+static int __cpuinit msm8625_release_secondary(unsigned int cpu)
{
void __iomem *base_ptr;
int value = 0;
@@ -178,7 +155,7 @@
return cpu_data[cpu].reset_core_base;
}
-int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
+int __cpuinit msm8625_boot_secondary(unsigned int cpu, struct task_struct *idle)
{
unsigned long timeout;
@@ -245,7 +222,7 @@
* Initialise the CPU possible map early - this describes the CPUs
* which may be present or become present in the system.
*/
-void __init smp_init_cpus(void)
+void __init msm8625_smp_init_cpus(void)
{
void __iomem *scu_base = scu_base_addr();
@@ -298,18 +275,11 @@
msm8625_boot_vector[1] = entry;
}
-void __init platform_smp_prepare_cpus(unsigned int max_cpus)
+void __init msm8625_platform_smp_prepare_cpus(unsigned int max_cpus)
{
- int i, cpu, value;
+ int cpu, value;
void __iomem *cpu_ptr;
- /*
- * Initialise the present map, which describes the set of CPUs
- * actually populated at the present time.
- */
- for (i = 0; i < max_cpus; i++)
- set_cpu_present(i, true);
-
scu_enable(scu_base_addr());
cpu_ptr = ioremap_nocache(MSM8625_CPU_PHYS, SZ_8);
@@ -350,3 +320,13 @@
}
}
+
+struct smp_operations msm8625_smp_ops __initdata = {
+ .smp_init_cpus = msm8625_smp_init_cpus,
+ .smp_prepare_cpus = msm8625_platform_smp_prepare_cpus,
+ .smp_secondary_init = msm8625_platform_secondary_init,
+ .smp_boot_secondary = msm8625_boot_secondary,
+ .cpu_kill = platform_cpu_kill,
+ .cpu_die = platform_cpu_die,
+ .cpu_disable = platform_cpu_disable
+};
diff --git a/arch/arm/mach-msm/platsmp-8910.c b/arch/arm/mach-msm/platsmp-8910.c
deleted file mode 100644
index af2f496..0000000
--- a/arch/arm/mach-msm/platsmp-8910.c
+++ /dev/null
@@ -1,190 +0,0 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/jiffies.h>
-#include <linux/smp.h>
-#include <linux/io.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-
-#include <asm/cacheflush.h>
-#include <asm/smp_plat.h>
-#include <asm/hardware/gic.h>
-#include <mach/msm_iomap.h>
-#include "pm.h"
-
-#define BOOT_REMAP_ENABLE 0x01
-
-/*
- * control for which core is the next to come out of the secondary
- * boot "holding pen"
- */
-volatile int pen_release = -1;
-
-/*
- * Write pen_release in a way that is guaranteed to be visible to all
- * observers, irrespective of whether they're taking part in coherency
- * or not. This is necessary for the hotplug code to work reliably.
- */
-static void __cpuinit write_pen_release(int val)
-{
- pen_release = val;
- smp_wmb();
- __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
- outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
-}
-
-static DEFINE_SPINLOCK(boot_lock);
-
-void __cpuinit platform_secondary_init(unsigned int cpu)
-{
- WARN_ON(msm_platform_secondary_init(cpu));
-
- /*
- * if any interrupts are already enabled for the primary
- * core (e.g. timer irq), then they will not have been enabled
- * for us: do so
- */
- gic_secondary_init(0);
-
- /*
- * let the primary processor know we're out of the
- * pen, then head off into the C entry point
- */
- write_pen_release(-1);
-
- /*
- * Synchronise with the boot thread.
- */
- spin_lock(&boot_lock);
- spin_unlock(&boot_lock);
-}
-
-static int __cpuinit release_secondary_sim(unsigned long base, int cpu)
-{
- void *base_ptr;
-
- base_ptr = ioremap_nocache(base + (cpu * 0x10000), SZ_4K);
- if (!base_ptr) {
- pr_err("Failed to release core %u\n", cpu);
- return -ENODEV;
- }
-
- writel_relaxed(0x800, base_ptr+0x04);
- writel_relaxed(0x3FFF, base_ptr+0x14);
- mb();
-
- return 0;
-}
-
-DEFINE_PER_CPU(int, cold_boot_done);
-
-int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
-{
- unsigned long timeout;
-
- preset_lpj = loops_per_jiffy;
-
- if (per_cpu(cold_boot_done, cpu) == false) {
- release_secondary_sim(0xF9088000, cpu);
- per_cpu(cold_boot_done, cpu) = true;
- }
-
- /*
- * Set synchronisation state between this boot processor
- * and the secondary one
- */
- spin_lock(&boot_lock);
-
- /*
- * The secondary processor is waiting to be released from
- * the holding pen - release it, then wait for it to flag
- * that it has been released by resetting pen_release.
- *
- * Note that "pen_release" is the hardware CPU ID, whereas
- * "cpu" is Linux's internal ID.
- */
- write_pen_release(cpu_logical_map(cpu));
-
- /*
- * Send the secondary CPU a soft interrupt, thereby causing
- * the boot monitor to read the system wide flags register,
- * and branch to the address found there.
- */
-
- gic_raise_softirq(cpumask_of(cpu), 1);
-
- timeout = jiffies + (1 * HZ);
- while (time_before(jiffies, timeout)) {
- smp_rmb();
- if (pen_release == -1)
- break;
-
- udelay(10);
- }
-
- /*
- * now the secondary core is starting up let it run its
- * calibrations, then wait for it to finish
- */
- spin_unlock(&boot_lock);
-
- return 0;
-}
-
-/*
- * Initialise the CPU possible map early - this describes the CPUs
- * which may be present or become present in the system
- */
-void __init smp_init_cpus(void)
-{
- unsigned int i, ncores;
-
- ncores = (__raw_readl(MSM_APCS_GCC_BASE + 0x30)) & 0xF;
-
- for (i = 0; i < ncores; i++)
- set_cpu_possible(i, true);
-
- set_smp_cross_call(gic_raise_softirq);
-}
-
-void __init platform_smp_prepare_cpus(unsigned int max_cpus)
-{
- int i;
- void __iomem *remap_ptr;
-
- /*
- * Initialise the present map, which describes the set of CPUs
- * actually populated at the present time
- */
- for (i = 0; i < max_cpus; i++)
- set_cpu_present(i, true);
-
- /*
- * Enable boot remapping and write the address of secondary
- * startup into boot remapper register
- */
- remap_ptr = ioremap_nocache(0xF9010000, SZ_4K); /* APCS_CFG_SECURE */
- if (!remap_ptr) {
- pr_err("Failed to ioremap for secondary cores\n");
- return;
- }
-
- __raw_writel((virt_to_phys(msm_secondary_startup)|BOOT_REMAP_ENABLE),
- (remap_ptr + 0x4));
- mb();
- iounmap(remap_ptr);
-}
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index b1d2464..80f6014 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -8,6 +8,7 @@
* published by the Free Software Foundation.
*/
+#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/cpumask.h>
@@ -27,14 +28,14 @@
#include <mach/msm_iomap.h>
#include "pm.h"
+#include "platsmp.h"
#include "scm-boot.h"
#include "spm.h"
#define VDD_SC1_ARRAY_CLAMP_GFS_CTL 0x15A0
#define SCSS_CPU1CORE_RESET 0xD80
#define SCSS_DBG_STATUS_CORE_PWRDUP 0xE64
-
-extern void msm_secondary_startup(void);
+#define BOOT_REMAP_ENABLE 0x01
/*
* control for which core is the next to come out of the secondary
@@ -47,7 +48,7 @@
* observers, irrespective of whether they're taking part in coherency
* or not. This is necessary for the hotplug code to work reliably.
*/
-static void __cpuinit write_pen_release(int val)
+void __cpuinit write_pen_release(int val)
{
pen_release = val;
smp_wmb();
@@ -81,6 +82,20 @@
spin_unlock(&boot_lock);
}
+static int __cpuinit release_secondary_sim(unsigned long base, int cpu)
+{
+ void *base_ptr = ioremap_nocache(base + (cpu * 0x10000), SZ_4K);
+ if (!base_ptr)
+ return -ENODEV;
+
+ writel_relaxed(0x800, base_ptr+0x04);
+ writel_relaxed(0x3FFF, base_ptr+0x14);
+
+ mb();
+ iounmap(base_ptr);
+ return 0;
+}
+
static int __cpuinit scorpion_release_secondary(void)
{
void *base_ptr = ioremap_nocache(0x00902000, SZ_4K*2);
@@ -97,23 +112,7 @@
return 0;
}
-static int __cpuinit krait_release_secondary_sim(unsigned long base, int cpu)
-{
- void *base_ptr = ioremap_nocache(base + (cpu * 0x10000), SZ_4K);
- if (!base_ptr)
- return -ENODEV;
-
- if (machine_is_msm8974_sim() || machine_is_mpq8092_sim()) {
- writel_relaxed(0x800, base_ptr+0x04);
- writel_relaxed(0x3FFF, base_ptr+0x14);
- }
-
- mb();
- iounmap(base_ptr);
- return 0;
-}
-
-static int __cpuinit krait_release_secondary(unsigned long base, int cpu)
+static int __cpuinit msm8960_release_secondary(unsigned long base, int cpu)
{
void *base_ptr = ioremap_nocache(base + (cpu * 0x10000), SZ_4K);
if (!base_ptr)
@@ -121,32 +120,30 @@
msm_spm_turn_on_cpu_rail(cpu);
- if (cpu_is_krait_v1() || cpu_is_krait_v2()) {
- writel_relaxed(0x109, base_ptr+0x04);
- writel_relaxed(0x101, base_ptr+0x04);
- mb();
- ndelay(300);
- writel_relaxed(0x121, base_ptr+0x04);
- } else
- writel_relaxed(0x021, base_ptr+0x04);
+ writel_relaxed(0x109, base_ptr+0x04);
+ writel_relaxed(0x101, base_ptr+0x04);
+ mb();
+ ndelay(300);
+
+ writel_relaxed(0x121, base_ptr+0x04);
mb();
udelay(2);
- writel_relaxed(0x020, base_ptr+0x04);
+ writel_relaxed(0x120, base_ptr+0x04);
mb();
udelay(2);
- writel_relaxed(0x000, base_ptr+0x04);
+ writel_relaxed(0x100, base_ptr+0x04);
mb();
udelay(100);
- writel_relaxed(0x080, base_ptr+0x04);
+ writel_relaxed(0x180, base_ptr+0x04);
mb();
iounmap(base_ptr);
return 0;
}
-static int __cpuinit krait_release_secondary_p3(unsigned long base, int cpu)
+static int __cpuinit msm8974_release_secondary(unsigned long base, int cpu)
{
void *base_ptr = ioremap_nocache(base + (cpu * 0x10000), SZ_4K);
if (!base_ptr)
@@ -171,46 +168,13 @@
return 0;
}
-static int __cpuinit release_secondary(unsigned int cpu)
-{
- BUG_ON(cpu >= get_core_count());
-
- if (machine_is_msm8974_rumi())
- return 0;
-
- if (cpu_is_msm8x60())
- return scorpion_release_secondary();
-
- if (machine_is_msm8974_sim() || machine_is_mpq8092_sim())
- return krait_release_secondary_sim(0xf9088000, cpu);
-
- if (soc_class_is_msm8960() || soc_class_is_msm8930() ||
- soc_class_is_apq8064())
- return krait_release_secondary(0x02088000, cpu);
-
- if (cpu_is_msm8974())
- return krait_release_secondary_p3(0xf9088000, cpu);
-
- WARN(1, "unknown CPU case in release_secondary\n");
- return -EINVAL;
-}
-
-DEFINE_PER_CPU(int, cold_boot_done);
-
-int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
+static int __cpuinit release_from_pen(unsigned int cpu)
{
unsigned long timeout;
- pr_debug("Starting secondary CPU %d\n", cpu);
-
/* Set preset_lpj to avoid subsequent lpj recalculations */
preset_lpj = loops_per_jiffy;
- if (per_cpu(cold_boot_done, cpu) == false) {
- release_secondary(cpu);
- per_cpu(cold_boot_done, cpu) = true;
- }
-
/*
* set synchronisation state between this boot processor
* and the secondary one
@@ -251,11 +215,67 @@
return pen_release != -1 ? -ENOSYS : 0;
}
+
+DEFINE_PER_CPU(int, cold_boot_done);
+
+int __cpuinit scorpion_boot_secondary(unsigned int cpu,
+ struct task_struct *idle)
+{
+ pr_debug("Starting secondary CPU %d\n", cpu);
+
+ if (per_cpu(cold_boot_done, cpu) == false) {
+ scorpion_release_secondary();
+ per_cpu(cold_boot_done, cpu) = true;
+ }
+ return release_from_pen(cpu);
+}
+
+int __cpuinit msm8960_boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+ pr_debug("Starting secondary CPU %d\n", cpu);
+
+ if (per_cpu(cold_boot_done, cpu) == false) {
+ msm8960_release_secondary(0x02088000, cpu);
+ per_cpu(cold_boot_done, cpu) = true;
+ }
+ return release_from_pen(cpu);
+}
+
+int __cpuinit msm8974_boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+ pr_debug("Starting secondary CPU %d\n", cpu);
+
+ if (per_cpu(cold_boot_done, cpu) == false) {
+ if (machine_is_msm8974_sim() || machine_is_mpq8092_sim())
+ release_secondary_sim(0xf9088000, cpu);
+ else if (machine_is_msm8974_rumi())
+ return 0;
+ else
+ msm8974_release_secondary(0xf9088000, cpu);
+
+ per_cpu(cold_boot_done, cpu) = true;
+ }
+ return release_from_pen(cpu);
+}
+
+int __cpuinit arm_boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+ pr_debug("Starting secondary CPU %d\n", cpu);
+
+ if (per_cpu(cold_boot_done, cpu) == false) {
+ if (machine_is_msm8226_sim() || machine_is_msm8910_sim())
+ release_secondary_sim(0xf9088000, cpu);
+
+ per_cpu(cold_boot_done, cpu) = true;
+ }
+ return release_from_pen(cpu);
+}
+
/*
* Initialise the CPU possible map early - this describes the CPUs
* which may be present or become present in the system.
*/
-void __init smp_init_cpus(void)
+static void __init msm_smp_init_cpus(void)
{
unsigned int i, ncores = get_core_count();
@@ -271,6 +291,24 @@
set_smp_cross_call(gic_raise_softirq);
}
+static void __init arm_smp_init_cpus(void)
+{
+ unsigned int i, ncores;
+
+ ncores = (__raw_readl(MSM_APCS_GCC_BASE + 0x30)) & 0xF;
+
+ if (ncores > nr_cpu_ids) {
+ pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
+ ncores, nr_cpu_ids);
+ ncores = nr_cpu_ids;
+ }
+
+ for (i = 0; i < ncores; i++)
+ set_cpu_possible(i, true);
+
+ set_smp_cross_call(gic_raise_softirq);
+}
+
static int cold_boot_flags[] __initdata = {
0,
SCM_FLAG_COLDBOOT_CPU1,
@@ -278,7 +316,7 @@
SCM_FLAG_COLDBOOT_CPU3,
};
-void __init platform_smp_prepare_cpus(unsigned int max_cpus)
+static void __init msm_platform_smp_prepare_cpus(unsigned int max_cpus)
{
int cpu, map;
unsigned int flags = 0;
@@ -296,3 +334,61 @@
if (scm_set_boot_addr(virt_to_phys(msm_secondary_startup), flags))
pr_warn("Failed to set CPU boot address\n");
}
+
+static void __init arm_platform_smp_prepare_cpus(unsigned int max_cpus)
+{
+ void *remap_ptr = ioremap_nocache(0xF9010000, SZ_4K);
+ if (!remap_ptr) {
+ pr_err("Failed to ioremap for secondary cores\n");
+ return;
+ }
+
+ /*
+ * Write the address of secondary startup into boot remapper
+ * register and enable boot remapping.
+ */
+ __raw_writel((virt_to_phys(msm_secondary_startup)|BOOT_REMAP_ENABLE),
+ (remap_ptr + 0x4));
+ mb();
+ iounmap(remap_ptr);
+}
+
+struct smp_operations arm_smp_ops __initdata = {
+ .smp_init_cpus = arm_smp_init_cpus,
+ .smp_prepare_cpus = arm_platform_smp_prepare_cpus,
+ .smp_secondary_init = platform_secondary_init,
+ .smp_boot_secondary = arm_boot_secondary,
+ .cpu_kill = platform_cpu_kill,
+ .cpu_die = platform_cpu_die,
+ .cpu_disable = platform_cpu_disable
+};
+
+struct smp_operations msm8974_smp_ops __initdata = {
+ .smp_init_cpus = msm_smp_init_cpus,
+ .smp_prepare_cpus = msm_platform_smp_prepare_cpus,
+ .smp_secondary_init = platform_secondary_init,
+ .smp_boot_secondary = msm8974_boot_secondary,
+ .cpu_kill = platform_cpu_kill,
+ .cpu_die = platform_cpu_die,
+ .cpu_disable = platform_cpu_disable
+};
+
+struct smp_operations msm8960_smp_ops __initdata = {
+ .smp_init_cpus = msm_smp_init_cpus,
+ .smp_prepare_cpus = msm_platform_smp_prepare_cpus,
+ .smp_secondary_init = platform_secondary_init,
+ .smp_boot_secondary = msm8960_boot_secondary,
+ .cpu_kill = platform_cpu_kill,
+ .cpu_die = platform_cpu_die,
+ .cpu_disable = platform_cpu_disable
+};
+
+struct smp_operations scorpion_smp_ops __initdata = {
+ .smp_init_cpus = msm_smp_init_cpus,
+ .smp_prepare_cpus = msm_platform_smp_prepare_cpus,
+ .smp_secondary_init = platform_secondary_init,
+ .smp_boot_secondary = scorpion_boot_secondary,
+ .cpu_kill = platform_cpu_kill,
+ .cpu_die = platform_cpu_die,
+ .cpu_disable = platform_cpu_disable
+};
diff --git a/arch/arm/mach-msm/platsmp.h b/arch/arm/mach-msm/platsmp.h
new file mode 100644
index 0000000..1d176d2
--- /dev/null
+++ b/arch/arm/mach-msm/platsmp.h
@@ -0,0 +1,31 @@
+/* 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.
+ */
+
+/*
+ * control for which core is the next to come out of the secondary
+ * boot "holding pen".
+ */
+extern volatile int pen_release;
+
+void __cpuinit msm_secondary_startup(void);
+void __cpuinit write_pen_release(int val);
+
+/* HOTPLUG Interface */
+int platform_cpu_kill(unsigned int cpu);
+void platform_cpu_die(unsigned int cpu);
+int platform_cpu_disable(unsigned int cpu);
+
+extern struct smp_operations arm_smp_ops __initdata;
+extern struct smp_operations msm8960_smp_ops __initdata;
+extern struct smp_operations msm8974_smp_ops __initdata;
+extern struct smp_operations msm8625_smp_ops __initdata;
+extern struct smp_operations scorpion_smp_ops __initdata;
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 550bb56..b42ad94 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -558,15 +558,18 @@
static bool msm_pm_power_collapse_standalone(bool from_idle)
{
unsigned int cpu = smp_processor_id();
- unsigned int avsdscr_setting;
- unsigned int avscsr_enable;
+ unsigned int avsdscr;
+ unsigned int avscsr;
bool collapsed;
- avsdscr_setting = avs_get_avsdscr();
- avscsr_enable = avs_disable();
+ avsdscr = avs_get_avsdscr();
+ avscsr = avs_get_avscsr();
+ avs_set_avscsr(0); /* Disable AVS */
+
collapsed = msm_pm_spm_power_collapse(cpu, from_idle, false);
- avs_enable(avscsr_enable);
- avs_reset_delays(avsdscr_setting);
+
+ avs_set_avsdscr(avsdscr);
+ avs_set_avscsr(avscsr);
return collapsed;
}
@@ -574,8 +577,8 @@
{
unsigned int cpu = smp_processor_id();
unsigned long saved_acpuclk_rate;
- unsigned int avsdscr_setting;
- unsigned int avscsr_enable;
+ unsigned int avsdscr;
+ unsigned int avscsr;
bool collapsed;
if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
@@ -586,8 +589,9 @@
if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
pr_info("CPU%u: %s: pre power down\n", cpu, __func__);
- avsdscr_setting = avs_get_avsdscr();
- avscsr_enable = avs_disable();
+ avsdscr = avs_get_avsdscr();
+ avscsr = avs_get_avscsr();
+ avs_set_avscsr(0); /* Disable AVS */
if (cpu_online(cpu))
saved_acpuclk_rate = acpuclk_power_collapse();
@@ -629,8 +633,8 @@
}
- avs_enable(avscsr_enable);
- avs_reset_delays(avsdscr_setting);
+ avs_set_avsdscr(avsdscr);
+ avs_set_avscsr(avscsr);
msm_pm_config_hw_after_power_up();
if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
pr_info("CPU%u: %s: post power up\n", cpu, __func__);
diff --git a/arch/arm/mach-msm/sensors_adsp.c b/arch/arm/mach-msm/sensors_adsp.c
new file mode 100644
index 0000000..0683bc5
--- /dev/null
+++ b/arch/arm/mach-msm/sensors_adsp.c
@@ -0,0 +1,1249 @@
+/* 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/workqueue.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/notifier.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/cdev.h>
+#include <linux/fs.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/ctype.h>
+#include <linux/of_device.h>
+#include <linux/msm_dsps.h>
+#include <linux/uaccess.h>
+#include <asm/mach-types.h>
+#include <asm/arch_timer.h>
+#include <mach/subsystem_restart.h>
+#include <mach/ocmem.h>
+#include <mach/msm_smd.h>
+#include <mach/sensors_adsp.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+
+#define DRV_NAME "sensors"
+#define DRV_VERSION "1.00"
+
+#define SNS_OCMEM_SMD_CHANNEL "SENSOR"
+#define SNS_OCMEM_CLIENT_ID OCMEM_SENSORS
+#define SNS_OCMEM_SIZE SZ_256K
+#define SMD_BUF_SIZE 2048
+#define SNS_TIMEOUT_MS 1000
+
+#define SNS_OCMEM_ALLOC_GROW 0x00000001
+#define SNS_OCMEM_ALLOC_SHRINK 0x00000002
+#define SNS_OCMEM_MAP_DONE 0x00000004
+#define SNS_OCMEM_MAP_FAIL 0x00000008
+#define SNS_OCMEM_UNMAP_DONE 0x00000010
+#define SNS_OCMEM_UNMAP_FAIL 0x00000020
+
+#define DSPS_HAS_CLIENT 0x00000100
+#define DSPS_HAS_NO_CLIENT 0x00000200
+#define DSPS_BW_VOTE_ON 0x00000400
+#define DSPS_BW_VOTE_OFF 0x00000800
+#define DSPS_PHYS_ADDR_SET 0x00001000
+
+/**
+ * Structure contains all state used by the sensors driver
+ */
+struct sns_adsp_control_s {
+ wait_queue_head_t sns_wait;
+ spinlock_t sns_lock;
+ struct workqueue_struct *sns_workqueue;
+ struct work_struct sns_work;
+ smd_channel_t *smd_ch;
+ uint32_t sns_ocmem_status;
+ uint32_t mem_segments_size;
+ struct sns_mem_segment_s_v01 mem_segments[SNS_OCMEM_MAX_NUM_SEG_V01];
+ struct ocmem_buf *buf;
+ struct ocmem_map_list map_list;
+ struct ocmem_notifier *ocmem_handle;
+ bool ocmem_enabled;
+ struct notifier_block ocmem_nb;
+ uint32_t sns_ocmem_bus_client;
+ struct platform_device *pdev;
+ void *pil;
+ struct class *dev_class;
+ dev_t dev_num;
+ struct device *dev;
+ struct cdev *cdev;
+};
+
+static struct sns_adsp_control_s sns_ctl;
+
+/* All asynchronous responses from the OCMEM driver are received
+by this function */
+int sns_ocmem_drv_cb(struct notifier_block *self,
+ unsigned long action,
+ void *dev)
+{
+ unsigned long flags;
+ pr_debug("%s\n", __func__);
+
+ spin_lock_irqsave(&sns_ctl.sns_lock, flags);
+
+ pr_debug("%s: Received OCMEM callback: action=%li\n",
+ __func__, action);
+
+ switch (action) {
+ case OCMEM_MAP_DONE:
+ sns_ctl.sns_ocmem_status |= SNS_OCMEM_MAP_DONE;
+ sns_ctl.sns_ocmem_status &= (~OCMEM_MAP_FAIL &
+ ~SNS_OCMEM_UNMAP_DONE &
+ ~SNS_OCMEM_UNMAP_FAIL);
+ break;
+ case OCMEM_MAP_FAIL:
+ sns_ctl.sns_ocmem_status |= SNS_OCMEM_MAP_FAIL;
+ sns_ctl.sns_ocmem_status &= (~OCMEM_MAP_DONE &
+ ~SNS_OCMEM_UNMAP_DONE &
+ ~SNS_OCMEM_UNMAP_FAIL);
+ break;
+ case OCMEM_UNMAP_DONE:
+ sns_ctl.sns_ocmem_status |= SNS_OCMEM_UNMAP_DONE;
+ sns_ctl.sns_ocmem_status &= (~SNS_OCMEM_UNMAP_FAIL &
+ ~SNS_OCMEM_MAP_DONE &
+ ~OCMEM_MAP_FAIL);
+ break;
+ case OCMEM_UNMAP_FAIL:
+ sns_ctl.sns_ocmem_status |= SNS_OCMEM_UNMAP_FAIL;
+ sns_ctl.sns_ocmem_status &= (~SNS_OCMEM_UNMAP_DONE &
+ ~SNS_OCMEM_MAP_DONE &
+ ~OCMEM_MAP_FAIL);
+ break;
+ case OCMEM_ALLOC_GROW:
+ sns_ctl.sns_ocmem_status |= SNS_OCMEM_ALLOC_GROW;
+ sns_ctl.sns_ocmem_status &= ~SNS_OCMEM_ALLOC_SHRINK;
+ break;
+ case OCMEM_ALLOC_SHRINK:
+ sns_ctl.sns_ocmem_status |= SNS_OCMEM_ALLOC_SHRINK;
+ sns_ctl.sns_ocmem_status &= ~SNS_OCMEM_ALLOC_GROW;
+ break;
+ default:
+ pr_err("%s: Unknown action received in OCMEM callback %lu\n",
+ __func__, action);
+ break;
+ }
+
+ pr_debug("%s: sns_ocmem_status: 0x%x\n", __func__,
+ sns_ctl.sns_ocmem_status);
+ spin_unlock_irqrestore(&sns_ctl.sns_lock, flags);
+
+ wake_up(&sns_ctl.sns_wait);
+
+ return 0;
+}
+
+/**
+ * Processes messages received through SMD from the ADSP
+ *
+ * @param hdr The message header
+ * @param msg Message pointer
+ *
+ * */
+void sns_ocmem_smd_process(struct sns_ocmem_hdr_s *hdr, void *msg)
+{
+ unsigned long flags;
+ pr_debug("%s\n", __func__);
+
+ spin_lock_irqsave(&sns_ctl.sns_lock, flags);
+
+ pr_debug("%s: Received message from ADSP; id: %i type: %i (%08x)\n",
+ __func__, hdr->msg_id, hdr->msg_type,
+ sns_ctl.sns_ocmem_status);
+
+ if (hdr->msg_id == SNS_OCMEM_PHYS_ADDR_RESP_V01 &&
+ hdr->msg_type == SNS_OCMEM_MSG_TYPE_RESP) {
+ struct sns_ocmem_phys_addr_resp_msg_v01 *msg_ptr =
+ (struct sns_ocmem_phys_addr_resp_msg_v01 *)msg;
+ pr_debug("%s: Received SNS_OCMEM_PHYS_ADDR_RESP_V01\n",
+ __func__);
+ pr_debug("%s: segments_valid=%d, segments_len=%d\n", __func__,
+ msg_ptr->segments_valid, msg_ptr->segments_len);
+
+ if (msg_ptr->segments_valid) {
+ sns_ctl.mem_segments_size = msg_ptr->segments_len;
+ memcpy(sns_ctl.mem_segments, msg_ptr->segments,
+ sizeof(struct sns_mem_segment_s_v01) *
+ msg_ptr->segments_len);
+
+ sns_ctl.sns_ocmem_status |= DSPS_PHYS_ADDR_SET;
+ } else {
+ pr_err("%s: Received invalid segment list\n", __func__);
+ }
+ } else if (hdr->msg_id == SNS_OCMEM_HAS_CLIENT_IND_V01 &&
+ hdr->msg_type == SNS_OCMEM_MSG_TYPE_IND) {
+ struct sns_ocmem_has_client_ind_msg_v01 *msg_ptr =
+ (struct sns_ocmem_has_client_ind_msg_v01 *)msg;
+
+ pr_debug("%s: Received SNS_OCMEM_HAS_CLIENT_IND_V01\n",
+ __func__);
+ pr_debug("%s: ADSP has %i client(s)\n", __func__,
+ msg_ptr->num_clients);
+ if (msg_ptr->num_clients > 0) {
+ sns_ctl.sns_ocmem_status |= DSPS_HAS_CLIENT;
+ sns_ctl.sns_ocmem_status &= ~DSPS_HAS_NO_CLIENT;
+ } else {
+ sns_ctl.sns_ocmem_status |= DSPS_HAS_NO_CLIENT;
+ sns_ctl.sns_ocmem_status &= ~DSPS_HAS_CLIENT;
+ }
+ } else if (hdr->msg_id == SNS_OCMEM_BW_VOTE_RESP_V01 &&
+ hdr->msg_type == SNS_OCMEM_MSG_TYPE_RESP) {
+ /* no need to handle this response msg, just return */
+ pr_debug("%s: Received SNS_OCMEM_BW_VOTE_RESP_V01\n", __func__);
+ spin_unlock_irqrestore(&sns_ctl.sns_lock, flags);
+ return;
+ } else if (hdr->msg_id == SNS_OCMEM_BW_VOTE_IND_V01 &&
+ hdr->msg_type == SNS_OCMEM_MSG_TYPE_IND) {
+ struct sns_ocmem_bw_vote_ind_msg_v01 *msg_ptr =
+ (struct sns_ocmem_bw_vote_ind_msg_v01 *)msg;
+ pr_debug("%s: Received BW_VOTE_IND_V01, is_vote_on=%d\n",
+ __func__, msg_ptr->is_vote_on);
+
+ if (msg_ptr->is_vote_on) {
+ sns_ctl.sns_ocmem_status |= DSPS_BW_VOTE_ON;
+ sns_ctl.sns_ocmem_status &= ~DSPS_BW_VOTE_OFF;
+ } else {
+ sns_ctl.sns_ocmem_status |= DSPS_BW_VOTE_OFF;
+ sns_ctl.sns_ocmem_status &= ~DSPS_BW_VOTE_ON;
+ }
+ } else {
+ pr_err("%s: Unknown message type received. id: %i; type: %i\n",
+ __func__, hdr->msg_id, hdr->msg_type);
+ }
+
+ pr_debug("%s: sns_ocmem_status: 0x%x\n",
+ __func__, sns_ctl.sns_ocmem_status);
+
+ spin_unlock_irqrestore(&sns_ctl.sns_lock, flags);
+
+ wake_up(&sns_ctl.sns_wait);
+}
+
+/**
+ * All SMD notifications and messages from Sensors on ADSP are
+ * received by this function
+ *
+ * */
+
+void sns_ocmem_smd_notify_data(void *data, unsigned int event)
+{
+ pr_debug("%s:\n", __func__);
+
+ if (event == SMD_EVENT_DATA) {
+ int len;
+ pr_debug("%s: Received SMD event Data\n", __func__);
+ len = smd_read_avail(sns_ctl.smd_ch);
+ pr_debug("%s: len=%d\n", __func__, len);
+ if (len > 0) {
+ data = kzalloc(SMD_BUF_SIZE, GFP_ATOMIC);
+ if (data == NULL) {
+ pr_err("%s: malloc failed", __func__);
+ return;
+ }
+
+ len = smd_read_from_cb(sns_ctl.smd_ch,
+ data, SMD_BUF_SIZE);
+ if (len > 0) {
+ sns_ocmem_smd_process(
+ (struct sns_ocmem_hdr_s *) data,
+ (void *)((char *)data +
+ sizeof(struct sns_ocmem_hdr_s)));
+ } else {
+ pr_err("Failed to read event from smd %i", len);
+ }
+ kfree(data);
+ } else if (len < 0) {
+ pr_err("Failed to read event from smd %i", len);
+ }
+ } else if (event == SMD_EVENT_OPEN) {
+ pr_debug("%s: Received SMD event Open\n", __func__);
+ } else if (event == SMD_EVENT_CLOSE) {
+ pr_debug("%s: Received SMD event Close\n", __func__);
+ }
+}
+
+static bool sns_ocmem_is_status_set(uint32_t sns_ocmem_status)
+{
+ unsigned long flags;
+ bool is_set;
+ pr_debug("%s: status=0x%x\n", __func__, sns_ocmem_status);
+
+ spin_lock_irqsave(&sns_ctl.sns_lock, flags);
+ is_set = sns_ctl.sns_ocmem_status & sns_ocmem_status;
+ spin_unlock_irqrestore(&sns_ctl.sns_lock, flags);
+ pr_debug("%s: is_set=%d\n", __func__, is_set);
+ return is_set;
+}
+
+/**
+ * Wait for a response from ADSP or OCMEM Driver, timeout if necessary
+ *
+ * @param sns_ocmem_status Status flags to wait for.
+ * @param timeout_sec Seconds to wait before timeout
+ * @param timeout_nsec Nanoseconds to wait. Total timeout = nsec + sec
+ *
+ * @return 0 If any status flag is set at any time prior to a timeout.
+ * 0 if success or timedout ; <0 for failures
+ *
+ */
+static int sns_ocmem_wait(uint32_t sns_ocmem_status,
+ uint32_t timeout_ms)
+{
+ int err;
+ pr_debug("%s: status=0x%x, timeout_ms=%d\n", __func__,
+ sns_ocmem_status, timeout_ms);
+ if (timeout_ms) {
+ err = wait_event_interruptible_timeout(sns_ctl.sns_wait,
+ sns_ocmem_is_status_set(sns_ocmem_status),
+ msecs_to_jiffies(timeout_ms));
+
+ if (err == 0)
+ pr_err("%s: interruptible_timeout timeout err=%i\n",
+ __func__, err);
+ else if (err < 0)
+ pr_err("%s: interruptible_timeout failed err=%i\n",
+ __func__, err);
+ } else { /* no timeout */
+ err = wait_event_interruptible(sns_ctl.sns_wait,
+ sns_ocmem_is_status_set(sns_ocmem_status));
+ if (err < 0)
+ pr_err("%s: wait_event_interruptible failed err=%i\n",
+ __func__, err);
+ }
+
+ return err;
+}
+
+/**
+ * Sends a message to the ADSP via SMD.
+ *
+ * @param hdr Specifies message type and other meta data
+ * @param msg_ptr Pointer to the message contents.
+ * Must be freed within this function if no error is returned.
+ *
+ * @return 0 upon success; < 0 upon error
+ */
+static int
+sns_ocmem_send_msg(struct sns_ocmem_hdr_s *hdr, void const *msg_ptr)
+{
+ int rv = 0;
+ int err = 0;
+ void *temp = NULL;
+ int size = sizeof(struct sns_ocmem_hdr_s) + hdr->msg_size;
+
+ temp = kzalloc(sizeof(struct sns_ocmem_hdr_s) + hdr->msg_size,
+ GFP_KERNEL);
+ pr_debug("%s size=%d\n", __func__, size);
+
+ if (temp == NULL) {
+ pr_err("%s: allocation failure\n", __func__);
+ rv = -ENOMEM;
+ }
+
+ hdr->dst_module = SNS_OCMEM_MODULE_ADSP;
+ hdr->src_module = SNS_OCMEM_MODULE_KERNEL;
+
+ memcpy(temp, hdr, sizeof(struct sns_ocmem_hdr_s));
+ memcpy((char *)temp + sizeof(struct sns_ocmem_hdr_s),
+ msg_ptr, hdr->msg_size);
+ pr_debug("%s: send msg type: %i size: %i id: %i dst: %i src: %i\n",
+ __func__, hdr->msg_type, hdr->msg_size,
+ hdr->msg_id, hdr->dst_module, hdr->src_module);
+
+ if (hdr == NULL) {
+ pr_err("%s: NULL message header\n", __func__);
+ rv = -EINVAL;
+ } else {
+ if (sns_ctl.smd_ch == NULL) {
+ pr_err("%s: null smd_ch\n", __func__);
+ rv = -EINVAL;
+ }
+ err = smd_write(sns_ctl.smd_ch, temp, size);
+ if (err < 0) {
+ pr_err("%s: smd_write failed %i\n", __func__, err);
+ rv = -ECOMM;
+ } else {
+ pr_debug("%s smd_write successful ret=%d\n",
+ __func__, err);
+ }
+ }
+
+ kfree(temp);
+
+ return rv;
+}
+
+/**
+ * Load ADSP Firmware.
+ */
+
+static int sns_load_adsp(void)
+{
+ pr_debug("%s.\n", __func__);
+
+ sns_ctl.pil = subsystem_get("adsp");
+ if (IS_ERR(sns_ctl.pil)) {
+ pr_err("%s: fail to load ADSP firmware\n", __func__);
+ return -ENODEV;
+ }
+
+ pr_debug("%s: Q6/ADSP image is loaded\n", __func__);
+
+ return 0;
+}
+
+static int sns_ocmem_platform_data_populate(struct platform_device *pdev)
+{
+ int ret;
+ struct msm_bus_scale_pdata *sns_ocmem_bus_scale_pdata = NULL;
+ struct msm_bus_vectors *sns_ocmem_bus_vectors = NULL;
+ struct msm_bus_paths *ocmem_sns_bus_paths = NULL;
+ u32 val;
+
+ if (!pdev->dev.of_node) {
+ pr_err("%s: device tree information missing\n", __func__);
+ return -ENODEV;
+ }
+
+ sns_ocmem_bus_vectors = kzalloc(sizeof(struct msm_bus_vectors),
+ GFP_KERNEL);
+ if (!sns_ocmem_bus_vectors) {
+ dev_err(&pdev->dev, "Failed to allocate memory for platform data\n");
+ return -ENOMEM;
+ }
+
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "qcom,src-id", &val);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: qcom,src-id missing in DT node\n",
+ __func__);
+ goto fail1;
+ }
+ sns_ocmem_bus_vectors->src = val;
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "qcom,dst-id", &val);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: qcom,dst-id missing in DT node\n",
+ __func__);
+ goto fail1;
+ }
+ sns_ocmem_bus_vectors->dst = val;
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "qcom,ab", &val);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: qcom,ab missing in DT node\n",
+ __func__);
+ goto fail1;
+ }
+ sns_ocmem_bus_vectors->ab = val;
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "qcom,ib", &val);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: qcom,ib missing in DT node\n",
+ __func__);
+ goto fail1;
+ }
+ sns_ocmem_bus_vectors->ib = val;
+ ocmem_sns_bus_paths = kzalloc(sizeof(struct msm_bus_paths),
+ GFP_KERNEL);
+
+ if (!ocmem_sns_bus_paths) {
+ dev_err(&pdev->dev, "Failed to allocate memory for platform data\n");
+ goto fail1;
+ }
+ ocmem_sns_bus_paths->num_paths = 1;
+ ocmem_sns_bus_paths->vectors = sns_ocmem_bus_vectors;
+
+ sns_ocmem_bus_scale_pdata =
+ kzalloc(sizeof(struct msm_bus_scale_pdata), GFP_KERNEL);
+ if (!sns_ocmem_bus_scale_pdata) {
+ dev_err(&pdev->dev, "Failed to allocate memory for platform data\n");
+ goto fail2;
+ }
+
+ sns_ocmem_bus_scale_pdata->usecase = ocmem_sns_bus_paths;
+ sns_ocmem_bus_scale_pdata->num_usecases = 1;
+ sns_ocmem_bus_scale_pdata->name = "sensors-ocmem";
+
+ dev_set_drvdata(&pdev->dev, sns_ocmem_bus_scale_pdata);
+ return ret;
+
+fail2:
+ kfree(ocmem_sns_bus_paths);
+fail1:
+ kfree(sns_ocmem_bus_vectors);
+ return ret;
+}
+
+
+/**
+ * Initialize all sensors ocmem driver data fields and register with the
+ * ocmem driver.
+ *
+ * @return 0 upon success; < 0 upon error
+ */
+static int sns_ocmem_init(void)
+{
+ int i, err, ret;
+ struct sns_ocmem_hdr_s addr_req_hdr;
+ struct msm_bus_scale_pdata *sns_ocmem_bus_scale_pdata = NULL;
+
+ pr_debug("%s\n", __func__);
+
+ /* register from OCMEM callack */
+ sns_ctl.ocmem_handle =
+ ocmem_notifier_register(SNS_OCMEM_CLIENT_ID,
+ &sns_ctl.ocmem_nb);
+ if (sns_ctl.ocmem_handle == NULL) {
+ pr_err("OCMEM notifier registration failed\n");
+ return -EFAULT;
+ }
+
+ /* populate platform data */
+ ret = sns_ocmem_platform_data_populate(sns_ctl.pdev);
+ if (ret) {
+ dev_err(&sns_ctl.pdev->dev,
+ "%s: failed to populate platform data, rc = %d\n",
+ __func__, ret);
+ return -ENODEV;
+ }
+ sns_ocmem_bus_scale_pdata = dev_get_drvdata(&sns_ctl.pdev->dev);
+
+ sns_ctl.sns_ocmem_bus_client =
+ msm_bus_scale_register_client(sns_ocmem_bus_scale_pdata);
+
+ if (!sns_ctl.sns_ocmem_bus_client) {
+ pr_err("%s: msm_bus_scale_register_client() failed\n",
+ __func__);
+ return -EFAULT;
+ }
+
+ /* load ADSP first */
+ if (sns_load_adsp() != 0) {
+ pr_err("%s: sns_load_adsp failed\n", __func__);
+ return -EFAULT;
+ }
+
+ /* wait before open SMD channel from kernel to ensure
+ channel has been openned already from ADSP side */
+ pr_debug("%s: sleep for 1000 ms\n", __func__);
+ msleep(1000);
+
+ err = smd_named_open_on_edge(SNS_OCMEM_SMD_CHANNEL,
+ SMD_APPS_QDSP,
+ &sns_ctl.smd_ch,
+ NULL,
+ sns_ocmem_smd_notify_data);
+ if (err != 0) {
+ pr_err("%s: smd_named_open_on_edge failed %i\n", __func__, err);
+ return -EFAULT;
+ }
+
+ pr_debug("%s: SMD channel openned successfuly!\n", __func__);
+ /* wait for the channel ready before writing data */
+ pr_debug("%s: sleep for 1000 ms\n", __func__);
+ msleep(1000);
+ pr_debug("%s sending PHYS_ADDR_REQ\n", __func__);
+ addr_req_hdr.msg_id = SNS_OCMEM_PHYS_ADDR_REQ_V01;
+ addr_req_hdr.msg_type = SNS_OCMEM_MSG_TYPE_REQ;
+ addr_req_hdr.msg_size = 0;
+
+ err = sns_ocmem_send_msg(&addr_req_hdr, NULL);
+ if (err != 0) {
+ pr_err("%s: sns_ocmem_send_msg failed %i\n", __func__, err);
+ return -ECOMM;
+ }
+
+ err = sns_ocmem_wait(DSPS_PHYS_ADDR_SET, 0);
+ if (err != 0) {
+ pr_err("%s: sns_ocmem_wait failed %i\n", __func__, err);
+ return -EFAULT;
+ }
+
+ sns_ctl.map_list.num_chunks = sns_ctl.mem_segments_size;
+ for (i = 0; i < sns_ctl.mem_segments_size; i++) {
+ sns_ctl.map_list.chunks[i].ro =
+ sns_ctl.mem_segments[i].type == 1 ? true : false;
+ sns_ctl.map_list.chunks[i].ddr_paddr =
+ sns_ctl.mem_segments[i].start_address;
+ sns_ctl.map_list.chunks[i].size =
+ sns_ctl.mem_segments[i].size;
+
+ pr_debug("%s: chunks[%d]: ro=%d, ddr_paddr=0x%lx, size=%li",
+ __func__, i,
+ sns_ctl.map_list.chunks[i].ro,
+ sns_ctl.map_list.chunks[i].ddr_paddr,
+ sns_ctl.map_list.chunks[i].size);
+ }
+
+ return 0;
+}
+
+/**
+ * Unmaps memory in ocmem back to DDR, indicates to the ADSP its completion,
+ * and waits for it to finish removing its bandwidth vote.
+ *
+ */
+static void sns_ocmem_unmap(void)
+{
+ unsigned long flags;
+ int err = 0;
+ pr_debug("%s\n", __func__);
+
+ ocmem_set_power_state(SNS_OCMEM_CLIENT_ID,
+ sns_ctl.buf, OCMEM_ON);
+
+ spin_lock_irqsave(&sns_ctl.sns_lock, flags);
+ sns_ctl.sns_ocmem_status &= (~SNS_OCMEM_UNMAP_FAIL &
+ ~SNS_OCMEM_UNMAP_DONE);
+ spin_unlock_irqrestore(&sns_ctl.sns_lock, flags);
+
+ err = ocmem_unmap(SNS_OCMEM_CLIENT_ID,
+ sns_ctl.buf,
+ &sns_ctl.map_list);
+
+ if (err != 0) {
+ pr_err("ocmem_unmap failed %i\n", err);
+ } else {
+ err = sns_ocmem_wait(SNS_OCMEM_UNMAP_DONE |
+ SNS_OCMEM_UNMAP_FAIL, 0);
+
+ if (err == 0) {
+ if (sns_ocmem_is_status_set(SNS_OCMEM_UNMAP_DONE))
+ pr_debug("%s: OCMEM_UNMAP_DONE\n", __func__);
+ else if (sns_ocmem_is_status_set(
+ SNS_OCMEM_UNMAP_FAIL)) {
+ pr_err("%s: OCMEM_UNMAP_FAIL\n", __func__);
+ BUG_ON(true);
+ } else
+ pr_err("%s: status flag not set\n", __func__);
+ } else {
+ pr_err("%s: sns_ocmem_wait failed %i\n",
+ __func__, err);
+ }
+ }
+
+ ocmem_set_power_state(SNS_OCMEM_CLIENT_ID,
+ sns_ctl.buf, OCMEM_OFF);
+}
+
+/**
+ * Waits for allocation to succeed. This may take considerable time if the device
+ * is presently in a high-power use case.
+ *
+ * @return 0 on success; < 0 upon error
+ */
+static int sns_ocmem_wait_for_alloc(void)
+{
+ int err = 0;
+ pr_debug("%s\n", __func__);
+
+ err = sns_ocmem_wait(SNS_OCMEM_ALLOC_GROW |
+ DSPS_HAS_NO_CLIENT, 0);
+
+ if (err == 0) {
+ if (sns_ocmem_is_status_set(DSPS_HAS_NO_CLIENT)) {
+ pr_debug("%s: Lost client while waiting for GROW\n",
+ __func__);
+ ocmem_free(SNS_OCMEM_CLIENT_ID, sns_ctl.buf);
+ sns_ctl.buf = NULL;
+ return -EPIPE;
+ }
+ } else {
+ pr_err("sns_ocmem_wait failed %i\n", err);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+/**
+ * Kicks-off the mapping of memory from DDR to ocmem. Waits for the process
+ * to complete, then indicates so to the ADSP.
+ *
+ * @return 0: Success; < 0: Other error
+ */
+static int sns_ocmem_map(void)
+{
+ int err = 0;
+ unsigned long flags;
+ pr_debug("%s\n", __func__);
+
+ spin_lock_irqsave(&sns_ctl.sns_lock, flags);
+ sns_ctl.sns_ocmem_status &=
+ (~SNS_OCMEM_MAP_FAIL & ~SNS_OCMEM_MAP_DONE);
+ spin_unlock_irqrestore(&sns_ctl.sns_lock, flags);
+
+ /* vote for ocmem bus bandwidth */
+ err = msm_bus_scale_client_update_request(
+ sns_ctl.sns_ocmem_bus_client,
+ 0);
+ if (err)
+ pr_err("%s: failed to vote for bus bandwidth\n", __func__);
+
+ err = ocmem_map(SNS_OCMEM_CLIENT_ID,
+ sns_ctl.buf,
+ &sns_ctl.map_list);
+
+ if (err != 0) {
+ pr_debug("ocmem_map failed %i\n", err);
+ ocmem_set_power_state(SNS_OCMEM_CLIENT_ID,
+ sns_ctl.buf, OCMEM_OFF);
+ ocmem_free(SNS_OCMEM_CLIENT_ID, sns_ctl.buf);
+ sns_ctl.buf = NULL;
+ } else {
+ err = sns_ocmem_wait(SNS_OCMEM_ALLOC_SHRINK |
+ DSPS_HAS_NO_CLIENT |
+ SNS_OCMEM_MAP_DONE |
+ SNS_OCMEM_MAP_FAIL, 0);
+
+ if (err == 0) {
+ if (sns_ocmem_is_status_set(SNS_OCMEM_MAP_DONE))
+ pr_debug("%s: OCMEM mapping DONE\n", __func__);
+ else if (sns_ocmem_is_status_set(DSPS_HAS_NO_CLIENT)) {
+ pr_debug("%s: Lost client while waiting for MAP\n",
+ __func__);
+ sns_ocmem_unmap();
+ ocmem_free(SNS_OCMEM_CLIENT_ID,
+ sns_ctl.buf);
+ sns_ctl.buf = NULL;
+ err = -EPIPE;
+ } else if (sns_ocmem_is_status_set(
+ SNS_OCMEM_ALLOC_SHRINK)) {
+ pr_debug("%s: SHRINK while wait for MAP\n",
+ __func__);
+ sns_ocmem_unmap();
+ err = ocmem_shrink(SNS_OCMEM_CLIENT_ID,
+ sns_ctl.buf, 0);
+ BUG_ON(err != 0);
+ err = -EFAULT;
+ } else if (sns_ocmem_is_status_set(
+ SNS_OCMEM_MAP_FAIL)) {
+ pr_err("%s: OCMEM mapping fails\n", __func__);
+ ocmem_set_power_state(SNS_OCMEM_CLIENT_ID,
+ sns_ctl.buf,
+ OCMEM_OFF);
+ ocmem_free(SNS_OCMEM_CLIENT_ID,
+ sns_ctl.buf);
+ sns_ctl.buf = NULL;
+ } else
+ pr_err("%s: status flag not set\n", __func__);
+ } else {
+ pr_err("sns_ocmem_wait failed %i\n", err);
+ }
+ }
+
+ return err;
+}
+
+/**
+ * Allocates memory in ocmem and maps to it from DDR.
+ *
+ * @return 0 upon success; <0 upon failure;
+ */
+static int sns_ocmem_alloc(void)
+{
+ int err = 0;
+ unsigned long flags;
+ pr_debug("%s\n", __func__);
+
+ if (sns_ctl.buf == NULL) {
+ spin_lock_irqsave(&sns_ctl.sns_lock, flags);
+ sns_ctl.sns_ocmem_status &= ~SNS_OCMEM_ALLOC_GROW &
+ ~SNS_OCMEM_ALLOC_SHRINK;
+ spin_unlock_irqrestore(&sns_ctl.sns_lock, flags);
+ sns_ctl.buf = ocmem_allocate_nb(SNS_OCMEM_CLIENT_ID,
+ SNS_OCMEM_SIZE);
+
+ if (sns_ctl.buf == NULL) {
+ pr_err("ocmem_allocate_nb returned NULL\n");
+ sns_ctl.ocmem_enabled = false;
+ err = -EFAULT;
+ } else if (sns_ctl.buf->len != 0 &&
+ SNS_OCMEM_SIZE > sns_ctl.buf->len) {
+ pr_err("ocmem_allocate_nb: invalid len %li, Req: %i)\n",
+ sns_ctl.buf->len, SNS_OCMEM_SIZE);
+ sns_ctl.ocmem_enabled = false;
+ err = -EFAULT;
+ }
+ }
+
+ pr_debug("%s OCMEM buf=%lx, buffer len=%li\n", __func__,
+ sns_ctl.buf->addr, sns_ctl.buf->len);
+
+ while (sns_ctl.ocmem_enabled) {
+ if (sns_ctl.buf->len == 0) {
+ pr_debug("%s: Waiting for memory allocation\n",
+ __func__);
+ err = sns_ocmem_wait_for_alloc();
+ if (err == -EPIPE) {
+ pr_debug("%s:Lost client while wait for alloc\n",
+ __func__);
+ break;
+ } else if (err != 0) {
+ pr_err("sns_ocmem_wait_for_alloc failed %i\n",
+ err);
+ break;
+ }
+ }
+
+ ocmem_set_power_state(SNS_OCMEM_CLIENT_ID,
+ sns_ctl.buf,
+ OCMEM_ON);
+
+ err = sns_ocmem_map();
+
+ if (err == -EPIPE) {
+ pr_debug("%s: Lost client while waiting for mapping\n",
+ __func__);
+ break;
+ } else if (err < 0) {
+ pr_debug("%s: Mapping failed, will try again\n",
+ __func__);
+ break;
+ } else if (err == 0) {
+ pr_debug("%s: Mapping finished\n", __func__);
+ break;
+ }
+ }
+
+ return err;
+}
+
+/**
+ * Indicate to the ADSP that unmapping has completed, and wait for the response
+ * that its bandwidth vote has been removed.
+ *
+ * @return 0 Upon success; < 0 upon error
+ */
+static int sns_ocmem_unmap_send(void)
+{
+ int err;
+ struct sns_ocmem_hdr_s msg_hdr;
+ struct sns_ocmem_bw_vote_req_msg_v01 msg;
+ pr_debug("%s\n", __func__);
+
+ memset(&msg, 0, sizeof(struct sns_ocmem_bw_vote_req_msg_v01));
+
+ msg_hdr.msg_id = SNS_OCMEM_BW_VOTE_REQ_V01;
+ msg_hdr.msg_type = SNS_OCMEM_MSG_TYPE_REQ;
+ msg_hdr.msg_size = sizeof(struct sns_ocmem_bw_vote_req_msg_v01);
+ msg.is_map = 0;
+ msg.vectors_valid = 0;
+ msg.vectors_len = 0;
+
+ pr_debug("%s: send bw_vote OFF\n", __func__);
+ err = sns_ocmem_send_msg(&msg_hdr, &msg);
+ if (err != 0) {
+ pr_err("%s: sns_ocmem_send_msg failed %i\n",
+ __func__, err);
+ } else {
+ err = sns_ocmem_wait(DSPS_BW_VOTE_OFF, 0);
+ if (err != 0)
+ pr_err("%s: sns_ocmem_wait failed %i\n", __func__, err);
+ }
+
+ return err;
+}
+
+/**
+ * Indicate to the ADSP that mapping has completed, and wait for the response
+ * that its bandwidth vote has been made.
+ *
+ * @return 0 Upon success; < 0 upon error
+ */
+static int sns_ocmem_map_send(void)
+{
+ int err;
+ struct sns_ocmem_hdr_s msg_hdr;
+ struct sns_ocmem_bw_vote_req_msg_v01 msg;
+ struct ocmem_vectors *vectors;
+ pr_debug("%s\n", __func__);
+
+ memset(&msg, 0, sizeof(struct sns_ocmem_bw_vote_req_msg_v01));
+
+ msg_hdr.msg_id = SNS_OCMEM_BW_VOTE_REQ_V01;
+ msg_hdr.msg_type = SNS_OCMEM_MSG_TYPE_REQ;
+ msg_hdr.msg_size = sizeof(struct sns_ocmem_bw_vote_req_msg_v01);
+ msg.is_map = 1;
+
+ vectors = ocmem_get_vectors(SNS_OCMEM_CLIENT_ID, sns_ctl.buf);
+ if ((vectors != NULL)) {
+ memcpy(&msg.vectors, vectors, sizeof(vectors));
+ /* TODO: set vectors_len */
+ msg.vectors_valid = true;
+ msg.vectors_len = 0;
+ }
+
+ pr_debug("%s: send bw_vote ON\n", __func__);
+ err = sns_ocmem_send_msg(&msg_hdr, &msg);
+ if (err != 0) {
+ pr_err("%s: sns_ocmem_send_msg failed %i\n", __func__, err);
+ } else {
+ err = sns_ocmem_wait(DSPS_BW_VOTE_ON |
+ SNS_OCMEM_ALLOC_SHRINK, 0);
+ if (err != 0)
+ pr_err("%s: sns_ocmem_wait failed %i\n", __func__, err);
+ }
+
+ return err;
+}
+
+/**
+ * Perform the encessary operations to clean-up OCMEM after being notified that
+ * there is no longer a client; if sensors was evicted; or if some error
+ * has occurred.
+ *
+ * @param[i] do_free Whether the memory should be freed (true) or if shrink
+ * should be called instead (false).
+ */
+static void sns_ocmem_evicted(bool do_free)
+{
+ int err = 0;
+ pr_debug("%s\n", __func__);
+
+ sns_ocmem_unmap();
+ if (do_free) {
+ ocmem_free(SNS_OCMEM_CLIENT_ID, sns_ctl.buf);
+ sns_ctl.buf = NULL;
+ } else {
+ err = ocmem_shrink(SNS_OCMEM_CLIENT_ID, sns_ctl.buf, 0);
+ BUG_ON(err != 0);
+ }
+
+ err = sns_ocmem_unmap_send();
+ if (err != 0)
+ pr_err("sns_ocmem_unmap_send failed %i\n", err);
+}
+
+/**
+ * After mapping has completed and the ADSP has reacted appropriately, wait
+ * for a shrink command or word from the ADSP that it no longer has a client.
+ *
+ * @return 0 If no clients; < 0 upon error;
+ */
+static int sns_ocmem_map_done(void)
+{
+ int err = 0;
+ unsigned long flags;
+
+ pr_debug("%s\n", __func__);
+
+ err = sns_ocmem_map_send();
+ if (err != 0) {
+ pr_err("sns_ocmem_map_send failed %i\n", err);
+ sns_ocmem_evicted(true);
+ } else {
+ ocmem_set_power_state(SNS_OCMEM_CLIENT_ID,
+ sns_ctl.buf, OCMEM_OFF);
+
+ pr_debug("%s: Waiting for shrink or 'no client' updates\n",
+ __func__);
+ err = sns_ocmem_wait(DSPS_HAS_NO_CLIENT |
+ SNS_OCMEM_ALLOC_SHRINK, 0);
+ if (err == 0) {
+ if (sns_ocmem_is_status_set(DSPS_HAS_NO_CLIENT)) {
+ pr_debug("%s: No longer have a client\n",
+ __func__);
+ sns_ocmem_evicted(true);
+ } else if (sns_ocmem_is_status_set(
+ SNS_OCMEM_ALLOC_SHRINK)) {
+ pr_debug("%s: Received SHRINK\n", __func__);
+ sns_ocmem_evicted(false);
+
+ spin_lock_irqsave(&sns_ctl.sns_lock, flags);
+ sns_ctl.sns_ocmem_status &=
+ ~SNS_OCMEM_ALLOC_SHRINK;
+ spin_unlock_irqrestore(&sns_ctl.sns_lock,
+ flags);
+ err = -EFAULT;
+ }
+ } else {
+ pr_err("sns_ocmem_wait failed %i\n", err);
+ }
+ }
+
+ return err;
+}
+
+/**
+ * Main function.
+ * Initializes sensors ocmem feature, and waits for an ADSP client.
+ *
+ */
+static void sns_ocmem_main(struct work_struct *work)
+{
+ int err = 0;
+ pr_debug("%s\n", __func__);
+
+ err = sns_ocmem_init();
+ if (err != 0) {
+ pr_err("%s: sns_ocmem_init failed %i\n", __func__, err);
+ return;
+ }
+
+ while (true) {
+ pr_debug("%s: Waiting for sensor client\n", __func__);
+ if (sns_ocmem_is_status_set(DSPS_HAS_CLIENT) ||
+ !sns_ocmem_wait(DSPS_HAS_CLIENT, 0)) {
+ pr_debug("%s: DSPS_HAS_CLIENT\n", __func__);
+
+ err = sns_ocmem_alloc();
+ if (err != 0) {
+ pr_err("sns_ocmem_alloc failed %i\n", err);
+ return;
+ } else {
+ err = sns_ocmem_map_done();
+ if (err != 0) {
+ pr_err("sns_ocmem_map_done failed %i",
+ err);
+ return;
+ }
+ }
+ }
+ }
+
+ ocmem_notifier_unregister(sns_ctl.ocmem_handle,
+ &sns_ctl.ocmem_nb);
+}
+
+static int sensors_adsp_open(struct inode *ip, struct file *fp)
+{
+ int ret = 0;
+ pr_debug("%s\n", __func__);
+ return ret;
+}
+
+static int sensors_adsp_release(struct inode *inode, struct file *file)
+{
+ pr_debug("%s\n", __func__);
+ return 0;
+}
+
+/**
+ * Read QTimer clock ticks and scale down to 32KHz clock as used
+ * in DSPS
+ */
+static u32 sns_read_qtimer(void)
+{
+ u64 val;
+ val = arch_counter_get_cntpct();
+ /*
+ * To convert ticks from 19.2 Mhz clock to 32768 Hz clock:
+ * x = (value * 32768) / 19200000
+ * This is same as first left shift the value by 4 bits, i.e. mutiply
+ * by 16, and then divide by 9375. The latter is preferable since
+ * QTimer tick (value) is 56-bit, so (value * 32768) could overflow,
+ * while (value * 16) will never do
+ */
+ val <<= 4;
+ do_div(val, 9375);
+
+ pr_debug("%s.count=%llu\n", __func__, val);
+ return (u32)val;
+}
+
+/**
+ * IO Control - handle commands from client.
+ *
+ */
+static long sensors_adsp_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret = 0;
+ u32 val = 0;
+ pr_debug("%s\n", __func__);
+
+ switch (cmd) {
+ case DSPS_IOCTL_READ_SLOW_TIMER:
+ val = sns_read_qtimer();
+ ret = put_user(val, (u32 __user *) arg);
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * platform driver
+ *
+ */
+const struct file_operations sensors_adsp_fops = {
+ .owner = THIS_MODULE,
+ .open = sensors_adsp_open,
+ .release = sensors_adsp_release,
+ .unlocked_ioctl = sensors_adsp_ioctl,
+};
+
+static int sensors_adsp_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ pr_debug("%s.\n", __func__);
+ sns_ctl.dev_class = class_create(THIS_MODULE, DRV_NAME);
+ if (sns_ctl.dev_class == NULL) {
+ pr_err("%s: class_create fail.\n", __func__);
+ goto res_err;
+ }
+
+ ret = alloc_chrdev_region(&sns_ctl.dev_num, 0, 1, DRV_NAME);
+ if (ret) {
+ pr_err("%s: alloc_chrdev_region fail.\n", __func__);
+ goto alloc_chrdev_region_err;
+ }
+
+ sns_ctl.dev = device_create(sns_ctl.dev_class, NULL,
+ sns_ctl.dev_num,
+ &sns_ctl, DRV_NAME);
+ if (IS_ERR(sns_ctl.dev)) {
+ pr_err("%s: device_create fail.\n", __func__);
+ goto device_create_err;
+ }
+
+ sns_ctl.cdev = cdev_alloc();
+ if (sns_ctl.cdev == NULL) {
+ pr_err("%s: cdev_alloc fail.\n", __func__);
+ goto cdev_alloc_err;
+ }
+ cdev_init(sns_ctl.cdev, &sensors_adsp_fops);
+ sns_ctl.cdev->owner = THIS_MODULE;
+
+ ret = cdev_add(sns_ctl.cdev, sns_ctl.dev_num, 1);
+ if (ret) {
+ pr_err("%s: cdev_add fail.\n", __func__);
+ goto cdev_add_err;
+ }
+
+ sns_ctl.sns_workqueue =
+ alloc_workqueue("sns_ocmem", WQ_NON_REENTRANT, 0);
+ if (!sns_ctl.sns_workqueue) {
+ pr_err("%s: Failed to create work queue\n",
+ __func__);
+ goto cdev_add_err;
+ }
+
+ init_waitqueue_head(&sns_ctl.sns_wait);
+ spin_lock_init(&sns_ctl.sns_lock);
+
+ sns_ctl.ocmem_handle = NULL;
+ sns_ctl.buf = NULL;
+ sns_ctl.sns_ocmem_status = 0;
+ sns_ctl.ocmem_enabled = true;
+ sns_ctl.ocmem_nb.notifier_call = sns_ocmem_drv_cb;
+ sns_ctl.smd_ch = NULL;
+ sns_ctl.pdev = pdev;
+
+ INIT_WORK(&sns_ctl.sns_work, sns_ocmem_main);
+ queue_work(sns_ctl.sns_workqueue, &sns_ctl.sns_work);
+
+ return 0;
+
+cdev_add_err:
+ kfree(sns_ctl.cdev);
+cdev_alloc_err:
+ device_destroy(sns_ctl.dev_class, sns_ctl.dev_num);
+device_create_err:
+ unregister_chrdev_region(sns_ctl.dev_num, 1);
+alloc_chrdev_region_err:
+ class_destroy(sns_ctl.dev_class);
+res_err:
+ return -ENODEV;
+}
+
+static int sensors_adsp_remove(struct platform_device *pdev)
+{
+ struct msm_bus_scale_pdata *sns_ocmem_bus_scale_pdata = NULL;
+ pr_debug("%s.\n", __func__);
+
+ sns_ocmem_bus_scale_pdata = (struct msm_bus_scale_pdata *)
+ dev_get_drvdata(&pdev->dev);
+
+ kfree(sns_ocmem_bus_scale_pdata->usecase->vectors);
+ kfree(sns_ocmem_bus_scale_pdata->usecase);
+ kfree(sns_ocmem_bus_scale_pdata);
+
+ ocmem_notifier_unregister(sns_ctl.ocmem_handle,
+ &sns_ctl.ocmem_nb);
+ destroy_workqueue(sns_ctl.sns_workqueue);
+
+ cdev_del(sns_ctl.cdev);
+ kfree(sns_ctl.cdev);
+ sns_ctl.cdev = NULL;
+ device_destroy(sns_ctl.dev_class, sns_ctl.dev_num);
+ unregister_chrdev_region(sns_ctl.dev_num, 1);
+ class_destroy(sns_ctl.dev_class);
+
+ return 0;
+}
+
+static const struct of_device_id msm_adsp_sensors_dt_match[] = {
+ {.compatible = "qcom,msm-adsp-sensors"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, msm_adsp_sensors_dt_match);
+
+
+static struct platform_driver sensors_adsp_driver = {
+ .driver = {
+ .name = "sensors-adsp",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_adsp_sensors_dt_match,
+ },
+ .probe = sensors_adsp_probe,
+ .remove = sensors_adsp_remove,
+};
+
+/**
+ * Module Init.
+ */
+static int sensors_adsp_init(void)
+{
+ int rc;
+ pr_debug("%s.\n", __func__);
+ pr_debug("%s driver version %s.\n", DRV_NAME, DRV_VERSION);
+
+ rc = platform_driver_register(&sensors_adsp_driver);
+
+ if (rc) {
+ pr_err("%s: Failed to register sensors adsp driver\n",
+ __func__);
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Module Exit.
+ */
+static void sensors_adsp_exit(void)
+{
+ pr_debug("%s.\n", __func__);
+ platform_driver_unregister(&sensors_adsp_driver);
+}
+
+module_init(sensors_adsp_init);
+module_exit(sensors_adsp_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Sensors ADSP driver");
diff --git a/arch/arm/mach-msm/spm.h b/arch/arm/mach-msm/spm.h
index a353ce0..01f6787 100644
--- a/arch/arm/mach-msm/spm.h
+++ b/arch/arm/mach-msm/spm.h
@@ -130,7 +130,14 @@
int msm_spm_set_low_power_mode(unsigned int mode, bool notify_rpm);
int msm_spm_set_vdd(unsigned int cpu, unsigned int vlevel);
unsigned int msm_spm_get_vdd(unsigned int cpu);
+#if defined(CONFIG_MSM_SPM_V2)
int msm_spm_turn_on_cpu_rail(unsigned int cpu);
+#else
+static inline int msm_spm_turn_on_cpu_rail(unsigned int cpu)
+{
+ return -ENOSYS;
+}
+#endif
/* Internal low power management specific functions */
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index 3c38536..32629e2 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -2305,6 +2305,9 @@
{
struct cfq_group *cfqg = cfq_get_next_cfqg(cfqd);
+ if (!cfqg)
+ return;
+
cfqd->serving_group = cfqg;
/* Restore the workload type data */
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 9e419e1..82d19e0 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -281,6 +281,7 @@
static const struct of_device_id ahci_of_match[] = {
{ .compatible = "calxeda,hb-ahci", },
{ .compatible = "snps,spear-ahci", },
+ { .compatible = "qcom,msm-ahci", },
{},
};
MODULE_DEVICE_TABLE(of, ahci_of_match);
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index f2f4f0c..d4b1856 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -138,7 +138,7 @@
buf+4+cmd_code_len, write_len);
entry->data_len += write_len;
/* delete immediate response entry */
- if (driver->smd_dci[SMD_MODEM_INDEX].
+ if (driver->smd_dci[MODEM_DATA].
buf_in_1[8+cmd_code_len] != 0x80)
driver->req_tracking_tbl[index].pid = 0;
break;
@@ -289,23 +289,7 @@
uint8_t *client_log_mask_ptr;
uint8_t *log_mask_ptr;
int ret;
- int index;
-
- switch (smd_info->peripheral) {
- case MODEM_PROC:
- index = SMD_MODEM_INDEX;
- break;
- case LPASS_PROC:
- index = SMD_LPASS_INDEX;
- break;
- case WCNSS_PROC:
- index = SMD_WCNSS_INDEX;
- break;
- default:
- pr_err("diag: In %s, unknown peripheral: %d\n",
- __func__, smd_info->peripheral);
- return;
- }
+ int index = smd_info->peripheral;
/* Update the peripheral(s) with the dci log and event masks */
@@ -379,7 +363,7 @@
int index;
if (pdev->id == SMD_APPS_MODEM) {
- index = SMD_MODEM_INDEX;
+ index = MODEM_DATA;
err = smd_open("DIAG_2", &driver->smd_dci[index].ch,
&driver->smd_dci[index],
diag_smd_notify);
@@ -397,6 +381,7 @@
int len, int index)
{
int i;
+ int status = 0;
/* remove UID from user space pkt before sending to peripheral */
buf = buf + 4;
@@ -414,17 +399,23 @@
driver->apps_dci_buf[9+len] = CONTROL_CHAR; /* end */
- if (entry.client_id == MODEM_PROC &&
- driver->smd_dci[SMD_MODEM_INDEX].ch) {
- smd_write(driver->smd_dci[SMD_MODEM_INDEX].ch,
+ for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) {
+ if (entry.client_id == driver->smd_dci[i].peripheral) {
+ if (driver->smd_dci[i].ch) {
+ smd_write(driver->smd_dci[i].ch,
driver->apps_dci_buf, len + 10);
- i = DIAG_DCI_NO_ERROR;
- } else {
+ status = DIAG_DCI_NO_ERROR;
+ }
+ break;
+ }
+ }
+
+ if (status != DIAG_DCI_NO_ERROR) {
pr_alert("diag: check DCI channel\n");
- i = DIAG_DCI_SEND_DATA_FAIL;
+ status = DIAG_DCI_SEND_DATA_FAIL;
}
mutex_unlock(&driver->dci_mutex);
- return i;
+ return status;
}
int diag_register_dci_transaction(int uid)
@@ -464,9 +455,9 @@
uint8_t *event_mask_ptr;
int offset = 0;
- if (!driver->smd_dci[SMD_MODEM_INDEX].ch) {
+ if (!driver->smd_dci[MODEM_DATA].ch) {
pr_err("diag: DCI smd channel for peripheral %d not valid for dci updates\n",
- driver->smd_dci[SMD_MODEM_INDEX].peripheral);
+ driver->smd_dci[MODEM_DATA].peripheral);
return DIAG_DCI_SEND_DATA_FAIL;
}
@@ -591,8 +582,7 @@
ret = DIAG_DCI_NO_ERROR;
}
/* send updated mask to peripherals */
- ret = diag_send_dci_log_mask(driver->
- smd_cntl[SMD_MODEM_INDEX].ch);
+ ret = diag_send_dci_log_mask(driver->smd_cntl[MODEM_DATA].ch);
} else if (*(int *)temp == DCI_EVENT_TYPE) {
/* find client id and table */
for (i = 0; i < MAX_DCI_CLIENTS; i++) {
@@ -638,8 +628,7 @@
ret = DIAG_DCI_NO_ERROR;
}
/* send updated mask to peripherals */
- ret = diag_send_dci_event_mask(driver->
- smd_cntl[SMD_MODEM_INDEX].ch);
+ ret = diag_send_dci_event_mask(driver->smd_cntl[MODEM_DATA].ch);
} else {
pr_alert("diag: Incorrect DCI transaction\n");
}
@@ -860,8 +849,8 @@
mutex_init(&driver->dci_mutex);
mutex_init(&dci_log_mask_mutex);
mutex_init(&dci_event_mask_mutex);
- success = diag_smd_constructor(&driver->smd_dci[SMD_MODEM_INDEX],
- MODEM_PROC, SMD_DCI_TYPE, DIAG_CON_MPSS);
+ success = diag_smd_constructor(&driver->smd_dci[MODEM_DATA],
+ MODEM_DATA, SMD_DCI_TYPE);
if (!success)
goto err;
diff --git a/drivers/char/diag/diag_debugfs.c b/drivers/char/diag/diag_debugfs.c
index 8badc55..d852d75 100644
--- a/drivers/char/diag/diag_debugfs.c
+++ b/drivers/char/diag/diag_debugfs.c
@@ -56,26 +56,26 @@
"RIVA in_busy_2: %d\n"
"DCI Modem in_busy_1: %d\n"
"logging_mode: %d\n",
- (unsigned int)driver->smd_data[SMD_MODEM_INDEX].ch,
- (unsigned int)driver->smd_data[SMD_LPASS_INDEX].ch,
- (unsigned int)driver->smd_data[SMD_WCNSS_INDEX].ch,
- (unsigned int)driver->smd_dci[SMD_MODEM_INDEX].ch,
- (unsigned int)driver->smd_cntl[SMD_MODEM_INDEX].ch,
- (unsigned int)driver->smd_cntl[SMD_LPASS_INDEX].ch,
- (unsigned int)driver->smd_cntl[SMD_WCNSS_INDEX].ch,
+ (unsigned int)driver->smd_data[MODEM_DATA].ch,
+ (unsigned int)driver->smd_data[LPASS_DATA].ch,
+ (unsigned int)driver->smd_data[WCNSS_DATA].ch,
+ (unsigned int)driver->smd_dci[MODEM_DATA].ch,
+ (unsigned int)driver->smd_cntl[MODEM_DATA].ch,
+ (unsigned int)driver->smd_cntl[LPASS_DATA].ch,
+ (unsigned int)driver->smd_cntl[WCNSS_DATA].ch,
chk_config_get_id(),
chk_apps_only(),
chk_apps_master(),
chk_polling_response(),
driver->polling_reg_flag,
driver->use_device_tree,
- driver->smd_data[SMD_MODEM_INDEX].in_busy_1,
- driver->smd_data[SMD_MODEM_INDEX].in_busy_2,
- driver->smd_data[SMD_LPASS_INDEX].in_busy_1,
- driver->smd_data[SMD_LPASS_INDEX].in_busy_2,
- driver->smd_data[SMD_WCNSS_INDEX].in_busy_1,
- driver->smd_data[SMD_WCNSS_INDEX].in_busy_2,
- driver->smd_dci[SMD_MODEM_INDEX].in_busy_1,
+ driver->smd_data[MODEM_DATA].in_busy_1,
+ driver->smd_data[MODEM_DATA].in_busy_2,
+ driver->smd_data[LPASS_DATA].in_busy_1,
+ driver->smd_data[LPASS_DATA].in_busy_2,
+ driver->smd_data[WCNSS_DATA].in_busy_1,
+ driver->smd_data[WCNSS_DATA].in_busy_2,
+ driver->smd_dci[MODEM_DATA].in_busy_1,
driver->logging_mode);
#ifdef CONFIG_DIAG_OVER_USB
@@ -119,33 +119,33 @@
"RIVA cntl diag_notify_update_smd_work: %d\n"
"Modem dci diag_notify_update_smd_work: %d\n",
work_pending(&(driver->diag_drain_work)),
- work_pending(&(driver->smd_data[SMD_MODEM_INDEX].
+ work_pending(&(driver->smd_data[MODEM_DATA].
diag_read_smd_work)),
- work_pending(&(driver->smd_data[SMD_LPASS_INDEX].
+ work_pending(&(driver->smd_data[LPASS_DATA].
diag_read_smd_work)),
- work_pending(&(driver->smd_data[SMD_WCNSS_INDEX].
+ work_pending(&(driver->smd_data[WCNSS_DATA].
diag_read_smd_work)),
- work_pending(&(driver->smd_cntl[SMD_MODEM_INDEX].
+ work_pending(&(driver->smd_cntl[MODEM_DATA].
diag_read_smd_work)),
- work_pending(&(driver->smd_cntl[SMD_LPASS_INDEX].
+ work_pending(&(driver->smd_cntl[LPASS_DATA].
diag_read_smd_work)),
- work_pending(&(driver->smd_cntl[SMD_WCNSS_INDEX].
+ work_pending(&(driver->smd_cntl[WCNSS_DATA].
diag_read_smd_work)),
- work_pending(&(driver->smd_dci[SMD_MODEM_INDEX].
+ work_pending(&(driver->smd_dci[MODEM_DATA].
diag_read_smd_work)),
- work_pending(&(driver->smd_data[SMD_MODEM_INDEX].
+ work_pending(&(driver->smd_data[MODEM_DATA].
diag_notify_update_smd_work)),
- work_pending(&(driver->smd_data[SMD_LPASS_INDEX].
+ work_pending(&(driver->smd_data[LPASS_DATA].
diag_notify_update_smd_work)),
- work_pending(&(driver->smd_data[SMD_WCNSS_INDEX].
+ work_pending(&(driver->smd_data[WCNSS_DATA].
diag_notify_update_smd_work)),
- work_pending(&(driver->smd_cntl[SMD_MODEM_INDEX].
+ work_pending(&(driver->smd_cntl[MODEM_DATA].
diag_notify_update_smd_work)),
- work_pending(&(driver->smd_cntl[SMD_LPASS_INDEX].
+ work_pending(&(driver->smd_cntl[LPASS_DATA].
diag_notify_update_smd_work)),
- work_pending(&(driver->smd_cntl[SMD_WCNSS_INDEX].
+ work_pending(&(driver->smd_cntl[WCNSS_DATA].
diag_notify_update_smd_work)),
- work_pending(&(driver->smd_dci[SMD_MODEM_INDEX].
+ work_pending(&(driver->smd_dci[MODEM_DATA].
diag_notify_update_smd_work)));
#ifdef CONFIG_DIAG_OVER_USB
@@ -185,6 +185,15 @@
}
bytes_remaining = buf_size;
+
+ if (diag_dbgfs_table_index == 0) {
+ bytes_written = scnprintf(buf+bytes_in_buffer, bytes_remaining,
+ "Client ids: Modem: %d, LPASS: %d, "
+ "WCNSS: %d, APPS: %d\n",
+ MODEM_DATA, LPASS_DATA, WCNSS_DATA, APPS_DATA);
+ bytes_in_buffer += bytes_written;
+ }
+
for (i = diag_dbgfs_table_index; i < diag_max_reg; i++) {
/* Do not process empty entries in the table */
if (driver->table[i].process_id == 0)
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index b2952f2..2a85a00 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -501,7 +501,7 @@
} /* Get log masks */
else if (*buf == 0x73 && *(int *)(buf+4) == 4) {
#if defined(CONFIG_DIAG_OVER_USB)
- if (!(driver->smd_data[SMD_MODEM_INDEX].ch) &&
+ if (!(driver->smd_data[MODEM_DATA].ch) &&
chk_apps_only()) {
equip_id = *(int *)(buf + 8);
num_items = *(int *)(buf + 12);
@@ -550,7 +550,7 @@
ssid_first = *(uint16_t *)(buf + 2);
ssid_last = *(uint16_t *)(buf + 4);
#if defined(CONFIG_DIAG_OVER_USB)
- if (!(driver->smd_data[SMD_MODEM_INDEX].ch) &&
+ if (!(driver->smd_data[MODEM_DATA].ch) &&
chk_apps_only()) {
driver->apps_rsp_buf[0] = 0x7d;
driver->apps_rsp_buf[1] = 0x3;
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index fe63a3c..77f9dd6 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -41,17 +41,14 @@
#define POOL_TYPE_HSIC 8
#define POOL_TYPE_HSIC_WRITE 16
#define POOL_TYPE_ALL 7
-#define MODEM_DATA 1
-#define LPASS_DATA 2
+#define MODEM_DATA 0
+#define LPASS_DATA 1
+#define WCNSS_DATA 2
#define APPS_DATA 3
#define SDIO_DATA 4
-#define WCNSS_DATA 5
-#define HSIC_DATA 6
-#define SMUX_DATA 7
-#define MODEM_PROC 0
+#define HSIC_DATA 5
+#define SMUX_DATA 6
#define APPS_PROC 1
-#define LPASS_PROC 2
-#define WCNSS_PROC 3
#define MSG_MASK_SIZE 10000
#define LOG_MASK_SIZE 8000
#define EVENT_MASK_SIZE 1000
@@ -85,10 +82,6 @@
#define SMD_CNTL_TYPE 1
#define SMD_DCI_TYPE 2
-#define SMD_MODEM_INDEX 0
-#define SMD_LPASS_INDEX 1
-#define SMD_WCNSS_INDEX 2
-
/* Maximum number of pkt reg supported at initialization*/
extern unsigned int diag_max_reg;
extern unsigned int diag_threshold_reg;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 47ba97f2..9bd8950 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -321,7 +321,7 @@
return 0;
}
-void diag_clear_reg(int proc_num)
+void diag_clear_reg(int peripheral)
{
int i;
@@ -329,9 +329,8 @@
/* reset polling flag */
driver->polling_reg_flag = 0;
for (i = 0; i < diag_max_reg; i++) {
- if (driver->table[i].client_id == proc_num) {
+ if (driver->table[i].client_id == peripheral)
driver->table[i].process_id = 0;
- }
}
/* re-scan the registration table */
for (i = 0; i < diag_max_reg; i++) {
@@ -358,7 +357,7 @@
driver->polling_reg_flag = 1;
if (params->proc_id == APPS_PROC) {
driver->table[j].process_id = current->tgid;
- driver->table[j].client_id = APPS_PROC;
+ driver->table[j].client_id = APPS_DATA;
} else {
driver->table[j].process_id = NON_APPS_PROC;
driver->table[j].client_id = params->client_id;
@@ -550,7 +549,8 @@
return -EFAULT;
mutex_lock(&driver->dci_mutex);
if (!(driver->num_dci_client))
- driver->smd_dci[SMD_MODEM_INDEX].in_busy_1 = 0;
+ for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++)
+ driver->smd_dci[i].in_busy_1 = 0;
driver->num_dci_client++;
pr_debug("diag: In %s, id = %d\n",
__func__, driver->dci_client_id);
@@ -602,9 +602,11 @@
mutex_unlock(&driver->dci_mutex);
return success;
} else if (iocmd == DIAG_IOCTL_DCI_SUPPORT) {
- if (driver->smd_dci[SMD_MODEM_INDEX].ch)
- support_list |=
- driver->smd_dci[SMD_MODEM_INDEX].peripheral_mask;
+ for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) {
+ if (driver->smd_dci[i].ch)
+ support_list |=
+ driver->smd_dci[i].peripheral_mask;
+ }
if (copy_to_user((void *)ioarg, &support_list,
sizeof(uint16_t)))
return -EFAULT;
@@ -1058,11 +1060,12 @@
}
}
driver->data_ready[index] ^= DCI_DATA_TYPE;
- driver->smd_dci[SMD_MODEM_INDEX].in_busy_1 = 0;
- if (driver->smd_dci[SMD_MODEM_INDEX].ch)
- queue_work(driver->diag_dci_wq,
- &(driver->smd_dci[SMD_MODEM_INDEX].
- diag_read_smd_work));
+ for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) {
+ driver->smd_dci[i].in_busy_1 = 0;
+ if (driver->smd_dci[i].ch)
+ queue_work(driver->diag_dci_wq,
+ &(driver->smd_dci[i].diag_read_smd_work));
+ }
goto exit;
}
exit:
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index bc9d3fa..6b4c337 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -54,7 +54,7 @@
void encode_rsp_and_send(int buf_length)
{
- struct diag_smd_info *data = &(driver->smd_data[SMD_MODEM_INDEX]);
+ struct diag_smd_info *data = &(driver->smd_data[MODEM_DATA]);
send.state = DIAG_STATE_START;
send.pkt = driver->apps_rsp_buf;
send.last = (void *)(driver->apps_rsp_buf + buf_length);
@@ -67,7 +67,7 @@
data->write_ptr_1->length = (int)(enc.dest -
(void *)(data->buf_in_1));
data->in_busy_1 = 1;
- diag_device_write(data->buf_in_1, MODEM_DATA,
+ diag_device_write(data->buf_in_1, data->peripheral,
data->write_ptr_1);
memset(driver->apps_rsp_buf, '\0', APPS_BUF_SIZE);
}
@@ -178,7 +178,7 @@
* has registered to respond for polling
*/
return 1;
- else if (!(driver->smd_data[SMD_MODEM_INDEX].ch) &&
+ else if (!(driver->smd_data[MODEM_DATA].ch) &&
!(chk_apps_master()))
/*
* If the apps processor is not the master and the modem
@@ -240,25 +240,9 @@
}
if (write_ptr_modem) {
- int data_type;
- switch (smd_info->peripheral) {
- case MODEM_PROC:
- data_type = MODEM_DATA;
- break;
- case LPASS_PROC:
- data_type = LPASS_DATA;
- break;
- case WCNSS_PROC:
- data_type = WCNSS_DATA;
- break;
- default:
- pr_err("diag: In %s, unknown peripheral type: %d\n",
- __func__, smd_info->peripheral);
- return 0;
- }
write_ptr_modem->length = total_recd;
*in_busy_ptr = 1;
- diag_device_write(buf, data_type, write_ptr_modem);
+ diag_device_write(buf, smd_info->peripheral, write_ptr_modem);
}
return 0;
@@ -362,12 +346,12 @@
diag_smd_send_req(smd_info);
}
-int diag_device_write(void *buf, int proc_num, struct diag_request *write_ptr)
+int diag_device_write(void *buf, int data_type, struct diag_request *write_ptr)
{
int i, err = 0;
if (driver->logging_mode == MEMORY_DEVICE_MODE) {
- if (proc_num == APPS_DATA) {
+ if (data_type == APPS_DATA) {
for (i = 0; i < driver->poolsize_write_struct; i++)
if (driver->buf_tbl[i].length == 0) {
driver->buf_tbl[i].buf = buf;
@@ -384,7 +368,7 @@
}
#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
- else if (proc_num == HSIC_DATA) {
+ else if (data_type == HSIC_DATA) {
unsigned long flags;
int foundIndex = -1;
@@ -419,34 +403,22 @@
} else
return -EINVAL;
} else if (driver->logging_mode == NO_LOGGING_MODE) {
- if (proc_num == MODEM_DATA) {
- driver->smd_data[SMD_MODEM_INDEX].in_busy_1 = 0;
- driver->smd_data[SMD_MODEM_INDEX].in_busy_2 = 0;
+ if ((data_type >= 0) && (data_type < NUM_SMD_DATA_CHANNELS)) {
+ driver->smd_data[data_type].in_busy_1 = 0;
+ driver->smd_data[data_type].in_busy_2 = 0;
queue_work(driver->diag_wq,
- &(driver->smd_data[SMD_MODEM_INDEX].
- diag_read_smd_work));
- } else if (proc_num == LPASS_DATA) {
- driver->smd_data[SMD_LPASS_INDEX].in_busy_1 = 0;
- driver->smd_data[SMD_LPASS_INDEX].in_busy_2 = 0;
- queue_work(driver->diag_wq,
- &(driver->smd_data[SMD_LPASS_INDEX].
- diag_read_smd_work));
- } else if (proc_num == WCNSS_DATA) {
- driver->smd_data[SMD_WCNSS_INDEX].in_busy_1 = 0;
- driver->smd_data[SMD_WCNSS_INDEX].in_busy_2 = 0;
- queue_work(driver->diag_wq,
- &(driver->smd_data[SMD_WCNSS_INDEX].
+ &(driver->smd_data[data_type].
diag_read_smd_work));
}
#ifdef CONFIG_DIAG_SDIO_PIPE
- else if (proc_num == SDIO_DATA) {
+ else if (data_type == SDIO_DATA) {
driver->in_busy_sdio = 0;
queue_work(driver->diag_sdio_wq,
&(driver->diag_read_sdio_work));
}
#endif
#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
- else if (proc_num == HSIC_DATA) {
+ else if (data_type == HSIC_DATA) {
if (driver->hsic_ch)
queue_work(diag_bridge[HSIC].wq,
&(driver->diag_read_hsic_work));
@@ -456,7 +428,7 @@
}
#ifdef CONFIG_DIAG_OVER_USB
else if (driver->logging_mode == USB_MODE) {
- if (proc_num == APPS_DATA) {
+ if (data_type == APPS_DATA) {
driver->write_ptr_svc = (struct diag_request *)
(diagmem_alloc(driver, sizeof(struct diag_request),
POOL_TYPE_WRITE_STRUCT));
@@ -467,7 +439,8 @@
driver->write_ptr_svc);
} else
err = -1;
- } else if (proc_num == MODEM_DATA) {
+ } else if ((data_type >= 0) &&
+ (data_type < NUM_SMD_DATA_CHANNELS)) {
write_ptr->buf = buf;
#ifdef DIAG_DEBUG
printk(KERN_INFO "writing data to USB,"
@@ -477,15 +450,9 @@
buf, write_ptr->length, 1);
#endif /* DIAG DEBUG */
err = usb_diag_write(driver->legacy_ch, write_ptr);
- } else if (proc_num == LPASS_DATA) {
- write_ptr->buf = buf;
- err = usb_diag_write(driver->legacy_ch, write_ptr);
- } else if (proc_num == WCNSS_DATA) {
- write_ptr->buf = buf;
- err = usb_diag_write(driver->legacy_ch, write_ptr);
}
#ifdef CONFIG_DIAG_SDIO_PIPE
- else if (proc_num == SDIO_DATA) {
+ else if (data_type == SDIO_DATA) {
if (machine_is_msm8x60_fusion() ||
machine_is_msm8x60_fusn_ffa()) {
write_ptr->buf = buf;
@@ -496,7 +463,7 @@
}
#endif
#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
- else if (proc_num == HSIC_DATA) {
+ else if (data_type == HSIC_DATA) {
if (driver->hsic_device_enabled) {
struct diag_request *write_ptr_mdm;
write_ptr_mdm = (struct diag_request *)
@@ -527,7 +494,7 @@
"while USB write\n");
err = -1;
}
- } else if (proc_num == SMUX_DATA) {
+ } else if (data_type == SMUX_DATA) {
write_ptr->buf = buf;
write_ptr->context = (void *)SMUX;
pr_debug("diag: writing SMUX data\n");
@@ -580,6 +547,15 @@
mutex_unlock(&driver->diagchar_mutex);
}
+static int diag_check_mode_reset(unsigned char *buf)
+{
+ int is_mode_reset = 0;
+ if (chk_apps_master() && (int)(*(char *)buf) == MODE_CMD)
+ if ((int)(*(char *)(buf+1)) == RESET_ID)
+ is_mode_reset = 1;
+ return is_mode_reset;
+}
+
void diag_send_data(struct diag_master_table entry, unsigned char *buf,
int len, int type)
{
@@ -589,25 +565,23 @@
diag_update_sleeping_process(entry.process_id, PKT_TYPE);
} else {
if (len > 0) {
- if (entry.client_id == MODEM_PROC &&
- driver->smd_data[SMD_MODEM_INDEX].ch) {
- if (chk_apps_master() &&
- (int)(*(char *)buf) == MODE_CMD)
- if ((int)(*(char *)(buf+1)) ==
- RESET_ID)
+ if ((entry.client_id >= 0) &&
+ (entry.client_id < NUM_SMD_DATA_CHANNELS)) {
+ int index = entry.client_id;
+ if (driver->smd_data[index].ch) {
+ if ((index == MODEM_DATA) &&
+ diag_check_mode_reset(buf)) {
return;
- smd_write(driver->smd_data[SMD_MODEM_INDEX].ch,
- buf, len);
- } else if (entry.client_id == LPASS_PROC &&
- driver->smd_data[SMD_LPASS_INDEX].ch) {
- smd_write(driver->smd_data[SMD_LPASS_INDEX].ch,
- buf, len);
- } else if (entry.client_id == WCNSS_PROC &&
- driver->smd_data[SMD_WCNSS_INDEX].ch) {
- smd_write(driver->smd_data[SMD_WCNSS_INDEX].ch,
- buf, len);
+ }
+ smd_write(driver->smd_data[index].ch,
+ buf, len);
+ } else {
+ pr_err("diag: In %s, smd channel %d not open\n",
+ __func__, index);
+ }
} else {
- pr_alert("diag: incorrect channel");
+ pr_alert("diag: In %s, incorrect channel: %d",
+ __func__, entry.client_id);
}
}
}
@@ -688,7 +662,7 @@
return 0;
}
/* Check for Apps Only & get event mask request */
- else if (!(driver->smd_data[SMD_MODEM_INDEX].ch) && chk_apps_only() &&
+ else if (!(driver->smd_data[MODEM_DATA].ch) && chk_apps_only() &&
*buf == 0x81) {
driver->apps_rsp_buf[0] = 0x81;
driver->apps_rsp_buf[1] = 0x0;
@@ -700,7 +674,7 @@
return 0;
}
/* Get log ID range & Check for Apps Only */
- else if (!(driver->smd_data[SMD_MODEM_INDEX].ch) && chk_apps_only()
+ else if (!(driver->smd_data[MODEM_DATA].ch) && chk_apps_only()
&& (*buf == 0x73) && *(int *)(buf+4) == 1) {
driver->apps_rsp_buf[0] = 0x73;
*(int *)(driver->apps_rsp_buf + 4) = 0x1; /* operation ID */
@@ -725,7 +699,7 @@
return 0;
}
/* Respond to Get SSID Range request message */
- else if (!(driver->smd_data[SMD_MODEM_INDEX].ch) && chk_apps_only()
+ else if (!(driver->smd_data[MODEM_DATA].ch) && chk_apps_only()
&& (*buf == 0x7d) && (*(buf+1) == 0x1)) {
driver->apps_rsp_buf[0] = 0x7d;
driver->apps_rsp_buf[1] = 0x1;
@@ -783,7 +757,7 @@
return 0;
}
/* Check for Apps Only Respond to Get Subsys Build mask */
- else if (!(driver->smd_data[SMD_MODEM_INDEX].ch) && chk_apps_only()
+ else if (!(driver->smd_data[MODEM_DATA].ch) && chk_apps_only()
&& (*buf == 0x7d) && (*(buf+1) == 0x2)) {
ssid_first = *(uint16_t *)(buf + 2);
ssid_last = *(uint16_t *)(buf + 4);
@@ -1000,12 +974,12 @@
type = 0;
}
/* implies this packet is NOT meant for apps */
- if (!(driver->smd_data[SMD_MODEM_INDEX].ch) && type == 1) {
+ if (!(driver->smd_data[MODEM_DATA].ch) && type == 1) {
if (chk_apps_only()) {
diag_send_error_rsp(hdlc.dest_idx);
} else { /* APQ 8060, Let Q6 respond */
- if (driver->smd_data[SMD_LPASS_INDEX].ch)
- smd_write(driver->smd_data[SMD_LPASS_INDEX].ch,
+ if (driver->smd_data[LPASS_DATA].ch)
+ smd_write(driver->smd_data[LPASS_DATA].ch,
driver->hdlc_buf,
hdlc.dest_idx - 3);
}
@@ -1019,10 +993,10 @@
driver->hdlc_buf)+i));
#endif /* DIAG DEBUG */
/* ignore 2 bytes for CRC, one for 7E and send */
- if ((driver->smd_data[SMD_MODEM_INDEX].ch) && (ret) && (type) &&
+ if ((driver->smd_data[MODEM_DATA].ch) && (ret) && (type) &&
(hdlc.dest_idx > 3)) {
APPEND_DEBUG('g');
- smd_write(driver->smd_data[SMD_MODEM_INDEX].ch,
+ smd_write(driver->smd_data[MODEM_DATA].ch,
driver->hdlc_buf, hdlc.dest_idx - 3);
APPEND_DEBUG('h');
#ifdef DIAG_DEBUG
@@ -1275,7 +1249,7 @@
int index = -1;
if (pdev->id == SMD_APPS_MODEM) {
- index = SMD_MODEM_INDEX;
+ index = MODEM_DATA;
r = smd_open("DIAG", &driver->smd_data[index].ch,
&driver->smd_data[index],
diag_smd_notify);
@@ -1284,7 +1258,7 @@
}
#if defined(CONFIG_MSM_N_WAY_SMD)
if (pdev->id == SMD_APPS_QDSP) {
- index = SMD_LPASS_INDEX;
+ index = LPASS_DATA;
r = smd_named_open_on_edge("DIAG", SMD_APPS_QDSP,
&driver->smd_data[index].ch,
&driver->smd_data[index],
@@ -1294,7 +1268,7 @@
}
#endif
if (pdev->id == SMD_APPS_WCNSS) {
- index = SMD_WCNSS_INDEX;
+ index = WCNSS_DATA;
r = smd_named_open_on_edge("APPS_RIVA_DATA",
SMD_APPS_WCNSS,
&driver->smd_data[index].ch,
@@ -1362,11 +1336,26 @@
}
int diag_smd_constructor(struct diag_smd_info *smd_info, int peripheral,
- int type, uint16_t peripheral_mask)
+ int type)
{
smd_info->peripheral = peripheral;
smd_info->type = type;
- smd_info->peripheral_mask = peripheral_mask;
+
+ switch (peripheral) {
+ case MODEM_DATA:
+ smd_info->peripheral_mask = DIAG_CON_MPSS;
+ break;
+ case LPASS_DATA:
+ smd_info->peripheral_mask = DIAG_CON_LPASS;
+ break;
+ case WCNSS_DATA:
+ smd_info->peripheral_mask = DIAG_CON_WCNSS;
+ break;
+ default:
+ pr_err("diag: In %s, unknown peripheral, peripheral: %d\n",
+ __func__, peripheral);
+ goto err;
+ }
smd_info->ch = 0;
smd_info->ch_save = 0;
@@ -1465,18 +1454,18 @@
driver->use_device_tree = has_device_tree();
mutex_init(&driver->diag_cntl_mutex);
- success = diag_smd_constructor(&driver->smd_data[SMD_MODEM_INDEX],
- MODEM_PROC, SMD_DATA_TYPE, DIAG_CON_MPSS);
+ success = diag_smd_constructor(&driver->smd_data[MODEM_DATA],
+ MODEM_DATA, SMD_DATA_TYPE);
if (!success)
goto err;
- success = diag_smd_constructor(&driver->smd_data[SMD_LPASS_INDEX],
- LPASS_PROC, SMD_DATA_TYPE, DIAG_CON_LPASS);
+ success = diag_smd_constructor(&driver->smd_data[LPASS_DATA],
+ LPASS_DATA, SMD_DATA_TYPE);
if (!success)
goto err;
- success = diag_smd_constructor(&driver->smd_data[SMD_WCNSS_INDEX],
- WCNSS_PROC, SMD_DATA_TYPE, DIAG_CON_WCNSS);
+ success = diag_smd_constructor(&driver->smd_data[WCNSS_DATA],
+ WCNSS_DATA, SMD_DATA_TYPE);
if (!success)
goto err;
diff --git a/drivers/char/diag/diagfwd.h b/drivers/char/diag/diagfwd.h
index b7f4aba..14e2dd5 100644
--- a/drivers/char/diag/diagfwd.h
+++ b/drivers/char/diag/diagfwd.h
@@ -37,7 +37,7 @@
void encode_rsp_and_send(int buf_length);
void diag_smd_notify(void *ctxt, unsigned event);
int diag_smd_constructor(struct diag_smd_info *smd_info, int peripheral,
- int type, uint16_t peripheral_mask);
+ int type);
void diag_smd_destructor(struct diag_smd_info *smd_info);
/* State for diag forwarding */
#ifdef CONFIG_DIAG_OVER_USB
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index 0673635..a900d97 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -96,7 +96,7 @@
temp->cmd_code = msg->cmd_code;
temp->subsys_id = msg->subsysid;
temp->client_id = smd_info->peripheral;
- temp->proc_id = smd_info->peripheral;
+ temp->proc_id = NON_APPS_PROC;
temp->cmd_code_lo = range->cmd_code_lo;
temp->cmd_code_hi = range->cmd_code_hi;
range++;
@@ -133,7 +133,7 @@
/* open control ports only on 8960 & newer targets */
if (chk_apps_only()) {
if (pdev->id == SMD_APPS_MODEM) {
- index = SMD_MODEM_INDEX;
+ index = MODEM_DATA;
r = smd_open("DIAG_CNTL",
&driver->smd_cntl[index].ch,
&driver->smd_cntl[index],
@@ -141,7 +141,7 @@
driver->smd_cntl[index].ch_save =
driver->smd_cntl[index].ch;
} else if (pdev->id == SMD_APPS_QDSP) {
- index = SMD_LPASS_INDEX;
+ index = LPASS_DATA;
r = smd_named_open_on_edge("DIAG_CNTL",
SMD_APPS_QDSP,
&driver->smd_cntl[index].ch,
@@ -150,7 +150,7 @@
driver->smd_cntl[index].ch_save =
driver->smd_cntl[index].ch;
} else if (pdev->id == SMD_APPS_WCNSS) {
- index = SMD_WCNSS_INDEX;
+ index = WCNSS_DATA;
r = smd_named_open_on_edge("APPS_RIVA_CTRL",
SMD_APPS_WCNSS,
&driver->smd_cntl[index].ch,
@@ -211,18 +211,18 @@
driver->polling_reg_flag = 0;
driver->diag_cntl_wq = create_singlethread_workqueue("diag_cntl_wq");
- success = diag_smd_constructor(&driver->smd_cntl[SMD_MODEM_INDEX],
- MODEM_PROC, SMD_CNTL_TYPE, DIAG_CON_MPSS);
+ success = diag_smd_constructor(&driver->smd_cntl[MODEM_DATA],
+ MODEM_DATA, SMD_CNTL_TYPE);
if (!success)
goto err;
- success = diag_smd_constructor(&driver->smd_cntl[SMD_LPASS_INDEX],
- LPASS_PROC, SMD_CNTL_TYPE, DIAG_CON_LPASS);
+ success = diag_smd_constructor(&driver->smd_cntl[LPASS_DATA],
+ LPASS_DATA, SMD_CNTL_TYPE);
if (!success)
goto err;
- success = diag_smd_constructor(&driver->smd_cntl[SMD_WCNSS_INDEX],
- WCNSS_PROC, SMD_CNTL_TYPE, DIAG_CON_WCNSS);
+ success = diag_smd_constructor(&driver->smd_cntl[WCNSS_DATA],
+ WCNSS_DATA, SMD_CNTL_TYPE);
if (!success)
goto err;
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 8f3c107..8a75cd9 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -1160,7 +1160,6 @@
dbs_timer_exit(this_dbs_info);
mutex_lock(&dbs_mutex);
- mutex_destroy(&this_dbs_info->timer_mutex);
dbs_enable--;
/* If device is being removed, policy is no longer
* valid. */
@@ -1239,7 +1238,14 @@
static void __exit cpufreq_gov_dbs_exit(void)
{
+ unsigned int i;
+
cpufreq_unregister_governor(&cpufreq_gov_ondemand);
+ for_each_possible_cpu(i) {
+ struct cpu_dbs_info_s *this_dbs_info =
+ &per_cpu(od_cpu_dbs_info, i);
+ mutex_destroy(&this_dbs_info->timer_mutex);
+ }
destroy_workqueue(input_wq);
}
diff --git a/drivers/gpu/ion/ion_cp_heap.c b/drivers/gpu/ion/ion_cp_heap.c
index 96a3cdc..d96b755 100644
--- a/drivers/gpu/ion/ion_cp_heap.c
+++ b/drivers/gpu/ion/ion_cp_heap.c
@@ -104,6 +104,7 @@
size_t heap_size;
dma_addr_t handle;
int cma;
+ int disallow_non_secure_allocation;
};
enum {
@@ -480,6 +481,13 @@
return ION_CP_ALLOCATE_FAIL;
}
+ if (!secure_allocation && cp_heap->disallow_non_secure_allocation) {
+ mutex_unlock(&cp_heap->lock);
+ pr_debug("%s: non-secure allocation disallowed from this heap\n",
+ __func__);
+ return ION_CP_ALLOCATE_FAIL;
+ }
+
/*
* The check above already checked for non-secure allocations when the
* heap is protected. HEAP_PROTECTED implies that this must be a secure
@@ -1286,6 +1294,8 @@
cp_heap->iommu_2x_map_domain =
extra_data->iommu_2x_map_domain;
cp_heap->cma = extra_data->is_cma;
+ cp_heap->disallow_non_secure_allocation =
+ extra_data->no_nonsecure_alloc;
}
diff --git a/drivers/gpu/ion/ion_iommu_heap.c b/drivers/gpu/ion/ion_iommu_heap.c
index 0b691f3..5483054 100644
--- a/drivers/gpu/ion/ion_iommu_heap.c
+++ b/drivers/gpu/ion/ion_iommu_heap.c
@@ -76,7 +76,8 @@
goto err2;
for_each_sg(table->sgl, sg, table->nents, i) {
- data->pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO);
+ data->pages[i] = alloc_page(
+ GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO);
if (!data->pages[i])
goto err3;
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 55597fc..24be1b0 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -884,8 +884,8 @@
if (adreno_of_read_property(node, "qcom,algo-ss-util-pct",
&info->algo_param.ss_util_pct))
goto err;
- if (adreno_of_read_property(node, "qcom,algo-ss-iobusy-conv",
- &info->algo_param.ss_iobusy_conv))
+ if (adreno_of_read_property(node, "qcom,algo-ss-no-corr-below-freq",
+ &info->algo_param.ss_no_corr_below_freq))
goto err;
if (adreno_of_read_property(node, "qcom,energy-active-coeff-a",
diff --git a/drivers/gud/Kconfig b/drivers/gud/Kconfig
index 3a241b7..929ba01d 100644
--- a/drivers/gud/Kconfig
+++ b/drivers/gud/Kconfig
@@ -3,7 +3,6 @@
#
config MOBICORE_SUPPORT
tristate "Linux MobiCore Support"
- #depends on ARM_TRUSTZONE
---help---
Enable Linux Kernel MobiCore Support
@@ -12,14 +11,14 @@
depends on MOBICORE_SUPPORT
---help---
Enable Debug mode in the MobiCore Driver.
- It enables printing information about mobicore operations
+ It enables printing information about MobiCore operations
config MOBICORE_VERBOSE
bool "MobiCore Module verbose debug mode"
depends on MOBICORE_DEBUG
---help---
Enable Verbose Debug mode in the MobiCore Driver.
- It enables printing extra information about mobicore operations
+ It enables printing extra information about MobiCore operations
Beware: this is only useful for debuging deep in the driver because
it prints too much logs
@@ -29,4 +28,3 @@
depends on MOBICORE_SUPPORT
---help---
Enable Linux Kernel MobiCore API
-
diff --git a/drivers/gud/Makefile b/drivers/gud/Makefile
index ea212c5..3a16bb7 100644
--- a/drivers/gud/Makefile
+++ b/drivers/gud/Makefile
@@ -6,7 +6,11 @@
obj-$(CONFIG_MOBICORE_API) += mckernelapi.o
obj-$(CONFIG_MOBICORE_SUPPORT) += mcdrvmodule.o
-mcdrvmodule-objs := mobicore_driver/logging.o mobicore_driver/main.o
+mcdrvmodule-objs := mobicore_driver/logging.o \
+ mobicore_driver/ops.o \
+ mobicore_driver/mem.o \
+ mobicore_driver/api.o \
+ mobicore_driver/main.o
mckernelapi-objs := mobicore_kernelapi/main.o \
mobicore_kernelapi/clientlib.o \
@@ -15,7 +19,7 @@
mobicore_kernelapi/connection.o
# Release mode by default
-ccflags-y := -DNDEBUG
+ccflags-y := -DNDEBUG -include $(PWD)/$(GUD_ROOT_FOLDER)/mobicore_driver/build_tag.h
ccflags-y += -Wno-declaration-after-statement
ccflags-$(CONFIG_MOBICORE_DEBUG) += -DDEBUG
diff --git a/drivers/gud/mobicore_driver/api.c b/drivers/gud/mobicore_driver/api.c
new file mode 100644
index 0000000..2506bc2
--- /dev/null
+++ b/drivers/gud/mobicore_driver/api.c
@@ -0,0 +1,114 @@
+/* MobiCore driver module.(interface to the secure world SWD)
+ * MobiCore Driver Kernel Module.
+ *
+ * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+
+#include "main.h"
+#include "mem.h"
+#include "debug.h"
+
+
+/*
+ * Map a virtual memory buffer structure to Mobicore
+ * @param instance
+ * @param addr address of the buffer(NB it must be kernel virtual!)
+ * @param len buffer length
+ * @param handle pointer to handle
+ * @param phys_wsm_l2_table pointer to physical L2 table(?)
+ *
+ * @return 0 if no error
+ *
+ */
+int mobicore_map_vmem(struct mc_instance *instance, void *addr,
+ uint32_t len, uint32_t *handle, uint32_t *phys)
+{
+ return mc_register_wsm_l2(instance, (uint32_t)addr, len,
+ handle, phys);
+}
+EXPORT_SYMBOL(mobicore_map_vmem);
+
+/*
+ * Unmap a virtual memory buffer from mobicore
+ * @param instance
+ * @param handle
+ *
+ * @return 0 if no error
+ *
+ */
+int mobicore_unmap_vmem(struct mc_instance *instance, uint32_t handle)
+{
+ return mc_unregister_wsm_l2(instance, handle);
+}
+EXPORT_SYMBOL(mobicore_unmap_vmem);
+
+/*
+ * Free a WSM buffer allocated with mobicore_allocate_wsm
+ * @param instance
+ * @param handle handle of the buffer
+ *
+ * @return 0 if no error
+ *
+ */
+int mobicore_free_wsm(struct mc_instance *instance, uint32_t handle)
+{
+ return mc_free_buffer(instance, handle);
+}
+EXPORT_SYMBOL(mobicore_free_wsm);
+
+
+/*
+ * Allocate WSM for given instance
+ *
+ * @param instance instance
+ * @param requested_size size of the WSM
+ * @param handle pointer where the handle will be saved
+ * @param virt_kernel_addr pointer for the kernel virtual address
+ * @param phys_addr pointer for the physical address
+ *
+ * @return error code or 0 for success
+ */
+int mobicore_allocate_wsm(struct mc_instance *instance,
+ unsigned long requested_size, uint32_t *handle, void **virt_kernel_addr,
+ void **phys_addr)
+{
+ struct mc_buffer *buffer = NULL;
+
+ /* Setup the WSM buffer structure! */
+ if (mc_get_buffer(instance, &buffer, requested_size))
+ return -EFAULT;
+
+ *handle = buffer->handle;
+ *phys_addr = buffer->phys;
+ *virt_kernel_addr = buffer->addr;
+ return 0;
+}
+EXPORT_SYMBOL(mobicore_allocate_wsm);
+
+/*
+ * Initialize a new mobicore API instance object
+ *
+ * @return Instance or NULL if no allocation was possible.
+ */
+struct mc_instance *mobicore_open(void)
+{
+ return mc_alloc_instance();
+}
+EXPORT_SYMBOL(mobicore_open);
+
+/*
+ * Release a mobicore instance object and all objects related to it
+ * @param instance instance
+ * @return 0 if Ok or -E ERROR
+ */
+int mobicore_release(struct mc_instance *instance)
+{
+ return mc_release_instance(instance);
+}
+EXPORT_SYMBOL(mobicore_release);
+
diff --git a/drivers/gud/mobicore_driver/arm.h b/drivers/gud/mobicore_driver/arm.h
new file mode 100644
index 0000000..0cddc0c
--- /dev/null
+++ b/drivers/gud/mobicore_driver/arm.h
@@ -0,0 +1,72 @@
+/*
+ * MobiCore driver module.(interface to the secure world SWD)
+ *
+ * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MC_ARM_H_
+#define _MC_ARM_H_
+
+#include "debug.h"
+
+/*
+ * ARM Trustzone specific masks and modes
+ * Vanilla Linux is unaware of TrustZone extension.
+ * I.e. arch/arm/include/asm/ptrace.h does not define monitor mode.
+ * Also TZ bits in cpuid are not defined, ARM port uses magic numbers,
+ * see arch/arm/kernel/setup.c
+ */
+#define ARM_MONITOR_MODE (0b10110)
+#define ARM_SECURITY_EXTENSION_MASK (0x30)
+
+/* check if CPU supports the ARM TrustZone Security Extensions */
+inline bool has_security_extensions(void)
+{
+ u32 fea = 0;
+ asm volatile(
+ "mrc p15, 0, %[fea], cr0, cr1, 0" :
+ [fea]"=r" (fea));
+
+ MCDRV_DBG_VERBOSE(mcd, "CPU Features: 0x%X", fea);
+
+ /*
+ * If the CPU features ID has 0 for security features then the CPU
+ * doesn't support TrustZone at all!
+ */
+ if ((fea & ARM_SECURITY_EXTENSION_MASK) == 0)
+ return false;
+
+ return true;
+}
+
+/* check if running in secure mode */
+inline bool is_secure_mode(void)
+{
+ u32 cpsr = 0;
+ u32 nsacr = 0;
+
+ asm volatile(
+ "mrc p15, 0, %[nsacr], cr1, cr1, 2\n"
+ "mrs %[cpsr], cpsr\n" :
+ [nsacr]"=r" (nsacr),
+ [cpsr]"=r"(cpsr));
+
+ MCDRV_DBG_VERBOSE(mcd, "CPRS.M = set to 0x%X\n", cpsr & MODE_MASK);
+ MCDRV_DBG_VERBOSE(mcd, "SCR.NS = set to 0x%X\n", nsacr);
+
+ /*
+ * If the NSACR contains the reset value(=0) then most likely we are
+ * running in Secure MODE.
+ * If the cpsr mode is set to monitor mode then we cannot load!
+ */
+ if (nsacr == 0 || ((cpsr & MODE_MASK) == ARM_MONITOR_MODE))
+ return true;
+
+ return false;
+}
+
+#endif /* _MC_ARM_H_ */
diff --git a/drivers/gud/mobicore_driver/build_tag.h b/drivers/gud/mobicore_driver/build_tag.h
index 43541bb..a6898f1 100644
--- a/drivers/gud/mobicore_driver/build_tag.h
+++ b/drivers/gud/mobicore_driver/build_tag.h
@@ -1,6 +1,5 @@
-/**
- *
- * <!-- Copyright Giesecke & Devrient GmbH 2012-2012 -->
+/*
+ * <-- Copyright Giesecke & Devrient GmbH 2012-2012 -->
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -26,4 +25,5 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#define MOBICORE_COMPONENT_BUILD_TAG "*** GC_MSM8960_Release_V010 ###"
+#define MOBICORE_COMPONENT_BUILD_TAG \
+ "*** GC_MSM8960_Release_V013 ###"
diff --git a/drivers/gud/mobicore_driver/debug.h b/drivers/gud/mobicore_driver/debug.h
new file mode 100644
index 0000000..f166605
--- /dev/null
+++ b/drivers/gud/mobicore_driver/debug.h
@@ -0,0 +1,65 @@
+/*
+ * MobiCore driver module.(interface to the secure world SWD)
+ *
+ * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MC_DEBUG_H_
+#define _MC_DEBUG_H_
+/* Found in main.c */
+extern struct device *mcd;
+
+#define MCDRV_DBG_ERROR(dev, txt, ...) \
+ dev_err(dev, "[%d] %s() ### ERROR: " txt, \
+ task_pid_vnr(current), \
+ __func__, \
+ ##__VA_ARGS__)
+
+/* dummy function helper macro. */
+#define DUMMY_FUNCTION() do {} while (0)
+
+#if defined(DEBUG)
+
+/* #define DEBUG_VERBOSE */
+#if defined(DEBUG_VERBOSE)
+#define MCDRV_DBG_VERBOSE MCDRV_DBG
+#else
+#define MCDRV_DBG_VERBOSE(...) DUMMY_FUNCTION()
+#endif
+
+#define MCDRV_DBG(dev, txt, ...) \
+ dev_info(dev, "[%d on CPU%d] %s(): " txt, \
+ task_pid_vnr(current), \
+ raw_smp_processor_id(), \
+ __func__, \
+ ##__VA_ARGS__)
+
+#define MCDRV_DBG_WARN(dev, txt, ...) \
+ dev_warn(dev, "[%d] %s() WARNING: " txt, \
+ task_pid_vnr(current), \
+ __func__, \
+ ##__VA_ARGS__)
+
+#define MCDRV_ASSERT(cond) \
+ do { \
+ if (unlikely(!(cond))) { \
+ panic("Assertion failed: %s:%d\n", \
+ __FILE__, __LINE__); \
+ } \
+ } while (0)
+
+#else
+
+#define MCDRV_DBG_VERBOSE(...) DUMMY_FUNCTION()
+#define MCDRV_DBG(...) DUMMY_FUNCTION()
+#define MCDRV_DBG_WARN(...) DUMMY_FUNCTION()
+
+#define MCDRV_ASSERT(...) DUMMY_FUNCTION()
+
+#endif /* [not] defined(DEBUG) */
+
+#endif /* _MC_DEBUG_H_ */
diff --git a/drivers/gud/mobicore_driver/fastcall.h b/drivers/gud/mobicore_driver/fastcall.h
new file mode 100644
index 0000000..9f360c1
--- /dev/null
+++ b/drivers/gud/mobicore_driver/fastcall.h
@@ -0,0 +1,157 @@
+/*
+ * Header file of MobiCore Driver Kernel Module.
+ *
+ * MobiCore Fast Call interface
+ *
+ * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MC_FASTCALL_H_
+#define _MC_FASTCALL_H_
+
+#include "debug.h"
+
+/*
+ * MobiCore SMCs
+ */
+#define MC_SMC_N_YIELD 0x3 /* Yield to switch from NWd to SWd. */
+#define MC_SMC_N_SIQ 0x4 /* SIQ to switch from NWd to SWd. */
+
+/*
+ * MobiCore fast calls. See MCI documentation
+ */
+#define MC_FC_INIT -1
+#define MC_FC_INFO -2
+#define MC_FC_POWER -3
+#define MC_FC_DUMP -4
+#define MC_FC_NWD_TRACE -31 /* Mem trace setup fastcall */
+
+
+/*
+ * return code for fast calls
+ */
+#define MC_FC_RET_OK 0
+#define MC_FC_RET_ERR_INVALID 1
+#define MC_FC_RET_ERR_ALREADY_INITIALIZED 5
+
+
+/* structure wrappers for specific fastcalls */
+
+/* generic fast call parameters */
+union fc_generic {
+ struct {
+ uint32_t cmd;
+ uint32_t param[3];
+ } as_in;
+ struct {
+ uint32_t resp;
+ uint32_t ret;
+ uint32_t param[2];
+ } as_out;
+};
+
+/* fast call init */
+union mc_fc_init {
+ union fc_generic as_generic;
+ struct {
+ uint32_t cmd;
+ uint32_t base;
+ uint32_t nq_info;
+ uint32_t mcp_info;
+ } as_in;
+ struct {
+ uint32_t resp;
+ uint32_t ret;
+ uint32_t rfu[2];
+ } as_out;
+};
+
+/* fast call info parameters */
+union mc_fc_info {
+ union fc_generic as_generic;
+ struct {
+ uint32_t cmd;
+ uint32_t ext_info_id;
+ uint32_t rfu[2];
+ } as_in;
+ struct {
+ uint32_t resp;
+ uint32_t ret;
+ uint32_t state;
+ uint32_t ext_info;
+ } as_out;
+};
+
+/*
+ * _smc() - fast call to MobiCore
+ *
+ * @data: pointer to fast call data
+ */
+static inline long _smc(void *data)
+{
+ union fc_generic fc_generic;
+ memcpy(&fc_generic, data, sizeof(union fc_generic));
+ if (data == NULL)
+ return -EPERM;
+#ifdef MC_SMC_FASTCALL
+ {
+ int ret = 0;
+ ret = smc_fastcall(data, sizeof(union fc_generic));
+ }
+#else
+ {
+ /* SVC expect values in r0-r3 */
+ register u32 reg0 __asm__("r0") = fc_generic.as_in.cmd;
+ register u32 reg1 __asm__("r1") = fc_generic.as_in.param[0];
+ register u32 reg2 __asm__("r2") = fc_generic.as_in.param[1];
+ register u32 reg3 __asm__("r3") = fc_generic.as_in.param[2];
+
+ __asm__ volatile (
+#ifdef MC_ARCH_EXTENSION_SEC
+ /* This pseudo op is supported and required from
+ * binutils 2.21 on */
+ ".arch_extension sec\n"
+#endif
+ "smc 0\n"
+ : "+r"(reg0), "+r"(reg1), "+r"(reg2), "+r"(reg3)
+ );
+
+ /* set response */
+ fc_generic.as_out.resp = reg0;
+ fc_generic.as_out.ret = reg1;
+ fc_generic.as_out.param[0] = reg2;
+ fc_generic.as_out.param[1] = reg3;
+ memcpy(data, &fc_generic, sizeof(union fc_generic));
+ }
+#endif
+ return 0;
+}
+
+/*
+ * convert fast call return code to linux driver module error code
+ */
+static inline int convert_fc_ret(uint32_t sret)
+{
+ int ret = -EFAULT;
+
+ switch (sret) {
+ case MC_FC_RET_OK:
+ ret = 0;
+ break;
+ case MC_FC_RET_ERR_INVALID:
+ ret = -EINVAL;
+ break;
+ case MC_FC_RET_ERR_ALREADY_INITIALIZED:
+ ret = -EBUSY;
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+#endif /* _MC_FASTCALL_H_ */
diff --git a/drivers/gud/mobicore_driver/logging.c b/drivers/gud/mobicore_driver/logging.c
index eb44c8a..089b91c 100644
--- a/drivers/gud/mobicore_driver/logging.c
+++ b/drivers/gud/mobicore_driver/logging.c
@@ -1,108 +1,104 @@
-/** MobiCore driver module.(interface to the secure world SWD)
- * @addtogroup MCD_MCDIMPL_KMOD_LOGGING MobiCore Driver Logging Subsystem.
- * @ingroup MCD_MCDIMPL_KMOD
- * @{
- * @file
+/*
* MobiCore Driver Logging Subsystem.
- * The logging subsytem provides the interface between the Mobicore trace
+ *
+ * The logging subsystem provides the interface between the Mobicore trace
* buffer and the Linux log
*
- * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-#include "mc_drv_module.h"
-#include "mc_drv_module_linux_api.h"
-#include "mc_drv_module_fastcalls.h"
+#include <linux/miscdevice.h>
+#include <linux/moduleparam.h>
+#include <linux/kthread.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/device.h>
-/* Default len of the log ring buffer 256KB*/
-#define LOG_BUF_SIZE (64 * PAGE_SIZE)
+#include "main.h"
+#include "debug.h"
+#include "ops.h"
+#include "logging.h"
+
+/* Default length of the log ring buffer 256KB*/
+#define LOG_BUF_SIZE (64 * PAGE_SIZE)
/* Max Len of a log line for printing */
-#define LOG_LINE_SIZE 256
+#define LOG_LINE_SIZE 256
static uint32_t log_size = LOG_BUF_SIZE;
-module_param(log_size, uint, 0);
-MODULE_PARM_DESC(log_size, " Size of the MobiCore log ringbuffer "
- "(or 256KB default).");
-/*----------------------------------------------------------------------------*/
+module_param(log_size, uint, 0);
+MODULE_PARM_DESC(log_size, "Size of the MobiCore log ringbuffer(256KB def)");
+
/* Definitions for log version 2 */
-#define LOG_TYPE_MASK (0x0007)
-#define LOG_TYPE_CHAR 0
-#define LOG_TYPE_INTEGER 1
+#define LOG_TYPE_MASK (0x0007)
+#define LOG_TYPE_CHAR 0
+#define LOG_TYPE_INTEGER 1
/* Field length */
-#define LOG_LENGTH_MASK (0x00F8)
-#define LOG_LENGTH_SHIFT 3
+#define LOG_LENGTH_MASK (0x00F8)
+#define LOG_LENGTH_SHIFT 3
/* Extra attributes */
-#define LOG_EOL (0x0100)
-#define LOG_INTEGER_DECIMAL (0x0200)
-#define LOG_INTEGER_SIGNED (0x0400)
+#define LOG_EOL (0x0100)
+#define LOG_INTEGER_DECIMAL (0x0200)
+#define LOG_INTEGER_SIGNED (0x0400)
struct logmsg_struct {
- /* Type and format of data */
- uint16_t ctrl;
- /* Unique value for each event source */
- uint16_t source;
- /* Value, if any */
- uint32_t log_data;
+ uint16_t ctrl; /* Type and format of data */
+ uint16_t source; /* Unique value for each event source */
+ uint32_t log_data; /* Value, if any */
};
-/** MobiCore log previous position */
-static uint32_t log_pos;
-/** MobiCore log buffer structure */
-static struct mc_trace_buf *log_buf;
-/** Log Thread task structure */
-struct task_struct *log_thread;
-/** Log Line buffer */
-static char *log_line;
+static uint32_t log_pos; /* MobiCore log previous position */
+static struct mc_trace_buf *log_buf; /* MobiCore log buffer structure */
+struct task_struct *log_thread; /* Log Thread task structure */
+static char *log_line; /* Log Line buffer */
+static uint32_t log_line_len; /* Log Line buffer current length */
-static void log_msg(struct logmsg_struct *msg);
-
-/*----------------------------------------------------------------------------*/
static void log_eol(void)
{
if (!strnlen(log_line, LOG_LINE_SIZE))
return;
- printk(KERN_INFO "%s\n", log_line);
+ dev_info(mcd, "%s\n", log_line);
+ log_line_len = 0;
log_line[0] = 0;
}
-/*----------------------------------------------------------------------------*/
-/**
- * Put a char to the log line if there is enough space if not then also
- * output the line. Assume nobody else is updating the line! */
+
+/*
+ * Collect chars in log_line buffer and output the buffer when it is full.
+ * No locking needed because only "mobicore_log" thread updates this buffer.
+ */
static void log_char(char ch)
{
- uint32_t len;
if (ch == '\n' || ch == '\r') {
log_eol();
return;
}
- if (strnlen(log_line, LOG_LINE_SIZE) >= LOG_LINE_SIZE - 1) {
- printk(KERN_INFO "%s\n", log_line);
+ if (log_line_len >= LOG_LINE_SIZE - 1) {
+ dev_info(mcd, "%s\n", log_line);
+ log_line_len = 0;
log_line[0] = 0;
}
- len = strnlen(log_line, LOG_LINE_SIZE);
- log_line[len] = ch;
- log_line[len + 1] = 0;
+ log_line[log_line_len] = ch;
+ log_line[log_line_len + 1] = 0;
+ log_line_len++;
}
-/*----------------------------------------------------------------------------*/
-/**
- * Put a string to the log line if there is enough space if not then also
- * output the line. Assume nobody else is updating the line! */
+/*
+ * Put a string to the log line.
+ */
static void log_str(const char *s)
{
int i;
+
for (i = 0; i < strnlen(s, LOG_LINE_SIZE); i++)
log_char(s[i]);
}
-/*----------------------------------------------------------------------------*/
static uint32_t process_v1log(void)
{
char *last_char = log_buf->buff + log_buf->write_pos;
@@ -116,44 +112,28 @@
return buff - log_buf->buff;
}
-/*----------------------------------------------------------------------------*/
-static uint32_t process_v2log(void)
-{
- char *last_msg = log_buf->buff + log_buf->write_pos;
- char *buff = log_buf->buff + log_pos;
- while (buff != last_msg) {
- log_msg((struct logmsg_struct *)buff);
- buff += sizeof(struct logmsg_struct);
- /* Wrap around */
- if (buff + sizeof(struct logmsg_struct) >
- (char *)log_buf + log_size)
- buff = log_buf->buff;
- }
- return buff - log_buf->buff;
-}
+static const uint8_t HEX2ASCII[16] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
-static const uint8_t HEX2ASCII[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
-
-/*----------------------------------------------------------------------------*/
static void dbg_raw_nro(uint32_t format, uint32_t value)
{
int digits = 1;
uint32_t base = (format & LOG_INTEGER_DECIMAL) ? 10 : 16;
int width = (format & LOG_LENGTH_MASK) >> LOG_LENGTH_SHIFT;
- int negative = FALSE;
+ int negative = 0;
uint32_t digit_base = 1;
if ((format & LOG_INTEGER_SIGNED) != 0 && ((signed int)value) < 0) {
- negative = TRUE;
- value = (uint32_t)(-(signed int)value);
- width--;
+ negative = 1;
+ value = (uint32_t)(-(signed int)value);
+ width--;
}
/* Find length and divider to get largest digit */
while (value / digit_base >= base) {
- digit_base *= base;
- digits++;
+ digit_base *= base;
+ digits++;
}
if (width > digits) {
@@ -175,11 +155,11 @@
}
}
-/*----------------------------------------------------------------------------*/
static void log_msg(struct logmsg_struct *msg)
{
unsigned char msgtxt[5];
int mpos = 0;
+
switch (msg->ctrl & LOG_TYPE_MASK) {
case LOG_TYPE_CHAR: {
uint32_t ch;
@@ -203,16 +183,27 @@
log_eol();
}
-/*----------------------------------------------------------------------------*/
+static uint32_t process_v2log(void)
+{
+ char *last_msg = log_buf->buff + log_buf->write_pos;
+ char *buff = log_buf->buff + log_pos;
+ while (buff != last_msg) {
+ log_msg((struct logmsg_struct *)buff);
+ buff += sizeof(struct logmsg_struct);
+ /* Wrap around */
+ if ((buff + sizeof(struct logmsg_struct)) >
+ ((char *)log_buf + log_size))
+ buff = log_buf->buff;
+ }
+ return buff - log_buf->buff;
+}
+
+/* log_worker() - Worker thread processing the log_buf buffer. */
static int log_worker(void *p)
{
if (log_buf == NULL)
return -EFAULT;
- /* The thread should have never started */
- if (log_buf == NULL)
- return -EFAULT;
-
while (!kthread_should_stop()) {
if (log_buf->write_pos == log_pos)
schedule_timeout_interruptible(MAX_SCHEDULE_TIMEOUT);
@@ -225,23 +216,21 @@
log_pos = process_v2log();
break;
default:
- MCDRV_DBG_ERROR("Unknown Mobicore log data "
- "version %d logging disabled.",
- log_buf->version);
+ MCDRV_DBG_ERROR(mcd, "Unknown Mobicore log data");
log_pos = log_buf->write_pos;
- /* Stop the thread as we have no idea what
- * happens next */
+ /*
+ * Stop the thread as we have no idea what
+ * happens next
+ */
return -EFAULT;
}
}
- MCDRV_DBG("Logging thread stopped!");
+ MCDRV_DBG(mcd, "Logging thread stopped!");
return 0;
}
-
-/*----------------------------------------------------------------------------*/
-/**
- * Wakeup the log reader thread
+/*
+ * Wake up the log reader thread
* This should be called from the places where calls into MobiCore have
* generated some logs(eg, yield, SIQ...)
*/
@@ -253,75 +242,89 @@
wake_up_process(log_thread);
}
-/*----------------------------------------------------------------------------*/
-/**
- * Setup mobicore kernel log. It assumes it's running on CORE 0!
+/*
+ * Setup MobiCore kernel log. It assumes it's running on CORE 0!
* The fastcall will complain is that is not the case!
*/
-long mobicore_log_setup(void *data)
+long mobicore_log_setup(void)
{
unsigned long phys_log_buf;
union fc_generic fc_log;
+ struct sched_param param = { .sched_priority = 1 };
+ long ret;
log_pos = 0;
log_buf = NULL;
log_thread = NULL;
log_line = NULL;
+ log_line_len = 0;
/* Sanity check for the log size */
if (log_size < PAGE_SIZE)
return -EFAULT;
else
- log_size =
- get_nr_of_pages_for_buffer(NULL, log_size) * PAGE_SIZE;
+ log_size = PAGE_ALIGN(log_size);
log_line = kzalloc(LOG_LINE_SIZE, GFP_KERNEL);
if (IS_ERR(log_line)) {
- MCDRV_DBG_ERROR("failed to allocate log line!");
+ MCDRV_DBG_ERROR(mcd, "failed to allocate log line!");
return -ENOMEM;
}
log_thread = kthread_create(log_worker, NULL, "mobicore_log");
if (IS_ERR(log_thread)) {
- MCDRV_DBG_ERROR("mobicore log thread creation failed!");
- return -EFAULT;
+ MCDRV_DBG_ERROR(mcd, "MobiCore log thread creation failed!");
+ ret = -EFAULT;
+ goto mobicore_log_setup_log_line;
}
- log_pos = 0;
+ sched_setscheduler(log_thread, SCHED_IDLE, ¶m);
+ /*
+ * We are going to map this buffer into virtual address space in SWd.
+ * To reduce complexity there, we use a contiguous buffer.
+ */
log_buf = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
- size_to_order(log_size));
+ get_order(log_size));
if (!log_buf) {
- MCDRV_DBG_ERROR("Failed to get page for logger!");
- return -ENOMEM;
+ MCDRV_DBG_ERROR(mcd, "Failed to get page for logger!");
+ ret = -ENOMEM;
+ goto mobicore_log_setup_kthread;
}
phys_log_buf = virt_to_phys(log_buf);
memset(&fc_log, 0, sizeof(fc_log));
- fc_log.as_in.cmd = MC_FC_NWD_TRACE;
+ fc_log.as_in.cmd = MC_FC_NWD_TRACE;
fc_log.as_in.param[0] = phys_log_buf;
fc_log.as_in.param[1] = log_size;
- MCDRV_DBG("fc_log virt=%p phys=%p ", log_buf, (void *)phys_log_buf);
+ MCDRV_DBG(mcd, "fc_log virt=%p phys=%p ",
+ log_buf, (void *)phys_log_buf);
mc_fastcall(&fc_log);
- MCDRV_DBG("fc_log out ret=0x%08x", fc_log.as_out.ret);
+ MCDRV_DBG(mcd, "fc_log out ret=0x%08x", fc_log.as_out.ret);
+
/* If the setup failed we must free the memory allocated */
if (fc_log.as_out.ret) {
- MCDRV_DBG_ERROR("MobiCore shared traces setup failed!");
- kthread_stop(log_thread);
- free_pages((unsigned long)log_buf, size_to_order(log_size));
-
+ MCDRV_DBG_ERROR(mcd, "MobiCore shared traces setup failed!");
+ free_pages((unsigned long)log_buf, get_order(log_size));
log_buf = NULL;
- log_thread = NULL;
- return -EIO;
+ ret = -EIO;
+ goto mobicore_log_setup_kthread;
}
- MCDRV_DBG("fc_log Logger version %u\n", log_buf->version);
+ MCDRV_DBG(mcd, "fc_log Logger version %u\n", log_buf->version);
return 0;
+
+mobicore_log_setup_kthread:
+ kthread_stop(log_thread);
+ log_thread = NULL;
+mobicore_log_setup_log_line:
+ kfree(log_line);
+ log_line = NULL;
+ return ret;
}
-/*----------------------------------------------------------------------------*/
-/**
- * Free kernel log componenets.
+/*
+ * Free kernel log components.
* ATTN: We can't free the log buffer because it's also in use by MobiCore and
* even if the module is unloaded MobiCore is still running.
*/
diff --git a/drivers/gud/mobicore_driver/logging.h b/drivers/gud/mobicore_driver/logging.h
new file mode 100644
index 0000000..ec7587f
--- /dev/null
+++ b/drivers/gud/mobicore_driver/logging.h
@@ -0,0 +1,27 @@
+/*
+ * MobiCore driver module.(interface to the secure world SWD)
+ *
+ * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MC_LOGGING_H_
+#define _MC_LOGGING_H_
+
+/* MobiCore internal trace buffer structure. */
+struct mc_trace_buf {
+ uint32_t version; /* version of trace buffer */
+ uint32_t length; /* length of allocated buffer(includes header) */
+ uint32_t write_pos; /* last write position */
+ char buff[1]; /* start of the log buffer */
+};
+
+/* MobiCore internal trace log setup. */
+void mobicore_log_read(void);
+long mobicore_log_setup(void);
+void mobicore_log_free(void);
+
+#endif /* _MC_LOGGING_H_ */
diff --git a/drivers/gud/mobicore_driver/main.c b/drivers/gud/mobicore_driver/main.c
index 8a8ea1e..1a745b3 100644
--- a/drivers/gud/mobicore_driver/main.c
+++ b/drivers/gud/mobicore_driver/main.c
@@ -1,1969 +1,626 @@
-/** MobiCore driver module.(interface to the secure world SWD)
- * @addtogroup MCD_MCDIMPL_KMOD_IMPL
- * @{
- * @file
+/*
* MobiCore Driver Kernel Module.
- * This module is written as a Linux device driver.
+ *
* This driver represents the command proxy on the lowest layer, from the
* secure world to the non secure world, and vice versa.
- * This driver is located in the non secure world (Linux).
+
* This driver offers IOCTL commands, for access to the secure world, and has
* the interface from the secure world to the normal world.
* The access to the driver is possible with a file descriptor,
- * which has to be created by the fd = open(/dev/mobicore) command.
+ * which has to be created by the fd = open(/dev/mobicore) command or
+ * fd = open(/dev/mobicore-user)
*
- * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-
+#include <linux/miscdevice.h>
+#include <linux/interrupt.h>
+#include <linux/highmem.h>
+#include <linux/slab.h>
+#include <linux/kthread.h>
+#include <linux/device.h>
#include <linux/module.h>
-#include "mc_drv_module.h"
-#include "mc_drv_module_linux_api.h"
-#include "mc_drv_module_android.h"
-#include "mc_drv_module_fastcalls.h"
-#include "public/mc_kernel_api.h"
+#include <linux/ioctl.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/completion.h>
-/* Initial value for the daemon sempahore signaling */
-#define DAEMON_SEM_VAL 0
+#include "main.h"
+#include "fastcall.h"
-/** MobiCore interrupt context data */
-static struct mc_drv_kmod_ctx mc_drv_kmod_ctx;
+#include "arm.h"
+#include "mem.h"
+#include "ops.h"
+#include "pm.h"
+#include "debug.h"
+#include "logging.h"
-/** MobiCore MCI information */
-static uint32_t mci_base;
-/*
-#############################################################################
-##
-## Convenience functions for Linux API functions
-##
-#############################################################################*/
-static int goto_cpu0(void);
-static int goto_all_cpu(void) __attribute__ ((unused));
+/* Define a MobiCore device structure for use with dev_debug() etc */
+struct device_driver mcd_debug_name = {
+ .name = "mcdrvkmod"
+};
+struct device mcd_debug_subname = {
+ .init_name = "", /* Set to 'mcd' at mc_init() time */
+ .driver = &mcd_debug_name
+};
-/*----------------------------------------------------------------------------*/
-static void init_and_add_to_list(
- struct list_head *item,
- struct list_head *list_head
-)
+struct device *mcd = &mcd_debug_subname;
+
+/* MobiCore interrupt context data */
+struct mc_context ctx;
+
+/* Get process context from file pointer */
+static struct mc_instance *get_instance(struct file *file)
{
- INIT_LIST_HEAD(item);
-
- list_add(item, list_head);
+ return (struct mc_instance *)(file->private_data);
}
-/*----------------------------------------------------------------------------*/
-/** check if CPU supports the ARM TrustZone Security Extensions
- * @return int TRUE or FALSE */
-static int has_security_extensions(
- void
-)
+/* Get a unique ID */
+unsigned int get_unique_id(void)
{
- u32 fea = 0;
- asm volatile(
- "mrc p15, 0, %[fea], cr0, cr1, 0" :
- [fea]"=r" (fea));
+ return (unsigned int)atomic_inc_return(&ctx.unique_counter);
+}
- MCDRV_DBG_VERBOSE("CPU Features: 0x%X", fea);
+/* Clears the reserved bit of each page and frees the pages */
+static inline void free_continguous_pages(void *addr, unsigned int order)
+{
+ int i;
+ struct page *page = virt_to_page(addr);
+ for (i = 0; i < (1<<order); i++) {
+ MCDRV_DBG_VERBOSE(mcd, "free page at 0x%p\n", page);
+ ClearPageReserved(page);
+ page++;
+ }
- /* If the CPU features ID has 0 for security features then the CPU
- * doesn't support TrustZone at all!
- */
- if ((fea & ARM_SECURITY_EXTENSION_MASK) == 0)
+ MCDRV_DBG_VERBOSE(mcd, "freeing addr:%p, order:%x\n", addr, order);
+ free_pages((unsigned long)addr, order);
+}
+
+/* Frees the memory associated with a buffer */
+static int free_buffer(struct mc_buffer *buffer)
+{
+ if (buffer->handle == 0)
+ return -EINVAL;
+
+ if (buffer->addr == 0)
+ return -EINVAL;
+
+ if (!atomic_dec_and_test(&buffer->usage)) {
+
+ MCDRV_DBG_VERBOSE(mcd, "Could not free buffer h=%u",
+ buffer->handle);
+ return 0;
+ }
+
+ MCDRV_DBG(mcd, "handle=%u phys_addr=0x%p, virt_addr=0x%p\n",
+ buffer->handle, buffer->phys, buffer->addr);
+
+ list_del(&buffer->list);
+
+ free_continguous_pages(buffer->addr, buffer->order);
+ kfree(buffer);
+ return 0;
+}
+
+static uint32_t mc_find_cont_wsm(struct mc_instance *instance, uint32_t handle,
+ uint32_t *phys, uint32_t *len)
+{
+ int ret = 0;
+ struct mc_buffer *buffer;
+
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
+
+ if (WARN_ON(!is_daemon(instance))) {
+ MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n");
+ return -EPERM;
+ }
+
+ mutex_lock(&instance->lock);
+
+ mutex_lock(&ctx.bufs_lock);
+
+ /* search for the given handle in the buffers list */
+ list_for_each_entry(buffer, &ctx.cont_bufs, list) {
+ if (buffer->handle == handle) {
+ *phys = (uint32_t)buffer->phys;
+ *len = buffer->len;
+ goto found;
+ }
+ }
+
+ /* Couldn't find the buffer */
+ ret = -EINVAL;
+
+found:
+ mutex_unlock(&ctx.bufs_lock);
+ mutex_unlock(&instance->lock);
+
+ return ret;
+}
+
+/*
+ * __free_buffer - Free a WSM buffer allocated with mobicore_allocate_wsm
+ *
+ * @instance
+ * @handle handle of the buffer
+ *
+ * Returns 0 if no error
+ *
+ */
+static int __free_buffer(struct mc_instance *instance, uint32_t handle)
+{
+ int ret = 0;
+ struct mc_buffer *buffer;
+
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
+
+ mutex_lock(&ctx.bufs_lock);
+ /* search for the given handle in the buffers list */
+ list_for_each_entry(buffer, &ctx.cont_bufs, list) {
+ if (buffer->handle == handle)
+ goto del_buffer;
+ }
+ ret = -EINVAL;
+ goto err;
+
+del_buffer:
+ ret = free_buffer(buffer);
+err:
+ mutex_unlock(&ctx.bufs_lock);
+ return ret;
+}
+
+int mc_free_buffer(struct mc_instance *instance, uint32_t handle)
+{
+ int ret = 0;
+
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
+
+ mutex_lock(&instance->lock);
+
+ ret = __free_buffer(instance, handle);
+ mutex_unlock(&instance->lock);
+ return ret;
+}
+
+
+int mc_get_buffer(struct mc_instance *instance,
+ struct mc_buffer **buffer, unsigned long len)
+{
+ struct mc_buffer *cbuffer = NULL;
+ void *addr = 0;
+ void *phys = 0;
+ unsigned int order;
+ unsigned long allocated_size;
+ int ret = 0;
+
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
+
+ if (len == 0) {
+ MCDRV_DBG_WARN(mcd, "cannot allocate size 0\n");
+ return -ENOMEM;
+ }
+
+ order = get_order(len);
+ if (order > MAX_ORDER) {
+ MCDRV_DBG_WARN(mcd, "Buffer size too large\n");
+ return -ENOMEM;
+ }
+ allocated_size = (1 << order) * PAGE_SIZE;
+
+ if (mutex_lock_interruptible(&instance->lock))
+ return -ERESTARTSYS;
+
+ /* allocate a new buffer. */
+ cbuffer = kzalloc(sizeof(struct mc_buffer), GFP_KERNEL);
+
+ if (cbuffer == NULL) {
+ MCDRV_DBG_WARN(mcd,
+ "MMAP_WSM request: could not allocate buffer\n");
+ ret = -ENOMEM;
+ goto unlock_instance;
+ }
+ mutex_lock(&ctx.bufs_lock);
+
+ MCDRV_DBG_VERBOSE(mcd, "size %ld -> order %d --> %ld (2^n pages)\n",
+ len, order, allocated_size);
+
+ addr = (void *)__get_free_pages(GFP_USER | __GFP_ZERO, order);
+
+ if (addr == NULL) {
+ MCDRV_DBG_WARN(mcd, "get_free_pages failed\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+ phys = (void *)virt_to_phys(addr);
+ cbuffer->handle = get_unique_id();
+ cbuffer->phys = phys;
+ cbuffer->addr = addr;
+ cbuffer->order = order;
+ cbuffer->len = len;
+ cbuffer->instance = instance;
+ /* Refcount +1 because the TLC is requesting it */
+ atomic_set(&cbuffer->usage, 1);
+
+ INIT_LIST_HEAD(&cbuffer->list);
+ list_add(&cbuffer->list, &ctx.cont_bufs);
+
+ MCDRV_DBG(mcd,
+ "allocated phys=0x%p - 0x%p, size=%ld, kvirt=0x%p, h=%d\n",
+ phys, (void *)((unsigned int)phys+allocated_size),
+ allocated_size, addr, cbuffer->handle);
+ *buffer = cbuffer;
+ goto unlock;
+
+err:
+ kfree(cbuffer);
+unlock:
+ mutex_unlock(&ctx.bufs_lock);
+unlock_instance:
+ mutex_unlock(&instance->lock);
+ return ret;
+}
+
+/*
+ * __lock_buffer() - Locks a contiguous buffer - +1 refcount.
+ * Assumes the instance lock is already taken!
+ */
+static int __lock_buffer(struct mc_instance *instance, uint32_t handle)
+{
+ int ret = 0;
+ struct mc_buffer *buffer;
+
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
+
+ if (WARN_ON(!is_daemon(instance))) {
+ MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n");
+ return -EPERM;
+ }
+
+ mutex_lock(&ctx.bufs_lock);
+ /* search for the given handle in the buffers list */
+ list_for_each_entry(buffer, &ctx.cont_bufs, list) {
+ if (buffer->handle == handle) {
+ atomic_inc(&buffer->usage);
+ goto unlock;
+ }
+ }
+ ret = -EINVAL;
+
+unlock:
+ mutex_unlock(&ctx.bufs_lock);
+ return ret;
+}
+
+void *get_mci_base_phys(unsigned int len)
+{
+ if (ctx.mci_base.phys) {
+ return ctx.mci_base.phys;
+ } else {
+ unsigned int order = get_order(len);
+ ctx.mcp = NULL;
+ ctx.mci_base.order = order;
+ ctx.mci_base.addr =
+ (void *)__get_free_pages(GFP_USER | __GFP_ZERO, order);
+ if (ctx.mci_base.addr == NULL) {
+ MCDRV_DBG_WARN(mcd, "get_free_pages failed\n");
+ memset(&ctx.mci_base, 0, sizeof(ctx.mci_base));
+ return NULL;
+ }
+ ctx.mci_base.phys = (void *)virt_to_phys(ctx.mci_base.addr);
+ return ctx.mci_base.phys;
+ }
+}
+
+/*
+ * Create a l2 table from a virtual memory buffer which can be vmalloc
+ * or user space virtual memory
+ */
+int mc_register_wsm_l2(struct mc_instance *instance,
+ uint32_t buffer, uint32_t len,
+ uint32_t *handle, uint32_t *phys)
+{
+ int ret = 0;
+ struct mc_l2_table *table = NULL;
+ struct task_struct *task = current;
+
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
+
+ if (len == 0) {
+ MCDRV_DBG_ERROR(mcd, "len=0 is not supported!\n");
+ return -EINVAL;
+ }
+
+ table = mc_alloc_l2_table(instance, task, (void *)buffer, len);
+
+ if (IS_ERR(table)) {
+ MCDRV_DBG_ERROR(mcd, "new_used_l2_table() failed\n");
+ return -EINVAL;
+ }
+
+ /* set response */
+ *handle = table->handle;
+ /* WARNING: daemon shouldn't know this either, but live with it */
+ if (is_daemon(instance))
+ *phys = (uint32_t)table->phys;
+ else
+ *phys = 0;
+
+ MCDRV_DBG_VERBOSE(mcd, "handle: %d, phys=%p\n",
+ *handle, (void *)*phys);
+
+ MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret);
+
+ return ret;
+}
+
+int mc_unregister_wsm_l2(struct mc_instance *instance, uint32_t handle)
+{
+ int ret = 0;
+
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
+
+ /* free table (if no further locks exist) */
+ mc_free_l2_table(instance, handle);
+
+ return ret;
+}
+/* Lock the object from handle, it could be a WSM l2 table or a cont buffer! */
+static int mc_lock_handle(struct mc_instance *instance, uint32_t handle)
+{
+ int ret = 0;
+
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
+
+ if (WARN_ON(!is_daemon(instance))) {
+ MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n");
+ return -EPERM;
+ }
+
+ mutex_lock(&instance->lock);
+ ret = mc_lock_l2_table(instance, handle);
+
+ /* Handle was not a l2 table but a cont buffer */
+ if (ret == -EINVAL) {
+ /* Call the non locking variant! */
+ ret = __lock_buffer(instance, handle);
+ }
+
+ mutex_unlock(&instance->lock);
+
+ return ret;
+}
+
+static int mc_unlock_handle(struct mc_instance *instance, uint32_t handle)
+{
+ int ret = 0;
+
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
+
+ if (WARN_ON(!is_daemon(instance))) {
+ MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n");
+ return -EPERM;
+ }
+
+ mutex_lock(&instance->lock);
+ ret = mc_free_l2_table(instance, handle);
+
+ /* Not a l2 table, then it must be a buffer */
+ if (ret == -EINVAL) {
+ /* Call the non locking variant! */
+ ret = __free_buffer(instance, handle);
+ }
+ mutex_unlock(&instance->lock);
+
+ return ret;
+}
+
+static uint32_t mc_find_wsm_l2(struct mc_instance *instance, uint32_t handle)
+{
+ uint32_t ret = 0;
+
+ if (WARN(!instance, "No instance data available"))
return 0;
- return 1;
+ if (WARN_ON(!is_daemon(instance))) {
+ MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n");
+ return 0;
+ }
+
+ mutex_lock(&instance->lock);
+ ret = mc_find_l2_table(instance, handle);
+ mutex_unlock(&instance->lock);
+
+ return ret;
}
-/*----------------------------------------------------------------------------*/
-/** check if running in secure mode
- * @return int TRUE or FALSE */
-static int is_secure_mode(
- void
-)
+static int mc_clean_wsm_l2(struct mc_instance *instance)
{
- u32 cpsr = 0, nsacr = 0;
- asm volatile(
- "mrc p15, 0, %[nsacr], cr1, cr1, 2\n"
- "mrs %[cpsr], cpsr\n" :
- [nsacr]"=r" (nsacr),
- [cpsr]"=r"(cpsr));
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
- MCDRV_DBG_VERBOSE("CPRS.M = set to 0x%X\n", cpsr & ARM_CPSR_MASK);
- MCDRV_DBG_VERBOSE("SCR.NS = set to 0x%X\n", nsacr);
+ if (WARN_ON(!is_daemon(instance))) {
+ MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n");
+ return -EPERM;
+ }
- /* If the NSACR contains the reset value(=0) then most likely we are
- * running in Secure MODE.
- * If the cpsr mode is set to monitor mode then we cannot load!
- */
- if (nsacr == 0 || ((cpsr & ARM_CPSR_MASK) == ARM_MONITOR_MODE))
- return 1;
+ mc_clean_l2_tables();
return 0;
}
-/*----------------------------------------------------------------------------*/
-/** check if userland caller is privileged (aka has "root" access rights).
- @return int TRUE or FALSE */
-static int is_userland_caller_privileged(
- void
-) {
- /* For some platforms we cannot run the Daemon as root - for Android
- * compliance tests it is not allowed, thus we assume the daemon is ran
- * as the system user.
- * In Android the system user for daemons has no particular capabilities
- * other than a fixed UID: AID_SYSTEM 1000
- * The actual number is guaranteed to be the same in all Android systems
- * so we will take it for granted: see android_filesystem_config.h in
- * the Android source tree for all UIDs and their meaning:
- * http://android-dls.com/wiki/index.php?title=Android_UIDs_and_GIDs
- */
-#ifdef MC_ANDROID_UID_CHECK
- return current_euid() <= AID_SYSTEM;
-#else
- /* capable should cover all possibilities, root or sudo, uid checking
- * was not very reliable */
- return capable(CAP_SYS_ADMIN);
-#endif
-}
-
-
-
-/*----------------------------------------------------------------------------*/
-static void unlock_page_from_used_l2_table(
- struct page *page
-){
- /* REV axh: check if we should do this. */
- SetPageDirty(page);
-
- /* release page, old api was page_cache_release() */
- ClearPageReserved(page);
- put_page(page);
-}
-
-/*----------------------------------------------------------------------------*/
-/* convert L2 PTE to page pointer */
-static struct page *l2_pte_to_page(
- pte_t pte
-) {
- void *phys_page_addr = (void *)((unsigned int)pte & PAGE_MASK);
- unsigned int pfn = addr_to_pfn(phys_page_addr);
- struct page *page = pfn_to_page(pfn);
- return page;
-}
-
-/*----------------------------------------------------------------------------*/
-/* convert page pointer to L2 PTE */
-static pte_t page_to_l2_pte(
- struct page *page
-)
+static int mc_fd_mmap(struct file *file, struct vm_area_struct *vmarea)
{
- unsigned int pfn = page_to_pfn(page);
- void *phys_addr = pfn_to_addr(pfn);
- pte_t pte = (pte_t)((unsigned int)phys_addr & PAGE_MASK);
- return pte;
-}
-
-
-/*----------------------------------------------------------------------------*/
-static inline int lock_user_pages(
- struct task_struct *task,
- void *virt_start_page_addr,
- int nr_of_pages,
- struct page **pages
-)
-{
- int ret = 0;
- int locked_pages = 0;
- unsigned int i;
-
- do {
-
- /* lock user pages, must hold the mmap_sem to do this. */
- down_read(&(task->mm->mmap_sem));
- locked_pages = get_user_pages(
- task,
- task->mm,
- (unsigned long)virt_start_page_addr,
- nr_of_pages,
- 1, /* write access */
- 0, /* they say drivers should always
- pass 0 here..... */
- pages,
- NULL); /* we don't need the VMAs */
- up_read(&(task->mm->mmap_sem));
-
- /* could as lock all pages? */
- if (locked_pages != nr_of_pages) {
- MCDRV_DBG_ERROR(
- "get_user_pages() failed, "
- "locked_pages=%d\n",
- locked_pages);
- ret = -ENOMEM;
- /* check if an error has been returned. */
- if (locked_pages < 0) {
- ret = locked_pages;
- locked_pages = 0;
- }
- break;
- }
-
- /* do cache maintenance on locked pages. */
- for (i = 0; i < nr_of_pages; i++)
- flush_dcache_page(pages[i]);
-
- } while (FALSE);
-
-
- if (ret != 0) {
- /* release all locked pages. */
- MCDRV_ASSERT(locked_pages >= 0);
- for (i = 0; i < locked_pages; i++)
- put_page(pages[i]);
- }
-
- return ret;
-
-}
-
-/*
-#############################################################################
-##
-## Driver implementation functions
-##
-#############################################################################*/
-/*----------------------------------------------------------------------------*/
-/* check if caller is MobiCore Daemon */
-static unsigned int is_caller_mc_daemon(
- struct mc_instance *instance
-)
-{
- return ((instance != NULL)
- && (mc_drv_kmod_ctx.daemon_inst == instance));
-}
-
-
-/*----------------------------------------------------------------------------*/
-/* Get process context from file pointer */
-static struct mc_instance *get_instance(
- struct file *file
-) {
- MCDRV_ASSERT(file != NULL);
-
- return (struct mc_instance *)(file->private_data);
-}
-
-
-/*----------------------------------------------------------------------------*/
-/* Get a unique ID */
-static unsigned int get_mc_kmod_unique_id(
- void
-)
-{
- return (unsigned int)atomic_inc_return(
- &(mc_drv_kmod_ctx.unique_counter));
-}
-
-
-/*----------------------------------------------------------------------------*/
-/* Get kernel pointer to shared L2 table given a per-process reference */
-static struct l2table *get_l2_table_kernel_virt(
- struct mc_used_l2_table *used_l2table
-)
-{
- MCDRV_ASSERT(used_l2table != NULL);
- MCDRV_ASSERT(used_l2table->set != NULL);
- MCDRV_ASSERT(used_l2table->set->kernel_virt != NULL);
- return &(used_l2table->set->kernel_virt->table[used_l2table->idx]);
-}
-
-/*----------------------------------------------------------------------------*/
-/* Get physical address of a shared L2 table given a per-process reference */
-static struct l2table *get_l2_table_phys(
- struct mc_used_l2_table *used_l2table
-)
-{
- MCDRV_ASSERT(used_l2table != NULL);
- MCDRV_ASSERT(used_l2table->set != NULL);
- MCDRV_ASSERT(used_l2table->set->phys != NULL);
- return &(used_l2table->set->phys->table[used_l2table->idx]);
-}
-
-/*----------------------------------------------------------------------------*/
-static unsigned int is_in_use_used_l2_table(
- struct mc_used_l2_table *used_l2table
-)
-{
- return ((used_l2table->flags &
- (MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_APP
- | MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC)) != 0);
-}
-
-
-
-/*----------------------------------------------------------------------------*/
-static struct mc_used_l2_table *find_used_l2_table_by_handle(
- unsigned int handle
-) {
- struct mc_used_l2_table *used_l2table;
- struct mc_used_l2_table *used_l2table_with_handle = NULL;
-
- list_for_each_entry(
- used_l2table,
- &(mc_drv_kmod_ctx.mc_used_l2_tables),
- list
- ) {
- if (handle == used_l2table->handle) {
- used_l2table_with_handle = used_l2table;
- break;
- }
- }
-
- return used_l2table_with_handle;
-}
-
-/*
-#############################################################################
-##
-## L2 Table Pool
-##
-#############################################################################*/
-
-/*----------------------------------------------------------------------------*/
-static struct mc_used_l2_table *allocate_used_l2_table(
- struct mc_instance *instance
-) {
- int ret = 0;
- struct mc_l2_table_store *l2table_store = NULL;
- struct mc_l2_tables_set *l2table_set = NULL;
- struct mc_used_l2_table *used_l2table = NULL;
- struct page *page;
- unsigned int i = 0;
-
- do {
- /* allocate a WSM L2 descriptor */
- used_l2table = kmalloc(sizeof(*used_l2table), GFP_KERNEL);
- if (used_l2table == NULL) {
- ret = -ENOMEM;
- MCDRV_DBG_ERROR("out of memory\n");
- break;
- }
- /* clean */
- memset(used_l2table, 0, sizeof(*used_l2table));
- used_l2table->handle = get_mc_kmod_unique_id();
- used_l2table->owner = instance;
-
- /* add to global list. */
- init_and_add_to_list(
- &(used_l2table->list),
- &(mc_drv_kmod_ctx.mc_used_l2_tables));
-
- /* walk though list to find free set. */
- list_for_each_entry(
- l2table_set,
- &(mc_drv_kmod_ctx.mc_l2_tables_sets),
- list
- ) {
- for (i = 0; i < MC_DRV_KMOD_L2_TABLE_PER_PAGES; i++) {
- if ((l2table_set->usage_bitmap & (1U << i))
- == 0) {
- /* found a set,
- l2table_set and i are set. */
- l2table_store =
- l2table_set->kernel_virt;
- break;
- }
- }
- if (l2table_store != NULL)
- break;
- } /* end while */
-
- if (l2table_store == NULL) {
- l2table_store = (struct mc_l2_table_store *)
- get_zeroed_page(GFP_KERNEL);
- if (l2table_store == NULL) {
- ret = -ENOMEM;
- break;
- }
-
- /* Actually, locking is not necessary, because kernel
- memory is not supposed to get swapped out. But
- we play safe.... */
- page = virt_to_page(l2table_store);
- SetPageReserved(page);
-
- /* allocate a descriptor */
- l2table_set = kmalloc(sizeof(*l2table_set), GFP_KERNEL);
- if (l2table_set == NULL) {
- kfree(l2table_store);
- ret = -ENOMEM;
- break;
- }
- /* initialize */
- memset(l2table_set, 0, sizeof(*l2table_set));
-
- l2table_set->kernel_virt = l2table_store;
- l2table_set->page = page;
- l2table_set->phys = (void *)virt_to_phys(l2table_store);
-
- /* init add to list. */
- init_and_add_to_list(
- &(l2table_set->list),
- &(mc_drv_kmod_ctx.mc_l2_tables_sets));
-
- /* use first table */
- i = 0;
- }
-
- /* set set usage */
- l2table_set->usage_bitmap |= (1U << i);
-
- /* set set reference */
- used_l2table->set = l2table_set;
- used_l2table->idx = i;
-
- MCDRV_DBG_VERBOSE(
- "chunkPhys=%p,idx=%d\n",
- l2table_set->phys, i);
-
- } while (FALSE);
-
- if (ret != 0) {
- if (used_l2table != NULL) {
- /* remove from list */
- list_del(&(l2table_set->list));
- /* free memory */
- kfree(used_l2table);
- used_l2table = NULL;
- }
- }
-
- return used_l2table;
-}
-
-/*----------------------------------------------------------------------------*/
-static void free_used_l2_table(
- struct mc_used_l2_table *used_l2table
-)
-{
- struct mc_l2_tables_set *l2table_set;
- unsigned int idx;
-
- MCDRV_ASSERT(used_l2table != NULL);
-
- l2table_set = used_l2table->set;
- MCDRV_ASSERT(l2table_set != NULL);
-
- /* clean usage flag */
- idx = used_l2table->idx;
- MCDRV_ASSERT(idx < MC_DRV_KMOD_L2_TABLE_PER_PAGES);
- l2table_set->usage_bitmap &= ~(1U << idx);
-
- /* if nobody uses this set, we can release it. */
- if (l2table_set->usage_bitmap == 0) {
- MCDRV_ASSERT(l2table_set->page != NULL);
- ClearPageReserved(l2table_set->page);
-
- MCDRV_ASSERT(l2table_set->kernel_virt != NULL);
- free_page((unsigned long)l2table_set->kernel_virt);
-
- /* remove from list */
- list_del(&(l2table_set->list));
-
- /* free memory */
- kfree(l2table_set);
- }
-
- return;
-}
-
-
-
-/*----------------------------------------------------------------------------*/
-/**
- * Create a L2 table in a WSM container that has been allocates previously.
- *
- * @param task pointer to task owning WSM
- * @param wsm_buffer user space WSM start
- * @param wsm_len WSM length
- * @param used_l2table Pointer to L2 table details
- */
-static int map_buffer_into_used_l2_table(
- struct task_struct *task,
- void *wsm_buffer,
- unsigned int wsm_len,
- struct mc_used_l2_table *used_l2table
-)
-{
- int ret = 0;
- unsigned int i, nr_of_pages;
- void *virt_addr_page;
- struct page *page;
- struct l2table *l2table;
- struct page **l2table_as_array_of_pointers_to_page;
-
- /* task can be null when called from kernel space */
- MCDRV_ASSERT(wsm_buffer != NULL);
- MCDRV_ASSERT(wsm_len != 0);
- MCDRV_ASSERT(used_l2table != NULL);
-
- MCDRV_DBG_VERBOSE("WSM addr=0x%p, len=0x%08x\n", wsm_buffer, wsm_len);
-
- /* Check if called from kernel space wsm_buffer is actually
- * vmalloced or not */
- if (task == NULL && !is_vmalloc_addr(wsm_buffer)) {
- MCDRV_DBG_ERROR("WSM addr is not a vmalloc address");
- return -EINVAL;
- }
-
- l2table = get_l2_table_kernel_virt(used_l2table);
- /* We use the memory for the L2 table to hold the pointer
- and convert them later. This works, as everything comes
- down to a 32 bit value. */
- l2table_as_array_of_pointers_to_page = (struct page **)l2table;
-
- do {
-
- /* no size > 1Mib supported */
- if (wsm_len > SZ_1M) {
- MCDRV_DBG_ERROR("size > 1 MiB\n");
- ret = -EINVAL;
- break;
- }
-
- /* calculate page usage */
- virt_addr_page = get_page_start(wsm_buffer);
- nr_of_pages = get_nr_of_pages_for_buffer(wsm_buffer, wsm_len);
-
-
- MCDRV_DBG_VERBOSE("virt addr pageStart=0x%p,pages=%d\n",
- virt_addr_page,
- nr_of_pages);
-
- /* L2 table can hold max 1MiB in 256 pages. */
- if ((nr_of_pages*PAGE_SIZE) > SZ_1M) {
- MCDRV_DBG_ERROR("WSM paged exceed 1 MiB\n");
- ret = -EINVAL;
- break;
- }
-
- /* Request comes from user space */
- if (task != NULL) {
- /* lock user page in memory, so they do not get swapped
- * out.
- * REV axh:
- * Kernel 2.6.27 added a new get_user_pages_fast()
- * function, maybe it is called fast_gup() in some
- * versions.
- * handle user process doing a fork().
- * Child should not get things.
- * http://osdir.com/ml/linux-media/2009-07/msg00813.html
- * http://lwn.net/Articles/275808/ */
-
- ret = lock_user_pages(
- task,
- virt_addr_page,
- nr_of_pages,
- l2table_as_array_of_pointers_to_page);
- if (ret != 0) {
- MCDRV_DBG_ERROR("lock_user_pages() failed\n");
- break;
- }
- }
- /* Request comes from kernel space(vmalloc buffer) */
- else {
- void *uaddr = wsm_buffer;
- for (i = 0; i < nr_of_pages; i++) {
- page = vmalloc_to_page(uaddr);
- if (!page) {
- MCDRV_DBG_ERROR(
- "vmalloc_to_Page()"
- " failed to map address\n");
- ret = -EINVAL;
- break;
- }
- get_page(page);
- /* Lock the page in memory, it can't be swapped
- * out */
- SetPageReserved(page);
- l2table_as_array_of_pointers_to_page[i] = page;
- uaddr += PAGE_SIZE;
- }
- }
-
- used_l2table->nr_of_pages = nr_of_pages;
- used_l2table->flags |= MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_APP;
-
- /* create L2 Table entries. used_l2table->table contains a list
- of page pointers here. For a proper cleanup we have to ensure
- that the following code either works and used_l2table contains
- a valid L2 table - or fails and used_l2table->table contains the
- list of page pointers. Any mixed contents will make cleanup
- difficult.*/
-
- for (i = 0; i < nr_of_pages; i++) {
- pte_t pte;
- page = l2table_as_array_of_pointers_to_page[i];
-
- /* create L2 table entry, see ARM MMU docu for details
- about flags stored in the lowest 12 bits. As a side
- reference, the Article "ARM's multiply-mapped memory
- mess" found in the collection at at
- http://lwn.net/Articles/409032/ is also worth reading.*/
- pte = page_to_l2_pte(page)
- | L2_FLAG_AP1 | L2_FLAG_AP0
- | L2_FLAG_C | L2_FLAG_B
- | L2_FLAG_SMALL | L2_FLAG_SMALL_XN
- /* Linux uses different mappings for SMP systems(the
- * sharing flag is set for the pte. In order not to
- * confuse things too much in Mobicore make sure the
- * shared buffers have the same flags.
- * This should also be done in SWD side
- */
-#ifdef CONFIG_SMP
- | L2_FLAG_S | L2_FLAG_SMALL_TEX0
-#endif
- ;
-
- l2table->table_entries[i] = pte;
- MCDRV_DBG_VERBOSE("L2 entry %d: 0x%08x\n", i,
- (unsigned int)(pte));
- }
-
- /* ensure rest of table is empty */
- while (i < 255)
- l2table->table_entries[i++] = (pte_t)0;
-
- } while (FALSE);
-
- return ret;
-}
-
-
-/*----------------------------------------------------------------------------*/
-/**
- * Remove a L2 table in a WSM container. Afterwards the container may be
- * released.
- *
- * @param used_l2table Pointer to L2 table details
- */
-
-static void unmap_buffers_from_used_l2_table(
- struct mc_used_l2_table *used_l2table
-)
-{
- unsigned int i;
- struct l2table *l2table;
-
- MCDRV_ASSERT(used_l2table != NULL);
- /* this should not happen, as we have no empty tables. */
- MCDRV_ASSERT(!is_in_use_used_l2_table(used_l2table));
-
- /* found the table, now release the resources. */
- MCDRV_DBG_VERBOSE("clear L2 table, phys_base=%p, nr_of_pages=%d\n",
- get_l2_table_phys(used_l2table),
- used_l2table->nr_of_pages);
-
- l2table = get_l2_table_kernel_virt(used_l2table);
-
- /* release all locked user space pages */
- for (i = 0; i < used_l2table->nr_of_pages; i++) {
- /* convert physical entries from L2 table to page pointers */
- pte_t pte = get_l2_table_kernel_virt(used_l2table)->
- table_entries[i];
- struct page *page = l2_pte_to_page(pte);
- unlock_page_from_used_l2_table(page);
- }
-
- /* remember that all pages have been freed */
- used_l2table->nr_of_pages = 0;
-
- return;
-}
-
-
-/*
-#############################################################################
-##
-## Helper functions
-##
-#############################################################################*/
-/*----------------------------------------------------------------------------*/
-#define FREE_FROM_SWD TRUE
-#define FREE_FROM_NWD FALSE
-/** Delete a used l2 table. */
-static void delete_used_l2_table(
- struct mc_used_l2_table *used_l2table,
- unsigned int is_swd
-)
-{
- if (is_swd) {
- used_l2table->flags &=
- ~MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC;
- } else {
- used_l2table->flags &=
- ~MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_APP;
- used_l2table->owner = NULL;
- }
-
- /* release if Nwd and Swd/MC do no longer use it. */
- if (is_in_use_used_l2_table(used_l2table)) {
- MCDRV_DBG_WARN(
- "WSM L2 table still in use: physBase=%p, "
- "nr_of_pages=%d\n",
- get_l2_table_phys(used_l2table),
- used_l2table->nr_of_pages);
- } else {
- unmap_buffers_from_used_l2_table(used_l2table);
- free_used_l2_table(used_l2table);
-
- list_del(&(used_l2table->list));
-
- kfree(used_l2table);
- }
- return;
-}
-
-/*----------------------------------------------------------------------------*/
-/** Allocate L2 table and map buffer into it. That is, create respective table
- entries. Must hold Semaphore mc_drv_kmod_ctx.wsm_l2_sem */
-static struct mc_used_l2_table *new_used_l2_table(
- struct mc_instance *instance,
- struct task_struct *task,
- void *wsm_buffer,
- unsigned int wsm_len
-) {
- int ret = 0;
- struct mc_used_l2_table *used_l2table;
-
- do {
- used_l2table = allocate_used_l2_table(instance);
- if (used_l2table == NULL) {
- MCDRV_DBG_ERROR(
- "allocate_used_l2_table() failed\n");
- break;
- }
-
- /* create the L2 page for the WSM */
- ret = map_buffer_into_used_l2_table(
- task,
- wsm_buffer,
- wsm_len,
- used_l2table);
- if (ret != 0) {
- MCDRV_DBG_ERROR(
- "map_buffer_into_used_l2_table() failed\n");
- delete_used_l2_table(used_l2table, FREE_FROM_NWD);
- used_l2table = NULL;
- break;
- }
-
- } while (FALSE);
-
-
- return used_l2table;
-}
-
-/*
-#############################################################################
-##
-## IoCtl handler
-##
-#############################################################################*/
-
-/**
- * Map a virtual memory buffer structure to Mobicore
- * @param instance
- * @param addr address of the buffer(NB it must be kernel virtual!)
- * @param len buffer length
- * @param handle pointer to handle
- * @param phys_wsm_l2_table pointer to physical L2 table(?)
- *
- * @return 0 if no error
- *
- */
-/*----------------------------------------------------------------------------*/
-int mobicore_map_vmem(
- struct mc_instance *instance,
- void *addr,
- uint32_t len,
- uint32_t *handle,
- void **phys_wsm_l2_table
-)
-{
- int ret = 0;
- struct mc_used_l2_table *used_l2table = NULL;
- MCDRV_ASSERT(instance != NULL);
-
- MCDRV_DBG_VERBOSE("enter\n");
-
- do {
- if (len == 0) {
- MCDRV_DBG_ERROR("len=0 is not supported!\n");
- ret = -EINVAL;
- break;
- }
-
- /* try to get the semaphore */
- ret = down_interruptible(&(mc_drv_kmod_ctx.wsm_l2_sem));
- if (ret != 0) {
- MCDRV_DBG_ERROR("down_interruptible() failed with %d\n",
- ret);
- ret = -ERESTARTSYS;
- break;
- }
-
- do {
- used_l2table = new_used_l2_table(
- instance,
- NULL,
- addr,
- len);
-
- if (used_l2table == NULL) {
- MCDRV_DBG_ERROR("new_used_l2_table() failed\n");
- ret = -EINVAL;
- break;
- }
-
- /* set response */
- *handle = used_l2table->handle;
- *phys_wsm_l2_table =
- (void *)get_l2_table_phys(used_l2table);
- MCDRV_DBG_VERBOSE("handle: %d, phys=%p\n",
- *handle,
- (void *)(*phys_wsm_l2_table));
-
- } while (FALSE);
-
- /* release semaphore */
- up(&(mc_drv_kmod_ctx.wsm_l2_sem));
-
- } while (FALSE);
-
- MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
-
- return ret;
-}
-EXPORT_SYMBOL(mobicore_map_vmem);
-/*----------------------------------------------------------------------------*/
-/**
- *
- * @param instance
- * @param arg
- *
- * @return 0 if no error
- *
- */
-static int handle_ioctl_app_register_wsm_l2(
- struct mc_instance *instance,
- union mc_ioctl_app_reg_wsm_l2_params *user_params
-)
-{
- int ret = 0;
- union mc_ioctl_app_reg_wsm_l2_params params;
- struct mc_used_l2_table *used_l2table = NULL;
- struct pid *pid_struct = NULL;
- struct task_struct *task = current;
-
- MCDRV_ASSERT(instance != NULL);
-
- MCDRV_DBG_VERBOSE("enter\n");
-
- do {
- /* get use parameters */
- ret = copy_from_user(
- &(params.in),
- &(user_params->in),
- sizeof(params.in));
- if (ret != 0) {
- MCDRV_DBG_ERROR("copy_from_user() failed\n");
- break;
- }
-
- /* daemon can do this for another task. */
- if (params.in.pid != 0) {
- MCDRV_DBG_ERROR("pid != 0 unsupported\n");
- ret = -EINVAL;
- break;
- }
- if (params.in.len == 0) {
- MCDRV_DBG_ERROR("len=0 is not supported!\n");
- ret = -EINVAL;
- break;
- }
-
- /* try to get the semaphore */
- ret = down_interruptible(&(mc_drv_kmod_ctx.wsm_l2_sem));
- if (ret != 0) {
- MCDRV_DBG_ERROR("down_interruptible() failed with %d\n",
- ret);
- ret = -ERESTARTSYS;
- break;
- }
-
- do {
- used_l2table = new_used_l2_table(
- instance,
- task,
- (void *)(params.in.buffer),
- params.in.len);
-
- if (used_l2table == NULL) {
- MCDRV_DBG_ERROR("new_used_l2_table() failed\n");
- ret = -EINVAL;
- break;
- }
-
- /* if the daemon does this, we set the MC lock */
- if (is_caller_mc_daemon(instance))
- used_l2table->flags |=
- MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC;
-
- /* set response */
- memset(¶ms.out, 0, sizeof(params.out));
- params.out.handle = used_l2table->handle;
- /* TODO: return the physical address for daemon only,
- otherwise set NULL */
- params.out.phys_wsm_l2_table =
- (uint32_t)get_l2_table_phys(used_l2table);
-
- MCDRV_DBG_VERBOSE("handle: %d, phys=%p\n",
- params.out.handle,
- (void *)(params.out.phys_wsm_l2_table));
-
-
- /* copy L2Table to user space */
- ret = copy_to_user(
- &(user_params->out),
- &(params.out),
- sizeof(params.out));
- if (ret != 0) {
- MCDRV_DBG_ERROR("copy_to_user() failed\n");
-
- /* free the table again, as app does not know
- about anything. */
- if (is_caller_mc_daemon(instance)) {
- used_l2table->flags &=
- ~MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC;
- }
- delete_used_l2_table(used_l2table,
- FREE_FROM_NWD);
- used_l2table = NULL;
- break;
- }
-
- } while (FALSE);
-
- /* release semaphore */
- up(&(mc_drv_kmod_ctx.wsm_l2_sem));
-
- } while (FALSE);
-
-
-
- /* release PID struct reference */
- if (pid_struct != NULL)
- put_pid(pid_struct);
-
-
- MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
-
- return ret;
-}
-
-
-/*----------------------------------------------------------------------------*/
-/**
- * Unmap a virtual memory buffer from mobicore
- * @param instance
- * @param handle
- *
- * @return 0 if no error
- *
- */
-int mobicore_unmap_vmem(
- struct mc_instance *instance,
- uint32_t handle
-)
-{
- int ret = 0;
- struct mc_used_l2_table *used_l2table = NULL;
-
- MCDRV_ASSERT(instance != NULL);
- MCDRV_DBG_VERBOSE("enter\n");
-
- do {
- /* try to get the semaphore */
- ret = down_interruptible(&(mc_drv_kmod_ctx.wsm_l2_sem));
- if (ret != 0) {
- MCDRV_DBG_ERROR("processOpenSession() failed with %d\n",
- ret);
- ret = -ERESTARTSYS;
- break;
- }
-
- do {
- used_l2table = find_used_l2_table_by_handle(handle);
- if (used_l2table == NULL) {
- ret = -EINVAL;
- MCDRV_DBG_ERROR("entry not found\n");
- break;
- }
-
- if (instance != used_l2table->owner) {
- ret = -EINVAL;
- MCDRV_DBG_ERROR("instance does no own it\n");
- break;
- }
-
- /* free table (if no further locks exist) */
- delete_used_l2_table(used_l2table, FREE_FROM_NWD);
- used_l2table = NULL;
- /* there are no out parameters */
- } while (FALSE);
- /* release semaphore */
- up(&(mc_drv_kmod_ctx.wsm_l2_sem));
-
- } while (FALSE);
-
- MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
-
- return ret;
-}
-EXPORT_SYMBOL(mobicore_unmap_vmem);
-/*----------------------------------------------------------------------------*/
-/**
- *
- * @param instance
- * @param arg
- *
- * @return 0 if no error
- *
- */
-static int handle_ioctl_app_unregister_wsm_l2(
- struct mc_instance *instance,
- struct mc_ioctl_app_unreg_wsm_l2_params *user_params
-)
-{
- int ret = 0;
- struct mc_ioctl_app_unreg_wsm_l2_params params;
- struct mc_used_l2_table *used_l2table = NULL;
-
- MCDRV_ASSERT(instance != NULL);
- MCDRV_DBG_VERBOSE("enter\n");
-
- do {
- ret = copy_from_user(
- &(params.in),
- &(user_params->in),
- sizeof(params.in));
-
- if (ret != 0) {
- MCDRV_DBG_ERROR("copy_from_user\n");
- break;
- }
-
- /* try to get the semaphore */
- ret = down_interruptible(&(mc_drv_kmod_ctx.wsm_l2_sem));
- if (ret != 0) {
- MCDRV_DBG_ERROR("down_interruptible() failed with %d\n",
- ret);
- ret = -ERESTARTSYS;
- break;
- }
-
- do {
- /* daemon can do this for another task. */
- if (params.in.pid != 0) {
- MCDRV_DBG_ERROR("pid != 0 unsupported\n");
- ret = -EINVAL;
- break;
- }
-
- used_l2table =
- find_used_l2_table_by_handle(params.in.handle);
- if (used_l2table == NULL) {
- ret = -EINVAL;
- MCDRV_DBG_ERROR("entry not found\n");
- break;
- }
-
- if (is_caller_mc_daemon(instance)) {
- /* if daemon does this, we have to release the
- MobiCore lock. */
- used_l2table->flags &=
- ~MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC;
- } else if (instance != used_l2table->owner) {
- ret = -EINVAL;
- MCDRV_DBG_ERROR("instance does no own it\n");
- break;
- }
-
- /* free table (if no further locks exist) */
- delete_used_l2_table(used_l2table, FREE_FROM_NWD);
- used_l2table = NULL;
-
- /* there are no out parameters */
-
- } while (FALSE);
-
- /* release semaphore */
- up(&(mc_drv_kmod_ctx.wsm_l2_sem));
-
- } while (FALSE);
-
- MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
-
- return ret;
-}
-
-
-/*----------------------------------------------------------------------------*/
-static int handle_ioctl_daemon_lock_wsm_l2(
- struct mc_instance *instance,
- struct mc_ioctl_daemon_lock_wsm_l2_params *user_params
-)
-{
- int ret = 0;
- struct mc_ioctl_daemon_lock_wsm_l2_params params;
- struct mc_used_l2_table *used_l2table = NULL;
-
- MCDRV_ASSERT(instance != NULL);
- MCDRV_DBG_VERBOSE("enter\n");
-
- do {
- if (!is_caller_mc_daemon(instance)) {
- MCDRV_DBG_ERROR("caller not MobiCore Daemon\n");
- ret = -EFAULT;
- break;
- }
-
- ret = copy_from_user(
- &(params.in),
- &(user_params->in),
- sizeof(params.in));
-
- if (ret != 0) {
- MCDRV_DBG_ERROR("copy_from_user\n");
- break;
- }
- /* try to get the semaphore */
- ret = down_interruptible(&(mc_drv_kmod_ctx.wsm_l2_sem));
- if (ret != 0) {
- MCDRV_DBG_ERROR("down_interruptible() failed with %d\n",
- ret);
- ret = -ERESTARTSYS;
- break;
- }
-
- do {
- used_l2table =
- find_used_l2_table_by_handle(params.in.handle);
- if (used_l2table == NULL) {
- ret = -EINVAL;
- MCDRV_DBG_ERROR("entry not found\n");
- break;
- }
- if (instance != used_l2table->owner) {
- ret = -EINVAL;
- MCDRV_DBG_ERROR("instance does no own it\n");
- break;
- }
-
- /* lock entry */
- if ((used_l2table->flags &
- MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC) != 0) {
- MCDRV_DBG_WARN("entry already locked\n");
- }
- used_l2table->flags |=
- MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC;
-
- /* prepare response */
- memset(&(params.out), 0, sizeof(params.out));
- params.out.phys_wsm_l2_table =
- (uint32_t)get_l2_table_phys(used_l2table);
-
- /* copy to user space */
- ret = copy_to_user(
- &(user_params->out),
- &(params.out),
- sizeof(params.out));
- if (ret != 0) {
- MCDRV_DBG_ERROR("copy_to_user() failed\n");
-
- /* undo, as userspace did not get it. */
- used_l2table->flags |=
- MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC;
- break;
- }
-
- } while (FALSE);
-
- /* release semaphore */
- up(&(mc_drv_kmod_ctx.wsm_l2_sem));
-
- } while (FALSE);
-
- MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
-
- return ret;
-}
-
-
-/*----------------------------------------------------------------------------*/
-static int handle_ioctl_daemon_unlock_wsm_l2(
- struct mc_instance *instance,
- struct mc_ioctl_daemon_unlock_wsm_l2_params *user_params
-)
-{
- int ret = 0;
- struct mc_ioctl_daemon_unlock_wsm_l2_params params;
- struct mc_used_l2_table *used_l2table = NULL;
-
- MCDRV_ASSERT(instance != NULL);
- MCDRV_DBG_VERBOSE("enter\n");
-
- do {
- if (!is_caller_mc_daemon(instance)) {
- MCDRV_DBG_ERROR("caller not MobiCore Daemon\n");
- ret = -EFAULT;
- break;
- }
-
- ret = copy_from_user(
- &(params.in),
- &(user_params->in),
- sizeof(params.in));
-
- if (ret != 0) {
- MCDRV_DBG_ERROR("copy_from_user\n");
- break;
- }
- /* try to get the semaphore */
- ret = down_interruptible(&(mc_drv_kmod_ctx.wsm_l2_sem));
- if (ret != 0) {
- MCDRV_DBG_ERROR("down_interruptible() failed with %d\n",
- ret);
- ret = -ERESTARTSYS;
- break;
- }
-
- do {
- used_l2table =
- find_used_l2_table_by_handle(params.in.handle);
- if (used_l2table == NULL) {
- ret = -EINVAL;
- MCDRV_DBG_ERROR("entry not found\n");
- break;
- }
- if (instance != used_l2table->owner) {
- ret = -EINVAL;
- MCDRV_DBG_ERROR("instance does no own it\n");
- break;
- }
-
- /* lock entry */
- if ((used_l2table->flags &
- MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC) == 0) {
- MCDRV_DBG_WARN("entry is not locked locked\n");
- }
-
- /* free table (if no further locks exist) */
- delete_used_l2_table(used_l2table, FREE_FROM_SWD);
- used_l2table = NULL;
-
- /* there are no out parameters */
-
- } while (FALSE);
-
- } while (FALSE);
-
-
- MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
-
- return ret;
-}
-
-/*----------------------------------------------------------------------------*/
-/** Clears the reserved bit of each page and frees the pages */
-static inline void free_continguous_pages(
- void *addr,
- unsigned int size
-)
-{
- struct page *page = virt_to_page(addr);
- int i;
- for (i = 0; i < size; i++) {
- MCDRV_DBG_VERBOSE("free page at 0x%p\n", page);
- ClearPageReserved(page);
- page++;
- }
- /* REV luh: see man kmalloc */
- free_pages((unsigned long)addr, size_to_order(size));
-}
-
-/*----------------------------------------------------------------------------*/
-/**
- * Free a WSM buffer allocated with mobicore_allocate_wsm
- * @param instance
- * @param handle handle of the buffer
- *
- * @return 0 if no error
- *
- */
-int mobicore_free(
- struct mc_instance *instance,
- uint32_t handle
-)
-{
- int ret = 0;
- unsigned int i;
- struct mc_contg_buffer *contg_buffer;
-
- do {
- /* search for the given address in the contg_buffers list */
- for (i = 0; i < MC_DRV_KMOD_CONTG_BUFFER_MAX; i++) {
- contg_buffer = &(instance->contg_buffers[i]);
- if (contg_buffer->handle == handle)
- break;
- }
- if (i == MC_DRV_KMOD_CONTG_BUFFER_MAX) {
- MCDRV_DBG_ERROR("contigous buffer not found\n");
- ret = -EFAULT;
- break;
- }
-
- MCDRV_DBG_VERBOSE("phys_addr=0x%p, virt_addr=0x%p\n",
- contg_buffer->phys_addr,
- contg_buffer->virt_kernel_addr);
-
- free_continguous_pages(contg_buffer->virt_kernel_addr,
- contg_buffer->num_pages);
-
- memset(contg_buffer, 0, sizeof(*contg_buffer));
-
- /* there are no out parameters */
-
- } while (FALSE);
-
-
- return ret;
-}
-EXPORT_SYMBOL(mobicore_free);
-/*----------------------------------------------------------------------------*/
-
-/**
- *
- * @param instance
- * @param arg
- *
- * @return 0 if no error
- *
- */
-static int handle_ioctl_free(
- struct mc_instance *instance,
- union mc_ioctl_free_params *user_params
-)
-{
- int ret = 0;
- union mc_ioctl_free_params params;
-
-
- MCDRV_ASSERT(instance != NULL);
- MCDRV_DBG_VERBOSE("enter\n");
-
- do {
- ret = copy_from_user(
- &(params.in),
- &(user_params->in),
- sizeof(params.in));
-
- if (ret != 0) {
- MCDRV_DBG_ERROR("copy_from_user\n");
- break;
- }
-
- /* daemon can do this for another task. */
- if (params.in.pid != 0) {
- MCDRV_DBG_ERROR("pid != 0 unsupported\n");
- ret = -EINVAL;
- break;
- }
-
- ret = mobicore_free(instance, params.in.handle);
-
- /* there are no out parameters */
-
- } while (FALSE);
-
- MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
-
- return ret;
-
-}
-
-
-/*----------------------------------------------------------------------------*/
-/**
- *
- * @param instance
- * @param arg
- *
- * @return 0 if no error
- *
- */
-static int handle_ioctl_info(
- struct mc_instance *instance,
- union mc_ioctl_info_params *user_params
-)
-{
- int ret = 0;
- union mc_ioctl_info_params params;
- union mc_fc_info fc_info;
-
-
- MCDRV_ASSERT(instance != NULL);
- MCDRV_DBG_VERBOSE("enter\n");
-
- do {
- /* only the MobiCore Daemon is allowed to call this function */
- if (!is_caller_mc_daemon(instance)) {
- MCDRV_DBG_ERROR("caller not MobiCore Daemon\n");
- ret = -EFAULT;
- break;
- }
-
- ret = copy_from_user(
- &(params.in),
- &(user_params->in),
- sizeof(params.in));
-
- if (ret != 0) {
- MCDRV_DBG_ERROR("copy_from_user\n");
- break;
- }
-
-
- memset(&fc_info, 0, sizeof(fc_info));
- fc_info.as_in.cmd = MC_FC_INFO;
- fc_info.as_in.ext_info_id = params.in.ext_info_id;
-
- MCDRV_DBG(
- "fc_info in cmd=0x%08x, ext_info_id=0x%08x "
- "rfu=(0x%08x, 0x%08x)\n",
- fc_info.as_in.cmd,
- fc_info.as_in.ext_info_id,
- fc_info.as_in.rfu[0],
- fc_info.as_in.rfu[1]);
-
- mc_fastcall(&(fc_info.as_generic));
-
- MCDRV_DBG(
- "fc_info out resp=0x%08x, ret=0x%08x "
- "state=0x%08x, ext_info=0x%08x\n",
- fc_info.as_out.resp,
- fc_info.as_out.ret,
- fc_info.as_out.state,
- fc_info.as_out.ext_info);
-
- ret = convert_fc_ret(fc_info.as_out.ret);
- if (ret != 0)
- break;
-
- memset(&(params.out), 0, sizeof(params.out));
- params.out.state = fc_info.as_out.state;
- params.out.ext_info = fc_info.as_out.ext_info;
-
- ret = copy_to_user(
- &(user_params->out),
- &(params.out),
- sizeof(params.out));
-
- if (ret != 0) {
- MCDRV_DBG_ERROR("copy_to_user\n");
- break;
- }
- } while (FALSE);
-
- MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
-
- return ret;
-}
-
-/*----------------------------------------------------------------------------*/
-/**
- *
- * @param instance
- * @param arg
- *
- * @return 0 if no error
- *
- */
-static int handle_ioctl_yield(
- struct mc_instance *instance
-)
-{
- int ret = 0;
- union mc_fc_s_yield fc_s_yield;
-
- MCDRV_ASSERT(instance != NULL);
-
- /* avoid putting debug output here, as we do this very often */
- MCDRV_DBG_VERBOSE("enter\n");
-
- do {
- /* only the MobiCore Daemon is allowed to call this function */
- if (!is_caller_mc_daemon(instance)) {
- MCDRV_DBG_ERROR("caller not MobiCore Daemon\n");
- ret = -EFAULT;
- break;
- }
-
- memset(&fc_s_yield, 0, sizeof(fc_s_yield));
- fc_s_yield.as_in.cmd = MC_SMC_N_YIELD;
- mc_fastcall(&(fc_s_yield.as_generic));
- ret = convert_fc_ret(fc_s_yield.as_out.ret);
- if (ret != 0)
- break;
-
- } while (FALSE);
-
- MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
-
- return ret;
-}
-
-/*----------------------------------------------------------------------------*/
-/**
- * handle ioctl and call common notify
- *
- * @param instance
- * @param arg
- *
- * @return 0 if no error
- *
- */
-static int handle_ioctl_nsiq(
- struct mc_instance *instance,
- unsigned long arg
-)
-{
- int ret = 0;
-
- MCDRV_ASSERT(instance != NULL);
-
- /* avoid putting debug output here, as we do this very often */
- MCDRV_DBG_VERBOSE("enter\n");
- /* only the MobiCore Daemon is allowed to call this function */
- if (!is_caller_mc_daemon(instance)) {
- MCDRV_DBG_ERROR("caller not MobiCore Daemon\n");
- return -EFAULT;
- }
-
- do {
- union mc_fc_nsiq fc_nsiq;
- memset(&fc_nsiq, 0, sizeof(fc_nsiq));
- fc_nsiq.as_in.cmd = MC_SMC_N_SIQ;
- mc_fastcall(&(fc_nsiq.as_generic));
- ret = convert_fc_ret(fc_nsiq.as_out.ret);
- if (ret != 0)
- break;
- } while (FALSE);
-
- MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
-
- return ret;
-}
-
-/*----------------------------------------------------------------------------*/
-/**
- *
- * @param instance
- * @param arg
- *
- * @return 0 if no error
- *
- */
-static int handle_ioctl_dump_status(
- struct mc_instance *instance,
- unsigned long arg
-)
-{
- int ret = 0;
- int i = 0;
- union mc_fc_info fc_info;
-
- MCDRV_ASSERT(instance != NULL);
- MCDRV_DBG_VERBOSE("enter\n");
-
- do {
- /* anybody with root access can do this. */
- if (!is_userland_caller_privileged()) {
- MCDRV_DBG_ERROR("caller must have root privileges\n");
- ret = -EFAULT;
- break;
- }
-
- /* loop ext_info */
- while (TRUE) {
- memset(&fc_info, 0, sizeof(fc_info));
- fc_info.as_in.cmd = MC_FC_INFO;
- fc_info.as_in.ext_info_id = i;
-
- MCDRV_DBG(
- "fc_info in cmd=0x%08x, ext_info_id=0x%08x "
- "rfu=(0x%08x, 0x%08x)\n",
- fc_info.as_in.cmd,
- fc_info.as_in.ext_info_id,
- fc_info.as_in.rfu[0],
- fc_info.as_in.rfu[1]);
-
- mc_fastcall(&(fc_info.as_generic));
-
- MCDRV_DBG(
- "fc_info out resp=0x%08x, ret=0x%08x "
- "state=0x%08x, ext_info=0x%08x\n",
- fc_info.as_out.resp,
- fc_info.as_out.ret,
- fc_info.as_out.state,
- fc_info.as_out.ext_info);
-
- ret = convert_fc_ret(fc_info.as_out.ret);
- if (ret != 0)
- break;
-
- MCDRV_DBG("state=%08X, idx=%02d: ext_info=%08X\n",
- fc_info.as_out.state,
- i,
- fc_info.as_out.ext_info);
- i++;
- };
-
- if (ret != 0)
- break;
-
-
- } while (FALSE);
-
- MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
-
- return ret;
-}
-
-/*----------------------------------------------------------------------------*/
-/**
- *
- * @param instance
- * @param arg
- *
- * @return 0 if no error
- *
- */
-static int handle_ioctl_init(
- struct mc_instance *instance,
- union mc_ioctl_init_params *user_params
-)
-{
- int ret = 0;
- union mc_ioctl_init_params params;
- union mc_fc_init fc_init;
-
- MCDRV_ASSERT(instance != NULL);
- MCDRV_DBG_VERBOSE("enter\n");
-
- do {
- /* only the MobiCore Daemon is allowed to call this function */
- if (!is_caller_mc_daemon(instance)) {
- MCDRV_DBG_ERROR("caller not MobiCore Daemon\n");
- ret = -EFAULT;
- break;
- }
-
- ret = copy_from_user(
- &(params.in),
- &(user_params->in),
- sizeof(params.in));
- if (ret != 0) {
- MCDRV_DBG_ERROR("copy_from_user failed\n");
- break;
- }
-
- memset(&fc_init, 0, sizeof(fc_init));
-
- fc_init.as_in.cmd = MC_FC_INIT;
- /* base address of mci buffer 4KB aligned */
- fc_init.as_in.base = (uint32_t)params.in.base;
- /* notification buffer start/length [16:16] [start, length] */
- fc_init.as_in.nq_info = (params.in.nq_offset << 16)
- | (params.in.nq_length & 0xFFFF);
- /* mcp buffer start/length [16:16] [start, length] */
- fc_init.as_in.mcp_info = (params.in.mcp_offset << 16)
- | (params.in.mcp_length & 0xFFFF);
-
- /* Set KMOD notification queue to start of MCI
- mciInfo was already set up in mmap */
- if (!mci_base) {
- MCDRV_DBG_ERROR("No MCI set yet.\n");
- return -EFAULT;
- }
- MCDRV_DBG("in cmd=0x%08x, base=0x%08x, "
- "nq_info=0x%08x, mcp_info=0x%08x\n",
- fc_init.as_in.cmd,
- fc_init.as_in.base,
- fc_init.as_in.nq_info,
- fc_init.as_in.mcp_info);
-
- mc_fastcall(&(fc_init.as_generic));
-
- MCDRV_DBG("out cmd=0x%08x, ret=0x%08x rfu=(0x%08x, 0x%08x)\n",
- fc_init.as_out.resp,
- fc_init.as_out.ret,
- fc_init.as_out.rfu[0],
- fc_init.as_out.rfu[1]);
-
- ret = convert_fc_ret(fc_init.as_out.ret);
- if (ret != 0)
- break;
-
- /* no ioctl response parameters */
-
- } while (FALSE);
-
- MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
-
- return ret;
-}
-
-/*----------------------------------------------------------------------------*/
-/**
- *
- * @param instance
- * @param arg
- *
- * @return 0 if no error
- *
- */
-static int handle_ioctl_fc_execute(
- struct mc_instance *instance,
- union mc_ioctl_fc_execute_params *user_params
-)
-{
- int ret = 0;
- union mc_ioctl_fc_execute_params params;
- union fc_generic fc_params;
-
- MCDRV_ASSERT(instance != NULL);
- MCDRV_DBG_VERBOSE("enter\n");
-
- do {
- /* only the MobiCore Daemon is allowed to call this function */
- if (!is_caller_mc_daemon(instance)) {
- MCDRV_DBG_ERROR("caller not MobiCore Daemon\n");
- ret = -EFAULT;
- break;
- }
-
- ret = copy_from_user(
- &(params.in),
- &(user_params->in),
- sizeof(params.in));
- if (ret != 0) {
- MCDRV_DBG_ERROR("copy_from_user failed\n");
- break;
- }
-
- fc_params.as_in.cmd = -4;/*FC_EXECUTE */
- fc_params.as_in.param[0] = params.in.phys_start_addr;
- fc_params.as_in.param[1] = params.in.length;
- fc_params.as_in.param[2] = 0;
-
- MCDRV_DBG("in cmd=0x%08x, startAddr=0x%08x, length=0x%08x\n",
- fc_params.as_in.cmd,
- fc_params.as_in.param[0],
- fc_params.as_in.param[1]);
-
- mc_fastcall(&fc_params);
-
- MCDRV_DBG("out cmd=0x%08x, ret=0x%08x rfu=(0x%08x, 0x%08x)\n",
- fc_params.as_out.resp,
- fc_params.as_out.ret,
- fc_params.as_out.param[0],
- fc_params.as_out.param[1]);
-
- ret = convert_fc_ret(fc_params.as_out.ret);
- if (ret != 0)
- break;
-
- /* no ioctl response parameters */
-
- } while (FALSE);
-
- MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
-
- return ret;
-}
-
-/*----------------------------------------------------------------------------*/
-#define MC_MAKE_VERSION(major, minor) \
- (((major & 0x0000ffff) << 16) | (minor & 0x0000ffff))
-/**
- *
- * @param instance
- * @param arg
- *
- * @return 0 if no error
- *
- */
-static int handle_ioctl_get_version(
- struct mc_instance *instance,
- struct mc_ioctl_get_version_params *user_params
-)
-{
- int ret = 0;
- struct mc_ioctl_get_version_params params = {
- {
- MC_MAKE_VERSION(MCDRVMODULEAPI_VERSION_MAJOR,
- MCDRVMODULEAPI_VERSION_MINOR)
- }
- };
-
- MCDRV_ASSERT(instance != NULL);
- MCDRV_DBG_VERBOSE("enter\n");
-
- do {
- MCDRV_DBG("mcDrvModuleApi version is %i.%i\n",
- MCDRVMODULEAPI_VERSION_MAJOR,
- MCDRVMODULEAPI_VERSION_MINOR);
-
- /* no ioctl response parameters */
- ret = copy_to_user(
- &(user_params->out),
- &(params.out),
- sizeof(params.out));
- if (ret != 0)
- MCDRV_DBG_ERROR("copy_to_user() failed\n");
-
- } while (FALSE);
-
- MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
-
- return ret;
-}
-
-/*----------------------------------------------------------------------------*/
-/**
- * This function will be called from user space as ioctl(...).
- * @param file pointer to file
- * @param cmd command
- * @param arg arguments
- *
- * @return int 0 for OK and an errno in case of error
- */
-static long mc_kernel_module_ioctl(
- struct file *file,
- unsigned int cmd,
- unsigned long arg
-)
-{
- int ret;
struct mc_instance *instance = get_instance(file);
+ unsigned long len = vmarea->vm_end - vmarea->vm_start;
+ void *paddr = (void *)(vmarea->vm_pgoff << PAGE_SHIFT);
+ unsigned int pfn;
+ struct mc_buffer *buffer = 0;
+ int ret = 0;
- MCDRV_ASSERT(instance != NULL);
+ MCDRV_DBG(mcd, "enter (vma start=0x%p, size=%ld, mci=%p)\n",
+ (void *)vmarea->vm_start, len, ctx.mci_base.phys);
+
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
+
+ if (len == 0) {
+ MCDRV_DBG_ERROR(mcd, "cannot allocate size 0\n");
+ return -ENOMEM;
+ }
+ if (paddr) {
+ mutex_lock(&ctx.bufs_lock);
+
+ /* search for the buffer list. */
+ list_for_each_entry(buffer, &ctx.cont_bufs, list) {
+ if (buffer->phys == paddr)
+ goto found;
+ else
+ break;
+ }
+ /* Nothing found return */
+ mutex_unlock(&ctx.bufs_lock);
+ return -EINVAL;
+
+found:
+ vmarea->vm_flags |= VM_RESERVED;
+ /*
+ * Convert kernel address to user address. Kernel address begins
+ * at PAGE_OFFSET, user address range is below PAGE_OFFSET.
+ * Remapping the area is always done, so multiple mappings
+ * of one region are possible. Now remap kernel address
+ * space into user space
+ */
+ pfn = (unsigned int)paddr >> PAGE_SHIFT;
+ ret = (int)remap_pfn_range(vmarea, vmarea->vm_start, pfn,
+ buffer->len, vmarea->vm_page_prot);
+ mutex_unlock(&ctx.bufs_lock);
+ } else {
+ if (!is_daemon(instance))
+ return -EPERM;
+
+ paddr = get_mci_base_phys(len);
+ if (!paddr)
+ return -EFAULT;
+
+ vmarea->vm_flags |= VM_RESERVED;
+ /*
+ * Convert kernel address to user address. Kernel address begins
+ * at PAGE_OFFSET, user address range is below PAGE_OFFSET.
+ * Remapping the area is always done, so multiple mappings
+ * of one region are possible. Now remap kernel address
+ * space into user space
+ */
+ pfn = (unsigned int)paddr >> PAGE_SHIFT;
+ ret = (int)remap_pfn_range(vmarea, vmarea->vm_start, pfn, len,
+ vmarea->vm_page_prot);
+ }
+
+ MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret);
+
+ return ret;
+}
+
+static inline int ioctl_check_pointer(unsigned int cmd, int __user *uarg)
+{
+ int err = 0;
+ if (_IOC_DIR(cmd) & _IOC_READ)
+ err = !access_ok(VERIFY_WRITE, uarg, _IOC_SIZE(cmd));
+ else if (_IOC_DIR(cmd) & _IOC_WRITE)
+ err = !access_ok(VERIFY_READ, uarg, _IOC_SIZE(cmd));
+ if (err)
+ return -EFAULT;
+
+ return 0;
+}
+
+/*
+ * mc_fd_user_ioctl() - Will be called from user space as ioctl(..)
+ * @file pointer to file
+ * @cmd command
+ * @arg arguments
+ *
+ * Returns 0 for OK and an errno in case of error
+ */
+static long mc_fd_user_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct mc_instance *instance = get_instance(file);
+ int __user *uarg = (int __user *)arg;
+ int ret = -EINVAL;
+
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
+
+ if (ioctl_check_pointer(cmd, uarg))
+ return -EFAULT;
switch (cmd) {
- /*--------------------------------------------------------------------*/
- case MC_DRV_KMOD_IOCTL_DUMP_STATUS:
- ret = handle_ioctl_dump_status(
- instance,
- arg);
+ case MC_IO_FREE:
+ ret = mc_free_buffer(instance, (uint32_t)arg);
break;
- /*--------------------------------------------------------------------*/
- case MC_DRV_KMOD_IOCTL_FC_INIT:
- ret = handle_ioctl_init(
- instance,
- (union mc_ioctl_init_params *)arg);
+ case MC_IO_REG_WSM:{
+ struct mc_ioctl_reg_wsm reg;
+ if (copy_from_user(®, uarg, sizeof(reg)))
+ return -EFAULT;
+
+ ret = mc_register_wsm_l2(instance, reg.buffer,
+ reg.len, ®.handle, ®.table_phys);
+ if (!ret) {
+ if (copy_to_user(uarg, ®, sizeof(reg))) {
+ ret = -EFAULT;
+ mc_unregister_wsm_l2(instance, reg.handle);
+ }
+ }
break;
- /*--------------------------------------------------------------------*/
- case MC_DRV_KMOD_IOCTL_FC_INFO:
- ret = handle_ioctl_info(
- instance,
- (union mc_ioctl_info_params *)arg);
+ }
+ case MC_IO_UNREG_WSM:
+ ret = mc_unregister_wsm_l2(instance, (uint32_t)arg);
break;
- /*--------------------------------------------------------------------*/
- case MC_DRV_KMOD_IOCTL_FC_YIELD:
- ret = handle_ioctl_yield(
- instance);
+ case MC_IO_VERSION:
+ ret = put_user(mc_get_version(), uarg);
+ if (ret)
+ MCDRV_DBG_ERROR(mcd,
+ "IOCTL_GET_VERSION failed to put data");
break;
- /*--------------------------------------------------------------------*/
- case MC_DRV_KMOD_IOCTL_FC_NSIQ:
- ret = handle_ioctl_nsiq(
- instance,
- arg);
- break;
+ case MC_IO_MAP_WSM:{
+ struct mc_ioctl_map map;
+ struct mc_buffer *buffer = 0;
+ if (copy_from_user(&map, uarg, sizeof(map)))
+ return -EFAULT;
- /*--------------------------------------------------------------------*/
- case MC_DRV_KMOD_IOCTL_DAEMON_LOCK_WSM_L2:
- ret = handle_ioctl_daemon_lock_wsm_l2(
- instance,
- (struct mc_ioctl_daemon_lock_wsm_l2_params *)arg);
- break;
+ /* Setup the WSM buffer structure! */
+ if (mc_get_buffer(instance, &buffer, map.len))
+ return -EFAULT;
- /*--------------------------------------------------------------------*/
- case MC_DRV_KMOD_IOCTL_DAEMON_UNLOCK_WSM_L2:
- ret = handle_ioctl_daemon_unlock_wsm_l2(
- instance,
- (struct mc_ioctl_daemon_unlock_wsm_l2_params *)arg);
- break;
+ map.handle = buffer->handle;
+ map.phys_addr = (unsigned long)buffer->phys;
+ map.reused = 0;
+ if (copy_to_user(uarg, &map, sizeof(map)))
+ ret = -EFAULT;
- /*--------------------------------------------------------------------*/
- case MC_DRV_KMOD_IOCTL_FREE:
- /* called by ClientLib */
- ret = handle_ioctl_free(
- instance,
- (union mc_ioctl_free_params *)arg);
+ ret = 0;
break;
-
- /*--------------------------------------------------------------------*/
- case MC_DRV_KMOD_IOCTL_APP_REGISTER_WSM_L2:
- /* called by ClientLib */
- ret = handle_ioctl_app_register_wsm_l2(
- instance,
- (union mc_ioctl_app_reg_wsm_l2_params *)arg);
- break;
-
- /*--------------------------------------------------------------------*/
- case MC_DRV_KMOD_IOCTL_APP_UNREGISTER_WSM_L2:
- /* called by ClientLib */
- ret = handle_ioctl_app_unregister_wsm_l2(
- instance,
- (struct mc_ioctl_app_unreg_wsm_l2_params *)arg);
- break;
-
- /*--------------------------------------------------------------------*/
- case MC_DRV_KMOD_IOCTL_FC_EXECUTE:
- ret = handle_ioctl_fc_execute(
- instance,
- (union mc_ioctl_fc_execute_params *)arg);
- break;
-
- /*--------------------------------------------------------------------*/
- case MC_DRV_KMOD_IOCTL_GET_VERSION:
- ret = handle_ioctl_get_version(
- instance,
- (struct mc_ioctl_get_version_params *)arg);
- break;
-
- /*--------------------------------------------------------------------*/
+ }
default:
- MCDRV_DBG_ERROR("unsupported cmd=%d\n", cmd);
- ret = -EFAULT;
+ MCDRV_DBG_ERROR(mcd, "unsupported cmd=%d\n", cmd);
+ ret = -ENOIOCTLCMD;
break;
} /* end switch(cmd) */
@@ -1975,895 +632,533 @@
return (int)ret;
}
-
-/*----------------------------------------------------------------------------*/
-/**
- * This function will be called from user space as read(...).
- * The read function is blocking until a interrupt occurs. In that case the
- * event counter is copied into user space and the function is finished.
- * @param *file
- * @param *buffer buffer where to copy to(userspace)
- * @param buffer_len number of requested data
- * @param *pos not used
- * @return ssize_t ok case: number of copied data
- * error case: return errno
- */
-static ssize_t mc_kernel_module_read(
- struct file *file,
- char *buffer,
- size_t buffer_len,
- loff_t *pos
-)
+static long mc_fd_admin_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
{
- int ret = 0, ssiq_counter;
- size_t retLen = 0;
struct mc_instance *instance = get_instance(file);
+ int __user *uarg = (int __user *)arg;
+ int ret = -EINVAL;
- MCDRV_ASSERT(instance != NULL);
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
- /* avoid debug output on non-error, because this is call quite often */
- MCDRV_DBG_VERBOSE("enter\n");
-
- do {
- /* only the MobiCore Daemon is allowed to call this function */
- if (!is_caller_mc_daemon(instance)) {
- MCDRV_DBG_ERROR("caller not MobiCore Daemon\n");
- ret = -EFAULT;
- break;
- }
-
- if (buffer_len < sizeof(unsigned int)) {
- MCDRV_DBG_ERROR("invalid length\n");
- ret = (ssize_t)(-EINVAL);
- break;
- }
-
- for (;;) {
- if (down_interruptible(
- &mc_drv_kmod_ctx.daemon_ctx.sem)) {
- MCDRV_DBG_VERBOSE("read interrupted\n");
- ret = (ssize_t)-ERESTARTSYS;
- break;
- }
-
- ssiq_counter = atomic_read(
- &(mc_drv_kmod_ctx.ssiq_ctx.counter));
- MCDRV_DBG_VERBOSE("ssiq_counter=%i, ctx.counter=%i\n",
- ssiq_counter,
- mc_drv_kmod_ctx.daemon_ctx.ssiq_counter);
-
- if (ssiq_counter !=
- mc_drv_kmod_ctx.daemon_ctx.ssiq_counter) {
- /* read data and exit loop without
- error */
- mc_drv_kmod_ctx.daemon_ctx.ssiq_counter =
- ssiq_counter;
- ret = 0;
- break;
- }
-
- /* end loop if non-blocking */
- if ((file->f_flags & O_NONBLOCK) != 0) {
- MCDRV_DBG_ERROR("non-blocking read\n");
- ret = (ssize_t)(-EAGAIN);
- break;
- }
-
- if (signal_pending(current) != 0) {
- MCDRV_DBG_VERBOSE("received signal.\n");
- ret = (ssize_t)(-ERESTARTSYS);
- break;
- }
-
- }
-
- /* we are here if an event occurred or we had an
- error.*/
- if (ret != 0)
- break;
-
- /* read data and exit loop */
- ret = copy_to_user(
- buffer,
- &(mc_drv_kmod_ctx.daemon_ctx.ssiq_counter),
- sizeof(unsigned int));
-
-
- if (ret != 0) {
- MCDRV_DBG_ERROR("copy_to_user failed\n");
- ret = (ssize_t)(-EFAULT);
- break;
- }
-
- retLen = sizeof(s32);
-
- } while (FALSE);
-
- /* avoid debug on non-error. */
- if (ret == 0)
- ret = (size_t)retLen;
- else
- MCDRV_DBG("exit with %d/0x%08X\n", ret, ret);
-
- return (ssize_t)ret;
-}
-
-/*----------------------------------------------------------------------------*/
-/**
- * Allocate WSM for given instance
- *
- * @param instance instance
- * @param requested_size size of the WSM
- * @param handle pointer where the handle will be saved
- * @param virt_kernel_addr pointer for the kernel virtual address
- * @param phys_addr pointer for the physical address
- *
- * @return error code or 0 for success
- */
-int mobicore_allocate_wsm(
- struct mc_instance *instance,
- unsigned long requested_size,
- uint32_t *handle,
- void **virt_kernel_addr,
- void **phys_addr
-)
-{
- unsigned int i;
- unsigned int order;
- unsigned long allocated_size;
- int ret = 0;
- struct mc_contg_buffer *contg_buffer = 0;
- void *virt_kernel_addr_stack;
- void *phys_addr_stack;
-
- MCDRV_ASSERT(instance != NULL);
- MCDRV_DBG("%s (size=%ld)\n", __func__, requested_size);
-
- order = size_to_order(requested_size);
- if (order == INVALID_ORDER) {
- MCDRV_DBG_ERROR(
- "size to order converting failed for size %ld\n",
- requested_size);
- return INVALID_ORDER;
+ if (WARN_ON(!is_daemon(instance))) {
+ MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n");
+ return -EPERM;
}
- allocated_size = (1<<order)*PAGE_SIZE;
+ if (ioctl_check_pointer(cmd, uarg))
+ return -EFAULT;
- MCDRV_DBG("size %ld -> order %d --> %ld (2^n pages)\n",
- requested_size, order, allocated_size);
-
- do {
- /* Usual Wsm request, allocate contigous buffer. */
- /* search for a free entry in the wsm buffer list
- * REV axh: serialize this over multiple instances. */
- for (i = 0; i < MC_DRV_KMOD_CONTG_BUFFER_MAX; i++) {
- contg_buffer = &(instance->contg_buffers[i]);
- if (contg_buffer->handle == 0) {
- contg_buffer->handle = get_mc_kmod_unique_id();
- break;
- }
+ if (ctx.mcp) {
+ while (ctx.mcp->flags.sleep_mode.SleepReq) {
+ ctx.daemon = current;
+ set_current_state(TASK_INTERRUPTIBLE);
+ /* Back off daemon for a while */
+ schedule_timeout(msecs_to_jiffies(DAEMON_BACKOFF_TIME));
+ set_current_state(TASK_RUNNING);
}
- if (i == MC_DRV_KMOD_CONTG_BUFFER_MAX) {
- MCDRV_DBG_ERROR("no free contigous buffer\n");
- ret = -EFAULT;
- break;
- }
-
- /* Common code for all allocation paths */
- virt_kernel_addr_stack = (void *)__get_free_pages(
- GFP_USER | __GFP_COMP,
- order);
- if (virt_kernel_addr_stack == NULL) {
- MCDRV_DBG_ERROR("get_free_pages failed\n");
- ret = -ENOMEM;
- break;
- }
-
- /* Get physical address to instance data */
- phys_addr_stack = (void *)virt_to_phys(virt_kernel_addr_stack);
- /* TODO: check for INVALID_ADDRESS? */
-
- MCDRV_DBG(
- "allocated phys=0x%p - 0x%p, "
- "size=%ld, kernel_virt=0x%p, handle=%d\n",
- phys_addr_stack,
- (void *)((unsigned int)phys_addr_stack+allocated_size),
- allocated_size,
- virt_kernel_addr_stack,
- contg_buffer->handle);
-
- /* Usual Wsm request, allocate contg_buffer.
- * Also, we never free a persistent Tci */
- contg_buffer->phys_addr = phys_addr_stack;
- contg_buffer->virt_kernel_addr = virt_kernel_addr_stack;
- contg_buffer->virt_user_addr = virt_kernel_addr_stack;
- contg_buffer->num_pages = (1U << order);
- *handle = contg_buffer->handle;
- *virt_kernel_addr = virt_kernel_addr_stack;
- *phys_addr = phys_addr_stack;
-
- } while (FALSE);
-
- MCDRV_DBG_VERBOSE("%s: exit with 0x%08X\n", __func__, ret);
-
- return ret;
-}
-EXPORT_SYMBOL(mobicore_allocate_wsm);
-
-
-/*----------------------------------------------------------------------------*/
-/**
- * This function will be called from user space as address = mmap(...).
- *
- * @param file
- * @param vmarea
- * vmarea.pg_offset != 0 is mapping of MCI is requested
- *
- * @return 0 if OK or -ENOMEM in case of error.
- */
-static int mc_kernel_module_mmap(
- struct file *file,
- struct vm_area_struct *vmarea
-)
-{
- unsigned int i;
- unsigned int order;
- void *virt_kernel_addr_stack = 0;
- void *phys_addr = 0;
- unsigned long requested_size =
- vmarea->vm_end - vmarea->vm_start;
- unsigned long allocated_size;
- int ret = 0;
- struct mc_contg_buffer *contg_buffer = 0;
- unsigned int handle = 0;
- struct mc_instance *instance = get_instance(file);
- unsigned int request = vmarea->vm_pgoff * 4096;
-#if defined(DEBUG)
- bool release = false;
-#else
- bool release = true;
-#endif
-
- MCDRV_ASSERT(instance != NULL);
- MCDRV_DBG("enter (vmaStart=0x%p, size=%ld, request=0x%x, mci=0x%x)\n",
- (void *)vmarea->vm_start,
- requested_size,
- request,
- mci_base);
-
- order = size_to_order(requested_size);
- if (order == INVALID_ORDER) {
- MCDRV_DBG_ERROR(
- "size to order converting failed for size %ld\n",
- requested_size);
- return -ENOMEM;
}
- allocated_size = (1<<order)*PAGE_SIZE;
+ switch (cmd) {
+ case MC_IO_INIT: {
+ struct mc_ioctl_init init;
+ ctx.mcp = NULL;
+ if (!ctx.mci_base.phys) {
+ MCDRV_DBG_ERROR(mcd,
+ "Cannot init MobiCore without MCI!");
+ return -EINVAL;
+ }
+ if (copy_from_user(&init, uarg, sizeof(init)))
+ return -EFAULT;
- MCDRV_DBG("size %ld -> order %d --> %ld (2^n pages)\n",
- requested_size, order, allocated_size);
+ ctx.mcp = ctx.mci_base.addr + init.mcp_offset;
+ ret = mc_init((uint32_t)ctx.mci_base.phys, init.nq_offset,
+ init.nq_length, init.mcp_offset, init.mcp_length);
+ break;
+ }
+ case MC_IO_INFO: {
+ struct mc_ioctl_info info;
+ if (copy_from_user(&info, uarg, sizeof(info)))
+ return -EFAULT;
- do {
- /* Daemon tries to get an existing MCI */
- if ((request == MC_DRV_KMOD_MMAP_MCI) && (mci_base != 0)) {
- MCDRV_DBG("Request MCI, it is at (%x)\n", mci_base);
+ ret = mc_info(info.ext_info_id, &info.state,
+ &info.ext_info);
- if (!is_caller_mc_daemon(instance)) {
- ret = -EPERM;
- break;
- }
- virt_kernel_addr_stack = (void *)mci_base;
- phys_addr =
- (void *)virt_to_phys(virt_kernel_addr_stack);
- } else {
- /* Usual Wsm request, allocate buffer. */
- if (request == MC_DRV_KMOD_MMAP_WSM) {
- /* search for a free entry in the buffer list
- REV axh: serialize this over multiple instances.
- */
- for (i = 0; i < MC_DRV_KMOD_CONTG_BUFFER_MAX;
- i++) {
- contg_buffer =
- &(instance->contg_buffers[i]);
- if (contg_buffer->handle == 0) {
- contg_buffer->handle =
- get_mc_kmod_unique_id();
- break;
- }
- }
- if (i == MC_DRV_KMOD_CONTG_BUFFER_MAX) {
- MCDRV_DBG_ERROR(
- "no free contigous buffer\n");
- ret = -EFAULT;
- break;
- }
- } else {
- if (request <= MC_DRV_KMOD_MMAP_PERSISTENTWSM
- || release) {
- /* Special Wsm request
- --> only Daemon is allowed */
- if (!is_caller_mc_daemon(instance)) {
- ret = -EPERM;
- break;
- }
- }
- }
- if (request <= MC_DRV_KMOD_MMAP_PERSISTENTWSM) {
- /* Common code for all allocation paths
- * get physical address, */
- virt_kernel_addr_stack =
- (void *)__get_free_pages(
- GFP_USER | __GFP_COMP,
- order);
- if (virt_kernel_addr_stack == NULL) {
- MCDRV_DBG_ERROR(
- "get_free_pages failed\n");
- ret = -ENOMEM;
- break;
- }
- if (request == MC_DRV_KMOD_MMAP_WSM)
- handle = contg_buffer->handle;
- /* Get physical address to instance data */
- /* TODO: check for INVALID_ADDRESS? */
- phys_addr = (void *)virt_to_phys(
- virt_kernel_addr_stack);
- } else {
-#if defined(DEBUG)
- phys_addr = (void *)request;
- virt_kernel_addr_stack = phys_to_virt(request);
+ if (!ret) {
+ if (copy_to_user(uarg, &info, sizeof(info)))
+ ret = -EFAULT;
+ }
+ break;
+ }
+ case MC_IO_YIELD:
+ ret = mc_yield();
+ break;
+
+ case MC_IO_NSIQ:
+ ret = mc_nsiq();
+ break;
+
+ case MC_IO_LOCK_WSM: {
+ ret = mc_lock_handle(instance, (uint32_t)arg);
+ break;
+ }
+ case MC_IO_UNLOCK_WSM:
+ ret = mc_unlock_handle(instance, (uint32_t)arg);
+ break;
+ case MC_IO_CLEAN_WSM:
+ ret = mc_clean_wsm_l2(instance);
+ break;
+ case MC_IO_RESOLVE_WSM: {
+ uint32_t handle, phys;
+ if (get_user(handle, uarg))
+ return -EFAULT;
+ phys = mc_find_wsm_l2(instance, handle);
+ if (!phys)
+ return -EFAULT;
+ ret = put_user(phys, uarg);
+ break;
+ }
+ case MC_IO_RESOLVE_CONT_WSM: {
+ struct mc_ioctl_resolv_cont_wsm cont_wsm;
+ uint32_t phys = 0, len = 0;
+ if (copy_from_user(&cont_wsm, uarg, sizeof(cont_wsm)))
+ return -EFAULT;
+ ret = mc_find_cont_wsm(instance, cont_wsm.handle, &phys, &len);
+ if (!ret) {
+ cont_wsm.phys = phys;
+ cont_wsm.length = len;
+ if (copy_to_user(uarg, &cont_wsm, sizeof(cont_wsm)))
+ ret = -EFAULT;
+ }
+ break;
+ }
+ case MC_IO_MAP_MCI:{
+ struct mc_ioctl_map map;
+ if (copy_from_user(&map, uarg, sizeof(map)))
+ return -EFAULT;
+
+ map.reused = (ctx.mci_base.phys != 0);
+ map.phys_addr = (unsigned long)get_mci_base_phys(map.len);
+ if (!map.phys_addr) {
+ MCDRV_DBG_ERROR(mcd, "Failed to setup MCI buffer!");
+ return -EFAULT;
+ }
+
+ if (copy_to_user(uarg, &map, sizeof(map)))
+ ret = -EFAULT;
+ ret = 0;
+ break;
+ }
+ case MC_IO_MAP_PWSM:{
+ break;
+ }
+
+ /* The rest is handled commonly by user IOCTL */
+ default:
+ ret = mc_fd_user_ioctl(file, cmd, arg);
+ } /* end switch(cmd) */
+
+#ifdef MC_MEM_TRACES
+ mobicore_log_read();
#endif
- }
- }
- /* Common code for all mmap calls:
- * map page to user
- * store data in page */
-
- MCDRV_DBG("allocated phys=0x%p - 0x%p, "
- "size=%ld, kernel_virt=0x%p, handle=%d\n",
- phys_addr,
- (void *)((unsigned int)phys_addr+allocated_size),
- allocated_size, virt_kernel_addr_stack, handle);
-
- vmarea->vm_flags |= VM_RESERVED;
- /* convert Kernel address to User Address. Kernel address begins
- at PAGE_OFFSET, user Address range is below PAGE_OFFSET.
- Remapping the area is always done, so multiple mappings
- of one region are possible. Now remap kernel address
- space into user space */
- ret = (int)remap_pfn_range(
- vmarea,
- (vmarea->vm_start),
- addr_to_pfn(phys_addr),
- requested_size,
- vmarea->vm_page_prot);
- if (ret != 0) {
- MCDRV_DBG_ERROR("remapPfnRange failed\n");
-
- /* free allocated pages when mmap fails, however, do not
- do it, when daemon tried to get an MCI that
- existed */
- if (!((request == MC_DRV_KMOD_MMAP_MCI) &&
- (mci_base != 0)))
- free_continguous_pages(virt_kernel_addr_stack,
- (1U << order));
- break;
- }
-
- /* Usual Wsm request, allocate contg_buffer.
- When requesting Mci, we do not associate the page with
- the process.
- Note: we also never free the Mci
- Also, we never free a persistent Tci */
- if (request == MC_DRV_KMOD_MMAP_WSM) {
- contg_buffer->phys_addr = phys_addr;
- contg_buffer->virt_kernel_addr = virt_kernel_addr_stack;
- contg_buffer->virt_user_addr =
- (void *)(vmarea->vm_start);
- contg_buffer->num_pages = (1U << order);
- }
-
- /* set response in allocated buffer */
- {
- struct mc_mmap_resp *mmap_resp =
- (struct mc_mmap_resp *)virt_kernel_addr_stack;
- /* TODO: do this for daemon only, otherwise set NULL */
- mmap_resp->phys_addr = (uint32_t)phys_addr;
- mmap_resp->handle = handle;
- if ((request == MC_DRV_KMOD_MMAP_MCI) &&
- (mci_base != 0)) {
- mmap_resp->is_reused = 1;
- } else
- mmap_resp->is_reused = 0;
- }
-
- /* store MCI pointer */
- if ((request == MC_DRV_KMOD_MMAP_MCI) && (mci_base == 0)) {
- mci_base = (uint32_t)virt_kernel_addr_stack;
- MCDRV_DBG("MCI base set to 0x%x\n", mci_base);
- }
- } while (FALSE);
-
- MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
return (int)ret;
}
-#ifdef CONFIG_SMP
-/*----------------------------------------------------------------------------*/
-/**
- * Force migration of current task to CPU0(where the monitor resides)
+/*
+ * mc_fd_read() - This will be called from user space as read(...)
+ * @file: file pointer
+ * @buffer: buffer where to copy to(userspace)
+ * @buffer_len: number of requested data
+ * @pos: not used
*
- * @return Error code or 0 for success
- */
-static int goto_cpu0(
- void
-)
-{
- int ret = 0;
- struct cpumask mask = CPU_MASK_CPU0;
-
- MCDRV_DBG_VERBOSE("System has %d CPU's, we are on CPU #%d\n"
- "\tBinding this process to CPU #0.\n"
- "\tactive mask is %lx, setting it to mask=%lx\n",
- nr_cpu_ids,
- raw_smp_processor_id(),
- cpu_active_mask->bits[0],
- mask.bits[0]);
- ret = set_cpus_allowed_ptr(current, &mask);
- if (ret != 0)
- MCDRV_DBG_ERROR("set_cpus_allowed_ptr=%d.\n", ret);
- MCDRV_DBG_VERBOSE("And now we are on CPU #%d\n",
- raw_smp_processor_id());
-
- return ret;
-}
-
-/*----------------------------------------------------------------------------*/
-/**
- * Restore CPU mask for current to ALL Cpus(reverse of goto_cpu0)
+ * The read function is blocking until a interrupt occurs. In that case the
+ * event counter is copied into user space and the function is finished.
*
- * @return Error code or 0 for success
+ * If OK this function returns the number of copied data otherwise it returns
+ * errno
*/
-static int goto_all_cpu(
- void
-)
+static ssize_t mc_fd_read(struct file *file, char *buffer, size_t buffer_len,
+ loff_t *pos)
{
- int ret = 0;
+ int ret = 0, ssiq_counter;
+ struct mc_instance *instance = get_instance(file);
- struct cpumask mask = CPU_MASK_ALL;
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
- MCDRV_DBG_VERBOSE("System has %d CPU's, we are on CPU #%d\n"
- "\tBinding this process to CPU #0.\n"
- "\tactive mask is %lx, setting it to mask=%lx\n",
- nr_cpu_ids,
- raw_smp_processor_id(),
- cpu_active_mask->bits[0],
- mask.bits[0]);
- ret = set_cpus_allowed_ptr(current, &mask);
- if (ret != 0)
- MCDRV_DBG_ERROR("set_cpus_allowed_ptr=%d.\n", ret);
- MCDRV_DBG_VERBOSE("And now we are on CPU #%d\n",
- raw_smp_processor_id());
+ /* avoid debug output on non-error, because this is call quite often */
+ MCDRV_DBG_VERBOSE(mcd, "enter\n");
- return ret;
+ /* only the MobiCore Daemon is allowed to call this function */
+ if (WARN_ON(!is_daemon(instance))) {
+ MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n");
+ return -EPERM;
+ }
+
+ if (buffer_len < sizeof(unsigned int)) {
+ MCDRV_DBG_ERROR(mcd, "invalid length\n");
+ return -EINVAL;
+ }
+
+ for (;;) {
+ if (wait_for_completion_interruptible(&ctx.isr_comp)) {
+ MCDRV_DBG_VERBOSE(mcd, "read interrupted\n");
+ return -ERESTARTSYS;
+ }
+
+ ssiq_counter = atomic_read(&ctx.isr_counter);
+ MCDRV_DBG_VERBOSE(mcd, "ssiq_counter=%i, ctx.counter=%i\n",
+ ssiq_counter, ctx.evt_counter);
+
+ if (ssiq_counter != ctx.evt_counter) {
+ /* read data and exit loop without error */
+ ctx.evt_counter = ssiq_counter;
+ ret = 0;
+ break;
+ }
+
+ /* end loop if non-blocking */
+ if (file->f_flags & O_NONBLOCK) {
+ MCDRV_DBG_ERROR(mcd, "non-blocking read\n");
+ return -EAGAIN;
+ }
+
+ if (signal_pending(current)) {
+ MCDRV_DBG_VERBOSE(mcd, "received signal.\n");
+ return -ERESTARTSYS;
+ }
+ }
+
+ /* read data and exit loop */
+ ret = copy_to_user(buffer, &ctx.evt_counter, sizeof(unsigned int));
+
+ if (ret != 0) {
+ MCDRV_DBG_ERROR(mcd, "copy_to_user failed\n");
+ return -EFAULT;
+ }
+
+ ret = sizeof(unsigned int);
+
+ return (ssize_t)ret;
}
-#else
-static int goto_cpu0(void)
-{
- return 0;
-}
-
-static int goto_all_cpu(void)
-{
- return 0;
-}
-#endif
-
-/*----------------------------------------------------------------------------*/
-/**
+/*
* Initialize a new mobicore API instance object
*
* @return Instance or NULL if no allocation was possible.
*/
-struct mc_instance *mobicore_open(
- void
-) {
- struct mc_instance *instance;
- pid_t pid_vnr;
+struct mc_instance *mc_alloc_instance(void)
+{
+ struct mc_instance *instance;
instance = kzalloc(sizeof(*instance), GFP_KERNEL);
if (instance == NULL)
return NULL;
/* get a unique ID for this instance (PIDs are not unique) */
- instance->handle = get_mc_kmod_unique_id();
+ instance->handle = get_unique_id();
- /* get the PID of the calling process. We avoid using
- * current->pid directly, as 2.6.24 introduced PID
- * namespaces. See also http://lwn.net/Articles/259217 */
- pid_vnr = task_pid_vnr(current);
- instance->pid_vnr = pid_vnr;
+ mutex_init(&instance->lock);
return instance;
}
-EXPORT_SYMBOL(mobicore_open);
-/*----------------------------------------------------------------------------*/
-/**
- * This function will be called from user space as fd = open(...).
+/*
+ * Release a mobicore instance object and all objects related to it
+ * @instance: instance
+ * Returns 0 if Ok or -E ERROR
+ */
+int mc_release_instance(struct mc_instance *instance)
+{
+ struct mc_buffer *buffer, *tmp;
+
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
+
+ mutex_lock(&instance->lock);
+ mc_clear_l2_tables(instance);
+
+ mutex_lock(&ctx.bufs_lock);
+ /* release all mapped data */
+
+ /* Check if some buffers are orphaned. */
+ list_for_each_entry_safe(buffer, tmp, &ctx.cont_bufs, list) {
+ if (buffer->instance == instance) {
+ buffer->instance = NULL;
+ free_buffer(buffer);
+ }
+ }
+ mutex_unlock(&ctx.bufs_lock);
+
+ mutex_unlock(&instance->lock);
+
+ /* release instance context */
+ kfree(instance);
+
+ return 0;
+}
+
+/*
+ * mc_fd_user_open() - Will be called from user space as fd = open(...)
* A set of internal instance data are created and initialized.
*
- * @param inode
- * @param file
- * @return 0 if OK or -ENOMEM if no allocation was possible.
+ * @inode
+ * @file
+ * Returns 0 if OK or -ENOMEM if no allocation was possible.
*/
-static int mc_kernel_module_open(
- struct inode *inode,
- struct file *file
-)
+static int mc_fd_user_open(struct inode *inode, struct file *file)
{
- struct mc_instance *instance;
- int ret = 0;
+ struct mc_instance *instance;
- MCDRV_DBG_VERBOSE("enter\n");
+ MCDRV_DBG_VERBOSE(mcd, "enter\n");
- do {
- instance = mobicore_open();
- if (instance == NULL)
- return -ENOMEM;
+ instance = mc_alloc_instance();
+ if (instance == NULL)
+ return -ENOMEM;
- /* check if Daemon. We simply assume that the first to open us
- with root privileges must be the daemon. */
- if ((is_userland_caller_privileged())
- && (mc_drv_kmod_ctx.daemon_inst == NULL)) {
- MCDRV_DBG("accept this as MobiCore Daemon\n");
+ /* store instance data reference */
+ file->private_data = instance;
- /* Set the caller's CPU mask to CPU0*/
- ret = goto_cpu0();
- if (ret != 0) {
- mobicore_release(instance);
- file->private_data = NULL;
- MCDRV_DBG("changing core failed!\n");
- break;
- }
-
- mc_drv_kmod_ctx.daemon_inst = instance;
- sema_init(&mc_drv_kmod_ctx.daemon_ctx.sem,
- DAEMON_SEM_VAL);
- /* init ssiq event counter */
- mc_drv_kmod_ctx.daemon_ctx.ssiq_counter =
- atomic_read(
- &(mc_drv_kmod_ctx.ssiq_ctx.counter));
-
-#ifdef MC_MEM_TRACES
- /* The traces have to be setup on CPU-0 since we must
- * do a fastcall to MobiCore. */
- if (!mci_base)
- /* Do the work only if MCI base is not
- * initialized properly */
- work_on_cpu(0, mobicore_log_setup, NULL);
-#endif
- }
-
- /* store instance data reference */
- file->private_data = instance;
-
- /* TODO axh: link all instances to allow clean up? */
-
- } while (FALSE);
-
- MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
-
- return (int)ret;
-
+ return 0;
}
-/*----------------------------------------------------------------------------*/
-/**
- * Release a mobicore instance object and all objects related to it
- * @param instance instance
- * @return 0 if Ok or -E ERROR
- */
-int mobicore_release(
- struct mc_instance *instance
-)
+static int mc_fd_admin_open(struct inode *inode, struct file *file)
{
- int ret = 0;
- int i;
- struct mc_used_l2_table *used_l2table, *used_l2table_temp;
+ struct mc_instance *instance;
- do {
- /* try to get the semaphore */
- ret = down_interruptible(&(mc_drv_kmod_ctx.wsm_l2_sem));
- if (ret != 0) {
- MCDRV_DBG_ERROR(
- "down_interruptible() failed with %d\n", ret);
- /* TODO: can be block here? */
- ret = -ERESTARTSYS;
- } else {
- /* Check if some WSM is still in use. */
- list_for_each_entry_safe(
- used_l2table,
- used_l2table_temp,
- &(mc_drv_kmod_ctx.mc_used_l2_tables),
- list
- ) {
- if (used_l2table->owner == instance) {
- MCDRV_DBG_WARN(
- "trying to release WSM L2: "
- "physBase=%p ,nr_of_pages=%d\n",
- get_l2_table_phys(used_l2table),
- used_l2table->nr_of_pages);
+ /*
+ * The daemon is already set so we can't allow anybody else to open
+ * the admin interface.
+ */
+ if (ctx.daemon_inst) {
+ MCDRV_DBG_ERROR(mcd, "Daemon is already connected");
+ return -EPERM;
+ }
+ /* Setup the usual variables */
+ if (mc_fd_user_open(inode, file))
+ return -ENOMEM;
+ instance = get_instance(file);
- /* unlock app usage and free if MobiCore
- does not use it */
- delete_used_l2_table(used_l2table,
- FREE_FROM_NWD);
- }
- } /* end while */
+ MCDRV_DBG(mcd, "accept this as MobiCore Daemon\n");
- /* release semaphore */
- up(&(mc_drv_kmod_ctx.wsm_l2_sem));
- }
+ ctx.daemon_inst = instance;
+ ctx.daemon = current;
+ instance->admin = true;
+ init_completion(&ctx.isr_comp);
+ /* init ssiq event counter */
+ ctx.evt_counter = atomic_read(&(ctx.isr_counter));
-
- /* release all mapped data */
- for (i = 0; i < MC_DRV_KMOD_CONTG_BUFFER_MAX; i++) {
- struct mc_contg_buffer *contg_buffer =
- &(instance->contg_buffers[i]);
-
- if (contg_buffer->virt_user_addr != 0) {
- free_continguous_pages(
- contg_buffer->virt_kernel_addr,
- contg_buffer->num_pages);
- }
- }
-
- /* release instance context */
- kfree(instance);
- } while (FALSE);
-
- return ret;
+ return 0;
}
-EXPORT_SYMBOL(mobicore_release);
-/*----------------------------------------------------------------------------*/
-/**
- * This function will be called from user space as close(...).
+/*
+ * mc_fd_release() - This function will be called from user space as close(...)
* The instance data are freed and the associated memory pages are unreserved.
*
- * @param inode
- * @param file
+ * @inode
+ * @file
*
- * @return 0
+ * Returns 0
*/
-static int mc_kernel_module_release(
- struct inode *inode,
- struct file *file
-)
+static int mc_fd_release(struct inode *inode, struct file *file)
{
- int ret = 0;
- struct mc_instance *instance = get_instance(file);
+ int ret = 0;
+ struct mc_instance *instance = get_instance(file);
- MCDRV_DBG_VERBOSE("enter\n");
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
- do {
- /* check if daemon closes us. */
- if (is_caller_mc_daemon(instance)) {
- /* TODO: cleanup?
- * mc_drv_kmod_ctx.mc_used_l2_tables remains */
- MCDRV_DBG_WARN("WARNING: MobiCore Daemon died\n");
- mc_drv_kmod_ctx.daemon_inst = NULL;
- }
+ /* check if daemon closes us. */
+ if (is_daemon(instance)) {
+ MCDRV_DBG_WARN(mcd, "WARNING: MobiCore Daemon died\n");
+ ctx.daemon_inst = NULL;
+ ctx.daemon = NULL;
+ }
- ret = mobicore_release(instance);
+ ret = mc_release_instance(instance);
- } while (FALSE);
-
- MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+ /*
+ * ret is quite irrelevant here as most apps don't care about the
+ * return value from close() and it's quite difficult to recover
+ */
+ MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret);
return (int)ret;
}
-
-/*----------------------------------------------------------------------------*/
-/**
+/*
* This function represents the interrupt function of the mcDrvModule.
* It signals by incrementing of an event counter and the start of the read
* waiting queue, the read function a interrupt has occurred.
- *
- * @param intr
- * @param *context pointer to registered device data
- *
- * @return IRQ_HANDLED
*/
-static irqreturn_t mc_kernel_module_intr_ssiq(
- int intr,
- void *context
-)
+static irqreturn_t mc_ssiq_isr(int intr, void *context)
{
- irqreturn_t ret = IRQ_NONE;
+ /* increment interrupt event counter */
+ atomic_inc(&(ctx.isr_counter));
- /* we know the context. */
- MCDRV_ASSERT(&mc_drv_kmod_ctx == context);
+ /* signal the daemon */
+ complete(&ctx.isr_comp);
- do {
- if (intr != MC_INTR_SSIQ) {
- /* this should not happen, as we did no register for any
- other interrupt. For debugging, we print a
- message, but continue */
- MCDRV_DBG_WARN(
- "unknown interrupt %d, expecting only %d\n",
- intr, MC_INTR_SSIQ);
- }
- MCDRV_DBG_VERBOSE("received interrupt %d\n",
- intr);
-
- /* increment interrupt event counter */
- atomic_inc(&(mc_drv_kmod_ctx.ssiq_ctx.counter));
-
- /* signal the daemon */
- up(&mc_drv_kmod_ctx.daemon_ctx.sem);
-
-
- ret = IRQ_HANDLED;
-
- } while (FALSE);
-
- return ret;
+ return IRQ_HANDLED;
}
-/*----------------------------------------------------------------------------*/
-/** function table structure of this device driver. */
-static const struct file_operations mc_kernel_module_file_operations = {
- .owner = THIS_MODULE, /**< driver owner */
- .open = mc_kernel_module_open, /**< driver open function */
- .release = mc_kernel_module_release, /**< driver release function*/
- .unlocked_ioctl = mc_kernel_module_ioctl, /**< driver ioctl function */
- .mmap = mc_kernel_module_mmap, /**< driver mmap function */
- .read = mc_kernel_module_read, /**< driver read function */
+/* function table structure of this device driver. */
+static const struct file_operations mc_admin_fops = {
+ .owner = THIS_MODULE,
+ .open = mc_fd_admin_open,
+ .release = mc_fd_release,
+ .unlocked_ioctl = mc_fd_admin_ioctl,
+ .mmap = mc_fd_mmap,
+ .read = mc_fd_read,
};
-/*----------------------------------------------------------------------------*/
-/** registration structure as miscdevice. */
-static struct miscdevice mc_kernel_module_device = {
- .name = MC_DRV_MOD_DEVNODE, /**< device name */
- .minor = MISC_DYNAMIC_MINOR, /**< device minor number */
- /** device interface function structure */
- .fops = &mc_kernel_module_file_operations,
+static struct miscdevice mc_admin_device = {
+ .name = MC_ADMIN_DEVNODE,
+ .mode = (S_IRWXU),
+ .minor = MISC_DYNAMIC_MINOR,
+ .fops = &mc_admin_fops,
};
+/* function table structure of this device driver. */
+static const struct file_operations mc_user_fops = {
+ .owner = THIS_MODULE,
+ .open = mc_fd_user_open,
+ .release = mc_fd_release,
+ .unlocked_ioctl = mc_fd_user_ioctl,
+ .mmap = mc_fd_mmap,
+};
-/*----------------------------------------------------------------------------*/
-/**
+static struct miscdevice mc_user_device = {
+ .name = MC_USER_DEVNODE,
+ .mode = (S_IRWXU | S_IRWXG | S_IRWXO),
+ .minor = MISC_DYNAMIC_MINOR,
+ .fops = &mc_user_fops,
+};
+
+/*
* This function is called the kernel during startup or by a insmod command.
* This device is installed and registered as miscdevice, then interrupt and
* queue handling is set up
- *
- * @return 0 for no error or -EIO if registration fails
*/
-static int __init mc_kernel_module_init(
- void
-)
+static int __init mobicore_init(void)
{
int ret = 0;
- MCDRV_DBG("enter (Build " __TIMESTAMP__ ")\n");
- MCDRV_DBG("mcDrvModuleApi version is %i.%i\n",
- MCDRVMODULEAPI_VERSION_MAJOR,
- MCDRVMODULEAPI_VERSION_MINOR);
+ dev_set_name(mcd, "mcd");
+
+ MCDRV_DBG(mcd, "enter (Build " __TIMESTAMP__ ")\n");
+ MCDRV_DBG(mcd, "mcDrvModuleApi version is %i.%i\n",
+ MCDRVMODULEAPI_VERSION_MAJOR,
+ MCDRVMODULEAPI_VERSION_MINOR);
#ifdef MOBICORE_COMPONENT_BUILD_TAG
- MCDRV_DBG("%s\n", MOBICORE_COMPONENT_BUILD_TAG);
+ MCDRV_DBG(mcd, "%s\n", MOBICORE_COMPONENT_BUILD_TAG);
#endif
- do {
- /* Hardware does not support ARM TrustZone
- -> Cannot continue! */
- if (!has_security_extensions()) {
- MCDRV_DBG_ERROR(
- "Hardware does't support ARM TrustZone!\n");
- ret = -ENODEV;
- break;
- }
+ /* Hardware does not support ARM TrustZone -> Cannot continue! */
+ if (!has_security_extensions()) {
+ MCDRV_DBG_ERROR(mcd,
+ "Hardware doesn't support ARM TrustZone!\n");
+ return -ENODEV;
+ }
- /* Running in secure mode -> Cannot load the driver! */
- if (is_secure_mode()) {
- MCDRV_DBG_ERROR("Running in secure MODE!\n");
- ret = -ENODEV;
- break;
- }
+ /* Running in secure mode -> Cannot load the driver! */
+ if (is_secure_mode()) {
+ MCDRV_DBG_ERROR(mcd, "Running in secure MODE!\n");
+ return -ENODEV;
+ }
- sema_init(&mc_drv_kmod_ctx.daemon_ctx.sem, DAEMON_SEM_VAL);
- /* set up S-SIQ interrupt handler */
- ret = request_irq(
- MC_INTR_SSIQ,
- mc_kernel_module_intr_ssiq,
- IRQF_TRIGGER_RISING,
- MC_DRV_MOD_DEVNODE,
- &mc_drv_kmod_ctx);
- if (ret != 0) {
- MCDRV_DBG_ERROR("interrupt request failed\n");
- break;
- }
+ init_completion(&ctx.isr_comp);
+ /* set up S-SIQ interrupt handler */
+ ret = request_irq(MC_INTR_SSIQ, mc_ssiq_isr, IRQF_TRIGGER_RISING,
+ MC_ADMIN_DEVNODE, &ctx);
+ if (ret != 0) {
+ MCDRV_DBG_ERROR(mcd, "interrupt request failed\n");
+ goto error;
+ }
- ret = misc_register(&mc_kernel_module_device);
- if (ret != 0) {
- MCDRV_DBG_ERROR("device register failed\n");
- break;
- }
+#ifdef MC_PM_RUNTIME
+ ret = mc_pm_initialize(&ctx);
+ if (ret != 0) {
+ MCDRV_DBG_ERROR(mcd, "Power Management init failed!\n");
+ goto free_isr;
+ }
+#endif
- /* initialize event counter for signaling of an IRQ to zero */
- atomic_set(&(mc_drv_kmod_ctx.ssiq_ctx.counter), 0);
+ ret = misc_register(&mc_admin_device);
+ if (ret != 0) {
+ MCDRV_DBG_ERROR(mcd, "admin device register failed\n");
+ goto free_isr;
+ }
- /* init list for WSM L2 chunks. */
- INIT_LIST_HEAD(&(mc_drv_kmod_ctx.mc_l2_tables_sets));
+ ret = misc_register(&mc_user_device);
+ if (ret != 0) {
+ MCDRV_DBG_ERROR(mcd, "user device register failed\n");
+ goto free_admin;
+ }
- /* L2 table descriptor list. */
- INIT_LIST_HEAD(&(mc_drv_kmod_ctx.mc_used_l2_tables));
+#ifdef MC_MEM_TRACES
+ mobicore_log_setup();
+#endif
- sema_init(&(mc_drv_kmod_ctx.wsm_l2_sem), 1);
+ /* initialize event counter for signaling of an IRQ to zero */
+ atomic_set(&ctx.isr_counter, 0);
- /* initialize unique number counter which we can use for
- handles. It is limited to 2^32, but this should be
- enough to be roll-over safe for us. We start with 1
- instead of 0. */
- atomic_set(&(mc_drv_kmod_ctx.unique_counter), 1);
+ ret = mc_init_l2_tables();
- mci_base = 0;
- MCDRV_DBG("initialized\n");
+ /*
+ * initialize unique number counter which we can use for
+ * handles. It is limited to 2^32, but this should be
+ * enough to be roll-over safe for us. We start with 1
+ * instead of 0.
+ */
+ atomic_set(&ctx.unique_counter, 1);
- ret = 0;
+ /* init list for contiguous buffers */
+ INIT_LIST_HEAD(&ctx.cont_bufs);
- } while (FALSE);
+ /* init lock for the buffers list */
+ mutex_init(&ctx.bufs_lock);
- MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+ memset(&ctx.mci_base, 0, sizeof(ctx.mci_base));
+ MCDRV_DBG(mcd, "initialized\n");
+ return 0;
- return (int)ret;
+free_admin:
+ misc_deregister(&mc_admin_device);
+free_isr:
+ free_irq(MC_INTR_SSIQ, &ctx);
+error:
+ return ret;
}
-
-
-/*----------------------------------------------------------------------------*/
-/**
+/*
* This function removes this device driver from the Linux device manager .
*/
-static void __exit mc_kernel_module_exit(
- void
-)
+static void __exit mobicore_exit(void)
{
- struct mc_used_l2_table *used_l2table;
-
- MCDRV_DBG_VERBOSE("enter\n");
-
+ MCDRV_DBG_VERBOSE(mcd, "enter\n");
+#ifdef MC_MEM_TRACES
mobicore_log_free();
+#endif
- /* Check if some WSM is still in use. */
- list_for_each_entry(
- used_l2table,
- &(mc_drv_kmod_ctx.mc_used_l2_tables),
- list
- ) {
- MCDRV_DBG_WARN(
- "WSM L2 still in use: physBase=%p ,nr_of_pages=%d\n",
- get_l2_table_phys(used_l2table),
- used_l2table->nr_of_pages);
- } /* end while */
+ mc_release_l2_tables();
- free_irq(MC_INTR_SSIQ, &mc_drv_kmod_ctx);
+#ifdef MC_PM_RUNTIME
+ mc_pm_free();
+#endif
- misc_deregister(&mc_kernel_module_device);
- MCDRV_DBG_VERBOSE("exit");
+ free_irq(MC_INTR_SSIQ, &ctx);
+
+ misc_deregister(&mc_admin_device);
+ misc_deregister(&mc_user_device);
+ MCDRV_DBG_VERBOSE(mcd, "exit");
}
-
-/*----------------------------------------------------------------------------*/
/* Linux Driver Module Macros */
-module_init(mc_kernel_module_init);
-module_exit(mc_kernel_module_exit);
+module_init(mobicore_init);
+module_exit(mobicore_exit);
MODULE_AUTHOR("Giesecke & Devrient GmbH");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("MobiCore driver");
-/** @} */
-
diff --git a/drivers/gud/mobicore_driver/main.h b/drivers/gud/mobicore_driver/main.h
new file mode 100644
index 0000000..e23c516
--- /dev/null
+++ b/drivers/gud/mobicore_driver/main.h
@@ -0,0 +1,144 @@
+/*
+ * Header file of MobiCore Driver Kernel Module.
+ *
+ * Internal structures of the McDrvModule
+ *
+ * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MC_MAIN_H_
+#define _MC_MAIN_H_
+
+#include <asm/pgtable.h>
+#include <linux/semaphore.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+
+#include "public/mc_linux.h"
+/* Platform specific settings */
+#include "platform.h"
+
+#define MC_VERSION(major, minor) \
+ (((major & 0x0000ffff) << 16) | (minor & 0x0000ffff))
+
+/* Instance data for MobiCore Daemon and TLCs. */
+struct mc_instance {
+ /* Instance lock */
+ struct mutex lock;
+ /* unique handle */
+ unsigned int handle;
+ bool admin;
+};
+
+/*
+ * Contiguous buffer allocated to TLCs.
+ * These buffers are uses as world shared memory (wsm) and shared with
+ * secure world.
+ * The virtual kernel address is added for a simpler search algorithm.
+ */
+struct mc_buffer {
+ struct list_head list;
+ /* unique handle */
+ unsigned int handle;
+ /* Number of references kept to this buffer */
+ atomic_t usage;
+ /* virtual Kernel start address */
+ void *addr;
+ /* physical start address */
+ void *phys;
+ /* order of number of pages */
+ unsigned int order;
+ uint32_t len;
+ struct mc_instance *instance;
+};
+
+/* MobiCore Driver Kernel Module context data. */
+struct mc_context {
+ /* MobiCore MCI information */
+ struct mc_buffer mci_base;
+ /* MobiCore MCP buffer */
+ struct mc_mcp_buffer *mcp;
+ /* event completion */
+ struct completion isr_comp;
+ /* isr event counter */
+ unsigned int evt_counter;
+ atomic_t isr_counter;
+ /* ever incrementing counter */
+ atomic_t unique_counter;
+ /* pointer to instance of daemon */
+ struct mc_instance *daemon_inst;
+ /* pointer to instance of daemon */
+ struct task_struct *daemon;
+ /* General list of contiguous buffers allocated by the kernel */
+ struct list_head cont_bufs;
+ /* Lock for the list of contiguous buffers */
+ struct mutex bufs_lock;
+};
+
+struct mc_sleep_mode {
+ uint16_t SleepReq;
+ uint16_t ReadyToSleep;
+};
+
+/* MobiCore is idle. No scheduling required. */
+#define SCHEDULE_IDLE 0
+/* MobiCore is non idle, scheduling is required. */
+#define SCHEDULE_NON_IDLE 1
+
+/* MobiCore status flags */
+struct mc_flags {
+ /*
+ * Scheduling hint: if <> SCHEDULE_IDLE, MobiCore should
+ * be scheduled by the NWd
+ */
+ uint32_t schedule;
+ /* State of sleep protocol */
+ struct mc_sleep_mode sleep_mode;
+ /* Reserved for future use: Must not be interpreted */
+ uint32_t rfu[2];
+};
+
+/* MCP buffer structure */
+struct mc_mcp_buffer {
+ /* MobiCore Flags */
+ struct mc_flags flags;
+ uint32_t rfu; /* MCP message buffer - ignore */
+};
+
+unsigned int get_unique_id(void);
+
+/* check if caller is MobiCore Daemon */
+static inline bool is_daemon(struct mc_instance *instance)
+{
+ if (!instance)
+ return false;
+ return instance->admin;
+}
+
+
+/* Initialize a new mobicore API instance object */
+struct mc_instance *mc_alloc_instance(void);
+/* Release a mobicore instance object and all objects related to it */
+int mc_release_instance(struct mc_instance *instance);
+
+/*
+ * mc_register_wsm_l2() - Create a L2 table from a virtual memory buffer which
+ * can be vmalloc or user space virtual memory
+ */
+int mc_register_wsm_l2(struct mc_instance *instance,
+ uint32_t buffer, uint32_t len,
+ uint32_t *handle, uint32_t *phys);
+/* Unregister the buffer mapped above */
+int mc_unregister_wsm_l2(struct mc_instance *instance, uint32_t handle);
+
+/* Allocate one mc_buffer of contiguous space */
+int mc_get_buffer(struct mc_instance *instance,
+ struct mc_buffer **buffer, unsigned long len);
+/* Free the buffer allocated above */
+int mc_free_buffer(struct mc_instance *instance, uint32_t handle);
+
+#endif /* _MC_MAIN_H_ */
diff --git a/drivers/gud/mobicore_driver/mc_drv_module.h b/drivers/gud/mobicore_driver/mc_drv_module.h
deleted file mode 100644
index 8b402d6..0000000
--- a/drivers/gud/mobicore_driver/mc_drv_module.h
+++ /dev/null
@@ -1,238 +0,0 @@
-/**
- * Header file of MobiCore Driver Kernel Module.
- *
- * @addtogroup MCD_MCDIMPL_KMOD_IMPL
- * @{
- * Internal structures of the McDrvModule
- * @file
- *
- * Header file the MobiCore Driver Kernel Module,
- * its internal structures and defines.
- *
- * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _MC_DRV_KMOD_H_
-#define _MC_DRV_KMOD_H_
-
-#include "mc_drv_module_linux_api.h"
-#include "public/mc_drv_module_api.h"
-/** Platform specific settings */
-#include "platform.h"
-
-/** ARM Specific masks and modes */
-#define ARM_CPSR_MASK 0x1F
-#define ARM_MONITOR_MODE 0b10110
-#define ARM_SECURITY_EXTENSION_MASK 0x30
-
-/**
- * Number of page table entries in one L2 table. This is ARM specific, an
- * L2 table covers 1 MiB by using 256 entry referring to 4KiB pages each.
- */
-#define MC_ARM_L2_TABLE_ENTRIES 256
-
-/** Maximum number of contiguous buffer allocations for one driver instance. */
-#define MC_DRV_KMOD_CONTG_BUFFER_MAX 16
-
-/** Number of pages for L2 tables. There are 4 table in each page. */
-#define MC_DRV_KMOD_L2_TABLE_PER_PAGES 4
-
-/** ARM level 2 (L2) table with 256 entries. Size: 1k */
-struct l2table {
- pte_t table_entries[MC_ARM_L2_TABLE_ENTRIES];
-};
-
-#define INVALID_ADDRESS ((void *)(-1))
-
-/** ARM L2 PTE bits */
-#define L2_FLAG_SMALL_XN (1U << 0)
-#define L2_FLAG_SMALL (1U << 1)
-#define L2_FLAG_B (1U << 2)
-#define L2_FLAG_C (1U << 3)
-#define L2_FLAG_AP0 (1U << 4)
-#define L2_FLAG_AP1 (1U << 5)
-#define L2_FLAG_SMALL_TEX0 (1U << 6)
-#define L2_FLAG_SMALL_TEX1 (1U << 7)
-#define L2_FLAG_SMALL_TEX2 (1U << 8)
-#define L2_FLAG_APX (1U << 9)
-#define L2_FLAG_S (1U << 10)
-#define L2_FLAG_NG (1U << 11)
-
-/**
- * Contiguous buffer allocated to TLCs.
- * These buffers are uses as world shared memory (wsm) and shared with
- * secure world.
- * The virtual kernel address is added for a simpler search algorithm.
- */
-struct mc_contg_buffer {
- unsigned int handle; /* unique handle */
- void *virt_user_addr; /**< virtual User start address */
- void *virt_kernel_addr; /**< virtual Kernel start address */
- void *phys_addr; /**< physical start address */
- unsigned int num_pages; /**< number of pages */
-};
-
-/** Instance data for MobiCore Daemon and TLCs. */
-struct mc_instance {
- /** unique handle */
- unsigned int handle;
- /** process that opened this instance */
- pid_t pid_vnr;
- /** buffer list for mmap generated address space and
- its virtual client address */
- struct mc_contg_buffer contg_buffers[MC_DRV_KMOD_CONTG_BUFFER_MAX];
-};
-
-/** Store for four L2 tables in one 4kb page*/
-struct mc_l2_table_store {
- struct l2table table[MC_DRV_KMOD_L2_TABLE_PER_PAGES];
-};
-
-/** Usage and maintenance information about mc_l2_table_store */
-struct mc_l2_tables_set {
- struct list_head list;
- unsigned int usage_bitmap; /**< usage bitmap */
- struct mc_l2_table_store *kernel_virt; /**< kernel virtual address */
- struct mc_l2_table_store *phys; /**< physical address */
- struct page *page; /**< pointer to page struct */
-};
-
-/**
- * L2 table allocated to the Daemon or a TLC describing a world shared buffer.
- * When users map a malloc()ed area into SWd, a L2 table is allocated.
- * In addition, the area of maximum 1MB virtual address space is mapped into
- * the L2 table and a handle for this table is returned to the user.
- */
-struct mc_used_l2_table {
- struct list_head list;
-
- /** handle as communicated to user mode */
- unsigned int handle;
- unsigned int flags;
-
- /** owner of this L2 table */
- struct mc_instance *owner;
-
- /** set describing where our L2 table is stored */
- struct mc_l2_tables_set *set;
-
- /** index into L2 table set */
- unsigned int idx;
-
- /** size of buffer */
- unsigned int nr_of_pages;
-};
-
-#define MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_APP (1U << 0)
-#define MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC (1U << 1)
-
-
-/** MobiCore S-SIQ interrupt context data. */
-struct mc_ssiq_ctx {
- /** S-SIQ interrupt counter */
- atomic_t counter;
-};
-
-/** MobiCore Daemon context data. */
-struct mc_daemon_ctx {
- /** event semaphore */
- struct semaphore sem;
- struct fasync_struct *async_queue;
- /** event counter */
- unsigned int ssiq_counter;
-};
-
-/** MobiCore Driver Kernel Module context data. */
-struct mc_drv_kmod_ctx {
-
- /** ever incrementing counter */
- atomic_t unique_counter;
-
- /** S-SIQ interrupt context */
- struct mc_ssiq_ctx ssiq_ctx;
-
- /** MobiCore Daemon context */
- struct mc_daemon_ctx daemon_ctx;
-
- /** pointer to instance of daemon */
- struct mc_instance *daemon_inst;
-
- /** Backing store for L2 tables */
- struct list_head mc_l2_tables_sets;
-
- /** Bookkeeping for used L2 tables */
- struct list_head mc_used_l2_tables;
-
- /** semaphore to synchronize access to above lists */
- struct semaphore wsm_l2_sem;
-};
-
-/** MobiCore internal trace buffer structure. */
-struct mc_trace_buf {
- uint32_t version; /**< version of trace buffer */
- uint32_t length; /**< length of allocated buffer(includes header) */
- uint32_t write_pos; /**< last write position */
- char buff[1]; /**< start of the log buffer */
-};
-
-/*** MobiCore internal trace log setup. */
-void mobicore_log_read(void);
-long mobicore_log_setup(void *);
-void mobicore_log_free(void);
-
-#define MCDRV_DBG_ERROR(txt, ...) \
- printk(KERN_ERR "mcDrvKMod [%d] %s() ### ERROR: " txt, \
- task_pid_vnr(current), \
- __func__, \
- ##__VA_ARGS__)
-
-/* dummy function helper macro. */
-#define DUMMY_FUNCTION() do {} while (0)
-
-#if defined(DEBUG)
-
-/* #define DEBUG_VERBOSE */
-#if defined(DEBUG_VERBOSE)
-#define MCDRV_DBG_VERBOSE MCDRV_DBG
-#else
-#define MCDRV_DBG_VERBOSE(...) DUMMY_FUNCTION()
-#endif
-
-#define MCDRV_DBG(txt, ...) \
- printk(KERN_INFO "mcDrvKMod [%d on CPU%d] %s(): " txt, \
- task_pid_vnr(current), \
- raw_smp_processor_id(), \
- __func__, \
- ##__VA_ARGS__)
-
-#define MCDRV_DBG_WARN(txt, ...) \
- printk(KERN_WARNING "mcDrvKMod [%d] %s() WARNING: " txt, \
- task_pid_vnr(current), \
- __func__, \
- ##__VA_ARGS__)
-
-#define MCDRV_ASSERT(cond) \
- do { \
- if (unlikely(!(cond))) { \
- panic("mcDrvKMod Assertion failed: %s:%d\n", \
- __FILE__, __LINE__); \
- } \
- } while (0)
-
-#else
-
-#define MCDRV_DBG_VERBOSE(...) DUMMY_FUNCTION()
-#define MCDRV_DBG(...) DUMMY_FUNCTION()
-#define MCDRV_DBG_WARN(...) DUMMY_FUNCTION()
-
-#define MCDRV_ASSERT(...) DUMMY_FUNCTION()
-
-#endif /* [not] defined(DEBUG) */
-
-
-#endif /* _MC_DRV_KMOD_H_ */
-/** @} */
diff --git a/drivers/gud/mobicore_driver/mc_drv_module_android.h b/drivers/gud/mobicore_driver/mc_drv_module_android.h
deleted file mode 100644
index 319509f..0000000
--- a/drivers/gud/mobicore_driver/mc_drv_module_android.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/**
- * Header file of MobiCore Driver Kernel Module.
- *
- * @addtogroup MobiCore_Driver_Kernel_Module
- * @{
- * Android specific defines
- * @file
- *
- * Android specific defines
- *
- * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _MC_DRV_MODULE_ANDROID_H_
-#define _MC_DRV_MODULE_ANDROID_H_
-
-/* Defines needed to identify the Daemon in Android systems
- * For the full list see:
- * platform_system_core/include/private/android_filesystem_config.h in the
- * Android source tree
- */
-/* traditional unix root user */
-#define AID_ROOT 0
-/* system server */
-#define AID_SYSTEM 1000
-/* access to misc storage */
-#define AID_MISC 9998
-#define AID_NOBODY 9999
-/* first app user */
-#define AID_APP 10000
-
-#endif /* _MC_DRV_MODULE_ANDROID_H_ */
-/** @} */
diff --git a/drivers/gud/mobicore_driver/mc_drv_module_fastcalls.h b/drivers/gud/mobicore_driver/mc_drv_module_fastcalls.h
deleted file mode 100644
index d058043..0000000
--- a/drivers/gud/mobicore_driver/mc_drv_module_fastcalls.h
+++ /dev/null
@@ -1,227 +0,0 @@
-/**
- * Header file of MobiCore Driver Kernel Module.
- *
- * @addtogroup MobiCore_Driver_Kernel_Module
- * @{
- * Internal structures of the McDrvModule
- * @file
- *
- * MobiCore Fast Call interface
- *
- * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _MC_DRV_MODULE_FC_H_
-#define _MC_DRV_MODULE_FC_H_
-
-#include "mc_drv_module.h"
-
-/**
- * MobiCore SMCs
- */
-enum mc_smc_codes {
- MC_SMC_N_YIELD = 0x3, /**< Yield to switch from NWd to SWd. */
- MC_SMC_N_SIQ = 0x4 /**< SIQ to switch from NWd to SWd. */
-};
-
-/**
- * MobiCore fast calls. See MCI documentation
- */
-enum mc_fast_call_codes {
- MC_FC_INIT = -1,
- MC_FC_INFO = -2,
- MC_FC_POWER = -3,
- MC_FC_DUMP = -4,
- MC_FC_NWD_TRACE = -31 /**< Mem trace setup fastcall */
-};
-
-/**
- * return code for fast calls
- */
-enum mc_fast_calls_result {
- MC_FC_RET_OK = 0,
- MC_FC_RET_ERR_INVALID = 1,
- MC_FC_RET_ERR_ALREADY_INITIALIZED = 5
-};
-
-
-
-/*------------------------------------------------------------------------------
- structure wrappers for specific fastcalls
-------------------------------------------------------------------------------*/
-
-/** generic fast call parameters */
-union fc_generic {
- struct {
- uint32_t cmd;
- uint32_t param[3];
- } as_in;
- struct {
- uint32_t resp;
- uint32_t ret;
- uint32_t param[2];
- } as_out;
-};
-
-
-/** fast call init */
-union mc_fc_init {
- union fc_generic as_generic;
- struct {
- uint32_t cmd;
- uint32_t base;
- uint32_t nq_info;
- uint32_t mcp_info;
- } as_in;
- struct {
- uint32_t resp;
- uint32_t ret;
- uint32_t rfu[2];
- } as_out;
-};
-
-
-/** fast call info parameters */
-union mc_fc_info {
- union fc_generic as_generic;
- struct {
- uint32_t cmd;
- uint32_t ext_info_id;
- uint32_t rfu[2];
- } as_in;
- struct {
- uint32_t resp;
- uint32_t ret;
- uint32_t state;
- uint32_t ext_info;
- } as_out;
-};
-
-
-/** fast call S-Yield parameters */
-union mc_fc_s_yield {
- union fc_generic as_generic;
- struct {
- uint32_t cmd;
- uint32_t rfu[3];
- } as_in;
- struct {
- uint32_t resp;
- uint32_t ret;
- uint32_t rfu[2];
- } as_out;
-};
-
-
-/** fast call N-SIQ parameters */
-union mc_fc_nsiq {
- union fc_generic as_generic;
- struct {
- uint32_t cmd;
- uint32_t rfu[3];
- } as_in;
- struct {
- uint32_t resp;
- uint32_t ret;
- uint32_t rfu[2];
- } as_out;
-};
-
-
-/*----------------------------------------------------------------------------*/
-/**
- * fast call to MobiCore
- *
- * @param fc_generic pointer to fast call data
- */
-static inline void mc_fastcall(
- union fc_generic *fc_generic
-)
-{
- MCDRV_ASSERT(fc_generic != NULL);
- /* We only expect to make smc calls on CPU0 otherwise something wrong
- * will happen */
- MCDRV_ASSERT(raw_smp_processor_id() == 0);
- mb();
-#ifdef MC_SMC_FASTCALL
- {
- int ret = 0;
- MCDRV_DBG("Going into SCM()");
- ret = smc_fastcall((void *)fc_generic, sizeof(*fc_generic));
- MCDRV_DBG("Coming from SCM, scm_call=%i, resp=%d/0x%x\n",
- ret,
- fc_generic->as_out.resp, fc_generic->as_out.resp);
- }
-#else
- {
- /* SVC expect values in r0-r3 */
- register u32 reg0 __asm__("r0") = fc_generic->as_in.cmd;
- register u32 reg1 __asm__("r1") = fc_generic->as_in.param[0];
- register u32 reg2 __asm__("r2") = fc_generic->as_in.param[1];
- register u32 reg3 __asm__("r3") = fc_generic->as_in.param[2];
-
- /* one of the famous preprocessor hacks to stingitize things.*/
-#define __STR2(x) #x
-#define __STR(x) __STR2(x)
-
- /* compiler does not support certain instructions
- "SMC": secure monitor call.*/
-#define ASM_ARM_SMC 0xE1600070
- /* "BPKT": debugging breakpoint. We keep this, as is comes
- quite handy for debugging. */
-#define ASM_ARM_BPKT 0xE1200070
-#define ASM_THUMB_BPKT 0xBE00
-
-
- __asm__ volatile (
- ".word " __STR(ASM_ARM_SMC) "\n"
- : "+r"(reg0), "+r"(reg1), "+r"(reg2), "+r"(reg3)
- );
-
- /* set response */
- fc_generic->as_out.resp = reg0;
- fc_generic->as_out.ret = reg1;
- fc_generic->as_out.param[0] = reg2;
- fc_generic->as_out.param[1] = reg3;
- }
-#endif
-}
-
-
-/*----------------------------------------------------------------------------*/
-/**
- * convert fast call return code to linux driver module error code
- *
- */
-static inline int convert_fc_ret(
- uint32_t sret
-)
-{
- int ret = -EFAULT;
-
- switch (sret) {
-
- case MC_FC_RET_OK:
- ret = 0;
- break;
-
- case MC_FC_RET_ERR_INVALID:
- ret = -EINVAL;
- break;
-
- case MC_FC_RET_ERR_ALREADY_INITIALIZED:
- ret = -EBUSY;
- break;
-
- default:
- break;
- } /* end switch( sret ) */
- return ret;
-}
-
-#endif /* _MC_DRV_MODULE_FC_H_ */
-/** @} */
diff --git a/drivers/gud/mobicore_driver/mc_drv_module_linux_api.h b/drivers/gud/mobicore_driver/mc_drv_module_linux_api.h
deleted file mode 100644
index b2a99f1..0000000
--- a/drivers/gud/mobicore_driver/mc_drv_module_linux_api.h
+++ /dev/null
@@ -1,187 +0,0 @@
-/**
- * Header file of MobiCore Driver Kernel Module.
- *
- * @addtogroup MobiCore_Driver_Kernel_Module
- * @{
- * Wrapper for Linux API
- * @file
- *
- * Some convenient wrappers for memory functions
- *
- * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _MC_DRV_MODULE_LINUX_API_H_
-#define _MC_DRV_MODULE_LINUX_API_H_
-
-#include <linux/version.h>
-#include <linux/miscdevice.h>
-#include <linux/interrupt.h>
-#include <linux/highmem.h>
-#include <linux/kthread.h>
-#include <linux/io.h>
-#include <linux/uaccess.h>
-#include <asm/sizes.h>
-#include <asm/pgtable.h>
-#include <linux/semaphore.h>
-#include <linux/moduleparam.h>
-#include <linux/slab.h>
-
-
-/* make some nice types */
-#if !defined(TRUE)
-#define TRUE (1 == 1)
-#endif
-
-#if !defined(FALSE)
-#define FALSE (1 != 1)
-#endif
-
-
-/* Linux GCC modifiers */
-#if !defined(__init)
-#warning "missing definition: __init"
-/* define a dummy */
-#define __init
-#endif
-
-
-#if !defined(__exit)
-#warning "missing definition: __exit"
-/* define a dummy */
-#define __exit
-#endif
-
-
-#if !defined(__must_check)
-#warning "missing definition: __must_check"
-/* define a dummy */
-#define __must_check
-#endif
-
-
-#if !defined(__user)
-#warning "missing definition: __user"
-/* define a dummy */
-#define __user
-#endif
-
-#define INVALID_ORDER ((unsigned int)(-1))
-
-/*----------------------------------------------------------------------------*/
-/* get start address of the 4 KiB page where the given addres is located in. */
-static inline void *get_page_start(
- void *addr
-)
-{
- return (void *)(((unsigned long)(addr)) & PAGE_MASK);
-}
-
-/*----------------------------------------------------------------------------*/
-/* get offset into the 4 KiB page where the given addres is located in. */
-static inline unsigned int get_offset_in_page(
- void *addr
-)
-{
- return (unsigned int)(((unsigned long)(addr)) & (~PAGE_MASK));
-}
-
-/*----------------------------------------------------------------------------*/
-/* get number of pages for a given buffer. */
-static inline unsigned int get_nr_of_pages_for_buffer(
- void *addr_start, /* may be null */
- unsigned int len
-)
-{
- /* calculate used number of pages. Example:
- offset+size newSize+PAGE_SIZE-1 nr_of_pages
- 0 4095 0
- 1 4096 1
- 4095 8190 1
- 4096 8191 1
- 4097 8192 2 */
-
- return (get_offset_in_page(addr_start) + len + PAGE_SIZE-1) / PAGE_SIZE;
-}
-
-
-/*----------------------------------------------------------------------------*/
-/**
- * convert a given size to page order, which is equivalent to finding log_2(x).
- * The maximum for order was 5 in Linux 2.0 corresponding to 32 pages.
- * Later versions allow 9 corresponding to 512 pages, which is 2 MB on
- * most platforms). Anyway, the bigger order is, the more likely it is
- * that the allocation will fail.
- * Size 0 1 4097 8193 12289 24577 28673 40961 61441
- * Pages - 1 2 3 4 7 8 15 16
- * Order INVALID_ORDER 0 1 1 2 2 3 3 4
- *
- * @param size
- * @return order
- */
-static inline unsigned int size_to_order(
- unsigned int size
-)
-{
- unsigned int order = INVALID_ORDER;
-
- if (size != 0) {
- /* ARMv5 as a CLZ instruction which count the leading zeros of
- the binary representation of a value. It return a value
- between 0 and 32.
- Value 0 1 2 3 4 5 6 7 8 9 10 ...
- CLZ 32 31 30 30 29 29 29 29 28 28 28 ...
-
- We have excluded Size==0 before, so this is safe. */
- order = __builtin_clz(
- get_nr_of_pages_for_buffer(NULL, size));
-
- /* there is a size overflow in get_nr_of_pages_for_buffer when
- * the size is too large */
- if (unlikely(order > 31))
- return INVALID_ORDER;
- order = 31 - order;
-
- /* above algorithm rounds down: clz(5)=2 instead of 3 */
- /* quick correction to fix it: */
- if (((1<<order)*PAGE_SIZE) < size)
- order++;
- }
- return order;
-}
-
-/* magic linux macro */
-#if !defined(list_for_each_entry)
-/* stop compiler */
-#error "missing macro: list_for_each_entry()"
-/* define a dummy */
-#define list_for_each_entry(a, b, c) if (0)
-#endif
-
-/*----------------------------------------------------------------------------*/
-/* return the page frame number of an address */
-static inline unsigned int addr_to_pfn(
- void *addr
-)
-{
- /* there is no real API for this */
- return ((unsigned int)(addr)) >> PAGE_SHIFT;
-}
-
-
-/*----------------------------------------------------------------------------*/
-/* return the address of a page frame number */
-static inline void *pfn_to_addr(
- unsigned int pfn
-)
-{
- /* there is no real API for this */
- return (void *)(pfn << PAGE_SHIFT);
-}
-
-#endif /* _MC_DRV_MODULE_LINUX_API_H_ */
-/** @} */
diff --git a/drivers/gud/mobicore_driver/mem.c b/drivers/gud/mobicore_driver/mem.c
new file mode 100644
index 0000000..da711ce
--- /dev/null
+++ b/drivers/gud/mobicore_driver/mem.c
@@ -0,0 +1,696 @@
+/*
+ * MobiCore Driver Kernel Module.
+ *
+ * This module is written as a Linux device driver.
+ * This driver represents the command proxy on the lowest layer, from the
+ * secure world to the non secure world, and vice versa.
+ * This driver is located in the non secure world (Linux).
+ * This driver offers IOCTL commands, for access to the secure world, and has
+ * the interface from the secure world to the normal world.
+ * The access to the driver is possible with a file descriptor,
+ * which has to be created by the fd = open(/dev/mobicore) command.
+ *
+ * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include "main.h"
+#include "debug.h"
+#include "mem.h"
+
+#include <linux/highmem.h>
+#include <linux/slab.h>
+#include <linux/kthread.h>
+#include <linux/pagemap.h>
+#include <linux/device.h>
+
+
+/* MobiCore memory context data */
+struct mc_mem_context mem_ctx;
+
+/* convert L2 PTE to page pointer */
+static inline struct page *l2_pte_to_page(pte_t pte)
+{
+ unsigned long phys_page_addr = ((unsigned long)pte & PAGE_MASK);
+ unsigned int pfn = phys_page_addr >> PAGE_SHIFT;
+ struct page *page = pfn_to_page(pfn);
+ return page;
+}
+
+/* convert page pointer to L2 PTE */
+static inline pte_t page_to_l2_pte(struct page *page)
+{
+ unsigned long pfn = page_to_pfn(page);
+ unsigned long phys_addr = (pfn << PAGE_SHIFT);
+ pte_t pte = (pte_t)(phys_addr & PAGE_MASK);
+ return pte;
+}
+
+static inline void release_page(struct page *page)
+{
+ SetPageDirty(page);
+
+ page_cache_release(page);
+}
+
+static int lock_pages(struct task_struct *task, void *virt_start_page_addr,
+ int pages_no, struct page **pages)
+{
+ int locked_pages;
+
+ /* lock user pages, must hold the mmap_sem to do this. */
+ down_read(&(task->mm->mmap_sem));
+ locked_pages = get_user_pages(
+ task,
+ task->mm,
+ (unsigned long)virt_start_page_addr,
+ pages_no,
+ 1, /* write access */
+ 0,
+ pages,
+ NULL);
+ up_read(&(task->mm->mmap_sem));
+
+ /* check if we could lock all pages. */
+ if (locked_pages != pages_no) {
+ MCDRV_DBG_ERROR(mcd, "get_user_pages() failed, locked_pages=%d",
+ locked_pages);
+ if (locked_pages > 0) {
+ /* release all locked pages. */
+ release_pages(pages, locked_pages, 0);
+ }
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/* Get kernel pointer to shared L2 table given a per-process reference */
+struct l2table *get_l2_table_kernel_virt(struct mc_l2_table *table)
+{
+ if (WARN(!table, "Invalid L2 table"))
+ return NULL;
+
+ if (WARN(!table->set, "Invalid L2 table set"))
+ return NULL;
+
+ if (WARN(!table->set->kernel_virt, "Invalid L2 pointer"))
+ return NULL;
+
+ return &(table->set->kernel_virt->table[table->idx]);
+}
+
+/* Get physical address of a shared L2 table given a per-process reference */
+struct l2table *get_l2_table_phys(struct mc_l2_table *table)
+{
+ if (WARN(!table, "Invalid L2 table"))
+ return NULL;
+ if (WARN(!table->set, "Invalid L2 table set"))
+ return NULL;
+ if (WARN(!table->set->kernel_virt, "Invalid L2 phys pointer"))
+ return NULL;
+
+ return &(table->set->phys->table[table->idx]);
+}
+
+static inline int in_use(struct mc_l2_table *table)
+{
+ return atomic_read(&table->usage) > 0;
+}
+
+/*
+ * Search the list of used l2 tables and return the one with the handle.
+ * Assumes the table_lock is taken.
+ */
+struct mc_l2_table *find_l2_table(unsigned int handle)
+{
+ struct mc_l2_table *table;
+
+ list_for_each_entry(table, &mem_ctx.l2_tables, list) {
+ if (table->handle == handle)
+ return table;
+ }
+ return NULL;
+}
+
+/*
+ * Allocate a new l2 table store plus L2_TABLES_PER_PAGE in the l2 free tables
+ * list. Assumes the table_lock is already taken by the caller above.
+ */
+static int alloc_table_store(void)
+{
+ unsigned long store;
+ struct mc_l2_tables_set *l2table_set;
+ struct mc_l2_table *l2table, *l2table2;
+ struct page *page;
+ int ret = 0, i;
+ /* temp list for holding the l2 tables */
+ LIST_HEAD(temp);
+
+ store = get_zeroed_page(GFP_KERNEL);
+ if (!store)
+ return -ENOMEM;
+
+ /*
+ * Actually, locking is not necessary, because kernel
+ * memory is not supposed to get swapped out. But we
+ * play safe....
+ */
+ page = virt_to_page(store);
+ SetPageReserved(page);
+
+ /* add all the descriptors to the free descriptors list */
+ l2table_set = kmalloc(sizeof(*l2table_set), GFP_KERNEL | __GFP_ZERO);
+ if (l2table_set == NULL) {
+ ret = -ENOMEM;
+ goto free_store;
+ }
+ /* initialize */
+ l2table_set->kernel_virt = (void *)store;
+ l2table_set->page = page;
+ l2table_set->phys = (void *)virt_to_phys((void *)store);
+ /* the set is not yet used */
+ atomic_set(&l2table_set->used_tables, 0);
+
+ /* init add to list. */
+ INIT_LIST_HEAD(&(l2table_set->list));
+ list_add(&l2table_set->list, &mem_ctx.l2_tables_sets);
+
+ for (i = 0; i < L2_TABLES_PER_PAGE; i++) {
+ /* allocate a WSM L2 descriptor */
+ l2table = kmalloc(sizeof(*l2table), GFP_KERNEL | __GFP_ZERO);
+ if (l2table == NULL) {
+ ret = -ENOMEM;
+ MCDRV_DBG_ERROR(mcd, "out of memory\n");
+ /* Free the full temp list and the store in this case */
+ goto free_temp_list;
+ }
+
+ /* set set reference */
+ l2table->set = l2table_set;
+ l2table->idx = i;
+ l2table->virt = get_l2_table_kernel_virt(l2table);
+ l2table->phys = (unsigned long)get_l2_table_phys(l2table);
+ atomic_set(&l2table->usage, 0);
+
+ /* add to temp list. */
+ INIT_LIST_HEAD(&l2table->list);
+ list_add_tail(&l2table->list, &temp);
+ }
+
+ /*
+ * If everything went ok then merge the temp list with the global
+ * free list
+ */
+ list_splice_tail(&temp, &mem_ctx.free_l2_tables);
+ return 0;
+free_temp_list:
+ list_for_each_entry_safe(l2table, l2table2, &temp, list) {
+ kfree(l2table);
+ }
+
+ list_del(&l2table_set->list);
+
+free_store:
+ free_page(store);
+ return ret;
+
+}
+/*
+ * Get a l2 table from the free tables list or allocate a new one and
+ * initialize it. Assumes the table_lock is already taken.
+ */
+static struct mc_l2_table *alloc_l2_table(struct mc_instance *instance)
+{
+ int ret = 0;
+ struct mc_l2_table *table = NULL;
+
+ if (list_empty(&mem_ctx.free_l2_tables)) {
+ ret = alloc_table_store();
+ if (ret) {
+ MCDRV_DBG_ERROR(mcd, "Failed to allocate new store!");
+ return ERR_PTR(-ENOMEM);
+ }
+ /* if it's still empty something wrong has happened */
+ if (list_empty(&mem_ctx.free_l2_tables)) {
+ MCDRV_DBG_ERROR(mcd,
+ "Free list not updated correctly!");
+ return ERR_PTR(-EFAULT);
+ }
+ }
+
+ /* get a WSM L2 descriptor */
+ table = list_first_entry(&mem_ctx.free_l2_tables,
+ struct mc_l2_table, list);
+ if (table == NULL) {
+ MCDRV_DBG_ERROR(mcd, "out of memory\n");
+ return ERR_PTR(-ENOMEM);
+ }
+ /* Move it to the used l2 tables list */
+ list_move_tail(&table->list, &mem_ctx.l2_tables);
+
+ table->handle = get_unique_id();
+ table->owner = instance;
+
+ atomic_inc(&table->set->used_tables);
+ atomic_inc(&table->usage);
+
+ MCDRV_DBG_VERBOSE(mcd,
+ "chunkPhys=%p,idx=%d", table->set->phys, table->idx);
+
+ return table;
+}
+
+/*
+ * Frees the object associated with a l2 table. Initially the object is moved
+ * to the free tables list, but if all the 4 lists of the store are free
+ * then the store is also released.
+ * Assumes the table_lock is already taken.
+ */
+static void free_l2_table(struct mc_l2_table *table)
+{
+ struct mc_l2_tables_set *l2table_set;
+
+ if (WARN(!table, "Invalid table"))
+ return;
+
+ l2table_set = table->set;
+ if (WARN(!l2table_set, "Invalid table set"))
+ return;
+
+ list_move_tail(&table->list, &mem_ctx.free_l2_tables);
+
+ /* if nobody uses this set, we can release it. */
+ if (atomic_dec_and_test(&l2table_set->used_tables)) {
+ struct mc_l2_table *tmp;
+
+ /* remove from list */
+ list_del(&l2table_set->list);
+ /*
+ * All the l2 tables are in the free list for this set
+ * so we can just remove them from there
+ */
+ list_for_each_entry_safe(table, tmp, &mem_ctx.free_l2_tables,
+ list) {
+ if (table->set == l2table_set) {
+ list_del(&table->list);
+ kfree(table);
+ }
+ } /* end while */
+
+ /*
+ * We shouldn't recover from this since it was some data
+ * corruption before
+ */
+ BUG_ON(!l2table_set->page);
+ ClearPageReserved(l2table_set->page);
+
+ BUG_ON(!l2table_set->kernel_virt);
+ free_page((unsigned long)l2table_set->kernel_virt);
+
+ kfree(l2table_set);
+ }
+}
+
+/*
+ * Create a L2 table in a WSM container that has been allocates previously.
+ * Assumes the table lock is already taken or there is no need to take like
+ * when first creating the l2 table the full list is locked.
+ *
+ * @task pointer to task owning WSM
+ * @wsm_buffer user space WSM start
+ * @wsm_len WSM length
+ * @table Pointer to L2 table details
+ */
+static int map_buffer(struct task_struct *task, void *wsm_buffer,
+ unsigned int wsm_len, struct mc_l2_table *table)
+{
+ int ret = 0;
+ unsigned int i, nr_of_pages;
+ /* start address of the 4 KiB page of wsm_buffer */
+ void *virt_addr_page;
+ struct page *page;
+ struct l2table *l2table;
+ struct page **l2table_as_array_of_pointers_to_page;
+ /* page offset in wsm buffer */
+ unsigned int offset;
+
+ if (WARN(!wsm_buffer, "Invalid WSM buffer pointer"))
+ return -EINVAL;
+
+ if (WARN(wsm_len == 0, "Invalid WSM buffer length"))
+ return -EINVAL;
+
+ if (WARN(!table, "Invalid mapping table for WSM"))
+ return -EINVAL;
+
+ /* no size > 1Mib supported */
+ if (wsm_len > SZ_1M) {
+ MCDRV_DBG_ERROR(mcd, "size > 1 MiB\n");
+ return -EINVAL;
+ }
+
+ MCDRV_DBG_VERBOSE(mcd, "WSM addr=0x%p, len=0x%08x\n", wsm_buffer,
+ wsm_len);
+
+ /*
+ * Check if called from kernel space and if
+ * wsm_buffer is actually vmalloced or not
+ */
+ if (task == NULL && !is_vmalloc_addr(wsm_buffer)) {
+ MCDRV_DBG_ERROR(mcd, "WSM addr is not a vmalloc address");
+ return -EINVAL;
+ }
+
+ /* calculate page usage */
+ virt_addr_page = (void *)(((unsigned long)(wsm_buffer)) & PAGE_MASK);
+ offset = (unsigned int) (((unsigned long)(wsm_buffer)) & (~PAGE_MASK));
+ nr_of_pages = PAGE_ALIGN(offset + wsm_len) / PAGE_SIZE;
+
+ MCDRV_DBG_VERBOSE(mcd, "virt addr page start=0x%p, pages=%d\n",
+ virt_addr_page, nr_of_pages);
+
+ /* L2 table can hold max 1MiB in 256 pages. */
+ if ((nr_of_pages * PAGE_SIZE) > SZ_1M) {
+ MCDRV_DBG_ERROR(mcd, "WSM paged exceed 1 MiB\n");
+ return -EINVAL;
+ }
+
+ l2table = table->virt;
+ /*
+ * We use the memory for the L2 table to hold the pointer
+ * and convert them later. This works, as everything comes
+ * down to a 32 bit value.
+ */
+ l2table_as_array_of_pointers_to_page = (struct page **)l2table;
+
+ /* Request comes from user space */
+ if (task != NULL && !is_vmalloc_addr(wsm_buffer)) {
+ /*
+ * lock user page in memory, so they do not get swapped
+ * out.
+ * REV axh: Kernel 2.6.27 added a new get_user_pages_fast()
+ * function, maybe it is called fast_gup() in some versions.
+ * handle user process doing a fork().
+ * Child should not get things.
+ * http://osdir.com/ml/linux-media/2009-07/msg00813.html
+ * http://lwn.net/Articles/275808/
+ */
+ ret = lock_pages(task, virt_addr_page, nr_of_pages,
+ l2table_as_array_of_pointers_to_page);
+ if (ret != 0) {
+ MCDRV_DBG_ERROR(mcd, "lock_user_pages() failed\n");
+ return ret;
+ }
+ }
+ /* Request comes from kernel space(vmalloc buffer) */
+ else {
+ void *uaddr = wsm_buffer;
+ for (i = 0; i < nr_of_pages; i++) {
+ page = vmalloc_to_page(uaddr);
+ if (!page) {
+ MCDRV_DBG_ERROR(mcd, "failed to map address");
+ return -EINVAL;
+ }
+ get_page(page);
+ l2table_as_array_of_pointers_to_page[i] = page;
+ uaddr += PAGE_SIZE;
+ }
+ }
+
+ table->pages = nr_of_pages;
+
+ /*
+ * create L2 Table entries.
+ * used_l2table->table contains a list of page pointers here.
+ * For a proper cleanup we have to ensure that the following
+ * code either works and used_l2table contains a valid L2 table
+ * - or fails and used_l2table->table contains the list of page
+ * pointers.
+ * Any mixed contents will make cleanup difficult.
+ */
+ for (i = 0; i < nr_of_pages; i++) {
+ pte_t pte;
+ page = l2table_as_array_of_pointers_to_page[i];
+
+ /*
+ * create L2 table entry, see ARM MMU docu for details
+ * about flags stored in the lowest 12 bits.
+ * As a side reference, the Article
+ * "ARM's multiply-mapped memory mess"
+ * found in the collection at
+ * http://lwn.net/Articles/409032/
+ * is also worth reading.
+ */
+ pte = page_to_l2_pte(page)
+ | PTE_EXT_AP1 | PTE_EXT_AP0
+ | PTE_CACHEABLE | PTE_BUFFERABLE
+ | PTE_TYPE_SMALL | PTE_TYPE_EXT | PTE_EXT_NG;
+ /*
+ * Linux uses different mappings for SMP systems(the
+ * sharing flag is set for the pte. In order not to
+ * confuse things too much in Mobicore make sure the
+ * shared buffers have the same flags.
+ * This should also be done in SWD side
+ */
+#ifdef CONFIG_SMP
+ pte |= PTE_EXT_SHARED | PTE_EXT_TEX(1);
+#endif
+
+ l2table->table_entries[i] = pte;
+ MCDRV_DBG_VERBOSE(mcd, "L2 entry %d: 0x%08x\n", i,
+ (unsigned int)(pte));
+ }
+
+ /* ensure rest of table is empty */
+ while (i < 255)
+ l2table->table_entries[i++] = (pte_t)0;
+
+
+ return ret;
+}
+
+/*
+ * Remove a L2 table in a WSM container. Afterwards the container may be
+ * released. Assumes the table_lock and the lock is taken.
+ */
+static void unmap_buffers(struct mc_l2_table *table)
+{
+ struct l2table *l2table;
+ int i;
+
+ if (WARN_ON(!table))
+ return;
+
+ /* found the table, now release the resources. */
+ MCDRV_DBG_VERBOSE(mcd, "clear L2 table, phys_base=%p, nr_of_pages=%d\n",
+ (void *)table->phys, table->pages);
+
+ l2table = table->virt;
+
+ /* release all locked user space pages */
+ for (i = 0; i < table->pages; i++) {
+ /* convert physical entries from L2 table to page pointers */
+ pte_t pte = l2table->table_entries[i];
+ struct page *page = l2_pte_to_page(pte);
+ release_page(page);
+ }
+
+ /* remember that all pages have been freed */
+ table->pages = 0;
+}
+
+/* Delete a used l2 table. Assumes the table_lock and the lock is taken */
+static void unmap_l2_table(struct mc_l2_table *table)
+{
+ /* Check if it's not locked by other processes too! */
+ if (!atomic_dec_and_test(&table->usage))
+ return;
+
+ /* release if Nwd and Swd/MC do no longer use it. */
+ unmap_buffers(table);
+ free_l2_table(table);
+}
+
+int mc_free_l2_table(struct mc_instance *instance, uint32_t handle)
+{
+ struct mc_l2_table *table;
+ int ret = 0;
+
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
+
+ mutex_lock(&mem_ctx.table_lock);
+ table = find_l2_table(handle);
+
+ if (table == NULL) {
+ MCDRV_DBG_VERBOSE(mcd, "entry not found");
+ ret = -EINVAL;
+ goto err_unlock;
+ }
+ if (instance != table->owner && !is_daemon(instance)) {
+ MCDRV_DBG_ERROR(mcd, "instance does no own it");
+ ret = -EPERM;
+ goto err_unlock;
+ }
+ /* free table (if no further locks exist) */
+ unmap_l2_table(table);
+err_unlock:
+ mutex_unlock(&mem_ctx.table_lock);
+
+ return ret;
+}
+
+int mc_lock_l2_table(struct mc_instance *instance, uint32_t handle)
+{
+ int ret = 0;
+ struct mc_l2_table *table = NULL;
+
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
+
+ mutex_lock(&mem_ctx.table_lock);
+ table = find_l2_table(handle);
+
+ if (table == NULL) {
+ MCDRV_DBG_VERBOSE(mcd, "entry not found %u\n", handle);
+ ret = -EINVAL;
+ goto table_err;
+ }
+ if (instance != table->owner && !is_daemon(instance)) {
+ MCDRV_DBG_ERROR(mcd, "instance does no own it\n");
+ ret = -EPERM;
+ goto table_err;
+ }
+
+ /* lock entry */
+ atomic_inc(&table->usage);
+table_err:
+ mutex_unlock(&mem_ctx.table_lock);
+ return ret;
+}
+/*
+ * Allocate L2 table and map buffer into it.
+ * That is, create respective table entries.
+ * Must hold Semaphore mem_ctx.wsm_l2_sem
+ */
+struct mc_l2_table *mc_alloc_l2_table(struct mc_instance *instance,
+ struct task_struct *task, void *wsm_buffer, unsigned int wsm_len)
+{
+ int ret = 0;
+ struct mc_l2_table *table;
+
+ if (WARN(!instance, "No instance data available"))
+ return ERR_PTR(-EFAULT);
+
+ mutex_lock(&mem_ctx.table_lock);
+ table = alloc_l2_table(instance);
+ if (IS_ERR(table)) {
+ MCDRV_DBG_ERROR(mcd, "allocate_used_l2_table() failed\n");
+ ret = -ENOMEM;
+ goto err_no_mem;
+ }
+
+ /* create the L2 page for the WSM */
+ ret = map_buffer(task, wsm_buffer, wsm_len, table);
+
+ if (ret != 0) {
+ MCDRV_DBG_ERROR(mcd, "map_buffer() failed\n");
+ unmap_l2_table(table);
+ goto err_no_mem;
+ }
+ MCDRV_DBG(mcd, "mapped buffer %p to table with handle %d @ %lx",
+ wsm_buffer, table->handle, table->phys);
+
+ mutex_unlock(&mem_ctx.table_lock);
+ return table;
+err_no_mem:
+ mutex_unlock(&mem_ctx.table_lock);
+ return ERR_PTR(ret);
+}
+
+uint32_t mc_find_l2_table(struct mc_instance *instance, uint32_t handle)
+{
+ uint32_t ret = 0;
+ struct mc_l2_table *table = NULL;
+
+ if (WARN(!instance, "No instance data available"))
+ return 0;
+
+ mutex_lock(&mem_ctx.table_lock);
+ table = find_l2_table(handle);
+
+ if (table == NULL) {
+ MCDRV_DBG_ERROR(mcd, "entry not found %u\n", handle);
+ ret = 0;
+ goto table_err;
+ }
+
+ ret = table->phys;
+table_err:
+ mutex_unlock(&mem_ctx.table_lock);
+ return ret;
+}
+
+void mc_clean_l2_tables(void)
+{
+ struct mc_l2_table *table, *tmp;
+
+ mutex_lock(&mem_ctx.table_lock);
+ /* Check if some WSM is orphaned. */
+ list_for_each_entry_safe(table, tmp, &mem_ctx.l2_tables, list) {
+ if (table->owner == NULL) {
+ MCDRV_DBG(mcd,
+ "clearing orphaned WSM L2: p=%lx pages=%d\n",
+ table->phys, table->pages);
+ unmap_l2_table(table);
+ }
+ }
+ mutex_unlock(&mem_ctx.table_lock);
+}
+
+void mc_clear_l2_tables(struct mc_instance *instance)
+{
+ struct mc_l2_table *table, *tmp;
+
+ mutex_lock(&mem_ctx.table_lock);
+ /* Check if some WSM is still in use. */
+ list_for_each_entry_safe(table, tmp, &mem_ctx.l2_tables, list) {
+ if (table->owner == instance) {
+ MCDRV_DBG(mcd, "release WSM L2: p=%lx pages=%d\n",
+ table->phys, table->pages);
+ /* unlock app usage and free or mark it as orphan */
+ table->owner = NULL;
+ unmap_l2_table(table);
+ }
+ }
+ mutex_unlock(&mem_ctx.table_lock);
+}
+
+int mc_init_l2_tables(void)
+{
+ /* init list for WSM L2 chunks. */
+ INIT_LIST_HEAD(&mem_ctx.l2_tables_sets);
+
+ /* L2 table descriptor list. */
+ INIT_LIST_HEAD(&mem_ctx.l2_tables);
+
+ /* L2 table descriptor list. */
+ INIT_LIST_HEAD(&mem_ctx.free_l2_tables);
+
+ mutex_init(&mem_ctx.table_lock);
+
+ return 0;
+}
+
+void mc_release_l2_tables()
+{
+ struct mc_l2_table *table;
+ /* Check if some WSM is still in use. */
+ list_for_each_entry(table, &mem_ctx.l2_tables, list) {
+ WARN(1, "WSM L2 still in use: phys=%lx ,nr_of_pages=%d\n",
+ table->phys, table->pages);
+ }
+}
diff --git a/drivers/gud/mobicore_driver/mem.h b/drivers/gud/mobicore_driver/mem.h
new file mode 100644
index 0000000..a90662a7
--- /dev/null
+++ b/drivers/gud/mobicore_driver/mem.h
@@ -0,0 +1,127 @@
+/*
+ * MobiCore driver module.(interface to the secure world SWD)
+ *
+ * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MC_MEM_H_
+#define _MC_MEM_H_
+
+#define FREE_FROM_SWD 1
+#define FREE_FROM_NWD 0
+
+#define LOCKED_BY_APP (1U << 0)
+#define LOCKED_BY_MC (1U << 1)
+
+/*
+ * MobiCore specific page tables for world shared memory.
+ * Linux uses shadow page tables, see arch/arm/include/asm/pgtable-2level.
+ * MobiCore uses the default ARM format.
+ *
+ * Number of page table entries in one L2 table. This is ARM specific, an
+ * L2 table covers 1 MiB by using 256 entry referring to 4KiB pages each.
+ */
+#define MC_ARM_L2_TABLE_ENTRIES 256
+
+/* ARM level 2 (L2) table with 256 entries. Size: 1k */
+struct l2table {
+ pte_t table_entries[MC_ARM_L2_TABLE_ENTRIES];
+};
+
+/* Number of pages for L2 tables. There are 4 table in each page. */
+#define L2_TABLES_PER_PAGE 4
+
+/* Store for four L2 tables in one 4kb page*/
+struct mc_l2_table_store {
+ struct l2table table[L2_TABLES_PER_PAGE];
+};
+
+/* Usage and maintenance information about mc_l2_table_store */
+struct mc_l2_tables_set {
+ struct list_head list;
+ /* kernel virtual address */
+ struct mc_l2_table_store *kernel_virt;
+ /* physical address */
+ struct mc_l2_table_store *phys;
+ /* pointer to page struct */
+ struct page *page;
+ /* How many pages from this set are used */
+ atomic_t used_tables;
+};
+
+/*
+ * L2 table allocated to the Daemon or a TLC describing a world shared buffer.
+ * When users map a malloc()ed area into SWd, a L2 table is allocated.
+ * In addition, the area of maximum 1MB virtual address space is mapped into
+ * the L2 table and a handle for this table is returned to the user.
+ */
+struct mc_l2_table {
+ struct list_head list;
+ /* Table lock */
+ struct mutex lock;
+ /* handle as communicated to user mode */
+ unsigned int handle;
+ /* Number of references kept to this l2 table */
+ atomic_t usage;
+ /* owner of this L2 table */
+ struct mc_instance *owner;
+ /* set describing where our L2 table is stored */
+ struct mc_l2_tables_set *set;
+ /* index into L2 table set */
+ unsigned int idx;
+ /* size of buffer */
+ unsigned int pages;
+ /* virtual address*/
+ void *virt;
+ unsigned long phys;
+};
+
+/* MobiCore Driver Memory context data. */
+struct mc_mem_context {
+ struct mc_instance *daemon_inst;
+ /* Backing store for L2 tables */
+ struct list_head l2_tables_sets;
+ /* Bookkeeping for used L2 tables */
+ struct list_head l2_tables;
+ /* Bookkeeping for free L2 tables */
+ struct list_head free_l2_tables;
+ /* semaphore to synchronize access to above lists */
+ struct mutex table_lock;
+};
+
+/*
+ * Allocate L2 table and map buffer into it.
+ * That is, create respective table entries.
+ */
+struct mc_l2_table *mc_alloc_l2_table(struct mc_instance *instance,
+ struct task_struct *task, void *wsm_buffer, unsigned int wsm_len);
+
+/* Delete all the l2 tables associated with an instance */
+void mc_clear_l2_tables(struct mc_instance *instance);
+
+/* Release all orphaned L2 tables */
+void mc_clean_l2_tables(void);
+
+/* Delete a used l2 table. */
+int mc_free_l2_table(struct mc_instance *instance, uint32_t handle);
+
+/*
+ * Lock a l2 table - the daemon adds +1 to refcount of the L2 table
+ * marking it in use by SWD so it doesn't get released when the TLC dies.
+ */
+int mc_lock_l2_table(struct mc_instance *instance, uint32_t handle);
+/* Unlock l2 table. */
+int mc_unlock_l2_table(struct mc_instance *instance, uint32_t handle);
+/* Return the phys address of l2 table. */
+uint32_t mc_find_l2_table(struct mc_instance *instance, uint32_t handle);
+/* Release all used l2 tables to Linux memory space */
+void mc_release_l2_tables(void);
+
+/* Initialize all l2 tables structure */
+int mc_init_l2_tables(void);
+
+#endif /* _MC_MEM_H_ */
diff --git a/drivers/gud/mobicore_driver/ops.c b/drivers/gud/mobicore_driver/ops.c
new file mode 100644
index 0000000..509b4e9
--- /dev/null
+++ b/drivers/gud/mobicore_driver/ops.c
@@ -0,0 +1,143 @@
+/*
+ * MobiCore Driver Kernel Module.
+ *
+ * This module is written as a Linux device driver.
+ * This driver represents the command proxy on the lowest layer, from the
+ * secure world to the non secure world, and vice versa.
+ * This driver is located in the non secure world (Linux).
+ * This driver offers IOCTL commands, for access to the secure world, and has
+ * the interface from the secure world to the normal world.
+ * The access to the driver is possible with a file descriptor,
+ * which has to be created by the fd = open(/dev/mobicore) command.
+ *
+ * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/device.h>
+
+#include "main.h"
+#include "fastcall.h"
+#include "ops.h"
+#include "mem.h"
+#include "debug.h"
+
+int mc_info(uint32_t ext_info_id, uint32_t *state, uint32_t *ext_info)
+{
+ int ret = 0;
+ union mc_fc_info fc_info;
+
+ MCDRV_DBG_VERBOSE(mcd, "enter\n");
+
+ memset(&fc_info, 0, sizeof(fc_info));
+ fc_info.as_in.cmd = MC_FC_INFO;
+ fc_info.as_in.ext_info_id = ext_info_id;
+
+ MCDRV_DBG(mcd, "fc_info <- cmd=0x%08x, ext_info_id=0x%08x\n",
+ fc_info.as_in.cmd, fc_info.as_in.ext_info_id);
+
+ mc_fastcall(&(fc_info.as_generic));
+
+ MCDRV_DBG(mcd,
+ "fc_info -> r=0x%08x ret=0x%08x state=0x%08x ext_info=0x%08x",
+ fc_info.as_out.resp,
+ fc_info.as_out.ret,
+ fc_info.as_out.state,
+ fc_info.as_out.ext_info);
+
+ ret = convert_fc_ret(fc_info.as_out.ret);
+
+ *state = fc_info.as_out.state;
+ *ext_info = fc_info.as_out.ext_info;
+
+ MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret);
+
+ return ret;
+}
+
+/* Yield to MobiCore */
+int mc_yield(void)
+{
+ int ret = 0;
+ union fc_generic yield;
+
+ MCDRV_DBG_VERBOSE(mcd, "enter\n");
+
+ memset(&yield, 0, sizeof(yield));
+ yield.as_in.cmd = MC_SMC_N_YIELD;
+ mc_fastcall(&yield);
+ ret = convert_fc_ret(yield.as_out.ret);
+
+ return ret;
+}
+
+/* call common notify */
+int mc_nsiq(void)
+{
+ int ret = 0;
+ union fc_generic nsiq;
+ MCDRV_DBG_VERBOSE(mcd, "enter\n");
+
+ memset(&nsiq, 0, sizeof(nsiq));
+ nsiq.as_in.cmd = MC_SMC_N_SIQ;
+ mc_fastcall(&nsiq);
+ ret = convert_fc_ret(nsiq.as_out.ret);
+
+ return ret;
+}
+
+/* Call the INIT fastcall to setup MobiCore initialization */
+int mc_init(uint32_t base, uint32_t nq_offset, uint32_t nq_length,
+ uint32_t mcp_offset, uint32_t mcp_length)
+{
+ int ret = 0;
+ union mc_fc_init fc_init;
+
+ MCDRV_DBG_VERBOSE(mcd, "enter\n");
+
+ memset(&fc_init, 0, sizeof(fc_init));
+
+ fc_init.as_in.cmd = MC_FC_INIT;
+ /* base address of mci buffer 4KB aligned */
+ fc_init.as_in.base = base;
+ /* notification buffer start/length [16:16] [start, length] */
+ fc_init.as_in.nq_info = (nq_offset << 16) | (nq_length & 0xFFFF);
+ /* mcp buffer start/length [16:16] [start, length] */
+ fc_init.as_in.mcp_info = (mcp_offset << 16) | (mcp_length & 0xFFFF);
+
+ /*
+ * Set KMOD notification queue to start of MCI
+ * mciInfo was already set up in mmap
+ */
+ MCDRV_DBG(mcd,
+ "cmd=0x%08x, base=0x%08x,nq_info=0x%08x, mcp_info=0x%08x\n",
+ fc_init.as_in.cmd, fc_init.as_in.base, fc_init.as_in.nq_info,
+ fc_init.as_in.mcp_info);
+
+ mc_fastcall(&fc_init.as_generic);
+
+ MCDRV_DBG(mcd, "out cmd=0x%08x, ret=0x%08x\n", fc_init.as_out.resp,
+ fc_init.as_out.ret);
+
+ ret = convert_fc_ret(fc_init.as_out.ret);
+
+ MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret);
+
+ return ret;
+}
+
+/* Return MobiCore driver version */
+uint32_t mc_get_version(void)
+{
+ MCDRV_DBG(mcd, "MobiCore driver version is %i.%i\n",
+ MCDRVMODULEAPI_VERSION_MAJOR,
+ MCDRVMODULEAPI_VERSION_MINOR);
+
+ return MC_VERSION(MCDRVMODULEAPI_VERSION_MAJOR,
+ MCDRVMODULEAPI_VERSION_MINOR);
+}
diff --git a/drivers/gud/mobicore_driver/ops.h b/drivers/gud/mobicore_driver/ops.h
new file mode 100644
index 0000000..673399f
--- /dev/null
+++ b/drivers/gud/mobicore_driver/ops.h
@@ -0,0 +1,30 @@
+/*
+ * MobiCore driver module.(interface to the secure world SWD)
+ *
+ * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MC_OPS_H_
+#define _MC_OPS_H_
+
+#include <linux/workqueue.h>
+#include "fastcall.h"
+
+int mc_yield(void);
+int mc_nsiq(void);
+uint32_t mc_get_version(void);
+
+int mc_info(uint32_t ext_info_id, uint32_t *state, uint32_t *ext_info);
+int mc_init(uint32_t base, uint32_t nq_offset, uint32_t nq_length,
+ uint32_t mcp_offset, uint32_t mcp_length);
+
+static inline void mc_fastcall(void *data)
+{
+ work_on_cpu(0, _smc, data);
+}
+
+#endif /* _MC_OPS_H_ */
diff --git a/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h b/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h
index 070222e..9efa026 100644
--- a/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h
+++ b/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h
@@ -1,32 +1,23 @@
-/**
- * Header file of MobiCore Driver Kernel Module Platform
- * specific structures
- *
- * @addtogroup MobiCore_Driver_Kernel_Module
- * @{
- * Internal structures of the McDrvModule
- * @file
- *
- * Header file the MobiCore Driver Kernel Module,
+/*
+ * Header file for the MobiCore Driver Kernel Module,
* its internal structures and defines.
*
- * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-#ifndef _MC_DRV_PLATFORM_H_
-#define _MC_DRV_PLATFORM_H_
+#ifndef _MC_PLATFORM_H_
+#define _MC_PLATFORM_H_
-/** MobiCore Interrupt for Qualcomm */
+/* MobiCore Interrupt for Qualcomm */
#define MC_INTR_SSIQ 280
-/** Use SMC for fastcalls */
+/* Use SMC for fastcalls */
#define MC_SMC_FASTCALL
-
/*--------------- Implementation -------------- */
#include <mach/scm.h>
/* from following file */
@@ -34,17 +25,16 @@
#define SCM_CMD_MOBICORE 1
extern int scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, size_t cmd_len,
- void *resp_buf, size_t resp_len);
+ void *resp_buf, size_t resp_len);
static inline int smc_fastcall(void *fc_generic, size_t size)
{
return scm_call(SCM_SVC_MOBICORE, SCM_CMD_MOBICORE,
- fc_generic, size,
- fc_generic, size);
+ fc_generic, size,
+ fc_generic, size);
}
-/** Enable mobicore mem traces */
+/* Enable mobicore mem traces */
#define MC_MEM_TRACES
-#endif /* _MC_DRV_PLATFORM_H_ */
-/** @} */
+#endif /* _MC_PLATFORM_H_ */
diff --git a/drivers/gud/mobicore_driver/pm.h b/drivers/gud/mobicore_driver/pm.h
new file mode 100644
index 0000000..067f095
--- /dev/null
+++ b/drivers/gud/mobicore_driver/pm.h
@@ -0,0 +1,17 @@
+/*
+ * Header file of MobiCore Driver Kernel Module.
+ *
+ * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MC_PM_H_
+#define _MC_PM_H_
+
+/* How much time after resume the daemon should back off */
+#define DAEMON_BACKOFF_TIME 10
+
+#endif /* _MC_PM_H_ */
diff --git a/drivers/gud/mobicore_driver/public/mc_drv_module_api.h b/drivers/gud/mobicore_driver/public/mc_drv_module_api.h
deleted file mode 100644
index 59366f3..0000000
--- a/drivers/gud/mobicore_driver/public/mc_drv_module_api.h
+++ /dev/null
@@ -1,311 +0,0 @@
-/** @addtogroup MCD_MCDIMPL_KMOD_API Mobicore Driver Module API
- * @ingroup MCD_MCDIMPL_KMOD
- * @{
- * Interface to Mobicore Driver Kernel Module.
- * @file
- *
- * <h2>Introduction</h2>
- * The MobiCore Driver Kernel Module is a Linux device driver, which represents
- * the command proxy on the lowest layer to the secure world (Swd). Additional
- * services like memory allocation via mmap and generation of a L2 tables for
- * given virtual memory are also supported. IRQ functionallity receives
- * information from the SWd in the non secure world (NWd).
- * As customary the driver is handled as linux device driver with "open",
- * "close" and "ioctl" commands. Access to the driver is possible after the
- * device "/dev/mobicore" has been opened.
- * The MobiCore Driver Kernel Module must be installed via
- * "insmod mcDrvModule.ko".
- *
- *
- * <h2>Version history</h2>
- * <table class="customtab">
- * <tr><td width="100px"><b>Date</b></td><td width="80px"><b>Version</b></td>
- * <td><b>Changes</b></td></tr>
- * <tr><td>2010-05-25</td><td>0.1</td><td>Initial Release</td></tr>
- * </table>
- *
- * <!-- Copyright Giesecke & Devrient GmbH 2010-2012 -->
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote
- * products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef _MC_DRV_MODULEAPI_H_
-#define _MC_DRV_MODULEAPI_H_
-
-#include "version.h"
-
-#define MC_DRV_MOD_DEVNODE "mobicore"
-#define MC_DRV_MOD_DEVNODE_FULLPATH "/dev/" MC_DRV_MOD_DEVNODE
-
-/**
- * Data exchange structure of the MC_DRV_MODULE_INIT ioctl command.
- * INIT request data to SWD
- */
-union mc_ioctl_init_params {
- struct {
- /** base address of mci buffer 4KB align */
- uint32_t base;
- /** notification buffer start/length [16:16] [start, length] */
- uint32_t nq_offset;
- /** length of notification queue */
- uint32_t nq_length;
- /** mcp buffer start/length [16:16] [start, length] */
- uint32_t mcp_offset;
- /** length of mcp buffer */
- uint32_t mcp_length;
- } in;
- struct {
- /* nothing */
- } out;
-};
-
-
-/**
- * Data exchange structure of the MC_DRV_MODULE_INFO ioctl command.
- * INFO request data to the SWD
- */
-union mc_ioctl_info_params {
- struct {
- uint32_t ext_info_id; /**< extended info ID */
- } in;
- struct {
- uint32_t state; /**< state */
- uint32_t ext_info; /**< extended info */
- } out;
-};
-
-/**
- * Mmap allocates and maps contiguous memory into a process.
- * We use the third parameter, void *offset, to distinguish between some cases
- * offset = MC_DRV_KMOD_MMAP_WSM usual operation, pages are registered in
- device structure and freed later.
- * offset = MC_DRV_KMOD_MMAP_MCI get Instance of MCI, allocates or mmaps
- the MCI to daemon
- * offset = MC_DRV_KMOD_MMAP_PERSISTENTWSM special operation, without
- registration of pages
- *
- * In mmap(), the offset specifies which of several device I/O pages is
- * requested. Linux only transfers the page number, i.e. the upper 20 bits to
- * kernel module. Therefore we define our special offsets as multiples of page
- * size.
- */
-enum mc_mmap_memtype {
- MC_DRV_KMOD_MMAP_WSM = 0,
- MC_DRV_KMOD_MMAP_MCI = 4096,
- MC_DRV_KMOD_MMAP_PERSISTENTWSM = 8192
-};
-
-struct mc_mmap_resp {
- uint32_t handle; /**< WSN handle */
- uint32_t phys_addr; /**< physical address of WSM (or NULL) */
- bool is_reused; /**< if WSM memory was reused, or new allocated */
-};
-
-/**
- * Data exchange structure of the MC_DRV_KMOD_IOCTL_FREE ioctl command.
- */
-union mc_ioctl_free_params {
- struct {
- uint32_t handle; /**< driver handle */
- uint32_t pid; /**< process id */
- } in;
- struct {
- /* nothing */
- } out;
-};
-
-
-/**
- * Data exchange structure of the MC_DRV_KMOD_IOCTL_APP_REGISTER_WSM_L2 command.
- *
- * Allocates a physical L2 table and maps the buffer into this page.
- * Returns the physical address of the L2 table.
- * The page alignment will be created and the appropriated pSize and pOffsetL2
- * will be modified to the used values.
- */
-union mc_ioctl_app_reg_wsm_l2_params {
- struct {
- uint32_t buffer; /**< base address of the virtual address */
- uint32_t len; /**< size of the virtual address space */
- uint32_t pid; /**< process id */
- } in;
- struct {
- uint32_t handle; /**< driver handle for locked memory */
- uint32_t phys_wsm_l2_table; /* physical address of the L2 table */
- } out;
-};
-
-
-/**
- * Data exchange structure of the MC_DRV_KMOD_IOCTL_APP_UNREGISTER_WSM_L2
- * command.
- */
-struct mc_ioctl_app_unreg_wsm_l2_params {
- struct {
- uint32_t handle; /**< driver handle for locked memory */
- uint32_t pid; /**< process id */
- } in;
- struct {
- /* nothing */
- } out;
-};
-
-
-/**
- * Data exchange structure of the MC_DRV_KMOD_IOCTL_DAEMON_LOCK_WSM_L2 command.
- */
-struct mc_ioctl_daemon_lock_wsm_l2_params {
- struct {
- uint32_t handle; /**< driver handle for locked memory */
- } in;
- struct {
- uint32_t phys_wsm_l2_table;
- } out;
-};
-
-
-/**
- * Data exchange structure of the MC_DRV_KMOD_IOCTL_DAEMON_UNLOCK_WSM_L2
- * command.
- */
-struct mc_ioctl_daemon_unlock_wsm_l2_params {
- struct {
- uint32_t handle; /**< driver handle for locked memory */
- } in;
- struct {
- /* nothing */
- } out;
-};
-
-/**
- * Data exchange structure of the MC_DRV_MODULE_FC_EXECUTE ioctl command.
- */
-union mc_ioctl_fc_execute_params {
- struct {
- /**< base address of mobicore binary */
- uint32_t phys_start_addr;
- /**< length of DDR area */
- uint32_t length;
- } in;
- struct {
- /* nothing */
- } out;
-};
-
-/**
- * Data exchange structure of the MC_DRV_MODULE_GET_VERSION ioctl command.
- */
-struct mc_ioctl_get_version_params {
- struct {
- uint32_t kernel_module_version;
- } out;
-};
-
-/* @defgroup Mobicore_Driver_Kernel_Module_Interface IOCTL */
-
-
-
-
-/* TODO: use IOCTL macros like _IOWR. See Documentation/ioctl/ioctl-number.txt,
- Documentation/ioctl/ioctl-decoding.txt */
-/**
- * defines for the ioctl mobicore driver module function call from user space.
- */
-enum mc_kmod_ioctl {
-
- /*
- * get detailed MobiCore Status
- */
- MC_DRV_KMOD_IOCTL_DUMP_STATUS = 200,
-
- /*
- * initialize MobiCore
- */
- MC_DRV_KMOD_IOCTL_FC_INIT = 201,
-
- /*
- * get MobiCore status
- */
- MC_DRV_KMOD_IOCTL_FC_INFO = 202,
-
- /**
- * ioctl parameter to send the YIELD command to the SWD.
- * Only possible in Privileged Mode.
- * ioctl(fd, MC_DRV_MODULE_YIELD)
- */
- MC_DRV_KMOD_IOCTL_FC_YIELD = 203,
- /**
- * ioctl parameter to send the NSIQ signal to the SWD.
- * Only possible in Privileged Mode
- * ioctl(fd, MC_DRV_MODULE_NSIQ)
- */
- MC_DRV_KMOD_IOCTL_FC_NSIQ = 204,
- /**
- * ioctl parameter to tzbsp to start Mobicore binary from DDR.
- * Only possible in Privileged Mode
- * ioctl(fd, MC_DRV_KMOD_IOCTL_FC_EXECUTE)
- */
- MC_DRV_KMOD_IOCTL_FC_EXECUTE = 205,
-
- /**
- * Free's memory which is formerly allocated by the driver's mmap
- * command. The parameter must be this mmaped address.
- * The internal instance data regarding to this address are deleted as
- * well as each according memory page and its appropriated reserved bit
- * is cleared (ClearPageReserved).
- * Usage: ioctl(fd, MC_DRV_MODULE_FREE, &address) with address beeing of
- * type long address
- */
- MC_DRV_KMOD_IOCTL_FREE = 218,
-
- /**
- * Creates a L2 Table of the given base address and the size of the
- * data.
- * Parameter: mc_ioctl_app_reg_wsm_l2_params
- */
- MC_DRV_KMOD_IOCTL_APP_REGISTER_WSM_L2 = 220,
-
- /**
- * Frees the L2 table created by a MC_DRV_KMOD_IOCTL_APP_REGISTER_WSM_L2
- * ioctl.
- * Parameter: mc_ioctl_app_unreg_wsm_l2_params
- */
- MC_DRV_KMOD_IOCTL_APP_UNREGISTER_WSM_L2 = 221,
-
-
- /* TODO: comment this. */
- MC_DRV_KMOD_IOCTL_DAEMON_LOCK_WSM_L2 = 222,
- MC_DRV_KMOD_IOCTL_DAEMON_UNLOCK_WSM_L2 = 223,
-
- /**
- * Return kernel driver version.
- * Parameter: mc_ioctl_get_version_params
- */
- MC_DRV_KMOD_IOCTL_GET_VERSION = 224,
-};
-
-
-#endif /* _MC_DRV_MODULEAPI_H_ */
-/** @} */
diff --git a/drivers/gud/mobicore_driver/public/mc_kernel_api.h b/drivers/gud/mobicore_driver/public/mc_kernel_api.h
index fdfc618..7a038c4 100644
--- a/drivers/gud/mobicore_driver/public/mc_kernel_api.h
+++ b/drivers/gud/mobicore_driver/public/mc_kernel_api.h
@@ -1,100 +1,76 @@
-/** @addtogroup MCD_MCDIMPL_KMOD_KAPI Mobicore Driver Module API inside Kernel.
- * @ingroup MCD_MCDIMPL_KMOD
- * @{
- * Interface to Mobicore Driver Kernel Module inside Kernel.
- * @file
- *
+/*
* Interface to be used by module MobiCoreKernelAPI.
*
- * <!-- Copyright Giesecke & Devrient GmbH 2010-2012 -->
+ * <-- Copyright Giesecke & Devrient GmbH 2010-2012 -->
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-#ifndef _MOBICORE_KERNELMODULE_API_H_
-#define _MOBICORE_KERNELMODULE_API_H_
+#ifndef _MC_KERNEL_API_H_
+#define _MC_KERNEL_API_H_
struct mc_instance;
-/**
- * Initialize a new mobicore API instance object
+/*
+ * mobicore_open() - Initialize a new MobiCore API instance object
*
- * @return Instance or NULL if no allocation was possible.
+ * Returns a MobiCore Instance or NULL if no allocation was possible.
*/
-struct mc_instance *mobicore_open(
- void
-);
+struct mc_instance *mobicore_open(void);
-/**
- * Release a mobicore instance object and all objects related to it
- * @param instance instance
- * @return 0 if Ok or -E ERROR
+/*
+ * mobicore_release() - Release a MobiCore instance object
+ * @instance: MobiCore instance
+ *
+ * Returns 0 if Ok or -E ERROR
*/
-int mobicore_release(
- struct mc_instance *instance
-);
+int mobicore_release(struct mc_instance *instance);
-/**
- * Free a WSM buffer allocated with mobicore_allocate_wsm
- * @param instance
- * @param handle handle of the buffer
+/*
+ * mobicore_allocate_wsm() - Allocate MobiCore WSM
+ * @instance: instance data for MobiCore Daemon and TLCs
+ * @requested_size: memory size requested in bytes
+ * @handle: pointer to handle
+ * @kernel_virt_addr: virtual user start address
+ * @phys_addr: physical start address
*
- * @return 0 if no error
- *
+ * Returns 0 if OK
*/
-int mobicore_allocate_wsm(
- struct mc_instance *instance,
- unsigned long requested_size,
- uint32_t *handle,
- void **kernel_virt_addr,
- void **phys_addr
-);
+int mobicore_allocate_wsm(struct mc_instance *instance,
+ unsigned long requested_size, uint32_t *handle,
+ void **virt_kernel_addr, void **phys_addr);
-/**
- * Free a WSM buffer allocated with mobicore_allocate_wsm
- * @param instance
- * @param handle handle of the buffer
+/*
+ * mobicore_free() - Free a WSM buffer allocated with mobicore_allocate_wsm
+ * @instance: instance data for MobiCore Daemon and TLCs
+ * @handle: handle of the buffer
*
- * @return 0 if no error
- *
+ * Returns 0 if OK
*/
-int mobicore_free(
- struct mc_instance *instance,
- uint32_t handle
-);
+int mobicore_free_wsm(struct mc_instance *instance, uint32_t handle);
-/**
- * Map a virtual memory buffer structure to Mobicore
- * @param instance
- * @param addr address of the buffer(NB it must be kernel virtual!)
- * @param len buffer length
- * @param handle pointer to handle
- * @param phys_wsm_l2_table pointer to physical L2 table(?)
+/*
+ * mobicore_map_vmem() - Map a virtual memory buffer structure to Mobicore
+ * @instance: instance data for MobiCore Daemon and TLCs
+ * @addr: address of the buffer (NB it must be kernel virtual!)
+ * @len: buffer length (in bytes)
+ * @handle: unique handle
+ * @phys: pointer for physical address of L2 table
*
- * @return 0 if no error
- *
+ * Returns 0 if no error
*/
-int mobicore_map_vmem(
- struct mc_instance *instance,
- void *addr,
- uint32_t len,
- uint32_t *handle,
- void **phys_wsm_l2_table
-);
+int mobicore_map_vmem(struct mc_instance *instance, void *addr,
+ uint32_t len, uint32_t *handle, uint32_t *phys);
-/**
- * Unmap a virtual memory buffer from mobicore
- * @param instance
- * @param handle
+/*
+ * mobicore_unmap_vmem() - Unmap a virtual memory buffer from MobiCore
+ * @instance: instance data for MobiCore Daemon and TLCs
+ * @handle: unique handle
*
- * @return 0 if no error
- *
+ * Returns 0 if no error
*/
-int mobicore_unmap_vmem(
- struct mc_instance *instance,
- uint32_t handle
-);
-#endif /* _MOBICORE_KERNELMODULE_API_H_ */
-/** @} */
+int mobicore_unmap_vmem(struct mc_instance *instance, uint32_t handle);
+
+#endif /* _MC_KERNEL_API_H_ */
diff --git a/drivers/gud/mobicore_driver/public/mc_linux.h b/drivers/gud/mobicore_driver/public/mc_linux.h
new file mode 100644
index 0000000..99b7769
--- /dev/null
+++ b/drivers/gud/mobicore_driver/public/mc_linux.h
@@ -0,0 +1,209 @@
+/*
+ * The MobiCore Driver Kernel Module is a Linux device driver, which represents
+ * the command proxy on the lowest layer to the secure world (Swd). Additional
+ * services like memory allocation via mmap and generation of a L2 tables for
+ * given virtual memory are also supported. IRQ functionality receives
+ * information from the SWd in the non secure world (NWd).
+ * As customary the driver is handled as linux device driver with "open",
+ * "close" and "ioctl" commands. Access to the driver is possible after the
+ * device "/dev/mobicore" has been opened.
+ * The MobiCore Driver Kernel Module must be installed via
+ * "insmod mcDrvModule.ko".
+ *
+ * <-- Copyright Giesecke & Devrient GmbH 2010-2012 -->
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _MC_LINUX_H_
+#define _MC_LINUX_H_
+
+#include "version.h"
+
+#define MC_ADMIN_DEVNODE "mobicore"
+#define MC_USER_DEVNODE "mobicore-user"
+
+/*
+ * Data exchange structure of the MC_DRV_MODULE_INIT ioctl command.
+ * INIT request data to SWD
+ */
+struct mc_ioctl_init {
+ /* notification buffer start/length [16:16] [start, length] */
+ uint32_t nq_offset;
+ /* length of notification queue */
+ uint32_t nq_length;
+ /* mcp buffer start/length [16:16] [start, length] */
+ uint32_t mcp_offset;
+ /* length of mcp buffer */
+ uint32_t mcp_length;
+};
+
+/*
+ * Data exchange structure of the MC_DRV_MODULE_INFO ioctl command.
+ * INFO request data to the SWD
+ */
+struct mc_ioctl_info {
+ uint32_t ext_info_id; /* extended info ID */
+ uint32_t state; /* state */
+ uint32_t ext_info; /* extended info */
+};
+
+/*
+ * Data exchange structure of the MC_IO_MAP_WSM, MC_IO_MAP_MCI, and
+ * MC_IO_MAP_PWSM commands.
+ *
+ * Allocate a contiguous memory buffer for a process.
+ * The physical address can be used as for later calls to mmap.
+ * The handle can be used to communicate about this buffer to the Daemon.
+ * For MC_IO_MAP_MCI command, the reused field indicates that MCI was set up
+ * already. I.e. Daemon was restarted.
+ */
+struct mc_ioctl_map {
+ size_t len; /* Buffer length */
+ uint32_t handle; /* WSM handle */
+ unsigned long addr; /* Virtual address */
+ unsigned long phys_addr;/* physical address of WSM (or NULL) */
+ bool reused; /* if WSM memory was reused, or new allocated */
+};
+
+/*
+ * Data exchange structure of the MC_IO_REG_WSM command.
+ *
+ * Allocates a physical L2 table and maps the buffer into this page.
+ * Returns the physical address of the L2 table.
+ * The page alignment will be created and the appropriated pSize and pOffsetL2
+ * will be modified to the used values.
+ */
+struct mc_ioctl_reg_wsm {
+ uint32_t buffer; /* base address of the virtual address */
+ uint32_t len; /* size of the virtual address space */
+ uint32_t pid; /* process id */
+ uint32_t handle; /* driver handle for locked memory */
+ uint32_t table_phys; /* physical address of the L2 table */
+};
+
+
+/*
+ * Data exchange structure of the MC_DRV_MODULE_FC_EXECUTE ioctl command.
+ * internal, unsupported
+ */
+struct mc_ioctl_execute {
+ /* base address of mobicore binary */
+ uint32_t phys_start_addr;
+ /* length of DDR area */
+ uint32_t length;
+};
+
+/*
+ * Data exchange structure of the MC_IO_RESOLVE_CONT_WSM ioctl command.
+ */
+struct mc_ioctl_resolv_cont_wsm {
+ /* driver handle for buffer */
+ uint32_t handle;
+ /* base address of memory */
+ uint32_t phys;
+ /* length memory */
+ uint32_t length;
+};
+
+
+/*
+ * defines for the ioctl mobicore driver module function call from user space.
+ */
+/* MobiCore IOCTL magic number */
+#define MC_IOC_MAGIC 'M'
+
+#define MC_IO_INIT _IOWR(MC_IOC_MAGIC, 0, struct mc_ioctl_init)
+#define MC_IO_INFO _IOWR(MC_IOC_MAGIC, 1, struct mc_ioctl_info)
+#define MC_IO_VERSION _IOR(MC_IOC_MAGIC, 2, uint32_t)
+/*
+ * ioctl parameter to send the YIELD command to the SWD.
+ * Only possible in Privileged Mode.
+ * ioctl(fd, MC_DRV_MODULE_YIELD)
+ */
+#define MC_IO_YIELD _IO(MC_IOC_MAGIC, 3)
+/*
+ * ioctl parameter to send the NSIQ signal to the SWD.
+ * Only possible in Privileged Mode
+ * ioctl(fd, MC_DRV_MODULE_NSIQ)
+ */
+#define MC_IO_NSIQ _IO(MC_IOC_MAGIC, 4)
+/*
+ * Free's memory which is formerly allocated by the driver's mmap
+ * command. The parameter must be this mmaped address.
+ * The internal instance data regarding to this address are deleted as
+ * well as each according memory page and its appropriated reserved bit
+ * is cleared (ClearPageReserved).
+ * Usage: ioctl(fd, MC_DRV_MODULE_FREE, &address) with address being of
+ * type long address
+ */
+#define MC_IO_FREE _IO(MC_IOC_MAGIC, 5)
+/*
+ * Creates a L2 Table of the given base address and the size of the
+ * data.
+ * Parameter: mc_ioctl_app_reg_wsm_l2_params
+ */
+#define MC_IO_REG_WSM _IOWR(MC_IOC_MAGIC, 6, struct mc_ioctl_reg_wsm)
+#define MC_IO_UNREG_WSM _IO(MC_IOC_MAGIC, 7)
+#define MC_IO_LOCK_WSM _IO(MC_IOC_MAGIC, 8)
+#define MC_IO_UNLOCK_WSM _IO(MC_IOC_MAGIC, 9)
+#define MC_IO_EXECUTE _IOWR(MC_IOC_MAGIC, 10, struct mc_ioctl_execute)
+
+/*
+ * Allocate contiguous memory for a process for later mapping with mmap.
+ * MC_DRV_KMOD_MMAP_WSM usual operation, pages are registered in
+ * device structure and freed later.
+ * MC_DRV_KMOD_MMAP_MCI get Instance of MCI, allocates or mmaps
+ * the MCI to daemon
+ * MC_DRV_KMOD_MMAP_PERSISTENTWSM special operation, without
+ * registration of pages
+ */
+#define MC_IO_MAP_WSM _IOWR(MC_IOC_MAGIC, 11, struct mc_ioctl_map)
+#define MC_IO_MAP_MCI _IOWR(MC_IOC_MAGIC, 12, struct mc_ioctl_map)
+#define MC_IO_MAP_PWSM _IOWR(MC_IOC_MAGIC, 13, struct mc_ioctl_map)
+
+/*
+ * Clean orphaned WSM buffers. Only available to the daemon and should
+ * only be carried out if the TLC crashes or otherwise calls exit() in
+ * an unexpected manner.
+ * The clean is needed together with the lock/unlock mechanism so the daemon
+ * has clear control of the mapped buffers so it can close a Trustlet before
+ * release all the WSM buffers, otherwise the Trustlet would be able to write
+ * to possibly kernel memory areas
+ */
+#define MC_IO_CLEAN_WSM _IO(MC_IOC_MAGIC, 14)
+
+/*
+ * Get L2 phys address of a buffer handle allocated to the user.
+ * Only available to the daemon.
+ */
+#define MC_IO_RESOLVE_WSM _IOWR(MC_IOC_MAGIC, 15, uint32_t)
+
+/*
+ * Get the phys address & length of a allocated contiguous buffer.
+ * Only available to the daemon */
+#define MC_IO_RESOLVE_CONT_WSM _IOWR(MC_IOC_MAGIC, 16, struct mc_ioctl_execute)
+
+#endif /* _MC_LINUX_H_ */
diff --git a/drivers/gud/mobicore_driver/public/version.h b/drivers/gud/mobicore_driver/public/version.h
index 9b2dbca..b08dd95 100644
--- a/drivers/gud/mobicore_driver/public/version.h
+++ b/drivers/gud/mobicore_driver/public/version.h
@@ -1,6 +1,5 @@
-/** @addtogroup MCD_MCDIMPL_KMOD
- * @{
- * <!-- Copyright Giesecke & Devrient GmbH 2010-2012 -->
+/*
+ * <-- Copyright Giesecke & Devrient GmbH 2010-2012 -->
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -30,7 +29,7 @@
#ifndef _MC_DRV_VERSION_H_
#define _MC_DRV_VERSION_H_
-#define MCDRVMODULEAPI_VERSION_MAJOR 0
+#define MCDRVMODULEAPI_VERSION_MAJOR 1
#define MCDRVMODULEAPI_VERSION_MINOR 1
#endif /* _MC_DRV_VERSION_H_ */
diff --git a/drivers/gud/mobicore_kernelapi/clientlib.c b/drivers/gud/mobicore_kernelapi/clientlib.c
index 13826f2..7038e02 100644
--- a/drivers/gud/mobicore_kernelapi/clientlib.c
+++ b/drivers/gud/mobicore_kernelapi/clientlib.c
@@ -1,7 +1,7 @@
-/**
+/*
* MobiCore KernelApi module
*
- * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -19,16 +19,15 @@
#include "public/mobicore_driver_api.h"
#include "public/mobicore_driver_cmd.h"
+#include "include/mcinq.h"
#include "device.h"
#include "session.h"
/* device list */
LIST_HEAD(devices);
-/*----------------------------------------------------------------------------*/
-static struct mcore_device_t *resolve_device_id(
- uint32_t device_id
-) {
+static struct mcore_device_t *resolve_device_id(uint32_t device_id)
+{
struct mcore_device_t *tmp;
struct list_head *pos;
@@ -41,19 +40,13 @@
return NULL;
}
-
-/*----------------------------------------------------------------------------*/
-static void add_device(
- struct mcore_device_t *device
-) {
+static void add_device(struct mcore_device_t *device)
+{
list_add_tail(&(device->list), &devices);
}
-
-/*----------------------------------------------------------------------------*/
-static bool remove_device(
- uint32_t device_id
-) {
+static bool remove_device(uint32_t device_id)
+{
struct mcore_device_t *tmp;
struct list_head *pos, *q;
@@ -68,22 +61,18 @@
return false;
}
-
-/*----------------------------------------------------------------------------*/
-enum mc_result mc_open_device(
- uint32_t device_id
-) {
+enum mc_result mc_open_device(uint32_t device_id)
+{
enum mc_result mc_result = MC_DRV_OK;
struct connection *dev_con = NULL;
- MCDRV_DBG_VERBOSE("===%s()===", __func__);
-
- /* Enter critical section */
+ MCDRV_DBG_VERBOSE(mc_kapi, "===%s()===", __func__);
do {
struct mcore_device_t *device = resolve_device_id(device_id);
if (device != NULL) {
- MCDRV_DBG_ERROR("Device %d already opened", device_id);
+ MCDRV_DBG_ERROR(mc_kapi,
+ "Device %d already opened", device_id);
mc_result = MC_DRV_ERR_INVALID_OPERATION;
break;
}
@@ -92,6 +81,7 @@
dev_con = connection_new();
if (!connection_connect(dev_con, MC_DAEMON_PID)) {
MCDRV_DBG_ERROR(
+ mc_kapi,
"Could not setup netlink connection to PID %u",
MC_DAEMON_PID);
mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
@@ -100,12 +90,11 @@
/* Forward device open to the daemon and read result */
struct mc_drv_cmd_open_device_t mc_drv_cmd_open_device = {
- /* C++ does not support C99 designated initializers */
- /* .header = */ {
- /* .command_id = */ MC_DRV_CMD_OPEN_DEVICE
+ {
+ MC_DRV_CMD_OPEN_DEVICE
},
- /* .payload = */ {
- /* .device_id = */ device_id
+ {
+ device_id
}
};
@@ -114,8 +103,9 @@
&mc_drv_cmd_open_device,
sizeof(struct mc_drv_cmd_open_device_t));
if (len < 0) {
- MCDRV_DBG_ERROR("CMD_OPEN_DEVICE writeCmd failed "
- "ret=%d", len);
+ MCDRV_DBG_ERROR(mc_kapi,
+ "CMD_OPEN_DEVICE writeCmd failed %d",
+ len);
mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
break;
}
@@ -126,14 +116,16 @@
&rsp_header,
sizeof(rsp_header));
if (len != sizeof(rsp_header)) {
- MCDRV_DBG_ERROR("CMD_OPEN_DEVICE readRsp failed "
- "ret=%d", len);
+ MCDRV_DBG_ERROR(mc_kapi,
+ "CMD_OPEN_DEVICE readRsp failed %d",
+ len);
mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
break;
}
if (rsp_header.response_id != MC_DRV_RSP_OK) {
- MCDRV_DBG_ERROR("CMD_OPEN_DEVICE failed, respId=%d",
- rsp_header.response_id);
+ MCDRV_DBG_ERROR(mc_kapi,
+ "CMD_OPEN_DEVICE failed, respId=%d",
+ rsp_header.response_id);
switch (rsp_header.response_id) {
case MC_DRV_RSP_PAYLOAD_LENGTH_ERROR:
mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
@@ -154,8 +146,9 @@
device = mcore_device_create(device_id, dev_con);
if (!mcore_device_open(device, MC_DRV_MOD_DEVNODE_FULLPATH)) {
mcore_device_cleanup(device);
- MCDRV_DBG_ERROR("could not open device file: %s",
- MC_DRV_MOD_DEVNODE_FULLPATH);
+ MCDRV_DBG_ERROR(mc_kapi,
+ "could not open device file: %s",
+ MC_DRV_MOD_DEVNODE_FULLPATH);
mc_result = MC_DRV_ERR_INVALID_DEVICE_FILE;
break;
}
@@ -167,25 +160,20 @@
if (mc_result != MC_DRV_OK)
connection_cleanup(dev_con);
- /* Exit critical section */
-
return mc_result;
}
EXPORT_SYMBOL(mc_open_device);
-/*----------------------------------------------------------------------------*/
-enum mc_result mc_close_device(
- uint32_t device_id
-) {
+enum mc_result mc_close_device(uint32_t device_id)
+{
enum mc_result mc_result = MC_DRV_OK;
- MCDRV_DBG_VERBOSE("===%s()===", __func__);
+ MCDRV_DBG_VERBOSE(mc_kapi, "===%s()===", __func__);
- /* Enter critical section */
do {
struct mcore_device_t *device = resolve_device_id(device_id);
if (device == NULL) {
- MCDRV_DBG_ERROR("Device not found");
+ MCDRV_DBG_ERROR(mc_kapi, "Device not found");
mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
break;
}
@@ -193,15 +181,15 @@
/* Return if not all sessions have been closed */
if (mcore_device_has_sessions(device)) {
- MCDRV_DBG_ERROR("cannot close with sessions pending");
+ MCDRV_DBG_ERROR(mc_kapi,
+ "cannot close with sessions pending");
mc_result = MC_DRV_ERR_SESSION_PENDING;
break;
}
struct mc_drv_cmd_close_device_t mc_drv_cmd_close_device = {
- /* C++ does not support C99 designated initializers */
- /* .header = */ {
- /* .command_id = */ MC_DRV_CMD_CLOSE_DEVICE
+ {
+ MC_DRV_CMD_CLOSE_DEVICE
}
};
int len = connection_write_data(
@@ -210,8 +198,9 @@
sizeof(struct mc_drv_cmd_close_device_t));
/* ignore error, but log details */
if (len < 0) {
- MCDRV_DBG_ERROR("CMD_CLOSE_DEVICE writeCmd failed "
- "ret=%d", len);
+ MCDRV_DBG_ERROR(mc_kapi,
+ "CMD_CLOSE_DEVICE writeCmd failed %d",
+ len);
mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
}
@@ -221,15 +210,17 @@
&rsp_header,
sizeof(rsp_header));
if (len != sizeof(rsp_header)) {
- MCDRV_DBG_ERROR("CMD_CLOSE_DEVICE readResp failed "
- " ret=%d", len);
+ MCDRV_DBG_ERROR(mc_kapi,
+ "CMD_CLOSE_DEVICE readResp failed %d",
+ len);
mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
break;
}
if (rsp_header.response_id != MC_DRV_RSP_OK) {
- MCDRV_DBG_ERROR("CMD_CLOSE_DEVICE failed, respId=%d",
- rsp_header.response_id);
+ MCDRV_DBG_ERROR(mc_kapi,
+ "CMD_CLOSE_DEVICE failed, respId=%d",
+ rsp_header.response_id);
mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
break;
}
@@ -238,44 +229,37 @@
} while (false);
- /* Exit critical section */
-
return mc_result;
}
EXPORT_SYMBOL(mc_close_device);
-/*----------------------------------------------------------------------------*/
-enum mc_result mc_open_session(
- struct mc_session_handle *session,
- const struct mc_uuid_t *uuid,
- uint8_t *tci,
- uint32_t len
-) {
+enum mc_result mc_open_session(struct mc_session_handle *session,
+ const struct mc_uuid_t *uuid,
+ uint8_t *tci, uint32_t len)
+{
enum mc_result mc_result = MC_DRV_OK;
- MCDRV_DBG_VERBOSE("===%s()===", __func__);
-
- /* Enter critical section */
+ MCDRV_DBG_VERBOSE(mc_kapi, "===%s()===", __func__);
do {
if (session == NULL) {
- MCDRV_DBG_ERROR("Session is null");
+ MCDRV_DBG_ERROR(mc_kapi, "Session is null");
mc_result = MC_DRV_ERR_INVALID_PARAMETER;
break;
}
if (uuid == NULL) {
- MCDRV_DBG_ERROR("UUID is null");
+ MCDRV_DBG_ERROR(mc_kapi, "UUID is null");
mc_result = MC_DRV_ERR_INVALID_PARAMETER;
break;
}
if (tci == NULL) {
- MCDRV_DBG_ERROR("TCI is null");
+ MCDRV_DBG_ERROR(mc_kapi, "TCI is null");
mc_result = MC_DRV_ERR_INVALID_PARAMETER;
break;
}
if (len > MC_MAX_TCI_LEN) {
- MCDRV_DBG_ERROR("TCI length is longer than %d",
- MC_MAX_TCI_LEN);
+ MCDRV_DBG_ERROR(mc_kapi, "TCI length is longer than %d",
+ MC_MAX_TCI_LEN);
mc_result = MC_DRV_ERR_INVALID_PARAMETER;
break;
}
@@ -284,7 +268,7 @@
struct mcore_device_t *device =
resolve_device_id(session->device_id);
if (device == NULL) {
- MCDRV_DBG_ERROR("Device not found");
+ MCDRV_DBG_ERROR(mc_kapi, "Device not found");
mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
break;
}
@@ -294,40 +278,40 @@
struct wsm *wsm =
mcore_device_find_contiguous_wsm(device, tci);
if (wsm == NULL) {
- MCDRV_DBG_ERROR("Could not resolve TCI phy address ");
+ MCDRV_DBG_ERROR(mc_kapi,
+ "Could not resolve TCI phy address ");
mc_result = MC_DRV_ERR_INVALID_PARAMETER;
break;
}
if (wsm->len < len) {
- MCDRV_DBG_ERROR("length is more than allocated TCI");
+ MCDRV_DBG_ERROR(mc_kapi,
+ "length is more than allocated TCI");
mc_result = MC_DRV_ERR_INVALID_PARAMETER;
break;
}
/* Prepare open session command */
struct mc_drv_cmd_open_session_t cmdOpenSession = {
- /* C++ does not support C99 designated initializers */
- /* .header = */ {
- /* .command_id = */ MC_DRV_CMD_OPEN_SESSION
+ {
+ MC_DRV_CMD_OPEN_SESSION
},
- /* .payload = */ {
- /* .device_id = */ session->device_id,
- /* .uuid = */ *uuid,
- /* .tci = */ (uint32_t)wsm->phys_addr,
- /* .len = */ len
+ {
+ session->device_id,
+ *uuid,
+ (uint32_t)wsm->phys_addr,
+ len
}
};
/* Transmit command data */
-
- int len = connection_write_data(
- dev_con,
+ int len = connection_write_data(dev_con,
&cmdOpenSession,
sizeof(cmdOpenSession));
if (len != sizeof(cmdOpenSession)) {
- MCDRV_DBG_ERROR("CMD_OPEN_SESSION writeData failed "
- "ret=%d", len);
+ MCDRV_DBG_ERROR(mc_kapi,
+ "CMD_OPEN_SESSION writeData failed %d",
+ len);
mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
break;
}
@@ -336,20 +320,21 @@
/* read header first */
struct mc_drv_response_header_t rsp_header;
- len = connection_read_datablock(
- dev_con,
- &rsp_header,
- sizeof(rsp_header));
+ len = connection_read_datablock(dev_con,
+ &rsp_header,
+ sizeof(rsp_header));
if (len != sizeof(rsp_header)) {
- MCDRV_DBG_ERROR("CMD_OPEN_SESSION readResp failed "
- " ret=%d", len);
+ MCDRV_DBG_ERROR(mc_kapi,
+ "CMD_OPEN_SESSION readResp failed %d",
+ len);
mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
break;
}
if (rsp_header.response_id != MC_DRV_RSP_OK) {
- MCDRV_DBG_ERROR("CMD_OPEN_SESSION failed, respId=%d",
- rsp_header.response_id);
+ MCDRV_DBG_ERROR(mc_kapi,
+ "CMD_OPEN_SESSION failed, respId=%d",
+ rsp_header.response_id);
switch (rsp_header.response_id) {
case MC_DRV_RSP_TRUSTLET_NOT_FOUND:
mc_result = MC_DRV_ERR_INVALID_DEVICE_FILE;
@@ -366,14 +351,15 @@
/* read payload */
struct mc_drv_rsp_open_session_payload_t
- rsp_open_session_payload;
+ rsp_open_session_payload;
len = connection_read_datablock(
dev_con,
&rsp_open_session_payload,
sizeof(rsp_open_session_payload));
if (len != sizeof(rsp_open_session_payload)) {
- MCDRV_DBG_ERROR("CMD_OPEN_SESSION readPayload failed "
- "ret=%d", len);
+ MCDRV_DBG_ERROR(mc_kapi,
+ "CMD_OPEN_SESSION readPayload fail %d",
+ len);
mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
break;
}
@@ -383,9 +369,10 @@
/* Set up second channel for notifications */
struct connection *session_connection = connection_new();
- /*TODO: no real need to connect here? */
+
if (!connection_connect(session_connection, MC_DAEMON_PID)) {
MCDRV_DBG_ERROR(
+ mc_kapi,
"Could not setup netlink connection to PID %u",
MC_DAEMON_PID);
connection_cleanup(session_connection);
@@ -393,42 +380,38 @@
break;
}
- /*TODO CONTINOUE HERE !!!! FIX RW RETURN HANDLING!!!! */
-
/* Write command to use channel for notifications */
struct mc_drv_cmd_nqconnect_t cmd_nqconnect = {
- /* C++ does not support C99 designated initializers */
- /* .header = */ {
- /* .command_id = */ MC_DRV_CMD_NQ_CONNECT
+ {
+ MC_DRV_CMD_NQ_CONNECT
},
- /* .payload = */ {
- /* .device_id = */ session->device_id,
- /* .session_id = */ session->session_id,
- /* .device_session_id = */
+ {
+ session->device_id,
+ session->session_id,
rsp_open_session_payload.device_session_id,
- /* .session_magic = */
- rsp_open_session_payload.session_magic
+ rsp_open_session_payload.session_magic
}
};
connection_write_data(session_connection,
- &cmd_nqconnect,
- sizeof(cmd_nqconnect));
+ &cmd_nqconnect,
+ sizeof(cmd_nqconnect));
/* Read command response, header first */
- len = connection_read_datablock(
- session_connection,
- &rsp_header,
- sizeof(rsp_header));
+ len = connection_read_datablock(session_connection,
+ &rsp_header,
+ sizeof(rsp_header));
if (len != sizeof(rsp_header)) {
- MCDRV_DBG_ERROR("CMD_NQ_CONNECT readRsp failed "
- "ret=%d", len);
+ MCDRV_DBG_ERROR(mc_kapi,
+ "CMD_NQ_CONNECT readRsp failed %d",
+ len);
connection_cleanup(session_connection);
mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
break;
}
if (rsp_header.response_id != MC_DRV_RSP_OK) {
- MCDRV_DBG_ERROR("CMD_NQ_CONNECT failed, respId=%d",
+ MCDRV_DBG_ERROR(mc_kapi,
+ "CMD_NQ_CONNECT failed, respId=%d",
rsp_header.response_id);
connection_cleanup(session_connection);
mc_result = MC_DRV_ERR_NQ_FAILED;
@@ -438,84 +421,78 @@
/* there is no payload. */
/* Session established, new session object must be created */
- mcore_device_create_new_session(
- device,
- session->session_id,
- session_connection);
+ mcore_device_create_new_session(device,
+ session->session_id,
+ session_connection);
} while (false);
- /* Exit critical section */
-
return mc_result;
}
EXPORT_SYMBOL(mc_open_session);
-/*----------------------------------------------------------------------------*/
-enum mc_result mc_close_session(
- struct mc_session_handle *session
-) {
+enum mc_result mc_close_session(struct mc_session_handle *session)
+{
enum mc_result mc_result = MC_DRV_OK;
- MCDRV_DBG_VERBOSE("===%s()===", __func__);
-
- /* Enter critical section */
+ MCDRV_DBG_VERBOSE(mc_kapi, "===%s()===", __func__);
do {
if (session == NULL) {
- MCDRV_DBG_ERROR("Session is null");
+ MCDRV_DBG_ERROR(mc_kapi, "Session is null");
mc_result = MC_DRV_ERR_INVALID_PARAMETER;
break;
}
- struct mcore_device_t *device =
+ struct mcore_device_t *device =
resolve_device_id(session->device_id);
if (device == NULL) {
- MCDRV_DBG_ERROR("Device not found");
+ MCDRV_DBG_ERROR(mc_kapi, "Device not found");
mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
break;
}
- struct connection *dev_con = device->connection;
+ struct connection *dev_con = device->connection;
- struct session *nq_session =
- mcore_device_resolve_session_id(device, session->session_id);
+ struct session *nq_session =
+ mcore_device_resolve_session_id(device,
+ session->session_id);
+
if (nq_session == NULL) {
- MCDRV_DBG_ERROR("Session not found");
+ MCDRV_DBG_ERROR(mc_kapi, "Session not found");
mc_result = MC_DRV_ERR_UNKNOWN_SESSION;
break;
}
/* Write close session command */
struct mc_drv_cmd_close_session_t cmd_close_session = {
- /* C++ does not support C99 designated initializers */
- /* .header = */ {
- /* .command_id = */ MC_DRV_CMD_CLOSE_SESSION
+ {
+ MC_DRV_CMD_CLOSE_SESSION
},
- /* .payload = */ {
- /* .session_id = */ session->session_id,
+ {
+ session->session_id,
}
};
- connection_write_data(
- dev_con,
- &cmd_close_session,
- sizeof(cmd_close_session));
+ connection_write_data(dev_con,
+ &cmd_close_session,
+ sizeof(cmd_close_session));
/* Read command response */
struct mc_drv_response_header_t rsp_header;
- int len = connection_read_datablock(
- dev_con,
- &rsp_header,
- sizeof(rsp_header));
+ int len = connection_read_datablock(dev_con,
+ &rsp_header,
+ sizeof(rsp_header));
if (len != sizeof(rsp_header)) {
- MCDRV_DBG_ERROR("CMD_CLOSE_SESSION readRsp failed "
- "ret=%d", len);
+ MCDRV_DBG_ERROR(mc_kapi,
+ "CMD_CLOSE_SESSION readRsp failed %d",
+ len);
mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
break;
}
if (rsp_header.response_id != MC_DRV_RSP_OK) {
- MCDRV_DBG_ERROR("CMD_CLOSE_SESSION failed, respId=%d",
- rsp_header.response_id);
+ MCDRV_DBG_ERROR(mc_kapi,
+ "CMD_CLOSE_SESSION failed, respId=%d",
+ rsp_header.response_id);
mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
break;
}
@@ -525,23 +502,19 @@
} while (false);
- /* Exit critical section */
-
return mc_result;
}
EXPORT_SYMBOL(mc_close_session);
-/*----------------------------------------------------------------------------*/
-enum mc_result mc_notify(
- struct mc_session_handle *session
-) {
+enum mc_result mc_notify(struct mc_session_handle *session)
+{
enum mc_result mc_result = MC_DRV_OK;
- MCDRV_DBG_VERBOSE("===%s()===", __func__);
+ MCDRV_DBG_VERBOSE(mc_kapi, "===%s()===", __func__);
do {
if (session == NULL) {
- MCDRV_DBG_ERROR("Session is null");
+ MCDRV_DBG_ERROR(mc_kapi, "Session is null");
mc_result = MC_DRV_ERR_INVALID_PARAMETER;
break;
}
@@ -549,7 +522,7 @@
struct mcore_device_t *device =
resolve_device_id(session->device_id);
if (device == NULL) {
- MCDRV_DBG_ERROR("Device not found");
+ MCDRV_DBG_ERROR(mc_kapi, "Device not found");
mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
break;
}
@@ -558,25 +531,23 @@
struct session *nqsession =
mcore_device_resolve_session_id(device, session->session_id);
if (nqsession == NULL) {
- MCDRV_DBG_ERROR("Session not found");
+ MCDRV_DBG_ERROR(mc_kapi, "Session not found");
mc_result = MC_DRV_ERR_UNKNOWN_SESSION;
break;
}
struct mc_drv_cmd_notify_t cmd_notify = {
- /* C++ does not support C99 designated initializers */
- /* .header = */ {
- /* .command_id = */ MC_DRV_CMD_NOTIFY
+ {
+ MC_DRV_CMD_NOTIFY
},
- /* .payload = */ {
- /* .session_id = */ session->session_id,
+ {
+ session->session_id
}
};
- connection_write_data(
- dev_con,
- &cmd_notify,
- sizeof(cmd_notify));
+ connection_write_data(dev_con,
+ &cmd_notify,
+ sizeof(cmd_notify));
/* Daemon will not return a response */
@@ -586,14 +557,12 @@
}
EXPORT_SYMBOL(mc_notify);
-/*----------------------------------------------------------------------------*/
-enum mc_result mc_wait_notification(
- struct mc_session_handle *session,
- int32_t timeout
-) {
+enum mc_result mc_wait_notification(struct mc_session_handle *session,
+ int32_t timeout)
+{
enum mc_result mc_result = MC_DRV_OK;
- MCDRV_DBG_VERBOSE("===%s()===", __func__);
+ MCDRV_DBG_VERBOSE(mc_kapi, "===%s()===", __func__);
do {
if (session == NULL) {
@@ -601,18 +570,19 @@
break;
}
- struct mcore_device_t *device =
+ struct mcore_device_t *device =
resolve_device_id(session->device_id);
if (device == NULL) {
- MCDRV_DBG_ERROR("Device not found");
+ MCDRV_DBG_ERROR(mc_kapi, "Device not found");
mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
break;
}
- struct session *nq_session =
- mcore_device_resolve_session_id(device, session->session_id);
+ struct session *nq_session =
+ mcore_device_resolve_session_id(device,
+ session->session_id);
if (nq_session == NULL) {
- MCDRV_DBG_ERROR("Session not found");
+ MCDRV_DBG_ERROR(mc_kapi, "Session not found");
mc_result = MC_DRV_ERR_UNKNOWN_SESSION;
break;
}
@@ -624,22 +594,26 @@
/* Read notification queue till it's empty */
for (;;) {
struct notification notification;
- ssize_t num_read = connection_read_data(
- nqconnection,
- ¬ification,
- sizeof(notification),
- timeout);
- /* Exit on timeout in first run. Later runs have
+ ssize_t num_read =
+ connection_read_data(nqconnection,
+ ¬ification,
+ sizeof(notification),
+ timeout);
+ /*
+ * Exit on timeout in first run. Later runs have
* timeout set to 0.
- * -2 means, there is no more data. */
+ * -2 means, there is no more data.
+ */
if (count == 0 && num_read == -2) {
- MCDRV_DBG_ERROR("read timeout");
+ MCDRV_DBG_ERROR(mc_kapi, "read timeout");
mc_result = MC_DRV_ERR_TIMEOUT;
break;
}
- /* After first notification the queue will be
+ /*
+ * After first notification the queue will be
* drained, Thus we set no timeout for the
- * following reads */
+ * following reads
+ */
timeout = 0;
if (num_read != sizeof(struct notification)) {
@@ -647,28 +621,33 @@
/* failure in first read, notify it */
mc_result = MC_DRV_ERR_NOTIFICATION;
MCDRV_DBG_ERROR(
+ mc_kapi,
"read notification failed, "
"%i bytes received", (int)num_read);
break;
} else {
- /* Read of the n-th notification
- failed/timeout. We don't tell the
- caller, as we got valid notifications
- before. */
+ /*
+ * Read of the n-th notification
+ * failed/timeout. We don't tell the
+ * caller, as we got valid notifications
+ * before.
+ */
mc_result = MC_DRV_OK;
break;
}
}
count++;
- MCDRV_DBG_VERBOSE("readNq count=%d, SessionID=%d, "
- "Payload=%d", count,
- notification.session_id, notification.payload);
+ MCDRV_DBG_VERBOSE(mc_kapi,
+ "count=%d, SessionID=%d, Payload=%d",
+ count,
+ notification.session_id,
+ notification.payload);
if (notification.payload != 0) {
/* Session end point died -> store exit code */
session_set_error_info(nq_session,
- notification.payload);
+ notification.payload);
mc_result = MC_DRV_INFO_NOTIFICATION;
break;
@@ -681,24 +660,17 @@
}
EXPORT_SYMBOL(mc_wait_notification);
-/*----------------------------------------------------------------------------*/
-enum mc_result mc_malloc_wsm(
- uint32_t device_id,
- uint32_t align,
- uint32_t len,
- uint8_t **wsm,
- uint32_t wsm_flags
-) {
+enum mc_result mc_malloc_wsm(uint32_t device_id, uint32_t align, uint32_t len,
+ uint8_t **wsm, uint32_t wsm_flags)
+{
enum mc_result mc_result = MC_DRV_ERR_UNKNOWN;
- MCDRV_DBG_VERBOSE("===%s()===", __func__);
-
- /* Enter critical section */
+ MCDRV_DBG_VERBOSE(mc_kapi, "===%s()===", __func__);
do {
struct mcore_device_t *device = resolve_device_id(device_id);
if (device == NULL) {
- MCDRV_DBG_ERROR("Device not found");
+ MCDRV_DBG_ERROR(mc_kapi, "Device not found");
mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
break;
}
@@ -710,7 +682,7 @@
struct wsm *wsm_stack =
mcore_device_allocate_contiguous_wsm(device, len);
if (wsm_stack == NULL) {
- MCDRV_DBG_ERROR("Allocation of WSM failed");
+ MCDRV_DBG_ERROR(mc_kapi, "Allocation of WSM failed");
mc_result = MC_DRV_ERR_NO_FREE_MEMORY;
break;
}
@@ -720,31 +692,24 @@
} while (false);
- /* Exit critical section */
-
return mc_result;
}
EXPORT_SYMBOL(mc_malloc_wsm);
-/*----------------------------------------------------------------------------*/
-enum mc_result mc_free_wsm(
- uint32_t device_id,
- uint8_t *wsm
-) {
+enum mc_result mc_free_wsm(uint32_t device_id, uint8_t *wsm)
+{
enum mc_result mc_result = MC_DRV_ERR_UNKNOWN;
struct mcore_device_t *device;
- MCDRV_DBG_VERBOSE("===%s()===", __func__);
-
- /* Enter critical section */
+ MCDRV_DBG_VERBOSE(mc_kapi, "===%s()===", __func__);
do {
/* Get the device associated wit the given session */
device = resolve_device_id(device_id);
if (device == NULL) {
- MCDRV_DBG_ERROR("Device not found");
+ MCDRV_DBG_ERROR(mc_kapi, "Device not found");
mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
break;
}
@@ -753,14 +718,15 @@
struct wsm *wsm_stack =
mcore_device_find_contiguous_wsm(device, wsm);
if (wsm_stack == NULL) {
- MCDRV_DBG_ERROR("unknown address");
+ MCDRV_DBG_ERROR(mc_kapi, "unknown address");
mc_result = MC_DRV_ERR_INVALID_PARAMETER;
break;
}
/* Free the given virtual address */
if (!mcore_device_free_contiguous_wsm(device, wsm_stack)) {
- MCDRV_DBG_ERROR("Free of virtual address failed");
+ MCDRV_DBG_ERROR(mc_kapi,
+ "Free of virtual address failed");
mc_result = MC_DRV_ERR_FREE_MEMORY_FAILED;
break;
}
@@ -768,130 +734,124 @@
} while (false);
- /* Exit critical section */
-
return mc_result;
}
EXPORT_SYMBOL(mc_free_wsm);
-/*----------------------------------------------------------------------------*/
-enum mc_result mc_map(
- struct mc_session_handle *session_handle,
- void *buf,
- uint32_t buf_len,
- struct mc_bulk_map *map_info
-) {
+enum mc_result mc_map(struct mc_session_handle *session_handle, void *buf,
+ uint32_t buf_len, struct mc_bulk_map *map_info)
+{
enum mc_result mc_result = MC_DRV_ERR_UNKNOWN;
- MCDRV_DBG_VERBOSE("===%s()===", __func__);
-
- /* Enter critical section */
+ MCDRV_DBG_VERBOSE(mc_kapi, "===%s()===", __func__);
do {
if (session_handle == NULL) {
- MCDRV_DBG_ERROR("session_handle is null");
+ MCDRV_DBG_ERROR(mc_kapi, "session_handle is null");
mc_result = MC_DRV_ERR_INVALID_PARAMETER;
break;
}
if (map_info == NULL) {
- MCDRV_DBG_ERROR("map_info is null");
+ MCDRV_DBG_ERROR(mc_kapi, "map_info is null");
mc_result = MC_DRV_ERR_INVALID_PARAMETER;
break;
}
if (buf == NULL) {
- MCDRV_DBG_ERROR("buf is null");
+ MCDRV_DBG_ERROR(mc_kapi, "buf is null");
mc_result = MC_DRV_ERR_INVALID_PARAMETER;
break;
}
/* Determine device the session belongs to */
- struct mcore_device_t *device = resolve_device_id(
- session_handle->device_id);
+ struct mcore_device_t *device =
+ resolve_device_id(session_handle->device_id);
+
if (device == NULL) {
- MCDRV_DBG_ERROR("Device not found");
+ MCDRV_DBG_ERROR(mc_kapi, "Device not found");
mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
break;
}
struct connection *dev_con = device->connection;
/* Get session */
- struct session *session =
- mcore_device_resolve_session_id(device,
- session_handle->session_id);
+ uint32_t session_id = session_handle->session_id;
+ struct session *session =
+ mcore_device_resolve_session_id(device,
+ session_id);
if (session == NULL) {
- MCDRV_DBG_ERROR("Session not found");
+ MCDRV_DBG_ERROR(mc_kapi, "Session not found");
mc_result = MC_DRV_ERR_UNKNOWN_SESSION;
break;
}
- /* Register mapped bulk buffer to Kernel Module and keep mapped
- bulk buffer in mind */
- struct bulk_buffer_descriptor *bulk_buf = session_add_bulk_buf(
- session, buf, buf_len);
+ /*
+ * Register mapped bulk buffer to Kernel Module and keep mapped
+ * bulk buffer in mind
+ */
+ struct bulk_buffer_descriptor *bulk_buf =
+ session_add_bulk_buf(session, buf, buf_len);
if (bulk_buf == NULL) {
- MCDRV_DBG_ERROR("Error mapping bulk buffer");
+ MCDRV_DBG_ERROR(mc_kapi, "Error mapping bulk buffer");
mc_result = MC_DRV_ERR_BULK_MAPPING;
break;
}
/* Prepare map command */
struct mc_drv_cmd_map_bulk_mem_t mc_drv_cmd_map_bulk_mem = {
- /* C++ does not support C99 designated initializers */
- /* .header = */ {
- /* .command_id = */ MC_DRV_CMD_MAP_BULK_BUF
+ {
+ MC_DRV_CMD_MAP_BULK_BUF
},
- /* .payload = */ {
- /* .session_id = */ session->session_id,
- /* .phys_addr_l2; = */
- (uint32_t)bulk_buf->phys_addr_wsm_l2,
- /* .offset_payload = */
- (uint32_t)(bulk_buf->virt_addr) & 0xFFF,
- /* .len_bulk_mem = */ bulk_buf->len
+ {
+ session->session_id,
+ bulk_buf->handle,
+ (uint32_t)bulk_buf->phys_addr_wsm_l2,
+ (uint32_t)(bulk_buf->virt_addr) & 0xFFF,
+ bulk_buf->len
}
};
/* Transmit map command to MobiCore device */
- connection_write_data(
- dev_con,
- &mc_drv_cmd_map_bulk_mem,
- sizeof(mc_drv_cmd_map_bulk_mem));
+ connection_write_data(dev_con,
+ &mc_drv_cmd_map_bulk_mem,
+ sizeof(mc_drv_cmd_map_bulk_mem));
/* Read command response */
struct mc_drv_response_header_t rsp_header;
- int len = connection_read_datablock(
- dev_con,
- &rsp_header,
- sizeof(rsp_header));
+ int len = connection_read_datablock(dev_con,
+ &rsp_header,
+ sizeof(rsp_header));
if (len != sizeof(rsp_header)) {
- MCDRV_DBG_ERROR("CMD_MAP_BULK_BUF readRsp failed, "
- "ret=%d", len);
+ MCDRV_DBG_ERROR(mc_kapi,
+ "CMD_MAP_BULK_BUF readRsp failed %d",
+ len);
mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
break;
}
if (rsp_header.response_id != MC_DRV_RSP_OK) {
- MCDRV_DBG_ERROR("CMD_MAP_BULK_BUF failed, respId=%d",
- rsp_header.response_id);
- /* REV We ignore Daemon Error code because client cannot
- handle it anyhow. */
+ MCDRV_DBG_ERROR(mc_kapi,
+ "CMD_MAP_BULK_BUF failed, respId=%d",
+ rsp_header.response_id);
+
mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
- /* Unregister mapped bulk buffer from Kernel Module and
- remove mapped bulk buffer from session maintenance */
+ /*
+ * Unregister mapped bulk buffer from Kernel Module and
+ * remove mapped bulk buffer from session maintenance
+ */
if (!session_remove_bulk_buf(session, buf)) {
/* Removing of bulk buffer not possible */
- MCDRV_DBG_ERROR("Unregistering of bulk memory"
- "from Kernel Module failed");
+ MCDRV_DBG_ERROR(mc_kapi,
+ "Unreg of bulk memory failed");
}
break;
}
struct mc_drv_rsp_map_bulk_mem_payload_t
rsp_map_bulk_mem_payload;
- connection_read_datablock(
- dev_con,
- &rsp_map_bulk_mem_payload,
- sizeof(rsp_map_bulk_mem_payload));
+ connection_read_datablock(dev_con,
+ &rsp_map_bulk_mem_payload,
+ sizeof(rsp_map_bulk_mem_payload));
/* Set mapping info for Trustlet */
map_info->secure_virt_addr =
@@ -901,37 +861,30 @@
} while (false);
- /* Exit critical section */
-
return mc_result;
}
EXPORT_SYMBOL(mc_map);
-/*----------------------------------------------------------------------------*/
-enum mc_result mc_unmap(
- struct mc_session_handle *session_handle,
- void *buf,
- struct mc_bulk_map *map_info
-) {
+enum mc_result mc_unmap(struct mc_session_handle *session_handle, void *buf,
+ struct mc_bulk_map *map_info)
+{
enum mc_result mc_result = MC_DRV_ERR_UNKNOWN;
- MCDRV_DBG_VERBOSE("===%s()===", __func__);
-
- /* Enter critical section */
+ MCDRV_DBG_VERBOSE(mc_kapi, "===%s()===", __func__);
do {
if (session_handle == NULL) {
- MCDRV_DBG_ERROR("session_handle is null");
+ MCDRV_DBG_ERROR(mc_kapi, "session_handle is null");
mc_result = MC_DRV_ERR_INVALID_PARAMETER;
break;
}
if (map_info == NULL) {
- MCDRV_DBG_ERROR("map_info is null");
+ MCDRV_DBG_ERROR(mc_kapi, "map_info is null");
mc_result = MC_DRV_ERR_INVALID_PARAMETER;
break;
}
if (buf == NULL) {
- MCDRV_DBG_ERROR("buf is null");
+ MCDRV_DBG_ERROR(mc_kapi, "buf is null");
mc_result = MC_DRV_ERR_INVALID_PARAMETER;
break;
}
@@ -940,79 +893,83 @@
struct mcore_device_t *device =
resolve_device_id(session_handle->device_id);
if (device == NULL) {
- MCDRV_DBG_ERROR("Device not found");
+ MCDRV_DBG_ERROR(mc_kapi, "Device not found");
mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
break;
}
- struct connection *dev_con = device->connection;
+ struct connection *dev_con = device->connection;
/* Get session */
+ uint32_t session_id = session_handle->session_id;
struct session *session =
mcore_device_resolve_session_id(device,
- session_handle->session_id);
+ session_id);
if (session == NULL) {
- MCDRV_DBG_ERROR("Session not found");
+ MCDRV_DBG_ERROR(mc_kapi, "Session not found");
mc_result = MC_DRV_ERR_UNKNOWN_SESSION;
break;
}
+ uint32_t handle = session_find_bulk_buf(session, buf);
+ if (handle == 0) {
+ MCDRV_DBG_ERROR(mc_kapi, "Buffer not found");
+ mc_result = MC_DRV_ERR_BULK_UNMAPPING;
+ break;
+ }
+
+
/* Prepare unmap command */
struct mc_drv_cmd_unmap_bulk_mem_t cmd_unmap_bulk_mem = {
- /* .header = */ {
- /* .command_id = */
- MC_DRV_CMD_UNMAP_BULK_BUF
+ {
+ MC_DRV_CMD_UNMAP_BULK_BUF
},
- /* .payload = */ {
- /* .session_id = */ session->session_id,
- /* .secure_virtual_adr = */
- (uint32_t)(map_info->secure_virt_addr),
- /* .len_bulk_mem =
- map_info->secure_virt_len*/
+ {
+ session->session_id,
+ handle,
+ (uint32_t)(map_info->secure_virt_addr)
}
};
- connection_write_data(
- dev_con,
- &cmd_unmap_bulk_mem,
- sizeof(cmd_unmap_bulk_mem));
+ connection_write_data(dev_con,
+ &cmd_unmap_bulk_mem,
+ sizeof(cmd_unmap_bulk_mem));
/* Read command response */
struct mc_drv_response_header_t rsp_header;
- int len = connection_read_datablock(
- dev_con,
- &rsp_header,
- sizeof(rsp_header));
+ int len = connection_read_datablock(dev_con,
+ &rsp_header,
+ sizeof(rsp_header));
if (len != sizeof(rsp_header)) {
- MCDRV_DBG_ERROR("CMD_UNMAP_BULK_BUF readRsp failed, "
- "ret=%d", len);
+ MCDRV_DBG_ERROR(mc_kapi,
+ "CMD_UNMAP_BULK_BUF readRsp failed %d",
+ len);
mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
break;
}
if (rsp_header.response_id != MC_DRV_RSP_OK) {
- MCDRV_DBG_ERROR("CMD_UNMAP_BULK_BUF failed, respId=%d",
- rsp_header.response_id);
- /* REV We ignore Daemon Error code because client
- cannot handle it anyhow. */
+ MCDRV_DBG_ERROR(mc_kapi,
+ "CMD_UNMAP_BULK_BUF failed, respId=%d",
+ rsp_header.response_id);
+
mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
break;
}
struct mc_drv_rsp_unmap_bulk_mem_payload_t
rsp_unmap_bulk_mem_payload;
- connection_read_datablock(
- dev_con,
- &rsp_unmap_bulk_mem_payload,
- sizeof(rsp_unmap_bulk_mem_payload));
+ connection_read_datablock(dev_con,
+ &rsp_unmap_bulk_mem_payload,
+ sizeof(rsp_unmap_bulk_mem_payload));
- /* REV axh: what about check the payload? */
-
- /* Unregister mapped bulk buffer from Kernel Module and
- * remove mapped bulk buffer from session maintenance */
+ /*
+ * Unregister mapped bulk buffer from Kernel Module and
+ * remove mapped bulk buffer from session maintenance
+ */
if (!session_remove_bulk_buf(session, buf)) {
/* Removing of bulk buffer not possible */
- MCDRV_DBG_ERROR("Unregistering of bulk memory from "
- "Kernel Module failed");
+ MCDRV_DBG_ERROR(mc_kapi,
+ "Unregistering of bulk memory failed");
mc_result = MC_DRV_ERR_BULK_UNMAPPING;
break;
}
@@ -1021,20 +978,16 @@
} while (false);
- /* Exit critical section */
-
return mc_result;
}
EXPORT_SYMBOL(mc_unmap);
-/*----------------------------------------------------------------------------*/
-enum mc_result mc_get_session_error_code(
- struct mc_session_handle *session,
- int32_t *last_error
-) {
+enum mc_result mc_get_session_error_code(struct mc_session_handle *session,
+ int32_t *last_error)
+{
enum mc_result mc_result = MC_DRV_OK;
- MCDRV_DBG_VERBOSE("===%s()===", __func__);
+ MCDRV_DBG_VERBOSE(mc_kapi, "===%s()===", __func__);
do {
if (session == NULL || last_error == NULL) {
@@ -1044,23 +997,24 @@
/* Get device */
struct mcore_device_t *device =
- resolve_device_id(session->device_id);
+ resolve_device_id(session->device_id);
if (device == NULL) {
- MCDRV_DBG_ERROR("Device not found");
+ MCDRV_DBG_ERROR(mc_kapi, "Device not found");
mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
break;
}
/* Get session */
+ uint32_t session_id = session->session_id;
struct session *nqsession =
- mcore_device_resolve_session_id(device, session->session_id);
+ mcore_device_resolve_session_id(device,
+ session_id);
if (nqsession == NULL) {
- MCDRV_DBG_ERROR("Session not found");
+ MCDRV_DBG_ERROR(mc_kapi, "Session not found");
mc_result = MC_DRV_ERR_UNKNOWN_SESSION;
break;
}
- /* get session error code from session */
*last_error = session_get_last_err(nqsession);
} while (false);
@@ -1069,24 +1023,17 @@
}
EXPORT_SYMBOL(mc_get_session_error_code);
-/*----------------------------------------------------------------------------*/
-enum mc_result mc_driver_ctrl(
- enum mc_driver_ctrl param,
- uint8_t *data,
- uint32_t len
-) {
- MCDRV_DBG_WARN("not implemented");
+enum mc_result mc_driver_ctrl(enum mc_driver_ctrl param, uint8_t *data,
+ uint32_t len)
+{
+ MCDRV_DBG_WARN(mc_kapi, "not implemented");
return MC_DRV_ERR_NOT_IMPLEMENTED;
}
EXPORT_SYMBOL(mc_driver_ctrl);
-/*----------------------------------------------------------------------------*/
-enum mc_result mc_manage(
- uint32_t device_id,
- uint8_t *data,
- uint32_t len
-) {
- MCDRV_DBG_WARN("not implemented");
+enum mc_result mc_manage(uint32_t device_id, uint8_t *data, uint32_t len)
+{
+ MCDRV_DBG_WARN(mc_kapi, "not implemented");
return MC_DRV_ERR_NOT_IMPLEMENTED;
}
EXPORT_SYMBOL(mc_manage);
diff --git a/drivers/gud/mobicore_kernelapi/common.h b/drivers/gud/mobicore_kernelapi/common.h
index 2a73474..a15b1d7 100644
--- a/drivers/gud/mobicore_kernelapi/common.h
+++ b/drivers/gud/mobicore_kernelapi/common.h
@@ -1,97 +1,73 @@
-/**
+/*
+ * Common data types for use by the MobiCore Kernel API Driver
*
- * Common data types
- *
- * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+ * <-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-#ifndef COMMON_H
-#define COMMON_H
+#ifndef _MC_KAPI_COMMON_H
+#define _MC_KAPI_COMMON_H
#include "connection.h"
#include "mcinq.h"
-void mcapi_insert_connection(
- struct connection *connection
-);
+void mcapi_insert_connection(struct connection *connection);
+void mcapi_remove_connection(uint32_t seq);
+unsigned int mcapi_unique_id(void);
-void mcapi_remove_connection(
- uint32_t seq
-);
+#define MC_DAEMON_PID 0xFFFFFFFF
+#define MC_DRV_MOD_DEVNODE_FULLPATH "/dev/mobicore"
-unsigned int mcapi_unique_id(
- void
-);
+/* dummy function helper macro */
+#define DUMMY_FUNCTION() do {} while (0)
+/* Found in main.c */
+extern struct device *mc_kapi;
-#define MC_DAEMON_PID 0xFFFFFFFF
-#define MC_DRV_MOD_DEVNODE_FULLPATH "/dev/mobicore"
-
-/* dummy function helper macro. */
-#define DUMMY_FUNCTION() do {} while (0)
-
-#define MCDRV_ERROR(txt, ...) \
- printk(KERN_ERR "mcKernelApi %s() ### ERROR: " txt, \
- __func__, \
- ##__VA_ARGS__)
+#define MCDRV_ERROR(dev, txt, ...) \
+ dev_err(dev, "%s() ### ERROR: " txt, __func__, ##__VA_ARGS__)
#if defined(DEBUG)
/* #define DEBUG_VERBOSE */
#if defined(DEBUG_VERBOSE)
-#define MCDRV_DBG_VERBOSE MCDRV_DBG
+#define MCDRV_DBG_VERBOSE MCDRV_DBG
#else
-#define MCDRV_DBG_VERBOSE(...) DUMMY_FUNCTION()
+#define MCDRV_DBG_VERBOSE(...) DUMMY_FUNCTION()
#endif
-#define MCDRV_DBG(txt, ...) \
- printk(KERN_INFO "mcKernelApi %s(): " txt, \
- __func__, \
- ##__VA_ARGS__)
+#define MCDRV_DBG(dev, txt, ...) \
+ dev_info(dev, "%s(): " txt, __func__, ##__VA_ARGS__)
-#define MCDRV_DBG_WARN(txt, ...) \
- printk(KERN_WARNING "mcKernelApi %s() WARNING: " txt, \
- __func__, \
- ##__VA_ARGS__)
+#define MCDRV_DBG_WARN(dev, txt, ...) \
+ dev_warn(dev, "%s() WARNING: " txt, __func__, ##__VA_ARGS__)
-#define MCDRV_DBG_ERROR(txt, ...) \
- printk(KERN_ERR "mcKernelApi %s() ### ERROR: " txt, \
- __func__, \
- ##__VA_ARGS__)
-
+#define MCDRV_DBG_ERROR(dev, txt, ...) \
+ dev_err(dev, "%s() ### ERROR: " txt, __func__, ##__VA_ARGS__)
#define MCDRV_ASSERT(cond) \
do { \
if (unlikely(!(cond))) { \
- panic("mcKernelApi Assertion failed: %s:%d\n", \
- __FILE__, __LINE__); \
+ panic("mc_kernelapi Assertion failed: %s:%d\n", \
+ __FILE__, __LINE__); \
} \
} while (0)
#elif defined(NDEBUG)
-#define MCDRV_DBG_VERBOSE(...) DUMMY_FUNCTION()
-#define MCDRV_DBG(...) DUMMY_FUNCTION()
-#define MCDRV_DBG_WARN(...) DUMMY_FUNCTION()
-#define MCDRV_DBG_ERROR(...) DUMMY_FUNCTION()
+#define MCDRV_DBG_VERBOSE(...) DUMMY_FUNCTION()
+#define MCDRV_DBG(...) DUMMY_FUNCTION()
+#define MCDRV_DBG_WARN(...) DUMMY_FUNCTION()
+#define MCDRV_DBG_ERROR(...) DUMMY_FUNCTION()
-#define MCDRV_ASSERT(...) DUMMY_FUNCTION()
+#define MCDRV_ASSERT(...) DUMMY_FUNCTION()
#else
#error "Define DEBUG or NDEBUG"
#endif /* [not] defined(DEBUG_MCMODULE) */
+#define assert(expr) MCDRV_ASSERT(expr)
-#define LOG_I MCDRV_DBG_VERBOSE
-#define LOG_W MCDRV_DBG_WARN
-#define LOG_E MCDRV_DBG_ERROR
-
-
-#define assert(expr) MCDRV_ASSERT(expr)
-
-#endif /* COMMON_H */
-
-/** @} */
+#endif /* _MC_KAPI_COMMON_H */
diff --git a/drivers/gud/mobicore_kernelapi/connection.c b/drivers/gud/mobicore_kernelapi/connection.c
index 9048ae8..03288a0 100644
--- a/drivers/gud/mobicore_kernelapi/connection.c
+++ b/drivers/gud/mobicore_kernelapi/connection.c
@@ -1,10 +1,7 @@
-/** @addtogroup MCD_MCDIMPL_DAEMON_SRV
- * @{
- * @file
- *
+/*
* Connection data.
*
- * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+ * <-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -26,37 +23,29 @@
/* Define the initial state of the Data Available Semaphore */
#define SEM_NO_DATA_AVAILABLE 0
-/*----------------------------------------------------------------------------*/
-struct connection *connection_new(
- void
-) {
- struct connection *conn = kzalloc(sizeof(struct connection),
- GFP_KERNEL);
+struct connection *connection_new(void)
+{
+ struct connection *conn;
+
+ conn = kzalloc(sizeof(*conn), GFP_KERNEL);
conn->sequence_magic = mcapi_unique_id();
mutex_init(&conn->data_lock);
- /* No data available */
sema_init(&conn->data_available_sem, SEM_NO_DATA_AVAILABLE);
mcapi_insert_connection(conn);
return conn;
}
-/*----------------------------------------------------------------------------*/
-struct connection *connection_create(
- int socket_descriptor,
- pid_t dest
-) {
+struct connection *connection_create(int socket_descriptor, pid_t dest)
+{
struct connection *conn = connection_new();
conn->peer_pid = dest;
return conn;
}
-
-/*----------------------------------------------------------------------------*/
-void connection_cleanup(
- struct connection *conn
-) {
+void connection_cleanup(struct connection *conn)
+{
if (!conn)
return;
@@ -66,26 +55,20 @@
kfree(conn);
}
-
-/*----------------------------------------------------------------------------*/
-bool connection_connect(
- struct connection *conn,
- pid_t dest
-) {
+bool connection_connect(struct connection *conn, pid_t dest)
+{
/* Nothing to connect */
conn->peer_pid = dest;
return true;
}
-/*----------------------------------------------------------------------------*/
-size_t connection_readDataMsg(
- struct connection *conn,
- void *buffer,
- uint32_t len
-) {
+size_t connection_read_data_msg(struct connection *conn, void *buffer,
+ uint32_t len)
+{
size_t ret = -1;
- MCDRV_DBG_VERBOSE("reading connection data %u, connection data left %u",
- len, conn->data_len);
+ MCDRV_DBG_VERBOSE(mc_kapi,
+ "reading connection data %u, connection data left %u",
+ len, conn->data_len);
/* trying to read more than the left data */
if (len > conn->data_len) {
ret = conn->data_len;
@@ -98,80 +81,75 @@
conn->data_start += len;
}
- if (conn->data_len == 0) {
+ if (conn->data_len == 0) {
conn->data_start = NULL;
kfree_skb(conn->skb);
conn->skb = NULL;
}
- MCDRV_DBG_VERBOSE("read %u", ret);
+ MCDRV_DBG_VERBOSE(mc_kapi, "read %u", ret);
return ret;
}
-/*----------------------------------------------------------------------------*/
-size_t connection_read_datablock(
- struct connection *conn,
- void *buffer,
- uint32_t len
-) {
+size_t connection_read_datablock(struct connection *conn, void *buffer,
+ uint32_t len)
+{
return connection_read_data(conn, buffer, len, -1);
}
-
-/*----------------------------------------------------------------------------*/
-size_t connection_read_data(
- struct connection *conn,
- void *buffer,
- uint32_t len,
- int32_t timeout
-) {
+size_t connection_read_data(struct connection *conn, void *buffer, uint32_t len,
+ int32_t timeout)
+{
size_t ret = 0;
MCDRV_ASSERT(buffer != NULL);
MCDRV_ASSERT(conn->socket_descriptor != NULL);
- MCDRV_DBG_VERBOSE("read data len = %u for PID = %u",
- len, conn->sequence_magic);
+ MCDRV_DBG_VERBOSE(mc_kapi, "read data len = %u for PID = %u",
+ len, conn->sequence_magic);
do {
- /* Wait until data is available or timeout
- msecs_to_jiffies(-1) -> wait forever for the sem */
+ /*
+ * Wait until data is available or timeout
+ * msecs_to_jiffies(-1) -> wait forever for the sem
+ */
if (down_timeout(&(conn->data_available_sem),
- msecs_to_jiffies(timeout))) {
- MCDRV_DBG_VERBOSE("Timeout reading the data sem");
+ msecs_to_jiffies(timeout))) {
+ MCDRV_DBG_VERBOSE(mc_kapi,
+ "Timeout reading the data sem");
ret = -2;
break;
}
if (mutex_lock_interruptible(&(conn->data_lock))) {
- MCDRV_DBG_ERROR("interrupted reading the data sem");
+ MCDRV_DBG_ERROR(mc_kapi,
+ "interrupted reading the data sem");
ret = -1;
break;
}
+
/* Have data, use it */
if (conn->data_len > 0)
- ret = connection_readDataMsg(conn, buffer, len);
+ ret = connection_read_data_msg(conn, buffer, len);
- mutex_unlock(&(conn->data_lock));
+ mutex_unlock(&(conn->data_lock));
/* There is still some data left */
if (conn->data_len > 0)
up(&conn->data_available_sem);
+
} while (0);
return ret;
}
-/*----------------------------------------------------------------------------*/
-size_t connection_write_data(
- struct connection *conn,
- void *buffer,
- uint32_t len
-) {
+size_t connection_write_data(struct connection *conn, void *buffer,
+ uint32_t len)
+{
struct sk_buff *skb = NULL;
struct nlmsghdr *nlh;
int ret = 0;
- MCDRV_DBG_VERBOSE("buffer length %u from pid %u\n",
- len, conn->sequence_magic);
+ MCDRV_DBG_VERBOSE(mc_kapi, "buffer length %u from pid %u\n",
+ len, conn->sequence_magic);
do {
skb = nlmsg_new(NLMSG_SPACE(len), GFP_KERNEL);
if (!skb) {
@@ -180,7 +158,7 @@
}
nlh = nlmsg_put(skb, 0, conn->sequence_magic, 2,
- NLMSG_LENGTH(len), NLM_F_REQUEST);
+ NLMSG_LENGTH(len), NLM_F_REQUEST);
if (!nlh) {
ret = -1;
break;
@@ -188,7 +166,7 @@
memcpy(NLMSG_DATA(nlh), buffer, len);
netlink_unicast(conn->socket_descriptor, skb,
- conn->peer_pid, MSG_DONTWAIT);
+ conn->peer_pid, MSG_DONTWAIT);
ret = len;
} while (0);
@@ -198,22 +176,20 @@
return ret;
}
-int connection_process(
- struct connection *conn,
- struct sk_buff *skb
-)
+int connection_process(struct connection *conn, struct sk_buff *skb)
{
int ret = 0;
do {
if (mutex_lock_interruptible(&(conn->data_lock))) {
- MCDRV_DBG_ERROR("Interrupted getting data semaphore!");
+ MCDRV_DBG_ERROR(mc_kapi,
+ "Interrupted getting data semaphore!");
ret = -1;
break;
}
kfree_skb(conn->skb);
- /* Get a reference to the incomming skb */
+ /* Get a reference to the incoming skb */
conn->skb = skb_get(skb);
if (conn->skb) {
conn->data_msg = nlmsg_hdr(conn->skb);
@@ -226,4 +202,3 @@
} while (0);
return ret;
}
-/** @} */
diff --git a/drivers/gud/mobicore_kernelapi/connection.h b/drivers/gud/mobicore_kernelapi/connection.h
index 0b468e6..6c3ff00 100644
--- a/drivers/gud/mobicore_kernelapi/connection.h
+++ b/drivers/gud/mobicore_kernelapi/connection.h
@@ -1,122 +1,58 @@
-/** @addtogroup MCD_MCDIMPL_DAEMON_SRV
- * @{
- * @file
- *
+/*
* Connection data.
*
- * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+ * <-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-#ifndef CONNECTION_H_
-#define CONNECTION_H_
+#ifndef _MC_KAPI_CONNECTION_H_
+#define _MC_KAPI_CONNECTION_H_
#include <linux/semaphore.h>
+#include <linux/mutex.h>
#include <stddef.h>
#include <stdbool.h>
-#define MAX_PAYLOAD_SIZE 128
-
struct connection {
- struct sock *socket_descriptor; /**< Netlink socket */
- uint32_t sequence_magic; /**< Random? magic to match requests/answers */
+ /* Netlink socket */
+ struct sock *socket_descriptor;
+ /* Random? magic to match requests/answers */
+ uint32_t sequence_magic;
- struct nlmsghdr *data_msg;
- uint32_t data_len; /**< How much connection data is left */
- void *data_start; /**< Start pointer of remaining data */
- struct sk_buff *skb;
+ struct nlmsghdr *data_msg;
+ /* How much connection data is left */
+ uint32_t data_len;
+ /* Start pointer of remaining data */
+ void *data_start;
+ struct sk_buff *skb;
- struct mutex data_lock; /**< Data protection lock */
- struct semaphore data_available_sem; /**< Data protection semaphore */
+ /* Data protection lock */
+ struct mutex data_lock;
+ /* Data protection semaphore */
+ struct semaphore data_available_sem;
- pid_t self_pid; /**< PID address used for local connection */
- pid_t peer_pid; /**< Remote PID for connection */
+ /* PID address used for local connection */
+ pid_t self_pid;
+ /* Remote PID for connection */
+ pid_t peer_pid;
- struct list_head list; /**< The list param for using the kernel lists*/
+ /* The list param for using the kernel lists */
+ struct list_head list;
};
-struct connection *connection_new(
- void
-);
+struct connection *connection_new(void);
+struct connection *connection_create(int socket_descriptor, pid_t dest);
+void connection_cleanup(struct connection *conn);
+bool connection_connect(struct connection *conn, pid_t dest);
+size_t connection_read_datablock(struct connection *conn, void *buffer,
+ uint32_t len);
+size_t connection_read_data(struct connection *conn, void *buffer,
+ uint32_t len, int32_t timeout);
+size_t connection_write_data(struct connection *conn, void *buffer,
+ uint32_t len);
+int connection_process(struct connection *conn, struct sk_buff *skb);
-struct connection *connection_create(
- int socket_descriptor,
- pid_t dest
-);
-
-void connection_cleanup(
- struct connection *conn
-);
-
-/**
- * Connect to destination.
- *
- * @param Destination pointer.
- * @return true on success.
- */
-bool connection_connect(
- struct connection *conn,
- pid_t dest
-);
-
-
-/**
- * Read bytes from the connection.
- *
- * @param buffer Pointer to destination buffer.
- * @param len Number of bytes to read.
- * @return Number of bytes read.
- */
-size_t connection_read_datablock(
- struct connection *conn,
- void *buffer,
- uint32_t len
-);
-/**
- * Read bytes from the connection.
- *
- * @param buffer Pointer to destination buffer.
- * @param len Number of bytes to read.
- * @param timeout Timeout in milliseconds
- * @return Number of bytes read.
- * @return -1 if select() failed (returned -1)
- * @return -2 if no data available, i.e. timeout
- */
-size_t connection_read_data(
- struct connection *conn,
- void *buffer,
- uint32_t len,
- int32_t timeout
-);
-
-/**
- * Write bytes to the connection.
- *
- * @param buffer Pointer to source buffer.
- * @param len Number of bytes to read.
- * @return Number of bytes written.
- */
-size_t connection_write_data(
- struct connection *conn,
- void *buffer,
- uint32_t len
-);
-
-/**
- * Write bytes to the connection.
- *
- * @param buffer Pointer to source buffer.
- * @param len Number of bytes to read.
- * @return Number of bytes written.
- */
-int connection_process(
- struct connection *conn,
- struct sk_buff *skb
-);
-
-#endif /* CONNECTION_H_ */
-
-/** @} */
+#endif /* _MC_KAPI_CONNECTION_H_ */
diff --git a/drivers/gud/mobicore_kernelapi/device.c b/drivers/gud/mobicore_kernelapi/device.c
index dbeee6a..a176322 100644
--- a/drivers/gud/mobicore_kernelapi/device.c
+++ b/drivers/gud/mobicore_kernelapi/device.c
@@ -1,12 +1,9 @@
-/** @addtogroup MCD_IMPL_LIB
- * @{
- * @file
+/*
+ * MobiCore client library device management.
*
- * Client library device management.
+ * Device and Trustlet Session management Functions.
*
- * Device and Trustlet Session management Funtions.
- *
- * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+ * <-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -14,21 +11,19 @@
*/
#include <linux/list.h>
#include <linux/slab.h>
+#include <linux/device.h>
#include "mc_kernel_api.h"
#include "public/mobicore_driver_api.h"
#include "device.h"
#include "common.h"
-/*----------------------------------------------------------------------------*/
-struct wsm *wsm_create(
- void *virt_addr,
- uint32_t len,
- uint32_t handle,
- void *phys_addr /*= NULL this may be unknown, so is can be omitted.*/
- )
+struct wsm *wsm_create(void *virt_addr, uint32_t len, uint32_t handle,
+ void *phys_addr)
{
- struct wsm *wsm = kzalloc(sizeof(struct wsm), GFP_KERNEL);
+ struct wsm *wsm;
+
+ wsm = kzalloc(sizeof(*wsm), GFP_KERNEL);
wsm->virt_addr = virt_addr;
wsm->len = len;
wsm->handle = handle;
@@ -36,14 +31,12 @@
return wsm;
}
+struct mcore_device_t *mcore_device_create(uint32_t device_id,
+ struct connection *connection)
+{
+ struct mcore_device_t *dev;
-/*----------------------------------------------------------------------------*/
-struct mcore_device_t *mcore_device_create(
- uint32_t device_id,
- struct connection *connection
-) {
- struct mcore_device_t *dev =
- kzalloc(sizeof(struct mcore_device_t), GFP_KERNEL);
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
dev->device_id = device_id;
dev->connection = connection;
@@ -53,17 +46,16 @@
return dev;
}
-
-/*----------------------------------------------------------------------------*/
-void mcore_device_cleanup(
- struct mcore_device_t *dev
-) {
+void mcore_device_cleanup(struct mcore_device_t *dev)
+{
struct session *tmp;
struct wsm *wsm;
struct list_head *pos, *q;
- /* Delete all session objects. Usually this should not be needed
- * as closeDevice()requires that all sessions have been closed before.*/
+ /*
+ * Delete all session objects. Usually this should not be needed
+ * as close_device() requires that all sessions have been closed before.
+ */
list_for_each_safe(pos, q, &dev->session_vector) {
tmp = list_entry(pos, struct session, list);
list_del(pos);
@@ -73,7 +65,6 @@
/* Free all allocated WSM descriptors */
list_for_each_safe(pos, q, &dev->wsm_l2_vector) {
wsm = list_entry(pos, struct wsm, list);
- /* mcKMod_free(dev->instance, wsm->handle); */
list_del(pos);
kfree(wsm);
}
@@ -83,56 +74,41 @@
kfree(dev);
}
-
-/*----------------------------------------------------------------------------*/
-bool mcore_device_open(
- struct mcore_device_t *dev,
- const char *deviceName
-) {
+bool mcore_device_open(struct mcore_device_t *dev, const char *deviceName)
+{
dev->instance = mobicore_open();
return (dev->instance != NULL);
}
-
-/*----------------------------------------------------------------------------*/
-void mcore_device_close(
- struct mcore_device_t *dev
-) {
+void mcore_device_close(struct mcore_device_t *dev)
+{
mobicore_release(dev->instance);
}
-
-/*----------------------------------------------------------------------------*/
-bool mcore_device_has_sessions(
- struct mcore_device_t *dev
-) {
+bool mcore_device_has_sessions(struct mcore_device_t *dev)
+{
return !list_empty(&dev->session_vector);
}
-
-/*----------------------------------------------------------------------------*/
-bool mcore_device_create_new_session(
- struct mcore_device_t *dev,
- uint32_t session_id,
- struct connection *connection
-) {
+bool mcore_device_create_new_session(struct mcore_device_t *dev,
+ uint32_t session_id,
+ struct connection *connection)
+{
/* Check if session_id already exists */
if (mcore_device_resolve_session_id(dev, session_id)) {
- MCDRV_DBG_ERROR(" session %u already exists", session_id);
+ MCDRV_DBG_ERROR(mc_kapi,
+ " session %u already exists", session_id);
return false;
}
- struct session *session = session_create(session_id, dev->instance,
- connection);
+ struct session *session =
+ session_create(session_id, dev->instance, connection);
list_add_tail(&(session->list), &(dev->session_vector));
return true;
}
-
-/*----------------------------------------------------------------------------*/
-bool mcore_device_remove_session(
- struct mcore_device_t *dev,
- uint32_t session_id
-) {
+bool mcore_device_remove_session(struct mcore_device_t *dev,
+ uint32_t session_id)
+{
bool ret = false;
struct session *tmp;
struct list_head *pos, *q;
@@ -149,17 +125,13 @@
return ret;
}
-
-/*----------------------------------------------------------------------------*/
-struct session *mcore_device_resolve_session_id(
- struct mcore_device_t *dev,
- uint32_t session_id
-) {
- struct session *ret = NULL;
+struct session *mcore_device_resolve_session_id(struct mcore_device_t *dev,
+ uint32_t session_id)
+{
+ struct session *ret = NULL;
struct session *tmp;
struct list_head *pos;
-
/* Get session for session_id */
list_for_each(pos, &dev->session_vector) {
tmp = list_entry(pos, struct session, list);
@@ -171,26 +143,20 @@
return ret;
}
-
-/*----------------------------------------------------------------------------*/
-struct wsm *mcore_device_allocate_contiguous_wsm(
- struct mcore_device_t *dev,
- uint32_t len
-) {
+struct wsm *mcore_device_allocate_contiguous_wsm(struct mcore_device_t *dev,
+ uint32_t len)
+{
struct wsm *wsm = NULL;
do {
if (len == 0)
break;
/* Allocate shared memory */
- void *virt_addr;
- uint32_t handle;
- void *phys_addr;
- int ret = mobicore_allocate_wsm(dev->instance,
- len,
- &handle,
- &virt_addr,
- &phys_addr);
+ void *virt_addr;
+ uint32_t handle;
+ void *phys_addr;
+ int ret = mobicore_allocate_wsm(dev->instance, len, &handle,
+ &virt_addr, &phys_addr);
if (ret != 0)
break;
@@ -201,16 +167,12 @@
} while (0);
- /* Return pointer to the allocated memory */
return wsm;
}
-
-/*----------------------------------------------------------------------------*/
-bool mcore_device_free_contiguous_wsm(
- struct mcore_device_t *dev,
- struct wsm *wsm
-) {
+bool mcore_device_free_contiguous_wsm(struct mcore_device_t *dev,
+ struct wsm *wsm)
+{
bool ret = false;
struct wsm *tmp;
struct list_head *pos;
@@ -224,11 +186,12 @@
}
if (ret) {
- MCDRV_DBG_VERBOSE("freeWsm virt_addr=0x%p, handle=%d",
- wsm->virt_addr, wsm->handle);
+ MCDRV_DBG_VERBOSE(mc_kapi,
+ "freeWsm virt_addr=0x%p, handle=%d",
+ wsm->virt_addr, wsm->handle);
/* ignore return code */
- mobicore_free(dev->instance, wsm->handle);
+ mobicore_free_wsm(dev->instance, wsm->handle);
list_del(pos);
kfree(wsm);
@@ -236,12 +199,9 @@
return ret;
}
-
-/*----------------------------------------------------------------------------*/
-struct wsm *mcore_device_find_contiguous_wsm(
- struct mcore_device_t *dev,
- void *virt_addr
-) {
+struct wsm *mcore_device_find_contiguous_wsm(struct mcore_device_t *dev,
+ void *virt_addr)
+{
struct wsm *wsm;
struct list_head *pos;
@@ -253,5 +213,3 @@
return NULL;
}
-
-/** @} */
diff --git a/drivers/gud/mobicore_kernelapi/device.h b/drivers/gud/mobicore_kernelapi/device.h
index f40d993..16626bd 100644
--- a/drivers/gud/mobicore_kernelapi/device.h
+++ b/drivers/gud/mobicore_kernelapi/device.h
@@ -1,19 +1,16 @@
-/** @addtogroup MCD_IMPL_LIB
- * @{
- * @file
- *
- * Client library device management.
+/*
+ * MobiCore client library device management.
*
* Device and Trustlet Session management Functions.
*
- * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+ * <-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-#ifndef DEVICE_H_
-#define DEVICE_H_
+#ifndef _MC_KAPI_DEVICE_H_
+#define _MC_KAPI_DEVICE_H_
#include <linux/list.h>
@@ -21,119 +18,39 @@
#include "session.h"
#include "wsm.h"
-
struct mcore_device_t {
- struct list_head session_vector; /**< MobiCore Trustlet session
- associated with the device */
- struct list_head wsm_l2_vector; /**< WSM L2 Table */
+ /* MobiCore Trustlet session associated with the device */
+ struct list_head session_vector;
+ struct list_head wsm_l2_vector; /* WSM L2 Table */
- uint32_t device_id; /**< Device identifier */
- struct connection *connection; /**< The device connection */
- struct mc_instance *instance; /**< MobiCore Driver instance */
+ uint32_t device_id; /* Device identifier */
+ struct connection *connection; /* The device connection */
+ struct mc_instance *instance; /* MobiCore Driver instance */
- struct list_head list; /**< The list param for using the kernel lists*/
+ /* The list param for using the kernel lists */
+ struct list_head list;
};
struct mcore_device_t *mcore_device_create(
- uint32_t device_id,
- struct connection *connection
-);
+ uint32_t device_id, struct connection *connection);
+void mcore_device_cleanup(struct mcore_device_t *dev);
-void mcore_device_cleanup(
- struct mcore_device_t *dev
-);
-/**
- * Open the device.
- * @param deviceName Name of the kernel modules device file.
- * @return true if the device has been opened successfully
- */
-bool mcore_device_open(
- struct mcore_device_t *dev,
- const char *deviceName
-);
-
-/**
- * Closes the device.
- */
-void mcore_device_close(
- struct mcore_device_t *dev
-);
-
-/**
- * Check if the device has open sessions.
- * @return true if the device has one or more open sessions.
- */
-bool mcore_device_has_sessions(
- struct mcore_device_t *dev
-);
-
-/**
- * Add a session to the device.
- * @param session_id session ID
- * @param connection session connection
- */
+bool mcore_device_open(struct mcore_device_t *dev, const char *deviceName);
+void mcore_device_close(struct mcore_device_t *dev);
+bool mcore_device_has_sessions(struct mcore_device_t *dev);
bool mcore_device_create_new_session(
- struct mcore_device_t *dev,
- uint32_t session_id,
- struct connection *connection
-);
-
-/**
- * Remove the specified session from the device.
- * The session object will be destroyed and all resources associated with it
- * will be freed.
- *
- * @param session_id Session of the session to remove.
- * @return true if a session has been found and removed.
- */
+ struct mcore_device_t *dev, uint32_t session_id,
+ struct connection *connection);
bool mcore_device_remove_session(
- struct mcore_device_t *dev,
- uint32_t session_id
-);
-
-/**
- * Get as session object for a given session ID.
- * @param session_id Identified of a previously opened session.
- * @return Session object if available or NULL if no session has been found.
- */
+ struct mcore_device_t *dev, uint32_t session_id);
struct session *mcore_device_resolve_session_id(
- struct mcore_device_t *dev,
- uint32_t session_id
-);
-
-/**
- * Allocate a block of contiguous WSM.
- * @param len The virtual address to be registered.
- * @return The virtual address of the allocated memory or NULL if no memory
- * is available.
- */
+ struct mcore_device_t *dev, uint32_t session_id);
struct wsm *mcore_device_allocate_contiguous_wsm(
- struct mcore_device_t *dev,
- uint32_t len
-);
-
-/**
- * Unregister a vaddr from a device.
- * @param vaddr The virtual address to be registered.
- * @param paddr The physical address to be registered.
- */
+ struct mcore_device_t *dev, uint32_t len);
bool mcore_device_free_contiguous_wsm(
- struct mcore_device_t *dev,
- struct wsm *wsm
-);
-
-/**
- * Get a WSM object for a given virtual address.
- * @param vaddr The virtual address which has been allocate with mc_malloc_wsm()
- * in advance.
- * @return the WSM object or NULL if no address has been found.
- */
+ struct mcore_device_t *dev, struct wsm *wsm);
struct wsm *mcore_device_find_contiguous_wsm(
- struct mcore_device_t *dev,
- void *virt_addr
-);
+ struct mcore_device_t *dev, void *virt_addr);
-#endif /* DEVICE_H_ */
-
-/** @} */
+#endif /* _MC_KAPI_DEVICE_H_ */
diff --git a/drivers/gud/mobicore_kernelapi/include/mcinq.h b/drivers/gud/mobicore_kernelapi/include/mcinq.h
index 3cb82be..b874925 100644
--- a/drivers/gud/mobicore_kernelapi/include/mcinq.h
+++ b/drivers/gud/mobicore_kernelapi/include/mcinq.h
@@ -1,8 +1,8 @@
-/** @addtogroup NQ
- * @{
+/*
* Notifications inform the MobiCore runtime environment that information is
* pending in a WSM buffer.
- * The Trustlet Connector (TLC) and the corresponding trustlet also utilize
+ *
+ * The Trustlet Connector (TLC) and the corresponding Trustlet also utilize
* this buffer to notify each other about new data within the
* Trustlet Connector Interface (TCI).
*
@@ -13,13 +13,12 @@
*
* Notifications hold the session ID, which is used to reference the
* communication partner in the other world.
- * So if, e.g., the TLC in the normal world wants to notify his trustlet
+ * So if, e.g., the TLC in the normal world wants to notify his Trustlet
* about new data in the TLC buffer
*
- * @file
* Notification queue declarations.
*
- * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -45,81 +44,74 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef NQ_H_
-#define NQ_H_
+#ifndef _MCINQ_H_
+#define _MCINQ_H_
-/** \name NQ Size Defines
- * Minimum and maximum count of elements in the notification queue.
- * @{ */
-#define MIN_NQ_ELEM 1 /**< Minimum notification queue elements. */
-#define MAX_NQ_ELEM 64 /**< Maximum notification queue elements. */
-/** @} */
+/* Minimum and maximum count of elements in the notification queue */
+#define MIN_NQ_ELEM 1 /* Minimum notification queue elements. */
+#define MAX_NQ_ELEM 64 /* Maximum notification queue elements. */
-/** \name NQ Length Defines
- * Minimum and maximum notification queue length.
- * @{ */
-/**< Minimum notification length (in bytes). */
-#define MIN_NQ_LEN (MIN_NQ_ELEM * sizeof(notification))
-/**< Maximum notification length (in bytes). */
-#define MAX_NQ_LEN (MAX_NQ_ELEM * sizeof(notification))
-/** @} */
+/* Minimum notification length (in bytes). */
+#define MIN_NQ_LEN (MIN_NQ_ELEM * sizeof(notification))
-/** \name Session ID Defines
- * Standard Session IDs.
- * @{ */
-/**< MCP session ID is used when directly communicating with the MobiCore
- * (e.g. for starting and stopping of trustlets). */
-#define SID_MCP 0
-/**< Invalid session id is returned in case of an error. */
-#define SID_INVALID 0xffffffff
-/** @} */
+/* Maximum notification length (in bytes). */
+#define MAX_NQ_LEN (MAX_NQ_ELEM * sizeof(notification))
-/** Notification data structure. */
+/*
+ * MCP session ID is used when directly communicating with the MobiCore
+ * (e.g. for starting and stopping of Trustlets).
+ */
+#define SID_MCP 0
+/* Invalid session id is returned in case of an error. */
+#define SID_INVALID 0xffffffff
+
+/* Notification data structure. */
struct notification {
- uint32_t session_id; /**< Session ID. */
- int32_t payload; /**< Additional notification information. */
+ uint32_t session_id; /* Session ID. */
+ int32_t payload; /* Additional notification info */
};
-/** Notification payload codes.
+/*
+ * Notification payload codes.
* 0 indicated a plain simple notification,
* a positive value is a termination reason from the task,
* a negative value is a termination reason from MobiCore.
* Possible negative values are given below.
*/
enum notification_payload {
- /**< task terminated, but exit code is invalid */
- ERR_INVALID_EXIT_CODE = -1,
- /**< task terminated due to session end, no exit code available */
- ERR_SESSION_CLOSE = -2,
- /**< task terminated due to invalid operation */
- ERR_INVALID_OPERATION = -3,
- /**< session ID is unknown */
- ERR_INVALID_SID = -4,
- /**< session is not active */
- ERR_SID_NOT_ACTIVE = -5
+ /* task terminated, but exit code is invalid */
+ ERR_INVALID_EXIT_CODE = -1,
+ /* task terminated due to session end, no exit code available */
+ ERR_SESSION_CLOSE = -2,
+ /* task terminated due to invalid operation */
+ ERR_INVALID_OPERATION = -3,
+ /* session ID is unknown */
+ ERR_INVALID_SID = -4,
+ /* session is not active */
+ ERR_SID_NOT_ACTIVE = -5
};
-/** Declaration of the notification queue header.
- * layout as specified in the data structure specification.
+/*
+ * Declaration of the notification queue header.
+ * Layout as specified in the data structure specification.
*/
struct notification_queue_header {
- uint32_t write_cnt; /**< Write counter. */
- uint32_t read_cnt; /**< Read counter. */
- uint32_t queue_size; /**< Queue size. */
+ uint32_t write_cnt; /* Write counter. */
+ uint32_t read_cnt; /* Read counter. */
+ uint32_t queue_size; /* Queue size. */
};
-/** Queue struct which defines a queue object.
+/*
+ * Queue struct which defines a queue object.
* The queue struct is accessed by the queue<operation> type of
* function. elementCnt must be a power of two and the power needs
* to be smaller than power of uint32_t (obviously 32).
*/
struct notification_queue {
- /**< Queue header. */
+ /* Queue header. */
struct notification_queue_header hdr;
- /**< Notification elements. */
+ /* Notification elements. */
struct notification notification[MIN_NQ_ELEM];
} ;
-#endif /** NQ_H_ */
-
-/** @} */
+#endif /* _MCINQ_H_ */
diff --git a/drivers/gud/mobicore_kernelapi/include/mcuuid.h b/drivers/gud/mobicore_kernelapi/include/mcuuid.h
index b72acb8..6da9437 100644
--- a/drivers/gud/mobicore_kernelapi/include/mcuuid.h
+++ b/drivers/gud/mobicore_kernelapi/include/mcuuid.h
@@ -1,7 +1,5 @@
-/**
- * @addtogroup MC_UUID mcUuid - Universally Unique Identifier.
- *
- * <!-- Copyright Giesecke & Devrient GmbH 2011-2012 -->
+/*
+ * <-- Copyright Giesecke & Devrient GmbH 2011-2012 -->
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -27,21 +25,19 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * @ingroup MC_DATA_TYPES
- * @{
*/
-#ifndef MC_UUID_H_
-#define MC_UUID_H_
+#ifndef _MCUUID_H_
+#define _MCUUID_H_
#define UUID_TYPE
-/** Universally Unique Identifier (UUID) according to ISO/IEC 11578. */
+/* Universally Unique Identifier (UUID) according to ISO/IEC 11578. */
struct mc_uuid_t {
- uint8_t value[16]; /**< Value of the UUID. */
+ uint8_t value[16]; /* Value of the UUID. */
};
-/** UUID value used as free marker in service provider containers. */
+/* UUID value used as free marker in service provider containers. */
#define MC_UUID_FREE_DEFINE \
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }
@@ -50,7 +46,7 @@
MC_UUID_FREE_DEFINE
};
-/** Reserved UUID. */
+/* Reserved UUID. */
#define MC_UUID_RESERVED_DEFINE \
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
@@ -59,7 +55,7 @@
MC_UUID_RESERVED_DEFINE
};
-/** UUID for system applications. */
+/* UUID for system applications. */
#define MC_UUID_SYSTEM_DEFINE \
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE }
@@ -68,7 +64,4 @@
MC_UUID_SYSTEM_DEFINE
};
-#endif /* MC_UUID_H_ */
-
-/** @} */
-
+#endif /* _MCUUID_H_ */
diff --git a/drivers/gud/mobicore_kernelapi/main.c b/drivers/gud/mobicore_kernelapi/main.c
index 62997f7..50359b1 100644
--- a/drivers/gud/mobicore_kernelapi/main.c
+++ b/drivers/gud/mobicore_kernelapi/main.c
@@ -1,7 +1,7 @@
-/**
+/*
* MobiCore KernelApi module
*
- * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -14,6 +14,7 @@
#include <linux/sched.h>
#include <linux/netlink.h>
#include <linux/kthread.h>
+#include <linux/device.h>
#include <net/sock.h>
#include <linux/list.h>
@@ -29,23 +30,27 @@
atomic_t counter;
};
-struct mc_kernelapi_ctx *mod_ctx; /* = NULL; */
+struct mc_kernelapi_ctx *mod_ctx;
-/*----------------------------------------------------------------------------*/
+/* Define a MobiCore Kernel API device structure for use with dev_debug() etc */
+struct device_driver mc_kernel_api_name = {
+ .name = "mckernelapi"
+};
+
+struct device mc_kernel_api_subname = {
+ .init_name = "", /* Set to 'mcapi' at mcapi_init() time */
+ .driver = &mc_kernel_api_name
+};
+
+struct device *mc_kapi = &mc_kernel_api_subname;
+
/* get a unique ID */
-unsigned int mcapi_unique_id(
- void
-)
+unsigned int mcapi_unique_id(void)
{
- return (unsigned int)atomic_inc_return(
- &(mod_ctx->counter));
+ return (unsigned int)atomic_inc_return(&(mod_ctx->counter));
}
-
-/*----------------------------------------------------------------------------*/
-static struct connection *mcapi_find_connection(
- uint32_t seq
-)
+static struct connection *mcapi_find_connection(uint32_t seq)
{
struct connection *tmp;
struct list_head *pos;
@@ -60,24 +65,21 @@
return NULL;
}
-/*----------------------------------------------------------------------------*/
-void mcapi_insert_connection(
- struct connection *connection
-)
+void mcapi_insert_connection(struct connection *connection)
{
list_add_tail(&(connection->list), &(mod_ctx->peers));
connection->socket_descriptor = mod_ctx->sk;
}
-void mcapi_remove_connection(
- uint32_t seq
-)
+void mcapi_remove_connection(uint32_t seq)
{
struct connection *tmp;
struct list_head *pos, *q;
- /* Delete all session objects. Usually this should not be needed as
- closeDevice() requires that all sessions have been closed before.*/
+ /*
+ * Delete all session objects. Usually this should not be needed as
+ * closeDevice() requires that all sessions have been closed before.
+ */
list_for_each_safe(pos, q, &mod_ctx->peers) {
tmp = list_entry(pos, struct connection, list);
if (tmp->sequence_magic == seq) {
@@ -87,11 +89,7 @@
}
}
-/*----------------------------------------------------------------------------*/
-static int mcapi_process(
- struct sk_buff *skb,
- struct nlmsghdr *nlh
-)
+static int mcapi_process(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct connection *c;
int length;
@@ -102,13 +100,14 @@
pid = nlh->nlmsg_pid;
length = nlh->nlmsg_len;
seq = nlh->nlmsg_seq;
- MCDRV_DBG_VERBOSE("nlmsg len %d type %d pid 0x%X seq %d\n",
- length, nlh->nlmsg_type, pid, seq);
+ MCDRV_DBG_VERBOSE(mc_kapi, "nlmsg len %d type %d pid 0x%X seq %d\n",
+ length, nlh->nlmsg_type, pid, seq);
do {
c = mcapi_find_connection(seq);
if (!c) {
- MCDRV_ERROR("Invalid incomming connection - seq=%u!",
- seq);
+ MCDRV_ERROR(mc_kapi,
+ "Invalid incoming connection - seq=%u!",
+ seq);
ret = -1;
break;
}
@@ -121,10 +120,7 @@
return ret;
}
-/*----------------------------------------------------------------------------*/
-static void mcapi_callback(
- struct sk_buff *skb
-)
+static void mcapi_callback(struct sk_buff *skb)
{
struct nlmsghdr *nlh = nlmsg_hdr(skb);
int len = skb->len;
@@ -141,19 +137,20 @@
}
}
-/*----------------------------------------------------------------------------*/
static int __init mcapi_init(void)
{
- printk(KERN_INFO "Mobicore API module initialized!\n");
+ dev_set_name(mc_kapi, "mcapi");
+
+ dev_info(mc_kapi, "Mobicore API module initialized!\n");
mod_ctx = kzalloc(sizeof(struct mc_kernelapi_ctx), GFP_KERNEL);
/* start kernel thread */
mod_ctx->sk = netlink_kernel_create(&init_net, MC_DAEMON_NETLINK, 0,
- mcapi_callback, NULL, THIS_MODULE);
+ mcapi_callback, NULL, THIS_MODULE);
if (!mod_ctx->sk) {
- MCDRV_ERROR("register of recieve handler failed");
+ MCDRV_ERROR(mc_kapi, "register of receive handler failed");
return -EFAULT;
}
@@ -163,7 +160,7 @@
static void __exit mcapi_exit(void)
{
- printk(KERN_INFO "Unloading Mobicore API module.\n");
+ dev_info(mc_kapi, "Unloading Mobicore API module.\n");
if (mod_ctx->sk != NULL) {
netlink_kernel_release(mod_ctx->sk);
diff --git a/drivers/gud/mobicore_kernelapi/public/mobicore_driver_api.h b/drivers/gud/mobicore_kernelapi/public/mobicore_driver_api.h
index ccfb2e5..07a3ae3 100644
--- a/drivers/gud/mobicore_kernelapi/public/mobicore_driver_api.h
+++ b/drivers/gud/mobicore_kernelapi/public/mobicore_driver_api.h
@@ -1,21 +1,10 @@
-/**
- * @defgroup MCD_API MobiCore Driver API
- * @addtogroup MCD_API
- * @{
- *
- * @if DOXYGEN_MCDRV_API
- * @mainpage MobiCore Driver API.
- * @endif
- *
+/*
* MobiCore Driver API.
*
* The MobiCore (MC) Driver API provides access functions to the MobiCore
* runtime environment and the contained Trustlets.
*
- * @image html DoxyOverviewDrvApi500x.png
- * @image latex DoxyOverviewDrvApi500x.png "MobiCore Overview" width=12cm
- *
- * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+ * <-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -41,278 +30,272 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef MCDRIVER_H_
-#define MCDRIVER_H_
+#ifndef _MOBICORE_DRIVER_API_H_
+#define _MOBICORE_DRIVER_API_H_
#define __MC_CLIENT_LIB_API
#include "mcuuid.h"
-/**
+/*
* Return values of MobiCore driver functions.
*/
enum mc_result {
- /**< Function call succeeded. */
- MC_DRV_OK = 0,
- /**< No notification available. */
- MC_DRV_NO_NOTIFICATION = 1,
- /**< Error during notification on communication level. */
- MC_DRV_ERR_NOTIFICATION = 2,
- /**< Function not implemented. */
- MC_DRV_ERR_NOT_IMPLEMENTED = 3,
- /**< No more resources available. */
- MC_DRV_ERR_OUT_OF_RESOURCES = 4,
- /**< Driver initialization failed. */
- MC_DRV_ERR_INIT = 5,
- /**< Unknown error. */
- MC_DRV_ERR_UNKNOWN = 6,
- /**< The specified device is unknown. */
- MC_DRV_ERR_UNKNOWN_DEVICE = 7,
- /**< The specified session is unknown.*/
- MC_DRV_ERR_UNKNOWN_SESSION = 8,
- /**< The specified operation is not allowed. */
- MC_DRV_ERR_INVALID_OPERATION = 9,
- /**< The response header from the MC is invalid. */
- MC_DRV_ERR_INVALID_RESPONSE = 10,
- /**< Function call timed out. */
- MC_DRV_ERR_TIMEOUT = 11,
- /**< Can not allocate additional memory. */
- MC_DRV_ERR_NO_FREE_MEMORY = 12,
- /**< Free memory failed. */
- MC_DRV_ERR_FREE_MEMORY_FAILED = 13,
- /**< Still some open sessions pending. */
- MC_DRV_ERR_SESSION_PENDING = 14,
- /**< MC daemon not reachable */
- MC_DRV_ERR_DAEMON_UNREACHABLE = 15,
- /**< The device file of the kernel module could not be opened. */
- MC_DRV_ERR_INVALID_DEVICE_FILE = 16,
- /**< Invalid parameter. */
+ /* Function call succeeded. */
+ MC_DRV_OK = 0,
+ /* No notification available. */
+ MC_DRV_NO_NOTIFICATION = 1,
+ /* Error during notification on communication level. */
+ MC_DRV_ERR_NOTIFICATION = 2,
+ /* Function not implemented. */
+ MC_DRV_ERR_NOT_IMPLEMENTED = 3,
+ /* No more resources available. */
+ MC_DRV_ERR_OUT_OF_RESOURCES = 4,
+ /* Driver initialization failed. */
+ MC_DRV_ERR_INIT = 5,
+ /* Unknown error. */
+ MC_DRV_ERR_UNKNOWN = 6,
+ /* The specified device is unknown. */
+ MC_DRV_ERR_UNKNOWN_DEVICE = 7,
+ /* The specified session is unknown.*/
+ MC_DRV_ERR_UNKNOWN_SESSION = 8,
+ /* The specified operation is not allowed. */
+ MC_DRV_ERR_INVALID_OPERATION = 9,
+ /* The response header from the MC is invalid. */
+ MC_DRV_ERR_INVALID_RESPONSE = 10,
+ /* Function call timed out. */
+ MC_DRV_ERR_TIMEOUT = 11,
+ /* Can not allocate additional memory. */
+ MC_DRV_ERR_NO_FREE_MEMORY = 12,
+ /* Free memory failed. */
+ MC_DRV_ERR_FREE_MEMORY_FAILED = 13,
+ /* Still some open sessions pending. */
+ MC_DRV_ERR_SESSION_PENDING = 14,
+ /* MC daemon not reachable */
+ MC_DRV_ERR_DAEMON_UNREACHABLE = 15,
+ /* The device file of the kernel module could not be opened. */
+ MC_DRV_ERR_INVALID_DEVICE_FILE = 16,
+ /* Invalid parameter. */
MC_DRV_ERR_INVALID_PARAMETER = 17,
- /**< Unspecified error from Kernel Module*/
- MC_DRV_ERR_KERNEL_MODULE = 18,
- /**< Error during mapping of additional bulk memory to session. */
- MC_DRV_ERR_BULK_MAPPING = 19,
- /**< Error during unmapping of additional bulk memory to session. */
- MC_DRV_ERR_BULK_UNMAPPING = 20,
- /**< Notification received, exit code available. */
- MC_DRV_INFO_NOTIFICATION = 21,
- /**< Set up of NWd connection failed. */
- MC_DRV_ERR_NQ_FAILED = 22
+ /* Unspecified error from Kernel Module*/
+ MC_DRV_ERR_KERNEL_MODULE = 18,
+ /* Error during mapping of additional bulk memory to session. */
+ MC_DRV_ERR_BULK_MAPPING = 19,
+ /* Error during unmapping of additional bulk memory to session. */
+ MC_DRV_ERR_BULK_UNMAPPING = 20,
+ /* Notification received, exit code available. */
+ MC_DRV_INFO_NOTIFICATION = 21,
+ /* Set up of NWd connection failed. */
+ MC_DRV_ERR_NQ_FAILED = 22
};
-
-/**
+/*
* Driver control command.
*/
enum mc_driver_ctrl {
- MC_CTRL_GET_VERSION = 1 /**< Return the driver version */
+ /* Return the driver version */
+ MC_CTRL_GET_VERSION = 1
};
-
-/** Structure of Session Handle, includes the Session ID and the Device ID the
+/*
+ * Structure of Session Handle, includes the Session ID and the Device ID the
* Session belongs to.
* The session handle will be used for session-based MobiCore communication.
* It will be passed to calls which address a communication end point in the
* MobiCore environment.
*/
struct mc_session_handle {
- uint32_t session_id; /**< MobiCore session ID */
- uint32_t device_id; /**< Device ID the session belongs to */
+ uint32_t session_id; /* MobiCore session ID */
+ uint32_t device_id; /* Device ID the session belongs to */
};
-/** Information structure about additional mapped Bulk buffer between the
- * Trustlet Connector (Nwd) and the Trustlet (Swd). This structure is
+/*
+ * Information structure about additional mapped Bulk buffer between the
+ * Trustlet Connector (NWd) and the Trustlet (SWd). This structure is
* initialized from a Trustlet Connector by calling mc_map().
* In order to use the memory within a Trustlet the Trustlet Connector has to
* inform the Trustlet with the content of this structure via the TCI.
*/
struct mc_bulk_map {
- /**< The virtual address of the Bulk buffer regarding the address space
+ /* The virtual address of the Bulk buffer regarding the address space
* of the Trustlet, already includes a possible offset! */
void *secure_virt_addr;
- uint32_t secure_virt_len; /**< Length of the mapped Bulk buffer */
+ uint32_t secure_virt_len; /* Length of the mapped Bulk buffer */
};
-
-/**< The default device ID */
+/* The default device ID */
#define MC_DEVICE_ID_DEFAULT 0
-/**< Wait infinite for a response of the MC. */
+/* Wait infinite for a response of the MC. */
#define MC_INFINITE_TIMEOUT ((int32_t)(-1))
-/**< Do not wait for a response of the MC. */
+/* Do not wait for a response of the MC. */
#define MC_NO_TIMEOUT 0
-/**< TCI/DCI must not exceed 1MiB */
+/* TCI/DCI must not exceed 1MiB */
#define MC_MAX_TCI_LEN 0x100000
-
-
-/** Open a new connection to a MobiCore device.
+/**
+ * mc_open_device() - Open a new connection to a MobiCore device.
+ * @device_id: Identifier for the MobiCore device to be used.
+ * MC_DEVICE_ID_DEFAULT refers to the default device.
*
- * mc_open_device() initializes all device specific resources required to
- * communicate with an MobiCore instance located on the specified device in the
- * system. If the device does not exist the function will return
- * MC_DRV_ERR_UNKNOWN_DEVICE.
+ * Initializes all device specific resources required to communicate with a
+ * MobiCore instance located on the specified device in the system. If the
+ * device does not exist the function will return MC_DRV_ERR_UNKNOWN_DEVICE.
*
- * @param [in] device_id Identifier for the MobiCore device to be used.
- * MC_DEVICE_ID_DEFAULT refers to the default device.
- *
- * @return MC_DRV_OK if operation has been successfully completed.
- * @return MC_DRV_ERR_INVALID_OPERATION if device already opened.
- * @return MC_DRV_ERR_DAEMON_UNREACHABLE when problems with daemon occur.
- * @return MC_DRV_ERR_UNKNOWN_DEVICE when device_id is unknown.
- * @return MC_DRV_ERR_INVALID_DEVICE_FILE if kernel module under
- * /dev/mobicore cannot be opened
- *
- * Uses a Mutex.
+ * Return codes:
+ * MC_DRV_OK: operation completed successfully
+ * MC_DRV_ERR_INVALID_OPERATION: device already opened
+ * MC_DRV_ERR_DAEMON_UNREACHABLE: problems with daemon
+ * MC_DRV_ERR_UNKNOWN_DEVICE: device_id unknown
+ * MC_DRV_ERR_INVALID_DEVICE_FILE: kernel module under /dev/mobicore
+ * cannot be opened
*/
-__MC_CLIENT_LIB_API enum mc_result mc_open_device(
- uint32_t device_id
-);
+__MC_CLIENT_LIB_API enum mc_result mc_open_device(uint32_t device_id);
-/** Close the connection to a MobiCore device.
+/**
+ * mc_close_device() - Close the connection to a MobiCore device.
+ * @device_id: Identifier for the MobiCore device.
+ *
* When closing a device, active sessions have to be closed beforehand.
* Resources associated with the device will be released.
* The device may be opened again after it has been closed.
*
- * @param [in] device_id Identifier for the MobiCore device.
* MC_DEVICE_ID_DEFAULT refers to the default device.
*
- * @return MC_DRV_OK if operation has been successfully completed.
- * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id is invalid.
- * @return MC_DRV_ERR_SESSION_PENDING when a session is still open.
- * @return MC_DRV_ERR_DAEMON_UNREACHABLE when problems with daemon occur.
- *
- * Uses a Mutex.
+ * Return codes:
+ * MC_DRV_OK: operation completed successfully
+ * MC_DRV_ERR_UNKNOWN_DEVICE: device id is invalid
+ * MC_DRV_ERR_SESSION_PENDING: a session is still open
+ * MC_DRV_ERR_DAEMON_UNREACHABLE: problems with daemon occur
*/
-__MC_CLIENT_LIB_API enum mc_result mc_close_device(
- uint32_t device_id
-);
+__MC_CLIENT_LIB_API enum mc_result mc_close_device(uint32_t device_id);
-/** Open a new session to a Trustlet. The trustlet with the given UUID has
- * to be available in the flash filesystem.
+/**
+ * mc_open_session() - Open a new session to a Trustlet.
+ * @session: On success, the session data will be returned
+ * @uuid: UUID of the Trustlet to be opened
+ * @tci: TCI buffer for communicating with the Trustlet
+ * @tci_len: Length of the TCI buffer. Maximum allowed value
+ * is MC_MAX_TCI_LEN
+ *
+ * The Trustlet with the given UUID has to be available in the flash filesystem.
*
* Write MCP open message to buffer and notify MobiCore about the availability
* of a new command.
+ *
* Waits till the MobiCore responses with the new session ID (stored in the MCP
* buffer).
*
- * @param [in,out] session On success, the session data will be returned.
* Note that session.device_id has to be the device id of an opened device.
- * @param [in] uuid UUID of the Trustlet to be opened.
- * @param [in] tci TCI buffer for communicating with the trustlet.
- * @param [in] tci_len Length of the TCI buffer. Maximum allowed value
- * is MC_MAX_TCI_LEN.
*
- * @return MC_DRV_OK if operation has been successfully completed.
- * @return MC_DRV_INVALID_PARAMETER if session parameter is invalid.
- * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id is invalid.
- * @return MC_DRV_ERR_DAEMON_UNREACHABLE when problems with daemon socket occur.
- * @return MC_DRV_ERR_UNKNOWN_DEVICE when daemon returns an error.
- *
- * Uses a Mutex.
+ * Return codes:
+ * MC_DRV_OK: operation completed successfully
+ * MC_DRV_INVALID_PARAMETER: session parameter is invalid
+ * MC_DRV_ERR_UNKNOWN_DEVICE: device id is invalid
+ * MC_DRV_ERR_DAEMON_UNREACHABLE: problems with daemon socket occur
+ * MC_DRV_ERR_NQ_FAILED: daemon returns an error
*/
__MC_CLIENT_LIB_API enum mc_result mc_open_session(
- struct mc_session_handle *session,
- const struct mc_uuid_t *uuid,
- uint8_t *tci,
- uint32_t tci_len
-);
+ struct mc_session_handle *session, const struct mc_uuid_t *uuid,
+ uint8_t *tci, uint32_t tci_len);
-/** Close a Trustlet session.
+/**
+ * mc_close_session() - Close a Trustlet session.
+ * @session: Session to be closed.
*
* Closes the specified MobiCore session. The call will block until the
* session has been closed.
*
- * @pre Device device_id has to be opened in advance.
+ * Device device_id has to be opened in advance.
*
- * @param [in] session Session to be closed.
- *
- * @return MC_DRV_OK if operation has been successfully completed.
- * @return MC_DRV_INVALID_PARAMETER if session parameter is invalid.
- * @return MC_DRV_ERR_UNKNOWN_SESSION when session id is invalid.
- * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id of session is invalid.
- * @return MC_DRV_ERR_DAEMON_UNREACHABLE when problems with daemon occur.
- * @return MC_DRV_ERR_INVALID_DEVICE_FILE when daemon cannot open trustlet file.
- *
- * Uses a Mutex.
+ * Return codes:
+ * MC_DRV_OK: operation completed successfully
+ * MC_DRV_INVALID_PARAMETER: session parameter is invalid
+ * MC_DRV_ERR_UNKNOWN_SESSION: session id is invalid
+ * MC_DRV_ERR_UNKNOWN_DEVICE: device id of session is invalid
+ * MC_DRV_ERR_DAEMON_UNREACHABLE: problems with daemon occur
+ * MC_DRV_ERR_INVALID_DEVICE_FILE: daemon cannot open Trustlet file
*/
__MC_CLIENT_LIB_API enum mc_result mc_close_session(
- struct mc_session_handle *session
-);
+ struct mc_session_handle *session);
-/** Notify a session.
+/**
+ * mc_notify() - Notify a session.
+ * @session: The session to be notified.
+ *
* Notifies the session end point about available message data.
* If the session parameter is correct, notify will always succeed.
* Corresponding errors can only be received by mc_wait_notification().
- * @pre A session has to be opened in advance.
*
- * @param session The session to be notified.
+ * A session has to be opened in advance.
*
- * @return MC_DRV_OK if operation has been successfully completed.
- * @return MC_DRV_INVALID_PARAMETER if session parameter is invalid.
- * @return MC_DRV_ERR_UNKNOWN_SESSION when session id is invalid.
- * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id of session is invalid.
+ * Return codes:
+ * MC_DRV_OK: operation completed successfully
+ * MC_DRV_INVALID_PARAMETER: session parameter is invalid
+ * MC_DRV_ERR_UNKNOWN_SESSION: session id is invalid
+ * MC_DRV_ERR_UNKNOWN_DEVICE: device id of session is invalid
*/
-__MC_CLIENT_LIB_API enum mc_result mc_notify(
- struct mc_session_handle *session
-);
+__MC_CLIENT_LIB_API enum mc_result mc_notify(struct mc_session_handle *session);
-/** Wait for a notification.
+/**
+ * mc_wait_notification() - Wait for a notification.
+ * @session: The session the notification should correspond to.
+ * @timeout: Time in milliseconds to wait
+ * (MC_NO_TIMEOUT : direct return, > 0 : milliseconds,
+ * MC_INFINITE_TIMEOUT : wait infinitely)
*
* Wait for a notification issued by the MobiCore for a specific session.
* The timeout parameter specifies the number of milliseconds the call will wait
* for a notification.
+ *
* If the caller passes 0 as timeout value the call will immediately return.
* If timeout value is below 0 the call will block until a notification for the
- session has been received.
+ * session has been received.
*
- * @attention if timeout is below 0, call will block:
+ * If timeout is below 0, call will block.
+ *
* Caller has to trust the other side to send a notification to wake him up
* again.
*
- * @param [in] session The session the notification should correspond to.
- * @param [in] timeout Time in milliseconds to wait
- * (MC_NO_TIMEOUT : direct return, > 0 : milliseconds,
- * MC_INFINITE_TIMEOUT : wait infinitely)
- *
- * @return MC_DRV_OK if notification is available.
- * @return MC_DRV_ERR_TIMEOUT if no notification arrived in time.
- * @return MC_DRV_INFO_NOTIFICATION if a problem with the session was
- * encountered. Get more details with mc_get_session_error_code().
- * @return MC_DRV_ERR_NOTIFICATION if a problem with the socket occurred.
- * @return MC_DRV_INVALID_PARAMETER if a parameter is invalid.
- * @return MC_DRV_ERR_UNKNOWN_SESSION when session id is invalid.
- * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id of session is invalid.
+ * Return codes:
+ * MC_DRV_OK: operation completed successfully
+ * MC_DRV_ERR_TIMEOUT: no notification arrived in time
+ * MC_DRV_INFO_NOTIFICATION: a problem with the session was
+ * encountered. Get more details with
+ * mc_get_session_error_code()
+ * MC_DRV_ERR_NOTIFICATION: a problem with the socket occurred
+ * MC_DRV_INVALID_PARAMETER: a parameter is invalid
+ * MC_DRV_ERR_UNKNOWN_SESSION: session id is invalid
+ * MC_DRV_ERR_UNKNOWN_DEVICE: device id of session is invalid
*/
__MC_CLIENT_LIB_API enum mc_result mc_wait_notification(
- struct mc_session_handle *session,
- int32_t timeout
-);
+ struct mc_session_handle *session, int32_t timeout);
/**
- * Allocate a block of world shared memory (WSM).
+ * mc_malloc_wsm() - Allocate a block of world shared memory (WSM).
+ * @device_id: The ID of an opened device to retrieve the WSM from.
+ * @align: The alignment (number of pages) of the memory block
+ * (e.g. 0x00000001 for 4kb).
+ * @len: Length of the block in bytes.
+ * @wsm: Virtual address of the world shared memory block.
+ * @wsm_flags: Platform specific flags describing the memory to
+ * be allocated.
+ *
* The MC driver allocates a contiguous block of memory which can be used as
* WSM.
* This implicates that the allocated memory is aligned according to the
* alignment parameter.
+ *
* Always returns a buffer of size WSM_SIZE aligned to 4K.
*
- * @param [in] device_id The ID of an opened device to retrieve the WSM from.
- * @param [in] align The alignment (number of pages) of the memory block
- * (e.g. 0x00000001 for 4kb).
- * @param [in] len Length of the block in bytes.
- * @param [out] wsm Virtual address of the world shared memory block.
- * @param [in] wsm_flags Platform specific flags describing the memory to
- * be allocated.
+ * Align and wsm_flags are currently ignored
*
- * @attention: align and wsm_flags are currently ignored
- *
- * @return MC_DRV_OK if operation has been successfully completed.
- * @return MC_DRV_INVALID_PARAMETER if a parameter is invalid.
- * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id is invalid.
- * @return MC_DRV_ERR_NO_FREE_MEMORY if no more contiguous memory is available
- * in this size or for this process.
- *
- * Uses a Mutex.
+ * Return codes:
+ * MC_DRV_OK: operation completed successfully
+ * MC_DRV_INVALID_PARAMETER: a parameter is invalid
+ * MC_DRV_ERR_UNKNOWN_DEVICE: device id is invalid
+ * MC_DRV_ERR_NO_FREE_MEMORY: no more contiguous memory is
+ * available in this size or for this
+ * process
*/
__MC_CLIENT_LIB_API enum mc_result mc_malloc_wsm(
uint32_t device_id,
@@ -323,161 +306,140 @@
);
/**
- * Free a block of world shared memory (WSM).
+ * mc_free_wsm() - Free a block of world shared memory (WSM).
+ * @device_id: The ID to which the given address belongs
+ * @wsm: Address of WSM block to be freed
+ *
* The MC driver will free a block of world shared memory (WSM) previously
* allocated with mc_malloc_wsm(). The caller has to assure that the address
* handed over to the driver is a valid WSM address.
*
- * @param [in] device_id The ID to which the given address belongs.
- * @param [in] wsm Address of WSM block to be freed.
- *
- * @return MC_DRV_OK if operation has been successfully completed.
- * @return MC_DRV_INVALID_PARAMETER if a parameter is invalid.
- * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id is invalid.
- * @return MC_DRV_ERR_FREE_MEMORY_FAILED on failures.
- *
- * Uses a Mutex.
+ * Return codes:
+ * MC_DRV_OK: operation completed successfully
+ * MC_DRV_INVALID_PARAMETER: a parameter is invalid
+ * MC_DRV_ERR_UNKNOWN_DEVICE: when device id is invalid
+ * MC_DRV_ERR_FREE_MEMORY_FAILED: on failure
*/
-__MC_CLIENT_LIB_API enum mc_result mc_free_wsm(
- uint32_t device_id,
- uint8_t *wsm
-);
+__MC_CLIENT_LIB_API enum mc_result mc_free_wsm(uint32_t device_id,
+ uint8_t *wsm);
/**
- * Map additional bulk buffer between a Trustlet Connector (TLC) and
- * the Trustlet (TL) for a session.
+ *mc_map() - Map additional bulk buffer between a Trustlet Connector (TLC)
+ * and the Trustlet (TL) for a session
+ * @session: Session handle with information of the device_id and
+ * the session_id. The given buffer is mapped to the
+ * session specified in the sessionHandle
+ * @buf: Virtual address of a memory portion (relative to TLC)
+ * to be shared with the Trustlet, already includes a
+ * possible offset!
+ * @len: length of buffer block in bytes.
+ * @map_info: Information structure about the mapped Bulk buffer
+ * between the TLC (NWd) and the TL (SWd).
+ *
* Memory allocated in user space of the TLC can be mapped as additional
* communication channel (besides TCI) to the Trustlet. Limitation of the
* Trustlet memory structure apply: only 6 chunks can be mapped with a maximum
* chunk size of 1 MiB each.
*
- * @attention It is up to the application layer (TLC) to inform the Trustlet
+ * It is up to the application layer (TLC) to inform the Trustlet
* about the additional mapped bulk memory.
*
- * @param [in] session Session handle with information of the device_id and
- * the session_id. The
- * given buffer is mapped to the session specified in the sessionHandle.
- * @param [in] buf Virtual address of a memory portion (relative to TLC)
- * to be shared with the Trustlet, already includes a possible offset!
- * @param [in] len length of buffer block in bytes.
- * @param [out] map_info Information structure about the mapped Bulk buffer
- * between the TLC (Nwd) and
- * the TL (Swd).
- *
- * @return MC_DRV_OK if operation has been successfully completed.
- * @return MC_DRV_INVALID_PARAMETER if a parameter is invalid.
- * @return MC_DRV_ERR_UNKNOWN_SESSION when session id is invalid.
- * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id of session is invalid.
- * @return MC_DRV_ERR_DAEMON_UNREACHABLE when problems with daemon occur.
- * @return MC_DRV_ERR_BULK_MAPPING when buf is already uses as bulk buffer or
- * when registering the buffer failed.
- *
- * Uses a Mutex.
+ * Return codes:
+ * MC_DRV_OK: operation completed successfully
+ * MC_DRV_INVALID_PARAMETER: a parameter is invalid
+ * MC_DRV_ERR_UNKNOWN_SESSION: session id is invalid
+ * MC_DRV_ERR_UNKNOWN_DEVICE: device id of session is invalid
+ * MC_DRV_ERR_DAEMON_UNREACHABLE: problems with daemon occur
+ * MC_DRV_ERR_BULK_MAPPING: buf is already uses as bulk buffer or
+ * when registering the buffer failed
*/
__MC_CLIENT_LIB_API enum mc_result mc_map(
- struct mc_session_handle *session,
- void *buf,
- uint32_t len,
- struct mc_bulk_map *map_info
-);
+ struct mc_session_handle *session, void *buf, uint32_t len,
+ struct mc_bulk_map *map_info);
/**
- * Remove additional mapped bulk buffer between Trustlet Connector (TLC)
- * and the Trustlet (TL) for a session.
+ * mc_unmap() - Remove additional mapped bulk buffer between Trustlet Connector
+ * (TLC) and the Trustlet (TL) for a session
+ * @session: Session handle with information of the device_id and
+ * the session_id. The given buffer is unmapped from the
+ * session specified in the sessionHandle.
+ * @buf: Virtual address of a memory portion (relative to TLC)
+ * shared with the TL, already includes a possible offset!
+ * @map_info: Information structure about the mapped Bulk buffer
+ * between the TLC (NWd) and the TL (SWd)
*
- * @attention The bulk buffer will immediately be unmapped from the session
- * context.
- * @attention The application layer (TLC) must inform the TL about unmapping
- * of the additional bulk memory before calling mc_unmap!
+ * The bulk buffer will immediately be unmapped from the session context.
*
- * @param [in] session Session handle with information of the device_id and
- * the session_id. The given buffer is unmapped from the session specified
- * in the sessionHandle.
- * @param [in] buf Virtual address of a memory portion (relative to TLC)
- * shared with the TL, already includes a possible offset!
- * @param [in] map_info Information structure about the mapped Bulk buffer
- * between the TLC (Nwd) and
- * the TL (Swd).
- * @attention The clientlib currently ignores the len field in map_info.
+ * The application layer (TLC) must inform the TL about unmapping of the
+ * additional bulk memory before calling mc_unmap!
*
- * @return MC_DRV_OK if operation has been successfully completed.
- * @return MC_DRV_INVALID_PARAMETER if a parameter is invalid.
- * @return MC_DRV_ERR_UNKNOWN_SESSION when session id is invalid.
- * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id of session is invalid.
- * @return MC_DRV_ERR_DAEMON_UNREACHABLE when problems with daemon occur.
- * @return MC_DRV_ERR_BULK_UNMAPPING when buf was not registered earlier
- * or when unregistering failed.
+ * The clientlib currently ignores the len field in map_info.
*
- * Uses a Mutex.
+ * Return codes:
+ * MC_DRV_OK: operation completed successfully
+ * MC_DRV_INVALID_PARAMETER: a parameter is invalid
+ * MC_DRV_ERR_UNKNOWN_SESSION: session id is invalid
+ * MC_DRV_ERR_UNKNOWN_DEVICE: device id of session is invalid
+ * MC_DRV_ERR_DAEMON_UNREACHABLE: problems with daemon occur
+ * MC_DRV_ERR_BULK_UNMAPPING: buf was not registered earlier
+ * or when unregistering failed
*/
__MC_CLIENT_LIB_API enum mc_result mc_unmap(
- struct mc_session_handle *session,
- void *buf,
- struct mc_bulk_map *map_info
-);
-
+ struct mc_session_handle *session, void *buf,
+ struct mc_bulk_map *map_info);
/**
- * @attention: Not implemented.
- * Execute driver specific command.
- * mc_driver_ctrl() can be used to execute driver specific commands.
- * Besides the control command MC_CTRL_GET_VERSION commands are implementation
- * specific.
+ * mc_driver_ctrl() - Execute driver specific command.
+ * @param: Command ID of the command to be executed
+ * @data: Command data and response depending on command
+ * @len: Length of the data block
+ *
+ * Can be used to execute driver specific commands. Besides the control command
+ * MC_CTRL_GET_VERSION commands are implementation specific.
+ *
* Please refer to the corresponding specification of the driver manufacturer.
*
- * @param [in] param Command ID of the command to be executed.
- * @param [in, out] data Command data and response depending on command.
- * @param [in] len Length of the data block.
- *
- * @return MC_DRV_ERR_NOT_IMPLEMENTED.
+ * Return codes:
+ * MC_DRV_ERR_NOT_IMPLEMENTED.
*/
__MC_CLIENT_LIB_API enum mc_result mc_driver_ctrl(
- enum mc_driver_ctrl param,
- uint8_t *data,
- uint32_t len
-);
+ enum mc_driver_ctrl param, uint8_t *data, uint32_t len);
/**
- * @attention: Not implemented.
- * Execute application management command.
- * mc_manage() shall be used to exchange application management commands with
- * the MobiCore.
+ * mc_manage() - Execute application management command.
+ * @device_id: Identifier for the MobiCore device to be used.
+ * NULL refers to the default device.
+ * @data: Command data/response data depending on command
+ * @len: Length of the data block
+ *
+ * Shall be used to exchange application management commands with the MobiCore.
* The MobiCore Application Management Protocol is described in [MCAMP].
*
- * @param [in] device_id Identifier for the MobiCore device to be used.
- * NULL refers to the default device.
- * @param [in, out] data Command data/response data depending on command.
- * @param [in] len Length of the data block.
- *
- * @return MC_DRV_ERR_NOT_IMPLEMENTED.
+ * Return codes:
+ * MC_DRV_ERR_NOT_IMPLEMENTED.
*/
__MC_CLIENT_LIB_API enum mc_result mc_manage(
- uint32_t device_id,
- uint8_t *data,
- uint32_t len
-);
+ uint32_t device_id, uint8_t *data, uint32_t len);
/**
- * Get additional error information of the last error that occured on a session.
+ * mc_get_session_error_code() - Get additional error information of the last
+ * error that occurred on a session.
+ * @session: Session handle with information of the device_id and
+ * the session_id
+ * @last_error: >0 Trustlet has terminated itself with this value,
+ * <0 Trustlet is dead because of an error within the
+ * MobiCore (e.g. Kernel exception). See also MCI
+ * definition.
+ *
* After the request the stored error code will be deleted.
*
- * @param [in] session Session handle with information of the device_id and
- * the session_id.
- * @param [out] last_error >0 Trustlet has terminated itself with this value,
- * <0 Trustlet is dead because of an error within the MobiCore
- * (e.g. Kernel exception).
- * See also MCI definition.
- *
- * @return MC_DRV_OK if operation has been successfully completed.
- * @return MC_DRV_INVALID_PARAMETER if a parameter is invalid.
- * @return MC_DRV_ERR_UNKNOWN_SESSION when session id is invalid.
- * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id of session is invalid.
+ * Return codes:
+ * MC_DRV_OK: operation completed successfully
+ * MC_DRV_INVALID_PARAMETER: a parameter is invalid
+ * MC_DRV_ERR_UNKNOWN_SESSION: session id is invalid
+ * MC_DRV_ERR_UNKNOWN_DEVICE: device id of session is invalid
*/
__MC_CLIENT_LIB_API enum mc_result mc_get_session_error_code(
- struct mc_session_handle *session,
- int32_t *last_error
-);
+ struct mc_session_handle *session, int32_t *last_error);
-#endif /** MCDRIVER_H_ */
-
-/** @} */
+#endif /* _MOBICORE_DRIVER_API_H_ */
diff --git a/drivers/gud/mobicore_kernelapi/public/mobicore_driver_cmd.h b/drivers/gud/mobicore_kernelapi/public/mobicore_driver_cmd.h
index 9ff7989..3b8eb4b 100644
--- a/drivers/gud/mobicore_kernelapi/public/mobicore_driver_cmd.h
+++ b/drivers/gud/mobicore_kernelapi/public/mobicore_driver_cmd.h
@@ -1,8 +1,5 @@
-/** @addtogroup MCD_MCDIMPL_DAEMON
- * @{
- * @file
- *
- * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+/*
+ * <-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -28,11 +25,8 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef MCDAEMON_H_
-#define MCDAEMON_H_
-
-
-
+#ifndef _MOBICORE_DRIVER_CMD_H_
+#define _MOBICORE_DRIVER_CMD_H_
#include "mcuuid.h"
@@ -64,19 +58,17 @@
struct mc_drv_command_header_t {
- uint32_t command_id;
+ uint32_t command_id;
};
struct mc_drv_response_header_t {
- uint32_t response_id;
+ uint32_t response_id;
};
-#define MC_DEVICE_ID_DEFAULT 0 /**< The default device ID */
+#define MC_DEVICE_ID_DEFAULT 0 /* The default device ID */
-
-/*****************************************************************************/
struct mc_drv_cmd_open_device_payload_t {
- uint32_t device_id;
+ uint32_t device_id;
};
struct mc_drv_cmd_open_device_t {
@@ -94,13 +86,13 @@
struct mc_drv_rsp_open_device_payload_t payload;
};
-
-/*****************************************************************************/
struct mc_drv_cmd_close_device_t {
struct mc_drv_command_header_t header;
- /* no payload here because close has none.
- If we use an empty struct, C++ will count it as 4 bytes.
- This will write too much into the socket at write(cmd,sizeof(cmd)) */
+ /*
+ * no payload here because close has none.
+ * If we use an empty struct, C++ will count it as 4 bytes.
+ * This will write too much into the socket at write(cmd,sizeof(cmd))
+ */
};
@@ -113,8 +105,6 @@
struct mc_drv_rsp_close_device_payload_t payload;
};
-
-/*****************************************************************************/
struct mc_drv_cmd_open_session_payload_t {
uint32_t device_id;
struct mc_uuid_t uuid;
@@ -141,8 +131,6 @@
struct mc_drv_rsp_open_session_payload_t payload;
};
-
-/*****************************************************************************/
struct mc_drv_cmd_close_session_payload_t {
uint32_t session_id;
};
@@ -162,8 +150,6 @@
struct mc_drv_rsp_close_session_payload_t payload;
};
-
-/*****************************************************************************/
struct mc_drv_cmd_notify_payload_t {
uint32_t session_id;
};
@@ -183,10 +169,9 @@
struct mc_drv_rsp_notify_payload_t payload;
};
-
-/*****************************************************************************/
struct mc_drv_cmd_map_bulk_mem_payload_t {
uint32_t session_id;
+ uint32_t handle;
uint32_t phys_addr_l2;
uint32_t offset_payload;
uint32_t len_bulk_mem;
@@ -209,10 +194,9 @@
struct mc_drv_rsp_map_bulk_mem_payload_t payload;
};
-
-/*****************************************************************************/
struct mc_drv_cmd_unmap_bulk_mem_payload_t {
uint32_t session_id;
+ uint32_t handle;
uint32_t secure_virtual_adr;
uint32_t len_bulk_mem;
};
@@ -234,8 +218,6 @@
struct mc_drv_rsp_unmap_bulk_mem_payload_t payload;
};
-
-/*****************************************************************************/
struct mc_drv_cmd_nqconnect_payload_t {
uint32_t device_id;
uint32_t session_id;
@@ -258,8 +240,6 @@
struct mc_drv_rsp_nqconnect_payload_t payload;
};
-
-/*****************************************************************************/
union mc_drv_command_t {
struct mc_drv_command_header_t header;
struct mc_drv_cmd_open_device_t mc_drv_cmd_open_device;
@@ -284,6 +264,4 @@
struct mc_drv_rsp_unmap_bulk_mem_t mc_drv_rsp_unmap_bulk_mem;
};
-#endif /* MCDAEMON_H_ */
-
-/** @} */
+#endif /* _MOBICORE_DRIVER_CMD_H_ */
diff --git a/drivers/gud/mobicore_kernelapi/session.c b/drivers/gud/mobicore_kernelapi/session.c
index e62b4b3..dae2c00 100644
--- a/drivers/gud/mobicore_kernelapi/session.c
+++ b/drivers/gud/mobicore_kernelapi/session.c
@@ -1,7 +1,5 @@
-/** @addtogroup MCD_IMPL_LIB
- * @{
- * @file
- * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+/*
+ * <-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -9,39 +7,35 @@
*/
#include <linux/types.h>
#include <linux/slab.h>
+#include <linux/device.h>
#include "mc_kernel_api.h"
#include "public/mobicore_driver_api.h"
#include "session.h"
-/*****************************************************************************/
struct bulk_buffer_descriptor *bulk_buffer_descriptor_create(
- void *virt_addr,
- uint32_t len,
- uint32_t handle,
- void *phys_addr_wsm_l2
-) {
- struct bulk_buffer_descriptor *desc =
- kzalloc(sizeof(struct bulk_buffer_descriptor), GFP_KERNEL);
+ void *virt_addr, uint32_t len, uint32_t handle, void *phys_addr_wsm_l2)
+{
+ struct bulk_buffer_descriptor *desc;
+
+ desc = kzalloc(sizeof(*desc), GFP_KERNEL);
desc->virt_addr = virt_addr;
desc->len = len;
desc->handle = handle;
desc->phys_addr_wsm_l2 = phys_addr_wsm_l2;
+
return desc;
}
-/*****************************************************************************/
struct session *session_create(
- uint32_t session_id,
- void *instance,
- struct connection *connection
-) {
- struct session *session =
- kzalloc(sizeof(struct session), GFP_KERNEL);
+ uint32_t session_id, void *instance, struct connection *connection)
+{
+ struct session *session;
+
+ session = kzalloc(sizeof(*session), GFP_KERNEL);
session->session_id = session_id;
session->instance = instance;
session->notification_connection = connection;
-
session->session_info.last_error = SESSION_ERR_NO;
session->session_info.state = SESSION_STATE_INITIAL;
@@ -49,29 +43,31 @@
return session;
}
-
-/*****************************************************************************/
-void session_cleanup(
- struct session *session
-) {
- struct bulk_buffer_descriptor *bulk_buf_descr;
+void session_cleanup(struct session *session)
+{
+ struct bulk_buffer_descriptor *bulk_buf_descr;
struct list_head *pos, *q;
+ unsigned int phys_addr_wsm_l2;
/* Unmap still mapped buffers */
list_for_each_safe(pos, q, &session->bulk_buffer_descriptors) {
bulk_buf_descr =
list_entry(pos, struct bulk_buffer_descriptor, list);
- MCDRV_DBG_VERBOSE("Physical Address of L2 Table = 0x%X, "
- "handle= %d",
- (unsigned int)bulk_buf_descr->phys_addr_wsm_l2,
- bulk_buf_descr->handle);
+ phys_addr_wsm_l2 =
+ (unsigned int)bulk_buf_descr->phys_addr_wsm_l2;
+
+ MCDRV_DBG_VERBOSE(mc_kapi,
+ "Phys Addr of L2 Table = 0x%X, handle= %d",
+ phys_addr_wsm_l2,
+ bulk_buf_descr->handle);
/* ignore any error, as we cannot do anything in this case. */
int ret = mobicore_unmap_vmem(session->instance,
- bulk_buf_descr->handle);
+ bulk_buf_descr->handle);
if (ret != 0)
- MCDRV_DBG_ERROR("mobicore_unmap_vmem failed: %d", ret);
+ MCDRV_DBG_ERROR(mc_kapi,
+ "mobicore_unmap_vmem failed: %d", ret);
list_del(pos);
kfree(bulk_buf_descr);
@@ -82,36 +78,27 @@
kfree(session);
}
-
-/*****************************************************************************/
-void session_set_error_info(
- struct session *session,
- int32_t err
-) {
+void session_set_error_info(struct session *session, int32_t err)
+{
session->session_info.last_error = err;
}
-
-/*****************************************************************************/
-int32_t session_get_last_err(
- struct session *session
-) {
+int32_t session_get_last_err(struct session *session)
+{
return session->session_info.last_error;
}
-
-/*****************************************************************************/
-struct bulk_buffer_descriptor *session_add_bulk_buf(
- struct session *session,
- void *buf,
- uint32_t len
-) {
+struct bulk_buffer_descriptor *session_add_bulk_buf(struct session *session,
+ void *buf, uint32_t len)
+{
struct bulk_buffer_descriptor *bulk_buf_descr = NULL;
- struct bulk_buffer_descriptor *tmp;
+ struct bulk_buffer_descriptor *tmp;
struct list_head *pos;
- /* Search bulk buffer descriptors for existing vAddr
- At the moment a virtual address can only be added one time */
+ /*
+ * Search bulk buffer descriptors for existing vAddr
+ * At the moment a virtual address can only be added one time
+ */
list_for_each(pos, &session->bulk_buffer_descriptors) {
tmp = list_entry(pos, struct bulk_buffer_descriptor, list);
if (tmp->virt_addr == buf)
@@ -119,84 +106,96 @@
}
do {
- /* Prepare the interface structure for memory registration in
- Kernel Module */
- void *l2_table_phys;
- uint32_t handle;
+ /*
+ * Prepare the interface structure for memory registration in
+ * Kernel Module
+ */
+ uint32_t l2_table_phys;
+ uint32_t handle;
- int ret = mobicore_map_vmem(session->instance,
- buf,
- len,
- &handle,
- &l2_table_phys);
+ int ret = mobicore_map_vmem(session->instance, buf, len,
+ &handle, &l2_table_phys);
if (ret != 0) {
- MCDRV_DBG_ERROR("mobicore_map_vmem failed, ret=%d",
+ MCDRV_DBG_ERROR(mc_kapi,
+ "mobicore_map_vmem failed, ret=%d",
ret);
break;
}
- MCDRV_DBG_VERBOSE("Physical Address of L2 Table = 0x%X, "
- "handle=%d",
- (unsigned int)l2_table_phys,
- handle);
+ MCDRV_DBG_VERBOSE(mc_kapi,
+ "Phys Addr of L2 Table = 0x%X, handle=%d",
+ (unsigned int)l2_table_phys, handle);
/* Create new descriptor */
- bulk_buf_descr = bulk_buffer_descriptor_create(
- buf,
- len,
- handle,
- l2_table_phys);
+ bulk_buf_descr =
+ bulk_buffer_descriptor_create(buf, len,
+ handle,
+ (void *)l2_table_phys);
/* Add to vector of descriptors */
list_add_tail(&(bulk_buf_descr->list),
- &(session->bulk_buffer_descriptors));
+ &(session->bulk_buffer_descriptors));
} while (0);
return bulk_buf_descr;
}
-
-/*****************************************************************************/
-bool session_remove_bulk_buf(
- struct session *session,
- void *virt_addr
-) {
+bool session_remove_bulk_buf(struct session *session, void *virt_addr)
+{
bool ret = true;
- struct bulk_buffer_descriptor *bulk_buf_descr = NULL;
- struct bulk_buffer_descriptor *tmp;
+ struct bulk_buffer_descriptor *bulk_buf = NULL;
+ struct bulk_buffer_descriptor *tmp;
struct list_head *pos, *q;
- MCDRV_DBG_VERBOSE("Virtual Address = 0x%X", (unsigned int) virt_addr);
+ MCDRV_DBG_VERBOSE(mc_kapi, "Virtual Address = 0x%X",
+ (unsigned int) virt_addr);
/* Search and remove bulk buffer descriptor */
list_for_each_safe(pos, q, &session->bulk_buffer_descriptors) {
tmp = list_entry(pos, struct bulk_buffer_descriptor, list);
if (tmp->virt_addr == virt_addr) {
- bulk_buf_descr = tmp;
+ bulk_buf = tmp;
list_del(pos);
break;
}
}
- if (bulk_buf_descr == NULL) {
- MCDRV_DBG_ERROR("Virtual Address not found");
+ if (bulk_buf == NULL) {
+ MCDRV_DBG_ERROR(mc_kapi, "Virtual Address not found");
ret = false;
} else {
- MCDRV_DBG_VERBOSE("WsmL2 phys=0x%X, handle=%d",
- (unsigned int)bulk_buf_descr->phys_addr_wsm_l2,
- bulk_buf_descr->handle);
+ MCDRV_DBG_VERBOSE(mc_kapi, "WsmL2 phys=0x%X, handle=%d",
+ (unsigned int)bulk_buf->phys_addr_wsm_l2,
+ bulk_buf->handle);
/* ignore any error, as we cannot do anything */
int ret = mobicore_unmap_vmem(session->instance,
- bulk_buf_descr->handle);
+ bulk_buf->handle);
if (ret != 0)
- MCDRV_DBG_ERROR("mobicore_unmap_vmem failed: %d", ret);
+ MCDRV_DBG_ERROR(mc_kapi,
+ "mobicore_unmap_vmem failed: %d", ret);
- kfree(bulk_buf_descr);
+ kfree(bulk_buf);
}
return ret;
}
-/** @} */
+uint32_t session_find_bulk_buf(struct session *session, void *virt_addr)
+{
+ struct bulk_buffer_descriptor *tmp;
+ struct list_head *pos, *q;
+
+ MCDRV_DBG_VERBOSE(mc_kapi, "Virtual Address = 0x%X",
+ (unsigned int) virt_addr);
+
+ /* Search and return buffer descriptor handle */
+ list_for_each_safe(pos, q, &session->bulk_buffer_descriptors) {
+ tmp = list_entry(pos, struct bulk_buffer_descriptor, list);
+ if (tmp->virt_addr == virt_addr)
+ return tmp->handle;
+ }
+
+ return 0;
+}
diff --git a/drivers/gud/mobicore_kernelapi/session.h b/drivers/gud/mobicore_kernelapi/session.h
index 9a53740..4a834e5 100644
--- a/drivers/gud/mobicore_kernelapi/session.h
+++ b/drivers/gud/mobicore_kernelapi/session.h
@@ -1,14 +1,12 @@
-/** @addtogroup MCD_IMPL_LIB
- * @{
- * @file
- * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+/*
+ * <-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-#ifndef SESSION_H_
-#define SESSION_H_
+#ifndef _MC_KAPI_SESSION_H_
+#define _MC_KAPI_SESSION_H_
#include "common.h"
@@ -17,23 +15,27 @@
struct bulk_buffer_descriptor {
- void *virt_addr;/**< The virtual address of the Bulk buffer*/
- uint32_t len; /**< Length of the Bulk buffer*/
+ void *virt_addr; /* The VA of the Bulk buffer */
+ uint32_t len; /* Length of the Bulk buffer */
uint32_t handle;
- void *phys_addr_wsm_l2; /**< The physical address of the
- L2 table of the Bulk buffer*/
- struct list_head list; /**< The list param for using the kernel lists*/
+
+ /* The physical address of the L2 table of the Bulk buffer*/
+ void *phys_addr_wsm_l2;
+
+ /* The list param for using the kernel lists*/
+ struct list_head list;
};
struct bulk_buffer_descriptor *bulk_buffer_descriptor_create(
- void *virt_addr,
- uint32_t len,
- uint32_t handle,
- void *phys_addr_wsm_l2
+ void *virt_addr,
+ uint32_t len,
+ uint32_t handle,
+ void *phys_addr_wsm_l2
);
-/** Session states.
- * At the moment not used !!.
+/*
+ * Session states.
+ * At the moment not used !!
*/
enum session_state {
SESSION_STATE_INITIAL,
@@ -41,96 +43,102 @@
SESSION_STATE_TRUSTLET_DEAD
};
-#define SESSION_ERR_NO 0 /**< No session error */
+#define SESSION_ERR_NO 0 /* No session error */
-/** Session information structure.
+/*
+ * Session information structure.
* The information structure is used to hold the state of the session, which
* will limit further actions for the session.
* Also the last error code will be stored till it's read.
*/
struct session_information {
- enum session_state state; /**< Session state */
- int32_t last_error; /**< Last error of session */
+ enum session_state state; /* Session state */
+ int32_t last_error; /* Last error of session */
};
struct session {
struct mc_instance *instance;
- /**< Descriptors of additional bulk buffer of a session */
- struct list_head bulk_buffer_descriptors;
- /**< Informations about session */
- struct session_information session_info;
- uint32_t session_id;
- struct connection *notification_connection;
+ /* Descriptors of additional bulk buffer of a session */
+ struct list_head bulk_buffer_descriptors;
- /**< The list param for using the kernel lists*/
- struct list_head list;
+ /* Information about session */
+ struct session_information session_info;
+
+ uint32_t session_id;
+ struct connection *notification_connection;
+
+ /* The list param for using the kernel lists */
+ struct list_head list;
};
struct session *session_create(
- uint32_t session_id,
- void *instance,
- struct connection *connection
+ uint32_t session_id,
+ void *instance,
+ struct connection *connection
);
-void session_cleanup(
- struct session *session
-);
+void session_cleanup(struct session *session);
-/**
- * Add address information of additional bulk buffer memory to session and
- * register virtual memory in kernel module.
- *
- * @attention The virtual address can only be added one time. If the virtual
- * address already exist, NULL is returned.
- *
- * @param buf The virtual address of bulk buffer.
- * @param len Length of bulk buffer.
- *
- * @return On success the actual Bulk buffer descriptor with all address
- * information is retured, NULL if an error occurs.
- */
+/*
+ * session_add_bulk_buf() - Add address information of additional bulk
+ * buffer memory to session and register virtual
+ * memory in kernel module
+ * @session: Session information structure
+ * @buf: The virtual address of bulk buffer.
+ * @len: Length of bulk buffer.
+ *
+ * The virtual address can only be added one time. If the virtual
+ * address already exist, NULL is returned.
+ *
+ * On success the actual Bulk buffer descriptor with all address information
+ * is returned, NULL if an error occurs.
+ */
struct bulk_buffer_descriptor *session_add_bulk_buf(
- struct session *session,
- void *buf,
- uint32_t len
-);
+ struct session *session, void *buf, uint32_t len);
-/**
- * Remove address information of additional bulk buffer memory from session and
- * unregister virtual memory in kernel module
- *
- * @param buf The virtual address of the bulk buffer.
- *
- * @return true on success.
- */
-bool session_remove_bulk_buf(
- struct session *session,
- void *buf
-);
+/*
+ * session_remove_bulk_buf() - Remove address information of additional bulk
+ * buffer memory from session and unregister
+ * virtual memory in kernel module
+ * @session: Session information structure
+ * @buf: The virtual address of the bulk buffer
+ *
+ * Returns true on success
+ */
+bool session_remove_bulk_buf(struct session *session, void *buf);
-/**
- * Set additional error information of the last error that occured.
- *
- * @param errorCode The actual error.
- */
-void session_set_error_info(
- struct session *session,
- int32_t err
-);
-/**
- * Get additional error information of the last error that occured.
- *
- * @attention After request the information is set to SESSION_ERR_NO.
- *
- * @return Last stored error code or SESSION_ERR_NO.
- */
-int32_t session_get_last_err(
- struct session *session
-);
+/*
+ * session_find_bulk_buf() - Find the handle of the bulk buffer for this
+ * session
+ *
+ * @session: Session information structure
+ * @buf: The virtual address of bulk buffer.
+ *
+ * On success the actual Bulk buffer handle is returned, 0
+ * if an error occurs.
+ */
+uint32_t session_find_bulk_buf(struct session *session, void *virt_addr);
-#endif /* SESSION_H_ */
+/*
+ * session_set_error_info() - Set additional error information of the last
+ * error that occurred.
+ * @session: Session information structure
+ * @err: The actual error
+ */
+void session_set_error_info(struct session *session, int32_t err);
-/** @} */
+/*
+ * session_get_last_err() - Get additional error information of the last
+ * error that occurred.
+ * @session: Session information structure
+ *
+ * After request the information is set to SESSION_ERR_NO.
+ *
+ * Returns the last stored error code or SESSION_ERR_NO
+ */
+int32_t session_get_last_err(struct session *session);
+
+#endif /* _MC_KAPI_SESSION_H_ */
diff --git a/drivers/gud/mobicore_kernelapi/wsm.h b/drivers/gud/mobicore_kernelapi/wsm.h
index 6877c53..f8a107c 100644
--- a/drivers/gud/mobicore_kernelapi/wsm.h
+++ b/drivers/gud/mobicore_kernelapi/wsm.h
@@ -1,35 +1,33 @@
-/** @addtogroup MCD_MCDIMPL_DAEMON_SRV
- * @{
- * @file
- *
+/*
* World shared memory definitions.
*
- * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+ * <-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-#ifndef WSM_H_
-#define WSM_H_
+#ifndef _MC_KAPI_WSM_H_
+#define _MC_KAPI_WSM_H_
#include "common.h"
#include <linux/list.h>
struct wsm {
- void *virt_addr;
- uint32_t len;
- uint32_t handle;
- void *phys_addr;
- struct list_head list;
+ void *virt_addr;
+ uint32_t len;
+ uint32_t handle;
+ void *phys_addr;
+ struct list_head list;
};
struct wsm *wsm_create(
- void *virt_addr,
- uint32_t len,
- uint32_t handle,
- void *phys_addr /*= NULL this may be unknown, so is can be omitted.*/
-);
-#endif /* WSM_H_ */
+ void *virt_addr,
+ uint32_t len,
+ uint32_t handle,
-/** @} */
+ /* NULL this may be unknown, so is can be omitted */
+ void *phys_addr
+);
+
+#endif /* _MC_KAPI_WSM_H_ */
diff --git a/drivers/hwmon/epm_adc.c b/drivers/hwmon/epm_adc.c
index 606bc36..a526f24 100644
--- a/drivers/hwmon/epm_adc.c
+++ b/drivers/hwmon/epm_adc.c
@@ -95,7 +95,8 @@
#define EPM_PSOC_GLOBAL_ENABLE 81
#define EPM_PSOC_VREF_VOLTAGE 2048
-#define EPM_PSOC_MAX_ADC_CODE_16_BIT 32767
+#define EPM_PSOC_MAX_ADC_CODE_15_BIT 32767
+#define EPM_PSOC_MAX_ADC_CODE_12_BIT 4096
#define EPM_GLOBAL_ENABLE_MIN_DELAY 5000
#define EPM_GLOBAL_ENABLE_MAX_DELAY 5100
@@ -590,13 +591,23 @@
struct epm_adc_drv *epm_adc = epm_adc_drv;
int32_t result_cur;
- /* result = 2.048V/(32767 * gain * rsense) */
- result_cur = (((EPM_PSOC_VREF_VOLTAGE * result)/
- EPM_PSOC_MAX_ADC_CODE_16_BIT) * 1000);
+ if ((1 << index) & epm_adc->channel_mask) {
+ /* result = (2.048V * code)/(4096 * gain * rsense) */
+ result_cur = ((EPM_PSOC_VREF_VOLTAGE * result)/
+ EPM_PSOC_MAX_ADC_CODE_12_BIT);
- result_cur = (result_cur/
+ result_cur = (result_cur/
+ (epm_adc->epm_psoc_ch_prop[index].gain *
+ epm_adc->epm_psoc_ch_prop[index].resistorvalue));
+ } else {
+ /* result = (2.048V * code)/(32767 * gain * rsense) */
+ result_cur = (((EPM_PSOC_VREF_VOLTAGE * result)/
+ EPM_PSOC_MAX_ADC_CODE_15_BIT) * 1000);
+
+ result_cur = (result_cur/
(epm_adc->epm_psoc_ch_prop[index].gain *
epm_adc->epm_psoc_ch_prop[index].resistorvalue));
+ }
return result_cur;
}
diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c
index 5fb041d..440dc42 100644
--- a/drivers/hwmon/qpnp-adc-common.c
+++ b/drivers/hwmon/qpnp-adc-common.c
@@ -632,7 +632,7 @@
do_div(adc_voltage, param1.dy);
- qpnp_adc_map_temp_voltage(adcmap_100k_104ef_104fb,
+ qpnp_adc_map_voltage_temp(adcmap_100k_104ef_104fb,
ARRAY_SIZE(adcmap_100k_104ef_104fb),
adc_voltage, result);
if (negative_offset)
@@ -649,7 +649,7 @@
qpnp_get_vadc_gain_and_offset(¶m1, CALIB_RATIOMETRIC);
- rc = qpnp_adc_map_voltage_temp(adcmap_100k_104ef_104fb,
+ rc = qpnp_adc_map_temp_voltage(adcmap_100k_104ef_104fb,
ARRAY_SIZE(adcmap_100k_104ef_104fb),
param->low_thr_temp, ¶m->low_thr_voltage);
if (rc)
@@ -659,7 +659,7 @@
do_div(param->low_thr_voltage, param1.adc_vref);
param->low_thr_voltage += param1.adc_gnd;
- rc = qpnp_adc_map_voltage_temp(adcmap_100k_104ef_104fb,
+ rc = qpnp_adc_map_temp_voltage(adcmap_100k_104ef_104fb,
ARRAY_SIZE(adcmap_100k_104ef_104fb),
param->high_thr_temp, ¶m->high_thr_voltage);
if (rc)
@@ -822,7 +822,7 @@
struct device_node *node = spmi->dev.of_node;
struct resource *res;
struct device_node *child;
- struct qpnp_vadc_amux *adc_channel_list;
+ struct qpnp_adc_amux *adc_channel_list;
struct qpnp_adc_properties *adc_prop;
struct qpnp_adc_amux_properties *amux_prop;
int count_adc_channel_list = 0, decimation, rc = 0, i = 0;
@@ -847,7 +847,7 @@
return -ENOMEM;
}
adc_channel_list = devm_kzalloc(&spmi->dev,
- ((sizeof(struct qpnp_vadc_amux)) * count_adc_channel_list),
+ ((sizeof(struct qpnp_adc_amux)) * count_adc_channel_list),
GFP_KERNEL);
if (!adc_channel_list) {
dev_err(&spmi->dev, "Unable to allocate memory\n");
@@ -877,8 +877,7 @@
return -EINVAL;
}
- rc = of_property_read_u32(child, "qcom,channel-num",
- &channel_num);
+ rc = of_property_read_u32(child, "reg", &channel_num);
if (rc) {
pr_err("Invalid channel num\n");
return -EINVAL;
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
index b5ee104..8071687e 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -171,6 +171,47 @@
return 0;
}
+static int32_t qpnp_iadc_status_debug(void)
+{
+ int rc = 0;
+ u8 mode = 0, status1 = 0, chan = 0, dig = 0, en = 0;
+
+ rc = qpnp_iadc_read_reg(QPNP_IADC_MODE_CTL, &mode);
+ if (rc < 0) {
+ pr_err("mode ctl register read failed with %d\n", rc);
+ return rc;
+ }
+
+ rc = qpnp_iadc_read_reg(QPNP_ADC_DIG_PARAM, &dig);
+ if (rc < 0) {
+ pr_err("digital param read failed with %d\n", rc);
+ return rc;
+ }
+
+ rc = qpnp_iadc_read_reg(QPNP_IADC_ADC_CH_SEL_CTL, &chan);
+ if (rc < 0) {
+ pr_err("channel read failed with %d\n", rc);
+ return rc;
+ }
+
+ rc = qpnp_iadc_read_reg(QPNP_STATUS1, &status1);
+ if (rc < 0) {
+ pr_err("status1 read failed with %d\n", rc);
+ return rc;
+ }
+
+ rc = qpnp_iadc_read_reg(QPNP_IADC_EN_CTL1, &en);
+ if (rc < 0) {
+ pr_err("en read failed with %d\n", rc);
+ return rc;
+ }
+
+ pr_err("EOC not set with status:%x, dig:%x, ch:%x, mode:%x, en:%x\n",
+ status1, dig, chan, mode, en);
+
+ return 0;
+}
+
static void trigger_iadc_completion(struct work_struct *work)
{
struct qpnp_iadc_drv *iadc = qpnp_iadc;
@@ -253,7 +294,7 @@
qpnp_iadc_dig_param_reg |= iadc->adc->amux_prop->decimation <<
QPNP_IADC_DEC_RATIO_SEL;
-
+ qpnp_iadc_mode_reg |= QPNP_ADC_TRIM_EN;
qpnp_iadc_conv_req = QPNP_IADC_CONV_REQ;
rc = qpnp_iadc_write_reg(QPNP_IADC_MODE_CTL, qpnp_iadc_mode_reg);
@@ -311,12 +352,15 @@
if (status1 == QPNP_STATUS1_EOC)
pr_debug("End of conversion status set\n");
else {
- pr_err("EOC interrupt not received\n");
+ rc = qpnp_iadc_status_debug();
+ if (rc < 0) {
+ pr_err("status1 read failed with %d\n", rc);
+ return rc;
+ }
return -EINVAL;
}
}
-
rc = qpnp_iadc_read_conversion_result(raw_code);
if (rc) {
pr_err("qpnp adc read adc failed with %d\n", rc);
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index b71c998..d8d5b53 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -170,7 +170,7 @@
return 0;
}
-int32_t qpnp_vadc_configure(
+static int32_t qpnp_vadc_configure(
struct qpnp_adc_amux_properties *chan_prop)
{
struct qpnp_vadc_drv *vadc = qpnp_vadc;
@@ -179,7 +179,8 @@
int rc = 0;
/* Mode selection */
- mode_ctrl = chan_prop->mode_sel << QPNP_VADC_OP_MODE_SHIFT;
+ mode_ctrl |= ((chan_prop->mode_sel << QPNP_VADC_OP_MODE_SHIFT) |
+ (QPNP_VADC_ADC_TRIM_EN | QPNP_VADC_AMUX_TRIM_EN));
rc = qpnp_vadc_write_reg(QPNP_VADC_MODE_CTL, mode_ctrl);
if (rc < 0) {
pr_err("Mode configure write error\n");
@@ -260,7 +261,6 @@
return 0;
}
-EXPORT_SYMBOL(qpnp_vadc_configure);
static int32_t qpnp_vadc_read_conversion_result(int32_t *data)
{
@@ -579,11 +579,11 @@
vadc->adc->amux_prop->amux_channel = channel;
- while (vadc->adc->adc_channels[dt_index].channel_num
- != channel || dt_index > vadc->max_channels_available)
+ while ((vadc->adc->adc_channels[dt_index].channel_num
+ != channel) && (dt_index < vadc->max_channels_available))
dt_index++;
- if (dt_index > vadc->max_channels_available) {
+ if (dt_index >= vadc->max_channels_available) {
pr_err("not a valid VADC channel\n");
rc = -EINVAL;
goto fail_unlock;
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 085b632..92d162b 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
+/* 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
@@ -164,7 +164,6 @@
struct msm_i2c_platform_data *pdata;
int suspended;
int clk_state;
- struct timer_list pwr_timer;
struct mutex mlock;
void *complete;
int i2c_gpios[ARRAY_SIZE(i2c_rsrcs)];
@@ -197,6 +196,9 @@
uint32_t op_flgs = readl_relaxed(dev->base + QUP_OPERATIONAL);
int err = 0;
+ if (pm_runtime_suspended(dev->dev))
+ return IRQ_NONE;
+
if (!dev->msg || !dev->complete) {
/* Clear Error interrupt if it's a level triggered interrupt*/
if (dev->num_irqs == 1) {
@@ -327,27 +329,18 @@
{
dev->clk_state = state;
if (state != 0) {
- clk_enable(dev->clk);
+ clk_prepare_enable(dev->clk);
if (!dev->pdata->keep_ahb_clk_on)
- clk_enable(dev->pclk);
+ clk_prepare_enable(dev->pclk);
} else {
qup_update_state(dev, QUP_RESET_STATE);
- clk_disable(dev->clk);
+ clk_disable_unprepare(dev->clk);
qup_config_core_on_en(dev);
if (!dev->pdata->keep_ahb_clk_on)
- clk_disable(dev->pclk);
+ clk_disable_unprepare(dev->pclk);
}
}
-static void
-qup_i2c_pwr_timer(unsigned long data)
-{
- struct qup_i2c_dev *dev = (struct qup_i2c_dev *) data;
- dev_dbg(dev->dev, "QUP_Power: Inactivity based power management\n");
- if (dev->clk_state == 1)
- qup_i2c_pwr_mgmt(dev, 0);
-}
-
static int
qup_i2c_poll_writeready(struct qup_i2c_dev *dev, int rem)
{
@@ -756,7 +749,7 @@
long timeout;
int err;
- del_timer_sync(&dev->pwr_timer);
+ pm_runtime_get_sync(dev->dev);
mutex_lock(&dev->mlock);
if (dev->suspended) {
@@ -764,9 +757,6 @@
return -EIO;
}
- if (dev->clk_state == 0)
- qup_i2c_pwr_mgmt(dev, 1);
-
/* Initialize QUP registers during first transfer */
if (dev->clk_ctl == 0) {
int fs_div;
@@ -1068,9 +1058,9 @@
dev->pos = 0;
dev->err = 0;
dev->cnt = 0;
- dev->pwr_timer.expires = jiffies + 3*HZ;
- add_timer(&dev->pwr_timer);
mutex_unlock(&dev->mlock);
+ pm_runtime_mark_last_busy(dev->dev);
+ pm_runtime_put_autosuspend(dev->dev);
return ret;
}
@@ -1322,21 +1312,14 @@
if (pdata->msm_i2c_config_gpio)
pdata->msm_i2c_config_gpio(dev->adapter.nr, 1);
- dev->suspended = 0;
mutex_init(&dev->mlock);
dev->clk_state = 0;
- clk_prepare(dev->clk);
- clk_prepare(dev->pclk);
/* If the same AHB clock is used on Modem side
* switch it on here itself and don't switch it
* on and off during suspend and resume.
*/
if (dev->pdata->keep_ahb_clk_on)
- clk_enable(dev->pclk);
- setup_timer(&dev->pwr_timer, qup_i2c_pwr_timer, (unsigned long) dev);
-
- pm_runtime_set_active(&pdev->dev);
- pm_runtime_enable(&pdev->dev);
+ clk_prepare_enable(dev->pclk);
ret = i2c_add_numbered_adapter(&dev->adapter);
if (ret) {
@@ -1351,6 +1334,10 @@
dev->adapter.dev.of_node = pdev->dev.of_node;
of_i2c_register_devices(&dev->adapter);
}
+
+ pm_runtime_set_autosuspend_delay(&pdev->dev, MSEC_PER_SEC);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
return 0;
}
@@ -1393,7 +1380,6 @@
dev->suspended = 1;
mutex_unlock(&dev->mlock);
mutex_destroy(&dev->mlock);
- del_timer_sync(&dev->pwr_timer);
if (dev->clk_state != 0)
qup_i2c_pwr_mgmt(dev, 0);
platform_set_drvdata(pdev, NULL);
@@ -1403,9 +1389,7 @@
}
free_irq(dev->err_irq, dev);
i2c_del_adapter(&dev->adapter);
- clk_unprepare(dev->clk);
if (!dev->pdata->keep_ahb_clk_on) {
- clk_unprepare(dev->pclk);
clk_put(dev->pclk);
}
clk_put(dev->clk);
@@ -1415,6 +1399,7 @@
iounmap(dev->base);
pm_runtime_disable(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
if (!(dev->pdata->use_gsbi_shared_mode)) {
gsbi_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
@@ -1431,67 +1416,63 @@
}
#ifdef CONFIG_PM
-static int qup_i2c_suspend(struct device *device)
+static int i2c_qup_pm_suspend_runtime(struct device *device)
{
struct platform_device *pdev = to_platform_device(device);
struct qup_i2c_dev *dev = platform_get_drvdata(pdev);
-
+ dev_dbg(device, "pm_runtime: suspending...\n");
/* Grab mutex to ensure ongoing transaction is over */
mutex_lock(&dev->mlock);
dev->suspended = 1;
mutex_unlock(&dev->mlock);
- del_timer_sync(&dev->pwr_timer);
if (dev->clk_state != 0)
qup_i2c_pwr_mgmt(dev, 0);
- clk_unprepare(dev->clk);
- if (!dev->pdata->keep_ahb_clk_on)
- clk_unprepare(dev->pclk);
qup_i2c_free_gpios(dev);
return 0;
}
+static int i2c_qup_pm_resume_runtime(struct device *device)
+{
+ struct platform_device *pdev = to_platform_device(device);
+ struct qup_i2c_dev *dev = platform_get_drvdata(pdev);
+ dev_dbg(device, "pm_runtime: resuming...\n");
+ BUG_ON(qup_i2c_request_gpios(dev) != 0);
+ if (dev->clk_state == 0)
+ qup_i2c_pwr_mgmt(dev, 1);
+ dev->suspended = 0;
+ return 0;
+}
+
+static int qup_i2c_suspend(struct device *device)
+{
+ if (!pm_runtime_enabled(device) || !pm_runtime_suspended(device)) {
+ dev_dbg(device, "system suspend");
+ i2c_qup_pm_suspend_runtime(device);
+ }
+ return 0;
+}
+
static int qup_i2c_resume(struct device *device)
{
- struct platform_device *pdev = to_platform_device(device);
- struct qup_i2c_dev *dev = platform_get_drvdata(pdev);
- BUG_ON(qup_i2c_request_gpios(dev) != 0);
- clk_prepare(dev->clk);
- if (!dev->pdata->keep_ahb_clk_on)
- clk_prepare(dev->pclk);
- dev->suspended = 0;
+ if (!pm_runtime_enabled(device) || !pm_runtime_suspended(device)) {
+ dev_dbg(device, "system resume");
+ i2c_qup_pm_resume_runtime(device);
+ pm_runtime_mark_last_busy(device);
+ pm_request_autosuspend(device);
+ }
return 0;
}
#endif /* CONFIG_PM */
-#ifdef CONFIG_PM_RUNTIME
-static int i2c_qup_runtime_idle(struct device *dev)
-{
- dev_dbg(dev, "pm_runtime: idle...\n");
- return 0;
-}
-
-static int i2c_qup_runtime_suspend(struct device *dev)
-{
- dev_dbg(dev, "pm_runtime: suspending...\n");
- return 0;
-}
-
-static int i2c_qup_runtime_resume(struct device *dev)
-{
- dev_dbg(dev, "pm_runtime: resuming...\n");
- return 0;
-}
-#endif
-
static const struct dev_pm_ops i2c_qup_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(
qup_i2c_suspend,
qup_i2c_resume
)
SET_RUNTIME_PM_OPS(
- i2c_qup_runtime_suspend,
- i2c_qup_runtime_resume,
- i2c_qup_runtime_idle
+ i2c_qup_pm_suspend_runtime,
+ i2c_qup_pm_resume_runtime,
+ NULL
)
};
diff --git a/drivers/input/misc/lis3dh_acc.c b/drivers/input/misc/lis3dh_acc.c
index cc4ee9f..ea1b079 100644
--- a/drivers/input/misc/lis3dh_acc.c
+++ b/drivers/input/misc/lis3dh_acc.c
@@ -274,6 +274,7 @@
rc = PTR_ERR(lis3dh_acc_vreg[i].vreg);
pr_err("%s:regulator get failed rc=%d\n",
__func__, rc);
+ lis3dh_acc_vreg[i].vreg = NULL;
goto error_vdd;
}
@@ -287,6 +288,7 @@
pr_err("%s: set voltage failed rc=%d\n",
__func__, rc);
regulator_put(lis3dh_acc_vreg[i].vreg);
+ lis3dh_acc_vreg[i].vreg = NULL;
goto error_vdd;
}
}
@@ -302,6 +304,7 @@
lis3dh_acc_vreg[i].max_uV);
}
regulator_put(lis3dh_acc_vreg[i].vreg);
+ lis3dh_acc_vreg[i].vreg = NULL;
goto error_vdd;
}
}
@@ -312,12 +315,16 @@
error_vdd:
while (--i >= 0) {
- if (regulator_count_voltages(lis3dh_acc_vreg[i].vreg) > 0) {
- regulator_set_voltage(lis3dh_acc_vreg[i].vreg, 0,
- lis3dh_acc_vreg[i].max_uV);
+ if (!IS_ERR_OR_NULL(lis3dh_acc_vreg[i].vreg)) {
+ if (regulator_count_voltages(
+ lis3dh_acc_vreg[i].vreg) > 0) {
+ regulator_set_voltage(lis3dh_acc_vreg[i].vreg,
+ 0, lis3dh_acc_vreg[i].max_uV);
+ }
+ regulator_disable(lis3dh_acc_vreg[i].vreg);
+ regulator_put(lis3dh_acc_vreg[i].vreg);
+ lis3dh_acc_vreg[i].vreg = NULL;
}
- regulator_disable(lis3dh_acc_vreg[i].vreg);
- regulator_put(lis3dh_acc_vreg[i].vreg);
}
return rc;
}
diff --git a/drivers/input/misc/mpu3050.c b/drivers/input/misc/mpu3050.c
index db6f93c..6c64a57 100644
--- a/drivers/input/misc/mpu3050.c
+++ b/drivers/input/misc/mpu3050.c
@@ -184,6 +184,7 @@
rc = PTR_ERR(mpu_vreg[i].vreg);
pr_err("%s:regulator get failed rc=%d\n",
__func__, rc);
+ mpu_vreg[i].vreg = NULL;
goto error_vdd;
}
@@ -194,6 +195,7 @@
pr_err("%s:set_voltage failed rc=%d\n",
__func__, rc);
regulator_put(mpu_vreg[i].vreg);
+ mpu_vreg[i].vreg = NULL;
goto error_vdd;
}
}
@@ -210,6 +212,7 @@
0, mpu_vreg[i].max_uV);
}
regulator_put(mpu_vreg[i].vreg);
+ mpu_vreg[i].vreg = NULL;
goto error_vdd;
}
}
@@ -219,12 +222,16 @@
}
error_vdd:
while (--i >= 0) {
- if (regulator_count_voltages(mpu_vreg[i].vreg) > 0) {
- regulator_set_voltage(mpu_vreg[i].vreg, 0,
+ if (!IS_ERR_OR_NULL(mpu_vreg[i].vreg)) {
+ if (regulator_count_voltages(
+ mpu_vreg[i].vreg) > 0) {
+ regulator_set_voltage(mpu_vreg[i].vreg, 0,
mpu_vreg[i].max_uV);
+ }
+ regulator_disable(mpu_vreg[i].vreg);
+ regulator_put(mpu_vreg[i].vreg);
+ mpu_vreg[i].vreg = NULL;
}
- regulator_disable(mpu_vreg[i].vreg);
- regulator_put(mpu_vreg[i].vreg);
}
return rc;
}
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index b3bd8a0..bb505d8 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -1820,6 +1820,7 @@
kfree(data->object_table);
data->object_table = NULL;
data->cfg_version_idx = 0;
+ data->config_info = NULL;
data->update_cfg = false;
/* T38 object address might have changed, read it from
diff --git a/drivers/iommu/msm_iommu_sec.c b/drivers/iommu/msm_iommu_sec.c
index 72ec4a6..a6483b9 100644
--- a/drivers/iommu/msm_iommu_sec.c
+++ b/drivers/iommu/msm_iommu_sec.c
@@ -74,9 +74,9 @@
unsigned int spare;
} pinit;
unsigned int *buf;
- int psize[2] = {0};
+ int psize[2] = {0, 0};
unsigned int spare;
- int ret, ptbl_ret;
+ int ret, ptbl_ret = 0;
for_each_compatible_node(np, NULL, "qcom,msm-smmu-v2")
if (of_find_property(np, "qcom,iommu-secure-id", NULL))
@@ -134,7 +134,7 @@
unsigned int id;
unsigned int spare;
} cfg;
- int ret, scm_ret;
+ int ret, scm_ret = 0;
cfg.id = sec_id;
diff --git a/drivers/media/dvb/mpq/adapter/mpq_stream_buffer.c b/drivers/media/dvb/mpq/adapter/mpq_stream_buffer.c
index 4b0e7be..f779851 100644
--- a/drivers/media/dvb/mpq/adapter/mpq_stream_buffer.c
+++ b/drivers/media/dvb/mpq/adapter/mpq_stream_buffer.c
@@ -14,17 +14,47 @@
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/wait.h>
+#include <linux/uaccess.h>
#include "mpq_dvb_debug.h"
#include "mpq_stream_buffer.h"
-void mpq_streambuffer_init(
+
+
+int mpq_streambuffer_init(
struct mpq_streambuffer *sbuff,
- void *data_buff, size_t data_buff_len,
- void *packet_buff, size_t packet_buff_size)
+ enum mpq_streambuffer_mode mode,
+ struct mpq_streambuffer_buffer_desc *data_buffers,
+ u32 data_buff_num,
+ void *packet_buff,
+ size_t packet_buff_size)
{
- dvb_ringbuffer_init(&sbuff->raw_data, data_buff, data_buff_len);
+ if ((NULL == sbuff) || (NULL == data_buffers) || (NULL == packet_buff))
+ return -EINVAL;
+
+ if (data_buff_num > 1) {
+ if (mode != MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR)
+ return -EINVAL;
+ /* Linear buffer group */
+ dvb_ringbuffer_init(
+ &sbuff->raw_data,
+ data_buffers,
+ data_buff_num *
+ sizeof(struct mpq_streambuffer_buffer_desc));
+ } else if (data_buff_num == 1) {
+ if (mode != MPQ_STREAMBUFFER_BUFFER_MODE_RING)
+ return -EINVAL;
+ /* Single ring-buffer */
+ dvb_ringbuffer_init(&sbuff->raw_data,
+ data_buffers[0].base, data_buffers[0].size);
+ }
+ sbuff->mode = mode;
+ sbuff->buffers = data_buffers;
+ sbuff->pending_buffers_count = 0;
+ sbuff->buffers_num = data_buff_num;
dvb_ringbuffer_init(&sbuff->packet_data, packet_buff, packet_buff_size);
+
+ return 0;
}
EXPORT_SYMBOL(mpq_streambuffer_init);
@@ -87,34 +117,55 @@
int ret;
struct mpq_streambuffer_packet_header packet;
- if (dispose_data) {
- /* read-out the packet header first */
- ret = dvb_ringbuffer_pkt_read(
- &sbuff->packet_data,
- idx,
- 0,
- (u8 *)&packet,
- sizeof(struct mpq_streambuffer_packet_header));
+ if (NULL == sbuff)
+ return -EINVAL;
- if (ret != sizeof(struct mpq_streambuffer_packet_header))
- return -EINVAL;
+ /* read-out the packet header first */
+ ret = dvb_ringbuffer_pkt_read(&sbuff->packet_data, idx,
+ 0,
+ (u8 *)&packet,
+ sizeof(struct mpq_streambuffer_packet_header));
+ if (ret != sizeof(struct mpq_streambuffer_packet_header))
+ return -EINVAL;
+
+ if ((MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR == sbuff->mode) ||
+ (dispose_data)) {
/* Advance the read pointer in the raw-data buffer first */
- ret = mpq_streambuffer_data_read_dispose(
- sbuff,
- packet.raw_data_len);
+ ret = mpq_streambuffer_data_read_dispose(sbuff,
+ packet.raw_data_len);
if (ret != 0)
return ret;
}
+ /* Move read pointer to the next linear buffer for subsequent reads */
+ if ((MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR == sbuff->mode) &&
+ (packet.raw_data_len > 0)) {
+ struct mpq_streambuffer_buffer_desc *desc;
+
+ desc = (struct mpq_streambuffer_buffer_desc *)
+ &sbuff->raw_data.data[sbuff->raw_data.pread];
+
+ desc->write_ptr = 0;
+ desc->read_ptr = 0;
+
+ DVB_RINGBUFFER_SKIP(&sbuff->raw_data,
+ sizeof(struct mpq_streambuffer_buffer_desc));
+ sbuff->pending_buffers_count--;
+
+ wake_up_all(&sbuff->raw_data.queue);
+ }
+
/* Now clear the packet from the packet header */
dvb_ringbuffer_pkt_dispose(&sbuff->packet_data, idx);
+ if (sbuff->cb)
+ sbuff->cb(sbuff, sbuff->cb_user_data);
+
return 0;
}
EXPORT_SYMBOL(mpq_streambuffer_pkt_dispose);
-
int mpq_streambuffer_pkt_write(
struct mpq_streambuffer *sbuff,
struct mpq_streambuffer_packet_header *packet,
@@ -123,30 +174,48 @@
ssize_t idx;
size_t len;
- len =
- sizeof(struct mpq_streambuffer_packet_header) +
+ if ((NULL == sbuff) || (NULL == packet))
+ return -EINVAL;
+
+ MPQ_DVB_DBG_PRINT(
+ "%s: handle=%d, offset=%d, len=%d\n",
+ __func__,
+ packet->raw_data_handle,
+ packet->raw_data_offset,
+ packet->raw_data_len);
+
+ len = sizeof(struct mpq_streambuffer_packet_header) +
packet->user_data_len;
/* Make sure enough space available for packet header */
if (dvb_ringbuffer_free(&sbuff->packet_data) < len)
return -ENOSPC;
- /* Starting writting packet header */
+ /* Starting writing packet header */
idx = dvb_ringbuffer_pkt_start(&sbuff->packet_data, len);
/* Write non-user private data header */
- dvb_ringbuffer_write(
- &sbuff->packet_data,
- (u8 *)packet,
- sizeof(struct mpq_streambuffer_packet_header));
+ dvb_ringbuffer_write(&sbuff->packet_data,
+ (u8 *)packet,
+ sizeof(struct mpq_streambuffer_packet_header));
/* Write user's own private data header */
dvb_ringbuffer_write(&sbuff->packet_data,
- user_data,
- packet->user_data_len);
+ user_data,
+ packet->user_data_len);
dvb_ringbuffer_pkt_close(&sbuff->packet_data, idx);
+ /* Move write pointer to next linear buffer for subsequent writes */
+ if ((MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR == sbuff->mode) &&
+ (packet->raw_data_len > 0)) {
+ if (sbuff->pending_buffers_count == sbuff->buffers_num)
+ return -ENOSPC;
+ DVB_RINGBUFFER_PUSH(&sbuff->raw_data,
+ sizeof(struct mpq_streambuffer_buffer_desc));
+ sbuff->pending_buffers_count++;
+ }
+
wake_up_all(&sbuff->packet_data.queue);
return 0;
@@ -160,11 +229,52 @@
{
int res;
- if (unlikely(dvb_ringbuffer_free(&sbuff->raw_data) < len))
- return -ENOSPC;
+ if ((NULL == sbuff) || (NULL == buf))
+ return -EINVAL;
- res = dvb_ringbuffer_write(&sbuff->raw_data, buf, len);
- wake_up_all(&sbuff->raw_data.queue);
+ if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode) {
+ if (unlikely(dvb_ringbuffer_free(&sbuff->raw_data) < len))
+ return -ENOSPC;
+ /*
+ * Secure buffers are not permitted to be mapped into kernel
+ * memory, and so buffer base address may be NULL
+ */
+ if (NULL == sbuff->raw_data.data)
+ return -EPERM;
+ res = dvb_ringbuffer_write(&sbuff->raw_data, buf, len);
+ wake_up_all(&sbuff->raw_data.queue);
+ } else {
+ /* Linear buffer group */
+ struct mpq_streambuffer_buffer_desc *desc;
+
+ desc = (struct mpq_streambuffer_buffer_desc *)
+ &sbuff->raw_data.data[sbuff->raw_data.pwrite];
+
+ /*
+ * Secure buffers are not permitted to be mapped into kernel
+ * memory, and so buffer base address may be NULL
+ */
+ if (NULL == desc->base)
+ return -EPERM;
+
+ if ((sbuff->pending_buffers_count == sbuff->buffers_num) ||
+ ((desc->size - desc->write_ptr) < len)) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: No space available! %d pending buffers out of %d total buffers. write_ptr=%d, size=%d\n",
+ __func__,
+ sbuff->pending_buffers_count,
+ sbuff->buffers_num,
+ desc->write_ptr,
+ desc->size);
+ return -ENOSPC;
+ }
+ memcpy(desc->base + desc->write_ptr, buf, len);
+ desc->write_ptr += len;
+ MPQ_DVB_DBG_PRINT(
+ "%s: copied %d data bytes. handle=%d, write_ptr=%d\n",
+ __func__, len, desc->handle, desc->write_ptr);
+ res = len;
+ }
return res;
}
@@ -175,50 +285,244 @@
struct mpq_streambuffer *sbuff,
size_t len)
{
+ if (NULL == sbuff)
+ return -EINVAL;
+
if (unlikely(dvb_ringbuffer_free(&sbuff->raw_data) < len))
return -ENOSPC;
- sbuff->raw_data.pwrite =
- (sbuff->raw_data.pwrite+len) % sbuff->raw_data.size;
+ if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode) {
+ DVB_RINGBUFFER_PUSH(&sbuff->raw_data, len);
+ wake_up_all(&sbuff->raw_data.queue);
+ } else {
+ /* Linear buffer group */
+ struct mpq_streambuffer_buffer_desc *desc;
+ desc = (struct mpq_streambuffer_buffer_desc *)
+ &sbuff->raw_data.data[sbuff->raw_data.pwrite];
- wake_up_all(&sbuff->raw_data.queue);
+ if ((sbuff->pending_buffers_count == sbuff->buffers_num) ||
+ ((desc->size - desc->write_ptr) < len)) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: No space available!\n",
+ __func__);
+ return -ENOSPC;
+ }
+ desc->write_ptr += len;
+ }
return 0;
}
EXPORT_SYMBOL(mpq_streambuffer_data_write_deposit);
-size_t mpq_streambuffer_data_read(
+ssize_t mpq_streambuffer_data_read(
struct mpq_streambuffer *sbuff,
u8 *buf, size_t len)
{
- ssize_t actual_len;
+ ssize_t actual_len = 0;
- actual_len = dvb_ringbuffer_avail(&sbuff->raw_data);
- if (actual_len < len)
- len = actual_len;
+ if ((NULL == sbuff) || (NULL == buf))
+ return -EINVAL;
- if (len)
- dvb_ringbuffer_read(&sbuff->raw_data, buf, len);
+ if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode) {
+ /*
+ * Secure buffers are not permitted to be mapped into kernel
+ * memory, and so buffer base address may be NULL
+ */
+ if (NULL == sbuff->raw_data.data)
+ return -EPERM;
- wake_up_all(&sbuff->raw_data.queue);
+ actual_len = dvb_ringbuffer_avail(&sbuff->raw_data);
+ if (actual_len < len)
+ len = actual_len;
+ if (len)
+ dvb_ringbuffer_read(&sbuff->raw_data, buf, len);
+
+ wake_up_all(&sbuff->raw_data.queue);
+ } else {
+ /* Linear buffer group */
+ struct mpq_streambuffer_buffer_desc *desc;
+
+ desc = (struct mpq_streambuffer_buffer_desc *)
+ &sbuff->raw_data.data[sbuff->raw_data.pread];
+
+ /*
+ * Secure buffers are not permitted to be mapped into kernel
+ * memory, and so buffer base address may be NULL
+ */
+ if (NULL == desc->base)
+ return -EPERM;
+
+ actual_len = (desc->write_ptr - desc->read_ptr);
+ if (actual_len < len)
+ len = actual_len;
+ memcpy(buf, desc->base + desc->read_ptr, len);
+ desc->read_ptr += len;
+ }
return len;
}
EXPORT_SYMBOL(mpq_streambuffer_data_read);
+ssize_t mpq_streambuffer_data_read_user(
+ struct mpq_streambuffer *sbuff,
+ u8 __user *buf, size_t len)
+{
+ ssize_t actual_len = 0;
+
+ if ((NULL == sbuff) || (NULL == buf))
+ return -EINVAL;
+
+ if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode) {
+ /*
+ * Secure buffers are not permitted to be mapped into kernel
+ * memory, and so buffer base address may be NULL
+ */
+ if (NULL == sbuff->raw_data.data)
+ return -EPERM;
+
+ actual_len = dvb_ringbuffer_avail(&sbuff->raw_data);
+ if (actual_len < len)
+ len = actual_len;
+ if (len)
+ dvb_ringbuffer_read_user(&sbuff->raw_data, buf, len);
+ wake_up_all(&sbuff->raw_data.queue);
+ } else {
+ /* Linear buffer group */
+ struct mpq_streambuffer_buffer_desc *desc;
+
+ desc = (struct mpq_streambuffer_buffer_desc *)
+ &sbuff->raw_data.data[sbuff->raw_data.pread];
+
+ /*
+ * Secure buffers are not permitted to be mapped into kernel
+ * memory, and so buffer base address may be NULL
+ */
+ if (NULL == desc->base)
+ return -EPERM;
+
+ actual_len = (desc->write_ptr - desc->read_ptr);
+ if (actual_len < len)
+ len = actual_len;
+ if (copy_to_user(buf, desc->base + desc->read_ptr, len))
+ return -EFAULT;
+ desc->read_ptr += len;
+ }
+
+ return len;
+}
+EXPORT_SYMBOL(mpq_streambuffer_data_read_user);
+
+
int mpq_streambuffer_data_read_dispose(
struct mpq_streambuffer *sbuff,
size_t len)
{
- if (unlikely(dvb_ringbuffer_avail(&sbuff->raw_data) < len))
+ if (NULL == sbuff)
return -EINVAL;
- DVB_RINGBUFFER_SKIP(&sbuff->raw_data, len);
+ if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode) {
+ if (unlikely(dvb_ringbuffer_avail(&sbuff->raw_data) < len))
+ return -EINVAL;
- wake_up_all(&sbuff->raw_data.queue);
+ DVB_RINGBUFFER_SKIP(&sbuff->raw_data, len);
+ wake_up_all(&sbuff->raw_data.queue);
+ } else {
+ struct mpq_streambuffer_buffer_desc *desc;
+
+ desc = (struct mpq_streambuffer_buffer_desc *)
+ &sbuff->raw_data.data[sbuff->raw_data.pread];
+ if ((desc->read_ptr + len) > desc->size)
+ desc->read_ptr = desc->size;
+ else
+ desc->read_ptr += len;
+ }
+
return 0;
}
EXPORT_SYMBOL(mpq_streambuffer_data_read_dispose);
+
+int mpq_streambuffer_get_buffer_handle(
+ struct mpq_streambuffer *sbuff,
+ int read_buffer,
+ int *handle)
+{
+ struct mpq_streambuffer_buffer_desc *desc = NULL;
+
+ if ((NULL == sbuff) || (NULL == handle))
+ return -EINVAL;
+
+ if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode) {
+ *handle = sbuff->buffers[0].handle;
+ } else {
+ if (read_buffer)
+ desc = (struct mpq_streambuffer_buffer_desc *)
+ &sbuff->raw_data.data[sbuff->raw_data.pread];
+ else
+ desc = (struct mpq_streambuffer_buffer_desc *)
+ &sbuff->raw_data.data[sbuff->raw_data.pwrite];
+ *handle = desc->handle;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(mpq_streambuffer_get_buffer_handle);
+
+
+int mpq_streambuffer_register_pkt_dispose(
+ struct mpq_streambuffer *sbuff,
+ mpq_streambuffer_pkt_dispose_cb cb_func,
+ void *user_data)
+{
+ if ((NULL == sbuff) || (NULL == cb_func))
+ return -EINVAL;
+
+ sbuff->cb = cb_func;
+ sbuff->cb_user_data = user_data;
+
+ return 0;
+}
+EXPORT_SYMBOL(mpq_streambuffer_register_pkt_dispose);
+
+
+ssize_t mpq_streambuffer_data_free(
+ struct mpq_streambuffer *sbuff)
+{
+ struct mpq_streambuffer_buffer_desc *desc;
+
+ if (NULL == sbuff)
+ return -EINVAL;
+
+ if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode)
+ return dvb_ringbuffer_free(&sbuff->raw_data);
+
+ if (sbuff->pending_buffers_count == sbuff->buffers_num)
+ return 0;
+
+ desc = (struct mpq_streambuffer_buffer_desc *)
+ &sbuff->raw_data.data[sbuff->raw_data.pwrite];
+
+ return desc->size - desc->write_ptr;
+}
+EXPORT_SYMBOL(mpq_streambuffer_data_free);
+
+
+ssize_t mpq_streambuffer_data_avail(
+ struct mpq_streambuffer *sbuff)
+{
+ struct mpq_streambuffer_buffer_desc *desc;
+
+ if (NULL == sbuff)
+ return -EINVAL;
+
+ if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode)
+ return dvb_ringbuffer_avail(&sbuff->raw_data);
+
+ desc = (struct mpq_streambuffer_buffer_desc *)
+ &sbuff->raw_data.data[sbuff->raw_data.pread];
+
+ return desc->write_ptr - desc->read_ptr;
+}
+EXPORT_SYMBOL(mpq_streambuffer_data_avail);
+
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 e2ef6a0..2a60840 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
@@ -13,6 +13,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/vmalloc.h>
+#include <linux/file.h>
#include "mpq_dvb_debug.h"
#include "mpq_dmx_plugin_common.h"
@@ -983,6 +984,19 @@
goto init_failed_free_payload_buffer;
}
+ feed_data->buffer_desc.read_ptr = 0;
+ feed_data->buffer_desc.write_ptr = 0;
+ feed_data->buffer_desc.base = payload_buffer;
+ feed_data->buffer_desc.size = actual_buffer_size;
+ feed_data->buffer_desc.handle =
+ ion_share_dma_buf(
+ mpq_demux->ion_client,
+ feed_data->payload_buff_handle);
+ if (feed_data->buffer_desc.handle < 0) {
+ ret = -EFAULT;
+ goto init_failed_unmap_payload_buffer;
+ }
+
/* Register the new stream-buffer interface to MPQ adapter */
switch (feed->pes_type) {
case DMX_TS_PES_VIDEO0:
@@ -1011,7 +1025,7 @@
__func__,
feed->pes_type);
ret = -EINVAL;
- goto init_failed_unmap_payload_buffer;
+ goto init_failed_unshare_payload_buffer;
}
/* make sure not occupied already */
@@ -1025,30 +1039,36 @@
__func__,
feed_data->stream_interface);
ret = -EBUSY;
- goto init_failed_unmap_payload_buffer;
+ goto init_failed_unshare_payload_buffer;
}
feed_data->video_buffer =
&mpq_dmx_info.decoder_buffers[feed_data->stream_interface];
- mpq_streambuffer_init(
- feed_data->video_buffer,
- payload_buffer,
- actual_buffer_size,
- packet_buffer,
- VIDEO_META_DATA_BUFFER_SIZE);
+ ret = mpq_streambuffer_init(
+ feed_data->video_buffer,
+ MPQ_STREAMBUFFER_BUFFER_MODE_RING,
+ &feed_data->buffer_desc,
+ 1,
+ packet_buffer,
+ VIDEO_META_DATA_BUFFER_SIZE);
+ if (ret < 0) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: mpq_streambuffer_init failed, err = %d\n",
+ __func__, ret);
+ goto init_failed_unshare_payload_buffer;
+ }
- ret =
- mpq_adapter_register_stream_if(
- feed_data->stream_interface,
- feed_data->video_buffer);
+ ret = mpq_adapter_register_stream_if(
+ feed_data->stream_interface,
+ feed_data->video_buffer);
if (ret < 0) {
MPQ_DVB_ERR_PRINT(
"%s: mpq_adapter_register_stream_if failed, "
"err = %d\n",
__func__, ret);
- goto init_failed_unmap_payload_buffer;
+ goto init_failed_unshare_payload_buffer;
}
feed->buffer_size = actual_buffer_size;
@@ -1067,7 +1087,13 @@
sizeof(struct mpq_framing_prefix_size_masks));
feed_data->first_pattern_offset = 0;
feed_data->first_prefix_size = 0;
- feed_data->write_pts_dts = 0;
+ feed_data->saved_pts_dts_info.pts_exist = 0;
+ feed_data->saved_pts_dts_info.dts_exist = 0;
+ feed_data->new_pts_dts_info.pts_exist = 0;
+ feed_data->new_pts_dts_info.dts_exist = 0;
+ feed_data->saved_info_used = 1;
+ feed_data->new_info_exists = 0;
+ feed_data->first_pts_dts_copy = 1;
spin_lock(&mpq_demux->feed_lock);
feed->priv = (void *)feed_data;
@@ -1075,6 +1101,8 @@
return 0;
+init_failed_unshare_payload_buffer:
+ put_unused_fd(feed_data->buffer_desc.handle);
init_failed_unmap_payload_buffer:
ion_unmap_kernel(mpq_demux->ion_client,
feed_data->payload_buff_handle);
@@ -1119,6 +1147,8 @@
vfree(feed_data->video_buffer->packet_data.data);
+ put_unused_fd(feed_data->buffer_desc.handle);
+
ion_unmap_kernel(mpq_demux->ion_client,
feed_data->payload_buff_handle);
@@ -1338,6 +1368,83 @@
return 0;
}
+static inline void mpq_dmx_save_pts_dts(struct mpq_video_feed_info *feed_data)
+{
+ if (feed_data->new_info_exists) {
+ feed_data->saved_pts_dts_info.pts_exist =
+ feed_data->new_pts_dts_info.pts_exist;
+ feed_data->saved_pts_dts_info.pts =
+ feed_data->new_pts_dts_info.pts;
+ feed_data->saved_pts_dts_info.dts_exist =
+ feed_data->new_pts_dts_info.dts_exist;
+ feed_data->saved_pts_dts_info.dts =
+ feed_data->new_pts_dts_info.dts;
+
+ feed_data->new_info_exists = 0;
+ feed_data->saved_info_used = 0;
+ }
+}
+
+static inline void mpq_dmx_write_pts_dts(struct mpq_video_feed_info *feed_data,
+ struct dmx_pts_dts_info *info)
+{
+ if (!feed_data->saved_info_used) {
+ info->pts_exist = feed_data->saved_pts_dts_info.pts_exist;
+ info->pts = feed_data->saved_pts_dts_info.pts;
+ info->dts_exist = feed_data->saved_pts_dts_info.dts_exist;
+ info->dts = feed_data->saved_pts_dts_info.dts;
+
+ feed_data->saved_info_used = 1;
+ } else {
+ info->pts_exist = 0;
+ info->dts_exist = 0;
+ }
+}
+
+static inline void mpq_dmx_get_pts_dts(struct mpq_video_feed_info *feed_data,
+ struct pes_packet_header *pes_header)
+{
+ struct dmx_pts_dts_info *info = &(feed_data->new_pts_dts_info);
+
+ /* Get PTS/DTS information from PES header */
+
+ if ((pes_header->pts_dts_flag == 2) ||
+ (pes_header->pts_dts_flag == 3)) {
+ info->pts_exist = 1;
+
+ info->pts =
+ ((u64)pes_header->pts_1 << 30) |
+ ((u64)pes_header->pts_2 << 22) |
+ ((u64)pes_header->pts_3 << 15) |
+ ((u64)pes_header->pts_4 << 7) |
+ (u64)pes_header->pts_5;
+ } else {
+ info->pts_exist = 0;
+ info->pts = 0;
+ }
+
+ if (pes_header->pts_dts_flag == 3) {
+ info->dts_exist = 1;
+
+ info->dts =
+ ((u64)pes_header->dts_1 << 30) |
+ ((u64)pes_header->dts_2 << 22) |
+ ((u64)pes_header->dts_3 << 15) |
+ ((u64)pes_header->dts_4 << 7) |
+ (u64)pes_header->dts_5;
+ } else {
+ info->dts_exist = 0;
+ info->dts = 0;
+ }
+
+ feed_data->new_info_exists = 1;
+
+ if (feed_data->first_pts_dts_copy) {
+ mpq_dmx_save_pts_dts(feed_data);
+ feed_data->first_pts_dts_copy = 0;
+ }
+}
+
static inline int mpq_dmx_parse_remaining_pes_header(
struct dvb_demux_feed *feed,
struct mpq_video_feed_info *feed_data,
@@ -1381,7 +1488,6 @@
/* else - we have the PTS */
*bytes_avail -= copy_len;
*ts_payload_offset += copy_len;
- feed_data->write_pts_dts = 1;
}
/* Did we capture the DTS value (if exist)? */
@@ -1412,7 +1518,6 @@
/* else - we have the DTS */
*bytes_avail -= copy_len;
*ts_payload_offset += copy_len;
- feed_data->write_pts_dts = 1;
}
/* Any more header bytes?! */
@@ -1421,6 +1526,9 @@
return -EINVAL;
}
+ /* get PTS/DTS information from PES header to be written later */
+ mpq_dmx_get_pts_dts(feed_data, pes_header);
+
/* Got PES header, process payload */
*bytes_avail -= feed_data->pes_header_left_bytes;
*ts_payload_offset += feed_data->pes_header_left_bytes;
@@ -1429,53 +1537,6 @@
return 0;
}
-static inline void mpq_dmx_get_pts_dts(struct mpq_video_feed_info *feed_data,
- struct pes_packet_header *pes_header,
- struct mpq_adapter_video_meta_data *meta_data,
- enum dmx_packet_type packet_type)
-{
- struct dmx_pts_dts_info *info;
-
- if (packet_type == DMX_PES_PACKET)
- info = &(meta_data->info.pes.pts_dts_info);
- else
- info = &(meta_data->info.framing.pts_dts_info);
-
- if (feed_data->write_pts_dts) {
- if ((pes_header->pts_dts_flag == 2) ||
- (pes_header->pts_dts_flag == 3)) {
- info->pts_exist = 1;
-
- info->pts =
- ((u64)pes_header->pts_1 << 30) |
- ((u64)pes_header->pts_2 << 22) |
- ((u64)pes_header->pts_3 << 15) |
- ((u64)pes_header->pts_4 << 7) |
- (u64)pes_header->pts_5;
- } else {
- info->pts_exist = 0;
- info->pts = 0;
- }
-
- if (pes_header->pts_dts_flag == 3) {
- info->dts_exist = 1;
-
- info->dts =
- ((u64)pes_header->dts_1 << 30) |
- ((u64)pes_header->dts_2 << 22) |
- ((u64)pes_header->dts_3 << 15) |
- ((u64)pes_header->dts_4 << 7) |
- (u64)pes_header->dts_5;
- } else {
- info->dts_exist = 0;
- info->dts = 0;
- }
- } else {
- info->pts_exist = 0;
- info->dts_exist = 0;
- }
-}
-
static int mpq_dmx_process_video_packet_framing(
struct dvb_demux_feed *feed,
const u8 *buf)
@@ -1550,7 +1611,6 @@
feed_data->pes_header_offset = 0;
feed_data->pes_header_left_bytes =
PES_MANDATORY_FIELDS_LEN;
- feed_data->write_pts_dts = 0;
} else {
feed->pusi_seen = 1;
}
@@ -1692,6 +1752,8 @@
feed->peslen += bytes_avail;
meta_data.packet_type = DMX_FRAMING_INFO_PACKET;
+ packet.raw_data_handle = feed_data->buffer_desc.handle;
+ packet.raw_data_offset = 0;
packet.user_data_len =
sizeof(struct mpq_adapter_video_meta_data);
@@ -1701,10 +1763,10 @@
feed->indexing_params.standard,
feed_data->last_framing_match_type);
if (is_video_frame == 1) {
- mpq_dmx_get_pts_dts(feed_data,
- pes_header,
- &meta_data,
- DMX_FRAMING_INFO_PACKET);
+ mpq_dmx_write_pts_dts(feed_data,
+ &(meta_data.info.framing.
+ pts_dts_info));
+ mpq_dmx_save_pts_dts(feed_data);
} else {
meta_data.info.framing.
pts_dts_info.pts_exist = 0;
@@ -1717,8 +1779,6 @@
*/
meta_data.info.framing.pattern_type =
feed_data->last_framing_match_type;
- packet.raw_data_addr =
- feed_data->last_framing_match_address;
pattern_addr = feed_data->pes_payload_address +
framing_res.info[i].offset -
@@ -1742,10 +1802,8 @@
feed_data->first_pattern_offset;
}
- MPQ_DVB_DBG_PRINT("Writing Packet: "
- "addr = 0x%X, len = %d, type = %d, "
- "isPts = %d, isDts = %d\n",
- packet.raw_data_addr,
+ MPQ_DVB_DBG_PRINT(
+ "Writing Packet: len = %d, type = %d, isPts = %d, isDts = %d\n",
packet.raw_data_len,
meta_data.info.framing.pattern_type,
meta_data.info.framing.
@@ -1754,16 +1812,11 @@
pts_dts_info.dts_exist);
if (mpq_streambuffer_pkt_write(stream_buffer,
- &packet,
- (u8 *)&meta_data) < 0) {
- MPQ_DVB_ERR_PRINT(
- "%s: "
- "Couldn't write packet. "
- "Should never happen\n",
+ &packet,
+ (u8 *)&meta_data) < 0) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: Couldn't write packet. Should never happen\n",
__func__);
- } else {
- if (is_video_frame == 1)
- feed_data->write_pts_dts = 0;
}
}
@@ -1855,18 +1908,17 @@
*/
if (0 == feed_data->pes_header_left_bytes) {
- packet.raw_data_addr =
- feed_data->pes_payload_address;
-
packet.raw_data_len = feed->peslen;
-
+ packet.raw_data_handle =
+ feed_data->buffer_desc.handle;
+ packet.raw_data_offset = 0;
packet.user_data_len =
sizeof(struct
mpq_adapter_video_meta_data);
- mpq_dmx_get_pts_dts(feed_data, pes_header,
- &meta_data,
- DMX_PES_PACKET);
+ mpq_dmx_write_pts_dts(feed_data,
+ &(meta_data.info.pes.pts_dts_info));
+ mpq_dmx_save_pts_dts(feed_data);
meta_data.packet_type = DMX_PES_PACKET;
@@ -1879,8 +1931,6 @@
"Couldn't write packet. "
"Should never happen\n",
__func__);
- else
- feed_data->write_pts_dts = 0;
} else {
MPQ_DVB_ERR_PRINT(
"%s: received PUSI"
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 69305b6..f7af1ef 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h
@@ -275,6 +275,7 @@
* @plugin_data: Underlying plugin's own private data.
* @video_buffer: Holds the streamer buffer shared with
* the decoder for feeds having the data going to the decoder.
+ * @buffer_desc: Holds decoder buffer(s) information used for stream buffer.
* @pes_header: Used for feeds that output data to decoder,
* holds PES header of current processed PES.
* @pes_header_left_bytes: Used for feeds that output data to decoder,
@@ -308,14 +309,18 @@
* to the stream buffer.
* @first_prefix_size: used to save the prefix size used to find the first
* pattern written to the stream buffer.
- * @write_pts_dts: Flag used to decide if to write PTS/DTS information
- * (if it is available in the PES header) in the meta-data passed
- * to the video decoder. PTS/DTS information is written in the first
- * packet after it is available.
+ * @saved_pts_dts_info: used to save PTS/DTS information until it is written.
+ * @new_pts_dts_info: used to store PTS/DTS information from current PES header.
+ * @saved_info_used: indicates if saved PTS/DTS information was used.
+ * @new_info_exists: indicates if new PTS/DTS information exists in
+ * new_pts_dts_info that should be saved to saved_pts_dts_info.
+ * @first_pts_dts_copy: a flag used to indicate if PTS/DTS information needs
+ * to be copied from the currently parsed PES header to the saved_pts_dts_info.
*/
struct mpq_video_feed_info {
void *plugin_data;
struct mpq_streambuffer *video_buffer;
+ struct mpq_streambuffer_buffer_desc buffer_desc;
struct pes_packet_header pes_header;
u32 pes_header_left_bytes;
u32 pes_header_offset;
@@ -331,7 +336,11 @@
struct mpq_framing_prefix_size_masks prefix_size;
u32 first_pattern_offset;
u32 first_prefix_size;
- int write_pts_dts;
+ struct dmx_pts_dts_info saved_pts_dts_info;
+ struct dmx_pts_dts_info new_pts_dts_info;
+ int saved_info_used;
+ int new_info_exists;
+ int first_pts_dts_copy;
};
/**
diff --git a/drivers/media/dvb/mpq/include/mpq_stream_buffer.h b/drivers/media/dvb/mpq/include/mpq_stream_buffer.h
index 4ea4222..9476c73 100644
--- a/drivers/media/dvb/mpq/include/mpq_stream_buffer.h
+++ b/drivers/media/dvb/mpq/include/mpq_stream_buffer.h
@@ -19,7 +19,7 @@
/**
* DOC: MPQ Stream Buffer
*
- * A stream buffer implmenetation used to transfer data between two units
+ * A stream buffer implementation is used to transfer data between two units
* such as demux and decoders. The implementation relies on dvb_ringbuffer
* implementation. Refer to dvb_ringbuffer.h for details.
*
@@ -28,8 +28,19 @@
* meta-data (information from PES header for example).
*
* The meta-data uses dvb_ringbuffer packet interface. Each meta-data
- * packet hold the address and size of raw-data described by the
- * meta-data packet, in addition to user's own parameters if any required.
+ * packet points to the data buffer, and includes the offset to the data in the
+ * buffer, the size of raw-data described by the meta-data packet, and also the
+ * size of user's own parameters if any required.
+ *
+ * Data can be managed in two ways: ring-buffer & linear buffers, as specified
+ * in initialization when calling the mpq_streambuffer_init function.
+ * For managing data as a ring buffer exactly 1 data buffer descriptor must be
+ * specified in initialization. For this mode, dvb_ringbuffer is used "as-is".
+ * For managing data in several linear buffers, an array of buffer descriptors
+ * must be passed.
+ * For both modes, data descriptor(s) must be remain valid throughout the life
+ * span of the mpq_streambuffer object.
+ * Apart from initialization API remains the same for both modes.
*
* Contrary to dvb_ringbuffer implementation, this API makes sure there's
* enough data to read/write when making read/write operations.
@@ -44,18 +55,22 @@
*
* Typical call flow from producer:
*
- * - Start writting the raw-data of new packet, the following call is
+ * - Start writing the raw-data of new packet, the following call is
* repeated until end of data of the specific packet
*
- * mpq_streambuffer_data_write(...)
+ * mpq_streambuffer_data_write(...)
*
* - Now write a new packet describing the new available raw-data
- * mpq_streambuffer_pkt_write(...)
+ * mpq_streambuffer_pkt_write(...)
+ *
+ * For linear buffer mode, writing a new packet with data size > 0, causes the
+ * current buffer to be marked as pending for reading, and triggers moving to
+ * the next available buffer, that shall now be the current write buffer.
*
* Typical call flow from consumer:
*
* - Poll for next available packet:
- * mpq_streambuffer_pkt_next(&streambuff,-1)
+ * mpq_streambuffer_pkt_next(&streambuff,-1,&len)
*
* In different approach, consumer can wait on event for new data and then
* call mpq_streambuffer_pkt_next, waiting for data can be done as follows:
@@ -77,58 +92,126 @@
* data buffer, the amount of raw-data is provided part of the
* packet's information. User should then call mpq_streambuffer_pkt_dispose
* with dispose_data set to 0 as the raw-data was already disposed.
+ * Note that secure buffer cannot be accessed directly and an error will
+ * occur.
*
* 2. Access the data directly using the raw-data address. The address
* of the raw data is provided part of the packet's information. User
* then should call mpq_streambuffer_pkt_dispose with dispose_data set
* to 1 to dispose the packet along with it's raw-data.
+ *
+ * - Disposal of packets:
+ * mpq_streambuffer_pkt_dispose(...)
+ *
+ * For linear buffer mode, disposing of a packet with data size > 0, causes
+ * the current buffer to be marked as free for writing, and triggers moving to
+ * the next available buffer, that shall now be the current read buffer.
+
+ *
*/
+struct mpq_streambuffer;
+
+typedef void (*mpq_streambuffer_pkt_dispose_cb) (
+ struct mpq_streambuffer *sbuff,
+ void *user_data);
+
+enum mpq_streambuffer_mode {
+ MPQ_STREAMBUFFER_BUFFER_MODE_RING,
+ MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR
+};
+
/**
* struct mpq_streambuffer - mpq stream buffer representation
*
- * @raw_data: The buffer used to hold the raw-data
+ * @raw_data: The buffer used to hold raw-data, or linear buffer descriptors
* @packet_data: The buffer user to hold the meta-data
+ * @buffers: array of buffer descriptor(s) holding buffer initial & dynamic
+ * buffer information
+ * @mode: mpq_streambuffer buffer management work mode - Ring-buffer or Linear
+ * buffers
+ * @buffers_num: number of data buffers to manage
+ * @pending_buffers_count: for linear buffer management, counts the number of
+ * buffer that has been
*/
struct mpq_streambuffer {
struct dvb_ringbuffer raw_data;
struct dvb_ringbuffer packet_data;
+ struct mpq_streambuffer_buffer_desc *buffers;
+ enum mpq_streambuffer_mode mode;
+ u32 buffers_num;
+ u32 pending_buffers_count;
+ mpq_streambuffer_pkt_dispose_cb cb;
+ void *cb_user_data;
+};
+
+/**
+ * mpq_streambuffer_linear_desc
+ * @handle: ION handle's file descriptor of buffer
+ * @base: kernel mapped address to start of buffer.
+ * Can be NULL for secured buffers
+ * @size: size of buffer
+ * @read_ptr: initial read pointer value (should normally be 0)
+ * @write_ptr: initial write pointer value (should normally be 0)
+ */
+struct mpq_streambuffer_buffer_desc {
+ int handle;
+ void *base;
+ u32 size;
+ u32 read_ptr;
+ u32 write_ptr;
};
/**
* struct mpq_streambuffer_packet_header - packet header saved in packet buffer
* @user_data_len: length of private user (meta) data
- * @raw_data_addr: raw-data address in the raw-buffer described by the packet
+ * @raw_data_handle: ION handle's file descriptor of raw-data buffer
+ * @raw_data_offset: offset of raw-data from start of buffer (0 for linear)
* @raw_data_len: size of raw-data in the raw-data buffer (can be 0)
*
* The packet structure that is saved in each packet-buffer:
* user_data_len
- * raw_data_addr
+ * raw_data_handle
+ * raw_data_offset
* raw_data_len
* private user-data bytes
*/
struct mpq_streambuffer_packet_header {
u32 user_data_len;
- u32 raw_data_addr;
- u32 raw_data_len;
+ int raw_data_handle;
+ u32 raw_data_offset;
+ u32 raw_data_len;
} __packed;
/**
* mpq_streambuffer_init - Initialize a new stream buffer
*
* @sbuff: The buffer to initialize
- * @data_buff: The buffer holding raw-data
- * @data_buff_len: Size of raw-data buffer
+ * @data_buffers: array of data buffer descriptor(s).
+ * Data descriptor(s) must be remain valid throughout the life
+ * span of the mpq_streambuffer object
+ * @data_buff_num: number of data buffer in array
* @packet_buff: The buffer holding meta-data
* @packet_buff_size: Size of meta-data buffer
+ *
+ * Return Error status, -EINVAL if any of the arguments are invalid
+ *
+ * Note:
+ * for data_buff_num > 1, mpq_streambuffer object manages these buffers as a
+ * separated set of linear buffers. A linear buffer cannot wrap-around and one
+ * can only write as many data bytes as the buffer's size. Data will not be
+ * written to the next free buffer.
*/
-void mpq_streambuffer_init(
+int mpq_streambuffer_init(
struct mpq_streambuffer *sbuff,
- void *data_buff, size_t data_buff_len,
- void *packet_buff, size_t packet_buff_size);
+ enum mpq_streambuffer_mode mode,
+ struct mpq_streambuffer_buffer_desc *data_buffers,
+ u32 data_buff_num,
+ void *packet_buff,
+ size_t packet_buff_size);
/**
- * mpq_streambuffer_packet_next - Returns index of next avaialble packet.
+ * mpq_streambuffer_packet_next - Returns index of next available packet.
*
* @sbuff: The stream buffer
* @idx: Previous packet index or -1 to return index of the the first
@@ -234,19 +317,29 @@
* @buf: The buffer to read the raw-data data to
* @len: The length of the buffer that will hold the raw-data
*
- * Return The actual number of bytes read
+ * Return The actual number of bytes read or error code
*
- * This fucntion copies the data from the ring-buffer to the
+ * This function copies the data from the ring-buffer to the
* provided buf parameter. The user can save the extra copy by accessing
* the data pointer directly and reading from it, then update the
* read pointer by the amount of data that was read using
* mpq_streambuffer_data_read_dispose
*/
-size_t mpq_streambuffer_data_read(
+ssize_t mpq_streambuffer_data_read(
struct mpq_streambuffer *sbuff,
u8 *buf, size_t len);
/**
+ * mpq_streambuffer_data_read_user
+ *
+ * Same as mpq_streambuffer_data_read except data can be copied to user-space
+ * buffer.
+ */
+ssize_t mpq_streambuffer_data_read_user(
+ struct mpq_streambuffer *sbuff,
+ u8 __user *buf, size_t len);
+
+/**
* mpq_streambuffer_data_read_dispose - Advances the raw-buffer read pointer.
* Assumes the raw-data was read by the user directly.
*
@@ -256,12 +349,69 @@
* Return error status, -EINVAL if buffer there's no enough data to
* be disposed
*
- * The user can instead dipose a packet along with the data in the
+ * The user can instead dispose a packet along with the data in the
* raw-data buffer using mpq_streambuffer_pkt_dispose.
*/
int mpq_streambuffer_data_read_dispose(
struct mpq_streambuffer *sbuff,
size_t len);
+/**
+ * mpq_streambuffer_get_buffer_handle - Returns the current linear buffer
+ * ION handle.
+ * @sbuff: The stream buffer
+ * @read_buffer: specifies if a read buffer handle is requested (when set),
+ * or a write buffer handle is requested.
+ * For linear buffer mode read & write buffers may be different
+ * buffers. For ring buffer mode, the same (single) buffer handle
+ * is returned.
+ * buffer handle
+ * @handle: returned handle
+ *
+ * Return error status
+ * -EINVAL is arguments are invalid.
+ * -EPERM if stream buffer specified was not initialized with linear support.
+ */
+int mpq_streambuffer_get_buffer_handle(
+ struct mpq_streambuffer *sbuff,
+ int read_buffer,
+ int *handle);
+
+/**
+ * mpq_streambuffer_data_free - Returns number of free bytes in data buffer.
+ * @sbuff: The stream buffer object
+ *
+ * Note: for linear buffer management this return number of free bytes in the
+ * current write buffer only.
+ */
+ssize_t mpq_streambuffer_data_free(
+ struct mpq_streambuffer *sbuff);
+
+/**
+ * mpq_streambuffer_data_avail - Returns number of bytes in data buffer that
+ * can be read.
+ * @sbuff: The stream buffer object
+ *
+ * Note: for linear buffer management this return number of data bytes in the
+ * current read buffer only.
+ */
+ssize_t mpq_streambuffer_data_avail(
+ struct mpq_streambuffer *sbuff);
+
+/**
+ * mpq_streambuffer_register_pkt_dispose - Registers a callback to notify on
+ * packet disposal events.
+ * can be read.
+ * @sbuff: The stream buffer object
+ * @cb_func: user callback function
+ * @user_data: user data to be passed to callback function.
+ *
+ * Returns error status
+ * -EINVAL if arguments are invalid
+ */
+int mpq_streambuffer_register_pkt_dispose(
+ struct mpq_streambuffer *sbuff,
+ mpq_streambuffer_pkt_dispose_cb cb_func,
+ void *user_data);
diff --git a/drivers/media/video/msm/server/msm_cam_server.c b/drivers/media/video/msm/server/msm_cam_server.c
index f61b74f..af31748 100644
--- a/drivers/media/video/msm/server/msm_cam_server.c
+++ b/drivers/media/video/msm/server/msm_cam_server.c
@@ -1445,9 +1445,10 @@
/*so that it isn't closed again*/
pmctl->mctl_release = NULL;
}
- msm_cam_server_send_error_evt(pmctl,
- V4L2_EVENT_PRIVATE_START +
- MSM_CAM_APP_NOTIFY_ERROR_EVENT);
+ if (pmctl)
+ msm_cam_server_send_error_evt(pmctl,
+ V4L2_EVENT_PRIVATE_START +
+ MSM_CAM_APP_NOTIFY_ERROR_EVENT);
}
}
sub.type = V4L2_EVENT_ALL;
@@ -1753,7 +1754,7 @@
case NOTIFY_VFE_MSG_COMP_STATS:
case NOTIFY_VFE_BUF_EVT:
p_mctl = msm_cam_server_get_mctl(mctl_handle);
- if (p_mctl->isp_notify && p_mctl->vfe_sdev)
+ if (p_mctl && p_mctl->isp_notify && p_mctl->vfe_sdev)
rc = p_mctl->isp_notify(p_mctl,
p_mctl->vfe_sdev, notification, arg);
break;
@@ -1772,18 +1773,20 @@
break;
case NOTIFY_AXI_RDI_SOF_COUNT:
p_mctl = msm_cam_server_get_mctl(mctl_handle);
- if (p_mctl->axi_sdev)
+ if (p_mctl && p_mctl->axi_sdev)
rc = v4l2_subdev_call(p_mctl->axi_sdev, core, ioctl,
VIDIOC_MSM_AXI_RDI_COUNT_UPDATE, arg);
break;
case NOTIFY_PCLK_CHANGE:
p_mctl = v4l2_get_subdev_hostdata(sd);
- if (p_mctl->axi_sdev)
- rc = v4l2_subdev_call(p_mctl->axi_sdev, video,
- s_crystal_freq, *(uint32_t *)arg, 0);
- else
- rc = v4l2_subdev_call(p_mctl->vfe_sdev, video,
- s_crystal_freq, *(uint32_t *)arg, 0);
+ if (p_mctl) {
+ if (p_mctl->axi_sdev)
+ rc = v4l2_subdev_call(p_mctl->axi_sdev, video,
+ s_crystal_freq, *(uint32_t *)arg, 0);
+ else
+ rc = v4l2_subdev_call(p_mctl->vfe_sdev, video,
+ s_crystal_freq, *(uint32_t *)arg, 0);
+ }
break;
case NOTIFY_GESTURE_EVT:
rc = v4l2_subdev_call(g_server_dev.gesture_device,
@@ -1795,8 +1798,10 @@
break;
case NOTIFY_VFE_CAMIF_ERROR: {
p_mctl = msm_cam_server_get_mctl(mctl_handle);
- msm_cam_server_send_error_evt(p_mctl, V4L2_EVENT_PRIVATE_START
- + MSM_CAM_APP_NOTIFY_ERROR_EVENT);
+ if (p_mctl)
+ msm_cam_server_send_error_evt(p_mctl,
+ V4L2_EVENT_PRIVATE_START +
+ MSM_CAM_APP_NOTIFY_ERROR_EVENT);
break;
}
default:
diff --git a/drivers/media/video/msm_vidc/msm_smem.c b/drivers/media/video/msm_vidc/msm_smem.c
index e1b73ef..eae18c4 100644
--- a/drivers/media/video/msm_vidc/msm_smem.c
+++ b/drivers/media/video/msm_vidc/msm_smem.c
@@ -134,6 +134,9 @@
}
heap_mask = ION_HEAP(ION_CP_MM_HEAP_ID);
+ if (!(flags & SMEM_SECURE))
+ heap_mask |= ION_HEAP(ION_IOMMU_HEAP_ID);
+
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 38e8de1..0979e99 100644
--- a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
@@ -92,11 +92,10 @@
.src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
.dst = MSM_BUS_SLAVE_OCMEM,
.ab = 3760000000U,
- .ib = 3910400000U,
+ .ib = 4888000000ULL,
},
};
-
static struct msm_bus_vectors dec_ocmem_init_vectors[] = {
{
.src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
@@ -147,7 +146,7 @@
.src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
.dst = MSM_BUS_SLAVE_OCMEM,
.ab = 2767360000U,
- .ib = 3113280000U,
+ .ib = 4981248000ULL,
},
};
@@ -156,7 +155,7 @@
.src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
.dst = MSM_BUS_SLAVE_OCMEM,
.ab = 3459200000U,
- .ib = 3459200000U,
+ .ib = 6226560000ULL,
},
};
@@ -295,7 +294,7 @@
.src = MSM_BUS_MASTER_VIDEO_P0,
.dst = MSM_BUS_SLAVE_EBI_CH0,
.ab = 161200000,
- .ib = 2659800000U,
+ .ib = 6400000000ULL,
},
};
@@ -358,7 +357,7 @@
.src = MSM_BUS_MASTER_VIDEO_P0,
.dst = MSM_BUS_SLAVE_EBI_CH0,
.ab = 2020000000U,
- .ib = 3636000000U,
+ .ib = 6400000000ULL,
},
};
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
index 711b3007..440c704 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.c
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -22,11 +22,15 @@
#define MSM_VDEC_DVC_NAME "msm_vdec_8974"
#define DEFAULT_HEIGHT 720
#define DEFAULT_WIDTH 1280
-#define MAX_SUPPORTED_WIDTH 1920
-#define MAX_SUPPORTED_HEIGHT 1088
+#define MAX_SUPPORTED_WIDTH 3820
+#define MAX_SUPPORTED_HEIGHT 2160
#define MIN_NUM_OUTPUT_BUFFERS 4
#define MAX_NUM_OUTPUT_BUFFERS 6
+enum msm_vdec_ctrl_cluster {
+ MSM_VDEC_CTRL_CLUSTER_MAX = 1,
+};
+
static const char *const mpeg_video_vidc_divx_format[] = {
"DIVX Format 3",
"DIVX Format 4",
@@ -68,7 +72,7 @@
"Extradata aspect ratio",
};
-static const struct msm_vidc_ctrl msm_vdec_ctrls[] = {
+static struct msm_vidc_ctrl msm_vdec_ctrls[] = {
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT,
.name = "NAL Format",
@@ -85,6 +89,7 @@
),
.qmenu = mpeg_video_stream_format,
.step = 0,
+ .cluster = 0,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER,
@@ -99,6 +104,7 @@
),
.qmenu = mpeg_video_output_order,
.step = 0,
+ .cluster = 0,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_PICTURE_TYPE,
@@ -110,6 +116,7 @@
.step = 1,
.menu_skip_mask = 0,
.qmenu = NULL,
+ .cluster = 0,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_KEEP_ASPECT_RATIO,
@@ -121,6 +128,7 @@
.step = 1,
.menu_skip_mask = 0,
.qmenu = NULL,
+ .cluster = 0,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_POST_LOOP_DEBLOCKER_MODE,
@@ -132,6 +140,7 @@
.step = 1,
.menu_skip_mask = 0,
.qmenu = NULL,
+ .cluster = 0,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_DIVX_FORMAT,
@@ -147,6 +156,7 @@
),
.qmenu = mpeg_video_vidc_divx_format,
.step = 0,
+ .cluster = 0,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_MB_ERROR_MAP_REPORTING,
@@ -158,6 +168,7 @@
.step = 1,
.menu_skip_mask = 0,
.qmenu = NULL,
+ .cluster = 0,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER,
@@ -169,6 +180,7 @@
.step = 1,
.menu_skip_mask = 0,
.qmenu = NULL,
+ .cluster = 0,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE,
@@ -188,6 +200,7 @@
.step = 0,
.menu_skip_mask = 0,
.qmenu = NULL,
+ .cluster = 0,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA,
@@ -1060,10 +1073,11 @@
inst->prop.height = DEFAULT_HEIGHT;
inst->prop.width = DEFAULT_WIDTH;
inst->prop.fps = 30;
+ inst->prop.prev_time_stamp = 0;
return rc;
}
-static int msm_vdec_op_s_ctrl(struct v4l2_ctrl *ctrl)
+static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
{
int rc = 0;
struct v4l2_control control;
@@ -1074,62 +1088,59 @@
enum hal_property property_id = 0;
u32 property_val = 0;
void *pdata;
- struct msm_vidc_inst *inst = container_of(ctrl->handler,
- struct msm_vidc_inst, ctrl_handler);
- control.id = ctrl->id;
- control.value = ctrl->val;
- switch (control.id) {
+
+ switch (ctrl->id) {
case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT:
property_id =
HAL_PARAM_NAL_STREAM_FORMAT_SELECT;
stream_format.nal_stream_format_supported =
- (0x00000001 << control.value);
+ (0x00000001 << ctrl->val);
pdata = &stream_format;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER:
property_id = HAL_PARAM_VDEC_OUTPUT_ORDER;
- property_val = control.value;
+ property_val = ctrl->val;
pdata = &property_val;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_PICTURE_TYPE:
property_id =
HAL_PARAM_VDEC_PICTURE_TYPE_DECODE;
- enable_picture.picture_type = control.value;
+ enable_picture.picture_type = ctrl->val;
pdata = &enable_picture;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_KEEP_ASPECT_RATIO:
property_id =
HAL_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO;
- hal_property.enable = control.value;
+ hal_property.enable = ctrl->val;
pdata = &hal_property;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_POST_LOOP_DEBLOCKER_MODE:
property_id =
HAL_CONFIG_VDEC_POST_LOOP_DEBLOCKER;
- hal_property.enable = control.value;
+ hal_property.enable = ctrl->val;
pdata = &hal_property;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_DIVX_FORMAT:
property_id = HAL_PARAM_DIVX_FORMAT;
- property_val = control.value;
+ property_val = ctrl->val;
pdata = &property_val;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_MB_ERROR_MAP_REPORTING:
property_id =
HAL_CONFIG_VDEC_MB_ERROR_MAP_REPORTING;
- hal_property.enable = control.value;
+ hal_property.enable = ctrl->val;
pdata = &hal_property;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER:
property_id =
HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER;
- hal_property.enable = control.value;
+ hal_property.enable = ctrl->val;
pdata = &hal_property;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE:
property_id =
HAL_PARAM_VDEC_SYNC_FRAME_DECODE;
- hal_property.enable = control.value;
+ hal_property.enable = ctrl->val;
pdata = &hal_property;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_SECURE:
@@ -1140,7 +1151,7 @@
{
struct hal_extradata_enable extra;
property_id = HAL_PARAM_INDEX_EXTRADATA;
- extra.index = msm_comm_get_hal_extradata_index(control.value);
+ extra.index = msm_comm_get_hal_extradata_index(ctrl->val);
extra.enable = 1;
pdata = &extra;
break;
@@ -1148,13 +1159,8 @@
default:
break;
}
+
if (property_id) {
- rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
- if (rc) {
- dprintk(VIDC_ERR,
- "Failed to move inst: %p to start done state\n", inst);
- goto failed_open_done;
- }
dprintk(VIDC_DBG,
"Control: HAL property=%d,ctrl_id=%d,ctrl_value=%d\n",
property_id,
@@ -1163,10 +1169,37 @@
rc = vidc_hal_session_set_property((void *)
inst->session, property_id,
pdata);
+ }
+
+ return rc;
+}
+
+static int msm_vdec_op_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ int rc = 0, c = 0;
+ struct msm_vidc_inst *inst = container_of(ctrl->handler,
+ struct msm_vidc_inst, ctrl_handler);
+ rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to move inst: %p to start done state\n", inst);
+ goto failed_open_done;
+ }
+
+ for (c = 0; c < ctrl->ncontrols; ++c) {
+ if (ctrl->cluster[c]->is_new) {
+ rc = try_set_ctrl(inst, ctrl->cluster[c]);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed setting %x",
+ ctrl->cluster[c]->id);
+ break;
+ }
}
+ }
+
+failed_open_done:
if (rc)
dprintk(VIDC_ERR, "Failed to set hal property for framesize\n");
-failed_open_done:
return rc;
}
@@ -1194,6 +1227,27 @@
{
return v4l2_g_ctrl(&inst->ctrl_handler, ctrl);
}
+
+static struct v4l2_ctrl **get_cluster(int type, int *size)
+{
+ int c = 0, sz = 0;
+ struct v4l2_ctrl **cluster = kmalloc(sizeof(struct v4l2_ctrl *) *
+ NUM_CTRLS, GFP_KERNEL);
+
+ if (type <= 0 || !size || !cluster)
+ return NULL;
+
+ for (c = 0; c < NUM_CTRLS; c++) {
+ if (msm_vdec_ctrls[c].cluster == type) {
+ cluster[sz] = msm_vdec_ctrls[c].priv;
+ ++sz;
+ }
+ }
+
+ *size = sz;
+ return cluster;
+}
+
int msm_vdec_ctrl_init(struct msm_vidc_inst *inst)
{
int idx = 0;
@@ -1209,12 +1263,13 @@
}
for (; idx < NUM_CTRLS; idx++) {
+ struct v4l2_ctrl *ctrl = NULL;
if (IS_PRIV_CTRL(msm_vdec_ctrls[idx].id)) {
/*add private control*/
ctrl_cfg.def = msm_vdec_ctrls[idx].default_value;
ctrl_cfg.flags = 0;
ctrl_cfg.id = msm_vdec_ctrls[idx].id;
- /*ctrl_cfg.is_private =
+ /* ctrl_cfg.is_private =
* msm_vdec_ctrls[idx].is_private;
* ctrl_cfg.is_volatile =
* msm_vdec_ctrls[idx].is_volatile;*/
@@ -1228,18 +1283,19 @@
ctrl_cfg.type = msm_vdec_ctrls[idx].type;
ctrl_cfg.qmenu = msm_vdec_ctrls[idx].qmenu;
- v4l2_ctrl_new_custom(&inst->ctrl_handler,
+ ctrl = v4l2_ctrl_new_custom(&inst->ctrl_handler,
&ctrl_cfg, NULL);
} else {
if (msm_vdec_ctrls[idx].type == V4L2_CTRL_TYPE_MENU) {
- v4l2_ctrl_new_std_menu(&inst->ctrl_handler,
+ ctrl = v4l2_ctrl_new_std_menu(
+ &inst->ctrl_handler,
&msm_vdec_ctrl_ops,
msm_vdec_ctrls[idx].id,
msm_vdec_ctrls[idx].maximum,
msm_vdec_ctrls[idx].menu_skip_mask,
msm_vdec_ctrls[idx].default_value);
} else {
- v4l2_ctrl_new_std(&inst->ctrl_handler,
+ ctrl = v4l2_ctrl_new_std(&inst->ctrl_handler,
&msm_vdec_ctrl_ops,
msm_vdec_ctrls[idx].id,
msm_vdec_ctrls[idx].minimum,
@@ -1248,11 +1304,51 @@
msm_vdec_ctrls[idx].default_value);
}
}
+
+
+ msm_vdec_ctrls[idx].priv = ctrl;
}
ret_val = inst->ctrl_handler.error;
if (ret_val)
dprintk(VIDC_ERR,
"Error adding ctrls to ctrl handle, %d\n",
inst->ctrl_handler.error);
+
+ /* Construct clusters */
+ for (idx = 1; idx < MSM_VDEC_CTRL_CLUSTER_MAX; ++idx) {
+ struct msm_vidc_ctrl_cluster *temp = NULL;
+ struct v4l2_ctrl **cluster = NULL;
+ int cluster_size = 0;
+
+ cluster = get_cluster(idx, &cluster_size);
+ if (!cluster || !cluster_size) {
+ dprintk(VIDC_WARN, "Failed to setup cluster of type %d",
+ idx);
+ continue;
+ }
+
+ v4l2_ctrl_cluster(cluster_size, cluster);
+
+ temp = kzalloc(sizeof(*temp), GFP_KERNEL);
+ if (!temp) {
+ ret_val = -ENOMEM;
+ break;
+ }
+
+ temp->cluster = cluster;
+ INIT_LIST_HEAD(&temp->list);
+ list_add_tail(&temp->list, &inst->ctrl_clusters);
+ }
return ret_val;
}
+
+int msm_vdec_ctrl_deinit(struct msm_vidc_inst *inst)
+{
+ struct msm_vidc_ctrl_cluster *curr, *next;
+ list_for_each_entry_safe(curr, next, &inst->ctrl_clusters, list) {
+ kfree(curr->cluster);
+ kfree(curr);
+ }
+
+ return 0;
+}
diff --git a/drivers/media/video/msm_vidc/msm_vdec.h b/drivers/media/video/msm_vidc/msm_vdec.h
index 419c8c1..73a516e 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.h
+++ b/drivers/media/video/msm_vidc/msm_vdec.h
@@ -18,6 +18,7 @@
int msm_vdec_inst_init(struct msm_vidc_inst *inst);
int msm_vdec_ctrl_init(struct msm_vidc_inst *inst);
+int msm_vdec_ctrl_deinit(struct msm_vidc_inst *inst);
int msm_vdec_querycap(void *instance, struct v4l2_capability *cap);
int msm_vdec_enum_fmt(void *instance, struct v4l2_fmtdesc *f);
int msm_vdec_s_fmt(void *instance, struct v4l2_format *f);
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
index 41518d7..0fa56b7 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -88,7 +88,20 @@
"High Latency",
};
-static const struct msm_vidc_ctrl msm_venc_ctrls[] = {
+enum msm_venc_ctrl_cluster {
+ MSM_VENC_CTRL_CLUSTER_QP = 1,
+ MSM_VENC_CTRL_CLUSTER_INTRA_PERIOD,
+ MSM_VENC_CTRL_CLUSTER_H264_PROFILE_LEVEL,
+ MSM_VENC_CTRL_CLUSTER_MPEG_PROFILE_LEVEL,
+ MSM_VENC_CTRL_CLUSTER_H263_PROFILE_LEVEL,
+ MSM_VENC_CTRL_CLUSTER_H264_ENTROPY,
+ MSM_VENC_CTRL_CLUSTER_SLICING,
+ MSM_VENC_CTRL_CLUSTER_INTRA_REFRESH,
+ MSM_VENC_CTRL_CLUSTER_BITRATE,
+ MSM_VENC_CTRL_CLUSTER_MAX,
+};
+
+static struct msm_vidc_ctrl msm_venc_ctrls[] = {
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE,
.name = "Frame Rate",
@@ -99,12 +112,13 @@
.step = 1,
.menu_skip_mask = 0,
.qmenu = NULL,
+ .cluster = 0,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_IDR_PERIOD,
.name = "IDR Period",
.type = V4L2_CTRL_TYPE_INTEGER,
- .minimum = 0,
+ .minimum = 1,
.maximum = 10*MAX_FRAME_RATE,
.default_value = DEFAULT_FRAME_RATE,
.step = 1,
@@ -112,6 +126,18 @@
.qmenu = NULL,
},
{
+ .id = V4L2_CID_MPEG_VIDEO_H264_I_PERIOD,
+ .name = "Intra Period",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 1,
+ .maximum = 10*MAX_FRAME_RATE,
+ .default_value = DEFAULT_FRAME_RATE,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ .cluster = MSM_VENC_CTRL_CLUSTER_INTRA_PERIOD,
+ },
+ {
.id = V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES,
.name = "Intra Period for P frames",
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -121,17 +147,19 @@
.step = 1,
.menu_skip_mask = 0,
.qmenu = NULL,
+ .cluster = MSM_VENC_CTRL_CLUSTER_INTRA_PERIOD,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES,
.name = "Intra Period for B frames",
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
- .maximum = 10*DEFAULT_FRAME_RATE,
+ .maximum = 2,
.default_value = 0,
.step = 1,
.menu_skip_mask = 0,
.qmenu = NULL,
+ .cluster = MSM_VENC_CTRL_CLUSTER_INTRA_PERIOD,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_IFRAME,
@@ -143,10 +171,11 @@
.step = 0,
.menu_skip_mask = 0,
.qmenu = NULL,
+ .cluster = 0,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL,
- .name = "Rate Control",
+ .name = "Video Framerate and Bitrate Control",
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_OFF,
.maximum = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR,
@@ -160,6 +189,22 @@
(1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR)
),
.qmenu = mpeg_video_rate_control,
+ .cluster = MSM_VENC_CTRL_CLUSTER_BITRATE,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+ .name = "Bitrate Control",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+ .maximum = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
+ .default_value = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
+ .step = 0,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) |
+ (1 << V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
+ ),
+ .qmenu = mpeg_video_rate_control,
+ .cluster = MSM_VENC_CTRL_CLUSTER_BITRATE,
},
{
.id = V4L2_CID_MPEG_VIDEO_BITRATE,
@@ -171,6 +216,7 @@
.step = BIT_RATE_STEP,
.menu_skip_mask = 0,
.qmenu = NULL,
+ .cluster = MSM_VENC_CTRL_CLUSTER_BITRATE,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE,
@@ -184,6 +230,7 @@
(1 << V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) |
(1 << V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC)
),
+ .cluster = MSM_VENC_CTRL_CLUSTER_H264_ENTROPY,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL,
@@ -199,6 +246,7 @@
(1 << V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_2)
),
.qmenu = h264_video_entropy_cabac_model,
+ .cluster = MSM_VENC_CTRL_CLUSTER_H264_ENTROPY,
},
{
.id = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE,
@@ -209,6 +257,7 @@
.default_value = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
.step = 1,
.menu_skip_mask = 0,
+ .cluster = MSM_VENC_CTRL_CLUSTER_MPEG_PROFILE_LEVEL,
},
{
.id = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL,
@@ -219,6 +268,7 @@
.default_value = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
.step = 1,
.menu_skip_mask = 0,
+ .cluster = MSM_VENC_CTRL_CLUSTER_MPEG_PROFILE_LEVEL,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_PROFILE,
@@ -229,6 +279,7 @@
.default_value = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
.step = 1,
.menu_skip_mask = 0,
+ .cluster = MSM_VENC_CTRL_CLUSTER_H264_PROFILE_LEVEL,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_LEVEL,
@@ -239,6 +290,7 @@
.default_value = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
.step = 0,
.menu_skip_mask = 0,
+ .cluster = MSM_VENC_CTRL_CLUSTER_H264_PROFILE_LEVEL,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE,
@@ -259,6 +311,7 @@
(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY)
),
.qmenu = h263_profile,
+ .cluster = MSM_VENC_CTRL_CLUSTER_H263_PROFILE_LEVEL,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL,
@@ -277,6 +330,7 @@
(1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0)
),
.qmenu = h263_level,
+ .cluster = MSM_VENC_CTRL_CLUSTER_H263_PROFILE_LEVEL,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_ROTATION,
@@ -293,6 +347,7 @@
(1 << V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_270)
),
.qmenu = mpeg_video_rotation,
+ .cluster = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP,
@@ -304,6 +359,7 @@
.step = 1,
.menu_skip_mask = 0,
.qmenu = NULL,
+ .cluster = MSM_VENC_CTRL_CLUSTER_QP,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP,
@@ -315,6 +371,7 @@
.step = 1,
.menu_skip_mask = 0,
.qmenu = NULL,
+ .cluster = MSM_VENC_CTRL_CLUSTER_QP,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP,
@@ -326,6 +383,7 @@
.step = 1,
.menu_skip_mask = 0,
.qmenu = NULL,
+ .cluster = MSM_VENC_CTRL_CLUSTER_QP,
},
{
.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
@@ -336,6 +394,7 @@
.default_value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
.step = 1,
.menu_skip_mask = 0,
+ .cluster = MSM_VENC_CTRL_CLUSTER_SLICING,
},
{
.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES,
@@ -347,6 +406,7 @@
.step = 1,
.menu_skip_mask = 0,
.qmenu = NULL,
+ .cluster = MSM_VENC_CTRL_CLUSTER_SLICING,
},
{
.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB,
@@ -358,6 +418,7 @@
.step = 1,
.menu_skip_mask = 0,
.qmenu = NULL,
+ .cluster = MSM_VENC_CTRL_CLUSTER_SLICING,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE,
@@ -374,6 +435,7 @@
(1 << V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_CYCLIC_ADAPTIVE) |
(1 << V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_RANDOM)
),
+ .cluster = MSM_VENC_CTRL_CLUSTER_INTRA_REFRESH,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS,
@@ -385,6 +447,7 @@
.step = 1,
.menu_skip_mask = 0,
.qmenu = NULL,
+ .cluster = MSM_VENC_CTRL_CLUSTER_INTRA_REFRESH,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF,
@@ -396,6 +459,7 @@
.step = 1,
.menu_skip_mask = 0,
.qmenu = NULL,
+ .cluster = MSM_VENC_CTRL_CLUSTER_INTRA_REFRESH,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS,
@@ -407,6 +471,7 @@
.step = 1,
.menu_skip_mask = 0,
.qmenu = NULL,
+ .cluster = MSM_VENC_CTRL_CLUSTER_INTRA_REFRESH,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA,
@@ -418,6 +483,7 @@
.step = 1,
.menu_skip_mask = 0,
.qmenu = NULL,
+ .cluster = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA,
@@ -429,6 +495,7 @@
.step = 1,
.menu_skip_mask = 0,
.qmenu = NULL,
+ .cluster = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
@@ -443,18 +510,24 @@
(1 << V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED) |
(1 << L_MODE)
),
+ .cluster = 0,
},
{
- .id = V4L2_CID_QCOM_VIDEO_SYNC_FRAME_SEQ_HDR,
- .name = "CodecConfig with sync frame",
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .minimum = 0,
- .maximum = 1,
- .default_value = 1,
+ .id = V4L2_CID_MPEG_VIDEO_HEADER_MODE,
+ .name = "Sequence Header Mode",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE,
+ .maximum = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME,
+ .default_value =
+ V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME,
.step = 1,
- .menu_skip_mask = 0,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) |
+ (1 << V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME)
+ ),
.qmenu = NULL,
- },
+ .cluster = 0,
+ }
};
#define NUM_CTRLS ARRAY_SIZE(msm_venc_ctrls)
@@ -476,29 +549,6 @@
return sz;
}
-static struct hal_quantization
- venc_quantization = {I_FRAME_QP, P_FRAME_QP, B_FRAME_QP};
-static struct hal_intra_period
- venc_intra_period = {2*DEFAULT_FRAME_RATE-1 , 0};
-static struct hal_profile_level
- venc_h264_profile_level = {HAL_H264_PROFILE_BASELINE,
- HAL_H264_LEVEL_1};
-static struct hal_profile_level
- venc_mpeg4_profile_level = {HAL_MPEG4_PROFILE_SIMPLE,
- HAL_MPEG4_LEVEL_0};
-static struct hal_profile_level
- venc_h263_profile_level = {HAL_H263_PROFILE_BASELINE,
- HAL_H263_LEVEL_10};
-static struct hal_h264_entropy_control
- venc_h264_entropy_control = {HAL_H264_ENTROPY_CAVLC,
- HAL_H264_CABAC_MODEL_0};
-static struct hal_multi_slice_control
- venc_multi_slice_control = {HAL_MULTI_SLICE_OFF ,
- 0};
-static struct hal_intra_refresh
- venc_intra_refresh = {HAL_INTRA_REFRESH_NONE ,
- DEFAULT_IR_MBS, DEFAULT_IR_MBS, DEFAULT_IR_MBS};
-
static const struct msm_vidc_format venc_formats[] = {
{
.name = "YCbCr Semiplanar 4:2:0",
@@ -744,11 +794,162 @@
return &msm_venc_vb2q_ops;
}
-static int msm_venc_op_s_ctrl(struct v4l2_ctrl *ctrl)
+static struct v4l2_ctrl *get_ctrl_from_cluster(int id,
+ struct v4l2_ctrl **cluster, int ncontrols)
{
+ int c;
+ for (c = 0; c < ncontrols; ++c)
+ if (cluster[c]->id == id)
+ return cluster[c];
+ return NULL;
+}
+
+/* Helper function to translate V4L2_* to HAL_* */
+static inline int venc_v4l2_to_hal(int id, int value)
+{
+ switch (id) {
+ /* MPEG4 */
+ case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
+ switch (value) {
+ case V4L2_MPEG_VIDEO_MPEG4_LEVEL_0:
+ return HAL_MPEG4_LEVEL_0;
+ case V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B:
+ return HAL_MPEG4_LEVEL_0b;
+ case V4L2_MPEG_VIDEO_MPEG4_LEVEL_1:
+ return HAL_MPEG4_LEVEL_1;
+ case V4L2_MPEG_VIDEO_MPEG4_LEVEL_2:
+ return HAL_MPEG4_LEVEL_2;
+ case V4L2_MPEG_VIDEO_MPEG4_LEVEL_3:
+ return HAL_MPEG4_LEVEL_3;
+ case V4L2_MPEG_VIDEO_MPEG4_LEVEL_4:
+ return HAL_MPEG4_LEVEL_4;
+ case V4L2_MPEG_VIDEO_MPEG4_LEVEL_5:
+ return HAL_MPEG4_LEVEL_5;
+ default:
+ goto unknown_value;
+ }
+ case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
+ switch (value) {
+ case V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE:
+ return HAL_MPEG4_PROFILE_SIMPLE;
+ case V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE:
+ return HAL_MPEG4_PROFILE_ADVANCEDSIMPLE;
+ default:
+ goto unknown_value;
+ }
+ /* H264 */
+ case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+ switch (value) {
+ case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
+ return HAL_H264_PROFILE_BASELINE;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
+ return HAL_H264_PROFILE_MAIN;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED:
+ return HAL_H264_PROFILE_EXTENDED;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
+ return HAL_H264_PROFILE_HIGH;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10:
+ return HAL_H264_PROFILE_HIGH10;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422:
+ return HAL_H264_PROFILE_HIGH422;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE:
+ return HAL_H264_PROFILE_HIGH444;
+ default:
+ goto unknown_value;
+ }
+ case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+ switch (value) {
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
+ return HAL_H264_LEVEL_1;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
+ return HAL_H264_LEVEL_1b;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
+ return HAL_H264_LEVEL_11;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
+ return HAL_H264_LEVEL_12;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
+ return HAL_H264_LEVEL_13;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
+ return HAL_H264_LEVEL_2;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
+ return HAL_H264_LEVEL_21;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
+ return HAL_H264_LEVEL_22;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
+ return HAL_H264_LEVEL_3;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
+ return HAL_H264_LEVEL_31;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
+ return HAL_H264_LEVEL_32;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
+ return HAL_H264_LEVEL_4;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_4_1:
+ return HAL_H264_LEVEL_41;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
+ return HAL_H264_LEVEL_42;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
+ return HAL_H264_LEVEL_3;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
+ return HAL_H264_LEVEL_51;
+ default:
+ goto unknown_value;
+ }
+ /* H263 */
+ case V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE:
+ switch (value) {
+ case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE:
+ return HAL_H263_PROFILE_BASELINE;
+ case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_H320CODING:
+ return HAL_H263_PROFILE_H320CODING;
+ case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BACKWARDCOMPATIBLE:
+ return HAL_H263_PROFILE_BACKWARDCOMPATIBLE;
+ case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV2:
+ return HAL_H263_PROFILE_ISWV2;
+ case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV3:
+ return HAL_H263_PROFILE_ISWV3;
+ case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHCOMPRESSION:
+ return HAL_H263_PROFILE_HIGHCOMPRESSION;
+ case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERNET:
+ return HAL_H263_PROFILE_INTERNET;
+ case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERLACE:
+ return HAL_H263_PROFILE_INTERLACE;
+ case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY:
+ return HAL_H263_PROFILE_HIGHLATENCY;
+ default:
+ goto unknown_value;
+ }
+ case V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL:
+ switch (value) {
+ case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0:
+ return HAL_H263_LEVEL_10;
+ case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_2_0:
+ return HAL_H263_LEVEL_20;
+ case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_3_0:
+ return HAL_H263_LEVEL_30;
+ case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_0:
+ return HAL_H263_LEVEL_40;
+ case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_5:
+ return HAL_H263_LEVEL_45;
+ case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_5_0:
+ return HAL_H263_LEVEL_50;
+ case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_6_0:
+ return HAL_H263_LEVEL_60;
+ case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0:
+ return HAL_H263_LEVEL_70;
+ default:
+ goto unknown_value;
+ }
+ }
+
+unknown_value:
+ dprintk(VIDC_WARN, "Unknown control (%x, %d)", id, value);
+ return -EINVAL;
+}
+
+static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
+{
int rc = 0;
- struct v4l2_control control;
struct hal_frame_rate frame_rate;
struct hal_request_iframe request_iframe;
struct hal_bitrate bitrate;
@@ -762,48 +963,78 @@
struct hal_multi_slice_control multi_slice_control;
struct hal_h264_db_control h264_db_control;
struct hal_enable enable;
- u32 property_id = 0;
- u32 property_val = 0;
+ u32 property_id = 0, property_val = 0;
void *pdata;
- struct msm_vidc_inst *inst = container_of(ctrl->handler,
- struct msm_vidc_inst, ctrl_handler);
- rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
- if (rc) {
- dprintk(VIDC_ERR,
- "Failed to move inst: %p to start done state\n", inst);
- goto failed_open_done;
- }
- control.id = ctrl->id;
- control.value = ctrl->val;
+ struct v4l2_ctrl *temp_ctrl = NULL;
- switch (control.id) {
+ /* Small helper macro for quickly getting a control and err checking */
+#define TRY_GET_CTRL(__ctrl_id) ({ \
+ struct v4l2_ctrl *__temp; \
+ __temp = get_ctrl_from_cluster( \
+ __ctrl_id, \
+ ctrl->cluster, ctrl->ncontrols); \
+ if (!__temp) { \
+ dprintk(VIDC_ERR, "Can't find %s (%x) in cluster", \
+ #__ctrl_id, __ctrl_id); \
+ rc = -ENOENT; \
+ break; \
+ } \
+ __temp; \
+ })
+
+ switch (ctrl->id) {
case V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE:
- property_id =
- HAL_CONFIG_FRAME_RATE;
- frame_rate.frame_rate = control.value;
- frame_rate.buffer_type = HAL_BUFFER_OUTPUT;
- pdata = &frame_rate;
+ property_id =
+ HAL_CONFIG_FRAME_RATE;
+ frame_rate.frame_rate = ctrl->val;
+ frame_rate.buffer_type = HAL_BUFFER_OUTPUT;
+ pdata = &frame_rate;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_IDR_PERIOD:
property_id =
HAL_CONFIG_VENC_IDR_PERIOD;
- idr_period.idr_period = control.value;
- pdata = &idr_period;
+ idr_period.idr_period = ctrl->val;
+ pdata = &idr_period;
break;
+ case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD: {
+ struct v4l2_ctrl *b;
+ b = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES);
+
+ if (inst->fmts[CAPTURE_PORT]->fourcc != V4L2_PIX_FMT_H264 &&
+ inst->fmts[CAPTURE_PORT]->fourcc !=
+ V4L2_PIX_FMT_H264_NO_SC) {
+ dprintk(VIDC_ERR, "Control 0x%x only valid for H264",
+ ctrl->id);
+ rc = -ENOTSUPP;
+ break;
+ }
+
+ /*
+ * We can't set the I-period explicitly. So set it implicitly
+ * by setting the number of P and B frames per I-period
+ */
+ property_id = HAL_CONFIG_VENC_INTRA_PERIOD;
+ intra_period.pframes = (ctrl->val - 1) - b->val;
+ intra_period.bframes = b->val;
+ pdata = &intra_period;
+ break;
+ }
case V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES:
+ temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES);
+
property_id =
HAL_CONFIG_VENC_INTRA_PERIOD;
- intra_period.pframes = control.value;
- venc_intra_period.pframes = control.value;
- intra_period.bframes = venc_intra_period.bframes;
+ intra_period.pframes = ctrl->val;
+ intra_period.bframes = temp_ctrl->val;
pdata = &intra_period;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES:
+ temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES);
+
property_id =
HAL_CONFIG_VENC_INTRA_PERIOD;
- intra_period.bframes = control.value;
- venc_intra_period.bframes = control.value;
- intra_period.pframes = venc_intra_period.pframes;
+ intra_period.bframes = ctrl->val;
+ intra_period.pframes = temp_ctrl->val;
pdata = &intra_period;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_IFRAME:
@@ -812,396 +1043,405 @@
request_iframe.enable = true;
pdata = &request_iframe;
break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ {
+ bool cfr = true, cbr = true;
+ int final_mode = 0;
+
+ temp_ctrl = TRY_GET_CTRL(
+ V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL);
+
+ switch (temp_ctrl->val) {
+ case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_OFF:
+ /* Let's assume CFR */
+ case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR:
+ case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR:
+ cfr = true;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_VFR:
+ case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_VFR:
+ cfr = false;
+ break;
+ default:
+ dprintk(VIDC_WARN, "Unknown framerate mode");
+ }
+
+ switch (ctrl->val) {
+ case V4L2_MPEG_VIDEO_BITRATE_MODE_VBR:
+ cbr = false;
+ break;
+ case V4L2_MPEG_VIDEO_BITRATE_MODE_CBR:
+ cbr = true;
+ break;
+ default:
+ dprintk(VIDC_WARN, "Unknown bitrate mode");
+ }
+
+ if (!cfr && !cbr)
+ final_mode =
+ V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_VFR;
+ else if (!cfr && cbr)
+ final_mode =
+ V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_VFR;
+ else if (cfr && !cbr)
+ final_mode =
+ V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR;
+ else /* ... if (cfr && cbr) */
+ final_mode =
+ V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR;
+
+ property_id = HAL_PARAM_VENC_RATE_CONTROL;
+ property_val = final_mode;
+ pdata = &property_val;
+ break;
+ }
case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL:
- property_id =
- HAL_PARAM_VENC_RATE_CONTROL;
- property_val = control.value;
+ property_id = HAL_PARAM_VENC_RATE_CONTROL;
+ property_val = ctrl->val;
pdata = &property_val;
break;
case V4L2_CID_MPEG_VIDEO_BITRATE:
property_id =
HAL_CONFIG_VENC_TARGET_BITRATE;
- bitrate.bit_rate = control.value;
+ bitrate.bit_rate = ctrl->val;
pdata = &bitrate;
break;
case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
+ temp_ctrl = TRY_GET_CTRL(
+ V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL);
+
property_id =
HAL_PARAM_VENC_H264_ENTROPY_CONTROL;
- h264_entropy_control.entropy_mode = control.value;
- venc_h264_entropy_control.entropy_mode = control.value;
- h264_entropy_control.cabac_model =
- venc_h264_entropy_control.cabac_model;
+ h264_entropy_control.entropy_mode = ctrl->val;
+ h264_entropy_control.cabac_model = temp_ctrl->val;
pdata = &h264_entropy_control;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL:
+ temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE);
+
property_id =
HAL_PARAM_VENC_H264_ENTROPY_CONTROL;
- h264_entropy_control.cabac_model = control.value;
- venc_h264_entropy_control.cabac_model = control.value;
- h264_entropy_control.entropy_mode =
- venc_h264_entropy_control.entropy_mode;
+ h264_entropy_control.cabac_model = ctrl->val;
+ h264_entropy_control.entropy_mode = temp_ctrl->val;
pdata = &h264_entropy_control;
break;
case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
+ temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL);
+
property_id =
HAL_PARAM_PROFILE_LEVEL_CURRENT;
- switch (control.value) {
- case V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE:
- control.value = HAL_MPEG4_PROFILE_SIMPLE;
- break;
- case V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE:
- control.value = HAL_MPEG4_PROFILE_ADVANCEDSIMPLE;
- break;
- default:
- break;
- }
- profile_level.profile = control.value;
- venc_mpeg4_profile_level.profile = control.value;
- profile_level.level = venc_mpeg4_profile_level.level;
+ profile_level.profile = venc_v4l2_to_hal(ctrl->id,
+ ctrl->val);
+ profile_level.level = venc_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL,
+ temp_ctrl->val);
pdata = &profile_level;
break;
case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
+ temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE);
+
property_id =
HAL_PARAM_PROFILE_LEVEL_CURRENT;
- switch (control.value) {
- case V4L2_MPEG_VIDEO_MPEG4_LEVEL_0:
- control.value = HAL_MPEG4_LEVEL_0;
- break;
- case V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B:
- control.value = HAL_MPEG4_LEVEL_0b;
- break;
- case V4L2_MPEG_VIDEO_MPEG4_LEVEL_1:
- control.value = HAL_MPEG4_LEVEL_1;
- break;
- case V4L2_MPEG_VIDEO_MPEG4_LEVEL_2:
- control.value = HAL_MPEG4_LEVEL_2;
- break;
- case V4L2_MPEG_VIDEO_MPEG4_LEVEL_3:
- control.value = HAL_MPEG4_LEVEL_3;
- break;
- case V4L2_MPEG_VIDEO_MPEG4_LEVEL_4:
- control.value = HAL_MPEG4_LEVEL_4;
- break;
- case V4L2_MPEG_VIDEO_MPEG4_LEVEL_5:
- control.value = HAL_MPEG4_LEVEL_5;
- break;
- default:
- break;
- }
- profile_level.level = control.value;
- venc_mpeg4_profile_level.level = control.value;
- profile_level.profile = venc_mpeg4_profile_level.profile;
+ profile_level.level = venc_v4l2_to_hal(ctrl->id,
+ ctrl->val);
+ profile_level.profile = venc_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE,
+ temp_ctrl->val);
pdata = &profile_level;
break;
case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+ temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_LEVEL);
+
property_id =
HAL_PARAM_PROFILE_LEVEL_CURRENT;
-
- switch (control.value) {
- case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
- control.value = HAL_H264_PROFILE_BASELINE;
- break;
- case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
- control.value = HAL_H264_PROFILE_MAIN;
- break;
- case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED:
- control.value = HAL_H264_PROFILE_EXTENDED;
- break;
- case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
- control.value = HAL_H264_PROFILE_HIGH;
- break;
- case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10:
- control.value = HAL_H264_PROFILE_HIGH10;
- break;
- case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422:
- control.value = HAL_H264_PROFILE_HIGH422;
- break;
- case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE:
- control.value = HAL_H264_PROFILE_HIGH444;
- break;
- default:
- break;
- }
- profile_level.profile = control.value;
- venc_h264_profile_level.profile = control.value;
- profile_level.level = venc_h264_profile_level.level;
+ profile_level.profile = venc_v4l2_to_hal(ctrl->id,
+ ctrl->val);
+ profile_level.level = venc_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+ temp_ctrl->val);
pdata = &profile_level;
dprintk(VIDC_DBG, "\nprofile: %d\n",
profile_level.profile);
break;
case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+ temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_PROFILE);
+
property_id =
HAL_PARAM_PROFILE_LEVEL_CURRENT;
-
- switch (control.value) {
- case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
- control.value = HAL_H264_LEVEL_1;
- break;
- case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
- control.value = HAL_H264_LEVEL_1b;
- break;
- case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
- control.value = HAL_H264_LEVEL_11;
- break;
- case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
- control.value = HAL_H264_LEVEL_12;
- break;
- case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
- control.value = HAL_H264_LEVEL_13;
- break;
- case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
- control.value = HAL_H264_LEVEL_2;
- break;
- case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
- control.value = HAL_H264_LEVEL_21;
- break;
- case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
- control.value = HAL_H264_LEVEL_22;
- break;
- case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
- control.value = HAL_H264_LEVEL_3;
- break;
- case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
- control.value = HAL_H264_LEVEL_31;
- break;
- case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
- control.value = HAL_H264_LEVEL_32;
- break;
- case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
- control.value = HAL_H264_LEVEL_4;
- break;
- case V4L2_MPEG_VIDEO_H264_LEVEL_4_1:
- control.value = HAL_H264_LEVEL_41;
- break;
- case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
- control.value = HAL_H264_LEVEL_42;
- break;
- case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
- control.value = HAL_H264_LEVEL_3;
- break;
- case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
- control.value = HAL_H264_LEVEL_51;
- break;
- default:
- break;
- }
- profile_level.level = control.value;
- venc_h264_profile_level.level = control.value;
- profile_level.profile = venc_h264_profile_level.profile;
- pdata = &profile_level;
+ profile_level.level = venc_v4l2_to_hal(ctrl->id,
+ ctrl->val);
+ profile_level.profile = venc_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+ temp_ctrl->val);
pdata = &profile_level;
dprintk(VIDC_DBG, "\nLevel: %d\n",
profile_level.level);
break;
case V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE:
+ temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL);
+
property_id =
HAL_PARAM_PROFILE_LEVEL_CURRENT;
-
- switch (control.value) {
- case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE:
- control.value = HAL_H263_PROFILE_BASELINE;
- break;
- case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_H320CODING:
- control.value = HAL_H263_PROFILE_H320CODING;
- break;
- case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BACKWARDCOMPATIBLE:
- control.value = HAL_H263_PROFILE_BACKWARDCOMPATIBLE;
- break;
- case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV2:
- control.value = HAL_H263_PROFILE_ISWV2;
- break;
- case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV3:
- control.value = HAL_H263_PROFILE_ISWV3;
- break;
- case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHCOMPRESSION:
- control.value = HAL_H263_PROFILE_HIGHCOMPRESSION;
- break;
- case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERNET:
- control.value = HAL_H263_PROFILE_INTERNET;
- break;
- case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERLACE:
- control.value = HAL_H263_PROFILE_INTERLACE;
- break;
- case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY:
- control.value = HAL_H263_PROFILE_HIGHLATENCY;
- break;
- default:
- break;
- }
- profile_level.profile = control.value;
- venc_h263_profile_level.profile = control.value;
- profile_level.level = venc_h263_profile_level.level;
+ profile_level.profile = venc_v4l2_to_hal(ctrl->id,
+ ctrl->val);
+ profile_level.level = venc_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL,
+ temp_ctrl->val);
pdata = &profile_level;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL:
+ temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE);
+
property_id =
HAL_PARAM_PROFILE_LEVEL_CURRENT;
-
- switch (control.value) {
- case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0:
- control.value = HAL_H263_LEVEL_10;
- break;
- case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_2_0:
- control.value = HAL_H263_LEVEL_20;
- break;
- case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_3_0:
- control.value = HAL_H263_LEVEL_30;
- break;
- case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_0:
- control.value = HAL_H263_LEVEL_40;
- break;
- case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_5:
- control.value = HAL_H263_LEVEL_45;
- break;
- case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_5_0:
- control.value = HAL_H263_LEVEL_50;
- break;
- case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_6_0:
- control.value = HAL_H263_LEVEL_60;
- break;
- case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0:
- control.value = HAL_H263_LEVEL_70;
- break;
- default:
- break;
- }
-
- profile_level.level = control.value;
- venc_h263_profile_level.level = control.value;
- profile_level.profile = venc_h263_profile_level.profile;
+ profile_level.level = venc_v4l2_to_hal(ctrl->id,
+ ctrl->val);
+ profile_level.profile = venc_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE,
+ ctrl->val);
pdata = &profile_level;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION:
property_id =
HAL_CONFIG_VPE_OPERATIONS;
- operations.rotate = control.value;
+ operations.rotate = ctrl->val;
pdata = &operations;
break;
- case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
+ case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: {
+ struct v4l2_ctrl *qpp, *qpb;
+
+ qpp = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP);
+ qpb = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP);
+
property_id =
HAL_PARAM_VENC_SESSION_QP;
- quantization.qpi = control.value;
- venc_quantization.qpi = control.value;
- quantization.qpp = venc_quantization.qpp;
- quantization.qpb = venc_quantization.qpb;
+ quantization.qpi = ctrl->val;
+ quantization.qpp = qpp->val;
+ quantization.qpb = qpb->val;
+
pdata = &quantization;
break;
- case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
+ }
+ case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP: {
+ struct v4l2_ctrl *qpi, *qpb;
+
+ qpi = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP);
+ qpb = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP);
+
property_id =
HAL_PARAM_VENC_SESSION_QP;
- quantization.qpp = control.value;
- venc_quantization.qpp = control.value;
- quantization.qpi = venc_quantization.qpi;
- quantization.qpb = venc_quantization.qpb;
+ quantization.qpp = ctrl->val;
+ quantization.qpi = qpi->val;
+ quantization.qpb = qpb->val;
+
pdata = &quantization;
break;
- case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:
+ }
+ case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP: {
+ struct v4l2_ctrl *qpi, *qpp;
+
+ qpi = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP);
+ qpp = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP);
+
property_id =
HAL_PARAM_VENC_SESSION_QP;
- quantization.qpb = control.value;
- venc_quantization.qpb = control.value;
- quantization.qpi = venc_quantization.qpi;
- quantization.qpp = venc_quantization.qpp;
+ quantization.qpb = ctrl->val;
+ quantization.qpi = qpi->val;
+ quantization.qpp = qpp->val;
+
pdata = &quantization;
break;
- case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
+ }
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: {
+ int temp = 0;
+
+ switch (ctrl->val) {
+ case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB:
+ temp = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB;
+ break;
+ case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES:
+ temp = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES;
+ break;
+ case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE:
+ default:
+ temp = 0;
+ break;
+ }
+
+ if (temp)
+ temp_ctrl = TRY_GET_CTRL(temp);
+
property_id =
HAL_PARAM_VENC_MULTI_SLICE_CONTROL;
- multi_slice_control.multi_slice = control.value;
- venc_multi_slice_control.multi_slice = control.value;
- multi_slice_control.slice_size =
- venc_multi_slice_control.slice_size;
+ multi_slice_control.multi_slice = ctrl->val;
+ multi_slice_control.slice_size = temp ? temp_ctrl->val : 0;
+
pdata = &multi_slice_control;
break;
+ }
case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
+ temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE);
+
property_id =
HAL_PARAM_VENC_MULTI_SLICE_CONTROL;
- multi_slice_control.multi_slice =
- venc_multi_slice_control.multi_slice;
- multi_slice_control.slice_size = control.value;
- venc_multi_slice_control.slice_size = control.value;
+ multi_slice_control.multi_slice = temp_ctrl->val;
+ multi_slice_control.slice_size = ctrl->val;
pdata = &multi_slice_control;
break;
- case V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE:
+ case V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE: {
+ struct v4l2_ctrl *air_mbs, *air_ref, *cir_mbs;
+ air_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS);
+ air_ref = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF);
+ cir_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS);
+
property_id =
HAL_PARAM_VENC_INTRA_REFRESH;
- intra_refresh.mode = control.value;
- intra_refresh.air_mbs = venc_intra_refresh.air_mbs;
- intra_refresh.air_ref = venc_intra_refresh.air_ref;
- intra_refresh.cir_mbs = venc_intra_refresh.cir_mbs;
- venc_intra_refresh.mode = intra_refresh.mode;
+
+ intra_refresh.mode = ctrl->val;
+ intra_refresh.air_mbs = air_mbs->val;
+ intra_refresh.air_ref = air_ref->val;
+ intra_refresh.cir_mbs = cir_mbs->val;
+
pdata = &intra_refresh;
break;
- case V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS:
+ }
+ case V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS: {
+ struct v4l2_ctrl *ir_mode, *air_ref, *cir_mbs;
+ ir_mode = TRY_GET_CTRL(
+ V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE);
+ air_ref = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF);
+ cir_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS);
+
property_id =
HAL_PARAM_VENC_INTRA_REFRESH;
- intra_refresh.air_mbs = control.value;
- intra_refresh.mode = venc_intra_refresh.mode;
- intra_refresh.air_ref = venc_intra_refresh.air_ref;
- intra_refresh.cir_mbs = venc_intra_refresh.cir_mbs;
- venc_intra_refresh.air_mbs = control.value;
+ intra_refresh.air_mbs = ctrl->val;
+ intra_refresh.mode = ir_mode->val;
+ intra_refresh.air_ref = air_ref->val;
+ intra_refresh.cir_mbs = cir_mbs->val;
+
pdata = &intra_refresh;
break;
- case V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF:
+ }
+ case V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF: {
+ struct v4l2_ctrl *ir_mode, *air_mbs, *cir_mbs;
+ ir_mode = TRY_GET_CTRL(
+ V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE);
+ air_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS);
+ cir_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS);
+
property_id =
HAL_PARAM_VENC_INTRA_REFRESH;
- intra_refresh.air_ref = control.value;
- intra_refresh.air_mbs = venc_intra_refresh.air_mbs;
- intra_refresh.mode = venc_intra_refresh.mode;
- intra_refresh.cir_mbs = venc_intra_refresh.cir_mbs;
- venc_intra_refresh.air_ref = control.value;
+ intra_refresh.air_ref = ctrl->val;
+ intra_refresh.air_mbs = air_mbs->val;
+ intra_refresh.mode = ir_mode->val;
+ intra_refresh.cir_mbs = cir_mbs->val;
+
pdata = &intra_refresh;
break;
- case V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS:
+ }
+ case V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS: {
+ struct v4l2_ctrl *ir_mode, *air_mbs, *air_ref;
+
+ ir_mode = TRY_GET_CTRL(
+ V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE);
+ air_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS);
+ air_ref = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF);
+
property_id =
HAL_PARAM_VENC_INTRA_REFRESH;
- intra_refresh.cir_mbs = control.value;
- intra_refresh.air_mbs = venc_intra_refresh.air_mbs;
- intra_refresh.air_ref = venc_intra_refresh.air_ref;
- intra_refresh.mode = venc_intra_refresh.mode;
- venc_intra_refresh.cir_mbs = control.value;
+
+ intra_refresh.cir_mbs = ctrl->val;
+ intra_refresh.air_mbs = air_mbs->val;
+ intra_refresh.air_ref = air_ref->val;
+ intra_refresh.mode = ir_mode->val;
+
pdata = &intra_refresh;
break;
+ }
case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
property_id =
HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
- h264_db_control.mode = control.value;
+ h264_db_control.mode = ctrl->val;
pdata = &h264_db_control;
break;
case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:
property_id =
HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
- h264_db_control.slice_alpha_offset = control.value;
+ h264_db_control.slice_alpha_offset = ctrl->val;
pdata = &h264_db_control;
break;
case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:
property_id =
HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
- h264_db_control.slice_beta_offset = control.value;
+ h264_db_control.slice_beta_offset = ctrl->val;
pdata = &h264_db_control;
break;
- case V4L2_CID_QCOM_VIDEO_SYNC_FRAME_SEQ_HDR:
+ case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
property_id =
HAL_PARAM_VENC_SYNC_FRAME_SEQUENCE_HEADER;
- enable.enable = control.value;
+
+ switch (ctrl->val) {
+ case V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE:
+ enable.enable = 0;
+ break;
+ case V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME:
+ enable.enable = 1;
+ break;
+ case V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME:
+ default:
+ rc = -ENOTSUPP;
+ break;
+ }
pdata = &enable;
break;
default:
+ rc = -ENOTSUPP;
break;
}
+#undef TRY_GET_CTRL
+
if (property_id) {
dprintk(VIDC_DBG, "Control: HAL property=%d,ctrl_value=%d\n",
property_id,
- control.value);
+ ctrl->val);
rc = vidc_hal_session_set_property((void *)inst->session,
property_id, pdata);
}
- if (rc)
- dprintk(VIDC_ERR, "Failed to set hal property for framesize\n");
-failed_open_done:
+
return rc;
}
+
+static int msm_venc_op_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+
+ int rc = 0, c = 0;
+ struct msm_vidc_inst *inst = container_of(ctrl->handler,
+ struct msm_vidc_inst, ctrl_handler);
+ rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to move inst: %p to start done state\n", inst);
+ goto failed_open_done;
+ }
+
+ for (c = 0; c < ctrl->ncontrols; ++c) {
+ if (ctrl->cluster[c]->is_new) {
+ rc = try_set_ctrl(inst, ctrl->cluster[c]);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed setting %x",
+ ctrl->cluster[c]->id);
+ break;
+ }
+ }
+ }
+failed_open_done:
+ if (rc)
+ dprintk(VIDC_ERR, "Failed to set hal property\n");
+ return rc;
+}
+
static int msm_venc_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
{
return 0;
@@ -1334,12 +1574,10 @@
if (a->parm.output.timeperframe.denominator) {
switch (a->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
- us_per_frame = a->parm.output.timeperframe.numerator/
- a->parm.output.timeperframe.denominator;
- break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- us_per_frame = a->parm.capture.timeperframe.numerator/
- a->parm.capture.timeperframe.denominator;
+ us_per_frame = a->parm.output.timeperframe.numerator *
+ USEC_PER_SEC / a->parm.output.\
+ timeperframe.denominator;
break;
default:
dprintk(VIDC_ERR,
@@ -1665,6 +1903,26 @@
return rc;
}
+static struct v4l2_ctrl **get_cluster(int type, int *size)
+{
+ int c = 0, sz = 0;
+ struct v4l2_ctrl **cluster = kmalloc(sizeof(struct v4l2_ctrl *) *
+ NUM_CTRLS, GFP_KERNEL);
+
+ if (type <= 0 || !size || !cluster)
+ return NULL;
+
+ for (c = 0; c < NUM_CTRLS; c++) {
+ if (msm_venc_ctrls[c].cluster == type) {
+ cluster[sz] = msm_venc_ctrls[c].priv;
+ ++sz;
+ }
+ }
+
+ *size = sz;
+ return cluster;
+}
+
int msm_venc_ctrl_init(struct msm_vidc_inst *inst)
{
@@ -1679,6 +1937,7 @@
}
for (; idx < NUM_CTRLS; idx++) {
+ struct v4l2_ctrl *ctrl = NULL;
if (IS_PRIV_CTRL(msm_venc_ctrls[idx].id)) {
ctrl_cfg.def = msm_venc_ctrls[idx].default_value;
ctrl_cfg.flags = 0;
@@ -1692,18 +1951,20 @@
ctrl_cfg.step = msm_venc_ctrls[idx].step;
ctrl_cfg.type = msm_venc_ctrls[idx].type;
ctrl_cfg.qmenu = msm_venc_ctrls[idx].qmenu;
- v4l2_ctrl_new_custom(&inst->ctrl_handler,
- &ctrl_cfg, NULL);
+ ctrl = v4l2_ctrl_new_custom(
+ &inst->ctrl_handler,
+ &ctrl_cfg, NULL);
} else {
if (msm_venc_ctrls[idx].type == V4L2_CTRL_TYPE_MENU) {
- v4l2_ctrl_new_std_menu(&inst->ctrl_handler,
+ ctrl = v4l2_ctrl_new_std_menu(
+ &inst->ctrl_handler,
&msm_venc_ctrl_ops,
msm_venc_ctrls[idx].id,
msm_venc_ctrls[idx].maximum,
msm_venc_ctrls[idx].menu_skip_mask,
msm_venc_ctrls[idx].default_value);
} else {
- v4l2_ctrl_new_std(&inst->ctrl_handler,
+ ctrl = v4l2_ctrl_new_std(&inst->ctrl_handler,
&msm_venc_ctrl_ops,
msm_venc_ctrls[idx].id,
msm_venc_ctrls[idx].minimum,
@@ -1712,11 +1973,51 @@
msm_venc_ctrls[idx].default_value);
}
}
+
+ msm_venc_ctrls[idx].priv = ctrl;
}
ret_val = inst->ctrl_handler.error;
if (ret_val)
dprintk(VIDC_ERR,
"CTRL ERR: Error adding ctrls to ctrl handle, %d\n",
inst->ctrl_handler.error);
+
+ /* Construct clusters */
+ for (idx = 1; idx < MSM_VENC_CTRL_CLUSTER_MAX; ++idx) {
+ struct msm_vidc_ctrl_cluster *temp = NULL;
+ struct v4l2_ctrl **cluster = NULL;
+ int cluster_size = 0;
+
+ cluster = get_cluster(idx, &cluster_size);
+ if (!cluster || !cluster_size) {
+ dprintk(VIDC_WARN, "Failed to setup cluster of type %d",
+ idx);
+ continue;
+ }
+
+ v4l2_ctrl_cluster(cluster_size, cluster);
+
+ temp = kzalloc(sizeof(*temp), GFP_KERNEL);
+ if (!temp) {
+ ret_val = -ENOMEM;
+ break;
+ }
+
+ temp->cluster = cluster;
+ INIT_LIST_HEAD(&temp->list);
+ list_add_tail(&temp->list, &inst->ctrl_clusters);
+ }
+
return ret_val;
}
+
+int msm_venc_ctrl_deinit(struct msm_vidc_inst *inst)
+{
+ struct msm_vidc_ctrl_cluster *curr, *next;
+ list_for_each_entry_safe(curr, next, &inst->ctrl_clusters, list) {
+ kfree(curr->cluster);
+ kfree(curr);
+ }
+
+ return 0;
+}
diff --git a/drivers/media/video/msm_vidc/msm_venc.h b/drivers/media/video/msm_vidc/msm_venc.h
index ad63e7d..c098773 100644
--- a/drivers/media/video/msm_vidc/msm_venc.h
+++ b/drivers/media/video/msm_vidc/msm_venc.h
@@ -18,6 +18,7 @@
int msm_venc_inst_init(struct msm_vidc_inst *inst);
int msm_venc_ctrl_init(struct msm_vidc_inst *inst);
+int msm_venc_ctrl_deinit(struct msm_vidc_inst *inst);
int msm_venc_querycap(void *instance, struct v4l2_capability *cap);
int msm_venc_enum_fmt(void *instance, struct v4l2_fmtdesc *f);
int msm_venc_s_fmt(void *instance, struct v4l2_format *f);
diff --git a/drivers/media/video/msm_vidc/msm_vidc.c b/drivers/media/video/msm_vidc/msm_vidc.c
index 6ecea30..13180c5 100644
--- a/drivers/media/video/msm_vidc/msm_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_vidc.c
@@ -428,6 +428,7 @@
INIT_LIST_HEAD(&inst->pendingq);
INIT_LIST_HEAD(&inst->internalbufs);
INIT_LIST_HEAD(&inst->persistbufs);
+ INIT_LIST_HEAD(&inst->ctrl_clusters);
init_waitqueue_head(&inst->kernel_event_queue);
inst->state = MSM_VIDC_CORE_UNINIT_DONE;
inst->core = core;
@@ -555,6 +556,12 @@
list_del(&inst->list);
}
mutex_unlock(&core->sync_lock);
+
+ if (inst->session_type == MSM_VIDC_DECODER)
+ msm_vdec_ctrl_deinit(inst);
+ else if (inst->session_type == MSM_VIDC_ENCODER)
+ msm_venc_ctrl_deinit(inst);
+
cleanup_instance(inst);
if (inst->state != MSM_VIDC_CORE_INVALID &&
core->state != VIDC_CORE_INVALID)
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index 5fbc63c..2a4a5e0 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -62,6 +62,8 @@
int ret;
};
+#define TIME_DIFF_THRESHOLD 200
+
static const u32 bus_table[] = {
36000,
110400,
@@ -755,12 +757,63 @@
}
}
+static void msm_comm_update_clocks(struct msm_vidc_inst *inst,
+ u64 cur_time_stamp)
+{
+ u32 new_time_diff = 0, cur_time_diff = 0;
+ u8 updated_fps = 0;
+ struct v4l2_ctrl *ctrl = NULL;
+ u32 output_order = 0;
+
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ goto exit;
+ if (cur_time_stamp >= LLONG_MAX) {
+ dprintk(VIDC_WARN,
+ "Clock scaling failed : Timestamp invalid\n");
+ goto exit;
+ }
+ ctrl = v4l2_ctrl_find(&inst->ctrl_handler,
+ V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER);
+ if (!ctrl) {
+ dprintk(VIDC_WARN, "Unable to find output order control\n");
+ dprintk(VIDC_WARN,
+ "Performance might be impacted for higher fps clips\n");
+ goto exit;
+ }
+ output_order = v4l2_ctrl_g_ctrl(ctrl);
+ if (output_order == V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY) {
+ new_time_diff =
+ (u32)(cur_time_stamp - inst->prop.prev_time_stamp);
+ inst->prop.prev_time_stamp = cur_time_stamp;
+ if (!new_time_diff)
+ goto exit;
+ if (inst->prop.fps)
+ cur_time_diff = USEC_PER_SEC / inst->prop.fps;
+ cur_time_diff = cur_time_diff > new_time_diff ?
+ cur_time_diff - new_time_diff :
+ new_time_diff - cur_time_diff;
+ if (cur_time_diff > TIME_DIFF_THRESHOLD) {
+ updated_fps = (u8) (USEC_PER_SEC / new_time_diff);
+ if (updated_fps && (updated_fps != inst->prop.fps)) {
+ inst->prop.fps = updated_fps;
+ dprintk(VIDC_DBG,
+ "Updating clocks: Decoding fps = %d\n",
+ inst->prop.fps);
+ msm_comm_scale_clocks_and_bus(inst);
+ }
+ }
+ }
+exit:
+ return;
+}
+
static void handle_fbd(enum command_response cmd, void *data)
{
struct msm_vidc_cb_data_done *response = data;
struct msm_vidc_inst *inst;
struct vb2_buffer *vb;
struct vidc_hal_fbd *fill_buf_done;
+
if (!response) {
dprintk(VIDC_ERR, "Invalid response from vidc_hal\n");
return;
@@ -776,9 +829,9 @@
int64_t time_usec = fill_buf_done->timestamp_hi;
time_usec = (time_usec << 32) |
fill_buf_done->timestamp_lo;
-
vb->v4l2_buf.timestamp =
ns_to_timeval(time_usec * NSEC_PER_USEC);
+ msm_comm_update_clocks(inst, time_usec);
}
vb->v4l2_buf.flags = 0;
@@ -788,7 +841,8 @@
vb->v4l2_buf.flags &= ~V4L2_QCOM_BUF_FLAG_CODECCONFIG;
if (fill_buf_done->flags1 & HAL_BUFFERFLAG_SYNCFRAME)
vb->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
-
+ if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOSEQ)
+ vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_EOSEQ;
switch (fill_buf_done->picture_type) {
case HAL_PICTURE_IDR:
case HAL_PICTURE_I:
@@ -1012,16 +1066,17 @@
}
if (msm_comm_scale_clocks(core)) {
dprintk(VIDC_WARN,
- "Failed to scale clocks. Performance might be impacted\n");
+ "Failed to scale clocks. Performance might be impacted\n");
}
if (msm_comm_scale_bus(core, inst->session_type, DDR_MEM)) {
dprintk(VIDC_WARN,
- "Failed to scale DDR bus. Performance might be impacted\n");
+ "Failed to scale DDR bus. Performance might be impacted\n");
}
if (core->resources.ocmem.buf) {
- if (msm_comm_scale_bus(core, inst->session_type, OCMEM_MEM))
+ if (msm_comm_scale_bus(core, inst->session_type,
+ OCMEM_MEM))
dprintk(VIDC_WARN,
- "Failed to scale OCMEM bus. Performance might be impacted\n");
+ "Failed to scale OCMEM bus. Performance might be impacted\n");
}
}
@@ -1709,7 +1764,6 @@
inst->state, state);
return rc;
}
-
int msm_comm_qbuf(struct vb2_buffer *vb)
{
int rc = 0;
diff --git a/drivers/media/video/msm_vidc/msm_vidc_internal.h b/drivers/media/video/msm_vidc/msm_vidc_internal.h
index f138c12..aadb4c2 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_internal.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_internal.h
@@ -170,6 +170,7 @@
u32 height;
u32 fps;
u32 bitrate;
+ u64 prev_time_stamp;
};
struct buf_queue {
@@ -250,6 +251,7 @@
void *mem_client;
struct v4l2_ctrl_handler ctrl_handler;
struct completion completions[SESSION_MSG_END - SESSION_MSG_START + 1];
+ struct list_head ctrl_clusters;
struct v4l2_fh event_handler;
struct msm_smem *extradata_handle;
wait_queue_head_t kernel_event_queue;
@@ -267,6 +269,11 @@
extern struct msm_vidc_drv *vidc_driver;
+struct msm_vidc_ctrl_cluster {
+ struct v4l2_ctrl **cluster;
+ struct list_head list;
+};
+
struct msm_vidc_ctrl {
u32 id;
char name[MAX_NAME_LENGTH];
@@ -277,6 +284,8 @@
u32 step;
u32 menu_skip_mask;
const char * const *qmenu;
+ u32 cluster;
+ struct v4l2_ctrl *priv;
};
void handle_cmd_response(enum command_response cmd, void *data);
diff --git a/drivers/media/video/msm_vidc/vidc_hal_api.h b/drivers/media/video/msm_vidc/vidc_hal_api.h
index 3b83424..3e70342 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_api.h
+++ b/drivers/media/video/msm_vidc/vidc_hal_api.h
@@ -39,6 +39,7 @@
#define HAL_BUFFERFLAG_TIMESTAMPINVALID 0x00000100
#define HAL_BUFFERFLAG_READONLY 0x00000200
#define HAL_BUFFERFLAG_ENDOFSUBFRAME 0x00000400
+#define HAL_BUFFERFLAG_EOSEQ 0x00200000
#define HAL_DEBUG_MSG_LOW 0x00000001
#define HAL_DEBUG_MSG_MEDIUM 0x00000002
diff --git a/drivers/media/video/msm_wfd/enc-venus-subdev.c b/drivers/media/video/msm_wfd/enc-venus-subdev.c
index 86242a3..73a3d8e 100644
--- a/drivers/media/video/msm_wfd/enc-venus-subdev.c
+++ b/drivers/media/video/msm_wfd/enc-venus-subdev.c
@@ -818,7 +818,7 @@
static long venc_set_framerate(struct v4l2_subdev *sd, void *arg)
{
struct venc_inst *inst = NULL;
- struct v4l2_control ctrl = {0};
+ struct v4l2_streamparm p = {0};
if (!sd) {
WFD_MSG_ERR("Subdevice required for %s\n", __func__);
@@ -829,9 +829,9 @@
}
inst = (struct venc_inst *)sd->dev_priv;
- ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE;
- ctrl.value = 30;
- return msm_vidc_s_ctrl(inst->vidc_context, &ctrl);
+ p.type = BUF_TYPE_INPUT;
+ p.parm.output.timeperframe = *(struct v4l2_fract *)arg;
+ return msm_vidc_s_parm(inst->vidc_context, &p);
}
static long venc_fill_outbuf(struct v4l2_subdev *sd, void *arg)
@@ -1064,7 +1064,6 @@
static long venc_set_property(struct v4l2_subdev *sd, void *arg)
{
struct venc_inst *inst = NULL;
- struct v4l2_control *ctrl = arg;
if (!sd) {
WFD_MSG_ERR("Subdevice required for %s\n", __func__);
@@ -1072,13 +1071,6 @@
}
inst = (struct venc_inst *)sd->dev_priv;
- if (ctrl->id == V4L2_CID_MPEG_VIDEO_HEADER_MODE) {
- /* XXX: We don't support this yet, but to prevent unncessary
- * target specific code for the client, we'll not error out.
- * The client ideally shouldn't notice this */
- return 0;
- }
-
return msm_vidc_s_ctrl(inst->vidc_context, (struct v4l2_control *)arg);
}
diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c
index 47b36ae..4012fec 100644
--- a/drivers/media/video/v4l2-ctrls.c
+++ b/drivers/media/video/v4l2-ctrls.c
@@ -252,6 +252,7 @@
static const char * const header_mode[] = {
"Separate Buffer",
"Joined With 1st Frame",
+ "Joined With I-Frames",
NULL,
};
static const char * const multi_slice[] = {
diff --git a/drivers/media/video/vcap_vp.c b/drivers/media/video/vcap_vp.c
index 5161b7b..06891899 100644
--- a/drivers/media/video/vcap_vp.c
+++ b/drivers/media/video/vcap_vp.c
@@ -166,17 +166,22 @@
void update_nr_value(struct vcap_dev *dev)
{
struct nr_param *par;
+ uint32_t val = 0;
par = &dev->nr_param;
if (par->mode == NR_MANUAL) {
writel_relaxed(par->window << 24 | par->decay_ratio << 20,
VCAP_VP_NR_CONFIG);
- writel_relaxed(par->luma.max_blend_ratio << 24 |
+ if (par->threshold)
+ val = VP_NR_DYNAMIC_THRESHOLD;
+ writel_relaxed(val |
+ par->luma.max_blend_ratio << 24 |
par->luma.scale_diff_ratio << 12 |
par->luma.diff_limit_ratio << 8 |
par->luma.scale_motion_ratio << 4 |
par->luma.blend_limit_ratio << 0,
VCAP_VP_NR_LUMA_CONFIG);
- writel_relaxed(par->chroma.max_blend_ratio << 24 |
+ writel_relaxed(val |
+ par->chroma.max_blend_ratio << 24 |
par->chroma.scale_diff_ratio << 12 |
par->chroma.diff_limit_ratio << 8 |
par->chroma.scale_motion_ratio << 4 |
@@ -646,6 +651,9 @@
param->decay_ratio = BITS_VALUE(rc, 20, 3);
rc = readl_relaxed(VCAP_VP_NR_LUMA_CONFIG);
+ param->threshold = NR_THRESHOLD_STATIC;
+ if (BITS_VALUE(rc, 16, 1))
+ param->threshold = NR_THRESHOLD_DYNAMIC;
param->luma.max_blend_ratio = BITS_VALUE(rc, 24, 4);
param->luma.scale_diff_ratio = BITS_VALUE(rc, 12, 4);
param->luma.diff_limit_ratio = BITS_VALUE(rc, 8, 4);
@@ -662,6 +670,7 @@
void s_default_nr_val(struct nr_param *param)
{
+ param->threshold = NR_THRESHOLD_STATIC;
param->window = 10;
param->decay_ratio = 0;
param->luma.max_blend_ratio = 0;
diff --git a/drivers/media/video/vcap_vp.h b/drivers/media/video/vcap_vp.h
index 2ad5848..70b10c3 100644
--- a/drivers/media/video/vcap_vp.h
+++ b/drivers/media/video/vcap_vp.h
@@ -90,6 +90,7 @@
#define VP_NR_MAX_WINDOW 120
#define VP_NR_MAX_RATIO 16
+#define VP_NR_DYNAMIC_THRESHOLD 0x000F0000
#define BITS_MASK(start, num_of_bits) \
(((1 << (num_of_bits)) - 1) << (start))
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index fa7c116..d43b399 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -37,6 +37,14 @@
#define SITAR_I2C_MODE 0x01
#define CODEC_DT_MAX_PROP_SIZE 40
#define WCD9XXX_I2C_GSBI_SLAVE_ID "3-000d"
+#define WCD9XXX_I2C_TOP_SLAVE_ADDR 0x0d
+#define WCD9XXX_ANALOG_I2C_SLAVE_ADDR 0x77
+#define WCD9XXX_DIGITAL1_I2C_SLAVE_ADDR 0x66
+#define WCD9XXX_DIGITAL2_I2C_SLAVE_ADDR 0x55
+#define WCD9XXX_I2C_TOP_LEVEL 0
+#define WCD9XXX_I2C_ANALOG 1
+#define WCD9XXX_I2C_DIGITAL_1 2
+#define WCD9XXX_I2C_DIGITAL_2 3
struct wcd9xxx_i2c {
struct i2c_client *client;
@@ -644,10 +652,11 @@
kfree(wcd9xxx->supplies);
}
-int wcd9xxx_get_intf_type(void)
+enum wcd9xxx_intf_status wcd9xxx_get_intf_type(void)
{
return wcd9xxx_intf;
}
+
EXPORT_SYMBOL_GPL(wcd9xxx_get_intf_type);
struct wcd9xxx_i2c *get_i2c_wcd9xxx_device_info(u16 reg)
@@ -768,100 +777,146 @@
return wcd9xxx_i2c_write_device(reg, src, bytes);
}
+static int wcd9xxx_i2c_get_client_index(struct i2c_client *client,
+ int *wcd9xx_index)
+{
+ int ret = 0;
+ switch (client->addr) {
+ case WCD9XXX_I2C_TOP_SLAVE_ADDR:
+ *wcd9xx_index = WCD9XXX_I2C_TOP_LEVEL;
+ break;
+ case WCD9XXX_ANALOG_I2C_SLAVE_ADDR:
+ *wcd9xx_index = WCD9XXX_I2C_ANALOG;
+ break;
+ case WCD9XXX_DIGITAL1_I2C_SLAVE_ADDR:
+ *wcd9xx_index = WCD9XXX_I2C_DIGITAL_1;
+ break;
+ case WCD9XXX_DIGITAL2_I2C_SLAVE_ADDR:
+ *wcd9xx_index = WCD9XXX_I2C_DIGITAL_2;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
static int __devinit wcd9xxx_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct wcd9xxx *wcd9xxx;
- struct wcd9xxx_pdata *pdata;
+ struct wcd9xxx *wcd9xxx = NULL;
+ struct wcd9xxx_pdata *pdata = NULL;
int val = 0;
int ret = 0;
int i2c_mode = 0;
- static int device_id;
+ int wcd9xx_index = 0;
struct device *dev;
- pr_info("%s\n", __func__);
+ pr_debug("%s: interface status %d\n", __func__, wcd9xxx_intf);
if (wcd9xxx_intf == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
dev_dbg(&client->dev, "%s:Codec is detected in slimbus mode\n",
- __func__);
+ __func__);
return -ENODEV;
- }
- if (device_id > 0) {
- wcd9xxx_modules[device_id++].client = client;
- dev_dbg(&client->dev, "%s:probe for other slaves\n"
- "devices of codec\n", __func__);
+ } else if (wcd9xxx_intf == WCD9XXX_INTERFACE_TYPE_I2C) {
+ ret = wcd9xxx_i2c_get_client_index(client, &wcd9xx_index);
+ if (ret != 0)
+ dev_err(&client->dev, "%s: I2C set codec I2C\n"
+ "client failed\n", __func__);
+ else {
+ dev_err(&client->dev, "%s:probe for other slaves\n"
+ "devices of codec I2C slave Addr = %x\n",
+ __func__, client->addr);
+ wcd9xxx_modules[wcd9xx_index].client = client;
+ }
return ret;
- }
- dev = &client->dev;
- if (client->dev.of_node) {
- dev_dbg(&client->dev, "%s:Platform data from device tree\n",
- __func__);
- pdata = wcd9xxx_populate_dt_pdata(&client->dev);
- client->dev.platform_data = pdata;
- } else {
- dev_dbg(&client->dev, "%s:Platform data from board file\n",
- __func__);
- pdata = client->dev.platform_data;
- }
- wcd9xxx = kzalloc(sizeof(struct wcd9xxx), GFP_KERNEL);
- if (wcd9xxx == NULL) {
- pr_err("%s: error, allocation failed\n", __func__);
- ret = -ENOMEM;
- goto fail;
- }
+ } else if (wcd9xxx_intf == WCD9XXX_INTERFACE_TYPE_PROBING) {
+ dev = &client->dev;
+ if (client->dev.of_node) {
+ dev_dbg(&client->dev, "%s:Platform data\n"
+ "from device tree\n", __func__);
+ pdata = wcd9xxx_populate_dt_pdata(&client->dev);
+ client->dev.platform_data = pdata;
+ } else {
+ dev_dbg(&client->dev, "%s:Platform data from\n"
+ "board file\n", __func__);
+ pdata = client->dev.platform_data;
+ }
+ wcd9xxx = kzalloc(sizeof(struct wcd9xxx), GFP_KERNEL);
+ if (wcd9xxx == NULL) {
+ pr_err("%s: error, allocation failed\n", __func__);
+ ret = -ENOMEM;
+ goto fail;
+ }
- if (!pdata) {
- dev_dbg(&client->dev, "no platform data?\n");
- ret = -EINVAL;
- goto fail;
- }
- if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
- dev_dbg(&client->dev, "can't talk I2C?\n");
- ret = -EIO;
- goto fail;
- }
- dev_set_drvdata(&client->dev, wcd9xxx);
- wcd9xxx->dev = &client->dev;
- wcd9xxx->reset_gpio = pdata->reset_gpio;
- ret = wcd9xxx_enable_supplies(wcd9xxx, pdata);
- if (ret) {
- pr_err("%s: Fail to enable Codec supplies\n", __func__);
- goto err_codec;
- }
+ if (!pdata) {
+ dev_dbg(&client->dev, "no platform data?\n");
+ ret = -EINVAL;
+ goto fail;
+ }
+ if (i2c_check_functionality(client->adapter,
+ I2C_FUNC_I2C) == 0) {
+ dev_dbg(&client->dev, "can't talk I2C?\n");
+ ret = -EIO;
+ goto fail;
+ }
+ dev_set_drvdata(&client->dev, wcd9xxx);
+ wcd9xxx->dev = &client->dev;
+ wcd9xxx->reset_gpio = pdata->reset_gpio;
+ if (client->dev.of_node)
+ wcd9xxx->mclk_rate = pdata->mclk_rate;
+ ret = wcd9xxx_enable_supplies(wcd9xxx, pdata);
+ if (ret) {
+ pr_err("%s: Fail to enable Codec supplies\n",
+ __func__);
+ goto err_codec;
+ }
- usleep_range(5, 5);
- ret = wcd9xxx_reset(wcd9xxx);
- if (ret) {
- pr_err("%s: Resetting Codec failed\n", __func__);
+ usleep_range(5, 5);
+ ret = wcd9xxx_reset(wcd9xxx);
+ if (ret) {
+ pr_err("%s: Resetting Codec failed\n", __func__);
goto err_supplies;
- }
- wcd9xxx_modules[device_id++].client = client;
+ }
- wcd9xxx->read_dev = wcd9xxx_i2c_read;
- wcd9xxx->write_dev = wcd9xxx_i2c_write;
- if (!wcd9xxx->dev->of_node) {
- wcd9xxx->irq = pdata->irq;
- wcd9xxx->irq_base = pdata->irq_base;
- }
+ ret = wcd9xxx_i2c_get_client_index(client, &wcd9xx_index);
+ if (ret != 0) {
+ pr_err("%s:Set codec I2C client failed\n", __func__);
+ goto err_supplies;
+ }
- ret = wcd9xxx_device_init(wcd9xxx);
- if (ret) {
- pr_err("%s: error, initializing device failed\n", __func__);
- goto err_device_init;
- }
+ wcd9xxx_modules[wcd9xx_index].client = client;
+ wcd9xxx->read_dev = wcd9xxx_i2c_read;
+ wcd9xxx->write_dev = wcd9xxx_i2c_write;
+ if (!wcd9xxx->dev->of_node) {
+ wcd9xxx->irq = pdata->irq;
+ wcd9xxx->irq_base = pdata->irq_base;
+ }
- if ((wcd9xxx->idbyte[0] == 0x2) || (wcd9xxx->idbyte[0] == 0x1))
- i2c_mode = TABLA_I2C_MODE;
- else if (wcd9xxx->idbyte[0] == 0x0)
- i2c_mode = SITAR_I2C_MODE;
+ ret = wcd9xxx_device_init(wcd9xxx);
+ if (ret) {
+ pr_err("%s: error, initializing device failed\n",
+ __func__);
+ goto err_device_init;
+ }
- ret = wcd9xxx_read(wcd9xxx, WCD9XXX_A_CHIP_STATUS, 1, &val, 0);
+ if ((wcd9xxx->idbyte[0] == 0x2) || (wcd9xxx->idbyte[0] == 0x1))
+ i2c_mode = TABLA_I2C_MODE;
+ else if (wcd9xxx->idbyte[0] == 0x0)
+ i2c_mode = SITAR_I2C_MODE;
- if ((ret < 0) || (val != i2c_mode))
- pr_err("failed to read the wcd9xxx status ret = %d\n", ret);
+ ret = wcd9xxx_read(wcd9xxx, WCD9XXX_A_CHIP_STATUS, 1, &val, 0);
+
+ if ((ret < 0) || (val != i2c_mode))
+ pr_err("failed to read the wcd9xxx status ret = %d\n",
+ ret);
wcd9xxx_intf = WCD9XXX_INTERFACE_TYPE_I2C;
- return ret;
+ return ret;
+ } else
+ pr_err("%s: I2C probe in wrong state\n", __func__);
+
+
err_device_init:
wcd9xxx_free_reset(wcd9xxx);
err_supplies:
@@ -1087,6 +1142,7 @@
int ret, i;
char **codec_supplies;
u32 num_of_supplies = 0;
+ u32 mclk_rate = 0;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
@@ -1130,6 +1186,19 @@
goto err;
}
dev_dbg(dev, "%s: reset gpio %d", __func__, pdata->reset_gpio);
+ ret = of_property_read_u32(dev->of_node,
+ "qcom,cdc-mclk-clk-rate",
+ &mclk_rate);
+ if (ret) {
+ dev_err(dev, "Looking up %s property in\n"
+ "node %s failed",
+ "qcom,cdc-mclk-clk-rate",
+ dev->of_node->full_name);
+ devm_kfree(dev, pdata);
+ ret = -EINVAL;
+ goto err;
+ }
+ pdata->mclk_rate = mclk_rate;
return pdata;
err:
devm_kfree(dev, pdata);
@@ -1162,6 +1231,11 @@
struct wcd9xxx_pdata *pdata;
int ret = 0;
+ if (wcd9xxx_intf == WCD9XXX_INTERFACE_TYPE_I2C) {
+ dev_dbg(&slim->dev, "%s:Codec is detected in I2C mode\n",
+ __func__);
+ return -ENODEV;
+ }
if (slim->dev.of_node) {
dev_info(&slim->dev, "Platform data from device tree\n");
pdata = wcd9xxx_populate_dt_pdata(&slim->dev);
@@ -1201,6 +1275,7 @@
slim_set_clientdata(slim, wcd9xxx);
wcd9xxx->reset_gpio = pdata->reset_gpio;
wcd9xxx->dev = &slim->dev;
+ wcd9xxx->mclk_rate = pdata->mclk_rate;
ret = wcd9xxx_enable_supplies(wcd9xxx, pdata);
if (ret)
@@ -1477,11 +1552,6 @@
.suspend = wcd9xxx_slim_suspend,
};
-#define WCD9XXX_I2C_TOP_LEVEL 0
-#define WCD9XXX_I2C_ANALOG 1
-#define WCD9XXX_I2C_DIGITAL_1 2
-#define WCD9XXX_I2C_DIGITAL_2 3
-
static struct i2c_device_id wcd9xxx_id_table[] = {
{"wcd9xxx-i2c", WCD9XXX_I2C_TOP_LEVEL},
{"wcd9xxx-i2c", WCD9XXX_I2C_ANALOG},
@@ -1528,6 +1598,8 @@
{
int ret1, ret2, ret3, ret4, ret5, ret6, ret7;
+ wcd9xxx_intf = WCD9XXX_INTERFACE_TYPE_PROBING;
+
ret1 = slim_driver_register(&tabla_slim_driver);
if (ret1 != 0)
pr_err("Failed to register tabla SB driver: %d\n", ret1);
diff --git a/drivers/misc/isa1200.c b/drivers/misc/isa1200.c
index 6c3e787..604ffd7 100644
--- a/drivers/misc/isa1200.c
+++ b/drivers/misc/isa1200.c
@@ -42,7 +42,7 @@
struct hrtimer timer;
struct timed_output_dev dev;
struct work_struct work;
- spinlock_t lock;
+ struct mutex lock;
unsigned int enable;
unsigned int period_ns;
bool is_len_gpio_valid;
@@ -216,9 +216,8 @@
{
struct isa1200_chip *haptic = container_of(dev, struct isa1200_chip,
dev);
- unsigned long flags;
- spin_lock_irqsave(&haptic->lock, flags);
+ mutex_lock(&haptic->lock);
hrtimer_cancel(&haptic->timer);
if (value == 0)
haptic->enable = 0;
@@ -230,7 +229,7 @@
ktime_set(value / 1000, (value % 1000) * 1000000),
HRTIMER_MODE_REL);
}
- spin_unlock_irqrestore(&haptic->lock, flags);
+ mutex_unlock(&haptic->lock);
schedule_work(&haptic->work);
}
@@ -501,7 +500,7 @@
}
}
- spin_lock_init(&haptic->lock);
+ mutex_init(&haptic->lock);
INIT_WORK(&haptic->work, isa1200_chip_work);
haptic->clk_on = false;
@@ -591,6 +590,7 @@
hen_gpio_fail:
timed_output_dev_unregister(&haptic->dev);
timed_reg_fail:
+ mutex_destroy(&haptic->lock);
if (pdata->power_on)
pdata->power_on(0);
pwr_up_fail:
@@ -637,6 +637,9 @@
ISA1200_HCTRL1_RESET);
+ /* destroy mutex */
+ mutex_destroy(&haptic->lock);
+
/* power-off the chip */
if (haptic->pdata->regulator_info) {
isa1200_reg_power(haptic, false);
diff --git a/drivers/misc/smsc_hub.c b/drivers/misc/smsc_hub.c
index bde25d9..31f18ed 100644
--- a/drivers/misc/smsc_hub.c
+++ b/drivers/misc/smsc_hub.c
@@ -16,6 +16,9 @@
#include <linux/regulator/consumer.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/of_device.h>
+#include <linux/clk.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/smsc3503.h>
@@ -28,12 +31,16 @@
SMSC3503_I2C_ADDR, I2C_CLIENT_END };
struct hsic_hub {
- struct regulator *hsic_hub_reg;
struct device *dev;
+ struct smsc_hub_platform_data *pdata;
struct i2c_client *client;
struct msm_xo_voter *xo_handle;
+ struct clk *ref_clk;
+ struct regulator *hsic_hub_reg;
+ struct regulator *int_pad_reg, *hub_vbus_reg;
};
static struct hsic_hub *smsc_hub;
+static struct platform_driver smsc_hub_driver;
/* APIs for setting/clearing bits and for reading/writing values */
static inline int hsic_hub_get_u8(struct i2c_client *client, u8 reg)
@@ -150,16 +157,208 @@
.id_table = hsic_hub_id,
};
+static int msm_hsic_hub_init_clock(struct hsic_hub *hub, int init)
+{
+ int ret;
+
+ if (!init) {
+ if (!IS_ERR(hub->ref_clk))
+ clk_disable_unprepare(hub->ref_clk);
+ else
+ msm_xo_put(smsc_hub->xo_handle);
+
+ return 0;
+ }
+
+ hub->ref_clk = devm_clk_get(hub->dev, "ref_clk");
+ if (IS_ERR(hub->ref_clk)) {
+ dev_dbg(hub->dev, "failed to get ref_clk\n");
+
+ /* In the absence of dedicated ref_clk, xo clocks the HUB */
+ smsc_hub->xo_handle = msm_xo_get(MSM_XO_TCXO_D1, "hsic_hub");
+ if (IS_ERR(smsc_hub->xo_handle)) {
+ dev_err(hub->dev, "not able to get the handle\n"
+ "for TCXO D1 buffer\n");
+ return PTR_ERR(smsc_hub->xo_handle);
+ }
+
+ ret = msm_xo_mode_vote(smsc_hub->xo_handle, MSM_XO_MODE_ON);
+ if (ret) {
+ dev_err(hub->dev, "failed to vote for TCXO\n"
+ "D1 buffer\n");
+ msm_xo_put(smsc_hub->xo_handle);
+ return ret;
+ }
+ } else {
+ ret = clk_prepare_enable(hub->ref_clk);
+ if (ret)
+ dev_err(hub->dev, "clk_enable failed for ref_clk\n");
+ }
+
+ return ret;
+}
+#define HSIC_HUB_INT_VOL_MIN 1800000 /* uV */
+#define HSIC_HUB_INT_VOL_MAX 2950000 /* uV */
+static int msm_hsic_hub_init_gpio(struct hsic_hub *hub, int init)
+{
+ int ret;
+ struct smsc_hub_platform_data *pdata = hub->pdata;
+
+ if (!init) {
+ if (!IS_ERR(smsc_hub->int_pad_reg)) {
+ regulator_disable(smsc_hub->int_pad_reg);
+ regulator_set_voltage(smsc_hub->int_pad_reg, 0,
+ HSIC_HUB_INT_VOL_MAX);
+ }
+ return 0;
+ }
+
+ ret = devm_gpio_request(hub->dev, pdata->hub_reset, "HSIC_HUB_RESET");
+ if (ret < 0) {
+ dev_err(hub->dev, "gpio request failed for GPIO%d\n",
+ pdata->hub_reset);
+ return ret;
+ }
+
+ if (pdata->refclk_gpio) {
+ ret = devm_gpio_request(hub->dev, pdata->refclk_gpio,
+ "HSIC_HUB_CLK");
+ if (ret < 0)
+ dev_err(hub->dev, "gpio request failed (CLK GPIO)\n");
+ }
+
+ if (pdata->int_gpio) {
+ ret = devm_gpio_request(hub->dev, pdata->int_gpio,
+ "HSIC_HUB_INT");
+ if (ret < 0) {
+ dev_err(hub->dev, "gpio request failed (INT GPIO)\n");
+ return ret;
+ }
+
+ /* Enable LDO if required for external pull-up */
+ smsc_hub->int_pad_reg = devm_regulator_get(hub->dev, "hub_int");
+ if (IS_ERR(smsc_hub->int_pad_reg)) {
+ dev_dbg(hub->dev, "unable to get ext hub_int reg\n");
+ } else {
+ ret = regulator_set_voltage(smsc_hub->int_pad_reg,
+ HSIC_HUB_INT_VOL_MIN,
+ HSIC_HUB_INT_VOL_MAX);
+ if (ret) {
+ dev_err(hub->dev, "unable to set the voltage\n"
+ " for hsic hub int reg\n");
+ return ret;
+ }
+ ret = regulator_enable(smsc_hub->int_pad_reg);
+ if (ret) {
+ dev_err(hub->dev, "unable to enable int reg\n");
+ regulator_set_voltage(smsc_hub->int_pad_reg, 0,
+ HSIC_HUB_INT_VOL_MAX);
+ return ret;
+ }
+ }
+ }
+
+ return 0;
+}
+
#define HSIC_HUB_VDD_VOL_MIN 1650000 /* uV */
#define HSIC_HUB_VDD_VOL_MAX 1950000 /* uV */
#define HSIC_HUB_VDD_LOAD 36000 /* uA */
+static int msm_hsic_hub_init_vdd(struct hsic_hub *hub, int init)
+{
+ int ret;
+
+ if (!init) {
+ if (!IS_ERR(smsc_hub->hsic_hub_reg)) {
+ regulator_disable(smsc_hub->hsic_hub_reg);
+ regulator_set_optimum_mode(smsc_hub->hsic_hub_reg, 0);
+ regulator_set_voltage(smsc_hub->hsic_hub_reg, 0,
+ HSIC_HUB_VDD_VOL_MAX);
+ }
+ return 0;
+ }
+
+ smsc_hub->hsic_hub_reg = devm_regulator_get(hub->dev, "EXT_HUB_VDDIO");
+ if (IS_ERR(smsc_hub->hsic_hub_reg)) {
+ dev_dbg(hub->dev, "unable to get ext hub vddcx\n");
+ } else {
+ ret = regulator_set_voltage(smsc_hub->hsic_hub_reg,
+ HSIC_HUB_VDD_VOL_MIN,
+ HSIC_HUB_VDD_VOL_MAX);
+ if (ret) {
+ dev_err(hub->dev, "unable to set the voltage\n"
+ "for hsic hub reg\n");
+ return ret;
+ }
+
+ ret = regulator_set_optimum_mode(smsc_hub->hsic_hub_reg,
+ HSIC_HUB_VDD_LOAD);
+ if (ret < 0) {
+ dev_err(hub->dev, "Unable to set mode of VDDCX\n");
+ goto reg_optimum_mode_fail;
+ }
+
+ ret = regulator_enable(smsc_hub->hsic_hub_reg);
+ if (ret) {
+ dev_err(hub->dev, "unable to enable ext hub vddcx\n");
+ goto reg_enable_fail;
+ }
+ }
+
+ return 0;
+
+reg_enable_fail:
+ regulator_set_optimum_mode(smsc_hub->hsic_hub_reg, 0);
+reg_optimum_mode_fail:
+ regulator_set_voltage(smsc_hub->hsic_hub_reg, 0,
+ HSIC_HUB_VDD_VOL_MAX);
+
+ return ret;
+}
+struct smsc_hub_platform_data *msm_hub_dt_to_pdata(
+ struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct smsc_hub_platform_data *pdata;
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ dev_err(&pdev->dev, "unable to allocate platform data\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ pdata->hub_reset = of_get_named_gpio(node, "smsc,reset-gpio", 0);
+ if (pdata->hub_reset < 0)
+ return ERR_PTR(pdata->hub_reset);
+
+ pdata->refclk_gpio = of_get_named_gpio(node, "smsc,refclk-gpio", 0);
+ if (pdata->refclk_gpio < 0)
+ pdata->refclk_gpio = 0;
+
+ pdata->int_gpio = of_get_named_gpio(node, "smsc,int-gpio", 0);
+ if (pdata->int_gpio < 0)
+ pdata->int_gpio = 0;
+
+ return pdata;
+}
+
static int __devinit smsc_hub_probe(struct platform_device *pdev)
{
int ret = 0;
const struct smsc_hub_platform_data *pdata;
+ struct device_node *node = pdev->dev.of_node;
struct i2c_adapter *i2c_adap;
struct i2c_board_info i2c_info;
+ if (pdev->dev.of_node) {
+ dev_dbg(&pdev->dev, "device tree enabled\n");
+ pdev->dev.platform_data = msm_hub_dt_to_pdata(pdev);
+ if (IS_ERR(pdev->dev.platform_data))
+ return PTR_ERR(pdev->dev.platform_data);
+
+ dev_set_name(&pdev->dev, smsc_hub_driver.driver.name);
+ }
+
if (!pdev->dev.platform_data) {
dev_err(&pdev->dev, "No platform data\n");
return -ENODEV;
@@ -169,59 +368,34 @@
if (!pdata->hub_reset)
return -EINVAL;
- smsc_hub = kzalloc(sizeof(*smsc_hub), GFP_KERNEL);
+ smsc_hub = devm_kzalloc(&pdev->dev, sizeof(*smsc_hub), GFP_KERNEL);
if (!smsc_hub)
return -ENOMEM;
- smsc_hub->hsic_hub_reg = regulator_get(&pdev->dev, "EXT_HUB_VDDIO");
- if (IS_ERR(smsc_hub->hsic_hub_reg)) {
- dev_err(&pdev->dev, "unable to get ext hub vddcx\n");
- ret = PTR_ERR(smsc_hub->hsic_hub_reg);
- goto free_mem;
+ smsc_hub->dev = &pdev->dev;
+ smsc_hub->pdata = pdev->dev.platform_data;
+
+ smsc_hub->hub_vbus_reg = devm_regulator_get(&pdev->dev, "hub_vbus");
+ ret = PTR_ERR(smsc_hub->hub_vbus_reg);
+ if (ret == -EPROBE_DEFER) {
+ dev_dbg(&pdev->dev, "failed to get hub_vbus\n");
+ return ret;
}
- ret = gpio_request(pdata->hub_reset, "HSIC_HUB_RESET_GPIO");
- if (ret < 0) {
- dev_err(&pdev->dev, "gpio request failed for GPIO%d\n",
- pdata->hub_reset);
- goto gpio_req_fail;
- }
-
- ret = regulator_set_voltage(smsc_hub->hsic_hub_reg,
- HSIC_HUB_VDD_VOL_MIN,
- HSIC_HUB_VDD_VOL_MAX);
+ ret = msm_hsic_hub_init_vdd(smsc_hub, 1);
if (ret) {
- dev_err(&pdev->dev, "unable to set the voltage"
- "for hsic hub reg\n");
- goto reg_set_voltage_fail;
+ dev_err(&pdev->dev, "failed to init hub VDD\n");
+ return ret;
}
-
- ret = regulator_set_optimum_mode(smsc_hub->hsic_hub_reg,
- HSIC_HUB_VDD_LOAD);
- if (ret < 0) {
- dev_err(&pdev->dev, "Unable to set optimum mode of regulator:"
- "VDDCX\n");
- goto reg_optimum_mode_fail;
- }
-
- ret = regulator_enable(smsc_hub->hsic_hub_reg);
+ ret = msm_hsic_hub_init_clock(smsc_hub, 1);
if (ret) {
- dev_err(&pdev->dev, "unable to enable ext hub vddcx\n");
- goto reg_enable_fail;
+ dev_err(&pdev->dev, "failed to init hub clock\n");
+ goto uninit_vdd;
}
-
- smsc_hub->xo_handle = msm_xo_get(MSM_XO_TCXO_D1, "hsic_hub");
- if (IS_ERR(smsc_hub->xo_handle)) {
- dev_err(&pdev->dev, "not able to get the handle"
- "for TCXO D1 buffer\n");
- goto disable_regulator;
- }
-
- ret = msm_xo_mode_vote(smsc_hub->xo_handle, MSM_XO_MODE_ON);
+ ret = msm_hsic_hub_init_gpio(smsc_hub, 1);
if (ret) {
- dev_err(&pdev->dev, "failed to vote for TCXO"
- "D1 buffer\n");
- goto xo_vote_fail;
+ dev_err(&pdev->dev, "failed to init hub gpios\n");
+ goto uninit_clock;
}
gpio_direction_output(pdata->hub_reset, 0);
@@ -231,6 +405,20 @@
udelay(5);
gpio_direction_output(pdata->hub_reset, 1);
+ ret = of_platform_populate(node, NULL, NULL, &pdev->dev);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add child node, ret=%d\n", ret);
+ goto uninit_gpio;
+ }
+
+ if (!IS_ERR(smsc_hub->hub_vbus_reg)) {
+ ret = regulator_enable(smsc_hub->hub_vbus_reg);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to enable hub_vbus\n");
+ goto uninit_gpio;
+ }
+ }
+
ret = i2c_add_driver(&hsic_hub_driver);
if (ret < 0) {
dev_err(&pdev->dev, "failed to add I2C hsic_hub_driver\n");
@@ -261,21 +449,12 @@
return 0;
-xo_vote_fail:
- msm_xo_put(smsc_hub->xo_handle);
-disable_regulator:
- regulator_disable(smsc_hub->hsic_hub_reg);
-reg_enable_fail:
- regulator_set_optimum_mode(smsc_hub->hsic_hub_reg, 0);
-reg_optimum_mode_fail:
- regulator_set_voltage(smsc_hub->hsic_hub_reg, 0,
- HSIC_HUB_VDD_VOL_MIN);
-reg_set_voltage_fail:
- gpio_free(pdata->hub_reset);
-gpio_req_fail:
- regulator_put(smsc_hub->hsic_hub_reg);
-free_mem:
- kfree(smsc_hub);
+uninit_gpio:
+ msm_hsic_hub_init_gpio(smsc_hub, 0);
+uninit_clock:
+ msm_hsic_hub_init_clock(smsc_hub, 0);
+uninit_vdd:
+ msm_hsic_hub_init_vdd(smsc_hub, 0);
return ret;
}
@@ -291,15 +470,11 @@
i2c_del_driver(&hsic_hub_driver);
}
pm_runtime_disable(&pdev->dev);
- msm_xo_put(smsc_hub->xo_handle);
- regulator_disable(smsc_hub->hsic_hub_reg);
- regulator_set_optimum_mode(smsc_hub->hsic_hub_reg, 0);
- regulator_set_voltage(smsc_hub->hsic_hub_reg, 0,
- HSIC_HUB_VDD_VOL_MIN);
- gpio_free(pdata->hub_reset);
- regulator_put(smsc_hub->hsic_hub_reg);
- kfree(smsc_hub);
+ regulator_disable(smsc_hub->hub_vbus_reg);
+ msm_hsic_hub_init_gpio(smsc_hub, 0);
+ msm_hsic_hub_init_clock(smsc_hub, 0);
+ msm_hsic_hub_init_vdd(smsc_hub, 0);
return 0;
}
@@ -314,24 +489,32 @@
static int smsc_hub_lpm_enter(struct device *dev)
{
- int ret;
+ int ret = 0;
- ret = msm_xo_mode_vote(smsc_hub->xo_handle, MSM_XO_MODE_OFF);
- if (ret) {
- pr_err("%s: failed to devote for TCXO"
- "D1 buffer%d\n", __func__, ret);
+ if (!IS_ERR(smsc_hub->ref_clk)) {
+ clk_disable_unprepare(smsc_hub->ref_clk);
+ } else {
+ ret = msm_xo_mode_vote(smsc_hub->xo_handle, MSM_XO_MODE_OFF);
+ if (ret) {
+ pr_err("%s: failed to devote for TCXO\n"
+ "D1 buffer%d\n", __func__, ret);
+ }
}
return ret;
}
static int smsc_hub_lpm_exit(struct device *dev)
{
- int ret;
+ int ret = 0;
- ret = msm_xo_mode_vote(smsc_hub->xo_handle, MSM_XO_MODE_ON);
- if (ret) {
- pr_err("%s: failed to vote for TCXO"
- "D1 buffer%d\n", __func__, ret);
+ if (!IS_ERR(smsc_hub->ref_clk)) {
+ clk_prepare_enable(smsc_hub->ref_clk);
+ } else {
+ ret = msm_xo_mode_vote(smsc_hub->xo_handle, MSM_XO_MODE_ON);
+ if (ret) {
+ pr_err("%s: failed to vote for TCXO\n"
+ "D1 buffer%d\n", __func__, ret);
+ }
}
return ret;
}
@@ -345,6 +528,13 @@
};
#endif
+static const struct of_device_id hsic_hub_dt_match[] = {
+ { .compatible = "qcom,hsic-smsc-hub",
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, hsic_hub_dt_match);
+
static struct platform_driver smsc_hub_driver = {
.driver = {
.name = "msm_smsc_hub",
@@ -352,13 +542,15 @@
#ifdef CONFIG_PM
.pm = &smsc_hub_dev_pm_ops,
#endif
+ .of_match_table = hsic_hub_dt_match,
},
+ .probe = smsc_hub_probe,
.remove = smsc_hub_remove,
};
static int __init smsc_hub_init(void)
{
- return platform_driver_probe(&smsc_hub_driver, smsc_hub_probe);
+ return platform_driver_register(&smsc_hub_driver);
}
static void __exit smsc_hub_exit(void)
diff --git a/drivers/misc/ti_drv2667.c b/drivers/misc/ti_drv2667.c
index 554799c..d06d336 100644
--- a/drivers/misc/ti_drv2667.c
+++ b/drivers/misc/ti_drv2667.c
@@ -46,7 +46,7 @@
#define DRV2667_FIFO_CHUNK_MS 10
#define DRV2667_BYTES_PER_MS 8
-#define DRV2667_WAV_SEQ_ID_IDX 1
+#define DRV2667_WAV_SEQ_ID_IDX 0
#define DRV2667_WAV_SEQ_REP_IDX 6
#define DRV2667_WAV_SEQ_FREQ_IDX 8
#define DRV2667_WAV_SEQ_FREQ_MIN 8
@@ -128,11 +128,19 @@
data = container_of(work, struct drv2667_data, work);
if (data->mode == WAV_SEQ_MODE) {
- if (data->runtime_left)
- val = data->cntl2_val | DRV2667_GO_MASK;
- else
- val = data->cntl2_val & ~DRV2667_GO_MASK;
+ /* clear go bit */
+ val = data->cntl2_val & ~DRV2667_GO_MASK;
rc = drv2667_write_reg(data->client, DRV2667_CNTL2_REG, val);
+ if (rc < 0) {
+ dev_err(&data->client->dev, "i2c send msg failed\n");
+ return;
+ }
+ /* restart wave if runtime is left */
+ if (data->runtime_left) {
+ val = data->cntl2_val | DRV2667_GO_MASK;
+ rc = drv2667_write_reg(data->client,
+ DRV2667_CNTL2_REG, val);
+ }
} else if (data->mode == FIFO_MODE) {
/* data is played at 8khz */
if (data->runtime_left < data->time_chunk_ms)
@@ -577,8 +585,9 @@
goto vreg_off;
/* program waveform sequence */
- for (reg = 0, i = 1; i < DRV2667_WAV_SEQ_LEN - 1; i++, reg++) {
- rc = drv2667_write_reg(client, reg, pdata->wav_seq[i]);
+ for (reg = 0, i = 0; i < DRV2667_WAV_SEQ_LEN - 1; i++, reg++) {
+ rc = drv2667_write_reg(client, reg,
+ pdata->wav_seq[i+1]);
if (rc < 0)
goto vreg_off;
}
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index f279d8d..751ba75 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -382,7 +382,11 @@
unsigned long value, freq;
int retval = -EINVAL;
- if (!host || !host->card || kstrtoul(buf, 0, &value))
+ if (!host)
+ goto out;
+
+ mmc_claim_host(host);
+ if (!host->card || kstrtoul(buf, 0, &value))
goto err;
if (value && !mmc_can_scale_clk(host)) {
@@ -409,8 +413,10 @@
}
host->clk_scaling.initialized = false;
}
- return count;
+ retval = count;
err:
+ mmc_release_host(host);
+out:
return retval;
}
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 00dc5bf..f3598cf 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -1640,6 +1640,11 @@
spin_lock(&host->lock);
+ if (!atomic_read(&host->clks_on)) {
+ spin_unlock(&host->lock);
+ return IRQ_NONE;
+ }
+
status = readl_relaxed(base + MMCISTATUS);
if (((readl_relaxed(host->base + MMCIMASK0) & status) &
@@ -5104,6 +5109,31 @@
}
}
+/*
+ * This function prints the testbus debug output for all the
+ * available SDCC controller test bus.
+ *
+ * Note: This function should only be called if the SDCC is clocked.
+ */
+static void msmsdcc_print_testbus_info(struct msmsdcc_host *host)
+{
+ int testbus_num;
+
+ if (!is_testbus_debug(host))
+ return;
+
+ pr_err("== SDCC Test Bus Debug ==");
+ for (testbus_num = 0; testbus_num < MAX_TESTBUS; testbus_num++) {
+ writel_relaxed(((testbus_num & MCI_TESTBUS_SEL_MASK)
+ | MCI_TESTBUS_ENA),
+ host->base + MCI_TESTBUS_CONFIG);
+ pr_err("TestBus(%d) = 0x%.8x\n", testbus_num,
+ (u32)readl_relaxed(host->base + MCI_SDCC_DEBUG_REG));
+ }
+ /* Disable the test bus output */
+ writel_relaxed(~MCI_TESTBUS_ENA, host->base + MCI_TESTBUS_CONFIG);
+}
+
static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
{
/* Dump current state of SDCC clocks, power and irq */
@@ -5123,6 +5153,7 @@
pr_err("%s: MCI_TEST_INPUT = 0x%.8x\n",
mmc_hostname(host->mmc),
readl_relaxed(host->base + MCI_TEST_INPUT));
+ msmsdcc_print_testbus_info(host);
}
if (host->curr.data) {
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index 500b5fb..7469c8e 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -193,6 +193,13 @@
#define MCI_TEST_INPUT 0x0D4
+#define MCI_TESTBUS_CONFIG 0x0CC
+#define MCI_TESTBUS_SEL_MASK (0x7)
+#define MAX_TESTBUS 8
+#define MCI_TESTBUS_ENA (1 << 3)
+
+#define MCI_SDCC_DEBUG_REG 0x124
+
#define MCI_IRQENABLE \
(MCI_CMDCRCFAILMASK|MCI_DATACRCFAILMASK|MCI_CMDTIMEOUTMASK| \
MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK| \
@@ -449,6 +456,7 @@
#define MSMSDCC_AUTO_CMD21 (1 << 10)
#define MSMSDCC_SW_RST_CFG_BROKEN (1 << 11)
#define MSMSDCC_DATA_PEND_FOR_CMD53 (1 << 12)
+#define MSMSDCC_TESTBUS_DEBUG (1 << 13)
#define set_hw_caps(h, val) ((h)->hw_caps |= val)
#define is_sps_mode(h) ((h)->hw_caps & MSMSDCC_SPS_BAM_SUP)
@@ -465,6 +473,7 @@
#define is_sw_reset_save_config_broken(h) \
((h)->hw_caps & MSMSDCC_SW_RST_CFG_BROKEN)
#define is_data_pend_for_cmd53(h) ((h)->hw_caps & MSMSDCC_DATA_PEND_FOR_CMD53)
+#define is_testbus_debug(h) ((h)->hw_caps & MSMSDCC_TESTBUS_DEBUG)
/* Set controller capabilities based on version */
static inline void set_default_hw_caps(struct msmsdcc_host *host)
@@ -498,7 +507,8 @@
if (step >= 0x2b) /* SDCC v4 2.1.0 and greater */
host->hw_caps |= MSMSDCC_SW_RST | MSMSDCC_SW_RST_CFG |
MSMSDCC_AUTO_CMD21 |
- MSMSDCC_DATA_PEND_FOR_CMD53;
+ MSMSDCC_DATA_PEND_FOR_CMD53 |
+ MSMSDCC_TESTBUS_DEBUG;
if (step == 0x2b)
host->hw_caps |= MSMSDCC_SW_RST_CFG_BROKEN;
diff --git a/drivers/net/usb/rmnet_usb_ctrl.c b/drivers/net/usb/rmnet_usb_ctrl.c
index f87b3b9..1476bb3 100644
--- a/drivers/net/usb/rmnet_usb_ctrl.c
+++ b/drivers/net/usb/rmnet_usb_ctrl.c
@@ -24,6 +24,7 @@
#define DEVICE_NAME "hsicctl"
#define NUM_CTRL_CHANNELS 4
#define DEFAULT_READ_URB_LENGTH 0x1000
+#define UNLINK_TIMEOUT_MS 500 /*random value*/
/*Output control lines.*/
#define ACM_CTRL_DTR BIT(0)
@@ -535,6 +536,7 @@
struct ctrl_pkt_list_elem *list_elem = NULL;
struct rmnet_ctrl_dev *dev;
unsigned long flag;
+ int time;
dev = file->private_data;
if (!dev)
@@ -558,7 +560,9 @@
dev->is_opened = 0;
mutex_unlock(&dev->dev_lock);
- if (is_dev_connected(dev))
+ time = usb_wait_anchor_empty_timeout(&dev->tx_submitted,
+ UNLINK_TIMEOUT_MS);
+ if (!time)
usb_kill_anchored_urbs(&dev->tx_submitted);
file->private_data = NULL;
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 5806449..715aef2 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -24,32 +24,15 @@
#include <linux/slab.h>
#include <linux/proc_fs.h>
-/**
- * struct alias_prop - Alias property in 'aliases' node
- * @link: List node to link the structure in aliases_lookup list
- * @alias: Alias property name
- * @np: Pointer to device_node that the alias stands for
- * @id: Index value from end of alias name
- * @stem: Alias string without the index
- *
- * The structure represents one alias property of 'aliases' node as
- * an entry in aliases_lookup list.
- */
-struct alias_prop {
- struct list_head link;
- const char *alias;
- struct device_node *np;
- int id;
- char stem[0];
-};
+#include "of_private.h"
-static LIST_HEAD(aliases_lookup);
+LIST_HEAD(aliases_lookup);
struct device_node *allnodes;
struct device_node *of_chosen;
struct device_node *of_aliases;
-static DEFINE_MUTEX(of_aliases_mutex);
+DEFINE_MUTEX(of_aliases_mutex);
/* use when traversing tree through the allnext, child, sibling,
* or parent members of struct device_node.
diff --git a/drivers/of/device.c b/drivers/of/device.c
index 4c74e4f..b8d31db 100644
--- a/drivers/of/device.c
+++ b/drivers/of/device.c
@@ -8,6 +8,7 @@
#include <linux/slab.h>
#include <asm/errno.h>
+#include "of_private.h"
/**
* of_match_device - Tell if a struct device matches an of_device_id list
@@ -131,6 +132,7 @@
void of_device_uevent(struct device *dev, struct kobj_uevent_env *env)
{
const char *compat;
+ struct alias_prop *app;
int seen = 0, cplen, sl;
if ((!dev) || (!dev->of_node))
@@ -153,6 +155,21 @@
seen++;
}
add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen);
+
+ seen = 0;
+ mutex_lock(&of_aliases_mutex);
+ list_for_each_entry(app, &aliases_lookup, link) {
+ if (dev->of_node == app->np) {
+ add_uevent_var(env, "OF_ALIAS_%d=%s", seen,
+ app->alias);
+ seen++;
+ }
+ }
+
+ if (seen)
+ add_uevent_var(env, "OF_ALIAS_N=%d", seen);
+
+ mutex_unlock(&of_aliases_mutex);
}
int of_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env)
diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h
new file mode 100644
index 0000000..b38415c
--- /dev/null
+++ b/drivers/of/of_private.h
@@ -0,0 +1,41 @@
+/*
+ * Procedures for creating, accessing and interpreting the device tree.
+ *
+ * Paul Mackerras August 1996.
+ * Copyright (C) 1996-2005 Paul Mackerras.
+ *
+ * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
+ * {engebret|bergner}@us.ibm.com
+ *
+ * Adapted for sparc and sparc64 by David S. Miller davem@davemloft.net
+ *
+ * Reconsolidated from arch/x/kernel/prom.c by Stephen Rothwell and
+ * Grant Likely.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+/**
+ * struct alias_prop - Alias property in 'aliases' node
+ * @link: List node to link the structure in aliases_lookup list
+ * @alias: Alias property name
+ * @np: Pointer to device_node that the alias stands for
+ * @id: Index value from end of alias name
+ * @stem: Alias string without the index
+ *
+ * The structure represents one alias property of 'aliases' node as
+ * an entry in aliases_lookup list.
+ */
+struct alias_prop {
+ struct list_head link;
+ const char *alias;
+ struct device_node *np;
+ int id;
+ char stem[0];
+};
+
+extern struct mutex of_aliases_mutex;
+extern struct list_head aliases_lookup;
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index 8f97531..6b067e7 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -398,8 +398,8 @@
pr_err("%s: src pipe connection failure\n", __func__);
return ret;
}
+ connection->src_enabled = 1;
}
- connection->src_enabled = 1;
if (dst_pipe_idx) {
/* open Peripheral -> USB pipe */
@@ -409,8 +409,8 @@
pr_err("%s: dst pipe connection failure\n", __func__);
return ret;
}
+ connection->dst_enabled = 1;
}
- connection->dst_enabled = 1;
return 0;
}
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 05b47cc..a8d52b5 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -1800,7 +1800,7 @@
pr_debug("RUC = %duAh\n", remaining_usable_charge_uah);
if (fcc_uah - unusable_charge_uah <= 0) {
- pr_warn("FCC = %duAh, UUC = %duAh forcing soc = 0\n",
+ pr_debug("FCC = %duAh, UUC = %duAh forcing soc = 0\n",
fcc_uah, unusable_charge_uah);
soc = 0;
} else {
@@ -1843,13 +1843,13 @@
soc = 100;
if (soc < 0) {
- pr_err("bad rem_usb_chg = %d rem_chg %d,"
+ pr_debug("bad rem_usb_chg = %d rem_chg %d,"
"cc_uah %d, unusb_chg %d\n",
remaining_usable_charge_uah,
remaining_charge_uah,
cc_uah, unusable_charge_uah);
- pr_err("for bad rem_usb_chg last_ocv_uv = %d"
+ pr_debug("for bad rem_usb_chg last_ocv_uv = %d"
"chargecycles = %d, batt_temp = %d"
"fcc = %d soc =%d\n",
chip->last_ocv_uv, chargecycles, batt_temp,
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index 87e41e6..bd62cf1 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -21,6 +21,7 @@
#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
#include <linux/mfd/pm8xxx/ccadc.h>
#include <linux/mfd/pm8xxx/core.h>
+#include <linux/regulator/consumer.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/bitops.h>
@@ -119,13 +120,6 @@
int batt_state;
};
-static int pm8921_battery_gauge_alarm_notify(struct notifier_block *nb,
- unsigned long status, void *unused);
-
-static struct notifier_block alarm_notifier = {
- .notifier_call = pm8921_battery_gauge_alarm_notify,
-};
-
static struct fsm_state_to_batt_status map[] = {
{FSM_STATE_OFF_0, POWER_SUPPLY_STATUS_UNKNOWN},
{FSM_STATE_BATFETDET_START_12, POWER_SUPPLY_STATUS_UNKNOWN},
@@ -261,10 +255,12 @@
struct dentry *dent;
struct bms_notify bms_notify;
int *usb_trim_table;
+ struct regulator *vreg_xoadc;
bool ext_charging;
bool ext_charge_done;
bool iusb_fine_res;
- bool disable_hw_clock_switching;
+ bool final_kickstart;
+ bool lockup_lpm_wrkarnd;
DECLARE_BITMAP(enabled_irqs, PM_CHG_MAX_INTS);
struct work_struct battery_id_valid_work;
int64_t batt_id_min;
@@ -312,13 +308,67 @@
static struct pm8921_chg_chip *the_chip;
+static DEFINE_SPINLOCK(lpm_lock);
+#define LPM_ENABLE_BIT BIT(2)
+static int pm8921_chg_set_lpm(struct pm8921_chg_chip *chip, int enable)
+{
+ int rc;
+ u8 reg;
+
+ rc = pm8xxx_readb(chip->dev->parent, CHG_CNTRL, ®);
+ if (rc) {
+ pr_err("pm8xxx_readb failed: addr=%03X, rc=%d\n",
+ CHG_CNTRL, rc);
+ return rc;
+ }
+ reg &= ~LPM_ENABLE_BIT;
+ reg |= (enable ? LPM_ENABLE_BIT : 0);
+
+ rc = pm8xxx_writeb(chip->dev->parent, CHG_CNTRL, reg);
+ if (rc) {
+ pr_err("pm_chg_write failed: addr=%03X, rc=%d\n",
+ CHG_CNTRL, rc);
+ return rc;
+ }
+
+ return rc;
+}
+
static int pm_chg_write(struct pm8921_chg_chip *chip, u16 addr, u8 reg)
{
int rc;
+ unsigned long flags = 0;
+
+ /* Disable LPM */
+ if (chip->lockup_lpm_wrkarnd) {
+ spin_lock_irqsave(&lpm_lock, flags);
+
+ /*
+ * This write could have initiated right after a previous write.
+ * Allow time to settle to go in to lpm from the previous write
+ */
+ udelay(200);
+ rc = pm8921_chg_set_lpm(chip, 0);
+ if (rc)
+ goto lpm_err;
+
+ /* Wait to come out of LPM */
+ udelay(200);
+ }
rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
- if (rc)
+ if (rc) {
pr_err("pm_chg_write failed: addr=%03X, rc=%d\n", addr, rc);
+ goto lpm_err;
+ }
+
+ /* Enable LPM */
+ if (chip->lockup_lpm_wrkarnd)
+ rc = pm8921_chg_set_lpm(chip, 1);
+
+lpm_err:
+ if (chip->lockup_lpm_wrkarnd)
+ spin_unlock_irqrestore(&lpm_lock, flags);
return rc;
}
@@ -350,6 +400,23 @@
chip->pmic_chg_irq[irq_id]);
}
+static int is_chg_on_bat(struct pm8921_chg_chip *chip)
+{
+ return !(pm_chg_get_rt_status(chip, DCIN_VALID_IRQ)
+ || pm_chg_get_rt_status(chip, USBIN_VALID_IRQ));
+}
+
+static void pm8921_chg_bypass_bat_gone_debounce(struct pm8921_chg_chip *chip,
+ int bypass)
+{
+ int rc;
+
+ rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, bypass ? 0x89 : 0x88);
+ if (rc) {
+ pr_err("Failed to set bypass bit to %d rc=%d\n", bypass, rc);
+ }
+}
+
/* Treat OverVoltage/UnderVoltage as source missing */
static int is_usb_chg_plugged_in(struct pm8921_chg_chip *chip)
{
@@ -1977,8 +2044,7 @@
if (disable) {
pr_warn("Disabling input current limit!\n");
- return pm_chg_write(the_chip,
- CHG_BUCK_CTRL_TEST3, 0xF2);
+ return pm_chg_write(the_chip, CHG_BUCK_CTRL_TEST3, 0xF2);
}
return 0;
}
@@ -2163,76 +2229,86 @@
return get_prop_batt_temp(the_chip);
}
-static int pm8921_charger_enable_batt_alarm(struct pm8921_chg_chip *chip)
+static int pm8921_apply_19p2mhz_kickstart(struct pm8921_chg_chip *chip)
{
- int rc = 0;
+ int err;
+ u8 temp;
+ unsigned long flags = 0;
- rc = pm8xxx_batt_alarm_disable(PM8XXX_BATT_ALARM_UPPER_COMPARATOR);
- if (!rc)
- rc = pm8xxx_batt_alarm_enable(
- PM8XXX_BATT_ALARM_LOWER_COMPARATOR);
- if (rc) {
- pr_err("unable to set batt alarm state rc=%d\n", rc);
- return rc;
+ spin_lock_irqsave(&lpm_lock, flags);
+ err = pm8921_chg_set_lpm(chip, 0);
+ if (err) {
+ pr_err("Error settig LPM rc=%d\n", err);
+ goto kick_err;
}
- return rc;
-}
-static int pm8921_charger_configure_batt_alarm(struct pm8921_chg_chip *chip)
-{
- int rc = 0;
-
- rc = pm8xxx_batt_alarm_disable(PM8XXX_BATT_ALARM_UPPER_COMPARATOR);
- if (!rc)
- rc = pm8xxx_batt_alarm_disable(
- PM8XXX_BATT_ALARM_LOWER_COMPARATOR);
- if (rc) {
- pr_err("unable to set batt alarm state rc=%d\n", rc);
- return rc;
+ temp = 0xD1;
+ err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
+ if (err) {
+ pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
+ goto kick_err;
}
- /*
- * The batt-alarm driver requires sane values for both min / max,
- * regardless of whether they're both activated.
- */
- rc = pm8xxx_batt_alarm_threshold_set(
- PM8XXX_BATT_ALARM_LOWER_COMPARATOR,
- chip->alarm_low_mv);
- if (!rc)
- rc = pm8xxx_batt_alarm_threshold_set(
- PM8XXX_BATT_ALARM_UPPER_COMPARATOR,
- chip->alarm_high_mv);
- if (rc) {
- pr_err("unable to set batt alarm threshold rc=%d\n", rc);
- return rc;
+ temp = 0xD3;
+ err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
+ if (err) {
+ pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
+ goto kick_err;
}
- rc = pm8xxx_batt_alarm_hold_time_set(
- PM8XXX_BATT_ALARM_HOLD_TIME_16_MS);
- if (rc) {
- pr_err("unable to set batt alarm hold time rc=%d\n", rc);
- return rc;
+ temp = 0xD1;
+ err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
+ if (err) {
+ pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
+ goto kick_err;
}
- /* PWM enabled at 2Hz */
- rc = pm8xxx_batt_alarm_pwm_rate_set(1, 7, 4);
- if (rc) {
- pr_err("unable to set batt alarm pwm rate rc=%d\n", rc);
- return rc;
+ temp = 0xD5;
+ err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
+ if (err) {
+ pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
+ goto kick_err;
}
- rc = pm8xxx_batt_alarm_register_notifier(&alarm_notifier);
- if (rc) {
- pr_err("unable to register alarm notifier rc=%d\n", rc);
- return rc;
+ /* Wait a few clock cycles before re-enabling hw clock switching */
+ udelay(183);
+
+ temp = 0xD1;
+ err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
+ if (err) {
+ pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
+ goto kick_err;
}
- return rc;
+ temp = 0xD0;
+ err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
+ if (err) {
+ pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
+ goto kick_err;
+ }
+
+ /* Wait for few clock cycles before re-enabling LPM */
+ udelay(32);
+
+kick_err:
+ err = pm8921_chg_set_lpm(chip, 1);
+ if (err)
+ pr_err("Error settig LPM rc=%d\n", err);
+
+ spin_unlock_irqrestore(&lpm_lock, flags);
+
+ return err;
}
static void handle_usb_insertion_removal(struct pm8921_chg_chip *chip)
{
- int usb_present;
+ int usb_present, rc = 0;
+
+ if (chip->lockup_lpm_wrkarnd) {
+ rc = pm8921_apply_19p2mhz_kickstart(chip);
+ if (rc)
+ pr_err("Failed to apply kickstart rc=%d\n", rc);
+ }
pm_chg_failed_clear(chip, 1);
usb_present = is_usb_chg_plugged_in(chip);
@@ -2242,6 +2318,11 @@
power_supply_changed(&chip->usb_psy);
power_supply_changed(&chip->batt_psy);
pm8921_bms_calibrate_hkadc();
+
+ /* Enable/disable bypass if charger is on battery */
+ if (chip->lockup_lpm_wrkarnd)
+ pm8921_chg_bypass_bat_gone_debounce(chip,
+ is_chg_on_bat(chip));
}
if (usb_present) {
schedule_delayed_work(&chip->unplug_check_work,
@@ -2257,6 +2338,10 @@
static void handle_stop_ext_chg(struct pm8921_chg_chip *chip)
{
+ if (chip->lockup_lpm_wrkarnd)
+ /* Enable bypass if charger is on battery */
+ pm8921_chg_bypass_bat_gone_debounce(chip, is_chg_on_bat(chip));
+
if (!chip->ext_psy) {
pr_debug("external charger not registered.\n");
return;
@@ -2283,10 +2368,13 @@
int dc_present;
int batt_present;
int batt_temp_ok;
- int vbat_ov;
unsigned long delay =
round_jiffies_relative(msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
+ /* Disable bypass if charger connected and not running on bat */
+ if (chip->lockup_lpm_wrkarnd)
+ pm8921_chg_bypass_bat_gone_debounce(chip, is_chg_on_bat(chip));
+
if (!chip->ext_psy) {
pr_debug("external charger not registered.\n");
return;
@@ -2297,7 +2385,7 @@
return;
}
- dc_present = is_dc_chg_plugged_in(the_chip);
+ dc_present = is_dc_chg_plugged_in(chip);
batt_present = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
batt_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
@@ -2317,12 +2405,6 @@
/* Force BATFET=ON */
pm8921_disable_source_current(true);
- vbat_ov = pm_chg_get_rt_status(chip, VBAT_OV_IRQ);
- if (vbat_ov) {
- pr_warn("%s. battery over voltage.\n", __func__);
- return;
- }
-
schedule_delayed_work(&chip->unplug_check_work,
msecs_to_jiffies(UNPLUG_CHECK_RAMP_MS));
@@ -2353,78 +2435,23 @@
rc = pm_chg_write(chip, ovptestreg, 0x30);
if (rc) {
- pr_err("Failed to write 0x30 to OVP_TEST rc = %d\n", rc);
+ pr_err("Failed to write 0x30 to ovptestreg rc = %d\n", rc);
return;
}
rc = pm8xxx_readb(chip->dev->parent, ovptestreg, &temp);
if (rc) {
- pr_err("Failed to read from OVP_TEST rc = %d\n", rc);
+ pr_err("Failed to read from ovptestreg rc = %d\n", rc);
return;
}
/* set ovp fet disable bit and the write bit */
temp |= 0x81;
rc = pm_chg_write(chip, ovptestreg, temp);
if (rc) {
- pr_err("Failed to write 0x%x OVP_TEST rc=%d\n", temp, rc);
+ pr_err("Failed to write 0x%x ovptestreg rc=%d\n", temp, rc);
return;
}
}
-static int pm8921_battery_gauge_alarm_notify(struct notifier_block *nb,
- unsigned long status, void *unused)
-{
- int rc;
-
- pr_info("status: %lu\n", status);
-
- /* Check if called before init */
-
- switch (status) {
- case 0:
- pr_err("spurious interrupt\n");
- break;
- /* expected case - trip of low threshold */
- case 1:
- if (!the_chip) {
- pr_err("not initialized\n");
- return -EINVAL;
- }
-
- the_chip->disable_hw_clock_switching = 1;
-
- rc = pm8xxx_batt_alarm_disable(
- PM8XXX_BATT_ALARM_LOWER_COMPARATOR);
- if (!rc)
- rc = pm8xxx_batt_alarm_enable(
- PM8XXX_BATT_ALARM_UPPER_COMPARATOR);
- if (rc)
- pr_err("unable to set alarm state rc=%d\n", rc);
- break;
- case 2:
- if (!the_chip) {
- pr_err("not initialized\n");
- return -EINVAL;
- }
-
- the_chip->disable_hw_clock_switching = 0;
-
- rc = pm8xxx_batt_alarm_disable(
- PM8XXX_BATT_ALARM_UPPER_COMPARATOR);
- if (!rc)
- rc = pm8xxx_batt_alarm_enable(
- PM8XXX_BATT_ALARM_LOWER_COMPARATOR);
- if (rc)
- pr_err("unable to set alarm state rc=%d\n", rc);
-
- pr_err("trip of high threshold\n");
- break;
- default:
- pr_err("error received\n");
- };
-
- return 0;
-}
-
static void turn_on_ovp_fet(struct pm8921_chg_chip *chip, u16 ovptestreg)
{
u8 temp;
@@ -2656,12 +2683,6 @@
return IRQ_HANDLED;
}
-static irqreturn_t vbat_ov_irq_handler(int irq, void *data)
-{
- pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
- return IRQ_HANDLED;
-}
-
static irqreturn_t chgwdog_irq_handler(int irq, void *data)
{
pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
@@ -2790,20 +2811,18 @@
struct delayed_work *dwork = to_delayed_work(work);
struct pm8921_chg_chip *chip = container_of(dwork,
struct pm8921_chg_chip, unplug_check_work);
- u8 reg_loop, active_path;
+ u8 reg_loop = 0, active_path;
int rc, ibat, active_chg_plugged_in, usb_ma;
int chg_gone = 0;
bool ramp = false;
- reg_loop = 0;
-
rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS1, &active_path);
if (rc) {
pr_err("Failed to read PBL_ACCESS1 rc=%d\n", rc);
return;
}
- chip->active_path = active_path;
+ chip->active_path = active_path;
active_chg_plugged_in = is_active_chg_plugged_in(chip, active_path);
pr_debug("active_path = 0x%x, active_chg_plugged_in = %d\n",
active_path, active_chg_plugged_in);
@@ -2830,11 +2849,28 @@
pm_chg_get_fsm_state(chip),
get_prop_batt_current(chip)
);
+ if (chip->lockup_lpm_wrkarnd) {
+ rc = pm8921_apply_19p2mhz_kickstart(chip);
+ if (rc)
+ pr_err("Failed kickstart rc=%d\n", rc);
+
+ /*
+ * Make sure kickstart happens at least 200 ms
+ * after charger has been removed.
+ */
+ if (chip->final_kickstart) {
+ chip->final_kickstart = false;
+ goto check_again_later;
+ }
+ }
return;
} else {
goto check_again_later;
}
}
+
+ chip->final_kickstart = true;
+
/* AICL only for usb wall charger */
if ((active_path & USB_ACTIVE_BIT) && usb_target_ma > 0) {
reg_loop = pm_chg_get_regulation_loop(chip);
@@ -3123,6 +3159,11 @@
else
handle_stop_ext_chg(chip);
} else {
+ if (chip->lockup_lpm_wrkarnd)
+ /* if no external supply call bypass debounce here */
+ pm8921_chg_bypass_bat_gone_debounce(chip,
+ is_chg_on_bat(chip));
+
if (dc_present)
schedule_delayed_work(&chip->unplug_check_work,
msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
@@ -3643,18 +3684,6 @@
goto eoc_worker_stop;
}
- /* If the disable hw clock switching
- * flag was set it can now be unset. Also, re-enable
- * the battery alarm to set the flag again when needed
- */
- if (chip->disable_hw_clock_switching) {
- /* Unset the hw clock switching flag */
- chip->disable_hw_clock_switching = 0;
-
- if (pm8921_charger_enable_batt_alarm(chip))
- pr_err("couldn't set up batt alarm!\n");
- }
-
if (end == CHG_FINISHED) {
count++;
} else {
@@ -3895,7 +3924,6 @@
batt_inserted_irq_handler),
CHG_IRQ(VBATDET_LOW_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
vbatdet_low_irq_handler),
- CHG_IRQ(VBAT_OV_IRQ, IRQF_TRIGGER_RISING, vbat_ov_irq_handler),
CHG_IRQ(CHGWDOG_IRQ, IRQF_TRIGGER_RISING, chgwdog_irq_handler),
CHG_IRQ(VCP_IRQ, IRQF_TRIGGER_RISING, vcp_irq_handler),
CHG_IRQ(ATCDONE_IRQ, IRQF_TRIGGER_RISING, atcdone_irq_handler),
@@ -3967,91 +3995,6 @@
return -EINVAL;
}
-static void pm8921_chg_force_19p2mhz_clk(struct pm8921_chg_chip *chip)
-{
- int err;
- u8 temp;
-
- temp = 0xD1;
- err = pm_chg_write(chip, CHG_TEST, temp);
- if (err) {
- pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
- return;
- }
-
- temp = 0xD3;
- err = pm_chg_write(chip, CHG_TEST, temp);
- if (err) {
- pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
- return;
- }
-
- temp = 0xD1;
- err = pm_chg_write(chip, CHG_TEST, temp);
- if (err) {
- pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
- return;
- }
-
- temp = 0xD5;
- err = pm_chg_write(chip, CHG_TEST, temp);
- if (err) {
- pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
- return;
- }
-
- udelay(183);
-
- temp = 0xD1;
- err = pm_chg_write(chip, CHG_TEST, temp);
- if (err) {
- pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
- return;
- }
-
- temp = 0xD0;
- err = pm_chg_write(chip, CHG_TEST, temp);
- if (err) {
- pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
- return;
- }
- udelay(32);
-
- temp = 0xD1;
- err = pm_chg_write(chip, CHG_TEST, temp);
- if (err) {
- pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
- return;
- }
-
- temp = 0xD3;
- err = pm_chg_write(chip, CHG_TEST, temp);
- if (err) {
- pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
- return;
- }
-}
-
-static void pm8921_chg_set_hw_clk_switching(struct pm8921_chg_chip *chip)
-{
- int err;
- u8 temp;
-
- temp = 0xD1;
- err = pm_chg_write(chip, CHG_TEST, temp);
- if (err) {
- pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
- return;
- }
-
- temp = 0xD0;
- err = pm_chg_write(chip, CHG_TEST, temp);
- if (err) {
- pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
- return;
- }
-}
-
#define VREF_BATT_THERM_FORCE_ON BIT(7)
static void detect_battery_removal(struct pm8921_chg_chip *chip)
{
@@ -4082,14 +4025,15 @@
#define DEFAULT_SAFETY_MINUTES 500
static int __devinit pm8921_chg_hw_init(struct pm8921_chg_chip *chip)
{
- int rc;
- int vdd_safe;
u8 subrev;
- int fcc_uah;
- int safety_time = DEFAULT_SAFETY_MINUTES;
+ int rc, vdd_safe, fcc_uah, safety_time = DEFAULT_SAFETY_MINUTES;
- /* forcing 19p2mhz before accessing any charger registers */
- pm8921_chg_force_19p2mhz_clk(chip);
+ spin_lock_init(&lpm_lock);
+ rc = pm8921_apply_19p2mhz_kickstart(chip);
+ if (rc) {
+ pr_err("Failed to apply kickstart rc=%d\n", rc);
+ return rc;
+ }
detect_battery_removal(chip);
@@ -4288,23 +4232,22 @@
}
/* Check if die 3.0.1 is present */
if (subrev == 0x1)
- pm_chg_write(chip,
- CHG_BUCK_CTRL_TEST3, 0xA4);
+ pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xA4);
else
- pm_chg_write(chip,
- CHG_BUCK_CTRL_TEST3, 0xAC);
+ pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xAC);
}
/* Enable isub_fine resolution AICL for PM8917 */
if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917) {
chip->iusb_fine_res = true;
- if (chip->uvd_voltage_mv)
+ if (chip->uvd_voltage_mv) {
rc = pm_chg_uvd_threshold_set(chip,
chip->uvd_voltage_mv);
if (rc) {
pr_err("Failed to set UVD threshold %drc=%d\n",
chip->uvd_voltage_mv, rc);
- return rc;
+ return rc;
+ }
}
}
@@ -4330,6 +4273,45 @@
return rc;
}
+ if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8921) {
+ /* Clear kickstart */
+ rc = pm8xxx_writeb(chip->dev->parent, CHG_TEST, 0xD0);
+ if (rc) {
+ pr_err("Failed to clear kickstart rc=%d\n", rc);
+ return rc;
+ }
+
+ /* From here the lpm_workaround will be active */
+ chip->lockup_lpm_wrkarnd = true;
+
+ /* Enable LPM */
+ pm8921_chg_set_lpm(chip, 1);
+ }
+
+ if (chip->lockup_lpm_wrkarnd) {
+ chip->vreg_xoadc = regulator_get(chip->dev, "vreg_xoadc");
+ if (IS_ERR(chip->vreg_xoadc))
+ return -ENODEV;
+
+ rc = regulator_set_optimum_mode(chip->vreg_xoadc, 10000);
+ if (rc < 0) {
+ pr_err("Failed to set configure HPM rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = regulator_set_voltage(chip->vreg_xoadc, 1800000, 1800000);
+ if (rc) {
+ pr_err("Failed to set L14 voltage rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = regulator_enable(chip->vreg_xoadc);
+ if (rc) {
+ pr_err("Failed to enable L14 rc=%d\n", rc);
+ return rc;
+ }
+ }
+
return 0;
}
@@ -4580,11 +4562,19 @@
int rc;
struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
+ if (chip->lockup_lpm_wrkarnd) {
+ rc = regulator_disable(chip->vreg_xoadc);
+ if (rc)
+ pr_err("Failed to disable L14 rc=%d\n", rc);
+
+ rc = pm8921_apply_19p2mhz_kickstart(chip);
+ if (rc)
+ pr_err("Failed to apply kickstart rc=%d\n", rc);
+ }
+
rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, 0);
if (rc)
pr_err("Failed to Force Vref therm off rc=%d\n", rc);
- if (!(chip->disable_hw_clock_switching))
- pm8921_chg_set_hw_clk_switching(chip);
return 0;
}
@@ -4593,7 +4583,15 @@
int rc;
struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
- pm8921_chg_force_19p2mhz_clk(chip);
+ if (chip->lockup_lpm_wrkarnd) {
+ rc = regulator_enable(chip->vreg_xoadc);
+ if (rc)
+ pr_err("Failed to enable L14 rc=%d\n", rc);
+
+ rc = pm8921_apply_19p2mhz_kickstart(chip);
+ if (rc)
+ pr_err("Failed to apply kickstart rc=%d\n", rc);
+ }
rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
VREF_BATT_THERM_FORCE_ON);
@@ -4615,7 +4613,6 @@
static int pm8921_charger_suspend(struct device *dev)
{
- int rc;
struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
if (is_usb_chg_plugged_in(chip)) {
@@ -4623,9 +4620,6 @@
enable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
}
- rc = pm8xxx_batt_alarm_enable(PM8XXX_BATT_ALARM_LOWER_COMPARATOR);
- if (rc < 0)
- pr_err("Failed to enable lower comparator\n");
return 0;
}
static int __devinit pm8921_charger_probe(struct platform_device *pdev)
@@ -4789,17 +4783,6 @@
enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
enable_irq_wake(chip->pmic_chg_irq[FASTCHG_IRQ]);
- rc = pm8921_charger_configure_batt_alarm(chip);
- if (rc) {
- pr_err("Couldn't configure battery alarm! rc=%d\n", rc);
- goto free_irq;
- }
-
- rc = pm8921_charger_enable_batt_alarm(chip);
- if (rc) {
- pr_err("Couldn't enable battery alarm! rc=%d\n", rc);
- goto free_irq;
- }
create_debugfs_entries(chip);
/* determine what state the charger is in */
@@ -4811,8 +4794,6 @@
(chip->update_time)));
return 0;
-free_irq:
- free_irqs(chip);
unregister_batt:
wake_lock_destroy(&chip->eoc_wake_lock);
power_supply_unregister(&chip->batt_psy);
@@ -4829,6 +4810,7 @@
{
struct pm8921_chg_chip *chip = platform_get_drvdata(pdev);
+ regulator_put(chip->vreg_xoadc);
free_irqs(chip);
platform_set_drvdata(pdev, NULL);
the_chip = NULL;
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 2c89065..51e4465 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -231,29 +231,40 @@
return 0;
}
-static int qpnp_masked_write(struct qpnp_bms_chip *chip, u16 addr,
+static int qpnp_masked_write_base(struct qpnp_bms_chip *chip, u16 addr,
u8 mask, u8 val)
{
int rc;
u8 reg;
- rc = qpnp_read_wrapper(chip, ®, chip->base + addr, 1);
+ rc = qpnp_read_wrapper(chip, ®, addr, 1);
if (rc) {
- pr_err("read failed addr = %03X, rc = %d\n",
- chip->base + addr, rc);
+ pr_err("read failed addr = %03X, rc = %d\n", addr, rc);
return rc;
}
reg &= ~mask;
reg |= val & mask;
- rc = qpnp_write_wrapper(chip, ®, chip->base + addr, 1);
+ rc = qpnp_write_wrapper(chip, ®, addr, 1);
if (rc) {
pr_err("write failed addr = %03X, val = %02x, mask = %02x, reg = %02x, rc = %d\n",
- chip->base + addr, val, mask, reg, rc);
+ addr, val, mask, reg, rc);
return rc;
}
return 0;
}
+static int qpnp_masked_write_iadc(struct qpnp_bms_chip *chip, u16 addr,
+ u8 mask, u8 val)
+{
+ return qpnp_masked_write_base(chip, chip->iadc_base + addr, mask, val);
+}
+
+static int qpnp_masked_write(struct qpnp_bms_chip *chip, u16 addr,
+ u8 mask, u8 val)
+{
+ return qpnp_masked_write_base(chip, chip->base + addr, mask, val);
+}
+
#define HOLD_OREG_DATA BIT(0)
static int lock_output_data(struct qpnp_bms_chip *chip)
{
@@ -1345,7 +1356,7 @@
pr_debug("RUC = %duAh\n", remaining_usable_charge_uah);
if (params.fcc_uah - params.uuc_uah <= 0) {
- pr_warn("FCC = %duAh, UUC = %duAh forcing soc = 0\n",
+ pr_debug("FCC = %duAh, UUC = %duAh forcing soc = 0\n",
params.fcc_uah,
params.uuc_uah);
soc = 0;
@@ -1379,12 +1390,12 @@
soc = 100;
if (soc < 0) {
- pr_err("bad rem_usb_chg = %d rem_chg %d, cc_uah %d, unusb_chg %d\n",
+ pr_debug("bad rem_usb_chg = %d rem_chg %d, cc_uah %d, unusb_chg %d\n",
remaining_usable_charge_uah,
params.ocv_charge_uah,
params.cc_uah, params.uuc_uah);
- pr_err("for bad rem_usb_chg last_ocv_uv = %d batt_temp = %d fcc = %d soc =%d\n",
+ pr_debug("for bad rem_usb_chg last_ocv_uv = %d batt_temp = %d fcc = %d soc =%d\n",
chip->last_ocv_uv, batt_temp,
params.fcc_uah, soc);
soc = 0;
@@ -1950,6 +1961,9 @@
SPMI_PROP_READ(low_soc_calculate_soc_ms,
"low-soc-calculate-soc-ms", rc);
SPMI_PROP_READ(calculate_soc_ms, "calculate-soc-ms", rc);
+ chip->use_external_rsense = of_property_read_bool(
+ chip->spmi->dev.of_node,
+ "qcom,bms-use-external-rsense");
chip->ignore_shutdown_soc = of_property_read_bool(
chip->spmi->dev.of_node,
"qcom,bms-ignore-shutdown-soc");
@@ -1970,7 +1984,7 @@
chip->batt_type);
pr_debug("ignore_shutdown_soc:%d, use_voltage_soc:%d\n",
chip->ignore_shutdown_soc, chip->use_voltage_soc);
-
+ pr_debug("use external rsense: %d\n", chip->use_external_rsense);
return 0;
}
@@ -2070,10 +2084,36 @@
iadc_channel_select &= ADC_CH_SEL_MASK;
if (iadc_channel_select == INTERNAL_RSENSE) {
pr_debug("Internal rsense used\n");
- chip->use_external_rsense = false;
+ if (chip->use_external_rsense) {
+ pr_debug("Changing rsense to external\n");
+ rc = qpnp_masked_write_iadc(chip,
+ IADC1_BMS_ADC_CH_SEL_CTL,
+ ADC_CH_SEL_MASK,
+ EXTERNAL_RSENSE);
+ if (rc) {
+ pr_err("Unable to set IADC1_BMS channel %x to %x: %d\n",
+ IADC1_BMS_ADC_CH_SEL_CTL,
+ EXTERNAL_RSENSE, rc);
+ return rc;
+ }
+ reset_cc(chip);
+ }
} else if (iadc_channel_select == EXTERNAL_RSENSE) {
pr_debug("External rsense used\n");
- chip->use_external_rsense = true;
+ if (!chip->use_external_rsense) {
+ pr_debug("Changing rsense to internal\n");
+ rc = qpnp_masked_write_iadc(chip,
+ IADC1_BMS_ADC_CH_SEL_CTL,
+ ADC_CH_SEL_MASK,
+ INTERNAL_RSENSE);
+ if (rc) {
+ pr_err("Unable to set IADC1_BMS channel %x to %x: %d\n",
+ IADC1_BMS_ADC_CH_SEL_CTL,
+ INTERNAL_RSENSE, rc);
+ return rc;
+ }
+ reset_cc(chip);
+ }
} else {
pr_err("IADC1_BMS_IADC configured incorrectly. Selected channel = %d\n",
iadc_channel_select);
@@ -2127,18 +2167,18 @@
}
pr_debug("BMS version: %hhu.%hhu\n", chip->revision2, chip->revision1);
- rc = read_iadc_channel_select(chip);
- if (rc) {
- pr_err("Unable to get iadc selected channel = %d\n", rc);
- goto error_read;
- }
-
rc = bms_read_properties(chip);
if (rc) {
pr_err("Unable to read all bms properties, rc = %d\n", rc);
goto error_read;
}
+ rc = read_iadc_channel_select(chip);
+ if (rc) {
+ pr_err("Unable to get iadc selected channel = %d\n", rc);
+ goto error_read;
+ }
+
rc = set_battery_data(chip);
if (rc) {
pr_err("Bad battery data %d\n", rc);
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index a0d84df..005f789 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -161,9 +161,12 @@
* @chg_done: indicates that charging is completed
* @usb_present: present status of usb
* @dc_present: present status of dc
+ * @use_default_batt_values: flag to report default battery properties
* @max_voltage_mv: the max volts the batt should be charged up to
- * @min_voltage_mv: the min battery voltage before turning the FETon
+ * @min_voltage_mv: min battery voltage before turning the FET on
+ * @resume_voltage_mv: voltage at which the battery resumes charging
* @term_current: the charging based term current
+ * @safe_current: battery safety current setting
* @revision: PMIC revision
* @dc_psy power supply to export information to userspace
* @usb_psy power supply to export information to userspace
@@ -191,11 +194,14 @@
bool usb_present;
bool dc_present;
bool charging_disabled;
+ bool use_default_batt_values;
unsigned int max_bat_chg_current;
unsigned int safe_voltage_mv;
unsigned int max_voltage_mv;
unsigned int min_voltage_mv;
+ unsigned int resume_voltage_mv;
unsigned int term_current;
+ unsigned int safe_current;
unsigned int revision;
struct power_supply dc_psy;
struct power_supply *usb_psy;
@@ -734,6 +740,9 @@
{
union power_supply_propval ret = {0,};
+ if (chip->use_default_batt_values || !get_prop_batt_present(chip))
+ return DEFAULT_CAPACITY;
+
if (chip->bms_psy) {
chip->bms_psy->get_property(chip->bms_psy,
POWER_SUPPLY_PROP_CAPACITY, &ret);
@@ -747,7 +756,7 @@
return DEFAULT_CAPACITY;
}
-#define DEFAULT_TEMP 25
+#define DEFAULT_TEMP 250
#define MAX_TOLERABLE_BATT_TEMP_DDC 680
static int
get_prop_batt_temp(struct qpnp_chg_chip *chip)
@@ -755,6 +764,9 @@
int rc = 0;
struct qpnp_vadc_result results;
+ if (chip->use_default_batt_values || !get_prop_batt_present(chip))
+ return DEFAULT_TEMP;
+
if (chip->revision > 0) {
rc = qpnp_vadc_read(LR_MUX1_BATT_THERM, &results);
if (rc) {
@@ -927,6 +939,28 @@
QPNP_CHG_VINMIN_MASK, temp, 1);
}
+#define QPNP_CHG_IBATSAFE_MIN_MA 100
+#define QPNP_CHG_IBATSAFE_MAX_MA 3250
+#define QPNP_CHG_I_STEP_MA 50
+#define QPNP_CHG_I_MIN_MA 100
+#define QPNP_CHG_I_MASK 0x3F
+static int
+qpnp_chg_ibatsafe_set(struct qpnp_chg_chip *chip, int safe_current)
+{
+ u8 temp;
+
+ if (safe_current < QPNP_CHG_IBATSAFE_MIN_MA
+ || safe_current > QPNP_CHG_IBATSAFE_MAX_MA) {
+ pr_err("bad mA=%d asked to set\n", safe_current);
+ return -EINVAL;
+ }
+
+ temp = (safe_current - QPNP_CHG_IBATSAFE_MIN_MA)
+ / QPNP_CHG_I_STEP_MA;
+ return qpnp_chg_masked_write(chip,
+ chip->chgr_base + CHGR_IBAT_SAFE,
+ QPNP_CHG_I_MASK, temp, 1);
+}
#define QPNP_CHG_ITERM_MIN_MA 100
#define QPNP_CHG_ITERM_MAX_MA 250
@@ -952,9 +986,6 @@
#define QPNP_CHG_IBATMAX_MIN 100
#define QPNP_CHG_IBATMAX_MAX 3250
-#define QPNP_CHG_I_STEP_MA 50
-#define QPNP_CHG_I_MIN_MA 100
-#define QPNP_CHG_I_MASK 0x3F
static int
qpnp_chg_ibatmax_set(struct qpnp_chg_chip *chip, int chg_current)
{
@@ -970,6 +1001,26 @@
QPNP_CHG_I_MASK, temp, 1);
}
+#define QPNP_CHG_VBATDET_MIN_MV 3240
+#define QPNP_CHG_VBATDET_MAX_MV 5780
+#define QPNP_CHG_VBATDET_STEP_MV 20
+static int
+qpnp_chg_vbatdet_set(struct qpnp_chg_chip *chip, int vbatdet_mv)
+{
+ u8 temp;
+
+ if (vbatdet_mv < QPNP_CHG_VBATDET_MIN_MV
+ || vbatdet_mv > QPNP_CHG_VBATDET_MAX_MV) {
+ pr_err("bad mV=%d asked to set\n", vbatdet_mv);
+ return -EINVAL;
+ }
+ temp = (vbatdet_mv - QPNP_CHG_VBATDET_MIN_MV)
+ / QPNP_CHG_VBATDET_STEP_MV;
+
+ pr_debug("voltage=%d setting %02x\n", vbatdet_mv, temp);
+ return qpnp_chg_write(chip, &temp,
+ chip->chgr_base + CHGR_VBAT_DET, 1);
+}
#define QPNP_CHG_V_MIN_MV 3240
#define QPNP_CHG_V_MAX_MV 4500
@@ -1072,6 +1123,11 @@
pr_debug("failed setting safe_voltage rc=%d\n", rc);
return rc;
}
+ rc = qpnp_chg_vbatdet_set(chip, chip->resume_voltage_mv);
+ if (rc) {
+ pr_debug("failed setting resume_voltage rc=%d\n", rc);
+ return rc;
+ }
rc = qpnp_chg_ibatmax_set(chip, chip->max_bat_chg_current);
if (rc) {
pr_debug("failed setting ibatmax rc=%d\n", rc);
@@ -1082,6 +1138,11 @@
pr_debug("failed setting ibatterm rc=%d\n", rc);
return rc;
}
+ rc = qpnp_chg_ibatsafe_set(chip, chip->safe_current);
+ if (rc) {
+ pr_debug("failed setting ibat_Safe rc=%d\n", rc);
+ return rc;
+ }
/* HACK: Disable wdog */
rc = qpnp_chg_masked_write(chip, chip->chgr_base + 0x62,
0xFF, 0xA0, 1);
@@ -1218,6 +1279,24 @@
goto fail_chg_enable;
}
+ /* Get the ibatsafe property */
+ rc = of_property_read_u32(spmi->dev.of_node,
+ "qcom,chg-vbatdet-mv",
+ &chip->resume_voltage_mv);
+ if (rc) {
+ pr_err("Error reading vbatdet property %d\n", rc);
+ goto fail_chg_enable;
+ }
+
+ /* Get the ibatsafe property */
+ rc = of_property_read_u32(spmi->dev.of_node,
+ "qcom,chg-ibatsafe-ma",
+ &chip->safe_current);
+ if (rc) {
+ pr_err("Error reading ibatsafe property %d\n", rc);
+ goto fail_chg_enable;
+ }
+
/* Get the ibatterm property */
rc = of_property_read_u32(spmi->dev.of_node,
"qcom,chg-ibatterm-ma",
@@ -1239,6 +1318,14 @@
chip->charging_disabled = of_property_read_bool(spmi->dev.of_node,
"qcom,chg-charging-disabled");
+ /* Get the fake-batt-values property */
+ chip->use_default_batt_values = of_property_read_bool(spmi->dev.of_node,
+ "qcom,chg-use-default-batt-values");
+
+ /* Disable charging when faking battery values */
+ if (chip->use_default_batt_values)
+ chip->charging_disabled = true;
+
spmi_for_each_container_dev(spmi_resource, spmi) {
if (!spmi_resource) {
pr_err("qpnp_chg: spmi resource absent\n");
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index dba02f8..6135e71 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -127,13 +127,72 @@
}
}
+/**
+ * msm_spi_clk_max_rate: finds the nearest lower rate for a clk
+ * @clk the clock for which to find nearest lower rate
+ * @rate clock frequency in Hz
+ * @return nearest lower rate or negative error value
+ *
+ * Public clock API extends clk_round_rate which is a ceiling function. This
+ * function is a floor function implemented as a binary search using the
+ * ceiling function.
+ */
+static long msm_spi_clk_max_rate(struct clk *clk, unsigned long rate)
+{
+ long lowest_available, nearest_low, step_size, cur;
+ long step_direction = -1;
+ long guess = rate;
+ int max_steps = 10;
+
+ cur = clk_round_rate(clk, rate);
+ if (cur == rate)
+ return rate;
+
+ /* if we got here then: cur > rate */
+ lowest_available = clk_round_rate(clk, 0);
+ if (lowest_available > rate)
+ return -EINVAL;
+
+ step_size = (rate - lowest_available) >> 1;
+ nearest_low = lowest_available;
+
+ while (max_steps-- && step_size) {
+ guess += step_size * step_direction;
+
+ cur = clk_round_rate(clk, guess);
+
+ if ((cur < rate) && (cur > nearest_low))
+ nearest_low = cur;
+
+ /*
+ * if we stepped too far, then start stepping in the other
+ * direction with half the step size
+ */
+ if (((cur > rate) && (step_direction > 0))
+ || ((cur < rate) && (step_direction < 0))) {
+ step_direction = -step_direction;
+ step_size >>= 1;
+ }
+ }
+ return nearest_low;
+}
+
static void msm_spi_clock_set(struct msm_spi *dd, int speed)
{
+ long rate;
int rc;
- rc = clk_set_rate(dd->clk, speed);
+ rate = msm_spi_clk_max_rate(dd->clk, speed);
+ if (rate < 0) {
+ dev_err(dd->dev,
+ "%s: no match found for requested clock frequency:%d",
+ __func__, speed);
+ return;
+ }
+
+ rc = clk_set_rate(dd->clk, rate);
if (!rc)
- dd->clock_speed = speed;
+ dd->clock_speed = rate;
}
static int msm_spi_calculate_size(int *fifo_size,
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index e70924c..347d9f2 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -107,3 +107,13 @@
available. If allowed via compile time configuration; enabling the
thermal zone device via the mode file results in shifting PMIC over
temperature shutdown control from hardware to software.
+
+config THERMAL_QPNP_ADC_TM
+ tristate "Qualcomm 8974 Thermal Monitor ADC Driver"
+ depends on THERMAL && SPMI
+ help
+ This enables the thermal Sysfs driver for the ADC thermal monitoring
+ device. It shows up in Sysfs as a thermal zone with multiple trip points.
+ Disabling the thermal zone device via the mode file results in disabling
+ the sensor. Also able to set threshold temperature for both hot and cold
+ and update when a threshold is reached.
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 3b2b3a8..01dce2d 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -11,3 +11,4 @@
obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o
obj-$(CONFIG_THERMAL_TSENS8974) += msm8974-tsens.o
obj-$(CONFIG_THERMAL_QPNP) += qpnp-temp-alarm.o
+obj-$(CONFIG_THERMAL_QPNP_ADC_TM) += qpnp-adc-tm.o
diff --git a/drivers/thermal/qpnp-adc-tm.c b/drivers/thermal/qpnp-adc-tm.c
new file mode 100644
index 0000000..bcc85f3
--- /dev/null
+++ b/drivers/thermal/qpnp-adc-tm.c
@@ -0,0 +1,1531 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+#include <linux/hwmon.h>
+#include <linux/module.h>
+#include <linux/debugfs.h>
+#include <linux/spmi.h>
+#include <linux/of_irq.h>
+#include <linux/wakelock.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/qpnp/qpnp-adc.h>
+#include <linux/thermal.h>
+#include <linux/platform_device.h>
+
+/* QPNP VADC TM register definition */
+#define QPNP_STATUS1 0x8
+#define QPNP_STATUS1_OP_MODE 4
+#define QPNP_STATUS1_MEAS_INTERVAL_EN_STS BIT(2)
+#define QPNP_STATUS1_REQ_STS BIT(1)
+#define QPNP_STATUS1_EOC BIT(0)
+#define QPNP_STATUS2 0x9
+#define QPNP_STATUS2_CONV_SEQ_STATE 6
+#define QPNP_STATUS2_FIFO_NOT_EMPTY_FLAG BIT(1)
+#define QPNP_STATUS2_CONV_SEQ_TIMEOUT_STS BIT(0)
+#define QPNP_CONV_TIMEOUT_ERR 2
+
+#define QPNP_MODE_CTL 0x40
+#define QPNP_OP_MODE_SHIFT 3
+#define QPNP_VREF_XO_THM_FORCE BIT(2)
+#define QPNP_AMUX_TRIM_EN BIT(1)
+#define QPNP_ADC_TRIM_EN BIT(0)
+#define QPNP_EN_CTL1 0x46
+#define QPNP_ADC_TM_EN BIT(7)
+#define QPNP_ADC_CH_SEL_CTL 0x48
+#define QPNP_ADC_DIG_PARAM 0x50
+#define QPNP_ADC_DIG_DEC_RATIO_SEL_SHIFT 3
+#define QPNP_HW_SETTLE_DELAY 0x51
+#define QPNP_CONV_REQ 0x52
+#define QPNP_CONV_REQ_SET BIT(7)
+#define QPNP_CONV_SEQ_CTL 0x54
+#define QPNP_CONV_SEQ_HOLDOFF_SHIFT 4
+#define QPNP_CONV_SEQ_TRIG_CTL 0x55
+#define QPNP_ADC_TM_MEAS_INTERVAL_CTL 0x57
+#define QPNP_ADC_TM_MEAS_INTERVAL_TIME_SHIFT 0x3
+#define QPNP_ADC_TM_MEAS_INTERVAL_CTL2 0x58
+#define QPNP_ADC_TM_MEAS_INTERVAL_CTL2_SHIFT 0x4
+#define QPNP_ADC_TM_MEAS_INTERVAL_CTL2_MASK 0xf0
+#define QPNP_ADC_TM_MEAS_INTERVAL_CTL3_MASK 0xf
+
+#define QPNP_ADC_MEAS_INTERVAL_OP_CTL 0x59
+#define QPNP_ADC_MEAS_INTERVAL_OP BIT(7)
+
+#define QPNP_FAST_AVG_CTL 0x5a
+#define QPNP_FAST_AVG_EN 0x5b
+
+#define QPNP_M0_LOW_THR_LSB 0x5c
+#define QPNP_M0_LOW_THR_MSB 0x5d
+#define QPNP_M0_HIGH_THR_LSB 0x5e
+#define QPNP_M0_HIGH_THR_MSB 0x5f
+#define QPNP_M1_LOW_THR_LSB 0x69
+#define QPNP_M1_LOW_THR_MSB 0x6a
+#define QPNP_M1_HIGH_THR_LSB 0x6b
+#define QPNP_M1_HIGH_THR_MSB 0x6c
+#define QPNP_M2_LOW_THR_LSB 0x71
+#define QPNP_M2_LOW_THR_MSB 0x72
+#define QPNP_M2_HIGH_THR_LSB 0x7b
+#define QPNP_M2_HIGH_THR_MSB 0x7c
+#define QPNP_M3_LOW_THR_LSB 0x79
+#define QPNP_M3_LOW_THR_MSB 0x7a
+#define QPNP_M3_HIGH_THR_LSB 0x7b
+#define QPNP_M3_HIGH_THR_MSB 0x7c
+#define QPNP_M4_LOW_THR_LSB 0x81
+#define QPNP_M4_LOW_THR_MSB 0x82
+#define QPNP_M4_HIGH_THR_LSB 0x83
+#define QPNP_M4_HIGH_THR_MSB 0x84
+
+#define QPNP_ADC_TM_MULTI_MEAS_EN 0x41
+#define QPNP_ADC_TM_MULTI_MEAS_EN_M0 BIT(0)
+#define QPNP_ADC_TM_MULTI_MEAS_EN_M1 BIT(1)
+#define QPNP_ADC_TM_MULTI_MEAS_EN_M2 BIT(2)
+#define QPNP_ADC_TM_MULTI_MEAS_EN_M3 BIT(3)
+#define QPNP_ADC_TM_MULTI_MEAS_EN_M4 BIT(4)
+#define QPNP_ADC_TM_LOW_THR_INT_EN 0x42
+#define QPNP_ADC_TM_LOW_THR_INT_EN_M0 BIT(0)
+#define QPNP_ADC_TM_LOW_THR_INT_EN_M1 BIT(1)
+#define QPNP_ADC_TM_LOW_THR_INT_EN_M2 BIT(2)
+#define QPNP_ADC_TM_LOW_THR_INT_EN_M3 BIT(3)
+#define QPNP_ADC_TM_LOW_THR_INT_EN_M4 BIT(4)
+#define QPNP_ADC_TM_HIGH_THR_INT_EN 0x43
+#define QPNP_ADC_TM_HIGH_THR_INT_EN_M0 BIT(0)
+#define QPNP_ADC_TM_HIGH_THR_INT_EN_M1 BIT(1)
+#define QPNP_ADC_TM_HIGH_THR_INT_EN_M2 BIT(2)
+#define QPNP_ADC_TM_HIGH_THR_INT_EN_M3 BIT(3)
+#define QPNP_ADC_TM_HIGH_THR_INT_EN_M4 BIT(4)
+
+#define QPNP_ADC_TM_M0_MEAS_INTERVAL_CTL 0x57
+#define QPNP_ADC_TM_M1_MEAS_INTERVAL_CTL 0x6d
+#define QPNP_ADC_TM_M2_MEAS_INTERVAL_CTL 0x75
+#define QPNP_ADC_TM_M3_MEAS_INTERVAL_CTL 0x7d
+#define QPNP_ADC_TM_M4_MEAS_INTERVAL_CTL 0x85
+#define QPNP_ADC_TM_STATUS1 0x8
+#define QPNP_ADC_TM_STATUS_LOW 0xa
+#define QPNP_ADC_TM_STATUS_HIGH 0xb
+
+#define QPNP_ADC_TM_M0_LOW_THR 0x5d5c
+#define QPNP_ADC_TM_M0_HIGH_THR 0x5f5e
+#define QPNP_ADC_TM_MEAS_INTERVAL 0x0
+
+#define QPNP_ADC_TM_THR_LSB_MASK(val) (val & 0xff)
+#define QPNP_ADC_TM_THR_MSB_MASK(val) ((val & 0xff00) >> 8)
+
+struct qpnp_adc_tm_sensor {
+ struct thermal_zone_device *tz_dev;
+ enum thermal_device_mode mode;
+ uint32_t sensor_num;
+ enum qpnp_adc_meas_timer_select timer_select;
+ uint32_t meas_interval;
+ uint32_t low_thr;
+ uint32_t high_thr;
+ uint32_t btm_channel_num;
+ struct work_struct work;
+};
+
+struct qpnp_adc_tm_drv {
+ struct qpnp_adc_drv *adc;
+ struct qpnp_adc_tm_usbid_param *usb_id_param;
+ struct work_struct usbid_work;
+ struct qpnp_adc_tm_btm_param *battery_param;
+ struct work_struct batt_work;
+ bool adc_tm_initialized;
+ struct qpnp_adc_tm_sensor sensor[0];
+};
+
+struct qpnp_adc_tm_drv *qpnp_adc_tm;
+
+struct qpnp_adc_tm_trip_reg_type {
+ uint16_t low_thr_lsb_addr;
+ uint16_t low_thr_msb_addr;
+ uint16_t high_thr_lsb_addr;
+ uint16_t high_thr_msb_addr;
+ u8 multi_meas_en;
+ u8 low_thr_int_chan_en;
+ u8 high_thr_int_chan_en;
+};
+
+static struct qpnp_adc_tm_trip_reg_type adc_tm_data[] = {
+ [QPNP_ADC_TM_M0_ADC_CH_SEL_CTL] = {QPNP_M0_LOW_THR_LSB,
+ QPNP_M0_LOW_THR_MSB, QPNP_M0_HIGH_THR_LSB,
+ QPNP_M0_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M0,
+ QPNP_ADC_TM_LOW_THR_INT_EN_M0, QPNP_ADC_TM_HIGH_THR_INT_EN_M0},
+ [QPNP_ADC_TM_M1_ADC_CH_SEL_CTL] = {QPNP_M1_LOW_THR_LSB,
+ QPNP_M1_LOW_THR_MSB, QPNP_M1_HIGH_THR_LSB,
+ QPNP_M1_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M1,
+ QPNP_ADC_TM_LOW_THR_INT_EN_M1, QPNP_ADC_TM_HIGH_THR_INT_EN_M1},
+ [QPNP_ADC_TM_M2_ADC_CH_SEL_CTL] = {QPNP_M2_LOW_THR_LSB,
+ QPNP_M2_LOW_THR_MSB, QPNP_M2_HIGH_THR_LSB,
+ QPNP_M2_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M2,
+ QPNP_ADC_TM_LOW_THR_INT_EN_M2, QPNP_ADC_TM_HIGH_THR_INT_EN_M2},
+ [QPNP_ADC_TM_M3_ADC_CH_SEL_CTL] = {QPNP_M3_LOW_THR_LSB,
+ QPNP_M3_LOW_THR_MSB, QPNP_M3_HIGH_THR_LSB,
+ QPNP_M3_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M3,
+ QPNP_ADC_TM_LOW_THR_INT_EN_M3, QPNP_ADC_TM_HIGH_THR_INT_EN_M3},
+ [QPNP_ADC_TM_M4_ADC_CH_SEL_CTL] = {QPNP_M4_LOW_THR_LSB,
+ QPNP_M4_LOW_THR_MSB, QPNP_M4_HIGH_THR_LSB,
+ QPNP_M4_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M4,
+ QPNP_ADC_TM_LOW_THR_INT_EN_M4, QPNP_ADC_TM_HIGH_THR_INT_EN_M4},
+};
+
+static int32_t qpnp_adc_tm_read_reg(int16_t reg, u8 *data)
+{
+ struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
+ int rc = 0;
+
+ rc = spmi_ext_register_readl(adc_tm->adc->spmi->ctrl,
+ adc_tm->adc->slave, (adc_tm->adc->offset + reg), data, 1);
+ if (rc < 0)
+ pr_err("adc-tm read reg %d failed with %d\n", reg, rc);
+
+ return rc;
+}
+
+static int32_t qpnp_adc_tm_write_reg(int16_t reg, u8 data)
+{
+ struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
+ int rc = 0;
+ u8 *buf;
+
+ buf = &data;
+
+ rc = spmi_ext_register_writel(adc_tm->adc->spmi->ctrl,
+ adc_tm->adc->slave, (adc_tm->adc->offset + reg), buf, 1);
+ if (rc < 0)
+ pr_err("adc-tm write reg %d failed with %d\n", reg, rc);
+
+ return rc;
+}
+
+static int32_t qpnp_adc_tm_enable(bool state)
+{
+ int rc = 0;
+ u8 data = 0, enable_check = 0;
+
+ if (state) {
+ data = QPNP_ADC_TM_EN;
+ rc = qpnp_adc_tm_write_reg(QPNP_EN_CTL1,
+ data);
+ if (rc < 0)
+ pr_err("adc-tm enable failed\n");
+ } else {
+ rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_MULTI_MEAS_EN,
+ &enable_check);
+ if (rc < 0) {
+ pr_err("multi measurement read failed\n");
+ return rc;
+ }
+
+ if (!enable_check) {
+ data = 0;
+ rc = qpnp_adc_tm_write_reg(QPNP_EN_CTL1, data);
+ if (rc < 0)
+ pr_err("adc-tm disable failed\n");
+ }
+ }
+
+ return rc;
+}
+
+static int32_t qpnp_adc_tm_enable_req_sts_check(void)
+{
+ u8 status1;
+ int rc;
+
+ /* The VADC_TM bank needs to be disabled for new conversion request */
+ rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_STATUS1, &status1);
+ if (rc) {
+ pr_err("adc-tm read status1 failed\n");
+ return rc;
+ }
+
+ /* Disable the bank if a conversion is occuring */
+ if (status1 & QPNP_STATUS1_REQ_STS) {
+ rc = qpnp_adc_tm_write_reg(QPNP_EN_CTL1, 0);
+ if (rc < 0)
+ pr_err("adc-tm disable failed\n");
+ }
+
+ return rc;
+}
+
+static int32_t qpnp_adc_tm_mode_select(u8 mode_ctl)
+{
+ int rc;
+
+ /* VADC_BTM current sets mode to recurring measurements */
+ rc = qpnp_adc_tm_write_reg(QPNP_MODE_CTL, mode_ctl);
+ if (rc < 0)
+ pr_err("adc-tm write mode selection err\n");
+
+ return rc;
+}
+
+static int32_t qpnp_adc_tm_timer_interval_select(
+ struct qpnp_vadc_chan_properties *chan_prop)
+{
+ int rc;
+ u8 meas_interval_timer2 = 0;
+
+ /* Configure USB_ID to timer1, batt_therm to timer2 */
+ switch (chan_prop->timer_select) {
+ case ADC_MEAS_TIMER_SELECT1:
+ rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL,
+ chan_prop->meas_interval1);
+ if (rc < 0) {
+ pr_err("timer1 configure failed\n");
+ return rc;
+ }
+ break;
+ case ADC_MEAS_TIMER_SELECT2:
+ rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
+ &meas_interval_timer2);
+ if (rc < 0) {
+ pr_err("timer2 configure read failed\n");
+ return rc;
+ }
+ meas_interval_timer2 |=
+ (chan_prop->meas_interval2 <<
+ QPNP_ADC_TM_MEAS_INTERVAL_CTL2_SHIFT);
+ rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
+ meas_interval_timer2);
+ if (rc < 0) {
+ pr_err("timer2 configure failed\n");
+ return rc;
+ }
+ break;
+ case ADC_MEAS_TIMER_SELECT3:
+ /* Thermal channels uses timer3, default to 1 second */
+ rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
+ &meas_interval_timer2);
+ if (rc < 0) {
+ pr_err("timer3 read failed\n");
+ return rc;
+ }
+ chan_prop->meas_interval2 = ADC_MEAS3_INTERVAL_1S;
+ meas_interval_timer2 |= chan_prop->meas_interval2;
+ rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
+ meas_interval_timer2);
+ if (rc < 0) {
+ pr_err("timer3 configure failed\n");
+ return rc;
+ }
+ break;
+ default:
+ pr_err("Invalid timer selection\n");
+ return -EINVAL;
+ }
+
+ return rc;
+}
+
+static int32_t qpnp_adc_tm_meas_int_update(uint16_t reg_addr_src,
+ u8 reg_addr_dst, bool state)
+{
+ u8 bit_mask_check = 0;
+ int rc = 0;
+
+ rc = qpnp_adc_tm_read_reg(reg_addr_src, &bit_mask_check);
+ if (rc < 0) {
+ pr_err("read failed for addr:%x\n", reg_addr_src);
+ return rc;
+ }
+
+ if (state)
+ bit_mask_check |= reg_addr_dst;
+ else
+ bit_mask_check &= ~reg_addr_dst;
+
+ rc = qpnp_adc_tm_write_reg(reg_addr_src, bit_mask_check);
+ if (rc < 0)
+ pr_err("write failed for addr:%x\n", reg_addr_src);
+
+ return rc;
+}
+
+static int32_t qpnp_adc_tm_usbid_btm_thr_en(uint32_t btm_chan,
+ struct qpnp_vadc_chan_properties *chan_prop)
+{
+ int rc = 0;
+
+ rc = qpnp_adc_tm_write_reg(
+ adc_tm_data[btm_chan].low_thr_lsb_addr,
+ QPNP_ADC_TM_THR_LSB_MASK(chan_prop->low_thr));
+ if (rc < 0) {
+ pr_err("low threshold lsb setting failed\n");
+ return rc;
+ }
+
+ rc = qpnp_adc_tm_write_reg(
+ adc_tm_data[btm_chan].low_thr_msb_addr,
+ QPNP_ADC_TM_THR_MSB_MASK(chan_prop->low_thr));
+ if (rc < 0) {
+ pr_err("low threshold msb setting failed\n");
+ return rc;
+ }
+
+ rc = qpnp_adc_tm_write_reg(
+ adc_tm_data[btm_chan].high_thr_lsb_addr,
+ QPNP_ADC_TM_THR_LSB_MASK(chan_prop->high_thr));
+ if (rc < 0) {
+ pr_err("high threshold lsb setting failed\n");
+ return rc;
+ }
+
+ rc = qpnp_adc_tm_write_reg(
+ adc_tm_data[btm_chan].high_thr_msb_addr,
+ QPNP_ADC_TM_THR_MSB_MASK(chan_prop->high_thr));
+ if (rc < 0)
+ pr_err("high threshold msb setting failed\n");
+
+ return rc;
+}
+
+static int32_t qpnp_adc_tm_channel_configure(uint32_t btm_chan,
+ struct qpnp_vadc_chan_properties *chan_prop,
+ uint32_t amux_channel)
+{
+ int rc = 0;
+
+ switch (btm_chan) {
+ case QPNP_ADC_TM_M0_ADC_CH_SEL_CTL:
+ case QPNP_ADC_TM_M1_ADC_CH_SEL_CTL:
+ /* Update low and high notification thresholds */
+ rc = qpnp_adc_tm_usbid_btm_thr_en(btm_chan,
+ chan_prop);
+ if (rc < 0) {
+ pr_err("setting chan:%d threshold failed\n", btm_chan);
+ return rc;
+ }
+
+ if ((chan_prop->state_request ==
+ ADC_TM_LOW_THR_ENABLE) ||
+ (chan_prop->state_request ==
+ ADC_TM_HIGH_LOW_THR_ENABLE)) {
+ /* Enable low threshold's interrupt */
+ rc = qpnp_adc_tm_meas_int_update(
+ QPNP_ADC_TM_LOW_THR_INT_EN,
+ adc_tm_data[btm_chan].low_thr_int_chan_en,
+ true);
+ if (rc < 0) {
+ pr_err("low thr enable err:%d\n", btm_chan);
+ return rc;
+ }
+ }
+
+ if ((chan_prop->state_request ==
+ ADC_TM_HIGH_THR_ENABLE) ||
+ (chan_prop->state_request ==
+ ADC_TM_HIGH_LOW_THR_ENABLE)) {
+ /* Enable high threshold's interrupt */
+ rc = qpnp_adc_tm_meas_int_update(
+ QPNP_ADC_TM_HIGH_THR_INT_EN,
+ adc_tm_data[btm_chan].high_thr_int_chan_en,
+ true);
+ if (rc < 0) {
+ pr_err("high thr enable err:%d\n", btm_chan);
+ return rc;
+ }
+ }
+ /* intention fall through to configure common chan meas */
+ case QPNP_ADC_TM_M2_ADC_CH_SEL_CTL:
+ case QPNP_ADC_TM_M3_ADC_CH_SEL_CTL:
+ case QPNP_ADC_TM_M4_ADC_CH_SEL_CTL:
+ /* Configure AMUX control register for channel selection */
+ rc = qpnp_adc_tm_write_reg(btm_chan, amux_channel);
+ if (rc < 0) {
+ pr_err("btm_chan:%d selection failed\n", btm_chan);
+ return rc;
+ }
+
+ /* Enable corresponding BTM channel measurement */
+ rc = qpnp_adc_tm_meas_int_update(
+ QPNP_ADC_TM_MULTI_MEAS_EN,
+ adc_tm_data[btm_chan].multi_meas_en, true);
+ if (rc < 0) {
+ pr_err("multi measurement en failed\n");
+ return rc;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return rc;
+}
+
+static int32_t qpnp_adc_tm_configure(
+ struct qpnp_adc_amux_properties *chan_prop)
+{
+ u8 decimation = 0;
+ int rc = 0;
+ uint32_t btm_chan = 0;
+
+ /* Check if a conversion is in progress */
+ rc = qpnp_adc_tm_enable_req_sts_check();
+ if (rc < 0) {
+ pr_err("adc-tm req_sts check failed\n");
+ return rc;
+ }
+
+ /* Set measurement in recurring mode */
+ rc = qpnp_adc_tm_mode_select(chan_prop->mode_sel);
+ if (rc < 0) {
+ pr_err("adc-tm mode select failed\n");
+ return rc;
+ }
+
+ /* Configure AMUX channel */
+ rc = qpnp_adc_tm_write_reg(QPNP_ADC_CH_SEL_CTL,
+ chan_prop->amux_channel);
+ if (rc < 0) {
+ pr_err("adc-tm channel selection err\n");
+ return rc;
+ }
+
+ /* Digital paramater setup */
+ decimation |= chan_prop->decimation <<
+ QPNP_ADC_DIG_DEC_RATIO_SEL_SHIFT;
+ rc = qpnp_adc_tm_write_reg(QPNP_ADC_DIG_PARAM, decimation);
+ if (rc < 0) {
+ pr_err("adc-tm digital parameter setup err\n");
+ return rc;
+ }
+
+ /* Hardware setting time */
+ rc = qpnp_adc_tm_write_reg(QPNP_HW_SETTLE_DELAY,
+ chan_prop->hw_settle_time);
+ if (rc < 0) {
+ pr_err("adc-tm hw settling time setup err\n");
+ return rc;
+ }
+
+ /* Fast averaging setup */
+ rc = qpnp_adc_tm_write_reg(QPNP_FAST_AVG_CTL,
+ chan_prop->fast_avg_setup);
+ if (rc < 0) {
+ pr_err("adc-tm fast-avg setup err\n");
+ return rc;
+ }
+
+ /* Measurement interval setup */
+ rc = qpnp_adc_tm_timer_interval_select(chan_prop->chan_prop);
+ if (rc < 0) {
+ pr_err("adc-tm timer select failed\n");
+ return rc;
+ }
+
+ /* Channel configuration setup */
+ btm_chan = chan_prop->chan_prop->tm_channel_select;
+ rc = qpnp_adc_tm_channel_configure(btm_chan, chan_prop->chan_prop,
+ chan_prop->amux_channel);
+ if (rc < 0) {
+ pr_err("adc-tm channel configure failed\n");
+ return rc;
+ }
+
+ /* Enable bank */
+ rc = qpnp_adc_tm_enable(true);
+ if (rc)
+ return rc;
+
+ /* Recurring interval measurement enable */
+ rc = qpnp_adc_tm_meas_int_update(QPNP_ADC_MEAS_INTERVAL_OP_CTL,
+ QPNP_ADC_MEAS_INTERVAL_OP, true);
+ if (rc < 0) {
+ pr_err("adc-tm meas interval op configure failed\n");
+ return rc;
+ }
+
+ /* Request conversion */
+ rc = qpnp_adc_tm_write_reg(QPNP_CONV_REQ, QPNP_CONV_REQ_SET);
+ if (rc < 0) {
+ pr_err("adc-tm request conversion failed\n");
+ return rc;
+ }
+
+ return 0;
+}
+
+static int qpnp_adc_tm_get_mode(struct thermal_zone_device *thermal,
+ enum thermal_device_mode *mode)
+{
+ struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
+
+ if (!adc_tm || !mode)
+ return -EINVAL;
+
+ *mode = adc_tm->mode;
+
+ return 0;
+}
+
+static int qpnp_adc_tm_set_mode(struct thermal_zone_device *thermal,
+ enum thermal_device_mode mode)
+{
+ struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
+ struct qpnp_adc_tm_drv *adc_drv = qpnp_adc_tm;
+ int rc = 0, channel;
+
+ if (!adc_tm)
+ return -EINVAL;
+
+ if (mode == THERMAL_DEVICE_ENABLED) {
+ adc_drv->adc->amux_prop->amux_channel = adc_tm->sensor_num;
+ channel = adc_tm->sensor_num;
+ adc_drv->adc->amux_prop->decimation =
+ adc_drv->adc->adc_channels[channel].adc_decimation;
+ adc_drv->adc->amux_prop->hw_settle_time =
+ adc_drv->adc->adc_channels[channel].hw_settle_time;
+ adc_drv->adc->amux_prop->fast_avg_setup =
+ adc_drv->adc->adc_channels[channel].fast_avg_setup;
+ adc_drv->adc->amux_prop->mode_sel =
+ ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT;
+ adc_drv->adc->amux_prop->chan_prop->timer_select =
+ ADC_MEAS_TIMER_SELECT1;
+ adc_drv->adc->amux_prop->chan_prop->meas_interval1 =
+ ADC_MEAS1_INTERVAL_1S;
+ adc_drv->adc->amux_prop->chan_prop->low_thr = adc_tm->low_thr;
+ adc_drv->adc->amux_prop->chan_prop->high_thr = adc_tm->high_thr;
+ adc_drv->adc->amux_prop->chan_prop->tm_channel_select =
+ adc_tm->btm_channel_num;
+
+ rc = qpnp_adc_tm_configure(adc_drv->adc->amux_prop);
+ if (rc) {
+ pr_err("adc-tm tm configure failed with %d\n", rc);
+ return -EINVAL;
+ }
+ } else if (mode == THERMAL_DEVICE_DISABLED) {
+ rc = qpnp_adc_tm_meas_int_update(QPNP_ADC_TM_MULTI_MEAS_EN,
+ adc_tm_data[adc_tm->btm_channel_num].multi_meas_en,
+ false);
+ if (rc < 0) {
+ pr_err("multi measurement update failed\n");
+ return rc;
+ }
+
+ rc = qpnp_adc_tm_enable(false);
+ if (rc < 0) {
+ pr_err("adc-tm disable failed\n");
+ return rc;
+ }
+ }
+
+ adc_tm->mode = mode;
+
+ return 0;
+}
+
+static int qpnp_adc_tm_get_trip_type(struct thermal_zone_device *thermal,
+ int trip, enum thermal_trip_type *type)
+{
+ struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
+
+ if (!adc_tm || !type || type < 0)
+ return -EINVAL;
+
+ switch (trip) {
+ case ADC_TM_TRIP_HIGH_WARM:
+ *type = THERMAL_TRIP_CONFIGURABLE_HI;
+ break;
+ case ADC_TM_TRIP_LOW_COOL:
+ *type = THERMAL_TRIP_CONFIGURABLE_LOW;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int qpnp_adc_tm_get_trip_temp(struct thermal_zone_device *thermal,
+ int trip, unsigned long *temp)
+{
+ struct qpnp_adc_tm_sensor *adc_tm_sensor = thermal->devdata;
+ struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
+ int64_t result = 0;
+ u8 trip_cool_thr0, trip_cool_thr1, trip_warm_thr0, trip_warm_thr1;
+ unsigned int reg, rc = 0, btm_channel_num;
+ uint16_t reg_low_thr_lsb, reg_low_thr_msb;
+ uint16_t reg_high_thr_lsb, reg_high_thr_msb;
+
+ if (!adc_tm)
+ return -EINVAL;
+
+ btm_channel_num = adc_tm_sensor->btm_channel_num;
+ reg_low_thr_lsb = adc_tm_data[btm_channel_num].low_thr_lsb_addr;
+ reg_low_thr_msb = adc_tm_data[btm_channel_num].low_thr_msb_addr;
+ reg_high_thr_lsb = adc_tm_data[btm_channel_num].high_thr_lsb_addr;
+ reg_high_thr_msb = adc_tm_data[btm_channel_num].high_thr_msb_addr;
+
+ switch (trip) {
+ case ADC_TM_TRIP_HIGH_WARM:
+ rc = qpnp_adc_tm_read_reg(reg_low_thr_lsb, &trip_warm_thr0);
+ if (rc) {
+ pr_err("adc-tm low_thr_lsb err\n");
+ return rc;
+ }
+
+ rc = qpnp_adc_tm_read_reg(reg_low_thr_msb, &trip_warm_thr1);
+ if (rc) {
+ pr_err("adc-tm low_thr_msb err\n");
+ return rc;
+ }
+ reg = (trip_warm_thr1 << 8) | trip_warm_thr0;
+ break;
+ case ADC_TM_TRIP_LOW_COOL:
+ rc = qpnp_adc_tm_read_reg(reg_high_thr_lsb, &trip_cool_thr0);
+ if (rc) {
+ pr_err("adc-tm_tm high_thr_lsb err\n");
+ return rc;
+ }
+
+ rc = qpnp_adc_tm_read_reg(reg_high_thr_msb, &trip_cool_thr1);
+ if (rc) {
+ pr_err("adc-tm_tm high_thr_lsb err\n");
+ return rc;
+ }
+ reg = (trip_cool_thr1 << 8) | trip_cool_thr0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ rc = qpnp_adc_tm_scale_voltage_therm_pu2(reg, &result);
+ if (rc < 0) {
+ pr_err("Failed to lookup the therm thresholds\n");
+ return rc;
+ }
+
+ *temp = result;
+
+ return 0;
+}
+
+static int qpnp_adc_tm_set_trip_temp(struct thermal_zone_device *thermal,
+ int trip, long temp)
+{
+ struct qpnp_adc_tm_sensor *adc_tm_sensor = thermal->devdata;
+ struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
+ struct qpnp_adc_tm_config tm_config;
+ u8 trip_cool_thr0, trip_cool_thr1, trip_warm_thr0, trip_warm_thr1;
+ uint16_t reg_low_thr_lsb, reg_low_thr_msb;
+ uint16_t reg_high_thr_lsb, reg_high_thr_msb;
+ int rc = 0, btm_channel_num;
+
+ if (!adc_tm)
+ return -EINVAL;
+
+ tm_config.channel = adc_tm_sensor->sensor_num;
+ switch (trip) {
+ case ADC_TM_TRIP_HIGH_WARM:
+ tm_config.high_thr_temp = temp;
+ break;
+ case ADC_TM_TRIP_LOW_COOL:
+ tm_config.low_thr_temp = temp;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ rc = qpnp_adc_tm_scale_therm_voltage_pu2(&tm_config);
+ if (rc < 0) {
+ pr_err("Failed to lookup the adc-tm thresholds\n");
+ return rc;
+ }
+
+ trip_warm_thr0 = ((tm_config.low_thr_voltage << 24) >> 24);
+ trip_warm_thr1 = ((tm_config.low_thr_voltage << 16) >> 24);
+ trip_cool_thr0 = ((tm_config.high_thr_voltage << 24) >> 24);
+ trip_cool_thr1 = ((tm_config.high_thr_voltage << 16) >> 24);
+
+ btm_channel_num = adc_tm_sensor->btm_channel_num;
+ reg_low_thr_lsb = adc_tm_data[btm_channel_num].low_thr_lsb_addr;
+ reg_low_thr_msb = adc_tm_data[btm_channel_num].low_thr_msb_addr;
+ reg_high_thr_lsb = adc_tm_data[btm_channel_num].high_thr_lsb_addr;
+ reg_high_thr_msb = adc_tm_data[btm_channel_num].high_thr_msb_addr;
+
+ switch (trip) {
+ case ADC_TM_TRIP_HIGH_WARM:
+ rc = qpnp_adc_tm_write_reg(reg_low_thr_lsb, trip_cool_thr0);
+ if (rc) {
+ pr_err("adc-tm_tm read threshold err\n");
+ return rc;
+ }
+
+ rc = qpnp_adc_tm_write_reg(reg_low_thr_msb, trip_cool_thr1);
+ if (rc) {
+ pr_err("adc-tm_tm read threshold err\n");
+ return rc;
+ }
+ adc_tm_sensor->low_thr = tm_config.high_thr_voltage;
+ break;
+ case ADC_TM_TRIP_LOW_COOL:
+ rc = qpnp_adc_tm_write_reg(reg_high_thr_lsb, trip_warm_thr0);
+ if (rc) {
+ pr_err("adc-tm_tm read threshold err\n");
+ return rc;
+ }
+
+ rc = qpnp_adc_tm_write_reg(reg_high_thr_msb, trip_warm_thr1);
+ if (rc) {
+ pr_err("adc-tm_tm read threshold err\n");
+ return rc;
+ }
+ adc_tm_sensor->high_thr = tm_config.low_thr_voltage;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void notify_uspace_qpnp_adc_tm_fn(struct work_struct *work)
+{
+ struct qpnp_adc_tm_sensor *adc_tm = container_of(work,
+ struct qpnp_adc_tm_sensor, work);
+
+ sysfs_notify(&adc_tm->tz_dev->device.kobj,
+ NULL, "btm");
+}
+
+static void notify_usb_fn(struct work_struct *work)
+{
+ struct qpnp_adc_tm_drv *adc_tm = container_of(work,
+ struct qpnp_adc_tm_drv, usbid_work);
+ int rc;
+ u8 status_low, status_high;
+
+ if (adc_tm->usb_id_param->threshold_notification != NULL) {
+ rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_STATUS_LOW,
+ &status_low);
+ if (rc) {
+ pr_err("adc-tm read low status failed\n");
+ return;
+ }
+
+ rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_STATUS_HIGH,
+ &status_high);
+ if (rc) {
+ pr_err("adc-tm read high status failed\n");
+ return;
+ }
+
+ if (status_low & 1)
+ adc_tm->usb_id_param->threshold_notification(
+ ADC_TM_LOW_STATE, adc_tm->usb_id_param->usbid_ctx);
+ else if (status_high & 1)
+ adc_tm->usb_id_param->threshold_notification(
+ ADC_TM_HIGH_STATE, adc_tm->usb_id_param->usbid_ctx);
+ }
+
+ return;
+}
+
+static void notify_batt_fn(struct work_struct *work)
+{
+ struct qpnp_adc_tm_drv *adc_tm = container_of(work,
+ struct qpnp_adc_tm_drv, batt_work);
+ int rc;
+ u8 status_low, status_high;
+
+ if (adc_tm->battery_param->threshold_notification != NULL) {
+ rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_STATUS_LOW,
+ &status_low);
+ if (rc) {
+ pr_err("adc-tm read low status failed\n");
+ return;
+ }
+
+ rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_STATUS_HIGH,
+ &status_high);
+ if (rc) {
+ pr_err("adc-tm read high status failed\n");
+ return;
+ }
+
+ if (status_low & QPNP_ADC_TM_LOW_THR_INT_EN_M1)
+ adc_tm->battery_param->threshold_notification(
+ ADC_TM_LOW_STATE);
+ else if (status_high & QPNP_ADC_TM_HIGH_THR_INT_EN_M1)
+ adc_tm->battery_param->threshold_notification(
+ ADC_TM_HIGH_STATE);
+ }
+
+ return;
+}
+
+static int qpnp_adc_tm_activate_trip_type_fn(uint32_t btm_channel_num,
+ enum thermal_trip_activation_mode mode, u8 *data, uint32_t reg)
+{
+ u8 thr_int = 0;
+ int rc = 0;
+
+ rc = qpnp_adc_tm_read_reg(reg, &thr_int);
+ if (rc) {
+ pr_err("multi meas read failed\n");
+ return rc;
+ }
+
+ thr_int = adc_tm_data[btm_channel_num].low_thr_int_chan_en;
+
+ if (mode == THERMAL_TRIP_ACTIVATION_ENABLED)
+ thr_int |= *data;
+ else
+ thr_int &= ~*data;
+
+ rc = qpnp_adc_tm_write_reg(reg, thr_int);
+ if (rc)
+ pr_err("multi meas write failed\n");
+
+ return rc;
+}
+
+static int qpnp_adc_tm_activate_trip_type(struct thermal_zone_device *thermal,
+ int trip, enum thermal_trip_activation_mode mode)
+{
+ struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
+ int rc = 0;
+ u8 thr_int_en = 0;
+
+ if (!adc_tm)
+ return -EINVAL;
+
+ switch (trip) {
+ case ADC_TM_TRIP_HIGH_WARM:
+ thr_int_en = adc_tm_data[adc_tm->btm_channel_num].
+ low_thr_int_chan_en;
+ rc = qpnp_adc_tm_activate_trip_type_fn(adc_tm->btm_channel_num,
+ mode, &thr_int_en, QPNP_ADC_TM_LOW_THR_INT_EN);
+ if (rc)
+ pr_err("channel:%x failed\n", adc_tm->btm_channel_num);
+ break;
+ case ADC_TM_TRIP_LOW_COOL:
+ thr_int_en = adc_tm_data[adc_tm->btm_channel_num].
+ high_thr_int_chan_en;
+ rc = qpnp_adc_tm_activate_trip_type_fn(adc_tm->btm_channel_num,
+ mode, &thr_int_en, QPNP_ADC_TM_HIGH_THR_INT_EN);
+ if (rc)
+ pr_err("channel:%x failed\n", adc_tm->btm_channel_num);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return rc;
+}
+
+static int qpnp_adc_tm_read_status(void)
+{
+ struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
+ u8 status_low = 0, status_high = 0, qpnp_adc_tm_meas_en = 0;
+ u8 adc_tm_low_enable = 0, adc_tm_high_enable = 0;
+ u8 thr_int_disable = 0;
+ int rc = 0, sensor_notify_num = 0;
+
+ rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_STATUS_LOW, &status_low);
+ if (rc) {
+ pr_err("adc-tm-tm read status low failed with %d\n", rc);
+ goto fail;
+ }
+
+ rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_STATUS_HIGH, &status_high);
+ if (rc) {
+ pr_err("adc-tm-tm read status high failed with %d\n", rc);
+ goto fail;
+ }
+
+ /* Check which interrupt threshold is lower and measure against the
+ * enabled channel */
+ rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_MULTI_MEAS_EN,
+ &qpnp_adc_tm_meas_en);
+ if (rc) {
+ pr_err("adc-tm-tm read status high failed with %d\n", rc);
+ goto fail;
+ }
+
+ adc_tm_low_enable = qpnp_adc_tm_meas_en & status_low;
+ adc_tm_high_enable = qpnp_adc_tm_meas_en & status_high;
+
+ if (adc_tm_high_enable) {
+ sensor_notify_num = (adc_tm_high_enable >> 3);
+ switch (adc_tm_high_enable) {
+ case 1:
+ case 2:
+ {
+ if (adc_tm_high_enable == 1)
+ thr_int_disable =
+ QPNP_ADC_TM_HIGH_THR_INT_EN_M0;
+ else if (adc_tm_high_enable == 2)
+ thr_int_disable =
+ QPNP_ADC_TM_HIGH_THR_INT_EN_M1;
+
+ rc = qpnp_adc_tm_meas_int_update(
+ QPNP_ADC_TM_HIGH_THR_INT_EN,
+ thr_int_disable, false);
+ if (rc < 0) {
+ pr_err("high threshold int read failed\n");
+ goto fail;
+ }
+
+ if (adc_tm_high_enable == 1)
+ schedule_work(&adc_tm->usbid_work);
+ else if (adc_tm_high_enable == 2)
+ schedule_work(&adc_tm->batt_work);
+ }
+ break;
+ case 4:
+ case 8:
+ case 16:
+ {
+ /* High voltage threshold is triggered by low temp */
+ rc = qpnp_adc_tm_activate_trip_type(
+ adc_tm->sensor[sensor_notify_num].tz_dev,
+ ADC_TM_TRIP_LOW_COOL,
+ THERMAL_TRIP_ACTIVATION_DISABLED);
+ if (rc < 0) {
+ pr_err("notify error:%d\n", sensor_notify_num);
+ goto fail;
+ }
+ schedule_work(&adc_tm->sensor[sensor_notify_num].work);
+ }
+ break;
+ default:
+ rc = -EINVAL;
+ }
+ }
+
+ if (adc_tm_low_enable) {
+ sensor_notify_num = (adc_tm_low_enable >> 3);
+ switch (adc_tm_low_enable) {
+ case 1:
+ case 2:
+ {
+ if (adc_tm_low_enable == 1)
+ thr_int_disable = QPNP_ADC_TM_LOW_THR_INT_EN_M0;
+ else if (adc_tm_low_enable == 2)
+ thr_int_disable = QPNP_ADC_TM_LOW_THR_INT_EN_M1;
+
+ rc = qpnp_adc_tm_meas_int_update(
+ QPNP_ADC_TM_LOW_THR_INT_EN,
+ thr_int_disable, false);
+ if (rc < 0) {
+ pr_err("low threshold int disable failed\n");
+ goto fail;
+ }
+
+ if (adc_tm_low_enable == 1)
+ schedule_work(&adc_tm->usbid_work);
+ else if (adc_tm_low_enable == 2)
+ schedule_work(&adc_tm->batt_work);
+ }
+ break;
+ case 4:
+ case 8:
+ case 16:
+ {
+ /* Low voltage threshold is triggered by high temp */
+ rc = qpnp_adc_tm_activate_trip_type(
+ adc_tm->sensor[sensor_notify_num].tz_dev,
+ ADC_TM_TRIP_HIGH_WARM,
+ THERMAL_TRIP_ACTIVATION_DISABLED);
+ if (rc < 0) {
+ pr_err("notify error:%d\n", sensor_notify_num);
+ goto fail;
+ }
+ schedule_work(&adc_tm->sensor[sensor_notify_num].work);
+ }
+ break;
+ default:
+ rc = -EINVAL;
+ }
+ }
+
+fail:
+ return rc;
+}
+
+static void qpnp_adc_tm_high_thr_work(struct work_struct *work)
+{
+ int rc;
+
+ rc = qpnp_adc_tm_read_status();
+
+ return;
+}
+DECLARE_WORK(trigger_completion_adc_tm_high_thr_work,
+ qpnp_adc_tm_high_thr_work);
+
+static irqreturn_t qpnp_adc_tm_high_thr_isr(int irq, void *data)
+{
+ schedule_work(&trigger_completion_adc_tm_high_thr_work);
+
+ return IRQ_HANDLED;
+}
+
+static void qpnp_adc_tm_low_thr_work(struct work_struct *work)
+{
+ int rc;
+
+ rc = qpnp_adc_tm_read_status();
+
+ return;
+}
+DECLARE_WORK(trigger_completion_adc_tm_low_thr_work, qpnp_adc_tm_low_thr_work);
+
+static irqreturn_t qpnp_adc_tm_low_thr_isr(int irq, void *data)
+{
+ schedule_work(&trigger_completion_adc_tm_low_thr_work);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t qpnp_adc_tm_isr(int irq, void *dev_id)
+{
+ struct qpnp_adc_tm_drv *adc_tm = dev_id;
+
+ complete(&adc_tm->adc->adc_rslt_completion);
+
+ return IRQ_HANDLED;
+}
+
+static int qpnp_adc_read_temp(struct thermal_zone_device *thermal,
+ unsigned long *temp)
+{
+ struct qpnp_adc_tm_sensor *adc_tm_sensor = thermal->devdata;
+ struct qpnp_vadc_result result;
+ int rc = 0;
+
+ rc = qpnp_vadc_read(adc_tm_sensor->sensor_num, &result);
+ if (rc)
+ return rc;
+
+ *temp = result.physical;
+
+ return rc;
+}
+
+static struct thermal_zone_device_ops qpnp_adc_tm_thermal_ops = {
+ .get_temp = qpnp_adc_read_temp,
+ .get_mode = qpnp_adc_tm_get_mode,
+ .set_mode = qpnp_adc_tm_set_mode,
+ .get_trip_type = qpnp_adc_tm_get_trip_type,
+ .activate_trip_type = qpnp_adc_tm_activate_trip_type,
+ .get_trip_temp = qpnp_adc_tm_get_trip_temp,
+ .set_trip_temp = qpnp_adc_tm_set_trip_temp,
+};
+
+int32_t qpnp_adc_tm_usbid_configure(struct qpnp_adc_tm_usbid_param *param)
+{
+ struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
+ uint32_t channel;
+ int rc = 0;
+
+ if (!adc_tm || !adc_tm->adc_tm_initialized)
+ return -ENODEV;
+
+ if (param->threshold_notification == NULL) {
+ pr_err("No USB_ID high/low voltage notificaton??\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&adc_tm->adc->adc_lock);
+
+ adc_tm->adc->amux_prop->amux_channel = LR_MUX10_PU2_AMUX_USB_ID_LV;
+ channel = LR_MUX10_PU2_AMUX_USB_ID_LV;
+ adc_tm->adc->amux_prop->decimation =
+ adc_tm->adc->adc_channels[channel].adc_decimation;
+ adc_tm->adc->amux_prop->hw_settle_time =
+ adc_tm->adc->adc_channels[channel].hw_settle_time;
+ adc_tm->adc->amux_prop->fast_avg_setup =
+ adc_tm->adc->adc_channels[channel].fast_avg_setup;
+ adc_tm->adc->amux_prop->mode_sel =
+ ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT;
+ adc_tm->adc->amux_prop->chan_prop->meas_interval1 =
+ ADC_MEAS1_INTERVAL_1S;
+ qpnp_adc_usb_scaler(param, &adc_tm->adc->amux_prop->chan_prop->low_thr,
+ &adc_tm->adc->amux_prop->chan_prop->high_thr);
+ adc_tm->adc->amux_prop->chan_prop->tm_channel_select =
+ QPNP_ADC_TM_M0_ADC_CH_SEL_CTL;
+ adc_tm->adc->amux_prop->chan_prop->timer_select =
+ ADC_MEAS_TIMER_SELECT1;
+ adc_tm->adc->amux_prop->chan_prop->state_request =
+ param->state_request;
+ rc = qpnp_adc_tm_configure(adc_tm->adc->amux_prop);
+ if (rc) {
+ pr_err("adc-tm configure failed with %d\n", rc);
+ goto fail_unlock;
+ }
+
+ adc_tm->usb_id_param = param;
+
+fail_unlock:
+ mutex_unlock(&adc_tm->adc->adc_lock);
+
+ return rc;
+}
+EXPORT_SYMBOL(qpnp_adc_tm_usbid_configure);
+
+static int32_t qpnp_adc_tm_chan_usbid_chan_btm_end(
+ uint32_t btm_chan_num)
+{
+ int32_t rc = 0;
+
+ rc = qpnp_adc_tm_meas_int_update(QPNP_ADC_TM_LOW_THR_INT_EN,
+ adc_tm_data[btm_chan_num].low_thr_int_chan_en,
+ false);
+ if (rc < 0) {
+ pr_err("low threshold int write failed\n");
+ return rc;
+ }
+
+ rc = qpnp_adc_tm_meas_int_update(QPNP_ADC_TM_HIGH_THR_INT_EN,
+ adc_tm_data[btm_chan_num].high_thr_int_chan_en,
+ false);
+ if (rc < 0) {
+ pr_err("high threshold int enable failed\n");
+ return rc;
+ }
+
+ rc = qpnp_adc_tm_meas_int_update(QPNP_ADC_TM_MULTI_MEAS_EN,
+ adc_tm_data[btm_chan_num].multi_meas_en,
+ false);
+ if (rc < 0) {
+ pr_err("multi measurement en failed\n");
+ return rc;
+ }
+
+ rc = qpnp_adc_tm_enable(false);
+ if (rc < 0)
+ pr_err("TM disable failed\n");
+
+ return rc;
+}
+
+int32_t qpnp_adc_tm_usbid_end(void)
+{
+ struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
+ int rc = 0;
+
+ if (!adc_tm || !adc_tm->adc_tm_initialized)
+ return -ENODEV;
+
+ mutex_lock(&adc_tm->adc->adc_lock);
+
+ rc = qpnp_adc_tm_chan_usbid_chan_btm_end(
+ QPNP_ADC_TM_M0_ADC_CH_SEL_CTL);
+ if (rc < 0)
+ pr_err("disabling thresholds for usb channel failed\n");
+
+ mutex_unlock(&adc_tm->adc->adc_lock);
+
+ return rc;
+}
+EXPORT_SYMBOL(qpnp_adc_tm_usbid_end);
+
+int32_t qpnp_adc_tm_btm_configure(struct qpnp_adc_tm_btm_param *param)
+{
+ struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
+ uint32_t channel;
+ int rc = 0;
+
+ if (!adc_tm || !adc_tm->adc_tm_initialized)
+ return -ENODEV;
+
+ if (param->threshold_notification == NULL) {
+ pr_err("No battery high/low temp notificaton??\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&adc_tm->adc->adc_lock);
+
+ adc_tm->adc->amux_prop->amux_channel = LR_MUX1_BATT_THERM;
+ channel = LR_MUX1_BATT_THERM;
+ adc_tm->adc->amux_prop->decimation =
+ adc_tm->adc->adc_channels[channel].adc_decimation;
+ adc_tm->adc->amux_prop->hw_settle_time =
+ adc_tm->adc->adc_channels[channel].hw_settle_time;
+ adc_tm->adc->amux_prop->fast_avg_setup =
+ adc_tm->adc->adc_channels[channel].fast_avg_setup;
+ adc_tm->adc->amux_prop->mode_sel =
+ ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT;
+ adc_tm->adc->amux_prop->chan_prop->meas_interval2 =
+ ADC_MEAS2_INTERVAL_1S;
+ qpnp_adc_btm_scaler(param, &adc_tm->adc->amux_prop->chan_prop->low_thr,
+ &adc_tm->adc->amux_prop->chan_prop->high_thr);
+ adc_tm->adc->amux_prop->chan_prop->tm_channel_select =
+ QPNP_ADC_TM_M1_ADC_CH_SEL_CTL;
+ adc_tm->adc->amux_prop->chan_prop->timer_select =
+ ADC_MEAS_TIMER_SELECT2;
+ adc_tm->adc->amux_prop->chan_prop->state_request =
+ param->state_request;
+ rc = qpnp_adc_tm_configure(adc_tm->adc->amux_prop);
+ if (rc) {
+ pr_err("adc-tm configure failed with %d\n", rc);
+ goto fail_unlock;
+ }
+
+ adc_tm->battery_param = param;
+
+fail_unlock:
+ mutex_unlock(&adc_tm->adc->adc_lock);
+
+ return rc;
+}
+EXPORT_SYMBOL(qpnp_adc_tm_btm_configure);
+
+int32_t qpnp_adc_tm_btm_end(void)
+{
+ struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
+ int rc = 0;
+
+ if (!adc_tm || !adc_tm->adc_tm_initialized)
+ return -ENODEV;
+
+ mutex_lock(&adc_tm->adc->adc_lock);
+
+ rc = qpnp_adc_tm_chan_usbid_chan_btm_end(
+ QPNP_ADC_TM_M1_ADC_CH_SEL_CTL);
+ if (rc < 0)
+ pr_err("disabling thresholds for batt channel failed\n");
+
+ mutex_unlock(&adc_tm->adc->adc_lock);
+
+ return rc;
+}
+EXPORT_SYMBOL(qpnp_adc_tm_btm_end);
+
+int32_t qpnp_adc_tm_is_ready(void)
+{
+ struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
+
+ if (!adc_tm || !adc_tm->adc_tm_initialized)
+ return -EPROBE_DEFER;
+ else
+ return 0;
+}
+EXPORT_SYMBOL(qpnp_adc_tm_is_ready);
+
+static int __devinit qpnp_adc_tm_probe(struct spmi_device *spmi)
+{
+ struct device_node *node = spmi->dev.of_node, *child;
+ struct qpnp_adc_tm_drv *adc_tm;
+ struct qpnp_adc_drv *adc_qpnp;
+ int32_t count_adc_channel_list = 0, rc, i = 0, j = 0;
+ u8 thr_init = 0;
+
+ if (!node)
+ return -EINVAL;
+
+ if (qpnp_adc_tm) {
+ pr_err("adc-tm already in use\n");
+ return -EBUSY;
+ }
+
+ for_each_child_of_node(node, child)
+ count_adc_channel_list++;
+
+ if (!count_adc_channel_list) {
+ pr_err("No channel listing\n");
+ return -EINVAL;
+ }
+
+ adc_tm = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_tm_drv) +
+ (count_adc_channel_list *
+ sizeof(struct qpnp_adc_tm_sensor)),
+ GFP_KERNEL);
+ if (!adc_tm) {
+ dev_err(&spmi->dev, "Unable to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ adc_qpnp = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_drv),
+ GFP_KERNEL);
+ if (!adc_qpnp) {
+ dev_err(&spmi->dev, "Unable to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ adc_tm->adc = adc_qpnp;
+
+ rc = qpnp_adc_get_devicetree_data(spmi, adc_tm->adc);
+ if (rc) {
+ dev_err(&spmi->dev, "failed to read device tree\n");
+ return rc;
+ }
+
+ /* Register the ADC peripheral interrupt */
+ adc_tm->adc->adc_high_thr_irq = spmi_get_irq_byname(spmi,
+ NULL, "high-thr-en-set");
+ if (adc_tm->adc->adc_high_thr_irq < 0) {
+ pr_err("Invalid irq\n");
+ return -ENXIO;
+ }
+
+ adc_tm->adc->adc_low_thr_irq = spmi_get_irq_byname(spmi,
+ NULL, "low-thr-en-set");
+ if (adc_tm->adc->adc_low_thr_irq < 0) {
+ pr_err("Invalid irq\n");
+ return -ENXIO;
+ }
+
+ rc = devm_request_irq(&spmi->dev, adc_tm->adc->adc_irq_eoc,
+ qpnp_adc_tm_isr, IRQF_TRIGGER_RISING,
+ "qpnp_adc_tm_interrupt", adc_tm);
+ if (rc) {
+ dev_err(&spmi->dev,
+ "failed to request adc irq with error %d\n", rc);
+ return rc;
+ } else {
+ enable_irq_wake(adc_tm->adc->adc_irq_eoc);
+ }
+
+ rc = devm_request_irq(&spmi->dev, adc_tm->adc->adc_high_thr_irq,
+ qpnp_adc_tm_high_thr_isr,
+ IRQF_TRIGGER_RISING, "qpnp_adc_tm_high_interrupt", adc_tm);
+ if (rc) {
+ dev_err(&spmi->dev, "failed to request adc irq\n");
+ return rc;
+ } else {
+ enable_irq_wake(adc_tm->adc->adc_high_thr_irq);
+ }
+
+ rc = devm_request_irq(&spmi->dev, adc_tm->adc->adc_low_thr_irq,
+ qpnp_adc_tm_low_thr_isr,
+ IRQF_TRIGGER_RISING, "qpnp_adc_tm_low_interrupt", adc_tm);
+ if (rc) {
+ dev_err(&spmi->dev, "failed to request adc irq\n");
+ return rc;
+ } else {
+ enable_irq_wake(adc_tm->adc->adc_low_thr_irq);
+ }
+
+ for_each_child_of_node(node, child) {
+ char name[25];
+ int btm_channel_num;
+ rc = of_property_read_u32(child,
+ "qcom,btm-channel-number", &btm_channel_num);
+ if (rc) {
+ pr_err("Invalid btm channel number\n");
+ return -EINVAL;
+ }
+
+ if ((btm_channel_num != QPNP_ADC_TM_M0_ADC_CH_SEL_CTL) &&
+ (btm_channel_num != QPNP_ADC_TM_M1_ADC_CH_SEL_CTL)) {
+ /* Register with the thermal zone */
+ adc_tm->sensor[i].mode = THERMAL_DEVICE_DISABLED;
+ snprintf(name, sizeof(name), "qpnp_adc_tm_sensor%d", i);
+ adc_tm->sensor[i].sensor_num =
+ adc_tm->adc->adc_channels[j].channel_num;
+ adc_tm->sensor[i].btm_channel_num = btm_channel_num;
+ adc_tm->sensor[i].meas_interval =
+ QPNP_ADC_TM_MEAS_INTERVAL;
+ adc_tm->sensor[i].low_thr = QPNP_ADC_TM_M0_LOW_THR;
+ adc_tm->sensor[i].high_thr = QPNP_ADC_TM_M0_HIGH_THR;
+ adc_tm->sensor[i].tz_dev =
+ thermal_zone_device_register(name,
+ ADC_TM_TRIP_NUM,
+ &adc_tm->sensor[i],
+ &qpnp_adc_tm_thermal_ops, 0, 0, 0, 0);
+ if (IS_ERR(adc_tm->sensor[i].tz_dev))
+ pr_err("thermal device register failed.\n");
+ INIT_WORK(&adc_tm->sensor[i].work,
+ notify_uspace_qpnp_adc_tm_fn);
+ i++;
+ }
+ j++;
+ }
+ INIT_WORK(&adc_tm->usbid_work, notify_usb_fn);
+ INIT_WORK(&adc_tm->batt_work, notify_batt_fn);
+ qpnp_adc_tm = adc_tm;
+ dev_set_drvdata(&spmi->dev, adc_tm);
+ rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_HIGH_THR_INT_EN, thr_init);
+ if (rc < 0) {
+ pr_err("high thr init failed\n");
+ return rc;
+ }
+
+ rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_LOW_THR_INT_EN, thr_init);
+ if (rc < 0) {
+ pr_err("low thr init failed\n");
+ return rc;
+ }
+
+ rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_MULTI_MEAS_EN, thr_init);
+ if (rc < 0) {
+ pr_err("multi meas en failed\n");
+ return rc;
+ }
+
+ adc_tm->adc_tm_initialized = true;
+
+ return 0;
+}
+
+static int __devexit qpnp_adc_tm_remove(struct spmi_device *spmi)
+{
+ struct qpnp_adc_tm_drv *adc_tm = dev_get_drvdata(&spmi->dev);
+ struct device_node *node = spmi->dev.of_node;
+ struct device_node *child;
+ int i = 0;
+
+ for_each_child_of_node(node, child) {
+ thermal_zone_device_unregister(adc_tm->sensor[i].tz_dev);
+ i++;
+ }
+
+ adc_tm->adc_tm_initialized = false;
+ dev_set_drvdata(&spmi->dev, NULL);
+
+ return 0;
+}
+
+static const struct of_device_id qpnp_adc_tm_match_table[] = {
+ { .compatible = "qcom,qpnp-adc-tm" },
+ {}
+};
+
+static struct spmi_driver qpnp_adc_tm_driver = {
+ .driver = {
+ .name = "qcom,qpnp-adc-tm",
+ .of_match_table = qpnp_adc_tm_match_table,
+ },
+ .probe = qpnp_adc_tm_probe,
+ .remove = qpnp_adc_tm_remove,
+};
+
+static int __init qpnp_adc_tm_init(void)
+{
+ return spmi_driver_register(&qpnp_adc_tm_driver);
+}
+module_init(qpnp_adc_tm_init);
+
+static void __exit qpnp_adc_tm_exit(void)
+{
+ spmi_driver_unregister(&qpnp_adc_tm_driver);
+}
+module_exit(qpnp_adc_tm_exit);
+
+MODULE_DESCRIPTION("QPNP PMIC ADC Threshold Monitoring driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/msm_serial_hs_lite.c b/drivers/tty/serial/msm_serial_hs_lite.c
index 0189a07..72a12d1 100644
--- a/drivers/tty/serial/msm_serial_hs_lite.c
+++ b/drivers/tty/serial/msm_serial_hs_lite.c
@@ -669,15 +669,15 @@
* Check requested baud rate and for higher baud rate than 460800,
* calculate required uart clock frequency and set the same.
*/
- if (baud > 460800) {
-
+ 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;
- }
+ else
+ port->uartclk = 7372800;
+
+ if (clk_set_rate(msm_hsl_port->clk, port->uartclk)) {
+ pr_err("Error: setting uartclk rate %u\n", port->uartclk);
+ WARN_ON(1);
+ return;
}
/* Set timeout to be ~600x the character transmit time */
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index c0b4b57..265a685 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -300,19 +300,7 @@
}
}
-/* XHCI reset, resets other CORE registers as well, re-init those */
-void dwc3_post_host_reset_core_init(struct dwc3 *dwc)
-{
- /*
- * XHCI reset clears EVENT buffer register as well, re-init
- * EVENT buffers and also do device specific re-initialization
- */
- dwc3_event_buffers_setup(dwc);
-
- dwc3_gadget_restart(dwc);
-}
-
-static void __devinit dwc3_cache_hwparams(struct dwc3 *dwc)
+static void dwc3_cache_hwparams(struct dwc3 *dwc)
{
struct dwc3_hwparams *parms = &dwc->hwparams;
@@ -333,7 +321,7 @@
*
* Returns 0 on success otherwise negative errno.
*/
-static int __devinit dwc3_core_init(struct dwc3 *dwc)
+static int dwc3_core_init(struct dwc3 *dwc)
{
unsigned long timeout;
u32 reg;
@@ -434,11 +422,13 @@
dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
}
- ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
- if (ret) {
- dev_err(dwc->dev, "failed to allocate event buffers\n");
- ret = -ENOMEM;
- goto err1;
+ if (!dwc->ev_buffs) {
+ ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
+ if (ret) {
+ dev_err(dwc->dev, "failed to allocate event buffers\n");
+ ret = -ENOMEM;
+ goto err1;
+ }
}
ret = dwc3_event_buffers_setup(dwc);
@@ -462,6 +452,13 @@
dwc3_free_event_buffers(dwc);
}
+/* XHCI reset, resets other CORE registers as well, re-init those */
+void dwc3_post_host_reset_core_init(struct dwc3 *dwc)
+{
+ dwc3_core_init(dwc);
+ dwc3_gadget_restart(dwc);
+}
+
#define DWC3_ALIGN_MASK (16 - 1)
static int __devinit dwc3_probe(struct platform_device *pdev)
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 2b0a79f..a3abe23 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.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
@@ -34,16 +34,31 @@
#include <linux/usb/msm_hsusb.h>
#include <linux/regulator/consumer.h>
#include <linux/power_supply.h>
+#include <linux/qpnp/qpnp-adc.h>
#include <mach/rpm-regulator.h>
#include <mach/rpm-regulator-smd.h>
#include <mach/msm_xo.h>
#include <mach/msm_bus.h>
+#include <mach/clk.h>
#include "dwc3_otg.h"
#include "core.h"
#include "gadget.h"
+/* ADC threshold values */
+static int adc_low_threshold = 700;
+module_param(adc_low_threshold, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(adc_low_threshold, "ADC ID Low voltage threshold");
+
+static int adc_high_threshold = 950;
+module_param(adc_high_threshold, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(adc_high_threshold, "ADC ID High voltage threshold");
+
+static int adc_meas_interval = ADC_MEAS1_INTERVAL_1S;
+module_param(adc_meas_interval, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(adc_meas_interval, "ADC ID polling period");
+
/**
* USB DBM Hardware registers.
*
@@ -160,6 +175,9 @@
struct usb_phy *otg_xceiv;
struct delayed_work chg_work;
enum usb_chg_state chg_state;
+ struct qpnp_adc_tm_usbid_param adc_param;
+ struct delayed_work init_adc_work;
+ bool id_adc_detect;
u8 dcd_retries;
u32 bus_perf_client;
struct msm_bus_scale_pdata *bus_scale_table;
@@ -171,6 +189,7 @@
unsigned int vdd_low_vol_level;
unsigned int vdd_high_vol_level;
bool vbus_active;
+ bool ext_inuse;
};
#define USB_HSPHY_3P3_VOL_MIN 3050000 /* uV */
@@ -188,6 +207,8 @@
static struct dwc3_msm *context;
static u64 dwc3_msm_dma_mask = DMA_BIT_MASK(64);
+static struct usb_ext_notification *usb_ext;
+
/**
*
* Read register with debug info.
@@ -894,6 +915,33 @@
}
EXPORT_SYMBOL(msm_ep_unconfig);
+/**
+ * msm_register_usb_ext_notification: register for event notification
+ * @info: pointer to client usb_ext_notification structure. May be NULL.
+ *
+ * @return int - 0 on success, negative on error
+ */
+int msm_register_usb_ext_notification(struct usb_ext_notification *info)
+{
+ pr_debug("%s usb_ext: %p\n", __func__, info);
+
+ if (info) {
+ if (usb_ext) {
+ pr_err("%s: already registered\n", __func__);
+ return -EEXIST;
+ }
+
+ if (!info->notify) {
+ pr_err("%s: notify is NULL\n", __func__);
+ return -EINVAL;
+ }
+ }
+
+ usb_ext = info;
+ return 0;
+}
+EXPORT_SYMBOL(msm_register_usb_ext_notification);
+
/* HSPHY */
static int dwc3_hsusb_config_vddcx(int high)
{
@@ -1099,6 +1147,95 @@
return rc < 0 ? rc : 0;
}
+static int dwc3_msm_link_clk_reset(bool assert)
+{
+ int ret = 0;
+ struct dwc3_msm *mdwc = context;
+
+ if (assert) {
+ /* Using asynchronous block reset to the hardware */
+ dev_dbg(mdwc->dev, "block_reset ASSERT\n");
+ clk_disable_unprepare(mdwc->ref_clk);
+ clk_disable_unprepare(mdwc->iface_clk);
+ clk_disable_unprepare(mdwc->core_clk);
+ ret = clk_reset(mdwc->core_clk, CLK_RESET_ASSERT);
+ if (ret)
+ dev_err(mdwc->dev, "dwc3 core_clk assert failed\n");
+ } else {
+ dev_dbg(mdwc->dev, "block_reset DEASSERT\n");
+ ret = clk_reset(mdwc->core_clk, CLK_RESET_DEASSERT);
+ ndelay(200);
+ clk_prepare_enable(mdwc->core_clk);
+ clk_prepare_enable(mdwc->ref_clk);
+ clk_prepare_enable(mdwc->iface_clk);
+ if (ret)
+ dev_err(mdwc->dev, "dwc3 core_clk deassert failed\n");
+ }
+
+ return ret;
+}
+
+/* Initialize QSCRATCH registers for HSPHY and SSPHY operation */
+static void dwc3_msm_qscratch_reg_init(struct dwc3_msm *msm)
+{
+ u32 data = 0;
+
+ /* SSPHY Initialization: Use ref_clk from pads and set its parameters */
+ dwc3_msm_write_reg(msm->base, SS_PHY_CTRL_REG, 0x10210002);
+ msleep(30);
+ /* Assert SSPHY reset */
+ dwc3_msm_write_reg(msm->base, SS_PHY_CTRL_REG, 0x10210082);
+ usleep_range(2000, 2200);
+ /* De-assert SSPHY reset - power and ref_clock must be ON */
+ dwc3_msm_write_reg(msm->base, SS_PHY_CTRL_REG, 0x10210002);
+ usleep_range(2000, 2200);
+ /* Ref clock must be stable now, enable ref clock for HS mode */
+ dwc3_msm_write_reg(msm->base, SS_PHY_CTRL_REG, 0x10210102);
+ usleep_range(2000, 2200);
+ /*
+ * HSPHY Initialization: Enable UTMI clock and clamp enable HVINTs,
+ * and disable RETENTION (power-on default is ENABLED)
+ */
+ dwc3_msm_write_reg(msm->base, HS_PHY_CTRL_REG, 0x5220bb2);
+ usleep_range(2000, 2200);
+ /* Disable (bypass) VBUS and ID filters */
+ dwc3_msm_write_reg(msm->base, QSCRATCH_GENERAL_CFG, 0x78);
+
+ /*
+ * WORKAROUND: There is SSPHY suspend bug due to which USB enumerates
+ * in HS mode instead of SS mode. Workaround it by asserting
+ * LANE0.TX_ALT_BLOCK.EN_ALT_BUS to enable TX to use alt bus mode
+ */
+ data = dwc3_msm_ssusb_read_phycreg(msm->base, 0x102D);
+ data |= (1 << 7);
+ dwc3_msm_ssusb_write_phycreg(msm->base, 0x102D, data);
+
+ data = dwc3_msm_ssusb_read_phycreg(msm->base, 0x1010);
+ data &= ~0xFF0;
+ data |= 0x40;
+ dwc3_msm_ssusb_write_phycreg(msm->base, 0x1010, data);
+}
+
+static void dwc3_msm_block_reset(void)
+{
+ struct dwc3_msm *mdwc = context;
+ int ret = 0;
+
+ ret = dwc3_msm_link_clk_reset(1);
+ if (ret)
+ return;
+
+ usleep_range(1000, 1200);
+ ret = dwc3_msm_link_clk_reset(0);
+ if (ret)
+ return;
+
+ usleep_range(10000, 12000);
+
+ /* Reinitialize QSCRATCH registers after block reset */
+ dwc3_msm_qscratch_reg_init(mdwc);
+}
+
static void dwc3_chg_enable_secondary_det(struct dwc3_msm *mdwc)
{
u32 chg_ctrl;
@@ -1482,7 +1619,7 @@
}
}
-static u32 debug_id, debug_bsv, debug_connect;
+static u32 debug_id = true, debug_bsv, debug_connect;
static int dwc3_connect_show(struct seq_file *s, void *unused)
{
@@ -1628,7 +1765,6 @@
if (mdwc->otg_xceiv && (mdwc->ext_xceiv.otg_capability ||
!init)) {
mdwc->ext_xceiv.bsv = val->intval;
- mdwc->ext_xceiv.id = DWC3_ID_FLOAT;
if (atomic_read(&mdwc->in_lpm)) {
dev_dbg(mdwc->dev,
"%s received in LPM\n", __func__);
@@ -1669,6 +1805,126 @@
POWER_SUPPLY_PROP_SCOPE,
};
+static void dwc3_init_adc_work(struct work_struct *w);
+
+static void dwc3_ext_notify_online(int on)
+{
+ struct dwc3_msm *mdwc = context;
+
+ if (!mdwc) {
+ pr_err("%s: DWC3 driver already removed\n", __func__);
+ return;
+ }
+
+ dev_dbg(mdwc->dev, "notify %s%s\n", on ? "" : "dis", "connected");
+
+ if (!on) {
+ /* external client offline; revert back to USB */
+ mdwc->ext_inuse = false;
+ queue_delayed_work(system_nrt_wq, &mdwc->resume_work, 0);
+ }
+}
+
+static bool dwc3_ext_trigger_handled(struct dwc3_msm *mdwc,
+ enum dwc3_id_state id)
+{
+ int ret;
+
+ if (!usb_ext)
+ return false;
+
+ ret = usb_ext->notify(usb_ext->ctxt, id, dwc3_ext_notify_online);
+ dev_dbg(mdwc->dev, "%s: external event handler returned %d\n", __func__,
+ ret);
+ mdwc->ext_inuse = ret == 0;
+ return mdwc->ext_inuse;
+}
+
+static void dwc3_adc_notification(enum qpnp_tm_state state, void *ctx)
+{
+ struct dwc3_msm *mdwc = ctx;
+
+ if (state >= ADC_TM_STATE_NUM) {
+ pr_err("%s: invalid notification %d\n", __func__, state);
+ return;
+ }
+
+ dev_dbg(mdwc->dev, "%s: state = %s\n", __func__,
+ state == ADC_TM_HIGH_STATE ? "high" : "low");
+
+ if (state == ADC_TM_HIGH_STATE) {
+ mdwc->ext_xceiv.id = DWC3_ID_FLOAT;
+ mdwc->adc_param.state_request = ADC_TM_LOW_THR_ENABLE;
+ } else {
+ mdwc->ext_xceiv.id = DWC3_ID_GROUND;
+ mdwc->adc_param.state_request = ADC_TM_HIGH_THR_ENABLE;
+ }
+
+ /* Give external client a chance to handle, otherwise notify OTG */
+ if (!mdwc->ext_inuse &&
+ !dwc3_ext_trigger_handled(mdwc, mdwc->ext_xceiv.id))
+ queue_delayed_work(system_nrt_wq, &mdwc->resume_work, 0);
+
+ /* re-arm ADC interrupt */
+ qpnp_adc_tm_usbid_configure(&mdwc->adc_param);
+}
+
+static void dwc3_init_adc_work(struct work_struct *w)
+{
+ struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm,
+ init_adc_work.work);
+ int ret;
+
+ ret = qpnp_adc_tm_is_ready();
+ if (ret == -EPROBE_DEFER) {
+ queue_delayed_work(system_nrt_wq, to_delayed_work(w),
+ msecs_to_jiffies(100));
+ return;
+ }
+
+ mdwc->adc_param.low_thr = adc_low_threshold;
+ mdwc->adc_param.high_thr = adc_high_threshold;
+ mdwc->adc_param.timer_interval = adc_meas_interval;
+ mdwc->adc_param.state_request = ADC_TM_HIGH_LOW_THR_ENABLE;
+ mdwc->adc_param.usbid_ctx = mdwc;
+ mdwc->adc_param.threshold_notification = dwc3_adc_notification;
+
+ ret = qpnp_adc_tm_usbid_configure(&mdwc->adc_param);
+ if (ret) {
+ dev_err(mdwc->dev, "%s: request ADC error %d\n", __func__, ret);
+ return;
+ }
+
+ mdwc->id_adc_detect = true;
+}
+
+static ssize_t adc_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", context->id_adc_detect ?
+ "enabled" : "disabled");
+}
+
+static ssize_t adc_enable_store(struct device *dev,
+ struct device_attribute *attr, const char
+ *buf, size_t size)
+{
+ if (!strnicmp(buf, "enable", 6)) {
+ if (!context->id_adc_detect)
+ dwc3_init_adc_work(&context->init_adc_work.work);
+ return size;
+ } else if (!strnicmp(buf, "disable", 7)) {
+ qpnp_adc_tm_usbid_end();
+ context->id_adc_detect = false;
+ return size;
+ }
+
+ return -EINVAL;
+}
+
+static DEVICE_ATTR(adc_enable, S_IRUGO | S_IWUSR, adc_enable_show,
+ adc_enable_store);
+
static int __devinit dwc3_msm_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
@@ -1679,7 +1935,6 @@
int ret = 0;
int len = 0;
u32 tmp[3];
- u32 data = 0;
msm = devm_kzalloc(&pdev->dev, sizeof(*msm), GFP_KERNEL);
if (!msm) {
@@ -1694,6 +1949,7 @@
INIT_LIST_HEAD(&msm->req_complete_list);
INIT_DELAYED_WORK(&msm->chg_work, dwc3_chg_detect_work);
INIT_DELAYED_WORK(&msm->resume_work, dwc3_resume_work);
+ INIT_DELAYED_WORK(&msm->init_adc_work, dwc3_init_adc_work);
msm->xo_handle = msm_xo_get(MSM_XO_TCXO_D0, "usb");
if (IS_ERR(msm->xo_handle)) {
@@ -1832,6 +2088,7 @@
goto free_hs_ldo_init;
}
+ msm->ext_xceiv.id = DWC3_ID_FLOAT;
msm->ext_xceiv.otg_capability = of_property_read_bool(node,
"qcom,otg-capability");
msm->charger.charging_disabled = of_property_read_bool(node,
@@ -1852,6 +2109,10 @@
}
enable_irq_wake(msm->hs_phy_irq);
}
+ } else {
+ /* Use ADC for ID pin detection */
+ queue_delayed_work(system_nrt_wq, &msm->init_adc_work, 0);
+ device_create_file(&pdev->dev, &dev_attr_adc_enable);
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
@@ -1902,40 +2163,7 @@
msm->resource_size = resource_size(res);
msm->dwc3 = dwc3;
- /* SSPHY Initialization: Use ref_clk from pads and set its parameters */
- dwc3_msm_write_reg(msm->base, SS_PHY_CTRL_REG, 0x10210002);
- msleep(30);
- /* Assert SSPHY reset */
- dwc3_msm_write_reg(msm->base, SS_PHY_CTRL_REG, 0x10210082);
- usleep_range(2000, 2200);
- /* De-assert SSPHY reset - power and ref_clock must be ON */
- dwc3_msm_write_reg(msm->base, SS_PHY_CTRL_REG, 0x10210002);
- usleep_range(2000, 2200);
- /* Ref clock must be stable now, enable ref clock for HS mode */
- dwc3_msm_write_reg(msm->base, SS_PHY_CTRL_REG, 0x10210102);
- usleep_range(2000, 2200);
- /*
- * HSPHY Initialization: Enable UTMI clock and clamp enable HVINTs,
- * and disable RETENTION (power-on default is ENABLED)
- */
- dwc3_msm_write_reg(msm->base, HS_PHY_CTRL_REG, 0x5220bb2);
- usleep_range(2000, 2200);
- /* Disable (bypass) VBUS and ID filters */
- dwc3_msm_write_reg(msm->base, QSCRATCH_GENERAL_CFG, 0x78);
-
- /*
- * WORKAROUND: There is SSPHY suspend bug due to which USB enumerates
- * in HS mode instead of SS mode. Workaround it by asserting
- * LANE0.TX_ALT_BLOCK.EN_ALT_BUS to enable TX to use alt bus mode
- */
- data = dwc3_msm_ssusb_read_phycreg(msm->base, 0x102D);
- data |= (1 << 7);
- dwc3_msm_ssusb_write_phycreg(msm->base, 0x102D, data);
-
- data = dwc3_msm_ssusb_read_phycreg(msm->base, 0x1010);
- data &= ~0xFF0;
- data |= 0x40;
- dwc3_msm_ssusb_write_phycreg(msm->base, 0x1010, data);
+ dwc3_msm_qscratch_reg_init(msm);
pm_runtime_set_active(msm->dev);
pm_runtime_enable(msm->dev);
@@ -2018,6 +2246,8 @@
goto put_xcvr;
}
+ if (msm->ext_xceiv.otg_capability)
+ msm->ext_xceiv.ext_block_reset = dwc3_msm_block_reset;
ret = dwc3_set_ext_xceiv(msm->otg_xceiv->otg, &msm->ext_xceiv);
if (ret || !msm->ext_xceiv.notify_ext_events) {
dev_err(&pdev->dev, "failed to register xceiver: %d\n",
@@ -2080,12 +2310,15 @@
{
struct dwc3_msm *msm = platform_get_drvdata(pdev);
+ if (msm->id_adc_detect)
+ qpnp_adc_tm_usbid_end();
if (dwc3_debugfs_root)
debugfs_remove_recursive(dwc3_debugfs_root);
if (msm->otg_xceiv) {
dwc3_start_chg_det(&msm->charger, false);
usb_put_transceiver(msm->otg_xceiv);
}
+
pm_runtime_disable(msm->dev);
platform_device_unregister(msm->dwc3);
wake_lock_destroy(&msm->wlock);
diff --git a/drivers/usb/dwc3/dwc3_otg.c b/drivers/usb/dwc3/dwc3_otg.c
index fab443c..136cc5d 100644
--- a/drivers/usb/dwc3/dwc3_otg.c
+++ b/drivers/usb/dwc3/dwc3_otg.c
@@ -1,7 +1,7 @@
/**
* dwc3_otg.c - DesignWare USB3 DRD Controller OTG
*
- * 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
@@ -38,12 +38,21 @@
*/
static void dwc3_otg_set_host_regs(struct dwc3_otg *dotg)
{
- u32 octl;
+ u32 reg;
+ struct dwc3 *dwc = dotg->dwc;
+ struct dwc3_ext_xceiv *ext_xceiv = dotg->ext_xceiv;
- /* Set OCTL[6](PeriMode) to 0 (host) */
- octl = dwc3_readl(dotg->regs, DWC3_OCTL);
- octl &= ~DWC3_OTG_OCTL_PERIMODE;
- dwc3_writel(dotg->regs, DWC3_OCTL, octl);
+ if (ext_xceiv && !ext_xceiv->otg_capability) {
+ /* Set OCTL[6](PeriMode) to 0 (host) */
+ reg = dwc3_readl(dotg->regs, DWC3_OCTL);
+ reg &= ~DWC3_OTG_OCTL_PERIMODE;
+ dwc3_writel(dotg->regs, DWC3_OCTL, reg);
+ } else {
+ reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+ reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
+ reg |= DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_HOST);
+ dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+ }
}
/**
@@ -76,17 +85,25 @@
*/
static void dwc3_otg_set_peripheral_regs(struct dwc3_otg *dotg)
{
- u32 octl;
+ u32 reg;
+ struct dwc3 *dwc = dotg->dwc;
+ struct dwc3_ext_xceiv *ext_xceiv = dotg->ext_xceiv;
- /* Set OCTL[6](PeriMode) to 1 (peripheral) */
- octl = dwc3_readl(dotg->regs, DWC3_OCTL);
- octl |= DWC3_OTG_OCTL_PERIMODE;
- dwc3_writel(dotg->regs, DWC3_OCTL, octl);
-
- /*
- * TODO: add more OTG registers writes for PERIPHERAL mode here,
- * see figure 12-19 B-device flow in dwc3 Synopsis spec
- */
+ if (ext_xceiv && !ext_xceiv->otg_capability) {
+ /* Set OCTL[6](PeriMode) to 1 (peripheral) */
+ reg = dwc3_readl(dotg->regs, DWC3_OCTL);
+ reg |= DWC3_OTG_OCTL_PERIMODE;
+ dwc3_writel(dotg->regs, DWC3_OCTL, reg);
+ /*
+ * TODO: add more OTG registers writes for PERIPHERAL mode here,
+ * see figure 12-19 B-device flow in dwc3 Synopsis spec
+ */
+ } else {
+ reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+ reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
+ reg |= DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_DEVICE);
+ dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+ }
}
/**
@@ -100,6 +117,7 @@
static int dwc3_otg_start_host(struct usb_otg *otg, int on)
{
struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
+ struct dwc3_ext_xceiv *ext_xceiv = dotg->ext_xceiv;
struct dwc3 *dwc = dotg->dwc;
int ret = 0;
@@ -148,7 +166,8 @@
}
/* re-init OTG EVTEN register as XHCI reset clears it */
- dwc3_otg_reset(dotg);
+ if (ext_xceiv && !ext_xceiv->otg_capability)
+ dwc3_otg_reset(dotg);
} else {
dev_dbg(otg->phy->dev, "%s: turn off host\n", __func__);
@@ -161,9 +180,15 @@
}
dwc3_otg_notify_host_mode(otg, on);
+ /* Do block reset for Host <-> peripheral switching to work */
+ if (ext_xceiv && ext_xceiv->otg_capability &&
+ ext_xceiv->ext_block_reset)
+ ext_xceiv->ext_block_reset();
+
/* re-init core and OTG register as XHCI reset clears it */
dwc3_post_host_reset_core_init(dwc);
- dwc3_otg_reset(dotg);
+ if (ext_xceiv && !ext_xceiv->otg_capability)
+ dwc3_otg_reset(dotg);
}
return 0;
@@ -312,6 +337,7 @@
struct dwc3_ext_xceiv *ext_xceiv = dotg->ext_xceiv;
struct usb_phy *phy = dotg->otg.phy;
int ret = 0;
+ int work = 0;
if (event == DWC3_EVENT_PHY_RESUME) {
if (!pm_runtime_status_suspended(phy->dev)) {
@@ -331,17 +357,28 @@
}
}
} else if (event == DWC3_EVENT_XCEIV_STATE) {
- if (ext_xceiv->id == DWC3_ID_FLOAT)
- set_bit(ID, &dotg->inputs);
- else
- clear_bit(ID, &dotg->inputs);
+ if (ext_xceiv->id == DWC3_ID_FLOAT) {
+ if (!test_and_set_bit(ID, &dotg->inputs)) {
+ dev_dbg(phy->dev, "XCVR: ID set\n");
+ work = 1;
+ }
+ } else {
+ if (test_and_clear_bit(ID, &dotg->inputs)) {
+ dev_dbg(phy->dev, "XCVR: ID clear\n");
+ work = 1;
+ }
+ }
if (ext_xceiv->bsv) {
- dev_dbg(phy->dev, "XCVR: BSV set\n");
- set_bit(B_SESS_VLD, &dotg->inputs);
+ if (!test_and_set_bit(B_SESS_VLD, &dotg->inputs)) {
+ dev_dbg(phy->dev, "XCVR: BSV set\n");
+ work = 1;
+ }
} else {
- dev_dbg(phy->dev, "XCVR: BSV clear\n");
- clear_bit(B_SESS_VLD, &dotg->inputs);
+ if (test_and_clear_bit(B_SESS_VLD, &dotg->inputs)) {
+ dev_dbg(phy->dev, "XCVR: BSV clear\n");
+ work = 1;
+ }
}
if (!init) {
@@ -350,7 +387,8 @@
dev_dbg(phy->dev, "XCVR: BSV init complete\n");
return;
}
- schedule_work(&dotg->sm_work);
+ if (work)
+ schedule_work(&dotg->sm_work);
}
}
@@ -457,6 +495,7 @@
u32 osts, oevt_reg;
int ret = IRQ_NONE;
int handled_irqs = 0;
+ struct usb_phy *phy = dotg->otg.phy;
oevt_reg = dwc3_readl(dotg->regs, DWC3_OEVT);
@@ -472,23 +511,30 @@
* function, switch from A to B or from B to A.
*/
- if (osts & DWC3_OTG_OSTS_CONIDSTS)
- set_bit(ID, &dotg->inputs);
- else
- clear_bit(ID, &dotg->inputs);
+ if (oevt_reg & DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT) {
+ if (osts & DWC3_OTG_OSTS_CONIDSTS) {
+ dev_dbg(phy->dev, "ID set\n");
+ set_bit(ID, &dotg->inputs);
+ } else {
+ dev_dbg(phy->dev, "ID clear\n");
+ clear_bit(ID, &dotg->inputs);
+ }
+ handled_irqs |= DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT;
+ }
- if (osts & DWC3_OTG_OSTS_BSESVALID)
- set_bit(B_SESS_VLD, &dotg->inputs);
- else
- clear_bit(B_SESS_VLD, &dotg->inputs);
+ if (oevt_reg & DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT) {
+ if (osts & DWC3_OTG_OSTS_BSESVALID) {
+ dev_dbg(phy->dev, "BSV set\n");
+ set_bit(B_SESS_VLD, &dotg->inputs);
+ } else {
+ dev_dbg(phy->dev, "BSV clear\n");
+ clear_bit(B_SESS_VLD, &dotg->inputs);
+ }
+ handled_irqs |= DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT;
+ }
schedule_work(&dotg->sm_work);
- handled_irqs |= (oevt_reg & DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT) ?
- DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT : 0;
- handled_irqs |= (oevt_reg & DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT) ?
- DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT : 0;
-
ret = IRQ_HANDLED;
/* Clear the interrupts we handled */
diff --git a/drivers/usb/dwc3/dwc3_otg.h b/drivers/usb/dwc3/dwc3_otg.h
index c93ce5f..5a36a4f 100644
--- a/drivers/usb/dwc3/dwc3_otg.h
+++ b/drivers/usb/dwc3/dwc3_otg.h
@@ -103,6 +103,8 @@
/* to notify OTG about LPM exit event, provided by OTG */
void (*notify_ext_events)(struct usb_otg *otg,
enum dwc3_ext_events ext_event);
+ /* for block reset USB core */
+ void (*ext_block_reset)(void);
};
/* for external transceiver driver */
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 3679191..c2bc3f3 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1546,11 +1546,63 @@
{
struct dwc3_ep *dep;
int ret = 0;
+ u32 reg;
- /* reinitialize physical ep0-1 */
+ /* Enable all but Start and End of Frame IRQs */
+ reg = (DWC3_DEVTEN_EVNTOVERFLOWEN |
+ DWC3_DEVTEN_CMDCMPLTEN |
+ DWC3_DEVTEN_ERRTICERREN |
+ DWC3_DEVTEN_WKUPEVTEN |
+ DWC3_DEVTEN_ULSTCNGEN |
+ DWC3_DEVTEN_CONNECTDONEEN |
+ DWC3_DEVTEN_USBRSTEN |
+ DWC3_DEVTEN_DISCONNEVTEN);
+ dwc3_writel(dwc->regs, DWC3_DEVTEN, reg);
+
+ /* Enable USB2 LPM and automatic phy suspend only on recent versions */
+ if (dwc->revision >= DWC3_REVISION_194A) {
+ reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+ reg |= DWC3_DCFG_LPM_CAP;
+ dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+ reg &= ~(DWC3_DCTL_HIRD_THRES_MASK | DWC3_DCTL_L1_HIBER_EN);
+
+ /* TODO: This should be configurable */
+ reg |= DWC3_DCTL_HIRD_THRES(28);
+
+ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+ }
+
+ reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+ reg &= ~(DWC3_DCFG_SPEED_MASK);
+
+ /**
+ * WORKAROUND: DWC3 revision < 2.20a have an issue
+ * which would cause metastability state on Run/Stop
+ * bit if we try to force the IP to USB2-only mode.
+ *
+ * Because of that, we cannot configure the IP to any
+ * speed other than the SuperSpeed
+ *
+ * Refers to:
+ *
+ * STAR#9000525659: Clock Domain Crossing on DCTL in
+ * USB 2.0 Mode
+ */
+ if (dwc->revision < DWC3_REVISION_220A)
+ reg |= DWC3_DCFG_SUPERSPEED;
+ else
+ reg |= dwc->maximum_speed;
+ dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+
+ dwc->start_config_issued = false;
+
+ /* Start with SuperSpeed Default */
+ dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
dwc->delayed_status = false;
-
+ /* reinitialize physical ep0-1 */
dep = dwc->eps[0];
dep->flags = 0;
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index b773d1a..fe59036 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -75,6 +75,7 @@
#include "rndis.c"
#include "u_bam_data.c"
#include "f_mbim.c"
+#include "f_ecm.c"
#include "f_qc_ecm.c"
#include "f_qc_rndis.c"
#include "u_ether.c"
@@ -1349,6 +1350,50 @@
.attributes = rndis_function_attributes,
};
+static int ecm_function_bind_config(struct android_usb_function *f,
+ struct usb_configuration *c)
+{
+ int ret;
+ struct ecm_function_config *ecm = f->config;
+
+ if (!ecm) {
+ pr_err("%s: ecm_pdata\n", __func__);
+ return -EINVAL;
+ }
+
+ pr_info("%s MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", __func__,
+ ecm->ethaddr[0], ecm->ethaddr[1], ecm->ethaddr[2],
+ ecm->ethaddr[3], ecm->ethaddr[4], ecm->ethaddr[5]);
+
+ ret = gether_setup_name(c->cdev->gadget, ecm->ethaddr, "ecm");
+ if (ret) {
+ pr_err("%s: gether_setup failed\n", __func__);
+ return ret;
+ }
+
+ ret = ecm_bind_config(c, ecm->ethaddr);
+ if (ret) {
+ pr_err("%s: ecm_bind_config failed\n", __func__);
+ gether_cleanup();
+ }
+ return ret;
+}
+
+static void ecm_function_unbind_config(struct android_usb_function *f,
+ struct usb_configuration *c)
+{
+ gether_cleanup();
+}
+
+static struct android_usb_function ecm_function = {
+ .name = "ecm",
+ .init = ecm_function_init,
+ .cleanup = ecm_function_cleanup,
+ .bind_config = ecm_function_bind_config,
+ .unbind_config = ecm_function_unbind_config,
+ .attributes = ecm_function_attributes,
+};
+
struct mass_storage_function_config {
struct fsg_config fsg;
struct fsg_common *common;
@@ -1618,6 +1663,7 @@
&ptp_function,
&rndis_function,
&rndis_qc_function,
+ &ecm_function,
&mass_storage_function,
&accessory_function,
&audio_source_function,
diff --git a/drivers/usb/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
index 85240ef..65b4890 100644
--- a/drivers/usb/gadget/f_mbim.c
+++ b/drivers/usb/gadget/f_mbim.c
@@ -216,7 +216,7 @@
.bcdMbbVersion = cpu_to_le16(0x0100),
.wMaxControlMessage = cpu_to_le16(0x1000),
- .bNumberFilters = 0x10,
+ .bNumberFilters = 0x20,
.bMaxFilterSize = 0x80,
.wMaxSegmentSize = cpu_to_le16(0xfe0),
.bmNetworkCapabilities = 0x20,
diff --git a/drivers/usb/gadget/f_rmnet.c b/drivers/usb/gadget/f_rmnet.c
index 79aac27..32fc79e 100644
--- a/drivers/usb/gadget/f_rmnet.c
+++ b/drivers/usb/gadget/f_rmnet.c
@@ -50,9 +50,6 @@
struct list_head cpkt_resp_q;
atomic_t notify_count;
unsigned long cpkts_len;
-
- /* IPA / RmNet Bridge support*/
- struct usb_bam_connect_ipa_params ipa_params;
};
#define NR_RMNET_PORTS 3
@@ -433,18 +430,9 @@
switch (dxport) {
case USB_GADGET_XPORT_BAM:
case USB_GADGET_XPORT_BAM2BAM:
- ret = gbam_connect(&dev->port, port_num,
- dxport, port_num, NULL);
- if (ret) {
- pr_err("%s: gbam_connect failed: err:%d\n",
- __func__, ret);
- gsmd_ctrl_disconnect(&dev->port, port_num);
- return ret;
- }
- break;
case USB_GADGET_XPORT_BAM2BAM_IPA:
ret = gbam_connect(&dev->port, port_num,
- dxport, port_num, &(dev->ipa_params));
+ dxport, port_num);
if (ret) {
pr_err("%s: gbam_connect failed: err:%d\n",
__func__, ret);
@@ -514,11 +502,8 @@
switch (dxport) {
case USB_GADGET_XPORT_BAM:
case USB_GADGET_XPORT_BAM2BAM:
- gbam_disconnect(&dev->port, port_num, dxport, NULL);
- break;
case USB_GADGET_XPORT_BAM2BAM_IPA:
- gbam_disconnect(&dev->port, port_num, dxport,
- &(dev->ipa_params));
+ gbam_disconnect(&dev->port, port_num, dxport);
break;
case USB_GADGET_XPORT_HSIC:
ghsic_data_disconnect(&dev->port, port_num);
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index 7f3713f..aa93a7d 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -102,7 +102,7 @@
u32 dst_pipe_idx;
u8 connection_idx;
enum transport_type trans;
- struct usb_bam_connect_ipa_params *ipa_params;
+ struct usb_bam_connect_ipa_params ipa_params;
/* stats */
unsigned int pending_with_bam;
@@ -649,7 +649,7 @@
int ret;
if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
- ret = usb_bam_disconnect_ipa(d->connection_idx, d->ipa_params);
+ ret = usb_bam_disconnect_ipa(d->connection_idx, &d->ipa_params);
if (ret)
pr_err("%s: usb_bam_disconnect_ipa failed: err:%d\n",
__func__, ret);
@@ -706,29 +706,29 @@
return;
}
} else if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
- d->ipa_params->client = IPA_CLIENT_USB_CONS;
- d->ipa_params->dir = PEER_PERIPHERAL_TO_USB;
- ret = usb_bam_connect_ipa(d->ipa_params);
+ d->ipa_params.client = IPA_CLIENT_USB_CONS;
+ d->ipa_params.dir = PEER_PERIPHERAL_TO_USB;
+ ret = usb_bam_connect_ipa(&d->ipa_params);
if (ret) {
pr_err("%s: usb_bam_connect_ipa failed: err:%d\n",
__func__, ret);
return;
}
- d->ipa_params->client = IPA_CLIENT_USB_PROD;
- d->ipa_params->dir = USB_TO_PEER_PERIPHERAL;
+ d->ipa_params.client = IPA_CLIENT_USB_PROD;
+ d->ipa_params.dir = USB_TO_PEER_PERIPHERAL;
/* Currently only DMA mode is supported */
- d->ipa_params->ipa_ep_cfg.mode.mode = IPA_DMA;
- d->ipa_params->ipa_ep_cfg.mode.dst =
+ d->ipa_params.ipa_ep_cfg.mode.mode = IPA_DMA;
+ d->ipa_params.ipa_ep_cfg.mode.dst =
IPA_CLIENT_A2_TETHERED_CONS;
- ret = usb_bam_connect_ipa(d->ipa_params);
+ ret = usb_bam_connect_ipa(&d->ipa_params);
if (ret) {
pr_err("%s: usb_bam_connect_ipa failed: err:%d\n",
__func__, ret);
return;
}
- rmnet_bridge_connect(d->ipa_params->prod_clnt_hdl,
- d->ipa_params->cons_clnt_hdl, 0);
+ rmnet_bridge_connect(d->ipa_params.prod_clnt_hdl,
+ d->ipa_params.cons_clnt_hdl, 0);
}
d->rx_req = usb_ep_alloc_request(port->port_usb->out, GFP_KERNEL);
@@ -1037,8 +1037,7 @@
static void gam_debugfs_init(void) { }
#endif
-void gbam_disconnect(struct grmnet *gr, u8 port_num, enum transport_type trans,
- struct usb_bam_connect_ipa_params *ipa_params)
+void gbam_disconnect(struct grmnet *gr, u8 port_num, enum transport_type trans)
{
struct gbam_port *port;
unsigned long flags;
@@ -1096,8 +1095,7 @@
}
int gbam_connect(struct grmnet *gr, u8 port_num,
- enum transport_type trans, u8 connection_idx,
- struct usb_bam_connect_ipa_params *ipa_params)
+ enum transport_type trans, u8 connection_idx)
{
struct gbam_port *port;
struct bam_ch_info *d;
@@ -1166,11 +1164,10 @@
port->gr = gr;
d->connection_idx = connection_idx;
} else if (trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
- d->ipa_params = ipa_params;
port->gr = gr;
- d->ipa_params->src_pipe = &(d->src_pipe_idx);
- d->ipa_params->dst_pipe = &(d->dst_pipe_idx);
- d->ipa_params->idx = connection_idx;
+ d->ipa_params.src_pipe = &(d->src_pipe_idx);
+ d->ipa_params.dst_pipe = &(d->dst_pipe_idx);
+ d->ipa_params.idx = connection_idx;
}
d->trans = trans;
diff --git a/drivers/usb/gadget/u_rmnet.h b/drivers/usb/gadget/u_rmnet.h
index a3d42fa..0f7c4fb 100644
--- a/drivers/usb/gadget/u_rmnet.h
+++ b/drivers/usb/gadget/u_rmnet.h
@@ -48,10 +48,8 @@
int gbam_setup(unsigned int no_bam_port, unsigned int no_bam2bam_port);
int gbam_connect(struct grmnet *gr, u8 port_num,
- enum transport_type trans, u8 connection_idx,
- struct usb_bam_connect_ipa_params *ipa_params);
-void gbam_disconnect(struct grmnet *gr, u8 port_num, enum transport_type trans,
- struct usb_bam_connect_ipa_params *ipa_params);
+ enum transport_type trans, u8 connection_idx);
+void gbam_disconnect(struct grmnet *gr, u8 port_num, enum transport_type trans);
void gbam_suspend(struct grmnet *gr, u8 port_num, enum transport_type trans);
void gbam_resume(struct grmnet *gr, u8 port_num, enum transport_type trans);
int gsmd_ctrl_connect(struct grmnet *gr, int port_num);
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 7d12598..57598c8 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -31,9 +31,11 @@
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
+#include <linux/usb/ulpi.h>
#include <linux/usb/msm_hsusb_hw.h>
#include <linux/usb/msm_hsusb.h>
#include <linux/gpio.h>
+#include <linux/of_gpio.h>
#include <linux/spinlock.h>
#include <linux/irq.h>
#include <linux/kthread.h>
@@ -106,6 +108,7 @@
static bool debug_bus_voting_enabled = true;
static u64 ehci_msm_hsic_dma_mask = DMA_BIT_MASK(32);
+static struct platform_driver ehci_msm_hsic_driver;
static unsigned int enable_payload_log = 1;
module_param(enable_payload_log, uint, S_IRUGO | S_IWUSR);
@@ -611,15 +614,17 @@
{
struct msm_hsic_host_platform_data *pdata = mehci->dev->platform_data;
int ret;
+ void __iomem *reg;
/* HSIC init sequence when HSIC signals (Strobe/Data) are
routed via GPIOs */
if (pdata && pdata->strobe && pdata->data) {
- /* Enable LV_MODE in HSIC_CAL_PAD_CTL register */
- writel_relaxed(HSIC_LV_MODE, HSIC_CAL_PAD_CTL);
-
- mb();
+ if (!pdata->ignore_cal_pad_config) {
+ /* Enable LV_MODE in HSIC_CAL_PAD_CTL register */
+ writel_relaxed(HSIC_LV_MODE, HSIC_CAL_PAD_CTL);
+ mb();
+ }
/*set periodic calibration interval to ~2.048sec in
HSIC_IO_CAL_REG */
@@ -634,9 +639,25 @@
dev_err(mehci->dev, " gpio configuarion failed\n");
return ret;
}
- /* Set LV_MODE=0x1 and DCC=0x2 in HSIC_GPIO PAD_CTL register */
- writel_relaxed(HSIC_GPIO_PAD_VAL, HSIC_STROBE_GPIO_PAD_CTL);
- writel_relaxed(HSIC_GPIO_PAD_VAL, HSIC_DATA_GPIO_PAD_CTL);
+ if (pdata->strobe_pad_offset) {
+ /* Set CORE_CTL_EN in STROBE GPIO PAD_CTL register */
+ reg = MSM_TLMM_BASE + pdata->strobe_pad_offset;
+ writel_relaxed(readl_relaxed(reg) | 0x2000000, reg);
+ } else {
+ /* Set LV_MODE=0x1 and DCC=0x2 in STROBE GPIO PAD_CTL */
+ reg = HSIC_STROBE_GPIO_PAD_CTL;
+ writel_relaxed(HSIC_GPIO_PAD_VAL, reg);
+ }
+
+ if (pdata->data_pad_offset) {
+ /* Set CORE_CTL_EN in HSIC_DATA GPIO PAD_CTL register */
+ reg = MSM_TLMM_BASE + pdata->data_pad_offset;
+ writel_relaxed(readl_relaxed(reg) | 0x2000000, reg);
+ } else {
+ /* Set LV_MODE=0x1 and DCC=0x2 in STROBE GPIO PAD_CTL */
+ reg = HSIC_DATA_GPIO_PAD_CTL;
+ writel_relaxed(HSIC_GPIO_PAD_VAL, reg);
+ }
mb();
@@ -1268,11 +1289,8 @@
/* alt_core_clk is for LINK to be used during PHY RESET
* clock rate appropriately set by target specific clock driver */
mehci->alt_core_clk = clk_get(mehci->dev, "alt_core_clk");
- if (IS_ERR(mehci->alt_core_clk)) {
- dev_err(mehci->dev, "failed to core_clk\n");
- ret = PTR_ERR(mehci->alt_core_clk);
- goto put_core_clk;
- }
+ if (IS_ERR(mehci->alt_core_clk))
+ dev_dbg(mehci->dev, "failed to get alt_core_clk\n");
/* phy_clk is required for HSIC PHY operation
* clock rate appropriately set by target specific clock driver */
@@ -1290,7 +1308,6 @@
ret = PTR_ERR(mehci->cal_clk);
goto put_phy_clk;
}
- clk_set_rate(mehci->cal_clk, 10000000);
/* ahb_clk is required for data transfers */
mehci->ahb_clk = clk_get(mehci->dev, "iface_clk");
@@ -1320,8 +1337,8 @@
put_phy_clk:
clk_put(mehci->phy_clk);
put_alt_core_clk:
- clk_put(mehci->alt_core_clk);
-put_core_clk:
+ if (!IS_ERR(mehci->alt_core_clk))
+ clk_put(mehci->alt_core_clk);
clk_put(mehci->core_clk);
return ret;
@@ -1569,6 +1586,36 @@
debugfs_remove_recursive(ehci_hsic_msm_dbg_root);
}
+struct msm_hsic_host_platform_data *msm_hsic_dt_to_pdata(
+ struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct msm_hsic_host_platform_data *pdata;
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ dev_err(&pdev->dev, "unable to allocate platform data\n");
+ return NULL;
+ }
+ pdata->strobe = of_get_named_gpio(node, "hsic,strobe-gpio", 0);
+ if (pdata->strobe < 0)
+ pdata->strobe = 0;
+
+ pdata->data = of_get_named_gpio(node, "hsic,data-gpio", 0);
+ if (pdata->data < 0)
+ pdata->data = 0;
+
+ pdata->ignore_cal_pad_config = of_property_read_bool(node,
+ "hsic,ignore-cal-pad-config");
+ of_property_read_u32(node, "hsic,strobe-pad-offset",
+ &pdata->strobe_pad_offset);
+ of_property_read_u32(node, "hsic,data-pad-offset",
+ &pdata->data_pad_offset);
+
+ return pdata;
+}
+
+
static int __devinit ehci_hsic_msm_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd;
@@ -1579,6 +1626,14 @@
dev_dbg(&pdev->dev, "ehci_msm-hsic probe\n");
+ if (pdev->dev.of_node) {
+ dev_dbg(&pdev->dev, "device tree enabled\n");
+ pdev->dev.platform_data = msm_hsic_dt_to_pdata(pdev);
+ dev_set_name(&pdev->dev, ehci_msm_hsic_driver.driver.name);
+ }
+ if (!pdev->dev.platform_data)
+ dev_dbg(&pdev->dev, "No platform data given\n");
+
if (!pdev->dev.dma_mask)
pdev->dev.dma_mask = &ehci_msm_hsic_dma_mask;
if (!pdev->dev.coherent_dma_mask)
diff --git a/drivers/usb/misc/diag_bridge.c b/drivers/usb/misc/diag_bridge.c
index 2d95945..ae7e1b6 100644
--- a/drivers/usb/misc/diag_bridge.c
+++ b/drivers/usb/misc/diag_bridge.c
@@ -527,6 +527,8 @@
.driver_info = VALID_INTERFACE_NUM, },
{ USB_DEVICE(0x5c6, 0x904C),
.driver_info = VALID_INTERFACE_NUM, },
+ { USB_DEVICE(0x5c6, 0x9075),
+ .driver_info = VALID_INTERFACE_NUM, },
{} /* terminating entry */
};
diff --git a/drivers/usb/misc/ks_bridge.c b/drivers/usb/misc/ks_bridge.c
index 410b5c4..86c59e7 100644
--- a/drivers/usb/misc/ks_bridge.c
+++ b/drivers/usb/misc/ks_bridge.c
@@ -402,6 +402,8 @@
.driver_info = (unsigned long)&ksb_efs_dev, },
{ USB_DEVICE(0x5c6, 0x904C),
.driver_info = (unsigned long)&ksb_efs_dev, },
+ { USB_DEVICE(0x5c6, 0x9075),
+ .driver_info = (unsigned long)&ksb_efs_dev, },
{} /* terminating entry */
};
diff --git a/drivers/usb/misc/mdm_data_bridge.c b/drivers/usb/misc/mdm_data_bridge.c
index e821fda..655e2f6 100644
--- a/drivers/usb/misc/mdm_data_bridge.c
+++ b/drivers/usb/misc/mdm_data_bridge.c
@@ -1017,6 +1017,7 @@
#define PID9034_IFACE_MASK 0xC
#define PID9048_IFACE_MASK 0x18
#define PID904C_IFACE_MASK 0x28
+#define PID9075_IFACE_MASK 0x28
static const struct usb_device_id bridge_ids[] = {
{ USB_DEVICE(0x5c6, 0x9001),
@@ -1031,6 +1032,9 @@
{ USB_DEVICE(0x5c6, 0x904c),
.driver_info = PID904C_IFACE_MASK,
},
+ { USB_DEVICE(0x5c6, 0x9075),
+ .driver_info = PID9075_IFACE_MASK,
+ },
{ } /* Terminating entry */
};
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index dde9312..3ad05b06 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -3133,8 +3133,16 @@
struct msm_otg *motg = the_msm_otg;
/* Ignore received BSV interrupts, if ID pin is GND */
- if (!test_bit(ID, &motg->inputs))
- return;
+ if (!test_bit(ID, &motg->inputs)) {
+ /*
+ * state machine work waits for initial VBUS
+ * completion in UNDEFINED state. Process
+ * the initial VBUS event in ID_GND state.
+ */
+ if (init)
+ return;
+ goto complete;
+ }
if (online) {
pr_debug("PMIC: BSV set\n");
@@ -3143,7 +3151,7 @@
pr_debug("PMIC: BSV clear\n");
clear_bit(B_SESS_VLD, &motg->inputs);
}
-
+complete:
if (!init) {
init = true;
complete(&pmic_vbus_init);
diff --git a/drivers/usb/serial/csvt.c b/drivers/usb/serial/csvt.c
index 3efdd77..6835ddc 100644
--- a/drivers/usb/serial/csvt.c
+++ b/drivers/usb/serial/csvt.c
@@ -48,6 +48,7 @@
static const struct usb_device_id id_table[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(0x05c6 , 0x904c, 0xff, 0xfe, 0xff)},
+ { USB_DEVICE_AND_INTERFACE_INFO(0x05c6 , 0x9075, 0xff, 0xfe, 0xff)},
{}, /* terminating entry */
};
MODULE_DEVICE_TABLE(usb, id_table);
diff --git a/drivers/video/msm/hdmi_msm.c b/drivers/video/msm/hdmi_msm.c
index 516c92c..bd32b6d 100644
--- a/drivers/video/msm/hdmi_msm.c
+++ b/drivers/video/msm/hdmi_msm.c
@@ -57,8 +57,8 @@
#define HDCP_DDC_CTRL_1 0x0124
#define HDMI_DDC_CTRL 0x020C
-#define HPD_DISCONNECT_POLARITY 0
-#define HPD_CONNECT_POLARITY 1
+#define HPD_EVENT_OFFLINE 0
+#define HPD_EVENT_ONLINE 1
#define SWITCH_SET_HDMI_AUDIO(d, force) \
do {\
@@ -770,6 +770,14 @@
static int hdmi_msm_read_edid(void);
static void hdmi_msm_hpd_off(void);
+static bool hdmi_ready(void)
+{
+ return MSM_HDMI_BASE &&
+ hdmi_msm_state &&
+ hdmi_msm_state->hdmi_app_clk &&
+ hdmi_msm_state->hpd_initialized;
+}
+
static void hdmi_msm_send_event(boolean on)
{
char *envp[2];
@@ -806,12 +814,14 @@
kobject_uevent(external_common_state->uevent_kobj,
KOBJ_OFFLINE);
}
+
+ if (!completion_done(&hdmi_msm_state->hpd_event_processed))
+ complete(&hdmi_msm_state->hpd_event_processed);
}
static void hdmi_msm_hpd_state_work(struct work_struct *work)
{
- if (!hdmi_msm_state || !hdmi_msm_state->hpd_initialized ||
- !MSM_HDMI_BASE) {
+ if (!hdmi_ready()) {
DEV_ERR("hdmi: %s: ignored, probe failed\n", __func__);
return;
}
@@ -1001,8 +1011,7 @@
static uint32 sample_drop_int_occurred;
const uint32 occurrence_limit = 5;
- if (!hdmi_msm_state || !hdmi_msm_state->hpd_initialized ||
- !MSM_HDMI_BASE) {
+ if (!hdmi_ready()) {
DEV_DBG("ISR ignored, probe failed\n");
return IRQ_HANDLED;
}
@@ -4167,19 +4176,28 @@
}
#endif
-static void hdmi_msm_hpd_polarity_setup(bool polarity, bool trigger)
+static void hdmi_msm_hpd_polarity_setup(void)
{
u32 cable_sense;
+ bool polarity = !external_common_state->hpd_state;
+ bool trigger = false;
+
if (polarity)
HDMI_OUTP(0x0254, BIT(2) | BIT(1));
else
HDMI_OUTP(0x0254, BIT(2));
cable_sense = (HDMI_INP(0x0250) & BIT(1)) >> 1;
- DEV_DBG("%s: listen=%s, sense=%s\n", __func__,
+
+ if (cable_sense == polarity)
+ trigger = true;
+
+ DEV_DBG("%s: listen=%s, sense=%s, trigger=%s\n", __func__,
polarity ? "connect" : "disconnect",
- cable_sense ? "connect" : "disconnect");
- if (trigger && (cable_sense == polarity)) {
+ cable_sense ? "connect" : "disconnect",
+ trigger ? "Yes" : "No");
+
+ if (trigger) {
u32 reg_val = HDMI_INP(0x0258);
/* Toggle HPD circuit to trigger HPD sense */
@@ -4280,8 +4298,8 @@
/* Turn on HPD HW circuit */
HDMI_OUTP(0x0258, hpd_ctrl | BIT(28));
- /* Set up HPD_CTRL to sense HPD event */
- hdmi_msm_hpd_polarity_setup(HPD_CONNECT_POLARITY, true);
+ /* Set HPD cable sense polarity */
+ hdmi_msm_hpd_polarity_setup();
}
DEV_DBG("%s: (IRQ, 5V on)\n", __func__);
@@ -4297,7 +4315,8 @@
static int hdmi_msm_power_ctrl(boolean enable)
{
- int rc = 0;
+ int rc = 0;
+ int time = 0;
if (enable) {
/*
@@ -4307,7 +4326,22 @@
if (hdmi_prim_display ||
external_common_state->hpd_feature_on) {
DEV_DBG("%s: Turning HPD ciruitry on\n", __func__);
+
rc = hdmi_msm_hpd_on();
+ if (rc) {
+ DEV_ERR("%s: HPD ON FAILED\n", __func__);
+ return rc;
+ }
+
+ /* Wait for HPD initialization to complete */
+ INIT_COMPLETION(hdmi_msm_state->hpd_event_processed);
+ time = wait_for_completion_interruptible_timeout(
+ &hdmi_msm_state->hpd_event_processed, HZ);
+ if (!time && !external_common_state->hpd_state) {
+ DEV_DBG("%s: cable not detected\n", __func__);
+ queue_work(hdmi_work_queue,
+ &hdmi_msm_state->hpd_state_work);
+ }
}
} else {
DEV_DBG("%s: Turning HPD ciruitry off\n", __func__);
@@ -4320,32 +4354,33 @@
static int hdmi_msm_power_on(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
+ int ret = 0;
bool changed;
- if (!hdmi_msm_state || !hdmi_msm_state->hdmi_app_clk || !MSM_HDMI_BASE)
- return -ENODEV;
-
- if (!hdmi_msm_state->hpd_initialized ||
- !external_common_state->hpd_state) {
- DEV_DBG("%s: HPD not initialized/cable not conn. Returning\n",
- __func__);
- return 0;
+ if (!hdmi_ready()) {
+ DEV_ERR("%s: HDMI/HPD not initialized\n", __func__);
+ return ret;
}
- DEV_INFO("power: ON (%dx%d %d)\n", mfd->var_xres, mfd->var_yres,
- mfd->var_pixclock);
+ if (!external_common_state->hpd_state) {
+ DEV_DBG("%s:HDMI cable not connected\n", __func__);
+ goto error;
+ }
/* Only start transmission with supported resolution */
changed = hdmi_common_get_video_format_from_drv_data(mfd);
if (changed || external_common_state->default_res_supported) {
- hdmi_msm_audio_info_setup(TRUE, 0, 0, 0, FALSE);
mutex_lock(&external_common_state_hpd_mutex);
- hdmi_msm_state->panel_power_on = TRUE;
if (external_common_state->hpd_state &&
hdmi_msm_is_power_on()) {
- DEV_DBG("%s: Turning HDMI on\n", __func__);
mutex_unlock(&external_common_state_hpd_mutex);
+
+ DEV_INFO("HDMI cable connected %s(%dx%d, %d)\n",
+ __func__, mfd->var_xres, mfd->var_yres,
+ mfd->var_pixclock);
+
hdmi_msm_turn_on();
+ hdmi_msm_state->panel_power_on = TRUE;
if (hdmi_msm_state->hdcp_enable) {
/* Kick off HDCP Authentication */
@@ -4370,10 +4405,11 @@
external_common_state->video_resolution);
}
- /* Enable HPD interrupt and listen to disconnect interrupts */
- hdmi_msm_hpd_polarity_setup(HPD_DISCONNECT_POLARITY,
- external_common_state->hpd_state);
- return 0;
+error:
+ /* Set HPD cable sense polarity */
+ hdmi_msm_hpd_polarity_setup();
+
+ return ret;
}
void mhl_connect_api(boolean on)
@@ -4422,12 +4458,16 @@
*/
static int hdmi_msm_power_off(struct platform_device *pdev)
{
- if (!hdmi_msm_state->hdmi_app_clk)
- return -ENODEV;
+ int ret = 0;
+
+ if (!hdmi_ready()) {
+ DEV_ERR("%s: HDMI/HPD not initialized\n", __func__);
+ return ret;
+ }
if (!hdmi_msm_state->panel_power_on) {
- DEV_DBG("%s: panel not on. returning\n", __func__);
- return 0;
+ DEV_DBG("%s: panel not ON\n", __func__);
+ goto error;
}
if (hdmi_msm_state->hdcp_enable) {
@@ -4463,11 +4503,13 @@
hdmi_msm_state->panel_power_on = FALSE;
DEV_INFO("power: OFF (audio off)\n");
- /* Enable HPD interrupt and listen to connect interrupts */
- hdmi_msm_hpd_polarity_setup(HPD_CONNECT_POLARITY,
- !external_common_state->hpd_state);
+ if (!completion_done(&hdmi_msm_state->hpd_event_processed))
+ complete(&hdmi_msm_state->hpd_event_processed);
+error:
+ /* Set HPD cable sense polarity */
+ hdmi_msm_hpd_polarity_setup();
- return 0;
+ return ret;
}
bool mhl_is_enabled(void)
@@ -4730,9 +4772,19 @@
if (on) {
rc = hdmi_msm_hpd_on();
} else {
- external_common_state->hpd_state = 0;
+ if (external_common_state->hpd_state) {
+ external_common_state->hpd_state = 0;
+
+ /* Send offline event to switch OFF HDMI and HAL FD */
+ hdmi_msm_send_event(HPD_EVENT_OFFLINE);
+
+ /* Wait for HDMI and FD to close */
+ INIT_COMPLETION(hdmi_msm_state->hpd_event_processed);
+ wait_for_completion_interruptible_timeout(
+ &hdmi_msm_state->hpd_event_processed, HZ);
+ }
+
hdmi_msm_hpd_off();
- SWITCH_SET_HDMI_AUDIO(0, 0);
/* Set HDMI switch node to 0 on HPD feature disable */
switch_set_state(&external_common_state->sdev, 0);
@@ -4828,6 +4880,7 @@
hdmi_common_init_panel_info(&hdmi_msm_panel_data.panel_info);
init_completion(&hdmi_msm_state->ddc_sw_done);
+ init_completion(&hdmi_msm_state->hpd_event_processed);
INIT_WORK(&hdmi_msm_state->hpd_state_work, hdmi_msm_hpd_state_work);
#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT
diff --git a/drivers/video/msm/hdmi_msm.h b/drivers/video/msm/hdmi_msm.h
index 17cefdd..aded4e0 100644
--- a/drivers/video/msm/hdmi_msm.h
+++ b/drivers/video/msm/hdmi_msm.h
@@ -106,6 +106,7 @@
struct external_common_state_type common;
boolean is_mhl_enabled;
+ struct completion hpd_event_processed;
};
extern struct hdmi_msm_state_type *hdmi_msm_state;
diff --git a/drivers/video/msm/lcdc.c b/drivers/video/msm/lcdc.c
index 2170abe..1bd4302 100644
--- a/drivers/video/msm/lcdc.c
+++ b/drivers/video/msm/lcdc.c
@@ -84,8 +84,6 @@
}
clk_disable_unprepare(mfd->ebi1_clk);
}
-#else
- mdp_bus_scale_update_request(0);
#endif
return ret;
@@ -108,9 +106,7 @@
if (!panel_pixclock_freq)
panel_pixclock_freq = mfd->fbi->var.pixclock;
-#ifdef CONFIG_MSM_BUS_SCALING
- mdp_bus_scale_update_request(2);
-#else
+#ifndef CONFIG_MSM_BUS_SCALING
if (panel_pixclock_freq > 65000000)
/* pm_qos_rate should be in Khz */
pm_qos_rate = panel_pixclock_freq / 1000 ;
diff --git a/drivers/video/msm/lvds.c b/drivers/video/msm/lvds.c
index 13bb9e3..e9bbceb 100644
--- a/drivers/video/msm/lvds.c
+++ b/drivers/video/msm/lvds.c
@@ -254,10 +254,6 @@
if (lvds_pdata && lvds_pdata->lcdc_gpio_config)
ret = lvds_pdata->lcdc_gpio_config(0);
-#ifdef CONFIG_MSM_BUS_SCALING
- mdp_bus_scale_update_request(0);
-#endif
-
return ret;
}
@@ -273,9 +269,6 @@
if (!panel_pixclock_freq)
panel_pixclock_freq = mfd->fbi->var.pixclock;
-#ifdef CONFIG_MSM_BUS_SCALING
- mdp_bus_scale_update_request(2);
-#endif
mfd = platform_get_drvdata(pdev);
if (lvds_clk) {
diff --git a/drivers/video/msm/mddi.c b/drivers/video/msm/mddi.c
index 1154913..b4c1e76 100644
--- a/drivers/video/msm/mddi.c
+++ b/drivers/video/msm/mddi.c
@@ -212,9 +212,7 @@
if (mddi_pdata && mddi_pdata->mddi_power_save)
mddi_pdata->mddi_power_save(0);
-#ifdef CONFIG_MSM_BUS_SCALING
- mdp_bus_scale_update_request(0);
-#else
+#ifndef CONFIG_MSM_BUS_SCALING
if (mfd->ebi1_clk)
clk_disable_unprepare(mfd->ebi1_clk);
#endif
@@ -275,9 +273,7 @@
printk(KERN_ERR "%s: clk_set_rate failed\n",
__func__);
-#ifdef CONFIG_MSM_BUS_SCALING
- mdp_bus_scale_update_request(2);
-#else
+#ifndef CONFIG_MSM_BUS_SCALING
if (mfd->ebi1_clk)
clk_prepare_enable(mfd->ebi1_clk);
#endif
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 372122c..e41017d 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -52,6 +52,7 @@
int mdp_rev;
int mdp_iommu_split_domain;
u32 mdp_max_clk = 200000000;
+u64 mdp_max_bw = 2000000000;
static struct platform_device *mdp_init_pdev;
static struct regulator *footswitch, *dsi_pll_vdda, *dsi_pll_vddio;
@@ -1378,34 +1379,49 @@
#define MAX_VSYNC_GAP 4
#define DEFAULT_FRAME_RATE 60
-static u32 mdp_get_panel_framerate(struct msm_fb_data_type *mfd)
+u32 mdp_get_panel_framerate(struct msm_fb_data_type *mfd)
{
- u32 frame_rate = 0, total_pixel;
+ u32 frame_rate = 0, pixel_rate = 0, total_pixel;
struct msm_panel_info *panel_info = &mfd->panel_info;
+
+ pixel_rate =
+ (panel_info->type == MIPI_CMD_PANEL ||
+ panel_info->type == MIPI_VIDEO_PANEL) ?
+ panel_info->mipi.dsi_pclk_rate :
+ panel_info->clk_rate;
+
+ if (!pixel_rate)
+ pr_warn("%s pixel rate is zero\n", __func__);
+
+ total_pixel =
+ (panel_info->lcdc.h_back_porch +
+ panel_info->lcdc.h_front_porch +
+ panel_info->lcdc.h_pulse_width +
+ panel_info->xres) *
+ (panel_info->lcdc.v_back_porch +
+ panel_info->lcdc.v_front_porch +
+ panel_info->lcdc.v_pulse_width +
+ panel_info->yres);
+
+ if (total_pixel)
+ frame_rate = pixel_rate / total_pixel;
+ else
+ pr_warn("%s total pixels are zero\n", __func__);
+
if (mfd->dest == DISPLAY_LCD) {
if (panel_info->type == MDDI_PANEL && panel_info->mddi.is_type1)
frame_rate = panel_info->lcd.refx100 / (100 * 2);
- else
+ else if (panel_info->type != MIPI_CMD_PANEL)
frame_rate = panel_info->lcd.refx100 / 100;
- } else {
- if (panel_info->type == MIPI_VIDEO_PANEL) {
- frame_rate = panel_info->mipi.frame_rate;
- } else {
- total_pixel = (panel_info->lcdc.h_back_porch +
- panel_info->lcdc.h_front_porch +
- panel_info->lcdc.h_pulse_width +
- panel_info->xres) *
- (panel_info->lcdc.v_back_porch +
- panel_info->lcdc.v_front_porch +
- panel_info->lcdc.v_pulse_width +
- panel_info->yres);
- if (total_pixel)
- frame_rate = panel_info->clk_rate /
- total_pixel;
- }
}
- if (frame_rate == 0)
+
+ if (frame_rate == 0) {
frame_rate = DEFAULT_FRAME_RATE;
+ pr_warn("%s frame rate=%d is default\n", __func__, frame_rate);
+ }
+ pr_debug("%s frame rate=%d total_pixel=%d, pixel_rate=%d\n", __func__,
+ frame_rate, total_pixel, pixel_rate);
+
return frame_rate;
}
@@ -1677,7 +1693,9 @@
mdp_clk_cnt--;
if (mdp_clk_cnt == 0)
mdp_clk_disable_unprepare();
- }
+ } else
+ pr_err("%s: %d: mdp clk off is invalid\n",
+ __func__, __LINE__);
}
pr_debug("%s: on=%d cnt=%d\n", __func__, on, mdp_clk_cnt);
mutex_unlock(&mdp_suspend_mutex);
@@ -2226,7 +2244,9 @@
ret = panel_next_off(pdev);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
mdp_clk_ctrl(0);
-
+#ifdef CONFIG_MSM_BUS_SCALING
+ mdp_bus_scale_update_request(0, 0);
+#endif
if (mdp_rev >= MDP_REV_41 && mfd->panel.type == MIPI_CMD_PANEL)
mdp_dsi_cmd_overlay_suspend(mfd);
pr_debug("%s:-\n", __func__);
@@ -2334,20 +2354,77 @@
}
#ifdef CONFIG_MSM_BUS_SCALING
+
+#ifndef MDP_BUS_VECTOR_ENTRY
+#define MDP_BUS_VECTOR_ENTRY(ab_val, ib_val) \
+ { \
+ .src = MSM_BUS_MASTER_MDP_PORT0, \
+ .dst = MSM_BUS_SLAVE_EBI_CH0, \
+ .ab = (ab_val), \
+ .ib = (ib_val), \
+ }
+#endif
+/*
+ * Entry 0 hold 0 request
+ * Entry 1 and 2 do ping pong request
+ */
+static struct msm_bus_vectors mdp_bus_vectors[] = {
+ MDP_BUS_VECTOR_ENTRY(0, 0),
+ MDP_BUS_VECTOR_ENTRY( 128000000, 160000000),
+ MDP_BUS_VECTOR_ENTRY( 128000000, 160000000),
+};
+
+static struct msm_bus_paths mdp_bus_usecases[ARRAY_SIZE(mdp_bus_vectors)];
+static struct msm_bus_scale_pdata mdp_bus_scale_table = {
+ .usecase = mdp_bus_usecases,
+ .num_usecases = ARRAY_SIZE(mdp_bus_usecases),
+ .name = "mdp",
+};
static uint32_t mdp_bus_scale_handle;
-int mdp_bus_scale_update_request(uint32_t index)
+static int mdp_bus_scale_register(void)
{
- if (!mdp_pdata && (!mdp_pdata->mdp_bus_scale_table
- || index > (mdp_pdata->mdp_bus_scale_table->num_usecases - 1))) {
- printk(KERN_ERR "%s invalid table or index\n", __func__);
- return -EINVAL;
+ struct msm_bus_scale_pdata *bus_pdata = &mdp_bus_scale_table;
+ int i;
+ for (i = 0; i < bus_pdata->num_usecases; i++) {
+ mdp_bus_usecases[i].num_paths = 1;
+ mdp_bus_usecases[i].vectors = &mdp_bus_vectors[i];
}
+ mdp_bus_scale_handle = msm_bus_scale_register_client(bus_pdata);
+ if (!mdp_bus_scale_handle) {
+ pr_err("%s: not able to get bus scale!\n", __func__);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+int mdp_bus_scale_update_request(u64 ab, u64 ib)
+{
+ static int bus_index = 1;
+
if (mdp_bus_scale_handle < 1) {
- pr_debug("%s invalid bus handle\n", __func__);
+ pr_err("%s invalid bus handle\n", __func__);
return -EINVAL;
}
- return msm_bus_scale_client_update_request(mdp_bus_scale_handle,
- index);
+
+ if (!ab)
+ return msm_bus_scale_client_update_request
+ (mdp_bus_scale_handle, 0);
+
+ /* ping pong bus_index between table entry 1 and 2 */
+ bus_index++;
+ bus_index = (bus_index > 2) ? 1 : bus_index;
+
+ mdp_bus_usecases[bus_index].vectors->ab = min(ab, mdp_max_bw);
+ ib = max(ib, ab);
+ mdp_bus_usecases[bus_index].vectors->ib = min(ib, mdp_max_bw);
+
+ pr_debug("%s: handle=%d index=%d ab=%llu ib=%llu\n", __func__,
+ (u32)mdp_bus_scale_handle, bus_index,
+ mdp_bus_usecases[bus_index].vectors->ab,
+ mdp_bus_usecases[bus_index].vectors->ib);
+
+ return msm_bus_scale_client_update_request
+ (mdp_bus_scale_handle, bus_index);
}
#endif
DEFINE_MUTEX(mdp_clk_lock);
@@ -2955,22 +3032,13 @@
mdp_clk_ctrl(0);
#ifdef CONFIG_MSM_BUS_SCALING
- if (!mdp_bus_scale_handle && mdp_pdata &&
- mdp_pdata->mdp_bus_scale_table) {
- mdp_bus_scale_handle =
- msm_bus_scale_register_client(
- mdp_pdata->mdp_bus_scale_table);
- if (!mdp_bus_scale_handle) {
- printk(KERN_ERR "%s not able to get bus scale\n",
- __func__);
- return -ENOMEM;
- }
- }
+ if (mdp_bus_scale_register())
+ return -ENOMEM;
/* req bus bandwidth immediately */
- if (!(mfd->cont_splash_done) && (mfd->panel_info.pdest == DISPLAY_1))
- mdp_bus_scale_update_request(5);
-
+ if (!(mfd->cont_splash_done))
+ mdp_bus_scale_update_request
+ (MDP_BUS_SCALE_INIT, MDP_BUS_SCALE_INIT);
#endif
/* set driver data */
@@ -3014,8 +3082,7 @@
mdp_probe_err:
platform_device_put(msm_fb_dev);
#ifdef CONFIG_MSM_BUS_SCALING
- if (mdp_pdata && mdp_pdata->mdp_bus_scale_table &&
- mdp_bus_scale_handle > 0)
+ if (mdp_bus_scale_handle > 0)
msm_bus_scale_unregister_client(mdp_bus_scale_handle);
#endif
return rc;
@@ -3146,8 +3213,7 @@
iounmap(msm_mdp_base);
pm_runtime_disable(&pdev->dev);
#ifdef CONFIG_MSM_BUS_SCALING
- if (mdp_pdata && mdp_pdata->mdp_bus_scale_table &&
- mdp_bus_scale_handle > 0)
+ if (mdp_bus_scale_handle > 0)
msm_bus_scale_unregister_client(mdp_bus_scale_handle);
#endif
return 0;
diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h
index 0bc2532..eab4dbe 100644
--- a/drivers/video/msm/mdp.h
+++ b/drivers/video/msm/mdp.h
@@ -849,12 +849,12 @@
int mdp_clk_round_rate(u32 rate);
unsigned long mdp_get_core_clk(void);
-unsigned long mdp_perf_level2clk_rate(uint32 perf_level);
#ifdef CONFIG_MSM_BUS_SCALING
-int mdp_bus_scale_update_request(uint32_t index);
+int mdp_bus_scale_update_request(u64 ab, u64 ib);
#else
-static inline int mdp_bus_scale_update_request(uint32_t index)
+static inline int mdp_bus_scale_update_request(u64 ab,
+ u64 ib)
{
return 0;
}
@@ -932,6 +932,8 @@
unsigned long srcp1_addr, unsigned long srcp1_size);
void mdp_update_pm(struct msm_fb_data_type *mfd, ktime_t pre_vsync);
+u32 mdp_get_panel_framerate(struct msm_fb_data_type *mfd);
+
#ifdef CONFIG_FB_MSM_DTV
void mdp_vid_quant_set(void);
#else
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index 67ef8bf..02cdd71 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -31,6 +31,12 @@
extern u32 dbg_force_ov0_blt;
extern u32 dbg_force_ov1_blt;
+extern u64 mdp_max_bw;
+#define MDP4_BW_AB_FACTOR (115) /* 1.15 */
+#define MDP4_BW_IB_FACTOR (125) /* 1.25 */
+#define MDP_BUS_SCALE_AB_STEP (0x4000000)
+#define MDP_BUS_SCALE_INIT (0x10000000)
+
#define MDP4_OVERLAYPROC0_BASE 0x10000
#define MDP4_OVERLAYPROC1_BASE 0x18000
#define MDP4_OVERLAYPROC2_BASE 0x88000
@@ -46,13 +52,6 @@
#define CS_CONTROLLER_0 0x0707ffff
#define CS_CONTROLLER_1 0x03073f3f
-enum {
- OVERLAY_PERF_LEVEL1 = 1,
- OVERLAY_PERF_LEVEL2,
- OVERLAY_PERF_LEVEL3,
- OVERLAY_PERF_LEVEL4
-};
-
typedef int (*cmd_fxn_t)(struct platform_device *pdev);
enum { /* display */
@@ -234,6 +233,12 @@
#define MDP4_MAX_PLANE 4
#define VSYNC_PERIOD 16
+#ifdef BLT_RGB565
+#define BLT_BPP 2
+#else
+#define BLT_BPP 3
+#endif
+
struct mdp4_hsic_regs {
int32_t params[NUM_HSIC_PARAM];
int32_t conv_matrix[3][3];
@@ -358,7 +363,8 @@
uint32 blt_dmap_koff;
uint32 blt_dmap_done;
uint32 req_clk;
- uint32 req_bw;
+ uint64 bw_ab_quota;
+ uint64 bw_ib_quota;
uint32 luma_align_size;
struct mdp_overlay_pp_params pp_cfg;
struct mdp_overlay req_data;
@@ -968,7 +974,9 @@
unsigned long srcp0_addr, unsigned long srcp1_addr,
unsigned long srcp2_addr);
int mdp4_overlay_mdp_pipe_req(struct mdp4_overlay_pipe *pipe,
- struct msm_fb_data_type *mfd);
+ struct msm_fb_data_type *mfd);
+int mdp4_calc_blt_mdp_bw(struct msm_fb_data_type *mfd,
+ struct mdp4_overlay_pipe *pipe);
int mdp4_overlay_mdp_perf_req(struct msm_fb_data_type *mfd,
struct mdp4_overlay_pipe *plist);
void mdp4_overlay_mdp_perf_upd(struct msm_fb_data_type *mfd, int flag);
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index f4332dd..43fcb7c 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -107,17 +107,15 @@
struct mdp4_overlay_perf {
u32 mdp_clk_rate;
- u32 use_ov0_blt;
- u32 use_ov1_blt;
- u32 mdp_bw;
+ u32 use_ov_blt[MDP4_MIXER_MAX];
+ u64 mdp_ov_ab_bw[MDP4_MIXER_MAX];
+ u64 mdp_ov_ib_bw[MDP4_MIXER_MAX];
+ u32 mdp_ab_bw;
+ u32 mdp_ib_bw;
};
-struct mdp4_overlay_perf perf_request = {
- .mdp_bw = OVERLAY_PERF_LEVEL4,
-};
-struct mdp4_overlay_perf perf_current = {
- .mdp_bw = OVERLAY_PERF_LEVEL4,
-};
+struct mdp4_overlay_perf perf_request;
+struct mdp4_overlay_perf perf_current;
static struct ion_client *display_iclient;
@@ -2515,12 +2513,10 @@
if (!pipe) {
pr_err("%s: pipe is null!\n", __func__);
- pipe->req_bw = OVERLAY_PERF_LEVEL4;
return ret;
}
if (!mfd) {
pr_err("%s: mfd is null!\n", __func__);
- pipe->req_bw = OVERLAY_PERF_LEVEL4;
return ret;
}
@@ -2686,18 +2682,13 @@
return 0;
}
-#define OVERLAY_VGA_SIZE 0x04B000
-#define OVERLAY_720P_TILE_SIZE 0x0E6000
-#define OVERLAY_WSVGA_SIZE 0x98000 /* 1024x608, align 600 to 32bit */
-
-#define OVERLAY_BUS_SCALE_TABLE_BASE 6
-
-
static int mdp4_calc_pipe_mdp_bw(struct msm_fb_data_type *mfd,
- struct mdp4_overlay_pipe *pipe)
+ struct mdp4_overlay_pipe *pipe)
{
- u32 res;
+ u32 fps;
int ret = -EINVAL;
+ u32 quota;
+ u32 shift = 16;
if (!pipe) {
pr_err("%s: pipe is null!\n", __func__);
@@ -2708,28 +2699,79 @@
return ret;
}
- if (pipe->flags & MDP_DEINTERLACE) {
- pr_info("%s deinterlace requires max mdp bw.\n",
- __func__);
- pipe->req_bw = OVERLAY_PERF_LEVEL1;
- return 0;
+ fps = mdp_get_panel_framerate(mfd);
+ quota = pipe->src_w * pipe->src_h * fps * pipe->bpp;
+
+ quota >>= shift;
+ /* factor 1.15 for ab */
+ pipe->bw_ab_quota = quota * MDP4_BW_AB_FACTOR / 100;
+ /* factor 1.25 for ib */
+ pipe->bw_ib_quota = quota * MDP4_BW_IB_FACTOR / 100;
+ /* down scaling factor for ib */
+ if ((!pipe->dst_h) && (!pipe->src_h) &&
+ (pipe->src_h > pipe->dst_h)) {
+ u64 ib = quota;
+ ib *= pipe->src_h;
+ ib /= pipe->dst_h;
+ pipe->bw_ib_quota = max(ib, pipe->bw_ib_quota);
+ pr_debug("%s: src_h=%d dst_h=%d mdp ib %llu, ib_quota=%llu\n",
+ __func__, pipe->src_h, pipe->dst_h,
+ ib<<shift, pipe->bw_ib_quota<<shift);
}
- if (pipe->pipe_type == OVERLAY_TYPE_BF) {
- pipe->req_bw = OVERLAY_PERF_LEVEL4;
- return 0;
+ pipe->bw_ab_quota <<= shift;
+ pipe->bw_ib_quota <<= shift;
+
+ pr_debug("%s: pipe ndx=%d src(h,w)(%d, %d) fps=%d bpp=%d\n",
+ __func__, pipe->pipe_ndx, pipe->src_h, pipe->src_w,
+ fps, pipe->bpp);
+ pr_debug("%s: ab_quota=%llu ib_quota=%llu\n", __func__,
+ pipe->bw_ab_quota, pipe->bw_ib_quota);
+
+ return 0;
+}
+
+int mdp4_calc_blt_mdp_bw(struct msm_fb_data_type *mfd,
+ struct mdp4_overlay_pipe *pipe)
+{
+ struct mdp4_overlay_perf *perf_req = &perf_request;
+ u32 fps;
+ int bpp;
+ int ret = -EINVAL;
+ u32 quota;
+ u32 shift = 16;
+ if (!pipe) {
+ pr_err("%s: pipe is null!\n", __func__);
+ return ret;
+ }
+ if (!mfd) {
+ pr_err("%s: mfd is null!\n", __func__);
+ return ret;
}
- res = pipe->src_w * pipe->src_h;
+ bpp = BLT_BPP;
+ fps = mdp_get_panel_framerate(mfd);
- if (res <= OVERLAY_WSVGA_SIZE)
- pipe->req_bw = OVERLAY_PERF_LEVEL4;
- else if (res <= OVERLAY_VGA_SIZE)
- pipe->req_bw = OVERLAY_PERF_LEVEL3;
- else if (res <= OVERLAY_720P_TILE_SIZE)
- pipe->req_bw = OVERLAY_PERF_LEVEL2;
- else
- pipe->req_bw = OVERLAY_PERF_LEVEL1;
+ /* read and write bw*/
+ quota = pipe->dst_w * pipe->dst_h * fps * bpp * 2;
+ quota >>= shift;
+
+ perf_req->mdp_ov_ab_bw[pipe->mixer_num] =
+ quota * MDP4_BW_AB_FACTOR / 100;
+
+ perf_req->mdp_ov_ib_bw[pipe->mixer_num] =
+ quota * MDP4_BW_IB_FACTOR / 100;
+
+ perf_req->mdp_ov_ab_bw[pipe->mixer_num] <<= shift;
+ perf_req->mdp_ov_ib_bw[pipe->mixer_num] <<= shift;
+
+ pr_debug("%s: pipe ndx=%d dst(h,w)(%d, %d) fps=%d bpp=%d\n",
+ __func__, pipe->pipe_ndx, pipe->dst_h, pipe->dst_w,
+ fps, bpp);
+ pr_debug("%s: overlay=%d ab_bw=%llu ib_bw=%llu\n", __func__,
+ pipe->mixer_num,
+ perf_req->mdp_ov_ab_bw[pipe->mixer_num],
+ perf_req->mdp_ov_ib_bw[pipe->mixer_num]);
return 0;
}
@@ -2738,12 +2780,12 @@
struct mdp4_overlay_pipe *plist)
{
u32 worst_mdp_clk = 0;
- u32 worst_mdp_bw = OVERLAY_PERF_LEVEL4;
int i;
struct mdp4_overlay_perf *perf_req = &perf_request;
struct mdp4_overlay_pipe *pipe = plist;
u32 cnt = 0;
int ret = -EINVAL;
+ u64 ab_quota_total = 0, ib_quota_total = 0;
if (!mfd) {
pr_err("%s: mfd is null!\n", __func__);
@@ -2755,8 +2797,8 @@
return ret;
}
- perf_req->use_ov0_blt = 0;
- perf_req->use_ov1_blt = 0;
+ for (i = 0; i < MDP4_MIXER_MAX; i++)
+ perf_req->use_ov_blt[i] = 0;
for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) {
@@ -2768,25 +2810,17 @@
cnt++;
if (worst_mdp_clk < pipe->req_clk)
worst_mdp_clk = pipe->req_clk;
- if (pipe->req_clk > mdp_max_clk) {
- if (pipe->mixer_num == MDP4_MIXER0)
- perf_req->use_ov0_blt = 1;
- if (pipe->mixer_num == MDP4_MIXER1)
- perf_req->use_ov1_blt = 1;
- }
- if (!pipe->req_bw) {
- pr_err("%s mdp pipe bw request should not be zero!\n",
- __func__);
- pr_debug("%s %d pid %d num %d idx %d mix %d bw %d\n",
- __func__, __LINE__, current->pid,
- pipe->pipe_num, pipe->pipe_ndx,
- pipe->mixer_num, pipe->req_bw);
- pipe->req_bw = OVERLAY_PERF_LEVEL4;
- }
+ if (pipe->req_clk > mdp_max_clk)
+ perf_req->use_ov_blt[pipe->mixer_num] = 1;
- if (pipe->req_bw < worst_mdp_bw)
- worst_mdp_bw = pipe->req_bw;
+ if (pipe->mixer_num == MDP4_MIXER2)
+ perf_req->use_ov_blt[MDP4_MIXER2] = 1;
+
+ if (pipe->pipe_type != OVERLAY_TYPE_BF) {
+ ab_quota_total += pipe->bw_ab_quota;
+ ib_quota_total += pipe->bw_ib_quota;
+ }
if (mfd->mdp_rev == MDP_REV_41) {
/*
@@ -2795,32 +2829,45 @@
*/
if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) {
if (pipe->dst_x != 0)
- perf_req->use_ov0_blt = 1;
+ perf_req->use_ov_blt[MDP4_MIXER0] = 1;
}
if ((mfd->panel_info.xres > 1280) &&
(mfd->panel_info.type != DTV_PANEL)) {
- perf_req->use_ov0_blt = 1;
+ perf_req->use_ov_blt[MDP4_MIXER0] = 1;
}
}
}
- perf_req->mdp_clk_rate = worst_mdp_clk;
- if (perf_req->mdp_clk_rate > mdp_max_clk)
- perf_req->mdp_clk_rate = mdp_max_clk;
-
+ perf_req->mdp_clk_rate = min(worst_mdp_clk, mdp_max_clk);
perf_req->mdp_clk_rate = mdp_clk_round_rate(perf_req->mdp_clk_rate);
- perf_req->mdp_bw = worst_mdp_bw;
+ for (i = 0; i < MDP4_MIXER_MAX; i++) {
+ if (perf_req->use_ov_blt[i]) {
+ ab_quota_total += perf_req->mdp_ov_ab_bw[i];
+ ib_quota_total += perf_req->mdp_ov_ib_bw[i];
+ }
+ }
- if (cnt >= 3)
- perf_req->mdp_bw = OVERLAY_PERF_LEVEL1;
+ perf_req->mdp_ab_bw = roundup(ab_quota_total, MDP_BUS_SCALE_AB_STEP);
+ perf_req->mdp_ib_bw = roundup(ib_quota_total, MDP_BUS_SCALE_AB_STEP);
- pr_debug("%s %d pid %d cnt %d clk %d ov0_blt %d, ov1_blt %d bw %d\n",
+ pr_debug("%s %d: ab_quota_total=(%llu, %d) ib_quota_total=(%llu, %d)\n",
+ __func__, __LINE__,
+ ab_quota_total, perf_req->mdp_ab_bw,
+ ib_quota_total, perf_req->mdp_ib_bw);
+
+ if (ab_quota_total > mdp_max_bw)
+ pr_warn("%s: req ab bw=%llu is larger than max bw=%llu",
+ __func__, ab_quota_total, mdp_max_bw);
+ if (ib_quota_total > mdp_max_bw)
+ pr_warn("%s: req ib bw=%llu is larger than max bw=%llu",
+ __func__, ib_quota_total, mdp_max_bw);
+
+ pr_debug("%s %d: pid %d cnt %d clk %d ov0_blt %d, ov1_blt %d\n",
__func__, __LINE__, current->pid, cnt,
perf_req->mdp_clk_rate,
- perf_req->use_ov0_blt,
- perf_req->use_ov1_blt,
- perf_req->mdp_bw);
+ perf_req->use_ov_blt[0],
+ perf_req->use_ov_blt[1]);
return 0;
}
@@ -2856,7 +2903,7 @@
flag);
if (!mdp4_extn_disp)
- perf_cur->use_ov1_blt = 0;
+ perf_cur->use_ov_blt[1] = 0;
if (flag) {
if (perf_req->mdp_clk_rate > perf_cur->mdp_clk_rate) {
@@ -2869,19 +2916,26 @@
perf_cur->mdp_clk_rate =
perf_req->mdp_clk_rate;
}
- if (perf_req->mdp_bw < perf_cur->mdp_bw) {
+ if ((perf_req->mdp_ab_bw > perf_cur->mdp_ab_bw) ||
+ (perf_req->mdp_ib_bw > perf_cur->mdp_ib_bw)) {
mdp_bus_scale_update_request
- (OVERLAY_BUS_SCALE_TABLE_BASE -
- perf_req->mdp_bw);
- pr_info("%s mdp bw is changed [%d] from %d to %d\n",
+ (perf_req->mdp_ab_bw, perf_req->mdp_ib_bw);
+ pr_debug("%s mdp ab_bw is changed [%d] from %d to %d\n",
__func__,
flag,
- perf_cur->mdp_bw,
- perf_req->mdp_bw);
- perf_cur->mdp_bw = perf_req->mdp_bw;
+ perf_cur->mdp_ab_bw,
+ perf_req->mdp_ab_bw);
+ pr_debug("%s mdp ib_bw is changed [%d] from %d to %d\n",
+ __func__,
+ flag,
+ perf_cur->mdp_ib_bw,
+ perf_req->mdp_ib_bw);
+ perf_cur->mdp_ab_bw = perf_req->mdp_ab_bw;
+ perf_cur->mdp_ib_bw = perf_req->mdp_ib_bw;
}
+
if ((mfd->panel_info.pdest == DISPLAY_1 &&
- perf_req->use_ov0_blt && !perf_cur->use_ov0_blt) ||
+ perf_req->use_ov_blt[0] && !perf_cur->use_ov_blt[0]) ||
dbg_force_ov0_blt) {
if (mfd->panel_info.type == LCDC_PANEL ||
mfd->panel_info.type == LVDS_PANEL)
@@ -2895,20 +2949,20 @@
pr_debug("%s mixer0 start blt [%d] from %d to %d.\n",
__func__,
flag,
- perf_cur->use_ov0_blt,
- perf_req->use_ov0_blt);
- perf_cur->use_ov0_blt = perf_req->use_ov0_blt;
+ perf_cur->use_ov_blt[0],
+ perf_req->use_ov_blt[0]);
+ perf_cur->use_ov_blt[0] = perf_req->use_ov_blt[0];
}
if ((mfd->panel_info.pdest == DISPLAY_2 &&
- perf_req->use_ov1_blt && !perf_cur->use_ov1_blt) ||
+ perf_req->use_ov_blt[1] && !perf_cur->use_ov_blt[1]) ||
dbg_force_ov1_blt) {
mdp4_dtv_overlay_blt_start(mfd);
pr_debug("%s mixer1 start blt [%d] from %d to %d.\n",
__func__,
flag,
- perf_cur->use_ov1_blt,
- perf_req->use_ov1_blt);
- perf_cur->use_ov1_blt = perf_req->use_ov1_blt;
+ perf_cur->use_ov_blt[1],
+ perf_req->use_ov_blt[1]);
+ perf_cur->use_ov_blt[1] = perf_req->use_ov_blt[1];
}
} else {
if (perf_req->mdp_clk_rate < perf_cur->mdp_clk_rate) {
@@ -2921,19 +2975,25 @@
perf_cur->mdp_clk_rate =
perf_req->mdp_clk_rate;
}
- if (perf_req->mdp_bw > perf_cur->mdp_bw) {
- pr_info("%s mdp bw is changed [%d] from %d to %d\n",
+ if (perf_req->mdp_ab_bw < perf_cur->mdp_ab_bw ||
+ perf_req->mdp_ib_bw < perf_cur->mdp_ib_bw) {
+ mdp_bus_scale_update_request
+ (perf_req->mdp_ab_bw, perf_req->mdp_ib_bw);
+ pr_debug("%s mdp ab bw is changed [%d] from %d to %d\n",
__func__,
flag,
- perf_cur->mdp_bw,
- perf_req->mdp_bw);
- mdp_bus_scale_update_request
- (OVERLAY_BUS_SCALE_TABLE_BASE -
- perf_req->mdp_bw);
- perf_cur->mdp_bw = perf_req->mdp_bw;
+ perf_cur->mdp_ab_bw,
+ perf_req->mdp_ab_bw);
+ pr_debug("%s mdp ib bw is changed [%d] from %d to %d\n",
+ __func__,
+ flag,
+ perf_cur->mdp_ib_bw,
+ perf_req->mdp_ib_bw);
+ perf_cur->mdp_ab_bw = perf_req->mdp_ab_bw;
+ perf_cur->mdp_ib_bw = perf_req->mdp_ib_bw;
}
if ((mfd->panel_info.pdest == DISPLAY_1 &&
- !perf_req->use_ov0_blt && perf_cur->use_ov0_blt) ||
+ !perf_req->use_ov_blt[0] && perf_cur->use_ov_blt[0]) ||
dbg_force_ov0_blt) {
if (mfd->panel_info.type == LCDC_PANEL ||
mfd->panel_info.type == LVDS_PANEL)
@@ -2947,20 +3007,20 @@
pr_debug("%s mixer0 stop blt [%d] from %d to %d.\n",
__func__,
flag,
- perf_cur->use_ov0_blt,
- perf_req->use_ov0_blt);
- perf_cur->use_ov0_blt = perf_req->use_ov0_blt;
+ perf_cur->use_ov_blt[0],
+ perf_req->use_ov_blt[0]);
+ perf_cur->use_ov_blt[0] = perf_req->use_ov_blt[0];
}
if ((mfd->panel_info.pdest == DISPLAY_2 &&
- !perf_req->use_ov1_blt && perf_cur->use_ov1_blt) ||
+ !perf_req->use_ov_blt[1] && perf_cur->use_ov_blt[1]) ||
dbg_force_ov1_blt) {
mdp4_dtv_overlay_blt_stop(mfd);
pr_debug("%s mixer1 stop blt [%d] from %d to %d.\n",
__func__,
flag,
- perf_cur->use_ov1_blt,
- perf_req->use_ov1_blt);
- perf_cur->use_ov1_blt = perf_req->use_ov1_blt;
+ perf_cur->use_ov_blt[1],
+ perf_req->use_ov_blt[1]);
+ perf_cur->use_ov_blt[1] = perf_req->use_ov_blt[1];
}
}
return;
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index 450f1de..a4d2b77 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -568,6 +568,7 @@
pipe->dst_w = fbi->var.xres;
mdp4_overlay_mdp_pipe_req(pipe, mfd);
+ mdp4_calc_blt_mdp_bw(mfd, pipe);
atomic_set(&vctrl->suspend, 0);
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index 7de2e2a..85fb305 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -869,6 +869,7 @@
pipe->srcp0_ystride = fbi->fix.line_length;
mdp4_overlay_mdp_pipe_req(pipe, mfd);
+ mdp4_calc_blt_mdp_bw(mfd, pipe);
ret = mdp4_overlay_format2pipe(pipe);
if (ret < 0)
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index a7058ce..4a46d72 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -546,6 +546,7 @@
pipe->bpp = bpp;
mdp4_overlay_mdp_pipe_req(pipe, mfd);
+ mdp4_calc_blt_mdp_bw(mfd, pipe);
atomic_set(&vctrl->suspend, 0);
diff --git a/drivers/video/msm/mdp4_overlay_writeback.c b/drivers/video/msm/mdp4_overlay_writeback.c
index aa50d94..bd20e82 100644
--- a/drivers/video/msm/mdp4_overlay_writeback.c
+++ b/drivers/video/msm/mdp4_overlay_writeback.c
@@ -61,6 +61,7 @@
struct msm_fb_data_type *mfd;
struct mdp4_overlay_pipe *base_pipe;
struct vsync_update vlist[2];
+ struct work_struct clk_work;
} vsync_ctrl_db[MAX_CONTROLLER];
static void vsync_irq_enable(int intr, int term)
@@ -260,6 +261,7 @@
pipe->dst_x = 0;
mdp4_overlay_mdp_pipe_req(pipe, mfd);
+ mdp4_calc_blt_mdp_bw(mfd, pipe);
if (mfd->display_iova)
pipe->srcp0_addr = mfd->display_iova + buf_offset;
@@ -375,6 +377,8 @@
}
}
+ mdp_clk_ctrl(1);
+
mdp4_mixer_stage_commit(mixer);
pipe = vctrl->base_pipe;
@@ -399,6 +403,13 @@
return cnt;
}
+static void clk_ctrl_work(struct work_struct *work)
+{
+ struct vsycn_ctrl *vctrl =
+ container_of(work, typeof(*vctrl), clk_work);
+ mdp_clk_ctrl(0);
+}
+
void mdp4_wfd_init(int cndx)
{
struct vsycn_ctrl *vctrl;
@@ -417,6 +428,7 @@
mutex_init(&vctrl->update_lock);
init_completion(&vctrl->ov_comp);
spin_lock_init(&vctrl->spin_lock);
+ INIT_WORK(&vctrl->clk_work, clk_ctrl_work);
}
static void mdp4_wfd_wait4ov(int cndx)
@@ -450,7 +462,7 @@
vsync_irq_disable(INTR_OVERLAY2_DONE, MDP_OVERLAY2_TERM);
vctrl->ov_done++;
complete(&vctrl->ov_comp);
-
+ schedule_work(&vctrl->clk_work);
pr_debug("%s ovdone interrupt\n", __func__);
spin_unlock(&vctrl->spin_lock);
}
@@ -475,16 +487,11 @@
mdp4_overlay_mdp_perf_upd(mfd, 1);
- mdp_clk_ctrl(1);
-
mdp4_wfd_pipe_commit(mfd, 0, 1);
mdp4_overlay_mdp_perf_upd(mfd, 0);
- mdp_clk_ctrl(0);
-
mutex_unlock(&mfd->dma->ov_mutex);
-
}
static int mdp4_overlay_writeback_register_buffer(
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index b6c2634..01ec10e 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -392,7 +392,8 @@
/* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- mdp_bus_scale_update_request(5);
+ mdp_bus_scale_update_request
+ (MDP_BUS_SCALE_INIT, MDP_BUS_SCALE_INIT);
#ifdef MDP4_ERROR
/*
diff --git a/drivers/video/msm/mdss/Makefile b/drivers/video/msm/mdss/Makefile
index a0d707e..4deaa8c 100644
--- a/drivers/video/msm/mdss/Makefile
+++ b/drivers/video/msm/mdss/Makefile
@@ -20,5 +20,6 @@
obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_util.o
obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_edid.o
obj-$(CONFIG_FB_MSM_MDSS_HDMI_MHL_8334) += mhl_sii8334.o
+obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_hdcp.o
obj-$(CONFIG_FB_MSM_MDSS_WRITEBACK) += mdss_wb.o
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 581ec17..2e8a654 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -847,11 +847,11 @@
var->xres_virtual = panel_info->xres;
var->yres_virtual = panel_info->yres * mfd->fb_page;
var->bits_per_pixel = bpp * 8; /* FrameBuffer color depth */
- var->upper_margin = panel_info->lcdc.v_front_porch;
- var->lower_margin = panel_info->lcdc.v_back_porch;
+ var->upper_margin = panel_info->lcdc.v_back_porch;
+ var->lower_margin = panel_info->lcdc.v_front_porch;
var->vsync_len = panel_info->lcdc.v_pulse_width;
- var->left_margin = panel_info->lcdc.h_front_porch;
- var->right_margin = panel_info->lcdc.h_back_porch;
+ var->left_margin = panel_info->lcdc.h_back_porch;
+ var->right_margin = panel_info->lcdc.h_front_porch;
var->hsync_len = panel_info->lcdc.h_pulse_width;
var->pixclock = panel_info->clk_rate / 1000;
@@ -1006,11 +1006,11 @@
{
pinfo->xres = var->xres;
pinfo->yres = var->yres;
- pinfo->lcdc.v_front_porch = var->upper_margin;
- pinfo->lcdc.v_back_porch = var->lower_margin;
+ pinfo->lcdc.v_front_porch = var->lower_margin;
+ pinfo->lcdc.v_back_porch = var->upper_margin;
pinfo->lcdc.v_pulse_width = var->vsync_len;
- pinfo->lcdc.h_front_porch = var->left_margin;
- pinfo->lcdc.h_back_porch = var->right_margin;
+ pinfo->lcdc.h_front_porch = var->right_margin;
+ pinfo->lcdc.h_back_porch = var->left_margin;
pinfo->lcdc.h_pulse_width = var->hsync_len;
pinfo->clk_rate = var->pixclock;
/* todo: find how to pass CEA vic through framebuffer APIs */
diff --git a/drivers/video/msm/mdss/mdss_hdmi_edid.c b/drivers/video/msm/mdss/mdss_hdmi_edid.c
index 8db38d6..6c76348 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_edid.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_edid.c
@@ -16,9 +16,17 @@
#include "mdss_hdmi_edid.h"
#define DBC_START_OFFSET 4
-#define HDMI_VSDB_3D_DATA_OFFSET(vsd) \
+#define HDMI_VSDB_3D_EVF_DATA_OFFSET(vsd) \
(!((vsd)[8] & BIT(7)) ? 9 : (!((vsd)[8] & BIT(6)) ? 11 : 13))
+/*
+ * As per the CEA-861E spec, there can be a total of 10 short audio
+ * descriptors with each SAD being 3 bytes long.
+ * Thus, the maximum length of the audio data block would be 30 bytes
+ */
+#define MAX_AUDIO_DATA_BLOCK_SIZE 30
+#define MAX_SPKR_ALLOC_DATA_BLOCK_SIZE 3
+
struct hdmi_edid_sink_data {
u32 disp_mode_list[HDMI_VFRMT_MAX];
u32 disp_3d_mode_list[HDMI_VFRMT_MAX];
@@ -35,11 +43,13 @@
u16 physical_address;
u32 video_resolution; /* selected by user */
u32 sink_mode; /* HDMI or DVI */
- u8 speaker_allocation_block;
- u8 audio_data_block_cnt;
u16 audio_latency;
u16 video_latency;
u32 present_3d;
+ u8 audio_data_block[MAX_AUDIO_DATA_BLOCK_SIZE];
+ int adb_size;
+ u8 spkr_alloc_data_block[MAX_SPKR_ALLOC_DATA_BLOCK_SIZE];
+ int sadb_size;
struct hdmi_edid_sink_data sink_data;
struct hdmi_edid_init_data init_data;
@@ -180,6 +190,10 @@
{HDMI_VFRMT_1920x1080i120_16_9, 1920, 1080, true, 2200, 280, 1125,
22, 67500, 120000, 148500, 120000, false},
+ /* All 2560 H Active */
+ {HDMI_VFRMT_2560x1600p60_16_9, 2560, 1600, false, 2720, 160, 1646,
+ 46, 98700, 60000, 268500, 60000, false},
+
/* All 2880 H Active */
{HDMI_VFRMT_2880x576i50_4_3, 2880, 576, true, 3456, 576, 625, 24,
15625, 50000, 54000, 50000, true},
@@ -437,7 +451,7 @@
u8 block_len = in_buf[offset] & 0x1F;
if ((in_buf[offset] >> 5) == type) {
*len = block_len;
- DEV_DBG("%s: EDID: block=%d found @ %d w/ length=%d\n",
+ DEV_DBG("%s: EDID: block=%d found @ 0x%x w/ len=%d\n",
__func__, type, offset, block_len);
return in_buf + offset;
@@ -533,8 +547,8 @@
return;
}
- offset = HDMI_VSDB_3D_DATA_OFFSET(vsd);
- DEV_DBG("%s: EDID: 3D present @ %d = %02x\n", __func__,
+ offset = HDMI_VSDB_3D_EVF_DATA_OFFSET(vsd);
+ DEV_DBG("%s: EDID: 3D present @ 0x%x = %02x\n", __func__,
offset, vsd[offset]);
if (vsd[offset] >> 7) { /* 3D format indication present */
@@ -547,26 +561,28 @@
static void hdmi_edid_extract_audio_data_blocks(
struct hdmi_edid_ctrl *edid_ctrl, const u8 *in_buf)
{
- u8 len;
- const u8 *sad = NULL;
+ u8 len, cnt = 0;
+ const u8 *adb = NULL;
if (!edid_ctrl) {
DEV_ERR("%s: invalid input\n", __func__);
return;
}
- sad = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 1, &len);
- if (sad == NULL)
+ adb = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 1, &len);
+ if ((adb == NULL) || (len > MAX_AUDIO_DATA_BLOCK_SIZE))
return;
- edid_ctrl->audio_data_block_cnt = 0;
- while (len >= 3 && edid_ctrl->audio_data_block_cnt < 16) {
- DEV_DBG("%s: ch=%d fmt=%d sampling=0x%02x bitdepth=0x%02x\n",
- __func__, (sad[1]&0x7)+1, sad[1]>>3, sad[2], sad[3]);
+ memcpy(edid_ctrl->audio_data_block, adb + 1, len);
+ edid_ctrl->adb_size = len;
- ++edid_ctrl->audio_data_block_cnt;
+ while (len >= 3 && cnt < 16) {
+ DEV_DBG("%s: ch=%d fmt=%d sampling=0x%02x bitdepth=0x%02x\n",
+ __func__, (adb[1]&0x7)+1, adb[1]>>3, adb[2], adb[3]);
+
+ cnt++;
len -= 3;
- sad += 3;
+ adb += 3;
}
} /* hdmi_edid_extract_audio_data_blocks */
@@ -574,27 +590,29 @@
struct hdmi_edid_ctrl *edid_ctrl, const u8 *in_buf)
{
u8 len;
- const u8 *sad = NULL;
+ const u8 *sadb = NULL;
if (!edid_ctrl) {
DEV_ERR("%s: invalid input\n", __func__);
return;
}
- sad = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 4, &len);
- if (sad == NULL)
+ sadb = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 4, &len);
+ if ((sadb == NULL) || (len != MAX_SPKR_ALLOC_DATA_BLOCK_SIZE))
return;
- edid_ctrl->speaker_allocation_block = sad[1];
+ memcpy(edid_ctrl->spkr_alloc_data_block, sadb + 1, len);
+ edid_ctrl->sadb_size = len;
+
DEV_DBG("%s: EDID: speaker alloc data SP byte = %08x %s%s%s%s%s%s%s\n",
- __func__, sad[1],
- (sad[1] & BIT(0)) ? "FL/FR," : "",
- (sad[1] & BIT(1)) ? "LFE," : "",
- (sad[1] & BIT(2)) ? "FC," : "",
- (sad[1] & BIT(3)) ? "RL/RR," : "",
- (sad[1] & BIT(4)) ? "RC," : "",
- (sad[1] & BIT(5)) ? "FLC/FRC," : "",
- (sad[1] & BIT(6)) ? "RLC/RRC," : "");
+ __func__, sadb[1],
+ (sadb[1] & BIT(0)) ? "FL/FR," : "",
+ (sadb[1] & BIT(1)) ? "LFE," : "",
+ (sadb[1] & BIT(2)) ? "FC," : "",
+ (sadb[1] & BIT(3)) ? "RL/RR," : "",
+ (sadb[1] & BIT(4)) ? "RC," : "",
+ (sadb[1] & BIT(5)) ? "FLC/FRC," : "",
+ (sadb[1] & BIT(6)) ? "RLC/RRC," : "");
} /* hdmi_edid_extract_speaker_allocation_data */
static void hdmi_edid_extract_latency_fields(struct hdmi_edid_ctrl *edid_ctrl,
@@ -835,7 +853,7 @@
3, &len) : NULL;
int i;
- offset = HDMI_VSDB_3D_DATA_OFFSET(vsd);
+ offset = HDMI_VSDB_3D_EVF_DATA_OFFSET(vsd);
present_multi_3d = (vsd[offset] & 0x60) >> 5;
offset += 1;
@@ -897,17 +915,16 @@
i = 0;
while (hdmi_3d_len > 0) {
- DEV_DBG("%s: EDID[3D]: 3D_Structure_%d @ %d: %02x\n", __func__,
- i + 1, offset, vsd[offset]);
+ DEV_DBG("%s: EDID: 3D_Structure_%d @ 0x%x: %02x\n",
+ __func__, i + 1, offset, vsd[offset]);
if ((vsd[offset] >> 4) >=
sink_data->disp_multi_3d_mode_list_cnt) {
if ((vsd[offset] & 0x0F) >= 8) {
offset += 1;
hdmi_3d_len -= 1;
- DEV_DBG("%s:EDID[3D]:3D_Detail_%d @ %d: %02x\n",
- __func__, i + 1, offset,
- vsd[offset]);
+ DEV_DBG("%s:EDID:3D_Detail_%d @ 0x%x: %02x\n",
+ __func__, i + 1, offset, vsd[offset]);
}
i += 1;
offset += 1;
@@ -941,7 +958,7 @@
if ((vsd[offset] & 0x0F) >= 8) {
offset += 1;
hdmi_3d_len -= 1;
- DEV_DBG("%s: EDID[3D]: 3D_Detail_%d @ %d: %02x\n",
+ DEV_DBG("%s: EDID[3D]: 3D_Detail_%d @ 0x%x: %02x\n",
__func__, i + 1, offset,
vsd[offset]);
}
@@ -951,6 +968,49 @@
}
} /* hdmi_edid_get_display_vsd_3d_mode */
+static void hdmi_edid_get_extended_video_formats(
+ struct hdmi_edid_ctrl *edid_ctrl, const u8 *in_buf)
+{
+ u8 db_len, offset, i;
+ u8 hdmi_vic_len;
+ u32 video_format;
+ const u8 *vsd = NULL;
+
+ if (!edid_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 3, &db_len);
+
+ if (vsd == NULL || db_len < 9) {
+ DEV_DBG("%s: blk-id 3 not found or not long enough\n",
+ __func__);
+ return;
+ }
+
+ /* check if HDMI_Video_present flag is set or not */
+ if (!(vsd[8] & BIT(5))) {
+ DEV_DBG("%s: extended vfmts are not supported by the sink.\n",
+ __func__);
+ return;
+ }
+
+ offset = HDMI_VSDB_3D_EVF_DATA_OFFSET(vsd);
+
+ hdmi_vic_len = vsd[offset + 1] >> 5;
+ if (hdmi_vic_len) {
+ DEV_DBG("%s: EDID: EVFRMT @ 0x%x of block 3, len = %02x\n",
+ __func__, offset, hdmi_vic_len);
+
+ for (i = 0; i < hdmi_vic_len; i++) {
+ video_format = HDMI_VFRMT_END + vsd[offset + 2 + i];
+ hdmi_edid_add_sink_video_format(&edid_ctrl->sink_data,
+ video_format);
+ }
+ }
+} /* hdmi_edid_get_extended_video_formats */
+
static void hdmi_edid_get_display_mode(struct hdmi_edid_ctrl *edid_ctrl,
const u8 *data_buf, u32 num_of_cea_blocks)
{
@@ -1113,6 +1173,8 @@
}
}
+ hdmi_edid_get_extended_video_formats(edid_ctrl, data_buf+0x80);
+
/* mandaroty 3d format */
if (edid_ctrl->present_3d) {
if (has60hz_mode) {
@@ -1177,6 +1239,12 @@
edid_ctrl->present_3d = 0;
memset(&edid_ctrl->sink_data, 0, sizeof(edid_ctrl->sink_data));
memset(edid_buf, 0, sizeof(edid_buf));
+ memset(edid_ctrl->audio_data_block, 0,
+ sizeof(edid_ctrl->audio_data_block));
+ memset(edid_ctrl->spkr_alloc_data_block, 0,
+ sizeof(edid_ctrl->spkr_alloc_data_block));
+ edid_ctrl->adb_size = 0;
+ edid_ctrl->sadb_size = 0;
status = hdmi_edid_read_block(edid_ctrl, 0, edid_buf);
if (status || !hdmi_edid_check_header(edid_buf)) {
@@ -1353,6 +1421,24 @@
return edid_ctrl->sink_mode;
} /* hdmi_edid_get_sink_mode */
+int hdmi_edid_get_audio_blk(void *input, struct msm_hdmi_audio_edid_blk *blk)
+{
+ struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input;
+
+ if (!edid_ctrl || !blk) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ blk->audio_data_blk = edid_ctrl->audio_data_block;
+ blk->audio_data_blk_size = edid_ctrl->adb_size;
+
+ blk->spk_alloc_data_blk = edid_ctrl->spkr_alloc_data_block;
+ blk->spk_alloc_data_blk_size = edid_ctrl->sadb_size;
+
+ return 0;
+} /* hdmi_edid_get_audio_blk */
+
void hdmi_edid_set_video_resolution(void *input, u32 resolution)
{
struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input;
diff --git a/drivers/video/msm/mdss/mdss_hdmi_edid.h b/drivers/video/msm/mdss/mdss_hdmi_edid.h
index 5c51e7e..bb56a24 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_edid.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_edid.h
@@ -13,6 +13,7 @@
#ifndef __HDMI_EDID_H__
#define __HDMI_EDID_H__
+#include <mach/msm_hdmi_audio_codec.h>
#include "mdss_hdmi_util.h"
struct hdmi_edid_init_data {
@@ -26,6 +27,8 @@
int hdmi_edid_read(void *edid_ctrl);
u8 hdmi_edid_get_sink_scaninfo(void *edid_ctrl, u32 resolution);
u32 hdmi_edid_get_sink_mode(void *edid_ctrl);
+int hdmi_edid_get_audio_blk(void *edid_ctrl,
+ struct msm_hdmi_audio_edid_blk *blk);
void hdmi_edid_set_video_resolution(void *edid_ctrl, u32 resolution);
void hdmi_edid_deinit(void *edid_ctrl);
void *hdmi_edid_init(struct hdmi_edid_init_data *init_data);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_hdcp.c b/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
new file mode 100644
index 0000000..e361510
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
@@ -0,0 +1,1180 @@
+/* Copyright (c) 2010-2012 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/io.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#include "mdss_hdmi_hdcp.h"
+
+#define HDCP_STATE_NAME (hdcp_state_name(hdcp_ctrl->hdcp_state))
+
+/* HDCP Keys state based on HDMI_HDCP_LINK0_STATUS:KEYS_STATE */
+#define HDCP_KEYS_STATE_NO_KEYS 0
+#define HDCP_KEYS_STATE_NOT_CHECKED 1
+#define HDCP_KEYS_STATE_CHECKING 2
+#define HDCP_KEYS_STATE_VALID 3
+#define HDCP_KEYS_STATE_AKSV_NOT_VALID 4
+#define HDCP_KEYS_STATE_CHKSUM_MISMATCH 5
+#define HDCP_KEYS_STATE_PROD_AKSV 6
+#define HDCP_KEYS_STATE_RESERVED 7
+
+struct hdmi_hdcp_ctrl {
+ enum hdmi_hdcp_state hdcp_state;
+ struct work_struct hdcp_auth_work;
+ struct work_struct hdcp_int_work;
+ struct completion r0_checked;
+ struct hdmi_hdcp_init_data init_data;
+ struct timer_list hdcp_timer;
+};
+
+const char *hdcp_state_name(enum hdmi_hdcp_state hdcp_state)
+{
+ switch (hdcp_state) {
+ case HDCP_STATE_INACTIVE: return "HDCP_STATE_INACTIVE";
+ case HDCP_STATE_AUTHENTICATING: return "HDCP_STATE_AUTHENTICATING";
+ case HDCP_STATE_AUTHENTICATED: return "HDCP_STATE_AUTHENTICATED";
+ case HDCP_STATE_AUTH_FAIL: return "HDCP_STATE_AUTH_FAIL";
+ default: return "???";
+ }
+} /* hdcp_state_name */
+
+static int hdmi_hdcp_count_one(u8 *array, u8 len)
+{
+ int i, j, count = 0;
+ for (i = 0; i < len; i++)
+ for (j = 0; j < 8; j++)
+ count += (((array[i] >> j) & 0x1) ? 1 : 0);
+ return count;
+} /* hdmi_hdcp_count_one */
+
+static void reset_hdcp_ddc_failures(struct hdmi_hdcp_ctrl *hdcp_ctrl)
+{
+ int hdcp_ddc_ctrl1_reg;
+ int hdcp_ddc_status;
+ int failure;
+ int nack0;
+ struct dss_io_data *io;
+
+ if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ io = hdcp_ctrl->init_data.core_io;
+
+ /* Check for any DDC transfer failures */
+ hdcp_ddc_status = DSS_REG_R(io, HDMI_HDCP_DDC_STATUS);
+ failure = (hdcp_ddc_status >> 16) & 0x1;
+ nack0 = (hdcp_ddc_status >> 14) & 0x1;
+ DEV_DBG("%s: %s: On Entry: HDCP_DDC_STATUS=0x%x, FAIL=%d, NACK0=%d\n",
+ __func__, HDCP_STATE_NAME, hdcp_ddc_status, failure, nack0);
+
+ if (failure == 0x1) {
+ /*
+ * Indicates that the last HDCP HW DDC transfer failed.
+ * This occurs when a transfer is attempted with HDCP DDC
+ * disabled (HDCP_DDC_DISABLE=1) or the number of retries
+ * matches HDCP_DDC_RETRY_CNT.
+ * Failure occured, let's clear it.
+ */
+ DEV_DBG("%s: %s: DDC failure detected.HDCP_DDC_STATUS=0x%08x\n",
+ __func__, HDCP_STATE_NAME, hdcp_ddc_status);
+
+ /* First, Disable DDC */
+ DSS_REG_W(io, HDMI_HDCP_DDC_CTRL_0, BIT(0));
+
+ /* ACK the Failure to Clear it */
+ hdcp_ddc_ctrl1_reg = DSS_REG_R(io, HDMI_HDCP_DDC_CTRL_1);
+ DSS_REG_W(io, HDMI_HDCP_DDC_CTRL_1,
+ hdcp_ddc_ctrl1_reg | BIT(0));
+
+ /* Check if the FAILURE got Cleared */
+ hdcp_ddc_status = DSS_REG_R(io, HDMI_HDCP_DDC_STATUS);
+ hdcp_ddc_status = (hdcp_ddc_status >> 16) & BIT(0);
+ if (hdcp_ddc_status == 0x0)
+ DEV_DBG("%s: %s: HDCP DDC Failure cleared\n", __func__,
+ HDCP_STATE_NAME);
+ else
+ DEV_WARN("%s: %s: Unable to clear HDCP DDC Failure",
+ __func__, HDCP_STATE_NAME);
+
+ /* Re-Enable HDCP DDC */
+ DSS_REG_W(io, HDMI_HDCP_DDC_CTRL_0, 0);
+ }
+
+ if (nack0 == 0x1) {
+ DEV_DBG("%s: %s: Before: HDMI_DDC_SW_STATUS=0x%08x\n", __func__,
+ HDCP_STATE_NAME, DSS_REG_R(io, HDMI_DDC_SW_STATUS));
+ /* Reset HDMI DDC software status */
+ DSS_REG_W_ND(io, HDMI_DDC_CTRL,
+ DSS_REG_R(io, HDMI_DDC_CTRL) | BIT(3));
+ msleep(20);
+ DSS_REG_W_ND(io, HDMI_DDC_CTRL,
+ DSS_REG_R(io, HDMI_DDC_CTRL) & ~(BIT(3)));
+
+ /* Reset HDMI DDC Controller */
+ DSS_REG_W_ND(io, HDMI_DDC_CTRL,
+ DSS_REG_R(io, HDMI_DDC_CTRL) | BIT(1));
+ msleep(20);
+ DSS_REG_W_ND(io, HDMI_DDC_CTRL,
+ DSS_REG_R(io, HDMI_DDC_CTRL) & ~BIT(1));
+ DEV_DBG("%s: %s: After: HDMI_DDC_SW_STATUS=0x%08x\n", __func__,
+ HDCP_STATE_NAME, DSS_REG_R(io, HDMI_DDC_SW_STATUS));
+ }
+
+ hdcp_ddc_status = DSS_REG_R(io, HDMI_HDCP_DDC_STATUS);
+
+ failure = (hdcp_ddc_status >> 16) & BIT(0);
+ nack0 = (hdcp_ddc_status >> 14) & BIT(0);
+ DEV_DBG("%s: %s: On Exit: HDCP_DDC_STATUS=0x%x, FAIL=%d, NACK0=%d\n",
+ __func__, HDCP_STATE_NAME, hdcp_ddc_status, failure, nack0);
+} /* reset_hdcp_ddc_failures */
+
+static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl)
+{
+ int rc;
+ u32 qfprom_aksv_lsb, qfprom_aksv_msb;
+ u32 link0_aksv_0, link0_aksv_1;
+ u32 link0_bksv_0, link0_bksv_1;
+ u32 link0_an_0, link0_an_1;
+ u32 timeout_count;
+ bool is_match;
+ bool stale_an = false;
+ struct dss_io_data *io;
+ u8 aksv[5], bksv[5];
+ u8 an[8];
+ u8 bcaps;
+ struct hdmi_tx_ddc_data ddc_data;
+ u32 link0_status, an_ready, keys_state;
+ u8 buf[0xFF];
+
+ if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io ||
+ !hdcp_ctrl->init_data.qfprom_io) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ if (HDCP_STATE_AUTHENTICATING != hdcp_ctrl->hdcp_state) {
+ DEV_DBG("%s: %s: invalid state. returning\n", __func__,
+ HDCP_STATE_NAME);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ io = hdcp_ctrl->init_data.core_io;
+
+ /* Fetch aksv from QFPROM, this info should be public. */
+ qfprom_aksv_lsb = DSS_REG_R(hdcp_ctrl->init_data.qfprom_io,
+ HDCP_KSV_LSB);
+ qfprom_aksv_msb = DSS_REG_R(hdcp_ctrl->init_data.qfprom_io,
+ HDCP_KSV_MSB);
+
+ aksv[0] = qfprom_aksv_lsb & 0xFF;
+ aksv[1] = (qfprom_aksv_lsb >> 8) & 0xFF;
+ aksv[2] = (qfprom_aksv_lsb >> 16) & 0xFF;
+ aksv[3] = (qfprom_aksv_lsb >> 24) & 0xFF;
+ aksv[4] = qfprom_aksv_msb & 0xFF;
+
+ /* check there are 20 ones in AKSV */
+ if (hdmi_hdcp_count_one(aksv, 5) != 20) {
+ DEV_ERR("%s: %s: AKSV QFPROM doesn't have 20 1's, 20 0's\n",
+ __func__, HDCP_STATE_NAME);
+ DEV_ERR("%s: %s: QFPROM AKSV chk failed (AKSV=%02x%08x)\n",
+ __func__, HDCP_STATE_NAME, qfprom_aksv_msb,
+ qfprom_aksv_lsb);
+ rc = -EINVAL;
+ goto error;
+ }
+ DEV_DBG("%s: %s: AKSV=%02x%08x\n", __func__, HDCP_STATE_NAME,
+ qfprom_aksv_msb, qfprom_aksv_lsb);
+
+ /*
+ * Write AKSV read from QFPROM to the HDCP registers.
+ * This step is needed for HDCP authentication and must be
+ * written before enabling HDCP.
+ */
+ DSS_REG_W(io, HDMI_HDCP_SW_LOWER_AKSV, qfprom_aksv_lsb);
+ DSS_REG_W(io, HDMI_HDCP_SW_UPPER_AKSV, qfprom_aksv_msb);
+
+ /* Check to see if link0_Status has stale values for An ready bit */
+ link0_status = DSS_REG_R(io, HDMI_HDCP_LINK0_STATUS);
+ DEV_DBG("%s: %s: Before enabling cipher Link0_status=0x%08x\n",
+ __func__, HDCP_STATE_NAME, link0_status);
+ if (link0_status & (BIT(8) | BIT(9))) {
+ DEV_DBG("%s: %s: An ready even before enabling HDCP\n",
+ __func__, HDCP_STATE_NAME);
+ stale_an = true;
+ }
+
+ /*
+ * Read BCAPS
+ * We need to first try to read an HDCP register on the sink to see if
+ * the sink is ready for HDCP authentication
+ */
+ memset(&ddc_data, 0, sizeof(ddc_data));
+ ddc_data.dev_addr = 0x74;
+ ddc_data.offset = 0x40;
+ ddc_data.data_buf = &bcaps;
+ ddc_data.data_len = 1;
+ ddc_data.request_len = 1;
+ ddc_data.retry = 5;
+ ddc_data.what = "Bcaps";
+ ddc_data.no_align = true;
+ rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl, &ddc_data);
+ if (rc) {
+ DEV_ERR("%s: %s: BCAPS read failed\n", __func__,
+ HDCP_STATE_NAME);
+ goto error;
+ }
+ DEV_DBG("%s: %s: BCAPS=%02x\n", __func__, HDCP_STATE_NAME, bcaps);
+
+ /*
+ * HDCP setup prior to enabling HDCP_CTRL.
+ * Setup seed values for random number An.
+ */
+ DSS_REG_W(io, HDMI_HDCP_ENTROPY_CTRL0, 0xB1FFB0FF);
+ DSS_REG_W(io, HDMI_HDCP_ENTROPY_CTRL1, 0xF00DFACE);
+
+ /* Disable the RngCipher state */
+ DSS_REG_W(io, HDMI_HDCP_DEBUG_CTRL,
+ DSS_REG_R(io, HDMI_HDCP_DEBUG_CTRL) & ~(BIT(2)));
+ DEV_DBG("%s: %s: HDCP_DEBUG_CTRL=0x%08x\n", __func__, HDCP_STATE_NAME,
+ DSS_REG_R(io, HDMI_HDCP_DEBUG_CTRL));
+
+ /* Ensure that all register writes are completed before
+ * enabling HDCP cipher
+ */
+ wmb();
+
+ /*
+ * Enable HDCP
+ * This needs to be done as early as possible in order for the
+ * hardware to make An available to read
+ */
+ DSS_REG_W(io, HDMI_HDCP_CTRL, BIT(0));
+
+ /* Clear any DDC failures from previous tries */
+ reset_hdcp_ddc_failures(hdcp_ctrl);
+
+ /* Write BCAPS to the hardware */
+ DSS_REG_W(io, HDMI_HDCP_RCVPORT_DATA12, bcaps);
+
+ /*
+ * If we had stale values for the An ready bit, it should most
+ * likely be cleared now after enabling HDCP cipher
+ */
+ link0_status = DSS_REG_R(io, HDMI_HDCP_LINK0_STATUS);
+ DEV_DBG("%s: %s: After enabling HDCP Link0_Status=0x%08x\n",
+ __func__, HDCP_STATE_NAME, link0_status);
+ if (!(link0_status & (BIT(8) | BIT(9)))) {
+ DEV_DBG("%s: %s: An not ready after enabling HDCP\n",
+ __func__, HDCP_STATE_NAME);
+ stale_an = false;
+ }
+
+ /* Wait for HDCP keys to be checked and validated */
+ timeout_count = 100;
+ keys_state = (link0_status >> 28) & 0x7;
+ while ((keys_state != HDCP_KEYS_STATE_VALID) &&
+ timeout_count--) {
+ link0_status = DSS_REG_R(io, HDMI_HDCP_LINK0_STATUS);
+ keys_state = (link0_status >> 28) & 0x7;
+ DEV_DBG("%s: %s: Keys not ready(%d). s=%d\n, l0=%0x08x",
+ __func__, HDCP_STATE_NAME, timeout_count,
+ keys_state, link0_status);
+ msleep(20);
+ }
+
+ if (!timeout_count) {
+ DEV_ERR("%s: %s: Invalid Keys State: %d\n", __func__,
+ HDCP_STATE_NAME, keys_state);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ /*
+ * 1.1_Features turned off by default.
+ * No need to write AInfo since 1.1_Features is disabled.
+ */
+ DSS_REG_W(io, HDMI_HDCP_RCVPORT_DATA4, 0);
+
+ /* Wait for An0 and An1 bit to be ready */
+ timeout_count = 100;
+ do {
+ link0_status = DSS_REG_R(io, HDMI_HDCP_LINK0_STATUS);
+ an_ready = (link0_status & BIT(8)) && (link0_status & BIT(9));
+ if (!an_ready) {
+ DEV_DBG("%s: %s: An not ready(%d). l0_status=0x%08x\n",
+ __func__, HDCP_STATE_NAME, timeout_count,
+ link0_status);
+ msleep(20);
+ }
+ } while (!an_ready && timeout_count--);
+
+ if (!timeout_count) {
+ rc = -ETIMEDOUT;
+ DEV_ERR("%s: %s: timedout, An0=%ld, An1=%ld\n", __func__,
+ HDCP_STATE_NAME, (link0_status & BIT(8)) >> 8,
+ (link0_status & BIT(9)) >> 9);
+ goto error;
+ }
+
+ /*
+ * In cases where An_ready bits had stale values, it would be
+ * better to delay reading of An to avoid any potential of this
+ * read being blocked
+ */
+ if (stale_an) {
+ msleep(200);
+ stale_an = false;
+ }
+
+ /* Read An0 and An1 */
+ link0_an_0 = DSS_REG_R(io, HDMI_HDCP_RCVPORT_DATA5);
+ link0_an_1 = DSS_REG_R(io, HDMI_HDCP_RCVPORT_DATA6);
+
+ /* Read AKSV */
+ link0_aksv_0 = DSS_REG_R(io, HDMI_HDCP_RCVPORT_DATA3);
+ link0_aksv_1 = DSS_REG_R(io, HDMI_HDCP_RCVPORT_DATA4);
+
+ /* Copy An and AKSV to byte arrays for transmission */
+ aksv[0] = link0_aksv_0 & 0xFF;
+ aksv[1] = (link0_aksv_0 >> 8) & 0xFF;
+ aksv[2] = (link0_aksv_0 >> 16) & 0xFF;
+ aksv[3] = (link0_aksv_0 >> 24) & 0xFF;
+ aksv[4] = link0_aksv_1 & 0xFF;
+
+ an[0] = link0_an_0 & 0xFF;
+ an[1] = (link0_an_0 >> 8) & 0xFF;
+ an[2] = (link0_an_0 >> 16) & 0xFF;
+ an[3] = (link0_an_0 >> 24) & 0xFF;
+ an[4] = link0_an_1 & 0xFF;
+ an[5] = (link0_an_1 >> 8) & 0xFF;
+ an[6] = (link0_an_1 >> 16) & 0xFF;
+ an[7] = (link0_an_1 >> 24) & 0xFF;
+
+ /* Write An to offset 0x18 */
+ memset(&ddc_data, 0, sizeof(ddc_data));
+ ddc_data.dev_addr = 0x74;
+ ddc_data.offset = 0x18;
+ ddc_data.data_buf = an;
+ ddc_data.data_len = 8;
+ ddc_data.what = "An";
+ rc = hdmi_ddc_write(hdcp_ctrl->init_data.ddc_ctrl, &ddc_data);
+ if (rc) {
+ DEV_ERR("%s: %s: An write failed\n", __func__, HDCP_STATE_NAME);
+ goto error;
+ }
+
+ /* Write AKSV to offset 0x10 */
+ memset(&ddc_data, 0, sizeof(ddc_data));
+ ddc_data.dev_addr = 0x74;
+ ddc_data.offset = 0x10;
+ ddc_data.data_buf = aksv;
+ ddc_data.data_len = 5;
+ ddc_data.what = "Aksv";
+ rc = hdmi_ddc_write(hdcp_ctrl->init_data.ddc_ctrl, &ddc_data);
+ if (rc) {
+ DEV_ERR("%s: %s: AKSV write failed\n", __func__,
+ HDCP_STATE_NAME);
+ goto error;
+ }
+ DEV_DBG("%s: %s: Link0-AKSV=%02x%08x\n", __func__,
+ HDCP_STATE_NAME, link0_aksv_1 & 0xFF, link0_aksv_0);
+
+ /* Read BKSV at offset 0x00 */
+ memset(&ddc_data, 0, sizeof(ddc_data));
+ ddc_data.dev_addr = 0x74;
+ ddc_data.offset = 0x00;
+ ddc_data.data_buf = bksv;
+ ddc_data.data_len = 5;
+ ddc_data.request_len = 5;
+ ddc_data.retry = 5;
+ ddc_data.what = "Bksv";
+ ddc_data.no_align = true;
+ rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl, &ddc_data);
+ if (rc) {
+ DEV_ERR("%s: %s: BKSV read failed\n", __func__,
+ HDCP_STATE_NAME);
+ goto error;
+ }
+
+ /* check there are 20 ones in BKSV */
+ if (hdmi_hdcp_count_one(bksv, 5) != 20) {
+ DEV_ERR("%s: %s: BKSV doesn't have 20 1's and 20 0's\n",
+ __func__, HDCP_STATE_NAME);
+ DEV_ERR("%s: %s: BKSV chk fail. BKSV=%02x%02x%02x%02x%02x\n",
+ __func__, HDCP_STATE_NAME, bksv[4], bksv[3], bksv[2],
+ bksv[1], bksv[0]);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ link0_bksv_0 = bksv[3];
+ link0_bksv_0 = (link0_bksv_0 << 8) | bksv[2];
+ link0_bksv_0 = (link0_bksv_0 << 8) | bksv[1];
+ link0_bksv_0 = (link0_bksv_0 << 8) | bksv[0];
+ link0_bksv_1 = bksv[4];
+ DEV_DBG("%s: %s: BKSV=%02x%08x\n", __func__, HDCP_STATE_NAME,
+ link0_bksv_1, link0_bksv_0);
+
+ /* Write BKSV read from sink to HDCP registers */
+ DSS_REG_W(io, HDMI_HDCP_RCVPORT_DATA0, link0_bksv_0);
+ DSS_REG_W(io, HDMI_HDCP_RCVPORT_DATA1, link0_bksv_1);
+
+ /* Enable HDCP interrupts and ack/clear any stale interrupts */
+ DSS_REG_W(io, HDMI_HDCP_INT_CTRL, 0xE6);
+
+ /*
+ * HDCP Compliace Test case 1A-01:
+ * Wait here at least 100ms before reading R0'
+ */
+ msleep(125);
+
+ /* Read R0' at offset 0x08 */
+ memset(buf, 0, sizeof(buf));
+ memset(&ddc_data, 0, sizeof(ddc_data));
+ ddc_data.dev_addr = 0x74;
+ ddc_data.offset = 0x08;
+ ddc_data.data_buf = buf;
+ ddc_data.data_len = 2;
+ ddc_data.request_len = 2;
+ ddc_data.retry = 5;
+ ddc_data.what = "R0'";
+ ddc_data.no_align = true;
+ rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl, &ddc_data);
+ if (rc) {
+ DEV_ERR("%s: %s: R0' read failed\n", __func__, HDCP_STATE_NAME);
+ goto error;
+ }
+ DEV_DBG("%s: %s: R0'=%02x%02x\n", __func__, HDCP_STATE_NAME,
+ buf[1], buf[0]);
+
+ /* Write R0' to HDCP registers and check to see if it is a match */
+ INIT_COMPLETION(hdcp_ctrl->r0_checked);
+ DSS_REG_W(io, HDMI_HDCP_RCVPORT_DATA2_0, (((u32)buf[1]) << 8) | buf[0]);
+ timeout_count = wait_for_completion_interruptible_timeout(
+ &hdcp_ctrl->r0_checked, HZ*2);
+ link0_status = DSS_REG_R(io, HDMI_HDCP_LINK0_STATUS);
+ is_match = link0_status & BIT(12);
+ if (!is_match) {
+ DEV_DBG("%s: %s: Link0_Status=0x%08x\n", __func__,
+ HDCP_STATE_NAME, link0_status);
+ if (!timeout_count) {
+ DEV_ERR("%s: %s: Timeout. No R0 mtch. R0'=%02x%02x\n",
+ __func__, HDCP_STATE_NAME, buf[1], buf[0]);
+ rc = -ETIMEDOUT;
+ goto error;
+ } else {
+ DEV_ERR("%s: %s: R0 mismatch. R0'=%02x%02x\n", __func__,
+ HDCP_STATE_NAME, buf[1], buf[0]);
+ rc = -EINVAL;
+ goto error;
+ }
+ } else {
+ DEV_DBG("%s: %s: R0 matches\n", __func__, HDCP_STATE_NAME);
+ }
+
+error:
+ if (rc) {
+ DEV_ERR("%s: %s: Authentication Part I failed\n", __func__,
+ HDCP_STATE_NAME);
+ } else {
+ /* Enable HDCP Encryption */
+ DSS_REG_W(io, HDMI_HDCP_CTRL, BIT(0) | BIT(8));
+ DEV_INFO("%s: %s: Authentication Part I successful\n",
+ __func__, HDCP_STATE_NAME);
+ }
+ return rc;
+} /* hdmi_hdcp_authentication_part1 */
+
+#define READ_WRITE_V_H(off, name, reg) \
+do { \
+ ddc_data.offset = (off); \
+ memset(what, 0, sizeof(what)); \
+ snprintf(what, sizeof(what), (name)); \
+ rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl, &ddc_data); \
+ if (rc) { \
+ DEV_ERR("%s: %s: Read %s failed\n", __func__, HDCP_STATE_NAME, \
+ what); \
+ goto error; \
+ } \
+ DEV_DBG("%s: %s: %s: buf[0]=%x, buf[1]=%x, buf[2]=%x, buf[3]=%x\n", \
+ __func__, HDCP_STATE_NAME, what, buf[0], buf[1], \
+ buf[2], buf[3]); \
+ DSS_REG_W(io, (reg), \
+ (buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0])); \
+} while (0);
+
+static int hdmi_hdcp_transfer_v_h(struct hdmi_hdcp_ctrl *hdcp_ctrl)
+{
+ char what[20];
+ int rc = 0;
+ u8 buf[4];
+ struct hdmi_tx_ddc_data ddc_data;
+ struct dss_io_data *io;
+
+ if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ io = hdcp_ctrl->init_data.core_io;
+ memset(&ddc_data, 0, sizeof(ddc_data));
+ ddc_data.dev_addr = 0x74;
+ ddc_data.data_buf = buf;
+ ddc_data.data_len = 4;
+ ddc_data.request_len = 4;
+ ddc_data.retry = 5;
+ ddc_data.what = what;
+ ddc_data.no_align = true;
+
+ /* Read V'.HO 4 Byte at offset 0x20 */
+ READ_WRITE_V_H(0x20, "V' H0", HDMI_HDCP_RCVPORT_DATA7);
+
+ /* Read V'.H1 4 Byte at offset 0x24 */
+ READ_WRITE_V_H(0x24, "V' H1", HDMI_HDCP_RCVPORT_DATA8);
+
+ /* Read V'.H2 4 Byte at offset 0x28 */
+ READ_WRITE_V_H(0x28, "V' H2", HDMI_HDCP_RCVPORT_DATA9);
+
+ /* Read V'.H3 4 Byte at offset 0x2C */
+ READ_WRITE_V_H(0x2C, "V' H3", HDMI_HDCP_RCVPORT_DATA10);
+
+ /* Read V'.H4 4 Byte at offset 0x30 */
+ READ_WRITE_V_H(0x30, "V' H4", HDMI_HDCP_RCVPORT_DATA11);
+
+error:
+ return rc;
+}
+
+static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl)
+{
+ int rc, cnt, i;
+ struct hdmi_tx_ddc_data ddc_data;
+ u32 timeout_count, down_stream_devices;
+ u8 buf[0xFF];
+ u8 ksv_fifo[5 * 127];
+ u8 bcaps;
+ u16 bstatus, max_devs_exceeded, max_cascade_exceeded;
+ u32 link0_status;
+ u32 ksv_bytes;
+ struct dss_io_data *io;
+
+ if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ if (HDCP_STATE_AUTHENTICATING != hdcp_ctrl->hdcp_state) {
+ DEV_DBG("%s: %s: invalid state. returning\n", __func__,
+ HDCP_STATE_NAME);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ io = hdcp_ctrl->init_data.core_io;
+
+ memset(buf, 0, sizeof(buf));
+ memset(ksv_fifo, 0, sizeof(ksv_fifo));
+
+ /* Read BCAPS at offset 0x40 */
+ memset(&ddc_data, 0, sizeof(ddc_data));
+ ddc_data.dev_addr = 0x74;
+ ddc_data.offset = 0x40;
+ ddc_data.data_buf = &bcaps;
+ ddc_data.data_len = 1;
+ ddc_data.request_len = 1;
+ ddc_data.retry = 5;
+ ddc_data.what = "Bcaps";
+ ddc_data.no_align = false;
+ rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl, &ddc_data);
+ if (rc) {
+ DEV_ERR("%s: %s: BCAPS read failed\n", __func__,
+ HDCP_STATE_NAME);
+ goto error;
+ }
+ DEV_DBG("%s: %s: BCAPS=%02x (%s)\n", __func__, HDCP_STATE_NAME, bcaps,
+ (bcaps & BIT(6)) ? "repeater" : "no repeater");
+
+ /* if REPEATER (Bit 6), perform Part2 Authentication */
+ if (!(bcaps & BIT(6))) {
+ DEV_INFO("%s: %s: auth part II skipped, no repeater\n",
+ __func__, HDCP_STATE_NAME);
+ return 0;
+ }
+
+ /* Wait until READY bit is set in BCAPS */
+ timeout_count = 50;
+ while (!(bcaps && BIT(5)) && timeout_count) {
+ msleep(100);
+ timeout_count--;
+ /* Read BCAPS at offset 0x40 */
+ memset(&ddc_data, 0, sizeof(ddc_data));
+ ddc_data.dev_addr = 0x74;
+ ddc_data.offset = 0x40;
+ ddc_data.data_buf = &bcaps;
+ ddc_data.data_len = 1;
+ ddc_data.request_len = 1;
+ ddc_data.retry = 5;
+ ddc_data.what = "Bcaps";
+ ddc_data.no_align = false;
+ rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl, &ddc_data);
+ if (rc) {
+ DEV_ERR("%s: %s: BCAPS read failed\n", __func__,
+ HDCP_STATE_NAME);
+ goto error;
+ }
+ }
+
+ /* Read BSTATUS at offset 0x41 */
+ memset(&ddc_data, 0, sizeof(ddc_data));
+ ddc_data.dev_addr = 0x74;
+ ddc_data.offset = 0x41;
+ ddc_data.data_buf = buf;
+ ddc_data.data_len = 2;
+ ddc_data.request_len = 2;
+ ddc_data.retry = 5;
+ ddc_data.what = "Bstatuss";
+ ddc_data.no_align = false;
+ rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl, &ddc_data);
+ if (rc) {
+ DEV_ERR("%s: %s: BSTATUS read failed\n", __func__,
+ HDCP_STATE_NAME);
+ goto error;
+ }
+ bstatus = buf[1];
+ bstatus = (bstatus << 8) | buf[0];
+
+ /* Write BSTATUS and BCAPS to HDCP registers */
+ DSS_REG_W(io, HDMI_HDCP_RCVPORT_DATA12, bcaps | (bstatus << 8));
+
+ down_stream_devices = bstatus & 0x7F;
+ if (down_stream_devices == 0) {
+ /*
+ * If no downstream devices are attached to the repeater
+ * then part II fails.
+ * todo: The other approach would be to continue PART II.
+ */
+ DEV_ERR("%s: %s: No downstream devices\n", __func__,
+ HDCP_STATE_NAME);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ /*
+ * HDCP Compliance 1B-05:
+ * Check if no. of devices connected to repeater
+ * exceed max_devices_connected from bit 7 of Bstatus.
+ */
+ max_devs_exceeded = (bstatus & BIT(7)) >> 7;
+ if (max_devs_exceeded == 0x01) {
+ DEV_ERR("%s: %s: no. of devs connected exceeds max allowed",
+ __func__, HDCP_STATE_NAME);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ /*
+ * HDCP Compliance 1B-06:
+ * Check if no. of cascade connected to repeater
+ * exceed max_cascade_connected from bit 11 of Bstatus.
+ */
+ max_cascade_exceeded = (bstatus & BIT(11)) >> 11;
+ if (max_cascade_exceeded == 0x01) {
+ DEV_ERR("%s: %s: no. of cascade conn exceeds max allowed",
+ __func__, HDCP_STATE_NAME);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ /*
+ * Read KSV FIFO over DDC
+ * Key Slection vector FIFO Used to pull downstream KSVs
+ * from HDCP Repeaters.
+ * All bytes (DEVICE_COUNT * 5) must be read in a single,
+ * auto incrementing access.
+ * All bytes read as 0x00 for HDCP Receivers that are not
+ * HDCP Repeaters (REPEATER == 0).
+ */
+ ksv_bytes = 5 * down_stream_devices;
+ memset(&ddc_data, 0, sizeof(ddc_data));
+ ddc_data.dev_addr = 0x74;
+ ddc_data.offset = 0x43;
+ ddc_data.data_buf = ksv_fifo;
+ ddc_data.data_len = ksv_bytes;
+ ddc_data.request_len = ksv_bytes;
+ ddc_data.retry = 5;
+ ddc_data.what = "KSV FIFO";
+ ddc_data.no_align = true;
+ cnt = 0;
+ do {
+ rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl, &ddc_data);
+ if (rc) {
+ DEV_ERR("%s: %s: KSV FIFO read failed\n", __func__,
+ HDCP_STATE_NAME);
+ /*
+ * HDCP Compliace Test case 1B-01:
+ * Wait here until all the ksv bytes have been
+ * read from the KSV FIFO register.
+ */
+ msleep(25);
+ } else {
+ break;
+ }
+ cnt++;
+ } while (cnt != 20);
+
+ if (cnt == 20)
+ goto error;
+
+ rc = hdmi_hdcp_transfer_v_h(hdcp_ctrl);
+ if (rc)
+ goto error;
+
+ /*
+ * Write KSV FIFO to HDCP_SHA_DATA.
+ * This is done 1 byte at time starting with the LSB.
+ * On the very last byte write, the HDCP_SHA_DATA_DONE bit[0]
+ */
+
+ /* First, reset SHA engine */
+ DSS_REG_W(io, HDMI_HDCP_SHA_CTRL, 1);
+ /* Next, enable SHA engine, SEL=DIGA_HDCP */
+ DSS_REG_W(io, HDMI_HDCP_SHA_CTRL, 0);
+
+ for (i = 0; i < ksv_bytes - 1; i++) {
+ /* Write KSV byte and do not set DONE bit[0] */
+ DSS_REG_W_ND(io, HDMI_HDCP_SHA_DATA, ksv_fifo[i] << 16);
+
+ /*
+ * Once 64 bytes have been written, we need to poll for
+ * HDCP_SHA_BLOCK_DONE before writing any further
+ */
+ if (i && !((i + 1) % 64)) {
+ timeout_count = 100;
+ while (!(DSS_REG_R(io, HDMI_HDCP_SHA_STATUS) & BIT(0))
+ && (--timeout_count)) {
+ DEV_DBG("%s: %s: Wrote 64 bytes KVS FIFO\n",
+ __func__, HDCP_STATE_NAME);
+ DEV_DBG("%s: %s: HDCP_SHA_STATUS=%08x\n",
+ __func__, HDCP_STATE_NAME,
+ DSS_REG_R(io, HDMI_HDCP_SHA_STATUS));
+ msleep(20);
+ }
+ if (!timeout_count) {
+ rc = -ETIMEDOUT;
+ DEV_ERR("%s: %s: Write KSV FIFO timedout",
+ __func__, HDCP_STATE_NAME);
+ goto error;
+ }
+ }
+
+ }
+
+ /* Write l to DONE bit[0] */
+ DSS_REG_W_ND(io, HDMI_HDCP_SHA_DATA,
+ (ksv_fifo[ksv_bytes - 1] << 16) | 0x1);
+
+ /* Now wait for HDCP_SHA_COMP_DONE */
+ timeout_count = 100;
+ while ((0x10 != (DSS_REG_R(io, HDMI_HDCP_SHA_STATUS)
+ & 0xFFFFFF10)) && --timeout_count)
+ msleep(20);
+ if (!timeout_count) {
+ rc = -ETIMEDOUT;
+ DEV_ERR("%s: %s: SHA computation timedout", __func__,
+ HDCP_STATE_NAME);
+ goto error;
+ }
+
+ /* Wait for V_MATCHES */
+ timeout_count = 100;
+ link0_status = DSS_REG_R(io, HDMI_HDCP_LINK0_STATUS);
+ while (((link0_status & BIT(20)) != BIT(20)) && --timeout_count) {
+ DEV_DBG("%s: %s: Waiting for V_MATCHES(%d). l0_status=0x%08x\n",
+ __func__, HDCP_STATE_NAME, timeout_count, link0_status);
+ msleep(20);
+ link0_status = DSS_REG_R(io, HDMI_HDCP_LINK0_STATUS);
+ }
+ if (!timeout_count) {
+ rc = -ETIMEDOUT;
+ DEV_ERR("%s: %s: HDCP V Match timedout", __func__,
+ HDCP_STATE_NAME);
+ goto error;
+ }
+
+error:
+ if (rc)
+ DEV_ERR("%s: %s: Authentication Part II failed\n", __func__,
+ HDCP_STATE_NAME);
+ else
+ DEV_INFO("%s: %s: Authentication Part II successful\n",
+ __func__, HDCP_STATE_NAME);
+ return rc;
+} /* hdmi_hdcp_authentication_part2 */
+
+static void hdmi_hdcp_timer(unsigned long data)
+{
+ struct hdmi_hdcp_ctrl *hdcp_ctrl = (struct hdmi_hdcp_ctrl *)data;
+
+ if (!hdcp_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ if (HDCP_STATE_AUTHENTICATING == hdcp_ctrl->hdcp_state) {
+ DEV_DBG("%s: %s: Queuing work to start HDCP authentication",
+ __func__, HDCP_STATE_NAME);
+ queue_work(hdcp_ctrl->init_data.workq,
+ &hdcp_ctrl->hdcp_auth_work);
+ } else {
+ DEV_DBG("%s: %s: Invalid state\n", __func__, HDCP_STATE_NAME);
+ }
+} /* hdmi_hdcp_timer */
+
+static void hdmi_hdcp_int_work(struct work_struct *work)
+{
+ struct hdmi_hdcp_ctrl *hdcp_ctrl = container_of(work,
+ struct hdmi_hdcp_ctrl, hdcp_int_work);
+
+ if (!hdcp_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ mutex_lock(hdcp_ctrl->init_data.mutex);
+ hdcp_ctrl->hdcp_state = HDCP_STATE_AUTH_FAIL;
+ mutex_unlock(hdcp_ctrl->init_data.mutex);
+
+ if (hdcp_ctrl->init_data.notify_status) {
+ hdcp_ctrl->init_data.notify_status(
+ hdcp_ctrl->init_data.cb_data,
+ hdcp_ctrl->hdcp_state);
+ }
+} /* hdmi_hdcp_int_work */
+
+static void hdmi_hdcp_auth_work(struct work_struct *work)
+{
+ int rc;
+ struct hdmi_hdcp_ctrl *hdcp_ctrl = container_of(work,
+ struct hdmi_hdcp_ctrl, hdcp_auth_work);
+
+ if (!hdcp_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ if (HDCP_STATE_AUTHENTICATING != hdcp_ctrl->hdcp_state) {
+ DEV_DBG("%s: %s: invalid state. returning\n", __func__,
+ HDCP_STATE_NAME);
+ return;
+ }
+
+ rc = hdmi_hdcp_authentication_part1(hdcp_ctrl);
+ if (rc) {
+ DEV_DBG("%s: %s: HDCP Auth Part I failed\n", __func__,
+ HDCP_STATE_NAME);
+ goto error;
+ }
+
+ rc = hdmi_hdcp_authentication_part2(hdcp_ctrl);
+ if (rc) {
+ DEV_DBG("%s: %s: HDCP Auth Part II failed\n", __func__,
+ HDCP_STATE_NAME);
+ goto error;
+ }
+
+error:
+ /*
+ * Ensure that the state did not change during authentication.
+ * If it did, it means that deauthenticate/reauthenticate was
+ * called. In that case, this function need not notify HDMI Tx
+ * of the result
+ */
+ mutex_lock(hdcp_ctrl->init_data.mutex);
+ if (HDCP_STATE_AUTHENTICATING == hdcp_ctrl->hdcp_state) {
+ if (rc)
+ hdcp_ctrl->hdcp_state = HDCP_STATE_AUTH_FAIL;
+ else
+ hdcp_ctrl->hdcp_state = HDCP_STATE_AUTHENTICATED;
+ mutex_unlock(hdcp_ctrl->init_data.mutex);
+
+ /* Notify HDMI Tx controller of the result */
+ DEV_DBG("%s: %s: Notifying HDMI Tx of auth result\n",
+ __func__, HDCP_STATE_NAME);
+ if (hdcp_ctrl->init_data.notify_status) {
+ hdcp_ctrl->init_data.notify_status(
+ hdcp_ctrl->init_data.cb_data,
+ hdcp_ctrl->hdcp_state);
+ }
+ } else {
+ DEV_DBG("%s: %s: HDCP state changed during authentication\n",
+ __func__, HDCP_STATE_NAME);
+ mutex_unlock(hdcp_ctrl->init_data.mutex);
+ }
+ return;
+} /* hdmi_hdcp_auth_work */
+
+int hdmi_hdcp_authenticate(void *input)
+{
+ struct hdmi_hdcp_ctrl *hdcp_ctrl = (struct hdmi_hdcp_ctrl *)input;
+
+ if (!hdcp_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ if (HDCP_STATE_INACTIVE != hdcp_ctrl->hdcp_state) {
+ DEV_DBG("%s: %s: already active or activating. returning\n",
+ __func__, HDCP_STATE_NAME);
+ return 0;
+ }
+
+ DEV_DBG("%s: %s: Queuing work to start HDCP authentication", __func__,
+ HDCP_STATE_NAME);
+ mutex_lock(hdcp_ctrl->init_data.mutex);
+ hdcp_ctrl->hdcp_state = HDCP_STATE_AUTHENTICATING;
+ mutex_unlock(hdcp_ctrl->init_data.mutex);
+ queue_work(hdcp_ctrl->init_data.workq, &hdcp_ctrl->hdcp_auth_work);
+
+ return 0;
+} /* hdmi_hdcp_authenticate */
+
+int hdmi_hdcp_reauthenticate(void *input)
+{
+ struct hdmi_hdcp_ctrl *hdcp_ctrl = (struct hdmi_hdcp_ctrl *)input;
+ struct dss_io_data *io;
+
+ if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ io = hdcp_ctrl->init_data.core_io;
+
+
+ if (HDCP_STATE_AUTH_FAIL != hdcp_ctrl->hdcp_state) {
+ DEV_DBG("%s: %s: invalid state. returning\n", __func__,
+ HDCP_STATE_NAME);
+ return 0;
+ }
+
+ /*
+ * Disable HPD circuitry.
+ * This is needed to reset the HDCP cipher engine so that when we
+ * attempt a re-authentication, HW would clear the AN0_READY and
+ * AN1_READY bits in HDMI_HDCP_LINK0_STATUS register
+ */
+ DSS_REG_W(io, HDMI_HPD_CTRL, DSS_REG_R(hdcp_ctrl->init_data.core_io,
+ HDMI_HPD_CTRL) & ~BIT(28));
+
+ /* Disable HDCP interrupts */
+ DSS_REG_W(io, HDMI_HDCP_INT_CTRL, 0);
+
+ DSS_REG_W(io, HDMI_HDCP_RESET, BIT(0));
+
+ /* Disable encryption and disable the HDCP block */
+ DSS_REG_W(io, HDMI_HDCP_CTRL, 0);
+
+ /* Enable HPD circuitry */
+ DSS_REG_W(hdcp_ctrl->init_data.core_io, HDMI_HPD_CTRL,
+ DSS_REG_R(hdcp_ctrl->init_data.core_io,
+ HDMI_HPD_CTRL) | BIT(28));
+
+ /* Restart authentication attempt */
+ DEV_DBG("%s: %s: Scheduling timer to start HDCP authentication",
+ __func__, HDCP_STATE_NAME);
+ mutex_lock(hdcp_ctrl->init_data.mutex);
+ hdcp_ctrl->hdcp_state = HDCP_STATE_AUTHENTICATING;
+ mutex_unlock(hdcp_ctrl->init_data.mutex);
+ mod_timer(&hdcp_ctrl->hdcp_timer, jiffies + HZ/2);
+
+ return 0;
+} /* hdmi_hdcp_reauthenticate */
+
+void hdmi_hdcp_off(void *input)
+{
+ struct hdmi_hdcp_ctrl *hdcp_ctrl = (struct hdmi_hdcp_ctrl *)input;
+ struct dss_io_data *io;
+ int rc = 0;
+
+ if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ io = hdcp_ctrl->init_data.core_io;
+
+ if (HDCP_STATE_INACTIVE == hdcp_ctrl->hdcp_state) {
+ DEV_DBG("%s: %s: inactive. returning\n", __func__,
+ HDCP_STATE_NAME);
+ return;
+ }
+
+ /*
+ * Need to set the state to inactive here so that any ongoing
+ * reauth works will know that the HDCP session has been turned off
+ */
+ mutex_lock(hdcp_ctrl->init_data.mutex);
+ hdcp_ctrl->hdcp_state = HDCP_STATE_INACTIVE;
+ mutex_unlock(hdcp_ctrl->init_data.mutex);
+
+ /* Disable HDCP interrupts */
+ DSS_REG_W(io, HDMI_HDCP_INT_CTRL, 0);
+
+ /*
+ * Cancel any pending auth/reauth attempts.
+ * If one is ongoing, this will wait for it to finish.
+ * No more reauthentiaction attempts will be scheduled since we
+ * set the currect state to inactive.
+ */
+ rc = del_timer_sync(&hdcp_ctrl->hdcp_timer);
+ if (rc)
+ DEV_DBG("%s: %s: Deleted hdcp reauth timer\n", __func__,
+ HDCP_STATE_NAME);
+ rc = cancel_work_sync(&hdcp_ctrl->hdcp_auth_work);
+ if (rc)
+ DEV_DBG("%s: %s: Deleted hdcp auth work\n", __func__,
+ HDCP_STATE_NAME);
+ rc = cancel_work_sync(&hdcp_ctrl->hdcp_int_work);
+ if (rc)
+ DEV_DBG("%s: %s: Deleted hdcp int work\n", __func__,
+ HDCP_STATE_NAME);
+
+ DSS_REG_W(io, HDMI_HDCP_RESET, BIT(0));
+
+ /* Disable encryption and disable the HDCP block */
+ DSS_REG_W(io, HDMI_HDCP_CTRL, 0);
+
+ DEV_DBG("%s: %s: HDCP: Off\n", __func__, HDCP_STATE_NAME);
+} /* hdmi_hdcp_off */
+
+int hdmi_hdcp_isr(void *input)
+{
+ struct hdmi_hdcp_ctrl *hdcp_ctrl = (struct hdmi_hdcp_ctrl *)input;
+ int rc = 0;
+ struct dss_io_data *io;
+ u32 hdcp_int_val;
+
+ if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ io = hdcp_ctrl->init_data.core_io;
+
+ /* Ignore HDCP interrupts if HDCP is disabled */
+ if (HDCP_STATE_INACTIVE == hdcp_ctrl->hdcp_state)
+ return 0;
+
+ hdcp_int_val = DSS_REG_R(io, HDMI_HDCP_INT_CTRL);
+ if (hdcp_int_val & BIT(0)) {
+ /* AUTH_SUCCESS_INT */
+ DSS_REG_W(io, HDMI_HDCP_INT_CTRL, (hdcp_int_val | BIT(1)));
+ DEV_INFO("%s: %s: AUTH_SUCCESS_INT received\n", __func__,
+ HDCP_STATE_NAME);
+ if (HDCP_STATE_AUTHENTICATING == hdcp_ctrl->hdcp_state)
+ complete_all(&hdcp_ctrl->r0_checked);
+ }
+
+ if (hdcp_int_val & BIT(4)) {
+ /* AUTH_FAIL_INT */
+ u32 link_status = DSS_REG_R(io, HDMI_HDCP_LINK0_STATUS);
+ DSS_REG_W(io, HDMI_HDCP_INT_CTRL, (hdcp_int_val | BIT(5)));
+ DEV_INFO("%s: %s: AUTH_FAIL_INT rcvd, LINK0_STATUS=0x%08x\n",
+ __func__, HDCP_STATE_NAME, link_status);
+ if (HDCP_STATE_AUTHENTICATED == hdcp_ctrl->hdcp_state) {
+ /* Inform HDMI Tx of the failure */
+ queue_work(hdcp_ctrl->init_data.workq,
+ &hdcp_ctrl->hdcp_int_work);
+ /* todo: print debug log with auth fail reason */
+ } else if (HDCP_STATE_AUTHENTICATING == hdcp_ctrl->hdcp_state) {
+ complete_all(&hdcp_ctrl->r0_checked);
+ }
+
+ /* Clear AUTH_FAIL_INFO as well */
+ DSS_REG_W(io, HDMI_HDCP_INT_CTRL, (hdcp_int_val | BIT(7)));
+ }
+
+ if (hdcp_int_val & BIT(8)) {
+ /* DDC_XFER_REQ_INT */
+ DSS_REG_W(io, HDMI_HDCP_INT_CTRL, (hdcp_int_val | BIT(9)));
+ DEV_INFO("%s: %s: DDC_XFER_REQ_INT received\n", __func__,
+ HDCP_STATE_NAME);
+ }
+
+ if (hdcp_int_val & BIT(12)) {
+ /* DDC_XFER_DONE_INT */
+ DSS_REG_W(io, HDMI_HDCP_INT_CTRL, (hdcp_int_val | BIT(13)));
+ DEV_INFO("%s: %s: DDC_XFER_DONE received\n", __func__,
+ HDCP_STATE_NAME);
+ }
+
+error:
+ return rc;
+} /* hdmi_hdcp_isr */
+
+void hdmi_hdcp_deinit(void *input)
+{
+ struct hdmi_hdcp_ctrl *hdcp_ctrl = (struct hdmi_hdcp_ctrl *)input;
+
+ if (!hdcp_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ del_timer_sync(&hdcp_ctrl->hdcp_timer);
+ kfree(hdcp_ctrl);
+} /* hdmi_hdcp_deinit */
+
+void *hdmi_hdcp_init(struct hdmi_hdcp_init_data *init_data)
+{
+ struct hdmi_hdcp_ctrl *hdcp_ctrl = NULL;
+
+ if (!init_data || !init_data->core_io || !init_data->qfprom_io ||
+ !init_data->mutex || !init_data->ddc_ctrl ||
+ !init_data->notify_status || !init_data->workq ||
+ !init_data->cb_data) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ goto error;
+ }
+
+ hdcp_ctrl = kzalloc(sizeof(*hdcp_ctrl), GFP_KERNEL);
+ if (!hdcp_ctrl) {
+ DEV_ERR("%s: Out of memory\n", __func__);
+ goto error;
+ }
+
+ hdcp_ctrl->init_data = *init_data;
+
+ INIT_WORK(&hdcp_ctrl->hdcp_auth_work, hdmi_hdcp_auth_work);
+ INIT_WORK(&hdcp_ctrl->hdcp_int_work, hdmi_hdcp_int_work);
+
+ init_timer(&hdcp_ctrl->hdcp_timer);
+ hdcp_ctrl->hdcp_timer.function = hdmi_hdcp_timer;
+ hdcp_ctrl->hdcp_timer.data = (u32)hdcp_ctrl;
+ hdcp_ctrl->hdcp_timer.expires = 0xffffffffL;
+
+ hdcp_ctrl->hdcp_state = HDCP_STATE_INACTIVE;
+ init_completion(&hdcp_ctrl->r0_checked);
+ DEV_DBG("%s: HDCP module initialized. HDCP_STATE=%s", __func__,
+ HDCP_STATE_NAME);
+
+error:
+ return (void *)hdcp_ctrl;
+} /* hdmi_hdcp_init */
diff --git a/drivers/video/msm/mdss/mdss_hdmi_hdcp.h b/drivers/video/msm/mdss/mdss_hdmi_hdcp.h
new file mode 100644
index 0000000..d35b2a9
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_hdmi_hdcp.h
@@ -0,0 +1,43 @@
+/* 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_HDMI_HDCP_H__
+#define __MDSS_HDMI_HDCP_H__
+
+#include "mdss_hdmi_util.h"
+
+enum hdmi_hdcp_state {
+ HDCP_STATE_INACTIVE,
+ HDCP_STATE_AUTHENTICATING,
+ HDCP_STATE_AUTHENTICATED,
+ HDCP_STATE_AUTH_FAIL
+};
+
+struct hdmi_hdcp_init_data {
+ struct dss_io_data *core_io;
+ struct dss_io_data *qfprom_io;
+ struct mutex *mutex;
+ struct workqueue_struct *workq;
+ void *cb_data;
+ void (*notify_status)(void *cb_data, enum hdmi_hdcp_state status);
+
+ struct hdmi_tx_ddc_ctrl *ddc_ctrl;
+};
+
+const char *hdcp_state_name(enum hdmi_hdcp_state hdcp_state);
+void *hdmi_hdcp_init(struct hdmi_hdcp_init_data *init_data);
+void hdmi_hdcp_deinit(void *input);
+int hdmi_hdcp_isr(void *ptr);
+int hdmi_hdcp_reauthenticate(void *input);
+int hdmi_hdcp_authenticate(void *hdcp_ctrl);
+void hdmi_hdcp_off(void *hdcp_ctrl);
+#endif /* __MDSS_HDMI_HDCP_H__ */
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index 37bbbdf..6cbde02 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -18,21 +18,23 @@
#include <linux/iopoll.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
#include <linux/types.h>
-#include <mach/msm_hdmi_audio.h>
+#include <mach/msm_hdmi_audio_codec.h>
#define REG_DUMP 0
#include "mdss_fb.h"
#include "mdss_hdmi_tx.h"
#include "mdss_hdmi_edid.h"
+#include "mdss_hdmi_hdcp.h"
#include "mdss.h"
#include "mdss_panel.h"
#define DRV_NAME "hdmi-tx"
#define COMPATIBLE_NAME "qcom,hdmi-tx"
-#define DEFAULT_VIDEO_RESOLUTION HDMI_VFRMT_1920x1080p60_16_9;
+#define DEFAULT_VIDEO_RESOLUTION HDMI_VFRMT_1920x1080p60_16_9
/* HDMI PHY/PLL bit field macros */
#define SW_RESET BIT(2)
@@ -45,6 +47,26 @@
((d & 0xff) + ((d >> 8) & 0xff) + \
((d >> 16) & 0xff) + ((d >> 24) & 0xff))
+/* Enable HDCP by default */
+static bool hdcp_feature_on = true;
+
+/* Supported HDMI Audio channels */
+#define MSM_HDMI_AUDIO_CHANNEL_2 2
+#define MSM_HDMI_AUDIO_CHANNEL_4 4
+#define MSM_HDMI_AUDIO_CHANNEL_6 6
+#define MSM_HDMI_AUDIO_CHANNEL_8 8
+
+enum msm_hdmi_supported_audio_sample_rates {
+ AUDIO_SAMPLE_RATE_32KHZ,
+ AUDIO_SAMPLE_RATE_44_1KHZ,
+ AUDIO_SAMPLE_RATE_48KHZ,
+ AUDIO_SAMPLE_RATE_88_2KHZ,
+ AUDIO_SAMPLE_RATE_96KHZ,
+ AUDIO_SAMPLE_RATE_176_4KHZ,
+ AUDIO_SAMPLE_RATE_192KHZ,
+ AUDIO_SAMPLE_RATE_MAX
+};
+
/* parameters for clock regeneration */
struct hdmi_tx_audio_acr {
u32 n;
@@ -53,7 +75,7 @@
struct hdmi_tx_audio_acr_arry {
u32 pclk;
- struct hdmi_tx_audio_acr lut[HDMI_SAMPLE_RATE_MAX];
+ struct hdmi_tx_audio_acr lut[AUDIO_SAMPLE_RATE_MAX];
};
static int hdmi_tx_sysfs_enable_hpd(struct hdmi_tx_ctrl *hdmi_ctrl, int on);
@@ -91,35 +113,46 @@
}
} /* hdmi_pm_name */
-static u8 hdmi_tx_avi_iframe_lut[][16] = {
-/* 480p60 480i60 576p50 576i50 720p60 720p50 1080p60 1080i60 1080p50
- 1080i50 1080p24 1080p30 1080p25 640x480p 480p60_16_9 576p50_4_3 */
- {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
- 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, /*00*/
- {0x18, 0x18, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
- 0x28, 0x28, 0x28, 0x28, 0x18, 0x28, 0x18}, /*01*/
- {0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
- 0x04, 0x04, 0x04, 0x04, 0x88, 0x00, 0x04}, /*02*/
- {0x02, 0x06, 0x11, 0x15, 0x04, 0x13, 0x10, 0x05, 0x1F,
- 0x14, 0x20, 0x22, 0x21, 0x01, 0x03, 0x11}, /*03*/
- {0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*04*/
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*05*/
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*06*/
- {0xE1, 0xE1, 0x41, 0x41, 0xD1, 0xd1, 0x39, 0x39, 0x39,
- 0x39, 0x39, 0x39, 0x39, 0xe1, 0xE1, 0x41}, /*07*/
- {0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x04, 0x04, 0x04,
- 0x04, 0x04, 0x04, 0x04, 0x01, 0x01, 0x02}, /*08*/
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*09*/
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*10*/
- {0xD1, 0xD1, 0xD1, 0xD1, 0x01, 0x01, 0x81, 0x81, 0x81,
- 0x81, 0x81, 0x81, 0x81, 0x81, 0xD1, 0xD1}, /*11*/
- {0x02, 0x02, 0x02, 0x02, 0x05, 0x05, 0x07, 0x07, 0x07,
- 0x07, 0x07, 0x07, 0x07, 0x02, 0x02, 0x02} /*12*/
+static u8 hdmi_tx_avi_iframe_lut[][20] = {
+ {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x10}, /*00*/
+ {0x18, 0x18, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+ 0x28, 0x28, 0x28, 0x28, 0x18, 0x28, 0x18, 0x28, 0x28,
+ 0x28, 0x28}, /*01*/
+ {0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x88, 0x00, 0x04, 0x04, 0x04,
+ 0x04, 0x04}, /*02*/
+ {0x02, 0x06, 0x11, 0x15, 0x04, 0x13, 0x10, 0x05, 0x1F,
+ 0x14, 0x20, 0x22, 0x21, 0x01, 0x03, 0x11, 0x00, 0x00,
+ 0x00, 0x00}, /*03*/
+ {0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00}, /*04*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00}, /*05*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00}, /*06*/
+ {0xE1, 0xE1, 0x41, 0x41, 0xD1, 0xd1, 0x39, 0x39, 0x39,
+ 0x39, 0x39, 0x39, 0x39, 0xe1, 0xE1, 0x41, 0x71, 0x71,
+ 0x71, 0x71}, /*07*/
+ {0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x01, 0x01, 0x02, 0x08, 0x08,
+ 0x08, 0x08}, /*08*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00}, /*09*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00}, /*10*/
+ {0xD1, 0xD1, 0xD1, 0xD1, 0x01, 0x01, 0x81, 0x81, 0x81,
+ 0x81, 0x81, 0x81, 0x81, 0x81, 0xD1, 0xD1, 0x01, 0x01,
+ 0x01, 0x01}, /*11*/
+ {0x02, 0x02, 0x02, 0x02, 0x05, 0x05, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x02, 0x02, 0x02, 0x0F, 0x0F,
+ 0x0F, 0x10} /*12*/
};
/* Audio constants lookup table for hdmi_tx_audio_acr_setup */
@@ -141,6 +174,10 @@
{148500, {{4096, 148500}, {6272, 165000}, {6144, 148500},
{12544, 165000}, {12288, 148500}, {25088, 165000},
{24576, 148500} } },
+ /* 297.000MHz */
+ {297000, {{3072, 222750}, {4704, 247500}, {5120, 247500},
+ {9408, 247500}, {10240, 247500}, {18816, 247500},
+ {20480, 247500} } },
};
const char *hdmi_tx_pm_name(enum hdmi_tx_power_module_type module)
@@ -406,10 +443,75 @@
hdmi_ctrl->kobj = NULL;
} /* hdmi_tx_sysfs_remove */
+static inline u32 hdmi_tx_is_dvi_mode(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+ return hdmi_edid_get_sink_mode(
+ hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]) ? 0 : 1;
+} /* hdmi_tx_is_dvi_mode */
+
+static inline void hdmi_tx_set_audio_switch_node(struct hdmi_tx_ctrl *hdmi_ctrl,
+ int val, bool force)
+{
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ if (!hdmi_tx_is_dvi_mode(hdmi_ctrl) &&
+ (force || (hdmi_ctrl->audio_sdev.state != val))) {
+ switch_set_state(&hdmi_ctrl->audio_sdev, val);
+ DEV_INFO("%s: hdmi_audio state switched to %d\n", __func__,
+ hdmi_ctrl->audio_sdev.state);
+ }
+} /* hdmi_tx_set_audio_switch_node */
+
+void hdmi_tx_hdcp_cb(void *ptr, enum hdmi_hdcp_state status)
+{
+ int rc = 0;
+ struct hdmi_tx_ctrl *hdmi_ctrl = (struct hdmi_tx_ctrl *)ptr;
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ DEV_DBG("%s: HDCP status=%s hpd_state=%d\n", __func__,
+ hdcp_state_name(status), hdmi_ctrl->hpd_state);
+
+ switch (status) {
+ case HDCP_STATE_AUTHENTICATED:
+ if (hdmi_ctrl->hpd_state)
+ hdmi_tx_set_audio_switch_node(hdmi_ctrl, 1, false);
+ break;
+ case HDCP_STATE_AUTH_FAIL:
+ hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0, false);
+
+ if (hdmi_ctrl->hpd_state) {
+ DEV_DBG("%s: Reauthenticating\n", __func__);
+ rc = hdmi_hdcp_reauthenticate(
+ hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP]);
+ if (rc)
+ DEV_ERR("%s: HDCP reauth failed. rc=%d\n",
+ __func__, rc);
+ } else {
+ DEV_DBG("%s: Not reauthenticating. Cable not conn\n",
+ __func__);
+ }
+
+ break;
+ case HDCP_STATE_AUTHENTICATING:
+ case HDCP_STATE_INACTIVE:
+ default:
+ break;
+ /* do nothing */
+ }
+}
+
/* Enable HDMI features */
static int hdmi_tx_init_features(struct hdmi_tx_ctrl *hdmi_ctrl)
{
struct hdmi_edid_init_data edid_init_data;
+ struct hdmi_hdcp_init_data hdcp_init_data;
if (!hdmi_ctrl) {
DEV_ERR("%s: invalid input\n", __func__);
@@ -431,6 +533,29 @@
hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID],
hdmi_ctrl->video_resolution);
+ /* Initialize HDCP feature */
+ if (hdmi_ctrl->present_hdcp) {
+ hdcp_init_data.core_io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+ hdcp_init_data.qfprom_io =
+ &hdmi_ctrl->pdata.io[HDMI_TX_QFPROM_IO];
+ hdcp_init_data.mutex = &hdmi_ctrl->mutex;
+ hdcp_init_data.ddc_ctrl = &hdmi_ctrl->ddc_ctrl;
+ hdcp_init_data.workq = hdmi_ctrl->workq;
+ hdcp_init_data.notify_status = hdmi_tx_hdcp_cb;
+ hdcp_init_data.cb_data = (void *)hdmi_ctrl;
+
+ hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP] =
+ hdmi_hdcp_init(&hdcp_init_data);
+ if (!hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP]) {
+ DEV_ERR("%s: hdmi_hdcp_init failed\n", __func__);
+ hdmi_edid_deinit(hdmi_ctrl->feature_data[
+ HDMI_TX_FEAT_EDID]);
+ hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID] = NULL;
+ return -EPERM;
+ }
+
+ DEV_DBG("%s: HDCP feature initialized\n", __func__);
+ }
return 0;
} /* hdmi_tx_init_features */
@@ -440,12 +565,6 @@
return DSS_REG_R_ND(io, HDMI_CTRL) & BIT(0);
} /* hdmi_tx_is_controller_on */
-static inline u32 hdmi_tx_is_dvi_mode(struct hdmi_tx_ctrl *hdmi_ctrl)
-{
- return hdmi_edid_get_sink_mode(
- hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]) ? 0 : 1;
-} /* hdmi_tx_is_dvi_mode */
-
static int hdmi_tx_init_panel_info(uint32_t resolution,
struct mdss_panel_info *pinfo)
{
@@ -482,9 +601,11 @@
} /* hdmi_tx_init_panel_info */
/* Table indicating the video format supported by the HDMI TX Core */
-/* Valid Pixel-Clock rates: 25.2MHz, 27MHz, 27.03MHz, 74.25MHz, 148.5MHz */
+/* Valid pclk rates (Mhz): 25.2, 27, 27.03, 74.25, 148.5, 268.5, 297 */
static void hdmi_tx_setup_video_mode_lut(void)
{
+ hdmi_init_supported_video_timings();
+
hdmi_set_supported_mode(HDMI_VFRMT_640x480p60_4_3);
hdmi_set_supported_mode(HDMI_VFRMT_720x480p60_4_3);
hdmi_set_supported_mode(HDMI_VFRMT_720x480p60_16_9);
@@ -502,6 +623,11 @@
hdmi_set_supported_mode(HDMI_VFRMT_1920x1080p50_16_9);
hdmi_set_supported_mode(HDMI_VFRMT_1920x1080i60_16_9);
hdmi_set_supported_mode(HDMI_VFRMT_1920x1080p60_16_9);
+ hdmi_set_supported_mode(HDMI_VFRMT_2560x1600p60_16_9);
+ hdmi_set_supported_mode(HDMI_VFRMT_3840x2160p30_16_9);
+ hdmi_set_supported_mode(HDMI_VFRMT_3840x2160p25_16_9);
+ hdmi_set_supported_mode(HDMI_VFRMT_3840x2160p24_16_9);
+ hdmi_set_supported_mode(HDMI_VFRMT_4096x2160p24_16_9);
} /* hdmi_tx_setup_video_mode_lut */
static int hdmi_tx_read_sink_info(struct hdmi_tx_ctrl *hdmi_ctrl)
@@ -534,7 +660,6 @@
static void hdmi_tx_hpd_int_work(struct work_struct *work)
{
struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
- struct dss_io_data *io = NULL;
hdmi_ctrl = container_of(work, struct hdmi_tx_ctrl, hpd_int_work);
if (!hdmi_ctrl || !hdmi_ctrl->hpd_initialized) {
@@ -542,16 +667,8 @@
return;
}
- io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
- if (!io->base) {
- DEV_ERR("%s: Core io is not initialized\n", __func__);
- return;
- }
-
DEV_DBG("%s: Got HPD interrupt\n", __func__);
- hdmi_ctrl->hpd_state =
- (DSS_REG_R(io, HDMI_HPD_INT_STATUS) & BIT(1)) >> 1;
if (hdmi_ctrl->hpd_state) {
hdmi_tx_read_sink_info(hdmi_ctrl);
DEV_INFO("HDMI HPD: sense CONNECTED: send ONLINE\n");
@@ -571,15 +688,22 @@
complete_all(&hdmi_ctrl->hpd_done);
} /* hdmi_tx_hpd_int_work */
-static int hdmi_tx_check_capability(struct dss_io_data *io)
+static int hdmi_tx_check_capability(struct hdmi_tx_ctrl *hdmi_ctrl)
{
u32 hdmi_disabled, hdcp_disabled;
+ struct dss_io_data *io = NULL;
- if (!io) {
+ if (!hdmi_ctrl) {
DEV_ERR("%s: invalid input\n", __func__);
return -EINVAL;
}
+ io = &hdmi_ctrl->pdata.io[HDMI_TX_QFPROM_IO];
+ if (!io->base) {
+ DEV_ERR("%s: QFPROM io is not initialized\n", __func__);
+ return -EINVAL;
+ }
+
hdcp_disabled = DSS_REG_R_ND(io,
QFPROM_RAW_FEAT_CONFIG_ROW0_LSB) & BIT(31);
@@ -594,8 +718,13 @@
return -ENODEV;
}
- if (hdcp_disabled)
+ if (hdcp_disabled) {
+ hdmi_ctrl->present_hdcp = 0;
DEV_WARN("%s: HDCP disabled\n", __func__);
+ } else {
+ hdmi_ctrl->present_hdcp = 1;
+ DEV_DBG("%s: Device is HDCP enabled\n", __func__);
+ }
return 0;
} /* hdmi_tx_check_capability */
@@ -636,7 +765,7 @@
return 0;
} /* hdmi_tx_set_video_fmt */
-static void hdmi_tx_video_setup(struct hdmi_tx_ctrl *hdmi_ctrl,
+static int hdmi_tx_video_setup(struct hdmi_tx_ctrl *hdmi_ctrl,
int video_format)
{
u32 total_v = 0;
@@ -652,47 +781,53 @@
if (timing == NULL) {
DEV_ERR("%s: video format not supported: %d\n", __func__,
video_format);
- return;
+ return -EPERM;
}
if (!hdmi_ctrl) {
DEV_ERR("%s: invalid input\n", __func__);
- return;
+ return -EINVAL;
}
io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
if (!io->base) {
DEV_ERR("%s: Core io is not initialized\n", __func__);
- return;
+ return -EPERM;
}
total_h = timing->active_h + timing->front_porch_h +
timing->back_porch_h + timing->pulse_width_h - 1;
total_v = timing->active_v + timing->front_porch_v +
timing->back_porch_v + timing->pulse_width_v - 1;
- DSS_REG_W(io, HDMI_TOTAL,
- ((total_v << 16) & 0x0FFF0000) |
- ((total_h << 0) & 0x00000FFF));
+ if (((total_v << 16) & 0xE0000000) || (total_h & 0xFFFFE000)) {
+ DEV_ERR("%s: total v=%d or h=%d is larger than supported\n",
+ __func__, total_v, total_h);
+ return -EPERM;
+ }
+ DSS_REG_W(io, HDMI_TOTAL, (total_v << 16) | (total_h << 0));
start_h = timing->back_porch_h + timing->pulse_width_h;
end_h = (total_h + 1) - timing->front_porch_h;
- DSS_REG_W(io, HDMI_ACTIVE_H,
- ((end_h << 16) & 0x0FFF0000) |
- ((start_h << 0) & 0x00000FFF));
+ if (((end_h << 16) & 0xE0000000) || (start_h & 0xFFFFE000)) {
+ DEV_ERR("%s: end_h=%d or start_h=%d is larger than supported\n",
+ __func__, end_h, start_h);
+ return -EPERM;
+ }
+ DSS_REG_W(io, HDMI_ACTIVE_H, (end_h << 16) | (start_h << 0));
start_v = timing->back_porch_v + timing->pulse_width_v - 1;
end_v = total_v - timing->front_porch_v;
- DSS_REG_W(io, HDMI_ACTIVE_V,
- ((end_v << 16) & 0x0FFF0000) |
- ((start_v << 0) & 0x00000FFF));
+ if (((end_v << 16) & 0xE0000000) || (start_v & 0xFFFFE000)) {
+ DEV_ERR("%s: end_v=%d or start_v=%d is larger than supported\n",
+ __func__, end_v, start_v);
+ return -EPERM;
+ }
+ DSS_REG_W(io, HDMI_ACTIVE_V, (end_v << 16) | (start_v << 0));
if (timing->interlaced) {
- DSS_REG_W(io, HDMI_V_TOTAL_F2,
- ((total_v + 1) << 0) & 0x00000FFF);
-
+ DSS_REG_W(io, HDMI_V_TOTAL_F2, (total_v + 1) << 0);
DSS_REG_W(io, HDMI_ACTIVE_V_F2,
- (((start_v + 1) << 0) & 0x00000FFF) |
- (((end_v + 1) << 16) & 0x0FFF0000));
+ ((end_v + 1) << 16) | ((start_v + 1) << 0));
} else {
DSS_REG_W(io, HDMI_V_TOTAL_F2, 0);
DSS_REG_W(io, HDMI_ACTIVE_V_F2, 0);
@@ -702,6 +837,8 @@
((timing->interlaced << 31) & 0x80000000) |
((timing->active_low_h << 29) & 0x20000000) |
((timing->active_low_v << 28) & 0x10000000));
+
+ return 0;
} /* hdmi_tx_video_setup */
static void hdmi_tx_set_avi_infoframe(struct hdmi_tx_ctrl *hdmi_ctrl)
@@ -772,6 +909,18 @@
case HDMI_VFRMT_720x576p50_4_3:
mode = 15;
break;
+ case HDMI_VFRMT_3840x2160p30_16_9:
+ mode = 16;
+ break;
+ case HDMI_VFRMT_3840x2160p25_16_9:
+ mode = 17;
+ break;
+ case HDMI_VFRMT_3840x2160p24_16_9:
+ mode = 18;
+ break;
+ case HDMI_VFRMT_4096x2160p24_16_9:
+ mode = 19;
+ break;
default:
DEV_INFO("%s: mode %d not supported\n", __func__,
hdmi_ctrl->video_resolution);
@@ -846,12 +995,87 @@
regVal = regVal << 8 | avi_iframe[14];
DSS_REG_W(io, HDMI_AVI_INFO3, regVal);
- /* 0x3 for AVI InfFrame enable (every frame) */
+ /* AVI InfFrame enable (every frame) */
DSS_REG_W(io, HDMI_INFOFRAME_CTRL0,
- DSS_REG_R(io, HDMI_INFOFRAME_CTRL0) |
- 0x00000003L);
+ DSS_REG_R(io, HDMI_INFOFRAME_CTRL0) | BIT(1) | BIT(0));
} /* hdmi_tx_set_avi_infoframe */
+/* todo: add 3D support */
+static void hdmi_tx_set_vendor_specific_infoframe(
+ struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+ int i;
+ u8 vs_iframe[9]; /* two header + length + 6 data */
+ u32 sum, reg_val;
+ u32 hdmi_vic, hdmi_video_format;
+ struct dss_io_data *io = NULL;
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+ if (!io->base) {
+ DEV_ERR("%s: Core io is not initialized\n", __func__);
+ return;
+ }
+
+ /* HDMI Spec 1.4a Table 8-10 */
+ vs_iframe[0] = 0x81; /* type */
+ vs_iframe[1] = 0x1; /* version */
+ vs_iframe[2] = 0x8; /* length */
+
+ vs_iframe[3] = 0x0; /* PB0: checksum */
+
+ /* PB1..PB3: 24 Bit IEEE Registration Code 00_0C_03 */
+ vs_iframe[4] = 0x03;
+ vs_iframe[5] = 0x0C;
+ vs_iframe[6] = 0x00;
+
+ hdmi_video_format = 0x1;
+ switch (hdmi_ctrl->video_resolution) {
+ case HDMI_VFRMT_3840x2160p30_16_9:
+ hdmi_vic = 0x1;
+ break;
+ case HDMI_VFRMT_3840x2160p25_16_9:
+ hdmi_vic = 0x2;
+ break;
+ case HDMI_VFRMT_3840x2160p24_16_9:
+ hdmi_vic = 0x3;
+ break;
+ case HDMI_VFRMT_4096x2160p24_16_9:
+ hdmi_vic = 0x4;
+ break;
+ default:
+ hdmi_video_format = 0x0;
+ hdmi_vic = 0x0;
+ }
+
+ /* PB4: HDMI Video Format[7:5], Reserved[4:0] */
+ vs_iframe[7] = (hdmi_video_format << 5) & 0xE0;
+
+ /* PB5: HDMI_VIC or 3D_Structure[7:4], Reserved[3:0] */
+ vs_iframe[8] = hdmi_vic;
+
+ /* compute checksum */
+ sum = 0;
+ for (i = 0; i < 9; i++)
+ sum += vs_iframe[i];
+
+ sum &= 0xFF;
+ sum = 256 - sum;
+ vs_iframe[3] = (u8)sum;
+
+ reg_val = (hdmi_vic << 16) | (vs_iframe[3] << 8) |
+ (hdmi_video_format << 5) | vs_iframe[2];
+ DSS_REG_W(io, HDMI_VENSPEC_INFO0, reg_val);
+
+ /* vendor specific info-frame enable (every frame) */
+ DSS_REG_W(io, HDMI_INFOFRAME_CTRL0,
+ DSS_REG_R(io, HDMI_INFOFRAME_CTRL0) | BIT(13) | BIT(12));
+} /* hdmi_tx_set_vendor_specific_infoframe */
+
static void hdmi_tx_set_spd_infoframe(struct hdmi_tx_ctrl *hdmi_ctrl)
{
u32 packet_header = 0;
@@ -979,12 +1203,14 @@
reg_val |= BIT(0); /* Enable the block */
if (hdmi_edid_get_sink_mode(
hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]) == 0) {
- if (hdmi_ctrl->present_hdcp)
+ if (hdmi_ctrl->hdcp_feature_on &&
+ hdmi_ctrl->present_hdcp)
/* HDMI Encryption */
reg_val |= BIT(2);
reg_val |= BIT(1);
} else {
- if (hdmi_ctrl->present_hdcp)
+ if (hdmi_ctrl->hdcp_feature_on &&
+ hdmi_ctrl->present_hdcp)
/* HDMI_Encryption_ON */
reg_val |= BIT(1) | BIT(2);
else
@@ -1300,13 +1526,13 @@
layout = (MSM_HDMI_AUDIO_CHANNEL_2 == num_of_channels) ? 0 : 1;
if (
- (HDMI_SAMPLE_RATE_192KHZ == hdmi_ctrl->audio_sample_rate) ||
- (HDMI_SAMPLE_RATE_176_4KHZ == hdmi_ctrl->audio_sample_rate)) {
+ (AUDIO_SAMPLE_RATE_192KHZ == hdmi_ctrl->audio_sample_rate) ||
+ (AUDIO_SAMPLE_RATE_176_4KHZ == hdmi_ctrl->audio_sample_rate)) {
multiplier = 4;
n >>= 2; /* divide N by 4 and use multiplier */
} else if (
- (HDMI_SAMPLE_RATE_96KHZ == hdmi_ctrl->audio_sample_rate) ||
- (HDMI_SAMPLE_RATE_88_2KHZ == hdmi_ctrl->audio_sample_rate)) {
+ (AUDIO_SAMPLE_RATE_96KHZ == hdmi_ctrl->audio_sample_rate) ||
+ (AUDIO_SAMPLE_RATE_88_2KHZ == hdmi_ctrl->audio_sample_rate)) {
multiplier = 2;
n >>= 1; /* divide N by 2 and use multiplier */
} else {
@@ -1320,9 +1546,9 @@
/* N_MULTIPLE(multiplier) */
acr_pck_ctrl_reg |= (multiplier & 7) << 16;
- if ((HDMI_SAMPLE_RATE_48KHZ == hdmi_ctrl->audio_sample_rate) ||
- (HDMI_SAMPLE_RATE_96KHZ == hdmi_ctrl->audio_sample_rate) ||
- (HDMI_SAMPLE_RATE_192KHZ == hdmi_ctrl->audio_sample_rate)) {
+ if ((AUDIO_SAMPLE_RATE_48KHZ == hdmi_ctrl->audio_sample_rate) ||
+ (AUDIO_SAMPLE_RATE_96KHZ == hdmi_ctrl->audio_sample_rate) ||
+ (AUDIO_SAMPLE_RATE_192KHZ == hdmi_ctrl->audio_sample_rate)) {
/* SELECT(3) */
acr_pck_ctrl_reg |= 3 << 4;
/* CTS_48 */
@@ -1333,9 +1559,9 @@
/* N */
DSS_REG_W(io, HDMI_ACR_48_1, n);
} else if (
- (HDMI_SAMPLE_RATE_44_1KHZ == hdmi_ctrl->audio_sample_rate) ||
- (HDMI_SAMPLE_RATE_88_2KHZ == hdmi_ctrl->audio_sample_rate) ||
- (HDMI_SAMPLE_RATE_176_4KHZ == hdmi_ctrl->audio_sample_rate)) {
+ (AUDIO_SAMPLE_RATE_44_1KHZ == hdmi_ctrl->audio_sample_rate) ||
+ (AUDIO_SAMPLE_RATE_88_2KHZ == hdmi_ctrl->audio_sample_rate) ||
+ (AUDIO_SAMPLE_RATE_176_4KHZ == hdmi_ctrl->audio_sample_rate)) {
/* SELECT(2) */
acr_pck_ctrl_reg |= 2 << 4;
/* CTS_44 */
@@ -1373,11 +1599,10 @@
return 0;
} /* hdmi_tx_audio_acr_setup */
-static int hdmi_tx_audio_info_setup(void *priv_d, bool enabled,
- u32 num_of_channels, u32 channel_allocation, u32 level_shift,
- bool down_mix)
+static int hdmi_tx_audio_iframe_setup(struct hdmi_tx_ctrl *hdmi_ctrl,
+ bool enabled, u32 num_of_channels, u32 channel_allocation,
+ u32 level_shift, bool down_mix)
{
- struct hdmi_tx_ctrl *hdmi_ctrl = (struct hdmi_tx_ctrl *)priv_d;
struct dss_io_data *io = NULL;
u32 channel_count = 1; /* Def to 2 channels -> Table 17 in CEA-D */
@@ -1422,22 +1647,15 @@
if (enabled) {
switch (num_of_channels) {
case MSM_HDMI_AUDIO_CHANNEL_2:
- channel_allocation = 0; /* Default to FR, FL */
break;
case MSM_HDMI_AUDIO_CHANNEL_4:
channel_count = 3;
- /* FC, LFE, FR, FL */
- channel_allocation = 0x3;
break;
case MSM_HDMI_AUDIO_CHANNEL_6:
channel_count = 5;
- /* RR, RL, FC, LFE, FR, FL */
- channel_allocation = 0xB;
break;
case MSM_HDMI_AUDIO_CHANNEL_8:
channel_count = 7;
- /* FRC, FLC, RR, RL, FC, LFE, FR, FL */
- channel_allocation = 0x1f;
break;
default:
DEV_ERR("%s: Unsupported num_of_channels = %u\n",
@@ -1505,8 +1723,66 @@
enabled ? "HDMI-AUDIO-ON: " : "HDMI-AUDIO-OFF: ", REG_DUMP);
return 0;
+} /* hdmi_tx_audio_iframe_setup */
+
+static int hdmi_tx_audio_info_setup(struct platform_device *pdev,
+ u32 num_of_channels, u32 channel_allocation, u32 level_shift,
+ bool down_mix)
+{
+ int rc = 0;
+ struct hdmi_tx_ctrl *hdmi_ctrl = platform_get_drvdata(pdev);
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -ENODEV;
+ }
+
+ if (hdmi_ctrl->panel_power_on) {
+ rc = hdmi_tx_audio_iframe_setup(hdmi_ctrl, true,
+ num_of_channels, channel_allocation, level_shift,
+ down_mix);
+ if (rc)
+ DEV_ERR("%s: hdmi_tx_audio_iframe_setup failed.rc=%d\n",
+ __func__, rc);
+ } else {
+ DEV_ERR("%s: Error. panel is not on.\n", __func__);
+ rc = -EPERM;
+ }
+
+ return 0;
} /* hdmi_tx_audio_info_setup */
+static int hdmi_tx_get_audio_edid_blk(struct platform_device *pdev,
+ struct msm_hdmi_audio_edid_blk *blk)
+{
+ struct hdmi_tx_ctrl *hdmi_ctrl = platform_get_drvdata(pdev);
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -ENODEV;
+ }
+
+ return hdmi_edid_get_audio_blk(
+ hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID], blk);
+} /* hdmi_tx_get_audio_edid_blk */
+
+int msm_hdmi_register_audio_codec(struct platform_device *pdev,
+ struct msm_hdmi_audio_codec_ops *ops)
+{
+ struct hdmi_tx_ctrl *hdmi_ctrl = platform_get_drvdata(pdev);
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -ENODEV;
+ }
+
+ ops->audio_info_setup = hdmi_tx_audio_info_setup;
+ ops->get_audio_edid_blk = hdmi_tx_get_audio_edid_blk;
+
+ return 0;
+} /* hdmi_tx_audio_register */
+EXPORT_SYMBOL(msm_hdmi_register_audio_codec);
+
static int hdmi_tx_audio_setup(struct hdmi_tx_ctrl *hdmi_ctrl)
{
int rc = 0;
@@ -1531,9 +1807,9 @@
return rc;
}
- rc = hdmi_tx_audio_info_setup(hdmi_ctrl, true, channels, 0, 0, false);
+ rc = hdmi_tx_audio_iframe_setup(hdmi_ctrl, true, channels, 0, 0, false);
if (rc) {
- DEV_ERR("%s: hdmi_tx_audio_info_setup failed. rc=%d\n",
+ DEV_ERR("%s: hdmi_tx_audio_iframe_setup failed. rc=%d\n",
__func__, rc);
return rc;
}
@@ -1545,7 +1821,7 @@
static void hdmi_tx_audio_off(struct hdmi_tx_ctrl *hdmi_ctrl)
{
- u32 i, status, max_reads, timeout_us, timeout_sec = 15;
+ u32 i, status, sleep_us, timeout_us, timeout_sec = 15;
struct dss_io_data *io = NULL;
if (!hdmi_ctrl) {
@@ -1562,17 +1838,17 @@
/* Check if audio engine is turned off by QDSP or not */
/* send off notification after every 1 sec for 15 seconds */
for (i = 0; i < timeout_sec; i++) {
- max_reads = 500;
- timeout_us = 1000 * 2;
+ sleep_us = 5000; /* Maximum time to sleep between two reads */
+ timeout_us = 1000 * 1000; /* Total time for condition to meet */
- if (readl_poll_timeout_noirq((io->base + HDMI_AUDIO_CFG),
+ if (readl_poll_timeout((io->base + HDMI_AUDIO_CFG),
status, ((status & BIT(0)) == 0),
- max_reads, timeout_us)) {
+ sleep_us, timeout_us)) {
DEV_ERR("%s: audio still on after %d sec. try again\n",
__func__, i+1);
- switch_set_state(&hdmi_ctrl->audio_sdev, 0);
+ hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0, true);
continue;
}
break;
@@ -1580,8 +1856,8 @@
if (i == timeout_sec)
DEV_ERR("%s: Error: cannot turn off audio engine\n", __func__);
- if (hdmi_tx_audio_info_setup(hdmi_ctrl, false, 0, 0, 0, false))
- DEV_ERR("%s: hdmi_tx_audio_info_setup failed.\n", __func__);
+ if (hdmi_tx_audio_iframe_setup(hdmi_ctrl, false, 0, 0, 0, false))
+ DEV_ERR("%s: hdmi_tx_audio_iframe_setup failed.\n", __func__);
if (hdmi_tx_audio_acr_setup(hdmi_ctrl, false, 0))
DEV_ERR("%s: hdmi_tx_audio_acr_setup failed.\n", __func__);
@@ -1610,7 +1886,13 @@
hdmi_tx_set_mode(hdmi_ctrl, true);
- hdmi_tx_video_setup(hdmi_ctrl, hdmi_ctrl->video_resolution);
+ rc = hdmi_tx_video_setup(hdmi_ctrl, hdmi_ctrl->video_resolution);
+ if (rc) {
+ DEV_ERR("%s: hdmi_tx_video_setup failed. rc=%d\n",
+ __func__, rc);
+ hdmi_tx_set_mode(hdmi_ctrl, false);
+ return rc;
+ }
if (!hdmi_tx_is_dvi_mode(hdmi_ctrl)) {
rc = hdmi_tx_audio_setup(hdmi_ctrl);
@@ -1621,16 +1903,15 @@
return rc;
}
- switch_set_state(&hdmi_ctrl->audio_sdev, 1);
- DEV_INFO("%s: hdmi_audio state switch to %d\n", __func__,
- hdmi_ctrl->audio_sdev.state);
+ if (!hdmi_ctrl->hdcp_feature_on || !hdmi_ctrl->present_hdcp)
+ hdmi_tx_set_audio_switch_node(hdmi_ctrl, 1, false);
+
+ hdmi_tx_set_avi_infoframe(hdmi_ctrl);
+ hdmi_tx_set_vendor_specific_infoframe(hdmi_ctrl);
+ hdmi_tx_set_spd_infoframe(hdmi_ctrl);
}
- hdmi_tx_set_avi_infoframe(hdmi_ctrl);
- /* todo: CONFIG_FB_MSM_HDMI_3D */
- hdmi_tx_set_spd_infoframe(hdmi_ctrl);
-
- /* todo: HDCP/CEC */
+ /* todo: CEC */
DEV_INFO("%s: HDMI Core: Initialized\n", __func__);
@@ -1689,11 +1970,13 @@
return;
}
- if (!hdmi_tx_is_dvi_mode(hdmi_ctrl)) {
- switch_set_state(&hdmi_ctrl->audio_sdev, 0);
- DEV_INFO("%s: hdmi_audio state switch to %d\n", __func__,
- hdmi_ctrl->audio_sdev.state);
+ if (hdmi_ctrl->hdcp_feature_on && hdmi_ctrl->present_hdcp) {
+ DEV_DBG("%s: Turning off HDCP\n", __func__);
+ hdmi_hdcp_off(hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP]);
+ }
+ if (!hdmi_tx_is_dvi_mode(hdmi_ctrl)) {
+ hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0, false);
hdmi_tx_audio_off(hdmi_ctrl);
}
@@ -1772,6 +2055,8 @@
return rc;
}
+ hdmi_ctrl->hdcp_feature_on = hdcp_feature_on;
+
DEV_INFO("power: ON (%s)\n", hdmi_get_video_fmt_2string(
hdmi_ctrl->video_resolution));
@@ -1794,7 +2079,6 @@
hdmi_tx_power_off(panel_data);
return rc;
}
- /* todo: HDCP */
} else {
mutex_unlock(&hdmi_ctrl->mutex);
}
@@ -1937,6 +2221,9 @@
}
if (DSS_REG_R(io, HDMI_HPD_INT_STATUS) & BIT(0)) {
+ hdmi_ctrl->hpd_state =
+ (DSS_REG_R(io, HDMI_HPD_INT_STATUS) & BIT(1)) >> 1;
+
/*
* Ack the current hpd interrupt and stop listening to
* new hpd interrupt.
@@ -1948,6 +2235,11 @@
if (hdmi_ddc_isr(&hdmi_ctrl->ddc_ctrl) < 0)
DEV_ERR("%s: hdmi_ddc_isr failed\n", __func__);
+ if (hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP])
+ if (hdmi_hdcp_isr(
+ hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP]) < 0)
+ DEV_ERR("%s: hdmi_hdcp_isr failed\n", __func__);
+
return IRQ_HANDLED;
} /* hdmi_tx_isr */
@@ -1958,6 +2250,11 @@
return;
}
+ if (hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP]) {
+ hdmi_hdcp_deinit(hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP]);
+ hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP] = NULL;
+ }
+
if (hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID])
hdmi_edid_deinit(hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]);
@@ -1982,7 +2279,7 @@
pdata = &hdmi_ctrl->pdata;
- rc = hdmi_tx_check_capability(&pdata->io[HDMI_TX_QFPROM_IO]);
+ rc = hdmi_tx_check_capability(hdmi_ctrl);
if (rc) {
DEV_ERR("%s: no HDMI device\n", __func__);
goto fail_no_hdmi;
@@ -2014,7 +2311,7 @@
INIT_WORK(&hdmi_ctrl->power_off_work, hdmi_tx_power_off_work);
- hdmi_ctrl->audio_sample_rate = HDMI_SAMPLE_RATE_48KHZ;
+ hdmi_ctrl->audio_sample_rate = AUDIO_SAMPLE_RATE_48KHZ;
hdmi_ctrl->sdev.name = "hdmi";
if (switch_dev_register(&hdmi_ctrl->sdev) < 0) {
@@ -2119,6 +2416,14 @@
break;
case MDSS_EVENT_TIMEGEN_ON:
+ if (hdmi_ctrl->hdcp_feature_on && hdmi_ctrl->present_hdcp) {
+ DEV_DBG("%s: Starting HDCP authentication\n", __func__);
+ rc = hdmi_hdcp_authenticate(
+ hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP]);
+ if (rc)
+ DEV_ERR("%s: hdcp auth failed. rc=%d\n",
+ __func__, rc);
+ }
break;
case MDSS_EVENT_SUSPEND:
@@ -2146,9 +2451,6 @@
break;
case MDSS_EVENT_TIMEGEN_OFF:
- /* If a power off is already underway, wait for it to finish */
- if (hdmi_ctrl->panel_suspend)
- flush_work_sync(&hdmi_ctrl->power_off_work);
break;
case MDSS_EVENT_CLOSE:
@@ -2792,6 +3094,15 @@
goto failed_init_features;
}
+ rc = of_platform_populate(of_node, NULL, NULL, &pdev->dev);
+ if (rc) {
+ DEV_ERR("%s: failed to add child devices, rc=%d\n",
+ __func__, rc);
+ goto failed_init_features;
+ } else {
+ DEV_DBG("%s: added child devices.\n", __func__);
+ }
+
return rc;
failed_init_features:
@@ -2855,6 +3166,26 @@
platform_driver_unregister(&this_driver);
} /* hdmi_tx_drv_exit */
+static int set_hdcp_feature_on(const char *val, const struct kernel_param *kp)
+{
+ int rc = 0;
+
+ rc = param_set_bool(val, kp);
+ if (!rc)
+ pr_debug("%s: HDCP feature = %d\n", __func__, hdcp_feature_on);
+
+ return rc;
+}
+
+static struct kernel_param_ops hdcp_feature_on_param_ops = {
+ .set = set_hdcp_feature_on,
+ .get = param_get_bool,
+};
+
+module_param_cb(hdcp, &hdcp_feature_on_param_ops, &hdcp_feature_on,
+ S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(hdcp, "Enable or Disable HDCP");
+
module_init(hdmi_tx_drv_init);
module_exit(hdmi_tx_drv_exit);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.h b/drivers/video/msm/mdss/mdss_hdmi_tx.h
index 5f8094f..f78ce9f 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.h
@@ -63,6 +63,7 @@
struct work_struct power_off_work;
+ bool hdcp_feature_on;
u32 present_hdcp;
u8 spd_vendor_name[8];
diff --git a/drivers/video/msm/mdss/mdss_hdmi_util.c b/drivers/video/msm/mdss/mdss_hdmi_util.c
index a3d76be..ad63605 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_util.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_util.c
@@ -16,73 +16,24 @@
#include "mdss_hdmi_util.h"
static struct hdmi_disp_mode_timing_type
- hdmi_supported_video_mode_lut[HDMI_VFRMT_MAX] = {
- HDMI_SETTINGS_640x480p60_4_3,
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p60_4_3),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p60_16_9),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1280x720p60_16_9),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080i60_16_9),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i60_4_3),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i60_16_9),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x240p60_4_3),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x240p60_16_9),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x480i60_4_3),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x480i60_16_9),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x240p60_4_3),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x240p60_16_9),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480p60_4_3),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480p60_16_9),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080p60_16_9),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p50_4_3),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p50_16_9),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1280x720p50_16_9),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080i50_16_9),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i50_4_3),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i50_16_9),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x288p50_4_3),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x288p50_16_9),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x576i50_4_3),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x576i50_16_9),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x288p50_4_3),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x288p50_16_9),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576p50_4_3),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576p50_16_9),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080p50_16_9),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080p24_16_9),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080p25_16_9),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080p30_16_9),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x480p60_4_3),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x480p60_16_9),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x576p50_4_3),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x576p50_16_9),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1250i50_16_9),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080i100_16_9),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1280x720p100_16_9),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p100_4_3),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p100_16_9),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i100_4_3),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i100_16_9),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080i120_16_9),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1280x720p120_16_9),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p120_4_3),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p120_16_9),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i120_4_3),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i120_16_9),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p200_4_3),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p200_16_9),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i200_4_3),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i200_16_9),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p240_4_3),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p240_16_9),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i240_4_3),
- VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i240_16_9),
-}; /* hdmi_supported_video_mode_lut */
+ hdmi_supported_video_mode_lut[HDMI_VFRMT_MAX];
#define HDMI_SETUP_LUT(MODE) do { \
struct hdmi_disp_mode_timing_type mode = HDMI_SETTINGS_##MODE; \
hdmi_supported_video_mode_lut[mode.video_format] = mode; \
} while (0)
+void hdmi_init_supported_video_timings(void)
+{
+ int i;
+
+ for (i = 0; i < HDMI_VFRMT_MAX; i++) {
+ struct hdmi_disp_mode_timing_type mode = VFRMT_NOT_SUPPORTED(i);
+
+ hdmi_supported_video_mode_lut[i] = mode;
+ }
+} /* hdmi_init_supported_video_timings */
+
const struct hdmi_disp_mode_timing_type *hdmi_get_supported_mode(u32 mode)
{
const struct hdmi_disp_mode_timing_type *ret = NULL;
@@ -203,6 +154,21 @@
case HDMI_VFRMT_1920x1080p60_16_9:
HDMI_SETUP_LUT(1920x1080p60_16_9);
break;
+ case HDMI_VFRMT_2560x1600p60_16_9:
+ HDMI_SETUP_LUT(2560x1600p60_16_9);
+ break;
+ case HDMI_VFRMT_3840x2160p30_16_9:
+ HDMI_SETUP_LUT(3840x2160p30_16_9);
+ break;
+ case HDMI_VFRMT_3840x2160p25_16_9:
+ HDMI_SETUP_LUT(3840x2160p25_16_9);
+ break;
+ case HDMI_VFRMT_3840x2160p24_16_9:
+ HDMI_SETUP_LUT(3840x2160p24_16_9);
+ break;
+ case HDMI_VFRMT_4096x2160p24_16_9:
+ HDMI_SETUP_LUT(4096x2160p24_16_9);
+ break;
default:
DEV_ERR("%s: unsupported mode=%d\n", __func__, mode);
}
@@ -270,6 +236,11 @@
case HDMI_VFRMT_720x480p240_16_9: return " 720x 480 p240 16/9";
case HDMI_VFRMT_1440x480i240_4_3: return "1440x 480 i240 4/3";
case HDMI_VFRMT_1440x480i240_16_9: return "1440x 480 i240 16/9";
+ case HDMI_VFRMT_2560x1600p60_16_9: return "2560x1600 p60 16/9";
+ case HDMI_VFRMT_3840x2160p30_16_9: return "3840x2160 p30 16/9";
+ case HDMI_VFRMT_3840x2160p25_16_9: return "3840x2160 p25 16/9";
+ case HDMI_VFRMT_3840x2160p24_16_9: return "3840x2160 p24 16/9";
+ case HDMI_VFRMT_4096x2160p24_16_9: return "4096x2160 p24 16/9";
default: return "???";
}
} /* hdmi_get_video_fmt_2string */
@@ -550,8 +521,8 @@
*/
DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_SETUP, 0xFF000000);
- /* Enable reference timer to 27 micro-seconds */
- DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_REF, (1 << 16) | (27 << 0));
+ /* Enable reference timer to 19 micro-seconds */
+ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_REF, (1 << 16) | (19 << 0));
} /* hdmi_ddc_config */
int hdmi_ddc_isr(struct hdmi_tx_ddc_ctrl *ddc_ctrl)
diff --git a/drivers/video/msm/mdss/mdss_hdmi_util.h b/drivers/video/msm/mdss/mdss_hdmi_util.h
index c970ebe..d79b6e7 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_util.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_util.h
@@ -215,8 +215,10 @@
/* QFPROM Registers for HDMI/HDCP */
#define QFPROM_RAW_FEAT_CONFIG_ROW0_LSB (0x000000F8)
#define QFPROM_RAW_FEAT_CONFIG_ROW0_MSB (0x000000FC)
+#define HDCP_KSV_LSB (0x000060D8)
+#define HDCP_KSV_MSB (0x000060DC)
-/* all video formats defined by EIA CEA 861D */
+/* all video formats defined by EIA CEA-861-E */
#define HDMI_VFRMT_640x480p60_4_3 0
#define HDMI_VFRMT_720x480p60_4_3 1
#define HDMI_VFRMT_720x480p60_16_9 2
@@ -292,7 +294,18 @@
#define HDMI_VFRMT_1440x480i240_4_3 HDMI_VFRMT_720x480i240_4_3
#define HDMI_VFRMT_720x480i240_16_9 58
#define HDMI_VFRMT_1440x480i240_16_9 HDMI_VFRMT_720x480i240_16_9
-#define HDMI_VFRMT_MAX 59
+/* Video Identification Codes from 65-127 are reserved for the future */
+#define HDMI_VFRMT_END 127
+/* extended video formats */
+#define HDMI_VFRMT_3840x2160p30_16_9 (HDMI_VFRMT_END + 1)
+#define HDMI_VFRMT_3840x2160p25_16_9 (HDMI_VFRMT_END + 2)
+#define HDMI_VFRMT_3840x2160p24_16_9 (HDMI_VFRMT_END + 3)
+#define HDMI_VFRMT_4096x2160p24_16_9 (HDMI_VFRMT_END + 4)
+#define HDMI_EVFRMT_END HDMI_VFRMT_4096x2160p24_16_9
+/* DVI only resolutions */
+#define HDMI_VFRMT_2560x1600p60_16_9 (HDMI_EVFRMT_END + 1)
+#define DVI_VFRMT_END HDMI_VFRMT_2560x1600p60_16_9
+#define HDMI_VFRMT_MAX (DVI_VFRMT_END + 1)
#define HDMI_VFRMT_FORCE_32BIT 0x7FFFFFFF
#define VFRMT_NOT_SUPPORTED(VFRMT) \
@@ -349,6 +362,21 @@
#define HDMI_SETTINGS_1920x1080p30_16_9 \
{HDMI_VFRMT_1920x1080p30_16_9, 1920, 88, 44, 148, false, \
1080, 4, 5, 36, false, 74250, 30000, false, true}
+#define HDMI_SETTINGS_2560x1600p60_16_9 \
+ {HDMI_VFRMT_2560x1600p60_16_9, 2560, 48, 32, 80, false, \
+ 1600, 3, 6, 37, false, 268500, 60000, false, true}
+#define HDMI_SETTINGS_3840x2160p30_16_9 \
+ {HDMI_VFRMT_3840x2160p30_16_9, 3840, 176, 88, 296, false, \
+ 2160, 8, 10, 72, false, 297000, 30000, false, true}
+#define HDMI_SETTINGS_3840x2160p25_16_9 \
+ {HDMI_VFRMT_3840x2160p25_16_9, 3840, 1056, 88, 296, false, \
+ 2160, 8, 10, 72, false, 297000, 25000, false, true}
+#define HDMI_SETTINGS_3840x2160p24_16_9 \
+ {HDMI_VFRMT_3840x2160p24_16_9, 3840, 1276, 88, 296, false, \
+ 2160, 8, 10, 72, false, 297000, 24000, false, true}
+#define HDMI_SETTINGS_4096x2160p24_16_9 \
+ {HDMI_VFRMT_4096x2160p24_16_9, 4096, 1020, 88, 296, false, \
+ 2160, 8, 10, 72, false, 297000, 24000, false, true}
#define TOP_AND_BOTTOM 0x10
#define FRAME_PACKING 0x20
@@ -397,6 +425,8 @@
int retry;
};
+/* video timing related utility routines */
+void hdmi_init_supported_video_timings(void);
int hdmi_get_video_id_code(struct hdmi_disp_mode_timing_type *timing_in);
const struct hdmi_disp_mode_timing_type *hdmi_get_supported_mode(u32 mode);
void hdmi_set_supported_mode(u32 mode);
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 31cc527..bd0f6c9 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -94,6 +94,7 @@
u32 quota, rate;
u32 v_total, v_active;
int i;
+ u32 max_clk_rate = 0, ab_total = 0, ib_total = 0;
*bus_ab_quota = 0;
*bus_ib_quota = 0;
@@ -135,6 +136,11 @@
pipe = mixer->stage_pipe[i];
if (pipe == NULL)
continue;
+ if (pipe->is_fg) {
+ ab_total = 0;
+ ib_total = 0;
+ max_clk_rate = 0;
+ }
quota = fps * pipe->src.w * pipe->src.h;
if (pipe->src_fmt->chroma_sample == MDSS_MDP_CHROMA_420)
@@ -161,12 +167,17 @@
pr_debug("mixer=%d pnum=%d clk_rate=%u bus ab=%u ib=%u\n",
mixer->num, pipe->num, rate, quota, ib_quota);
- *bus_ab_quota += quota >> MDSS_MDP_BUS_FACTOR_SHIFT;
- *bus_ib_quota += ib_quota >> MDSS_MDP_BUS_FACTOR_SHIFT;
- if (rate > *clk_rate)
- *clk_rate = rate;
+ ab_total += quota >> MDSS_MDP_BUS_FACTOR_SHIFT;
+ ib_total += ib_quota >> MDSS_MDP_BUS_FACTOR_SHIFT;
+ if (rate > max_clk_rate)
+ max_clk_rate = rate;
}
+ *bus_ab_quota += ab_total;
+ *bus_ib_quota += ib_total;
+ if (max_clk_rate > *clk_rate)
+ *clk_rate = max_clk_rate;
+
pr_debug("final mixer=%d clk_rate=%u bus ab=%u ib=%u\n", mixer->num,
*clk_rate, *bus_ab_quota, *bus_ib_quota);
}
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index 4757c63..a6a6d59 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -16,6 +16,9 @@
#include "mdss_fb.h"
#include "mdss_mdp.h"
+/* wait for at most 2 vsync for lowest refresh rate (24hz) */
+#define VSYNC_TIMEOUT msecs_to_jiffies(84)
+
/* intf timing settings */
struct intf_timing_params {
u32 width;
@@ -41,7 +44,6 @@
u8 ref_cnt;
u8 timegen_en;
- struct completion pp_comp;
struct completion vsync_comp;
atomic_t vsync_ref;
@@ -236,21 +238,6 @@
return 0;
}
-static void mdss_mdp_video_pp_intr_done(void *arg)
-{
- struct mdss_mdp_ctl *ctl = arg;
- struct mdss_mdp_video_ctx *ctx = ctl->priv_data;
-
- if (!ctx) {
- pr_err("invalid ctx\n");
- return;
- }
-
- pr_debug("intr mixer=%d\n", ctx->pp_num);
-
- complete(&ctx->pp_comp);
-}
-
static void mdss_mdp_video_vsync_intr_done(void *arg)
{
struct mdss_mdp_ctl *ctl = arg;
@@ -273,27 +260,6 @@
spin_unlock(&ctx->vsync_lock);
}
-static int mdss_mdp_video_prepare(struct mdss_mdp_ctl *ctl, void *arg)
-{
- struct mdss_mdp_video_ctx *ctx;
-
- ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data;
- if (!ctx) {
- pr_err("invalid ctx\n");
- return -ENODEV;
- }
-
- if (ctx->timegen_en) {
- INIT_COMPLETION(ctx->pp_comp);
- pr_debug("waiting for ping pong %d done\n", ctx->pp_num);
- mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num);
- wait_for_completion_interruptible(&ctx->pp_comp);
- mdss_mdp_irq_disable(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num);
- }
-
- return 0;
-}
-
static int mdss_mdp_video_display(struct mdss_mdp_ctl *ctl, void *arg)
{
struct mdss_mdp_video_ctx *ctx;
@@ -322,7 +288,9 @@
wmb();
}
- wait_for_completion(&ctx->vsync_comp);
+ rc = wait_for_completion_interruptible_timeout(&ctx->vsync_comp,
+ VSYNC_TIMEOUT);
+ WARN(rc <= 0, "vsync timed out (%d) ctl=%d\n", rc, ctl->num);
if (!ctx->timegen_en) {
ctx->timegen_en = true;
@@ -366,15 +334,12 @@
}
ctl->priv_data = ctx;
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);
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num,
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, ctl);
itp.width = pinfo->xres + pinfo->lcdc.xres_pad;
itp.height = pinfo->yres + pinfo->lcdc.yres_pad;
@@ -397,7 +362,6 @@
}
ctl->stop_fnc = mdss_mdp_video_stop;
- ctl->prepare_fnc = mdss_mdp_video_prepare;
ctl->display_fnc = mdss_mdp_video_display;
ctl->set_vsync_handler = mdss_mdp_video_set_vsync_handler;
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index 459cf14..ade7cb4 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -80,16 +80,21 @@
static int mdss_mdp_smp_reserve(struct mdss_mdp_pipe *pipe)
{
u32 num_blks = 0, reserved = 0;
- int i;
+ struct mdss_mdp_plane_sizes ps;
+ int i, rc;
- if ((pipe->src_planes.num_planes > 1) &&
- (pipe->type == MDSS_MDP_PIPE_TYPE_RGB))
+ rc = mdss_mdp_get_plane_sizes(pipe->src_fmt->format, pipe->src.w,
+ pipe->src.h, &ps);
+ if (rc)
+ return rc;
+
+ if ((ps.num_planes > 1) && (pipe->type == MDSS_MDP_PIPE_TYPE_RGB))
return -EINVAL;
mutex_lock(&mdss_mdp_smp_lock);
- for (i = 0; i < pipe->src_planes.num_planes; i++) {
- num_blks = DIV_ROUND_UP(2 * pipe->src_planes.ystride[i],
- mdss_res->smp_mb_size);
+ for (i = 0; i < ps.num_planes; i++) {
+ num_blks = DIV_ROUND_UP(2 * ps.ystride[i],
+ mdss_res->smp_mb_size);
pr_debug("reserving %d mmb for pnum=%d plane=%d\n",
num_blks, pipe->num, i);
diff --git a/drivers/video/msm/mipi_NT35510.c b/drivers/video/msm/mipi_NT35510.c
index d75198a..6d0bf7c 100644
--- a/drivers/video/msm/mipi_NT35510.c
+++ b/drivers/video/msm/mipi_NT35510.c
@@ -473,6 +473,8 @@
struct msm_fb_data_type *mfd;
struct mipi_panel_info *mipi;
static int rotate;
+ struct dcs_cmd_req cmdreq;
+
mfd = platform_get_drvdata(pdev);
if (!mfd)
return -ENODEV;
@@ -490,25 +492,41 @@
if (mipi_nt35510_pdata && mipi_nt35510_pdata->rotate_panel)
rotate = mipi_nt35510_pdata->rotate_panel();
+ memset(&cmdreq, 0, sizeof(cmdreq));
if (mipi->mode == DSI_VIDEO_MODE) {
- mipi_dsi_cmds_tx(&nt35510_tx_buf,
- nt35510_video_display_on_cmds,
- ARRAY_SIZE(nt35510_video_display_on_cmds));
+ cmdreq.cmds = nt35510_video_display_on_cmds;
+ cmdreq.cmds_cnt = ARRAY_SIZE(nt35510_video_display_on_cmds);
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+ mipi_dsi_cmdlist_put(&cmdreq);
if (rotate) {
- mipi_dsi_cmds_tx(&nt35510_tx_buf,
- nt35510_video_display_on_cmds_rotate,
- ARRAY_SIZE(nt35510_video_display_on_cmds_rotate));
+ cmdreq.cmds = nt35510_video_display_on_cmds_rotate;
+ cmdreq.cmds_cnt =
+ ARRAY_SIZE(nt35510_video_display_on_cmds_rotate);
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+ mipi_dsi_cmdlist_put(&cmdreq);
}
} else if (mipi->mode == DSI_CMD_MODE) {
- mipi_dsi_cmds_tx(&nt35510_tx_buf,
- nt35510_cmd_display_on_cmds,
- ARRAY_SIZE(nt35510_cmd_display_on_cmds));
+ cmdreq.cmds = nt35510_cmd_display_on_cmds;
+ cmdreq.cmds_cnt =
+ ARRAY_SIZE(nt35510_cmd_display_on_cmds);
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+ mipi_dsi_cmdlist_put(&cmdreq);
if (rotate) {
- mipi_dsi_cmds_tx(&nt35510_tx_buf,
- nt35510_cmd_display_on_cmds_rotate,
- ARRAY_SIZE(nt35510_cmd_display_on_cmds_rotate));
+ cmdreq.cmds = nt35510_cmd_display_on_cmds_rotate;
+ cmdreq.cmds_cnt =
+ ARRAY_SIZE(nt35510_cmd_display_on_cmds_rotate);
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+ mipi_dsi_cmdlist_put(&cmdreq);
}
}
@@ -518,6 +536,7 @@
static int mipi_nt35510_lcd_off(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
+ struct dcs_cmd_req cmdreq;
pr_debug("mipi_nt35510_lcd_off E\n");
@@ -528,8 +547,13 @@
if (mfd->key != MFD_KEY)
return -EINVAL;
- mipi_dsi_cmds_tx(&nt35510_tx_buf, nt35510_display_off_cmds,
- ARRAY_SIZE(nt35510_display_off_cmds));
+ memset(&cmdreq, 0, sizeof(cmdreq));
+ cmdreq.cmds = nt35510_display_off_cmds;
+ cmdreq.cmds_cnt = ARRAY_SIZE(nt35510_display_off_cmds);
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+ mipi_dsi_cmdlist_put(&cmdreq);
pr_debug("mipi_nt35510_lcd_off X\n");
return 0;
diff --git a/drivers/video/msm/mipi_dsi.c b/drivers/video/msm/mipi_dsi.c
index cc19555..35b6ae6 100644
--- a/drivers/video/msm/mipi_dsi.c
+++ b/drivers/video/msm/mipi_dsi.c
@@ -106,10 +106,6 @@
ret = panel_next_off(pdev);
-#ifdef CONFIG_MSM_BUS_SCALING
- mdp_bus_scale_update_request(0);
-#endif
-
mipi_dsi_clk_disable();
/* disbale dsi engine */
@@ -313,10 +309,6 @@
mipi_dsi_unprepare_clocks();
}
-#ifdef CONFIG_MSM_BUS_SCALING
- mdp_bus_scale_update_request(2);
-#endif
-
if (mdp_rev >= MDP_REV_41)
mutex_unlock(&mfd->dma->ov_mutex);
else
diff --git a/drivers/video/msm/mipi_dsi.h b/drivers/video/msm/mipi_dsi.h
index d4d7288..02b42bc 100644
--- a/drivers/video/msm/mipi_dsi.h
+++ b/drivers/video/msm/mipi_dsi.h
@@ -267,11 +267,13 @@
#define CMD_REQ_COMMIT 0x0002
#define CMD_CLK_CTRL 0x0004
#define CMD_REQ_NO_MAX_PKT_SIZE 0x0008
+#define CMD_MDP3_CMD_PANEL 0x80000000 /* mdp3 only */
struct dcs_cmd_req {
struct dsi_cmd_desc *cmds;
int cmds_cnt;
u32 flags;
+ struct dsi_buf *rbuf;
int rlen; /* rx length */
fxn cb;
};
@@ -291,14 +293,7 @@
void mipi_dsi_bist_ctrl(void);
int mipi_dsi_buf_alloc(struct dsi_buf *, int size);
int mipi_dsi_cmd_dma_add(struct dsi_buf *dp, struct dsi_cmd_desc *cm);
-int mipi_dsi_cmds_tx(struct dsi_buf *dp, struct dsi_cmd_desc *cmds, int cnt);
-
-int mipi_dsi_cmd_dma_tx(struct dsi_buf *dp);
int mipi_dsi_cmd_reg_tx(uint32 data);
-int mipi_dsi_cmds_rx(struct msm_fb_data_type *mfd,
- struct dsi_buf *tp, struct dsi_buf *rp,
- struct dsi_cmd_desc *cmds, int len);
-int mipi_dsi_cmd_dma_rx(struct dsi_buf *tp, int rlen);
void mipi_dsi_host_init(struct mipi_panel_info *pinfo);
void mipi_dsi_op_mode_config(int mode);
void mipi_dsi_cmd_mode_ctrl(int enable);
diff --git a/drivers/video/msm/mipi_dsi_host.c b/drivers/video/msm/mipi_dsi_host.c
index ee4a578..559c7a1 100644
--- a/drivers/video/msm/mipi_dsi_host.c
+++ b/drivers/video/msm/mipi_dsi_host.c
@@ -1130,11 +1130,15 @@
return 4;
}
+static int mipi_dsi_cmd_dma_tx(struct dsi_buf *tp);
+static int mipi_dsi_cmd_dma_rx(struct dsi_buf *rp, int rlen);
+
/*
* mipi_dsi_cmds_tx:
* thread context only
*/
-int mipi_dsi_cmds_tx(struct dsi_buf *tp, struct dsi_cmd_desc *cmds, int cnt)
+static int mipi_dsi_cmds_tx(struct dsi_buf *tp,
+ struct dsi_cmd_desc *cmds, int cnt)
{
struct dsi_cmd_desc *cm;
uint32 dsi_ctrl, ctrl;
@@ -1187,122 +1191,8 @@
* len should be either 4 or 8
* any return data more than MIPI_DSI_LEN need to be break down
* to multiple transactions.
- *
- * ov_mutex need to be acquired before call this function.
*/
-int mipi_dsi_cmds_rx(struct msm_fb_data_type *mfd,
- struct dsi_buf *tp, struct dsi_buf *rp,
- struct dsi_cmd_desc *cmds, int rlen)
-{
- int cnt, len, diff, pkt_size;
- char cmd;
-
- if (mfd->panel_info.mipi.no_max_pkt_size) {
- /* Only support rlen = 4*n */
- rlen += 3;
- rlen &= ~0x03;
- }
-
- len = rlen;
- diff = 0;
-
- if (len <= 2)
- cnt = 4; /* short read */
- else {
- if (len > MIPI_DSI_LEN)
- len = MIPI_DSI_LEN; /* 8 bytes at most */
-
- len = (len + 3) & ~0x03; /* len 4 bytes align */
- diff = len - rlen;
- /*
- * add extra 2 bytes to len to have overall
- * packet size is multipe by 4. This also make
- * sure 4 bytes dcs headerlocates within a
- * 32 bits register after shift in.
- * after all, len should be either 6 or 10.
- */
- len += 2;
- cnt = len + 6; /* 4 bytes header + 2 bytes crc */
- }
-
- if (mfd->panel_info.type == MIPI_CMD_PANEL) {
- /* make sure mdp dma is not txing pixel data */
-#ifdef CONFIG_FB_MSM_MDP303
- mdp3_dsi_cmd_dma_busy_wait(mfd);
-#endif
- }
-
- if (!mfd->panel_info.mipi.no_max_pkt_size) {
- /* packet size need to be set at every read */
- pkt_size = len;
- max_pktsize[0] = pkt_size;
- mipi_dsi_enable_irq(DSI_CMD_TERM);
- mipi_dsi_buf_init(tp);
- mipi_dsi_cmd_dma_add(tp, pkt_size_cmd);
- mipi_dsi_cmd_dma_tx(tp);
- }
-
- mipi_dsi_enable_irq(DSI_CMD_TERM);
- mipi_dsi_buf_init(tp);
- mipi_dsi_cmd_dma_add(tp, cmds);
-
- /* transmit read comamnd to client */
- mipi_dsi_cmd_dma_tx(tp);
-
- /*
- * once cmd_dma_done interrupt received,
- * return data from client is ready and stored
- * at RDBK_DATA register already
- */
- mipi_dsi_buf_init(rp);
- if (mfd->panel_info.mipi.no_max_pkt_size) {
- /*
- * expect rlen = n * 4
- * short alignement for start addr
- */
- rp->data += 2;
- }
-
- mipi_dsi_cmd_dma_rx(rp, cnt);
-
- if (mfd->panel_info.mipi.no_max_pkt_size) {
- /*
- * remove extra 2 bytes from previous
- * rx transaction at shift register
- * which was inserted during copy
- * shift registers to rx buffer
- * rx payload start from long alignment addr
- */
- rp->data += 2;
- }
-
- cmd = rp->data[0];
- switch (cmd) {
- case DTYPE_ACK_ERR_RESP:
- pr_debug("%s: rx ACK_ERR_PACLAGE\n", __func__);
- break;
- case DTYPE_GEN_READ1_RESP:
- case DTYPE_DCS_READ1_RESP:
- mipi_dsi_short_read1_resp(rp);
- break;
- case DTYPE_GEN_READ2_RESP:
- case DTYPE_DCS_READ2_RESP:
- mipi_dsi_short_read2_resp(rp);
- break;
- case DTYPE_GEN_LREAD_RESP:
- case DTYPE_DCS_LREAD_RESP:
- mipi_dsi_long_read_resp(rp);
- rp->len -= 2; /* extra 2 bytes added */
- rp->len -= diff; /* align bytes */
- break;
- default:
- break;
- }
-
- return rp->len;
-}
-
-int mipi_dsi_cmds_rx_new(struct dsi_buf *tp, struct dsi_buf *rp,
+static int mipi_dsi_cmds_rx(struct dsi_buf *tp, struct dsi_buf *rp,
struct dcs_cmd_req *req, int rlen)
{
struct dsi_cmd_desc *cmds;
@@ -1411,7 +1301,7 @@
return rp->len;
}
-int mipi_dsi_cmd_dma_tx(struct dsi_buf *tp)
+static int mipi_dsi_cmd_dma_tx(struct dsi_buf *tp)
{
unsigned long flags;
@@ -1458,7 +1348,7 @@
return tp->len;
}
-int mipi_dsi_cmd_dma_rx(struct dsi_buf *rp, int rlen)
+static int mipi_dsi_cmd_dma_rx(struct dsi_buf *rp, int rlen)
{
uint32 *lp, data;
int i, off, cnt;
@@ -1563,12 +1453,17 @@
struct dsi_buf *rp;
mipi_dsi_buf_init(&dsi_tx_buf);
- mipi_dsi_buf_init(&dsi_rx_buf);
tp = &dsi_tx_buf;
- rp = &dsi_rx_buf;
- len = mipi_dsi_cmds_rx_new(tp, rp, req, req->rlen);
+ if (req->rbuf)
+ rp = req->rbuf;
+ else
+ rp = &dsi_rx_buf;
+
+ mipi_dsi_buf_init(rp);
+
+ len = mipi_dsi_cmds_rx(tp, rp, req, req->rlen);
dp = (u32 *)rp->data;
if (req->cb)
diff --git a/drivers/video/msm/mipi_novatek.c b/drivers/video/msm/mipi_novatek.c
index 68bc65e..7e0a46e 100644
--- a/drivers/video/msm/mipi_novatek.c
+++ b/drivers/video/msm/mipi_novatek.c
@@ -314,10 +314,12 @@
{
struct dcs_cmd_req cmdreq;
+ memset(&cmdreq, 0, sizeof(cmdreq));
cmdreq.cmds = &novatek_manufacture_id_cmd;
cmdreq.cmds_cnt = 1;
cmdreq.flags = CMD_REQ_RX | CMD_REQ_COMMIT;
cmdreq.rlen = 3;
+ cmdreq.rbuf = NULL;
cmdreq.cb = mipi_novatek_manufacture_cb; /* call back */
mipi_dsi_cmdlist_put(&cmdreq);
/*
diff --git a/drivers/video/msm/mipi_orise.c b/drivers/video/msm/mipi_orise.c
index d1d6956..ea37def 100644
--- a/drivers/video/msm/mipi_orise.c
+++ b/drivers/video/msm/mipi_orise.c
@@ -53,6 +53,7 @@
struct msm_fb_data_type *mfd;
struct mipi_panel_info *mipi;
struct msm_panel_info *pinfo;
+ struct dcs_cmd_req cmdreq;
mfd = platform_get_drvdata(pdev);
if (!mfd)
@@ -63,12 +64,21 @@
pinfo = &mfd->panel_info;
mipi = &mfd->panel_info.mipi;
+ memset(&cmdreq, 0, sizeof(cmdreq));
if (mipi->mode == DSI_VIDEO_MODE) {
- mipi_dsi_cmds_tx(&orise_tx_buf, orise_video_on_cmds,
- ARRAY_SIZE(orise_video_on_cmds));
+ cmdreq.cmds = orise_video_on_cmds;
+ cmdreq.cmds_cnt = ARRAY_SIZE(orise_video_on_cmds);
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+ mipi_dsi_cmdlist_put(&cmdreq);
} else {
- mipi_dsi_cmds_tx(&orise_tx_buf, orise_cmd_on_cmds,
- ARRAY_SIZE(orise_cmd_on_cmds));
+ cmdreq.cmds = orise_cmd_on_cmds;
+ cmdreq.cmds_cnt = ARRAY_SIZE(orise_cmd_on_cmds);
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+ mipi_dsi_cmdlist_put(&cmdreq);
mipi_dsi_cmd_bta_sw_trigger(); /* clean up ack_err_status */
}
@@ -79,6 +89,7 @@
static int mipi_orise_lcd_off(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
+ struct dcs_cmd_req cmdreq;
mfd = platform_get_drvdata(pdev);
@@ -87,8 +98,13 @@
if (mfd->key != MFD_KEY)
return -EINVAL;
- mipi_dsi_cmds_tx(&orise_tx_buf, orise_display_off_cmds,
- ARRAY_SIZE(orise_display_off_cmds));
+ memset(&cmdreq, 0, sizeof(cmdreq));
+ cmdreq.cmds = orise_display_off_cmds;
+ cmdreq.cmds_cnt = ARRAY_SIZE(orise_display_off_cmds);
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+ mipi_dsi_cmdlist_put(&cmdreq);
return 0;
}
diff --git a/drivers/video/msm/mipi_renesas.c b/drivers/video/msm/mipi_renesas.c
index c842672..0d6b4be 100644
--- a/drivers/video/msm/mipi_renesas.c
+++ b/drivers/video/msm/mipi_renesas.c
@@ -1122,6 +1122,7 @@
{
struct msm_fb_data_type *mfd;
struct mipi_panel_info *mipi;
+ struct dcs_cmd_req cmdreq;
mfd = platform_get_drvdata(pdev);
mipi = &mfd->panel_info.mipi;
@@ -1131,24 +1132,47 @@
if (mfd->key != MFD_KEY)
return -EINVAL;
- mipi_dsi_cmds_tx(&renesas_tx_buf, renesas_sleep_off_cmds,
- ARRAY_SIZE(renesas_sleep_off_cmds));
+ memset(&cmdreq, 0, sizeof(cmdreq));
+ cmdreq.cmds = renesas_sleep_off_cmds;
+ cmdreq.cmds_cnt = ARRAY_SIZE(renesas_sleep_off_cmds);
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+ mipi_dsi_cmdlist_put(&cmdreq);
mipi_set_tx_power_mode(1);
- mipi_dsi_cmds_tx(&renesas_tx_buf, renesas_display_on_cmds,
- ARRAY_SIZE(renesas_display_on_cmds));
+
+ cmdreq.cmds = renesas_display_on_cmds;
+ cmdreq.cmds_cnt = ARRAY_SIZE(renesas_display_on_cmds);
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+ mipi_dsi_cmdlist_put(&cmdreq);
if (cpu_is_msm7x25a() || cpu_is_msm7x25aa() || cpu_is_msm7x25ab()) {
- mipi_dsi_cmds_tx(&renesas_tx_buf, renesas_hvga_on_cmds,
- ARRAY_SIZE(renesas_hvga_on_cmds));
+ cmdreq.cmds = renesas_hvga_on_cmds;
+ cmdreq.cmds_cnt = ARRAY_SIZE(renesas_hvga_on_cmds);
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+ mipi_dsi_cmdlist_put(&cmdreq);
}
- if (mipi->mode == DSI_VIDEO_MODE)
- mipi_dsi_cmds_tx(&renesas_tx_buf, renesas_video_on_cmds,
- ARRAY_SIZE(renesas_video_on_cmds));
- else
- mipi_dsi_cmds_tx(&renesas_tx_buf, renesas_cmd_on_cmds,
- ARRAY_SIZE(renesas_cmd_on_cmds));
+ if (mipi->mode == DSI_VIDEO_MODE) {
+ cmdreq.cmds = renesas_video_on_cmds;
+ cmdreq.cmds_cnt = ARRAY_SIZE(renesas_video_on_cmds);
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+ mipi_dsi_cmdlist_put(&cmdreq);
+ } else {
+ cmdreq.cmds = renesas_cmd_on_cmds;
+ cmdreq.cmds_cnt = ARRAY_SIZE(renesas_cmd_on_cmds);
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+ mipi_dsi_cmdlist_put(&cmdreq);
+ }
mipi_set_tx_power_mode(0);
return 0;
@@ -1157,6 +1181,7 @@
static int mipi_renesas_lcd_off(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
+ struct dcs_cmd_req cmdreq;
mfd = platform_get_drvdata(pdev);
@@ -1165,8 +1190,13 @@
if (mfd->key != MFD_KEY)
return -EINVAL;
- mipi_dsi_cmds_tx(&renesas_tx_buf, renesas_display_off_cmds,
- ARRAY_SIZE(renesas_display_off_cmds));
+ memset(&cmdreq, 0, sizeof(cmdreq));
+ cmdreq.cmds = renesas_display_off_cmds;
+ cmdreq.cmds_cnt = ARRAY_SIZE(renesas_display_off_cmds);
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+ mipi_dsi_cmdlist_put(&cmdreq);
return 0;
}
diff --git a/drivers/video/msm/mipi_simulator.c b/drivers/video/msm/mipi_simulator.c
index c751472..cac927b 100644
--- a/drivers/video/msm/mipi_simulator.c
+++ b/drivers/video/msm/mipi_simulator.c
@@ -36,6 +36,7 @@
{
struct msm_fb_data_type *mfd;
struct mipi_panel_info *mipi;
+ struct dcs_cmd_req cmdreq;
mfd = platform_get_drvdata(pdev);
mipi = &mfd->panel_info.mipi;
@@ -48,9 +49,14 @@
pr_debug("%s:%d, debug info (mode) : %d", __func__, __LINE__,
mipi->mode);
+ memset(&cmdreq, 0, sizeof(cmdreq));
if (mipi->mode == DSI_VIDEO_MODE) {
- mipi_dsi_cmds_tx(&simulator_tx_buf, display_on_cmds,
- ARRAY_SIZE(display_on_cmds));
+ cmdreq.cmds = display_on_cmds;
+ cmdreq.cmds_cnt = ARRAY_SIZE(display_on_cmds);
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+ mipi_dsi_cmdlist_put(&cmdreq);
} else {
pr_err("%s:%d, CMD MODE NOT SUPPORTED", __func__, __LINE__);
return -EINVAL;
@@ -63,6 +69,7 @@
{
struct msm_fb_data_type *mfd;
struct mipi_panel_info *mipi;
+ struct dcs_cmd_req cmdreq;
mfd = platform_get_drvdata(pdev);
mipi = &mfd->panel_info.mipi;
@@ -74,9 +81,14 @@
pr_debug("%s:%d, debug info", __func__, __LINE__);
+ memset(&cmdreq, 0, sizeof(cmdreq));
if (mipi->mode == DSI_VIDEO_MODE) {
- mipi_dsi_cmds_tx(&simulator_tx_buf, display_off_cmds,
- ARRAY_SIZE(display_off_cmds));
+ cmdreq.cmds = display_off_cmds;
+ cmdreq.cmds_cnt = ARRAY_SIZE(display_off_cmds);
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+ mipi_dsi_cmdlist_put(&cmdreq);
} else {
pr_debug("%s:%d, DONT REACH HERE", __func__, __LINE__);
return -EINVAL;
diff --git a/drivers/video/msm/mipi_tc358764_dsi2lvds.c b/drivers/video/msm/mipi_tc358764_dsi2lvds.c
index 1583168..5db4fd2 100644
--- a/drivers/video/msm/mipi_tc358764_dsi2lvds.c
+++ b/drivers/video/msm/mipi_tc358764_dsi2lvds.c
@@ -243,20 +243,25 @@
{
u32 data;
int len = 4;
+ struct dcs_cmd_req cmdreq;
struct dsi_cmd_desc cmd_read_reg = {
DTYPE_GEN_READ2, 1, 0, 1, 0, /* cmd 0x24 */
sizeof(reg), (char *) ®};
- mipi_dsi_buf_init(&d2l_tx_buf);
mipi_dsi_buf_init(&d2l_rx_buf);
- /* mutex had been acquired at mipi_dsi_on */
- len = mipi_dsi_cmds_rx(mfd, &d2l_tx_buf, &d2l_rx_buf,
- &cmd_read_reg, len);
+ memset(&cmdreq, 0, sizeof(cmdreq));
+ cmdreq.cmds = &cmd_read_reg;
+ cmdreq.cmds_cnt = 1;
+ cmdreq.flags = CMD_REQ_RX | CMD_REQ_COMMIT | CMD_REQ_NO_MAX_PKT_SIZE;
+ cmdreq.rbuf = &d2l_rx_buf;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+ mipi_dsi_cmdlist_put(&cmdreq);
data = *(u32 *)d2l_rx_buf.data;
- if (len != 4)
+ if (d2l_rx_buf.len != 4)
pr_err("%s: invalid rlen=%d, expecting 4.\n", __func__, len);
pr_debug("%s: reg=0x%x.data=0x%08x.\n", __func__, reg, data);
@@ -274,6 +279,7 @@
static int mipi_d2l_write_reg(struct msm_fb_data_type *mfd, u16 reg, u32 data)
{
struct wr_cmd_payload payload;
+ struct dcs_cmd_req cmdreq;
struct dsi_cmd_desc cmd_write_reg = {
DTYPE_GEN_LWRITE, 1, 0, 0, 0,
sizeof(payload), (char *)&payload};
@@ -281,8 +287,13 @@
payload.addr = reg;
payload.data = data;
- /* mutex had been acquried at dsi_on */
- mipi_dsi_cmds_tx(&d2l_tx_buf, &cmd_write_reg, 1);
+ memset(&cmdreq, 0, sizeof(cmdreq));
+ cmdreq.cmds = &cmd_write_reg;
+ cmdreq.cmds_cnt = 1;
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+ mipi_dsi_cmdlist_put(&cmdreq);
pr_debug("%s: reg=0x%x. data=0x%x.\n", __func__, reg, data);
diff --git a/drivers/video/msm/mipi_toshiba.c b/drivers/video/msm/mipi_toshiba.c
index 520c67b..63504c9 100644
--- a/drivers/video/msm/mipi_toshiba.c
+++ b/drivers/video/msm/mipi_toshiba.c
@@ -184,6 +184,7 @@
static int mipi_toshiba_lcd_on(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
+ struct dcs_cmd_req cmdreq;
mfd = platform_get_drvdata(pdev);
@@ -192,16 +193,23 @@
if (mfd->key != MFD_KEY)
return -EINVAL;
- if (TM_GET_PID(mfd->panel.id) == MIPI_DSI_PANEL_WVGA_PT)
- mipi_dsi_cmds_tx(&toshiba_tx_buf,
- toshiba_wvga_display_on_cmds,
- ARRAY_SIZE(toshiba_wvga_display_on_cmds));
- else if (TM_GET_PID(mfd->panel.id) == MIPI_DSI_PANEL_WSVGA_PT ||
- TM_GET_PID(mfd->panel.id) == MIPI_DSI_PANEL_WUXGA)
- mipi_dsi_cmds_tx(&toshiba_tx_buf,
- toshiba_wsvga_display_on_cmds,
- ARRAY_SIZE(toshiba_wsvga_display_on_cmds));
- else
+ memset(&cmdreq, 0, sizeof(cmdreq));
+ if (TM_GET_PID(mfd->panel.id) == MIPI_DSI_PANEL_WVGA_PT) {
+ cmdreq.cmds = toshiba_wvga_display_on_cmds;
+ cmdreq.cmds_cnt = ARRAY_SIZE(toshiba_wvga_display_on_cmds);
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+ mipi_dsi_cmdlist_put(&cmdreq);
+ } else if (TM_GET_PID(mfd->panel.id) == MIPI_DSI_PANEL_WSVGA_PT ||
+ TM_GET_PID(mfd->panel.id) == MIPI_DSI_PANEL_WUXGA) {
+ cmdreq.cmds = toshiba_wsvga_display_on_cmds;
+ cmdreq.cmds_cnt = ARRAY_SIZE(toshiba_wsvga_display_on_cmds);
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+ mipi_dsi_cmdlist_put(&cmdreq);
+ } else
return -EINVAL;
return 0;
@@ -210,6 +218,7 @@
static int mipi_toshiba_lcd_off(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
+ struct dcs_cmd_req cmdreq;
mfd = platform_get_drvdata(pdev);
@@ -218,8 +227,13 @@
if (mfd->key != MFD_KEY)
return -EINVAL;
- mipi_dsi_cmds_tx(&toshiba_tx_buf, toshiba_display_off_cmds,
- ARRAY_SIZE(toshiba_display_off_cmds));
+ memset(&cmdreq, 0, sizeof(cmdreq));
+ cmdreq.cmds = toshiba_display_off_cmds;
+ cmdreq.cmds_cnt = ARRAY_SIZE(toshiba_display_off_cmds);
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+ mipi_dsi_cmdlist_put(&cmdreq);
return 0;
}
diff --git a/drivers/video/msm/mipi_truly.c b/drivers/video/msm/mipi_truly.c
index fd2a3ea..ea9c047 100644
--- a/drivers/video/msm/mipi_truly.c
+++ b/drivers/video/msm/mipi_truly.c
@@ -107,6 +107,7 @@
static int mipi_truly_lcd_on(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
+ struct dcs_cmd_req cmdreq;
mfd = platform_get_drvdata(pdev);
@@ -116,8 +117,14 @@
return -EINVAL;
msleep(20);
- mipi_dsi_cmds_tx(&truly_tx_buf, truly_display_on_cmds,
- ARRAY_SIZE(truly_display_on_cmds));
+
+ memset(&cmdreq, 0, sizeof(cmdreq));
+ cmdreq.cmds = truly_display_on_cmds;
+ cmdreq.cmds_cnt = ARRAY_SIZE(truly_display_on_cmds);
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+ mipi_dsi_cmdlist_put(&cmdreq);
return 0;
}
@@ -125,6 +132,7 @@
static int mipi_truly_lcd_off(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
+ struct dcs_cmd_req cmdreq;
mfd = platform_get_drvdata(pdev);
@@ -133,8 +141,13 @@
if (mfd->key != MFD_KEY)
return -EINVAL;
- mipi_dsi_cmds_tx(&truly_tx_buf, truly_display_off_cmds,
- ARRAY_SIZE(truly_display_off_cmds));
+ memset(&cmdreq, 0, sizeof(cmdreq));
+ cmdreq.cmds = truly_display_off_cmds;
+ cmdreq.cmds_cnt = ARRAY_SIZE(truly_display_off_cmds);
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+ mipi_dsi_cmdlist_put(&cmdreq);
return 0;
}
diff --git a/drivers/video/msm/mipi_truly_tft540960_1_e.c b/drivers/video/msm/mipi_truly_tft540960_1_e.c
index 50db66e..7f001eb 100644
--- a/drivers/video/msm/mipi_truly_tft540960_1_e.c
+++ b/drivers/video/msm/mipi_truly_tft540960_1_e.c
@@ -679,6 +679,7 @@
{
struct msm_fb_data_type *mfd;
struct mipi_panel_info *mipi;
+ struct dcs_cmd_req cmdreq;
mfd = platform_get_drvdata(pdev);
@@ -692,14 +693,21 @@
pr_info("%s: mode = %d\n", __func__, mipi->mode);
msleep(120);
+ memset(&cmdreq, 0, sizeof(cmdreq));
if (mipi->mode == DSI_VIDEO_MODE) {
- mipi_dsi_cmds_tx(&truly_tx_buf,
- truly_video_display_on_cmds,
- ARRAY_SIZE(truly_video_display_on_cmds));
+ cmdreq.cmds = truly_video_display_on_cmds;
+ cmdreq.cmds_cnt = ARRAY_SIZE(truly_video_display_on_cmds);
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+ mipi_dsi_cmdlist_put(&cmdreq);
} else if (mipi->mode == DSI_CMD_MODE) {
- mipi_dsi_cmds_tx(&truly_tx_buf,
- truly_cmd_display_on_cmds,
- ARRAY_SIZE(truly_cmd_display_on_cmds));
+ cmdreq.cmds = truly_cmd_display_on_cmds;
+ cmdreq.cmds_cnt = ARRAY_SIZE(truly_cmd_display_on_cmds);
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+ mipi_dsi_cmdlist_put(&cmdreq);
}
return 0;
@@ -708,6 +716,7 @@
static int mipi_truly_lcd_off(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
+ struct dcs_cmd_req cmdreq;
mfd = platform_get_drvdata(pdev);
@@ -716,8 +725,13 @@
if (mfd->key != MFD_KEY)
return -EINVAL;
- mipi_dsi_cmds_tx(&truly_tx_buf, truly_display_off_cmds,
- ARRAY_SIZE(truly_display_off_cmds));
+ memset(&cmdreq, 0, sizeof(cmdreq));
+ cmdreq.cmds = truly_display_off_cmds;
+ cmdreq.cmds_cnt = ARRAY_SIZE(truly_display_off_cmds);
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+ mipi_dsi_cmdlist_put(&cmdreq);
return 0;
}
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 993ec01..b7e0bbf 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -1286,27 +1286,8 @@
var->yres_virtual = panel_info->yres * mfd->fb_page +
((PAGE_SIZE - remainder)/fix->line_length) * mfd->fb_page;
var->bits_per_pixel = bpp * 8; /* FrameBuffer color depth */
- if (mfd->dest == DISPLAY_LCD) {
- if (panel_info->type == MDDI_PANEL && panel_info->mddi.is_type1)
- var->reserved[4] = panel_info->lcd.refx100 / (100 * 2);
- else
- var->reserved[4] = panel_info->lcd.refx100 / 100;
- } else {
- if (panel_info->type == MIPI_VIDEO_PANEL) {
- var->reserved[4] = panel_info->mipi.frame_rate;
- } else {
- var->reserved[4] = panel_info->clk_rate /
- ((panel_info->lcdc.h_back_porch +
- panel_info->lcdc.h_front_porch +
- panel_info->lcdc.h_pulse_width +
- panel_info->xres) *
- (panel_info->lcdc.v_back_porch +
- panel_info->lcdc.v_front_porch +
- panel_info->lcdc.v_pulse_width +
- panel_info->yres));
- }
- }
- pr_debug("reserved[4] %u\n", var->reserved[4]);
+
+ var->reserved[4] = mdp_get_panel_framerate(mfd);
/*
* id field for fb app
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
index 78f96c8..d189408 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
@@ -1259,7 +1259,7 @@
output_vcd_frm->flags |=
VCD_FRAME_FLAG_DATACORRUPT;
}
- if (decoder->codec.codec != VCD_CODEC_H264 ||
+ if (decoder->codec.codec != VCD_CODEC_H264 &&
decoder->codec.codec != VCD_CODEC_MPEG2)
output_vcd_frm->flags &= ~VCD_FRAME_FLAG_DATACORRUPT;
output_vcd_frm->ip_frm_tag = dec_disp_info->tag_top;
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 504e61b..6e0f58b 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -663,6 +663,42 @@
return PTR_ERR(req);
}
}
+
+#ifdef CONFIG_DMA_CMA
+ if (is_cma_pageblock(page)) {
+ struct page *oldpage = page, *newpage;
+ int err;
+
+ /* make sure that old page is not free in-between the calls */
+ page_cache_get(oldpage);
+
+ newpage = alloc_page(GFP_HIGHUSER);
+ if (!newpage) {
+ page_cache_release(oldpage);
+ return -ENOMEM;
+ }
+
+ err = replace_page_cache_page(oldpage, newpage, GFP_KERNEL);
+ if (err) {
+ __free_page(newpage);
+ page_cache_release(oldpage);
+ return err;
+ }
+
+ /*
+ * Decrement the count on new page to make page cache the only
+ * owner of it
+ */
+ lock_page(newpage);
+ put_page(newpage);
+
+ /* finally release the old page and swap pointers */
+ unlock_page(oldpage);
+ page_cache_release(oldpage);
+ page = newpage;
+ }
+#endif
+
page_cache_get(page);
req->pages[req->num_pages] = page;
req->num_pages++;
diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h
index 4e9e1ce..2874a3b 100644
--- a/include/linux/mfd/wcd9xxx/core.h
+++ b/include/linux/mfd/wcd9xxx/core.h
@@ -22,10 +22,6 @@
#define WCD9XXX_NUM_IRQ_REGS 4
#define WCD9XXX_SLIM_NUM_PORT_REG 3
-
-#define WCD9XXX_INTERFACE_TYPE_SLIMBUS 0x00
-#define WCD9XXX_INTERFACE_TYPE_I2C 0x01
-
#define TABLA_VERSION_1_0 0
#define TABLA_VERSION_1_1 1
#define TABLA_VERSION_2_0 2
@@ -135,6 +131,12 @@
wait_queue_head_t dai_wait;
};
+enum wcd9xxx_intf_status {
+ WCD9XXX_INTERFACE_TYPE_PROBING,
+ WCD9XXX_INTERFACE_TYPE_SLIMBUS,
+ WCD9XXX_INTERFACE_TYPE_I2C,
+};
+
#define WCD9XXX_CH(xport, xshift) \
{.port = xport, .shift = xshift}
@@ -177,6 +179,7 @@
u32 num_tx_port;
struct wcd9xxx_ch *rx_chs;
struct wcd9xxx_ch *tx_chs;
+ u32 mclk_rate;
};
int wcd9xxx_reg_read(struct wcd9xxx *wcd9xxx, unsigned short reg);
@@ -192,7 +195,7 @@
int wcd9xxx_irq_init(struct wcd9xxx *wcd9xxx);
void wcd9xxx_irq_exit(struct wcd9xxx *wcd9xxx);
int wcd9xxx_get_logical_addresses(u8 *pgd_la, u8 *inf_la);
-int wcd9xxx_get_intf_type(void);
+enum wcd9xxx_intf_status wcd9xxx_get_intf_type(void);
bool wcd9xxx_lock_sleep(struct wcd9xxx *wcd9xxx);
void wcd9xxx_unlock_sleep(struct wcd9xxx *wcd9xxx);
diff --git a/include/linux/mfd/wcd9xxx/pdata.h b/include/linux/mfd/wcd9xxx/pdata.h
index a7ca417..bfd95a6 100644
--- a/include/linux/mfd/wcd9xxx/pdata.h
+++ b/include/linux/mfd/wcd9xxx/pdata.h
@@ -154,6 +154,7 @@
struct wcd9xxx_micbias_setting micbias;
struct wcd9xxx_ocp_setting ocp;
struct wcd9xxx_regulator regulator[MAX_REGULATOR];
+ u32 mclk_rate;
};
#endif
diff --git a/include/linux/msm_ion.h b/include/linux/msm_ion.h
index 21648ad..d423b26 100644
--- a/include/linux/msm_ion.h
+++ b/include/linux/msm_ion.h
@@ -137,6 +137,7 @@
* goes from 1 -> 0
* @setup_region: function to be called upon ion registration
* @memory_type:Memory type used for the heap
+ * @no_nonsecure_alloc: don't allow non-secure allocations from this heap
*
*/
struct ion_cp_heap_pdata {
@@ -155,6 +156,7 @@
int (*release_region)(void *);
void *(*setup_region)(void);
enum ion_memory_types memory_type;
+ int no_nonsecure_alloc;
};
/**
diff --git a/include/linux/netfilter_ipv4/Kbuild b/include/linux/netfilter_ipv4/Kbuild
index 31f8bec..6733ccc 100644
--- a/include/linux/netfilter_ipv4/Kbuild
+++ b/include/linux/netfilter_ipv4/Kbuild
@@ -10,3 +10,4 @@
header-y += ipt_ah.h
header-y += ipt_ecn.h
header-y += ipt_ttl.h
+header-y += ipt_NATTYPE.h
diff --git a/include/linux/netfilter_ipv4/ipt_NATTYPE.h b/include/linux/netfilter_ipv4/ipt_NATTYPE.h
new file mode 100644
index 0000000..b612290
--- /dev/null
+++ b/include/linux/netfilter_ipv4/ipt_NATTYPE.h
@@ -0,0 +1,25 @@
+#ifndef _IPT_NATTYPE_H_target
+#define _IPT_NATTYPE_H_target
+
+#define NATTYPE_TIMEOUT 300
+
+enum nattype_mode {
+ MODE_DNAT,
+ MODE_FORWARD_IN,
+ MODE_FORWARD_OUT
+};
+
+enum nattype_type {
+ TYPE_PORT_ADDRESS_RESTRICTED,
+ TYPE_ENDPOINT_INDEPENDENT,
+ TYPE_ADDRESS_RESTRICTED
+};
+
+
+struct ipt_nattype_info {
+ u_int16_t mode;
+ u_int16_t type;
+};
+
+#endif /*_IPT_NATTYPE_H_target*/
+
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index fc34b22..3ab7b9d 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -1,5 +1,5 @@
/*
- * 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
@@ -660,13 +660,16 @@
* thresholds.
* @timer_interval: Select polling rate from qpnp_adc_meas_timer_1 type.
* @threshold_notification: Notification callback once threshold are crossed.
+ * @usbid_ctx: A context of void type.
*/
struct qpnp_adc_tm_usbid_param {
int32_t high_thr;
int32_t low_thr;
enum qpnp_state_request state_request;
enum qpnp_adc_meas_timer_1 timer_interval;
- void (*threshold_notification) (enum qpnp_tm_state state);
+ void *usbid_ctx;
+ void (*threshold_notification) (enum qpnp_tm_state state,
+ void *ctx);
};
/**
@@ -743,16 +746,32 @@
* input channel.
* @offset_gain_denominator: The inverse denominator of the gain applied to the
* input channel.
+ * @high_thr: High threshold voltage that is requested to be set.
+ * @low_thr: Low threshold voltage that is requested to be set.
+ * @timer_select: Choosen from one of the 3 timers to set the polling rate for
+ * the VADC_BTM channel.
+ * @meas_interval1: Polling rate to set for timer 1.
+ * @meas_interval2: Polling rate to set for timer 2.
+ * @tm_channel_select: BTM channel number for the 5 VADC_BTM channels.
+ * @state_request: User can select either enable or disable high/low or both
+ * activation levels based on the qpnp_state_request type.
* @adc_graph: ADC graph for the channel of struct type qpnp_adc_linear_graph.
*/
struct qpnp_vadc_chan_properties {
uint32_t offset_gain_numerator;
uint32_t offset_gain_denominator;
+ uint32_t high_thr;
+ uint32_t low_thr;
+ enum qpnp_adc_meas_timer_select timer_select;
+ enum qpnp_adc_meas_timer_1 meas_interval1;
+ enum qpnp_adc_meas_timer_2 meas_interval2;
+ enum qpnp_adc_tm_channel_select tm_channel_select;
+ enum qpnp_state_request state_request;
struct qpnp_vadc_linear_graph adc_graph[2];
};
/**
- * struct qpnp_adc_result - Represent the result of the QPNP ADC.
+ * struct qpnp_vadc_result - Represent the result of the QPNP ADC.
* @chan: The channel number of the requested conversion.
* @adc_code: The pre-calibrated digital output of a given ADC relative to the
* the ADC reference.
@@ -774,7 +793,7 @@
};
/**
- * struct qpnp_vadc_amux - AMUX properties for individual channel
+ * struct qpnp_adc_amux - AMUX properties for individual channel
* @name: Channel string name.
* @channel_num: Channel in integer used from qpnp_adc_channels.
* @chan_path_prescaling: Channel scaling performed on the input signal.
@@ -783,7 +802,7 @@
* each individual channel whether it is voltage, current,
* temperature, etc and compensates the channel properties.
*/
-struct qpnp_vadc_amux {
+struct qpnp_adc_amux {
char *name;
enum qpnp_vadc_channels channel_num;
enum qpnp_adc_channel_scaling_param chan_path_prescaling;
@@ -858,6 +877,11 @@
* @amux_prop - AMUX properties representing the ADC peripheral.
* @adc_channels - ADC channel properties for the ADC peripheral.
* @adc_irq_eoc - End of Conversion IRQ.
+ * @adc_irq_fifo_not_empty - Conversion sequencer request written
+ * to FIFO when not empty.
+ * @adc_irq_conv_seq_timeout - Conversion sequencer trigger timeout.
+ * @adc_high_thr_irq - Output higher than high threshold set for measurement.
+ * @adc_low_thr_irq - Output lower than low threshold set for measurement.
* @adc_lock - ADC lock for access to the peripheral.
* @adc_rslt_completion - ADC result notification after interrupt
* is received.
@@ -869,8 +893,12 @@
uint16_t offset;
struct qpnp_adc_properties *adc_prop;
struct qpnp_adc_amux_properties *amux_prop;
- struct qpnp_vadc_amux *adc_channels;
+ struct qpnp_adc_amux *adc_channels;
int adc_irq_eoc;
+ int adc_irq_fifo_not_empty;
+ int adc_irq_conv_seq_timeout;
+ int adc_high_thr_irq;
+ int adc_low_thr_irq;
struct mutex adc_lock;
struct completion adc_rslt_completion;
struct qpnp_iadc_calib calib;
@@ -937,13 +965,6 @@
struct qpnp_adc_drv *adc_qpnp);
/**
- * qpnp_vadc_configure() - Configure ADC device to start conversion.
- * @chan_prop: Individual channel properties for the AMUX channel.
- */
-int32_t qpnp_vadc_configure(
- struct qpnp_adc_amux_properties *chan_prop);
-
-/**
* qpnp_adc_scale_default() - Scales the pre-calibrated digital output
* of an ADC to the ADC reference and compensates for the
* gain and offset.
@@ -1234,4 +1255,65 @@
{ return -ENXIO; }
#endif
+/* Public API */
+#if defined(CONFIG_THERMAL_QPNP_ADC_TM) \
+ || defined(CONFIG_THERMAL_QPNP_ADC_TM_MODULE)
+/**
+ * qpnp_adc_tm_usbid_configure() - Configures Channel 0 of VADC_BTM to
+ * monitor USB_ID channel using 100k internal pull-up.
+ * USB driver passes the high/low voltage threshold along
+ * with the notification callback once the set thresholds
+ * are crossed.
+ * @param: Structure pointer of qpnp_adc_tm_usbid_param type.
+ * Clients pass the low/high voltage along with the threshold
+ * notification callback.
+ */
+int32_t qpnp_adc_tm_usbid_configure(struct qpnp_adc_tm_usbid_param *param);
+/**
+ * qpnp_adc_tm_usbid_end() - Disables the monitoring of channel 0 thats
+ * assigned for monitoring USB_ID. Disables the low/high
+ * threshold activation for channel 0 as well.
+ * @param: none.
+ */
+int32_t qpnp_adc_tm_usbid_end(void);
+/**
+ * qpnp_adc_tm_usbid_configure() - Configures Channel 1 of VADC_BTM to
+ * monitor batt_therm channel using 100k internal pull-up.
+ * Battery driver passes the high/low voltage threshold along
+ * with the notification callback once the set thresholds
+ * are crossed.
+ * @param: Structure pointer of qpnp_adc_tm_btm_param type.
+ * Clients pass the low/high temperature along with the threshold
+ * notification callback.
+ */
+int32_t qpnp_adc_tm_btm_configure(struct qpnp_adc_tm_btm_param *param);
+/**
+ * qpnp_adc_tm_btm_end() - Disables the monitoring of channel 1 thats
+ * assigned for monitoring batt_therm. Disables the low/high
+ * threshold activation for channel 1 as well.
+ * @param: none.
+ */
+int32_t qpnp_adc_tm_btm_end(void);
+/**
+ * qpnp_adc_tm_is_ready() - Clients can use this API to check if the
+ * device is ready to use.
+ * @result: 0 on success and -EPROBE_DEFER when probe for the device
+ * has not occured.
+ */
+int32_t qpnp_adc_tm_is_ready(void);
+#else
+static inline int32_t qpnp_adc_tm_usbid_configure(
+ struct qpnp_adc_tm_usbid_param *param)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_tm_usbid_end(void)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_tm_btm_configure(
+ struct qpnp_adc_tm_btm_param *param)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_tm_btm_end(void)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_tm_is_ready(void)
+{ return -ENXIO; }
+#endif
+
#endif
diff --git a/include/linux/regulator/krait-regulator.h b/include/linux/regulator/krait-regulator.h
index eb1c3fd..9806225 100644
--- a/include/linux/regulator/krait-regulator.h
+++ b/include/linux/regulator/krait-regulator.h
@@ -22,7 +22,17 @@
* should be called from appropriate initialization code. Returns 0 on
* success and error on failure.
*/
+
+#ifdef CONFIG_ARCH_MSM8974
int __init krait_power_init(void);
void secondary_cpu_hs_init(void *base_ptr);
+#else
+static inline int __init krait_power_init(void)
+{
+ return -ENOSYS;
+}
+
+static inline void secondary_cpu_hs_init(void *base_ptr) {}
+#endif
#endif
diff --git a/include/linux/smsc3503.h b/include/linux/smsc3503.h
index 66ba003..857ad1f 100644
--- a/include/linux/smsc3503.h
+++ b/include/linux/smsc3503.h
@@ -43,6 +43,8 @@
struct smsc_hub_platform_data {
unsigned hub_reset;
+ unsigned refclk_gpio;
+ unsigned int_gpio;
};
#endif
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 5b7820d..bcbdec4 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -394,6 +394,10 @@
struct msm_hsic_host_platform_data {
unsigned strobe;
unsigned data;
+ bool ignore_cal_pad_config;
+ int strobe_pad_offset;
+ int data_pad_offset;
+
struct msm_bus_scale_pdata *bus_scale_table;
unsigned log2_irq_thresh;
@@ -479,12 +483,35 @@
MAX_BAMS,
};
+/**
+ * struct usb_ext_notification: event notification structure
+ * @notify: pointer to client function to call when ID event is detected.
+ * The last parameter is provided by driver to be called back when
+ * external client indicates it is done using the USB. This function
+ * should return 0 if handled successfully, otherise an error code.
+ * @ctxt: client-specific context pointer
+ *
+ * This structure should be used by clients wishing to register (via
+ * msm_register_usb_ext_notification) for event notification whenever a USB
+ * cable is plugged in and ID pin status changes. Clients must provide a
+ * callback function pointer. If this callback returns 0, the USB driver will
+ * assume the client is "taking over" the connection, and will relinquish any
+ * further processing until its callback (passed via the third parameter) is
+ * called with the online parameter set to false.
+ */
+struct usb_ext_notification {
+ int (*notify)(void *, int, void (*)(int online));
+ void *ctxt;
+};
+
#ifdef CONFIG_USB_DWC3_MSM
int msm_ep_config(struct usb_ep *ep);
int msm_ep_unconfig(struct usb_ep *ep);
int msm_data_fifo_config(struct usb_ep *ep, u32 addr, u32 size,
u8 dst_pipe_idx);
+int msm_register_usb_ext_notification(struct usb_ext_notification *info);
+
#else
static inline int msm_data_fifo_config(struct usb_ep *ep, u32 addr, u32 size,
u8 dst_pipe_idx)
@@ -501,5 +528,11 @@
{
return -ENODEV;
}
+
+static inline int msm_register_usb_ext_notification(
+ struct usb_ext_notification *info)
+{
+ return -ENODEV;
+}
#endif
#endif
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 3858022..bc25e24 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -2139,6 +2139,7 @@
};
#define V4L2_QCOM_BUF_FLAG_CODECCONFIG 0x4000
+#define V4L2_QCOM_BUF_FLAG_EOSEQ 0x8000
/* Decoder commands */
#define V4L2_DEC_CMD_START (0)
diff --git a/include/media/Kbuild b/include/media/Kbuild
index 70f6334..fc764eb 100644
--- a/include/media/Kbuild
+++ b/include/media/Kbuild
@@ -8,3 +8,4 @@
header-y += msm_mercury.h
header-y += msm_jpeg.h
header-y += msm_media_info.h
+header-y += msm_vidc.h
diff --git a/include/media/msm_media_info.h b/include/media/msm_media_info.h
index 13ce043..ab76d79 100644
--- a/include/media/msm_media_info.h
+++ b/include/media/msm_media_info.h
@@ -97,7 +97,7 @@
uv_sclines = VENUS_UV_SCANLINES(color_fmt, height);
switch (color_fmt) {
case COLOR_FMT_NV12:
- uv_alignment = 0;
+ uv_alignment = 4096;
y_plane = y_stride * y_sclines;
uv_plane = uv_stride * uv_sclines + uv_alignment;
size = y_plane + uv_plane;
diff --git a/include/media/msm_vidc.h b/include/media/msm_vidc.h
index 0fd11a3..4261d34 100644
--- a/include/media/msm_vidc.h
+++ b/include/media/msm_vidc.h
@@ -1,19 +1,8 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * 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_VIDC_H_
#define _MSM_VIDC_H_
+#ifdef __KERNEL__
+
#include <linux/poll.h>
#include <linux/videodev2.h>
@@ -71,3 +60,59 @@
int msm_vidc_wait(void *instance);
int msm_vidc_s_parm(void *instance, struct v4l2_streamparm *a);
#endif
+struct msm_vidc_interlace_payload {
+ unsigned int format;
+};
+struct msm_vidc_framerate_payload {
+ unsigned int frame_rate;
+};
+struct msm_vidc_ts_payload {
+ unsigned int timestamp_hi;
+ unsigned int timestamp_lo;
+};
+struct msm_vidc_concealmb_payload {
+ unsigned int num_mbs;
+};
+struct msm_vidc_recoverysei_payload {
+ unsigned int flags;
+};
+struct msm_vidc_panscan_window {
+ unsigned int panscan_height_offset;
+ unsigned int panscan_width_offset;
+ unsigned int panscan_window_width;
+ unsigned int panscan_window_height;
+};
+struct msm_vidc_panscan_window_payload {
+ unsigned int num_panscan_windows;
+ struct msm_vidc_panscan_window wnd[1];
+};
+enum msm_vidc_extradata_type {
+ EXTRADATA_NONE = 0x00000000,
+ EXTRADATA_MB_QUANTIZATION = 0x00000001,
+ EXTRADATA_INTERLACE_VIDEO = 0x00000002,
+ EXTRADATA_VC1_FRAMEDISP = 0x00000003,
+ EXTRADATA_VC1_SEQDISP = 0x00000004,
+ EXTRADATA_TIMESTAMP = 0x00000005,
+ EXTRADATA_S3D_FRAME_PACKING = 0x00000006,
+ EXTRADATA_FRAME_RATE = 0x00000007,
+ EXTRADATA_PANSCAN_WINDOW = 0x00000008,
+ EXTRADATA_RECOVERY_POINT_SEI = 0x00000009,
+ EXTRADATA_MULTISLICE_INFO = 0x7F100000,
+ EXTRADATA_NUM_CONCEALED_MB = 0x7F100001,
+ EXTRADATA_INDEX = 0x7F100002,
+ EXTRADATA_METADATA_FILLER = 0x7FE00002,
+};
+enum msm_vidc_interlace_type {
+ INTERLACE_FRAME_PROGRESSIVE = 0x01,
+ INTERLACE_INTERLEAVE_FRAME_TOPFIELDFIRST = 0x02,
+ INTERLACE_INTERLEAVE_FRAME_BOTTOMFIELDFIRST = 0x04,
+ INTERLACE_FRAME_TOPFIELDFIRST = 0x08,
+ INTERLACE_FRAME_BOTTOMFIELDFIRST = 0x10,
+};
+enum msm_vidc_recovery_sei {
+ FRAME_RECONSTRUCTION_INCORRECT = 0x0,
+ FRAME_RECONSTRUCTION_CORRECT = 0x01,
+ FRAME_RECONSTRUCTION_APPROXIMATELY_CORRECT = 0x02,
+};
+
+#endif
diff --git a/include/media/vcap_fmt.h b/include/media/vcap_fmt.h
index 369cf45..2787e8d 100644
--- a/include/media/vcap_fmt.h
+++ b/include/media/vcap_fmt.h
@@ -47,6 +47,11 @@
HAL_VCAP_RGB,
};
+enum nr_threshold_mode {
+ NR_THRESHOLD_STATIC = 0,
+ NR_THRESHOLD_DYNAMIC,
+};
+
enum nr_mode {
NR_DISABLE = 0,
NR_AUTO,
@@ -73,6 +78,7 @@
};
struct nr_param {
+ enum nr_threshold_mode threshold;
enum nr_mode mode;
enum nr_decay_ratio decay_ratio;
uint8_t window;
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 3abe85d..88acdfc 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -281,6 +281,26 @@
*/
} __packed;
+/* Defined specifically for in-band use, includes params */
+struct adm_cmd_set_pp_params_inband_v5 {
+ struct apr_hdr hdr;
+ /* LSW of parameter data payload address.*/
+ u32 payload_addr_lsw;
+ /* MSW of parameter data payload address.*/
+ u32 payload_addr_msw;
+ /* Memory map handle returned by ADM_CMD_SHARED_MEM_MAP_REGIONS */
+ /* command. If mem_map_handle is zero implies the message is in */
+ /* the payload */
+ u32 mem_map_handle;
+ /* Size in bytes of the variable payload accompanying this */
+ /* message or in shared memory. This is used for parsing the */
+ /* parameter payload. */
+ u32 payload_size;
+ /* Parameters passed for in band payload */
+ struct adm_param_data_v5 params;
+} __packed;
+
+
/* Returns the status and COPP ID to an #ADM_CMD_DEVICE_OPEN_V5 command.
*/
#define ADM_CMDRSP_DEVICE_OPEN_V5 0x00010329
@@ -6196,6 +6216,111 @@
#define VOICE_EVT_GET_PARAM_ACK 0x00011008
+/* SRS TRUMEDIA start */
+/* topology */
+#define SRS_TRUMEDIA_TOPOLOGY_ID 0x00010D90
+/* module */
+#define SRS_TRUMEDIA_MODULE_ID 0x10005010
+/* parameters */
+#define SRS_TRUMEDIA_PARAMS 0x10005011
+#define SRS_TRUMEDIA_PARAMS_WOWHD 0x10005012
+#define SRS_TRUMEDIA_PARAMS_CSHP 0x10005013
+#define SRS_TRUMEDIA_PARAMS_HPF 0x10005014
+#define SRS_TRUMEDIA_PARAMS_PEQ 0x10005015
+#define SRS_TRUMEDIA_PARAMS_HL 0x10005016
+
+#define SRS_ID_GLOBAL 0x00000001
+#define SRS_ID_WOWHD 0x00000002
+#define SRS_ID_CSHP 0x00000003
+#define SRS_ID_HPF 0x00000004
+#define SRS_ID_PEQ 0x00000005
+#define SRS_ID_HL 0x00000006
+
+#define SRS_CMD_UPLOAD 0x7FFF0000
+#define SRS_PARAM_INDEX_MASK 0x80000000
+#define SRS_PARAM_OFFSET_MASK 0x3FFF0000
+#define SRS_PARAM_VALUE_MASK 0x0000FFFF
+
+struct srs_trumedia_params_GLOBAL {
+ uint8_t v1;
+ uint8_t v2;
+ uint8_t v3;
+ uint8_t v4;
+ uint8_t v5;
+ uint8_t v6;
+ uint8_t v7;
+ uint8_t v8;
+} __packed;
+
+struct srs_trumedia_params_WOWHD {
+ uint32_t v1;
+ uint16_t v2;
+ uint16_t v3;
+ uint16_t v4;
+ uint16_t v5;
+ uint16_t v6;
+ uint16_t v7;
+ uint16_t v8;
+ uint16_t v____A1;
+ uint32_t v9;
+ uint16_t v10;
+ uint16_t v11;
+ uint32_t v12[16];
+} __packed;
+
+struct srs_trumedia_params_CSHP {
+ uint32_t v1;
+ uint16_t v2;
+ uint16_t v3;
+ uint16_t v4;
+ uint16_t v5;
+ uint16_t v6;
+ uint16_t v____A1;
+ uint32_t v7;
+ uint16_t v8;
+ uint16_t v9;
+ uint32_t v10[16];
+} __packed;
+
+struct srs_trumedia_params_HPF {
+ uint32_t v1;
+ uint32_t v2[26];
+} __packed;
+
+struct srs_trumedia_params_PEQ {
+ uint32_t v1;
+ uint16_t v2;
+ uint16_t v3;
+ uint16_t v4;
+ uint16_t v____A1;
+ uint32_t v5[26];
+ uint32_t v6[26];
+} __packed;
+
+struct srs_trumedia_params_HL {
+ uint16_t v1;
+ uint16_t v2;
+ uint16_t v3;
+ uint16_t v____A1;
+ int32_t v4;
+ uint32_t v5;
+ uint16_t v6;
+ uint16_t v____A2;
+ uint32_t v7;
+} __packed;
+
+struct srs_trumedia_params {
+ struct srs_trumedia_params_GLOBAL global;
+ struct srs_trumedia_params_WOWHD wowhd;
+ struct srs_trumedia_params_CSHP cshp;
+ struct srs_trumedia_params_HPF hpf;
+ struct srs_trumedia_params_PEQ peq;
+ struct srs_trumedia_params_HL hl;
+} __packed;
+/* SRS TruMedia end */
+
+
+
/* ERROR CODES */
/* Success. The operation completed with no errors. */
#define ADSP_EOK 0x00000000
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index bfd7208..5afbfad 100644
--- a/include/sound/apr_audio.h
+++ b/include/sound/apr_audio.h
@@ -697,18 +697,6 @@
#define ASM_OPEN_READ_PERF_MODE_BIT (1<<29)
#define ADM_MULTI_CH_COPP_OPEN_PERF_MODE_BIT (1<<13)
-/* SRS TRUMEDIA GUIDS */
-/* topology */
-#define SRS_TRUMEDIA_TOPOLOGY_ID 0x00010D90
-/* module */
-#define SRS_TRUMEDIA_MODULE_ID 0x10005010
-/* parameters */
-#define SRS_TRUMEDIA_PARAMS 0x10005011
-#define SRS_TRUMEDIA_PARAMS_WOWHD 0x10005012
-#define SRS_TRUMEDIA_PARAMS_CSHP 0x10005013
-#define SRS_TRUMEDIA_PARAMS_HPF 0x10005014
-#define SRS_TRUMEDIA_PARAMS_PEQ 0x10005015
-#define SRS_TRUMEDIA_PARAMS_HL 0x10005016
#define ASM_MAX_EQ_BANDS 12
@@ -1767,18 +1755,36 @@
#define ADSP_ENOTIMPL 0x00000011 /* Operation is not implemented. */
#define ADSP_ENEEDMORE 0x00000012 /* Operation needs more data or resources*/
-/* SRS TRUMEDIA start */
-#define SRS_ID_GLOBAL 0x00000001
-#define SRS_ID_WOWHD 0x00000002
-#define SRS_ID_CSHP 0x00000003
-#define SRS_ID_HPF 0x00000004
-#define SRS_ID_PEQ 0x00000005
-#define SRS_ID_HL 0x00000006
+/* SRS TRUMEDIA GUIDS */
+#define SRS_TRUMEDIA_TOPOLOGY_ID 0x00010D90
+#define SRS_TRUMEDIA_MODULE_ID 0x10005010
+#define SRS_TRUMEDIA_PARAMS 0x10005011
+#define SRS_TRUMEDIA_PARAMS_WOWHD 0x10005012
+#define SRS_TRUMEDIA_PARAMS_CSHP 0x10005013
+#define SRS_TRUMEDIA_PARAMS_HPF 0x10005014
+#define SRS_TRUMEDIA_PARAMS_PEQ 0x10005015
+#define SRS_TRUMEDIA_PARAMS_HL 0x10005016
-#define SRS_CMD_UPLOAD 0x7FFF0000
-#define SRS_PARAM_INDEX_MASK 0x80000000
-#define SRS_PARAM_OFFSET_MASK 0x3FFF0000
-#define SRS_PARAM_VALUE_MASK 0x0000FFFF
+/* SRS STUDIO SOUND 3D GUIDS */
+#define SRS_SS3D_TOPOLOGY_ID 0x00010720
+#define SRS_SS3D_MODULE_ID 0x10005020
+#define SRS_SS3D_PARAMS 0x10005021
+#define SRS_SS3D_PARAMS_CTRL 0x10005022
+#define SRS_SS3D_PARAMS_FILTER 0x10005023
+
+/* SRS ALSA CMD MASKS */
+#define SRS_CMD_UPLOAD 0x7FFF0000
+#define SRS_PARAM_INDEX_MASK 0x80000000
+#define SRS_PARAM_OFFSET_MASK 0x3FFF0000
+#define SRS_PARAM_VALUE_MASK 0x0000FFFF
+
+/* SRS TRUMEDIA start */
+#define SRS_ID_GLOBAL 0x00000001
+#define SRS_ID_WOWHD 0x00000002
+#define SRS_ID_CSHP 0x00000003
+#define SRS_ID_HPF 0x00000004
+#define SRS_ID_PEQ 0x00000005
+#define SRS_ID_HL 0x00000006
struct srs_trumedia_params_GLOBAL {
uint8_t v1;
@@ -1856,7 +1862,41 @@
struct srs_trumedia_params_PEQ peq;
struct srs_trumedia_params_HL hl;
} __packed;
+
int srs_trumedia_open(int port_id, int srs_tech_id, void *srs_params);
/* SRS TruMedia end */
+/* SRS Studio Sound 3D start */
+#define SRS_ID_SS3D_GLOBAL 0x00000001
+#define SRS_ID_SS3D_CTRL 0x00000002
+#define SRS_ID_SS3D_FILTER 0x00000003
+
+struct srs_SS3D_params_GLOBAL {
+ uint8_t v1;
+ uint8_t v2;
+ uint8_t v3;
+ uint8_t v4;
+ uint8_t v5;
+ uint8_t v6;
+ uint8_t v7;
+ uint8_t v8;
+} __packed;
+
+struct srs_SS3D_ctrl_params {
+ uint8_t v[236];
+} __packed;
+
+struct srs_SS3D_filter_params {
+ uint8_t v[28 + 2752];
+} __packed;
+
+struct srs_SS3D_params {
+ struct srs_SS3D_params_GLOBAL global;
+ struct srs_SS3D_ctrl_params ss3d;
+ struct srs_SS3D_filter_params ss3d_f;
+} __packed;
+
+int srs_ss3d_open(int port_id, int srs_tech_id, void *srs_params);
+/* SRS Studio Sound 3D end */
+
#endif /*_APR_AUDIO_H_*/
diff --git a/include/sound/q6adm-v2.h b/include/sound/q6adm-v2.h
index 9c43d09..fdc3cb9 100644
--- a/include/sound/q6adm-v2.h
+++ b/include/sound/q6adm-v2.h
@@ -27,6 +27,8 @@
unsigned int session_id;
};
+int srs_trumedia_open(int port_id, int srs_tech_id, void *srs_params);
+
int adm_open(int port, int path, int rate, int mode, int topology);
int adm_multi_ch_copp_open(int port, int path, int rate, int mode,
diff --git a/mm/filemap.c b/mm/filemap.c
index 79c4b2b..8ed5c5c 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -2343,9 +2343,17 @@
if (page)
goto found;
+retry:
page = __page_cache_alloc(gfp_mask & ~gfp_notmask);
if (!page)
return NULL;
+
+ if (is_cma_pageblock(page)) {
+ __free_page(page);
+ gfp_notmask |= __GFP_MOVABLE;
+ goto retry;
+ }
+
status = add_to_page_cache_lru(page, mapping, index,
GFP_KERNEL & ~gfp_notmask);
if (unlikely(status)) {
diff --git a/mm/memory.c b/mm/memory.c
index 174fcaa..c130853 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -49,6 +49,7 @@
#include <linux/rmap.h>
#include <linux/export.h>
#include <linux/delayacct.h>
+#include <linux/delay.h>
#include <linux/init.h>
#include <linux/writeback.h>
#include <linux/memcontrol.h>
@@ -2912,6 +2913,16 @@
entry = pte_to_swp_entry(orig_pte);
if (unlikely(non_swap_entry(entry))) {
if (is_migration_entry(entry)) {
+#ifdef CONFIG_DMA_CMA
+ /*
+ * FIXME: mszyprow: cruel, brute-force method for
+ * letting cma/migration to finish it's job without
+ * stealing the lock migration_entry_wait() and creating
+ * a live-lock on the faulted page
+ * (page->_count == 2 migration failure issue)
+ */
+ mdelay(10);
+#endif
migration_entry_wait(mm, pmd, address);
} else if (is_hwpoison_entry(entry)) {
ret = VM_FAULT_HWPOISON;
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index c642286..bd3f0f3 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -5682,7 +5682,7 @@
};
INIT_LIST_HEAD(&cc.migratepages);
- migrate_prep_local();
+ migrate_prep();
while (pfn < end || !list_empty(&cc.migratepages)) {
if (fatal_signal_pending(current)) {
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index 9669d4a..8cec741 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -397,8 +397,10 @@
if (sco_pi(sk)->conn) {
sk->sk_state = BT_DISCONN;
sco_sock_set_timer(sk, SCO_DISCONN_TIMEOUT);
- hci_conn_put(sco_pi(sk)->conn->hcon);
- sco_pi(sk)->conn->hcon = NULL;
+ if (sco_pi(sk)->conn->hcon != NULL) {
+ hci_conn_put(sco_pi(sk)->conn->hcon);
+ sco_pi(sk)->conn->hcon = NULL;
+ }
} else
sco_chan_del(sk, ECONNRESET);
break;
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index a1dce8a..49650e9 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -184,6 +184,17 @@
To compile it as a module, choose M here. If unsure, say N.
+config IP_NF_TARGET_NATTYPE_MODULE
+ tristate "NATTYPE target support"
+ depends on NF_NAT
+ default m if NETFILTER_ADVANCED=n
+ help
+ NATTYPE is a special case of NAT: used to support FULL Cone NAT
+ and ADDRESS Restricted Cone NAT. All incoming connections are
+ allowed if there is an outgoing connection using that port.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
config IP_NF_TARGET_NETMAP
tristate "NETMAP target support"
depends on NF_NAT
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index 2177507..291934b 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -55,6 +55,7 @@
obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o
obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o
obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
+obj-$(CONFIG_IP_NF_TARGET_NATTYPE_MODULE) += ipt_NATTYPE.o
obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o
obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o
diff --git a/net/ipv4/netfilter/ipt_NATTYPE.c b/net/ipv4/netfilter/ipt_NATTYPE.c
new file mode 100644
index 0000000..6b28794
--- /dev/null
+++ b/net/ipv4/netfilter/ipt_NATTYPE.c
@@ -0,0 +1,608 @@
+/*
+ * net/ipv4/netfilter/ipt_NATTYPE.c
+ * Endpoint Independent, Address Restricted and Port-Address Restricted
+ * NAT types' kernel side implementation.
+ *
+ * (C) Copyright 2011, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port is free software: you can redistribute
+ * it and/or modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Ubicom32 Linux Kernel Port is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Ubicom32 Linux Kernel Port. If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from
+ * Cameo's implementation(with many thanks):
+ */
+#include <linux/types.h>
+#include <linux/ip.h>
+#include <linux/udp.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/module.h>
+#include <net/protocol.h>
+#include <net/checksum.h>
+#include <net/ip.h>
+#include <linux/tcp.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_core.h>
+#include <net/netfilter/nf_nat_rule.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter_ipv4/ipt_NATTYPE.h>
+#include <linux/atomic.h>
+
+#if !defined(NATTYPE_DEBUG)
+#define DEBUGP(type, args...)
+#else
+static const char * const types[] = {"TYPE_PORT_ADDRESS_RESTRICTED",
+ "TYPE_ENDPOINT_INDEPENDENT",
+ "TYPE_ADDRESS_RESTRICTED"};
+static const char * const modes[] = {"MODE_DNAT", "MODE_FORWARD_IN",
+ "MODE_FORWARD_OUT"};
+#define DEBUGP(args...) printk(KERN_DEBUG args);
+#endif
+
+/*
+ * TODO: Add magic value checks to data structure.
+ */
+struct ipt_nattype {
+ struct list_head list;
+ struct timer_list timeout;
+ unsigned short proto; /* Protocol: TCP or UDP */
+ struct nf_nat_ipv4_range range; /* LAN side source information */
+ unsigned short nat_port; /* Routed NAT port */
+ unsigned int dest_addr; /* Original egress packets destination addr */
+ unsigned short dest_port;/* Original egress packets destination port */
+};
+
+/*
+ * TODO: It might be better to use a hash table for performance in
+ * heavy traffic.
+ */
+static LIST_HEAD(nattype_list);
+static DEFINE_SPINLOCK(nattype_lock);
+
+/*
+ * nattype_nte_debug_print()
+ */
+static void nattype_nte_debug_print(const struct ipt_nattype *nte,
+ const char *s)
+{
+#if defined(NATTYPE_DEBUG)
+ DEBUGP("%p: %s - proto[%d], src[%pI4:%d], nat[<x>:%d], dest[%pI4:%d]\n",
+ nte, s, nte->proto,
+ &nte->range.min_ip, ntohs(nte->range.min.all),
+ ntohs(nte->nat_port),
+ &nte->dest_addr, ntohs(nte->dest_port));
+#endif
+}
+
+/*
+ * nattype_free()
+ * Free the object.
+ */
+static void nattype_free(struct ipt_nattype *nte)
+{
+ nattype_nte_debug_print(nte, "free");
+ kfree(nte);
+}
+
+/*
+ * nattype_refresh_timer()
+ * Refresh the timer for this object.
+ */
+static bool nattype_refresh_timer(struct ipt_nattype *nte)
+{
+
+ if (del_timer(&nte->timeout)) {
+ nte->timeout.expires = jiffies + NATTYPE_TIMEOUT * HZ;
+ add_timer(&nte->timeout);
+ return true;
+ }
+ return false;
+}
+
+/*
+ * nattype_timer_timeout()
+ * The timer has gone off, self-destruct
+ */
+static void nattype_timer_timeout(unsigned long in_nattype)
+{
+ struct ipt_nattype *nte = (void *) in_nattype;
+
+ /*
+ * The race with list deletion is solved by ensuring
+ * that either this code or the list deletion code
+ * but not both will remove the oject.
+ */
+ nattype_nte_debug_print(nte, "timeout");
+ spin_lock_bh(&nattype_lock);
+ list_del(&nte->list);
+ spin_unlock_bh(&nattype_lock);
+ nattype_free(nte);
+}
+
+/*
+ * nattype_packet_in_match()
+ * Ingress packet, try to match with this nattype entry.
+ */
+static bool nattype_packet_in_match(const struct ipt_nattype *nte,
+ struct sk_buff *skb,
+ const struct ipt_nattype_info *info)
+{
+ const struct iphdr *iph = ip_hdr(skb);
+ uint16_t dst_port = 0;
+
+ /*
+ * If the protocols are not the same, no sense in looking
+ * further.
+ */
+ if (nte->proto != iph->protocol) {
+ DEBUGP("nattype_packet_in_match: protocol failed: nte proto:" \
+ " %d, packet proto: %d\n",
+ nte->proto, iph->protocol);
+ return false;
+ }
+
+ /*
+ * In ADDRESS_RESTRICT, the egress destination must match the source
+ * of this ingress packet.
+ */
+ if (info->type == TYPE_ADDRESS_RESTRICTED) {
+ if (nte->dest_addr != iph->saddr) {
+ DEBUGP("nattype_packet_in_match: dest/src check" \
+ " failed: dest_addr: %pI4, src dest: %pI4\n",
+ &nte->dest_addr, &iph->saddr);
+ return false;
+ }
+ }
+
+ /*
+ * Obtain the destination port value for TCP or UDP. The nattype
+ * entries are stored in native (not host).
+ */
+ if (iph->protocol == IPPROTO_TCP) {
+ struct tcphdr _tcph;
+ struct tcphdr *tcph;
+ tcph = skb_header_pointer(skb, ip_hdrlen(skb),
+ sizeof(_tcph), &_tcph);
+ if (!tcph)
+ return false;
+ dst_port = tcph->dest;
+ } else if (iph->protocol == IPPROTO_UDP) {
+ struct udphdr _udph;
+ struct udphdr *udph;
+ udph = skb_header_pointer(skb, ip_hdrlen(skb),
+ sizeof(_udph), &_udph);
+ if (!udph)
+ return false;
+ dst_port = udph->dest;
+ }
+
+ /*
+ * Our NAT port must match the ingress pacekt's destination packet.
+ */
+ if (nte->nat_port != dst_port) {
+ DEBUGP("nattype_packet_in_match fail: nat port: %d," \
+ " dest_port: %d\n",
+ ntohs(nte->nat_port), ntohs(dst_port));
+ return false;
+ }
+
+ /*
+ * In either EI or AR mode, the ingress packet's src port
+ * can be anything.
+ */
+ nattype_nte_debug_print(nte, "INGRESS MATCH");
+ return true;
+}
+
+/*
+ * nattype_compare
+ * Compare two entries, return true if relevant fields are the same.
+ */
+static bool nattype_compare(struct ipt_nattype *n1, struct ipt_nattype *n2)
+{
+ /*
+ * Protocol compare.
+ */
+ if (n1->proto != n2->proto) {
+ DEBUGP("nattype_compare: protocol mismatch: %d:%d\n",
+ n1->proto, n2->proto);
+ return false;
+ }
+
+ /*
+ * LAN Source compare.
+ * Since we always keep min/max values the same,
+ * just compare the min values.
+ */
+ if (n1->range.min_ip != n2->range.min_ip) {
+ DEBUGP("nattype_compare: r.min_ip mismatch: %pI4:%pI4\n",
+ &n1->range.min_ip, &n2->range.min_ip);
+ return false;
+ }
+
+ if (n1->range.min.all != n2->range.min.all) {
+ DEBUGP("nattype_compare: r.min mismatch: %d:%d\n",
+ ntohs(n1->range.min.all),
+ ntohs(n2->range.min.all));
+ return false;
+ }
+
+ /*
+ * NAT port
+ */
+ if (n1->nat_port != n2->nat_port) {
+ DEBUGP("nattype_compare: nat_port mistmatch: %d:%d\n",
+ ntohs(n1->nat_port), ntohs(n2->nat_port));
+ return false;
+ }
+
+ /*
+ * Destination compare
+ */
+ if (n1->dest_addr != n2->dest_addr) {
+ DEBUGP("nattype_compare: dest_addr mismatch: %pI4:%pI4\n",
+ &n1->dest_addr, &n2->dest_addr);
+ return false;
+ }
+
+ if (n1->dest_port != n2->dest_port) {
+ DEBUGP("nattype_compare: dest_port mismatch: %d:%d\n",
+ ntohs(n1->dest_port), ntohs(n2->dest_port));
+ return false;
+ }
+ return true;
+}
+
+/*
+ * nattype_nat()
+ * Ingress packet on PRE_ROUTING hook, find match, update conntrack
+ * to allow
+ */
+static unsigned int nattype_nat(struct sk_buff *skb,
+ const struct xt_action_param *par)
+{
+ struct ipt_nattype *nte;
+
+ if (par->hooknum != NF_INET_PRE_ROUTING)
+ return XT_CONTINUE;
+ spin_lock_bh(&nattype_lock);
+ list_for_each_entry(nte, &nattype_list, list) {
+ struct nf_conn *ct;
+ enum ip_conntrack_info ctinfo;
+ struct nf_nat_ipv4_range newrange;
+ unsigned int ret;
+
+ if (!nattype_packet_in_match(nte, skb, par->targinfo))
+ continue;
+
+ /*
+ * Copy the LAN source data into the ingress' pacekts
+ * conntrack in the reply direction.
+ */
+ newrange = nte->range;
+ spin_unlock_bh(&nattype_lock);
+
+ /*
+ * Find the ingress packet's conntrack.
+ */
+ ct = nf_ct_get(skb, &ctinfo);
+ if (!ct) {
+ DEBUGP("ingress packet conntrack not found\n");
+ return XT_CONTINUE;
+ }
+
+ /*
+ * Expand the ingress conntrack to include the reply as source
+ */
+ DEBUGP("Expand ingress conntrack=%p, type=%d, src[%pI4:%d]\n",
+ ct, ctinfo, &newrange.min_ip, ntohs(newrange.min.all));
+ ret = nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_DST);
+ DEBUGP("Expand returned: %d\n", ret);
+ return ret;
+ }
+ spin_unlock_bh(&nattype_lock);
+ return XT_CONTINUE;
+}
+
+/*
+ * nattype_forward()
+ * Ingress and Egress packet forwarding hook
+ */
+static unsigned int nattype_forward(struct sk_buff *skb,
+ const struct xt_action_param *par)
+{
+ const struct iphdr *iph = ip_hdr(skb);
+ void *protoh = (void *)iph + iph->ihl * 4;
+ struct ipt_nattype *nte;
+ struct ipt_nattype *nte2;
+ struct nf_conn *ct;
+ enum ip_conntrack_info ctinfo;
+ const struct ipt_nattype_info *info = par->targinfo;
+ uint16_t nat_port;
+
+ if (par->hooknum != NF_INET_FORWARD)
+ return XT_CONTINUE;
+
+ /*
+ * Ingress packet, refresh the timer if we find an entry.
+ */
+ if (info->mode == MODE_FORWARD_IN) {
+ spin_lock_bh(&nattype_lock);
+ list_for_each_entry(nte, &nattype_list, list) {
+ /*
+ * Compare the ingress packet with the existing
+ * entries looking for a match.
+ */
+ if (!nattype_packet_in_match(nte, skb, info))
+ continue;
+
+ /*
+ * Refresh the timer, if we fail, break
+ * out and forward fail as though we never
+ * found the entry.
+ */
+ if (!nattype_refresh_timer(nte))
+ break;
+
+ /*
+ * The entry is found and refreshed, the
+ * entry values should not change so print
+ * them outside the lock.
+ */
+ spin_unlock_bh(&nattype_lock);
+ nattype_nte_debug_print(nte, "refresh");
+ DEBUGP("FORWARD_IN_ACCEPT\n");
+ return NF_ACCEPT;
+ }
+ spin_unlock_bh(&nattype_lock);
+ DEBUGP("FORWARD_IN_FAIL\n");
+ return XT_CONTINUE;
+ }
+
+ /*
+ * Egress packet, create a new rule in our list. If conntrack does
+ * not have an entry, skip this packet.
+ */
+ ct = nf_ct_get(skb, &ctinfo);
+ if (!ct || (ctinfo == IP_CT_NEW && ctinfo == IP_CT_RELATED))
+ return XT_CONTINUE;
+
+ nat_port = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all;
+
+ /*
+ * Allocate a new entry
+ */
+ nte = kzalloc(sizeof(struct ipt_nattype), GFP_ATOMIC | __GFP_NOWARN);
+ if (!nte) {
+ DEBUGP("kernel malloc fail\n");
+ return XT_CONTINUE;
+ }
+
+ INIT_LIST_HEAD(&nte->list);
+
+ nte->proto = iph->protocol;
+ nte->nat_port = nat_port;
+ nte->dest_addr = iph->daddr;
+ nte->range.max_ip = nte->range.min_ip = iph->saddr;
+
+ /*
+ * TOOD: Would it be better to get this information from the
+ * conntrack instead of the headers.
+ */
+ if (iph->protocol == IPPROTO_TCP) {
+ nte->range.max.tcp.port = nte->range.min.tcp.port =
+ ((struct tcphdr *)protoh)->source;
+ nte->dest_port = ((struct tcphdr *)protoh)->dest;
+ } else if (iph->protocol == IPPROTO_UDP) {
+ nte->range.max.udp.port = nte->range.min.udp.port =
+ ((struct udphdr *)protoh)->source;
+ nte->dest_port = ((struct udphdr *)protoh)->dest;
+ }
+ nte->range.flags = (NF_NAT_RANGE_MAP_IPS |
+ NF_NAT_RANGE_PROTO_SPECIFIED);
+
+ /*
+ * Initilize the self-destruct timer.
+ */
+ init_timer(&nte->timeout);
+ nte->timeout.data = (unsigned long)nte;
+ nte->timeout.function = nattype_timer_timeout;
+
+ /*
+ * We have created the new nte; however, it might not be unique.
+ * Search the list for a matching entry. If found, throw away
+ * the new entry and refresh the old. If not found, atomically
+ * insert the new entry on the list.
+ */
+ spin_lock_bh(&nattype_lock);
+ list_for_each_entry(nte2, &nattype_list, list) {
+ if (!nattype_compare(nte, nte2))
+ continue;
+
+ /*
+ * If we can not refresh this entry, insert our new
+ * entry as this one is timed out and will be removed
+ * from the list shortly.
+ */
+ if (!nattype_refresh_timer(nte2))
+ break;
+
+ /*
+ * Found and refreshed an existing entry. Its values
+ * do not change so print the values outside of the lock.
+ *
+ * Free up the new entry.
+ */
+ spin_unlock_bh(&nattype_lock);
+ nattype_nte_debug_print(nte2, "refresh");
+ nattype_free(nte);
+ return XT_CONTINUE;
+ }
+
+ /*
+ * Add the new entry to the list.
+ */
+ nte->timeout.expires = jiffies + (NATTYPE_TIMEOUT * HZ);
+ add_timer(&nte->timeout);
+ list_add(&nte->list, &nattype_list);
+ spin_unlock_bh(&nattype_lock);
+ nattype_nte_debug_print(nte, "ADD");
+ return XT_CONTINUE;
+}
+
+/*
+ * nattype_target()
+ * One of the iptables hooks has a packet for us to analyze, do so.
+ */
+static unsigned int nattype_target(struct sk_buff *skb,
+ const struct xt_action_param *par)
+{
+ const struct ipt_nattype_info *info = par->targinfo;
+ const struct iphdr *iph = ip_hdr(skb);
+
+ /*
+ * The default behavior for Linux is PORT and ADDRESS restricted. So
+ * we do not need to create rules/entries if we are in that mode.
+ */
+ if (info->type == TYPE_PORT_ADDRESS_RESTRICTED)
+ return XT_CONTINUE;
+
+ /*
+ * Check if we have enough data in the skb.
+ */
+ if (skb->len < ip_hdrlen(skb))
+ return XT_CONTINUE;
+
+ /*
+ * We can not perform endpoint filtering on anything but UDP and TCP.
+ */
+ if ((iph->protocol != IPPROTO_TCP) && (iph->protocol != IPPROTO_UDP))
+ return XT_CONTINUE;
+
+ /*
+ * Check for LAND attack and ignore.
+ */
+ if (iph->daddr == iph->saddr)
+ return XT_CONTINUE;
+
+ /*
+ * Check that we have valid source and destination addresses.
+ */
+ if ((iph->daddr == (__be32)0) || (iph->saddr == (__be32)0))
+ return XT_CONTINUE;
+
+ DEBUGP("nattype_target: type = %s, mode = %s\n",
+ types[info->type], modes[info->mode]);
+
+ /*
+ * TODO: why have mode at all since par->hooknum provides
+ * this information?
+ */
+ switch (info->mode) {
+ case MODE_DNAT:
+ return nattype_nat(skb, par);
+ case MODE_FORWARD_OUT:
+ case MODE_FORWARD_IN:
+ return nattype_forward(skb, par);
+ }
+ return XT_CONTINUE;
+}
+
+/*
+ * nattype_check()
+ * check info (mode/type) set by iptables.
+ */
+static int nattype_check(const struct xt_tgchk_param *par)
+{
+ const struct ipt_nattype_info *info = par->targinfo;
+ struct list_head *cur, *tmp;
+
+ if ((info->type != TYPE_PORT_ADDRESS_RESTRICTED) &&
+ (info->type != TYPE_ENDPOINT_INDEPENDENT) &&
+ (info->type != TYPE_ADDRESS_RESTRICTED)) {
+ DEBUGP("nattype_check: unknown type: %d\n", info->type);
+ return -EINVAL;
+ }
+
+ if (info->mode != MODE_DNAT && info->mode != MODE_FORWARD_IN &&
+ info->mode != MODE_FORWARD_OUT) {
+ DEBUGP("nattype_check: unknown mode - %d.\n", info->mode);
+ return -EINVAL;
+ }
+
+ DEBUGP("nattype_check: type = %s, mode = %s\n",
+ types[info->type], modes[info->mode]);
+
+ if (par->hook_mask & ~((1 << NF_INET_PRE_ROUTING) |
+ (1 << NF_INET_FORWARD))) {
+ DEBUGP("nattype_check: bad hooks %x.\n", par->hook_mask);
+ return -EINVAL;
+ }
+
+ /*
+ * Remove all entries from the nattype list.
+ */
+drain:
+ spin_lock_bh(&nattype_lock);
+ list_for_each_safe(cur, tmp, &nattype_list) {
+ struct ipt_nattype *nte = (void *)cur;
+
+ /*
+ * If the timeout is in process, it will tear
+ * us down. Since it is waiting on the spinlock
+ * we have to give up the spinlock to give the
+ * timeout on another CPU a chance to run.
+ */
+ if (!del_timer(&nte->timeout)) {
+ spin_unlock_bh(&nattype_lock);
+ goto drain;
+ }
+
+ DEBUGP("%p: removing from list\n", nte);
+ list_del(&nte->list);
+ spin_unlock_bh(&nattype_lock);
+ nattype_free(nte);
+ goto drain;
+ }
+ spin_unlock_bh(&nattype_lock);
+ return 0;
+}
+
+static struct xt_target nattype = {
+ .name = "NATTYPE",
+ .family = NFPROTO_IPV4,
+ .target = nattype_target,
+ .checkentry = nattype_check,
+ .targetsize = sizeof(struct ipt_nattype_info),
+ .hooks = ((1 << NF_INET_PRE_ROUTING) |
+ (1 << NF_INET_FORWARD)),
+ .me = THIS_MODULE,
+};
+
+static int __init init(void)
+{
+ return xt_register_target(&nattype);
+}
+
+static void __exit fini(void)
+{
+ xt_unregister_target(&nattype);
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/msm_stub.c b/sound/soc/codecs/msm_stub.c
index 7e603b4..0143e51 100644
--- a/sound/soc/codecs/msm_stub.c
+++ b/sound/soc/codecs/msm_stub.c
@@ -34,7 +34,7 @@
.capture = { /* Support maximum range */
.stream_name = "Record",
.channels_min = 1,
- .channels_max = 4,
+ .channels_max = 8,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 6aa5bbb..76623b1 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -54,7 +54,8 @@
#define TAIKO_SLIM_IRQ_OVERFLOW (1 << 0)
#define TAIKO_SLIM_IRQ_UNDERFLOW (1 << 1)
#define TAIKO_SLIM_IRQ_PORT_CLOSED (1 << 2)
-
+#define TAIKO_MCLK_CLK_12P288MHZ 12288000
+#define TAIKO_MCLK_CLK_9P6HZ 9600000
enum {
AIF1_PB = 0,
AIF1_CAP,
@@ -3120,11 +3121,7 @@
static int taiko_set_dai_sysclk(struct snd_soc_dai *dai,
int clk_id, unsigned int freq, int dir)
{
- struct snd_soc_codec *codec = dai->codec;
- if (freq == TAIKO_MCLK_CLK_12P288MHZ)
- snd_soc_write(codec, TAIKO_A_CHIP_CTL, 0x04);
- else if (freq == TAIKO_MCLK_CLK_9P6HZ)
- snd_soc_write(codec, TAIKO_A_CHIP_CTL, 0x0A);
+ pr_debug("%s\n", __func__);
return 0;
}
@@ -4810,6 +4807,11 @@
taiko->aux_l_gain = 0x1F;
taiko->aux_r_gain = 0x1F;
taiko_update_reg_defaults(codec);
+ pr_debug("%s: MCLK Rate = %x\n", __func__, wcd9xxx->mclk_rate);
+ if (wcd9xxx->mclk_rate == TAIKO_MCLK_CLK_12P288MHZ)
+ snd_soc_write(codec, TAIKO_A_CHIP_CTL, 0x04);
+ else if (wcd9xxx->mclk_rate == TAIKO_MCLK_CLK_9P6HZ)
+ snd_soc_write(codec, TAIKO_A_CHIP_CTL, 0x0A);
taiko_codec_init_reg(codec);
ret = taiko_handle_pdata(taiko);
if (IS_ERR_VALUE(ret)) {
diff --git a/sound/soc/msm/apq8064.c b/sound/soc/msm/apq8064.c
index 4fe002b..a351f7b 100644
--- a/sound/soc/msm/apq8064.c
+++ b/sound/soc/msm/apq8064.c
@@ -92,7 +92,7 @@
static int msm_btsco_rate = BTSCO_RATE_8KHZ;
static int msm_btsco_ch = 1;
-
+static int hdmi_rate_variable;
static int rec_mode = INCALL_REC_MONO;
static struct clk *codec_clk;
@@ -642,11 +642,13 @@
static const char *spk_function[] = {"Off", "On"};
static const char *slim0_rx_ch_text[] = {"One", "Two"};
static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
+static const char * const hdmi_rate[] = {"Default", "Variable"};
static const struct soc_enum msm_enum[] = {
SOC_ENUM_SINGLE_EXT(2, spk_function),
SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
+ SOC_ENUM_SINGLE_EXT(2, hdmi_rate),
};
static const char *btsco_rate_text[] = {"8000", "16000"};
@@ -756,6 +758,21 @@
return 0;
}
+static int msm_hdmi_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ hdmi_rate_variable = ucontrol->value.integer.value[0];
+ pr_debug("%s: hdmi_rate_variable = %d\n", __func__, hdmi_rate_variable);
+ return 0;
+}
+
+static int msm_hdmi_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = hdmi_rate_variable;
+ return 0;
+}
+
static const struct snd_kcontrol_new tabla_msm_controls[] = {
SOC_ENUM_EXT("Speaker Function", msm_enum[0], msm_get_spk,
msm_set_spk),
@@ -769,6 +786,9 @@
msm_incall_rec_mode_get, msm_incall_rec_mode_put),
SOC_ENUM_EXT("SLIM_3_RX Channels", msm_enum[1],
msm_slim_3_rx_ch_get, msm_slim_3_rx_ch_put),
+ SOC_ENUM_EXT("HDMI RX Rate", msm_enum[3],
+ msm_hdmi_rate_get,
+ msm_hdmi_rate_put),
};
static void *def_tabla_mbhc_cal(void)
@@ -1328,7 +1348,8 @@
if (channels->max < 2)
channels->min = channels->max = 2;
- rate->min = rate->max = 48000;
+ if (!hdmi_rate_variable)
+ rate->min = rate->max = 48000;
return 0;
}
diff --git a/sound/soc/msm/mdm9615.c b/sound/soc/msm/mdm9615.c
index 7190ae9..433786d 100644
--- a/sound/soc/msm/mdm9615.c
+++ b/sound/soc/msm/mdm9615.c
@@ -316,8 +316,6 @@
static struct clk *codec_clk;
static int clk_users;
-static int mdm9615_headset_gpios_configured;
-
static struct snd_soc_jack hs_jack;
static struct snd_soc_jack button_jack;
@@ -2294,57 +2292,6 @@
},
};
-static int mdm9615_configure_headset_mic_gpios(void)
-{
- int ret;
- 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,
- };
-
- ret = gpio_request(PM8018_GPIO_PM_TO_SYS(23), "AV_SWITCH");
- if (ret) {
- pr_err("%s: Failed to request gpio %d\n", __func__,
- PM8018_GPIO_PM_TO_SYS(23));
- return ret;
- }
-
- ret = pm8xxx_gpio_config(PM8018_GPIO_PM_TO_SYS(23), ¶m);
- if (ret)
- pr_err("%s: Failed to configure gpio %d\n", __func__,
- PM8018_GPIO_PM_TO_SYS(23));
- else
- gpio_direction_output(PM8018_GPIO_PM_TO_SYS(23), 0);
-
- ret = gpio_request(PM8018_GPIO_PM_TO_SYS(35), "US_EURO_SWITCH");
- if (ret) {
- pr_err("%s: Failed to request gpio %d\n", __func__,
- PM8018_GPIO_PM_TO_SYS(35));
- gpio_free(PM8018_GPIO_PM_TO_SYS(23));
- return ret;
- }
- ret = pm8xxx_gpio_config(PM8018_GPIO_PM_TO_SYS(35), ¶m);
- if (ret)
- pr_err("%s: Failed to configure gpio %d\n", __func__,
- PM8018_GPIO_PM_TO_SYS(35));
- else
- gpio_direction_output(PM8018_GPIO_PM_TO_SYS(35), 0);
-
- return 0;
-}
-static void mdm9615_free_headset_mic_gpios(void)
-{
- if (mdm9615_headset_gpios_configured) {
- gpio_free(PM8018_GPIO_PM_TO_SYS(23));
- gpio_free(PM8018_GPIO_PM_TO_SYS(35));
- }
-}
-
static int __init mdm9615_audio_init(void)
{
int ret;
@@ -2411,12 +2358,6 @@
return ret;
}
- if (mdm9615_configure_headset_mic_gpios()) {
- pr_err("%s Fail to configure headset mic gpios\n", __func__);
- mdm9615_headset_gpios_configured = 0;
- } else
- mdm9615_headset_gpios_configured = 1;
-
/*
* Irrespective of audio interface type get virtual address
* of LPAIF registers as it may not be guaranted that I2S
@@ -2444,7 +2385,6 @@
pr_err("%s: Not the right machine type\n", __func__);
return ;
}
- mdm9615_free_headset_mic_gpios();
platform_device_unregister(mdm9615_snd_device_slim);
platform_device_unregister(mdm9615_snd_device_i2s);
kfree(mbhc_cfg.calibration);
diff --git a/sound/soc/msm/mdm9625.c b/sound/soc/msm/mdm9625.c
index b1822f6..4c7b69d 100644
--- a/sound/soc/msm/mdm9625.c
+++ b/sound/soc/msm/mdm9625.c
@@ -68,7 +68,6 @@
unsigned gpio_no;
char *gpio_name;
};
-static bool cdc_mclk_init;
static struct mutex cdc_mclk_mutex;
static int mdm9625_mi2s_rx_ch = 1;
static int mdm9625_mi2s_tx_ch = 1;
@@ -292,25 +291,6 @@
return ret;
}
-static int set_codec_mclk(struct snd_soc_pcm_runtime *rtd)
-{
- int ret = 0;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_card *card = rtd->card;
- struct mdm9625_machine_data *pdata = snd_soc_card_get_drvdata(card);
-
- if (cdc_mclk_init == true)
- return 0;
- ret = snd_soc_dai_set_sysclk(codec_dai, TAIKO_MCLK_ID, pdata->mclk_freq,
- SND_SOC_CLOCK_IN);
- if (ret < 0) {
- pr_err("%s: Set codec sys clk failed %x", __func__, ret);
- return ret;
- }
- cdc_mclk_init = true;
- return 0;
-}
-
static int mdm9625_mi2s_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -320,7 +300,6 @@
SNDRV_PCM_HW_PARAM_CHANNELS);
rate->min = rate->max = 48000;
channels->min = channels->max = mdm9625_mi2s_rx_ch;
- set_codec_mclk(rtd);
return 0;
}
@@ -333,7 +312,6 @@
SNDRV_PCM_HW_PARAM_CHANNELS);
rate->min = rate->max = 48000;
channels->min = channels->max = mdm9625_mi2s_tx_ch;
- set_codec_mclk(rtd);
return 0;
}
@@ -713,7 +691,6 @@
mutex_init(&cdc_mclk_mutex);
gpio_enable = false;
- cdc_mclk_init = false;
if (!pdev->dev.of_node) {
dev_err(&pdev->dev, "No platform supplied from device tree\n");
return -EINVAL;
diff --git a/sound/soc/msm/mpq8064.c b/sound/soc/msm/mpq8064.c
index d0bfb76..cef8659 100644
--- a/sound/soc/msm/mpq8064.c
+++ b/sound/soc/msm/mpq8064.c
@@ -30,10 +30,56 @@
#include "../codecs/wcd9310.h"
/* 8064 machine driver */
-
+#define PM8921_MPP_BASE (PM8921_GPIO_BASE + PM8921_NR_GPIOS)
+#define PM8821_NR_MPPS (4)
+#define PM8821_MPP_BASE (PM8921_MPP_BASE + PM8921_NR_MPPS)
#define PM8921_GPIO_BASE NR_GPIO_IRQS
#define PM8921_GPIO_PM_TO_SYS(pm_gpio) (pm_gpio - 1 + PM8921_GPIO_BASE)
+#define GPIO_EXPANDER_IRQ_BASE (TABLA_INTERRUPT_BASE + \
+ NR_TABLA_IRQS)
+#define GPIO_EXPANDER_GPIO_BASE (PM8821_MPP_BASE + PM8821_NR_MPPS)
+
+#define GPIO_EPM_EXPANDER_BASE GPIO_EXPANDER_GPIO_BASE
+#define SX150X_EPM_NR_GPIOS 16
+#define SX150X_EPM_NR_IRQS 8
+
+#define SX150X_EXP1_GPIO_BASE (GPIO_EPM_EXPANDER_BASE + \
+ SX150X_EPM_NR_GPIOS)
+#define SX150X_EXP1_IRQ_BASE (GPIO_EXPANDER_IRQ_BASE + \
+ SX150X_EPM_NR_IRQS)
+#define SX150X_EXP1_NR_IRQS 16
+#define SX150X_EXP1_NR_GPIOS 16
+
+#define SX150X_EXP2_GPIO_BASE (SX150X_EXP1_GPIO_BASE + \
+ SX150X_EXP1_NR_GPIOS)
+#define SX150X_EXP2_IRQ_BASE (SX150X_EXP1_IRQ_BASE + SX150X_EXP1_NR_IRQS)
+#define SX150X_EXP2_NR_IRQS 8
+#define SX150X_EXP2_NR_GPIOS 8
+
+#define SX150X_EXP3_GPIO_BASE (SX150X_EXP2_GPIO_BASE + \
+ SX150X_EXP2_NR_GPIOS)
+#define SX150X_EXP3_IRQ_BASE (SX150X_EXP2_IRQ_BASE + SX150X_EXP2_NR_IRQS)
+#define SX150X_EXP3_NR_IRQS 8
+#define SX150X_EXP3_NR_GPIOS 8
+
+#define SX150X_EXP4_GPIO_BASE (SX150X_EXP3_GPIO_BASE + \
+ SX150X_EXP3_NR_GPIOS)
+#define SX150X_EXP4_IRQ_BASE (SX150X_EXP3_IRQ_BASE + SX150X_EXP3_NR_IRQS)
+#define SX150X_EXP4_NR_IRQS 16
+#define SX150X_EXP4_NR_GPIOS 16
+
+#define SX150X_GPIO(_expander, _pin) (SX150X_EXP##_expander##_GPIO_BASE + _pin)
+
+enum {
+ SX150X_EPM,
+ SX150X_EXP1,
+ SX150X_EXP2,
+ SX150X_EXP3,
+ SX150X_EXP4,
+};
+
+
#define MPQ8064_SPK_ON 1
#define MPQ8064_SPK_OFF 0
@@ -147,6 +193,8 @@
static struct snd_soc_jack hs_jack;
static struct snd_soc_jack button_jack;
+static int detect_dtv_platform;
+
static int msm_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
bool dapm);
@@ -763,6 +811,60 @@
return ret;
}
+
+static int mpq_dtv_amp_power_up(void)
+{
+ int ret;
+ pr_debug("%s()\n", __func__);
+ ret = gpio_request(SX150X_GPIO(1, 14),
+ "DTV AMP Sleep");
+ if (ret) {
+ pr_err("%s: DTV AMP Sleep GPIO request returns %d\n",
+ __func__, ret);
+ return ret;
+ }
+ ret = gpio_direction_output(SX150X_GPIO(1, 14), 0);
+ if (ret) {
+ pr_err("%s: DTV AMP Sleep GPIO set output returns %d\n",
+ __func__, ret);
+ return ret;
+ }
+ ret = gpio_request(SX150X_GPIO(1, 13),
+ "DTV AMP Mute");
+ if (ret) {
+ pr_err("%s: DTV AMP Mute GPIO request returns %d\n",
+ __func__, ret);
+ return ret;
+ }
+ ret = gpio_direction_output(SX150X_GPIO(1, 13), 0);
+ if (ret) {
+ pr_err("%s: DTV AMP Mute GPIO set output returns %d\n",
+ __func__, ret);
+ return ret;
+ }
+ return ret;
+}
+
+static int mpq_dtv_amp_power_down(void)
+{
+ int ret;
+ pr_debug("%s()\n", __func__);
+ ret = gpio_direction_output(SX150X_GPIO(1, 14), 1);
+ if (ret) {
+ pr_err("%s: DTV AMP Sleep GPIO set output failed\n", __func__);
+ return ret;
+ }
+ gpio_free(SX150X_GPIO(1, 14));
+
+ ret = gpio_direction_output(SX150X_GPIO(1, 13), 1);
+ if (ret) {
+ pr_err("%s: DTV AMP Mute GPIO set output failed\n", __func__);
+ return ret;
+ }
+ gpio_free(SX150X_GPIO(1, 13));
+ return ret;
+}
+
static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
{
int err;
@@ -810,6 +912,57 @@
snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
+ if (detect_dtv_platform) {
+ err = gpio_request(SX150X_GPIO(1, 11),
+ "DTV AMP Gain0");
+ if (err) {
+ pr_err("%s: DTV AMP Gain0 request returns %d\n",
+ __func__, err);
+ return err;
+ }
+ err = gpio_direction_output(SX150X_GPIO(1, 11), 0);
+ if (err) {
+ pr_err("%s: DTV AMP Gain0 set output returns %d\n",
+ __func__, err);
+ return err;
+ }
+ gpio_free(SX150X_GPIO(1, 11));
+
+ err = gpio_request(SX150X_GPIO(1, 12),
+ "DTV AMP Gain1");
+ if (err) {
+ pr_err("%s: DTV AMP Gain0 request returns %d\n",
+ __func__, err);
+ return err;
+ }
+ err = gpio_direction_output(SX150X_GPIO(1, 12), 0);
+ if (err) {
+ pr_err("%s: DTV AMP Gain1 set output returns %d\n",
+ __func__, err);
+ return err;
+ }
+ gpio_free(SX150X_GPIO(1, 12));
+
+ err = gpio_request(SX150X_GPIO(1, 15),
+ "DTV AMP Status");
+ if (err) {
+ pr_err("%s: DTV AMP Status request returns %d\n",
+ __func__, err);
+ return err;
+ }
+ err = gpio_direction_input(SX150X_GPIO(1, 15));
+ if (err) {
+ pr_err("%s: DTV AMP Status set output returns %d\n",
+ __func__, err);
+ return err;
+ }
+ err = mpq_dtv_amp_power_down();
+ if (err) {
+ pr_err("%s: DTV AMP Status set output returns %d\n",
+ __func__, err);
+ return err;
+ }
+ }
return err;
}
@@ -1049,6 +1202,8 @@
{
pr_debug("%s(): substream = %s stream = %d\n", __func__,
substream->name, substream->stream);
+ if (detect_dtv_platform)
+ mpq_dtv_amp_power_up();
return 0;
}
@@ -1056,6 +1211,9 @@
{
pr_debug("%s(): substream = %s stream = %d\n", __func__,
substream->name, substream->stream);
+
+ if (detect_dtv_platform)
+ mpq_dtv_amp_power_down();
}
static int mpq8064_auxpcm_startup(struct snd_pcm_substream *substream)
@@ -1670,7 +1828,9 @@
if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
bottom_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(16);
-
+ if (machine_is_mpq8064_dtv())
+ detect_dtv_platform = 1;
+ pr_info("MPQ8064: detect_dtv_platform is %d\n", detect_dtv_platform);
mbhc_cfg.calibration = def_tabla_mbhc_cal();
if (!mbhc_cfg.calibration) {
pr_err("Calibration data allocation failed\n");
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 79ce671..841d313 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -49,7 +49,8 @@
static int fm_switch_enable;
static int fm_pcmrx_switch_enable;
-static int srs_alsa_ctrl_ever_called;
+static short int srs_alsa_ctrl_ever_called_tm;
+static short int srs_alsa_ctrl_ever_called_ss3d;
#define INT_RX_VOL_MAX_STEPS 0x2000
#define INT_RX_VOL_GAIN 0x2000
@@ -125,19 +126,13 @@
unsigned short int raw_params[1];
};
static union srs_trumedia_params_u msm_srs_trumedia_params[2];
-static int srs_port_id = -1;
-static void srs_send_params(int port_id, unsigned int techs,
+static void srs_send_params_trumedia(int port_id, unsigned int techs,
int param_block_idx) {
-
- /* only send commands to dsp if srs alsa ctrl was used
- at least one time */
- if (!srs_alsa_ctrl_ever_called)
- return;
-
pr_debug("SRS %s: called, port_id = %d, techs flags = %u,"
" paramblockidx %d", __func__, port_id, techs,
param_block_idx);
+
/* force all if techs is set to 1 */
if (techs == 1)
techs = 0xFFFFFFFF;
@@ -162,6 +157,46 @@
(void *)&msm_srs_trumedia_params[param_block_idx].srs_params.global);
}
+union srs_SS3D_params_u {
+ struct srs_SS3D_params srs_params;
+ unsigned short int raw_params[1];
+};
+static union srs_SS3D_params_u msm_srs_SS3D_params[2];
+
+static void srs_send_params_SS3D(int port_id, unsigned int techs,
+ int param_block_idx) {
+ pr_debug("SRS %s: called, port_id = %d, techs flags = %u,\n"
+ " paramblockidx %d", __func__, port_id, techs,
+ param_block_idx);
+
+ /* force all if techs is set to 1 */
+ if (techs == 1)
+ techs = 0xFFFFFFFF;
+
+ if (techs & (1 << SRS_ID_SS3D_CTRL))
+ srs_ss3d_open(port_id, SRS_ID_SS3D_CTRL,
+ (void *)&msm_srs_SS3D_params[param_block_idx].srs_params.ss3d);
+ if (techs & (1 << SRS_ID_SS3D_FILTER))
+ srs_ss3d_open(port_id, SRS_ID_SS3D_FILTER,
+ (void *)&msm_srs_SS3D_params[param_block_idx].srs_params.ss3d_f);
+ if (techs & (1 << SRS_ID_SS3D_GLOBAL))
+ srs_ss3d_open(port_id, SRS_ID_SS3D_GLOBAL,
+ (void *)&msm_srs_SS3D_params[param_block_idx].srs_params.global);
+ return;
+}
+
+static int srs_port_id = -1;
+static void srs_send_params(int port_id, unsigned int techs,
+ int param_block_id) {
+ if (srs_alsa_ctrl_ever_called_tm)
+ srs_send_params_trumedia(port_id, techs, param_block_id);
+ if (srs_alsa_ctrl_ever_called_ss3d)
+ srs_send_params_SS3D(port_id, techs, param_block_id);
+}
+
+/* This array is indexed by back-end DAI ID defined in msm-pcm-routing.h
+ * If new back-end is defined, add new back-end DAI ID at the end of enum
+ */
static struct msm_pcm_routing_bdai_data msm_bedais[MSM_BACKEND_DAI_MAX] = {
{ PRIMARY_I2S_RX, 0, 0, 0, 0, 0},
{ PRIMARY_I2S_TX, 0, 0, 0, 0, 0},
@@ -994,7 +1029,7 @@
unsigned int techs = 0;
unsigned short offset, value, max, index;
- srs_alsa_ctrl_ever_called = 1;
+ srs_alsa_ctrl_ever_called_tm = 1;
max = sizeof(msm_srs_trumedia_params) >> 1;
index = (unsigned short)((ucontrol->value.integer.value[0] &
@@ -1005,7 +1040,7 @@
pr_debug("SRS %s: send params request, flags = %u",
__func__, techs);
if (srs_port_id >= 0 && techs)
- srs_send_params(srs_port_id, techs, index);
+ srs_send_params_trumedia(srs_port_id, techs, index);
return 0;
}
offset = (unsigned short)((ucontrol->value.integer.value[0] &
@@ -1014,32 +1049,10 @@
SRS_PARAM_VALUE_MASK);
if (offset < max) {
msm_srs_trumedia_params[index].raw_params[offset] = value;
- pr_debug("SRS %s: index set... (max %d, requested %d,"
- " val %d, paramblockidx %d)", __func__, max, offset,
- value, index);
} else {
pr_err("SRS %s: index out of bounds! (max %d, requested %d)",
__func__, max, offset);
}
- if (offset == 4) {
- int i;
- for (i = 0; i < max; i++) {
- if (i == 0) {
- pr_debug("SRS %s: global block start",
- __func__);
- }
- if (i ==
- (sizeof(struct srs_trumedia_params_GLOBAL) >> 1)) {
- break;
- pr_debug("SRS %s: wowhd block start at"
- " offset %d word offset %d", __func__,
- i, i>>1);
- }
- pr_debug("SRS %s: param_index %d index %d val %d",
- __func__, index, i,
- msm_srs_trumedia_params[index].raw_params[i]);
- }
- }
return 0;
}
@@ -1047,7 +1060,6 @@
struct snd_ctl_elem_value *ucontrol) {
int ret;
- pr_debug("SRS control normal called");
mutex_lock(&routing_lock);
srs_port_id = SLIMBUS_0_RX;
ret = msm_routing_set_srs_trumedia_control_(kcontrol, ucontrol);
@@ -1060,7 +1072,6 @@
struct snd_ctl_elem_value *ucontrol) {
int ret;
- pr_debug("SRS control I2S called");
mutex_lock(&routing_lock);
srs_port_id = PRIMARY_I2S_RX;
ret = msm_routing_set_srs_trumedia_control_(kcontrol, ucontrol);
@@ -1073,7 +1084,6 @@
struct snd_ctl_elem_value *ucontrol) {
int ret;
- pr_debug("SRS control HDMI called");
mutex_lock(&routing_lock);
srs_port_id = HDMI_RX;
ret = msm_routing_set_srs_trumedia_control_(kcontrol, ucontrol);
@@ -1081,6 +1091,83 @@
return ret;
}
+static int msm_routing_get_srs_SS3D_control(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = 0;
+ return 0;
+}
+
+
+static int msm_routing_set_srs_SS3D_control_(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ unsigned int techs = 0;
+ unsigned short offset, value, max, index;
+
+ srs_alsa_ctrl_ever_called_ss3d = 1;
+
+ max = sizeof(msm_srs_SS3D_params) >> 1;
+ index = (unsigned short)((ucontrol->value.integer.value[0] &
+ SRS_PARAM_INDEX_MASK) >> 31);
+ if (SRS_CMD_UPLOAD ==
+ (ucontrol->value.integer.value[0] & SRS_CMD_UPLOAD)) {
+ techs = ucontrol->value.integer.value[0] & 0xFF;
+ pr_debug("SRS %s: send params request, flags = %u", __func__,
+ techs);
+ if (srs_port_id >= 0 && techs)
+ srs_send_params_SS3D(srs_port_id, techs, index);
+ return 0;
+ }
+
+ offset = (unsigned short)((ucontrol->value.integer.value[0] &
+ SRS_PARAM_OFFSET_MASK) >> 16);
+ value = (unsigned short)(ucontrol->value.integer.value[0] &
+ SRS_PARAM_VALUE_MASK);
+ if (offset < max) {
+ msm_srs_SS3D_params[index].raw_params[offset] = value;
+ } else {
+ pr_err("SRS %s: index out of bounds! (max %d, requested %d)",
+ __func__, max, offset);
+ }
+ return 0;
+}
+
+static int msm_routing_set_srs_SS3D_control(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol) {
+ int ret;
+
+ mutex_lock(&routing_lock);
+ srs_port_id = SLIMBUS_0_RX;
+ ret = msm_routing_set_srs_SS3D_control_(kcontrol, ucontrol);
+ mutex_unlock(&routing_lock);
+ return ret;
+}
+
+static int msm_routing_set_srs_SS3D_control_I2S(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol) {
+ int ret;
+
+ mutex_lock(&routing_lock);
+ srs_port_id = PRIMARY_I2S_RX;
+ ret = msm_routing_set_srs_SS3D_control_(kcontrol, ucontrol);
+ mutex_unlock(&routing_lock);
+ return ret;
+}
+
+static int msm_routing_set_srs_SS3D_control_HDMI(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol) {
+ int ret;
+
+ mutex_lock(&routing_lock);
+ srs_port_id = HDMI_RX;
+ ret = msm_routing_set_srs_SS3D_control_(kcontrol, ucontrol);
+ mutex_unlock(&routing_lock);
+ return ret;
+}
+
static void msm_send_eq_values(int eq_idx)
{
int result;
@@ -2109,6 +2196,66 @@
}
};
+static const struct snd_kcontrol_new lpa_SRS_SS3D_controls[] = {
+ {.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "SRS SS3D",
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+ SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_soc_info_volsw, \
+ .get = msm_routing_get_srs_SS3D_control,
+ .put = msm_routing_set_srs_SS3D_control,
+ .private_value = ((unsigned long)&(struct soc_mixer_control)
+ {.reg = SND_SOC_NOPM,
+ .rreg = SND_SOC_NOPM,
+ .shift = 0,
+ .rshift = 0,
+ .max = 0xFFFFFFFF,
+ .platform_max = 0xFFFFFFFF,
+ .invert = 0
+ })
+ }
+};
+
+static const struct snd_kcontrol_new lpa_SRS_SS3D_controls_HDMI[] = {
+ {.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "SRS SS3D HDMI",
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+ SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_soc_info_volsw, \
+ .get = msm_routing_get_srs_SS3D_control,
+ .put = msm_routing_set_srs_SS3D_control_HDMI,
+ .private_value = ((unsigned long)&(struct soc_mixer_control)
+ {.reg = SND_SOC_NOPM,
+ .rreg = SND_SOC_NOPM,
+ .shift = 0,
+ .rshift = 0,
+ .max = 0xFFFFFFFF,
+ .platform_max = 0xFFFFFFFF,
+ .invert = 0
+ })
+ }
+};
+
+static const struct snd_kcontrol_new lpa_SRS_SS3D_controls_I2S[] = {
+ {.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "SRS SS3D I2S",
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+ SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_soc_info_volsw, \
+ .get = msm_routing_get_srs_SS3D_control,
+ .put = msm_routing_set_srs_SS3D_control_I2S,
+ .private_value = ((unsigned long)&(struct soc_mixer_control)
+ {.reg = SND_SOC_NOPM,
+ .rreg = SND_SOC_NOPM,
+ .shift = 0,
+ .rshift = 0,
+ .max = 0xFFFFFFFF,
+ .platform_max = 0xFFFFFFFF,
+ .invert = 0
+ })
+ }
+};
+
static const struct snd_kcontrol_new eq_enable_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia1 EQ Enable", SND_SOC_NOPM,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_eq_enable_mixer,
@@ -3060,6 +3207,18 @@
ARRAY_SIZE(lpa_SRS_trumedia_controls_I2S));
snd_soc_add_platform_controls(platform,
+ lpa_SRS_SS3D_controls,
+ ARRAY_SIZE(lpa_SRS_SS3D_controls));
+
+ snd_soc_add_platform_controls(platform,
+ lpa_SRS_SS3D_controls_HDMI,
+ ARRAY_SIZE(lpa_SRS_SS3D_controls_HDMI));
+
+ snd_soc_add_platform_controls(platform,
+ lpa_SRS_SS3D_controls_I2S,
+ ARRAY_SIZE(lpa_SRS_SS3D_controls_I2S));
+
+ snd_soc_add_platform_controls(platform,
ec_ref_rx_mixer_controls,
ARRAY_SIZE(ec_ref_rx_mixer_controls));
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
index 42699c9..bb9f2be 100644
--- a/sound/soc/msm/msm8930.c
+++ b/sound/soc/msm/msm8930.c
@@ -58,7 +58,7 @@
static int msm8930_ext_spk_pamp;
static int msm8930_btsco_rate = BTSCO_RATE_8KHZ;
static int msm8930_btsco_ch = 1;
-
+static int hdmi_rate_variable;
static struct clk *codec_clk;
static int clk_users;
@@ -395,10 +395,13 @@
static const char *slim0_rx_ch_text[] = {"One", "Two"};
static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
+static const char * const hdmi_rate[] = {"Default", "Variable"};
+
static const struct soc_enum msm8930_enum[] = {
SOC_ENUM_SINGLE_EXT(2, spk_function),
SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
+ SOC_ENUM_SINGLE_EXT(2, hdmi_rate),
};
static const char *btsco_rate_text[] = {"8000", "16000"};
@@ -505,6 +508,21 @@
return ret;
}
+static int msm8930_hdmi_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ hdmi_rate_variable = ucontrol->value.integer.value[0];
+ pr_debug("%s: hdmi_rate_variable = %d\n", __func__, hdmi_rate_variable);
+ return 0;
+}
+
+static int msm8930_hdmi_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = hdmi_rate_variable;
+ return 0;
+}
+
static const struct snd_kcontrol_new sitar_msm8930_controls[] = {
SOC_ENUM_EXT("Speaker Function", msm8930_enum[0], msm8930_get_spk,
msm8930_set_spk),
@@ -516,6 +534,9 @@
msm8930_pmic_gain_get, msm8930_pmic_gain_put),
SOC_ENUM_EXT("Internal BTSCO SampleRate", msm8930_btsco_enum[0],
msm8930_btsco_rate_get, msm8930_btsco_rate_put),
+ SOC_ENUM_EXT("HDMI RX Rate", msm8930_enum[3],
+ msm8930_hdmi_rate_get,
+ msm8930_hdmi_rate_put),
};
static void *def_sitar_mbhc_cal(void)
@@ -751,7 +772,8 @@
struct snd_interval *channels = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
- rate->min = rate->max = 48000;
+ if (!hdmi_rate_variable)
+ rate->min = rate->max = 48000;
channels->min = channels->max = 2;
return 0;
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index ad78255..da62729 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -73,7 +73,7 @@
static int msm8960_btsco_rate = SAMPLE_RATE_8KHZ;
static int msm8960_btsco_ch = 1;
-
+static int hdmi_rate_variable;
static int msm8960_auxpcm_rate = SAMPLE_RATE_8KHZ;
static struct clk *codec_clk;
@@ -549,11 +549,13 @@
static const char *spk_function[] = {"Off", "On"};
static const char *slim0_rx_ch_text[] = {"One", "Two"};
static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
+static const char * const hdmi_rate[] = {"Default", "Variable"};
static const struct soc_enum msm8960_enum[] = {
SOC_ENUM_SINGLE_EXT(2, spk_function),
SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
+ SOC_ENUM_SINGLE_EXT(2, hdmi_rate),
};
static const char *btsco_rate_text[] = {"8000", "16000"};
@@ -660,6 +662,21 @@
return 0;
}
+static int msm8960_hdmi_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ hdmi_rate_variable = ucontrol->value.integer.value[0];
+ pr_debug("%s: hdmi_rate_variable = %d\n", __func__, hdmi_rate_variable);
+ return 0;
+}
+
+static int msm8960_hdmi_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = hdmi_rate_variable;
+ return 0;
+}
+
static const struct snd_kcontrol_new tabla_msm8960_controls[] = {
SOC_ENUM_EXT("Speaker Function", msm8960_enum[0], msm8960_get_spk,
msm8960_set_spk),
@@ -671,6 +688,9 @@
msm8960_btsco_rate_get, msm8960_btsco_rate_put),
SOC_ENUM_EXT("AUX PCM SampleRate", msm8960_auxpcm_enum[0],
msm8960_auxpcm_rate_get, msm8960_auxpcm_rate_put),
+ SOC_ENUM_EXT("HDMI RX Rate", msm8960_enum[3],
+ msm8960_hdmi_rate_get,
+ msm8960_hdmi_rate_put),
};
static void *def_tabla_mbhc_cal(void)
@@ -1003,7 +1023,8 @@
if (channels->max < 2)
channels->min = channels->max = 2;
- rate->min = rate->max = 48000;
+ if (!hdmi_rate_variable)
+ rate->min = rate->max = 48000;
return 0;
}
diff --git a/sound/soc/msm/qdsp6/q6adm.c b/sound/soc/msm/qdsp6/q6adm.c
index 119e017..2d8d9ca 100644
--- a/sound/soc/msm/qdsp6/q6adm.c
+++ b/sound/soc/msm/qdsp6/q6adm.c
@@ -230,6 +230,182 @@
return ret;
}
+struct SS3D {
+ int _1; int _2; short _3; short _4;
+ short _5; short _6; int _7; int _X[32];
+ short _8; short _9; short _10; short _11;
+ short _12; short _13; short _14; short _15;
+ short _16; short _17; short _18; short _19;
+ short _20; short _21; short _22; short _23;
+ short _24; short _25; short _26[5];
+ short _27; short _28; short _29; short _30;
+ short _31; short _32; short _33; int _34; int _35;
+ int _36; int _37; int _38; int _39; int _40;
+};
+
+struct SS3D_F {
+ int _1; int _2; int _3; int _4; int _5; int _6; int _7; int _X[];
+};
+
+int srs_ss3d_open(int port_id, int srs_tech_id, void *srs_params)
+{
+ struct asm_pp_params_command *open = NULL;
+ int ret = 0, sz = 0;
+
+ int index;
+
+ pr_debug("SRS - %s: called.", __func__);
+
+ switch (srs_tech_id) {
+ case SRS_ID_SS3D_GLOBAL: {
+ struct srs_SS3D_params_GLOBAL *glb_params = NULL;
+ sz = sizeof(struct asm_pp_params_command) +
+ sizeof(struct srs_SS3D_params_GLOBAL);
+ open = kzalloc(sz, GFP_KERNEL);
+
+ open->payload_size = sizeof(struct srs_SS3D_params_GLOBAL) +
+ sizeof(struct asm_pp_param_data_hdr);
+ open->params.param_id = SRS_SS3D_PARAMS;
+ open->params.param_size =
+ sizeof(struct srs_SS3D_params_GLOBAL);
+
+ glb_params = (struct srs_SS3D_params_GLOBAL *)((u8 *)open +
+ sizeof(struct asm_pp_params_command));
+ memcpy(glb_params, srs_params,
+ sizeof(struct srs_SS3D_params_GLOBAL));
+
+ pr_debug("SRS - ss3d global params - 1 = %x, 2 = %x, 3 = %x\n"
+ " 4 = %x, 5 = %x, 6 = %x, 7 = %x, 8 = %x\n",
+ (int)glb_params->v1, (int)glb_params->v2,
+ (int)glb_params->v3, (int)glb_params->v4,
+ (int)glb_params->v5, (int)glb_params->v6,
+ (int)glb_params->v7, (int)glb_params->v8);
+ break;
+ }
+ case SRS_ID_SS3D_CTRL: {
+ struct srs_SS3D_ctrl_params *whd_params = NULL;
+ sz = sizeof(struct asm_pp_params_command) +
+ sizeof(struct srs_SS3D_ctrl_params);
+ open = kzalloc(sz, GFP_KERNEL);
+
+ open->payload_size = sizeof(struct srs_SS3D_ctrl_params) +
+ sizeof(struct asm_pp_param_data_hdr);
+ open->params.param_id = SRS_SS3D_PARAMS_CTRL;
+ open->params.param_size = sizeof(struct srs_SS3D_ctrl_params);
+
+ whd_params = (struct srs_SS3D_ctrl_params *)((u8 *)open +
+ sizeof(struct asm_pp_params_command));
+ memcpy(whd_params, srs_params,
+ sizeof(struct srs_SS3D_ctrl_params));
+
+ {
+ struct SS3D *D = (struct SS3D *)whd_params->v;
+ pr_debug("SRS - ss3d ctrl params\n"
+ "1 = 0x%08X, 2 = 0x%08X, 3 = 0x%04X,\n"
+ "4 = 0x%04X, 5 = 0x%04X, 6 = 0x%04X,\n"
+ "7 = 0x%08X, 8 = 0x%04X, 9 = 0x%04X,\n"
+ "10 = 0x%04X, 11 = 0x%04X, 12 = 0x%04X,\n"
+ "13 = 0x%04X, 14 = 0x%04X, 15 = 0x%04X,\n"
+ "16 = 0x%04X, 17 = 0x%04X, 18 = 0x%04X,\n"
+ "19 = 0x%04X, 20 = 0x%04X, 21 = 0x%04X,\n"
+ "22 = 0x%04X, 23 = 0x%04X, 24 = 0x%04X,\n"
+ "25 = 0x%04X, 26.0 = 0x%04X, 26.1 = 0x%04X,\n"
+ "26.2 = 0x%04X, 26.3 = 0x%04X,\n"
+ "26.4 = 0x%04X, 27 = 0x%04X, 28 = 0x%04X,\n"
+ "29 = 0x%04X, 30 = 0x%04X, 31 = 0x%04X,\n"
+ "32 = 0x%04X, 33 = 0x%04X, 34 = 0x%08X,\n"
+ "35 = 0x%08X, 36 = 0x%08X, 37 = 0x%08X,\n"
+ "38 = 0x%08X, 39 = 0x%08X, 40 = 0x%08X",
+ D->_1, D->_2, D->_3, D->_4, D->_5, D->_6, D->_7,
+ D->_8, D->_9, D->_10, D->_11, D->_12, D->_13,
+ D->_14, D->_15, D->_16, D->_17, D->_18, D->_19,
+ D->_20, D->_21, D->_22, D->_23, D->_24, D->_25,
+ D->_26[0], D->_26[1], D->_26[2], D->_26[3],
+ D->_26[4], D->_27, D->_28, D->_29, D->_30,
+ D->_31, D->_32, D->_33, D->_34, D->_35, D->_36,
+ D->_37, D->_38, D->_39, D->_40);
+ }
+ break;
+ }
+ case SRS_ID_SS3D_FILTER: {
+ struct srs_SS3D_filter_params *chp_params = NULL;
+ sz = sizeof(struct asm_pp_params_command) +
+ sizeof(struct srs_SS3D_filter_params);
+ open = kzalloc(sz, GFP_KERNEL);
+
+ open->payload_size = sizeof(struct srs_SS3D_filter_params) +
+ sizeof(struct asm_pp_param_data_hdr);
+ open->params.param_id = SRS_SS3D_PARAMS_FILTER;
+ open->params.param_size =
+ sizeof(struct srs_SS3D_filter_params);
+
+ chp_params = (struct srs_SS3D_filter_params *)((u8 *)open +
+ sizeof(struct asm_pp_params_command));
+ memcpy(chp_params, srs_params,
+ sizeof(struct srs_SS3D_filter_params));
+
+ {
+ struct SS3D_F *D = (struct SS3D_F *)chp_params->v;
+ pr_debug("SRS - ss3d filter params\n"
+ "1 = 0x%08X, 2 = 0x%08X, 3 = 0x%08X\n"
+ "4 = 0x%08X, 5 = 0x%08X, 6 = 0x%08X\n"
+ "7 = 0x%08X", D->_1, D->_2, D->_3, D->_4, D->_5,
+ D->_6, D->_7);
+ }
+ break;
+ }
+ default:
+ pr_debug("SRS - bad param!\n");
+ goto fail_cmd;
+ }
+
+ open->payload = NULL;
+
+ open->params.module_id = SRS_SS3D_MODULE_ID;
+ open->params.reserved = 0;
+
+ open->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ open->hdr.pkt_size = sz;
+ open->hdr.src_svc = APR_SVC_ADM;
+ open->hdr.src_domain = APR_DOMAIN_APPS;
+ open->hdr.src_port = port_id;
+ open->hdr.dest_svc = APR_SVC_ADM;
+ open->hdr.dest_domain = APR_DOMAIN_ADSP;
+
+ index = afe_get_port_index(port_id);
+ open->hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+ /* port_id;//atomic_read(&this_adm.copp_id[port_id]); */
+ open->hdr.token = port_id;
+ open->hdr.opcode = ADM_CMD_SET_PARAMS;
+
+ pr_debug("SRS - %s: Command was sent now check Q6 - port id = %d,\n"
+ "size %d, module id %x, param id %x.\n",
+ __func__, open->hdr.dest_port, open->payload_size,
+ open->params.module_id, open->params.param_id);
+
+ ret = apr_send_pkt(this_adm.apr, (uint32_t *)open);
+ if (ret < 0) {
+ pr_err("SRS - %s: ADM enable for port %d failed\n",
+ __func__, port_id);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ /* Wait for the callback with copp id */
+ ret = wait_event_timeout(this_adm.wait, 1,
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("SRS - %s: ADM open failed for port %d\n",
+ __func__, port_id);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+fail_cmd:
+ kfree(open);
+ return ret;
+}
+
static int32_t adm_callback(struct apr_client_data *data, void *priv)
{
uint32_t *payload;
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index 6f0dbf2..2f4c256 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -900,7 +900,7 @@
SNDRV_PCM_RATE_16000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
- .channels_max = 4,
+ .channels_max = 8,
.rate_min = 8000,
.rate_max = 48000,
},
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
index 73a04c2..1aa12e3 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
@@ -33,8 +33,10 @@
#include <mach/msm_subsystem_map.h>
#include "msm-pcm-afe-v2.h"
-#define MIN_PERIOD_SIZE (128 * 2)
-#define MAX_PERIOD_SIZE (128 * 2 * 2 * 6)
+#define MIN_PERIOD_SIZE (128 * 2 * 8)
+#define MAX_PERIOD_SIZE (128 * 2 * 2 * 6 * 8)
+#define MAX_NUM_PERIODS 384
+#define MIN_NUM_PERIODS 32
static struct snd_pcm_hardware msm_afe_hardware = {
.info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -47,12 +49,12 @@
.rate_min = 8000,
.rate_max = 48000,
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 8,
.buffer_bytes_max = MAX_PERIOD_SIZE * 32,
.period_bytes_min = MIN_PERIOD_SIZE,
.period_bytes_max = MAX_PERIOD_SIZE,
- .periods_min = 32,
- .periods_max = 384,
+ .periods_min = MIN_NUM_PERIODS,
+ .periods_max = MAX_NUM_PERIODS,
.fifo_size = 0,
};
static enum hrtimer_restart afe_hrtimer_callback(struct hrtimer *hrt);
@@ -353,6 +355,17 @@
if (ret < 0)
pr_err("snd_pcm_hw_constraint_integer failed\n");
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ ret = snd_pcm_hw_constraint_minmax(runtime,
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+ MAX_NUM_PERIODS * MIN_PERIOD_SIZE,
+ MIN_NUM_PERIODS * MAX_PERIOD_SIZE);
+ if (ret < 0) {
+ pr_err("constraint for buffer bytes min max ret = %d\n",
+ ret);
+ }
+ }
+
return 0;
}
@@ -497,8 +510,8 @@
dir = OUT;
rc = q6afe_audio_client_buf_alloc_contiguous(dir,
prtd->audio_client,
- runtime->hw.period_bytes_min,
- runtime->hw.periods_max);
+ (params_buffer_bytes(params) / params_periods(params)),
+ params_periods(params));
if (rc < 0) {
pr_err("Audio Start: Buffer Allocation failed rc = %d\n", rc);
mutex_unlock(&prtd->lock);
@@ -517,14 +530,14 @@
dma_buf->private_data = NULL;
dma_buf->area = buf[0].data;
dma_buf->addr = buf[0].phys;
- dma_buf->bytes = runtime->hw.buffer_bytes_max;
+ dma_buf->bytes = params_buffer_bytes(params);
if (!dma_buf->area) {
pr_err("%s:MSM AFE physical memory allocation failed\n",
__func__);
mutex_unlock(&prtd->lock);
return -ENOMEM;
}
- memset(dma_buf->area, 0, runtime->hw.buffer_bytes_max);
+ memset(dma_buf->area, 0, params_buffer_bytes(params));
prtd->dma_addr = (u32) dma_buf->addr;
mutex_unlock(&prtd->lock);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index fbdbbf6..58300c4 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -50,6 +50,7 @@
static int fm_switch_enable;
static int fm_pcmrx_switch_enable;
+static int srs_alsa_ctrl_ever_called;
#define INT_RX_VOL_MAX_STEPS 0x2000
#define INT_RX_VOL_GAIN 0x2000
@@ -112,6 +113,49 @@
/* This array is indexed by back-end DAI ID defined in msm-pcm-routing.h
* If new back-end is defined, add new back-end DAI ID at the end of enum
*/
+
+
+union srs_trumedia_params_u {
+ struct srs_trumedia_params srs_params;
+ unsigned short int raw_params[1];
+};
+static union srs_trumedia_params_u msm_srs_trumedia_params[2];
+static int srs_port_id = -1;
+
+static void srs_send_params(int port_id, unsigned int techs,
+ int param_block_idx)
+{
+ /* only send commands to dsp if srs alsa ctrl was used
+ at least one time */
+ if (!srs_alsa_ctrl_ever_called)
+ return;
+
+ pr_debug("SRS %s: called, port_id = %d, techs flags = %u, paramblockidx %d",
+ __func__, port_id, techs, param_block_idx);
+ /* force all if techs is set to 1 */
+ if (techs == 1)
+ techs = 0xFFFFFFFF;
+
+ if (techs & (1 << SRS_ID_WOWHD))
+ srs_trumedia_open(port_id, SRS_ID_WOWHD,
+ (void *)&msm_srs_trumedia_params[param_block_idx].srs_params.wowhd);
+ if (techs & (1 << SRS_ID_CSHP))
+ srs_trumedia_open(port_id, SRS_ID_CSHP,
+ (void *)&msm_srs_trumedia_params[param_block_idx].srs_params.cshp);
+ if (techs & (1 << SRS_ID_HPF))
+ srs_trumedia_open(port_id, SRS_ID_HPF,
+ (void *)&msm_srs_trumedia_params[param_block_idx].srs_params.hpf);
+ if (techs & (1 << SRS_ID_PEQ))
+ srs_trumedia_open(port_id, SRS_ID_PEQ,
+ (void *)&msm_srs_trumedia_params[param_block_idx].srs_params.peq);
+ if (techs & (1 << SRS_ID_HL))
+ srs_trumedia_open(port_id, SRS_ID_HL,
+ (void *)&msm_srs_trumedia_params[param_block_idx].srs_params.hl);
+ if (techs & (1 << SRS_ID_GLOBAL))
+ srs_trumedia_open(port_id, SRS_ID_GLOBAL,
+ (void *)&msm_srs_trumedia_params[param_block_idx].srs_params.global);
+}
+
#define SLIMBUS_EXTPROC_RX AFE_PORT_INVALID
static struct msm_pcm_routing_bdai_data msm_bedais[MSM_BACKEND_DAI_MAX] = {
{ PRIMARY_I2S_RX, 0, 0, 0, 0, 0},
@@ -285,6 +329,8 @@
payload.copp_ids[payload.num_copps++] =
msm_bedais[i].port_id;
+ srs_port_id = msm_bedais[i].port_id;
+ srs_send_params(srs_port_id, 1, 0);
}
}
if (payload.num_copps)
@@ -393,6 +439,8 @@
msm_pcm_routing_build_matrix(val,
fe_dai_map[val][session_type], path_type);
+ srs_port_id = msm_bedais[reg].port_id;
+ srs_send_params(srs_port_id, 1, 0);
}
} else {
if (test_bit(val, &msm_bedais[reg].fe_sessions) &&
@@ -755,6 +803,104 @@
return 0;
}
+static int msm_routing_get_srs_trumedia_control(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = 0;
+ return 0;
+}
+
+static int msm_routing_set_srs_trumedia_control_(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ unsigned int techs = 0;
+ unsigned short offset, value, max, index;
+
+ srs_alsa_ctrl_ever_called = 1;
+
+ max = sizeof(msm_srs_trumedia_params) >> 1;
+ index = (unsigned short)((ucontrol->value.integer.value[0] &
+ SRS_PARAM_INDEX_MASK) >> 31);
+ if (SRS_CMD_UPLOAD ==
+ (ucontrol->value.integer.value[0] & SRS_CMD_UPLOAD)) {
+ techs = ucontrol->value.integer.value[0] & 0xFF;
+ pr_debug("SRS %s: send params request, flags = %u",
+ __func__, techs);
+ if (srs_port_id >= 0 && techs)
+ srs_send_params(srs_port_id, techs, index);
+ return 0;
+ }
+ offset = (unsigned short)((ucontrol->value.integer.value[0] &
+ SRS_PARAM_OFFSET_MASK) >> 16);
+ value = (unsigned short)(ucontrol->value.integer.value[0] &
+ SRS_PARAM_VALUE_MASK);
+ if (offset < max) {
+ msm_srs_trumedia_params[index].raw_params[offset] = value;
+ pr_debug("SRS %s: index set... (max %d, requested %d, val %d, paramblockidx %d)",
+ __func__, max, offset, value, index);
+ } else {
+ pr_err("SRS %s: index out of bounds! (max %d, requested %d)",
+ __func__, max, offset);
+ }
+ if (offset == 4) {
+ int i;
+ for (i = 0; i < max; i++) {
+ if (i == 0) {
+ pr_debug("SRS %s: global block start",
+ __func__);
+ }
+ if (i ==
+ (sizeof(struct srs_trumedia_params_GLOBAL) >> 1)) {
+ pr_debug("SRS %s: wowhd block start at offset %d word offset %d",
+ __func__, i, i>>1);
+ break;
+ }
+ pr_debug("SRS %s: param_index %d index %d val %d",
+ __func__, index, i,
+ msm_srs_trumedia_params[index].raw_params[i]);
+ }
+ }
+ return 0;
+}
+
+static int msm_routing_set_srs_trumedia_control(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol) {
+ int ret;
+
+ pr_debug("SRS control normal called");
+ mutex_lock(&routing_lock);
+ srs_port_id = SLIMBUS_0_RX;
+ ret = msm_routing_set_srs_trumedia_control_(kcontrol, ucontrol);
+ mutex_unlock(&routing_lock);
+ return ret;
+}
+
+static int msm_routing_set_srs_trumedia_control_I2S(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol) {
+ int ret;
+
+ pr_debug("SRS control I2S called");
+ mutex_lock(&routing_lock);
+ srs_port_id = PRIMARY_I2S_RX;
+ ret = msm_routing_set_srs_trumedia_control_(kcontrol, ucontrol);
+ mutex_unlock(&routing_lock);
+ return ret;
+}
+
+static int msm_routing_set_srs_trumedia_control_HDMI(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol) {
+ int ret;
+
+ pr_debug("SRS control HDMI called");
+ mutex_lock(&routing_lock);
+ srs_port_id = HDMI_RX;
+ ret = msm_routing_set_srs_trumedia_control_(kcontrol, ucontrol);
+ mutex_unlock(&routing_lock);
+ return ret;
+}
+
static void msm_send_eq_values(int eq_idx)
{
int result;
@@ -1410,6 +1556,67 @@
INT_RX_VOL_GAIN, 0, msm_routing_get_compressed_vol_mixer,
msm_routing_set_compressed_vol_mixer, compressed_rx_vol_gain),
};
+
+static const struct snd_kcontrol_new lpa_SRS_trumedia_controls[] = {
+ {.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "SRS TruMedia",
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+ SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_soc_info_volsw, \
+ .get = msm_routing_get_srs_trumedia_control,
+ .put = msm_routing_set_srs_trumedia_control,
+ .private_value = ((unsigned long)&(struct soc_mixer_control)
+ {.reg = SND_SOC_NOPM,
+ .rreg = SND_SOC_NOPM,
+ .shift = 0,
+ .rshift = 0,
+ .max = 0xFFFFFFFF,
+ .platform_max = 0xFFFFFFFF,
+ .invert = 0
+ })
+ }
+};
+
+static const struct snd_kcontrol_new lpa_SRS_trumedia_controls_HDMI[] = {
+ {.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "SRS TruMedia HDMI",
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+ SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_soc_info_volsw, \
+ .get = msm_routing_get_srs_trumedia_control,
+ .put = msm_routing_set_srs_trumedia_control_HDMI,
+ .private_value = ((unsigned long)&(struct soc_mixer_control)
+ {.reg = SND_SOC_NOPM,
+ .rreg = SND_SOC_NOPM,
+ .shift = 0,
+ .rshift = 0,
+ .max = 0xFFFFFFFF,
+ .platform_max = 0xFFFFFFFF,
+ .invert = 0
+ })
+ }
+};
+
+static const struct snd_kcontrol_new lpa_SRS_trumedia_controls_I2S[] = {
+ {.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "SRS TruMedia I2S",
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+ SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_soc_info_volsw, \
+ .get = msm_routing_get_srs_trumedia_control,
+ .put = msm_routing_set_srs_trumedia_control_I2S,
+ .private_value = ((unsigned long)&(struct soc_mixer_control)
+ {.reg = SND_SOC_NOPM,
+ .rreg = SND_SOC_NOPM,
+ .shift = 0,
+ .rshift = 0,
+ .max = 0xFFFFFFFF,
+ .platform_max = 0xFFFFFFFF,
+ .invert = 0
+ })
+ }
+};
+
static const struct snd_kcontrol_new eq_enable_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia1 EQ Enable", SND_SOC_NOPM,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_eq_enable_mixer,
@@ -2102,6 +2309,7 @@
for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MM_SIZE) {
if (fe_dai_map[i][session_type] != INVALID_SESSION)
adm_close(bedai->port_id);
+ srs_port_id = -1;
}
bedai->active = 0;
@@ -2167,6 +2375,8 @@
msm_pcm_routing_build_matrix(i,
fe_dai_map[i][session_type], path_type);
+ srs_port_id = bedai->port_id;
+ srs_send_params(srs_port_id, 1, 0);
}
}
@@ -2234,6 +2444,18 @@
snd_soc_add_platform_controls(platform,
compressed_vol_mixer_controls,
ARRAY_SIZE(compressed_vol_mixer_controls));
+
+ snd_soc_add_platform_controls(platform,
+ lpa_SRS_trumedia_controls,
+ ARRAY_SIZE(lpa_SRS_trumedia_controls));
+
+ snd_soc_add_platform_controls(platform,
+ lpa_SRS_trumedia_controls_HDMI,
+ ARRAY_SIZE(lpa_SRS_trumedia_controls_HDMI));
+
+ snd_soc_add_platform_controls(platform,
+ lpa_SRS_trumedia_controls_I2S,
+ ARRAY_SIZE(lpa_SRS_trumedia_controls_I2S));
return 0;
}
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index 985f76b..1e0ad9e 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -50,6 +50,202 @@
static struct adm_ctl this_adm;
+int srs_trumedia_open(int port_id, int srs_tech_id, void *srs_params)
+{
+ struct adm_cmd_set_pp_params_inband_v5 *adm_params = NULL;
+ int ret = 0, sz = 0;
+ int index;
+
+ pr_debug("SRS - %s", __func__);
+ switch (srs_tech_id) {
+ case SRS_ID_GLOBAL: {
+ struct srs_trumedia_params_GLOBAL *glb_params = NULL;
+ sz = sizeof(struct adm_cmd_set_pp_params_inband_v5) +
+ sizeof(struct srs_trumedia_params_GLOBAL);
+ adm_params = kzalloc(sz, GFP_KERNEL);
+ adm_params->payload_size =
+ sizeof(struct srs_trumedia_params_GLOBAL) +
+ sizeof(struct adm_param_data_v5);
+ adm_params->params.param_id = SRS_TRUMEDIA_PARAMS;
+ adm_params->params.param_size =
+ sizeof(struct srs_trumedia_params_GLOBAL);
+ glb_params = (struct srs_trumedia_params_GLOBAL *)
+ ((u8 *)adm_params +
+ sizeof(struct adm_cmd_set_pp_params_inband_v5));
+ memcpy(glb_params, srs_params,
+ sizeof(struct srs_trumedia_params_GLOBAL));
+ pr_debug("SRS - %s: Global params - 1 = %x, 2 = %x, 3 = %x, 4 = %x, 5 = %x, 6 = %x, 7 = %x, 8 = %x\n",
+ __func__, (int)glb_params->v1,
+ (int)glb_params->v2, (int)glb_params->v3,
+ (int)glb_params->v4, (int)glb_params->v5,
+ (int)glb_params->v6, (int)glb_params->v7,
+ (int)glb_params->v8);
+ break;
+ }
+ case SRS_ID_WOWHD: {
+ struct srs_trumedia_params_WOWHD *whd_params = NULL;
+ sz = sizeof(struct adm_cmd_set_pp_params_inband_v5) +
+ sizeof(struct srs_trumedia_params_WOWHD);
+ adm_params = kzalloc(sz, GFP_KERNEL);
+ adm_params->payload_size =
+ sizeof(struct srs_trumedia_params_WOWHD) +
+ sizeof(struct adm_param_data_v5);
+ adm_params->params.param_id = SRS_TRUMEDIA_PARAMS_WOWHD;
+ adm_params->params.param_size =
+ sizeof(struct srs_trumedia_params_WOWHD);
+ whd_params = (struct srs_trumedia_params_WOWHD *)
+ ((u8 *)adm_params +
+ sizeof(struct adm_cmd_set_pp_params_inband_v5));
+ memcpy(whd_params, srs_params,
+ sizeof(struct srs_trumedia_params_WOWHD));
+ pr_debug("SRS - %s: WOWHD params - 1 = %x, 2 = %x, 3 = %x, 4 = %x, 5 = %x, 6 = %x, 7 = %x, 8 = %x, 9 = %x, 10 = %x, 11 = %x\n",
+ __func__, (int)whd_params->v1,
+ (int)whd_params->v2, (int)whd_params->v3,
+ (int)whd_params->v4, (int)whd_params->v5,
+ (int)whd_params->v6, (int)whd_params->v7,
+ (int)whd_params->v8, (int)whd_params->v9,
+ (int)whd_params->v10, (int)whd_params->v11);
+ break;
+ }
+ case SRS_ID_CSHP: {
+ struct srs_trumedia_params_CSHP *chp_params = NULL;
+ sz = sizeof(struct adm_cmd_set_pp_params_inband_v5) +
+ sizeof(struct srs_trumedia_params_CSHP);
+ adm_params = kzalloc(sz, GFP_KERNEL);
+ adm_params->payload_size =
+ sizeof(struct srs_trumedia_params_CSHP) +
+ sizeof(struct adm_param_data_v5);
+ adm_params->params.param_id = SRS_TRUMEDIA_PARAMS_CSHP;
+ adm_params->params.param_size =
+ sizeof(struct srs_trumedia_params_CSHP);
+ chp_params = (struct srs_trumedia_params_CSHP *)
+ ((u8 *)adm_params +
+ sizeof(struct adm_cmd_set_pp_params_inband_v5));
+ memcpy(chp_params, srs_params,
+ sizeof(struct srs_trumedia_params_CSHP));
+ pr_debug("SRS - %s: CSHP params - 1 = %x, 2 = %x, 3 = %x, 4 = %x, 5 = %x, 6 = %x, 7 = %x, 8 = %x, 9 = %x\n",
+ __func__, (int)chp_params->v1,
+ (int)chp_params->v2, (int)chp_params->v3,
+ (int)chp_params->v4, (int)chp_params->v5,
+ (int)chp_params->v6, (int)chp_params->v7,
+ (int)chp_params->v8, (int)chp_params->v9);
+ break;
+ }
+ case SRS_ID_HPF: {
+ struct srs_trumedia_params_HPF *hpf_params = NULL;
+ sz = sizeof(struct adm_cmd_set_pp_params_inband_v5) +
+ sizeof(struct srs_trumedia_params_HPF);
+ adm_params = kzalloc(sz, GFP_KERNEL);
+ adm_params->payload_size =
+ sizeof(struct srs_trumedia_params_HPF) +
+ sizeof(struct adm_param_data_v5);
+ adm_params->params.param_id = SRS_TRUMEDIA_PARAMS_HPF;
+ adm_params->params.param_size =
+ sizeof(struct srs_trumedia_params_HPF);
+ hpf_params = (struct srs_trumedia_params_HPF *)
+ ((u8 *)adm_params +
+ sizeof(struct adm_cmd_set_pp_params_inband_v5));
+ memcpy(hpf_params, srs_params,
+ sizeof(struct srs_trumedia_params_HPF));
+ pr_debug("SRS - %s: HPF params - 1 = %x\n", __func__,
+ (int)hpf_params->v1);
+ break;
+ }
+ case SRS_ID_PEQ: {
+ struct srs_trumedia_params_PEQ *peq_params = NULL;
+ sz = sizeof(struct adm_cmd_set_pp_params_inband_v5) +
+ sizeof(struct srs_trumedia_params_PEQ);
+ adm_params = kzalloc(sz, GFP_KERNEL);
+ adm_params->payload_size =
+ sizeof(struct srs_trumedia_params_PEQ) +
+ sizeof(struct adm_param_data_v5);
+ adm_params->params.param_id = SRS_TRUMEDIA_PARAMS_PEQ;
+ adm_params->params.param_size =
+ sizeof(struct srs_trumedia_params_PEQ);
+ peq_params = (struct srs_trumedia_params_PEQ *)
+ ((u8 *)adm_params +
+ sizeof(struct adm_cmd_set_pp_params_inband_v5));
+ memcpy(peq_params, srs_params,
+ sizeof(struct srs_trumedia_params_PEQ));
+ pr_debug("SRS - %s: PEQ params - 1 = %x 2 = %x, 3 = %x, 4 = %x\n",
+ __func__, (int)peq_params->v1,
+ (int)peq_params->v2, (int)peq_params->v3,
+ (int)peq_params->v4);
+ break;
+ }
+ case SRS_ID_HL: {
+ struct srs_trumedia_params_HL *hl_params = NULL;
+ sz = sizeof(struct adm_cmd_set_pp_params_inband_v5) +
+ sizeof(struct srs_trumedia_params_HL);
+ adm_params = kzalloc(sz, GFP_KERNEL);
+ adm_params->payload_size =
+ sizeof(struct srs_trumedia_params_HL) +
+ sizeof(struct adm_param_data_v5);
+ adm_params->params.param_id = SRS_TRUMEDIA_PARAMS_HL;
+ adm_params->params.param_size =
+ sizeof(struct srs_trumedia_params_HL);
+ hl_params = (struct srs_trumedia_params_HL *)
+ ((u8 *)adm_params +
+ sizeof(struct adm_cmd_set_pp_params_inband_v5));
+ memcpy(hl_params, srs_params,
+ sizeof(struct srs_trumedia_params_HL));
+ pr_debug("SRS - %s: HL params - 1 = %x, 2 = %x, 3 = %x, 4 = %x, 5 = %x, 6 = %x, 7 = %x\n",
+ __func__, (int)hl_params->v1,
+ (int)hl_params->v2, (int)hl_params->v3,
+ (int)hl_params->v4, (int)hl_params->v5,
+ (int)hl_params->v6, (int)hl_params->v7);
+ break;
+ }
+ default:
+ goto fail_cmd;
+ }
+
+ adm_params->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ adm_params->hdr.pkt_size = sz;
+ adm_params->hdr.src_svc = APR_SVC_ADM;
+ adm_params->hdr.src_domain = APR_DOMAIN_APPS;
+ adm_params->hdr.src_port = port_id;
+ adm_params->hdr.dest_svc = APR_SVC_ADM;
+ adm_params->hdr.dest_domain = APR_DOMAIN_ADSP;
+ index = afe_get_port_index(port_id);
+ adm_params->hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+ adm_params->hdr.token = port_id;
+ adm_params->hdr.opcode = ADM_CMD_SET_PP_PARAMS_V5;
+ adm_params->payload_addr_lsw = 0;
+ adm_params->payload_addr_msw = 0;
+ adm_params->mem_map_handle = 0;
+
+ adm_params->params.module_id = SRS_TRUMEDIA_MODULE_ID;
+ adm_params->params.reserved = 0;
+
+ pr_debug("SRS - %s: Command was sent now check Q6 - port id = %d, size %d, module id %x, param id %x.\n",
+ __func__, adm_params->hdr.dest_port,
+ adm_params->payload_size, adm_params->params.module_id,
+ adm_params->params.param_id);
+
+ ret = apr_send_pkt(this_adm.apr, (uint32_t *)adm_params);
+ if (ret < 0) {
+ pr_err("SRS - %s: ADM enable for port %d failed\n", __func__,
+ port_id);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ /* Wait for the callback with copp id */
+ ret = wait_event_timeout(this_adm.wait[index], 1,
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: SRS set params timed out port = %d\n",
+ __func__, port_id);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+fail_cmd:
+ kfree(adm_params);
+ return ret;
+}
+
static void adm_callback_debug_print(struct apr_client_data *data)
{
uint32_t *payload;
@@ -538,8 +734,8 @@
open.dev_channel_mapping[3] = PCM_CHANNEL_FC;
open.dev_channel_mapping[4] = PCM_CHANNEL_LB;
open.dev_channel_mapping[5] = PCM_CHANNEL_RB;
- open.dev_channel_mapping[6] = PCM_CHANNEL_FLC;
- open.dev_channel_mapping[7] = PCM_CHANNEL_FRC;
+ open.dev_channel_mapping[6] = PCM_CHANNEL_RLC;
+ open.dev_channel_mapping[7] = PCM_CHANNEL_RRC;
} else {
pr_err("%s invalid num_chan %d\n", __func__,
channel_mode);
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 85646cb..0cbd136 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -1849,12 +1849,12 @@
lchannel_mapping[3] = PCM_CHANNEL_LB;
lchannel_mapping[4] = PCM_CHANNEL_RB;
} else if (channels == 6) {
- lchannel_mapping[0] = PCM_CHANNEL_FL;
- lchannel_mapping[1] = PCM_CHANNEL_FR;
- lchannel_mapping[2] = PCM_CHANNEL_LFE;
- lchannel_mapping[3] = PCM_CHANNEL_FC;
- lchannel_mapping[4] = PCM_CHANNEL_LB;
- lchannel_mapping[5] = PCM_CHANNEL_RB;
+ channel_mapping[0] = PCM_CHANNEL_FC;
+ channel_mapping[1] = PCM_CHANNEL_FL;
+ channel_mapping[2] = PCM_CHANNEL_FR;
+ channel_mapping[3] = PCM_CHANNEL_LB;
+ channel_mapping[4] = PCM_CHANNEL_RB;
+ channel_mapping[5] = PCM_CHANNEL_LFE;
} else if (channels == 8) {
lchannel_mapping[0] = PCM_CHANNEL_FL;
lchannel_mapping[1] = PCM_CHANNEL_FR;
@@ -1862,14 +1862,15 @@
lchannel_mapping[3] = PCM_CHANNEL_FC;
lchannel_mapping[4] = PCM_CHANNEL_LB;
lchannel_mapping[5] = PCM_CHANNEL_RB;
- lchannel_mapping[6] = PCM_CHANNEL_FLC;
- lchannel_mapping[7] = PCM_CHANNEL_FRC;
+ lchannel_mapping[6] = PCM_CHANNEL_RLC;
+ lchannel_mapping[7] = PCM_CHANNEL_RRC;
} else {
pr_err("%s: ERROR.unsupported num_ch = %u\n",
__func__, channels);
return -EINVAL;
}
return 0;
+
}
int q6asm_enable_sbrps(struct audio_client *ac,