brintos

brintos / linux-shallow public Read only

0
0
Text · 9.8 KiB · 5757ca3 Raw
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, &reg, 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