msm: 8064: hsic: Add msm_bus vote for hsic controller driver
Drivers need to specify their bandwidth requirements to
bus-scaling driver to get guaranteed bandwidth on fabrics.
HSIC USB performance depends upon system fabric frequency
as HSIC USB controller has to support high bi-directional
data transfers. Hence, request for high bus bandwidth as
long as HSIC is active.
Also add debugfs entry to enable/disable the bus voting:-
echo enable > /sys/kernel/debug/ehci_hsic_msm_dbg/bus_voting
echo disable > /sys/kernel/debug/ehci_hsic_msm_dbg/bus_voting
CRs-Fixed: 342032
Signed-off-by: Hemant Kumar <hemantk@codeaurora.org>
Change-Id: I7e208d67ef1c0168cd7621aeae4e8b123adef255
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index df20d60..d01af99 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -479,9 +479,59 @@
}
#ifdef CONFIG_USB_EHCI_MSM_HSIC
+/* Bandwidth requests (zero) if no vote placed */
+static struct msm_bus_vectors hsic_init_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_SPS,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_SPS,
+ .dst = MSM_BUS_SLAVE_SPS,
+ .ab = 0,
+ .ib = 0,
+ },
+};
+
+/* Bus bandwidth requests in Bytes/sec */
+static struct msm_bus_vectors hsic_max_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_SPS,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 60000000, /* At least 480Mbps on bus. */
+ .ib = 960000000, /* MAX bursts rate */
+ },
+ {
+ .src = MSM_BUS_MASTER_SPS,
+ .dst = MSM_BUS_SLAVE_SPS,
+ .ab = 0,
+ .ib = 512000000, /*vote for 64Mhz dfab clk rate*/
+ },
+};
+
+static struct msm_bus_paths hsic_bus_scale_usecases[] = {
+ {
+ ARRAY_SIZE(hsic_init_vectors),
+ hsic_init_vectors,
+ },
+ {
+ ARRAY_SIZE(hsic_max_vectors),
+ hsic_max_vectors,
+ },
+};
+
+static struct msm_bus_scale_pdata hsic_bus_scale_pdata = {
+ hsic_bus_scale_usecases,
+ ARRAY_SIZE(hsic_bus_scale_usecases),
+ .name = "hsic",
+};
+
static struct msm_hsic_host_platform_data msm_hsic_pdata = {
- .strobe = 88,
- .data = 89,
+ .strobe = 88,
+ .data = 89,
+ .bus_scale_table = &hsic_bus_scale_pdata,
};
#else
static struct msm_hsic_host_platform_data msm_hsic_pdata;
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 347711b..dbbfad4 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -25,9 +25,12 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/err.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
#include <linux/wakelock.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
+#include <mach/msm_bus.h>
#include <linux/usb/msm_hsusb_hw.h>
#include <linux/usb/msm_hsusb.h>
@@ -55,8 +58,10 @@
int peripheral_status_irq;
int wakeup_irq;
bool wakeup_irq_enabled;
+ uint32_t bus_perf_client;
};
+static bool debug_bus_voting_enabled = true;
static inline struct msm_hsic_hcd *hcd_to_hsic(struct usb_hcd *hcd)
{
return (struct msm_hsic_hcd *) (hcd->hcd_priv);
@@ -464,6 +469,14 @@
if (ret < 0)
dev_err(mehci->dev, "unable to set vddcx voltage: min:0.5v max:1.3v\n");
+ if (mehci->bus_perf_client && debug_bus_voting_enabled) {
+ ret = msm_bus_scale_client_update_request(
+ mehci->bus_perf_client, 0);
+ if (ret)
+ dev_err(mehci->dev, "%s: Failed to dvote for "
+ "bus bandwidth %d\n", __func__, ret);
+ }
+
atomic_set(&mehci->in_lpm, 1);
enable_irq(hcd->irq);
wake_unlock(&mehci->wlock);
@@ -487,6 +500,14 @@
wake_lock(&mehci->wlock);
+ if (mehci->bus_perf_client && debug_bus_voting_enabled) {
+ ret = msm_bus_scale_client_update_request(
+ mehci->bus_perf_client, 1);
+ if (ret)
+ dev_err(mehci->dev, "%s: Failed to vote for "
+ "bus bandwidth %d\n", __func__, ret);
+ }
+
ret = regulator_set_voltage(mehci->hsic_vddcx,
USB_PHY_VDD_DIG_VOL_MIN,
USB_PHY_VDD_DIG_VOL_MAX);
@@ -754,6 +775,88 @@
return IRQ_HANDLED;
}
+static int ehci_hsic_msm_bus_show(struct seq_file *s, void *unused)
+{
+ if (debug_bus_voting_enabled)
+ seq_printf(s, "enabled\n");
+ else
+ seq_printf(s, "disabled\n");
+
+ return 0;
+}
+
+static int ehci_hsic_msm_bus_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ehci_hsic_msm_bus_show, inode->i_private);
+}
+
+static ssize_t ehci_hsic_msm_bus_write(struct file *file,
+ const char __user *ubuf, size_t count, loff_t *ppos)
+{
+ char buf[8];
+ int ret;
+ struct seq_file *s = file->private_data;
+ struct msm_hsic_hcd *mehci = s->private;
+
+ memset(buf, 0x00, sizeof(buf));
+
+ if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+ return -EFAULT;
+
+ if (!strncmp(buf, "enable", 6)) {
+ /* Do not vote here. Let hsic driver decide when to vote */
+ debug_bus_voting_enabled = true;
+ } else {
+ debug_bus_voting_enabled = false;
+ if (mehci->bus_perf_client) {
+ ret = msm_bus_scale_client_update_request(
+ mehci->bus_perf_client, 0);
+ if (ret)
+ dev_err(mehci->dev, "%s: Failed to devote "
+ "for bus bw %d\n", __func__, ret);
+ }
+ }
+
+ return count;
+}
+
+const struct file_operations ehci_hsic_msm_bus_fops = {
+ .open = ehci_hsic_msm_bus_open,
+ .read = seq_read,
+ .write = ehci_hsic_msm_bus_write,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static struct dentry *ehci_hsic_msm_dbg_root;
+static int ehci_hsic_msm_debugfs_init(struct msm_hsic_hcd *mehci)
+{
+ struct dentry *ehci_hsic_msm_dentry;
+
+ ehci_hsic_msm_dbg_root = debugfs_create_dir("ehci_hsic_msm_dbg", NULL);
+
+ if (!ehci_hsic_msm_dbg_root || IS_ERR(ehci_hsic_msm_dbg_root))
+ return -ENODEV;
+
+ ehci_hsic_msm_dentry = debugfs_create_file("bus_voting",
+ S_IRUGO | S_IWUSR,
+ ehci_hsic_msm_dbg_root, mehci,
+ &ehci_hsic_msm_bus_fops);
+
+ if (!ehci_hsic_msm_dentry) {
+ debugfs_remove_recursive(ehci_hsic_msm_dbg_root);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void ehci_hsic_msm_debugfs_cleanup(void)
+{
+ debugfs_remove_recursive(ehci_hsic_msm_dbg_root);
+}
+
+
static int __devinit ehci_hsic_msm_probe(struct platform_device *pdev)
{
@@ -886,6 +989,27 @@
}
}
+ ret = ehci_hsic_msm_debugfs_init(mehci);
+ if (ret)
+ dev_dbg(&pdev->dev, "mode debugfs file is"
+ "not available\n");
+
+ if (pdata && pdata->bus_scale_table) {
+ mehci->bus_perf_client =
+ msm_bus_scale_register_client(pdata->bus_scale_table);
+ /* Configure BUS performance parameters for MAX bandwidth */
+ if (mehci->bus_perf_client) {
+ ret = msm_bus_scale_client_update_request(
+ mehci->bus_perf_client, 1);
+ if (ret)
+ dev_err(&pdev->dev, "%s: Failed to vote for "
+ "bus bandwidth %d\n", __func__, ret);
+ } else {
+ dev_err(&pdev->dev, "%s: Failed to register BUS "
+ "scaling client!!\n", __func__);
+ }
+ }
+
/*
* This pdev->dev is assigned parent of root-hub by USB core,
* hence, runtime framework automatically calls this driver's
@@ -930,6 +1054,10 @@
free_irq(mehci->wakeup_irq, mehci);
}
+ if (mehci->bus_perf_client)
+ msm_bus_scale_unregister_client(mehci->bus_perf_client);
+
+ ehci_hsic_msm_debugfs_cleanup();
device_init_wakeup(&pdev->dev, 0);
pm_runtime_set_suspended(&pdev->dev);
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index bb6a01d..1a6df8b 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -331,6 +331,7 @@
unsigned strobe;
unsigned data;
unsigned hub_reset;
+ struct msm_bus_scale_pdata *bus_scale_table;
};
struct msm_usb_host_platform_data {