113194f3bSVivek Gautam /* 213194f3bSVivek Gautam * SAMSUNG EXYNOS5 USB HOST XHCI Controller 313194f3bSVivek Gautam * 413194f3bSVivek Gautam * Copyright (C) 2012 Samsung Electronics Co.Ltd 513194f3bSVivek Gautam * Vivek Gautam <gautam.vivek@samsung.com> 613194f3bSVivek Gautam * Vikas Sajjan <vikas.sajjan@samsung.com> 713194f3bSVivek Gautam * 813194f3bSVivek Gautam * SPDX-License-Identifier: GPL-2.0+ 913194f3bSVivek Gautam */ 1013194f3bSVivek Gautam 1113194f3bSVivek Gautam /* 1213194f3bSVivek Gautam * This file is a conglomeration for DWC3-init sequence and further 1313194f3bSVivek Gautam * exynos5 specific PHY-init sequence. 1413194f3bSVivek Gautam */ 1513194f3bSVivek Gautam 1613194f3bSVivek Gautam #include <common.h> 1752e69357SSimon Glass #include <dm.h> 1813194f3bSVivek Gautam #include <fdtdec.h> 19*b08c8c48SMasahiro Yamada #include <linux/libfdt.h> 2013194f3bSVivek Gautam #include <malloc.h> 2113194f3bSVivek Gautam #include <usb.h> 2213194f3bSVivek Gautam #include <watchdog.h> 2313194f3bSVivek Gautam #include <asm/arch/cpu.h> 2413194f3bSVivek Gautam #include <asm/arch/power.h> 2513194f3bSVivek Gautam #include <asm/arch/xhci-exynos.h> 264a271cb1SJulius Werner #include <asm/gpio.h> 275d97dff0SMasahiro Yamada #include <linux/errno.h> 2813194f3bSVivek Gautam #include <linux/compat.h> 2913194f3bSVivek Gautam #include <linux/usb/dwc3.h> 3013194f3bSVivek Gautam 3113194f3bSVivek Gautam #include "xhci.h" 3213194f3bSVivek Gautam 3313194f3bSVivek Gautam /* Declare global data pointer */ 3413194f3bSVivek Gautam DECLARE_GLOBAL_DATA_PTR; 3513194f3bSVivek Gautam 3652e69357SSimon Glass struct exynos_xhci_platdata { 3752e69357SSimon Glass fdt_addr_t hcd_base; 3852e69357SSimon Glass fdt_addr_t phy_base; 3952e69357SSimon Glass struct gpio_desc vbus_gpio; 4052e69357SSimon Glass }; 4152e69357SSimon Glass 4213194f3bSVivek Gautam /** 4313194f3bSVivek Gautam * Contains pointers to register base addresses 4413194f3bSVivek Gautam * for the usb controller. 4513194f3bSVivek Gautam */ 4613194f3bSVivek Gautam struct exynos_xhci { 4752e69357SSimon Glass struct usb_platdata usb_plat; 4852e69357SSimon Glass struct xhci_ctrl ctrl; 4913194f3bSVivek Gautam struct exynos_usb3_phy *usb3_phy; 5013194f3bSVivek Gautam struct xhci_hccr *hcd; 5113194f3bSVivek Gautam struct dwc3 *dwc3_reg; 5213194f3bSVivek Gautam }; 5313194f3bSVivek Gautam 5452e69357SSimon Glass static int xhci_usb_ofdata_to_platdata(struct udevice *dev) 5552e69357SSimon Glass { 5652e69357SSimon Glass struct exynos_xhci_platdata *plat = dev_get_platdata(dev); 5752e69357SSimon Glass const void *blob = gd->fdt_blob; 5852e69357SSimon Glass unsigned int node; 5952e69357SSimon Glass int depth; 6052e69357SSimon Glass 6152e69357SSimon Glass /* 6252e69357SSimon Glass * Get the base address for XHCI controller from the device node 6352e69357SSimon Glass */ 64a821c4afSSimon Glass plat->hcd_base = devfdt_get_addr(dev); 6552e69357SSimon Glass if (plat->hcd_base == FDT_ADDR_T_NONE) { 6652e69357SSimon Glass debug("Can't get the XHCI register base address\n"); 6752e69357SSimon Glass return -ENXIO; 6852e69357SSimon Glass } 6952e69357SSimon Glass 7052e69357SSimon Glass depth = 0; 71e160f7d4SSimon Glass node = fdtdec_next_compatible_subnode(blob, dev_of_offset(dev), 7252e69357SSimon Glass COMPAT_SAMSUNG_EXYNOS5_USB3_PHY, &depth); 7352e69357SSimon Glass if (node <= 0) { 7452e69357SSimon Glass debug("XHCI: Can't get device node for usb3-phy controller\n"); 7552e69357SSimon Glass return -ENODEV; 7652e69357SSimon Glass } 7752e69357SSimon Glass 7852e69357SSimon Glass /* 7952e69357SSimon Glass * Get the base address for usbphy from the device node 8052e69357SSimon Glass */ 8152e69357SSimon Glass plat->phy_base = fdtdec_get_addr(blob, node, "reg"); 8252e69357SSimon Glass if (plat->phy_base == FDT_ADDR_T_NONE) { 8352e69357SSimon Glass debug("Can't get the usbphy register address\n"); 8452e69357SSimon Glass return -ENXIO; 8552e69357SSimon Glass } 8652e69357SSimon Glass 8752e69357SSimon Glass /* Vbus gpio */ 8852e69357SSimon Glass gpio_request_by_name(dev, "samsung,vbus-gpio", 0, 8952e69357SSimon Glass &plat->vbus_gpio, GPIOD_IS_OUT); 9052e69357SSimon Glass 9152e69357SSimon Glass return 0; 9252e69357SSimon Glass } 9313194f3bSVivek Gautam 9413194f3bSVivek Gautam static void exynos5_usb3_phy_init(struct exynos_usb3_phy *phy) 9513194f3bSVivek Gautam { 9613194f3bSVivek Gautam u32 reg; 9713194f3bSVivek Gautam 9813194f3bSVivek Gautam /* enabling usb_drd phy */ 9913194f3bSVivek Gautam set_usbdrd_phy_ctrl(POWER_USB_DRD_PHY_CTRL_EN); 10013194f3bSVivek Gautam 10113194f3bSVivek Gautam /* Reset USB 3.0 PHY */ 10213194f3bSVivek Gautam writel(0x0, &phy->phy_reg0); 10313194f3bSVivek Gautam 10413194f3bSVivek Gautam clrbits_le32(&phy->phy_param0, 10513194f3bSVivek Gautam /* Select PHY CLK source */ 10613194f3bSVivek Gautam PHYPARAM0_REF_USE_PAD | 10713194f3bSVivek Gautam /* Set Loss-of-Signal Detector sensitivity */ 10813194f3bSVivek Gautam PHYPARAM0_REF_LOSLEVEL_MASK); 10913194f3bSVivek Gautam setbits_le32(&phy->phy_param0, PHYPARAM0_REF_LOSLEVEL); 11013194f3bSVivek Gautam 11113194f3bSVivek Gautam writel(0x0, &phy->phy_resume); 11213194f3bSVivek Gautam 11313194f3bSVivek Gautam /* 11413194f3bSVivek Gautam * Setting the Frame length Adj value[6:1] to default 0x20 11513194f3bSVivek Gautam * See xHCI 1.0 spec, 5.2.4 11613194f3bSVivek Gautam */ 11713194f3bSVivek Gautam setbits_le32(&phy->link_system, 11813194f3bSVivek Gautam LINKSYSTEM_XHCI_VERSION_CONTROL | 11913194f3bSVivek Gautam LINKSYSTEM_FLADJ(0x20)); 12013194f3bSVivek Gautam 12113194f3bSVivek Gautam /* Set Tx De-Emphasis level */ 12213194f3bSVivek Gautam clrbits_le32(&phy->phy_param1, PHYPARAM1_PCS_TXDEEMPH_MASK); 12313194f3bSVivek Gautam setbits_le32(&phy->phy_param1, PHYPARAM1_PCS_TXDEEMPH); 12413194f3bSVivek Gautam 12513194f3bSVivek Gautam setbits_le32(&phy->phy_batchg, PHYBATCHG_UTMI_CLKSEL); 12613194f3bSVivek Gautam 12713194f3bSVivek Gautam /* PHYTEST POWERDOWN Control */ 12813194f3bSVivek Gautam clrbits_le32(&phy->phy_test, 12913194f3bSVivek Gautam PHYTEST_POWERDOWN_SSP | 13013194f3bSVivek Gautam PHYTEST_POWERDOWN_HSP); 13113194f3bSVivek Gautam 13213194f3bSVivek Gautam /* UTMI Power Control */ 13313194f3bSVivek Gautam writel(PHYUTMI_OTGDISABLE, &phy->phy_utmi); 13413194f3bSVivek Gautam 13513194f3bSVivek Gautam /* Use core clock from main PLL */ 13613194f3bSVivek Gautam reg = PHYCLKRST_REFCLKSEL_EXT_REFCLK | 13713194f3bSVivek Gautam /* Default 24Mhz crystal clock */ 13813194f3bSVivek Gautam PHYCLKRST_FSEL(FSEL_CLKSEL_24M) | 13913194f3bSVivek Gautam PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF | 14013194f3bSVivek Gautam PHYCLKRST_SSC_REFCLKSEL(0x88) | 14113194f3bSVivek Gautam /* Force PortReset of PHY */ 14213194f3bSVivek Gautam PHYCLKRST_PORTRESET | 14313194f3bSVivek Gautam /* Digital power supply in normal operating mode */ 14413194f3bSVivek Gautam PHYCLKRST_RETENABLEN | 14513194f3bSVivek Gautam /* Enable ref clock for SS function */ 14613194f3bSVivek Gautam PHYCLKRST_REF_SSP_EN | 14713194f3bSVivek Gautam /* Enable spread spectrum */ 14813194f3bSVivek Gautam PHYCLKRST_SSC_EN | 14913194f3bSVivek Gautam /* Power down HS Bias and PLL blocks in suspend mode */ 15013194f3bSVivek Gautam PHYCLKRST_COMMONONN; 15113194f3bSVivek Gautam 15213194f3bSVivek Gautam writel(reg, &phy->phy_clk_rst); 15313194f3bSVivek Gautam 15413194f3bSVivek Gautam /* giving time to Phy clock to settle before resetting */ 15513194f3bSVivek Gautam udelay(10); 15613194f3bSVivek Gautam 15713194f3bSVivek Gautam reg &= ~PHYCLKRST_PORTRESET; 15813194f3bSVivek Gautam writel(reg, &phy->phy_clk_rst); 15913194f3bSVivek Gautam } 16013194f3bSVivek Gautam 16113194f3bSVivek Gautam static void exynos5_usb3_phy_exit(struct exynos_usb3_phy *phy) 16213194f3bSVivek Gautam { 16313194f3bSVivek Gautam setbits_le32(&phy->phy_utmi, 16413194f3bSVivek Gautam PHYUTMI_OTGDISABLE | 16513194f3bSVivek Gautam PHYUTMI_FORCESUSPEND | 16613194f3bSVivek Gautam PHYUTMI_FORCESLEEP); 16713194f3bSVivek Gautam 16813194f3bSVivek Gautam clrbits_le32(&phy->phy_clk_rst, 16913194f3bSVivek Gautam PHYCLKRST_REF_SSP_EN | 17013194f3bSVivek Gautam PHYCLKRST_SSC_EN | 17113194f3bSVivek Gautam PHYCLKRST_COMMONONN); 17213194f3bSVivek Gautam 17313194f3bSVivek Gautam /* PHYTEST POWERDOWN Control to remove leakage current */ 17413194f3bSVivek Gautam setbits_le32(&phy->phy_test, 17513194f3bSVivek Gautam PHYTEST_POWERDOWN_SSP | 17613194f3bSVivek Gautam PHYTEST_POWERDOWN_HSP); 17713194f3bSVivek Gautam 17813194f3bSVivek Gautam /* disabling usb_drd phy */ 17913194f3bSVivek Gautam set_usbdrd_phy_ctrl(POWER_USB_DRD_PHY_CTRL_DISABLE); 18013194f3bSVivek Gautam } 18113194f3bSVivek Gautam 18213194f3bSVivek Gautam static int exynos_xhci_core_init(struct exynos_xhci *exynos) 18313194f3bSVivek Gautam { 18413194f3bSVivek Gautam int ret; 18513194f3bSVivek Gautam 18613194f3bSVivek Gautam exynos5_usb3_phy_init(exynos->usb3_phy); 18713194f3bSVivek Gautam 18813194f3bSVivek Gautam ret = dwc3_core_init(exynos->dwc3_reg); 18913194f3bSVivek Gautam if (ret) { 19013194f3bSVivek Gautam debug("failed to initialize core\n"); 19113194f3bSVivek Gautam return -EINVAL; 19213194f3bSVivek Gautam } 19313194f3bSVivek Gautam 19413194f3bSVivek Gautam /* We are hard-coding DWC3 core to Host Mode */ 19513194f3bSVivek Gautam dwc3_set_mode(exynos->dwc3_reg, DWC3_GCTL_PRTCAP_HOST); 19613194f3bSVivek Gautam 19713194f3bSVivek Gautam return 0; 19813194f3bSVivek Gautam } 19913194f3bSVivek Gautam 20013194f3bSVivek Gautam static void exynos_xhci_core_exit(struct exynos_xhci *exynos) 20113194f3bSVivek Gautam { 20213194f3bSVivek Gautam exynos5_usb3_phy_exit(exynos->usb3_phy); 20313194f3bSVivek Gautam } 20413194f3bSVivek Gautam 20552e69357SSimon Glass static int xhci_usb_probe(struct udevice *dev) 20652e69357SSimon Glass { 20752e69357SSimon Glass struct exynos_xhci_platdata *plat = dev_get_platdata(dev); 20852e69357SSimon Glass struct exynos_xhci *ctx = dev_get_priv(dev); 20952e69357SSimon Glass struct xhci_hcor *hcor; 21052e69357SSimon Glass int ret; 21152e69357SSimon Glass 21252e69357SSimon Glass ctx->hcd = (struct xhci_hccr *)plat->hcd_base; 21352e69357SSimon Glass ctx->usb3_phy = (struct exynos_usb3_phy *)plat->phy_base; 21452e69357SSimon Glass ctx->dwc3_reg = (struct dwc3 *)((char *)(ctx->hcd) + DWC3_REG_OFFSET); 21552e69357SSimon Glass hcor = (struct xhci_hcor *)((uint32_t)ctx->hcd + 21652e69357SSimon Glass HC_LENGTH(xhci_readl(&ctx->hcd->cr_capbase))); 21752e69357SSimon Glass 21852e69357SSimon Glass /* setup the Vbus gpio here */ 21952e69357SSimon Glass if (dm_gpio_is_valid(&plat->vbus_gpio)) 22052e69357SSimon Glass dm_gpio_set_value(&plat->vbus_gpio, 1); 22152e69357SSimon Glass 22252e69357SSimon Glass ret = exynos_xhci_core_init(ctx); 22352e69357SSimon Glass if (ret) { 22452e69357SSimon Glass puts("XHCI: failed to initialize controller\n"); 22552e69357SSimon Glass return -EINVAL; 22652e69357SSimon Glass } 22752e69357SSimon Glass 22852e69357SSimon Glass return xhci_register(dev, ctx->hcd, hcor); 22952e69357SSimon Glass } 23052e69357SSimon Glass 23152e69357SSimon Glass static int xhci_usb_remove(struct udevice *dev) 23252e69357SSimon Glass { 23352e69357SSimon Glass struct exynos_xhci *ctx = dev_get_priv(dev); 23452e69357SSimon Glass int ret; 23552e69357SSimon Glass 23652e69357SSimon Glass ret = xhci_deregister(dev); 23752e69357SSimon Glass if (ret) 23852e69357SSimon Glass return ret; 23952e69357SSimon Glass exynos_xhci_core_exit(ctx); 24052e69357SSimon Glass 24152e69357SSimon Glass return 0; 24252e69357SSimon Glass } 24352e69357SSimon Glass 24452e69357SSimon Glass static const struct udevice_id xhci_usb_ids[] = { 24552e69357SSimon Glass { .compatible = "samsung,exynos5250-xhci" }, 24652e69357SSimon Glass { } 24752e69357SSimon Glass }; 24852e69357SSimon Glass 24952e69357SSimon Glass U_BOOT_DRIVER(usb_xhci) = { 25052e69357SSimon Glass .name = "xhci_exynos", 25152e69357SSimon Glass .id = UCLASS_USB, 25252e69357SSimon Glass .of_match = xhci_usb_ids, 25352e69357SSimon Glass .ofdata_to_platdata = xhci_usb_ofdata_to_platdata, 25452e69357SSimon Glass .probe = xhci_usb_probe, 25552e69357SSimon Glass .remove = xhci_usb_remove, 25652e69357SSimon Glass .ops = &xhci_usb_ops, 25752e69357SSimon Glass .platdata_auto_alloc_size = sizeof(struct exynos_xhci_platdata), 25852e69357SSimon Glass .priv_auto_alloc_size = sizeof(struct exynos_xhci), 25952e69357SSimon Glass .flags = DM_FLAG_ALLOC_PRIV_DMA, 26052e69357SSimon Glass }; 261