diff options
author | Stefano Babic <sbabic@denx.de> | 2015-07-10 09:21:44 +0200 |
---|---|---|
committer | Stefano Babic <sbabic@denx.de> | 2015-07-10 09:21:44 +0200 |
commit | 1254ff97abb7606ccd0d7bdcd9f22581c50fe535 (patch) | |
tree | 61b31e61173154abd38aaa6584e84ea77314b861 /drivers/usb | |
parent | 54e0f96f764f662be186baae7d6c2c97423bc29d (diff) | |
parent | f3edfd30541d6f245d7dfa6fa7354cc916cc53e1 (diff) |
Merge branch 'master' of git://git.denx.de/u-boot
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/dwc3/Makefile | 1 | ||||
-rw-r--r-- | drivers/usb/dwc3/samsung_usb_phy.c | 78 | ||||
-rw-r--r-- | drivers/usb/gadget/f_mass_storage.c | 2 | ||||
-rw-r--r-- | drivers/usb/host/ehci-fsl.c | 2 | ||||
-rw-r--r-- | drivers/usb/host/ehci-hcd.c | 26 | ||||
-rw-r--r-- | drivers/usb/musb-new/sunxi.c | 80 |
6 files changed, 128 insertions, 61 deletions
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile index e455a5279c..02bb216db7 100644 --- a/drivers/usb/dwc3/Makefile +++ b/drivers/usb/dwc3/Makefile @@ -6,3 +6,4 @@ dwc3-y += gadget.o ep0.o obj-$(CONFIG_USB_DWC3_OMAP) += dwc3-omap.o obj-$(CONFIG_USB_DWC3_PHY_OMAP) += ti_usb_phy.o +obj-$(CONFIG_USB_DWC3_PHY_SAMSUNG) += samsung_usb_phy.o diff --git a/drivers/usb/dwc3/samsung_usb_phy.c b/drivers/usb/dwc3/samsung_usb_phy.c new file mode 100644 index 0000000000..4220986548 --- /dev/null +++ b/drivers/usb/dwc3/samsung_usb_phy.c @@ -0,0 +1,78 @@ +/** + * samsung_usb_phy.c - DesignWare USB3 (DWC3) PHY handling file + * + * Copyright (C) 2015 Samsung Electronics + * + * Author: Joonyoung Shim <jy0922.shim@samsung.com> + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <common.h> +#include <asm/arch/power.h> +#include <asm/arch/xhci-exynos.h> + +void exynos5_usb3_phy_init(struct exynos_usb3_phy *phy) +{ + u32 reg; + + /* Reset USB 3.0 PHY */ + writel(0x0, &phy->phy_reg0); + + clrbits_le32(&phy->phy_param0, + /* Select PHY CLK source */ + PHYPARAM0_REF_USE_PAD | + /* Set Loss-of-Signal Detector sensitivity */ + PHYPARAM0_REF_LOSLEVEL_MASK); + setbits_le32(&phy->phy_param0, PHYPARAM0_REF_LOSLEVEL); + + + writel(0x0, &phy->phy_resume); + + /* + * Setting the Frame length Adj value[6:1] to default 0x20 + * See xHCI 1.0 spec, 5.2.4 + */ + setbits_le32(&phy->link_system, + LINKSYSTEM_XHCI_VERSION_CONTROL | + LINKSYSTEM_FLADJ(0x20)); + + /* Set Tx De-Emphasis level */ + clrbits_le32(&phy->phy_param1, PHYPARAM1_PCS_TXDEEMPH_MASK); + setbits_le32(&phy->phy_param1, PHYPARAM1_PCS_TXDEEMPH); + + setbits_le32(&phy->phy_batchg, PHYBATCHG_UTMI_CLKSEL); + + /* PHYTEST POWERDOWN Control */ + clrbits_le32(&phy->phy_test, + PHYTEST_POWERDOWN_SSP | + PHYTEST_POWERDOWN_HSP); + + /* UTMI Power Control */ + writel(PHYUTMI_OTGDISABLE, &phy->phy_utmi); + + /* Use core clock from main PLL */ + reg = PHYCLKRST_REFCLKSEL_EXT_REFCLK | + /* Default 24Mhz crystal clock */ + PHYCLKRST_FSEL(FSEL_CLKSEL_24M) | + PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF | + PHYCLKRST_SSC_REFCLKSEL(0) | + /* Force PortReset of PHY */ + PHYCLKRST_PORTRESET | + /* Digital power supply in normal operating mode */ + PHYCLKRST_RETENABLEN | + /* Enable ref clock for SS function */ + PHYCLKRST_REF_SSP_EN | + /* Enable spread spectrum */ + PHYCLKRST_SSC_EN | + /* Power down HS Bias and PLL blocks in suspend mode */ + PHYCLKRST_COMMONONN; + + writel(reg, &phy->phy_clk_rst); + + /* giving time to Phy clock to settle before resetting */ + udelay(10); + + reg &= ~PHYCLKRST_PORTRESET; + writel(reg, &phy->phy_clk_rst); +} diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index d1bc5efa9b..abe9391d3d 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -671,7 +671,7 @@ static int sleep_thread(struct fsg_common *common) if (common->thread_wakeup_needed) break; - if (++i == 50000) { + if (++i == 20000) { busy_indicator(); i = 0; k++; diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 5fd618df87..97b7f14542 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -76,7 +76,7 @@ int ehci_hcd_init(int index, enum usb_init_type init, break; default: printf("ERROR: wrong controller index!!\n"); - break; + return -EINVAL; }; *hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength); diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 1e5a6e2b20..bf02221c9f 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -1214,6 +1214,7 @@ static int _ehci_submit_control_msg(struct usb_device *dev, unsigned long pipe, struct int_queue { int elementsize; + unsigned long pipe; struct QH *first; struct QH *current; struct QH *last; @@ -1269,7 +1270,7 @@ static struct int_queue *_ehci_create_int_queue(struct usb_device *dev, { struct ehci_ctrl *ctrl = ehci_get_ctrl(dev); struct int_queue *result = NULL; - int i; + uint32_t i, toggle; /* * Interrupt transfers requiring several transactions are not supported @@ -1309,6 +1310,7 @@ static struct int_queue *_ehci_create_int_queue(struct usb_device *dev, goto fail1; } result->elementsize = elementsize; + result->pipe = pipe; result->first = memalign(USB_DMA_MINALIGN, sizeof(struct QH) * queuesize); if (!result->first) { @@ -1326,6 +1328,8 @@ static struct int_queue *_ehci_create_int_queue(struct usb_device *dev, memset(result->first, 0, sizeof(struct QH) * queuesize); memset(result->tds, 0, sizeof(struct qTD) * queuesize); + toggle = usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); + for (i = 0; i < queuesize; i++) { struct QH *qh = result->first + i; struct qTD *td = result->tds + i; @@ -1357,7 +1361,9 @@ static struct int_queue *_ehci_create_int_queue(struct usb_device *dev, td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); debug("communication direction is '%s'\n", usb_pipein(pipe) ? "in" : "out"); - td->qt_token = cpu_to_hc32((elementsize << 16) | + td->qt_token = cpu_to_hc32( + QT_TOKEN_DT(toggle) | + (elementsize << 16) | ((usb_pipein(pipe) ? 1 : 0) << 8) | /* IN/OUT token */ 0x80); /* active */ td->qt_buffer[0] = @@ -1372,6 +1378,7 @@ static struct int_queue *_ehci_create_int_queue(struct usb_device *dev, cpu_to_hc32((td->qt_buffer[0] + 0x4000) & ~0xfff); *buf = buffer + i * elementsize; + toggle ^= 1; } flush_dcache_range((unsigned long)buffer, @@ -1426,6 +1433,8 @@ static void *_ehci_poll_int_queue(struct usb_device *dev, { struct QH *cur = queue->current; struct qTD *cur_td; + uint32_t token, toggle; + unsigned long pipe = queue->pipe; /* depleted queue */ if (cur == NULL) { @@ -1436,12 +1445,15 @@ static void *_ehci_poll_int_queue(struct usb_device *dev, cur_td = &queue->tds[queue->current - queue->first]; invalidate_dcache_range((unsigned long)cur_td, ALIGN_END_ADDR(struct qTD, cur_td, 1)); - if (QT_TOKEN_GET_STATUS(hc32_to_cpu(cur_td->qt_token)) & - QT_TOKEN_STATUS_ACTIVE) { - debug("Exit poll_int_queue with no completed intr transfer. token is %x\n", - hc32_to_cpu(cur_td->qt_token)); + token = hc32_to_cpu(cur_td->qt_token); + if (QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_ACTIVE) { + debug("Exit poll_int_queue with no completed intr transfer. token is %x\n", token); return NULL; } + + toggle = QT_TOKEN_GET_DT(token); + usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), toggle); + if (!(cur->qh_link & QH_LINK_TERMINATE)) queue->current++; else @@ -1452,7 +1464,7 @@ static void *_ehci_poll_int_queue(struct usb_device *dev, queue->elementsize)); debug("Exit poll_int_queue with completed intr transfer. token is %x at %p (first at %p)\n", - hc32_to_cpu(cur_td->qt_token), cur, queue->first); + token, cur, queue->first); return cur->buffer; } diff --git a/drivers/usb/musb-new/sunxi.c b/drivers/usb/musb-new/sunxi.c index e8a3a23aa4..052e0657d0 100644 --- a/drivers/usb/musb-new/sunxi.c +++ b/drivers/usb/musb-new/sunxi.c @@ -105,16 +105,6 @@ static void USBC_EnableIdPullUp(__iomem void *base) musb_writel(base, USBC_REG_o_ISCR, reg_val); } -static void USBC_DisableIdPullUp(__iomem void *base) -{ - u32 reg_val; - - reg_val = musb_readl(base, USBC_REG_o_ISCR); - reg_val &= ~(1 << USBC_BP_ISCR_ID_PULLUP_EN); - reg_val = USBC_WakeUp_ClearChangeDetect(reg_val); - musb_writel(base, USBC_REG_o_ISCR, reg_val); -} - static void USBC_EnableDpDmPullUp(__iomem void *base) { u32 reg_val; @@ -125,34 +115,35 @@ static void USBC_EnableDpDmPullUp(__iomem void *base) musb_writel(base, USBC_REG_o_ISCR, reg_val); } -static void USBC_DisableDpDmPullUp(__iomem void *base) +static void USBC_ForceIdToLow(__iomem void *base) { u32 reg_val; reg_val = musb_readl(base, USBC_REG_o_ISCR); - reg_val &= ~(1 << USBC_BP_ISCR_DPDM_PULLUP_EN); + reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_ID); + reg_val |= (0x02 << USBC_BP_ISCR_FORCE_ID); reg_val = USBC_WakeUp_ClearChangeDetect(reg_val); musb_writel(base, USBC_REG_o_ISCR, reg_val); } -static void USBC_ForceIdToLow(__iomem void *base) +static void USBC_ForceIdToHigh(__iomem void *base) { u32 reg_val; reg_val = musb_readl(base, USBC_REG_o_ISCR); reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_ID); - reg_val |= (0x02 << USBC_BP_ISCR_FORCE_ID); + reg_val |= (0x03 << USBC_BP_ISCR_FORCE_ID); reg_val = USBC_WakeUp_ClearChangeDetect(reg_val); musb_writel(base, USBC_REG_o_ISCR, reg_val); } -static void USBC_ForceIdToHigh(__iomem void *base) +static void USBC_ForceVbusValidToLow(__iomem void *base) { u32 reg_val; reg_val = musb_readl(base, USBC_REG_o_ISCR); - reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_ID); - reg_val |= (0x03 << USBC_BP_ISCR_FORCE_ID); + reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID); + reg_val |= (0x02 << USBC_BP_ISCR_FORCE_VBUS_VALID); reg_val = USBC_WakeUp_ClearChangeDetect(reg_val); musb_writel(base, USBC_REG_o_ISCR, reg_val); } @@ -205,42 +196,41 @@ static irqreturn_t sunxi_musb_interrupt(int irq, void *__hci) return retval; } +/* musb_core does not call enable / disable in a balanced manner <sigh> */ +static bool enabled = false; + static void sunxi_musb_enable(struct musb *musb) { pr_debug("%s():\n", __func__); + if (enabled) + return; + /* select PIO mode */ musb_writeb(musb->mregs, USBC_REG_o_VEND0, 0); - if (is_host_enabled(musb)) { - /* port power on */ - sunxi_usb_phy_power_on(0); - } + if (is_host_enabled(musb)) + sunxi_usb_phy_power_on(0); /* port power on */ + + USBC_ForceVbusValidToHigh(musb->mregs); + + enabled = true; } static void sunxi_musb_disable(struct musb *musb) { - struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; - pr_debug("%s():\n", __func__); - /* Put the controller back in a pristane state for "usb reset" */ - if (musb->is_active) { - sunxi_usb_phy_exit(0); -#ifdef CONFIG_SUNXI_GEN_SUN6I - clrbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_GATE_OFFSET_USB0); -#endif - clrbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_USB0); + if (!enabled) + return; - mdelay(10); + if (is_host_enabled(musb)) + sunxi_usb_phy_power_off(0); /* port power off */ - setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_USB0); -#ifdef CONFIG_SUNXI_GEN_SUN6I - setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_GATE_OFFSET_USB0); -#endif - sunxi_usb_phy_init(0); - musb->is_active = 0; - } + USBC_ForceVbusValidToLow(musb->mregs); + mdelay(200); /* Wait for the current session to timeout */ + + enabled = false; } static int sunxi_musb_init(struct musb *musb) @@ -282,22 +272,8 @@ static int sunxi_musb_init(struct musb *musb) return 0; } -static int sunxi_musb_exit(struct musb *musb) -{ - pr_debug("%s():\n", __func__); - - USBC_DisableDpDmPullUp(musb->mregs); - USBC_DisableIdPullUp(musb->mregs); - sunxi_usb_phy_power_off(0); - sunxi_usb_phy_exit(0); - - return 0; -} - const struct musb_platform_ops sunxi_musb_ops = { .init = sunxi_musb_init, - .exit = sunxi_musb_exit, - .enable = sunxi_musb_enable, .disable = sunxi_musb_disable, }; |