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