brintos

brintos / linux-shallow public Read only

0
0
Text · 11.8 KiB · 278205d Raw
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