aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-08-14 16:43:09 -0700
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-08-14 16:43:09 -0700
commit37a842d36f63a047d94be2603d40d4407c949f1b (patch)
tree6aed94775f66f7198130b725bb5c7eae98faacdb /drivers/usb
parentMerge tag 'usb-for-v4.3' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next (diff)
parentusb: chipidea: add tx/rx burst size configuration interface (diff)
downloadlinux-dev-37a842d36f63a047d94be2603d40d4407c949f1b.tar.xz
linux-dev-37a842d36f63a047d94be2603d40d4407c949f1b.zip
Merge tag 'usb-ci-v4.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/peter.chen/usb into usb-next
Peter writes: USB: chipidea updates for v4.3-rc1 The main changes are adding several system interfaces for tuning performance, and each vendors can adjust them according to their design configurations. Others are tiny improvements, like more well siTD supports, USB_DEVICE_A_HNP_SUPPORT supports, etc.
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/chipidea/bits.h12
-rw-r--r--drivers/usb/chipidea/ci.h4
-rw-r--r--drivers/usb/chipidea/ci_hdrc_imx.c17
-rw-r--r--drivers/usb/chipidea/core.c113
-rw-r--r--drivers/usb/chipidea/debug.c6
-rw-r--r--drivers/usb/chipidea/host.c26
-rw-r--r--drivers/usb/chipidea/otg_fsm.c1
-rw-r--r--drivers/usb/chipidea/udc.c9
-rw-r--r--drivers/usb/chipidea/usbmisc_imx.c12
9 files changed, 169 insertions, 31 deletions
diff --git a/drivers/usb/chipidea/bits.h b/drivers/usb/chipidea/bits.h
index 3cb9bda51ddf..e462f55c8b99 100644
--- a/drivers/usb/chipidea/bits.h
+++ b/drivers/usb/chipidea/bits.h
@@ -25,6 +25,9 @@
#define VERSION (0xF << 25)
#define CIVERSION (0x7 << 29)
+/* SBUSCFG */
+#define AHBBRST_MASK 0x7
+
/* HCCPARAMS */
#define HCCPARAMS_LEN BIT(17)
@@ -53,6 +56,15 @@
#define DEVICEADDR_USBADRA BIT(24)
#define DEVICEADDR_USBADR (0x7FUL << 25)
+/* TTCTRL */
+#define TTCTRL_TTHA_MASK (0x7fUL << 24)
+/* Set non-zero value for internal TT Hub address representation */
+#define TTCTRL_TTHA (0x7fUL << 24)
+
+/* BURSTSIZE */
+#define RX_BURST_MASK 0xff
+#define TX_BURST_MASK 0xff00
+
/* PORTSC */
#define PORTSC_CCS BIT(0)
#define PORTSC_CSC BIT(1)
diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
index f243f0b431c3..41d7cf6d63ba 100644
--- a/drivers/usb/chipidea/ci.h
+++ b/drivers/usb/chipidea/ci.h
@@ -50,6 +50,8 @@ enum ci_hw_regs {
OP_USBINTR,
OP_DEVICEADDR,
OP_ENDPTLISTADDR,
+ OP_TTCTRL,
+ OP_BURSTSIZE,
OP_PORTSC,
OP_DEVLC,
OP_OTGSC,
@@ -429,4 +431,6 @@ u8 hw_port_test_get(struct ci_hdrc *ci);
int hw_wait_reg(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask,
u32 value, unsigned int timeout_ms);
+void ci_platform_configure(struct ci_hdrc *ci);
+
#endif /* __DRIVERS_USB_CHIPIDEA_CI_H */
diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c
index 389f0e034259..867e9f3f3859 100644
--- a/drivers/usb/chipidea/ci_hdrc_imx.c
+++ b/drivers/usb/chipidea/ci_hdrc_imx.c
@@ -29,26 +29,31 @@ struct ci_hdrc_imx_platform_flag {
};
static const struct ci_hdrc_imx_platform_flag imx27_usb_data = {
+ CI_HDRC_DISABLE_STREAMING,
};
static const struct ci_hdrc_imx_platform_flag imx28_usb_data = {
.flags = CI_HDRC_IMX28_WRITE_FIX |
- CI_HDRC_TURN_VBUS_EARLY_ON,
+ CI_HDRC_TURN_VBUS_EARLY_ON |
+ CI_HDRC_DISABLE_STREAMING,
};
static const struct ci_hdrc_imx_platform_flag imx6q_usb_data = {
.flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
- CI_HDRC_TURN_VBUS_EARLY_ON,
+ CI_HDRC_TURN_VBUS_EARLY_ON |
+ CI_HDRC_DISABLE_STREAMING,
};
static const struct ci_hdrc_imx_platform_flag imx6sl_usb_data = {
.flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
- CI_HDRC_TURN_VBUS_EARLY_ON,
+ CI_HDRC_TURN_VBUS_EARLY_ON |
+ CI_HDRC_DISABLE_HOST_STREAMING,
};
static const struct ci_hdrc_imx_platform_flag imx6sx_usb_data = {
.flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
- CI_HDRC_TURN_VBUS_EARLY_ON,
+ CI_HDRC_TURN_VBUS_EARLY_ON |
+ CI_HDRC_DISABLE_HOST_STREAMING,
};
static const struct of_device_id ci_hdrc_imx_dt_ids[] = {
@@ -104,7 +109,7 @@ static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev)
misc_pdev = of_find_device_by_node(args.np);
of_node_put(args.np);
- if (!misc_pdev)
+ if (!misc_pdev || !platform_get_drvdata(misc_pdev))
return ERR_PTR(-EPROBE_DEFER);
data->dev = &misc_pdev->dev;
@@ -126,7 +131,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
struct ci_hdrc_platform_data pdata = {
.name = dev_name(&pdev->dev),
.capoffset = DEF_CAPOFFSET,
- .flags = CI_HDRC_DISABLE_STREAMING,
+ .flags = CI_HDRC_SET_NON_ZERO_TTHA,
};
int ret;
const struct of_device_id *of_id =
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index ab6212e888e1..3feebf7f31f0 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -64,6 +64,7 @@
#include <linux/of.h>
#include <linux/phy.h>
#include <linux/regulator/consumer.h>
+#include <linux/usb/ehci_def.h>
#include "ci.h"
#include "udc.h"
@@ -84,6 +85,8 @@ static const u8 ci_regs_nolpm[] = {
[OP_USBINTR] = 0x08U,
[OP_DEVICEADDR] = 0x14U,
[OP_ENDPTLISTADDR] = 0x18U,
+ [OP_TTCTRL] = 0x1CU,
+ [OP_BURSTSIZE] = 0x20U,
[OP_PORTSC] = 0x44U,
[OP_DEVLC] = 0x84U,
[OP_OTGSC] = 0x64U,
@@ -106,6 +109,8 @@ static const u8 ci_regs_lpm[] = {
[OP_USBINTR] = 0x08U,
[OP_DEVICEADDR] = 0x14U,
[OP_ENDPTLISTADDR] = 0x18U,
+ [OP_TTCTRL] = 0x1CU,
+ [OP_BURSTSIZE] = 0x20U,
[OP_PORTSC] = 0x44U,
[OP_DEVLC] = 0x84U,
[OP_OTGSC] = 0xC4U,
@@ -118,7 +123,7 @@ static const u8 ci_regs_lpm[] = {
[OP_ENDPTCTRL] = 0xECU,
};
-static int hw_alloc_regmap(struct ci_hdrc *ci, bool is_lpm)
+static void hw_alloc_regmap(struct ci_hdrc *ci, bool is_lpm)
{
int i;
@@ -134,7 +139,6 @@ static int hw_alloc_regmap(struct ci_hdrc *ci, bool is_lpm)
? ci_regs_lpm[OP_ENDPTCTRL]
: ci_regs_nolpm[OP_ENDPTCTRL]);
- return 0;
}
static enum ci_revision ci_get_revision(struct ci_hdrc *ci)
@@ -403,6 +407,55 @@ static int ci_usb_phy_init(struct ci_hdrc *ci)
return ret;
}
+
+/**
+ * ci_platform_configure: do controller configure
+ * @ci: the controller
+ *
+ */
+void ci_platform_configure(struct ci_hdrc *ci)
+{
+ bool is_device_mode, is_host_mode;
+
+ is_device_mode = hw_read(ci, OP_USBMODE, USBMODE_CM) == USBMODE_CM_DC;
+ is_host_mode = hw_read(ci, OP_USBMODE, USBMODE_CM) == USBMODE_CM_HC;
+
+ if (is_device_mode &&
+ (ci->platdata->flags & CI_HDRC_DISABLE_DEVICE_STREAMING))
+ hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS);
+
+ if (is_host_mode &&
+ (ci->platdata->flags & CI_HDRC_DISABLE_HOST_STREAMING))
+ hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS);
+
+ if (ci->platdata->flags & CI_HDRC_FORCE_FULLSPEED) {
+ if (ci->hw_bank.lpm)
+ hw_write(ci, OP_DEVLC, DEVLC_PFSC, DEVLC_PFSC);
+ else
+ hw_write(ci, OP_PORTSC, PORTSC_PFSC, PORTSC_PFSC);
+ }
+
+ if (ci->platdata->flags & CI_HDRC_SET_NON_ZERO_TTHA)
+ hw_write(ci, OP_TTCTRL, TTCTRL_TTHA_MASK, TTCTRL_TTHA);
+
+ hw_write(ci, OP_USBCMD, 0xff0000, ci->platdata->itc_setting << 16);
+
+ if (ci->platdata->flags & CI_HDRC_OVERRIDE_AHB_BURST)
+ hw_write_id_reg(ci, ID_SBUSCFG, AHBBRST_MASK,
+ ci->platdata->ahb_burst_config);
+
+ /* override burst size, take effect only when ahb_burst_config is 0 */
+ if (!hw_read_id_reg(ci, ID_SBUSCFG, AHBBRST_MASK)) {
+ if (ci->platdata->flags & CI_HDRC_OVERRIDE_TX_BURST)
+ hw_write(ci, OP_BURSTSIZE, TX_BURST_MASK,
+ ci->platdata->tx_burst_size << __ffs(TX_BURST_MASK));
+
+ if (ci->platdata->flags & CI_HDRC_OVERRIDE_RX_BURST)
+ hw_write(ci, OP_BURSTSIZE, RX_BURST_MASK,
+ ci->platdata->rx_burst_size);
+ }
+}
+
/**
* hw_controller_reset: do controller reset
* @ci: the controller
@@ -447,16 +500,6 @@ int hw_device_reset(struct ci_hdrc *ci)
ci->platdata->notify_event(ci,
CI_HDRC_CONTROLLER_RESET_EVENT);
- if (ci->platdata->flags & CI_HDRC_DISABLE_STREAMING)
- hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS);
-
- if (ci->platdata->flags & CI_HDRC_FORCE_FULLSPEED) {
- if (ci->hw_bank.lpm)
- hw_write(ci, OP_DEVLC, DEVLC_PFSC, DEVLC_PFSC);
- else
- hw_write(ci, OP_PORTSC, PORTSC_PFSC, PORTSC_PFSC);
- }
-
/* USBMODE should be configured step by step */
hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE);
hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_DC);
@@ -469,6 +512,8 @@ int hw_device_reset(struct ci_hdrc *ci)
return -ENODEV;
}
+ ci_platform_configure(ci);
+
return 0;
}
@@ -606,6 +651,50 @@ static int ci_get_platdata(struct device *dev,
if (of_usb_get_maximum_speed(dev->of_node) == USB_SPEED_FULL)
platdata->flags |= CI_HDRC_FORCE_FULLSPEED;
+ platdata->itc_setting = 1;
+ if (of_find_property(dev->of_node, "itc-setting", NULL)) {
+ ret = of_property_read_u32(dev->of_node, "itc-setting",
+ &platdata->itc_setting);
+ if (ret) {
+ dev_err(dev,
+ "failed to get itc-setting\n");
+ return ret;
+ }
+ }
+
+ if (of_find_property(dev->of_node, "ahb-burst-config", NULL)) {
+ ret = of_property_read_u32(dev->of_node, "ahb-burst-config",
+ &platdata->ahb_burst_config);
+ if (ret) {
+ dev_err(dev,
+ "failed to get ahb-burst-config\n");
+ return ret;
+ }
+ platdata->flags |= CI_HDRC_OVERRIDE_AHB_BURST;
+ }
+
+ if (of_find_property(dev->of_node, "tx-burst-size-dword", NULL)) {
+ ret = of_property_read_u32(dev->of_node, "tx-burst-size-dword",
+ &platdata->tx_burst_size);
+ if (ret) {
+ dev_err(dev,
+ "failed to get tx-burst-size-dword\n");
+ return ret;
+ }
+ platdata->flags |= CI_HDRC_OVERRIDE_TX_BURST;
+ }
+
+ if (of_find_property(dev->of_node, "rx-burst-size-dword", NULL)) {
+ ret = of_property_read_u32(dev->of_node, "rx-burst-size-dword",
+ &platdata->rx_burst_size);
+ if (ret) {
+ dev_err(dev,
+ "failed to get rx-burst-size-dword\n");
+ return ret;
+ }
+ platdata->flags |= CI_HDRC_OVERRIDE_RX_BURST;
+ }
+
return 0;
}
diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c
index 3869c6d75515..080b7be3daf0 100644
--- a/drivers/usb/chipidea/debug.c
+++ b/drivers/usb/chipidea/debug.c
@@ -67,9 +67,11 @@ static int ci_port_test_show(struct seq_file *s, void *data)
unsigned long flags;
unsigned mode;
+ pm_runtime_get_sync(ci->dev);
spin_lock_irqsave(&ci->lock, flags);
mode = hw_port_test_get(ci);
spin_unlock_irqrestore(&ci->lock, flags);
+ pm_runtime_put_sync(ci->dev);
seq_printf(s, "mode = %u\n", mode);
@@ -99,9 +101,11 @@ static ssize_t ci_port_test_write(struct file *file, const char __user *ubuf,
if (sscanf(buf, "%u", &mode) != 1)
return -EINVAL;
+ pm_runtime_get_sync(ci->dev);
spin_lock_irqsave(&ci->lock, flags);
ret = hw_port_test_set(ci, mode);
spin_unlock_irqrestore(&ci->lock, flags);
+ pm_runtime_put_sync(ci->dev);
return ret ? ret : count;
}
@@ -317,8 +321,10 @@ static ssize_t ci_role_write(struct file *file, const char __user *ubuf,
if (role == CI_ROLE_END || role == ci->role)
return -EINVAL;
+ pm_runtime_get_sync(ci->dev);
ci_role_stop(ci);
ret = ci_role_start(ci, role);
+ pm_runtime_put_sync(ci->dev);
return ret ? ret : count;
}
diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c
index 7161439def19..3d24304405b3 100644
--- a/drivers/usb/chipidea/host.c
+++ b/drivers/usb/chipidea/host.c
@@ -37,15 +37,14 @@ static int (*orig_bus_suspend)(struct usb_hcd *hcd);
struct ehci_ci_priv {
struct regulator *reg_vbus;
- struct ci_hdrc *ci;
};
static int ehci_ci_portpower(struct usb_hcd *hcd, int portnum, bool enable)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
struct ehci_ci_priv *priv = (struct ehci_ci_priv *)ehci->priv;
- struct ci_hdrc *ci = priv->ci;
struct device *dev = hcd->self.controller;
+ struct ci_hdrc *ci = dev_get_drvdata(dev);
int ret = 0;
int port = HCS_N_PORTS(ehci->hcs_params);
@@ -78,9 +77,25 @@ static int ehci_ci_portpower(struct usb_hcd *hcd, int portnum, bool enable)
return 0;
};
+static int ehci_ci_reset(struct usb_hcd *hcd)
+{
+ struct device *dev = hcd->self.controller;
+ struct ci_hdrc *ci = dev_get_drvdata(dev);
+ int ret;
+
+ ret = ehci_setup(hcd);
+ if (ret)
+ return ret;
+
+ ci_platform_configure(ci);
+
+ return ret;
+}
+
static const struct ehci_driver_overrides ehci_ci_overrides = {
.extra_priv_size = sizeof(struct ehci_ci_priv),
.port_power = ehci_ci_portpower,
+ .reset = ehci_ci_reset,
};
static irqreturn_t host_irq(struct ci_hdrc *ci)
@@ -123,7 +138,6 @@ static int host_start(struct ci_hdrc *ci)
priv = (struct ehci_ci_priv *)ehci->priv;
priv->reg_vbus = NULL;
- priv->ci = ci;
if (ci->platdata->reg_vbus && !ci_otg_is_fsm_mode(ci)) {
if (ci->platdata->flags & CI_HDRC_TURN_VBUS_EARLY_ON) {
@@ -153,12 +167,6 @@ static int host_start(struct ci_hdrc *ci)
}
}
- if (ci->platdata->flags & CI_HDRC_DISABLE_STREAMING)
- hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS);
-
- if (ci->platdata->flags & CI_HDRC_FORCE_FULLSPEED)
- hw_write(ci, OP_PORTSC, PORTSC_PFSC, PORTSC_PFSC);
-
return ret;
disable_reg:
diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c
index 19d655a743b5..00ab59d45da1 100644
--- a/drivers/usb/chipidea/otg_fsm.c
+++ b/drivers/usb/chipidea/otg_fsm.c
@@ -525,7 +525,6 @@ static int ci_otg_start_host(struct otg_fsm *fsm, int on)
ci_role_start(ci, CI_ROLE_HOST);
} else {
ci_role_stop(ci);
- hw_device_reset(ci);
ci_role_start(ci, CI_ROLE_GADGET);
}
return 0;
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index c592b6f0fe21..a637da25dda0 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -445,7 +445,7 @@ static int _hardware_enqueue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
rest -= count;
}
- if (hwreq->req.zero && hwreq->req.length
+ if (hwreq->req.zero && hwreq->req.length && hwep->dir == TX
&& (hwreq->req.length % hwep->ep.maxpacket == 0))
add_td_to_list(hwep, hwreq, 0);
@@ -1090,6 +1090,13 @@ __acquires(ci->lock)
if (ci_otg_is_fsm_mode(ci))
err = otg_a_alt_hnp_support(ci);
break;
+ case USB_DEVICE_A_HNP_SUPPORT:
+ if (ci_otg_is_fsm_mode(ci)) {
+ ci->gadget.a_hnp_support = 1;
+ err = isr_setup_status_phase(
+ ci);
+ }
+ break;
default:
goto delegate;
}
diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c
index 3cefd49ddb00..5ddab30ee240 100644
--- a/drivers/usb/chipidea/usbmisc_imx.c
+++ b/drivers/usb/chipidea/usbmisc_imx.c
@@ -54,6 +54,7 @@
#define MX53_USB_PHYCTRL1_PLLDIV_MASK 0x3
#define MX53_USB_PLL_DIV_24_MHZ 0x01
+#define MX6_BM_NON_BURST_SETTING BIT(1)
#define MX6_BM_OVER_CUR_DIS BIT(7)
#define MX6_BM_WAKEUP_ENABLE BIT(10)
#define MX6_BM_ID_WAKEUP BIT(16)
@@ -255,14 +256,21 @@ static int usbmisc_imx6q_init(struct imx_usbmisc_data *data)
if (data->index > 3)
return -EINVAL;
+ spin_lock_irqsave(&usbmisc->lock, flags);
+
if (data->disable_oc) {
- spin_lock_irqsave(&usbmisc->lock, flags);
reg = readl(usbmisc->base + data->index * 4);
writel(reg | MX6_BM_OVER_CUR_DIS,
usbmisc->base + data->index * 4);
- spin_unlock_irqrestore(&usbmisc->lock, flags);
}
+ /* SoC non-burst setting */
+ reg = readl(usbmisc->base + data->index * 4);
+ writel(reg | MX6_BM_NON_BURST_SETTING,
+ usbmisc->base + data->index * 4);
+
+ spin_unlock_irqrestore(&usbmisc->lock, flags);
+
usbmisc_imx6q_set_wakeup(data, false);
return 0;