linux/drivers/usb/cdns3/drd.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Cadence USBSS and USBSSP DRD Driver.
   4 *
   5 * Copyright (C) 2018-2020 Cadence.
   6 * Copyright (C) 2019 Texas Instruments
   7 *
   8 * Author: Pawel Laszczak <pawell@cadence.com>
   9 *         Roger Quadros <rogerq@ti.com>
  10 *
  11 */
  12#include <linux/kernel.h>
  13#include <linux/interrupt.h>
  14#include <linux/delay.h>
  15#include <linux/iopoll.h>
  16#include <linux/usb/otg.h>
  17
  18#include "drd.h"
  19#include "core.h"
  20
  21/**
  22 * cdns_set_mode - change mode of OTG Core
  23 * @cdns: pointer to context structure
  24 * @mode: selected mode from cdns_role
  25 *
  26 * Returns 0 on success otherwise negative errno
  27 */
  28static int cdns_set_mode(struct cdns *cdns, enum usb_dr_mode mode)
  29{
  30        void __iomem  *override_reg;
  31        u32 reg;
  32
  33        switch (mode) {
  34        case USB_DR_MODE_PERIPHERAL:
  35                break;
  36        case USB_DR_MODE_HOST:
  37                break;
  38        case USB_DR_MODE_OTG:
  39                dev_dbg(cdns->dev, "Set controller to OTG mode\n");
  40
  41                if (cdns->version == CDNSP_CONTROLLER_V2)
  42                        override_reg = &cdns->otg_cdnsp_regs->override;
  43                else if (cdns->version == CDNS3_CONTROLLER_V1)
  44                        override_reg = &cdns->otg_v1_regs->override;
  45                else
  46                        override_reg = &cdns->otg_v0_regs->ctrl1;
  47
  48                reg = readl(override_reg);
  49
  50                if (cdns->version != CDNS3_CONTROLLER_V0)
  51                        reg |= OVERRIDE_IDPULLUP;
  52                else
  53                        reg |= OVERRIDE_IDPULLUP_V0;
  54
  55                writel(reg, override_reg);
  56
  57                if (cdns->version == CDNS3_CONTROLLER_V1) {
  58                        /*
  59                         * Enable work around feature built into the
  60                         * controller to address issue with RX Sensitivity
  61                         * est (EL_17) for USB2 PHY. The issue only occures
  62                         * for 0x0002450D controller version.
  63                         */
  64                        if (cdns->phyrst_a_enable) {
  65                                reg = readl(&cdns->otg_v1_regs->phyrst_cfg);
  66                                reg |= PHYRST_CFG_PHYRST_A_ENABLE;
  67                                writel(reg, &cdns->otg_v1_regs->phyrst_cfg);
  68                        }
  69                }
  70
  71                /*
  72                 * Hardware specification says: "ID_VALUE must be valid within
  73                 * 50ms after idpullup is set to '1" so driver must wait
  74                 * 50ms before reading this pin.
  75                 */
  76                usleep_range(50000, 60000);
  77                break;
  78        default:
  79                dev_err(cdns->dev, "Unsupported mode of operation %d\n", mode);
  80                return -EINVAL;
  81        }
  82
  83        return 0;
  84}
  85
  86int cdns_get_id(struct cdns *cdns)
  87{
  88        int id;
  89
  90        id = readl(&cdns->otg_regs->sts) & OTGSTS_ID_VALUE;
  91        dev_dbg(cdns->dev, "OTG ID: %d", id);
  92
  93        return id;
  94}
  95
  96int cdns_get_vbus(struct cdns *cdns)
  97{
  98        int vbus;
  99
 100        vbus = !!(readl(&cdns->otg_regs->sts) & OTGSTS_VBUS_VALID);
 101        dev_dbg(cdns->dev, "OTG VBUS: %d", vbus);
 102
 103        return vbus;
 104}
 105
 106void cdns_clear_vbus(struct cdns *cdns)
 107{
 108        u32 reg;
 109
 110        if (cdns->version != CDNSP_CONTROLLER_V2)
 111                return;
 112
 113        reg = readl(&cdns->otg_cdnsp_regs->override);
 114        reg |= OVERRIDE_SESS_VLD_SEL;
 115        writel(reg, &cdns->otg_cdnsp_regs->override);
 116}
 117EXPORT_SYMBOL_GPL(cdns_clear_vbus);
 118
 119void cdns_set_vbus(struct cdns *cdns)
 120{
 121        u32 reg;
 122
 123        if (cdns->version != CDNSP_CONTROLLER_V2)
 124                return;
 125
 126        reg = readl(&cdns->otg_cdnsp_regs->override);
 127        reg &= ~OVERRIDE_SESS_VLD_SEL;
 128        writel(reg, &cdns->otg_cdnsp_regs->override);
 129}
 130EXPORT_SYMBOL_GPL(cdns_set_vbus);
 131
 132bool cdns_is_host(struct cdns *cdns)
 133{
 134        if (cdns->dr_mode == USB_DR_MODE_HOST)
 135                return true;
 136        else if (cdns_get_id(cdns) == CDNS3_ID_HOST)
 137                return true;
 138
 139        return false;
 140}
 141
 142bool cdns_is_device(struct cdns *cdns)
 143{
 144        if (cdns->dr_mode == USB_DR_MODE_PERIPHERAL)
 145                return true;
 146        else if (cdns->dr_mode == USB_DR_MODE_OTG)
 147                if (cdns_get_id(cdns) == CDNS3_ID_PERIPHERAL)
 148                        return true;
 149
 150        return false;
 151}
 152
 153/**
 154 * cdns_otg_disable_irq - Disable all OTG interrupts
 155 * @cdns: Pointer to controller context structure
 156 */
 157static void cdns_otg_disable_irq(struct cdns *cdns)
 158{
 159        writel(0, &cdns->otg_irq_regs->ien);
 160}
 161
 162/**
 163 * cdns_otg_enable_irq - enable id and sess_valid interrupts
 164 * @cdns: Pointer to controller context structure
 165 */
 166static void cdns_otg_enable_irq(struct cdns *cdns)
 167{
 168        writel(OTGIEN_ID_CHANGE_INT | OTGIEN_VBUSVALID_RISE_INT |
 169               OTGIEN_VBUSVALID_FALL_INT, &cdns->otg_irq_regs->ien);
 170}
 171
 172/**
 173 * cdns_drd_host_on - start host.
 174 * @cdns: Pointer to controller context structure.
 175 *
 176 * Returns 0 on success otherwise negative errno.
 177 */
 178int cdns_drd_host_on(struct cdns *cdns)
 179{
 180        u32 val, ready_bit;
 181        int ret;
 182
 183        /* Enable host mode. */
 184        writel(OTGCMD_HOST_BUS_REQ | OTGCMD_OTG_DIS,
 185               &cdns->otg_regs->cmd);
 186
 187        if (cdns->version == CDNSP_CONTROLLER_V2)
 188                ready_bit = OTGSTS_CDNSP_XHCI_READY;
 189        else
 190                ready_bit = OTGSTS_CDNS3_XHCI_READY;
 191
 192        dev_dbg(cdns->dev, "Waiting till Host mode is turned on\n");
 193        ret = readl_poll_timeout_atomic(&cdns->otg_regs->sts, val,
 194                                        val & ready_bit, 1, 100000);
 195
 196        if (ret)
 197                dev_err(cdns->dev, "timeout waiting for xhci_ready\n");
 198
 199        phy_set_mode(cdns->usb3_phy, PHY_MODE_USB_HOST);
 200        return ret;
 201}
 202
 203/**
 204 * cdns_drd_host_off - stop host.
 205 * @cdns: Pointer to controller context structure.
 206 */
 207void cdns_drd_host_off(struct cdns *cdns)
 208{
 209        u32 val;
 210
 211        writel(OTGCMD_HOST_BUS_DROP | OTGCMD_DEV_BUS_DROP |
 212               OTGCMD_DEV_POWER_OFF | OTGCMD_HOST_POWER_OFF,
 213               &cdns->otg_regs->cmd);
 214
 215        /* Waiting till H_IDLE state.*/
 216        readl_poll_timeout_atomic(&cdns->otg_regs->state, val,
 217                                  !(val & OTGSTATE_HOST_STATE_MASK),
 218                                  1, 2000000);
 219        phy_set_mode(cdns->usb3_phy, PHY_MODE_INVALID);
 220}
 221
 222/**
 223 * cdns_drd_gadget_on - start gadget.
 224 * @cdns: Pointer to controller context structure.
 225 *
 226 * Returns 0 on success otherwise negative errno
 227 */
 228int cdns_drd_gadget_on(struct cdns *cdns)
 229{
 230        u32 reg = OTGCMD_OTG_DIS;
 231        u32 ready_bit;
 232        int ret, val;
 233
 234        /* switch OTG core */
 235        writel(OTGCMD_DEV_BUS_REQ | reg, &cdns->otg_regs->cmd);
 236
 237        dev_dbg(cdns->dev, "Waiting till Device mode is turned on\n");
 238
 239        if (cdns->version == CDNSP_CONTROLLER_V2)
 240                ready_bit = OTGSTS_CDNSP_DEV_READY;
 241        else
 242                ready_bit = OTGSTS_CDNS3_DEV_READY;
 243
 244        ret = readl_poll_timeout_atomic(&cdns->otg_regs->sts, val,
 245                                        val & ready_bit, 1, 100000);
 246        if (ret) {
 247                dev_err(cdns->dev, "timeout waiting for dev_ready\n");
 248                return ret;
 249        }
 250
 251        phy_set_mode(cdns->usb3_phy, PHY_MODE_USB_DEVICE);
 252        return 0;
 253}
 254EXPORT_SYMBOL_GPL(cdns_drd_gadget_on);
 255
 256/**
 257 * cdns_drd_gadget_off - stop gadget.
 258 * @cdns: Pointer to controller context structure.
 259 */
 260void cdns_drd_gadget_off(struct cdns *cdns)
 261{
 262        u32 val;
 263
 264        /*
 265         * Driver should wait at least 10us after disabling Device
 266         * before turning-off Device (DEV_BUS_DROP).
 267         */
 268        usleep_range(20, 30);
 269        writel(OTGCMD_HOST_BUS_DROP | OTGCMD_DEV_BUS_DROP |
 270               OTGCMD_DEV_POWER_OFF | OTGCMD_HOST_POWER_OFF,
 271               &cdns->otg_regs->cmd);
 272        /* Waiting till DEV_IDLE state.*/
 273        readl_poll_timeout_atomic(&cdns->otg_regs->state, val,
 274                                  !(val & OTGSTATE_DEV_STATE_MASK),
 275                                  1, 2000000);
 276        phy_set_mode(cdns->usb3_phy, PHY_MODE_INVALID);
 277}
 278EXPORT_SYMBOL_GPL(cdns_drd_gadget_off);
 279
 280/**
 281 * cdns_init_otg_mode - initialize drd controller
 282 * @cdns: Pointer to controller context structure
 283 *
 284 * Returns 0 on success otherwise negative errno
 285 */
 286static int cdns_init_otg_mode(struct cdns *cdns)
 287{
 288        int ret;
 289
 290        cdns_otg_disable_irq(cdns);
 291        /* clear all interrupts */
 292        writel(~0, &cdns->otg_irq_regs->ivect);
 293
 294        ret = cdns_set_mode(cdns, USB_DR_MODE_OTG);
 295        if (ret)
 296                return ret;
 297
 298        cdns_otg_enable_irq(cdns);
 299
 300        return 0;
 301}
 302
 303/**
 304 * cdns_drd_update_mode - initialize mode of operation
 305 * @cdns: Pointer to controller context structure
 306 *
 307 * Returns 0 on success otherwise negative errno
 308 */
 309int cdns_drd_update_mode(struct cdns *cdns)
 310{
 311        int ret;
 312
 313        switch (cdns->dr_mode) {
 314        case USB_DR_MODE_PERIPHERAL:
 315                ret = cdns_set_mode(cdns, USB_DR_MODE_PERIPHERAL);
 316                break;
 317        case USB_DR_MODE_HOST:
 318                ret = cdns_set_mode(cdns, USB_DR_MODE_HOST);
 319                break;
 320        case USB_DR_MODE_OTG:
 321                ret = cdns_init_otg_mode(cdns);
 322                break;
 323        default:
 324                dev_err(cdns->dev, "Unsupported mode of operation %d\n",
 325                        cdns->dr_mode);
 326                return -EINVAL;
 327        }
 328
 329        return ret;
 330}
 331
 332static irqreturn_t cdns_drd_thread_irq(int irq, void *data)
 333{
 334        struct cdns *cdns = data;
 335
 336        cdns_hw_role_switch(cdns);
 337
 338        return IRQ_HANDLED;
 339}
 340
 341/**
 342 * cdns_drd_irq - interrupt handler for OTG events
 343 *
 344 * @irq: irq number for cdns core device
 345 * @data: structure of cdns
 346 *
 347 * Returns IRQ_HANDLED or IRQ_NONE
 348 */
 349static irqreturn_t cdns_drd_irq(int irq, void *data)
 350{
 351        irqreturn_t ret = IRQ_NONE;
 352        struct cdns *cdns = data;
 353        u32 reg;
 354
 355        if (cdns->dr_mode != USB_DR_MODE_OTG)
 356                return IRQ_NONE;
 357
 358        if (cdns->in_lpm)
 359                return ret;
 360
 361        reg = readl(&cdns->otg_irq_regs->ivect);
 362
 363        if (!reg)
 364                return IRQ_NONE;
 365
 366        if (reg & OTGIEN_ID_CHANGE_INT) {
 367                dev_dbg(cdns->dev, "OTG IRQ: new ID: %d\n",
 368                        cdns_get_id(cdns));
 369
 370                ret = IRQ_WAKE_THREAD;
 371        }
 372
 373        if (reg & (OTGIEN_VBUSVALID_RISE_INT | OTGIEN_VBUSVALID_FALL_INT)) {
 374                dev_dbg(cdns->dev, "OTG IRQ: new VBUS: %d\n",
 375                        cdns_get_vbus(cdns));
 376
 377                ret = IRQ_WAKE_THREAD;
 378        }
 379
 380        writel(~0, &cdns->otg_irq_regs->ivect);
 381        return ret;
 382}
 383
 384int cdns_drd_init(struct cdns *cdns)
 385{
 386        void __iomem *regs;
 387        u32 state;
 388        int ret;
 389
 390        regs = devm_ioremap_resource(cdns->dev, &cdns->otg_res);
 391        if (IS_ERR(regs))
 392                return PTR_ERR(regs);
 393
 394        /* Detection of DRD version. Controller has been released
 395         * in three versions. All are very similar and are software compatible,
 396         * but they have same changes in register maps.
 397         * The first register in oldest version is command register and it's
 398         * read only. Driver should read 0 from it. On the other hand, in v1
 399         * and v2 the first register contains device ID number which is not
 400         * set to 0. Driver uses this fact to detect the proper version of
 401         * controller.
 402         */
 403        cdns->otg_v0_regs = regs;
 404        if (!readl(&cdns->otg_v0_regs->cmd)) {
 405                cdns->version  = CDNS3_CONTROLLER_V0;
 406                cdns->otg_v1_regs = NULL;
 407                cdns->otg_cdnsp_regs = NULL;
 408                cdns->otg_regs = regs;
 409                cdns->otg_irq_regs = (struct cdns_otg_irq_regs __iomem  *)
 410                                     &cdns->otg_v0_regs->ien;
 411                writel(1, &cdns->otg_v0_regs->simulate);
 412                dev_dbg(cdns->dev, "DRD version v0 (%08x)\n",
 413                         readl(&cdns->otg_v0_regs->version));
 414        } else {
 415                cdns->otg_v0_regs = NULL;
 416                cdns->otg_v1_regs = regs;
 417                cdns->otg_cdnsp_regs = regs;
 418
 419                cdns->otg_regs = (void __iomem *)&cdns->otg_v1_regs->cmd;
 420
 421                if (readl(&cdns->otg_cdnsp_regs->did) == OTG_CDNSP_DID) {
 422                        cdns->otg_irq_regs = (struct cdns_otg_irq_regs __iomem *)
 423                                              &cdns->otg_cdnsp_regs->ien;
 424                        cdns->version  = CDNSP_CONTROLLER_V2;
 425                } else {
 426                        cdns->otg_irq_regs = (struct cdns_otg_irq_regs __iomem *)
 427                                              &cdns->otg_v1_regs->ien;
 428                        writel(1, &cdns->otg_v1_regs->simulate);
 429                        cdns->version  = CDNS3_CONTROLLER_V1;
 430                }
 431
 432                dev_dbg(cdns->dev, "DRD version v1 (ID: %08x, rev: %08x)\n",
 433                         readl(&cdns->otg_v1_regs->did),
 434                         readl(&cdns->otg_v1_regs->rid));
 435        }
 436
 437        state = OTGSTS_STRAP(readl(&cdns->otg_regs->sts));
 438
 439        /* Update dr_mode according to STRAP configuration. */
 440        cdns->dr_mode = USB_DR_MODE_OTG;
 441
 442        if ((cdns->version == CDNSP_CONTROLLER_V2 &&
 443             state == OTGSTS_CDNSP_STRAP_HOST) ||
 444            (cdns->version != CDNSP_CONTROLLER_V2 &&
 445             state == OTGSTS_STRAP_HOST)) {
 446                dev_dbg(cdns->dev, "Controller strapped to HOST\n");
 447                cdns->dr_mode = USB_DR_MODE_HOST;
 448        } else if ((cdns->version == CDNSP_CONTROLLER_V2 &&
 449                    state == OTGSTS_CDNSP_STRAP_GADGET) ||
 450                   (cdns->version != CDNSP_CONTROLLER_V2 &&
 451                    state == OTGSTS_STRAP_GADGET)) {
 452                dev_dbg(cdns->dev, "Controller strapped to PERIPHERAL\n");
 453                cdns->dr_mode = USB_DR_MODE_PERIPHERAL;
 454        }
 455
 456        ret = devm_request_threaded_irq(cdns->dev, cdns->otg_irq,
 457                                        cdns_drd_irq,
 458                                        cdns_drd_thread_irq,
 459                                        IRQF_SHARED,
 460                                        dev_name(cdns->dev), cdns);
 461        if (ret) {
 462                dev_err(cdns->dev, "couldn't get otg_irq\n");
 463                return ret;
 464        }
 465
 466        state = readl(&cdns->otg_regs->sts);
 467        if (OTGSTS_OTG_NRDY(state)) {
 468                dev_err(cdns->dev, "Cadence USB3 OTG device not ready\n");
 469                return -ENODEV;
 470        }
 471
 472        return 0;
 473}
 474
 475int cdns_drd_exit(struct cdns *cdns)
 476{
 477        cdns_otg_disable_irq(cdns);
 478
 479        return 0;
 480}
 481
 482
 483/* Indicate the cdns3 core was power lost before */
 484bool cdns_power_is_lost(struct cdns *cdns)
 485{
 486        if (cdns->version == CDNS3_CONTROLLER_V1) {
 487                if (!(readl(&cdns->otg_v1_regs->simulate) & BIT(0)))
 488                        return true;
 489        } else {
 490                if (!(readl(&cdns->otg_v0_regs->simulate) & BIT(0)))
 491                        return true;
 492        }
 493        return false;
 494}
 495EXPORT_SYMBOL_GPL(cdns_power_is_lost);
 496