uboot/drivers/usb/mtu3/mtu3_plat.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 2016 MediaTek Inc.
   4 *
   5 * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
   6 */
   7
   8#include <common.h>
   9#include <dm/lists.h>
  10#include <linux/iopoll.h>
  11
  12#include "mtu3.h"
  13#include "mtu3_dr.h"
  14
  15void ssusb_set_force_mode(struct ssusb_mtk *ssusb,
  16                          enum mtu3_dr_force_mode mode)
  17{
  18        u32 value;
  19
  20        value = mtu3_readl(ssusb->ippc_base, SSUSB_U2_CTRL(0));
  21        switch (mode) {
  22        case MTU3_DR_FORCE_DEVICE:
  23                value |= SSUSB_U2_PORT_FORCE_IDDIG | SSUSB_U2_PORT_RG_IDDIG;
  24                break;
  25        case MTU3_DR_FORCE_HOST:
  26                value |= SSUSB_U2_PORT_FORCE_IDDIG;
  27                value &= ~SSUSB_U2_PORT_RG_IDDIG;
  28                break;
  29        case MTU3_DR_FORCE_NONE:
  30                value &= ~(SSUSB_U2_PORT_FORCE_IDDIG | SSUSB_U2_PORT_RG_IDDIG);
  31                break;
  32        default:
  33                return;
  34        }
  35        mtu3_writel(ssusb->ippc_base, SSUSB_U2_CTRL(0), value);
  36}
  37
  38/* u2-port0 should be powered on and enabled; */
  39int ssusb_check_clocks(struct ssusb_mtk *ssusb, u32 ex_clks)
  40{
  41        void __iomem *ibase = ssusb->ippc_base;
  42        u32 value, check_val;
  43        int ret;
  44
  45        check_val = ex_clks | SSUSB_SYS125_RST_B_STS | SSUSB_SYSPLL_STABLE |
  46                        SSUSB_REF_RST_B_STS;
  47
  48        ret = readl_poll_timeout(ibase + U3D_SSUSB_IP_PW_STS1, value,
  49                                 ((value & check_val) == check_val), 10000);
  50        if (ret) {
  51                dev_err(ssusb->dev, "clks of sts1 are not stable!\n");
  52                return ret;
  53        }
  54
  55        ret = readl_poll_timeout(ibase + U3D_SSUSB_IP_PW_STS2, value,
  56                                 (value & SSUSB_U2_MAC_SYS_RST_B_STS), 10000);
  57        if (ret) {
  58                dev_err(ssusb->dev, "mac2 clock is not stable\n");
  59                return ret;
  60        }
  61
  62        return 0;
  63}
  64
  65int ssusb_phy_setup(struct ssusb_mtk *ssusb)
  66{
  67        struct udevice *dev = ssusb->dev;
  68        struct phy_bulk *phys = &ssusb->phys;
  69        int ret;
  70
  71        ret = generic_phy_get_bulk(dev, phys);
  72        if (ret)
  73                return ret;
  74
  75        ret = generic_phy_init_bulk(phys);
  76        if (ret)
  77                return ret;
  78
  79        ret = generic_phy_power_on_bulk(phys);
  80        if (ret)
  81                generic_phy_exit_bulk(phys);
  82
  83        return ret;
  84}
  85
  86void ssusb_phy_shutdown(struct ssusb_mtk *ssusb)
  87{
  88        generic_phy_power_off_bulk(&ssusb->phys);
  89        generic_phy_exit_bulk(&ssusb->phys);
  90}
  91
  92static int ssusb_rscs_init(struct ssusb_mtk *ssusb)
  93{
  94        int ret = 0;
  95
  96        ret = regulator_set_enable(ssusb->vusb33_supply, true);
  97        if (ret < 0 && ret != -ENOSYS) {
  98                dev_err(ssusb->dev, "failed to enable vusb33\n");
  99                goto vusb33_err;
 100        }
 101
 102        ret = clk_enable_bulk(&ssusb->clks);
 103        if (ret)
 104                goto clks_err;
 105
 106        ret = ssusb_phy_setup(ssusb);
 107        if (ret) {
 108                dev_err(ssusb->dev, "failed to setup phy\n");
 109                goto phy_err;
 110        }
 111
 112        return 0;
 113
 114phy_err:
 115        clk_disable_bulk(&ssusb->clks);
 116clks_err:
 117        regulator_set_enable(ssusb->vusb33_supply, false);
 118vusb33_err:
 119        return ret;
 120}
 121
 122static void ssusb_rscs_exit(struct ssusb_mtk *ssusb)
 123{
 124        clk_disable_bulk(&ssusb->clks);
 125        regulator_set_enable(ssusb->vusb33_supply, false);
 126        ssusb_phy_shutdown(ssusb);
 127}
 128
 129static void ssusb_ip_sw_reset(struct ssusb_mtk *ssusb)
 130{
 131        /* reset whole ip (xhci & u3d) */
 132        mtu3_setbits(ssusb->ippc_base, U3D_SSUSB_IP_PW_CTRL0, SSUSB_IP_SW_RST);
 133        udelay(1);
 134        mtu3_clrbits(ssusb->ippc_base, U3D_SSUSB_IP_PW_CTRL0, SSUSB_IP_SW_RST);
 135}
 136
 137static int get_ssusb_rscs(struct udevice *dev, struct ssusb_mtk *ssusb)
 138{
 139        struct udevice *child;
 140        int ret;
 141
 142        ret = device_get_supply_regulator(dev, "vusb33-supply",
 143                                          &ssusb->vusb33_supply);
 144        if (ret)        /* optional, ignore error */
 145                dev_warn(dev, "can't get optional vusb33 %d\n", ret);
 146
 147        ret = device_get_supply_regulator(dev, "vbus-supply",
 148                                          &ssusb->vbus_supply);
 149        if (ret)        /* optional, ignore error */
 150                dev_warn(dev, "can't get optional vbus regulator %d!\n", ret);
 151
 152        ret = clk_get_bulk(dev, &ssusb->clks);
 153        if (ret) {
 154                dev_err(dev, "failed to get clocks %d!\n", ret);
 155                return ret;
 156        }
 157
 158        ssusb->ippc_base = devfdt_remap_addr_name(dev, "ippc");
 159        if (!ssusb->ippc_base) {
 160                dev_err(dev, "error mapping memory for ippc\n");
 161                return -ENODEV;
 162        }
 163
 164        ret = device_find_first_child(dev, &child);
 165        if (ret || !child) {
 166                dev_err(dev, "failed to get child %d!\n", ret);
 167                return ret;
 168        }
 169
 170        ssusb->mac_base = devfdt_remap_addr_name(child, "mac");
 171        if (!ssusb->mac_base) {
 172                dev_err(dev, "error mapping memory for mac\n");
 173                return -ENODEV;
 174        }
 175
 176        ssusb->dr_mode = usb_get_dr_mode(child->node);
 177
 178        if (ssusb->dr_mode == USB_DR_MODE_UNKNOWN ||
 179                ssusb->dr_mode == USB_DR_MODE_OTG)
 180                ssusb->dr_mode = USB_DR_MODE_PERIPHERAL;
 181
 182        if (IS_ENABLED(CONFIG_USB_MTU3_GADGET))
 183                ssusb->dr_mode = USB_DR_MODE_PERIPHERAL;
 184        else if (IS_ENABLED(CONFIG_USB_MTU3_HOST))
 185                ssusb->dr_mode = USB_DR_MODE_HOST;
 186
 187        dev_info(dev, "dr_mode: %d, ippc: 0x%p, mac: 0x%p\n",
 188                 ssusb->dr_mode, ssusb->ippc_base, ssusb->mac_base);
 189
 190        return 0;
 191}
 192
 193static int mtu3_probe(struct udevice *dev)
 194{
 195        struct ssusb_mtk *ssusb = dev_get_priv(dev);
 196        int ret = -ENOMEM;
 197
 198        ssusb->dev = dev;
 199
 200        ret = get_ssusb_rscs(dev, ssusb);
 201        if (ret)
 202                return ret;
 203
 204        ret = ssusb_rscs_init(ssusb);
 205        if (ret)
 206                return ret;
 207
 208        ssusb_ip_sw_reset(ssusb);
 209
 210        return 0;
 211}
 212
 213static int mtu3_remove(struct udevice *dev)
 214{
 215        struct ssusb_mtk *ssusb = dev_to_ssusb(dev);
 216
 217        ssusb_rscs_exit(ssusb);
 218        return 0;
 219}
 220
 221static const struct udevice_id ssusb_of_match[] = {
 222        {.compatible = "mediatek,ssusb",},
 223        {},
 224};
 225
 226#if CONFIG_IS_ENABLED(DM_USB_GADGET)
 227int dm_usb_gadget_handle_interrupts(struct udevice *dev)
 228{
 229        struct mtu3 *mtu = dev_get_priv(dev);
 230
 231        mtu3_irq(0, mtu);
 232
 233        return 0;
 234}
 235
 236static int mtu3_gadget_probe(struct udevice *dev)
 237{
 238        struct ssusb_mtk *ssusb = dev_to_ssusb(dev->parent);
 239        struct mtu3 *mtu = dev_get_priv(dev);
 240
 241        mtu->dev = dev;
 242        ssusb->u3d = mtu;
 243        return ssusb_gadget_init(ssusb);
 244}
 245
 246static int mtu3_gadget_remove(struct udevice *dev)
 247{
 248        struct mtu3 *mtu = dev_get_priv(dev);
 249
 250        ssusb_gadget_exit(mtu->ssusb);
 251        return 0;
 252}
 253
 254U_BOOT_DRIVER(mtu3_peripheral) = {
 255        .name = "mtu3-peripheral",
 256        .id = UCLASS_USB_GADGET_GENERIC,
 257        .of_match = ssusb_of_match,
 258        .probe = mtu3_gadget_probe,
 259        .remove = mtu3_gadget_remove,
 260        .priv_auto_alloc_size = sizeof(struct mtu3),
 261};
 262#endif
 263
 264#if defined(CONFIG_SPL_USB_HOST_SUPPORT) || \
 265        (!defined(CONFIG_SPL_BUILD) && defined(CONFIG_USB_HOST))
 266static int mtu3_host_probe(struct udevice *dev)
 267{
 268        struct ssusb_mtk *ssusb = dev_to_ssusb(dev->parent);
 269        struct mtu3_host *u3h = dev_get_priv(dev);
 270        struct xhci_hcor *hcor;
 271        int rc;
 272
 273        u3h->dev = dev;
 274        ssusb->u3h = u3h;
 275        rc = ssusb_host_init(ssusb);
 276        if (rc)
 277                return rc;
 278
 279        u3h->ctrl.quirks = XHCI_MTK_HOST;
 280        hcor = (struct xhci_hcor *)((uintptr_t)u3h->hcd +
 281                        HC_LENGTH(xhci_readl(&u3h->hcd->cr_capbase)));
 282
 283        return xhci_register(dev, u3h->hcd, hcor);
 284}
 285
 286static int mtu3_host_remove(struct udevice *dev)
 287{
 288        struct mtu3_host *u3h = dev_get_priv(dev);
 289
 290        xhci_deregister(dev);
 291        ssusb_host_exit(u3h->ssusb);
 292        return 0;
 293}
 294
 295U_BOOT_DRIVER(mtu3_host) = {
 296        .name = "mtu3-host",
 297        .id = UCLASS_USB,
 298        .of_match = ssusb_of_match,
 299        .probe = mtu3_host_probe,
 300        .remove = mtu3_host_remove,
 301        .priv_auto_alloc_size = sizeof(struct mtu3_host),
 302        .ops = &xhci_usb_ops,
 303        .flags = DM_FLAG_ALLOC_PRIV_DMA,
 304};
 305#endif
 306
 307static int mtu3_glue_bind(struct udevice *parent)
 308{
 309        struct udevice *dev;
 310        enum usb_dr_mode dr_mode;
 311        const char *driver;
 312        const char *name;
 313        ofnode node;
 314        int ret;
 315
 316        node = ofnode_by_compatible(parent->node, "mediatek,ssusb");
 317        if (!ofnode_valid(node))
 318                return -ENODEV;
 319
 320        name = ofnode_get_name(node);
 321        dr_mode = usb_get_dr_mode(node);
 322
 323        switch (dr_mode) {
 324#if CONFIG_IS_ENABLED(DM_USB_GADGET)
 325        case USB_DR_MODE_PERIPHERAL:
 326        case USB_DR_MODE_OTG:
 327                dev_dbg(parent, "%s: dr_mode: peripheral\n", __func__);
 328                driver = "mtu3-peripheral";
 329                break;
 330#endif
 331
 332#if defined(CONFIG_SPL_USB_HOST_SUPPORT) || \
 333        (!defined(CONFIG_SPL_BUILD) && defined(CONFIG_USB_HOST))
 334        case USB_DR_MODE_HOST:
 335                dev_dbg(parent, "%s: dr_mode: host\n", __func__);
 336                driver = "mtu3-host";
 337                break;
 338#endif
 339        default:
 340                dev_err(parent, "%s: unsupported dr_mode %d\n",
 341                        __func__, dr_mode);
 342                return -ENODEV;
 343        };
 344
 345        dev_dbg(parent, "%s: node name: %s, driver %s, dr_mode %d\n",
 346                __func__, name, driver, dr_mode);
 347
 348        ret = device_bind_driver_to_node(parent, driver, name, node, &dev);
 349        if (ret)
 350                dev_err(parent, "%s: not able to bind usb device mode\n",
 351                        __func__);
 352
 353        return ret;
 354}
 355
 356static const struct udevice_id mtu3_of_match[] = {
 357        {.compatible = "mediatek,mtu3",},
 358        {},
 359};
 360
 361U_BOOT_DRIVER(mtu3) = {
 362        .name = "mtu3",
 363        .id = UCLASS_NOP,
 364        .of_match = mtu3_of_match,
 365        .bind = mtu3_glue_bind,
 366        .probe = mtu3_probe,
 367        .remove = mtu3_remove,
 368        .priv_auto_alloc_size = sizeof(struct ssusb_mtk),
 369};
 370