uboot/drivers/pci/pcie_dw_meson.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Amlogic DesignWare based PCIe host controller driver
   4 *
   5 * Copyright (c) 2021 BayLibre, SAS
   6 * Author: Neil Armstrong <narmstrong@baylibre.com>
   7 *
   8 * Based on pcie_dw_rockchip.c
   9 * Copyright (c) 2021 Rockchip, Inc.
  10 */
  11
  12#include <common.h>
  13#include <clk.h>
  14#include <dm.h>
  15#include <generic-phy.h>
  16#include <pci.h>
  17#include <power-domain.h>
  18#include <reset.h>
  19#include <syscon.h>
  20#include <asm/global_data.h>
  21#include <asm/io.h>
  22#include <asm-generic/gpio.h>
  23#include <dm/device_compat.h>
  24#include <linux/iopoll.h>
  25#include <linux/delay.h>
  26#include <linux/log2.h>
  27#include <linux/bitfield.h>
  28
  29#include "pcie_dw_common.h"
  30
  31DECLARE_GLOBAL_DATA_PTR;
  32
  33/**
  34 * struct meson_pcie - Amlogic Meson DW PCIe controller state
  35 *
  36 * @pci: The common PCIe DW structure
  37 * @meson_cfg_base: The base address of vendor regs
  38 * @phy
  39 * @clk_port
  40 * @clk_general
  41 * @clk_pclk
  42 * @rsts
  43 * @rst_gpio: The #PERST signal for slot
  44 */
  45struct meson_pcie {
  46        /* Must be first member of the struct */
  47        struct pcie_dw dw;
  48        void *meson_cfg_base;
  49        struct phy phy;
  50        struct clk clk_port;
  51        struct clk clk_general;
  52        struct clk clk_pclk;
  53        struct reset_ctl_bulk rsts;
  54        struct gpio_desc rst_gpio;
  55};
  56
  57#define PCI_EXP_DEVCTL_PAYLOAD  0x00e0  /* Max_Payload_Size */
  58
  59#define PCIE_CAP_MAX_PAYLOAD_SIZE(x)    ((x) << 5)
  60#define PCIE_CAP_MAX_READ_REQ_SIZE(x)   ((x) << 12)
  61
  62/* PCIe specific config registers */
  63#define PCIE_CFG0                       0x0
  64#define APP_LTSSM_ENABLE                BIT(7)
  65
  66#define PCIE_CFG_STATUS12               0x30
  67#define IS_SMLH_LINK_UP(x)              ((x) & (1 << 6))
  68#define IS_RDLH_LINK_UP(x)              ((x) & (1 << 16))
  69#define IS_LTSSM_UP(x)                  ((((x) >> 10) & 0x1f) == 0x11)
  70
  71#define PCIE_CFG_STATUS17               0x44
  72#define PM_CURRENT_STATE(x)             (((x) >> 7) & 0x1)
  73
  74#define WAIT_LINKUP_TIMEOUT             4000
  75#define PORT_CLK_RATE                   100000000UL
  76#define MAX_PAYLOAD_SIZE                256
  77#define MAX_READ_REQ_SIZE               256
  78#define PCIE_RESET_DELAY                500
  79#define PCIE_SHARED_RESET               1
  80#define PCIE_NORMAL_RESET               0
  81
  82enum pcie_data_rate {
  83        PCIE_GEN1,
  84        PCIE_GEN2,
  85        PCIE_GEN3,
  86        PCIE_GEN4
  87};
  88
  89/* Parameters for the waiting for #perst signal */
  90#define PERST_WAIT_US                   1000000
  91
  92static inline u32 meson_cfg_readl(struct meson_pcie *priv, u32 reg)
  93{
  94        return readl(priv->meson_cfg_base + reg);
  95}
  96
  97static inline void meson_cfg_writel(struct meson_pcie *priv, u32 val, u32 reg)
  98{
  99        writel(val, priv->meson_cfg_base + reg);
 100}
 101
 102/**
 103 * meson_pcie_configure() - Configure link
 104 *
 105 * @meson_pcie: Pointer to the PCI controller state
 106 *
 107 * Configure the link mode and width
 108 */
 109static void meson_pcie_configure(struct meson_pcie *priv)
 110{
 111        u32 val;
 112
 113        dw_pcie_dbi_write_enable(&priv->dw, true);
 114
 115        val = readl(priv->dw.dbi_base + PCIE_PORT_LINK_CONTROL);
 116        val &= ~PORT_LINK_FAST_LINK_MODE;
 117        val |= PORT_LINK_DLL_LINK_EN;
 118        val &= ~PORT_LINK_MODE_MASK;
 119        val |= PORT_LINK_MODE_1_LANES;
 120        writel(val, priv->dw.dbi_base + PCIE_PORT_LINK_CONTROL);
 121
 122        val = readl(priv->dw.dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
 123        val &= ~PORT_LOGIC_LINK_WIDTH_MASK;
 124        val |= PORT_LOGIC_LINK_WIDTH_1_LANES;
 125        writel(val, priv->dw.dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
 126
 127        dw_pcie_dbi_write_enable(&priv->dw, false);
 128}
 129
 130static inline void meson_pcie_enable_ltssm(struct meson_pcie *priv)
 131{
 132        u32 val;
 133
 134        val = meson_cfg_readl(priv, PCIE_CFG0);
 135        val |= APP_LTSSM_ENABLE;
 136        meson_cfg_writel(priv, val, PCIE_CFG0);
 137}
 138
 139static int meson_pcie_wait_link_up(struct meson_pcie *priv)
 140{
 141        u32 speed_okay = 0;
 142        u32 cnt = 0;
 143        u32 state12, state17, smlh_up, ltssm_up, rdlh_up;
 144
 145        do {
 146                state12 = meson_cfg_readl(priv, PCIE_CFG_STATUS12);
 147                state17 = meson_cfg_readl(priv, PCIE_CFG_STATUS17);
 148                smlh_up = IS_SMLH_LINK_UP(state12);
 149                rdlh_up = IS_RDLH_LINK_UP(state12);
 150                ltssm_up = IS_LTSSM_UP(state12);
 151
 152                if (PM_CURRENT_STATE(state17) < PCIE_GEN3)
 153                        speed_okay = 1;
 154
 155                if (smlh_up)
 156                        debug("%s: smlh_link_up is on\n", __func__);
 157                if (rdlh_up)
 158                        debug("%s: rdlh_link_up is on\n", __func__);
 159                if (ltssm_up)
 160                        debug("%s: ltssm_up is on\n", __func__);
 161                if (speed_okay)
 162                        debug("%s: speed_okay\n", __func__);
 163
 164                if (smlh_up && rdlh_up && ltssm_up && speed_okay)
 165                        return 0;
 166
 167                cnt++;
 168
 169                udelay(10);
 170        } while (cnt < WAIT_LINKUP_TIMEOUT);
 171
 172        printf("%s: error: wait linkup timeout\n", __func__);
 173        return -EIO;
 174}
 175
 176/**
 177 * meson_pcie_link_up() - Wait for the link to come up
 178 *
 179 * @meson_pcie: Pointer to the PCI controller state
 180 * @cap_speed: Desired link speed
 181 *
 182 * Return: 1 (true) for active line and negative (false) for no link (timeout)
 183 */
 184static int meson_pcie_link_up(struct meson_pcie *priv, u32 cap_speed)
 185{
 186        /* DW link configurations */
 187        meson_pcie_configure(priv);
 188
 189        /* Reset the device */
 190        if (dm_gpio_is_valid(&priv->rst_gpio)) {
 191                dm_gpio_set_value(&priv->rst_gpio, 1);
 192                /*
 193                 * Minimal is 100ms from spec but we see
 194                 * some wired devices need much more, such as 600ms.
 195                 * Add a enough delay to cover all cases.
 196                 */
 197                udelay(PERST_WAIT_US);
 198                dm_gpio_set_value(&priv->rst_gpio, 0);
 199        }
 200
 201        /* Enable LTSSM */
 202        meson_pcie_enable_ltssm(priv);
 203
 204        return meson_pcie_wait_link_up(priv);
 205}
 206
 207static int meson_size_to_payload(int size)
 208{
 209        /*
 210         * dwc supports 2^(val+7) payload size, which val is 0~5 default to 1.
 211         * So if input size is not 2^order alignment or less than 2^7 or bigger
 212         * than 2^12, just set to default size 2^(1+7).
 213         */
 214        if (!is_power_of_2(size) || size < 128 || size > 4096) {
 215                debug("%s: payload size %d, set to default 256\n", __func__, size);
 216                return 1;
 217        }
 218
 219        return fls(size) - 8;
 220}
 221
 222static void meson_set_max_payload(struct meson_pcie *priv, int size)
 223{
 224        u32 val;
 225        u16 offset = dm_pci_find_capability(priv->dw.dev, PCI_CAP_ID_EXP);
 226        int max_payload_size = meson_size_to_payload(size);
 227
 228        dw_pcie_dbi_write_enable(&priv->dw, true);
 229
 230        val = readl(priv->dw.dbi_base + offset + PCI_EXP_DEVCTL);
 231        val &= ~PCI_EXP_DEVCTL_PAYLOAD;
 232        writel(val, priv->dw.dbi_base + offset + PCI_EXP_DEVCTL);
 233
 234        val = readl(priv->dw.dbi_base + offset + PCI_EXP_DEVCTL);
 235        val |= PCIE_CAP_MAX_PAYLOAD_SIZE(max_payload_size);
 236        writel(val, priv->dw.dbi_base + PCI_EXP_DEVCTL);
 237
 238        dw_pcie_dbi_write_enable(&priv->dw, false);
 239}
 240
 241static void meson_set_max_rd_req_size(struct meson_pcie *priv, int size)
 242{
 243        u32 val;
 244        u16 offset = dm_pci_find_capability(priv->dw.dev, PCI_CAP_ID_EXP);
 245        int max_rd_req_size = meson_size_to_payload(size);
 246
 247        dw_pcie_dbi_write_enable(&priv->dw, true);
 248
 249        val = readl(priv->dw.dbi_base + offset + PCI_EXP_DEVCTL);
 250        val &= ~PCI_EXP_DEVCTL_PAYLOAD;
 251        writel(val, priv->dw.dbi_base + offset + PCI_EXP_DEVCTL);
 252
 253        val = readl(priv->dw.dbi_base + offset + PCI_EXP_DEVCTL);
 254        val |= PCIE_CAP_MAX_READ_REQ_SIZE(max_rd_req_size);
 255        writel(val, priv->dw.dbi_base + PCI_EXP_DEVCTL);
 256
 257        dw_pcie_dbi_write_enable(&priv->dw, false);
 258}
 259
 260static int meson_pcie_init_port(struct udevice *dev)
 261{
 262        int ret;
 263        struct meson_pcie *priv = dev_get_priv(dev);
 264
 265        ret = generic_phy_init(&priv->phy);
 266        if (ret) {
 267                dev_err(dev, "failed to init phy (ret=%d)\n", ret);
 268                return ret;
 269        }
 270
 271        ret = generic_phy_power_on(&priv->phy);
 272        if (ret) {
 273                dev_err(dev, "failed to power on phy (ret=%d)\n", ret);
 274                goto err_exit_phy;
 275        }
 276
 277        ret = generic_phy_reset(&priv->phy);
 278        if (ret) {
 279                dev_err(dev, "failed to reset phy (ret=%d)\n", ret);
 280                goto err_exit_phy;
 281        }
 282
 283        ret = reset_assert_bulk(&priv->rsts);
 284        if (ret) {
 285                dev_err(dev, "failed to assert resets (ret=%d)\n", ret);
 286                goto err_power_off_phy;
 287        }
 288
 289        udelay(PCIE_RESET_DELAY);
 290
 291        ret = reset_deassert_bulk(&priv->rsts);
 292        if (ret) {
 293                dev_err(dev, "failed to deassert resets (ret=%d)\n", ret);
 294                goto err_power_off_phy;
 295        }
 296
 297        udelay(PCIE_RESET_DELAY);
 298
 299        ret = clk_set_rate(&priv->clk_port, PORT_CLK_RATE);
 300        if (ret) {
 301                dev_err(dev, "failed to set port clk rate (ret=%d)\n", ret);
 302                goto err_deassert_bulk;
 303        }
 304
 305        ret = clk_enable(&priv->clk_general);
 306        if (ret) {
 307                dev_err(dev, "failed to enable clk general (ret=%d)\n", ret);
 308                goto err_deassert_bulk;
 309        }
 310
 311        ret = clk_enable(&priv->clk_pclk);
 312        if (ret) {
 313                dev_err(dev, "failed to enable pclk (ret=%d)\n", ret);
 314                goto err_deassert_bulk;
 315        }
 316
 317        meson_set_max_payload(priv, MAX_PAYLOAD_SIZE);
 318        meson_set_max_rd_req_size(priv, MAX_READ_REQ_SIZE);
 319
 320        pcie_dw_setup_host(&priv->dw);
 321
 322        ret = meson_pcie_link_up(priv, LINK_SPEED_GEN_2);
 323        if (ret < 0)
 324                goto err_link_up;
 325
 326        return 0;
 327err_link_up:
 328        clk_disable(&priv->clk_port);
 329        clk_disable(&priv->clk_general);
 330        clk_disable(&priv->clk_pclk);
 331err_deassert_bulk:
 332        reset_assert_bulk(&priv->rsts);
 333err_power_off_phy:
 334        generic_phy_power_off(&priv->phy);
 335err_exit_phy:
 336        generic_phy_exit(&priv->phy);
 337
 338        return ret;
 339}
 340
 341static int meson_pcie_parse_dt(struct udevice *dev)
 342{
 343        struct meson_pcie *priv = dev_get_priv(dev);
 344        int ret;
 345
 346        priv->dw.dbi_base = (void *)dev_read_addr_index(dev, 0);
 347        if (!priv->dw.dbi_base)
 348                return -ENODEV;
 349
 350        dev_dbg(dev, "ELBI address is 0x%p\n", priv->dw.dbi_base);
 351
 352        priv->meson_cfg_base = (void *)dev_read_addr_index(dev, 1);
 353        if (!priv->meson_cfg_base)
 354                return -ENODEV;
 355
 356        dev_dbg(dev, "CFG address is 0x%p\n", priv->meson_cfg_base);
 357
 358        ret = gpio_request_by_name(dev, "reset-gpios", 0,
 359                                   &priv->rst_gpio, GPIOD_IS_OUT);
 360        if (ret) {
 361                dev_err(dev, "failed to find reset-gpios property\n");
 362                return ret;
 363        }
 364
 365        ret = reset_get_bulk(dev, &priv->rsts);
 366        if (ret) {
 367                dev_err(dev, "Can't get reset: %d\n", ret);
 368                return ret;
 369        }
 370
 371        ret = clk_get_by_name(dev, "port", &priv->clk_port);
 372        if (ret) {
 373                dev_err(dev, "Can't get port clock: %d\n", ret);
 374                return ret;
 375        }
 376
 377        ret = clk_get_by_name(dev, "general", &priv->clk_general);
 378        if (ret) {
 379                dev_err(dev, "Can't get port clock: %d\n", ret);
 380                return ret;
 381        }
 382
 383        ret = clk_get_by_name(dev, "pclk", &priv->clk_pclk);
 384        if (ret) {
 385                dev_err(dev, "Can't get port clock: %d\n", ret);
 386                return ret;
 387        }
 388
 389        ret = generic_phy_get_by_index(dev, 0, &priv->phy);
 390        if (ret) {
 391                dev_err(dev, "failed to get pcie phy (ret=%d)\n", ret);
 392                return ret;
 393        }
 394
 395        return 0;
 396}
 397
 398/**
 399 * meson_pcie_probe() - Probe the PCIe bus for active link
 400 *
 401 * @dev: A pointer to the device being operated on
 402 *
 403 * Probe for an active link on the PCIe bus and configure the controller
 404 * to enable this port.
 405 *
 406 * Return: 0 on success, else -ENODEV
 407 */
 408static int meson_pcie_probe(struct udevice *dev)
 409{
 410        struct meson_pcie *priv = dev_get_priv(dev);
 411        struct udevice *ctlr = pci_get_controller(dev);
 412        struct pci_controller *hose = dev_get_uclass_priv(ctlr);
 413        int ret = 0;
 414
 415        priv->dw.first_busno = dev_seq(dev);
 416        priv->dw.dev = dev;
 417
 418        ret = meson_pcie_parse_dt(dev);
 419        if (ret)
 420                return ret;
 421
 422        ret = meson_pcie_init_port(dev);
 423        if (ret) {
 424                dm_gpio_free(dev, &priv->rst_gpio);
 425                return ret;
 426        }
 427
 428        printf("PCIE-%d: Link up (Gen%d-x%d, Bus%d)\n",
 429               dev_seq(dev), pcie_dw_get_link_speed(&priv->dw),
 430               pcie_dw_get_link_width(&priv->dw),
 431               hose->first_busno);
 432
 433        return pcie_dw_prog_outbound_atu_unroll(&priv->dw,
 434                                                PCIE_ATU_REGION_INDEX0,
 435                                                PCIE_ATU_TYPE_MEM,
 436                                                priv->dw.mem.phys_start,
 437                                                priv->dw.mem.bus_start,
 438                                                priv->dw.mem.size);
 439}
 440
 441static const struct dm_pci_ops meson_pcie_ops = {
 442        .read_config    = pcie_dw_read_config,
 443        .write_config   = pcie_dw_write_config,
 444};
 445
 446static const struct udevice_id meson_pcie_ids[] = {
 447        { .compatible = "amlogic,axg-pcie" },
 448        { .compatible = "amlogic,g12a-pcie" },
 449        { }
 450};
 451
 452U_BOOT_DRIVER(meson_dw_pcie) = {
 453        .name                   = "pcie_dw_meson",
 454        .id                     = UCLASS_PCI,
 455        .of_match               = meson_pcie_ids,
 456        .ops                    = &meson_pcie_ops,
 457        .probe                  = meson_pcie_probe,
 458        .priv_auto              = sizeof(struct meson_pcie),
 459};
 460