uboot/drivers/usb/phy/omap_usb_phy.c
<<
>>
Prefs
   1/*
   2 * OMAP USB PHY Support
   3 *
   4 * (C) Copyright 2013
   5 * Texas Instruments, <www.ti.com>
   6 *
   7 * Author: Dan Murphy <dmurphy@ti.com>
   8 *
   9 * SPDX-License-Identifier:     GPL-2.0+
  10 */
  11
  12#include <common.h>
  13#include <usb.h>
  14#include <asm-generic/errno.h>
  15#include <asm/omap_common.h>
  16#include <asm/arch/cpu.h>
  17#include <asm/arch/sys_proto.h>
  18
  19#include <linux/compat.h>
  20#include <linux/usb/dwc3.h>
  21#include <linux/usb/xhci-omap.h>
  22
  23#include "../host/xhci.h"
  24
  25#ifdef CONFIG_OMAP_USB3PHY1_HOST
  26struct usb3_dpll_params {
  27        u16     m;
  28        u8      n;
  29        u8      freq:3;
  30        u8      sd;
  31        u32     mf;
  32};
  33
  34struct usb3_dpll_map {
  35        unsigned long rate;
  36        struct usb3_dpll_params params;
  37        struct usb3_dpll_map *dpll_map;
  38};
  39
  40static struct usb3_dpll_map dpll_map_usb[] = {
  41        {12000000, {1250, 5, 4, 20, 0} },       /* 12 MHz */
  42        {16800000, {3125, 20, 4, 20, 0} },      /* 16.8 MHz */
  43        {19200000, {1172, 8, 4, 20, 65537} },   /* 19.2 MHz */
  44        {20000000, {1000, 7, 4, 10, 0} },       /* 20 MHz */
  45        {26000000, {1250, 12, 4, 20, 0} },      /* 26 MHz */
  46        {38400000, {3125, 47, 4, 20, 92843} },  /* 38.4 MHz */
  47        { },                                    /* Terminator */
  48};
  49
  50static struct usb3_dpll_params *omap_usb3_get_dpll_params(void)
  51{
  52        unsigned long rate;
  53        struct usb3_dpll_map *dpll_map = dpll_map_usb;
  54
  55        rate = get_sys_clk_freq();
  56
  57        for (; dpll_map->rate; dpll_map++) {
  58                if (rate == dpll_map->rate)
  59                        return &dpll_map->params;
  60        }
  61
  62        dev_err(phy->dev, "No DPLL configuration for %lu Hz SYS CLK\n", rate);
  63
  64        return NULL;
  65}
  66
  67static void omap_usb_dpll_relock(struct omap_usb3_phy *phy_regs)
  68{
  69        u32 val;
  70
  71        writel(SET_PLL_GO, &phy_regs->pll_go);
  72        do {
  73                val = readl(&phy_regs->pll_status);
  74                        if (val & PLL_LOCK)
  75                                break;
  76        } while (1);
  77}
  78
  79static void omap_usb_dpll_lock(struct omap_usb3_phy *phy_regs)
  80{
  81        struct usb3_dpll_params *dpll_params;
  82        u32 val;
  83
  84        dpll_params = omap_usb3_get_dpll_params();
  85        if (!dpll_params)
  86                return;
  87
  88        val = readl(&phy_regs->pll_config_1);
  89        val &= ~PLL_REGN_MASK;
  90        val |= dpll_params->n << PLL_REGN_SHIFT;
  91        writel(val, &phy_regs->pll_config_1);
  92
  93        val = readl(&phy_regs->pll_config_2);
  94        val &= ~PLL_SELFREQDCO_MASK;
  95        val |= dpll_params->freq << PLL_SELFREQDCO_SHIFT;
  96        writel(val, &phy_regs->pll_config_2);
  97
  98        val = readl(&phy_regs->pll_config_1);
  99        val &= ~PLL_REGM_MASK;
 100        val |= dpll_params->m << PLL_REGM_SHIFT;
 101        writel(val, &phy_regs->pll_config_1);
 102
 103        val = readl(&phy_regs->pll_config_4);
 104        val &= ~PLL_REGM_F_MASK;
 105        val |= dpll_params->mf << PLL_REGM_F_SHIFT;
 106        writel(val, &phy_regs->pll_config_4);
 107
 108        val = readl(&phy_regs->pll_config_3);
 109        val &= ~PLL_SD_MASK;
 110        val |= dpll_params->sd << PLL_SD_SHIFT;
 111        writel(val, &phy_regs->pll_config_3);
 112
 113        omap_usb_dpll_relock(phy_regs);
 114}
 115
 116static void usb3_phy_partial_powerup(struct omap_usb3_phy *phy_regs)
 117{
 118        u32 rate = get_sys_clk_freq()/1000000;
 119        u32 val;
 120
 121        val = readl((*ctrl)->control_phy_power_usb);
 122        val &= ~(USB3_PWRCTL_CLK_CMD_MASK | USB3_PWRCTL_CLK_FREQ_MASK);
 123        val |= (USB3_PHY_PARTIAL_RX_POWERON | USB3_PHY_TX_RX_POWERON);
 124        val |= rate << USB3_PWRCTL_CLK_FREQ_SHIFT;
 125
 126        writel(val, (*ctrl)->control_phy_power_usb);
 127}
 128
 129void usb_phy_power(int on)
 130{
 131        u32 val;
 132
 133        val = readl((*ctrl)->control_phy_power_usb);
 134        if (on) {
 135                val &= ~USB3_PWRCTL_CLK_CMD_MASK;
 136                val |= USB3_PHY_TX_RX_POWERON;
 137        } else {
 138                val &= (~USB3_PWRCTL_CLK_CMD_MASK & ~USB3_PHY_TX_RX_POWERON);
 139        }
 140
 141        writel(val, (*ctrl)->control_phy_power_usb);
 142}
 143
 144void omap_usb3_phy_init(struct omap_usb3_phy *phy_regs)
 145{
 146        omap_usb_dpll_lock(phy_regs);
 147        usb3_phy_partial_powerup(phy_regs);
 148        /*
 149         * Give enough time for the PHY to partially power-up before
 150         * powering it up completely. delay value suggested by the HW
 151         * team.
 152         */
 153        mdelay(100);
 154}
 155
 156static void omap_enable_usb3_phy(struct omap_xhci *omap)
 157{
 158        u32     val;
 159
 160        val = (USBOTGSS_DMADISABLE |
 161                        USBOTGSS_STANDBYMODE_SMRT_WKUP |
 162                        USBOTGSS_IDLEMODE_NOIDLE);
 163        writel(val, &omap->otg_wrapper->sysconfig);
 164
 165        /* Clear the utmi OTG status */
 166        val = readl(&omap->otg_wrapper->utmi_otg_status);
 167        writel(val, &omap->otg_wrapper->utmi_otg_status);
 168
 169        /* Enable interrupts */
 170        writel(USBOTGSS_COREIRQ_EN, &omap->otg_wrapper->irqenable_set_0);
 171        val = (USBOTGSS_IRQ_SET_1_IDPULLUP_FALL_EN |
 172                        USBOTGSS_IRQ_SET_1_DISCHRGVBUS_FALL_EN |
 173                        USBOTGSS_IRQ_SET_1_CHRGVBUS_FALL_EN     |
 174                        USBOTGSS_IRQ_SET_1_DRVVBUS_FALL_EN      |
 175                        USBOTGSS_IRQ_SET_1_IDPULLUP_RISE_EN     |
 176                        USBOTGSS_IRQ_SET_1_DISCHRGVBUS_RISE_EN  |
 177                        USBOTGSS_IRQ_SET_1_CHRGVBUS_RISE_EN |
 178                        USBOTGSS_IRQ_SET_1_DRVVBUS_RISE_EN |
 179                        USBOTGSS_IRQ_SET_1_OEVT_EN);
 180        writel(val, &omap->otg_wrapper->irqenable_set_1);
 181
 182        /* Clear the IRQ status */
 183        val = readl(&omap->otg_wrapper->irqstatus_1);
 184        writel(val, &omap->otg_wrapper->irqstatus_1);
 185        val = readl(&omap->otg_wrapper->irqstatus_0);
 186        writel(val, &omap->otg_wrapper->irqstatus_0);
 187};
 188#endif /* CONFIG_OMAP_USB3PHY1_HOST */
 189
 190#ifdef CONFIG_OMAP_USB2PHY2_HOST
 191static void omap_enable_usb2_phy2(struct omap_xhci *omap)
 192{
 193        u32 reg, val;
 194
 195        val = (~USB2PHY_AUTORESUME_EN & USB2PHY_DISCHGDET);
 196        writel(val, (*ctrl)->control_srcomp_north_side);
 197
 198        setbits_le32((*prcm)->cm_coreaon_usb_phy2_core_clkctrl,
 199                        USBPHY_CORE_CLKCTRL_OPTFCLKEN_CLK32K);
 200
 201        setbits_le32((*prcm)->cm_l3init_hsusbhost_clkctrl,
 202                                        (USBPHY_CORE_CLKCTRL_OPTFCLKEN_CLK32K |
 203                                         OTG_SS_CLKCTRL_MODULEMODE_HW));
 204
 205        /* This is an undocumented Reserved register */
 206        reg = 0x4a0086c0;
 207        val = readl(reg);
 208        val |= 0x100;
 209        setbits_le32(reg, val);
 210}
 211
 212void usb_phy_power(int on)
 213{
 214        return;
 215}
 216#endif /* CONFIG_OMAP_USB2PHY2_HOST */
 217
 218#ifdef CONFIG_AM437X_USB2PHY2_HOST
 219static void am437x_enable_usb2_phy2(struct omap_xhci *omap)
 220{
 221        const u32 usb_otg_ss_clk_val = (USBOTGSSX_CLKCTRL_MODULE_EN |
 222                                USBOTGSSX_CLKCTRL_OPTFCLKEN_REFCLK960);
 223
 224        writel(usb_otg_ss_clk_val, PRM_PER_USB_OTG_SS0_CLKCTRL);
 225        writel(usb_otg_ss_clk_val, PRM_PER_USB_OTG_SS1_CLKCTRL);
 226
 227        writel(USBPHYOCPSCP_MODULE_EN, PRM_PER_USBPHYOCP2SCP0_CLKCTRL);
 228        writel(USBPHYOCPSCP_MODULE_EN, PRM_PER_USBPHYOCP2SCP1_CLKCTRL);
 229}
 230
 231void usb_phy_power(int on)
 232{
 233        u32 val;
 234
 235        /* USB1_CTRL */
 236        val = readl(USB1_CTRL);
 237        if (on) {
 238                /*
 239                 * these bits are re-used on AM437x to power up/down the USB
 240                 * CM and OTG PHYs, if we don't toggle them, USB will not be
 241                 * functional on newer silicon revisions
 242                 */
 243                val &= ~(USB1_CTRL_CM_PWRDN | USB1_CTRL_OTG_PWRDN);
 244        } else {
 245                val |= USB1_CTRL_CM_PWRDN | USB1_CTRL_OTG_PWRDN;
 246        }
 247
 248        writel(val, USB1_CTRL);
 249}
 250#endif /* CONFIG_AM437X_USB2PHY2_HOST */
 251
 252void omap_enable_phy(struct omap_xhci *omap)
 253{
 254#ifdef CONFIG_OMAP_USB2PHY2_HOST
 255        omap_enable_usb2_phy2(omap);
 256#endif
 257
 258#ifdef CONFIG_AM437X_USB2PHY2_HOST
 259        am437x_enable_usb2_phy2(omap);
 260#endif
 261
 262#ifdef CONFIG_OMAP_USB3PHY1_HOST
 263        omap_enable_usb3_phy(omap);
 264        omap_usb3_phy_init(omap->usb3_phy);
 265#endif
 266}
 267