mmc: msm_sdcc: vote for msm bus bandwidth

If there is no voting for the system fabric clock, it may run at the
minimum clock speed. If system fabric is running at lower speed (than what
is needed by SDCC workload), SDCC read & write throughput numbers may be
degraded.

This patch adds the msm bus voting for bandwidth required by SDCC driver
based on card clock speed and bus width.

CRs-Fixed: 355327
Change-Id: I2542a3b9d2b9909d48304d52b3256ec607e433e2
Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
diff --git a/arch/arm/include/asm/mach/mmc.h b/arch/arm/include/asm/mach/mmc.h
index dabd390..745a3a4 100644
--- a/arch/arm/include/asm/mach/mmc.h
+++ b/arch/arm/include/asm/mach/mmc.h
@@ -8,6 +8,7 @@
 #include <linux/mmc/card.h>
 #include <linux/mmc/sdio_func.h>
 #include <mach/gpio.h>
+#include <mach/msm_bus.h>
 
 #define SDC_DAT1_DISABLE 0
 #define SDC_DAT1_ENABLE  1
@@ -112,6 +113,12 @@
 	struct msm_mmc_pad_data *pad_data;
 };
 
+struct msm_mmc_bus_voting_data {
+	struct msm_bus_scale_pdata *use_cases;
+	unsigned int *bw_vecs;
+	unsigned int bw_vecs_size;
+};
+
 struct mmc_platform_data {
 	unsigned int ocr_mask;			/* available voltages */
 	int built_in;				/* built-in device flag */
@@ -153,6 +160,7 @@
 	bool disable_runtime_pm;
 	bool disable_cmd23;
 	u32 cpu_dma_latency;
+	struct msm_mmc_bus_voting_data *msm_bus_voting_data;
 };
 
 #endif
diff --git a/arch/arm/mach-msm/board-8064-storage.c b/arch/arm/mach-msm/board-8064-storage.c
index b4e7d35..72126c8 100644
--- a/arch/arm/mach-msm/board-8064-storage.c
+++ b/arch/arm/mach-msm/board-8064-storage.c
@@ -23,6 +23,7 @@
 #include <mach/gpiomux.h>
 #include "devices.h"
 #include "board-8064.h"
+#include "board-storage-common-a.h"
 
 
 /* APQ8064 has 4 SDCC controllers */
@@ -219,6 +220,7 @@
 	.vreg_data	= &mmc_slot_vreg_data[SDCC1],
 	.uhs_caps	= MMC_CAP_1_8V_DDR | MMC_CAP_UHS_DDR50,
 	.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC1_DAT1,
+	.msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
 };
 static struct mmc_platform_data *apq8064_sdc1_pdata = &sdc1_data;
 #else
@@ -249,6 +251,7 @@
 			MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_DDR50 |
 			MMC_CAP_UHS_SDR104 | MMC_CAP_MAX_CURRENT_800),
 	.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC3_DAT1,
+	.msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
 };
 static struct mmc_platform_data *apq8064_sdc3_pdata = &sdc3_data;
 #else
diff --git a/arch/arm/mach-msm/board-8930-storage.c b/arch/arm/mach-msm/board-8930-storage.c
index 9171749..6dd7add 100644
--- a/arch/arm/mach-msm/board-8930-storage.c
+++ b/arch/arm/mach-msm/board-8930-storage.c
@@ -24,6 +24,7 @@
 #include "devices.h"
 
 #include "board-8930.h"
+#include "board-storage-common-a.h"
 
 /* MSM8960 has 5 SDCC controllers */
 enum sdcc_controllers {
@@ -235,6 +236,7 @@
 	.vreg_data	= &mmc_slot_vreg_data[SDCC1],
 	.pin_data	= &mmc_slot_pin_data[SDCC1],
 	.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC1_DAT1,
+	.msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
 };
 #endif
 
@@ -273,6 +275,7 @@
 			MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_DDR50 |
 			MMC_CAP_UHS_SDR104 | MMC_CAP_MAX_CURRENT_800),
 	.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC3_DAT1,
+	.msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
 };
 #endif
 
diff --git a/arch/arm/mach-msm/board-8960-storage.c b/arch/arm/mach-msm/board-8960-storage.c
index df1d846..10a6903 100644
--- a/arch/arm/mach-msm/board-8960-storage.c
+++ b/arch/arm/mach-msm/board-8960-storage.c
@@ -17,12 +17,12 @@
 #include <linux/bootmem.h>
 #include <asm/mach-types.h>
 #include <asm/mach/mmc.h>
-#include <mach/msm_bus_board.h>
 #include <mach/board.h>
 #include <mach/gpio.h>
 #include <mach/gpiomux.h>
 #include "devices.h"
 #include "board-8960.h"
+#include "board-storage-common-a.h"
 
 /* MSM8960 has 5 SDCC controllers */
 enum sdcc_controllers {
@@ -299,6 +299,7 @@
 	.vreg_data	= &mmc_slot_vreg_data[SDCC1],
 	.pin_data	= &mmc_slot_pin_data[SDCC1],
 	.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC1_DAT1,
+	.msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
 };
 #endif
 
@@ -316,6 +317,7 @@
 	.vreg_data      = &mmc_slot_vreg_data[SDCC2],
 	.pin_data       = &mmc_slot_pin_data[SDCC2],
 	.sdiowakeup_irq = MSM_GPIO_TO_INT(90),
+	.msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
 };
 #endif
 
@@ -342,6 +344,7 @@
 			MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_DDR50 |
 			MMC_CAP_UHS_SDR104 | MMC_CAP_MAX_CURRENT_600),
 	.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC3_DAT1,
+	.msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
 };
 #endif
 
@@ -359,6 +362,7 @@
 	.vreg_data      = &mmc_slot_vreg_data[SDCC4],
 	.pin_data       = &mmc_slot_pin_data[SDCC4],
 	.sdiowakeup_irq = MSM_GPIO_TO_INT(85),
+	.msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
 };
 #endif
 
diff --git a/arch/arm/mach-msm/board-9615-storage.c b/arch/arm/mach-msm/board-9615-storage.c
index 7580cc3..5bdeb94 100644
--- a/arch/arm/mach-msm/board-9615-storage.c
+++ b/arch/arm/mach-msm/board-9615-storage.c
@@ -22,6 +22,7 @@
 #include "devices.h"
 
 #include "board-9615.h"
+#include "board-storage-common-a.h"
 
 #if (defined(CONFIG_MMC_MSM_SDC1_SUPPORT) \
 		|| defined(CONFIG_MMC_MSM_SDC2_SUPPORT))
@@ -187,6 +188,7 @@
 	.uhs_caps	= (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
 			   MMC_CAP_MAX_CURRENT_400),
 	.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC1_DAT1,
+	.msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
 };
 static struct mmc_platform_data *msm9615_sdc1_pdata = &sdc1_data;
 #else
@@ -206,6 +208,7 @@
 	.pclk_src_dfab	= 1,
 	.pin_data	= &mmc_slot_pin_data[SDCC2],
 	.sdiowakeup_irq = MSM_GPIO_TO_INT(GPIO_SDC2_DAT1_WAKEUP),
+	.msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
 };
 static struct mmc_platform_data *msm9615_sdc2_pdata = &sdc2_data;
 #else
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index e5a31f2a..b0799c2 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -102,6 +102,7 @@
 #include "rpm_resources.h"
 #include "acpuclock.h"
 #include "pm-boot.h"
+#include "board-storage-common-a.h"
 
 #include <linux/ion.h>
 #include <mach/ion.h>
@@ -8356,6 +8357,7 @@
 	.msmsdcc_fmax	= 48000000,
 	.nonremovable	= 1,
 	.pclk_src_dfab	= 1,
+	.msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
 };
 #endif
 
@@ -8374,6 +8376,7 @@
 #ifdef CONFIG_MSM_SDIO_AL
 	.is_sdio_al_client = 1,
 #endif
+	.msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
 };
 #endif
 
@@ -8395,6 +8398,7 @@
 	.nonremovable	= 0,
 	.pclk_src_dfab  = 1,
 	.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC3_DAT1,
+	.msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
 };
 #endif
 
@@ -8409,6 +8413,7 @@
 	.nonremovable	= 0,
 	.pclk_src_dfab  = 1,
 	.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC4_DAT1,
+	.msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
 };
 #endif
 
@@ -8427,6 +8432,7 @@
 #ifdef CONFIG_MSM_SDIO_AL
 	.is_sdio_al_client = 1,
 #endif
+	.msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
 };
 #endif
 
diff --git a/arch/arm/mach-msm/board-storage-common-a.h b/arch/arm/mach-msm/board-storage-common-a.h
new file mode 100644
index 0000000..7737819
--- /dev/null
+++ b/arch/arm/mach-msm/board-storage-common-a.h
@@ -0,0 +1,99 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _BOARD_STORAGE_A_H
+#define _BOARD_STORAGE_A_H
+
+#include <asm/mach/mmc.h>
+#include <mach/msm_bus_board.h>
+#include <mach/msm_bus.h>
+
+#define MSM_BUS_SPS_TO_DDR_VOTE_VECTOR(num, _ib) \
+static struct msm_bus_vectors sps_to_ddr_perf_vectors_##num[] = { \
+	{ \
+		.src = MSM_BUS_MASTER_SPS, \
+		.dst = MSM_BUS_SLAVE_EBI_CH0, \
+		.ib = (_ib), \
+		.ab = ((_ib) / 2), \
+	} \
+}
+
+#define MSM_BUS_SPS_TO_DDR_VOTE_VECTOR_USECASE(num) \
+	{ \
+		ARRAY_SIZE(sps_to_ddr_perf_vectors_##num), \
+		sps_to_ddr_perf_vectors_##num, \
+	}
+
+/* no bandwidth required */
+MSM_BUS_SPS_TO_DDR_VOTE_VECTOR(0, 0);
+/*
+ * 13 MB/s bandwidth
+ * 4-bit MMC_TIMING_LEGACY
+ * 4-bit MMC_TIMING_UHS_SDR12
+ */
+MSM_BUS_SPS_TO_DDR_VOTE_VECTOR(1, 13 * 1024 * 1024);
+/*
+ * 26 MB/s bandwidth
+ * 8-bit MMC_TIMING_LEGACY
+ * 4-bit MMC_TIMING_MMC_HS / MMC_TIMING_SD_HS /
+ *	 MMC_TIMING_UHS_SDR25
+ */
+MSM_BUS_SPS_TO_DDR_VOTE_VECTOR(2, 26 * 1024 * 1024);
+/*
+ * 52 MB/s bandwidth
+ * 8-bit MMC_TIMING_MMC_HS
+ * 4-bit MMC_TIMING_UHS_SDR50 / MMC_TIMING_UHS_DDR50
+ */
+MSM_BUS_SPS_TO_DDR_VOTE_VECTOR(3, 52 * 1024 * 1024);
+/*
+ * 104 MB/s bandwidth
+ * 8-bit MMC_TIMING_UHS_DDR50
+ * 4-bit MMC_TIMING_UHS_SDR104 / MMC_TIMING_MMC_HS200
+ */
+MSM_BUS_SPS_TO_DDR_VOTE_VECTOR(4, 104 * 1024 * 1024);
+/*
+ * 200 MB/s bandwidth
+ * 8-bit MMC_TIMING_MMC_HS200
+ */
+MSM_BUS_SPS_TO_DDR_VOTE_VECTOR(5, 200 * 1024 * 1024);
+/* max. possible bandwidth */
+MSM_BUS_SPS_TO_DDR_VOTE_VECTOR(6, UINT_MAX);
+
+static unsigned int sdcc_bw_vectors[] = {0, (13 * 1024 * 1024),
+				(26 * 1024 * 1024), (52 * 1024 * 1024),
+				(104 * 1024 * 1024), (200 * 1024 * 1024),
+				UINT_MAX};
+
+static struct msm_bus_paths sps_to_ddr_bus_scale_usecases[] = {
+	MSM_BUS_SPS_TO_DDR_VOTE_VECTOR_USECASE(0),
+	MSM_BUS_SPS_TO_DDR_VOTE_VECTOR_USECASE(1),
+	MSM_BUS_SPS_TO_DDR_VOTE_VECTOR_USECASE(2),
+	MSM_BUS_SPS_TO_DDR_VOTE_VECTOR_USECASE(3),
+	MSM_BUS_SPS_TO_DDR_VOTE_VECTOR_USECASE(4),
+	MSM_BUS_SPS_TO_DDR_VOTE_VECTOR_USECASE(5),
+	MSM_BUS_SPS_TO_DDR_VOTE_VECTOR_USECASE(6),
+};
+
+static struct msm_bus_scale_pdata sps_to_ddr_bus_scale_data = {
+	sps_to_ddr_bus_scale_usecases,
+	ARRAY_SIZE(sps_to_ddr_bus_scale_usecases),
+	.name = "msm_sdcc",
+};
+
+static struct msm_mmc_bus_voting_data sps_to_ddr_bus_voting_data = {
+	.use_cases = &sps_to_ddr_bus_scale_data,
+	.bw_vecs = sdcc_bw_vectors,
+	.bw_vecs_size = sizeof(sdcc_bw_vectors),
+};
+
+#endif /* _BOARD_STORAGE_A_H */