pcie-keembay.c (11647B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * PCIe controller driver for Intel Keem Bay 4 * Copyright (C) 2020 Intel Corporation 5 */ 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 0x0004 26#define PCIE_DEVICE_TYPE BIT(8) 27#define PCIE_RSTN BIT(0) 28#define PCIE_REGS_PCIE_APP_CNTRL 0x0008 29#define APP_LTSSM_ENABLE BIT(0) 30#define PCIE_REGS_INTERRUPT_ENABLE 0x0028 31#define MSI_CTRL_INT_EN BIT(8) 32#define EDMA_INT_EN GENMASK(7, 0) 33#define PCIE_REGS_INTERRUPT_STATUS 0x002c 34#define MSI_CTRL_INT BIT(8) 35#define PCIE_REGS_PCIE_SII_PM_STATE 0x00b0 36#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 0x0164 40#define PHY0_SRAM_BYPASS BIT(8) 41#define PCIE_REGS_PCIE_PHY_STAT 0x0168 42#define PHY0_MPLLA_STATE BIT(1) 43#define PCIE_REGS_LJPLL_STA 0x016c 44#define LJPLL_LOCK BIT(0) 45#define PCIE_REGS_LJPLL_CNTRL_0 0x0170 46#define LJPLL_EN BIT(29) 47#define LJPLL_FOUT_EN GENMASK(24, 21) 48#define PCIE_REGS_LJPLL_CNTRL_2 0x0178 49#define LJPLL_REF_DIV GENMASK(17, 12) 50#define LJPLL_FB_DIV GENMASK(11, 0) 51#define PCIE_REGS_LJPLL_CNTRL_3 0x017c 52#define LJPLL_POST_DIV3A GENMASK(24, 22) 53#define LJPLL_POST_DIV2A GENMASK(18, 16) 54 55#define PERST_DELAY_US 1000 56#define AUX_CLK_RATE_HZ 24000000 57 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 Electromechanical 84 * 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 else 100 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 struct clk *keembay_pcie_probe_clock(struct device *dev, 152 const char *id, u64 rate) 153{ 154 struct clk *clk; 155 int ret; 156 157 clk = devm_clk_get(dev, id); 158 if (IS_ERR(clk)) 159 return clk; 160 161 if (rate) { 162 ret = clk_set_rate(clk, rate); 163 if (ret) 164 return ERR_PTR(ret); 165 } 166 167 ret = clk_prepare_enable(clk); 168 if (ret) 169 return ERR_PTR(ret); 170 171 ret = devm_add_action_or_reset(dev, 172 (void(*)(void *))clk_disable_unprepare, 173 clk); 174 if (ret) 175 return ERR_PTR(ret); 176 177 return clk; 178} 179 180static int keembay_pcie_probe_clocks(struct keembay_pcie *pcie) 181{ 182 struct dw_pcie *pci = &pcie->pci; 183 struct device *dev = pci->dev; 184 185 pcie->clk_master = keembay_pcie_probe_clock(dev, "master", 0); 186 if (IS_ERR(pcie->clk_master)) 187 return dev_err_probe(dev, PTR_ERR(pcie->clk_master), 188 "Failed to enable master clock"); 189 190 pcie->clk_aux = keembay_pcie_probe_clock(dev, "aux", AUX_CLK_RATE_HZ); 191 if (IS_ERR(pcie->clk_aux)) 192 return dev_err_probe(dev, PTR_ERR(pcie->clk_aux), 193 "Failed to enable auxiliary clock"); 194 195 return 0; 196} 197 198/* 199 * Initialize the internal PCIe PLL in Host mode. 200 * See the following sections in Keem Bay data book, 201 * (1) 6.4.6.1 PCIe Subsystem Example Initialization, 202 * (2) 6.8 PCIe Low Jitter PLL for Ref Clk Generation. 203 */ 204static int keembay_pcie_pll_init(struct keembay_pcie *pcie) 205{ 206 struct dw_pcie *pci = &pcie->pci; 207 u32 val; 208 int ret; 209 210 val = FIELD_PREP(LJPLL_REF_DIV, 0) | FIELD_PREP(LJPLL_FB_DIV, 0x32); 211 writel(val, pcie->apb_base + PCIE_REGS_LJPLL_CNTRL_2); 212 213 val = FIELD_PREP(LJPLL_POST_DIV3A, 0x2) | 214 FIELD_PREP(LJPLL_POST_DIV2A, 0x2); 215 writel(val, pcie->apb_base + PCIE_REGS_LJPLL_CNTRL_3); 216 217 val = FIELD_PREP(LJPLL_EN, 0x1) | FIELD_PREP(LJPLL_FOUT_EN, 0xc); 218 writel(val, pcie->apb_base + PCIE_REGS_LJPLL_CNTRL_0); 219 220 ret = readl_poll_timeout(pcie->apb_base + PCIE_REGS_LJPLL_STA, 221 val, val & LJPLL_LOCK, 20, 222 500 * USEC_PER_MSEC); 223 if (ret) 224 dev_err(pci->dev, "Low jitter PLL is not locked\n"); 225 226 return ret; 227} 228 229static void keembay_pcie_msi_irq_handler(struct irq_desc *desc) 230{ 231 struct keembay_pcie *pcie = irq_desc_get_handler_data(desc); 232 struct irq_chip *chip = irq_desc_get_chip(desc); 233 u32 val, mask, status; 234 struct pcie_port *pp; 235 236 /* 237 * Keem Bay PCIe Controller provides an additional IP logic on top of 238 * standard DWC IP to clear MSI IRQ by writing '1' to the respective 239 * bit of the status register. 240 * 241 * So, a chained irq handler is defined to handle this additional 242 * IP logic. 243 */ 244 245 chained_irq_enter(chip, desc); 246 247 pp = &pcie->pci.pp; 248 val = readl(pcie->apb_base + PCIE_REGS_INTERRUPT_STATUS); 249 mask = readl(pcie->apb_base + PCIE_REGS_INTERRUPT_ENABLE); 250 251 status = val & mask; 252 253 if (status & MSI_CTRL_INT) { 254 dw_handle_msi_irq(pp); 255 writel(status, pcie->apb_base + PCIE_REGS_INTERRUPT_STATUS); 256 } 257 258 chained_irq_exit(chip, desc); 259} 260 261static int keembay_pcie_setup_msi_irq(struct keembay_pcie *pcie) 262{ 263 struct dw_pcie *pci = &pcie->pci; 264 struct device *dev = pci->dev; 265 struct platform_device *pdev = to_platform_device(dev); 266 int irq; 267 268 irq = platform_get_irq_byname(pdev, "pcie"); 269 if (irq < 0) 270 return irq; 271 272 irq_set_chained_handler_and_data(irq, keembay_pcie_msi_irq_handler, 273 pcie); 274 275 return 0; 276} 277 278static void keembay_pcie_ep_init(struct dw_pcie_ep *ep) 279{ 280 struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 281 struct keembay_pcie *pcie = dev_get_drvdata(pci->dev); 282 283 writel(EDMA_INT_EN, pcie->apb_base + PCIE_REGS_INTERRUPT_ENABLE); 284} 285 286static int keembay_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, 287 enum pci_epc_irq_type type, 288 u16 interrupt_num) 289{ 290 struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 291 292 switch (type) { 293 case PCI_EPC_IRQ_LEGACY: 294 /* Legacy interrupts are not supported in Keem Bay */ 295 dev_err(pci->dev, "Legacy IRQ is not supported\n"); 296 return -EINVAL; 297 case PCI_EPC_IRQ_MSI: 298 return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num); 299 case PCI_EPC_IRQ_MSIX: 300 return dw_pcie_ep_raise_msix_irq(ep, func_no, interrupt_num); 301 default: 302 dev_err(pci->dev, "Unknown IRQ type %d\n", type); 303 return -EINVAL; 304 } 305} 306 307static const struct pci_epc_features keembay_pcie_epc_features = { 308 .linkup_notifier = false, 309 .msi_capable = true, 310 .msix_capable = true, 311 .reserved_bar = BIT(BAR_1) | BIT(BAR_3) | BIT(BAR_5), 312 .bar_fixed_64bit = BIT(BAR_0) | BIT(BAR_2) | BIT(BAR_4), 313 .align = SZ_16K, 314}; 315 316static const struct pci_epc_features * 317keembay_pcie_get_features(struct dw_pcie_ep *ep) 318{ 319 return &keembay_pcie_epc_features; 320} 321 322static const struct dw_pcie_ep_ops keembay_pcie_ep_ops = { 323 .ep_init = keembay_pcie_ep_init, 324 .raise_irq = keembay_pcie_ep_raise_irq, 325 .get_features = keembay_pcie_get_features, 326}; 327 328static const struct dw_pcie_host_ops keembay_pcie_host_ops = { 329}; 330 331static int keembay_pcie_add_pcie_port(struct keembay_pcie *pcie, 332 struct platform_device *pdev) 333{ 334 struct dw_pcie *pci = &pcie->pci; 335 struct pcie_port *pp = &pci->pp; 336 struct device *dev = &pdev->dev; 337 u32 val; 338 int ret; 339 340 pp->ops = &keembay_pcie_host_ops; 341 pp->msi_irq = -ENODEV; 342 343 ret = keembay_pcie_setup_msi_irq(pcie); 344 if (ret) 345 return ret; 346 347 pcie->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); 348 if (IS_ERR(pcie->reset)) 349 return PTR_ERR(pcie->reset); 350 351 ret = keembay_pcie_probe_clocks(pcie); 352 if (ret) 353 return ret; 354 355 val = readl(pcie->apb_base + PCIE_REGS_PCIE_PHY_CNTL); 356 val |= PHY0_SRAM_BYPASS; 357 writel(val, pcie->apb_base + PCIE_REGS_PCIE_PHY_CNTL); 358 359 writel(PCIE_DEVICE_TYPE, pcie->apb_base + PCIE_REGS_PCIE_CFG); 360 361 ret = keembay_pcie_pll_init(pcie); 362 if (ret) 363 return ret; 364 365 val = readl(pcie->apb_base + PCIE_REGS_PCIE_CFG); 366 writel(val | PCIE_RSTN, pcie->apb_base + PCIE_REGS_PCIE_CFG); 367 keembay_ep_reset_deassert(pcie); 368 369 ret = dw_pcie_host_init(pp); 370 if (ret) { 371 keembay_ep_reset_assert(pcie); 372 dev_err(dev, "Failed to initialize host: %d\n", ret); 373 return ret; 374 } 375 376 val = readl(pcie->apb_base + PCIE_REGS_INTERRUPT_ENABLE); 377 if (IS_ENABLED(CONFIG_PCI_MSI)) 378 val |= MSI_CTRL_INT_EN; 379 writel(val, pcie->apb_base + PCIE_REGS_INTERRUPT_ENABLE); 380 381 return 0; 382} 383 384static int keembay_pcie_probe(struct platform_device *pdev) 385{ 386 const struct keembay_pcie_of_data *data; 387 struct device *dev = &pdev->dev; 388 struct keembay_pcie *pcie; 389 struct dw_pcie *pci; 390 enum dw_pcie_device_mode mode; 391 392 data = device_get_match_data(dev); 393 if (!data) 394 return -ENODEV; 395 396 mode = (enum dw_pcie_device_mode)data->mode; 397 398 pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); 399 if (!pcie) 400 return -ENOMEM; 401 402 pci = &pcie->pci; 403 pci->dev = dev; 404 pci->ops = &keembay_pcie_ops; 405 406 pcie->mode = mode; 407 408 pcie->apb_base = devm_platform_ioremap_resource_byname(pdev, "apb"); 409 if (IS_ERR(pcie->apb_base)) 410 return PTR_ERR(pcie->apb_base); 411 412 platform_set_drvdata(pdev, pcie); 413 414 switch (pcie->mode) { 415 case DW_PCIE_RC_TYPE: 416 if (!IS_ENABLED(CONFIG_PCIE_KEEMBAY_HOST)) 417 return -ENODEV; 418 419 return keembay_pcie_add_pcie_port(pcie, pdev); 420 case DW_PCIE_EP_TYPE: 421 if (!IS_ENABLED(CONFIG_PCIE_KEEMBAY_EP)) 422 return -ENODEV; 423 424 pci->ep.ops = &keembay_pcie_ep_ops; 425 return dw_pcie_ep_init(&pci->ep); 426 default: 427 dev_err(dev, "Invalid device type %d\n", pcie->mode); 428 return -ENODEV; 429 } 430} 431 432static const struct keembay_pcie_of_data keembay_pcie_rc_of_data = { 433 .mode = DW_PCIE_RC_TYPE, 434}; 435 436static const struct keembay_pcie_of_data keembay_pcie_ep_of_data = { 437 .mode = DW_PCIE_EP_TYPE, 438}; 439 440static const struct of_device_id keembay_pcie_of_match[] = { 441 { 442 .compatible = "intel,keembay-pcie", 443 .data = &keembay_pcie_rc_of_data, 444 }, 445 { 446 .compatible = "intel,keembay-pcie-ep", 447 .data = &keembay_pcie_ep_of_data, 448 }, 449 {} 450}; 451 452static struct platform_driver keembay_pcie_driver = { 453 .driver = { 454 .name = "keembay-pcie", 455 .of_match_table = keembay_pcie_of_match, 456 .suppress_bind_attrs = true, 457 }, 458 .probe = keembay_pcie_probe, 459}; 460builtin_platform_driver(keembay_pcie_driver);