uboot/drivers/usb/cdns3/cdns3-ti.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/**
   3 * cdns_ti-ti.c - TI specific Glue layer for Cadence USB Controller
   4 *
   5 * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com
   6 */
   7
   8#include <common.h>
   9#include <asm-generic/io.h>
  10#include <clk.h>
  11#include <dm.h>
  12#include <dm/device_compat.h>
  13#include <linux/io.h>
  14#include <linux/usb/otg.h>
  15#include <malloc.h>
  16
  17#include "core.h"
  18
  19/* USB Wrapper register offsets */
  20#define USBSS_PID               0x0
  21#define USBSS_W1                0x4
  22#define USBSS_STATIC_CONFIG     0x8
  23#define USBSS_PHY_TEST          0xc
  24#define USBSS_DEBUG_CTRL        0x10
  25#define USBSS_DEBUG_INFO        0x14
  26#define USBSS_DEBUG_LINK_STATE  0x18
  27#define USBSS_DEVICE_CTRL       0x1c
  28
  29/* Wrapper 1 register bits */
  30#define USBSS_W1_PWRUP_RST              BIT(0)
  31#define USBSS_W1_OVERCURRENT_SEL        BIT(8)
  32#define USBSS_W1_MODESTRAP_SEL          BIT(9)
  33#define USBSS_W1_OVERCURRENT            BIT(16)
  34#define USBSS_W1_MODESTRAP_MASK         GENMASK(18, 17)
  35#define USBSS_W1_MODESTRAP_SHIFT        17
  36#define USBSS_W1_USB2_ONLY              BIT(19)
  37
  38/* Static config register bits */
  39#define USBSS1_STATIC_PLL_REF_SEL_MASK  GENMASK(8, 5)
  40#define USBSS1_STATIC_PLL_REF_SEL_SHIFT 5
  41#define USBSS1_STATIC_LOOPBACK_MODE_MASK        GENMASK(4, 3)
  42#define USBSS1_STATIC_LOOPBACK_MODE_SHIFT       3
  43#define USBSS1_STATIC_VBUS_SEL_MASK     GENMASK(2, 1)
  44#define USBSS1_STATIC_VBUS_SEL_SHIFT    1
  45#define USBSS1_STATIC_LANE_REVERSE      BIT(0)
  46
  47/* Modestrap modes */
  48enum modestrap_mode { USBSS_MODESTRAP_MODE_NONE,
  49                      USBSS_MODESTRAP_MODE_HOST,
  50                      USBSS_MODESTRAP_MODE_PERIPHERAL};
  51
  52struct cdns_ti {
  53        struct udevice *dev;
  54        void __iomem *usbss;
  55        int usb2_only:1;
  56        int vbus_divider:1;
  57        struct clk *usb2_refclk;
  58        struct clk *lpm_clk;
  59};
  60
  61static const int cdns_ti_rate_table[] = {       /* in KHZ */
  62        9600,
  63        10000,
  64        12000,
  65        19200,
  66        20000,
  67        24000,
  68        25000,
  69        26000,
  70        38400,
  71        40000,
  72        58000,
  73        50000,
  74        52000,
  75};
  76
  77static inline u32 cdns_ti_readl(struct cdns_ti *data, u32 offset)
  78{
  79        return readl(data->usbss + offset);
  80}
  81
  82static inline void cdns_ti_writel(struct cdns_ti *data, u32 offset, u32 value)
  83{
  84        writel(value, data->usbss + offset);
  85}
  86
  87static int cdns_ti_probe(struct udevice *dev)
  88{
  89        struct cdns_ti *data = dev_get_platdata(dev);
  90        struct clk usb2_refclk;
  91        int modestrap_mode;
  92        unsigned long rate;
  93        int rate_code, i;
  94        u32 reg;
  95        int ret;
  96
  97        data->dev = dev;
  98
  99        data->usbss = dev_remap_addr_index(dev, 0);
 100        if (!data->usbss)
 101                return -EINVAL;
 102
 103        ret = clk_get_by_name(dev, "usb2_refclk", &usb2_refclk);
 104        if (ret) {
 105                dev_err(dev, "Failed to get usb2_refclk\n");
 106                return ret;
 107        }
 108
 109        rate = clk_get_rate(&usb2_refclk);
 110        rate /= 1000;   /* To KHz */
 111        for (i = 0; i < ARRAY_SIZE(cdns_ti_rate_table); i++) {
 112                if (cdns_ti_rate_table[i] == rate)
 113                        break;
 114        }
 115
 116        if (i == ARRAY_SIZE(cdns_ti_rate_table)) {
 117                dev_err(dev, "unsupported usb2_refclk rate: %lu KHz\n", rate);
 118                return -EINVAL;
 119        }
 120
 121        rate_code = i;
 122
 123        /* assert RESET */
 124        reg = cdns_ti_readl(data, USBSS_W1);
 125        reg &= ~USBSS_W1_PWRUP_RST;
 126        cdns_ti_writel(data, USBSS_W1, reg);
 127
 128        /* set static config */
 129        reg = cdns_ti_readl(data, USBSS_STATIC_CONFIG);
 130        reg &= ~USBSS1_STATIC_PLL_REF_SEL_MASK;
 131        reg |= rate_code << USBSS1_STATIC_PLL_REF_SEL_SHIFT;
 132
 133        reg &= ~USBSS1_STATIC_VBUS_SEL_MASK;
 134        data->vbus_divider = dev_read_bool(dev, "ti,vbus-divider");
 135        if (data->vbus_divider)
 136                reg |= 1 << USBSS1_STATIC_VBUS_SEL_SHIFT;
 137
 138        cdns_ti_writel(data, USBSS_STATIC_CONFIG, reg);
 139        reg = cdns_ti_readl(data, USBSS_STATIC_CONFIG);
 140
 141        /* set USB2_ONLY mode if requested */
 142        reg = cdns_ti_readl(data, USBSS_W1);
 143        data->usb2_only = dev_read_bool(dev, "ti,usb2-only");
 144        if (data->usb2_only)
 145                reg |= USBSS_W1_USB2_ONLY;
 146
 147        /* set modestrap  */
 148        if (dev_read_bool(dev, "ti,modestrap-host"))
 149                modestrap_mode = USBSS_MODESTRAP_MODE_HOST;
 150        else if (dev_read_bool(dev, "ti,modestrap-peripheral"))
 151                modestrap_mode = USBSS_MODESTRAP_MODE_PERIPHERAL;
 152        else
 153                modestrap_mode = USBSS_MODESTRAP_MODE_NONE;
 154
 155        reg |= USBSS_W1_MODESTRAP_SEL;
 156        reg &= ~USBSS_W1_MODESTRAP_MASK;
 157        reg |= modestrap_mode << USBSS_W1_MODESTRAP_SHIFT;
 158        cdns_ti_writel(data, USBSS_W1, reg);
 159
 160        /* de-assert RESET */
 161        reg |= USBSS_W1_PWRUP_RST;
 162        cdns_ti_writel(data, USBSS_W1, reg);
 163
 164        return 0;
 165}
 166
 167static int cdns_ti_remove(struct udevice *dev)
 168{
 169        struct cdns_ti *data = dev_get_platdata(dev);
 170        u32 reg;
 171
 172        /* put device back to RESET*/
 173        reg = cdns_ti_readl(data, USBSS_W1);
 174        reg &= ~USBSS_W1_PWRUP_RST;
 175        cdns_ti_writel(data, USBSS_W1, reg);
 176
 177        return 0;
 178}
 179
 180static const struct udevice_id cdns_ti_of_match[] = {
 181        { .compatible = "ti,j721e-usb", },
 182        {},
 183};
 184
 185U_BOOT_DRIVER(cdns_ti) = {
 186        .name = "cdns-ti",
 187        .id = UCLASS_NOP,
 188        .of_match = cdns_ti_of_match,
 189        .bind = cdns3_bind,
 190        .probe = cdns_ti_probe,
 191        .remove = cdns_ti_remove,
 192        .platdata_auto_alloc_size = sizeof(struct cdns_ti),
 193        .flags = DM_FLAG_OS_PREPARE,
 194};
 195