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