brintos

brintos / linux-shallow public Read only

0
0
Text · 11.2 KiB · d6e7381 Raw
475 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * PCIe endpoint 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/iopoll.h>14#include <linux/of.h>15#include <linux/pci.h>16#include <linux/phy/phy.h>17#include <linux/platform_device.h>18#include <linux/reset.h>19 20#include "pcie-designware.h"21 22/* Link Glue registers */23#define PCL_RSTCTRL0			0x001024#define PCL_RSTCTRL_AXI_REG		BIT(3)25#define PCL_RSTCTRL_AXI_SLAVE		BIT(2)26#define PCL_RSTCTRL_AXI_MASTER		BIT(1)27#define PCL_RSTCTRL_PIPE3		BIT(0)28 29#define PCL_RSTCTRL1			0x002030#define PCL_RSTCTRL_PERST		BIT(0)31 32#define PCL_RSTCTRL2			0x002433#define PCL_RSTCTRL_PHY_RESET		BIT(0)34 35#define PCL_PINCTRL0			0x002c36#define PCL_PERST_PLDN_REGEN		BIT(12)37#define PCL_PERST_NOE_REGEN		BIT(11)38#define PCL_PERST_OUT_REGEN		BIT(8)39#define PCL_PERST_PLDN_REGVAL		BIT(4)40#define PCL_PERST_NOE_REGVAL		BIT(3)41#define PCL_PERST_OUT_REGVAL		BIT(0)42 43#define PCL_PIPEMON			0x004444#define PCL_PCLK_ALIVE			BIT(15)45 46#define PCL_MODE			0x800047#define PCL_MODE_REGEN			BIT(8)48#define PCL_MODE_REGVAL			BIT(0)49 50#define PCL_APP_CLK_CTRL		0x800451#define PCL_APP_CLK_REQ			BIT(0)52 53#define PCL_APP_READY_CTRL		0x800854#define PCL_APP_LTSSM_ENABLE		BIT(0)55 56#define PCL_APP_MSI0			0x804057#define PCL_APP_VEN_MSI_TC_MASK		GENMASK(10, 8)58#define PCL_APP_VEN_MSI_VECTOR_MASK	GENMASK(4, 0)59 60#define PCL_APP_MSI1			0x804461#define PCL_APP_MSI_REQ			BIT(0)62 63#define PCL_APP_INTX			0x807464#define PCL_APP_INTX_SYS_INT		BIT(0)65 66#define PCL_APP_PM0			0x807867#define PCL_SYS_AUX_PWR_DET		BIT(8)68 69/* assertion time of INTx in usec */70#define PCL_INTX_WIDTH_USEC		3071 72struct uniphier_pcie_ep_priv {73	void __iomem *base;74	struct dw_pcie pci;75	struct clk *clk, *clk_gio;76	struct reset_control *rst, *rst_gio;77	struct phy *phy;78	const struct uniphier_pcie_ep_soc_data *data;79};80 81struct uniphier_pcie_ep_soc_data {82	bool has_gio;83	void (*init)(struct uniphier_pcie_ep_priv *priv);84	int (*wait)(struct uniphier_pcie_ep_priv *priv);85	const struct pci_epc_features features;86};87 88#define to_uniphier_pcie(x)	dev_get_drvdata((x)->dev)89 90static void uniphier_pcie_ltssm_enable(struct uniphier_pcie_ep_priv *priv,91				       bool enable)92{93	u32 val;94 95	val = readl(priv->base + PCL_APP_READY_CTRL);96	if (enable)97		val |= PCL_APP_LTSSM_ENABLE;98	else99		val &= ~PCL_APP_LTSSM_ENABLE;100	writel(val, priv->base + PCL_APP_READY_CTRL);101}102 103static void uniphier_pcie_phy_reset(struct uniphier_pcie_ep_priv *priv,104				    bool assert)105{106	u32 val;107 108	val = readl(priv->base + PCL_RSTCTRL2);109	if (assert)110		val |= PCL_RSTCTRL_PHY_RESET;111	else112		val &= ~PCL_RSTCTRL_PHY_RESET;113	writel(val, priv->base + PCL_RSTCTRL2);114}115 116static void uniphier_pcie_pro5_init_ep(struct uniphier_pcie_ep_priv *priv)117{118	u32 val;119 120	/* set EP mode */121	val = readl(priv->base + PCL_MODE);122	val |= PCL_MODE_REGEN | PCL_MODE_REGVAL;123	writel(val, priv->base + PCL_MODE);124 125	/* clock request */126	val = readl(priv->base + PCL_APP_CLK_CTRL);127	val &= ~PCL_APP_CLK_REQ;128	writel(val, priv->base + PCL_APP_CLK_CTRL);129 130	/* deassert PIPE3 and AXI reset */131	val = readl(priv->base + PCL_RSTCTRL0);132	val |= PCL_RSTCTRL_AXI_REG | PCL_RSTCTRL_AXI_SLAVE133		| PCL_RSTCTRL_AXI_MASTER | PCL_RSTCTRL_PIPE3;134	writel(val, priv->base + PCL_RSTCTRL0);135 136	uniphier_pcie_ltssm_enable(priv, false);137 138	msleep(100);139}140 141static void uniphier_pcie_nx1_init_ep(struct uniphier_pcie_ep_priv *priv)142{143	u32 val;144 145	/* set EP mode */146	val = readl(priv->base + PCL_MODE);147	val |= PCL_MODE_REGEN | PCL_MODE_REGVAL;148	writel(val, priv->base + PCL_MODE);149 150	/* use auxiliary power detection */151	val = readl(priv->base + PCL_APP_PM0);152	val |= PCL_SYS_AUX_PWR_DET;153	writel(val, priv->base + PCL_APP_PM0);154 155	/* assert PERST# */156	val = readl(priv->base + PCL_PINCTRL0);157	val &= ~(PCL_PERST_NOE_REGVAL | PCL_PERST_OUT_REGVAL158		 | PCL_PERST_PLDN_REGVAL);159	val |= PCL_PERST_NOE_REGEN | PCL_PERST_OUT_REGEN160		| PCL_PERST_PLDN_REGEN;161	writel(val, priv->base + PCL_PINCTRL0);162 163	uniphier_pcie_ltssm_enable(priv, false);164 165	usleep_range(100000, 200000);166 167	/* deassert PERST# */168	val = readl(priv->base + PCL_PINCTRL0);169	val |= PCL_PERST_OUT_REGVAL | PCL_PERST_OUT_REGEN;170	writel(val, priv->base + PCL_PINCTRL0);171}172 173static int uniphier_pcie_nx1_wait_ep(struct uniphier_pcie_ep_priv *priv)174{175	u32 status;176	int ret;177 178	/* wait PIPE clock */179	ret = readl_poll_timeout(priv->base + PCL_PIPEMON, status,180				 status & PCL_PCLK_ALIVE, 100000, 1000000);181	if (ret) {182		dev_err(priv->pci.dev,183			"Failed to initialize controller in EP mode\n");184		return ret;185	}186 187	return 0;188}189 190static int uniphier_pcie_start_link(struct dw_pcie *pci)191{192	struct uniphier_pcie_ep_priv *priv = to_uniphier_pcie(pci);193 194	uniphier_pcie_ltssm_enable(priv, true);195 196	return 0;197}198 199static void uniphier_pcie_stop_link(struct dw_pcie *pci)200{201	struct uniphier_pcie_ep_priv *priv = to_uniphier_pcie(pci);202 203	uniphier_pcie_ltssm_enable(priv, false);204}205 206static void uniphier_pcie_ep_init(struct dw_pcie_ep *ep)207{208	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);209	enum pci_barno bar;210 211	for (bar = BAR_0; bar <= BAR_5; bar++)212		dw_pcie_ep_reset_bar(pci, bar);213}214 215static int uniphier_pcie_ep_raise_intx_irq(struct dw_pcie_ep *ep)216{217	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);218	struct uniphier_pcie_ep_priv *priv = to_uniphier_pcie(pci);219	u32 val;220 221	/*222	 * This makes pulse signal to send INTx to the RC, so this should223	 * be cleared as soon as possible. This sequence is covered with224	 * mutex in pci_epc_raise_irq().225	 */226	/* assert INTx */227	val = readl(priv->base + PCL_APP_INTX);228	val |= PCL_APP_INTX_SYS_INT;229	writel(val, priv->base + PCL_APP_INTX);230 231	udelay(PCL_INTX_WIDTH_USEC);232 233	/* deassert INTx */234	val &= ~PCL_APP_INTX_SYS_INT;235	writel(val, priv->base + PCL_APP_INTX);236 237	return 0;238}239 240static int uniphier_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep,241					  u8 func_no, u16 interrupt_num)242{243	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);244	struct uniphier_pcie_ep_priv *priv = to_uniphier_pcie(pci);245	u32 val;246 247	val = FIELD_PREP(PCL_APP_VEN_MSI_TC_MASK, func_no)248		| FIELD_PREP(PCL_APP_VEN_MSI_VECTOR_MASK, interrupt_num - 1);249	writel(val, priv->base + PCL_APP_MSI0);250 251	val = readl(priv->base + PCL_APP_MSI1);252	val |= PCL_APP_MSI_REQ;253	writel(val, priv->base + PCL_APP_MSI1);254 255	return 0;256}257 258static int uniphier_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,259				      unsigned int type, u16 interrupt_num)260{261	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);262 263	switch (type) {264	case PCI_IRQ_INTX:265		return uniphier_pcie_ep_raise_intx_irq(ep);266	case PCI_IRQ_MSI:267		return uniphier_pcie_ep_raise_msi_irq(ep, func_no,268						      interrupt_num);269	default:270		dev_err(pci->dev, "UNKNOWN IRQ type (%d)\n", type);271	}272 273	return 0;274}275 276static const struct pci_epc_features*277uniphier_pcie_get_features(struct dw_pcie_ep *ep)278{279	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);280	struct uniphier_pcie_ep_priv *priv = to_uniphier_pcie(pci);281 282	return &priv->data->features;283}284 285static const struct dw_pcie_ep_ops uniphier_pcie_ep_ops = {286	.init = uniphier_pcie_ep_init,287	.raise_irq = uniphier_pcie_ep_raise_irq,288	.get_features = uniphier_pcie_get_features,289};290 291static int uniphier_pcie_ep_enable(struct uniphier_pcie_ep_priv *priv)292{293	int ret;294 295	ret = clk_prepare_enable(priv->clk);296	if (ret)297		return ret;298 299	ret = clk_prepare_enable(priv->clk_gio);300	if (ret)301		goto out_clk_disable;302 303	ret = reset_control_deassert(priv->rst);304	if (ret)305		goto out_clk_gio_disable;306 307	ret = reset_control_deassert(priv->rst_gio);308	if (ret)309		goto out_rst_assert;310 311	if (priv->data->init)312		priv->data->init(priv);313 314	uniphier_pcie_phy_reset(priv, true);315 316	ret = phy_init(priv->phy);317	if (ret)318		goto out_rst_gio_assert;319 320	uniphier_pcie_phy_reset(priv, false);321 322	if (priv->data->wait) {323		ret = priv->data->wait(priv);324		if (ret)325			goto out_phy_exit;326	}327 328	return 0;329 330out_phy_exit:331	phy_exit(priv->phy);332out_rst_gio_assert:333	reset_control_assert(priv->rst_gio);334out_rst_assert:335	reset_control_assert(priv->rst);336out_clk_gio_disable:337	clk_disable_unprepare(priv->clk_gio);338out_clk_disable:339	clk_disable_unprepare(priv->clk);340 341	return ret;342}343 344static const struct dw_pcie_ops dw_pcie_ops = {345	.start_link = uniphier_pcie_start_link,346	.stop_link = uniphier_pcie_stop_link,347};348 349static int uniphier_pcie_ep_probe(struct platform_device *pdev)350{351	struct device *dev = &pdev->dev;352	struct uniphier_pcie_ep_priv *priv;353	int ret;354 355	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);356	if (!priv)357		return -ENOMEM;358 359	priv->data = of_device_get_match_data(dev);360	if (WARN_ON(!priv->data))361		return -EINVAL;362 363	priv->pci.dev = dev;364	priv->pci.ops = &dw_pcie_ops;365 366	priv->base = devm_platform_ioremap_resource_byname(pdev, "link");367	if (IS_ERR(priv->base))368		return PTR_ERR(priv->base);369 370	if (priv->data->has_gio) {371		priv->clk_gio = devm_clk_get(dev, "gio");372		if (IS_ERR(priv->clk_gio))373			return PTR_ERR(priv->clk_gio);374 375		priv->rst_gio = devm_reset_control_get_shared(dev, "gio");376		if (IS_ERR(priv->rst_gio))377			return PTR_ERR(priv->rst_gio);378	}379 380	priv->clk = devm_clk_get(dev, "link");381	if (IS_ERR(priv->clk))382		return PTR_ERR(priv->clk);383 384	priv->rst = devm_reset_control_get_shared(dev, "link");385	if (IS_ERR(priv->rst))386		return PTR_ERR(priv->rst);387 388	priv->phy = devm_phy_optional_get(dev, "pcie-phy");389	if (IS_ERR(priv->phy)) {390		ret = PTR_ERR(priv->phy);391		dev_err(dev, "Failed to get phy (%d)\n", ret);392		return ret;393	}394 395	platform_set_drvdata(pdev, priv);396 397	ret = uniphier_pcie_ep_enable(priv);398	if (ret)399		return ret;400 401	priv->pci.ep.ops = &uniphier_pcie_ep_ops;402	ret = dw_pcie_ep_init(&priv->pci.ep);403	if (ret)404		return ret;405 406	ret = dw_pcie_ep_init_registers(&priv->pci.ep);407	if (ret) {408		dev_err(dev, "Failed to initialize DWC endpoint registers\n");409		dw_pcie_ep_deinit(&priv->pci.ep);410		return ret;411	}412 413	pci_epc_init_notify(priv->pci.ep.epc);414 415	return 0;416}417 418static const struct uniphier_pcie_ep_soc_data uniphier_pro5_data = {419	.has_gio = true,420	.init = uniphier_pcie_pro5_init_ep,421	.wait = NULL,422	.features = {423		.linkup_notifier = false,424		.msi_capable = true,425		.msix_capable = false,426		.align = 1 << 16,427		.bar[BAR_0] = { .only_64bit = true, },428		.bar[BAR_1] = { .type = BAR_RESERVED, },429		.bar[BAR_2] = { .only_64bit = true, },430		.bar[BAR_3] = { .type = BAR_RESERVED, },431		.bar[BAR_4] = { .type = BAR_RESERVED, },432		.bar[BAR_5] = { .type = BAR_RESERVED, },433	},434};435 436static const struct uniphier_pcie_ep_soc_data uniphier_nx1_data = {437	.has_gio = false,438	.init = uniphier_pcie_nx1_init_ep,439	.wait = uniphier_pcie_nx1_wait_ep,440	.features = {441		.linkup_notifier = false,442		.msi_capable = true,443		.msix_capable = false,444		.align = 1 << 12,445		.bar[BAR_0] = { .only_64bit = true, },446		.bar[BAR_1] = { .type = BAR_RESERVED, },447		.bar[BAR_2] = { .only_64bit = true, },448		.bar[BAR_3] = { .type = BAR_RESERVED, },449		.bar[BAR_4] = { .only_64bit = true, },450		.bar[BAR_5] = { .type = BAR_RESERVED, },451	},452};453 454static const struct of_device_id uniphier_pcie_ep_match[] = {455	{456		.compatible = "socionext,uniphier-pro5-pcie-ep",457		.data = &uniphier_pro5_data,458	},459	{460		.compatible = "socionext,uniphier-nx1-pcie-ep",461		.data = &uniphier_nx1_data,462	},463	{ /* sentinel */ },464};465 466static struct platform_driver uniphier_pcie_ep_driver = {467	.probe  = uniphier_pcie_ep_probe,468	.driver = {469		.name = "uniphier-pcie-ep",470		.of_match_table = uniphier_pcie_ep_match,471		.suppress_bind_attrs = true,472	},473};474builtin_platform_driver(uniphier_pcie_ep_driver);475