Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * PCIe host controller driver for Rockchip SoCs.
0004  *
0005  * Copyright (C) 2021 Rockchip Electronics Co., Ltd.
0006  *      http://www.rock-chips.com
0007  *
0008  * Author: Simon Xue <xxm@rock-chips.com>
0009  */
0010 
0011 #include <linux/clk.h>
0012 #include <linux/gpio/consumer.h>
0013 #include <linux/irqchip/chained_irq.h>
0014 #include <linux/irqdomain.h>
0015 #include <linux/mfd/syscon.h>
0016 #include <linux/module.h>
0017 #include <linux/of_device.h>
0018 #include <linux/of_irq.h>
0019 #include <linux/phy/phy.h>
0020 #include <linux/platform_device.h>
0021 #include <linux/regmap.h>
0022 #include <linux/reset.h>
0023 
0024 #include "pcie-designware.h"
0025 
0026 /*
0027  * The upper 16 bits of PCIE_CLIENT_CONFIG are a write
0028  * mask for the lower 16 bits.
0029  */
0030 #define HIWORD_UPDATE(mask, val) (((mask) << 16) | (val))
0031 #define HIWORD_UPDATE_BIT(val)  HIWORD_UPDATE(val, val)
0032 #define HIWORD_DISABLE_BIT(val) HIWORD_UPDATE(val, ~val)
0033 
0034 #define to_rockchip_pcie(x) dev_get_drvdata((x)->dev)
0035 
0036 #define PCIE_CLIENT_RC_MODE     HIWORD_UPDATE_BIT(0x40)
0037 #define PCIE_CLIENT_ENABLE_LTSSM    HIWORD_UPDATE_BIT(0xc)
0038 #define PCIE_SMLH_LINKUP        BIT(16)
0039 #define PCIE_RDLH_LINKUP        BIT(17)
0040 #define PCIE_LINKUP         (PCIE_SMLH_LINKUP | PCIE_RDLH_LINKUP)
0041 #define PCIE_L0S_ENTRY          0x11
0042 #define PCIE_CLIENT_GENERAL_CONTROL 0x0
0043 #define PCIE_CLIENT_INTR_STATUS_LEGACY  0x8
0044 #define PCIE_CLIENT_INTR_MASK_LEGACY    0x1c
0045 #define PCIE_CLIENT_GENERAL_DEBUG   0x104
0046 #define PCIE_CLIENT_HOT_RESET_CTRL  0x180
0047 #define PCIE_CLIENT_LTSSM_STATUS    0x300
0048 #define PCIE_LTSSM_ENABLE_ENHANCE   BIT(4)
0049 #define PCIE_LTSSM_STATUS_MASK      GENMASK(5, 0)
0050 
0051 struct rockchip_pcie {
0052     struct dw_pcie          pci;
0053     void __iomem            *apb_base;
0054     struct phy          *phy;
0055     struct clk_bulk_data        *clks;
0056     unsigned int            clk_cnt;
0057     struct reset_control        *rst;
0058     struct gpio_desc        *rst_gpio;
0059     struct regulator                *vpcie3v3;
0060     struct irq_domain       *irq_domain;
0061 };
0062 
0063 static int rockchip_pcie_readl_apb(struct rockchip_pcie *rockchip,
0064                          u32 reg)
0065 {
0066     return readl_relaxed(rockchip->apb_base + reg);
0067 }
0068 
0069 static void rockchip_pcie_writel_apb(struct rockchip_pcie *rockchip,
0070                         u32 val, u32 reg)
0071 {
0072     writel_relaxed(val, rockchip->apb_base + reg);
0073 }
0074 
0075 static void rockchip_pcie_legacy_int_handler(struct irq_desc *desc)
0076 {
0077     struct irq_chip *chip = irq_desc_get_chip(desc);
0078     struct rockchip_pcie *rockchip = irq_desc_get_handler_data(desc);
0079     unsigned long reg, hwirq;
0080 
0081     chained_irq_enter(chip, desc);
0082 
0083     reg = rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_INTR_STATUS_LEGACY);
0084 
0085     for_each_set_bit(hwirq, &reg, 4)
0086         generic_handle_domain_irq(rockchip->irq_domain, hwirq);
0087 
0088     chained_irq_exit(chip, desc);
0089 }
0090 
0091 static void rockchip_intx_mask(struct irq_data *data)
0092 {
0093     rockchip_pcie_writel_apb(irq_data_get_irq_chip_data(data),
0094                  HIWORD_UPDATE_BIT(BIT(data->hwirq)),
0095                  PCIE_CLIENT_INTR_MASK_LEGACY);
0096 };
0097 
0098 static void rockchip_intx_unmask(struct irq_data *data)
0099 {
0100     rockchip_pcie_writel_apb(irq_data_get_irq_chip_data(data),
0101                  HIWORD_DISABLE_BIT(BIT(data->hwirq)),
0102                  PCIE_CLIENT_INTR_MASK_LEGACY);
0103 };
0104 
0105 static struct irq_chip rockchip_intx_irq_chip = {
0106     .name           = "INTx",
0107     .irq_mask       = rockchip_intx_mask,
0108     .irq_unmask     = rockchip_intx_unmask,
0109     .flags          = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND,
0110 };
0111 
0112 static int rockchip_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
0113                   irq_hw_number_t hwirq)
0114 {
0115     irq_set_chip_and_handler(irq, &rockchip_intx_irq_chip, handle_level_irq);
0116     irq_set_chip_data(irq, domain->host_data);
0117 
0118     return 0;
0119 }
0120 
0121 static const struct irq_domain_ops intx_domain_ops = {
0122     .map = rockchip_pcie_intx_map,
0123 };
0124 
0125 static int rockchip_pcie_init_irq_domain(struct rockchip_pcie *rockchip)
0126 {
0127     struct device *dev = rockchip->pci.dev;
0128     struct device_node *intc;
0129 
0130     intc = of_get_child_by_name(dev->of_node, "legacy-interrupt-controller");
0131     if (!intc) {
0132         dev_err(dev, "missing child interrupt-controller node\n");
0133         return -EINVAL;
0134     }
0135 
0136     rockchip->irq_domain = irq_domain_add_linear(intc, PCI_NUM_INTX,
0137                             &intx_domain_ops, rockchip);
0138     of_node_put(intc);
0139     if (!rockchip->irq_domain) {
0140         dev_err(dev, "failed to get a INTx IRQ domain\n");
0141         return -EINVAL;
0142     }
0143 
0144     return 0;
0145 }
0146 
0147 static void rockchip_pcie_enable_ltssm(struct rockchip_pcie *rockchip)
0148 {
0149     rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_ENABLE_LTSSM,
0150                  PCIE_CLIENT_GENERAL_CONTROL);
0151 }
0152 
0153 static int rockchip_pcie_link_up(struct dw_pcie *pci)
0154 {
0155     struct rockchip_pcie *rockchip = to_rockchip_pcie(pci);
0156     u32 val = rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_LTSSM_STATUS);
0157 
0158     if ((val & PCIE_LINKUP) == PCIE_LINKUP &&
0159         (val & PCIE_LTSSM_STATUS_MASK) == PCIE_L0S_ENTRY)
0160         return 1;
0161 
0162     return 0;
0163 }
0164 
0165 static int rockchip_pcie_start_link(struct dw_pcie *pci)
0166 {
0167     struct rockchip_pcie *rockchip = to_rockchip_pcie(pci);
0168 
0169     /* Reset device */
0170     gpiod_set_value_cansleep(rockchip->rst_gpio, 0);
0171 
0172     rockchip_pcie_enable_ltssm(rockchip);
0173 
0174     /*
0175      * PCIe requires the refclk to be stable for 100µs prior to releasing
0176      * PERST. See table 2-4 in section 2.6.2 AC Specifications of the PCI
0177      * Express Card Electromechanical Specification, 1.1. However, we don't
0178      * know if the refclk is coming from RC's PHY or external OSC. If it's
0179      * from RC, so enabling LTSSM is the just right place to release #PERST.
0180      * We need more extra time as before, rather than setting just
0181      * 100us as we don't know how long should the device need to reset.
0182      */
0183     msleep(100);
0184     gpiod_set_value_cansleep(rockchip->rst_gpio, 1);
0185 
0186     return 0;
0187 }
0188 
0189 static int rockchip_pcie_host_init(struct dw_pcie_rp *pp)
0190 {
0191     struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
0192     struct rockchip_pcie *rockchip = to_rockchip_pcie(pci);
0193     struct device *dev = rockchip->pci.dev;
0194     u32 val = HIWORD_UPDATE_BIT(PCIE_LTSSM_ENABLE_ENHANCE);
0195     int irq, ret;
0196 
0197     irq = of_irq_get_byname(dev->of_node, "legacy");
0198     if (irq < 0)
0199         return irq;
0200 
0201     ret = rockchip_pcie_init_irq_domain(rockchip);
0202     if (ret < 0)
0203         dev_err(dev, "failed to init irq domain\n");
0204 
0205     irq_set_chained_handler_and_data(irq, rockchip_pcie_legacy_int_handler,
0206                      rockchip);
0207 
0208     /* LTSSM enable control mode */
0209     rockchip_pcie_writel_apb(rockchip, val, PCIE_CLIENT_HOT_RESET_CTRL);
0210 
0211     rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_RC_MODE,
0212                  PCIE_CLIENT_GENERAL_CONTROL);
0213 
0214     return 0;
0215 }
0216 
0217 static const struct dw_pcie_host_ops rockchip_pcie_host_ops = {
0218     .host_init = rockchip_pcie_host_init,
0219 };
0220 
0221 static int rockchip_pcie_clk_init(struct rockchip_pcie *rockchip)
0222 {
0223     struct device *dev = rockchip->pci.dev;
0224     int ret;
0225 
0226     ret = devm_clk_bulk_get_all(dev, &rockchip->clks);
0227     if (ret < 0)
0228         return ret;
0229 
0230     rockchip->clk_cnt = ret;
0231 
0232     return clk_bulk_prepare_enable(rockchip->clk_cnt, rockchip->clks);
0233 }
0234 
0235 static int rockchip_pcie_resource_get(struct platform_device *pdev,
0236                       struct rockchip_pcie *rockchip)
0237 {
0238     rockchip->apb_base = devm_platform_ioremap_resource_byname(pdev, "apb");
0239     if (IS_ERR(rockchip->apb_base))
0240         return PTR_ERR(rockchip->apb_base);
0241 
0242     rockchip->rst_gpio = devm_gpiod_get_optional(&pdev->dev, "reset",
0243                              GPIOD_OUT_HIGH);
0244     if (IS_ERR(rockchip->rst_gpio))
0245         return PTR_ERR(rockchip->rst_gpio);
0246 
0247     rockchip->rst = devm_reset_control_array_get_exclusive(&pdev->dev);
0248     if (IS_ERR(rockchip->rst))
0249         return dev_err_probe(&pdev->dev, PTR_ERR(rockchip->rst),
0250                      "failed to get reset lines\n");
0251 
0252     return 0;
0253 }
0254 
0255 static int rockchip_pcie_phy_init(struct rockchip_pcie *rockchip)
0256 {
0257     struct device *dev = rockchip->pci.dev;
0258     int ret;
0259 
0260     rockchip->phy = devm_phy_get(dev, "pcie-phy");
0261     if (IS_ERR(rockchip->phy))
0262         return dev_err_probe(dev, PTR_ERR(rockchip->phy),
0263                      "missing PHY\n");
0264 
0265     ret = phy_init(rockchip->phy);
0266     if (ret < 0)
0267         return ret;
0268 
0269     ret = phy_power_on(rockchip->phy);
0270     if (ret)
0271         phy_exit(rockchip->phy);
0272 
0273     return ret;
0274 }
0275 
0276 static void rockchip_pcie_phy_deinit(struct rockchip_pcie *rockchip)
0277 {
0278     phy_exit(rockchip->phy);
0279     phy_power_off(rockchip->phy);
0280 }
0281 
0282 static const struct dw_pcie_ops dw_pcie_ops = {
0283     .link_up = rockchip_pcie_link_up,
0284     .start_link = rockchip_pcie_start_link,
0285 };
0286 
0287 static int rockchip_pcie_probe(struct platform_device *pdev)
0288 {
0289     struct device *dev = &pdev->dev;
0290     struct rockchip_pcie *rockchip;
0291     struct dw_pcie_rp *pp;
0292     int ret;
0293 
0294     rockchip = devm_kzalloc(dev, sizeof(*rockchip), GFP_KERNEL);
0295     if (!rockchip)
0296         return -ENOMEM;
0297 
0298     platform_set_drvdata(pdev, rockchip);
0299 
0300     rockchip->pci.dev = dev;
0301     rockchip->pci.ops = &dw_pcie_ops;
0302 
0303     pp = &rockchip->pci.pp;
0304     pp->ops = &rockchip_pcie_host_ops;
0305 
0306     ret = rockchip_pcie_resource_get(pdev, rockchip);
0307     if (ret)
0308         return ret;
0309 
0310     ret = reset_control_assert(rockchip->rst);
0311     if (ret)
0312         return ret;
0313 
0314     /* DON'T MOVE ME: must be enable before PHY init */
0315     rockchip->vpcie3v3 = devm_regulator_get_optional(dev, "vpcie3v3");
0316     if (IS_ERR(rockchip->vpcie3v3)) {
0317         if (PTR_ERR(rockchip->vpcie3v3) != -ENODEV)
0318             return dev_err_probe(dev, PTR_ERR(rockchip->vpcie3v3),
0319                     "failed to get vpcie3v3 regulator\n");
0320         rockchip->vpcie3v3 = NULL;
0321     } else {
0322         ret = regulator_enable(rockchip->vpcie3v3);
0323         if (ret) {
0324             dev_err(dev, "failed to enable vpcie3v3 regulator\n");
0325             return ret;
0326         }
0327     }
0328 
0329     ret = rockchip_pcie_phy_init(rockchip);
0330     if (ret)
0331         goto disable_regulator;
0332 
0333     ret = reset_control_deassert(rockchip->rst);
0334     if (ret)
0335         goto deinit_phy;
0336 
0337     ret = rockchip_pcie_clk_init(rockchip);
0338     if (ret)
0339         goto deinit_phy;
0340 
0341     ret = dw_pcie_host_init(pp);
0342     if (!ret)
0343         return 0;
0344 
0345     clk_bulk_disable_unprepare(rockchip->clk_cnt, rockchip->clks);
0346 deinit_phy:
0347     rockchip_pcie_phy_deinit(rockchip);
0348 disable_regulator:
0349     if (rockchip->vpcie3v3)
0350         regulator_disable(rockchip->vpcie3v3);
0351 
0352     return ret;
0353 }
0354 
0355 static const struct of_device_id rockchip_pcie_of_match[] = {
0356     { .compatible = "rockchip,rk3568-pcie", },
0357     {},
0358 };
0359 
0360 static struct platform_driver rockchip_pcie_driver = {
0361     .driver = {
0362         .name   = "rockchip-dw-pcie",
0363         .of_match_table = rockchip_pcie_of_match,
0364         .suppress_bind_attrs = true,
0365     },
0366     .probe = rockchip_pcie_probe,
0367 };
0368 builtin_platform_driver(rockchip_pcie_driver);