uboot/drivers/phy/meson-g12a-usb3-pcie.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Meson G12A USB3+PCIE Combo PHY driver
   4 *
   5 * Copyright (C) 2018 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
   6 * Copyright (C) 2019 BayLibre, SAS
   7 * Author: Neil Armstrong <narmstron@baylibre.com>
   8 */
   9
  10#include <common.h>
  11#include <clk.h>
  12#include <dm.h>
  13#include <malloc.h>
  14#include <regmap.h>
  15#include <errno.h>
  16#include <asm/io.h>
  17#include <reset.h>
  18#include <bitfield.h>
  19#include <generic-phy.h>
  20#include <linux/delay.h>
  21
  22#include <linux/bitops.h>
  23#include <linux/compat.h>
  24#include <linux/bitfield.h>
  25
  26#define PHY_R0                                                  0x00
  27        #define PHY_R0_PCIE_POWER_STATE                         GENMASK(4, 0)
  28        #define PHY_R0_PCIE_USB3_SWITCH                         GENMASK(6, 5)
  29
  30#define PHY_R1                                                  0x04
  31        #define PHY_R1_PHY_TX1_TERM_OFFSET                      GENMASK(4, 0)
  32        #define PHY_R1_PHY_TX0_TERM_OFFSET                      GENMASK(9, 5)
  33        #define PHY_R1_PHY_RX1_EQ                               GENMASK(12, 10)
  34        #define PHY_R1_PHY_RX0_EQ                               GENMASK(15, 13)
  35        #define PHY_R1_PHY_LOS_LEVEL                            GENMASK(20, 16)
  36        #define PHY_R1_PHY_LOS_BIAS                             GENMASK(23, 21)
  37        #define PHY_R1_PHY_REF_CLKDIV2                          BIT(24)
  38        #define PHY_R1_PHY_MPLL_MULTIPLIER                      GENMASK(31, 25)
  39
  40#define PHY_R2                                                  0x08
  41        #define PHY_R2_PCS_TX_DEEMPH_GEN2_6DB                   GENMASK(5, 0)
  42        #define PHY_R2_PCS_TX_DEEMPH_GEN2_3P5DB                 GENMASK(11, 6)
  43        #define PHY_R2_PCS_TX_DEEMPH_GEN1                       GENMASK(17, 12)
  44        #define PHY_R2_PHY_TX_VBOOST_LVL                        GENMASK(20, 18)
  45
  46#define PHY_R4                                                  0x10
  47        #define PHY_R4_PHY_CR_WRITE                             BIT(0)
  48        #define PHY_R4_PHY_CR_READ                              BIT(1)
  49        #define PHY_R4_PHY_CR_DATA_IN                           GENMASK(17, 2)
  50        #define PHY_R4_PHY_CR_CAP_DATA                          BIT(18)
  51        #define PHY_R4_PHY_CR_CAP_ADDR                          BIT(19)
  52
  53#define PHY_R5                                                  0x14
  54        #define PHY_R5_PHY_CR_DATA_OUT                          GENMASK(15, 0)
  55        #define PHY_R5_PHY_CR_ACK                               BIT(16)
  56        #define PHY_R5_PHY_BS_OUT                               BIT(17)
  57
  58struct phy_g12a_usb3_pcie_priv {
  59        struct regmap           *regmap;
  60#if CONFIG_IS_ENABLED(CLK)
  61        struct clk              clk;
  62#endif
  63        struct reset_ctl_bulk   resets;
  64};
  65
  66static int phy_g12a_usb3_pcie_cr_bus_addr(struct phy_g12a_usb3_pcie_priv *priv,
  67                                          unsigned int addr)
  68{
  69        unsigned int val, reg;
  70        int ret;
  71
  72        reg = FIELD_PREP(PHY_R4_PHY_CR_DATA_IN, addr);
  73
  74        regmap_write(priv->regmap, PHY_R4, reg);
  75        regmap_write(priv->regmap, PHY_R4, reg);
  76
  77        regmap_write(priv->regmap, PHY_R4, reg | PHY_R4_PHY_CR_CAP_ADDR);
  78
  79        ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val,
  80                                       (val & PHY_R5_PHY_CR_ACK),
  81                                       5, 1000);
  82        if (ret)
  83                return ret;
  84
  85        regmap_write(priv->regmap, PHY_R4, reg);
  86
  87        ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val,
  88                                       !(val & PHY_R5_PHY_CR_ACK),
  89                                       5, 1000);
  90        if (ret)
  91                return ret;
  92
  93        return 0;
  94}
  95
  96static int
  97phy_g12a_usb3_pcie_cr_bus_read(struct phy_g12a_usb3_pcie_priv *priv,
  98                               unsigned int addr, unsigned int *data)
  99{
 100        unsigned int val;
 101        int ret;
 102
 103        ret = phy_g12a_usb3_pcie_cr_bus_addr(priv, addr);
 104        if (ret)
 105                return ret;
 106
 107        regmap_write(priv->regmap, PHY_R4, 0);
 108        regmap_write(priv->regmap, PHY_R4, PHY_R4_PHY_CR_READ);
 109
 110        ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val,
 111                                       (val & PHY_R5_PHY_CR_ACK),
 112                                       5, 1000);
 113        if (ret)
 114                return ret;
 115
 116        *data = FIELD_GET(PHY_R5_PHY_CR_DATA_OUT, val);
 117
 118        regmap_write(priv->regmap, PHY_R4, 0);
 119
 120        ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val,
 121                                       !(val & PHY_R5_PHY_CR_ACK),
 122                                       5, 1000);
 123        if (ret)
 124                return ret;
 125
 126        return 0;
 127}
 128
 129static int
 130phy_g12a_usb3_pcie_cr_bus_write(struct phy_g12a_usb3_pcie_priv *priv,
 131                                unsigned int addr, unsigned int data)
 132{
 133        unsigned int val, reg;
 134        int ret;
 135
 136        ret = phy_g12a_usb3_pcie_cr_bus_addr(priv, addr);
 137        if (ret)
 138                return ret;
 139
 140        reg = FIELD_PREP(PHY_R4_PHY_CR_DATA_IN, data);
 141
 142        regmap_write(priv->regmap, PHY_R4, reg);
 143        regmap_write(priv->regmap, PHY_R4, reg);
 144
 145        regmap_write(priv->regmap, PHY_R4, reg | PHY_R4_PHY_CR_CAP_DATA);
 146
 147        ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val,
 148                                       (val & PHY_R5_PHY_CR_ACK),
 149                                       5, 1000);
 150        if (ret)
 151                return ret;
 152
 153        regmap_write(priv->regmap, PHY_R4, reg);
 154
 155        ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val,
 156                                       (val & PHY_R5_PHY_CR_ACK) == 0,
 157                                       5, 1000);
 158        if (ret)
 159                return ret;
 160
 161        regmap_write(priv->regmap, PHY_R4, reg);
 162
 163        regmap_write(priv->regmap, PHY_R4, reg | PHY_R4_PHY_CR_WRITE);
 164
 165        ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val,
 166                                       (val & PHY_R5_PHY_CR_ACK),
 167                                       5, 1000);
 168        if (ret)
 169                return ret;
 170
 171        regmap_write(priv->regmap, PHY_R4, reg);
 172
 173        ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val,
 174                                       (val & PHY_R5_PHY_CR_ACK) == 0,
 175                                       5, 1000);
 176        if (ret)
 177                return ret;
 178
 179        return 0;
 180}
 181
 182static int
 183phy_g12a_usb3_pcie_cr_bus_update_bits(struct phy_g12a_usb3_pcie_priv *priv,
 184                                      uint offset, uint mask, uint val)
 185{
 186        uint reg;
 187        int ret;
 188
 189        ret = phy_g12a_usb3_pcie_cr_bus_read(priv, offset, &reg);
 190        if (ret)
 191                return ret;
 192
 193        reg &= ~mask;
 194
 195        return phy_g12a_usb3_pcie_cr_bus_write(priv, offset, reg | val);
 196}
 197
 198static int phy_meson_g12a_usb3_init(struct phy *phy)
 199{
 200        struct udevice *dev = phy->dev;
 201        struct phy_g12a_usb3_pcie_priv *priv = dev_get_priv(dev);
 202        unsigned int data;
 203        int ret;
 204
 205        /* TOFIX Handle PCIE mode */
 206
 207        ret = reset_assert_bulk(&priv->resets);
 208        udelay(1);
 209        ret |= reset_deassert_bulk(&priv->resets);
 210        if (ret)
 211                return ret;
 212
 213        /* Switch PHY to USB3 */
 214        regmap_update_bits(priv->regmap, PHY_R0,
 215                           PHY_R0_PCIE_USB3_SWITCH,
 216                           PHY_R0_PCIE_USB3_SWITCH);
 217
 218        /*
 219         * WORKAROUND: There is SSPHY suspend bug due to
 220         * which USB enumerates
 221         * in HS mode instead of SS mode. Workaround it by asserting
 222         * LANE0.TX_ALT_BLOCK.EN_ALT_BUS to enable TX to use alt bus
 223         * mode
 224         */
 225        ret = phy_g12a_usb3_pcie_cr_bus_update_bits(priv, 0x102d,
 226                                                    BIT(7), BIT(7));
 227        if (ret)
 228                return ret;
 229
 230        ret = phy_g12a_usb3_pcie_cr_bus_update_bits(priv, 0x1010, 0xff0, 20);
 231        if (ret)
 232                return ret;
 233
 234        /*
 235         * Fix RX Equalization setting as follows
 236         * LANE0.RX_OVRD_IN_HI. RX_EQ_EN set to 0
 237         * LANE0.RX_OVRD_IN_HI.RX_EQ_EN_OVRD set to 1
 238         * LANE0.RX_OVRD_IN_HI.RX_EQ set to 3
 239         * LANE0.RX_OVRD_IN_HI.RX_EQ_OVRD set to 1
 240         */
 241        ret = phy_g12a_usb3_pcie_cr_bus_read(priv, 0x1006, &data);
 242        if (ret)
 243                return ret;
 244
 245        data &= ~BIT(6);
 246        data |= BIT(7);
 247        data &= ~(0x7 << 8);
 248        data |= (0x3 << 8);
 249        data |= (1 << 11);
 250        ret = phy_g12a_usb3_pcie_cr_bus_write(priv, 0x1006, data);
 251        if (ret)
 252                return ret;
 253
 254        /*
 255         * Set EQ and TX launch amplitudes as follows
 256         * LANE0.TX_OVRD_DRV_LO.PREEMPH set to 22
 257         * LANE0.TX_OVRD_DRV_LO.AMPLITUDE set to 127
 258         * LANE0.TX_OVRD_DRV_LO.EN set to 1.
 259         */
 260        ret = phy_g12a_usb3_pcie_cr_bus_read(priv, 0x1002, &data);
 261        if (ret)
 262                return ret;
 263
 264        data &= ~0x3f80;
 265        data |= (0x16 << 7);
 266        data &= ~0x7f;
 267        data |= (0x7f | BIT(14));
 268        ret = phy_g12a_usb3_pcie_cr_bus_write(priv, 0x1002, data);
 269        if (ret)
 270                return ret;
 271
 272        /*
 273         * MPLL_LOOP_CTL.PROP_CNTRL = 8
 274         */
 275        ret = phy_g12a_usb3_pcie_cr_bus_update_bits(priv, 0x30,
 276                                                    0xf << 4, 8 << 4);
 277        if (ret)
 278                return ret;
 279
 280        regmap_update_bits(priv->regmap, PHY_R2,
 281                        PHY_R2_PHY_TX_VBOOST_LVL,
 282                        FIELD_PREP(PHY_R2_PHY_TX_VBOOST_LVL, 0x4));
 283
 284        regmap_update_bits(priv->regmap, PHY_R1,
 285                        PHY_R1_PHY_LOS_BIAS | PHY_R1_PHY_LOS_LEVEL,
 286                        FIELD_PREP(PHY_R1_PHY_LOS_BIAS, 4) |
 287                        FIELD_PREP(PHY_R1_PHY_LOS_LEVEL, 9));
 288
 289        return ret;
 290}
 291
 292static int phy_meson_g12a_usb3_exit(struct phy *phy)
 293{
 294        struct phy_g12a_usb3_pcie_priv *priv = dev_get_priv(phy->dev);
 295
 296        return reset_assert_bulk(&priv->resets);
 297}
 298
 299struct phy_ops meson_g12a_usb3_pcie_phy_ops = {
 300        .init = phy_meson_g12a_usb3_init,
 301        .exit = phy_meson_g12a_usb3_exit,
 302};
 303
 304int meson_g12a_usb3_pcie_phy_probe(struct udevice *dev)
 305{
 306        struct phy_g12a_usb3_pcie_priv *priv = dev_get_priv(dev);
 307        int ret;
 308
 309        ret = regmap_init_mem(dev_ofnode(dev), &priv->regmap);
 310        if (ret)
 311                return ret;
 312
 313        ret = reset_get_bulk(dev, &priv->resets);
 314        if (ret == -ENOTSUPP)
 315                return 0;
 316        else if (ret)
 317                return ret;
 318
 319#if CONFIG_IS_ENABLED(CLK)
 320        ret = clk_get_by_index(dev, 0, &priv->clk);
 321        if (ret < 0)
 322                return ret;
 323
 324        ret = clk_enable(&priv->clk);
 325        if (ret && ret != -ENOENT && ret != -ENOTSUPP) {
 326                pr_err("failed to enable PHY clock\n");
 327                clk_free(&priv->clk);
 328                return ret;
 329        }
 330#endif
 331
 332        return 0;
 333}
 334
 335static const struct udevice_id meson_g12a_usb3_pcie_phy_ids[] = {
 336        { .compatible = "amlogic,g12a-usb3-pcie-phy" },
 337        { }
 338};
 339
 340U_BOOT_DRIVER(meson_g12a_usb3_pcie_phy) = {
 341        .name = "meson_g12a_usb3_pcie_phy",
 342        .id = UCLASS_PHY,
 343        .of_match = meson_g12a_usb3_pcie_phy_ids,
 344        .probe = meson_g12a_usb3_pcie_phy_probe,
 345        .ops = &meson_g12a_usb3_pcie_phy_ops,
 346        .priv_auto_alloc_size = sizeof(struct phy_g12a_usb3_pcie_priv),
 347};
 348