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