Merge "msm: otg: Add vbus sensing support"
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
index 24b6b36..a0c7037 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
+++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
@@ -31,6 +31,10 @@
"HS200_1p2v" - indicates that host can support HS200 at 1.2v.
"DDR_1p8v" - indicates that host can support DDR mode at 1.8v.
"DDR_1p2v" - indicates that host can support DDR mode at 1.2v.
+ - qcom,cpu-dma-latency-us: specifies acceptable DMA latency in microseconds. There is
+ no default value that the driver assumes if this property
+ is not specified. So if this property is not specified,
+ then SDHC driver will not vote for PM QOS.
In the following, <supply> can be vdd (flash core voltage) or vdd-io (I/O voltage).
- qcom,<supply>-always-on - specifies whether supply should be kept "on" always.
@@ -51,6 +55,18 @@
- qcom,pad-drv-off - Suspend drive strength configuration for sdc tlmm pins.
Tlmm pins are specified as <clk cmd data>
+ - qcom,bus-bw-vectors-bps: specifies array of throughput values in
+ Bytes/sec. The values in the array are determined according to
+ supported bus speed modes. For example, if host supports SDR12 mode,
+ value is 13631488 Bytes/sec.
+ - Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for
+ below optional properties:
+ - qcom,msm-bus,name
+ - qcom,msm-bus,num-cases
+ - qcom,msm-bus,active-only
+ - qcom,msm-bus,num-paths
+ - qcom,msm-bus,vectors-KBps
+
Example:
aliases {
@@ -86,6 +102,7 @@
<&msmgpio 36 0>, /* DATA2 */
<&msmgpio 35 0>; /* DATA3 */
qcom,gpio-names = "CLK", "CMD", "DAT0", "DAT1", "DAT2", "DAT3";
+ qcom,cpu-dma-latency-us = <200>;
};
sdhc_2: qcom,sdhc@f98a4900 {
@@ -104,4 +121,18 @@
qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+ qcom,cpu-dma-latency-us = <200>;
+ qcom,msm-bus,name = "sdhc2";
+ qcom,msm-bus,num-cases = <7>;
+ qcom,msm-bus,active-only = <0>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps = <81 512 0 0>, /* No vote */
+ <81 512 6656 13312>, /* 13 MB/s*/
+ <81 512 13312 26624>, /* 26 MB/s */
+ <81 512 26624 53248>, /* 52 MB/s */
+ <81 512 53248 106496>, /* 104 MB/s */
+ <81 512 106496 212992>, /* 208 MB/s */
+ <81 512 2147483647 4294967295>; /* Max. bandwidth */
+ qcom,bus-bw-vectors-bps = <0 13631488 27262976 54525952 109051904 218103808 4294967295>;
};
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
index 8f602b6..df3f71c 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
@@ -17,14 +17,14 @@
- vdd_cx-supply: Reference to the regulator that supplies the vdd_cx domain.
- vdd_mx-supply: Reference to the regulator that supplies the memory rail.
- qcom,firmware-name: Base name of the firmware image. Ex. "mdsp"
-- qcom,pil-self-auth: <0> if the hardware does not require self-authenticating
- images and self-authentication is not desired;
- <1> if the hardware requires self-authenticating images.
-- qcom,is-loadable: if PIL is required to load the modem image
Optional properties:
- vdd_pll-supply: Reference to the regulator that supplies the PLL's rail.
- qcom,vdd_pll: Voltage to be set for the PLL's rail.
+- reg-names: "cxrail_bhs_reg" - control register for modem power
+ domain.
+- qcom,is-loadable: Boolean- Present if the image needs to be loaded.
+- qcom,pil-self-auth: Boolean- True if authentication is required.
Example:
qcom,mss@fc880000 {
@@ -43,5 +43,5 @@
qcom,is-loadable;
qcom,firmware-name = "mba";
- qcom,pil-self-auth = <1>;
+ qcom,pil-self-auth;
};
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index 859db3b..6cf59ee 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -112,6 +112,8 @@
Optional properties :
- qcom,usb2-enable-hsphy2: If present, select second PHY for USB operation.
+- qcom,pool-64-bit-align: If present then the pool's memory will be aligned
+ to 64 bits
Example MSM HSUSB EHCI controller device node :
ehci: qcom,ehci-host@f9a55000 {
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 8111b40..46812e7 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -541,6 +541,29 @@
qcom,firmware-name = "adsp";
};
+ qcom,mss@fc880000 {
+ compatible = "qcom,pil-q6v5-mss";
+ reg = <0xfc880000 0x100>,
+ <0xfd485000 0x400>,
+ <0xfc820000 0x020>,
+ <0xfc401680 0x004>,
+ <0x0d1fc000 0x4000>,
+ <0xfd485194 0x4>;
+ reg-names = "qdsp6_base", "halt_base", "rmb_base",
+ "restart_reg", "metadata_base", "cxrail_bhs_reg";
+
+ interrupts = <0 24 1>;
+ vdd_mss-supply = <&pm8226_s1>;
+ vdd_cx-supply = <&pm8226_s1_corner>;
+ vdd_mx-supply = <&pm8226_l3>;
+ vdd_pll-supply = <&pm8226_l8>;
+ qcom,vdd_pll = <1800000>;
+
+ qcom,is-loadable;
+ qcom,firmware-name = "mba";
+ qcom,pil-self-auth;
+ };
+
qcom,msm-mem-hole {
compatible = "qcom,msm-mem-hole";
qcom,memblock-remove = <0x8400000 0x7b00000>; /* Address and Size of Hole */
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index ab6b7c8..1922591 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -344,6 +344,7 @@
interrupts = <0 123 0>, <0 138 0>;
interrupt-names = "hc_irq", "pwr_irq";
qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+ qcom,cpu-dma-latency-us = <200>;
status = "disable";
};
@@ -355,6 +356,7 @@
interrupt-names = "hc_irq", "pwr_irq";
qcom,bus-width = <4>;
+ qcom,cpu-dma-latency-us = <200>;
status = "disable";
};
@@ -373,6 +375,7 @@
qcom,gpio-names = "CLK", "CMD", "DAT0", "DAT1", "DAT2", "DAT3";
qcom,bus-width = <4>;
+ qcom,cpu-dma-latency-us = <200>;
status = "disable";
};
@@ -391,6 +394,7 @@
qcom,gpio-names = "CLK", "CMD", "DAT0", "DAT1", "DAT2", "DAT3";
qcom,bus-width = <4>;
+ qcom,cpu-dma-latency-us = <200>;
status = "disable";
};
@@ -914,7 +918,7 @@
qcom,vdd_pll = <1800000>;
qcom,is-loadable;
qcom,firmware-name = "mba";
- qcom,pil-self-auth = <1>;
+ qcom,pil-self-auth;
};
qcom,pronto@fb21b000 {
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index 03eaaf3..e1501ac 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -91,6 +91,7 @@
qcom,hsusb-otg-disable-reset;
qcom,hsusb-otg-lpm-on-dev-suspend;
qcom,hsusb-otg-clk-always-on-workaround;
+ qcom,hsusb-otg-delay-lpm;
qcom,msm-bus,name = "usb2";
qcom,msm-bus,num-cases = <2>;
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index c6be3c5..4b7065b 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -460,6 +460,6 @@
CONFIG_CRYPTO_XCBC=y
CONFIG_CRYPTO_TWOFISH=y
CONFIG_CRYPTO_DEV_QCRYPTO=m
-CONFIG_CRYPTO_DEV_QCE=m
-CONFIG_CRYPTO_DEV_QCEDEV=m
+CONFIG_CRYPTO_DEV_QCE=y
+CONFIG_CRYPTO_DEV_QCEDEV=y
CONFIG_CRC_CCITT=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index f77f04f..6a4737c 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -485,6 +485,6 @@
CONFIG_CRYPTO_XCBC=y
CONFIG_CRYPTO_TWOFISH=y
CONFIG_CRYPTO_DEV_QCRYPTO=m
-CONFIG_CRYPTO_DEV_QCE=m
-CONFIG_CRYPTO_DEV_QCEDEV=m
+CONFIG_CRYPTO_DEV_QCE=y
+CONFIG_CRYPTO_DEV_QCEDEV=y
CONFIG_CRC_CCITT=y
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 1d07356..27ad085 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -110,7 +110,7 @@
#define MSM_ION_MM_SIZE 0x3800000
#define MSM_ION_SF_SIZE 0
#define MSM_ION_QSECOM_SIZE 0x780000 /* (7.5MB) */
-#define MSM_ION_HEAP_NUM 7
+#define MSM_ION_HEAP_NUM 8
#else
#define MSM_ION_MM_SIZE MSM_PMEM_ADSP_SIZE
#define MSM_ION_SF_SIZE MSM_PMEM_SIZE
@@ -130,6 +130,7 @@
#define MAX_FIXED_AREA_SIZE 0x10000000
#define MSM_MM_FW_SIZE (0x200000 - HOLE_SIZE)
#define APQ8064_FW_START APQ8064_FIXED_AREA_START
+#define MSM_ION_ADSP_SIZE SZ_8M
#define QFPROM_RAW_FEAT_CONFIG_ROW0_MSB (MSM_QFPROM_BASE + 0x23c)
#define QFPROM_RAW_OEM_CONFIG_ROW0_LSB (MSM_QFPROM_BASE + 0x220)
@@ -341,6 +342,14 @@
}
};
+static struct platform_device ion_adsp_heap_device = {
+ .name = "ion-adsp-heap-device",
+ .id = -1,
+ .dev = {
+ .dma_mask = &msm_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ }
+};
/**
* These heaps are listed in the order they will be allocated. Due to
* video hardware restrictions and content protection the FW heap has to
@@ -415,6 +424,15 @@
.memory_type = ION_EBI_TYPE,
.extra_data = (void *) &co_apq8064_ion_pdata,
},
+ {
+ .id = ION_ADSP_HEAP_ID,
+ .type = ION_HEAP_TYPE_DMA,
+ .name = ION_ADSP_HEAP_NAME,
+ .size = MSM_ION_ADSP_SIZE,
+ .memory_type = ION_EBI_TYPE,
+ .extra_data = (void *) &co_apq8064_ion_pdata,
+ .priv = &ion_adsp_heap_device.dev,
+ },
#endif
};
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 73b4eb7..f8e1a90 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -150,7 +150,7 @@
#define MSM_ION_MM_SIZE 0x3800000 /* Need to be multiple of 64K */
#define MSM_ION_SF_SIZE 0x0
#define MSM_ION_QSECOM_SIZE 0x780000 /* (7.5MB) */
-#define MSM_ION_HEAP_NUM 7
+#define MSM_ION_HEAP_NUM 8
#else
#define MSM_ION_SF_SIZE MSM_PMEM_SIZE
#define MSM_ION_MM_SIZE MSM_PMEM_ADSP_SIZE
@@ -170,6 +170,7 @@
HOLE_SIZE))
#define MAX_FIXED_AREA_SIZE 0x10000000
#define MSM8930_FW_START MSM8930_FIXED_AREA_START
+#define MSM_ION_ADSP_SIZE SZ_8M
#else
#define MSM_CONTIG_MEM_SIZE 0x110C000
@@ -380,6 +381,14 @@
}
};
+static struct platform_device ion_adsp_heap_device = {
+ .name = "ion-adsp-heap-device",
+ .id = -1,
+ .dev = {
+ .dma_mask = &msm_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ }
+};
/**
* These heaps are listed in the order they will be allocated. Due to
* video hardware restrictions and content protection the FW heap has to
@@ -454,6 +463,15 @@
.memory_type = ION_EBI_TYPE,
.extra_data = (void *) &co_msm8930_ion_pdata,
},
+ {
+ .id = ION_ADSP_HEAP_ID,
+ .type = ION_HEAP_TYPE_DMA,
+ .name = ION_ADSP_HEAP_NAME,
+ .size = MSM_ION_ADSP_SIZE,
+ .memory_type = ION_EBI_TYPE,
+ .extra_data = (void *) &co_msm8930_ion_pdata,
+ .priv = &ion_adsp_heap_device.dev,
+ },
#endif
};
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index bd54756..74f152e 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -160,7 +160,7 @@
#define MSM_ION_MM_SIZE 0x3800000 /* Need to be multiple of 64K */
#define MSM_ION_SF_SIZE 0x0
#define MSM_ION_QSECOM_SIZE 0x780000 /* (7.5MB) */
-#define MSM_ION_HEAP_NUM 7
+#define MSM_ION_HEAP_NUM 8
#else
#define MSM_ION_MM_SIZE MSM_PMEM_ADSP_SIZE
#define MSM_ION_SF_SIZE MSM_PMEM_SIZE
@@ -180,6 +180,7 @@
HOLE_SIZE))
#define MAX_FIXED_AREA_SIZE 0x10000000
#define MSM8960_FW_START MSM8960_FIXED_AREA_START
+#define MSM_ION_ADSP_SIZE SZ_8M
static unsigned msm_ion_sf_size = MSM_ION_SF_SIZE;
#else
@@ -402,6 +403,15 @@
}
};
+static struct platform_device ion_adsp_heap_device = {
+ .name = "ion-adsp-heap-device",
+ .id = -1,
+ .dev = {
+ .dma_mask = &msm_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ }
+};
+
/**
* These heaps are listed in the order they will be allocated. Due to
* video hardware restrictions and content protection the FW heap has to
@@ -476,6 +486,15 @@
.memory_type = ION_EBI_TYPE,
.extra_data = (void *) &co_msm8960_ion_pdata,
},
+ {
+ .id = ION_ADSP_HEAP_ID,
+ .type = ION_HEAP_TYPE_DMA,
+ .name = ION_ADSP_HEAP_NAME,
+ .size = MSM_ION_ADSP_SIZE,
+ .memory_type = ION_EBI_TYPE,
+ .extra_data = (void *) &co_msm8960_ion_pdata,
+ .priv = &ion_adsp_heap_device.dev,
+ },
#endif
};
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index b40617c..898b7e0 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -2559,7 +2559,7 @@
static struct branch_clk oxili_gfx3d_clk = {
.cbcr_reg = OXILI_GFX3D_CBCR,
- .has_sibling = 1,
+ .has_sibling = 0,
.max_div = 0,
.base = &virt_bases[MMSS_BASE],
.c = {
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index 214d1b7..c3b4ca7 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -805,7 +805,6 @@
struct clk_ops clk_ops_rcg_hdmi = {
.enable = rcg_clk_prepare,
.set_rate = rcg_clk_set_rate_hdmi,
- .set_rate = rcg_clk_set_rate,
.list_rate = rcg_clk_list_rate,
.round_rate = rcg_clk_round_rate,
.handoff = rcg_clk_handoff,
diff --git a/arch/arm/mach-msm/include/mach/ipa.h b/arch/arm/mach-msm/include/mach/ipa.h
index f2a4427..2010abb 100644
--- a/arch/arm/mach-msm/include/mach/ipa.h
+++ b/arch/arm/mach-msm/include/mach/ipa.h
@@ -355,36 +355,6 @@
};
/**
- * enum ipa_rm_resource_name - IPA RM clients identification names
- *
- * Add new mapping to ipa_rm_dep_prod_index() / ipa_rm_dep_cons_index()
- * when adding new entry to this enum.
- */
-enum ipa_rm_resource_name {
- IPA_RM_RESOURCE_PROD = 0,
- IPA_RM_RESOURCE_BRIDGE_PROD = IPA_RM_RESOURCE_PROD,
- IPA_RM_RESOURCE_A2_PROD,
- IPA_RM_RESOURCE_USB_PROD,
- IPA_RM_RESOURCE_HSIC_PROD,
- IPA_RM_RESOURCE_STD_ECM_PROD,
- IPA_RM_RESOURCE_WWAN_0_PROD,
- IPA_RM_RESOURCE_WWAN_1_PROD,
- IPA_RM_RESOURCE_WWAN_2_PROD,
- IPA_RM_RESOURCE_WWAN_3_PROD,
- IPA_RM_RESOURCE_WWAN_4_PROD,
- IPA_RM_RESOURCE_WWAN_5_PROD,
- IPA_RM_RESOURCE_WWAN_6_PROD,
- IPA_RM_RESOURCE_WWAN_7_PROD,
- IPA_RM_RESOURCE_WLAN_PROD,
- IPA_RM_RESOURCE_PROD_MAX,
-
- IPA_RM_RESOURCE_A2_CONS = IPA_RM_RESOURCE_PROD_MAX,
- IPA_RM_RESOURCE_USB_CONS,
- IPA_RM_RESOURCE_HSIC_CONS,
- IPA_RM_RESOURCE_MAX
-};
-
-/**
* enum ipa_rm_event - IPA RM events
*
* Indicate the resource state change
diff --git a/arch/arm/mach-msm/include/mach/usb_bam.h b/arch/arm/mach-msm/include/mach/usb_bam.h
index a7f052e..b3fb8af 100644
--- a/arch/arm/mach-msm/include/mach/usb_bam.h
+++ b/arch/arm/mach-msm/include/mach/usb_bam.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -163,12 +163,6 @@
*/
int usb_bam_client_ready(bool ready);
-/**
- * Returns QDSS BAM connection number
- *
- */
-u8 usb_bam_get_qdss_num(void);
-
#else
static inline int usb_bam_connect(u8 idx, u32 *src_pipe_idx, u32 *dst_pipe_idx)
{
@@ -222,10 +216,5 @@
return -ENODEV;
}
-static inline u8 usb_bam_get_qdss_num(void)
-{
- return -ENODEV;
-}
-
#endif
#endif /* _USB_BAM_H_ */
diff --git a/arch/arm/mach-msm/ipc_socket.c b/arch/arm/mach-msm/ipc_socket.c
index a08e7de..16b60a1 100644
--- a/arch/arm/mach-msm/ipc_socket.c
+++ b/arch/arm/mach-msm/ipc_socket.c
@@ -613,13 +613,14 @@
void msm_ipc_router_ipc_log_init(void)
{
ipc_req_resp_log_txt =
- ipc_log_context_create(REQ_RESP_IPC_LOG_PAGES, "req_resp");
+ ipc_log_context_create(REQ_RESP_IPC_LOG_PAGES,
+ "ipc_rtr_req_resp");
if (!ipc_req_resp_log_txt) {
pr_err("%s: Unable to create IPC logging for Req/Resp",
__func__);
}
ipc_ind_log_txt =
- ipc_log_context_create(IND_IPC_LOG_PAGES, "indication");
+ ipc_log_context_create(IND_IPC_LOG_PAGES, "ipc_rtr_ind");
if (!ipc_ind_log_txt) {
pr_err("%s: Unable to create IPC logging for Indications",
__func__);
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
index 539a4fe..8194721 100644
--- a/arch/arm/mach-msm/lpm_levels.c
+++ b/arch/arm/mach-msm/lpm_levels.c
@@ -205,6 +205,8 @@
int best_level_iter = msm_lpm_level_count + 1;
bool irqs_detect = false;
bool gpio_detect = false;
+ bool modify_event_timer;
+ uint32_t next_wakeup_us = time_param->sleep_us;
if (!msm_lpm_levels)
return NULL;
@@ -219,6 +221,8 @@
for (i = 0; i < msm_lpm_level_count; i++) {
struct msm_rpmrs_level *level = &msm_lpm_levels[i];
+ modify_event_timer = false;
+
if (!level->available)
continue;
@@ -228,6 +232,23 @@
if (time_param->latency_us < level->latency_us)
continue;
+ if (time_param->next_event_us &&
+ time_param->next_event_us < level->latency_us)
+ continue;
+
+ if (time_param->next_event_us) {
+ if ((time_param->next_event_us < time_param->sleep_us)
+ || ((time_param->next_event_us - level->latency_us) <
+ time_param->sleep_us)) {
+ modify_event_timer = true;
+ next_wakeup_us = time_param->next_event_us -
+ level->latency_us;
+ }
+ }
+
+ if (next_wakeup_us <= level->time_overhead_us)
+ continue;
+
if ((sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) &&
!msm_lpm_irqs_detectable(&level->rs_limits,
irqs_detect, gpio_detect))
@@ -238,19 +259,19 @@
if (!cpu && msm_rpm_waiting_for_ack())
break;
- if (time_param->sleep_us <= 1) {
+ if (next_wakeup_us <= 1) {
pwr = level->energy_overhead;
- } else if (time_param->sleep_us <= level->time_overhead_us) {
- pwr = level->energy_overhead / time_param->sleep_us;
- } else if ((time_param->sleep_us >> 10)
+ } else if (next_wakeup_us <= level->time_overhead_us) {
+ pwr = level->energy_overhead / next_wakeup_us;
+ } else if ((next_wakeup_us >> 10)
> level->time_overhead_us) {
pwr = level->steady_state_power;
} else {
pwr = level->steady_state_power;
pwr -= (level->time_overhead_us *
level->steady_state_power) /
- time_param->sleep_us;
- pwr += level->energy_overhead / time_param->sleep_us;
+ next_wakeup_us;
+ pwr += level->energy_overhead / next_wakeup_us;
}
if (!best_level || best_level->rs_limits.power[cpu] >= pwr) {
@@ -261,6 +282,14 @@
best_level_iter = i;
if (power)
*power = pwr;
+ if (modify_event_timer &&
+ (sleep_mode !=
+ MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT))
+ time_param->modified_time_us =
+ time_param->next_event_us -
+ best_level->latency_us;
+ else
+ time_param->modified_time_us = 0;
}
}
if (best_level && !lpm_level_permitted(best_level_iter))
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
index aa42f5b..1954ec3 100644
--- a/arch/arm/mach-msm/pil-q6v5-mss.c
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -70,6 +70,11 @@
#define MAX_SSR_REASON_LEN 81U
+/* External BHS */
+#define EXTERNAL_BHS_ON BIT(0)
+#define EXTERNAL_BHS_STATUS BIT(4)
+#define BHS_TIMEOUT_US 50
+
struct mba_data {
void __iomem *metadata_base;
void __iomem *rmb_base;
@@ -81,7 +86,7 @@
void *adsp_state_notifier;
u32 img_length;
struct q6v5_data *q6;
- int self_auth;
+ bool self_auth;
void *ramdump_dev;
void *smem_ramdump_dev;
bool crash_shutdown;
@@ -99,16 +104,34 @@
{
int ret;
struct device *dev = drv->desc.dev;
+ u32 regval;
ret = regulator_enable(drv->vreg);
if (ret)
dev_err(dev, "Failed to enable modem regulator.\n");
+ if (drv->cxrail_bhs) {
+ regval = readl_relaxed(drv->cxrail_bhs);
+ regval |= EXTERNAL_BHS_ON;
+ writel_relaxed(regval, drv->cxrail_bhs);
+
+ ret = readl_poll_timeout(drv->cxrail_bhs, regval,
+ regval & EXTERNAL_BHS_STATUS, 1, BHS_TIMEOUT_US);
+ }
+
return ret;
}
static int pil_mss_power_down(struct q6v5_data *drv)
{
+ u32 regval;
+
+ if (drv->cxrail_bhs) {
+ regval = readl_relaxed(drv->cxrail_bhs);
+ regval &= ~EXTERNAL_BHS_ON;
+ writel_relaxed(regval, drv->cxrail_bhs);
+ }
+
return regulator_disable(drv->vreg);
}
@@ -198,10 +221,15 @@
pil_q6v5_shutdown(pil);
pil_mss_disable_clks(drv);
- pil_mss_power_down(drv);
writel_relaxed(1, drv->restart_reg);
+ /*
+ * access to the cx_rail_bhs is restricted until after the gcc_mss
+ * reset is asserted once the PBL starts executing.
+ */
+ pil_mss_power_down(drv);
+
drv->is_booted = false;
return 0;
@@ -215,11 +243,6 @@
unsigned long start_addr = pil_get_entry_addr(pil);
int ret;
- /* Deassert reset to subsystem and wait for propagation */
- writel_relaxed(0, drv->restart_reg);
- mb();
- udelay(2);
-
/*
* Bring subsystem out of reset and enable required
* regulators and clocks.
@@ -228,6 +251,11 @@
if (ret)
goto err_power;
+ /* Deassert reset to subsystem and wait for propagation */
+ writel_relaxed(0, drv->restart_reg);
+ mb();
+ udelay(2);
+
ret = pil_mss_enable_clks(drv);
if (ret)
goto err_clks;
@@ -679,8 +707,8 @@
q6_desc->owner = THIS_MODULE;
q6_desc->proxy_timeout = PROXY_TIMEOUT_MS;
- of_property_read_u32(pdev->dev.of_node, "qcom,pil-self-auth",
- &drv->self_auth);
+ drv->self_auth = of_property_read_bool(pdev->dev.of_node,
+ "qcom,pil-self-auth");
if (drv->self_auth) {
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"rmb_base");
@@ -721,6 +749,13 @@
return ret;
}
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "cxrail_bhs_reg");
+ if (res)
+ q6->cxrail_bhs = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+
+
q6->ahb_clk = devm_clk_get(&pdev->dev, "iface_clk");
if (IS_ERR(q6->ahb_clk))
return PTR_ERR(q6->ahb_clk);
diff --git a/arch/arm/mach-msm/pil-q6v5.h b/arch/arm/mach-msm/pil-q6v5.h
index 0d986a6..48d10df 100644
--- a/arch/arm/mach-msm/pil-q6v5.h
+++ b/arch/arm/mach-msm/pil-q6v5.h
@@ -22,12 +22,13 @@
struct q6v5_data {
void __iomem *reg_base;
- struct clk *xo; /* XO clock source */
- struct clk *ahb_clk; /* PIL access to registers */
- struct clk *axi_clk; /* CPU access to memory */
- struct clk *core_clk; /* CPU core */
- struct clk *reg_clk; /* CPU access registers */
- struct clk *rom_clk; /* Boot ROM */
+ void __iomem *cxrail_bhs; /* External BHS register */
+ struct clk *xo; /* XO clock source */
+ struct clk *ahb_clk; /* PIL access to registers */
+ struct clk *axi_clk; /* CPU access to memory */
+ struct clk *core_clk; /* CPU core */
+ struct clk *reg_clk; /* CPU access registers */
+ struct clk *rom_clk; /* Boot ROM */
void __iomem *axi_halt_base;
void __iomem *restart_reg;
struct regulator *vreg;
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 0867676..1c9f968 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -107,43 +107,40 @@
break;
}
}
- if (index == -1)
+ if (index == -1) {
pr_alert("diag: No matching PID for DCI data\n");
+ return;
+ }
/* Using PID of client process, find client buffer */
- for (i = 0; i < MAX_DCI_CLIENTS; i++) {
- if (driver->dci_client_tbl[i].client != NULL) {
- if (curr_client_pid ==
- driver->dci_client_tbl[i].client->tgid) {
- /* copy pkt rsp in client buf */
- entry = &(driver->dci_client_tbl[i]);
- if (DCI_CHK_CAPACITY(entry, 8+write_len)) {
- pr_alert("diag: create capacity for pkt rsp\n");
- entry->total_capacity += 8+write_len;
- temp_buf = krealloc(entry->dci_data,
- entry->total_capacity, GFP_KERNEL);
- if (!temp_buf) {
- pr_err("diag: DCI realloc failed\n");
- break;
- } else {
- entry->dci_data = temp_buf;
- }
- }
- *(int *)(entry->dci_data+entry->data_len) =
- DCI_PKT_RSP_TYPE;
- entry->data_len += 4;
- *(int *)(entry->dci_data+entry->data_len)
- = write_len;
- entry->data_len += 4;
- memcpy(entry->dci_data+entry->data_len,
- buf+4+cmd_code_len, write_len);
- entry->data_len += write_len;
- /* delete immediate response entry */
- if (driver->smd_dci[MODEM_DATA].
- buf_in_1[8+cmd_code_len] != 0x80)
- driver->req_tracking_tbl[index].pid = 0;
- break;
+ i = diag_dci_find_client_index(curr_client_pid);
+ if (i != DCI_CLIENT_INDEX_INVALID) {
+ /* copy pkt rsp in client buf */
+ entry = &(driver->dci_client_tbl[i]);
+ if (DCI_CHK_CAPACITY(entry, 8+write_len)) {
+ pr_alert("diag: create capacity for pkt rsp\n");
+ entry->total_capacity += 8+write_len;
+ temp_buf = krealloc(entry->dci_data,
+ entry->total_capacity, GFP_KERNEL);
+ if (!temp_buf) {
+ pr_err("diag: DCI realloc failed\n");
+ return;
+ } else {
+ entry->dci_data = temp_buf;
}
}
+ *(int *)(entry->dci_data+entry->data_len) =
+ DCI_PKT_RSP_TYPE;
+ entry->data_len += 4;
+ *(int *)(entry->dci_data+entry->data_len)
+ = write_len;
+ entry->data_len += 4;
+ memcpy(entry->dci_data+entry->data_len,
+ buf+4+cmd_code_len, write_len);
+ entry->data_len += write_len;
+ /* delete immediate response entry */
+ if (driver->smd_dci[MODEM_DATA].
+ buf_in_1[8+cmd_code_len] != 0x80)
+ driver->req_tracking_tbl[index].pid = 0;
}
}
@@ -527,16 +524,8 @@
}
} else if (*(int *)temp == DCI_LOG_TYPE) {
/* find client id and table */
- for (i = 0; i < MAX_DCI_CLIENTS; i++) {
- if (driver->dci_client_tbl[i].client != NULL) {
- if (driver->dci_client_tbl[i].client->tgid ==
- current->tgid) {
- found = 1;
- break;
- }
- }
- }
- if (!found) {
+ i = diag_dci_find_client_index(current->tgid);
+ if (i == DCI_CLIENT_INDEX_INVALID) {
pr_err("diag: dci client not registered/found\n");
return ret;
}
@@ -610,16 +599,8 @@
ret = diag_send_dci_log_mask(driver->smd_cntl[MODEM_DATA].ch);
} else if (*(int *)temp == DCI_EVENT_TYPE) {
/* find client id and table */
- for (i = 0; i < MAX_DCI_CLIENTS; i++) {
- if (driver->dci_client_tbl[i].client != NULL) {
- if (driver->dci_client_tbl[i].client->tgid ==
- current->tgid) {
- found = 1;
- break;
- }
- }
- }
- if (!found) {
+ i = diag_dci_find_client_index(current->tgid);
+ if (i == DCI_CLIENT_INDEX_INVALID) {
pr_err("diag: dci client not registered/found\n");
return ret;
}
@@ -672,6 +653,22 @@
return ret;
}
+int diag_dci_find_client_index(int client_id)
+{
+ int i, ret = DCI_CLIENT_INDEX_INVALID;
+
+ for (i = 0; i < MAX_DCI_CLIENTS; i++) {
+ if (driver->dci_client_tbl[i].client != NULL) {
+ if (driver->dci_client_tbl[i].client->tgid ==
+ client_id) {
+ ret = i;
+ break;
+ }
+ }
+ }
+ return ret;
+}
+
void update_dci_cumulative_event_mask(int offset, uint8_t byte_mask)
{
int i;
@@ -698,6 +695,69 @@
mutex_unlock(&dci_event_mask_mutex);
}
+void clear_client_dci_cumulative_event_mask(int client_index)
+{
+ int i, j;
+ uint8_t *update_ptr = dci_cumulative_event_mask;
+ uint8_t *event_mask_ptr, *client_event_mask_ptr, byte_mask = 0;
+ bool is_set = false;
+
+ event_mask_ptr =
+ (driver->dci_client_tbl[client_index].dci_event_mask);
+
+ mutex_lock(&dci_event_mask_mutex);
+ for (i = 0; i < DCI_EVENT_MASK_SIZE; i++) {
+ is_set = false;
+ /* Already cleared event masks need not to be considered */
+ if (*event_mask_ptr != 0) {
+ byte_mask = *event_mask_ptr;
+ } else {
+ update_ptr++;
+ event_mask_ptr++;
+ continue;
+ }
+ for (j = 0; j < MAX_DCI_CLIENTS; j++) {
+ /* continue searching for valid client */
+ if (driver->dci_client_tbl[j].client == NULL ||
+ client_index == j)
+ continue;
+ client_event_mask_ptr =
+ (driver->dci_client_tbl[j].dci_event_mask);
+ client_event_mask_ptr += i;
+ if (*client_event_mask_ptr & byte_mask) {
+ /*
+ * Break if another client has same
+ * event mask set
+ */
+ if ((*client_event_mask_ptr &
+ byte_mask) == byte_mask) {
+ is_set = true;
+ break;
+ } else {
+ byte_mask =
+ (~(*client_event_mask_ptr) &
+ byte_mask);
+ is_set = false;
+ }
+ }
+ }
+ /*
+ * Clear only if this client has event mask set else
+ * don't update cumulative event mask ptr
+ */
+ if (is_set == false)
+ *update_ptr &= ~byte_mask;
+
+ update_ptr++;
+ event_mask_ptr++;
+ }
+ event_mask_ptr =
+ (driver->dci_client_tbl[client_index].dci_event_mask);
+ memset(event_mask_ptr, 0, DCI_EVENT_MASK_SIZE);
+ mutex_unlock(&dci_event_mask_mutex);
+}
+
+
int diag_send_dci_event_mask(smd_channel_t *ch)
{
void *buf = driver->buf_event_mask_update;
@@ -777,6 +837,87 @@
mutex_unlock(&dci_log_mask_mutex);
}
+void clear_client_dci_cumulative_log_mask(int client_index)
+{
+ int i, j, k;
+ uint8_t *update_ptr = dci_cumulative_log_mask;
+ uint8_t *log_mask_ptr, *client_log_mask_ptr, byte_mask = 0;
+ bool is_set = false;
+
+ log_mask_ptr = driver->dci_client_tbl[client_index].dci_log_mask;
+
+ mutex_lock(&dci_log_mask_mutex);
+ *update_ptr = 0;
+ /* set the equipment IDs */
+ for (i = 0; i < 16; i++)
+ *(update_ptr + (i*514)) = i;
+
+ /* update cumulative log mask ptr*/
+ update_ptr += 2;
+ log_mask_ptr += 2;
+ for (i = 0; i < 16; i++) {
+ for (j = 0; j < 512; j++) {
+ is_set = false;
+ /*
+ * Already cleared log masks need
+ * not to be considered
+ */
+ if (*log_mask_ptr != 0) {
+ byte_mask = *log_mask_ptr;
+ } else {
+ update_ptr++;
+ log_mask_ptr++;
+ continue;
+ }
+ for (k = 0; k < MAX_DCI_CLIENTS; k++) {
+ /* continue searching for valid client */
+ if (driver->dci_client_tbl[k].client == NULL ||
+ client_index == k)
+ continue;
+ client_log_mask_ptr =
+ (driver->dci_client_tbl[k].dci_log_mask);
+ client_log_mask_ptr += (i*514) + 2 + j;
+ if (*client_log_mask_ptr & byte_mask) {
+ /*
+ * Break if another client has same
+ * log mask set
+ */
+ if ((*client_log_mask_ptr &
+ byte_mask) == byte_mask) {
+ is_set = true;
+ break;
+ } else {
+ byte_mask =
+ (~(*client_log_mask_ptr) &
+ byte_mask);
+ is_set = false;
+ }
+ }
+ }
+ /*
+ * Clear only if this client has log mask set else
+ * don't update cumulative log mask ptr
+ */
+ if (is_set == false) {
+ /*
+ * Update the dirty bit for the equipment
+ * whose mask is changing
+ */
+ dci_cumulative_log_mask[1+(i*514)] = 1;
+ *update_ptr &= ~byte_mask;
+ }
+
+ update_ptr++;
+ log_mask_ptr++;
+ }
+ update_ptr += 2;
+ log_mask_ptr += 2;
+ }
+ log_mask_ptr = driver->dci_client_tbl[client_index].dci_log_mask;
+ memset(log_mask_ptr, 0, DCI_LOG_MASK_SIZE);
+ mutex_unlock(&dci_log_mask_mutex);
+}
+
int diag_send_dci_log_mask(smd_channel_t *ch)
{
void *buf = driver->buf_log_mask_update;
@@ -886,10 +1027,12 @@
mutex_init(&driver->dci_mutex);
mutex_init(&dci_log_mask_mutex);
mutex_init(&dci_event_mask_mutex);
- success = diag_smd_constructor(&driver->smd_dci[MODEM_DATA],
- MODEM_DATA, SMD_DCI_TYPE);
- if (!success)
- goto err;
+ for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) {
+ success = diag_smd_constructor(&driver->smd_dci[i],
+ i, SMD_DCI_TYPE);
+ if (!success)
+ goto err;
+ }
if (driver->req_tracking_tbl == NULL) {
driver->req_tracking_tbl = kzalloc(dci_max_reg *
diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h
index 0f47740..9187516 100644
--- a/drivers/char/diag/diag_dci.h
+++ b/drivers/char/diag/diag_dci.h
@@ -23,6 +23,8 @@
#define SET_LOG_MASK 1
#define DISABLE_LOG_MASK 0
#define MAX_EVENT_SIZE 512
+#define DCI_CLIENT_INDEX_INVALID -1
+
/* 16 log code categories, each has:
* 1 bytes equip id + 1 dirty byte + 512 byte max log mask
@@ -86,14 +88,17 @@
int diag_send_dci_pkt(struct diag_master_table entry, unsigned char *buf,
int len, int index);
void extract_dci_pkt_rsp(unsigned char *buf);
+int diag_dci_find_client_index(int client_id);
/* DCI Log streaming functions */
void create_dci_log_mask_tbl(unsigned char *tbl_buf);
void update_dci_cumulative_log_mask(int offset, unsigned int byte_index,
uint8_t byte_mask);
+void clear_client_dci_cumulative_log_mask(int client_index);
int diag_send_dci_log_mask(smd_channel_t *ch);
void extract_dci_log(unsigned char *buf);
/* DCI event streaming functions */
void update_dci_cumulative_event_mask(int offset, uint8_t byte_mask);
+void clear_client_dci_cumulative_event_mask(int client_index);
int diag_send_dci_event_mask(smd_channel_t *ch);
void extract_dci_events(unsigned char *buf);
void create_dci_event_mask_tbl(unsigned char *tbl_buf);
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 13e52df..2809900 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -245,7 +245,7 @@
static int diagchar_close(struct inode *inode, struct file *file)
{
- int i = 0;
+ int i = -1;
struct diagchar_priv *diagpriv_data = file->private_data;
pr_debug("diag: process exit %s\n", current->comm);
@@ -261,14 +261,9 @@
* This will specially help in case of ungraceful exit of any DCI client
* This call will remove any pending registrations of such client
*/
- for (i = 0; i < MAX_DCI_CLIENTS; i++) {
- if (driver->dci_client_tbl[i].client &&
- driver->dci_client_tbl[i].client->tgid ==
- current->tgid) {
- diagchar_ioctl(NULL, DIAG_IOCTL_DCI_DEINIT, 0);
- break;
- }
- }
+ if (diag_dci_find_client_index(current->tgid) !=
+ DCI_CLIENT_INDEX_INVALID)
+ diagchar_ioctl(NULL, DIAG_IOCTL_DCI_DEINIT, 0);
/* If the exiting process is the socket process */
if (driver->socket_process &&
(driver->socket_process->tgid == current->tgid)) {
@@ -530,7 +525,7 @@
long diagchar_ioctl(struct file *filp,
unsigned int iocmd, unsigned long ioarg)
{
- int i, j, temp, success = -1, status;
+ int i, j, temp, success = -1, status, index = -1;
unsigned int count_entries = 0, interim_count = 0;
void *temp_buf;
uint16_t support_list = 0;
@@ -731,19 +726,40 @@
return driver->dci_client_id;
} else if (iocmd == DIAG_IOCTL_DCI_DEINIT) {
success = -1;
- /* Delete this process from DCI table */
+ /*
+ * Clear log/event masks and send updated
+ * masks to peripherals
+ */
mutex_lock(&driver->dci_mutex);
+ index = diag_dci_find_client_index(current->tgid);
+ if (index != DCI_CLIENT_INDEX_INVALID) {
+ /* clear respective cumulative log masks */
+ clear_client_dci_cumulative_log_mask(index);
+ /* send updated log mask to peripherals */
+ success =
+ diag_send_dci_log_mask(driver->smd_cntl[MODEM_DATA].ch);
+ if (success != DIAG_DCI_NO_ERROR) {
+ mutex_unlock(&driver->dci_mutex);
+ return success;
+ }
+ /* clear respective cumulative event masks */
+ clear_client_dci_cumulative_event_mask(index);
+ /* send updated event mask to peripherals */
+ success =
+ diag_send_dci_event_mask(
+ driver->smd_cntl[MODEM_DATA].ch);
+ if (success != DIAG_DCI_NO_ERROR) {
+ mutex_unlock(&driver->dci_mutex);
+ return success;
+ }
+ }
+ /* Delete this process from DCI table */
for (i = 0; i < dci_max_reg; i++)
if (driver->req_tracking_tbl[i].pid == current->tgid)
driver->req_tracking_tbl[i].pid = 0;
- for (i = 0; i < MAX_DCI_CLIENTS; i++) {
- if (driver->dci_client_tbl[i].client &&
- driver->dci_client_tbl[i].client->tgid ==
- current->tgid) {
- driver->dci_client_tbl[i].client = NULL;
- success = i;
- break;
- }
+ if (index != DCI_CLIENT_INDEX_INVALID) {
+ driver->dci_client_tbl[index].client = NULL;
+ success = index;
}
if (success >= 0)
driver->num_dci_client--;
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index b1cab9b..c1f2423 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -127,7 +127,7 @@
void (*irq_control)(struct adreno_device *, int);
unsigned int (*irq_pending)(struct adreno_device *);
void * (*snapshot)(struct adreno_device *, void *, int *, int);
- void (*rb_init)(struct adreno_device *, struct adreno_ringbuffer *);
+ int (*rb_init)(struct adreno_device *, struct adreno_ringbuffer *);
void (*start)(struct adreno_device *);
unsigned int (*busy_cycles)(struct adreno_device *);
};
diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c
index 6db6e7b..335d407 100644
--- a/drivers/gpu/msm/adreno_a2xx.c
+++ b/drivers/gpu/msm/adreno_a2xx.c
@@ -1825,13 +1825,16 @@
(mh & kgsl_mmu_get_int_mask())) ? 1 : 0;
}
-static void a2xx_rb_init(struct adreno_device *adreno_dev,
+static int a2xx_rb_init(struct adreno_device *adreno_dev,
struct adreno_ringbuffer *rb)
{
unsigned int *cmds, cmds_gpu;
/* ME_INIT */
cmds = adreno_ringbuffer_allocspace(rb, NULL, 19);
+ if (cmds == NULL)
+ return -ENOMEM;
+
cmds_gpu = rb->buffer_desc.gpuaddr + sizeof(uint)*(rb->wptr-19);
GSL_RB_WRITE(cmds, cmds_gpu, cp_type3_packet(CP_ME_INIT, 18));
@@ -1884,6 +1887,8 @@
GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
adreno_ringbuffer_submit(rb);
+
+ return 0;
}
static unsigned int a2xx_busy_cycles(struct adreno_device *adreno_dev)
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 73a7f52..08c800e 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2486,11 +2486,14 @@
}
}
-static void a3xx_rb_init(struct adreno_device *adreno_dev,
+static int a3xx_rb_init(struct adreno_device *adreno_dev,
struct adreno_ringbuffer *rb)
{
unsigned int *cmds, cmds_gpu;
cmds = adreno_ringbuffer_allocspace(rb, NULL, 18);
+ if (cmds == NULL)
+ return -ENOMEM;
+
cmds_gpu = rb->buffer_desc.gpuaddr + sizeof(uint) * (rb->wptr - 18);
GSL_RB_WRITE(cmds, cmds_gpu, cp_type3_packet(CP_ME_INIT, 17));
@@ -2514,6 +2517,8 @@
GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
adreno_ringbuffer_submit(rb);
+
+ return 0;
}
static void a3xx_err_callback(struct adreno_device *adreno_dev, int bit)
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 1d25646..5cdf911 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -445,7 +445,9 @@
adreno_regwrite(device, REG_CP_ME_CNTL, 0);
/* ME init is GPU specific, so jump into the sub-function */
- adreno_dev->gpudev->rb_init(adreno_dev, rb);
+ status = adreno_dev->gpudev->rb_init(adreno_dev, rb);
+ if (status)
+ return status;
/* idle device to validate ME INIT */
status = adreno_idle(device);
diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c
index 26be9da..c8229e7 100644
--- a/drivers/gpu/msm/adreno_snapshot.c
+++ b/drivers/gpu/msm/adreno_snapshot.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -177,10 +177,11 @@
{ 8, 2 },
};
-static void ib_parse_load_state(struct kgsl_device *device, unsigned int *pkt,
+static int ib_parse_load_state(struct kgsl_device *device, unsigned int *pkt,
unsigned int ptbase)
{
unsigned int block, source, type;
+ int ret = 0;
/*
* The object here is to find indirect shaders i.e - shaders loaded from
@@ -192,7 +193,7 @@
*/
if (type3_pkt_size(pkt[0]) < 2)
- return;
+ return 0;
/*
* pkt[1] 18:16 - source
@@ -220,8 +221,14 @@
pkt[2] & 0xFFFFFFFC,
(((pkt[1] >> 22) & 0x03FF) * unitsize) << 2,
SNAPSHOT_GPU_OBJECT_SHADER);
+
+ if (ret < 0)
+ return -EINVAL;
+
snapshot_frozen_objsize += ret;
}
+
+ return ret;
}
/*
@@ -229,23 +236,31 @@
* visiblity stream size buffer.
*/
-static void ib_parse_set_bin_data(struct kgsl_device *device, unsigned int *pkt,
+static int ib_parse_set_bin_data(struct kgsl_device *device, unsigned int *pkt,
unsigned int ptbase)
{
int ret;
if (type3_pkt_size(pkt[0]) < 2)
- return;
+ return 0;
/* Visiblity stream buffer */
ret = kgsl_snapshot_get_object(device, ptbase, pkt[1], 0,
SNAPSHOT_GPU_OBJECT_GENERIC);
+
+ if (ret < 0)
+ return -EINVAL;
+
snapshot_frozen_objsize += ret;
/* visiblity stream size buffer (fixed size 8 dwords) */
ret = kgsl_snapshot_get_object(device, ptbase, pkt[2], 32,
SNAPSHOT_GPU_OBJECT_GENERIC);
- snapshot_frozen_objsize += ret;
+
+ if (ret >= 0)
+ snapshot_frozen_objsize += ret;
+
+ return ret;
}
/*
@@ -254,13 +269,13 @@
* buffers that are written to as frozen
*/
-static void ib_parse_mem_write(struct kgsl_device *device, unsigned int *pkt,
+static int ib_parse_mem_write(struct kgsl_device *device, unsigned int *pkt,
unsigned int ptbase)
{
int ret;
if (type3_pkt_size(pkt[0]) < 1)
- return;
+ return 0;
/*
* The address is where the data in the rest of this packet is written
@@ -272,7 +287,10 @@
ret = kgsl_snapshot_get_object(device, ptbase, pkt[1] & 0xFFFFFFFC, 0,
SNAPSHOT_GPU_OBJECT_GENERIC);
- snapshot_frozen_objsize += ret;
+ if (ret >= 0)
+ snapshot_frozen_objsize += ret;
+
+ return ret;
}
/*
@@ -282,19 +300,22 @@
* frozen with the others
*/
-static void ib_parse_draw_indx(struct kgsl_device *device, unsigned int *pkt,
+static int ib_parse_draw_indx(struct kgsl_device *device, unsigned int *pkt,
unsigned int ptbase)
{
- int ret, i;
+ int ret = 0, i;
if (type3_pkt_size(pkt[0]) < 3)
- return;
+ return 0;
/* DRAW_IDX may have a index buffer pointer */
if (type3_pkt_size(pkt[0]) > 3) {
ret = kgsl_snapshot_get_object(device, ptbase, pkt[4], pkt[5],
SNAPSHOT_GPU_OBJECT_GENERIC);
+ if (ret < 0)
+ return -EINVAL;
+
snapshot_frozen_objsize += ret;
}
@@ -310,6 +331,9 @@
ret = kgsl_snapshot_get_object(device, ptbase,
vsc_pipe[i].base, vsc_pipe[i].size,
SNAPSHOT_GPU_OBJECT_GENERIC);
+ if (ret < 0)
+ return -EINVAL;
+
snapshot_frozen_objsize += ret;
}
}
@@ -320,6 +344,9 @@
ret = kgsl_snapshot_get_object(device, ptbase,
vsc_size_address, 32,
SNAPSHOT_GPU_OBJECT_GENERIC);
+ if (ret < 0)
+ return -EINVAL;
+
snapshot_frozen_objsize += ret;
}
@@ -328,6 +355,9 @@
ret = kgsl_snapshot_get_object(device, ptbase,
sp_vs_pvt_mem_addr, 8192,
SNAPSHOT_GPU_OBJECT_GENERIC);
+ if (ret < 0)
+ return -EINVAL;
+
snapshot_frozen_objsize += ret;
sp_vs_pvt_mem_addr = 0;
}
@@ -336,6 +366,9 @@
ret = kgsl_snapshot_get_object(device, ptbase,
sp_fs_pvt_mem_addr, 8192,
SNAPSHOT_GPU_OBJECT_GENERIC);
+ if (ret < 0)
+ return -EINVAL;
+
snapshot_frozen_objsize += ret;
sp_fs_pvt_mem_addr = 0;
}
@@ -358,6 +391,9 @@
ret = kgsl_snapshot_get_object(device, ptbase,
vbo[i].base,
0, SNAPSHOT_GPU_OBJECT_GENERIC);
+ if (ret < 0)
+ return -EINVAL;
+
snapshot_frozen_objsize += ret;
}
@@ -367,6 +403,8 @@
vfd_control_0 = 0;
vfd_index_max = 0;
+
+ return ret;
}
/*
@@ -374,23 +412,21 @@
* such as additional GPU buffers to grab or a draw initator
*/
-static void ib_parse_type3(struct kgsl_device *device, unsigned int *ptr,
+static int ib_parse_type3(struct kgsl_device *device, unsigned int *ptr,
unsigned int ptbase)
{
- switch (cp_type3_opcode(*ptr)) {
- case CP_LOAD_STATE:
- ib_parse_load_state(device, ptr, ptbase);
- break;
- case CP_SET_BIN_DATA:
- ib_parse_set_bin_data(device, ptr, ptbase);
- break;
- case CP_MEM_WRITE:
- ib_parse_mem_write(device, ptr, ptbase);
- break;
- case CP_DRAW_INDX:
- ib_parse_draw_indx(device, ptr, ptbase);
- break;
- }
+ int opcode = cp_type3_opcode(*ptr);
+
+ if (opcode == CP_LOAD_STATE)
+ return ib_parse_load_state(device, ptr, ptbase);
+ else if (opcode == CP_SET_BIN_DATA)
+ return ib_parse_set_bin_data(device, ptr, ptbase);
+ else if (opcode == CP_MEM_WRITE)
+ return ib_parse_mem_write(device, ptr, ptbase);
+ else if (opcode == CP_DRAW_INDX)
+ return ib_parse_draw_indx(device, ptr, ptbase);
+
+ return 0;
}
/*
@@ -474,9 +510,12 @@
}
}
+static inline int parse_ib(struct kgsl_device *device, unsigned int ptbase,
+ unsigned int gpuaddr, unsigned int dwords);
+
/* Add an IB as a GPU object, but first, parse it to find more goodies within */
-static void ib_add_gpu_object(struct kgsl_device *device, unsigned int ptbase,
+static int ib_add_gpu_object(struct kgsl_device *device, unsigned int ptbase,
unsigned int gpuaddr, unsigned int dwords)
{
int i, ret, rem = dwords;
@@ -487,13 +526,13 @@
*/
if (kgsl_snapshot_have_object(device, ptbase, gpuaddr, dwords << 2))
- return;
+ return 0;
src = (unsigned int *) adreno_convertaddr(device, ptbase, gpuaddr,
dwords << 2);
if (src == NULL)
- return;
+ return -EINVAL;
for (i = 0; rem > 0; rem--, i++) {
int pktsize;
@@ -513,26 +552,23 @@
if (adreno_cmd_is_ib(src[i])) {
unsigned int gpuaddr = src[i + 1];
unsigned int size = src[i + 2];
- unsigned int ibbase;
- /* Address of the last processed IB2 */
- kgsl_regread(device, REG_CP_IB2_BASE, &ibbase);
+ ret = parse_ib(device, ptbase, gpuaddr, size);
+ /* If adding the IB failed then stop parsing */
+ if (ret < 0)
+ goto done;
+ } else {
+ ret = ib_parse_type3(device, &src[i], ptbase);
/*
- * If this is the last IB2 that was executed,
- * then push it to make sure it goes into the
- * static space
+ * If the parse function failed (probably
+ * because of a bad decode) then bail out and
+ * just capture the binary IB data
*/
- if (ibbase == gpuaddr)
- push_object(device,
- SNAPSHOT_OBJ_TYPE_IB, ptbase,
- gpuaddr, size);
- else
- ib_add_gpu_object(device, ptbase,
- gpuaddr, size);
- } else
- ib_parse_type3(device, &src[i], ptbase);
+ if (ret < 0)
+ goto done;
+ }
} else if (pkt_is_type0(src[i])) {
ib_parse_type0(device, &src[i], ptbase);
}
@@ -541,10 +577,44 @@
rem -= pktsize;
}
+done:
ret = kgsl_snapshot_get_object(device, ptbase, gpuaddr, dwords << 2,
SNAPSHOT_GPU_OBJECT_IB);
- snapshot_frozen_objsize += ret;
+ if (ret >= 0)
+ snapshot_frozen_objsize += ret;
+
+ return ret;
+}
+
+/*
+ * We want to store the last executed IB1 and IB2 in the static region to ensure
+ * that we get at least some information out of the snapshot even if we can't
+ * access the dynamic data from the sysfs file. Push all other IBs on the
+ * dynamic list
+ */
+static inline int parse_ib(struct kgsl_device *device, unsigned int ptbase,
+ unsigned int gpuaddr, unsigned int dwords)
+{
+ unsigned int ib1base, ib2base;
+ int ret = 0;
+
+ /*
+ * Check the IB address - if it is either the last executed IB1 or the
+ * last executed IB2 then push it into the static blob otherwise put
+ * it in the dynamic list
+ */
+
+ kgsl_regread(device, REG_CP_IB1_BASE, &ib1base);
+ kgsl_regread(device, REG_CP_IB2_BASE, &ib2base);
+
+ if (gpuaddr == ib1base || gpuaddr == ib2base)
+ push_object(device, SNAPSHOT_OBJ_TYPE_IB, ptbase,
+ gpuaddr, dwords);
+ else
+ ret = ib_add_gpu_object(device, ptbase, gpuaddr, dwords);
+
+ return ret;
}
/* Snapshot the ringbuffer memory */
@@ -697,12 +767,11 @@
* others get marked at GPU objects
*/
- if (ibaddr == ibbase || memdesc != NULL)
+ if (memdesc != NULL)
push_object(device, SNAPSHOT_OBJ_TYPE_IB,
ptbase, ibaddr, ibsize);
else
- ib_add_gpu_object(device, ptbase, ibaddr,
- ibsize);
+ parse_ib(device, ptbase, ibaddr, ibsize);
}
index = index + 1;
@@ -725,7 +794,7 @@
struct kgsl_snapshot_obj *obj = priv;
unsigned int *src = obj->ptr;
unsigned int *dst = snapshot + sizeof(*header);
- int i;
+ int i, ret;
if (remain < (obj->dwords << 2) + sizeof(*header)) {
KGSL_DRV_ERR(device,
@@ -747,10 +816,14 @@
continue;
if (adreno_cmd_is_ib(*src))
- push_object(device, SNAPSHOT_OBJ_TYPE_IB,
- obj->ptbase, src[1], src[2]);
+ ret = parse_ib(device, obj->ptbase, src[1],
+ src[2]);
else
- ib_parse_type3(device, src, obj->ptbase);
+ ret = ib_parse_type3(device, src, obj->ptbase);
+
+ /* Stop parsing if the type3 decode fails */
+ if (ret < 0)
+ break;
}
}
diff --git a/drivers/gpu/msm/kgsl_debugfs.c b/drivers/gpu/msm/kgsl_debugfs.c
index f967cd2..76998db 100644
--- a/drivers/gpu/msm/kgsl_debugfs.c
+++ b/drivers/gpu/msm/kgsl_debugfs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2008-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2008-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -247,8 +247,8 @@
kgsl_get_memory_usage(usage, sizeof(usage), m->flags);
- seq_printf(s, "%08x %8d %5d %5s %10s %16s %5d\n",
- m->gpuaddr, m->size, entry->id, flags,
+ seq_printf(s, "%08x %08lx %8d %5d %5s %10s %16s %5d\n",
+ m->gpuaddr, m->useraddr, m->size, entry->id, flags,
memtype_str(entry->memtype), usage, m->sglen);
}
@@ -259,8 +259,9 @@
struct kgsl_process_private *private = s->private;
int next = 0;
- seq_printf(s, "%8s %8s %5s %5s %10s %16s %5s\n",
- "gpuaddr", "size", "id", "flags", "type", "usage", "sglen");
+ seq_printf(s, "%8s %8s %8s %5s %5s %10s %16s %5s\n",
+ "gpuaddr", "useraddr", "size", "id", "flags", "type",
+ "usage", "sglen");
/* print all entries with a GPU address */
spin_lock(&private->mem_lock);
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 18aed14..f71cf8c 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -68,8 +68,10 @@
device = kgsl_driver.devp[KGSL_DEVICE_3D0];
if (device->mmu.mmu_ops->mmu_setup_pt != NULL) {
status = device->mmu.mmu_ops->mmu_setup_pt(&device->mmu, pt);
- if (status)
+ if (status) {
+ i = KGSL_DEVICE_MAX - 1;
goto error_pt;
+ }
}
return status;
error_pt:
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index e9bbac8..0935f64 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -339,14 +339,14 @@
if (entry == NULL) {
KGSL_DRV_ERR(device, "Unable to find GPU buffer %8.8X\n",
gpuaddr);
- return 0;
+ return -EINVAL;
}
/* We can't freeze external memory, because we don't own it */
if (entry->memtype != KGSL_MEM_ENTRY_KERNEL) {
KGSL_DRV_ERR(device,
"Only internal GPU buffers can be frozen\n");
- return 0;
+ return -EINVAL;
}
/*
@@ -369,7 +369,7 @@
if (size + offset > entry->memdesc.size) {
KGSL_DRV_ERR(device, "Invalid size for GPU buffer %8.8X\n",
gpuaddr);
- return 0;
+ return -EINVAL;
}
/* If the buffer is already on the list, skip it */
@@ -386,14 +386,14 @@
if (kgsl_memdesc_map(&entry->memdesc) == NULL) {
KGSL_DRV_ERR(device, "Unable to map GPU buffer %X\n",
gpuaddr);
- return 0;
+ return -EINVAL;
}
obj = kzalloc(sizeof(*obj), GFP_KERNEL);
if (obj == NULL) {
KGSL_DRV_ERR(device, "Unable to allocate memory\n");
- return 0;
+ return -EINVAL;
}
/* Ref count the mem entry */
@@ -518,6 +518,7 @@
struct kgsl_snapshot_header *header = device->snapshot;
int remain = device->snapshot_maxsize - sizeof(*header);
void *snapshot;
+ struct timespec boot;
/*
* The first hang is always the one we are interested in. To
@@ -559,7 +560,13 @@
snapshot = device->ftbl->snapshot(device, snapshot, &remain,
hang);
- device->snapshot_timestamp = get_seconds();
+ /*
+ * The timestamp is the seconds since boot so it is easier to match to
+ * the kernel log
+ */
+
+ getboottime(&boot);
+ device->snapshot_timestamp = get_seconds() - boot.tv_sec;
device->snapshot_size = (int) (snapshot - device->snapshot);
/* Freeze the snapshot on a hang until it gets read */
@@ -655,7 +662,7 @@
/* Show the timestamp of the last collected snapshot */
static ssize_t timestamp_show(struct kgsl_device *device, char *buf)
{
- return snprintf(buf, PAGE_SIZE, "%x\n", device->snapshot_timestamp);
+ return snprintf(buf, PAGE_SIZE, "%d\n", device->snapshot_timestamp);
}
/* manually trigger a new snapshot to be collected */
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index bbc18a4..1f3dc2f 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -3749,6 +3749,31 @@
return retval;
}
+static int iris_fops_release(struct file *file)
+{
+ struct iris_device *radio = video_get_drvdata(video_devdata(file));
+ int retval = 0;
+
+ FMDBG("Enter %s ", __func__);
+ if (radio == NULL)
+ return -EINVAL;
+
+ if (radio->mode == FM_OFF)
+ return 0;
+
+ if (radio->mode == FM_RECV)
+ retval = hci_cmd(HCI_FM_DISABLE_RECV_CMD,
+ radio->fm_hdev);
+ else if (radio->mode == FM_TRANS)
+ retval = hci_cmd(HCI_FM_DISABLE_TRANS_CMD,
+ radio->fm_hdev);
+ if (retval < 0)
+ FMDERR("Err on disable FM %d\n", retval);
+
+ radio->mode = FM_OFF;
+ return retval;
+}
+
static int iris_vidioc_dqbuf(struct file *file, void *priv,
struct v4l2_buffer *buffer)
{
@@ -3843,6 +3868,7 @@
static const struct v4l2_file_operations iris_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = video_ioctl2,
+ .release = iris_fops_release,
};
static struct video_device iris_viddev_template = {
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index f0706e83..27e6c79 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -33,6 +33,7 @@
#include <linux/slab.h>
#include <linux/mmc/mmc.h>
#include <mach/gpio.h>
+#include <mach/msm_bus.h>
#include "sdhci-pltfm.h"
@@ -76,6 +77,10 @@
#define CORE_CLK_PWRSAVE (1 << 1)
#define CORE_IO_PAD_PWR_SWITCH (1 << 16)
+/* 8KB descriptors */
+#define SDHCI_MSM_MAX_SEGMENTS (1 << 13)
+#define SDHCI_MSM_MMC_CLK_GATE_DELAY 200 /* msecs */
+
static const u32 tuning_block_64[] = {
0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
@@ -176,6 +181,12 @@
struct sdhci_msm_pad_data *pad_data;
};
+struct sdhci_msm_bus_voting_data {
+ struct msm_bus_scale_pdata *bus_pdata;
+ unsigned int *bw_vecs;
+ unsigned int bw_vecs_size;
+};
+
struct sdhci_msm_pltfm_data {
/* Supported UHS-I Modes */
u32 caps;
@@ -188,17 +199,32 @@
struct sdhci_msm_slot_reg_data *vreg_data;
bool nonremovable;
struct sdhci_msm_pin_data *pin_data;
+ u32 cpu_dma_latency_us;
+ struct sdhci_msm_bus_voting_data *voting_data;
+};
+
+struct sdhci_msm_bus_vote {
+ uint32_t client_handle;
+ uint32_t curr_vote;
+ int min_bw_vote;
+ int max_bw_vote;
+ bool is_max_bw_needed;
+ struct delayed_work vote_work;
+ struct device_attribute max_bus_bw;
};
struct sdhci_msm_host {
+ struct platform_device *pdev;
void __iomem *core_mem; /* MSM SDCC mapped address */
struct clk *clk; /* main SD/MMC bus clock */
struct clk *pclk; /* SDHC peripheral bus clock */
struct clk *bus_clk; /* SDHC bus voter clock */
+ atomic_t clks_on; /* Set if clocks are enabled */
struct sdhci_msm_pltfm_data *pdata;
struct mmc_host *mmc;
struct sdhci_pltfm_data sdhci_msm_pdata;
wait_queue_head_t pwr_irq_wait;
+ struct sdhci_msm_bus_vote msm_bus_vote;
};
enum vdd_io_level {
@@ -1040,6 +1066,7 @@
struct sdhci_msm_pltfm_data *pdata = NULL;
struct device_node *np = dev->of_node;
u32 bus_width = 0;
+ u32 cpu_dma_latency;
int len, i;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
@@ -1058,6 +1085,10 @@
pdata->mmc_bus_width = 0;
}
+ if (!of_property_read_u32(np, "qcom,cpu-dma-latency-us",
+ &cpu_dma_latency))
+ pdata->cpu_dma_latency_us = cpu_dma_latency;
+
pdata->vreg_data = devm_kzalloc(dev, sizeof(struct
sdhci_msm_slot_reg_data),
GFP_KERNEL);
@@ -1115,6 +1146,218 @@
return NULL;
}
+/* Returns required bandwidth in Bytes per Sec */
+static unsigned int sdhci_get_bw_required(struct sdhci_host *host,
+ struct mmc_ios *ios)
+{
+ unsigned int bw;
+
+ bw = host->clock;
+ /*
+ * For DDR mode, SDCC controller clock will be at
+ * the double rate than the actual clock that goes to card.
+ */
+ if (ios->bus_width == MMC_BUS_WIDTH_4)
+ bw /= 2;
+ else if (ios->bus_width == MMC_BUS_WIDTH_1)
+ bw /= 8;
+
+ return bw;
+}
+
+static int sdhci_msm_bus_get_vote_for_bw(struct sdhci_msm_host *host,
+ unsigned int bw)
+{
+ unsigned int *table = host->pdata->voting_data->bw_vecs;
+ unsigned int size = host->pdata->voting_data->bw_vecs_size;
+ int i;
+
+ if (host->msm_bus_vote.is_max_bw_needed && bw)
+ return host->msm_bus_vote.max_bw_vote;
+
+ for (i = 0; i < size; i++) {
+ if (bw <= table[i])
+ break;
+ }
+
+ if (i && (i == size))
+ i--;
+
+ return i;
+}
+
+/*
+ * This function must be called with host lock acquired.
+ * Caller of this function should also ensure that msm bus client
+ * handle is not null.
+ */
+static inline int sdhci_msm_bus_set_vote(struct sdhci_msm_host *msm_host,
+ int vote,
+ unsigned long flags)
+{
+ struct sdhci_host *host = platform_get_drvdata(msm_host->pdev);
+ int rc = 0;
+
+ if (vote != msm_host->msm_bus_vote.curr_vote) {
+ spin_unlock_irqrestore(&host->lock, flags);
+ rc = msm_bus_scale_client_update_request(
+ msm_host->msm_bus_vote.client_handle, vote);
+ spin_lock_irqsave(&host->lock, flags);
+ if (rc) {
+ pr_err("%s: msm_bus_scale_client_update_request() failed: bus_client_handle=0x%x, vote=%d, err=%d\n",
+ mmc_hostname(host->mmc),
+ msm_host->msm_bus_vote.client_handle, vote, rc);
+ goto out;
+ }
+ msm_host->msm_bus_vote.curr_vote = vote;
+ }
+out:
+ return rc;
+}
+
+/*
+ * Internal work. Work to set 0 bandwidth for msm bus.
+ */
+static void sdhci_msm_bus_work(struct work_struct *work)
+{
+ struct sdhci_msm_host *msm_host;
+ struct sdhci_host *host;
+ unsigned long flags;
+
+ msm_host = container_of(work, struct sdhci_msm_host,
+ msm_bus_vote.vote_work.work);
+ host = platform_get_drvdata(msm_host->pdev);
+
+ if (!msm_host->msm_bus_vote.client_handle)
+ return;
+
+ spin_lock_irqsave(&host->lock, flags);
+ /* don't vote for 0 bandwidth if any request is in progress */
+ if (!host->mrq) {
+ sdhci_msm_bus_set_vote(msm_host,
+ msm_host->msm_bus_vote.min_bw_vote, flags);
+ } else
+ pr_warning("%s: %s: Transfer in progress. skipping bus voting to 0 bandwidth\n",
+ mmc_hostname(host->mmc), __func__);
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
+/*
+ * This function cancels any scheduled delayed work and sets the bus
+ * vote based on bw (bandwidth) argument.
+ */
+static void sdhci_msm_bus_cancel_work_and_set_vote(struct sdhci_host *host,
+ unsigned int bw)
+{
+ int vote;
+ unsigned long flags;
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+
+ cancel_delayed_work_sync(&msm_host->msm_bus_vote.vote_work);
+ spin_lock_irqsave(&host->lock, flags);
+ vote = sdhci_msm_bus_get_vote_for_bw(msm_host, bw);
+ sdhci_msm_bus_set_vote(msm_host, vote, flags);
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
+#define MSM_MMC_BUS_VOTING_DELAY 200 /* msecs */
+
+/* This function queues a work which will set the bandwidth requiement to 0 */
+static void sdhci_msm_bus_queue_work(struct sdhci_host *host)
+{
+ unsigned long flags;
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+
+ spin_lock_irqsave(&host->lock, flags);
+ if (msm_host->msm_bus_vote.min_bw_vote !=
+ msm_host->msm_bus_vote.curr_vote)
+ queue_delayed_work(system_nrt_wq,
+ &msm_host->msm_bus_vote.vote_work,
+ msecs_to_jiffies(MSM_MMC_BUS_VOTING_DELAY));
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static int sdhci_msm_bus_register(struct sdhci_msm_host *host,
+ struct platform_device *pdev)
+{
+ int rc = 0;
+ struct msm_bus_scale_pdata *bus_pdata;
+
+ struct sdhci_msm_bus_voting_data *data;
+ struct device *dev = &pdev->dev;
+
+ data = devm_kzalloc(dev,
+ sizeof(struct sdhci_msm_bus_voting_data), GFP_KERNEL);
+ if (!data) {
+ dev_err(&pdev->dev,
+ "%s: failed to allocate memory\n", __func__);
+ rc = -ENOMEM;
+ goto out;
+ }
+ data->bus_pdata = msm_bus_cl_get_pdata(pdev);
+ if (data->bus_pdata) {
+ rc = sdhci_msm_dt_get_array(dev, "qcom,bus-bw-vectors-bps",
+ &data->bw_vecs, &data->bw_vecs_size, 0);
+ if (rc) {
+ dev_err(&pdev->dev,
+ "%s: Failed to get bus-bw-vectors-bps\n",
+ __func__);
+ goto out;
+ }
+ host->pdata->voting_data = data;
+ }
+ if (host->pdata->voting_data &&
+ host->pdata->voting_data->bus_pdata &&
+ host->pdata->voting_data->bw_vecs &&
+ host->pdata->voting_data->bw_vecs_size) {
+
+ bus_pdata = host->pdata->voting_data->bus_pdata;
+ host->msm_bus_vote.client_handle =
+ msm_bus_scale_register_client(bus_pdata);
+ if (!host->msm_bus_vote.client_handle) {
+ dev_err(&pdev->dev, "msm_bus_scale_register_client()\n");
+ rc = -EFAULT;
+ goto out;
+ }
+ /* cache the vote index for minimum and maximum bandwidth */
+ host->msm_bus_vote.min_bw_vote =
+ sdhci_msm_bus_get_vote_for_bw(host, 0);
+ host->msm_bus_vote.max_bw_vote =
+ sdhci_msm_bus_get_vote_for_bw(host, UINT_MAX);
+ } else {
+ devm_kfree(dev, data);
+ }
+
+out:
+ return rc;
+}
+
+static void sdhci_msm_bus_unregister(struct sdhci_msm_host *host)
+{
+ if (host->msm_bus_vote.client_handle)
+ msm_bus_scale_unregister_client(
+ host->msm_bus_vote.client_handle);
+}
+
+static void sdhci_msm_bus_voting(struct sdhci_host *host, u32 enable)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ struct mmc_ios *ios = &host->mmc->ios;
+ unsigned int bw;
+
+ if (!msm_host->msm_bus_vote.client_handle)
+ return;
+
+ bw = sdhci_get_bw_required(host, ios);
+ if (enable)
+ sdhci_msm_bus_cancel_work_and_set_vote(host, bw);
+ else
+ sdhci_msm_bus_queue_work(host);
+}
+
/* Regulator utility functions */
static int sdhci_msm_vreg_init_reg(struct device *dev,
struct sdhci_msm_reg_data *vreg)
@@ -1477,6 +1720,35 @@
else
return 0;
}
+static ssize_t
+show_sdhci_max_bus_bw(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sdhci_host *host = dev_get_drvdata(dev);
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ msm_host->msm_bus_vote.is_max_bw_needed);
+}
+
+static ssize_t
+store_sdhci_max_bus_bw(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sdhci_host *host = dev_get_drvdata(dev);
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ uint32_t value;
+ unsigned long flags;
+
+ if (!kstrtou32(buf, 0, &value)) {
+ spin_lock_irqsave(&host->lock, flags);
+ msm_host->msm_bus_vote.is_max_bw_needed = !!value;
+ spin_unlock_irqrestore(&host->lock, flags);
+ }
+ return count;
+}
static void sdhci_msm_check_power_status(struct sdhci_host *host)
{
@@ -1511,10 +1783,79 @@
host->ioaddr + CORE_DLL_CONFIG);
}
+static unsigned int sdhci_msm_max_segs(void)
+{
+ return SDHCI_MSM_MAX_SEGMENTS;
+}
+
+void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+ int rc;
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ unsigned long flags;
+
+ if (clock && !atomic_read(&msm_host->clks_on)) {
+ pr_debug("%s: request to enable clock at rate %u\n",
+ mmc_hostname(host->mmc), clock);
+ if (!IS_ERR_OR_NULL(msm_host->bus_clk)) {
+ rc = clk_prepare_enable(msm_host->bus_clk);
+ if (rc) {
+ pr_err("%s: %s: failed to enable the bus-clock with error %d\n",
+ mmc_hostname(host->mmc), __func__, rc);
+ goto out;
+ }
+ }
+ if (!IS_ERR(msm_host->pclk)) {
+ rc = clk_prepare_enable(msm_host->pclk);
+ if (rc) {
+ pr_err("%s: %s: failed to enable the pclk with error %d\n",
+ mmc_hostname(host->mmc), __func__, rc);
+ goto disable_bus_clk;
+ }
+ }
+ rc = clk_prepare_enable(msm_host->clk);
+ if (rc) {
+ pr_err("%s: %s: failed to enable the host-clk with error %d\n",
+ mmc_hostname(host->mmc), __func__, rc);
+ goto disable_pclk;
+ }
+ mb();
+ atomic_set(&msm_host->clks_on, 1);
+
+ } else if (!clock && atomic_read(&msm_host->clks_on)) {
+ pr_debug("%s: request to disable clocks\n",
+ mmc_hostname(host->mmc));
+ sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
+ mb();
+ clk_disable_unprepare(msm_host->clk);
+ if (!IS_ERR(msm_host->pclk))
+ clk_disable_unprepare(msm_host->pclk);
+ if (!IS_ERR_OR_NULL(msm_host->bus_clk))
+ clk_disable_unprepare(msm_host->bus_clk);
+ atomic_set(&msm_host->clks_on, 0);
+ }
+ spin_lock_irqsave(&host->lock, flags);
+ host->clock = clock;
+ spin_unlock_irqrestore(&host->lock, flags);
+ goto out;
+disable_pclk:
+ if (!IS_ERR_OR_NULL(msm_host->pclk))
+ clk_disable_unprepare(msm_host->pclk);
+disable_bus_clk:
+ if (!IS_ERR_OR_NULL(msm_host->bus_clk))
+ clk_disable_unprepare(msm_host->bus_clk);
+out:
+ return;
+}
+
static struct sdhci_ops sdhci_msm_ops = {
.check_power_status = sdhci_msm_check_power_status,
.execute_tuning = sdhci_msm_execute_tuning,
.toggle_cdr = sdhci_msm_toggle_cdr,
+ .get_max_segments = sdhci_msm_max_segs,
+ .set_clock = sdhci_msm_set_clock,
+ .platform_bus_voting = sdhci_msm_bus_voting,
};
static int __devinit sdhci_msm_probe(struct platform_device *pdev)
@@ -1546,6 +1887,7 @@
pltfm_host = sdhci_priv(host);
pltfm_host->priv = msm_host;
msm_host->mmc = host->mmc;
+ msm_host->pdev = pdev;
/* Extract platform data */
if (pdev->dev.of_node) {
@@ -1592,6 +1934,7 @@
if (ret)
goto pclk_disable;
+ atomic_set(&msm_host->clks_on, 1);
/* Setup regulators */
ret = sdhci_msm_vreg_init(&pdev->dev, msm_host->pdata, true);
if (ret) {
@@ -1662,6 +2005,9 @@
/* Enable pwr irq interrupts */
writel_relaxed(INT_MASK, (msm_host->core_mem + CORE_PWRCTL_MASK));
+ /* Set clock gating delay to be used when CONFIG_MMC_CLKGATE is set */
+ msm_host->mmc->clkgate_delay = SDHCI_MSM_MMC_CLK_GATE_DELAY;
+
/* Set host capabilities */
msm_host->mmc->caps |= msm_host->pdata->mmc_bus_width;
msm_host->mmc->caps |= msm_host->pdata->caps;
@@ -1695,10 +2041,20 @@
if (msm_host->pdata->nonremovable)
msm_host->mmc->caps |= MMC_CAP_NONREMOVABLE;
+ host->cpu_dma_latency_us = msm_host->pdata->cpu_dma_latency_us;
+
+ ret = sdhci_msm_bus_register(msm_host, pdev);
+ if (ret)
+ goto vreg_deinit;
+
+ if (msm_host->msm_bus_vote.client_handle)
+ INIT_DELAYED_WORK(&msm_host->msm_bus_vote.vote_work,
+ sdhci_msm_bus_work);
+
ret = sdhci_add_host(host);
if (ret) {
dev_err(&pdev->dev, "Add host failed (%d)\n", ret);
- goto vreg_deinit;
+ goto bus_unregister;
}
/* Set core clk rate, optionally override from dts */
@@ -1710,12 +2066,24 @@
goto remove_host;
}
+ msm_host->msm_bus_vote.max_bus_bw.show = show_sdhci_max_bus_bw;
+ msm_host->msm_bus_vote.max_bus_bw.store = store_sdhci_max_bus_bw;
+ sysfs_attr_init(&msm_host->msm_bus_vote.max_bus_bw.attr);
+ msm_host->msm_bus_vote.max_bus_bw.attr.name = "max_bus_bw";
+ msm_host->msm_bus_vote.max_bus_bw.attr.mode = S_IRUGO | S_IWUSR;
+ ret = device_create_file(&pdev->dev,
+ &msm_host->msm_bus_vote.max_bus_bw);
+ if (ret)
+ goto remove_host;
+
/* Successful initialization */
goto out;
remove_host:
dead = (readl_relaxed(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
sdhci_remove_host(host, dead);
+bus_unregister:
+ sdhci_msm_bus_unregister(msm_host);
vreg_deinit:
sdhci_msm_vreg_init(&pdev->dev, msm_host->pdata, false);
clk_disable:
@@ -1744,17 +2112,18 @@
0xffffffff);
pr_debug("%s: %s\n", dev_name(&pdev->dev), __func__);
+ device_remove_file(&pdev->dev, &msm_host->msm_bus_vote.max_bus_bw);
sdhci_remove_host(host, dead);
sdhci_pltfm_free(pdev);
sdhci_msm_vreg_init(&pdev->dev, msm_host->pdata, false);
- if (!IS_ERR(msm_host->clk))
- clk_disable_unprepare(msm_host->clk);
- if (!IS_ERR(msm_host->pclk))
- clk_disable_unprepare(msm_host->pclk);
- if (!IS_ERR_OR_NULL(msm_host->bus_clk))
- clk_disable_unprepare(msm_host->bus_clk);
+
if (pdata->pin_data)
sdhci_msm_setup_pins(pdata, false);
+
+ if (msm_host->msm_bus_vote.client_handle) {
+ sdhci_msm_bus_cancel_work_and_set_vote(host, 0);
+ sdhci_msm_bus_unregister(msm_host);
+ }
return 0;
}
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index b9bd3a1..97c1013 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -483,9 +483,10 @@
* The ADMA descriptor table is mapped further down as we
* need to fill it with data first.
*/
-
host->align_addr = dma_map_single(mmc_dev(host->mmc),
- host->align_buffer, 128 * 4, direction);
+ host->align_buffer,
+ host->align_buf_sz,
+ direction);
if (dma_mapping_error(mmc_dev(host->mmc), host->align_addr))
goto fail;
BUG_ON(host->align_addr & 0x3);
@@ -544,7 +545,8 @@
* If this triggers then we have a calculation bug
* somewhere. :/
*/
- WARN_ON((desc - host->adma_desc) > (128 * 2 + 1) * 4);
+ WARN_ON((desc - host->adma_desc) > host->adma_desc_sz);
+
}
if (host->quirks & SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC) {
@@ -569,11 +571,15 @@
*/
if (data->flags & MMC_DATA_WRITE) {
dma_sync_single_for_device(mmc_dev(host->mmc),
- host->align_addr, 128 * 4, direction);
+ host->align_addr,
+ host->align_buf_sz,
+ direction);
}
host->adma_addr = dma_map_single(mmc_dev(host->mmc),
- host->adma_desc, (128 * 2 + 1) * 4, DMA_TO_DEVICE);
+ host->adma_desc,
+ host->adma_desc_sz,
+ DMA_TO_DEVICE);
if (dma_mapping_error(mmc_dev(host->mmc), host->adma_addr))
goto unmap_entries;
BUG_ON(host->adma_addr & 0x3);
@@ -585,7 +591,7 @@
data->sg_len, direction);
unmap_align:
dma_unmap_single(mmc_dev(host->mmc), host->align_addr,
- 128 * 4, direction);
+ host->align_buf_sz, direction);
fail:
return -EINVAL;
}
@@ -607,10 +613,10 @@
direction = DMA_TO_DEVICE;
dma_unmap_single(mmc_dev(host->mmc), host->adma_addr,
- (128 * 2 + 1) * 4, DMA_TO_DEVICE);
+ host->adma_desc_sz, DMA_TO_DEVICE);
dma_unmap_single(mmc_dev(host->mmc), host->align_addr,
- 128 * 4, direction);
+ host->align_buf_sz, direction);
if (data->flags & MMC_DATA_READ) {
dma_sync_sg_for_cpu(mmc_dev(host->mmc), data->sg,
@@ -721,7 +727,7 @@
return;
/* Sanity checks */
- BUG_ON(data->blksz * data->blocks > 524288);
+ BUG_ON(data->blksz * data->blocks > host->mmc->max_req_size);
BUG_ON(data->blksz > host->mmc->max_blk_size);
BUG_ON(data->blocks > 65535);
@@ -962,6 +968,8 @@
tasklet_schedule(&host->finish_tasklet);
}
+#define SDHCI_REQUEST_TIMEOUT 10 /* Default request timeout in seconds */
+
static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
{
int flags;
@@ -995,7 +1003,11 @@
mdelay(1);
}
- mod_timer(&host->timer, jiffies + 10 * HZ);
+ mod_timer(&host->timer, jiffies + SDHCI_REQUEST_TIMEOUT * HZ);
+
+ if (cmd->cmd_timeout_ms > SDHCI_REQUEST_TIMEOUT * MSEC_PER_SEC)
+ mod_timer(&host->timer, jiffies +
+ (msecs_to_jiffies(cmd->cmd_timeout_ms * 2)));
host->cmd = cmd;
@@ -1082,19 +1094,24 @@
int real_div = div, clk_mul = 1;
u16 clk = 0;
unsigned long timeout;
+ unsigned long flags;
+ spin_lock_irqsave(&host->lock, flags);
if (clock && clock == host->clock)
- return;
+ goto ret;
host->mmc->actual_clock = 0;
if (host->ops->set_clock) {
+ spin_unlock_irqrestore(&host->lock, flags);
host->ops->set_clock(host, clock);
+ spin_lock_irqsave(&host->lock, flags);
if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK)
- return;
+ goto ret;
}
- sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
+ if (host->clock)
+ sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
if (clock == 0)
goto out;
@@ -1170,7 +1187,7 @@
pr_err("%s: Internal clock never "
"stabilised.\n", mmc_hostname(host->mmc));
sdhci_dumpregs(host);
- return;
+ goto ret;
}
timeout--;
mdelay(1);
@@ -1181,6 +1198,8 @@
out:
host->clock = clock;
+ret:
+ spin_unlock_irqrestore(&host->lock, flags);
}
static int sdhci_set_power(struct sdhci_host *host, unsigned short power)
@@ -1259,6 +1278,32 @@
* *
\*****************************************************************************/
+static int sdhci_enable(struct mmc_host *mmc)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+
+ if (host->cpu_dma_latency_us)
+ pm_qos_update_request(&host->pm_qos_req_dma,
+ host->cpu_dma_latency_us);
+ if (host->ops->platform_bus_voting)
+ host->ops->platform_bus_voting(host, 1);
+
+ return 0;
+}
+
+static int sdhci_disable(struct mmc_host *mmc)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+
+ if (host->cpu_dma_latency_us)
+ pm_qos_update_request(&host->pm_qos_req_dma,
+ PM_QOS_DEFAULT_VALUE);
+ if (host->ops->platform_bus_voting)
+ host->ops->platform_bus_voting(host, 0);
+
+ return 0;
+}
+
static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct sdhci_host *host;
@@ -1341,20 +1386,17 @@
return;
}
- /*
- * Reset the chip on each power off.
- * Should clear out any weird states.
- */
- if (ios->power_mode == MMC_POWER_OFF) {
- sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
- sdhci_reinit(host);
+ if (ios->clock)
+ sdhci_set_clock(host, ios->clock);
+
+ spin_lock_irqsave(&host->lock, flags);
+ if (!host->clock) {
+ spin_unlock_irqrestore(&host->lock, flags);
+ return;
}
+ spin_unlock_irqrestore(&host->lock, flags);
- sdhci_set_clock(host, ios->clock);
-
- if (ios->power_mode == MMC_POWER_OFF)
- vdd_bit = sdhci_set_power(host, -1);
- else
+ if (ios->power_mode & (MMC_POWER_UP | MMC_POWER_ON))
vdd_bit = sdhci_set_power(host, ios->vdd);
if (host->vmmc && vdd_bit != -1)
@@ -1442,10 +1484,11 @@
/* Re-enable SD Clock */
clock = host->clock;
host->clock = 0;
+ spin_unlock_irqrestore(&host->lock, flags);
sdhci_set_clock(host, clock);
+ spin_lock_irqsave(&host->lock, flags);
}
-
/* Reset SD Clock Enable */
clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
clk &= ~SDHCI_CLOCK_CARD_EN;
@@ -1475,10 +1518,13 @@
/* Re-enable SD Clock */
clock = host->clock;
host->clock = 0;
+ spin_unlock_irqrestore(&host->lock, flags);
sdhci_set_clock(host, clock);
+ spin_lock_irqsave(&host->lock, flags);
} else
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+ spin_unlock_irqrestore(&host->lock, flags);
/*
* Some (ENE) controllers go apeshit on some ios operation,
* signalling timeout and CRC errors even on CMD0. Resetting
@@ -1487,8 +1533,21 @@
if(host->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS)
sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
+ /*
+ * Reset the chip on each power off.
+ * Should clear out any weird states.
+ */
+ if (ios->power_mode == MMC_POWER_OFF) {
+ sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
+ sdhci_reinit(host);
+ vdd_bit = sdhci_set_power(host, -1);
+ if (host->vmmc && vdd_bit != -1)
+ mmc_regulator_set_ocr(host->mmc, host->vmmc, vdd_bit);
+ }
+ if (!ios->clock)
+ sdhci_set_clock(host, ios->clock);
+
mmiowb();
- spin_unlock_irqrestore(&host->lock, flags);
}
static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
@@ -1965,6 +2024,8 @@
.start_signal_voltage_switch = sdhci_start_signal_voltage_switch,
.execute_tuning = sdhci_execute_tuning,
.enable_preset_value = sdhci_enable_preset_value,
+ .enable = sdhci_enable,
+ .disable = sdhci_disable,
};
/*****************************************************************************\
@@ -2042,7 +2103,9 @@
/* This is to force an update */
clock = host->clock;
host->clock = 0;
+ spin_unlock_irqrestore(&host->lock, flags);
sdhci_set_clock(host, clock);
+ spin_lock_irqsave(&host->lock, flags);
}
/* Spec says we should do both at the same time, but Ricoh
@@ -2715,11 +2778,23 @@
if (host->flags & SDHCI_USE_ADMA) {
/*
* We need to allocate descriptors for all sg entries
- * (128) and potentially one alignment transfer for
+ * (128/max_segments) and potentially one alignment transfer for
* each of those entries.
*/
- host->adma_desc = kmalloc((128 * 2 + 1) * 4, GFP_KERNEL);
- host->align_buffer = kmalloc(128 * 4, GFP_KERNEL);
+ if (host->ops->get_max_segments)
+ host->adma_max_desc = host->ops->get_max_segments();
+ else
+ host->adma_max_desc = 128;
+
+ host->adma_desc_sz = (host->adma_max_desc * 2 + 1) * 4;
+ host->align_buf_sz = host->adma_max_desc * 4;
+
+ pr_debug("%s: %s: dma_desc_size: %d\n",
+ mmc_hostname(host->mmc), __func__, host->adma_desc_sz);
+ host->adma_desc = kmalloc(host->adma_desc_sz,
+ GFP_KERNEL);
+ host->align_buffer = kmalloc(host->align_buf_sz,
+ GFP_KERNEL);
if (!host->adma_desc || !host->align_buffer) {
kfree(host->adma_desc);
kfree(host->align_buffer);
@@ -2973,17 +3048,21 @@
* can do scatter/gather or not.
*/
if (host->flags & SDHCI_USE_ADMA)
- mmc->max_segs = 128;
+ mmc->max_segs = host->adma_max_desc;
else if (host->flags & SDHCI_USE_SDMA)
mmc->max_segs = 1;
- else /* PIO */
- mmc->max_segs = 128;
+ else/* PIO */
+ mmc->max_segs = host->adma_max_desc;
/*
* Maximum number of sectors in one transfer. Limited by DMA boundary
- * size (512KiB).
+ * size (512KiB), unless specified by platform specific driver. Each
+ * descriptor can transfer a maximum of 64KB.
*/
- mmc->max_req_size = 524288;
+ if (host->ops->get_max_segments)
+ mmc->max_req_size = (host->adma_max_desc * 65536);
+ else
+ mmc->max_req_size = 524288;
/*
* Maximum segment size. Could be one segment with the maximum number
@@ -3073,6 +3152,9 @@
mmiowb();
+ if (host->cpu_dma_latency_us)
+ pm_qos_add_request(&host->pm_qos_req_dma,
+ PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
mmc_add_host(mmc);
pr_info("%s: SDHCI controller on %s [%s] using %s\n",
@@ -3120,6 +3202,8 @@
sdhci_disable_card_detection(host);
+ if (host->cpu_dma_latency_us)
+ pm_qos_remove_request(&host->pm_qos_req_dma);
mmc_remove_host(host->mmc);
#ifdef SDHCI_USE_LEDS_CLASS
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 4f8d01d..49d7957 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -280,6 +280,8 @@
void (*check_power_status)(struct sdhci_host *host);
int (*execute_tuning)(struct sdhci_host *host, u32 opcode);
void (*toggle_cdr)(struct sdhci_host *host, bool enable);
+ unsigned int (*get_max_segments)(void);
+ void (*platform_bus_voting)(struct sdhci_host *host, u32 enable);
};
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c
index edf3a60..1142094 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -161,6 +161,7 @@
struct ipa_ioc_nat_alloc_mem nat_mem;
struct ipa_ioc_v4_nat_init nat_init;
struct ipa_ioc_v4_nat_del nat_del;
+ struct ipa_ioc_rm_dependency rm_depend;
size_t sz;
IPADBG("cmd=%x nr=%d\n", cmd, _IOC_NR(cmd));
@@ -593,6 +594,24 @@
break;
}
break;
+ case IPA_IOC_RM_ADD_DEPENDENCY:
+ if (copy_from_user((u8 *)&rm_depend, (u8 *)arg,
+ sizeof(struct ipa_ioc_rm_dependency))) {
+ retval = -EFAULT;
+ break;
+ }
+ retval = ipa_rm_add_dependency(rm_depend.resource_name,
+ rm_depend.depends_on_name);
+ break;
+ case IPA_IOC_RM_DEL_DEPENDENCY:
+ if (copy_from_user((u8 *)&rm_depend, (u8 *)arg,
+ sizeof(struct ipa_ioc_rm_dependency))) {
+ retval = -EFAULT;
+ break;
+ }
+ retval = ipa_rm_delete_dependency(rm_depend.resource_name,
+ rm_depend.depends_on_name);
+ break;
default: /* redundant, as cmd was checked against MAXNR */
return -ENOTTY;
}
diff --git a/drivers/platform/msm/ipa/ipa_rm.c b/drivers/platform/msm/ipa/ipa_rm.c
index 99b19cc..1fdd300 100644
--- a/drivers/platform/msm/ipa/ipa_rm.c
+++ b/drivers/platform/msm/ipa/ipa_rm.c
@@ -48,7 +48,7 @@
if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
create_params->name,
&resource) == 0) {
- result = -EPERM;
+ result = -EEXIST;
goto bail;
}
result = ipa_rm_resource_create(create_params,
diff --git a/drivers/platform/msm/ipa/ipa_rm_resource.c b/drivers/platform/msm/ipa/ipa_rm_resource.c
index 3ba8e84..0a6771c 100644
--- a/drivers/platform/msm/ipa/ipa_rm_resource.c
+++ b/drivers/platform/msm/ipa/ipa_rm_resource.c
@@ -451,7 +451,7 @@
resource->name,
depends_on->peers_list,
depends_on->name))
- return -EINVAL;
+ return -EEXIST;
ipa_rm_peers_list_add_peer(resource->peers_list, depends_on);
ipa_rm_peers_list_add_peer(depends_on->peers_list, resource);
spin_lock_irqsave(&resource->state_lock, flags);
@@ -507,7 +507,7 @@
unsigned long flags;
if (!resource || !depends_on)
return -EINVAL;
- if (ipa_rm_peers_list_check_dependency(resource->peers_list,
+ if (!ipa_rm_peers_list_check_dependency(resource->peers_list,
resource->name,
depends_on->peers_list,
depends_on->name))
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index c841575..a9a850c 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -472,6 +472,63 @@
return 0;
}
+static void usb_prod_notify_cb(void *user_data, enum ipa_rm_event event,
+ unsigned long data)
+{
+ switch (event) {
+ case IPA_RM_RESOURCE_GRANTED:
+ pr_debug("USB_PROD resource granted\n");
+ break;
+ case IPA_RM_RESOURCE_RELEASED:
+ pr_debug("USB_PROD resource released\n");
+ break;
+ default:
+ break;
+ }
+ return;
+}
+
+static int usb_cons_request_resource(void)
+{
+ pr_debug(": Requesting USB_CONS resource\n");
+ return 0;
+}
+
+static int usb_cons_release_resource(void)
+{
+ pr_debug(": Releasing USB_CONS resource\n");
+ return 0;
+}
+
+static void usb_bam_ipa_create_resources(void)
+{
+ struct ipa_rm_create_params usb_prod_create_params;
+ struct ipa_rm_create_params usb_cons_create_params;
+ int ret;
+
+ /* Create USB_PROD entity */
+ memset(&usb_prod_create_params, 0, sizeof(usb_prod_create_params));
+ usb_prod_create_params.name = IPA_RM_RESOURCE_USB_PROD;
+ usb_prod_create_params.reg_params.notify_cb = usb_prod_notify_cb;
+ usb_prod_create_params.reg_params.user_data = NULL;
+ ret = ipa_rm_create_resource(&usb_prod_create_params);
+ if (ret) {
+ pr_err("%s: Failed to create USB_PROD resource\n", __func__);
+ return;
+ }
+
+ /* Create USB_CONS entity */
+ memset(&usb_cons_create_params, 0, sizeof(usb_cons_create_params));
+ usb_cons_create_params.name = IPA_RM_RESOURCE_USB_CONS;
+ usb_cons_create_params.request_resource = usb_cons_request_resource;
+ usb_cons_create_params.release_resource = usb_cons_release_resource;
+ ret = ipa_rm_create_resource(&usb_cons_create_params);
+ if (ret) {
+ pr_err("%s: Failed to create USB_CONS resource\n", __func__);
+ return ;
+ }
+}
+
int usb_bam_connect_ipa(struct usb_bam_connect_ipa_params *ipa_params)
{
u8 idx = ipa_params->idx;
@@ -500,6 +557,8 @@
connection->idx = idx;
+ ipa_rm_request_resource(IPA_CLIENT_USB_PROD);
+
ret = connect_pipe_ipa(ipa_params);
if (ret) {
pr_err("%s: dst pipe connection failure\n", __func__);
@@ -779,6 +838,7 @@
}
}
+ ipa_rm_release_resource(IPA_CLIENT_USB_PROD);
return 0;
}
@@ -925,14 +985,6 @@
return 0;
}
-static u8 qdss_conn_num;
-
-u8 usb_bam_get_qdss_num(void)
-{
- return qdss_conn_num;
-}
-EXPORT_SYMBOL(usb_bam_get_qdss_num);
-
static struct msm_usb_bam_platform_data *usb_bam_dt_to_pdata(
struct platform_device *pdev)
{
@@ -1055,11 +1107,6 @@
!strcmp(str, "usb-to-peri-qdss-hsusb") ||
!strcmp(str, "peri-to-usb-qdss-hsusb"))
conn_num = 0;
- else if (!strcmp(str, "usb-to-qdss-hsusb") ||
- !strcmp(str, "qdss-to-usb-hsusb")) {
- conn_num = 1;
- qdss_conn_num = 1;
- }
else
goto err;
@@ -1094,8 +1141,6 @@
struct resource *res, *ram_resource;
int irq;
- qdss_conn_num = 0;
-
res = platform_get_resource_byname(usb_bam_pdev, IORESOURCE_MEM,
bam_enable_strings[pdata->usb_active_bam]);
if (!res) {
@@ -1276,6 +1321,8 @@
return -ENOMEM;
}
+ usb_bam_ipa_create_resources();
+
return ret;
}
diff --git a/drivers/usb/gadget/u_qdss.c b/drivers/usb/gadget/u_qdss.c
index 2931ace..028d5e6 100644
--- a/drivers/usb/gadget/u_qdss.c
+++ b/drivers/usb/gadget/u_qdss.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -15,6 +15,8 @@
#include <linux/usb/msm_hsusb.h>
#include <mach/usb_bam.h>
+#define BAM_CONNC_IDX 0 /* USB bam connection index */
+
struct usb_qdss_bam_connect_info {
u32 usb_bam_pipe_idx;
u32 peer_pipe_idx;
@@ -55,18 +57,17 @@
pr_err("send_sps_req: usb_ep_queue error\n");
return -EIO;
}
-
return 0;
}
int set_qdss_data_connection(struct usb_ep *data_ep, u8 data_addr, int enable)
{
int res = 0;
- u8 conn_num = usb_bam_get_qdss_num();
+
pr_debug("set_qdss_data_connection\n");
if (enable) {
- res = usb_bam_connect(conn_num, NULL,
+ res = usb_bam_connect(BAM_CONNC_IDX, NULL,
&(bam_info.usb_bam_pipe_idx));
if (res) {
pr_err("usb_bam_connection error\n");
@@ -79,7 +80,7 @@
pr_err("qdss_data_connection: memory alloc failed\n");
return -ENOMEM;
}
- get_bam2bam_connection_info(conn_num,
+ get_bam2bam_connection_info(BAM_CONNC_IDX,
PEER_PERIPHERAL_TO_USB, &bam_info.usb_bam_handle,
&bam_info.usb_bam_pipe_idx, &bam_info.peer_pipe_idx,
NULL, bam_info.data_fifo);
@@ -88,7 +89,7 @@
bam_info.data_fifo->size, bam_info.usb_bam_pipe_idx);
} else {
kfree(bam_info.data_fifo);
- res = usb_bam_disconnect_pipe(conn_num);
+ res = usb_bam_disconnect_pipe(BAM_CONNC_IDX);
if (res) {
pr_err("usb_bam_disconnection error\n");
return res;
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index f1f6962..ea5484b 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -1776,6 +1776,9 @@
pdata->bus_scale_table = msm_bus_cl_get_pdata(pdev);
+ pdata->pool_64_bit_align = of_property_read_bool(node,
+ "qcom,pool-64-bit-align");
+
return pdata;
}
@@ -1853,6 +1856,7 @@
mehci->ehci.reset_sof_bug = 1;
mehci->ehci.resume_sof_bug = 1;
+ mehci->ehci.pool_64_bit_align = pdata->pool_64_bit_align;
if (pdata)
mehci->ehci.log2_irq_thresh = pdata->log2_irq_thresh;
diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
index 07a232a..d238b4e2 100644
--- a/drivers/usb/host/ehci-platform.c
+++ b/drivers/usb/host/ehci-platform.c
@@ -30,7 +30,6 @@
hcd->has_tt = pdata->has_tt;
ehci->has_synopsys_hc_bug = pdata->has_synopsys_hc_bug;
- ehci->pool_64_bit_align = pdata->pool_64_bit_align;
ehci->big_endian_desc = pdata->big_endian_desc;
ehci->big_endian_mmio = pdata->big_endian_mmio;
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index bde7340..1c8664c 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -379,7 +379,7 @@
list_add_tail(&urb->urb_list, &portdata->in_urb_list);
spin_unlock_irqrestore(&portdata->in_lock, flags);
- schedule_work(&portdata->in_work);
+ queue_work(system_nrt_wq, &portdata->in_work);
return;
}
@@ -498,7 +498,7 @@
port->throttle_req = false;
port->throttled = false;
- schedule_work(&portdata->in_work);
+ queue_work(system_nrt_wq, &portdata->in_work);
}
EXPORT_SYMBOL(usb_wwan_unthrottle);
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index 565d6b5..bd24575 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -16,6 +16,7 @@
#include <linux/types.h>
#include <linux/io.h>
#include <linux/mmc/host.h>
+#include <linux/pm_qos.h>
struct sdhci_host {
/* Data set by hardware interface driver */
@@ -161,6 +162,10 @@
u8 *adma_desc; /* ADMA descriptor table */
u8 *align_buffer; /* Bounce buffer */
+ unsigned int adma_desc_sz; /* ADMA descriptor table size */
+ unsigned int align_buf_sz; /* Bounce buffer size */
+ unsigned int adma_max_desc; /* Max ADMA descriptos (max sg segments) */
+
dma_addr_t adma_addr; /* Mapped ADMA descr. table */
dma_addr_t align_addr; /* Mapped bounce buffer */
@@ -183,6 +188,9 @@
#define SDHCI_TUNING_MODE_1 0
struct timer_list tuning_timer; /* Timer for tuning */
+ unsigned int cpu_dma_latency_us;
+ struct pm_qos_request pm_qos_req_dma;
+
unsigned long private[0] ____cacheline_aligned;
};
#endif /* LINUX_MMC_SDHCI_H */
diff --git a/include/linux/msm_ion.h b/include/linux/msm_ion.h
index 2593154..ff22e12 100644
--- a/include/linux/msm_ion.h
+++ b/include/linux/msm_ion.h
@@ -40,6 +40,7 @@
ION_CP_MFC_HEAP_ID = 12,
ION_CP_WB_HEAP_ID = 16, /* 8660 only */
ION_CAMERA_HEAP_ID = 20, /* 8660 only */
+ ION_ADSP_HEAP_ID = 22,
ION_PIL1_HEAP_ID = 23, /* Currently used for other PIL images */
ION_SF_HEAP_ID = 24,
ION_IOMMU_HEAP_ID = 25,
@@ -87,6 +88,7 @@
*/
#define ION_HEAP(bit) (1 << (bit))
+#define ION_ADSP_HEAP_NAME "adsp"
#define ION_VMALLOC_HEAP_NAME "vmalloc"
#define ION_AUDIO_HEAP_NAME "audio"
#define ION_SF_HEAP_NAME "sf"
diff --git a/include/linux/msm_ipa.h b/include/linux/msm_ipa.h
index 30bf4f2..b377a6c 100644
--- a/include/linux/msm_ipa.h
+++ b/include/linux/msm_ipa.h
@@ -49,7 +49,9 @@
#define IPA_IOCTL_V4_DEL_NAT 26
#define IPA_IOCTL_PULL_MSG 27
#define IPA_IOCTL_GET_NAT_OFFSET 28
-#define IPA_IOCTL_MAX 29
+#define IPA_IOCTL_RM_ADD_DEPENDENCY 29
+#define IPA_IOCTL_RM_DEL_DEPENDENCY 30
+#define IPA_IOCTL_MAX 31
/**
* max size of the header to be inserted
@@ -173,6 +175,35 @@
WLAN_STA_DISCONNECT,
};
+/**
+ * enum ipa_rm_resource_name - IPA RM clients identification names
+ *
+ * Add new mapping to ipa_rm_dep_prod_index() / ipa_rm_dep_cons_index()
+ * when adding new entry to this enum.
+ */
+enum ipa_rm_resource_name {
+ IPA_RM_RESOURCE_PROD = 0,
+ IPA_RM_RESOURCE_BRIDGE_PROD = IPA_RM_RESOURCE_PROD,
+ IPA_RM_RESOURCE_A2_PROD,
+ IPA_RM_RESOURCE_USB_PROD,
+ IPA_RM_RESOURCE_HSIC_PROD,
+ IPA_RM_RESOURCE_STD_ECM_PROD,
+ IPA_RM_RESOURCE_WWAN_0_PROD,
+ IPA_RM_RESOURCE_WWAN_1_PROD,
+ IPA_RM_RESOURCE_WWAN_2_PROD,
+ IPA_RM_RESOURCE_WWAN_3_PROD,
+ IPA_RM_RESOURCE_WWAN_4_PROD,
+ IPA_RM_RESOURCE_WWAN_5_PROD,
+ IPA_RM_RESOURCE_WWAN_6_PROD,
+ IPA_RM_RESOURCE_WWAN_7_PROD,
+ IPA_RM_RESOURCE_WLAN_PROD,
+ IPA_RM_RESOURCE_PROD_MAX,
+
+ IPA_RM_RESOURCE_A2_CONS = IPA_RM_RESOURCE_PROD_MAX,
+ IPA_RM_RESOURCE_USB_CONS,
+ IPA_RM_RESOURCE_HSIC_CONS,
+ IPA_RM_RESOURCE_MAX
+};
/**
* struct ipa_rule_attrib - attributes of a routing/filtering
@@ -682,6 +713,15 @@
uint8_t mac_addr[IPA_MAC_ADDR_SIZE];
};
+/**
+ * struct ipa_ioc_rm_dependency - parameters for add/delete dependency
+ * @resource_name: name of dependent resource
+ * @depends_on_name: name of its dependency
+ */
+struct ipa_ioc_rm_dependency {
+ enum ipa_rm_resource_name resource_name;
+ enum ipa_rm_resource_name depends_on_name;
+};
/**
@@ -768,6 +808,12 @@
#define IPA_IOC_PULL_MSG _IOWR(IPA_IOC_MAGIC, \
IPA_IOCTL_PULL_MSG, \
struct ipa_msg_meta *)
+#define IPA_IOC_RM_ADD_DEPENDENCY _IOWR(IPA_IOC_MAGIC, \
+ IPA_IOCTL_RM_ADD_DEPENDENCY, \
+ struct ipa_ioc_rm_dependency *)
+#define IPA_IOC_RM_DEL_DEPENDENCY _IOWR(IPA_IOC_MAGIC, \
+ IPA_IOCTL_RM_DEL_DEPENDENCY, \
+ struct ipa_ioc_rm_dependency *)
/*
* unique magic number of the Tethering bridge ioctls
diff --git a/include/linux/usb/ehci_pdriver.h b/include/linux/usb/ehci_pdriver.h
index 4c1b7a0..1894f42 100644
--- a/include/linux/usb/ehci_pdriver.h
+++ b/include/linux/usb/ehci_pdriver.h
@@ -41,7 +41,6 @@
unsigned big_endian_mmio:1;
unsigned port_power_on:1;
unsigned port_power_off:1;
- unsigned pool_64_bit_align:1;
};
#endif /* __USB_CORE_EHCI_PDRIVER_H */
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index b210a2e..c7c6b05 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -411,6 +411,7 @@
/*standalone latency is required when HSCI is active*/
u32 standalone_latency;
+ bool pool_64_bit_align;
};
struct msm_usb_host_platform_data {