485 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * PCIe controller driver for Intel Keem Bay4 * Copyright (C) 2020 Intel Corporation5 */6 7#include <linux/bitfield.h>8#include <linux/bits.h>9#include <linux/clk.h>10#include <linux/delay.h>11#include <linux/err.h>12#include <linux/gpio/consumer.h>13#include <linux/init.h>14#include <linux/iopoll.h>15#include <linux/irqchip/chained_irq.h>16#include <linux/kernel.h>17#include <linux/mod_devicetable.h>18#include <linux/pci.h>19#include <linux/platform_device.h>20#include <linux/property.h>21 22#include "pcie-designware.h"23 24/* PCIE_REGS_APB_SLV Registers */25#define PCIE_REGS_PCIE_CFG 0x000426#define PCIE_DEVICE_TYPE BIT(8)27#define PCIE_RSTN BIT(0)28#define PCIE_REGS_PCIE_APP_CNTRL 0x000829#define APP_LTSSM_ENABLE BIT(0)30#define PCIE_REGS_INTERRUPT_ENABLE 0x002831#define MSI_CTRL_INT_EN BIT(8)32#define EDMA_INT_EN GENMASK(7, 0)33#define PCIE_REGS_INTERRUPT_STATUS 0x002c34#define MSI_CTRL_INT BIT(8)35#define PCIE_REGS_PCIE_SII_PM_STATE 0x00b036#define SMLH_LINK_UP BIT(19)37#define RDLH_LINK_UP BIT(8)38#define PCIE_REGS_PCIE_SII_LINK_UP (SMLH_LINK_UP | RDLH_LINK_UP)39#define PCIE_REGS_PCIE_PHY_CNTL 0x016440#define PHY0_SRAM_BYPASS BIT(8)41#define PCIE_REGS_PCIE_PHY_STAT 0x016842#define PHY0_MPLLA_STATE BIT(1)43#define PCIE_REGS_LJPLL_STA 0x016c44#define LJPLL_LOCK BIT(0)45#define PCIE_REGS_LJPLL_CNTRL_0 0x017046#define LJPLL_EN BIT(29)47#define LJPLL_FOUT_EN GENMASK(24, 21)48#define PCIE_REGS_LJPLL_CNTRL_2 0x017849#define LJPLL_REF_DIV GENMASK(17, 12)50#define LJPLL_FB_DIV GENMASK(11, 0)51#define PCIE_REGS_LJPLL_CNTRL_3 0x017c52#define LJPLL_POST_DIV3A GENMASK(24, 22)53#define LJPLL_POST_DIV2A GENMASK(18, 16)54 55#define PERST_DELAY_US 100056#define AUX_CLK_RATE_HZ 2400000057 58struct keembay_pcie {59 struct dw_pcie pci;60 void __iomem *apb_base;61 enum dw_pcie_device_mode mode;62 63 struct clk *clk_master;64 struct clk *clk_aux;65 struct gpio_desc *reset;66};67 68struct keembay_pcie_of_data {69 enum dw_pcie_device_mode mode;70};71 72static void keembay_ep_reset_assert(struct keembay_pcie *pcie)73{74 gpiod_set_value_cansleep(pcie->reset, 1);75 usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500);76}77 78static void keembay_ep_reset_deassert(struct keembay_pcie *pcie)79{80 /*81 * Ensure that PERST# is asserted for a minimum of 100ms.82 *83 * For more details, refer to PCI Express Card Electromechanical84 * Specification Revision 1.1, Table-2.4.85 */86 msleep(100);87 88 gpiod_set_value_cansleep(pcie->reset, 0);89 usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500);90}91 92static void keembay_pcie_ltssm_set(struct keembay_pcie *pcie, bool enable)93{94 u32 val;95 96 val = readl(pcie->apb_base + PCIE_REGS_PCIE_APP_CNTRL);97 if (enable)98 val |= APP_LTSSM_ENABLE;99 else100 val &= ~APP_LTSSM_ENABLE;101 writel(val, pcie->apb_base + PCIE_REGS_PCIE_APP_CNTRL);102}103 104static int keembay_pcie_link_up(struct dw_pcie *pci)105{106 struct keembay_pcie *pcie = dev_get_drvdata(pci->dev);107 u32 val;108 109 val = readl(pcie->apb_base + PCIE_REGS_PCIE_SII_PM_STATE);110 111 return (val & PCIE_REGS_PCIE_SII_LINK_UP) == PCIE_REGS_PCIE_SII_LINK_UP;112}113 114static int keembay_pcie_start_link(struct dw_pcie *pci)115{116 struct keembay_pcie *pcie = dev_get_drvdata(pci->dev);117 u32 val;118 int ret;119 120 if (pcie->mode == DW_PCIE_EP_TYPE)121 return 0;122 123 keembay_pcie_ltssm_set(pcie, false);124 125 ret = readl_poll_timeout(pcie->apb_base + PCIE_REGS_PCIE_PHY_STAT,126 val, val & PHY0_MPLLA_STATE, 20,127 500 * USEC_PER_MSEC);128 if (ret) {129 dev_err(pci->dev, "MPLLA is not locked\n");130 return ret;131 }132 133 keembay_pcie_ltssm_set(pcie, true);134 135 return 0;136}137 138static void keembay_pcie_stop_link(struct dw_pcie *pci)139{140 struct keembay_pcie *pcie = dev_get_drvdata(pci->dev);141 142 keembay_pcie_ltssm_set(pcie, false);143}144 145static const struct dw_pcie_ops keembay_pcie_ops = {146 .link_up = keembay_pcie_link_up,147 .start_link = keembay_pcie_start_link,148 .stop_link = keembay_pcie_stop_link,149};150 151static inline void keembay_pcie_disable_clock(void *data)152{153 struct clk *clk = data;154 155 clk_disable_unprepare(clk);156}157 158static inline struct clk *keembay_pcie_probe_clock(struct device *dev,159 const char *id, u64 rate)160{161 struct clk *clk;162 int ret;163 164 clk = devm_clk_get(dev, id);165 if (IS_ERR(clk))166 return clk;167 168 if (rate) {169 ret = clk_set_rate(clk, rate);170 if (ret)171 return ERR_PTR(ret);172 }173 174 ret = clk_prepare_enable(clk);175 if (ret)176 return ERR_PTR(ret);177 178 ret = devm_add_action_or_reset(dev, keembay_pcie_disable_clock, clk);179 if (ret)180 return ERR_PTR(ret);181 182 return clk;183}184 185static int keembay_pcie_probe_clocks(struct keembay_pcie *pcie)186{187 struct dw_pcie *pci = &pcie->pci;188 struct device *dev = pci->dev;189 190 pcie->clk_master = keembay_pcie_probe_clock(dev, "master", 0);191 if (IS_ERR(pcie->clk_master))192 return dev_err_probe(dev, PTR_ERR(pcie->clk_master),193 "Failed to enable master clock");194 195 pcie->clk_aux = keembay_pcie_probe_clock(dev, "aux", AUX_CLK_RATE_HZ);196 if (IS_ERR(pcie->clk_aux))197 return dev_err_probe(dev, PTR_ERR(pcie->clk_aux),198 "Failed to enable auxiliary clock");199 200 return 0;201}202 203/*204 * Initialize the internal PCIe PLL in Host mode.205 * See the following sections in Keem Bay data book,206 * (1) 6.4.6.1 PCIe Subsystem Example Initialization,207 * (2) 6.8 PCIe Low Jitter PLL for Ref Clk Generation.208 */209static int keembay_pcie_pll_init(struct keembay_pcie *pcie)210{211 struct dw_pcie *pci = &pcie->pci;212 u32 val;213 int ret;214 215 val = FIELD_PREP(LJPLL_REF_DIV, 0) | FIELD_PREP(LJPLL_FB_DIV, 0x32);216 writel(val, pcie->apb_base + PCIE_REGS_LJPLL_CNTRL_2);217 218 val = FIELD_PREP(LJPLL_POST_DIV3A, 0x2) |219 FIELD_PREP(LJPLL_POST_DIV2A, 0x2);220 writel(val, pcie->apb_base + PCIE_REGS_LJPLL_CNTRL_3);221 222 val = FIELD_PREP(LJPLL_EN, 0x1) | FIELD_PREP(LJPLL_FOUT_EN, 0xc);223 writel(val, pcie->apb_base + PCIE_REGS_LJPLL_CNTRL_0);224 225 ret = readl_poll_timeout(pcie->apb_base + PCIE_REGS_LJPLL_STA,226 val, val & LJPLL_LOCK, 20,227 500 * USEC_PER_MSEC);228 if (ret)229 dev_err(pci->dev, "Low jitter PLL is not locked\n");230 231 return ret;232}233 234static void keembay_pcie_msi_irq_handler(struct irq_desc *desc)235{236 struct keembay_pcie *pcie = irq_desc_get_handler_data(desc);237 struct irq_chip *chip = irq_desc_get_chip(desc);238 u32 val, mask, status;239 struct dw_pcie_rp *pp;240 241 /*242 * Keem Bay PCIe Controller provides an additional IP logic on top of243 * standard DWC IP to clear MSI IRQ by writing '1' to the respective244 * bit of the status register.245 *246 * So, a chained irq handler is defined to handle this additional247 * IP logic.248 */249 250 chained_irq_enter(chip, desc);251 252 pp = &pcie->pci.pp;253 val = readl(pcie->apb_base + PCIE_REGS_INTERRUPT_STATUS);254 mask = readl(pcie->apb_base + PCIE_REGS_INTERRUPT_ENABLE);255 256 status = val & mask;257 258 if (status & MSI_CTRL_INT) {259 dw_handle_msi_irq(pp);260 writel(status, pcie->apb_base + PCIE_REGS_INTERRUPT_STATUS);261 }262 263 chained_irq_exit(chip, desc);264}265 266static int keembay_pcie_setup_msi_irq(struct keembay_pcie *pcie)267{268 struct dw_pcie *pci = &pcie->pci;269 struct device *dev = pci->dev;270 struct platform_device *pdev = to_platform_device(dev);271 int irq;272 273 irq = platform_get_irq_byname(pdev, "pcie");274 if (irq < 0)275 return irq;276 277 irq_set_chained_handler_and_data(irq, keembay_pcie_msi_irq_handler,278 pcie);279 280 return 0;281}282 283static void keembay_pcie_ep_init(struct dw_pcie_ep *ep)284{285 struct dw_pcie *pci = to_dw_pcie_from_ep(ep);286 struct keembay_pcie *pcie = dev_get_drvdata(pci->dev);287 288 writel(EDMA_INT_EN, pcie->apb_base + PCIE_REGS_INTERRUPT_ENABLE);289}290 291static int keembay_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,292 unsigned int type, u16 interrupt_num)293{294 struct dw_pcie *pci = to_dw_pcie_from_ep(ep);295 296 switch (type) {297 case PCI_IRQ_INTX:298 /* INTx interrupts are not supported in Keem Bay */299 dev_err(pci->dev, "INTx IRQ is not supported\n");300 return -EINVAL;301 case PCI_IRQ_MSI:302 return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num);303 case PCI_IRQ_MSIX:304 return dw_pcie_ep_raise_msix_irq(ep, func_no, interrupt_num);305 default:306 dev_err(pci->dev, "Unknown IRQ type %d\n", type);307 return -EINVAL;308 }309}310 311static const struct pci_epc_features keembay_pcie_epc_features = {312 .linkup_notifier = false,313 .msi_capable = true,314 .msix_capable = true,315 .bar[BAR_0] = { .only_64bit = true, },316 .bar[BAR_1] = { .type = BAR_RESERVED, },317 .bar[BAR_2] = { .only_64bit = true, },318 .bar[BAR_3] = { .type = BAR_RESERVED, },319 .bar[BAR_4] = { .only_64bit = true, },320 .bar[BAR_5] = { .type = BAR_RESERVED, },321 .align = SZ_16K,322};323 324static const struct pci_epc_features *325keembay_pcie_get_features(struct dw_pcie_ep *ep)326{327 return &keembay_pcie_epc_features;328}329 330static const struct dw_pcie_ep_ops keembay_pcie_ep_ops = {331 .init = keembay_pcie_ep_init,332 .raise_irq = keembay_pcie_ep_raise_irq,333 .get_features = keembay_pcie_get_features,334};335 336static const struct dw_pcie_host_ops keembay_pcie_host_ops = {337};338 339static int keembay_pcie_add_pcie_port(struct keembay_pcie *pcie,340 struct platform_device *pdev)341{342 struct dw_pcie *pci = &pcie->pci;343 struct dw_pcie_rp *pp = &pci->pp;344 struct device *dev = &pdev->dev;345 u32 val;346 int ret;347 348 pp->ops = &keembay_pcie_host_ops;349 pp->msi_irq[0] = -ENODEV;350 351 ret = keembay_pcie_setup_msi_irq(pcie);352 if (ret)353 return ret;354 355 pcie->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);356 if (IS_ERR(pcie->reset))357 return PTR_ERR(pcie->reset);358 359 ret = keembay_pcie_probe_clocks(pcie);360 if (ret)361 return ret;362 363 val = readl(pcie->apb_base + PCIE_REGS_PCIE_PHY_CNTL);364 val |= PHY0_SRAM_BYPASS;365 writel(val, pcie->apb_base + PCIE_REGS_PCIE_PHY_CNTL);366 367 writel(PCIE_DEVICE_TYPE, pcie->apb_base + PCIE_REGS_PCIE_CFG);368 369 ret = keembay_pcie_pll_init(pcie);370 if (ret)371 return ret;372 373 val = readl(pcie->apb_base + PCIE_REGS_PCIE_CFG);374 writel(val | PCIE_RSTN, pcie->apb_base + PCIE_REGS_PCIE_CFG);375 keembay_ep_reset_deassert(pcie);376 377 ret = dw_pcie_host_init(pp);378 if (ret) {379 keembay_ep_reset_assert(pcie);380 dev_err(dev, "Failed to initialize host: %d\n", ret);381 return ret;382 }383 384 val = readl(pcie->apb_base + PCIE_REGS_INTERRUPT_ENABLE);385 if (IS_ENABLED(CONFIG_PCI_MSI))386 val |= MSI_CTRL_INT_EN;387 writel(val, pcie->apb_base + PCIE_REGS_INTERRUPT_ENABLE);388 389 return 0;390}391 392static int keembay_pcie_probe(struct platform_device *pdev)393{394 const struct keembay_pcie_of_data *data;395 struct device *dev = &pdev->dev;396 struct keembay_pcie *pcie;397 struct dw_pcie *pci;398 enum dw_pcie_device_mode mode;399 int ret;400 401 data = device_get_match_data(dev);402 if (!data)403 return -ENODEV;404 405 mode = (enum dw_pcie_device_mode)data->mode;406 407 pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);408 if (!pcie)409 return -ENOMEM;410 411 pci = &pcie->pci;412 pci->dev = dev;413 pci->ops = &keembay_pcie_ops;414 415 pcie->mode = mode;416 417 pcie->apb_base = devm_platform_ioremap_resource_byname(pdev, "apb");418 if (IS_ERR(pcie->apb_base))419 return PTR_ERR(pcie->apb_base);420 421 platform_set_drvdata(pdev, pcie);422 423 switch (pcie->mode) {424 case DW_PCIE_RC_TYPE:425 if (!IS_ENABLED(CONFIG_PCIE_KEEMBAY_HOST))426 return -ENODEV;427 428 return keembay_pcie_add_pcie_port(pcie, pdev);429 case DW_PCIE_EP_TYPE:430 if (!IS_ENABLED(CONFIG_PCIE_KEEMBAY_EP))431 return -ENODEV;432 433 pci->ep.ops = &keembay_pcie_ep_ops;434 ret = dw_pcie_ep_init(&pci->ep);435 if (ret)436 return ret;437 438 ret = dw_pcie_ep_init_registers(&pci->ep);439 if (ret) {440 dev_err(dev, "Failed to initialize DWC endpoint registers\n");441 dw_pcie_ep_deinit(&pci->ep);442 return ret;443 }444 445 pci_epc_init_notify(pci->ep.epc);446 447 break;448 default:449 dev_err(dev, "Invalid device type %d\n", pcie->mode);450 return -ENODEV;451 }452 453 return 0;454}455 456static const struct keembay_pcie_of_data keembay_pcie_rc_of_data = {457 .mode = DW_PCIE_RC_TYPE,458};459 460static const struct keembay_pcie_of_data keembay_pcie_ep_of_data = {461 .mode = DW_PCIE_EP_TYPE,462};463 464static const struct of_device_id keembay_pcie_of_match[] = {465 {466 .compatible = "intel,keembay-pcie",467 .data = &keembay_pcie_rc_of_data,468 },469 {470 .compatible = "intel,keembay-pcie-ep",471 .data = &keembay_pcie_ep_of_data,472 },473 {}474};475 476static struct platform_driver keembay_pcie_driver = {477 .driver = {478 .name = "keembay-pcie",479 .of_match_table = keembay_pcie_of_match,480 .suppress_bind_attrs = true,481 },482 .probe = keembay_pcie_probe,483};484builtin_platform_driver(keembay_pcie_driver);485