uboot/drivers/usb/cdns3/drd.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Cadence USBSS DRD Driver.
   4 *
   5 * Copyright (C) 2018-2019 Cadence.
   6 * Copyright (C) 2019 Texas Instruments
   7 *
   8 * Author: Pawel Laszczak <pawell@cadence.com>
   9 *         Roger Quadros <rogerq@ti.com>
  10 *
  11 *
  12 */
  13#include <dm.h>
  14#include <dm/device_compat.h>
  15#include <linux/delay.h>
  16#include <linux/iopoll.h>
  17#include <linux/kernel.h>
  18#include <linux/usb/otg.h>
  19
  20#include "gadget.h"
  21#include "drd.h"
  22#include "core.h"
  23
  24#define readl_poll_timeout_atomic readl_poll_timeout
  25#define usleep_range(a, b) udelay((b))
  26/**
  27 * cdns3_set_mode - change mode of OTG Core
  28 * @cdns: pointer to context structure
  29 * @mode: selected mode from cdns_role
  30 *
  31 * Returns 0 on success otherwise negative errno
  32 */
  33int cdns3_set_mode(struct cdns3 *cdns, enum usb_dr_mode mode)
  34{
  35        int ret = 0;
  36        u32 reg;
  37
  38        switch (mode) {
  39        case USB_DR_MODE_PERIPHERAL:
  40                break;
  41        case USB_DR_MODE_HOST:
  42                break;
  43        case USB_DR_MODE_OTG:
  44                dev_dbg(cdns->dev, "Set controller to OTG mode\n");
  45                if (cdns->version == CDNS3_CONTROLLER_V1) {
  46                        reg = readl(&cdns->otg_v1_regs->override);
  47                        reg |= OVERRIDE_IDPULLUP;
  48                        writel(reg, &cdns->otg_v1_regs->override);
  49                } else {
  50                        reg = readl(&cdns->otg_v0_regs->ctrl1);
  51                        reg |= OVERRIDE_IDPULLUP_V0;
  52                        writel(reg, &cdns->otg_v0_regs->ctrl1);
  53                }
  54
  55                /*
  56                 * Hardware specification says: "ID_VALUE must be valid within
  57                 * 50ms after idpullup is set to '1" so driver must wait
  58                 * 50ms before reading this pin.
  59                 */
  60                usleep_range(50000, 60000);
  61                break;
  62        default:
  63                dev_err(cdns->dev, "Unsupported mode of operation %d\n", mode);
  64                return -EINVAL;
  65        }
  66
  67        return ret;
  68}
  69
  70int cdns3_get_id(struct cdns3 *cdns)
  71{
  72        int id;
  73
  74        id = readl(&cdns->otg_regs->sts) & OTGSTS_ID_VALUE;
  75        dev_dbg(cdns->dev, "OTG ID: %d", id);
  76
  77        return id;
  78}
  79
  80int cdns3_get_vbus(struct cdns3 *cdns)
  81{
  82        int vbus;
  83
  84        vbus = !!(readl(&cdns->otg_regs->sts) & OTGSTS_VBUS_VALID);
  85        dev_dbg(cdns->dev, "OTG VBUS: %d", vbus);
  86
  87        return vbus;
  88}
  89
  90int cdns3_is_host(struct cdns3 *cdns)
  91{
  92        if (cdns->dr_mode == USB_DR_MODE_HOST)
  93                return 1;
  94        else if (!cdns3_get_id(cdns))
  95                return 1;
  96
  97        return 0;
  98}
  99
 100int cdns3_is_device(struct cdns3 *cdns)
 101{
 102        if (cdns->dr_mode == USB_DR_MODE_PERIPHERAL)
 103                return 1;
 104        else if (cdns->dr_mode == USB_DR_MODE_OTG)
 105                if (cdns3_get_id(cdns))
 106                        return 1;
 107
 108        return 0;
 109}
 110
 111/**
 112 * cdns3_drd_switch_host - start/stop host
 113 * @cdns: Pointer to controller context structure
 114 * @on: 1 for start, 0 for stop
 115 *
 116 * Returns 0 on success otherwise negative errno
 117 */
 118int cdns3_drd_switch_host(struct cdns3 *cdns, int on)
 119{
 120        int ret, val;
 121        u32 reg = OTGCMD_OTG_DIS;
 122
 123        /* switch OTG core */
 124        if (on) {
 125                writel(OTGCMD_HOST_BUS_REQ | reg, &cdns->otg_regs->cmd);
 126
 127                dev_dbg(cdns->dev, "Waiting till Host mode is turned on\n");
 128                ret = readl_poll_timeout_atomic(&cdns->otg_regs->sts, val,
 129                                                val & OTGSTS_XHCI_READY,
 130                                                100000);
 131                if (ret) {
 132                        dev_err(cdns->dev, "timeout waiting for xhci_ready\n");
 133                        return ret;
 134                }
 135        } else {
 136                writel(OTGCMD_HOST_BUS_DROP | OTGCMD_DEV_BUS_DROP |
 137                       OTGCMD_DEV_POWER_OFF | OTGCMD_HOST_POWER_OFF,
 138                       &cdns->otg_regs->cmd);
 139                /* Waiting till H_IDLE state.*/
 140                readl_poll_timeout_atomic(&cdns->otg_regs->state, val,
 141                                          !(val & OTGSTATE_HOST_STATE_MASK),
 142                                          2000000);
 143        }
 144
 145        return 0;
 146}
 147
 148/**
 149 * cdns3_drd_switch_gadget - start/stop gadget
 150 * @cdns: Pointer to controller context structure
 151 * @on: 1 for start, 0 for stop
 152 *
 153 * Returns 0 on success otherwise negative errno
 154 */
 155int cdns3_drd_switch_gadget(struct cdns3 *cdns, int on)
 156{
 157        int ret, val;
 158        u32 reg = OTGCMD_OTG_DIS;
 159
 160        /* switch OTG core */
 161        if (on) {
 162                writel(OTGCMD_DEV_BUS_REQ | reg, &cdns->otg_regs->cmd);
 163
 164                dev_dbg(cdns->dev, "Waiting till Device mode is turned on\n");
 165
 166                ret = readl_poll_timeout_atomic(&cdns->otg_regs->sts, val,
 167                                                val & OTGSTS_DEV_READY,
 168                                                100000);
 169                if (ret) {
 170                        dev_err(cdns->dev, "timeout waiting for dev_ready\n");
 171                        return ret;
 172                }
 173        } else {
 174                /*
 175                 * driver should wait at least 10us after disabling Device
 176                 * before turning-off Device (DEV_BUS_DROP)
 177                 */
 178                usleep_range(20, 30);
 179                writel(OTGCMD_HOST_BUS_DROP | OTGCMD_DEV_BUS_DROP |
 180                       OTGCMD_DEV_POWER_OFF | OTGCMD_HOST_POWER_OFF,
 181                       &cdns->otg_regs->cmd);
 182                /* Waiting till DEV_IDLE state.*/
 183                readl_poll_timeout_atomic(&cdns->otg_regs->state, val,
 184                                          !(val & OTGSTATE_DEV_STATE_MASK),
 185                                          2000000);
 186        }
 187
 188        return 0;
 189}
 190
 191/**
 192 * cdns3_init_otg_mode - initialize drd controller
 193 * @cdns: Pointer to controller context structure
 194 *
 195 * Returns 0 on success otherwise negative errno
 196 */
 197static int cdns3_init_otg_mode(struct cdns3 *cdns)
 198{
 199        int ret = 0;
 200
 201        /* clear all interrupts */
 202        writel(~0, &cdns->otg_regs->ivect);
 203
 204        ret = cdns3_set_mode(cdns, USB_DR_MODE_OTG);
 205        if (ret)
 206                return ret;
 207
 208        return ret;
 209}
 210
 211/**
 212 * cdns3_drd_update_mode - initialize mode of operation
 213 * @cdns: Pointer to controller context structure
 214 *
 215 * Returns 0 on success otherwise negative errno
 216 */
 217int cdns3_drd_update_mode(struct cdns3 *cdns)
 218{
 219        int ret = 0;
 220
 221        switch (cdns->dr_mode) {
 222        case USB_DR_MODE_PERIPHERAL:
 223                ret = cdns3_set_mode(cdns, USB_DR_MODE_PERIPHERAL);
 224                break;
 225        case USB_DR_MODE_HOST:
 226                ret = cdns3_set_mode(cdns, USB_DR_MODE_HOST);
 227                break;
 228        case USB_DR_MODE_OTG:
 229                ret = cdns3_init_otg_mode(cdns);
 230                break;
 231        default:
 232                dev_err(cdns->dev, "Unsupported mode of operation %d\n",
 233                        cdns->dr_mode);
 234                return -EINVAL;
 235        }
 236
 237        return ret;
 238}
 239
 240int cdns3_drd_init(struct cdns3 *cdns)
 241{
 242        void __iomem *regs;
 243        int ret = 0;
 244        u32 state;
 245
 246        regs = dev_remap_addr_name(cdns->dev, "otg");
 247        if (!regs)
 248                return -EINVAL;
 249
 250        /* Detection of DRD version. Controller has been released
 251         * in two versions. Both are similar, but they have same changes
 252         * in register maps.
 253         * The first register in old version is command register and it's read
 254         * only, so driver should read 0 from it. On the other hand, in v1
 255         * the first register contains device ID number which is not set to 0.
 256         * Driver uses this fact to detect the proper version of
 257         * controller.
 258         */
 259        cdns->otg_v0_regs = regs;
 260        if (!readl(&cdns->otg_v0_regs->cmd)) {
 261                cdns->version  = CDNS3_CONTROLLER_V0;
 262                cdns->otg_v1_regs = NULL;
 263                cdns->otg_regs = regs;
 264                writel(1, &cdns->otg_v0_regs->simulate);
 265                dev_info(cdns->dev, "DRD version v0 (%08x)\n",
 266                         readl(&cdns->otg_v0_regs->version));
 267        } else {
 268                cdns->otg_v0_regs = NULL;
 269                cdns->otg_v1_regs = regs;
 270                cdns->otg_regs = (void *)&cdns->otg_v1_regs->cmd;
 271                cdns->version  = CDNS3_CONTROLLER_V1;
 272                writel(1, &cdns->otg_v1_regs->simulate);
 273                dev_info(cdns->dev, "DRD version v1 (ID: %08x, rev: %08x)\n",
 274                         readl(&cdns->otg_v1_regs->did),
 275                         readl(&cdns->otg_v1_regs->rid));
 276        }
 277
 278        state = OTGSTS_STRAP(readl(&cdns->otg_regs->sts));
 279
 280        /* Update dr_mode according to STRAP configuration. */
 281        cdns->dr_mode = USB_DR_MODE_OTG;
 282        if (state == OTGSTS_STRAP_HOST) {
 283                dev_dbg(cdns->dev, "Controller strapped to HOST\n");
 284                cdns->dr_mode = USB_DR_MODE_HOST;
 285        } else if (state == OTGSTS_STRAP_GADGET) {
 286                dev_dbg(cdns->dev, "Controller strapped to PERIPHERAL\n");
 287                cdns->dr_mode = USB_DR_MODE_PERIPHERAL;
 288        }
 289
 290        state = readl(&cdns->otg_regs->sts);
 291        if (OTGSTS_OTG_NRDY(state) != 0) {
 292                dev_err(cdns->dev, "Cadence USB3 OTG device not ready\n");
 293                return -ENODEV;
 294        }
 295
 296        return ret;
 297}
 298
 299int cdns3_drd_exit(struct cdns3 *cdns)
 300{
 301        return 0;
 302}
 303