1ba55453cSDan Murphy /* 2ba55453cSDan Murphy * OMAP USB PHY Support 3ba55453cSDan Murphy * 4ba55453cSDan Murphy * (C) Copyright 2013 5ba55453cSDan Murphy * Texas Instruments, <www.ti.com> 6ba55453cSDan Murphy * 7ba55453cSDan Murphy * Author: Dan Murphy <dmurphy@ti.com> 8ba55453cSDan Murphy * 9ba55453cSDan Murphy * SPDX-License-Identifier: GPL-2.0+ 10ba55453cSDan Murphy */ 11ba55453cSDan Murphy 12ba55453cSDan Murphy #include <common.h> 13ba55453cSDan Murphy #include <usb.h> 14ba55453cSDan Murphy #include <asm-generic/errno.h> 15ba55453cSDan Murphy #include <asm/omap_common.h> 16ba55453cSDan Murphy #include <asm/arch/cpu.h> 17ba55453cSDan Murphy #include <asm/arch/sys_proto.h> 18ba55453cSDan Murphy 19ba55453cSDan Murphy #include <linux/compat.h> 20ba55453cSDan Murphy #include <linux/usb/dwc3.h> 21ba55453cSDan Murphy #include <linux/usb/xhci-omap.h> 22ba55453cSDan Murphy 23ba55453cSDan Murphy #include "../host/xhci.h" 24ba55453cSDan Murphy 25834e91afSDan Murphy #ifdef CONFIG_OMAP_USB3PHY1_HOST 26*68a775a7SRoger Quadros struct usb3_dpll_params { 27ba55453cSDan Murphy u16 m; 28ba55453cSDan Murphy u8 n; 29ba55453cSDan Murphy u8 freq:3; 30ba55453cSDan Murphy u8 sd; 31ba55453cSDan Murphy u32 mf; 32ba55453cSDan Murphy }; 33ba55453cSDan Murphy 34*68a775a7SRoger Quadros struct usb3_dpll_map { 35*68a775a7SRoger Quadros unsigned long rate; 36*68a775a7SRoger Quadros struct usb3_dpll_params params; 37*68a775a7SRoger Quadros struct usb3_dpll_map *dpll_map; 38ba55453cSDan Murphy }; 39ba55453cSDan Murphy 40*68a775a7SRoger Quadros static struct usb3_dpll_map dpll_map_usb[] = { 41*68a775a7SRoger Quadros {12000000, {1250, 5, 4, 20, 0} }, /* 12 MHz */ 42*68a775a7SRoger Quadros {16800000, {3125, 20, 4, 20, 0} }, /* 16.8 MHz */ 43*68a775a7SRoger Quadros {19200000, {1172, 8, 4, 20, 65537} }, /* 19.2 MHz */ 44*68a775a7SRoger Quadros {20000000, {1000, 7, 4, 10, 0} }, /* 20 MHz */ 45*68a775a7SRoger Quadros {26000000, {1250, 12, 4, 20, 0} }, /* 26 MHz */ 46*68a775a7SRoger Quadros {38400000, {3125, 47, 4, 20, 92843} }, /* 38.4 MHz */ 47*68a775a7SRoger Quadros { }, /* Terminator */ 48*68a775a7SRoger Quadros }; 49*68a775a7SRoger Quadros 50*68a775a7SRoger Quadros static struct usb3_dpll_params *omap_usb3_get_dpll_params(void) 51*68a775a7SRoger Quadros { 52*68a775a7SRoger Quadros unsigned long rate; 53*68a775a7SRoger Quadros struct usb3_dpll_map *dpll_map = dpll_map_usb; 54*68a775a7SRoger Quadros 55*68a775a7SRoger Quadros rate = get_sys_clk_freq(); 56*68a775a7SRoger Quadros 57*68a775a7SRoger Quadros for (; dpll_map->rate; dpll_map++) { 58*68a775a7SRoger Quadros if (rate == dpll_map->rate) 59*68a775a7SRoger Quadros return &dpll_map->params; 60*68a775a7SRoger Quadros } 61*68a775a7SRoger Quadros 62*68a775a7SRoger Quadros dev_err(phy->dev, "No DPLL configuration for %lu Hz SYS CLK\n", rate); 63*68a775a7SRoger Quadros 64*68a775a7SRoger Quadros return NULL; 65*68a775a7SRoger Quadros } 66*68a775a7SRoger Quadros 67ba55453cSDan Murphy static void omap_usb_dpll_relock(struct omap_usb3_phy *phy_regs) 68ba55453cSDan Murphy { 69ba55453cSDan Murphy u32 val; 70ba55453cSDan Murphy 71ba55453cSDan Murphy writel(SET_PLL_GO, &phy_regs->pll_go); 72ba55453cSDan Murphy do { 73ba55453cSDan Murphy val = readl(&phy_regs->pll_status); 74ba55453cSDan Murphy if (val & PLL_LOCK) 75ba55453cSDan Murphy break; 76ba55453cSDan Murphy } while (1); 77ba55453cSDan Murphy } 78ba55453cSDan Murphy 79ba55453cSDan Murphy static void omap_usb_dpll_lock(struct omap_usb3_phy *phy_regs) 80ba55453cSDan Murphy { 81*68a775a7SRoger Quadros struct usb3_dpll_params *dpll_params; 82ba55453cSDan Murphy u32 val; 83ba55453cSDan Murphy 84*68a775a7SRoger Quadros dpll_params = omap_usb3_get_dpll_params(); 85*68a775a7SRoger Quadros if (!dpll_params) 86*68a775a7SRoger Quadros return; 87*68a775a7SRoger Quadros 88ba55453cSDan Murphy val = readl(&phy_regs->pll_config_1); 89ba55453cSDan Murphy val &= ~PLL_REGN_MASK; 90*68a775a7SRoger Quadros val |= dpll_params->n << PLL_REGN_SHIFT; 91ba55453cSDan Murphy writel(val, &phy_regs->pll_config_1); 92ba55453cSDan Murphy 93ba55453cSDan Murphy val = readl(&phy_regs->pll_config_2); 94ba55453cSDan Murphy val &= ~PLL_SELFREQDCO_MASK; 95*68a775a7SRoger Quadros val |= dpll_params->freq << PLL_SELFREQDCO_SHIFT; 96ba55453cSDan Murphy writel(val, &phy_regs->pll_config_2); 97ba55453cSDan Murphy 98ba55453cSDan Murphy val = readl(&phy_regs->pll_config_1); 99ba55453cSDan Murphy val &= ~PLL_REGM_MASK; 100*68a775a7SRoger Quadros val |= dpll_params->m << PLL_REGM_SHIFT; 101ba55453cSDan Murphy writel(val, &phy_regs->pll_config_1); 102ba55453cSDan Murphy 103ba55453cSDan Murphy val = readl(&phy_regs->pll_config_4); 104ba55453cSDan Murphy val &= ~PLL_REGM_F_MASK; 105*68a775a7SRoger Quadros val |= dpll_params->mf << PLL_REGM_F_SHIFT; 106ba55453cSDan Murphy writel(val, &phy_regs->pll_config_4); 107ba55453cSDan Murphy 108ba55453cSDan Murphy val = readl(&phy_regs->pll_config_3); 109ba55453cSDan Murphy val &= ~PLL_SD_MASK; 110*68a775a7SRoger Quadros val |= dpll_params->sd << PLL_SD_SHIFT; 111ba55453cSDan Murphy writel(val, &phy_regs->pll_config_3); 112ba55453cSDan Murphy 113ba55453cSDan Murphy omap_usb_dpll_relock(phy_regs); 114ba55453cSDan Murphy } 115ba55453cSDan Murphy 116ba55453cSDan Murphy static void usb3_phy_partial_powerup(struct omap_usb3_phy *phy_regs) 117ba55453cSDan Murphy { 118ba55453cSDan Murphy u32 rate = get_sys_clk_freq()/1000000; 119ba55453cSDan Murphy u32 val; 120ba55453cSDan Murphy 121ba55453cSDan Murphy val = readl((*ctrl)->control_phy_power_usb); 122ba55453cSDan Murphy val &= ~(USB3_PWRCTL_CLK_CMD_MASK | USB3_PWRCTL_CLK_FREQ_MASK); 123ba55453cSDan Murphy val |= (USB3_PHY_PARTIAL_RX_POWERON | USB3_PHY_TX_RX_POWERON); 124ba55453cSDan Murphy val |= rate << USB3_PWRCTL_CLK_FREQ_SHIFT; 125ba55453cSDan Murphy 126ba55453cSDan Murphy writel(val, (*ctrl)->control_phy_power_usb); 127ba55453cSDan Murphy } 128ba55453cSDan Murphy 129834e91afSDan Murphy void usb_phy_power(int on) 130ba55453cSDan Murphy { 131ba55453cSDan Murphy u32 val; 132ba55453cSDan Murphy 133ba55453cSDan Murphy val = readl((*ctrl)->control_phy_power_usb); 134ba55453cSDan Murphy if (on) { 135ba55453cSDan Murphy val &= ~USB3_PWRCTL_CLK_CMD_MASK; 136ba55453cSDan Murphy val |= USB3_PHY_TX_RX_POWERON; 137ba55453cSDan Murphy } else { 138ba55453cSDan Murphy val &= (~USB3_PWRCTL_CLK_CMD_MASK & ~USB3_PHY_TX_RX_POWERON); 139ba55453cSDan Murphy } 140ba55453cSDan Murphy 141ba55453cSDan Murphy writel(val, (*ctrl)->control_phy_power_usb); 142ba55453cSDan Murphy } 143ba55453cSDan Murphy 144ba55453cSDan Murphy void omap_usb3_phy_init(struct omap_usb3_phy *phy_regs) 145ba55453cSDan Murphy { 146ba55453cSDan Murphy omap_usb_dpll_lock(phy_regs); 147ba55453cSDan Murphy usb3_phy_partial_powerup(phy_regs); 148ba55453cSDan Murphy /* 149ba55453cSDan Murphy * Give enough time for the PHY to partially power-up before 150ba55453cSDan Murphy * powering it up completely. delay value suggested by the HW 151ba55453cSDan Murphy * team. 152ba55453cSDan Murphy */ 153ba55453cSDan Murphy mdelay(100); 154ba55453cSDan Murphy } 155ba55453cSDan Murphy 156834e91afSDan Murphy static void omap_enable_usb3_phy(struct omap_xhci *omap) 157ba55453cSDan Murphy { 158ba55453cSDan Murphy u32 val; 159ba55453cSDan Murphy 160ba55453cSDan Murphy val = (USBOTGSS_DMADISABLE | 161ba55453cSDan Murphy USBOTGSS_STANDBYMODE_SMRT_WKUP | 162ba55453cSDan Murphy USBOTGSS_IDLEMODE_NOIDLE); 163ba55453cSDan Murphy writel(val, &omap->otg_wrapper->sysconfig); 164ba55453cSDan Murphy 165ba55453cSDan Murphy /* Clear the utmi OTG status */ 166ba55453cSDan Murphy val = readl(&omap->otg_wrapper->utmi_otg_status); 167ba55453cSDan Murphy writel(val, &omap->otg_wrapper->utmi_otg_status); 168ba55453cSDan Murphy 169ba55453cSDan Murphy /* Enable interrupts */ 170ba55453cSDan Murphy writel(USBOTGSS_COREIRQ_EN, &omap->otg_wrapper->irqenable_set_0); 171ba55453cSDan Murphy val = (USBOTGSS_IRQ_SET_1_IDPULLUP_FALL_EN | 172ba55453cSDan Murphy USBOTGSS_IRQ_SET_1_DISCHRGVBUS_FALL_EN | 173ba55453cSDan Murphy USBOTGSS_IRQ_SET_1_CHRGVBUS_FALL_EN | 174ba55453cSDan Murphy USBOTGSS_IRQ_SET_1_DRVVBUS_FALL_EN | 175ba55453cSDan Murphy USBOTGSS_IRQ_SET_1_IDPULLUP_RISE_EN | 176ba55453cSDan Murphy USBOTGSS_IRQ_SET_1_DISCHRGVBUS_RISE_EN | 177ba55453cSDan Murphy USBOTGSS_IRQ_SET_1_CHRGVBUS_RISE_EN | 178ba55453cSDan Murphy USBOTGSS_IRQ_SET_1_DRVVBUS_RISE_EN | 179ba55453cSDan Murphy USBOTGSS_IRQ_SET_1_OEVT_EN); 180ba55453cSDan Murphy writel(val, &omap->otg_wrapper->irqenable_set_1); 181ba55453cSDan Murphy 182ba55453cSDan Murphy /* Clear the IRQ status */ 183ba55453cSDan Murphy val = readl(&omap->otg_wrapper->irqstatus_1); 184ba55453cSDan Murphy writel(val, &omap->otg_wrapper->irqstatus_1); 185ba55453cSDan Murphy val = readl(&omap->otg_wrapper->irqstatus_0); 186ba55453cSDan Murphy writel(val, &omap->otg_wrapper->irqstatus_0); 187ba55453cSDan Murphy }; 188834e91afSDan Murphy #endif /* CONFIG_OMAP_USB3PHY1_HOST */ 189834e91afSDan Murphy 190834e91afSDan Murphy #ifdef CONFIG_OMAP_USB2PHY2_HOST 191834e91afSDan Murphy static void omap_enable_usb2_phy2(struct omap_xhci *omap) 192834e91afSDan Murphy { 193834e91afSDan Murphy u32 reg, val; 194834e91afSDan Murphy 195834e91afSDan Murphy val = (~USB2PHY_AUTORESUME_EN & USB2PHY_DISCHGDET); 196834e91afSDan Murphy writel(val, (*ctrl)->control_srcomp_north_side); 197834e91afSDan Murphy 198834e91afSDan Murphy setbits_le32((*prcm)->cm_coreaon_usb_phy2_core_clkctrl, 199834e91afSDan Murphy USBPHY_CORE_CLKCTRL_OPTFCLKEN_CLK32K); 200834e91afSDan Murphy 201834e91afSDan Murphy setbits_le32((*prcm)->cm_l3init_hsusbhost_clkctrl, 202834e91afSDan Murphy (USBPHY_CORE_CLKCTRL_OPTFCLKEN_CLK32K | 203834e91afSDan Murphy OTG_SS_CLKCTRL_MODULEMODE_HW)); 204834e91afSDan Murphy 205834e91afSDan Murphy /* This is an undocumented Reserved register */ 206834e91afSDan Murphy reg = 0x4a0086c0; 207834e91afSDan Murphy val = readl(reg); 208834e91afSDan Murphy val |= 0x100; 209834e91afSDan Murphy setbits_le32(reg, val); 210834e91afSDan Murphy } 211834e91afSDan Murphy 212834e91afSDan Murphy void usb_phy_power(int on) 213834e91afSDan Murphy { 214834e91afSDan Murphy return; 215834e91afSDan Murphy } 216834e91afSDan Murphy #endif /* CONFIG_OMAP_USB2PHY2_HOST */ 217ba55453cSDan Murphy 2183d799c7fSDan Murphy #ifdef CONFIG_AM437X_USB2PHY2_HOST 2193d799c7fSDan Murphy static void am437x_enable_usb2_phy2(struct omap_xhci *omap) 2203d799c7fSDan Murphy { 2213d799c7fSDan Murphy const u32 usb_otg_ss_clk_val = (USBOTGSSX_CLKCTRL_MODULE_EN | 2223d799c7fSDan Murphy USBOTGSSX_CLKCTRL_OPTFCLKEN_REFCLK960); 2233d799c7fSDan Murphy 2243d799c7fSDan Murphy writel(usb_otg_ss_clk_val, PRM_PER_USB_OTG_SS0_CLKCTRL); 2253d799c7fSDan Murphy writel(usb_otg_ss_clk_val, PRM_PER_USB_OTG_SS1_CLKCTRL); 2263d799c7fSDan Murphy 2273d799c7fSDan Murphy writel(USBPHYOCPSCP_MODULE_EN, PRM_PER_USBPHYOCP2SCP0_CLKCTRL); 2283d799c7fSDan Murphy writel(USBPHYOCPSCP_MODULE_EN, PRM_PER_USBPHYOCP2SCP1_CLKCTRL); 2293d799c7fSDan Murphy } 2303d799c7fSDan Murphy 2313d799c7fSDan Murphy void usb_phy_power(int on) 2323d799c7fSDan Murphy { 2335ba95541SFelipe Balbi u32 val; 2345ba95541SFelipe Balbi 2355ba95541SFelipe Balbi /* USB1_CTRL */ 2365ba95541SFelipe Balbi val = readl(USB1_CTRL); 2375ba95541SFelipe Balbi if (on) { 2385ba95541SFelipe Balbi /* 2395ba95541SFelipe Balbi * these bits are re-used on AM437x to power up/down the USB 2405ba95541SFelipe Balbi * CM and OTG PHYs, if we don't toggle them, USB will not be 2415ba95541SFelipe Balbi * functional on newer silicon revisions 2425ba95541SFelipe Balbi */ 2435ba95541SFelipe Balbi val &= ~(USB1_CTRL_CM_PWRDN | USB1_CTRL_OTG_PWRDN); 2445ba95541SFelipe Balbi } else { 2455ba95541SFelipe Balbi val |= USB1_CTRL_CM_PWRDN | USB1_CTRL_OTG_PWRDN; 2465ba95541SFelipe Balbi } 2475ba95541SFelipe Balbi 2485ba95541SFelipe Balbi writel(val, USB1_CTRL); 2493d799c7fSDan Murphy } 2503d799c7fSDan Murphy #endif /* CONFIG_AM437X_USB2PHY2_HOST */ 2513d799c7fSDan Murphy 252834e91afSDan Murphy void omap_enable_phy(struct omap_xhci *omap) 253834e91afSDan Murphy { 254834e91afSDan Murphy #ifdef CONFIG_OMAP_USB2PHY2_HOST 255834e91afSDan Murphy omap_enable_usb2_phy2(omap); 256834e91afSDan Murphy #endif 257834e91afSDan Murphy 2583d799c7fSDan Murphy #ifdef CONFIG_AM437X_USB2PHY2_HOST 2593d799c7fSDan Murphy am437x_enable_usb2_phy2(omap); 2603d799c7fSDan Murphy #endif 2613d799c7fSDan Murphy 262834e91afSDan Murphy #ifdef CONFIG_OMAP_USB3PHY1_HOST 263834e91afSDan Murphy omap_enable_usb3_phy(omap); 264834e91afSDan Murphy omap_usb3_phy_init(omap->usb3_phy); 265834e91afSDan Murphy #endif 266834e91afSDan Murphy } 267