linux/drivers/phy/socionext/phy-uniphier-ahci.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * phy-uniphier-ahci.c - PHY driver for UniPhier AHCI controller
   4 * Copyright 2016-2020, Socionext Inc.
   5 * Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
   6 */
   7
   8#include <linux/bitfield.h>
   9#include <linux/bitops.h>
  10#include <linux/clk.h>
  11#include <linux/iopoll.h>
  12#include <linux/module.h>
  13#include <linux/of.h>
  14#include <linux/of_platform.h>
  15#include <linux/phy/phy.h>
  16#include <linux/platform_device.h>
  17#include <linux/reset.h>
  18
  19struct uniphier_ahciphy_priv {
  20        struct device *dev;
  21        void __iomem  *base;
  22        struct clk *clk, *clk_parent, *clk_parent_gio;
  23        struct reset_control *rst, *rst_parent, *rst_parent_gio;
  24        struct reset_control *rst_pm, *rst_tx, *rst_rx;
  25        const struct uniphier_ahciphy_soc_data *data;
  26};
  27
  28struct uniphier_ahciphy_soc_data {
  29        int (*init)(struct uniphier_ahciphy_priv *priv);
  30        int (*power_on)(struct uniphier_ahciphy_priv *priv);
  31        int (*power_off)(struct uniphier_ahciphy_priv *priv);
  32        bool is_legacy;
  33        bool is_ready_high;
  34        bool is_phy_clk;
  35};
  36
  37/* for Pro4 */
  38#define CKCTRL0                         0x0
  39#define CKCTRL0_CK_OFF                  BIT(9)
  40#define CKCTRL0_NCY_MASK                GENMASK(8, 4)
  41#define CKCTRL0_NCY5_MASK               GENMASK(3, 2)
  42#define CKCTRL0_PRESCALE_MASK           GENMASK(1, 0)
  43#define CKCTRL1                         0x4
  44#define CKCTRL1_LOS_LVL_MASK            GENMASK(20, 16)
  45#define CKCTRL1_TX_LVL_MASK             GENMASK(12, 8)
  46#define RXTXCTRL                        0x8
  47#define RXTXCTRL_RX_EQ_VALL_MASK        GENMASK(31, 29)
  48#define RXTXCTRL_RX_DPLL_MODE_MASK      GENMASK(28, 26)
  49#define RXTXCTRL_TX_ATTEN_MASK          GENMASK(14, 12)
  50#define RXTXCTRL_TX_BOOST_MASK          GENMASK(11, 8)
  51#define RXTXCTRL_TX_EDGERATE_MASK       GENMASK(3, 2)
  52#define RXTXCTRL_TX_CKO_EN              BIT(0)
  53#define RSTPWR                          0x30
  54#define RSTPWR_RX_EN_VAL                BIT(18)
  55
  56/* for PXs2/PXs3 */
  57#define CKCTRL                          0x0
  58#define CKCTRL_P0_READY                 BIT(15)
  59#define CKCTRL_P0_RESET                 BIT(10)
  60#define CKCTRL_REF_SSP_EN               BIT(9)
  61#define TXCTRL0                         0x4
  62#define TXCTRL0_AMP_G3_MASK             GENMASK(22, 16)
  63#define TXCTRL0_AMP_G2_MASK             GENMASK(14, 8)
  64#define TXCTRL0_AMP_G1_MASK             GENMASK(6, 0)
  65#define TXCTRL1                         0x8
  66#define TXCTRL1_DEEMPH_G3_MASK          GENMASK(21, 16)
  67#define TXCTRL1_DEEMPH_G2_MASK          GENMASK(13, 8)
  68#define TXCTRL1_DEEMPH_G1_MASK          GENMASK(5, 0)
  69#define RXCTRL                          0xc
  70#define RXCTRL_LOS_LVL_MASK             GENMASK(20, 16)
  71#define RXCTRL_LOS_BIAS_MASK            GENMASK(10, 8)
  72#define RXCTRL_RX_EQ_MASK               GENMASK(2, 0)
  73
  74static int uniphier_ahciphy_pro4_init(struct uniphier_ahciphy_priv *priv)
  75{
  76        u32 val;
  77
  78        /* set phy MPLL parameters */
  79        val = readl(priv->base + CKCTRL0);
  80        val &= ~CKCTRL0_NCY_MASK;
  81        val |= FIELD_PREP(CKCTRL0_NCY_MASK, 0x6);
  82        val &= ~CKCTRL0_NCY5_MASK;
  83        val |= FIELD_PREP(CKCTRL0_NCY5_MASK, 0x2);
  84        val &= ~CKCTRL0_PRESCALE_MASK;
  85        val |= FIELD_PREP(CKCTRL0_PRESCALE_MASK, 0x1);
  86        writel(val, priv->base + CKCTRL0);
  87
  88        /* setup phy control parameters */
  89        val = readl(priv->base + CKCTRL1);
  90        val &= ~CKCTRL1_LOS_LVL_MASK;
  91        val |= FIELD_PREP(CKCTRL1_LOS_LVL_MASK, 0x10);
  92        val &= ~CKCTRL1_TX_LVL_MASK;
  93        val |= FIELD_PREP(CKCTRL1_TX_LVL_MASK, 0x06);
  94        writel(val, priv->base + CKCTRL1);
  95
  96        val = readl(priv->base + RXTXCTRL);
  97        val &= ~RXTXCTRL_RX_EQ_VALL_MASK;
  98        val |= FIELD_PREP(RXTXCTRL_RX_EQ_VALL_MASK, 0x6);
  99        val &= ~RXTXCTRL_RX_DPLL_MODE_MASK;
 100        val |= FIELD_PREP(RXTXCTRL_RX_DPLL_MODE_MASK, 0x3);
 101        val &= ~RXTXCTRL_TX_ATTEN_MASK;
 102        val |= FIELD_PREP(RXTXCTRL_TX_ATTEN_MASK, 0x3);
 103        val &= ~RXTXCTRL_TX_BOOST_MASK;
 104        val |= FIELD_PREP(RXTXCTRL_TX_BOOST_MASK, 0x5);
 105        val &= ~RXTXCTRL_TX_EDGERATE_MASK;
 106        val |= FIELD_PREP(RXTXCTRL_TX_EDGERATE_MASK, 0x0);
 107        writel(val, priv->base + RXTXCTRL);
 108
 109        return 0;
 110}
 111
 112static int uniphier_ahciphy_pro4_power_on(struct uniphier_ahciphy_priv *priv)
 113{
 114        u32 val;
 115        int ret;
 116
 117        /* enable reference clock for phy */
 118        val = readl(priv->base + CKCTRL0);
 119        val &= ~CKCTRL0_CK_OFF;
 120        writel(val, priv->base + CKCTRL0);
 121
 122        /* enable TX clock */
 123        val = readl(priv->base + RXTXCTRL);
 124        val |= RXTXCTRL_TX_CKO_EN;
 125        writel(val, priv->base + RXTXCTRL);
 126
 127        /* wait until RX is ready */
 128        ret = readl_poll_timeout(priv->base + RSTPWR, val,
 129                                 !(val & RSTPWR_RX_EN_VAL), 200, 2000);
 130        if (ret) {
 131                dev_err(priv->dev, "Failed to check whether Rx is ready\n");
 132                goto out_disable_clock;
 133        }
 134
 135        /* release all reset */
 136        ret = reset_control_deassert(priv->rst_pm);
 137        if (ret) {
 138                dev_err(priv->dev, "Failed to release PM reset\n");
 139                goto out_disable_clock;
 140        }
 141
 142        ret = reset_control_deassert(priv->rst_tx);
 143        if (ret) {
 144                dev_err(priv->dev, "Failed to release Tx reset\n");
 145                goto out_reset_pm_assert;
 146        }
 147
 148        ret = reset_control_deassert(priv->rst_rx);
 149        if (ret) {
 150                dev_err(priv->dev, "Failed to release Rx reset\n");
 151                goto out_reset_tx_assert;
 152        }
 153
 154        return 0;
 155
 156out_reset_tx_assert:
 157        reset_control_assert(priv->rst_tx);
 158out_reset_pm_assert:
 159        reset_control_assert(priv->rst_pm);
 160
 161out_disable_clock:
 162        /* disable TX clock */
 163        val = readl(priv->base + RXTXCTRL);
 164        val &= ~RXTXCTRL_TX_CKO_EN;
 165        writel(val, priv->base + RXTXCTRL);
 166
 167        /* disable reference clock for phy */
 168        val = readl(priv->base + CKCTRL0);
 169        val |= CKCTRL0_CK_OFF;
 170        writel(val, priv->base + CKCTRL0);
 171
 172        return ret;
 173}
 174
 175static int uniphier_ahciphy_pro4_power_off(struct uniphier_ahciphy_priv *priv)
 176{
 177        u32 val;
 178
 179        reset_control_assert(priv->rst_rx);
 180        reset_control_assert(priv->rst_tx);
 181        reset_control_assert(priv->rst_pm);
 182
 183        /* disable TX clock */
 184        val = readl(priv->base + RXTXCTRL);
 185        val &= ~RXTXCTRL_TX_CKO_EN;
 186        writel(val, priv->base + RXTXCTRL);
 187
 188        /* disable reference clock for phy */
 189        val = readl(priv->base + CKCTRL0);
 190        val |= CKCTRL0_CK_OFF;
 191        writel(val, priv->base + CKCTRL0);
 192
 193        return 0;
 194}
 195
 196static void uniphier_ahciphy_pxs2_enable(struct uniphier_ahciphy_priv *priv,
 197                                         bool enable)
 198{
 199        u32 val;
 200
 201        val = readl(priv->base + CKCTRL);
 202
 203        if (enable) {
 204                val |= CKCTRL_REF_SSP_EN;
 205                writel(val, priv->base + CKCTRL);
 206                val &= ~CKCTRL_P0_RESET;
 207                writel(val, priv->base + CKCTRL);
 208        } else {
 209                val |= CKCTRL_P0_RESET;
 210                writel(val, priv->base + CKCTRL);
 211                val &= ~CKCTRL_REF_SSP_EN;
 212                writel(val, priv->base + CKCTRL);
 213        }
 214}
 215
 216static int uniphier_ahciphy_pxs2_power_on(struct uniphier_ahciphy_priv *priv)
 217{
 218        int ret;
 219        u32 val;
 220
 221        uniphier_ahciphy_pxs2_enable(priv, true);
 222
 223        /* wait until PLL is ready */
 224        if (priv->data->is_ready_high)
 225                ret = readl_poll_timeout(priv->base + CKCTRL, val,
 226                                         (val & CKCTRL_P0_READY), 200, 400);
 227        else
 228                ret = readl_poll_timeout(priv->base + CKCTRL, val,
 229                                         !(val & CKCTRL_P0_READY), 200, 400);
 230        if (ret) {
 231                dev_err(priv->dev, "Failed to check whether PHY PLL is ready\n");
 232                uniphier_ahciphy_pxs2_enable(priv, false);
 233        }
 234
 235        return ret;
 236}
 237
 238static int uniphier_ahciphy_pxs2_power_off(struct uniphier_ahciphy_priv *priv)
 239{
 240        uniphier_ahciphy_pxs2_enable(priv, false);
 241
 242        return 0;
 243}
 244
 245static int uniphier_ahciphy_pxs3_init(struct uniphier_ahciphy_priv *priv)
 246{
 247        int i;
 248        u32 val;
 249
 250        /* setup port parameter */
 251        val = readl(priv->base + TXCTRL0);
 252        val &= ~TXCTRL0_AMP_G3_MASK;
 253        val |= FIELD_PREP(TXCTRL0_AMP_G3_MASK, 0x73);
 254        val &= ~TXCTRL0_AMP_G2_MASK;
 255        val |= FIELD_PREP(TXCTRL0_AMP_G2_MASK, 0x46);
 256        val &= ~TXCTRL0_AMP_G1_MASK;
 257        val |= FIELD_PREP(TXCTRL0_AMP_G1_MASK, 0x42);
 258        writel(val, priv->base + TXCTRL0);
 259
 260        val = readl(priv->base + TXCTRL1);
 261        val &= ~TXCTRL1_DEEMPH_G3_MASK;
 262        val |= FIELD_PREP(TXCTRL1_DEEMPH_G3_MASK, 0x23);
 263        val &= ~TXCTRL1_DEEMPH_G2_MASK;
 264        val |= FIELD_PREP(TXCTRL1_DEEMPH_G2_MASK, 0x05);
 265        val &= ~TXCTRL1_DEEMPH_G1_MASK;
 266        val |= FIELD_PREP(TXCTRL1_DEEMPH_G1_MASK, 0x05);
 267
 268        val = readl(priv->base + RXCTRL);
 269        val &= ~RXCTRL_LOS_LVL_MASK;
 270        val |= FIELD_PREP(RXCTRL_LOS_LVL_MASK, 0x9);
 271        val &= ~RXCTRL_LOS_BIAS_MASK;
 272        val |= FIELD_PREP(RXCTRL_LOS_BIAS_MASK, 0x2);
 273        val &= ~RXCTRL_RX_EQ_MASK;
 274        val |= FIELD_PREP(RXCTRL_RX_EQ_MASK, 0x1);
 275
 276        /* dummy read 25 times to make a wait time for the phy to stabilize */
 277        for (i = 0; i < 25; i++)
 278                readl(priv->base + CKCTRL);
 279
 280        return 0;
 281}
 282
 283static int uniphier_ahciphy_init(struct phy *phy)
 284{
 285        struct uniphier_ahciphy_priv *priv = phy_get_drvdata(phy);
 286        int ret;
 287
 288        ret = clk_prepare_enable(priv->clk_parent_gio);
 289        if (ret)
 290                return ret;
 291
 292        ret = clk_prepare_enable(priv->clk_parent);
 293        if (ret)
 294                goto out_clk_gio_disable;
 295
 296        ret = reset_control_deassert(priv->rst_parent_gio);
 297        if (ret)
 298                goto out_clk_disable;
 299
 300        ret = reset_control_deassert(priv->rst_parent);
 301        if (ret)
 302                goto out_rst_gio_assert;
 303
 304        if (priv->data->init) {
 305                ret = priv->data->init(priv);
 306                if (ret)
 307                        goto out_rst_assert;
 308        }
 309
 310        return 0;
 311
 312out_rst_assert:
 313        reset_control_assert(priv->rst_parent);
 314out_rst_gio_assert:
 315        reset_control_assert(priv->rst_parent_gio);
 316out_clk_disable:
 317        clk_disable_unprepare(priv->clk_parent);
 318out_clk_gio_disable:
 319        clk_disable_unprepare(priv->clk_parent_gio);
 320
 321        return ret;
 322}
 323
 324static int uniphier_ahciphy_exit(struct phy *phy)
 325{
 326        struct uniphier_ahciphy_priv *priv = phy_get_drvdata(phy);
 327
 328        reset_control_assert(priv->rst_parent);
 329        reset_control_assert(priv->rst_parent_gio);
 330        clk_disable_unprepare(priv->clk_parent);
 331        clk_disable_unprepare(priv->clk_parent_gio);
 332
 333        return 0;
 334}
 335
 336static int uniphier_ahciphy_power_on(struct phy *phy)
 337{
 338        struct uniphier_ahciphy_priv *priv = phy_get_drvdata(phy);
 339        int ret = 0;
 340
 341        ret = clk_prepare_enable(priv->clk);
 342        if (ret)
 343                return ret;
 344
 345        ret = reset_control_deassert(priv->rst);
 346        if (ret)
 347                goto out_clk_disable;
 348
 349        if (priv->data->power_on) {
 350                ret = priv->data->power_on(priv);
 351                if (ret)
 352                        goto out_reset_assert;
 353        }
 354
 355        return 0;
 356
 357out_reset_assert:
 358        reset_control_assert(priv->rst);
 359out_clk_disable:
 360        clk_disable_unprepare(priv->clk);
 361
 362        return ret;
 363}
 364
 365static int uniphier_ahciphy_power_off(struct phy *phy)
 366{
 367        struct uniphier_ahciphy_priv *priv = phy_get_drvdata(phy);
 368        int ret = 0;
 369
 370        if (priv->data->power_off)
 371                ret = priv->data->power_off(priv);
 372
 373        reset_control_assert(priv->rst);
 374        clk_disable_unprepare(priv->clk);
 375
 376        return ret;
 377}
 378
 379static const struct phy_ops uniphier_ahciphy_ops = {
 380        .init  = uniphier_ahciphy_init,
 381        .exit  = uniphier_ahciphy_exit,
 382        .power_on  = uniphier_ahciphy_power_on,
 383        .power_off = uniphier_ahciphy_power_off,
 384        .owner = THIS_MODULE,
 385};
 386
 387static int uniphier_ahciphy_probe(struct platform_device *pdev)
 388{
 389        struct device *dev = &pdev->dev;
 390        struct uniphier_ahciphy_priv *priv;
 391        struct phy *phy;
 392        struct phy_provider *phy_provider;
 393
 394        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 395        if (!priv)
 396                return -ENOMEM;
 397
 398        priv->dev = dev;
 399        priv->data = of_device_get_match_data(dev);
 400        if (WARN_ON(!priv->data))
 401                return -EINVAL;
 402
 403        priv->base = devm_platform_ioremap_resource(pdev, 0);
 404        if (IS_ERR(priv->base))
 405                return PTR_ERR(priv->base);
 406
 407        priv->clk_parent = devm_clk_get(dev, "link");
 408        if (IS_ERR(priv->clk_parent))
 409                return PTR_ERR(priv->clk_parent);
 410
 411        if (priv->data->is_phy_clk) {
 412                priv->clk = devm_clk_get(dev, "phy");
 413                if (IS_ERR(priv->clk))
 414                        return PTR_ERR(priv->clk);
 415        }
 416
 417        priv->rst_parent = devm_reset_control_get_shared(dev, "link");
 418        if (IS_ERR(priv->rst_parent))
 419                return PTR_ERR(priv->rst_parent);
 420
 421        priv->rst = devm_reset_control_get_shared(dev, "phy");
 422        if (IS_ERR(priv->rst))
 423                return PTR_ERR(priv->rst);
 424
 425        if (priv->data->is_legacy) {
 426                priv->clk_parent_gio = devm_clk_get(dev, "gio");
 427                if (IS_ERR(priv->clk_parent_gio))
 428                        return PTR_ERR(priv->clk_parent_gio);
 429                priv->rst_parent_gio =
 430                        devm_reset_control_get_shared(dev, "gio");
 431                if (IS_ERR(priv->rst_parent_gio))
 432                        return PTR_ERR(priv->rst_parent_gio);
 433
 434                priv->rst_pm = devm_reset_control_get_shared(dev, "pm");
 435                if (IS_ERR(priv->rst_pm))
 436                        return PTR_ERR(priv->rst_pm);
 437
 438                priv->rst_tx = devm_reset_control_get_shared(dev, "tx");
 439                if (IS_ERR(priv->rst_tx))
 440                        return PTR_ERR(priv->rst_tx);
 441
 442                priv->rst_rx = devm_reset_control_get_shared(dev, "rx");
 443                if (IS_ERR(priv->rst_rx))
 444                        return PTR_ERR(priv->rst_rx);
 445        }
 446
 447        phy = devm_phy_create(dev, dev->of_node, &uniphier_ahciphy_ops);
 448        if (IS_ERR(phy)) {
 449                dev_err(dev, "failed to create phy\n");
 450                return PTR_ERR(phy);
 451        }
 452
 453        phy_set_drvdata(phy, priv);
 454        phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
 455        if (IS_ERR(phy_provider))
 456                return PTR_ERR(phy_provider);
 457
 458        return 0;
 459}
 460
 461static const struct uniphier_ahciphy_soc_data uniphier_pro4_data = {
 462        .init = uniphier_ahciphy_pro4_init,
 463        .power_on  = uniphier_ahciphy_pro4_power_on,
 464        .power_off = uniphier_ahciphy_pro4_power_off,
 465        .is_legacy = true,
 466        .is_phy_clk = false,
 467};
 468
 469static const struct uniphier_ahciphy_soc_data uniphier_pxs2_data = {
 470        .power_on  = uniphier_ahciphy_pxs2_power_on,
 471        .power_off = uniphier_ahciphy_pxs2_power_off,
 472        .is_legacy = false,
 473        .is_ready_high = false,
 474        .is_phy_clk = false,
 475};
 476
 477static const struct uniphier_ahciphy_soc_data uniphier_pxs3_data = {
 478        .init      = uniphier_ahciphy_pxs3_init,
 479        .power_on  = uniphier_ahciphy_pxs2_power_on,
 480        .power_off = uniphier_ahciphy_pxs2_power_off,
 481        .is_legacy = false,
 482        .is_ready_high = true,
 483        .is_phy_clk = true,
 484};
 485
 486static const struct of_device_id uniphier_ahciphy_match[] = {
 487        {
 488                .compatible = "socionext,uniphier-pro4-ahci-phy",
 489                .data = &uniphier_pro4_data,
 490        },
 491        {
 492                .compatible = "socionext,uniphier-pxs2-ahci-phy",
 493                .data = &uniphier_pxs2_data,
 494        },
 495        {
 496                .compatible = "socionext,uniphier-pxs3-ahci-phy",
 497                .data = &uniphier_pxs3_data,
 498        },
 499        { /* Sentinel */ },
 500};
 501MODULE_DEVICE_TABLE(of, uniphier_ahciphy_match);
 502
 503static struct platform_driver uniphier_ahciphy_driver = {
 504        .probe = uniphier_ahciphy_probe,
 505        .driver = {
 506                .name = "uniphier-ahci-phy",
 507                .of_match_table = uniphier_ahciphy_match,
 508        },
 509};
 510module_platform_driver(uniphier_ahciphy_driver);
 511
 512MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
 513MODULE_DESCRIPTION("UniPhier PHY driver for AHCI controller");
 514MODULE_LICENSE("GPL v2");
 515