linux/drivers/usb/cdns3/cdns3-imx.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * cdns3-imx.c - NXP i.MX specific Glue layer for Cadence USB Controller
   4 *
   5 * Copyright (C) 2019 NXP
   6 */
   7
   8#include <linux/bits.h>
   9#include <linux/clk.h>
  10#include <linux/module.h>
  11#include <linux/kernel.h>
  12#include <linux/interrupt.h>
  13#include <linux/platform_device.h>
  14#include <linux/dma-mapping.h>
  15#include <linux/io.h>
  16#include <linux/of_platform.h>
  17#include <linux/iopoll.h>
  18#include <linux/pm_runtime.h>
  19#include "core.h"
  20
  21#define USB3_CORE_CTRL1    0x00
  22#define USB3_CORE_CTRL2    0x04
  23#define USB3_INT_REG       0x08
  24#define USB3_CORE_STATUS   0x0c
  25#define XHCI_DEBUG_LINK_ST 0x10
  26#define XHCI_DEBUG_BUS     0x14
  27#define USB3_SSPHY_CTRL1   0x40
  28#define USB3_SSPHY_CTRL2   0x44
  29#define USB3_SSPHY_STATUS  0x4c
  30#define USB2_PHY_CTRL1     0x50
  31#define USB2_PHY_CTRL2     0x54
  32#define USB2_PHY_STATUS    0x5c
  33
  34/* Register bits definition */
  35
  36/* USB3_CORE_CTRL1 */
  37#define SW_RESET_MASK   GENMASK(31, 26)
  38#define PWR_SW_RESET    BIT(31)
  39#define APB_SW_RESET    BIT(30)
  40#define AXI_SW_RESET    BIT(29)
  41#define RW_SW_RESET     BIT(28)
  42#define PHY_SW_RESET    BIT(27)
  43#define PHYAHB_SW_RESET BIT(26)
  44#define ALL_SW_RESET    (PWR_SW_RESET | APB_SW_RESET | AXI_SW_RESET | \
  45                RW_SW_RESET | PHY_SW_RESET | PHYAHB_SW_RESET)
  46#define OC_DISABLE      BIT(9)
  47#define MDCTRL_CLK_SEL  BIT(7)
  48#define MODE_STRAP_MASK (0x7)
  49#define DEV_MODE        (1 << 2)
  50#define HOST_MODE       (1 << 1)
  51#define OTG_MODE        (1 << 0)
  52
  53/* USB3_INT_REG */
  54#define CLK_125_REQ     BIT(29)
  55#define LPM_CLK_REQ     BIT(28)
  56#define DEVU3_WAEKUP_EN BIT(14)
  57#define OTG_WAKEUP_EN   BIT(12)
  58#define DEV_INT_EN      (3 << 8) /* DEV INT b9:8 */
  59#define HOST_INT1_EN    (1 << 0) /* HOST INT b7:0 */
  60
  61/* USB3_CORE_STATUS */
  62#define MDCTRL_CLK_STATUS       BIT(15)
  63#define DEV_POWER_ON_READY      BIT(13)
  64#define HOST_POWER_ON_READY     BIT(12)
  65
  66/* USB3_SSPHY_STATUS */
  67#define CLK_VALID_MASK          (0x3f << 26)
  68#define CLK_VALID_COMPARE_BITS  (0xf << 28)
  69#define PHY_REFCLK_REQ          (1 << 0)
  70
  71/* OTG registers definition */
  72#define OTGSTS          0x4
  73/* OTGSTS */
  74#define OTG_NRDY        BIT(11)
  75
  76/* xHCI registers definition  */
  77#define XECP_PM_PMCSR           0x8018
  78#define XECP_AUX_CTRL_REG1      0x8120
  79
  80/* Register bits definition */
  81/* XECP_AUX_CTRL_REG1 */
  82#define CFG_RXDET_P3_EN         BIT(15)
  83
  84/* XECP_PM_PMCSR */
  85#define PS_MASK                 GENMASK(1, 0)
  86#define PS_D0                   0
  87#define PS_D1                   1
  88
  89struct cdns_imx {
  90        struct device *dev;
  91        void __iomem *noncore;
  92        struct clk_bulk_data *clks;
  93        int num_clks;
  94        struct platform_device *cdns3_pdev;
  95};
  96
  97static inline u32 cdns_imx_readl(struct cdns_imx *data, u32 offset)
  98{
  99        return readl(data->noncore + offset);
 100}
 101
 102static inline void cdns_imx_writel(struct cdns_imx *data, u32 offset, u32 value)
 103{
 104        writel(value, data->noncore + offset);
 105}
 106
 107static const struct clk_bulk_data imx_cdns3_core_clks[] = {
 108        { .id = "usb3_lpm_clk" },
 109        { .id = "usb3_bus_clk" },
 110        { .id = "usb3_aclk" },
 111        { .id = "usb3_ipg_clk" },
 112        { .id = "usb3_core_pclk" },
 113};
 114
 115static int cdns_imx_noncore_init(struct cdns_imx *data)
 116{
 117        u32 value;
 118        int ret;
 119        struct device *dev = data->dev;
 120
 121        cdns_imx_writel(data, USB3_SSPHY_STATUS, CLK_VALID_MASK);
 122        udelay(1);
 123        ret = readl_poll_timeout(data->noncore + USB3_SSPHY_STATUS, value,
 124                (value & CLK_VALID_COMPARE_BITS) == CLK_VALID_COMPARE_BITS,
 125                10, 100000);
 126        if (ret) {
 127                dev_err(dev, "wait clkvld timeout\n");
 128                return ret;
 129        }
 130
 131        value = cdns_imx_readl(data, USB3_CORE_CTRL1);
 132        value |= ALL_SW_RESET;
 133        cdns_imx_writel(data, USB3_CORE_CTRL1, value);
 134        udelay(1);
 135
 136        value = cdns_imx_readl(data, USB3_CORE_CTRL1);
 137        value = (value & ~MODE_STRAP_MASK) | OTG_MODE | OC_DISABLE;
 138        cdns_imx_writel(data, USB3_CORE_CTRL1, value);
 139
 140        value = cdns_imx_readl(data, USB3_INT_REG);
 141        value |= HOST_INT1_EN | DEV_INT_EN;
 142        cdns_imx_writel(data, USB3_INT_REG, value);
 143
 144        value = cdns_imx_readl(data, USB3_CORE_CTRL1);
 145        value &= ~ALL_SW_RESET;
 146        cdns_imx_writel(data, USB3_CORE_CTRL1, value);
 147        return ret;
 148}
 149
 150static int cdns_imx_platform_suspend(struct device *dev,
 151        bool suspend, bool wakeup);
 152static struct cdns3_platform_data cdns_imx_pdata = {
 153        .platform_suspend = cdns_imx_platform_suspend,
 154        .quirks           = CDNS3_DEFAULT_PM_RUNTIME_ALLOW,
 155};
 156
 157static const struct of_dev_auxdata cdns_imx_auxdata[] = {
 158        {
 159                .compatible = "cdns,usb3",
 160                .platform_data = &cdns_imx_pdata,
 161        },
 162        {},
 163};
 164
 165static int cdns_imx_probe(struct platform_device *pdev)
 166{
 167        struct device *dev = &pdev->dev;
 168        struct device_node *node = dev->of_node;
 169        struct cdns_imx *data;
 170        int ret;
 171
 172        if (!node)
 173                return -ENODEV;
 174
 175        data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
 176        if (!data)
 177                return -ENOMEM;
 178
 179        platform_set_drvdata(pdev, data);
 180        data->dev = dev;
 181        data->noncore = devm_platform_ioremap_resource(pdev, 0);
 182        if (IS_ERR(data->noncore)) {
 183                dev_err(dev, "can't map IOMEM resource\n");
 184                return PTR_ERR(data->noncore);
 185        }
 186
 187        data->num_clks = ARRAY_SIZE(imx_cdns3_core_clks);
 188        data->clks = devm_kmemdup(dev, imx_cdns3_core_clks,
 189                                sizeof(imx_cdns3_core_clks), GFP_KERNEL);
 190        if (!data->clks)
 191                return -ENOMEM;
 192
 193        ret = devm_clk_bulk_get(dev, data->num_clks, data->clks);
 194        if (ret)
 195                return ret;
 196
 197        ret = clk_bulk_prepare_enable(data->num_clks, data->clks);
 198        if (ret)
 199                return ret;
 200
 201        ret = cdns_imx_noncore_init(data);
 202        if (ret)
 203                goto err;
 204
 205        ret = of_platform_populate(node, NULL, cdns_imx_auxdata, dev);
 206        if (ret) {
 207                dev_err(dev, "failed to create children: %d\n", ret);
 208                goto err;
 209        }
 210
 211        device_set_wakeup_capable(dev, true);
 212        pm_runtime_set_active(dev);
 213        pm_runtime_enable(dev);
 214
 215        return ret;
 216err:
 217        clk_bulk_disable_unprepare(data->num_clks, data->clks);
 218        return ret;
 219}
 220
 221static int cdns_imx_remove(struct platform_device *pdev)
 222{
 223        struct device *dev = &pdev->dev;
 224        struct cdns_imx *data = dev_get_drvdata(dev);
 225
 226        pm_runtime_get_sync(dev);
 227        of_platform_depopulate(dev);
 228        clk_bulk_disable_unprepare(data->num_clks, data->clks);
 229        pm_runtime_disable(dev);
 230        pm_runtime_put_noidle(dev);
 231        platform_set_drvdata(pdev, NULL);
 232
 233        return 0;
 234}
 235
 236#ifdef CONFIG_PM
 237static void cdns3_set_wakeup(struct cdns_imx *data, bool enable)
 238{
 239        u32 value;
 240
 241        value = cdns_imx_readl(data, USB3_INT_REG);
 242        if (enable)
 243                value |= OTG_WAKEUP_EN | DEVU3_WAEKUP_EN;
 244        else
 245                value &= ~(OTG_WAKEUP_EN | DEVU3_WAEKUP_EN);
 246
 247        cdns_imx_writel(data, USB3_INT_REG, value);
 248}
 249
 250static int cdns_imx_platform_suspend(struct device *dev,
 251                bool suspend, bool wakeup)
 252{
 253        struct cdns *cdns = dev_get_drvdata(dev);
 254        struct device *parent = dev->parent;
 255        struct cdns_imx *data = dev_get_drvdata(parent);
 256        void __iomem *otg_regs = (void __iomem *)(cdns->otg_regs);
 257        void __iomem *xhci_regs = cdns->xhci_regs;
 258        u32 value;
 259        int ret = 0;
 260
 261        if (cdns->role != USB_ROLE_HOST)
 262                return 0;
 263
 264        if (suspend) {
 265                /* SW request low power when all usb ports allow to it ??? */
 266                value = readl(xhci_regs + XECP_PM_PMCSR);
 267                value &= ~PS_MASK;
 268                value |= PS_D1;
 269                writel(value, xhci_regs + XECP_PM_PMCSR);
 270
 271                /* mdctrl_clk_sel */
 272                value = cdns_imx_readl(data, USB3_CORE_CTRL1);
 273                value |= MDCTRL_CLK_SEL;
 274                cdns_imx_writel(data, USB3_CORE_CTRL1, value);
 275
 276                /* wait for mdctrl_clk_status */
 277                value = cdns_imx_readl(data, USB3_CORE_STATUS);
 278                ret = readl_poll_timeout(data->noncore + USB3_CORE_STATUS, value,
 279                        (value & MDCTRL_CLK_STATUS) == MDCTRL_CLK_STATUS,
 280                        10, 100000);
 281                if (ret)
 282                        dev_warn(parent, "wait mdctrl_clk_status timeout\n");
 283
 284                /* wait lpm_clk_req to be 0 */
 285                value = cdns_imx_readl(data, USB3_INT_REG);
 286                ret = readl_poll_timeout(data->noncore + USB3_INT_REG, value,
 287                        (value & LPM_CLK_REQ) != LPM_CLK_REQ,
 288                        10, 100000);
 289                if (ret)
 290                        dev_warn(parent, "wait lpm_clk_req timeout\n");
 291
 292                /* wait phy_refclk_req to be 0 */
 293                value = cdns_imx_readl(data, USB3_SSPHY_STATUS);
 294                ret = readl_poll_timeout(data->noncore + USB3_SSPHY_STATUS, value,
 295                        (value & PHY_REFCLK_REQ) != PHY_REFCLK_REQ,
 296                        10, 100000);
 297                if (ret)
 298                        dev_warn(parent, "wait phy_refclk_req timeout\n");
 299
 300                cdns3_set_wakeup(data, wakeup);
 301        } else {
 302                cdns3_set_wakeup(data, false);
 303
 304                /* SW request D0 */
 305                value = readl(xhci_regs + XECP_PM_PMCSR);
 306                value &= ~PS_MASK;
 307                value |= PS_D0;
 308                writel(value, xhci_regs + XECP_PM_PMCSR);
 309
 310                /* clr CFG_RXDET_P3_EN */
 311                value = readl(xhci_regs + XECP_AUX_CTRL_REG1);
 312                value &= ~CFG_RXDET_P3_EN;
 313                writel(value, xhci_regs + XECP_AUX_CTRL_REG1);
 314
 315                /* clear mdctrl_clk_sel */
 316                value = cdns_imx_readl(data, USB3_CORE_CTRL1);
 317                value &= ~MDCTRL_CLK_SEL;
 318                cdns_imx_writel(data, USB3_CORE_CTRL1, value);
 319
 320                /* wait CLK_125_REQ to be 1 */
 321                value = cdns_imx_readl(data, USB3_INT_REG);
 322                ret = readl_poll_timeout(data->noncore + USB3_INT_REG, value,
 323                        (value & CLK_125_REQ) == CLK_125_REQ,
 324                        10, 100000);
 325                if (ret)
 326                        dev_warn(parent, "wait CLK_125_REQ timeout\n");
 327
 328                /* wait for mdctrl_clk_status is cleared */
 329                value = cdns_imx_readl(data, USB3_CORE_STATUS);
 330                ret = readl_poll_timeout(data->noncore + USB3_CORE_STATUS, value,
 331                        (value & MDCTRL_CLK_STATUS) != MDCTRL_CLK_STATUS,
 332                        10, 100000);
 333                if (ret)
 334                        dev_warn(parent, "wait mdctrl_clk_status cleared timeout\n");
 335
 336                /* Wait until OTG_NRDY is 0 */
 337                value = readl(otg_regs + OTGSTS);
 338                ret = readl_poll_timeout(otg_regs + OTGSTS, value,
 339                        (value & OTG_NRDY) != OTG_NRDY,
 340                        10, 100000);
 341                if (ret)
 342                        dev_warn(parent, "wait OTG ready timeout\n");
 343        }
 344
 345        return ret;
 346
 347}
 348
 349static int cdns_imx_resume(struct device *dev)
 350{
 351        struct cdns_imx *data = dev_get_drvdata(dev);
 352
 353        return clk_bulk_prepare_enable(data->num_clks, data->clks);
 354}
 355
 356static int cdns_imx_suspend(struct device *dev)
 357{
 358        struct cdns_imx *data = dev_get_drvdata(dev);
 359
 360        clk_bulk_disable_unprepare(data->num_clks, data->clks);
 361
 362        return 0;
 363}
 364
 365
 366/* Indicate if the controller was power lost before */
 367static inline bool cdns_imx_is_power_lost(struct cdns_imx *data)
 368{
 369        u32 value;
 370
 371        value = cdns_imx_readl(data, USB3_CORE_CTRL1);
 372        if ((value & SW_RESET_MASK) == ALL_SW_RESET)
 373                return true;
 374        else
 375                return false;
 376}
 377
 378static int __maybe_unused cdns_imx_system_resume(struct device *dev)
 379{
 380        struct cdns_imx *data = dev_get_drvdata(dev);
 381        int ret;
 382
 383        ret = cdns_imx_resume(dev);
 384        if (ret)
 385                return ret;
 386
 387        if (cdns_imx_is_power_lost(data)) {
 388                dev_dbg(dev, "resume from power lost\n");
 389                ret = cdns_imx_noncore_init(data);
 390                if (ret)
 391                        cdns_imx_suspend(dev);
 392        }
 393
 394        return ret;
 395}
 396
 397#else
 398static int cdns_imx_platform_suspend(struct device *dev,
 399        bool suspend, bool wakeup)
 400{
 401        return 0;
 402}
 403
 404#endif /* CONFIG_PM */
 405
 406static const struct dev_pm_ops cdns_imx_pm_ops = {
 407        SET_RUNTIME_PM_OPS(cdns_imx_suspend, cdns_imx_resume, NULL)
 408        SET_SYSTEM_SLEEP_PM_OPS(cdns_imx_suspend, cdns_imx_system_resume)
 409};
 410
 411static const struct of_device_id cdns_imx_of_match[] = {
 412        { .compatible = "fsl,imx8qm-usb3", },
 413        {},
 414};
 415MODULE_DEVICE_TABLE(of, cdns_imx_of_match);
 416
 417static struct platform_driver cdns_imx_driver = {
 418        .probe          = cdns_imx_probe,
 419        .remove         = cdns_imx_remove,
 420        .driver         = {
 421                .name   = "cdns3-imx",
 422                .of_match_table = cdns_imx_of_match,
 423                .pm     = &cdns_imx_pm_ops,
 424        },
 425};
 426module_platform_driver(cdns_imx_driver);
 427
 428MODULE_ALIAS("platform:cdns3-imx");
 429MODULE_AUTHOR("Peter Chen <peter.chen@nxp.com>");
 430MODULE_LICENSE("GPL v2");
 431MODULE_DESCRIPTION("Cadence USB3 i.MX Glue Layer");
 432