410 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * PCIe host controller driver for UniPhier SoCs4 * Copyright 2018 Socionext Inc.5 * Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>6 */7 8#include <linux/bitops.h>9#include <linux/bitfield.h>10#include <linux/clk.h>11#include <linux/delay.h>12#include <linux/init.h>13#include <linux/interrupt.h>14#include <linux/iopoll.h>15#include <linux/irqchip/chained_irq.h>16#include <linux/irqdomain.h>17#include <linux/of_irq.h>18#include <linux/pci.h>19#include <linux/phy/phy.h>20#include <linux/platform_device.h>21#include <linux/reset.h>22 23#include "pcie-designware.h"24 25#define PCL_PINCTRL0 0x002c26#define PCL_PERST_PLDN_REGEN BIT(12)27#define PCL_PERST_NOE_REGEN BIT(11)28#define PCL_PERST_OUT_REGEN BIT(8)29#define PCL_PERST_PLDN_REGVAL BIT(4)30#define PCL_PERST_NOE_REGVAL BIT(3)31#define PCL_PERST_OUT_REGVAL BIT(0)32 33#define PCL_PIPEMON 0x004434#define PCL_PCLK_ALIVE BIT(15)35 36#define PCL_MODE 0x800037#define PCL_MODE_REGEN BIT(8)38#define PCL_MODE_REGVAL BIT(0)39 40#define PCL_APP_READY_CTRL 0x800841#define PCL_APP_LTSSM_ENABLE BIT(0)42 43#define PCL_APP_PM0 0x807844#define PCL_SYS_AUX_PWR_DET BIT(8)45 46#define PCL_RCV_INT 0x810847#define PCL_RCV_INT_ALL_ENABLE GENMASK(20, 17)48#define PCL_CFG_BW_MGT_STATUS BIT(4)49#define PCL_CFG_LINK_AUTO_BW_STATUS BIT(3)50#define PCL_CFG_AER_RC_ERR_MSI_STATUS BIT(2)51#define PCL_CFG_PME_MSI_STATUS BIT(1)52 53#define PCL_RCV_INTX 0x810c54#define PCL_RCV_INTX_ALL_ENABLE GENMASK(19, 16)55#define PCL_RCV_INTX_ALL_MASK GENMASK(11, 8)56#define PCL_RCV_INTX_MASK_SHIFT 857#define PCL_RCV_INTX_ALL_STATUS GENMASK(3, 0)58#define PCL_RCV_INTX_STATUS_SHIFT 059 60#define PCL_STATUS_LINK 0x814061#define PCL_RDLH_LINK_UP BIT(1)62#define PCL_XMLH_LINK_UP BIT(0)63 64struct uniphier_pcie {65 struct dw_pcie pci;66 void __iomem *base;67 struct clk *clk;68 struct reset_control *rst;69 struct phy *phy;70 struct irq_domain *intx_irq_domain;71};72 73#define to_uniphier_pcie(x) dev_get_drvdata((x)->dev)74 75static void uniphier_pcie_ltssm_enable(struct uniphier_pcie *pcie,76 bool enable)77{78 u32 val;79 80 val = readl(pcie->base + PCL_APP_READY_CTRL);81 if (enable)82 val |= PCL_APP_LTSSM_ENABLE;83 else84 val &= ~PCL_APP_LTSSM_ENABLE;85 writel(val, pcie->base + PCL_APP_READY_CTRL);86}87 88static void uniphier_pcie_init_rc(struct uniphier_pcie *pcie)89{90 u32 val;91 92 /* set RC MODE */93 val = readl(pcie->base + PCL_MODE);94 val |= PCL_MODE_REGEN;95 val &= ~PCL_MODE_REGVAL;96 writel(val, pcie->base + PCL_MODE);97 98 /* use auxiliary power detection */99 val = readl(pcie->base + PCL_APP_PM0);100 val |= PCL_SYS_AUX_PWR_DET;101 writel(val, pcie->base + PCL_APP_PM0);102 103 /* assert PERST# */104 val = readl(pcie->base + PCL_PINCTRL0);105 val &= ~(PCL_PERST_NOE_REGVAL | PCL_PERST_OUT_REGVAL106 | PCL_PERST_PLDN_REGVAL);107 val |= PCL_PERST_NOE_REGEN | PCL_PERST_OUT_REGEN108 | PCL_PERST_PLDN_REGEN;109 writel(val, pcie->base + PCL_PINCTRL0);110 111 uniphier_pcie_ltssm_enable(pcie, false);112 113 usleep_range(100000, 200000);114 115 /* deassert PERST# */116 val = readl(pcie->base + PCL_PINCTRL0);117 val |= PCL_PERST_OUT_REGVAL | PCL_PERST_OUT_REGEN;118 writel(val, pcie->base + PCL_PINCTRL0);119}120 121static int uniphier_pcie_wait_rc(struct uniphier_pcie *pcie)122{123 u32 status;124 int ret;125 126 /* wait PIPE clock */127 ret = readl_poll_timeout(pcie->base + PCL_PIPEMON, status,128 status & PCL_PCLK_ALIVE, 100000, 1000000);129 if (ret) {130 dev_err(pcie->pci.dev,131 "Failed to initialize controller in RC mode\n");132 return ret;133 }134 135 return 0;136}137 138static int uniphier_pcie_link_up(struct dw_pcie *pci)139{140 struct uniphier_pcie *pcie = to_uniphier_pcie(pci);141 u32 val, mask;142 143 val = readl(pcie->base + PCL_STATUS_LINK);144 mask = PCL_RDLH_LINK_UP | PCL_XMLH_LINK_UP;145 146 return (val & mask) == mask;147}148 149static int uniphier_pcie_start_link(struct dw_pcie *pci)150{151 struct uniphier_pcie *pcie = to_uniphier_pcie(pci);152 153 uniphier_pcie_ltssm_enable(pcie, true);154 155 return 0;156}157 158static void uniphier_pcie_stop_link(struct dw_pcie *pci)159{160 struct uniphier_pcie *pcie = to_uniphier_pcie(pci);161 162 uniphier_pcie_ltssm_enable(pcie, false);163}164 165static void uniphier_pcie_irq_enable(struct uniphier_pcie *pcie)166{167 writel(PCL_RCV_INT_ALL_ENABLE, pcie->base + PCL_RCV_INT);168 writel(PCL_RCV_INTX_ALL_ENABLE, pcie->base + PCL_RCV_INTX);169}170 171 172static void uniphier_pcie_irq_mask(struct irq_data *d)173{174 struct dw_pcie_rp *pp = irq_data_get_irq_chip_data(d);175 struct dw_pcie *pci = to_dw_pcie_from_pp(pp);176 struct uniphier_pcie *pcie = to_uniphier_pcie(pci);177 unsigned long flags;178 u32 val;179 180 raw_spin_lock_irqsave(&pp->lock, flags);181 182 val = readl(pcie->base + PCL_RCV_INTX);183 val |= BIT(irqd_to_hwirq(d) + PCL_RCV_INTX_MASK_SHIFT);184 writel(val, pcie->base + PCL_RCV_INTX);185 186 raw_spin_unlock_irqrestore(&pp->lock, flags);187}188 189static void uniphier_pcie_irq_unmask(struct irq_data *d)190{191 struct dw_pcie_rp *pp = irq_data_get_irq_chip_data(d);192 struct dw_pcie *pci = to_dw_pcie_from_pp(pp);193 struct uniphier_pcie *pcie = to_uniphier_pcie(pci);194 unsigned long flags;195 u32 val;196 197 raw_spin_lock_irqsave(&pp->lock, flags);198 199 val = readl(pcie->base + PCL_RCV_INTX);200 val &= ~BIT(irqd_to_hwirq(d) + PCL_RCV_INTX_MASK_SHIFT);201 writel(val, pcie->base + PCL_RCV_INTX);202 203 raw_spin_unlock_irqrestore(&pp->lock, flags);204}205 206static struct irq_chip uniphier_pcie_irq_chip = {207 .name = "PCI",208 .irq_mask = uniphier_pcie_irq_mask,209 .irq_unmask = uniphier_pcie_irq_unmask,210};211 212static int uniphier_pcie_intx_map(struct irq_domain *domain, unsigned int irq,213 irq_hw_number_t hwirq)214{215 irq_set_chip_and_handler(irq, &uniphier_pcie_irq_chip,216 handle_level_irq);217 irq_set_chip_data(irq, domain->host_data);218 219 return 0;220}221 222static const struct irq_domain_ops uniphier_intx_domain_ops = {223 .map = uniphier_pcie_intx_map,224};225 226static void uniphier_pcie_irq_handler(struct irq_desc *desc)227{228 struct dw_pcie_rp *pp = irq_desc_get_handler_data(desc);229 struct dw_pcie *pci = to_dw_pcie_from_pp(pp);230 struct uniphier_pcie *pcie = to_uniphier_pcie(pci);231 struct irq_chip *chip = irq_desc_get_chip(desc);232 unsigned long reg;233 u32 val, bit;234 235 /* INT for debug */236 val = readl(pcie->base + PCL_RCV_INT);237 238 if (val & PCL_CFG_BW_MGT_STATUS)239 dev_dbg(pci->dev, "Link Bandwidth Management Event\n");240 if (val & PCL_CFG_LINK_AUTO_BW_STATUS)241 dev_dbg(pci->dev, "Link Autonomous Bandwidth Event\n");242 if (val & PCL_CFG_AER_RC_ERR_MSI_STATUS)243 dev_dbg(pci->dev, "Root Error\n");244 if (val & PCL_CFG_PME_MSI_STATUS)245 dev_dbg(pci->dev, "PME Interrupt\n");246 247 writel(val, pcie->base + PCL_RCV_INT);248 249 /* INTx */250 chained_irq_enter(chip, desc);251 252 val = readl(pcie->base + PCL_RCV_INTX);253 reg = FIELD_GET(PCL_RCV_INTX_ALL_STATUS, val);254 255 for_each_set_bit(bit, ®, PCI_NUM_INTX)256 generic_handle_domain_irq(pcie->intx_irq_domain, bit);257 258 chained_irq_exit(chip, desc);259}260 261static int uniphier_pcie_config_intx_irq(struct dw_pcie_rp *pp)262{263 struct dw_pcie *pci = to_dw_pcie_from_pp(pp);264 struct uniphier_pcie *pcie = to_uniphier_pcie(pci);265 struct device_node *np = pci->dev->of_node;266 struct device_node *np_intc;267 int ret = 0;268 269 np_intc = of_get_child_by_name(np, "legacy-interrupt-controller");270 if (!np_intc) {271 dev_err(pci->dev, "Failed to get legacy-interrupt-controller node\n");272 return -EINVAL;273 }274 275 pp->irq = irq_of_parse_and_map(np_intc, 0);276 if (!pp->irq) {277 dev_err(pci->dev, "Failed to get an IRQ entry in legacy-interrupt-controller\n");278 ret = -EINVAL;279 goto out_put_node;280 }281 282 pcie->intx_irq_domain = irq_domain_add_linear(np_intc, PCI_NUM_INTX,283 &uniphier_intx_domain_ops, pp);284 if (!pcie->intx_irq_domain) {285 dev_err(pci->dev, "Failed to get INTx domain\n");286 ret = -ENODEV;287 goto out_put_node;288 }289 290 irq_set_chained_handler_and_data(pp->irq, uniphier_pcie_irq_handler,291 pp);292 293out_put_node:294 of_node_put(np_intc);295 return ret;296}297 298static int uniphier_pcie_host_init(struct dw_pcie_rp *pp)299{300 struct dw_pcie *pci = to_dw_pcie_from_pp(pp);301 struct uniphier_pcie *pcie = to_uniphier_pcie(pci);302 int ret;303 304 ret = uniphier_pcie_config_intx_irq(pp);305 if (ret)306 return ret;307 308 uniphier_pcie_irq_enable(pcie);309 310 return 0;311}312 313static const struct dw_pcie_host_ops uniphier_pcie_host_ops = {314 .init = uniphier_pcie_host_init,315};316 317static int uniphier_pcie_host_enable(struct uniphier_pcie *pcie)318{319 int ret;320 321 ret = clk_prepare_enable(pcie->clk);322 if (ret)323 return ret;324 325 ret = reset_control_deassert(pcie->rst);326 if (ret)327 goto out_clk_disable;328 329 uniphier_pcie_init_rc(pcie);330 331 ret = phy_init(pcie->phy);332 if (ret)333 goto out_rst_assert;334 335 ret = uniphier_pcie_wait_rc(pcie);336 if (ret)337 goto out_phy_exit;338 339 return 0;340 341out_phy_exit:342 phy_exit(pcie->phy);343out_rst_assert:344 reset_control_assert(pcie->rst);345out_clk_disable:346 clk_disable_unprepare(pcie->clk);347 348 return ret;349}350 351static const struct dw_pcie_ops dw_pcie_ops = {352 .start_link = uniphier_pcie_start_link,353 .stop_link = uniphier_pcie_stop_link,354 .link_up = uniphier_pcie_link_up,355};356 357static int uniphier_pcie_probe(struct platform_device *pdev)358{359 struct device *dev = &pdev->dev;360 struct uniphier_pcie *pcie;361 int ret;362 363 pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);364 if (!pcie)365 return -ENOMEM;366 367 pcie->pci.dev = dev;368 pcie->pci.ops = &dw_pcie_ops;369 370 pcie->base = devm_platform_ioremap_resource_byname(pdev, "link");371 if (IS_ERR(pcie->base))372 return PTR_ERR(pcie->base);373 374 pcie->clk = devm_clk_get(dev, NULL);375 if (IS_ERR(pcie->clk))376 return PTR_ERR(pcie->clk);377 378 pcie->rst = devm_reset_control_get_shared(dev, NULL);379 if (IS_ERR(pcie->rst))380 return PTR_ERR(pcie->rst);381 382 pcie->phy = devm_phy_optional_get(dev, "pcie-phy");383 if (IS_ERR(pcie->phy))384 return PTR_ERR(pcie->phy);385 386 platform_set_drvdata(pdev, pcie);387 388 ret = uniphier_pcie_host_enable(pcie);389 if (ret)390 return ret;391 392 pcie->pci.pp.ops = &uniphier_pcie_host_ops;393 394 return dw_pcie_host_init(&pcie->pci.pp);395}396 397static const struct of_device_id uniphier_pcie_match[] = {398 { .compatible = "socionext,uniphier-pcie", },399 { /* sentinel */ },400};401 402static struct platform_driver uniphier_pcie_driver = {403 .probe = uniphier_pcie_probe,404 .driver = {405 .name = "uniphier-pcie",406 .of_match_table = uniphier_pcie_match,407 },408};409builtin_platform_driver(uniphier_pcie_driver);410