Merge "ASoC: msm: qdsp6: Add support to configure ISO and ARIB coefficients"
diff --git a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
index 1b881f0..aa24dc6 100644
--- a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
+++ b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
@@ -203,21 +203,6 @@
- qcom,cpr-uplift-speed-bin: The speed bin value corresponding to one type of processor which needs to apply the
pvs voltage uplift workaround.
This is required if cpr-fuse-uplift-disable-sel is present.
-- qcom,cpr-quot-adjust-table: Array of triples in which each triple indicates the speed bin of the CPU, the virtual
- corner to use and the quotient adjustment.
- The 3 elements in one triple are:
- [0]: => the speed bin of the CPU.
- [1]: => the virtual voltage corner to use.
- [2]: => the quotient adjustment for the corresponding virtual corner.
- If the speed bin in a triple is equal to the speed bin of the CPU, the adjustment would
- be subtracted from the quotient value of the voltage corner when the CPU is running at
- that virtual corner. Each virtual corner value must be in the range 1 to the number of
- elements in qcom,cpr-corner-map.
-- qcom,cpr-corner-map: Array of elements of fuse corner value for each virtual corner.
- The location or 1-based index of an element in the list corresponds to
- the virtual corner value. For example, the first element in the list is the fuse corner
- value that virtual corner 1 maps to.
- This is required if qcom,cpr-quot-adjust-table is present.
- qcom,cpr-quotient-adjustment: Array of three elements of CPR quotient adjustments for each corner.
The 3 quotient adjustments with index[0..2] are:
[0] => amount to add to the SVS quotient
@@ -230,6 +215,42 @@
Not Present: No such regulator.
- vdd-apc-optional-sec-supply: Present: Regulator of second highest priority to supply VDD APC power.
Not Present: No such regulator.
+- qcom,cpr-speed-bin-max-corners: Array of quintuples in which each quintuple maps a CPU speed bin and PVS version to
+ the maximum virtual voltage corner corresponding to the SVS, NORMAL and TURBO corners.
+ The 5 elements in one quintuple are:
+ [0]: => the speed bin of the CPU.
+ [1]: => the PVS version of the CPU.
+ [2]: => the max virtual voltage corner value corresponding to SVS corner for this speed bin.
+ [3]: => the max virtual voltage corner value corresponding to NORMAL corner for this speed bin.
+ [4]: => the max virtual voltage corner value corresponding to TURBO corner for this speed bin.
+ No CPR target quotient scaling is applied on chips which have a speed bin + PVS version
+ pair that does not appear in one of the quintuples in this property. If the property is
+ specified, then quotient scaling is enabled for the TURBO corner. If this property is
+ not specified, then no quotient scaling can take place.
+- qcom,cpr-corner-map: Array of elements of fuse corner value for each virtual corner.
+ The location or 1-based index of an element in the list corresponds to
+ the virtual corner value. For example, the first element in the list is the fuse corner
+ value that virtual corner 1 maps to.
+ This property is required if qcom,cpr-speed-bin-max-corners is present.
+- qcom,cpr-corner-frequency-map: Array of tuples in which a tuple describes a corner to application processor frequency
+ mapping.
+ The 2 elements in one tuple are:
+ [0]: => a virtual voltage corner.
+ [1]: => the application processor frequency in Hz corresponding to the virtual corner.
+ This property is required if qcom,cpr-speed-bin-max-corners is present.
+- qcom,pvs-version-fuse-sel: Array of 4 elements to indicate where to read the pvs version of the processor,
+ and the fuse reading method.
+ The 4 elements with index[0..3] are:
+ [0]: => the fuse row number of the selector;
+ [1]: => LSB bit position of the bits;
+ [2]: => the number of bits;
+ [3]: => fuse reading method, 0 for direct reading or 1 for SCM reading.
+ This property is required if qcom,cpr-speed-bin-max-corners is present.
+- qcom,cpr-quot-adjust-scaling-factor-max: The maximum allowed CPR target quotient scaling factor to use when
+ calculating the quotient adjustment for a given virtual voltage corner. It
+ corresponds to 'scaling' in this equation:
+ quot_adjust = (freq_turbo - freq_corner) * scaling / 1000.
+ This property is required if qcom,cpr-speed-bin-max-corners is present.
Example:
apc_vreg_corner: regulator@f9018000 {
@@ -319,9 +340,25 @@
qcom,cpr-uplift-speed-bin = <1>;
qcom,speed-bin-fuse-sel = <22 0 3 0>;
qcom,cpr-corner-map = <1 1 2 2 3 3 3 3 3 3 3 3>;
- qcom,cpr-quot-adjust-table = <1 1 0>, <1 2 0>, <1 3 0>,
- <1 4 0>, <1 5 450>, <1 6 375>,
- <1 7 300>, <1 8 225>, <1 9 187>,
- <1 10 150>, <1 11 75>, <1 12 0>;
+ qcom,cpr-corner-frequency-map =
+ <1 300000000>,
+ <2 384000000>,
+ <3 600000000>,
+ <4 787200000>,
+ <5 998400000>,
+ <6 1094400000>,
+ <7 1190400000>,
+ <8 1305600000>,
+ <9 1344000000>,
+ <10 1401600000>,
+ <11 1497600000>,
+ <12 1593600000>;
+ qcom,pvs-version-fuse-sel = <22 4 2 0>;
+ qcom,cpr-speed-bin-max-corners =
+ <0 1 2 4 7>,
+ <1 1 2 4 12>,
+ <2 1 2 4 10>,
+ <5 1 2 4 14>;
+ qcom,cpr-quot-adjust-scaling-factor-max = <650>;
};
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt
index cda437a..e8b02cf 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt
@@ -6,7 +6,8 @@
Required properties:
- compatible: Must be "qcom,mdss-dsi-ctrl"
- cell-index: Specifies the controller used among the two controllers.
-- reg: offset and length of the register set for the device.
+- 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.
- vdd-supply: Phandle for vdd regulator device node.
- vddio-supply: Phandle for vdd-io regulator device node.
- vdda-supply: Phandle for vreg regulator device node.
@@ -52,7 +53,9 @@
compatible = "qcom,mdss-dsi-ctrl";
label = "MDSS DSI CTRL->0";
cell-index = <0>;
- reg = <0xfd922800 0x600>;
+ reg = <0xfd922800 0x600>,
+ <0xfd828000 0x108>;
+ reg-names = "dsi_phys", "mmss_misc_phys";
vdd-supply = <&pm8226_l15>;
vddio-supply = <&pm8226_l8>;
vdda-supply = <&pm8226_l4>;
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index 4bc67ff..02d6df9 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -256,6 +256,7 @@
delay required by panel to reach functional.
- qcom,mdss-dsi-rx-eot-ignore: Boolean used to enable ignoring end of transmission packets.
- qcom,mdss-dsi-tx-eot-append: Boolean used to enable appending end of transmission packets.
+- qcom,ulps-enabled: Boolean to enable support for Ultra Low Power State (ULPS) mode.
Note, if a given optional qcom,* binding is not present, then the driver will configure
the default values specified.
@@ -352,5 +353,6 @@
qcom,mdss-dsi-init-delay-us = <100>;
mdss-dsi-rx-eot-ignore;
mdss-dsi-tx-eot-append;
+ qcom,ulps-enabled;
};
};
diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
index 656f3a4..ec5cfa5 100644
--- a/Documentation/devicetree/bindings/gpu/adreno.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno.txt
@@ -71,6 +71,13 @@
This is used to override faulty hardware readings.
- qcom,strtstp-sleepwake: Boolean. Enables use of GPU SLUMBER instead of SLEEP for power savings
+- qcom,pm-qos-latency: Every time GPU wakes up from sleep, driver votes for
+ acceptable maximum latency to the pm-qos driver. This
+ voting demands that *CPU* can not go into a power save
+ state *if* the latency to bring CPU back into normal
+ state is more than this value.
+ Value is in microseconds.
+
The following properties are optional as collecting data via coresight might
not be supported for every chipset. The documentation for coresight
properties can be found in:
diff --git a/Documentation/devicetree/bindings/mtd/msm_qpic_nand.txt b/Documentation/devicetree/bindings/mtd/msm_qpic_nand.txt
index 8cef7f0..447c8c1 100644
--- a/Documentation/devicetree/bindings/mtd/msm_qpic_nand.txt
+++ b/Documentation/devicetree/bindings/mtd/msm_qpic_nand.txt
@@ -13,11 +13,12 @@
Each partition is represented as a sub-node of the qcom,mtd-partitions device.
Each node's name represents the name of the corresponding partition.
-Required properties:
-- reg : The partition offset and size
-- label : The label / name for this partition.
+This is now completely optional as the partition information is avaialble from
+bootloader.
Optional properties:
+- reg : The partition offset and size
+- label : The label / name for this partition.
- read-only: This parameter, if present, indicates that this partition
should only be mounted read-only.
diff --git a/Documentation/devicetree/bindings/nfc/nfc-nci.txt b/Documentation/devicetree/bindings/nfc/nfc-nci.txt
index 2c06599..7af847c 100644
--- a/Documentation/devicetree/bindings/nfc/nfc-nci.txt
+++ b/Documentation/devicetree/bindings/nfc/nfc-nci.txt
@@ -12,13 +12,12 @@
- qcom,clk-src-gpio: msm gpio clock,used ony if clock source is msm gpio
- qcom,clk-req-gpio: clk-req input gpio for MSM based clocks.
not used for pmic implementation
-- vlogic-supply: LDO for power supply
- interrupt-parent: Should be phandle for the interrupt controller
that services interrupts for this device.
- interrupts: Nfc read interrupt,gpio-clk-req interrupt
- qcom,clk-gpio: pmic or msm gpio on which bbclk2 signal is coming.
-LDO example:
+Example:
i2c@f9925000 { /* BLSP-1 QUP-3 */
nfc-nci@e {
@@ -31,7 +30,6 @@
interrupt-parent = <&msmgpio>;
interrupts = <77 0>;
qcom,clk-gpio = <&msmgpio 75 0x00>;
- vlogic-supply = <&pm8110_l14>;
};
};
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index fd826d9..b94b587 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -8,6 +8,7 @@
apm Applied Micro Circuits Corporation (APM)
arm ARM Ltd.
atmel Atmel Corporation
+avago Avago Technologies
bosch Bosch Sensortec GmbH
capella Capella Microsystems, Inc.
cavium Cavium, Inc.
diff --git a/arch/arm/boot/dts/msm8226-gpu.dtsi b/arch/arm/boot/dts/msm8226-gpu.dtsi
index fd20d8c..d1c3264 100644
--- a/arch/arm/boot/dts/msm8226-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8226-gpu.dtsi
@@ -47,6 +47,9 @@
/* IOMMU Data */
iommu = <&kgsl_iommu>;
+ /* CPU latency parameter */
+ qcom,pm-qos-latency = <701>;
+
/* Power levels */
qcom,gpu-pwrlevels {
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/msm8226-mdss.dtsi b/arch/arm/boot/dts/msm8226-mdss.dtsi
index 375c5df..2176d39 100644
--- a/arch/arm/boot/dts/msm8226-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8226-mdss.dtsi
@@ -95,7 +95,9 @@
compatible = "qcom,mdss-dsi-ctrl";
label = "MDSS DSI CTRL->0";
cell-index = <0>;
- reg = <0xfd922800 0x600>;
+ reg = <0xfd922800 0x600>,
+ <0xfd828000 0x108>;
+ reg-names = "dsi_phys", "mmss_misc_phys";
qcom,mdss-fb-map = <&mdss_fb0>;
qcom,mdss-mdp = <&mdss_mdp>;
vdd-supply = <&pm8226_l15>;
diff --git a/arch/arm/boot/dts/msm8226-v2.dtsi b/arch/arm/boot/dts/msm8226-v2.dtsi
index 6215740..14fe237 100644
--- a/arch/arm/boot/dts/msm8226-v2.dtsi
+++ b/arch/arm/boot/dts/msm8226-v2.dtsi
@@ -37,14 +37,28 @@
qcom,cpr-up-threshold = <0>;
qcom,cpr-down-threshold = <5>;
qcom,cpr-corner-map = <1 1 2 2 3 3 3 3 3 3 3 3 3 3>;
- qcom,cpr-quot-adjust-table =
- <1 5 450>,
- <1 6 375>,
- <1 7 300>,
- <1 8 225>,
- <1 9 187>,
- <1 10 150>,
- <1 11 75>;
+ qcom,pvs-version-fuse-sel = <22 4 2 0>;
+ qcom,cpr-corner-frequency-map =
+ <1 300000000>,
+ <2 384000000>,
+ <3 600000000>,
+ <4 787200000>,
+ <5 998400000>,
+ <6 1094400000>,
+ <7 1190400000>,
+ <8 1305600000>,
+ <9 1344000000>,
+ <10 1401600000>,
+ <11 1497600000>,
+ <12 1593600000>,
+ <13 1689600000>,
+ <14 1785600000>;
+ qcom,cpr-speed-bin-max-corners =
+ <0 2 2 4 7>,
+ <1 2 2 4 12>,
+ <2 2 2 4 10>,
+ <5 2 2 4 14>;
+ qcom,cpr-quot-adjust-scaling-factor-max = <650>;
};
&msm_gpu {
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index ff97564..cf8e3b3 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -1264,8 +1264,8 @@
qcom,msm-bus,num-cases = <2>;
qcom,msm-bus,num-paths = <1>;
qcom,msm-bus,vectors-KBps =
- <1 618 0 0>,
- <1 618 0 800>;
+ <54 618 0 0>,
+ <54 618 0 800>;
};
qcom,tz-log@fe805720 {
diff --git a/arch/arm/boot/dts/msm8610-gpu.dtsi b/arch/arm/boot/dts/msm8610-gpu.dtsi
index de480df..480ec11 100644
--- a/arch/arm/boot/dts/msm8610-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8610-gpu.dtsi
@@ -46,6 +46,9 @@
/* IOMMU Data */
iommu = <&gfx_iommu>;
+ /* CPU latency parameter */
+ qcom,pm-qos-latency = <701>;
+
/* Power levels */
qcom,gpu-pwrlevels {
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index f152ceb..90e8fd6 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -765,6 +765,11 @@
compatible = "qcom,msm-dai-q6-dev";
qcom,msm-dai-q6-dev-id = <32773>;
};
+
+ qcom,msm-dai-q6-incall-music-2-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32770>;
+ };
};
qcom,msm-pcm-hostless {
diff --git a/arch/arm/boot/dts/msm8926.dtsi b/arch/arm/boot/dts/msm8926.dtsi
index 8a0e5c4..e866286 100644
--- a/arch/arm/boot/dts/msm8926.dtsi
+++ b/arch/arm/boot/dts/msm8926.dtsi
@@ -138,15 +138,29 @@
regulator-min-microvolt = <1>;
regulator-max-microvolt = <14>;
qcom,cpr-corner-map = <1 1 2 2 3 3 3 3 3 3 3 3 3 3>;
- qcom,cpr-quot-adjust-table =
- <1 5 450>,
- <1 6 375>,
- <1 7 300>,
- <1 8 225>,
- <1 9 187>,
- <1 10 150>,
- <1 11 75>;
qcom,cpr-quotient-adjustment = <0 72 72>;
+ qcom,pvs-version-fuse-sel = <22 4 2 0>;
+ qcom,cpr-corner-frequency-map =
+ <1 300000000>,
+ <2 384000000>,
+ <3 600000000>,
+ <4 787200000>,
+ <5 998400000>,
+ <6 1094400000>,
+ <7 1190400000>,
+ <8 1305600000>,
+ <9 1344000000>,
+ <10 1401600000>,
+ <11 1497600000>,
+ <12 1593600000>,
+ <13 1689600000>,
+ <14 1785600000>;
+ qcom,cpr-speed-bin-max-corners =
+ <0 1 2 4 7>,
+ <1 1 2 4 12>,
+ <2 1 2 4 10>,
+ <5 1 2 4 14>;
+ qcom,cpr-quot-adjust-scaling-factor-max = <650>;
};
&tsens {
diff --git a/arch/arm/boot/dts/msm8974-mdss.dtsi b/arch/arm/boot/dts/msm8974-mdss.dtsi
index 7f63234..0e72446 100644
--- a/arch/arm/boot/dts/msm8974-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8974-mdss.dtsi
@@ -113,7 +113,9 @@
compatible = "qcom,mdss-dsi-ctrl";
label = "MDSS DSI CTRL->0";
cell-index = <0>;
- reg = <0xfd922800 0x600>;
+ reg = <0xfd922800 0x600>,
+ <0xfdf30000 0x108>;
+ reg-names = "dsi_phys", "mmss_misc_phys";
vdd-supply = <&pm8941_l22>;
vddio-supply = <&pm8941_l12>;
vdda-supply = <&pm8941_l2>;
@@ -169,7 +171,9 @@
compatible = "qcom,mdss-dsi-ctrl";
label = "MDSS DSI CTRL->1";
cell-index = <1>;
- reg = <0xfd922e00 0x600>;
+ reg = <0xfd922e00 0x600>,
+ <0xfdf30000 0x108>;
+ reg-names = "dsi_phys", "mmss_misc_phys";
vdd-supply = <&pm8941_l22>;
vddio-supply = <&pm8941_l12>;
vdda-supply = <&pm8941_l2>;
diff --git a/arch/arm/boot/dts/msm8974pro-pm.dtsi b/arch/arm/boot/dts/msm8974pro-pm.dtsi
index aca8f20..f735b65 100644
--- a/arch/arm/boot/dts/msm8974pro-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pm.dtsi
@@ -242,6 +242,7 @@
<0xff 109>, /* ocmem_dm_nonsec_irq */
<0xff 126>, /* bam_irq[0] */
<0xff 140>, /* uart_dm_intr */
+ <0xff 146>, /* uart_dm_intr: blsp2_uart_2_irq */
<0xff 155>, /* sdcc_irq[0] */
<0xff 157>, /* sdcc_irq[0] */
<0xff 159>, /* sdcc_irq[0] */
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index c7abf42..1ba8527 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -412,6 +412,8 @@
CONFIG_CRYPTO_MD4=y
CONFIG_CRYPTO_ARC4=y
CONFIG_CRYPTO_TWOFISH=y
+CONFIG_MOBICORE_SUPPORT=m
+CONFIG_MOBICORE_API=m
# CONFIG_CRYPTO_HW is not set
CONFIG_CRC_CCITT=y
CONFIG_PPP=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index fe84f96..458faac 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -485,3 +485,5 @@
CONFIG_SENSORS_MMA8X5X=y
CONFIG_SENSORS_CAPELLA_CM36283=y
CONFIG_MSM_RDBG=m
+CONFIG_MOBICORE_SUPPORT=m
+CONFIG_MOBICORE_API=m
diff --git a/arch/arm/mach-msm/board-8226-gpiomux.c b/arch/arm/mach-msm/board-8226-gpiomux.c
index 5882ebc..fe7de31 100644
--- a/arch/arm/mach-msm/board-8226-gpiomux.c
+++ b/arch/arm/mach-msm/board-8226-gpiomux.c
@@ -11,6 +11,7 @@
*
*/
+#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <mach/board.h>
@@ -18,6 +19,12 @@
#include <mach/gpiomux.h>
#include <mach/socinfo.h>
+#define WLAN_CLK 44
+#define WLAN_SET 43
+#define WLAN_DATA0 42
+#define WLAN_DATA1 41
+#define WLAN_DATA2 40
+
#ifdef CONFIG_USB_EHCI_MSM_HSIC
static struct gpiomux_setting hsic_sus_cfg = {
.func = GPIOMUX_FUNC_GPIO,
@@ -140,6 +147,18 @@
.pull = GPIOMUX_PULL_DOWN,
};
+static struct gpiomux_setting wcnss_5gpio_suspend_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting wcnss_5gpio_active_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
static struct gpiomux_setting gpio_i2c_config = {
.func = GPIOMUX_FUNC_3,
.drv = GPIOMUX_DRV_2MA,
@@ -542,6 +561,44 @@
},
};
+static struct msm_gpiomux_config wcnss_5gpio_interface[] = {
+ {
+ .gpio = 40,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 41,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 42,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 43,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 44,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+};
+
static struct gpiomux_setting gpio_suspend_config[] = {
{
.func = GPIOMUX_FUNC_GPIO, /* IN-NP */
@@ -884,3 +941,109 @@
msm_gpiomux_install(msm_hsic_configs, ARRAY_SIZE(msm_hsic_configs));
#endif
}
+
+static void wcnss_switch_to_gpio(void)
+{
+ /* Switch MUX to GPIO */
+ msm_gpiomux_install(wcnss_5gpio_interface,
+ ARRAY_SIZE(wcnss_5gpio_interface));
+
+ /* Ensure GPIO config */
+ gpio_direction_input(WLAN_DATA2);
+ gpio_direction_input(WLAN_DATA1);
+ gpio_direction_input(WLAN_DATA0);
+ gpio_direction_output(WLAN_SET, 0);
+ gpio_direction_output(WLAN_CLK, 0);
+}
+
+static void wcnss_switch_to_5wire(void)
+{
+ msm_gpiomux_install(wcnss_5wire_interface,
+ ARRAY_SIZE(wcnss_5wire_interface));
+}
+
+u32 wcnss_rf_read_reg(u32 rf_reg_addr)
+{
+ int count = 0;
+ u32 rf_cmd_and_addr = 0;
+ u32 rf_data_received = 0;
+ u32 rf_bit = 0;
+
+ wcnss_switch_to_gpio();
+
+ /* Reset the signal if it is already being used. */
+ gpio_set_value(WLAN_SET, 0);
+ gpio_set_value(WLAN_CLK, 0);
+
+ /* We start with cmd_set high WLAN_SET = 1. */
+ gpio_set_value(WLAN_SET, 1);
+
+ gpio_direction_output(WLAN_DATA0, 1);
+ gpio_direction_output(WLAN_DATA1, 1);
+ gpio_direction_output(WLAN_DATA2, 1);
+
+ gpio_set_value(WLAN_DATA0, 0);
+ gpio_set_value(WLAN_DATA1, 0);
+ gpio_set_value(WLAN_DATA2, 0);
+
+ /* Prepare command and RF register address that need to sent out.
+ * Make sure that we send only 14 bits from LSB.
+ */
+ rf_cmd_and_addr = (((WLAN_RF_READ_REG_CMD) |
+ (rf_reg_addr << WLAN_RF_REG_ADDR_START_OFFSET)) &
+ WLAN_RF_READ_CMD_MASK);
+
+ for (count = 0; count < 5; count++) {
+ gpio_set_value(WLAN_CLK, 0);
+
+ rf_bit = (rf_cmd_and_addr & 0x1);
+ gpio_set_value(WLAN_DATA0, rf_bit ? 1 : 0);
+ rf_cmd_and_addr = (rf_cmd_and_addr >> 1);
+
+ rf_bit = (rf_cmd_and_addr & 0x1);
+ gpio_set_value(WLAN_DATA1, rf_bit ? 1 : 0);
+ rf_cmd_and_addr = (rf_cmd_and_addr >> 1);
+
+ rf_bit = (rf_cmd_and_addr & 0x1);
+ gpio_set_value(WLAN_DATA2, rf_bit ? 1 : 0);
+ rf_cmd_and_addr = (rf_cmd_and_addr >> 1);
+
+ /* Send the data out WLAN_CLK = 1 */
+ gpio_set_value(WLAN_CLK, 1);
+ }
+
+ /* Pull down the clock signal */
+ gpio_set_value(WLAN_CLK, 0);
+
+ /* Configure data pins to input IO pins */
+ gpio_direction_input(WLAN_DATA0);
+ gpio_direction_input(WLAN_DATA1);
+ gpio_direction_input(WLAN_DATA2);
+
+ for (count = 0; count < 2; count++) {
+ gpio_set_value(WLAN_CLK, 1);
+ gpio_set_value(WLAN_CLK, 0);
+ }
+
+ rf_bit = 0;
+ for (count = 0; count < 6; count++) {
+ gpio_set_value(WLAN_CLK, 1);
+ gpio_set_value(WLAN_CLK, 0);
+
+ rf_bit = gpio_get_value(WLAN_DATA0);
+ rf_data_received |= (rf_bit << (count * 3 + 0));
+
+ if (count != 5) {
+ rf_bit = gpio_get_value(WLAN_DATA1);
+ rf_data_received |= (rf_bit << (count * 3 + 1));
+
+ rf_bit = gpio_get_value(WLAN_DATA2);
+ rf_data_received |= (rf_bit << (count * 3 + 2));
+ }
+ }
+
+ gpio_set_value(WLAN_SET, 0);
+ wcnss_switch_to_5wire();
+
+ return rf_data_received;
+}
diff --git a/arch/arm/mach-msm/board-8226.c b/arch/arm/mach-msm/board-8226.c
index 1c1fbe3..43646cd 100644
--- a/arch/arm/mach-msm/board-8226.c
+++ b/arch/arm/mach-msm/board-8226.c
@@ -167,7 +167,7 @@
NULL
};
-DT_MACHINE_START(MSM8226_DT, "Qualcomm MSM 8226 (Flattened Device Tree)")
+DT_MACHINE_START(MSM8226_DT, "Qualcomm MSM 8x26 / MSM 8x28 (Flattened Device Tree)")
.map_io = msm_map_msm8226_io,
.init_irq = msm_dt_init_irq,
.init_machine = msm8226_init,
diff --git a/arch/arm/mach-msm/board-8610-gpiomux.c b/arch/arm/mach-msm/board-8610-gpiomux.c
index 2e12fc2..4234f2a 100644
--- a/arch/arm/mach-msm/board-8610-gpiomux.c
+++ b/arch/arm/mach-msm/board-8610-gpiomux.c
@@ -11,6 +11,7 @@
*
*/
+#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <mach/board.h>
@@ -18,6 +19,12 @@
#include <mach/gpiomux.h>
#include <mach/socinfo.h>
+#define WLAN_CLK 27
+#define WLAN_SET 26
+#define WLAN_DATA0 25
+#define WLAN_DATA1 24
+#define WLAN_DATA2 23
+
static struct gpiomux_setting gpio_spi_config = {
.func = GPIOMUX_FUNC_1,
.drv = GPIOMUX_DRV_6MA,
@@ -112,6 +119,18 @@
.pull = GPIOMUX_PULL_DOWN,
};
+static struct gpiomux_setting wcnss_5gpio_suspend_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting wcnss_5gpio_active_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
static struct gpiomux_setting lcd_en_act_cfg = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_8MA,
@@ -405,6 +424,44 @@
},
};
+static struct msm_gpiomux_config wcnss_5gpio_interface[] = {
+ {
+ .gpio = 23,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 24,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 25,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 26,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 27,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+};
+
static struct gpiomux_setting gpio_suspend_config[] = {
{
.func = GPIOMUX_FUNC_GPIO, /* IN-NP */
@@ -714,3 +771,109 @@
msm_gpiomux_install(msm_cdc_dmic_configs,
ARRAY_SIZE(msm_cdc_dmic_configs));
}
+
+static void wcnss_switch_to_gpio(void)
+{
+ /* Switch MUX to GPIO */
+ msm_gpiomux_install(wcnss_5gpio_interface,
+ ARRAY_SIZE(wcnss_5gpio_interface));
+
+ /* Ensure GPIO config */
+ gpio_direction_input(WLAN_DATA2);
+ gpio_direction_input(WLAN_DATA1);
+ gpio_direction_input(WLAN_DATA0);
+ gpio_direction_output(WLAN_SET, 0);
+ gpio_direction_output(WLAN_CLK, 0);
+}
+
+static void wcnss_switch_to_5wire(void)
+{
+ msm_gpiomux_install(wcnss_5wire_interface,
+ ARRAY_SIZE(wcnss_5wire_interface));
+}
+
+u32 wcnss_rf_read_reg(u32 rf_reg_addr)
+{
+ int count = 0;
+ u32 rf_cmd_and_addr = 0;
+ u32 rf_data_received = 0;
+ u32 rf_bit = 0;
+
+ wcnss_switch_to_gpio();
+
+ /* Reset the signal if it is already being used. */
+ gpio_set_value(WLAN_SET, 0);
+ gpio_set_value(WLAN_CLK, 0);
+
+ /* We start with cmd_set high WLAN_SET = 1. */
+ gpio_set_value(WLAN_SET, 1);
+
+ gpio_direction_output(WLAN_DATA0, 1);
+ gpio_direction_output(WLAN_DATA1, 1);
+ gpio_direction_output(WLAN_DATA2, 1);
+
+ gpio_set_value(WLAN_DATA0, 0);
+ gpio_set_value(WLAN_DATA1, 0);
+ gpio_set_value(WLAN_DATA2, 0);
+
+ /* Prepare command and RF register address that need to sent out.
+ * Make sure that we send only 14 bits from LSB.
+ */
+ rf_cmd_and_addr = (((WLAN_RF_READ_REG_CMD) |
+ (rf_reg_addr << WLAN_RF_REG_ADDR_START_OFFSET)) &
+ WLAN_RF_READ_CMD_MASK);
+
+ for (count = 0; count < 5; count++) {
+ gpio_set_value(WLAN_CLK, 0);
+
+ rf_bit = (rf_cmd_and_addr & 0x1);
+ gpio_set_value(WLAN_DATA0, rf_bit ? 1 : 0);
+ rf_cmd_and_addr = (rf_cmd_and_addr >> 1);
+
+ rf_bit = (rf_cmd_and_addr & 0x1);
+ gpio_set_value(WLAN_DATA1, rf_bit ? 1 : 0);
+ rf_cmd_and_addr = (rf_cmd_and_addr >> 1);
+
+ rf_bit = (rf_cmd_and_addr & 0x1);
+ gpio_set_value(WLAN_DATA2, rf_bit ? 1 : 0);
+ rf_cmd_and_addr = (rf_cmd_and_addr >> 1);
+
+ /* Send the data out WLAN_CLK = 1 */
+ gpio_set_value(WLAN_CLK, 1);
+ }
+
+ /* Pull down the clock signal */
+ gpio_set_value(WLAN_CLK, 0);
+
+ /* Configure data pins to input IO pins */
+ gpio_direction_input(WLAN_DATA0);
+ gpio_direction_input(WLAN_DATA1);
+ gpio_direction_input(WLAN_DATA2);
+
+ for (count = 0; count < 2; count++) {
+ gpio_set_value(WLAN_CLK, 1);
+ gpio_set_value(WLAN_CLK, 0);
+ }
+
+ rf_bit = 0;
+ for (count = 0; count < 6; count++) {
+ gpio_set_value(WLAN_CLK, 1);
+ gpio_set_value(WLAN_CLK, 0);
+
+ rf_bit = gpio_get_value(WLAN_DATA0);
+ rf_data_received |= (rf_bit << (count * 3 + 0));
+
+ if (count != 5) {
+ rf_bit = gpio_get_value(WLAN_DATA1);
+ rf_data_received |= (rf_bit << (count * 3 + 1));
+
+ rf_bit = gpio_get_value(WLAN_DATA2);
+ rf_data_received |= (rf_bit << (count * 3 + 2));
+ }
+ }
+
+ gpio_set_value(WLAN_SET, 0);
+ wcnss_switch_to_5wire();
+
+ return rf_data_received;
+}
diff --git a/arch/arm/mach-msm/board-8610.c b/arch/arm/mach-msm/board-8610.c
index d175bb4..cd9b82e 100644
--- a/arch/arm/mach-msm/board-8610.c
+++ b/arch/arm/mach-msm/board-8610.c
@@ -136,7 +136,7 @@
NULL
};
-DT_MACHINE_START(MSM8610_DT, "Qualcomm MSM 8610 (Flattened Device Tree)")
+DT_MACHINE_START(MSM8610_DT, "Qualcomm MSM 8x10 / MSM 8x12 (Flattened Device Tree)")
.map_io = msm_map_msm8610_io,
.init_irq = msm_dt_init_irq,
.init_machine = msm8610_init,
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index cec1a8f..5d4d379 100755
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -11,6 +11,7 @@
*
*/
+#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <mach/board.h>
@@ -20,6 +21,12 @@
#define KS8851_IRQ_GPIO 94
+#define WLAN_CLK 40
+#define WLAN_SET 39
+#define WLAN_DATA0 38
+#define WLAN_DATA1 37
+#define WLAN_DATA2 36
+
static struct gpiomux_setting ap2mdm_cfg = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_2MA,
@@ -208,6 +215,18 @@
.pull = GPIOMUX_PULL_DOWN,
};
+static struct gpiomux_setting wcnss_5gpio_suspend_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting wcnss_5gpio_active_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
static struct gpiomux_setting ath_gpio_active_cfg = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_2MA,
@@ -1158,6 +1177,43 @@
},
};
+static struct msm_gpiomux_config wcnss_5gpio_interface[] = {
+ {
+ .gpio = 36,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 37,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 38,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 39,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 40,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+};
static struct msm_gpiomux_config ath_gpio_configs[] = {
{
@@ -1467,3 +1523,109 @@
msm_gpiomux_install(apq8074_dragonboard_ts_config,
ARRAY_SIZE(apq8074_dragonboard_ts_config));
}
+
+static void wcnss_switch_to_gpio(void)
+{
+ /* Switch MUX to GPIO */
+ msm_gpiomux_install(wcnss_5gpio_interface,
+ ARRAY_SIZE(wcnss_5gpio_interface));
+
+ /* Ensure GPIO config */
+ gpio_direction_input(WLAN_DATA2);
+ gpio_direction_input(WLAN_DATA1);
+ gpio_direction_input(WLAN_DATA0);
+ gpio_direction_output(WLAN_SET, 0);
+ gpio_direction_output(WLAN_CLK, 0);
+}
+
+static void wcnss_switch_to_5wire(void)
+{
+ msm_gpiomux_install(wcnss_5wire_interface,
+ ARRAY_SIZE(wcnss_5wire_interface));
+}
+
+u32 wcnss_rf_read_reg(u32 rf_reg_addr)
+{
+ int count = 0;
+ u32 rf_cmd_and_addr = 0;
+ u32 rf_data_received = 0;
+ u32 rf_bit = 0;
+
+ wcnss_switch_to_gpio();
+
+ /* Reset the signal if it is already being used. */
+ gpio_set_value(WLAN_SET, 0);
+ gpio_set_value(WLAN_CLK, 0);
+
+ /* We start with cmd_set high WLAN_SET = 1. */
+ gpio_set_value(WLAN_SET, 1);
+
+ gpio_direction_output(WLAN_DATA0, 1);
+ gpio_direction_output(WLAN_DATA1, 1);
+ gpio_direction_output(WLAN_DATA2, 1);
+
+ gpio_set_value(WLAN_DATA0, 0);
+ gpio_set_value(WLAN_DATA1, 0);
+ gpio_set_value(WLAN_DATA2, 0);
+
+ /* Prepare command and RF register address that need to sent out.
+ * Make sure that we send only 14 bits from LSB.
+ */
+ rf_cmd_and_addr = (((WLAN_RF_READ_REG_CMD) |
+ (rf_reg_addr << WLAN_RF_REG_ADDR_START_OFFSET)) &
+ WLAN_RF_READ_CMD_MASK);
+
+ for (count = 0; count < 5; count++) {
+ gpio_set_value(WLAN_CLK, 0);
+
+ rf_bit = (rf_cmd_and_addr & 0x1);
+ gpio_set_value(WLAN_DATA0, rf_bit ? 1 : 0);
+ rf_cmd_and_addr = (rf_cmd_and_addr >> 1);
+
+ rf_bit = (rf_cmd_and_addr & 0x1);
+ gpio_set_value(WLAN_DATA1, rf_bit ? 1 : 0);
+ rf_cmd_and_addr = (rf_cmd_and_addr >> 1);
+
+ rf_bit = (rf_cmd_and_addr & 0x1);
+ gpio_set_value(WLAN_DATA2, rf_bit ? 1 : 0);
+ rf_cmd_and_addr = (rf_cmd_and_addr >> 1);
+
+ /* Send the data out WLAN_CLK = 1 */
+ gpio_set_value(WLAN_CLK, 1);
+ }
+
+ /* Pull down the clock signal */
+ gpio_set_value(WLAN_CLK, 0);
+
+ /* Configure data pins to input IO pins */
+ gpio_direction_input(WLAN_DATA0);
+ gpio_direction_input(WLAN_DATA1);
+ gpio_direction_input(WLAN_DATA2);
+
+ for (count = 0; count < 2; count++) {
+ gpio_set_value(WLAN_CLK, 1);
+ gpio_set_value(WLAN_CLK, 0);
+ }
+
+ rf_bit = 0;
+ for (count = 0; count < 6; count++) {
+ gpio_set_value(WLAN_CLK, 1);
+ gpio_set_value(WLAN_CLK, 0);
+
+ rf_bit = gpio_get_value(WLAN_DATA0);
+ rf_data_received |= (rf_bit << (count * 3 + 0));
+
+ if (count != 5) {
+ rf_bit = gpio_get_value(WLAN_DATA1);
+ rf_data_received |= (rf_bit << (count * 3 + 1));
+
+ rf_bit = gpio_get_value(WLAN_DATA2);
+ rf_data_received |= (rf_bit << (count * 3 + 2));
+ }
+ }
+
+ gpio_set_value(WLAN_SET, 0);
+ wcnss_switch_to_5wire();
+
+ return rf_data_received;
+}
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index d16d0f1..d1f8666 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -3383,6 +3383,8 @@
CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd922800.qcom,mdss_dsi"),
CLK_LOOKUP("bus_clk", mdss_axi_clk.c, "fd922800.qcom,mdss_dsi"),
CLK_LOOKUP("mdp_core_clk", mdss_mdp_clk.c, "fd922800.qcom,mdss_dsi"),
+ CLK_LOOKUP("core_mmss_clk", mmss_misc_ahb_clk.c,
+ "fd922800.qcom,mdss_dsi"),
CLK_LOOKUP("core_clk", mdss_mdp_clk.c, "fd900000.qcom,mdss_mdp"),
CLK_LOOKUP("lut_clk", mdss_mdp_lut_clk.c, "fd900000.qcom,mdss_mdp"),
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index fc5a78a..b42878d 100755
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -5076,6 +5076,10 @@
CLK_LOOKUP("pixel_clk", mdss_pclk1_clk.c, "fd922e00.qcom,mdss_dsi"),
CLK_LOOKUP("mdp_core_clk", mdss_mdp_clk.c, "fd922800.qcom,mdss_dsi"),
CLK_LOOKUP("mdp_core_clk", mdss_mdp_clk.c, "fd922e00.qcom,mdss_dsi"),
+ CLK_LOOKUP("core_mmss_clk", mmss_misc_ahb_clk.c,
+ "fd922800.qcom,mdss_dsi"),
+ CLK_LOOKUP("core_mmss_clk", mmss_misc_ahb_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"),
diff --git a/arch/arm/mach-msm/cpr-regulator.c b/arch/arm/mach-msm/cpr-regulator.c
index 039d2d7..d952f82 100644
--- a/arch/arm/mach-msm/cpr-regulator.c
+++ b/arch/arm/mach-msm/cpr-regulator.c
@@ -169,6 +169,8 @@
/* Process voltage variables */
u32 pvs_bin;
u32 speed_bin;
+ u32 pvs_version;
+
/* APC voltage regulator */
struct regulator *vdd_apc;
@@ -1291,14 +1293,48 @@
return rc;
}
-static int cpr_get_of_corner_mappings(struct cpr_regulator *cpr_vreg,
+static void cpr_parse_pvs_version_fuse(struct cpr_regulator *cpr_vreg,
+ struct device_node *of_node)
+{
+ int rc;
+ u64 fuse_bits;
+ u32 fuse_sel[4];
+
+ rc = of_property_read_u32_array(of_node,
+ "qcom,pvs-version-fuse-sel", fuse_sel, 4);
+ if (!rc) {
+ fuse_bits = cpr_read_efuse_row(cpr_vreg,
+ fuse_sel[0], fuse_sel[3]);
+ cpr_vreg->pvs_version = (fuse_bits >> fuse_sel[1]) &
+ ((1 << fuse_sel[2]) - 1);
+ pr_info("[row: %d]: 0x%llx, pvs_version = %d\n",
+ fuse_sel[0], fuse_bits, cpr_vreg->pvs_version);
+ } else {
+ cpr_vreg->pvs_version = UINT_MAX;
+ }
+}
+
+/*
+ * cpr_get_corner_quot_adjustment() -- get the quot_adjust for each corner.
+ *
+ * Get the corner to fuse corner (SVS/NORMAL/TURBO) mappings and corner to
+ * APC clock frequency mappings from device tree.
+ * Calculate the quotient adjustment scaling factor for those corners mapping
+ * to the TURBO fuse corner.
+ * Calculate the quotient adjustment for each corner which map to the TURBO
+ * fuse corner.
+ */
+static int cpr_get_corner_quot_adjustment(struct cpr_regulator *cpr_vreg,
struct device *dev)
{
int rc = 0;
- int i, size, stripe_size;
+ int i, size;
struct property *prop;
- u32 *tmp;
bool corners_mapped;
+ u32 *tmp, *freq_mappings = NULL;
+ u32 scaling, max_factor;
+ u32 corner, turbo_corner = 0, normal_corner = 0, svs_corner = 0;
+ u32 freq_turbo, freq_normal, freq_corner;
prop = of_find_property(dev->of_node, "qcom,cpr-corner-map", NULL);
@@ -1313,81 +1349,182 @@
cpr_vreg->corner_map = devm_kzalloc(dev, sizeof(int) * (size + 1),
GFP_KERNEL);
if (!cpr_vreg->corner_map) {
- pr_err("Can't allocate cpr_vreg->corner_map memory\n");
+ pr_err("Can't allocate memory for cpr_vreg->corner_map\n");
return -ENOMEM;
}
cpr_vreg->num_corners = size;
+ cpr_vreg->quot_adjust = devm_kzalloc(dev,
+ sizeof(u32) * (cpr_vreg->num_corners + 1),
+ GFP_KERNEL);
+ if (!cpr_vreg->quot_adjust) {
+ pr_err("Can't allocate memory for cpr_vreg->quot_adjust\n");
+ return -ENOMEM;
+ }
+
if (!corners_mapped) {
for (i = CPR_FUSE_CORNER_SVS; i < CPR_FUSE_CORNER_MAX; i++)
cpr_vreg->corner_map[i] = i;
+ return 0;
} else {
rc = of_property_read_u32_array(dev->of_node,
"qcom,cpr-corner-map", &cpr_vreg->corner_map[1], size);
if (rc) {
- pr_err("qcom,cpr-corner-map missing, rc = %d", rc);
+ pr_err("qcom,cpr-corner-map missing, rc = %d\n", rc);
return rc;
}
}
- cpr_vreg->quot_adjust = devm_kzalloc(dev,
- sizeof(int) * (cpr_vreg->num_corners + 1),
- GFP_KERNEL);
- if (!cpr_vreg->quot_adjust) {
- pr_err("Can't allocate cpr_vreg->quot_adjust memory\n");
+ prop = of_find_property(dev->of_node,
+ "qcom,cpr-speed-bin-max-corners", NULL);
+ if (!prop) {
+ cpr_debug("qcom,cpr-speed-bin-max-corner missing\n");
+ return 0;
+ }
+
+ size = prop->length / sizeof(u32);
+ tmp = kzalloc(size * sizeof(u32), GFP_KERNEL);
+ if (!tmp) {
+ pr_err("memory alloc failed\n");
return -ENOMEM;
}
-
- prop = of_find_property(dev->of_node, "qcom,cpr-quot-adjust-table",
- NULL);
-
- if (prop) {
- if (!corners_mapped) {
- pr_err("qcom,cpr-corner-map missing\n");
- return -EINVAL;
- }
-
- size = prop->length / sizeof(u32);
- tmp = kzalloc(sizeof(u32) * size, GFP_KERNEL);
- if (!tmp)
- return -ENOMEM;
-
- rc = of_property_read_u32_array(dev->of_node,
- "qcom,cpr-quot-adjust-table", tmp, size);
- if (rc) {
- pr_err("qcom,cpr-quot-adjust-table missing, rc = %d",
- rc);
- kfree(tmp);
- return rc;
- }
-
- stripe_size = sizeof(struct quot_adjust_info) / sizeof(int);
-
- if ((size % stripe_size) != 0) {
- pr_err("qcom,cpr-quot-adjust-table data is not correct");
- kfree(tmp);
- return -EINVAL;
- }
-
- for (i = 0; i < size; i += stripe_size) {
- if (tmp[i] == cpr_vreg->speed_bin) {
- if (tmp[i + 1] >= 1 &&
- tmp[i + 1] <=
- cpr_vreg->num_corners) {
- cpr_vreg->quot_adjust[tmp[i + 1]] =
- tmp[i + 2];
- } else {
- pr_err("qcom,cpr-quot-adjust-table data is not correct");
- kfree(tmp);
- return -EINVAL;
- }
- }
- }
-
+ rc = of_property_read_u32_array(dev->of_node,
+ "qcom,cpr-speed-bin-max-corners", tmp, size);
+ if (rc < 0) {
kfree(tmp);
+ pr_err("get cpr-speed-bin-max-corners failed, rc = %d\n", rc);
+ return rc;
}
+ cpr_parse_pvs_version_fuse(cpr_vreg, dev->of_node);
+
+ /*
+ * According to speed_bin && pvs_version, get the maximum
+ * corner corresponding to SVS/NORMAL/TURBO fuse corner.
+ */
+ for (i = 0; i < size; i += 5) {
+ if (tmp[i] == cpr_vreg->speed_bin &&
+ tmp[i + 1] == cpr_vreg->pvs_version) {
+ svs_corner = tmp[i + 2];
+ normal_corner = tmp[i + 3];
+ turbo_corner = tmp[i + 4];
+ break;
+ }
+ }
+ kfree(tmp);
+ /*
+ * Return success if the virtual corner values read from
+ * qcom,cpr-speed-bin-max-corners property are incorrect,
+ * which make sure the driver could continue run without
+ * error.
+ */
+ if (turbo_corner <= normal_corner ||
+ turbo_corner > cpr_vreg->num_corners) {
+ cpr_debug("turbo:%d should be larger than normal:%d\n",
+ turbo_corner, normal_corner);
+ return 0;
+ }
+
+ prop = of_find_property(dev->of_node,
+ "qcom,cpr-corner-frequency-map", NULL);
+ if (!prop) {
+ cpr_debug("qcom,cpr-corner-frequency-map missing\n");
+ return 0;
+ }
+
+ size = prop->length / sizeof(u32);
+ tmp = kzalloc(sizeof(u32) * size, GFP_KERNEL);
+ if (!tmp) {
+ pr_err("memory alloc failed\n");
+ return -ENOMEM;
+ }
+ rc = of_property_read_u32_array(dev->of_node,
+ "qcom,cpr-corner-frequency-map", tmp, size);
+ if (rc < 0) {
+ pr_err("get cpr-corner-frequency-map failed, rc = %d\n", rc);
+ kfree(tmp);
+ return rc;
+ }
+ freq_mappings = kzalloc(sizeof(u32) * (cpr_vreg->num_corners + 1),
+ GFP_KERNEL);
+ if (!freq_mappings) {
+ pr_err("memory alloc for freq_mappings failed!\n");
+ kfree(tmp);
+ return -ENOMEM;
+ }
+ for (i = 0; i < size; i += 2) {
+ corner = tmp[i];
+ if ((corner < 1) || (corner > cpr_vreg->num_corners)) {
+ pr_err("corner should be in 1~%d range: %d\n",
+ cpr_vreg->num_corners, corner);
+ continue;
+ }
+ freq_mappings[corner] = tmp[i + 1];
+ cpr_debug("Frequency at virtual corner %d is %d Hz.\n",
+ corner, freq_mappings[corner]);
+ }
+ kfree(tmp);
+
+ rc = of_property_read_u32(dev->of_node,
+ "qcom,cpr-quot-adjust-scaling-factor-max",
+ &max_factor);
+ if (rc < 0) {
+ cpr_debug("get cpr-quot-adjust-scaling-factor-max failed\n");
+ kfree(freq_mappings);
+ return 0;
+ }
+
+ /*
+ * Get the quot adjust scaling factor, according to:
+ * scaling =
+ * min(1000 * (QUOT(fused @turbo) - QUOT(fused @normal)) /
+ * (freq_turbo - freq_normal), max_factor)
+ *
+ * @QUOT(fused @turbo): quotient read from fuse for TURBO fuse corner;
+ * @QUOT(fused @normal): quotient read from fuse for NORMAL fuse corner;
+ * @freq_turbo: MHz, max frequency running at TURBO fuse corner;
+ * @freq_normal: MHz, max frequency running at NORMAL fuse corner.
+ */
+
+ freq_turbo = freq_mappings[turbo_corner];
+ freq_normal = freq_mappings[normal_corner];
+ if (freq_normal == 0 || freq_turbo <= freq_normal) {
+ pr_err("freq_turbo: %d should larger than freq_normal: %d\n",
+ freq_turbo, freq_normal);
+ kfree(freq_mappings);
+ return -EINVAL;
+ }
+ freq_turbo /= 1000000; /* MHz */
+ freq_normal /= 1000000;
+ scaling = 1000 *
+ (cpr_vreg->cpr_fuse_target_quot[CPR_FUSE_CORNER_TURBO] -
+ cpr_vreg->cpr_fuse_target_quot[CPR_FUSE_CORNER_NORMAL]) /
+ (freq_turbo - freq_normal);
+ scaling = min(scaling, max_factor);
+ pr_info("quotient adjustment scaling factor: %d.%03d\n",
+ scaling / 1000, scaling % 1000);
+
+ /*
+ * Walk through the corners mapped to the TURBO fuse corner and
+ * calculate the quotient adjustment for each one using the following
+ * formula:
+ * quot_adjust = (freq_turbo - freq_corner) * scaling / 1000
+ *
+ * @freq_turbo: MHz, max frequency running at TURBO fuse corner;
+ * @freq_corner: MHz, frequency running at a corner.
+ */
+ for (i = turbo_corner; i > normal_corner; i--) {
+ freq_corner = freq_mappings[i] / 1000000; /* MHz */
+ if (freq_corner > 0) {
+ cpr_vreg->quot_adjust[i] =
+ scaling * (freq_turbo - freq_corner) / 1000;
+ }
+ pr_info("adjusted quotient[%d] = %d\n", i,
+ (cpr_vreg->cpr_fuse_target_quot[cpr_vreg->corner_map[i]]
+ - cpr_vreg->quot_adjust[i]));
+ }
+ kfree(freq_mappings);
return 0;
}
@@ -1531,7 +1668,7 @@
}
}
- rc = cpr_get_of_corner_mappings(cpr_vreg, &pdev->dev);
+ rc = cpr_get_corner_quot_adjustment(cpr_vreg, &pdev->dev);
if (rc)
return rc;
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 89e3b51..c7f8b74 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -27,6 +27,12 @@
#include <linux/msm_ssbi.h>
#include <mach/msm_bus.h>
+#define WLAN_RF_REG_ADDR_START_OFFSET 0x3
+#define WLAN_RF_REG_DATA_START_OFFSET 0xf
+#define WLAN_RF_READ_REG_CMD 0x3
+#define WLAN_RF_WRITE_REG_CMD 0x2
+#define WLAN_RF_READ_CMD_MASK 0x3fff
+
struct msm_camera_io_ext {
uint32_t mdcphy;
uint32_t mdcsz;
@@ -677,4 +683,5 @@
extern phys_addr_t msm_shared_ram_phys; /* defined in arch/arm/mach-msm/io.c */
+u32 wcnss_rf_read_reg(u32 rf_reg_addr);
#endif
diff --git a/arch/arm/mach-msm/include/mach/kgsl.h b/arch/arm/mach-msm/include/mach/kgsl.h
index f398652..edfe6b4 100644
--- a/arch/arm/mach-msm/include/mach/kgsl.h
+++ b/arch/arm/mach-msm/include/mach/kgsl.h
@@ -91,6 +91,7 @@
struct coresight_device *csdev;
struct coresight_platform_data *coresight_pdata;
unsigned int chipid;
+ unsigned int pm_qos_latency;
};
#endif
diff --git a/arch/arm/mach-msm/include/mach/ocmem_priv.h b/arch/arm/mach-msm/include/mach/ocmem_priv.h
index 32d58d4..00aedb6 100644
--- a/arch/arm/mach-msm/include/mach/ocmem_priv.h
+++ b/arch/arm/mach-msm/include/mach/ocmem_priv.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -226,7 +226,6 @@
int process_dump(int, struct ocmem_handle *, unsigned long);
int ocmem_rdm_transfer(int, struct ocmem_map_list *,
unsigned long, int);
-int ocmem_clear(unsigned long, unsigned long);
unsigned long process_quota(int);
int ocmem_memory_off(int, unsigned long, unsigned long);
int ocmem_memory_on(int, unsigned long, unsigned long);
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
index 7128017..9857162 100644
--- a/arch/arm/mach-msm/lpm_levels.c
+++ b/arch/arm/mach-msm/lpm_levels.c
@@ -526,7 +526,7 @@
if (latency_us < pwr->latency_us)
continue;
- if (next_event_us)
+ if (next_event_us) {
if (next_event_us < pwr->latency_us)
continue;
@@ -535,6 +535,7 @@
next_wakeup_us = next_event_us
- pwr->latency_us;
}
+ }
if (next_wakeup_us <= pwr->time_overhead_us)
continue;
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
index 626c5e8..0ffc194 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
@@ -364,7 +364,7 @@
{
struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
void *sel_cdata;
- long rounded_rate;
+ long rounded_rate, cur_rate;
sel_cdata = fabric->cdata[ctx];
@@ -379,16 +379,20 @@
}
/* Enable clocks before accessing QoS registers */
- if (fabric->info.nodeclk[DUAL_CTX].clk)
+ if (fabric->info.nodeclk[DUAL_CTX].clk) {
if (fabric->info.nodeclk[DUAL_CTX].rate == 0) {
- rounded_rate = clk_round_rate(fabric->
- info.nodeclk[DUAL_CTX].clk, 1);
+ cur_rate = clk_get_rate(
+ fabric->info.nodeclk[DUAL_CTX].clk);
+ rounded_rate = clk_round_rate(
+ fabric->info.nodeclk[DUAL_CTX].clk,
+ cur_rate ? cur_rate : 1);
if (clk_set_rate(fabric->info.nodeclk[DUAL_CTX].clk,
rounded_rate))
MSM_BUS_ERR("Error: clk: en: Node: %d rate: %ld",
fabric->fabdev.id, rounded_rate);
clk_prepare_enable(fabric->info.nodeclk[DUAL_CTX].clk);
+ }
}
if (info->iface_clk.clk)
@@ -514,22 +518,26 @@
struct msm_bus_inode_info *info, uint64_t req_clk, uint64_t req_bw)
{
struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
- long rounded_rate;
+ long rounded_rate, cur_rate;
if (fabdev->hw_algo.config_master == NULL)
return;
/* Enable clocks before accessing QoS registers */
- if (fabric->info.nodeclk[DUAL_CTX].clk)
+ if (fabric->info.nodeclk[DUAL_CTX].clk) {
if (fabric->info.nodeclk[DUAL_CTX].rate == 0) {
- rounded_rate = clk_round_rate(fabric->
- info.nodeclk[DUAL_CTX].clk, 1);
+ cur_rate = clk_get_rate(
+ fabric->info.nodeclk[DUAL_CTX].clk);
+ rounded_rate = clk_round_rate(
+ fabric->info.nodeclk[DUAL_CTX].clk,
+ cur_rate ? cur_rate : 1);
if (clk_set_rate(fabric->info.nodeclk[DUAL_CTX].clk,
rounded_rate))
MSM_BUS_ERR("Error: clk: en: Node: %d rate: %ld",
fabric->fabdev.id, rounded_rate);
clk_prepare_enable(fabric->info.nodeclk[DUAL_CTX].clk);
+ }
}
if (info->iface_clk.clk)
diff --git a/arch/arm/mach-msm/ocmem_core.c b/arch/arm/mach-msm/ocmem_core.c
index c186a5e..f753391 100644
--- a/arch/arm/mach-msm/ocmem_core.c
+++ b/arch/arm/mach-msm/ocmem_core.c
@@ -51,6 +51,7 @@
static struct ocmem_hw_region *region_ctrl;
static struct mutex region_ctrl_lock;
static void *ocmem_base;
+static void *ocmem_vbase;
#define OCMEM_V1_MACROS 8
#define OCMEM_V1_MACRO_SZ (SZ_64K)
@@ -562,6 +563,13 @@
ocmem_write(0x0, ocmem_base + OC_GFX_MPU_END);
}
+int ocmem_clear(unsigned long start, unsigned long size)
+{
+ memset((ocmem_vbase + start), 0x4D4D434F, size);
+ mb();
+ return 0;
+}
+
static int do_lock(enum ocmem_client id, unsigned long offset,
unsigned long len, enum region_mode mode)
{
@@ -1144,6 +1152,7 @@
pdata = platform_get_drvdata(pdev);
ocmem_base = pdata->reg_base;
+ ocmem_vbase = pdata->vbase;
rc = ocmem_enable_core_clock();
diff --git a/arch/arm/mach-msm/ocmem_rdm.c b/arch/arm/mach-msm/ocmem_rdm.c
index 4ff7212..9eac050 100644
--- a/arch/arm/mach-msm/ocmem_rdm.c
+++ b/arch/arm/mach-msm/ocmem_rdm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -149,38 +149,6 @@
return IRQ_HANDLED;
}
-#ifdef CONFIG_MSM_OCMEM_NONSECURE
-int ocmem_clear(unsigned long start, unsigned long size)
-{
- INIT_COMPLETION(dm_clear_event);
- /* Clear DM Mask */
- ocmem_write(DM_MASK_RESET, dm_base + DM_INTR_MASK);
- /* Clear DM Interrupts */
- ocmem_write(DM_INTR_RESET, dm_base + DM_INTR_CLR);
- /* DM CLR offset */
- ocmem_write(start, dm_base + DM_CLR_OFFSET);
- /* DM CLR size */
- ocmem_write(size, dm_base + DM_CLR_SIZE);
- /* Wipe out memory as "OCMM" */
- ocmem_write(0x4D4D434F, dm_base + DM_CLR_PATTERN);
- /* The offset, size and pattern for clearing must be set
- * before triggering the clearing engine
- */
- mb();
- /* Trigger Data Clear */
- ocmem_write(DM_CLR_ENABLE, dm_base + DM_CLR_TRIGGER);
-
- wait_for_completion(&dm_clear_event);
-
- return 0;
-}
-#else
-int ocmem_clear(unsigned long start, unsigned long size)
-{
- return 0;
-}
-#endif
-
/* Lock during transfers */
int ocmem_rdm_transfer(int id, struct ocmem_map_list *clist,
unsigned long start, int direction)
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 9f50547..ab03712 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -678,6 +678,8 @@
char *buf)
{
uint32_t hw_subtype;
+ WARN_ONCE(1, "Deprecated, use platform_subtype_id instead\n");
+
if (!socinfo) {
pr_err("%s: No socinfo found!\n", __func__);
return 0;
@@ -707,6 +709,18 @@
}
static ssize_t
+socinfo_show_platform_subtype_id(struct sys_device *dev,
+ struct sysdev_attribute *attr,
+ char *buf)
+{
+ uint32_t hw_subtype;
+
+ hw_subtype = socinfo_get_platform_subtype();
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ hw_subtype);
+}
+
+static ssize_t
socinfo_show_pmic_model(struct sys_device *dev,
struct sysdev_attribute *attr,
char *buf)
@@ -829,6 +843,17 @@
}
static ssize_t
+msm_get_platform_subtype_id(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ uint32_t hw_subtype;
+ hw_subtype = socinfo_get_platform_subtype();
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ hw_subtype);
+}
+
+static ssize_t
msm_get_pmic_model(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -974,6 +999,8 @@
static struct sysdev_attribute socinfo_v6_files[] = {
_SYSDEV_ATTR(platform_subtype, 0444,
socinfo_show_platform_subtype, NULL),
+ _SYSDEV_ATTR(platform_subtype_id, 0444,
+ socinfo_show_platform_subtype_id, NULL),
};
static struct sysdev_attribute socinfo_v7_files[] = {
@@ -1059,6 +1086,13 @@
__ATTR(platform_subtype, S_IRUGO,
msm_get_platform_subtype, NULL);
+/* Platform Subtype String is being deprecated. Use Platform
+ * Subtype ID instead.
+ */
+static struct device_attribute msm_soc_attr_platform_subtype_id =
+ __ATTR(platform_subtype_id, S_IRUGO,
+ msm_get_platform_subtype_id, NULL);
+
static struct device_attribute msm_soc_attr_pmic_model =
__ATTR(pmic_model, S_IRUGO,
msm_get_pmic_model, NULL);
@@ -1152,6 +1186,8 @@
case 6:
device_create_file(msm_soc_device,
&msm_soc_attr_platform_subtype);
+ device_create_file(msm_soc_device,
+ &msm_soc_attr_platform_subtype_id);
case 5:
device_create_file(msm_soc_device,
&msm_soc_attr_accessory_chip);
diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c
index f35ba53..0c7c9e0 100644
--- a/drivers/coresight/coresight-tmc.c
+++ b/drivers/coresight/coresight-tmc.c
@@ -177,6 +177,7 @@
bool byte_cntr_read_active;
wait_queue_head_t wq;
char *byte_cntr_node;
+ uint32_t mem_size;
};
static void tmc_wait_for_flush(struct tmc_drvdata *drvdata)
@@ -1310,6 +1311,32 @@
static DEVICE_ATTR(byte_cntr_value, S_IRUGO | S_IWUSR,
tmc_etr_show_byte_cntr_value, tmc_etr_store_byte_cntr_value);
+static ssize_t tmc_etr_show_mem_size(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long val = drvdata->mem_size;
+
+ return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t tmc_etr_store_mem_size(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long val;
+
+ if (sscanf(buf, "%lx", &val) != 1)
+ return -EINVAL;
+
+ drvdata->mem_size = val;
+ return size;
+}
+static DEVICE_ATTR(mem_size, S_IRUGO | S_IWUSR,
+ tmc_etr_show_mem_size, tmc_etr_store_mem_size);
+
static struct attribute *tmc_attrs[] = {
&dev_attr_trigger_cntr.attr,
NULL,
@@ -1322,6 +1349,7 @@
static struct attribute *tmc_etr_attrs[] = {
&dev_attr_out_mode.attr,
&dev_attr_byte_cntr_value.attr,
+ &dev_attr_mem_size.attr,
NULL,
};
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index 3aebaf0..48dc6ec 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -39,6 +39,7 @@
#include <crypto/authenc.h>
#include <crypto/scatterwalk.h>
#include <crypto/internal/hash.h>
+#include <crypto/internal/aead.h>
#include <mach/scm.h>
#include <linux/platform_data/qcom_crypto_device.h>
@@ -66,6 +67,8 @@
u32 aead_sha1_3des_dec;
u32 aead_ccm_aes_enc;
u32 aead_ccm_aes_dec;
+ u32 aead_rfc4309_ccm_aes_enc;
+ u32 aead_rfc4309_ccm_aes_dec;
u32 aead_op_success;
u32 aead_op_fail;
u32 aead_bad_msg;
@@ -231,6 +234,8 @@
/* max of AES_BLOCK_SIZE, DES3_EDE_BLOCK_SIZE */
#define QCRYPTO_MAX_IV_LENGTH 16
+#define QCRYPTO_CCM4309_NONCE_LEN 3
+
struct qcrypto_cipher_ctx {
u8 auth_key[QCRYPTO_MAX_KEY_SIZE];
u8 iv[QCRYPTO_MAX_IV_LENGTH];
@@ -244,10 +249,12 @@
struct crypto_priv *cp;
unsigned int flags;
struct crypto_engine *pengine; /* fixed engine assigned */
+ u8 ccm4309_nonce[QCRYPTO_CCM4309_NONCE_LEN];
};
struct qcrypto_cipher_req_ctx {
u8 *iv;
+ u8 rfc4309_iv[QCRYPTO_MAX_IV_LENGTH];
unsigned int ivsize;
int aead;
struct scatterlist asg; /* Formatted associated data sg */
@@ -736,7 +743,12 @@
len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" AEAD CCM-AES decryption : %d\n",
pstat->aead_ccm_aes_dec);
-
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ " AEAD RFC4309-CCM-AES encryption : %d\n",
+ pstat->aead_rfc4309_ccm_aes_enc);
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ " AEAD RFC4309-CCM-AES decryption : %d\n",
+ pstat->aead_rfc4309_ccm_aes_dec);
len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" AEAD operation success : %d\n",
pstat->aead_op_success);
@@ -1272,6 +1284,12 @@
uint32_t bytes = 0;
uint32_t num_sg = 0;
+ if (alen == 0) {
+ qreq->assoc = NULL;
+ qreq->assoclen = 0;
+ return 0;
+ }
+
qreq->assoc = kzalloc((alen + 0x64), GFP_ATOMIC);
if (!qreq->assoc) {
pr_err("qcrypto Memory allocation of adata FAIL, error %ld\n",
@@ -1455,7 +1473,10 @@
qreq.authkey = cipher_ctx->auth_key;
qreq.authklen = cipher_ctx->auth_key_len;
qreq.authsize = crypto_aead_authsize(aead);
- qreq.ivsize = crypto_aead_ivsize(aead);
+ if (qreq.mode == QCE_MODE_CCM)
+ qreq.ivsize = AES_BLOCK_SIZE;
+ else
+ qreq.ivsize = crypto_aead_ivsize(aead);
qreq.flags = cipher_ctx->flags;
if (qreq.mode == QCE_MODE_CCM) {
@@ -1502,8 +1523,9 @@
kzfree(qreq.assoc);
return -ENOMEM;
}
-
- memcpy((char *)rctx->data, qreq.assoc, qreq.assoclen);
+ if (qreq.assoclen)
+ memcpy((char *)rctx->data, qreq.assoc,
+ qreq.assoclen);
num_sg = qcrypto_count_sg(req->src, req->cryptlen);
bytes = qcrypto_sg_copy_to_buffer(req->src, num_sg,
@@ -1845,6 +1867,29 @@
return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
}
+static int _qcrypto_aead_rfc4309_enc_aes_ccm(struct aead_request *req)
+{
+ struct qcrypto_cipher_req_ctx *rctx;
+ struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+ struct crypto_priv *cp = ctx->cp;
+ struct crypto_stat *pstat;
+
+ pstat = &_qcrypto_stat;
+
+ rctx = aead_request_ctx(req);
+ rctx->aead = 1;
+ rctx->alg = CIPHER_ALG_AES;
+ rctx->dir = QCE_ENCRYPT;
+ rctx->mode = QCE_MODE_CCM;
+ memset(rctx->rfc4309_iv, 0, sizeof(rctx->rfc4309_iv));
+ rctx->rfc4309_iv[0] = 3; /* L -1 */
+ memcpy(&rctx->rfc4309_iv[1], ctx->ccm4309_nonce, 3);
+ memcpy(&rctx->rfc4309_iv[4], req->iv, 8);
+ rctx->iv = rctx->rfc4309_iv;
+ pstat->aead_rfc4309_ccm_aes_enc++;
+ return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
+}
+
static int _qcrypto_enc_des_ecb(struct ablkcipher_request *req)
{
struct qcrypto_cipher_req_ctx *rctx;
@@ -2136,6 +2181,27 @@
return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
}
+static int _qcrypto_aead_rfc4309_dec_aes_ccm(struct aead_request *req)
+{
+ struct qcrypto_cipher_req_ctx *rctx;
+ struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+ struct crypto_priv *cp = ctx->cp;
+ struct crypto_stat *pstat;
+
+ pstat = &_qcrypto_stat;
+ rctx = aead_request_ctx(req);
+ rctx->aead = 1;
+ rctx->alg = CIPHER_ALG_AES;
+ rctx->dir = QCE_DECRYPT;
+ rctx->mode = QCE_MODE_CCM;
+ memset(rctx->rfc4309_iv, 0, sizeof(rctx->rfc4309_iv));
+ rctx->rfc4309_iv[0] = 3; /* L -1 */
+ memcpy(&rctx->rfc4309_iv[1], ctx->ccm4309_nonce, 3);
+ memcpy(&rctx->rfc4309_iv[4], req->iv, 8);
+ rctx->iv = rctx->rfc4309_iv;
+ pstat->aead_rfc4309_ccm_aes_dec++;
+ return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
+}
static int _qcrypto_aead_setauthsize(struct crypto_aead *authenc,
unsigned int authsize)
{
@@ -2166,6 +2232,24 @@
return 0;
}
+static int _qcrypto_aead_rfc4309_ccm_setauthsize(struct crypto_aead *authenc,
+ unsigned int authsize)
+{
+ struct qcrypto_cipher_ctx *ctx = crypto_aead_ctx(authenc);
+
+ switch (authsize) {
+ case 8:
+ case 12:
+ case 16:
+ break;
+ default:
+ return -EINVAL;
+ }
+ ctx->authsize = authsize;
+ return 0;
+}
+
+
static int _qcrypto_aead_setkey(struct crypto_aead *tfm, const u8 *key,
unsigned int keylen)
{
@@ -2231,6 +2315,21 @@
return 0;
}
+static int _qcrypto_aead_rfc4309_ccm_setkey(struct crypto_aead *aead,
+ const u8 *key, unsigned int key_len)
+{
+ struct crypto_tfm *tfm = crypto_aead_tfm(aead);
+ struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
+ int ret;
+
+ if (key_len < QCRYPTO_CCM4309_NONCE_LEN)
+ return -EINVAL;
+ key_len -= QCRYPTO_CCM4309_NONCE_LEN;
+ memcpy(ctx->ccm4309_nonce, key + key_len, QCRYPTO_CCM4309_NONCE_LEN);
+ ret = _qcrypto_aead_ccm_setkey(aead, key, key_len);
+ return ret;
+};
+
static int _qcrypto_aead_encrypt_aes_cbc(struct aead_request *req)
{
struct qcrypto_cipher_req_ctx *rctx;
@@ -3762,7 +3861,7 @@
.cra_u = {
.aead = {
.ivsize = AES_BLOCK_SIZE,
- .maxauthsize = SHA1_DIGEST_SIZE,
+ .maxauthsize = AES_BLOCK_SIZE,
.setkey = _qcrypto_aead_ccm_setkey,
.setauthsize = _qcrypto_aead_ccm_setauthsize,
.encrypt = _qcrypto_aead_encrypt_aes_ccm,
@@ -3772,6 +3871,31 @@
}
};
+static struct crypto_alg _qcrypto_aead_rfc4309_ccm_algo = {
+ .cra_name = "rfc4309(ccm(aes))",
+ .cra_driver_name = "qcrypto-rfc4309-aes-ccm",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = 1,
+ .cra_ctxsize = sizeof(struct qcrypto_cipher_ctx),
+ .cra_alignmask = 0,
+ .cra_type = &crypto_nivaead_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = _qcrypto_cra_aead_init,
+ .cra_exit = _qcrypto_cra_aead_exit,
+ .cra_u = {
+ .aead = {
+ .ivsize = 8,
+ .maxauthsize = 16,
+ .setkey = _qcrypto_aead_rfc4309_ccm_setkey,
+ .setauthsize = _qcrypto_aead_rfc4309_ccm_setauthsize,
+ .encrypt = _qcrypto_aead_rfc4309_enc_aes_ccm,
+ .decrypt = _qcrypto_aead_rfc4309_dec_aes_ccm,
+ .geniv = "seqiv",
+ }
+ }
+};
+
static int _qcrypto_probe(struct platform_device *pdev)
{
@@ -4078,6 +4202,36 @@
dev_info(&pdev->dev, "%s\n",
q_alg->cipher_alg.cra_driver_name);
}
+
+ q_alg = _qcrypto_cipher_alg_alloc(cp,
+ &_qcrypto_aead_rfc4309_ccm_algo);
+ if (IS_ERR(q_alg)) {
+ rc = PTR_ERR(q_alg);
+ goto err;
+ }
+
+ if (cp->ce_support.use_sw_aes_ccm_algo) {
+ rc = _qcrypto_prefix_alg_cra_name(
+ q_alg->cipher_alg.cra_name,
+ strlen(q_alg->cipher_alg.cra_name));
+ if (rc) {
+ dev_err(&pdev->dev,
+ "The algorithm name %s is too long.\n",
+ q_alg->cipher_alg.cra_name);
+ kfree(q_alg);
+ goto err;
+ }
+ }
+ rc = crypto_register_alg(&q_alg->cipher_alg);
+ if (rc) {
+ dev_err(&pdev->dev, "%s alg registration failed\n",
+ q_alg->cipher_alg.cra_driver_name);
+ kfree(q_alg);
+ } else {
+ list_add_tail(&q_alg->entry, &cp->alg_list);
+ dev_info(&pdev->dev, "%s\n",
+ q_alg->cipher_alg.cra_driver_name);
+ }
}
mutex_unlock(&cp->engine_lock);
diff --git a/drivers/gpio/qpnp-pin.c b/drivers/gpio/qpnp-pin.c
index 8d934df..6176df9 100644
--- a/drivers/gpio/qpnp-pin.c
+++ b/drivers/gpio/qpnp-pin.c
@@ -182,6 +182,7 @@
struct device_node *int_ctrl;
struct list_head chip_list;
struct dentry *dfs_dir;
+ bool chip_registered;
};
static LIST_HEAD(qpnp_pin_chips);
@@ -912,7 +913,7 @@
static int qpnp_pin_free_chip(struct qpnp_pin_chip *q_chip)
{
struct spmi_device *spmi = q_chip->spmi;
- int rc, i;
+ int i, rc = 0;
if (q_chip->chip_gpios)
for (i = 0; i < spmi->num_dev_node; i++)
@@ -921,10 +922,12 @@
mutex_lock(&qpnp_pin_chips_lock);
list_del(&q_chip->chip_list);
mutex_unlock(&qpnp_pin_chips_lock);
- rc = gpiochip_remove(&q_chip->gpio_chip);
- if (rc)
- dev_err(&q_chip->spmi->dev, "%s: unable to remove gpio\n",
- __func__);
+ if (q_chip->chip_registered) {
+ rc = gpiochip_remove(&q_chip->gpio_chip);
+ if (rc)
+ dev_err(&q_chip->spmi->dev, "%s: unable to remove gpio\n",
+ __func__);
+ }
kfree(q_chip->chip_gpios);
kfree(q_chip->pmic_pins);
kfree(q_chip);
@@ -1342,6 +1345,7 @@
goto err_probe;
}
+ q_chip->chip_registered = true;
/* now configure gpio config defaults if they exist */
for (i = 0; i < spmi->num_dev_node; i++) {
q_spec = qpnp_chip_gpio_get_spec(q_chip, i);
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 7717829..7a92fe6 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -1625,17 +1625,19 @@
goto err;
}
- ret = of_property_read_u32_array(child, "reg", reg_val, 2);
- if (ret) {
- KGSL_CORE_ERR("Unable to read KGSL IOMMU 'reg'\n");
+ if (!strcmp("gfx3d_user", ctxs[ctx_index].iommu_ctx_name)) {
+ ctxs[ctx_index].ctx_id = 0;
+ } else if (!strcmp("gfx3d_priv",
+ ctxs[ctx_index].iommu_ctx_name)) {
+ ctxs[ctx_index].ctx_id = 1;
+ } else if (!strcmp("gfx3d_spare",
+ ctxs[ctx_index].iommu_ctx_name)) {
+ ctxs[ctx_index].ctx_id = 2;
+ } else {
+ KGSL_CORE_ERR("dt: IOMMU context %s is invalid\n",
+ ctxs[ctx_index].iommu_ctx_name);
goto err;
}
- if (msm_soc_version_supports_iommu_v0())
- ctxs[ctx_index].ctx_id = (reg_val[0] -
- data->physstart) >> KGSL_IOMMU_CTX_SHIFT;
- else
- ctxs[ctx_index].ctx_id = ((reg_val[0] -
- data->physstart) >> KGSL_IOMMU_CTX_SHIFT) - 8;
ctx_index++;
}
@@ -1690,6 +1692,12 @@
if (ret)
goto err;
+ /* get pm-qos-latency from target, set it to default if not found */
+ if (adreno_of_read_property(pdev->dev.of_node, "qcom,pm-qos-latency",
+ &pdata->pm_qos_latency))
+ pdata->pm_qos_latency = 501;
+
+
if (adreno_of_read_property(pdev->dev.of_node, "qcom,idle-timeout",
&pdata->idle_timeout))
pdata->idle_timeout = HZ/12;
diff --git a/drivers/gpu/msm/kgsl_events.c b/drivers/gpu/msm/kgsl_events.c
index e21fd88..ccd13d5 100644
--- a/drivers/gpu/msm/kgsl_events.c
+++ b/drivers/gpu/msm/kgsl_events.c
@@ -210,7 +210,7 @@
kgsl_event_func func, void *priv, void *owner)
{
struct kgsl_event *event;
- unsigned int queued, cur_ts;
+ unsigned int queued = 0, cur_ts;
struct kgsl_context *context = NULL;
BUG_ON(!mutex_is_locked(&device->mutex));
@@ -224,11 +224,21 @@
return -EINVAL;
}
- queued = kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_QUEUED);
+ /*
+ * If the caller is creating their own timestamps, let them schedule
+ * events in the future. Otherwise only allow timestamps that have been
+ * queued.
+ */
+ if (context == NULL ||
+ ((context->flags & KGSL_CONTEXT_USER_GENERATED_TS) == 0)) {
- if (timestamp_cmp(ts, queued) > 0) {
- kgsl_context_put(context);
- return -EINVAL;
+ queued = kgsl_readtimestamp(device, context,
+ KGSL_TIMESTAMP_QUEUED);
+
+ if (timestamp_cmp(ts, queued) > 0) {
+ kgsl_context_put(context);
+ return -EINVAL;
+ }
}
cur_ts = kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_RETIRED);
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 6b04aad..d64d0d3 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -85,16 +85,8 @@
return status;
}
-static void kgsl_destroy_pagetable(struct kref *kref)
+static void _kgsl_destroy_pagetable(struct kgsl_pagetable *pagetable)
{
- struct kgsl_pagetable *pagetable = container_of(kref,
- struct kgsl_pagetable, refcount);
- unsigned long flags;
-
- spin_lock_irqsave(&kgsl_driver.ptlock, flags);
- list_del(&pagetable->list);
- spin_unlock_irqrestore(&kgsl_driver.ptlock, flags);
-
pagetable_remove_sysfs_objects(pagetable);
kgsl_cleanup_pt(pagetable);
@@ -109,6 +101,29 @@
kfree(pagetable);
}
+static void kgsl_destroy_pagetable(struct kref *kref)
+{
+ struct kgsl_pagetable *pagetable = container_of(kref,
+ struct kgsl_pagetable, refcount);
+ unsigned long flags;
+
+ spin_lock_irqsave(&kgsl_driver.ptlock, flags);
+ list_del(&pagetable->list);
+ spin_unlock_irqrestore(&kgsl_driver.ptlock, flags);
+
+ _kgsl_destroy_pagetable(pagetable);
+}
+
+static void kgsl_destroy_pagetable_locked(struct kref *kref)
+{
+ struct kgsl_pagetable *pagetable = container_of(kref,
+ struct kgsl_pagetable, refcount);
+
+ list_del(&pagetable->list);
+
+ _kgsl_destroy_pagetable(pagetable);
+}
+
static inline void kgsl_put_pagetable(struct kgsl_pagetable *pagetable)
{
if (pagetable)
@@ -128,7 +143,7 @@
ret = pt;
break;
}
- kref_put(&pt->refcount, kgsl_destroy_pagetable);
+ kref_put(&pt->refcount, kgsl_destroy_pagetable_locked);
}
}
@@ -139,12 +154,12 @@
static struct kgsl_pagetable *
_get_pt_from_kobj(struct kobject *kobj)
{
- unsigned long ptname;
+ unsigned int ptname;
if (!kobj)
return NULL;
- if (sscanf(kobj->name, "%ld", &ptname) != 1)
+ if (kstrtou32(kobj->name, 0, &ptname))
return NULL;
return kgsl_get_pagetable(ptname);
@@ -328,10 +343,11 @@
if (kref_get_unless_zero(&pt->refcount)) {
if (mmu->mmu_ops->mmu_pt_equal(mmu, pt, pt_base)) {
ptid = (int) pt->name;
- kref_put(&pt->refcount, kgsl_destroy_pagetable);
+ kref_put(&pt->refcount,
+ kgsl_destroy_pagetable_locked);
break;
}
- kref_put(&pt->refcount, kgsl_destroy_pagetable);
+ kref_put(&pt->refcount, kgsl_destroy_pagetable_locked);
}
}
spin_unlock(&kgsl_driver.ptlock);
@@ -356,18 +372,18 @@
if ((addr & ~(PAGE_SIZE-1)) == pt->fault_addr) {
ret = 1;
kref_put(&pt->refcount,
- kgsl_destroy_pagetable);
+ kgsl_destroy_pagetable_locked);
break;
} else {
pt->fault_addr =
(addr & ~(PAGE_SIZE-1));
ret = 0;
kref_put(&pt->refcount,
- kgsl_destroy_pagetable);
+ kgsl_destroy_pagetable_locked);
break;
}
}
- kref_put(&pt->refcount, kgsl_destroy_pagetable);
+ kref_put(&pt->refcount, kgsl_destroy_pagetable_locked);
}
}
spin_unlock(&kgsl_driver.ptlock);
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 9353b2e..656d7e2 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -1124,8 +1124,7 @@
pwr->pwrlevels[pwr->active_pwrlevel].
bus_freq);
- /* Set the CPU latency to 501usec to allow low latency PC modes */
- pwr->pm_qos_latency = 501;
+ pwr->pm_qos_latency = pdata->pm_qos_latency;
pm_runtime_enable(device->parentdev);
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index d3adf84..c8ea471 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-2014, 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
@@ -73,12 +73,12 @@
_get_priv_from_kobj(struct kobject *kobj)
{
struct kgsl_process_private *private;
- unsigned long name;
+ unsigned int name;
if (!kobj)
return NULL;
- if (sscanf(kobj->name, "%ld", &name) != 1)
+ if (kstrtou32(kobj->name, 0, &name))
return NULL;
list_for_each_entry(private, &kgsl_driver.process_list, list) {
@@ -255,13 +255,13 @@
const char *buf, size_t count)
{
int ret;
- unsigned int thresh;
- ret = sscanf(buf, "%d", &thresh);
- if (ret != 1)
- return count;
+ unsigned int thresh = 0;
+
+ ret = kgsl_sysfs_store(buf, &thresh);
+ if (ret)
+ return ret;
kgsl_driver.full_cache_threshold = thresh;
-
return count;
}
diff --git a/drivers/gud/Makefile b/drivers/gud/Makefile
index ef0e083..c415ad8 100644
--- a/drivers/gud/Makefile
+++ b/drivers/gud/Makefile
@@ -3,34 +3,35 @@
#
GUD_ROOT_FOLDER := drivers/gud
# add our modules to kernel.
-obj-$(CONFIG_MOBICORE_API) += mckernelapi.o
-obj-$(CONFIG_MOBICORE_SUPPORT) += mcdrvmodule.o
+obj-$(CONFIG_MOBICORE_API) += mcKernelApi.o
+obj-$(CONFIG_MOBICORE_SUPPORT) += mcDrvModule.o
-mcdrvmodule-objs := mobicore_driver/logging.o \
- mobicore_driver/ops.o \
- mobicore_driver/mem.o \
- mobicore_driver/api.o \
- mobicore_driver/main.o \
- mobicore_driver/pm.o
+mcDrvModule-objs := MobiCoreDriver/logging.o \
+ MobiCoreDriver/ops.o \
+ MobiCoreDriver/mem.o \
+ MobiCoreDriver/api.o \
+ MobiCoreDriver/pm.o \
+ MobiCoreDriver/main.o
-mckernelapi-objs := mobicore_kernelapi/main.o \
- mobicore_kernelapi/clientlib.o \
- mobicore_kernelapi/device.o \
- mobicore_kernelapi/session.o \
- mobicore_kernelapi/connection.o
+mcKernelApi-objs := MobiCoreKernelApi/main.o \
+ MobiCoreKernelApi/clientlib.o \
+ MobiCoreKernelApi/device.o \
+ MobiCoreKernelApi/session.o \
+ MobiCoreKernelApi/connection.o
# Release mode by default
-ccflags-y := -DNDEBUG -include $(PWD)/$(GUD_ROOT_FOLDER)/mobicore_driver/build_tag.h
+ccflags-y := -DNDEBUG -I$(GUD_ROOT_FOLDER)
ccflags-y += -Wno-declaration-after-statement
ccflags-$(CONFIG_MOBICORE_DEBUG) += -DDEBUG
ccflags-$(CONFIG_MOBICORE_VERBOSE) += -DDEBUG_VERBOSE
# Choose one platform from the folder
-MOBICORE_PLATFORM := $(shell (ls -1 $(PWD)/$(GUD_ROOT_FOLDER)/mobicore_driver/platforms | tail -1) )
+MOBICORE_PLATFORM := $(shell (ls -1 $(PWD)/$(GUD_ROOT_FOLDER)/MobiCoreDriver/platforms | tail -1) )
# Use the available platform folder
-ccflags-y += -I$(GUD_ROOT_FOLDER)/mobicore_driver/platforms/$(MOBICORE_PLATFORM)
-
-
-ccflags-y += -I$(GUD_ROOT_FOLDER)/mobicore_driver/public
-ccflags-y += -I$(GUD_ROOT_FOLDER)/mobicore_kernelapi/include
+ccflags-y += -I$(GUD_ROOT_FOLDER)/MobiCoreDriver/platforms/$(MOBICORE_PLATFORM)
+# MobiCore Driver includes
+ccflags-y += -I$(GUD_ROOT_FOLDER)/MobiCoreDriver/public
+# MobiCore KernelApi required incldes
+ccflags-y += -I$(GUD_ROOT_FOLDER)/MobiCoreKernelApi/include
+ccflags-y += -I$(GUD_ROOT_FOLDER)/MobiCoreKernelApi/public
diff --git a/drivers/gud/MobiCoreDriver/Makefile b/drivers/gud/MobiCoreDriver/Makefile
new file mode 100644
index 0000000..c17f35e
--- /dev/null
+++ b/drivers/gud/MobiCoreDriver/Makefile
@@ -0,0 +1,26 @@
+#
+# this makefile is called from the kernel make system. Thus we basically
+# add things to "obj-m" here.
+
+ifeq ($(MODE),release)
+ ccflags-y = -O2 -DNDEBUG
+else
+ ccflags-y = -DDEBUG
+endif # DEBUG/RELEASE
+
+# CFLAGS from the build script
+ifdef MOBICORE_CFLAGS
+ ccflags-y += $(MOBICORE_CFLAGS)
+endif
+#EXTRA_CFLAGS+=-DDEBUG_VERBOSE
+
+ccflags-y += -I$(M) -Wall -D__$(PLATFORM)__
+# add our module to kernel.
+obj-m += mcDrvModule.o
+
+mcDrvModule-objs :=logging.o ops.o mem.o api.o pm.o main.o
+
+clean:
+ rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions \
+ Module.markers Module.symvers modules.order
+
diff --git a/drivers/gud/mobicore_driver/api.c b/drivers/gud/MobiCoreDriver/api.c
similarity index 80%
rename from drivers/gud/mobicore_driver/api.c
rename to drivers/gud/MobiCoreDriver/api.c
index b47383a0..e7fa8e2 100644
--- a/drivers/gud/mobicore_driver/api.c
+++ b/drivers/gud/MobiCoreDriver/api.c
@@ -14,23 +14,12 @@
#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)
+ uint32_t len, uint32_t *handle)
{
- return mc_register_wsm_l2(instance, (uint32_t)addr, len,
- handle, phys);
+ phys_addr_t phys;
+ return mc_register_wsm_mmu(instance, addr, len,
+ handle, &phys);
}
EXPORT_SYMBOL(mobicore_map_vmem);
@@ -44,7 +33,7 @@
*/
int mobicore_unmap_vmem(struct mc_instance *instance, uint32_t handle)
{
- return mc_unregister_wsm_l2(instance, handle);
+ return mc_unregister_wsm_mmu(instance, handle);
}
EXPORT_SYMBOL(mobicore_unmap_vmem);
@@ -70,13 +59,11 @@
* @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 long requested_size, uint32_t *handle, void **virt_kernel_addr)
{
struct mc_buffer *buffer = NULL;
@@ -85,7 +72,6 @@
return -EFAULT;
*handle = buffer->handle;
- *phys_addr = buffer->phys;
*virt_kernel_addr = buffer->addr;
return 0;
}
@@ -117,3 +103,14 @@
}
EXPORT_SYMBOL(mobicore_release);
+/*
+ * Test if mobicore can sleep
+ *
+ * @return true if mobicore can sleep, false if it can't sleep
+ */
+bool mobicore_sleep_ready(void)
+{
+ return mc_sleep_ready();
+}
+EXPORT_SYMBOL(mobicore_sleep_ready);
+
diff --git a/drivers/gud/mobicore_driver/arm.h b/drivers/gud/MobiCoreDriver/arm.h
similarity index 100%
rename from drivers/gud/mobicore_driver/arm.h
rename to drivers/gud/MobiCoreDriver/arm.h
diff --git a/drivers/gud/MobiCoreDriver/build.sh b/drivers/gud/MobiCoreDriver/build.sh
new file mode 100644
index 0000000..db8410c
--- /dev/null
+++ b/drivers/gud/MobiCoreDriver/build.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+# source the setup script
+if [ -z $COMP_PATH_ROOT ]; then
+ echo "The build environment is not set!"
+ echo "Trying to source setupDrivers.sh automatically!"
+ source ../setupDrivers.sh || exit 1
+fi
+
+ROOT_PATH=$(dirname $(readlink -f $0))
+# These folders need to be relative to the kernel dir or absolute!
+PLATFORM=EXYNOS_5410_STD
+CODE_INCLUDE=$(readlink -f $ROOT_PATH/Locals/Code)
+PLATFORM_INCLUDE="$CODE_INCLUDE/platforms/$PLATFORM"
+MOBICORE_DAEMON=$COMP_PATH_MobiCoreDriverLib/Public
+
+MOBICORE_CFLAGS="-I$MOBICORE_DRIVER/Public -I$MOBICORE_DAEMON -I$COMP_PATH_MobiCore/inc/Mci -I$COMP_PATH_MobiCore/inc -I${PLATFORM_INCLUDE}"
+
+# Clean first
+make -C $CODE_INCLUDE clean
+
+make -C $LINUX_PATH \
+ MODE=$MODE \
+ ARCH=arm \
+ CROSS_COMPILE=$CROSS_COMPILE \
+ M=$CODE_INCLUDE \
+ "MOBICORE_CFLAGS=$MOBICORE_CFLAGS" \
+ modules
diff --git a/drivers/gud/mobicore_driver/debug.h b/drivers/gud/MobiCoreDriver/debug.h
similarity index 89%
rename from drivers/gud/mobicore_driver/debug.h
rename to drivers/gud/MobiCoreDriver/debug.h
index 1f9a632..d29efef 100644
--- a/drivers/gud/mobicore_driver/debug.h
+++ b/drivers/gud/MobiCoreDriver/debug.h
@@ -15,7 +15,7 @@
extern struct device *mcd;
#define MCDRV_DBG_ERROR(dev, txt, ...) \
- dev_err(dev, "MobiCore %s() ### ERROR: " txt, \
+ dev_err(dev, "MobiCore %s() ### ERROR: " txt "\n", \
__func__, \
##__VA_ARGS__)
@@ -32,12 +32,12 @@
#endif
#define MCDRV_DBG(dev, txt, ...) \
- dev_info(dev, "MobiCore %s(): " txt, \
+ dev_info(dev, "MobiCore %s(): " txt "\n", \
__func__, \
##__VA_ARGS__)
#define MCDRV_DBG_WARN(dev, txt, ...) \
- dev_warn(dev, "MobiCore %s() WARNING: " txt, \
+ dev_warn(dev, "MobiCore %s() WARNING: " txt "\n", \
__func__, \
##__VA_ARGS__)
diff --git a/drivers/gud/mobicore_driver/fastcall.h b/drivers/gud/MobiCoreDriver/fastcall.h
similarity index 70%
rename from drivers/gud/mobicore_driver/fastcall.h
rename to drivers/gud/MobiCoreDriver/fastcall.h
index 1c90520..33538df 100644
--- a/drivers/gud/mobicore_driver/fastcall.h
+++ b/drivers/gud/MobiCoreDriver/fastcall.h
@@ -36,9 +36,10 @@
*/
#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 */
+#ifdef TBASE_CORE_SWITCHER
+#define MC_FC_SWITCH_CORE 0x84000005
+#endif
/*
@@ -96,6 +97,23 @@
} as_out;
};
+#ifdef TBASE_CORE_SWITCHER
+/* fast call switch Core parameters */
+union mc_fc_swich_core {
+ union fc_generic as_generic;
+ struct {
+ uint32_t cmd;
+ uint32_t core_id;
+ uint32_t rfu[2];
+ } as_in;
+ struct {
+ uint32_t resp;
+ uint32_t ret;
+ uint32_t state;
+ uint32_t ext_info;
+ } as_out;
+};
+#endif
/*
* _smc() - fast call to MobiCore
*
@@ -104,23 +122,22 @@
static inline long _smc(void *data)
{
int ret = 0;
- union fc_generic fc_generic;
if (data == NULL)
return -EPERM;
#ifdef MC_SMC_FASTCALL
{
- ret = smc_fastcall(data, sizeof(fc_generic));
+ ret = smc_fastcall(data, sizeof(union fc_generic));
}
#else
- memcpy(&fc_generic, data, sizeof(union fc_generic));
{
- /* 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];
+ union fc_generic *fc_generic = data;
+ /* SMC 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
@@ -131,13 +148,23 @@
"smc 0\n"
: "+r"(reg0), "+r"(reg1), "+r"(reg2), "+r"(reg3)
);
+#ifdef __ARM_VE_A9X4_QEMU__
+ /* Qemu does not return to the address following the SMC
+ instruction so we have to insert several nop instructions to
+ workaround this Qemu bug. */
+ __asm__ volatile (
+ "nop\n"
+ "nop\n"
+ "nop\n"
+ "nop"
+ );
+#endif
/* 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));
+ 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
return ret;
diff --git a/drivers/gud/mobicore_driver/logging.c b/drivers/gud/MobiCoreDriver/logging.c
similarity index 95%
rename from drivers/gud/mobicore_driver/logging.c
rename to drivers/gud/MobiCoreDriver/logging.c
index 1f599f9..507c4ed 100644
--- a/drivers/gud/mobicore_driver/logging.c
+++ b/drivers/gud/MobiCoreDriver/logging.c
@@ -251,7 +251,7 @@
*/
long mobicore_log_setup(void)
{
- unsigned long phys_log_buf;
+ phys_addr_t phys_log_buf;
union fc_generic fc_log;
struct sched_param param = { .sched_priority = 1 };
@@ -300,11 +300,12 @@
memset(&fc_log, 0, sizeof(fc_log));
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;
+ fc_log.as_in.param[0] = (uint32_t)phys_log_buf;
+ fc_log.as_in.param[1] = (uint32_t)(((uint64_t)phys_log_buf) >> 32);
+ fc_log.as_in.param[2] = log_size;
- MCDRV_DBG(mcd, "fc_log virt=%p phys=%p ",
- log_buf, (void *)phys_log_buf);
+ MCDRV_DBG(mcd, "fc_log virt=%p phys=0x%llX",
+ log_buf, (u64)phys_log_buf);
mc_fastcall(&fc_log);
MCDRV_DBG(mcd, "fc_log out ret=0x%08x", fc_log.as_out.ret);
@@ -319,7 +320,7 @@
set_task_state(log_thread, TASK_INTERRUPTIBLE);
- MCDRV_DBG(mcd, "fc_log Logger version %u\n", log_buf->version);
+ MCDRV_DBG(mcd, "fc_log Logger version %u", log_buf->version);
return 0;
err_stop_kthread:
diff --git a/drivers/gud/mobicore_driver/logging.h b/drivers/gud/MobiCoreDriver/logging.h
similarity index 100%
rename from drivers/gud/mobicore_driver/logging.h
rename to drivers/gud/MobiCoreDriver/logging.h
diff --git a/drivers/gud/mobicore_driver/main.c b/drivers/gud/MobiCoreDriver/main.c
similarity index 81%
rename from drivers/gud/mobicore_driver/main.c
rename to drivers/gud/MobiCoreDriver/main.c
index 0451452..ed2928a 100644
--- a/drivers/gud/mobicore_driver/main.c
+++ b/drivers/gud/MobiCoreDriver/main.c
@@ -112,12 +112,12 @@
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);
+ MCDRV_DBG_VERBOSE(mcd, "free page at 0x%p", page);
+ clear_bit(PG_reserved, &page->flags);
page++;
}
- MCDRV_DBG_VERBOSE(mcd, "freeing addr:%p, order:%x\n", addr, order);
+ MCDRV_DBG_VERBOSE(mcd, "freeing addr:%p, order:%x", addr, order);
free_pages((unsigned long)addr, order);
}
@@ -131,8 +131,9 @@
return -EINVAL;
MCDRV_DBG_VERBOSE(mcd,
- "handle=%u phys_addr=0x%p, virt_addr=0x%p len=%u\n",
- buffer->handle, buffer->phys, buffer->addr, buffer->len);
+ "handle=%u phys_addr=0x%llx, virt_addr=0x%p len=%u",
+ buffer->handle, (u64)buffer->phys,
+ buffer->addr, buffer->len);
if (!atomic_dec_and_test(&buffer->usage)) {
MCDRV_DBG_VERBOSE(mcd, "Could not free %u", buffer->handle);
@@ -147,7 +148,7 @@
}
static uint32_t mc_find_cont_wsm_addr(struct mc_instance *instance, void *uaddr,
- uint32_t *addr, uint32_t len)
+ void **addr, uint32_t len)
{
int ret = 0;
struct mc_buffer *buffer;
@@ -162,7 +163,7 @@
/* search for the given handle in the buffers list */
list_for_each_entry(buffer, &ctx.cont_bufs, list) {
if (buffer->uaddr == uaddr && buffer->len == len) {
- *addr = (uint32_t)buffer->addr;
+ *addr = buffer->addr;
goto found;
}
}
@@ -186,7 +187,7 @@
struct task_struct *peer = NULL;
bool ret = false;
- MCDRV_DBG(mcd, "Finding wsm for fd = %d\n", fd);
+ MCDRV_DBG_VERBOSE(mcd, "Finding wsm for fd = %d", fd);
if (!instance)
return false;
@@ -197,7 +198,7 @@
s = __get_socket(fp);
if (s) {
peer = get_pid_task(s->sk_peer_pid, PIDTYPE_PID);
- MCDRV_DBG(mcd, "Found pid for fd %d\n", peer->pid);
+ MCDRV_DBG_VERBOSE(mcd, "Found pid for fd %d", peer->pid);
}
if (peer) {
task_lock(peer);
@@ -209,11 +210,10 @@
if (!fp)
continue;
if (fp->private_data == instance) {
- MCDRV_DBG(mcd, "Found owner!");
+ MCDRV_DBG_VERBOSE(mcd, "Found owner!");
ret = true;
goto out;
}
-
}
} else {
MCDRV_DBG(mcd, "Owner not found!");
@@ -230,7 +230,7 @@
#endif
}
static uint32_t mc_find_cont_wsm(struct mc_instance *instance, uint32_t handle,
- int32_t fd, uint32_t *phys, uint32_t *len)
+ int32_t fd, phys_addr_t *phys, uint32_t *len)
{
int ret = 0;
struct mc_buffer *buffer;
@@ -239,7 +239,7 @@
return -EFAULT;
if (WARN_ON(!is_daemon(instance))) {
- MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n");
+ MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon");
return -EPERM;
}
@@ -251,7 +251,7 @@
list_for_each_entry(buffer, &ctx.cont_bufs, list) {
if (buffer->handle == handle) {
if (mc_check_owner_fd(buffer->instance, fd)) {
- *phys = (uint32_t)buffer->phys;
+ *phys = buffer->phys;
*len = buffer->len;
goto found;
} else {
@@ -326,7 +326,7 @@
/* Something is not right if we end up here, better not
* clean the buffer so we just leak memory instead of
* creating security issues */
- MCDRV_DBG_ERROR(mcd, "Memory can't be unmapped\n");
+ MCDRV_DBG_ERROR(mcd, "Memory can't be unmapped");
return -EINVAL;
}
}
@@ -370,7 +370,7 @@
{
struct mc_buffer *cbuffer = NULL;
void *addr = 0;
- void *phys = 0;
+ phys_addr_t phys = 0;
unsigned int order;
unsigned long allocated_size;
int ret = 0;
@@ -379,13 +379,13 @@
return -EFAULT;
if (len == 0) {
- MCDRV_DBG_WARN(mcd, "cannot allocate size 0\n");
+ MCDRV_DBG_WARN(mcd, "cannot allocate size 0");
return -ENOMEM;
}
order = get_order(len);
if (order > MAX_ORDER) {
- MCDRV_DBG_WARN(mcd, "Buffer size too large\n");
+ MCDRV_DBG_WARN(mcd, "Buffer size too large");
return -ENOMEM;
}
allocated_size = (1 << order) * PAGE_SIZE;
@@ -398,23 +398,23 @@
if (cbuffer == NULL) {
MCDRV_DBG_WARN(mcd,
- "MMAP_WSM request: could not allocate buffer\n");
+ "MMAP_WSM request: could not allocate buffer");
ret = -ENOMEM;
goto unlock_instance;
}
mutex_lock(&ctx.bufs_lock);
- MCDRV_DBG_VERBOSE(mcd, "size %ld -> order %d --> %ld (2^n pages)\n",
+ MCDRV_DBG_VERBOSE(mcd, "size %ld -> order %d --> %ld (2^n pages)",
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");
+ MCDRV_DBG_WARN(mcd, "get_free_pages failed");
ret = -ENOMEM;
goto err;
}
- phys = (void *)virt_to_phys(addr);
+ phys = virt_to_phys(addr);
cbuffer->handle = get_unique_id();
cbuffer->phys = phys;
cbuffer->addr = addr;
@@ -429,9 +429,11 @@
list_add(&cbuffer->list, &ctx.cont_bufs);
MCDRV_DBG_VERBOSE(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);
+ "allocated phys=0x%llx - 0x%llx, size=%ld, kvirt=0x%p"
+ ", h=%d",
+ (u64)phys,
+ (u64)(phys+allocated_size),
+ allocated_size, addr, cbuffer->handle);
*buffer = cbuffer;
goto unlock;
@@ -457,7 +459,7 @@
return -EFAULT;
if (WARN_ON(!is_daemon(instance))) {
- MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n");
+ MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon");
return -EPERM;
}
@@ -476,7 +478,7 @@
return ret;
}
-void *get_mci_base_phys(unsigned int len)
+static phys_addr_t get_mci_base_phys(unsigned int len)
{
if (ctx.mci_base.phys) {
return ctx.mci_base.phys;
@@ -487,45 +489,45 @@
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");
+ MCDRV_DBG_WARN(mcd, "get_free_pages failed");
memset(&ctx.mci_base, 0, sizeof(ctx.mci_base));
- return NULL;
+ return 0;
}
- ctx.mci_base.phys = (void *)virt_to_phys(ctx.mci_base.addr);
+ ctx.mci_base.phys = 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
+ * Create a MMU 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 mc_register_wsm_mmu(struct mc_instance *instance,
+ void *buffer, uint32_t len,
+ uint32_t *handle, phys_addr_t *phys)
{
int ret = 0;
- struct mc_l2_table *table = NULL;
+ struct mc_mmu_table *table = NULL;
struct task_struct *task = current;
- uint32_t kbuff = 0x0;
+ void *kbuff = NULL;
if (WARN(!instance, "No instance data available"))
return -EFAULT;
if (len == 0) {
- MCDRV_DBG_ERROR(mcd, "len=0 is not supported!\n");
+ MCDRV_DBG_ERROR(mcd, "len=0 is not supported!");
return -EINVAL;
}
- MCDRV_DBG_VERBOSE(mcd, "buffer: %p, len=%08x\n", (void *)buffer, len);
+ MCDRV_DBG_VERBOSE(mcd, "buffer: %p, len=%08x", buffer, len);
- if (!mc_find_cont_wsm_addr(instance, (void *)buffer, &kbuff, len))
- table = mc_alloc_l2_table(instance, NULL, (void *)kbuff, len);
+ if (!mc_find_cont_wsm_addr(instance, buffer, &kbuff, len))
+ table = mc_alloc_mmu_table(instance, NULL, kbuff, len);
else
- table = mc_alloc_l2_table(instance, task, (void *)buffer, len);
+ table = mc_alloc_mmu_table(instance, task, buffer, len);
if (IS_ERR(table)) {
- MCDRV_DBG_ERROR(mcd, "new_used_l2_table() failed\n");
+ MCDRV_DBG_ERROR(mcd, "mc_alloc_mmu_table() failed");
return -EINVAL;
}
@@ -533,19 +535,19 @@
*handle = table->handle;
/* WARNING: daemon shouldn't know this either, but live with it */
if (is_daemon(instance))
- *phys = (uint32_t)table->phys;
+ *phys = table->phys;
else
*phys = 0;
- MCDRV_DBG_VERBOSE(mcd, "handle: %d, phys=%p\n",
- *handle, (void *)*phys);
+ MCDRV_DBG_VERBOSE(mcd, "handle: %d, phys=0x%llX",
+ *handle, (u64)(*phys));
- MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret);
+ MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X", ret, ret);
return ret;
}
-int mc_unregister_wsm_l2(struct mc_instance *instance, uint32_t handle)
+int mc_unregister_wsm_mmu(struct mc_instance *instance, uint32_t handle)
{
int ret = 0;
@@ -553,11 +555,11 @@
return -EFAULT;
/* free table (if no further locks exist) */
- mc_free_l2_table(instance, handle);
+ mc_free_mmu_table(instance, handle);
return ret;
}
-/* Lock the object from handle, it could be a WSM l2 table or a cont buffer! */
+/* Lock the object from handle, it could be a WSM MMU table or a cont buffer! */
static int mc_lock_handle(struct mc_instance *instance, uint32_t handle)
{
int ret = 0;
@@ -566,14 +568,14 @@
return -EFAULT;
if (WARN_ON(!is_daemon(instance))) {
- MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n");
+ MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon");
return -EPERM;
}
mutex_lock(&instance->lock);
- ret = mc_lock_l2_table(instance, handle);
+ ret = mc_lock_mmu_table(instance, handle);
- /* Handle was not a l2 table but a cont buffer */
+ /* Handle was not a MMU table but a cont buffer */
if (ret == -EINVAL) {
/* Call the non locking variant! */
ret = __lock_buffer(instance, handle);
@@ -592,14 +594,14 @@
return -EFAULT;
if (WARN_ON(!is_daemon(instance))) {
- MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n");
+ MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon");
return -EPERM;
}
mutex_lock(&instance->lock);
- ret = mc_free_l2_table(instance, handle);
+ ret = mc_free_mmu_table(instance, handle);
- /* Not a l2 table, then it must be a buffer */
+ /* Not a MMU table, then it must be a buffer */
if (ret == -EINVAL) {
/* Call the non locking variant! */
ret = __free_buffer(instance, handle, true);
@@ -609,35 +611,31 @@
return ret;
}
-static uint32_t mc_find_wsm_l2(struct mc_instance *instance,
+static phys_addr_t mc_find_wsm_mmu(struct mc_instance *instance,
uint32_t handle, int32_t fd)
{
- uint32_t ret = 0;
-
if (WARN(!instance, "No instance data available"))
return 0;
if (WARN_ON(!is_daemon(instance))) {
- MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n");
+ MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon");
return 0;
}
- ret = mc_find_l2_table(handle, fd);
-
- return ret;
+ return mc_find_mmu_table(handle, fd);
}
-static int mc_clean_wsm_l2(struct mc_instance *instance)
+static int mc_clean_wsm_mmu(struct mc_instance *instance)
{
if (WARN(!instance, "No instance data available"))
return -EFAULT;
if (WARN_ON(!is_daemon(instance))) {
- MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n");
+ MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon");
return -EPERM;
}
- mc_clean_l2_tables();
+ mc_clean_mmu_tables();
return 0;
}
@@ -646,19 +644,20 @@
{
struct mc_instance *instance = get_instance(file);
unsigned long len = vmarea->vm_end - vmarea->vm_start;
- void *paddr = (void *)(vmarea->vm_pgoff << PAGE_SHIFT);
+ phys_addr_t paddr = (vmarea->vm_pgoff << PAGE_SHIFT);
unsigned int pfn;
struct mc_buffer *buffer = 0;
int ret = 0;
- MCDRV_DBG_VERBOSE(mcd, "enter (vma start=0x%p, size=%ld, mci=%p)\n",
- (void *)vmarea->vm_start, len, ctx.mci_base.phys);
+ MCDRV_DBG_VERBOSE(mcd, "enter (vma start=0x%p, size=%ld, mci=0x%llX)",
+ (void *)vmarea->vm_start, len,
+ (u64)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");
+ MCDRV_DBG_ERROR(mcd, "cannot allocate size 0");
return -ENOMEM;
}
if (paddr) {
@@ -722,7 +721,7 @@
vmarea->vm_page_prot);
}
- MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret);
+ MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X", ret, ret);
return ret;
}
@@ -768,21 +767,24 @@
case MC_IO_REG_WSM:{
struct mc_ioctl_reg_wsm reg;
+ phys_addr_t phys;
if (copy_from_user(®, uarg, sizeof(reg)))
return -EFAULT;
- ret = mc_register_wsm_l2(instance, reg.buffer,
- reg.len, ®.handle, ®.table_phys);
+ ret = mc_register_wsm_mmu(instance, (void *)reg.buffer,
+ reg.len, ®.handle, &phys);
+ reg.table_phys = phys;
+
if (!ret) {
if (copy_to_user(uarg, ®, sizeof(reg))) {
ret = -EFAULT;
- mc_unregister_wsm_l2(instance, reg.handle);
+ mc_unregister_wsm_mmu(instance, reg.handle);
}
}
break;
}
case MC_IO_UNREG_WSM:
- ret = mc_unregister_wsm_l2(instance, (uint32_t)arg);
+ ret = mc_unregister_wsm_mmu(instance, (uint32_t)arg);
break;
case MC_IO_VERSION:
@@ -803,7 +805,7 @@
return -EFAULT;
map.handle = buffer->handle;
- map.phys_addr = (unsigned long)buffer->phys;
+ map.phys_addr = buffer->phys;
map.reused = 0;
if (copy_to_user(uarg, &map, sizeof(map)))
ret = -EFAULT;
@@ -812,7 +814,7 @@
break;
}
default:
- MCDRV_DBG_ERROR(mcd, "unsupported cmd=%d\n", cmd);
+ MCDRV_DBG_ERROR(mcd, "unsupported cmd=0x%x", cmd);
ret = -ENOIOCTLCMD;
break;
@@ -836,7 +838,7 @@
return -EFAULT;
if (WARN_ON(!is_daemon(instance))) {
- MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n");
+ MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon");
return -EPERM;
}
@@ -856,8 +858,8 @@
return -EFAULT;
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);
+ ret = mc_init(ctx.mci_base.phys, init.nq_length,
+ init.mcp_offset, init.mcp_length);
break;
}
case MC_IO_INFO: {
@@ -890,14 +892,14 @@
ret = mc_unlock_handle(instance, (uint32_t)arg);
break;
case MC_IO_CLEAN_WSM:
- ret = mc_clean_wsm_l2(instance);
+ ret = mc_clean_wsm_mmu(instance);
break;
case MC_IO_RESOLVE_WSM: {
- uint32_t phys;
+ phys_addr_t phys;
struct mc_ioctl_resolv_wsm wsm;
if (copy_from_user(&wsm, uarg, sizeof(wsm)))
return -EFAULT;
- phys = mc_find_wsm_l2(instance, wsm.handle, wsm.fd);
+ phys = mc_find_wsm_mmu(instance, wsm.handle, wsm.fd);
if (!phys)
return -EINVAL;
@@ -909,7 +911,8 @@
}
case MC_IO_RESOLVE_CONT_WSM: {
struct mc_ioctl_resolv_cont_wsm cont_wsm;
- uint32_t phys = 0, len = 0;
+ phys_addr_t phys = 0;
+ uint32_t len = 0;
if (copy_from_user(&cont_wsm, uarg, sizeof(cont_wsm)))
return -EFAULT;
ret = mc_find_cont_wsm(instance, cont_wsm.handle, cont_wsm.fd,
@@ -928,7 +931,7 @@
return -EFAULT;
map.reused = (ctx.mci_base.phys != 0);
- map.phys_addr = (unsigned long)get_mci_base_phys(map.len);
+ map.phys_addr = get_mci_base_phys(map.len);
if (!map.phys_addr) {
MCDRV_DBG_ERROR(mcd, "Failed to setup MCI buffer!");
return -EFAULT;
@@ -939,10 +942,6 @@
ret = 0;
break;
}
- case MC_IO_MAP_PWSM:{
- break;
- }
-
case MC_IO_LOG_SETUP: {
#ifdef MC_MEM_TRACES
ret = mobicore_log_setup();
@@ -985,27 +984,27 @@
return -EFAULT;
/* avoid debug output on non-error, because this is call quite often */
- MCDRV_DBG_VERBOSE(mcd, "enter\n");
+ MCDRV_DBG_VERBOSE(mcd, "enter");
/* 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");
+ MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon");
return -EPERM;
}
if (buffer_len < sizeof(unsigned int)) {
- MCDRV_DBG_ERROR(mcd, "invalid length\n");
+ MCDRV_DBG_ERROR(mcd, "invalid length");
return -EINVAL;
}
for (;;) {
if (wait_for_completion_interruptible(&ctx.isr_comp)) {
- MCDRV_DBG_VERBOSE(mcd, "read interrupted\n");
+ MCDRV_DBG_VERBOSE(mcd, "read interrupted");
return -ERESTARTSYS;
}
ssiq_counter = atomic_read(&ctx.isr_counter);
- MCDRV_DBG_VERBOSE(mcd, "ssiq_counter=%i, ctx.counter=%i\n",
+ MCDRV_DBG_VERBOSE(mcd, "ssiq_counter=%i, ctx.counter=%i",
ssiq_counter, ctx.evt_counter);
if (ssiq_counter != ctx.evt_counter) {
@@ -1017,12 +1016,12 @@
/* end loop if non-blocking */
if (file->f_flags & O_NONBLOCK) {
- MCDRV_DBG_ERROR(mcd, "non-blocking read\n");
+ MCDRV_DBG_ERROR(mcd, "non-blocking read");
return -EAGAIN;
}
if (signal_pending(current)) {
- MCDRV_DBG_VERBOSE(mcd, "received signal.\n");
+ MCDRV_DBG_VERBOSE(mcd, "received signal.");
return -ERESTARTSYS;
}
}
@@ -1031,7 +1030,7 @@
ret = copy_to_user(buffer, &ctx.evt_counter, sizeof(unsigned int));
if (ret != 0) {
- MCDRV_DBG_ERROR(mcd, "copy_to_user failed\n");
+ MCDRV_DBG_ERROR(mcd, "copy_to_user failed");
return -EFAULT;
}
@@ -1061,6 +1060,43 @@
return instance;
}
+#if defined(TBASE_CORE_SWITCHER) && defined(DEBUG)
+static ssize_t mc_fd_write(struct file *file, const char __user *buffer,
+ size_t buffer_len, loff_t *x)
+{
+ uint32_t cpu_new;
+ /* we only consider one digit */
+ char buf[2];
+ struct mc_instance *instance = get_instance(file);
+
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
+
+ /* Invalid data, nothing to do */
+ if (buffer_len < 1)
+ return -EINVAL;
+
+ /* Invalid data, nothing to do */
+ if (copy_from_user(buf, buffer, min(sizeof(buf), buffer_len)))
+ return -EFAULT;
+
+ if (buf[0] == 'n') {
+ mc_nsiq();
+ /* If it's a digit then switch cores */
+ } else if ((buf[0] >= '0') && (buf[0] <= '9')) {
+ cpu_new = buf[0] - '0';
+ if (cpu_new <= 8) {
+ MCDRV_DBG_VERBOSE(mcd, "Set Active Cpu: %d\n", cpu_new);
+ mc_switch_core(cpu_new);
+ }
+ } else {
+ return -EINVAL;
+ }
+
+ return buffer_len;
+}
+#endif
+
/*
* Release a mobicore instance object and all objects related to it
* @instance: instance
@@ -1074,7 +1110,7 @@
return -EFAULT;
mutex_lock(&instance->lock);
- mc_clear_l2_tables(instance);
+ mc_clear_mmu_tables(instance);
mutex_lock(&ctx.bufs_lock);
/* release all mapped data */
@@ -1112,7 +1148,7 @@
{
struct mc_instance *instance;
- MCDRV_DBG_VERBOSE(mcd, "enter\n");
+ MCDRV_DBG_VERBOSE(mcd, "enter");
instance = mc_alloc_instance();
if (instance == NULL)
@@ -1141,7 +1177,7 @@
return -ENOMEM;
instance = get_instance(file);
- MCDRV_DBG(mcd, "accept this as MobiCore Daemon\n");
+ MCDRV_DBG(mcd, "accept this as MobiCore Daemon");
ctx.daemon_inst = instance;
ctx.daemon = current;
@@ -1172,7 +1208,7 @@
/* check if daemon closes us. */
if (is_daemon(instance)) {
- MCDRV_DBG_WARN(mcd, "WARNING: MobiCore Daemon died\n");
+ MCDRV_DBG_WARN(mcd, "MobiCore Daemon died");
ctx.daemon_inst = NULL;
ctx.daemon = NULL;
}
@@ -1183,7 +1219,7 @@
* 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);
+ MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X", ret, ret);
return (int)ret;
}
@@ -1200,7 +1236,9 @@
/* signal the daemon */
complete(&ctx.isr_comp);
-
+#ifdef MC_MEM_TRACES
+ mobicore_log_read();
+#endif
return IRQ_HANDLED;
}
@@ -1221,6 +1259,9 @@
.release = mc_fd_release,
.unlocked_ioctl = mc_fd_user_ioctl,
.mmap = mc_fd_mmap,
+#if defined(TBASE_CORE_SWITCHER) && defined(DEBUG)
+ .write = mc_fd_write,
+#endif
};
static int create_devices(void)
@@ -1239,17 +1280,17 @@
ret = alloc_chrdev_region(&mc_dev_admin, 0, MC_DEV_MAX, "mobicore");
if (ret < 0) {
- MCDRV_DBG_ERROR(mcd, "failed to allocate char dev region\n");
+ MCDRV_DBG_ERROR(mcd, "failed to allocate char dev region");
goto error;
}
mc_dev_user = MKDEV(MAJOR(mc_dev_admin), 1);
- MCDRV_DBG_VERBOSE(mcd, "%s: dev %d", "mobicore", MAJOR(mc_dev_region));
+ MCDRV_DBG_VERBOSE(mcd, "%s: dev %d", "mobicore", MAJOR(mc_dev_admin));
/* First the ADMIN node */
ret = cdev_add(&mc_admin_cdev, mc_dev_admin, 1);
if (ret != 0) {
- MCDRV_DBG_ERROR(mcd, "admin device register failed\n");
+ MCDRV_DBG_ERROR(mcd, "admin device register failed");
goto error;
}
mc_admin_cdev.owner = THIS_MODULE;
@@ -1260,7 +1301,7 @@
ret = cdev_add(&mc_user_cdev, mc_dev_user, 1);
if (ret != 0) {
- MCDRV_DBG_ERROR(mcd, "user device register failed\n");
+ MCDRV_DBG_ERROR(mcd, "user device register failed");
goto error_unregister;
}
mc_user_cdev.owner = THIS_MODULE;
@@ -1301,13 +1342,13 @@
/* Hardware does not support ARM TrustZone -> Cannot continue! */
if (!has_security_extensions()) {
MCDRV_DBG_ERROR(mcd,
- "Hardware doesn't support ARM TrustZone!\n");
+ "Hardware doesn't support ARM TrustZone!");
return -ENODEV;
}
/* Running in secure mode -> Cannot load the driver! */
if (is_secure_mode()) {
- MCDRV_DBG_ERROR(mcd, "Running in secure MODE!\n");
+ MCDRV_DBG_ERROR(mcd, "Running in secure MODE!");
return -ENODEV;
}
@@ -1320,18 +1361,18 @@
/* initialize event counter for signaling of an IRQ to zero */
atomic_set(&ctx.isr_counter, 0);
- /* set up S-SIQ interrupt handler */
+ /* 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");
+ MCDRV_DBG_ERROR(mcd, "interrupt request failed");
goto err_req_irq;
}
#ifdef MC_PM_RUNTIME
ret = mc_pm_initialize(&ctx);
if (ret != 0) {
- MCDRV_DBG_ERROR(mcd, "Power Management init failed!\n");
+ MCDRV_DBG_ERROR(mcd, "Power Management init failed!");
goto free_isr;
}
#endif
@@ -1340,7 +1381,7 @@
if (ret != 0)
goto free_pm;
- ret = mc_init_l2_tables();
+ ret = mc_init_mmu_tables();
#ifdef MC_CRYPTO_CLOCK_MANAGEMENT
ret = mc_pm_clock_initialize();
@@ -1361,7 +1402,7 @@
mutex_init(&ctx.bufs_lock);
memset(&ctx.mci_base, 0, sizeof(ctx.mci_base));
- MCDRV_DBG(mcd, "initialized\n");
+ MCDRV_DBG(mcd, "initialized");
return 0;
free_pm:
@@ -1381,12 +1422,12 @@
*/
static void __exit mobicore_exit(void)
{
- MCDRV_DBG_VERBOSE(mcd, "enter\n");
+ MCDRV_DBG_VERBOSE(mcd, "enter");
#ifdef MC_MEM_TRACES
mobicore_log_free();
#endif
- mc_release_l2_tables();
+ mc_release_mmu_tables();
#ifdef MC_PM_RUNTIME
mc_pm_free();
@@ -1408,6 +1449,15 @@
MCDRV_DBG_VERBOSE(mcd, "exit");
}
+bool mc_sleep_ready(void)
+{
+#ifdef MC_PM_RUNTIME
+ return mc_pm_sleep_ready();
+#else
+ return true;
+#endif
+}
+
/* Linux Driver Module Macros */
module_init(mobicore_init);
module_exit(mobicore_exit);
diff --git a/drivers/gud/mobicore_driver/main.h b/drivers/gud/MobiCoreDriver/main.h
similarity index 89%
rename from drivers/gud/mobicore_driver/main.h
rename to drivers/gud/MobiCoreDriver/main.h
index 871191e..11e304c 100644
--- a/drivers/gud/mobicore_driver/main.h
+++ b/drivers/gud/MobiCoreDriver/main.h
@@ -52,7 +52,7 @@
/* virtual Userspace start address */
void *uaddr;
/* physical start address */
- void *phys;
+ phys_addr_t phys;
/* order of number of pages */
unsigned int order;
uint32_t len;
@@ -83,8 +83,8 @@
};
struct mc_sleep_mode {
- uint16_t SleepReq;
- uint16_t ReadyToSleep;
+ uint16_t sleep_req;
+ uint16_t ready_to_sleep;
};
/* MobiCore is idle. No scheduling required. */
@@ -129,14 +129,14 @@
int mc_release_instance(struct mc_instance *instance);
/*
- * mc_register_wsm_l2() - Create a L2 table from a virtual memory buffer which
+ * mc_register_wsm_mmu() - Create a MMU 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 mc_register_wsm_mmu(struct mc_instance *instance,
+ void *buffer, uint32_t len,
+ uint32_t *handle, phys_addr_t *phys);
/* Unregister the buffer mapped above */
-int mc_unregister_wsm_l2(struct mc_instance *instance, uint32_t handle);
+int mc_unregister_wsm_mmu(struct mc_instance *instance, uint32_t handle);
/* Allocate one mc_buffer of contiguous space */
int mc_get_buffer(struct mc_instance *instance,
@@ -147,4 +147,7 @@
/* Check if the other end of the fd owns instance */
bool mc_check_owner_fd(struct mc_instance *instance, int32_t fd);
+/* Test if sleep is possible */
+bool mc_sleep_ready(void);
+
#endif /* _MC_MAIN_H_ */
diff --git a/drivers/gud/MobiCoreDriver/mem.c b/drivers/gud/MobiCoreDriver/mem.c
new file mode 100644
index 0000000..2d92f74
--- /dev/null
+++ b/drivers/gud/MobiCoreDriver/mem.c
@@ -0,0 +1,743 @@
+/*
+ * 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 -->
+ * <-- Copyright Trustonic Limited 2013 -->
+ *
+ * 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>
+
+#ifdef LPAE_SUPPORT
+#define MMU_TYPE_PAGE (3 << 0)
+#define MMU_BUFFERABLE (1 << 2) /* AttrIndx[0] */
+#define MMU_CACHEABLE (1 << 3) /* AttrIndx[1] */
+#define MMU_NS (1 << 5)
+#define MMU_AP_RW_ALL (1 << 6) /* AP[2:1], RW, at any privilege level */
+#define MMU_EXT_SHARED (3 << 8) /* SH[1:0], inner shareable */
+#define MMU_EXT_AF (1 << 10) /* Access Flag */
+#define MMU_EXT_NG (1 << 11)
+#define MMU_EXT_XN (((uint64_t)1) << 54) /* XN */
+#else
+#define MMU_TYPE_EXT (3 << 0) /* v5 */
+#define MMU_TYPE_SMALL (2 << 0)
+#define MMU_BUFFERABLE (1 << 2)
+#define MMU_CACHEABLE (1 << 3)
+#define MMU_EXT_AP0 (1 << 4)
+#define MMU_EXT_AP1 (2 << 4)
+#define MMU_EXT_TEX(x) ((x) << 6) /* v5 */
+#define MMU_EXT_SHARED (1 << 10) /* v6 */
+#define MMU_EXT_NG (1 << 11) /* v6 */
+#endif
+
+/* MobiCore memory context data */
+struct mc_mem_context mem_ctx;
+
+static inline void release_page(struct page *page)
+{
+ set_bit(PG_dirty, &page->flags);
+
+ 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 MMU table given a per-process reference */
+static void *get_mmu_table_kernel_virt(struct mc_mmu_table *table)
+{
+ if (WARN(!table, "Invalid MMU table"))
+ return NULL;
+
+ if (WARN(!table->set, "Invalid MMU table set"))
+ return NULL;
+
+ if (WARN(!table->set->kernel_virt, "Invalid MMU pointer"))
+ return NULL;
+
+ return &(table->set->kernel_virt->table[table->idx]);
+}
+
+static inline int in_use(struct mc_mmu_table *table)
+{
+ return atomic_read(&table->usage) > 0;
+}
+
+/*
+ * Search the list of used MMU tables and return the one with the handle.
+ * Assumes the table_lock is taken.
+ */
+struct mc_mmu_table *find_mmu_table(unsigned int handle)
+{
+ struct mc_mmu_table *table;
+
+ list_for_each_entry(table, &mem_ctx.mmu_tables, list) {
+ if (table->handle == handle)
+ return table;
+ }
+ return NULL;
+}
+
+/*
+ * Allocate a new MMU table store plus MMU_TABLES_PER_PAGE in the MMU free
+ * tables list. Assumes the table_lock is already taken by the caller above.
+ */
+static int alloc_mmu_table_store(void)
+{
+ unsigned long store;
+ struct mc_mmu_tables_set *mmutable_set;
+ struct mc_mmu_table *mmutable, *mmutable2;
+ struct page *page;
+ int ret = 0, i;
+ /* temp list for holding the MMU 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);
+ set_bit(PG_reserved, &page->flags);
+
+ /* add all the descriptors to the free descriptors list */
+ mmutable_set = kmalloc(sizeof(*mmutable_set), GFP_KERNEL | __GFP_ZERO);
+ if (mmutable_set == NULL) {
+ ret = -ENOMEM;
+ goto free_store;
+ }
+ /* initialize */
+ mmutable_set->kernel_virt = (void *)store;
+ mmutable_set->page = page;
+ mmutable_set->phys = virt_to_phys((void *)store);
+ /* the set is not yet used */
+ atomic_set(&mmutable_set->used_tables, 0);
+
+ /* init add to list. */
+ INIT_LIST_HEAD(&(mmutable_set->list));
+ list_add(&mmutable_set->list, &mem_ctx.mmu_tables_sets);
+
+ for (i = 0; i < MMU_TABLES_PER_PAGE; i++) {
+ /* allocate a WSM MMU descriptor */
+ mmutable = kmalloc(sizeof(*mmutable), GFP_KERNEL | __GFP_ZERO);
+ if (mmutable == NULL) {
+ ret = -ENOMEM;
+ MCDRV_DBG_ERROR(mcd, "out of memory");
+ /* Free the full temp list and the store in this case */
+ goto free_temp_list;
+ }
+
+ /* set set reference */
+ mmutable->set = mmutable_set;
+ mmutable->idx = i;
+ mmutable->virt = get_mmu_table_kernel_virt(mmutable);
+ mmutable->phys = mmutable_set->phys+i*sizeof(struct mmutable);
+ atomic_set(&mmutable->usage, 0);
+
+ /* add to temp list. */
+ INIT_LIST_HEAD(&mmutable->list);
+ list_add_tail(&mmutable->list, &temp);
+ }
+
+ /*
+ * If everything went ok then merge the temp list with the global
+ * free list
+ */
+ list_splice_tail(&temp, &mem_ctx.free_mmu_tables);
+ return 0;
+free_temp_list:
+ list_for_each_entry_safe(mmutable, mmutable2, &temp, list) {
+ kfree(mmutable);
+ }
+
+ list_del(&mmutable_set->list);
+
+free_store:
+ free_page(store);
+ return ret;
+}
+/*
+ * Get a MMU table from the free tables list or allocate a new one and
+ * initialize it. Assumes the table_lock is already taken.
+ */
+static struct mc_mmu_table *alloc_mmu_table(struct mc_instance *instance)
+{
+ int ret = 0;
+ struct mc_mmu_table *table = NULL;
+
+ if (list_empty(&mem_ctx.free_mmu_tables)) {
+ ret = alloc_mmu_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_mmu_tables)) {
+ MCDRV_DBG_ERROR(mcd,
+ "Free list not updated correctly!");
+ return ERR_PTR(-EFAULT);
+ }
+ }
+
+ /* get a WSM MMU descriptor */
+ table = list_first_entry(&mem_ctx.free_mmu_tables,
+ struct mc_mmu_table, list);
+ if (table == NULL) {
+ MCDRV_DBG_ERROR(mcd, "out of memory");
+ return ERR_PTR(-ENOMEM);
+ }
+ /* Move it to the used MMU tables list */
+ list_move_tail(&table->list, &mem_ctx.mmu_tables);
+
+ table->handle = get_unique_id();
+ table->owner = instance;
+
+ atomic_inc(&table->set->used_tables);
+ atomic_inc(&table->usage);
+
+ MCDRV_DBG_VERBOSE(mcd,
+ "chunkPhys=0x%llX, idx=%d",
+ (u64)table->set->phys, table->idx);
+
+ return table;
+}
+
+/*
+ * Frees the object associated with a MMU 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_mmu_table(struct mc_mmu_table *table)
+{
+ struct mc_mmu_tables_set *mmutable_set;
+
+ if (WARN(!table, "Invalid table"))
+ return;
+
+ mmutable_set = table->set;
+ if (WARN(!mmutable_set, "Invalid table set"))
+ return;
+
+ list_move_tail(&table->list, &mem_ctx.free_mmu_tables);
+
+ /* if nobody uses this set, we can release it. */
+ if (atomic_dec_and_test(&mmutable_set->used_tables)) {
+ struct mc_mmu_table *tmp;
+
+ /* remove from list */
+ list_del(&mmutable_set->list);
+ /*
+ * All the MMU 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_mmu_tables,
+ list) {
+ if (table->set == mmutable_set) {
+ list_del(&table->list);
+ kfree(table);
+ }
+ } /* end while */
+
+ /*
+ * We shouldn't recover from this since it was some data
+ * corruption before
+ */
+ BUG_ON(!mmutable_set->page);
+ clear_bit(PG_reserved, &(mmutable_set->page)->flags);
+
+
+ BUG_ON(!mmutable_set->kernel_virt);
+ free_page((unsigned long)mmutable_set->kernel_virt);
+
+ kfree(mmutable_set);
+ }
+}
+
+/*
+ * Create a MMU 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 MMU 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 MMU table details
+ */
+static int map_buffer(struct task_struct *task, void *wsm_buffer,
+ unsigned int wsm_len, struct mc_mmu_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 mmutable *mmutable;
+ struct page **mmutable_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");
+ return -EINVAL;
+ }
+
+ MCDRV_DBG_VERBOSE(mcd, "WSM addr=0x%p, len=0x%08x", wsm_buffer,
+ wsm_len);
+
+ /* 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",
+ virt_addr_page, nr_of_pages);
+
+ /* MMU 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");
+ return -EINVAL;
+ }
+
+ mmutable = table->virt;
+ /*
+ * We use the memory for the MMU table to hold the pointer
+ * and convert them later. This works, as everything comes
+ * down to a 32 bit value.
+ */
+ mmutable_as_array_of_pointers_to_page = (struct page **)mmutable;
+
+ /* 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,
+ mmutable_as_array_of_pointers_to_page);
+ if (ret != 0) {
+ MCDRV_DBG_ERROR(mcd, "lock_user_pages() failed");
+ return ret;
+ }
+ }
+ /* Request comes from kernel space(cont buffer) */
+ else if (task == NULL && !is_vmalloc_addr(wsm_buffer)) {
+ void *uaddr = wsm_buffer;
+ for (i = 0; i < nr_of_pages; i++) {
+ page = virt_to_page(uaddr);
+ if (!page) {
+ MCDRV_DBG_ERROR(mcd, "failed to map address");
+ return -EINVAL;
+ }
+ get_page(page);
+ mmutable_as_array_of_pointers_to_page[i] = page;
+ uaddr += PAGE_SIZE;
+ }
+ }
+ /* 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);
+ mmutable_as_array_of_pointers_to_page[i] = page;
+ uaddr += PAGE_SIZE;
+ }
+ }
+
+ table->pages = nr_of_pages;
+
+ /*
+ * create MMU Table entries.
+ * used_mmutable->table contains a list of page pointers here.
+ * For a proper cleanup we have to ensure that the following
+ * code either works and used_mmutable contains a valid MMU table
+ * - or fails and used_mmutable->table contains the list of page
+ * pointers.
+ * Any mixed contents will make cleanup difficult.
+ * Fill the table in reverse order as the table is used as input and
+ * output.
+ */
+ i = MC_ARM_MMU_TABLE_ENTRIES-1;
+ do {
+ if (i < nr_of_pages) {
+#ifdef LPAE_SUPPORT
+ uint64_t pte;
+#elif defined(CONFIG_ARM_LPAE) && !defined(LPAE_SUPPORT)
+ /* Nwd supports 64bit addresses, SWD only 32bit */
+ uint64_t pte64;
+ uint32_t pte;
+#else
+ uint32_t pte;
+#endif
+ page = mmutable_as_array_of_pointers_to_page[i];
+
+ /*
+ * create MMU 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.
+ */
+#ifdef LPAE_SUPPORT
+ pte = page_to_phys(page);
+ pte |= MMU_EXT_XN
+ | MMU_EXT_NG
+ | MMU_EXT_AF
+ | MMU_AP_RW_ALL
+ | MMU_NS
+ | MMU_CACHEABLE | MMU_BUFFERABLE
+ | MMU_TYPE_PAGE;
+#elif defined(CONFIG_ARM_LPAE) && !defined(LPAE_SUPPORT)
+ /*
+ * NWD uses 64bit addresses but SWD can handle only
+ * short descriptors
+ * and physical addresses not bigger than 4GB
+ */
+ pte64 = page_to_phys(page);
+ if ((pte64 >> 32) != 0) {
+ MCDRV_DBG_ERROR(mcd,
+ "physical addresses bigger than 4GB not supported");
+ return -EINVAL;
+ }
+ pte = (uint32_t)pte64;
+ pte |= MMU_EXT_AP1 | MMU_EXT_AP0
+ | MMU_CACHEABLE | MMU_BUFFERABLE
+ | MMU_TYPE_SMALL | MMU_TYPE_EXT | MMU_EXT_NG;
+#else
+ pte = page_to_phys(page);
+ pte |= MMU_EXT_AP1 | MMU_EXT_AP0
+ | MMU_CACHEABLE | MMU_BUFFERABLE
+ | MMU_TYPE_SMALL | MMU_TYPE_EXT | MMU_EXT_NG;
+#endif /* LPAE_SUPPORT */
+ /*
+ * 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
+#ifdef LPAE_SUPPORT
+ pte |= MMU_EXT_SHARED;
+#else
+ pte |= MMU_EXT_SHARED | MMU_EXT_TEX(1);
+#endif /* LPAE_SUPPORT */
+#endif /* CONFIG_SMP */
+
+ mmutable->table_entries[i] = pte;
+ MCDRV_DBG_VERBOSE(mcd, "MMU entry %d: 0x%llx", i,
+ (u64)(pte));
+ } else {
+ /* ensure rest of table is empty */
+ mmutable->table_entries[i] = 0;
+ }
+ } while (i-- != 0);
+
+ return ret;
+}
+
+/*
+ * Remove a MMU 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_mmu_table *table)
+{
+ struct mmutable *mmutable;
+ int i;
+
+ if (WARN_ON(!table))
+ return;
+
+ /* found the table, now release the resources. */
+ MCDRV_DBG_VERBOSE(mcd,
+ "clear MMU table, phys_base=0x%llX,nr_of_pages=%d",
+ (u64)table->phys, table->pages);
+
+ mmutable = table->virt;
+
+ /* release all locked user space pages */
+ for (i = 0; i < table->pages; i++) {
+ /* convert physical entries from MMU table to page pointers */
+ struct page *page;
+ page = phys_to_page(mmutable->table_entries[i]);
+ release_page(page);
+ }
+
+ /* remember that all pages have been freed */
+ table->pages = 0;
+}
+
+/* Delete a used MMU table. Assumes the table_lock and the lock is taken */
+static void unmap_mmu_table(struct mc_mmu_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_mmu_table(table);
+}
+
+int mc_free_mmu_table(struct mc_instance *instance, uint32_t handle)
+{
+ struct mc_mmu_table *table;
+ int ret = 0;
+
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
+
+ mutex_lock(&mem_ctx.table_lock);
+ table = find_mmu_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_mmu_table(table);
+err_unlock:
+ mutex_unlock(&mem_ctx.table_lock);
+
+ return ret;
+}
+
+int mc_lock_mmu_table(struct mc_instance *instance, uint32_t handle)
+{
+ int ret = 0;
+ struct mc_mmu_table *table = NULL;
+
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
+
+ mutex_lock(&mem_ctx.table_lock);
+ table = find_mmu_table(handle);
+
+ if (table == NULL) {
+ MCDRV_DBG_VERBOSE(mcd, "entry not found %u", handle);
+ ret = -EINVAL;
+ goto table_err;
+ }
+ if (instance != table->owner && !is_daemon(instance)) {
+ MCDRV_DBG_ERROR(mcd, "instance does no own it");
+ ret = -EPERM;
+ goto table_err;
+ }
+
+ /* lock entry */
+ atomic_inc(&table->usage);
+table_err:
+ mutex_unlock(&mem_ctx.table_lock);
+ return ret;
+}
+/*
+ * Allocate MMU table and map buffer into it.
+ * That is, create respective table entries.
+ */
+struct mc_mmu_table *mc_alloc_mmu_table(struct mc_instance *instance,
+ struct task_struct *task, void *wsm_buffer, unsigned int wsm_len)
+{
+ int ret = 0;
+ struct mc_mmu_table *table;
+
+ if (WARN(!instance, "No instance data available"))
+ return ERR_PTR(-EFAULT);
+
+ mutex_lock(&mem_ctx.table_lock);
+ table = alloc_mmu_table(instance);
+ if (IS_ERR(table)) {
+ MCDRV_DBG_ERROR(mcd, "alloc_mmu_table() failed");
+ ret = -ENOMEM;
+ goto err_no_mem;
+ }
+
+ /* create the MMU page for the WSM */
+ ret = map_buffer(task, wsm_buffer, wsm_len, table);
+
+ if (ret != 0) {
+ MCDRV_DBG_ERROR(mcd, "map_buffer() failed");
+ unmap_mmu_table(table);
+ goto err_no_mem;
+ }
+ MCDRV_DBG_VERBOSE(mcd,
+ "mapped buffer %p to table with handle %d @ 0x%llX",
+ wsm_buffer, table->handle, (u64)table->phys);
+
+ mutex_unlock(&mem_ctx.table_lock);
+ return table;
+err_no_mem:
+ mutex_unlock(&mem_ctx.table_lock);
+ return ERR_PTR(ret);
+}
+
+phys_addr_t mc_find_mmu_table(uint32_t handle, int32_t fd)
+{
+ phys_addr_t ret = 0;
+ struct mc_mmu_table *table = NULL;
+
+ mutex_lock(&mem_ctx.table_lock);
+ table = find_mmu_table(handle);
+
+ if (table == NULL) {
+ MCDRV_DBG_ERROR(mcd, "entry not found %u", handle);
+ ret = 0;
+ goto table_err;
+ }
+
+ /* It's safe here not to lock the instance since the owner of
+ * the table will be cleared only with the table lock taken */
+ if (!mc_check_owner_fd(table->owner, fd)) {
+ MCDRV_DBG_ERROR(mcd, "not valid owner %u", handle);
+ ret = 0;
+ goto table_err;
+ }
+
+ ret = table->phys;
+table_err:
+ mutex_unlock(&mem_ctx.table_lock);
+ return ret;
+}
+
+void mc_clean_mmu_tables(void)
+{
+ struct mc_mmu_table *table, *tmp;
+
+ mutex_lock(&mem_ctx.table_lock);
+ /* Check if some WSM is orphaned. */
+ list_for_each_entry_safe(table, tmp, &mem_ctx.mmu_tables, list) {
+ if (table->owner == NULL) {
+ MCDRV_DBG(mcd,
+ "cleariM MMU: p=0x%llX pages=%d",
+ (u64)table->phys,
+ table->pages);
+ unmap_mmu_table(table);
+ }
+ }
+ mutex_unlock(&mem_ctx.table_lock);
+}
+
+void mc_clear_mmu_tables(struct mc_instance *instance)
+{
+ struct mc_mmu_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.mmu_tables, list) {
+ if (table->owner == instance) {
+ MCDRV_DBG(mcd, "release WSM MMU: p=0x%llX pages=%d",
+ (u64)table->phys,
+ table->pages);
+ /* unlock app usage and free or mark it as orphan */
+ table->owner = NULL;
+ unmap_mmu_table(table);
+ }
+ }
+ mutex_unlock(&mem_ctx.table_lock);
+}
+
+int mc_init_mmu_tables(void)
+{
+ /* init list for WSM MMU chunks. */
+ INIT_LIST_HEAD(&mem_ctx.mmu_tables_sets);
+
+ /* MMU table descriptor list. */
+ INIT_LIST_HEAD(&mem_ctx.mmu_tables);
+
+ /* MMU free table descriptor list. */
+ INIT_LIST_HEAD(&mem_ctx.free_mmu_tables);
+
+ mutex_init(&mem_ctx.table_lock);
+
+ return 0;
+}
+
+void mc_release_mmu_tables(void)
+{
+ struct mc_mmu_table *table;
+ /* Check if some WSM is still in use. */
+ list_for_each_entry(table, &mem_ctx.mmu_tables, list) {
+ WARN(1, "WSM MMU still in use: phys=0x%llX ,nr_of_pages=%d",
+ (u64)table->phys, table->pages);
+ }
+}
diff --git a/drivers/gud/MobiCoreDriver/mem.h b/drivers/gud/MobiCoreDriver/mem.h
new file mode 100644
index 0000000..5c9006a
--- /dev/null
+++ b/drivers/gud/MobiCoreDriver/mem.h
@@ -0,0 +1,139 @@
+/*
+ * MobiCore driver module.(interface to the secure world SWD)
+ *
+ * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ * <-- Copyright Trustonic Limited 2013 -->
+ *
+ * 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_
+
+#ifdef LPAE_SUPPORT
+/*
+ * Number of page table entries in one MMU table. This is ARM specific, an
+ * MMU table covers 2 MiB by using 512 entries referring to 4KiB pages each.
+ */
+#define MC_ARM_MMU_TABLE_ENTRIES 512
+
+/* ARM level 3 (MMU) table with 512 entries. Size: 4k */
+struct mmutable {
+ uint64_t table_entries[MC_ARM_MMU_TABLE_ENTRIES];
+};
+
+/* There is 1 table in each page. */
+#define MMU_TABLES_PER_PAGE 1
+#else
+/*
+ * 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 MMU table. This is ARM specific, an
+ * MMU table covers 1 MiB by using 256 entries referring to 4KiB pages each.
+ */
+#define MC_ARM_MMU_TABLE_ENTRIES 256
+
+/* ARM level 2 (MMU) table with 256 entries. Size: 1k */
+struct mmutable {
+ uint32_t table_entries[MC_ARM_MMU_TABLE_ENTRIES];
+};
+
+/* There are 4 tables in each page. */
+#define MMU_TABLES_PER_PAGE 4
+#endif
+
+/* Store for four MMU tables in one 4kb page*/
+struct mc_mmu_table_store {
+ struct mmutable table[MMU_TABLES_PER_PAGE];
+};
+
+/* Usage and maintenance information about mc_mmu_table_store */
+struct mc_mmu_tables_set {
+ struct list_head list;
+ /* kernel virtual address */
+ struct mc_mmu_table_store *kernel_virt;
+ /* physical address */
+ phys_addr_t phys;
+ /* pointer to page struct */
+ struct page *page;
+ /* How many pages from this set are used */
+ atomic_t used_tables;
+};
+
+/*
+ * MMU table allocated to the Daemon or a TLC describing a world shared
+ * buffer.
+ * When users map a malloc()ed area into SWd, a MMU table is allocated.
+ * In addition, the area of maximum 1MB virtual address space is mapped into
+ * the MMU table and a handle for this table is returned to the user.
+ */
+struct mc_mmu_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 MMU table */
+ atomic_t usage;
+ /* owner of this MMU table */
+ struct mc_instance *owner;
+ /* set describing where our MMU table is stored */
+ struct mc_mmu_tables_set *set;
+ /* index into MMU table set */
+ unsigned int idx;
+ /* size of buffer */
+ unsigned int pages;
+ /* virtual address*/
+ void *virt;
+ /* physical address */
+ phys_addr_t phys;
+};
+
+/* MobiCore Driver Memory context data. */
+struct mc_mem_context {
+ struct mc_instance *daemon_inst;
+ /* Backing store for MMU tables */
+ struct list_head mmu_tables_sets;
+ /* Bookkeeping for used MMU tables */
+ struct list_head mmu_tables;
+ /* Bookkeeping for free MMU tables */
+ struct list_head free_mmu_tables;
+ /* semaphore to synchronize access to above lists */
+ struct mutex table_lock;
+};
+
+/*
+ * Allocate MMU table and map buffer into it.
+ * That is, create respective table entries.
+ */
+struct mc_mmu_table *mc_alloc_mmu_table(struct mc_instance *instance,
+ struct task_struct *task, void *wsm_buffer, unsigned int wsm_len);
+
+/* Delete all the MMU tables associated with an instance */
+void mc_clear_mmu_tables(struct mc_instance *instance);
+
+/* Release all orphaned MMU tables */
+void mc_clean_mmu_tables(void);
+
+/* Delete a used MMU table. */
+int mc_free_mmu_table(struct mc_instance *instance, uint32_t handle);
+
+/*
+ * Lock a MMU table - the daemon adds +1 to refcount of the MMU table
+ * marking it in use by SWD so it doesn't get released when the TLC dies.
+ */
+int mc_lock_mmu_table(struct mc_instance *instance, uint32_t handle);
+
+/* Return the phys address of MMU table. */
+phys_addr_t mc_find_mmu_table(uint32_t handle, int32_t fd);
+/* Release all used MMU tables to Linux memory space */
+void mc_release_mmu_tables(void);
+
+/* Initialize all MMU tables structure */
+int mc_init_mmu_tables(void);
+
+#endif /* _MC_MEM_H_ */
diff --git a/drivers/gud/MobiCoreDriver/ops.c b/drivers/gud/MobiCoreDriver/ops.c
new file mode 100644
index 0000000..96b4f4f
--- /dev/null
+++ b/drivers/gud/MobiCoreDriver/ops.c
@@ -0,0 +1,398 @@
+/*
+ * 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 -->
+ * <-- Copyright Trustonic Limited 2013 -->
+ *
+ * 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 <linux/workqueue.h>
+#include <linux/cpu.h>
+
+#include "main.h"
+#include "fastcall.h"
+#include "ops.h"
+#include "mem.h"
+#include "pm.h"
+#include "debug.h"
+
+/* MobiCore context data */
+static struct mc_context *ctx;
+#ifdef TBASE_CORE_SWITCHER
+static uint32_t active_cpu;
+
+static int mobicore_cpu_callback(struct notifier_block *nfb,
+ unsigned long action, void *hcpu);
+static struct notifier_block mobicore_cpu_notifer = {
+ .notifier_call = mobicore_cpu_callback,
+};
+#endif
+
+static inline long smc(union fc_generic *fc)
+{
+ /* If we request sleep yields must be filtered out as they
+ * make no sense */
+ if (ctx->mcp)
+ if (ctx->mcp->flags.sleep_mode.sleep_req) {
+ if (fc->as_in.cmd == MC_SMC_N_YIELD)
+ return MC_FC_RET_ERR_INVALID;
+ }
+ return _smc(fc);
+}
+
+struct fastcall_work {
+#ifdef MC_FASTCALL_WORKER_THREAD
+ struct kthread_work work;
+#else
+ struct work_struct work;
+#endif
+ void *data;
+};
+
+#ifdef MC_FASTCALL_WORKER_THREAD
+static void fastcall_work_func(struct kthread_work *work);
+#else
+static void fastcall_work_func(struct work_struct *work);
+#endif
+
+
+#ifdef MC_FASTCALL_WORKER_THREAD
+
+static struct task_struct *fastcall_thread;
+static DEFINE_KTHREAD_WORKER(fastcall_worker);
+
+bool mc_fastcall(void *data)
+{
+ struct fastcall_work fc_work = {
+ KTHREAD_WORK_INIT(fc_work.work, fastcall_work_func),
+ .data = data,
+ };
+
+ if (!queue_kthread_work(&fastcall_worker, &fc_work.work))
+ return false;
+ flush_kthread_work(&fc_work.work);
+ return true;
+}
+
+int mc_fastcall_init(struct mc_context *context)
+{
+ int ret = 0;
+ ctx = context;
+
+ fastcall_thread = kthread_create(kthread_worker_fn, &fastcall_worker,
+ "mc_fastcall");
+ if (IS_ERR(fastcall_thread)) {
+ ret = PTR_ERR(fastcall_thread);
+ fastcall_thread = NULL;
+ MCDRV_DBG_ERROR(mcd, "cannot create fastcall wq (%d)", ret);
+ return ret;
+ }
+
+ wake_up_process(fastcall_thread);
+
+ /* this thread MUST run on CPU 0 at startup */
+ set_cpus_allowed(fastcall_thread, CPU_MASK_CPU0);
+#ifdef TBASE_CORE_SWITCHER
+ register_cpu_notifier(&mobicore_cpu_notifer);
+#endif
+ return 0;
+}
+
+void mc_fastcall_destroy(void)
+{
+ if (!IS_ERR_OR_NULL(fastcall_thread)) {
+ kthread_stop(fastcall_thread);
+ fastcall_thread = NULL;
+ }
+}
+#else
+
+bool mc_fastcall(void *data)
+{
+ struct fastcall_work work = {
+ .data = data,
+ };
+ INIT_WORK(&work.work, fastcall_work_func);
+ if (!schedule_work_on(0, &work.work))
+ return false;
+ flush_work(&work.work);
+ return true;
+}
+
+int mc_fastcall_init(struct mc_context *context)
+{
+ ctx = context;
+ return 0;
+};
+
+void mc_fastcall_destroy(void) {};
+#endif
+
+#ifdef MC_FASTCALL_WORKER_THREAD
+static void fastcall_work_func(struct kthread_work *work)
+#else
+static void fastcall_work_func(struct work_struct *work)
+#endif
+{
+ struct fastcall_work *fc_work =
+ container_of(work, struct fastcall_work, work);
+ union fc_generic *fc_generic = fc_work->data;
+#ifdef TBASE_CORE_SWITCHER
+ uint32_t cpu_swap = 0, new_cpu;
+ uint32_t cpu_id[] = CPU_IDS;
+#endif
+
+#ifdef MC_CRYPTO_CLOCK_MANAGEMENT
+ mc_pm_clock_enable();
+#endif
+
+
+ if (fc_generic == NULL)
+ return;
+#ifdef TBASE_CORE_SWITCHER
+ if (fc_generic->as_in.cmd == MC_FC_SWITCH_CORE) {
+ cpu_swap = 1;
+ new_cpu = fc_generic->as_in.param[0];
+ fc_generic->as_in.param[0] = cpu_id[fc_generic->as_in.param[0]];
+ }
+#endif
+ smc(fc_work->data);
+#ifdef TBASE_CORE_SWITCHER
+ if (cpu_swap) {
+ if (fc_generic->as_out.ret == 0) {
+ cpumask_t cpu;
+ active_cpu = new_cpu;
+ MCDRV_DBG(mcd, "CoreSwap ok %d -> %d\n",
+ raw_smp_processor_id(), active_cpu);
+ cpumask_clear(&cpu);
+ cpumask_set_cpu(active_cpu, &cpu);
+#ifdef MC_FASTCALL_WORKER_THREAD
+ set_cpus_allowed(fastcall_thread, cpu);
+#endif
+ } else {
+ MCDRV_DBG(mcd, "CoreSwap failed %d -> %d\n",
+ raw_smp_processor_id(),
+ fc_generic->as_in.param[0]);
+ }
+ }
+#endif
+#ifdef MC_CRYPTO_CLOCK_MANAGEMENT
+ mc_pm_clock_disable();
+#endif
+}
+
+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");
+
+ 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, "<- cmd=0x%08x, ext_info_id=0x%08x",
+ fc_info.as_in.cmd, fc_info.as_in.ext_info_id);
+
+ mc_fastcall(&(fc_info.as_generic));
+
+ MCDRV_DBG(mcd,
+ "-> 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", ret, ret);
+
+ return ret;
+}
+
+#ifdef TBASE_CORE_SWITCHER
+int mc_switch_core(uint32_t core_num)
+{
+ int32_t ret = 0;
+ union mc_fc_swich_core fc_switch_core;
+
+ if (!cpu_online(core_num))
+ return 1;
+
+ MCDRV_DBG_VERBOSE(mcd, "enter\n");
+
+ memset(&fc_switch_core, 0, sizeof(fc_switch_core));
+ fc_switch_core.as_in.cmd = MC_FC_SWITCH_CORE;
+
+ if (core_num < COUNT_OF_CPUS)
+ fc_switch_core.as_in.core_id = core_num;
+ else
+ fc_switch_core.as_in.core_id = 0;
+
+ MCDRV_DBG(
+ mcd, "<- cmd=0x%08x, core_num=0x%08x, "
+ "active_cpu=0x%08x, active_cpu=0x%08x\n",
+ fc_switch_core.as_in.cmd,
+ fc_switch_core.as_in.core_id,
+ core_num, active_cpu);
+ mc_fastcall(&(fc_switch_core.as_generic));
+
+ ret = convert_fc_ret(fc_switch_core.as_out.ret);
+
+ MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret);
+
+ return ret;
+}
+
+void mc_cpu_offfline(int cpu)
+{
+ if (active_cpu == cpu) {
+ int i;
+ /* Chose the first online CPU and switch! */
+ for_each_online_cpu(i) {
+ if (i == cpu) {
+ MCDRV_DBG(mcd, "Skipping CPU %d\n", cpu);
+ continue;
+ }
+ MCDRV_DBG(mcd, "CPU %d is dying, switching to %d\n",
+ cpu, i);
+ mc_switch_core(i);
+ break;
+ }
+ } else {
+ MCDRV_DBG(mcd, "not active CPU, no action taken\n");
+ }
+}
+
+static int mobicore_cpu_callback(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ unsigned int cpu = (unsigned long)hcpu;
+
+ switch (action) {
+ case CPU_DOWN_PREPARE:
+ case CPU_DOWN_PREPARE_FROZEN:
+ dev_info(mcd, "Cpu %u is going to die\n", cpu);
+ mc_cpu_offfline(cpu);
+ break;
+ case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
+ dev_info(mcd, "Cpu %u is dead\n", cpu);
+ break;
+ }
+ return NOTIFY_OK;
+}
+#endif
+
+/* Yield to MobiCore */
+int mc_yield(void)
+{
+ int ret = 0;
+ union fc_generic yield;
+
+ MCDRV_DBG_VERBOSE(mcd, "enter");
+ 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");
+ 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 common notify */
+int _nsiq(void)
+{
+ int ret = 0;
+ union fc_generic nsiq;
+ MCDRV_DBG_VERBOSE(mcd, "enter");
+ memset(&nsiq, 0, sizeof(nsiq));
+ nsiq.as_in.cmd = MC_SMC_N_SIQ;
+ _smc(&nsiq);
+ ret = convert_fc_ret(nsiq.as_out.ret);
+ return ret;
+}
+
+/* Call the INIT fastcall to setup MobiCore initialization */
+int mc_init(phys_addr_t base, uint32_t nq_length,
+ uint32_t mcp_offset, uint32_t mcp_length)
+{
+ int ret = 0;
+ union mc_fc_init fc_init;
+ uint64_t base_addr = (uint64_t)base;
+ uint32_t base_high = (uint32_t)(base_addr >> 32);
+
+ MCDRV_DBG_VERBOSE(mcd, "enter");
+
+ 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)base_addr;
+ /* notification buffer start/length [16:16] [start, length] */
+ fc_init.as_in.nq_info = ((base_high && 0xFFFF) << 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",
+ 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", 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", ret, ret);
+
+ return ret;
+}
+
+/* Return MobiCore driver version */
+uint32_t mc_get_version(void)
+{
+ MCDRV_DBG(mcd, "MobiCore driver version is %i.%i",
+ 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/MobiCoreDriver/ops.h
similarity index 78%
rename from drivers/gud/mobicore_driver/ops.h
rename to drivers/gud/MobiCoreDriver/ops.h
index 910c1f4..f04eb3e 100644
--- a/drivers/gud/mobicore_driver/ops.h
+++ b/drivers/gud/MobiCoreDriver/ops.h
@@ -21,10 +21,13 @@
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);
+int mc_init(phys_addr_t base, uint32_t nq_length, uint32_t mcp_offset,
+ uint32_t mcp_length);
+#ifdef TBASE_CORE_SWITCHER
+int mc_switch_core(uint32_t core_num);
+#endif
-void mc_fastcall(void *data);
+bool mc_fastcall(void *data);
int mc_fastcall_init(struct mc_context *context);
void mc_fastcall_destroy(void);
diff --git a/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h b/drivers/gud/MobiCoreDriver/platforms/MSM8960_SURF_STD/platform.h
similarity index 85%
rename from drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h
rename to drivers/gud/MobiCoreDriver/platforms/MSM8960_SURF_STD/platform.h
index 9d128ae..72ea3ed 100644
--- a/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h
+++ b/drivers/gud/MobiCoreDriver/platforms/MSM8960_SURF_STD/platform.h
@@ -36,19 +36,12 @@
}
/* Enable mobicore mem traces */
-/* #define MC_MEM_TRACES */
+#define MC_MEM_TRACES
/* Enable the use of vm_unamp instead of the deprecated do_munmap
* and other 3.7 features
*/
-#ifndef CONFIG_ARCH_MSM8960
#define MC_VM_UNMAP
-#endif
-
-#if defined (CONFIG_ARCH_MSM8974) || defined (CONFIG_ARCH_MSM8226)
-/* Perform clock enable/disable */
-#define MC_CRYPTO_CLOCK_MANAGEMENT
-#endif
/* Enable Power Management for Crypto Engine */
#define MC_CRYPTO_CLOCK_MANAGEMENT
diff --git a/drivers/gud/mobicore_driver/pm.c b/drivers/gud/MobiCoreDriver/pm.c
similarity index 66%
rename from drivers/gud/mobicore_driver/pm.c
rename to drivers/gud/MobiCoreDriver/pm.c
index 55a1ef7..40365ef 100644
--- a/drivers/gud/mobicore_driver/pm.c
+++ b/drivers/gud/MobiCoreDriver/pm.c
@@ -46,7 +46,7 @@
if (!ctx->mcp)
return false;
- if (!ctx->mcp->flags.sleep_mode.ReadyToSleep & READY_TO_SLEEP)
+ if (!(ctx->mcp->flags.sleep_mode.ready_to_sleep & READY_TO_SLEEP))
return false;
return true;
@@ -57,7 +57,7 @@
if (!ctx->mcp)
return;
- ctx->mcp->flags.sleep_mode.SleepReq = REQ_TO_SLEEP;
+ ctx->mcp->flags.sleep_mode.sleep_req = REQ_TO_SLEEP;
_nsiq();
}
DECLARE_WORK(suspend_work, mc_suspend_handler);
@@ -66,9 +66,9 @@
{
MCDRV_DBG(mcd, "MobiCore IDLE=%d!", flags->schedule);
MCDRV_DBG(mcd,
- "MobiCore Request Sleep=%d!", flags->sleep_mode.SleepReq);
+ "MobiCore Request Sleep=%d!", flags->sleep_mode.sleep_req);
MCDRV_DBG(mcd,
- "MobiCore Sleep Ready=%d!", flags->sleep_mode.ReadyToSleep);
+ "MobiCore Sleep Ready=%d!", flags->sleep_mode.ready_to_sleep);
}
static int mc_suspend_notifier(struct notifier_block *nb,
@@ -96,12 +96,12 @@
*/
dump_sleep_params(&mcp->flags);
if (!sleep_ready()) {
- ctx->mcp->flags.sleep_mode.SleepReq = REQ_TO_SLEEP;
+ ctx->mcp->flags.sleep_mode.sleep_req = REQ_TO_SLEEP;
schedule_work_on(0, &suspend_work);
flush_work(&suspend_work);
if (!sleep_ready()) {
dump_sleep_params(&mcp->flags);
- ctx->mcp->flags.sleep_mode.SleepReq = 0;
+ ctx->mcp->flags.sleep_mode.sleep_req = 0;
MCDRV_DBG_ERROR(mcd, "MobiCore can't SLEEP!");
return NOTIFY_BAD;
}
@@ -109,7 +109,7 @@
break;
case PM_POST_SUSPEND:
MCDRV_DBG(mcd, "Resume MobiCore system!");
- ctx->mcp->flags.sleep_mode.SleepReq = 0;
+ ctx->mcp->flags.sleep_mode.sleep_req = 0;
break;
default:
break;
@@ -121,57 +121,6 @@
.notifier_call = mc_suspend_notifier,
};
-#ifdef MC_BL_NOTIFIER
-
-static int bL_switcher_notifier_handler(struct notifier_block *this,
- unsigned long event, void *ptr)
-{
- unsigned int mpidr, cpu, cluster;
- struct mc_mcp_buffer *mcp = ctx->mcp;
-
- if (!mcp)
- return 0;
-
- asm volatile ("mrc\tp15, 0, %0, c0, c0, 5" : "=r" (mpidr));
- cpu = mpidr & 0x3;
- cluster = (mpidr >> 8) & 0xf;
- MCDRV_DBG(mcd, "%s switching!!, cpu: %u, Out=%u\n",
- (event == SWITCH_ENTER ? "Before" : "After"), cpu, cluster);
-
- if (cpu != 0)
- return 0;
-
- switch (event) {
- case SWITCH_ENTER:
- if (!sleep_ready()) {
- ctx->mcp->flags.sleep_mode.SleepReq = REQ_TO_SLEEP;
- _nsiq();
- /* By this time we should be ready for sleep or we are
- * in the middle of something important */
- if (!sleep_ready()) {
- dump_sleep_params(&mcp->flags);
- MCDRV_DBG(mcd,
- "MobiCore: Don't allow switch!\n");
- ctx->mcp->flags.sleep_mode.SleepReq = 0;
- return -EPERM;
- }
- }
- break;
- case SWITCH_EXIT:
- ctx->mcp->flags.sleep_mode.SleepReq = 0;
- break;
- default:
- MCDRV_DBG(mcd, "MobiCore: Unknown switch event!\n");
- }
-
- return 0;
-}
-
-static struct notifier_block switcher_nb = {
- .notifier_call = bL_switcher_notifier_handler,
-};
-#endif
-
int mc_pm_initialize(struct mc_context *context)
{
int ret = 0;
@@ -180,12 +129,7 @@
ret = register_pm_notifier(&mc_notif_block);
if (ret)
- MCDRV_DBG_ERROR(mcd, "device pm register failed\n");
-#ifdef MC_BL_NOTIFIER
- if (register_bL_swicher_notifier(&switcher_nb))
- MCDRV_DBG_ERROR(mcd,
- "Failed to register to bL_switcher_notifier\n");
-#endif
+ MCDRV_DBG_ERROR(mcd, "device pm register failed");
return ret;
}
@@ -194,15 +138,16 @@
{
int ret = unregister_pm_notifier(&mc_notif_block);
if (ret)
- MCDRV_DBG_ERROR(mcd, "device pm unregister failed\n");
-#ifdef MC_BL_NOTIFIER
- ret = unregister_bL_swicher_notifier(&switcher_nb);
- if (ret)
- MCDRV_DBG_ERROR(mcd, "device bl unregister failed\n");
-#endif
+ MCDRV_DBG_ERROR(mcd, "device pm unregister failed");
return ret;
}
+bool mc_pm_sleep_ready(void)
+{
+ if (ctx == 0)
+ return true;
+ return sleep_ready();
+}
#endif /* MC_PM_RUNTIME */
#ifdef MC_CRYPTO_CLOCK_MANAGEMENT
@@ -215,7 +160,7 @@
mc_ce_core_clk = clk_get(mcd, "core_clk");
if (IS_ERR(mc_ce_core_clk)) {
ret = PTR_ERR(mc_ce_core_clk);
- MCDRV_DBG_ERROR(mcd, "cannot get core clock\n");
+ MCDRV_DBG_ERROR(mcd, "cannot get core clock");
goto error;
}
/* Get Interface clk */
@@ -223,7 +168,7 @@
if (IS_ERR(mc_ce_iface_clk)) {
clk_put(mc_ce_core_clk);
ret = PTR_ERR(mc_ce_iface_clk);
- MCDRV_DBG_ERROR(mcd, "cannot get iface clock\n");
+ MCDRV_DBG_ERROR(mcd, "cannot get iface clock");
goto error;
}
/* Get AXI clk */
@@ -232,7 +177,7 @@
clk_put(mc_ce_iface_clk);
clk_put(mc_ce_core_clk);
ret = PTR_ERR(mc_ce_bus_clk);
- MCDRV_DBG_ERROR(mcd, "cannot get AXI bus clock\n");
+ MCDRV_DBG_ERROR(mcd, "cannot get AXI bus clock");
goto error;
}
return ret;
@@ -263,17 +208,17 @@
rc = clk_prepare_enable(mc_ce_core_clk);
if (rc) {
- MCDRV_DBG_ERROR(mcd, "cannot enable clock\n");
+ MCDRV_DBG_ERROR(mcd, "cannot enable clock");
} else {
rc = clk_prepare_enable(mc_ce_iface_clk);
if (rc) {
clk_disable_unprepare(mc_ce_core_clk);
- MCDRV_DBG_ERROR(mcd, "cannot enable clock\n");
+ MCDRV_DBG_ERROR(mcd, "cannot enable clock");
} else {
rc = clk_prepare_enable(mc_ce_bus_clk);
if (rc) {
clk_disable_unprepare(mc_ce_iface_clk);
- MCDRV_DBG_ERROR(mcd, "cannot enable clock\n");
+ MCDRV_DBG_ERROR(mcd, "cannot enable clock");
}
}
}
diff --git a/drivers/gud/mobicore_driver/pm.h b/drivers/gud/MobiCoreDriver/pm.h
similarity index 94%
rename from drivers/gud/mobicore_driver/pm.h
rename to drivers/gud/MobiCoreDriver/pm.h
index 332da34..b71c603 100644
--- a/drivers/gud/mobicore_driver/pm.h
+++ b/drivers/gud/MobiCoreDriver/pm.h
@@ -13,10 +13,6 @@
#define _MC_PM_H_
#include "main.h"
-#ifdef MC_BL_NOTIFIER
-#include <asm/bL_switcher.h>
-#endif
-
#define NO_SLEEP_REQ 0
#define REQ_TO_SLEEP 1
@@ -39,5 +35,7 @@
int mc_pm_clock_enable(void);
/* Disable secure crypto clocks */
void mc_pm_clock_disable(void);
+/* Test if sleep is possible */
+bool mc_pm_sleep_ready(void);
#endif /* _MC_PM_H_ */
diff --git a/drivers/gud/mobicore_driver/public/mc_kernel_api.h b/drivers/gud/MobiCoreDriver/public/mc_kernel_api.h
similarity index 89%
rename from drivers/gud/mobicore_driver/public/mc_kernel_api.h
rename to drivers/gud/MobiCoreDriver/public/mc_kernel_api.h
index cca0636..15fd4a2 100644
--- a/drivers/gud/mobicore_driver/public/mc_kernel_api.h
+++ b/drivers/gud/MobiCoreDriver/public/mc_kernel_api.h
@@ -35,13 +35,12 @@
* @requested_size: memory size requested in bytes
* @handle: pointer to handle
* @kernel_virt_addr: virtual user start address
- * @phys_addr: physical start address
*
* Returns 0 if OK
*/
int mobicore_allocate_wsm(struct mc_instance *instance,
unsigned long requested_size, uint32_t *handle,
- void **virt_kernel_addr, void **phys_addr);
+ void **virt_kernel_addr);
/*
* mobicore_free() - Free a WSM buffer allocated with mobicore_allocate_wsm
@@ -58,12 +57,11 @@
* @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
*
* Returns 0 if no error
*/
int mobicore_map_vmem(struct mc_instance *instance, void *addr,
- uint32_t len, uint32_t *handle, uint32_t *phys);
+ uint32_t len, uint32_t *handle);
/*
* mobicore_unmap_vmem() - Unmap a virtual memory buffer from MobiCore
@@ -74,4 +72,12 @@
*/
int mobicore_unmap_vmem(struct mc_instance *instance, uint32_t handle);
+/*
+ * mobicore_sleep_ready() - Test if mobicore can sleep
+ *
+ * Returns true if mobicore can sleep, false if it can't sleep
+ */
+bool mobicore_sleep_ready(void);
+
+
#endif /* _MC_KERNEL_API_H_ */
diff --git a/drivers/gud/mobicore_driver/public/mc_linux.h b/drivers/gud/MobiCoreDriver/public/mc_linux.h
similarity index 81%
rename from drivers/gud/mobicore_driver/public/mc_linux.h
rename to drivers/gud/MobiCoreDriver/public/mc_linux.h
index af027dc..98e7af1 100644
--- a/drivers/gud/mobicore_driver/public/mc_linux.h
+++ b/drivers/gud/MobiCoreDriver/public/mc_linux.h
@@ -1,7 +1,7 @@
/*
* 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
+ * services like memory allocation via mmap and generation of a MMU 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",
@@ -55,8 +55,6 @@
* 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] */
@@ -76,8 +74,7 @@
};
/*
- * Data exchange structure of the MC_IO_MAP_WSM, MC_IO_MAP_MCI, and
- * MC_IO_MAP_PWSM commands.
+ * Data exchange structure of the MC_IO_MAP_WSM and MC_IO_MAP_MCI commands.
*
* Allocate a contiguous memory buffer for a process.
* The physical address can be used as for later calls to mmap.
@@ -86,19 +83,19 @@
* 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 */
+ size_t len; /* Buffer length */
+ uint32_t handle; /* WSM handle */
+ uint64_t phys_addr; /* physical address of WSM (or 0) */
+ unsigned long addr; /* Virtual address */
+ 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
+ * Allocates a physical MMU table and maps the buffer into this page.
+ * Returns the physical address of the MMU table.
+ * The page alignment will be created and the appropriated pSize and pOffsetMMU
* will be modified to the used values.
*/
struct mc_ioctl_reg_wsm {
@@ -106,19 +103,7 @@
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;
+ uint64_t table_phys; /* physical address of the MMU table */
};
/*
@@ -127,10 +112,10 @@
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;
+ /* base address of memory */
+ uint64_t phys;
/* fd to owner of the buffer */
int32_t fd;
};
@@ -144,7 +129,7 @@
/* fd to owner of the buffer */
int32_t fd;
/* base address of memory */
- uint32_t phys;
+ uint64_t phys;
};
@@ -180,28 +165,24 @@
*/
#define MC_IO_FREE _IO(MC_IOC_MAGIC, 5)
/*
- * Creates a L2 Table of the given base address and the size of the
+ * Creates a MMU Table of the given base address and the size of the
* data.
- * Parameter: mc_ioctl_app_reg_wsm_l2_params
+ * Parameter: mc_ioctl_reg_wsm
*/
#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
+ * MC_IO_MAP_WSM usual operation, pages are registered in
* device structure and freed later.
- * MC_DRV_KMOD_MMAP_MCI get Instance of MCI, allocates or mmaps
+ * MC_IO_MAP_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
@@ -215,7 +196,7 @@
#define MC_IO_CLEAN_WSM _IO(MC_IOC_MAGIC, 14)
/*
- * Get L2 phys address of a buffer handle allocated to the user.
+ * Get MMU 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, \
diff --git a/drivers/gud/mobicore_driver/public/version.h b/drivers/gud/MobiCoreDriver/public/version.h
similarity index 100%
rename from drivers/gud/mobicore_driver/public/version.h
rename to drivers/gud/MobiCoreDriver/public/version.h
diff --git a/drivers/gud/MobiCoreKernelApi/Makefile b/drivers/gud/MobiCoreKernelApi/Makefile
new file mode 100644
index 0000000..9b37eea
--- /dev/null
+++ b/drivers/gud/MobiCoreKernelApi/Makefile
@@ -0,0 +1,52 @@
+#
+# this makefile is called from the kernel make syste
+ifeq ($(MODE),release)
+ ccflags-y += -O2 -DNDEBUG
+else # DEBUG
+ # "-O" is needed to expand inlines
+ ccflags-y += -O -g3 -DDEBUG
+endif # DEBUG/RELEASE
+
+ifdef MOBICORE_CFLAGS
+ ccflags-y +=$(MOBICORE_CFLAGS)
+endif
+
+#Set the extra symbols
+ifdef MCDRV_SYMBOLS_FILE
+ KBUILD_EXTRA_SYMBOLS=$(MCDRV_SYMBOLS_FILE)
+endif
+
+ifeq ($(PLATFORM), ARM_VE_A9X4_QEMU)
+ ccflags-y += -DMC_NETLINK_COMPAT_V37
+endif
+
+ifeq ($(PLATFORM), MSM8974_SURF_STD)
+ ccflags-y += -DMC_NETLINK_COMPAT_V37
+endif
+
+ifeq ($(PLATFORM), EXYNOS_5422_STD)
+ ccflags-y += -DMC_NETLINK_COMPAT_V37
+endif
+
+ifeq ($(PLATFORM), EXYNOS_5430_STD)
+ ccflags-y += -DMC_NETLINK_COMPAT_V37
+endif
+
+#EXTRA_CFLAGS += -DDEBUG -DDEBUG_VERBOSE
+#EXTRA_CFLAGS += -Wno-declaration-after-statement
+ccflags-y += -Wno-declaration-after-statement
+# add our module to kernel.
+obj-m += mcKernelApi.o
+
+mcKernelApi-objs := main.o clientlib.o device.o session.o connection.o
+
+clean:
+ rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions \
+ Module.markers Module.symvers modules.order
+
+depend .depend dep:
+ $(CC) $(CFLAGS) -M *.c > .depend
+
+ifeq (.depend,$(wildcard .depend))
+ include .depend
+endif
diff --git a/drivers/gud/MobiCoreKernelApi/build.sh b/drivers/gud/MobiCoreKernelApi/build.sh
new file mode 100644
index 0000000..86fe1b8
--- /dev/null
+++ b/drivers/gud/MobiCoreKernelApi/build.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+
+if [ -z $COMP_PATH_ROOT ]; then
+ echo "The build environment is not set!"
+ echo "Trying to source setupDrivers.sh automatically!"
+ source ../setupDrivers.sh || exit 1
+fi
+
+ROOT_PATH=$(dirname $(readlink -f $BASH_SOURCE))
+# These folders need to be relative to the kernel dir or absolute!
+PLATFORM=EXYNOS_4X12_STD
+CODE_INCLUDE=$(readlink -f $ROOT_PATH/Locals/Code)
+
+MOBICORE_DRIVER=$COMP_PATH_MobiCoreDriverMod
+MOBICORE_DAEMON=$COMP_PATH_MobiCoreDriverLib/Public
+MOBICORE_CFLAGS="-I$MOBICORE_DRIVER/Public -I$MOBICORE_DAEMON -I$COMP_PATH_MobiCore/inc/Mci -I$COMP_PATH_MobiCore/inc -I$CODE_INCLUDE/include -I$CODE_INCLUDE/public"
+MCDRV_SYMBOLS_FILE="$COMP_PATH_ROOT/MobiCoreDriverMod/Locals/Code/Module.symvers"
+
+if [ ! -f $MCDRV_SYMBOLS_FILE ]; then
+ echo "Please build the Mobicore Driver Module first!"
+ echo "Otherwise you will see warnings of missing symbols"
+fi
+
+# Clean first
+make -C $CODE_INCLUDE clean
+
+make -C $LINUX_PATH \
+ MODE=$MODE \
+ ARCH=arm \
+ CROSS_COMPILE=$CROSS_COMPILE \
+ M=$CODE_INCLUDE \
+ "MOBICORE_CFLAGS=$MOBICORE_CFLAGS" \
+ MCDRV_SYMBOLS_FILE=$MCDRV_SYMBOLS_FILE \
+ modules
diff --git a/drivers/gud/mobicore_kernelapi/clientlib.c b/drivers/gud/MobiCoreKernelApi/clientlib.c
similarity index 95%
rename from drivers/gud/mobicore_kernelapi/clientlib.c
rename to drivers/gud/MobiCoreKernelApi/clientlib.c
index 16b52e5..65b4a1c 100644
--- a/drivers/gud/mobicore_kernelapi/clientlib.c
+++ b/drivers/gud/MobiCoreKernelApi/clientlib.c
@@ -25,6 +25,7 @@
/* device list */
LIST_HEAD(devices);
+atomic_t device_usage = ATOMIC_INIT(0);
static struct mcore_device_t *resolve_device_id(uint32_t device_id)
{
@@ -71,14 +72,20 @@
do {
struct mcore_device_t *device = resolve_device_id(device_id);
if (device != NULL) {
- MCDRV_DBG_ERROR(mc_kapi,
- "Device %d already opened", device_id);
- mc_result = MC_DRV_ERR_INVALID_OPERATION;
+ MCDRV_DBG(mc_kapi,
+ "Device %d already opened\n", device_id);
+ atomic_inc(&device_usage);
+ mc_result = MC_DRV_OK;
break;
}
/* Open new connection to device */
dev_con = connection_new();
+ if (dev_con == NULL) {
+ mc_result = MC_DRV_ERR_NO_FREE_MEMORY;
+ break;
+ }
+
if (!connection_connect(dev_con, MC_DAEMON_PID)) {
MCDRV_DBG_ERROR(
mc_kapi,
@@ -144,6 +151,10 @@
/* there is no payload to read */
device = mcore_device_create(device_id, dev_con);
+ if (device == NULL) {
+ mc_result = MC_DRV_ERR_NO_FREE_MEMORY;
+ break;
+ }
if (!mcore_device_open(device, MC_DRV_MOD_DEVNODE_FULLPATH)) {
mcore_device_cleanup(device);
MCDRV_DBG_ERROR(mc_kapi,
@@ -154,6 +165,7 @@
}
add_device(device);
+ atomic_inc(&device_usage);
} while (false);
@@ -177,6 +189,12 @@
mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
break;
}
+ /* Check if it's not used by other modules */
+ if (!atomic_dec_and_test(&device_usage)) {
+ mc_result = MC_DRV_OK;
+ break;
+ }
+
struct connection *dev_con = device->connection;
/* Return if not all sessions have been closed */
@@ -274,12 +292,12 @@
}
struct connection *dev_con = device->connection;
- /* Get the physical address of the given TCI */
+ /* Get the wsm of the given TCI */
struct wsm *wsm =
mcore_device_find_contiguous_wsm(device, tci);
if (wsm == NULL) {
MCDRV_DBG_ERROR(mc_kapi,
- "Could not resolve TCI phy address ");
+ "Could not resolve TCI address ");
mc_result = MC_DRV_ERR_INVALID_PARAMETER;
break;
}
@@ -292,14 +310,14 @@
}
/* Prepare open session command */
- struct mc_drv_cmd_open_session_t cmdOpenSession = {
+ struct mc_drv_cmd_open_session_t cmd_open_session = {
{
MC_DRV_CMD_OPEN_SESSION
},
{
session->device_id,
*uuid,
- (uint32_t)(wsm->phys_addr) & 0xFFF,
+ (uint32_t)(wsm->virt_addr) & 0xFFF,
wsm->handle,
len
}
@@ -307,9 +325,9 @@
/* Transmit command data */
int len = connection_write_data(dev_con,
- &cmdOpenSession,
- sizeof(cmdOpenSession));
- if (len != sizeof(cmdOpenSession)) {
+ &cmd_open_session,
+ sizeof(cmd_open_session));
+ if (len != sizeof(cmd_open_session)) {
MCDRV_DBG_ERROR(mc_kapi,
"CMD_OPEN_SESSION writeData failed %d",
len);
@@ -370,6 +388,10 @@
/* Set up second channel for notifications */
struct connection *session_connection = connection_new();
+ if (session_connection == NULL) {
+ mc_result = MC_DRV_ERR_NO_FREE_MEMORY;
+ break;
+ }
if (!connection_connect(session_connection, MC_DAEMON_PID)) {
MCDRV_DBG_ERROR(
@@ -422,9 +444,13 @@
/* there is no payload. */
/* Session established, new session object must be created */
- mcore_device_create_new_session(device,
- session->session_id,
- session_connection);
+ if (!mcore_device_create_new_session(device,
+ session->session_id,
+ session_connection)) {
+ connection_cleanup(session_connection);
+ mc_result = MC_DRV_ERR_NO_FREE_MEMORY;
+ break;
+ }
} while (false);
@@ -706,7 +732,6 @@
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) {
@@ -805,7 +830,7 @@
{
session->session_id,
bulk_buf->handle,
- (uint32_t)bulk_buf->phys_addr_wsm_l2,
+ 0,
(uint32_t)(bulk_buf->virt_addr) & 0xFFF,
bulk_buf->len
}
@@ -819,8 +844,8 @@
/* Read command response */
struct mc_drv_response_header_t rsp_header;
int len = connection_read_datablock(dev_con,
- &rsp_header,
- sizeof(rsp_header));
+ &rsp_header,
+ sizeof(rsp_header));
if (len != sizeof(rsp_header)) {
MCDRV_DBG_ERROR(mc_kapi,
"CMD_MAP_BULK_BUF readRsp failed %d",
diff --git a/drivers/gud/mobicore_kernelapi/common.h b/drivers/gud/MobiCoreKernelApi/common.h
similarity index 100%
rename from drivers/gud/mobicore_kernelapi/common.h
rename to drivers/gud/MobiCoreKernelApi/common.h
diff --git a/drivers/gud/mobicore_kernelapi/connection.c b/drivers/gud/MobiCoreKernelApi/connection.c
similarity index 96%
rename from drivers/gud/mobicore_kernelapi/connection.c
rename to drivers/gud/MobiCoreKernelApi/connection.c
index 03288a0..0372b82 100644
--- a/drivers/gud/mobicore_kernelapi/connection.c
+++ b/drivers/gud/MobiCoreKernelApi/connection.c
@@ -28,6 +28,10 @@
struct connection *conn;
conn = kzalloc(sizeof(*conn), GFP_KERNEL);
+ if (conn == NULL) {
+ MCDRV_DBG_ERROR(mc_kapi, "Allocation failure");
+ return NULL;
+ }
conn->sequence_magic = mcapi_unique_id();
mutex_init(&conn->data_lock);
sema_init(&conn->data_available_sem, SEM_NO_DATA_AVAILABLE);
@@ -36,14 +40,6 @@
return conn;
}
-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)
{
if (!conn)
diff --git a/drivers/gud/mobicore_kernelapi/connection.h b/drivers/gud/MobiCoreKernelApi/connection.h
similarity index 95%
rename from drivers/gud/mobicore_kernelapi/connection.h
rename to drivers/gud/MobiCoreKernelApi/connection.h
index 6c3ff00..57e783b 100644
--- a/drivers/gud/mobicore_kernelapi/connection.h
+++ b/drivers/gud/MobiCoreKernelApi/connection.h
@@ -44,7 +44,6 @@
};
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,
diff --git a/drivers/gud/mobicore_kernelapi/device.c b/drivers/gud/MobiCoreKernelApi/device.c
similarity index 85%
rename from drivers/gud/mobicore_kernelapi/device.c
rename to drivers/gud/MobiCoreKernelApi/device.c
index a176322..04db4c3 100644
--- a/drivers/gud/mobicore_kernelapi/device.c
+++ b/drivers/gud/MobiCoreKernelApi/device.c
@@ -18,16 +18,18 @@
#include "device.h"
#include "common.h"
-struct wsm *wsm_create(void *virt_addr, uint32_t len, uint32_t handle,
- void *phys_addr)
+static struct wsm *wsm_create(void *virt_addr, uint32_t len, uint32_t handle)
{
struct wsm *wsm;
wsm = kzalloc(sizeof(*wsm), GFP_KERNEL);
+ if (wsm == NULL) {
+ MCDRV_DBG_ERROR(mc_kapi, "Allocation failure");
+ return NULL;
+ }
wsm->virt_addr = virt_addr;
wsm->len = len;
wsm->handle = handle;
- wsm->phys_addr = phys_addr;
return wsm;
}
@@ -37,11 +39,15 @@
struct mcore_device_t *dev;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL) {
+ MCDRV_DBG_ERROR(mc_kapi, "Allocation failure");
+ return NULL;
+ }
dev->device_id = device_id;
dev->connection = connection;
INIT_LIST_HEAD(&dev->session_vector);
- INIT_LIST_HEAD(&dev->wsm_l2_vector);
+ INIT_LIST_HEAD(&dev->wsm_mmu_vector);
return dev;
}
@@ -63,7 +69,7 @@
}
/* Free all allocated WSM descriptors */
- list_for_each_safe(pos, q, &dev->wsm_l2_vector) {
+ list_for_each_safe(pos, q, &dev->wsm_mmu_vector) {
wsm = list_entry(pos, struct wsm, list);
list_del(pos);
kfree(wsm);
@@ -74,7 +80,7 @@
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 *device_name)
{
dev->instance = mobicore_open();
return (dev->instance != NULL);
@@ -102,6 +108,8 @@
}
struct session *session =
session_create(session_id, dev->instance, connection);
+ if (session == NULL)
+ return false;
list_add_tail(&(session->list), &(dev->session_vector));
return true;
}
@@ -154,16 +162,19 @@
/* 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);
+ &virt_addr);
if (ret != 0)
break;
- /* Register (vaddr,paddr) with device */
- wsm = wsm_create(virt_addr, len, handle, phys_addr);
+ /* Register (vaddr) with device */
+ wsm = wsm_create(virt_addr, len, handle);
+ if (wsm == NULL) {
+ mobicore_free_wsm(dev->instance, handle);
+ break;
+ }
- list_add_tail(&(wsm->list), &(dev->wsm_l2_vector));
+ list_add_tail(&(wsm->list), &(dev->wsm_mmu_vector));
} while (0);
@@ -177,7 +188,7 @@
struct wsm *tmp;
struct list_head *pos;
- list_for_each(pos, &dev->wsm_l2_vector) {
+ list_for_each(pos, &dev->wsm_mmu_vector) {
tmp = list_entry(pos, struct wsm, list);
if (tmp == wsm) {
ret = true;
@@ -205,7 +216,7 @@
struct wsm *wsm;
struct list_head *pos;
- list_for_each(pos, &dev->wsm_l2_vector) {
+ list_for_each(pos, &dev->wsm_mmu_vector) {
wsm = list_entry(pos, struct wsm, list);
if (virt_addr == wsm->virt_addr)
return wsm;
diff --git a/drivers/gud/mobicore_kernelapi/device.h b/drivers/gud/MobiCoreKernelApi/device.h
similarity index 95%
rename from drivers/gud/mobicore_kernelapi/device.h
rename to drivers/gud/MobiCoreKernelApi/device.h
index 16626bd..c795ee8 100644
--- a/drivers/gud/mobicore_kernelapi/device.h
+++ b/drivers/gud/MobiCoreKernelApi/device.h
@@ -21,7 +21,7 @@
struct mcore_device_t {
/* MobiCore Trustlet session associated with the device */
struct list_head session_vector;
- struct list_head wsm_l2_vector; /* WSM L2 Table */
+ struct list_head wsm_mmu_vector; /* WSM L2 or L3 Table */
uint32_t device_id; /* Device identifier */
struct connection *connection; /* The device connection */
@@ -36,7 +36,7 @@
void mcore_device_cleanup(struct mcore_device_t *dev);
-bool mcore_device_open(struct mcore_device_t *dev, const char *deviceName);
+bool mcore_device_open(struct mcore_device_t *dev, const char *device_name);
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(
diff --git a/drivers/gud/mobicore_kernelapi/include/mcinq.h b/drivers/gud/MobiCoreKernelApi/include/mcinq.h
similarity index 100%
rename from drivers/gud/mobicore_kernelapi/include/mcinq.h
rename to drivers/gud/MobiCoreKernelApi/include/mcinq.h
diff --git a/drivers/gud/mobicore_kernelapi/include/mcuuid.h b/drivers/gud/MobiCoreKernelApi/include/mcuuid.h
similarity index 100%
rename from drivers/gud/mobicore_kernelapi/include/mcuuid.h
rename to drivers/gud/MobiCoreKernelApi/include/mcuuid.h
diff --git a/drivers/gud/mobicore_kernelapi/main.c b/drivers/gud/MobiCoreKernelApi/main.c
similarity index 97%
rename from drivers/gud/mobicore_kernelapi/main.c
rename to drivers/gud/MobiCoreKernelApi/main.c
index 8943c26..5da3ef7 100644
--- a/drivers/gud/mobicore_kernelapi/main.c
+++ b/drivers/gud/MobiCoreKernelApi/main.c
@@ -150,6 +150,10 @@
dev_info(mc_kapi, "Mobicore API module initialized!\n");
mod_ctx = kzalloc(sizeof(struct mc_kernelapi_ctx), GFP_KERNEL);
+ if (mod_ctx == NULL) {
+ MCDRV_DBG_ERROR(mc_kapi, "Allocation failure");
+ return -ENOMEM;
+ }
#ifdef MC_NETLINK_COMPAT_V37
mod_ctx->sk = netlink_kernel_create(&init_net, MC_DAEMON_NETLINK,
&cfg);
diff --git a/drivers/gud/mobicore_kernelapi/public/mobicore_driver_api.h b/drivers/gud/MobiCoreKernelApi/public/mobicore_driver_api.h
similarity index 100%
rename from drivers/gud/mobicore_kernelapi/public/mobicore_driver_api.h
rename to drivers/gud/MobiCoreKernelApi/public/mobicore_driver_api.h
diff --git a/drivers/gud/mobicore_kernelapi/public/mobicore_driver_cmd.h b/drivers/gud/MobiCoreKernelApi/public/mobicore_driver_cmd.h
similarity index 99%
rename from drivers/gud/mobicore_kernelapi/public/mobicore_driver_cmd.h
rename to drivers/gud/MobiCoreKernelApi/public/mobicore_driver_cmd.h
index eaf7e6c..993d581 100644
--- a/drivers/gud/mobicore_kernelapi/public/mobicore_driver_cmd.h
+++ b/drivers/gud/MobiCoreKernelApi/public/mobicore_driver_cmd.h
@@ -171,7 +171,7 @@
struct mc_drv_cmd_map_bulk_mem_payload_t {
uint32_t session_id;
uint32_t handle;
- uint32_t phys_addr_l2;
+ uint32_t rfu;
uint32_t offset_payload;
uint32_t len_bulk_mem;
};
diff --git a/drivers/gud/mobicore_kernelapi/session.c b/drivers/gud/MobiCoreKernelApi/session.c
similarity index 86%
rename from drivers/gud/mobicore_kernelapi/session.c
rename to drivers/gud/MobiCoreKernelApi/session.c
index dae2c00..2ea50e8 100644
--- a/drivers/gud/mobicore_kernelapi/session.c
+++ b/drivers/gud/MobiCoreKernelApi/session.c
@@ -14,15 +14,18 @@
#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)
+ void *virt_addr, uint32_t len, uint32_t handle)
{
struct bulk_buffer_descriptor *desc;
desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+ if (desc == NULL) {
+ MCDRV_DBG_ERROR(mc_kapi, "Allocation failure");
+ return NULL;
+ }
desc->virt_addr = virt_addr;
desc->len = len;
desc->handle = handle;
- desc->phys_addr_wsm_l2 = phys_addr_wsm_l2;
return desc;
}
@@ -33,6 +36,10 @@
struct session *session;
session = kzalloc(sizeof(*session), GFP_KERNEL);
+ if (session == NULL) {
+ MCDRV_DBG_ERROR(mc_kapi, "Allocation failure");
+ return NULL;
+ }
session->session_id = session_id;
session->instance = instance;
session->notification_connection = connection;
@@ -47,19 +54,14 @@
{
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);
- 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,
+ "handle= %d",
bulk_buf_descr->handle);
/* ignore any error, as we cannot do anything in this case. */
@@ -110,11 +112,10 @@
* 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);
+ &handle);
if (ret != 0) {
MCDRV_DBG_ERROR(mc_kapi,
@@ -123,15 +124,15 @@
break;
}
- MCDRV_DBG_VERBOSE(mc_kapi,
- "Phys Addr of L2 Table = 0x%X, handle=%d",
- (unsigned int)l2_table_phys, handle);
+ MCDRV_DBG_VERBOSE(mc_kapi, "handle=%d", handle);
/* Create new descriptor */
bulk_buf_descr =
- bulk_buffer_descriptor_create(buf, len,
- handle,
- (void *)l2_table_phys);
+ bulk_buffer_descriptor_create(buf, len, handle);
+ if (bulk_buf_descr == NULL) {
+ mobicore_unmap_vmem(session->instance, handle);
+ break;
+ }
/* Add to vector of descriptors */
list_add_tail(&(bulk_buf_descr->list),
@@ -165,8 +166,7 @@
MCDRV_DBG_ERROR(mc_kapi, "Virtual Address not found");
ret = false;
} else {
- MCDRV_DBG_VERBOSE(mc_kapi, "WsmL2 phys=0x%X, handle=%d",
- (unsigned int)bulk_buf->phys_addr_wsm_l2,
+ MCDRV_DBG_VERBOSE(mc_kapi, "Wsm handle=%d",
bulk_buf->handle);
/* ignore any error, as we cannot do anything */
diff --git a/drivers/gud/mobicore_kernelapi/session.h b/drivers/gud/MobiCoreKernelApi/session.h
similarity index 96%
rename from drivers/gud/mobicore_kernelapi/session.h
rename to drivers/gud/MobiCoreKernelApi/session.h
index 4a834e5..edcadcd 100644
--- a/drivers/gud/mobicore_kernelapi/session.h
+++ b/drivers/gud/MobiCoreKernelApi/session.h
@@ -19,9 +19,6 @@
uint32_t len; /* Length of the Bulk buffer */
uint32_t handle;
- /* 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;
};
@@ -29,8 +26,7 @@
struct bulk_buffer_descriptor *bulk_buffer_descriptor_create(
void *virt_addr,
uint32_t len,
- uint32_t handle,
- void *phys_addr_wsm_l2
+ uint32_t handle
);
/*
diff --git a/drivers/gud/mobicore_kernelapi/wsm.h b/drivers/gud/MobiCoreKernelApi/wsm.h
similarity index 74%
rename from drivers/gud/mobicore_kernelapi/wsm.h
rename to drivers/gud/MobiCoreKernelApi/wsm.h
index f8a107c..3a1767d 100644
--- a/drivers/gud/mobicore_kernelapi/wsm.h
+++ b/drivers/gud/MobiCoreKernelApi/wsm.h
@@ -17,17 +17,7 @@
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,
-
- /* NULL this may be unknown, so is can be omitted */
- void *phys_addr
-);
-
#endif /* _MC_KAPI_WSM_H_ */
diff --git a/drivers/gud/mobicore_driver/build_tag.h b/drivers/gud/build_tag.h
similarity index 96%
rename from drivers/gud/mobicore_driver/build_tag.h
rename to drivers/gud/build_tag.h
index 4a24275..18faf5a 100644
--- a/drivers/gud/mobicore_driver/build_tag.h
+++ b/drivers/gud/build_tag.h
@@ -26,4 +26,4 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define MOBICORE_COMPONENT_BUILD_TAG \
- "*** t-base-202_V001 ###"
+ "*** t-base-300-QC-8974-Android-V001 ###"
diff --git a/drivers/gud/mobicore_driver/mem.c b/drivers/gud/mobicore_driver/mem.c
deleted file mode 100644
index 33c51b6..0000000
--- a/drivers/gud/mobicore_driver/mem.c
+++ /dev/null
@@ -1,708 +0,0 @@
-/*
- * 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 -->
- * <-- Copyright Trustonic Limited 2013 -->
- *
- * 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);
-
-
- /* 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(cont buffer) */
- else if (task == NULL && !is_vmalloc_addr(wsm_buffer)) {
- void *uaddr = wsm_buffer;
- for (i = 0; i < nr_of_pages; i++) {
- page = virt_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;
- }
- }
- /* 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(uint32_t handle, int32_t fd)
-{
- uint32_t ret = 0;
- struct mc_l2_table *table = NULL;
-
- 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;
- }
-
- /* It's safe here not to lock the instance since the owner of
- * the table will be cleared only with the table lock taken */
- if (!mc_check_owner_fd(table->owner, fd)) {
- MCDRV_DBG_ERROR(mcd, "not valid owner%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
deleted file mode 100644
index 397a6cc..0000000
--- a/drivers/gud/mobicore_driver/mem.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * MobiCore driver module.(interface to the secure world SWD)
- *
- * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
- * <-- Copyright Trustonic Limited 2013 -->
- *
- * 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(uint32_t handle, int32_t fd);
-/* 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
deleted file mode 100644
index 9d4af72..0000000
--- a/drivers/gud/mobicore_driver/ops.c
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- * 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 -->
- * <-- Copyright Trustonic Limited 2013 -->
- *
- * 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 <linux/workqueue.h>
-#include <linux/cpu.h>
-
-#include "main.h"
-#include "fastcall.h"
-#include "ops.h"
-#include "mem.h"
-#include "pm.h"
-#include "debug.h"
-
-/* MobiCore context data */
-static struct mc_context *ctx;
-
-static inline long smc(union fc_generic *fc)
-{
- /* If we request sleep yields must be filtered out as they
- * make no sense */
- if (ctx->mcp)
- if (ctx->mcp->flags.sleep_mode.SleepReq) {
- if (fc->as_in.cmd == MC_SMC_N_YIELD)
- return MC_FC_RET_ERR_INVALID;
- }
- return _smc(fc);
-}
-
-#ifdef MC_FASTCALL_WORKER_THREAD
-
-static struct task_struct *fastcall_thread;
-static DEFINE_KTHREAD_WORKER(fastcall_worker);
-
-struct fastcall_work {
- struct kthread_work work;
- void *data;
-};
-
-static void fastcall_work_func(struct kthread_work *work)
-{
- struct fastcall_work *fc_work =
- container_of(work, struct fastcall_work, work);
-
-#ifdef MC_CRYPTO_CLOCK_MANAGEMENT
- mc_pm_clock_enable();
-#endif
-
- smc(fc_work->data);
-
-#ifdef MC_CRYPTO_CLOCK_MANAGEMENT
- mc_pm_clock_disable();
-#endif
-}
-
-void mc_fastcall(void *data)
-{
- struct fastcall_work fc_work = {
- KTHREAD_WORK_INIT(fc_work.work, fastcall_work_func),
- .data = data,
- };
-
- queue_kthread_work(&fastcall_worker, &fc_work.work);
- flush_kthread_work(&fc_work.work);
-}
-
-int mc_fastcall_init(struct mc_context *context)
-{
- int ret = 0;
-
- ctx = context;
-
- fastcall_thread = kthread_create(kthread_worker_fn, &fastcall_worker,
- "mc_fastcall");
- if (IS_ERR(fastcall_thread)) {
- ret = PTR_ERR(fastcall_thread);
- fastcall_thread = NULL;
- MCDRV_DBG_ERROR(mcd, "cannot create fastcall wq (%d)\n", ret);
- return ret;
- }
-
- /* this thread MUST run on CPU 0 */
- kthread_bind(fastcall_thread, 0);
- wake_up_process(fastcall_thread);
-
- return 0;
-}
-
-void mc_fastcall_destroy(void)
-{
- if (!IS_ERR_OR_NULL(fastcall_thread)) {
- kthread_stop(fastcall_thread);
- fastcall_thread = NULL;
- }
-}
-#else
-
-struct fastcall_work_struct {
- struct work_struct work;
- void *data;
-};
-
-static void fastcall_work_func(struct work_struct *work)
-{
- struct fastcall_work_struct *fc_work =
- container_of(work, struct fastcall_work_struct, work);
-
-#ifdef MC_CRYPTO_CLOCK_MANAGEMENT
- mc_pm_clock_enable();
-#endif
-
- smc(fc_work->data);
-
-#ifdef MC_CRYPTO_CLOCK_MANAGEMENT
- mc_pm_clock_disable();
-#endif
-}
-
-void mc_fastcall(void *data)
-{
- struct fastcall_work_struct work = {
- .data = data,
- };
- INIT_WORK(&work.work, fastcall_work_func);
- schedule_work_on(0, &work.work);
-
- flush_work(&work.work);
-}
-
-int mc_fastcall_init(struct mc_context *context)
-{
- ctx = context;
- return 0;
-};
-
-void mc_fastcall_destroy(void) {};
-#endif
-
-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 common notify */
-int _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;
- _smc(&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/setupDrivers.sh b/drivers/gud/setupDrivers.sh
new file mode 100644
index 0000000..8f877b7
--- /dev/null
+++ b/drivers/gud/setupDrivers.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+export COMP_PATH_ROOT=$(dirname $(readlink -f $BASH_SOURCE)) #set this to the absolute path of the folder containing this file
+
+# This part has to be set by the customer
+# To be set, absolute path of kernel folder
+export LINUX_PATH=
+# To be set, absolute path! CROSS_COMPILE variable needed by kernel eg /home/user/arm-2009q3/bin/arm-none-linux-gnueabi-
+export CROSS_COMPILE=
+# To be set, build mode debug or release
+export MODE=debug
+# To be set, the absolute path to the Linux Android NDK
+export NDK_PATH=
+
+# Global variables needed by build scripts
+export COMP_PATH_Logwrapper=$COMP_PATH_ROOT/Logwrapper/Out
+export COMP_PATH_MobiCore=$COMP_PATH_ROOT/MobiCore/Out
+export COMP_PATH_MobiCoreDriverMod=$COMP_PATH_ROOT/mobicore_driver/Out
+export COMP_PATH_MobiCoreDriverLib=$COMP_PATH_ROOT/daemon/Out
+export COMP_PATH_AndroidNdkLinux=$NDK_PATH
\ No newline at end of file
diff --git a/drivers/input/misc/mma8x5x.c b/drivers/input/misc/mma8x5x.c
index d708d94..a605720 100644
--- a/drivers/input/misc/mma8x5x.c
+++ b/drivers/input/misc/mma8x5x.c
@@ -26,8 +26,8 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/i2c.h>
-#include <linux/input-polldev.h>
#include <linux/sensors.h>
+#include <linux/input.h>
#include <linux/regulator/consumer.h>
#include <linux/of_gpio.h>
#include <linux/irq.h>
@@ -44,8 +44,6 @@
#define POLL_INTERVAL_MAX 10000
#define POLL_INTERVAL 100 /* msecs */
-/* if sensor is standby ,set POLL_STOP_TIME to slow down the poll */
-#define POLL_STOP_TIME 10000
#define INPUT_FUZZ 32
#define INPUT_FLAT 32
#define INPUT_DATA_DIVIDER 16
@@ -81,6 +79,7 @@
#define MMA_INT_ROUTING_CFG 0x01
#define MMA_POWER_CFG_MASK 0xFE
+#define MMA_ODR_MASK 0x38
struct sensor_regulator {
struct regulator *vreg;
@@ -189,7 +188,7 @@
};
struct mma8x5x_data {
struct i2c_client *client;
- struct input_polled_dev *poll_dev;
+ struct delayed_work dwork;
struct input_dev *idev;
struct mutex data_lock;
struct sensors_classdev cdev;
@@ -229,7 +228,6 @@
{{ 0, 1, 0}, { 1, 0, 0}, {0, 0, -1} },
{{ 1, 0, 0}, { 0, -1, 0}, {0, 0, -1} },
};
-static struct mma8x5x_data *drv_data;
static int mma8x5x_config_regulator(struct i2c_client *client, bool on)
{
int rc = 0, i;
@@ -408,7 +406,7 @@
if (result < 0)
goto out;
- val = (u8)result | val;
+ val = ((u8)result & ~MMA_ODR_MASK) | val;
result = i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG1,
(val & MMA_POWER_CFG_MASK));
if (result < 0)
@@ -487,32 +485,27 @@
static void mma8x5x_report_data(struct mma8x5x_data *pdata)
{
- struct input_polled_dev *poll_dev = pdata->poll_dev;
struct mma8x5x_data_axis data;
+
mutex_lock(&pdata->data_lock);
- if ((pdata->active & MMA_STATE_MASK) == MMA_STANDBY) {
- poll_dev->poll_interval = POLL_STOP_TIME;
- /* if standby ,set as 10s to slow the poll. */
- goto out;
- } else {
- if (poll_dev->poll_interval == POLL_STOP_TIME)
- poll_dev->poll_interval = pdata->poll_delay;
- }
if (mma8x5x_read_data(pdata->client, &data) != 0)
goto out;
mma8x5x_data_convert(pdata, &data);
- input_report_abs(poll_dev->input, ABS_X, data.x);
- input_report_abs(poll_dev->input, ABS_Y, data.y);
- input_report_abs(poll_dev->input, ABS_Z, data.z);
- input_sync(poll_dev->input);
+ input_report_abs(pdata->idev, ABS_X, data.x);
+ input_report_abs(pdata->idev, ABS_Y, data.y);
+ input_report_abs(pdata->idev, ABS_Z, data.z);
+ input_sync(pdata->idev);
out:
mutex_unlock(&pdata->data_lock);
}
-static void mma8x5x_dev_poll(struct input_polled_dev *dev)
+static void mma8x5x_dev_poll(struct work_struct *work)
{
- struct mma8x5x_data *pdata = (struct mma8x5x_data *)dev->private;
+ struct mma8x5x_data *pdata = container_of((struct delayed_work *)work,
+ struct mma8x5x_data, dwork);
mma8x5x_report_data(pdata);
+ schedule_delayed_work(&pdata->dwork,
+ msecs_to_jiffies(pdata->poll_delay));
}
static irqreturn_t mma8x5x_interrupt(int vec, void *data)
@@ -577,12 +570,18 @@
dev_err(&client->dev, "change device state failed!");
goto err_failed;
}
+
+ schedule_delayed_work(&pdata->dwork,
+ msecs_to_jiffies(pdata->poll_delay));
+
pdata->active = MMA_ACTIVED;
dev_dbg(&client->dev, "%s:mma enable setting active.\n",
__func__);
}
} else if (enable == 0) {
if (pdata->active == MMA_ACTIVED) {
+ cancel_delayed_work_sync(&pdata->dwork);
+
val = i2c_smbus_read_byte_data(client,
MMA8X5X_CTRL_REG1);
if (val < 0) {
@@ -616,7 +615,7 @@
static ssize_t mma8x5x_enable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct mma8x5x_data *pdata = drv_data;
+ struct mma8x5x_data *pdata = dev_get_drvdata(dev);
struct i2c_client *client;
u8 val;
int enable;
@@ -641,7 +640,7 @@
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct mma8x5x_data *pdata = drv_data;
+ struct mma8x5x_data *pdata = dev_get_drvdata(dev);
struct i2c_client *client;
int ret;
unsigned long enable;
@@ -663,7 +662,7 @@
static ssize_t mma8x5x_position_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct mma8x5x_data *pdata = drv_data;
+ struct mma8x5x_data *pdata = dev_get_drvdata(dev);
int position = 0;
if (!pdata) {
@@ -680,7 +679,7 @@
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct mma8x5x_data *pdata = drv_data;
+ struct mma8x5x_data *pdata = dev_get_drvdata(dev);
int position;
int ret;
@@ -714,7 +713,6 @@
} else {
mutex_lock(&pdata->data_lock);
pdata->poll_delay = delay_ms;
- pdata->poll_dev->poll_interval = pdata->poll_delay;
mutex_unlock(&pdata->data_lock);
}
@@ -724,7 +722,7 @@
static ssize_t mma8x5x_poll_delay_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct mma8x5x_data *pdata = drv_data;
+ struct mma8x5x_data *pdata = dev_get_drvdata(dev);
if (!pdata) {
dev_err(dev, "Invalid driver private data!");
@@ -738,7 +736,7 @@
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct mma8x5x_data *pdata = drv_data;
+ struct mma8x5x_data *pdata = dev_get_drvdata(dev);
int delay;
int ret;
@@ -825,7 +823,6 @@
struct input_dev *idev;
struct mma8x5x_data *pdata;
struct i2c_adapter *adapter;
- struct input_polled_dev *poll_dev;
adapter = to_i2c_adapter(client->dev.parent);
/* power on the device */
result = mma8x5x_config_regulator(client, 1);
@@ -836,7 +833,7 @@
I2C_FUNC_SMBUS_BYTE |
I2C_FUNC_SMBUS_BYTE_DATA);
if (!result)
- goto err_out;
+ goto err_check_id;
chip_id = i2c_smbus_read_byte_data(client, MMA8X5X_WHO_AM_I);
@@ -846,14 +843,14 @@
chip_id, MMA8451_ID, MMA8452_ID, MMA8453_ID,
MMA8652_ID, MMA8653_ID);
result = -EINVAL;
- goto err_out;
+ goto err_check_id;
}
/* set the private data */
pdata = kzalloc(sizeof(struct mma8x5x_data), GFP_KERNEL);
if (!pdata) {
result = -ENOMEM;
dev_err(&client->dev, "alloc data memory error!\n");
- goto err_out;
+ goto err_check_id;
}
if (client->dev.of_node) {
@@ -867,12 +864,10 @@
}
/* Initialize the MMA8X5X chip */
- drv_data = pdata;
pdata->client = client;
pdata->chip_id = chip_id;
pdata->mode = MODE_2G;
- pdata->poll_delay = POLL_STOP_TIME;
- pdata->poll_dev = NULL;
+ pdata->poll_delay = POLL_INTERVAL;
mutex_init(&pdata->data_lock);
i2c_set_clientdata(client, pdata);
@@ -894,29 +889,9 @@
if (result) {
dev_err(&client->dev,
"set_direction for irq gpio failed\n");
- goto err_set_direction;
+ goto err_set_gpio_direction;
}
}
- idev = input_allocate_device();
- if (!idev) {
- result = -ENOMEM;
- dev_err(&client->dev, "alloc input device failed!\n");
- goto err_alloc_poll_device;
- }
- input_set_drvdata(idev, pdata);
- idev->name = ACCEL_INPUT_DEV_NAME;
- idev->uniq = mma8x5x_id2name(pdata->chip_id);
- idev->id.bustype = BUS_I2C;
- idev->evbit[0] = BIT_MASK(EV_ABS);
- input_set_abs_params(idev, ABS_X, -0x7fff, 0x7fff, 0, 0);
- input_set_abs_params(idev, ABS_Y, -0x7fff, 0x7fff, 0, 0);
- input_set_abs_params(idev, ABS_Z, -0x7fff, 0x7fff, 0, 0);
- result = input_register_device(idev);
- if (result) {
- dev_err(&client->dev, "register input device failed!\n");
- goto err_register_device;
- }
- pdata->idev = idev;
device_init_wakeup(&client->dev, true);
enable_irq_wake(client->irq);
result = request_threaded_irq(client->irq, NULL,
@@ -930,34 +905,29 @@
}
mma8x5x_device_int_init(client);
} else {
- /* create the input poll device */
- poll_dev = input_allocate_polled_device();
- if (!poll_dev) {
- result = -ENOMEM;
- dev_err(&client->dev, "alloc poll device failed!\n");
- goto err_alloc_poll_device;
- }
- pdata->poll_dev = poll_dev;
- pdata->idev = NULL;
- poll_dev->poll = mma8x5x_dev_poll;
- poll_dev->poll_interval = POLL_STOP_TIME;
- poll_dev->poll_interval_min = POLL_INTERVAL_MIN;
- poll_dev->poll_interval_max = POLL_INTERVAL_MAX;
- poll_dev->private = pdata;
- idev = poll_dev->input;
- idev->name = ACCEL_INPUT_DEV_NAME;
- idev->uniq = mma8x5x_id2name(pdata->chip_id);
- idev->id.bustype = BUS_I2C;
- idev->evbit[0] = BIT_MASK(EV_ABS);
- input_set_abs_params(idev, ABS_X, -0x7fff, 0x7fff, 0, 0);
- input_set_abs_params(idev, ABS_Y, -0x7fff, 0x7fff, 0, 0);
- input_set_abs_params(idev, ABS_Z, -0x7fff, 0x7fff, 0, 0);
- result = input_register_polled_device(pdata->poll_dev);
- if (result) {
- dev_err(&client->dev, "register poll device failed!\n");
- goto err_register_device;
- }
+ INIT_DELAYED_WORK(&pdata->dwork, mma8x5x_dev_poll);
}
+ idev = input_allocate_device();
+ if (!idev) {
+ result = -ENOMEM;
+ dev_err(&client->dev, "alloc input device failed!\n");
+ goto err_alloc_poll_device;
+ }
+ input_set_drvdata(idev, pdata);
+ idev->name = ACCEL_INPUT_DEV_NAME;
+ idev->uniq = mma8x5x_id2name(pdata->chip_id);
+ idev->id.bustype = BUS_I2C;
+ idev->evbit[0] = BIT_MASK(EV_ABS);
+ input_set_abs_params(idev, ABS_X, -0x7fff, 0x7fff, 0, 0);
+ input_set_abs_params(idev, ABS_Y, -0x7fff, 0x7fff, 0, 0);
+ input_set_abs_params(idev, ABS_Z, -0x7fff, 0x7fff, 0, 0);
+ result = input_register_device(idev);
+ if (result) {
+ dev_err(&client->dev, "register input device failed!\n");
+ goto err_register_device;
+ }
+ pdata->idev = idev;
+
result = sysfs_create_group(&idev->dev.kobj, &mma8x5x_attr_group);
if (result) {
dev_err(&client->dev, "create device file failed!\n");
@@ -983,23 +953,20 @@
err_create_class_sysfs:
sysfs_remove_group(&idev->dev.kobj, &mma8x5x_attr_group);
err_create_sysfs:
- input_unregister_polled_device(pdata->poll_dev);
+ input_unregister_device(idev);
+err_register_device:
+ input_free_device(idev);
+err_alloc_poll_device:
err_register_irq:
if (pdata->use_int)
device_init_wakeup(&client->dev, false);
-err_register_device:
- if (pdata->use_int)
- input_free_device(idev);
- else
- input_free_polled_device(pdata->poll_dev);
-err_alloc_poll_device:
-err_set_direction:
+err_set_gpio_direction:
if (gpio_is_valid(pdata->int_pin) && pdata->use_int)
gpio_free(pdata->int_pin);
err_request_gpio:
err_parse_dt:
kfree(pdata);
-err_out:
+err_check_id:
mma8x5x_config_regulator(client, 0);
err_power_on:
return result;
@@ -1007,14 +974,22 @@
static int __devexit mma8x5x_remove(struct i2c_client *client)
{
struct mma8x5x_data *pdata = i2c_get_clientdata(client);
- struct input_polled_dev *poll_dev;
+ struct input_dev *idev;
+
mma8x5x_device_stop(client);
if (pdata) {
- poll_dev = pdata->poll_dev;
- input_unregister_polled_device(poll_dev);
- input_free_polled_device(poll_dev);
+ idev = pdata->idev;
+ sysfs_remove_group(&idev->dev.kobj, &mma8x5x_attr_group);
+ if (pdata->use_int) {
+ device_init_wakeup(&client->dev, false);
+ if (gpio_is_valid(pdata->int_pin))
+ gpio_free(pdata->int_pin);
+ }
+ input_unregister_device(idev);
+ input_free_device(idev);
kfree(pdata);
}
+ mma8x5x_config_regulator(client, 0);
return 0;
}
@@ -1026,8 +1001,10 @@
if (pdata->use_int && pdata->active == MMA_ACTIVED)
return 0;
- if (pdata->active == MMA_ACTIVED)
+ if (pdata->active == MMA_ACTIVED) {
mma8x5x_device_stop(client);
+ cancel_delayed_work_sync(&pdata->dwork);
+ }
if (pdata->active & MMA_SHUTTEDDOWN)
return 0;
if (!mma8x5x_config_regulator(client, 0))
@@ -1058,6 +1035,8 @@
if (pdata->active == MMA_ACTIVED) {
val = i2c_smbus_read_byte_data(client, MMA8X5X_CTRL_REG1);
i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG1, val|0x01);
+ schedule_delayed_work(&pdata->dwork,
+ msecs_to_jiffies(pdata->poll_delay));
}
return 0;
diff --git a/drivers/md/dm-req-crypt.c b/drivers/md/dm-req-crypt.c
index 16141b5..ab21404 100644
--- a/drivers/md/dm-req-crypt.c
+++ b/drivers/md/dm-req-crypt.c
@@ -41,7 +41,7 @@
#define MAX_ENCRYPTION_BUFFERS 1
#define MIN_IOS 16
#define MIN_POOL_PAGES 32
-#define KEY_SIZE_XTS 32
+#define KEY_SIZE_XTS 64
#define AES_XTS_IV_LEN 16
#define DM_REQ_CRYPT_ERROR -1
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
index 044f6f1..eb05015 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -176,15 +176,15 @@
uint32_t irq_status0, uint32_t irq_status1,
struct msm_isp_timestamp *ts)
{
+ uint32_t cnt;
if (!(irq_status0 & 0x1F))
return;
if (irq_status0 & BIT(0)) {
ISP_DBG("%s: SOF IRQ\n", __func__);
- if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0
- && vfe_dev->axi_data.src_info[VFE_PIX_0].
- pix_stream_count == 0) {
- msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts);
+ cnt = vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count;
+ if (cnt > 0) {
+ msm_isp_sof_notify(vfe_dev, VFE_RAW_0, ts);
if (vfe_dev->axi_data.stream_update)
msm_isp_axi_stream_update(vfe_dev);
msm_isp_update_framedrop_reg(vfe_dev);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index d53d7f6..e443e9a 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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
@@ -370,15 +370,16 @@
uint32_t irq_status0, uint32_t irq_status1,
struct msm_isp_timestamp *ts)
{
+ int cnt;
+
if (!(irq_status0 & 0xF))
return;
if (irq_status0 & (1 << 0)) {
ISP_DBG("%s: SOF IRQ\n", __func__);
- if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0
- && vfe_dev->axi_data.src_info[VFE_PIX_0].
- pix_stream_count == 0) {
- msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts);
+ cnt = vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count;
+ if (cnt > 0) {
+ msm_isp_sof_notify(vfe_dev, VFE_RAW_0, ts);
if (vfe_dev->axi_data.stream_update)
msm_isp_axi_stream_update(vfe_dev);
msm_isp_update_framedrop_reg(vfe_dev);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index 01106d2..206620c 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -81,6 +81,10 @@
return rc;
switch (stream_cfg_cmd->output_format) {
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_YVYU:
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_VYUY:
case V4L2_PIX_FMT_SBGGR8:
case V4L2_PIX_FMT_SGBRG8:
case V4L2_PIX_FMT_SGRBG8:
@@ -167,6 +171,10 @@
uint32_t size = 0;
struct msm_vfe_axi_plane_cfg *plane_cfg = stream_info->plane_cfg;
switch (stream_info->output_format) {
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_YVYU:
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_VYUY:
case V4L2_PIX_FMT_SBGGR8:
case V4L2_PIX_FMT_SGBRG8:
case V4L2_PIX_FMT_SGRBG8:
@@ -444,7 +452,7 @@
sof_event.frame_id = vfe_dev->axi_data.src_info[frame_src].frame_id;
sof_event.timestamp = ts->event_time;
sof_event.mono_timestamp = ts->buf_time;
- msm_isp_send_event(vfe_dev, ISP_EVENT_SOF, &sof_event);
+ msm_isp_send_event(vfe_dev, ISP_EVENT_SOF + frame_src, &sof_event);
}
void msm_isp_calculate_framedrop(
@@ -1215,6 +1223,8 @@
msm_isp_axi_stream_enable_cfg(vfe_dev, stream_info);
stream_info->state = ACTIVE;
}
+ vfe_dev->axi_data.src_info[
+ SRC_TO_INTF(stream_info->stream_src)].frame_id = 0;
}
msm_isp_update_stream_bandwidth(vfe_dev);
vfe_dev->hw_info->vfe_ops.axi_ops.reload_wm(vfe_dev, wm_reload_mask);
@@ -1228,16 +1238,6 @@
update_camif_state(vfe_dev, camif_update);
}
- if (vfe_dev->axi_data.src_info[VFE_RAW_0].raw_stream_count > 0) {
- vfe_dev->axi_data.src_info[VFE_RAW_0].frame_id = 0;
- }
- else if (vfe_dev->axi_data.src_info[VFE_RAW_1].raw_stream_count > 0) {
- vfe_dev->axi_data.src_info[VFE_RAW_1].frame_id = 0;
- }
- else if (vfe_dev->axi_data.src_info[VFE_RAW_2].raw_stream_count > 0) {
- vfe_dev->axi_data.src_info[VFE_RAW_2].frame_id = 0;
- }
-
if (wait_for_complete)
rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, camif_update);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index 191a2ec..ffe0b9c 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -806,6 +806,12 @@
case V4L2_PIX_FMT_NV61:
val = CAL_WORD(pixel_per_line, 1, 8);
break;
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_YVYU:
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_VYUY:
+ val = CAL_WORD(pixel_per_line, 2, 8);
+ break;
/*TD: Add more image format*/
default:
msm_isp_print_fourcc_error(__func__, output_format);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
index 981c210..8662657 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
@@ -457,9 +457,8 @@
break;
}
for (i = 0; i < csid_params.lut_params.num_cid; i++) {
- vc_cfg = kzalloc(csid_params.lut_params.num_cid *
- sizeof(struct msm_camera_csid_vc_cfg),
- GFP_KERNEL);
+ vc_cfg = kzalloc(sizeof(struct msm_camera_csid_vc_cfg),
+ GFP_KERNEL);
if (!vc_cfg) {
pr_err("%s: %d failed\n", __func__, __LINE__);
for (i--; i >= 0; i--)
@@ -469,8 +468,7 @@
}
if (copy_from_user(vc_cfg,
(void *)csid_params.lut_params.vc_cfg[i],
- (csid_params.lut_params.num_cid *
- sizeof(struct msm_camera_csid_vc_cfg)))) {
+ sizeof(struct msm_camera_csid_vc_cfg))) {
pr_err("%s: %d failed\n", __func__, __LINE__);
kfree(vc_cfg);
for (i--; i >= 0; i--)
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index f0721c3..9dbecfb 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -1343,7 +1343,6 @@
mutex_lock(&inst->lock);
}
mutex_unlock(&inst->lock);
- msm_smem_delete_client(inst->mem_client);
debugfs_remove_recursive(inst->debugfs_root);
}
}
@@ -1401,7 +1400,9 @@
for (i = 0; i < MAX_PORT_NUM; i++)
vb2_queue_release(&inst->bufq[i].vb2_bufq);
+ msm_smem_delete_client(inst->mem_client);
pr_info(VIDC_DBG_TAG "Closed video instance: %p\n", VIDC_INFO, inst);
kfree(inst);
+
return 0;
}
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 4fcd20e..d6000c9 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -1561,9 +1561,6 @@
dev->intr_status = 0;
INIT_LIST_HEAD(&dev->sess_head);
- mutex_init(&dev->read_lock);
- mutex_init(&dev->write_lock);
- mutex_init(&dev->session_lock);
venus_hfi_set_registers(dev);
if (!dev->hal_client) {
@@ -3301,7 +3298,6 @@
__func__, device);
return -EINVAL;
}
- mutex_init(&device->clk_pwr_lock);
device->clk_gating_level = VCODEC_CLK;
rc = venus_hfi_iommu_attach(device);
if (rc) {
@@ -3574,6 +3570,11 @@
goto error_createq_pm;
}
+ mutex_init(&hdevice->read_lock);
+ mutex_init(&hdevice->write_lock);
+ mutex_init(&hdevice->session_lock);
+ mutex_init(&hdevice->clk_pwr_lock);
+
if (hal_ctxt.dev_count == 0)
INIT_LIST_HEAD(&hal_ctxt.dev_head);
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index df3e5d1..efafa23 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -1089,16 +1089,13 @@
return -EINVAL;
}
- if (((uint32_t)req_ptr->cmd_req_buf <
- data_ptr->client.user_virt_sb_base)
- || ((uint32_t)req_ptr->cmd_req_buf >=
- (data_ptr->client.user_virt_sb_base +
- data_ptr->client.sb_length))) {
- pr_err("cmd buffer address not within shared bufffer\n");
+ /* Clients need to ensure req_buf is at base offset of shared buffer */
+ if ((uint32_t)req_ptr->cmd_req_buf !=
+ data_ptr->client.user_virt_sb_base) {
+ pr_err("cmd buf not pointing to base offset of shared buffer\n");
return -EINVAL;
}
-
if (((uint32_t)req_ptr->resp_buf < data_ptr->client.user_virt_sb_base)
|| ((uint32_t)req_ptr->resp_buf >=
(data_ptr->client.user_virt_sb_base +
@@ -1117,8 +1114,6 @@
(uint32_t)req_ptr->resp_buf));
send_svc_ireq_ptr->rsp_len = req_ptr->resp_len;
- pr_debug("CMD ID (%x), KEY_TYPE (%d)\n", send_svc_ireq_ptr->qsee_cmd_id,
- ((struct qseecom_rpmb_provision_key *)req_ptr->cmd_req_buf)->key_type);
return ret;
}
@@ -1143,6 +1138,21 @@
return -EINVAL;
}
+ if (data->client.sb_virt == NULL) {
+ pr_err("sb_virt null\n");
+ return -EINVAL;
+ }
+
+ if (data->client.user_virt_sb_base == 0) {
+ pr_err("user_virt_sb_base is null\n");
+ return -EINVAL;
+ }
+
+ if (data->client.sb_length == 0) {
+ pr_err("sb_length is 0\n");
+ return -EINVAL;
+ }
+
data->type = QSEECOM_SECURE_SERVICE;
switch (req.cmd_id) {
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 9c6bef6..6de1cde 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -2638,15 +2638,13 @@
struct mmc_host *host = card->host;
unsigned long flags;
+ if (req && !mq->mqrq_prev->req) {
+ mmc_rpm_hold(host, &card->dev);
#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
if (mmc_bus_needs_resume(card->host)) {
mmc_resume_bus(card->host);
- mmc_blk_set_blksize(md, card);
}
#endif
-
- if (req && !mq->mqrq_prev->req) {
- mmc_rpm_hold(host, &card->dev);
/* claim host only for the first request */
mmc_claim_host(card->host);
if (card->ext_csd.bkops_en)
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index c496077..1feb26b 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -983,6 +983,10 @@
*/
void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
{
+#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
+ if (mmc_bus_needs_resume(host))
+ mmc_resume_bus(host);
+#endif
__mmc_start_req(host, mrq);
mmc_wait_for_req_done(host, mrq);
}
@@ -2011,9 +2015,6 @@
host->bus_ops->resume(host);
}
- if (host->bus_ops->detect && !host->bus_dead)
- host->bus_ops->detect(host);
-
mmc_bus_put(host);
printk("%s: Deferred resume completed\n", mmc_hostname(host));
return 0;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 885d0d2..63952e7 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -340,6 +340,8 @@
card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
mmc_select_card_type(card);
+ card->ext_csd.raw_drive_strength = ext_csd[EXT_CSD_DRIVE_STRENGTH];
+
card->ext_csd.raw_s_a_timeout = ext_csd[EXT_CSD_S_A_TIMEOUT];
card->ext_csd.raw_erase_timeout_mult =
ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT];
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 32f5220..822548e 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1503,7 +1503,8 @@
mrq->cmd->error = -EIO;
if (mrq->data)
mrq->data->error = -EIO;
- tasklet_schedule(&host->finish_tasklet);
+ mmc_request_done(host->mmc, mrq);
+ sdhci_runtime_pm_put(host);
return;
}
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 38c70a3..d2b381b 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -36,6 +36,7 @@
#include <linux/mfd/pm8xxx/misc.h>
#include <linux/qpnp/qpnp-adc.h>
+#include <mach/board.h>
#include <mach/msm_smd.h>
#include <mach/msm_iomap.h>
#include <mach/subsystem_restart.h>
@@ -188,6 +189,7 @@
/* max 20mhz channel count */
#define WCNSS_MAX_CH_NUM 45
+#define WCNSS_MAX_PIL_RETRY 3
#define VALID_VERSION(version) \
((strncmp(version, "INVALID", WCNSS_VERSION_LEN)) ? 1 : 0)
@@ -591,6 +593,14 @@
reg = readl_relaxed(reg_addr);
pr_info_ratelimited("%s: PRONTO_SAW2_SPM_STS %08x\n", __func__, reg);
+ reg_addr = penv->pronto_pll_base + PRONTO_PLL_STATUS_OFFSET;
+ reg = readl_relaxed(reg_addr);
+ pr_err("PRONTO_PLL_STATUS %08x\n", reg);
+
+ reg_addr = penv->msm_wcnss_base + PRONTO_PMU_CPU_AHB_CMD_RCGR_OFFSET;
+ reg4 = readl_relaxed(reg_addr);
+ pr_err("PMU_CPU_CMD_RCGR %08x\n", reg4);
+
reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_GDSCR_OFFSET;
reg = readl_relaxed(reg_addr);
pr_info_ratelimited("%s: PRONTO_PMU_COM_GDSCR %08x\n",
@@ -639,10 +649,6 @@
reg = readl_relaxed(reg_addr);
pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR2 %08x\n", __func__, reg);
- reg_addr = penv->pronto_pll_base + PRONTO_PLL_STATUS_OFFSET;
- reg = readl_relaxed(reg_addr);
- pr_info_ratelimited("%s: PRONTO_PLL_STATUS %08x\n", __func__, reg);
-
tst_addr = penv->pronto_a2xb_base + A2XB_TSTBUS_OFFSET;
tst_ctrl_addr = penv->pronto_a2xb_base + A2XB_TSTBUS_CTRL_OFFSET;
@@ -716,10 +722,6 @@
reg3 = readl_relaxed(reg_addr);
pr_info_ratelimited("%s: PMU_WLAN_AHB_CBCR %08x\n", __func__, reg3);
- reg_addr = penv->msm_wcnss_base + PRONTO_PMU_CPU_AHB_CMD_RCGR_OFFSET;
- reg4 = readl_relaxed(reg_addr);
- pr_info_ratelimited("%s: PMU_CPU_CMD_RCGR %08x\n", __func__, reg4);
-
if ((reg & PRONTO_PMU_WLAN_BCR_BLK_ARES) ||
(reg2 & PRONTO_PMU_WLAN_GDSCR_SW_COLLAPSE) ||
(!(reg4 & PRONTO_PMU_CPU_AHB_CMD_RCGR_ROOT_EN)) ||
@@ -748,6 +750,22 @@
EXPORT_SYMBOL(wcnss_pronto_log_debug_regs);
#ifdef CONFIG_WCNSS_REGISTER_DUMP_ON_BITE
+static void wcnss_log_iris_regs(void)
+{
+ int i;
+ u32 reg_val;
+ u32 regs_array[] = {
+ 0x04, 0x05, 0x11, 0x1e, 0x40, 0x48,
+ 0x49, 0x4b, 0x00, 0x01, 0x4d};
+
+ pr_info("IRIS Registers [address] : value\n");
+
+ for (i = 0; i < ARRAY_SIZE(regs_array); i++) {
+ reg_val = wcnss_rf_read_reg(regs_array[i]);
+ pr_info("[0x%08x] : 0x%08x\n", regs_array[i], reg_val);
+ }
+}
+
void wcnss_log_debug_regs_on_bite(void)
{
struct platform_device *pdev = wcnss_get_platform_device();
@@ -768,10 +786,12 @@
clk_rate = clk_get_rate(measure);
pr_debug("wcnss: clock frequency is: %luHz\n", clk_rate);
- if (clk_rate)
+ if (clk_rate) {
wcnss_pronto_log_debug_regs();
- else
+ } else {
pr_err("clock frequency is zero, cannot access PMU or other registers\n");
+ wcnss_log_iris_regs();
+ }
}
}
#endif
@@ -2049,6 +2069,7 @@
unsigned long wcnss_phys_addr;
int size = 0;
struct resource *res;
+ int pil_retry = 0;
int has_pronto_hw = of_property_read_bool(pdev->dev.of_node,
"qcom,has-pronto-hw");
@@ -2240,12 +2261,17 @@
penv->fw_vbatt_state = WCNSS_CONFIG_UNSPECIFIED;
}
- /* trigger initialization of the WCNSS */
- penv->pil = subsystem_get(WCNSS_PIL_DEVICE);
- if (IS_ERR(penv->pil)) {
- dev_err(&pdev->dev, "Peripheral Loader failed on WCNSS.\n");
- ret = PTR_ERR(penv->pil);
- wcnss_pronto_log_debug_regs();
+ do {
+ /* trigger initialization of the WCNSS */
+ penv->pil = subsystem_get(WCNSS_PIL_DEVICE);
+ if (IS_ERR(penv->pil)) {
+ dev_err(&pdev->dev, "Peripheral Loader failed on WCNSS.\n");
+ ret = PTR_ERR(penv->pil);
+ wcnss_pronto_log_debug_regs();
+ }
+ } while (pil_retry++ < WCNSS_MAX_PIL_RETRY && IS_ERR(penv->pil));
+
+ if (pil_retry >= WCNSS_MAX_PIL_RETRY) {
penv->pil = NULL;
goto fail_pil;
}
diff --git a/drivers/nfc/nfc-nci.c b/drivers/nfc/nfc-nci.c
index c6192ed..a44c06c 100644
--- a/drivers/nfc/nfc-nci.c
+++ b/drivers/nfc/nfc-nci.c
@@ -1397,18 +1397,6 @@
gpio_set_value(platform_data->dis_gpio, 1);
goto err_nfcc_not_present;
}
- regulators.regulator = regulator_get(&client->dev, regulators.name);
- if (IS_ERR(regulators.regulator)) {
- r = PTR_ERR(regulators.regulator);
- pr_err("regulator get of %s failed (%d)\n", regulators.name, r);
- } else {
- /* Enable the regulator */
- r = regulator_enable(regulators.regulator);
- if (r) {
- pr_err("vreg %s enable failed (%d)\n",
- regulators.name, r);
- }
- }
logging_level = 0;
/* request irq. The irq is set whenever the chip has data available
diff --git a/drivers/nfc/nfc-nci.h b/drivers/nfc/nfc-nci.h
index 9bfb77d..297c152 100644
--- a/drivers/nfc/nfc-nci.h
+++ b/drivers/nfc/nfc-nci.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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
@@ -223,9 +223,3 @@
unsigned int reg;
};
#endif
-/* enable LDO */
-struct vregs_info {
- const char * const name;
- struct regulator *regulator;
-};
-struct vregs_info regulators = {"vlogic", NULL};
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 2dc77e6..0870202 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -3558,7 +3558,7 @@
state == ADC_TM_WARM_STATE ? "warm" : "cool");
if (state == ADC_TM_WARM_STATE) {
- if (temp > chip->warm_bat_decidegc) {
+ if (temp >= chip->warm_bat_decidegc) {
/* Normal to warm */
bat_warm = true;
bat_cool = false;
@@ -3566,7 +3566,7 @@
chip->warm_bat_decidegc - HYSTERISIS_DECIDEGC;
chip->adc_param.state_request =
ADC_TM_COOL_THR_ENABLE;
- } else if (temp >
+ } else if (temp >=
chip->cool_bat_decidegc + HYSTERISIS_DECIDEGC){
/* Cool to normal */
bat_warm = false;
@@ -3578,7 +3578,7 @@
ADC_TM_HIGH_LOW_THR_ENABLE;
}
} else {
- if (temp < chip->cool_bat_decidegc) {
+ if (temp <= chip->cool_bat_decidegc) {
/* Normal to cool */
bat_warm = false;
bat_cool = true;
@@ -3586,7 +3586,7 @@
chip->cool_bat_decidegc + HYSTERISIS_DECIDEGC;
chip->adc_param.state_request =
ADC_TM_WARM_THR_ENABLE;
- } else if (temp <
+ } else if (temp <=
chip->warm_bat_decidegc - HYSTERISIS_DECIDEGC){
/* Warm to normal */
bat_warm = false;
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index f858822..0f8f1dd 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -265,9 +265,13 @@
u8 txn_mt;
u16 txn_mc = txn->mc;
u8 wbuf[SLIM_MSGQ_BUF_LEN];
+ bool report_sat = false;
+ if (txn->mc == SLIM_USR_MC_REPORT_SATELLITE &&
+ txn->mt == SLIM_MSG_MT_SRC_REFERRED_USER)
+ report_sat = true;
if (!pm_runtime_enabled(dev->dev) && dev->state == MSM_CTRL_ASLEEP &&
- txn->mc != SLIM_USR_MC_REPORT_SATELLITE) {
+ report_sat == false) {
/*
* Counter-part of system-suspend when runtime-pm is not enabled
* This way, resume can be left empty and device will be put in
@@ -295,7 +299,7 @@
return 0;
}
/* If txn is tried when controller is down, wait for ADSP to boot */
- if (txn->mc != SLIM_USR_MC_REPORT_SATELLITE) {
+ if (!report_sat) {
if (dev->state == MSM_CTRL_DOWN) {
u8 mc = (u8)txn->mc;
int timeout;
@@ -358,8 +362,7 @@
}
mutex_lock(&dev->tx_lock);
- if (txn->mc != SLIM_USR_MC_REPORT_SATELLITE &&
- (dev->state != MSM_CTRL_AWAKE)) {
+ if (report_sat == false && dev->state != MSM_CTRL_AWAKE) {
dev_err(dev->dev, "controller not ready");
mutex_unlock(&dev->tx_lock);
msm_slim_put_ctrl(dev);
@@ -436,11 +439,13 @@
puc = ((u8 *)pbuf) + 2;
if (txn->rbuf)
*(puc++) = txn->tid;
- if ((txn->mt == SLIM_MSG_MT_CORE) &&
+ if (((txn->mt == SLIM_MSG_MT_CORE) &&
((txn->mc >= SLIM_MSG_MC_REQUEST_INFORMATION &&
txn->mc <= SLIM_MSG_MC_REPORT_INFORMATION) ||
(txn->mc >= SLIM_MSG_MC_REQUEST_VALUE &&
- txn->mc <= SLIM_MSG_MC_CHANGE_VALUE))) {
+ txn->mc <= SLIM_MSG_MC_CHANGE_VALUE))) ||
+ (txn->mc == SLIM_USR_MC_REPEAT_CHANGE_VALUE &&
+ txn->mt == SLIM_MSG_MT_DEST_REFERRED_USER)) {
*(puc++) = (txn->ec & 0xFF);
*(puc++) = (txn->ec >> 8)&0xFF;
}
@@ -540,11 +545,49 @@
}
ngd_xfer_err:
mutex_unlock(&dev->tx_lock);
- if (txn_mc != SLIM_USR_MC_REPORT_SATELLITE)
+ if (!report_sat)
msm_slim_put_ctrl(dev);
return ret ? ret : dev->err;
}
+static int ngd_user_msg(struct slim_controller *ctrl, u8 la, u8 mt, u8 mc,
+ struct slim_ele_access *msg, u8 *buf, u8 len)
+{
+ struct slim_msg_txn txn;
+
+ if (mt != SLIM_MSG_MT_DEST_REFERRED_USER ||
+ mc != SLIM_USR_MC_REPEAT_CHANGE_VALUE) {
+ return -EPROTONOSUPPORT;
+ }
+ if (len > SLIM_MAX_VE_SLC_BYTES ||
+ msg->start_offset > MSM_SLIM_VE_MAX_MAP_ADDR)
+ return -EINVAL;
+ if (len <= 4) {
+ txn.ec = len - 1;
+ } else if (len <= 8) {
+ if (len & 0x1)
+ return -EINVAL;
+ txn.ec = ((len >> 1) + 1);
+ } else {
+ if (len & 0x3)
+ return -EINVAL;
+ txn.ec = ((len >> 2) + 3);
+ }
+ txn.ec |= (0x8 | ((msg->start_offset & 0xF) << 4));
+ txn.ec |= ((msg->start_offset & 0xFF0) << 4);
+
+ txn.la = la;
+ txn.mt = mt;
+ txn.mc = mc;
+ txn.dt = SLIM_MSG_DEST_LOGICALADDR;
+ txn.len = len;
+ txn.rl = len + 6;
+ txn.wbuf = buf;
+ txn.rbuf = NULL;
+ txn.comp = msg->comp;
+ return ngd_xfer_msg(ctrl, &txn);
+}
+
static int ngd_xferandwait_ack(struct slim_controller *ctrl,
struct slim_msg_txn *txn)
{
@@ -1222,6 +1265,7 @@
dev->ctrl.get_laddr = ngd_get_laddr;
dev->ctrl.allocbw = ngd_allocbw;
dev->ctrl.xfer_msg = ngd_xfer_msg;
+ dev->ctrl.xfer_user_msg = ngd_user_msg;
dev->ctrl.wakeup = ngd_clk_pause_wakeup;
dev->ctrl.alloc_port = msm_alloc_port;
dev->ctrl.dealloc_port = msm_dealloc_port;
diff --git a/drivers/slimbus/slim-msm.c b/drivers/slimbus/slim-msm.c
index 5d30e54..8589b9f 100644
--- a/drivers/slimbus/slim-msm.c
+++ b/drivers/slimbus/slim-msm.c
@@ -305,7 +305,7 @@
}
enum slim_port_err msm_slim_port_xfer_status(struct slim_controller *ctr,
- u8 pn, u8 **done_buf, u32 *done_len)
+ u8 pn, phys_addr_t *done_buf, u32 *done_len)
{
struct msm_slim_ctrl *dev = slim_get_ctrldata(ctr);
struct sps_iovec sio;
@@ -313,7 +313,7 @@
if (done_len)
*done_len = 0;
if (done_buf)
- *done_buf = NULL;
+ *done_buf = 0;
if (!dev->pipes[pn].connected)
return SLIM_P_DISCONNECT;
ret = sps_get_iovec(dev->pipes[pn].sps, &sio);
@@ -321,7 +321,7 @@
if (done_len)
*done_len = sio.size;
if (done_buf)
- *done_buf = (u8 *)sio.addr;
+ *done_buf = (phys_addr_t)sio.addr;
}
dev_dbg(dev->dev, "get iovec returned %d\n", ret);
return SLIM_P_INPROGRESS;
@@ -346,7 +346,7 @@
complete(comp);
}
-int msm_slim_port_xfer(struct slim_controller *ctrl, u8 pn, u8 *iobuf,
+int msm_slim_port_xfer(struct slim_controller *ctrl, u8 pn, phys_addr_t iobuf,
u32 len, struct completion *comp)
{
struct sps_register_event sreg;
@@ -366,7 +366,7 @@
dev_dbg(dev->dev, "sps register event error:%x\n", ret);
return ret;
}
- ret = sps_transfer_one(dev->pipes[pn].sps, (u32)iobuf, len, comp,
+ ret = sps_transfer_one(dev->pipes[pn].sps, iobuf, len, comp,
SPS_IOVEC_FLAG_INT);
dev_dbg(dev->dev, "sps submit xfer error code:%x\n", ret);
if (!ret) {
diff --git a/drivers/slimbus/slim-msm.h b/drivers/slimbus/slim-msm.h
index 5ffa300..2327b38 100644
--- a/drivers/slimbus/slim-msm.h
+++ b/drivers/slimbus/slim-msm.h
@@ -37,6 +37,10 @@
#define SLIM_USR_MC_CONNECT_SINK 0x2D
#define SLIM_USR_MC_DISCONNECT_PORT 0x2E
+#define SLIM_USR_MC_REPEAT_CHANGE_VALUE 0x0
+#define MSM_SLIM_VE_MAX_MAP_ADDR 0xFFF
+#define SLIM_MAX_VE_SLC_BYTES 16
+
#define MSM_SLIM_AUTOSUSPEND MSEC_PER_SEC
/*
@@ -306,8 +310,8 @@
void msm_dealloc_port(struct slim_controller *ctrl, u8 pn);
int msm_slim_connect_pipe_port(struct msm_slim_ctrl *dev, u8 pn);
enum slim_port_err msm_slim_port_xfer_status(struct slim_controller *ctr,
- u8 pn, u8 **done_buf, u32 *done_len);
-int msm_slim_port_xfer(struct slim_controller *ctrl, u8 pn, u8 *iobuf,
+ u8 pn, phys_addr_t *done_buf, u32 *done_len);
+int msm_slim_port_xfer(struct slim_controller *ctrl, u8 pn, phys_addr_t iobuf,
u32 len, struct completion *comp);
int msm_send_msg_buf(struct msm_slim_ctrl *dev, u32 *buf, u8 len, u32 tx_reg);
u32 *msm_get_msg_buf(struct msm_slim_ctrl *dev, int len);
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index caf7a87..fecf5ec 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -1107,6 +1107,28 @@
EXPORT_SYMBOL_GPL(slim_xfer_msg);
/*
+ * User message:
+ * slim_user_msg: Send user message that is interpreted by destination device
+ * @sb: Client handle sending the message
+ * @la: Destination device for this user message
+ * @mt: Message Type (Soruce-referred, or Destination-referred)
+ * @mc: Message Code
+ * @msg: Message structure (start offset, number of bytes) to be sent
+ * @buf: data buffer to be sent
+ * @len: data buffer size in bytes
+ */
+int slim_user_msg(struct slim_device *sb, u8 la, u8 mt, u8 mc,
+ struct slim_ele_access *msg, u8 *buf, u8 len)
+{
+ if (!sb || !sb->ctrl || !msg || mt == SLIM_MSG_MT_CORE)
+ return -EINVAL;
+ if (!sb->ctrl->xfer_user_msg)
+ return -EPROTONOSUPPORT;
+ return sb->ctrl->xfer_user_msg(sb->ctrl, la, mt, mc, msg, buf, len);
+}
+EXPORT_SYMBOL(slim_user_msg);
+
+/*
* slim_alloc_mgrports: Allocate port on manager side.
* @sb: device/client handle.
* @req: Port request type.
@@ -1462,7 +1484,7 @@
* Client will call slim_port_get_xfer_status to get error and/or number of
* bytes transferred if used asynchronously.
*/
-int slim_port_xfer(struct slim_device *sb, u32 ph, u8 *iobuf, u32 len,
+int slim_port_xfer(struct slim_device *sb, u32 ph, phys_addr_t iobuf, u32 len,
struct completion *comp)
{
struct slim_controller *ctrl = sb->ctrl;
@@ -1492,7 +1514,7 @@
* processed from the multiple transfers.
*/
enum slim_port_err slim_port_get_xfer_status(struct slim_device *sb, u32 ph,
- u8 **done_buf, u32 *done_len)
+ phys_addr_t *done_buf, u32 *done_len)
{
struct slim_controller *ctrl = sb->ctrl;
u8 pn = SLIM_HDL_TO_PORT(ph);
@@ -1505,7 +1527,7 @@
*/
if (la != SLIM_LA_MANAGER) {
if (done_buf)
- *done_buf = NULL;
+ *done_buf = 0;
if (done_len)
*done_len = 0;
return SLIM_P_NOT_OWNED;
diff --git a/drivers/usb/gadget/f_diag.c b/drivers/usb/gadget/f_diag.c
index e218130..16f961e 100644
--- a/drivers/usb/gadget/f_diag.c
+++ b/drivers/usb/gadget/f_diag.c
@@ -26,6 +26,7 @@
#include <linux/usb/gadget.h>
#include <linux/workqueue.h>
#include <linux/debugfs.h>
+#include <linux/kmemleak.h>
static DEFINE_SPINLOCK(ch_lock);
static LIST_HEAD(usb_diag_ch_list);
@@ -381,6 +382,7 @@
req = usb_ep_alloc_request(ctxt->in, GFP_ATOMIC);
if (!req)
goto fail;
+ kmemleak_not_leak(req);
req->complete = diag_write_complete;
list_add_tail(&req->list, &ctxt->write_pool);
}
@@ -389,6 +391,7 @@
req = usb_ep_alloc_request(ctxt->out, GFP_ATOMIC);
if (!req)
goto fail;
+ kmemleak_not_leak(req);
req->complete = diag_read_complete;
list_add_tail(&req->list, &ctxt->read_pool);
}
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index ad09139..0a82e58 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -1013,9 +1013,6 @@
}
xhci = hcd_to_xhci(hcd);
- if (xhci->xhc_state & XHCI_STATE_HALTED)
- return -ENODEV;
-
if (check_virt_dev) {
if (!udev->slot_id || !xhci->devs[udev->slot_id]) {
printk(KERN_DEBUG "xHCI %s called with unaddressed "
@@ -1031,6 +1028,9 @@
}
}
+ if (xhci->xhc_state & XHCI_STATE_HALTED)
+ return -ENODEV;
+
return 1;
}
diff --git a/drivers/video/msm/mdss/dsi_host_v2.c b/drivers/video/msm/mdss/dsi_host_v2.c
index ca7f199..884f7f2 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.c
+++ b/drivers/video/msm/mdss/dsi_host_v2.c
@@ -1216,6 +1216,13 @@
mutex_unlock(&ctrl_pdata->mutex);
return ret;
}
+ pinfo->panel_power_on = 1;
+ ret = mdss_dsi_panel_reset(pdata, 1);
+ if (ret) {
+ pr_err("%s: Panel reset failed\n", __func__);
+ mutex_unlock(&ctrl_pdata->mutex);
+ return ret;
+ }
msm_dsi_ahb_ctrl(1);
msm_dsi_prepare_clocks();
diff --git a/drivers/video/msm/mdss/dsi_v2.c b/drivers/video/msm/mdss/dsi_v2.c
index ccde545..bc76fd0 100644
--- a/drivers/video/msm/mdss/dsi_v2.c
+++ b/drivers/video/msm/mdss/dsi_v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -66,6 +66,7 @@
if (enable) {
dsi_ctrl_gpio_request(ctrl_pdata);
mdss_dsi_panel_reset(pdata, 1);
+ pdata->panel_info.panel_power_on = 1;
rc = ctrl_pdata->on(pdata);
if (rc)
pr_err("dsi_panel_handler panel on failed %d\n", rc);
@@ -73,6 +74,7 @@
if (dsi_intf.op_mode_config)
dsi_intf.op_mode_config(DSI_CMD_MODE, pdata);
rc = ctrl_pdata->off(pdata);
+ pdata->panel_info.panel_power_on = 0;
mdss_dsi_panel_reset(pdata, 0);
dsi_ctrl_gpio_free(ctrl_pdata);
}
@@ -202,75 +204,23 @@
{
int rc = 0;
- if (gpio_is_valid(ctrl_pdata->disp_en_gpio)) {
- rc = gpio_request(ctrl_pdata->disp_en_gpio, "disp_enable");
- if (rc)
- goto gpio_request_err4;
-
- ctrl_pdata->disp_en_gpio_requested = 1;
- }
-
- if (gpio_is_valid(ctrl_pdata->rst_gpio)) {
- rc = gpio_request(ctrl_pdata->rst_gpio, "disp_rst_n");
- if (rc)
- goto gpio_request_err3;
-
- ctrl_pdata->rst_gpio_requested = 1;
- }
-
if (gpio_is_valid(ctrl_pdata->disp_te_gpio)) {
rc = gpio_request(ctrl_pdata->disp_te_gpio, "disp_te");
if (rc)
- goto gpio_request_err2;
-
- ctrl_pdata->disp_te_gpio_requested = 1;
+ ctrl_pdata->disp_te_gpio_requested = 0;
+ else
+ ctrl_pdata->disp_te_gpio_requested = 1;
}
- if (gpio_is_valid(ctrl_pdata->mode_gpio)) {
- rc = gpio_request(ctrl_pdata->mode_gpio, "panel_mode");
- if (rc)
- goto gpio_request_err1;
-
- ctrl_pdata->mode_gpio_requested = 1;
- }
-
- return rc;
-
-gpio_request_err1:
- if (gpio_is_valid(ctrl_pdata->disp_te_gpio))
- gpio_free(ctrl_pdata->disp_te_gpio);
-gpio_request_err2:
- if (gpio_is_valid(ctrl_pdata->rst_gpio))
- gpio_free(ctrl_pdata->rst_gpio);
-gpio_request_err3:
- if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
- gpio_free(ctrl_pdata->disp_en_gpio);
-gpio_request_err4:
- ctrl_pdata->disp_en_gpio_requested = 0;
- ctrl_pdata->rst_gpio_requested = 0;
- ctrl_pdata->disp_te_gpio_requested = 0;
- ctrl_pdata->mode_gpio_requested = 0;
return rc;
}
void dsi_ctrl_gpio_free(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
- if (ctrl_pdata->disp_en_gpio_requested) {
- gpio_free(ctrl_pdata->disp_en_gpio);
- ctrl_pdata->disp_en_gpio_requested = 0;
- }
- if (ctrl_pdata->rst_gpio_requested) {
- gpio_free(ctrl_pdata->rst_gpio);
- ctrl_pdata->rst_gpio_requested = 0;
- }
if (ctrl_pdata->disp_te_gpio_requested) {
gpio_free(ctrl_pdata->disp_te_gpio);
ctrl_pdata->disp_te_gpio_requested = 0;
}
- if (ctrl_pdata->mode_gpio_requested) {
- gpio_free(ctrl_pdata->mode_gpio);
- ctrl_pdata->mode_gpio_requested = 0;
- }
}
static int dsi_parse_vreg(struct device *dev, struct dss_module_power *mp)
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index b324130..1111aeb 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -798,7 +798,7 @@
rc = mdp3_dma->stop(mdp3_dma, mdp3_session->intf);
if (rc) {
- pr_err("fail to stop the MDP3 dma\n");
+ pr_err("fail to stop the MDP3 dma %d\n", rc);
goto reset_error;
}
@@ -1011,7 +1011,11 @@
panel = mdp3_session->panel;
if (!mdp3_iommu_is_attached(MDP3_CLIENT_DMA_P)) {
pr_debug("continuous splash screen, IOMMU not attached\n");
- mdp3_ctrl_reset(mfd);
+ rc = mdp3_ctrl_reset(mfd);
+ if (rc) {
+ pr_err("fail to reset display\n");
+ return -EINVAL;
+ }
reset_done = true;
}
@@ -1092,7 +1096,11 @@
if (!mdp3_iommu_is_attached(MDP3_CLIENT_DMA_P)) {
pr_debug("continuous splash screen, IOMMU not attached\n");
- mdp3_ctrl_reset(mfd);
+ rc = mdp3_ctrl_reset(mfd);
+ if (rc) {
+ pr_err("fail to reset display\n");
+ return;
+ }
}
mutex_lock(&mdp3_session->lock);
diff --git a/drivers/video/msm/mdss/mdp3_dma.c b/drivers/video/msm/mdss/mdp3_dma.c
index 800c4b3..993a36f 100644
--- a/drivers/video/msm/mdss/mdp3_dma.c
+++ b/drivers/video/msm/mdss/mdp3_dma.c
@@ -18,7 +18,7 @@
#include "mdp3_hwio.h"
#define DMA_STOP_POLL_SLEEP_US 1000
-#define DMA_STOP_POLL_TIMEOUT_US 32000
+#define DMA_STOP_POLL_TIMEOUT_US 200000
#define DMA_HISTO_RESET_TIMEOUT_MS 40
#define DMA_LUT_CONFIG_MASK 0xfffffbe8
#define DMA_CCS_CONFIG_MASK 0xfffffc17
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index ada1281..7e6faa8 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -192,6 +192,7 @@
int handoff_pending;
struct mdss_prefill_data prefill_data;
+ bool ulps;
};
extern struct mdss_data_type *mdss_res;
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index ece867c..7b4b065 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -72,13 +72,25 @@
goto error;
}
- if (pdata->panel_info.panel_power_on == 0)
- mdss_dsi_panel_reset(pdata, 1);
-
+ if (!pdata->panel_info.mipi.lp11_init) {
+ ret = mdss_dsi_panel_reset(pdata, 1);
+ if (ret) {
+ pr_err("%s: Panel reset failed. rc=%d\n",
+ __func__, ret);
+ if (msm_dss_enable_vreg(
+ ctrl_pdata->power_data.vreg_config,
+ ctrl_pdata->power_data.num_vreg, 0))
+ pr_err("Disable vregs failed\n");
+ goto error;
+ }
+ }
} else {
-
- mdss_dsi_panel_reset(pdata, 0);
-
+ ret = mdss_dsi_panel_reset(pdata, 0);
+ if (ret) {
+ pr_err("%s: Panel reset failed. rc=%d\n",
+ __func__, ret);
+ goto error;
+ }
ret = msm_dss_enable_vreg(
ctrl_pdata->power_data.vreg_config,
ctrl_pdata->power_data.num_vreg, 0);
@@ -296,7 +308,7 @@
if (!pdata->panel_info.panel_power_on) {
pr_warn("%s:%d Panel already off.\n", __func__, __LINE__);
- return -EPERM;
+ return 0;
}
pdata->panel_info.panel_power_on = 0;
@@ -335,63 +347,22 @@
return ret;
}
-int mdss_dsi_on(struct mdss_panel_data *pdata)
+static void __mdss_dsi_ctrl_setup(struct mdss_panel_data *pdata)
{
- int ret = 0;
- u32 clk_rate;
+ struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
struct mdss_panel_info *pinfo;
struct mipi_panel_info *mipi;
+ u32 clk_rate;
u32 hbp, hfp, vbp, vfp, hspw, vspw, width, height;
u32 ystride, bpp, data, dst_bpp;
u32 dummy_xres, dummy_yres;
- struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
u32 hsync_period, vsync_period;
- if (pdata == NULL) {
- pr_err("%s: Invalid input data\n", __func__);
- return -EINVAL;
- }
-
- if (pdata->panel_info.panel_power_on) {
- pr_warn("%s:%d Panel already on.\n", __func__, __LINE__);
- return 0;
- }
-
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
panel_data);
- pr_debug("%s+: ctrl=%p ndx=%d\n",
- __func__, ctrl_pdata, ctrl_pdata->ndx);
-
pinfo = &pdata->panel_info;
- ret = msm_dss_enable_vreg(ctrl_pdata->power_data.vreg_config,
- ctrl_pdata->power_data.num_vreg, 1);
- if (ret) {
- pr_err("%s:Failed to enable vregs. rc=%d\n", __func__, ret);
- return ret;
- }
-
- pdata->panel_info.panel_power_on = 1;
-
- if (!pdata->panel_info.mipi.lp11_init)
- mdss_dsi_panel_reset(pdata, 1);
-
- ret = mdss_dsi_bus_clk_start(ctrl_pdata);
- if (ret) {
- pr_err("%s: failed to enable bus clocks. rc=%d\n", __func__,
- ret);
- mdss_dsi_panel_power_on(pdata, 0);
- pdata->panel_info.panel_power_on = 0;
- return ret;
- }
-
- mdss_dsi_phy_sw_reset((ctrl_pdata->ctrl_base));
- mdss_dsi_phy_init(pdata);
- mdss_dsi_bus_clk_stop(ctrl_pdata);
-
- mdss_dsi_clk_ctrl(ctrl_pdata, 1);
-
clk_rate = pdata->panel_info.clk_rate;
clk_rate = min(clk_rate, pdata->panel_info.clk_max);
@@ -421,7 +392,7 @@
vsync_period = vspw + vbp + height + dummy_yres + vfp;
hsync_period = hspw + hbp + width + dummy_xres + hfp;
- mipi = &pdata->panel_info.mipi;
+ mipi = &pdata->panel_info.mipi;
if (pdata->panel_info.type == MIPI_VIDEO_PANEL) {
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x24,
((hspw + hbp + width + dummy_xres) << 16 |
@@ -459,19 +430,195 @@
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x64, data);
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x5C, data);
}
+}
+static inline bool __mdss_dsi_ulps_feature_enabled(
+ struct mdss_panel_data *pdata)
+{
+ return pdata->panel_info.ulps_feature_enabled;
+}
+
+static int mdss_dsi_ulps_config_sub(struct mdss_dsi_ctrl_pdata *ctrl_pdata,
+ int enable)
+{
+ int ret = 0;
+ struct mdss_panel_data *pdata = NULL;
+ u32 lane_status = 0;
+
+ if (!ctrl_pdata) {
+ pr_err("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ pdata = &ctrl_pdata->panel_data;
+
+ if (!__mdss_dsi_ulps_feature_enabled(pdata)) {
+ pr_debug("%s: ULPS feature not supported. enable=%d\n",
+ __func__, enable);
+ return -ENOTSUPP;
+ }
+
+ if (enable && !ctrl_pdata->ulps) {
+ /* No need to configure ULPS mode when entering suspend state */
+ if (!pdata->panel_info.panel_power_on) {
+ pr_err("%s: panel off. returning\n", __func__);
+ goto error;
+ }
+
+ if (__mdss_dsi_clk_enabled(ctrl_pdata)) {
+ pr_err("%s: cannot enter ulps mode if dsi clocks are on\n",
+ __func__);
+ ret = -EPERM;
+ goto error;
+ }
+
+ mdss_dsi_clk_ctrl(ctrl_pdata, 1);
+ /*
+ * ULPS Entry Request.
+ * Wait for a short duration to ensure that the lanes
+ * enter ULP state.
+ */
+ MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, 0x01F);
+ usleep(100);
+
+ /* Enable MMSS DSI Clamps */
+ MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14, 0x3FF);
+ MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14, 0x83FF);
+
+ wmb();
+
+ MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x108, 0x1);
+ /* disable DSI controller */
+ mdss_dsi_controller_cfg(0, pdata);
+
+ lane_status = MIPI_INP(ctrl_pdata->ctrl_base + 0xA8),
+ mdss_dsi_clk_ctrl(ctrl_pdata, 0);
+ ctrl_pdata->ulps = true;
+ } else if (ctrl_pdata->ulps) {
+ mdss_dsi_phy_init(pdata);
+
+ __mdss_dsi_ctrl_setup(pdata);
+ mdss_dsi_sw_reset(pdata);
+ mdss_dsi_host_init(pdata);
+ mdss_dsi_op_mode_config(pdata->panel_info.mipi.mode,
+ pdata);
+
+ /* Disable MMSS DSI Clamps */
+ MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14, 0x0);
+
+ /*
+ * ULPS Exit Request
+ * Hardware requirement is to wait for at least 1ms
+ */
+ MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, 0x1F00);
+ usleep(1000);
+ MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, 0x0);
+
+ /*
+ * Wait for a short duration before enabling
+ * data transmission
+ */
+ usleep(100);
+
+ lane_status = MIPI_INP(ctrl_pdata->ctrl_base + 0xA8),
+ ctrl_pdata->ulps = false;
+ }
+
+ pr_debug("%s: DSI lane status = 0x%08x. Ulps %s\n", __func__,
+ lane_status, enable ? "enabled" : "disabled");
+
+error:
+ return ret;
+}
+
+static int mdss_dsi_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl,
+ int enable)
+{
+ int rc;
+ struct mdss_dsi_ctrl_pdata *sctrl = NULL;
+
+ if (ctrl->flags & DSI_FLAG_CLOCK_MASTER)
+ sctrl = mdss_dsi_ctrl_slave(ctrl);
+
+ if (sctrl) {
+ pr_debug("%s: configuring ulps (%s) for slave ctrl\n",
+ __func__, (enable ? "on" : "off"));
+ rc = mdss_dsi_ulps_config_sub(sctrl, enable);
+ if (rc)
+ return rc;
+ }
+
+ pr_debug("%s: configuring ulps (%s) for master ctrl\n",
+ __func__, (enable ? "on" : "off"));
+ return mdss_dsi_ulps_config_sub(ctrl, enable);
+}
+
+int mdss_dsi_on(struct mdss_panel_data *pdata)
+{
+ int ret = 0;
+ struct mdss_panel_info *pinfo;
+ struct mipi_panel_info *mipi;
+ struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+
+ if (pdata == NULL) {
+ pr_err("%s: Invalid input data\n", __func__);
+ return -EINVAL;
+ }
+
+ if (pdata->panel_info.panel_power_on) {
+ pr_warn("%s:%d Panel already on.\n", __func__, __LINE__);
+ return 0;
+ }
+
+ ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+ panel_data);
+
+ pr_debug("%s+: ctrl=%p ndx=%d\n",
+ __func__, ctrl_pdata, ctrl_pdata->ndx);
+
+ pinfo = &pdata->panel_info;
+ mipi = &pdata->panel_info.mipi;
+
+ ret = mdss_dsi_panel_power_on(pdata, 1);
+ if (ret) {
+ pr_err("%s:Panel power on failed. rc=%d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = mdss_dsi_bus_clk_start(ctrl_pdata);
+ if (ret) {
+ pr_err("%s: failed to enable bus clocks. rc=%d\n", __func__,
+ ret);
+ ret = mdss_dsi_panel_power_on(pdata, 0);
+ if (ret) {
+ pr_err("%s: Panel reset failed. rc=%d\n",
+ __func__, ret);
+ return ret;
+ }
+ pdata->panel_info.panel_power_on = 0;
+ return ret;
+ }
+ pdata->panel_info.panel_power_on = 1;
+
+ mdss_dsi_phy_sw_reset((ctrl_pdata->ctrl_base));
+ mdss_dsi_phy_init(pdata);
+ mdss_dsi_bus_clk_stop(ctrl_pdata);
+
+ mdss_dsi_clk_ctrl(ctrl_pdata, 1);
+
+ __mdss_dsi_ctrl_setup(pdata);
mdss_dsi_sw_reset(pdata);
- mdss_dsi_host_init(mipi, pdata);
+ mdss_dsi_host_init(pdata);
/*
* Issue hardware reset line after enabling the DSI clocks and data
* data lanes for LP11 init
*/
- if (pdata->panel_info.mipi.lp11_init)
+ if (mipi->lp11_init)
mdss_dsi_panel_reset(pdata, 1);
- if (pdata->panel_info.mipi.init_delay)
- usleep(pdata->panel_info.mipi.init_delay);
+ if (mipi->init_delay)
+ usleep(mipi->init_delay);
if (mipi->force_clk_lane_hs) {
u32 tmp;
@@ -545,6 +692,17 @@
panel_data);
mipi = &pdata->panel_info.mipi;
+ if (__mdss_dsi_ulps_feature_enabled(pdata) &&
+ (ctrl_pdata->ulps)) {
+ /* Disable ULPS mode before blanking the panel */
+ ret = mdss_dsi_ulps_config(ctrl_pdata, 0);
+ if (ret) {
+ pr_err("%s: failed to exit ULPS mode. rc=%d\n",
+ __func__, ret);
+ return ret;
+ }
+ }
+
mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata);
if (pdata->panel_info.type == MIPI_CMD_PANEL) {
@@ -591,7 +749,7 @@
"Incorrect Ctrl state=0x%x\n", ctrl_pdata->ctrl_state);
mdss_dsi_sw_reset(pdata);
- mdss_dsi_host_init(mipi, pdata);
+ mdss_dsi_host_init(pdata);
mdss_dsi_op_mode_config(mipi->mode, pdata);
if (ctrl_pdata->on_cmds.link_state == DSI_LP_MODE) {
@@ -798,6 +956,9 @@
case MDSS_EVENT_ENABLE_PARTIAL_UPDATE:
rc = mdss_dsi_ctl_partial_update(pdata);
break;
+ case MDSS_EVENT_DSI_ULPS_CTRL:
+ rc = mdss_dsi_ulps_config(ctrl_pdata, (int)arg);
+ break;
default:
pr_debug("%s: unhandled event=%d\n", __func__, event);
break;
@@ -1028,6 +1189,7 @@
pr_err("%s: failed to de-init vregs\n", __func__);
mdss_dsi_put_dt_vreg_data(&pdev->dev, &ctrl_pdata->power_data);
mfd = platform_get_drvdata(pdev);
+ msm_dss_iounmap(&ctrl_pdata->mmss_misc_io);
return 0;
}
@@ -1086,6 +1248,13 @@
pr_info("%s: dsi base=%x size=%x\n",
__func__, (int)ctrl->ctrl_base, ctrl->reg_size);
+ rc = msm_dss_ioremap_byname(pdev, &ctrl->mmss_misc_io,
+ "mmss_misc_phys");
+ if (rc) {
+ pr_err("%s:%d mmss_misc IO remap failed\n", __func__, __LINE__);
+ return rc;
+ }
+
return 0;
}
@@ -1223,18 +1392,9 @@
ctrl_pdata->disp_en_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node,
"qcom,platform-enable-gpio", 0);
- if (!gpio_is_valid(ctrl_pdata->disp_en_gpio)) {
+ if (!gpio_is_valid(ctrl_pdata->disp_en_gpio))
pr_err("%s:%d, Disp_en gpio not specified\n",
__func__, __LINE__);
- } else {
- rc = gpio_request(ctrl_pdata->disp_en_gpio, "disp_enable");
- if (rc) {
- pr_err("request reset gpio failed, rc=%d\n",
- rc);
- gpio_free(ctrl_pdata->disp_en_gpio);
- return -ENODEV;
- }
- }
if (pinfo->type == MIPI_CMD_PANEL) {
ctrl_pdata->disp_te_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node,
@@ -1251,7 +1411,6 @@
if (rc) {
pr_err("request TE gpio failed, rc=%d\n",
rc);
- gpio_free(ctrl_pdata->disp_te_gpio);
return -ENODEV;
}
rc = gpio_tlmm_config(GPIO_CFG(
@@ -1281,44 +1440,18 @@
ctrl_pdata->rst_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node,
"qcom,platform-reset-gpio", 0);
- if (!gpio_is_valid(ctrl_pdata->rst_gpio)) {
+ if (!gpio_is_valid(ctrl_pdata->rst_gpio))
pr_err("%s:%d, reset gpio not specified\n",
__func__, __LINE__);
- } else {
- rc = gpio_request(ctrl_pdata->rst_gpio, "disp_rst_n");
- if (rc) {
- pr_err("request reset gpio failed, rc=%d\n",
- rc);
- gpio_free(ctrl_pdata->rst_gpio);
- if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
- gpio_free(ctrl_pdata->disp_en_gpio);
- return -ENODEV;
- }
- }
if (pinfo->mode_gpio_state != MODE_GPIO_NOT_VALID) {
ctrl_pdata->mode_gpio = of_get_named_gpio(
ctrl_pdev->dev.of_node,
"qcom,platform-mode-gpio", 0);
- if (!gpio_is_valid(ctrl_pdata->mode_gpio)) {
+ if (!gpio_is_valid(ctrl_pdata->mode_gpio))
pr_info("%s:%d, mode gpio not specified\n",
__func__, __LINE__);
- } else {
- rc = gpio_request(ctrl_pdata->mode_gpio, "panel_mode");
- if (rc) {
- pr_err("request panel mode gpio failed,rc=%d\n",
- rc);
- gpio_free(ctrl_pdata->mode_gpio);
- if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
- gpio_free(ctrl_pdata->disp_en_gpio);
- if (gpio_is_valid(ctrl_pdata->rst_gpio))
- gpio_free(ctrl_pdata->rst_gpio);
- if (gpio_is_valid(ctrl_pdata->disp_te_gpio))
- gpio_free(ctrl_pdata->disp_te_gpio);
- return -ENODEV;
- }
- }
}
if (mdss_dsi_clk_init(ctrl_pdev, ctrl_pdata)) {
@@ -1369,10 +1502,6 @@
rc = mdss_register_panel(ctrl_pdev, &(ctrl_pdata->panel_data));
if (rc) {
pr_err("%s: unable to register MIPI DSI panel\n", __func__);
- if (ctrl_pdata->rst_gpio)
- gpio_free(ctrl_pdata->rst_gpio);
- if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
- gpio_free(ctrl_pdata->disp_en_gpio);
return rc;
}
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index 2c9c37d..57b0e75 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -238,6 +238,7 @@
int (*cmdlist_commit)(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
struct mdss_panel_data panel_data;
unsigned char *ctrl_base;
+ struct dss_io_data mmss_misc_io;
int reg_size;
u32 clk_cnt;
int clk_cnt_sub;
@@ -245,6 +246,7 @@
struct clk *mdp_core_clk;
struct clk *ahb_clk;
struct clk *axi_clk;
+ struct clk *mmss_misc_ahb_clk;
struct clk *byte_clk;
struct clk *esc_clk;
struct clk *pixel_clk;
@@ -256,10 +258,7 @@
int disp_en_gpio;
int disp_te_gpio;
int mode_gpio;
- int rst_gpio_requested;
- int disp_en_gpio_requested;
int disp_te_gpio_requested;
- int mode_gpio_requested;
int bklt_ctrl; /* backlight ctrl */
int pwm_period;
int pwm_pmic_gpio;
@@ -290,6 +289,8 @@
struct mutex mutex;
struct mutex cmd_mutex;
+ bool ulps;
+
struct dsi_buf tx_buf;
struct dsi_buf rx_buf;
};
@@ -303,8 +304,7 @@
int mdss_dsi_cmds_rx(struct mdss_dsi_ctrl_pdata *ctrl,
struct dsi_cmd_desc *cmds, int rlen);
-void mdss_dsi_host_init(struct mipi_panel_info *pinfo,
- struct mdss_panel_data *pdata);
+void mdss_dsi_host_init(struct mdss_panel_data *pdata);
void mdss_dsi_op_mode_config(int mode,
struct mdss_panel_data *pdata);
void mdss_dsi_cmd_mode_ctrl(int enable);
@@ -337,7 +337,7 @@
void mdss_dsi_clk_deinit(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
int mdss_dsi_enable_bus_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
void mdss_dsi_disable_bus_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
-void mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable);
+int mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable);
void mdss_dsi_phy_disable(struct mdss_dsi_ctrl_pdata *ctrl);
void mdss_dsi_phy_init(struct mdss_panel_data *pdata);
void mdss_dsi_phy_sw_reset(unsigned char *ctrl_base);
@@ -351,6 +351,7 @@
int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
void mdss_dsi_cmdlist_kickoff(int intf);
int mdss_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl);
+bool __mdss_dsi_clk_enabled(struct mdss_dsi_ctrl_pdata *ctrl);
int mdss_dsi_panel_init(struct device_node *node,
struct mdss_dsi_ctrl_pdata *ctrl_pdata,
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index b4478ac..c2fbc1a 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -250,12 +250,12 @@
MIPI_OUTP((ctrl->ctrl_base) + 0x015c, 0x0);
}
-void mdss_dsi_host_init(struct mipi_panel_info *pinfo,
- struct mdss_panel_data *pdata)
+void mdss_dsi_host_init(struct mdss_panel_data *pdata)
{
u32 dsi_ctrl, intr_ctrl;
u32 data;
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+ struct mipi_panel_info *pinfo = NULL;
if (pdata == NULL) {
pr_err("%s: Invalid input data\n", __func__);
@@ -265,6 +265,8 @@
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
panel_data);
+ pinfo = &pdata->panel_info.mipi;
+
pinfo->rgb_swap = DSI_RGB_SWAP_RGB;
ctrl_pdata->panel_mode = pinfo->mode;
@@ -1477,7 +1479,9 @@
u32 isr0;
isr0 = MIPI_INP(left_ctrl_pdata->ctrl_base
+ 0x0110);/* DSI_INTR_CTRL */
- MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0110, isr0);
+ if (isr0 & DSI_INTR_CMD_DMA_DONE)
+ MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0110,
+ DSI_INTR_CMD_DMA_DONE);
}
pr_debug("%s: ndx=%d isr=%x\n", __func__, ctrl->ndx, isr);
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index 7abb761..5415a7e 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -153,15 +153,53 @@
mdss_dsi_cmdlist_put(ctrl, &cmdreq);
}
-void mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable)
+static int mdss_dsi_request_gpios(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+{
+ int rc = 0;
+
+ if (gpio_is_valid(ctrl_pdata->disp_en_gpio)) {
+ rc = gpio_request(ctrl_pdata->disp_en_gpio,
+ "disp_enable");
+ if (rc) {
+ pr_err("request disp_en gpio failed, rc=%d\n",
+ rc);
+ goto disp_en_gpio_err;
+ }
+ }
+ rc = gpio_request(ctrl_pdata->rst_gpio, "disp_rst_n");
+ if (rc) {
+ pr_err("request reset gpio failed, rc=%d\n",
+ rc);
+ goto rst_gpio_err;
+ }
+ if (gpio_is_valid(ctrl_pdata->mode_gpio)) {
+ rc = gpio_request(ctrl_pdata->mode_gpio, "panel_mode");
+ if (rc) {
+ pr_err("request panel mode gpio failed,rc=%d\n",
+ rc);
+ goto mode_gpio_err;
+ }
+ }
+ return rc;
+
+mode_gpio_err:
+ gpio_free(ctrl_pdata->rst_gpio);
+rst_gpio_err:
+ if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
+ gpio_free(ctrl_pdata->disp_en_gpio);
+disp_en_gpio_err:
+ return rc;
+}
+
+int mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable)
{
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
struct mdss_panel_info *pinfo = NULL;
- int i;
+ int i, rc = 0;
if (pdata == NULL) {
pr_err("%s: Invalid input data\n", __func__);
- return;
+ return -EINVAL;
}
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
@@ -175,21 +213,28 @@
if (!gpio_is_valid(ctrl_pdata->rst_gpio)) {
pr_debug("%s:%d, reset line not configured\n",
__func__, __LINE__);
- return;
+ return rc;
}
pr_debug("%s: enable = %d\n", __func__, enable);
pinfo = &(ctrl_pdata->panel_data.panel_info);
if (enable) {
- if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
- gpio_set_value((ctrl_pdata->disp_en_gpio), 1);
+ rc = mdss_dsi_request_gpios(ctrl_pdata);
+ if (rc) {
+ pr_err("gpio request failed\n");
+ return rc;
+ }
+ if (!pinfo->panel_power_on) {
+ if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
+ gpio_set_value((ctrl_pdata->disp_en_gpio), 1);
- for (i = 0; i < pdata->panel_info.rst_seq_len; ++i) {
- gpio_set_value((ctrl_pdata->rst_gpio),
- pdata->panel_info.rst_seq[i]);
- if (pdata->panel_info.rst_seq[++i])
- usleep(pdata->panel_info.rst_seq[i] * 1000);
+ for (i = 0; i < pdata->panel_info.rst_seq_len; ++i) {
+ gpio_set_value((ctrl_pdata->rst_gpio),
+ pdata->panel_info.rst_seq[i]);
+ if (pdata->panel_info.rst_seq[++i])
+ usleep(pinfo->rst_seq[i] * 1000);
+ }
}
if (gpio_is_valid(ctrl_pdata->mode_gpio)) {
@@ -205,10 +250,16 @@
pr_debug("%s: Reset panel done\n", __func__);
}
} else {
- gpio_set_value((ctrl_pdata->rst_gpio), 0);
- if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
+ if (gpio_is_valid(ctrl_pdata->disp_en_gpio)) {
gpio_set_value((ctrl_pdata->disp_en_gpio), 0);
+ gpio_free(ctrl_pdata->disp_en_gpio);
+ }
+ gpio_set_value((ctrl_pdata->rst_gpio), 0);
+ gpio_free(ctrl_pdata->rst_gpio);
+ if (gpio_is_valid(ctrl_pdata->mode_gpio))
+ gpio_free(ctrl_pdata->mode_gpio);
}
+ return rc;
}
static char caset[] = {0x2a, 0x00, 0x00, 0x03, 0x00}; /* DTYPE_DCS_LWRITE */
@@ -266,6 +317,17 @@
return rc;
}
+static struct mdss_dsi_ctrl_pdata *get_rctrl_data(struct mdss_panel_data *pdata)
+{
+ if (!pdata || !pdata->next) {
+ pr_err("%s: Invalid panel data\n", __func__);
+ return NULL;
+ }
+
+ return container_of(pdata->next, struct mdss_dsi_ctrl_pdata,
+ panel_data);
+}
+
static void mdss_dsi_panel_bl_ctrl(struct mdss_panel_data *pdata,
u32 bl_level)
{
@@ -297,6 +359,16 @@
break;
case BL_DCS_CMD:
mdss_dsi_panel_bklt_dcs(ctrl_pdata, bl_level);
+ if (ctrl_pdata->shared_pdata.broadcast_enable &&
+ ctrl_pdata->ndx == DSI_CTRL_0) {
+ struct mdss_dsi_ctrl_pdata *rctrl_pdata = NULL;
+ rctrl_pdata = get_rctrl_data(pdata);
+ if (!rctrl_pdata) {
+ pr_err("%s: Right ctrl data NULL\n", __func__);
+ return;
+ }
+ mdss_dsi_panel_bklt_dcs(rctrl_pdata, bl_level);
+ }
break;
default:
pr_err("%s: Unknown bl_ctrl configuration\n",
@@ -632,6 +704,35 @@
return 0;
}
+static int mdss_dsi_parse_panel_features(struct device_node *np,
+ struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ struct mdss_panel_info *pinfo;
+
+ if (!np || !ctrl) {
+ pr_err("%s: Invalid arguments\n", __func__);
+ return -ENODEV;
+ }
+
+ pinfo = &ctrl->panel_data.panel_info;
+
+ pinfo->cont_splash_enabled = of_property_read_bool(np,
+ "qcom,cont-splash-enabled");
+
+ pinfo->partial_update_enabled = of_property_read_bool(np,
+ "qcom,partial-update-enabled");
+ pr_info("%s:%d Partial update %s\n", __func__, __LINE__,
+ (pinfo->partial_update_enabled ? "enabled" : "disabled"));
+ if (pinfo->partial_update_enabled)
+ ctrl->partial_update_fnc = mdss_dsi_panel_partial_update;
+
+ pinfo->ulps_feature_enabled = of_property_read_bool(np,
+ "qcom,ulps-enabled");
+ pr_info("%s: ulps feature %s", __func__,
+ (pinfo->ulps_feature_enabled ? "enabled" : "disabled"));
+
+ return 0;
+}
static int mdss_panel_parse_dt(struct device_node *np,
struct mdss_dsi_ctrl_pdata *ctrl_pdata)
@@ -911,6 +1012,12 @@
mdss_dsi_parse_dcs_cmds(np, &ctrl_pdata->off_cmds,
"qcom,mdss-dsi-off-command", "qcom,mdss-dsi-off-command-state");
+ rc = mdss_dsi_parse_panel_features(np, ctrl_pdata);
+ if (rc) {
+ pr_err("%s: failed to parse panel features\n", __func__);
+ goto error;
+ }
+
return 0;
error:
@@ -923,14 +1030,15 @@
{
int rc = 0;
static const char *panel_name;
- bool cont_splash_enabled;
- bool partial_update_enabled;
+ struct mdss_panel_info *pinfo;
- if (!node) {
- pr_err("%s: no panel node\n", __func__);
+ if (!node || !ctrl_pdata) {
+ pr_err("%s: Invalid arguments\n", __func__);
return -ENODEV;
}
+ pinfo = &ctrl_pdata->panel_data.panel_info;
+
pr_debug("%s:%d\n", __func__, __LINE__);
panel_name = of_get_property(node, "qcom,mdss-dsi-panel-name", NULL);
if (!panel_name)
@@ -945,33 +1053,10 @@
return rc;
}
- if (cmd_cfg_cont_splash)
- cont_splash_enabled = of_property_read_bool(node,
- "qcom,cont-splash-enabled");
- else
- cont_splash_enabled = false;
- if (!cont_splash_enabled) {
- pr_info("%s:%d Continuous splash flag not found.\n",
- __func__, __LINE__);
- ctrl_pdata->panel_data.panel_info.cont_splash_enabled = 0;
- } else {
- pr_info("%s:%d Continuous splash flag enabled.\n",
- __func__, __LINE__);
-
- ctrl_pdata->panel_data.panel_info.cont_splash_enabled = 1;
- }
-
- partial_update_enabled = of_property_read_bool(node,
- "qcom,partial-update-enabled");
- if (partial_update_enabled) {
- pr_info("%s:%d Partial update enabled.\n", __func__, __LINE__);
- ctrl_pdata->panel_data.panel_info.partial_update_enabled = 1;
- ctrl_pdata->partial_update_fnc = mdss_dsi_panel_partial_update;
- } else {
- pr_info("%s:%d Partial update disabled.\n", __func__, __LINE__);
- ctrl_pdata->panel_data.panel_info.partial_update_enabled = 0;
- ctrl_pdata->partial_update_fnc = NULL;
- }
+ if (!cmd_cfg_cont_splash)
+ pinfo->cont_splash_enabled = false;
+ pr_info("%s: Continuous splash %s", __func__,
+ pinfo->cont_splash_enabled ? "enabled" : "disabled");
ctrl_pdata->on = mdss_dsi_panel_on;
ctrl_pdata->off = mdss_dsi_panel_off;
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 3bace66..252a86e 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -1214,9 +1214,11 @@
struct mdss_fb_proc_info *pinfo = NULL;
int result;
int pid = current->tgid;
+ struct task_struct *task = current->group_leader;
if (mfd->shutdown_pending) {
- pr_err("Shutdown pending. Aborting operation\n");
+ pr_err("Shutdown pending. Aborting operation. Request from pid:%d name=%s\n",
+ pid, task->comm);
return -EPERM;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index e1786a6..cfa594c 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -2405,8 +2405,10 @@
pr_debug("Enable MDP FS\n");
if (!mdata->fs_ena) {
regulator_enable(mdata->fs);
- mdss_mdp_cx_ctrl(mdata, true);
- mdss_mdp_batfet_ctrl(mdata, true);
+ if (!mdata->ulps) {
+ mdss_mdp_cx_ctrl(mdata, true);
+ mdss_mdp_batfet_ctrl(mdata, true);
+ }
}
mdata->fs_ena = true;
} else {
@@ -2414,13 +2416,41 @@
mdss_iommu_dettach(mdata);
if (mdata->fs_ena) {
regulator_disable(mdata->fs);
- mdss_mdp_cx_ctrl(mdata, false);
- mdss_mdp_batfet_ctrl(mdata, false);
+ if (!mdata->ulps) {
+ mdss_mdp_cx_ctrl(mdata, false);
+ mdss_mdp_batfet_ctrl(mdata, false);
+ }
}
mdata->fs_ena = false;
}
}
+/**
+ * mdss_mdp_footswitch_ctrl_ulps() - MDSS GDSC control with ULPS feature
+ * @on: 1 to turn on footswitch, 0 to turn off footswitch
+ * @dev: framebuffer device node
+ *
+ * MDSS GDSC can be voted off during idle-screen usecase for MIPI DSI command
+ * mode displays with Ultra-Low Power State (ULPS) feature enabled. Upon
+ * subsequent frame update, MDSS GDSC needs to turned back on and hw state
+ * needs to be restored.
+ */
+void mdss_mdp_footswitch_ctrl_ulps(int on, struct device *dev)
+{
+ struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+
+ pr_debug("called on=%d\n", on);
+ if (on) {
+ pm_runtime_get_sync(dev);
+ mdss_iommu_attach(mdata);
+ mdss_hw_init(mdata);
+ mdata->ulps = false;
+ } else {
+ mdata->ulps = true;
+ pm_runtime_put_sync(dev);
+ }
+}
+
static inline int mdss_mdp_suspend_sub(struct mdss_data_type *mdata)
{
mdata->suspend_fs_ena = mdata->fs_ena;
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 3afb27e..9a469a4 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -681,6 +681,8 @@
int mdss_mdp_wb_set_secure(struct msm_fb_data_type *mfd, int enable);
int mdss_mdp_wb_get_secure(struct msm_fb_data_type *mfd, uint8_t *enable);
+void mdss_mdp_ctl_restore(struct mdss_mdp_ctl *ctl);
+void mdss_mdp_footswitch_ctrl_ulps(int on, struct device *dev);
int mdss_mdp_pipe_program_pixel_extn(struct mdss_mdp_pipe *pipe);
#define mfd_to_mdp5_data(mfd) (mfd->mdp.private1)
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index b445afa..fa64448 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -1588,6 +1588,25 @@
return rc;
}
+/*
+ * mdss_mdp_ctl_restore() - restore mdp ctl path
+ * @ctl: mdp controller.
+ *
+ * This function is called whenever MDP comes out of a power collapse as
+ * a result of a screen update when DSI ULPS mode is enabled. It restores
+ * the MDP controller's software state to the hardware registers.
+ */
+void mdss_mdp_ctl_restore(struct mdss_mdp_ctl *ctl)
+{
+ u32 temp;
+
+ temp = readl_relaxed(ctl->mdata->mdp_base +
+ MDSS_MDP_REG_DISP_INTF_SEL);
+ temp |= (ctl->intf_type << ((ctl->intf_num - MDSS_MDP_INTF0) * 8));
+ writel_relaxed(temp, ctl->mdata->mdp_base +
+ MDSS_MDP_REG_DISP_INTF_SEL);
+}
+
static int mdss_mdp_ctl_start_sub(struct mdss_mdp_ctl *ctl, bool handoff)
{
struct mdss_mdp_mixer *mixer;
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
index 79bdee2..8c7dc29 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
@@ -27,6 +27,7 @@
#define KOFF_TIMEOUT msecs_to_jiffies(84)
#define STOP_TIMEOUT msecs_to_jiffies(16 * (VSYNC_EXPIRE_TICK + 2))
+#define ULPS_ENTER_TIME msecs_to_jiffies(100)
struct mdss_mdp_cmd_ctx {
struct mdss_mdp_ctl *ctl;
@@ -43,6 +44,7 @@
struct mutex clk_mtx;
spinlock_t clk_lock;
struct work_struct clk_work;
+ struct delayed_work ulps_work;
struct work_struct pp_done_work;
atomic_t pp_done_cnt;
@@ -53,6 +55,7 @@
u16 start_threshold;
u32 vclk_line; /* vsync clock per line */
struct mdss_panel_recovery recovery;
+ bool ulps;
};
struct mdss_mdp_cmd_ctx mdss_mdp_cmd_ctx_list[MAX_SESSIONS];
@@ -200,8 +203,19 @@
mutex_lock(&ctx->clk_mtx);
if (!ctx->clk_enabled) {
ctx->clk_enabled = 1;
+ if (cancel_delayed_work_sync(&ctx->ulps_work))
+ pr_debug("deleted pending ulps work\n");
mdss_mdp_ctl_intf_event
(ctx->ctl, MDSS_EVENT_PANEL_CLK_CTRL, (void *)1);
+
+ if (ctx->ulps) {
+ if (mdss_mdp_cmd_tearcheck_setup(ctx->ctl, 1))
+ pr_warn("tearcheck setup failed\n");
+ mdss_mdp_ctl_intf_event(ctx->ctl,
+ MDSS_EVENT_DSI_ULPS_CTRL, (void *)0);
+ ctx->ulps = false;
+ }
+
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
mdss_mdp_hist_intr_setup(&mdata->hist_intr, MDSS_IRQ_RESUME);
}
@@ -231,6 +245,8 @@
mdss_mdp_ctl_intf_event
(ctx->ctl, MDSS_EVENT_PANEL_CLK_CTRL, (void *)0);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ if (ctx->panel_on)
+ schedule_delayed_work(&ctx->ulps_work, ULPS_ENTER_TIME);
}
mutex_unlock(&ctx->clk_mtx);
}
@@ -365,6 +381,38 @@
mdss_mdp_cmd_clk_off(ctx);
}
+static void __mdss_mdp_cmd_ulps_work(struct work_struct *work)
+{
+ struct delayed_work *dw = to_delayed_work(work);
+ struct mdss_mdp_cmd_ctx *ctx =
+ container_of(dw, struct mdss_mdp_cmd_ctx, ulps_work);
+
+ if (!ctx) {
+ pr_err("%s: invalid ctx\n", __func__);
+ return;
+ }
+
+ mutex_lock(&ctx->clk_mtx);
+ if (ctx->clk_enabled) {
+ mutex_unlock(&ctx->clk_mtx);
+ pr_warn("Cannot enter ulps mode if DSI clocks are on\n");
+ return;
+ }
+ mutex_unlock(&ctx->clk_mtx);
+
+ if (!ctx->panel_on) {
+ pr_err("Panel is off. skipping ULPS configuration\n");
+ return;
+ }
+
+ if (!mdss_mdp_ctl_intf_event(ctx->ctl, MDSS_EVENT_DSI_ULPS_CTRL,
+ (void *)1)) {
+ ctx->ulps = true;
+ ctx->ctl->play_cnt = 0;
+ mdss_mdp_footswitch_ctrl_ulps(0, &ctx->ctl->mfd->pdev->dev);
+ }
+}
+
static int mdss_mdp_cmd_add_vsync_handler(struct mdss_mdp_ctl *ctl,
struct mdss_mdp_vsync_handler *handle)
{
@@ -583,11 +631,14 @@
if (cancel_work_sync(&ctx->clk_work))
pr_debug("no pending clk work\n");
+ if (cancel_delayed_work_sync(&ctx->ulps_work))
+ pr_debug("deleted pending ulps work\n");
+
+ ctx->panel_on = 0;
mdss_mdp_cmd_clk_off(ctx);
flush_work(&ctx->pp_done_work);
- ctx->panel_on = 0;
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctx->pp_num,
NULL, NULL);
@@ -653,6 +704,7 @@
spin_lock_init(&ctx->clk_lock);
mutex_init(&ctx->clk_mtx);
INIT_WORK(&ctx->clk_work, clk_ctrl_work);
+ INIT_DELAYED_WORK(&ctx->ulps_work, __mdss_mdp_cmd_ulps_work);
INIT_WORK(&ctx->pp_done_work, pingpong_done_work);
atomic_set(&ctx->pp_done_cnt, 0);
INIT_LIST_HEAD(&ctx->vsync_handlers);
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 4a71a84..7420f95 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -847,6 +847,11 @@
struct mdss_mdp_ctl *ctl = mdp5_data->ctl;
if (ctl->power_on) {
+ if (mdp5_data->mdata->ulps) {
+ mdss_mdp_footswitch_ctrl_ulps(1, &mfd->pdev->dev);
+ mdss_mdp_ctl_restore(ctl);
+ }
+
if (!mdp5_data->mdata->batfet)
mdss_mdp_batfet_ctrl(mdp5_data->mdata, true);
if (!mfd->panel_info->cont_splash_enabled)
@@ -1042,11 +1047,13 @@
pipe->mixer = mdss_mdp_mixer_get(tmp,
MDSS_MDP_MIXER_MUX_DEFAULT);
}
+
+ /* ensure pipes are always reconfigured after power off/on */
+ if (ctl->play_cnt == 0)
+ pipe->params_changed++;
+
if (pipe->back_buf.num_planes) {
buf = &pipe->back_buf;
- } else if (ctl->play_cnt == 0 && pipe->front_buf.num_planes) {
- pipe->params_changed++;
- buf = &pipe->front_buf;
} else if (!pipe->params_changed) {
continue;
} else if (pipe->front_buf.num_planes) {
@@ -2270,10 +2277,12 @@
struct mdp_overlay_list *ovlist,
struct mdp_overlay *overlays)
{
+ struct mdss_mdp_pipe *right_plist[MDSS_MDP_MAX_STAGE] = { 0 };
+ struct mdss_mdp_pipe *left_plist[MDSS_MDP_MAX_STAGE] = { 0 };
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
struct mdss_mdp_pipe *pipe;
struct mdp_overlay *req;
- int ret = 0;
+ int ret = 0, left_cnt = 0, right_cnt = 0;
int i;
u32 new_reqs = 0;
@@ -2302,8 +2311,29 @@
/* keep track of the new overlays to unset in case of errors */
if (pipe->play_cnt == 0)
new_reqs |= pipe->ndx;
+
+ if (pipe->flags & MDSS_MDP_RIGHT_MIXER) {
+ if (right_cnt >= MDSS_MDP_MAX_STAGE) {
+ pr_err("too many pipes on right mixer\n");
+ ret = -EINVAL;
+ goto validate_exit;
+ }
+ right_plist[right_cnt] = pipe;
+ right_cnt++;
+ } else {
+ if (left_cnt >= MDSS_MDP_MAX_STAGE) {
+ pr_err("too many pipes on left mixer\n");
+ ret = -EINVAL;
+ goto validate_exit;
+ }
+ left_plist[left_cnt] = pipe;
+ left_cnt++;
+ }
}
+ ret = mdss_mdp_perf_bw_check(mdp5_data->ctl, left_plist, left_cnt,
+ right_plist, right_cnt);
+
validate_exit:
if (IS_ERR_VALUE(ret))
mdss_mdp_overlay_release(mfd, new_reqs);
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index 274c523..135a00a 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -127,6 +127,11 @@
- 1 clock enable
* @MDSS_EVENT_ENABLE_PARTIAL_UPDATE: Event to update ROI of the panel.
* @MDSS_EVENT_DSI_CMDLIST_KOFF: acquire dsi_mdp_busy lock before kickoff.
+ * @MDSS_EVENT_DSI_ULPS_CTRL: Event to configure Ultra Lower Power Saving
+ * mode for the DSI data and clock lanes. The
+ * event arguments can have one of these values:
+ * - 0: Disable ULPS mode
+ * - 1: Enable ULPS mode
*/
enum mdss_intf_events {
MDSS_EVENT_RESET = 1,
@@ -145,6 +150,7 @@
MDSS_EVENT_PANEL_CLK_CTRL,
MDSS_EVENT_DSI_CMDLIST_KOFF,
MDSS_EVENT_ENABLE_PARTIAL_UPDATE,
+ MDSS_EVENT_DSI_ULPS_CTRL,
};
struct lcd_panel_info {
@@ -300,6 +306,7 @@
int pwm_period;
u32 mode_gpio_state;
bool dynamic_fps;
+ bool ulps_feature_enabled;
char dfps_update;
int new_fps;
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index 6ebcdf6..a0663e3 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -64,6 +64,16 @@
goto mdss_dsi_clk_err;
}
+ if (ctrl_pdata->panel_data.panel_info.type == MIPI_CMD_PANEL) {
+ ctrl_pdata->mmss_misc_ahb_clk = clk_get(dev, "core_mmss_clk");
+ if (IS_ERR(ctrl_pdata->mmss_misc_ahb_clk)) {
+ rc = PTR_ERR(ctrl_pdata->mmss_misc_ahb_clk);
+ pr_err("%s: Unable to get mmss misc ahb clk. rc=%d\n",
+ __func__, rc);
+ goto mdss_dsi_clk_err;
+ }
+ }
+
ctrl_pdata->byte_clk = clk_get(dev, "byte_clk");
if (IS_ERR(ctrl_pdata->byte_clk)) {
rc = PTR_ERR(ctrl_pdata->byte_clk);
@@ -105,6 +115,8 @@
clk_put(ctrl_pdata->esc_clk);
if (ctrl_pdata->pixel_clk)
clk_put(ctrl_pdata->pixel_clk);
+ if (ctrl_pdata->mmss_misc_ahb_clk)
+ clk_put(ctrl_pdata->mmss_misc_ahb_clk);
if (ctrl_pdata->axi_clk)
clk_put(ctrl_pdata->axi_clk);
if (ctrl_pdata->ahb_clk)
@@ -275,12 +287,26 @@
goto error;
}
+ if (ctrl_pdata->mmss_misc_ahb_clk) {
+ rc = clk_prepare_enable(ctrl_pdata->mmss_misc_ahb_clk);
+ if (rc) {
+ pr_err("%s: failed to enable mmss misc ahb clk.rc=%d\n",
+ __func__, rc);
+ clk_disable_unprepare(ctrl_pdata->axi_clk);
+ clk_disable_unprepare(ctrl_pdata->ahb_clk);
+ clk_disable_unprepare(ctrl_pdata->mdp_core_clk);
+ goto error;
+ }
+ }
+
error:
return rc;
}
void mdss_dsi_bus_clk_stop(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
+ if (ctrl_pdata->mmss_misc_ahb_clk)
+ clk_disable_unprepare(ctrl_pdata->mmss_misc_ahb_clk);
clk_disable_unprepare(ctrl_pdata->axi_clk);
clk_disable_unprepare(ctrl_pdata->ahb_clk);
clk_disable_unprepare(ctrl_pdata->mdp_core_clk);
@@ -507,6 +533,16 @@
static DEFINE_MUTEX(dsi_clk_lock); /* per system */
+bool __mdss_dsi_clk_enabled(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ bool enabled;
+ mutex_lock(&dsi_clk_lock);
+ enabled = ctrl->clk_cnt ? true : false;
+ mutex_unlock(&dsi_clk_lock);
+
+ return enabled;
+}
+
void mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable)
{
int changed = 0;
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 272fe77..8b604e3 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -94,6 +94,7 @@
u8 raw_erased_mem_count; /* 181 */
u8 raw_ext_csd_structure; /* 194 */
u8 raw_card_type; /* 196 */
+ u8 raw_drive_strength; /* 197 */
u8 out_of_int_time; /* 198 */
u8 raw_s_a_timeout; /* 217 */
u8 raw_hc_erase_gap_size; /* 221 */
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 764beec..b626915 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -303,6 +303,7 @@
#define EXT_CSD_REV 192 /* RO */
#define EXT_CSD_STRUCTURE 194 /* RO */
#define EXT_CSD_CARD_TYPE 196 /* RO */
+#define EXT_CSD_DRIVE_STRENGTH 197 /* RO */
#define EXT_CSD_OUT_OF_INTERRUPT_TIME 198 /* RO */
#define EXT_CSD_PART_SWITCH_TIME 199 /* RO */
#define EXT_CSD_PWR_CL_52_195 200 /* RO */
diff --git a/include/linux/slimbus/slimbus.h b/include/linux/slimbus/slimbus.h
index 56a3a5f..7a7b3eb 100644
--- a/include/linux/slimbus/slimbus.h
+++ b/include/linux/slimbus/slimbus.h
@@ -525,6 +525,8 @@
* @port_xfer_status: Called by framework when client calls get_xfer_status
* API. Returns how much buffer is actually processed and the port
* errors (e.g. overflow/underflow) if any.
+ * @xfer_user_msg: Send user message to specified logical address. Underlying
+ * controller has to support sending user messages. Returns error if any.
*/
struct slim_controller {
struct device dev;
@@ -567,10 +569,13 @@
int (*framer_handover)(struct slim_controller *ctrl,
struct slim_framer *new_framer);
int (*port_xfer)(struct slim_controller *ctrl,
- u8 pn, u8 *iobuf, u32 len,
+ u8 pn, phys_addr_t iobuf, u32 len,
struct completion *comp);
enum slim_port_err (*port_xfer_status)(struct slim_controller *ctr,
- u8 pn, u8 **done_buf, u32 *done_len);
+ u8 pn, phys_addr_t *done_buf, u32 *done_len);
+ int (*xfer_user_msg)(struct slim_controller *ctrl,
+ u8 la, u8 mt, u8 mc,
+ struct slim_ele_access *msg, u8 *buf, u8 len);
};
#define to_slim_controller(d) container_of(d, struct slim_controller, dev)
@@ -744,6 +749,20 @@
extern int slim_xfer_msg(struct slim_controller *ctrl,
struct slim_device *sbdev, struct slim_ele_access *msg,
u16 mc, u8 *rbuf, const u8 *wbuf, u8 len);
+
+/*
+ * User message:
+ * slim_user_msg: Send user message that is interpreted by destination device
+ * @sb: Client handle sending the message
+ * @la: Destination device for this user message
+ * @mt: Message Type (Soruce-referred, or Destination-referred)
+ * @mc: Message Code
+ * @msg: Message structure (start offset, number of bytes) to be sent
+ * @buf: data buffer to be sent
+ * @len: data buffer size in bytes
+ */
+extern int slim_user_msg(struct slim_device *sb, u8 la, u8 mt, u8 mc,
+ struct slim_ele_access *msg, u8 *buf, u8 len);
/* end of message apis */
/* Port management for manager device APIs */
@@ -783,8 +802,8 @@
* Client will call slim_port_get_xfer_status to get error and/or number of
* bytes transferred if used asynchronously.
*/
-extern int slim_port_xfer(struct slim_device *sb, u32 ph, u8 *iobuf, u32 len,
- struct completion *comp);
+extern int slim_port_xfer(struct slim_device *sb, u32 ph, phys_addr_t iobuf,
+ u32 len, struct completion *comp);
/*
* slim_port_get_xfer_status: Poll for port transfers, or get transfer status
@@ -806,7 +825,7 @@
* processed from the multiple transfers.
*/
extern enum slim_port_err slim_port_get_xfer_status(struct slim_device *sb,
- u32 ph, u8 **done_buf, u32 *done_len);
+ u32 ph, phys_addr_t *done_buf, u32 *done_len);
/*
* slim_connect_src: Connect source port to channel.
diff --git a/include/linux/tick.h b/include/linux/tick.h
index dc15221..78ae909 100644
--- a/include/linux/tick.h
+++ b/include/linux/tick.h
@@ -92,7 +92,16 @@
# ifdef CONFIG_TICK_ONESHOT
extern struct cpumask *tick_get_broadcast_oneshot_mask(void);
# endif
+#else
+static inline struct tick_device *tick_get_broadcast_device(void)
+{
+ return NULL;
+}
+static inline struct cpumask *tick_get_broadcast_mask(void)
+{
+ return NULL;
+}
# endif /* BROADCAST */
# ifdef CONFIG_TICK_ONESHOT
@@ -109,6 +118,10 @@
static inline int tick_check_oneshot_change(int allow_nohz) { return 0; }
static inline void tick_check_idle(int cpu) { }
static inline int tick_oneshot_mode_active(void) { return 0; }
+static inline struct cpumask *tick_get_broadcast_oneshot_mask(void)
+{
+ return NULL;
+}
# endif
#else /* CONFIG_GENERIC_CLOCKEVENTS */
diff --git a/include/media/msmb_isp.h b/include/media/msmb_isp.h
index 3ba0abe..3828221 100644
--- a/include/media/msmb_isp.h
+++ b/include/media/msmb_isp.h
@@ -1,3 +1,14 @@
+/* Copyright (c) 2013-2014, 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 __MSMB_ISP__
#define __MSMB_ISP__
@@ -302,15 +313,16 @@
ISP_WM_BUS_OVERFLOW = 4,
ISP_STATS_OVERFLOW = 5,
ISP_CAMIF_ERROR = 6,
- ISP_SOF = 7,
- ISP_EOF = 8,
- ISP_EVENT_MAX = 9
+ ISP_BUF_DONE = 9,
+ ISP_EVENT_MAX = 10
};
#define ISP_EVENT_OFFSET 8
#define ISP_EVENT_BASE (V4L2_EVENT_PRIVATE_START)
#define ISP_BUF_EVENT_BASE (ISP_EVENT_BASE + (1 << ISP_EVENT_OFFSET))
#define ISP_STATS_EVENT_BASE (ISP_EVENT_BASE + (2 << ISP_EVENT_OFFSET))
+#define ISP_SOF_EVENT_BASE (ISP_EVENT_BASE + (3 << ISP_EVENT_OFFSET))
+#define ISP_EOF_EVENT_BASE (ISP_EVENT_BASE + (4 << ISP_EVENT_OFFSET))
#define ISP_EVENT_REG_UPDATE (ISP_EVENT_BASE + ISP_REG_UPDATE)
#define ISP_EVENT_START_ACK (ISP_EVENT_BASE + ISP_START_ACK)
#define ISP_EVENT_STOP_ACK (ISP_EVENT_BASE + ISP_STOP_ACK)
@@ -318,8 +330,9 @@
#define ISP_EVENT_WM_BUS_OVERFLOW (ISP_EVENT_BASE + ISP_WM_BUS_OVERFLOW)
#define ISP_EVENT_STATS_OVERFLOW (ISP_EVENT_BASE + ISP_STATS_OVERFLOW)
#define ISP_EVENT_CAMIF_ERROR (ISP_EVENT_BASE + ISP_CAMIF_ERROR)
-#define ISP_EVENT_SOF (ISP_EVENT_BASE + ISP_SOF)
-#define ISP_EVENT_EOF (ISP_EVENT_BASE + ISP_EOF)
+#define ISP_EVENT_SOF (ISP_SOF_EVENT_BASE)
+#define ISP_EVENT_EOF (ISP_EOF_EVENT_BASE)
+#define ISP_EVENT_BUF_DONE (ISP_EVENT_BASE + ISP_BUF_DONE)
#define ISP_EVENT_BUF_DIVERT (ISP_BUF_EVENT_BASE)
#define ISP_EVENT_STATS_NOTIFY (ISP_STATS_EVENT_BASE)
#define ISP_EVENT_COMP_STATS_NOTIFY (ISP_EVENT_STATS_NOTIFY + MSM_ISP_STATS_MAX)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 9f0d486..ecaef21 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -3224,8 +3224,8 @@
static inline struct sk_buff *
cfg80211_vendor_cmd_alloc_reply_skb(struct wiphy *wiphy, int approxlen)
{
- return __cfg80211_alloc_reply_skb(wiphy, NL80211_CMD_TESTMODE,
- NL80211_ATTR_TESTDATA, approxlen);
+ return __cfg80211_alloc_reply_skb(wiphy, NL80211_CMD_VENDOR,
+ NL80211_ATTR_VENDOR_DATA, approxlen);
}
/**
diff --git a/lib/genalloc.c b/lib/genalloc.c
index 0218f4b..fd699ca 100644
--- a/lib/genalloc.c
+++ b/lib/genalloc.c
@@ -177,7 +177,7 @@
struct gen_pool_chunk *chunk;
int nbits = size >> pool->min_alloc_order;
int nbytes = sizeof(struct gen_pool_chunk) +
- (nbits + BITS_PER_BYTE - 1) / BITS_PER_BYTE;
+ BITS_TO_LONGS(nbits) * sizeof(long);
if (nbytes <= PAGE_SIZE)
chunk = kmalloc_node(nbytes, __GFP_ZERO, nid);
diff --git a/net/wireless/db.txt b/net/wireless/db.txt
index c27f165..f6c74c9 100644
--- a/net/wireless/db.txt
+++ b/net/wireless/db.txt
@@ -18,7 +18,7 @@
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (3, 17)
(5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5710 @ 80), (3, 24), DFS
+ (5490 - 5730 @ 80), (3, 24), DFS
(5735 - 5835 @ 80), (3, 30)
country AL:
@@ -42,7 +42,7 @@
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (3, 17)
(5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5710 @ 80), (3, 24), DFS
+ (5490 - 5730 @ 80), (3, 24), DFS
(5735 - 5835 @ 80), (3, 30)
country AS:
@@ -64,7 +64,7 @@
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (3, 17)
(5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5710 @ 80), (3, 24), DFS
+ (5490 - 5730 @ 80), (3, 24), DFS
(5735 - 5835 @ 80), (3, 30)
country AW:
@@ -139,7 +139,7 @@
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (3, 17)
(5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5710 @ 80), (3, 24), DFS
+ (5490 - 5730 @ 80), (3, 24), DFS
(5735 - 5835 @ 80), (3, 30)
country BS:
@@ -163,7 +163,7 @@
(2402 - 2472 @ 40), (N/A, 27)
(5170 - 5250 @ 80), (3, 17)
(5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5710 @ 80), (3, 24), DFS
+ (5490 - 5730 @ 80), (3, 24), DFS
(5735 - 5835 @ 80), (3, 30)
country CH: DFS-ETSI
@@ -196,14 +196,14 @@
(2402 - 2472 @ 40), (N/A, 27)
(5170 - 5250 @ 80), (3, 17)
(5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5710 @ 80), (3, 24), DFS
+ (5490 - 5730 @ 80), (3, 24), DFS
(5735 - 5835 @ 80), (3, 30)
country CR:
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 20), (3, 17)
(5250 - 5330 @ 20), (3, 24), DFS
- (5490 - 5710 @ 20), (3, 24), DFS
+ (5490 - 5730 @ 20), (3, 24), DFS
(5735 - 5835 @ 20), (3, 30)
country CY: DFS-ETSI
@@ -271,7 +271,7 @@
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 20), (3, 17)
(5250 - 5330 @ 20), (3, 24), DFS
- (5490 - 5710 @ 20), (3, 24), DFS
+ (5490 - 5730 @ 20), (3, 24), DFS
(5735 - 5835 @ 20), (3, 30)
country EE: DFS-ETSI
@@ -342,7 +342,7 @@
(2402 - 2472 @ 40), (3, 30)
(5170 - 5250 @ 80), (6, 17)
(5250 - 5330 @ 80), (6, 24), DFS
- (5490 - 5710 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
(5735 - 5835 @ 80), (6, 30)
country GP:
@@ -375,21 +375,21 @@
(2402 - 2472 @ 40), (3, 30)
(5170 - 5250 @ 20), (6, 17)
(5250 - 5330 @ 20), (6, 24), DFS
- (5490 - 5710 @ 20), (6, 24), DFS
+ (5490 - 5730 @ 20), (6, 24), DFS
(5735 - 5835 @ 20), (6, 30)
country HN:
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (6, 17)
(5250 - 5330 @ 80), (6, 24), DFS
- (5490 - 5710 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
(5735 - 5835 @ 80), (6, 30)
country HK:
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (6, 17)
(5250 - 5330 @ 80), (6, 24), DFS
- (5490 - 5710 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
(5735 - 5835 @ 80), (6, 30)
country HR: DFS-ETSI
@@ -462,7 +462,7 @@
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (6, 17)
(5250 - 5330 @ 80), (6, 24), DFS
- (5490 - 5710 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
(5735 - 5835 @ 80), (6, 30)
country JP:
@@ -495,7 +495,7 @@
(2402 - 2472 @ 40), (N/A, 27)
(5170 - 5250 @ 80), (3, 17)
(5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5710 @ 80), (3, 24), DFS
+ (5490 - 5730 @ 80), (3, 24), DFS
(5735 - 5835 @ 80), (3, 30)
country KP:
@@ -537,7 +537,7 @@
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 20), (3, 17)
(5250 - 5330 @ 20), (3, 20), DFS
- (5490 - 5710 @ 20), (3, 20), DFS
+ (5490 - 5730 @ 20), (3, 20), DFS
(5735 - 5835 @ 20), (3, 30)
country LT: DFS-ETSI
@@ -634,7 +634,7 @@
(2402 - 2472 @ 40), (3, 27)
(5170 - 5250 @ 80), (3, 17)
(5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5710 @ 80), (3, 24), DFS
+ (5490 - 5730 @ 80), (3, 24), DFS
(5735 - 5835 @ 80), (3, 30)
country MW:
@@ -681,7 +681,7 @@
(2402 - 2482 @ 40), (N/A, 30)
(5170 - 5250 @ 80), (6, 17)
(5250 - 5330 @ 80), (6, 24), DFS
- (5490 - 5710 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
(5735 - 5835 @ 80), (6, 30)
country OM:
@@ -700,7 +700,7 @@
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (6, 20)
(5250 - 5330 @ 80), (6, 20), DFS
- (5490 - 5710 @ 80), (6, 27), DFS
+ (5490 - 5730 @ 80), (6, 27), DFS
(5735 - 5835 @ 80), (6, 30)
country PF:
@@ -720,7 +720,7 @@
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (6, 17)
(5250 - 5330 @ 80), (6, 24), DFS
- (5490 - 5710 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
(5735 - 5835 @ 80), (6, 30)
country PK:
@@ -747,7 +747,7 @@
(2402 - 2472 @ 40), (3, 30)
(5170 - 5250 @ 80), (6, 17)
(5250 - 5330 @ 80), (6, 24), DFS
- (5490 - 5710 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
(5735 - 5835 @ 80), (6, 30)
country PY:
@@ -819,7 +819,7 @@
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (6, 17)
(5250 - 5330 @ 80), (6, 24), DFS
- (5490 - 5710 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
(5735 - 5835 @ 80), (6, 30)
country SI: DFS-ETSI
@@ -856,21 +856,21 @@
country TW:
(2402 - 2472 @ 40), (3, 27)
(5270 - 5330 @ 40), (6, 17), DFS
- (5490 - 5710 @ 80), (6, 30), DFS
+ (5490 - 5730 @ 80), (6, 30), DFS
(5735 - 5815 @ 80), (6, 30)
country TH:
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (3, 17)
(5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5710 @ 80), (3, 24), DFS
+ (5490 - 5730 @ 80), (3, 24), DFS
(5735 - 5835 @ 80), (3, 30)
country TT:
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 40), (3, 17)
(5250 - 5330 @ 40), (3, 20), DFS
- (5490 - 5710 @ 40), (3, 20), DFS
+ (5490 - 5730 @ 40), (3, 20), DFS
(5735 - 5835 @ 40), (3, 30)
country TN:
@@ -914,8 +914,8 @@
(5170 - 5250 @ 80), (3, 17)
(5250 - 5330 @ 80), (3, 24), DFS
(5490 - 5600 @ 80), (3, 24), DFS
- (5650 - 5710 @ 40), (3, 24), DFS
- (5710 - 5835 @ 80), (3, 30)
+ (5650 - 5730 @ 40), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
# 60g band
# reference: http://cfr.regstoday.com/47cfr15.aspx#47_CFR_15p255
# channels 1,2,3, EIRP=40dBm(43dBm peak)
@@ -935,14 +935,14 @@
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 40), (3, 17)
(5250 - 5330 @ 40), (3, 20), DFS
- (5490 - 5710 @ 40), (3, 20), DFS
+ (5490 - 5730 @ 40), (3, 20), DFS
(5735 - 5835 @ 40), (3, 30)
country UZ:
(2402 - 2472 @ 40), (3, 27)
(5170 - 5250 @ 40), (3, 17)
(5250 - 5330 @ 40), (3, 20), DFS
- (5490 - 5710 @ 40), (3, 20), DFS
+ (5490 - 5730 @ 40), (3, 20), DFS
(5735 - 5835 @ 40), (3, 30)
country VE:
@@ -956,7 +956,7 @@
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (3, 17)
(5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5710 @ 80), (3, 24), DFS
+ (5490 - 5730 @ 80), (3, 24), DFS
(5735 - 5835 @ 80), (3, 30)
country VI:
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index e90ef68..b73cfe5 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -5431,6 +5431,8 @@
return err;
}
+#endif
+
struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
enum nl80211_commands cmd,
enum nl80211_attrs attr,
@@ -5478,7 +5480,7 @@
nl80211_testmode_mcgrp.id, gfp);
}
EXPORT_SYMBOL(__cfg80211_send_event_skb);
-#endif
+
static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
{
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 5dedec8..b72590f 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -1652,6 +1652,21 @@
"DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
};
+static const char * const iir_inp2_text[] = {
+ "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
+ "DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
+};
+
+static const char * const iir_inp3_text[] = {
+ "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
+ "DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
+};
+
+static const char * const iir_inp4_text[] = {
+ "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
+ "DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
+};
+
static const struct soc_enum rx_mix1_inp1_chain_enum =
SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_mix1_text);
@@ -1800,6 +1815,24 @@
static const struct soc_enum iir2_inp1_mux_enum =
SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_EQ2_B1_CTL, 0, 18, iir_inp1_text);
+static const struct soc_enum iir1_inp2_mux_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_EQ1_B2_CTL, 0, 18, iir_inp2_text);
+
+static const struct soc_enum iir2_inp2_mux_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_EQ2_B2_CTL, 0, 18, iir_inp2_text);
+
+static const struct soc_enum iir1_inp3_mux_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_EQ1_B3_CTL, 0, 18, iir_inp3_text);
+
+static const struct soc_enum iir2_inp3_mux_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_EQ2_B3_CTL, 0, 18, iir_inp3_text);
+
+static const struct soc_enum iir1_inp4_mux_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_EQ1_B4_CTL, 0, 18, iir_inp4_text);
+
+static const struct soc_enum iir2_inp4_mux_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_EQ2_B4_CTL, 0, 18, iir_inp4_text);
+
static const struct snd_kcontrol_new rx_mix1_inp1_mux =
SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
@@ -2025,6 +2058,24 @@
static const struct snd_kcontrol_new iir2_inp1_mux =
SOC_DAPM_ENUM("IIR2 INP1 Mux", iir2_inp1_mux_enum);
+static const struct snd_kcontrol_new iir1_inp2_mux =
+ SOC_DAPM_ENUM("IIR1 INP2 Mux", iir1_inp2_mux_enum);
+
+static const struct snd_kcontrol_new iir2_inp2_mux =
+ SOC_DAPM_ENUM("IIR2 INP2 Mux", iir2_inp2_mux_enum);
+
+static const struct snd_kcontrol_new iir1_inp3_mux =
+ SOC_DAPM_ENUM("IIR1 INP3 Mux", iir1_inp3_mux_enum);
+
+static const struct snd_kcontrol_new iir2_inp3_mux =
+ SOC_DAPM_ENUM("IIR2 INP3 Mux", iir2_inp3_mux_enum);
+
+static const struct snd_kcontrol_new iir1_inp4_mux =
+ SOC_DAPM_ENUM("IIR1 INP4 Mux", iir1_inp4_mux_enum);
+
+static const struct snd_kcontrol_new iir2_inp4_mux =
+ SOC_DAPM_ENUM("IIR2 INP4 Mux", iir2_inp4_mux_enum);
+
static const struct snd_kcontrol_new anc1_mux =
SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
@@ -4012,6 +4063,120 @@
{"IIR2 INP1 MUX", "RX6", "SLIM RX6"},
{"IIR2 INP1 MUX", "RX7", "SLIM RX7"},
+ {"IIR1", NULL, "IIR1 INP2 MUX"},
+ {"IIR1 INP2 MUX", "DEC1", "DEC1 MUX"},
+ {"IIR1 INP2 MUX", "DEC2", "DEC2 MUX"},
+ {"IIR1 INP2 MUX", "DEC3", "DEC3 MUX"},
+ {"IIR1 INP2 MUX", "DEC4", "DEC4 MUX"},
+ {"IIR1 INP2 MUX", "DEC5", "DEC5 MUX"},
+ {"IIR1 INP2 MUX", "DEC6", "DEC6 MUX"},
+ {"IIR1 INP2 MUX", "DEC7", "DEC7 MUX"},
+ {"IIR1 INP2 MUX", "DEC8", "DEC8 MUX"},
+ {"IIR1 INP2 MUX", "DEC9", "DEC9 MUX"},
+ {"IIR1 INP2 MUX", "DEC10", "DEC10 MUX"},
+ {"IIR1 INP2 MUX", "RX1", "SLIM RX1"},
+ {"IIR1 INP2 MUX", "RX2", "SLIM RX2"},
+ {"IIR1 INP2 MUX", "RX3", "SLIM RX3"},
+ {"IIR1 INP2 MUX", "RX4", "SLIM RX4"},
+ {"IIR1 INP2 MUX", "RX5", "SLIM RX5"},
+ {"IIR1 INP2 MUX", "RX6", "SLIM RX6"},
+ {"IIR1 INP2 MUX", "RX7", "SLIM RX7"},
+
+ {"IIR2", NULL, "IIR2 INP2 MUX"},
+ {"IIR2 INP2 MUX", "DEC1", "DEC1 MUX"},
+ {"IIR2 INP2 MUX", "DEC2", "DEC2 MUX"},
+ {"IIR2 INP2 MUX", "DEC3", "DEC3 MUX"},
+ {"IIR2 INP2 MUX", "DEC4", "DEC4 MUX"},
+ {"IIR2 INP2 MUX", "DEC5", "DEC5 MUX"},
+ {"IIR2 INP2 MUX", "DEC6", "DEC6 MUX"},
+ {"IIR2 INP2 MUX", "DEC7", "DEC7 MUX"},
+ {"IIR2 INP2 MUX", "DEC8", "DEC8 MUX"},
+ {"IIR2 INP2 MUX", "DEC9", "DEC9 MUX"},
+ {"IIR2 INP2 MUX", "DEC10", "DEC10 MUX"},
+ {"IIR2 INP2 MUX", "RX1", "SLIM RX1"},
+ {"IIR2 INP2 MUX", "RX2", "SLIM RX2"},
+ {"IIR2 INP2 MUX", "RX3", "SLIM RX3"},
+ {"IIR2 INP2 MUX", "RX4", "SLIM RX4"},
+ {"IIR2 INP2 MUX", "RX5", "SLIM RX5"},
+ {"IIR2 INP2 MUX", "RX6", "SLIM RX6"},
+ {"IIR2 INP2 MUX", "RX7", "SLIM RX7"},
+
+ {"IIR1", NULL, "IIR1 INP3 MUX"},
+ {"IIR1 INP3 MUX", "DEC1", "DEC1 MUX"},
+ {"IIR1 INP3 MUX", "DEC2", "DEC2 MUX"},
+ {"IIR1 INP3 MUX", "DEC3", "DEC3 MUX"},
+ {"IIR1 INP3 MUX", "DEC4", "DEC4 MUX"},
+ {"IIR1 INP3 MUX", "DEC5", "DEC5 MUX"},
+ {"IIR1 INP3 MUX", "DEC6", "DEC6 MUX"},
+ {"IIR1 INP3 MUX", "DEC7", "DEC7 MUX"},
+ {"IIR1 INP3 MUX", "DEC8", "DEC8 MUX"},
+ {"IIR1 INP3 MUX", "DEC9", "DEC9 MUX"},
+ {"IIR1 INP3 MUX", "DEC10", "DEC10 MUX"},
+ {"IIR1 INP3 MUX", "RX1", "SLIM RX1"},
+ {"IIR1 INP3 MUX", "RX2", "SLIM RX2"},
+ {"IIR1 INP3 MUX", "RX3", "SLIM RX3"},
+ {"IIR1 INP3 MUX", "RX4", "SLIM RX4"},
+ {"IIR1 INP3 MUX", "RX5", "SLIM RX5"},
+ {"IIR1 INP3 MUX", "RX6", "SLIM RX6"},
+ {"IIR1 INP3 MUX", "RX7", "SLIM RX7"},
+
+ {"IIR2", NULL, "IIR2 INP3 MUX"},
+ {"IIR2 INP3 MUX", "DEC1", "DEC1 MUX"},
+ {"IIR2 INP3 MUX", "DEC2", "DEC2 MUX"},
+ {"IIR2 INP3 MUX", "DEC3", "DEC3 MUX"},
+ {"IIR2 INP3 MUX", "DEC4", "DEC4 MUX"},
+ {"IIR2 INP3 MUX", "DEC5", "DEC5 MUX"},
+ {"IIR2 INP3 MUX", "DEC6", "DEC6 MUX"},
+ {"IIR2 INP3 MUX", "DEC7", "DEC7 MUX"},
+ {"IIR2 INP3 MUX", "DEC8", "DEC8 MUX"},
+ {"IIR2 INP3 MUX", "DEC9", "DEC9 MUX"},
+ {"IIR2 INP3 MUX", "DEC10", "DEC10 MUX"},
+ {"IIR2 INP3 MUX", "RX1", "SLIM RX1"},
+ {"IIR2 INP3 MUX", "RX2", "SLIM RX2"},
+ {"IIR2 INP3 MUX", "RX3", "SLIM RX3"},
+ {"IIR2 INP3 MUX", "RX4", "SLIM RX4"},
+ {"IIR2 INP3 MUX", "RX5", "SLIM RX5"},
+ {"IIR2 INP3 MUX", "RX6", "SLIM RX6"},
+ {"IIR2 INP3 MUX", "RX7", "SLIM RX7"},
+
+ {"IIR1", NULL, "IIR1 INP4 MUX"},
+ {"IIR1 INP4 MUX", "DEC1", "DEC1 MUX"},
+ {"IIR1 INP4 MUX", "DEC2", "DEC2 MUX"},
+ {"IIR1 INP4 MUX", "DEC3", "DEC3 MUX"},
+ {"IIR1 INP4 MUX", "DEC4", "DEC4 MUX"},
+ {"IIR1 INP4 MUX", "DEC5", "DEC5 MUX"},
+ {"IIR1 INP4 MUX", "DEC6", "DEC6 MUX"},
+ {"IIR1 INP4 MUX", "DEC7", "DEC7 MUX"},
+ {"IIR1 INP4 MUX", "DEC8", "DEC8 MUX"},
+ {"IIR1 INP4 MUX", "DEC9", "DEC9 MUX"},
+ {"IIR1 INP4 MUX", "DEC10", "DEC10 MUX"},
+ {"IIR1 INP4 MUX", "RX1", "SLIM RX1"},
+ {"IIR1 INP4 MUX", "RX2", "SLIM RX2"},
+ {"IIR1 INP4 MUX", "RX3", "SLIM RX3"},
+ {"IIR1 INP4 MUX", "RX4", "SLIM RX4"},
+ {"IIR1 INP4 MUX", "RX5", "SLIM RX5"},
+ {"IIR1 INP4 MUX", "RX6", "SLIM RX6"},
+ {"IIR1 INP4 MUX", "RX7", "SLIM RX7"},
+
+ {"IIR2", NULL, "IIR2 INP4 MUX"},
+ {"IIR2 INP4 MUX", "DEC1", "DEC1 MUX"},
+ {"IIR2 INP4 MUX", "DEC2", "DEC2 MUX"},
+ {"IIR2 INP4 MUX", "DEC3", "DEC3 MUX"},
+ {"IIR2 INP4 MUX", "DEC4", "DEC4 MUX"},
+ {"IIR2 INP4 MUX", "DEC5", "DEC5 MUX"},
+ {"IIR2 INP4 MUX", "DEC6", "DEC6 MUX"},
+ {"IIR2 INP4 MUX", "DEC7", "DEC7 MUX"},
+ {"IIR2 INP4 MUX", "DEC8", "DEC8 MUX"},
+ {"IIR2 INP4 MUX", "DEC9", "DEC9 MUX"},
+ {"IIR2 INP4 MUX", "DEC10", "DEC10 MUX"},
+ {"IIR2 INP4 MUX", "RX1", "SLIM RX1"},
+ {"IIR2 INP4 MUX", "RX2", "SLIM RX2"},
+ {"IIR2 INP4 MUX", "RX3", "SLIM RX3"},
+ {"IIR2 INP4 MUX", "RX4", "SLIM RX4"},
+ {"IIR2 INP4 MUX", "RX5", "SLIM RX5"},
+ {"IIR2 INP4 MUX", "RX6", "SLIM RX6"},
+ {"IIR2 INP4 MUX", "RX7", "SLIM RX7"},
+
{"MIC BIAS1 Internal1", NULL, "LDO_H"},
{"MIC BIAS1 Internal2", NULL, "LDO_H"},
{"MIC BIAS1 External", NULL, "LDO_H"},
@@ -5667,12 +5832,36 @@
&iir1_inp1_mux, taiko_codec_iir_mux_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("IIR1 INP2 MUX", TAIKO_A_CDC_IIR1_GAIN_B2_CTL, 0, 0,
+ &iir1_inp2_mux, taiko_codec_iir_mux_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX_E("IIR1 INP3 MUX", TAIKO_A_CDC_IIR1_GAIN_B3_CTL, 0, 0,
+ &iir1_inp3_mux, taiko_codec_iir_mux_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX_E("IIR1 INP4 MUX", TAIKO_A_CDC_IIR1_GAIN_B4_CTL, 0, 0,
+ &iir1_inp4_mux, taiko_codec_iir_mux_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
SND_SOC_DAPM_MIXER("IIR1", TAIKO_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
SND_SOC_DAPM_MUX_E("IIR2 INP1 MUX", TAIKO_A_CDC_IIR2_GAIN_B1_CTL, 0, 0,
&iir2_inp1_mux, taiko_codec_iir_mux_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("IIR2 INP2 MUX", TAIKO_A_CDC_IIR2_GAIN_B2_CTL, 0, 0,
+ &iir2_inp2_mux, taiko_codec_iir_mux_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX_E("IIR2 INP3 MUX", TAIKO_A_CDC_IIR2_GAIN_B3_CTL, 0, 0,
+ &iir2_inp3_mux, taiko_codec_iir_mux_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX_E("IIR2 INP4 MUX", TAIKO_A_CDC_IIR2_GAIN_B4_CTL, 0, 0,
+ &iir2_inp4_mux, taiko_codec_iir_mux_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
SND_SOC_DAPM_MIXER("IIR2", TAIKO_A_CDC_CLK_SD_CTL, 1, 0, NULL, 0),
/* AUX PGA */
diff --git a/sound/soc/msm/msm8226.c b/sound/soc/msm/msm8226.c
index b512bb5..17e99dd 100644
--- a/sound/soc/msm/msm8226.c
+++ b/sound/soc/msm/msm8226.c
@@ -32,6 +32,10 @@
#include "../codecs/wcd9xxx-common.h"
#include "../codecs/wcd9306.h"
+#define SAMPLING_RATE_48KHZ 48000
+#define SAMPLING_RATE_96KHZ 96000
+#define SAMPLING_RATE_192KHZ 192000
+
#define DRV_NAME "msm8226-asoc-tapan"
#define MSM_SLIM_0_RX_MAX_CHANNELS 2
@@ -154,6 +158,8 @@
static int ext_spk_amp_gpio = -1;
static int vdd_spkr_gpio = -1;
static int msm_proxy_rx_ch = 2;
+
+static int slim0_rx_sample_rate = SAMPLING_RATE_48KHZ;
static int slim0_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
static inline int param_is_mask(int p)
@@ -388,6 +394,9 @@
static const char *const slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
static const char *const proxy_rx_ch_text[] = {"One", "Two", "Three", "Four",
"Five", "Six", "Seven", "Eight"};
+static char const *rx_bit_format_text[] = {"S16_LE", "S24_LE"};
+static char const *slim0_rx_sample_rate_text[] = {"KHZ_48", "KHZ_96",
+ "KHZ_192"};
static const struct soc_enum msm_enum[] = {
SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
@@ -399,6 +408,58 @@
SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
};
+static int slim0_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int sample_rate_val = 0;
+
+ switch (slim0_rx_sample_rate) {
+ case SAMPLING_RATE_192KHZ:
+ sample_rate_val = 2;
+ break;
+
+ case SAMPLING_RATE_96KHZ:
+ sample_rate_val = 1;
+ break;
+
+ case SAMPLING_RATE_48KHZ:
+ default:
+ sample_rate_val = 0;
+ break;
+ }
+
+ ucontrol->value.integer.value[0] = sample_rate_val;
+ pr_debug("%s: slim0_rx_sample_rate = %d\n", __func__,
+ slim0_rx_sample_rate);
+
+ return 0;
+}
+
+static int slim0_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: ucontrol value = %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 2:
+ slim0_rx_sample_rate = SAMPLING_RATE_192KHZ;
+ break;
+ case 1:
+ slim0_rx_sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 0:
+ default:
+ slim0_rx_sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ }
+
+ pr_debug("%s: slim0_rx_sample_rate = %d\n", __func__,
+ slim0_rx_sample_rate);
+
+ return 0;
+}
+
static int msm_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -725,8 +786,7 @@
pr_debug("%s()\n", __func__);
param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
slim0_rx_bit_format);
-
- rate->min = rate->max = 48000;
+ rate->min = rate->max = slim0_rx_sample_rate;
channels->min = channels->max = msm_slim_0_rx_ch;
return 0;
@@ -780,6 +840,8 @@
SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
SOC_ENUM_SINGLE_EXT(8, proxy_rx_ch_text),
+ SOC_ENUM_SINGLE_EXT(2, rx_bit_format_text),
+ SOC_ENUM_SINGLE_EXT(3, slim0_rx_sample_rate_text),
};
static const struct snd_kcontrol_new msm_snd_controls[] = {
@@ -795,7 +857,8 @@
msm_proxy_rx_ch_get, msm_proxy_rx_ch_put),
SOC_ENUM_EXT("SLIM_0_RX Format", msm_snd_enum[3],
slim0_rx_bit_format_get, slim0_rx_bit_format_put),
-
+ SOC_ENUM_EXT("SLIM_0_RX SampleRate", msm_snd_enum[4],
+ slim0_rx_sample_rate_get, slim0_rx_sample_rate_put),
};
static int msm_afe_set_config(struct snd_soc_codec *codec)
diff --git a/sound/soc/msm/msm8x10.c b/sound/soc/msm/msm8x10.c
index fe44a23..89df806 100644
--- a/sound/soc/msm/msm8x10.c
+++ b/sound/soc/msm/msm8x10.c
@@ -894,6 +894,21 @@
.codec_name = "snd-soc-dummy",
.be_id = MSM_FRONTEND_DAI_QCHAT,
},
+ {/* hw:x,15 */
+ .name = "MSM8X10 Media9",
+ .stream_name = "MultiMedia9",
+ .cpu_dai_name = "MultiMedia9",
+ .platform_name = "msm-pcm-dsp.0",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA9
+ },
/* Backend I2S DAI Links */
{
.name = LPASS_BE_SEC_MI2S_RX,
@@ -1039,6 +1054,19 @@
.be_hw_params_fixup = msm_be_hw_params_fixup,
.ignore_suspend = 1,
},
+ /* Incall Music 2 BACK END DAI Link */
+ {
+ .name = LPASS_BE_VOICE2_PLAYBACK_TX,
+ .stream_name = "Voice2 Farend Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.32770",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
};
struct snd_soc_card snd_soc_card_msm8x10 = {
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 33317fa..98d7dee 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -2611,6 +2611,11 @@
0, 1, 0, msm_routing_get_fm_pcmrx_switch_mixer,
msm_routing_put_fm_pcmrx_switch_mixer);
+static const struct snd_kcontrol_new pri_mi2s_rx_switch_mixer_controls =
+ SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
+ 0, 1, 0, msm_routing_get_switch_mixer,
+ msm_routing_put_switch_mixer);
+
static const struct soc_enum lsm_mux_enum =
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mad_audio_mux_text), mad_audio_mux_text);
@@ -3192,6 +3197,9 @@
SND_SOC_DAPM_AIF_OUT("PRI_MI2S_UL_HL",
"Primary MI2S_TX Hostless Capture",
0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("PRI_MI2S_DL_HL",
+ "Primary MI2S_RX Hostless Playback",
+ 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MI2S_DL_HL", "MI2S_RX_HOSTLESS Playback",
0, 0, 0, 0),
@@ -3298,6 +3306,8 @@
&fm_switch_mixer_controls),
SND_SOC_DAPM_SWITCH("PCM_RX_DL_HL", SND_SOC_NOPM, 0, 0,
&pcm_rx_switch_mixer_controls),
+ SND_SOC_DAPM_SWITCH("PRI_MI2S_RX_DL_HL", SND_SOC_NOPM, 0, 0,
+ &pri_mi2s_rx_switch_mixer_controls),
/* Mux Definitions */
SND_SOC_DAPM_MUX("LSM1 MUX", SND_SOC_NOPM, 0, 0, &lsm1_mux),
@@ -3914,6 +3924,8 @@
{"MI2S_UL_HL", NULL, "MI2S_TX"},
{"PCM_RX_DL_HL", "Switch", "SLIM0_DL_HL"},
{"PCM_RX", NULL, "PCM_RX_DL_HL"},
+ {"PRI_MI2S_RX_DL_HL", "Switch", "PRI_MI2S_DL_HL"},
+ {"PRI_MI2S_RX", NULL, "PRI_MI2S_RX_DL_HL"},
{"MI2S_UL_HL", NULL, "TERT_MI2S_TX"},
{"SEC_I2S_RX", NULL, "SEC_I2S_DL_HL"},
{"PRI_MI2S_UL_HL", NULL, "PRI_MI2S_TX"},
@@ -4171,7 +4183,7 @@
path_type,
bedai->sample_rate,
channels,
- topology, false,
+ topology, fe_dai_perf_mode[i][session_type],
bits_per_sample);
}